summaryrefslogtreecommitdiff
path: root/chromium/net
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-01-04 14:17:57 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-01-05 10:05:06 +0000
commit39d357e3248f80abea0159765ff39554affb40db (patch)
treeaba0e6bfb76de0244bba0f5fdbd64b830dd6e621 /chromium/net
parent87778abf5a1f89266f37d1321b92a21851d8244d (diff)
downloadqtwebengine-chromium-39d357e3248f80abea0159765ff39554affb40db.tar.gz
BASELINE: Update Chromium to 55.0.2883.105
And updates ninja to 1.7.2 Change-Id: I20d43c737f82764d857ada9a55586901b18b9243 Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/net')
-rw-r--r--chromium/net/BUILD.gn256
-rw-r--r--chromium/net/DEPS5
-rw-r--r--chromium/net/OWNERS3
-rw-r--r--chromium/net/android/BUILD.gn14
-rw-r--r--chromium/net/android/cellular_signal_strength.cc57
-rw-r--r--chromium/net/android/cellular_signal_strength.h39
-rw-r--r--chromium/net/android/cellular_signal_strength_unittest.cc55
-rw-r--r--chromium/net/android/cert_verify_result_android.cc8
-rw-r--r--chromium/net/android/cert_verify_result_android.h7
-rw-r--r--chromium/net/android/dummy_spnego_authenticator.cc2
-rw-r--r--chromium/net/android/gurl_utils.cc3
-rw-r--r--chromium/net/android/http_auth_negotiate_android.cc9
-rw-r--r--chromium/net/android/http_auth_negotiate_android.h1
-rw-r--r--chromium/net/android/keystore.cc24
-rw-r--r--chromium/net/android/keystore.h26
-rw-r--r--chromium/net/android/keystore_openssl.cc550
-rw-r--r--chromium/net/android/keystore_openssl.h49
-rw-r--r--chromium/net/android/keystore_unittest.cc555
-rw-r--r--chromium/net/android/network_change_notifier_android.h1
-rw-r--r--chromium/net/android/network_change_notifier_android_unittest.cc13
-rw-r--r--chromium/net/android/network_change_notifier_delegate_android.cc55
-rw-r--r--chromium/net/android/network_change_notifier_delegate_android.h19
-rw-r--r--chromium/net/android/network_library.cc27
-rw-r--r--chromium/net/android/network_library.h5
-rw-r--r--chromium/net/android/traffic_stats.cc4
-rw-r--r--chromium/net/android/traffic_stats.h2
-rw-r--r--chromium/net/android/unittest_support/AndroidManifest.xml7
-rw-r--r--chromium/net/base/address_list.cc3
-rw-r--r--chromium/net/base/address_list.h4
-rw-r--r--chromium/net/base/address_tracker_linux.h1
-rw-r--r--chromium/net/base/arena.cc32
-rw-r--r--chromium/net/base/arena.h4
-rw-r--r--chromium/net/base/arena_unittest.cc45
-rw-r--r--chromium/net/base/auth.cc6
-rw-r--r--chromium/net/base/auth.h13
-rw-r--r--chromium/net/base/backoff_entry.cc8
-rw-r--r--chromium/net/base/backoff_entry.h7
-rw-r--r--chromium/net/base/backoff_entry_serializer.cc2
-rw-r--r--chromium/net/base/chunked_upload_data_stream.cc4
-rw-r--r--chromium/net/base/chunked_upload_data_stream.h2
-rw-r--r--chromium/net/base/chunked_upload_data_stream_unittest.cc70
-rw-r--r--chromium/net/base/directory_lister_unittest.cc31
-rw-r--r--chromium/net/base/elements_upload_data_stream.cc2
-rw-r--r--chromium/net/base/elements_upload_data_stream.h2
-rw-r--r--chromium/net/base/elements_upload_data_stream_unittest.cc200
-rw-r--r--chromium/net/base/expiring_cache_unittest.cc40
-rw-r--r--chromium/net/base/file_stream_context.cc31
-rw-r--r--chromium/net/base/file_stream_context.h25
-rw-r--r--chromium/net/base/file_stream_context_posix.cc7
-rw-r--r--chromium/net/base/file_stream_context_win.cc15
-rw-r--r--chromium/net/base/file_stream_unittest.cc107
-rw-r--r--chromium/net/base/filename_util.cc4
-rw-r--r--chromium/net/base/filename_util_internal.cc4
-rw-r--r--chromium/net/base/fuzzed_data_provider.cc76
-rw-r--r--chromium/net/base/fuzzed_data_provider.h74
-rw-r--r--chromium/net/base/ip_pattern.cc2
-rw-r--r--chromium/net/base/layered_network_delegate.cc14
-rw-r--r--chromium/net/base/layered_network_delegate.h6
-rw-r--r--chromium/net/base/layered_network_delegate_unittest.cc8
-rw-r--r--chromium/net/base/linked_hash_map.h4
-rw-r--r--chromium/net/base/load_flags_list.h6
-rw-r--r--chromium/net/base/load_timing_info.cc7
-rw-r--r--chromium/net/base/load_timing_info.h4
-rw-r--r--chromium/net/base/logging_network_change_observer.cc44
-rw-r--r--chromium/net/base/net_error_details.h3
-rw-r--r--chromium/net/base/net_error_list.h22
-rw-r--r--chromium/net/base/net_errors.cc5
-rw-r--r--chromium/net/base/net_errors.h3
-rw-r--r--chromium/net/base/net_resources.grd2
-rw-r--r--chromium/net/base/net_string_util_icu_alternatives_android.cc8
-rw-r--r--chromium/net/base/net_string_util_icu_alternatives_android.h18
-rw-r--r--chromium/net/base/network_activity_monitor_unittest.cc8
-rw-r--r--chromium/net/base/network_change_notifier.h7
-rw-r--r--chromium/net/base/network_change_notifier_win_unittest.cc15
-rw-r--r--chromium/net/base/network_delegate.cc33
-rw-r--r--chromium/net/base/network_delegate.h13
-rw-r--r--chromium/net/base/network_delegate_impl.cc18
-rw-r--r--chromium/net/base/network_delegate_impl.h7
-rw-r--r--chromium/net/base/network_interfaces_linux.cc8
-rw-r--r--chromium/net/base/network_interfaces_linux.h1
-rw-r--r--chromium/net/base/parse_url_hostname_to_address_fuzzer.cc31
-rw-r--r--chromium/net/base/priority_queue.h1
-rw-r--r--chromium/net/base/proxy_delegate.h20
-rw-r--r--chromium/net/base/sdch_manager_unittest.cc1
-rw-r--r--chromium/net/base/sdch_net_log_params.cc1
-rw-r--r--chromium/net/base/sdch_net_log_params.h8
-rw-r--r--chromium/net/base/static_cookie_policy_unittest.cc64
-rw-r--r--chromium/net/base/test_completion_callback_unittest.cc4
-rw-r--r--chromium/net/base/test_proxy_delegate.cc25
-rw-r--r--chromium/net/base/test_proxy_delegate.h24
-rw-r--r--chromium/net/base/upload_bytes_element_reader_unittest.cc8
-rw-r--r--chromium/net/base/upload_data_stream.cc80
-rw-r--r--chromium/net/base/upload_data_stream.h13
-rw-r--r--chromium/net/base/upload_file_element_reader_unittest.cc41
-rw-r--r--chromium/net/base/url_util.cc3
-rw-r--r--chromium/net/base/winsock_init.cc11
-rw-r--r--chromium/net/base/winsock_util.h2
-rw-r--r--chromium/net/cert/caching_cert_verifier.cc2
-rw-r--r--chromium/net/cert/caching_cert_verifier.h2
-rw-r--r--chromium/net/cert/caching_cert_verifier_unittest.cc44
-rw-r--r--chromium/net/cert/cert_verifier.h8
-rw-r--r--chromium/net/cert/cert_verify_proc.cc133
-rw-r--r--chromium/net/cert/cert_verify_proc_ios.cc27
-rw-r--r--chromium/net/cert/cert_verify_proc_ios.h6
-rw-r--r--chromium/net/cert/cert_verify_proc_ios_unittest.cc72
-rw-r--r--chromium/net/cert/cert_verify_proc_mac.cc573
-rw-r--r--chromium/net/cert/cert_verify_proc_nss.cc10
-rw-r--r--chromium/net/cert/cert_verify_proc_unittest.cc240
-rw-r--r--chromium/net/cert/cert_verify_proc_whitelist.cc440
-rw-r--r--chromium/net/cert/cert_verify_proc_win.cc4
-rw-r--r--chromium/net/cert/cert_verify_result.cc5
-rw-r--r--chromium/net/cert/cert_verify_result.h4
-rw-r--r--chromium/net/cert/ct_known_logs.cc6
-rw-r--r--chromium/net/cert/ct_known_logs_static-inc.h75
-rw-r--r--chromium/net/cert/ct_log_verifier.cc13
-rw-r--r--chromium/net/cert/ct_log_verifier.h15
-rw-r--r--chromium/net/cert/ct_log_verifier_unittest.cc158
-rw-r--r--chromium/net/cert/ct_objects_extractor_unittest.cc2
-rw-r--r--chromium/net/cert/ct_policy_enforcer.cc20
-rw-r--r--chromium/net/cert/ct_policy_enforcer.h7
-rw-r--r--chromium/net/cert/ct_policy_enforcer_unittest.cc125
-rw-r--r--chromium/net/cert/ct_sct_to_string.cc8
-rw-r--r--chromium/net/cert/ct_sct_to_string.h1
-rw-r--r--chromium/net/cert/ct_serialization_unittest.cc1
-rw-r--r--chromium/net/cert/ct_signed_certificate_timestamp_log_param.cc26
-rw-r--r--chromium/net/cert/ct_signed_certificate_timestamp_log_param.h7
-rw-r--r--chromium/net/cert/ct_verifier.h4
-rw-r--r--chromium/net/cert/ct_verify_result.cc11
-rw-r--r--chromium/net/cert/ct_verify_result.h17
-rw-r--r--chromium/net/cert/ev_root_ca_metadata.cc88
-rw-r--r--chromium/net/cert/ev_root_ca_metadata.h16
-rw-r--r--chromium/net/cert/ev_root_ca_metadata_unittest.cc25
-rw-r--r--chromium/net/cert/internal/cert_error_id.cc14
-rw-r--r--chromium/net/cert/internal/cert_error_id.h37
-rw-r--r--chromium/net/cert/internal/cert_error_params.cc135
-rw-r--r--chromium/net/cert/internal/cert_error_params.h74
-rw-r--r--chromium/net/cert/internal/cert_error_scoper.cc54
-rw-r--r--chromium/net/cert/internal/cert_error_scoper.h59
-rw-r--r--chromium/net/cert/internal/cert_errors.cc140
-rw-r--r--chromium/net/cert/internal/cert_errors.h164
-rw-r--r--chromium/net/cert/internal/cert_issuer_source.h8
-rw-r--r--chromium/net/cert/internal/cert_issuer_source_aia.cc21
-rw-r--r--chromium/net/cert/internal/cert_issuer_source_aia.h6
-rw-r--r--chromium/net/cert/internal/cert_issuer_source_aia_unittest.cc13
-rw-r--r--chromium/net/cert/internal/cert_issuer_source_static.cc7
-rw-r--r--chromium/net/cert/internal/cert_issuer_source_static.h6
-rw-r--r--chromium/net/cert/internal/cert_issuer_source_static_unittest.cc19
-rw-r--r--chromium/net/cert/internal/extended_key_usage.h1
-rw-r--r--chromium/net/cert/internal/name_constraints.cc4
-rw-r--r--chromium/net/cert/internal/name_constraints.h5
-rw-r--r--chromium/net/cert/internal/name_constraints_unittest.cc148
-rw-r--r--chromium/net/cert/internal/nist_pkits_unittest.h28
-rw-r--r--chromium/net/cert/internal/parse_certificate.cc69
-rw-r--r--chromium/net/cert/internal/parse_certificate.h25
-rw-r--r--chromium/net/cert/internal/parse_certificate_fuzzer.cc75
-rw-r--r--chromium/net/cert/internal/parse_certificate_unittest.cc590
-rw-r--r--chromium/net/cert/internal/parse_name.cc8
-rw-r--r--chromium/net/cert/internal/parse_name.h4
-rw-r--r--chromium/net/cert/internal/parse_ocsp.cc51
-rw-r--r--chromium/net/cert/internal/parse_ocsp.h23
-rw-r--r--chromium/net/cert/internal/parse_ocsp_unittest.cc141
-rw-r--r--chromium/net/cert/internal/parsed_certificate.cc93
-rw-r--r--chromium/net/cert/internal/parsed_certificate.h106
-rw-r--r--chromium/net/cert/internal/path_builder.cc750
-rw-r--r--chromium/net/cert/internal/path_builder.h188
-rw-r--r--chromium/net/cert/internal/path_builder_pkits_unittest.cc231
-rw-r--r--chromium/net/cert/internal/path_builder_unittest.cc1297
-rw-r--r--chromium/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc53
-rw-r--r--chromium/net/cert/internal/signature_algorithm.cc12
-rw-r--r--chromium/net/cert/internal/signature_algorithm.h11
-rw-r--r--chromium/net/cert/internal/signature_algorithm_unittest.cc17
-rw-r--r--chromium/net/cert/internal/signature_policy.cc41
-rw-r--r--chromium/net/cert/internal/signature_policy.h15
-rw-r--r--chromium/net/cert/internal/test_helpers.cc95
-rw-r--r--chromium/net/cert/internal/test_helpers.h17
-rw-r--r--chromium/net/cert/internal/trust_store.cc53
-rw-r--r--chromium/net/cert/internal/trust_store.h149
-rw-r--r--chromium/net/cert/internal/trust_store_collection.cc38
-rw-r--r--chromium/net/cert/internal/trust_store_collection.h62
-rw-r--r--chromium/net/cert/internal/trust_store_collection_unittest.cc231
-rw-r--r--chromium/net/cert/internal/trust_store_in_memory.cc32
-rw-r--r--chromium/net/cert/internal/trust_store_in_memory.h52
-rw-r--r--chromium/net/cert/internal/trust_store_nss.cc137
-rw-r--r--chromium/net/cert/internal/trust_store_nss.h50
-rw-r--r--chromium/net/cert/internal/trust_store_nss_unittest.cc248
-rw-r--r--chromium/net/cert/internal/trust_store_test_helpers.cc95
-rw-r--r--chromium/net/cert/internal/trust_store_test_helpers.h68
-rw-r--r--chromium/net/cert/internal/verify_certificate_chain.cc393
-rw-r--r--chromium/net/cert/internal/verify_certificate_chain.h47
-rw-r--r--chromium/net/cert/internal/verify_certificate_chain_pkits_unittest.cc33
-rw-r--r--chromium/net/cert/internal/verify_certificate_chain_typed_unittest.h269
-rw-r--r--chromium/net/cert/internal/verify_certificate_chain_unittest.cc265
-rw-r--r--chromium/net/cert/internal/verify_name_match_fuzzer.cc4
-rw-r--r--chromium/net/cert/internal/verify_name_match_verifynameinsubtree_fuzzer.cc4
-rw-r--r--chromium/net/cert/internal/verify_signed_data.cc52
-rw-r--r--chromium/net/cert/internal/verify_signed_data.h6
-rw-r--r--chromium/net/cert/internal/verify_signed_data_unittest.cc30
-rw-r--r--chromium/net/cert/merkle_audit_proof.cc5
-rw-r--r--chromium/net/cert/merkle_audit_proof.h6
-rw-r--r--chromium/net/cert/merkle_tree_leaf.cc9
-rw-r--r--chromium/net/cert/merkle_tree_leaf.h32
-rw-r--r--chromium/net/cert/merkle_tree_leaf_unittest.cc6
-rw-r--r--chromium/net/cert/mock_cert_verifier.cc2
-rw-r--r--chromium/net/cert/mock_cert_verifier.h2
-rw-r--r--chromium/net/cert/multi_log_ct_verifier.cc71
-rw-r--r--chromium/net/cert/multi_log_ct_verifier.h2
-rw-r--r--chromium/net/cert/multi_log_ct_verifier_unittest.cc80
-rw-r--r--chromium/net/cert/multi_threaded_cert_verifier.cc43
-rw-r--r--chromium/net/cert/multi_threaded_cert_verifier.h2
-rw-r--r--chromium/net/cert/multi_threaded_cert_verifier_unittest.cc56
-rw-r--r--chromium/net/cert/nss_cert_database_unittest.cc57
-rw-r--r--chromium/net/cert/ocsp_revocation_status.h18
-rw-r--r--chromium/net/cert/ocsp_verify_result.cc24
-rw-r--r--chromium/net/cert/ocsp_verify_result.h68
-rw-r--r--chromium/net/cert/sct_status_flags.cc27
-rw-r--r--chromium/net/cert/sct_status_flags.h25
-rw-r--r--chromium/net/cert/signed_certificate_timestamp.cc8
-rw-r--r--chromium/net/cert/signed_certificate_timestamp_and_status.cc23
-rw-r--r--chromium/net/cert/signed_certificate_timestamp_and_status.h38
-rw-r--r--chromium/net/cert/test_keychain_search_list_mac.cc55
-rw-r--r--chromium/net/cert/test_keychain_search_list_mac.h46
-rw-r--r--chromium/net/cert/test_root_certs.cc2
-rw-r--r--chromium/net/cert/test_root_certs_nss.cc2
-rw-r--r--chromium/net/cert/test_root_certs_unittest.cc6
-rw-r--r--chromium/net/cert/x509_certificate_net_log_param.cc1
-rw-r--r--chromium/net/cert/x509_certificate_net_log_param.h5
-rw-r--r--chromium/net/cert/x509_certificate_openssl.cc3
-rw-r--r--chromium/net/cert/x509_util.cc88
-rw-r--r--chromium/net/cert/x509_util.h13
-rw-r--r--chromium/net/cert/x509_util_android.cc2
-rw-r--r--chromium/net/cert/x509_util_mac.cc129
-rw-r--r--chromium/net/cert/x509_util_mac.h11
-rw-r--r--chromium/net/cert/x509_util_openssl.cc4
-rw-r--r--chromium/net/cert_net/cert_net_fetcher_impl.cc93
-rw-r--r--chromium/net/cert_net/cert_net_fetcher_impl_unittest.cc64
-rw-r--r--chromium/net/cert_net/nss_ocsp.cc21
-rw-r--r--chromium/net/cert_net/nss_ocsp_unittest.cc12
-rw-r--r--chromium/net/cookies/canonical_cookie.cc86
-rw-r--r--chromium/net/cookies/canonical_cookie.h68
-rw-r--r--chromium/net/cookies/canonical_cookie_unittest.cc182
-rw-r--r--chromium/net/cookies/cookie_monster.cc103
-rw-r--r--chromium/net/cookies/cookie_monster.h39
-rw-r--r--chromium/net/cookies/cookie_monster_store_test.cc4
-rw-r--r--chromium/net/cookies/cookie_monster_store_test.h2
-rw-r--r--chromium/net/cookies/cookie_monster_unittest.cc74
-rw-r--r--chromium/net/cookies/cookie_store.cc4
-rw-r--r--chromium/net/cookies/cookie_store.h33
-rw-r--r--chromium/net/cookies/cookie_store_unittest.h50
-rw-r--r--chromium/net/cookies/parsed_cookie.cc57
-rw-r--r--chromium/net/cookies/parsed_cookie.h3
-rw-r--r--chromium/net/cookies/parsed_cookie_unittest.cc69
-rwxr-xr-xchromium/net/data/cert_issuer_source_aia_unittest/generate-certs.py26
-rw-r--r--chromium/net/data/cert_issuer_source_aia_unittest/i.pem100
-rw-r--r--chromium/net/data/cert_issuer_source_aia_unittest/i2.pem100
-rw-r--r--chromium/net/data/cert_issuer_source_aia_unittest/i3.pem100
-rw-r--r--chromium/net/data/cert_issuer_source_aia_unittest/target_file_aia.pem104
-rw-r--r--chromium/net/data/cert_issuer_source_aia_unittest/target_file_and_http_aia.pem102
-rw-r--r--chromium/net/data/cert_issuer_source_aia_unittest/target_invalid_and_http_aia.pem102
-rw-r--r--chromium/net/data/cert_issuer_source_aia_unittest/target_invalid_url_aia.pem102
-rw-r--r--chromium/net/data/cert_issuer_source_aia_unittest/target_no_aia.pem104
-rw-r--r--chromium/net/data/cert_issuer_source_aia_unittest/target_one_aia.pem98
-rw-r--r--chromium/net/data/cert_issuer_source_aia_unittest/target_six_aia.pem102
-rw-r--r--chromium/net/data/cert_issuer_source_aia_unittest/target_three_aia.pem104
-rw-r--r--chromium/net/data/cert_issuer_source_aia_unittest/target_two_aia.pem104
-rwxr-xr-xchromium/net/data/cert_issuer_source_static_unittest/generate-certs.py8
-rw-r--r--chromium/net/data/ftp/dir-listing-ls-20.expected28
-rw-r--r--chromium/net/data/ftp/dir-listing-ls-21.expected48
-rw-r--r--chromium/net/data/ftp/dir-listing-ls-22.expected110
-rw-r--r--chromium/net/data/fuzzer_data/hostnames/ipv4_1.txt1
-rw-r--r--chromium/net/data/fuzzer_data/hostnames/ipv4_2.txt1
-rw-r--r--chromium/net/data/fuzzer_data/hostnames/ipv4_3.txt1
-rw-r--r--chromium/net/data/fuzzer_data/hostnames/ipv4_4.txt1
-rw-r--r--chromium/net/data/fuzzer_data/hostnames/ipv4_5.txt1
-rw-r--r--chromium/net/data/fuzzer_data/hostnames/ipv4_6.txt1
-rw-r--r--chromium/net/data/fuzzer_data/hostnames/ipv4_7.txt1
-rw-r--r--chromium/net/data/fuzzer_data/hostnames/ipv4_8.txt1
-rw-r--r--chromium/net/data/fuzzer_data/hostnames/ipv4_9.txt1
-rw-r--r--chromium/net/data/fuzzer_data/hostnames/ipv6_1.txt1
-rw-r--r--chromium/net/data/fuzzer_data/hostnames/ipv6_2.txt1
-rw-r--r--chromium/net/data/fuzzer_data/hostnames/ipv6_3.txt1
-rw-r--r--chromium/net/data/fuzzer_data/hostnames/ipv6_4.txt1
-rw-r--r--chromium/net/data/fuzzer_data/hostnames/ipv6_5.txt1
-rw-r--r--chromium/net/data/fuzzer_dictionaries/net_dns_hosts_parse_fuzzer.dict843
-rw-r--r--chromium/net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict843
-rw-r--r--chromium/net/data/fuzzer_dictionaries/net_get_domain_and_registry_fuzzer.dict848
-rw-r--r--chromium/net/data/fuzzer_dictionaries/net_host_resolver_impl_fuzzer.dict1397
-rw-r--r--chromium/net/data/fuzzer_dictionaries/net_http_proxy_client_socket_fuzzer.dict1088
-rw-r--r--chromium/net/data/fuzzer_dictionaries/net_http_stream_parser_fuzzer.dict1039
-rw-r--r--chromium/net/data/fuzzer_dictionaries/net_mime_sniffer_fuzzer.dict447
-rw-r--r--chromium/net/data/fuzzer_dictionaries/net_parse_data_url_fuzzer.dict449
-rw-r--r--chromium/net/data/fuzzer_dictionaries/net_parse_proxy_bypass_rules_fuzzer.dict9
-rw-r--r--chromium/net/data/fuzzer_dictionaries/net_url_request_fuzzer.dict1718
-rw-r--r--chromium/net/data/fuzzer_dictionaries/net_websocket_extension_parser_fuzzer.dict30
-rw-r--r--chromium/net/data/fuzzer_dictionaries/net_websocket_frame_parser_fuzzer.dict460
-rw-r--r--chromium/net/data/http/http.dict163
-rw-r--r--chromium/net/data/parse_certificate_unittest/basic_constraints_ca_false.pem16
-rw-r--r--chromium/net/data/parse_certificate_unittest/basic_constraints_ca_no_path.pem16
-rw-r--r--chromium/net/data/parse_certificate_unittest/basic_constraints_ca_path_9.pem18
-rw-r--r--chromium/net/data/parse_certificate_unittest/basic_constraints_negative_path.pem18
-rw-r--r--chromium/net/data/parse_certificate_unittest/basic_constraints_not_ca.pem13
-rw-r--r--chromium/net/data/parse_certificate_unittest/basic_constraints_path_too_large.pem18
-rw-r--r--chromium/net/data/parse_certificate_unittest/basic_constraints_pathlen_255.pem18
-rw-r--r--chromium/net/data/parse_certificate_unittest/basic_constraints_pathlen_256.pem18
-rw-r--r--chromium/net/data/parse_certificate_unittest/basic_constraints_pathlen_not_ca.pem16
-rw-r--r--chromium/net/data/parse_certificate_unittest/basic_constraints_unconsumed_data.pem16
-rw-r--r--chromium/net/data/parse_certificate_unittest/cert_algorithm_not_sequence.pem6
-rw-r--r--chromium/net/data/parse_certificate_unittest/cert_data_after_signature.pem6
-rw-r--r--chromium/net/data/parse_certificate_unittest/cert_empty_sequence.pem6
-rw-r--r--chromium/net/data/parse_certificate_unittest/cert_missing_signature.pem6
-rw-r--r--chromium/net/data/parse_certificate_unittest/cert_not_sequence.pem6
-rw-r--r--chromium/net/data/parse_certificate_unittest/cert_signature_not_bit_string.pem6
-rw-r--r--chromium/net/data/parse_certificate_unittest/extended_key_usage.pem21
-rw-r--r--chromium/net/data/parse_certificate_unittest/extension_critical.pem24
-rw-r--r--chromium/net/data/parse_certificate_unittest/extension_critical_0.pem24
-rw-r--r--chromium/net/data/parse_certificate_unittest/extension_critical_3.pem24
-rw-r--r--chromium/net/data/parse_certificate_unittest/extension_not_critical.pem24
-rw-r--r--chromium/net/data/parse_certificate_unittest/extensions_basic_constraints.pem15
-rw-r--r--chromium/net/data/parse_certificate_unittest/extensions_data_after_sequence.pem28
-rw-r--r--chromium/net/data/parse_certificate_unittest/extensions_duplicate_key_usage.pem38
-rw-r--r--chromium/net/data/parse_certificate_unittest/extensions_empty_sequence.pem13
-rw-r--r--chromium/net/data/parse_certificate_unittest/extensions_extended_key_usage.pem19
-rw-r--r--chromium/net/data/parse_certificate_unittest/extensions_key_usage.pem15
-rw-r--r--chromium/net/data/parse_certificate_unittest/extensions_not_sequence.pem13
-rw-r--r--chromium/net/data/parse_certificate_unittest/extensions_policies.pem24
-rw-r--r--chromium/net/data/parse_certificate_unittest/extensions_real.pem114
-rw-r--r--chromium/net/data/parse_certificate_unittest/extensions_subject_alt_name.pem15
-rw-r--r--chromium/net/data/parse_certificate_unittest/extensions_unknown_critical.pem9
-rw-r--r--chromium/net/data/parse_certificate_unittest/extensions_unknown_non_critical.pem8
-rw-r--r--chromium/net/data/parse_certificate_unittest/key_usage.pem15
-rw-r--r--chromium/net/data/parse_certificate_unittest/policies.pem27
-rwxr-xr-xchromium/net/data/parse_certificate_unittest/regenerate_pem_from_ascii.py104
-rw-r--r--chromium/net/data/parse_certificate_unittest/subject_alt_name.pem16
-rw-r--r--chromium/net/data/parse_certificate_unittest/tbs_v3_data_after_extensions.pem6
-rw-r--r--chromium/net/data/parse_certificate_unittest/v3_certificate_template.txt127
-rw-r--r--chromium/net/data/ssl/certificates/README32
-rw-r--r--chromium/net/data/ssl/certificates/android-test-key-dsa-public.pem20
-rw-r--r--chromium/net/data/ssl/certificates/android-test-key-dsa.pem20
-rw-r--r--chromium/net/data/ssl/certificates/android-test-key-ecdsa-public.pem4
-rw-r--r--chromium/net/data/ssl/certificates/android-test-key-ecdsa.pem8
-rw-r--r--chromium/net/data/ssl/certificates/android-test-key-rsa.pem27
-rw-r--r--chromium/net/data/ssl/certificates/client_1.key50
-rw-r--r--chromium/net/data/ssl/certificates/client_1.pem100
-rw-r--r--chromium/net/data/ssl/certificates/client_1.pk8bin1218 -> 1218 bytes
-rw-r--r--chromium/net/data/ssl/certificates/client_1_ca.pem98
-rw-r--r--chromium/net/data/ssl/certificates/client_2.key50
-rw-r--r--chromium/net/data/ssl/certificates/client_2.pem100
-rw-r--r--chromium/net/data/ssl/certificates/client_2.pk8bin1216 -> 1217 bytes
-rw-r--r--chromium/net/data/ssl/certificates/client_2_ca.pem98
-rw-r--r--chromium/net/data/ssl/certificates/client_3.key50
-rw-r--r--chromium/net/data/ssl/certificates/client_3.pem98
-rw-r--r--chromium/net/data/ssl/certificates/client_3.pk8bin1220 -> 1218 bytes
-rw-r--r--chromium/net/data/ssl/certificates/client_3_ca.pem98
-rw-r--r--chromium/net/data/ssl/certificates/client_4.key5
-rw-r--r--chromium/net/data/ssl/certificates/client_4.pem54
-rw-r--r--chromium/net/data/ssl/certificates/client_4.pk8bin0 -> 138 bytes
-rw-r--r--chromium/net/data/ssl/certificates/client_4_ca.pem71
-rw-r--r--chromium/net/data/ssl/certificates/client_root_ca.pem18
-rw-r--r--chromium/net/data/ssl/certificates/multi-root-BFE.keychainbin0 -> 24884 bytes
-rw-r--r--chromium/net/data/ssl/certificates/ocsp-test-root.pem36
-rw-r--r--chromium/net/data/ssl/certificates/tripadvisor-verisign-chain.pem221
-rw-r--r--chromium/net/data/ssl/certificates/verisign_class3_g5_crosssigned-trusted.keychainbin0 -> 24740 bytes
-rw-r--r--chromium/net/data/ssl/certificates/verisign_class3_g5_crosssigned.pem92
-rwxr-xr-xchromium/net/data/ssl/scripts/crlsetutil.py15
-rwxr-xr-xchromium/net/data/ssl/scripts/generate-android-test-keys.sh56
-rwxr-xr-xchromium/net/data/ssl/scripts/generate-client-certificates.sh35
-rwxr-xr-xchromium/net/data/ssl/scripts/generate-keychain.sh73
-rwxr-xr-xchromium/net/data/ssl/scripts/generate-multi-root-BFE-keychain.sh18
-rwxr-xr-xchromium/net/data/ssl/scripts/generate-verisign_class3_g5_crosssigned-trusted-keychain.sh19
-rw-r--r--chromium/net/data/ssl/symantec/README.md7
-rw-r--r--chromium/net/data/ssl/symantec/excluded/8c31013d19f8eea618c95fda6d21f5777c6e930c7413031559ee863d78dfe809.pem96
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/README53
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/basic-constraints-pathlen-0-self-issued.pem436
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/common.py179
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/constrained-non-self-signed-root.pem283
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/constrained-root-basic-constraints-ca-false.pem284
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/constrained-root-lacks-basic-constraints.pem280
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/expired-constrained-root.pem284
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/expired-intermediary.pem280
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/expired-intermediate.pem290
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/expired-root.pem280
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/expired-target-notBefore.pem328
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/expired-target.pem328
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/expired-unconstrained-root.pem284
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-basic-constraints-pathlen-0-self-issued.py27
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-constrained-non-self-signed-root.py30
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-constrained-root-basic-constraints-ca-false.py30
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-constrained-root-lacks-basic-constraints.py28
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-expired-constrained-root.py35
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-expired-intermediary.py32
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-expired-intermediate.py36
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-expired-root.py32
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-expired-target-notBefore.py24
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-expired-target.py24
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-expired-unconstrained-root.py36
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-incorrect-trust-anchor.py35
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-intermediary-basic-constraints-ca-false.py28
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-intermediary-basic-constraints-not-critical.py28
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-intermediary-lacks-basic-constraints.py27
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-intermediary-lacks-signing-key-usage.py28
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-intermediary-signed-with-md5.py27
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-intermediary-unknown-critical-extension.py29
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-intermediary-unknown-non-critical-extension.py28
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-intermediate-basic-constraints-ca-false.py32
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-intermediate-basic-constraints-not-critical.py29
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-intermediate-lacks-basic-constraints.py31
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-intermediate-lacks-signing-key-usage.py32
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-intermediate-signed-with-md5.py32
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-intermediate-unknown-critical-extension.py35
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-intermediate-unknown-non-critical-extension.py29
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-key-rollover.py92
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-non-self-signed-root.py17
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-target-and-intermediary.py25
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-target-and-intermediate.py26
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-target-has-keycertsign-but-not-ca.py20
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-target-has-pathlen-but-not-ca.py20
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-target-not-end-entity.py17
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-target-signed-by-512bit-rsa.py26
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-target-signed-using-ecdsa.py19
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-target-signed-with-md5.py21
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-target-unknown-critical-extension.py22
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-target-wrong-signature.py23
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-unconstrained-non-self-signed-root.py30
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-unconstrained-root-basic-constraints-ca-false.py31
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-unconstrained-root-lacks-basic-constraints.py28
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-unknown-root.py26
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-violates-basic-constraints-pathlen-0.py32
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-violates-pathlen-1-constrained-root.py36
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-violates-pathlen-1-root.py31
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/generate-violates-pathlen-1-unconstrained-root.py33
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/incorrect-trust-anchor.pem292
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/intermediary-basic-constraints-ca-false.pem281
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/intermediary-basic-constraints-not-critical.pem282
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/intermediary-lacks-basic-constraints.pem278
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/intermediary-lacks-signing-key-usage.pem281
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/intermediary-signed-with-md5.pem281
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/intermediary-unknown-critical-extension.pem284
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/intermediary-unknown-non-critical-extension.pem284
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/intermediate-basic-constraints-ca-false.pem291
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/intermediate-basic-constraints-not-critical.pem284
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/intermediate-lacks-basic-constraints.pem288
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/intermediate-lacks-signing-key-usage.pem291
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/intermediate-signed-with-md5.pem292
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/intermediate-unknown-critical-extension.pem296
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/intermediate-unknown-non-critical-extension.pem286
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/issuer-and-subject-not-byte-for-byte-equal-anchor.pem4
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/issuer-and-subject-not-byte-for-byte-equal.pem4
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/key-rollover-longrolloverchain.pem491
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/key-rollover-newchain.pem313
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/key-rollover-oldchain.pem313
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/key-rollover-rolloverchain.pem402
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/non-self-signed-root.pem320
-rwxr-xr-xchromium/net/data/verify_certificate_chain_unittest/rebase-errors.py177
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/target-and-intermediary.pem280
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/target-and-intermediate.pem282
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/target-has-keycertsign-but-not-ca.pem330
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/target-has-pathlen-but-not-ca.pem330
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/target-not-end-entity.pem320
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/target-signed-by-512bit-rsa.pem268
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/target-signed-using-ecdsa.pem272
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/target-signed-with-md5.pem329
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/target-unknown-critical-extension.pem336
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/target-wrong-signature.pem327
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/unconstrained-non-self-signed-root.pem283
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/unconstrained-root-basic-constraints-ca-false.pem284
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/unconstrained-root-lacks-basic-constraints.pem280
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/unknown-root.pem192
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/violates-basic-constraints-pathlen-0.pem442
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/violates-pathlen-1-constrained-root.pem380
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/violates-pathlen-1-root.pem369
-rw-r--r--chromium/net/data/verify_certificate_chain_unittest/violates-pathlen-1-unconstrained-root.pem372
-rw-r--r--chromium/net/der/encode_values.cc30
-rw-r--r--chromium/net/der/encode_values.h28
-rw-r--r--chromium/net/der/encode_values_unittest.cc98
-rw-r--r--chromium/net/disk_cache/backend_unittest.cc499
-rw-r--r--chromium/net/disk_cache/blockfile/backend_impl.cc10
-rw-r--r--chromium/net/disk_cache/blockfile/backend_impl.h1
-rw-r--r--chromium/net/disk_cache/blockfile/disk_format_base.h2
-rw-r--r--chromium/net/disk_cache/blockfile/entry_impl.cc52
-rw-r--r--chromium/net/disk_cache/blockfile/entry_impl.h12
-rw-r--r--chromium/net/disk_cache/blockfile/eviction.cc1
-rw-r--r--chromium/net/disk_cache/blockfile/file_posix.cc5
-rw-r--r--chromium/net/disk_cache/blockfile/rankings.cc1
-rw-r--r--chromium/net/disk_cache/blockfile/sparse_control.cc31
-rw-r--r--chromium/net/disk_cache/cache_util_unittest.cc4
-rw-r--r--chromium/net/disk_cache/disk_cache_test_base.cc19
-rw-r--r--chromium/net/disk_cache/entry_unittest.cc353
-rw-r--r--chromium/net/disk_cache/memory/mem_backend_impl.cc51
-rw-r--r--chromium/net/disk_cache/memory/mem_backend_impl.h1
-rw-r--r--chromium/net/disk_cache/memory/mem_entry_impl.cc55
-rw-r--r--chromium/net/disk_cache/memory/mem_entry_impl.h9
-rw-r--r--chromium/net/disk_cache/net_log_parameters.cc25
-rw-r--r--chromium/net/disk_cache/net_log_parameters.h29
-rw-r--r--chromium/net/disk_cache/simple/simple_backend_impl.cc8
-rw-r--r--chromium/net/disk_cache/simple/simple_backend_impl.h1
-rw-r--r--chromium/net/disk_cache/simple/simple_entry_impl.cc160
-rw-r--r--chromium/net/disk_cache/simple/simple_entry_impl.h8
-rw-r--r--chromium/net/disk_cache/simple/simple_entry_operation.h1
-rw-r--r--chromium/net/disk_cache/simple/simple_index.cc47
-rw-r--r--chromium/net/disk_cache/simple/simple_index.h16
-rw-r--r--chromium/net/disk_cache/simple/simple_index_file.cc9
-rw-r--r--chromium/net/disk_cache/simple/simple_index_file_unittest.cc30
-rw-r--r--chromium/net/disk_cache/simple/simple_index_unittest.cc29
-rw-r--r--chromium/net/disk_cache/simple/simple_net_log_parameters.cc5
-rw-r--r--chromium/net/disk_cache/simple/simple_net_log_parameters.h6
-rw-r--r--chromium/net/disk_cache/simple/simple_version_upgrade_unittest.cc8
-rw-r--r--chromium/net/dns/address_sorter_posix.cc3
-rw-r--r--chromium/net/dns/address_sorter_posix_unittest.cc11
-rw-r--r--chromium/net/dns/dns_client.cc17
-rw-r--r--chromium/net/dns/dns_client.h8
-rw-r--r--chromium/net/dns/dns_config_service_posix_unittest.cc10
-rw-r--r--chromium/net/dns/dns_hosts.cc3
-rw-r--r--chromium/net/dns/dns_hosts_unittest.cc30
-rw-r--r--chromium/net/dns/dns_session.cc30
-rw-r--r--chromium/net/dns/dns_session.h8
-rw-r--r--chromium/net/dns/dns_session_unittest.cc12
-rw-r--r--chromium/net/dns/dns_socket_pool.cc9
-rw-r--r--chromium/net/dns/dns_socket_pool.h10
-rw-r--r--chromium/net/dns/dns_test_util.cc8
-rw-r--r--chromium/net/dns/dns_test_util.h2
-rw-r--r--chromium/net/dns/dns_transaction.cc50
-rw-r--r--chromium/net/dns/dns_transaction.h4
-rw-r--r--chromium/net/dns/dns_transaction_unittest.cc46
-rw-r--r--chromium/net/dns/dns_util.cc5
-rw-r--r--chromium/net/dns/dns_util.h3
-rw-r--r--chromium/net/dns/fuzzed_host_resolver.cc20
-rw-r--r--chromium/net/dns/fuzzed_host_resolver.h12
-rw-r--r--chromium/net/dns/host_cache.cc24
-rw-r--r--chromium/net/dns/host_cache.h12
-rw-r--r--chromium/net/dns/host_cache_unittest.cc93
-rw-r--r--chromium/net/dns/host_resolver.cc49
-rw-r--r--chromium/net/dns/host_resolver.h80
-rw-r--r--chromium/net/dns/host_resolver_impl.cc393
-rw-r--r--chromium/net/dns/host_resolver_impl.h46
-rw-r--r--chromium/net/dns/host_resolver_impl_fuzzer.cc35
-rw-r--r--chromium/net/dns/host_resolver_impl_unittest.cc592
-rw-r--r--chromium/net/dns/host_resolver_mojo.cc45
-rw-r--r--chromium/net/dns/host_resolver_mojo.h12
-rw-r--r--chromium/net/dns/host_resolver_mojo_unittest.cc116
-rw-r--r--chromium/net/dns/mapped_host_resolver.cc12
-rw-r--r--chromium/net/dns/mapped_host_resolver.h7
-rw-r--r--chromium/net/dns/mapped_host_resolver_unittest.cc129
-rw-r--r--chromium/net/dns/mdns_client.cc3
-rw-r--r--chromium/net/dns/mdns_client.h1
-rw-r--r--chromium/net/dns/mdns_client_impl.cc3
-rw-r--r--chromium/net/dns/mdns_client_impl.h1
-rw-r--r--chromium/net/dns/mdns_client_unittest.cc9
-rw-r--r--chromium/net/dns/mock_host_resolver.cc116
-rw-r--r--chromium/net/dns/mock_host_resolver.h25
-rw-r--r--chromium/net/dns/mock_mdns_socket_factory.h5
-rw-r--r--chromium/net/dns/mojo_host_resolver_impl.cc25
-rw-r--r--chromium/net/dns/mojo_host_resolver_impl.h9
-rw-r--r--chromium/net/dns/mojo_host_resolver_impl_unittest.cc32
-rw-r--r--chromium/net/dns/record_rdata.h7
-rw-r--r--chromium/net/dns/record_rdata_unittest.cc73
-rw-r--r--chromium/net/dns/single_request_host_resolver.cc79
-rw-r--r--chromium/net/dns/single_request_host_resolver.h64
-rw-r--r--chromium/net/dns/single_request_host_resolver_unittest.cc127
-rw-r--r--chromium/net/docs/crash-course-in-net-internals.md2
-rw-r--r--chromium/net/docs/filter.md36
-rw-r--r--chromium/net/extras/sqlite/sqlite_channel_id_store_unittest.cc34
-rw-r--r--chromium/net/extras/sqlite/sqlite_persistent_cookie_store_perftest.cc8
-rw-r--r--chromium/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc50
-rw-r--r--chromium/net/features.gni23
-rw-r--r--chromium/net/filter/brotli_source_stream.cc191
-rw-r--r--chromium/net/filter/brotli_source_stream.h21
-rw-r--r--chromium/net/filter/brotli_source_stream_disabled.cc14
-rw-r--r--chromium/net/filter/brotli_source_stream_unittest.cc275
-rw-r--r--chromium/net/filter/filter.cc4
-rw-r--r--chromium/net/filter/filter.h8
-rw-r--r--chromium/net/filter/filter_source_stream.cc176
-rw-r--r--chromium/net/filter/filter_source_stream.h119
-rw-r--r--chromium/net/filter/filter_source_stream_unittest.cc547
-rw-r--r--chromium/net/filter/gzip_header.h3
-rw-r--r--chromium/net/filter/gzip_source_stream.cc221
-rw-r--r--chromium/net/filter/gzip_source_stream.h105
-rw-r--r--chromium/net/filter/gzip_source_stream_unittest.cc420
-rw-r--r--chromium/net/filter/mock_filter_context.cc2
-rw-r--r--chromium/net/filter/mock_filter_context.h6
-rw-r--r--chromium/net/filter/mock_source_stream.cc78
-rw-r--r--chromium/net/filter/mock_source_stream.h70
-rw-r--r--chromium/net/filter/sdch_filter.cc7
-rw-r--r--chromium/net/filter/source_stream.cc17
-rw-r--r--chromium/net/filter/source_stream.h67
-rw-r--r--chromium/net/filter/source_stream_type_list.h11
-rw-r--r--chromium/net/ftp/ftp_ctrl_response_buffer.cc9
-rw-r--r--chromium/net/ftp/ftp_ctrl_response_buffer.h6
-rw-r--r--chromium/net/ftp/ftp_ctrl_response_buffer_unittest.cc60
-rw-r--r--chromium/net/ftp/ftp_ctrl_response_fuzzer.cc3
-rw-r--r--chromium/net/ftp/ftp_directory_listing_parser.cc44
-rw-r--r--chromium/net/ftp/ftp_directory_listing_parser_unittest.cc4
-rw-r--r--chromium/net/ftp/ftp_network_layer.cc4
-rw-r--r--chromium/net/ftp/ftp_network_transaction.cc18
-rw-r--r--chromium/net/ftp/ftp_network_transaction.h11
-rw-r--r--chromium/net/ftp/ftp_network_transaction_unittest.cc27
-rw-r--r--chromium/net/ftp/ftp_transaction.h4
-rw-r--r--chromium/net/ftp/ftp_util.cc6
-rw-r--r--chromium/net/http/bidirectional_stream.cc128
-rw-r--r--chromium/net/http/bidirectional_stream.h25
-rw-r--r--chromium/net/http/bidirectional_stream_impl.h15
-rw-r--r--chromium/net/http/bidirectional_stream_unittest.cc810
-rw-r--r--chromium/net/http/disk_cache_based_quic_server_info.cc2
-rw-r--r--chromium/net/http/disk_cache_based_quic_server_info.h33
-rw-r--r--chromium/net/http/disk_cache_based_quic_server_info_unittest.cc53
-rw-r--r--chromium/net/http/failing_http_transaction_factory.cc12
-rw-r--r--chromium/net/http/failing_http_transaction_factory.h1
-rw-r--r--chromium/net/http/http_auth.cc2
-rw-r--r--chromium/net/http/http_auth.h4
-rw-r--r--chromium/net/http/http_auth_cache.cc7
-rw-r--r--chromium/net/http/http_auth_cache.h12
-rw-r--r--chromium/net/http/http_auth_cache_unittest.cc38
-rw-r--r--chromium/net/http/http_auth_challenge_tokenizer_fuzzer.cc18
-rw-r--r--chromium/net/http/http_auth_controller.cc58
-rw-r--r--chromium/net/http/http_auth_controller.h18
-rw-r--r--chromium/net/http/http_auth_controller_unittest.cc17
-rw-r--r--chromium/net/http/http_auth_handler.cc11
-rw-r--r--chromium/net/http/http_auth_handler.h6
-rw-r--r--chromium/net/http/http_auth_handler_basic.cc2
-rw-r--r--chromium/net/http/http_auth_handler_basic.h2
-rw-r--r--chromium/net/http/http_auth_handler_basic_unittest.cc15
-rw-r--r--chromium/net/http/http_auth_handler_digest.cc2
-rw-r--r--chromium/net/http/http_auth_handler_digest.h2
-rw-r--r--chromium/net/http/http_auth_handler_digest_unittest.cc21
-rw-r--r--chromium/net/http/http_auth_handler_factory.cc10
-rw-r--r--chromium/net/http/http_auth_handler_factory.h12
-rw-r--r--chromium/net/http/http_auth_handler_factory_unittest.cc46
-rw-r--r--chromium/net/http/http_auth_handler_mock.cc75
-rw-r--r--chromium/net/http/http_auth_handler_mock.h16
-rw-r--r--chromium/net/http/http_auth_handler_negotiate.cc24
-rw-r--r--chromium/net/http/http_auth_handler_negotiate.h7
-rw-r--r--chromium/net/http/http_auth_handler_negotiate_unittest.cc27
-rw-r--r--chromium/net/http/http_auth_handler_ntlm.h3
-rw-r--r--chromium/net/http/http_auth_handler_ntlm_portable.cc2
-rw-r--r--chromium/net/http/http_auth_handler_ntlm_win.cc2
-rw-r--r--chromium/net/http/http_auth_handler_unittest.cc12
-rw-r--r--chromium/net/http/http_auth_scheme.cc1
-rw-r--r--chromium/net/http/http_auth_scheme.h2
-rw-r--r--chromium/net/http/http_auth_sspi_win_unittest.cc9
-rw-r--r--chromium/net/http/http_auth_unittest.cc9
-rw-r--r--chromium/net/http/http_basic_state.cc14
-rw-r--r--chromium/net/http/http_basic_state.h14
-rw-r--r--chromium/net/http/http_basic_state_unittest.cc42
-rw-r--r--chromium/net/http/http_basic_stream.cc28
-rw-r--r--chromium/net/http/http_basic_stream.h16
-rw-r--r--chromium/net/http/http_cache.cc11
-rw-r--r--chromium/net/http/http_cache_transaction.cc217
-rw-r--r--chromium/net/http/http_cache_transaction.h14
-rw-r--r--chromium/net/http/http_cache_unittest.cc537
-rw-r--r--chromium/net/http/http_chunked_decoder.cc33
-rw-r--r--chromium/net/http/http_chunked_decoder.h5
-rw-r--r--chromium/net/http/http_chunked_decoder_unittest.cc77
-rw-r--r--chromium/net/http/http_content_disposition.cc22
-rw-r--r--chromium/net/http/http_log_util.cc1
-rw-r--r--chromium/net/http/http_log_util.h3
-rw-r--r--chromium/net/http/http_log_util_unittest.cc2
-rw-r--r--chromium/net/http/http_network_layer_unittest.cc43
-rw-r--r--chromium/net/http/http_network_session.cc167
-rw-r--r--chromium/net/http/http_network_session.h61
-rw-r--r--chromium/net/http/http_network_session_peer.cc4
-rw-r--r--chromium/net/http/http_network_session_peer.h2
-rw-r--r--chromium/net/http/http_network_transaction.cc110
-rw-r--r--chromium/net/http/http_network_transaction.h11
-rw-r--r--chromium/net/http/http_network_transaction_ssl_unittest.cc17
-rw-r--r--chromium/net/http/http_network_transaction_unittest.cc6334
-rw-r--r--chromium/net/http/http_proxy_client_socket.cc27
-rw-r--r--chromium/net/http/http_proxy_client_socket.h12
-rw-r--r--chromium/net/http/http_proxy_client_socket_fuzzer.cc4
-rw-r--r--chromium/net/http/http_proxy_client_socket_pool.cc19
-rw-r--r--chromium/net/http/http_proxy_client_socket_pool.h5
-rw-r--r--chromium/net/http/http_proxy_client_socket_pool_unittest.cc266
-rw-r--r--chromium/net/http/http_proxy_client_socket_wrapper.cc28
-rw-r--r--chromium/net/http/http_proxy_client_socket_wrapper.h12
-rw-r--r--chromium/net/http/http_request_headers.cc35
-rw-r--r--chromium/net/http/http_request_headers.h10
-rw-r--r--chromium/net/http/http_request_headers_unittest.cc1
-rw-r--r--chromium/net/http/http_response_body_drainer_unittest.cc8
-rw-r--r--chromium/net/http/http_response_headers.cc1
-rw-r--r--chromium/net/http/http_response_headers.h4
-rw-r--r--chromium/net/http/http_response_headers_unittest.cc1
-rw-r--r--chromium/net/http/http_response_info.cc86
-rw-r--r--chromium/net/http/http_response_info.h19
-rw-r--r--chromium/net/http/http_response_info_unittest.cc99
-rw-r--r--chromium/net/http/http_security_headers_unittest.cc7
-rw-r--r--chromium/net/http/http_server_properties.cc69
-rw-r--r--chromium/net/http/http_server_properties.h31
-rw-r--r--chromium/net/http/http_server_properties_impl.cc40
-rw-r--r--chromium/net/http/http_server_properties_impl_unittest.cc12
-rw-r--r--chromium/net/http/http_server_properties_manager.cc17
-rw-r--r--chromium/net/http/http_server_properties_manager.h1
-rw-r--r--chromium/net/http/http_server_properties_manager_unittest.cc57
-rw-r--r--chromium/net/http/http_stream.h19
-rw-r--r--chromium/net/http/http_stream_factory.cc13
-rw-r--r--chromium/net/http/http_stream_factory.h29
-rw-r--r--chromium/net/http/http_stream_factory_impl.cc45
-rw-r--r--chromium/net/http/http_stream_factory_impl.h17
-rw-r--r--chromium/net/http/http_stream_factory_impl_job.cc588
-rw-r--r--chromium/net/http/http_stream_factory_impl_job.h236
-rw-r--r--chromium/net/http/http_stream_factory_impl_job_controller.cc375
-rw-r--r--chromium/net/http/http_stream_factory_impl_job_controller.h83
-rw-r--r--chromium/net/http/http_stream_factory_impl_job_controller_unittest.cc731
-rw-r--r--chromium/net/http/http_stream_factory_impl_request.cc28
-rw-r--r--chromium/net/http/http_stream_factory_impl_request.h20
-rw-r--r--chromium/net/http/http_stream_factory_impl_request_unittest.cc91
-rw-r--r--chromium/net/http/http_stream_factory_impl_unittest.cc614
-rw-r--r--chromium/net/http/http_stream_factory_test_util.cc36
-rw-r--r--chromium/net/http/http_stream_factory_test_util.h29
-rw-r--r--chromium/net/http/http_stream_parser.cc110
-rw-r--r--chromium/net/http/http_stream_parser.h33
-rw-r--r--chromium/net/http/http_stream_parser_fuzzer.cc5
-rw-r--r--chromium/net/http/http_stream_parser_unittest.cc399
-rw-r--r--chromium/net/http/http_transaction.h8
-rw-r--r--chromium/net/http/http_transaction_test_util.cc21
-rw-r--r--chromium/net/http/http_transaction_test_util.h13
-rw-r--r--chromium/net/http/http_util.cc68
-rw-r--r--chromium/net/http/http_util.h16
-rw-r--r--chromium/net/http/http_util_unittest.cc41
-rw-r--r--chromium/net/http/mock_http_cache.cc4
-rw-r--r--chromium/net/http/proxy_client_socket.cc7
-rw-r--r--chromium/net/http/proxy_client_socket.h6
-rw-r--r--chromium/net/http/proxy_connect_redirect_http_stream.cc9
-rw-r--r--chromium/net/http/proxy_connect_redirect_http_stream.h8
-rw-r--r--chromium/net/http/transport_security_persister_unittest.cc12
-rw-r--r--chromium/net/http/transport_security_state.cc182
-rw-r--r--chromium/net/http/transport_security_state.h33
-rw-r--r--chromium/net/http/transport_security_state_ct_policies.inc3
-rw-r--r--chromium/net/http/transport_security_state_static.h21221
-rw-r--r--chromium/net/http/transport_security_state_static.json1866
-rw-r--r--chromium/net/http/transport_security_state_unittest.cc348
-rw-r--r--chromium/net/interfaces/BUILD.gn2
-rw-r--r--chromium/net/log/bounded_file_net_log_observer.cc405
-rw-r--r--chromium/net/log/bounded_file_net_log_observer.h136
-rw-r--r--chromium/net/log/bounded_file_net_log_observer_unittest.cc860
-rw-r--r--chromium/net/log/net_log.cc313
-rw-r--r--chromium/net/log/net_log.h240
-rw-r--r--chromium/net/log/net_log_entry.cc69
-rw-r--r--chromium/net/log/net_log_entry.h73
-rw-r--r--chromium/net/log/net_log_event_type.h27
-rw-r--r--chromium/net/log/net_log_event_type_list.h157
-rw-r--r--chromium/net/log/net_log_parameters_callback.h28
-rw-r--r--chromium/net/log/net_log_source.cc78
-rw-r--r--chromium/net/log/net_log_source.h52
-rw-r--r--chromium/net/log/net_log_source_type.h20
-rw-r--r--chromium/net/log/net_log_source_type_list.h1
-rw-r--r--chromium/net/log/net_log_unittest.cc32
-rw-r--r--chromium/net/log/net_log_util.cc43
-rw-r--r--chromium/net/log/net_log_util.h2
-rw-r--r--chromium/net/log/net_log_util_unittest.cc2
-rw-r--r--chromium/net/log/net_log_with_source.cc145
-rw-r--r--chromium/net/log/net_log_with_source.h97
-rwxr-xr-xchromium/net/log/stitch_net_log_files.py92
-rw-r--r--chromium/net/log/test_net_log.cc14
-rw-r--r--chromium/net/log/test_net_log.h18
-rw-r--r--chromium/net/log/test_net_log_entry.cc6
-rw-r--r--chromium/net/log/test_net_log_entry.h17
-rw-r--r--chromium/net/log/test_net_log_util.cc32
-rw-r--r--chromium/net/log/test_net_log_util.h22
-rw-r--r--chromium/net/log/trace_net_log_observer.cc11
-rw-r--r--chromium/net/log/trace_net_log_observer.h2
-rw-r--r--chromium/net/log/trace_net_log_observer_unittest.cc61
-rw-r--r--chromium/net/log/write_to_file_net_log_observer.cc3
-rw-r--r--chromium/net/log/write_to_file_net_log_observer.h3
-rw-r--r--chromium/net/log/write_to_file_net_log_observer_unittest.cc26
-rw-r--r--chromium/net/net.gyp1784
-rw-r--r--chromium/net/net.gypi864
-rw-r--r--chromium/net/net_common.gypi366
-rw-r--r--chromium/net/net_nacl.gyp45
-rw-r--r--chromium/net/net_unittests.isolate55
-rw-r--r--chromium/net/net_unittests_apk.isolate26
-rw-r--r--chromium/net/nqe/cached_network_quality.cc20
-rw-r--r--chromium/net/nqe/cached_network_quality.h28
-rw-r--r--chromium/net/nqe/effective_connection_type.cc74
-rw-r--r--chromium/net/nqe/effective_connection_type.h70
-rw-r--r--chromium/net/nqe/effective_connection_type_unittest.cc53
-rw-r--r--chromium/net/nqe/network_id.h68
-rw-r--r--chromium/net/nqe/network_qualities_prefs_manager.cc80
-rw-r--r--chromium/net/nqe/network_qualities_prefs_manager.h104
-rw-r--r--chromium/net/nqe/network_qualities_prefs_manager_unittest.cc75
-rw-r--r--chromium/net/nqe/network_quality.cc21
-rw-r--r--chromium/net/nqe/network_quality.h20
-rw-r--r--chromium/net/nqe/network_quality_estimator.cc917
-rw-r--r--chromium/net/nqe/network_quality_estimator.h283
-rw-r--r--chromium/net/nqe/network_quality_estimator_test_util.cc191
-rw-r--r--chromium/net/nqe/network_quality_estimator_test_util.h197
-rw-r--r--chromium/net/nqe/network_quality_estimator_unittest.cc1580
-rw-r--r--chromium/net/nqe/network_quality_observation_source.h4
-rw-r--r--chromium/net/nqe/network_quality_observation_unittest.cc332
-rw-r--r--chromium/net/nqe/network_quality_store.cc101
-rw-r--r--chromium/net/nqe/network_quality_store.h100
-rw-r--r--chromium/net/nqe/network_quality_store_unittest.cc189
-rw-r--r--chromium/net/nqe/observation_buffer.h18
-rw-r--r--chromium/net/nqe/observation_buffer_unittest.cc397
-rw-r--r--chromium/net/nqe/throughput_analyzer_unittest.cc2
-rw-r--r--chromium/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc26
-rw-r--r--chromium/net/proxy/dhcp_proxy_script_fetcher_factory.cc2
-rw-r--r--chromium/net/proxy/dhcp_proxy_script_fetcher_win.cc4
-rw-r--r--chromium/net/proxy/dhcp_proxy_script_fetcher_win.h1
-rw-r--r--chromium/net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc19
-rw-r--r--chromium/net/proxy/dhcpcsvc_init_win.cc11
-rw-r--r--chromium/net/proxy/in_process_mojo_proxy_resolver_factory.cc7
-rw-r--r--chromium/net/proxy/mock_proxy_resolver.cc15
-rw-r--r--chromium/net/proxy/mock_proxy_resolver.h4
-rw-r--r--chromium/net/proxy/mojo_proxy_resolver_factory_impl.cc73
-rw-r--r--chromium/net/proxy/mojo_proxy_resolver_factory_impl.h14
-rw-r--r--chromium/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc15
-rw-r--r--chromium/net/proxy/mojo_proxy_resolver_impl.cc22
-rw-r--r--chromium/net/proxy/mojo_proxy_resolver_impl.h3
-rw-r--r--chromium/net/proxy/mojo_proxy_resolver_impl_unittest.cc13
-rw-r--r--chromium/net/proxy/mojo_proxy_resolver_v8_tracing_bindings.h8
-rw-r--r--chromium/net/proxy/mojo_proxy_resolver_v8_tracing_bindings_unittest.cc2
-rw-r--r--chromium/net/proxy/multi_threaded_proxy_resolver.cc23
-rw-r--r--chromium/net/proxy/multi_threaded_proxy_resolver_unittest.cc157
-rw-r--r--chromium/net/proxy/network_delegate_error_observer.h1
-rw-r--r--chromium/net/proxy/network_delegate_error_observer_unittest.cc4
-rw-r--r--chromium/net/proxy/parse_proxy_bypass_rules_fuzzer.cc1
-rw-r--r--chromium/net/proxy/polling_proxy_config_service.h1
-rw-r--r--chromium/net/proxy/proxy_bypass_rules.cc34
-rw-r--r--chromium/net/proxy/proxy_bypass_rules.h9
-rw-r--r--chromium/net/proxy/proxy_config.h1
-rw-r--r--chromium/net/proxy/proxy_config_service_android.cc12
-rw-r--r--chromium/net/proxy/proxy_config_service_android_unittest.cc5
-rw-r--r--chromium/net/proxy/proxy_config_service_fixed.h1
-rw-r--r--chromium/net/proxy/proxy_config_service_win.cc20
-rw-r--r--chromium/net/proxy/proxy_config_service_win.h5
-rw-r--r--chromium/net/proxy/proxy_info.cc2
-rw-r--r--chromium/net/proxy/proxy_info.h5
-rw-r--r--chromium/net/proxy/proxy_info_unittest.cc6
-rw-r--r--chromium/net/proxy/proxy_list.cc11
-rw-r--r--chromium/net/proxy/proxy_list.h9
-rw-r--r--chromium/net/proxy/proxy_list_unittest.cc20
-rw-r--r--chromium/net/proxy/proxy_resolver.h4
-rw-r--r--chromium/net/proxy/proxy_resolver_factory_mojo.cc35
-rw-r--r--chromium/net/proxy/proxy_resolver_factory_mojo_unittest.cc98
-rw-r--r--chromium/net/proxy/proxy_resolver_mac.cc4
-rw-r--r--chromium/net/proxy/proxy_resolver_perftest.cc27
-rw-r--r--chromium/net/proxy/proxy_resolver_v8_tracing.cc19
-rw-r--r--chromium/net/proxy/proxy_resolver_v8_tracing.h5
-rw-r--r--chromium/net/proxy/proxy_resolver_v8_tracing_unittest.cc79
-rw-r--r--chromium/net/proxy/proxy_resolver_v8_tracing_wrapper.cc31
-rw-r--r--chromium/net/proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc189
-rw-r--r--chromium/net/proxy/proxy_resolver_v8_unittest.cc88
-rw-r--r--chromium/net/proxy/proxy_resolver_winhttp.cc4
-rw-r--r--chromium/net/proxy/proxy_script_decider.cc48
-rw-r--r--chromium/net/proxy/proxy_script_decider.h14
-rw-r--r--chromium/net/proxy/proxy_script_decider_unittest.cc105
-rw-r--r--chromium/net/proxy/proxy_script_fetcher_impl.cc33
-rw-r--r--chromium/net/proxy/proxy_script_fetcher_impl.h5
-rw-r--r--chromium/net/proxy/proxy_script_fetcher_impl_unittest.cc89
-rw-r--r--chromium/net/proxy/proxy_service.cc125
-rw-r--r--chromium/net/proxy/proxy_service.h21
-rw-r--r--chromium/net/proxy/proxy_service_mojo.cc4
-rw-r--r--chromium/net/proxy/proxy_service_mojo_unittest.cc69
-rw-r--r--chromium/net/proxy/proxy_service_unittest.cc940
-rw-r--r--chromium/net/proxy/proxy_service_v8.cc4
-rw-r--r--chromium/net/quic/bidirectional_stream_quic_impl.cc357
-rw-r--r--chromium/net/quic/bidirectional_stream_quic_impl.h133
-rw-r--r--chromium/net/quic/bidirectional_stream_quic_impl_unittest.cc1675
-rw-r--r--chromium/net/quic/chromium/bidirectional_stream_quic_impl.cc359
-rw-r--r--chromium/net/quic/chromium/bidirectional_stream_quic_impl.h142
-rw-r--r--chromium/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc1779
-rw-r--r--chromium/net/quic/chromium/crypto/channel_id_chromium.cc224
-rw-r--r--chromium/net/quic/chromium/crypto/channel_id_chromium.h66
-rw-r--r--chromium/net/quic/chromium/crypto/proof_source_chromium.cc169
-rw-r--r--chromium/net/quic/chromium/crypto/proof_source_chromium.h62
-rw-r--r--chromium/net/quic/chromium/crypto/proof_test_chromium.cc484
-rw-r--r--chromium/net/quic/chromium/crypto/proof_verifier_chromium.cc625
-rw-r--r--chromium/net/quic/chromium/crypto/proof_verifier_chromium.h118
-rw-r--r--chromium/net/quic/chromium/crypto/proof_verifier_chromium_test.cc622
-rw-r--r--chromium/net/quic/chromium/crypto_test_utils_chromium.cc139
-rw-r--r--chromium/net/quic/chromium/mock_network_change_notifier.cc87
-rw-r--r--chromium/net/quic/chromium/mock_network_change_notifier.h69
-rw-r--r--chromium/net/quic/chromium/mock_quic_data.cc68
-rw-r--r--chromium/net/quic/chromium/mock_quic_data.h64
-rw-r--r--chromium/net/quic/chromium/network_connection.cc75
-rw-r--r--chromium/net/quic/chromium/network_connection.h (renamed from chromium/net/quic/network_connection.h)0
-rw-r--r--chromium/net/quic/chromium/network_connection_unittest.cc80
-rw-r--r--chromium/net/quic/chromium/port_suggester.cc47
-rw-r--r--chromium/net/quic/chromium/port_suggester.h (renamed from chromium/net/quic/port_suggester.h)0
-rw-r--r--chromium/net/quic/chromium/port_suggester_unittest.cc108
-rw-r--r--chromium/net/quic/chromium/quic_chromium_alarm_factory.cc117
-rw-r--r--chromium/net/quic/chromium/quic_chromium_alarm_factory.h49
-rw-r--r--chromium/net/quic/chromium/quic_chromium_alarm_factory_test.cc172
-rw-r--r--chromium/net/quic/chromium/quic_chromium_client_session.cc1418
-rw-r--r--chromium/net/quic/chromium/quic_chromium_client_session.h400
-rw-r--r--chromium/net/quic/chromium/quic_chromium_client_session_peer.cc37
-rw-r--r--chromium/net/quic/chromium/quic_chromium_client_session_peer.h40
-rw-r--r--chromium/net/quic/chromium/quic_chromium_client_session_test.cc568
-rw-r--r--chromium/net/quic/chromium/quic_chromium_client_stream.cc338
-rw-r--r--chromium/net/quic/chromium/quic_chromium_client_stream.h162
-rw-r--r--chromium/net/quic/chromium/quic_chromium_client_stream_test.cc648
-rw-r--r--chromium/net/quic/chromium/quic_chromium_connection_helper.cc28
-rw-r--r--chromium/net/quic/chromium/quic_chromium_connection_helper.h47
-rw-r--r--chromium/net/quic/chromium/quic_chromium_connection_helper_test.cc34
-rw-r--r--chromium/net/quic/chromium/quic_chromium_packet_reader.cc90
-rw-r--r--chromium/net/quic/chromium/quic_chromium_packet_reader.h74
-rw-r--r--chromium/net/quic/chromium/quic_chromium_packet_writer.cc117
-rw-r--r--chromium/net/quic/chromium/quic_chromium_packet_writer.h87
-rw-r--r--chromium/net/quic/chromium/quic_connection_logger.cc750
-rw-r--r--chromium/net/quic/chromium/quic_connection_logger.h168
-rw-r--r--chromium/net/quic/chromium/quic_end_to_end_unittest.cc374
-rw-r--r--chromium/net/quic/chromium/quic_http_stream.cc834
-rw-r--r--chromium/net/quic/chromium/quic_http_stream.h233
-rw-r--r--chromium/net/quic/chromium/quic_http_stream_test.cc2069
-rw-r--r--chromium/net/quic/chromium/quic_network_transaction_unittest.cc3283
-rw-r--r--chromium/net/quic/chromium/quic_stream_factory.cc1929
-rw-r--r--chromium/net/quic/chromium/quic_stream_factory.h665
-rw-r--r--chromium/net/quic/chromium/quic_stream_factory_test.cc5316
-rw-r--r--chromium/net/quic/chromium/quic_utils_chromium.h (renamed from chromium/net/quic/quic_utils_chromium.h)0
-rw-r--r--chromium/net/quic/chromium/quic_utils_chromium_test.cc50
-rw-r--r--chromium/net/quic/congestion_control/cubic.cc197
-rw-r--r--chromium/net/quic/congestion_control/cubic.h100
-rw-r--r--chromium/net/quic/congestion_control/cubic_bytes.cc175
-rw-r--r--chromium/net/quic/congestion_control/cubic_bytes.h97
-rw-r--r--chromium/net/quic/congestion_control/cubic_bytes_test.cc120
-rw-r--r--chromium/net/quic/congestion_control/cubic_test.cc113
-rw-r--r--chromium/net/quic/congestion_control/general_loss_algorithm.cc143
-rw-r--r--chromium/net/quic/congestion_control/general_loss_algorithm.h70
-rw-r--r--chromium/net/quic/congestion_control/general_loss_algorithm_test.cc359
-rw-r--r--chromium/net/quic/congestion_control/hybrid_slow_start.cc107
-rw-r--r--chromium/net/quic/congestion_control/hybrid_slow_start.h84
-rw-r--r--chromium/net/quic/congestion_control/hybrid_slow_start_test.cc76
-rw-r--r--chromium/net/quic/congestion_control/loss_detection_interface.h48
-rw-r--r--chromium/net/quic/congestion_control/pacing_sender.cc195
-rw-r--r--chromium/net/quic/congestion_control/pacing_sender.h94
-rw-r--r--chromium/net/quic/congestion_control/pacing_sender_test.cc408
-rw-r--r--chromium/net/quic/congestion_control/prr_sender.cc71
-rw-r--r--chromium/net/quic/congestion_control/prr_sender.h44
-rw-r--r--chromium/net/quic/congestion_control/prr_sender_test.cc134
-rw-r--r--chromium/net/quic/congestion_control/rtt_stats.cc131
-rw-r--r--chromium/net/quic/congestion_control/rtt_stats.h109
-rw-r--r--chromium/net/quic/congestion_control/rtt_stats_test.cc202
-rw-r--r--chromium/net/quic/congestion_control/send_algorithm_interface.cc58
-rw-r--r--chromium/net/quic/congestion_control/send_algorithm_interface.h127
-rw-r--r--chromium/net/quic/congestion_control/send_algorithm_simulator.cc394
-rw-r--r--chromium/net/quic/congestion_control/send_algorithm_simulator.h238
-rw-r--r--chromium/net/quic/congestion_control/tcp_cubic_sender_base.cc288
-rw-r--r--chromium/net/quic/congestion_control/tcp_cubic_sender_base.h158
-rw-r--r--chromium/net/quic/congestion_control/tcp_cubic_sender_bytes.cc224
-rw-r--r--chromium/net/quic/congestion_control/tcp_cubic_sender_bytes.h104
-rw-r--r--chromium/net/quic/congestion_control/tcp_cubic_sender_bytes_test.cc898
-rw-r--r--chromium/net/quic/congestion_control/tcp_cubic_sender_packets.cc225
-rw-r--r--chromium/net/quic/congestion_control/tcp_cubic_sender_packets.h106
-rw-r--r--chromium/net/quic/congestion_control/tcp_cubic_sender_packets_test.cc1050
-rw-r--r--chromium/net/quic/congestion_control/windowed_filter.h146
-rw-r--r--chromium/net/quic/congestion_control/windowed_filter_test.cc330
-rw-r--r--chromium/net/quic/core/congestion_control/cubic.cc190
-rw-r--r--chromium/net/quic/core/congestion_control/cubic.h105
-rw-r--r--chromium/net/quic/core/congestion_control/cubic_bytes.cc183
-rw-r--r--chromium/net/quic/core/congestion_control/cubic_bytes.h97
-rw-r--r--chromium/net/quic/core/congestion_control/cubic_bytes_test.cc128
-rw-r--r--chromium/net/quic/core/congestion_control/cubic_test.cc114
-rw-r--r--chromium/net/quic/core/congestion_control/general_loss_algorithm.cc145
-rw-r--r--chromium/net/quic/core/congestion_control/general_loss_algorithm.h74
-rw-r--r--chromium/net/quic/core/congestion_control/general_loss_algorithm_test.cc390
-rw-r--r--chromium/net/quic/core/congestion_control/hybrid_slow_start.cc107
-rw-r--r--chromium/net/quic/core/congestion_control/hybrid_slow_start.h84
-rw-r--r--chromium/net/quic/core/congestion_control/hybrid_slow_start_test.cc76
-rw-r--r--chromium/net/quic/core/congestion_control/loss_detection_interface.h49
-rw-r--r--chromium/net/quic/core/congestion_control/pacing_sender.cc154
-rw-r--r--chromium/net/quic/core/congestion_control/pacing_sender.h75
-rw-r--r--chromium/net/quic/core/congestion_control/pacing_sender_test.cc349
-rw-r--r--chromium/net/quic/core/congestion_control/prr_sender.cc71
-rw-r--r--chromium/net/quic/core/congestion_control/prr_sender.h45
-rw-r--r--chromium/net/quic/core/congestion_control/prr_sender_test.cc134
-rw-r--r--chromium/net/quic/core/congestion_control/rtt_stats.cc130
-rw-r--r--chromium/net/quic/core/congestion_control/rtt_stats.h114
-rw-r--r--chromium/net/quic/core/congestion_control/rtt_stats_test.cc217
-rw-r--r--chromium/net/quic/core/congestion_control/send_algorithm_interface.cc46
-rw-r--r--chromium/net/quic/core/congestion_control/send_algorithm_interface.h137
-rw-r--r--chromium/net/quic/core/congestion_control/send_algorithm_simulator.cc400
-rw-r--r--chromium/net/quic/core/congestion_control/send_algorithm_simulator.h245
-rw-r--r--chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.cc285
-rw-r--r--chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.h159
-rw-r--r--chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc217
-rw-r--r--chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h103
-rw-r--r--chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc895
-rw-r--r--chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets.cc218
-rw-r--r--chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets.h105
-rw-r--r--chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets_test.cc1005
-rw-r--r--chromium/net/quic/core/congestion_control/windowed_filter.h156
-rw-r--r--chromium/net/quic/core/congestion_control/windowed_filter_test.cc392
-rw-r--r--chromium/net/quic/core/crypto/aead_base_decrypter.cc168
-rw-r--r--chromium/net/quic/core/crypto/aead_base_decrypter.h68
-rw-r--r--chromium/net/quic/core/crypto/aead_base_encrypter.cc164
-rw-r--r--chromium/net/quic/core/crypto/aead_base_encrypter.h76
-rw-r--r--chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter.cc42
-rw-r--r--chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter.h42
-rw-r--r--chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc287
-rw-r--r--chromium/net/quic/core/crypto/aes_128_gcm_12_encrypter.cc30
-rw-r--r--chromium/net/quic/core/crypto/aes_128_gcm_12_encrypter.h38
-rw-r--r--chromium/net/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc238
-rw-r--r--chromium/net/quic/core/crypto/cert_compressor.cc647
-rw-r--r--chromium/net/quic/core/crypto/cert_compressor.h58
-rw-r--r--chromium/net/quic/core/crypto/cert_compressor_test.cc129
-rw-r--r--chromium/net/quic/core/crypto/chacha20_poly1305_decrypter.cc39
-rw-r--r--chromium/net/quic/core/crypto/chacha20_poly1305_decrypter.h43
-rw-r--r--chromium/net/quic/core/crypto/chacha20_poly1305_decrypter_test.cc177
-rw-r--r--chromium/net/quic/core/crypto/chacha20_poly1305_encrypter.cc30
-rw-r--r--chromium/net/quic/core/crypto/chacha20_poly1305_encrypter.h39
-rw-r--r--chromium/net/quic/core/crypto/chacha20_poly1305_encrypter_test.cc154
-rw-r--r--chromium/net/quic/core/crypto/channel_id.cc91
-rw-r--r--chromium/net/quic/core/crypto/channel_id.h99
-rw-r--r--chromium/net/quic/core/crypto/channel_id_test.cc274
-rw-r--r--chromium/net/quic/core/crypto/common_cert_set.cc168
-rw-r--r--chromium/net/quic/core/crypto/common_cert_set.h48
-rw-r--r--chromium/net/quic/core/crypto/common_cert_set_2.c129
-rw-r--r--chromium/net/quic/core/crypto/common_cert_set_2a.inc (renamed from chromium/net/quic/crypto/common_cert_set_2a.inc)0
-rw-r--r--chromium/net/quic/core/crypto/common_cert_set_2b.inc (renamed from chromium/net/quic/crypto/common_cert_set_2b.inc)0
-rw-r--r--chromium/net/quic/core/crypto/common_cert_set_3.c123
-rw-r--r--chromium/net/quic/core/crypto/common_cert_set_3a.inc (renamed from chromium/net/quic/crypto/common_cert_set_3a.inc)0
-rw-r--r--chromium/net/quic/core/crypto/common_cert_set_3b.inc (renamed from chromium/net/quic/crypto/common_cert_set_3b.inc)0
-rw-r--r--chromium/net/quic/core/crypto/common_cert_set_test.cc249
-rw-r--r--chromium/net/quic/core/crypto/crypto_framer.cc294
-rw-r--r--chromium/net/quic/core/crypto/crypto_framer.h118
-rw-r--r--chromium/net/quic/core/crypto/crypto_framer_test.cc471
-rw-r--r--chromium/net/quic/core/crypto/crypto_handshake.cc43
-rw-r--r--chromium/net/quic/core/crypto/crypto_handshake.h192
-rw-r--r--chromium/net/quic/core/crypto/crypto_handshake_message.cc328
-rw-r--r--chromium/net/quic/core/crypto/crypto_handshake_message.h140
-rw-r--r--chromium/net/quic/core/crypto/crypto_handshake_message_test.cc129
-rw-r--r--chromium/net/quic/core/crypto/crypto_protocol.h258
-rw-r--r--chromium/net/quic/core/crypto/crypto_secret_boxer.cc132
-rw-r--r--chromium/net/quic/core/crypto/crypto_secret_boxer.h (renamed from chromium/net/quic/crypto/crypto_secret_boxer.h)0
-rw-r--r--chromium/net/quic/core/crypto/crypto_secret_boxer_test.cc81
-rw-r--r--chromium/net/quic/core/crypto/crypto_server_config_protobuf.cc18
-rw-r--r--chromium/net/quic/core/crypto/crypto_server_config_protobuf.h115
-rw-r--r--chromium/net/quic/core/crypto/crypto_server_test.cc1288
-rw-r--r--chromium/net/quic/core/crypto/crypto_utils.cc340
-rw-r--r--chromium/net/quic/core/crypto/crypto_utils.h170
-rw-r--r--chromium/net/quic/core/crypto/crypto_utils_test.cc195
-rw-r--r--chromium/net/quic/core/crypto/curve25519_key_exchange.cc86
-rw-r--r--chromium/net/quic/core/crypto/curve25519_key_exchange.h51
-rw-r--r--chromium/net/quic/core/crypto/curve25519_key_exchange_test.cc44
-rw-r--r--chromium/net/quic/core/crypto/ephemeral_key_source.h42
-rw-r--r--chromium/net/quic/core/crypto/key_exchange.h47
-rw-r--r--chromium/net/quic/core/crypto/local_strike_register_client.cc52
-rw-r--r--chromium/net/quic/core/crypto/local_strike_register_client.h45
-rw-r--r--chromium/net/quic/core/crypto/local_strike_register_client_test.cc134
-rw-r--r--chromium/net/quic/core/crypto/null_decrypter.cc104
-rw-r--r--chromium/net/quic/core/crypto/null_decrypter.h55
-rw-r--r--chromium/net/quic/core/crypto/null_decrypter_test.cc67
-rw-r--r--chromium/net/quic/core/crypto/null_encrypter.cc78
-rw-r--r--chromium/net/quic/core/crypto/null_encrypter.h50
-rw-r--r--chromium/net/quic/core/crypto/null_encrypter_test.cc48
-rw-r--r--chromium/net/quic/core/crypto/p256_key_exchange.cc119
-rw-r--r--chromium/net/quic/core/crypto/p256_key_exchange.h69
-rw-r--r--chromium/net/quic/core/crypto/p256_key_exchange_test.cc45
-rw-r--r--chromium/net/quic/core/crypto/proof_source.cc14
-rw-r--r--chromium/net/quic/core/crypto/proof_source.h136
-rw-r--r--chromium/net/quic/core/crypto/proof_verifier.h113
-rw-r--r--chromium/net/quic/core/crypto/properties_based_quic_server_info.cc107
-rw-r--r--chromium/net/quic/core/crypto/properties_based_quic_server_info.h63
-rw-r--r--chromium/net/quic/core/crypto/properties_based_quic_server_info_test.cc110
-rw-r--r--chromium/net/quic/core/crypto/quic_compressed_certs_cache.cc124
-rw-r--r--chromium/net/quic/core/crypto/quic_compressed_certs_cache.h109
-rw-r--r--chromium/net/quic/core/crypto/quic_compressed_certs_cache_test.cc91
-rw-r--r--chromium/net/quic/core/crypto/quic_crypto_client_config.cc997
-rw-r--r--chromium/net/quic/core/crypto/quic_crypto_client_config.h392
-rw-r--r--chromium/net/quic/core/crypto/quic_crypto_client_config_test.cc539
-rw-r--r--chromium/net/quic/core/crypto/quic_crypto_server_config.cc2164
-rw-r--r--chromium/net/quic/core/crypto/quic_crypto_server_config.h856
-rw-r--r--chromium/net/quic/core/crypto/quic_crypto_server_config_test.cc549
-rw-r--r--chromium/net/quic/core/crypto/quic_decrypter.cc49
-rw-r--r--chromium/net/quic/core/crypto/quic_decrypter.h98
-rw-r--r--chromium/net/quic/core/crypto/quic_encrypter.cc29
-rw-r--r--chromium/net/quic/core/crypto/quic_encrypter.h85
-rw-r--r--chromium/net/quic/core/crypto/quic_random.cc59
-rw-r--r--chromium/net/quic/core/crypto/quic_random.h (renamed from chromium/net/quic/crypto/quic_random.h)0
-rw-r--r--chromium/net/quic/core/crypto/quic_random_test.cc40
-rw-r--r--chromium/net/quic/core/crypto/quic_server_info.cc163
-rw-r--r--chromium/net/quic/core/crypto/quic_server_info.h181
-rw-r--r--chromium/net/quic/core/crypto/scoped_evp_aead_ctx.cc23
-rw-r--r--chromium/net/quic/core/crypto/scoped_evp_aead_ctx.h (renamed from chromium/net/quic/crypto/scoped_evp_aead_ctx.h)0
-rw-r--r--chromium/net/quic/core/crypto/strike_register.cc519
-rw-r--r--chromium/net/quic/core/crypto/strike_register.h (renamed from chromium/net/quic/crypto/strike_register.h)0
-rw-r--r--chromium/net/quic/core/crypto/strike_register_client.h60
-rw-r--r--chromium/net/quic/core/crypto/strike_register_test.cc407
-rw-r--r--chromium/net/quic/core/interval.h302
-rw-r--r--chromium/net/quic/core/interval_set.h857
-rw-r--r--chromium/net/quic/core/interval_set_test.cc981
-rw-r--r--chromium/net/quic/core/interval_test.cc283
-rw-r--r--chromium/net/quic/core/iovector.cc15
-rw-r--r--chromium/net/quic/core/iovector.h (renamed from chromium/net/quic/iovector.h)0
-rw-r--r--chromium/net/quic/core/iovector_test.cc373
-rw-r--r--chromium/net/quic/core/proto/cached_network_parameters.proto (renamed from chromium/net/quic/proto/cached_network_parameters.proto)0
-rw-r--r--chromium/net/quic/core/proto/source_address_token.proto (renamed from chromium/net/quic/proto/source_address_token.proto)0
-rw-r--r--chromium/net/quic/core/quic_address_mismatch.cc51
-rw-r--r--chromium/net/quic/core/quic_address_mismatch.h (renamed from chromium/net/quic/quic_address_mismatch.h)0
-rw-r--r--chromium/net/quic/core/quic_address_mismatch_test.cc99
-rw-r--r--chromium/net/quic/core/quic_alarm.cc76
-rw-r--r--chromium/net/quic/core/quic_alarm.h89
-rw-r--r--chromium/net/quic/core/quic_alarm_factory.h40
-rw-r--r--chromium/net/quic/core/quic_alarm_test.cc168
-rw-r--r--chromium/net/quic/core/quic_arena_scoped_ptr.h210
-rw-r--r--chromium/net/quic/core/quic_arena_scoped_ptr_test.cc102
-rw-r--r--chromium/net/quic/core/quic_bandwidth.cc143
-rw-r--r--chromium/net/quic/core/quic_bandwidth.h124
-rw-r--r--chromium/net/quic/core/quic_bandwidth_test.cc121
-rw-r--r--chromium/net/quic/core/quic_blocked_writer_interface.h (renamed from chromium/net/quic/quic_blocked_writer_interface.h)0
-rw-r--r--chromium/net/quic/core/quic_buffered_packet_store.cc223
-rw-r--r--chromium/net/quic/core/quic_buffered_packet_store.h161
-rw-r--r--chromium/net/quic/core/quic_buffered_packet_store_test.cc482
-rw-r--r--chromium/net/quic/core/quic_bug_tracker.h (renamed from chromium/net/quic/quic_bug_tracker.h)0
-rw-r--r--chromium/net/quic/core/quic_client_promised_info.cc123
-rw-r--r--chromium/net/quic/core/quic_client_promised_info.h113
-rw-r--r--chromium/net/quic/core/quic_client_promised_info_test.cc377
-rw-r--r--chromium/net/quic/core/quic_client_push_promise_index.cc49
-rw-r--r--chromium/net/quic/core/quic_client_push_promise_index.h99
-rw-r--r--chromium/net/quic/core/quic_client_push_promise_index_test.cc108
-rw-r--r--chromium/net/quic/core/quic_client_session_base.cc208
-rw-r--r--chromium/net/quic/core/quic_client_session_base.h140
-rw-r--r--chromium/net/quic/core/quic_clock.cc48
-rw-r--r--chromium/net/quic/core/quic_clock.h44
-rw-r--r--chromium/net/quic/core/quic_clock_test.cc38
-rw-r--r--chromium/net/quic/core/quic_config.cc762
-rw-r--r--chromium/net/quic/core/quic_config.h460
-rw-r--r--chromium/net/quic/core/quic_config_test.cc255
-rw-r--r--chromium/net/quic/core/quic_connection.cc2599
-rw-r--r--chromium/net/quic/core/quic_connection.h1121
-rw-r--r--chromium/net/quic/core/quic_connection_stats.cc49
-rw-r--r--chromium/net/quic/core/quic_connection_stats.h93
-rw-r--r--chromium/net/quic/core/quic_connection_test.cc5265
-rw-r--r--chromium/net/quic/core/quic_crypto_client_stream.cc678
-rw-r--r--chromium/net/quic/core/quic_crypto_client_stream.h277
-rw-r--r--chromium/net/quic/core/quic_crypto_client_stream_factory.cc40
-rw-r--r--chromium/net/quic/core/quic_crypto_client_stream_factory.h38
-rw-r--r--chromium/net/quic/core/quic_crypto_client_stream_test.cc388
-rw-r--r--chromium/net/quic/core/quic_crypto_framer_parse_message_fuzzer.cc18
-rw-r--r--chromium/net/quic/core/quic_crypto_server_stream.cc514
-rw-r--r--chromium/net/quic/core/quic_crypto_server_stream.h275
-rw-r--r--chromium/net/quic/core/quic_crypto_server_stream_test.cc629
-rw-r--r--chromium/net/quic/core/quic_crypto_stream.cc120
-rw-r--r--chromium/net/quic/core/quic_crypto_stream.h92
-rw-r--r--chromium/net/quic/core/quic_crypto_stream_test.cc115
-rw-r--r--chromium/net/quic/core/quic_data_reader.cc133
-rw-r--r--chromium/net/quic/core/quic_data_reader.h (renamed from chromium/net/quic/quic_data_reader.h)0
-rw-r--r--chromium/net/quic/core/quic_data_writer.cc145
-rw-r--r--chromium/net/quic/core/quic_data_writer.h76
-rw-r--r--chromium/net/quic/core/quic_data_writer_test.cc204
-rw-r--r--chromium/net/quic/core/quic_flags.cc9
-rw-r--r--chromium/net/quic/core/quic_flags.h16
-rw-r--r--chromium/net/quic/core/quic_flags_list.h164
-rw-r--r--chromium/net/quic/core/quic_flow_controller.cc254
-rw-r--r--chromium/net/quic/core/quic_flow_controller.h171
-rw-r--r--chromium/net/quic/core/quic_flow_controller_test.cc376
-rw-r--r--chromium/net/quic/core/quic_frame_list.cc254
-rw-r--r--chromium/net/quic/core/quic_frame_list.h82
-rw-r--r--chromium/net/quic/core/quic_framer.cc2650
-rw-r--r--chromium/net/quic/core/quic_framer.h629
-rw-r--r--chromium/net/quic/core/quic_framer_test.cc7276
-rw-r--r--chromium/net/quic/core/quic_header_list.cc58
-rw-r--r--chromium/net/quic/core/quic_header_list.h61
-rw-r--r--chromium/net/quic/core/quic_header_list_test.cc36
-rw-r--r--chromium/net/quic/core/quic_headers_stream.cc652
-rw-r--r--chromium/net/quic/core/quic_headers_stream.h175
-rw-r--r--chromium/net/quic/core/quic_headers_stream_test.cc997
-rw-r--r--chromium/net/quic/core/quic_http_utils.cc38
-rw-r--r--chromium/net/quic/core/quic_http_utils.h32
-rw-r--r--chromium/net/quic/core/quic_http_utils_test.cc39
-rw-r--r--chromium/net/quic/core/quic_multipath_received_packet_manager.cc118
-rw-r--r--chromium/net/quic/core/quic_multipath_received_packet_manager.h76
-rw-r--r--chromium/net/quic/core/quic_multipath_received_packet_manager_test.cc158
-rw-r--r--chromium/net/quic/core/quic_multipath_sent_packet_manager.cc524
-rw-r--r--chromium/net/quic/core/quic_multipath_sent_packet_manager.h220
-rw-r--r--chromium/net/quic/core/quic_multipath_sent_packet_manager_test.cc356
-rw-r--r--chromium/net/quic/core/quic_multipath_transmissions_map.cc70
-rw-r--r--chromium/net/quic/core/quic_multipath_transmissions_map.h74
-rw-r--r--chromium/net/quic/core/quic_multipath_transmissions_map_test.cc114
-rw-r--r--chromium/net/quic/core/quic_one_block_arena.h77
-rw-r--r--chromium/net/quic/core/quic_one_block_arena_test.cc59
-rw-r--r--chromium/net/quic/core/quic_packet_creator.cc690
-rw-r--r--chromium/net/quic/core/quic_packet_creator.h350
-rw-r--r--chromium/net/quic/core/quic_packet_creator_test.cc1075
-rw-r--r--chromium/net/quic/core/quic_packet_generator.cc347
-rw-r--r--chromium/net/quic/core/quic_packet_generator.h223
-rw-r--r--chromium/net/quic/core/quic_packet_generator_test.cc897
-rw-r--r--chromium/net/quic/core/quic_packet_writer.h74
-rw-r--r--chromium/net/quic/core/quic_protocol.cc884
-rw-r--r--chromium/net/quic/core/quic_protocol.h1553
-rw-r--r--chromium/net/quic/core/quic_protocol_test.cc553
-rw-r--r--chromium/net/quic/core/quic_received_packet_manager.cc325
-rw-r--r--chromium/net/quic/core/quic_received_packet_manager.h192
-rw-r--r--chromium/net/quic/core/quic_received_packet_manager_test.cc396
-rw-r--r--chromium/net/quic/core/quic_sent_entropy_manager.cc113
-rw-r--r--chromium/net/quic/core/quic_sent_entropy_manager.h89
-rw-r--r--chromium/net/quic/core/quic_sent_entropy_manager_test.cc96
-rw-r--r--chromium/net/quic/core/quic_sent_packet_manager.cc1015
-rw-r--r--chromium/net/quic/core/quic_sent_packet_manager.h420
-rw-r--r--chromium/net/quic/core/quic_sent_packet_manager_interface.h195
-rw-r--r--chromium/net/quic/core/quic_sent_packet_manager_test.cc1744
-rw-r--r--chromium/net/quic/core/quic_server_id.cc59
-rw-r--r--chromium/net/quic/core/quic_server_id.h (renamed from chromium/net/quic/quic_server_id.h)0
-rw-r--r--chromium/net/quic/core/quic_server_id_test.cc145
-rw-r--r--chromium/net/quic/core/quic_server_session_base.cc249
-rw-r--r--chromium/net/quic/core/quic_server_session_base.h168
-rw-r--r--chromium/net/quic/core/quic_server_session_base_test.cc577
-rw-r--r--chromium/net/quic/core/quic_session.cc778
-rw-r--r--chromium/net/quic/core/quic_session.h417
-rw-r--r--chromium/net/quic/core/quic_session_test.cc1257
-rw-r--r--chromium/net/quic/core/quic_simple_buffer_allocator.cc21
-rw-r--r--chromium/net/quic/core/quic_simple_buffer_allocator.h22
-rw-r--r--chromium/net/quic/core/quic_simple_buffer_allocator_test.cc35
-rw-r--r--chromium/net/quic/core/quic_socket_address_coder.cc89
-rw-r--r--chromium/net/quic/core/quic_socket_address_coder.h (renamed from chromium/net/quic/quic_socket_address_coder.h)0
-rw-r--r--chromium/net/quic/core/quic_socket_address_coder_test.cc126
-rw-r--r--chromium/net/quic/core/quic_spdy_session.cc189
-rw-r--r--chromium/net/quic/core/quic_spdy_session.h154
-rw-r--r--chromium/net/quic/core/quic_spdy_stream.cc426
-rw-r--r--chromium/net/quic/core/quic_spdy_stream.h269
-rw-r--r--chromium/net/quic/core/quic_spdy_stream_test.cc1001
-rw-r--r--chromium/net/quic/core/quic_stream_sequencer.cc236
-rw-r--r--chromium/net/quic/core/quic_stream_sequencer.h151
-rw-r--r--chromium/net/quic/core/quic_stream_sequencer_buffer.cc609
-rw-r--r--chromium/net/quic/core/quic_stream_sequencer_buffer.h263
-rw-r--r--chromium/net/quic/core/quic_stream_sequencer_buffer_interface.h77
-rw-r--r--chromium/net/quic/core/quic_stream_sequencer_buffer_test.cc1065
-rw-r--r--chromium/net/quic/core/quic_stream_sequencer_test.cc691
-rw-r--r--chromium/net/quic/core/quic_sustained_bandwidth_recorder.cc61
-rw-r--r--chromium/net/quic/core/quic_sustained_bandwidth_recorder.h94
-rw-r--r--chromium/net/quic/core/quic_sustained_bandwidth_recorder_test.cc131
-rw-r--r--chromium/net/quic/core/quic_time.cc87
-rw-r--r--chromium/net/quic/core/quic_time.h280
-rw-r--r--chromium/net/quic/core/quic_time_test.cc166
-rw-r--r--chromium/net/quic/core/quic_types.cc25
-rw-r--r--chromium/net/quic/core/quic_types.h (renamed from chromium/net/quic/quic_types.h)0
-rw-r--r--chromium/net/quic/core/quic_unacked_packet_map.cc358
-rw-r--r--chromium/net/quic/core/quic_unacked_packet_map.h203
-rw-r--r--chromium/net/quic/core/quic_unacked_packet_map_test.cc395
-rw-r--r--chromium/net/quic/core/quic_utils.cc577
-rw-r--r--chromium/net/quic/core/quic_utils.h160
-rw-r--r--chromium/net/quic/core/quic_utils_test.cc159
-rw-r--r--chromium/net/quic/core/quic_write_blocked_list.cc19
-rw-r--r--chromium/net/quic/core/quic_write_blocked_list.h176
-rw-r--r--chromium/net/quic/core/quic_write_blocked_list_test.cc219
-rw-r--r--chromium/net/quic/core/reliable_quic_stream.cc473
-rw-r--r--chromium/net/quic/core/reliable_quic_stream.h311
-rw-r--r--chromium/net/quic/core/reliable_quic_stream_test.cc716
-rw-r--r--chromium/net/quic/core/spdy_utils.cc259
-rw-r--r--chromium/net/quic/core/spdy_utils.h87
-rw-r--r--chromium/net/quic/core/spdy_utils_test.cc374
-rw-r--r--chromium/net/quic/crypto/aead_base_decrypter.cc167
-rw-r--r--chromium/net/quic/crypto/aead_base_decrypter.h67
-rw-r--r--chromium/net/quic/crypto/aead_base_encrypter.cc164
-rw-r--r--chromium/net/quic/crypto/aead_base_encrypter.h75
-rw-r--r--chromium/net/quic/crypto/aes_128_gcm_12_decrypter.cc42
-rw-r--r--chromium/net/quic/crypto/aes_128_gcm_12_decrypter.h41
-rw-r--r--chromium/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc287
-rw-r--r--chromium/net/quic/crypto/aes_128_gcm_12_encrypter.cc30
-rw-r--r--chromium/net/quic/crypto/aes_128_gcm_12_encrypter.h37
-rw-r--r--chromium/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc238
-rw-r--r--chromium/net/quic/crypto/cert_compressor.cc647
-rw-r--r--chromium/net/quic/crypto/cert_compressor.h58
-rw-r--r--chromium/net/quic/crypto/cert_compressor_test.cc129
-rw-r--r--chromium/net/quic/crypto/chacha20_poly1305_decrypter.cc39
-rw-r--r--chromium/net/quic/crypto/chacha20_poly1305_decrypter.h42
-rw-r--r--chromium/net/quic/crypto/chacha20_poly1305_decrypter_test.cc177
-rw-r--r--chromium/net/quic/crypto/chacha20_poly1305_encrypter.cc30
-rw-r--r--chromium/net/quic/crypto/chacha20_poly1305_encrypter.h38
-rw-r--r--chromium/net/quic/crypto/chacha20_poly1305_encrypter_test.cc154
-rw-r--r--chromium/net/quic/crypto/channel_id.cc91
-rw-r--r--chromium/net/quic/crypto/channel_id.h99
-rw-r--r--chromium/net/quic/crypto/channel_id_chromium.cc224
-rw-r--r--chromium/net/quic/crypto/channel_id_chromium.h65
-rw-r--r--chromium/net/quic/crypto/channel_id_test.cc274
-rw-r--r--chromium/net/quic/crypto/common_cert_set.cc168
-rw-r--r--chromium/net/quic/crypto/common_cert_set.h48
-rw-r--r--chromium/net/quic/crypto/common_cert_set_1.c145
-rw-r--r--chromium/net/quic/crypto/common_cert_set_2.c129
-rw-r--r--chromium/net/quic/crypto/common_cert_set_3.c123
-rw-r--r--chromium/net/quic/crypto/common_cert_set_test.cc249
-rw-r--r--chromium/net/quic/crypto/crypto_framer.cc294
-rw-r--r--chromium/net/quic/crypto/crypto_framer.h118
-rw-r--r--chromium/net/quic/crypto/crypto_framer_test.cc471
-rw-r--r--chromium/net/quic/crypto/crypto_handshake.cc43
-rw-r--r--chromium/net/quic/crypto/crypto_handshake.h192
-rw-r--r--chromium/net/quic/crypto/crypto_handshake_message.cc317
-rw-r--r--chromium/net/quic/crypto/crypto_handshake_message.h137
-rw-r--r--chromium/net/quic/crypto/crypto_handshake_message_test.cc51
-rw-r--r--chromium/net/quic/crypto/crypto_protocol.h250
-rw-r--r--chromium/net/quic/crypto/crypto_secret_boxer.cc132
-rw-r--r--chromium/net/quic/crypto/crypto_secret_boxer_test.cc81
-rw-r--r--chromium/net/quic/crypto/crypto_server_config_protobuf.cc18
-rw-r--r--chromium/net/quic/crypto/crypto_server_config_protobuf.h115
-rw-r--r--chromium/net/quic/crypto/crypto_server_test.cc1165
-rw-r--r--chromium/net/quic/crypto/crypto_utils.cc340
-rw-r--r--chromium/net/quic/crypto/crypto_utils.h170
-rw-r--r--chromium/net/quic/crypto/crypto_utils_test.cc195
-rw-r--r--chromium/net/quic/crypto/curve25519_key_exchange.cc86
-rw-r--r--chromium/net/quic/crypto/curve25519_key_exchange.h51
-rw-r--r--chromium/net/quic/crypto/curve25519_key_exchange_test.cc44
-rw-r--r--chromium/net/quic/crypto/ephemeral_key_source.h42
-rw-r--r--chromium/net/quic/crypto/key_exchange.h47
-rw-r--r--chromium/net/quic/crypto/local_strike_register_client.cc52
-rw-r--r--chromium/net/quic/crypto/local_strike_register_client.h45
-rw-r--r--chromium/net/quic/crypto/local_strike_register_client_test.cc134
-rw-r--r--chromium/net/quic/crypto/null_decrypter.cc104
-rw-r--r--chromium/net/quic/crypto/null_decrypter.h55
-rw-r--r--chromium/net/quic/crypto/null_decrypter_test.cc67
-rw-r--r--chromium/net/quic/crypto/null_encrypter.cc78
-rw-r--r--chromium/net/quic/crypto/null_encrypter.h50
-rw-r--r--chromium/net/quic/crypto/null_encrypter_test.cc48
-rw-r--r--chromium/net/quic/crypto/p256_key_exchange.cc119
-rw-r--r--chromium/net/quic/crypto/p256_key_exchange.h69
-rw-r--r--chromium/net/quic/crypto/p256_key_exchange_test.cc45
-rw-r--r--chromium/net/quic/crypto/proof_source.cc14
-rw-r--r--chromium/net/quic/crypto/proof_source.h87
-rw-r--r--chromium/net/quic/crypto/proof_source_chromium.cc154
-rw-r--r--chromium/net/quic/crypto/proof_source_chromium.h56
-rw-r--r--chromium/net/quic/crypto/proof_test.cc418
-rw-r--r--chromium/net/quic/crypto/proof_verifier.h94
-rw-r--r--chromium/net/quic/crypto/proof_verifier_chromium.cc519
-rw-r--r--chromium/net/quic/crypto/proof_verifier_chromium.h110
-rw-r--r--chromium/net/quic/crypto/proof_verifier_chromium_test.cc591
-rw-r--r--chromium/net/quic/crypto/properties_based_quic_server_info.cc68
-rw-r--r--chromium/net/quic/crypto/properties_based_quic_server_info.h63
-rw-r--r--chromium/net/quic/crypto/properties_based_quic_server_info_test.cc106
-rw-r--r--chromium/net/quic/crypto/quic_compressed_certs_cache.cc124
-rw-r--r--chromium/net/quic/crypto/quic_compressed_certs_cache.h108
-rw-r--r--chromium/net/quic/crypto/quic_compressed_certs_cache_test.cc91
-rw-r--r--chromium/net/quic/crypto/quic_crypto_client_config.cc996
-rw-r--r--chromium/net/quic/crypto/quic_crypto_client_config.h384
-rw-r--r--chromium/net/quic/crypto/quic_crypto_client_config_test.cc483
-rw-r--r--chromium/net/quic/crypto/quic_crypto_server_config.cc1835
-rw-r--r--chromium/net/quic/crypto/quic_crypto_server_config.h677
-rw-r--r--chromium/net/quic/crypto/quic_crypto_server_config_test.cc583
-rw-r--r--chromium/net/quic/crypto/quic_decrypter.cc49
-rw-r--r--chromium/net/quic/crypto/quic_decrypter.h98
-rw-r--r--chromium/net/quic/crypto/quic_encrypter.cc29
-rw-r--r--chromium/net/quic/crypto/quic_encrypter.h85
-rw-r--r--chromium/net/quic/crypto/quic_random.cc59
-rw-r--r--chromium/net/quic/crypto/quic_random_test.cc40
-rw-r--r--chromium/net/quic/crypto/quic_server_info.cc163
-rw-r--r--chromium/net/quic/crypto/quic_server_info.h149
-rw-r--r--chromium/net/quic/crypto/scoped_evp_aead_ctx.cc23
-rw-r--r--chromium/net/quic/crypto/strike_register.cc519
-rw-r--r--chromium/net/quic/crypto/strike_register_client.h60
-rw-r--r--chromium/net/quic/crypto/strike_register_test.cc407
-rw-r--r--chromium/net/quic/interval.h362
-rw-r--r--chromium/net/quic/interval_set.h857
-rw-r--r--chromium/net/quic/interval_set_test.cc981
-rw-r--r--chromium/net/quic/interval_test.cc333
-rw-r--r--chromium/net/quic/iovector.cc15
-rw-r--r--chromium/net/quic/iovector_test.cc373
-rw-r--r--chromium/net/quic/network_connection.cc75
-rw-r--r--chromium/net/quic/network_connection_unittest.cc80
-rw-r--r--chromium/net/quic/p2p/quic_p2p_crypto_config.cc41
-rw-r--r--chromium/net/quic/p2p/quic_p2p_crypto_config.h44
-rw-r--r--chromium/net/quic/p2p/quic_p2p_crypto_stream.cc49
-rw-r--r--chromium/net/quic/p2p/quic_p2p_crypto_stream.h31
-rw-r--r--chromium/net/quic/p2p/quic_p2p_session.cc127
-rw-r--r--chromium/net/quic/p2p/quic_p2p_session.h97
-rw-r--r--chromium/net/quic/p2p/quic_p2p_session_test.cc405
-rw-r--r--chromium/net/quic/p2p/quic_p2p_stream.cc76
-rw-r--r--chromium/net/quic/p2p/quic_p2p_stream.h63
-rw-r--r--chromium/net/quic/port_suggester.cc47
-rw-r--r--chromium/net/quic/port_suggester_unittest.cc108
-rw-r--r--chromium/net/quic/quic_address_mismatch.cc51
-rw-r--r--chromium/net/quic/quic_address_mismatch_test.cc99
-rw-r--r--chromium/net/quic/quic_alarm.cc59
-rw-r--r--chromium/net/quic/quic_alarm.h84
-rw-r--r--chromium/net/quic/quic_alarm_factory.h40
-rw-r--r--chromium/net/quic/quic_alarm_test.cc168
-rw-r--r--chromium/net/quic/quic_arena_scoped_ptr.h210
-rw-r--r--chromium/net/quic/quic_arena_scoped_ptr_test.cc102
-rw-r--r--chromium/net/quic/quic_bandwidth.cc118
-rw-r--r--chromium/net/quic/quic_bandwidth.h89
-rw-r--r--chromium/net/quic/quic_bandwidth_test.cc99
-rw-r--r--chromium/net/quic/quic_buffered_packet_store.cc149
-rw-r--r--chromium/net/quic/quic_buffered_packet_store.h124
-rw-r--r--chromium/net/quic/quic_buffered_packet_store_test.cc231
-rw-r--r--chromium/net/quic/quic_chromium_alarm_factory.cc117
-rw-r--r--chromium/net/quic/quic_chromium_alarm_factory.h48
-rw-r--r--chromium/net/quic/quic_chromium_alarm_factory_test.cc175
-rw-r--r--chromium/net/quic/quic_chromium_client_session.cc1214
-rw-r--r--chromium/net/quic/quic_chromium_client_session.h364
-rw-r--r--chromium/net/quic/quic_chromium_client_session_test.cc555
-rw-r--r--chromium/net/quic/quic_chromium_client_stream.cc320
-rw-r--r--chromium/net/quic/quic_chromium_client_stream.h157
-rw-r--r--chromium/net/quic/quic_chromium_client_stream_test.cc559
-rw-r--r--chromium/net/quic/quic_chromium_connection_helper.cc28
-rw-r--r--chromium/net/quic/quic_chromium_connection_helper.h46
-rw-r--r--chromium/net/quic/quic_chromium_connection_helper_test.cc34
-rw-r--r--chromium/net/quic/quic_chromium_packet_reader.cc90
-rw-r--r--chromium/net/quic/quic_chromium_packet_reader.h74
-rw-r--r--chromium/net/quic/quic_chromium_packet_writer.cc87
-rw-r--r--chromium/net/quic/quic_chromium_packet_writer.h59
-rw-r--r--chromium/net/quic/quic_client_promised_info.cc123
-rw-r--r--chromium/net/quic/quic_client_promised_info.h112
-rw-r--r--chromium/net/quic/quic_client_promised_info_test.cc380
-rw-r--r--chromium/net/quic/quic_client_push_promise_index.cc49
-rw-r--r--chromium/net/quic/quic_client_push_promise_index.h98
-rw-r--r--chromium/net/quic/quic_client_push_promise_index_test.cc109
-rw-r--r--chromium/net/quic/quic_client_session_base.cc201
-rw-r--r--chromium/net/quic/quic_client_session_base.h136
-rw-r--r--chromium/net/quic/quic_clock.cc48
-rw-r--r--chromium/net/quic/quic_clock.h44
-rw-r--r--chromium/net/quic/quic_clock_test.cc38
-rw-r--r--chromium/net/quic/quic_config.cc744
-rw-r--r--chromium/net/quic/quic_config.h452
-rw-r--r--chromium/net/quic/quic_config_test.cc252
-rw-r--r--chromium/net/quic/quic_connection.cc2536
-rw-r--r--chromium/net/quic/quic_connection.h1078
-rw-r--r--chromium/net/quic/quic_connection_logger.cc898
-rw-r--r--chromium/net/quic/quic_connection_logger.h201
-rw-r--r--chromium/net/quic/quic_connection_logger_unittest.cc81
-rw-r--r--chromium/net/quic/quic_connection_stats.cc49
-rw-r--r--chromium/net/quic/quic_connection_stats.h93
-rw-r--r--chromium/net/quic/quic_connection_test.cc4984
-rw-r--r--chromium/net/quic/quic_crypto_client_stream.cc705
-rw-r--r--chromium/net/quic/quic_crypto_client_stream.h276
-rw-r--r--chromium/net/quic/quic_crypto_client_stream_factory.cc40
-rw-r--r--chromium/net/quic/quic_crypto_client_stream_factory.h38
-rw-r--r--chromium/net/quic/quic_crypto_client_stream_test.cc363
-rw-r--r--chromium/net/quic/quic_crypto_framer_parse_message_fuzzer.cc18
-rw-r--r--chromium/net/quic/quic_crypto_server_stream.cc427
-rw-r--r--chromium/net/quic/quic_crypto_server_stream.h223
-rw-r--r--chromium/net/quic/quic_crypto_server_stream_test.cc610
-rw-r--r--chromium/net/quic/quic_crypto_stream.cc108
-rw-r--r--chromium/net/quic/quic_crypto_stream.h91
-rw-r--r--chromium/net/quic/quic_crypto_stream_test.cc115
-rw-r--r--chromium/net/quic/quic_data_reader.cc133
-rw-r--r--chromium/net/quic/quic_data_writer.cc145
-rw-r--r--chromium/net/quic/quic_data_writer.h76
-rw-r--r--chromium/net/quic/quic_data_writer_test.cc204
-rw-r--r--chromium/net/quic/quic_end_to_end_unittest.cc386
-rw-r--r--chromium/net/quic/quic_flags.cc176
-rw-r--r--chromium/net/quic/quic_flags.h59
-rw-r--r--chromium/net/quic/quic_flow_controller.cc258
-rw-r--r--chromium/net/quic/quic_flow_controller.h171
-rw-r--r--chromium/net/quic/quic_flow_controller_test.cc379
-rw-r--r--chromium/net/quic/quic_frame_list.cc254
-rw-r--r--chromium/net/quic/quic_frame_list.h81
-rw-r--r--chromium/net/quic/quic_framer.cc2600
-rw-r--r--chromium/net/quic/quic_framer.h617
-rw-r--r--chromium/net/quic/quic_framer_test.cc7192
-rw-r--r--chromium/net/quic/quic_header_list.cc51
-rw-r--r--chromium/net/quic/quic_header_list.h56
-rw-r--r--chromium/net/quic/quic_header_list_test.cc36
-rw-r--r--chromium/net/quic/quic_headers_stream.cc509
-rw-r--r--chromium/net/quic/quic_headers_stream.h162
-rw-r--r--chromium/net/quic/quic_headers_stream_test.cc792
-rw-r--r--chromium/net/quic/quic_http_stream.cc828
-rw-r--r--chromium/net/quic/quic_http_stream.h217
-rw-r--r--chromium/net/quic/quic_http_stream_test.cc1841
-rw-r--r--chromium/net/quic/quic_http_utils.cc38
-rw-r--r--chromium/net/quic/quic_http_utils.h32
-rw-r--r--chromium/net/quic/quic_http_utils_test.cc39
-rw-r--r--chromium/net/quic/quic_multipath_received_packet_manager.cc119
-rw-r--r--chromium/net/quic/quic_multipath_received_packet_manager.h76
-rw-r--r--chromium/net/quic/quic_multipath_received_packet_manager_test.cc158
-rw-r--r--chromium/net/quic/quic_multipath_transmissions_map.cc70
-rw-r--r--chromium/net/quic/quic_multipath_transmissions_map.h73
-rw-r--r--chromium/net/quic/quic_multipath_transmissions_map_test.cc114
-rw-r--r--chromium/net/quic/quic_network_transaction_unittest.cc2751
-rw-r--r--chromium/net/quic/quic_one_block_arena.h77
-rw-r--r--chromium/net/quic/quic_one_block_arena_test.cc58
-rw-r--r--chromium/net/quic/quic_packet_creator.cc724
-rw-r--r--chromium/net/quic/quic_packet_creator.h354
-rw-r--r--chromium/net/quic/quic_packet_creator_test.cc1337
-rw-r--r--chromium/net/quic/quic_packet_generator.cc329
-rw-r--r--chromium/net/quic/quic_packet_generator.h225
-rw-r--r--chromium/net/quic/quic_packet_generator_test.cc880
-rw-r--r--chromium/net/quic/quic_packet_writer.h73
-rw-r--r--chromium/net/quic/quic_protocol.cc881
-rw-r--r--chromium/net/quic/quic_protocol.h1502
-rw-r--r--chromium/net/quic/quic_protocol_test.cc405
-rw-r--r--chromium/net/quic/quic_received_packet_manager.cc323
-rw-r--r--chromium/net/quic/quic_received_packet_manager.h191
-rw-r--r--chromium/net/quic/quic_received_packet_manager_test.cc396
-rw-r--r--chromium/net/quic/quic_sent_entropy_manager.cc109
-rw-r--r--chromium/net/quic/quic_sent_entropy_manager.h88
-rw-r--r--chromium/net/quic/quic_sent_entropy_manager_test.cc96
-rw-r--r--chromium/net/quic/quic_sent_packet_manager.cc1026
-rw-r--r--chromium/net/quic/quic_sent_packet_manager.h412
-rw-r--r--chromium/net/quic/quic_sent_packet_manager_interface.h197
-rw-r--r--chromium/net/quic/quic_sent_packet_manager_test.cc1801
-rw-r--r--chromium/net/quic/quic_server_id.cc59
-rw-r--r--chromium/net/quic/quic_server_id_test.cc145
-rw-r--r--chromium/net/quic/quic_server_session_base.cc257
-rw-r--r--chromium/net/quic/quic_server_session_base.h189
-rw-r--r--chromium/net/quic/quic_server_session_base_test.cc573
-rw-r--r--chromium/net/quic/quic_session.cc842
-rw-r--r--chromium/net/quic/quic_session.h417
-rw-r--r--chromium/net/quic/quic_session_test.cc1187
-rw-r--r--chromium/net/quic/quic_simple_buffer_allocator.cc21
-rw-r--r--chromium/net/quic/quic_simple_buffer_allocator.h21
-rw-r--r--chromium/net/quic/quic_simple_buffer_allocator_test.cc35
-rw-r--r--chromium/net/quic/quic_socket_address_coder.cc89
-rw-r--r--chromium/net/quic/quic_socket_address_coder_test.cc126
-rw-r--r--chromium/net/quic/quic_spdy_session.cc158
-rw-r--r--chromium/net/quic/quic_spdy_session.h129
-rw-r--r--chromium/net/quic/quic_spdy_stream.cc405
-rw-r--r--chromium/net/quic/quic_spdy_stream.h250
-rw-r--r--chromium/net/quic/quic_spdy_stream_test.cc999
-rw-r--r--chromium/net/quic/quic_stream_factory.cc1878
-rw-r--r--chromium/net/quic/quic_stream_factory.h597
-rw-r--r--chromium/net/quic/quic_stream_factory_test.cc4420
-rw-r--r--chromium/net/quic/quic_stream_sequencer.cc205
-rw-r--r--chromium/net/quic/quic_stream_sequencer.h147
-rw-r--r--chromium/net/quic/quic_stream_sequencer_buffer.cc505
-rw-r--r--chromium/net/quic/quic_stream_sequencer_buffer.h246
-rw-r--r--chromium/net/quic/quic_stream_sequencer_buffer_interface.h76
-rw-r--r--chromium/net/quic/quic_stream_sequencer_buffer_test.cc1060
-rw-r--r--chromium/net/quic/quic_stream_sequencer_test.cc669
-rw-r--r--chromium/net/quic/quic_sustained_bandwidth_recorder.cc61
-rw-r--r--chromium/net/quic/quic_sustained_bandwidth_recorder.h93
-rw-r--r--chromium/net/quic/quic_sustained_bandwidth_recorder_test.cc131
-rw-r--r--chromium/net/quic/quic_time.cc65
-rw-r--r--chromium/net/quic/quic_time.h268
-rw-r--r--chromium/net/quic/quic_time_test.cc143
-rw-r--r--chromium/net/quic/quic_types.cc25
-rw-r--r--chromium/net/quic/quic_unacked_packet_map.cc360
-rw-r--r--chromium/net/quic/quic_unacked_packet_map.h195
-rw-r--r--chromium/net/quic/quic_unacked_packet_map_test.cc395
-rw-r--r--chromium/net/quic/quic_utils.cc586
-rw-r--r--chromium/net/quic/quic_utils.h165
-rw-r--r--chromium/net/quic/quic_utils_chromium_test.cc50
-rw-r--r--chromium/net/quic/quic_utils_test.cc190
-rw-r--r--chromium/net/quic/quic_write_blocked_list.cc19
-rw-r--r--chromium/net/quic/quic_write_blocked_list.h176
-rw-r--r--chromium/net/quic/quic_write_blocked_list_test.cc219
-rw-r--r--chromium/net/quic/reliable_quic_stream.cc466
-rw-r--r--chromium/net/quic/reliable_quic_stream.h304
-rw-r--r--chromium/net/quic/reliable_quic_stream_test.cc723
-rw-r--r--chromium/net/quic/spdy_utils.cc253
-rw-r--r--chromium/net/quic/spdy_utils.h76
-rw-r--r--chromium/net/quic/spdy_utils_test.cc359
-rw-r--r--chromium/net/quic/test_tools/crypto_test_utils.cc264
-rw-r--r--chromium/net/quic/test_tools/crypto_test_utils.h52
-rw-r--r--chromium/net/quic/test_tools/crypto_test_utils_chromium.cc137
-rw-r--r--chromium/net/quic/test_tools/crypto_test_utils_test.cc169
-rw-r--r--chromium/net/quic/test_tools/delayed_verify_strike_register_client.h2
-rw-r--r--chromium/net/quic/test_tools/mock_clock.cc7
-rw-r--r--chromium/net/quic/test_tools/mock_clock.h3
-rw-r--r--chromium/net/quic/test_tools/mock_crypto_client_stream.cc12
-rw-r--r--chromium/net/quic/test_tools/mock_crypto_client_stream.h16
-rw-r--r--chromium/net/quic/test_tools/mock_crypto_client_stream_factory.cc17
-rw-r--r--chromium/net/quic/test_tools/mock_crypto_client_stream_factory.h10
-rw-r--r--chromium/net/quic/test_tools/mock_quic_client_promised_info.h4
-rw-r--r--chromium/net/quic/test_tools/mock_quic_dispatcher.cc15
-rw-r--r--chromium/net/quic/test_tools/mock_quic_dispatcher.h13
-rw-r--r--chromium/net/quic/test_tools/mock_quic_spdy_client_stream.h2
-rw-r--r--chromium/net/quic/test_tools/mock_random.h2
-rw-r--r--chromium/net/quic/test_tools/quic_buffered_packet_store_peer.cc25
-rw-r--r--chromium/net/quic/test_tools/quic_buffered_packet_store_peer.h33
-rw-r--r--chromium/net/quic/test_tools/quic_chromium_client_session_peer.cc37
-rw-r--r--chromium/net/quic/test_tools/quic_chromium_client_session_peer.h40
-rw-r--r--chromium/net/quic/test_tools/quic_config_peer.cc19
-rw-r--r--chromium/net/quic/test_tools/quic_config_peer.h12
-rw-r--r--chromium/net/quic/test_tools/quic_connection_peer.cc46
-rw-r--r--chromium/net/quic/test_tools/quic_connection_peer.h24
-rw-r--r--chromium/net/quic/test_tools/quic_crypto_server_config_peer.cc12
-rw-r--r--chromium/net/quic/test_tools/quic_crypto_server_config_peer.h7
-rw-r--r--chromium/net/quic/test_tools/quic_flow_controller_peer.cc4
-rw-r--r--chromium/net/quic/test_tools/quic_flow_controller_peer.h2
-rw-r--r--chromium/net/quic/test_tools/quic_framer_peer.cc12
-rw-r--r--chromium/net/quic/test_tools/quic_framer_peer.h8
-rw-r--r--chromium/net/quic/test_tools/quic_headers_stream_peer.cc19
-rw-r--r--chromium/net/quic/test_tools/quic_headers_stream_peer.h28
-rw-r--r--chromium/net/quic/test_tools/quic_multipath_sent_packet_manager_peer.cc29
-rw-r--r--chromium/net/quic/test_tools/quic_multipath_sent_packet_manager_peer.h31
-rw-r--r--chromium/net/quic/test_tools/quic_packet_creator_peer.cc15
-rw-r--r--chromium/net/quic/test_tools/quic_packet_creator_peer.h7
-rw-r--r--chromium/net/quic/test_tools/quic_packet_generator_peer.cc4
-rw-r--r--chromium/net/quic/test_tools/quic_packet_generator_peer.h2
-rw-r--r--chromium/net/quic/test_tools/quic_received_packet_manager_peer.cc4
-rw-r--r--chromium/net/quic/test_tools/quic_received_packet_manager_peer.h2
-rw-r--r--chromium/net/quic/test_tools/quic_sent_packet_manager_peer.cc35
-rw-r--r--chromium/net/quic/test_tools/quic_sent_packet_manager_peer.h11
-rw-r--r--chromium/net/quic/test_tools/quic_session_peer.cc11
-rw-r--r--chromium/net/quic/test_tools/quic_session_peer.h8
-rw-r--r--chromium/net/quic/test_tools/quic_spdy_session_peer.cc8
-rw-r--r--chromium/net/quic/test_tools/quic_spdy_session_peer.h5
-rw-r--r--chromium/net/quic/test_tools/quic_spdy_stream_peer.cc2
-rw-r--r--chromium/net/quic/test_tools/quic_stream_factory_peer.cc77
-rw-r--r--chromium/net/quic/test_tools/quic_stream_factory_peer.h29
-rw-r--r--chromium/net/quic/test_tools/quic_stream_sequencer_buffer_peer.cc142
-rw-r--r--chromium/net/quic/test_tools/quic_stream_sequencer_buffer_peer.h63
-rw-r--r--chromium/net/quic/test_tools/quic_stream_sequencer_peer.cc10
-rw-r--r--chromium/net/quic/test_tools/quic_stream_sequencer_peer.h4
-rw-r--r--chromium/net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.cc4
-rw-r--r--chromium/net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h2
-rw-r--r--chromium/net/quic/test_tools/quic_test_packet_maker.cc35
-rw-r--r--chromium/net/quic/test_tools/quic_test_packet_maker.h9
-rw-r--r--chromium/net/quic/test_tools/quic_test_utils.cc91
-rw-r--r--chromium/net/quic/test_tools/quic_test_utils.h165
-rw-r--r--chromium/net/quic/test_tools/quic_test_utils_test.cc41
-rw-r--r--chromium/net/quic/test_tools/reliable_quic_stream_peer.cc8
-rw-r--r--chromium/net/quic/test_tools/reliable_quic_stream_peer.h5
-rw-r--r--chromium/net/quic/test_tools/rtt_stats_peer.h4
-rw-r--r--chromium/net/quic/test_tools/simple_quic_framer.cc10
-rw-r--r--chromium/net/quic/test_tools/simple_quic_framer.h4
-rw-r--r--chromium/net/quic/test_tools/simulator/README.md98
-rw-r--r--chromium/net/quic/test_tools/simulator/actor.cc29
-rw-r--r--chromium/net/quic/test_tools/simulator/actor.h67
-rw-r--r--chromium/net/quic/test_tools/simulator/alarm_factory.cc82
-rw-r--r--chromium/net/quic/test_tools/simulator/alarm_factory.h39
-rw-r--r--chromium/net/quic/test_tools/simulator/link.cc116
-rw-r--r--chromium/net/quic/test_tools/simulator/link.h100
-rw-r--r--chromium/net/quic/test_tools/simulator/port.cc21
-rw-r--r--chromium/net/quic/test_tools/simulator/port.h66
-rw-r--r--chromium/net/quic/test_tools/simulator/queue.cc64
-rw-r--r--chromium/net/quic/test_tools/simulator/queue.h59
-rw-r--r--chromium/net/quic/test_tools/simulator/quic_endpoint.cc272
-rw-r--r--chromium/net/quic/test_tools/simulator/quic_endpoint.h169
-rw-r--r--chromium/net/quic/test_tools/simulator/quic_endpoint_test.cc190
-rw-r--r--chromium/net/quic/test_tools/simulator/simulator.cc146
-rw-r--r--chromium/net/quic/test_tools/simulator/simulator.h155
-rw-r--r--chromium/net/quic/test_tools/simulator/simulator_test.cc564
-rw-r--r--chromium/net/quic/test_tools/simulator/switch.cc87
-rw-r--r--chromium/net/quic/test_tools/simulator/switch.h86
-rw-r--r--chromium/net/sdch/sdch_owner.cc32
-rw-r--r--chromium/net/sdch/sdch_owner.h14
-rw-r--r--chromium/net/sdch/sdch_owner_unittest.cc16
-rw-r--r--chromium/net/server/http_server.cc48
-rw-r--r--chromium/net/server/http_server.h8
-rw-r--r--chromium/net/server/http_server_unittest.cc86
-rw-r--r--chromium/net/server/web_socket_encoder.cc16
-rw-r--r--chromium/net/socket/OWNERS2
-rw-r--r--chromium/net/socket/client_socket_factory.cc4
-rw-r--r--chromium/net/socket/client_socket_factory.h9
-rw-r--r--chromium/net/socket/client_socket_handle.cc8
-rw-r--r--chromium/net/socket/client_socket_handle.h9
-rw-r--r--chromium/net/socket/client_socket_pool.h7
-rw-r--r--chromium/net/socket/client_socket_pool_base.cc103
-rw-r--r--chromium/net/socket/client_socket_pool_base.h38
-rw-r--r--chromium/net/socket/client_socket_pool_base_unittest.cc1135
-rw-r--r--chromium/net/socket/client_socket_pool_manager.cc29
-rw-r--r--chromium/net/socket/client_socket_pool_manager.h16
-rw-r--r--chromium/net/socket/client_socket_pool_manager_impl.cc100
-rw-r--r--chromium/net/socket/client_socket_pool_manager_impl.h34
-rw-r--r--chromium/net/socket/fuzzed_socket.cc11
-rw-r--r--chromium/net/socket/fuzzed_socket.h16
-rw-r--r--chromium/net/socket/fuzzed_socket_factory.cc29
-rw-r--r--chromium/net/socket/fuzzed_socket_factory.h14
-rw-r--r--chromium/net/socket/mock_client_socket_pool_manager.cc24
-rw-r--r--chromium/net/socket/mock_client_socket_pool_manager.h25
-rw-r--r--chromium/net/socket/next_proto.cc14
-rw-r--r--chromium/net/socket/next_proto.h34
-rw-r--r--chromium/net/socket/sequenced_socket_data_unittest.cc11
-rw-r--r--chromium/net/socket/socket_net_log_params.cc11
-rw-r--r--chromium/net/socket/socket_net_log_params.h12
-rw-r--r--chromium/net/socket/socket_posix.cc19
-rw-r--r--chromium/net/socket/socket_posix.h1
-rw-r--r--chromium/net/socket/socket_test_util.cc85
-rw-r--r--chromium/net/socket/socket_test_util.h52
-rw-r--r--chromium/net/socket/socks5_client_socket.cc45
-rw-r--r--chromium/net/socket/socks5_client_socket.h8
-rw-r--r--chromium/net/socket/socks5_client_socket_fuzzer.cc4
-rw-r--r--chromium/net/socket/socks5_client_socket_unittest.cc75
-rw-r--r--chromium/net/socket/socks_client_socket.cc19
-rw-r--r--chromium/net/socket/socks_client_socket.h12
-rw-r--r--chromium/net/socket/socks_client_socket_fuzzer.cc4
-rw-r--r--chromium/net/socket/socks_client_socket_pool.cc28
-rw-r--r--chromium/net/socket/socks_client_socket_pool.h5
-rw-r--r--chromium/net/socket/socks_client_socket_pool_unittest.cc56
-rw-r--r--chromium/net/socket/socks_client_socket_unittest.cc117
-rw-r--r--chromium/net/socket/ssl_client_socket.cc114
-rw-r--r--chromium/net/socket/ssl_client_socket.h76
-rw-r--r--chromium/net/socket/ssl_client_socket_impl.cc559
-rw-r--r--chromium/net/socket/ssl_client_socket_impl.h83
-rw-r--r--chromium/net/socket/ssl_client_socket_pool.cc78
-rw-r--r--chromium/net/socket/ssl_client_socket_pool.h5
-rw-r--r--chromium/net/socket/ssl_client_socket_pool_unittest.cc251
-rw-r--r--chromium/net/socket/ssl_client_socket_unittest.cc949
-rw-r--r--chromium/net/socket/ssl_server_socket_impl.cc24
-rw-r--r--chromium/net/socket/ssl_server_socket_impl.h1
-rw-r--r--chromium/net/socket/ssl_server_socket_unittest.cc89
-rw-r--r--chromium/net/socket/ssl_socket.h1
-rw-r--r--chromium/net/socket/stream_socket.h5
-rw-r--r--chromium/net/socket/tcp_client_socket.cc6
-rw-r--r--chromium/net/socket/tcp_client_socket.h7
-rw-r--r--chromium/net/socket/tcp_client_socket_unittest.cc41
-rw-r--r--chromium/net/socket/tcp_server_socket.cc2
-rw-r--r--chromium/net/socket/tcp_server_socket.h6
-rw-r--r--chromium/net/socket/tcp_server_socket_unittest.cc51
-rw-r--r--chromium/net/socket/tcp_socket_posix.cc50
-rw-r--r--chromium/net/socket/tcp_socket_posix.h16
-rw-r--r--chromium/net/socket/tcp_socket_unittest.cc71
-rw-r--r--chromium/net/socket/tcp_socket_win.cc56
-rw-r--r--chromium/net/socket/tcp_socket_win.h16
-rw-r--r--chromium/net/socket/transport_client_socket_pool.cc32
-rw-r--r--chromium/net/socket/transport_client_socket_pool.h17
-rw-r--r--chromium/net/socket/transport_client_socket_pool_test_util.cc29
-rw-r--r--chromium/net/socket/transport_client_socket_pool_test_util.h6
-rw-r--r--chromium/net/socket/transport_client_socket_pool_unittest.cc274
-rw-r--r--chromium/net/socket/transport_client_socket_unittest.cc36
-rw-r--r--chromium/net/socket/unix_domain_client_socket_posix.cc2
-rw-r--r--chromium/net/socket/unix_domain_client_socket_posix.h6
-rw-r--r--chromium/net/socket/unix_domain_client_socket_posix_unittest.cc61
-rw-r--r--chromium/net/socket/unix_domain_server_socket_posix_unittest.cc20
-rw-r--r--chromium/net/socket/websocket_endpoint_lock_manager.cc7
-rw-r--r--chromium/net/socket/websocket_endpoint_lock_manager_unittest.cc35
-rw-r--r--chromium/net/socket/websocket_transport_client_socket_pool.cc154
-rw-r--r--chromium/net/socket/websocket_transport_client_socket_pool.h31
-rw-r--r--chromium/net/socket/websocket_transport_client_socket_pool_unittest.cc319
-rw-r--r--chromium/net/socket/websocket_transport_connect_sub_job.cc4
-rw-r--r--chromium/net/socket/websocket_transport_connect_sub_job.h4
-rw-r--r--chromium/net/spdy/bidirectional_stream_spdy_impl.cc41
-rw-r--r--chromium/net/spdy/bidirectional_stream_spdy_impl.h13
-rw-r--r--chromium/net/spdy/bidirectional_stream_spdy_impl_unittest.cc217
-rw-r--r--chromium/net/spdy/buffered_spdy_framer.cc118
-rw-r--r--chromium/net/spdy/buffered_spdy_framer.h39
-rw-r--r--chromium/net/spdy/buffered_spdy_framer_unittest.cc162
-rw-r--r--chromium/net/spdy/header_coalescer.cc17
-rw-r--r--chromium/net/spdy/header_coalescer.h10
-rw-r--r--chromium/net/spdy/header_coalescer_test.cc80
-rw-r--r--chromium/net/spdy/hpack/hpack_constants.h6
-rw-r--r--chromium/net/spdy/hpack/hpack_decoder.cc94
-rw-r--r--chromium/net/spdy/hpack/hpack_decoder.h60
-rw-r--r--chromium/net/spdy/hpack/hpack_decoder_interface.h6
-rw-r--r--chromium/net/spdy/hpack/hpack_decoder_test.cc11
-rw-r--r--chromium/net/spdy/hpack/hpack_encoder.cc230
-rw-r--r--chromium/net/spdy/hpack/hpack_encoder.h66
-rw-r--r--chromium/net/spdy/hpack/hpack_encoder_test.cc145
-rw-r--r--chromium/net/spdy/hpack/hpack_header_table.cc7
-rw-r--r--chromium/net/spdy/hpack/hpack_header_table_test.cc36
-rw-r--r--chromium/net/spdy/hpack/hpack_huffman_decoder.cc7
-rw-r--r--chromium/net/spdy/hpack/hpack_huffman_decoder.h3
-rw-r--r--chromium/net/spdy/hpack/hpack_huffman_table.cc5
-rw-r--r--chromium/net/spdy/hpack/hpack_huffman_table.h1
-rw-r--r--chromium/net/spdy/hpack/hpack_huffman_table_test.cc37
-rw-r--r--chromium/net/spdy/hpack/hpack_input_stream.cc2
-rw-r--r--chromium/net/spdy/hpack/hpack_output_stream.cc20
-rw-r--r--chromium/net/spdy/hpack/hpack_output_stream.h11
-rw-r--r--chromium/net/spdy/hpack/hpack_output_stream_test.cc19
-rw-r--r--chromium/net/spdy/hpack/hpack_round_trip_test.cc53
-rw-r--r--chromium/net/spdy/hpack/hpack_static_table.h1
-rw-r--r--chromium/net/spdy/hpack/hpack_static_table_test.cc1
-rw-r--r--chromium/net/spdy/http2_priority_dependencies.h1
-rw-r--r--chromium/net/spdy/http2_write_scheduler.h75
-rw-r--r--chromium/net/spdy/http2_write_scheduler_test.cc74
-rw-r--r--chromium/net/spdy/priority_write_scheduler.h19
-rw-r--r--chromium/net/spdy/priority_write_scheduler_test.cc42
-rw-r--r--chromium/net/spdy/spdy_deframer_visitor.cc1112
-rw-r--r--chromium/net/spdy/spdy_deframer_visitor.h250
-rw-r--r--chromium/net/spdy/spdy_deframer_visitor_test.cc273
-rw-r--r--chromium/net/spdy/spdy_flags.cc18
-rw-r--r--chromium/net/spdy/spdy_flags.h10
-rw-r--r--chromium/net/spdy/spdy_frame_builder.cc27
-rw-r--r--chromium/net/spdy/spdy_frame_builder.h4
-rw-r--r--chromium/net/spdy/spdy_framer.cc393
-rw-r--r--chromium/net/spdy/spdy_framer.h111
-rw-r--r--chromium/net/spdy/spdy_framer_decoder_adapter.cc23
-rw-r--r--chromium/net/spdy/spdy_framer_decoder_adapter.h14
-rw-r--r--chromium/net/spdy/spdy_framer_test.cc294
-rw-r--r--chromium/net/spdy/spdy_header_block.cc73
-rw-r--r--chromium/net/spdy/spdy_header_block.h25
-rw-r--r--chromium/net/spdy/spdy_header_block_test.cc95
-rw-r--r--chromium/net/spdy/spdy_headers_block_parser.cc12
-rw-r--r--chromium/net/spdy/spdy_headers_block_parser_test.cc35
-rw-r--r--chromium/net/spdy/spdy_headers_handler_interface.h10
-rw-r--r--chromium/net/spdy/spdy_http_stream.cc69
-rw-r--r--chromium/net/spdy/spdy_http_stream.h20
-rw-r--r--chromium/net/spdy/spdy_http_stream_unittest.cc527
-rw-r--r--chromium/net/spdy/spdy_http_utils.cc83
-rw-r--r--chromium/net/spdy/spdy_http_utils.h16
-rw-r--r--chromium/net/spdy/spdy_http_utils_unittest.cc85
-rw-r--r--chromium/net/spdy/spdy_network_transaction_unittest.cc4269
-rw-r--r--chromium/net/spdy/spdy_no_op_visitor.cc34
-rw-r--r--chromium/net/spdy/spdy_no_op_visitor.h97
-rw-r--r--chromium/net/spdy/spdy_protocol.cc58
-rw-r--r--chromium/net/spdy/spdy_protocol.h70
-rw-r--r--chromium/net/spdy/spdy_protocol_test.cc27
-rw-r--r--chromium/net/spdy/spdy_protocol_test_utils.cc191
-rw-r--r--chromium/net/spdy/spdy_protocol_test_utils.h160
-rw-r--r--chromium/net/spdy/spdy_proxy_client_socket.cc72
-rw-r--r--chromium/net/spdy/spdy_proxy_client_socket.h19
-rw-r--r--chromium/net/spdy/spdy_proxy_client_socket_unittest.cc657
-rw-r--r--chromium/net/spdy/spdy_read_queue.cc17
-rw-r--r--chromium/net/spdy/spdy_read_queue.h4
-rw-r--r--chromium/net/spdy/spdy_read_queue_unittest.cc37
-rw-r--r--chromium/net/spdy/spdy_session.cc614
-rw-r--r--chromium/net/spdy/spdy_session.h132
-rw-r--r--chromium/net/spdy/spdy_session_key.h1
-rw-r--r--chromium/net/spdy/spdy_session_pool.cc45
-rw-r--r--chromium/net/spdy/spdy_session_pool.h29
-rw-r--r--chromium/net/spdy/spdy_session_pool_unittest.cc209
-rw-r--r--chromium/net/spdy/spdy_session_unittest.cc2645
-rw-r--r--chromium/net/spdy/spdy_stream.cc108
-rw-r--r--chromium/net/spdy/spdy_stream.h74
-rw-r--r--chromium/net/spdy/spdy_stream_test_util.cc5
-rw-r--r--chromium/net/spdy/spdy_stream_unittest.cc572
-rw-r--r--chromium/net/spdy/spdy_test_util_common.cc595
-rw-r--r--chromium/net/spdy/spdy_test_util_common.h268
-rw-r--r--chromium/net/spdy/spdy_test_utils.cc17
-rw-r--r--chromium/net/spdy/spdy_test_utils.h3
-rw-r--r--chromium/net/spdy/spdy_write_queue.cc67
-rw-r--r--chromium/net/spdy/spdy_write_queue.h11
-rw-r--r--chromium/net/spdy/spdy_write_queue_unittest.cc41
-rw-r--r--chromium/net/spdy/write_scheduler.h1
-rw-r--r--chromium/net/ssl/channel_id_service.cc25
-rw-r--r--chromium/net/ssl/channel_id_service.h2
-rw-r--r--chromium/net/ssl/channel_id_service_unittest.cc87
-rw-r--r--chromium/net/ssl/client_cert_store_nss.cc41
-rw-r--r--chromium/net/ssl/client_cert_store_nss_unittest.cc76
-rw-r--r--chromium/net/ssl/client_cert_store_unittest-inl.h17
-rw-r--r--chromium/net/ssl/default_channel_id_store_unittest.cc85
-rw-r--r--chromium/net/ssl/openssl_client_key_store.cc127
-rw-r--r--chromium/net/ssl/openssl_client_key_store.h56
-rw-r--r--chromium/net/ssl/openssl_client_key_store_unittest.cc147
-rw-r--r--chromium/net/ssl/openssl_ssl_util.cc6
-rw-r--r--chromium/net/ssl/openssl_ssl_util.h4
-rw-r--r--chromium/net/ssl/signed_certificate_timestamp_and_status.cc23
-rw-r--r--chromium/net/ssl/signed_certificate_timestamp_and_status.h38
-rw-r--r--chromium/net/ssl/ssl_cipher_suite_names.cc104
-rw-r--r--chromium/net/ssl/ssl_cipher_suite_names.h34
-rw-r--r--chromium/net/ssl/ssl_cipher_suite_names_unittest.cc112
-rw-r--r--chromium/net/ssl/ssl_client_session_cache.cc48
-rw-r--r--chromium/net/ssl/ssl_client_session_cache.h16
-rw-r--r--chromium/net/ssl/ssl_client_session_cache_unittest.cc46
-rw-r--r--chromium/net/ssl/ssl_config.cc31
-rw-r--r--chromium/net/ssl/ssl_config.h39
-rw-r--r--chromium/net/ssl/ssl_connection_status_flags.h5
-rw-r--r--chromium/net/ssl/ssl_info.cc25
-rw-r--r--chromium/net/ssl/ssl_info.h16
-rw-r--r--chromium/net/ssl/ssl_key_logger.cc6
-rw-r--r--chromium/net/ssl/ssl_platform_key_android.cc241
-rw-r--r--chromium/net/ssl/ssl_platform_key_android.h25
-rw-r--r--chromium/net/ssl/ssl_platform_key_android_unittest.cc354
-rw-r--r--chromium/net/ssl/ssl_platform_key_chromecast.cc2
-rw-r--r--chromium/net/ssl/ssl_platform_key_mac.cc2
-rw-r--r--chromium/net/ssl/ssl_platform_key_nss.cc2
-rw-r--r--chromium/net/ssl/ssl_platform_key_task_runner.cc21
-rw-r--r--chromium/net/ssl/ssl_platform_key_task_runner.h19
-rw-r--r--chromium/net/ssl/ssl_platform_key_win.cc45
-rw-r--r--chromium/net/ssl/ssl_server_config.cc2
-rw-r--r--chromium/net/ssl/test_ssl_private_key.cc2
-rw-r--r--chromium/net/ssl/threaded_ssl_private_key.cc4
-rw-r--r--chromium/net/ssl/threaded_ssl_private_key.h9
-rw-r--r--chromium/net/ssl/token_binding.cc85
-rw-r--r--chromium/net/ssl/token_binding.h38
-rw-r--r--chromium/net/test/ct_test_util.cc16
-rw-r--r--chromium/net/test/embedded_test_server/android/embedded_test_server_android.cc10
-rw-r--r--chromium/net/test/embedded_test_server/android/embedded_test_server_android.h3
-rw-r--r--chromium/net/test/embedded_test_server/default_handlers.cc8
-rw-r--r--chromium/net/test/embedded_test_server/embedded_test_server.cc38
-rw-r--r--chromium/net/test/embedded_test_server/embedded_test_server.h6
-rw-r--r--chromium/net/test/embedded_test_server/embedded_test_server_unittest.cc15
-rw-r--r--chromium/net/test/embedded_test_server/request_handler_util.cc3
-rw-r--r--chromium/net/test/gtest_util.h100
-rw-r--r--chromium/net/test/net_test_suite.cc7
-rw-r--r--chromium/net/test/python_utils.cc5
-rw-r--r--chromium/net/test/python_utils.h3
-rw-r--r--chromium/net/test/python_utils_unittest.cc9
-rw-r--r--chromium/net/test/run_all_unittests.cc11
-rw-r--r--chromium/net/test/spawned_test_server/base_test_server.cc123
-rw-r--r--chromium/net/test/spawned_test_server/base_test_server.h57
-rw-r--r--chromium/net/test/spawned_test_server/local_test_server.cc5
-rw-r--r--chromium/net/test/spawned_test_server/local_test_server_win.cc3
-rw-r--r--chromium/net/test/spawned_test_server/spawner_communicator.cc59
-rw-r--r--chromium/net/test/spawned_test_server/spawner_communicator.h4
-rw-r--r--chromium/net/test/test_data_directory.cc7
-rw-r--r--chromium/net/test/url_request/url_request_hanging_read_job.cc4
-rw-r--r--chromium/net/test/url_request/url_request_hanging_read_job.h1
-rw-r--r--chromium/net/test/url_request/url_request_mock_data_job.cc4
-rw-r--r--chromium/net/test/url_request/url_request_mock_data_job.h1
-rw-r--r--chromium/net/third_party/nss/README.chromium7
-rw-r--r--chromium/net/third_party/nss/ssl/cmpcert.c89
-rw-r--r--chromium/net/third_party/nss/ssl/cmpcert.cc58
-rw-r--r--chromium/net/third_party/nss/ssl/cmpcert.h30
-rw-r--r--chromium/net/tools/DEPS1
-rw-r--r--chromium/net/tools/balsa/balsa_headers.cc6
-rw-r--r--chromium/net/tools/balsa/balsa_headers.h1
-rw-r--r--chromium/net/tools/balsa/balsa_headers_token_utils.cc2
-rw-r--r--chromium/net/tools/cachetool/cachetool.cc502
-rw-r--r--chromium/net/tools/cert_verify_tool/cert_verify_tool.cc103
-rw-r--r--chromium/net/tools/cert_verify_tool/cert_verify_tool_util.cc8
-rw-r--r--chromium/net/tools/cert_verify_tool/cert_verify_tool_util.h6
-rw-r--r--chromium/net/tools/cert_verify_tool/verify_using_path_builder.cc273
-rw-r--r--chromium/net/tools/cert_verify_tool/verify_using_path_builder.h29
-rw-r--r--chromium/net/tools/epoll_server/epoll_server.cc2
-rw-r--r--chromium/net/tools/flip_server/acceptor_thread.cc206
-rw-r--r--chromium/net/tools/flip_server/acceptor_thread.h95
-rw-r--r--chromium/net/tools/flip_server/constants.h25
-rw-r--r--chromium/net/tools/flip_server/flip_config.cc144
-rw-r--r--chromium/net/tools/flip_server/flip_config.h97
-rw-r--r--chromium/net/tools/flip_server/flip_in_mem_edsm_server.cc403
-rw-r--r--chromium/net/tools/flip_server/flip_test_utils.cc13
-rw-r--r--chromium/net/tools/flip_server/flip_test_utils.h58
-rw-r--r--chromium/net/tools/flip_server/http_interface.cc343
-rw-r--r--chromium/net/tools/flip_server/http_interface.h143
-rw-r--r--chromium/net/tools/flip_server/http_interface_test.cc491
-rw-r--r--chromium/net/tools/flip_server/mem_cache.cc238
-rw-r--r--chromium/net/tools/flip_server/mem_cache.h154
-rw-r--r--chromium/net/tools/flip_server/mem_cache_test.cc100
-rw-r--r--chromium/net/tools/flip_server/output_ordering.cc180
-rw-r--r--chromium/net/tools/flip_server/output_ordering.h91
-rw-r--r--chromium/net/tools/flip_server/ring_buffer.cc241
-rw-r--r--chromium/net/tools/flip_server/ring_buffer.h113
-rw-r--r--chromium/net/tools/flip_server/run_all_tests.cc8
-rw-r--r--chromium/net/tools/flip_server/sm_connection.cc661
-rw-r--r--chromium/net/tools/flip_server/sm_connection.h163
-rw-r--r--chromium/net/tools/flip_server/sm_interface.h87
-rw-r--r--chromium/net/tools/flip_server/spdy_interface.cc616
-rw-r--r--chromium/net/tools/flip_server/spdy_interface.h238
-rw-r--r--chromium/net/tools/flip_server/spdy_interface_test.cc642
-rw-r--r--chromium/net/tools/flip_server/spdy_ssl.cc114
-rw-r--r--chromium/net/tools/flip_server/spdy_ssl.h30
-rw-r--r--chromium/net/tools/flip_server/spdy_util.cc35
-rw-r--r--chromium/net/tools/flip_server/spdy_util.h22
-rw-r--r--chromium/net/tools/flip_server/streamer_interface.cc201
-rw-r--r--chromium/net/tools/flip_server/streamer_interface.h138
-rw-r--r--chromium/net/tools/flip_server/tcp_socket_util.cc276
-rw-r--r--chromium/net/tools/flip_server/tcp_socket_util.h54
-rw-r--r--chromium/net/tools/flip_server/url_to_filename_encoder.cc275
-rw-r--r--chromium/net/tools/flip_server/url_to_filename_encoder.h214
-rw-r--r--chromium/net/tools/flip_server/url_to_filename_encoder_unittest.cc357
-rw-r--r--chromium/net/tools/flip_server/url_utilities.cc124
-rw-r--r--chromium/net/tools/flip_server/url_utilities.h35
-rw-r--r--chromium/net/tools/flip_server/url_utilities_unittest.cc98
-rw-r--r--chromium/net/tools/gdig/file_net_log.cc5
-rw-r--r--chromium/net/tools/gdig/file_net_log.h2
-rw-r--r--chromium/net/tools/gdig/gdig.cc12
-rw-r--r--chromium/net/tools/get_server_time/get_server_time.cc11
-rw-r--r--chromium/net/tools/net_watcher/net_watcher.cc23
-rw-r--r--chromium/net/tools/quic/chlo_extractor.cc19
-rw-r--r--chromium/net/tools/quic/chlo_extractor.h6
-rw-r--r--chromium/net/tools/quic/chlo_extractor_test.cc12
-rw-r--r--chromium/net/tools/quic/crypto_message_printer_bin.cc4
-rw-r--r--chromium/net/tools/quic/end_to_end_test.cc504
-rw-r--r--chromium/net/tools/quic/quic_client.cc367
-rw-r--r--chromium/net/tools/quic/quic_client.h211
-rw-r--r--chromium/net/tools/quic/quic_client_base.cc343
-rw-r--r--chromium/net/tools/quic/quic_client_base.h248
-rw-r--r--chromium/net/tools/quic/quic_client_bin.cc39
-rw-r--r--chromium/net/tools/quic/quic_client_session.cc12
-rw-r--r--chromium/net/tools/quic/quic_client_session.h9
-rw-r--r--chromium/net/tools/quic/quic_client_session_test.cc9
-rw-r--r--chromium/net/tools/quic/quic_client_test.cc6
-rw-r--r--chromium/net/tools/quic/quic_default_packet_writer.h5
-rw-r--r--chromium/net/tools/quic/quic_dispatcher.cc366
-rw-r--r--chromium/net/tools/quic/quic_dispatcher.h122
-rw-r--r--chromium/net/tools/quic/quic_dispatcher_test.cc931
-rw-r--r--chromium/net/tools/quic/quic_epoll_alarm_factory.cc3
-rw-r--r--chromium/net/tools/quic/quic_epoll_alarm_factory.h4
-rw-r--r--chromium/net/tools/quic/quic_epoll_alarm_factory_test.cc35
-rw-r--r--chromium/net/tools/quic/quic_epoll_clock.cc14
-rw-r--r--chromium/net/tools/quic/quic_epoll_clock.h4
-rw-r--r--chromium/net/tools/quic/quic_epoll_clock_test.cc8
-rw-r--r--chromium/net/tools/quic/quic_epoll_connection_helper.cc2
-rw-r--r--chromium/net/tools/quic/quic_epoll_connection_helper.h10
-rw-r--r--chromium/net/tools/quic/quic_epoll_connection_helper_test.cc4
-rw-r--r--chromium/net/tools/quic/quic_in_memory_cache.cc40
-rw-r--r--chromium/net/tools/quic/quic_in_memory_cache.h6
-rw-r--r--chromium/net/tools/quic/quic_in_memory_cache_test.cc18
-rw-r--r--chromium/net/tools/quic/quic_packet_printer_bin.cc6
-rw-r--r--chromium/net/tools/quic/quic_packet_reader.cc71
-rw-r--r--chromium/net/tools/quic/quic_packet_reader.h9
-rw-r--r--chromium/net/tools/quic/quic_packet_writer_wrapper.cc2
-rw-r--r--chromium/net/tools/quic/quic_packet_writer_wrapper.h2
-rw-r--r--chromium/net/tools/quic/quic_per_connection_packet_writer.h6
-rw-r--r--chromium/net/tools/quic/quic_process_packet_interface.h2
-rw-r--r--chromium/net/tools/quic/quic_reject_reason_decoder_bin.cc47
-rw-r--r--chromium/net/tools/quic/quic_server.cc52
-rw-r--r--chromium/net/tools/quic/quic_server.h24
-rw-r--r--chromium/net/tools/quic/quic_server_bin.cc16
-rw-r--r--chromium/net/tools/quic/quic_server_test.cc130
-rw-r--r--chromium/net/tools/quic/quic_simple_client.cc347
-rw-r--r--chromium/net/tools/quic/quic_simple_client.h191
-rw-r--r--chromium/net/tools/quic/quic_simple_client_bin.cc37
-rw-r--r--chromium/net/tools/quic/quic_simple_client_test.cc2
-rw-r--r--chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.cc28
-rw-r--r--chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.h35
-rw-r--r--chromium/net/tools/quic/quic_simple_dispatcher.cc43
-rw-r--r--chromium/net/tools/quic/quic_simple_dispatcher.h32
-rw-r--r--chromium/net/tools/quic/quic_simple_per_connection_packet_writer.h4
-rw-r--r--chromium/net/tools/quic/quic_simple_server.cc86
-rw-r--r--chromium/net/tools/quic/quic_simple_server.h31
-rw-r--r--chromium/net/tools/quic/quic_simple_server_bin.cc17
-rw-r--r--chromium/net/tools/quic/quic_simple_server_packet_writer.cc5
-rw-r--r--chromium/net/tools/quic/quic_simple_server_packet_writer.h36
-rw-r--r--chromium/net/tools/quic/quic_simple_server_session.cc20
-rw-r--r--chromium/net/tools/quic/quic_simple_server_session.h11
-rw-r--r--chromium/net/tools/quic/quic_simple_server_session_helper.h6
-rw-r--r--chromium/net/tools/quic/quic_simple_server_session_helper_test.cc8
-rw-r--r--chromium/net/tools/quic/quic_simple_server_session_test.cc124
-rw-r--r--chromium/net/tools/quic/quic_simple_server_stream.cc18
-rw-r--r--chromium/net/tools/quic/quic_simple_server_stream.h4
-rw-r--r--chromium/net/tools/quic/quic_simple_server_stream_test.cc35
-rw-r--r--chromium/net/tools/quic/quic_simple_server_test.cc10
-rw-r--r--chromium/net/tools/quic/quic_socket_utils.cc46
-rw-r--r--chromium/net/tools/quic/quic_socket_utils.h21
-rw-r--r--chromium/net/tools/quic/quic_spdy_client_stream.cc18
-rw-r--r--chromium/net/tools/quic/quic_spdy_client_stream.h4
-rw-r--r--chromium/net/tools/quic/quic_spdy_client_stream_test.cc5
-rw-r--r--chromium/net/tools/quic/quic_time_wait_list_manager.cc34
-rw-r--r--chromium/net/tools/quic/quic_time_wait_list_manager.h14
-rw-r--r--chromium/net/tools/quic/quic_time_wait_list_manager_test.cc36
-rw-r--r--chromium/net/tools/quic/spdy_balsa_utils.cc28
-rw-r--r--chromium/net/tools/quic/spdy_balsa_utils.h2
-rw-r--r--chromium/net/tools/quic/spdy_balsa_utils_test.cc4
-rw-r--r--chromium/net/tools/quic/stateless_rejector.cc116
-rw-r--r--chromium/net/tools/quic/stateless_rejector.h49
-rw-r--r--chromium/net/tools/quic/stateless_rejector_test.cc126
-rw-r--r--chromium/net/tools/quic/synchronous_host_resolver.cc17
-rw-r--r--chromium/net/tools/quic/synchronous_host_resolver.h1
-rw-r--r--chromium/net/tools/quic/test_tools/limited_mtu_test_writer.h2
-rw-r--r--chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.cc4
-rw-r--r--chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.h13
-rw-r--r--chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc8
-rw-r--r--chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h9
-rw-r--r--chromium/net/tools/quic/test_tools/packet_reordering_writer.cc50
-rw-r--r--chromium/net/tools/quic/test_tools/packet_reordering_writer.h45
-rw-r--r--chromium/net/tools/quic/test_tools/quic_client_peer.cc4
-rw-r--r--chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc25
-rw-r--r--chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h13
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_client.cc222
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_client.h56
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_server.cc58
-rw-r--r--chromium/net/tools/quic/test_tools/quic_test_server.h10
-rw-r--r--chromium/net/tools/quic/test_tools/server_thread.h2
-rw-r--r--chromium/net/tools/quic/test_tools/simple_client.cc14
-rw-r--r--chromium/net/tools/quic/test_tools/simple_client.h6
-rw-r--r--chromium/net/tools/testserver/minica.py210
-rw-r--r--chromium/net/tools/testserver/run_testserver.cc3
-rwxr-xr-xchromium/net/tools/testserver/testserver.py105
-rw-r--r--chromium/net/tools/tld_cleanup/tld_cleanup.gyp23
-rw-r--r--chromium/net/tools/tld_cleanup/tld_cleanup_util.cc2
-rw-r--r--chromium/net/udp/datagram_client_socket.h1
-rw-r--r--chromium/net/udp/datagram_server_socket.h1
-rw-r--r--chromium/net/udp/datagram_socket.h15
-rw-r--r--chromium/net/udp/fuzzed_datagram_client_socket.cc12
-rw-r--r--chromium/net/udp/fuzzed_datagram_client_socket.h17
-rw-r--r--chromium/net/udp/udp_client_socket.cc13
-rw-r--r--chromium/net/udp/udp_client_socket.h15
-rw-r--r--chromium/net/udp/udp_net_log_parameters.cc4
-rw-r--r--chromium/net/udp/udp_net_log_parameters.h6
-rw-r--r--chromium/net/udp/udp_server_socket.cc20
-rw-r--r--chromium/net/udp/udp_server_socket.h16
-rw-r--r--chromium/net/udp/udp_socket_perftest.cc19
-rw-r--r--chromium/net/udp/udp_socket_posix.cc140
-rw-r--r--chromium/net/udp/udp_socket_posix.h17
-rw-r--r--chromium/net/udp/udp_socket_unittest.cc305
-rw-r--r--chromium/net/udp/udp_socket_win.cc39
-rw-r--r--chromium/net/udp/udp_socket_win.h17
-rw-r--r--chromium/net/url_request/data_protocol_handler.h1
-rw-r--r--chromium/net/url_request/file_protocol_handler.h1
-rw-r--r--chromium/net/url_request/ftp_protocol_handler.h1
-rw-r--r--chromium/net/url_request/report_sender.cc27
-rw-r--r--chromium/net/url_request/report_sender.h12
-rw-r--r--chromium/net/url_request/report_sender_unittest.cc22
-rw-r--r--chromium/net/url_request/sdch_dictionary_fetcher.cc36
-rw-r--r--chromium/net/url_request/sdch_dictionary_fetcher.h7
-rw-r--r--chromium/net/url_request/sdch_dictionary_fetcher_unittest.cc2
-rw-r--r--chromium/net/url_request/test_url_fetcher_factory.cc4
-rw-r--r--chromium/net/url_request/url_fetcher_core.cc50
-rw-r--r--chromium/net/url_request/url_fetcher_core.h8
-rw-r--r--chromium/net/url_request/url_fetcher_delegate.cc8
-rw-r--r--chromium/net/url_request/url_fetcher_delegate.h5
-rw-r--r--chromium/net/url_request/url_fetcher_impl_unittest.cc60
-rw-r--r--chromium/net/url_request/url_fetcher_response_writer.cc108
-rw-r--r--chromium/net/url_request/url_fetcher_response_writer.h32
-rw-r--r--chromium/net/url_request/url_fetcher_response_writer_unittest.cc102
-rw-r--r--chromium/net/url_request/url_request.cc175
-rw-r--r--chromium/net/url_request/url_request.h112
-rw-r--r--chromium/net/url_request/url_request_backoff_manager.cc147
-rw-r--r--chromium/net/url_request/url_request_backoff_manager.h138
-rw-r--r--chromium/net/url_request/url_request_backoff_manager_unittest.cc118
-rw-r--r--chromium/net/url_request/url_request_context.h14
-rw-r--r--chromium/net/url_request/url_request_context_builder.cc48
-rw-r--r--chromium/net/url_request/url_request_context_builder.h27
-rw-r--r--chromium/net/url_request/url_request_context_builder_unittest.cc20
-rw-r--r--chromium/net/url_request/url_request_context_getter.cc2
-rw-r--r--chromium/net/url_request/url_request_context_storage.cc7
-rw-r--r--chromium/net/url_request/url_request_context_storage.h10
-rw-r--r--chromium/net/url_request/url_request_data_job.h1
-rw-r--r--chromium/net/url_request/url_request_data_job_fuzzer.cc39
-rw-r--r--chromium/net/url_request/url_request_file_dir_job_unittest.cc47
-rw-r--r--chromium/net/url_request/url_request_file_job_unittest.cc70
-rw-r--r--chromium/net/url_request/url_request_ftp_job.cc22
-rw-r--r--chromium/net/url_request/url_request_ftp_job.h7
-rw-r--r--chromium/net/url_request/url_request_ftp_job_unittest.cc49
-rw-r--r--chromium/net/url_request/url_request_fuzzer.cc4
-rw-r--r--chromium/net/url_request/url_request_http_job.cc99
-rw-r--r--chromium/net/url_request/url_request_http_job.h8
-rw-r--r--chromium/net/url_request/url_request_http_job_unittest.cc361
-rw-r--r--chromium/net/url_request/url_request_job.cc132
-rw-r--r--chromium/net/url_request/url_request_job.h25
-rw-r--r--chromium/net/url_request/url_request_job_factory_impl.cc6
-rw-r--r--chromium/net/url_request/url_request_job_factory_impl_unittest.cc11
-rw-r--r--chromium/net/url_request/url_request_job_unittest.cc31
-rw-r--r--chromium/net/url_request/url_request_netlog_params.cc1
-rw-r--r--chromium/net/url_request/url_request_netlog_params.h4
-rw-r--r--chromium/net/url_request/url_request_quic_unittest.cc246
-rw-r--r--chromium/net/url_request/url_request_redirect_job.cc11
-rw-r--r--chromium/net/url_request/url_request_simple_job_unittest.cc72
-rw-r--r--chromium/net/url_request/url_request_test_job.cc37
-rw-r--r--chromium/net/url_request/url_request_test_job.h17
-rw-r--r--chromium/net/url_request/url_request_test_util.cc126
-rw-r--r--chromium/net/url_request/url_request_test_util.h20
-rw-r--r--chromium/net/url_request/url_request_throttler_entry.cc27
-rw-r--r--chromium/net/url_request/url_request_throttler_entry.h10
-rw-r--r--chromium/net/url_request/url_request_throttler_manager.cc8
-rw-r--r--chromium/net/url_request/url_request_throttler_manager.h4
-rw-r--r--chromium/net/url_request/url_request_throttler_unittest.cc18
-rw-r--r--chromium/net/url_request/url_request_unittest.cc1257
-rw-r--r--chromium/net/url_request/view_cache_helper_unittest.cc24
-rw-r--r--chromium/net/websockets/websocket_basic_handshake_stream.cc41
-rw-r--r--chromium/net/websockets/websocket_basic_handshake_stream.h17
-rw-r--r--chromium/net/websockets/websocket_basic_stream.h1
-rw-r--r--chromium/net/websockets/websocket_basic_stream_test.cc184
-rw-r--r--chromium/net/websockets/websocket_channel.cc113
-rw-r--r--chromium/net/websockets/websocket_channel.h51
-rw-r--r--chromium/net/websockets/websocket_channel_test.cc487
-rw-r--r--chromium/net/websockets/websocket_deflate_predictor_impl_test.cc2
-rw-r--r--chromium/net/websockets/websocket_deflate_stream_fuzzer.cc103
-rw-r--r--chromium/net/websockets/websocket_deflate_stream_test.cc76
-rw-r--r--chromium/net/websockets/websocket_end_to_end_test.cc20
-rw-r--r--chromium/net/websockets/websocket_errors.h1
-rw-r--r--chromium/net/websockets/websocket_errors_test.cc6
-rw-r--r--chromium/net/websockets/websocket_event_interface.h10
-rw-r--r--chromium/net/websockets/websocket_extension_parser.cc55
-rw-r--r--chromium/net/websockets/websocket_extension_parser.h4
-rw-r--r--chromium/net/websockets/websocket_extension_parser_fuzzer.cc16
-rw-r--r--chromium/net/websockets/websocket_extension_parser_test.cc14
-rw-r--r--chromium/net/websockets/websocket_frame_parser_fuzzer.cc9
-rw-r--r--chromium/net/websockets/websocket_handshake_stream_base.h1
-rw-r--r--chromium/net/websockets/websocket_handshake_stream_create_helper.cc25
-rw-r--r--chromium/net/websockets/websocket_handshake_stream_create_helper.h29
-rw-r--r--chromium/net/websockets/websocket_handshake_stream_create_helper_test.cc35
-rw-r--r--chromium/net/websockets/websocket_stream.cc131
-rw-r--r--chromium/net/websockets/websocket_stream.h41
-rw-r--r--chromium/net/websockets/websocket_stream_cookie_test.cc4
-rw-r--r--chromium/net/websockets/websocket_stream_create_test_base.cc7
-rw-r--r--chromium/net/websockets/websocket_stream_create_test_base.h1
-rw-r--r--chromium/net/websockets/websocket_stream_test.cc18
-rw-r--r--chromium/net/websockets/websocket_test_util.h2
2126 files changed, 204425 insertions, 168139 deletions
diff --git a/chromium/net/BUILD.gn b/chromium/net/BUILD.gn
index 617cd80d23b..980b69230c0 100644
--- a/chromium/net/BUILD.gn
+++ b/chromium/net/BUILD.gn
@@ -8,13 +8,14 @@ import("//build/config/compiler/compiler.gni")
import("//build/config/crypto.gni")
import("//build/config/features.gni")
import("//build/config/ui.gni")
-import("//build_overrides/v8.gni")
+import("//net/features.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
import("//testing/test.gni")
import("//third_party/icu/config.gni")
import("//third_party/protobuf/proto_library.gni")
import("//tools/grit/grit_rule.gni")
import("//url/features.gni")
+import("//v8/gni/v8.gni")
if (is_android) {
import("//build/config/android/config.gni")
@@ -39,24 +40,6 @@ posix_avoid_mmap = is_android && current_cpu != "x86"
use_v8_in_net = !is_ios
enable_built_in_dns = !is_ios
-declare_args() {
- # Disables support for file URLs. File URL support requires use of icu.
- disable_file_support = false
-
- # WebSockets and socket stream code are not used on iOS and are optional in
- # cronet.
- enable_websockets = !is_ios
- disable_ftp_support = is_ios
-
- # Enable Kerberos authentication. It is disabled by default on ChromeOS, iOS,
- # Chromecast, at least for now. This feature needs configuration (krb5.conf
- # and so on).
- use_kerberos = !is_chromeos && !is_ios && !is_chromecast
-
- # Do not disable brotli filter by default.
- disable_brotli_filter = false
-}
-
config("net_config") {
defines = []
if (posix_avoid_mmap) {
@@ -195,7 +178,7 @@ component("net") {
]
}
- if (use_glib && use_gconf && !is_chromeos) {
+ if (use_gio) {
deps += [ "//build/linux/libgio" ]
}
@@ -204,6 +187,8 @@ component("net") {
"base/crypto_module_nss.cc",
"base/keygen_handler_nss.cc",
"cert/cert_database_nss.cc",
+ "cert/internal/trust_store_nss.cc",
+ "cert/internal/trust_store_nss.h",
"cert/nss_cert_database.cc",
"cert/nss_cert_database.h",
"cert/x509_certificate_nss.cc",
@@ -231,10 +216,10 @@ component("net") {
"ssl/ssl_platform_key_nss.cc",
]
} else {
- # client_cert_store_nss.c requires NSS_CmpCertChainWCANames from NSS's
- # libssl, but our bundled copy is not built in OpenSSL ports. Pull that
- # file in directly.
- sources += [ "third_party/nss/ssl/cmpcert.c" ]
+ sources += [
+ "third_party/nss/ssl/cmpcert.cc",
+ "third_party/nss/ssl/cmpcert.h",
+ ]
}
if (!use_nss_certs) {
@@ -263,10 +248,6 @@ component("net") {
"dns/mdns_client.h",
"dns/mdns_client_impl.cc",
"dns/mdns_client_impl.h",
- "dns/record_parsed.cc",
- "dns/record_parsed.h",
- "dns/record_rdata.cc",
- "dns/record_rdata.h",
]
}
@@ -360,6 +341,7 @@ component("net") {
"crypt32.lib",
"dhcpcsvc.lib",
"iphlpapi.lib",
+ "ncrypt.lib",
"rpcrt4.lib",
"secur32.lib",
"urlmon.lib",
@@ -384,10 +366,7 @@ component("net") {
if (use_platform_icu_alternatives) {
if (is_android) {
# Use ICU alternative on Android.
- sources += [
- "base/net_string_util_icu_alternatives_android.cc",
- "base/net_string_util_icu_alternatives_android.h",
- ]
+ sources += [ "base/net_string_util_icu_alternatives_android.cc" ]
deps += [ ":net_jni_headers" ]
} else if (is_ios) {
# Use ICU alternative on iOS.
@@ -411,9 +390,11 @@ component("net") {
# Brotli support.
if (!disable_brotli_filter) {
sources += [ "filter/brotli_filter.cc" ]
+ sources += [ "filter/brotli_source_stream.cc" ]
deps += [ "//third_party/brotli" ]
} else {
sources += [ "filter/brotli_filter_disabled.cc" ]
+ sources += [ "filter/brotli_source_stream_disabled.cc" ]
}
}
}
@@ -431,8 +412,8 @@ proto_library("net_quic_proto") {
visibility = [ ":net" ]
sources = [
- "quic/proto/cached_network_parameters.proto",
- "quic/proto/source_address_token.proto",
+ "quic/core/proto/cached_network_parameters.proto",
+ "quic/core/proto/source_address_token.proto",
]
cc_generator_options = "dllexport_decl=NET_EXPORT_PRIVATE:"
cc_include = "net/base/net_export.h"
@@ -510,7 +491,7 @@ bundle_data("test_support_bundle_data") {
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"base/load_timing_info_test_util.cc",
@@ -633,15 +614,15 @@ source_set("test_support") {
"//url",
]
- deps = [
- ":test_support_bundle_data",
- ]
+ deps = []
data = [
"data/",
]
- if (!is_ios) {
+ if (is_ios) {
+ deps += [ ":test_support_bundle_data" ]
+ } else {
public_deps += [ "//third_party/protobuf:py_proto" ]
}
@@ -823,6 +804,8 @@ if (!is_ios && !is_android) {
"tools/cert_verify_tool/cert_verify_tool_util.h",
"tools/cert_verify_tool/verify_using_cert_verify_proc.cc",
"tools/cert_verify_tool/verify_using_cert_verify_proc.h",
+ "tools/cert_verify_tool/verify_using_path_builder.cc",
+ "tools/cert_verify_tool/verify_using_path_builder.h",
]
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
@@ -978,14 +961,6 @@ if (!is_ios && !is_android) {
"//build/config/sanitizers:deps",
"//build/win:default_exe_manifest",
]
-
- if (is_desktop_linux && use_gconf && use_glib) {
- configs += [
- "//build/config/linux/gconf",
- "//build/config/linux:glib",
- ]
- deps += [ "//build/linux/libgio" ]
- }
}
}
@@ -1079,87 +1054,6 @@ if (is_linux) {
]
}
- static_library("flip_in_mem_edsm_server_base") {
- testonly = true
- sources = [
- "tools/flip_server/acceptor_thread.cc",
- "tools/flip_server/acceptor_thread.h",
- "tools/flip_server/constants.h",
- "tools/flip_server/flip_config.cc",
- "tools/flip_server/flip_config.h",
- "tools/flip_server/http_interface.cc",
- "tools/flip_server/http_interface.h",
- "tools/flip_server/mem_cache.cc",
- "tools/flip_server/mem_cache.h",
- "tools/flip_server/output_ordering.cc",
- "tools/flip_server/output_ordering.h",
- "tools/flip_server/ring_buffer.cc",
- "tools/flip_server/ring_buffer.h",
- "tools/flip_server/sm_connection.cc",
- "tools/flip_server/sm_connection.h",
- "tools/flip_server/sm_interface.h",
- "tools/flip_server/spdy_interface.cc",
- "tools/flip_server/spdy_interface.h",
- "tools/flip_server/spdy_ssl.cc",
- "tools/flip_server/spdy_ssl.h",
- "tools/flip_server/spdy_util.cc",
- "tools/flip_server/spdy_util.h",
- "tools/flip_server/streamer_interface.cc",
- "tools/flip_server/streamer_interface.h",
- "tools/flip_server/tcp_socket_util.cc",
- "tools/flip_server/tcp_socket_util.h",
- "tools/flip_server/url_to_filename_encoder.cc",
- "tools/flip_server/url_to_filename_encoder.h",
- "tools/flip_server/url_utilities.cc",
- "tools/flip_server/url_utilities.h",
- ]
- deps = [
- ":balsa",
- ":epoll_server",
- ":net",
- "//base",
- "//third_party/boringssl",
- ]
- }
-
- executable("flip_in_mem_edsm_server_unittests") {
- testonly = true
- sources = [
- "tools/flip_server/flip_test_utils.cc",
- "tools/flip_server/flip_test_utils.h",
- "tools/flip_server/http_interface_test.cc",
- "tools/flip_server/mem_cache_test.cc",
- "tools/flip_server/run_all_tests.cc",
- "tools/flip_server/spdy_interface_test.cc",
- "tools/flip_server/url_to_filename_encoder_unittest.cc",
- "tools/flip_server/url_utilities_unittest.cc",
- ]
- deps = [
- ":balsa",
- ":flip_in_mem_edsm_server_base",
- ":net",
- ":test_support",
- "//build/config/sanitizers:deps",
- "//testing/gmock",
- "//testing/gtest",
- "//third_party/boringssl",
- ]
- }
-
- executable("flip_in_mem_edsm_server") {
- testonly = true
- sources = [
- "tools/flip_server/flip_in_mem_edsm_server.cc",
- ]
- deps = [
- ":balsa",
- ":flip_in_mem_edsm_server_base",
- ":net",
- "//base",
- "//build/config/sanitizers:deps",
- ]
- }
-
source_set("epoll_quic_tools") {
sources = [
"tools/quic/quic_client.cc",
@@ -1230,6 +1124,7 @@ if (is_linux) {
if (is_android) {
generate_jni("net_jni_headers") {
sources = [
+ "android/java/src/org/chromium/net/AndroidCellularSignalStrength.java",
"android/java/src/org/chromium/net/AndroidCertVerifyResult.java",
"android/java/src/org/chromium/net/AndroidKeyStore.java",
"android/java/src/org/chromium/net/AndroidNetworkLibrary.java",
@@ -1284,6 +1179,10 @@ source_set("simple_quic_tools") {
"tools/quic/quic_process_packet_interface.h",
"tools/quic/quic_simple_client.cc",
"tools/quic/quic_simple_client.h",
+ "tools/quic/quic_simple_crypto_server_stream_helper.cc",
+ "tools/quic/quic_simple_crypto_server_stream_helper.h",
+ "tools/quic/quic_simple_dispatcher.cc",
+ "tools/quic/quic_simple_dispatcher.h",
"tools/quic/quic_simple_per_connection_packet_writer.cc",
"tools/quic/quic_simple_per_connection_packet_writer.h",
"tools/quic/quic_simple_server.cc",
@@ -1384,6 +1283,20 @@ if (!is_ios) {
"//third_party/protobuf:protobuf_lite",
]
}
+ executable("quic_reject_reason_decoder") {
+ sources = [
+ "tools/quic/quic_reject_reason_decoder_bin.cc",
+ ]
+ deps = [
+ ":net",
+ ":simple_quic_tools",
+ "//base",
+ "//build/config/sanitizers:deps",
+ "//build/win:default_exe_manifest",
+ "//third_party/boringssl",
+ "//third_party/protobuf:protobuf_lite",
+ ]
+ }
executable("crypto_message_printer") {
sources = [
"tools/quic/crypto_message_printer_bin.cc",
@@ -1421,7 +1334,6 @@ test("net_unittests") {
":balsa",
":extras",
":net",
- ":net_unittests_bundle_data",
":simple_quic_tools",
":stale_while_revalidate_experiment_domains",
":test_support",
@@ -1473,7 +1385,6 @@ test("net_unittests") {
deps += [
":epoll_quic_tools",
":epoll_server",
- ":flip_in_mem_edsm_server_base",
]
}
@@ -1481,6 +1392,10 @@ test("net_unittests") {
sources += gypi_values.net_base_test_mac_ios_sources
}
+ if (is_mac) {
+ libs = [ "Security.framework" ]
+ }
+
if (is_chromeos) {
sources -= [ "proxy/proxy_config_service_linux_unittest.cc" ]
}
@@ -1491,6 +1406,7 @@ test("net_unittests") {
if (!use_nss_certs) {
sources -= [
+ "cert/internal/trust_store_nss_unittest.cc",
"cert/nss_cert_database_unittest.cc",
"ssl/client_cert_store_nss_unittest.cc",
]
@@ -1596,8 +1512,6 @@ test("net_unittests") {
sources -= [
"dns/mdns_cache_unittest.cc",
"dns/mdns_client_unittest.cc",
- "dns/record_parsed_unittest.cc",
- "dns/record_rdata_unittest.cc",
]
}
@@ -1631,6 +1545,8 @@ test("net_unittests") {
"socket/unix_domain_client_socket_posix_unittest.cc",
"socket/unix_domain_server_socket_posix_unittest.cc",
]
+
+ bundle_deps = [ ":net_unittests_bundle_data" ]
}
# Unit tests that aren't supported by the current ICU alternatives on Android.
@@ -1669,6 +1585,7 @@ test("net_unittests") {
# Also, exclude the test from iOS for now (needs to read input data files).
if (disable_brotli_filter || is_ios) {
sources -= [ "filter/brotli_filter_unittest.cc" ]
+ sources -= [ "filter/brotli_source_stream_unittest.cc" ]
}
if (is_android) {
@@ -1752,12 +1669,12 @@ if (!is_ios) {
# Fuzzers
+# This has a global (InitGlobals) that must always be linked in, so
+# must be a source set instead of a static library.
source_set("net_fuzzer_test_support") {
testonly = true
sources = [
- "base/fuzzed_data_provider.cc",
- "base/fuzzed_data_provider.h",
"base/fuzzer_test_support.cc",
"socket/fuzzed_socket.cc",
"socket/fuzzed_socket.h",
@@ -1766,6 +1683,9 @@ source_set("net_fuzzer_test_support") {
"udp/fuzzed_datagram_client_socket.cc",
"udp/fuzzed_datagram_client_socket.h",
]
+ public_deps = [
+ "//base/test:test_support",
+ ]
deps = [
"//base",
"//base:i18n",
@@ -1794,6 +1714,7 @@ fuzzer_test("net_mime_sniffer_fuzzer") {
"//base",
"//net",
]
+ dict = "data/fuzzer_dictionaries/net_mime_sniffer_fuzzer.dict"
}
fuzzer_test("net_parse_proxy_list_pac_fuzzer") {
@@ -1834,6 +1755,7 @@ fuzzer_test("net_parse_proxy_rules_fuzzer") {
":net_fuzzer_test_support",
"//net",
]
+ dict = "data/fuzzer_dictionaries/net_parse_proxy_bypass_rules_fuzzer.dict"
}
fuzzer_test("net_parse_data_url_fuzzer") {
@@ -1845,6 +1767,7 @@ fuzzer_test("net_parse_data_url_fuzzer") {
"//base",
"//net",
]
+ dict = "data/fuzzer_dictionaries/net_parse_data_url_fuzzer.dict"
}
fuzzer_test("net_parse_ip_pattern_fuzzer") {
@@ -1866,6 +1789,7 @@ fuzzer_test("net_get_domain_and_registry_fuzzer") {
"//base",
"//net",
]
+ dict = "data/fuzzer_dictionaries/net_get_domain_and_registry_fuzzer.dict"
}
fuzzer_test("net_cert_verify_name_match_fuzzer") {
@@ -1929,6 +1853,7 @@ fuzzer_test("net_dns_record_fuzzer") {
"//base",
"//net",
]
+ dict = "data/fuzzer_dictionaries/net_dns_record_fuzzer.dict"
}
fuzzer_test("net_dns_hosts_parse_fuzzer") {
@@ -1940,6 +1865,7 @@ fuzzer_test("net_dns_hosts_parse_fuzzer") {
"//base",
"//net",
]
+ dict = "data/fuzzer_dictionaries/net_dns_hosts_parse_fuzzer.dict"
}
fuzzer_test("net_host_resolver_impl_fuzzer") {
@@ -1954,7 +1880,7 @@ fuzzer_test("net_host_resolver_impl_fuzzer") {
"//base",
"//net",
]
- dict = "data/dns/dns.dict"
+ dict = "data/fuzzer_dictionaries/net_host_resolver_impl_fuzzer.dict"
}
fuzzer_test("net_http_stream_parser_fuzzer") {
@@ -1967,7 +1893,7 @@ fuzzer_test("net_http_stream_parser_fuzzer") {
"//base",
"//net",
]
- dict = "data/http/http.dict"
+ dict = "data/fuzzer_dictionaries/net_http_stream_parser_fuzzer.dict"
}
fuzzer_test("net_ftp_ctrl_response_fuzzer") {
@@ -2005,6 +1931,30 @@ fuzzer_test("net_unescape_url_component_fuzzer") {
libfuzzer_options = [ "max_len = 2048" ]
}
+fuzzer_test("net_websocket_deflate_stream_fuzzer") {
+ sources = [
+ "websockets/websocket_deflate_stream_fuzzer.cc",
+ ]
+ deps = [
+ ":net_fuzzer_test_support",
+ "//net",
+ ]
+ dict = "data/fuzzer_dictionaries/net_websocket_frame_parser_fuzzer.dict"
+ libfuzzer_options = [ "max_len=512" ]
+}
+
+fuzzer_test("net_websocket_extension_parser_fuzzer") {
+ sources = [
+ "websockets/websocket_extension_parser_fuzzer.cc",
+ ]
+ deps = [
+ ":net_fuzzer_test_support",
+ "//net",
+ ]
+ dict = "data/fuzzer_dictionaries/net_websocket_extension_parser_fuzzer.dict"
+ libfuzzer_options = [ "max_len = 256" ]
+}
+
fuzzer_test("net_websocket_frame_parser_fuzzer") {
sources = [
"websockets/websocket_frame_parser_fuzzer.cc",
@@ -2013,6 +1963,8 @@ fuzzer_test("net_websocket_frame_parser_fuzzer") {
":net_fuzzer_test_support",
"//net",
]
+ dict = "data/fuzzer_dictionaries/net_websocket_frame_parser_fuzzer.dict"
+ libfuzzer_options = [ "max_len=256" ]
}
fuzzer_test("net_http_chunked_decoder_fuzzer") {
@@ -2023,7 +1975,6 @@ fuzzer_test("net_http_chunked_decoder_fuzzer") {
":net_fuzzer_test_support",
"//net",
]
- dict = "http/http_chunked_decoder_fuzzer.dict"
}
fuzzer_test("net_http_proxy_client_socket_fuzzer") {
@@ -2036,12 +1987,25 @@ fuzzer_test("net_http_proxy_client_socket_fuzzer") {
"//base",
"//net",
]
- dict = "data/http/http.dict"
+ dict = "data/fuzzer_dictionaries/net_http_proxy_client_socket_fuzzer.dict"
+}
+
+fuzzer_test("net_parse_url_hostname_to_address_fuzzer") {
+ sources = [
+ "base/parse_url_hostname_to_address_fuzzer.cc",
+ ]
+ deps = [
+ ":net_fuzzer_test_support",
+ "//base",
+ "//net",
+ ]
+ libfuzzer_options = [ "max_len=512" ]
+ seed_corpus = "data/fuzzer_data/hostnames/"
}
fuzzer_test("net_quic_crypto_framer_parse_message_fuzzer") {
sources = [
- "quic/quic_crypto_framer_parse_message_fuzzer.cc",
+ "quic/core/quic_crypto_framer_parse_message_fuzzer.cc",
]
deps = [
":net_fuzzer_test_support",
@@ -2084,5 +2048,17 @@ fuzzer_test("net_url_request_fuzzer") {
"//base",
"//net",
]
- dict = "data/http/http.dict"
+ dict = "data/fuzzer_dictionaries/net_url_request_fuzzer.dict"
+}
+
+fuzzer_test("net_auth_challenge_tokenizer_fuzzer") {
+ sources = [
+ "http/http_auth_challenge_tokenizer_fuzzer.cc",
+ ]
+ deps = [
+ ":net_fuzzer_test_support",
+ ":test_support",
+ "//base",
+ "//net",
+ ]
}
diff --git a/chromium/net/DEPS b/chromium/net/DEPS
index 88c82c8eb03..c927655f4e0 100644
--- a/chromium/net/DEPS
+++ b/chromium/net/DEPS
@@ -61,6 +61,10 @@ specific_include_rules = {
"+third_party/brotli",
],
+ "brotli_source_stream\.cc": [
+ "+third_party/brotli",
+ ],
+
"fuzzer_test_support.cc": [
"+base/i18n",
],
@@ -68,5 +72,4 @@ specific_include_rules = {
skip_child_includes = [
"third_party",
- "tools/flip_server",
]
diff --git a/chromium/net/OWNERS b/chromium/net/OWNERS
index 8282dadc18d..7038b935202 100644
--- a/chromium/net/OWNERS
+++ b/chromium/net/OWNERS
@@ -20,3 +20,6 @@ xunjieli@chromium.org
per-file *.isolate=maruel@chromium.org
per-file *.isolate=tandrii@chromium.org
per-file *.isolate=vadimsh@chromium.org
+
+per-file BUILD.gn=bengr@chromium.org
+per-file net.gyp*=bengr@chromium.org
diff --git a/chromium/net/android/BUILD.gn b/chromium/net/android/BUILD.gn
index 9beadb061b4..c29caa95f90 100644
--- a/chromium/net/android/BUILD.gn
+++ b/chromium/net/android/BUILD.gn
@@ -7,6 +7,7 @@ import("//build/config/android/rules.gni")
android_library("net_java") {
java_files = [
+ "java/src/org/chromium/net/AndroidCellularSignalStrength.java",
"java/src/org/chromium/net/AndroidCertVerifyResult.java",
"java/src/org/chromium/net/AndroidKeyStore.java",
"java/src/org/chromium/net/AndroidNetworkLibrary.java",
@@ -24,6 +25,8 @@ android_library("net_java") {
]
deps = [
"//base:base_java",
+ "//third_party/android_tools:android_support_annotations_java",
+ "//third_party/jsr-305:jsr_305_javalib",
]
srcjar_deps = [
":net_errors_java",
@@ -41,16 +44,11 @@ android_aidl("embedded_test_server_aidl") {
android_library("net_java_test_support") {
testonly = true
java_files = [
- "../test/android/javatests/src/org/chromium/net/test/BaseHttpTestServer.java",
- "../test/android/javatests/src/org/chromium/net/test/BaseTcpTestServer.java",
- "../test/android/javatests/src/org/chromium/net/test/BaseTestServer.java",
"../test/android/javatests/src/org/chromium/net/test/DummySpnegoAuthenticator.java",
"../test/android/javatests/src/org/chromium/net/test/DummySpnegoAuthenticatorService.java",
"../test/android/javatests/src/org/chromium/net/test/EmbeddedTestServer.java",
"../test/android/javatests/src/org/chromium/net/test/EmbeddedTestServerImpl.java",
"../test/android/javatests/src/org/chromium/net/test/EmbeddedTestServerService.java",
- "../test/android/javatests/src/org/chromium/net/test/TestServerBuilder.java",
- "../test/android/javatests/src/org/chromium/net/test/TestServerSpawner.java",
"../test/android/javatests/src/org/chromium/net/test/util/CertTestUtil.java",
"../test/android/javatests/src/org/chromium/net/test/util/NetworkChangeNotifierTestUtil.java",
"../test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java",
@@ -59,6 +57,7 @@ android_library("net_java_test_support") {
":net_java",
"//base:base_java",
"//base:base_java_test_support",
+ "//third_party/android_tools:android_support_annotations_java",
"//third_party/android_tools:legacy_http_javalib",
]
srcjar_deps = [
@@ -146,6 +145,7 @@ java_cpp_enum("net_android_java_enums_srcjar") {
sources = [
"../base/mime_util.h",
"../base/network_change_notifier.h",
+ "cellular_signal_strength.cc",
"cert_verify_result_android.h",
"keystore.h",
"network_change_notifier_android.cc",
@@ -160,7 +160,7 @@ junit_binary("net_junit_tests") {
":net_java",
"//base:base_java",
"//base:base_java_test_support",
- "//base:base_junit_test_support",
- "//third_party/junit:hamcrest",
+ "//third_party/hamcrest:hamcrest_java",
]
+ srcjar_deps = [ "//base:base_build_config_gen" ]
}
diff --git a/chromium/net/android/cellular_signal_strength.cc b/chromium/net/android/cellular_signal_strength.cc
new file mode 100644
index 00000000000..4c236954f7a
--- /dev/null
+++ b/chromium/net/android/cellular_signal_strength.cc
@@ -0,0 +1,57 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/android/cellular_signal_strength.h"
+
+#include "base/android/context_utils.h"
+#include "jni/AndroidCellularSignalStrength_jni.h"
+
+namespace net {
+
+namespace android {
+
+namespace cellular_signal_strength {
+
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.net
+enum CellularSignalStrengthError {
+ // Value returned by CellularSignalStrength APIs when a valid value is
+ // unavailable. This value is same as INT32_MIN, but the following code uses
+ // the explicit value of INT32_MIN so that the auto-generated Java enums work
+ // correctly.
+ ERROR_NOT_SUPPORTED = -2147483648,
+};
+
+static_assert(
+ INT32_MIN == ERROR_NOT_SUPPORTED,
+ "CellularSignalStrengthError.ERROR_NOT_SUPPORTED has unexpected value");
+
+bool GetSignalStrengthDbm(int32_t* signal_strength_dbm) {
+ int32_t signal_strength_dbm_tmp =
+ Java_AndroidCellularSignalStrength_getSignalStrengthDbm(
+ base::android::AttachCurrentThread(),
+ base::android::GetApplicationContext());
+ if (signal_strength_dbm_tmp == ERROR_NOT_SUPPORTED)
+ return false;
+
+ *signal_strength_dbm = signal_strength_dbm_tmp;
+ return true;
+}
+
+bool GetSignalStrengthLevel(int32_t* signal_strength_level) {
+ int32_t signal_strength_level_tmp =
+ Java_AndroidCellularSignalStrength_getSignalStrengthLevel(
+ base::android::AttachCurrentThread(),
+ base::android::GetApplicationContext());
+ if (signal_strength_level_tmp == ERROR_NOT_SUPPORTED)
+ return false;
+
+ *signal_strength_level = signal_strength_level_tmp;
+ return true;
+}
+
+} // namespace cellular_signal_strength
+
+} // namespace android
+
+} // namespace net
diff --git a/chromium/net/android/cellular_signal_strength.h b/chromium/net/android/cellular_signal_strength.h
new file mode 100644
index 00000000000..4165a73da78
--- /dev/null
+++ b/chromium/net/android/cellular_signal_strength.h
@@ -0,0 +1,39 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_ANDROID_CELLULAR_SIGNAL_STRENGTH_H_
+#define NET_ANDROID_CELLULAR_SIGNAL_STRENGTH_H_
+
+#include <jni.h>
+#include <stdint.h>
+
+#include "base/compiler_specific.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+namespace android {
+
+namespace cellular_signal_strength {
+
+// Returns true if the signal strength (in dbM) of the currently registered
+// cellular connection is available, and sets |*signal_strength_dbm| to that
+// value.
+NET_EXPORT bool GetSignalStrengthDbm(int32_t* signal_strength_dbm)
+ WARN_UNUSED_RESULT;
+
+// Returns true if the signal strength level (between 0 and 4, both inclusive)
+// of the currently registered cellular connection is available, and sets
+// |*signal_strength_level| to that value with lower value indicating lower
+// signal strength.
+NET_EXPORT bool GetSignalStrengthLevel(int32_t* signal_strength_level)
+ WARN_UNUSED_RESULT;
+
+} // namespace cellular_signal_strength
+
+} // namespace android
+
+} // namespace net
+
+#endif // NET_ANDROID_CELLULAR_SIGNAL_STRENGTH_H_
diff --git a/chromium/net/android/cellular_signal_strength_unittest.cc b/chromium/net/android/cellular_signal_strength_unittest.cc
new file mode 100644
index 00000000000..50510b7f631
--- /dev/null
+++ b/chromium/net/android/cellular_signal_strength_unittest.cc
@@ -0,0 +1,55 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/android/cellular_signal_strength.h"
+
+#include <stdint.h>
+
+#include "net/base/network_change_notifier.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+TEST(CellularSignalStrengthAndroidTest, SignalStrengthTest) {
+ int signal_strength_dbm = INT32_MIN;
+ bool signal_strength_available =
+ android::cellular_signal_strength::GetSignalStrengthDbm(
+ &signal_strength_dbm);
+
+ // Signal strength is unavailable if the device does not have an active
+ // cellular connection.
+ if (!NetworkChangeNotifier::IsConnectionCellular(
+ NetworkChangeNotifier::GetConnectionType())) {
+ return;
+ }
+
+ EXPECT_TRUE(signal_strength_available);
+ // Signal strength (in dbM) should typically be between -130 and 0.
+ EXPECT_LE(-130, signal_strength_dbm);
+ EXPECT_GE(0, signal_strength_dbm);
+}
+
+TEST(CellularSignalStrengthAndroidTest, SignalStrengthLevelTest) {
+ int signal_strength_level = INT32_MIN;
+ bool signal_strength_level_available =
+ android::cellular_signal_strength::GetSignalStrengthLevel(
+ &signal_strength_level);
+
+ // Signal strength is unavailable if the device does not have an active
+ // cellular connection.
+ if (!NetworkChangeNotifier::IsConnectionCellular(
+ NetworkChangeNotifier::GetConnectionType())) {
+ return;
+ }
+
+ EXPECT_TRUE(signal_strength_level_available);
+ EXPECT_LE(0, signal_strength_level);
+ EXPECT_GE(4, signal_strength_level);
+}
+
+} // namespace
+
+} // namespace net \ No newline at end of file
diff --git a/chromium/net/android/cert_verify_result_android.cc b/chromium/net/android/cert_verify_result_android.cc
index 151c4ef4eae..925e71bed42 100644
--- a/chromium/net/android/cert_verify_result_android.cc
+++ b/chromium/net/android/cert_verify_result_android.cc
@@ -10,11 +10,13 @@
using base::android::AttachCurrentThread;
using base::android::JavaArrayOfByteArrayToStringVector;
+using base::android::JavaRef;
+using base::android::ScopedJavaLocalRef;
namespace net {
namespace android {
-void ExtractCertVerifyResult(jobject result,
+void ExtractCertVerifyResult(const JavaRef<jobject>& result,
CertVerifyStatusAndroid* status,
bool* is_issued_by_known_root,
std::vector<std::string>* verified_chain) {
@@ -32,9 +34,5 @@ void ExtractCertVerifyResult(jobject result,
env, chain_byte_array.obj(), verified_chain);
}
-bool RegisterCertVerifyResult(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
} // namespace android
} // namespace net
diff --git a/chromium/net/android/cert_verify_result_android.h b/chromium/net/android/cert_verify_result_android.h
index 1bc9a1f44dd..96c61e44864 100644
--- a/chromium/net/android/cert_verify_result_android.h
+++ b/chromium/net/android/cert_verify_result_android.h
@@ -10,6 +10,8 @@
#include <string>
#include <vector>
+#include "base/android/scoped_java_ref.h"
+
namespace net {
namespace android {
@@ -39,14 +41,11 @@ enum CertVerifyStatusAndroid {
};
// Extract parameters out of an AndroidCertVerifyResult object.
-void ExtractCertVerifyResult(jobject result,
+void ExtractCertVerifyResult(const base::android::JavaRef<jobject>& result,
CertVerifyStatusAndroid* status,
bool* is_issued_by_known_root,
std::vector<std::string>* verified_chain);
-// Register JNI methods.
-bool RegisterCertVerifyResult(JNIEnv* env);
-
} // namespace android
} // namespace net
diff --git a/chromium/net/android/dummy_spnego_authenticator.cc b/chromium/net/android/dummy_spnego_authenticator.cc
index 5614c33ddfb..934d098bf06 100644
--- a/chromium/net/android/dummy_spnego_authenticator.cc
+++ b/chromium/net/android/dummy_spnego_authenticator.cc
@@ -8,6 +8,8 @@
#include "net/test/jni/DummySpnegoAuthenticator_jni.h"
#include "testing/gtest/include/gtest/gtest.h"
+using base::android::JavaParamRef;
+
namespace net {
// iso.org.dod.internet.security.mechanism.snego (1.3.6.1.5.5.2)
diff --git a/chromium/net/android/gurl_utils.cc b/chromium/net/android/gurl_utils.cc
index 5b2ff3f8ccc..826b1b8e667 100644
--- a/chromium/net/android/gurl_utils.cc
+++ b/chromium/net/android/gurl_utils.cc
@@ -8,6 +8,9 @@
#include "jni/GURLUtils_jni.h"
#include "url/gurl.h"
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
namespace net {
ScopedJavaLocalRef<jstring> GetOrigin(JNIEnv* env,
diff --git a/chromium/net/android/http_auth_negotiate_android.cc b/chromium/net/android/http_auth_negotiate_android.cc
index 7586246ae49..745ce639571 100644
--- a/chromium/net/android/http_auth_negotiate_android.cc
+++ b/chromium/net/android/http_auth_negotiate_android.cc
@@ -20,6 +20,7 @@
using base::android::AttachCurrentThread;
using base::android::ConvertUTF8ToJavaString;
using base::android::ConvertJavaStringToUTF8;
+using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
namespace net {
@@ -64,8 +65,7 @@ HttpAuthNegotiateAndroid::HttpAuthNegotiateAndroid(
JNIEnv* env = AttachCurrentThread();
java_authenticator_.Reset(Java_HttpNegotiateAuthenticator_create(
env,
- ConvertUTF8ToJavaString(env, prefs->AuthAndroidNegotiateAccountType())
- .obj()));
+ ConvertUTF8ToJavaString(env, prefs->AuthAndroidNegotiateAccountType())));
}
HttpAuthNegotiateAndroid::~HttpAuthNegotiateAndroid() {
@@ -139,9 +139,8 @@ int HttpAuthNegotiateAndroid::GenerateAuthToken(
JavaNegotiateResultWrapper* callback_wrapper = new JavaNegotiateResultWrapper(
callback_task_runner, thread_safe_callback);
Java_HttpNegotiateAuthenticator_getNextAuthToken(
- env, java_authenticator_.obj(),
- reinterpret_cast<intptr_t>(callback_wrapper), java_spn.obj(),
- java_server_auth_token.obj(), can_delegate_);
+ env, java_authenticator_, reinterpret_cast<intptr_t>(callback_wrapper),
+ java_spn, java_server_auth_token, can_delegate_);
return ERR_IO_PENDING;
}
diff --git a/chromium/net/android/http_auth_negotiate_android.h b/chromium/net/android/http_auth_negotiate_android.h
index 98ad8e578cc..f63620d567b 100644
--- a/chromium/net/android/http_auth_negotiate_android.h
+++ b/chromium/net/android/http_auth_negotiate_android.h
@@ -15,6 +15,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
#include "net/http/http_auth.h"
namespace net {
diff --git a/chromium/net/android/keystore.cc b/chromium/net/android/keystore.cc
index fc16ae42b81..d2246103e66 100644
--- a/chromium/net/android/keystore.cc
+++ b/chromium/net/android/keystore.cc
@@ -13,15 +13,17 @@
using base::android::AttachCurrentThread;
using base::android::HasException;
+using base::android::JavaArrayOfByteArrayToStringVector;
using base::android::JavaByteArrayToByteVector;
+using base::android::JavaRef;
using base::android::ScopedJavaLocalRef;
using base::android::ToJavaByteArray;
-using base::android::JavaArrayOfByteArrayToStringVector;
namespace net {
namespace android {
-bool GetRSAKeyModulus(jobject private_key_ref, std::vector<uint8_t>* result) {
+bool GetRSAKeyModulus(const JavaRef<jobject>& private_key_ref,
+ std::vector<uint8_t>* result) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jbyteArray> modulus_ref =
@@ -33,7 +35,8 @@ bool GetRSAKeyModulus(jobject private_key_ref, std::vector<uint8_t>* result) {
return true;
}
-bool GetECKeyOrder(jobject private_key_ref, std::vector<uint8_t>* result) {
+bool GetECKeyOrder(const JavaRef<jobject>& private_key_ref,
+ std::vector<uint8_t>* result) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jbyteArray> order_ref =
@@ -46,7 +49,7 @@ bool GetECKeyOrder(jobject private_key_ref, std::vector<uint8_t>* result) {
return true;
}
-bool RawSignDigestWithPrivateKey(jobject private_key_ref,
+bool RawSignDigestWithPrivateKey(const JavaRef<jobject>& private_key_ref,
const base::StringPiece& digest,
std::vector<uint8_t>* signature) {
JNIEnv* env = AttachCurrentThread();
@@ -59,7 +62,7 @@ bool RawSignDigestWithPrivateKey(jobject private_key_ref,
// Invoke platform API
ScopedJavaLocalRef<jbyteArray> signature_ref =
Java_AndroidKeyStore_rawSignDigestWithPrivateKey(env, private_key_ref,
- digest_ref.obj());
+ digest_ref);
if (HasException(env) || signature_ref.is_null())
return false;
@@ -68,13 +71,14 @@ bool RawSignDigestWithPrivateKey(jobject private_key_ref,
return true;
}
-PrivateKeyType GetPrivateKeyType(jobject private_key_ref) {
+PrivateKeyType GetPrivateKeyType(const JavaRef<jobject>& private_key_ref) {
JNIEnv* env = AttachCurrentThread();
int type = Java_AndroidKeyStore_getPrivateKeyType(env, private_key_ref);
return static_cast<PrivateKeyType>(type);
}
-AndroidEVP_PKEY* GetOpenSSLSystemHandleForPrivateKey(jobject private_key_ref) {
+AndroidEVP_PKEY* GetOpenSSLSystemHandleForPrivateKey(
+ const JavaRef<jobject>& private_key_ref) {
JNIEnv* env = AttachCurrentThread();
// Note: the pointer is passed as a jint here because that's how it
// is stored in the Java object. Java doesn't have a primitive type
@@ -90,16 +94,12 @@ AndroidEVP_PKEY* GetOpenSSLSystemHandleForPrivateKey(jobject private_key_ref) {
}
ScopedJavaLocalRef<jobject> GetOpenSSLEngineForPrivateKey(
- jobject private_key_ref) {
+ const JavaRef<jobject>& private_key_ref) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> engine =
Java_AndroidKeyStore_getOpenSSLEngineForPrivateKey(env, private_key_ref);
return engine;
}
-bool RegisterKeyStore(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
} // namespace android
} // namespace net
diff --git a/chromium/net/android/keystore.h b/chromium/net/android/keystore.h
index df804d7154d..7691c262932 100644
--- a/chromium/net/android/keystore.h
+++ b/chromium/net/android/keystore.h
@@ -47,8 +47,9 @@ enum PrivateKeyType {
// |modulus| will receive the modulus bytes on success.
// Returns true on success, or false on failure (e.g. if the key
// is not RSA).
-NET_EXPORT bool GetRSAKeyModulus(jobject private_key,
- std::vector<uint8_t>* modulus);
+NET_EXPORT bool GetRSAKeyModulus(
+ const base::android::JavaRef<jobject>& private_key,
+ std::vector<uint8_t>* modulus);
// Returns the order parameter of a given ECPrivateKey platform object,
// as a series of bytes, in big-endian representation. This can be used
@@ -57,7 +58,8 @@ NET_EXPORT bool GetRSAKeyModulus(jobject private_key,
// |order| will receive the result bytes on success.
// Returns true on success, or false on failure (e.g. if the key is
// not EC).
-bool GetECKeyOrder(jobject private_key, std::vector<uint8_t>* order);
+bool GetECKeyOrder(const base::android::JavaRef<jobject>& private_key,
+ std::vector<uint8_t>* order);
// Compute the signature of a given message, which is actually a hash,
// using a private key. For more details, please read the comments for the
@@ -68,15 +70,17 @@ bool GetECKeyOrder(jobject private_key, std::vector<uint8_t>* order);
// |signature| will receive the signature on success.
// Returns true on success, false on failure.
//
-NET_EXPORT bool RawSignDigestWithPrivateKey(jobject private_key,
- const base::StringPiece& digest,
- std::vector<uint8_t>* signature);
+NET_EXPORT bool RawSignDigestWithPrivateKey(
+ const base::android::JavaRef<jobject>& private_key,
+ const base::StringPiece& digest,
+ std::vector<uint8_t>* signature);
// Return the PrivateKeyType of a given private key.
// |private_key| is a JNI reference for the private key.
// Returns a PrivateKeyType, while will be CLIENT_CERT_INVALID_TYPE
// on error.
-NET_EXPORT PrivateKeyType GetPrivateKeyType(jobject private_key);
+NET_EXPORT PrivateKeyType
+GetPrivateKeyType(const base::android::JavaRef<jobject>& private_key);
// Returns a handle to the system AndroidEVP_PKEY object used to back a given
// private_key object. This must *only* be used for RSA private keys on Android
@@ -91,7 +95,8 @@ NET_EXPORT PrivateKeyType GetPrivateKeyType(jobject private_key);
// anything about OpenSSL, it just type-casts a system pointer that
// is passed as an int through JNI. As such, it never increments
// the returned key's reference count.
-AndroidEVP_PKEY* GetOpenSSLSystemHandleForPrivateKey(jobject private_key);
+AndroidEVP_PKEY* GetOpenSSLSystemHandleForPrivateKey(
+ const base::android::JavaRef<jobject>& private_key);
// Returns a JNI reference to the OpenSSLEngine object which is used to back a
// given private_key object. This must *only* be used for RSA private keys on
@@ -99,10 +104,7 @@ AndroidEVP_PKEY* GetOpenSSLSystemHandleForPrivateKey(jobject private_key);
// image contains a vanilla implementation of the Java API frameworks based on
// Harmony + OpenSSL.
base::android::ScopedJavaLocalRef<jobject> GetOpenSSLEngineForPrivateKey(
- jobject private_key);
-
-// Register JNI methods
-NET_EXPORT bool RegisterKeyStore(JNIEnv* env);
+ const base::android::JavaRef<jobject>& private_key);
} // namespace android
} // namespace net
diff --git a/chromium/net/android/keystore_openssl.cc b/chromium/net/android/keystore_openssl.cc
deleted file mode 100644
index fd07440dd08..00000000000
--- a/chromium/net/android/keystore_openssl.cc
+++ /dev/null
@@ -1,550 +0,0 @@
-// Copyright (c) 2013 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/android/keystore_openssl.h"
-
-#include <jni.h>
-#include <openssl/bn.h>
-#include <openssl/ec.h>
-#include <openssl/engine.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/rsa.h>
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/android/build_info.h"
-#include "base/android/scoped_java_ref.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "crypto/openssl_util.h"
-#include "net/android/keystore.h"
-#include "net/android/legacy_openssl.h"
-#include "net/ssl/scoped_openssl_types.h"
-#include "net/ssl/ssl_client_cert_type.h"
-
-// IMPORTANT NOTE: The following code will currently only work when used
-// to implement client certificate support with OpenSSL. That's because
-// only the signing operations used in this use case are implemented here.
-//
-// Generally speaking, OpenSSL provides many different ways to sign
-// digests. This code doesn't support all these cases, only the ones that
-// are required to sign the digest during the OpenSSL handshake for TLS.
-//
-// The OpenSSL EVP_PKEY type is a generic wrapper around key pairs.
-// Internally, it can hold a pointer to a RSA or ECDSA structure, which model
-// keypair implementations of each respective crypto algorithm.
-//
-// The RSA type has a 'method' field pointer to a vtable-like structure
-// called a RSA_METHOD. This contains several function pointers that
-// correspond to operations on RSA keys (e.g. decode/encode with public
-// key, decode/encode with private key, signing, validation), as well as
-// a few flags.
-//
-// For example, the RSA_sign() function will call "method->rsa_sign()" if
-// method->rsa_sign is not NULL, otherwise, it will perform a regular
-// signing operation using the other fields in the RSA structure (which
-// are used to hold the typical modulus / exponent / parameters for the
-// key pair).
-//
-// This source file thus defines a custom RSA_METHOD structure whose
-// fields point to static methods used to implement the corresponding
-// RSA operation using platform Android APIs.
-//
-// However, the platform APIs require a jobject JNI reference to work. It must
-// be stored in the RSA instance, or made accessible when the custom RSA
-// methods are called. This is done by storing it in a |KeyExData| structure
-// that's referenced by the key using |EX_DATA|.
-
-using base::android::ScopedJavaGlobalRef;
-using base::android::ScopedJavaLocalRef;
-
-namespace net {
-namespace android {
-
-namespace {
-
-extern const RSA_METHOD android_rsa_method;
-extern const ECDSA_METHOD android_ecdsa_method;
-
-// KeyExData contains the data that is contained in the EX_DATA of the RSA and
-// EC_KEY objects that are created to wrap Android system keys.
-struct KeyExData {
- // private_key contains a reference to a Java, private-key object.
- ScopedJavaGlobalRef<jobject> private_key;
- // legacy_rsa, if not NULL, points to an RSA* in the system's OpenSSL (which
- // might not be ABI compatible with Chromium).
- AndroidRSA* legacy_rsa;
- // cached_size contains the "size" of the key. This is the size of the
- // modulus (in bytes) for RSA, or the group order size for ECDSA. This
- // avoids calling into Java to calculate the size.
- size_t cached_size;
-};
-
-// ExDataDup is called when one of the RSA or EC_KEY objects is duplicated. We
-// don't support this and it should never happen.
-int ExDataDup(CRYPTO_EX_DATA* to,
- const CRYPTO_EX_DATA* from,
- void** from_d,
- int index,
- long argl,
- void* argp) {
- CHECK_EQ((void*)NULL, *from_d);
- return 0;
-}
-
-// ExDataFree is called when one of the RSA or EC_KEY objects is freed.
-void ExDataFree(void* parent,
- void* ptr,
- CRYPTO_EX_DATA* ad,
- int index,
- long argl,
- void* argp) {
- // Ensure the global JNI reference created with this wrapper is
- // properly destroyed with it.
- KeyExData* ex_data = reinterpret_cast<KeyExData*>(ptr);
- delete ex_data;
-}
-
-// BoringSSLEngine is a BoringSSL ENGINE that implements RSA and ECDSA by
-// forwarding the requested operations to the Java libraries.
-class BoringSSLEngine {
- public:
- BoringSSLEngine()
- : rsa_index_(RSA_get_ex_new_index(0 /* argl */,
- NULL /* argp */,
- NULL /* new_func */,
- ExDataDup,
- ExDataFree)),
- ec_key_index_(EC_KEY_get_ex_new_index(0 /* argl */,
- NULL /* argp */,
- NULL /* new_func */,
- ExDataDup,
- ExDataFree)),
- engine_(ENGINE_new()) {
- ENGINE_set_RSA_method(engine_, &android_rsa_method,
- sizeof(android_rsa_method));
- ENGINE_set_ECDSA_method(engine_, &android_ecdsa_method,
- sizeof(android_ecdsa_method));
- }
-
- int rsa_ex_index() const { return rsa_index_; }
- int ec_key_ex_index() const { return ec_key_index_; }
-
- const ENGINE* engine() const { return engine_; }
-
- private:
- const int rsa_index_;
- const int ec_key_index_;
- ENGINE* const engine_;
-};
-
-base::LazyInstance<BoringSSLEngine>::Leaky global_boringssl_engine =
- LAZY_INSTANCE_INITIALIZER;
-
-// VectorBignumSize returns the number of bytes needed to represent the bignum
-// given in |v|, i.e. the length of |v| less any leading zero bytes.
-size_t VectorBignumSize(const std::vector<uint8_t>& v) {
- size_t size = v.size();
- // Ignore any leading zero bytes.
- for (size_t i = 0; i < v.size() && v[i] == 0; i++) {
- size--;
- }
- return size;
-}
-
-KeyExData* RsaGetExData(const RSA* rsa) {
- return reinterpret_cast<KeyExData*>(
- RSA_get_ex_data(rsa, global_boringssl_engine.Get().rsa_ex_index()));
-}
-
-size_t RsaMethodSize(const RSA* rsa) {
- const KeyExData* ex_data = RsaGetExData(rsa);
- return ex_data->cached_size;
-}
-
-int RsaMethodEncrypt(RSA* rsa,
- size_t* out_len,
- uint8_t* out,
- size_t max_out,
- const uint8_t* in,
- size_t in_len,
- int padding) {
- NOTIMPLEMENTED();
- OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE);
- return 0;
-}
-
-int RsaMethodSignRaw(RSA* rsa,
- size_t* out_len,
- uint8_t* out,
- size_t max_out,
- const uint8_t* in,
- size_t in_len,
- int padding) {
- DCHECK_EQ(RSA_PKCS1_PADDING, padding);
- if (padding != RSA_PKCS1_PADDING) {
- // TODO(davidben): If we need to, we can implement RSA_NO_PADDING
- // by using javax.crypto.Cipher and picking either the
- // "RSA/ECB/NoPadding" or "RSA/ECB/PKCS1Padding" transformation as
- // appropriate. I believe support for both of these was added in
- // the same Android version as the "NONEwithRSA"
- // java.security.Signature algorithm, so the same version checks
- // for GetRsaLegacyKey should work.
- OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE);
- return 0;
- }
-
- // Retrieve private key JNI reference.
- const KeyExData* ex_data = RsaGetExData(rsa);
- if (!ex_data || !ex_data->private_key.obj()) {
- LOG(WARNING) << "Null JNI reference passed to RsaMethodSignRaw!";
- OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- // Pre-4.2 legacy codepath.
- if (ex_data->legacy_rsa) {
- int ret = ex_data->legacy_rsa->meth->rsa_priv_enc(
- in_len, in, out, ex_data->legacy_rsa, ANDROID_RSA_PKCS1_PADDING);
- if (ret < 0) {
- LOG(WARNING) << "Could not sign message in RsaMethodSignRaw!";
- // System OpenSSL will use a separate error queue, so it is still
- // necessary to push a new error.
- //
- // TODO(davidben): It would be good to also clear the system error queue
- // if there were some way to convince Java to do it. (Without going
- // through Java, it's difficult to get a handle on a system OpenSSL
- // function; dlopen loads a second copy.)
- OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- *out_len = ret;
- return 1;
- }
-
- base::StringPiece from_piece(reinterpret_cast<const char*>(in), in_len);
- std::vector<uint8_t> result;
- // For RSA keys, this function behaves as RSA_private_encrypt with
- // PKCS#1 padding.
- if (!RawSignDigestWithPrivateKey(ex_data->private_key.obj(), from_piece,
- &result)) {
- LOG(WARNING) << "Could not sign message in RsaMethodSignRaw!";
- OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- size_t expected_size = static_cast<size_t>(RSA_size(rsa));
- if (result.size() > expected_size) {
- LOG(ERROR) << "RSA Signature size mismatch, actual: " << result.size()
- << ", expected <= " << expected_size;
- OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- if (max_out < expected_size) {
- OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE);
- return 0;
- }
-
- // Copy result to OpenSSL-provided buffer. RawSignDigestWithPrivateKey
- // should pad with leading 0s, but if it doesn't, pad the result.
- size_t zero_pad = expected_size - result.size();
- memset(out, 0, zero_pad);
- memcpy(out + zero_pad, &result[0], result.size());
- *out_len = expected_size;
-
- return 1;
-}
-
-int RsaMethodDecrypt(RSA* rsa,
- size_t* out_len,
- uint8_t* out,
- size_t max_out,
- const uint8_t* in,
- size_t in_len,
- int padding) {
- NOTIMPLEMENTED();
- OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE);
- return 0;
-}
-
-int RsaMethodVerifyRaw(RSA* rsa,
- size_t* out_len,
- uint8_t* out,
- size_t max_out,
- const uint8_t* in,
- size_t in_len,
- int padding) {
- NOTIMPLEMENTED();
- OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE);
- return 0;
-}
-
-const RSA_METHOD android_rsa_method = {
- {
- 0 /* references */, 1 /* is_static */
- } /* common */,
- nullptr /* app_data */,
-
- nullptr /* init */,
- nullptr /* finish */,
- RsaMethodSize,
- nullptr /* sign */,
- nullptr /* verify */,
- RsaMethodEncrypt,
- RsaMethodSignRaw,
- RsaMethodDecrypt,
- RsaMethodVerifyRaw,
- nullptr /* private_transform */,
- nullptr /* mod_exp */,
- nullptr /* bn_mod_exp */,
- RSA_FLAG_OPAQUE,
- nullptr /* keygen */,
- nullptr /* multi_prime_keygen */,
- nullptr /* supports_digest */,
-};
-
-// Setup an EVP_PKEY to wrap an existing platform RSA PrivateKey object.
-// |private_key| is the JNI reference (local or global) to the object.
-// |legacy_rsa|, if non-NULL, is a pointer to the system OpenSSL RSA object
-// backing |private_key|. This parameter is only used for Android < 4.2 to
-// implement key operations not exposed by the platform.
-// Returns a new EVP_PKEY on success, NULL otherwise.
-// On success, this creates a new global JNI reference to the object
-// that is owned by and destroyed with the EVP_PKEY. I.e. caller can
-// free |private_key| after the call.
-crypto::ScopedEVP_PKEY CreateRsaPkeyWrapper(
- jobject private_key,
- AndroidRSA* legacy_rsa,
- const crypto::OpenSSLErrStackTracer& tracer) {
- crypto::ScopedRSA rsa(RSA_new_method(global_boringssl_engine.Get().engine()));
-
- std::vector<uint8_t> modulus;
- if (!GetRSAKeyModulus(private_key, &modulus)) {
- LOG(ERROR) << "Failed to get private key modulus";
- return nullptr;
- }
-
- std::unique_ptr<KeyExData> ex_data(new KeyExData);
- ex_data->private_key.Reset(nullptr, private_key);
- if (ex_data->private_key.is_null()) {
- LOG(ERROR) << "Could not create global JNI reference";
- return nullptr;
- }
- ex_data->legacy_rsa = legacy_rsa;
- ex_data->cached_size = VectorBignumSize(modulus);
-
- RSA_set_ex_data(rsa.get(), global_boringssl_engine.Get().rsa_ex_index(),
- ex_data.release());
-
- crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
- if (!pkey || !EVP_PKEY_set1_RSA(pkey.get(), rsa.get()))
- return nullptr;
- return pkey;
-}
-
-// On Android < 4.2, the libkeystore.so ENGINE uses CRYPTO_EX_DATA and is not
-// added to the global engine list. If all references to it are dropped, OpenSSL
-// will dlclose the module, leaving a dangling function pointer in the RSA
-// CRYPTO_EX_DATA class. To work around this, leak an extra reference to the
-// ENGINE we extract in GetRsaLegacyKey.
-//
-// In 4.2, this change avoids the problem:
-// https://android.googlesource.com/platform/libcore/+/106a8928fb4249f2f3d4dba1dddbe73ca5cb3d61
-//
-// https://crbug.com/381465
-class KeystoreEngineWorkaround {
- public:
- KeystoreEngineWorkaround() {}
-
- void LeakEngine(jobject private_key) {
- if (!engine_.is_null())
- return;
- ScopedJavaLocalRef<jobject> engine =
- GetOpenSSLEngineForPrivateKey(private_key);
- if (engine.is_null()) {
- NOTREACHED();
- return;
- }
- engine_.Reset(engine);
- }
-
- private:
- ScopedJavaGlobalRef<jobject> engine_;
-};
-
-void LeakEngine(jobject private_key) {
- static base::LazyInstance<KeystoreEngineWorkaround>::Leaky s_instance =
- LAZY_INSTANCE_INITIALIZER;
- s_instance.Get().LeakEngine(private_key);
-}
-
-// Creates an EVP_PKEY wrapper corresponding to the RSA key
-// |private_key|. Returns nullptr on failure.
-crypto::ScopedEVP_PKEY GetRsaPkeyWrapper(jobject private_key) {
- const int kAndroid42ApiLevel = 17;
- crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
-
- if (base::android::BuildInfo::GetInstance()->sdk_int() >=
- kAndroid42ApiLevel) {
- return CreateRsaPkeyWrapper(private_key, nullptr, tracer);
- }
-
- // Route around platform limitation: if Android < 4.2, then
- // base::android::RawSignDigestWithPrivateKey() cannot work, so try to get the
- // system OpenSSL's EVP_PKEY backing this PrivateKey object.
- AndroidEVP_PKEY* sys_pkey = GetOpenSSLSystemHandleForPrivateKey(private_key);
- if (sys_pkey == nullptr)
- return nullptr;
-
- if (sys_pkey->type != ANDROID_EVP_PKEY_RSA) {
- LOG(ERROR) << "Private key has wrong type!";
- return nullptr;
- }
-
- AndroidRSA* sys_rsa = sys_pkey->pkey.rsa;
- if (sys_rsa->engine) {
- // |private_key| may not have an engine if the PrivateKey did not come
- // from the key store, such as in unit tests.
- if (strcmp(sys_rsa->engine->id, "keystore") == 0) {
- LeakEngine(private_key);
- } else {
- NOTREACHED();
- }
- }
-
- return CreateRsaPkeyWrapper(private_key, sys_rsa, tracer);
-}
-
-// Custom ECDSA_METHOD that uses the platform APIs.
-// Note that for now, only signing through ECDSA_sign() is really supported.
-// all other method pointers are either stubs returning errors, or no-ops.
-
-jobject EcKeyGetKey(const EC_KEY* ec_key) {
- KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data(
- ec_key, global_boringssl_engine.Get().ec_key_ex_index()));
- return ex_data->private_key.obj();
-}
-
-size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) {
- KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data(
- ec_key, global_boringssl_engine.Get().ec_key_ex_index()));
- return ex_data->cached_size;
-}
-
-int EcdsaMethodSign(const uint8_t* digest,
- size_t digest_len,
- uint8_t* sig,
- unsigned int* sig_len,
- EC_KEY* ec_key) {
- // Retrieve private key JNI reference.
- jobject private_key = EcKeyGetKey(ec_key);
- if (!private_key) {
- LOG(WARNING) << "Null JNI reference passed to EcdsaMethodSign!";
- return 0;
- }
- // Sign message with it through JNI.
- std::vector<uint8_t> signature;
- base::StringPiece digest_sp(reinterpret_cast<const char*>(digest),
- digest_len);
- if (!RawSignDigestWithPrivateKey(private_key, digest_sp, &signature)) {
- LOG(WARNING) << "Could not sign message in EcdsaMethodSign!";
- return 0;
- }
-
- // Note: With ECDSA, the actual signature may be smaller than
- // ECDSA_size().
- size_t max_expected_size = ECDSA_size(ec_key);
- if (signature.size() > max_expected_size) {
- LOG(ERROR) << "ECDSA Signature size mismatch, actual: " << signature.size()
- << ", expected <= " << max_expected_size;
- return 0;
- }
-
- memcpy(sig, &signature[0], signature.size());
- *sig_len = signature.size();
- return 1;
-}
-
-int EcdsaMethodVerify(const uint8_t* digest,
- size_t digest_len,
- const uint8_t* sig,
- size_t sig_len,
- EC_KEY* ec_key) {
- NOTIMPLEMENTED();
- OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED);
- return 0;
-}
-
-// Setup an EVP_PKEY to wrap an existing platform PrivateKey object.
-// |private_key| is the JNI reference (local or global) to the object.
-// Returns a new EVP_PKEY on success, NULL otherwise.
-// On success, this creates a global JNI reference to the object that
-// is owned by and destroyed with the EVP_PKEY. I.e. the caller shall
-// always free |private_key| after the call.
-crypto::ScopedEVP_PKEY GetEcdsaPkeyWrapper(jobject private_key) {
- crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
- crypto::ScopedEC_KEY ec_key(
- EC_KEY_new_method(global_boringssl_engine.Get().engine()));
-
- std::vector<uint8_t> order;
- if (!GetECKeyOrder(private_key, &order)) {
- LOG(ERROR) << "Can't extract order parameter from EC private key";
- return nullptr;
- }
-
- std::unique_ptr<KeyExData> ex_data(new KeyExData);
- ex_data->private_key.Reset(nullptr, private_key);
- if (ex_data->private_key.is_null()) {
- LOG(ERROR) << "Can't create global JNI reference";
- return nullptr;
- }
- ex_data->legacy_rsa = nullptr;
- ex_data->cached_size = VectorBignumSize(order);
-
- EC_KEY_set_ex_data(ec_key.get(),
- global_boringssl_engine.Get().ec_key_ex_index(),
- ex_data.release());
-
- crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
- if (!pkey || !EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()))
- return nullptr;
- return pkey;
-}
-
-const ECDSA_METHOD android_ecdsa_method = {
- {
- 0 /* references */, 1 /* is_static */
- } /* common */,
- NULL /* app_data */,
-
- NULL /* init */,
- NULL /* finish */,
- EcdsaMethodGroupOrderSize,
- EcdsaMethodSign,
- EcdsaMethodVerify,
- ECDSA_FLAG_OPAQUE,
-};
-
-} // namespace
-
-crypto::ScopedEVP_PKEY GetOpenSSLPrivateKeyWrapper(jobject private_key) {
- // Create sub key type, depending on private key's algorithm type.
- PrivateKeyType key_type = GetPrivateKeyType(private_key);
- switch (key_type) {
- case PRIVATE_KEY_TYPE_RSA:
- return GetRsaPkeyWrapper(private_key);
- case PRIVATE_KEY_TYPE_ECDSA:
- return GetEcdsaPkeyWrapper(private_key);
- default:
- LOG(WARNING)
- << "GetOpenSSLPrivateKeyWrapper() called with invalid key type";
- return nullptr;
- }
-}
-
-} // namespace android
-} // namespace net
diff --git a/chromium/net/android/keystore_openssl.h b/chromium/net/android/keystore_openssl.h
deleted file mode 100644
index 72f3994c1f0..00000000000
--- a/chromium/net/android/keystore_openssl.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2013 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_ANDROID_KEYSTORE_OPENSSL_H
-#define NET_ANDROID_KEYSTORE_OPENSSL_H
-
-#include <jni.h>
-#include <openssl/evp.h>
-
-#include "crypto/scoped_openssl_types.h"
-#include "net/base/net_export.h"
-
-// The features provided here are highly implementation specific and are
-// segregated from net/android/keystore.h because the latter only provides
-// simply JNI stubs to call Java code which only uses platform APIs.
-
-namespace net {
-namespace android {
-
-// Create a custom OpenSSL EVP_PKEY instance that wraps a platform
-// java.security.PrivateKey object, and will call the platform APIs
-// through JNI to implement signing (and only signing).
-//
-// This method can be called from any thread. It shall only be used
-// to implement client certificate handling though.
-//
-// |private_key| is a JNI local (or global) reference to the Java
-// PrivateKey object.
-//
-// Returns a new EVP_PKEY* object with the following features:
-//
-// - Only contains a private key.
-//
-// - Owns its own _global_ JNI reference to the object. This means the
-// caller can free |private_key| safely after the call, and that the
-// the returned EVP_PKEY instance can be used from any thread.
-//
-// - Uses a custom method to implement the minimum functions required to
-// *sign* the digest that is part of the "Verify Certificate" message
-// during the OpenSSL handshake. Anything else will result in undefined
-// behaviour.
-NET_EXPORT crypto::ScopedEVP_PKEY GetOpenSSLPrivateKeyWrapper(
- jobject private_key);
-
-} // namespace android
-} // namespace net
-
-#endif // NET_ANDROID_KEYSTORE_OPENSSL_H
diff --git a/chromium/net/android/keystore_unittest.cc b/chromium/net/android/keystore_unittest.cc
deleted file mode 100644
index b6f4aaa6ae8..00000000000
--- a/chromium/net/android/keystore_unittest.cc
+++ /dev/null
@@ -1,555 +0,0 @@
-// Copyright (c) 2013 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 <openssl/bn.h>
-#include <openssl/dsa.h>
-#include <openssl/ecdsa.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-#include <openssl/rsa.h>
-
-#include "base/android/build_info.h"
-#include "base/android/jni_android.h"
-#include "base/android/jni_array.h"
-#include "base/android/scoped_java_ref.h"
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "crypto/auto_cbb.h"
-#include "crypto/openssl_util.h"
-#include "net/android/keystore.h"
-#include "net/android/keystore_openssl.h"
-#include "net/ssl/scoped_openssl_types.h"
-#include "net/test/jni/AndroidKeyStoreTestUtil_jni.h"
-#include "net/test/test_data_directory.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// Technical note:
-//
-// This source file not only checks that signing with
-// RawSignDigestWithPrivateKey() works correctly, it also verifies that
-// the generated signature matches 100% of what OpenSSL generates when
-// calling RSA_sign(NID_md5_sha1,...), DSA_sign(0, ...) or
-// ECDSA_sign(0, ...).
-//
-// That's crucial to ensure that this function can later be used to
-// implement client certificate support. More specifically, that it is
-// possible to create a custom EVP_PKEY that uses
-// RawSignDigestWithPrivateKey() internally to perform RSA/DSA/ECDSA
-// signing, as invoked by the OpenSSL code at
-// openssl/ssl/s3_clnt.c:ssl3_send_client_verify().
-//
-// For more details, read the comments in AndroidKeyStore.java.
-//
-// Finally, it also checks that using the EVP_PKEY generated with
-// GetOpenSSLPrivateKeyWrapper() works correctly.
-
-namespace net {
-namespace android {
-
-namespace {
-
-typedef base::android::ScopedJavaLocalRef<jobject> ScopedJava;
-
-JNIEnv* InitEnv() {
- JNIEnv* env = base::android::AttachCurrentThread();
- static bool inited = false;
- if (!inited) {
- RegisterNativesImpl(env);
- inited = true;
- }
- return env;
-}
-
-// Returns true if running on an Android version older than 4.2
-bool IsOnAndroidOlderThan_4_2(void) {
- const int kAndroid42ApiLevel = 17;
- int level = base::android::BuildInfo::GetInstance()->sdk_int();
- return level < kAndroid42ApiLevel;
-}
-
-// Implements the callback expected by ERR_print_errors_cb().
-// used by GetOpenSSLErrorString below.
-int openssl_print_error_callback(const char* msg, size_t msglen, void* u) {
- std::string* result = reinterpret_cast<std::string*>(u);
- result->append(msg, msglen);
- return 1;
-}
-
-// Retrieves the OpenSSL error as a string
-std::string GetOpenSSLErrorString(void) {
- std::string result;
- ERR_print_errors_cb(openssl_print_error_callback, &result);
- return result;
-}
-
-// Resize a string to |size| bytes of data, then return its data buffer
-// address cast as an 'unsigned char*', as expected by OpenSSL functions.
-// |str| the target string.
-// |size| the number of bytes to write into the string.
-// Return the string's new buffer in memory, as an 'unsigned char*'
-// pointer.
-unsigned char* OpenSSLWriteInto(std::string* str, size_t size) {
- return reinterpret_cast<unsigned char*>(base::WriteInto(str, size + 1));
-}
-
-// Load a given private key file into an EVP_PKEY.
-// |filename| is the key file path.
-// Returns a new EVP_PKEY on success, NULL on failure.
-EVP_PKEY* ImportPrivateKeyFile(const char* filename) {
- // Load file in memory.
- base::FilePath certs_dir = GetTestCertsDirectory();
- base::FilePath file_path = certs_dir.AppendASCII(filename);
- base::ScopedFILE handle(base::OpenFile(file_path, "rb"));
- if (!handle.get()) {
- LOG(ERROR) << "Could not open private key file: " << filename;
- return NULL;
- }
- // Assume it is PEM_encoded. Load it as an EVP_PKEY.
- EVP_PKEY* pkey = PEM_read_PrivateKey(handle.get(), NULL, NULL, NULL);
- if (!pkey) {
- LOG(ERROR) << "Could not load public key file: " << filename
- << ", " << GetOpenSSLErrorString();
- return NULL;
- }
- return pkey;
-}
-
-// Convert a private key into its PKCS#8 encoded representation.
-// |pkey| is the EVP_PKEY handle for the private key.
-// |pkcs8| will receive the PKCS#8 bytes.
-// Returns true on success, false otherwise.
-bool GetPrivateKeyPkcs8Bytes(const crypto::ScopedEVP_PKEY& pkey,
- std::string* pkcs8) {
- uint8_t* der;
- size_t der_len;
- crypto::AutoCBB cbb;
- if (!CBB_init(cbb.get(), 0) ||
- !EVP_marshal_private_key(cbb.get(), pkey.get()) ||
- !CBB_finish(cbb.get(), &der, &der_len)) {
- return false;
- }
- pkcs8->assign(reinterpret_cast<const char*>(der), der_len);
- OPENSSL_free(der);
- return true;
-}
-
-bool ImportPrivateKeyFileAsPkcs8(const char* filename,
- std::string* pkcs8) {
- crypto::ScopedEVP_PKEY pkey(ImportPrivateKeyFile(filename));
- if (!pkey.get())
- return false;
- return GetPrivateKeyPkcs8Bytes(pkey, pkcs8);
-}
-
-// Same as ImportPrivateKey, but for public ones.
-EVP_PKEY* ImportPublicKeyFile(const char* filename) {
- // Load file as PEM data.
- base::FilePath certs_dir = GetTestCertsDirectory();
- base::FilePath file_path = certs_dir.AppendASCII(filename);
- base::ScopedFILE handle(base::OpenFile(file_path, "rb"));
- if (!handle.get()) {
- LOG(ERROR) << "Could not open public key file: " << filename;
- return NULL;
- }
- EVP_PKEY* pkey = PEM_read_PUBKEY(handle.get(), NULL, NULL, NULL);
- if (!pkey) {
- LOG(ERROR) << "Could not load public key file: " << filename
- << ", " << GetOpenSSLErrorString();
- return NULL;
- }
- return pkey;
-}
-
-// Retrieve a JNI local ref from encoded PKCS#8 data.
-ScopedJava GetPKCS8PrivateKeyJava(PrivateKeyType key_type,
- const std::string& pkcs8_key) {
- JNIEnv* env = InitEnv();
- base::android::ScopedJavaLocalRef<jbyteArray> bytes(
- base::android::ToJavaByteArray(
- env, reinterpret_cast<const uint8_t*>(pkcs8_key.data()),
- pkcs8_key.size()));
-
- ScopedJava key(
- Java_AndroidKeyStoreTestUtil_createPrivateKeyFromPKCS8(
- env, key_type, bytes.obj()));
-
- return key;
-}
-
-const char kTestRsaKeyFile[] = "android-test-key-rsa.pem";
-
-// The RSA test hash must be 36 bytes exactly.
-const char kTestRsaHash[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
-// Retrieve a JNI local ref for our test RSA key.
-ScopedJava GetRSATestKeyJava() {
- std::string key;
- if (!ImportPrivateKeyFileAsPkcs8(kTestRsaKeyFile, &key))
- return ScopedJava();
- return GetPKCS8PrivateKeyJava(PRIVATE_KEY_TYPE_RSA, key);
-}
-
-const char kTestEcdsaKeyFile[] = "android-test-key-ecdsa.pem";
-const char kTestEcdsaPublicKeyFile[] = "android-test-key-ecdsa-public.pem";
-
-// The test hash for ECDSA keys must be 20 bytes exactly.
-const char kTestEcdsaHash[] = "0123456789ABCDEFGHIJ";
-
-// Retrieve a JNI local ref for our test ECDSA key.
-ScopedJava GetECDSATestKeyJava() {
- std::string key;
- if (!ImportPrivateKeyFileAsPkcs8(kTestEcdsaKeyFile, &key))
- return ScopedJava();
- return GetPKCS8PrivateKeyJava(PRIVATE_KEY_TYPE_ECDSA, key);
-}
-
-// Call this function to verify that one message signed with our
-// test ECDSA private key is correct. Since ECDSA signing introduces
-// random elements in the signature, it is not possible to compare
-// signature bits directly. However, one can use the public key
-// to do the check.
-bool VerifyTestECDSASignature(const base::StringPiece& message,
- const base::StringPiece& signature) {
- crypto::ScopedEVP_PKEY pkey(ImportPublicKeyFile(kTestEcdsaPublicKeyFile));
- if (!pkey.get())
- return false;
- crypto::ScopedEC_KEY pub_key(EVP_PKEY_get1_EC_KEY(pkey.get()));
- if (!pub_key.get()) {
- LOG(ERROR) << "Could not get ECDSA public key: "
- << GetOpenSSLErrorString();
- return false;
- }
-
- const unsigned char* digest =
- reinterpret_cast<const unsigned char*>(message.data());
- int digest_len = static_cast<int>(message.size());
- const unsigned char* sigbuf =
- reinterpret_cast<const unsigned char*>(signature.data());
- int siglen = static_cast<int>(signature.size());
-
- int ret = ECDSA_verify(
- 0, digest, digest_len, sigbuf, siglen, pub_key.get());
- if (ret != 1) {
- LOG(ERROR) << "ECDSA_verify() failed: " << GetOpenSSLErrorString();
- return false;
- }
- return true;
-}
-
-// Sign a message with OpenSSL, return the result as a string.
-// |message| is the message to be signed.
-// |openssl_key| is an OpenSSL EVP_PKEY to use.
-// |result| receives the result.
-// Returns true on success, false otherwise.
-bool SignWithOpenSSL(const base::StringPiece& message,
- EVP_PKEY* openssl_key,
- std::string* result) {
- const unsigned char* digest =
- reinterpret_cast<const unsigned char*>(message.data());
- unsigned int digest_len = static_cast<unsigned int>(message.size());
- std::string signature;
- size_t signature_size;
- size_t max_signature_size;
- int key_type = EVP_PKEY_id(openssl_key);
- switch (key_type) {
- case EVP_PKEY_RSA:
- {
- crypto::ScopedRSA rsa(EVP_PKEY_get1_RSA(openssl_key));
- if (!rsa.get()) {
- LOG(ERROR) << "Could not get RSA from EVP_PKEY: "
- << GetOpenSSLErrorString();
- return false;
- }
- // With RSA, the signature will always be RSA_size() bytes.
- max_signature_size = static_cast<size_t>(RSA_size(rsa.get()));
- unsigned char* p = OpenSSLWriteInto(&signature,
- max_signature_size);
- unsigned int p_len = 0;
- int ret = RSA_sign(
- NID_md5_sha1, digest, digest_len, p, &p_len, rsa.get());
- if (ret != 1) {
- LOG(ERROR) << "RSA_sign() failed: " << GetOpenSSLErrorString();
- return false;
- }
- signature_size = static_cast<size_t>(p_len);
- break;
- }
- case EVP_PKEY_EC:
- {
- crypto::ScopedEC_KEY ecdsa(EVP_PKEY_get1_EC_KEY(openssl_key));
- if (!ecdsa.get()) {
- LOG(ERROR) << "Could not get EC_KEY from EVP_PKEY: "
- << GetOpenSSLErrorString();
- return false;
- }
- // Note, the actual signature can be smaller than ECDSA_size()
- max_signature_size = ECDSA_size(ecdsa.get());
- unsigned char* p = OpenSSLWriteInto(&signature,
- max_signature_size);
- unsigned int p_len = 0;
- // Note: first parameter is ignored by function.
- int ret = ECDSA_sign(
- 0, digest, digest_len, p, &p_len, ecdsa.get());
- if (ret != 1) {
- LOG(ERROR) << "ECDSA_sign() fialed: " << GetOpenSSLErrorString();
- return false;
- }
- signature_size = static_cast<size_t>(p_len);
- break;
- }
- default:
- LOG(WARNING) << "Invalid OpenSSL key type: " << key_type;
- return false;
- }
-
- if (signature_size == 0) {
- LOG(ERROR) << "Signature is empty!";
- return false;
- }
- if (signature_size > max_signature_size) {
- LOG(ERROR) << "Signature size mismatch, actual " << signature_size
- << ", expected <= " << max_signature_size;
- return false;
- }
- signature.resize(signature_size);
- result->swap(signature);
- return true;
-}
-
-// Check that a generated signature for a given message matches
-// OpenSSL output byte-by-byte.
-// |message| is the input message.
-// |signature| is the generated signature for the message.
-// |openssl_key| is a raw EVP_PKEY for the same private key than the
-// one which was used to generate the signature.
-// Returns true on success, false otherwise.
-bool CompareSignatureWithOpenSSL(const base::StringPiece& message,
- const base::StringPiece& signature,
- EVP_PKEY* openssl_key) {
- std::string openssl_signature;
- SignWithOpenSSL(message, openssl_key, &openssl_signature);
-
- if (signature.size() != openssl_signature.size()) {
- LOG(ERROR) << "Signature size mismatch, actual "
- << signature.size() << ", expected "
- << openssl_signature.size();
- return false;
- }
- for (size_t n = 0; n < signature.size(); ++n) {
- if (openssl_signature[n] != signature[n]) {
- LOG(ERROR) << "Signature byte mismatch at index " << n
- << "actual " << signature[n] << ", expected "
- << openssl_signature[n];
- LOG(ERROR) << "Actual signature : "
- << base::HexEncode(signature.data(), signature.size());
- LOG(ERROR) << "Expected signature: "
- << base::HexEncode(openssl_signature.data(),
- openssl_signature.size());
- return false;
- }
- }
- return true;
-}
-
-// Sign a message with our platform API.
-//
-// |android_key| is a JNI reference to the platform PrivateKey object.
-// |openssl_key| is a pointer to an OpenSSL key object for the exact
-// same key content.
-// |message| is a message.
-// |result| will receive the result.
-void DoKeySigning(jobject android_key,
- EVP_PKEY* openssl_key,
- const base::StringPiece& message,
- std::string* result) {
- // First, get the platform signature.
- std::vector<uint8_t> android_signature;
- ASSERT_TRUE(
- RawSignDigestWithPrivateKey(android_key,
- message,
- &android_signature));
-
- result->assign(
- reinterpret_cast<const char*>(&android_signature[0]),
- android_signature.size());
-}
-
-// Sign a message with our OpenSSL EVP_PKEY wrapper around platform
-// APIS.
-//
-// |android_key| is a JNI reference to the platform PrivateKey object.
-// |openssl_key| is a pointer to an OpenSSL key object for the exact
-// same key content.
-// |message| is a message.
-// |result| will receive the result.
-void DoKeySigningWithWrapper(EVP_PKEY* wrapper_key,
- EVP_PKEY* openssl_key,
- const base::StringPiece& message,
- std::string* result) {
- // First, get the platform signature.
- std::string wrapper_signature;
- SignWithOpenSSL(message, wrapper_key, &wrapper_signature);
- ASSERT_NE(0U, wrapper_signature.size());
-
- result->assign(
- reinterpret_cast<const char*>(&wrapper_signature[0]),
- wrapper_signature.size());
-}
-
-} // namespace
-
-TEST(AndroidKeyStore, GetRSAKeyModulus) {
- crypto::OpenSSLErrStackTracer err_trace(FROM_HERE);
- InitEnv();
-
- // Load the test RSA key.
- crypto::ScopedEVP_PKEY pkey(ImportPrivateKeyFile(kTestRsaKeyFile));
- ASSERT_TRUE(pkey.get());
-
- // Convert it to encoded PKCS#8 bytes.
- std::string pkcs8_data;
- ASSERT_TRUE(GetPrivateKeyPkcs8Bytes(pkey, &pkcs8_data));
-
- // Create platform PrivateKey object from it.
- ScopedJava key_java = GetPKCS8PrivateKeyJava(PRIVATE_KEY_TYPE_RSA,
- pkcs8_data);
- ASSERT_FALSE(key_java.is_null());
-
- // Retrieve the corresponding modulus through JNI
- std::vector<uint8_t> modulus_java;
- ASSERT_TRUE(GetRSAKeyModulus(key_java.obj(), &modulus_java));
-
- // Create an OpenSSL BIGNUM from it.
- crypto::ScopedBIGNUM bn(
- BN_bin2bn(reinterpret_cast<const unsigned char*>(&modulus_java[0]),
- static_cast<int>(modulus_java.size()),
- NULL));
- ASSERT_TRUE(bn.get());
-
- // Compare it to the one in the RSA key, they must be identical.
- crypto::ScopedRSA rsa(EVP_PKEY_get1_RSA(pkey.get()));
- ASSERT_TRUE(rsa.get()) << GetOpenSSLErrorString();
-
- ASSERT_EQ(0, BN_cmp(bn.get(), rsa.get()->n));
-}
-
-TEST(AndroidKeyStore,GetPrivateKeyTypeRSA) {
- crypto::OpenSSLErrStackTracer err_trace(FROM_HERE);
-
- ScopedJava rsa_key = GetRSATestKeyJava();
- ASSERT_FALSE(rsa_key.is_null());
- EXPECT_EQ(PRIVATE_KEY_TYPE_RSA,
- GetPrivateKeyType(rsa_key.obj()));
-}
-
-TEST(AndroidKeyStore,SignWithPrivateKeyRSA) {
- ScopedJava rsa_key = GetRSATestKeyJava();
- ASSERT_FALSE(rsa_key.is_null());
-
- if (IsOnAndroidOlderThan_4_2()) {
- LOG(INFO) << "This test can't run on Android < 4.2";
- return;
- }
-
- crypto::ScopedEVP_PKEY openssl_key(ImportPrivateKeyFile(kTestRsaKeyFile));
- ASSERT_TRUE(openssl_key.get());
-
- std::string message = kTestRsaHash;
- ASSERT_EQ(36U, message.size());
-
- std::string signature;
- DoKeySigning(rsa_key.obj(), openssl_key.get(), message, &signature);
- ASSERT_TRUE(
- CompareSignatureWithOpenSSL(message, signature, openssl_key.get()));
- // All good.
-}
-
-TEST(AndroidKeyStore,SignWithWrapperKeyRSA) {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
-
- ScopedJava rsa_key = GetRSATestKeyJava();
- ASSERT_FALSE(rsa_key.is_null());
-
- crypto::ScopedEVP_PKEY wrapper_key(
- GetOpenSSLPrivateKeyWrapper(rsa_key.obj()));
- ASSERT_TRUE(wrapper_key.get() != NULL);
-
- crypto::ScopedEVP_PKEY openssl_key(ImportPrivateKeyFile(kTestRsaKeyFile));
- ASSERT_TRUE(openssl_key.get());
-
- // Check that RSA_size() works properly on the wrapper key.
- EXPECT_EQ(EVP_PKEY_size(openssl_key.get()),
- EVP_PKEY_size(wrapper_key.get()));
-
- // Message size must be 36 for RSA_sign(NID_md5_sha1,...) to return
- // without an error.
- std::string message = kTestRsaHash;
- ASSERT_EQ(36U, message.size());
-
- std::string signature;
- DoKeySigningWithWrapper(wrapper_key.get(),
- openssl_key.get(),
- message,
- &signature);
- ASSERT_TRUE(
- CompareSignatureWithOpenSSL(message, signature, openssl_key.get()));
-}
-
-TEST(AndroidKeyStore,GetPrivateKeyTypeECDSA) {
- crypto::OpenSSLErrStackTracer err_trace(FROM_HERE);
-
- ScopedJava ecdsa_key = GetECDSATestKeyJava();
- ASSERT_FALSE(ecdsa_key.is_null());
- EXPECT_EQ(PRIVATE_KEY_TYPE_ECDSA,
- GetPrivateKeyType(ecdsa_key.obj()));
-}
-
-TEST(AndroidKeyStore,SignWithPrivateKeyECDSA) {
- ScopedJava ecdsa_key = GetECDSATestKeyJava();
- ASSERT_FALSE(ecdsa_key.is_null());
-
- crypto::ScopedEVP_PKEY openssl_key(ImportPrivateKeyFile(kTestEcdsaKeyFile));
- ASSERT_TRUE(openssl_key.get());
-
- std::string message = kTestEcdsaHash;
- std::string signature;
- DoKeySigning(ecdsa_key.obj(), openssl_key.get(), message, &signature);
- ASSERT_TRUE(VerifyTestECDSASignature(message, signature));
-}
-
-TEST(AndroidKeyStore, SignWithWrapperKeyECDSA) {
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
-
- ScopedJava ecdsa_key = GetECDSATestKeyJava();
- ASSERT_FALSE(ecdsa_key.is_null());
-
- crypto::ScopedEVP_PKEY wrapper_key(
- GetOpenSSLPrivateKeyWrapper(ecdsa_key.obj()));
- ASSERT_TRUE(wrapper_key.get());
-
- crypto::ScopedEVP_PKEY openssl_key(ImportPrivateKeyFile(kTestEcdsaKeyFile));
- ASSERT_TRUE(openssl_key.get());
-
- // Check that ECDSA size works correctly on the wrapper.
- EXPECT_EQ(EVP_PKEY_size(openssl_key.get()),
- EVP_PKEY_size(wrapper_key.get()));
-
- std::string message = kTestEcdsaHash;
- std::string signature;
- DoKeySigningWithWrapper(wrapper_key.get(),
- openssl_key.get(),
- message,
- &signature);
- ASSERT_TRUE(VerifyTestECDSASignature(message, signature));
-}
-
-} // namespace android
-} // namespace net
diff --git a/chromium/net/android/network_change_notifier_android.h b/chromium/net/android/network_change_notifier_android.h
index a931f74343c..41366b96dc8 100644
--- a/chromium/net/android/network_change_notifier_android.h
+++ b/chromium/net/android/network_change_notifier_android.h
@@ -11,6 +11,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "net/android/network_change_notifier_delegate_android.h"
+#include "net/base/net_export.h"
#include "net/base/network_change_notifier.h"
namespace net {
diff --git a/chromium/net/android/network_change_notifier_android_unittest.cc b/chromium/net/android/network_change_notifier_android_unittest.cc
index dee034fb290..7c54250cb6c 100644
--- a/chromium/net/android/network_change_notifier_android_unittest.cc
+++ b/chromium/net/android/network_change_notifier_android_unittest.cc
@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "net/android/network_change_notifier_android.h"
#include "net/android/network_change_notifier_delegate_android.h"
#include "net/base/ip_address.h"
@@ -214,18 +215,18 @@ class BaseNetworkChangeNotifierAndroidTest : public testing::Test {
delegate_.SetOnline();
// Note that this is needed because base::ObserverListThreadSafe uses
// PostTask().
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
void SetOffline() {
delegate_.SetOffline();
// See comment above.
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
void FakeMaxBandwidthChange(double max_bandwidth_mbps) {
delegate_.FakeMaxBandwidthChanged(max_bandwidth_mbps);
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
void FakeNetworkChange(ChangeType change,
@@ -249,13 +250,13 @@ class BaseNetworkChangeNotifierAndroidTest : public testing::Test {
break;
}
// See comment above.
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
void FakePurgeActiveNetworkList(NetworkChangeNotifier::NetworkList networks) {
delegate_.FakePurgeActiveNetworkList(networks);
// See comment above.
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
NetworkChangeNotifierDelegateAndroid delegate_;
@@ -422,7 +423,7 @@ TEST_F(NetworkChangeNotifierDelegateAndroidTest,
TEST_F(NetworkChangeNotifierAndroidTest, InitialSignal) {
DNSChangeObserver dns_change_observer;
NetworkChangeNotifier::AddDNSObserver(&dns_change_observer);
- base::MessageLoop::current()->Run();
+ base::RunLoop().Run();
EXPECT_EQ(1, dns_change_observer.initial_notifications_count());
EXPECT_EQ(0, dns_change_observer.change_notifications_count());
NetworkChangeNotifier::RemoveDNSObserver(&dns_change_observer);
diff --git a/chromium/net/android/network_change_notifier_delegate_android.cc b/chromium/net/android/network_change_notifier_delegate_android.cc
index b05e3d8b367..6bafb44dbe4 100644
--- a/chromium/net/android/network_change_notifier_delegate_android.cc
+++ b/chromium/net/android/network_change_notifier_delegate_android.cc
@@ -10,6 +10,9 @@
#include "jni/NetworkChangeNotifier_jni.h"
#include "net/android/network_change_notifier_android.h"
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
namespace net {
namespace {
@@ -47,16 +50,16 @@ NetworkChangeNotifier::ConnectionSubtype ConvertConnectionSubtype(
} // namespace
// static
-void NetworkChangeNotifierDelegateAndroid::JavaIntArrayToNetworkMap(
+void NetworkChangeNotifierDelegateAndroid::JavaLongArrayToNetworkMap(
JNIEnv* env,
- jintArray int_array,
+ jlongArray long_array,
NetworkMap* network_map) {
- std::vector<int> int_list;
- base::android::JavaIntArrayToIntVector(env, int_array, &int_list);
+ std::vector<int64_t> int64_list;
+ base::android::JavaLongArrayToInt64Vector(env, long_array, &int64_list);
network_map->clear();
- for (auto i = int_list.begin(); i != int_list.end(); ++i) {
+ for (auto i = int64_list.begin(); i != int64_list.end(); ++i) {
NetworkChangeNotifier::NetworkHandle network_handle = *i;
- CHECK(++i != int_list.end());
+ CHECK(++i != int64_list.end());
(*network_map)[network_handle] = static_cast<ConnectionType>(*i);
}
}
@@ -75,22 +78,20 @@ NetworkChangeNotifierDelegateAndroid::NetworkChangeNotifierDelegateAndroid()
Java_NetworkChangeNotifier_init(
env, base::android::GetApplicationContext()));
Java_NetworkChangeNotifier_addNativeObserver(
- env, java_network_change_notifier_.obj(),
- reinterpret_cast<intptr_t>(this));
+ env, java_network_change_notifier_, reinterpret_cast<intptr_t>(this));
SetCurrentConnectionType(
- ConvertConnectionType(
- Java_NetworkChangeNotifier_getCurrentConnectionType(
- env, java_network_change_notifier_.obj())));
+ ConvertConnectionType(Java_NetworkChangeNotifier_getCurrentConnectionType(
+ env, java_network_change_notifier_)));
SetCurrentMaxBandwidth(
Java_NetworkChangeNotifier_getCurrentMaxBandwidthInMbps(
- env, java_network_change_notifier_.obj()));
+ env, java_network_change_notifier_));
SetCurrentDefaultNetwork(Java_NetworkChangeNotifier_getCurrentDefaultNetId(
- env, java_network_change_notifier_.obj()));
+ env, java_network_change_notifier_));
NetworkMap network_map;
- ScopedJavaLocalRef<jintArray> networks_and_types =
+ ScopedJavaLocalRef<jlongArray> networks_and_types =
Java_NetworkChangeNotifier_getCurrentNetworksAndTypes(
- env, java_network_change_notifier_.obj());
- JavaIntArrayToNetworkMap(env, networks_and_types.obj(), &network_map);
+ env, java_network_change_notifier_);
+ JavaLongArrayToNetworkMap(env, networks_and_types.obj(), &network_map);
SetCurrentNetworksAndTypes(network_map);
}
@@ -99,8 +100,7 @@ NetworkChangeNotifierDelegateAndroid::~NetworkChangeNotifierDelegateAndroid() {
observers_->AssertEmpty();
JNIEnv* env = base::android::AttachCurrentThread();
Java_NetworkChangeNotifier_removeNativeObserver(
- env, java_network_change_notifier_.obj(),
- reinterpret_cast<intptr_t>(this));
+ env, java_network_change_notifier_, reinterpret_cast<intptr_t>(this));
}
NetworkChangeNotifier::ConnectionType
@@ -114,8 +114,7 @@ NetworkChangeNotifierDelegateAndroid::GetCurrentConnectionSubtype() const {
DCHECK(thread_checker_.CalledOnValidThread());
return ConvertConnectionSubtype(
Java_NetworkChangeNotifier_getCurrentConnectionSubtype(
- base::android::AttachCurrentThread(),
- java_network_change_notifier_.obj()));
+ base::android::AttachCurrentThread(), java_network_change_notifier_));
}
void NetworkChangeNotifierDelegateAndroid::
@@ -155,7 +154,7 @@ void NetworkChangeNotifierDelegateAndroid::NotifyConnectionTypeChanged(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
jint new_connection_type,
- jint default_netid) {
+ jlong default_netid) {
DCHECK(thread_checker_.CalledOnValidThread());
const ConnectionType actual_connection_type = ConvertConnectionType(
new_connection_type);
@@ -204,7 +203,7 @@ void NetworkChangeNotifierDelegateAndroid::NotifyMaxBandwidthChanged(
void NetworkChangeNotifierDelegateAndroid::NotifyOfNetworkConnect(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
- jint net_id,
+ jlong net_id,
jint connection_type) {
DCHECK(thread_checker_.CalledOnValidThread());
NetworkHandle network = net_id;
@@ -228,7 +227,7 @@ void NetworkChangeNotifierDelegateAndroid::NotifyOfNetworkConnect(
void NetworkChangeNotifierDelegateAndroid::NotifyOfNetworkSoonToDisconnect(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
- jint net_id) {
+ jlong net_id) {
DCHECK(thread_checker_.CalledOnValidThread());
NetworkHandle network = net_id;
{
@@ -242,7 +241,7 @@ void NetworkChangeNotifierDelegateAndroid::NotifyOfNetworkSoonToDisconnect(
void NetworkChangeNotifierDelegateAndroid::NotifyOfNetworkDisconnect(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
- jint net_id) {
+ jlong net_id) {
DCHECK(thread_checker_.CalledOnValidThread());
NetworkHandle network = net_id;
{
@@ -258,11 +257,11 @@ void NetworkChangeNotifierDelegateAndroid::NotifyOfNetworkDisconnect(
void NetworkChangeNotifierDelegateAndroid::NotifyPurgeActiveNetworkList(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
- const JavaParamRef<jintArray>& active_networks) {
+ const JavaParamRef<jlongArray>& active_networks) {
DCHECK(thread_checker_.CalledOnValidThread());
NetworkList active_network_list;
- base::android::JavaIntArrayToIntVector(env, active_networks,
- &active_network_list);
+ base::android::JavaLongArrayToInt64Vector(env, active_networks,
+ &active_network_list);
NetworkList disconnected_networks;
{
base::AutoLock auto_lock(connection_lock_);
@@ -355,7 +354,7 @@ void NetworkChangeNotifierDelegateAndroid::FakePurgeActiveNetworkList(
NetworkChangeNotifier::NetworkList networks) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_NetworkChangeNotifier_fakePurgeActiveNetworkList(
- env, base::android::ToJavaIntArray(env, networks).obj());
+ env, base::android::ToJavaLongArray(env, networks));
}
void NetworkChangeNotifierDelegateAndroid::FakeDefaultNetwork(
diff --git a/chromium/net/android/network_change_notifier_delegate_android.h b/chromium/net/android/network_change_notifier_delegate_android.h
index 6e710a0cd0d..e80ebe90d1d 100644
--- a/chromium/net/android/network_change_notifier_delegate_android.h
+++ b/chromium/net/android/network_change_notifier_delegate_android.h
@@ -13,6 +13,7 @@
#include "base/observer_list_threadsafe.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
+#include "net/base/net_export.h"
#include "net/base/network_change_notifier.h"
namespace net {
@@ -54,7 +55,7 @@ class NET_EXPORT_PRIVATE NetworkChangeNotifierDelegateAndroid {
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
jint new_connection_type,
- jint default_netid);
+ jlong default_netid);
jint GetConnectionType(JNIEnv* env, jobject obj) const;
// Called from NetworkChangeNotifier.java on the JNI thread whenever
@@ -77,20 +78,20 @@ class NET_EXPORT_PRIVATE NetworkChangeNotifierDelegateAndroid {
// NetworkChangeNotifierAutoDetect.Observer functions of the same names.
void NotifyOfNetworkConnect(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
- jint net_id,
+ jlong net_id,
jint connection_type);
void NotifyOfNetworkSoonToDisconnect(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
- jint net_id);
+ jlong net_id);
void NotifyOfNetworkDisconnect(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
- jint net_id);
+ jlong net_id);
void NotifyPurgeActiveNetworkList(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
- const base::android::JavaParamRef<jintArray>& active_networks);
+ const base::android::JavaParamRef<jlongArray>& active_networks);
// These methods can be called on any thread. Note that the provided observer
// will be notified on the thread AddObserver() is called on.
@@ -119,11 +120,11 @@ class NET_EXPORT_PRIVATE NetworkChangeNotifierDelegateAndroid {
// Map of active connected networks and their connection type.
typedef std::map<NetworkHandle, ConnectionType> NetworkMap;
- // Converts a Java int[] into a NetworkMap. Expects int[] to contain
+ // Converts a Java long[] into a NetworkMap. Expects long[] to contain
// repeated instances of: NetworkHandle, ConnectionType
- static void JavaIntArrayToNetworkMap(JNIEnv* env,
- jintArray int_array,
- NetworkMap* network_map);
+ static void JavaLongArrayToNetworkMap(JNIEnv* env,
+ jlongArray long_array,
+ NetworkMap* network_map);
// Setters that grab appropriate lock.
void SetCurrentConnectionType(ConnectionType connection_type);
diff --git a/chromium/net/android/network_library.cc b/chromium/net/android/network_library.cc
index eb2376e77e9..54847e08df0 100644
--- a/chromium/net/android/network_library.cc
+++ b/chromium/net/android/network_library.cc
@@ -45,17 +45,17 @@ void VerifyX509CertChain(const std::vector<std::string>& cert_chain,
ScopedJavaLocalRef<jobject> result =
Java_AndroidNetworkLibrary_verifyServerCertificates(
- env, chain_byte_array.obj(), auth_string.obj(), host_string.obj());
+ env, chain_byte_array, auth_string, host_string);
- ExtractCertVerifyResult(result.obj(),
- status, is_issued_by_known_root, verified_chain);
+ ExtractCertVerifyResult(result, status, is_issued_by_known_root,
+ verified_chain);
}
void AddTestRootCertificate(const uint8_t* cert, size_t len) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jbyteArray> cert_array = ToJavaByteArray(env, cert, len);
DCHECK(!cert_array.is_null());
- Java_AndroidNetworkLibrary_addTestRootCertificate(env, cert_array.obj());
+ Java_AndroidNetworkLibrary_addTestRootCertificate(env, cert_array);
}
void ClearTestRootCertificates() {
@@ -72,8 +72,8 @@ bool StoreKeyPair(const uint8_t* public_key,
ToJavaByteArray(env, public_key, public_len);
ScopedJavaLocalRef<jbyteArray> private_array =
ToJavaByteArray(env, private_key, private_len);
- jboolean ret = Java_AndroidNetworkLibrary_storeKeyPair(env,
- GetApplicationContext(), public_array.obj(), private_array.obj());
+ jboolean ret = Java_AndroidNetworkLibrary_storeKeyPair(
+ env, GetApplicationContext(), public_array, private_array);
LOG_IF(WARNING, !ret) <<
"Call to Java_AndroidNetworkLibrary_storeKeyPair failed";
return ret;
@@ -85,8 +85,8 @@ void StoreCertificate(net::CertificateMimeType cert_type,
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jbyteArray> data_array =
ToJavaByteArray(env, reinterpret_cast<const uint8_t*>(data), data_len);
- jboolean ret = Java_AndroidNetworkLibrary_storeCertificate(env,
- GetApplicationContext(), cert_type, data_array.obj());
+ jboolean ret = Java_AndroidNetworkLibrary_storeCertificate(
+ env, GetApplicationContext(), cert_type, data_array);
LOG_IF(WARNING, !ret) <<
"Call to Java_AndroidNetworkLibrary_storeCertificate"
" failed";
@@ -107,8 +107,8 @@ bool GetMimeTypeFromExtension(const std::string& extension,
ScopedJavaLocalRef<jstring> extension_string =
ConvertUTF8ToJavaString(env, extension);
ScopedJavaLocalRef<jstring> ret =
- Java_AndroidNetworkLibrary_getMimeTypeFromExtension(
- env, extension_string.obj());
+ Java_AndroidNetworkLibrary_getMimeTypeFromExtension(env,
+ extension_string);
if (!ret.obj())
return false;
@@ -143,8 +143,11 @@ bool GetIsRoaming() {
base::android::GetApplicationContext());
}
-bool RegisterNetworkLibrary(JNIEnv* env) {
- return RegisterNativesImpl(env);
+std::string GetWifiSSID() {
+ return base::android::ConvertJavaStringToUTF8(
+ Java_AndroidNetworkLibrary_getWifiSSID(
+ base::android::AttachCurrentThread(),
+ base::android::GetApplicationContext()));
}
} // namespace android
diff --git a/chromium/net/android/network_library.h b/chromium/net/android/network_library.h
index 827548ac590..7e1c8000fd5 100644
--- a/chromium/net/android/network_library.h
+++ b/chromium/net/android/network_library.h
@@ -77,8 +77,9 @@ NET_EXPORT std::string GetTelephonySimOperator();
// true, it suggests that use of data may incur extra costs.
NET_EXPORT bool GetIsRoaming();
-// Register JNI methods
-NET_EXPORT bool RegisterNetworkLibrary(JNIEnv* env);
+// Gets the SSID of the currently associated WiFi access point if there is one.
+// Otherwise, returns empty string.
+NET_EXPORT_PRIVATE std::string GetWifiSSID();
} // namespace android
} // namespace net
diff --git a/chromium/net/android/traffic_stats.cc b/chromium/net/android/traffic_stats.cc
index 4a953a6b880..e690974e154 100644
--- a/chromium/net/android/traffic_stats.cc
+++ b/chromium/net/android/traffic_stats.cc
@@ -43,10 +43,6 @@ bool GetCurrentUidRxBytes(int64_t* bytes) {
return *bytes != ERROR_NOT_SUPPORTED;
}
-bool Register(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
} // namespace traffic_stats
} // namespace android
diff --git a/chromium/net/android/traffic_stats.h b/chromium/net/android/traffic_stats.h
index f6aadadf8ad..866e6b7ae46 100644
--- a/chromium/net/android/traffic_stats.h
+++ b/chromium/net/android/traffic_stats.h
@@ -47,8 +47,6 @@ NET_EXPORT bool GetCurrentUidTxBytes(int64_t* bytes);
// and UDP usage. |bytes| must not be nullptr.
NET_EXPORT bool GetCurrentUidRxBytes(int64_t* bytes);
-bool Register(JNIEnv* env);
-
} // namespace traffic_stats
} // namespace android
diff --git a/chromium/net/android/unittest_support/AndroidManifest.xml b/chromium/net/android/unittest_support/AndroidManifest.xml
index d538c5065a2..69a29e08f5a 100644
--- a/chromium/net/android/unittest_support/AndroidManifest.xml
+++ b/chromium/net/android/unittest_support/AndroidManifest.xml
@@ -11,6 +11,7 @@ found in the LICENSE file.
android:versionName="1.0">
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
@@ -28,14 +29,16 @@ found in the LICENSE file.
android:name="org.chromium.base.BaseChromiumApplication">
<activity android:name=".NativeUnitTestActivity"
android:label="NativeTest"
- android:configChanges="orientation|keyboardHidden">
+ android:configChanges="orientation|keyboardHidden"
+ android:process=":test_process">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="org.chromium.net.test.DummySpnegoAuthenticatorService"
- android:exported = "false">
+ android:exported="false"
+ android:process=":test_process">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
diff --git a/chromium/net/base/address_list.cc b/chromium/net/base/address_list.cc
index 5ef9675df02..13a79660bea 100644
--- a/chromium/net/base/address_list.cc
+++ b/chromium/net/base/address_list.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/values.h"
#include "net/base/sys_addrinfo.h"
+#include "net/log/net_log_capture_mode.h"
namespace net {
@@ -92,7 +93,7 @@ void AddressList::SetDefaultCanonicalName() {
set_canonical_name(front().ToStringWithoutPort());
}
-NetLog::ParametersCallback AddressList::CreateNetLogCallback() const {
+NetLogParametersCallback AddressList::CreateNetLogCallback() const {
return base::Bind(&NetLogAddressListCallback, this);
}
diff --git a/chromium/net/base/address_list.h b/chromium/net/base/address_list.h
index c87add8d5ea..d2a13abc911 100644
--- a/chromium/net/base/address_list.h
+++ b/chromium/net/base/address_list.h
@@ -13,7 +13,7 @@
#include "base/compiler_specific.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_export.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_parameters_callback.h"
struct addrinfo;
@@ -55,7 +55,7 @@ class NET_EXPORT AddressList {
// Creates a callback for use with the NetLog that returns a Value
// representation of the address list. The callback must be destroyed before
// |this| is.
- NetLog::ParametersCallback CreateNetLogCallback() const;
+ NetLogParametersCallback CreateNetLogCallback() const;
using iterator = std::vector<IPEndPoint>::iterator;
using const_iterator = std::vector<IPEndPoint>::const_iterator;
diff --git a/chromium/net/base/address_tracker_linux.h b/chromium/net/base/address_tracker_linux.h
index 747bff9908c..1f78860bd0b 100644
--- a/chromium/net/base/address_tracker_linux.h
+++ b/chromium/net/base/address_tracker_linux.h
@@ -23,6 +23,7 @@
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
#include "net/base/ip_address.h"
+#include "net/base/net_export.h"
#include "net/base/network_change_notifier.h"
namespace net {
diff --git a/chromium/net/base/arena.cc b/chromium/net/base/arena.cc
index 6ddecba3db1..eeb286337be 100644
--- a/chromium/net/base/arena.cc
+++ b/chromium/net/base/arena.cc
@@ -19,23 +19,47 @@ UnsafeArena::~UnsafeArena() {}
UnsafeArena::UnsafeArena(UnsafeArena&& other) = default;
UnsafeArena& UnsafeArena::operator=(UnsafeArena&& other) = default;
-char* UnsafeArena::Memdup(const char* data, size_t size) {
+char* UnsafeArena::Alloc(size_t size) {
Reserve(size);
Block& b = blocks_.back();
DCHECK_GE(b.size, b.used + size);
char* out = b.data.get() + b.used;
b.used += size;
+ return out;
+}
+
+char* UnsafeArena::Realloc(char* original, size_t oldsize, size_t newsize) {
+ DCHECK(!blocks_.empty());
+ Block& last = blocks_.back();
+ if (last.data.get() <= original && original < last.data.get() + last.size) {
+ // (original, oldsize) is in the last Block.
+ DCHECK_GE(last.data.get() + last.used, original + oldsize);
+ if (original + oldsize == last.data.get() + last.used) {
+ // (original, oldsize) was the most recent allocation,
+ if (original + newsize < last.data.get() + last.size) {
+ // (original, newsize) fits in the same Block.
+ last.used += newsize - oldsize;
+ return original;
+ }
+ }
+ }
+ char* out = Alloc(newsize);
+ memcpy(out, original, oldsize);
+ return out;
+}
+
+char* UnsafeArena::Memdup(const char* data, size_t size) {
+ char* out = Alloc(size);
memcpy(out, data, size);
return out;
}
-void UnsafeArena::Free(void* data, size_t size) {
+void UnsafeArena::Free(char* data, size_t size) {
if (blocks_.empty()) {
return;
}
Block& b = blocks_.back();
- if (size <= b.used &&
- reinterpret_cast<char*>(data) + size == b.data.get() + b.used) {
+ if (size <= b.used && data + size == b.data.get() + b.used) {
// The memory region passed by the caller was the most recent allocation
// from the final block in this arena.
b.used -= size;
diff --git a/chromium/net/base/arena.h b/chromium/net/base/arena.h
index 29f885b51c4..223517df5e2 100644
--- a/chromium/net/base/arena.h
+++ b/chromium/net/base/arena.h
@@ -29,11 +29,13 @@ class NET_EXPORT_PRIVATE UnsafeArena {
UnsafeArena(UnsafeArena&& other);
UnsafeArena& operator=(UnsafeArena&& other);
+ char* Alloc(size_t size);
+ char* Realloc(char* original, size_t oldsize, size_t newsize);
char* Memdup(const char* data, size_t size);
// If |data| and |size| describe the most recent allocation made from this
// arena, the memory is reclaimed. Otherwise, this method is a no-op.
- void Free(void* data, size_t size);
+ void Free(char* data, size_t size);
void Reset();
diff --git a/chromium/net/base/arena_unittest.cc b/chromium/net/base/arena_unittest.cc
index 4d012d2daaf..434d76eecf9 100644
--- a/chromium/net/base/arena_unittest.cc
+++ b/chromium/net/base/arena_unittest.cc
@@ -89,5 +89,50 @@ TEST(UnsafeArenaTest, Free) {
EXPECT_EQ(c4, c5);
}
+TEST(UnsafeArenaTest, Alloc) {
+ UnsafeArena arena(kDefaultBlockSize);
+ const size_t length = strlen(kTestString);
+ char* c1 = arena.Alloc(length);
+ char* c2 = arena.Alloc(2 * length);
+ char* c3 = arena.Alloc(3 * length);
+ char* c4 = arena.Memdup(kTestString, length);
+ EXPECT_EQ(c1 + length, c2);
+ EXPECT_EQ(c2 + 2 * length, c3);
+ EXPECT_EQ(c3 + 3 * length, c4);
+ EXPECT_EQ(StringPiece(c4, length), kTestString);
+}
+
+TEST(UnsafeArenaTest, Realloc) {
+ UnsafeArena arena(kDefaultBlockSize);
+ const size_t length = strlen(kTestString);
+ // Simple realloc that fits in the block.
+ char* c1 = arena.Memdup(kTestString, length);
+ char* c2 = arena.Realloc(c1, length, 2 * length);
+ EXPECT_TRUE(c1);
+ EXPECT_EQ(c1, c2);
+ EXPECT_EQ(StringPiece(c1, length), kTestString);
+ // Multiple reallocs.
+ char* c3 = arena.Memdup(kTestString, length);
+ EXPECT_EQ(c2 + 2 * length, c3);
+ EXPECT_EQ(StringPiece(c3, length), kTestString);
+ char* c4 = arena.Realloc(c3, length, 2 * length);
+ EXPECT_EQ(c3, c4);
+ EXPECT_EQ(StringPiece(c4, length), kTestString);
+ char* c5 = arena.Realloc(c4, 2 * length, 3 * length);
+ EXPECT_EQ(c4, c5);
+ EXPECT_EQ(StringPiece(c5, length), kTestString);
+ char* c6 = arena.Memdup(kTestString, length);
+ EXPECT_EQ(c5 + 3 * length, c6);
+ EXPECT_EQ(StringPiece(c6, length), kTestString);
+ // Realloc that does not fit in the remainder of the first block.
+ char* c7 = arena.Realloc(c6, length, kDefaultBlockSize);
+ EXPECT_EQ(StringPiece(c7, length), kTestString);
+ arena.Free(c7, kDefaultBlockSize);
+ char* c8 = arena.Memdup(kTestString, length);
+ EXPECT_NE(c6, c7);
+ EXPECT_EQ(c7, c8);
+ EXPECT_EQ(StringPiece(c8, length), kTestString);
+}
+
} // namespace
} // namespace net
diff --git a/chromium/net/base/auth.cc b/chromium/net/base/auth.cc
index 13ab1edfa8c..a1af831030c 100644
--- a/chromium/net/base/auth.cc
+++ b/chromium/net/base/auth.cc
@@ -19,12 +19,6 @@ bool AuthChallengeInfo::Equals(const AuthChallengeInfo& that) const {
AuthChallengeInfo::~AuthChallengeInfo() {
}
-AuthData::AuthData() : state(AUTH_STATE_NEED_AUTH) {
-}
-
-AuthData::~AuthData() {
-}
-
AuthCredentials::AuthCredentials() {
}
diff --git a/chromium/net/base/auth.h b/chromium/net/base/auth.h
index ed369f8fc64..5f97acbf87f 100644
--- a/chromium/net/base/auth.h
+++ b/chromium/net/base/auth.h
@@ -89,19 +89,6 @@ enum AuthState {
AUTH_STATE_CANCELED
};
-class AuthData : public base::RefCountedThreadSafe<AuthData> {
- public:
- AuthState state; // whether we need, have, or gave up on authentication.
- AuthCredentials credentials; // The credentials to use for auth.
-
- // We wouldn't instantiate this class if we didn't need authentication.
- AuthData();
-
- private:
- friend class base::RefCountedThreadSafe<AuthData>;
- ~AuthData();
-};
-
} // namespace net
#endif // NET_BASE_AUTH_H__
diff --git a/chromium/net/base/backoff_entry.cc b/chromium/net/base/backoff_entry.cc
index 64125721c57..a77c5251c9e 100644
--- a/chromium/net/base/backoff_entry.cc
+++ b/chromium/net/base/backoff_entry.cc
@@ -114,6 +114,10 @@ void BackoffEntry::Reset() {
exponential_backoff_release_time_ = base::TimeTicks();
}
+base::TimeTicks BackoffEntry::GetTimeTicksNow() const {
+ return clock_ ? clock_->NowTicks() : base::TimeTicks::Now();
+}
+
base::TimeTicks BackoffEntry::CalculateReleaseTime() const {
int effective_failure_count =
std::max(0, failure_count_ - policy_->num_errors_to_ignore);
@@ -179,8 +183,4 @@ base::TimeTicks BackoffEntry::BackoffDurationToReleaseTime(
return base::TimeTicks() + base::TimeDelta::FromMicroseconds(release_time_us);
}
-base::TimeTicks BackoffEntry::GetTimeTicksNow() const {
- return clock_ ? clock_->NowTicks() : base::TimeTicks::Now();
-}
-
} // namespace net
diff --git a/chromium/net/base/backoff_entry.h b/chromium/net/base/backoff_entry.h
index 3efd32cee01..f8543cd7556 100644
--- a/chromium/net/base/backoff_entry.h
+++ b/chromium/net/base/backoff_entry.h
@@ -108,16 +108,13 @@ class NET_EXPORT BackoffEntry : NON_EXPORTED_BASE(public base::NonThreadSafe) {
// Returns the failure count for this entry.
int failure_count() const { return failure_count_; }
- // Returns the TickClock passed in to the constructor. May be NULL.
- base::TickClock* tick_clock() const { return clock_; }
+ // Equivalent to TimeTicks::Now(), using clock_ if provided.
+ base::TimeTicks GetTimeTicksNow() const;
private:
// Calculates when requests should again be allowed through.
base::TimeTicks CalculateReleaseTime() const;
- // Equivalent to TimeTicks::Now(), using clock_ if provided.
- base::TimeTicks GetTimeTicksNow() const;
-
// Timestamp calculated by the exponential back-off algorithm at which we are
// allowed to start sending requests again.
base::TimeTicks exponential_backoff_release_time_;
diff --git a/chromium/net/base/backoff_entry_serializer.cc b/chromium/net/base/backoff_entry_serializer.cc
index acd6e9f9a7c..f2cbec753e0 100644
--- a/chromium/net/base/backoff_entry_serializer.cc
+++ b/chromium/net/base/backoff_entry_serializer.cc
@@ -29,7 +29,7 @@ std::unique_ptr<base::Value> BackoffEntrySerializer::SerializeToValue(
// Can't use entry.GetTimeUntilRelease as it doesn't allow negative deltas.
base::TimeDelta backoff_duration =
- entry.GetReleaseTime() - entry.tick_clock()->NowTicks();
+ entry.GetReleaseTime() - entry.GetTimeTicksNow();
// Redundantly stores both the remaining time delta and the absolute time.
// The delta is used to work around some cases where wall clock time changes.
serialized->AppendDouble(backoff_duration.InSecondsF());
diff --git a/chromium/net/base/chunked_upload_data_stream.cc b/chromium/net/base/chunked_upload_data_stream.cc
index 8d5a2912bcc..4670a0c1b1c 100644
--- a/chromium/net/base/chunked_upload_data_stream.cc
+++ b/chromium/net/base/chunked_upload_data_stream.cc
@@ -49,7 +49,7 @@ void ChunkedUploadDataStream::AppendData(
if (data_len > 0) {
DCHECK(data);
upload_data_.push_back(
- base::WrapUnique(new std::vector<char>(data, data + data_len)));
+ base::MakeUnique<std::vector<char>>(data, data + data_len));
}
all_data_appended_ = is_done;
@@ -64,7 +64,7 @@ void ChunkedUploadDataStream::AppendData(
OnReadCompleted(result);
}
-int ChunkedUploadDataStream::InitInternal() {
+int ChunkedUploadDataStream::InitInternal(const NetLogWithSource& net_log) {
// ResetInternal should already have been called.
DCHECK(!read_buffer_.get());
DCHECK_EQ(0u, read_index_);
diff --git a/chromium/net/base/chunked_upload_data_stream.h b/chromium/net/base/chunked_upload_data_stream.h
index f58faf6a09c..5efd67146db 100644
--- a/chromium/net/base/chunked_upload_data_stream.h
+++ b/chromium/net/base/chunked_upload_data_stream.h
@@ -79,7 +79,7 @@ class NET_EXPORT ChunkedUploadDataStream : public UploadDataStream {
private:
// UploadDataStream implementation.
- int InitInternal() override;
+ int InitInternal(const NetLogWithSource& net_log) override;
int ReadInternal(IOBuffer* buf, int buf_len) override;
void ResetInternal() override;
diff --git a/chromium/net/base/chunked_upload_data_stream_unittest.cc b/chromium/net/base/chunked_upload_data_stream_unittest.cc
index 5b0d2164be6..59d515e1439 100644
--- a/chromium/net/base/chunked_upload_data_stream_unittest.cc
+++ b/chromium/net/base/chunked_upload_data_stream_unittest.cc
@@ -11,8 +11,14 @@
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/base/upload_data_stream.h"
+#include "net/log/net_log_with_source.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -38,7 +44,9 @@ std::string ReadSync(UploadDataStream* stream, int buffer_size) {
TEST(ChunkedUploadDataStreamTest, AppendOnce) {
ChunkedUploadDataStream stream(0);
- ASSERT_EQ(OK, stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(
+ stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(stream.IsInMemory());
EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
EXPECT_EQ(0u, stream.position());
@@ -47,7 +55,7 @@ TEST(ChunkedUploadDataStreamTest, AppendOnce) {
TestCompletionCallback callback;
scoped_refptr<IOBuffer> buf = new IOBuffer(kTestBufferSize);
int result = stream.Read(buf.get(), kTestBufferSize, callback.callback());
- ASSERT_EQ(ERR_IO_PENDING, result);
+ ASSERT_THAT(result, IsError(ERR_IO_PENDING));
stream.AppendData(kTestData, kTestDataSize, true);
int read = callback.WaitForResult();
@@ -61,7 +69,9 @@ TEST(ChunkedUploadDataStreamTest, AppendOnce) {
TEST(ChunkedUploadDataStreamTest, AppendOnceBeforeRead) {
ChunkedUploadDataStream stream(0);
- ASSERT_EQ(OK, stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(
+ stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(stream.IsInMemory());
EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
EXPECT_EQ(0u, stream.position());
@@ -83,7 +93,9 @@ TEST(ChunkedUploadDataStreamTest, AppendOnceBeforeInit) {
ChunkedUploadDataStream stream(0);
stream.AppendData(kTestData, kTestDataSize, true);
- ASSERT_EQ(OK, stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(
+ stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(stream.IsInMemory());
EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
EXPECT_EQ(0u, stream.position());
@@ -99,7 +111,9 @@ TEST(ChunkedUploadDataStreamTest, AppendOnceBeforeInit) {
TEST(ChunkedUploadDataStreamTest, MultipleAppends) {
ChunkedUploadDataStream stream(0);
- ASSERT_EQ(OK, stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(
+ stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(stream.IsInMemory());
EXPECT_EQ(0u, stream.size());
EXPECT_EQ(0u, stream.position());
@@ -114,7 +128,7 @@ TEST(ChunkedUploadDataStreamTest, MultipleAppends) {
int bytes_read = stream.Read(buf.get(),
kTestBufferSize,
callback.callback());
- ASSERT_EQ(ERR_IO_PENDING, bytes_read);
+ ASSERT_THAT(bytes_read, IsError(ERR_IO_PENDING));
stream.AppendData(&kTestData[i], 1, i == kTestDataSize - 1);
ASSERT_EQ(1, callback.WaitForResult());
EXPECT_EQ(kTestData[i], buf->data()[0]);
@@ -128,7 +142,9 @@ TEST(ChunkedUploadDataStreamTest, MultipleAppends) {
TEST(ChunkedUploadDataStreamTest, MultipleAppendsBetweenReads) {
ChunkedUploadDataStream stream(0);
- ASSERT_EQ(OK, stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(
+ stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(stream.IsInMemory());
EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
EXPECT_EQ(0u, stream.position());
@@ -157,7 +173,9 @@ TEST(ChunkedUploadDataStreamTest, MultipleAppendsBeforeInit) {
stream.AppendData(kTestData + 1, 1, false);
stream.AppendData(kTestData + 2, kTestDataSize - 2, true);
- ASSERT_EQ(OK, stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(
+ stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(stream.IsInMemory());
EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
EXPECT_EQ(0u, stream.position());
@@ -179,7 +197,9 @@ TEST(ChunkedUploadDataStreamTest, MultipleReads) {
stream.AppendData(kTestData, kTestDataSize, false);
stream.AppendData(kTestData, kTestDataSize, true);
- ASSERT_EQ(OK, stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(
+ stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(stream.IsInMemory());
EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
EXPECT_EQ(0u, stream.position());
@@ -209,7 +229,9 @@ TEST(ChunkedUploadDataStreamTest, MultipleReads) {
TEST(ChunkedUploadDataStreamTest, EmptyUpload) {
ChunkedUploadDataStream stream(0);
- ASSERT_EQ(OK, stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(
+ stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(stream.IsInMemory());
EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
EXPECT_EQ(0u, stream.position());
@@ -218,7 +240,7 @@ TEST(ChunkedUploadDataStreamTest, EmptyUpload) {
TestCompletionCallback callback;
scoped_refptr<IOBuffer> buf = new IOBuffer(kTestBufferSize);
int result = stream.Read(buf.get(), kTestBufferSize, callback.callback());
- ASSERT_EQ(ERR_IO_PENDING, result);
+ ASSERT_THAT(result, IsError(ERR_IO_PENDING));
stream.AppendData(NULL, 0, true);
int read = callback.WaitForResult();
@@ -231,7 +253,9 @@ TEST(ChunkedUploadDataStreamTest, EmptyUploadEndedBeforeInit) {
ChunkedUploadDataStream stream(0);
stream.AppendData(NULL, 0, true);
- ASSERT_EQ(OK, stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(
+ stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(stream.IsInMemory());
EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
EXPECT_EQ(0u, stream.position());
@@ -248,7 +272,9 @@ TEST(ChunkedUploadDataStreamTest, RewindAfterComplete) {
stream.AppendData(kTestData, 1, false);
stream.AppendData(kTestData + 1, kTestDataSize - 1, true);
- ASSERT_EQ(OK, stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(
+ stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(stream.IsInMemory());
EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
EXPECT_EQ(0u, stream.position());
@@ -260,7 +286,9 @@ TEST(ChunkedUploadDataStreamTest, RewindAfterComplete) {
ASSERT_TRUE(stream.IsEOF());
// Rewind stream and repeat.
- ASSERT_EQ(OK, stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(
+ stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(stream.IsInMemory());
EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
EXPECT_EQ(0u, stream.position());
@@ -275,7 +303,9 @@ TEST(ChunkedUploadDataStreamTest, RewindAfterComplete) {
TEST(ChunkedUploadDataStreamTest, RewindWhileReading) {
ChunkedUploadDataStream stream(0);
- ASSERT_EQ(OK, stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(
+ stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(stream.IsInMemory());
EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
EXPECT_EQ(0u, stream.position());
@@ -284,9 +314,11 @@ TEST(ChunkedUploadDataStreamTest, RewindWhileReading) {
TestCompletionCallback callback;
scoped_refptr<IOBuffer> buf = new IOBuffer(kTestBufferSize);
int result = stream.Read(buf.get(), kTestBufferSize, callback.callback());
- ASSERT_EQ(ERR_IO_PENDING, result);
+ ASSERT_THAT(result, IsError(ERR_IO_PENDING));
- ASSERT_EQ(OK, stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(
+ stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(stream.IsInMemory());
EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
EXPECT_EQ(0u, stream.position());
@@ -314,7 +346,9 @@ TEST(ChunkedUploadDataStreamTest, ChunkedUploadDataStreamWriter) {
// Write before Init.
ASSERT_TRUE(writer->AppendData(kTestData, 1, false));
- ASSERT_EQ(OK, stream->Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(
+ stream->Init(TestCompletionCallback().callback(), NetLogWithSource()),
+ IsOk());
// Write after Init.
ASSERT_TRUE(writer->AppendData(kTestData + 1, kTestDataSize - 1, false));
diff --git a/chromium/net/base/directory_lister_unittest.cc b/chromium/net/base/directory_lister_unittest.cc
index 6bb77dfb2f6..64dda72b74c 100644
--- a/chromium/net/base/directory_lister_unittest.cc
+++ b/chromium/net/base/directory_lister_unittest.cc
@@ -16,9 +16,14 @@
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/directory_lister.h"
#include "net/base/net_errors.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -138,7 +143,7 @@ class DirectoryListerTest : public PlatformTest {
// directory.
std::list<std::pair<base::FilePath, int> > directories;
ASSERT_TRUE(temp_root_dir_.CreateUniqueTempDir());
- directories.push_back(std::make_pair(temp_root_dir_.path(), 0));
+ directories.push_back(std::make_pair(temp_root_dir_.GetPath(), 0));
while (!directories.empty()) {
std::pair<base::FilePath, int> dir_data = directories.front();
directories.pop_front();
@@ -149,7 +154,7 @@ class DirectoryListerTest : public PlatformTest {
base::File::FLAG_CREATE | base::File::FLAG_WRITE);
ASSERT_TRUE(file.IsValid());
++total_created_file_system_objects_in_temp_root_dir_;
- if (dir_data.first == temp_root_dir_.path())
+ if (dir_data.first == temp_root_dir_.GetPath())
++created_file_system_objects_in_temp_root_dir_;
}
if (dir_data.second < kMaxDepth - 1) {
@@ -158,7 +163,7 @@ class DirectoryListerTest : public PlatformTest {
base::FilePath dir_path = dir_data.first.AppendASCII(dir_name);
ASSERT_TRUE(base::CreateDirectory(dir_path));
++total_created_file_system_objects_in_temp_root_dir_;
- if (dir_data.first == temp_root_dir_.path())
+ if (dir_data.first == temp_root_dir_.GetPath())
++created_file_system_objects_in_temp_root_dir_;
directories.push_back(std::make_pair(dir_path, dir_data.second + 1));
}
@@ -167,9 +172,7 @@ class DirectoryListerTest : public PlatformTest {
PlatformTest::SetUp();
}
- const base::FilePath& root_path() const {
- return temp_root_dir_.path();
- }
+ const base::FilePath& root_path() const { return temp_root_dir_.GetPath(); }
int expected_list_length_recursive() const {
// List should include everything but the top level directory, and does not
@@ -198,7 +201,7 @@ TEST_F(DirectoryListerTest, BigDirTest) {
delegate.Run(&lister);
EXPECT_TRUE(delegate.done());
- EXPECT_EQ(OK, delegate.error());
+ EXPECT_THAT(delegate.error(), IsOk());
EXPECT_EQ(expected_list_length_non_recursive(), delegate.num_files());
}
@@ -209,7 +212,7 @@ TEST_F(DirectoryListerTest, BigDirRecursiveTest) {
delegate.Run(&lister);
EXPECT_TRUE(delegate.done());
- EXPECT_EQ(OK, delegate.error());
+ EXPECT_THAT(delegate.error(), IsOk());
EXPECT_EQ(expected_list_length_recursive(), delegate.num_files());
}
@@ -218,11 +221,11 @@ TEST_F(DirectoryListerTest, EmptyDirTest) {
EXPECT_TRUE(tempDir.CreateUniqueTempDir());
ListerDelegate delegate(DirectoryLister::ALPHA_DIRS_FIRST);
- DirectoryLister lister(tempDir.path(), &delegate);
+ DirectoryLister lister(tempDir.GetPath(), &delegate);
delegate.Run(&lister);
EXPECT_TRUE(delegate.done());
- EXPECT_EQ(OK, delegate.error());
+ EXPECT_THAT(delegate.error(), IsOk());
// Contains only the parent directory ("..").
EXPECT_EQ(1, delegate.num_files());
}
@@ -261,7 +264,7 @@ TEST_F(DirectoryListerTest, CancelOnListDoneTest) {
delegate.Run(&lister);
EXPECT_TRUE(delegate.done());
- EXPECT_EQ(OK, delegate.error());
+ EXPECT_THAT(delegate.error(), IsOk());
EXPECT_EQ(expected_list_length_non_recursive(), delegate.num_files());
}
@@ -270,7 +273,7 @@ TEST_F(DirectoryListerTest, CancelOnLastElementTest) {
EXPECT_TRUE(tempDir.CreateUniqueTempDir());
ListerDelegate delegate(DirectoryLister::ALPHA_DIRS_FIRST);
- DirectoryLister lister(tempDir.path(), &delegate);
+ DirectoryLister lister(tempDir.GetPath(), &delegate);
delegate.set_cancel_lister_on_list_file(true);
delegate.Run(&lister);
@@ -285,10 +288,10 @@ TEST_F(DirectoryListerTest, NoSuchDirTest) {
ListerDelegate delegate(DirectoryLister::ALPHA_DIRS_FIRST);
DirectoryLister lister(
- tempDir.path().AppendASCII("this_path_does_not_exist"), &delegate);
+ tempDir.GetPath().AppendASCII("this_path_does_not_exist"), &delegate);
delegate.Run(&lister);
- EXPECT_EQ(ERR_FILE_NOT_FOUND, delegate.error());
+ EXPECT_THAT(delegate.error(), IsError(ERR_FILE_NOT_FOUND));
EXPECT_EQ(0, delegate.num_files());
}
diff --git a/chromium/net/base/elements_upload_data_stream.cc b/chromium/net/base/elements_upload_data_stream.cc
index 2fdbf1934e3..78d563701d5 100644
--- a/chromium/net/base/elements_upload_data_stream.cc
+++ b/chromium/net/base/elements_upload_data_stream.cc
@@ -35,7 +35,7 @@ std::unique_ptr<UploadDataStream> ElementsUploadDataStream::CreateWithReader(
new ElementsUploadDataStream(std::move(readers), identifier));
}
-int ElementsUploadDataStream::InitInternal() {
+int ElementsUploadDataStream::InitInternal(const NetLogWithSource& net_log) {
return InitElements(0);
}
diff --git a/chromium/net/base/elements_upload_data_stream.h b/chromium/net/base/elements_upload_data_stream.h
index 296cfbb8052..4ad404897fe 100644
--- a/chromium/net/base/elements_upload_data_stream.h
+++ b/chromium/net/base/elements_upload_data_stream.h
@@ -43,7 +43,7 @@ class NET_EXPORT ElementsUploadDataStream : public UploadDataStream {
bool IsInMemory() const override;
const std::vector<std::unique_ptr<UploadElementReader>>* GetElementReaders()
const override;
- int InitInternal() override;
+ int InitInternal(const NetLogWithSource& net_log) override;
int ReadInternal(IOBuffer* buf, int buf_len) override;
void ResetInternal() override;
diff --git a/chromium/net/base/elements_upload_data_stream_unittest.cc b/chromium/net/base/elements_upload_data_stream_unittest.cc
index 0fab7acdedf..98240de2b83 100644
--- a/chromium/net/base/elements_upload_data_stream_unittest.cc
+++ b/chromium/net/base/elements_upload_data_stream_unittest.cc
@@ -27,10 +27,15 @@
#include "net/base/upload_bytes_element_reader.h"
#include "net/base/upload_data_stream.h"
#include "net/base/upload_file_element_reader.h"
+#include "net/log/net_log_with_source.h"
+#include "net/test/gtest_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsError;
+using net::test::IsOk;
+
using ::testing::DoAll;
using ::testing::Invoke;
using ::testing::Return;
@@ -150,7 +155,7 @@ class ElementsUploadDataStreamTest : public PlatformTest {
TEST_F(ElementsUploadDataStreamTest, EmptyUploadData) {
std::unique_ptr<UploadDataStream> stream(
new ElementsUploadDataStream(std::move(element_readers_), 0));
- ASSERT_EQ(OK, stream->Init(CompletionCallback()));
+ ASSERT_THAT(stream->Init(CompletionCallback(), NetLogWithSource()), IsOk());
EXPECT_TRUE(stream->IsInMemory());
EXPECT_EQ(0U, stream->size());
EXPECT_EQ(0U, stream->position());
@@ -159,10 +164,10 @@ TEST_F(ElementsUploadDataStreamTest, EmptyUploadData) {
TEST_F(ElementsUploadDataStreamTest, ConsumeAllBytes) {
element_readers_.push_back(
- base::WrapUnique(new UploadBytesElementReader(kTestData, kTestDataSize)));
+ base::MakeUnique<UploadBytesElementReader>(kTestData, kTestDataSize));
std::unique_ptr<UploadDataStream> stream(
new ElementsUploadDataStream(std::move(element_readers_), 0));
- ASSERT_EQ(OK, stream->Init(CompletionCallback()));
+ ASSERT_THAT(stream->Init(CompletionCallback(), NetLogWithSource()), IsOk());
EXPECT_TRUE(stream->IsInMemory());
EXPECT_EQ(kTestDataSize, stream->size());
EXPECT_EQ(0U, stream->position());
@@ -179,20 +184,21 @@ TEST_F(ElementsUploadDataStreamTest, ConsumeAllBytes) {
TEST_F(ElementsUploadDataStreamTest, File) {
base::FilePath temp_file_path;
- ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(),
- &temp_file_path));
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &temp_file_path));
ASSERT_EQ(static_cast<int>(kTestDataSize),
base::WriteFile(temp_file_path, kTestData, kTestDataSize));
- element_readers_.push_back(base::WrapUnique(new UploadFileElementReader(
+ element_readers_.push_back(base::MakeUnique<UploadFileElementReader>(
base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
- std::numeric_limits<uint64_t>::max(), base::Time())));
+ std::numeric_limits<uint64_t>::max(), base::Time()));
TestCompletionCallback init_callback;
std::unique_ptr<UploadDataStream> stream(
new ElementsUploadDataStream(std::move(element_readers_), 0));
- ASSERT_EQ(ERR_IO_PENDING, stream->Init(init_callback.callback()));
- ASSERT_EQ(OK, init_callback.WaitForResult());
+ ASSERT_THAT(stream->Init(init_callback.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ ASSERT_THAT(init_callback.WaitForResult(), IsOk());
EXPECT_FALSE(stream->IsInMemory());
EXPECT_EQ(kTestDataSize, stream->size());
EXPECT_EQ(0U, stream->position());
@@ -211,8 +217,8 @@ TEST_F(ElementsUploadDataStreamTest, File) {
TEST_F(ElementsUploadDataStreamTest, FileSmallerThanLength) {
base::FilePath temp_file_path;
- ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(),
- &temp_file_path));
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &temp_file_path));
ASSERT_EQ(static_cast<int>(kTestDataSize),
base::WriteFile(temp_file_path, kTestData, kTestDataSize));
const uint64_t kFakeSize = kTestDataSize * 2;
@@ -220,15 +226,16 @@ TEST_F(ElementsUploadDataStreamTest, FileSmallerThanLength) {
UploadFileElementReader::ScopedOverridingContentLengthForTests
overriding_content_length(kFakeSize);
- element_readers_.push_back(base::WrapUnique(new UploadFileElementReader(
+ element_readers_.push_back(base::MakeUnique<UploadFileElementReader>(
base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
- std::numeric_limits<uint64_t>::max(), base::Time())));
+ std::numeric_limits<uint64_t>::max(), base::Time()));
TestCompletionCallback init_callback;
std::unique_ptr<UploadDataStream> stream(
new ElementsUploadDataStream(std::move(element_readers_), 0));
- ASSERT_EQ(ERR_IO_PENDING, stream->Init(init_callback.callback()));
- ASSERT_EQ(OK, init_callback.WaitForResult());
+ ASSERT_THAT(stream->Init(init_callback.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ ASSERT_THAT(init_callback.WaitForResult(), IsOk());
EXPECT_FALSE(stream->IsInMemory());
EXPECT_EQ(kFakeSize, stream->size());
EXPECT_EQ(0U, stream->position());
@@ -262,13 +269,13 @@ TEST_F(ElementsUploadDataStreamTest, ReadErrorSync) {
// This element is ignored because of the error from the previous reader.
element_readers_.push_back(
- base::WrapUnique(new UploadBytesElementReader(kTestData, kTestDataSize)));
+ base::MakeUnique<UploadBytesElementReader>(kTestData, kTestDataSize));
std::unique_ptr<UploadDataStream> stream(
new ElementsUploadDataStream(std::move(element_readers_), 0));
// Run Init().
- ASSERT_EQ(OK, stream->Init(CompletionCallback()));
+ ASSERT_THAT(stream->Init(CompletionCallback(), NetLogWithSource()), IsOk());
EXPECT_EQ(kTestDataSize*2, stream->size());
EXPECT_EQ(0U, stream->position());
EXPECT_FALSE(stream->IsEOF());
@@ -297,15 +304,16 @@ TEST_F(ElementsUploadDataStreamTest, ReadErrorAsync) {
// This element is ignored because of the error from the previous reader.
element_readers_.push_back(
- base::WrapUnique(new UploadBytesElementReader(kTestData, kTestDataSize)));
+ base::MakeUnique<UploadBytesElementReader>(kTestData, kTestDataSize));
std::unique_ptr<UploadDataStream> stream(
new ElementsUploadDataStream(std::move(element_readers_), 0));
// Run Init().
TestCompletionCallback init_callback;
- ASSERT_EQ(ERR_IO_PENDING, stream->Init(init_callback.callback()));
- EXPECT_EQ(OK, init_callback.WaitForResult());
+ ASSERT_THAT(stream->Init(init_callback.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(init_callback.WaitForResult(), IsOk());
EXPECT_EQ(kTestDataSize*2, stream->size());
EXPECT_EQ(0U, stream->position());
EXPECT_FALSE(stream->IsEOF());
@@ -318,7 +326,7 @@ TEST_F(ElementsUploadDataStreamTest, ReadErrorAsync) {
TestCompletionCallback read_callback;
ASSERT_EQ(ERR_IO_PENDING,
stream->Read(buf.get(), kTestBufferSize, read_callback.callback()));
- EXPECT_EQ(ERR_FAILED, read_callback.WaitForResult());
+ EXPECT_THAT(read_callback.WaitForResult(), IsError(ERR_FAILED));
EXPECT_EQ(0U, stream->position());
EXPECT_FALSE(stream->IsEOF());
@@ -328,26 +336,27 @@ TEST_F(ElementsUploadDataStreamTest, ReadErrorAsync) {
TEST_F(ElementsUploadDataStreamTest, FileAndBytes) {
base::FilePath temp_file_path;
- ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(),
- &temp_file_path));
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &temp_file_path));
ASSERT_EQ(static_cast<int>(kTestDataSize),
base::WriteFile(temp_file_path, kTestData, kTestDataSize));
const uint64_t kFileRangeOffset = 1;
const uint64_t kFileRangeLength = 4;
- element_readers_.push_back(base::WrapUnique(new UploadFileElementReader(
+ element_readers_.push_back(base::MakeUnique<UploadFileElementReader>(
base::ThreadTaskRunnerHandle::Get().get(), temp_file_path,
- kFileRangeOffset, kFileRangeLength, base::Time())));
+ kFileRangeOffset, kFileRangeLength, base::Time()));
element_readers_.push_back(
- base::WrapUnique(new UploadBytesElementReader(kTestData, kTestDataSize)));
+ base::MakeUnique<UploadBytesElementReader>(kTestData, kTestDataSize));
const uint64_t kStreamSize = kTestDataSize + kFileRangeLength;
TestCompletionCallback init_callback;
std::unique_ptr<UploadDataStream> stream(
new ElementsUploadDataStream(std::move(element_readers_), 0));
- ASSERT_EQ(ERR_IO_PENDING, stream->Init(init_callback.callback()));
- ASSERT_EQ(OK, init_callback.WaitForResult());
+ ASSERT_THAT(stream->Init(init_callback.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ ASSERT_THAT(init_callback.WaitForResult(), IsOk());
EXPECT_FALSE(stream->IsInMemory());
EXPECT_EQ(kStreamSize, stream->size());
EXPECT_EQ(0U, stream->position());
@@ -398,8 +407,9 @@ TEST_F(ElementsUploadDataStreamTest, InitAsync) {
// Run Init().
TestCompletionCallback callback;
- ASSERT_EQ(ERR_IO_PENDING, stream->Init(callback.callback()));
- EXPECT_EQ(OK, callback.WaitForResult());
+ ASSERT_THAT(stream->Init(callback.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
}
// Init() of a reader fails asynchronously.
@@ -415,8 +425,9 @@ TEST_F(ElementsUploadDataStreamTest, InitAsyncFailureAsync) {
// Run Init().
TestCompletionCallback callback;
- ASSERT_EQ(ERR_IO_PENDING, stream->Init(callback.callback()));
- EXPECT_EQ(ERR_FAILED, callback.WaitForResult());
+ ASSERT_THAT(stream->Init(callback.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_FAILED));
}
// Init() of a reader fails synchronously.
@@ -437,8 +448,9 @@ TEST_F(ElementsUploadDataStreamTest, InitAsyncFailureSync) {
// Run Init().
TestCompletionCallback callback;
- ASSERT_EQ(ERR_IO_PENDING, stream->Init(callback.callback()));
- EXPECT_EQ(ERR_FAILED, callback.WaitForResult());
+ ASSERT_THAT(stream->Init(callback.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_FAILED));
}
// Read with a buffer whose size is same as the data.
@@ -448,7 +460,7 @@ TEST_F(ElementsUploadDataStreamTest, ReadAsyncWithExactSizeBuffer) {
std::unique_ptr<UploadDataStream> stream(
new ElementsUploadDataStream(std::move(element_readers_), 0));
- ASSERT_EQ(OK, stream->Init(CompletionCallback()));
+ ASSERT_THAT(stream->Init(CompletionCallback(), NetLogWithSource()), IsOk());
EXPECT_TRUE(stream->IsInMemory());
EXPECT_EQ(kTestDataSize, stream->size());
EXPECT_EQ(0U, stream->position());
@@ -492,8 +504,9 @@ TEST_F(ElementsUploadDataStreamTest, ReadAsync) {
// Run Init().
TestCompletionCallback init_callback;
- EXPECT_EQ(ERR_IO_PENDING, stream->Init(init_callback.callback()));
- EXPECT_EQ(OK, init_callback.WaitForResult());
+ EXPECT_THAT(stream->Init(init_callback.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(init_callback.WaitForResult(), IsOk());
scoped_refptr<IOBuffer> buf = new IOBuffer(kTestBufferSize);
@@ -526,24 +539,25 @@ void ElementsUploadDataStreamTest::FileChangedHelper(
// Don't use element_readers_ here, as this function is called twice, and
// reusing element_readers_ is wrong.
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(base::WrapUnique(new UploadFileElementReader(
- base::ThreadTaskRunnerHandle::Get().get(), file_path, 1, 2, time)));
+ element_readers.push_back(base::MakeUnique<UploadFileElementReader>(
+ base::ThreadTaskRunnerHandle::Get().get(), file_path, 1, 2, time));
TestCompletionCallback init_callback;
std::unique_ptr<UploadDataStream> stream(
new ElementsUploadDataStream(std::move(element_readers), 0));
- ASSERT_EQ(ERR_IO_PENDING, stream->Init(init_callback.callback()));
+ ASSERT_THAT(stream->Init(init_callback.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
int error_code = init_callback.WaitForResult();
if (error_expected)
- ASSERT_EQ(ERR_UPLOAD_FILE_CHANGED, error_code);
+ ASSERT_THAT(error_code, IsError(ERR_UPLOAD_FILE_CHANGED));
else
- ASSERT_EQ(OK, error_code);
+ ASSERT_THAT(error_code, IsOk());
}
TEST_F(ElementsUploadDataStreamTest, FileChanged) {
base::FilePath temp_file_path;
- ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(),
- &temp_file_path));
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &temp_file_path));
ASSERT_EQ(static_cast<int>(kTestDataSize),
base::WriteFile(temp_file_path, kTestData, kTestDataSize));
@@ -561,17 +575,17 @@ TEST_F(ElementsUploadDataStreamTest, FileChanged) {
TEST_F(ElementsUploadDataStreamTest, MultipleInit) {
base::FilePath temp_file_path;
- ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(),
- &temp_file_path));
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &temp_file_path));
ASSERT_EQ(static_cast<int>(kTestDataSize),
base::WriteFile(temp_file_path, kTestData, kTestDataSize));
// Prepare data.
element_readers_.push_back(
- base::WrapUnique(new UploadBytesElementReader(kTestData, kTestDataSize)));
- element_readers_.push_back(base::WrapUnique(new UploadFileElementReader(
+ base::MakeUnique<UploadBytesElementReader>(kTestData, kTestDataSize));
+ element_readers_.push_back(base::MakeUnique<UploadFileElementReader>(
base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
- std::numeric_limits<uint64_t>::max(), base::Time())));
+ std::numeric_limits<uint64_t>::max(), base::Time()));
std::unique_ptr<UploadDataStream> stream(
new ElementsUploadDataStream(std::move(element_readers_), 0));
@@ -580,8 +594,9 @@ TEST_F(ElementsUploadDataStreamTest, MultipleInit) {
// Call Init().
TestCompletionCallback init_callback1;
- ASSERT_EQ(ERR_IO_PENDING, stream->Init(init_callback1.callback()));
- ASSERT_EQ(OK, init_callback1.WaitForResult());
+ ASSERT_THAT(stream->Init(init_callback1.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ ASSERT_THAT(init_callback1.WaitForResult(), IsOk());
EXPECT_FALSE(stream->IsEOF());
EXPECT_EQ(kTestDataSize*2, stream->size());
@@ -591,8 +606,9 @@ TEST_F(ElementsUploadDataStreamTest, MultipleInit) {
// Call Init() again to reset.
TestCompletionCallback init_callback2;
- ASSERT_EQ(ERR_IO_PENDING, stream->Init(init_callback2.callback()));
- ASSERT_EQ(OK, init_callback2.WaitForResult());
+ ASSERT_THAT(stream->Init(init_callback2.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ ASSERT_THAT(init_callback2.WaitForResult(), IsOk());
EXPECT_FALSE(stream->IsEOF());
EXPECT_EQ(kTestDataSize*2, stream->size());
@@ -603,18 +619,18 @@ TEST_F(ElementsUploadDataStreamTest, MultipleInit) {
TEST_F(ElementsUploadDataStreamTest, MultipleInitAsync) {
base::FilePath temp_file_path;
- ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(),
- &temp_file_path));
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &temp_file_path));
ASSERT_EQ(static_cast<int>(kTestDataSize),
base::WriteFile(temp_file_path, kTestData, kTestDataSize));
TestCompletionCallback test_callback;
// Prepare data.
element_readers_.push_back(
- base::WrapUnique(new UploadBytesElementReader(kTestData, kTestDataSize)));
- element_readers_.push_back(base::WrapUnique(new UploadFileElementReader(
+ base::MakeUnique<UploadBytesElementReader>(kTestData, kTestDataSize));
+ element_readers_.push_back(base::MakeUnique<UploadFileElementReader>(
base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
- std::numeric_limits<uint64_t>::max(), base::Time())));
+ std::numeric_limits<uint64_t>::max(), base::Time()));
std::unique_ptr<UploadDataStream> stream(
new ElementsUploadDataStream(std::move(element_readers_), 0));
@@ -622,8 +638,9 @@ TEST_F(ElementsUploadDataStreamTest, MultipleInitAsync) {
expected_data += expected_data;
// Call Init().
- ASSERT_EQ(ERR_IO_PENDING, stream->Init(test_callback.callback()));
- EXPECT_EQ(OK, test_callback.WaitForResult());
+ ASSERT_THAT(stream->Init(test_callback.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(test_callback.WaitForResult(), IsOk());
EXPECT_FALSE(stream->IsEOF());
EXPECT_EQ(kTestDataSize*2, stream->size());
@@ -632,8 +649,9 @@ TEST_F(ElementsUploadDataStreamTest, MultipleInitAsync) {
EXPECT_TRUE(stream->IsEOF());
// Call Init() again to reset.
- ASSERT_EQ(ERR_IO_PENDING, stream->Init(test_callback.callback()));
- EXPECT_EQ(OK, test_callback.WaitForResult());
+ ASSERT_THAT(stream->Init(test_callback.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(test_callback.WaitForResult(), IsOk());
EXPECT_FALSE(stream->IsEOF());
EXPECT_EQ(kTestDataSize*2, stream->size());
@@ -644,17 +662,17 @@ TEST_F(ElementsUploadDataStreamTest, MultipleInitAsync) {
TEST_F(ElementsUploadDataStreamTest, InitToReset) {
base::FilePath temp_file_path;
- ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(),
- &temp_file_path));
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &temp_file_path));
ASSERT_EQ(static_cast<int>(kTestDataSize),
base::WriteFile(temp_file_path, kTestData, kTestDataSize));
// Prepare data.
element_readers_.push_back(
- base::WrapUnique(new UploadBytesElementReader(kTestData, kTestDataSize)));
- element_readers_.push_back(base::WrapUnique(new UploadFileElementReader(
+ base::MakeUnique<UploadBytesElementReader>(kTestData, kTestDataSize));
+ element_readers_.push_back(base::MakeUnique<UploadFileElementReader>(
base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
- std::numeric_limits<uint64_t>::max(), base::Time())));
+ std::numeric_limits<uint64_t>::max(), base::Time()));
std::unique_ptr<UploadDataStream> stream(
new ElementsUploadDataStream(std::move(element_readers_), 0));
@@ -664,8 +682,9 @@ TEST_F(ElementsUploadDataStreamTest, InitToReset) {
// Call Init().
TestCompletionCallback init_callback1;
- ASSERT_EQ(ERR_IO_PENDING, stream->Init(init_callback1.callback()));
- EXPECT_EQ(OK, init_callback1.WaitForResult());
+ ASSERT_THAT(stream->Init(init_callback1.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(init_callback1.WaitForResult(), IsOk());
EXPECT_FALSE(stream->IsEOF());
EXPECT_EQ(kTestDataSize*2, stream->size());
@@ -682,8 +701,9 @@ TEST_F(ElementsUploadDataStreamTest, InitToReset) {
// Call Init to reset the state.
TestCompletionCallback init_callback2;
- ASSERT_EQ(ERR_IO_PENDING, stream->Init(init_callback2.callback()));
- EXPECT_EQ(OK, init_callback2.WaitForResult());
+ ASSERT_THAT(stream->Init(init_callback2.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(init_callback2.WaitForResult(), IsOk());
EXPECT_FALSE(stream->IsEOF());
EXPECT_EQ(kTestDataSize*2, stream->size());
@@ -700,17 +720,17 @@ TEST_F(ElementsUploadDataStreamTest, InitToReset) {
TEST_F(ElementsUploadDataStreamTest, InitDuringAsyncInit) {
base::FilePath temp_file_path;
- ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(),
- &temp_file_path));
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &temp_file_path));
ASSERT_EQ(static_cast<int>(kTestDataSize),
base::WriteFile(temp_file_path, kTestData, kTestDataSize));
// Prepare data.
element_readers_.push_back(
- base::WrapUnique(new UploadBytesElementReader(kTestData, kTestDataSize)));
- element_readers_.push_back(base::WrapUnique(new UploadFileElementReader(
+ base::MakeUnique<UploadBytesElementReader>(kTestData, kTestDataSize));
+ element_readers_.push_back(base::MakeUnique<UploadFileElementReader>(
base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
- std::numeric_limits<uint64_t>::max(), base::Time())));
+ std::numeric_limits<uint64_t>::max(), base::Time()));
std::unique_ptr<UploadDataStream> stream(
new ElementsUploadDataStream(std::move(element_readers_), 0));
@@ -720,12 +740,14 @@ TEST_F(ElementsUploadDataStreamTest, InitDuringAsyncInit) {
// Start Init.
TestCompletionCallback init_callback1;
- EXPECT_EQ(ERR_IO_PENDING, stream->Init(init_callback1.callback()));
+ EXPECT_THAT(stream->Init(init_callback1.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
// Call Init again to cancel the previous init.
TestCompletionCallback init_callback2;
- EXPECT_EQ(ERR_IO_PENDING, stream->Init(init_callback2.callback()));
- EXPECT_EQ(OK, init_callback2.WaitForResult());
+ EXPECT_THAT(stream->Init(init_callback2.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(init_callback2.WaitForResult(), IsOk());
EXPECT_FALSE(stream->IsEOF());
EXPECT_EQ(kTestDataSize*2, stream->size());
@@ -746,17 +768,17 @@ TEST_F(ElementsUploadDataStreamTest, InitDuringAsyncInit) {
TEST_F(ElementsUploadDataStreamTest, InitDuringAsyncRead) {
base::FilePath temp_file_path;
- ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(),
- &temp_file_path));
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &temp_file_path));
ASSERT_EQ(static_cast<int>(kTestDataSize),
base::WriteFile(temp_file_path, kTestData, kTestDataSize));
// Prepare data.
element_readers_.push_back(
- base::WrapUnique(new UploadBytesElementReader(kTestData, kTestDataSize)));
- element_readers_.push_back(base::WrapUnique(new UploadFileElementReader(
+ base::MakeUnique<UploadBytesElementReader>(kTestData, kTestDataSize));
+ element_readers_.push_back(base::MakeUnique<UploadFileElementReader>(
base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
- std::numeric_limits<uint64_t>::max(), base::Time())));
+ std::numeric_limits<uint64_t>::max(), base::Time()));
std::unique_ptr<UploadDataStream> stream(
new ElementsUploadDataStream(std::move(element_readers_), 0));
@@ -766,8 +788,9 @@ TEST_F(ElementsUploadDataStreamTest, InitDuringAsyncRead) {
// Call Init().
TestCompletionCallback init_callback1;
- ASSERT_EQ(ERR_IO_PENDING, stream->Init(init_callback1.callback()));
- EXPECT_EQ(OK, init_callback1.WaitForResult());
+ ASSERT_THAT(stream->Init(init_callback1.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(init_callback1.WaitForResult(), IsOk());
EXPECT_FALSE(stream->IsEOF());
EXPECT_EQ(kTestDataSize*2, stream->size());
@@ -782,8 +805,9 @@ TEST_F(ElementsUploadDataStreamTest, InitDuringAsyncRead) {
// Call Init to cancel the previous read.
TestCompletionCallback init_callback2;
- EXPECT_EQ(ERR_IO_PENDING, stream->Init(init_callback2.callback()));
- EXPECT_EQ(OK, init_callback2.WaitForResult());
+ EXPECT_THAT(stream->Init(init_callback2.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(init_callback2.WaitForResult(), IsOk());
EXPECT_FALSE(stream->IsEOF());
EXPECT_EQ(kTestDataSize*2, stream->size());
diff --git a/chromium/net/base/expiring_cache_unittest.cc b/chromium/net/base/expiring_cache_unittest.cc
index 74b069dd8d8..f1414f90656 100644
--- a/chromium/net/base/expiring_cache_unittest.cc
+++ b/chromium/net/base/expiring_cache_unittest.cc
@@ -119,16 +119,16 @@ TEST(ExpiringCacheTest, Compact) {
}
EXPECT_EQ(10U, cache.size());
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid0"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid1"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid2"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid3"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid4"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "expired0"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "expired1"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "expired2"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "negative0"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "negative1"));
+ EXPECT_TRUE(base::ContainsKey(cache.entries_, "valid0"));
+ EXPECT_TRUE(base::ContainsKey(cache.entries_, "valid1"));
+ EXPECT_TRUE(base::ContainsKey(cache.entries_, "valid2"));
+ EXPECT_TRUE(base::ContainsKey(cache.entries_, "valid3"));
+ EXPECT_TRUE(base::ContainsKey(cache.entries_, "valid4"));
+ EXPECT_TRUE(base::ContainsKey(cache.entries_, "expired0"));
+ EXPECT_TRUE(base::ContainsKey(cache.entries_, "expired1"));
+ EXPECT_TRUE(base::ContainsKey(cache.entries_, "expired2"));
+ EXPECT_TRUE(base::ContainsKey(cache.entries_, "negative0"));
+ EXPECT_TRUE(base::ContainsKey(cache.entries_, "negative1"));
// Shrink the new max constraints bound and compact. The "negative" and
// "expired" entries should be dropped.
@@ -136,16 +136,16 @@ TEST(ExpiringCacheTest, Compact) {
cache.Compact(now);
EXPECT_EQ(5U, cache.size());
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid0"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid1"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid2"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid3"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid4"));
- EXPECT_FALSE(ContainsKey(cache.entries_, "expired0"));
- EXPECT_FALSE(ContainsKey(cache.entries_, "expired1"));
- EXPECT_FALSE(ContainsKey(cache.entries_, "expired2"));
- EXPECT_FALSE(ContainsKey(cache.entries_, "negative0"));
- EXPECT_FALSE(ContainsKey(cache.entries_, "negative1"));
+ EXPECT_TRUE(base::ContainsKey(cache.entries_, "valid0"));
+ EXPECT_TRUE(base::ContainsKey(cache.entries_, "valid1"));
+ EXPECT_TRUE(base::ContainsKey(cache.entries_, "valid2"));
+ EXPECT_TRUE(base::ContainsKey(cache.entries_, "valid3"));
+ EXPECT_TRUE(base::ContainsKey(cache.entries_, "valid4"));
+ EXPECT_FALSE(base::ContainsKey(cache.entries_, "expired0"));
+ EXPECT_FALSE(base::ContainsKey(cache.entries_, "expired1"));
+ EXPECT_FALSE(base::ContainsKey(cache.entries_, "expired2"));
+ EXPECT_FALSE(base::ContainsKey(cache.entries_, "negative0"));
+ EXPECT_FALSE(base::ContainsKey(cache.entries_, "negative1"));
// Shrink further -- this time the compact will start dropping valid entries
// to make space.
diff --git a/chromium/net/base/file_stream_context.cc b/chromium/net/base/file_stream_context.cc
index 7da28a99f2e..f059be71057 100644
--- a/chromium/net/base/file_stream_context.cc
+++ b/chromium/net/base/file_stream_context.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/debug/alias.h"
#include "base/files/file_path.h"
#include "base/location.h"
#include "base/profiler/scoped_tracker.h"
@@ -83,7 +84,7 @@ void FileStream::Context::Orphan() {
void FileStream::Context::Open(const base::FilePath& path,
int open_flags,
const CompletionCallback& callback) {
- DCHECK(!async_in_progress_);
+ CheckNoAsyncInProgress();
bool posted = base::PostTaskAndReplyWithResult(
task_runner_.get(),
@@ -93,11 +94,12 @@ void FileStream::Context::Open(const base::FilePath& path,
base::Bind(&Context::OnOpenCompleted, base::Unretained(this), callback));
DCHECK(posted);
+ last_operation_ = OPEN;
async_in_progress_ = true;
}
void FileStream::Context::Close(const CompletionCallback& callback) {
- DCHECK(!async_in_progress_);
+ CheckNoAsyncInProgress();
bool posted = base::PostTaskAndReplyWithResult(
task_runner_.get(),
FROM_HERE,
@@ -107,12 +109,13 @@ void FileStream::Context::Close(const CompletionCallback& callback) {
IntToInt64(callback)));
DCHECK(posted);
+ last_operation_ = CLOSE;
async_in_progress_ = true;
}
void FileStream::Context::Seek(int64_t offset,
const Int64CompletionCallback& callback) {
- DCHECK(!async_in_progress_);
+ CheckNoAsyncInProgress();
bool posted = base::PostTaskAndReplyWithResult(
task_runner_.get(), FROM_HERE,
@@ -120,11 +123,12 @@ void FileStream::Context::Seek(int64_t offset,
base::Bind(&Context::OnAsyncCompleted, base::Unretained(this), callback));
DCHECK(posted);
+ last_operation_ = SEEK;
async_in_progress_ = true;
}
void FileStream::Context::Flush(const CompletionCallback& callback) {
- DCHECK(!async_in_progress_);
+ CheckNoAsyncInProgress();
bool posted = base::PostTaskAndReplyWithResult(
task_runner_.get(),
@@ -135,6 +139,7 @@ void FileStream::Context::Flush(const CompletionCallback& callback) {
IntToInt64(callback)));
DCHECK(posted);
+ last_operation_ = FLUSH;
async_in_progress_ = true;
}
@@ -142,6 +147,16 @@ bool FileStream::Context::IsOpen() const {
return file_.IsValid();
}
+void FileStream::Context::CheckNoAsyncInProgress() const {
+ if (!async_in_progress_)
+ return;
+ LastOperation state = last_operation_;
+ base::debug::Alias(&state);
+ // TODO(xunjieli): Once https://crbug.com/487732 is fixed, use
+ // DCHECK(!async_in_progress_) directly at call places.
+ CHECK(!async_in_progress_);
+}
+
FileStream::Context::OpenResult FileStream::Context::OpenFileImpl(
const base::FilePath& path, int open_flags) {
#if defined(OS_POSIX)
@@ -200,13 +215,12 @@ void FileStream::Context::CloseAndDelete() {
// TODO(ananta)
// Replace this CHECK with a DCHECK once we figure out the root cause of
// http://crbug.com/455066
- CHECK(!async_in_progress_);
+ CheckNoAsyncInProgress();
if (file_.IsValid()) {
bool posted = task_runner_.get()->PostTask(
- FROM_HERE,
- base::Bind(base::IgnoreResult(&Context::CloseFileImpl),
- base::Owned(this)));
+ FROM_HERE, base::Bind(base::IgnoreResult(&Context::CloseFileImpl),
+ base::Owned(this)));
DCHECK(posted);
} else {
delete this;
@@ -229,6 +243,7 @@ void FileStream::Context::OnAsyncCompleted(
// should be reset before Close() because it shouldn't run if any async
// operation is in progress.
async_in_progress_ = false;
+ last_operation_ = NONE;
if (orphaned_)
CloseAndDelete();
else
diff --git a/chromium/net/base/file_stream_context.h b/chromium/net/base/file_stream_context.h
index aaff5adbdd8..6b445809741 100644
--- a/chromium/net/base/file_stream_context.h
+++ b/chromium/net/base/file_stream_context.h
@@ -125,6 +125,27 @@ class FileStream::Context {
DISALLOW_COPY_AND_ASSIGN(OpenResult);
};
+ // TODO(xunjieli): Remove after crbug.com/487732 is fixed.
+ enum LastOperation {
+ // FileStream has a pending Open().
+ OPEN,
+ // FileStream has a pending Write().
+ WRITE,
+ // FileStream has a pending Read().
+ READ,
+ // FileStream has a pending Seek().
+ SEEK,
+ // FileStream has a pending Flush().
+ FLUSH,
+ // FileStream has a pending Close().
+ CLOSE,
+ // FileStream doesn't have any pending operation.
+ NONE
+ };
+
+ // TODO(xunjieli): Remove after crbug.com/487732 is fixed.
+ void CheckNoAsyncInProgress() const;
+
////////////////////////////////////////////////////////////////////////////
// Platform-independent methods implemented in file_stream_context.cc.
////////////////////////////////////////////////////////////////////////////
@@ -217,6 +238,10 @@ class FileStream::Context {
base::File file_;
bool async_in_progress_;
+
+ // TODO(xunjieli): Remove after crbug.com/487732 is fixed.
+ LastOperation last_operation_;
+
bool orphaned_;
scoped_refptr<base::TaskRunner> task_runner_;
diff --git a/chromium/net/base/file_stream_context_posix.cc b/chromium/net/base/file_stream_context_posix.cc
index af98c7825fe..67c772a0c68 100644
--- a/chromium/net/base/file_stream_context_posix.cc
+++ b/chromium/net/base/file_stream_context_posix.cc
@@ -32,6 +32,7 @@ FileStream::Context::Context(base::File file,
const scoped_refptr<base::TaskRunner>& task_runner)
: file_(std::move(file)),
async_in_progress_(false),
+ last_operation_(NONE),
orphaned_(false),
task_runner_(task_runner) {}
@@ -41,7 +42,7 @@ FileStream::Context::~Context() {
int FileStream::Context::Read(IOBuffer* in_buf,
int buf_len,
const CompletionCallback& callback) {
- DCHECK(!async_in_progress_);
+ CheckNoAsyncInProgress();
scoped_refptr<IOBuffer> buf = in_buf;
const bool posted = base::PostTaskAndReplyWithResult(
@@ -54,13 +55,14 @@ int FileStream::Context::Read(IOBuffer* in_buf,
DCHECK(posted);
async_in_progress_ = true;
+ last_operation_ = READ;
return ERR_IO_PENDING;
}
int FileStream::Context::Write(IOBuffer* in_buf,
int buf_len,
const CompletionCallback& callback) {
- DCHECK(!async_in_progress_);
+ CheckNoAsyncInProgress();
scoped_refptr<IOBuffer> buf = in_buf;
const bool posted = base::PostTaskAndReplyWithResult(
@@ -73,6 +75,7 @@ int FileStream::Context::Write(IOBuffer* in_buf,
DCHECK(posted);
async_in_progress_ = true;
+ last_operation_ = WRITE;
return ERR_IO_PENDING;
}
diff --git a/chromium/net/base/file_stream_context_win.cc b/chromium/net/base/file_stream_context_win.cc
index 5028f195993..4e417dc02f5 100644
--- a/chromium/net/base/file_stream_context_win.cc
+++ b/chromium/net/base/file_stream_context_win.cc
@@ -38,6 +38,7 @@ void IncrementOffset(OVERLAPPED* overlapped, DWORD count) {
FileStream::Context::Context(const scoped_refptr<base::TaskRunner>& task_runner)
: async_in_progress_(false),
+ last_operation_(NONE),
orphaned_(false),
task_runner_(task_runner),
async_read_initiated_(false),
@@ -49,6 +50,7 @@ FileStream::Context::Context(base::File file,
const scoped_refptr<base::TaskRunner>& task_runner)
: file_(std::move(file)),
async_in_progress_(false),
+ last_operation_(NONE),
orphaned_(false),
task_runner_(task_runner),
async_read_initiated_(false),
@@ -67,11 +69,13 @@ FileStream::Context::~Context() {
int FileStream::Context::Read(IOBuffer* buf,
int buf_len,
const CompletionCallback& callback) {
- CHECK(!async_in_progress_);
+ CheckNoAsyncInProgress();
+
DCHECK(!async_read_initiated_);
DCHECK(!async_read_completed_);
DCHECK(!io_complete_for_read_received_);
+ last_operation_ = READ;
IOCompletionIsPending(callback, buf);
async_read_initiated_ = true;
@@ -88,8 +92,9 @@ int FileStream::Context::Read(IOBuffer* buf,
int FileStream::Context::Write(IOBuffer* buf,
int buf_len,
const CompletionCallback& callback) {
- CHECK(!async_in_progress_);
+ CheckNoAsyncInProgress();
+ last_operation_ = WRITE;
result_ = 0;
DWORD bytes_written = 0;
@@ -137,8 +142,10 @@ void FileStream::Context::OnIOCompleted(
DCHECK(!callback_.is_null());
DCHECK(async_in_progress_);
- if (!async_read_initiated_)
+ if (!async_read_initiated_) {
+ last_operation_ = NONE;
async_in_progress_ = false;
+ }
if (orphaned_) {
io_complete_for_read_received_ = true;
@@ -178,6 +185,7 @@ void FileStream::Context::InvokeUserCallback() {
async_read_initiated_ = false;
io_complete_for_read_received_ = false;
async_read_completed_ = false;
+ last_operation_ = NONE;
async_in_progress_ = false;
}
CompletionCallback temp_callback = callback_;
@@ -188,6 +196,7 @@ void FileStream::Context::InvokeUserCallback() {
}
void FileStream::Context::DeleteOrphanedContext() {
+ last_operation_ = NONE;
async_in_progress_ = false;
callback_.Reset();
in_flight_buf_ = NULL;
diff --git a/chromium/net/base/file_stream_unittest.cc b/chromium/net/base/file_stream_unittest.cc
index 6a41d4e7d1c..8b2e43c6655 100644
--- a/chromium/net/base/file_stream_unittest.cc
+++ b/chromium/net/base/file_stream_unittest.cc
@@ -16,17 +16,22 @@
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/synchronization/waitable_event.h"
-#include "base/test/sequenced_worker_pool_owner.h"
#include "base/test/test_timeouts.h"
+#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/log/test_net_log.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsError;
+using net::test::IsOk;
+
#if defined(OS_ANDROID)
#include "base/test/test_file_util.h"
#endif
@@ -79,11 +84,11 @@ TEST_F(FileStreamTest, OpenExplicitClose) {
base::File::FLAG_READ |
base::File::FLAG_ASYNC;
int rv = stream.Open(temp_file_path(), flags, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(stream.IsOpen());
- EXPECT_EQ(ERR_IO_PENDING, stream.Close(callback.callback()));
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(stream.Close(callback.callback()), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_FALSE(stream.IsOpen());
}
@@ -94,10 +99,10 @@ TEST_F(FileStreamTest, OpenExplicitCloseOrphaned) {
int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
base::File::FLAG_ASYNC;
int rv = stream->Open(temp_file_path(), flags, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(stream->IsOpen());
- EXPECT_EQ(ERR_IO_PENDING, stream->Close(callback.callback()));
+ EXPECT_THAT(stream->Close(callback.callback()), IsError(ERR_IO_PENDING));
stream.reset();
// File isn't actually closed yet.
base::RunLoop runloop;
@@ -120,7 +125,8 @@ TEST_F(FileStreamTest, UseFileHandle) {
// Seek to the beginning of the file and read.
std::unique_ptr<FileStream> read_stream(
new FileStream(std::move(file), base::ThreadTaskRunnerHandle::Get()));
- ASSERT_EQ(ERR_IO_PENDING, read_stream->Seek(0, callback64.callback()));
+ ASSERT_THAT(read_stream->Seek(0, callback64.callback()),
+ IsError(ERR_IO_PENDING));
ASSERT_EQ(0, callback64.WaitForResult());
// Read into buffer and compare.
scoped_refptr<IOBufferWithSize> read_buffer =
@@ -138,7 +144,8 @@ TEST_F(FileStreamTest, UseFileHandle) {
std::unique_ptr<FileStream> write_stream(
new FileStream(std::move(file), base::ThreadTaskRunnerHandle::Get()));
- ASSERT_EQ(ERR_IO_PENDING, write_stream->Seek(0, callback64.callback()));
+ ASSERT_THAT(write_stream->Seek(0, callback64.callback()),
+ IsError(ERR_IO_PENDING));
ASSERT_EQ(0, callback64.WaitForResult());
scoped_refptr<IOBufferWithSize> write_buffer = CreateTestDataBuffer();
rv = write_stream->Write(write_buffer.get(), kTestDataSize,
@@ -164,12 +171,12 @@ TEST_F(FileStreamTest, UseClosedStream) {
// Try seeking...
rv = stream.Seek(5, callback64.callback());
- EXPECT_EQ(ERR_UNEXPECTED, callback64.GetResult(rv));
+ EXPECT_THAT(callback64.GetResult(rv), IsError(ERR_UNEXPECTED));
// Try reading...
scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(10);
rv = stream.Read(buf.get(), buf->size(), callback.callback());
- EXPECT_EQ(ERR_UNEXPECTED, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsError(ERR_UNEXPECTED));
}
TEST_F(FileStreamTest, Read) {
@@ -181,7 +188,7 @@ TEST_F(FileStreamTest, Read) {
base::File::FLAG_ASYNC;
TestCompletionCallback callback;
int rv = stream.Open(temp_file_path(), flags, callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
int total_bytes_read = 0;
@@ -210,14 +217,14 @@ TEST_F(FileStreamTest, Read_EarlyDelete) {
base::File::FLAG_ASYNC;
TestCompletionCallback callback;
int rv = stream->Open(temp_file_path(), flags, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4);
rv = stream->Read(buf.get(), buf->size(), callback.callback());
stream.reset(); // Delete instead of closing it.
if (rv < 0) {
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// The callback should not be called if the request is cancelled.
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(callback.have_result());
@@ -235,13 +242,13 @@ TEST_F(FileStreamTest, Read_FromOffset) {
base::File::FLAG_ASYNC;
TestCompletionCallback callback;
int rv = stream.Open(temp_file_path(), flags, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
TestInt64CompletionCallback callback64;
const int64_t kOffset = 3;
rv = stream.Seek(kOffset, callback64.callback());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
int64_t new_offset = callback64.WaitForResult();
EXPECT_EQ(kOffset, new_offset);
@@ -269,7 +276,7 @@ TEST_F(FileStreamTest, Write) {
base::File::FLAG_ASYNC;
TestCompletionCallback callback;
int rv = stream.Open(temp_file_path(), flags, callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
int64_t file_size;
EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
@@ -295,8 +302,8 @@ TEST_F(FileStreamTest, Write_EarlyDelete) {
base::File::FLAG_ASYNC;
TestCompletionCallback callback;
int rv = stream->Open(temp_file_path(), flags, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
int64_t file_size;
EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
@@ -306,7 +313,7 @@ TEST_F(FileStreamTest, Write_EarlyDelete) {
rv = stream->Write(buf.get(), buf->size(), callback.callback());
stream.reset();
if (rv < 0) {
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// The callback should not be called if the request is cancelled.
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(callback.have_result());
@@ -325,13 +332,13 @@ TEST_F(FileStreamTest, Write_FromOffset) {
base::File::FLAG_ASYNC;
TestCompletionCallback callback;
int rv = stream.Open(temp_file_path(), flags, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
TestInt64CompletionCallback callback64;
const int64_t kOffset = kTestDataSize;
rv = stream.Seek(kOffset, callback64.callback());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
int64_t new_offset = callback64.WaitForResult();
EXPECT_EQ(kTestDataSize, new_offset);
@@ -365,8 +372,8 @@ TEST_F(FileStreamTest, BasicReadWrite) {
base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
TestCompletionCallback callback;
int rv = stream->Open(temp_file_path(), flags, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
int64_t total_bytes_read = 0;
@@ -418,12 +425,12 @@ TEST_F(FileStreamTest, BasicWriteRead) {
base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
TestCompletionCallback callback;
int rv = stream->Open(temp_file_path(), flags, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
TestInt64CompletionCallback callback64;
rv = stream->Seek(file_size, callback64.callback());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
int64_t offset = callback64.WaitForResult();
EXPECT_EQ(offset, file_size);
@@ -447,7 +454,7 @@ TEST_F(FileStreamTest, BasicWriteRead) {
EXPECT_EQ(kTestDataSize, total_bytes_written);
rv = stream->Seek(0, callback64.callback());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
offset = callback64.WaitForResult();
EXPECT_EQ(0, offset);
@@ -549,7 +556,8 @@ class TestWriteReadCompletionCallback {
*data_read_ += data_read;
} else { // We're done writing all data. Start reading the data.
TestInt64CompletionCallback callback64;
- EXPECT_EQ(ERR_IO_PENDING, stream_->Seek(0, callback64.callback()));
+ EXPECT_THAT(stream_->Seek(0, callback64.callback()),
+ IsError(ERR_IO_PENDING));
{
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
@@ -587,11 +595,12 @@ TEST_F(FileStreamTest, WriteRead) {
base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
TestCompletionCallback open_callback;
int rv = stream->Open(temp_file_path(), flags, open_callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, open_callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(open_callback.WaitForResult(), IsOk());
TestInt64CompletionCallback callback64;
- EXPECT_EQ(ERR_IO_PENDING, stream->Seek(file_size, callback64.callback()));
+ EXPECT_THAT(stream->Seek(file_size, callback64.callback()),
+ IsError(ERR_IO_PENDING));
EXPECT_EQ(file_size, callback64.WaitForResult());
int total_bytes_written = 0;
@@ -693,11 +702,12 @@ TEST_F(FileStreamTest, WriteClose) {
base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
TestCompletionCallback open_callback;
int rv = stream->Open(temp_file_path(), flags, open_callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, open_callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(open_callback.WaitForResult(), IsOk());
TestInt64CompletionCallback callback64;
- EXPECT_EQ(ERR_IO_PENDING, stream->Seek(file_size, callback64.callback()));
+ EXPECT_THAT(stream->Seek(file_size, callback64.callback()),
+ IsError(ERR_IO_PENDING));
EXPECT_EQ(file_size, callback64.WaitForResult());
int total_bytes_written = 0;
@@ -717,25 +727,28 @@ TEST_F(FileStreamTest, WriteClose) {
}
TEST_F(FileStreamTest, OpenAndDelete) {
- base::SequencedWorkerPoolOwner pool_owner(1, "StreamTest");
+ base::Thread worker_thread("StreamTest");
+ ASSERT_TRUE(worker_thread.Start());
bool prev = base::ThreadRestrictions::SetIOAllowed(false);
- std::unique_ptr<FileStream> stream(new FileStream(pool_owner.pool()));
+ std::unique_ptr<FileStream> stream(
+ new FileStream(worker_thread.task_runner()));
int flags = base::File::FLAG_OPEN | base::File::FLAG_WRITE |
base::File::FLAG_ASYNC;
TestCompletionCallback open_callback;
int rv = stream->Open(temp_file_path(), flags, open_callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Delete the stream without waiting for the open operation to be
// complete. Should be safe.
stream.reset();
- // Force an operation through the pool.
- std::unique_ptr<FileStream> stream2(new FileStream(pool_owner.pool()));
+ // Force an operation through the worker.
+ std::unique_ptr<FileStream> stream2(
+ new FileStream(worker_thread.task_runner()));
TestCompletionCallback open_callback2;
rv = stream2->Open(temp_file_path(), flags, open_callback2.callback());
- EXPECT_EQ(OK, open_callback2.GetResult(rv));
+ EXPECT_THAT(open_callback2.GetResult(rv), IsOk());
stream2.reset();
// open_callback won't be called.
@@ -816,8 +829,8 @@ TEST_F(FileStreamTest, ContentUriRead) {
base::File::FLAG_ASYNC;
TestCompletionCallback callback;
int rv = stream.Open(path, flags, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
int total_bytes_read = 0;
diff --git a/chromium/net/base/filename_util.cc b/chromium/net/base/filename_util.cc
index 153ce43d024..1e1d51c0e24 100644
--- a/chromium/net/base/filename_util.cc
+++ b/chromium/net/base/filename_util.cc
@@ -174,8 +174,10 @@ bool IsReservedNameOnWindows(const base::FilePath::StringType& filename) {
if (filename_lower == known_devices[i])
return true;
// Starts with "DEVICE.".
- if (filename_lower.find(std::string(known_devices[i]) + ".") == 0)
+ if (base::StartsWith(filename_lower, std::string(known_devices[i]) + ".",
+ base::CompareCase::SENSITIVE)) {
return true;
+ }
}
static const char* const magic_names[] = {
diff --git a/chromium/net/base/filename_util_internal.cc b/chromium/net/base/filename_util_internal.cc
index 6eb3f55ed44..fa0a91f620b 100644
--- a/chromium/net/base/filename_util_internal.cc
+++ b/chromium/net/base/filename_util_internal.cc
@@ -54,7 +54,7 @@ base::FilePath::StringType GetCorrectedExtensionUnsafe(
// "foo.jpg" to "foo.jpeg".
std::vector<base::FilePath::StringType> all_mime_extensions;
GetExtensionsForMimeType(mime_type, &all_mime_extensions);
- if (ContainsValue(all_mime_extensions, extension))
+ if (base::ContainsValue(all_mime_extensions, extension))
return extension;
// Get the "final" extension. In most cases, this is the same as the
@@ -68,7 +68,7 @@ base::FilePath::StringType GetCorrectedExtensionUnsafe(
// If there's a double extension, and the second extension is in the
// list of valid extensions for the given type, keep the double extension.
// This avoids renaming things like "foo.tar.gz" to "foo.gz".
- if (ContainsValue(all_mime_extensions, final_extension))
+ if (base::ContainsValue(all_mime_extensions, final_extension))
return extension;
return preferred_mime_extension;
}
diff --git a/chromium/net/base/fuzzed_data_provider.cc b/chromium/net/base/fuzzed_data_provider.cc
deleted file mode 100644
index b947837dc95..00000000000
--- a/chromium/net/base/fuzzed_data_provider.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/base/fuzzed_data_provider.h"
-
-#include <algorithm>
-#include <limits>
-
-#include "base/logging.h"
-
-namespace net {
-
-FuzzedDataProvider::FuzzedDataProvider(const uint8_t* data, size_t size)
- : remaining_data_(reinterpret_cast<const char*>(data), size) {}
-
-FuzzedDataProvider::~FuzzedDataProvider() {}
-
-base::StringPiece FuzzedDataProvider::ConsumeBytes(size_t num_bytes) {
- num_bytes = std::min(num_bytes, remaining_data_.length());
- base::StringPiece result(remaining_data_.data(), num_bytes);
- remaining_data_ = remaining_data_.substr(num_bytes);
- return result;
-}
-
-base::StringPiece FuzzedDataProvider::ConsumeRemainingBytes() {
- return ConsumeBytes(remaining_data_.length());
-}
-
-uint32_t FuzzedDataProvider::ConsumeUint32InRange(uint32_t min, uint32_t max) {
- CHECK_LE(min, max);
-
- uint32_t range = max - min;
- uint32_t offset = 0;
- uint32_t result = 0;
-
- while ((range >> offset) > 0 && !remaining_data_.empty()) {
- // Pull bytes off the end of the seed data. Experimentally, this seems to
- // allow the fuzzer to more easily explore the input space. This makes
- // sense, since it works by modifying inputs that caused new code to run,
- // and this data is often used to encode length of data read by
- // ConsumeBytes. Separating out read lengths makes it easier modify the
- // contents of the data that is actually read.
- uint8_t next_byte = remaining_data_.back();
- remaining_data_.remove_suffix(1);
- result = (result << 8) | next_byte;
- offset += 8;
- }
-
- // Avoid division by 0, in the case |range + 1| results in overflow.
- if (range == std::numeric_limits<uint32_t>::max())
- return result;
-
- return min + result % (range + 1);
-}
-
-int FuzzedDataProvider::ConsumeInt32InRange(int min, int max) {
- CHECK_LE(min, max);
-
- uint32_t range = max - min;
- return min + ConsumeUint32InRange(0, range);
-}
-
-bool FuzzedDataProvider::ConsumeBool() {
- return (ConsumeUint8() & 0x01) == 0x01;
-}
-
-uint8_t FuzzedDataProvider::ConsumeUint8() {
- return ConsumeUint32InRange(0, 0xFF);
-}
-
-uint16_t FuzzedDataProvider::ConsumeUint16() {
- return ConsumeUint32InRange(0, 0xFFFF);
-}
-
-} // namespace net
diff --git a/chromium/net/base/fuzzed_data_provider.h b/chromium/net/base/fuzzed_data_provider.h
deleted file mode 100644
index 4aa13db6c20..00000000000
--- a/chromium/net/base/fuzzed_data_provider.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_BASE_FUZZED_DATA_PROVIDER_H
-#define NET_BASE_FUZZED_DATA_PROVIDER_H
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-
-namespace net {
-
-// Utility class to break up fuzzer input for multiple consumers. Whenever run
-// on the same input, provides the same output, as long as its methods are
-// called in the same order, with the same arguments.
-class FuzzedDataProvider {
- public:
- // |data| is an array of length |size| that the FuzzedDataProvider wraps to
- // provide more granular access. |data| must outlive the FuzzedDataProvider.
- FuzzedDataProvider(const uint8_t* data, size_t size);
- ~FuzzedDataProvider();
-
- // Returns a StringPiece containing |num_bytes| of input data. If fewer than
- // |num_bytes| of data remain, returns a shorter StringPiece containing all
- // of the data that's left. The data pointed at by the returned StringPiece
- // must not be used after the FuzzedDataProvider is destroyed.
- base::StringPiece ConsumeBytes(size_t num_bytes);
-
- // Returns a StringPiece containing all remaining bytes of the input data.
- // The data pointed at by the returned StringPiece must not be used after the
- // FuzzedDataProvider is destroyed.
- base::StringPiece ConsumeRemainingBytes();
-
- // Returns a number in the range [min, max] by consuming bytes from the input
- // data. The value might not be uniformly distributed in the given range. If
- // there's no input data left, always returns |min|. |min| must be less than
- // or equal to |max|.
- uint32_t ConsumeUint32InRange(uint32_t min, uint32_t max);
- int ConsumeInt32InRange(int min, int max);
-
- // Returns a bool, or false when no data remains.
- bool ConsumeBool();
-
- // Returns a uint8_t from the input or 0 if nothing remains. This is
- // equivalent to ConsumeUint32InRange(0, 0xFF).
- uint8_t ConsumeUint8();
-
- // Returns a uint16_t from the input. If fewer than 2 bytes of data remain
- // will fill the most significant bytes with 0. This is equivalent to
- // ConsumeUint32InRange(0, 0xFFFF).
- uint16_t ConsumeUint16();
-
- // Returns a value from |array|, consuming as many bytes as needed to do so.
- // |array| must be a fixed-size array. Equivalent to
- // array[ConsumeUint32InRange(sizeof(array)-1)];
- template <typename Type, size_t size>
- Type PickValueInArray(Type (&array)[size]) {
- return array[ConsumeUint32InRange(0, size - 1)];
- }
-
- // Reports the remaining bytes available for fuzzed input.
- size_t remaining_bytes() { return remaining_data_.length(); }
-
- private:
- base::StringPiece remaining_data_;
-
- DISALLOW_COPY_AND_ASSIGN(FuzzedDataProvider);
-};
-
-} // namespace net
-
-#endif // NET_BASE_FUZZED_DATA_PROVIDER_H
diff --git a/chromium/net/base/ip_pattern.cc b/chromium/net/base/ip_pattern.cc
index 0a3b0992636..bba6b241bb1 100644
--- a/chromium/net/base/ip_pattern.cc
+++ b/chromium/net/base/ip_pattern.cc
@@ -116,7 +116,7 @@ bool IPPattern::ParsePattern(const std::string& ip_pattern) {
component_values_.push_back(value);
continue;
}
- if (component[component.size() - 1] != ']') {
+ if (component.back() != ']') {
DVLOG(1) << "Missing close bracket: " << ip_pattern;
return false;
}
diff --git a/chromium/net/base/layered_network_delegate.cc b/chromium/net/base/layered_network_delegate.cc
index 24e3e246f48..914e62fdf89 100644
--- a/chromium/net/base/layered_network_delegate.cc
+++ b/chromium/net/base/layered_network_delegate.cc
@@ -104,9 +104,10 @@ void LayeredNetworkDelegate::OnBeforeRedirectInternal(
const GURL& new_location) {
}
-void LayeredNetworkDelegate::OnResponseStarted(URLRequest* request) {
+void LayeredNetworkDelegate::OnResponseStarted(URLRequest* request,
+ int net_error) {
OnResponseStartedInternal(request);
- nested_network_delegate_->NotifyResponseStarted(request);
+ nested_network_delegate_->NotifyResponseStarted(request, net_error);
}
void LayeredNetworkDelegate::OnResponseStartedInternal(URLRequest* request) {
@@ -131,14 +132,15 @@ void LayeredNetworkDelegate::OnNetworkBytesSent(URLRequest* request,
void LayeredNetworkDelegate::OnNetworkBytesSentInternal(URLRequest* request,
int64_t bytes_sent) {}
-void LayeredNetworkDelegate::OnCompleted(URLRequest* request, bool started) {
+void LayeredNetworkDelegate::OnCompleted(URLRequest* request,
+ bool started,
+ int net_error) {
OnCompletedInternal(request, started);
- nested_network_delegate_->NotifyCompleted(request, started);
+ nested_network_delegate_->NotifyCompleted(request, started, net_error);
}
void LayeredNetworkDelegate::OnCompletedInternal(URLRequest* request,
- bool started) {
-}
+ bool started) {}
void LayeredNetworkDelegate::OnURLRequestDestroyed(URLRequest* request) {
OnURLRequestDestroyedInternal(request);
diff --git a/chromium/net/base/layered_network_delegate.h b/chromium/net/base/layered_network_delegate.h
index ba7ecc710f9..7b2454a6877 100644
--- a/chromium/net/base/layered_network_delegate.h
+++ b/chromium/net/base/layered_network_delegate.h
@@ -11,6 +11,7 @@
#include "base/strings/string16.h"
#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
#include "net/base/network_delegate.h"
#include "net/cookies/canonical_cookie.h"
#include "net/proxy/proxy_retry_info.h"
@@ -59,11 +60,12 @@ class NET_EXPORT LayeredNetworkDelegate : public NetworkDelegate {
scoped_refptr<HttpResponseHeaders>* override_response_headers,
GURL* allowed_unsafe_redirect_url) final;
void OnBeforeRedirect(URLRequest* request, const GURL& new_location) final;
- void OnResponseStarted(URLRequest* request) final;
+
+ void OnResponseStarted(URLRequest* request, int net_error) final;
void OnNetworkBytesReceived(URLRequest* request,
int64_t bytes_received) final;
void OnNetworkBytesSent(URLRequest* request, int64_t bytes_sent) final;
- void OnCompleted(URLRequest* request, bool started) final;
+ void OnCompleted(URLRequest* request, bool started, int net_error) final;
void OnURLRequestDestroyed(URLRequest* request) final;
void OnPACScriptError(int line_number, const base::string16& error) final;
AuthRequiredResponse OnAuthRequired(URLRequest* request,
diff --git a/chromium/net/base/layered_network_delegate_unittest.cc b/chromium/net/base/layered_network_delegate_unittest.cc
index 40add36436d..f1d07bc47ac 100644
--- a/chromium/net/base/layered_network_delegate_unittest.cc
+++ b/chromium/net/base/layered_network_delegate_unittest.cc
@@ -80,7 +80,7 @@ class TestNetworkDelegateImpl : public NetworkDelegateImpl {
IncrementAndCompareCounter("on_before_redirect_count");
}
- void OnResponseStarted(URLRequest* request) override {
+ void OnResponseStarted(URLRequest* request, int net_error) override {
IncrementAndCompareCounter("on_response_started_count");
}
@@ -93,7 +93,7 @@ class TestNetworkDelegateImpl : public NetworkDelegateImpl {
IncrementAndCompareCounter("on_network_bytes_sent_count");
}
- void OnCompleted(URLRequest* request, bool started) override {
+ void OnCompleted(URLRequest* request, bool started, int net_error) override {
IncrementAndCompareCounter("on_completed_count");
}
@@ -194,9 +194,9 @@ class TestLayeredNetworkDelegate : public LayeredNetworkDelegate {
OnNetworkBytesSent(request.get(), 42);
EXPECT_EQ(OK, OnHeadersReceived(NULL, completion_callback.callback(),
response_headers.get(), NULL, NULL));
- OnResponseStarted(request.get());
+ OnResponseStarted(request.get(), net::OK);
OnNetworkBytesReceived(request.get(), 42);
- OnCompleted(request.get(), false);
+ OnCompleted(request.get(), false, net::OK);
OnURLRequestDestroyed(request.get());
OnPACScriptError(0, base::string16());
EXPECT_EQ(
diff --git a/chromium/net/base/linked_hash_map.h b/chromium/net/base/linked_hash_map.h
index 306ac52b77a..34fbc0abe6a 100644
--- a/chromium/net/base/linked_hash_map.h
+++ b/chromium/net/base/linked_hash_map.h
@@ -24,6 +24,8 @@
#include "base/logging.h"
#include "base/macros.h"
+namespace net {
+
// This holds a list of pair<Key, Value> items. This list is what gets
// traversed, and it's iterators from this list that we return from
// begin/end/find.
@@ -254,4 +256,6 @@ class linked_hash_map {
DISALLOW_COPY_AND_ASSIGN(linked_hash_map);
};
+} // namespace net
+
#endif // UTIL_GTL_LINKED_HASH_MAP_H_
diff --git a/chromium/net/base/load_flags_list.h b/chromium/net/base/load_flags_list.h
index 28cbcba8db6..1f030eaa788 100644
--- a/chromium/net/base/load_flags_list.h
+++ b/chromium/net/base/load_flags_list.h
@@ -54,10 +54,14 @@ LOAD_FLAG(DO_NOT_SEND_AUTH_DATA, 1 << 10)
// This should only be used for testing (set by HttpNetworkTransaction).
LOAD_FLAG(IGNORE_ALL_CERT_ERRORS, 1 << 11)
+// DO NOT USE THIS FLAG
+// The network stack should not have frame level knowledge. Any pre-connect
+// or pre-resolution requiring that knowledge should be done from the
+// stack embedder.
// Indicate that this is a top level frame, so that we don't assume it is a
// subresource and speculatively pre-connect or pre-resolve when a referring
// page is loaded.
-LOAD_FLAG(MAIN_FRAME, 1 << 12)
+LOAD_FLAG(MAIN_FRAME_DEPRECATED, 1 << 12)
// Indicates that this load was motivated by the rel=prefetch feature,
// and is (in theory) not intended for the current frame.
diff --git a/chromium/net/base/load_timing_info.cc b/chromium/net/base/load_timing_info.cc
index 309e7b33b51..f3301fb2191 100644
--- a/chromium/net/base/load_timing_info.cc
+++ b/chromium/net/base/load_timing_info.cc
@@ -4,7 +4,7 @@
#include "net/base/load_timing_info.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_source.h"
namespace net {
@@ -12,9 +12,8 @@ LoadTimingInfo::ConnectTiming::ConnectTiming() {}
LoadTimingInfo::ConnectTiming::~ConnectTiming() {}
-LoadTimingInfo::LoadTimingInfo() : socket_reused(false),
- socket_log_id(NetLog::Source::kInvalidId) {
-}
+LoadTimingInfo::LoadTimingInfo()
+ : socket_reused(false), socket_log_id(NetLogSource::kInvalidId) {}
LoadTimingInfo::LoadTimingInfo(const LoadTimingInfo& other) = default;
diff --git a/chromium/net/base/load_timing_info.h b/chromium/net/base/load_timing_info.h
index b4654e5cb32..d397e07ea8c 100644
--- a/chromium/net/base/load_timing_info.h
+++ b/chromium/net/base/load_timing_info.h
@@ -77,8 +77,8 @@ struct NET_EXPORT LoadTimingInfo {
base::TimeTicks dns_end;
// The time spent establishing the connection. Connect time includes proxy
- // connect times (Though not proxy_resolve times), DNS lookup times, time
- // spent waiting in certain queues, TCP, and SSL time.
+ // connect times (though not proxy_resolve or DNS lookup times), time spent
+ // waiting in certain queues, TCP, and SSL time.
// TODO(mmenke): For proxies, this includes time spent blocking on higher
// level socket pools. Fix this.
// TODO(mmenke): Retried connections to the same server should apparently
diff --git a/chromium/net/base/logging_network_change_observer.cc b/chromium/net/base/logging_network_change_observer.cc
index 3f690a29d0d..0370d00dc0e 100644
--- a/chromium/net/base/logging_network_change_observer.cc
+++ b/chromium/net/base/logging_network_change_observer.cc
@@ -10,11 +10,30 @@
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
namespace net {
namespace {
+// Returns a human readable integer from a NetworkHandle.
+int HumanReadableNetworkHandle(NetworkChangeNotifier::NetworkHandle network) {
+#if defined(OS_ANDROID)
+ // On Marshmallow, demunge the NetID to undo munging done in java
+ // Network.getNetworkHandle() by shifting away 0xfacade from
+ // http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/net/Network.java#385
+ if (base::android::BuildInfo::GetInstance()->sdk_int() >=
+ base::android::SDK_VERSION_MARSHMALLOW) {
+ return network >> 32;
+ }
+#endif
+ return network;
+}
+
// Return a dictionary of values that provide information about a
// network-specific change. This also includes relevant current state
// like the default network, and the types of active networks.
@@ -22,18 +41,21 @@ std::unique_ptr<base::Value> NetworkSpecificNetLogCallback(
NetworkChangeNotifier::NetworkHandle network,
NetLogCaptureMode capture_mode) {
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetInteger("changed_network_handle", network);
+ dict->SetInteger("changed_network_handle",
+ HumanReadableNetworkHandle(network));
dict->SetString(
"changed_network_type",
NetworkChangeNotifier::ConnectionTypeToString(
NetworkChangeNotifier::GetNetworkConnectionType(network)));
- dict->SetInteger("default_active_network_handle",
- NetworkChangeNotifier::GetDefaultNetwork());
+ dict->SetInteger(
+ "default_active_network_handle",
+ HumanReadableNetworkHandle(NetworkChangeNotifier::GetDefaultNetwork()));
NetworkChangeNotifier::NetworkList networks;
NetworkChangeNotifier::GetConnectedNetworks(&networks);
for (NetworkChangeNotifier::NetworkHandle active_network : networks) {
dict->SetString(
- "current_active_networks." + base::IntToString(active_network),
+ "current_active_networks." +
+ base::IntToString(HumanReadableNetworkHandle(active_network)),
NetworkChangeNotifier::ConnectionTypeToString(
NetworkChangeNotifier::GetNetworkConnectionType(active_network)));
}
@@ -62,7 +84,7 @@ LoggingNetworkChangeObserver::~LoggingNetworkChangeObserver() {
void LoggingNetworkChangeObserver::OnIPAddressChanged() {
VLOG(1) << "Observed a change to the network IP addresses";
- net_log_->AddGlobalEntry(NetLog::TYPE_NETWORK_IP_ADDRESSES_CHANGED);
+ net_log_->AddGlobalEntry(NetLogEventType::NETWORK_IP_ADDRESSES_CHANGED);
}
void LoggingNetworkChangeObserver::OnConnectionTypeChanged(
@@ -74,7 +96,7 @@ void LoggingNetworkChangeObserver::OnConnectionTypeChanged(
<< type_as_string;
net_log_->AddGlobalEntry(
- NetLog::TYPE_NETWORK_CONNECTIVITY_CHANGED,
+ NetLogEventType::NETWORK_CONNECTIVITY_CHANGED,
NetLog::StringCallback("new_connection_type", &type_as_string));
}
@@ -86,7 +108,7 @@ void LoggingNetworkChangeObserver::OnNetworkChanged(
VLOG(1) << "Observed a network change to state " << type_as_string;
net_log_->AddGlobalEntry(
- NetLog::TYPE_NETWORK_CHANGED,
+ NetLogEventType::NETWORK_CHANGED,
NetLog::StringCallback("new_connection_type", &type_as_string));
}
@@ -94,7 +116,7 @@ void LoggingNetworkChangeObserver::OnNetworkConnected(
NetworkChangeNotifier::NetworkHandle network) {
VLOG(1) << "Observed network " << network << " connect";
- net_log_->AddGlobalEntry(NetLog::TYPE_SPECIFIC_NETWORK_CONNECTED,
+ net_log_->AddGlobalEntry(NetLogEventType::SPECIFIC_NETWORK_CONNECTED,
base::Bind(&NetworkSpecificNetLogCallback, network));
}
@@ -102,7 +124,7 @@ void LoggingNetworkChangeObserver::OnNetworkDisconnected(
NetworkChangeNotifier::NetworkHandle network) {
VLOG(1) << "Observed network " << network << " disconnect";
- net_log_->AddGlobalEntry(NetLog::TYPE_SPECIFIC_NETWORK_DISCONNECTED,
+ net_log_->AddGlobalEntry(NetLogEventType::SPECIFIC_NETWORK_DISCONNECTED,
base::Bind(&NetworkSpecificNetLogCallback, network));
}
@@ -110,7 +132,7 @@ void LoggingNetworkChangeObserver::OnNetworkSoonToDisconnect(
NetworkChangeNotifier::NetworkHandle network) {
VLOG(1) << "Observed network " << network << " soon to disconnect";
- net_log_->AddGlobalEntry(NetLog::TYPE_SPECIFIC_NETWORK_SOON_TO_DISCONNECT,
+ net_log_->AddGlobalEntry(NetLogEventType::SPECIFIC_NETWORK_SOON_TO_DISCONNECT,
base::Bind(&NetworkSpecificNetLogCallback, network));
}
@@ -118,7 +140,7 @@ void LoggingNetworkChangeObserver::OnNetworkMadeDefault(
NetworkChangeNotifier::NetworkHandle network) {
VLOG(1) << "Observed network " << network << " made the default network";
- net_log_->AddGlobalEntry(NetLog::TYPE_SPECIFIC_NETWORK_MADE_DEFAULT,
+ net_log_->AddGlobalEntry(NetLogEventType::SPECIFIC_NETWORK_MADE_DEFAULT,
base::Bind(&NetworkSpecificNetLogCallback, network));
}
diff --git a/chromium/net/base/net_error_details.h b/chromium/net/base/net_error_details.h
index 7bd5baad67d..a7f239a3a91 100644
--- a/chromium/net/base/net_error_details.h
+++ b/chromium/net/base/net_error_details.h
@@ -5,8 +5,9 @@
#ifndef NET_BASE_NET_ERROR_DETAILS_H_
#define NET_BASE_NET_ERROR_DETAILS_H_
+#include "net/base/net_export.h"
#include "net/http/http_response_info.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
diff --git a/chromium/net/base/net_error_list.h b/chromium/net/base/net_error_list.h
index df55033f861..2ea5d9aefc3 100644
--- a/chromium/net/base/net_error_list.h
+++ b/chromium/net/base/net_error_list.h
@@ -190,7 +190,7 @@ NET_ERROR(SOCKS_CONNECTION_FAILED, -120)
NET_ERROR(SOCKS_CONNECTION_HOST_UNREACHABLE, -121)
// The request to negotiate an alternate protocol failed.
-NET_ERROR(NPN_NEGOTIATION_FAILED, -122)
+NET_ERROR(ALPN_NEGOTIATION_FAILED, -122)
// The peer sent an SSL no_renegotiation alert message.
NET_ERROR(SSL_NO_RENEGOTIATION, -123)
@@ -314,9 +314,7 @@ NET_ERROR(WS_THROTTLE_QUEUE_TOO_LARGE, -154)
// The SSL server certificate changed in a renegotiation.
NET_ERROR(SSL_SERVER_CERT_CHANGED, -156)
-// The SSL server indicated that an unnecessary TLS version fallback was
-// performed.
-NET_ERROR(SSL_INAPPROPRIATE_FALLBACK, -157)
+// Error -157 was removed (SSL_INAPPROPRIATE_FALLBACK).
// Certificate Transparency: All Signed Certificate Timestamps failed to verify.
NET_ERROR(CT_NO_SCTS_VERIFIED_OK, -158)
@@ -342,9 +340,7 @@ NET_ERROR(SOCKET_SEND_BUFFER_SIZE_UNCHANGEABLE, -163)
// library.
NET_ERROR(SSL_CLIENT_AUTH_CERT_BAD_FORMAT, -164)
-// The SSL server requires falling back to a version older than the configured
-// minimum fallback version, and thus fallback failed.
-NET_ERROR(SSL_FALLBACK_BEYOND_MINIMUM_VERSION, -165)
+// Error -165 was removed (SSL_FALLBACK_BEYOND_MINIMUM_VERSION).
// Resolving a hostname to an IP address list included the IPv4 address
// "127.0.53.53". This is a special IP address which ICANN has recommended to
@@ -674,14 +670,14 @@ NET_ERROR(PROXY_HTTP_1_1_REQUIRED, -366)
// The PAC script terminated fatally and must be reloaded.
NET_ERROR(PAC_SCRIPT_TERMINATED, -367)
-// The certificate offered by the alternative server is not valid for the
-// origin, a violation of HTTP Alternative Services specification Section 2.1,
-// https://tools.ietf.org/id/draft-ietf-httpbis-alt-svc-06.html#host_auth.
-NET_ERROR(ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN, -368)
-
+// Obsolete. Kept here to avoid reuse.
// Request is throttled because of a Backoff header.
// See: crbug.com/486891.
-NET_ERROR(TEMPORARY_BACKOFF, -369)
+// NET_ERROR(TEMPORARY_BACKOFF, -369)
+
+// The server was expected to return an HTTP/1.x response, but did not. Rather
+// than treat it as HTTP/0.9, this error is returned.
+NET_ERROR(INVALID_HTTP_RESPONSE, -370)
// The cache does not have the requested entry.
NET_ERROR(CACHE_MISS, -400)
diff --git a/chromium/net/base/net_errors.cc b/chromium/net/base/net_errors.cc
index ddba87b94c5..9d91659c5b6 100644
--- a/chromium/net/base/net_errors.cc
+++ b/chromium/net/base/net_errors.cc
@@ -52,6 +52,11 @@ bool IsClientCertificateError(int error) {
}
}
+bool IsDnsError(int error) {
+ return (error == ERR_NAME_NOT_RESOLVED ||
+ error == ERR_NAME_RESOLUTION_FAILED);
+}
+
Error FileErrorToNetError(base::File::Error file_error) {
switch (file_error) {
case base::File::FILE_OK:
diff --git a/chromium/net/base/net_errors.h b/chromium/net/base/net_errors.h
index 27a2e51c79f..8fe976d4648 100644
--- a/chromium/net/base/net_errors.h
+++ b/chromium/net/base/net_errors.h
@@ -44,6 +44,9 @@ NET_EXPORT bool IsCertificateError(int error);
// certificate.
NET_EXPORT bool IsClientCertificateError(int error);
+// Returns true if |error| is a DNS error.
+NET_EXPORT bool IsDnsError(int error);
+
// Map system error code to Error.
NET_EXPORT Error MapSystemError(logging::SystemErrorCode os_error);
diff --git a/chromium/net/base/net_resources.grd b/chromium/net/base/net_resources.grd
index fef4e69d2f5..2937014ce89 100644
--- a/chromium/net/base/net_resources.grd
+++ b/chromium/net/base/net_resources.grd
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0" current_release="1">
+<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
<outputs>
<output filename="grit/net_resources.h" type="rc_header">
<emit emit_type='prepend'></emit>
diff --git a/chromium/net/base/net_string_util_icu_alternatives_android.cc b/chromium/net/base/net_string_util_icu_alternatives_android.cc
index 0551a03c565..1b56c4867a1 100644
--- a/chromium/net/base/net_string_util_icu_alternatives_android.cc
+++ b/chromium/net/base/net_string_util_icu_alternatives_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 "net/base/net_string_util_icu_alternatives_android.h"
-
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/strings/string16.h"
@@ -11,6 +9,8 @@
#include "jni/NetStringUtil_jni.h"
#include "net/base/net_string_util.h"
+using base::android::ScopedJavaLocalRef;
+
namespace net {
namespace {
@@ -113,8 +113,4 @@ bool ConvertToUTF16WithSubstitutions(const std::string& text,
return true;
}
-bool RegisterNetStringUtils(JNIEnv* env) {
- return android::RegisterNativesImpl(env);
-}
-
} // namespace net
diff --git a/chromium/net/base/net_string_util_icu_alternatives_android.h b/chromium/net/base/net_string_util_icu_alternatives_android.h
deleted file mode 100644
index c3a6cf507e6..00000000000
--- a/chromium/net/base/net_string_util_icu_alternatives_android.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_BASE_NET_STRING_UTIL_ICU_ALTERNATIVES_ANDROID_H_
-#define NET_BASE_NET_STRING_UTIL_ICU_ALTERNATIVES_ANDROID_H_
-
-#include <jni.h>
-
-namespace net {
-
-// Explicitly register static JNI functions needed when not using ICU.
-bool RegisterNetStringUtils(JNIEnv* env);
-
-} // namespace net
-
-#endif // NET_BASE_NET_STRING_UTIL_ICU_ALTERNATIVES_ANDROID_H_
-
diff --git a/chromium/net/base/network_activity_monitor_unittest.cc b/chromium/net/base/network_activity_monitor_unittest.cc
index 78b452117ec..cb822744329 100644
--- a/chromium/net/base/network_activity_monitor_unittest.cc
+++ b/chromium/net/base/network_activity_monitor_unittest.cc
@@ -8,7 +8,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/stl_util.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
@@ -94,9 +94,9 @@ void IncrementBytesSent(uint64_t bytes) {
} // namespace
TEST_F(NetworkActivityMontiorTest, Threading) {
- std::vector<base::Thread*> threads;
+ std::vector<std::unique_ptr<base::Thread>> threads;
for (size_t i = 0; i < 3; ++i) {
- threads.push_back(new base::Thread(base::SizeTToString(i)));
+ threads.push_back(base::MakeUnique<base::Thread>(base::SizeTToString(i)));
ASSERT_TRUE(threads.back()->Start());
}
@@ -119,7 +119,7 @@ TEST_F(NetworkActivityMontiorTest, Threading) {
base::Bind(&VerifyBytesReceivedIsMultipleOf, bytes_received));
}
- STLDeleteElements(&threads);
+ threads.clear();
NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
EXPECT_EQ(num_increments * bytes_received, monitor->GetBytesReceived());
diff --git a/chromium/net/base/network_change_notifier.h b/chromium/net/base/network_change_notifier.h
index aafee7a2006..27a798d04d1 100644
--- a/chromium/net/base/network_change_notifier.h
+++ b/chromium/net/base/network_change_notifier.h
@@ -211,8 +211,11 @@ class NET_EXPORT NetworkChangeNotifier {
// example an association with a particular WiFi network with a particular
// SSID or a connection to particular cellular network.
// The meaning of this handle is target-dependent. On Android NetworkHandles
- // are equivalent to the framework's concept of NetIDs (e.g. Network.netId).
- typedef int32_t NetworkHandle;
+ // are equivalent to:
+ // On Lollipop, the framework's concept of NetIDs (e.g. Network.netId), and
+ // On Marshmallow and newer releases, network handles
+ // (e.g. Network.getNetworkHandle()).
+ typedef int64_t NetworkHandle;
// A list of networks.
typedef std::vector<NetworkHandle> NetworkList;
diff --git a/chromium/net/base/network_change_notifier_win_unittest.cc b/chromium/net/base/network_change_notifier_win_unittest.cc
index 083a744c702..40dc42df66d 100644
--- a/chromium/net/base/network_change_notifier_win_unittest.cc
+++ b/chromium/net/base/network_change_notifier_win_unittest.cc
@@ -4,6 +4,7 @@
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "net/base/network_change_notifier.h"
#include "net/base/network_change_notifier_factory.h"
#include "net/base/network_change_notifier_win.h"
@@ -89,7 +90,7 @@ class NetworkChangeNotifierWinTest : public testing::Test {
// If a task to notify observers of the IP address change event was
// incorrectly posted, make sure it gets run to trigger a failure.
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
// Calls WatchForAddressChange, and simulates a WatchForAddressChangeInternal
@@ -112,7 +113,7 @@ class NetworkChangeNotifierWinTest : public testing::Test {
// If a task to notify observers of the IP address change event was
// incorrectly posted, make sure it gets run.
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
// Simulates a network change event, resulting in a call to OnObjectSignaled.
@@ -132,7 +133,7 @@ class NetworkChangeNotifierWinTest : public testing::Test {
EXPECT_EQ(0, network_change_notifier_.sequential_failures());
// Run the task to notify observers of the IP address change event.
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
// Simulates a network change event, resulting in a call to OnObjectSignaled.
@@ -154,7 +155,7 @@ class NetworkChangeNotifierWinTest : public testing::Test {
EXPECT_LT(0, network_change_notifier_.sequential_failures());
// Run the task to notify observers of the IP address change event.
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
// Runs the message loop until WatchForAddressChange is called again, as a
@@ -172,7 +173,7 @@ class NetworkChangeNotifierWinTest : public testing::Test {
EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
.Times(1).WillOnce(Return(true));
- base::MessageLoop::current()->Run();
+ base::RunLoop().Run();
EXPECT_TRUE(network_change_notifier_.is_watching());
EXPECT_EQ(0, network_change_notifier_.sequential_failures());
@@ -196,7 +197,7 @@ class NetworkChangeNotifierWinTest : public testing::Test {
.Times(AtLeast(1))
.WillRepeatedly(Invoke(ExitMessageLoopAndReturnFalse));
- base::MessageLoop::current()->Run();
+ base::RunLoop().Run();
EXPECT_FALSE(network_change_notifier_.is_watching());
EXPECT_LT(initial_sequential_failures,
@@ -204,7 +205,7 @@ class NetworkChangeNotifierWinTest : public testing::Test {
// If a task to notify observers of the IP address change event was
// incorrectly posted, make sure it gets run.
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
private:
diff --git a/chromium/net/base/network_delegate.cc b/chromium/net/base/network_delegate.cc
index a2ca52b3769..192b9e37cef 100644
--- a/chromium/net/base/network_delegate.cc
+++ b/chromium/net/base/network_delegate.cc
@@ -78,10 +78,12 @@ int NetworkDelegate::NotifyHeadersReceived(
allowed_unsafe_redirect_url);
}
-void NetworkDelegate::NotifyResponseStarted(URLRequest* request) {
+void NetworkDelegate::NotifyResponseStarted(URLRequest* request,
+ int net_error) {
DCHECK(CalledOnValidThread());
DCHECK(request);
- OnResponseStarted(request);
+
+ OnResponseStarted(request, net_error);
}
void NetworkDelegate::NotifyNetworkBytesReceived(URLRequest* request,
@@ -107,7 +109,9 @@ void NetworkDelegate::NotifyBeforeRedirect(URLRequest* request,
OnBeforeRedirect(request, new_location);
}
-void NetworkDelegate::NotifyCompleted(URLRequest* request, bool started) {
+void NetworkDelegate::NotifyCompleted(URLRequest* request,
+ bool started,
+ int net_error) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("net"),
"NetworkDelegate::NotifyCompleted");
DCHECK(CalledOnValidThread());
@@ -115,7 +119,8 @@ void NetworkDelegate::NotifyCompleted(URLRequest* request, bool started) {
// TODO(cbentzel): Remove ScopedTracker below once crbug.com/475753 is fixed.
tracked_objects::ScopedTracker tracking_profile(
FROM_HERE_WITH_EXPLICIT_FUNCTION("475753 NetworkDelegate::OnCompleted"));
- OnCompleted(request, started);
+
+ OnCompleted(request, started, net_error);
}
void NetworkDelegate::NotifyURLRequestDestroyed(URLRequest* request) {
@@ -188,4 +193,24 @@ bool NetworkDelegate::CancelURLRequestWithPolicyViolatingReferrerHeader(
request, target_url, referrer_url);
}
+void NetworkDelegate::OnResponseStarted(URLRequest* request, int net_error) {
+ OnResponseStarted(request);
+}
+
+// Deprecated
+void NetworkDelegate::OnResponseStarted(URLRequest* request) {
+ NOTREACHED();
+}
+
+void NetworkDelegate::OnCompleted(URLRequest* request,
+ bool started,
+ int net_error) {
+ OnCompleted(request, started);
+}
+
+// Deprecated.
+void NetworkDelegate::OnCompleted(URLRequest* request, bool started) {
+ NOTREACHED();
+}
+
} // namespace net
diff --git a/chromium/net/base/network_delegate.h b/chromium/net/base/network_delegate.h
index 2deb9c585c8..6fc19f90818 100644
--- a/chromium/net/base/network_delegate.h
+++ b/chromium/net/base/network_delegate.h
@@ -14,6 +14,7 @@
#include "base/threading/non_thread_safe.h"
#include "net/base/auth.h"
#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
#include "net/cookies/canonical_cookie.h"
#include "net/proxy/proxy_retry_info.h"
@@ -80,9 +81,13 @@ class NET_EXPORT NetworkDelegate : public base::NonThreadSafe {
GURL* allowed_unsafe_redirect_url);
void NotifyBeforeRedirect(URLRequest* request,
const GURL& new_location);
+ void NotifyResponseStarted(URLRequest* request, int net_error);
+ // Deprecated.
void NotifyResponseStarted(URLRequest* request);
void NotifyNetworkBytesReceived(URLRequest* request, int64_t bytes_received);
void NotifyNetworkBytesSent(URLRequest* request, int64_t bytes_sent);
+ void NotifyCompleted(URLRequest* request, bool started, int net_error);
+ // Deprecated.
void NotifyCompleted(URLRequest* request, bool started);
void NotifyURLRequestDestroyed(URLRequest* request);
void NotifyPACScriptError(int line_number, const base::string16& error);
@@ -185,7 +190,9 @@ class NET_EXPORT NetworkDelegate : public base::NonThreadSafe {
const GURL& new_location) = 0;
// This corresponds to URLRequestDelegate::OnResponseStarted.
- virtual void OnResponseStarted(URLRequest* request) = 0;
+ virtual void OnResponseStarted(URLRequest* request, int net_error);
+ // Deprecated.
+ virtual void OnResponseStarted(URLRequest* request);
// Called when bytes are received from the network, such as after receiving
// headers or reading raw response bytes. This includes localhost requests.
@@ -210,7 +217,9 @@ class NET_EXPORT NetworkDelegate : public base::NonThreadSafe {
// Indicates that the URL request has been completed or failed.
// |started| indicates whether the request has been started. If false,
// some information like the socket address is not available.
- virtual void OnCompleted(URLRequest* request, bool started) = 0;
+ virtual void OnCompleted(URLRequest* request, bool started, int net_error);
+ // Deprecated.
+ virtual void OnCompleted(URLRequest* request, bool started);
// Called when an URLRequest is being destroyed. Note that the request is
// being deleted, so it's not safe to call any methods that may result in
diff --git a/chromium/net/base/network_delegate_impl.cc b/chromium/net/base/network_delegate_impl.cc
index fa573e9e80f..be48c3ff022 100644
--- a/chromium/net/base/network_delegate_impl.cc
+++ b/chromium/net/base/network_delegate_impl.cc
@@ -41,21 +41,31 @@ int NetworkDelegateImpl::OnHeadersReceived(
}
void NetworkDelegateImpl::OnBeforeRedirect(URLRequest* request,
- const GURL& new_location) {
-}
+ const GURL& new_location) {}
-void NetworkDelegateImpl::OnResponseStarted(URLRequest* request) {
+void NetworkDelegateImpl::OnResponseStarted(URLRequest* request,
+ int net_error) {
+ OnResponseStarted(request);
}
+// Deprecated.
+void NetworkDelegateImpl::OnResponseStarted(URLRequest* request) {}
+
void NetworkDelegateImpl::OnNetworkBytesReceived(URLRequest* request,
int64_t bytes_received) {}
void NetworkDelegateImpl::OnNetworkBytesSent(URLRequest* request,
int64_t bytes_sent) {}
-void NetworkDelegateImpl::OnCompleted(URLRequest* request, bool started) {
+void NetworkDelegateImpl::OnCompleted(URLRequest* request,
+ bool started,
+ int net_error) {
+ OnCompleted(request, started);
}
+// Deprecated.
+void NetworkDelegateImpl::OnCompleted(URLRequest* request, bool started) {}
+
void NetworkDelegateImpl::OnURLRequestDestroyed(URLRequest* request) {
}
diff --git a/chromium/net/base/network_delegate_impl.h b/chromium/net/base/network_delegate_impl.h
index b2d56c770d5..d025a76847c 100644
--- a/chromium/net/base/network_delegate_impl.h
+++ b/chromium/net/base/network_delegate_impl.h
@@ -9,6 +9,7 @@
#include "base/strings/string16.h"
#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
#include "net/base/network_delegate.h"
#include "net/cookies/canonical_cookie.h"
#include "net/proxy/proxy_retry_info.h"
@@ -104,6 +105,9 @@ class NET_EXPORT NetworkDelegateImpl : public NetworkDelegate {
void OnBeforeRedirect(URLRequest* request, const GURL& new_location) override;
// This corresponds to URLRequestDelegate::OnResponseStarted.
+ void OnResponseStarted(URLRequest* request, int net_error) override;
+ // Deprecated.
+ // TODO(maksims): Remove this;
void OnResponseStarted(URLRequest* request) override;
// Called when bytes are received from the network, such as after receiving
@@ -129,6 +133,9 @@ class NET_EXPORT NetworkDelegateImpl : public NetworkDelegate {
// Indicates that the URL request has been completed or failed.
// |started| indicates whether the request has been started. If false,
// some information like the socket address is not available.
+ void OnCompleted(URLRequest* request, bool started, int net_error) override;
+ // Deprecated.
+ // TODO(maksims): Remove this;
void OnCompleted(URLRequest* request, bool started) override;
// Called when an URLRequest is being destroyed. Note that the request is
diff --git a/chromium/net/base/network_interfaces_linux.cc b/chromium/net/base/network_interfaces_linux.cc
index 293e32e4570..3c460be2871 100644
--- a/chromium/net/base/network_interfaces_linux.cc
+++ b/chromium/net/base/network_interfaces_linux.cc
@@ -30,6 +30,10 @@
#include "net/base/network_interfaces_posix.h"
#include "url/gurl.h"
+#if defined(OS_ANDROID)
+#include "net/android/network_library.h"
+#endif
+
namespace net {
namespace {
@@ -212,6 +216,10 @@ bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
}
std::string GetWifiSSID() {
+// On Android, obtain the SSID using the Android-specific APIs.
+#if defined(OS_ANDROID)
+ return android::GetWifiSSID();
+#endif
NetworkInterfaceList networks;
if (GetNetworkList(&networks, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES)) {
return internal::GetWifiSSIDFromInterfaceListInternal(
diff --git a/chromium/net/base/network_interfaces_linux.h b/chromium/net/base/network_interfaces_linux.h
index 8fe2284bd4e..9dfea10fb3a 100644
--- a/chromium/net/base/network_interfaces_linux.h
+++ b/chromium/net/base/network_interfaces_linux.h
@@ -12,6 +12,7 @@
#include <unordered_set>
#include "net/base/address_tracker_linux.h"
+#include "net/base/net_export.h"
#include "net/base/network_interfaces.h"
namespace net {
diff --git a/chromium/net/base/parse_url_hostname_to_address_fuzzer.cc b/chromium/net/base/parse_url_hostname_to_address_fuzzer.cc
new file mode 100644
index 00000000000..06a451c5dd2
--- /dev/null
+++ b/chromium/net/base/parse_url_hostname_to_address_fuzzer.cc
@@ -0,0 +1,31 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <functional>
+
+#include "net/base/address_list.h"
+#include "net/base/ip_address.h"
+
+// Entry point for LibFuzzer.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ const base::StringPiece hostname(reinterpret_cast<const char*>(data), size);
+ net::IPAddress address;
+
+ if (net::ParseURLHostnameToAddress(hostname, &address)) {
+ // To fuzz port number without spending raw bytes of data, use hash(data).
+ std::size_t data_hash = std::hash<std::string>()(hostname.as_string());
+ uint16_t port = static_cast<uint16_t>(data_hash & 0xFFFF);
+ net::AddressList addresses =
+ net::AddressList::CreateFromIPAddress(address, port);
+
+ for (const auto& endpoint : addresses) {
+ endpoint.ToString();
+ }
+ }
+
+ return 0;
+}
diff --git a/chromium/net/base/priority_queue.h b/chromium/net/base/priority_queue.h
index 5ea8679e4be..50e6aabf462 100644
--- a/chromium/net/base/priority_queue.h
+++ b/chromium/net/base/priority_queue.h
@@ -14,7 +14,6 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/threading/non_thread_safe.h"
-#include "net/base/net_export.h"
#if !defined(NDEBUG)
#include <unordered_set>
diff --git a/chromium/net/base/proxy_delegate.h b/chromium/net/base/proxy_delegate.h
index 3026a41bada..ad3a2bcafdd 100644
--- a/chromium/net/base/proxy_delegate.h
+++ b/chromium/net/base/proxy_delegate.h
@@ -38,7 +38,6 @@ class NET_EXPORT ProxyDelegate {
// ProxyInfo |result|.
virtual void OnResolveProxy(const GURL& url,
const std::string& method,
- int load_flags,
const ProxyService& proxy_service,
ProxyInfo* result) = 0;
@@ -69,6 +68,25 @@ class NET_EXPORT ProxyDelegate {
// 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;
+
+ // Notifies the ProxyDelegate that |alternative_proxy_server| is broken.
+ virtual void OnAlternativeProxyBroken(
+ const ProxyServer& alternative_proxy_server) = 0;
+
+ // Returns the default alternative proxy server. May return an invalid proxy
+ // server if no valid proxy server is available.
+ virtual ProxyServer GetDefaultAlternativeProxy() const = 0;
+
private:
DISALLOW_COPY_AND_ASSIGN(ProxyDelegate);
};
diff --git a/chromium/net/base/sdch_manager_unittest.cc b/chromium/net/base/sdch_manager_unittest.cc
index e910f111622..bfdb78fc7ca 100644
--- a/chromium/net/base/sdch_manager_unittest.cc
+++ b/chromium/net/base/sdch_manager_unittest.cc
@@ -14,7 +14,6 @@
#include "base/strings/stringprintf.h"
#include "base/test/simple_test_clock.h"
#include "net/base/sdch_observer.h"
-#include "net/log/net_log.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
diff --git a/chromium/net/base/sdch_net_log_params.cc b/chromium/net/base/sdch_net_log_params.cc
index 92009f3974e..75226c0e817 100644
--- a/chromium/net/base/sdch_net_log_params.cc
+++ b/chromium/net/base/sdch_net_log_params.cc
@@ -8,6 +8,7 @@
#include "base/values.h"
#include "net/base/net_errors.h"
+#include "net/log/net_log_capture_mode.h"
#include "url/gurl.h"
namespace net {
diff --git a/chromium/net/base/sdch_net_log_params.h b/chromium/net/base/sdch_net_log_params.h
index fb546122226..26e0e76280a 100644
--- a/chromium/net/base/sdch_net_log_params.h
+++ b/chromium/net/base/sdch_net_log_params.h
@@ -5,16 +5,22 @@
#ifndef NET_BASE_SDCH_NET_LOG_PARAMS_H_
#define NET_BASE_SDCH_NET_LOG_PARAMS_H_
+#include <memory>
#include <string>
#include "net/base/net_export.h"
#include "net/base/sdch_problem_codes.h"
-#include "net/log/net_log.h"
class GURL;
+namespace base {
+class Value;
+}
+
namespace net {
+class NetLogCaptureMode;
+
NET_EXPORT std::unique_ptr<base::Value> NetLogSdchResourceProblemCallback(
SdchProblemCode problem,
NetLogCaptureMode capture_mode);
diff --git a/chromium/net/base/static_cookie_policy_unittest.cc b/chromium/net/base/static_cookie_policy_unittest.cc
index 7749411addf..f2d9abf4374 100644
--- a/chromium/net/base/static_cookie_policy_unittest.cc
+++ b/chromium/net/base/static_cookie_policy_unittest.cc
@@ -4,9 +4,13 @@
#include "net/base/net_errors.h"
#include "net/base/static_cookie_policy.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+using net::test::IsOk;
+
namespace net {
class StaticCookiePolicyTest : public testing::Test {
@@ -35,49 +39,49 @@ class StaticCookiePolicyTest : public testing::Test {
};
TEST_F(StaticCookiePolicyTest, DefaultPolicyTest) {
- EXPECT_EQ(OK, CanGetCookies(url_google_, url_google_));
- EXPECT_EQ(OK, CanGetCookies(url_google_, url_google_secure_));
- EXPECT_EQ(OK, CanGetCookies(url_google_, url_google_mail_));
- EXPECT_EQ(OK, CanGetCookies(url_google_, url_google_analytics_));
- EXPECT_EQ(OK, CanGetCookies(url_google_, GURL()));
-
- EXPECT_EQ(OK, CanSetCookie(url_google_, url_google_));
- EXPECT_EQ(OK, CanSetCookie(url_google_, url_google_secure_));
- EXPECT_EQ(OK, CanSetCookie(url_google_, url_google_mail_));
- EXPECT_EQ(OK, CanSetCookie(url_google_, url_google_analytics_));
- EXPECT_EQ(OK, CanSetCookie(url_google_, GURL()));
+ EXPECT_THAT(CanGetCookies(url_google_, url_google_), IsOk());
+ EXPECT_THAT(CanGetCookies(url_google_, url_google_secure_), IsOk());
+ EXPECT_THAT(CanGetCookies(url_google_, url_google_mail_), IsOk());
+ EXPECT_THAT(CanGetCookies(url_google_, url_google_analytics_), IsOk());
+ EXPECT_THAT(CanGetCookies(url_google_, GURL()), IsOk());
+
+ EXPECT_THAT(CanSetCookie(url_google_, url_google_), IsOk());
+ EXPECT_THAT(CanSetCookie(url_google_, url_google_secure_), IsOk());
+ EXPECT_THAT(CanSetCookie(url_google_, url_google_mail_), IsOk());
+ EXPECT_THAT(CanSetCookie(url_google_, url_google_analytics_), IsOk());
+ EXPECT_THAT(CanSetCookie(url_google_, GURL()), IsOk());
}
TEST_F(StaticCookiePolicyTest, AllowAllCookiesTest) {
SetPolicyType(StaticCookiePolicy::ALLOW_ALL_COOKIES);
- EXPECT_EQ(OK, CanGetCookies(url_google_, url_google_));
- EXPECT_EQ(OK, CanGetCookies(url_google_, url_google_secure_));
- EXPECT_EQ(OK, CanGetCookies(url_google_, url_google_mail_));
- EXPECT_EQ(OK, CanGetCookies(url_google_, url_google_analytics_));
- EXPECT_EQ(OK, CanGetCookies(url_google_, GURL()));
-
- EXPECT_EQ(OK, CanSetCookie(url_google_, url_google_));
- EXPECT_EQ(OK, CanSetCookie(url_google_, url_google_secure_));
- EXPECT_EQ(OK, CanSetCookie(url_google_, url_google_mail_));
- EXPECT_EQ(OK, CanSetCookie(url_google_, url_google_analytics_));
- EXPECT_EQ(OK, CanSetCookie(url_google_, GURL()));
+ EXPECT_THAT(CanGetCookies(url_google_, url_google_), IsOk());
+ EXPECT_THAT(CanGetCookies(url_google_, url_google_secure_), IsOk());
+ EXPECT_THAT(CanGetCookies(url_google_, url_google_mail_), IsOk());
+ EXPECT_THAT(CanGetCookies(url_google_, url_google_analytics_), IsOk());
+ EXPECT_THAT(CanGetCookies(url_google_, GURL()), IsOk());
+
+ EXPECT_THAT(CanSetCookie(url_google_, url_google_), IsOk());
+ EXPECT_THAT(CanSetCookie(url_google_, url_google_secure_), IsOk());
+ EXPECT_THAT(CanSetCookie(url_google_, url_google_mail_), IsOk());
+ EXPECT_THAT(CanSetCookie(url_google_, url_google_analytics_), IsOk());
+ EXPECT_THAT(CanSetCookie(url_google_, GURL()), IsOk());
}
TEST_F(StaticCookiePolicyTest, BlockAllThirdPartyCookiesTest) {
SetPolicyType(StaticCookiePolicy::BLOCK_ALL_THIRD_PARTY_COOKIES);
- EXPECT_EQ(OK, CanGetCookies(url_google_, url_google_));
- EXPECT_EQ(OK, CanGetCookies(url_google_, url_google_secure_));
- EXPECT_EQ(OK, CanGetCookies(url_google_, url_google_mail_));
+ EXPECT_THAT(CanGetCookies(url_google_, url_google_), IsOk());
+ EXPECT_THAT(CanGetCookies(url_google_, url_google_secure_), IsOk());
+ EXPECT_THAT(CanGetCookies(url_google_, url_google_mail_), IsOk());
EXPECT_NE(OK, CanGetCookies(url_google_, url_google_analytics_));
- EXPECT_EQ(OK, CanGetCookies(url_google_, GURL()));
+ EXPECT_THAT(CanGetCookies(url_google_, GURL()), IsOk());
- EXPECT_EQ(OK, CanSetCookie(url_google_, url_google_));
- EXPECT_EQ(OK, CanSetCookie(url_google_, url_google_secure_));
- EXPECT_EQ(OK, CanSetCookie(url_google_, url_google_mail_));
+ EXPECT_THAT(CanSetCookie(url_google_, url_google_), IsOk());
+ EXPECT_THAT(CanSetCookie(url_google_, url_google_secure_), IsOk());
+ EXPECT_THAT(CanSetCookie(url_google_, url_google_mail_), IsOk());
EXPECT_NE(OK, CanSetCookie(url_google_, url_google_analytics_));
- EXPECT_EQ(OK, CanSetCookie(url_google_, GURL()));
+ EXPECT_THAT(CanSetCookie(url_google_, GURL()), IsOk());
}
TEST_F(StaticCookiePolicyTest, BlockAllCookiesTest) {
diff --git a/chromium/net/base/test_completion_callback_unittest.cc b/chromium/net/base/test_completion_callback_unittest.cc
index 9a40b240fe2..a2bc49092dd 100644
--- a/chromium/net/base/test_completion_callback_unittest.cc
+++ b/chromium/net/base/test_completion_callback_unittest.cc
@@ -112,9 +112,7 @@ bool ExampleEmployer::DoSomething(const CompletionCallback& callback) {
// Dispatch to worker thread...
if (!base::WorkerPool::PostTask(
- FROM_HERE,
- base::Bind(&ExampleWorker::DoWork, request_.get()),
- true)) {
+ FROM_HERE, base::Bind(&ExampleWorker::DoWork, request_), true)) {
NOTREACHED();
request_ = NULL;
return false;
diff --git a/chromium/net/base/test_proxy_delegate.cc b/chromium/net/base/test_proxy_delegate.cc
index e76b50ed74a..bfaa28e1dc0 100644
--- a/chromium/net/base/test_proxy_delegate.cc
+++ b/chromium/net/base/test_proxy_delegate.cc
@@ -13,7 +13,8 @@ namespace net {
TestProxyDelegate::TestProxyDelegate()
: on_before_tunnel_request_called_(false),
on_tunnel_request_completed_called_(false),
- on_tunnel_headers_received_called_(false) {}
+ on_tunnel_headers_received_called_(false),
+ get_alternative_proxy_invocations_(0) {}
TestProxyDelegate::~TestProxyDelegate() {}
@@ -41,7 +42,6 @@ void TestProxyDelegate::VerifyOnTunnelHeadersReceived(
void TestProxyDelegate::OnResolveProxy(const GURL& url,
const std::string& method,
- int load_flags,
const ProxyService& proxy_service,
ProxyInfo* result) {}
@@ -80,4 +80,25 @@ bool TestProxyDelegate::IsTrustedSpdyProxy(
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());
+ EXPECT_EQ(alternative_proxy_server_, alternative_proxy_server);
+ alternative_proxy_server_ = ProxyServer();
+}
+
+ProxyServer TestProxyDelegate::GetDefaultAlternativeProxy() const {
+ return alternative_proxy_server_;
+}
+
} // namespace net \ No newline at end of file
diff --git a/chromium/net/base/test_proxy_delegate.h b/chromium/net/base/test_proxy_delegate.h
index 91bb185d2cb..dea1e609930 100644
--- a/chromium/net/base/test_proxy_delegate.h
+++ b/chromium/net/base/test_proxy_delegate.h
@@ -52,7 +52,6 @@ class TestProxyDelegate : public ProxyDelegate {
// ProxyDelegate implementation:
void OnResolveProxy(const GURL& url,
const std::string& method,
- int load_flags,
const ProxyService& proxy_service,
ProxyInfo* result) override;
void OnTunnelConnectCompleted(const HostPortPair& endpoint,
@@ -66,6 +65,25 @@ class TestProxyDelegate : public ProxyDelegate {
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;
+ void OnAlternativeProxyBroken(
+ const ProxyServer& alternative_proxy_server) override;
+ ProxyServer GetDefaultAlternativeProxy() const override;
+
+ void set_alternative_proxy_server(
+ const ProxyServer& alternative_proxy_server) {
+ alternative_proxy_server_ = alternative_proxy_server;
+ }
+ const ProxyServer& alternative_proxy_server() const {
+ return alternative_proxy_server_;
+ }
+
+ int get_alternative_proxy_invocations() const {
+ return get_alternative_proxy_invocations_;
+ }
private:
bool on_before_tunnel_request_called_;
@@ -77,6 +95,10 @@ class TestProxyDelegate : public ProxyDelegate {
HostPortPair on_tunnel_headers_received_origin_;
HostPortPair on_tunnel_headers_received_proxy_server_;
std::string on_tunnel_headers_received_status_line_;
+ 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_bytes_element_reader_unittest.cc b/chromium/net/base/upload_bytes_element_reader_unittest.cc
index 59bd1eae899..e93caed03d7 100644
--- a/chromium/net/base/upload_bytes_element_reader_unittest.cc
+++ b/chromium/net/base/upload_bytes_element_reader_unittest.cc
@@ -8,9 +8,13 @@
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsOk;
+
namespace net {
class UploadBytesElementReaderTest : public PlatformTest {
@@ -19,7 +23,7 @@ class UploadBytesElementReaderTest : public PlatformTest {
const char kData[] = "123abc";
bytes_.assign(kData, kData + arraysize(kData));
reader_.reset(new UploadBytesElementReader(&bytes_[0], bytes_.size()));
- ASSERT_EQ(OK, reader_->Init(CompletionCallback()));
+ ASSERT_THAT(reader_->Init(CompletionCallback()), IsOk());
EXPECT_EQ(bytes_.size(), reader_->GetContentLength());
EXPECT_EQ(bytes_.size(), reader_->BytesRemaining());
EXPECT_TRUE(reader_->IsInMemory());
@@ -78,7 +82,7 @@ TEST_F(UploadBytesElementReaderTest, MultipleInit) {
EXPECT_EQ(bytes_, buf);
// Call Init() again to reset the state.
- ASSERT_EQ(OK, reader_->Init(CompletionCallback()));
+ ASSERT_THAT(reader_->Init(CompletionCallback()), IsOk());
EXPECT_EQ(bytes_.size(), reader_->GetContentLength());
EXPECT_EQ(bytes_.size(), reader_->BytesRemaining());
diff --git a/chromium/net/base/upload_data_stream.cc b/chromium/net/base/upload_data_stream.cc
index 37e19aed313..8b5a989bad1 100644
--- a/chromium/net/base/upload_data_stream.cc
+++ b/chromium/net/base/upload_data_stream.cc
@@ -6,11 +6,39 @@
#include "base/callback_helpers.h"
#include "base/logging.h"
+#include "base/values.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
+#include "net/log/net_log_event_type.h"
namespace net {
+namespace {
+
+std::unique_ptr<base::Value> NetLogInitEndInfoCallback(
+ int result,
+ int total_size,
+ bool is_chunked,
+ NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+
+ dict->SetInteger("net_error", result);
+ dict->SetInteger("total_size", total_size);
+ dict->SetBoolean("is_chunked", is_chunked);
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogReadInfoCallback(
+ int current_position,
+ NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+
+ dict->SetInteger("current_position", current_position);
+ return std::move(dict);
+}
+
+} // namespace
+
UploadDataStream::UploadDataStream(bool is_chunked, int64_t identifier)
: total_size_(0),
current_position_(0),
@@ -23,18 +51,23 @@ UploadDataStream::UploadDataStream(bool is_chunked, int64_t identifier)
UploadDataStream::~UploadDataStream() {
}
-int UploadDataStream::Init(const CompletionCallback& callback) {
+int UploadDataStream::Init(const CompletionCallback& callback,
+ const NetLogWithSource& net_log) {
Reset();
DCHECK(!initialized_successfully_);
DCHECK(callback_.is_null());
DCHECK(!callback.is_null() || IsInMemory());
- int result = InitInternal();
+ net_log_ = net_log;
+ net_log_.BeginEvent(NetLogEventType::UPLOAD_DATA_STREAM_INIT);
+
+ int result = InitInternal(net_log_);
if (result == ERR_IO_PENDING) {
DCHECK(!IsInMemory());
callback_ = callback;
} else {
OnInitCompleted(result);
}
+
return result;
}
@@ -44,15 +77,21 @@ int UploadDataStream::Read(IOBuffer* buf,
DCHECK(!callback.is_null() || IsInMemory());
DCHECK(initialized_successfully_);
DCHECK_GT(buf_len, 0);
- if (is_eof_)
- return 0;
- int result = ReadInternal(buf, buf_len);
+
+ net_log_.BeginEvent(NetLogEventType::UPLOAD_DATA_STREAM_READ,
+ base::Bind(&NetLogReadInfoCallback, current_position_));
+
+ int result = 0;
+ if (!is_eof_)
+ result = ReadInternal(buf, buf_len);
+
if (result == ERR_IO_PENDING) {
DCHECK(!IsInMemory());
callback_ = callback;
} else {
OnReadCompleted(result);
}
+
return result;
}
@@ -63,6 +102,21 @@ bool UploadDataStream::IsEOF() const {
}
void UploadDataStream::Reset() {
+ // If there's a pending callback, there's a pending init or read call that is
+ // being canceled.
+ if (!callback_.is_null()) {
+ if (!initialized_successfully_) {
+ // If initialization has not yet succeeded, this call is aborting
+ // initialization.
+ net_log_.EndEventWithNetErrorCode(
+ NetLogEventType::UPLOAD_DATA_STREAM_INIT, ERR_ABORTED);
+ } else {
+ // Otherwise, a read is being aborted.
+ net_log_.EndEventWithNetErrorCode(
+ NetLogEventType::UPLOAD_DATA_STREAM_READ, ERR_ABORTED);
+ }
+ }
+
current_position_ = 0;
initialized_successfully_ = false;
is_eof_ = false;
@@ -104,6 +158,11 @@ void UploadDataStream::OnInitCompleted(int result) {
if (!is_chunked_ && total_size_ == 0)
is_eof_ = true;
}
+
+ net_log_.EndEvent(
+ NetLogEventType::UPLOAD_DATA_STREAM_INIT,
+ base::Bind(&NetLogInitEndInfoCallback, result, total_size_, is_chunked_));
+
if (!callback_.is_null())
base::ResetAndReturn(&callback_).Run(result);
}
@@ -122,8 +181,19 @@ void UploadDataStream::OnReadCompleted(int result) {
}
}
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::UPLOAD_DATA_STREAM_READ,
+ result);
+
if (!callback_.is_null())
base::ResetAndReturn(&callback_).Run(result);
}
+UploadProgress UploadDataStream::GetUploadProgress() const {
+ // While initialization / rewinding is in progress, return nothing.
+ if (!initialized_successfully_)
+ return UploadProgress();
+
+ return UploadProgress(current_position_, total_size_);
+}
+
} // namespace net
diff --git a/chromium/net/base/upload_data_stream.h b/chromium/net/base/upload_data_stream.h
index b3f360ef67f..6b8f1bffb0c 100644
--- a/chromium/net/base/upload_data_stream.h
+++ b/chromium/net/base/upload_data_stream.h
@@ -13,6 +13,8 @@
#include "base/macros.h"
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
+#include "net/base/upload_progress.h"
+#include "net/log/net_log_with_source.h"
namespace net {
@@ -43,7 +45,7 @@ class NET_EXPORT UploadDataStream {
// Returns OK on success. Returns ERR_UPLOAD_FILE_CHANGED if the expected
// file modification time is set (usually not set, but set for sliced
// files) and the target file is changed.
- int Init(const CompletionCallback& callback);
+ int Init(const CompletionCallback& callback, const NetLogWithSource& net_log);
// When possible, reads up to |buf_len| bytes synchronously from the upload
// data stream to |buf| and returns the number of bytes read; otherwise,
@@ -89,6 +91,11 @@ class NET_EXPORT UploadDataStream {
virtual const std::vector<std::unique_ptr<UploadElementReader>>*
GetElementReaders() const;
+ // Returns the upload progress. If the stream was not initialized
+ // successfully, or has been reset and not yet re-initialized, returns an
+ // empty UploadProgress.
+ virtual UploadProgress GetUploadProgress() const;
+
protected:
// Must be called by subclasses when InitInternal and ReadInternal complete
// asynchronously.
@@ -107,7 +114,7 @@ class NET_EXPORT UploadDataStream {
// See Init(). If it returns ERR_IO_PENDING, OnInitCompleted must be called
// once it completes. If the upload is not chunked, SetSize must be called
// before it completes.
- virtual int InitInternal() = 0;
+ virtual int InitInternal(const NetLogWithSource& net_log) = 0;
// See Read(). For chunked uploads, must call SetIsFinalChunk if this is the
// final chunk. For non-chunked uploads, the UploadDataStream determins which
@@ -135,6 +142,8 @@ class NET_EXPORT UploadDataStream {
CompletionCallback callback_;
+ NetLogWithSource net_log_;
+
DISALLOW_COPY_AND_ASSIGN(UploadDataStream);
};
diff --git a/chromium/net/base/upload_file_element_reader_unittest.cc b/chromium/net/base/upload_file_element_reader_unittest.cc
index 7ad742c9b72..03e34ebba71 100644
--- a/chromium/net/base/upload_file_element_reader_unittest.cc
+++ b/chromium/net/base/upload_file_element_reader_unittest.cc
@@ -15,9 +15,14 @@
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
class UploadFileElementReaderTest : public PlatformTest {
@@ -30,8 +35,8 @@ class UploadFileElementReaderTest : public PlatformTest {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(),
- &temp_file_path_));
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &temp_file_path_));
ASSERT_EQ(
static_cast<int>(bytes_.size()),
base::WriteFile(temp_file_path_, &bytes_[0], bytes_.size()));
@@ -40,8 +45,8 @@ class UploadFileElementReaderTest : public PlatformTest {
base::ThreadTaskRunnerHandle::Get().get(), temp_file_path_, 0,
std::numeric_limits<uint64_t>::max(), base::Time()));
TestCompletionCallback callback;
- ASSERT_EQ(ERR_IO_PENDING, reader_->Init(callback.callback()));
- EXPECT_EQ(OK, callback.WaitForResult());
+ ASSERT_THAT(reader_->Init(callback.callback()), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(bytes_.size(), reader_->GetContentLength());
EXPECT_EQ(bytes_.size(), reader_->BytesRemaining());
EXPECT_FALSE(reader_->IsInMemory());
@@ -125,8 +130,8 @@ TEST_F(UploadFileElementReaderTest, MultipleInit) {
// Call Init() again to reset the state.
TestCompletionCallback init_callback;
- ASSERT_EQ(ERR_IO_PENDING, reader_->Init(init_callback.callback()));
- EXPECT_EQ(OK, init_callback.WaitForResult());
+ ASSERT_THAT(reader_->Init(init_callback.callback()), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(init_callback.WaitForResult(), IsOk());
EXPECT_EQ(bytes_.size(), reader_->GetContentLength());
EXPECT_EQ(bytes_.size(), reader_->BytesRemaining());
@@ -152,12 +157,14 @@ TEST_F(UploadFileElementReaderTest, InitDuringAsyncOperation) {
// Call Init to cancel the previous read.
TestCompletionCallback init_callback1;
- EXPECT_EQ(ERR_IO_PENDING, reader_->Init(init_callback1.callback()));
+ EXPECT_THAT(reader_->Init(init_callback1.callback()),
+ IsError(ERR_IO_PENDING));
// Call Init again to cancel the previous init.
TestCompletionCallback init_callback2;
- EXPECT_EQ(ERR_IO_PENDING, reader_->Init(init_callback2.callback()));
- EXPECT_EQ(OK, init_callback2.WaitForResult());
+ EXPECT_THAT(reader_->Init(init_callback2.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(init_callback2.WaitForResult(), IsOk());
EXPECT_EQ(bytes_.size(), reader_->GetContentLength());
EXPECT_EQ(bytes_.size(), reader_->BytesRemaining());
@@ -185,8 +192,8 @@ TEST_F(UploadFileElementReaderTest, Range) {
base::ThreadTaskRunnerHandle::Get().get(), temp_file_path_, kOffset,
kLength, base::Time()));
TestCompletionCallback init_callback;
- ASSERT_EQ(ERR_IO_PENDING, reader_->Init(init_callback.callback()));
- EXPECT_EQ(OK, init_callback.WaitForResult());
+ ASSERT_THAT(reader_->Init(init_callback.callback()), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(init_callback.WaitForResult(), IsOk());
EXPECT_EQ(kLength, reader_->GetContentLength());
EXPECT_EQ(kLength, reader_->BytesRemaining());
std::vector<char> buf(kLength);
@@ -212,8 +219,8 @@ TEST_F(UploadFileElementReaderTest, FileChanged) {
base::ThreadTaskRunnerHandle::Get().get(), temp_file_path_, 0,
std::numeric_limits<uint64_t>::max(), expected_modification_time));
TestCompletionCallback init_callback;
- ASSERT_EQ(ERR_IO_PENDING, reader_->Init(init_callback.callback()));
- EXPECT_EQ(ERR_UPLOAD_FILE_CHANGED, init_callback.WaitForResult());
+ ASSERT_THAT(reader_->Init(init_callback.callback()), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(init_callback.WaitForResult(), IsError(ERR_UPLOAD_FILE_CHANGED));
}
TEST_F(UploadFileElementReaderTest, InexactExpectedTimeStamp) {
@@ -226,8 +233,8 @@ TEST_F(UploadFileElementReaderTest, InexactExpectedTimeStamp) {
base::ThreadTaskRunnerHandle::Get().get(), temp_file_path_, 0,
std::numeric_limits<uint64_t>::max(), expected_modification_time));
TestCompletionCallback init_callback;
- ASSERT_EQ(ERR_IO_PENDING, reader_->Init(init_callback.callback()));
- EXPECT_EQ(OK, init_callback.WaitForResult());
+ ASSERT_THAT(reader_->Init(init_callback.callback()), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(init_callback.WaitForResult(), IsOk());
}
TEST_F(UploadFileElementReaderTest, WrongPath) {
@@ -236,8 +243,8 @@ TEST_F(UploadFileElementReaderTest, WrongPath) {
base::ThreadTaskRunnerHandle::Get().get(), wrong_path, 0,
std::numeric_limits<uint64_t>::max(), base::Time()));
TestCompletionCallback init_callback;
- ASSERT_EQ(ERR_IO_PENDING, reader_->Init(init_callback.callback()));
- EXPECT_EQ(ERR_FILE_NOT_FOUND, init_callback.WaitForResult());
+ ASSERT_THAT(reader_->Init(init_callback.callback()), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(init_callback.WaitForResult(), IsError(ERR_FILE_NOT_FOUND));
}
} // namespace net
diff --git a/chromium/net/base/url_util.cc b/chromium/net/base/url_util.cc
index 879c746c9b3..8d47bd3be29 100644
--- a/chromium/net/base/url_util.cc
+++ b/chromium/net/base/url_util.cc
@@ -74,8 +74,7 @@ GURL AppendOrReplaceQueryParameter(const GURL& url,
replaced = true;
key_value_pair = (param_name + "=" + param_value);
} else {
- key_value_pair.assign(input.data(),
- key_range.begin,
+ key_value_pair.assign(input, key_range.begin,
value_range.end() - key_range.begin);
}
if (!output.empty())
diff --git a/chromium/net/base/winsock_init.cc b/chromium/net/base/winsock_init.cc
index e7601859e78..1f488c96c6b 100644
--- a/chromium/net/base/winsock_init.cc
+++ b/chromium/net/base/winsock_init.cc
@@ -30,15 +30,12 @@ class WinsockInitSingleton {
WSAGetLastError();
}
}
-
- ~WinsockInitSingleton() {
- // Don't call WSACleanup() since the worker pool threads can continue to
- // call getaddrinfo() after Winsock has shutdown, which can lead to crashes.
- }
};
-static base::LazyInstance<WinsockInitSingleton> g_winsock_init_singleton =
- LAZY_INSTANCE_INITIALIZER;
+// Worker pool threads that use the Windows Sockets API may still be running at
+// shutdown. Leak instance and skip cleanup.
+static base::LazyInstance<WinsockInitSingleton>::Leaky
+ g_winsock_init_singleton = LAZY_INSTANCE_INITIALIZER;
} // namespace
diff --git a/chromium/net/base/winsock_util.h b/chromium/net/base/winsock_util.h
index 80edc3faf1a..ff204019528 100644
--- a/chromium/net/base/winsock_util.h
+++ b/chromium/net/base/winsock_util.h
@@ -8,8 +8,6 @@
#include <stddef.h>
#include <winsock2.h>
-#include "net/base/net_export.h"
-
namespace net {
// Bluetooth address size. Windows Bluetooth is supported via winsock.
diff --git a/chromium/net/cert/caching_cert_verifier.cc b/chromium/net/cert/caching_cert_verifier.cc
index 1b053853e62..43515f8d4b5 100644
--- a/chromium/net/cert/caching_cert_verifier.cc
+++ b/chromium/net/cert/caching_cert_verifier.cc
@@ -36,7 +36,7 @@ int CachingCertVerifier::Verify(const CertVerifier::RequestParams& params,
CertVerifyResult* verify_result,
const CompletionCallback& callback,
std::unique_ptr<Request>* out_req,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
out_req->reset();
requests_++;
diff --git a/chromium/net/cert/caching_cert_verifier.h b/chromium/net/cert/caching_cert_verifier.h
index 54ba118cf2f..e10d6db0ed2 100644
--- a/chromium/net/cert/caching_cert_verifier.h
+++ b/chromium/net/cert/caching_cert_verifier.h
@@ -62,7 +62,7 @@ class NET_EXPORT CachingCertVerifier : public CertVerifier,
CertVerifyResult* verify_result,
const CompletionCallback& callback,
std::unique_ptr<Request>* out_req,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
bool SupportsOCSPStapling() override;
// Opportunistically attempts to add |error| and |verify_result| as the
diff --git a/chromium/net/cert/caching_cert_verifier_unittest.cc b/chromium/net/cert/caching_cert_verifier_unittest.cc
index ad0283b36ea..f67781c0e0e 100644
--- a/chromium/net/cert/caching_cert_verifier_unittest.cc
+++ b/chromium/net/cert/caching_cert_verifier_unittest.cc
@@ -15,12 +15,16 @@
#include "net/cert/cert_verify_result.h"
#include "net/cert/mock_cert_verifier.h"
#include "net/cert/x509_certificate.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
using testing::_;
using testing::Mock;
using testing::Return;
@@ -68,7 +72,8 @@ TEST_F(CachingCertVerifierTest, CacheHit) {
error = callback.GetResult(verifier_.Verify(
CertVerifier::RequestParams(test_cert, "www.example.com", 0,
std::string(), CertificateList()),
- nullptr, &verify_result, callback.callback(), &request, BoundNetLog()));
+ nullptr, &verify_result, callback.callback(), &request,
+ NetLogWithSource()));
ASSERT_TRUE(IsCertificateError(error));
ASSERT_EQ(1u, verifier_.requests());
ASSERT_EQ(0u, verifier_.cache_hits());
@@ -77,7 +82,8 @@ TEST_F(CachingCertVerifierTest, CacheHit) {
error = verifier_.Verify(
CertVerifier::RequestParams(test_cert, "www.example.com", 0,
std::string(), CertificateList()),
- nullptr, &verify_result, callback.callback(), &request, BoundNetLog());
+ nullptr, &verify_result, callback.callback(), &request,
+ NetLogWithSource());
// Synchronous completion.
ASSERT_NE(ERR_IO_PENDING, error);
ASSERT_TRUE(IsCertificateError(error));
@@ -100,9 +106,9 @@ TEST_F(CachingCertVerifierTest, Visitor) {
CertVerifier::RequestParams params1(test_cert, "www.example.com", 0,
std::string(), CertificateList());
CertVerifyResult result1;
- int error1 = callback.GetResult(verifier_.Verify(params1, nullptr, &result1,
- callback.callback(),
- &request, BoundNetLog()));
+ int error1 = callback.GetResult(
+ verifier_.Verify(params1, nullptr, &result1, callback.callback(),
+ &request, NetLogWithSource()));
ASSERT_TRUE(IsCertificateError(error1));
ASSERT_EQ(1u, verifier_.requests());
ASSERT_EQ(0u, verifier_.cache_hits());
@@ -111,9 +117,9 @@ TEST_F(CachingCertVerifierTest, Visitor) {
CertVerifier::RequestParams params2(test_cert, "www.example.net", 0,
std::string(), CertificateList());
CertVerifyResult result2;
- int error2 = callback.GetResult(verifier_.Verify(params2, nullptr, &result2,
- callback.callback(),
- &request, BoundNetLog()));
+ int error2 = callback.GetResult(
+ verifier_.Verify(params2, nullptr, &result2, callback.callback(),
+ &request, NetLogWithSource()));
ASSERT_TRUE(IsCertificateError(error2));
ASSERT_EQ(2u, verifier_.requests());
ASSERT_EQ(0u, verifier_.cache_hits());
@@ -122,9 +128,9 @@ TEST_F(CachingCertVerifierTest, Visitor) {
CertVerifier::RequestParams params3(test_cert, "www.example.org", 0,
std::string(), CertificateList());
CertVerifyResult result3;
- int error3 = callback.GetResult(verifier_.Verify(params3, nullptr, &result3,
- callback.callback(),
- &request, BoundNetLog()));
+ int error3 = callback.GetResult(
+ verifier_.Verify(params3, nullptr, &result3, callback.callback(),
+ &request, NetLogWithSource()));
ASSERT_TRUE(IsCertificateError(error3));
ASSERT_EQ(3u, verifier_.requests());
ASSERT_EQ(0u, verifier_.cache_hits());
@@ -187,8 +193,8 @@ TEST_F(CachingCertVerifierTest, AddsEntries) {
CertVerifyResult cached_result;
int error = callback.GetResult(
verifier_.Verify(params, nullptr, &cached_result, callback.callback(),
- &request, BoundNetLog()));
- ASSERT_EQ(ERR_CERT_WEAK_KEY, error);
+ &request, NetLogWithSource()));
+ ASSERT_THAT(error, IsError(ERR_CERT_WEAK_KEY));
EXPECT_TRUE(cached_result.has_md2);
EXPECT_FALSE(cached_result.is_issued_by_known_root);
@@ -203,8 +209,8 @@ TEST_F(CachingCertVerifierTest, AddsEntries) {
error = callback.GetResult(verifier_.Verify(params, nullptr, &cached_result,
callback.callback(), &request,
- BoundNetLog()));
- ASSERT_EQ(ERR_CERT_WEAK_KEY, error);
+ NetLogWithSource()));
+ ASSERT_THAT(error, IsError(ERR_CERT_WEAK_KEY));
EXPECT_TRUE(cached_result.has_md2);
EXPECT_FALSE(cached_result.is_issued_by_known_root);
@@ -253,7 +259,8 @@ TEST_F(CachingCertVerifierTest, DifferentCACerts) {
error = callback.GetResult(verifier_.Verify(
CertVerifier::RequestParams(cert_chain1, "www.example.com", 0,
std::string(), CertificateList()),
- nullptr, &verify_result, callback.callback(), &request, BoundNetLog()));
+ nullptr, &verify_result, callback.callback(), &request,
+ NetLogWithSource()));
ASSERT_TRUE(IsCertificateError(error));
ASSERT_EQ(1u, verifier_.requests());
ASSERT_EQ(0u, verifier_.cache_hits());
@@ -262,7 +269,8 @@ TEST_F(CachingCertVerifierTest, DifferentCACerts) {
error = callback.GetResult(verifier_.Verify(
CertVerifier::RequestParams(cert_chain2, "www.example.com", 0,
std::string(), CertificateList()),
- nullptr, &verify_result, callback.callback(), &request, BoundNetLog()));
+ nullptr, &verify_result, callback.callback(), &request,
+ NetLogWithSource()));
ASSERT_TRUE(IsCertificateError(error));
ASSERT_EQ(2u, verifier_.requests());
ASSERT_EQ(0u, verifier_.cache_hits());
diff --git a/chromium/net/cert/cert_verifier.h b/chromium/net/cert/cert_verifier.h
index 2b5ef1f70bd..be510119d3b 100644
--- a/chromium/net/cert/cert_verifier.h
+++ b/chromium/net/cert/cert_verifier.h
@@ -18,9 +18,9 @@
namespace net {
-class BoundNetLog;
class CertVerifyResult;
class CRLSet;
+class NetLogWithSource;
// CertVerifier represents a service for verifying certificates.
//
@@ -75,6 +75,10 @@ class NET_EXPORT CertVerifier {
// can only provide information for the leaf, and not for any
// intermediates.
VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS = 1 << 4,
+
+ // If set, certificates with SHA-1 signatures will be allowed, but only if
+ // they are issued by non-public trust anchors.
+ VERIFY_ENABLE_SHA1_LOCAL_ANCHORS = 1 << 5,
};
// Parameters to verify |certificate| against the supplied
@@ -163,7 +167,7 @@ class NET_EXPORT CertVerifier {
CertVerifyResult* verify_result,
const CompletionCallback& callback,
std::unique_ptr<Request>* out_req,
- const BoundNetLog& net_log) = 0;
+ const NetLogWithSource& net_log) = 0;
// Returns true if this CertVerifier supports stapled OCSP responses.
virtual bool SupportsOCSPStapling();
diff --git a/chromium/net/cert/cert_verify_proc.cc b/chromium/net/cert/cert_verify_proc.cc
index 49a170d3cb5..8fdd93cbb1b 100644
--- a/chromium/net/cert/cert_verify_proc.cc
+++ b/chromium/net/cert/cert_verify_proc.cc
@@ -23,7 +23,10 @@
#include "net/cert/cert_verify_proc_whitelist.h"
#include "net/cert/cert_verify_result.h"
#include "net/cert/crl_set.h"
+#include "net/cert/internal/parse_ocsp.h"
+#include "net/cert/ocsp_revocation_status.h"
#include "net/cert/x509_certificate.h"
+#include "net/der/encode_values.h"
#include "url/url_canon.h"
#if defined(USE_NSS_CERTS)
@@ -182,6 +185,130 @@ bool IsPastSHA1DeprecationDate(const X509Certificate& cert) {
return start >= kSHA1DeprecationDate;
}
+// Checks if the given RFC 6960 OCSPCertID structure |cert_id| has the same
+// serial number as |certificate|.
+//
+// TODO(dadrian): Verify name and key hashes. https://crbug.com/620005
+bool CheckCertIDMatchesCertificate(const OCSPCertID& cert_id,
+ const X509Certificate& certificate) {
+ der::Input serial(&certificate.serial_number());
+ return cert_id.serial_number == serial;
+}
+
+// Populates |ocsp_result| with revocation information for |certificate|, based
+// on the unparsed OCSP response in |raw_response|.
+void CheckOCSP(const std::string& raw_response,
+ const X509Certificate& certificate,
+ OCSPVerifyResult* ocsp_result) {
+ // The maximum age for an OCSP response, implemented as time since the
+ // |this_update| field in OCSPSingleREsponse. Responses older than |max_age|
+ // will be considered invalid.
+ static base::TimeDelta max_age = base::TimeDelta::FromDays(7);
+ *ocsp_result = OCSPVerifyResult();
+
+ if (raw_response.empty()) {
+ ocsp_result->response_status = OCSPVerifyResult::MISSING;
+ return;
+ }
+
+ der::Input response_der(&raw_response);
+ OCSPResponse response;
+ if (!ParseOCSPResponse(response_der, &response)) {
+ ocsp_result->response_status = OCSPVerifyResult::PARSE_RESPONSE_ERROR;
+ return;
+ }
+
+ // RFC 6960 defines all responses |response_status| != SUCCESSFUL as error
+ // responses. No revocation information is provided on error responses, and
+ // the OCSPResponseData structure is not set.
+ if (response.status != OCSPResponse::ResponseStatus::SUCCESSFUL) {
+ ocsp_result->response_status = OCSPVerifyResult::ERROR_RESPONSE;
+ return;
+ }
+
+ // Actual revocation information is contained within the BasicOCSPResponse as
+ // a ResponseData structure. The BasicOCSPResponse was parsed above, and
+ // contains an unparsed ResponseData. From RFC 6960:
+ //
+ // BasicOCSPResponse ::= SEQUENCE {
+ // tbsResponseData ResponseData,
+ // signatureAlgorithm AlgorithmIdentifier,
+ // signature BIT STRING,
+ // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ //
+ // ResponseData ::= SEQUENCE {
+ // version [0] EXPLICIT Version DEFAULT v1,
+ // responderID ResponderID,
+ // producedAt GeneralizedTime,
+ // responses SEQUENCE OF SingleResponse,
+ // responseExtensions [1] EXPLICIT Extensions OPTIONAL }
+ OCSPResponseData response_data;
+ if (!ParseOCSPResponseData(response.data, &response_data)) {
+ ocsp_result->response_status = OCSPVerifyResult::PARSE_RESPONSE_DATA_ERROR;
+ return;
+ }
+
+ // If producedAt is outside of the certificate validity period, reject the
+ // response.
+ der::GeneralizedTime not_before, not_after;
+ if (!der::EncodeTimeAsGeneralizedTime(certificate.valid_start(),
+ &not_before) ||
+ !der::EncodeTimeAsGeneralizedTime(certificate.valid_expiry(),
+ &not_after)) {
+ ocsp_result->response_status = OCSPVerifyResult::BAD_PRODUCED_AT;
+ return;
+ }
+ if (response_data.produced_at < not_before ||
+ response_data.produced_at > not_after) {
+ ocsp_result->response_status = OCSPVerifyResult::BAD_PRODUCED_AT;
+ return;
+ }
+
+ // TODO(svaldez): Unify with GetOCSPCertStatus. https://crbug.com/629249
+ base::Time verify_time = base::Time::Now();
+ ocsp_result->response_status = OCSPVerifyResult::NO_MATCHING_RESPONSE;
+ for (const auto& single_response_der : response_data.responses) {
+ // In the common case, there should only be one SingleResponse in the
+ // ResponseData (matching the certificate requested and used on this
+ // connection). However, it is possible for the OCSP responder to provide
+ // multiple responses for multiple certificates. Look through all the
+ // provided SingleResponses, and check to see if any match the certificate.
+ // A SingleResponse matches a certificate if it has the same serial number.
+ OCSPSingleResponse single_response;
+ if (!ParseOCSPSingleResponse(single_response_der, &single_response))
+ continue;
+ OCSPCertID cert_id;
+ if (!ParseOCSPCertID(single_response.cert_id_tlv, &cert_id))
+ continue;
+ if (!CheckCertIDMatchesCertificate(cert_id, certificate))
+ continue;
+ // The SingleResponse matches the certificate, but may be out of date. Out
+ // of date responses are noted seperate from responses with mismatched
+ // serial numbers. If an OCSP responder provides both an up to date response
+ // and an expired response, the up to date response takes precedence
+ // (PROVIDED > INVALID_DATE).
+ if (!CheckOCSPDateValid(single_response, verify_time, max_age)) {
+ if (ocsp_result->response_status != OCSPVerifyResult::PROVIDED)
+ ocsp_result->response_status = OCSPVerifyResult::INVALID_DATE;
+ continue;
+ }
+
+ // In the case with multiple matching and up to date responses, keep only
+ // the strictest status (REVOKED > UNKNOWN > GOOD). The current
+ // |revocation_status| is only valid if |response_status| is already set to
+ // PROVIDED.
+ OCSPRevocationStatus current_status = OCSPRevocationStatus::GOOD;
+ if (ocsp_result->response_status == OCSPVerifyResult::PROVIDED) {
+ current_status = ocsp_result->revocation_status;
+ }
+ if (current_status == OCSPRevocationStatus::GOOD ||
+ single_response.cert_status.status == OCSPRevocationStatus::REVOKED) {
+ ocsp_result->revocation_status = single_response.cert_status.status;
+ }
+ ocsp_result->response_status = OCSPVerifyResult::PROVIDED;
+ }
+}
+
// Comparison functor used for binary searching whether a given HashValue,
// which MUST be a SHA-256 hash, is contained with an array of SHA-256
// hashes.
@@ -258,6 +385,9 @@ int CertVerifyProc::Verify(X509Certificate* cert,
verify_result->common_name_fallback_used);
}
+ CheckOCSP(ocsp_response, *verify_result->verified_cert,
+ &verify_result->ocsp_result);
+
// This check is done after VerifyInternal so that VerifyInternal can fill
// in the list of public key hashes.
if (IsPublicKeyBlacklisted(verify_result->public_key_hashes)) {
@@ -310,6 +440,9 @@ int CertVerifyProc::Verify(X509Certificate* cert,
// disabled on this date, but enterprises need more time to transition.
// As the risk is greatest for publicly trusted certificates, prevent
// those certificates from being trusted from that date forward.
+ //
+ // TODO(mattm): apply the SHA-1 deprecation check to all certs unless
+ // CertVerifier::VERIFY_ENABLE_SHA1_LOCAL_ANCHORS flag is present.
if (verify_result->has_md5 ||
(verify_result->has_sha1_leaf && verify_result->is_issued_by_known_root &&
IsPastSHA1DeprecationDate(*cert))) {
diff --git a/chromium/net/cert/cert_verify_proc_ios.cc b/chromium/net/cert/cert_verify_proc_ios.cc
index 017d84b7664..73f8a150481 100644
--- a/chromium/net/cert/cert_verify_proc_ios.cc
+++ b/chromium/net/cert/cert_verify_proc_ios.cc
@@ -5,7 +5,6 @@
#include "net/cert/cert_verify_proc_ios.h"
#include <CommonCrypto/CommonDigest.h>
-#include <Security/Security.h>
#include "base/logging.h"
#include "base/mac/scoped_cftyperef.h"
@@ -172,6 +171,10 @@ void GetCertChainInfo(CFArrayRef cert_chain, CertVerifyResult* verify_result) {
X509Certificate::CreateFromHandle(verified_cert, verified_chain);
}
+} // namespace
+
+CertVerifyProcIOS::CertVerifyProcIOS() {}
+
// The iOS APIs don't expose an API-stable set of reasons for certificate
// validation failures. However, internally, the reason is tracked, and it's
// converted to user-facing localized strings.
@@ -184,9 +187,11 @@ void GetCertChainInfo(CFArrayRef cert_chain, CertVerifyResult* verify_result) {
//
// TODO(rsleevi): https://crbug.com/601915 - Use a less brittle solution when
// possible.
-CertStatus GetFailureFromTrustProperties(CFArrayRef properties) {
+// static
+CertStatus CertVerifyProcIOS::GetCertFailureStatusFromTrust(SecTrustRef trust) {
CertStatus reason = 0;
+ base::ScopedCFTypeRef<CFArrayRef> properties(SecTrustCopyProperties(trust));
if (!properties)
return CERT_STATUS_INVALID;
@@ -207,6 +212,11 @@ CertStatus GetFailureFromTrustProperties(CFArrayRef properties) {
CFSTR("One or more certificates is using a weak key size.");
ScopedCFTypeRef<CFStringRef> weak_error(CFBundleCopyLocalizedString(
bundle, weak_string, weak_string, CFSTR("SecCertificate")));
+ CFStringRef hostname_mismatch_string = CFSTR("Hostname mismatch.");
+ ScopedCFTypeRef<CFStringRef> hostname_mismatch_error(
+ CFBundleCopyLocalizedString(bundle, hostname_mismatch_string,
+ hostname_mismatch_string,
+ CFSTR("SecCertificate")));
for (CFIndex i = 0; i < properties_length; ++i) {
CFDictionaryRef dict = reinterpret_cast<CFDictionaryRef>(
@@ -220,6 +230,8 @@ CertStatus GetFailureFromTrustProperties(CFArrayRef properties) {
reason |= CERT_STATUS_AUTHORITY_INVALID;
} else if (CFEqual(error, weak_error)) {
reason |= CERT_STATUS_WEAK_KEY;
+ } else if (CFEqual(error, hostname_mismatch_error)) {
+ reason |= CERT_STATUS_COMMON_NAME_INVALID;
} else {
reason |= CERT_STATUS_INVALID;
}
@@ -228,12 +240,6 @@ CertStatus GetFailureFromTrustProperties(CFArrayRef properties) {
return reason;
}
-} // namespace
-
-CertVerifyProcIOS::CertVerifyProcIOS() {}
-
-CertVerifyProcIOS::~CertVerifyProcIOS() {}
-
bool CertVerifyProcIOS::SupportsAdditionalTrustAnchors() const {
return false;
}
@@ -242,6 +248,8 @@ bool CertVerifyProcIOS::SupportsOCSPStapling() const {
return false;
}
+CertVerifyProcIOS::~CertVerifyProcIOS() = default;
+
int CertVerifyProcIOS::VerifyInternal(
X509Certificate* cert,
const std::string& hostname,
@@ -278,8 +286,7 @@ int CertVerifyProcIOS::VerifyInternal(
verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID;
break;
default:
- CFArrayRef properties = SecTrustCopyProperties(trust_ref);
- verify_result->cert_status |= GetFailureFromTrustProperties(properties);
+ verify_result->cert_status |= GetCertFailureStatusFromTrust(trust_ref);
}
GetCertChainInfo(final_chain, verify_result);
diff --git a/chromium/net/cert/cert_verify_proc_ios.h b/chromium/net/cert/cert_verify_proc_ios.h
index e965a486e03..ac5e3885e85 100644
--- a/chromium/net/cert/cert_verify_proc_ios.h
+++ b/chromium/net/cert/cert_verify_proc_ios.h
@@ -7,6 +7,8 @@
#include "net/cert/cert_verify_proc.h"
+#include <Security/Security.h>
+
namespace net {
// Performs certificate path construction and validation using iOS's
@@ -15,6 +17,10 @@ class CertVerifyProcIOS : public CertVerifyProc {
public:
CertVerifyProcIOS();
+ // Returns error CertStatus from the given |trust| object. Returns
+ // CERT_STATUS_INVALID if the trust is null.
+ static CertStatus GetCertFailureStatusFromTrust(SecTrustRef trust);
+
bool SupportsAdditionalTrustAnchors() const override;
bool SupportsOCSPStapling() const override;
diff --git a/chromium/net/cert/cert_verify_proc_ios_unittest.cc b/chromium/net/cert/cert_verify_proc_ios_unittest.cc
new file mode 100644
index 00000000000..b2191ce64ae
--- /dev/null
+++ b/chromium/net/cert/cert_verify_proc_ios_unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/cert_verify_proc_ios.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Security.h>
+
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/ref_counted.h"
+#include "net/cert/x509_certificate.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Creates new SecTrustRef object backed up by cert from |cert_file|.
+base::ScopedCFTypeRef<SecTrustRef> CreateSecTrust(
+ const std::string& cert_file) {
+ base::ScopedCFTypeRef<SecTrustRef> scoped_result;
+
+ scoped_refptr<net::X509Certificate> cert =
+ net::ImportCertFromFile(net::GetTestCertsDirectory(), cert_file);
+ base::ScopedCFTypeRef<CFMutableArrayRef> certs(
+ CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks));
+ CFArrayAppendValue(certs, cert->os_cert_handle());
+
+ base::ScopedCFTypeRef<SecPolicyRef> policy(
+ SecPolicyCreateSSL(TRUE, CFSTR("chromium.org")));
+ SecTrustRef result = nullptr;
+ if (SecTrustCreateWithCertificates(certs, policy, &result) == errSecSuccess) {
+ scoped_result.reset(result);
+ }
+ return scoped_result;
+}
+
+} // namespace
+
+namespace net {
+
+// Tests |GetCertFailureStatusFromTrust| with null trust object.
+TEST(CertVerifyProcIOSTest, StatusForNullTrust) {
+ EXPECT_EQ(CERT_STATUS_INVALID,
+ CertVerifyProcIOS::GetCertFailureStatusFromTrust(nullptr));
+}
+
+// Tests |GetCertFailureStatusFromTrust| with trust object that has not been
+// evaluated backed by ok_cert.pem cert.
+TEST(CertVerifyProcIOSTest, StatusForNotEvaluatedTrust) {
+ CertStatus status = CertVerifyProcIOS::GetCertFailureStatusFromTrust(
+ CreateSecTrust("ok_cert.pem"));
+ EXPECT_TRUE(status & CERT_STATUS_COMMON_NAME_INVALID);
+ EXPECT_TRUE(status & CERT_STATUS_AUTHORITY_INVALID);
+ EXPECT_FALSE(status & CERT_STATUS_DATE_INVALID);
+}
+
+// Tests |GetCertFailureStatusFromTrust| with evaluated trust object backed by
+// expired_cert.pem cert.
+TEST(CertVerifyProcIOSTest, StatusForEvaluatedTrust) {
+ base::ScopedCFTypeRef<SecTrustRef> trust(CreateSecTrust("expired_cert.pem"));
+ ASSERT_TRUE(trust);
+ SecTrustEvaluate(trust, nullptr);
+
+ CertStatus status = CertVerifyProcIOS::GetCertFailureStatusFromTrust(trust);
+ EXPECT_TRUE(status & CERT_STATUS_COMMON_NAME_INVALID);
+ EXPECT_TRUE(status & CERT_STATUS_AUTHORITY_INVALID);
+ EXPECT_TRUE(status & CERT_STATUS_DATE_INVALID);
+}
+
+} // namespace net
diff --git a/chromium/net/cert/cert_verify_proc_mac.cc b/chromium/net/cert/cert_verify_proc_mac.cc
index 07a49a234b0..08f1b887f59 100644
--- a/chromium/net/cert/cert_verify_proc_mac.cc
+++ b/chromium/net/cert/cert_verify_proc_mac.cc
@@ -15,6 +15,7 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/mac/mac_logging.h"
+#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/sha1.h"
#include "base/strings/string_piece.h"
@@ -28,6 +29,10 @@
#include "net/cert/cert_verifier.h"
#include "net/cert/cert_verify_result.h"
#include "net/cert/crl_set.h"
+#include "net/cert/ev_root_ca_metadata.h"
+#include "net/cert/internal/certificate_policies.h"
+#include "net/cert/internal/parsed_certificate.h"
+#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_mac.h"
@@ -37,12 +42,6 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-// From 10.7.2 libsecurity_keychain-55035/lib/SecTrustPriv.h, for use with
-// SecTrustCopyExtendedResult.
-#ifndef kSecEVOrganizationName
-#define kSecEVOrganizationName CFSTR("Organization")
-#endif
-
using base::ScopedCFTypeRef;
namespace net {
@@ -148,21 +147,19 @@ CertStatus CertStatusFromOSStatus(OSStatus status) {
}
// Creates a series of SecPolicyRefs to be added to a SecTrustRef used to
-// validate a certificate for an SSL server. |hostname| contains the name of
-// the SSL server that the certificate should be verified against. |flags| is
-// a bitwise-OR of VerifyFlags that can further alter how trust is validated,
-// such as how revocation is checked. If successful, returns noErr, and
-// stores the resultant array of SecPolicyRefs in |policies|.
-OSStatus CreateTrustPolicies(const std::string& hostname,
- int flags,
- ScopedCFTypeRef<CFArrayRef>* policies) {
+// validate a certificate for an SSL server. |flags| is a bitwise-OR of
+// VerifyFlags that can further alter how trust is validated, such as how
+// revocation is checked. If successful, returns noErr, and stores the
+// resultant array of SecPolicyRefs in |policies|.
+OSStatus CreateTrustPolicies(int flags, ScopedCFTypeRef<CFArrayRef>* policies) {
ScopedCFTypeRef<CFMutableArrayRef> local_policies(
CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
if (!local_policies)
return memFullErr;
SecPolicyRef ssl_policy;
- OSStatus status = x509_util::CreateSSLServerPolicy(hostname, &ssl_policy);
+ OSStatus status =
+ x509_util::CreateSSLServerPolicy(std::string(), &ssl_policy);
if (status)
return status;
CFArrayAppendValue(local_policies, ssl_policy);
@@ -172,9 +169,7 @@ OSStatus CreateTrustPolicies(const std::string& hostname,
// revocation checking policies and instead respect the application-level
// revocation preference.
status = x509_util::CreateRevocationPolicies(
- (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED),
- (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY),
- local_policies);
+ (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED), local_policies);
if (status)
return status;
@@ -273,6 +268,113 @@ void GetCertChainInfo(CFArrayRef cert_chain,
X509Certificate::CreateFromHandle(verified_cert, verified_chain);
}
+using ExtensionsMap = std::map<net::der::Input, net::ParsedExtension>;
+
+// Helper that looks up an extension by OID given a map of extensions.
+bool GetExtensionValue(const ExtensionsMap& extensions,
+ const net::der::Input& oid,
+ net::der::Input* value) {
+ auto it = extensions.find(oid);
+ if (it == extensions.end())
+ return false;
+ *value = it->second.value;
+ return true;
+}
+
+// Checks if |*cert| has a Certificate Policies extension containing either
+// of |ev_policy_oid| or anyPolicy.
+bool HasPolicyOrAnyPolicy(const ParsedCertificate* cert,
+ const der::Input& ev_policy_oid) {
+ der::Input extension_value;
+ if (!GetExtensionValue(cert->unparsed_extensions(), CertificatePoliciesOid(),
+ &extension_value)) {
+ return false;
+ }
+
+ std::vector<der::Input> policies;
+ if (!ParseCertificatePoliciesExtension(extension_value, &policies))
+ return false;
+
+ for (const der::Input& policy_oid : policies) {
+ if (policy_oid == ev_policy_oid || policy_oid == AnyPolicy())
+ return true;
+ }
+ return false;
+}
+
+// Looks for known EV policy OIDs in |cert_input|, if one is found it will be
+// stored in |*ev_policy_oid| as a DER-encoded OID value (no tag or length).
+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(der_cert, {}, nullptr));
+ if (!cert)
+ return;
+
+ der::Input extension_value;
+ if (!GetExtensionValue(cert->unparsed_extensions(), CertificatePoliciesOid(),
+ &extension_value)) {
+ return;
+ }
+
+ std::vector<der::Input> policies;
+ if (!ParseCertificatePoliciesExtension(extension_value, &policies))
+ return;
+
+ EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
+ for (const der::Input& policy_oid : policies) {
+ if (metadata->IsEVPolicyOID(policy_oid)) {
+ *ev_policy_oid = policy_oid.AsString();
+ return;
+ }
+ }
+}
+
+// Checks that the certificate chain of |cert| has policies consistent with
+// |ev_policy_oid_string|. The leaf is not checked, as it is assumed that is
+// where the policy came from.
+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();
+
+ // Root should have matching policy in EVRootCAMetadata.
+ std::string der_cert;
+ if (!X509Certificate::GetDEREncoded(os_cert_chain.back(), &der_cert))
+ return false;
+ SHA1HashValue weak_fingerprint;
+ base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(der_cert.data()),
+ der_cert.size(), weak_fingerprint.data);
+ EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
+ if (!metadata->HasEVPolicyOID(weak_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;
+ scoped_refptr<ParsedCertificate> intermediate_cert(
+ ParsedCertificate::Create(der_cert, {}, nullptr));
+ if (!intermediate_cert)
+ return false;
+ if (!HasPolicyOrAnyPolicy(intermediate_cert.get(), ev_policy_oid))
+ return false;
+ }
+
+ return true;
+}
+
void AppendPublicKeyHashes(CFArrayRef chain,
HashValueVector* hashes) {
const CFIndex n = CFArrayGetCount(chain);
@@ -299,9 +401,35 @@ void AppendPublicKeyHashes(CFArrayRef chain,
}
}
-bool CheckRevocationWithCRLSet(CFArrayRef chain, CRLSet* crl_set) {
+enum CRLSetResult {
+ kCRLSetOk,
+ kCRLSetRevoked,
+ kCRLSetUnknown,
+};
+
+// CheckRevocationWithCRLSet attempts to check each element of |cert_list|
+// against |crl_set|. It returns:
+// kCRLSetRevoked: if any element of the chain is known to have been revoked.
+// kCRLSetUnknown: if there is no fresh information about the leaf
+// certificate in the chain or if the CRLSet has expired.
+//
+// Only the leaf certificate is considered for coverage because some
+// intermediates have CRLs with no revocations (after filtering) and
+// those CRLs are pruned from the CRLSet at generation time. This means
+// that some EV sites would otherwise take the hit of an OCSP lookup for
+// no reason.
+// kCRLSetOk: otherwise.
+CRLSetResult CheckRevocationWithCRLSet(CFArrayRef chain, CRLSet* crl_set) {
if (CFArrayGetCount(chain) == 0)
- return true;
+ return kCRLSetOk;
+
+ // error is set to true if any errors are found. It causes such chains to be
+ // considered as not covered.
+ bool error = false;
+ // last_covered is set to the coverage state of the previous certificate. The
+ // certificates are iterated over backwards thus, after the iteration,
+ // |last_covered| contains the coverage state of the leaf certificate.
+ bool last_covered = false;
// We iterate from the root certificate down to the leaf, keeping track of
// the issuer's SPKI at each step.
@@ -314,6 +442,7 @@ bool CheckRevocationWithCRLSet(CFArrayRef chain, CRLSet* crl_set) {
OSStatus err = SecCertificateGetData(cert, &cert_data);
if (err != noErr) {
NOTREACHED();
+ error = true;
continue;
}
base::StringPiece der_bytes(reinterpret_cast<const char*>(cert_data.Data),
@@ -321,6 +450,7 @@ bool CheckRevocationWithCRLSet(CFArrayRef chain, CRLSet* crl_set) {
base::StringPiece spki;
if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) {
NOTREACHED();
+ error = true;
continue;
}
@@ -328,12 +458,14 @@ bool CheckRevocationWithCRLSet(CFArrayRef chain, CRLSet* crl_set) {
x509_util::CSSMCachedCertificate cached_cert;
if (cached_cert.Init(cert) != CSSM_OK) {
NOTREACHED();
+ error = true;
continue;
}
x509_util::CSSMFieldValue serial_number;
err = cached_cert.GetField(&CSSMOID_X509V1SerialNumber, &serial_number);
if (err || !serial_number.field()) {
NOTREACHED();
+ error = true;
continue;
}
@@ -350,17 +482,23 @@ bool CheckRevocationWithCRLSet(CFArrayRef chain, CRLSet* crl_set) {
switch (result) {
case CRLSet::REVOKED:
- return false;
+ return kCRLSetRevoked;
case CRLSet::UNKNOWN:
+ last_covered = false;
+ continue;
case CRLSet::GOOD:
+ last_covered = true;
continue;
default:
NOTREACHED();
- return false;
+ error = true;
+ continue;
}
}
- return true;
+ if (error || !last_covered || crl_set->IsExpired())
+ return kCRLSetUnknown;
+ return kCRLSetOk;
}
// Builds and evaluates a SecTrustRef for the certificate chain contained
@@ -377,6 +515,7 @@ bool CheckRevocationWithCRLSet(CFArrayRef chain, CRLSet* crl_set) {
int BuildAndEvaluateSecTrustRef(CFArrayRef cert_array,
CFArrayRef trust_policies,
int flags,
+ CFArrayRef keychain_search_list,
ScopedCFTypeRef<SecTrustRef>* trust_ref,
SecTrustResultType* trust_result,
ScopedCFTypeRef<CFArrayRef>* verified_chain,
@@ -394,6 +533,12 @@ int BuildAndEvaluateSecTrustRef(CFArrayRef cert_array,
return NetErrorFromOSStatus(status);
}
+ if (keychain_search_list) {
+ status = SecTrustSetKeychains(tmp_trust, keychain_search_list);
+ if (status)
+ return NetErrorFromOSStatus(status);
+ }
+
CSSM_APPLE_TP_ACTION_DATA tp_action_data;
memset(&tp_action_data, 0, sizeof(tp_action_data));
tp_action_data.Version = CSSM_APPLE_TP_ACTION_VERSION;
@@ -515,42 +660,21 @@ class OSXKnownRootHelper {
base::LazyInstance<OSXKnownRootHelper>::Leaky g_known_roots =
LAZY_INSTANCE_INITIALIZER;
-} // namespace
-
-CertVerifyProcMac::CertVerifyProcMac() {}
-
-CertVerifyProcMac::~CertVerifyProcMac() {}
-
-bool CertVerifyProcMac::SupportsAdditionalTrustAnchors() const {
- return false;
-}
-
-bool CertVerifyProcMac::SupportsOCSPStapling() const {
- // TODO(rsleevi): Plumb an OCSP response into the Mac system library.
- // https://crbug.com/430714
- return false;
-}
-
-int CertVerifyProcMac::VerifyInternal(
- X509Certificate* cert,
- const std::string& hostname,
- const std::string& ocsp_response,
- int flags,
- CRLSet* crl_set,
- const CertificateList& additional_trust_anchors,
- CertVerifyResult* verify_result) {
+// Runs path building & verification loop for |cert|, given |flags|. This is
+// split into a separate function so verification can be repeated with different
+// flags. This function does not handle EV.
+int VerifyWithGivenFlags(X509Certificate* cert,
+ const std::string& hostname,
+ const int flags,
+ CRLSet* crl_set,
+ CertVerifyResult* verify_result,
+ CRLSetResult* completed_chain_crl_result) {
ScopedCFTypeRef<CFArrayRef> trust_policies;
- OSStatus status = CreateTrustPolicies(hostname, flags, &trust_policies);
+ OSStatus status = CreateTrustPolicies(flags, &trust_policies);
if (status)
return NetErrorFromOSStatus(status);
- // Create and configure a SecTrustRef, which takes our certificate(s)
- // and our SSL SecPolicyRef. SecTrustCreateWithCertificates() takes an
- // array of certificates, the first of which is the certificate we're
- // verifying, and the subsequent (optional) certificates are used for
- // chain building.
- ScopedCFTypeRef<CFMutableArrayRef> cert_array(
- cert->CreateOSCertChainForCert());
+ *completed_chain_crl_result = kCRLSetUnknown;
// Serialize all calls that may use the Keychain, to work around various
// issues in OS X 10.6+ with multi-threaded access to Security.framework.
@@ -597,6 +721,10 @@ int CertVerifyProcMac::VerifyInternal(
// present in the AIA of A is signed using a strong algorithm. Since a
// 'strong' chain exists, it would be desirable to prefer this chain.
//
+ // - A user keychain may contain a less desirable intermediate or root.
+ // OS X gives the user keychains higher priority than the system keychain,
+ // so it may build a weak chain.
+ //
// Because of this, the code below first attempts to validate the peer's
// identity using the supplied chain. If it is not trusted (e.g. the OS only
// trusts C, but the version of C signed by D was sent, and D is not trusted),
@@ -605,73 +733,164 @@ int CertVerifyProcMac::VerifyInternal(
// chain is found, it is used, otherwise, the algorithm continues until only
// the peer's certificate remains.
//
+ // If the loop does not find a trusted chain, the loop will be repeated with
+ // the keychain search order altered to give priority to the System Roots
+ // keychain.
+ //
// This does cause a performance hit for these users, but only in cases where
// OS X is building weaker chains than desired, or when it would otherwise
// fail the connection.
- while (CFArrayGetCount(cert_array) > 0) {
- ScopedCFTypeRef<SecTrustRef> temp_ref;
- SecTrustResultType temp_trust_result = kSecTrustResultDeny;
- ScopedCFTypeRef<CFArrayRef> temp_chain;
- CSSM_TP_APPLE_EVIDENCE_INFO* temp_chain_info = NULL;
-
- int rv = BuildAndEvaluateSecTrustRef(cert_array, trust_policies, flags,
- &temp_ref, &temp_trust_result,
- &temp_chain, &temp_chain_info);
- if (rv != OK)
- return rv;
-
- bool untrusted = (temp_trust_result != kSecTrustResultUnspecified &&
- temp_trust_result != kSecTrustResultProceed);
- bool weak_chain = false;
- if (CFArrayGetCount(temp_chain) == 0) {
- // If the chain is empty, it cannot be trusted or have recoverable
- // errors.
- DCHECK(untrusted);
- DCHECK_NE(kSecTrustResultRecoverableTrustFailure, temp_trust_result);
- } else {
- CertVerifyResult temp_verify_result;
- bool leaf_is_weak = false;
- GetCertChainInfo(temp_chain, temp_chain_info, &temp_verify_result,
- &leaf_is_weak);
- weak_chain = !leaf_is_weak &&
- (temp_verify_result.has_md2 || temp_verify_result.has_md4 ||
- temp_verify_result.has_md5 || temp_verify_result.has_sha1);
+ for (bool try_reordered_keychain : {false, true}) {
+ ScopedCFTypeRef<CFArrayRef> scoped_alternate_keychain_search_list;
+ if (TestKeychainSearchList::HasInstance()) {
+ // Unit tests need to be able to hermetically simulate situations where a
+ // user has an undesirable certificate in a per-user keychain.
+ // Adding/Removing a Keychain using SecKeychainCreate/SecKeychainDelete
+ // has global side effects, which would break other tests and processes
+ // running on the same machine, so instead tests may load pre-created
+ // keychains using SecKeychainOpen and then inject them through
+ // TestKeychainSearchList.
+ CFArrayRef keychain_search_list;
+ status = TestKeychainSearchList::GetInstance()->CopySearchList(
+ &keychain_search_list);
+ if (status)
+ return NetErrorFromOSStatus(status);
+ scoped_alternate_keychain_search_list.reset(keychain_search_list);
}
- // Set the result to the current chain if:
- // - This is the first verification attempt. This ensures that if
- // everything is awful (e.g. it may just be an untrusted cert), that
- // what is reported is exactly what was sent by the server
- // - If the current chain is trusted, and the old chain was not trusted,
- // then prefer this chain. This ensures that if there is at least a
- // valid path to a trust anchor, it's preferred over reporting an error.
- // - If the current chain is trusted, and the old chain is trusted, but
- // the old chain contained weak algorithms while the current chain only
- // contains strong algorithms, then prefer the current chain over the
- // old chain.
- //
- // Note: If the leaf certificate itself is weak, then the only
- // consideration is whether or not there is a trusted chain. That's
- // because no amount of path discovery will fix a weak leaf.
- if (!trust_ref || (!untrusted && (candidate_untrusted ||
- (candidate_weak && !weak_chain)))) {
- trust_ref = temp_ref;
- trust_result = temp_trust_result;
- completed_chain = temp_chain;
- chain_info = temp_chain_info;
-
- candidate_untrusted = untrusted;
- candidate_weak = weak_chain;
+ if (try_reordered_keychain) {
+ // If a TestKeychainSearchList is present, it will have already set
+ // |scoped_alternate_keychain_search_list|, which will be used as the
+ // basis for reordering the keychain. Otherwise, get the current keychain
+ // search list and use that.
+ if (!scoped_alternate_keychain_search_list) {
+ CFArrayRef keychain_search_list;
+ status = SecKeychainCopySearchList(&keychain_search_list);
+ if (status)
+ return NetErrorFromOSStatus(status);
+ scoped_alternate_keychain_search_list.reset(keychain_search_list);
+ }
+ CFMutableArrayRef mutable_keychain_search_list = CFArrayCreateMutableCopy(
+ kCFAllocatorDefault,
+ CFArrayGetCount(scoped_alternate_keychain_search_list.get()) + 1,
+ scoped_alternate_keychain_search_list.get());
+ if (!mutable_keychain_search_list)
+ return ERR_OUT_OF_MEMORY;
+ scoped_alternate_keychain_search_list.reset(mutable_keychain_search_list);
+
+ SecKeychainRef keychain;
+ // Get a reference to the System Roots keychain. The System Roots
+ // keychain is not normally present in the keychain search list, but is
+ // implicitly checked after the keychains in the search list. By
+ // including it directly, force it to be checked first. This is a gross
+ // hack, but the path is known to be valid on OS X 10.9-10.11.
+ status = SecKeychainOpen(
+ "/System/Library/Keychains/SystemRootCertificates.keychain",
+ &keychain);
+ if (status)
+ return NetErrorFromOSStatus(status);
+ ScopedCFTypeRef<SecKeychainRef> scoped_keychain(keychain);
+
+ CFArrayInsertValueAtIndex(mutable_keychain_search_list, 0, keychain);
+ }
+
+ ScopedCFTypeRef<CFMutableArrayRef> cert_array(
+ cert->CreateOSCertChainForCert());
+
+ // Beginning with the certificate chain as supplied by the server, attempt
+ // to verify the chain. If a failure is encountered, trim a certificate
+ // from the end (so long as one remains) and retry, in the hope of forcing
+ // OS X to find a better path.
+ while (CFArrayGetCount(cert_array) > 0) {
+ ScopedCFTypeRef<SecTrustRef> temp_ref;
+ SecTrustResultType temp_trust_result = kSecTrustResultDeny;
+ ScopedCFTypeRef<CFArrayRef> temp_chain;
+ CSSM_TP_APPLE_EVIDENCE_INFO* temp_chain_info = NULL;
+
+ int rv = BuildAndEvaluateSecTrustRef(
+ cert_array, trust_policies, flags,
+ scoped_alternate_keychain_search_list.get(), &temp_ref,
+ &temp_trust_result, &temp_chain, &temp_chain_info);
+ if (rv != OK)
+ return rv;
+
+ // Check to see if the path |temp_chain| has been revoked. This is less
+ // than ideal to perform after path building, rather than during, because
+ // there may be multiple paths to trust anchors, and only some of them
+ // are revoked. Ideally, CRLSets would be part of path building, which
+ // they are when using NSS (Linux) or CryptoAPI (Windows).
+ //
+ // The CRLSet checking is performed inside the loop in the hope that if a
+ // path is revoked, it's an older path, and the only reason it was built
+ // is because the server forced it (by supplying an older or less
+ // desirable intermediate) or because the user had installed a
+ // certificate in their Keychain forcing this path. However, this means
+ // its still possible for a CRLSet block of an intermediate to prevent
+ // access, even when there is a 'good' chain. To fully remedy this, a
+ // solution might be to have CRLSets contain enough knowledge about what
+ // the 'desired' path might be, but for the time being, the
+ // implementation is kept as 'simple' as it can be.
+ CRLSetResult crl_result = kCRLSetUnknown;
+ if (crl_set)
+ crl_result = CheckRevocationWithCRLSet(temp_chain, crl_set);
+ bool untrusted = (temp_trust_result != kSecTrustResultUnspecified &&
+ temp_trust_result != kSecTrustResultProceed) ||
+ crl_result == kCRLSetRevoked;
+ bool weak_chain = false;
+ if (CFArrayGetCount(temp_chain) == 0) {
+ // If the chain is empty, it cannot be trusted or have recoverable
+ // errors.
+ DCHECK(untrusted);
+ DCHECK_NE(kSecTrustResultRecoverableTrustFailure, temp_trust_result);
+ } else {
+ CertVerifyResult temp_verify_result;
+ bool leaf_is_weak = false;
+ GetCertChainInfo(temp_chain, temp_chain_info, &temp_verify_result,
+ &leaf_is_weak);
+ weak_chain =
+ !leaf_is_weak &&
+ (temp_verify_result.has_md2 || temp_verify_result.has_md4 ||
+ temp_verify_result.has_md5 || temp_verify_result.has_sha1);
+ }
+ // Set the result to the current chain if:
+ // - This is the first verification attempt. This ensures that if
+ // everything is awful (e.g. it may just be an untrusted cert), that
+ // what is reported is exactly what was sent by the server
+ // - If the current chain is trusted, and the old chain was not trusted,
+ // then prefer this chain. This ensures that if there is at least a
+ // valid path to a trust anchor, it's preferred over reporting an error.
+ // - If the current chain is trusted, and the old chain is trusted, but
+ // the old chain contained weak algorithms while the current chain only
+ // contains strong algorithms, then prefer the current chain over the
+ // old chain.
+ //
+ // Note: If the leaf certificate itself is weak, then the only
+ // consideration is whether or not there is a trusted chain. That's
+ // because no amount of path discovery will fix a weak leaf.
+ if (!trust_ref || (!untrusted && (candidate_untrusted ||
+ (candidate_weak && !weak_chain)))) {
+ trust_ref = temp_ref;
+ trust_result = temp_trust_result;
+ completed_chain = temp_chain;
+ *completed_chain_crl_result = crl_result;
+ chain_info = temp_chain_info;
+
+ candidate_untrusted = untrusted;
+ candidate_weak = weak_chain;
+ }
+ // Short-circuit when a current, trusted chain is found.
+ if (!untrusted && !weak_chain)
+ break;
+ CFArrayRemoveValueAtIndex(cert_array, CFArrayGetCount(cert_array) - 1);
}
// Short-circuit when a current, trusted chain is found.
- if (!untrusted && !weak_chain)
+ if (!candidate_untrusted && !candidate_weak)
break;
- CFArrayRemoveValueAtIndex(cert_array, CFArrayGetCount(cert_array) - 1);
}
if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED)
verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
- if (crl_set && !CheckRevocationWithCRLSet(completed_chain, crl_set))
+ if (*completed_chain_crl_result == kCRLSetRevoked)
verify_result->cert_status |= CERT_STATUS_REVOKED;
if (CFArrayGetCount(completed_chain) > 0) {
@@ -686,6 +905,7 @@ int CertVerifyProcMac::VerifyInternal(
// the CSSMERR_TP_VERIFY_ACTION_FAILED to CERT_STATUS_INVALID if the only
// error was due to an unsupported key size.
bool policy_failed = false;
+ bool policy_fail_already_mapped = false;
bool weak_key_or_signature_algorithm = false;
// Evaluate the results
@@ -743,20 +963,35 @@ int CertVerifyProcMac::VerifyInternal(
if (policy_failed &&
chain_info[index].StatusCodes[status_code_index] ==
CSSMERR_TP_INVALID_CERTIFICATE) {
- mapped_status = CERT_STATUS_WEAK_SIGNATURE_ALGORITHM;
- weak_key_or_signature_algorithm = true;
+ mapped_status = CERT_STATUS_WEAK_SIGNATURE_ALGORITHM;
+ weak_key_or_signature_algorithm = true;
+ policy_fail_already_mapped = true;
+ } else if (policy_failed &&
+ (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) &&
+ chain_info[index].StatusCodes[status_code_index] ==
+ CSSMERR_TP_VERIFY_ACTION_FAILED &&
+ base::mac::IsAtLeastOS10_12()) {
+ // On 10.12, using kSecRevocationRequirePositiveResponse flag
+ // causes a CSSMERR_TP_VERIFY_ACTION_FAILED status if revocation
+ // couldn't be checked. (Note: even if the cert had no
+ // crlDistributionPoints or OCSP AIA.)
+ mapped_status = CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
+ policy_fail_already_mapped = true;
} else {
- mapped_status = CertStatusFromOSStatus(
- chain_info[index].StatusCodes[status_code_index]);
- if (mapped_status == CERT_STATUS_WEAK_KEY)
- weak_key_or_signature_algorithm = true;
+ mapped_status = CertStatusFromOSStatus(
+ chain_info[index].StatusCodes[status_code_index]);
+ if (mapped_status == CERT_STATUS_WEAK_KEY) {
+ weak_key_or_signature_algorithm = true;
+ policy_fail_already_mapped = true;
+ }
}
verify_result->cert_status |= mapped_status;
}
}
- if (policy_failed && !weak_key_or_signature_algorithm) {
+ if (policy_failed && !policy_fail_already_mapped) {
// If CSSMERR_TP_VERIFY_ACTION_FAILED wasn't returned due to a weak
- // key, map it back to an appropriate error code.
+ // key or problem checking revocation, map it back to an appropriate
+ // error code.
verify_result->cert_status |= CertStatusFromOSStatus(cssm_result);
}
if (!IsCertStatusError(verify_result->cert_status)) {
@@ -798,42 +1033,74 @@ int CertVerifyProcMac::VerifyInternal(
if (IsCertStatusError(verify_result->cert_status))
return MapCertStatusToNetError(verify_result->cert_status);
- if (flags & CertVerifier::VERIFY_EV_CERT) {
- // Determine the certificate's EV status using SecTrustCopyExtendedResult(),
- // which is an internal/private API function added in OS X 10.5.7.
- // Note: "ExtendedResult" means extended validation results.
- CFBundleRef bundle =
- CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security"));
- if (bundle) {
- SecTrustCopyExtendedResultFuncPtr copy_extended_result =
- reinterpret_cast<SecTrustCopyExtendedResultFuncPtr>(
- CFBundleGetFunctionPointerForName(bundle,
- CFSTR("SecTrustCopyExtendedResult")));
- if (copy_extended_result) {
- CFDictionaryRef ev_dict_temp = NULL;
- status = copy_extended_result(trust_ref, &ev_dict_temp);
- ScopedCFTypeRef<CFDictionaryRef> ev_dict(ev_dict_temp);
- ev_dict_temp = NULL;
- if (status == noErr && ev_dict) {
- // In 10.7.3, SecTrustCopyExtendedResult returns noErr and populates
- // ev_dict even for non-EV certificates, but only EV certificates
- // will cause ev_dict to contain kSecEVOrganizationName. In previous
- // releases, SecTrustCopyExtendedResult would only return noErr and
- // populate ev_dict for EV certificates, but would always include
- // kSecEVOrganizationName in that case, so checking for this key is
- // appropriate for all known versions of SecTrustCopyExtendedResult.
- // The actual organization name is unneeded here and can be accessed
- // through other means. All that matters here is the OS' conception
- // of whether or not the certificate is EV.
- if (CFDictionaryContainsKey(ev_dict,
- kSecEVOrganizationName)) {
- verify_result->cert_status |= CERT_STATUS_IS_EV;
- if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY)
- verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
- }
- }
- }
+ return OK;
+}
+
+} // namespace
+
+CertVerifyProcMac::CertVerifyProcMac() {}
+
+CertVerifyProcMac::~CertVerifyProcMac() {}
+
+bool CertVerifyProcMac::SupportsAdditionalTrustAnchors() const {
+ return false;
+}
+
+bool CertVerifyProcMac::SupportsOCSPStapling() const {
+ // TODO(rsleevi): Plumb an OCSP response into the Mac system library.
+ // https://crbug.com/430714
+ return false;
+}
+
+int CertVerifyProcMac::VerifyInternal(
+ X509Certificate* cert,
+ const std::string& hostname,
+ const std::string& ocsp_response,
+ int flags,
+ CRLSet* crl_set,
+ const CertificateList& additional_trust_anchors,
+ CertVerifyResult* verify_result) {
+ // Save the input state of |*verify_result|, which may be needed to re-do
+ // verification with different flags.
+ const CertVerifyResult input_verify_result(*verify_result);
+
+ // If EV verification is enabled, check for EV policy in leaf cert.
+ std::string candidate_ev_policy_oid;
+ if (flags & CertVerifier::VERIFY_EV_CERT)
+ GetCandidateEVPolicy(cert, &candidate_ev_policy_oid);
+
+ CRLSetResult completed_chain_crl_result;
+ int rv = VerifyWithGivenFlags(cert, hostname, flags, crl_set, verify_result,
+ &completed_chain_crl_result);
+ if (rv != OK)
+ return rv;
+
+ if (!candidate_ev_policy_oid.empty() &&
+ CheckCertChainEV(verify_result->verified_cert.get(),
+ candidate_ev_policy_oid)) {
+ // EV policies check out and the verification succeeded. See if revocation
+ // checking still needs to be done before it can be marked as EV.
+ if (completed_chain_crl_result == kCRLSetUnknown &&
+ (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY) &&
+ !(flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED)) {
+ // If this is an EV cert and it wasn't covered by CRLSets and revocation
+ // checking wasn't already on, try again with revocation forced on.
+ //
+ // Restore the input state of |*verify_result|, so that the
+ // re-verification starts with a clean slate.
+ *verify_result = input_verify_result;
+ int tmp_rv = VerifyWithGivenFlags(
+ verify_result->verified_cert.get(), hostname,
+ flags | CertVerifier::VERIFY_REV_CHECKING_ENABLED, crl_set,
+ verify_result, &completed_chain_crl_result);
+ // If re-verification failed, return those results without setting EV
+ // status.
+ if (tmp_rv != OK)
+ return tmp_rv;
+ // Otherwise, fall through and add the EV status flag.
}
+ // EV cert and it was covered by CRLSets or revocation checking passed.
+ verify_result->cert_status |= CERT_STATUS_IS_EV;
}
return OK;
diff --git a/chromium/net/cert/cert_verify_proc_nss.cc b/chromium/net/cert/cert_verify_proc_nss.cc
index 673ec29a4ca..1ac27cb48ef 100644
--- a/chromium/net/cert/cert_verify_proc_nss.cc
+++ b/chromium/net/cert/cert_verify_proc_nss.cc
@@ -282,12 +282,12 @@ CRLSetResult CheckRevocationWithCRLSet(const CERTCertList* cert_list,
if (root)
certs.push_back(root);
- // error is set to true if any errors are found. It causes such chains to be
- // considered as not covered.
+ // Set to true if any errors are found, which will cause such chains to not be
+ // treated as covered by the CRLSet.
bool error = false;
- // last_covered is set to the coverage state of the previous certificate. The
- // certificates are iterated over backwards thus, after the iteration,
- // |last_covered| contains the coverage state of the leaf certificate.
+ // Set to the coverage state of the previous certificate. As the certificates
+ // are iterated over from root to leaf, at the end of the iteration, this
+ // indicates the coverage state of the leaf certificate.
bool last_covered = false;
// We iterate from the root certificate down to the leaf, keeping track of
diff --git a/chromium/net/cert/cert_verify_proc_unittest.cc b/chromium/net/cert/cert_verify_proc_unittest.cc
index 12b31497c81..ee6a9b14f55 100644
--- a/chromium/net/cert/cert_verify_proc_unittest.cc
+++ b/chromium/net/cert/cert_verify_proc_unittest.cc
@@ -25,14 +25,23 @@
#include "net/cert/test_root_certs.h"
#include "net/cert/x509_certificate.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_certificate_data.h"
#include "net/test/test_data_directory.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_ANDROID)
#include "base/android/build_info.h"
#endif
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include "net/cert/test_keychain_search_list_mac.h"
+#endif
+
+using net::test::IsError;
+using net::test::IsOk;
+
using base::HexEncode;
namespace net {
@@ -191,7 +200,7 @@ TEST_F(CertVerifyProcTest, MAYBE_EVVerification) {
crl_set.get(),
empty_cert_list_,
&verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_IS_EV);
}
@@ -223,15 +232,15 @@ TEST_F(CertVerifyProcTest, DISABLED_PaypalNullCertParsing) {
empty_cert_list_,
&verify_result);
#if defined(USE_NSS_CERTS) || defined(OS_ANDROID)
- EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_COMMON_NAME_INVALID));
#elif defined(OS_IOS) && TARGET_IPHONE_SIMULATOR
// iOS returns a ERR_CERT_INVALID error on the simulator, while returning
// ERR_CERT_AUTHORITY_INVALID on the real device.
- EXPECT_EQ(ERR_CERT_INVALID, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_INVALID));
#else
// TOOD(bulach): investigate why macosx and win aren't returning
// ERR_CERT_INVALID or ERR_CERT_COMMON_NAME_INVALID.
- EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
#endif
// Either the system crypto library should correctly report a certificate
// name mismatch, or our certificate blacklist should cause us to report an
@@ -278,7 +287,7 @@ TEST_F(CertVerifyProcTest, MAYBE_IntermediateCARequireExplicitPolicy) {
NULL,
empty_cert_list_,
&verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(0u, verify_result.cert_status);
}
@@ -301,7 +310,7 @@ TEST_F(CertVerifyProcTest, RejectExpiredCert) {
CertVerifyResult verify_result;
int error = Verify(cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_,
&verify_result);
- EXPECT_EQ(ERR_CERT_DATE_INVALID, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_DATE_INVALID));
EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_DATE_INVALID);
}
@@ -379,7 +388,7 @@ TEST_F(CertVerifyProcTest, RejectWeakKeys) {
EXPECT_NE(CERT_STATUS_INVALID,
verify_result.cert_status & CERT_STATUS_INVALID);
} else {
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(0U, verify_result.cert_status & CERT_STATUS_WEAK_KEY);
}
}
@@ -431,7 +440,7 @@ TEST_F(CertVerifyProcTest, MAYBE_ExtraneousMD5RootCert) {
NULL,
empty_cert_list_,
&verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
// The extra MD5 root should be discarded
ASSERT_TRUE(verify_result.verified_cert.get());
@@ -557,12 +566,12 @@ TEST_F(CertVerifyProcTest, NameConstraintsOk) {
NULL,
empty_cert_list_,
&verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(0U, verify_result.cert_status);
error = Verify(leaf.get(), "foo.test2.example.com", flags, NULL,
empty_cert_list_, &verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(0U, verify_result.cert_status);
}
@@ -597,7 +606,7 @@ TEST_F(CertVerifyProcTest, NameConstraintsFailure) {
NULL,
empty_cert_list_,
&verify_result);
- EXPECT_EQ(ERR_CERT_NAME_CONSTRAINT_VIOLATION, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_NAME_CONSTRAINT_VIOLATION));
EXPECT_EQ(CERT_STATUS_NAME_CONSTRAINT_VIOLATION,
verify_result.cert_status & CERT_STATUS_NAME_CONSTRAINT_VIOLATION);
}
@@ -657,7 +666,7 @@ TEST_F(CertVerifyProcTest, DISABLED_TestKnownRoot) {
// against agl. See also PublicKeyHashes.
int error = Verify(cert_chain.get(), "twitter.com", flags, NULL,
empty_cert_list_, &verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_TRUE(verify_result.is_issued_by_known_root);
}
@@ -686,7 +695,7 @@ TEST_F(CertVerifyProcTest, DISABLED_PublicKeyHashes) {
// against agl. See also TestKnownRoot.
int error = Verify(cert_chain.get(), "twitter.com", flags, NULL,
empty_cert_list_, &verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
ASSERT_LE(3U, verify_result.public_key_hashes.size());
HashValueVector sha1_hashes;
@@ -738,9 +747,9 @@ TEST_F(CertVerifyProcTest, InvalidKeyUsage) {
// This certificate has two errors: "invalid key usage" and "untrusted CA".
// However, OpenSSL returns only one (the latter), and we can't detect
// the other errors.
- EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
#else
- EXPECT_EQ(ERR_CERT_INVALID, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_INVALID));
EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_INVALID);
#endif
// TODO(wtc): fix http://crbug.com/75520 to get all the certificate errors
@@ -790,7 +799,7 @@ TEST_F(CertVerifyProcTest, VerifyReturnChainBasic) {
NULL,
empty_cert_list_,
&verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
ASSERT_NE(static_cast<X509Certificate*>(NULL),
verify_result.verified_cert.get());
@@ -832,7 +841,7 @@ TEST_F(CertVerifyProcTest, IntranetHostsRejected) {
verify_proc_ = new MockCertVerifyProc(dummy_result);
error =
Verify(cert.get(), "intranet", 0, NULL, empty_cert_list_, &verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_NON_UNIQUE_NAME);
// However, if the CA is not well known, these should not be flagged:
@@ -841,7 +850,7 @@ TEST_F(CertVerifyProcTest, IntranetHostsRejected) {
verify_proc_ = new MockCertVerifyProc(dummy_result);
error =
Verify(cert.get(), "intranet", 0, NULL, empty_cert_list_, &verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_FALSE(verify_result.cert_status & CERT_STATUS_NON_UNIQUE_NAME);
}
@@ -868,7 +877,7 @@ TEST_F(CertVerifyProcTest, VerifyRejectsSHA1AfterDeprecation) {
ASSERT_TRUE(cert);
error = Verify(cert.get(), "127.0.0.1", 0, NULL, empty_cert_list_,
&verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_SHA1_SIGNATURE_PRESENT);
// Publicly trusted SHA-1 leaf certificates issued on/after 1 January 2016
@@ -885,7 +894,7 @@ TEST_F(CertVerifyProcTest, VerifyRejectsSHA1AfterDeprecation) {
ASSERT_TRUE(cert);
error = Verify(cert.get(), "127.0.0.1", 0, NULL, empty_cert_list_,
&verify_result);
- EXPECT_EQ(ERR_CERT_WEAK_SIGNATURE_ALGORITHM, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_WEAK_SIGNATURE_ALGORITHM));
EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_WEAK_SIGNATURE_ALGORITHM);
// Enterprise issued SHA-1 leaf certificates issued on/after 1 January 2016
@@ -902,7 +911,7 @@ TEST_F(CertVerifyProcTest, VerifyRejectsSHA1AfterDeprecation) {
ASSERT_TRUE(cert);
error = Verify(cert.get(), "127.0.0.1", 0, NULL, empty_cert_list_,
&verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_SHA1_SIGNATURE_PRESENT);
// Publicly trusted SHA-1 intermediates issued on/after 1 January 2016 are,
@@ -919,7 +928,7 @@ TEST_F(CertVerifyProcTest, VerifyRejectsSHA1AfterDeprecation) {
ASSERT_TRUE(cert);
error = Verify(cert.get(), "127.0.0.1", 0, NULL, empty_cert_list_,
&verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_SHA1_SIGNATURE_PRESENT);
}
@@ -962,7 +971,7 @@ TEST_F(CertVerifyProcTest, VerifyReturnChainProperlyOrdered) {
NULL,
empty_cert_list_,
&verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
ASSERT_NE(static_cast<X509Certificate*>(NULL),
verify_result.verified_cert.get());
@@ -1023,7 +1032,7 @@ TEST_F(CertVerifyProcTest, VerifyReturnChainFiltersUnrelatedCerts) {
NULL,
empty_cert_list_,
&verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
ASSERT_NE(static_cast<X509Certificate*>(NULL),
verify_result.verified_cert.get());
@@ -1065,7 +1074,7 @@ TEST_F(CertVerifyProcTest, AdditionalTrustAnchors) {
CertVerifyResult verify_result;
int error = Verify(
cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result);
- EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result.cert_status);
EXPECT_FALSE(verify_result.is_issued_by_additional_trust_anchor);
@@ -1074,7 +1083,7 @@ TEST_F(CertVerifyProcTest, AdditionalTrustAnchors) {
trust_anchors.push_back(ca_cert);
error = Verify(
cert.get(), "127.0.0.1", flags, NULL, trust_anchors, &verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(0U, verify_result.cert_status);
EXPECT_TRUE(verify_result.is_issued_by_additional_trust_anchor);
@@ -1082,7 +1091,7 @@ TEST_F(CertVerifyProcTest, AdditionalTrustAnchors) {
// should be skipped).
error = Verify(
cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result);
- EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result.cert_status);
EXPECT_FALSE(verify_result.is_issued_by_additional_trust_anchor);
}
@@ -1103,7 +1112,7 @@ TEST_F(CertVerifyProcTest, IsIssuedByKnownRootIgnoresTestRoots) {
CertVerifyResult verify_result;
int error = Verify(
cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(0U, verify_result.cert_status);
// But should not be marked as a known root.
EXPECT_FALSE(verify_result.is_issued_by_known_root);
@@ -1130,7 +1139,7 @@ TEST_F(CertVerifyProcTest, CRLSet) {
CertVerifyResult verify_result;
int error = Verify(
cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(0U, verify_result.cert_status);
scoped_refptr<CRLSet> crl_set;
@@ -1148,7 +1157,7 @@ TEST_F(CertVerifyProcTest, CRLSet) {
crl_set.get(),
empty_cert_list_,
&verify_result);
- EXPECT_EQ(ERR_CERT_REVOKED, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_REVOKED));
// Second, test revocation by serial number of a cert directly under the
// root.
@@ -1164,7 +1173,7 @@ TEST_F(CertVerifyProcTest, CRLSet) {
crl_set.get(),
empty_cert_list_,
&verify_result);
- EXPECT_EQ(ERR_CERT_REVOKED, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_REVOKED));
}
TEST_F(CertVerifyProcTest, CRLSetLeafSerial) {
@@ -1200,7 +1209,7 @@ TEST_F(CertVerifyProcTest, CRLSetLeafSerial) {
NULL,
empty_cert_list_,
&verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(CERT_STATUS_SHA1_SIGNATURE_PRESENT, verify_result.cert_status);
// Test revocation by serial number of a certificate not under the root.
@@ -1217,7 +1226,7 @@ TEST_F(CertVerifyProcTest, CRLSetLeafSerial) {
crl_set.get(),
empty_cert_list_,
&verify_result);
- EXPECT_EQ(ERR_CERT_REVOKED, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_REVOKED));
}
// Tests that CRLSets participate in path building functions, and that as
@@ -1309,7 +1318,7 @@ TEST_F(CertVerifyProcTest, CRLSetDuringPathBuilding) {
continue;
}
- ASSERT_EQ(OK, error);
+ ASSERT_THAT(error, IsOk());
ASSERT_EQ(0U, verify_result.cert_status);
ASSERT_TRUE(verify_result.verified_cert.get());
@@ -1335,6 +1344,157 @@ TEST_F(CertVerifyProcTest, CRLSetDuringPathBuilding) {
#endif
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+// Test that a CRLSet blocking one of the intermediates supplied by the server
+// can be worked around by the chopping workaround for path building. (Once the
+// supplied chain is chopped back to just the target, a better path can be
+// found out-of-band. Normally that would be by AIA fetching, for the purposes
+// of this test the better path is supplied by a test keychain.)
+//
+// In this test, there are two possible paths to validate a leaf (A):
+// 1. A(B) -> B(C) -> C(E) -> E(E)
+// 2. A(B) -> B(F) -> F(E) -> E(E)
+//
+// A(B) -> B(C) -> C(E) is supplied to the verifier.
+// B(F) and F(E) are supplied in a test keychain.
+// C is blocked by a CRLset.
+//
+// The verifier should rollback until it just tries A(B) alone, at which point
+// it will pull B(F) & F(E) from the keychain and succeed.
+TEST_F(CertVerifyProcTest, MacCRLIntermediate) {
+ const char* const kPath2Files[] = {
+ "multi-root-A-by-B.pem", "multi-root-B-by-C.pem", "multi-root-C-by-E.pem",
+ "multi-root-E-by-E.pem"};
+ CertificateList path_2_certs;
+ ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kPath2Files, &path_2_certs));
+
+ const char* const kPath3Files[] = {
+ "multi-root-A-by-B.pem", "multi-root-B-by-F.pem", "multi-root-F-by-E.pem",
+ "multi-root-E-by-E.pem"};
+
+ CertificateList path_3_certs;
+ ASSERT_NO_FATAL_FAILURE(LoadCertificateFiles(kPath3Files, &path_3_certs));
+
+ // 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);
+ ASSERT_TRUE(cert);
+
+ std::unique_ptr<TestKeychainSearchList> test_keychain_search_list(
+ TestKeychainSearchList::Create());
+ ASSERT_TRUE(test_keychain_search_list);
+
+ base::FilePath keychain_path(
+ GetTestCertsDirectory().AppendASCII("multi-root-BFE.keychain"));
+ // SecKeychainOpen does not fail if the file doesn't exist, so assert it here
+ // for easier debugging.
+ ASSERT_TRUE(base::PathExists(keychain_path));
+ SecKeychainRef keychain;
+ OSStatus status =
+ SecKeychainOpen(keychain_path.MaybeAsASCII().c_str(), &keychain);
+ ASSERT_EQ(errSecSuccess, status);
+ ASSERT_TRUE(keychain);
+ base::ScopedCFTypeRef<SecKeychainRef> scoped_keychain(keychain);
+ test_keychain_search_list->AddKeychain(keychain);
+
+ scoped_refptr<CRLSet> crl_set;
+ std::string crl_set_bytes;
+ // CRL which blocks C by SPKI.
+ EXPECT_TRUE(base::ReadFileToString(
+ GetTestCertsDirectory().AppendASCII("multi-root-crlset-C.raw"),
+ &crl_set_bytes));
+ ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set));
+
+ int flags = 0;
+ CertVerifyResult verify_result;
+ int error = Verify(cert.get(), "127.0.0.1", flags, crl_set.get(),
+ empty_cert_list_, &verify_result);
+
+ ASSERT_EQ(OK, error);
+ ASSERT_EQ(0U, verify_result.cert_status);
+ ASSERT_TRUE(verify_result.verified_cert.get());
+
+ const X509Certificate::OSCertHandles& verified_intermediates =
+ verify_result.verified_cert->GetIntermediateCertificates();
+ ASSERT_EQ(3U, verified_intermediates.size());
+
+ scoped_refptr<X509Certificate> intermediate =
+ X509Certificate::CreateFromHandle(verified_intermediates[1],
+ X509Certificate::OSCertHandles());
+ ASSERT_TRUE(intermediate);
+
+ scoped_refptr<X509Certificate> expected_intermediate = path_3_certs[2];
+ EXPECT_TRUE(expected_intermediate->Equals(intermediate.get()))
+ << "Expected: " << expected_intermediate->subject().common_name
+ << " issued by " << expected_intermediate->issuer().common_name
+ << "; Got: " << intermediate->subject().common_name << " issued by "
+ << intermediate->issuer().common_name;
+}
+
+// Test that if a keychain is present which trusts a less-desirable root (ex,
+// one using SHA1), that the keychain reordering hack will cause the better
+// root in the System Roots to be used instead.
+TEST_F(CertVerifyProcTest, MacKeychainReordering) {
+ // Note: target cert expires Apr 2 23:59:59 2018 GMT
+ scoped_refptr<X509Certificate> cert = CreateCertificateChainFromFile(
+ GetTestCertsDirectory(), "tripadvisor-verisign-chain.pem",
+ X509Certificate::FORMAT_AUTO);
+ ASSERT_TRUE(cert);
+
+ // Create a test keychain search list that will Always Trust the SHA1
+ // cross-signed VeriSign Class 3 Public Primary Certification Authority - G5
+ std::unique_ptr<TestKeychainSearchList> test_keychain_search_list(
+ TestKeychainSearchList::Create());
+ ASSERT_TRUE(test_keychain_search_list);
+
+ base::FilePath keychain_path(GetTestCertsDirectory().AppendASCII(
+ "verisign_class3_g5_crosssigned-trusted.keychain"));
+ // SecKeychainOpen does not fail if the file doesn't exist, so assert it here
+ // for easier debugging.
+ ASSERT_TRUE(base::PathExists(keychain_path));
+ SecKeychainRef keychain;
+ OSStatus status =
+ SecKeychainOpen(keychain_path.MaybeAsASCII().c_str(), &keychain);
+ ASSERT_EQ(errSecSuccess, status);
+ ASSERT_TRUE(keychain);
+ base::ScopedCFTypeRef<SecKeychainRef> scoped_keychain(keychain);
+ test_keychain_search_list->AddKeychain(keychain);
+
+ int flags = 0;
+ CertVerifyResult verify_result;
+ int error = Verify(cert.get(), "www.tripadvisor.com", flags,
+ nullptr /* crl_set */, empty_cert_list_, &verify_result);
+
+ ASSERT_EQ(OK, error);
+ EXPECT_EQ(0U, verify_result.cert_status);
+ EXPECT_FALSE(verify_result.has_sha1);
+ ASSERT_TRUE(verify_result.verified_cert.get());
+
+ const X509Certificate::OSCertHandles& verified_intermediates =
+ verify_result.verified_cert->GetIntermediateCertificates();
+ ASSERT_EQ(2U, verified_intermediates.size());
+}
+
+// Test that the system root certificate keychain is in the expected location
+// and can be opened. Other tests would fail if this was not true, but this
+// test makes the reason for the failure obvious.
+TEST_F(CertVerifyProcTest, MacSystemRootCertificateKeychainLocation) {
+ const char* root_keychain_path =
+ "/System/Library/Keychains/SystemRootCertificates.keychain";
+ ASSERT_TRUE(base::PathExists(base::FilePath(root_keychain_path)));
+
+ SecKeychainRef keychain;
+ OSStatus status = SecKeychainOpen(root_keychain_path, &keychain);
+ ASSERT_EQ(errSecSuccess, status);
+ CFRelease(keychain);
+}
+#endif
+
enum ExpectedAlgorithms {
EXPECT_MD2 = 1 << 0,
EXPECT_MD4 = 1 << 1,
@@ -1434,11 +1594,11 @@ TEST_P(CertVerifyProcWeakDigestTest, Verify) {
// present (MD2, MD4, MD5).
if (data.root_cert_filename) {
if (data.expected_algorithms & (EXPECT_MD2 | EXPECT_MD4)) {
- EXPECT_EQ(ERR_CERT_INVALID, rv);
+ EXPECT_THAT(rv, IsError(ERR_CERT_INVALID));
} else if (data.expected_algorithms & EXPECT_MD5) {
- EXPECT_EQ(ERR_CERT_WEAK_SIGNATURE_ALGORITHM, rv);
+ EXPECT_THAT(rv, IsError(ERR_CERT_WEAK_SIGNATURE_ALGORITHM));
} else {
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
}
}
@@ -1647,10 +1807,10 @@ TEST_P(CertVerifyProcNameTest, VerifyCertName) {
int error = Verify(cert.get(), data.hostname, 0, NULL, empty_cert_list_,
&verify_result);
if (data.valid) {
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_FALSE(verify_result.cert_status & CERT_STATUS_COMMON_NAME_INVALID);
} else {
- EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_COMMON_NAME_INVALID));
EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_COMMON_NAME_INVALID);
}
}
@@ -1679,7 +1839,7 @@ TEST_F(CertVerifyProcTest, LargeKey) {
CertVerifyResult verify_result;
int error = Verify(cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_,
&verify_result);
- EXPECT_EQ(ERR_CERT_INVALID, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_INVALID));
EXPECT_EQ(CERT_STATUS_INVALID, verify_result.cert_status);
}
#endif // defined(OS_MACOSX) && !defined(OS_IOS)
diff --git a/chromium/net/cert/cert_verify_proc_whitelist.cc b/chromium/net/cert/cert_verify_proc_whitelist.cc
index 2f84204ce7c..8b412e447fa 100644
--- a/chromium/net/cert/cert_verify_proc_whitelist.cc
+++ b/chromium/net/cert/cert_verify_proc_whitelist.cc
@@ -22,10 +22,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xa0, 0xa8, 0xbb, 0xa5, 0x0a, 0x72, 0xd4, 0xe1,
0x83, 0x9a, 0x94, 0xfb, 0x1a, 0x58, 0x5a, 0xd7,
0x2a, 0x7a, 0xac, 0x3c, 0x72, 0x56, 0x1f, 0xc0 },
- { 0x01, 0xd6, 0x0a, 0xe5, 0x22, 0x20, 0x8e, 0xc6,
- 0xf5, 0x04, 0xd5, 0x91, 0xf9, 0x7a, 0x99, 0xa5,
- 0xef, 0x25, 0x25, 0x98, 0x71, 0xe4, 0x77, 0x42,
- 0xd4, 0x71, 0xe2, 0x6f, 0xf0, 0x75, 0xe9, 0xe9 },
{ 0x02, 0x01, 0x4e, 0x80, 0xf5, 0xc4, 0xf3, 0x8b,
0xa9, 0xd9, 0x04, 0x79, 0x1a, 0x63, 0xf6, 0x4d,
0x05, 0xf9, 0xe2, 0x03, 0xa1, 0xf1, 0x2b, 0x06,
@@ -50,26 +46,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x25, 0x1b, 0x4d, 0xc8, 0xfa, 0x7b, 0x2b, 0xd8,
0xfd, 0x3a, 0x1c, 0x65, 0x2a, 0xa1, 0x16, 0xe7,
0xfc, 0x70, 0x0b, 0x2a, 0xb5, 0x1a, 0x2a, 0x1a },
- { 0x04, 0x49, 0x38, 0x0a, 0x30, 0xbd, 0x6d, 0xbd,
- 0x55, 0xdf, 0xe2, 0x54, 0xc8, 0x20, 0xa0, 0x77,
- 0xff, 0x11, 0xca, 0xfc, 0x83, 0xb5, 0x0e, 0x0a,
- 0x13, 0xf1, 0x3d, 0x59, 0xd3, 0xca, 0x6c, 0xaf },
- { 0x04, 0x80, 0x71, 0x3a, 0x76, 0x91, 0x7e, 0xb1,
- 0x7f, 0xb5, 0x4c, 0x93, 0xee, 0xd3, 0xfd, 0x8a,
- 0x98, 0x2b, 0xd9, 0x06, 0x9c, 0x69, 0xab, 0xea,
- 0xde, 0xb2, 0x5a, 0x76, 0xd9, 0xa5, 0x90, 0x65 },
- { 0x04, 0x8a, 0x21, 0x7a, 0xd4, 0x4e, 0x00, 0xca,
- 0xd1, 0xeb, 0xee, 0x67, 0x23, 0x51, 0xd2, 0x89,
- 0x10, 0xaf, 0x69, 0xed, 0x4d, 0x45, 0x5a, 0xef,
- 0x42, 0x76, 0x23, 0xf7, 0xd7, 0xad, 0xde, 0xc7 },
- { 0x04, 0xa6, 0x4d, 0xd4, 0x31, 0x97, 0xc6, 0x2c,
- 0x2c, 0xd3, 0xb6, 0x0b, 0xdf, 0x30, 0x5b, 0x3e,
- 0x81, 0xe5, 0xf5, 0x00, 0x2c, 0x15, 0x78, 0x59,
- 0xfb, 0xb7, 0xb4, 0x85, 0x45, 0xe6, 0x49, 0x11 },
- { 0x06, 0x17, 0xf8, 0xbc, 0x10, 0x4c, 0x24, 0x0a,
- 0x8e, 0x33, 0x42, 0x82, 0x00, 0x29, 0x1d, 0xb3,
- 0xa6, 0xa0, 0x67, 0x70, 0x90, 0xcb, 0x02, 0x39,
- 0x9f, 0xfd, 0x88, 0x75, 0xb9, 0x05, 0xb1, 0x1f },
{ 0x06, 0xd4, 0x08, 0xff, 0xa9, 0x93, 0xaf, 0x04,
0x45, 0x9c, 0x45, 0x67, 0x1a, 0xab, 0xd8, 0x7e,
0xf9, 0x2b, 0x85, 0x6b, 0x1b, 0x42, 0xc6, 0x7e,
@@ -106,10 +82,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xa7, 0x06, 0xff, 0xab, 0xd2, 0x1e, 0x7a, 0xd2,
0x25, 0xf6, 0x25, 0xf7, 0x1f, 0xf8, 0x9d, 0xb3,
0x9b, 0x32, 0x2a, 0xcb, 0x0c, 0x84, 0x57, 0x4f },
- { 0x09, 0xa5, 0x9e, 0x8b, 0x56, 0xfd, 0x2b, 0xa0,
- 0xac, 0x68, 0x5c, 0xb6, 0xf7, 0x51, 0xa0, 0x2f,
- 0x83, 0x5c, 0x68, 0x50, 0x81, 0xa2, 0xd5, 0xdc,
- 0x02, 0xb0, 0x4e, 0x9b, 0x3b, 0xc7, 0xc8, 0xbc },
{ 0x09, 0xeb, 0xdd, 0x1b, 0x7f, 0xfa, 0x4e, 0xd7,
0x4b, 0xeb, 0xae, 0x96, 0xba, 0x10, 0x65, 0xdc,
0x7d, 0xa1, 0xc5, 0xd3, 0x18, 0x3c, 0xc5, 0x94,
@@ -138,18 +110,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x69, 0xd0, 0x5f, 0xd8, 0x67, 0xb6, 0x69, 0xf2,
0x71, 0x24, 0xaf, 0xeb, 0x7c, 0x60, 0x8c, 0xfe,
0x54, 0xcf, 0x46, 0x33, 0x06, 0xcc, 0x99, 0x2e },
- { 0x0c, 0xa8, 0x11, 0xfe, 0xdb, 0x74, 0xbe, 0xad,
- 0x8b, 0xb6, 0xa9, 0xef, 0x22, 0xe7, 0x3a, 0x5f,
- 0x5f, 0x3f, 0x38, 0x53, 0xfd, 0xe6, 0xdb, 0xe3,
- 0xf6, 0xa2, 0xd8, 0xef, 0x7f, 0x62, 0x27, 0x3a },
{ 0x0c, 0xb9, 0x31, 0x93, 0xf1, 0x65, 0x26, 0xe1,
0xd1, 0x65, 0x52, 0x11, 0x7b, 0xa2, 0x1a, 0xac,
0xb9, 0xf1, 0xd7, 0xa8, 0x93, 0x56, 0xa3, 0x5d,
0xe4, 0xf6, 0x65, 0xe9, 0x39, 0x90, 0x79, 0x38 },
- { 0x0d, 0x01, 0xd9, 0x55, 0x23, 0x47, 0x90, 0x24,
- 0x17, 0x4e, 0x8d, 0xc1, 0x05, 0x00, 0x90, 0x39,
- 0xe7, 0x3c, 0x0b, 0xc6, 0x34, 0x66, 0x54, 0x6d,
- 0x91, 0xfa, 0xcd, 0x29, 0xaa, 0x39, 0x13, 0xc6 },
{ 0x0d, 0x16, 0x1b, 0xb9, 0xca, 0x0d, 0x20, 0xe4,
0x67, 0x35, 0x89, 0x67, 0x22, 0x78, 0xb0, 0xa3,
0xc5, 0xe2, 0x69, 0x30, 0xa4, 0xdc, 0x3a, 0x82,
@@ -178,14 +142,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x40, 0x21, 0x25, 0xc3, 0xca, 0x22, 0x68, 0xe0,
0x15, 0xa3, 0x1b, 0xa4, 0xfd, 0xb0, 0x05, 0x9d,
0x66, 0x6b, 0x73, 0xc8, 0x51, 0xd5, 0x35, 0x92 },
- { 0x11, 0xde, 0x20, 0x2a, 0x3e, 0x34, 0x13, 0xa2,
- 0x33, 0x3e, 0xc1, 0x67, 0x8e, 0xbb, 0x50, 0x6d,
- 0xd9, 0x55, 0x7c, 0x06, 0x81, 0xce, 0x5f, 0xed,
- 0xcd, 0x25, 0xaa, 0xd1, 0x2c, 0x46, 0x67, 0xd6 },
- { 0x12, 0x0d, 0x2b, 0x28, 0x15, 0xc5, 0xef, 0x5c,
- 0x28, 0x71, 0xa1, 0x93, 0x4d, 0xd4, 0x3d, 0x49,
- 0x9e, 0x4e, 0xe6, 0xb6, 0x30, 0x00, 0xae, 0x1a,
- 0xbe, 0xf7, 0x6d, 0x0d, 0x85, 0x51, 0xef, 0xc6 },
{ 0x12, 0x6b, 0x1b, 0xa6, 0x38, 0xc7, 0xe6, 0x99,
0xbc, 0xbc, 0x54, 0xf5, 0x79, 0xac, 0xd3, 0x9f,
0xe6, 0x1d, 0x08, 0x22, 0x5f, 0xe5, 0xb1, 0xf9,
@@ -222,26 +178,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xbf, 0x2f, 0x83, 0xc2, 0x80, 0xd1, 0x24, 0x6d,
0xce, 0x02, 0xa6, 0x28, 0x31, 0x26, 0xc6, 0x17,
0xe4, 0x17, 0xd2, 0xb7, 0xea, 0xc1, 0x19, 0x24 },
- { 0x15, 0xcf, 0x2f, 0x78, 0xe6, 0x79, 0x62, 0x2c,
- 0x06, 0x78, 0xdc, 0x5b, 0xa8, 0x03, 0x84, 0x7a,
- 0xbd, 0xb5, 0xea, 0x64, 0x31, 0x65, 0x3e, 0xc2,
- 0x5f, 0xdc, 0x8d, 0x2b, 0xb3, 0x3d, 0x12, 0x23 },
- { 0x16, 0x21, 0xec, 0x14, 0xe0, 0xb4, 0x13, 0xfa,
- 0xb7, 0xd0, 0x27, 0x5a, 0x9a, 0xc3, 0xc3, 0xc9,
- 0x85, 0x13, 0xfe, 0x18, 0xa2, 0x02, 0x86, 0xf6,
- 0x56, 0x59, 0x36, 0x9c, 0x8d, 0x34, 0x68, 0xda },
- { 0x16, 0x9a, 0xfa, 0x4c, 0x7d, 0x97, 0x78, 0xc7,
- 0x1d, 0xb5, 0x84, 0x6c, 0xca, 0x8e, 0xb7, 0x19,
- 0x12, 0x3d, 0x4b, 0x06, 0xb3, 0xff, 0x98, 0x66,
- 0xd7, 0x4d, 0x6e, 0x18, 0x7c, 0x1e, 0xf9, 0x70 },
{ 0x17, 0x3d, 0xe2, 0x60, 0xe2, 0x2d, 0x76, 0x9d,
0x2d, 0x54, 0x99, 0xc8, 0x22, 0x0d, 0x86, 0xed,
0xe3, 0x48, 0xda, 0x1e, 0x57, 0xc1, 0xe7, 0xc8,
0x15, 0x07, 0xfb, 0x3e, 0x6b, 0xd7, 0x3b, 0x7f },
- { 0x17, 0xf7, 0x25, 0xac, 0x12, 0xce, 0xa5, 0xe0,
- 0x86, 0x6f, 0xcc, 0x3e, 0x83, 0x4e, 0x9c, 0xb6,
- 0x34, 0x14, 0x5c, 0xed, 0xc5, 0x6b, 0x61, 0x3d,
- 0x2a, 0x1f, 0xe1, 0x3c, 0xf4, 0x0e, 0xdf, 0xd4 },
{ 0x18, 0x1e, 0xbb, 0x29, 0x8d, 0x20, 0x68, 0x5c,
0x48, 0xf7, 0x53, 0x89, 0x80, 0xc5, 0x63, 0xc8,
0xf7, 0x48, 0x95, 0x4c, 0xf2, 0x64, 0x41, 0x9a,
@@ -262,10 +202,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xdd, 0x59, 0xec, 0x97, 0xfe, 0x16, 0xf0, 0xea,
0xb4, 0x68, 0x5b, 0x95, 0xce, 0x14, 0xd2, 0x62,
0x3e, 0x70, 0x94, 0x2c, 0xff, 0x25, 0xe7, 0x30 },
- { 0x1b, 0xd6, 0xa6, 0xf7, 0x63, 0xd2, 0xf6, 0xd8,
- 0xbc, 0xec, 0x91, 0xa6, 0x22, 0xaa, 0x37, 0x00,
- 0xd7, 0xa4, 0x2d, 0x18, 0x8c, 0x5b, 0xd8, 0x64,
- 0x16, 0x57, 0x6f, 0xfd, 0x32, 0x50, 0x7c, 0x92 },
{ 0x1b, 0xd7, 0xb3, 0x62, 0xbc, 0x14, 0x66, 0xfa,
0xc0, 0x5e, 0xc5, 0x9e, 0x12, 0xe8, 0x1b, 0xe7,
0x35, 0x38, 0xc4, 0x97, 0x28, 0xf5, 0xad, 0xba,
@@ -306,10 +242,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xcc, 0xd4, 0xe6, 0xad, 0xe1, 0xcb, 0x75, 0x13,
0x8d, 0xd6, 0xd9, 0x06, 0xfe, 0xf3, 0x49, 0xc0,
0xc9, 0x86, 0xa5, 0x1b, 0x29, 0xb9, 0xe5, 0x2d },
- { 0x20, 0xf1, 0x85, 0xbc, 0x7f, 0xa7, 0x61, 0x16,
- 0x6e, 0xa3, 0xa9, 0x98, 0x8f, 0xb1, 0x0b, 0x24,
- 0xc7, 0x01, 0xef, 0xdd, 0xab, 0xe4, 0x74, 0x05,
- 0x63, 0x43, 0xa1, 0x36, 0x11, 0xd5, 0x4d, 0x7d },
{ 0x21, 0x09, 0xf3, 0x10, 0x7d, 0x97, 0xf8, 0x70,
0x48, 0x70, 0x8e, 0xc8, 0x7c, 0xa2, 0xdc, 0x31,
0x8b, 0x2f, 0x2b, 0x57, 0x47, 0xc3, 0x38, 0xbd,
@@ -350,10 +282,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x83, 0x7f, 0x95, 0x1a, 0x00, 0x49, 0xfd, 0xc3,
0xc4, 0xb2, 0x39, 0xf0, 0x82, 0xf6, 0xbf, 0x89,
0x5d, 0xb8, 0xf3, 0x27, 0x05, 0xe6, 0x9c, 0xf3 },
- { 0x26, 0x5f, 0x09, 0x6c, 0x74, 0xf9, 0xc4, 0x5a,
- 0x3b, 0xd3, 0x7c, 0x2b, 0xc8, 0x23, 0xee, 0x27,
- 0x1a, 0x23, 0xf8, 0xf5, 0xc0, 0x9e, 0x1b, 0x71,
- 0x68, 0x7a, 0xec, 0x17, 0xe3, 0x8e, 0x46, 0x91 },
{ 0x27, 0x50, 0x11, 0x93, 0xe4, 0x61, 0xca, 0xce,
0x55, 0x32, 0xfa, 0xd5, 0xd5, 0xb2, 0x7e, 0x01,
0x16, 0x57, 0x92, 0xe0, 0x4f, 0x24, 0x21, 0x93,
@@ -374,14 +302,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x36, 0x15, 0xdf, 0x12, 0x2e, 0x95, 0x21, 0x17,
0x42, 0x15, 0xee, 0x68, 0xf7, 0x44, 0xb2, 0xfa,
0x35, 0xd2, 0x9c, 0x5d, 0xf1, 0x08, 0xf5, 0x5b },
- { 0x29, 0x74, 0x8a, 0x69, 0xe9, 0x42, 0xa0, 0x67,
- 0xe6, 0xa6, 0xa3, 0x5a, 0x9d, 0x40, 0x00, 0x0a,
- 0x31, 0x8d, 0x7d, 0xdf, 0x5f, 0x5a, 0x2f, 0x4d,
- 0x3d, 0x18, 0xbe, 0xba, 0xd3, 0x96, 0x91, 0xec },
- { 0x29, 0xa8, 0x28, 0x26, 0x64, 0x3d, 0x5a, 0x98,
- 0xc4, 0x7d, 0xf3, 0xa7, 0x8f, 0xbb, 0x84, 0x49,
- 0xb3, 0xe6, 0xd3, 0xcc, 0xe6, 0x2c, 0xf4, 0x57,
- 0x12, 0xa4, 0xcd, 0x99, 0x21, 0xf3, 0xc6, 0x88 },
{ 0x2a, 0x0f, 0x70, 0x67, 0x6e, 0x18, 0x4d, 0x49,
0x39, 0xa4, 0x04, 0xde, 0x35, 0xac, 0x84, 0xab,
0x81, 0xaf, 0xec, 0x36, 0x17, 0xe7, 0xe1, 0xbf,
@@ -418,10 +338,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xb3, 0xd7, 0xdf, 0x24, 0xca, 0x74, 0xa7, 0x7d,
0xdc, 0x12, 0x06, 0x01, 0x52, 0x7b, 0x0f, 0x51,
0x06, 0x91, 0x05, 0xca, 0x88, 0x37, 0x6e, 0x20 },
- { 0x2f, 0xef, 0xa7, 0xcb, 0x12, 0x6b, 0x81, 0xc9,
- 0x47, 0x4d, 0x3e, 0x2c, 0x9b, 0x97, 0x3a, 0x83,
- 0x69, 0xbb, 0x08, 0x43, 0x41, 0xd3, 0x82, 0xd3,
- 0x7e, 0x9e, 0x95, 0xc4, 0xdb, 0xe3, 0x71, 0xee },
{ 0x30, 0x7b, 0x09, 0x34, 0xef, 0x97, 0x85, 0xe7,
0x08, 0xed, 0x48, 0x1a, 0x99, 0x7a, 0x8a, 0x88,
0xb7, 0xbf, 0x22, 0xdd, 0x26, 0xaa, 0x17, 0x17,
@@ -442,10 +358,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x74, 0x2d, 0x6b, 0xe8, 0x40, 0x0a, 0xde, 0x51,
0xb2, 0x09, 0x83, 0xf6, 0x83, 0xa2, 0xaa, 0xee,
0xb2, 0x5f, 0x58, 0xdf, 0x98, 0x1b, 0xde, 0x0d },
- { 0x32, 0x8b, 0x9a, 0x45, 0xef, 0xef, 0x20, 0xb5,
- 0xd1, 0x57, 0x39, 0xdd, 0xfa, 0xc1, 0x0c, 0x7e,
- 0xfe, 0x5f, 0xa7, 0x96, 0xbf, 0xe0, 0x1e, 0xd1,
- 0xa1, 0x25, 0xa9, 0x15, 0x8e, 0x2f, 0x1b, 0x17 },
{ 0x32, 0xef, 0x13, 0x33, 0x86, 0xbf, 0x0c, 0x63,
0xcf, 0x29, 0xd6, 0x2b, 0x0d, 0x76, 0x88, 0x9e,
0x9d, 0x9d, 0x53, 0x2e, 0xe4, 0x90, 0x38, 0x94,
@@ -466,14 +378,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xc8, 0x68, 0x5e, 0xea, 0xac, 0x57, 0x87, 0x2d,
0x3b, 0x47, 0xe6, 0x02, 0xf4, 0x97, 0xe9, 0xf0,
0x28, 0x54, 0x12, 0x32, 0x59, 0xfb, 0xe1, 0x69 },
- { 0x35, 0x49, 0xb6, 0xec, 0xbd, 0x8d, 0x25, 0x2b,
- 0xe7, 0x17, 0xb9, 0x22, 0x73, 0x27, 0x38, 0x08,
- 0x0b, 0xaf, 0xd5, 0x60, 0xb4, 0x5a, 0x05, 0x40,
- 0x33, 0xbd, 0x11, 0x0b, 0x3c, 0x39, 0x48, 0x22 },
- { 0x35, 0x58, 0x91, 0xa3, 0x12, 0x34, 0xfd, 0xd0,
- 0x84, 0x79, 0xb8, 0xab, 0xa8, 0x58, 0x1e, 0x85,
- 0x7c, 0x6b, 0x5c, 0x6b, 0x40, 0xcf, 0xfc, 0x7b,
- 0x67, 0x80, 0x92, 0x65, 0x1f, 0x06, 0x87, 0xc1 },
{ 0x35, 0x98, 0x10, 0xff, 0xfe, 0xd1, 0x3a, 0x2c,
0x25, 0xcd, 0x91, 0xfc, 0xf0, 0x85, 0x59, 0x33,
0xc9, 0x94, 0xa9, 0xdf, 0xc9, 0x39, 0x2d, 0x97,
@@ -494,10 +398,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x44, 0xd6, 0xab, 0x39, 0xb7, 0xa8, 0x18, 0xf8,
0x17, 0x6e, 0x65, 0x20, 0xdc, 0x86, 0x3d, 0xce,
0x43, 0xb3, 0x98, 0xc3, 0x0b, 0x5e, 0xdb, 0x09 },
- { 0x37, 0xc9, 0x7a, 0x48, 0xf5, 0xee, 0x3e, 0x68,
- 0xcc, 0x24, 0xb5, 0x4e, 0x7c, 0x4d, 0x9f, 0x91,
- 0xc7, 0xd1, 0x8b, 0x8d, 0xb6, 0x1e, 0x04, 0xee,
- 0x64, 0x25, 0x1e, 0x75, 0xb0, 0xd1, 0x9f, 0xc5 },
{ 0x38, 0x23, 0x4e, 0x55, 0x9d, 0x30, 0x27, 0xd1,
0x61, 0xda, 0x8c, 0x98, 0x88, 0x04, 0x9a, 0x4d,
0x20, 0xac, 0xf2, 0x00, 0x90, 0xad, 0x1a, 0x22,
@@ -614,10 +514,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xce, 0x25, 0x85, 0x70, 0x48, 0x96, 0x9d, 0xc8,
0x9d, 0xf5, 0x97, 0x7b, 0xb2, 0xe3, 0x34, 0x7c,
0x9c, 0xeb, 0x0e, 0x5a, 0x7b, 0x68, 0xc5, 0x31 },
- { 0x44, 0xa0, 0x6e, 0xb4, 0x9a, 0x72, 0xbc, 0xa4,
- 0x4a, 0x58, 0x1f, 0x4f, 0x10, 0x91, 0xab, 0xef,
- 0x33, 0x2d, 0x8a, 0x7c, 0xef, 0x60, 0xe6, 0x8d,
- 0xaf, 0x84, 0x13, 0x23, 0x26, 0x12, 0x90, 0xf0 },
{ 0x45, 0x63, 0xcf, 0x13, 0xc2, 0x49, 0x2c, 0xaa,
0x92, 0xf5, 0x5b, 0x17, 0x26, 0x3a, 0xdd, 0x72,
0x04, 0xa8, 0x0f, 0xe6, 0x24, 0x0c, 0x4d, 0x63,
@@ -646,10 +542,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x95, 0xb1, 0xa6, 0xa2, 0x19, 0xf8, 0x1b, 0xbd,
0xf9, 0xd2, 0xe5, 0xc0, 0x70, 0xec, 0x97, 0xdf,
0x3c, 0xb0, 0xb7, 0x3e, 0xf4, 0x70, 0xdc, 0xe9 },
- { 0x48, 0xe9, 0xc3, 0xdb, 0x3a, 0x8f, 0x3b, 0x82,
- 0x60, 0x20, 0x9f, 0x05, 0x13, 0x3d, 0xba, 0xdb,
- 0xf5, 0x11, 0x7f, 0xb1, 0x0d, 0x11, 0x14, 0xa8,
- 0xc9, 0x26, 0x83, 0x45, 0x41, 0x59, 0x41, 0x63 },
{ 0x49, 0xdc, 0xf8, 0xfa, 0x68, 0xe9, 0x2b, 0x5c,
0x21, 0xfe, 0xf9, 0x3d, 0x26, 0x0c, 0x24, 0x8c,
0xe3, 0xbe, 0x98, 0x62, 0x68, 0x68, 0xe7, 0x5a,
@@ -670,18 +562,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x2a, 0xf2, 0xae, 0x56, 0x84, 0x42, 0x9c, 0xca,
0xab, 0x21, 0x39, 0xc9, 0xb3, 0x51, 0xbf, 0x7e,
0x1b, 0x03, 0x0a, 0xe8, 0x62, 0x4a, 0xc1, 0x72 },
- { 0x4b, 0x5d, 0xbf, 0x01, 0x0b, 0x3e, 0x62, 0x78,
- 0x9c, 0x43, 0x8e, 0x07, 0x18, 0xec, 0xb4, 0x4a,
- 0x5d, 0xc0, 0x8f, 0xeb, 0xcf, 0xf7, 0x0a, 0xdf,
- 0x5b, 0xe0, 0x0a, 0x6e, 0x49, 0xe5, 0x71, 0xf7 },
{ 0x4b, 0x92, 0xdc, 0xfd, 0x0e, 0xda, 0x00, 0x5d,
0x9a, 0x37, 0x3d, 0x91, 0xa6, 0x1f, 0x23, 0x12,
0x9d, 0x7b, 0x85, 0x3d, 0x79, 0x52, 0x87, 0xc9,
0x5c, 0x7e, 0x17, 0x24, 0xa9, 0x1c, 0x53, 0xb3 },
- { 0x4c, 0x3a, 0x76, 0xd1, 0x2c, 0x70, 0x0c, 0x25,
- 0x1b, 0x02, 0x04, 0xba, 0x9f, 0x27, 0xc0, 0xda,
- 0xcb, 0x2e, 0x47, 0x37, 0x72, 0x64, 0xcd, 0x31,
- 0xc4, 0xfe, 0xa4, 0xa4, 0x58, 0x5a, 0x99, 0x60 },
{ 0x4c, 0xd0, 0xd6, 0x7e, 0xcc, 0x3b, 0x01, 0xc8,
0xc2, 0x63, 0x4e, 0x7a, 0x73, 0x76, 0x12, 0xf6,
0x3a, 0x17, 0xff, 0x51, 0x0a, 0x77, 0xa8, 0x04,
@@ -690,18 +574,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x46, 0x7f, 0x6f, 0x52, 0xad, 0x80, 0x4e, 0x19,
0x1d, 0x5b, 0xc8, 0x13, 0x51, 0x72, 0x0e, 0xc0,
0xd1, 0x9b, 0xd2, 0x5b, 0xf8, 0xf0, 0xa5, 0x53 },
- { 0x4e, 0x48, 0xc1, 0x6c, 0x9d, 0x0d, 0xe5, 0xdd,
- 0x8c, 0x9c, 0x36, 0x37, 0x35, 0xdd, 0xfb, 0xc3,
- 0xdb, 0xd2, 0x6e, 0xa0, 0xae, 0xcd, 0xe1, 0xc7,
- 0x62, 0xbb, 0x56, 0xbb, 0x3f, 0xe4, 0xfa, 0x74 },
{ 0x4f, 0x19, 0xdd, 0x12, 0x92, 0x4c, 0xe0, 0xc1,
0x4f, 0x82, 0xc0, 0x56, 0xc7, 0xd4, 0x2b, 0xac,
0x43, 0xd0, 0x13, 0x3a, 0xaf, 0x89, 0xc1, 0xef,
0xdc, 0xfa, 0x3c, 0x3e, 0x47, 0x09, 0x7d, 0x59 },
- { 0x4f, 0xe9, 0xf1, 0x68, 0x70, 0x6a, 0x07, 0x5d,
- 0xa9, 0x6c, 0x71, 0x3d, 0xa4, 0x32, 0x61, 0xe3,
- 0x39, 0xa9, 0x93, 0x6e, 0xdd, 0xd5, 0x88, 0x8b,
- 0xd6, 0x35, 0x00, 0xca, 0xa6, 0xef, 0xbf, 0xa8 },
{ 0x4f, 0xfb, 0x59, 0x19, 0xbc, 0x38, 0x5c, 0x8c,
0x58, 0xe4, 0x62, 0xbf, 0x13, 0x22, 0x10, 0xd8,
0xb7, 0x86, 0x12, 0xd0, 0xc2, 0x2a, 0x6b, 0x6a,
@@ -734,26 +610,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xb5, 0x8c, 0x17, 0x54, 0x46, 0xbf, 0x2d, 0x1b,
0xb7, 0x86, 0xa5, 0x30, 0xfb, 0xf0, 0xae, 0xcd,
0x12, 0xea, 0xb8, 0xa9, 0xa5, 0xb4, 0x96, 0x60 },
- { 0x53, 0x96, 0xb9, 0x32, 0x9d, 0xe7, 0xb3, 0x55,
- 0x2e, 0x18, 0x0d, 0xdd, 0x33, 0x17, 0x63, 0x53,
- 0xba, 0xcd, 0x65, 0x66, 0x18, 0x2b, 0x2b, 0x23,
- 0x05, 0x71, 0x67, 0x0a, 0xce, 0xb0, 0xc1, 0x91 },
{ 0x53, 0x9c, 0xa9, 0xe1, 0xf0, 0x6a, 0xf2, 0x10,
0x7f, 0x96, 0xbf, 0x4b, 0x7d, 0xd4, 0xce, 0xcd,
0x9e, 0xd1, 0x1a, 0x38, 0xd6, 0x70, 0x91, 0x69,
0x9c, 0x56, 0x26, 0xe2, 0x7a, 0x1f, 0x54, 0xa5 },
- { 0x53, 0xaf, 0xbd, 0xdb, 0xfa, 0xc7, 0x4e, 0xbc,
- 0xa1, 0xbe, 0xf4, 0xba, 0xcd, 0xeb, 0x45, 0x29,
- 0x7c, 0x43, 0xf0, 0xf7, 0x4e, 0x8d, 0x04, 0xba,
- 0x81, 0x79, 0xb4, 0xf3, 0x72, 0x41, 0xbe, 0x6c },
- { 0x53, 0xb6, 0xe2, 0xaa, 0xa6, 0x2d, 0x18, 0x5a,
- 0x42, 0x3e, 0x92, 0x9d, 0x8c, 0x75, 0xd7, 0xe3,
- 0x2b, 0x37, 0x2f, 0x5d, 0xf0, 0x06, 0x0a, 0x73,
- 0xba, 0xfa, 0xc4, 0x9a, 0xa8, 0x51, 0x1e, 0x24 },
- { 0x53, 0xeb, 0xd5, 0x29, 0x2d, 0x32, 0xce, 0xa0,
- 0x08, 0x60, 0x96, 0x78, 0xc4, 0x3b, 0xdd, 0xab,
- 0x90, 0x28, 0xba, 0x6c, 0x17, 0x68, 0x4c, 0x51,
- 0x22, 0x42, 0x62, 0x43, 0xcb, 0x61, 0x2a, 0x29 },
{ 0x55, 0x21, 0xf9, 0x63, 0x57, 0x81, 0x58, 0xb8,
0xd0, 0xe7, 0xc4, 0x91, 0xcd, 0xb8, 0x5c, 0x3d,
0xe9, 0xd5, 0x2e, 0xa5, 0x1f, 0xfc, 0xb0, 0x93,
@@ -774,10 +634,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x89, 0xa8, 0xb3, 0x4f, 0xe7, 0x42, 0x51, 0xea,
0xd5, 0xa5, 0xfb, 0xe9, 0xe6, 0x13, 0x67, 0xca,
0x76, 0xaf, 0xd9, 0xdd, 0xd9, 0xc6, 0xf1, 0x6f },
- { 0x59, 0xe8, 0x20, 0x27, 0xa5, 0xf6, 0x28, 0x1a,
- 0xbc, 0xfb, 0x41, 0xa9, 0x9f, 0xfc, 0xb5, 0xba,
- 0xb1, 0x3a, 0xa1, 0x32, 0x57, 0xfc, 0x12, 0xe1,
- 0xdd, 0x4c, 0x38, 0x08, 0xb9, 0x64, 0x27, 0x39 },
{ 0x59, 0xe9, 0xfa, 0x2f, 0xf0, 0x76, 0x89, 0x33,
0x28, 0x33, 0xc6, 0x40, 0xf5, 0x05, 0xfa, 0x24,
0x09, 0xeb, 0x88, 0x93, 0x32, 0x57, 0xc1, 0x93,
@@ -786,10 +642,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x83, 0x9c, 0x0b, 0xf6, 0x9e, 0xe6, 0x63, 0x26,
0x57, 0x16, 0xa8, 0xe2, 0x4c, 0xc6, 0x49, 0x95,
0xfb, 0xa6, 0xcb, 0x6f, 0x0c, 0x12, 0x39, 0xdc },
- { 0x5a, 0x2a, 0x8b, 0xcb, 0xef, 0x60, 0xf7, 0x79,
- 0x13, 0xb1, 0xb6, 0xae, 0xdf, 0xd3, 0xae, 0x8f,
- 0xe5, 0xfc, 0x42, 0x2f, 0xdb, 0x3b, 0xa7, 0x9e,
- 0xf7, 0x17, 0xa9, 0xbe, 0x19, 0xfa, 0x89, 0xdc },
{ 0x5a, 0x84, 0xaf, 0xe6, 0x74, 0x05, 0xab, 0xe8,
0x4a, 0x0c, 0xd4, 0x2c, 0x2b, 0xa2, 0xe4, 0xc8,
0x8f, 0x35, 0xe0, 0xa5, 0x95, 0xe5, 0x69, 0xa3,
@@ -822,22 +674,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x5f, 0x61, 0x6a, 0x95, 0x17, 0xa1, 0x30, 0xd8,
0x66, 0xa8, 0xcb, 0x0b, 0x18, 0x96, 0x3d, 0x54,
0xe7, 0xed, 0xae, 0xe2, 0x61, 0xcb, 0x1c, 0x19 },
- { 0x5f, 0x5c, 0xca, 0x19, 0x1e, 0xc9, 0x2f, 0x4d,
- 0xad, 0x96, 0x6d, 0xaa, 0xfd, 0x6d, 0xe7, 0x56,
- 0x34, 0x44, 0x18, 0x60, 0x4d, 0x8a, 0xd5, 0x0a,
- 0x78, 0x14, 0xf4, 0x39, 0xf4, 0xf2, 0x0a, 0xf1 },
- { 0x5f, 0x85, 0xde, 0xa9, 0xbb, 0x0d, 0x94, 0x81,
- 0xc2, 0x47, 0x23, 0x2e, 0xf2, 0x5c, 0x77, 0xe8,
- 0x4e, 0x68, 0x95, 0x60, 0x0d, 0x0b, 0xda, 0xf8,
- 0xe7, 0x0e, 0x82, 0x8a, 0xdc, 0x6f, 0xd4, 0xff },
{ 0x5f, 0x8b, 0x88, 0x8e, 0xe9, 0x6c, 0x0c, 0x0f,
0x5a, 0x91, 0x72, 0x90, 0xac, 0xa6, 0x5a, 0xfd,
0x6e, 0xbd, 0xae, 0x05, 0xa0, 0x2a, 0xaf, 0x04,
0x29, 0xe9, 0x72, 0xec, 0x01, 0x90, 0xec, 0xfc },
- { 0x61, 0x91, 0x5b, 0xc8, 0xdf, 0x67, 0x8c, 0x52,
- 0xa2, 0x3c, 0x2d, 0x53, 0xc6, 0x47, 0x31, 0x4e,
- 0x63, 0x6e, 0xef, 0xc5, 0x40, 0x81, 0xa7, 0x0d,
- 0x3a, 0xc1, 0x45, 0x28, 0x66, 0x1d, 0x62, 0xff },
{ 0x62, 0x2e, 0xc3, 0xbe, 0x7c, 0xf5, 0xe4, 0xe6,
0x3f, 0x74, 0x18, 0x69, 0x28, 0x74, 0x40, 0x05,
0xcb, 0xb7, 0x8d, 0xf3, 0x06, 0xb8, 0x67, 0xc3,
@@ -862,18 +702,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x8c, 0x9e, 0x3c, 0x46, 0xac, 0xea, 0xc4, 0x52,
0x33, 0xd8, 0x66, 0xe3, 0x98, 0xff, 0x90, 0xeb,
0x59, 0xb2, 0xc6, 0x25, 0x20, 0x82, 0xac, 0x04 },
- { 0x66, 0x72, 0x1f, 0xe0, 0x69, 0xf1, 0xaa, 0x25,
- 0x32, 0x11, 0x68, 0x0e, 0xad, 0x5c, 0x9e, 0x3d,
- 0x12, 0x3c, 0x21, 0x24, 0xd3, 0xa2, 0xa4, 0xbd,
- 0x78, 0x82, 0xf7, 0x36, 0x5a, 0x33, 0x05, 0xa3 },
{ 0x66, 0xbe, 0x7e, 0xa1, 0x13, 0x8b, 0xcb, 0xa4,
0xde, 0x0b, 0x41, 0x28, 0x5d, 0x9a, 0x13, 0x3f,
0xa7, 0xf5, 0x70, 0xa3, 0xc8, 0x13, 0x55, 0x79,
0xb8, 0x60, 0x19, 0x9d, 0x0a, 0x51, 0x45, 0x7c },
- { 0x66, 0xc9, 0x9a, 0x49, 0x61, 0x2e, 0x60, 0x18,
- 0x90, 0x02, 0xe2, 0x03, 0x04, 0xd2, 0xfc, 0xc5,
- 0xbe, 0x07, 0x59, 0xdf, 0xba, 0x84, 0x04, 0x70,
- 0x7e, 0x85, 0x37, 0x00, 0x26, 0x51, 0x84, 0x85 },
{ 0x67, 0xcf, 0x34, 0x6c, 0xf2, 0x46, 0x77, 0x1b,
0x3f, 0x5f, 0x3e, 0x51, 0xcd, 0x75, 0x4e, 0x10,
0x93, 0x27, 0x3d, 0x35, 0x69, 0x88, 0x80, 0x84,
@@ -886,10 +718,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x5b, 0x31, 0xcb, 0xd9, 0xfc, 0x5e, 0x94, 0xc2,
0xf6, 0xf4, 0x3c, 0x58, 0xdb, 0xde, 0xe9, 0xe3,
0xe4, 0x6b, 0x19, 0xd7, 0x59, 0xbb, 0xb8, 0x81 },
- { 0x69, 0x52, 0x89, 0x99, 0x34, 0xd7, 0x23, 0x2b,
- 0xf9, 0xf6, 0x96, 0x8b, 0xca, 0x13, 0x43, 0x92,
- 0x47, 0xbf, 0xc3, 0x65, 0x92, 0x98, 0x00, 0x3d,
- 0xb1, 0xee, 0xb7, 0x43, 0x92, 0x81, 0xb1, 0xd6 },
{ 0x69, 0x75, 0x67, 0xbb, 0xac, 0x94, 0xee, 0xc3,
0xe6, 0xfa, 0x4a, 0x4e, 0x46, 0xfa, 0x51, 0x74,
0x05, 0xf3, 0x77, 0xc0, 0xde, 0xe3, 0xd4, 0x29,
@@ -898,14 +726,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xa0, 0xad, 0x0e, 0x9e, 0xf6, 0x36, 0x43, 0x7d,
0x36, 0x0d, 0xc7, 0xc9, 0xf1, 0x40, 0x44, 0x17,
0xa3, 0x36, 0x91, 0x94, 0x4e, 0x76, 0x31, 0x36 },
- { 0x6a, 0xe7, 0x98, 0xd7, 0xde, 0x07, 0x84, 0x90,
- 0xa5, 0x0f, 0x73, 0x89, 0x86, 0xd4, 0x03, 0x39,
- 0x42, 0x97, 0x9d, 0xe2, 0x42, 0x6a, 0xfa, 0x95,
- 0x42, 0x24, 0x2e, 0x76, 0x3f, 0xec, 0xf4, 0xa6 },
- { 0x6b, 0x37, 0xdd, 0x56, 0xdb, 0xc9, 0x97, 0x01,
- 0xee, 0x6b, 0x55, 0x75, 0x23, 0x8b, 0x1e, 0xcf,
- 0x35, 0xdf, 0x1b, 0x5e, 0x85, 0x91, 0x09, 0x1d,
- 0xb6, 0x8c, 0xc3, 0x5b, 0xd5, 0xa3, 0x6c, 0xe4 },
{ 0x6b, 0x4a, 0x8c, 0xb6, 0x07, 0xf5, 0x1c, 0x83,
0x0d, 0xe7, 0x20, 0xf4, 0xbb, 0xde, 0xdf, 0x49,
0x10, 0x15, 0x13, 0xdf, 0xd1, 0xdb, 0x0b, 0x0a,
@@ -934,10 +754,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x47, 0xb2, 0x80, 0xb1, 0xb1, 0x45, 0x0d, 0x87,
0x8e, 0x09, 0x8b, 0xb2, 0xe2, 0xa9, 0xe3, 0xc2,
0x5c, 0xc7, 0x6a, 0xff, 0x93, 0xc0, 0xbe, 0xab },
- { 0x6e, 0x0c, 0x0b, 0x5d, 0x7b, 0x82, 0x23, 0x21,
- 0x87, 0x41, 0xe6, 0x7b, 0x87, 0x6c, 0xcb, 0x8c,
- 0xb5, 0x81, 0x11, 0x48, 0x82, 0x87, 0xda, 0x8c,
- 0x30, 0x64, 0xe8, 0x2e, 0xcc, 0xc2, 0x70, 0x12 },
{ 0x6e, 0x1a, 0x88, 0x63, 0xf2, 0x93, 0x4b, 0x39,
0x01, 0x23, 0x7e, 0x84, 0xd0, 0x76, 0x27, 0x04,
0x23, 0x06, 0x78, 0x7f, 0x2d, 0xe0, 0x66, 0x30,
@@ -966,10 +782,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x96, 0x85, 0x84, 0x5d, 0x94, 0xfc, 0x9e, 0x77,
0x7c, 0x12, 0x69, 0xcf, 0x15, 0x31, 0x68, 0x51,
0x98, 0x3d, 0x60, 0x58, 0x76, 0x1c, 0xf0, 0x63 },
- { 0x70, 0xed, 0x64, 0x0c, 0xbc, 0xe7, 0x84, 0xa6,
- 0x8e, 0xcd, 0xd6, 0x32, 0x0b, 0x61, 0x3c, 0x88,
- 0x42, 0xe6, 0xd7, 0x09, 0xbd, 0x96, 0xf1, 0xd2,
- 0x43, 0xe4, 0xb2, 0x1e, 0xed, 0x8b, 0x12, 0x8c },
{ 0x71, 0x1e, 0xf0, 0x96, 0x33, 0x43, 0x8a, 0xc5,
0xbe, 0x9d, 0xa8, 0x12, 0x2e, 0x7a, 0xcf, 0x0e,
0xa2, 0x68, 0xb8, 0x72, 0xad, 0xdc, 0x3e, 0xe8,
@@ -1006,14 +818,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xa2, 0xa2, 0xab, 0x2a, 0x4e, 0x85, 0x49, 0x83,
0xc5, 0xfd, 0xe6, 0x73, 0xce, 0x8e, 0xb1, 0x71,
0x23, 0x49, 0x48, 0x64, 0x86, 0x7a, 0x98, 0xb1 },
- { 0x77, 0xac, 0x72, 0x54, 0x6a, 0x39, 0xca, 0x2f,
- 0x24, 0xe2, 0xd1, 0x3c, 0x0d, 0x74, 0x91, 0x5f,
- 0x67, 0xbc, 0xd4, 0x37, 0x09, 0xa9, 0xe5, 0xdb,
- 0x8b, 0x33, 0x1a, 0x55, 0x77, 0xfd, 0x50, 0x88 },
- { 0x77, 0xb7, 0xcc, 0x99, 0xce, 0x02, 0x4e, 0x0b,
- 0x7e, 0xd5, 0x33, 0xc9, 0x9c, 0xc8, 0x25, 0x08,
- 0xeb, 0xa6, 0xac, 0x3a, 0x0b, 0xe5, 0xbc, 0xbf,
- 0x7a, 0xc9, 0x94, 0x95, 0x2b, 0x6d, 0x35, 0x07 },
{ 0x77, 0xdd, 0xc8, 0x1b, 0xd2, 0x8b, 0x9d, 0x46,
0x1e, 0x7d, 0x3c, 0xd4, 0xa8, 0x12, 0x2a, 0xa9,
0x8a, 0x24, 0x60, 0xfb, 0xa0, 0x8f, 0x1b, 0x7b,
@@ -1038,10 +842,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x35, 0x6b, 0x09, 0xc6, 0xb8, 0x64, 0xfc, 0x92,
0xe5, 0xfb, 0xc9, 0xe6, 0x9b, 0xec, 0x93, 0xa4,
0xe3, 0x3b, 0x8d, 0xf5, 0x75, 0x60, 0x17, 0xbe },
- { 0x7a, 0x1e, 0x5e, 0xa4, 0xe9, 0x74, 0xeb, 0x10,
- 0x8a, 0xda, 0x2d, 0xdf, 0xbd, 0x06, 0x8a, 0xc3,
- 0x5d, 0x0f, 0x9d, 0xfa, 0xe6, 0x70, 0xf3, 0xe3,
- 0x95, 0xd4, 0x03, 0x7c, 0x3f, 0x8c, 0x4d, 0xd0 },
{ 0x7b, 0xfe, 0x47, 0xae, 0xba, 0x8b, 0x0a, 0x3a,
0x94, 0x5a, 0x88, 0xd8, 0xef, 0x18, 0x91, 0xc9,
0x89, 0x97, 0x8a, 0xbf, 0x12, 0x2e, 0xc5, 0xe0,
@@ -1086,10 +886,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xb1, 0x89, 0xaf, 0xd6, 0x74, 0x95, 0xfe, 0x8a,
0xb9, 0xd8, 0x3a, 0x74, 0x2e, 0x35, 0x8c, 0xbb,
0xdb, 0xd1, 0x54, 0x98, 0xbf, 0x9c, 0x7b, 0x56 },
- { 0x81, 0x21, 0x5f, 0x4c, 0x05, 0x58, 0x6c, 0x90,
- 0x8b, 0xa6, 0x65, 0x15, 0xd6, 0xa2, 0x64, 0x81,
- 0xed, 0xdc, 0xd9, 0x89, 0x44, 0xac, 0x01, 0x98,
- 0x40, 0xe9, 0xe3, 0x32, 0x2e, 0x35, 0x8d, 0xd2 },
{ 0x81, 0xa0, 0xf1, 0xd0, 0x29, 0x46, 0x8e, 0xe8,
0x66, 0x36, 0x4a, 0x19, 0x8a, 0x26, 0x08, 0x58,
0x30, 0xc2, 0xa4, 0x16, 0xe4, 0x9e, 0x22, 0x4c,
@@ -1106,10 +902,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x18, 0x02, 0x3a, 0xb7, 0x85, 0xfa, 0x3c, 0xde,
0xd6, 0x6f, 0x42, 0x5d, 0xe1, 0xf3, 0x2f, 0xcd,
0x72, 0x1b, 0x49, 0x46, 0x3a, 0x5a, 0x5f, 0x5b },
- { 0x83, 0x25, 0x41, 0x78, 0xae, 0x2c, 0x8b, 0xaa,
- 0x1a, 0xcb, 0xb9, 0x99, 0x82, 0x63, 0x8c, 0x79,
- 0x9b, 0x9b, 0x37, 0x9d, 0xa4, 0xd0, 0x2b, 0x28,
- 0x91, 0x86, 0x20, 0xe2, 0xf1, 0xd8, 0x35, 0xc5 },
{ 0x83, 0x34, 0xea, 0xb8, 0x1c, 0x60, 0x4e, 0x99,
0xd5, 0x40, 0x51, 0x3e, 0xf2, 0xe3, 0x7a, 0xba,
0x71, 0x4f, 0x07, 0xb2, 0xba, 0x01, 0x0a, 0xd7,
@@ -1130,10 +922,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xc8, 0xfa, 0x37, 0x98, 0x21, 0x97, 0x37, 0xe1,
0x92, 0xba, 0x72, 0x72, 0xa1, 0x08, 0xb7, 0x17,
0x28, 0xa8, 0xd1, 0x65, 0x17, 0xf6, 0x1e, 0x9d },
- { 0x84, 0x88, 0x61, 0x71, 0x6d, 0x7a, 0xd3, 0xf9,
- 0x6f, 0xff, 0x73, 0xf8, 0x2e, 0x6c, 0x75, 0x7c,
- 0x43, 0x35, 0xae, 0x5d, 0x3a, 0x1f, 0x52, 0xc4,
- 0xb6, 0x24, 0x08, 0xdb, 0x51, 0xdf, 0x9e, 0xb2 },
{ 0x85, 0x31, 0xb2, 0xbf, 0xc5, 0x45, 0x79, 0xe8,
0xf1, 0x8f, 0x27, 0xb2, 0xe6, 0xec, 0xc0, 0xf8,
0x90, 0x64, 0xee, 0x86, 0x87, 0x0e, 0xcc, 0x8b,
@@ -1174,10 +962,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xcb, 0x84, 0xd9, 0xd6, 0x56, 0x27, 0x82, 0xfd,
0x2e, 0xb3, 0x42, 0x5d, 0x49, 0x1e, 0x68, 0x74,
0x20, 0x28, 0x4b, 0x76, 0xa1, 0xde, 0xbf, 0xab },
- { 0x88, 0xb0, 0x25, 0x04, 0x88, 0x31, 0x94, 0xb9,
- 0x9f, 0xd1, 0xb8, 0x1d, 0x5d, 0x5d, 0xc4, 0x99,
- 0xd3, 0x97, 0x65, 0x62, 0x1f, 0x7f, 0x43, 0x0c,
- 0x73, 0x46, 0xa7, 0x7b, 0x23, 0x39, 0x43, 0x82 },
{ 0x89, 0xaf, 0x0e, 0x54, 0xc7, 0x62, 0x77, 0x86,
0x93, 0x52, 0x9d, 0x0a, 0x95, 0x0b, 0x78, 0x33,
0xf5, 0xea, 0xba, 0xf3, 0x42, 0x79, 0x72, 0x60,
@@ -1206,10 +990,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x5b, 0x64, 0x42, 0x6a, 0x99, 0x0f, 0x58, 0xb3,
0xa0, 0x71, 0xef, 0x78, 0x2e, 0x6c, 0x09, 0x53,
0x07, 0xd7, 0x74, 0x74, 0xd5, 0xb5, 0x7a, 0x62 },
- { 0x8b, 0x1b, 0x7c, 0x94, 0xb9, 0x94, 0x4f, 0x59,
- 0xa3, 0xde, 0x10, 0x21, 0x3b, 0xf6, 0x2b, 0xdc,
- 0x50, 0x15, 0x79, 0x0d, 0xdb, 0x18, 0x6f, 0x63,
- 0x18, 0x24, 0x1a, 0x01, 0x51, 0x51, 0x3c, 0xf6 },
{ 0x8b, 0x3a, 0x10, 0x35, 0xc3, 0xfd, 0xf3, 0x45,
0xfb, 0x70, 0x80, 0x44, 0x83, 0xa5, 0x04, 0x49,
0xa3, 0xd7, 0x60, 0xc6, 0xba, 0x48, 0xf5, 0xb8,
@@ -1230,18 +1010,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x33, 0xf2, 0x4e, 0xfd, 0x60, 0xee, 0x70, 0xcf,
0xed, 0xdb, 0xd6, 0x41, 0x59, 0x04, 0x70, 0x9e,
0x78, 0x5c, 0x33, 0x1b, 0x1e, 0xf5, 0x8f, 0x8e },
- { 0x8c, 0xb4, 0x26, 0x39, 0x8a, 0xd9, 0x7b, 0x04,
- 0x5d, 0x6a, 0xe9, 0x75, 0x3e, 0x4d, 0x48, 0xb1,
- 0x79, 0x23, 0xb9, 0x36, 0x5a, 0x6b, 0x4b, 0x97,
- 0xc4, 0xec, 0xac, 0x4a, 0x4b, 0x37, 0x03, 0x4b },
{ 0x8e, 0x18, 0xfd, 0xbd, 0xb0, 0x08, 0x16, 0x00,
0x35, 0xfa, 0xf5, 0x01, 0x5b, 0xe7, 0xda, 0xf4,
0x63, 0xb5, 0xc4, 0x14, 0xea, 0xbc, 0x8b, 0x89,
0xf3, 0xdb, 0xa2, 0x05, 0xab, 0x09, 0xa6, 0x43 },
- { 0x8e, 0x57, 0x12, 0xc7, 0x5e, 0xc1, 0xe0, 0x31,
- 0x73, 0x15, 0x96, 0x35, 0x60, 0xf2, 0x6c, 0x8e,
- 0xcb, 0x29, 0xa7, 0xa0, 0x28, 0x7f, 0x84, 0xe7,
- 0xcc, 0x29, 0x99, 0x67, 0x5e, 0x41, 0xa0, 0x5d },
{ 0x8f, 0x10, 0x10, 0x47, 0x93, 0xe8, 0x55, 0x42,
0xbc, 0x06, 0x04, 0xd6, 0xcf, 0x21, 0x5f, 0x78,
0x80, 0xbd, 0x6a, 0x4d, 0xd0, 0xfd, 0xf1, 0xe7,
@@ -1254,14 +1026,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x41, 0x8a, 0x30, 0x7c, 0x76, 0x36, 0xe4, 0x9b,
0x14, 0x4f, 0xa5, 0x3e, 0x52, 0xe1, 0x04, 0x15,
0x5f, 0x58, 0x03, 0x5e, 0x45, 0x41, 0xcd, 0x6e },
- { 0x8f, 0x9f, 0x3e, 0x59, 0xd3, 0x6a, 0x9f, 0x33,
- 0x15, 0x04, 0x9b, 0x99, 0x1c, 0x89, 0xc3, 0x21,
- 0xe1, 0xf1, 0xf6, 0x78, 0xe0, 0xa2, 0xa4, 0x2f,
- 0xc1, 0x44, 0xe5, 0xff, 0xf2, 0x3b, 0x62, 0xa5 },
- { 0x90, 0x30, 0xec, 0x29, 0x71, 0x10, 0x6a, 0x7c,
- 0x68, 0x8b, 0xbe, 0xa9, 0x1d, 0x70, 0xf3, 0x4d,
- 0x75, 0xd6, 0x74, 0x5b, 0x30, 0x48, 0xfb, 0x1d,
- 0x9d, 0x3b, 0xc4, 0x9f, 0x9f, 0xc8, 0x78, 0xba },
{ 0x90, 0xb3, 0xa1, 0x85, 0x36, 0x86, 0xaf, 0xeb,
0x15, 0x4a, 0xef, 0x7e, 0x84, 0x0d, 0x38, 0x04,
0x4e, 0x7d, 0x7f, 0x6d, 0xc4, 0xce, 0x82, 0x8c,
@@ -1270,10 +1034,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xbd, 0x9b, 0x51, 0x0c, 0xfd, 0xa8, 0x48, 0x49,
0x72, 0xfd, 0xf0, 0xe0, 0x6d, 0xc1, 0x1f, 0x5d,
0x1d, 0x59, 0x0b, 0xe3, 0xfc, 0x38, 0xdf, 0xf0 },
- { 0x91, 0x6b, 0x1a, 0x6b, 0x61, 0x6c, 0x6d, 0x8a,
- 0xc1, 0x49, 0xa3, 0x31, 0x04, 0x83, 0x51, 0x1a,
- 0xf7, 0xa7, 0xd5, 0x3c, 0x60, 0x17, 0x9e, 0x7f,
- 0xa7, 0x93, 0x1e, 0x59, 0x70, 0xb7, 0x82, 0xf1 },
{ 0x91, 0x90, 0xf8, 0x25, 0x51, 0x0c, 0x65, 0x98,
0xe1, 0x9d, 0x17, 0xdb, 0xbe, 0x6e, 0x7c, 0x82,
0x31, 0x86, 0x9c, 0xa7, 0xf6, 0xe3, 0x07, 0xa2,
@@ -1290,10 +1050,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x07, 0xe9, 0x40, 0x7f, 0x7f, 0xff, 0x6a, 0x64,
0x63, 0x5d, 0x7c, 0xe9, 0x06, 0x66, 0xd4, 0x29,
0x94, 0x09, 0x7a, 0xf4, 0x0c, 0x31, 0x36, 0xfb },
- { 0x93, 0x03, 0x43, 0xb5, 0xe8, 0xc1, 0x5d, 0x6d,
- 0x93, 0x9d, 0x0f, 0x39, 0xf0, 0x53, 0x7a, 0xa6,
- 0x23, 0x3f, 0x61, 0x17, 0x93, 0x79, 0xce, 0xbc,
- 0x8d, 0x7c, 0x62, 0x01, 0x09, 0x9f, 0xfd, 0xe2 },
{ 0x93, 0x8a, 0xe3, 0xe7, 0x15, 0x48, 0xa9, 0xc3,
0x14, 0x27, 0xcb, 0xa7, 0x40, 0xbe, 0x2e, 0xb9,
0x26, 0x88, 0x68, 0xbd, 0xac, 0xc1, 0xda, 0xa8,
@@ -1310,10 +1066,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x72, 0x01, 0x96, 0xdc, 0x58, 0x6d, 0x17, 0x9d,
0x73, 0x5d, 0xf7, 0x17, 0x92, 0x6c, 0x06, 0x1e,
0xa7, 0x0c, 0x40, 0x85, 0x64, 0x8f, 0xf3, 0x12 },
- { 0x95, 0xf4, 0x59, 0xac, 0xf2, 0x57, 0x64, 0x4c,
- 0x90, 0x9a, 0xdc, 0xae, 0xad, 0xd8, 0x8a, 0x3c,
- 0x57, 0x76, 0x2e, 0xcb, 0x09, 0x2c, 0x50, 0xb4,
- 0x51, 0xc1, 0x58, 0x6b, 0x21, 0x8e, 0x6b, 0x26 },
{ 0x96, 0xa4, 0x59, 0x90, 0xfc, 0xd0, 0x1c, 0x9c,
0x2a, 0xf0, 0x64, 0x5f, 0x87, 0xb9, 0x69, 0x8b,
0x05, 0xaf, 0xe6, 0x94, 0x32, 0xeb, 0x57, 0x01,
@@ -1334,18 +1086,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xc0, 0xa8, 0x3e, 0xd4, 0x9e, 0x65, 0x0a, 0xdf,
0xd9, 0xbc, 0x0b, 0x3c, 0x50, 0x04, 0x9d, 0x7b,
0x93, 0x24, 0x5a, 0xcc, 0x3a, 0x0c, 0x16, 0xaf },
- { 0x98, 0xaa, 0xb4, 0xed, 0x43, 0x89, 0xf3, 0x5e,
- 0x74, 0x23, 0x74, 0x90, 0x68, 0x01, 0x15, 0x3d,
- 0xc7, 0xc8, 0xe3, 0x2d, 0x18, 0xb4, 0xd7, 0x81,
- 0x88, 0x28, 0x3a, 0x55, 0x77, 0xcb, 0x55, 0xfb },
{ 0x98, 0xb5, 0x92, 0x4e, 0x06, 0xcd, 0xea, 0x1b,
0xa1, 0x7f, 0xdb, 0x1b, 0x13, 0x97, 0x90, 0x24,
0xb1, 0xc2, 0x5b, 0x0a, 0x69, 0x0c, 0xfe, 0x87,
0x8d, 0x4c, 0xb4, 0x07, 0x76, 0xb9, 0x6f, 0xb0 },
- { 0x99, 0x05, 0x0a, 0x48, 0x01, 0x8d, 0x00, 0xb3,
- 0xbf, 0xe5, 0xa8, 0x09, 0x24, 0x6e, 0x25, 0x54,
- 0x5f, 0x36, 0xd2, 0x17, 0x8f, 0xd2, 0x02, 0xae,
- 0x5d, 0xc8, 0xe7, 0xff, 0x4d, 0x5a, 0x07, 0xf9 },
{ 0x99, 0xa5, 0x5f, 0x76, 0xcb, 0xea, 0x0f, 0x3e,
0x60, 0x71, 0xd3, 0x82, 0x18, 0x1a, 0xf6, 0xcb,
0x25, 0xbd, 0xc5, 0x87, 0x5e, 0x29, 0xf0, 0xf4,
@@ -1358,26 +1102,14 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xe7, 0x7f, 0x3c, 0x8a, 0xaf, 0xdb, 0xdc, 0x11,
0x1a, 0x36, 0xb7, 0x3c, 0xca, 0xdb, 0x87, 0x04,
0x98, 0x25, 0x00, 0xd1, 0xb0, 0xf1, 0x09, 0xf2 },
- { 0x9a, 0x4c, 0xa1, 0x75, 0xc4, 0x6f, 0x5c, 0x17,
- 0x05, 0x5e, 0x28, 0x16, 0xc8, 0x37, 0x98, 0x54,
- 0x89, 0x46, 0x76, 0xee, 0xb3, 0x4c, 0xf7, 0x2a,
- 0x14, 0x83, 0x04, 0x97, 0xd8, 0x4a, 0x4f, 0x6c },
{ 0x9a, 0x5f, 0xab, 0xe5, 0x8a, 0x1e, 0xae, 0x4b,
0x20, 0xba, 0xb3, 0xa7, 0xeb, 0x5e, 0x42, 0xa2,
0xda, 0x83, 0x11, 0x59, 0x25, 0x7d, 0xd4, 0xe3,
0x55, 0x2e, 0xc6, 0xf7, 0xd2, 0x67, 0xfa, 0xba },
- { 0x9a, 0x9f, 0x50, 0x16, 0x20, 0x70, 0x69, 0x62,
- 0xe5, 0x07, 0xf7, 0x57, 0xb2, 0xfe, 0x76, 0x44,
- 0xa3, 0xf4, 0x96, 0x90, 0x57, 0x1a, 0x30, 0x34,
- 0xdb, 0xbc, 0x35, 0x96, 0xa4, 0xc1, 0x60, 0x2c },
{ 0x9a, 0xae, 0x9d, 0x45, 0xaa, 0x04, 0x03, 0x06,
0x4b, 0xc5, 0xa7, 0x4d, 0xd0, 0x32, 0x5d, 0xa4,
0x1e, 0x12, 0xcf, 0x58, 0x6c, 0x46, 0x2e, 0xe0,
0x6c, 0x2b, 0xb4, 0x56, 0xf8, 0x44, 0x1c, 0x4f },
- { 0x9a, 0xc0, 0xd1, 0x78, 0x82, 0x0b, 0xc5, 0x49,
- 0x96, 0x0a, 0xa1, 0x52, 0xbc, 0x17, 0x3d, 0x70,
- 0xba, 0x6b, 0x36, 0x24, 0x7e, 0x18, 0xa0, 0x42,
- 0xeb, 0x83, 0x05, 0x41, 0x96, 0x84, 0xa7, 0x2c },
{ 0x9b, 0x8f, 0x9f, 0xc4, 0xaf, 0xa7, 0x04, 0x0d,
0x4e, 0x59, 0x4d, 0x66, 0x7c, 0x44, 0x44, 0xb5,
0x25, 0x88, 0x20, 0xc0, 0x8f, 0x89, 0x91, 0x0e,
@@ -1386,18 +1118,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xbc, 0x8a, 0x77, 0x53, 0x12, 0x57, 0x2a, 0xb2,
0x79, 0x21, 0x6d, 0x55, 0x6d, 0xa7, 0x4a, 0xc2,
0xa7, 0xc0, 0x41, 0xe8, 0xce, 0xb0, 0xbe, 0x0a },
- { 0x9c, 0x85, 0x31, 0xe7, 0xc8, 0xfb, 0xda, 0xb8,
- 0x61, 0x4d, 0x56, 0x17, 0x79, 0x9e, 0x00, 0x6b,
- 0x69, 0x42, 0xe4, 0x20, 0xc4, 0x07, 0x1d, 0x7d,
- 0xb8, 0x9c, 0xd7, 0x72, 0x81, 0x69, 0x16, 0x70 },
{ 0x9c, 0xca, 0x23, 0x7c, 0xdf, 0xca, 0x2c, 0x72,
0xc6, 0x09, 0x25, 0x4a, 0x72, 0x57, 0xfe, 0xd5,
0x3a, 0xf1, 0x44, 0xab, 0xc2, 0x5e, 0xcd, 0x8e,
0xf7, 0x01, 0x30, 0x8c, 0xb1, 0x3c, 0xf7, 0x69 },
- { 0x9c, 0xf9, 0x96, 0xc5, 0x3a, 0x2a, 0x7b, 0x1a,
- 0x99, 0xae, 0x53, 0x0f, 0xc4, 0x36, 0x19, 0x62,
- 0x28, 0xea, 0xe4, 0x79, 0x72, 0xae, 0x9c, 0xb0,
- 0x69, 0xb1, 0x8c, 0x29, 0xe3, 0x30, 0x40, 0x9c },
{ 0x9d, 0x32, 0x0d, 0x7b, 0x3d, 0x46, 0x34, 0x5f,
0x0f, 0x2d, 0xec, 0xb7, 0x62, 0xa4, 0x81, 0x7b,
0x26, 0xa9, 0xa7, 0xcf, 0xe8, 0x71, 0xb1, 0x3e,
@@ -1410,10 +1134,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x39, 0xcd, 0x01, 0xec, 0x4b, 0x33, 0xa1, 0x2f,
0x47, 0x51, 0x2f, 0x54, 0x09, 0xff, 0x09, 0x5d,
0x40, 0xaa, 0xd6, 0x20, 0x84, 0xef, 0x15, 0xbe },
- { 0x9e, 0x98, 0xf7, 0xda, 0x04, 0x74, 0xd4, 0x86,
- 0x5a, 0xc7, 0x05, 0xd4, 0xd7, 0xab, 0xbe, 0xb7,
- 0x1a, 0xef, 0xba, 0x2c, 0xf2, 0xe0, 0x82, 0xf0,
- 0x5f, 0xed, 0x53, 0x62, 0x41, 0x4b, 0xd3, 0x93 },
{ 0x9f, 0x24, 0x5c, 0x0a, 0x0e, 0xc6, 0x3a, 0xaa,
0xcb, 0xf9, 0x69, 0xc6, 0xfc, 0x24, 0xa1, 0x07,
0x15, 0x83, 0xb7, 0x79, 0xa5, 0x8a, 0xb6, 0x23,
@@ -1438,14 +1158,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x47, 0x6f, 0x67, 0xbe, 0xfe, 0xd6, 0xcf, 0x2c,
0x61, 0xb7, 0x45, 0xf0, 0xce, 0x8d, 0x26, 0x58,
0x3d, 0x03, 0xb2, 0x70, 0x02, 0xd5, 0xcd, 0xaf },
- { 0xa1, 0xa3, 0xf6, 0x88, 0xff, 0x45, 0xf6, 0x56,
- 0x75, 0x7a, 0x24, 0x52, 0xd5, 0xdb, 0xcd, 0x15,
- 0x39, 0x4a, 0xc1, 0x1a, 0xf3, 0x8c, 0x2f, 0xea,
- 0x0c, 0x7c, 0x39, 0x07, 0xfe, 0xc4, 0xb7, 0x8c },
- { 0xa2, 0x6b, 0xa6, 0x8b, 0xd5, 0x7f, 0x66, 0x70,
- 0x89, 0xb7, 0x52, 0x56, 0x1d, 0x87, 0x12, 0xf0,
- 0x8c, 0x7d, 0x96, 0x3d, 0x0f, 0xcd, 0x36, 0xac,
- 0x58, 0x99, 0x8e, 0x4c, 0x1f, 0xd3, 0xe2, 0xda },
{ 0xa2, 0x6c, 0x37, 0x5e, 0xb3, 0x19, 0x6e, 0x28,
0x3b, 0xec, 0x60, 0x3d, 0xb6, 0xbb, 0xda, 0xe2,
0x49, 0x55, 0xe4, 0xba, 0x91, 0x0c, 0xd4, 0x2d,
@@ -1470,10 +1182,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xe1, 0x2d, 0xb4, 0x09, 0x97, 0x61, 0x71, 0xac,
0xb5, 0x1f, 0xb3, 0xdc, 0xfb, 0xb7, 0x6e, 0xe3,
0x84, 0x95, 0x39, 0xcd, 0x8a, 0xb0, 0x66, 0xdf },
- { 0xa7, 0x08, 0x0d, 0xeb, 0x9a, 0xfe, 0x85, 0xba,
- 0x27, 0xfe, 0xb4, 0xa9, 0xc2, 0xf9, 0xa7, 0x54,
- 0xf3, 0xd5, 0xff, 0xe6, 0xc3, 0xc4, 0xee, 0x95,
- 0x56, 0x63, 0x1c, 0xe7, 0xea, 0x20, 0x22, 0x72 },
{ 0xa8, 0x53, 0xad, 0xc1, 0xc2, 0x18, 0x59, 0xaf,
0x7c, 0x46, 0x2b, 0x4a, 0xa0, 0xa5, 0x74, 0xca,
0x9f, 0xee, 0xfb, 0x18, 0x5a, 0x1f, 0xdb, 0xb6,
@@ -1494,10 +1202,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xa5, 0x7d, 0xc1, 0xf0, 0xf8, 0x6d, 0xe1, 0x07,
0xb5, 0xe2, 0xf0, 0x36, 0x09, 0x53, 0xf1, 0xed,
0x12, 0x5e, 0x37, 0x07, 0x59, 0x47, 0x1d, 0x09 },
- { 0xaa, 0x0e, 0x12, 0x52, 0x43, 0x6d, 0xef, 0x79,
- 0x07, 0xfb, 0x99, 0xf7, 0x64, 0x15, 0x50, 0xd8,
- 0x0f, 0xaf, 0xfb, 0xf3, 0x01, 0x71, 0x1c, 0x7b,
- 0x6b, 0xef, 0x59, 0x6f, 0x94, 0x10, 0xef, 0xd2 },
{ 0xaa, 0x4b, 0xb3, 0x6f, 0x51, 0xd3, 0xc5, 0x33,
0xb5, 0x27, 0x23, 0xcf, 0x66, 0xa5, 0xa9, 0x9f,
0xc1, 0x2f, 0x11, 0xd4, 0xcc, 0x12, 0x87, 0x56,
@@ -1550,10 +1254,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x41, 0x81, 0xd8, 0x6a, 0x7e, 0x8f, 0x07, 0x69,
0xb6, 0x1d, 0x46, 0xd7, 0xb6, 0xfa, 0xc6, 0xe6,
0xf9, 0x59, 0x6d, 0xe9, 0x4a, 0xa8, 0xe2, 0xe8 },
- { 0xb0, 0x1e, 0xb1, 0x82, 0x68, 0x1a, 0xa9, 0x5d,
- 0x7b, 0xea, 0xaf, 0x53, 0xba, 0x75, 0x5b, 0x7f,
- 0x3d, 0x0f, 0xb7, 0x97, 0x76, 0xd5, 0x62, 0xb9,
- 0x93, 0x8f, 0xfe, 0x98, 0x8d, 0x99, 0xb3, 0x13 },
{ 0xb0, 0x5c, 0x14, 0x33, 0x61, 0x75, 0x9b, 0xe1,
0x52, 0xfd, 0x76, 0xa5, 0xff, 0xa4, 0x87, 0x2d,
0xd4, 0x2e, 0xa0, 0x60, 0xae, 0x40, 0xa3, 0x83,
@@ -1562,10 +1262,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xa9, 0x57, 0x3b, 0xd3, 0xcf, 0x43, 0xf9, 0xdf,
0xd2, 0xad, 0x3e, 0x56, 0x15, 0x54, 0x63, 0x7f,
0x1e, 0x7b, 0x71, 0x91, 0x4d, 0x62, 0x73, 0x38 },
- { 0xb1, 0x92, 0x30, 0x7c, 0xfa, 0xee, 0x42, 0x7b,
- 0x76, 0x7b, 0xc2, 0xf9, 0x9b, 0xc2, 0x26, 0x74,
- 0x26, 0x0a, 0x4e, 0x8e, 0x1e, 0x6b, 0x36, 0x19,
- 0x8c, 0x2f, 0x4e, 0xea, 0x67, 0xca, 0x85, 0xef },
{ 0xb2, 0xdc, 0x86, 0x25, 0x6c, 0xcf, 0xf4, 0xbb,
0x14, 0xfd, 0x70, 0x27, 0x9f, 0xcc, 0x3c, 0xe9,
0x25, 0xc5, 0x1f, 0xb7, 0x17, 0xe5, 0x87, 0x6f,
@@ -1578,10 +1274,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x91, 0x04, 0xf9, 0x4f, 0xaa, 0x66, 0xe0, 0xcc,
0xc0, 0x41, 0x34, 0xd5, 0x80, 0x9a, 0x2a, 0x26,
0x70, 0xa3, 0xb7, 0xbc, 0x7d, 0xd9, 0x64, 0xf8 },
- { 0xb3, 0x95, 0x0e, 0x0b, 0xd2, 0x2c, 0x39, 0xfa,
- 0xb1, 0xdb, 0xd7, 0xbe, 0xb7, 0x42, 0x56, 0xaf,
- 0xb1, 0x1d, 0xcb, 0x26, 0x35, 0x69, 0x70, 0x83,
- 0xd6, 0x8f, 0xdb, 0xee, 0x80, 0xb0, 0x5f, 0x54 },
{ 0xb3, 0xe6, 0x42, 0x06, 0x6e, 0x41, 0x78, 0x67,
0xd9, 0x0f, 0xb9, 0xb2, 0xba, 0x15, 0x41, 0x98,
0xa5, 0xc5, 0xf6, 0xcc, 0x82, 0x9b, 0x51, 0x39,
@@ -1626,10 +1318,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x62, 0xb6, 0x2f, 0x36, 0x50, 0xdb, 0x00, 0xa3,
0x45, 0xf4, 0x6a, 0x0e, 0x8e, 0x01, 0x1a, 0x20,
0x01, 0x3f, 0xd8, 0xed, 0xce, 0x25, 0x27, 0x0d },
- { 0xba, 0x18, 0x2c, 0x1b, 0x75, 0xd8, 0xdf, 0xd1,
- 0x18, 0x92, 0xe4, 0x77, 0x59, 0x59, 0xad, 0x8a,
- 0x8c, 0x78, 0x2c, 0xef, 0x60, 0xec, 0xea, 0xbe,
- 0x56, 0x19, 0x72, 0x9b, 0xb8, 0x1b, 0x4a, 0x10 },
{ 0xba, 0x51, 0xaf, 0xf5, 0xd5, 0xd3, 0x10, 0x5f,
0x34, 0xa2, 0xb3, 0x3a, 0x83, 0xe3, 0xad, 0xfd,
0x12, 0xd7, 0x9c, 0xa6, 0x05, 0x90, 0x9d, 0x96,
@@ -1646,22 +1334,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xd9, 0x70, 0x44, 0xfd, 0xe3, 0xe3, 0xf9, 0x00,
0xfb, 0x1a, 0x0b, 0x04, 0x03, 0xb5, 0x81, 0x72,
0x5f, 0x34, 0xe3, 0xc1, 0x90, 0x05, 0x60, 0x56 },
- { 0xbe, 0x68, 0x35, 0x4f, 0x7c, 0x36, 0x24, 0x2d,
- 0xb6, 0x20, 0x4f, 0x20, 0x13, 0x1b, 0x01, 0xff,
- 0x28, 0xb7, 0xdd, 0xff, 0x36, 0x2e, 0x42, 0x9b,
- 0xfd, 0xf8, 0x8f, 0x36, 0x37, 0x58, 0x24, 0x51 },
{ 0xbe, 0xb9, 0x09, 0x0c, 0x92, 0xd1, 0x6b, 0xd0,
0x5a, 0xf3, 0x91, 0x5a, 0x39, 0xcc, 0x2a, 0xfa,
0x9f, 0x6a, 0x8a, 0x6f, 0xbe, 0xd4, 0xfe, 0x54,
0xd9, 0xde, 0x32, 0x49, 0x23, 0xb3, 0x93, 0x5a },
- { 0xbe, 0xd6, 0xf8, 0x1a, 0xd8, 0x5e, 0x71, 0x6b,
- 0x60, 0xd3, 0xe9, 0x7d, 0x8b, 0x90, 0x81, 0xe9,
- 0xc1, 0xb9, 0xec, 0x3b, 0xe8, 0xf3, 0xfd, 0x5b,
- 0xad, 0x55, 0x40, 0x2b, 0x79, 0x78, 0x5b, 0x37 },
- { 0xbe, 0xe1, 0xd6, 0x40, 0x7d, 0x2f, 0xe3, 0xdb,
- 0x76, 0x64, 0x4c, 0x58, 0xa4, 0xf2, 0xb6, 0x4e,
- 0x62, 0xf8, 0x93, 0xf8, 0x04, 0xfb, 0x9a, 0x87,
- 0xfe, 0xa3, 0x2c, 0x4c, 0x76, 0x45, 0x7f, 0x3b },
{ 0xbf, 0x38, 0xe6, 0xae, 0x32, 0x0f, 0x69, 0x16,
0x16, 0x0d, 0xa6, 0x06, 0x86, 0x83, 0xbf, 0x49,
0xf2, 0xb2, 0x2b, 0x25, 0x24, 0x84, 0x63, 0x68,
@@ -1718,10 +1394,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xfa, 0xe8, 0x9c, 0x45, 0x14, 0x3f, 0x20, 0xcc,
0x1b, 0x3e, 0x18, 0x1d, 0x29, 0xc2, 0xd0, 0xe8,
0xff, 0x7d, 0x3f, 0x2a, 0x66, 0xb1, 0x82, 0xfe },
- { 0xc4, 0x87, 0xa2, 0x59, 0x81, 0x9b, 0x56, 0xd3,
- 0x15, 0x9d, 0xd1, 0x73, 0x15, 0x7e, 0x86, 0x45,
- 0xb7, 0x0b, 0xca, 0x29, 0x08, 0xcb, 0x2c, 0x5b,
- 0xae, 0x34, 0x48, 0x6e, 0xa4, 0xf6, 0x14, 0xff },
{ 0xc4, 0x98, 0xa1, 0xb6, 0x9f, 0x54, 0x40, 0x86,
0x17, 0x47, 0x47, 0x71, 0x5a, 0x27, 0x4d, 0x3f,
0xb5, 0x90, 0x19, 0xbe, 0x09, 0x21, 0x31, 0xbc,
@@ -1766,10 +1438,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x5c, 0x8e, 0x95, 0xde, 0x62, 0x9a, 0xf5, 0xc1,
0xbf, 0xea, 0xc5, 0x50, 0x04, 0xc1, 0x54, 0x82,
0x3a, 0x58, 0xba, 0xe8, 0x05, 0x6e, 0x3c, 0x64 },
- { 0xc8, 0x26, 0xbe, 0xdd, 0x88, 0x6a, 0x87, 0x1d,
- 0xd5, 0xcf, 0x3a, 0x2a, 0xe0, 0xa5, 0x1c, 0x93,
- 0xbc, 0x2c, 0xff, 0x31, 0x90, 0xd1, 0xcb, 0x2c,
- 0x13, 0x13, 0x97, 0x29, 0x5a, 0x81, 0x76, 0xb5 },
{ 0xc8, 0x37, 0xd6, 0xf2, 0xab, 0x14, 0x79, 0x91,
0x42, 0xed, 0x3c, 0x79, 0xbe, 0xd9, 0x44, 0x1e,
0x92, 0x50, 0xbd, 0x05, 0x20, 0x25, 0xad, 0x8a,
@@ -1802,10 +1470,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xc5, 0x6f, 0xdf, 0x19, 0x1e, 0x1d, 0xaf, 0x9f,
0x32, 0x5c, 0x65, 0x0b, 0xd6, 0x2f, 0x07, 0xc4,
0x67, 0x71, 0x72, 0x07, 0x35, 0x1a, 0xe3, 0x29 },
- { 0xcb, 0x9c, 0x10, 0xf2, 0xcb, 0x7f, 0x7c, 0xdb,
- 0xfd, 0xb1, 0xf8, 0xed, 0x6a, 0x42, 0x32, 0xb4,
- 0x4d, 0x6f, 0x7c, 0x32, 0x57, 0xa5, 0x94, 0x99,
- 0xe2, 0x37, 0xec, 0x11, 0x3a, 0x2d, 0xdc, 0x1d },
{ 0xcc, 0x2a, 0x70, 0x6f, 0xe6, 0x8f, 0x5d, 0x17,
0xf4, 0xab, 0xaf, 0x60, 0x86, 0xe5, 0xbd, 0x97,
0xae, 0x35, 0xeb, 0x35, 0x9f, 0x75, 0xc0, 0x92,
@@ -1838,14 +1502,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x0f, 0x5c, 0x88, 0x75, 0x46, 0x4d, 0xcd, 0x5b,
0xa6, 0xc8, 0x90, 0xf4, 0x49, 0xb3, 0x20, 0x7b,
0xca, 0x2b, 0xc9, 0x61, 0x82, 0x2d, 0x27, 0xc4 },
- { 0xce, 0x83, 0x25, 0x83, 0x1d, 0xa3, 0xaf, 0x4d,
- 0x77, 0xac, 0x41, 0xce, 0xd9, 0x2a, 0xed, 0x17,
- 0x95, 0x8a, 0x2b, 0x27, 0xaa, 0xfd, 0xef, 0x64,
- 0xdb, 0x3e, 0xa2, 0x26, 0x03, 0x2c, 0x0f, 0x87 },
- { 0xce, 0x9d, 0xe7, 0xac, 0x2e, 0x0b, 0x8a, 0x4f,
- 0x85, 0xf5, 0xb6, 0x4e, 0x65, 0x22, 0x8d, 0x03,
- 0xfc, 0x77, 0x93, 0xd9, 0x49, 0x42, 0xf8, 0x8a,
- 0x1c, 0x72, 0xbb, 0x7b, 0x61, 0x14, 0x51, 0xd5 },
{ 0xcf, 0xa0, 0xc0, 0x0c, 0xb2, 0xfb, 0x4b, 0x85,
0x7a, 0xad, 0x22, 0xb1, 0x3a, 0x90, 0xe3, 0x46,
0xa0, 0x3e, 0x6b, 0x79, 0xab, 0xd5, 0xd2, 0x75,
@@ -1854,14 +1510,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x51, 0x69, 0x81, 0xee, 0x56, 0xf1, 0xd5, 0x98,
0xa2, 0xa6, 0x03, 0x48, 0x8c, 0x67, 0x8c, 0x1b,
0x7b, 0xbe, 0xa6, 0x44, 0x6b, 0x00, 0x83, 0xad },
- { 0xd1, 0x24, 0xfc, 0x30, 0x54, 0x79, 0x1f, 0x76,
- 0xbb, 0x8b, 0xaf, 0x57, 0xf5, 0xc4, 0x5b, 0x69,
- 0x16, 0x8c, 0x3a, 0x6e, 0xe3, 0xfb, 0xcd, 0xf3,
- 0xec, 0x2a, 0x77, 0xe8, 0x7c, 0x7c, 0x50, 0x09 },
- { 0xd2, 0x56, 0x79, 0xcb, 0x58, 0x3b, 0xa0, 0x10,
- 0x8f, 0x74, 0x97, 0xe3, 0x21, 0xc6, 0x5c, 0x4d,
- 0xc2, 0xca, 0x0f, 0x28, 0x20, 0xc7, 0xfc, 0xdb,
- 0x11, 0x3f, 0x05, 0x72, 0xdf, 0x44, 0x79, 0x34 },
{ 0xd2, 0x90, 0x3c, 0xa2, 0x55, 0x17, 0x27, 0xed,
0x01, 0x71, 0xcc, 0x4a, 0x43, 0xb3, 0xca, 0xe0,
0x09, 0xb7, 0x47, 0xb9, 0xf4, 0xf8, 0x48, 0x72,
@@ -1870,10 +1518,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xd1, 0xba, 0x8f, 0x09, 0xe4, 0xff, 0x10, 0x7b,
0x62, 0x35, 0x78, 0x85, 0x42, 0xaa, 0x61, 0x83,
0xd1, 0x76, 0xdb, 0xf1, 0xc8, 0x8d, 0xcf, 0xb6 },
- { 0xd3, 0x22, 0xe0, 0xc4, 0x4e, 0xa7, 0x92, 0xc0,
- 0x00, 0x13, 0x01, 0xa6, 0x32, 0xa1, 0x1d, 0x50,
- 0x6e, 0xa9, 0x17, 0xde, 0xed, 0xca, 0x8e, 0xd0,
- 0x5f, 0x9e, 0x7a, 0xf0, 0xb6, 0x08, 0x55, 0x8b },
{ 0xd5, 0x04, 0x88, 0x96, 0x86, 0x07, 0x29, 0xa8,
0xfa, 0x5d, 0x23, 0x57, 0x81, 0x2b, 0xa5, 0x6c,
0xbe, 0x84, 0xc9, 0xab, 0x7d, 0x14, 0xdf, 0x47,
@@ -1890,10 +1534,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x7e, 0x50, 0x48, 0x66, 0xfe, 0x5b, 0xa3, 0xc0,
0xed, 0xca, 0xee, 0xd5, 0x2a, 0xd0, 0xaf, 0x07,
0xe6, 0x79, 0x17, 0x73, 0x85, 0x12, 0xc8, 0xf5 },
- { 0xd5, 0xcb, 0xab, 0xc2, 0x61, 0x1a, 0x6c, 0x55,
- 0xaf, 0xb0, 0x43, 0x27, 0xe2, 0x60, 0x8c, 0xec,
- 0xf3, 0x45, 0x6c, 0x9f, 0xd8, 0xc7, 0x66, 0x58,
- 0x18, 0xa5, 0x4d, 0x5d, 0x93, 0x24, 0x97, 0xab },
{ 0xd6, 0x25, 0xc0, 0x59, 0x2b, 0x25, 0xdc, 0x03,
0xaa, 0x7e, 0x87, 0x8e, 0x6a, 0x85, 0x09, 0x1b,
0xaa, 0x07, 0x8d, 0x26, 0x8b, 0xbd, 0xb4, 0x9f,
@@ -1902,10 +1542,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x70, 0xa0, 0xb4, 0x3b, 0xa5, 0x9a, 0xb3, 0xd3,
0x22, 0x5f, 0x37, 0x32, 0x64, 0xdd, 0x87, 0xfb,
0xca, 0x00, 0x61, 0xec, 0x1c, 0x4d, 0xa1, 0x1a },
- { 0xd7, 0x2c, 0x0e, 0x02, 0xa8, 0x71, 0xa9, 0xc2,
- 0x86, 0x7d, 0xb5, 0x13, 0x63, 0x62, 0x56, 0x98,
- 0x32, 0xdc, 0x3b, 0x85, 0xaa, 0x05, 0x4a, 0x6c,
- 0x9e, 0xcc, 0x19, 0x01, 0x0e, 0xba, 0x39, 0x3a },
{ 0xd7, 0x32, 0x49, 0x74, 0xb5, 0x60, 0x09, 0x62,
0x17, 0x61, 0xf7, 0xc0, 0xff, 0x68, 0x9d, 0xde,
0x47, 0x74, 0x99, 0x85, 0xe1, 0xee, 0x8b, 0x5c,
@@ -1934,26 +1570,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x64, 0x8d, 0x0e, 0xd8, 0x9b, 0x5d, 0xe0, 0xee,
0x93, 0x1f, 0x1b, 0x33, 0x84, 0x78, 0xab, 0xf5,
0x69, 0x29, 0xa9, 0x4d, 0x3b, 0xd6, 0x1d, 0x46 },
- { 0xdb, 0x1b, 0x33, 0x54, 0x93, 0xbe, 0x68, 0xd2,
- 0x8e, 0x3c, 0x4d, 0x3d, 0x11, 0x84, 0x99, 0x42,
- 0x26, 0x17, 0x93, 0x49, 0xda, 0xf1, 0x79, 0x5b,
- 0x77, 0x39, 0x3e, 0x2d, 0xd9, 0x87, 0xbb, 0x43 },
- { 0xdb, 0xa2, 0x21, 0xc2, 0xab, 0x44, 0xb5, 0x2c,
- 0x0b, 0x83, 0x36, 0xc4, 0x69, 0xfa, 0xa8, 0x56,
- 0xd6, 0xc3, 0xec, 0xdc, 0x6c, 0x24, 0x6b, 0xe3,
- 0xca, 0xc7, 0xe0, 0xf6, 0x28, 0x4b, 0x5b, 0xda },
{ 0xdc, 0xb2, 0x1d, 0xef, 0x3c, 0x26, 0x0b, 0x20,
0x50, 0xf3, 0x4c, 0x5f, 0x51, 0xbe, 0x30, 0x9c,
0x3c, 0x76, 0x36, 0x30, 0x6d, 0x51, 0xb9, 0xbe,
0x43, 0xd8, 0x9d, 0xe0, 0x8f, 0x60, 0xd9, 0x4a },
- { 0xdd, 0x30, 0xcb, 0x75, 0xc9, 0x3e, 0x01, 0xfc,
- 0xc6, 0xe8, 0x44, 0x63, 0xfd, 0x47, 0x78, 0x15,
- 0x8f, 0x3a, 0x18, 0xce, 0x89, 0x67, 0x7b, 0x01,
- 0xe6, 0xff, 0x5b, 0xa7, 0x2f, 0xa4, 0xd0, 0xf6 },
- { 0xde, 0x5c, 0x3d, 0x09, 0x58, 0xa6, 0x12, 0xbd,
- 0x6d, 0x48, 0x09, 0x15, 0x03, 0x3d, 0x97, 0x15,
- 0x58, 0xdf, 0x35, 0xce, 0xb1, 0xc9, 0x18, 0xe6,
- 0x9a, 0x01, 0x34, 0x51, 0xe4, 0x50, 0x95, 0xb8 },
{ 0xde, 0xcd, 0xb9, 0xfc, 0x1d, 0xde, 0xc9, 0x7e,
0x09, 0xc3, 0x02, 0x6a, 0xce, 0xb7, 0x6b, 0xda,
0xe9, 0xde, 0xb6, 0x62, 0x75, 0x1d, 0xda, 0x34,
@@ -1990,10 +1610,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x05, 0x68, 0x6f, 0x17, 0x79, 0x1b, 0x05, 0xf1,
0xfe, 0x25, 0xf7, 0x71, 0x86, 0x9c, 0x42, 0x63,
0xa5, 0x5b, 0x94, 0x18, 0x77, 0xe4, 0x79, 0x04 },
- { 0xe2, 0xb4, 0x03, 0x32, 0x0b, 0x01, 0xf6, 0x03,
- 0xd7, 0xb0, 0xca, 0x1f, 0x89, 0xf0, 0x8e, 0x25,
- 0xa7, 0x95, 0xe8, 0xb6, 0x04, 0x36, 0x8b, 0xa0,
- 0x78, 0x69, 0x68, 0x46, 0x8c, 0x18, 0xc3, 0xf0 },
{ 0xe2, 0xf3, 0x9a, 0x9d, 0x48, 0xa3, 0x22, 0x10,
0x55, 0xb3, 0xc8, 0xa3, 0xeb, 0x14, 0x39, 0xd6,
0xb8, 0x73, 0x01, 0x3e, 0xe4, 0xd0, 0x97, 0x12,
@@ -2002,18 +1618,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x7e, 0x1f, 0x45, 0x5b, 0x85, 0xc0, 0x6f, 0x0d,
0x80, 0x9e, 0x75, 0xa5, 0x5c, 0x6b, 0x05, 0x48,
0x16, 0xe0, 0x19, 0x89, 0x9a, 0x3a, 0x02, 0xff },
- { 0xe3, 0xc8, 0xfc, 0x63, 0x7b, 0x7b, 0xb0, 0xcc,
- 0x67, 0x4a, 0x5a, 0x4c, 0x3b, 0x4d, 0x35, 0x62,
- 0xeb, 0x8a, 0xa0, 0x0d, 0x7a, 0xd2, 0xc8, 0xa9,
- 0xc6, 0x37, 0x09, 0xe4, 0x51, 0x06, 0x52, 0xd5 },
{ 0xe4, 0xf1, 0xde, 0x31, 0xcd, 0xaa, 0x6d, 0x9e,
0xb1, 0xaa, 0xfd, 0x10, 0x81, 0x27, 0xa2, 0xf0,
0xa8, 0xfb, 0x6d, 0xa8, 0x5a, 0x04, 0x14, 0xad,
0x24, 0x99, 0x47, 0xc4, 0x8d, 0x24, 0x92, 0xc5 },
- { 0xe5, 0xf1, 0x20, 0xb8, 0x78, 0x63, 0x43, 0x1a,
- 0xd8, 0x34, 0xd8, 0x47, 0x94, 0x86, 0x4a, 0x90,
- 0x0e, 0x39, 0x30, 0xe0, 0xce, 0xce, 0xa1, 0x4b,
- 0x0d, 0x31, 0x33, 0xa9, 0x87, 0x74, 0x48, 0x89 },
{ 0xe6, 0x44, 0xd1, 0x1c, 0x37, 0x07, 0x0f, 0x89,
0x69, 0x33, 0x08, 0x17, 0x8d, 0x6b, 0xe4, 0x95,
0x94, 0x96, 0x92, 0xc1, 0xfb, 0xeb, 0x30, 0xed,
@@ -2050,22 +1658,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xe1, 0x85, 0x28, 0x37, 0x5c, 0xfd, 0xc7, 0x21,
0x9a, 0x6b, 0xde, 0x46, 0x1b, 0x19, 0x73, 0xbe,
0x2b, 0xb8, 0xbd, 0xf0, 0xda, 0x78, 0xb2, 0xb4 },
- { 0xea, 0x2e, 0x8c, 0x23, 0xaa, 0x7c, 0xc3, 0x7d,
- 0x64, 0xcf, 0xc3, 0x03, 0xdd, 0x9f, 0x3f, 0x92,
- 0x1b, 0xae, 0x11, 0x8c, 0xa3, 0xdf, 0x81, 0xe5,
- 0x92, 0xe3, 0x0b, 0xbb, 0x03, 0x71, 0x4d, 0x96 },
- { 0xea, 0x5a, 0xb6, 0x6c, 0xaf, 0xde, 0x63, 0x38,
- 0xc0, 0x67, 0x8d, 0x74, 0x54, 0xd0, 0x79, 0x6d,
- 0xde, 0xa0, 0xd2, 0x84, 0xdd, 0xaa, 0x79, 0x4d,
- 0x04, 0x42, 0x0e, 0xda, 0x97, 0x71, 0xc5, 0x1a },
{ 0xeb, 0x11, 0x63, 0xaa, 0xef, 0xe8, 0xfd, 0x88,
0xe1, 0x32, 0x7b, 0x48, 0xa9, 0xc0, 0x06, 0x2e,
0x06, 0xf0, 0xa6, 0xea, 0xa0, 0xa0, 0x18, 0x24,
0x7f, 0x9f, 0xa4, 0xe3, 0x4e, 0x3a, 0x47, 0x4c },
- { 0xeb, 0x5b, 0x21, 0x0f, 0x76, 0xa3, 0xc4, 0x5e,
- 0x5a, 0x76, 0x07, 0x64, 0x3e, 0x15, 0x26, 0x0d,
- 0x1c, 0x93, 0xfd, 0x9b, 0xe0, 0xfa, 0xb1, 0x0b,
- 0x76, 0xdc, 0x96, 0x86, 0xf6, 0x54, 0xc6, 0xe5 },
{ 0xec, 0x4b, 0xbd, 0xeb, 0x15, 0x12, 0x1d, 0x96,
0x76, 0x4d, 0x6c, 0x01, 0xb2, 0x7e, 0xd5, 0xae,
0x86, 0x46, 0x5c, 0x46, 0xd5, 0xa4, 0x0e, 0x34,
@@ -2082,10 +1678,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x17, 0x08, 0xf2, 0x56, 0x75, 0x4a, 0x89, 0xc4,
0x29, 0x67, 0x9b, 0x30, 0x75, 0x8e, 0xe0, 0x12,
0x2b, 0x9e, 0x50, 0x85, 0x8d, 0xe2, 0x10, 0x4b },
- { 0xed, 0x6d, 0xda, 0xe4, 0xf4, 0xaf, 0xce, 0x6b,
- 0xaf, 0x3a, 0x63, 0x7d, 0x89, 0x0a, 0x0d, 0x65,
- 0x75, 0x3e, 0x45, 0x97, 0x14, 0x5a, 0xf8, 0x97,
- 0x53, 0x9b, 0xf9, 0xf7, 0xd3, 0x42, 0xa1, 0xd1 },
{ 0xed, 0xc1, 0xbf, 0x3e, 0xfb, 0xf7, 0xe1, 0xd9,
0x5e, 0x19, 0xc5, 0x5e, 0xca, 0xe7, 0x7e, 0x83,
0x69, 0x46, 0xab, 0x0a, 0x26, 0xa7, 0x8e, 0x32,
@@ -2110,10 +1702,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x62, 0x2b, 0xf4, 0x3a, 0x0e, 0xb3, 0xc5, 0x1a,
0xcb, 0xdd, 0xde, 0xdc, 0x23, 0x92, 0xf1, 0x61,
0xac, 0xed, 0x16, 0x71, 0xa6, 0x53, 0x60, 0x7e },
- { 0xef, 0xb5, 0xbe, 0x9f, 0xa2, 0xc6, 0xee, 0x48,
- 0x9f, 0x9e, 0xb3, 0xdd, 0x55, 0x42, 0xa7, 0x0c,
- 0x22, 0x57, 0xb5, 0x6b, 0x24, 0x0b, 0x3b, 0x4b,
- 0x29, 0xf3, 0xb4, 0xe6, 0xba, 0x8a, 0xed, 0xe3 },
{ 0xef, 0xd1, 0xe0, 0xe7, 0x3f, 0xa8, 0x71, 0x00,
0xb7, 0x6a, 0x93, 0x23, 0x49, 0xc4, 0x5d, 0x09,
0xb2, 0x8b, 0x2d, 0x8a, 0x00, 0x17, 0x19, 0xa5,
@@ -2134,18 +1722,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x38, 0xed, 0xb5, 0x9f, 0x0f, 0x99, 0x23, 0xc6,
0xd4, 0x11, 0x0a, 0x4b, 0x3a, 0xc8, 0xac, 0x76,
0x55, 0x6a, 0x0c, 0x92, 0x44, 0xf0, 0x3f, 0xc1 },
- { 0xf1, 0x9a, 0xe4, 0x7d, 0x93, 0x67, 0x16, 0x52,
- 0x78, 0xe1, 0x66, 0xed, 0x44, 0xff, 0xc3, 0x7e,
- 0x5b, 0x28, 0x19, 0x6c, 0x01, 0x4b, 0xf1, 0x18,
- 0xcf, 0xc6, 0x4e, 0xd5, 0xfa, 0x18, 0x19, 0x4d },
{ 0xf2, 0xb1, 0x95, 0x84, 0x6e, 0xe2, 0xb9, 0xab,
0x5f, 0x18, 0xe6, 0x80, 0x21, 0xf8, 0xdf, 0x7c,
0x0b, 0x60, 0x58, 0xde, 0xde, 0x86, 0xc5, 0xd5,
0x90, 0xf2, 0xe8, 0x64, 0x3a, 0xfe, 0x04, 0x52 },
- { 0xf2, 0xe3, 0x0f, 0xb6, 0xcd, 0x91, 0x67, 0x54,
- 0x84, 0x72, 0xcc, 0xdf, 0x58, 0x9f, 0x3d, 0x00,
- 0x43, 0x0c, 0x22, 0xb8, 0x33, 0x44, 0xa1, 0x16,
- 0x5b, 0x64, 0xe6, 0x87, 0x4d, 0xf3, 0x5e, 0xdc },
{ 0xf2, 0xe5, 0x30, 0x0c, 0x39, 0xf2, 0x86, 0xc6,
0x78, 0x99, 0x90, 0x9c, 0x7c, 0xe7, 0x35, 0x9b,
0x09, 0x45, 0xd2, 0xaf, 0xd3, 0x4a, 0x6d, 0xd6,
@@ -2154,10 +1734,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0x5f, 0x07, 0x09, 0x6a, 0xf4, 0xb8, 0xbe, 0xdc,
0x16, 0x3c, 0x0f, 0x6e, 0xd5, 0x34, 0x6e, 0xfc,
0x28, 0xe8, 0xcf, 0xaf, 0x84, 0x2f, 0xa5, 0xd9 },
- { 0xf5, 0x82, 0xf1, 0x66, 0xb8, 0x2b, 0xed, 0x47,
- 0xef, 0xe3, 0x66, 0x1a, 0xa8, 0x02, 0x32, 0xfa,
- 0x81, 0x67, 0xd2, 0xe8, 0x97, 0x96, 0xa3, 0x66,
- 0xea, 0x35, 0xad, 0x40, 0xa1, 0xba, 0x2f, 0x66 },
{ 0xf6, 0x13, 0xd5, 0x90, 0x46, 0xd1, 0x66, 0x71,
0xd3, 0xc5, 0x60, 0x17, 0x6f, 0x3d, 0x77, 0xfd,
0xc5, 0x1e, 0x5f, 0x57, 0xb5, 0xe4, 0x8a, 0xe7,
@@ -2174,22 +1750,10 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xe7, 0xf7, 0x75, 0x2c, 0x2f, 0x74, 0x5d, 0x59,
0xd6, 0x37, 0x57, 0xc6, 0xcc, 0x14, 0xd2, 0x25,
0x3a, 0x64, 0x7c, 0xd1, 0x81, 0x49, 0x39, 0x93 },
- { 0xf6, 0xfe, 0xb3, 0x88, 0x25, 0xe6, 0xee, 0x7b,
- 0xa5, 0xbf, 0xd9, 0x4b, 0xb5, 0x77, 0x12, 0xa4,
- 0x14, 0x1e, 0xb8, 0xd0, 0x92, 0xbb, 0x2d, 0x5d,
- 0xd1, 0x64, 0xf6, 0x74, 0xa2, 0xe5, 0xb0, 0x64 },
{ 0xf8, 0x64, 0x44, 0x3e, 0x2f, 0x63, 0x9e, 0x7c,
0xff, 0xd2, 0x42, 0x21, 0xf6, 0x1b, 0xbf, 0xf0,
0x7c, 0xce, 0x5c, 0x61, 0xdd, 0xb1, 0x68, 0xb3,
0xb4, 0x04, 0xd7, 0xc8, 0xcd, 0xca, 0x18, 0xb2 },
- { 0xf8, 0x76, 0xc7, 0x3f, 0xae, 0x72, 0x52, 0x5d,
- 0x4a, 0xd5, 0x26, 0x69, 0xbc, 0x5a, 0x34, 0xdc,
- 0x8d, 0x46, 0x14, 0xe9, 0x3b, 0xfd, 0xee, 0xec,
- 0xa3, 0xd9, 0xbe, 0xca, 0x97, 0x2e, 0xc6, 0xb8 },
- { 0xf8, 0x81, 0x51, 0xc3, 0xd8, 0x91, 0x6b, 0x1d,
- 0x03, 0xa0, 0x5f, 0x55, 0x85, 0xec, 0x38, 0xad,
- 0x1c, 0xc0, 0x3a, 0x36, 0x2e, 0x68, 0x60, 0x8e,
- 0x39, 0x13, 0xed, 0xdf, 0xb1, 0xfd, 0xf1, 0x27 },
{ 0xf8, 0x94, 0xf9, 0x67, 0x36, 0x9c, 0xe7, 0xcf,
0xa3, 0x1a, 0xc1, 0x9a, 0x66, 0x65, 0xb0, 0xc4,
0x24, 0xba, 0x40, 0x8a, 0xd5, 0xd3, 0x65, 0xf1,
@@ -2258,10 +1822,6 @@ const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = {
0xff, 0xcb, 0x68, 0xd0, 0x76, 0x4e, 0xcb, 0x2a,
0x87, 0xca, 0xa0, 0xae, 0x4c, 0xb5, 0x66, 0x62,
0x21, 0x04, 0xd3, 0x6f, 0xfb, 0x52, 0xcb, 0x29 },
- { 0xfe, 0xb8, 0xf0, 0x0c, 0x83, 0xea, 0x05, 0xbd,
- 0xa2, 0x85, 0x0e, 0xc5, 0xbb, 0x77, 0x43, 0xe4,
- 0x42, 0xeb, 0xf4, 0x31, 0xe3, 0xba, 0x75, 0x4a,
- 0xa2, 0xd9, 0x47, 0x5e, 0x98, 0x0b, 0x6e, 0x3a },
{ 0xff, 0x82, 0x6e, 0x2d, 0x0c, 0xb7, 0x71, 0x68,
0x68, 0x67, 0x5a, 0xe4, 0xb4, 0x31, 0xb6, 0x37,
0x1e, 0x9f, 0x0c, 0xdf, 0xcc, 0xb4, 0x9d, 0x43,
diff --git a/chromium/net/cert/cert_verify_proc_win.cc b/chromium/net/cert/cert_verify_proc_win.cc
index 226c359fb6c..a2647969d80 100644
--- a/chromium/net/cert/cert_verify_proc_win.cc
+++ b/chromium/net/cert/cert_verify_proc_win.cc
@@ -949,8 +949,8 @@ int CertVerifyProcWin::VerifyInternal(
// By default, use the default HCERTCHAINENGINE (aka HCCE_CURRENT_USER). When
// running tests, use a dynamic HCERTCHAINENGINE. All of the status and cache
// of verified certificates and chains is tied to the HCERTCHAINENGINE. As
- // each invocation may have changed the set of known roots, invalid the cache
- // between runs.
+ // each invocation may have changed the set of known roots, invalidate the
+ // cache between runs.
//
// This is not the most efficient means of doing so; it's possible to mark the
// Root store used by TestRootCerts as changed, via CertControlStore with the
diff --git a/chromium/net/cert/cert_verify_result.cc b/chromium/net/cert/cert_verify_result.cc
index 1b91fc7d23f..b1054e4ced3 100644
--- a/chromium/net/cert/cert_verify_result.cc
+++ b/chromium/net/cert/cert_verify_result.cc
@@ -32,6 +32,7 @@ void CertVerifyResult::Reset() {
common_name_fallback_used = false;
public_key_hashes.clear();
+ ocsp_result = OCSPVerifyResult();
}
bool CertVerifyResult::operator==(const CertVerifyResult& other) const {
@@ -39,12 +40,12 @@ bool CertVerifyResult::operator==(const CertVerifyResult& other) const {
std::tie(cert_status, has_md2, has_md4, has_md5, has_sha1,
has_sha1_leaf, public_key_hashes, is_issued_by_known_root,
is_issued_by_additional_trust_anchor,
- common_name_fallback_used) ==
+ common_name_fallback_used, ocsp_result) ==
std::tie(other.cert_status, other.has_md2, other.has_md4,
other.has_md5, other.has_sha1, other.has_sha1_leaf,
other.public_key_hashes, other.is_issued_by_known_root,
other.is_issued_by_additional_trust_anchor,
- other.common_name_fallback_used);
+ other.common_name_fallback_used, other.ocsp_result);
}
} // namespace net
diff --git a/chromium/net/cert/cert_verify_result.h b/chromium/net/cert/cert_verify_result.h
index e93d8b06841..29c0675af3f 100644
--- a/chromium/net/cert/cert_verify_result.h
+++ b/chromium/net/cert/cert_verify_result.h
@@ -10,6 +10,7 @@
#include "base/memory/ref_counted.h"
#include "net/base/net_export.h"
#include "net/cert/cert_status_flags.h"
+#include "net/cert/ocsp_verify_result.h"
#include "net/cert/x509_cert_types.h"
namespace net {
@@ -66,6 +67,9 @@ class NET_EXPORT CertVerifyResult {
// True if a fallback to the common name was used when matching the host
// name, rather than using the subjectAltName.
bool common_name_fallback_used;
+
+ // Verification of stapled OCSP response, if present.
+ OCSPVerifyResult ocsp_result;
};
} // namespace net
diff --git a/chromium/net/cert/ct_known_logs.cc b/chromium/net/cert/ct_known_logs.cc
index da086c7312c..a65988971ed 100644
--- a/chromium/net/cert/ct_known_logs.cc
+++ b/chromium/net/cert/ct_known_logs.cc
@@ -37,7 +37,8 @@ CreateLogVerifiersForKnownLogs() {
// Add all qualified logs.
for (const auto& log : kCTLogList) {
base::StringPiece key(log.log_key, log.log_key_length);
- verifiers.push_back(CTLogVerifier::Create(key, log.log_name, log.log_url));
+ verifiers.push_back(CTLogVerifier::Create(key, log.log_name, log.log_url,
+ log.log_dns_domain));
// Make sure no null logs enter verifiers. Parsing of all known logs should
// succeed.
CHECK(verifiers.back().get());
@@ -48,7 +49,8 @@ CreateLogVerifiersForKnownLogs() {
for (const auto& disqualified_log : kDisqualifiedCTLogList) {
const CTLogInfo& log = disqualified_log.log_info;
base::StringPiece key(log.log_key, log.log_key_length);
- verifiers.push_back(CTLogVerifier::Create(key, log.log_name, log.log_url));
+ verifiers.push_back(CTLogVerifier::Create(key, log.log_name, log.log_url,
+ log.log_dns_domain));
// Make sure no null logs enter verifiers. Parsing of all known logs should
// succeed.
CHECK(verifiers.back().get());
diff --git a/chromium/net/cert/ct_known_logs_static-inc.h b/chromium/net/cert/ct_known_logs_static-inc.h
index 783db760ead..7ead66cc559 100644
--- a/chromium/net/cert/ct_known_logs_static-inc.h
+++ b/chromium/net/cert/ct_known_logs_static-inc.h
@@ -10,12 +10,19 @@ struct CTLogInfo {
// The user-friendly log name.
// Note: This will not be translated.
const char* const log_name;
- // The API endpoint for the log.
+ // The HTTPS API endpoint for the log.
// Note: Trailing slashes should be included.
const char* const log_url;
+ // The DNS API endpoint for the log.
+ // This is used as the parent domain for all queries about the log.
+ // If empty, CT DNS queries are not supported for the log. This will prevent
+ // retrieval of inclusion proofs over DNS for SCTs from the log.
+ // https://github.com/google/certificate-transparency-rfcs/blob/master/dns/draft-ct-over-dns.md.
+ const char* const log_dns_domain;
};
// The set of all presently-qualifying CT logs.
+// Google provides DNS frontends for all of the logs.
const CTLogInfo kCTLogList[] = {
{"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86"
"\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x7d\xa8\x4b\x12\x29\x80\xa3"
@@ -23,35 +30,40 @@ const CTLogInfo kCTLogList[] = {
"\x0c\xe8\x41\x46\xe8\x81\x01\x1b\x15\xe1\x4b\xf1\x1b\x62\xdd\x36\x0a"
"\x08\x18\xba\xed\x0b\x35\x84\xd0\x9e\x40\x3c\x2d\x9e\x9b\x82\x65\xbd"
"\x1f\x04\x10\x41\x4c\xa0",
- 91, "Google 'Pilot' log", "https://ct.googleapis.com/pilot/"},
+ 91, "Google 'Pilot' log", "https://ct.googleapis.com/pilot/",
+ "pilot.ct.googleapis.com"},
{"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86"
"\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xd7\xf4\xcc\x69\xb2\xe4\x0e"
"\x90\xa3\x8a\xea\x5a\x70\x09\x4f\xef\x13\x62\xd0\x8d\x49\x60\xff\x1b"
"\x40\x50\x07\x0c\x6d\x71\x86\xda\x25\x49\x8d\x65\xe1\x08\x0d\x47\x34"
"\x6b\xbd\x27\xbc\x96\x21\x3e\x34\xf5\x87\x76\x31\xb1\x7f\x1d\xc9\x85"
"\x3b\x0d\xf7\x1f\x3f\xe9",
- 91, "Google 'Aviator' log", "https://ct.googleapis.com/aviator/"},
+ 91, "Google 'Aviator' log", "https://ct.googleapis.com/aviator/",
+ "aviator.ct.googleapis.com"},
{"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86"
"\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x02\x46\xc5\xbe\x1b\xbb\x82"
"\x40\x16\xe8\xc1\xd2\xac\x19\x69\x13\x59\xf8\xf8\x70\x85\x46\x40\xb9"
"\x38\xb0\x23\x82\xa8\x64\x4c\x7f\xbf\xbb\x34\x9f\x4a\x5f\x28\x8a\xcf"
"\x19\xc4\x00\xf6\x36\x06\x93\x65\xed\x4c\xf5\xa9\x21\x62\x5a\xd8\x91"
"\xeb\x38\x24\x40\xac\xe8",
- 91, "DigiCert Log Server", "https://ct1.digicert-ct.com/log/"},
+ 91, "DigiCert Log Server", "https://ct1.digicert-ct.com/log/",
+ "digicert.ct.googleapis.com"},
{"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86"
"\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x20\x5b\x18\xc8\x3c\xc1\x8b"
"\xb3\x31\x08\x00\xbf\xa0\x90\x57\x2b\xb7\x47\x8c\x6f\xb5\x68\xb0\x8e"
"\x90\x78\xe9\xa0\x73\xea\x4f\x28\x21\x2e\x9c\xc0\xf4\x16\x1b\xaa\xf9"
"\xd5\xd7\xa9\x80\xc3\x4e\x2f\x52\x3c\x98\x01\x25\x46\x24\x25\x28\x23"
"\x77\x2d\x05\xc2\x40\x7a",
- 91, "Google 'Rocketeer' log", "https://ct.googleapis.com/rocketeer/"},
+ 91, "Google 'Rocketeer' log", "https://ct.googleapis.com/rocketeer/",
+ "rocketeer.ct.googleapis.com"},
{"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86"
"\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x96\xea\xac\x1c\x46\x0c\x1b"
"\x55\xdc\x0d\xfc\xb5\x94\x27\x46\x57\x42\x70\x3a\x69\x18\xe2\xbf\x3b"
"\xc4\xdb\xab\xa0\xf4\xb6\x6c\xc0\x53\x3f\x4d\x42\x10\x33\xf0\x58\x97"
"\x8f\x6b\xbe\x72\xf4\x2a\xec\x1c\x42\xaa\x03\x2f\x1a\x7e\x28\x35\x76"
"\x99\x08\x3d\x21\x14\x86",
- 91, "Symantec log", "https://ct.ws.symantec.com/"},
+ 91, "Symantec log", "https://ct.ws.symantec.com/",
+ "symantec.ct.googleapis.com"},
{"\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01"
"\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xa2"
"\x5a\x48\x1f\x17\x52\x95\x35\xcb\xa3\x5b\x3a\x1f\x53\x82\x76\x94\xa3"
@@ -70,14 +82,16 @@ const CTLogInfo kCTLogList[] = {
"\x05\xbf\x5f\xae\x94\x97\xdb\x5f\x64\xd4\xee\x16\x8b\xa3\x84\x6c\x71"
"\x2b\xf1\xab\x7f\x5d\x0d\x32\xee\x04\xe2\x90\xec\x41\x9f\xfb\x39\xc1"
"\x02\x03\x01\x00\x01",
- 294, "Venafi log", "https://ctlog.api.venafi.com/"},
+ 294, "Venafi log", "https://ctlog.api.venafi.com/",
+ "venafi.ct.googleapis.com"},
{"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86"
"\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xea\x95\x9e\x02\xff\xee\xf1"
"\x33\x6d\x4b\x87\xbc\xcd\xfd\x19\x17\x62\xff\x94\xd3\xd0\x59\x07\x3f"
"\x02\x2d\x1c\x90\xfe\xc8\x47\x30\x3b\xf1\xdd\x0d\xb8\x11\x0c\x5d\x1d"
"\x86\xdd\xab\xd3\x2b\x46\x66\xfb\x6e\x65\xb7\x3b\xfd\x59\x68\xac\xdf"
"\xa6\xf8\xce\xd2\x18\x4d",
- 91, "Symantec 'Vega' log", "https://vega.ws.symantec.com/"},
+ 91, "Symantec 'Vega' log", "https://vega.ws.symantec.com/",
+ "symantec-vega.ct.googleapis.com"},
{"\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01"
"\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xbf"
"\xb5\x08\x61\x9a\x29\x32\x04\xd3\x25\x63\xe9\xd8\x85\xe1\x86\xe0\x1f"
@@ -96,7 +110,40 @@ const CTLogInfo kCTLogList[] = {
"\x6f\xdf\x3c\x2c\x43\x57\xa1\x47\x0c\x91\x04\xf4\x75\x4d\xda\x89\x81"
"\xa4\x14\x06\x34\xb9\x98\xc3\xda\xf1\xfd\xed\x33\x36\xd3\x16\x2d\x35"
"\x02\x03\x01\x00\x01",
- 294, "CNNIC CT log", "https://ctserver.cnnic.cn/"}};
+ 294, "CNNIC CT log", "https://ctserver.cnnic.cn/",
+ "cnnic.ct.googleapis.com"},
+ {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86"
+ "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xcc\x11\x88\x7b\x2d\x66\xcb"
+ "\xae\x8f\x4d\x30\x66\x27\x19\x25\x22\x93\x21\x46\xb4\x2f\x01\xd3\xc6"
+ "\xf9\x2b\xd5\xc8\xba\x73\x9b\x06\xa2\xf0\x8a\x02\x9c\xd0\x6b\x46\x18"
+ "\x30\x85\xba\xe9\x24\x8b\x0e\xd1\x5b\x70\x28\x0c\x7e\xf1\x3a\x45\x7f"
+ "\x5a\xf3\x82\x42\x60\x31",
+ 91, "WoSign log", "https://ctlog.wosign.com/",
+ "wosign1.ct.googleapis.com"},
+ {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86"
+ "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x48\xf3\x59\xf3\xf6\x05\x18"
+ "\xd3\xdb\xb2\xed\x46\x7e\xcf\xc8\x11\xb5\x57\xb1\xa8\xd6\x4c\xe6\x9f"
+ "\xb7\x4a\x1a\x14\x86\x43\xa9\x48\xb0\xcb\x5a\x3f\x3c\x4a\xca\xdf\xc4"
+ "\x82\x14\x55\x9a\xf8\xf7\x8e\x40\x55\xdc\xf4\xd2\xaf\xea\x75\x74\xfb"
+ "\x4e\x7f\x60\x86\x2e\x51",
+ 91, "StartCom CT log", "https://ct.startssl.com/",
+ "startcom1.ct.googleapis.com"},
+ {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86"
+ "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x12\x6c\x86\x0e\xf6\x17\xb1"
+ "\x12\x6c\x37\x25\xd2\xad\x87\x3d\x0e\x31\xec\x21\xad\xb1\xcd\xbe\x14"
+ "\x47\xb6\x71\x56\x85\x7a\x9a\xb7\x3d\x89\x90\x7b\xc6\x32\x3a\xf8\xda"
+ "\xce\x8b\x01\xfe\x3f\xfc\x71\x91\x19\x8e\x14\x6e\x89\x7a\x5d\xb4\xab"
+ "\x7e\xe1\x4e\x1e\x7c\xac",
+ 91, "Google 'Skydiver' log", "https://ct.googleapis.com/skydiver/",
+ "skydiver.ct.googleapis.com"},
+ {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86"
+ "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x4e\xd2\xbc\xbf\xb3\x08\x0a"
+ "\xf7\xb9\xea\xa4\xc7\x1c\x38\x61\x04\xeb\x95\xe0\x89\x54\x68\x44\xb1"
+ "\x66\xbc\x82\x7e\x4f\x50\x6c\x6f\x5c\xa3\xf0\xaa\x3e\xf4\xec\x80\xf0"
+ "\xdb\x0a\x9a\x7a\xa0\x5b\x72\x00\x7c\x25\x0e\x19\xef\xaf\xb2\x62\x8d"
+ "\x74\x43\xf4\x26\xf6\x14",
+ 91, "Google 'Icarus' log", "https://ct.googleapis.com/icarus/",
+ "icarus.ct.googleapis.com"}};
// Information related to previously-qualified, but now disqualified, CT
// logs.
@@ -123,7 +170,8 @@ const DisqualifiedCTLogInfo kDisqualifiedCTLogList[] = {
"\x11\xc4\x11\x17\xab\x5c\xcf\x0f\x74\xac\xb5\x97\x90\x93\x00\x5b\xb8"
"\xeb\xf7\x27\x3d\xd9\xb2\x0a\x81\x5f\x2f\x0d\x75\x38\x94\x37\x99\x1e"
"\xf6\x07\x76\xe0\xee\xbe",
- 91, "Izenpe log", "https://ct.izenpe.com/"},
+ 91, "Izenpe log", "https://ct.izenpe.com/",
+ "izenpe1.ct.googleapis.com"},
// 2016-05-30 00:00:00 UTC
base::TimeDelta::FromSeconds(1464566400),
},
@@ -136,7 +184,8 @@ const DisqualifiedCTLogInfo kDisqualifiedCTLogList[] = {
"\x8f\x01\x42\x0a\x7c\x98\x26\x27\xc1\xb5\xdd\x92\x93\xb0\xae\xf8\x9b"
"\x3d\x0c\xd8\x4c\x4e\x1d\xf9\x15\xfb\x47\x68\x7b\xba\x66\xb7\x25\x9c"
"\xd0\x4a\xc2\x66\xdb\x48",
- 91, "Certly.IO log", "https://log.certly.io/"},
+ 91, "Certly.IO log", "https://log.certly.io/",
+ "certly.ct.googleapis.com"},
// 2016-04-15 00:00:00 UTC
base::TimeDelta::FromSeconds(1460678400),
},
@@ -144,9 +193,13 @@ const DisqualifiedCTLogInfo kDisqualifiedCTLogList[] = {
// The list is sorted.
const char kGoogleLogIDs[][33] = {
+ "\x29\x3c\x51\x96\x54\xc8\x39\x65\xba\xaa\x50\xfc\x58\x07\xd4\xb7\x6f"
+ "\xbf\x58\x7a\x29\x72\xdc\xa4\xc3\x0c\xf4\xe5\x45\x47\xf4\x78",
"\x68\xf6\x98\xf8\x1f\x64\x82\xbe\x3a\x8c\xee\xb9\x28\x1d\x4c\xfc\x71"
"\x51\x5d\x67\x93\xd4\x44\xd1\x0a\x67\xac\xbb\x4f\x4f\xfb\xc4",
"\xa4\xb9\x09\x90\xb4\x18\x58\x14\x87\xbb\x13\xa2\xcc\x67\x70\x0a\x3c"
"\x35\x98\x04\xf9\x1b\xdf\xb8\xe3\x77\xcd\x0e\xc8\x0d\xdc\x10",
+ "\xbb\xd9\xdf\xbc\x1f\x8a\x71\xb5\x93\x94\x23\x97\xaa\x92\x7b\x47\x38"
+ "\x57\x95\x0a\xab\x52\xe8\x1a\x90\x96\x64\x36\x8e\x1e\xd1\x85",
"\xee\x4b\xbd\xb7\x75\xce\x60\xba\xe1\x42\x69\x1f\xab\xe1\x9e\x66\xa3"
"\x0f\x7e\x5f\xb0\x72\xd8\x83\x00\xc4\x7b\x89\x7a\xa8\xfd\xcb"};
diff --git a/chromium/net/cert/ct_log_verifier.cc b/chromium/net/cert/ct_log_verifier.cc
index 45adabe4862..04eb2f15a12 100644
--- a/chromium/net/cert/ct_log_verifier.cc
+++ b/chromium/net/cert/ct_log_verifier.cc
@@ -58,24 +58,29 @@ const EVP_MD* GetEvpAlg(ct::DigitallySigned::HashAlgorithm alg) {
scoped_refptr<const CTLogVerifier> CTLogVerifier::Create(
const base::StringPiece& public_key,
const base::StringPiece& description,
- const base::StringPiece& url) {
- GURL log_url(url.as_string());
+ const base::StringPiece& url,
+ const base::StringPiece& dns_domain) {
+ GURL log_url(url);
if (!log_url.is_valid())
return nullptr;
- scoped_refptr<CTLogVerifier> result(new CTLogVerifier(description, log_url));
+ scoped_refptr<CTLogVerifier> result(
+ new CTLogVerifier(description, log_url, dns_domain));
if (!result->Init(public_key))
return nullptr;
return result;
}
CTLogVerifier::CTLogVerifier(const base::StringPiece& description,
- const GURL& url)
+ const GURL& url,
+ const base::StringPiece& dns_domain)
: description_(description.as_string()),
url_(url),
+ dns_domain_(dns_domain.as_string()),
hash_algorithm_(ct::DigitallySigned::HASH_ALGO_NONE),
signature_algorithm_(ct::DigitallySigned::SIG_ALGO_ANONYMOUS),
public_key_(NULL) {
DCHECK(url_.is_valid());
+ DCHECK(!dns_domain_.empty());
}
bool CTLogVerifier::Verify(const ct::LogEntry& entry,
diff --git a/chromium/net/cert/ct_log_verifier.h b/chromium/net/cert/ct_log_verifier.h
index fa5ba248b7d..e9ba307c3e9 100644
--- a/chromium/net/cert/ct_log_verifier.h
+++ b/chromium/net/cert/ct_log_verifier.h
@@ -40,10 +40,13 @@ class NET_EXPORT CTLogVerifier
// using |public_key|, which is a DER-encoded SubjectPublicKeyInfo.
// If |public_key| refers to an unsupported public key, returns NULL.
// |description| is a textual description of the log.
+ // |url| is the URL of the log's HTTPS API endpoint.
+ // |dns_domain| is the DNS name of the log's DNS API endpoint, if one exists.
static scoped_refptr<const CTLogVerifier> Create(
const base::StringPiece& public_key,
const base::StringPiece& description,
- const base::StringPiece& url);
+ const base::StringPiece& url,
+ const base::StringPiece& dns_domain);
// Returns the log's key ID (RFC6962, Section 3.2)
const std::string& key_id() const { return key_id_; }
@@ -52,6 +55,11 @@ class NET_EXPORT CTLogVerifier
// Returns the log's URL
const GURL& url() const { return url_; }
+ // Returns the log's DNS domain for CT over DNS queries, as described in
+ // https://github.com/google/certificate-transparency-rfcs/blob/master/dns/draft-ct-over-dns.md.
+ // This will be empty if the log has no DNS API endpoint.
+ const std::string& dns_domain() const { return dns_domain_; }
+
// Verifies that |sct| is valid for |entry| and was signed by this log.
bool Verify(const ct::LogEntry& entry,
const ct::SignedCertificateTimestamp& sct) const;
@@ -72,7 +80,9 @@ class NET_EXPORT CTLogVerifier
FRIEND_TEST_ALL_PREFIXES(CTLogVerifierTest, VerifySignature);
friend class base::RefCountedThreadSafe<CTLogVerifier>;
- CTLogVerifier(const base::StringPiece& description, const GURL& url);
+ CTLogVerifier(const base::StringPiece& description,
+ const GURL& url,
+ const base::StringPiece& dns_domain);
~CTLogVerifier();
// Performs crypto-library specific initialization.
@@ -91,6 +101,7 @@ class NET_EXPORT CTLogVerifier
std::string key_id_;
std::string description_;
GURL url_;
+ std::string dns_domain_;
ct::DigitallySigned::HashAlgorithm hash_algorithm_;
ct::DigitallySigned::SignatureAlgorithm signature_algorithm_;
diff --git a/chromium/net/cert/ct_log_verifier_unittest.cc b/chromium/net/cert/ct_log_verifier_unittest.cc
index 9221f066327..91ddbc737e3 100644
--- a/chromium/net/cert/ct_log_verifier_unittest.cc
+++ b/chromium/net/cert/ct_log_verifier_unittest.cc
@@ -8,6 +8,7 @@
#include <memory>
#include <string>
+#include <vector>
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
@@ -36,15 +37,6 @@ uint64_t CalculateNearestPowerOfTwo(uint64_t n) {
return ret;
}
-// The following structures, TestVector and ProofTestVector are used for
-// definining test proofs later on.
-
-// A single hash node.
-struct TestVector {
- const char* const str;
- size_t length_bytes;
-};
-
// A single consistency proof. Contains the old and new tree sizes
// (snapshot1 and snapshot2), the length of the proof (proof_length) and
// at most 3 proof nodes (all test proofs will be for a tree of size 8).
@@ -52,72 +44,70 @@ struct ProofTestVector {
uint64_t snapshot1;
uint64_t snapshot2;
size_t proof_length;
- TestVector proof[3];
+ const char* const proof[3];
};
// All test data replicated from
// https://github.com/google/certificate-transparency/blob/c41b090ecc14ddd6b3531dc7e5ce36b21e253fdd/cpp/merkletree/merkle_tree_test.cc
// A hash of the empty string.
-const TestVector kSHA256EmptyTreeHash = {
- "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 32};
-
-// Node hashes for a sample tree of size 8 (each element in this array is
-// a node hash, not leaf data; order represents order of the nodes in the tree).
-const TestVector kSHA256Roots[8] = {
- {"6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d", 32},
- {"fac54203e7cc696cf0dfcb42c92a1d9dbaf70ad9e621f4bd8d98662f00e3c125", 32},
- {"aeb6bcfe274b70a14fb067a5e5578264db0fa9b51af5e0ba159158f329e06e77", 32},
- {"d37ee418976dd95753c1c73862b9398fa2a2cf9b4ff0fdfe8b30cd95209614b7", 32},
- {"4e3bbb1f7b478dcfe71fb631631519a3bca12c9aefca1612bfce4c13a86264d4", 32},
- {"76e67dadbcdf1e10e1b74ddc608abd2f98dfb16fbce75277b5232a127f2087ef", 32},
- {"ddb89be403809e325750d3d263cd78929c2942b7942a34b77e122c9594a74c8c", 32},
- {"5dc9da79a70659a9ad559cb701ded9a2ab9d823aad2f4960cfe370eff4604328", 32}};
+const uint8_t kSHA256EmptyTreeHash[32] = {
+ 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4,
+ 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
+ 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55};
+
+// Root hashes from building the sample tree of size 8 leaf-by-leaf.
+// The first entry is the root at size 0, the last is the root at size 8.
+const char* const kSHA256Roots[8] = {
+ "6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d",
+ "fac54203e7cc696cf0dfcb42c92a1d9dbaf70ad9e621f4bd8d98662f00e3c125",
+ "aeb6bcfe274b70a14fb067a5e5578264db0fa9b51af5e0ba159158f329e06e77",
+ "d37ee418976dd95753c1c73862b9398fa2a2cf9b4ff0fdfe8b30cd95209614b7",
+ "4e3bbb1f7b478dcfe71fb631631519a3bca12c9aefca1612bfce4c13a86264d4",
+ "76e67dadbcdf1e10e1b74ddc608abd2f98dfb16fbce75277b5232a127f2087ef",
+ "ddb89be403809e325750d3d263cd78929c2942b7942a34b77e122c9594a74c8c",
+ "5dc9da79a70659a9ad559cb701ded9a2ab9d823aad2f4960cfe370eff4604328"};
// A collection of consistency proofs between various sub-trees of the tree
// defined by |kSHA256Roots|.
const ProofTestVector kSHA256Proofs[4] = {
// Empty consistency proof between trees of the same size (1).
- {1, 1, 0, {{"", 0}, {"", 0}, {"", 0}}},
+ {1, 1, 0, {"", "", ""}},
// Consistency proof between tree of size 1 and tree of size 8, with 3
// nodes in the proof.
{1,
8,
3,
- {{"96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7", 32},
- {"5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e", 32},
- {"6b47aaf29ee3c2af9af889bc1fb9254dabd31177f16232dd6aab035ca39bf6e4",
- 32}}},
+ {"96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7",
+ "5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e",
+ "6b47aaf29ee3c2af9af889bc1fb9254dabd31177f16232dd6aab035ca39bf6e4"}},
// Consistency proof between tree of size 6 and tree of size 8, with 3
// nodes in the proof.
{6,
8,
3,
- {{"0ebc5d3437fbe2db158b9f126a1d118e308181031d0a949f8dededebc558ef6a", 32},
- {"ca854ea128ed050b41b35ffc1b87b8eb2bde461e9e3b5596ece6b9d5975a0ae0", 32},
- {"d37ee418976dd95753c1c73862b9398fa2a2cf9b4ff0fdfe8b30cd95209614b7",
- 32}}},
+ {"0ebc5d3437fbe2db158b9f126a1d118e308181031d0a949f8dededebc558ef6a",
+ "ca854ea128ed050b41b35ffc1b87b8eb2bde461e9e3b5596ece6b9d5975a0ae0",
+ "d37ee418976dd95753c1c73862b9398fa2a2cf9b4ff0fdfe8b30cd95209614b7"}},
// Consistency proof between tree of size 2 and tree of size 5, with 2
// nodes in the proof.
{2,
5,
2,
- {{"5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e", 32},
- {"bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b", 32},
- {"", 0}}}};
+ {"5f083f0a1a33ca076a95279832580db3e0ef4584bdff1f54c8a360f50de3031e",
+ "bc1a0643b12e4d2d7c77918f44e0f4f79a838b6cf9ec5b5c283e1f4d88599e6b", ""}}};
// Decodes a hexadecimal string into the binary data it represents.
-std::string HexToBytes(const char* hex_data, size_t hex_data_length) {
+std::string HexToBytes(const std::string& hex_data) {
std::vector<uint8_t> output;
std::string result;
- std::string hex_data_input(hex_data, hex_data_length);
if (base::HexStringToBytes(hex_data, &output))
- result.assign(reinterpret_cast<const char*>(&output[0]), output.size());
+ result.assign(output.begin(), output.end());
return result;
}
std::string GetEmptyTreeHash() {
- return HexToBytes(kSHA256EmptyTreeHash.str,
- kSHA256EmptyTreeHash.length_bytes);
+ return std::string(std::begin(kSHA256EmptyTreeHash),
+ std::end(kSHA256EmptyTreeHash));
}
// Creates a ct::MerkleConsistencyProof and returns the result of
@@ -140,10 +130,11 @@ class CTLogVerifierTest : public ::testing::Test {
void SetUp() override {
log_ = CTLogVerifier::Create(ct::GetTestPublicKey(), "testlog",
- "https://ct.example.com");
+ "https://ct.example.com", "ct.example.com");
ASSERT_TRUE(log_);
- ASSERT_EQ(log_->key_id(), ct::GetTestPublicKeyId());
+ ASSERT_EQ(ct::GetTestPublicKeyId(), log_->key_id());
+ ASSERT_EQ("ct.example.com", log_->dns_domain());
}
// Given a consistency proof between two snapshots of the tree, asserts that
@@ -317,8 +308,8 @@ TEST_F(CTLogVerifierTest, ExcessDataInPublicKey) {
std::string key = ct::GetTestPublicKey();
key += "extra";
- scoped_refptr<const CTLogVerifier> log =
- CTLogVerifier::Create(key, "testlog", "https://ct.example.com");
+ scoped_refptr<const CTLogVerifier> log = CTLogVerifier::Create(
+ key, "testlog", "https://ct.example.com", "ct.example.com");
EXPECT_FALSE(log);
}
@@ -378,18 +369,18 @@ TEST_F(CTLogVerifierTest, VerifiesValidConsistencyProofs) {
// Known good proofs.
for (size_t i = 0; i < arraysize(kSHA256Proofs); ++i) {
+ SCOPED_TRACE(i);
proof.clear();
for (size_t j = 0; j < kSHA256Proofs[i].proof_length; ++j) {
- const TestVector& v = kSHA256Proofs[i].proof[j];
- proof.push_back(HexToBytes(v.str, v.length_bytes));
+ const char* const v = kSHA256Proofs[i].proof[j];
+ proof.push_back(HexToBytes(v));
}
const uint64_t snapshot1 = kSHA256Proofs[i].snapshot1;
const uint64_t snapshot2 = kSHA256Proofs[i].snapshot2;
- const TestVector& old_root = kSHA256Roots[snapshot1 - 1];
- const TestVector& new_root = kSHA256Roots[snapshot2 - 1];
- VerifierConsistencyCheck(
- snapshot1, snapshot2, HexToBytes(old_root.str, old_root.length_bytes),
- HexToBytes(new_root.str, new_root.length_bytes), proof);
+ const char* const old_root = kSHA256Roots[snapshot1 - 1];
+ const char* const new_root = kSHA256Roots[snapshot2 - 1];
+ VerifierConsistencyCheck(snapshot1, snapshot2, HexToBytes(old_root),
+ HexToBytes(new_root), proof);
}
}
@@ -401,11 +392,6 @@ const char kLeafPrefix[] = {'\x00'};
// code.
class TreeHasher {
public:
- static std::string HashEmpty() {
- return HexToBytes(kSHA256EmptyTreeHash.str,
- kSHA256EmptyTreeHash.length_bytes);
- }
-
static std::string HashLeaf(const std::string& leaf) {
SHA256HashValue sha256;
memset(sha256.data, 0, sizeof(sha256.data));
@@ -426,7 +412,7 @@ class TreeHasher {
// specified in |inputs|.
std::string ReferenceMerkleTreeHash(std::string* inputs, uint64_t input_size) {
if (!input_size)
- return TreeHasher::HashEmpty();
+ return GetEmptyTreeHash();
if (input_size == 1)
return TreeHasher::HashLeaf(inputs[0]);
@@ -484,35 +470,41 @@ std::vector<std::string> ReferenceSnapshotConsistency(std::string* inputs,
return proof;
}
-// Times out on Win7 test bot. http://crbug.com/598406
-#if defined(OS_WIN)
-#define MAYBE_VerifiesValidConsistencyProofsFromReferenceGenerator \
- DISABLED_VerifiesValidConsistencyProofsFromReferenceGenerator
-#else
-#define MAYBE_VerifiesValidConsistencyProofsFromReferenceGenerator \
- VerifiesValidConsistencyProofsFromReferenceGenerator
-#endif
-TEST_F(CTLogVerifierTest,
- MAYBE_VerifiesValidConsistencyProofsFromReferenceGenerator) {
- std::vector<std::string> data;
- for (int i = 0; i < 256; ++i)
- data.push_back(std::string(1, i));
+class CTLogVerifierTestUsingReferenceGenerator
+ : public CTLogVerifierTest,
+ public ::testing::WithParamInterface<uint64_t> {};
- std::vector<std::string> proof;
- std::string root1, root2;
- // More tests with reference proof generator.
- for (size_t tree_size = 1; tree_size <= data.size() / 2; ++tree_size) {
- root2 = ReferenceMerkleTreeHash(data.data(), tree_size);
- // Repeat for each snapshot in range.
- for (size_t snapshot = 1; snapshot <= tree_size; ++snapshot) {
- proof =
- ReferenceSnapshotConsistency(data.data(), tree_size, snapshot, true);
- root1 = ReferenceMerkleTreeHash(data.data(), snapshot);
- VerifierConsistencyCheck(snapshot, tree_size, root1, root2, proof);
- }
+const uint64_t kReferenceTreeSize = 256;
+
+// Tests that every possible valid consistency proof for a tree of a given size
+// verifies correctly. Also checks that invalid variations of each proof fail to
+// verify (see VerifierConsistencyCheck).
+TEST_P(CTLogVerifierTestUsingReferenceGenerator,
+ VerifiesValidConsistencyProof) {
+ std::vector<std::string> data;
+ for (uint64_t i = 0; i < kReferenceTreeSize; ++i)
+ data.push_back(std::string(1, static_cast<char>(i)));
+
+ const uint64_t tree_size = GetParam();
+ const std::string tree_root = ReferenceMerkleTreeHash(data.data(), tree_size);
+
+ for (uint64_t snapshot = 1; snapshot <= tree_size; ++snapshot) {
+ SCOPED_TRACE(snapshot);
+ const std::string snapshot_root =
+ ReferenceMerkleTreeHash(data.data(), snapshot);
+ const std::vector<std::string> proof =
+ ReferenceSnapshotConsistency(data.data(), tree_size, snapshot, true);
+ VerifierConsistencyCheck(snapshot, tree_size, snapshot_root, tree_root,
+ proof);
}
}
+// Test verification of consistency proofs between all tree sizes from 1 to 128.
+INSTANTIATE_TEST_CASE_P(RangeOfTreeSizesAndSnapshots,
+ CTLogVerifierTestUsingReferenceGenerator,
+ testing::Range(UINT64_C(1),
+ (kReferenceTreeSize / 2) + 1));
+
} // namespace
} // namespace net
diff --git a/chromium/net/cert/ct_objects_extractor_unittest.cc b/chromium/net/cert/ct_objects_extractor_unittest.cc
index e8718bd8b85..7efec352535 100644
--- a/chromium/net/cert/ct_objects_extractor_unittest.cc
+++ b/chromium/net/cert/ct_objects_extractor_unittest.cc
@@ -32,7 +32,7 @@ class CTObjectsExtractorTest : public ::testing::Test {
der_test_cert.length());
log_ = CTLogVerifier::Create(ct::GetTestPublicKey(), "testlog",
- "https://ct.example.com");
+ "https://ct.example.com", "dns.example.com");
ASSERT_TRUE(log_);
}
diff --git a/chromium/net/cert/ct_policy_enforcer.cc b/chromium/net/cert/ct_policy_enforcer.cc
index a4e1e818c41..42f631eaa53 100644
--- a/chromium/net/cert/ct_policy_enforcer.cc
+++ b/chromium/net/cert/ct_policy_enforcer.cc
@@ -27,7 +27,10 @@
#include "net/cert/signed_certificate_timestamp.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_certificate_net_log_param.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_parameters_callback.h"
+#include "net/log/net_log_with_source.h"
namespace net {
@@ -380,7 +383,7 @@ ct::EVPolicyCompliance CertPolicyComplianceToEVPolicyCompliance(
void CheckCTEVPolicyCompliance(X509Certificate* cert,
const ct::EVCertsWhitelist* ev_whitelist,
const ct::SCTList& verified_scts,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
EVComplianceDetails* result) {
result->status = CertPolicyComplianceToEVPolicyCompliance(
CheckCertPolicyCompliance(*cert, verified_scts));
@@ -398,7 +401,7 @@ void CheckCTEVPolicyCompliance(X509Certificate* cert,
ct::CertPolicyCompliance CTPolicyEnforcer::DoesConformToCertPolicy(
X509Certificate* cert,
const ct::SCTList& verified_scts,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
// If the build is not timely, no certificate is considered compliant
// with CT policy. The reasoning is that, for example, a log might
// have been pulled and is no longer considered valid; thus, a client
@@ -412,11 +415,12 @@ ct::CertPolicyCompliance CTPolicyEnforcer::DoesConformToCertPolicy(
compliance = CheckCertPolicyCompliance(*cert, verified_scts);
}
- NetLog::ParametersCallback net_log_callback =
+ NetLogParametersCallback net_log_callback =
base::Bind(&NetLogCertComplianceCheckResultCallback,
base::Unretained(cert), build_timely, compliance);
- net_log.AddEvent(NetLog::TYPE_CERT_CT_COMPLIANCE_CHECKED, net_log_callback);
+ net_log.AddEvent(NetLogEventType::CERT_CT_COMPLIANCE_CHECKED,
+ net_log_callback);
return compliance;
}
@@ -425,7 +429,7 @@ ct::EVPolicyCompliance CTPolicyEnforcer::DoesConformToCTEVPolicy(
X509Certificate* cert,
const ct::EVCertsWhitelist* ev_whitelist,
const ct::SCTList& verified_scts,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
EVComplianceDetails details;
// If the build is not timely, no certificate is considered compliant
// with EV policy. The reasoning is that, for example, a log might
@@ -440,11 +444,11 @@ ct::EVPolicyCompliance CTPolicyEnforcer::DoesConformToCTEVPolicy(
&details);
}
- NetLog::ParametersCallback net_log_callback =
+ NetLogParametersCallback net_log_callback =
base::Bind(&NetLogEVComplianceCheckResultCallback, base::Unretained(cert),
base::Unretained(&details));
- net_log.AddEvent(NetLog::TYPE_EV_CERT_CT_COMPLIANCE_CHECKED,
+ net_log.AddEvent(NetLogEventType::EV_CERT_CT_COMPLIANCE_CHECKED,
net_log_callback);
if (!details.build_timely)
diff --git a/chromium/net/cert/ct_policy_enforcer.h b/chromium/net/cert/ct_policy_enforcer.h
index c49e09101b1..c732cee6ff4 100644
--- a/chromium/net/cert/ct_policy_enforcer.h
+++ b/chromium/net/cert/ct_policy_enforcer.h
@@ -10,10 +10,11 @@
#include "net/base/net_export.h"
#include "net/cert/signed_certificate_timestamp.h"
-#include "net/log/net_log.h"
namespace net {
+class NetLogWithSource;
+
namespace ct {
class EVCertsWhitelist;
@@ -85,7 +86,7 @@ class NET_EXPORT CTPolicyEnforcer {
virtual ct::CertPolicyCompliance DoesConformToCertPolicy(
X509Certificate* cert,
const SCTList& verified_scts,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Returns the CT/EV policy compliance status for a given certificate
// and collection of SCTs.
@@ -99,7 +100,7 @@ class NET_EXPORT CTPolicyEnforcer {
X509Certificate* cert,
const ct::EVCertsWhitelist* ev_whitelist,
const SCTList& verified_scts,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
};
} // namespace net
diff --git a/chromium/net/cert/ct_policy_enforcer_unittest.cc b/chromium/net/cert/ct_policy_enforcer_unittest.cc
index e86ff256b85..59544094c29 100644
--- a/chromium/net/cert/ct_policy_enforcer_unittest.cc
+++ b/chromium/net/cert/ct_policy_enforcer_unittest.cc
@@ -16,6 +16,7 @@
#include "net/cert/ct_verify_result.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/ct_test_util.h"
#include "net/test/test_data_directory.h"
@@ -147,10 +148,10 @@ TEST_F(CTPolicyEnforcerTest,
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_NOT_DIVERSE_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_DIVERSE_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
}
TEST_F(CTPolicyEnforcerTest,
@@ -164,10 +165,10 @@ TEST_F(CTPolicyEnforcerTest,
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_NOT_DIVERSE_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_DIVERSE_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
}
TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyIfSCTBeforeEnforcementDate) {
@@ -179,10 +180,10 @@ TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyIfSCTBeforeEnforcementDate) {
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
}
TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyWithNonEmbeddedSCTs) {
@@ -192,10 +193,10 @@ TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyWithNonEmbeddedSCTs) {
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
}
TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyWithEmbeddedSCTs) {
@@ -206,10 +207,10 @@ TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyWithEmbeddedSCTs) {
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
}
TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyWithPooledNonEmbeddedSCTs) {
@@ -232,10 +233,10 @@ TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyWithPooledNonEmbeddedSCTs) {
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
}
TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyWithPooledEmbeddedSCTs) {
@@ -257,10 +258,10 @@ TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyWithPooledEmbeddedSCTs) {
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
}
TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTEVPolicyNotEnoughSCTs) {
@@ -273,18 +274,18 @@ TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTEVPolicyNotEnoughSCTs) {
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
- EXPECT_EQ(
- ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(
- chain_.get(), non_including_whitelist.get(), scts, BoundNetLog()));
+ NetLogWithSource()));
+ EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS,
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), non_including_whitelist.get(), scts,
+ NetLogWithSource()));
// ... but should be OK if whitelisted.
scoped_refptr<ct::EVCertsWhitelist> whitelist(
new DummyEVCertsWhitelist(true, true));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST,
policy_enforcer_->DoesConformToCTEVPolicy(
- chain_.get(), whitelist.get(), scts, BoundNetLog()));
+ chain_.get(), whitelist.get(), scts, NetLogWithSource()));
}
TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTEVPolicyNotEnoughFreshSCTs) {
@@ -301,10 +302,10 @@ TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTEVPolicyNotEnoughFreshSCTs) {
false, &scts);
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_NOT_DIVERSE_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_DIVERSE_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
// SCT from after disqualification.
scts.clear();
@@ -314,10 +315,10 @@ TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTEVPolicyNotEnoughFreshSCTs) {
true, &scts);
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_NOT_DIVERSE_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_DIVERSE_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
// Embedded SCT from before disqualification.
scts.clear();
@@ -327,10 +328,10 @@ TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTEVPolicyNotEnoughFreshSCTs) {
&scts);
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_NOT_DIVERSE_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_DIVERSE_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
// Embedded SCT from after disqualification.
scts.clear();
@@ -340,10 +341,10 @@ TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTEVPolicyNotEnoughFreshSCTs) {
&scts);
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_NOT_DIVERSE_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_DIVERSE_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
}
TEST_F(CTPolicyEnforcerTest,
@@ -357,10 +358,10 @@ TEST_F(CTPolicyEnforcerTest,
// |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
}
TEST_F(CTPolicyEnforcerTest,
@@ -374,10 +375,10 @@ TEST_F(CTPolicyEnforcerTest,
// |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
}
TEST_F(CTPolicyEnforcerTest,
@@ -394,10 +395,10 @@ TEST_F(CTPolicyEnforcerTest,
// |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
}
TEST_F(CTPolicyEnforcerTest,
@@ -429,10 +430,10 @@ TEST_F(CTPolicyEnforcerTest,
// However, there are only 4 SCTs are from distinct logs.
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
}
TEST_F(CTPolicyEnforcerTest,
@@ -496,12 +497,12 @@ TEST_F(CTPolicyEnforcerTest,
std::vector<std::string>(), false, &scts);
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS,
policy_enforcer_->DoesConformToCertPolicy(cert.get(), scts,
- BoundNetLog()))
+ NetLogWithSource()))
<< " for: " << (end - start).InDays() << " and " << required_scts
<< " scts=" << scts.size() << " i=" << i;
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(cert.get(), nullptr,
- scts, BoundNetLog()))
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ cert.get(), nullptr, scts, NetLogWithSource()))
<< " for: " << (end - start).InDays() << " and " << required_scts
<< " scts=" << scts.size() << " i=" << i;
}
@@ -511,12 +512,12 @@ TEST_F(CTPolicyEnforcerTest,
&scts);
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS,
policy_enforcer_->DoesConformToCertPolicy(cert.get(), scts,
- BoundNetLog()))
+ NetLogWithSource()))
<< " for: " << (end - start).InDays() << " and " << required_scts
<< " scts=" << scts.size();
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(cert.get(), nullptr,
- scts, BoundNetLog()))
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ cert.get(), nullptr, scts, NetLogWithSource()))
<< " for: " << (end - start).InDays() << " and " << required_scts
<< " scts=" << scts.size();
}
@@ -531,10 +532,10 @@ TEST_F(CTPolicyEnforcerTest, ConformsToPolicyByEVWhitelistPresence) {
&scts);
EXPECT_EQ(ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS,
policy_enforcer_->DoesConformToCertPolicy(chain_.get(), scts,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST,
policy_enforcer_->DoesConformToCTEVPolicy(
- chain_.get(), whitelist.get(), scts, BoundNetLog()));
+ chain_.get(), whitelist.get(), scts, NetLogWithSource()));
}
TEST_F(CTPolicyEnforcerTest, IgnoresInvalidEVWhitelist) {
@@ -546,7 +547,7 @@ TEST_F(CTPolicyEnforcerTest, IgnoresInvalidEVWhitelist) {
&scts);
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS,
policy_enforcer_->DoesConformToCTEVPolicy(
- chain_.get(), whitelist.get(), scts, BoundNetLog()));
+ chain_.get(), whitelist.get(), scts, NetLogWithSource()));
}
TEST_F(CTPolicyEnforcerTest, IgnoresNullEVWhitelist) {
@@ -554,8 +555,8 @@ TEST_F(CTPolicyEnforcerTest, IgnoresNullEVWhitelist) {
FillListWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 2,
&scts);
EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS,
- policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
- scts, BoundNetLog()));
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), nullptr, scts, NetLogWithSource()));
}
} // namespace
diff --git a/chromium/net/cert/ct_sct_to_string.cc b/chromium/net/cert/ct_sct_to_string.cc
index f3912a82862..4d7449252b4 100644
--- a/chromium/net/cert/ct_sct_to_string.cc
+++ b/chromium/net/cert/ct_sct_to_string.cc
@@ -62,14 +62,14 @@ const std::string StatusToString(SCTVerifyStatus status) {
switch (status) {
case SCT_STATUS_LOG_UNKNOWN:
return "From unknown log";
- case SCT_STATUS_INVALID:
- return "Invalid";
+ case SCT_STATUS_INVALID_SIGNATURE:
+ return "Invalid signature";
case SCT_STATUS_OK:
return "Verified";
case SCT_STATUS_NONE:
return "None";
- case SCT_STATUS_MAX:
- NOTREACHED();
+ case SCT_STATUS_INVALID_TIMESTAMP:
+ return "Invalid timestamp";
}
return "Unknown";
}
diff --git a/chromium/net/cert/ct_sct_to_string.h b/chromium/net/cert/ct_sct_to_string.h
index 165dd89b89e..5dc77962190 100644
--- a/chromium/net/cert/ct_sct_to_string.h
+++ b/chromium/net/cert/ct_sct_to_string.h
@@ -7,6 +7,7 @@
#include <string>
+#include "net/base/net_export.h"
#include "net/cert/sct_status_flags.h"
#include "net/cert/signed_certificate_timestamp.h"
diff --git a/chromium/net/cert/ct_serialization_unittest.cc b/chromium/net/cert/ct_serialization_unittest.cc
index 65f99945e65..6056ea3bcf1 100644
--- a/chromium/net/cert/ct_serialization_unittest.cc
+++ b/chromium/net/cert/ct_serialization_unittest.cc
@@ -13,7 +13,6 @@
#include "net/cert/signed_certificate_timestamp.h"
#include "net/cert/signed_tree_head.h"
#include "net/cert/x509_certificate.h"
-#include "net/log/net_log.h"
#include "net/test/cert_test_util.h"
#include "net/test/ct_test_util.h"
#include "net/test/test_data_directory.h"
diff --git a/chromium/net/cert/ct_signed_certificate_timestamp_log_param.cc b/chromium/net/cert/ct_signed_certificate_timestamp_log_param.cc
index f829e56a813..6afd32224e5 100644
--- a/chromium/net/cert/ct_signed_certificate_timestamp_log_param.cc
+++ b/chromium/net/cert/ct_signed_certificate_timestamp_log_param.cc
@@ -6,7 +6,6 @@
#include <algorithm>
#include <memory>
-#include <string>
#include <utility>
#include "base/base64.h"
@@ -16,6 +15,7 @@
#include "net/cert/ct_sct_to_string.h"
#include "net/cert/ct_verify_result.h"
#include "net/cert/signed_certificate_timestamp.h"
+#include "net/log/net_log_capture_mode.h"
namespace net {
@@ -37,10 +37,12 @@ void SetBinaryData(
// is this field's value in the SCT. This dictionary is meant to be used for
// outputting a de-serialized SCT to the NetLog.
std::unique_ptr<base::DictionaryValue> SCTToDictionary(
- const ct::SignedCertificateTimestamp& sct) {
+ const ct::SignedCertificateTimestamp& sct,
+ ct::SCTVerifyStatus status) {
std::unique_ptr<base::DictionaryValue> out(new base::DictionaryValue());
out->SetString("origin", OriginToString(sct.origin));
+ out->SetString("verification_status", StatusToString(status));
out->SetInteger("version", sct.version);
SetBinaryData("log_id", sct.log_id, out.get());
@@ -59,13 +61,14 @@ std::unique_ptr<base::DictionaryValue> SCTToDictionary(
return out;
}
-// Given a list of SCTs, return a ListValue instance where each item in the
-// list is a dictionary created by SCTToDictionary.
+// Given a list of SCTs and their statuses, return a ListValue instance where
+// each item in the list is a dictionary created by SCTToDictionary.
std::unique_ptr<base::ListValue> SCTListToPrintableValues(
- const ct::SCTList& sct_list) {
+ const SignedCertificateTimestampAndStatusList& sct_and_status_list) {
std::unique_ptr<base::ListValue> output_scts(new base::ListValue());
- for (const auto& sct : sct_list)
- output_scts->Append(SCTToDictionary(*(sct.get())));
+ for (const auto& sct_and_status : sct_and_status_list)
+ output_scts->Append(
+ SCTToDictionary(*(sct_and_status.sct.get()), sct_and_status.status));
return output_scts;
}
@@ -77,14 +80,7 @@ std::unique_ptr<base::Value> NetLogSignedCertificateTimestampCallback(
NetLogCaptureMode capture_mode) {
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->Set("verified_scts",
- SCTListToPrintableValues(ct_result->verified_scts));
-
- dict->Set("invalid_scts",
- SCTListToPrintableValues(ct_result->invalid_scts));
-
- dict->Set("unknown_logs_scts",
- SCTListToPrintableValues(ct_result->unknown_logs_scts));
+ dict->Set("scts", SCTListToPrintableValues(ct_result->scts));
return std::move(dict);
}
diff --git a/chromium/net/cert/ct_signed_certificate_timestamp_log_param.h b/chromium/net/cert/ct_signed_certificate_timestamp_log_param.h
index 7d2466906cf..1c1a7d8ad2e 100644
--- a/chromium/net/cert/ct_signed_certificate_timestamp_log_param.h
+++ b/chromium/net/cert/ct_signed_certificate_timestamp_log_param.h
@@ -6,11 +6,16 @@
#define NET_CERT_CT_SIGNED_CERTIFICATE_TIMESTAMP_LOG_PARAM_H_
#include <memory>
+#include <string>
-#include "net/log/net_log.h"
+namespace base {
+class Value;
+}
namespace net {
+class NetLogCaptureMode;
+
namespace ct {
struct CTVerifyResult;
}
diff --git a/chromium/net/cert/ct_verifier.h b/chromium/net/cert/ct_verifier.h
index cdc81c91cb4..38ce2efa471 100644
--- a/chromium/net/cert/ct_verifier.h
+++ b/chromium/net/cert/ct_verifier.h
@@ -16,8 +16,8 @@ struct CTVerifyResult;
struct SignedCertificateTimestamp;
} // namespace ct
-class BoundNetLog;
class CTLogVerifier;
+class NetLogWithSource;
class X509Certificate;
// Interface for verifying Signed Certificate Timestamps over a certificate.
@@ -55,7 +55,7 @@ class NET_EXPORT CTVerifier {
const std::string& stapled_ocsp_response,
const std::string& sct_list_from_tls_extension,
ct::CTVerifyResult* result,
- const BoundNetLog& net_log) = 0;
+ const NetLogWithSource& net_log) = 0;
// Registers |observer| to receive notifications of validated SCTs. Does not
// take ownership of the observer as the observer may be performing
diff --git a/chromium/net/cert/ct_verify_result.cc b/chromium/net/cert/ct_verify_result.cc
index 227bc120f94..5587b67ed78 100644
--- a/chromium/net/cert/ct_verify_result.cc
+++ b/chromium/net/cert/ct_verify_result.cc
@@ -20,6 +20,17 @@ CTVerifyResult::CTVerifyResult(const CTVerifyResult& other) = default;
CTVerifyResult::~CTVerifyResult() {}
+SCTList SCTsMatchingStatus(
+ const SignedCertificateTimestampAndStatusList& sct_and_status_list,
+ SCTVerifyStatus match_status) {
+ SCTList result;
+ for (const auto& sct_and_status : sct_and_status_list)
+ if (sct_and_status.status == match_status)
+ result.push_back(sct_and_status.sct);
+
+ return result;
+}
+
} // namespace ct
} // namespace net
diff --git a/chromium/net/cert/ct_verify_result.h b/chromium/net/cert/ct_verify_result.h
index ca163580d73..33a25dd3f30 100644
--- a/chromium/net/cert/ct_verify_result.h
+++ b/chromium/net/cert/ct_verify_result.h
@@ -7,8 +7,9 @@
#include <vector>
+#include "net/base/net_export.h"
#include "net/cert/ct_policy_enforcer.h"
-#include "net/cert/signed_certificate_timestamp.h"
+#include "net/cert/signed_certificate_timestamp_and_status.h"
namespace net {
@@ -27,12 +28,8 @@ struct NET_EXPORT CTVerifyResult {
CTVerifyResult(const CTVerifyResult& other);
~CTVerifyResult();
- // SCTs from known logs where the signature verified correctly.
- SCTList verified_scts;
- // SCTs from known logs where the signature failed to verify.
- SCTList invalid_scts;
- // SCTs from unknown logs and as such are unverifiable.
- SCTList unknown_logs_scts;
+ // All SCTs and their statuses
+ SignedCertificateTimestampAndStatusList scts;
// True if any CT policies were applied on this connection.
bool ct_policies_applied;
@@ -44,6 +41,12 @@ struct NET_EXPORT CTVerifyResult {
EVPolicyCompliance ev_policy_compliance;
};
+// Returns a list of SCTs from |sct_and_status_list| whose status matches
+// |match_status|.
+SCTList NET_EXPORT SCTsMatchingStatus(
+ const SignedCertificateTimestampAndStatusList& sct_and_status_list,
+ SCTVerifyStatus match_status);
+
} // namespace ct
} // namespace net
diff --git a/chromium/net/cert/ev_root_ca_metadata.cc b/chromium/net/cert/ev_root_ca_metadata.cc
index 26f9773d326..1370f1726c4 100644
--- a/chromium/net/cert/ev_root_ca_metadata.cc
+++ b/chromium/net/cert/ev_root_ca_metadata.cc
@@ -17,15 +17,19 @@
#include "base/logging.h"
#if defined(USE_NSS_CERTS)
#include "crypto/nss_util.h"
+#elif defined(OS_MACOSX)
+#include "net/der/input.h"
+#include "third_party/boringssl/src/include/openssl/asn1.h"
+#include "third_party/boringssl/src/include/openssl/obj.h"
#endif
namespace net {
-#if defined(USE_NSS_CERTS) || defined(OS_WIN)
+#if defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX)
// Raw metadata.
struct EVMetadata {
// kMaxOIDsPerCA is the number of OIDs that we can support per root CA. At
- // least one CA has different EV policies for businuss vs government
+ // least one CA has different EV policies for business vs government
// entities and, in the case of cross-signing, we might need to list another
// CA's policy OID under the cross-signing root.
static const size_t kMaxOIDsPerCA = 2;
@@ -48,8 +52,7 @@ static const EVMetadata ev_root_ca_metadata[] = {
0x30, 0x50, 0xba, 0x9e, 0xa8, 0x7e, 0xfe, 0x9a, 0xce, 0x3c}},
{
// AC Camerfirma uses the last two arcs to track how the private key
- // is
- // managed - the effective verification policy is the same.
+ // is managed - the effective verification policy is the same.
"1.3.6.1.4.1.17326.10.14.2.1.2", "1.3.6.1.4.1.17326.10.14.2.2.2",
},
},
@@ -60,8 +63,7 @@ static const EVMetadata ev_root_ca_metadata[] = {
0xc7, 0x52, 0xa1, 0x2c, 0x5b, 0x29, 0xf6, 0xd6, 0xaa, 0x0c}},
{
// AC Camerfirma uses the last two arcs to track how the private key
- // is
- // managed - the effective verification policy is the same.
+ // is managed - the effective verification policy is the same.
"1.3.6.1.4.1.17326.10.8.12.1.2", "1.3.6.1.4.1.17326.10.8.12.2.2",
},
},
@@ -710,6 +712,61 @@ bool EVRootCAMetadata::RemoveEVCA(const SHA1HashValue& fingerprint) {
return true;
}
+#elif defined(OS_MACOSX)
+
+namespace {
+
+std::string OIDStringToDER(const char* policy) {
+ bssl::UniquePtr<ASN1_OBJECT> obj(
+ OBJ_txt2obj(policy, 1 /* dont_search_names */));
+ if (!obj)
+ return std::string();
+
+ return std::string(reinterpret_cast<const char*>(obj->data), obj->length);
+}
+
+} // namespace
+
+bool EVRootCAMetadata::IsEVPolicyOID(PolicyOID policy_oid) const {
+ return policy_oids_.find(policy_oid.AsString()) != policy_oids_.end();
+}
+
+bool EVRootCAMetadata::HasEVPolicyOID(const SHA1HashValue& fingerprint,
+ PolicyOID policy_oid) const {
+ PolicyOIDMap::const_iterator iter = ev_policy_.find(fingerprint);
+ if (iter == ev_policy_.end())
+ return false;
+ for (const std::string& ev_oid : iter->second) {
+ if (der::Input(&ev_oid) == policy_oid)
+ return true;
+ }
+ return false;
+}
+
+bool EVRootCAMetadata::AddEVCA(const SHA1HashValue& fingerprint,
+ const char* policy) {
+ if (ev_policy_.find(fingerprint) != ev_policy_.end())
+ return false;
+
+ std::string der_policy = OIDStringToDER(policy);
+ if (der_policy.empty())
+ return false;
+
+ ev_policy_[fingerprint].push_back(der_policy);
+ policy_oids_.insert(der_policy);
+ return true;
+}
+
+bool EVRootCAMetadata::RemoveEVCA(const SHA1HashValue& fingerprint) {
+ PolicyOIDMap::iterator it = ev_policy_.find(fingerprint);
+ if (it == ev_policy_.end())
+ return false;
+ std::string oid = it->second[0];
+ ev_policy_.erase(it);
+ policy_oids_.erase(oid);
+ return true;
+}
+
#else
// These are just stub functions for platforms where we don't use this EV
@@ -748,6 +805,25 @@ EVRootCAMetadata::EVRootCAMetadata() {
policy_oids_.insert(policy);
}
}
+#elif defined(OS_MACOSX)
+ for (size_t i = 0; i < arraysize(ev_root_ca_metadata); i++) {
+ const EVMetadata& metadata = ev_root_ca_metadata[i];
+ for (size_t j = 0; j < arraysize(metadata.policy_oids); j++) {
+ if (metadata.policy_oids[j][0] == '\0')
+ break;
+ const char* policy_oid = metadata.policy_oids[j];
+
+ PolicyOID policy;
+ std::string policy_der = OIDStringToDER(policy_oid);
+ if (policy_der.empty()) {
+ LOG(ERROR) << "Failed to register OID: " << policy_oid;
+ continue;
+ }
+
+ ev_policy_[metadata.fingerprint].push_back(policy_der);
+ policy_oids_.insert(policy_der);
+ }
+ }
#endif
}
diff --git a/chromium/net/cert/ev_root_ca_metadata.h b/chromium/net/cert/ev_root_ca_metadata.h
index dfb14bc6aa4..e99cdd1f19e 100644
--- a/chromium/net/cert/ev_root_ca_metadata.h
+++ b/chromium/net/cert/ev_root_ca_metadata.h
@@ -27,6 +27,10 @@ struct DefaultLazyInstanceTraits;
namespace net {
+namespace der {
+class Input;
+} // namespace der
+
// A singleton. This class stores the meta data of the root CAs that issue
// extended-validation (EV) certificates.
class NET_EXPORT_PRIVATE EVRootCAMetadata {
@@ -35,11 +39,14 @@ class NET_EXPORT_PRIVATE EVRootCAMetadata {
typedef SECOidTag PolicyOID;
#elif defined(OS_WIN)
typedef const char* PolicyOID;
+#elif defined(OS_MACOSX)
+ // DER-encoded OID value (no tag or length).
+ typedef der::Input PolicyOID;
#endif
static EVRootCAMetadata* GetInstance();
-#if defined(USE_NSS_CERTS) || defined(OS_WIN)
+#if defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX)
// Returns true if policy_oid is an EV policy OID of some root CA.
bool IsEVPolicyOID(PolicyOID policy_oid) const;
@@ -80,6 +87,13 @@ class NET_EXPORT_PRIVATE EVRootCAMetadata {
// extra_cas_ contains any EV CA metadata that was added at runtime.
ExtraEVCAMap extra_cas_;
+#elif defined(OS_MACOSX)
+ typedef std::
+ map<SHA1HashValue, std::vector<std::string>, SHA1HashValueLessThan>
+ PolicyOIDMap;
+
+ PolicyOIDMap ev_policy_;
+ std::set<std::string> policy_oids_;
#endif
DISALLOW_COPY_AND_ASSIGN(EVRootCAMetadata);
diff --git a/chromium/net/cert/ev_root_ca_metadata_unittest.cc b/chromium/net/cert/ev_root_ca_metadata_unittest.cc
index 9da006483fd..3f3e7172838 100644
--- a/chromium/net/cert/ev_root_ca_metadata_unittest.cc
+++ b/chromium/net/cert/ev_root_ca_metadata_unittest.cc
@@ -5,6 +5,7 @@
#include "net/cert/ev_root_ca_metadata.h"
#include "net/cert/x509_cert_types.h"
+#include "net/der/input.h"
#include "net/test/cert_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,6 +22,17 @@ namespace {
const char kVerisignPolicy[] = "2.16.840.1.113733.1.7.23.6";
const char kThawtePolicy[] = "2.16.840.1.113733.1.7.48.1";
const char kFakePolicy[] = "2.16.840.1.42";
+#elif defined(OS_MACOSX)
+// DER OID values (no tag or length).
+const uint8_t kVerisignPolicy[] = {0x60, 0x86, 0x48, 0x01, 0x86, 0xf8,
+ 0x45, 0x01, 0x07, 0x17, 0x06};
+const uint8_t kThawtePolicy[] = {0x60, 0x86, 0x48, 0x01, 0x86, 0xf8,
+ 0x45, 0x01, 0x07, 0x30, 0x01};
+const uint8_t kFakePolicy[] = {0x60, 0x86, 0x48, 0x01, 0x2a};
+#endif
+
+#if defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX)
+const char kFakePolicyStr[] = "2.16.840.1.42";
const SHA1HashValue kVerisignFingerprint =
{ { 0x74, 0x2c, 0x31, 0x92, 0xe6, 0x07, 0xe4, 0x24, 0xeb, 0x45,
0x49, 0x54, 0x2b, 0xe1, 0xbb, 0xc5, 0x3e, 0x61, 0x74, 0xe2 } };
@@ -38,7 +50,7 @@ class EVOidData {
EVRootCAMetadata::PolicyOID fake_policy;
};
-#endif // defined(USE_NSS_CERTS) || defined(OS_WIN)
+#endif // defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX)
#if defined(USE_NSS_CERTS)
@@ -78,13 +90,12 @@ bool EVOidData::Init() {
fake_policy != SEC_OID_UNKNOWN;
}
-#elif defined(OS_WIN)
+#elif defined(OS_WIN) || defined(OS_MACOSX)
EVOidData::EVOidData()
: verisign_policy(kVerisignPolicy),
thawte_policy(kThawtePolicy),
- fake_policy(kFakePolicy) {
-}
+ fake_policy(kFakePolicy) {}
bool EVOidData::Init() {
return true;
@@ -92,7 +103,7 @@ bool EVOidData::Init() {
#endif
-#if defined(USE_NSS_CERTS) || defined(OS_WIN)
+#if defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX)
class EVRootCAMetadataTest : public testing::Test {
protected:
@@ -125,7 +136,7 @@ TEST_F(EVRootCAMetadataTest, AddRemove) {
{
ScopedTestEVPolicy test_ev_policy(ev_metadata, kFakeFingerprint,
- kFakePolicy);
+ kFakePolicyStr);
EXPECT_TRUE(ev_metadata->IsEVPolicyOID(ev_oid_data.fake_policy));
EXPECT_TRUE(ev_metadata->HasEVPolicyOID(kFakeFingerprint,
@@ -137,7 +148,7 @@ TEST_F(EVRootCAMetadataTest, AddRemove) {
ev_oid_data.fake_policy));
}
-#endif // defined(USE_NSS_CERTS) || defined(OS_WIN)
+#endif // defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX)
} // namespace
diff --git a/chromium/net/cert/internal/cert_error_id.cc b/chromium/net/cert/internal/cert_error_id.cc
new file mode 100644
index 00000000000..80ab4f4f214
--- /dev/null
+++ b/chromium/net/cert/internal/cert_error_id.cc
@@ -0,0 +1,14 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/cert_error_id.h"
+
+namespace net {
+
+const char* CertErrorIdToDebugString(CertErrorId id) {
+ // The CertErrorId is simply a pointer for a C-string literal.
+ return reinterpret_cast<const char*>(id);
+}
+
+} // namespace net
diff --git a/chromium/net/cert/internal/cert_error_id.h b/chromium/net/cert/internal/cert_error_id.h
new file mode 100644
index 00000000000..062ba4069f7
--- /dev/null
+++ b/chromium/net/cert/internal/cert_error_id.h
@@ -0,0 +1,37 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_CERT_INTERNAL_CERT_ERROR_ID_H_
+#define NET_CERT_INTERNAL_CERT_ERROR_ID_H_
+
+#include "net/base/net_export.h"
+
+namespace net {
+
+// Each "class" of certificate error/warning has its own unique ID. This is
+// essentially like an error code, however the value is not stable. Under the
+// hood these IDs are pointers and use the process's address space to ensure
+// uniqueness.
+//
+// Equality of CertErrorId can be done using the == operator.
+//
+// To define new error IDs use the macro DEFINE_CERT_ERROR_ID().
+using CertErrorId = const void*;
+
+// DEFINE_CERT_ERROR_ID() creates a CertErrorId given a non-null C-string
+// literal. The string should be a textual name for the error which will appear
+// when pretty-printing errors for debugging. It should be ASCII.
+//
+// TODO(crbug.com/634443): Implement this -- add magic to ensure that storage
+// of identical strings isn't pool.
+#define DEFINE_CERT_ERROR_ID(name, c_str_literal) \
+ CertErrorId name = c_str_literal
+
+// Returns a debug string for a CertErrorId. In practice this returns the
+// string literal given to DEFINE_CERT_ERROR_ID(), which is human-readable.
+NET_EXPORT const char* CertErrorIdToDebugString(CertErrorId id);
+
+} // namespace net
+
+#endif // NET_CERT_INTERNAL_CERT_ERROR_ID_H_
diff --git a/chromium/net/cert/internal/cert_error_params.cc b/chromium/net/cert/internal/cert_error_params.cc
new file mode 100644
index 00000000000..29730602a09
--- /dev/null
+++ b/chromium/net/cert/internal/cert_error_params.cc
@@ -0,0 +1,135 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/cert_error_params.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/der/input.h"
+
+namespace net {
+
+namespace {
+
+// Parameters subclass for describing (and pretty-printing) 1 or 2 DER
+// blobs. It makes a copy of the der::Inputs.
+class CertErrorParams2Der : public CertErrorParams {
+ public:
+ CertErrorParams2Der(const char* name1,
+ const der::Input& der1,
+ const char* name2,
+ const der::Input& der2)
+ : name1_(name1),
+ der1_(der1.AsString()),
+ name2_(name2),
+ der2_(der2.AsString()) {}
+
+ std::string ToDebugString() const override {
+ std::string result;
+ AppendDer(name1_, der1_, &result);
+ if (name2_) {
+ result += "\n";
+ AppendDer(name2_, der2_, &result);
+ }
+ return result;
+ }
+
+ private:
+ static void AppendDer(const char* name,
+ const std::string& der,
+ std::string* out) {
+ *out += name;
+ *out += ": " + base::HexEncode(der.data(), der.size());
+ }
+
+ const char* name1_;
+ std::string der1_;
+
+ const char* name2_;
+ std::string der2_;
+
+ DISALLOW_COPY_AND_ASSIGN(CertErrorParams2Der);
+};
+
+// Parameters subclass for describing (and pretty-printing) a single size_t.
+class CertErrorParams1SizeT : public CertErrorParams {
+ public:
+ CertErrorParams1SizeT(const char* name, size_t value)
+ : name_(name), value_(value) {}
+
+ std::string ToDebugString() const override {
+ return name_ + std::string(": ") + base::SizeTToString(value_);
+ }
+
+ private:
+ const char* name_;
+ size_t value_;
+
+ DISALLOW_COPY_AND_ASSIGN(CertErrorParams1SizeT);
+};
+
+// Parameters subclass for describing (and pretty-printing) two size_t
+// values.
+class CertErrorParams2SizeT : public CertErrorParams {
+ public:
+ CertErrorParams2SizeT(const char* name1,
+ size_t value1,
+ const char* name2,
+ size_t value2)
+ : name1_(name1), value1_(value1), name2_(name2), value2_(value2) {}
+
+ std::string ToDebugString() const override {
+ return name1_ + std::string(": ") + base::SizeTToString(value1_) + "\n" +
+ name2_ + std::string(": ") + base::SizeTToString(value2_);
+ }
+
+ private:
+ const char* name1_;
+ size_t value1_;
+ const char* name2_;
+ size_t value2_;
+
+ DISALLOW_COPY_AND_ASSIGN(CertErrorParams2SizeT);
+};
+
+} // namespace
+
+CertErrorParams::CertErrorParams() = default;
+CertErrorParams::~CertErrorParams() = default;
+
+std::unique_ptr<CertErrorParams> CreateCertErrorParams1Der(
+ const char* name,
+ const der::Input& der) {
+ DCHECK(name);
+ return base::MakeUnique<CertErrorParams2Der>(name, der, nullptr,
+ der::Input());
+}
+
+std::unique_ptr<CertErrorParams> CreateCertErrorParams2Der(
+ const char* name1,
+ const der::Input& der1,
+ const char* name2,
+ const der::Input& der2) {
+ DCHECK(name1);
+ DCHECK(name2);
+ return base::MakeUnique<CertErrorParams2Der>(name1, der1, name2, der2);
+}
+
+std::unique_ptr<CertErrorParams> CreateCertErrorParams1SizeT(const char* name,
+ size_t value) {
+ DCHECK(name);
+ return base::MakeUnique<CertErrorParams1SizeT>(name, value);
+}
+
+NET_EXPORT std::unique_ptr<CertErrorParams> CreateCertErrorParams2SizeT(
+ const char* name1,
+ size_t value1,
+ const char* name2,
+ size_t value2) {
+ DCHECK(name1);
+ DCHECK(name2);
+ return base::MakeUnique<CertErrorParams2SizeT>(name1, value1, name2, value2);
+}
+
+} // namespace net
diff --git a/chromium/net/cert/internal/cert_error_params.h b/chromium/net/cert/internal/cert_error_params.h
new file mode 100644
index 00000000000..a57c24781ee
--- /dev/null
+++ b/chromium/net/cert/internal/cert_error_params.h
@@ -0,0 +1,74 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_CERT_INTERNAL_CERT_ERROR_PARAMS_H_
+#define NET_CERT_INTERNAL_CERT_ERROR_PARAMS_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+namespace der {
+class Input;
+}
+
+// CertErrorParams is a base class for describing extra parameters attached to
+// a CertErrorNode.
+//
+// An example use for parameters is to identify the OID for an unconsumed
+// critical extension. This parameter could then be pretty printed when
+// diagnosing the error.
+class NET_EXPORT CertErrorParams {
+ public:
+ CertErrorParams();
+ virtual ~CertErrorParams();
+
+ // Creates a representation of this parameter as a string, which may be
+ // used for pretty printing the error.
+ virtual std::string ToDebugString() const = 0;
+
+ // TODO(crbug.com/634443): Add methods to access the underlying
+ // structure, should they be needed for non-pretty-printing use cases.
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CertErrorParams);
+};
+
+// TODO(crbug.com/634443): Should the underlying parameter classes be exposed
+// so error consumers can access their data directly? (Without having to go
+// through the generic virtuals).
+
+// Creates a parameter object that holds a copy of |der|, and names it |name|
+// in debug string outputs.
+NET_EXPORT std::unique_ptr<CertErrorParams> CreateCertErrorParams1Der(
+ const char* name,
+ const der::Input& der);
+
+// Same as CreateCertErrorParams1Der() but has a second DER blob.
+NET_EXPORT std::unique_ptr<CertErrorParams> CreateCertErrorParams2Der(
+ const char* name1,
+ const der::Input& der1,
+ const char* name2,
+ const der::Input& der2);
+
+// Creates a parameter object that holds a single size_t value. |name| is used
+// when pretty-printing the parameters.
+NET_EXPORT std::unique_ptr<CertErrorParams> CreateCertErrorParams1SizeT(
+ const char* name,
+ size_t value);
+
+// Same as CreateCertErrorParams1SizeT() but has a second size_t.
+NET_EXPORT std::unique_ptr<CertErrorParams> CreateCertErrorParams2SizeT(
+ const char* name1,
+ size_t value1,
+ const char* name2,
+ size_t value2);
+
+} // namespace net
+
+#endif // NET_CERT_INTERNAL_CERT_ERROR_PARAMS_H_
diff --git a/chromium/net/cert/internal/cert_error_scoper.cc b/chromium/net/cert/internal/cert_error_scoper.cc
new file mode 100644
index 00000000000..c970f9acde6
--- /dev/null
+++ b/chromium/net/cert/internal/cert_error_scoper.cc
@@ -0,0 +1,54 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/cert_error_scoper.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "net/cert/internal/cert_error_params.h"
+#include "net/cert/internal/cert_errors.h"
+
+namespace net {
+
+CertErrorScoper::CertErrorScoper(CertErrors* parent_errors) {
+ DCHECK(parent_errors);
+ parent_errors_ = parent_errors;
+ parent_scoper_ = parent_errors->SetScoper(this);
+}
+
+CertErrorScoper::~CertErrorScoper() {
+ CertErrorScoper* prev = parent_errors_->SetScoper(parent_scoper_);
+ DCHECK_EQ(prev, this);
+}
+
+CertErrorNode* CertErrorScoper::LazyGetRootNode() {
+ if (!root_node_) {
+ // Create the node.
+ auto root_node = BuildRootNode();
+ root_node_ = root_node.get();
+
+ // Attach it to the node hiearchy (ownership of this node is passed off
+ // to its parent, which is ultimately rooted in the CertErrors object).
+ if (parent_scoper_) {
+ parent_scoper_->LazyGetRootNode()->AddChild(std::move(root_node));
+ } else {
+ parent_errors_->nodes_.push_back(std::move(root_node));
+ }
+ }
+
+ return root_node_;
+}
+
+CertErrorScoperNoParams::CertErrorScoperNoParams(CertErrors* parent_errors,
+ CertErrorId id)
+ : CertErrorScoper(parent_errors), id_(id) {}
+
+std::unique_ptr<CertErrorNode> CertErrorScoperNoParams::BuildRootNode() {
+ return base::MakeUnique<CertErrorNode>(CertErrorNodeType::TYPE_CONTEXT, id_,
+ nullptr);
+}
+
+} // namespace net
diff --git a/chromium/net/cert/internal/cert_error_scoper.h b/chromium/net/cert/internal/cert_error_scoper.h
new file mode 100644
index 00000000000..141581270df
--- /dev/null
+++ b/chromium/net/cert/internal/cert_error_scoper.h
@@ -0,0 +1,59 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_CERT_INTERNAL_CERT_ERROR_SCOPER_H_
+#define NET_CERT_INTERNAL_CERT_ERROR_SCOPER_H_
+
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/cert/internal/cert_error_id.h"
+
+namespace net {
+
+class CertErrors;
+struct CertErrorNode;
+
+// CertErrorScoper is a base class for adding parent nodes into a CertErrors
+// object.
+class NET_EXPORT CertErrorScoper {
+ public:
+ explicit CertErrorScoper(CertErrors* parent_errors);
+ virtual ~CertErrorScoper();
+
+ // BuildRootNode() will be called at most once, to create the desired parent
+ // node. It may never be called if no errors are added to the CertErrors
+ // parent.
+ virtual std::unique_ptr<CertErrorNode> BuildRootNode() = 0;
+
+ // Returns the parent node for this scoper (the one created by
+ // BuildRootNode()).
+ CertErrorNode* LazyGetRootNode();
+
+ private:
+ CertErrorScoper* parent_scoper_ = nullptr;
+ CertErrors* parent_errors_ = nullptr;
+ CertErrorNode* root_node_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(CertErrorScoper);
+};
+
+// Implementation of CertErrorScoper that creates a simple parent node with no
+// parameters (just an ID).
+class NET_EXPORT CertErrorScoperNoParams : public CertErrorScoper {
+ public:
+ CertErrorScoperNoParams(CertErrors* parent_errors, CertErrorId id);
+ std::unique_ptr<CertErrorNode> BuildRootNode() override;
+
+ private:
+ CertErrorId id_;
+
+ DISALLOW_COPY_AND_ASSIGN(CertErrorScoperNoParams);
+};
+
+} // namespace net
+
+#endif // NET_CERT_INTERNAL_CERT_ERROR_SCOPER_H_
diff --git a/chromium/net/cert/internal/cert_errors.cc b/chromium/net/cert/internal/cert_errors.cc
new file mode 100644
index 00000000000..e66ab827fcf
--- /dev/null
+++ b/chromium/net/cert/internal/cert_errors.cc
@@ -0,0 +1,140 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/cert_errors.h"
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_split.h"
+#include "net/cert/internal/cert_error_params.h"
+#include "net/cert/internal/cert_error_scoper.h"
+
+namespace net {
+
+namespace {
+
+// Helpers for pretty-printing CertErrors to a string.
+void AppendNodeToDebugString(CertErrorNode* node,
+ const std::string& indentation,
+ std::string* out);
+
+void AppendChildrenToDebugString(const CertErrorNodes& children,
+ const std::string& indentation,
+ std::string* out) {
+ for (const auto& child : children)
+ AppendNodeToDebugString(child.get(), indentation, out);
+}
+
+void AppendLinesWithIndentation(const std::string& text,
+ const std::string& indentation,
+ std::string* out) {
+ std::vector<base::StringPiece> lines = base::SplitStringPieceUsingSubstr(
+ text, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+
+ for (const auto& line : lines) {
+ *out += indentation;
+ line.AppendToString(out);
+ *out += "\n";
+ }
+}
+
+const char* CertErrorNodeTypeToString(CertErrorNodeType type) {
+ switch (type) {
+ case CertErrorNodeType::TYPE_CONTEXT:
+ return "[Context] ";
+ case CertErrorNodeType::TYPE_WARNING:
+ return "[Warning] ";
+ case CertErrorNodeType::TYPE_ERROR:
+ return "[Error] ";
+ }
+ return nullptr;
+}
+
+void AppendNodeToDebugString(CertErrorNode* node,
+ const std::string& indentation,
+ std::string* out) {
+ std::string cur_indentation = indentation;
+
+ *out += cur_indentation;
+ *out += CertErrorNodeTypeToString(node->node_type);
+ *out += CertErrorIdToDebugString(node->id);
+ *out += +"\n";
+
+ if (node->params) {
+ cur_indentation += " ";
+ AppendLinesWithIndentation(node->params->ToDebugString(), cur_indentation,
+ out);
+ }
+
+ cur_indentation += " ";
+
+ AppendChildrenToDebugString(node->children, cur_indentation, out);
+}
+
+} // namespace
+
+CertErrorNode::CertErrorNode(CertErrorNodeType node_type,
+ CertErrorId id,
+ std::unique_ptr<CertErrorParams> params)
+ : node_type(node_type), id(id), params(std::move(params)) {}
+
+CertErrorNode::~CertErrorNode() = default;
+
+void CertErrorNode::AddChild(std::unique_ptr<CertErrorNode> child) {
+ DCHECK_EQ(CertErrorNodeType::TYPE_CONTEXT, node_type);
+ children.push_back(std::move(child));
+}
+
+CertErrors::CertErrors() = default;
+
+CertErrors::~CertErrors() = default;
+
+void CertErrors::Add(CertErrorNodeType node_type,
+ CertErrorId id,
+ std::unique_ptr<CertErrorParams> params) {
+ AddNode(base::MakeUnique<CertErrorNode>(node_type, id, std::move(params)));
+}
+
+void CertErrors::AddError(CertErrorId id,
+ std::unique_ptr<CertErrorParams> params) {
+ Add(CertErrorNodeType::TYPE_ERROR, id, std::move(params));
+}
+
+void CertErrors::AddError(CertErrorId id) {
+ AddError(id, nullptr);
+}
+
+void CertErrors::AddWarning(CertErrorId id,
+ std::unique_ptr<CertErrorParams> params) {
+ Add(CertErrorNodeType::TYPE_WARNING, id, std::move(params));
+}
+
+void CertErrors::AddWarning(CertErrorId id) {
+ AddWarning(id, nullptr);
+}
+
+bool CertErrors::empty() const {
+ return nodes_.empty();
+}
+
+std::string CertErrors::ToDebugString() const {
+ std::string result;
+ AppendChildrenToDebugString(nodes_, std::string(), &result);
+ return result;
+}
+
+void CertErrors::AddNode(std::unique_ptr<CertErrorNode> node) {
+ if (current_scoper_)
+ current_scoper_->LazyGetRootNode()->AddChild(std::move(node));
+ else
+ nodes_.push_back(std::move(node));
+}
+
+CertErrorScoper* CertErrors::SetScoper(CertErrorScoper* scoper) {
+ CertErrorScoper* prev = current_scoper_;
+ current_scoper_ = scoper;
+ return prev;
+}
+
+} // namespace net
diff --git a/chromium/net/cert/internal/cert_errors.h b/chromium/net/cert/internal/cert_errors.h
new file mode 100644
index 00000000000..a9579ce0c31
--- /dev/null
+++ b/chromium/net/cert/internal/cert_errors.h
@@ -0,0 +1,164 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ----------------------------
+// Overview of error design
+// ----------------------------
+//
+// Certificate path validation/parsing may emit a sequence of
+// errors/warnings/context. These are represented by a tree of CertErrorNodes.
+// Each node is comprised of:
+//
+// * A unique identifier.
+//
+// This serves similarly to an error code, and is useful for querying if a
+// particular error occurred.
+//
+// * [optional] A parameters object.
+//
+// Nodes may attach a heap-allocated subclass of CertErrorParams, to carry
+// extra information that is useful when reporting the error. For instance
+// a parsing error may want to describe where in the DER the failure
+// happened, or what the unexpected value was.
+//
+// * [optional] Child nodes.
+//
+// Error nodes are arranged in a tree. The parent/child hierarchy is used to
+// group errors that share some common state.
+// For instance during path processing it is useful to group the
+// errors/warnings that happened while processing certificate "i" as
+// children of a shared "context" node. The context node in this case
+// doesn't describe a particular error, but rather some shared event and
+// its parameters.
+//
+// ----------------------------
+// Using errors in other APIs
+// ----------------------------
+//
+// The top level object used in APIs is CertErrors. A pointer to a CertErrors
+// object is typically given as an out-parameter for code that may generate
+// errors.
+//
+// Note that CertErrors gives a non-hiearhical interface for emitting errors.
+// In other words, it doesn't let you create parent/child relationships
+// directly.
+//
+// To change the parent node for subsequently emitted errors in the CertErrors
+// object, one constructs a CertErrorScoper on the stack.
+//
+// ----------------------------
+// Defining new errors
+// ----------------------------
+//
+// The error IDs are extensible and do not need to be centrally defined.
+//
+// To define a new error use the macro DEFINE_CERT_ERROR_ID() in a .cc file.
+// If consumers are to be able to query for this error then the symbol should
+// also be exposed in a header file.
+//
+// Error IDs are in truth string literals, whose pointer value will be unique
+// per process.
+
+#ifndef NET_CERT_INTERNAL_CERT_ERRORS_H_
+#define NET_CERT_INTERNAL_CERT_ERRORS_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/cert/internal/cert_error_id.h"
+
+namespace net {
+
+class CertErrorParams;
+class CertErrorScoper;
+class ParsedCertificate;
+
+// The type of a particular CertErrorNode.
+enum class CertErrorNodeType {
+ // Note the TYPE_ prefix is to avoid compile errors. Because ERROR() is a
+ // commonly used macro name.
+
+ // Node that represents a single error.
+ TYPE_ERROR,
+
+ // Node that represents a single non-fatal error.
+ TYPE_WARNING,
+
+ // Parent node for other errors/warnings.
+ TYPE_CONTEXT,
+};
+
+struct CertErrorNode;
+using CertErrorNodes = std::vector<std::unique_ptr<CertErrorNode>>;
+
+// CertErrorNode represents a node in the error tree. This could be an error,
+// warning, or simply contextual parent node. See the error design overview for
+// a better description of how this is used.
+struct NET_EXPORT CertErrorNode {
+ CertErrorNode(CertErrorNodeType node_type,
+ CertErrorId id,
+ std::unique_ptr<CertErrorParams> params);
+ ~CertErrorNode();
+
+ void AddChild(std::unique_ptr<CertErrorNode> child);
+
+ CertErrorNodeType node_type;
+ CertErrorId id;
+ std::unique_ptr<CertErrorParams> params;
+ CertErrorNodes children;
+};
+
+// CertErrors is the main object for emitting errors and internally builds up
+// the error tree.
+class NET_EXPORT CertErrors {
+ public:
+ CertErrors();
+ ~CertErrors();
+
+ // Adds a node to the current insertion point in the error tree. |params| may
+ // be null.
+ void Add(CertErrorNodeType node_type,
+ CertErrorId id,
+ std::unique_ptr<CertErrorParams> params);
+
+ void AddError(CertErrorId id, std::unique_ptr<CertErrorParams> params);
+ void AddError(CertErrorId id);
+
+ void AddWarning(CertErrorId id, std::unique_ptr<CertErrorParams> params);
+ void AddWarning(CertErrorId id);
+
+ // Returns true if the tree is empty. Note that emptiness of the error tree
+ // is NOT equivalent to success for some call, and vice versa. (For instance
+ // consumers may forget to emit errors on failures, or some errors may be
+ // non-fatal warnings).
+ bool empty() const;
+
+ // Dumps a textual representation of the errors for debugging purposes.
+ std::string ToDebugString() const;
+
+ private:
+ // CertErrorScoper manipulates the CertErrors object.
+ friend class CertErrorScoper;
+
+ void AddNode(std::unique_ptr<CertErrorNode> node);
+
+ // Used by CertErrorScoper to register itself as the top-level scoper.
+ // Returns the previously set scoper, or nullptr if there was none.
+ CertErrorScoper* SetScoper(CertErrorScoper* scoper);
+
+ CertErrorNodes nodes_;
+
+ // The top-most CertErrorScoper that is currently in scope (and which affects
+ // the parent node for newly added errors).
+ CertErrorScoper* current_scoper_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(CertErrors);
+};
+
+} // namespace net
+
+#endif // NET_CERT_INTERNAL_CERT_ERRORS_H_
diff --git a/chromium/net/cert/internal/cert_issuer_source.h b/chromium/net/cert/internal/cert_issuer_source.h
index 61580a80f48..1ffc3b3a9f9 100644
--- a/chromium/net/cert/internal/cert_issuer_source.h
+++ b/chromium/net/cert/internal/cert_issuer_source.h
@@ -11,11 +11,10 @@
#include "base/callback.h"
#include "net/base/net_export.h"
#include "net/cert/internal/completion_status.h"
+#include "net/cert/internal/parsed_certificate.h"
namespace net {
-class ParsedCertificate;
-
// Interface for looking up issuers of a certificate during path building.
// Provides a synchronous and asynchronous method for retrieving issuers, so the
// path builder can try to complete synchronously first. The caller is expected
@@ -58,9 +57,8 @@ class NET_EXPORT CertIssuerSource {
// Matches are appended to |issuers|. Any existing contents of |issuers| will
// not be modified. If the implementation does not support synchronous
// lookups, or if there are no matches, |issuers| is not modified.
- virtual void SyncGetIssuersOf(
- const ParsedCertificate* cert,
- std::vector<scoped_refptr<ParsedCertificate>>* issuers) = 0;
+ virtual void SyncGetIssuersOf(const ParsedCertificate* cert,
+ ParsedCertificateList* issuers) = 0;
// Finds certificates whose Subject matches |cert|'s Issuer.
// If an async callback will be made |*out_req| is filled with a Request
diff --git a/chromium/net/cert/internal/cert_issuer_source_aia.cc b/chromium/net/cert/internal/cert_issuer_source_aia.cc
index 4dacc340467..a6fb1b703d1 100644
--- a/chromium/net/cert/internal/cert_issuer_source_aia.cc
+++ b/chromium/net/cert/internal/cert_issuer_source_aia.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "net/cert/cert_net_fetcher.h"
-#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/cert_errors.h"
#include "url/gurl.h"
namespace net {
@@ -37,7 +37,7 @@ class AiaRequest : public CertIssuerSource::Request {
CertIssuerSource::IssuerCallback issuers_callback_;
std::vector<std::unique_ptr<CertNetFetcher::Request>> cert_fetcher_requests_;
size_t pending_requests_ = 0;
- std::vector<scoped_refptr<ParsedCertificate>> results_;
+ ParsedCertificateList results_;
size_t current_result_ = 0;
DISALLOW_COPY_AND_ASSIGN(AiaRequest);
@@ -87,11 +87,13 @@ void AiaRequest::OnFetchCompleted(Error error,
// TODO(mattm): Avoid copying bytes. Change the CertNetFetcher and
// ParsedCertificate interface to allow passing through ownership of the
// bytes.
- if (!ParsedCertificate::CreateAndAddToVector(
- fetched_bytes.data(), fetched_bytes.size(),
- ParsedCertificate::DataSource::INTERNAL_COPY, {}, &results_)) {
- // TODO(mattm): propagate error info.
- LOG(ERROR) << "Error parsing AIA data";
+ CertErrors errors;
+ if (!ParsedCertificate::CreateAndAddToVector(fetched_bytes.data(),
+ fetched_bytes.size(), {},
+ &results_, &errors)) {
+ // TODO(crbug.com/634443): propagate error info.
+ LOG(ERROR) << "Error parsing cert retrieved from AIA:\n"
+ << errors.ToDebugString();
}
}
// If the client is waiting for results, need to run callback if:
@@ -109,9 +111,8 @@ CertIssuerSourceAia::CertIssuerSourceAia(CertNetFetcher* cert_fetcher)
CertIssuerSourceAia::~CertIssuerSourceAia() = default;
-void CertIssuerSourceAia::SyncGetIssuersOf(
- const ParsedCertificate* cert,
- std::vector<scoped_refptr<ParsedCertificate>>* issuers) {
+void CertIssuerSourceAia::SyncGetIssuersOf(const ParsedCertificate* cert,
+ ParsedCertificateList* issuers) {
// CertIssuerSourceAia never returns synchronous results.
}
diff --git a/chromium/net/cert/internal/cert_issuer_source_aia.h b/chromium/net/cert/internal/cert_issuer_source_aia.h
index e0c7fe77676..73c8177bce0 100644
--- a/chromium/net/cert/internal/cert_issuer_source_aia.h
+++ b/chromium/net/cert/internal/cert_issuer_source_aia.h
@@ -6,6 +6,7 @@
#define NET_CERT_INTERNAL_CERT_ISSUER_SOURCE_AIA_H_
#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
#include "net/cert/internal/cert_issuer_source.h"
namespace net {
@@ -22,9 +23,8 @@ class NET_EXPORT CertIssuerSourceAia : public CertIssuerSource {
~CertIssuerSourceAia() override;
// CertIssuerSource implementation:
- void SyncGetIssuersOf(
- const ParsedCertificate* cert,
- std::vector<scoped_refptr<ParsedCertificate>>* issuers) override;
+ void SyncGetIssuersOf(const ParsedCertificate* cert,
+ ParsedCertificateList* issuers) override;
void AsyncGetIssuersOf(const ParsedCertificate* cert,
const IssuerCallback& issuers_callback,
std::unique_ptr<Request>* out_req) override;
diff --git a/chromium/net/cert/internal/cert_issuer_source_aia_unittest.cc b/chromium/net/cert/internal/cert_issuer_source_aia_unittest.cc
index 455cf669b3a..b0f1aa72d28 100644
--- a/chromium/net/cert/internal/cert_issuer_source_aia_unittest.cc
+++ b/chromium/net/cert/internal/cert_issuer_source_aia_unittest.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "net/cert/cert_net_fetcher.h"
+#include "net/cert/internal/cert_errors.h"
#include "net/cert/internal/parsed_certificate.h"
#include "net/cert/internal/test_helpers.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -38,9 +39,13 @@ using ::testing::StrictMock;
"CERTIFICATE", &der);
if (!r)
return r;
- *result = ParsedCertificate::CreateFromCertificateCopy(der, {});
- if (!*result)
- return ::testing::AssertionFailure() << "CreateFromCertificateCopy failed";
+ CertErrors errors;
+ *result = ParsedCertificate::Create(der, {}, &errors);
+ if (!*result) {
+ return ::testing::AssertionFailure()
+ << "ParsedCertificate::Create() failed:\n"
+ << errors.ToDebugString();
+ }
return ::testing::AssertionSuccess();
}
@@ -166,7 +171,7 @@ TEST(CertIssuerSourceAiaTest, NoSyncResults) {
StrictMock<MockCertNetFetcherImpl> mock_fetcher;
CertIssuerSourceAia aia_source(&mock_fetcher);
- std::vector<scoped_refptr<ParsedCertificate>> issuers;
+ ParsedCertificateList issuers;
aia_source.SyncGetIssuersOf(cert.get(), &issuers);
EXPECT_EQ(0U, issuers.size());
}
diff --git a/chromium/net/cert/internal/cert_issuer_source_static.cc b/chromium/net/cert/internal/cert_issuer_source_static.cc
index c7685f436a1..d8a42a3f30e 100644
--- a/chromium/net/cert/internal/cert_issuer_source_static.cc
+++ b/chromium/net/cert/internal/cert_issuer_source_static.cc
@@ -4,8 +4,6 @@
#include "net/cert/internal/cert_issuer_source_static.h"
-#include "net/cert/internal/parsed_certificate.h"
-
namespace net {
CertIssuerSourceStatic::CertIssuerSourceStatic() = default;
@@ -16,9 +14,8 @@ void CertIssuerSourceStatic::AddCert(scoped_refptr<ParsedCertificate> cert) {
cert->normalized_subject().AsStringPiece(), std::move(cert)));
}
-void CertIssuerSourceStatic::SyncGetIssuersOf(
- const ParsedCertificate* cert,
- std::vector<scoped_refptr<ParsedCertificate>>* issuers) {
+void CertIssuerSourceStatic::SyncGetIssuersOf(const ParsedCertificate* cert,
+ ParsedCertificateList* issuers) {
auto range =
intermediates_.equal_range(cert->normalized_issuer().AsStringPiece());
for (auto it = range.first; it != range.second; ++it)
diff --git a/chromium/net/cert/internal/cert_issuer_source_static.h b/chromium/net/cert/internal/cert_issuer_source_static.h
index af67268c2aa..143e97d660b 100644
--- a/chromium/net/cert/internal/cert_issuer_source_static.h
+++ b/chromium/net/cert/internal/cert_issuer_source_static.h
@@ -8,6 +8,7 @@
#include <unordered_map>
#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
#include "net/cert/internal/cert_issuer_source.h"
namespace net {
@@ -23,9 +24,8 @@ class NET_EXPORT CertIssuerSourceStatic : public CertIssuerSource {
void AddCert(scoped_refptr<ParsedCertificate> cert);
// CertIssuerSource implementation:
- void SyncGetIssuersOf(
- const ParsedCertificate* cert,
- std::vector<scoped_refptr<ParsedCertificate>>* issuers) override;
+ void SyncGetIssuersOf(const ParsedCertificate* cert,
+ ParsedCertificateList* issuers) override;
void AsyncGetIssuersOf(const ParsedCertificate* cert,
const IssuerCallback& issuers_callback,
std::unique_ptr<Request>* out_req) override;
diff --git a/chromium/net/cert/internal/cert_issuer_source_static_unittest.cc b/chromium/net/cert/internal/cert_issuer_source_static_unittest.cc
index 148f3620dd0..949035c0eb1 100644
--- a/chromium/net/cert/internal/cert_issuer_source_static_unittest.cc
+++ b/chromium/net/cert/internal/cert_issuer_source_static_unittest.cc
@@ -5,6 +5,7 @@
#include "net/cert/internal/cert_issuer_source_static.h"
#include "base/bind.h"
+#include "net/cert/internal/cert_errors.h"
#include "net/cert/internal/parsed_certificate.h"
#include "net/cert/internal/test_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -36,9 +37,13 @@ void NotCalled(CertIssuerSource::Request* req) {
"CERTIFICATE", &der);
if (!r)
return r;
- *result = ParsedCertificate::CreateFromCertificateCopy(der, {});
- if (!*result)
- return ::testing::AssertionFailure() << "CreateFromCertificateCopy failed";
+ CertErrors errors;
+ *result = ParsedCertificate::Create(der, {}, &errors);
+ if (!*result) {
+ return ::testing::AssertionFailure()
+ << "ParsedCertificate::Create() failed:\n"
+ << errors.ToDebugString();
+ }
return ::testing::AssertionSuccess();
}
@@ -78,7 +83,7 @@ TEST_F(CertIssuerSourceStaticTest, NoMatch) {
CertIssuerSourceStatic source;
source.AddCert(root_);
- std::vector<scoped_refptr<ParsedCertificate>> issuers;
+ ParsedCertificateList issuers;
source.SyncGetIssuersOf(c1_.get(), &issuers);
ASSERT_EQ(0U, issuers.size());
}
@@ -87,7 +92,7 @@ TEST_F(CertIssuerSourceStaticTest, OneMatch) {
CertIssuerSourceStatic source;
AddAllCerts(&source);
- std::vector<scoped_refptr<ParsedCertificate>> issuers;
+ ParsedCertificateList issuers;
source.SyncGetIssuersOf(i1_1_.get(), &issuers);
ASSERT_EQ(1U, issuers.size());
EXPECT_TRUE(issuers[0] == root_);
@@ -102,7 +107,7 @@ TEST_F(CertIssuerSourceStaticTest, MultipleMatches) {
CertIssuerSourceStatic source;
AddAllCerts(&source);
- std::vector<scoped_refptr<ParsedCertificate>> issuers;
+ ParsedCertificateList issuers;
source.SyncGetIssuersOf(c1_.get(), &issuers);
ASSERT_EQ(2U, issuers.size());
@@ -120,7 +125,7 @@ TEST_F(CertIssuerSourceStaticTest, SelfIssued) {
CertIssuerSourceStatic source;
AddAllCerts(&source);
- std::vector<scoped_refptr<ParsedCertificate>> issuers;
+ ParsedCertificateList issuers;
source.SyncGetIssuersOf(root_.get(), &issuers);
ASSERT_EQ(1U, issuers.size());
diff --git a/chromium/net/cert/internal/extended_key_usage.h b/chromium/net/cert/internal/extended_key_usage.h
index 9e8812a38a0..ae4cd8560a3 100644
--- a/chromium/net/cert/internal/extended_key_usage.h
+++ b/chromium/net/cert/internal/extended_key_usage.h
@@ -7,6 +7,7 @@
#include <vector>
+#include "net/base/net_export.h"
#include "net/der/input.h"
namespace net {
diff --git a/chromium/net/cert/internal/name_constraints.cc b/chromium/net/cert/internal/name_constraints.cc
index a515789730d..162569f964c 100644
--- a/chromium/net/cert/internal/name_constraints.cc
+++ b/chromium/net/cert/internal/name_constraints.cc
@@ -300,7 +300,7 @@ GeneralNames::GeneralNames() {}
GeneralNames::~GeneralNames() {}
// static
-std::unique_ptr<GeneralNames> GeneralNames::CreateFromDer(
+std::unique_ptr<GeneralNames> GeneralNames::Create(
const der::Input& general_names_tlv) {
// RFC 5280 section 4.2.1.6:
// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
@@ -332,7 +332,7 @@ std::unique_ptr<GeneralNames> GeneralNames::CreateFromDer(
NameConstraints::~NameConstraints() {}
// static
-std::unique_ptr<NameConstraints> NameConstraints::CreateFromDer(
+std::unique_ptr<NameConstraints> NameConstraints::Create(
const der::Input& extension_value,
bool is_critical) {
std::unique_ptr<NameConstraints> name_constraints(new NameConstraints());
diff --git a/chromium/net/cert/internal/name_constraints.h b/chromium/net/cert/internal/name_constraints.h
index ccf4ac12b74..117c3f0bebc 100644
--- a/chromium/net/cert/internal/name_constraints.h
+++ b/chromium/net/cert/internal/name_constraints.h
@@ -12,6 +12,7 @@
#include "base/compiler_specific.h"
#include "net/base/ip_address.h"
+#include "net/base/net_export.h"
namespace net {
@@ -48,7 +49,7 @@ struct NET_EXPORT GeneralNames {
// Create a GeneralNames object representing the DER-encoded
// |general_names_tlv|.
- static std::unique_ptr<GeneralNames> CreateFromDer(
+ static std::unique_ptr<GeneralNames> Create(
const der::Input& general_names_tlv);
// ASCII hostnames.
@@ -84,7 +85,7 @@ class NET_EXPORT NameConstraints {
// the OCTET STRING tag). |is_critical| should be true if the extension was
// marked critical. Returns nullptr if parsing the the extension failed.
// The object lifetime is not bound to the lifetime of |extension_value| data.
- static std::unique_ptr<NameConstraints> CreateFromDer(
+ static std::unique_ptr<NameConstraints> Create(
const der::Input& extension_value,
bool is_critical);
diff --git a/chromium/net/cert/internal/name_constraints_unittest.cc b/chromium/net/cert/internal/name_constraints_unittest.cc
index f61e1da5c2d..f1dd470d093 100644
--- a/chromium/net/cert/internal/name_constraints_unittest.cc
+++ b/chromium/net/cert/internal/name_constraints_unittest.cc
@@ -8,8 +8,12 @@
#include "net/base/ip_address.h"
#include "net/cert/internal/test_helpers.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -49,9 +53,9 @@ namespace {
LoadTestSubjectAltNameData(basename, &san_der);
if (!load_result)
return load_result;
- *result = GeneralNames::CreateFromDer(der::Input(&san_der));
+ *result = GeneralNames::Create(der::Input(&san_der));
if (!*result)
- return ::testing::AssertionFailure() << "CreateFromDer failed";
+ return ::testing::AssertionFailure() << "Create failed";
return ::testing::AssertionSuccess();
}
@@ -74,7 +78,7 @@ TEST_P(ParseNameConstraints, DNSNames) {
ASSERT_TRUE(LoadTestNameConstraint("dnsname.pem", &a));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(name_constraints);
EXPECT_TRUE(name_constraints->IsPermittedDNSName("permitted.example.com"));
@@ -157,7 +161,7 @@ TEST_P(ParseNameConstraints,
std::string a;
ASSERT_TRUE(LoadTestNameConstraint("dnsname2.pem", &a));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(name_constraints);
// Matches permitted exactly.
@@ -187,7 +191,7 @@ TEST_P(ParseNameConstraints, DNSNamesWithLeadingDot) {
ASSERT_TRUE(
LoadTestNameConstraint("dnsname-permitted_with_leading_dot.pem", &a));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(name_constraints);
// dNSName constraints should be specified as a host. A dNSName constraint
@@ -204,7 +208,7 @@ TEST_P(ParseNameConstraints, DNSNamesExcludeOnly) {
ASSERT_TRUE(LoadTestNameConstraint("dnsname-excluded.pem", &a));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(name_constraints);
// Only "excluded.permitted.example.com" is excluded, and since permitted is
@@ -223,7 +227,7 @@ TEST_P(ParseNameConstraints, DNSNamesExcludeAll) {
ASSERT_TRUE(LoadTestNameConstraint("dnsname-excludeall.pem", &a));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(name_constraints);
// "permitted.example.com" is in the permitted section, but since "" is
@@ -240,7 +244,7 @@ TEST_P(ParseNameConstraints, DNSNamesExcludeDot) {
ASSERT_TRUE(LoadTestNameConstraint("dnsname-exclude_dot.pem", &a));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(name_constraints);
// "." is excluded, which should match nothing.
@@ -258,7 +262,7 @@ TEST_P(ParseNameConstraints, DNSNamesFailOnInvalidIA5String) {
ASSERT_NE(std::string::npos, replace_location);
a.replace(replace_location, 1, 1, -1);
- EXPECT_FALSE(NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ EXPECT_FALSE(NameConstraints::Create(der::Input(&a), is_critical()));
}
TEST_P(ParseNameConstraints, DirectoryNames) {
@@ -284,8 +288,7 @@ TEST_P(ParseNameConstraints, DirectoryNames) {
ASSERT_TRUE(LoadTestName("name-ca.pem", &name_ca));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
// Not in any permitted subtree.
@@ -347,8 +350,7 @@ TEST_P(ParseNameConstraints, DirectoryNamesExcludeOnly) {
ASSERT_TRUE(
LoadTestNameConstraint("directoryname-excluded.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
std::string name_empty;
@@ -378,8 +380,7 @@ TEST_P(ParseNameConstraints, DirectoryNamesExcludeAll) {
ASSERT_TRUE(
LoadTestNameConstraint("directoryname-excludeall.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
std::string name_empty;
@@ -411,7 +412,7 @@ TEST_P(ParseNameConstraints, IPAdresses) {
ASSERT_TRUE(LoadTestNameConstraint("ipaddress.pem", &a));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(name_constraints);
// IPv4 tests:
@@ -526,7 +527,7 @@ TEST_P(ParseNameConstraints, IPAdressesExcludeOnly) {
ASSERT_TRUE(LoadTestNameConstraint("ipaddress-excluded.pem", &a));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(name_constraints);
// Only 192.168.5.0/255.255.255.0 is excluded, and since permitted is empty,
@@ -542,7 +543,7 @@ TEST_P(ParseNameConstraints, IPAdressesExcludeAll) {
ASSERT_TRUE(LoadTestNameConstraint("ipaddress-excludeall.pem", &a));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(name_constraints);
// 192.168.0.0/255.255.0.0 and
@@ -561,7 +562,7 @@ TEST_P(ParseNameConstraints, IPAdressesNetmaskPermitSingleHost) {
ASSERT_TRUE(LoadTestNameConstraint("ipaddress-permit_singlehost.pem", &a));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(name_constraints);
EXPECT_FALSE(name_constraints->IsPermittedIP(IPAddress::IPv4AllZeros()));
@@ -577,7 +578,7 @@ TEST_P(ParseNameConstraints, IPAdressesNetmaskPermitPrefixLen31) {
ASSERT_TRUE(LoadTestNameConstraint("ipaddress-permit_prefix31.pem", &a));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(name_constraints);
EXPECT_FALSE(name_constraints->IsPermittedIP(IPAddress::IPv4AllZeros()));
@@ -594,7 +595,7 @@ TEST_P(ParseNameConstraints, IPAdressesNetmaskPermitPrefixLen1) {
ASSERT_TRUE(LoadTestNameConstraint("ipaddress-permit_prefix1.pem", &a));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(name_constraints);
EXPECT_FALSE(name_constraints->IsPermittedIP(IPAddress::IPv4AllZeros()));
@@ -610,7 +611,7 @@ TEST_P(ParseNameConstraints, IPAdressesNetmaskPermitAll) {
ASSERT_TRUE(LoadTestNameConstraint("ipaddress-permit_all.pem", &a));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(name_constraints);
EXPECT_TRUE(name_constraints->IsPermittedIP(IPAddress::IPv4AllZeros()));
@@ -622,26 +623,26 @@ TEST_P(ParseNameConstraints, IPAdressesFailOnInvalidAddr) {
std::string a;
ASSERT_TRUE(LoadTestNameConstraint("ipaddress-invalid_addr.pem", &a));
- EXPECT_FALSE(NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ EXPECT_FALSE(NameConstraints::Create(der::Input(&a), is_critical()));
}
TEST_P(ParseNameConstraints, IPAdressesFailOnInvalidMaskNotContiguous) {
std::string a;
ASSERT_TRUE(LoadTestNameConstraint(
"ipaddress-invalid_mask_not_contiguous_1.pem", &a));
- EXPECT_FALSE(NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ EXPECT_FALSE(NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(LoadTestNameConstraint(
"ipaddress-invalid_mask_not_contiguous_2.pem", &a));
- EXPECT_FALSE(NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ EXPECT_FALSE(NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(LoadTestNameConstraint(
"ipaddress-invalid_mask_not_contiguous_3.pem", &a));
- EXPECT_FALSE(NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ EXPECT_FALSE(NameConstraints::Create(der::Input(&a), is_critical()));
ASSERT_TRUE(LoadTestNameConstraint(
"ipaddress-invalid_mask_not_contiguous_4.pem", &a));
- EXPECT_FALSE(NameConstraints::CreateFromDer(der::Input(&a), is_critical()));
+ EXPECT_FALSE(NameConstraints::Create(der::Input(&a), is_critical()));
}
TEST_P(ParseNameConstraints, OtherNamesInPermitted) {
@@ -649,8 +650,7 @@ TEST_P(ParseNameConstraints, OtherNamesInPermitted) {
ASSERT_TRUE(
LoadTestNameConstraint("othername-permitted.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
if (is_critical()) {
@@ -671,8 +671,7 @@ TEST_P(ParseNameConstraints, OtherNamesInExcluded) {
ASSERT_TRUE(
LoadTestNameConstraint("othername-excluded.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
if (is_critical()) {
@@ -693,8 +692,7 @@ TEST_P(ParseNameConstraints, Rfc822NamesInPermitted) {
ASSERT_TRUE(
LoadTestNameConstraint("rfc822name-permitted.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
if (is_critical()) {
@@ -715,8 +713,7 @@ TEST_P(ParseNameConstraints, Rfc822NamesInExcluded) {
ASSERT_TRUE(
LoadTestNameConstraint("rfc822name-excluded.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
if (is_critical()) {
@@ -737,8 +734,7 @@ TEST_P(ParseNameConstraints, X400AddresssInPermitted) {
ASSERT_TRUE(
LoadTestNameConstraint("x400address-permitted.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
if (is_critical()) {
@@ -759,8 +755,7 @@ TEST_P(ParseNameConstraints, X400AddresssInExcluded) {
ASSERT_TRUE(
LoadTestNameConstraint("x400address-excluded.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
if (is_critical()) {
@@ -781,8 +776,7 @@ TEST_P(ParseNameConstraints, EdiPartyNamesInPermitted) {
ASSERT_TRUE(
LoadTestNameConstraint("edipartyname-permitted.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
if (is_critical()) {
@@ -803,8 +797,7 @@ TEST_P(ParseNameConstraints, EdiPartyNamesInExcluded) {
ASSERT_TRUE(
LoadTestNameConstraint("edipartyname-excluded.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
if (is_critical()) {
@@ -824,8 +817,7 @@ TEST_P(ParseNameConstraints, URIsInPermitted) {
std::string constraints_der;
ASSERT_TRUE(LoadTestNameConstraint("uri-permitted.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
if (is_critical()) {
@@ -845,8 +837,7 @@ TEST_P(ParseNameConstraints, URIsInExcluded) {
std::string constraints_der;
ASSERT_TRUE(LoadTestNameConstraint("uri-excluded.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
if (is_critical()) {
@@ -867,8 +858,7 @@ TEST_P(ParseNameConstraints, RegisteredIDsInPermitted) {
ASSERT_TRUE(
LoadTestNameConstraint("registeredid-permitted.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
if (is_critical()) {
@@ -889,8 +879,7 @@ TEST_P(ParseNameConstraints, RegisteredIDsInExcluded) {
ASSERT_TRUE(
LoadTestNameConstraint("registeredid-excluded.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
if (is_critical()) {
@@ -914,16 +903,16 @@ TEST_P(ParseNameConstraints,
// The value should not be in the DER encoding if it is the default. But this
// could be changed to allowed if there are buggy encoders out there that
// include it anyway.
- EXPECT_FALSE(NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ EXPECT_FALSE(
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
}
TEST_P(ParseNameConstraints, FailsOnGeneralSubtreeWithMinimum) {
std::string constraints_der;
ASSERT_TRUE(
LoadTestNameConstraint("dnsname-with_min_1.pem", &constraints_der));
- EXPECT_FALSE(NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ EXPECT_FALSE(
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
}
TEST_P(ParseNameConstraints,
@@ -931,61 +920,60 @@ TEST_P(ParseNameConstraints,
std::string constraints_der;
ASSERT_TRUE(LoadTestNameConstraint("dnsname-with_min_0_and_max.pem",
&constraints_der));
- EXPECT_FALSE(NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ EXPECT_FALSE(
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
}
TEST_P(ParseNameConstraints, FailsOnGeneralSubtreeWithMinimumAndMaximum) {
std::string constraints_der;
ASSERT_TRUE(LoadTestNameConstraint("dnsname-with_min_1_and_max.pem",
&constraints_der));
- EXPECT_FALSE(NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ EXPECT_FALSE(
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
}
TEST_P(ParseNameConstraints, FailsOnGeneralSubtreeWithMaximum) {
std::string constraints_der;
ASSERT_TRUE(LoadTestNameConstraint("dnsname-with_max.pem", &constraints_der));
- EXPECT_FALSE(NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ EXPECT_FALSE(
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
}
TEST_P(ParseNameConstraints, FailsOnEmptyExtensionValue) {
std::string constraints_der = "";
- EXPECT_FALSE(NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ EXPECT_FALSE(
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
}
TEST_P(ParseNameConstraints, FailsOnNoPermittedAndExcluded) {
std::string constraints_der;
ASSERT_TRUE(
LoadTestNameConstraint("invalid-no_subtrees.pem", &constraints_der));
- EXPECT_FALSE(NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ EXPECT_FALSE(
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
}
TEST_P(ParseNameConstraints, FailsOnEmptyPermitted) {
std::string constraints_der;
ASSERT_TRUE(LoadTestNameConstraint("invalid-empty_permitted_subtree.pem",
&constraints_der));
- EXPECT_FALSE(NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ EXPECT_FALSE(
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
}
TEST_P(ParseNameConstraints, FailsOnEmptyExcluded) {
std::string constraints_der;
ASSERT_TRUE(LoadTestNameConstraint("invalid-empty_excluded_subtree.pem",
&constraints_der));
- EXPECT_FALSE(NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ EXPECT_FALSE(
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
}
TEST_P(ParseNameConstraints, IsPermittedCertSubjectEmailAddressIsOk) {
std::string constraints_der;
ASSERT_TRUE(LoadTestNameConstraint("directoryname.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
std::string name_us_arizona_email;
@@ -1004,8 +992,7 @@ TEST_P(ParseNameConstraints, IsPermittedCertSubjectEmailAddressIsNotOk) {
ASSERT_TRUE(
LoadTestNameConstraint("rfc822name-permitted.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
std::string name_us_arizona_email;
@@ -1027,8 +1014,7 @@ TEST_P(ParseNameConstraints, IsPermittedCertSubjectDnsNames) {
ASSERT_TRUE(LoadTestNameConstraint("directoryname_and_dnsname.pem",
&constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
std::string name_us_az_foocom;
@@ -1069,8 +1055,7 @@ TEST_P(ParseNameConstraints, IsPermittedCertSubjectIpAddresses) {
ASSERT_TRUE(LoadTestNameConstraint(
"directoryname_and_dnsname_and_ipaddress.pem", &constraints_der));
std::unique_ptr<NameConstraints> name_constraints(
- NameConstraints::CreateFromDer(der::Input(&constraints_der),
- is_critical()));
+ NameConstraints::Create(der::Input(&constraints_der), is_critical()));
ASSERT_TRUE(name_constraints);
std::string name_us_az_1_1_1_1;
@@ -1112,20 +1097,19 @@ TEST_P(ParseNameConstraints, IsPermittedCertSubjectIpAddresses) {
nullptr /* subject_alt_names */));
}
-TEST_P(ParseNameConstraints,
- GeneralNamesCreateFromDerFailsOnEmptySubjectAltName) {
+TEST_P(ParseNameConstraints, GeneralNamesCreateFailsOnEmptySubjectAltName) {
std::string invalid_san_der;
ASSERT_TRUE(
LoadTestSubjectAltNameData("san-invalid-empty.pem", &invalid_san_der));
- EXPECT_FALSE(GeneralNames::CreateFromDer(der::Input(&invalid_san_der)));
+ EXPECT_FALSE(GeneralNames::Create(der::Input(&invalid_san_der)));
}
TEST_P(ParseNameConstraints,
- GeneralNamesCreateFromDerFailsOnInvalidIpInSubjectAltName) {
+ GeneralNamesCreateFailsOnInvalidIpInSubjectAltName) {
std::string invalid_san_der;
ASSERT_TRUE(LoadTestSubjectAltNameData("san-invalid-ipaddress.pem",
&invalid_san_der));
- EXPECT_FALSE(GeneralNames::CreateFromDer(der::Input(&invalid_san_der)));
+ EXPECT_FALSE(GeneralNames::Create(der::Input(&invalid_san_der)));
}
} // namespace net
diff --git a/chromium/net/cert/internal/nist_pkits_unittest.h b/chromium/net/cert/internal/nist_pkits_unittest.h
index aaf3992b645..47fd46274d6 100644
--- a/chromium/net/cert/internal/nist_pkits_unittest.h
+++ b/chromium/net/cert/internal/nist_pkits_unittest.h
@@ -5,9 +5,7 @@
#ifndef NET_CERT_INTERNAL_NIST_PKITS_UNITTEST_H
#define NET_CERT_INTERNAL_NIST_PKITS_UNITTEST_H
-#include "base/base_paths.h"
-#include "base/files/file_util.h"
-#include "base/path_service.h"
+#include "net/cert/internal/test_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"
// Parameterized test class for PKITS tests.
@@ -22,30 +20,14 @@ class PkitsTest : public ::testing::Test {
const char* const (&crl_names)[num_crls]) {
std::vector<std::string> cert_ders;
for (const std::string& s : cert_names)
- cert_ders.push_back(ReadTestFileToString("certs/" + s + ".crt"));
+ cert_ders.push_back(net::ReadTestFileToString(
+ "net/third_party/nist-pkits/certs/" + s + ".crt"));
std::vector<std::string> crl_ders;
for (const std::string& s : crl_names)
- crl_ders.push_back(ReadTestFileToString("crls/" + s + ".crl"));
+ crl_ders.push_back(net::ReadTestFileToString(
+ "net/third_party/nist-pkits/crls/" + s + ".crl"));
return PkitsTestDelegate::Verify(cert_ders, crl_ders);
}
-
- private:
- std::string ReadTestFileToString(const std::string& file_name) {
- // Compute the full path, relative to the src/ directory.
- base::FilePath src_root;
- PathService::Get(base::DIR_SOURCE_ROOT, &src_root);
- base::FilePath filepath = src_root.AppendASCII(
- std::string("net/third_party/nist-pkits/") + file_name);
-
- // Read the full contents of the file.
- std::string file_data;
- if (!base::ReadFileToString(filepath, &file_data)) {
- ADD_FAILURE() << "Couldn't read file: " << filepath.value();
- return std::string();
- }
-
- return file_data;
- }
};
// Inline the generated test code:
diff --git a/chromium/net/cert/internal/parse_certificate.cc b/chromium/net/cert/internal/parse_certificate.cc
index 644734cfebe..291e91c28bf 100644
--- a/chromium/net/cert/internal/parse_certificate.cc
+++ b/chromium/net/cert/internal/parse_certificate.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/strings/string_util.h"
+#include "net/cert/internal/cert_errors.h"
#include "net/der/input.h"
#include "net/der/parse_values.h"
#include "net/der/parser.h"
@@ -15,6 +16,23 @@ namespace net {
namespace {
+DEFINE_CERT_ERROR_ID(kCertificateNotSequence,
+ "Failed parsing Certificate SEQUENCE");
+DEFINE_CERT_ERROR_ID(kUnconsumedDataInsideCertificateSequence,
+ "Unconsumed data inside Certificate SEQUENCE");
+DEFINE_CERT_ERROR_ID(kUnconsumedDataAfterCertificateSequence,
+ "Unconsumed data after Certificate SEQUENCE");
+DEFINE_CERT_ERROR_ID(kTbsCertificateNotSequence,
+ "Couldn't read tbsCertificate as SEQUENCE");
+DEFINE_CERT_ERROR_ID(
+ kSignatureAlgorithmNotSequence,
+ "Couldn't read Certificate.signatureAlgorithm as SEQUENCE");
+DEFINE_CERT_ERROR_ID(kSignatureValueNotBitString,
+ "Couldn't read Certificate.signatureValue as BIT STRING");
+
+DEFINE_CERT_ERROR_ID(kUnconsumedDataInsideTbsCertificateSequence,
+ "Unconsumed data inside TBSCertificate");
+
// Returns true if |input| is a SEQUENCE and nothing else.
WARN_UNUSED_RESULT bool IsSequenceTLV(const der::Input& input) {
der::Parser parser(input);
@@ -170,34 +188,56 @@ bool VerifySerialNumber(const der::Input& value) {
bool ParseCertificate(const der::Input& certificate_tlv,
der::Input* out_tbs_certificate_tlv,
der::Input* out_signature_algorithm_tlv,
- der::BitString* out_signature_value) {
+ der::BitString* out_signature_value,
+ CertErrors* out_errors) {
+ // |out_errors| is optional. But ensure it is non-null for the remainder of
+ // this function.
+ if (!out_errors) {
+ CertErrors unused_errors;
+ return ParseCertificate(certificate_tlv, out_tbs_certificate_tlv,
+ out_signature_algorithm_tlv, out_signature_value,
+ &unused_errors);
+ }
+
der::Parser parser(certificate_tlv);
// Certificate ::= SEQUENCE {
der::Parser certificate_parser;
- if (!parser.ReadSequence(&certificate_parser))
+ if (!parser.ReadSequence(&certificate_parser)) {
+ out_errors->AddError(kCertificateNotSequence);
return false;
+ }
// tbsCertificate TBSCertificate,
- if (!ReadSequenceTLV(&certificate_parser, out_tbs_certificate_tlv))
+ if (!ReadSequenceTLV(&certificate_parser, out_tbs_certificate_tlv)) {
+ out_errors->AddError(kTbsCertificateNotSequence);
return false;
+ }
// signatureAlgorithm AlgorithmIdentifier,
- if (!ReadSequenceTLV(&certificate_parser, out_signature_algorithm_tlv))
+ if (!ReadSequenceTLV(&certificate_parser, out_signature_algorithm_tlv)) {
+ out_errors->AddError(kSignatureAlgorithmNotSequence);
return false;
+ }
// signatureValue BIT STRING }
- if (!certificate_parser.ReadBitString(out_signature_value))
+ if (!certificate_parser.ReadBitString(out_signature_value)) {
+ out_errors->AddError(kSignatureValueNotBitString);
return false;
+ }
// There isn't an extension point at the end of Certificate.
- if (certificate_parser.HasMore())
+ if (certificate_parser.HasMore()) {
+ out_errors->AddError(kUnconsumedDataInsideCertificateSequence);
return false;
+ }
// By definition the input was a single Certificate, so there shouldn't be
// unconsumed data.
- if (parser.HasMore())
+ if (parser.HasMore()) {
+ out_errors->AddError(kUnconsumedDataAfterCertificateSequence);
return false;
+ }
return true;
}
@@ -221,7 +261,16 @@ bool ParseCertificate(const der::Input& certificate_tlv,
// }
bool ParseTbsCertificate(const der::Input& tbs_tlv,
const ParseCertificateOptions& options,
- ParsedTbsCertificate* out) {
+ ParsedTbsCertificate* out,
+ CertErrors* errors) {
+ // The rest of this function assumes that |errors| is non-null.
+ if (!errors) {
+ CertErrors unused_errors;
+ return ParseTbsCertificate(tbs_tlv, options, out, &unused_errors);
+ }
+
+ // TODO(crbug.com/634443): Add useful error information to |errors|.
+
der::Parser parser(tbs_tlv);
// Certificate ::= SEQUENCE {
@@ -337,8 +386,10 @@ bool ParseTbsCertificate(const der::Input& tbs_tlv,
// However because only v1, v2, and v3 certificates are supported by the
// parsing, there shouldn't be any subsequent data in those versions, so
// reject.
- if (tbs_parser.HasMore())
+ if (tbs_parser.HasMore()) {
+ errors->AddError(kUnconsumedDataInsideTbsCertificateSequence);
return false;
+ }
// By definition the input was a single TBSCertificate, so there shouldn't be
// unconsumed data.
diff --git a/chromium/net/cert/internal/parse_certificate.h b/chromium/net/cert/internal/parse_certificate.h
index 13409dc3be5..a164682eb49 100644
--- a/chromium/net/cert/internal/parse_certificate.h
+++ b/chromium/net/cert/internal/parse_certificate.h
@@ -17,6 +17,7 @@
namespace net {
+class CertErrors;
struct ParsedTbsCertificate;
// Returns true if the given serial number (CertificateSerialNumber in RFC 5280)
@@ -55,14 +56,17 @@ struct NET_EXPORT ParseCertificateOptions {
};
// Parses a DER-encoded "Certificate" as specified by RFC 5280. Returns true on
-// success and sets the results in the |out_*| parameters.
+// success and sets the results in the |out_*| parameters. On both the failure
+// and success case, if |out_errors| was non-null it may contain extra error
+// information.
//
// Note that on success the out parameters alias data from the input
// |certificate_tlv|. Hence the output values are only valid as long as
// |certificate_tlv| remains valid.
//
-// On failure the out parameters have an undefined state. Some of them may have
-// been updated during parsing, whereas others may not have been changed.
+// On failure the out parameters have an undefined state, except for
+// out_errors. Some of them may have been updated during parsing, whereas
+// others may not have been changed.
//
// The out parameters represent each field of the Certificate SEQUENCE:
// Certificate ::= SEQUENCE {
@@ -81,7 +85,7 @@ struct NET_EXPORT ParseCertificateOptions {
//
// This contains the full (unverified) Tag-Length-Value for a SEQUENCE. No
// guarantees are made regarding the value of this SEQUENCE.
-// This can be further parsed using SignatureValue::CreateFromDer().
+// This can be further parsed using SignatureValue::Create().
//
// The |out_signature_value| parameter corresponds with "signatureValue" from
// RFC 5280:
@@ -91,13 +95,16 @@ struct NET_EXPORT ParseCertificateOptions {
NET_EXPORT bool ParseCertificate(const der::Input& certificate_tlv,
der::Input* out_tbs_certificate_tlv,
der::Input* out_signature_algorithm_tlv,
- der::BitString* out_signature_value)
- WARN_UNUSED_RESULT;
+ der::BitString* out_signature_value,
+ CertErrors* out_errors) WARN_UNUSED_RESULT;
// Parses a DER-encoded "TBSCertificate" as specified by RFC 5280. Returns true
// on success and sets the results in |out|. Certain invalid inputs may
// be accepted based on the provided |options|.
//
+// If |errors| was non-null then any warnings/errors that occur during parsing
+// are added to it.
+//
// Note that on success |out| aliases data from the input |tbs_tlv|.
// Hence the fields of the ParsedTbsCertificate are only valid as long as
// |tbs_tlv| remains valid.
@@ -125,8 +132,8 @@ NET_EXPORT bool ParseCertificate(const der::Input& certificate_tlv,
// }
NET_EXPORT bool ParseTbsCertificate(const der::Input& tbs_tlv,
const ParseCertificateOptions& options,
- ParsedTbsCertificate* out)
- WARN_UNUSED_RESULT;
+ ParsedTbsCertificate* out,
+ CertErrors* errors) WARN_UNUSED_RESULT;
// Represents a "Version" from RFC 5280:
// Version ::= INTEGER { v1(0), v2(1), v3(2) }
@@ -176,7 +183,7 @@ struct NET_EXPORT ParsedTbsCertificate {
// This contains the full (unverified) Tag-Length-Value for a SEQUENCE. No
// guarantees are made regarding the value of this SEQUENCE.
//
- // This can be further parsed using SignatureValue::CreateFromDer().
+ // This can be further parsed using SignatureValue::Create().
der::Input signature_algorithm_tlv;
// Corresponds with "issuer" from RFC 5280:
diff --git a/chromium/net/cert/internal/parse_certificate_fuzzer.cc b/chromium/net/cert/internal/parse_certificate_fuzzer.cc
index 5efcd6fc20e..67ea6986e54 100644
--- a/chromium/net/cert/internal/parse_certificate_fuzzer.cc
+++ b/chromium/net/cert/internal/parse_certificate_fuzzer.cc
@@ -6,75 +6,14 @@
#include <stdint.h>
#include "base/macros.h"
-#include "net/cert/internal/certificate_policies.h"
-#include "net/cert/internal/extended_key_usage.h"
-#include "net/cert/internal/name_constraints.h"
-#include "net/cert/internal/parse_certificate.h"
-#include "net/cert/internal/parse_name.h"
-#include "net/cert/internal/signature_algorithm.h"
-#include "net/cert/internal/signature_policy.h"
-#include "net/cert/internal/verify_signed_data.h"
-
-namespace net {
-namespace {
-
-bool FindExtension(const der::Input& oid,
- std::map<der::Input, ParsedExtension>* extensions,
- ParsedExtension* extension) {
- auto it = extensions->find(oid);
- if (it == extensions->end())
- return false;
- *extension = it->second;
- return true;
-}
-
-void ParseCertificateForFuzzer(const der::Input& in) {
- der::Input tbs_certificate_tlv;
- der::Input signature_algorithm_tlv;
- der::BitString signature_value;
- if (!ParseCertificate(in, &tbs_certificate_tlv, &signature_algorithm_tlv,
- &signature_value))
- return;
- std::unique_ptr<SignatureAlgorithm> sig_alg(
- SignatureAlgorithm::CreateFromDer(signature_algorithm_tlv));
-
- ParsedTbsCertificate tbs;
- if (!ParseTbsCertificate(tbs_certificate_tlv, {}, &tbs))
- return;
-
- RDNSequence subject;
- ignore_result(ParseName(tbs.subject_tlv, &subject));
-
- std::map<der::Input, ParsedExtension> extensions;
- if (tbs.has_extensions && ParseExtensions(tbs.extensions_tlv, &extensions)) {
- ParsedExtension extension;
- ParsedBasicConstraints basic_constraints;
- der::BitString key_usage;
- std::vector<der::Input> policies;
- std::vector<der::Input> eku_oids;
- std::vector<base::StringPiece> ca_issuers_uris;
- std::vector<base::StringPiece> ocsp_uris;
- if (FindExtension(BasicConstraintsOid(), &extensions, &extension))
- ignore_result(ParseBasicConstraints(extension.value, &basic_constraints));
- if (FindExtension(KeyUsageOid(), &extensions, &extension))
- ignore_result(ParseKeyUsage(extension.value, &key_usage));
- if (FindExtension(SubjectAltNameOid(), &extensions, &extension))
- GeneralNames::CreateFromDer(extension.value);
- if (FindExtension(CertificatePoliciesOid(), &extensions, &extension))
- ParseCertificatePoliciesExtension(extension.value, &policies);
- if (FindExtension(ExtKeyUsageOid(), &extensions, &extension))
- ParseEKUExtension(extension.value, &eku_oids);
- if (FindExtension(AuthorityInfoAccessOid(), &extensions, &extension))
- ignore_result(ParseAuthorityInfoAccess(extension.value, &ca_issuers_uris,
- &ocsp_uris));
- }
-}
-
-} // namespace
-} // namespace net
+#include "net/cert/internal/cert_errors.h"
+#include "net/cert/internal/parsed_certificate.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- net::der::Input in(data, size);
- net::ParseCertificateForFuzzer(in);
+ net::CertErrors errors;
+ scoped_refptr<net::ParsedCertificate> cert =
+ net::ParsedCertificate::Create(data, size, {}, &errors);
+
+ // TODO(crbug.com/634443): Ensure that !errors.empty() on parsing failure.
return 0;
}
diff --git a/chromium/net/cert/internal/parse_certificate_unittest.cc b/chromium/net/cert/internal/parse_certificate_unittest.cc
index 474ab6d2a4b..08c37944cea 100644
--- a/chromium/net/cert/internal/parse_certificate_unittest.cc
+++ b/chromium/net/cert/internal/parse_certificate_unittest.cc
@@ -5,6 +5,11 @@
#include "net/cert/internal/parse_certificate.h"
#include "base/strings/stringprintf.h"
+#include "net/cert/internal/cert_errors.h"
+// TODO(eroman): These tests should be moved into
+// parsed_certificate_unittest.cc; this include dependency should
+// go.
+#include "net/cert/internal/parsed_certificate.h"
#include "net/cert/internal/test_helpers.h"
#include "net/der/input.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -27,10 +32,12 @@ std::string GetFilePath(const std::string& file_name) {
}
// Loads certificate data and expectations from the PEM file |file_name|.
-// Verifies that parsing the Certificate succeeds, and each parsed field matches
-// the expectations.
-void EnsureParsingCertificateSucceeds(const std::string& file_name) {
+// Verifies that parsing the Certificate matches expectations:
+// * If expected to fail, emits the expected errors
+// * If expected to succeeds, the parsed fields match expectations
+void RunCertificateTest(const std::string& file_name) {
std::string data;
+ std::string expected_errors;
std::string expected_tbs_certificate;
std::string expected_signature_algorithm;
std::string expected_signature;
@@ -38,94 +45,123 @@ void EnsureParsingCertificateSucceeds(const std::string& file_name) {
// Read the certificate data and test expectations from a single PEM file.
const PemBlockMapping mappings[] = {
{"CERTIFICATE", &data},
- {"SIGNATURE", &expected_signature},
- {"SIGNATURE ALGORITHM", &expected_signature_algorithm},
- {"TBS CERTIFICATE", &expected_tbs_certificate},
+ {"ERRORS", &expected_errors, true /*optional*/},
+ {"SIGNATURE", &expected_signature, true /*optional*/},
+ {"SIGNATURE ALGORITHM", &expected_signature_algorithm, true /*optional*/},
+ {"TBS CERTIFICATE", &expected_tbs_certificate, true /*optional*/},
};
- ASSERT_TRUE(ReadTestDataFromPemFile(GetFilePath(file_name), mappings));
+ std::string test_file_path = GetFilePath(file_name);
+ ASSERT_TRUE(ReadTestDataFromPemFile(test_file_path, mappings));
- // Parsing the certificate should succeed.
+ // Note that empty expected_errors doesn't necessarily mean success.
+ bool expected_result = !expected_tbs_certificate.empty();
+
+ // Parsing the certificate.
der::Input tbs_certificate_tlv;
der::Input signature_algorithm_tlv;
der::BitString signature_value;
- ASSERT_TRUE(ParseCertificate(der::Input(&data), &tbs_certificate_tlv,
- &signature_algorithm_tlv, &signature_value));
+ CertErrors errors;
+ bool actual_result =
+ ParseCertificate(der::Input(&data), &tbs_certificate_tlv,
+ &signature_algorithm_tlv, &signature_value, &errors);
+
+ EXPECT_EQ(expected_result, actual_result);
+ EXPECT_EQ(expected_errors, errors.ToDebugString()) << "Test file: "
+ << test_file_path;
// Ensure that the parsed certificate matches expectations.
- EXPECT_EQ(0, signature_value.unused_bits());
- EXPECT_EQ(der::Input(&expected_signature), signature_value.bytes());
- EXPECT_EQ(der::Input(&expected_signature_algorithm), signature_algorithm_tlv);
- EXPECT_EQ(der::Input(&expected_tbs_certificate), tbs_certificate_tlv);
+ if (expected_result && actual_result) {
+ EXPECT_EQ(0, signature_value.unused_bits());
+ EXPECT_EQ(der::Input(&expected_signature), signature_value.bytes());
+ EXPECT_EQ(der::Input(&expected_signature_algorithm),
+ signature_algorithm_tlv);
+ EXPECT_EQ(der::Input(&expected_tbs_certificate), tbs_certificate_tlv);
+ }
}
-// Loads certificate data from the PEM file |file_name| and verifies that the
-// Certificate parsing fails.
-void EnsureParsingCertificateFails(const std::string& file_name) {
+// Reads and parses a certificate from the PEM file |file_name|.
+//
+// Returns nullptr if the certificate parsing failed, and verifies that any
+// errors match the ERRORS block in the .pem file.
+scoped_refptr<ParsedCertificate> ParseCertificateFromFile(
+ const std::string& file_name) {
std::string data;
+ std::string expected_errors;
+ // Read the certificate data and error expectations from a single PEM file.
const PemBlockMapping mappings[] = {
- {"CERTIFICATE", &data},
+ {"CERTIFICATE", &data}, {"ERRORS", &expected_errors, true /*optional*/},
};
+ std::string test_file_path = GetFilePath(file_name);
+ EXPECT_TRUE(ReadTestDataFromPemFile(test_file_path, mappings));
- ASSERT_TRUE(ReadTestDataFromPemFile(GetFilePath(file_name), mappings));
+ CertErrors errors;
+ scoped_refptr<ParsedCertificate> cert =
+ ParsedCertificate::Create(data, {}, &errors);
- // Parsing the Certificate should fail.
- der::Input tbs_certificate_tlv;
- der::Input signature_algorithm_tlv;
- der::BitString signature_value;
- ASSERT_FALSE(ParseCertificate(der::Input(&data), &tbs_certificate_tlv,
- &signature_algorithm_tlv, &signature_value));
+ EXPECT_EQ(expected_errors, errors.ToDebugString()) << "Test file: "
+ << test_file_path;
+
+ // TODO(crbug.com/634443): Every parse failure being tested should emit error
+ // information.
+ // if (!cert)
+ // EXPECT_FALSE(errors.empty());
+
+ return cert;
}
// Tests parsing a Certificate.
TEST(ParseCertificateTest, Version3) {
- EnsureParsingCertificateSucceeds("cert_version3.pem");
+ RunCertificateTest("cert_version3.pem");
}
// Tests parsing a simplified Certificate-like structure (the sub-fields for
// algorithm and tbsCertificate are not actually valid, but ParseCertificate()
// doesn't check them)
TEST(ParseCertificateTest, Skeleton) {
- EnsureParsingCertificateSucceeds("cert_skeleton.pem");
+ RunCertificateTest("cert_skeleton.pem");
}
// Tests parsing a Certificate that is not a sequence fails.
TEST(ParseCertificateTest, NotSequence) {
- EnsureParsingCertificateFails("cert_not_sequence.pem");
+ RunCertificateTest("cert_not_sequence.pem");
}
// Tests that uncomsumed data is not allowed after the main SEQUENCE.
TEST(ParseCertificateTest, DataAfterSignature) {
- EnsureParsingCertificateFails("cert_data_after_signature.pem");
+ RunCertificateTest("cert_data_after_signature.pem");
}
// Tests that parsing fails if the signature BIT STRING is missing.
TEST(ParseCertificateTest, MissingSignature) {
- EnsureParsingCertificateFails("cert_missing_signature.pem");
+ RunCertificateTest("cert_missing_signature.pem");
}
// Tests that parsing fails if the signature is present but not a BIT STRING.
TEST(ParseCertificateTest, SignatureNotBitString) {
- EnsureParsingCertificateFails("cert_signature_not_bit_string.pem");
+ RunCertificateTest("cert_signature_not_bit_string.pem");
}
// Tests that parsing fails if the main SEQUENCE is empty (missing all the
// fields).
TEST(ParseCertificateTest, EmptySequence) {
- EnsureParsingCertificateFails("cert_empty_sequence.pem");
+ RunCertificateTest("cert_empty_sequence.pem");
}
// Tests what happens when the signature algorithm is present, but has the wrong
// tag.
TEST(ParseCertificateTest, AlgorithmNotSequence) {
- EnsureParsingCertificateFails("cert_algorithm_not_sequence.pem");
+ RunCertificateTest("cert_algorithm_not_sequence.pem");
}
// Loads tbsCertificate data and expectations from the PEM file |file_name|.
// Verifies that parsing the TBSCertificate succeeds, and each parsed field
// matches the expectations.
-void EnsureParsingTbsSucceeds(const std::string& file_name,
- CertificateVersion expected_version) {
+//
+// TODO(eroman): Get rid of the |expected_version| parameter -- this should be
+// encoded in the test expectations file.
+void RunTbsCertificateTestGivenVersion(const std::string& file_name,
+ CertificateVersion expected_version) {
std::string data;
std::string expected_serial_number;
std::string expected_signature_algorithm;
@@ -137,26 +173,39 @@ void EnsureParsingTbsSucceeds(const std::string& file_name,
std::string expected_issuer_unique_id;
std::string expected_subject_unique_id;
std::string expected_extensions;
+ std::string expected_errors;
// Read the certificate data and test expectations from a single PEM file.
const PemBlockMapping mappings[] = {
{"TBS CERTIFICATE", &data},
- {"SIGNATURE ALGORITHM", &expected_signature_algorithm},
- {"SERIAL NUMBER", &expected_serial_number},
- {"ISSUER", &expected_issuer},
- {"VALIDITY NOTBEFORE", &expected_validity_not_before},
- {"VALIDITY NOTAFTER", &expected_validity_not_after},
- {"SUBJECT", &expected_subject},
- {"SPKI", &expected_spki},
+ {"SIGNATURE ALGORITHM", &expected_signature_algorithm, true},
+ {"SERIAL NUMBER", &expected_serial_number, true},
+ {"ISSUER", &expected_issuer, true},
+ {"VALIDITY NOTBEFORE", &expected_validity_not_before, true},
+ {"VALIDITY NOTAFTER", &expected_validity_not_after, true},
+ {"SUBJECT", &expected_subject, true},
+ {"SPKI", &expected_spki, true},
{"ISSUER UNIQUE ID", &expected_issuer_unique_id, true},
{"SUBJECT UNIQUE ID", &expected_subject_unique_id, true},
{"EXTENSIONS", &expected_extensions, true},
+ {"ERRORS", &expected_errors, true},
};
- ASSERT_TRUE(ReadTestDataFromPemFile(GetFilePath(file_name), mappings));
+ std::string test_file_path = GetFilePath(file_name);
+ ASSERT_TRUE(ReadTestDataFromPemFile(test_file_path, mappings));
+
+ bool expected_result = !expected_spki.empty();
- // Parsing the TBSCertificate should succeed.
ParsedTbsCertificate parsed;
- ASSERT_TRUE(ParseTbsCertificate(der::Input(&data), {}, &parsed));
+ CertErrors errors;
+ bool actual_result =
+ ParseTbsCertificate(der::Input(&data), {}, &parsed, &errors);
+
+ EXPECT_EQ(expected_result, actual_result);
+ EXPECT_EQ(expected_errors, errors.ToDebugString()) << "Test file: "
+ << test_file_path;
+
+ if (!expected_result || !actual_result)
+ return;
// Ensure that the ParsedTbsCertificate matches expectations.
EXPECT_EQ(expected_version, parsed.version);
@@ -186,30 +235,18 @@ void EnsureParsingTbsSucceeds(const std::string& file_name,
EXPECT_EQ(!expected_extensions.empty(), parsed.has_extensions);
}
-// Loads certificate data from the PEM file |file_name| and verifies that the
-// Certificate parsing succeed, however the TBSCertificate parsing fails.
-void EnsureParsingTbsFails(const std::string& file_name) {
- std::string data;
-
- const PemBlockMapping mappings[] = {
- {"TBS CERTIFICATE", &data},
- };
-
- ASSERT_TRUE(ReadTestDataFromPemFile(GetFilePath(file_name), mappings));
-
- // Parsing the TBSCertificate should fail.
- ParsedTbsCertificate parsed;
- ASSERT_FALSE(ParseTbsCertificate(der::Input(&data), {}, &parsed));
+void RunTbsCertificateTest(const std::string& file_name) {
+ RunTbsCertificateTestGivenVersion(file_name, CertificateVersion::V3);
}
// Tests parsing a TBSCertificate for v3 that contains no optional fields.
TEST(ParseTbsCertificateTest, Version3NoOptionals) {
- EnsureParsingTbsSucceeds("tbs_v3_no_optionals.pem", CertificateVersion::V3);
+ RunTbsCertificateTest("tbs_v3_no_optionals.pem");
}
// Tests parsing a TBSCertificate for v3 that contains extensions.
TEST(ParseTbsCertificateTest, Version3WithExtensions) {
- EnsureParsingTbsSucceeds("tbs_v3_extensions.pem", CertificateVersion::V3);
+ RunTbsCertificateTest("tbs_v3_extensions.pem");
}
// Tests parsing a TBSCertificate for v3 that contains no optional fields, and
@@ -218,293 +255,197 @@ TEST(ParseTbsCertificateTest, Version3WithExtensions) {
// CAs are not supposed to include negative serial numbers, however RFC 5280
// expects consumers to deal with it anyway).
TEST(ParseTbsCertificateTest, NegativeSerialNumber) {
- EnsureParsingTbsSucceeds("tbs_negative_serial_number.pem",
- CertificateVersion::V3);
+ RunTbsCertificateTest("tbs_negative_serial_number.pem");
}
// Tests parsing a TBSCertificate with a serial number that is 21 octets long
// (and the first byte is 0).
TEST(ParseTbCertificateTest, SerialNumber21OctetsLeading0) {
- EnsureParsingTbsFails("tbs_serial_number_21_octets_leading_0.pem");
+ RunTbsCertificateTest("tbs_serial_number_21_octets_leading_0.pem");
}
// Tests parsing a TBSCertificate with a serial number that is 26 octets long
// (and does not contain a leading 0).
TEST(ParseTbsCertificateTest, SerialNumber26Octets) {
- EnsureParsingTbsFails("tbs_serial_number_26_octets.pem");
+ RunTbsCertificateTest("tbs_serial_number_26_octets.pem");
}
// Tests parsing a TBSCertificate which lacks a version number (causing it to
// default to v1).
TEST(ParseTbsCertificateTest, Version1) {
- EnsureParsingTbsSucceeds("tbs_v1.pem", CertificateVersion::V1);
+ RunTbsCertificateTestGivenVersion("tbs_v1.pem", CertificateVersion::V1);
}
// The version was set to v1 explicitly rather than omitting the version field.
TEST(ParseTbsCertificateTest, ExplicitVersion1) {
- EnsureParsingTbsFails("tbs_explicit_v1.pem");
+ RunTbsCertificateTest("tbs_explicit_v1.pem");
}
// Extensions are not defined in version 1.
TEST(ParseTbsCertificateTest, Version1WithExtensions) {
- EnsureParsingTbsFails("tbs_v1_extensions.pem");
+ RunTbsCertificateTest("tbs_v1_extensions.pem");
}
// Extensions are not defined in version 2.
TEST(ParseTbsCertificateTest, Version2WithExtensions) {
- EnsureParsingTbsFails("tbs_v2_extensions.pem");
+ RunTbsCertificateTest("tbs_v2_extensions.pem");
}
// A boring version 2 certificate with none of the optional fields.
TEST(ParseTbsCertificateTest, Version2NoOptionals) {
- EnsureParsingTbsSucceeds("tbs_v2_no_optionals.pem", CertificateVersion::V2);
+ RunTbsCertificateTestGivenVersion("tbs_v2_no_optionals.pem",
+ CertificateVersion::V2);
}
// A version 2 certificate with an issuer unique ID field.
TEST(ParseTbsCertificateTest, Version2IssuerUniqueId) {
- EnsureParsingTbsSucceeds("tbs_v2_issuer_unique_id.pem",
- CertificateVersion::V2);
+ RunTbsCertificateTestGivenVersion("tbs_v2_issuer_unique_id.pem",
+ CertificateVersion::V2);
}
// A version 2 certificate with both a issuer and subject unique ID field.
TEST(ParseTbsCertificateTest, Version2IssuerAndSubjectUniqueId) {
- EnsureParsingTbsSucceeds("tbs_v2_issuer_and_subject_unique_id.pem",
- CertificateVersion::V2);
+ RunTbsCertificateTestGivenVersion("tbs_v2_issuer_and_subject_unique_id.pem",
+ CertificateVersion::V2);
}
// A version 3 certificate with all of the optional fields (issuer unique id,
// subject unique id, and extensions).
TEST(ParseTbsCertificateTest, Version3AllOptionals) {
- EnsureParsingTbsSucceeds("tbs_v3_all_optionals.pem", CertificateVersion::V3);
+ RunTbsCertificateTest("tbs_v3_all_optionals.pem");
}
// The version was set to v4, which is unrecognized.
TEST(ParseTbsCertificateTest, Version4) {
- EnsureParsingTbsFails("tbs_v4.pem");
+ RunTbsCertificateTest("tbs_v4.pem");
}
// Tests that extraneous data after extensions in a v3 is rejected.
TEST(ParseTbsCertificateTest, Version3DataAfterExtensions) {
- EnsureParsingTbsFails("tbs_v3_data_after_extensions.pem");
+ RunTbsCertificateTest("tbs_v3_data_after_extensions.pem");
}
// Tests using a real-world certificate (whereas the other tests are fabricated
// (and in fact invalid) data.
TEST(ParseTbsCertificateTest, Version3Real) {
- EnsureParsingTbsSucceeds("tbs_v3_real.pem", CertificateVersion::V3);
+ RunTbsCertificateTest("tbs_v3_real.pem");
}
// Parses a TBSCertificate whose "validity" field expresses both notBefore
// and notAfter using UTCTime.
TEST(ParseTbsCertificateTest, ValidityBothUtcTime) {
- EnsureParsingTbsSucceeds("tbs_validity_both_utc_time.pem",
- CertificateVersion::V3);
+ RunTbsCertificateTest("tbs_validity_both_utc_time.pem");
}
// Parses a TBSCertificate whose "validity" field expresses both notBefore
// and notAfter using GeneralizedTime.
TEST(ParseTbsCertificateTest, ValidityBothGeneralizedTime) {
- EnsureParsingTbsSucceeds("tbs_validity_both_generalized_time.pem",
- CertificateVersion::V3);
+ RunTbsCertificateTest("tbs_validity_both_generalized_time.pem");
}
// Parses a TBSCertificate whose "validity" field expresses notBefore using
// UTCTime and notAfter using GeneralizedTime.
TEST(ParseTbsCertificateTest, ValidityUTCTimeAndGeneralizedTime) {
- EnsureParsingTbsSucceeds("tbs_validity_utc_time_and_generalized_time.pem",
- CertificateVersion::V3);
+ RunTbsCertificateTest("tbs_validity_utc_time_and_generalized_time.pem");
}
// Parses a TBSCertificate whose validity" field expresses notBefore using
// GeneralizedTime and notAfter using UTCTime. Also of interest, notBefore >
// notAfter. Parsing will succeed, however no time can satisfy this constraint.
TEST(ParseTbsCertificateTest, ValidityGeneralizedTimeAndUTCTime) {
- EnsureParsingTbsSucceeds("tbs_validity_generalized_time_and_utc_time.pem",
- CertificateVersion::V3);
+ RunTbsCertificateTest("tbs_validity_generalized_time_and_utc_time.pem");
}
// Parses a TBSCertificate whose "validity" field does not strictly follow
// the DER rules (and fails to be parsed).
TEST(ParseTbsCertificateTest, ValidityRelaxed) {
- EnsureParsingTbsFails("tbs_validity_relaxed.pem");
+ RunTbsCertificateTest("tbs_validity_relaxed.pem");
}
-// Reads a PEM file containing a block "EXTENSION". This input will be
-// passed to ParseExtension, and the results filled in |out|.
-bool ParseExtensionFromFile(const std::string& file_name,
- ParsedExtension* out,
- std::string* data) {
- const PemBlockMapping mappings[] = {
- {"EXTENSION", data},
- };
-
- EXPECT_TRUE(ReadTestDataFromPemFile(GetFilePath(file_name), mappings));
- return ParseExtension(der::Input(data), out);
+der::Input DavidBenOid() {
+ // This OID corresponds with
+ // 1.2.840.113554.4.1.72585.0 (https://davidben.net/oid)
+ static const uint8_t kOid[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12,
+ 0x04, 0x01, 0x84, 0xb7, 0x09, 0x00};
+ return der::Input(kOid);
}
// Parses an Extension whose critical field is true (255).
-TEST(ParseExtensionTest, Critical) {
- std::string data;
- ParsedExtension extension;
- ASSERT_TRUE(
- ParseExtensionFromFile("extension_critical.pem", &extension, &data));
+TEST(ParseCertificateTest, ExtensionCritical) {
+ scoped_refptr<ParsedCertificate> cert =
+ ParseCertificateFromFile("extension_critical.pem");
+ ASSERT_TRUE(cert);
- EXPECT_TRUE(extension.critical);
+ const uint8_t kExpectedValue[] = {0x30, 0x00};
- const uint8_t kExpectedOid[] = {0x55, 0x1d, 0x13};
- EXPECT_EQ(der::Input(kExpectedOid), extension.oid);
+ auto it = cert->unparsed_extensions().find(DavidBenOid());
+ ASSERT_NE(cert->unparsed_extensions().end(), it);
+ const auto& extension = it->second;
- const uint8_t kExpectedValue[] = {0x30, 0x00};
+ EXPECT_TRUE(extension.critical);
+ EXPECT_EQ(DavidBenOid(), extension.oid);
EXPECT_EQ(der::Input(kExpectedValue), extension.value);
}
// Parses an Extension whose critical field is false (omitted).
-TEST(ParseExtensionTest, NotCritical) {
- std::string data;
- ParsedExtension extension;
- ASSERT_TRUE(
- ParseExtensionFromFile("extension_not_critical.pem", &extension, &data));
+TEST(ParseCertificateTest, ExtensionNotCritical) {
+ scoped_refptr<ParsedCertificate> cert =
+ ParseCertificateFromFile("extension_not_critical.pem");
+ ASSERT_TRUE(cert);
- EXPECT_FALSE(extension.critical);
+ const uint8_t kExpectedValue[] = {0x30, 0x00};
- const uint8_t kExpectedOid[] = {0x55, 0x1d, 0x13};
- EXPECT_EQ(der::Input(kExpectedOid), extension.oid);
+ auto it = cert->unparsed_extensions().find(DavidBenOid());
+ ASSERT_NE(cert->unparsed_extensions().end(), it);
+ const auto& extension = it->second;
- const uint8_t kExpectedValue[] = {0x30, 0x00};
+ EXPECT_FALSE(extension.critical);
+ EXPECT_EQ(DavidBenOid(), extension.oid);
EXPECT_EQ(der::Input(kExpectedValue), extension.value);
}
// Parses an Extension whose critical field is 0. This is in one sense FALSE,
// however because critical has DEFAULT of false this is in fact invalid
// DER-encoding.
-TEST(ParseExtensionTest, Critical0) {
- std::string data;
- ParsedExtension extension;
- ASSERT_FALSE(
- ParseExtensionFromFile("extension_critical_0.pem", &extension, &data));
+TEST(ParseCertificateTest, ExtensionCritical0) {
+ ASSERT_FALSE(ParseCertificateFromFile("extension_critical_0.pem"));
}
// Parses an Extension whose critical field is 3. Under DER-encoding BOOLEAN
// values must an octet of either all zero bits, or all 1 bits, so this is not
// valid.
-TEST(ParseExtensionTest, Critical3) {
- std::string data;
- ParsedExtension extension;
- ASSERT_FALSE(
- ParseExtensionFromFile("extension_critical_3.pem", &extension, &data));
-}
-
-// Runs a test for extensions parsing. The input file is a PEM file which
-// contains a DER-encoded Extensions sequence, as well as the expected value
-// for each contained extension.
-void EnsureParsingExtensionsSucceeds(
- const std::string& file_name,
- std::map<der::Input, ParsedExtension>* extensions,
- std::string* data) {
- const PemBlockMapping mappings[] = {
- // Test Input.
- {"EXTENSIONS", data},
- };
-
- ASSERT_TRUE(ReadTestDataFromPemFile(GetFilePath(file_name), mappings));
- ASSERT_TRUE(ParseExtensions(der::Input(data), extensions));
-}
-
-// Runs a test that verifies extensions parsing fails. The input file is a PEM
-// file which contains a DER-encoded Extensions sequence.
-void EnsureParsingExtensionsFails(const std::string& file_name) {
- std::string data;
-
- const PemBlockMapping mappings[] = {
- {"EXTENSIONS", &data},
- };
-
- std::map<der::Input, ParsedExtension> extensions;
- ASSERT_TRUE(ReadTestDataFromPemFile(GetFilePath(file_name), mappings));
- ASSERT_FALSE(ParseExtensions(der::Input(&data), &extensions));
+TEST(ParseCertificateTest, ExtensionCritical3) {
+ ASSERT_FALSE(ParseCertificateFromFile("extension_critical_3.pem"));
}
// Parses an Extensions that is an empty sequence.
-TEST(ParseExtensionsTest, EmptySequence) {
- EnsureParsingExtensionsFails("extensions_empty_sequence.pem");
+TEST(ParseCertificateTest, ExtensionsEmptySequence) {
+ ASSERT_FALSE(ParseCertificateFromFile("extensions_empty_sequence.pem"));
}
// Parses an Extensions that is not a sequence.
-TEST(ParseExtensionsTest, NotSequence) {
- EnsureParsingExtensionsFails("extensions_not_sequence.pem");
+TEST(ParseCertificateTest, ExtensionsNotSequence) {
+ ASSERT_FALSE(ParseCertificateFromFile("extensions_not_sequence.pem"));
}
// Parses an Extensions that has data after the sequence.
-TEST(ParseExtensionsTest, DataAfterSequence) {
- EnsureParsingExtensionsFails("extensions_data_after_sequence.pem");
+TEST(ParseCertificateTest, ExtensionsDataAfterSequence) {
+ ASSERT_FALSE(ParseCertificateFromFile("extensions_data_after_sequence.pem"));
}
// Parses an Extensions that contains duplicated key usages.
-TEST(ParseExtensionsTest, DuplicateKeyUsage) {
- EnsureParsingExtensionsFails("extensions_duplicate_key_usage.pem");
-}
-
-// Parses an Extensions that contains an unknown critical extension.
-TEST(ParseExtensionsTest, UnknownCritical) {
- std::string data;
- std::map<der::Input, ParsedExtension> extensions;
- EnsureParsingExtensionsSucceeds("extensions_unknown_critical.pem",
- &extensions, &data);
-
- ASSERT_EQ(1u, extensions.size());
- // This OID corresponds with
- // 1.2.840.113554.4.1.72585.0 (https://davidben.net/oid)
- const uint8_t oid[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12,
- 0x04, 0x01, 0x84, 0xb7, 0x09, 0x00};
-
- auto iter = extensions.find(der::Input(oid));
- ASSERT_TRUE(iter != extensions.end());
- EXPECT_TRUE(iter->second.critical);
- EXPECT_EQ(4u, iter->second.value.Length());
-}
-
-// Parses an Extensions that contains an unknown non-critical extension.
-TEST(ParseExtensionsTest, UnknownNonCritical) {
- std::string data;
- std::map<der::Input, ParsedExtension> extensions;
- EnsureParsingExtensionsSucceeds("extensions_unknown_non_critical.pem",
- &extensions, &data);
-
- ASSERT_EQ(1u, extensions.size());
- // This OID corresponds with
- // 1.2.840.113554.4.1.72585.0 (https://davidben.net/oid)
- const uint8_t oid[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12,
- 0x04, 0x01, 0x84, 0xb7, 0x09, 0x00};
-
- auto iter = extensions.find(der::Input(oid));
- ASSERT_TRUE(iter != extensions.end());
- EXPECT_FALSE(iter->second.critical);
- EXPECT_EQ(4u, iter->second.value.Length());
-}
-
-// Parses an Extensions that contains a basic constraints.
-TEST(ParseExtensionsTest, BasicConstraints) {
- std::string data;
- std::map<der::Input, ParsedExtension> extensions;
- EnsureParsingExtensionsSucceeds("extensions_basic_constraints.pem",
- &extensions, &data);
-
- ASSERT_EQ(1u, extensions.size());
-
- auto iter = extensions.find(BasicConstraintsOid());
- ASSERT_TRUE(iter != extensions.end());
- EXPECT_TRUE(iter->second.critical);
- EXPECT_EQ(2u, iter->second.value.Length());
+TEST(ParseCertificateTest, ExtensionsDuplicateKeyUsage) {
+ ASSERT_FALSE(ParseCertificateFromFile("extensions_duplicate_key_usage.pem"));
}
// Parses an Extensions that contains an extended key usages.
-TEST(ParseExtensionsTest, ExtendedKeyUsage) {
- std::string data;
- std::map<der::Input, ParsedExtension> extensions;
- EnsureParsingExtensionsSucceeds("extensions_extended_key_usage.pem",
- &extensions, &data);
+TEST(ParseCertificateTest, ExtendedKeyUsage) {
+ scoped_refptr<ParsedCertificate> cert =
+ ParseCertificateFromFile("extended_key_usage.pem");
+ ASSERT_TRUE(cert);
- ASSERT_EQ(1u, extensions.size());
+ const auto& extensions = cert->unparsed_extensions();
+ ASSERT_EQ(3u, extensions.size());
auto iter = extensions.find(ExtKeyUsageOid());
ASSERT_TRUE(iter != extensions.end());
@@ -513,28 +454,30 @@ TEST(ParseExtensionsTest, ExtendedKeyUsage) {
}
// Parses an Extensions that contains a key usage.
-TEST(ParseExtensionsTest, KeyUsage) {
- std::string data;
- std::map<der::Input, ParsedExtension> extensions;
- EnsureParsingExtensionsSucceeds("extensions_key_usage.pem", &extensions,
- &data);
+TEST(ParseCertificateTest, KeyUsage) {
+ scoped_refptr<ParsedCertificate> cert =
+ ParseCertificateFromFile("key_usage.pem");
+ ASSERT_TRUE(cert);
- ASSERT_EQ(1u, extensions.size());
+ ASSERT_TRUE(cert->has_key_usage());
- auto iter = extensions.find(KeyUsageOid());
- ASSERT_TRUE(iter != extensions.end());
- EXPECT_TRUE(iter->second.critical);
- EXPECT_EQ(4u, iter->second.value.Length());
+ EXPECT_EQ(5u, cert->key_usage().unused_bits());
+ const uint8_t kExpectedBytes[] = {0xA0};
+ EXPECT_EQ(der::Input(kExpectedBytes), cert->key_usage().bytes());
+
+ EXPECT_TRUE(cert->key_usage().AssertsBit(0));
+ EXPECT_FALSE(cert->key_usage().AssertsBit(1));
+ EXPECT_TRUE(cert->key_usage().AssertsBit(2));
}
// Parses an Extensions that contains a policies extension.
-TEST(ParseExtensionsTest, Policies) {
- std::string data;
- std::map<der::Input, ParsedExtension> extensions;
- EnsureParsingExtensionsSucceeds("extensions_policies.pem", &extensions,
- &data);
+TEST(ParseCertificateTest, Policies) {
+ scoped_refptr<ParsedCertificate> cert =
+ ParseCertificateFromFile("policies.pem");
+ ASSERT_TRUE(cert);
- ASSERT_EQ(1u, extensions.size());
+ const auto& extensions = cert->unparsed_extensions();
+ ASSERT_EQ(3u, extensions.size());
auto iter = extensions.find(CertificatePoliciesOid());
ASSERT_TRUE(iter != extensions.end());
@@ -543,40 +486,28 @@ TEST(ParseExtensionsTest, Policies) {
}
// Parses an Extensions that contains a subjectaltname extension.
-TEST(ParseExtensionsTest, SubjectAltName) {
- std::string data;
- std::map<der::Input, ParsedExtension> extensions;
- EnsureParsingExtensionsSucceeds("extensions_subject_alt_name.pem",
- &extensions, &data);
+TEST(ParseCertificateTest, SubjectAltName) {
+ scoped_refptr<ParsedCertificate> cert =
+ ParseCertificateFromFile("subject_alt_name.pem");
+ ASSERT_TRUE(cert);
- ASSERT_EQ(1u, extensions.size());
-
- auto iter = extensions.find(SubjectAltNameOid());
- ASSERT_TRUE(iter != extensions.end());
- EXPECT_FALSE(iter->second.critical);
- EXPECT_EQ(23u, iter->second.value.Length());
+ ASSERT_TRUE(cert->has_subject_alt_names());
}
// Parses an Extensions that contains multiple extensions, sourced from a
// real-world certificate.
-TEST(ParseExtensionsTest, Real) {
- std::string data;
- std::map<der::Input, ParsedExtension> extensions;
- EnsureParsingExtensionsSucceeds("extensions_real.pem", &extensions, &data);
-
- ASSERT_EQ(7u, extensions.size());
+TEST(ParseCertificateTest, ExtensionsReal) {
+ scoped_refptr<ParsedCertificate> cert =
+ ParseCertificateFromFile("extensions_real.pem");
+ ASSERT_TRUE(cert);
- auto iter = extensions.find(KeyUsageOid());
- ASSERT_TRUE(iter != extensions.end());
- EXPECT_TRUE(iter->second.critical);
- EXPECT_EQ(4u, iter->second.value.Length());
+ const auto& extensions = cert->unparsed_extensions();
+ ASSERT_EQ(4u, extensions.size());
- iter = extensions.find(BasicConstraintsOid());
- ASSERT_TRUE(iter != extensions.end());
- EXPECT_TRUE(iter->second.critical);
- EXPECT_EQ(8u, iter->second.value.Length());
+ EXPECT_TRUE(cert->has_key_usage());
+ EXPECT_TRUE(cert->has_basic_constraints());
- iter = extensions.find(CertificatePoliciesOid());
+ auto iter = extensions.find(CertificatePoliciesOid());
ASSERT_TRUE(iter != extensions.end());
EXPECT_FALSE(iter->second.critical);
EXPECT_EQ(16u, iter->second.value.Length());
@@ -584,107 +515,100 @@ TEST(ParseExtensionsTest, Real) {
// TODO(eroman): Verify the other 4 extensions' values.
}
-// Reads a PEM file containing a block "BASIC CONSTRAINTS". This input will
-// be passed to ParseExtension, and the results filled in |out|.
-bool ParseBasicConstraintsFromFile(const std::string& file_name,
- ParsedBasicConstraints* out) {
- std::string data;
- const PemBlockMapping mappings[] = {
- {"BASIC CONSTRAINTS", &data},
- };
-
- EXPECT_TRUE(ReadTestDataFromPemFile(GetFilePath(file_name), mappings));
- return ParseBasicConstraints(der::Input(&data), out);
-}
-
// Parses a BasicConstraints with no CA or pathlen.
-TEST(ParseBasicConstraintsTest, NotCa) {
- ParsedBasicConstraints constraints;
- ASSERT_TRUE(ParseBasicConstraintsFromFile("basic_constraints_not_ca.pem",
- &constraints));
- EXPECT_FALSE(constraints.is_ca);
- EXPECT_FALSE(constraints.has_path_len);
+TEST(ParseCertificateTest, BasicConstraintsNotCa) {
+ scoped_refptr<ParsedCertificate> cert =
+ ParseCertificateFromFile("basic_constraints_not_ca.pem");
+ ASSERT_TRUE(cert);
+
+ EXPECT_TRUE(cert->has_basic_constraints());
+ EXPECT_FALSE(cert->basic_constraints().is_ca);
+ EXPECT_FALSE(cert->basic_constraints().has_path_len);
}
// Parses a BasicConstraints with CA but no pathlen.
-TEST(ParseBasicConstraintsTest, CaNoPath) {
- ParsedBasicConstraints constraints;
- ASSERT_TRUE(ParseBasicConstraintsFromFile("basic_constraints_ca_no_path.pem",
- &constraints));
- EXPECT_TRUE(constraints.is_ca);
- EXPECT_FALSE(constraints.has_path_len);
+TEST(ParseCertificateTest, BasicConstraintsCaNoPath) {
+ scoped_refptr<ParsedCertificate> cert =
+ ParseCertificateFromFile("basic_constraints_ca_no_path.pem");
+ ASSERT_TRUE(cert);
+
+ EXPECT_TRUE(cert->has_basic_constraints());
+ EXPECT_TRUE(cert->basic_constraints().is_ca);
+ EXPECT_FALSE(cert->basic_constraints().has_path_len);
}
// Parses a BasicConstraints with CA and pathlen of 9.
-TEST(ParseBasicConstraintsTest, CaPath9) {
- ParsedBasicConstraints constraints;
- ASSERT_TRUE(ParseBasicConstraintsFromFile("basic_constraints_ca_path_9.pem",
- &constraints));
- EXPECT_TRUE(constraints.is_ca);
- EXPECT_TRUE(constraints.has_path_len);
- EXPECT_EQ(9u, constraints.path_len);
+TEST(ParseCertificateTest, BasicConstraintsCaPath9) {
+ scoped_refptr<ParsedCertificate> cert =
+ ParseCertificateFromFile("basic_constraints_ca_path_9.pem");
+ ASSERT_TRUE(cert);
+
+ EXPECT_TRUE(cert->has_basic_constraints());
+ EXPECT_TRUE(cert->basic_constraints().is_ca);
+ EXPECT_TRUE(cert->basic_constraints().has_path_len);
+ EXPECT_EQ(9u, cert->basic_constraints().path_len);
}
// Parses a BasicConstraints with CA and pathlen of 255 (largest allowed size).
-TEST(ParseBasicConstraintsTest, Pathlen255) {
- ParsedBasicConstraints constraints;
- ASSERT_TRUE(ParseBasicConstraintsFromFile("basic_constraints_pathlen_255.pem",
- &constraints));
- EXPECT_TRUE(constraints.is_ca);
- EXPECT_TRUE(constraints.has_path_len);
- EXPECT_EQ(255, constraints.path_len);
+TEST(ParseCertificateTest, BasicConstraintsPathlen255) {
+ scoped_refptr<ParsedCertificate> cert =
+ ParseCertificateFromFile("basic_constraints_pathlen_255.pem");
+ ASSERT_TRUE(cert);
+
+ EXPECT_TRUE(cert->has_basic_constraints());
+ EXPECT_TRUE(cert->basic_constraints().is_ca);
+ EXPECT_TRUE(cert->basic_constraints().has_path_len);
+ EXPECT_EQ(255, cert->basic_constraints().path_len);
}
// Parses a BasicConstraints with CA and pathlen of 256 (too large).
-TEST(ParseBasicConstraintsTest, Pathlen256) {
- ParsedBasicConstraints constraints;
- ASSERT_FALSE(ParseBasicConstraintsFromFile(
- "basic_constraints_pathlen_256.pem", &constraints));
+TEST(ParseCertificateTest, BasicConstraintsPathlen256) {
+ ASSERT_FALSE(ParseCertificateFromFile("basic_constraints_pathlen_256.pem"));
}
// Parses a BasicConstraints with CA and a negative pathlen.
-TEST(ParseBasicConstraintsTest, NegativePath) {
- ParsedBasicConstraints constraints;
- ASSERT_FALSE(ParseBasicConstraintsFromFile(
- "basic_constraints_negative_path.pem", &constraints));
+TEST(ParseCertificateTest, BasicConstraintsNegativePath) {
+ ASSERT_FALSE(ParseCertificateFromFile("basic_constraints_negative_path.pem"));
}
// Parses a BasicConstraints with CA and pathlen that is very large (and
// couldn't fit in a 64-bit integer).
-TEST(ParseBasicConstraintsTest, PathTooLarge) {
- ParsedBasicConstraints constraints;
- ASSERT_FALSE(ParseBasicConstraintsFromFile(
- "basic_constraints_path_too_large.pem", &constraints));
+TEST(ParseCertificateTest, BasicConstraintsPathTooLarge) {
+ ASSERT_FALSE(
+ ParseCertificateFromFile("basic_constraints_path_too_large.pem"));
}
// Parses a BasicConstraints with CA explicitly set to false. This violates
// DER-encoding rules, however is commonly used, so it is accepted.
-TEST(ParseBasicConstraintsTest, CaFalse) {
- ParsedBasicConstraints constraints;
- ASSERT_TRUE(ParseBasicConstraintsFromFile("basic_constraints_ca_false.pem",
- &constraints));
- EXPECT_FALSE(constraints.is_ca);
- EXPECT_FALSE(constraints.has_path_len);
+TEST(ParseCertificateTest, BasicConstraintsCaFalse) {
+ scoped_refptr<ParsedCertificate> cert =
+ ParseCertificateFromFile("basic_constraints_ca_false.pem");
+ ASSERT_TRUE(cert);
+
+ EXPECT_TRUE(cert->has_basic_constraints());
+ EXPECT_FALSE(cert->basic_constraints().is_ca);
+ EXPECT_FALSE(cert->basic_constraints().has_path_len);
}
// Parses a BasicConstraints with CA set to true and an unexpected NULL at
// the end.
-TEST(ParseBasicConstraintsTest, UnconsumedData) {
- ParsedBasicConstraints constraints;
- ASSERT_FALSE(ParseBasicConstraintsFromFile(
- "basic_constraints_unconsumed_data.pem", &constraints));
+TEST(ParseCertificateTest, BasicConstraintsUnconsumedData) {
+ ASSERT_FALSE(
+ ParseCertificateFromFile("basic_constraints_unconsumed_data.pem"));
}
// Parses a BasicConstraints with CA omitted (false), but with a pathlen of 1.
// This is valid DER for the ASN.1, however is not valid when interpreting the
// BasicConstraints at a higher level.
-TEST(ParseBasicConstraintsTest, PathLenButNotCa) {
- ParsedBasicConstraints constraints;
- ASSERT_TRUE(ParseBasicConstraintsFromFile(
- "basic_constraints_pathlen_not_ca.pem", &constraints));
- EXPECT_FALSE(constraints.is_ca);
- EXPECT_TRUE(constraints.has_path_len);
- EXPECT_EQ(1u, constraints.path_len);
+TEST(ParseCertificateTest, BasicConstraintsPathLenButNotCa) {
+ scoped_refptr<ParsedCertificate> cert =
+ ParseCertificateFromFile("basic_constraints_pathlen_not_ca.pem");
+ ASSERT_TRUE(cert);
+
+ EXPECT_TRUE(cert->has_basic_constraints());
+ EXPECT_FALSE(cert->basic_constraints().is_ca);
+ EXPECT_TRUE(cert->basic_constraints().has_path_len);
+ EXPECT_EQ(1u, cert->basic_constraints().path_len);
}
// Parses a KeyUsage with a single 0 bit.
diff --git a/chromium/net/cert/internal/parse_name.cc b/chromium/net/cert/internal/parse_name.cc
index dc491ae1920..bb9b64051ac 100644
--- a/chromium/net/cert/internal/parse_name.cc
+++ b/chromium/net/cert/internal/parse_name.cc
@@ -289,10 +289,14 @@ bool ReadRdn(der::Parser* parser, RelativeDistinguishedName* out) {
bool ParseName(const der::Input& name_tlv, RDNSequence* out) {
der::Parser name_parser(name_tlv);
- der::Parser rdn_sequence_parser;
- if (!name_parser.ReadSequence(&rdn_sequence_parser))
+ der::Input name_value;
+ if (!name_parser.ReadTag(der::kSequence, &name_value))
return false;
+ return ParseNameValue(name_value, out);
+}
+bool ParseNameValue(const der::Input& name_value, RDNSequence* out) {
+ der::Parser rdn_sequence_parser(name_value);
while (rdn_sequence_parser.HasMore()) {
der::Parser rdn_parser;
if (!rdn_sequence_parser.ReadConstructed(der::kSet, &rdn_parser))
diff --git a/chromium/net/cert/internal/parse_name.h b/chromium/net/cert/internal/parse_name.h
index 00d2bbb7ef1..ce09bc82d4d 100644
--- a/chromium/net/cert/internal/parse_name.h
+++ b/chromium/net/cert/internal/parse_name.h
@@ -91,6 +91,10 @@ NET_EXPORT bool ReadRdn(der::Parser* parser,
// and sets the results in |out|.
NET_EXPORT bool ParseName(const der::Input& name_tlv,
RDNSequence* out) WARN_UNUSED_RESULT;
+// Parses a DER-encoded "Name" value (without the sequence tag & length) as
+// specified by 5280. Returns true on success and sets the results in |out|.
+NET_EXPORT bool ParseNameValue(const der::Input& name_value,
+ RDNSequence* out) WARN_UNUSED_RESULT;
// Formats a RDNSequence |rdn_sequence| per RFC2253 as an ASCII string and
// stores the result into |out|, and returns whether the conversion was
diff --git a/chromium/net/cert/internal/parse_ocsp.cc b/chromium/net/cert/internal/parse_ocsp.cc
index 0243d9537b6..2f734102270 100644
--- a/chromium/net/cert/internal/parse_ocsp.cc
+++ b/chromium/net/cert/internal/parse_ocsp.cc
@@ -6,7 +6,9 @@
#include "base/sha1.h"
#include "crypto/sha2.h"
+#include "net/cert/internal/cert_errors.h"
#include "net/cert/internal/parse_ocsp.h"
+#include "net/der/encode_values.h"
namespace net {
@@ -127,13 +129,13 @@ bool ParseCertStatus(const der::Input& raw_tlv, OCSPCertStatus* out) {
out->has_reason = false;
if (status_tag == der::ContextSpecificPrimitive(0)) {
- out->status = OCSPCertStatus::Status::GOOD;
+ out->status = OCSPRevocationStatus::GOOD;
} else if (status_tag == der::ContextSpecificConstructed(1)) {
- out->status = OCSPCertStatus::Status::REVOKED;
+ out->status = OCSPRevocationStatus::REVOKED;
if (!ParseRevokedInfo(status, out))
return false;
} else if (status_tag == der::ContextSpecificPrimitive(2)) {
- out->status = OCSPCertStatus::Status::UNKNOWN;
+ out->status = OCSPRevocationStatus::UNKNOWN;
} else {
return false;
}
@@ -322,7 +324,9 @@ bool ParseBasicOCSPResponse(const der::Input& raw_tlv, OCSPResponse* out) {
der::Input sigalg_tlv;
if (!parser.ReadRawTLV(&sigalg_tlv))
return false;
- out->signature_algorithm = SignatureAlgorithm::CreateFromDer(sigalg_tlv);
+ // TODO(crbug.com/634443): Propagate the errors.
+ net::CertErrors errors;
+ out->signature_algorithm = SignatureAlgorithm::Create(sigalg_tlv, &errors);
if (!out->signature_algorithm)
return false;
if (!parser.ReadBitString(&(out->signature)))
@@ -496,13 +500,16 @@ bool GetOCSPCertStatus(const OCSPResponseData& response_data,
const der::Input& issuer_tbs_certificate_tlv,
const der::Input& cert_tbs_certificate_tlv,
OCSPCertStatus* out) {
- out->status = OCSPCertStatus::Status::GOOD;
+ out->status = OCSPRevocationStatus::GOOD;
ParsedTbsCertificate tbs_cert;
- if (!ParseTbsCertificate(cert_tbs_certificate_tlv, {}, &tbs_cert))
+ // TODO(crbug.com/634443): Propagate the errors.
+ CertErrors errors;
+ if (!ParseTbsCertificate(cert_tbs_certificate_tlv, {}, &tbs_cert, &errors))
return false;
ParsedTbsCertificate issuer_tbs_cert;
- if (!ParseTbsCertificate(issuer_tbs_certificate_tlv, {}, &issuer_tbs_cert))
+ if (!ParseTbsCertificate(issuer_tbs_certificate_tlv, {}, &issuer_tbs_cert,
+ &errors))
return false;
bool found = false;
@@ -516,17 +523,41 @@ bool GetOCSPCertStatus(const OCSPResponseData& response_data,
found = true;
// In the case that we receive multiple responses, we keep only the
// strictest status (REVOKED > UNKNOWN > GOOD).
- if (out->status == OCSPCertStatus::Status::GOOD ||
- new_status.status == OCSPCertStatus::Status::REVOKED) {
+ if (out->status == OCSPRevocationStatus::GOOD ||
+ new_status.status == OCSPRevocationStatus::REVOKED) {
*out = new_status;
}
}
}
if (!found)
- out->status = OCSPCertStatus::Status::UNKNOWN;
+ out->status = OCSPRevocationStatus::UNKNOWN;
return found;
}
+bool CheckOCSPDateValid(const OCSPSingleResponse& response,
+ const base::Time& verify_time,
+ const base::TimeDelta& max_age) {
+ der::GeneralizedTime verify_time_der;
+ if (!der::EncodeTimeAsGeneralizedTime(verify_time, &verify_time_der))
+ return false;
+
+ if (response.this_update > verify_time_der)
+ return false; // Response is not yet valid.
+
+ if (response.has_next_update && (response.next_update <= verify_time_der))
+ return false; // Response is no longer valid.
+
+ der::GeneralizedTime earliest_this_update;
+ if (!der::EncodeTimeAsGeneralizedTime(verify_time - max_age,
+ &earliest_this_update)) {
+ return false;
+ }
+ if (response.this_update < earliest_this_update)
+ return false; // Response is too old.
+
+ return true;
+}
+
} // namespace net
diff --git a/chromium/net/cert/internal/parse_ocsp.h b/chromium/net/cert/internal/parse_ocsp.h
index b9052aee9f6..6b0fddedd88 100644
--- a/chromium/net/cert/internal/parse_ocsp.h
+++ b/chromium/net/cert/internal/parse_ocsp.h
@@ -10,13 +10,20 @@
#include <vector>
#include "net/base/hash_value.h"
+#include "net/base/net_export.h"
#include "net/cert/internal/parse_certificate.h"
#include "net/cert/internal/signature_algorithm.h"
+#include "net/cert/ocsp_revocation_status.h"
#include "net/der/input.h"
#include "net/der/parse_values.h"
#include "net/der/parser.h"
#include "net/der/tag.h"
+namespace base {
+class Time;
+class TimeDelta;
+}
+
namespace net {
// OCSPCertID contains a representation of a DER-encoded RFC 6960 "CertID".
@@ -70,11 +77,6 @@ struct OCSPCertID {
// }
// (from RFC 5280)
struct OCSPCertStatus {
- enum class Status {
- GOOD,
- REVOKED,
- UNKNOWN,
- };
// Correspond to the values of CRLReason
enum class RevocationReason {
@@ -93,7 +95,7 @@ struct OCSPCertStatus {
LAST = AA_COMPROMISE,
};
- Status status;
+ OCSPRevocationStatus status;
der::GeneralizedTime revocation_time;
bool has_reason;
RevocationReason revocation_reason;
@@ -278,6 +280,15 @@ NET_EXPORT_PRIVATE bool GetOCSPCertStatus(
const der::Input& cert_tbs_certificate_tlv,
OCSPCertStatus* out);
+// Returns true if |response|, a valid OCSP response with a thisUpdate field and
+// potentially a nextUpdate field, is valid at |verify_time| and not older than
+// |max_age|. Expressed differently, returns true if |response.thisUpdate| <=
+// |verify_time| < response.nextUpdate, and |response.thisUpdate| >=
+// |verify_time| - |max_age|.
+NET_EXPORT_PRIVATE bool CheckOCSPDateValid(const OCSPSingleResponse& response,
+ const base::Time& verify_time,
+ const base::TimeDelta& max_age);
+
} // namespace net
#endif // NET_CERT_INTERNAL_PARSE_OCSP_H_
diff --git a/chromium/net/cert/internal/parse_ocsp_unittest.cc b/chromium/net/cert/internal/parse_ocsp_unittest.cc
index c0fc061b5e4..08e18db35e8 100644
--- a/chromium/net/cert/internal/parse_ocsp_unittest.cc
+++ b/chromium/net/cert/internal/parse_ocsp_unittest.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "net/cert/internal/test_helpers.h"
#include "net/cert/x509_certificate.h"
+#include "net/der/encode_values.h"
#include "net/test/test_data_directory.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -15,6 +16,8 @@ namespace net {
namespace {
+const base::TimeDelta kOCSPAgeOneWeek = base::TimeDelta::FromDays(7);
+
std::string GetFilePath(const std::string& file_name) {
return std::string("net/data/parse_ocsp_unittest/") + file_name;
}
@@ -56,10 +59,11 @@ OCSPFailure ParseOCSP(const std::string& file_name) {
der::BitString cert_signature_value;
if (!ParseCertificate(ca_input, &issuer_tbs_certificate_tlv,
&issuer_signature_algorithm_tlv,
- &issuer_signature_value))
+ &issuer_signature_value, nullptr))
return PARSE_CERT;
if (!ParseCertificate(cert_input, &cert_tbs_certificate_tlv,
- &cert_signature_algorithm_tlv, &cert_signature_value))
+ &cert_signature_algorithm_tlv, &cert_signature_value,
+ nullptr))
return PARSE_CERT;
OCSPResponse parsed_ocsp;
OCSPResponseData parsed_ocsp_data;
@@ -77,11 +81,11 @@ OCSPFailure ParseOCSP(const std::string& file_name) {
return PARSE_OCSP_SINGLE_RESPONSE;
switch (status.status) {
- case OCSPCertStatus::Status::GOOD:
+ case OCSPRevocationStatus::GOOD:
return OCSP_SUCCESS;
- case OCSPCertStatus::Status::REVOKED:
+ case OCSPRevocationStatus::REVOKED:
return OCSP_SUCCESS_REVOKED;
- case OCSPCertStatus::Status::UNKNOWN:
+ case OCSPRevocationStatus::UNKNOWN:
return OCSP_SUCCESS_UNKNOWN;
}
@@ -182,4 +186,131 @@ TEST(ParseOCSPTest, OCSPMissingResponse) {
ASSERT_EQ(PARSE_OCSP_SINGLE_RESPONSE, ParseOCSP("missing_response.pem"));
}
+TEST(OCSPDateTest, Valid) {
+ OCSPSingleResponse response;
+
+ base::Time now = base::Time::Now();
+ base::Time this_update = now - base::TimeDelta::FromHours(1);
+ ASSERT_TRUE(
+ der::EncodeTimeAsGeneralizedTime(this_update, &response.this_update));
+ response.has_next_update = false;
+ EXPECT_TRUE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
+
+ base::Time next_update = this_update + base::TimeDelta::FromDays(7);
+ ASSERT_TRUE(
+ der::EncodeTimeAsGeneralizedTime(next_update, &response.next_update));
+ response.has_next_update = true;
+ EXPECT_TRUE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
+}
+
+TEST(OCSPDateTest, ThisUpdateInTheFuture) {
+ OCSPSingleResponse response;
+
+ base::Time now = base::Time::Now();
+ base::Time this_update = now + base::TimeDelta::FromHours(1);
+ ASSERT_TRUE(
+ der::EncodeTimeAsGeneralizedTime(this_update, &response.this_update));
+ response.has_next_update = false;
+ EXPECT_FALSE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
+
+ base::Time next_update = this_update + base::TimeDelta::FromDays(7);
+ ASSERT_TRUE(
+ der::EncodeTimeAsGeneralizedTime(next_update, &response.next_update));
+ response.has_next_update = true;
+ EXPECT_FALSE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
+}
+
+TEST(OCSPDateTest, NextUpdatePassed) {
+ OCSPSingleResponse response;
+
+ base::Time now = base::Time::Now();
+ base::Time this_update = now - base::TimeDelta::FromDays(6);
+ ASSERT_TRUE(
+ der::EncodeTimeAsGeneralizedTime(this_update, &response.this_update));
+ response.has_next_update = false;
+ EXPECT_TRUE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
+
+ base::Time next_update = now - base::TimeDelta::FromHours(1);
+ ASSERT_TRUE(
+ der::EncodeTimeAsGeneralizedTime(next_update, &response.next_update));
+ response.has_next_update = true;
+ EXPECT_FALSE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
+}
+
+TEST(OCSPDateTest, NextUpdateBeforeThisUpdate) {
+ OCSPSingleResponse response;
+
+ base::Time now = base::Time::Now();
+ base::Time this_update = now - base::TimeDelta::FromDays(1);
+ ASSERT_TRUE(
+ der::EncodeTimeAsGeneralizedTime(this_update, &response.this_update));
+ response.has_next_update = false;
+ EXPECT_TRUE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
+
+ base::Time next_update = this_update - base::TimeDelta::FromDays(1);
+ ASSERT_TRUE(
+ der::EncodeTimeAsGeneralizedTime(next_update, &response.next_update));
+ response.has_next_update = true;
+ EXPECT_FALSE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
+}
+
+TEST(OCSPDateTest, ThisUpdateOlderThanMaxAge) {
+ OCSPSingleResponse response;
+
+ base::Time now = base::Time::Now();
+ base::Time this_update = now - kOCSPAgeOneWeek;
+ ASSERT_TRUE(
+ der::EncodeTimeAsGeneralizedTime(this_update, &response.this_update));
+ response.has_next_update = false;
+ EXPECT_TRUE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
+
+ base::Time next_update = now + base::TimeDelta::FromHours(1);
+ ASSERT_TRUE(
+ der::EncodeTimeAsGeneralizedTime(next_update, &response.next_update));
+ response.has_next_update = true;
+ EXPECT_TRUE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
+
+ ASSERT_TRUE(der::EncodeTimeAsGeneralizedTime(
+ this_update - base::TimeDelta::FromSeconds(1), &response.this_update));
+ response.has_next_update = false;
+ EXPECT_FALSE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
+ response.has_next_update = true;
+ EXPECT_FALSE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
+}
+
+TEST(OCSPDateTest, VerifyTimeFromBeforeWindowsEpoch) {
+ OCSPSingleResponse response;
+ base::Time windows_epoch;
+ base::Time verify_time = windows_epoch - base::TimeDelta::FromDays(1);
+
+ base::Time now = base::Time::Now();
+ base::Time this_update = now - base::TimeDelta::FromHours(1);
+ ASSERT_TRUE(
+ der::EncodeTimeAsGeneralizedTime(this_update, &response.this_update));
+ response.has_next_update = false;
+ EXPECT_FALSE(CheckOCSPDateValid(response, verify_time, kOCSPAgeOneWeek));
+
+ base::Time next_update = this_update + kOCSPAgeOneWeek;
+ ASSERT_TRUE(
+ der::EncodeTimeAsGeneralizedTime(next_update, &response.next_update));
+ response.has_next_update = true;
+ EXPECT_FALSE(CheckOCSPDateValid(response, verify_time, kOCSPAgeOneWeek));
+}
+
+TEST(OCSPDateTest, VerifyTimeMinusAgeFromBeforeWindowsEpoch) {
+ OCSPSingleResponse response;
+ base::Time windows_epoch;
+ base::Time verify_time = windows_epoch + base::TimeDelta::FromDays(1);
+
+ base::Time this_update = windows_epoch;
+ ASSERT_TRUE(
+ der::EncodeTimeAsGeneralizedTime(this_update, &response.this_update));
+ response.has_next_update = false;
+#if defined(OS_WIN)
+ EXPECT_FALSE(CheckOCSPDateValid(response, verify_time, kOCSPAgeOneWeek));
+#else
+ EXPECT_TRUE(CheckOCSPDateValid(response, verify_time, kOCSPAgeOneWeek));
+#endif
+}
+
} // namespace net
diff --git a/chromium/net/cert/internal/parsed_certificate.cc b/chromium/net/cert/internal/parsed_certificate.cc
index e8e08c4e0ac..6c2676cdbd0 100644
--- a/chromium/net/cert/internal/parsed_certificate.cc
+++ b/chromium/net/cert/internal/parsed_certificate.cc
@@ -24,11 +24,62 @@ WARN_UNUSED_RESULT bool GetSequenceValue(const der::Input& tlv,
ParsedCertificate::ParsedCertificate() {}
ParsedCertificate::~ParsedCertificate() {}
-scoped_refptr<ParsedCertificate> ParsedCertificate::CreateFromCertificateData(
+scoped_refptr<ParsedCertificate> ParsedCertificate::Create(
+ const uint8_t* data,
+ size_t length,
+ const ParseCertificateOptions& options,
+ CertErrors* errors) {
+ return CreateInternal(data, length, DataSource::INTERNAL_COPY, options,
+ errors);
+}
+
+scoped_refptr<ParsedCertificate> ParsedCertificate::Create(
+ const base::StringPiece& data,
+ const ParseCertificateOptions& options,
+ CertErrors* errors) {
+ return ParsedCertificate::Create(
+ reinterpret_cast<const uint8_t*>(data.data()), data.size(), options,
+ errors);
+}
+
+bool ParsedCertificate::CreateAndAddToVector(
+ const uint8_t* data,
+ size_t length,
+ const ParseCertificateOptions& options,
+ ParsedCertificateList* chain,
+ CertErrors* errors) {
+ scoped_refptr<ParsedCertificate> cert(Create(data, length, options, errors));
+ if (!cert)
+ return false;
+ chain->push_back(std::move(cert));
+ return true;
+}
+
+bool ParsedCertificate::CreateAndAddToVector(
+ const base::StringPiece& data,
+ const ParseCertificateOptions& options,
+ ParsedCertificateList* chain,
+ CertErrors* errors) {
+ return CreateAndAddToVector(reinterpret_cast<const uint8_t*>(data.data()),
+ data.size(), options, chain, errors);
+}
+
+scoped_refptr<ParsedCertificate> ParsedCertificate::CreateWithoutCopyingUnsafe(
+ const uint8_t* data,
+ size_t length,
+ const ParseCertificateOptions& options,
+ CertErrors* errors) {
+ return CreateInternal(data, length, DataSource::EXTERNAL_REFERENCE, options,
+ errors);
+}
+
+scoped_refptr<ParsedCertificate> ParsedCertificate::CreateInternal(
const uint8_t* data,
size_t length,
DataSource source,
- const ParseCertificateOptions& options) {
+ const ParseCertificateOptions& options,
+ CertErrors* errors) {
+ // TODO(crbug.com/634443): Add errors
scoped_refptr<ParsedCertificate> result(new ParsedCertificate);
switch (source) {
@@ -44,22 +95,22 @@ scoped_refptr<ParsedCertificate> ParsedCertificate::CreateFromCertificateData(
if (!ParseCertificate(result->cert_, &result->tbs_certificate_tlv_,
&result->signature_algorithm_tlv_,
- &result->signature_value_)) {
+ &result->signature_value_, errors)) {
return nullptr;
}
- if (!ParseTbsCertificate(result->tbs_certificate_tlv_, options,
- &result->tbs_)) {
+ if (!ParseTbsCertificate(result->tbs_certificate_tlv_, options, &result->tbs_,
+ errors)) {
return nullptr;
}
// Attempt to parse the signature algorithm contained in the Certificate.
- // Do not give up on failure here, since SignatureAlgorithm::CreateFromDer
+ // Do not give up on failure here, since SignatureAlgorithm::Create
// will fail on valid but unsupported signature algorithms.
// TODO(mattm): should distinguish between unsupported algorithms and parsing
// errors.
result->signature_algorithm_ =
- SignatureAlgorithm::CreateFromDer(result->signature_algorithm_tlv_);
+ SignatureAlgorithm::Create(result->signature_algorithm_tlv_, errors);
der::Input subject_value;
if (!GetSequenceValue(result->tbs_.subject_tlv, &subject_value) ||
@@ -105,8 +156,8 @@ scoped_refptr<ParsedCertificate> ParsedCertificate::CreateFromCertificateData(
&result->subject_alt_names_extension_)) {
// RFC 5280 section 4.2.1.6:
// SubjectAltName ::= GeneralNames
- result->subject_alt_names_ = GeneralNames::CreateFromDer(
- result->subject_alt_names_extension_.value);
+ result->subject_alt_names_ =
+ GeneralNames::Create(result->subject_alt_names_extension_.value);
if (!result->subject_alt_names_)
return nullptr;
// RFC 5280 section 4.1.2.6:
@@ -124,7 +175,7 @@ scoped_refptr<ParsedCertificate> ParsedCertificate::CreateFromCertificateData(
if (ConsumeExtension(NameConstraintsOid(), &result->unparsed_extensions_,
&extension)) {
result->name_constraints_ =
- NameConstraints::CreateFromDer(extension.value, extension.critical);
+ NameConstraints::Create(extension.value, extension.critical);
if (!result->name_constraints_)
return nullptr;
}
@@ -149,26 +200,4 @@ scoped_refptr<ParsedCertificate> ParsedCertificate::CreateFromCertificateData(
return result;
}
-scoped_refptr<ParsedCertificate> ParsedCertificate::CreateFromCertificateCopy(
- const base::StringPiece& data,
- const ParseCertificateOptions& options) {
- return ParsedCertificate::CreateFromCertificateData(
- reinterpret_cast<const uint8_t*>(data.data()), data.size(),
- DataSource::INTERNAL_COPY, options);
-}
-
-bool ParsedCertificate::CreateAndAddToVector(
- const uint8_t* data,
- size_t length,
- DataSource source,
- const ParseCertificateOptions& options,
- std::vector<scoped_refptr<ParsedCertificate>>* chain) {
- scoped_refptr<ParsedCertificate> cert(
- CreateFromCertificateData(data, length, source, options));
- if (!cert)
- return false;
- chain->push_back(std::move(cert));
- return true;
-}
-
} // namespace net
diff --git a/chromium/net/cert/internal/parsed_certificate.h b/chromium/net/cert/internal/parsed_certificate.h
index 82377522989..0b7c89ff51d 100644
--- a/chromium/net/cert/internal/parsed_certificate.h
+++ b/chromium/net/cert/internal/parsed_certificate.h
@@ -18,7 +18,11 @@ namespace net {
struct GeneralNames;
class NameConstraints;
+class ParsedCertificate;
class SignatureAlgorithm;
+class CertErrors;
+
+using ParsedCertificateList = std::vector<scoped_refptr<ParsedCertificate>>;
// Represents an X.509 certificate, including Certificate, TBSCertificate, and
// standard extensions.
@@ -33,40 +37,67 @@ class NET_EXPORT ParsedCertificate
// Map from OID to ParsedExtension.
using ExtensionsMap = std::map<der::Input, ParsedExtension>;
- // The certificate data for may either be owned internally (INTERNAL_COPY) or
- // owned externally (EXTERNAL_REFERENCE). When it is owned internally the data
- // is held by |cert_data_|
- enum class DataSource {
- INTERNAL_COPY,
- EXTERNAL_REFERENCE,
- };
-
// Creates a ParsedCertificate given a DER-encoded Certificate. Returns
// nullptr on failure. Failure will occur if the standard certificate fields
// and supported extensions cannot be parsed.
//
- // The provided certificate data is either copied, or aliased, depending on
- // the value of |source|. See the comments for DataSource for details.
- static scoped_refptr<ParsedCertificate> CreateFromCertificateData(
+ // The provided certificate data is copied, so |data| needn't remain valid
+ // after this call.
+ //
+ // On either success or failure, if |errors| is non-null it may have error
+ // information added to it.
+ static scoped_refptr<ParsedCertificate> Create(
const uint8_t* data,
size_t length,
- DataSource source,
- const ParseCertificateOptions& options);
+ const ParseCertificateOptions& options,
+ CertErrors* errors);
- // Creates a ParsedCertificate and appends it to |chain|. Returns true if the
- // certificate was successfully parsed and added. If false is return, |chain|
- // is unmodified.
+ // Overload that takes a StringPiece.
+ static scoped_refptr<ParsedCertificate> Create(
+ const base::StringPiece& data,
+ const ParseCertificateOptions& options,
+ CertErrors* errors);
+
+ // Creates a ParsedCertificate by copying the provided |data|, and appends it
+ // to |chain|. Returns true if the certificate was successfully parsed and
+ // added. If false is return, |chain| is unmodified.
+ //
+ // On either success or failure, if |errors| is non-null it may have error
+ // information added to it.
static bool CreateAndAddToVector(
const uint8_t* data,
size_t length,
- DataSource source,
const ParseCertificateOptions& options,
- std::vector<scoped_refptr<net::ParsedCertificate>>* chain);
+ std::vector<scoped_refptr<net::ParsedCertificate>>* chain,
+ CertErrors* errors);
- // Creates a ParsedCertificate, copying the data from |data|.
- static scoped_refptr<ParsedCertificate> CreateFromCertificateCopy(
+ // Overload that takes a StringPiece.
+ static bool CreateAndAddToVector(
const base::StringPiece& data,
- const ParseCertificateOptions& options);
+ const ParseCertificateOptions& options,
+ std::vector<scoped_refptr<net::ParsedCertificate>>* chain,
+ CertErrors* errors);
+
+ // Like Create() this builds a ParsedCertificate given a DER-encoded
+ // Certificate and returns nullptr on failure.
+ //
+ // However a copy of |data| is NOT made.
+ //
+ // This is a dangerous way to create as ParsedCertificate and should only be
+ // used with care when saving a copy is really worth it, or the data is known
+ // to come from static storage (and hence remain valid for entire life of
+ // process).
+ //
+ // ParsedCertificate is reference counted, so it is easy to extend the life
+ // and and end up with a ParsedCertificate referencing feed memory.
+ //
+ // On either success or failure, if |errors| is non-null it may have error
+ // information added to it.
+ static scoped_refptr<ParsedCertificate> CreateWithoutCopyingUnsafe(
+ const uint8_t* data,
+ size_t length,
+ const ParseCertificateOptions& options,
+ CertErrors* errors);
// Returns the DER-encoded certificate data for this cert.
const der::Input& der_cert() const { return cert_; }
@@ -177,10 +208,43 @@ class NET_EXPORT ParsedCertificate
}
private:
+ // The certificate data for may either be owned internally (INTERNAL_COPY) or
+ // owned externally (EXTERNAL_REFERENCE). When it is owned internally the data
+ // is held by |cert_data_|
+ enum class DataSource {
+ INTERNAL_COPY,
+ EXTERNAL_REFERENCE,
+ };
+
friend class base::RefCountedThreadSafe<ParsedCertificate>;
ParsedCertificate();
~ParsedCertificate();
+ static scoped_refptr<ParsedCertificate> CreateInternal(
+ const uint8_t* data,
+ size_t length,
+ DataSource source,
+ const ParseCertificateOptions& options,
+ CertErrors* errors);
+
+ // These private overloads should not be used, and have no definition.
+ //
+ // They are here to prevent incorrectly passing a const char*
+ // in place of a base::StringPiece (thanks to StringPiece implicit
+ // ctor on const char*).
+ //
+ // Accidentally inflating a const char* (without length) to a
+ // StringPiece would be a bug.
+ static scoped_refptr<ParsedCertificate> Create(
+ const char* invalid_data,
+ const ParseCertificateOptions& options,
+ CertErrors* errors);
+ static bool CreateAndAddToVector(
+ const char* data,
+ const ParseCertificateOptions& options,
+ std::vector<scoped_refptr<net::ParsedCertificate>>* chain,
+ CertErrors* errors);
+
// The backing store for the certificate data. This is only applicable when
// the ParsedCertificate was initialized using DataSource::INTERNAL_COPY.
std::vector<uint8_t> cert_data_;
diff --git a/chromium/net/cert/internal/path_builder.cc b/chromium/net/cert/internal/path_builder.cc
new file mode 100644
index 00000000000..36cd9d45f8d
--- /dev/null
+++ b/chromium/net/cert/internal/path_builder.cc
@@ -0,0 +1,750 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/path_builder.h"
+
+#include <set>
+#include <unordered_set>
+
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "net/base/net_errors.h"
+#include "net/cert/internal/cert_issuer_source.h"
+#include "net/cert/internal/parse_certificate.h"
+#include "net/cert/internal/parse_name.h" // For CertDebugString.
+#include "net/cert/internal/signature_policy.h"
+#include "net/cert/internal/trust_store.h"
+#include "net/cert/internal/verify_certificate_chain.h"
+#include "net/cert/internal/verify_name_match.h"
+#include "net/der/parser.h"
+#include "net/der/tag.h"
+
+namespace net {
+
+namespace {
+
+using CertIssuerSources = std::vector<CertIssuerSource*>;
+
+// TODO(mattm): decide how much debug logging to keep.
+std::string CertDebugString(const ParsedCertificate* cert) {
+ RDNSequence subject, issuer;
+ std::string subject_str, issuer_str;
+ if (!ParseName(cert->tbs().subject_tlv, &subject) ||
+ !ConvertToRFC2253(subject, &subject_str))
+ subject_str = "???";
+ if (!ParseName(cert->tbs().issuer_tlv, &issuer) ||
+ !ConvertToRFC2253(issuer, &issuer_str))
+ issuer_str = "???";
+
+ return subject_str + "(" + issuer_str + ")";
+}
+
+// This structure contains either a ParsedCertificate or a TrustAnchor. It is
+// used to describe the result of getting a certificate's issuer, which may
+// either be another certificate, or a trust anchor.
+struct CertificateOrTrustAnchor {
+ CertificateOrTrustAnchor() {}
+
+ explicit CertificateOrTrustAnchor(scoped_refptr<ParsedCertificate> cert)
+ : cert(std::move(cert)) {}
+
+ explicit CertificateOrTrustAnchor(scoped_refptr<TrustAnchor> anchor)
+ : anchor(std::move(anchor)) {}
+
+ bool IsTrustAnchor() const { return anchor.get() != nullptr; }
+ bool IsCertificate() const { return cert.get() != nullptr; }
+ bool IsEmpty() const { return !IsTrustAnchor() && !IsCertificate(); }
+
+ scoped_refptr<ParsedCertificate> cert;
+ scoped_refptr<TrustAnchor> anchor;
+};
+
+// CertIssuersIter iterates through the intermediates from |cert_issuer_sources|
+// which may be issuers of |cert|.
+class CertIssuersIter {
+ public:
+ // Constructs the CertIssuersIter. |*cert_issuer_sources| and |*trust_store|
+ // must be valid for the lifetime of the CertIssuersIter.
+ CertIssuersIter(scoped_refptr<ParsedCertificate> cert,
+ CertIssuerSources* cert_issuer_sources,
+ const TrustStore* trust_store);
+
+ // Gets the next candidate issuer. If an issuer is ready synchronously, SYNC
+ // is returned and the cert is stored in |*cert|. If an issuer is not
+ // ready, ASYNC is returned and |callback| will be called once |*out_cert| has
+ // been set. If |callback| is null, always completes synchronously.
+ //
+ // In either case, if all issuers have been exhausted, |*out| is cleared.
+ CompletionStatus GetNextIssuer(CertificateOrTrustAnchor* out,
+ const base::Closure& callback);
+
+ // Returns the |cert| for which issuers are being retrieved.
+ const ParsedCertificate* cert() const { return cert_.get(); }
+ scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; }
+
+ private:
+ void DoAsyncIssuerQuery();
+ void GotAsyncAnchors(TrustAnchors anchors);
+ void GotAsyncCerts(CertIssuerSource::Request* request);
+ void NotifyIfNecessary();
+
+ scoped_refptr<ParsedCertificate> cert_;
+ CertIssuerSources* cert_issuer_sources_;
+ const TrustStore* trust_store_;
+
+ // The list of trust anchors that match the issuer name for |cert_|.
+ TrustAnchors anchors_;
+ // The index of the next trust anchor in |anchors_| to return.
+ size_t cur_anchor_ = 0;
+
+ // The list of issuers for |cert_|. This is added to incrementally (first
+ // synchronous results, then possibly multiple times as asynchronous results
+ // arrive.) The issuers may be re-sorted each time new issuers are added, but
+ // only the results from |cur_| onwards should be sorted, since the earlier
+ // results were already returned.
+ // Elements should not be removed from |issuers_| once added, since
+ // |present_issuers_| will point to data owned by the certs.
+ ParsedCertificateList issuers_;
+ // The index of the next cert in |issuers_| to return.
+ size_t cur_issuer_ = 0;
+
+ // Set of DER-encoded values for the certs in |issuers_|. Used to prevent
+ // duplicates. This is based on the full DER of the cert to allow different
+ // versions of the same certificate to be tried in different candidate paths.
+ // This points to data owned by |issuers_|.
+ std::unordered_set<base::StringPiece, base::StringPieceHash> present_issuers_;
+
+ // Tracks which requests have been made yet.
+ bool did_initial_query_ = false;
+ bool did_async_issuer_query_ = false;
+ // If asynchronous requests were made, how many of them are still outstanding?
+ size_t pending_async_results_;
+ // Owns the Request objects for any asynchronous requests so that they will be
+ // cancelled if CertIssuersIter is destroyed.
+ std::vector<std::unique_ptr<CertIssuerSource::Request>>
+ pending_async_requests_;
+ std::unique_ptr<TrustStore::Request> pending_anchor_request_;
+
+ // When GetNextIssuer was called and returned asynchronously, |*out_| is
+ // where the result will be stored, and |callback_| will be run when the
+ // result is ready.
+ CertificateOrTrustAnchor* out_;
+ base::Closure callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(CertIssuersIter);
+};
+
+CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert,
+ CertIssuerSources* cert_issuer_sources,
+ const TrustStore* trust_store)
+ : cert_(in_cert),
+ cert_issuer_sources_(cert_issuer_sources),
+ trust_store_(trust_store) {
+ DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created";
+}
+
+CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out,
+ const base::Closure& callback) {
+ // Should not be called again while already waiting for an async result.
+ DCHECK(callback_.is_null());
+
+ if (!did_initial_query_) {
+ did_initial_query_ = true;
+ trust_store_->FindTrustAnchorsForCert(
+ cert_,
+ callback.is_null() ? TrustStore::TrustAnchorsCallback()
+ : base::Bind(&CertIssuersIter::GotAsyncAnchors,
+ base::Unretained(this)),
+ &anchors_, &pending_anchor_request_);
+
+ for (auto* cert_issuer_source : *cert_issuer_sources_) {
+ ParsedCertificateList new_issuers;
+ cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers);
+ for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) {
+ if (present_issuers_.find(issuer->der_cert().AsStringPiece()) !=
+ present_issuers_.end())
+ continue;
+ present_issuers_.insert(issuer->der_cert().AsStringPiece());
+ issuers_.push_back(std::move(issuer));
+ }
+ }
+ DVLOG(1) << anchors_.size() << " sync anchors, " << issuers_.size()
+ << " sync issuers";
+ // TODO(mattm): sort by notbefore, etc (eg if cert issuer matches a trust
+ // anchor subject (or is a trust anchor), that should be sorted higher too.
+ // See big list of possible sorting hints in RFC 4158.)
+ // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that
+ // is done)
+ }
+
+ // Return possible trust anchors first.
+ if (cur_anchor_ < anchors_.size()) {
+ DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+ << "): returning anchor " << cur_anchor_ << " of "
+ << anchors_.size();
+ // Still have anchors that haven't been returned yet, return one of them.
+ *out = CertificateOrTrustAnchor(anchors_[cur_anchor_++]);
+ return CompletionStatus::SYNC;
+ }
+
+ if (pending_anchor_request_) {
+ DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+ << ") Still waiting for async trust anchor results.";
+ out_ = out;
+ callback_ = callback;
+ return CompletionStatus::ASYNC;
+ }
+
+ if (cur_issuer_ < issuers_.size()) {
+ DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+ << "): returning issuer " << cur_issuer_ << " of "
+ << issuers_.size();
+ // Still have issuers that haven't been returned yet, return one of them.
+ // A reference to the returned issuer is retained, since |present_issuers_|
+ // points to data owned by it.
+ *out = CertificateOrTrustAnchor(issuers_[cur_issuer_++]);
+ return CompletionStatus::SYNC;
+ }
+
+ if (did_async_issuer_query_) {
+ if (pending_async_results_ == 0) {
+ DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+ << ") Reached the end of all available issuers.";
+ // Reached the end of all available issuers.
+ *out = CertificateOrTrustAnchor();
+ return CompletionStatus::SYNC;
+ }
+
+ DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+ << ") Still waiting for async results from other "
+ "CertIssuerSources.";
+ // Still waiting for async results from other CertIssuerSources.
+ out_ = out;
+ callback_ = callback;
+ return CompletionStatus::ASYNC;
+ }
+ // Reached the end of synchronously gathered issuers.
+
+ if (callback.is_null()) {
+ // Synchronous-only mode, don't try to query async sources.
+ *out = CertificateOrTrustAnchor();
+ return CompletionStatus::SYNC;
+ }
+
+ // Now issue request(s) for async ones (AIA, etc).
+ DoAsyncIssuerQuery();
+
+ if (pending_async_results_ == 0) {
+ DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+ << ") No cert sources have async results.";
+ // No cert sources have async results.
+ *out = CertificateOrTrustAnchor();
+ return CompletionStatus::SYNC;
+ }
+
+ DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+ << ") issued AsyncGetIssuersOf call(s) (n=" << pending_async_results_
+ << ")";
+ out_ = out;
+ callback_ = callback;
+ return CompletionStatus::ASYNC;
+}
+
+void CertIssuersIter::DoAsyncIssuerQuery() {
+ DCHECK(!did_async_issuer_query_);
+ did_async_issuer_query_ = true;
+ pending_async_results_ = 0;
+ for (auto* cert_issuer_source : *cert_issuer_sources_) {
+ std::unique_ptr<CertIssuerSource::Request> request;
+ cert_issuer_source->AsyncGetIssuersOf(
+ cert(),
+ base::Bind(&CertIssuersIter::GotAsyncCerts, base::Unretained(this)),
+ &request);
+ if (request) {
+ DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert())
+ << ") pending...";
+ pending_async_results_++;
+ pending_async_requests_.push_back(std::move(request));
+ }
+ }
+}
+
+void CertIssuersIter::GotAsyncAnchors(TrustAnchors anchors) {
+ DVLOG(1) << "CertIssuersIter::GotAsyncAnchors(" << CertDebugString(cert())
+ << "): " << anchors.size() << " anchors";
+ for (scoped_refptr<TrustAnchor>& anchor : anchors)
+ anchors_.push_back(std::move(anchor));
+ pending_anchor_request_.reset();
+
+ NotifyIfNecessary();
+}
+
+void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) {
+ DVLOG(1) << "CertIssuersIter::GotAsyncCerts(" << CertDebugString(cert())
+ << ")";
+ while (true) {
+ scoped_refptr<ParsedCertificate> cert;
+ CompletionStatus status = request->GetNext(&cert);
+ if (!cert) {
+ if (status == CompletionStatus::SYNC) {
+ // Request is exhausted, no more results pending from that
+ // CertIssuerSource.
+ DCHECK_GT(pending_async_results_, 0U);
+ pending_async_results_--;
+ }
+ break;
+ }
+ DCHECK_EQ(status, CompletionStatus::SYNC);
+ if (present_issuers_.find(cert->der_cert().AsStringPiece()) !=
+ present_issuers_.end())
+ continue;
+ present_issuers_.insert(cert->der_cert().AsStringPiece());
+ issuers_.push_back(std::move(cert));
+ }
+
+ // TODO(mattm): re-sort remaining elements of issuers_ (remaining elements may
+ // be more than the ones just inserted, depending on |cur_| value).
+
+ NotifyIfNecessary();
+}
+
+void CertIssuersIter::NotifyIfNecessary() {
+ // Notify that more results are available, if necessary.
+ if (!callback_.is_null()) {
+ if (cur_anchor_ < anchors_.size()) {
+ DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+ << "): async returning anchor " << cur_anchor_ << " of "
+ << anchors_.size();
+ *out_ = CertificateOrTrustAnchor(std::move(anchors_[cur_anchor_++]));
+ base::ResetAndReturn(&callback_).Run();
+ return;
+ }
+ if (cur_issuer_ < issuers_.size()) {
+ DCHECK(!pending_anchor_request_);
+ DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+ << "): async returning issuer " << cur_issuer_ << " of "
+ << issuers_.size();
+ *out_ = CertificateOrTrustAnchor(std::move(issuers_[cur_issuer_++]));
+ base::ResetAndReturn(&callback_).Run();
+ return;
+ }
+
+ if (!did_async_issuer_query_)
+ DoAsyncIssuerQuery();
+
+ if (pending_async_results_ == 0) {
+ DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+ << "): async returning empty result";
+ *out_ = CertificateOrTrustAnchor();
+ base::ResetAndReturn(&callback_).Run();
+ return;
+ }
+ DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+ << "): empty result, but other async results "
+ "pending, waiting..";
+ }
+}
+
+// CertIssuerIterPath tracks which certs are present in the path and prevents
+// paths from being built which repeat any certs (including different versions
+// of the same cert, based on Subject+SubjectAltName+SPKI).
+class CertIssuerIterPath {
+ public:
+ // Returns true if |cert| is already present in the path.
+ bool IsPresent(const ParsedCertificate* cert) const {
+ return present_certs_.find(GetKey(cert)) != present_certs_.end();
+ }
+
+ // Appends |cert_issuers_iter| to the path. The cert referred to by
+ // |cert_issuers_iter| must not be present in the path already.
+ void Append(std::unique_ptr<CertIssuersIter> cert_issuers_iter) {
+ bool added =
+ present_certs_.insert(GetKey(cert_issuers_iter->cert())).second;
+ DCHECK(added);
+ cur_path_.push_back(std::move(cert_issuers_iter));
+ }
+
+ // Pops the last CertIssuersIter off the path.
+ void Pop() {
+ size_t num_erased = present_certs_.erase(GetKey(cur_path_.back()->cert()));
+ DCHECK_EQ(num_erased, 1U);
+ cur_path_.pop_back();
+ }
+
+ // Copies the ParsedCertificate elements of the current path to |*out_path|.
+ void CopyPath(ParsedCertificateList* out_path) {
+ out_path->clear();
+ for (const auto& node : cur_path_)
+ out_path->push_back(node->reference_cert());
+ }
+
+ // Returns true if the path is empty.
+ bool Empty() const { return cur_path_.empty(); }
+
+ // Returns the last CertIssuersIter in the path.
+ CertIssuersIter* back() { return cur_path_.back().get(); }
+
+ std::string PathDebugString() {
+ std::string s;
+ for (const auto& node : cur_path_) {
+ if (!s.empty())
+ s += " <- ";
+ s += CertDebugString(node->cert());
+ }
+ return s;
+ }
+
+ private:
+ using Key =
+ std::tuple<base::StringPiece, base::StringPiece, base::StringPiece>;
+
+ static Key GetKey(const ParsedCertificate* cert) {
+ // TODO(mattm): ideally this would use a normalized version of
+ // SubjectAltName, but it's not that important just for LoopChecker.
+ //
+ // Note that subject_alt_names_extension().value will be empty if the cert
+ // had no SubjectAltName extension, so there is no need for a condition on
+ // has_subject_alt_names().
+ return Key(cert->normalized_subject().AsStringPiece(),
+ cert->subject_alt_names_extension().value.AsStringPiece(),
+ cert->tbs().spki_tlv.AsStringPiece());
+ }
+
+ std::vector<std::unique_ptr<CertIssuersIter>> cur_path_;
+
+ // This refers to data owned by |cur_path_|.
+ // TODO(mattm): use unordered_set. Requires making a hash function for Key.
+ std::set<Key> present_certs_;
+};
+
+} // namespace
+
+CertPath::CertPath() = default;
+CertPath::~CertPath() = default;
+
+void CertPath::Clear() {
+ trust_anchor = nullptr;
+ certs.clear();
+}
+
+bool CertPath::IsEmpty() const {
+ return certs.empty();
+}
+
+// CertPathIter generates possible paths from |cert| to a trust anchor in
+// |trust_store|, using intermediates from the |cert_issuer_source| objects if
+// necessary.
+class CertPathIter {
+ public:
+ CertPathIter(scoped_refptr<ParsedCertificate> cert,
+ const TrustStore* trust_store);
+
+ // Adds a CertIssuerSource to provide intermediates for use in path building.
+ // The |*cert_issuer_source| must remain valid for the lifetime of the
+ // CertPathIter.
+ void AddCertIssuerSource(CertIssuerSource* cert_issuer_source);
+
+ // Gets the next candidate path. If a path is ready synchronously, SYNC is
+ // returned and the path is stored in |*path|. If a path is not ready,
+ // ASYNC is returned and |callback| will be called once |*path| has been set.
+ // In either case, if all paths have been exhausted, |*path| is cleared.
+ CompletionStatus GetNextPath(CertPath* path, const base::Closure& callback);
+
+ private:
+ enum State {
+ STATE_NONE,
+ STATE_GET_NEXT_ISSUER,
+ STATE_GET_NEXT_ISSUER_COMPLETE,
+ STATE_RETURN_A_PATH,
+ STATE_BACKTRACK,
+ };
+
+ CompletionStatus DoLoop(bool allow_async);
+
+ CompletionStatus DoGetNextIssuer(bool allow_async);
+ CompletionStatus DoGetNextIssuerComplete();
+ CompletionStatus DoBackTrack();
+
+ void HandleGotNextIssuer(void);
+
+ // Stores the next candidate issuer, until it is used during the
+ // STATE_GET_NEXT_ISSUER_COMPLETE step.
+ CertificateOrTrustAnchor next_issuer_;
+ // The current path being explored, made up of CertIssuerIters. Each node
+ // keeps track of the state of searching for issuers of that cert, so that
+ // when backtracking it can resume the search where it left off.
+ CertIssuerIterPath cur_path_;
+ // The CertIssuerSources for retrieving candidate issuers.
+ CertIssuerSources cert_issuer_sources_;
+ // The TrustStore for checking if a path ends in a trust anchor.
+ const TrustStore* trust_store_;
+ // The output variable for storing the next candidate path, which the client
+ // passes in to GetNextPath. Only used for a single path output.
+ CertPath* out_path_;
+ // The callback to be called if an async lookup generated a candidate path.
+ base::Closure callback_;
+ // Current state of the state machine.
+ State next_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(CertPathIter);
+};
+
+CertPathIter::CertPathIter(scoped_refptr<ParsedCertificate> cert,
+ const TrustStore* trust_store)
+ : next_issuer_(std::move(cert)),
+ trust_store_(trust_store),
+ next_state_(STATE_GET_NEXT_ISSUER_COMPLETE) {}
+
+void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) {
+ cert_issuer_sources_.push_back(cert_issuer_source);
+}
+
+CompletionStatus CertPathIter::GetNextPath(CertPath* path,
+ const base::Closure& callback) {
+ out_path_ = path;
+ out_path_->Clear();
+ CompletionStatus rv = DoLoop(!callback.is_null());
+ if (rv == CompletionStatus::ASYNC) {
+ callback_ = callback;
+ } else {
+ // Clear the reference to the output parameter as a precaution.
+ out_path_ = nullptr;
+ }
+ return rv;
+}
+
+CompletionStatus CertPathIter::DoLoop(bool allow_async) {
+ CompletionStatus result = CompletionStatus::SYNC;
+ do {
+ State state = next_state_;
+ next_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_NONE:
+ NOTREACHED();
+ break;
+ case STATE_GET_NEXT_ISSUER:
+ result = DoGetNextIssuer(allow_async);
+ break;
+ case STATE_GET_NEXT_ISSUER_COMPLETE:
+ result = DoGetNextIssuerComplete();
+ break;
+ case STATE_RETURN_A_PATH:
+ // If the returned path did not verify, keep looking for other paths
+ // (the trust root is not part of cur_path_, so don't need to
+ // backtrack).
+ next_state_ = STATE_GET_NEXT_ISSUER;
+ result = CompletionStatus::SYNC;
+ break;
+ case STATE_BACKTRACK:
+ result = DoBackTrack();
+ break;
+ }
+ } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE &&
+ next_state_ != STATE_RETURN_A_PATH);
+
+ return result;
+}
+
+CompletionStatus CertPathIter::DoGetNextIssuer(bool allow_async) {
+ next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE;
+ CompletionStatus rv = cur_path_.back()->GetNextIssuer(
+ &next_issuer_, allow_async
+ ? base::Bind(&CertPathIter::HandleGotNextIssuer,
+ base::Unretained(this))
+ : base::Closure());
+ return rv;
+}
+
+CompletionStatus CertPathIter::DoGetNextIssuerComplete() {
+ // If the issuer is a trust anchor signal readiness.
+ if (next_issuer_.IsTrustAnchor()) {
+ DVLOG(1) << "CertPathIter got anchor("
+ << CertDebugString(next_issuer_.anchor->cert().get());
+ next_state_ = STATE_RETURN_A_PATH;
+ cur_path_.CopyPath(&out_path_->certs);
+ out_path_->trust_anchor = std::move(next_issuer_.anchor);
+ next_issuer_ = CertificateOrTrustAnchor();
+ return CompletionStatus::SYNC;
+ }
+
+ if (next_issuer_.IsCertificate()) {
+ // Skip this cert if it is already in the chain.
+ if (cur_path_.IsPresent(next_issuer_.cert.get())) {
+ next_state_ = STATE_GET_NEXT_ISSUER;
+ return CompletionStatus::SYNC;
+ }
+
+ cur_path_.Append(base::MakeUnique<CertIssuersIter>(
+ std::move(next_issuer_.cert), &cert_issuer_sources_, trust_store_));
+ next_issuer_ = CertificateOrTrustAnchor();
+ DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString();
+ // Continue descending the tree.
+ next_state_ = STATE_GET_NEXT_ISSUER;
+ } else {
+ // TODO(mattm): should also include such paths in CertPathBuilder::Result,
+ // maybe with a flag to enable it. Or use a visitor pattern so the caller
+ // can decide what to do with any failed paths.
+ // No more issuers for current chain, go back up and see if there are any
+ // more for the previous cert.
+ next_state_ = STATE_BACKTRACK;
+ }
+ return CompletionStatus::SYNC;
+}
+
+CompletionStatus CertPathIter::DoBackTrack() {
+ DVLOG(1) << "CertPathIter backtracking...";
+ cur_path_.Pop();
+ if (cur_path_.Empty()) {
+ // Exhausted all paths.
+ next_state_ = STATE_NONE;
+ } else {
+ // Continue exploring issuers of the previous path.
+ next_state_ = STATE_GET_NEXT_ISSUER;
+ }
+ return CompletionStatus::SYNC;
+}
+
+void CertPathIter::HandleGotNextIssuer(void) {
+ DCHECK(!callback_.is_null());
+ CompletionStatus rv = DoLoop(true /* allow_async */);
+ if (rv == CompletionStatus::SYNC) {
+ // Clear the reference to the output parameter as a precaution.
+ out_path_ = nullptr;
+ base::ResetAndReturn(&callback_).Run();
+ }
+}
+
+CertPathBuilder::ResultPath::ResultPath() = default;
+CertPathBuilder::ResultPath::~ResultPath() = default;
+CertPathBuilder::Result::Result() = default;
+CertPathBuilder::Result::~Result() = default;
+
+const CertPathBuilder::ResultPath* CertPathBuilder::Result::GetBestValidPath()
+ const {
+ DCHECK((paths.empty() && best_result_index == 0) ||
+ best_result_index < paths.size());
+
+ if (best_result_index >= paths.size())
+ return nullptr;
+
+ const ResultPath* result_path = paths[best_result_index].get();
+ if (result_path->valid)
+ return result_path;
+
+ return nullptr;
+}
+
+bool CertPathBuilder::Result::HasValidPath() const {
+ return GetBestValidPath() != nullptr;
+}
+
+CertPathBuilder::CertPathBuilder(scoped_refptr<ParsedCertificate> cert,
+ const TrustStore* trust_store,
+ const SignaturePolicy* signature_policy,
+ const der::GeneralizedTime& time,
+ Result* result)
+ : cert_path_iter_(new CertPathIter(std::move(cert), trust_store)),
+ signature_policy_(signature_policy),
+ time_(time),
+ next_state_(STATE_NONE),
+ out_result_(result) {}
+
+CertPathBuilder::~CertPathBuilder() {}
+
+void CertPathBuilder::AddCertIssuerSource(
+ CertIssuerSource* cert_issuer_source) {
+ cert_path_iter_->AddCertIssuerSource(cert_issuer_source);
+}
+
+CompletionStatus CertPathBuilder::Run(const base::Closure& callback) {
+ DCHECK_EQ(STATE_NONE, next_state_);
+ next_state_ = STATE_GET_NEXT_PATH;
+ CompletionStatus rv = DoLoop(!callback.is_null());
+
+ if (rv == CompletionStatus::ASYNC)
+ callback_ = callback;
+
+ return rv;
+}
+
+CompletionStatus CertPathBuilder::DoLoop(bool allow_async) {
+ CompletionStatus result = CompletionStatus::SYNC;
+
+ do {
+ State state = next_state_;
+ next_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_NONE:
+ NOTREACHED();
+ break;
+ case STATE_GET_NEXT_PATH:
+ result = DoGetNextPath(allow_async);
+ break;
+ case STATE_GET_NEXT_PATH_COMPLETE:
+ result = DoGetNextPathComplete();
+ break;
+ }
+ } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE);
+
+ return result;
+}
+
+CompletionStatus CertPathBuilder::DoGetNextPath(bool allow_async) {
+ next_state_ = STATE_GET_NEXT_PATH_COMPLETE;
+ CompletionStatus rv = cert_path_iter_->GetNextPath(
+ &next_path_, allow_async ? base::Bind(&CertPathBuilder::HandleGotNextPath,
+ base::Unretained(this))
+ : base::Closure());
+ return rv;
+}
+
+void CertPathBuilder::HandleGotNextPath() {
+ DCHECK(!callback_.is_null());
+ CompletionStatus rv = DoLoop(true /* allow_async */);
+ if (rv == CompletionStatus::SYNC)
+ base::ResetAndReturn(&callback_).Run();
+}
+
+CompletionStatus CertPathBuilder::DoGetNextPathComplete() {
+ if (next_path_.IsEmpty()) {
+ // No more paths to check, signal completion.
+ next_state_ = STATE_NONE;
+ return CompletionStatus::SYNC;
+ }
+
+ // Verify the entire certificate chain.
+ auto result_path = base::MakeUnique<ResultPath>();
+ bool verify_result =
+ VerifyCertificateChain(next_path_.certs, next_path_.trust_anchor.get(),
+ signature_policy_, time_, &result_path->errors);
+ DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = "
+ << result_path->valid;
+ result_path->path = next_path_;
+ result_path->valid = verify_result;
+ AddResultPath(std::move(result_path));
+
+ if (verify_result) {
+ // Found a valid path, return immediately.
+ // TODO(mattm): add debug/test mode that tries all possible paths.
+ next_state_ = STATE_NONE;
+ return CompletionStatus::SYNC;
+ }
+
+ // Path did not verify. Try more paths. If there are no more paths, the result
+ // will be returned next time DoGetNextPathComplete is called with next_path_
+ // empty.
+ next_state_ = STATE_GET_NEXT_PATH;
+ return CompletionStatus::SYNC;
+}
+
+void CertPathBuilder::AddResultPath(std::unique_ptr<ResultPath> result_path) {
+ // TODO(mattm): set best_result_index based on number or severity of errors.
+ if (result_path->valid)
+ out_result_->best_result_index = out_result_->paths.size();
+ // TODO(mattm): add flag to only return a single path or all attempted paths?
+ out_result_->paths.push_back(std::move(result_path));
+}
+
+} // namespace net
diff --git a/chromium/net/cert/internal/path_builder.h b/chromium/net/cert/internal/path_builder.h
new file mode 100644
index 00000000000..69784f333b0
--- /dev/null
+++ b/chromium/net/cert/internal/path_builder.h
@@ -0,0 +1,188 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_CERT_INTERNAL_PATH_BUILDER_H_
+#define NET_CERT_INTERNAL_PATH_BUILDER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
+#include "net/cert/internal/cert_errors.h"
+#include "net/cert/internal/completion_status.h"
+#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/trust_store.h"
+#include "net/der/input.h"
+#include "net/der/parse_values.h"
+
+namespace net {
+
+namespace der {
+struct GeneralizedTime;
+}
+
+class CertPathIter;
+class CertIssuerSource;
+class SignaturePolicy;
+
+// CertPath describes a chain of certificates in the "forward" direction.
+//
+// By convention:
+// certs[0] is the target certificate
+// certs[i] was issued by certs[i+1]
+// certs.back() was issued by trust_anchor
+struct NET_EXPORT CertPath {
+ CertPath();
+ ~CertPath();
+
+ scoped_refptr<TrustAnchor> trust_anchor;
+
+ // Path in the forward direction (path[0] is the target cert).
+ ParsedCertificateList certs;
+
+ // Resets the path to empty path (same as if default constructed).
+ void Clear();
+
+ // Returns true if the path is empty.
+ bool IsEmpty() const;
+};
+
+// Checks whether a certificate is trusted by building candidate paths to trust
+// anchors and verifying those paths according to RFC 5280. Each instance of
+// CertPathBuilder is used for a single verification.
+//
+// WARNING: This implementation is currently experimental. Consult an OWNER
+// before using it.
+class NET_EXPORT CertPathBuilder {
+ public:
+ // Represents a single candidate path that was built.
+ struct NET_EXPORT ResultPath {
+ ResultPath();
+ ~ResultPath();
+
+ // The (possibly partial) certificate path. Consumers must always test
+ // |valid| before using |path|. When |!valid| path.trust_anchor may be
+ // nullptr, and the path may be otherwise incomplete/invalid.
+ CertPath path;
+
+ // The errors/warnings from this path. Note that the list of errors is
+ // independent of whether the path was |valid| (a valid path may
+ // contain errors/warnings, and vice versa an invalid path may not have
+ // logged any errors).
+ CertErrors errors;
+
+ // True if |path| is a correct verified certificate chain.
+ bool valid = false;
+ };
+
+ // Provides the overall result of path building. This includes the paths that
+ // were attempted.
+ struct NET_EXPORT Result {
+ Result();
+ ~Result();
+
+ // Returns true if there was a valid path.
+ bool HasValidPath() const;
+
+ // Returns the ResultPath for the best valid path, or nullptr if there
+ // was none.
+ const ResultPath* GetBestValidPath() const;
+
+ // List of paths that were attempted and the result for each.
+ std::vector<std::unique_ptr<ResultPath>> paths;
+
+ // Index into |paths|. Before use, |paths.empty()| must be checked.
+ // NOTE: currently the definition of "best" is fairly limited. Valid is
+ // better than invalid, but otherwise nothing is guaranteed.
+ size_t best_result_index = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Result);
+ };
+
+ // TODO(mattm): allow caller specified hook/callback to extend path
+ // verification.
+ //
+ // Creates a CertPathBuilder that attempts to find a path from |cert| to a
+ // trust anchor in |trust_store|, which satisfies |signature_policy| and is
+ // valid at |time|. Details of attempted path(s) are stored in |*result|.
+ //
+ // The caller must keep |trust_store|, |signature_policy|, and |*result| valid
+ // for the lifetime of the CertPathBuilder.
+ CertPathBuilder(scoped_refptr<ParsedCertificate> cert,
+ const TrustStore* trust_store,
+ const SignaturePolicy* signature_policy,
+ const der::GeneralizedTime& time,
+ Result* result);
+ ~CertPathBuilder();
+
+ // Adds a CertIssuerSource to provide intermediates for use in path building.
+ // Multiple sources may be added. Must not be called after Run is called.
+ // The |*cert_issuer_source| must remain valid for the lifetime of the
+ // CertPathBuilder.
+ //
+ // (If no issuer sources are added, the target certificate will only verify if
+ // it is a trust anchor or is directly signed by a trust anchor.)
+ void AddCertIssuerSource(CertIssuerSource* cert_issuer_source);
+
+ // Begins verification of the target certificate.
+ //
+ // If the return value is SYNC then the verification is complete and the
+ // |result| value can be inspected for the status, and |callback| will not be
+ // called.
+ // If the return value is ASYNC, the |callback| will be called asynchronously
+ // once the verification is complete. |result| should not be examined or
+ // modified until the |callback| is run.
+ //
+ // If |callback| is null, verification always completes synchronously, even if
+ // it fails to find a valid path and one could have been found asynchronously.
+ //
+ // The CertPathBuilder may be deleted while an ASYNC verification is pending,
+ // in which case the verification is cancelled, |callback| will not be called,
+ // and the output Result will be in an undefined state.
+ // It is safe to delete the CertPathBuilder during the |callback|.
+ // Run must not be called more than once on each CertPathBuilder instance.
+ CompletionStatus Run(const base::Closure& callback);
+
+ private:
+ enum State {
+ STATE_NONE,
+ STATE_GET_NEXT_PATH,
+ STATE_GET_NEXT_PATH_COMPLETE,
+ };
+
+ CompletionStatus DoLoop(bool allow_async);
+
+ CompletionStatus DoGetNextPath(bool allow_async);
+ void HandleGotNextPath();
+ CompletionStatus DoGetNextPathComplete();
+
+ void AddResultPath(std::unique_ptr<ResultPath> result_path);
+
+ base::Closure callback_;
+
+ std::unique_ptr<CertPathIter> cert_path_iter_;
+ const SignaturePolicy* signature_policy_;
+ const der::GeneralizedTime time_;
+
+ // Stores the next complete path to attempt verification on. This is filled in
+ // by |cert_path_iter_| during the STATE_GET_NEXT_PATH step, and thus should
+ // only be accessed during the STATE_GET_NEXT_PATH_COMPLETE step.
+ // (Will be empty if all paths have been tried, otherwise will be a candidate
+ // path starting with the target cert and ending with a
+ // certificate issued by trust anchor.)
+ CertPath next_path_;
+ State next_state_;
+
+ Result* out_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(CertPathBuilder);
+};
+
+} // namespace net
+
+#endif // NET_CERT_INTERNAL_PATH_BUILDER_H_
diff --git a/chromium/net/cert/internal/path_builder_pkits_unittest.cc b/chromium/net/cert/internal/path_builder_pkits_unittest.cc
new file mode 100644
index 00000000000..4039428687e
--- /dev/null
+++ b/chromium/net/cert/internal/path_builder_pkits_unittest.cc
@@ -0,0 +1,231 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/path_builder.h"
+
+#include "net/base/net_errors.h"
+#include "net/cert/internal/cert_issuer_source_static.h"
+#include "net/cert/internal/parse_certificate.h"
+#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/signature_policy.h"
+#include "net/cert/internal/trust_store_in_memory.h"
+#include "net/cert/internal/verify_certificate_chain.h"
+#include "net/der/input.h"
+
+// Disable tests that require DSA signatures (DSA signatures are intentionally
+// unsupported). Custom versions of the DSA tests are defined below which expect
+// verification to fail.
+#define Section1ValidDSASignaturesTest4 DISABLED_Section1ValidDSASignaturesTest4
+#define Section1ValidDSAParameterInheritanceTest5 \
+ DISABLED_Section1ValidDSAParameterInheritanceTest5
+
+// Disable tests that require name constraints with name types that are
+// intentionally unsupported. Custom versions of the tests are defined below
+// which expect verification to fail.
+#define Section13ValidRFC822nameConstraintsTest21 \
+ DISABLED_Section13ValidRFC822nameConstraintsTest21
+#define Section13ValidRFC822nameConstraintsTest23 \
+ DISABLED_Section13ValidRFC822nameConstraintsTest23
+#define Section13ValidRFC822nameConstraintsTest25 \
+ DISABLED_Section13ValidRFC822nameConstraintsTest25
+#define Section13ValidDNandRFC822nameConstraintsTest27 \
+ DISABLED_Section13ValidDNandRFC822nameConstraintsTest27
+#define Section13ValidURInameConstraintsTest34 \
+ DISABLED_Section13ValidURInameConstraintsTest34
+#define Section13ValidURInameConstraintsTest36 \
+ DISABLED_Section13ValidURInameConstraintsTest36
+
+// TODO(mattm): these require CRL support:
+#define Section7InvalidkeyUsageCriticalcRLSignFalseTest4 \
+ DISABLED_Section7InvalidkeyUsageCriticalcRLSignFalseTest4
+#define Section7InvalidkeyUsageNotCriticalcRLSignFalseTest5 \
+ DISABLED_Section7InvalidkeyUsageNotCriticalcRLSignFalseTest5
+
+#include "net/cert/internal/nist_pkits_unittest.h"
+
+namespace net {
+
+namespace {
+
+class PathBuilderPkitsTestDelegate {
+ public:
+ static bool Verify(std::vector<std::string> cert_ders,
+ std::vector<std::string> crl_ders) {
+ if (cert_ders.empty()) {
+ ADD_FAILURE() << "cert_ders is empty";
+ return false;
+ }
+ ParsedCertificateList certs;
+ for (const std::string& der : cert_ders) {
+ CertErrors errors;
+ if (!ParsedCertificate::CreateAndAddToVector(der, {}, &certs, &errors)) {
+ ADD_FAILURE() << "ParseCertificate::CreateAndAddToVector() failed:\n"
+ << errors.ToDebugString();
+ return false;
+ }
+ }
+ // First entry in the PKITS chain is the trust anchor.
+ // TODO(mattm): test with all possible trust anchors in the trust store?
+ TrustStoreInMemory trust_store;
+
+ scoped_refptr<TrustAnchor> trust_anchor =
+ TrustAnchor::CreateFromCertificateNoConstraints(certs[0]);
+ trust_store.AddTrustAnchor(std::move(trust_anchor));
+
+ // TODO(mattm): test with other irrelevant certs in cert_issuer_sources?
+ CertIssuerSourceStatic cert_issuer_source;
+ for (size_t i = 1; i < cert_ders.size() - 1; ++i)
+ cert_issuer_source.AddCert(certs[i]);
+
+ scoped_refptr<ParsedCertificate> target_cert(certs.back());
+
+ SimpleSignaturePolicy signature_policy(1024);
+
+ // Run all tests at the time the PKITS was published.
+ der::GeneralizedTime time = {2011, 4, 15, 0, 0, 0};
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(std::move(target_cert), &trust_store,
+ &signature_policy, time, &result);
+ path_builder.AddCertIssuerSource(&cert_issuer_source);
+
+ CompletionStatus rv = path_builder.Run(base::Closure());
+ EXPECT_EQ(CompletionStatus::SYNC, rv);
+
+ return result.HasValidPath();
+ }
+};
+
+} // namespace
+
+class PkitsTest01SignatureVerificationCustomPathBuilderFoo
+ : public PkitsTest<PathBuilderPkitsTestDelegate> {};
+
+// Modified version of 4.1.4 Valid DSA Signatures Test4
+TEST_F(PkitsTest01SignatureVerificationCustomPathBuilderFoo,
+ Section1ValidDSASignaturesTest4Custom) {
+ const char* const certs[] = {"TrustAnchorRootCertificate", "DSACACert",
+ "ValidDSASignaturesTest4EE"};
+ const char* const crls[] = {"TrustAnchorRootCRL", "DSACACRL"};
+ // DSA signatures are intentionally unsupported.
+ ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+// Modified version of 4.1.5 Valid DSA Parameter Inheritance Test5
+TEST_F(PkitsTest01SignatureVerificationCustomPathBuilderFoo,
+ Section1ValidDSAParameterInheritanceTest5Custom) {
+ const char* const certs[] = {"TrustAnchorRootCertificate", "DSACACert",
+ "DSAParametersInheritedCACert",
+ "ValidDSAParameterInheritanceTest5EE"};
+ const char* const crls[] = {"TrustAnchorRootCRL", "DSACACRL",
+ "DSAParametersInheritedCACRL"};
+ // DSA signatures are intentionally unsupported.
+ ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+class PkitsTest13SignatureVerificationCustomPathBuilderFoo
+ : public PkitsTest<PathBuilderPkitsTestDelegate> {};
+
+// Modified version of 4.13.21 Valid RFC822 nameConstraints Test21
+TEST_F(PkitsTest13SignatureVerificationCustomPathBuilderFoo,
+ Section13ValidRFC822nameConstraintsTest21Custom) {
+ const char* const certs[] = {"TrustAnchorRootCertificate",
+ "nameConstraintsRFC822CA1Cert",
+ "ValidRFC822nameConstraintsTest21EE"};
+ const char* const crls[] = {"TrustAnchorRootCRL",
+ "nameConstraintsRFC822CA1CRL"};
+ // Name constraints on rfc822Names are not supported.
+ ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+// Modified version of 4.13.23 Valid RFC822 nameConstraints Test23
+TEST_F(PkitsTest13SignatureVerificationCustomPathBuilderFoo,
+ Section13ValidRFC822nameConstraintsTest23Custom) {
+ const char* const certs[] = {"TrustAnchorRootCertificate",
+ "nameConstraintsRFC822CA2Cert",
+ "ValidRFC822nameConstraintsTest23EE"};
+ const char* const crls[] = {"TrustAnchorRootCRL",
+ "nameConstraintsRFC822CA2CRL"};
+ // Name constraints on rfc822Names are not supported.
+ ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+// Modified version of 4.13.25 Valid RFC822 nameConstraints Test25
+TEST_F(PkitsTest13SignatureVerificationCustomPathBuilderFoo,
+ Section13ValidRFC822nameConstraintsTest25Custom) {
+ const char* const certs[] = {"TrustAnchorRootCertificate",
+ "nameConstraintsRFC822CA3Cert",
+ "ValidRFC822nameConstraintsTest25EE"};
+ const char* const crls[] = {"TrustAnchorRootCRL",
+ "nameConstraintsRFC822CA3CRL"};
+ // Name constraints on rfc822Names are not supported.
+ ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+// Modified version of 4.13.27 Valid DN and RFC822 nameConstraints Test27
+TEST_F(PkitsTest13SignatureVerificationCustomPathBuilderFoo,
+ Section13ValidDNandRFC822nameConstraintsTest27Custom) {
+ const char* const certs[] = {"TrustAnchorRootCertificate",
+ "nameConstraintsDN1CACert",
+ "nameConstraintsDN1subCA3Cert",
+ "ValidDNandRFC822nameConstraintsTest27EE"};
+ const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL",
+ "nameConstraintsDN1subCA3CRL"};
+ // Name constraints on rfc822Names are not supported.
+ ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+// Modified version of 4.13.34 Valid URI nameConstraints Test34
+TEST_F(PkitsTest13SignatureVerificationCustomPathBuilderFoo,
+ Section13ValidURInameConstraintsTest34Custom) {
+ const char* const certs[] = {"TrustAnchorRootCertificate",
+ "nameConstraintsURI1CACert",
+ "ValidURInameConstraintsTest34EE"};
+ const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsURI1CACRL"};
+ // Name constraints on uniformResourceIdentifiers are not supported.
+ ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+// Modified version of 4.13.36 Valid URI nameConstraints Test36
+TEST_F(PkitsTest13SignatureVerificationCustomPathBuilderFoo,
+ Section13ValidURInameConstraintsTest36Custom) {
+ const char* const certs[] = {"TrustAnchorRootCertificate",
+ "nameConstraintsURI2CACert",
+ "ValidURInameConstraintsTest36EE"};
+ const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsURI2CACRL"};
+ // Name constraints on uniformResourceIdentifiers are not supported.
+ ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+ PkitsTest01SignatureVerification,
+ PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+ PkitsTest02ValidityPeriods,
+ PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+ PkitsTest03VerifyingNameChaining,
+ PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+ PkitsTest06VerifyingBasicConstraints,
+ PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+ PkitsTest07KeyUsage,
+ PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+ PkitsTest13NameConstraints,
+ PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+ PkitsTest16PrivateCertificateExtensions,
+ PathBuilderPkitsTestDelegate);
+
+// TODO(mattm): CRL support: PkitsTest04BasicCertificateRevocationTests,
+// PkitsTest05VerifyingPathswithSelfIssuedCertificates,
+// PkitsTest14DistributionPoints, PkitsTest15DeltaCRLs
+
+// TODO(mattm): Certificate Policies support: PkitsTest08CertificatePolicies,
+// PkitsTest09RequireExplicitPolicy PkitsTest10PolicyMappings,
+// PkitsTest11InhibitPolicyMapping, PkitsTest12InhibitAnyPolicy
+
+} // namespace net
diff --git a/chromium/net/cert/internal/path_builder_unittest.cc b/chromium/net/cert/internal/path_builder_unittest.cc
new file mode 100644
index 00000000000..5f0a2eb6234
--- /dev/null
+++ b/chromium/net/cert/internal/path_builder_unittest.cc
@@ -0,0 +1,1297 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/path_builder.h"
+
+#include "base/base_paths.h"
+#include "base/cancelable_callback.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
+#include "base/path_service.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "net/base/test_completion_callback.h"
+#include "net/cert/internal/cert_issuer_source_static.h"
+#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/signature_policy.h"
+#include "net/cert/internal/test_helpers.h"
+#include "net/cert/internal/trust_store_in_memory.h"
+#include "net/cert/internal/trust_store_test_helpers.h"
+#include "net/cert/internal/verify_certificate_chain.h"
+#include "net/cert/pem_tokenizer.h"
+#include "net/der/input.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/test_certificate_data.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+// TODO(crbug.com/634443): Assert the errors for each ResultPath.
+
+namespace {
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::SetArgPointee;
+using ::testing::StrictMock;
+
+// AsyncCertIssuerSourceStatic always returns its certs asynchronously.
+class AsyncCertIssuerSourceStatic : public CertIssuerSource {
+ public:
+ class StaticAsyncRequest : public Request {
+ public:
+ StaticAsyncRequest(const IssuerCallback& issuers_callback,
+ ParsedCertificateList&& issuers)
+ : cancelable_closure_(base::Bind(&StaticAsyncRequest::RunCallback,
+ base::Unretained(this))),
+ issuers_callback_(issuers_callback) {
+ issuers_.swap(issuers);
+ issuers_iter_ = issuers_.begin();
+ }
+ ~StaticAsyncRequest() override {}
+
+ CompletionStatus GetNext(
+ scoped_refptr<ParsedCertificate>* out_cert) override {
+ if (issuers_iter_ == issuers_.end())
+ *out_cert = nullptr;
+ else
+ *out_cert = std::move(*issuers_iter_++);
+ return CompletionStatus::SYNC;
+ }
+
+ base::Closure callback() { return cancelable_closure_.callback(); }
+
+ private:
+ void RunCallback() { issuers_callback_.Run(this); }
+
+ base::CancelableClosure cancelable_closure_;
+ IssuerCallback issuers_callback_;
+ ParsedCertificateList issuers_;
+ ParsedCertificateList::iterator issuers_iter_;
+
+ DISALLOW_COPY_AND_ASSIGN(StaticAsyncRequest);
+ };
+
+ ~AsyncCertIssuerSourceStatic() override {}
+
+ void AddCert(scoped_refptr<ParsedCertificate> cert) {
+ static_cert_issuer_source_.AddCert(std::move(cert));
+ }
+
+ void SyncGetIssuersOf(const ParsedCertificate* cert,
+ ParsedCertificateList* issuers) override {}
+ void AsyncGetIssuersOf(const ParsedCertificate* cert,
+ const IssuerCallback& issuers_callback,
+ std::unique_ptr<Request>* out_req) override {
+ num_async_gets_++;
+ ParsedCertificateList issuers;
+ static_cert_issuer_source_.SyncGetIssuersOf(cert, &issuers);
+ std::unique_ptr<StaticAsyncRequest> req(
+ new StaticAsyncRequest(issuers_callback, std::move(issuers)));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, req->callback());
+ *out_req = std::move(req);
+ }
+ int num_async_gets() const { return num_async_gets_; }
+
+ private:
+ CertIssuerSourceStatic static_cert_issuer_source_;
+
+ int num_async_gets_ = 0;
+};
+
+::testing::AssertionResult ReadTestPem(const std::string& file_name,
+ const std::string& block_name,
+ std::string* result) {
+ const PemBlockMapping mappings[] = {
+ {block_name.c_str(), result},
+ };
+
+ return ReadTestDataFromPemFile(file_name, mappings);
+}
+
+::testing::AssertionResult ReadTestCert(
+ const std::string& file_name,
+ scoped_refptr<ParsedCertificate>* result) {
+ std::string der;
+ ::testing::AssertionResult r = ReadTestPem(
+ "net/data/ssl/certificates/" + file_name, "CERTIFICATE", &der);
+ if (!r)
+ return r;
+ CertErrors errors;
+ *result = ParsedCertificate::Create(der, {}, &errors);
+ if (!*result) {
+ return ::testing::AssertionFailure()
+ << "ParseCertificate::Create() failed:\n"
+ << errors.ToDebugString();
+ }
+ return ::testing::AssertionSuccess();
+}
+
+// Run the path builder, and wait for async completion if necessary. The return
+// value signifies whether the path builder completed synchronously or
+// asynchronously, not that RunPathBuilder itself is asynchronous.
+CompletionStatus RunPathBuilder(CertPathBuilder* path_builder) {
+ TestClosure callback;
+ CompletionStatus rv = path_builder->Run(callback.closure());
+
+ if (rv == CompletionStatus::ASYNC) {
+ DVLOG(1) << "waiting for async completion...";
+ callback.WaitForResult();
+ DVLOG(1) << "async completed.";
+ }
+ return rv;
+}
+
+class PathBuilderMultiRootTest : public ::testing::Test {
+ public:
+ PathBuilderMultiRootTest() : signature_policy_(1024) {}
+
+ void SetUp() override {
+ ASSERT_TRUE(ReadTestCert("multi-root-A-by-B.pem", &a_by_b_));
+ ASSERT_TRUE(ReadTestCert("multi-root-B-by-C.pem", &b_by_c_));
+ ASSERT_TRUE(ReadTestCert("multi-root-B-by-F.pem", &b_by_f_));
+ ASSERT_TRUE(ReadTestCert("multi-root-C-by-D.pem", &c_by_d_));
+ ASSERT_TRUE(ReadTestCert("multi-root-C-by-E.pem", &c_by_e_));
+ ASSERT_TRUE(ReadTestCert("multi-root-D-by-D.pem", &d_by_d_));
+ ASSERT_TRUE(ReadTestCert("multi-root-E-by-E.pem", &e_by_e_));
+ ASSERT_TRUE(ReadTestCert("multi-root-F-by-E.pem", &f_by_e_));
+ }
+
+ protected:
+ scoped_refptr<ParsedCertificate> a_by_b_, b_by_c_, b_by_f_, c_by_d_, c_by_e_,
+ d_by_d_, e_by_e_, f_by_e_;
+
+ SimpleSignaturePolicy signature_policy_;
+ der::GeneralizedTime time_ = {2016, 4, 11, 0, 0, 0};
+};
+
+void AddTrustedCertificate(scoped_refptr<ParsedCertificate> cert,
+ TrustStoreInMemory* trust_store) {
+ ASSERT_TRUE(cert.get());
+ scoped_refptr<TrustAnchor> anchor =
+ TrustAnchor::CreateFromCertificateNoConstraints(std::move(cert));
+ ASSERT_TRUE(anchor.get());
+ trust_store->AddTrustAnchor(std::move(anchor));
+}
+
+// If the target cert is has the same name and key as a trust anchor, however
+// is signed but a different trust anchor. This should successfully build a
+// path, however the trust anchor will be the signer of this cert.
+//
+// (This test is very similar to TestEndEntityHasSameNameAndSpkiAsTrustAnchor
+// but with different data; also in this test the target cert itself is in the
+// trust store).
+TEST_F(PathBuilderMultiRootTest, TargetHasNameAndSpkiOfTrustAnchor) {
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(a_by_b_, &trust_store);
+ AddTrustedCertificate(b_by_f_, &trust_store);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
+ &result);
+
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+ ASSERT_TRUE(result.HasValidPath());
+ const auto& path = result.GetBestValidPath()->path;
+ ASSERT_EQ(1U, path.certs.size());
+ EXPECT_EQ(a_by_b_, path.certs[0]);
+ EXPECT_EQ(b_by_f_, path.trust_anchor->cert());
+}
+
+// If the target cert is has the same name and key as a trust anchor, however
+// is NOT itself signed by a trust anchor, it fails. Although the provided SPKI
+// is trusted, the certificate contents cannot be verified.
+TEST_F(PathBuilderMultiRootTest, TargetWithSameNameAsTrustAnchorFails) {
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(a_by_b_, &trust_store);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
+ &result);
+
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+ EXPECT_FALSE(result.HasValidPath());
+}
+
+// Test a failed path building when the trust anchor is provided as a
+// supplemental certificate. Conceptually the following paths can be built:
+//
+// B(C) <- C(D) <- [Trust anchor D]
+// B(C) <- C(D) <- D(D) <- [Trust anchor D]
+//
+// The second one is extraneous given the shorter one, however path building
+// will enumerate it if the shorter one failed validation.
+TEST_F(PathBuilderMultiRootTest, SelfSignedTrustAnchorSupplementalCert) {
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(d_by_d_, &trust_store);
+
+ // The (extraneous) trust anchor D(D) is supplied as a certificate, as is the
+ // intermediate needed for path building C(D).
+ CertIssuerSourceStatic sync_certs;
+ sync_certs.AddCert(d_by_d_);
+ sync_certs.AddCert(c_by_d_);
+
+ // C(D) is not valid at this time, so path building will fail.
+ der::GeneralizedTime expired_time = {2016, 1, 1, 0, 0, 0};
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(b_by_c_, &trust_store, &signature_policy_,
+ expired_time, &result);
+ path_builder.AddCertIssuerSource(&sync_certs);
+
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+ EXPECT_FALSE(result.HasValidPath());
+ ASSERT_EQ(2U, result.paths.size());
+
+ EXPECT_FALSE(result.paths[0]->valid);
+ const auto& path0 = result.paths[0]->path;
+ ASSERT_EQ(2U, path0.certs.size());
+ EXPECT_EQ(b_by_c_, path0.certs[0]);
+ EXPECT_EQ(c_by_d_, path0.certs[1]);
+ EXPECT_EQ(d_by_d_, path0.trust_anchor->cert());
+
+ const auto& path1 = result.paths[1]->path;
+ ASSERT_EQ(3U, path1.certs.size());
+ EXPECT_EQ(b_by_c_, path1.certs[0]);
+ EXPECT_EQ(c_by_d_, path1.certs[1]);
+ EXPECT_EQ(d_by_d_, path1.certs[2]);
+ EXPECT_EQ(d_by_d_, path1.trust_anchor->cert());
+}
+
+// If the target cert is a self-signed cert whose key is a trust anchor, it
+// should verify.
+TEST_F(PathBuilderMultiRootTest, TargetIsSelfSignedTrustAnchor) {
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(e_by_e_, &trust_store);
+ // This is not necessary for the test, just an extra...
+ AddTrustedCertificate(f_by_e_, &trust_store);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(e_by_e_, &trust_store, &signature_policy_, time_,
+ &result);
+
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+ ASSERT_TRUE(result.HasValidPath());
+ const auto& path = result.GetBestValidPath()->path;
+ ASSERT_EQ(1U, path.certs.size());
+ EXPECT_EQ(e_by_e_, path.certs[0]);
+ EXPECT_EQ(e_by_e_, path.trust_anchor->cert());
+}
+
+// If the target cert is directly issued by a trust anchor, it should verify
+// without any intermediate certs being provided.
+TEST_F(PathBuilderMultiRootTest, TargetDirectlySignedByTrustAnchor) {
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(b_by_f_, &trust_store);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
+ &result);
+
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+ ASSERT_TRUE(result.HasValidPath());
+ const auto& path = result.GetBestValidPath()->path;
+ ASSERT_EQ(1U, path.certs.size());
+ EXPECT_EQ(a_by_b_, path.certs[0]);
+ EXPECT_EQ(b_by_f_, path.trust_anchor->cert());
+}
+
+// Test that async cert queries are not made if the path can be successfully
+// built with synchronously available certs.
+TEST_F(PathBuilderMultiRootTest, TriesSyncFirst) {
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(e_by_e_, &trust_store);
+
+ CertIssuerSourceStatic sync_certs;
+ sync_certs.AddCert(b_by_f_);
+ sync_certs.AddCert(f_by_e_);
+
+ AsyncCertIssuerSourceStatic async_certs;
+ async_certs.AddCert(b_by_c_);
+ async_certs.AddCert(c_by_e_);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
+ &result);
+ path_builder.AddCertIssuerSource(&async_certs);
+ path_builder.AddCertIssuerSource(&sync_certs);
+
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+ EXPECT_TRUE(result.HasValidPath());
+ EXPECT_EQ(0, async_certs.num_async_gets());
+}
+
+// Test that async cert queries are not made if no callback is provided.
+TEST_F(PathBuilderMultiRootTest, SychronousOnlyMode) {
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(e_by_e_, &trust_store);
+
+ CertIssuerSourceStatic sync_certs;
+ sync_certs.AddCert(f_by_e_);
+
+ AsyncCertIssuerSourceStatic async_certs;
+ async_certs.AddCert(b_by_f_);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
+ &result);
+ path_builder.AddCertIssuerSource(&async_certs);
+ path_builder.AddCertIssuerSource(&sync_certs);
+
+ EXPECT_EQ(CompletionStatus::SYNC, path_builder.Run(base::Closure()));
+
+ EXPECT_FALSE(result.HasValidPath());
+ EXPECT_EQ(0, async_certs.num_async_gets());
+}
+
+// If async queries are needed, all async sources will be queried
+// simultaneously.
+TEST_F(PathBuilderMultiRootTest, TestAsyncSimultaneous) {
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(e_by_e_, &trust_store);
+
+ CertIssuerSourceStatic sync_certs;
+ sync_certs.AddCert(b_by_c_);
+ sync_certs.AddCert(b_by_f_);
+
+ AsyncCertIssuerSourceStatic async_certs1;
+ async_certs1.AddCert(c_by_e_);
+
+ AsyncCertIssuerSourceStatic async_certs2;
+ async_certs2.AddCert(f_by_e_);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
+ &result);
+ path_builder.AddCertIssuerSource(&async_certs1);
+ path_builder.AddCertIssuerSource(&async_certs2);
+ path_builder.AddCertIssuerSource(&sync_certs);
+
+ EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder));
+
+ EXPECT_TRUE(result.HasValidPath());
+ EXPECT_EQ(1, async_certs1.num_async_gets());
+ EXPECT_EQ(1, async_certs2.num_async_gets());
+}
+
+// Test that PathBuilder does not generate longer paths than necessary if one of
+// the supplied certs is itself a trust anchor.
+TEST_F(PathBuilderMultiRootTest, TestLongChain) {
+ // Both D(D) and C(D) are trusted roots.
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(d_by_d_, &trust_store);
+ AddTrustedCertificate(c_by_d_, &trust_store);
+
+ // Certs B(C), and C(D) are all supplied.
+ CertIssuerSourceStatic sync_certs;
+ sync_certs.AddCert(b_by_c_);
+ sync_certs.AddCert(c_by_d_);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
+ &result);
+ path_builder.AddCertIssuerSource(&sync_certs);
+
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+ ASSERT_TRUE(result.HasValidPath());
+
+ // The result path should be A(B) <- B(C) <- C(D)
+ // not the longer but also valid A(B) <- B(C) <- C(D) <- D(D)
+ EXPECT_EQ(2U, result.GetBestValidPath()->path.certs.size());
+}
+
+// Test that PathBuilder will backtrack and try a different path if the first
+// one doesn't work out.
+TEST_F(PathBuilderMultiRootTest, TestBacktracking) {
+ // Only D(D) is a trusted root.
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(d_by_d_, &trust_store);
+
+ // Certs B(F) and F(E) are supplied synchronously, thus the path
+ // A(B) <- B(F) <- F(E) should be built first, though it won't verify.
+ CertIssuerSourceStatic sync_certs;
+ sync_certs.AddCert(b_by_f_);
+ sync_certs.AddCert(f_by_e_);
+
+ // Certs B(C), and C(D) are supplied asynchronously, so the path
+ // A(B) <- B(C) <- C(D) <- D(D) should be tried second.
+ AsyncCertIssuerSourceStatic async_certs;
+ async_certs.AddCert(b_by_c_);
+ async_certs.AddCert(c_by_d_);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
+ &result);
+ path_builder.AddCertIssuerSource(&sync_certs);
+ path_builder.AddCertIssuerSource(&async_certs);
+
+ EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder));
+
+ ASSERT_TRUE(result.HasValidPath());
+
+ // The result path should be A(B) <- B(C) <- C(D) <- D(D)
+ const auto& path = result.GetBestValidPath()->path;
+ ASSERT_EQ(3U, path.certs.size());
+ EXPECT_EQ(a_by_b_, path.certs[0]);
+ EXPECT_EQ(b_by_c_, path.certs[1]);
+ EXPECT_EQ(c_by_d_, path.certs[2]);
+ EXPECT_EQ(d_by_d_, path.trust_anchor->cert());
+}
+
+// Test that whichever order CertIssuerSource returns the issuers, the path
+// building still succeeds.
+TEST_F(PathBuilderMultiRootTest, TestCertIssuerOrdering) {
+ // Only D(D) is a trusted root.
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(d_by_d_, &trust_store);
+
+ for (bool reverse_order : {false, true}) {
+ SCOPED_TRACE(reverse_order);
+ std::vector<scoped_refptr<ParsedCertificate>> certs = {
+ b_by_c_, b_by_f_, f_by_e_, c_by_d_, c_by_e_};
+ CertIssuerSourceStatic sync_certs;
+ if (reverse_order) {
+ for (auto it = certs.rbegin(); it != certs.rend(); ++it)
+ sync_certs.AddCert(*it);
+ } else {
+ for (const auto& cert : certs)
+ sync_certs.AddCert(cert);
+ }
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_,
+ time_, &result);
+ path_builder.AddCertIssuerSource(&sync_certs);
+
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+ ASSERT_TRUE(result.HasValidPath());
+
+ // The result path should be A(B) <- B(C) <- C(D) <- D(D)
+ const auto& path = result.GetBestValidPath()->path;
+ ASSERT_EQ(3U, path.certs.size());
+ EXPECT_EQ(a_by_b_, path.certs[0]);
+ EXPECT_EQ(b_by_c_, path.certs[1]);
+ EXPECT_EQ(c_by_d_, path.certs[2]);
+ EXPECT_EQ(d_by_d_, path.trust_anchor->cert());
+ }
+}
+
+class PathBuilderKeyRolloverTest : public ::testing::Test {
+ public:
+ PathBuilderKeyRolloverTest() : signature_policy_(1024) {}
+
+ void SetUp() override {
+ ParsedCertificateList path;
+ bool unused_result;
+ std::string unused_errors;
+
+ ReadVerifyCertChainTestFromFile(
+ "net/data/verify_certificate_chain_unittest/key-rollover-oldchain.pem",
+ &path, &oldroot_, &time_, &unused_result, &unused_errors);
+ ASSERT_EQ(2U, path.size());
+ target_ = path[0];
+ oldintermediate_ = path[1];
+ ASSERT_TRUE(target_);
+ ASSERT_TRUE(oldintermediate_);
+
+ ReadVerifyCertChainTestFromFile(
+ "net/data/verify_certificate_chain_unittest/"
+ "key-rollover-longrolloverchain.pem",
+ &path, &oldroot_, &time_, &unused_result, &unused_errors);
+ ASSERT_EQ(4U, path.size());
+ newintermediate_ = path[1];
+ newroot_ = path[2];
+ newrootrollover_ = path[3];
+ ASSERT_TRUE(newintermediate_);
+ ASSERT_TRUE(newroot_);
+ ASSERT_TRUE(newrootrollover_);
+ }
+
+ protected:
+ // oldroot-------->newrootrollover newroot
+ // | | |
+ // v v v
+ // oldintermediate newintermediate
+ // | |
+ // +------------+-------------+
+ // |
+ // v
+ // target
+ scoped_refptr<ParsedCertificate> target_;
+ scoped_refptr<ParsedCertificate> oldintermediate_;
+ scoped_refptr<ParsedCertificate> newintermediate_;
+ scoped_refptr<TrustAnchor> oldroot_;
+ scoped_refptr<ParsedCertificate> newroot_;
+ scoped_refptr<ParsedCertificate> newrootrollover_;
+
+ SimpleSignaturePolicy signature_policy_;
+ der::GeneralizedTime time_;
+};
+
+// Tests that if only the old root cert is trusted, the path builder can build a
+// path through the new intermediate and rollover cert to the old root.
+TEST_F(PathBuilderKeyRolloverTest, TestRolloverOnlyOldRootTrusted) {
+ // Only oldroot is trusted.
+ TrustStoreInMemory trust_store;
+ trust_store.AddTrustAnchor(oldroot_);
+
+ // Old intermediate cert is not provided, so the pathbuilder will need to go
+ // through the rollover cert.
+ CertIssuerSourceStatic sync_certs;
+ sync_certs.AddCert(newintermediate_);
+ sync_certs.AddCert(newrootrollover_);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+ &result);
+ path_builder.AddCertIssuerSource(&sync_certs);
+
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+ EXPECT_TRUE(result.HasValidPath());
+
+ // Path builder will first attempt: target <- newintermediate <- oldroot
+ // but it will fail since newintermediate is signed by newroot.
+ ASSERT_EQ(2U, result.paths.size());
+ const auto& path0 = result.paths[0]->path;
+ EXPECT_FALSE(result.paths[0]->valid);
+ ASSERT_EQ(2U, path0.certs.size());
+ EXPECT_EQ(target_, path0.certs[0]);
+ EXPECT_EQ(newintermediate_, path0.certs[1]);
+ EXPECT_EQ(oldroot_, path0.trust_anchor);
+
+ // Path builder will next attempt:
+ // target <- newintermediate <- newrootrollover <- oldroot
+ // which will succeed.
+ const auto& path1 = result.paths[1]->path;
+ EXPECT_EQ(1U, result.best_result_index);
+ EXPECT_TRUE(result.paths[1]->valid);
+ ASSERT_EQ(3U, path1.certs.size());
+ EXPECT_EQ(target_, path1.certs[0]);
+ EXPECT_EQ(newintermediate_, path1.certs[1]);
+ EXPECT_EQ(newrootrollover_, path1.certs[2]);
+ EXPECT_EQ(oldroot_, path1.trust_anchor);
+}
+
+// Tests that if both old and new roots are trusted it can build a path through
+// either.
+// TODO(mattm): Once prioritization is implemented, it should test that it
+// always builds the path through the new intermediate and new root.
+TEST_F(PathBuilderKeyRolloverTest, TestRolloverBothRootsTrusted) {
+ // Both oldroot and newroot are trusted.
+ TrustStoreInMemory trust_store;
+ trust_store.AddTrustAnchor(oldroot_);
+ AddTrustedCertificate(newroot_, &trust_store);
+
+ // Both old and new intermediates + rollover cert are provided.
+ CertIssuerSourceStatic sync_certs;
+ sync_certs.AddCert(oldintermediate_);
+ sync_certs.AddCert(newintermediate_);
+ sync_certs.AddCert(newrootrollover_);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+ &result);
+ path_builder.AddCertIssuerSource(&sync_certs);
+
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+ EXPECT_TRUE(result.HasValidPath());
+
+ // Path builder willattempt one of:
+ // target <- oldintermediate <- oldroot
+ // target <- newintermediate <- newroot
+ // either will succeed.
+ ASSERT_EQ(1U, result.paths.size());
+ const auto& path = result.paths[0]->path;
+ EXPECT_TRUE(result.paths[0]->valid);
+ ASSERT_EQ(2U, path.certs.size());
+ EXPECT_EQ(target_, path.certs[0]);
+ if (path.certs[1] != newintermediate_) {
+ DVLOG(1) << "USED OLD";
+ EXPECT_EQ(oldintermediate_, path.certs[1]);
+ EXPECT_EQ(oldroot_, path.trust_anchor);
+ } else {
+ DVLOG(1) << "USED NEW";
+ EXPECT_EQ(newintermediate_, path.certs[1]);
+ EXPECT_EQ(newroot_, path.trust_anchor->cert());
+ }
+}
+
+// If trust anchors are provided both synchronously and asynchronously for the
+// same cert, the synchronously provided ones should be tried first, and
+// pathbuilder should finish synchronously.
+TEST_F(PathBuilderKeyRolloverTest, TestSyncAnchorsPreferred) {
+ TrustStoreInMemoryAsync trust_store;
+ // Both oldintermediate and newintermediate are trusted, but oldintermediate
+ // is returned synchronously and newintermediate asynchronously.
+ trust_store.AddSyncTrustAnchor(
+ TrustAnchor::CreateFromCertificateNoConstraints(oldintermediate_));
+ trust_store.AddAsyncTrustAnchor(
+ TrustAnchor::CreateFromCertificateNoConstraints(newintermediate_));
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+ &result);
+
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+ EXPECT_TRUE(result.HasValidPath());
+
+ ASSERT_EQ(1U, result.paths.size());
+ const auto& path = result.paths[0]->path;
+ EXPECT_TRUE(result.paths[0]->valid);
+ ASSERT_EQ(1U, path.certs.size());
+ EXPECT_EQ(target_, path.certs[0]);
+ EXPECT_EQ(oldintermediate_, path.trust_anchor->cert());
+}
+
+// Async trust anchor checks should be done before synchronous issuer checks are
+// considered. (Avoiding creating unnecessarily long paths.)
+//
+// Two valid paths could be built:
+// newintermediate <- newrootrollover <- oldroot
+// newintermediate <- newroot
+// One invalid path could be built:
+// newintermediate <- oldroot
+//
+// First: newintermediate <- oldroot will be tried, since oldroot is
+// available synchronously, but this path will not verify.
+// Second: newintermediate <- newroot should be built, even though
+// newrootrollover issuer is available synchronously and newroot is async. This
+// path should verify and pathbuilder will stop.
+TEST_F(PathBuilderKeyRolloverTest, TestAsyncAnchorsBeforeSyncIssuers) {
+ TrustStoreInMemoryAsync trust_store;
+ trust_store.AddSyncTrustAnchor(oldroot_);
+ trust_store.AddAsyncTrustAnchor(
+ TrustAnchor::CreateFromCertificateNoConstraints(newroot_));
+
+ CertIssuerSourceStatic sync_certs;
+ sync_certs.AddCert(newrootrollover_);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(newintermediate_, &trust_store,
+ &signature_policy_, time_, &result);
+ path_builder.AddCertIssuerSource(&sync_certs);
+
+ EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder));
+
+ EXPECT_TRUE(result.HasValidPath());
+
+ ASSERT_EQ(2U, result.paths.size());
+ {
+ const auto& path = result.paths[0]->path;
+ EXPECT_FALSE(result.paths[0]->valid);
+ ASSERT_EQ(1U, path.certs.size());
+ EXPECT_EQ(newintermediate_, path.certs[0]);
+ EXPECT_EQ(oldroot_, path.trust_anchor);
+ }
+ {
+ const auto& path = result.paths[1]->path;
+ EXPECT_TRUE(result.paths[1]->valid);
+ ASSERT_EQ(1U, path.certs.size());
+ EXPECT_EQ(newintermediate_, path.certs[0]);
+ EXPECT_EQ(newroot_, path.trust_anchor->cert());
+ }
+}
+
+// If async trust anchor query returned no results, and there are no issuer
+// sources, path building should fail at that point.
+TEST_F(PathBuilderKeyRolloverTest, TestAsyncAnchorsNoMatchAndNoIssuerSources) {
+ TrustStoreInMemoryAsync trust_store;
+ trust_store.AddAsyncTrustAnchor(
+ TrustAnchor::CreateFromCertificateNoConstraints(newroot_));
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+ &result);
+
+ EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder));
+
+ EXPECT_FALSE(result.HasValidPath());
+
+ ASSERT_EQ(0U, result.paths.size());
+}
+
+// Both trust store and issuer source are async. Should successfully build a
+// path.
+TEST_F(PathBuilderKeyRolloverTest, TestAsyncAnchorsAndAsyncIssuers) {
+ TrustStoreInMemoryAsync trust_store;
+ trust_store.AddAsyncTrustAnchor(
+ TrustAnchor::CreateFromCertificateNoConstraints(newroot_));
+
+ AsyncCertIssuerSourceStatic async_certs;
+ async_certs.AddCert(newintermediate_);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+ &result);
+ path_builder.AddCertIssuerSource(&async_certs);
+
+ EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder));
+
+ EXPECT_TRUE(result.HasValidPath());
+
+ ASSERT_EQ(1U, result.paths.size());
+ const auto& path = result.paths[0]->path;
+ EXPECT_TRUE(result.paths[0]->valid);
+ ASSERT_EQ(2U, path.certs.size());
+ EXPECT_EQ(target_, path.certs[0]);
+ EXPECT_EQ(newintermediate_, path.certs[1]);
+ EXPECT_EQ(newroot_, path.trust_anchor->cert());
+}
+
+// Tests that multiple trust root matches on a single path will be considered.
+// Both roots have the same subject but different keys. Only one of them will
+// verify.
+TEST_F(PathBuilderKeyRolloverTest, TestMultipleRootMatchesOnlyOneWorks) {
+ TrustStoreInMemoryAsync trust_store;
+ // Since FindTrustAnchorsByNormalizedName returns newroot synchronously, it
+ // should be tried first.
+ trust_store.AddSyncTrustAnchor(
+ TrustAnchor::CreateFromCertificateNoConstraints(newroot_));
+ // oldroot is returned asynchronously, so it should only be tried after the
+ // path built with newroot fails.
+ trust_store.AddAsyncTrustAnchor(oldroot_);
+
+ // Only oldintermediate is supplied, so the path with newroot should fail,
+ // oldroot should succeed.
+ CertIssuerSourceStatic sync_certs;
+ sync_certs.AddCert(oldintermediate_);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+ &result);
+ path_builder.AddCertIssuerSource(&sync_certs);
+
+ EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder));
+
+ EXPECT_TRUE(result.HasValidPath());
+ ASSERT_EQ(2U, result.paths.size());
+
+ {
+ // Path builder may first attempt: target <- oldintermediate <- newroot
+ // but it will fail since oldintermediate is signed by oldroot.
+ EXPECT_FALSE(result.paths[0]->valid);
+ const auto& path = result.paths[0]->path;
+ ASSERT_EQ(2U, path.certs.size());
+ EXPECT_EQ(target_, path.certs[0]);
+ EXPECT_EQ(oldintermediate_, path.certs[1]);
+ EXPECT_EQ(newroot_, path.trust_anchor->cert());
+ }
+
+ {
+ // Path builder will next attempt:
+ // target <- old intermediate <- oldroot
+ // which should succeed.
+ EXPECT_TRUE(result.paths[result.best_result_index]->valid);
+ const auto& path = result.paths[result.best_result_index]->path;
+ ASSERT_EQ(2U, path.certs.size());
+ EXPECT_EQ(target_, path.certs[0]);
+ EXPECT_EQ(oldintermediate_, path.certs[1]);
+ EXPECT_EQ(oldroot_, path.trust_anchor);
+ }
+}
+
+// Tests that the path builder doesn't build longer than necessary paths.
+TEST_F(PathBuilderKeyRolloverTest, TestRolloverLongChain) {
+ // Only oldroot is trusted.
+ TrustStoreInMemory trust_store;
+ trust_store.AddTrustAnchor(oldroot_);
+
+ // New intermediate and new root are provided synchronously.
+ CertIssuerSourceStatic sync_certs;
+ sync_certs.AddCert(newintermediate_);
+ sync_certs.AddCert(newroot_);
+
+ // Rollover cert is only provided asynchronously. This will force the
+ // pathbuilder to first try building a longer than necessary path.
+ AsyncCertIssuerSourceStatic async_certs;
+ async_certs.AddCert(newrootrollover_);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+ &result);
+ path_builder.AddCertIssuerSource(&sync_certs);
+ path_builder.AddCertIssuerSource(&async_certs);
+
+ EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder));
+
+ EXPECT_TRUE(result.HasValidPath());
+ ASSERT_EQ(3U, result.paths.size());
+
+ // Path builder will first attempt: target <- newintermediate <- oldroot
+ // but it will fail since newintermediate is signed by newroot.
+ EXPECT_FALSE(result.paths[0]->valid);
+ const auto& path0 = result.paths[0]->path;
+ ASSERT_EQ(2U, path0.certs.size());
+ EXPECT_EQ(target_, path0.certs[0]);
+ EXPECT_EQ(newintermediate_, path0.certs[1]);
+ EXPECT_EQ(oldroot_, path0.trust_anchor);
+
+ // Path builder will next attempt:
+ // target <- newintermediate <- newroot <- oldroot
+ // but it will fail since newroot is self-signed.
+ EXPECT_FALSE(result.paths[1]->valid);
+ const auto& path1 = result.paths[1]->path;
+ ASSERT_EQ(3U, path1.certs.size());
+ EXPECT_EQ(target_, path1.certs[0]);
+ EXPECT_EQ(newintermediate_, path1.certs[1]);
+ EXPECT_EQ(newroot_, path1.certs[2]);
+ EXPECT_EQ(oldroot_, path1.trust_anchor);
+
+ // Path builder will skip:
+ // target <- newintermediate <- newroot <- newrootrollover <- ...
+ // Since newroot and newrootrollover have the same Name+SAN+SPKI.
+
+ // Finally path builder will use:
+ // target <- newintermediate <- newrootrollover <- oldroot
+ EXPECT_EQ(2U, result.best_result_index);
+ EXPECT_TRUE(result.paths[2]->valid);
+ const auto& path2 = result.paths[2]->path;
+ ASSERT_EQ(3U, path2.certs.size());
+ EXPECT_EQ(target_, path2.certs[0]);
+ EXPECT_EQ(newintermediate_, path2.certs[1]);
+ EXPECT_EQ(newrootrollover_, path2.certs[2]);
+ EXPECT_EQ(oldroot_, path2.trust_anchor);
+}
+
+// If the target cert is a trust anchor, however is not itself *signed* by a
+// trust anchor, then it is not considered valid (the SPKI and name of the
+// trust anchor matches the SPKI and subject of the targe certificate, but the
+// rest of the certificate cannot be verified).
+TEST_F(PathBuilderKeyRolloverTest, TestEndEntityIsTrustRoot) {
+ // Trust newintermediate.
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(newintermediate_, &trust_store);
+
+ CertPathBuilder::Result result;
+ // Newintermediate is also the target cert.
+ CertPathBuilder path_builder(newintermediate_, &trust_store,
+ &signature_policy_, time_, &result);
+
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+ EXPECT_FALSE(result.HasValidPath());
+}
+
+// If target has same Name+SAN+SPKI as a necessary intermediate, test if a path
+// can still be built.
+// Since LoopChecker will prevent the intermediate from being included, this
+// currently does NOT verify. This case shouldn't occur in the web PKI.
+TEST_F(PathBuilderKeyRolloverTest,
+ TestEndEntityHasSameNameAndSpkiAsIntermediate) {
+ // Trust oldroot.
+ TrustStoreInMemory trust_store;
+ trust_store.AddTrustAnchor(oldroot_);
+
+ // New root rollover is provided synchronously.
+ CertIssuerSourceStatic sync_certs;
+ sync_certs.AddCert(newrootrollover_);
+
+ CertPathBuilder::Result result;
+ // Newroot is the target cert.
+ CertPathBuilder path_builder(newroot_, &trust_store, &signature_policy_,
+ time_, &result);
+ path_builder.AddCertIssuerSource(&sync_certs);
+
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+ // This could actually be OK, but CertPathBuilder does not build the
+ // newroot <- newrootrollover <- oldroot path.
+ EXPECT_FALSE(result.HasValidPath());
+}
+
+// If target has same Name+SAN+SPKI as the trust root, test that a (trivial)
+// path can still be built.
+TEST_F(PathBuilderKeyRolloverTest,
+ TestEndEntityHasSameNameAndSpkiAsTrustAnchor) {
+ // Trust newrootrollover.
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(newrootrollover_, &trust_store);
+
+ CertPathBuilder::Result result;
+ // Newroot is the target cert.
+ CertPathBuilder path_builder(newroot_, &trust_store, &signature_policy_,
+ time_, &result);
+
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+ ASSERT_TRUE(result.HasValidPath());
+
+ const CertPathBuilder::ResultPath* best_result = result.GetBestValidPath();
+
+ // Newroot has same name+SPKI as newrootrollover, thus the path is valid and
+ // only contains newroot.
+ EXPECT_TRUE(best_result->valid);
+ ASSERT_EQ(1U, best_result->path.certs.size());
+ EXPECT_EQ(newroot_, best_result->path.certs[0]);
+ EXPECT_EQ(newrootrollover_, best_result->path.trust_anchor->cert());
+}
+
+// Test that PathBuilder will not try the same path twice if multiple
+// CertIssuerSources provide the same certificate.
+TEST_F(PathBuilderKeyRolloverTest, TestDuplicateIntermediates) {
+ // Create a separate copy of oldintermediate.
+ scoped_refptr<ParsedCertificate> oldintermediate_dupe(
+ ParsedCertificate::Create(oldintermediate_->der_cert().AsStringPiece(),
+ {}, nullptr));
+
+ // Only newroot is a trusted root.
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(newroot_, &trust_store);
+
+ // The oldintermediate is supplied synchronously by |sync_certs1| and
+ // another copy of oldintermediate is supplied synchronously by |sync_certs2|.
+ // The path target <- oldintermediate <- newroot should be built first,
+ // though it won't verify. It should not be attempted again even though
+ // oldintermediate was supplied twice.
+ CertIssuerSourceStatic sync_certs1;
+ sync_certs1.AddCert(oldintermediate_);
+ CertIssuerSourceStatic sync_certs2;
+ sync_certs2.AddCert(oldintermediate_dupe);
+
+ // The newintermediate is supplied asynchronously, so the path
+ // target <- newintermediate <- newroot should be tried second.
+ AsyncCertIssuerSourceStatic async_certs;
+ async_certs.AddCert(newintermediate_);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+ &result);
+ path_builder.AddCertIssuerSource(&sync_certs1);
+ path_builder.AddCertIssuerSource(&sync_certs2);
+ path_builder.AddCertIssuerSource(&async_certs);
+
+ EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder));
+
+ EXPECT_TRUE(result.HasValidPath());
+ ASSERT_EQ(2U, result.paths.size());
+
+ // Path builder will first attempt: target <- oldintermediate <- newroot
+ // but it will fail since oldintermediate is signed by oldroot.
+ EXPECT_FALSE(result.paths[0]->valid);
+ const auto& path0 = result.paths[0]->path;
+
+ ASSERT_EQ(2U, path0.certs.size());
+ EXPECT_EQ(target_, path0.certs[0]);
+ // Compare the DER instead of ParsedCertificate pointer, don't care which copy
+ // of oldintermediate was used in the path.
+ EXPECT_EQ(oldintermediate_->der_cert(), path0.certs[1]->der_cert());
+ EXPECT_EQ(newroot_, path0.trust_anchor->cert());
+
+ // Path builder will next attempt: target <- newintermediate <- newroot
+ // which will succeed.
+ EXPECT_EQ(1U, result.best_result_index);
+ EXPECT_TRUE(result.paths[1]->valid);
+ const auto& path1 = result.paths[1]->path;
+ ASSERT_EQ(2U, path1.certs.size());
+ EXPECT_EQ(target_, path1.certs[0]);
+ EXPECT_EQ(newintermediate_, path1.certs[1]);
+ EXPECT_EQ(newroot_, path1.trust_anchor->cert());
+}
+
+// Test when PathBuilder is given a cert CertIssuerSources that has the same
+// SPKI as a TrustAnchor.
+TEST_F(PathBuilderKeyRolloverTest, TestDuplicateIntermediateAndRoot) {
+ // Create a separate copy of newroot.
+ scoped_refptr<ParsedCertificate> newroot_dupe(ParsedCertificate::Create(
+ newroot_->der_cert().AsStringPiece(), {}, nullptr));
+
+ // Only newroot is a trusted root.
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(newroot_, &trust_store);
+
+ // The oldintermediate and newroot are supplied synchronously by |sync_certs|.
+ CertIssuerSourceStatic sync_certs;
+ sync_certs.AddCert(oldintermediate_);
+ sync_certs.AddCert(newroot_dupe);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+ &result);
+ path_builder.AddCertIssuerSource(&sync_certs);
+
+ EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+ EXPECT_FALSE(result.HasValidPath());
+ ASSERT_EQ(2U, result.paths.size());
+ // TODO(eroman): Is this right?
+
+ // Path builder attempt: target <- oldintermediate <- newroot
+ // but it will fail since oldintermediate is signed by oldroot.
+ EXPECT_FALSE(result.paths[0]->valid);
+ const auto& path = result.paths[0]->path;
+ ASSERT_EQ(2U, path.certs.size());
+ EXPECT_EQ(target_, path.certs[0]);
+ EXPECT_EQ(oldintermediate_, path.certs[1]);
+ // Compare the DER instead of ParsedCertificate pointer, don't care which copy
+ // of newroot was used in the path.
+ EXPECT_EQ(newroot_->der_cert(), path.trust_anchor->cert()->der_cert());
+}
+
+class MockCertIssuerSourceRequest : public CertIssuerSource::Request {
+ public:
+ MOCK_METHOD1(GetNext, CompletionStatus(scoped_refptr<ParsedCertificate>*));
+};
+
+class MockCertIssuerSource : public CertIssuerSource {
+ public:
+ MOCK_METHOD2(SyncGetIssuersOf,
+ void(const ParsedCertificate*, ParsedCertificateList*));
+ MOCK_METHOD3(AsyncGetIssuersOf,
+ void(const ParsedCertificate*,
+ const IssuerCallback&,
+ std::unique_ptr<Request>*));
+};
+
+// Helper class to pass the Request to the PathBuilder when it calls
+// AsyncGetIssuersOf. (GoogleMock has a ByMove helper, but it apparently can
+// only be used with Return, not SetArgPointee.)
+class CertIssuerSourceRequestMover {
+ public:
+ CertIssuerSourceRequestMover(std::unique_ptr<CertIssuerSource::Request> req)
+ : request_(std::move(req)) {}
+ void MoveIt(const ParsedCertificate* cert,
+ const CertIssuerSource::IssuerCallback& issuers_callback,
+ std::unique_ptr<CertIssuerSource::Request>* out_req) {
+ *out_req = std::move(request_);
+ }
+
+ private:
+ std::unique_ptr<CertIssuerSource::Request> request_;
+};
+
+// Test that a single CertIssuerSource returning multiple async batches of
+// issuers is handled correctly. Due to the StrictMocks, it also tests that path
+// builder does not request issuers of certs that it shouldn't.
+TEST_F(PathBuilderKeyRolloverTest, TestMultipleAsyncCallbacksFromSingleSource) {
+ StrictMock<MockCertIssuerSource> cert_issuer_source;
+
+ // Only newroot is a trusted root.
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(newroot_, &trust_store);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+ &result);
+ path_builder.AddCertIssuerSource(&cert_issuer_source);
+
+ CertIssuerSource::IssuerCallback target_issuers_callback;
+ // Create the mock CertIssuerSource::Request...
+ std::unique_ptr<StrictMock<MockCertIssuerSourceRequest>>
+ target_issuers_req_owner(new StrictMock<MockCertIssuerSourceRequest>());
+ // Keep a raw pointer to the Request...
+ StrictMock<MockCertIssuerSourceRequest>* target_issuers_req =
+ target_issuers_req_owner.get();
+ // Setup helper class to pass ownership of the Request to the PathBuilder when
+ // it calls AsyncGetIssuersOf.
+ CertIssuerSourceRequestMover req_mover(std::move(target_issuers_req_owner));
+ {
+ ::testing::InSequence s;
+ EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(target_.get(), _));
+ EXPECT_CALL(cert_issuer_source, AsyncGetIssuersOf(target_.get(), _, _))
+ .WillOnce(
+ DoAll(SaveArg<1>(&target_issuers_callback),
+ Invoke(&req_mover, &CertIssuerSourceRequestMover::MoveIt)));
+ }
+
+ TestClosure callback;
+ CompletionStatus rv = path_builder.Run(callback.closure());
+ ASSERT_EQ(CompletionStatus::ASYNC, rv);
+
+ ASSERT_FALSE(target_issuers_callback.is_null());
+
+ ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source);
+
+ // First async batch: return oldintermediate_.
+ EXPECT_CALL(*target_issuers_req, GetNext(_))
+ .WillOnce(DoAll(SetArgPointee<0>(oldintermediate_),
+ Return(CompletionStatus::SYNC)))
+ .WillOnce(
+ DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC)));
+ {
+ ::testing::InSequence s;
+ // oldintermediate_ does not create a valid path, so both sync and async
+ // lookups are expected.
+ EXPECT_CALL(cert_issuer_source,
+ SyncGetIssuersOf(oldintermediate_.get(), _));
+ EXPECT_CALL(cert_issuer_source,
+ AsyncGetIssuersOf(oldintermediate_.get(), _, _));
+ }
+ target_issuers_callback.Run(target_issuers_req);
+ ::testing::Mock::VerifyAndClearExpectations(target_issuers_req);
+ ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source);
+
+ // Second async batch: return newintermediate_.
+ EXPECT_CALL(*target_issuers_req, GetNext(_))
+ .WillOnce(DoAll(SetArgPointee<0>(newintermediate_),
+ Return(CompletionStatus::SYNC)))
+ .WillOnce(
+ DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC)));
+ // newroot_ is in the trust store, so this path will be completed
+ // synchronously. AsyncGetIssuersOf will not be called on newintermediate_.
+ EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(newintermediate_.get(), _));
+ target_issuers_callback.Run(target_issuers_req);
+ // Note that VerifyAndClearExpectations(target_issuers_req) is not called
+ // here. PathBuilder could have destroyed it already, so just let the
+ // expectations get checked by the destructor.
+ ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source);
+
+ // Ensure pathbuilder finished and filled result.
+ callback.WaitForResult();
+
+ EXPECT_TRUE(result.HasValidPath());
+ ASSERT_EQ(2U, result.paths.size());
+
+ // Path builder first attempts: target <- oldintermediate <- newroot
+ // but it will fail since oldintermediate is signed by oldroot.
+ EXPECT_FALSE(result.paths[0]->valid);
+ const auto& path0 = result.paths[0]->path;
+ ASSERT_EQ(2U, path0.certs.size());
+ EXPECT_EQ(target_, path0.certs[0]);
+ EXPECT_EQ(oldintermediate_, path0.certs[1]);
+ EXPECT_EQ(newroot_, path0.trust_anchor->cert());
+
+ // After the second batch of async results, path builder will attempt:
+ // target <- newintermediate <- newroot which will succeed.
+ EXPECT_TRUE(result.paths[1]->valid);
+ const auto& path1 = result.paths[1]->path;
+ ASSERT_EQ(2U, path1.certs.size());
+ EXPECT_EQ(target_, path1.certs[0]);
+ EXPECT_EQ(newintermediate_, path1.certs[1]);
+ EXPECT_EQ(newroot_, path1.trust_anchor->cert());
+}
+
+// Test that PathBuilder will not try the same path twice if CertIssuerSources
+// asynchronously provide the same certificate multiple times.
+TEST_F(PathBuilderKeyRolloverTest, TestDuplicateAsyncIntermediates) {
+ StrictMock<MockCertIssuerSource> cert_issuer_source;
+
+ // Only newroot is a trusted root.
+ TrustStoreInMemory trust_store;
+ AddTrustedCertificate(newroot_, &trust_store);
+
+ CertPathBuilder::Result result;
+ CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+ &result);
+ path_builder.AddCertIssuerSource(&cert_issuer_source);
+
+ CertIssuerSource::IssuerCallback target_issuers_callback;
+ // Create the mock CertIssuerSource::Request...
+ std::unique_ptr<StrictMock<MockCertIssuerSourceRequest>>
+ target_issuers_req_owner(new StrictMock<MockCertIssuerSourceRequest>());
+ // Keep a raw pointer to the Request...
+ StrictMock<MockCertIssuerSourceRequest>* target_issuers_req =
+ target_issuers_req_owner.get();
+ // Setup helper class to pass ownership of the Request to the PathBuilder when
+ // it calls AsyncGetIssuersOf.
+ CertIssuerSourceRequestMover req_mover(std::move(target_issuers_req_owner));
+ {
+ ::testing::InSequence s;
+ EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(target_.get(), _));
+ EXPECT_CALL(cert_issuer_source, AsyncGetIssuersOf(target_.get(), _, _))
+ .WillOnce(
+ DoAll(SaveArg<1>(&target_issuers_callback),
+ Invoke(&req_mover, &CertIssuerSourceRequestMover::MoveIt)));
+ }
+
+ TestClosure callback;
+ CompletionStatus rv = path_builder.Run(callback.closure());
+ ASSERT_EQ(CompletionStatus::ASYNC, rv);
+
+ ASSERT_FALSE(target_issuers_callback.is_null());
+
+ ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source);
+
+ // First async batch: return oldintermediate_.
+ EXPECT_CALL(*target_issuers_req, GetNext(_))
+ .WillOnce(DoAll(SetArgPointee<0>(oldintermediate_),
+ Return(CompletionStatus::SYNC)))
+ .WillOnce(
+ DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC)));
+ {
+ ::testing::InSequence s;
+ // oldintermediate_ does not create a valid path, so both sync and async
+ // lookups are expected.
+ EXPECT_CALL(cert_issuer_source,
+ SyncGetIssuersOf(oldintermediate_.get(), _));
+ EXPECT_CALL(cert_issuer_source,
+ AsyncGetIssuersOf(oldintermediate_.get(), _, _));
+ }
+ target_issuers_callback.Run(target_issuers_req);
+ ::testing::Mock::VerifyAndClearExpectations(target_issuers_req);
+ ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source);
+
+ // Second async batch: return a different copy of oldintermediate_ again.
+ scoped_refptr<ParsedCertificate> oldintermediate_dupe(
+ ParsedCertificate::Create(oldintermediate_->der_cert().AsStringPiece(),
+ {}, nullptr));
+ EXPECT_CALL(*target_issuers_req, GetNext(_))
+ .WillOnce(DoAll(SetArgPointee<0>(oldintermediate_dupe),
+ Return(CompletionStatus::SYNC)))
+ .WillOnce(
+ DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC)));
+ target_issuers_callback.Run(target_issuers_req);
+ // oldintermediate was already processed above, it should not generate any
+ // more requests.
+ ::testing::Mock::VerifyAndClearExpectations(target_issuers_req);
+ ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source);
+
+ // Third async batch: return newintermediate_.
+ EXPECT_CALL(*target_issuers_req, GetNext(_))
+ .WillOnce(DoAll(SetArgPointee<0>(newintermediate_),
+ Return(CompletionStatus::SYNC)))
+ .WillOnce(
+ DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC)));
+ // newroot_ is in the trust store, so this path will be completed
+ // synchronously. AsyncGetIssuersOf will not be called on newintermediate_.
+ EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(newintermediate_.get(), _));
+ target_issuers_callback.Run(target_issuers_req);
+ // Note that VerifyAndClearExpectations(target_issuers_req) is not called
+ // here. PathBuilder could have destroyed it already, so just let the
+ // expectations get checked by the destructor.
+ ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source);
+
+ // Ensure pathbuilder finished and filled result.
+ callback.WaitForResult();
+
+ EXPECT_TRUE(result.HasValidPath());
+ ASSERT_EQ(2U, result.paths.size());
+
+ // Path builder first attempts: target <- oldintermediate <- newroot
+ // but it will fail since oldintermediate is signed by oldroot.
+ EXPECT_FALSE(result.paths[0]->valid);
+ const auto& path0 = result.paths[0]->path;
+ ASSERT_EQ(2U, path0.certs.size());
+ EXPECT_EQ(target_, path0.certs[0]);
+ EXPECT_EQ(oldintermediate_, path0.certs[1]);
+ EXPECT_EQ(newroot_, path0.trust_anchor->cert());
+
+ // The second async result does not generate any path.
+
+ // After the third batch of async results, path builder will attempt:
+ // target <- newintermediate <- newroot which will succeed.
+ EXPECT_TRUE(result.paths[1]->valid);
+ const auto& path1 = result.paths[1]->path;
+ ASSERT_EQ(2U, path1.certs.size());
+ EXPECT_EQ(target_, path1.certs[0]);
+ EXPECT_EQ(newintermediate_, path1.certs[1]);
+ EXPECT_EQ(newroot_, path1.trust_anchor->cert());
+}
+
+} // namespace
+
+} // namespace net
diff --git a/chromium/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc b/chromium/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc
new file mode 100644
index 00000000000..3bc20ef0819
--- /dev/null
+++ b/chromium/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc
@@ -0,0 +1,53 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/path_builder.h"
+
+#include "net/cert/internal/cert_issuer_source_static.h"
+#include "net/cert/internal/signature_policy.h"
+#include "net/cert/internal/trust_store_in_memory.h"
+#include "net/cert/internal/verify_certificate_chain_typed_unittest.h"
+
+namespace net {
+
+namespace {
+
+class PathBuilderDelegate {
+ public:
+ static void Verify(const ParsedCertificateList& chain,
+ const scoped_refptr<TrustAnchor>& trust_anchor,
+ const der::GeneralizedTime& time,
+ bool expected_result,
+ const std::string& expected_errors,
+ const std::string& test_file_path) {
+ SimpleSignaturePolicy signature_policy(1024);
+ ASSERT_FALSE(chain.empty());
+
+ TrustStoreInMemory trust_store;
+ trust_store.AddTrustAnchor(trust_anchor);
+
+ CertIssuerSourceStatic intermediate_cert_issuer_source;
+ for (size_t i = 1; i < chain.size(); ++i)
+ intermediate_cert_issuer_source.AddCert(chain[i]);
+
+ CertPathBuilder::Result result;
+ // First cert in the |chain| is the target.
+ CertPathBuilder path_builder(chain.front(), &trust_store, &signature_policy,
+ time, &result);
+ path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source);
+
+ CompletionStatus rv = path_builder.Run(base::Closure());
+ EXPECT_EQ(CompletionStatus::SYNC, rv);
+
+ EXPECT_EQ(expected_result, result.HasValidPath());
+ }
+};
+
+} // namespace
+
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+ VerifyCertificateChainSingleRootTest,
+ PathBuilderDelegate);
+
+} // namespace net
diff --git a/chromium/net/cert/internal/signature_algorithm.cc b/chromium/net/cert/internal/signature_algorithm.cc
index a2f99dd1f31..0a1b0e610ed 100644
--- a/chromium/net/cert/internal/signature_algorithm.cc
+++ b/chromium/net/cert/internal/signature_algorithm.cc
@@ -537,8 +537,11 @@ RsaPssParameters::RsaPssParameters(DigestAlgorithm mgf1_hash,
SignatureAlgorithm::~SignatureAlgorithm() {
}
-std::unique_ptr<SignatureAlgorithm> SignatureAlgorithm::CreateFromDer(
- const der::Input& algorithm_identifier) {
+std::unique_ptr<SignatureAlgorithm> SignatureAlgorithm::Create(
+ const der::Input& algorithm_identifier,
+ CertErrors* errors) {
+ // TODO(crbug.com/634443): Add useful error information.
+
der::Input oid;
der::Input params;
if (!ParseAlgorithmIdentifier(algorithm_identifier, &oid, &params))
@@ -577,6 +580,9 @@ std::unique_ptr<SignatureAlgorithm> SignatureAlgorithm::CreateFromDer(
if (oid == der::Input(kOidSha1WithRsaSignature))
return ParseRsaPkcs1(DigestAlgorithm::Sha1, params);
+ // TODO(crbug.com/634443): Add an error indicating what the OID
+ // was.
+
return nullptr; // Unsupported OID.
}
@@ -598,7 +604,7 @@ std::unique_ptr<SignatureAlgorithm> SignatureAlgorithm::CreateRsaPss(
uint32_t salt_length) {
return base::WrapUnique(new SignatureAlgorithm(
SignatureAlgorithmId::RsaPss, digest,
- base::WrapUnique(new RsaPssParameters(mgf1_hash, salt_length))));
+ base::MakeUnique<RsaPssParameters>(mgf1_hash, salt_length)));
}
const RsaPssParameters* SignatureAlgorithm::ParamsForRsaPss() const {
diff --git a/chromium/net/cert/internal/signature_algorithm.h b/chromium/net/cert/internal/signature_algorithm.h
index 0942cce8354..a184c41d1e3 100644
--- a/chromium/net/cert/internal/signature_algorithm.h
+++ b/chromium/net/cert/internal/signature_algorithm.h
@@ -15,6 +15,8 @@
namespace net {
+class CertErrors;
+
namespace der {
class Input;
} // namespace der
@@ -87,11 +89,14 @@ class NET_EXPORT SignatureAlgorithm {
DigestAlgorithm digest() const { return digest_; }
// Creates a SignatureAlgorithm by parsing a DER-encoded "AlgorithmIdentifier"
- // (RFC 5280). Returns nullptr on failure.
- static std::unique_ptr<SignatureAlgorithm> CreateFromDer(
- const der::Input& algorithm_identifier);
+ // (RFC 5280). Returns nullptr on failure. If |errors| was non-null then
+ // error/warning information is output to it.
+ static std::unique_ptr<SignatureAlgorithm> Create(
+ const der::Input& algorithm_identifier,
+ CertErrors* errors);
// Creates a new SignatureAlgorithm with the given type and parameters.
+ // Guaranteed to return non-null result.
static std::unique_ptr<SignatureAlgorithm> CreateRsaPkcs1(
DigestAlgorithm digest);
static std::unique_ptr<SignatureAlgorithm> CreateEcdsa(
diff --git a/chromium/net/cert/internal/signature_algorithm_unittest.cc b/chromium/net/cert/internal/signature_algorithm_unittest.cc
index 04177976a86..2c124ada0d6 100644
--- a/chromium/net/cert/internal/signature_algorithm_unittest.cc
+++ b/chromium/net/cert/internal/signature_algorithm_unittest.cc
@@ -8,6 +8,7 @@
#include "base/files/file_util.h"
#include "base/strings/string_number_conversions.h"
+#include "net/cert/internal/cert_errors.h"
#include "net/cert/pem_tokenizer.h"
#include "net/der/input.h"
#include "net/der/parser.h"
@@ -23,15 +24,25 @@ namespace {
template <size_t N>
bool ParseDer(const uint8_t (&data)[N],
std::unique_ptr<SignatureAlgorithm>* out) {
- *out = SignatureAlgorithm::CreateFromDer(der::Input(data, N));
- return !!*out;
+ CertErrors errors;
+ *out = SignatureAlgorithm::Create(der::Input(data, N), &errors);
+ bool success = !!*out;
+
+ // TODO(crbug.com/634443): Test the errors.
+ // if (!success)
+ // EXPECT_FALSE(errors.empty());
+
+ return success;
}
// Parses a SignatureAlgorithm given an empty DER input.
TEST(SignatureAlgorithmTest, ParseDerEmpty) {
+ CertErrors errors;
std::unique_ptr<SignatureAlgorithm> algorithm =
- SignatureAlgorithm::CreateFromDer(der::Input());
+ SignatureAlgorithm::Create(der::Input(), &errors);
ASSERT_FALSE(algorithm);
+ // TODO(crbug.com/634443): Test the errors.
+ // EXPECT_FALSE(errors.empty());
}
// Parses a SignatureAlgorithm given invalid DER input.
diff --git a/chromium/net/cert/internal/signature_policy.cc b/chromium/net/cert/internal/signature_policy.cc
index c00212ac941..20a4cd3588e 100644
--- a/chromium/net/cert/internal/signature_policy.cc
+++ b/chromium/net/cert/internal/signature_policy.cc
@@ -5,37 +5,66 @@
#include "net/cert/internal/signature_policy.h"
#include "base/logging.h"
+#include "net/cert/internal/cert_error_params.h"
+#include "net/cert/internal/cert_errors.h"
#include <openssl/obj.h>
namespace net {
+namespace {
+
+DEFINE_CERT_ERROR_ID(kUnacceptableCurveForEcdsa,
+ "Only P-256, P-384, P-521 are supported for ECDSA");
+DEFINE_CERT_ERROR_ID(kRsaModulusTooSmall, "RSA modulus too small");
+
+bool IsModulusSizeGreaterOrEqual(size_t modulus_length_bits,
+ size_t min_length_bits,
+ CertErrors* errors) {
+ if (modulus_length_bits < min_length_bits) {
+ errors->AddError(kRsaModulusTooSmall,
+ CreateCertErrorParams2SizeT("actual", modulus_length_bits,
+ "minimum", min_length_bits));
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
bool SignaturePolicy::IsAcceptableSignatureAlgorithm(
- const SignatureAlgorithm& algorithm) const {
+ const SignatureAlgorithm& algorithm,
+ CertErrors* errors) const {
return true;
}
-bool SignaturePolicy::IsAcceptableCurveForEcdsa(int curve_nid) const {
+bool SignaturePolicy::IsAcceptableCurveForEcdsa(int curve_nid,
+ CertErrors* errors) const {
switch (curve_nid) {
case NID_X9_62_prime256v1:
case NID_secp384r1:
case NID_secp521r1:
return true;
}
+
+ errors->AddError(kUnacceptableCurveForEcdsa);
return false;
}
bool SignaturePolicy::IsAcceptableModulusLengthForRsa(
- size_t modulus_length_bits) const {
- return modulus_length_bits >= 2048;
+ size_t modulus_length_bits,
+ CertErrors* errors) const {
+ return IsModulusSizeGreaterOrEqual(modulus_length_bits, 2048, errors);
}
SimpleSignaturePolicy::SimpleSignaturePolicy(size_t min_rsa_modulus_length_bits)
: min_rsa_modulus_length_bits_(min_rsa_modulus_length_bits) {}
bool SimpleSignaturePolicy::IsAcceptableModulusLengthForRsa(
- size_t modulus_length_bits) const {
- return modulus_length_bits >= min_rsa_modulus_length_bits_;
+ size_t modulus_length_bits,
+ CertErrors* errors) const {
+ return IsModulusSizeGreaterOrEqual(modulus_length_bits,
+ min_rsa_modulus_length_bits_, errors);
}
} // namespace net
diff --git a/chromium/net/cert/internal/signature_policy.h b/chromium/net/cert/internal/signature_policy.h
index 749862377d8..86d6c32b19f 100644
--- a/chromium/net/cert/internal/signature_policy.h
+++ b/chromium/net/cert/internal/signature_policy.h
@@ -13,6 +13,7 @@
namespace net {
+class CertErrors;
class SignatureAlgorithm;
// SignaturePolicy is an interface (and base implementation) for applying
@@ -28,21 +29,23 @@ class NET_EXPORT SignaturePolicy {
//
// The default implementation accepts all signature algorithms.
virtual bool IsAcceptableSignatureAlgorithm(
- const SignatureAlgorithm& algorithm) const;
+ const SignatureAlgorithm& algorithm,
+ CertErrors* errors) const;
// Implementations should return true if |curve_nid| is an allowed
// elliptical curve. |curve_nid| is an object ID from BoringSSL (for example
// NID_secp384r1).
//
// The default implementation accepts secp256r1, secp384r1, secp521r1 only.
- virtual bool IsAcceptableCurveForEcdsa(int curve_nid) const;
+ virtual bool IsAcceptableCurveForEcdsa(int curve_nid,
+ CertErrors* errors) const;
// Implementations should return true if |modulus_length_bits| is an allowed
// RSA key size in bits.
//
// The default implementation accepts any modulus length >= 2048 bits.
- virtual bool IsAcceptableModulusLengthForRsa(
- size_t modulus_length_bits) const;
+ virtual bool IsAcceptableModulusLengthForRsa(size_t modulus_length_bits,
+ CertErrors* errors) const;
};
// SimpleSignaturePolicy modifies the base SignaturePolicy by allowing the
@@ -51,8 +54,8 @@ class NET_EXPORT SimpleSignaturePolicy : public SignaturePolicy {
public:
explicit SimpleSignaturePolicy(size_t min_rsa_modulus_length_bits);
- bool IsAcceptableModulusLengthForRsa(
- size_t modulus_length_bits) const override;
+ bool IsAcceptableModulusLengthForRsa(size_t modulus_length_bits,
+ CertErrors* errors) const override;
private:
const size_t min_rsa_modulus_length_bits_;
diff --git a/chromium/net/cert/internal/test_helpers.cc b/chromium/net/cert/internal/test_helpers.cc
index 71b9a26e90a..2b87e49d866 100644
--- a/chromium/net/cert/internal/test_helpers.cc
+++ b/chromium/net/cert/internal/test_helpers.cc
@@ -8,6 +8,7 @@
#include "base/base_paths.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
+#include "net/cert/internal/cert_errors.h"
#include "net/cert/pem_tokenizer.h"
#include "net/der/parser.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -100,4 +101,98 @@ der::Input SequenceValueFromString(const std::string* s) {
return ::testing::AssertionSuccess();
}
+void ReadVerifyCertChainTestFromFile(const std::string& file_path_ascii,
+ ParsedCertificateList* chain,
+ scoped_refptr<TrustAnchor>* trust_anchor,
+ der::GeneralizedTime* time,
+ bool* verify_result,
+ std::string* expected_errors) {
+ chain->clear();
+ *trust_anchor = nullptr;
+ expected_errors->clear();
+
+ std::string file_data = ReadTestFileToString(file_path_ascii);
+
+ std::vector<std::string> pem_headers;
+
+ // For details on the file format refer to:
+ // net/data/verify_certificate_chain_unittest/README.
+ const char kCertificateHeader[] = "CERTIFICATE";
+ const char kTrustAnchorUnconstrained[] = "TRUST_ANCHOR_UNCONSTRAINED";
+ const char kTrustAnchorConstrained[] = "TRUST_ANCHOR_CONSTRAINED";
+ const char kTimeHeader[] = "TIME";
+ const char kResultHeader[] = "VERIFY_RESULT";
+ const char kErrorsHeader[] = "ERRORS";
+
+ pem_headers.push_back(kCertificateHeader);
+ pem_headers.push_back(kTrustAnchorUnconstrained);
+ pem_headers.push_back(kTrustAnchorConstrained);
+ pem_headers.push_back(kTimeHeader);
+ pem_headers.push_back(kResultHeader);
+ pem_headers.push_back(kErrorsHeader);
+
+ bool has_time = false;
+ bool has_result = false;
+ bool has_errors = false;
+
+ PEMTokenizer pem_tokenizer(file_data, pem_headers);
+ while (pem_tokenizer.GetNext()) {
+ const std::string& block_type = pem_tokenizer.block_type();
+ const std::string& block_data = pem_tokenizer.data();
+
+ if (block_type == kCertificateHeader) {
+ CertErrors errors;
+ ASSERT_TRUE(net::ParsedCertificate::CreateAndAddToVector(block_data, {},
+ chain, &errors))
+ << errors.ToDebugString();
+ } else if (block_type == kTrustAnchorUnconstrained ||
+ block_type == kTrustAnchorConstrained) {
+ ASSERT_FALSE(*trust_anchor) << "Duplicate trust anchor";
+ CertErrors errors;
+ scoped_refptr<ParsedCertificate> root =
+ net::ParsedCertificate::Create(block_data, {}, &errors);
+ ASSERT_TRUE(root) << errors.ToDebugString();
+ *trust_anchor =
+ block_type == kTrustAnchorUnconstrained
+ ? TrustAnchor::CreateFromCertificateNoConstraints(std::move(root))
+ : TrustAnchor::CreateFromCertificateWithConstraints(
+ std::move(root));
+ } else if (block_type == kTimeHeader) {
+ ASSERT_FALSE(has_time) << "Duplicate " << kTimeHeader;
+ has_time = true;
+ ASSERT_TRUE(der::ParseUTCTime(der::Input(&block_data), time));
+ } else if (block_type == kResultHeader) {
+ ASSERT_FALSE(has_result) << "Duplicate " << kResultHeader;
+ ASSERT_TRUE(block_data == "SUCCESS" || block_data == "FAIL")
+ << "Unrecognized result: " << block_data;
+ has_result = true;
+ *verify_result = block_data == "SUCCESS";
+ } else if (block_type == kErrorsHeader) {
+ ASSERT_FALSE(has_errors) << "Duplicate " << kErrorsHeader;
+ has_errors = true;
+ *expected_errors = block_data;
+ }
+ }
+
+ ASSERT_TRUE(has_time);
+ ASSERT_TRUE(has_result);
+ ASSERT_TRUE(*trust_anchor);
+}
+
+std::string ReadTestFileToString(const std::string& file_path_ascii) {
+ // Compute the full path, relative to the src/ directory.
+ base::FilePath src_root;
+ PathService::Get(base::DIR_SOURCE_ROOT, &src_root);
+ base::FilePath filepath = src_root.AppendASCII(file_path_ascii);
+
+ // Read the full contents of the file.
+ std::string file_data;
+ if (!base::ReadFileToString(filepath, &file_data)) {
+ ADD_FAILURE() << "Couldn't read file: " << filepath.value();
+ return std::string();
+ }
+
+ return file_data;
+}
+
} // namespace net
diff --git a/chromium/net/cert/internal/test_helpers.h b/chromium/net/cert/internal/test_helpers.h
index 999c37b5569..0e4cd17a58d 100644
--- a/chromium/net/cert/internal/test_helpers.h
+++ b/chromium/net/cert/internal/test_helpers.h
@@ -11,6 +11,8 @@
#include <string>
#include <vector>
+#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/trust_store.h"
#include "net/der/input.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -74,6 +76,21 @@ template <size_t N>
return ReadTestDataFromPemFile(file_path_ascii, mappings, N);
}
+// Reads a test case from |file_path_ascii| (which is relative to //src). Test
+// cases are comprised of a certificate chain, trust anchor, a timestamp to
+// validate at, and the expected result of verification.
+// Generally |file_path_ascii| will start with:
+// net/data/verify_certificate_chain_unittest/
+void ReadVerifyCertChainTestFromFile(const std::string& file_path_ascii,
+ ParsedCertificateList* chain,
+ scoped_refptr<TrustAnchor>* trust_anchor,
+ der::GeneralizedTime* time,
+ bool* verify_result,
+ std::string* expected_errors);
+
+// Reads a data file relative to the src root directory.
+std::string ReadTestFileToString(const std::string& file_path_ascii);
+
} // namespace net
#endif // NET_CERT_INTERNAL_TEST_HELPERS_H_
diff --git a/chromium/net/cert/internal/trust_store.cc b/chromium/net/cert/internal/trust_store.cc
index 892698ba5f6..07eff04a326 100644
--- a/chromium/net/cert/internal/trust_store.cc
+++ b/chromium/net/cert/internal/trust_store.cc
@@ -4,41 +4,42 @@
#include "net/cert/internal/trust_store.h"
-#include "net/cert/internal/parsed_certificate.h"
-
namespace net {
-TrustStore::TrustStore() {}
-TrustStore::~TrustStore() {}
+scoped_refptr<TrustAnchor> TrustAnchor::CreateFromCertificateNoConstraints(
+ scoped_refptr<ParsedCertificate> cert) {
+ return scoped_refptr<TrustAnchor>(new TrustAnchor(std::move(cert), false));
+}
+
+scoped_refptr<TrustAnchor> TrustAnchor::CreateFromCertificateWithConstraints(
+ scoped_refptr<ParsedCertificate> cert) {
+ return scoped_refptr<TrustAnchor>(new TrustAnchor(std::move(cert), true));
+}
-void TrustStore::Clear() {
- anchors_.clear();
+der::Input TrustAnchor::spki() const {
+ return cert_->tbs().spki_tlv;
}
-void TrustStore::AddTrustedCertificate(
- scoped_refptr<ParsedCertificate> anchor) {
- // TODO(mattm): should this check for duplicate certs?
- anchors_.insert(std::make_pair(anchor->normalized_subject().AsStringPiece(),
- std::move(anchor)));
+der::Input TrustAnchor::normalized_subject() const {
+ return cert_->normalized_subject();
}
-void TrustStore::FindTrustAnchorsByNormalizedName(
- const der::Input& normalized_name,
- std::vector<scoped_refptr<ParsedCertificate>>* matches) const {
- auto range = anchors_.equal_range(normalized_name.AsStringPiece());
- for (auto it = range.first; it != range.second; ++it)
- matches->push_back(it->second);
+const scoped_refptr<ParsedCertificate>& TrustAnchor::cert() const {
+ return cert_;
}
-bool TrustStore::IsTrustedCertificate(const ParsedCertificate* cert) const {
- auto range = anchors_.equal_range(cert->normalized_subject().AsStringPiece());
- for (auto it = range.first; it != range.second; ++it) {
- // First compare the ParsedCertificate pointers as an optimization, fall
- // back to comparing full DER encoding.
- if (it->second == cert || it->second->der_cert() == cert->der_cert())
- return true;
- }
- return false;
+TrustAnchor::TrustAnchor(scoped_refptr<ParsedCertificate> cert,
+ bool enforces_constraints)
+ : cert_(std::move(cert)), enforces_constraints_(enforces_constraints) {
+ DCHECK(cert_);
}
+TrustAnchor::~TrustAnchor() = default;
+
+TrustStore::Request::Request() = default;
+TrustStore::Request::~Request() = default;
+
+TrustStore::TrustStore() = default;
+TrustStore::~TrustStore() = default;
+
} // namespace net
diff --git a/chromium/net/cert/internal/trust_store.h b/chromium/net/cert/internal/trust_store.h
index 611af1c40a3..8422fd5c96a 100644
--- a/chromium/net/cert/internal/trust_store.h
+++ b/chromium/net/cert/internal/trust_store.h
@@ -5,12 +5,12 @@
#ifndef NET_CERT_INTERNAL_TRUST_STORE_H_
#define NET_CERT_INTERNAL_TRUST_STORE_H_
-#include <unordered_map>
#include <vector>
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
-#include "base/strings/string_piece.h"
#include "net/base/net_export.h"
+#include "net/cert/internal/parsed_certificate.h"
namespace net {
@@ -18,39 +18,134 @@ namespace der {
class Input;
}
-class ParsedCertificate;
-
-// A very simple implementation of a TrustStore, which contains a set of
-// trusted certificates.
-// TODO(mattm): convert this into an interface, provide implementations that
-// interface with OS trust store.
-class NET_EXPORT TrustStore {
+// A TrustAnchor represents a trust anchor used during RFC 5280 path validation.
+//
+// At its core, each trust anchor has two parts:
+// * Name
+// * Public Key
+//
+// Optionally a trust anchor may contain:
+// * An associated certificate (used when pretty-printing)
+// * Mandatory trust anchor constraints
+//
+// Relationship between ParsedCertificate and TrustAnchor:
+//
+// For convenience trust anchors are often described using a
+// (self-signed) certificate. TrustAnchor facilitates this by allowing
+// construction of a TrustAnchor given a ParsedCertificate.
+//
+// When constructing a TrustAnchor from a certificate there are different
+// interpretations for the meaning of properties other than the Subject and
+// SPKI in the certificate.
+//
+// * CreateFromCertificateNoConstraints() -- Extracts the Subject and SPKI from
+// the source certificate. ALL other information in the certificate is
+// considered irrelevant during path validation.
+//
+// * CreateFromCertificateWithConstraints() -- Extracts the Subject and SPKI
+// from the source certificate, and additionally interprets some properties of
+// the source certificate as mandatory anchor constraints.
+//
+// Trust anchor constraints are described in more detail by RFC 5937. This
+// implementation follows that description, and fixes
+// "enforceTrustAnchorConstraints" to true.
+class NET_EXPORT TrustAnchor : public base::RefCountedThreadSafe<TrustAnchor> {
public:
- TrustStore();
- ~TrustStore();
+ // Creates a TrustAnchor given a certificate. The ONLY parts of the
+ // certificate that are relevant to the resulting trust anchor are:
+ //
+ // * Subject
+ // * SPKI
+ //
+ // Everything else, including the source certiticate's expiration, basic
+ // constraints, policy constraints, etc is not used.
+ //
+ // This is the common interpretation for a trust anchor when given as a
+ // certificate.
+ static scoped_refptr<TrustAnchor> CreateFromCertificateNoConstraints(
+ scoped_refptr<ParsedCertificate> cert);
- // Empties the trust store, resetting it to original state.
- void Clear();
+ // Creates a TrustAnchor given a certificate. The resulting trust anchor is
+ // initialized using the source certificate's subject and SPKI as usual,
+ // however other parts of the certificate are applied as anchor constraints.
+ //
+ // The implementation matches the properties identified by RFC 5937,
+ // resulting in the following hodgepodge of enforcement on the source
+ // certificate:
+ //
+ // * Signature: No
+ // * Validity (expiration): No
+ // * Key usage: No
+ // * Extended key usage: No
+ // * Basic constraints: Yes, but only the pathlen (CA=false is accepted)
+ // * Name constraints: Yes
+ // * Certificate policies: Not currently, TODO(crbug.com/634453)
+ // * inhibitAnyPolicy: Not currently, TODO(crbug.com/634453)
+ // * PolicyConstraints: Not currently, TODO(crbug.com/634452)
+ //
+ // The presence of any other unrecognized extension marked as critical fails
+ // validation.
+ static scoped_refptr<TrustAnchor> CreateFromCertificateWithConstraints(
+ scoped_refptr<ParsedCertificate> cert);
- // Adds a trusted certificate to the store.
- void AddTrustedCertificate(scoped_refptr<ParsedCertificate> anchor);
+ der::Input spki() const;
+ der::Input normalized_subject() const;
- // Returns the trust anchors that match |name| in |*matches|, if any.
- void FindTrustAnchorsByNormalizedName(
- const der::Input& normalized_name,
- std::vector<scoped_refptr<ParsedCertificate>>* matches) const;
+ // Returns the optional certificate representing this trust anchor.
+ // In the current implementation it will never return nullptr...
+ // however clients should be prepared to handle this case.
+ const scoped_refptr<ParsedCertificate>& cert() const;
- // Returns true if |cert| matches a certificate in the TrustStore.
- bool IsTrustedCertificate(const ParsedCertificate* cert) const
- WARN_UNUSED_RESULT;
+ // Returns true if the trust anchor has attached (mandatory) trust anchor
+ // constraints. This returns true when the anchor was constructed using
+ // CreateFromCertificateWithConstraints.
+ bool enforces_constraints() const { return enforces_constraints_; }
private:
- // Multimap from normalized subject -> ParsedCertificate.
- std::unordered_multimap<base::StringPiece,
- scoped_refptr<ParsedCertificate>,
- base::StringPieceHash>
- anchors_;
+ friend class base::RefCountedThreadSafe<TrustAnchor>;
+ TrustAnchor(scoped_refptr<ParsedCertificate>, bool enforces_constraints);
+ ~TrustAnchor();
+
+ scoped_refptr<ParsedCertificate> cert_;
+ bool enforces_constraints_ = false;
+};
+
+using TrustAnchors = std::vector<scoped_refptr<TrustAnchor>>;
+
+// Interface for finding trust anchors.
+class NET_EXPORT TrustStore {
+ public:
+ class NET_EXPORT Request {
+ public:
+ Request();
+ // Destruction of the Request cancels it.
+ virtual ~Request();
+ };
+
+ TrustStore();
+ virtual ~TrustStore();
+ using TrustAnchorsCallback = base::Callback<void(TrustAnchors)>;
+
+ // Returns the trust anchors that match |cert|'s issuer name in
+ // |*synchronous_matches| and/or through |callback|. |cert| and
+ // |synchronous_matches| must not be null.
+ //
+ // If results are available synchronously, they will be appended to
+ // |*synchronous_matches|. |*synchronous_matches| will not be modified
+ // asynchronously.
+ //
+ // If |callback| is not null and results may be available asynchronously,
+ // |*out_req| will be filled with a Request, and |callback| will be called
+ // when results are available. The Request may be destroyed to cancel
+ // the callback if it has not occurred yet.
+ virtual void FindTrustAnchorsForCert(
+ const scoped_refptr<ParsedCertificate>& cert,
+ const TrustAnchorsCallback& callback,
+ TrustAnchors* synchronous_matches,
+ std::unique_ptr<Request>* out_req) const = 0;
+
+ private:
DISALLOW_COPY_AND_ASSIGN(TrustStore);
};
diff --git a/chromium/net/cert/internal/trust_store_collection.cc b/chromium/net/cert/internal/trust_store_collection.cc
new file mode 100644
index 00000000000..dc35306eee2
--- /dev/null
+++ b/chromium/net/cert/internal/trust_store_collection.cc
@@ -0,0 +1,38 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/trust_store_collection.h"
+
+namespace net {
+
+TrustStoreCollection::TrustStoreCollection() = default;
+TrustStoreCollection::~TrustStoreCollection() = default;
+
+void TrustStoreCollection::SetPrimaryTrustStore(TrustStore* store) {
+ DCHECK(!primary_store_);
+ DCHECK(store);
+ primary_store_ = store;
+}
+
+void TrustStoreCollection::AddTrustStoreSynchronousOnly(TrustStore* store) {
+ DCHECK(store);
+ sync_only_stores_.push_back(store);
+}
+
+void TrustStoreCollection::FindTrustAnchorsForCert(
+ const scoped_refptr<ParsedCertificate>& cert,
+ const TrustAnchorsCallback& callback,
+ TrustAnchors* synchronous_matches,
+ std::unique_ptr<Request>* out_req) const {
+ if (primary_store_)
+ primary_store_->FindTrustAnchorsForCert(cert, callback, synchronous_matches,
+ out_req);
+
+ for (auto* store : sync_only_stores_) {
+ store->FindTrustAnchorsForCert(cert, TrustAnchorsCallback(),
+ synchronous_matches, nullptr);
+ }
+}
+
+} // namespace net
diff --git a/chromium/net/cert/internal/trust_store_collection.h b/chromium/net/cert/internal/trust_store_collection.h
new file mode 100644
index 00000000000..ec9d49fd8e2
--- /dev/null
+++ b/chromium/net/cert/internal/trust_store_collection.h
@@ -0,0 +1,62 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_CERT_INTERNAL_TRUST_STORE_COLLECTION_H_
+#define NET_CERT_INTERNAL_TRUST_STORE_COLLECTION_H_
+
+#include "base/memory/ref_counted.h"
+#include "net/base/net_export.h"
+#include "net/cert/internal/trust_store.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace net {
+
+// TrustStoreCollection is an implementation of TrustStore which combines the
+// results from multiple TrustStores.
+//
+// The synchronous matches will be in order from the primary store, and then
+// from the secondary stores in the order they were added to the
+// TrustStoreCollection.
+//
+// Currently only one "primary" store can be added that supports async queries,
+// any number of additional, synchronous-only stores can be used. (The
+// assumption is that the async one would be useful for OS integration, while
+// the sync only stores can be used for supplying additional anchors. If
+// multiple async stores are desired, it might be worth changing the
+// FindTrustAnchorsForCert interface so that it can return async results in
+// multiple batches.)
+class NET_EXPORT TrustStoreCollection : public TrustStore {
+ public:
+ TrustStoreCollection();
+ ~TrustStoreCollection() override;
+
+ // Includes results from |store| in the combined output. Both sync and async
+ // queries to |store| will be allowed. |store| must outlive the
+ // TrustStoreCollection.
+ void SetPrimaryTrustStore(TrustStore* store);
+
+ // Includes results from |store| in the combined output. |store| will only be
+ // queried synchronously. |store| must outlive the TrustStoreCollection.
+ void AddTrustStoreSynchronousOnly(TrustStore* store);
+
+ // TrustStore implementation:
+ void FindTrustAnchorsForCert(
+ const scoped_refptr<ParsedCertificate>& cert,
+ const TrustAnchorsCallback& callback,
+ TrustAnchors* synchronous_matches,
+ std::unique_ptr<Request>* out_req) const override;
+
+ private:
+ TrustStore* primary_store_ = nullptr;
+ std::vector<TrustStore*> sync_only_stores_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrustStoreCollection);
+};
+
+} // namespace net
+
+#endif // NET_CERT_INTERNAL_TRUST_STORE_COLLECTION_H_
diff --git a/chromium/net/cert/internal/trust_store_collection_unittest.cc b/chromium/net/cert/internal/trust_store_collection_unittest.cc
new file mode 100644
index 00000000000..a7561d3f782
--- /dev/null
+++ b/chromium/net/cert/internal/trust_store_collection_unittest.cc
@@ -0,0 +1,231 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/trust_store_collection.h"
+
+#include "base/bind.h"
+#include "net/cert/internal/test_helpers.h"
+#include "net/cert/internal/trust_store_test_helpers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+using ::testing::_;
+using ::testing::Property;
+using ::testing::StrictMock;
+
+void NotCalled(TrustAnchors anchors) {
+ ADD_FAILURE() << "NotCalled was called";
+}
+
+class MockTrustStore : public TrustStore {
+ public:
+ MOCK_CONST_METHOD4(FindTrustAnchorsForCert,
+ void(const scoped_refptr<ParsedCertificate>&,
+ const TrustAnchorsCallback&,
+ TrustAnchors*,
+ std::unique_ptr<Request>*));
+};
+
+class TrustStoreCollectionTest : public testing::Test {
+ public:
+ void SetUp() override {
+ ParsedCertificateList chain;
+ bool unused_verify_result;
+ der::GeneralizedTime unused_time;
+ std::string unused_errors;
+
+ ReadVerifyCertChainTestFromFile(
+ "net/data/verify_certificate_chain_unittest/key-rollover-oldchain.pem",
+ &chain, &oldroot_, &unused_time, &unused_verify_result, &unused_errors);
+ ASSERT_EQ(2U, chain.size());
+ target_ = chain[0];
+ oldintermediate_ = chain[1];
+ ASSERT_TRUE(target_);
+ ASSERT_TRUE(oldintermediate_);
+ ASSERT_TRUE(oldroot_);
+
+ scoped_refptr<TrustAnchor> unused_root;
+ ReadVerifyCertChainTestFromFile(
+ "net/data/verify_certificate_chain_unittest/"
+ "key-rollover-longrolloverchain.pem",
+ &chain, &unused_root, &unused_time, &unused_verify_result,
+ &unused_errors);
+ ASSERT_EQ(4U, chain.size());
+ newintermediate_ = chain[1];
+ newroot_ = TrustAnchor::CreateFromCertificateNoConstraints(chain[2]);
+ newrootrollover_ =
+ TrustAnchor::CreateFromCertificateNoConstraints(chain[3]);
+ ASSERT_TRUE(newintermediate_);
+ ASSERT_TRUE(newroot_);
+ ASSERT_TRUE(newrootrollover_);
+ }
+
+ protected:
+ scoped_refptr<TrustAnchor> oldroot_;
+ scoped_refptr<TrustAnchor> newroot_;
+ scoped_refptr<TrustAnchor> newrootrollover_;
+
+ scoped_refptr<ParsedCertificate> target_;
+ scoped_refptr<ParsedCertificate> oldintermediate_;
+ scoped_refptr<ParsedCertificate> newintermediate_;
+};
+
+// Collection contains no stores, should return no results and complete
+// synchronously.
+TEST_F(TrustStoreCollectionTest, NoStores) {
+ std::unique_ptr<TrustStore::Request> req;
+ TrustAnchors sync_matches;
+
+ TrustStoreCollection collection;
+ collection.FindTrustAnchorsForCert(target_, base::Bind(&NotCalled),
+ &sync_matches, &req);
+
+ EXPECT_FALSE(req);
+ EXPECT_TRUE(sync_matches.empty());
+}
+
+// Collection contains only one synchronous store, should complete
+// synchronously.
+TEST_F(TrustStoreCollectionTest, NoPrimaryStoreOneSyncStore) {
+ std::unique_ptr<TrustStore::Request> req;
+ TrustAnchors sync_matches;
+
+ TrustStoreCollection collection;
+ TrustStoreInMemory in_memory;
+ in_memory.AddTrustAnchor(newroot_);
+ collection.AddTrustStoreSynchronousOnly(&in_memory);
+ collection.FindTrustAnchorsForCert(newintermediate_, base::Bind(&NotCalled),
+ &sync_matches, &req);
+
+ EXPECT_FALSE(req);
+ ASSERT_EQ(1U, sync_matches.size());
+ EXPECT_EQ(newroot_, sync_matches[0]);
+}
+
+// Collection contains two synchronous stores, should complete synchronously.
+TEST_F(TrustStoreCollectionTest, NoPrimaryStoreTwoSyncStores) {
+ std::unique_ptr<TrustStore::Request> req;
+ TrustAnchors sync_matches;
+
+ TrustStoreCollection collection;
+ TrustStoreInMemory in_memory1;
+ TrustStoreInMemory in_memory2;
+ in_memory1.AddTrustAnchor(newroot_);
+ in_memory2.AddTrustAnchor(oldroot_);
+ collection.AddTrustStoreSynchronousOnly(&in_memory1);
+ collection.AddTrustStoreSynchronousOnly(&in_memory2);
+ collection.FindTrustAnchorsForCert(newintermediate_, base::Bind(&NotCalled),
+ &sync_matches, &req);
+
+ EXPECT_FALSE(req);
+ ASSERT_EQ(2U, sync_matches.size());
+ EXPECT_EQ(newroot_, sync_matches[0]);
+ EXPECT_EQ(oldroot_, sync_matches[1]);
+}
+
+// The secondary stores in the collection should not be passed a callback to
+// their FindTrustAnchorsForCert call.
+TEST_F(TrustStoreCollectionTest, SyncStoresAreQueriedSynchronously) {
+ std::unique_ptr<TrustStore::Request> req;
+ TrustAnchors sync_matches;
+
+ TrustStoreCollection collection;
+ StrictMock<MockTrustStore> store;
+ collection.AddTrustStoreSynchronousOnly(&store);
+
+ EXPECT_CALL(
+ store,
+ FindTrustAnchorsForCert(
+ _, Property(&TrustStore::TrustAnchorsCallback::is_null, true), _, _));
+
+ collection.FindTrustAnchorsForCert(newintermediate_, base::Bind(&NotCalled),
+ &sync_matches, &req);
+
+ EXPECT_FALSE(req);
+ EXPECT_TRUE(sync_matches.empty());
+}
+
+// If the primary store completes synchronously, TrustStoreCollection should
+// complete synchronously also.
+TEST_F(TrustStoreCollectionTest, AllStoresAreSynchronous) {
+ std::unique_ptr<TrustStore::Request> req;
+ TrustAnchors sync_matches;
+
+ TrustStoreCollection collection;
+ TrustStoreInMemory in_memory1;
+ TrustStoreInMemory in_memory2;
+ in_memory1.AddTrustAnchor(newroot_);
+ in_memory2.AddTrustAnchor(oldroot_);
+ collection.SetPrimaryTrustStore(&in_memory1);
+ collection.AddTrustStoreSynchronousOnly(&in_memory2);
+ collection.FindTrustAnchorsForCert(newintermediate_, base::Bind(&NotCalled),
+ &sync_matches, &req);
+
+ EXPECT_FALSE(req);
+ ASSERT_EQ(2U, sync_matches.size());
+ EXPECT_EQ(newroot_, sync_matches[0]);
+ EXPECT_EQ(oldroot_, sync_matches[1]);
+}
+
+// Primary store returns results asynchronously. No secondary stores registered.
+TEST_F(TrustStoreCollectionTest, AsyncPrimaryStore) {
+ std::unique_ptr<TrustStore::Request> req;
+ TrustAnchors sync_matches;
+
+ TrustStoreInMemoryAsync in_memory_async;
+ in_memory_async.AddAsyncTrustAnchor(newroot_);
+
+ TrustStoreCollection collection;
+ collection.SetPrimaryTrustStore(&in_memory_async);
+
+ TrustAnchorResultRecorder anchor_results;
+ collection.FindTrustAnchorsForCert(
+ newintermediate_, anchor_results.Callback(), &sync_matches, &req);
+
+ ASSERT_TRUE(req);
+ EXPECT_TRUE(sync_matches.empty());
+
+ anchor_results.Run();
+ ASSERT_EQ(1U, anchor_results.matches().size());
+ EXPECT_EQ(newroot_, anchor_results.matches()[0]);
+}
+
+// Primary store returns results both synchronously and asynchronously, and
+// a secondary store returns results synchronously as well.
+TEST_F(TrustStoreCollectionTest, SyncAndAsyncPrimaryStoreAndSyncStore) {
+ std::unique_ptr<TrustStore::Request> req;
+ TrustAnchors sync_matches;
+
+ TrustStoreInMemoryAsync in_memory_async;
+ in_memory_async.AddAsyncTrustAnchor(newroot_);
+ in_memory_async.AddSyncTrustAnchor(newrootrollover_);
+
+ TrustStoreInMemory in_memory;
+ in_memory.AddTrustAnchor(oldroot_);
+
+ TrustStoreCollection collection;
+ collection.SetPrimaryTrustStore(&in_memory_async);
+ collection.AddTrustStoreSynchronousOnly(&in_memory);
+
+ TrustAnchorResultRecorder anchor_results;
+ collection.FindTrustAnchorsForCert(
+ newintermediate_, anchor_results.Callback(), &sync_matches, &req);
+
+ ASSERT_TRUE(req);
+ ASSERT_EQ(2U, sync_matches.size());
+ EXPECT_EQ(newrootrollover_, sync_matches[0]);
+ EXPECT_EQ(oldroot_, sync_matches[1]);
+
+ anchor_results.Run();
+ ASSERT_EQ(1U, anchor_results.matches().size());
+ EXPECT_EQ(newroot_, anchor_results.matches()[0]);
+}
+
+} // namespace
+
+} // namespace net
diff --git a/chromium/net/cert/internal/trust_store_in_memory.cc b/chromium/net/cert/internal/trust_store_in_memory.cc
new file mode 100644
index 00000000000..4cdab9672d2
--- /dev/null
+++ b/chromium/net/cert/internal/trust_store_in_memory.cc
@@ -0,0 +1,32 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/trust_store_in_memory.h"
+
+namespace net {
+
+TrustStoreInMemory::TrustStoreInMemory() = default;
+TrustStoreInMemory::~TrustStoreInMemory() = default;
+
+void TrustStoreInMemory::Clear() {
+ anchors_.clear();
+}
+
+void TrustStoreInMemory::AddTrustAnchor(scoped_refptr<TrustAnchor> anchor) {
+ // TODO(mattm): should this check for duplicate anchors?
+ anchors_.insert(std::make_pair(anchor->normalized_subject().AsStringPiece(),
+ std::move(anchor)));
+}
+
+void TrustStoreInMemory::FindTrustAnchorsForCert(
+ const scoped_refptr<ParsedCertificate>& cert,
+ const TrustAnchorsCallback& callback,
+ TrustAnchors* synchronous_matches,
+ std::unique_ptr<Request>* out_req) const {
+ auto range = anchors_.equal_range(cert->normalized_issuer().AsStringPiece());
+ for (auto it = range.first; it != range.second; ++it)
+ synchronous_matches->push_back(it->second);
+}
+
+} // namespace net
diff --git a/chromium/net/cert/internal/trust_store_in_memory.h b/chromium/net/cert/internal/trust_store_in_memory.h
new file mode 100644
index 00000000000..fea4c87d314
--- /dev/null
+++ b/chromium/net/cert/internal/trust_store_in_memory.h
@@ -0,0 +1,52 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_CERT_INTERNAL_TRUST_STORE_IN_MEMORY_H_
+#define NET_CERT_INTERNAL_TRUST_STORE_IN_MEMORY_H_
+
+#include <unordered_map>
+
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/cert/internal/trust_store.h"
+
+namespace net {
+
+namespace der {
+class Input;
+}
+
+// A very simple implementation of a TrustStore, which contains a set of
+// trust anchors.
+class NET_EXPORT TrustStoreInMemory : public TrustStore {
+ public:
+ TrustStoreInMemory();
+ ~TrustStoreInMemory() override;
+
+ // Empties the trust store, resetting it to original state.
+ void Clear();
+
+ void AddTrustAnchor(scoped_refptr<TrustAnchor> anchor);
+
+ // TrustStore implementation:
+ void FindTrustAnchorsForCert(
+ const scoped_refptr<ParsedCertificate>& cert,
+ const TrustAnchorsCallback& callback,
+ TrustAnchors* synchronous_matches,
+ std::unique_ptr<Request>* out_req) const override;
+
+ private:
+ // Multimap from normalized subject -> TrustAnchor.
+ std::unordered_multimap<base::StringPiece,
+ scoped_refptr<TrustAnchor>,
+ base::StringPieceHash>
+ anchors_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrustStoreInMemory);
+};
+
+} // namespace net
+
+#endif // NET_CERT_INTERNAL_TRUST_STORE_IN_MEMORY_H_
diff --git a/chromium/net/cert/internal/trust_store_nss.cc b/chromium/net/cert/internal/trust_store_nss.cc
new file mode 100644
index 00000000000..1a01875ecdf
--- /dev/null
+++ b/chromium/net/cert/internal/trust_store_nss.cc
@@ -0,0 +1,137 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/trust_store_nss.h"
+
+#include <cert.h>
+#include <certdb.h>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#include "base/task_runner.h"
+#include "crypto/nss_util.h"
+#include "net/cert/internal/cert_errors.h"
+#include "net/cert/internal/parsed_certificate.h"
+
+// TODO(mattm): structure so that supporting ChromeOS multi-profile stuff is
+// doable (Have a TrustStoreChromeOS which uses net::NSSProfileFilterChromeOS,
+// similar to CertVerifyProcChromeOS.)
+
+namespace net {
+
+namespace {
+
+// Get all certs in NSS which have a subject matching |der_name| and which are
+// marked as a trusted CA.
+void GetAnchors(const scoped_refptr<ParsedCertificate>& cert,
+ SECTrustType trust_type,
+ TrustAnchors* out_anchors) {
+ crypto::EnsureNSSInit();
+
+ SECItem name;
+ // Use the original issuer value instead of the normalized version. NSS does a
+ // less extensive normalization in its Name comparisons, so our normalized
+ // version may not match the unnormalized version.
+ name.len = cert->tbs().issuer_tlv.Length();
+ name.data = const_cast<uint8_t*>(cert->tbs().issuer_tlv.UnsafeData());
+ // |validOnly| in CERT_CreateSubjectCertList controls whether to return only
+ // certs that are valid at |sorttime|. Expiration isn't meaningful for trust
+ // anchors, so request all the matches.
+ CERTCertList* found_certs = CERT_CreateSubjectCertList(
+ nullptr /* certList */, CERT_GetDefaultCertDB(), &name,
+ PR_Now() /* sorttime */, PR_FALSE /* validOnly */);
+ if (!found_certs)
+ return;
+
+ for (CERTCertListNode* node = CERT_LIST_HEAD(found_certs);
+ !CERT_LIST_END(node, found_certs); node = CERT_LIST_NEXT(node)) {
+ CERTCertTrust trust;
+ if (CERT_GetCertTrust(node->cert, &trust) != SECSuccess)
+ continue;
+
+ // TODO(mattm): handle explicit distrust (blacklisting)?
+ const int ca_trust = CERTDB_TRUSTED_CA;
+ if ((SEC_GET_TRUST_FLAGS(&trust, trust_type) & ca_trust) != ca_trust)
+ continue;
+
+ CertErrors errors;
+ scoped_refptr<ParsedCertificate> anchor_cert = ParsedCertificate::Create(
+ node->cert->derCert.data, node->cert->derCert.len, {}, &errors);
+ if (!anchor_cert) {
+ // TODO(crbug.com/634443): return errors better.
+ LOG(ERROR) << "Error parsing issuer certificate:\n"
+ << errors.ToDebugString();
+ continue;
+ }
+
+ out_anchors->push_back(TrustAnchor::CreateFromCertificateNoConstraints(
+ std::move(anchor_cert)));
+ }
+ CERT_DestroyCertList(found_certs);
+}
+
+class GetAnchorsRequest : public TrustStore::Request {
+ public:
+ explicit GetAnchorsRequest(const TrustStore::TrustAnchorsCallback& callback);
+ // Destruction of the Request cancels it. GetAnchors will still run, but the
+ // callback will not be called since the WeakPtr will be invalidated.
+ ~GetAnchorsRequest() override = default;
+
+ void Start(const scoped_refptr<ParsedCertificate>& cert,
+ SECTrustType trust_type,
+ base::TaskRunner* task_runner);
+
+ private:
+ void HandleGetAnchors(std::unique_ptr<TrustAnchors> anchors);
+
+ TrustStore::TrustAnchorsCallback callback_;
+ base::WeakPtrFactory<GetAnchorsRequest> weak_ptr_factory_;
+};
+
+GetAnchorsRequest::GetAnchorsRequest(
+ const TrustStore::TrustAnchorsCallback& callback)
+ : callback_(callback), weak_ptr_factory_(this) {}
+
+void GetAnchorsRequest::Start(const scoped_refptr<ParsedCertificate>& cert,
+ SECTrustType trust_type,
+ base::TaskRunner* task_runner) {
+ auto anchors = base::MakeUnique<TrustAnchors>();
+
+ auto* anchors_ptr = anchors.get();
+ task_runner->PostTaskAndReply(
+ FROM_HERE, base::Bind(&GetAnchors, cert, trust_type, anchors_ptr),
+ base::Bind(&GetAnchorsRequest::HandleGetAnchors,
+ weak_ptr_factory_.GetWeakPtr(), base::Passed(&anchors)));
+}
+
+void GetAnchorsRequest::HandleGetAnchors(
+ std::unique_ptr<TrustAnchors> anchors) {
+ base::ResetAndReturn(&callback_).Run(std::move(*anchors));
+ // |this| may be deleted here.
+}
+
+} // namespace
+
+TrustStoreNSS::TrustStoreNSS(SECTrustType trust_type,
+ scoped_refptr<base::TaskRunner> nss_task_runner)
+ : trust_type_(trust_type), nss_task_runner_(std::move(nss_task_runner)) {}
+
+TrustStoreNSS::~TrustStoreNSS() = default;
+
+void TrustStoreNSS::FindTrustAnchorsForCert(
+ const scoped_refptr<ParsedCertificate>& cert,
+ const TrustAnchorsCallback& callback,
+ TrustAnchors* synchronous_matches,
+ std::unique_ptr<Request>* out_req) const {
+ if (callback.is_null())
+ return;
+
+ auto req = base::MakeUnique<GetAnchorsRequest>(callback);
+ req->Start(cert, trust_type_, nss_task_runner_.get());
+ *out_req = std::move(req);
+}
+
+} // namespace net
diff --git a/chromium/net/cert/internal/trust_store_nss.h b/chromium/net/cert/internal/trust_store_nss.h
new file mode 100644
index 00000000000..d153dbc5fdf
--- /dev/null
+++ b/chromium/net/cert/internal/trust_store_nss.h
@@ -0,0 +1,50 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_CERT_INTERNAL_TRUST_STORE_NSS_H_
+#define NET_CERT_INTERNAL_TRUST_STORE_NSS_H_
+
+#include <certt.h>
+
+#include "base/memory/ref_counted.h"
+#include "net/base/net_export.h"
+#include "net/cert/internal/trust_store.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace net {
+
+// TrustStoreNSS is an implementation of TrustStore which uses NSS to find trust
+// anchors for path building.
+// TODO(mattm): also implement CertIssuerSource to return intermediates in NSS
+// DB? Or have a separate CertIssuerSourceNSS for that? (implementing both in
+// the same class could be more efficient with some caching/etc. Need to be
+// careful about caching between different pathbuilder instances though.)
+class NET_EXPORT TrustStoreNSS : public TrustStore {
+ public:
+ // Creates a TrustStoreNSS which will find anchors that are trusted for
+ // |trust_type|. All NSS calls will be done on |nss_task_runner|.
+ TrustStoreNSS(SECTrustType trust_type,
+ scoped_refptr<base::TaskRunner> nss_task_runner);
+ ~TrustStoreNSS() override;
+
+ // TrustStore implementation:
+ void FindTrustAnchorsForCert(
+ const scoped_refptr<ParsedCertificate>& cert,
+ const TrustAnchorsCallback& callback,
+ TrustAnchors* synchronous_matches,
+ std::unique_ptr<Request>* out_req) const override;
+
+ private:
+ SECTrustType trust_type_;
+ scoped_refptr<base::TaskRunner> nss_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrustStoreNSS);
+};
+
+} // namespace net
+
+#endif // NET_CERT_INTERNAL_TRUST_STORE_NSS_H_
diff --git a/chromium/net/cert/internal/trust_store_nss_unittest.cc b/chromium/net/cert/internal/trust_store_nss_unittest.cc
new file mode 100644
index 00000000000..b74c5f97125
--- /dev/null
+++ b/chromium/net/cert/internal/trust_store_nss_unittest.cc
@@ -0,0 +1,248 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/trust_store_nss.h"
+
+#include <cert.h>
+#include <certdb.h>
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "crypto/scoped_test_nss_db.h"
+#include "net/cert/internal/test_helpers.h"
+#include "net/cert/internal/trust_store_test_helpers.h"
+#include "net/cert/scoped_nss_types.h"
+#include "net/cert/x509_certificate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+void NotCalled(TrustAnchors anchors) {
+ ADD_FAILURE() << "NotCalled was called";
+}
+
+class TrustStoreNSSTest : public testing::Test {
+ public:
+ void SetUp() override {
+ ASSERT_TRUE(test_nssdb_.is_open());
+
+ ParsedCertificateList chain;
+ bool unused_verify_result;
+ der::GeneralizedTime unused_time;
+ std::string unused_errors;
+
+ ReadVerifyCertChainTestFromFile(
+ "net/data/verify_certificate_chain_unittest/key-rollover-oldchain.pem",
+ &chain, &oldroot_, &unused_time, &unused_verify_result, &unused_errors);
+ ASSERT_EQ(2U, chain.size());
+ target_ = chain[0];
+ oldintermediate_ = chain[1];
+ ASSERT_TRUE(target_);
+ ASSERT_TRUE(oldintermediate_);
+ ASSERT_TRUE(oldroot_);
+
+ scoped_refptr<TrustAnchor> unused_root;
+ ReadVerifyCertChainTestFromFile(
+ "net/data/verify_certificate_chain_unittest/"
+ "key-rollover-longrolloverchain.pem",
+ &chain, &unused_root, &unused_time, &unused_verify_result,
+ &unused_errors);
+ ASSERT_EQ(4U, chain.size());
+ newintermediate_ = chain[1];
+ newroot_ = TrustAnchor::CreateFromCertificateNoConstraints(chain[2]);
+ newrootrollover_ = chain[3];
+ ASSERT_TRUE(newintermediate_);
+ ASSERT_TRUE(newroot_);
+ ASSERT_TRUE(newrootrollover_);
+
+ trust_store_nss_.reset(
+ new TrustStoreNSS(trustSSL, base::ThreadTaskRunnerHandle::Get()));
+ }
+
+ std::string GetUniqueNickname() {
+ return "trust_store_nss_unittest" + base::UintToString(nickname_counter_++);
+ }
+
+ void AddCertToNSS(const ParsedCertificate* cert) {
+ std::string nickname = GetUniqueNickname();
+ ScopedCERTCertificate nss_cert(
+ X509Certificate::CreateOSCertHandleFromBytesWithNickname(
+ cert->der_cert().AsStringPiece().data(), cert->der_cert().Length(),
+ nickname.c_str()));
+ ASSERT_TRUE(nss_cert);
+ SECStatus srv =
+ PK11_ImportCert(test_nssdb_.slot(), nss_cert.get(), CK_INVALID_HANDLE,
+ nickname.c_str(), PR_FALSE /* includeTrust (unused) */);
+ ASSERT_EQ(SECSuccess, srv);
+ }
+
+ void AddCertsToNSS() {
+ AddCertToNSS(target_.get());
+ AddCertToNSS(oldintermediate_.get());
+ AddCertToNSS(newintermediate_.get());
+ AddCertToNSS(oldroot_->cert().get());
+ AddCertToNSS(newroot_->cert().get());
+ AddCertToNSS(newrootrollover_.get());
+ }
+
+ // Trusts |cert|. Assumes the cert was already imported into NSS.
+ void TrustCert(const TrustAnchor* anchor) { TrustCert(anchor->cert().get()); }
+ void TrustCert(const ParsedCertificate* cert) {
+ SECItem der_cert;
+ der_cert.data = const_cast<uint8_t*>(cert->der_cert().UnsafeData());
+ der_cert.len = base::checked_cast<unsigned>(cert->der_cert().Length());
+ der_cert.type = siDERCertBuffer;
+
+ ScopedCERTCertificate nss_cert(
+ CERT_FindCertByDERCert(CERT_GetDefaultCertDB(), &der_cert));
+ ASSERT_TRUE(nss_cert);
+
+ CERTCertTrust trust = {0};
+ trust.sslFlags =
+ CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA | CERTDB_VALID_CA;
+ SECStatus srv =
+ CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nss_cert.get(), &trust);
+ ASSERT_EQ(SECSuccess, srv);
+ }
+
+ protected:
+ void ExpectTrustStoreContains(tracked_objects::Location loc,
+ scoped_refptr<ParsedCertificate> cert,
+ TrustAnchors expected_async_matches) {
+ SCOPED_TRACE(loc.ToString());
+
+ TrustAnchors sync_matches;
+ TrustAnchorResultRecorder anchor_results;
+ std::unique_ptr<TrustStore::Request> req;
+ trust_store_nss_->FindTrustAnchorsForCert(cert, anchor_results.Callback(),
+ &sync_matches, &req);
+ ASSERT_TRUE(req);
+ EXPECT_TRUE(sync_matches.empty());
+
+ anchor_results.Run();
+ std::vector<der::Input> der_result_matches;
+ for (const auto& it : anchor_results.matches())
+ der_result_matches.push_back(it->cert()->der_cert());
+ std::sort(der_result_matches.begin(), der_result_matches.end());
+
+ std::vector<der::Input> der_expected_matches;
+ for (const auto& it : expected_async_matches)
+ der_expected_matches.push_back(it->cert()->der_cert());
+ std::sort(der_expected_matches.begin(), der_expected_matches.end());
+
+ EXPECT_EQ(der_expected_matches, der_result_matches);
+ }
+
+ scoped_refptr<TrustAnchor> oldroot_;
+ scoped_refptr<TrustAnchor> newroot_;
+
+ scoped_refptr<ParsedCertificate> target_;
+ scoped_refptr<ParsedCertificate> oldintermediate_;
+ scoped_refptr<ParsedCertificate> newintermediate_;
+ scoped_refptr<ParsedCertificate> newrootrollover_;
+ crypto::ScopedTestNSSDB test_nssdb_;
+ std::unique_ptr<TrustStoreNSS> trust_store_nss_;
+ unsigned nickname_counter_ = 0;
+};
+
+// Without adding any certs to the NSS DB, should get no anchor results for any
+// of the test certs.
+TEST_F(TrustStoreNSSTest, CertsNotPresent) {
+ ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors());
+ ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors());
+ ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), TrustAnchors());
+}
+
+// If certs are present in NSS DB but aren't marked as trusted, should get no
+// anchor results for any of the test certs.
+TEST_F(TrustStoreNSSTest, CertsPresentButNotTrusted) {
+ AddCertsToNSS();
+ ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors());
+ ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors());
+ ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors());
+ ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), TrustAnchors());
+}
+
+// A self-signed CA certificate is trusted. FindTrustAnchorsForCert should
+// return the cert on any intermediates with a matching issuer, and on any
+// matching self-signed/self-issued CA certs.
+TEST_F(TrustStoreNSSTest, TrustedCA) {
+ AddCertsToNSS();
+ TrustCert(newroot_.get());
+ ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors());
+ ExpectTrustStoreContains(FROM_HERE, newintermediate_, {newroot_});
+ ExpectTrustStoreContains(FROM_HERE, oldintermediate_, {newroot_});
+ ExpectTrustStoreContains(FROM_HERE, newrootrollover_, {newroot_});
+ ExpectTrustStoreContains(FROM_HERE, oldroot_->cert(), {newroot_});
+ ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), {newroot_});
+}
+
+// When an intermediate certificate is trusted, FindTrustAnchorsForCert should
+// return that cert on any certs issued by the intermediate, but not for the
+// intermediate itself (or the CAs).
+TEST_F(TrustStoreNSSTest, TrustedIntermediate) {
+ AddCertsToNSS();
+ TrustCert(newintermediate_.get());
+ ExpectTrustStoreContains(
+ FROM_HERE, target_,
+ {TrustAnchor::CreateFromCertificateNoConstraints(newintermediate_)});
+ ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors());
+ ExpectTrustStoreContains(FROM_HERE, oldintermediate_, TrustAnchors());
+ ExpectTrustStoreContains(FROM_HERE, newrootrollover_, TrustAnchors());
+ ExpectTrustStoreContains(FROM_HERE, oldroot_->cert(), TrustAnchors());
+ ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), TrustAnchors());
+}
+
+// Multiple self-signed CA certificates with the same name are trusted.
+// FindTrustAnchorsForCert should return all these certs on any intermediates
+// with a matching issuer, and on any matching self-signed/self-issued CA certs.
+TEST_F(TrustStoreNSSTest, MultipleTrustedCAWithSameSubject) {
+ AddCertsToNSS();
+ TrustCert(oldroot_.get());
+ TrustCert(newroot_.get());
+ ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors());
+ ExpectTrustStoreContains(FROM_HERE, newintermediate_, {newroot_, oldroot_});
+ ExpectTrustStoreContains(FROM_HERE, oldintermediate_, {newroot_, oldroot_});
+ ExpectTrustStoreContains(FROM_HERE, oldroot_->cert(), {newroot_, oldroot_});
+}
+
+// Cancel a FindTrustAnchorsForCert request before it has returned any results.
+// Callback should not be called.
+TEST_F(TrustStoreNSSTest, CancelRequest) {
+ std::unique_ptr<TrustStore::Request> req;
+ TrustAnchors sync_matches;
+ trust_store_nss_->FindTrustAnchorsForCert(target_, base::Bind(&NotCalled),
+ &sync_matches, &req);
+ ASSERT_TRUE(req);
+ req.reset();
+ base::RunLoop().RunUntilIdle();
+}
+
+// Cancel a FindTrustAnchorsForCert request during the callback. Should not
+// crash.
+TEST_F(TrustStoreNSSTest, CancelRequestDuringCallback) {
+ AddCertsToNSS();
+ TrustCert(newroot_.get());
+
+ base::RunLoop run_loop;
+ std::unique_ptr<TrustStore::Request> req;
+ TrustAnchors sync_matches;
+ trust_store_nss_->FindTrustAnchorsForCert(
+ newintermediate_,
+ base::Bind(&TrustStoreRequestDeleter, &req, run_loop.QuitClosure()),
+ &sync_matches, &req);
+ ASSERT_TRUE(req);
+ run_loop.Run();
+ ASSERT_FALSE(req);
+ base::RunLoop().RunUntilIdle();
+}
+
+} // namespace
+
+} // namespace net
diff --git a/chromium/net/cert/internal/trust_store_test_helpers.cc b/chromium/net/cert/internal/trust_store_test_helpers.cc
new file mode 100644
index 00000000000..52edc4e61e4
--- /dev/null
+++ b/chromium/net/cert/internal/trust_store_test_helpers.cc
@@ -0,0 +1,95 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/trust_store_test_helpers.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_task_runner_handle.h"
+
+namespace net {
+
+namespace {
+
+class TrustStoreInMemoryAsyncRequest : public TrustStore::Request {
+ public:
+ explicit TrustStoreInMemoryAsyncRequest(
+ const TrustStore::TrustAnchorsCallback& callback)
+ : callback_(callback), weak_ptr_factory_(this) {}
+
+ void PostTrustCallback(TrustAnchors anchors) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&TrustStoreInMemoryAsyncRequest::DoTrustCallback,
+ weak_ptr_factory_.GetWeakPtr(), std::move(anchors)));
+ }
+
+ private:
+ void DoTrustCallback(TrustAnchors anchors) {
+ base::ResetAndReturn(&callback_).Run(std::move(anchors));
+ // |this| may be deleted here.
+ }
+
+ TrustStore::TrustAnchorsCallback callback_;
+ base::WeakPtrFactory<TrustStoreInMemoryAsyncRequest> weak_ptr_factory_;
+};
+
+} // namespace
+
+void TrustStoreRequestDeleter(std::unique_ptr<TrustStore::Request>* req_owner,
+ const base::Closure& done_callback,
+ TrustAnchors anchors) {
+ req_owner->reset();
+ done_callback.Run();
+}
+
+TrustAnchorResultRecorder::TrustAnchorResultRecorder() = default;
+TrustAnchorResultRecorder::~TrustAnchorResultRecorder() = default;
+
+TrustStore::TrustAnchorsCallback TrustAnchorResultRecorder::Callback() {
+ return base::Bind(&TrustAnchorResultRecorder::OnGotAnchors,
+ base::Unretained(this));
+}
+
+void TrustAnchorResultRecorder::OnGotAnchors(TrustAnchors anchors) {
+ anchors_ = std::move(anchors);
+ run_loop_.Quit();
+}
+
+TrustStoreInMemoryAsync::TrustStoreInMemoryAsync() = default;
+TrustStoreInMemoryAsync::~TrustStoreInMemoryAsync() = default;
+
+void TrustStoreInMemoryAsync::AddSyncTrustAnchor(
+ scoped_refptr<TrustAnchor> anchor) {
+ sync_store_.AddTrustAnchor(std::move(anchor));
+}
+
+void TrustStoreInMemoryAsync::AddAsyncTrustAnchor(
+ scoped_refptr<TrustAnchor> anchor) {
+ async_store_.AddTrustAnchor(std::move(anchor));
+}
+
+void TrustStoreInMemoryAsync::FindTrustAnchorsForCert(
+ const scoped_refptr<ParsedCertificate>& cert,
+ const TrustAnchorsCallback& callback,
+ TrustAnchors* synchronous_matches,
+ std::unique_ptr<Request>* out_req) const {
+ sync_store_.FindTrustAnchorsForCert(cert, TrustAnchorsCallback(),
+ synchronous_matches, nullptr);
+ if (!callback.is_null()) {
+ TrustAnchors async_matches;
+ async_store_.FindTrustAnchorsForCert(cert, TrustAnchorsCallback(),
+ &async_matches, nullptr);
+
+ std::unique_ptr<TrustStoreInMemoryAsyncRequest> req(
+ base::MakeUnique<TrustStoreInMemoryAsyncRequest>(callback));
+ req->PostTrustCallback(std::move(async_matches));
+
+ *out_req = std::move(req);
+ }
+}
+
+} // namespace net
diff --git a/chromium/net/cert/internal/trust_store_test_helpers.h b/chromium/net/cert/internal/trust_store_test_helpers.h
new file mode 100644
index 00000000000..3d1d5a6594c
--- /dev/null
+++ b/chromium/net/cert/internal/trust_store_test_helpers.h
@@ -0,0 +1,68 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_CERT_INTERNAL_TRUST_STORE_TEST_HELPERS_H_
+#define NET_CERT_INTERNAL_TRUST_STORE_TEST_HELPERS_H_
+
+#include "base/callback.h"
+#include "base/run_loop.h"
+#include "net/cert/internal/trust_store.h"
+#include "net/cert/internal/trust_store_in_memory.h"
+
+namespace net {
+
+// Deletes the Request owned by |*req_owner|, then calls done_callback. Intended
+// to be passed as the TrustAnchorsCallback to FindTrustAnchorsForCert to test
+// deleting the Request during the request callback.
+void TrustStoreRequestDeleter(std::unique_ptr<TrustStore::Request>* req_owner,
+ const base::Closure& done_callback,
+ TrustAnchors anchors);
+
+// Helper to record async results from a FindTrustAnchorsForCert call.
+class TrustAnchorResultRecorder {
+ public:
+ TrustAnchorResultRecorder();
+ ~TrustAnchorResultRecorder();
+
+ TrustStore::TrustAnchorsCallback Callback();
+
+ void Run() { run_loop_.Run(); }
+
+ const TrustAnchors& matches() const { return anchors_; }
+
+ private:
+ void OnGotAnchors(TrustAnchors anchors);
+
+ base::RunLoop run_loop_;
+ TrustAnchors anchors_;
+};
+
+// In-memory TrustStore that can return results synchronously, asynchronously,
+// or both.
+class TrustStoreInMemoryAsync : public TrustStore {
+ public:
+ TrustStoreInMemoryAsync();
+ ~TrustStoreInMemoryAsync() override;
+
+ // Adds |anchor| to the set of results that will be returned synchronously.
+ void AddSyncTrustAnchor(scoped_refptr<TrustAnchor> anchor);
+
+ // Adds |anchor| to the set of results that will be returned asynchronously.
+ void AddAsyncTrustAnchor(scoped_refptr<TrustAnchor> anchor);
+
+ // TrustStore implementation:
+ void FindTrustAnchorsForCert(
+ const scoped_refptr<ParsedCertificate>& cert,
+ const TrustAnchorsCallback& callback,
+ TrustAnchors* synchronous_matches,
+ std::unique_ptr<Request>* out_req) const override;
+
+ private:
+ TrustStoreInMemory sync_store_;
+ TrustStoreInMemory async_store_;
+};
+
+} // namespace net
+
+#endif // NET_CERT_INTERNAL_TRUST_STORE_TEST_HELPERS_H_
diff --git a/chromium/net/cert/internal/verify_certificate_chain.cc b/chromium/net/cert/internal/verify_certificate_chain.cc
index 73bd6f1361d..33f831e6e36 100644
--- a/chromium/net/cert/internal/verify_certificate_chain.cc
+++ b/chromium/net/cert/internal/verify_certificate_chain.cc
@@ -7,9 +7,12 @@
#include <memory>
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "net/cert/internal/cert_error_params.h"
+#include "net/cert/internal/cert_error_scoper.h"
+#include "net/cert/internal/cert_errors.h"
#include "net/cert/internal/name_constraints.h"
#include "net/cert/internal/parse_certificate.h"
-#include "net/cert/internal/parsed_certificate.h"
#include "net/cert/internal/signature_algorithm.h"
#include "net/cert/internal/signature_policy.h"
#include "net/cert/internal/trust_store.h"
@@ -21,15 +24,77 @@ namespace net {
namespace {
+// -----------------------------------------------
+// Errors/Warnings set by VerifyCertificateChain
+// -----------------------------------------------
+
+DEFINE_CERT_ERROR_ID(
+ kSignatureAlgorithmMismatch,
+ "Certificate.signatureAlgorithm != TBSCertificate.signature");
+DEFINE_CERT_ERROR_ID(kInvalidOrUnsupportedSignatureAlgorithm,
+ "Invalid or unsupported signature algorithm");
+DEFINE_CERT_ERROR_ID(kChainIsEmpty, "Chain is empty");
+DEFINE_CERT_ERROR_ID(kUnconsumedCriticalExtension,
+ "Unconsumed critical extension");
+DEFINE_CERT_ERROR_ID(
+ kTargetCertInconsistentCaBits,
+ "Target certificate looks like a CA but does not set all CA properties");
+DEFINE_CERT_ERROR_ID(kKeyCertSignBitNotSet, "keyCertSign bit is not set");
+DEFINE_CERT_ERROR_ID(kMaxPathLengthViolated, "max_path_length reached");
+DEFINE_CERT_ERROR_ID(kBasicConstraintsIndicatesNotCa,
+ "Basic Constraints indicates not a CA");
+DEFINE_CERT_ERROR_ID(kMissingBasicConstraints,
+ "Does not have Basic Constraints");
+DEFINE_CERT_ERROR_ID(kNotPermittedByNameConstraints,
+ "Not permitted by name constraints");
+DEFINE_CERT_ERROR_ID(kSubjectDoesNotMatchIssuer,
+ "subject does not match issuer");
+DEFINE_CERT_ERROR_ID(kVerifySignedDataFailed, "VerifySignedData failed");
+DEFINE_CERT_ERROR_ID(kValidityFailedNotAfter, "Time is after notAfter");
+DEFINE_CERT_ERROR_ID(kValidityFailedNotBefore, "Time is before notBefore");
+DEFINE_CERT_ERROR_ID(kSignatureAlgorithmsDifferentEncoding,
+ "Certificate.signatureAlgorithm is encoded differently "
+ "than TBSCertificate.signature");
+
+DEFINE_CERT_ERROR_ID(kContextTrustAnchor, "Processing Trust Anchor");
+DEFINE_CERT_ERROR_ID(kContextCertificate, "Processing Certificate");
+
+// This class changes the error scope to indicate which certificate in the
+// chain is currently being processed.
+class CertErrorScoperForCert : public CertErrorScoper {
+ public:
+ CertErrorScoperForCert(CertErrors* parent_errors, size_t index)
+ : CertErrorScoper(parent_errors), index_(index) {}
+
+ std::unique_ptr<CertErrorNode> BuildRootNode() override {
+ return base::MakeUnique<CertErrorNode>(
+ CertErrorNodeType::TYPE_CONTEXT, kContextCertificate,
+ CreateCertErrorParams1SizeT("index", index_));
+ }
+
+ private:
+ size_t index_;
+
+ DISALLOW_COPY_AND_ASSIGN(CertErrorScoperForCert);
+};
+
// Returns true if the certificate does not contain any unconsumed _critical_
// extensions.
WARN_UNUSED_RESULT bool VerifyNoUnconsumedCriticalExtensions(
- const ParsedCertificate& cert) {
+ const ParsedCertificate& cert,
+ CertErrors* errors) {
+ bool has_unconsumed_critical_extensions = false;
+
for (const auto& entry : cert.unparsed_extensions()) {
- if (entry.second.critical)
- return false;
+ if (entry.second.critical) {
+ has_unconsumed_critical_extensions = true;
+ errors->AddError(kUnconsumedCriticalExtension,
+ CreateCertErrorParams2Der("oid", entry.second.oid,
+ "value", entry.second.value));
+ }
}
- return true;
+
+ return !has_unconsumed_critical_extensions;
}
// Returns true if |cert| was self-issued. The definition of self-issuance
@@ -55,9 +120,19 @@ WARN_UNUSED_RESULT bool IsSelfIssued(const ParsedCertificate& cert) {
// The validity period for a certificate is the period of time from
// notBefore through notAfter, inclusive.
WARN_UNUSED_RESULT bool VerifyTimeValidity(const ParsedCertificate& cert,
- const der::GeneralizedTime time) {
- return !(time < cert.tbs().validity_not_before) &&
- !(cert.tbs().validity_not_after < time);
+ const der::GeneralizedTime time,
+ CertErrors* errors) {
+ if (time < cert.tbs().validity_not_before) {
+ errors->AddError(kValidityFailedNotBefore);
+ return false;
+ }
+
+ if (cert.tbs().validity_not_after < time) {
+ errors->AddError(kValidityFailedNotAfter);
+ return false;
+ }
+
+ return true;
}
// Returns true if |signature_algorithm_tlv| is a valid algorithm encoding for
@@ -65,7 +140,7 @@ WARN_UNUSED_RESULT bool VerifyTimeValidity(const ParsedCertificate& cert,
WARN_UNUSED_RESULT bool IsRsaWithSha1SignatureAlgorithm(
const der::Input& signature_algorithm_tlv) {
std::unique_ptr<SignatureAlgorithm> algorithm =
- SignatureAlgorithm::CreateFromDer(signature_algorithm_tlv);
+ SignatureAlgorithm::Create(signature_algorithm_tlv, nullptr);
return algorithm &&
algorithm->algorithm() == SignatureAlgorithmId::RsaPkcs1 &&
@@ -92,62 +167,80 @@ WARN_UNUSED_RESULT bool IsRsaWithSha1SignatureAlgorithm(
// specifying RSA with SHA1 (different OIDs). This is special-cased for
// compatibility sake.
WARN_UNUSED_RESULT bool VerifySignatureAlgorithmsMatch(
- const ParsedCertificate& cert) {
+ const ParsedCertificate& cert,
+ CertErrors* errors) {
const der::Input& alg1_tlv = cert.signature_algorithm_tlv();
const der::Input& alg2_tlv = cert.tbs().signature_algorithm_tlv;
// Ensure that the two DER-encoded signature algorithms are byte-for-byte
- // equal, but make a compatibility concession for RSA with SHA1.
- return alg1_tlv == alg2_tlv || (IsRsaWithSha1SignatureAlgorithm(alg1_tlv) &&
- IsRsaWithSha1SignatureAlgorithm(alg2_tlv));
+ // equal.
+ if (alg1_tlv == alg2_tlv)
+ return true;
+
+ // But make a compatibility concession for RSA with SHA1.
+ if (IsRsaWithSha1SignatureAlgorithm(alg1_tlv) &&
+ IsRsaWithSha1SignatureAlgorithm(alg2_tlv)) {
+ errors->AddWarning(
+ kSignatureAlgorithmsDifferentEncoding,
+ CreateCertErrorParams2Der("Certificate.algorithm", alg1_tlv,
+ "TBSCertificate.signature", alg2_tlv));
+ return true;
+ }
+
+ errors->AddError(
+ kSignatureAlgorithmMismatch,
+ CreateCertErrorParams2Der("Certificate.algorithm", alg1_tlv,
+ "TBSCertificate.signature", alg2_tlv));
+
+ return false;
}
// This function corresponds to RFC 5280 section 6.1.3's "Basic Certificate
// Processing" procedure.
-//
-// |skip_issuer_checks| controls whether the function will skip:
-// - Checking that |cert|'s signature using |working_spki|
-// - Checkinging that |cert|'s issuer matches |working_normalized_issuer_name|
-// This should be set to true only when verifying a trusted root certificate.
WARN_UNUSED_RESULT bool BasicCertificateProcessing(
const ParsedCertificate& cert,
bool is_target_cert,
- bool skip_issuer_checks,
const SignaturePolicy* signature_policy,
const der::GeneralizedTime& time,
const der::Input& working_spki,
const der::Input& working_normalized_issuer_name,
- const std::vector<const NameConstraints*>& name_constraints_list) {
+ const std::vector<const NameConstraints*>& name_constraints_list,
+ CertErrors* errors) {
// Check that the signature algorithms in Certificate vs TBSCertificate
// match. This isn't part of RFC 5280 section 6.1.3, but is mandated by
// sections 4.1.1.2 and 4.1.2.3.
- if (!VerifySignatureAlgorithmsMatch(cert))
+ if (!VerifySignatureAlgorithmsMatch(cert, errors))
return false;
// Verify the digital signature using the previous certificate's key (RFC
// 5280 section 6.1.3 step a.1).
- if (!skip_issuer_checks) {
- if (!cert.has_valid_supported_signature_algorithm() ||
- !VerifySignedData(cert.signature_algorithm(),
- cert.tbs_certificate_tlv(), cert.signature_value(),
- working_spki, signature_policy)) {
- return false;
- }
+ if (!cert.has_valid_supported_signature_algorithm()) {
+ errors->AddError(
+ kInvalidOrUnsupportedSignatureAlgorithm,
+ CreateCertErrorParams1Der("algorithm", cert.signature_algorithm_tlv()));
+ return false;
+ }
+
+ if (!VerifySignedData(cert.signature_algorithm(), cert.tbs_certificate_tlv(),
+ cert.signature_value(), working_spki, signature_policy,
+ errors)) {
+ errors->AddError(kVerifySignedDataFailed);
+ return false;
}
// Check the time range for the certificate's validity, ensuring it is valid
// at |time|.
// (RFC 5280 section 6.1.3 step a.2)
- if (!VerifyTimeValidity(cert, time))
+ if (!VerifyTimeValidity(cert, time, errors))
return false;
// TODO(eroman): Check revocation (RFC 5280 section 6.1.3 step a.3)
// Verify the certificate's issuer name matches the issuing certificate's
// subject name. (RFC 5280 section 6.1.3 step a.4)
- if (!skip_issuer_checks) {
- if (cert.normalized_issuer() != working_normalized_issuer_name)
- return false;
+ if (cert.normalized_issuer() != working_normalized_issuer_name) {
+ errors->AddError(kSubjectDoesNotMatchIssuer);
+ return false;
}
// Name constraints (RFC 5280 section 6.1.3 step b & c)
@@ -158,6 +251,7 @@ WARN_UNUSED_RESULT bool BasicCertificateProcessing(
for (const NameConstraints* nc : name_constraints_list) {
if (!nc->IsPermittedCert(cert.normalized_subject(),
cert.subject_alt_names())) {
+ errors->AddError(kNotPermittedByNameConstraints);
return false;
}
}
@@ -170,15 +264,16 @@ WARN_UNUSED_RESULT bool BasicCertificateProcessing(
}
// This function corresponds to RFC 5280 section 6.1.4's "Preparation for
-// Certificate i+1" procedure. |cert| is expected to be an intermediary.
+// Certificate i+1" procedure. |cert| is expected to be an intermediate.
WARN_UNUSED_RESULT bool PrepareForNextCertificate(
const ParsedCertificate& cert,
size_t* max_path_length_ptr,
der::Input* working_spki,
der::Input* working_normalized_issuer_name,
- std::vector<const NameConstraints*>* name_constraints_list) {
- // TODO(eroman): Steps a-b are omitted, as policy constraints are not yet
- // implemented.
+ std::vector<const NameConstraints*>* name_constraints_list,
+ CertErrors* errors) {
+ // TODO(crbug.com/634456): Steps a-b are omitted, as policy mappings are not
+ // yet implemented.
// From RFC 5280 section 6.1.4 step c:
//
@@ -198,8 +293,8 @@ WARN_UNUSED_RESULT bool PrepareForNextCertificate(
if (cert.has_name_constraints())
name_constraints_list->push_back(&cert.name_constraints());
- // TODO(eroman): Steps h-j are omitted as policy constraints are not yet
- // implemented.
+ // TODO(eroman): Steps h-j are omitted as policy
+ // constraints/mappings/inhibitAnyPolicy are not yet implemented.
// From RFC 5280 section 6.1.4 step k:
//
@@ -212,10 +307,17 @@ WARN_UNUSED_RESULT bool PrepareForNextCertificate(
// choose to reject all version 1 and version 2 intermediate
// certificates.)
//
- // This code implicitly rejects non version 3 intermediaries, since they
+ // This code implicitly rejects non version 3 intermediates, since they
// can't contain a BasicConstraints extension.
- if (!cert.has_basic_constraints() || !cert.basic_constraints().is_ca)
+ if (!cert.has_basic_constraints()) {
+ errors->AddError(kMissingBasicConstraints);
+ return false;
+ }
+
+ if (!cert.basic_constraints().is_ca) {
+ errors->AddError(kBasicConstraintsIndicatesNotCa);
return false;
+ }
// From RFC 5280 section 6.1.4 step l:
//
@@ -223,8 +325,10 @@ WARN_UNUSED_RESULT bool PrepareForNextCertificate(
// max_path_length is greater than zero and decrement
// max_path_length by 1.
if (!IsSelfIssued(cert)) {
- if (*max_path_length_ptr == 0)
+ if (*max_path_length_ptr == 0) {
+ errors->AddError(kMaxPathLengthViolated);
return false;
+ }
--(*max_path_length_ptr);
}
@@ -244,6 +348,7 @@ WARN_UNUSED_RESULT bool PrepareForNextCertificate(
// keyCertSign bit is set.
if (cert.has_key_usage() &&
!cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)) {
+ errors->AddError(kKeyCertSignBitNotSet);
return false;
}
@@ -253,7 +358,7 @@ WARN_UNUSED_RESULT bool PrepareForNextCertificate(
// the certificate. Process any other recognized non-critical
// extension present in the certificate that is relevant to path
// processing.
- if (!VerifyNoUnconsumedCriticalExtensions(cert))
+ if (!VerifyNoUnconsumedCriticalExtensions(cert, errors))
return false;
return true;
@@ -282,7 +387,8 @@ WARN_UNUSED_RESULT bool PrepareForNextCertificate(
// for compatibility reasons. Investigate if we need to similarly relax this
// constraint.
WARN_UNUSED_RESULT bool VerifyTargetCertHasConsistentCaBits(
- const ParsedCertificate& cert) {
+ const ParsedCertificate& cert,
+ CertErrors* errors) {
// Check if the certificate contains any property specific to CAs.
bool has_ca_property =
(cert.has_basic_constraints() &&
@@ -294,9 +400,16 @@ WARN_UNUSED_RESULT bool VerifyTargetCertHasConsistentCaBits(
// If it "looks" like a CA because it has a CA-only property, then check that
// it sets ALL the properties expected of a CA.
if (has_ca_property) {
- return cert.has_basic_constraints() && cert.basic_constraints().is_ca &&
- (!cert.has_key_usage() ||
- cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN));
+ bool success = cert.has_basic_constraints() &&
+ cert.basic_constraints().is_ca &&
+ (!cert.has_key_usage() ||
+ cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN));
+ if (!success) {
+ // TODO(eroman): Add DER for basic constraints and key usage.
+ errors->AddError(kTargetCertInconsistentCaBits);
+ }
+
+ return success;
}
return true;
@@ -304,9 +417,10 @@ WARN_UNUSED_RESULT bool VerifyTargetCertHasConsistentCaBits(
// This function corresponds with RFC 5280 section 6.1.5's "Wrap-Up Procedure".
// It does processing for the final certificate (the target cert).
-WARN_UNUSED_RESULT bool WrapUp(const ParsedCertificate& cert) {
- // TODO(eroman): Steps a-b are omitted as policy constraints are not yet
- // implemented.
+WARN_UNUSED_RESULT bool WrapUp(const ParsedCertificate& cert,
+ CertErrors* errors) {
+ // TODO(crbug.com/634452): Steps a-b are omitted as policy constraints are not
+ // yet implemented.
// Note step c-e are omitted the verification function does
// not output the working public key.
@@ -320,7 +434,7 @@ WARN_UNUSED_RESULT bool WrapUp(const ParsedCertificate& cert) {
//
// Note that this is duplicated by PrepareForNextCertificate() so as to
// directly match the procedures in RFC 5280's section 6.1.
- if (!VerifyNoUnconsumedCriticalExtensions(cert))
+ if (!VerifyNoUnconsumedCriticalExtensions(cert, errors))
return false;
// TODO(eroman): Step g is omitted, as policy constraints are not yet
@@ -328,37 +442,90 @@ WARN_UNUSED_RESULT bool WrapUp(const ParsedCertificate& cert) {
// The following check is NOT part of RFC 5280 6.1.5's "Wrap-Up Procedure",
// however is implied by RFC 5280 section 4.2.1.9.
- if (!VerifyTargetCertHasConsistentCaBits(cert))
+ if (!VerifyTargetCertHasConsistentCaBits(cert, errors))
return false;
return true;
}
-} // namespace
+// Initializes the path validation algorithm given anchor constraints. This
+// follows the description in RFC 5937
+WARN_UNUSED_RESULT bool ProcessTrustAnchorConstraints(
+ const TrustAnchor& trust_anchor,
+ size_t* max_path_length_ptr,
+ std::vector<const NameConstraints*>* name_constraints_list,
+ CertErrors* errors) {
+ // Set the trust anchor as the current context for any subsequent errors.
+ CertErrorScoperNoParams error_context(errors, kContextTrustAnchor);
+
+ // In RFC 5937 the enforcement of anchor constraints is governed by the input
+ // enforceTrustAnchorConstraints to path validation. In our implementation
+ // this is always on, and enforcement is controlled solely by whether or not
+ // the trust anchor specified constraints.
+ if (!trust_anchor.enforces_constraints())
+ return true;
-// TODO(eroman): Move this into existing anonymous namespace.
-namespace {
+ // Anchor constraints are encoded via the attached certificate.
+ const ParsedCertificate& cert = *trust_anchor.cert();
+
+ // The following enforcements follow from RFC 5937 (primarily section 3.2):
+
+ // Initialize name constraints initial-permitted/excluded-subtrees.
+ if (cert.has_name_constraints())
+ name_constraints_list->push_back(&cert.name_constraints());
+
+ // TODO(eroman): Initialize user-initial-policy-set based on anchor
+ // constraints.
+
+ // TODO(eroman): Initialize inhibit any policy based on anchor constraints.
+
+ // TODO(eroman): Initialize require explicit policy based on anchor
+ // constraints.
+
+ // TODO(eroman): Initialize inhibit policy mapping based on anchor
+ // constraints.
+
+ // From RFC 5937 section 3.2:
+ //
+ // If a basic constraints extension is associated with the trust
+ // anchor and contains a pathLenConstraint value, set the
+ // max_path_length state variable equal to the pathLenConstraint
+ // value from the basic constraints extension.
+ //
+ // NOTE: RFC 5937 does not say to enforce the CA=true part of basic
+ // constraints.
+ if (cert.has_basic_constraints() && cert.basic_constraints().has_path_len)
+ *max_path_length_ptr = cert.basic_constraints().path_len;
+
+ // From RFC 5937 section 2:
+ //
+ // Extensions may be marked critical or not critical. When trust anchor
+ // constraints are enforced, clients MUST reject certification paths
+ // containing a trust anchor with unrecognized critical extensions.
+ if (!VerifyNoUnconsumedCriticalExtensions(cert, errors))
+ return false;
+
+ return true;
+}
+
+} // namespace
// This implementation is structured to mimic the description of certificate
// path verification given by RFC 5280 section 6.1.
-//
-// Unlike RFC 5280, the trust anchor is specified as the root certificate in
-// the chain. This root certificate is assumed to be trusted, and neither its
-// signature nor issuer name are verified. (It needn't be self-signed).
-bool VerifyCertificateChainAssumingTrustedRoot(
- const std::vector<scoped_refptr<ParsedCertificate>>& certs,
- // The trust store is only used for assertions.
- const TrustStore& trust_store,
- const SignaturePolicy* signature_policy,
- const der::GeneralizedTime& time) {
+bool VerifyCertificateChain(const ParsedCertificateList& certs,
+ const TrustAnchor* trust_anchor,
+ const SignaturePolicy* signature_policy,
+ const der::GeneralizedTime& time,
+ CertErrors* errors) {
+ DCHECK(trust_anchor);
+ DCHECK(signature_policy);
+ DCHECK(errors);
+
// An empty chain is necessarily invalid.
- if (certs.empty())
+ if (certs.empty()) {
+ errors->AddError(kChainIsEmpty);
return false;
-
- // IMPORTANT: the assumption being made is that the root certificate in
- // the given path is the trust anchor (and has already been verified as
- // such).
- DCHECK(trust_store.IsTrustedCertificate(certs.back().get()));
+ }
// Will contain a NameConstraints for each previous cert in the chain which
// had nameConstraints. This corresponds to the permitted_subtrees and
@@ -379,14 +546,15 @@ bool VerifyCertificateChainAssumingTrustedRoot(
//
// working_public_key: the public key used to verify the
// signature of a certificate.
- der::Input working_spki;
+ der::Input working_spki = trust_anchor->spki();
// |working_normalized_issuer_name| is the normalized value of the
// working_issuer_name variable in RFC 5280 section 6.1.2:
//
// working_issuer_name: the issuer distinguished name expected
// in the next certificate in the chain.
- der::Input working_normalized_issuer_name;
+ der::Input working_normalized_issuer_name =
+ trust_anchor->normalized_subject();
// |max_path_length| corresponds with the same named variable in RFC 5280
// section 6.1.2:
@@ -398,12 +566,19 @@ bool VerifyCertificateChainAssumingTrustedRoot(
// certificate.
size_t max_path_length = certs.size();
+ // Apply any trust anchor constraints per RFC 5937.
+ if (!ProcessTrustAnchorConstraints(*trust_anchor, &max_path_length,
+ &name_constraints_list, errors)) {
+ return false;
+ }
+
// Iterate over all the certificates in the reverse direction: starting from
- // the trust anchor and progressing towards the target certificate.
+ // the certificate signed by trust anchor and progressing towards the target
+ // certificate.
//
// Note that |i| uses 0-based indexing whereas in RFC 5280 it is 1-based.
//
- // * i=0 : Trust anchor.
+ // * i=0 : Certificated signed by trust anchor.
// * i=N-1 : Target certificate.
for (size_t i = 0; i < certs.size(); ++i) {
const size_t index_into_certs = certs.size() - i - 1;
@@ -413,31 +588,29 @@ bool VerifyCertificateChainAssumingTrustedRoot(
// end-entity certificate.
const bool is_target_cert = index_into_certs == 0;
- // |is_trust_anchor| is true if the current certificate is the trust
- // anchor. This certificate is implicitly trusted.
- const bool is_trust_anchor = i == 0;
-
const ParsedCertificate& cert = *certs[index_into_certs];
+ // Set the current certificate as the context for any subsequent errors.
+ CertErrorScoperForCert error_context(errors, i);
+
// Per RFC 5280 section 6.1:
// * Do basic processing for each certificate
// * If it is the last certificate in the path (target certificate)
// - Then run "Wrap up"
// - Otherwise run "Prepare for Next cert"
- if (!BasicCertificateProcessing(cert, is_target_cert, is_trust_anchor,
- signature_policy, time, working_spki,
- working_normalized_issuer_name,
- name_constraints_list)) {
+ if (!BasicCertificateProcessing(
+ cert, is_target_cert, signature_policy, time, working_spki,
+ working_normalized_issuer_name, name_constraints_list, errors)) {
return false;
}
if (!is_target_cert) {
if (!PrepareForNextCertificate(cert, &max_path_length, &working_spki,
&working_normalized_issuer_name,
- &name_constraints_list)) {
+ &name_constraints_list, errors)) {
return false;
}
} else {
- if (!WrapUp(cert))
+ if (!WrapUp(cert, errors))
return false;
}
}
@@ -450,56 +623,4 @@ bool VerifyCertificateChainAssumingTrustedRoot(
return true;
}
-// TODO(eroman): This function is a temporary hack in the absence of full
-// path building. It may insert 1 certificate at the root of the
-// chain to ensure that the path's root certificate is a trust anchor.
-//
-// Beyond this no other verification is done on the chain. The caller is
-// responsible for verifying the subsequent chain's correctness.
-WARN_UNUSED_RESULT bool BuildSimplePathToTrustAnchor(
- const TrustStore& trust_store,
- std::vector<scoped_refptr<ParsedCertificate>>* certs) {
- if (certs->empty())
- return false;
-
- // Check if the current root certificate is trusted. If it is then no
- // extra work is needed.
- if (trust_store.IsTrustedCertificate(certs->back().get()))
- return true;
-
- std::vector<scoped_refptr<ParsedCertificate>> trust_anchors;
- trust_store.FindTrustAnchorsByNormalizedName(
- certs->back()->normalized_issuer(), &trust_anchors);
- if (trust_anchors.empty())
- return false;
- // TODO(mattm): this only tries the first match, even if there are multiple.
- certs->push_back(std::move(trust_anchors[0]));
- return true;
-}
-
-} // namespace
-
-bool VerifyCertificateChain(
- const std::vector<scoped_refptr<ParsedCertificate>>& cert_chain,
- const TrustStore& trust_store,
- const SignaturePolicy* signature_policy,
- const der::GeneralizedTime& time,
- std::vector<scoped_refptr<ParsedCertificate>>* trusted_chain_out) {
- if (cert_chain.empty())
- return false;
-
- std::vector<scoped_refptr<ParsedCertificate>> full_chain = cert_chain;
-
- // Modify the certificate chain so that its root is a trusted certificate.
- if (!BuildSimplePathToTrustAnchor(trust_store, &full_chain))
- return false;
-
- // Verify the chain.
- bool success = VerifyCertificateChainAssumingTrustedRoot(
- full_chain, trust_store, signature_policy, time);
- if (success && trusted_chain_out != nullptr)
- *trusted_chain_out = std::move(full_chain);
- return success;
-}
-
} // namespace net
diff --git a/chromium/net/cert/internal/verify_certificate_chain.h b/chromium/net/cert/internal/verify_certificate_chain.h
index 291c843d9ed..d1ea57e0575 100644
--- a/chromium/net/cert/internal/verify_certificate_chain.h
+++ b/chromium/net/cert/internal/verify_certificate_chain.h
@@ -10,6 +10,8 @@
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "net/base/net_export.h"
+#include "net/cert/internal/cert_errors.h"
+#include "net/cert/internal/parsed_certificate.h"
#include "net/der/input.h"
namespace net {
@@ -18,16 +20,20 @@ namespace der {
struct GeneralizedTime;
}
-class ParsedCertificate;
class SignaturePolicy;
+class TrustAnchor;
class TrustStore;
// VerifyCertificateChain() verifies a certificate path (chain) based on the
-// rules in RFC 5280.
+// rules in RFC 5280. The caller is responsible for building the path and
+// finding the trust anchor.
//
// WARNING: This implementation is in progress, and is currently incomplete.
// Consult an OWNER before using it.
//
+// TODO(eroman): Take a CertPath instead of ParsedCertificateList +
+// TrustAnchor.
+//
// ---------
// Inputs
// ---------
@@ -38,11 +44,11 @@ class TrustStore;
//
// * cert_chain[0] is the target certificate to verify.
// * cert_chain[i+1] holds the certificate that issued cert_chain[i].
-// * cert_chain[N-1] must be the trust anchor, or have been directly
-// issued by a trust anchor.
+// * cert_chain[N-1] must be issued by the trust anchor.
//
-// trust_store:
-// Contains the set of trusted public keys (and their names).
+// trust_anchor:
+// Contains the trust anchor (root) used to verify the chain. Must be
+// non-null.
//
// signature_policy:
// The policy to use when verifying signatures (what hash algorithms are
@@ -51,28 +57,23 @@ class TrustStore;
// time:
// The UTC time to use for expiration checks.
//
-// trusted_chain_out:
-// The vector to populate with the verified trusted certificate chain.
-// * trusted_chain_out[0] is the target certificate verified.
-// * trusted_chain_out[i+1] holds the certificate that issued
-// trusted_chain_out[i].
-// * trusted_chain_out[N-1] is the trust anchor.
-// If a nullptr is passed, this parameter is ignored.
-// If the target certificate can not be verified, this parameter is
-// ignored.
-//
// ---------
// Outputs
// ---------
//
// Returns true if the target certificate can be verified.
-NET_EXPORT bool VerifyCertificateChain(
- const std::vector<scoped_refptr<ParsedCertificate>>& cert_chain,
- const TrustStore& trust_store,
- const SignaturePolicy* signature_policy,
- const der::GeneralizedTime& time,
- std::vector<scoped_refptr<ParsedCertificate>>* trusted_chain_out)
- WARN_UNUSED_RESULT;
+//
+// errors:
+// Must be non-null. The set of errors/warnings encountered while
+// validating the path are appended to this structure. There is no
+// guarantee that on success |errors| is empty, or conversely that
+// on failure |errors| is non-empty. Consumers must only use the
+// boolean return value to determine success/failure.
+NET_EXPORT bool VerifyCertificateChain(const ParsedCertificateList& certs,
+ const TrustAnchor* trust_anchor,
+ const SignaturePolicy* signature_policy,
+ const der::GeneralizedTime& time,
+ CertErrors* errors) WARN_UNUSED_RESULT;
} // namespace net
diff --git a/chromium/net/cert/internal/verify_certificate_chain_pkits_unittest.cc b/chromium/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
index 4c543f46bab..6e2209a0f7a 100644
--- a/chromium/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
+++ b/chromium/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
@@ -52,35 +52,36 @@ class VerifyCertificateChainPkitsTestDelegate {
ADD_FAILURE() << "cert_ders is empty";
return false;
}
- // First entry in the PKITS chain is the trust anchor.
- TrustStore trust_store;
- scoped_refptr<ParsedCertificate> anchor(
- ParsedCertificate::CreateFromCertificateCopy(cert_ders[0], {}));
- EXPECT_TRUE(anchor);
- if (anchor)
- trust_store.AddTrustedCertificate(std::move(anchor));
// PKITS lists chains from trust anchor to target, VerifyCertificateChain
// takes them starting with the target and not including the trust anchor.
std::vector<scoped_refptr<net::ParsedCertificate>> input_chain;
- for (size_t i = cert_ders.size() - 1; i > 0; --i) {
- if (!net::ParsedCertificate::CreateAndAddToVector(
- reinterpret_cast<const uint8_t*>(cert_ders[i].data()),
- cert_ders[i].size(),
- net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE, {},
- &input_chain)) {
- ADD_FAILURE() << "cert " << i << " failed to parse";
+ CertErrors errors;
+ for (auto i = cert_ders.rbegin(); i != cert_ders.rend(); ++i) {
+ if (!net::ParsedCertificate::CreateAndAddToVector(*i, {}, &input_chain,
+ &errors)) {
+ ADD_FAILURE() << "Cert failed to parse:\n" << errors.ToDebugString();
return false;
}
}
+ scoped_refptr<TrustAnchor> trust_anchor =
+ TrustAnchor::CreateFromCertificateNoConstraints(input_chain.back());
+ input_chain.pop_back();
+
SimpleSignaturePolicy signature_policy(1024);
// Run all tests at the time the PKITS was published.
der::GeneralizedTime time = {2011, 4, 15, 0, 0, 0};
- return VerifyCertificateChain(input_chain, trust_store, &signature_policy,
- time, nullptr);
+ bool result = VerifyCertificateChain(input_chain, trust_anchor.get(),
+ &signature_policy, time, &errors);
+
+ // TODO(crbug.com/634443): Test errors on failure?
+ if (!result)
+ EXPECT_FALSE(errors.empty());
+
+ return result;
}
};
diff --git a/chromium/net/cert/internal/verify_certificate_chain_typed_unittest.h b/chromium/net/cert/internal/verify_certificate_chain_typed_unittest.h
new file mode 100644
index 00000000000..8c64d916cc3
--- /dev/null
+++ b/chromium/net/cert/internal/verify_certificate_chain_typed_unittest.h
@@ -0,0 +1,269 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_CERT_INTERNAL_VERIFY_CERTIFICATE_CHAIN_TYPED_UNITTEST_H_
+#define NET_CERT_INTERNAL_VERIFY_CERTIFICATE_CHAIN_TYPED_UNITTEST_H_
+
+#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/test_helpers.h"
+#include "net/cert/internal/trust_store.h"
+#include "net/cert/pem_tokenizer.h"
+#include "net/der/input.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+template <typename TestDelegate>
+class VerifyCertificateChainTest : public ::testing::Test {
+ public:
+ void RunTest(const char* file_name) {
+ ParsedCertificateList chain;
+ scoped_refptr<TrustAnchor> trust_anchor;
+ der::GeneralizedTime time;
+ bool expected_result;
+ std::string expected_errors;
+
+ std::string path =
+ std::string("net/data/verify_certificate_chain_unittest/") + file_name;
+
+ ReadVerifyCertChainTestFromFile(path, &chain, &trust_anchor, &time,
+ &expected_result, &expected_errors);
+
+ TestDelegate::Verify(chain, trust_anchor, time, expected_result,
+ expected_errors, path);
+ }
+};
+
+// Tests that have only one root. These can be tested without requiring any
+// path-building ability.
+template <typename TestDelegate>
+class VerifyCertificateChainSingleRootTest
+ : public VerifyCertificateChainTest<TestDelegate> {};
+
+TYPED_TEST_CASE_P(VerifyCertificateChainSingleRootTest);
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, TargetAndIntermediate) {
+ this->RunTest("target-and-intermediate.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ IntermediateLacksBasicConstraints) {
+ this->RunTest("intermediate-lacks-basic-constraints.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ IntermediateBasicConstraintsCaFalse) {
+ this->RunTest("intermediate-basic-constraints-ca-false.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ IntermediateBasicConstraintsNotCritical) {
+ this->RunTest("intermediate-basic-constraints-not-critical.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ IntermediateLacksSigningKeyUsage) {
+ this->RunTest("intermediate-lacks-signing-key-usage.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ IntermediateUnknownCriticalExtension) {
+ this->RunTest("intermediate-unknown-critical-extension.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ IntermediateUnknownNonCriticalExtension) {
+ this->RunTest("intermediate-unknown-non-critical-extension.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ ViolatesBasicConstraintsPathlen0) {
+ this->RunTest("violates-basic-constraints-pathlen-0.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ BasicConstraintsPathlen0SelfIssued) {
+ this->RunTest("basic-constraints-pathlen-0-self-issued.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, TargetSignedWithMd5) {
+ this->RunTest("target-signed-with-md5.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, IntermediateSignedWithMd5) {
+ this->RunTest("intermediate-signed-with-md5.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, TargetWrongSignature) {
+ this->RunTest("target-wrong-signature.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, TargetSignedBy512bitRsa) {
+ this->RunTest("target-signed-by-512bit-rsa.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, TargetSignedUsingEcdsa) {
+ this->RunTest("target-signed-using-ecdsa.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, ExpiredIntermediate) {
+ this->RunTest("expired-intermediate.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, ExpiredTarget) {
+ this->RunTest("expired-target.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, ExpiredTargetNotBefore) {
+ this->RunTest("expired-target-notBefore.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, ExpiredUnconstrainedRoot) {
+ this->RunTest("expired-unconstrained-root.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, ExpiredConstrainedRoot) {
+ this->RunTest("expired-constrained-root.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, TargetNotEndEntity) {
+ this->RunTest("target-not-end-entity.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ TargetHasKeyCertSignButNotCa) {
+ this->RunTest("target-has-keycertsign-but-not-ca.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, TargetHasPathlenButNotCa) {
+ this->RunTest("target-has-pathlen-but-not-ca.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ TargetUnknownCriticalExtension) {
+ this->RunTest("target-unknown-critical-extension.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ IssuerAndSubjectNotByteForByteEqual) {
+ this->RunTest("issuer-and-subject-not-byte-for-byte-equal.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ IssuerAndSubjectNotByteForByteEqualAnchor) {
+ this->RunTest("issuer-and-subject-not-byte-for-byte-equal-anchor.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ ViolatesPathlen1UnconstrainedRoot) {
+ this->RunTest("violates-pathlen-1-unconstrained-root.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ ViolatesPathlen1ConstrainedRoot) {
+ this->RunTest("violates-pathlen-1-constrained-root.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, NonSelfSignedRoot) {
+ this->RunTest("non-self-signed-root.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, KeyRolloverOldChain) {
+ this->RunTest("key-rollover-oldchain.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, KeyRolloverRolloverChain) {
+ this->RunTest("key-rollover-rolloverchain.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ KeyRolloverLongRolloverChain) {
+ this->RunTest("key-rollover-longrolloverchain.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, KeyRolloverNewChain) {
+ this->RunTest("key-rollover-newchain.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, IncorrectTrustAnchor) {
+ this->RunTest("incorrect-trust-anchor.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ UnconstrainedRootLacksBasicConstraints) {
+ this->RunTest("unconstrained-root-lacks-basic-constraints.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ ConstrainedRootLacksBasicConstraints) {
+ this->RunTest("constrained-root-lacks-basic-constraints.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ UnconstrainedRootBasicConstraintsCaFalse) {
+ this->RunTest("unconstrained-root-basic-constraints-ca-false.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ ConstrainedRootBasicConstraintsCaFalse) {
+ this->RunTest("constrained-root-basic-constraints-ca-false.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ UnconstrainedNonSelfSignedRoot) {
+ this->RunTest("unconstrained-non-self-signed-root.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+ ConstrainedNonSelfSignedRoot) {
+ this->RunTest("constrained-non-self-signed-root.pem");
+}
+
+// TODO(eroman): Add test that invalid validity dates where the day or month
+// ordinal not in range, like "March 39, 2016" are rejected.
+
+REGISTER_TYPED_TEST_CASE_P(VerifyCertificateChainSingleRootTest,
+ TargetAndIntermediate,
+ IntermediateLacksBasicConstraints,
+ IntermediateBasicConstraintsCaFalse,
+ IntermediateBasicConstraintsNotCritical,
+ IntermediateLacksSigningKeyUsage,
+ IntermediateUnknownCriticalExtension,
+ IntermediateUnknownNonCriticalExtension,
+ ViolatesBasicConstraintsPathlen0,
+ BasicConstraintsPathlen0SelfIssued,
+ TargetSignedWithMd5,
+ IntermediateSignedWithMd5,
+ TargetWrongSignature,
+ TargetSignedBy512bitRsa,
+ TargetSignedUsingEcdsa,
+ ExpiredIntermediate,
+ ExpiredTarget,
+ ExpiredTargetNotBefore,
+ ExpiredUnconstrainedRoot,
+ ExpiredConstrainedRoot,
+ TargetNotEndEntity,
+ TargetHasKeyCertSignButNotCa,
+ TargetHasPathlenButNotCa,
+ TargetUnknownCriticalExtension,
+ IssuerAndSubjectNotByteForByteEqual,
+ IssuerAndSubjectNotByteForByteEqualAnchor,
+ ViolatesPathlen1UnconstrainedRoot,
+ ViolatesPathlen1ConstrainedRoot,
+ NonSelfSignedRoot,
+ KeyRolloverOldChain,
+ KeyRolloverRolloverChain,
+ KeyRolloverLongRolloverChain,
+ KeyRolloverNewChain,
+ IncorrectTrustAnchor,
+ UnconstrainedRootLacksBasicConstraints,
+ ConstrainedRootLacksBasicConstraints,
+ UnconstrainedRootBasicConstraintsCaFalse,
+ ConstrainedRootBasicConstraintsCaFalse,
+ UnconstrainedNonSelfSignedRoot,
+ ConstrainedNonSelfSignedRoot);
+
+} // namespace net
+
+#endif // NET_CERT_INTERNAL_VERIFY_CERTIFICATE_CHAIN_TYPED_UNITTEST_H_
diff --git a/chromium/net/cert/internal/verify_certificate_chain_unittest.cc b/chromium/net/cert/internal/verify_certificate_chain_unittest.cc
index 9103f12f3df..ec5f637a5a5 100644
--- a/chromium/net/cert/internal/verify_certificate_chain_unittest.cc
+++ b/chromium/net/cert/internal/verify_certificate_chain_unittest.cc
@@ -4,254 +4,41 @@
#include "net/cert/internal/verify_certificate_chain.h"
-#include "base/base_paths.h"
-#include "base/files/file_util.h"
-#include "base/path_service.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "net/cert/internal/parsed_certificate.h"
#include "net/cert/internal/signature_policy.h"
-#include "net/cert/internal/test_helpers.h"
#include "net/cert/internal/trust_store.h"
-#include "net/cert/pem_tokenizer.h"
-#include "net/der/input.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#include "net/cert/internal/verify_certificate_chain_typed_unittest.h"
namespace net {
namespace {
-// Reads a data file from the unit-test data.
-std::string ReadTestFileToString(const std::string& file_name) {
- // Compute the full path, relative to the src/ directory.
- base::FilePath src_root;
- PathService::Get(base::DIR_SOURCE_ROOT, &src_root);
- base::FilePath filepath = src_root.AppendASCII(
- std::string("net/data/verify_certificate_chain_unittest/") + file_name);
-
- // Read the full contents of the file.
- std::string file_data;
- if (!base::ReadFileToString(filepath, &file_data)) {
- ADD_FAILURE() << "Couldn't read file: " << filepath.value();
- return std::string();
- }
-
- return file_data;
-}
-
-// Reads a test case from |file_name|. Test cases are comprised of a
-// certificate chain, trust store, a timestamp to validate at, and the
-// expected result of verification.
-void ReadTestFromFile(const std::string& file_name,
- std::vector<std::string>* chain,
- TrustStore* trust_store,
- der::GeneralizedTime* time,
- bool* verify_result) {
- chain->clear();
- trust_store->Clear();
-
- std::string file_data = ReadTestFileToString(file_name);
-
- std::vector<std::string> pem_headers;
-
- const char kCertificateHeader[] = "CERTIFICATE";
- const char kTrustedCertificateHeader[] = "TRUSTED_CERTIFICATE";
- const char kTimeHeader[] = "TIME";
- const char kResultHeader[] = "VERIFY_RESULT";
-
- pem_headers.push_back(kCertificateHeader);
- pem_headers.push_back(kTrustedCertificateHeader);
- pem_headers.push_back(kTimeHeader);
- pem_headers.push_back(kResultHeader);
-
- bool has_time = false;
- bool has_result = false;
-
- PEMTokenizer pem_tokenizer(file_data, pem_headers);
- while (pem_tokenizer.GetNext()) {
- const std::string& block_type = pem_tokenizer.block_type();
- const std::string& block_data = pem_tokenizer.data();
-
- if (block_type == kCertificateHeader) {
- chain->push_back(block_data);
- } else if (block_type == kTrustedCertificateHeader) {
- scoped_refptr<ParsedCertificate> cert(
- ParsedCertificate::CreateFromCertificateCopy(block_data, {}));
- ASSERT_TRUE(cert);
- trust_store->AddTrustedCertificate(std::move(cert));
- } else if (block_type == kTimeHeader) {
- ASSERT_FALSE(has_time) << "Duplicate " << kTimeHeader;
- has_time = true;
- ASSERT_TRUE(der::ParseUTCTime(der::Input(&block_data), time));
- } else if (block_type == kResultHeader) {
- ASSERT_FALSE(has_result) << "Duplicate " << kResultHeader;
- ASSERT_TRUE(block_data == "SUCCESS" || block_data == "FAIL")
- << "Unrecognized result: " << block_data;
- has_result = true;
- *verify_result = block_data == "SUCCESS";
- }
- }
-
- ASSERT_TRUE(has_time);
- ASSERT_TRUE(has_result);
-}
-
-void RunTest(const char* file_name) {
- std::vector<std::string> chain;
- TrustStore trust_store;
- der::GeneralizedTime time;
- bool expected_result;
-
- ReadTestFromFile(file_name, &chain, &trust_store, &time, &expected_result);
-
- std::vector<scoped_refptr<net::ParsedCertificate>> input_chain;
- for (const auto& cert_der : chain) {
- ASSERT_TRUE(net::ParsedCertificate::CreateAndAddToVector(
- reinterpret_cast<const uint8_t*>(cert_der.data()), cert_der.size(),
- net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE, {},
- &input_chain));
+class VerifyCertificateChainDelegate {
+ public:
+ static void Verify(const ParsedCertificateList& chain,
+ const scoped_refptr<TrustAnchor>& trust_anchor,
+ const der::GeneralizedTime& time,
+ bool expected_result,
+ const std::string& expected_errors,
+ const std::string& test_file_path) {
+ ASSERT_TRUE(trust_anchor);
+
+ SimpleSignaturePolicy signature_policy(1024);
+
+ CertErrors errors;
+ bool result = VerifyCertificateChain(chain, trust_anchor.get(),
+ &signature_policy, time, &errors);
+ EXPECT_EQ(expected_result, result);
+ EXPECT_EQ(expected_errors, errors.ToDebugString()) << "Test file: "
+ << test_file_path;
+ if (!result)
+ EXPECT_FALSE(errors.empty());
}
-
- SimpleSignaturePolicy signature_policy(1024);
-
- std::vector<scoped_refptr<ParsedCertificate>> trusted_chain;
- bool result = VerifyCertificateChain(input_chain, trust_store,
- &signature_policy, time, &trusted_chain);
- if (result) {
- ASSERT_EQ(trusted_chain.size(), input_chain.size() + 1);
- ASSERT_TRUE(std::equal(input_chain.begin(), input_chain.end(),
- trusted_chain.begin()));
- ASSERT_TRUE(trust_store.IsTrustedCertificate(trusted_chain.back().get()));
- } else {
- ASSERT_EQ(trusted_chain.size(), 0u);
- }
-
- ASSERT_EQ(expected_result, result);
-}
-
-TEST(VerifyCertificateChainTest, TargetAndIntermediary) {
- RunTest("target-and-intermediary.pem");
-}
-
-TEST(VerifyCertificateChainTest, UnknownRoot) {
- RunTest("unknown-root.pem");
-}
-
-TEST(VerifyCertificateChainTest, IntermediaryLacksBasicConstraints) {
- RunTest("intermediary-lacks-basic-constraints.pem");
-}
-
-TEST(VerifyCertificateChainTest, IntermediaryBasicConstraintsCaFalse) {
- RunTest("intermediary-basic-constraints-ca-false.pem");
-}
-
-TEST(VerifyCertificateChainTest, IntermediaryBasicConstraintsNotCritical) {
- RunTest("intermediary-basic-constraints-not-critical.pem");
-}
-
-TEST(VerifyCertificateChainTest, IntermediaryLacksSigningKeyUsage) {
- RunTest("intermediary-lacks-signing-key-usage.pem");
-}
-
-TEST(VerifyCertificateChainTest, IntermediaryUnknownCriticalExtension) {
- RunTest("intermediary-unknown-critical-extension.pem");
-}
-
-TEST(VerifyCertificateChainTest, IntermediaryUnknownNonCriticalExtension) {
- RunTest("intermediary-unknown-non-critical-extension.pem");
-}
-
-TEST(VerifyCertificateChainTest, ViolatesBasicConstraintsPathlen0) {
- RunTest("violates-basic-constraints-pathlen-0.pem");
-}
-
-TEST(VerifyCertificateChainTest, BasicConstraintsPathlen0SelfIssued) {
- RunTest("basic-constraints-pathlen-0-self-issued.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetSignedWithMd5) {
- RunTest("target-signed-with-md5.pem");
-}
-
-TEST(VerifyCertificateChainTest, IntermediarySignedWithMd5) {
- RunTest("intermediary-signed-with-md5.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetWrongSignature) {
- RunTest("target-wrong-signature.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetSignedBy512bitRsa) {
- RunTest("target-signed-by-512bit-rsa.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetSignedUsingEcdsa) {
- RunTest("target-signed-using-ecdsa.pem");
-}
-
-TEST(VerifyCertificateChainTest, ExpiredIntermediary) {
- RunTest("expired-intermediary.pem");
-}
-
-TEST(VerifyCertificateChainTest, ExpiredTarget) {
- RunTest("expired-target.pem");
-}
-
-TEST(VerifyCertificateChainTest, ExpiredTargetNotBefore) {
- RunTest("expired-target-notBefore.pem");
-}
-
-TEST(VerifyCertificateChainTest, ExpiredRoot) {
- RunTest("expired-root.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetNotEndEntity) {
- RunTest("target-not-end-entity.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetHasKeyCertSignButNotCa) {
- RunTest("target-has-keycertsign-but-not-ca.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetHasPathlenButNotCa) {
- RunTest("target-has-pathlen-but-not-ca.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetUnknownCriticalExtension) {
- RunTest("target-unknown-critical-extension.pem");
-}
-
-TEST(VerifyCertificateChainTest, IssuerAndSubjectNotByteForByteEqual) {
- RunTest("issuer-and-subject-not-byte-for-byte-equal.pem");
-}
-
-TEST(VerifyCertificateChainTest, IssuerAndSubjectNotByteForByteEqualAnchor) {
- RunTest("issuer-and-subject-not-byte-for-byte-equal-anchor.pem");
-}
-
-TEST(VerifyCertificateChainTest, ViolatesPathlen1Root) {
- RunTest("violates-pathlen-1-root.pem");
-}
-
-TEST(VerifyCertificateChainTest, NonSelfSignedRoot) {
- RunTest("non-self-signed-root.pem");
-}
-
-// Tests that verifying a chain with no certificates fails.
-TEST(VerifyCertificateChainTest, EmptyChainIsInvalid) {
- TrustStore trust_store;
- der::GeneralizedTime time;
- std::vector<scoped_refptr<ParsedCertificate>> chain;
- SimpleSignaturePolicy signature_policy(2048);
-
- ASSERT_FALSE(VerifyCertificateChain(chain, trust_store, &signature_policy,
- time, nullptr));
-}
-
-// TODO(eroman): Add test that invalidate validity dates where the day or month
-// ordinal not in range, like "March 39, 2016" are rejected.
+};
} // namespace
+INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain,
+ VerifyCertificateChainSingleRootTest,
+ VerifyCertificateChainDelegate);
+
} // namespace net
diff --git a/chromium/net/cert/internal/verify_name_match_fuzzer.cc b/chromium/net/cert/internal/verify_name_match_fuzzer.cc
index 8f516931b80..464108e51d2 100644
--- a/chromium/net/cert/internal/verify_name_match_fuzzer.cc
+++ b/chromium/net/cert/internal/verify_name_match_fuzzer.cc
@@ -4,12 +4,12 @@
#include "net/cert/internal/verify_name_match.h"
-#include "net/base/fuzzed_data_provider.h"
+#include "base/test/fuzzed_data_provider.h"
#include "net/der/input.h"
// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- net::FuzzedDataProvider fuzzed_data(data, size);
+ base::FuzzedDataProvider fuzzed_data(data, size);
size_t first_part_size = fuzzed_data.ConsumeUint16();
base::StringPiece first_part = fuzzed_data.ConsumeBytes(first_part_size);
base::StringPiece second_part = fuzzed_data.ConsumeRemainingBytes();
diff --git a/chromium/net/cert/internal/verify_name_match_verifynameinsubtree_fuzzer.cc b/chromium/net/cert/internal/verify_name_match_verifynameinsubtree_fuzzer.cc
index f0a8828844d..1d4ea048513 100644
--- a/chromium/net/cert/internal/verify_name_match_verifynameinsubtree_fuzzer.cc
+++ b/chromium/net/cert/internal/verify_name_match_verifynameinsubtree_fuzzer.cc
@@ -4,12 +4,12 @@
#include "net/cert/internal/verify_name_match.h"
-#include "net/base/fuzzed_data_provider.h"
+#include "base/test/fuzzed_data_provider.h"
#include "net/der/input.h"
// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- net::FuzzedDataProvider fuzzed_data(data, size);
+ base::FuzzedDataProvider fuzzed_data(data, size);
size_t first_part_size = fuzzed_data.ConsumeUint16();
base::StringPiece first_part = fuzzed_data.ConsumeBytes(first_part_size);
base::StringPiece second_part = fuzzed_data.ConsumeRemainingBytes();
diff --git a/chromium/net/cert/internal/verify_signed_data.cc b/chromium/net/cert/internal/verify_signed_data.cc
index fe6aae80d94..bd0ee60f5ea 100644
--- a/chromium/net/cert/internal/verify_signed_data.cc
+++ b/chromium/net/cert/internal/verify_signed_data.cc
@@ -15,6 +15,7 @@
#include "base/logging.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
+#include "net/cert/internal/cert_errors.h"
#include "net/cert/internal/signature_algorithm.h"
#include "net/cert/internal/signature_policy.h"
#include "net/der/input.h"
@@ -25,6 +26,15 @@ namespace net {
namespace {
+DEFINE_CERT_ERROR_ID(kUnacceptableSignatureAlgorithm,
+ "Unacceptable signature algorithm");
+DEFINE_CERT_ERROR_ID(kUnacceptableRsaModulusLength,
+ "Unacceptable modulus length for RSA key");
+DEFINE_CERT_ERROR_ID(kUnacceptableEcdsaCurve,
+ "Unacceptable curve for ECDSA key");
+DEFINE_CERT_ERROR_ID(kSignatureVerificationFailed,
+ "Signature verification failed");
+
// Converts a DigestAlgorithm to an equivalent EVP_MD*.
WARN_UNUSED_RESULT bool GetDigest(DigestAlgorithm digest, const EVP_MD** out) {
*out = nullptr;
@@ -144,7 +154,9 @@ WARN_UNUSED_RESULT bool ImportPkeyFromSpki(const der::Input& spki,
// Following RFC 3279 in this case.
WARN_UNUSED_RESULT bool ParseRsaKeyFromSpki(const der::Input& public_key_spki,
crypto::ScopedEVP_PKEY* pkey,
- const SignaturePolicy* policy) {
+ const SignaturePolicy* policy,
+ CertErrors* errors) {
+ // TODO(crbug.com/634443): Add more specific errors.
if (!ImportPkeyFromSpki(public_key_spki, EVP_PKEY_RSA, pkey))
return false;
@@ -154,7 +166,12 @@ WARN_UNUSED_RESULT bool ParseRsaKeyFromSpki(const der::Input& public_key_spki,
return false;
unsigned int modulus_length_bits = BN_num_bits(rsa->n);
- return policy->IsAcceptableModulusLengthForRsa(modulus_length_bits);
+ if (!policy->IsAcceptableModulusLengthForRsa(modulus_length_bits, errors)) {
+ errors->AddError(kUnacceptableRsaModulusLength);
+ return false;
+ }
+
+ return true;
}
// Does signature verification using either RSA or ECDSA.
@@ -246,7 +263,9 @@ WARN_UNUSED_RESULT bool DoVerify(const SignatureAlgorithm& algorithm,
// }
WARN_UNUSED_RESULT bool ParseEcKeyFromSpki(const der::Input& public_key_spki,
crypto::ScopedEVP_PKEY* pkey,
- const SignaturePolicy* policy) {
+ const SignaturePolicy* policy,
+ CertErrors* errors) {
+ // TODO(crbug.com/634443): Add more specific errors.
if (!ImportPkeyFromSpki(public_key_spki, EVP_PKEY_EC, pkey))
return false;
@@ -256,7 +275,12 @@ WARN_UNUSED_RESULT bool ParseEcKeyFromSpki(const der::Input& public_key_spki,
return false; // Unexpected.
int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get()));
- return policy->IsAcceptableCurveForEcdsa(curve_nid);
+ if (!policy->IsAcceptableCurveForEcdsa(curve_nid, errors)) {
+ errors->AddError(kUnacceptableEcdsaCurve);
+ return false;
+ }
+
+ return true;
}
} // namespace
@@ -265,9 +289,12 @@ bool VerifySignedData(const SignatureAlgorithm& signature_algorithm,
const der::Input& signed_data,
const der::BitString& signature_value,
const der::Input& public_key_spki,
- const SignaturePolicy* policy) {
- if (!policy->IsAcceptableSignatureAlgorithm(signature_algorithm))
+ const SignaturePolicy* policy,
+ CertErrors* errors) {
+ if (!policy->IsAcceptableSignatureAlgorithm(signature_algorithm, errors)) {
+ errors->AddError(kUnacceptableSignatureAlgorithm);
return false;
+ }
crypto::ScopedEVP_PKEY public_key;
@@ -275,17 +302,22 @@ bool VerifySignedData(const SignatureAlgorithm& signature_algorithm,
switch (signature_algorithm.algorithm()) {
case SignatureAlgorithmId::RsaPkcs1:
case SignatureAlgorithmId::RsaPss:
- if (!ParseRsaKeyFromSpki(public_key_spki, &public_key, policy))
+ if (!ParseRsaKeyFromSpki(public_key_spki, &public_key, policy, errors))
return false;
break;
case SignatureAlgorithmId::Ecdsa:
- if (!ParseEcKeyFromSpki(public_key_spki, &public_key, policy))
+ if (!ParseEcKeyFromSpki(public_key_spki, &public_key, policy, errors))
return false;
break;
}
- return DoVerify(signature_algorithm, signed_data, signature_value,
- public_key.get());
+ if (!DoVerify(signature_algorithm, signed_data, signature_value,
+ public_key.get())) {
+ errors->AddError(kSignatureVerificationFailed);
+ return false;
+ }
+
+ return true;
}
} // namespace net
diff --git a/chromium/net/cert/internal/verify_signed_data.h b/chromium/net/cert/internal/verify_signed_data.h
index 97c150dffba..9c749123f3b 100644
--- a/chromium/net/cert/internal/verify_signed_data.h
+++ b/chromium/net/cert/internal/verify_signed_data.h
@@ -15,6 +15,7 @@ class BitString;
class Input;
} // namespace der
+class CertErrors;
class SignatureAlgorithm;
class SignaturePolicy;
@@ -30,14 +31,15 @@ class SignaturePolicy;
// * The parsed RSA key is an adequate size.
// * The parsed EC key is for an allowed curve.
// * The signature algorithm and its parameters are acceptable.
+// |errors| - Non-null destination for errors/warnings information.
//
// Returns true if verification was successful.
NET_EXPORT bool VerifySignedData(const SignatureAlgorithm& signature_algorithm,
const der::Input& signed_data,
const der::BitString& signature_value,
const der::Input& public_key,
- const SignaturePolicy* policy)
- WARN_UNUSED_RESULT;
+ const SignaturePolicy* policy,
+ CertErrors* errors) WARN_UNUSED_RESULT;
} // namespace net
diff --git a/chromium/net/cert/internal/verify_signed_data_unittest.cc b/chromium/net/cert/internal/verify_signed_data_unittest.cc
index ba0fab2c215..7710abc47f2 100644
--- a/chromium/net/cert/internal/verify_signed_data_unittest.cc
+++ b/chromium/net/cert/internal/verify_signed_data_unittest.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <set>
+#include "net/cert/internal/cert_errors.h"
#include "net/cert/internal/signature_algorithm.h"
#include "net/cert/internal/signature_policy.h"
#include "net/cert/internal/test_helpers.h"
@@ -54,9 +55,10 @@ void RunTestCaseUsingPolicy(VerifyResult expected_result,
ASSERT_TRUE(ReadTestDataFromPemFile(path, mappings));
+ CertErrors algorithm_errors;
std::unique_ptr<SignatureAlgorithm> signature_algorithm =
- SignatureAlgorithm::CreateFromDer(der::Input(&algorithm));
- ASSERT_TRUE(signature_algorithm);
+ SignatureAlgorithm::Create(der::Input(&algorithm), &algorithm_errors);
+ ASSERT_TRUE(signature_algorithm) << algorithm_errors.ToDebugString();
der::BitString signature_value_bit_string;
der::Parser signature_value_parser((der::Input(&signature_value)));
@@ -65,10 +67,15 @@ void RunTestCaseUsingPolicy(VerifyResult expected_result,
bool expected_result_bool = expected_result == SUCCESS;
- EXPECT_EQ(expected_result_bool,
- VerifySignedData(*signature_algorithm, der::Input(&signed_data),
- signature_value_bit_string,
- der::Input(&public_key), policy));
+ CertErrors verify_errors;
+ bool result =
+ VerifySignedData(*signature_algorithm, der::Input(&signed_data),
+ signature_value_bit_string, der::Input(&public_key),
+ policy, &verify_errors);
+ EXPECT_EQ(expected_result_bool, result);
+ // TODO(crbug.com/634443): Verify the returned errors.
+ // if (!result)
+ // EXPECT_FALSE(verify_errors.empty());
}
// RunTestCase() is the same as RunTestCaseUsingPolicy(), only it uses a
@@ -215,7 +222,8 @@ TEST(VerifySignedDataTest, EcdsaPrime256v1Sha512UnusedBitsSignature) {
// This policy rejects specifically secp384r1 curves.
class RejectSecp384r1Policy : public SignaturePolicy {
public:
- bool IsAcceptableCurveForEcdsa(int curve_nid) const override {
+ bool IsAcceptableCurveForEcdsa(int curve_nid,
+ CertErrors* errors) const override {
if (curve_nid == NID_secp384r1)
return false;
return true;
@@ -253,8 +261,8 @@ class RejectSha512 : public SignaturePolicy {
public:
RejectSha512() : SignaturePolicy() {}
- bool IsAcceptableSignatureAlgorithm(
- const SignatureAlgorithm& algorithm) const override {
+ bool IsAcceptableSignatureAlgorithm(const SignatureAlgorithm& algorithm,
+ CertErrors* errors) const override {
if (algorithm.algorithm() == SignatureAlgorithmId::RsaPss &&
algorithm.ParamsForRsaPss()->mgf1_hash() == DigestAlgorithm::Sha512) {
return false;
@@ -263,8 +271,8 @@ class RejectSha512 : public SignaturePolicy {
return algorithm.digest() != DigestAlgorithm::Sha512;
}
- bool IsAcceptableModulusLengthForRsa(
- size_t modulus_length_bits) const override {
+ bool IsAcceptableModulusLengthForRsa(size_t modulus_length_bits,
+ CertErrors* errors) const override {
return true;
}
};
diff --git a/chromium/net/cert/merkle_audit_proof.cc b/chromium/net/cert/merkle_audit_proof.cc
index eef237e6dd7..675485b2589 100644
--- a/chromium/net/cert/merkle_audit_proof.cc
+++ b/chromium/net/cert/merkle_audit_proof.cc
@@ -30,10 +30,9 @@ uint64_t CalculateAuditPathLength(uint64_t leaf_index, uint64_t tree_size) {
MerkleAuditProof::MerkleAuditProof() {}
-MerkleAuditProof::MerkleAuditProof(const std::string& log_id,
- uint64_t leaf_index,
+MerkleAuditProof::MerkleAuditProof(uint64_t leaf_index,
const std::vector<std::string>& audit_path)
- : log_id(log_id), leaf_index(leaf_index), nodes(audit_path) {}
+ : leaf_index(leaf_index), nodes(audit_path) {}
MerkleAuditProof::~MerkleAuditProof() {}
diff --git a/chromium/net/cert/merkle_audit_proof.h b/chromium/net/cert/merkle_audit_proof.h
index 2f6fdb93b9f..b214891ee14 100644
--- a/chromium/net/cert/merkle_audit_proof.h
+++ b/chromium/net/cert/merkle_audit_proof.h
@@ -25,14 +25,10 @@ NET_EXPORT uint64_t CalculateAuditPathLength(uint64_t leaf_index,
// Audit proof for a Merkle tree leaf, as defined in section 2.1.1. of RFC6962.
struct NET_EXPORT MerkleAuditProof {
MerkleAuditProof();
- MerkleAuditProof(const std::string& log_id,
- uint64_t leaf_index,
+ MerkleAuditProof(uint64_t leaf_index,
const std::vector<std::string>& audit_path);
~MerkleAuditProof();
- // The origin of this proof.
- std::string log_id;
-
// Index of the tree leaf in the log.
uint64_t leaf_index = 0;
diff --git a/chromium/net/cert/merkle_tree_leaf.cc b/chromium/net/cert/merkle_tree_leaf.cc
index 21e2814402c..5dfe08e350f 100644
--- a/chromium/net/cert/merkle_tree_leaf.cc
+++ b/chromium/net/cert/merkle_tree_leaf.cc
@@ -15,9 +15,13 @@ namespace ct {
MerkleTreeLeaf::MerkleTreeLeaf() {}
-MerkleTreeLeaf::~MerkleTreeLeaf() {}
+MerkleTreeLeaf::MerkleTreeLeaf(const MerkleTreeLeaf& other) = default;
-bool Hash(const MerkleTreeLeaf& tree_leaf, std::string* out) {
+MerkleTreeLeaf::MerkleTreeLeaf(MerkleTreeLeaf&&) = default;
+
+MerkleTreeLeaf::~MerkleTreeLeaf() = default;
+
+bool HashMerkleTreeLeaf(const MerkleTreeLeaf& tree_leaf, std::string* out) {
// Prepend 0 byte as per RFC 6962, section-2.1
std::string leaf_in_tls_format("\x00", 1);
if (!EncodeTreeLeaf(tree_leaf, &leaf_in_tls_format))
@@ -44,7 +48,6 @@ bool GetMerkleTreeLeaf(const X509Certificate* cert,
}
}
- merkle_tree_leaf->log_id = sct->log_id;
merkle_tree_leaf->timestamp = sct->timestamp;
merkle_tree_leaf->extensions = sct->extensions;
return true;
diff --git a/chromium/net/cert/merkle_tree_leaf.h b/chromium/net/cert/merkle_tree_leaf.h
index 8f314f56a70..21217bb6ec5 100644
--- a/chromium/net/cert/merkle_tree_leaf.h
+++ b/chromium/net/cert/merkle_tree_leaf.h
@@ -19,15 +19,25 @@ class X509Certificate;
namespace ct {
// Represents a MerkleTreeLeaf as defined in RFC6962, section 3.4.
-// Has all the data as the MerkleTreeLeaf defined in the RFC, arranged
-// slightly differently.
+// The goal of this struct is to represent the Merkle tree entry such that
+// all details are easily accessible and a leaf hash can be easily calculated
+// for the entry.
+//
+// As such, it has all the data as the MerkleTreeLeaf defined in the RFC,
+// but it is not identical to the structure in the RFC for the following
+// reasons:
+// * The version is implicit - it is only used for V1 leaves currently.
+// * the leaf_type is also implicit: There's exactly one leaf type and no
+// new types are planned.
+// * The timestamped_entry's |timestamp| and |extensions| fields are directly
+// accessible.
+// * The timestamped_entry's entry_type can be deduced from |log_entry|.type
struct NET_EXPORT MerkleTreeLeaf {
MerkleTreeLeaf();
+ MerkleTreeLeaf(const MerkleTreeLeaf& other);
+ MerkleTreeLeaf(MerkleTreeLeaf&&);
~MerkleTreeLeaf();
- // The log id this leaf belongs to.
- std::string log_id;
-
// Certificate / Precertificate and indication of entry type.
LogEntry log_entry;
@@ -38,13 +48,19 @@ struct NET_EXPORT MerkleTreeLeaf {
std::string extensions;
};
+// Given a |cert| and an |sct| for that certificate, constructs the
+// representation of this entry in the Merkle tree by filling in
+// |merkle_tree_leaf|.
+// Returns false if it failed to construct the |merkle_tree_leaf|.
NET_EXPORT bool GetMerkleTreeLeaf(const X509Certificate* cert,
const SignedCertificateTimestamp* sct,
MerkleTreeLeaf* merkle_tree_leaf);
-// Sets |*out| to the hash of the Merkle |tree_leaf|, as defined in RFC6962.
-// Returns true if the hash was generated, false if an error occurred.
-NET_EXPORT bool Hash(const MerkleTreeLeaf& tree_leaf, std::string* out);
+// Sets |*out| to the hash of the Merkle |tree_leaf|, as defined in RFC6962,
+// section 3.4. Returns true if the hash was generated, false if an error
+// occurred.
+NET_EXPORT bool HashMerkleTreeLeaf(const MerkleTreeLeaf& tree_leaf,
+ std::string* out);
} // namespace ct
diff --git a/chromium/net/cert/merkle_tree_leaf_unittest.cc b/chromium/net/cert/merkle_tree_leaf_unittest.cc
index 42d6ad474d0..29c4c18179d 100644
--- a/chromium/net/cert/merkle_tree_leaf_unittest.cc
+++ b/chromium/net/cert/merkle_tree_leaf_unittest.cc
@@ -75,7 +75,6 @@ TEST_F(MerkleTreeLeafTest, CreatesForX509Cert) {
MerkleTreeLeaf leaf;
ASSERT_TRUE(GetMerkleTreeLeaf(test_cert_.get(), x509_sct_.get(), &leaf));
- EXPECT_EQ(x509_sct_->log_id, leaf.log_id);
EXPECT_EQ(LogEntry::LOG_ENTRY_TYPE_X509, leaf.log_entry.type);
EXPECT_FALSE(leaf.log_entry.leaf_certificate.empty());
EXPECT_TRUE(leaf.log_entry.tbs_certificate.empty());
@@ -89,7 +88,6 @@ TEST_F(MerkleTreeLeafTest, CreatesForPrecert) {
ASSERT_TRUE(
GetMerkleTreeLeaf(test_precert_.get(), precert_sct_.get(), &leaf));
- EXPECT_EQ(precert_sct_->log_id, leaf.log_id);
EXPECT_EQ(LogEntry::LOG_ENTRY_TYPE_PRECERT, leaf.log_entry.type);
EXPECT_FALSE(leaf.log_entry.tbs_certificate.empty());
EXPECT_TRUE(leaf.log_entry.leaf_certificate.empty());
@@ -114,7 +112,7 @@ TEST_F(MerkleTreeLeafTest, HashForX509Cert) {
ct::GetX509CertTreeLeaf(&leaf);
std::string hash;
- ASSERT_TRUE(Hash(leaf, &hash));
+ ASSERT_TRUE(HashMerkleTreeLeaf(leaf, &hash));
EXPECT_THAT(hash, HexEq("452da788b3b8d15872ff0bb0777354b2a7f1c1887b5633201e76"
"2ba5a4b143fc"));
}
@@ -124,7 +122,7 @@ TEST_F(MerkleTreeLeafTest, HashForPrecert) {
ct::GetPrecertTreeLeaf(&leaf);
std::string hash;
- ASSERT_TRUE(Hash(leaf, &hash));
+ ASSERT_TRUE(HashMerkleTreeLeaf(leaf, &hash));
EXPECT_THAT(hash, HexEq("257ae85f08810445511e35e33f7aee99ee19407971e35e95822b"
"bf42a74be223"));
}
diff --git a/chromium/net/cert/mock_cert_verifier.cc b/chromium/net/cert/mock_cert_verifier.cc
index f184e55ebdf..9cbbafd3cfe 100644
--- a/chromium/net/cert/mock_cert_verifier.cc
+++ b/chromium/net/cert/mock_cert_verifier.cc
@@ -45,7 +45,7 @@ int MockCertVerifier::Verify(const RequestParams& params,
CertVerifyResult* verify_result,
const CompletionCallback& callback,
std::unique_ptr<Request>* out_req,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
RuleList::const_iterator it;
for (it = rules_.begin(); it != rules_.end(); ++it) {
// Check just the server cert. Intermediates will be ignored.
diff --git a/chromium/net/cert/mock_cert_verifier.h b/chromium/net/cert/mock_cert_verifier.h
index 994c5548c75..b5b35a1a0c4 100644
--- a/chromium/net/cert/mock_cert_verifier.h
+++ b/chromium/net/cert/mock_cert_verifier.h
@@ -31,7 +31,7 @@ class MockCertVerifier : public CertVerifier {
CertVerifyResult* verify_result,
const CompletionCallback& callback,
std::unique_ptr<Request>* out_req,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
// Sets the default return value for Verify() for certificates/hosts that do
// not have explicit results added via the AddResult*() methods.
diff --git a/chromium/net/cert/multi_log_ct_verifier.cc b/chromium/net/cert/multi_log_ct_verifier.cc
index d3ff7375a9c..8dc172677a5 100644
--- a/chromium/net/cert/multi_log_ct_verifier.cc
+++ b/chromium/net/cert/multi_log_ct_verifier.cc
@@ -18,7 +18,9 @@
#include "net/cert/ct_verify_result.h"
#include "net/cert/sct_status_flags.h"
#include "net/cert/x509_certificate.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_parameters_callback.h"
+#include "net/log/net_log_with_source.h"
namespace net {
@@ -27,8 +29,12 @@ namespace {
// Record SCT verification status. This metric would help detecting presence
// of unknown CT logs as well as bad deployments (invalid SCTs).
void LogSCTStatusToUMA(ct::SCTVerifyStatus status) {
- UMA_HISTOGRAM_ENUMERATION(
- "Net.CertificateTransparency.SCTStatus", status, ct::SCT_STATUS_MAX);
+ // Note SCT_STATUS_MAX + 1 is passed to the UMA_HISTOGRAM_ENUMERATION as that
+ // macro requires the values to be strictly less than the boundary value,
+ // and SCT_STATUS_MAX is the last valid value of the SCTVerifyStatus enum
+ // (since that enum is used for IPC as well).
+ UMA_HISTOGRAM_ENUMERATION("Net.CertificateTransparency.SCTStatus", status,
+ ct::SCT_STATUS_MAX + 1);
}
// Record SCT origin enum. This metric measure the popularity
@@ -46,12 +52,14 @@ void LogSCTOriginToUMA(ct::SignedCertificateTimestamp::Origin origin) {
// * When SCTs are available, how many are available per connection.
void LogNumSCTsToUMA(const ct::CTVerifyResult& result) {
UMA_HISTOGRAM_CUSTOM_COUNTS("Net.CertificateTransparency.SCTsPerConnection",
- result.invalid_scts.size() +
- result.verified_scts.size() +
- result.unknown_logs_scts.size(),
- 1,
- 10,
- 11);
+ result.scts.size(), 1, 10, 11);
+}
+
+void AddSCTAndLogStatus(scoped_refptr<ct::SignedCertificateTimestamp> sct,
+ ct::SCTVerifyStatus status,
+ SignedCertificateTimestampAndStatusList* sct_list) {
+ LogSCTStatusToUMA(status);
+ sct_list->push_back(SignedCertificateTimestampAndStatus(sct, status));
}
} // namespace
@@ -73,18 +81,15 @@ void MultiLogCTVerifier::SetObserver(Observer* observer) {
observer_ = observer;
}
-int MultiLogCTVerifier::Verify(
- X509Certificate* cert,
- const std::string& stapled_ocsp_response,
- const std::string& sct_list_from_tls_extension,
- ct::CTVerifyResult* result,
- const BoundNetLog& net_log) {
+int MultiLogCTVerifier::Verify(X509Certificate* cert,
+ const std::string& stapled_ocsp_response,
+ const std::string& sct_list_from_tls_extension,
+ ct::CTVerifyResult* result,
+ const NetLogWithSource& net_log) {
DCHECK(cert);
DCHECK(result);
- result->verified_scts.clear();
- result->invalid_scts.clear();
- result->unknown_logs_scts.clear();
+ result->scts.clear();
bool has_verified_scts = false;
@@ -113,13 +118,12 @@ int MultiLogCTVerifier::Verify(
// Log to Net Log, after extracting SCTs but before possibly failing on
// X.509 entry creation.
- NetLog::ParametersCallback net_log_callback =
- base::Bind(&NetLogRawSignedCertificateTimestampCallback,
- &embedded_scts, &sct_list_from_ocsp, &sct_list_from_tls_extension);
+ NetLogParametersCallback net_log_callback =
+ base::Bind(&NetLogRawSignedCertificateTimestampCallback, &embedded_scts,
+ &sct_list_from_ocsp, &sct_list_from_tls_extension);
- net_log.AddEvent(
- NetLog::TYPE_SIGNED_CERTIFICATE_TIMESTAMPS_RECEIVED,
- net_log_callback);
+ net_log.AddEvent(NetLogEventType::SIGNED_CERTIFICATE_TIMESTAMPS_RECEIVED,
+ net_log_callback);
ct::LogEntry x509_entry;
if (ct::GetX509LogEntry(cert->os_cert_handle(), &x509_entry)) {
@@ -132,12 +136,11 @@ int MultiLogCTVerifier::Verify(
ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, cert, result);
}
- NetLog::ParametersCallback net_log_checked_callback =
+ NetLogParametersCallback net_log_checked_callback =
base::Bind(&NetLogSignedCertificateTimestampCallback, result);
- net_log.AddEvent(
- NetLog::TYPE_SIGNED_CERTIFICATE_TIMESTAMPS_CHECKED,
- net_log_checked_callback);
+ net_log.AddEvent(NetLogEventType::SIGNED_CERTIFICATE_TIMESTAMPS_CHECKED,
+ net_log_checked_callback);
LogNumSCTsToUMA(*result);
@@ -191,8 +194,7 @@ bool MultiLogCTVerifier::VerifySingleSCT(
const auto& it = logs_.find(sct->log_id);
if (it == logs_.end()) {
DVLOG(1) << "SCT does not match any known log.";
- result->unknown_logs_scts.push_back(sct);
- LogSCTStatusToUMA(ct::SCT_STATUS_LOG_UNKNOWN);
+ AddSCTAndLogStatus(sct, ct::SCT_STATUS_LOG_UNKNOWN, &(result->scts));
return false;
}
@@ -200,21 +202,18 @@ bool MultiLogCTVerifier::VerifySingleSCT(
if (!it->second->Verify(expected_entry, *sct.get())) {
DVLOG(1) << "Unable to verify SCT signature.";
- result->invalid_scts.push_back(sct);
- LogSCTStatusToUMA(ct::SCT_STATUS_INVALID);
+ AddSCTAndLogStatus(sct, ct::SCT_STATUS_INVALID_SIGNATURE, &(result->scts));
return false;
}
// SCT verified ok, just make sure the timestamp is legitimate.
if (sct->timestamp > base::Time::Now()) {
DVLOG(1) << "SCT is from the future!";
- result->invalid_scts.push_back(sct);
- LogSCTStatusToUMA(ct::SCT_STATUS_INVALID);
+ AddSCTAndLogStatus(sct, ct::SCT_STATUS_INVALID_TIMESTAMP, &(result->scts));
return false;
}
- LogSCTStatusToUMA(ct::SCT_STATUS_OK);
- result->verified_scts.push_back(sct);
+ AddSCTAndLogStatus(sct, ct::SCT_STATUS_OK, &(result->scts));
if (observer_)
observer_->OnSCTVerified(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 0d8667e6e7e..38ea659dfb8 100644
--- a/chromium/net/cert/multi_log_ct_verifier.h
+++ b/chromium/net/cert/multi_log_ct_verifier.h
@@ -38,7 +38,7 @@ class NET_EXPORT MultiLogCTVerifier : public CTVerifier {
const std::string& stapled_ocsp_response,
const std::string& sct_list_from_tls_extension,
ct::CTVerifyResult* result,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void SetObserver(Observer* observer) override;
diff --git a/chromium/net/cert/multi_log_ct_verifier_unittest.cc b/chromium/net/cert/multi_log_ct_verifier_unittest.cc
index 36dbdc697d1..7186a3a22e6 100644
--- a/chromium/net/cert/multi_log_ct_verifier_unittest.cc
+++ b/chromium/net/cert/multi_log_ct_verifier_unittest.cc
@@ -21,7 +21,8 @@
#include "net/cert/sct_status_flags.h"
#include "net/cert/signed_certificate_timestamp.h"
#include "net/cert/x509_certificate.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_source_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
#include "net/log/test_net_log_entry.h"
#include "net/test/cert_test_util.h"
@@ -51,8 +52,9 @@ class MockSCTObserver : public CTVerifier::Observer {
class MultiLogCTVerifierTest : public ::testing::Test {
public:
void SetUp() override {
- scoped_refptr<const CTLogVerifier> log(CTLogVerifier::Create(
- ct::GetTestPublicKey(), kLogDescription, "https://ct.example.com"));
+ scoped_refptr<const CTLogVerifier> log(
+ CTLogVerifier::Create(ct::GetTestPublicKey(), kLogDescription,
+ "https://ct.example.com", "dns.example.com"));
ASSERT_TRUE(log);
log_verifiers_.push_back(log);
@@ -85,14 +87,13 @@ class MultiLogCTVerifierTest : public ::testing::Test {
return false;
const TestNetLogEntry& parsed = entries[1];
- base::ListValue* verified_scts;
- if (!parsed.GetListValue("verified_scts", &verified_scts) ||
- verified_scts->GetSize() != 1) {
+ base::ListValue* scts;
+ if (!parsed.GetListValue("scts", &scts) || scts->GetSize() != 1) {
return false;
}
base::DictionaryValue* the_sct;
- if (!verified_scts->GetDictionary(0, &the_sct))
+ if (!scts->GetDictionary(0, &the_sct))
return false;
std::string origin;
@@ -101,53 +102,42 @@ class MultiLogCTVerifierTest : public ::testing::Test {
if (origin != "Embedded in certificate")
return false;
- base::ListValue* other_scts;
- if (!parsed.GetListValue("invalid_scts", &other_scts) ||
- !other_scts->empty()) {
+ std::string verification_status;
+ if (!the_sct->GetString("verification_status", &verification_status))
return false;
- }
-
- if (!parsed.GetListValue("unknown_logs_scts", &other_scts) ||
- !other_scts->empty()) {
+ if (verification_status != "Verified")
return false;
- }
return true;
}
bool VerifySinglePrecertificateChain(scoped_refptr<X509Certificate> chain,
- const BoundNetLog& bound_net_log,
+ const NetLogWithSource& net_log,
ct::CTVerifyResult* result) {
- return verifier_->Verify(chain.get(),
- std::string(),
- std::string(),
- result,
- bound_net_log) == OK;
+ return verifier_->Verify(chain.get(), std::string(), std::string(), result,
+ net_log) == OK;
}
bool VerifySinglePrecertificateChain(scoped_refptr<X509Certificate> chain) {
ct::CTVerifyResult result;
- TestNetLog net_log;
- BoundNetLog bound_net_log =
- BoundNetLog::Make(&net_log, NetLog::SOURCE_CONNECT_JOB);
-
- return verifier_->Verify(chain.get(),
- std::string(),
- std::string(),
- &result,
- bound_net_log) == OK;
+ TestNetLog test_net_log;
+ NetLogWithSource net_log =
+ NetLogWithSource::Make(&test_net_log, NetLogSourceType::CONNECT_JOB);
+
+ return verifier_->Verify(chain.get(), std::string(), std::string(), &result,
+ net_log) == OK;
}
bool CheckPrecertificateVerification(scoped_refptr<X509Certificate> chain) {
ct::CTVerifyResult result;
- TestNetLog net_log;
- BoundNetLog bound_net_log =
- BoundNetLog::Make(&net_log, NetLog::SOURCE_CONNECT_JOB);
- return (VerifySinglePrecertificateChain(chain, bound_net_log, &result) &&
+ TestNetLog test_net_log;
+ NetLogWithSource net_log =
+ NetLogWithSource::Make(&test_net_log, NetLogSourceType::CONNECT_JOB);
+ return (VerifySinglePrecertificateChain(chain, net_log, &result) &&
ct::CheckForSingleVerifiedSCTInResult(result, kLogDescription) &&
ct::CheckForSCTOrigin(
result, ct::SignedCertificateTimestamp::SCT_EMBEDDED) &&
- CheckForEmbeddedSCTInNetLog(net_log));
+ CheckForEmbeddedSCTInNetLog(test_net_log));
}
// Histogram-related helper methods
@@ -221,9 +211,8 @@ TEST_F(MultiLogCTVerifierTest, VerifiesSCTOverX509Cert) {
std::string sct_list = ct::GetSCTListForTesting();
ct::CTVerifyResult result;
- EXPECT_EQ(OK,
- verifier_->Verify(
- chain_.get(), std::string(), sct_list, &result, BoundNetLog()));
+ EXPECT_EQ(OK, verifier_->Verify(chain_.get(), std::string(), sct_list,
+ &result, NetLogWithSource()));
ASSERT_TRUE(ct::CheckForSingleVerifiedSCTInResult(result, kLogDescription));
ASSERT_TRUE(ct::CheckForSCTOrigin(
result, ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION));
@@ -233,11 +222,11 @@ TEST_F(MultiLogCTVerifierTest, IdentifiesSCTFromUnknownLog) {
std::string sct_list = ct::GetSCTListWithInvalidSCT();
ct::CTVerifyResult result;
- EXPECT_NE(OK,
- verifier_->Verify(
- chain_.get(), std::string(), sct_list, &result, BoundNetLog()));
- EXPECT_EQ(1U, result.unknown_logs_scts.size());
- EXPECT_EQ("", result.unknown_logs_scts[0]->log_description);
+ EXPECT_NE(OK, verifier_->Verify(chain_.get(), std::string(), sct_list,
+ &result, NetLogWithSource()));
+ EXPECT_EQ(1U, result.scts.size());
+ EXPECT_EQ("", result.scts[0].sct->log_description);
+ EXPECT_EQ(ct::SCT_STATUS_LOG_UNKNOWN, result.scts[0].status);
}
TEST_F(MultiLogCTVerifierTest, CountsValidSCTsInStatusHistogram) {
@@ -255,9 +244,8 @@ TEST_F(MultiLogCTVerifierTest, CountsInvalidSCTsInStatusHistogram) {
int num_invalid_scts = GetValueFromHistogram(
"Net.CertificateTransparency.SCTStatus", ct::SCT_STATUS_LOG_UNKNOWN);
- EXPECT_NE(OK,
- verifier_->Verify(
- chain_.get(), std::string(), sct_list, &result, BoundNetLog()));
+ EXPECT_NE(OK, verifier_->Verify(chain_.get(), std::string(), sct_list,
+ &result, NetLogWithSource()));
ASSERT_EQ(num_valid_scts, NumValidSCTsInStatusHistogram());
ASSERT_EQ(num_invalid_scts + 1,
diff --git a/chromium/net/cert/multi_threaded_cert_verifier.cc b/chromium/net/cert/multi_threaded_cert_verifier.cc
index 7e51fd206e2..b2e8e28203c 100644
--- a/chromium/net/cert/multi_threaded_cert_verifier.cc
+++ b/chromium/net/cert/multi_threaded_cert_verifier.cc
@@ -30,7 +30,11 @@
#include "net/cert/crl_set.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_certificate_net_log_param.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
+#include "net/log/net_log_with_source.h"
#if defined(USE_NSS_CERTS)
#include <private/pprthred.h> // PR_DetachThread
@@ -38,6 +42,8 @@
namespace net {
+class NetLogCaptureMode;
+
////////////////////////////////////////////////////////////////////////////
//
// MultiThreadedCertVerifier is a thread-unsafe object which lives, dies, and is
@@ -125,20 +131,20 @@ class CertVerifierRequest : public base::LinkNode<CertVerifierRequest>,
CertVerifierRequest(CertVerifierJob* job,
const CompletionCallback& callback,
CertVerifyResult* verify_result,
- const BoundNetLog& net_log)
+ const NetLogWithSource& net_log)
: job_(job),
callback_(callback),
verify_result_(verify_result),
net_log_(net_log) {
- net_log_.BeginEvent(NetLog::TYPE_CERT_VERIFIER_REQUEST);
+ net_log_.BeginEvent(NetLogEventType::CERT_VERIFIER_REQUEST);
}
// Cancels the request.
~CertVerifierRequest() override {
if (job_) {
// Cancel the outstanding request.
- net_log_.AddEvent(NetLog::TYPE_CANCELLED);
- net_log_.EndEvent(NetLog::TYPE_CERT_VERIFIER_REQUEST);
+ net_log_.AddEvent(NetLogEventType::CANCELLED);
+ net_log_.EndEvent(NetLogEventType::CERT_VERIFIER_REQUEST);
// Remove the request from the Job. No attempt is made to cancel the job
// even though it may no longer have any requests attached to it. Because
@@ -153,7 +159,7 @@ class CertVerifierRequest : public base::LinkNode<CertVerifierRequest>,
DCHECK(job_);
job_ = nullptr;
- net_log_.EndEvent(NetLog::TYPE_CERT_VERIFIER_REQUEST);
+ net_log_.EndEvent(NetLogEventType::CERT_VERIFIER_REQUEST);
*verify_result_ = verify_result.result;
base::ResetAndReturn(&callback_).Run(verify_result.error);
@@ -164,13 +170,13 @@ class CertVerifierRequest : public base::LinkNode<CertVerifierRequest>,
callback_.Reset();
}
- const BoundNetLog& net_log() const { return net_log_; }
+ const NetLogWithSource& net_log() const { return net_log_; }
private:
CertVerifierJob* job_; // Not owned.
CompletionCallback callback_;
CertVerifyResult* verify_result_;
- const BoundNetLog net_log_;
+ const NetLogWithSource net_log_;
};
// DoVerifyOnWorkerThread runs the verification synchronously on a worker
@@ -208,11 +214,12 @@ class CertVerifierJob {
MultiThreadedCertVerifier* cert_verifier)
: key_(key),
start_time_(base::TimeTicks::Now()),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_CERT_VERIFIER_JOB)),
+ net_log_(NetLogWithSource::Make(net_log,
+ NetLogSourceType::CERT_VERIFIER_JOB)),
cert_verifier_(cert_verifier),
is_first_job_(false),
weak_ptr_factory_(this) {
- net_log_.BeginEvent(NetLog::TYPE_CERT_VERIFIER_JOB,
+ net_log_.BeginEvent(NetLogEventType::CERT_VERIFIER_JOB,
base::Bind(&NetLogX509CertificateCallback,
base::Unretained(key.certificate().get())));
}
@@ -251,8 +258,8 @@ class CertVerifierJob {
if (cert_verifier_) {
cert_verifier_ = nullptr;
- net_log_.AddEvent(NetLog::TYPE_CANCELLED);
- net_log_.EndEvent(NetLog::TYPE_CERT_VERIFIER_JOB);
+ net_log_.AddEvent(NetLogEventType::CANCELLED);
+ net_log_.EndEvent(NetLogEventType::CERT_VERIFIER_JOB);
// Notify each request of the cancellation.
for (base::LinkNode<CertVerifierRequest>* it = requests_.head();
@@ -266,12 +273,12 @@ class CertVerifierJob {
std::unique_ptr<CertVerifierRequest> CreateRequest(
const CompletionCallback& callback,
CertVerifyResult* verify_result,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
std::unique_ptr<CertVerifierRequest> request(
new CertVerifierRequest(this, callback, verify_result, net_log));
request->net_log().AddEvent(
- NetLog::TYPE_CERT_VERIFIER_REQUEST_BOUND_TO_JOB,
+ NetLogEventType::CERT_VERIFIER_REQUEST_BOUND_TO_JOB,
net_log_.source().ToEventParametersCallback());
requests_.Append(request.get());
@@ -284,7 +291,7 @@ class CertVerifierJob {
// Called on completion of the Job to log UMA metrics and NetLog events.
void LogMetrics(const ResultHelper& verify_result) {
net_log_.EndEvent(
- NetLog::TYPE_CERT_VERIFIER_JOB,
+ NetLogEventType::CERT_VERIFIER_JOB,
base::Bind(&CertVerifyResultCallback, verify_result.result));
base::TimeDelta latency = base::TimeTicks::Now() - start_time_;
UMA_HISTOGRAM_CUSTOM_TIMES("Net.CertVerifier_Job_Latency",
@@ -326,7 +333,7 @@ class CertVerifierJob {
RequestList requests_; // Non-owned.
- const BoundNetLog net_log_;
+ const NetLogWithSource net_log_;
MultiThreadedCertVerifier* cert_verifier_; // Non-owned.
bool is_first_job_;
@@ -338,7 +345,7 @@ MultiThreadedCertVerifier::MultiThreadedCertVerifier(
: requests_(0), inflight_joins_(0), verify_proc_(verify_proc) {}
MultiThreadedCertVerifier::~MultiThreadedCertVerifier() {
- STLDeleteElements(&inflight_);
+ base::STLDeleteElements(&inflight_);
}
int MultiThreadedCertVerifier::Verify(const RequestParams& params,
@@ -346,7 +353,7 @@ int MultiThreadedCertVerifier::Verify(const RequestParams& params,
CertVerifyResult* verify_result,
const CompletionCallback& callback,
std::unique_ptr<Request>* out_req,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
out_req->reset();
DCHECK(CalledOnValidThread());
diff --git a/chromium/net/cert/multi_threaded_cert_verifier.h b/chromium/net/cert/multi_threaded_cert_verifier.h
index f1c4af3a42f..d30d1fbd5d0 100644
--- a/chromium/net/cert/multi_threaded_cert_verifier.h
+++ b/chromium/net/cert/multi_threaded_cert_verifier.h
@@ -46,7 +46,7 @@ class NET_EXPORT_PRIVATE MultiThreadedCertVerifier
CertVerifyResult* verify_result,
const CompletionCallback& callback,
std::unique_ptr<Request>* out_req,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
bool SupportsOCSPStapling() override;
diff --git a/chromium/net/cert/multi_threaded_cert_verifier_unittest.cc b/chromium/net/cert/multi_threaded_cert_verifier_unittest.cc
index d57ec06faae..1c1dbe43f31 100644
--- a/chromium/net/cert/multi_threaded_cert_verifier_unittest.cc
+++ b/chromium/net/cert/multi_threaded_cert_verifier_unittest.cc
@@ -16,11 +16,16 @@
#include "net/cert/cert_verify_proc.h"
#include "net/cert/cert_verify_result.h"
#include "net/cert/x509_certificate.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -83,14 +88,15 @@ TEST_F(MultiThreadedCertVerifierTest, InflightJoin) {
error = verifier_.Verify(
CertVerifier::RequestParams(test_cert, "www.example.com", 0,
std::string(), CertificateList()),
- NULL, &verify_result, callback.callback(), &request, BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, error);
+ NULL, &verify_result, callback.callback(), &request, NetLogWithSource());
+ ASSERT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request);
error = verifier_.Verify(
CertVerifier::RequestParams(test_cert, "www.example.com", 0,
std::string(), CertificateList()),
- NULL, &verify_result2, callback2.callback(), &request2, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, error);
+ NULL, &verify_result2, callback2.callback(), &request2,
+ NetLogWithSource());
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request2);
error = callback.WaitForResult();
EXPECT_TRUE(IsCertificateError(error));
@@ -114,8 +120,9 @@ TEST_F(MultiThreadedCertVerifierTest, CancelRequest) {
error = verifier_.Verify(
CertVerifier::RequestParams(test_cert, "www.example.com", 0,
std::string(), CertificateList()),
- NULL, &verify_result, base::Bind(&FailTest), &request, BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, error);
+ NULL, &verify_result, base::Bind(&FailTest), &request,
+ NetLogWithSource());
+ ASSERT_THAT(error, IsError(ERR_IO_PENDING));
ASSERT_TRUE(request);
request.reset();
@@ -127,8 +134,9 @@ TEST_F(MultiThreadedCertVerifierTest, CancelRequest) {
error = verifier_.Verify(
CertVerifier::RequestParams(test_cert, "www2.example.com", 0,
std::string(), CertificateList()),
- NULL, &verify_result, callback.callback(), &request, BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, error);
+ NULL, &verify_result, callback.callback(), &request,
+ NetLogWithSource());
+ ASSERT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request);
error = callback.WaitForResult();
}
@@ -157,9 +165,10 @@ TEST_F(MultiThreadedCertVerifierTest, CancelRequestThenQuit) {
error = verifier_.Verify(
CertVerifier::RequestParams(test_cert, "www.example.com", 0,
std::string(), CertificateList()),
- NULL, &verify_result, callback.callback(), &request, BoundNetLog());
+ NULL, &verify_result, callback.callback(), &request,
+ NetLogWithSource());
}
- ASSERT_EQ(ERR_IO_PENDING, error);
+ ASSERT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request);
request.reset();
// Destroy |verifier| by going out of scope.
@@ -198,37 +207,42 @@ TEST_F(MultiThreadedCertVerifierTest, MultipleInflightJoin) {
error = verifier_.Verify(
CertVerifier::RequestParams(test_cert, domain2, 0, std::string(),
CertificateList()),
- nullptr, &verify_result1, callback1.callback(), &request1, BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, error);
+ nullptr, &verify_result1, callback1.callback(), &request1,
+ NetLogWithSource());
+ ASSERT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request1);
error = verifier_.Verify(
CertVerifier::RequestParams(test_cert, domain2, 0, std::string(),
CertificateList()),
- nullptr, &verify_result2, callback2.callback(), &request2, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, error);
+ nullptr, &verify_result2, callback2.callback(), &request2,
+ NetLogWithSource());
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request2);
error = verifier_.Verify(
CertVerifier::RequestParams(test_cert, domain3, 0, std::string(),
CertificateList()),
- nullptr, &verify_result3, callback3.callback(), &request3, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, error);
+ nullptr, &verify_result3, callback3.callback(), &request3,
+ NetLogWithSource());
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request3);
// Start duplicate requests (which should join to existing jobs).
error = verifier_.Verify(
CertVerifier::RequestParams(test_cert, domain1, 0, std::string(),
CertificateList()),
- nullptr, &verify_result4, callback4.callback(), &request4, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, error);
+ nullptr, &verify_result4, callback4.callback(), &request4,
+ NetLogWithSource());
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request4);
error = verifier_.Verify(
CertVerifier::RequestParams(test_cert, domain2, 0, std::string(),
CertificateList()),
- nullptr, &verify_result5, callback5.callback(), &request5, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, error);
+ nullptr, &verify_result5, callback5.callback(), &request5,
+ NetLogWithSource());
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request5);
error = callback1.WaitForResult();
diff --git a/chromium/net/cert/nss_cert_database_unittest.cc b/chromium/net/cert/nss_cert_database_unittest.cc
index 3f66b565301..9e20f886def 100644
--- a/chromium/net/cert/nss_cert_database_unittest.cc
+++ b/chromium/net/cert/nss_cert_database_unittest.cc
@@ -30,10 +30,15 @@
#include "net/cert/cert_verify_result.h"
#include "net/cert/x509_certificate.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
#include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
// In NSS 3.13, CERTDB_VALID_PEER was renamed CERTDB_TERMINAL_RECORD. So we use
// the new name of the macro.
#if !defined(CERTDB_TERMINAL_RECORD)
@@ -390,7 +395,7 @@ TEST_F(CertDatabaseNSSTest, ImportCA_NotCACert) {
// ImportCACerts returns the same pointers that were passed in. In the
// general case IsSameOSCert should be used.
EXPECT_EQ(certs[0], failed[0].certificate);
- EXPECT_EQ(ERR_IMPORT_CA_CERT_NOT_CA, failed[0].net_error);
+ EXPECT_THAT(failed[0].net_error, IsError(ERR_IMPORT_CA_CERT_NOT_CA));
EXPECT_EQ(0U, ListCerts().size());
}
@@ -413,9 +418,10 @@ TEST_F(CertDatabaseNSSTest, ImportCACertHierarchy) {
ASSERT_EQ(2U, failed.size());
EXPECT_EQ("DOD CA-17", failed[0].certificate->subject().common_name);
- EXPECT_EQ(ERR_FAILED, failed[0].net_error); // The certificate expired.
+ EXPECT_THAT(failed[0].net_error,
+ IsError(ERR_FAILED)); // The certificate expired.
EXPECT_EQ("www.us.army.mil", failed[1].certificate->subject().common_name);
- EXPECT_EQ(ERR_IMPORT_CA_CERT_NOT_CA, failed[1].net_error);
+ EXPECT_THAT(failed[1].net_error, IsError(ERR_IMPORT_CA_CERT_NOT_CA));
CertificateList cert_list = ListCerts();
ASSERT_EQ(1U, cert_list.size());
@@ -449,11 +455,12 @@ TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyDupeRoot) {
ASSERT_EQ(3U, failed.size());
EXPECT_EQ("DoD Root CA 2", failed[0].certificate->subject().common_name);
- EXPECT_EQ(ERR_IMPORT_CERT_ALREADY_EXISTS, failed[0].net_error);
+ EXPECT_THAT(failed[0].net_error, IsError(ERR_IMPORT_CERT_ALREADY_EXISTS));
EXPECT_EQ("DOD CA-17", failed[1].certificate->subject().common_name);
- EXPECT_EQ(ERR_FAILED, failed[1].net_error); // The certificate expired.
+ EXPECT_THAT(failed[1].net_error,
+ IsError(ERR_FAILED)); // The certificate expired.
EXPECT_EQ("www.us.army.mil", failed[2].certificate->subject().common_name);
- EXPECT_EQ(ERR_IMPORT_CA_CERT_NOT_CA, failed[2].net_error);
+ EXPECT_THAT(failed[2].net_error, IsError(ERR_IMPORT_CA_CERT_NOT_CA));
cert_list = ListCerts();
ASSERT_EQ(1U, cert_list.size());
@@ -474,7 +481,7 @@ TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyUntrusted) {
EXPECT_EQ("DOD CA-17", failed[0].certificate->subject().common_name);
// TODO(mattm): should check for net error equivalent of
// SEC_ERROR_UNTRUSTED_ISSUER
- EXPECT_EQ(ERR_FAILED, failed[0].net_error);
+ EXPECT_THAT(failed[0].net_error, IsError(ERR_FAILED));
CertificateList cert_list = ListCerts();
ASSERT_EQ(1U, cert_list.size());
@@ -495,9 +502,11 @@ TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyTree) {
EXPECT_EQ(2U, failed.size());
EXPECT_EQ("DOD CA-13", failed[0].certificate->subject().common_name);
- EXPECT_EQ(ERR_FAILED, failed[0].net_error); // The certificate expired.
+ EXPECT_THAT(failed[0].net_error,
+ IsError(ERR_FAILED)); // The certificate expired.
EXPECT_EQ("DOD CA-17", failed[1].certificate->subject().common_name);
- EXPECT_EQ(ERR_FAILED, failed[1].net_error); // The certificate expired.
+ EXPECT_THAT(failed[1].net_error,
+ IsError(ERR_FAILED)); // The certificate expired.
CertificateList cert_list = ListCerts();
ASSERT_EQ(1U, cert_list.size());
@@ -522,9 +531,9 @@ TEST_F(CertDatabaseNSSTest, ImportCACertNotHierarchy) {
// TODO(mattm): should check for net error equivalent of
// SEC_ERROR_UNKNOWN_ISSUER
EXPECT_EQ("DOD CA-13", failed[0].certificate->subject().common_name);
- EXPECT_EQ(ERR_FAILED, failed[0].net_error);
+ EXPECT_THAT(failed[0].net_error, IsError(ERR_FAILED));
EXPECT_EQ("DOD CA-17", failed[1].certificate->subject().common_name);
- EXPECT_EQ(ERR_FAILED, failed[1].net_error);
+ EXPECT_THAT(failed[1].net_error, IsError(ERR_FAILED));
CertificateList cert_list = ListCerts();
ASSERT_EQ(1U, cert_list.size());
@@ -566,7 +575,7 @@ TEST_F(CertDatabaseNSSTest, DISABLED_ImportServerCert) {
int error =
verify_proc->Verify(goog_cert.get(), "www.google.com", std::string(),
flags, NULL, empty_cert_list_, &verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(0U, verify_result.cert_status);
}
@@ -594,7 +603,7 @@ TEST_F(CertDatabaseNSSTest, ImportServerCert_SelfSigned) {
int error =
verify_proc->Verify(puny_cert.get(), "xn--wgv71a119e.com", std::string(),
flags, NULL, empty_cert_list_, &verify_result);
- EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result.cert_status);
}
@@ -623,7 +632,7 @@ TEST_F(CertDatabaseNSSTest, ImportServerCert_SelfSigned_Trusted) {
int error =
verify_proc->Verify(puny_cert.get(), "xn--wgv71a119e.com", std::string(),
flags, NULL, empty_cert_list_, &verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(0U, verify_result.cert_status);
}
@@ -656,7 +665,7 @@ TEST_F(CertDatabaseNSSTest, ImportCaAndServerCert) {
int error =
verify_proc->Verify(certs[0].get(), "127.0.0.1", std::string(), flags,
NULL, empty_cert_list_, &verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(0U, verify_result.cert_status);
}
@@ -695,7 +704,7 @@ TEST_F(CertDatabaseNSSTest, ImportCaAndServerCert_DistrustServer) {
int error =
verify_proc->Verify(certs[0].get(), "127.0.0.1", std::string(), flags,
NULL, empty_cert_list_, &verify_result);
- EXPECT_EQ(ERR_CERT_REVOKED, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_REVOKED));
EXPECT_EQ(CERT_STATUS_REVOKED, verify_result.cert_status);
}
@@ -740,7 +749,7 @@ TEST_F(CertDatabaseNSSTest, TrustIntermediateCa) {
int error =
verify_proc->Verify(certs[0].get(), "127.0.0.1", std::string(), flags,
NULL, empty_cert_list_, &verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(0U, verify_result.cert_status);
// Trust the root cert and distrust the intermediate.
@@ -767,7 +776,7 @@ TEST_F(CertDatabaseNSSTest, TrustIntermediateCa) {
CertVerifyResult verify_result2;
error = verify_proc->Verify(certs[0].get(), "127.0.0.1", std::string(), flags,
NULL, empty_cert_list_, &verify_result2);
- EXPECT_EQ(ERR_CERT_REVOKED, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_REVOKED));
EXPECT_EQ(CERT_STATUS_REVOKED, verify_result2.cert_status);
}
@@ -809,7 +818,7 @@ TEST_F(CertDatabaseNSSTest, TrustIntermediateCa2) {
int error =
verify_proc->Verify(certs[0].get(), "127.0.0.1", std::string(), flags,
NULL, empty_cert_list_, &verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(0U, verify_result.cert_status);
// Without explicit trust of the intermediate, verification should fail.
@@ -820,7 +829,7 @@ TEST_F(CertDatabaseNSSTest, TrustIntermediateCa2) {
CertVerifyResult verify_result2;
error = verify_proc->Verify(certs[0].get(), "127.0.0.1", std::string(), flags,
NULL, empty_cert_list_, &verify_result2);
- EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result2.cert_status);
}
@@ -872,7 +881,7 @@ TEST_F(CertDatabaseNSSTest, TrustIntermediateCa3) {
int error =
verify_proc->Verify(certs[0].get(), "127.0.0.1", std::string(), flags,
NULL, empty_cert_list_, &verify_result);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(0U, verify_result.cert_status);
// Without explicit trust of the intermediate, verification should fail.
@@ -883,7 +892,7 @@ TEST_F(CertDatabaseNSSTest, TrustIntermediateCa3) {
CertVerifyResult verify_result2;
error = verify_proc->Verify(certs[0].get(), "127.0.0.1", std::string(), flags,
NULL, empty_cert_list_, &verify_result2);
- EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result2.cert_status);
}
@@ -929,7 +938,7 @@ TEST_F(CertDatabaseNSSTest, TrustIntermediateCa4) {
int error =
verify_proc->Verify(certs[0].get(), "127.0.0.1", std::string(), flags,
NULL, empty_cert_list_, &verify_result);
- EXPECT_EQ(ERR_CERT_REVOKED, error);
+ EXPECT_THAT(error, IsError(ERR_CERT_REVOKED));
EXPECT_EQ(CERT_STATUS_REVOKED, verify_result.cert_status);
// Without explicit distrust of the intermediate, verification should succeed.
@@ -940,7 +949,7 @@ TEST_F(CertDatabaseNSSTest, TrustIntermediateCa4) {
CertVerifyResult verify_result2;
error = verify_proc->Verify(certs[0].get(), "127.0.0.1", std::string(), flags,
NULL, empty_cert_list_, &verify_result2);
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(0U, verify_result2.cert_status);
}
diff --git a/chromium/net/cert/ocsp_revocation_status.h b/chromium/net/cert/ocsp_revocation_status.h
new file mode 100644
index 00000000000..945104f26f6
--- /dev/null
+++ b/chromium/net/cert/ocsp_revocation_status.h
@@ -0,0 +1,18 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_CERT_OCSP_REVOCATION_STATUS_H
+#define NET_CERT_OCSP_REVOCATION_STATUS_H
+
+namespace net {
+
+enum class OCSPRevocationStatus {
+ GOOD,
+ REVOKED,
+ UNKNOWN,
+};
+
+} // namespace net
+
+#endif // NET_CERT_OCSP_REVOCATION_STATUS_H
diff --git a/chromium/net/cert/ocsp_verify_result.cc b/chromium/net/cert/ocsp_verify_result.cc
new file mode 100644
index 00000000000..35069e711d3
--- /dev/null
+++ b/chromium/net/cert/ocsp_verify_result.cc
@@ -0,0 +1,24 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/ocsp_verify_result.h"
+
+namespace net {
+
+OCSPVerifyResult::OCSPVerifyResult() = default;
+OCSPVerifyResult::OCSPVerifyResult(const OCSPVerifyResult&) = default;
+OCSPVerifyResult::~OCSPVerifyResult() = default;
+
+bool OCSPVerifyResult::operator==(const OCSPVerifyResult& other) const {
+ if (response_status != other.response_status)
+ return false;
+
+ if (response_status == PROVIDED) {
+ // |revocation_status| is only defined when |response_status| is PROVIDED.
+ return revocation_status == other.revocation_status;
+ }
+ return true;
+}
+
+} // namespace net
diff --git a/chromium/net/cert/ocsp_verify_result.h b/chromium/net/cert/ocsp_verify_result.h
new file mode 100644
index 00000000000..a2b8494b277
--- /dev/null
+++ b/chromium/net/cert/ocsp_verify_result.h
@@ -0,0 +1,68 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_CERT_OCSP_VERIFY_RESULT_H
+#define NET_CERT_OCSP_VERIFY_RESULT_H
+
+#include <string>
+
+#include "net/base/net_export.h"
+#include "net/cert/ocsp_revocation_status.h"
+
+namespace net {
+
+// The result of OCSP verification. This always contains a ResponseStatus, which
+// describes whether or not an OCSP response was provided, and response level
+// errors. It optionally contains an OCSPRevocationStatus when |response_status
+// = PROVIDED|. For example, a stapled OCSP response matching the certificate,
+// and indicating a non-revoked status, will have |response_status = PROVIDED|
+// and |revocation_status = GOOD|. This is populated as part of the certificate
+// verification process, and should not be modified at other layers.
+struct NET_EXPORT OCSPVerifyResult {
+ OCSPVerifyResult();
+ OCSPVerifyResult(const OCSPVerifyResult&);
+ ~OCSPVerifyResult();
+
+ bool operator==(const OCSPVerifyResult& other) const;
+
+ enum ResponseStatus {
+ // No OCSPResponse was stapled.
+ MISSING,
+
+ // An up-to-date OCSP response was stapled and matched the certificate.
+ PROVIDED,
+
+ // The stapled OCSP response did not have a SUCCESSFUL status.
+ ERROR_RESPONSE,
+
+ // The OCSPResponseData field producedAt was outside the certificate
+ // validity period.
+ BAD_PRODUCED_AT,
+
+ // At least one OCSPSingleResponse was stapled, but none matched the
+ // certificate.
+ NO_MATCHING_RESPONSE,
+
+ // A matching OCSPSingleResponse was stapled, but was either expired or not
+ // yet valid.
+ INVALID_DATE,
+
+ // The OCSPResponse structure could not be parsed.
+ PARSE_RESPONSE_ERROR,
+
+ // The OCSPResponseData structure could not be parsed.
+ PARSE_RESPONSE_DATA_ERROR,
+
+ };
+
+ ResponseStatus response_status = MISSING;
+
+ // The strictest CertStatus matching the certificate (REVOKED > UNKNOWN >
+ // GOOD). Only valid if |response_status| = PROVIDED.
+ OCSPRevocationStatus revocation_status = OCSPRevocationStatus::UNKNOWN;
+};
+
+} // namespace net
+
+#endif // NET_CERT_OCSP_VERIFY_RESULT_H
diff --git a/chromium/net/cert/sct_status_flags.cc b/chromium/net/cert/sct_status_flags.cc
new file mode 100644
index 00000000000..a8f070a7298
--- /dev/null
+++ b/chromium/net/cert/sct_status_flags.cc
@@ -0,0 +1,27 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/sct_status_flags.h"
+
+namespace net {
+
+namespace ct {
+
+bool IsValidSCTStatus(uint32_t status) {
+ switch (status) {
+ case net::ct::SCT_STATUS_LOG_UNKNOWN:
+ case net::ct::SCT_STATUS_INVALID_SIGNATURE:
+ case net::ct::SCT_STATUS_OK:
+ case net::ct::SCT_STATUS_INVALID_TIMESTAMP:
+ return true;
+ case net::ct::SCT_STATUS_NONE:
+ return false;
+ }
+
+ return false;
+}
+
+} // namespace ct
+
+} // namespace net
diff --git a/chromium/net/cert/sct_status_flags.h b/chromium/net/cert/sct_status_flags.h
index 123c25c8905..86daa0c5925 100644
--- a/chromium/net/cert/sct_status_flags.h
+++ b/chromium/net/cert/sct_status_flags.h
@@ -5,6 +5,10 @@
#ifndef NET_CERT_SCT_STATUS_FLAGS_H_
#define NET_CERT_SCT_STATUS_FLAGS_H_
+#include <stdint.h>
+
+#include "net/base/net_export.h"
+
namespace net {
namespace ct {
@@ -12,7 +16,7 @@ namespace ct {
// The possible verification statuses for a SignedCertificateTimestamp.
// Note: The numeric values are used within histograms and should not change
// or be re-assigned.
-enum SCTVerifyStatus {
+enum SCTVerifyStatus : uint32_t {
// Not a real status, this just prevents a default int value from being
// mis-interpreseted as a valid status.
// Also used to count SCTs that cannot be decoded in the histogram.
@@ -21,16 +25,27 @@ enum SCTVerifyStatus {
// The SCT is from an unknown log, so we cannot verify its signature.
SCT_STATUS_LOG_UNKNOWN = 1,
- // The SCT is from a known log, but the signature is invalid.
- SCT_STATUS_INVALID = 2,
+ // Obsolete. Kept here to avoid reuse.
+ // SCT_STATUS_INVALID = 2,
// The SCT is from a known log, and the signature is valid.
SCT_STATUS_OK = 3,
- // Used to bound the enum values.
- SCT_STATUS_MAX,
+ // The SCT is from a known log, but the signature is invalid.
+ SCT_STATUS_INVALID_SIGNATURE = 4,
+
+ // The SCT is from a known log, but the timestamp is in the future.
+ SCT_STATUS_INVALID_TIMESTAMP = 5,
+
+ // Used to bound the enum values. Since this enum is passed over IPC,
+ // the last value must be a valid one (rather than one past a valid one).
+ SCT_STATUS_MAX = SCT_STATUS_INVALID_TIMESTAMP,
};
+// Returns true if |status| denotes a valid value in SCTVerifyStatus, which
+// is all current values in the enum except SCT_STATUS_NONE.
+NET_EXPORT bool IsValidSCTStatus(uint32_t status);
+
} // namespace ct
} // namespace net
diff --git a/chromium/net/cert/signed_certificate_timestamp.cc b/chromium/net/cert/signed_certificate_timestamp.cc
index f5f9c946481..489c88c6c19 100644
--- a/chromium/net/cert/signed_certificate_timestamp.cc
+++ b/chromium/net/cert/signed_certificate_timestamp.cc
@@ -28,7 +28,8 @@ bool SignedCertificateTimestamp::LessThan::operator()(
return lhs->version < rhs->version;
}
-SignedCertificateTimestamp::SignedCertificateTimestamp() {}
+SignedCertificateTimestamp::SignedCertificateTimestamp()
+ : version(V1), origin(SCT_EMBEDDED) {}
SignedCertificateTimestamp::~SignedCertificateTimestamp() {}
@@ -77,7 +78,7 @@ SignedCertificateTimestamp::CreateFromPickle(base::PickleIterator* iter) {
return sct;
}
-LogEntry::LogEntry() {}
+LogEntry::LogEntry() : type(LOG_ENTRY_TYPE_X509) {}
LogEntry::~LogEntry() {}
@@ -87,7 +88,8 @@ void LogEntry::Reset() {
tbs_certificate.clear();
}
-DigitallySigned::DigitallySigned() {}
+DigitallySigned::DigitallySigned()
+ : hash_algorithm(HASH_ALGO_NONE), signature_algorithm(SIG_ALGO_ANONYMOUS) {}
DigitallySigned::~DigitallySigned() {}
diff --git a/chromium/net/cert/signed_certificate_timestamp_and_status.cc b/chromium/net/cert/signed_certificate_timestamp_and_status.cc
new file mode 100644
index 00000000000..364bb2c1e1b
--- /dev/null
+++ b/chromium/net/cert/signed_certificate_timestamp_and_status.cc
@@ -0,0 +1,23 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/signed_certificate_timestamp_and_status.h"
+
+#include "net/cert/signed_certificate_timestamp.h"
+
+namespace net {
+
+SignedCertificateTimestampAndStatus::SignedCertificateTimestampAndStatus() {}
+
+SignedCertificateTimestampAndStatus::SignedCertificateTimestampAndStatus(
+ const scoped_refptr<ct::SignedCertificateTimestamp>& sct,
+ const ct::SCTVerifyStatus status)
+ : sct(sct), status(status) {}
+
+SignedCertificateTimestampAndStatus::SignedCertificateTimestampAndStatus(
+ const SignedCertificateTimestampAndStatus& other) = default;
+
+SignedCertificateTimestampAndStatus::~SignedCertificateTimestampAndStatus() {}
+
+} // namespace net
diff --git a/chromium/net/cert/signed_certificate_timestamp_and_status.h b/chromium/net/cert/signed_certificate_timestamp_and_status.h
new file mode 100644
index 00000000000..51cc06dd719
--- /dev/null
+++ b/chromium/net/cert/signed_certificate_timestamp_and_status.h
@@ -0,0 +1,38 @@
+// Copyright 2013 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_CERT_SIGNED_CERTIFICATE_TIMESTAMP_AND_STATUS_H_
+#define NET_CERT_SIGNED_CERTIFICATE_TIMESTAMP_AND_STATUS_H_
+
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "net/base/net_export.h"
+#include "net/cert/sct_status_flags.h"
+#include "net/cert/signed_certificate_timestamp.h"
+
+namespace net {
+
+struct NET_EXPORT SignedCertificateTimestampAndStatus {
+ SignedCertificateTimestampAndStatus();
+
+ SignedCertificateTimestampAndStatus(
+ const scoped_refptr<ct::SignedCertificateTimestamp>& sct,
+ ct::SCTVerifyStatus status);
+
+ SignedCertificateTimestampAndStatus(
+ const SignedCertificateTimestampAndStatus& other);
+
+ ~SignedCertificateTimestampAndStatus();
+
+ scoped_refptr<ct::SignedCertificateTimestamp> sct;
+ ct::SCTVerifyStatus status;
+};
+
+typedef std::vector<SignedCertificateTimestampAndStatus>
+ SignedCertificateTimestampAndStatusList;
+
+} // namespace net
+
+#endif // NET_CERT_SIGNED_CERTIFICATE_TIMESTAMP_AND_STATUS_H_
diff --git a/chromium/net/cert/test_keychain_search_list_mac.cc b/chromium/net/cert/test_keychain_search_list_mac.cc
new file mode 100644
index 00000000000..c2fe00107a2
--- /dev/null
+++ b/chromium/net/cert/test_keychain_search_list_mac.cc
@@ -0,0 +1,55 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/test_keychain_search_list_mac.h"
+
+#include "base/memory/ptr_util.h"
+
+namespace net {
+
+namespace {
+
+TestKeychainSearchList* g_test_keychain_search_list = nullptr;
+
+} // namespace
+
+TestKeychainSearchList::TestKeychainSearchList() {
+ g_test_keychain_search_list = this;
+ scoped_keychain_search_list.reset(
+ CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
+}
+
+TestKeychainSearchList::~TestKeychainSearchList() {
+ g_test_keychain_search_list = nullptr;
+}
+
+// static
+std::unique_ptr<TestKeychainSearchList> TestKeychainSearchList::Create() {
+ if (g_test_keychain_search_list)
+ return nullptr;
+ return base::WrapUnique(new TestKeychainSearchList);
+}
+
+// static
+bool TestKeychainSearchList::HasInstance() {
+ return !!g_test_keychain_search_list;
+}
+
+// static
+TestKeychainSearchList* TestKeychainSearchList::GetInstance() {
+ return g_test_keychain_search_list;
+}
+
+OSStatus TestKeychainSearchList::CopySearchList(
+ CFArrayRef* keychain_search_list) const {
+ *keychain_search_list =
+ CFArrayCreateCopy(kCFAllocatorDefault, scoped_keychain_search_list.get());
+ return *keychain_search_list ? 0 : errSecAllocate;
+}
+
+void TestKeychainSearchList::AddKeychain(SecKeychainRef keychain) {
+ CFArrayAppendValue(scoped_keychain_search_list.get(), keychain);
+}
+
+} // namespace net
diff --git a/chromium/net/cert/test_keychain_search_list_mac.h b/chromium/net/cert/test_keychain_search_list_mac.h
new file mode 100644
index 00000000000..d0faffdbf54
--- /dev/null
+++ b/chromium/net/cert/test_keychain_search_list_mac.h
@@ -0,0 +1,46 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_CERT_KEYCHAIN_SEARCH_LIST_MAC_H_
+#define NET_CERT_KEYCHAIN_SEARCH_LIST_MAC_H_
+
+#include <CoreServices/CoreServices.h>
+#include <Security/Security.h>
+
+#include "base/mac/scoped_cftyperef.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+class NET_EXPORT TestKeychainSearchList {
+ public:
+ ~TestKeychainSearchList();
+
+ // Creates a TestKeychainSearchList, which will be used by HasInstance and
+ // GetInstance.
+ // Only one TestKeychainSearchList object may exist at a time, returns nullptr
+ // if one exists already.
+ static std::unique_ptr<TestKeychainSearchList> Create();
+
+ // Returns true if a TestKeychainSearchList currently exists.
+ static bool HasInstance();
+
+ // Returns the current TestKeychainSearchList instance, if any.
+ static TestKeychainSearchList* GetInstance();
+
+ // Copies the test keychain search list into |keychain_search_list|.
+ OSStatus CopySearchList(CFArrayRef* keychain_search_list) const;
+
+ // Adds |keychain| to the end of the test keychain search list.
+ void AddKeychain(SecKeychainRef keychain);
+
+ private:
+ TestKeychainSearchList();
+
+ base::ScopedCFTypeRef<CFMutableArrayRef> scoped_keychain_search_list;
+};
+
+} // namespace net
+
+#endif // NET_CERT_KEYCHAIN_SEARCH_LIST_MAC_H_
diff --git a/chromium/net/cert/test_root_certs.cc b/chromium/net/cert/test_root_certs.cc
index c39c4b49ee2..c5f777ed619 100644
--- a/chromium/net/cert/test_root_certs.cc
+++ b/chromium/net/cert/test_root_certs.cc
@@ -9,6 +9,7 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
#include "net/cert/x509_certificate.h"
namespace net {
@@ -43,6 +44,7 @@ bool TestRootCerts::HasInstance() {
}
bool TestRootCerts::AddFromFile(const base::FilePath& file) {
+ base::ThreadRestrictions::ScopedAllowIO allow_io_for_loading_test_certs;
CertificateList root_certs = LoadCertificates(file);
if (root_certs.empty() || root_certs.size() > 1)
return false;
diff --git a/chromium/net/cert/test_root_certs_nss.cc b/chromium/net/cert/test_root_certs_nss.cc
index bcd4add1e86..99ca63491c9 100644
--- a/chromium/net/cert/test_root_certs_nss.cc
+++ b/chromium/net/cert/test_root_certs_nss.cc
@@ -108,7 +108,7 @@ void TestRootCerts::Clear() {
// occur after Clear() has been called.
DCHECK_EQ(SECSuccess, rv) << "Cannot restore certificate trust.";
}
- STLDeleteElements(&trust_cache_);
+ base::STLDeleteElements(&trust_cache_);
}
bool TestRootCerts::IsEmpty() const {
diff --git a/chromium/net/cert/test_root_certs_unittest.cc b/chromium/net/cert/test_root_certs_unittest.cc
index f9e1e0eb183..b08926f3b93 100644
--- a/chromium/net/cert/test_root_certs_unittest.cc
+++ b/chromium/net/cert/test_root_certs_unittest.cc
@@ -11,13 +11,17 @@
#include "net/cert/test_root_certs.h"
#include "net/cert/x509_certificate.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(USE_NSS_CERTS)
#include <nss.h>
#endif
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -105,7 +109,7 @@ TEST(TestRootCertsTest, OverrideTrust) {
int good_status =
verify_proc->Verify(test_cert.get(), "127.0.0.1", std::string(), flags,
NULL, CertificateList(), &good_verify_result);
- EXPECT_EQ(OK, good_status);
+ EXPECT_THAT(good_status, IsOk());
EXPECT_EQ(0u, good_verify_result.cert_status);
test_roots->Clear();
diff --git a/chromium/net/cert/x509_certificate_net_log_param.cc b/chromium/net/cert/x509_certificate_net_log_param.cc
index b056388eb08..d1cebd0f9c0 100644
--- a/chromium/net/cert/x509_certificate_net_log_param.cc
+++ b/chromium/net/cert/x509_certificate_net_log_param.cc
@@ -11,6 +11,7 @@
#include "base/values.h"
#include "net/cert/x509_certificate.h"
+#include "net/log/net_log_capture_mode.h"
namespace net {
diff --git a/chromium/net/cert/x509_certificate_net_log_param.h b/chromium/net/cert/x509_certificate_net_log_param.h
index 8f073b98629..01b46f95b15 100644
--- a/chromium/net/cert/x509_certificate_net_log_param.h
+++ b/chromium/net/cert/x509_certificate_net_log_param.h
@@ -7,10 +7,13 @@
#include <memory>
-#include "net/log/net_log.h"
+namespace base {
+class Value;
+}
namespace net {
+class NetLogCaptureMode;
class X509Certificate;
// Creates NetLog parameter to describe an X509Certificate.
diff --git a/chromium/net/cert/x509_certificate_openssl.cc b/chromium/net/cert/x509_certificate_openssl.cc
index c2bd6aa53a6..e22ea9f099d 100644
--- a/chromium/net/cert/x509_certificate_openssl.cc
+++ b/chromium/net/cert/x509_certificate_openssl.cc
@@ -180,7 +180,8 @@ void sk_X509_NAME_free_all(STACK_OF(X509_NAME)* sk) {
X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
OSCertHandle cert_handle) {
DCHECK(cert_handle);
- return X509_up_ref(cert_handle);
+ X509_up_ref(cert_handle);
+ return cert_handle;
}
// static
diff --git a/chromium/net/cert/x509_util.cc b/chromium/net/cert/x509_util.cc
index 51e7b6ac176..35913c19d2b 100644
--- a/chromium/net/cert/x509_util.cc
+++ b/chromium/net/cert/x509_util.cc
@@ -10,12 +10,47 @@
#include "crypto/ec_private_key.h"
#include "crypto/rsa_private_key.h"
#include "net/base/hash_value.h"
+#include "net/cert/internal/name_constraints.h"
#include "net/cert/internal/parse_certificate.h"
+#include "net/cert/internal/parse_name.h"
#include "net/cert/internal/signature_algorithm.h"
#include "net/cert/x509_certificate.h"
+#include "net/der/input.h"
+#include "net/der/parse_values.h"
namespace net {
+namespace {
+
+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.ValueAsStringUnsafe(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);
+}
+
+} // namespace
+
namespace x509_util {
// RSA keys created by CreateKeyAndSelfSignedCert will be of this length.
@@ -82,6 +117,59 @@ bool CreateKeyAndSelfSignedCert(const std::string& subject,
return success;
}
+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, ParseCertificateOptions(),
+ &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;
+
+ 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);
+ if (subject_alt_names) {
+ *dns_names = subject_alt_names->dns_names;
+ for (const auto& ip : subject_alt_names->ip_addresses)
+ ip_addresses->push_back(ip.ToString());
+ }
+ }
+
+ return true;
+}
+
} // namespace x509_util
} // namespace net
diff --git a/chromium/net/cert/x509_util.h b/chromium/net/cert/x509_util.h
index 3ae9a146d86..07f4e21b1d3 100644
--- a/chromium/net/cert/x509_util.h
+++ b/chromium/net/cert/x509_util.h
@@ -9,8 +9,10 @@
#include <memory>
#include <string>
+#include <vector>
#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "net/base/net_export.h"
@@ -73,6 +75,17 @@ 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);
+
// Comparator for use in STL algorithms that will sort client certificates by
// order of preference.
// Returns true if |a| is more preferable than |b|, allowing it to be used
diff --git a/chromium/net/cert/x509_util_android.cc b/chromium/net/cert/x509_util_android.cc
index ee47845f57e..b2219b1a5c5 100644
--- a/chromium/net/cert/x509_util_android.cc
+++ b/chromium/net/cert/x509_util_android.cc
@@ -10,6 +10,8 @@
#include "jni/X509Util_jni.h"
#include "net/cert/cert_database.h"
+using base::android::JavaParamRef;
+
namespace net {
void NotifyKeyChainChanged(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
diff --git a/chromium/net/cert/x509_util_mac.cc b/chromium/net/cert/x509_util_mac.cc
index 7971a733af0..f2ce0f3b4b4 100644
--- a/chromium/net/cert/x509_util_mac.cc
+++ b/chromium/net/cert/x509_util_mac.cc
@@ -5,6 +5,9 @@
#include "net/cert/x509_util_mac.h"
#include "base/logging.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/strings/sys_string_conversions.h"
#include "third_party/apple_apsl/cssmapplePriv.h"
namespace net {
@@ -51,36 +54,59 @@ OSStatus CreatePolicy(const CSSM_OID* policy_oid,
OSStatus CreateSSLClientPolicy(SecPolicyRef* policy) {
- CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options;
- memset(&tp_ssl_options, 0, sizeof(tp_ssl_options));
- tp_ssl_options.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
- tp_ssl_options.Flags |= CSSM_APPLE_TP_SSL_CLIENT;
-
- return CreatePolicy(&CSSMOID_APPLE_TP_SSL, &tp_ssl_options,
- sizeof(tp_ssl_options), policy);
+ *policy = SecPolicyCreateSSL(false /* server */, nullptr);
+ return *policy ? noErr : errSecNoPolicyModule;
}
OSStatus CreateSSLServerPolicy(const std::string& hostname,
SecPolicyRef* policy) {
- CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options;
- memset(&tp_ssl_options, 0, sizeof(tp_ssl_options));
- tp_ssl_options.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
+ base::ScopedCFTypeRef<CFStringRef> hostname_cfstring;
if (!hostname.empty()) {
- tp_ssl_options.ServerName = hostname.data();
- tp_ssl_options.ServerNameLen = hostname.size();
+ hostname_cfstring.reset(base::SysUTF8ToCFStringRef(hostname));
+ if (!hostname_cfstring)
+ return errSecNoPolicyModule;
}
- return CreatePolicy(&CSSMOID_APPLE_TP_SSL, &tp_ssl_options,
- sizeof(tp_ssl_options), policy);
+ *policy = SecPolicyCreateSSL(true /* server */, hostname_cfstring.get());
+ return *policy ? noErr : errSecNoPolicyModule;
}
OSStatus CreateBasicX509Policy(SecPolicyRef* policy) {
- return CreatePolicy(&CSSMOID_APPLE_X509_BASIC, NULL, 0, policy);
+ *policy = SecPolicyCreateBasicX509();
+ return *policy ? noErr : errSecNoPolicyModule;
}
OSStatus CreateRevocationPolicies(bool enable_revocation_checking,
- bool enable_ev_checking,
CFMutableArrayRef policies) {
+ if (base::mac::IsAtLeastOS10_12()) {
+// SecPolicyCreateRevocation is only on 10.9 or newer. This pragma stops
+// clang from complaining about it.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
+ // On Sierra, it's not possible to disable network revocation checking
+ // without also breaking AIA. If revocation checking isn't explicitly
+ // enabled, just don't add a revocation policy.
+ if (!enable_revocation_checking)
+ return noErr;
+
+ // If revocation checking is requested, enable checking and require positive
+ // results. Note that this will fail if there are certs with no
+ // CRLDistributionPoints or OCSP AIA urls, which differs from the behavior
+ // of |enable_revocation_checking| on pre-10.12. There does not appear to be
+ // a way around this, but it shouldn't matter much in practice since
+ // revocation checking is generally used with EV certs, where it is expected
+ // that all certs include revocation mechanisms.
+ SecPolicyRef revocation_policy =
+ SecPolicyCreateRevocation(kSecRevocationUseAnyAvailableMethod |
+ kSecRevocationRequirePositiveResponse);
+
+ if (!revocation_policy)
+ return errSecNoPolicyModule;
+ CFArrayAppendValue(policies, revocation_policy);
+ CFRelease(revocation_policy);
+#pragma clang diagnostic pop
+ return noErr;
+ }
OSStatus status = noErr;
// In order to bypass the system revocation checking settings, the
@@ -92,7 +118,7 @@ OSStatus CreateRevocationPolicies(bool enable_revocation_checking,
// OCSP policy to perform the online checking, and if it doesn't believe
// that the leaf is EV, then the default CRL policy will effectively no-op.
// This behaviour is used to implement EV-only revocation checking.
- if (enable_ev_checking || enable_revocation_checking) {
+ if (enable_revocation_checking) {
CSSM_APPLE_TP_CRL_OPTIONS tp_crl_options;
memset(&tp_crl_options, 0, sizeof(tp_crl_options));
tp_crl_options.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION;
@@ -100,8 +126,9 @@ OSStatus CreateRevocationPolicies(bool enable_revocation_checking,
// online revocation checking. Note that, as of OS X 10.7.2, the system
// will set force this flag on according to system policies, so
// online revocation checks cannot be completely disabled.
- if (enable_revocation_checking)
- tp_crl_options.CrlFlags = CSSM_TP_ACTION_FETCH_CRL_FROM_NET;
+ // Starting with OS X 10.12, if a CRL policy is added without the
+ // FETCH_CRL_FROM_NET flag, AIA fetching is disabled.
+ tp_crl_options.CrlFlags = CSSM_TP_ACTION_FETCH_CRL_FROM_NET;
SecPolicyRef crl_policy;
status = CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_CRL, &tp_crl_options,
@@ -113,43 +140,39 @@ OSStatus CreateRevocationPolicies(bool enable_revocation_checking,
}
// If revocation checking is explicitly enabled, then add an OCSP policy
- // and allow network access. If both revocation checking and EV checking
- // are disabled, then the added OCSP policy will be prevented from
+ // and allow network access. If both revocation checking is
+ // disabled, then the added OCSP policy will be prevented from
// accessing the network. This is done because the TP will force an OCSP
- // policy to be present when it believes the certificate is EV. If network
- // fetching was not explicitly disabled, then it would be as if
- // enable_ev_checking was always set to true.
- if (enable_revocation_checking || !enable_ev_checking) {
- CSSM_APPLE_TP_OCSP_OPTIONS tp_ocsp_options;
- memset(&tp_ocsp_options, 0, sizeof(tp_ocsp_options));
- tp_ocsp_options.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION;
-
- if (enable_revocation_checking) {
- // The default for the OCSP policy is to fetch responses via the network,
- // unlike the CRL policy default. The policy is further modified to
- // prefer OCSP over CRLs, if both are specified on the certificate. This
- // is because an OCSP response is both sufficient and typically
- // significantly smaller than the CRL counterpart.
- tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_SUFFICIENT;
- } else {
- // Effectively disable OCSP checking by making it impossible to get an
- // OCSP response. Even if the Apple TP forces OCSP, no checking will
- // be able to succeed. If this happens, the Apple TP will report an error
- // that OCSP was unavailable, but this will be handled and suppressed in
- // X509Certificate::Verify().
- tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_DISABLE_NET |
- CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE;
- }
-
- SecPolicyRef ocsp_policy;
- status = CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_OCSP, &tp_ocsp_options,
- sizeof(tp_ocsp_options), &ocsp_policy);
- if (status)
- return status;
- CFArrayAppendValue(policies, ocsp_policy);
- CFRelease(ocsp_policy);
+ // policy to be present when it believes the certificate is EV.
+ CSSM_APPLE_TP_OCSP_OPTIONS tp_ocsp_options;
+ memset(&tp_ocsp_options, 0, sizeof(tp_ocsp_options));
+ tp_ocsp_options.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION;
+
+ if (enable_revocation_checking) {
+ // The default for the OCSP policy is to fetch responses via the network,
+ // unlike the CRL policy default. The policy is further modified to
+ // prefer OCSP over CRLs, if both are specified on the certificate. This
+ // is because an OCSP response is both sufficient and typically
+ // significantly smaller than the CRL counterpart.
+ tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_SUFFICIENT;
+ } else {
+ // Effectively disable OCSP checking by making it impossible to get an
+ // OCSP response. Even if the Apple TP forces OCSP, no checking will
+ // be able to succeed. If this happens, the Apple TP will report an error
+ // that OCSP was unavailable, but this will be handled and suppressed in
+ // X509Certificate::Verify().
+ tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_DISABLE_NET |
+ CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE;
}
+ SecPolicyRef ocsp_policy;
+ status = CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_OCSP, &tp_ocsp_options,
+ sizeof(tp_ocsp_options), &ocsp_policy);
+ if (status)
+ return status;
+ CFArrayAppendValue(policies, ocsp_policy);
+ CFRelease(ocsp_policy);
+
return status;
}
diff --git a/chromium/net/cert/x509_util_mac.h b/chromium/net/cert/x509_util_mac.h
index 08c158921d4..6b320a8cd6c 100644
--- a/chromium/net/cert/x509_util_mac.h
+++ b/chromium/net/cert/x509_util_mac.h
@@ -43,18 +43,11 @@ OSStatus NET_EXPORT CreateBasicX509Policy(SecPolicyRef* policy);
// Creates security policies to control revocation checking (OCSP and CRL).
// If |enable_revocation_checking| is true, revocation checking will be
// explicitly enabled.
-// If |enable_revocation_checking| is false, but |enable_ev_checking| is
-// true, then the system policies for EV checking (which include checking
-// for an online OCSP response) will be permitted. However, if the OS
-// does not believe the certificate is EV, no revocation checking will be
-// performed.
-// If both are false, then the policies returned will be explicitly
-// prohibited from accessing the network or the local cache, regardless of
-// system settings.
+// Otherwise, the policies returned will be explicitly prohibited from accessing
+// the network or the local cache, if possible.
// If the policies are successfully created, they will be appended to
// |policies|.
OSStatus NET_EXPORT CreateRevocationPolicies(bool enable_revocation_checking,
- bool enable_ev_checking,
CFMutableArrayRef policies);
// CSSM functions are deprecated as of OSX 10.7, but have no replacement.
diff --git a/chromium/net/cert/x509_util_openssl.cc b/chromium/net/cert/x509_util_openssl.cc
index 2327deddcf2..4c6ee78547e 100644
--- a/chromium/net/cert/x509_util_openssl.cc
+++ b/chromium/net/cert/x509_util_openssl.cc
@@ -322,11 +322,11 @@ bool GetTLSServerEndPointChannelBinding(const X509Certificate& certificate,
der::BitString signature_value;
if (!ParseCertificate(der::Input(&der_encoded_certificate),
&tbs_certificate_tlv, &signature_algorithm_tlv,
- &signature_value))
+ &signature_value, nullptr))
return false;
std::unique_ptr<SignatureAlgorithm> signature_algorithm =
- SignatureAlgorithm::CreateFromDer(signature_algorithm_tlv);
+ SignatureAlgorithm::Create(signature_algorithm_tlv, nullptr);
if (!signature_algorithm)
return false;
diff --git a/chromium/net/cert_net/cert_net_fetcher_impl.cc b/chromium/net/cert_net/cert_net_fetcher_impl.cc
index e46a0f34faf..323211025f6 100644
--- a/chromium/net/cert_net/cert_net_fetcher_impl.cc
+++ b/chromium/net/cert_net/cert_net_fetcher_impl.cc
@@ -178,7 +178,7 @@ class CertNetFetcherImpl::Job : public URLRequest::Delegate {
void OnReceivedRedirect(URLRequest* request,
const RedirectInfo& redirect_info,
bool* defer_redirect) override;
- void OnResponseStarted(URLRequest* request) override;
+ void OnResponseStarted(URLRequest* request, int net_error) override;
void OnReadCompleted(URLRequest* request, int bytes_read) override;
// Clears the URLRequest and timer. Helper for doing work common to
@@ -192,17 +192,17 @@ class CertNetFetcherImpl::Job : public URLRequest::Delegate {
// aggregated buffer.
bool ConsumeBytesRead(URLRequest* request, int num_bytes);
- // Called once the job has exceeded its deadline.
- void OnTimeout();
-
// Called when the URLRequest has completed (either success or failure).
- void OnUrlRequestCompleted(URLRequest* request);
+ void OnUrlRequestCompleted(int net_error);
// Called when the Job has completed. The job may finish in response to a
// timeout, an invalid URL, or the URLRequest completing. By the time this
- // method is called, the response variables have been assigned
- // (result_net_error_ and response_body_).
- void OnJobCompleted();
+ // method is called, the |response_body_| variable have been assigned.
+ void OnJobCompleted(Error error);
+
+ // Cancels a request with a specified error code and calls
+ // OnUrlRequestCompleted().
+ void FailRequest(Error error);
// The requests attached to this job.
RequestList requests_;
@@ -212,7 +212,6 @@ class CertNetFetcherImpl::Job : public URLRequest::Delegate {
// The URLRequest response information.
std::vector<uint8_t> response_body_;
- Error result_net_error_;
std::unique_ptr<URLRequest> url_request_;
scoped_refptr<IOBuffer> read_buffer_;
@@ -235,7 +234,6 @@ CertNetFetcherImpl::RequestImpl::~RequestImpl() {
CertNetFetcherImpl::Job::Job(std::unique_ptr<RequestParams> request_params,
CertNetFetcherImpl* parent)
: request_params_(std::move(request_params)),
- result_net_error_(ERR_IO_PENDING),
parent_(parent) {}
CertNetFetcherImpl::Job::~Job() {
@@ -280,10 +278,11 @@ void CertNetFetcherImpl::Job::DetachRequest(RequestImpl* request) {
void CertNetFetcherImpl::Job::StartURLRequest(URLRequestContext* context) {
Error error = CanFetchUrl(request_params_->url);
if (error != OK) {
- result_net_error_ = error;
// The CertNetFetcher's API contract is that requests always complete
// asynchronously. Use the timer class so the task is easily cancelled.
- timer_.Start(FROM_HERE, base::TimeDelta(), this, &Job::OnJobCompleted);
+ timer_.Start(
+ FROM_HERE, base::TimeDelta(),
+ base::Bind(&Job::OnJobCompleted, base::Unretained(this), error));
return;
}
@@ -299,7 +298,9 @@ void CertNetFetcherImpl::Job::StartURLRequest(URLRequestContext* context) {
// Start a timer to limit how long the job runs for.
if (request_params_->timeout > base::TimeDelta())
- timer_.Start(FROM_HERE, request_params_->timeout, this, &Job::OnTimeout);
+ timer_.Start(
+ FROM_HERE, request_params_->timeout,
+ base::Bind(&Job::FailRequest, base::Unretained(this), ERR_TIMED_OUT));
}
void CertNetFetcherImpl::Job::OnReceivedRedirect(
@@ -311,24 +312,24 @@ void CertNetFetcherImpl::Job::OnReceivedRedirect(
// Ensure that the new URL matches the policy.
Error error = CanFetchUrl(redirect_info.new_url);
if (error != OK) {
- request->CancelWithError(error);
- OnUrlRequestCompleted(request);
+ FailRequest(error);
return;
}
}
-void CertNetFetcherImpl::Job::OnResponseStarted(URLRequest* request) {
+void CertNetFetcherImpl::Job::OnResponseStarted(URLRequest* request,
+ int net_error) {
DCHECK_EQ(url_request_.get(), request);
+ DCHECK_NE(ERR_IO_PENDING, net_error);
- if (!request->status().is_success()) {
- OnUrlRequestCompleted(request);
+ if (net_error != OK) {
+ OnUrlRequestCompleted(net_error);
return;
}
if (request->GetResponseCode() != 200) {
// TODO(eroman): Use a more specific error code.
- request->CancelWithError(ERR_FAILED);
- OnUrlRequestCompleted(request);
+ FailRequest(ERR_FAILED);
return;
}
@@ -338,6 +339,7 @@ void CertNetFetcherImpl::Job::OnResponseStarted(URLRequest* request) {
void CertNetFetcherImpl::Job::OnReadCompleted(URLRequest* request,
int bytes_read) {
DCHECK_EQ(url_request_.get(), request);
+ DCHECK_NE(ERR_IO_PENDING, bytes_read);
// Keep reading the response body.
if (ConsumeBytesRead(request, bytes_read))
@@ -351,31 +353,30 @@ void CertNetFetcherImpl::Job::Stop() {
void CertNetFetcherImpl::Job::ReadBody(URLRequest* request) {
// Read as many bytes as are available synchronously.
- int num_bytes;
- while (
- request->Read(read_buffer_.get(), kReadBufferSizeInBytes, &num_bytes)) {
+ int num_bytes = 0;
+ while (num_bytes >= 0) {
+ num_bytes = request->Read(read_buffer_.get(), kReadBufferSizeInBytes);
+ if (num_bytes == ERR_IO_PENDING)
+ return;
if (!ConsumeBytesRead(request, num_bytes))
return;
}
- // Check whether the read failed synchronously.
- if (!request->status().is_io_pending())
- OnUrlRequestCompleted(request);
- return;
+ OnUrlRequestCompleted(num_bytes);
}
bool CertNetFetcherImpl::Job::ConsumeBytesRead(URLRequest* request,
int num_bytes) {
+ DCHECK_NE(ERR_IO_PENDING, num_bytes);
if (num_bytes <= 0) {
// Error while reading, or EOF.
- OnUrlRequestCompleted(request);
+ OnUrlRequestCompleted(num_bytes);
return false;
}
// Enforce maximum size bound.
if (num_bytes + response_body_.size() > request_params_->max_response_bytes) {
- request->CancelWithError(ERR_FILE_TOO_BIG);
- OnUrlRequestCompleted(request);
+ FailRequest(ERR_FILE_TOO_BIG);
return false;
}
@@ -386,24 +387,14 @@ bool CertNetFetcherImpl::Job::ConsumeBytesRead(URLRequest* request,
return true;
}
-void CertNetFetcherImpl::Job::OnTimeout() {
- result_net_error_ = ERR_TIMED_OUT;
- url_request_->CancelWithError(result_net_error_);
- OnJobCompleted();
+void CertNetFetcherImpl::Job::OnUrlRequestCompleted(int net_error) {
+ DCHECK_NE(ERR_IO_PENDING, net_error);
+ Error result = static_cast<Error>(net_error);
+ OnJobCompleted(result);
}
-void CertNetFetcherImpl::Job::OnUrlRequestCompleted(URLRequest* request) {
- DCHECK_EQ(request, url_request_.get());
-
- if (request->status().is_success())
- result_net_error_ = OK;
- else
- result_net_error_ = static_cast<Error>(request->status().error());
-
- OnJobCompleted();
-}
-
-void CertNetFetcherImpl::Job::OnJobCompleted() {
+void CertNetFetcherImpl::Job::OnJobCompleted(Error error) {
+ DCHECK_NE(ERR_IO_PENDING, error);
// Stop the timer and clear the URLRequest.
Stop();
@@ -419,19 +410,25 @@ void CertNetFetcherImpl::Job::OnJobCompleted() {
while (!requests_.empty()) {
base::LinkNode<RequestImpl>* request = requests_.head();
request->RemoveFromList();
- request->value()->OnJobCompleted(this, result_net_error_, response_body_);
+ request->value()->OnJobCompleted(this, error, response_body_);
}
if (parent_)
parent_->ClearCurrentlyCompletingJob(this);
}
+void CertNetFetcherImpl::Job::FailRequest(Error error) {
+ DCHECK_NE(ERR_IO_PENDING, error);
+ int result = url_request_->CancelWithError(error);
+ OnUrlRequestCompleted(result);
+}
+
CertNetFetcherImpl::CertNetFetcherImpl(URLRequestContext* context)
: currently_completing_job_(nullptr), context_(context) {
}
CertNetFetcherImpl::~CertNetFetcherImpl() {
- STLDeleteElements(&jobs_);
+ base::STLDeleteElements(&jobs_);
// The CertNetFetcherImpl was destroyed in a FetchCallback. Detach all
// remaining requests from the job so no further callbacks are called.
diff --git a/chromium/net/cert_net/cert_net_fetcher_impl_unittest.cc b/chromium/net/cert_net/cert_net_fetcher_impl_unittest.cc
index d8c257b4cb2..da2c116064a 100644
--- a/chromium/net/cert_net/cert_net_fetcher_impl_unittest.cc
+++ b/chromium/net/cert_net/cert_net_fetcher_impl_unittest.cc
@@ -16,11 +16,15 @@
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_server_properties_impl.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/gtest_util.h"
#include "net/url_request/url_request_job_factory_impl.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsOk;
+
// TODO(eroman): Test that cookies aren't sent.
using base::ASCIIToUTF16;
@@ -60,11 +64,11 @@ class RequestContext : public URLRequestContext {
params.ssl_config_service = ssl_config_service();
params.http_server_properties = http_server_properties();
storage_.set_http_network_session(
- base::WrapUnique(new HttpNetworkSession(params)));
- storage_.set_http_transaction_factory(base::WrapUnique(new HttpCache(
+ base::MakeUnique<HttpNetworkSession>(params));
+ storage_.set_http_transaction_factory(base::MakeUnique<HttpCache>(
storage_.http_network_session(), HttpCache::DefaultBackend::InMemory(0),
- false /* set_up_quic_server_info */)));
- storage_.set_job_factory(base::WrapUnique(new URLRequestJobFactoryImpl()));
+ false /* set_up_quic_server_info */));
+ storage_.set_job_factory(base::MakeUnique<URLRequestJobFactoryImpl>());
}
~RequestContext() override { AssertNoURLRequests(); }
@@ -79,7 +83,7 @@ class FetchResult {
: net_error_(net_error), response_body_(response_body) {}
void VerifySuccess(const std::string& expected_body) {
- EXPECT_EQ(OK, net_error_);
+ EXPECT_THAT(net_error_, IsOk());
EXPECT_EQ(expected_body,
std::string(response_body_.begin(), response_body_.end()));
}
@@ -165,9 +169,15 @@ WARN_UNUSED_RESULT std::unique_ptr<CertNetFetcher::Request> StartRequest(
CertNetFetcher::DEFAULT, callback.callback());
}
+// Flaky on Android. See http://crbug.com/646147.
+#if defined(OS_ANDROID)
+#define MAYBE_ParallelFetchNoDuplicates DISABLED_ParallelFetchNoDuplicates
+#else
+#define MAYBE_ParallelFetchNoDuplicates ParallelFetchNoDuplicates
+#endif
// Fetch a few unique URLs using GET in parallel. Each URL has a different body
// and Content-Type.
-TEST_F(CertNetFetcherImplTest, ParallelFetchNoDuplicates) {
+TEST_F(CertNetFetcherImplTest, MAYBE_ParallelFetchNoDuplicates) {
ASSERT_TRUE(test_server_.Start());
CertNetFetcherImpl fetcher(&context_);
@@ -407,9 +417,16 @@ TEST_F(CertNetFetcherImplTest, CancelHttpsNotAllowed) {
EXPECT_EQ(0, network_delegate_.created_requests());
}
+// Flaky on Android. See http://crbug.com/646147.
+#if defined(OS_ANDROID)
+#define MAYBE_CancelBeforeRunningMessageLoop \
+ DISABLED_CancelBeforeRunningMessageLoop
+#else
+#define MAYBE_CancelBeforeRunningMessageLoop CancelBeforeRunningMessageLoop
+#endif
// Start a few requests, and cancel one of them before running the message loop
// again.
-TEST_F(CertNetFetcherImplTest, CancelBeforeRunningMessageLoop) {
+TEST_F(CertNetFetcherImplTest, MAYBE_CancelBeforeRunningMessageLoop) {
ASSERT_TRUE(test_server_.Start());
CertNetFetcherImpl fetcher(&context_);
@@ -517,9 +534,15 @@ TEST_F(CertNetFetcherImplTest, DeleteCancels) {
fetcher.reset();
}
+// Flaky on Android. See http://crbug.com/646147.
+#if defined(OS_ANDROID)
+#define MAYBE_ParallelFetchDuplicates DISABLED_ParallelFetchDuplicates
+#else
+#define MAYBE_ParallelFetchDuplicates ParallelFetchDuplicates
+#endif
// Fetch the same URLs in parallel and verify that only 1 request is made per
// URL.
-TEST_F(CertNetFetcherImplTest, ParallelFetchDuplicates) {
+TEST_F(CertNetFetcherImplTest, MAYBE_ParallelFetchDuplicates) {
ASSERT_TRUE(test_server_.Start());
CertNetFetcherImpl fetcher(&context_);
@@ -578,8 +601,14 @@ TEST_F(CertNetFetcherImplTest, ParallelFetchDuplicates) {
EXPECT_EQ(2, network_delegate_.created_requests());
}
+// Flaky on Android. See http://crbug.com/646147.
+#if defined(OS_ANDROID)
+#define MAYBE_CancelThenStart DISABLED_CancelThenStart
+#else
+#define MAYBE_CancelThenStart CancelThenStart
+#endif
// Cancel a request and then start another one for the same URL.
-TEST_F(CertNetFetcherImplTest, CancelThenStart) {
+TEST_F(CertNetFetcherImplTest, MAYBE_CancelThenStart) {
ASSERT_TRUE(test_server_.Start());
CertNetFetcherImpl fetcher(&context_);
@@ -673,8 +702,14 @@ void FetchRequest(CertNetFetcher* fetcher,
*request = StartRequest(fetcher, url, *callback);
}
+// Flaky on Android. See http://crbug.com/646147.
+#if defined(OS_ANDROID)
+#define MAYBE_FetchWithinCallback DISABLED_FetchWithinCallback
+#else
+#define MAYBE_FetchWithinCallback FetchWithinCallback
+#endif
// Make a request during callback for the same URL.
-TEST_F(CertNetFetcherImplTest, FetchWithinCallback) {
+TEST_F(CertNetFetcherImplTest, MAYBE_FetchWithinCallback) {
ASSERT_TRUE(test_server_.Start());
CertNetFetcherImpl fetcher(&context_);
@@ -736,9 +771,16 @@ TEST_F(CertNetFetcherImplTest, CancelWithinCallback) {
EXPECT_FALSE(callback[2].HasResult());
}
+// Flaky on Android. See http://crbug.com/646147.
+#if defined(OS_ANDROID)
+#define MAYBE_CancelLastRequestWithinCallback \
+ DISABLED_CancelLastRequestWithinCallback
+#else
+#define MAYBE_CancelLastRequestWithinCallback CancelLastRequestWithinCallback
+#endif
// Cancel the final request while executing a callback for the same job. Ensure
// that the job is not deleted twice.
-TEST_F(CertNetFetcherImplTest, CancelLastRequestWithinCallback) {
+TEST_F(CertNetFetcherImplTest, MAYBE_CancelLastRequestWithinCallback) {
ASSERT_TRUE(test_server_.Start());
CertNetFetcherImpl fetcher(&context_);
diff --git a/chromium/net/cert_net/nss_ocsp.cc b/chromium/net/cert_net/nss_ocsp.cc
index 50edb9305d3..0eb4678434b 100644
--- a/chromium/net/cert_net/nss_ocsp.cc
+++ b/chromium/net/cert_net/nss_ocsp.cc
@@ -23,6 +23,7 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
@@ -298,16 +299,17 @@ class OCSPRequestSession
}
}
- void OnResponseStarted(URLRequest* request) override {
+ void OnResponseStarted(URLRequest* request, int net_error) override {
DCHECK_EQ(request_.get(), request);
DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_);
+ DCHECK_NE(ERR_IO_PENDING, net_error);
int bytes_read = 0;
- if (request->status().is_success()) {
+ if (net_error == OK) {
response_code_ = request_->GetResponseCode();
response_headers_ = request_->response_headers();
response_headers_->GetMimeType(&response_content_type_);
- request_->Read(buffer_.get(), kRecvBufferSize, &bytes_read);
+ bytes_read = request_->Read(buffer_.get(), kRecvBufferSize);
}
OnReadCompleted(request_.get(), bytes_read);
}
@@ -316,13 +318,12 @@ class OCSPRequestSession
DCHECK_EQ(request_.get(), request);
DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_);
- do {
- if (!request_->status().is_success() || bytes_read <= 0)
- break;
+ while (bytes_read > 0) {
data_.append(buffer_->data(), bytes_read);
- } while (request_->Read(buffer_.get(), kRecvBufferSize, &bytes_read));
+ bytes_read = request_->Read(buffer_.get(), kRecvBufferSize);
+ }
- if (!request_->status().is_io_pending()) {
+ if (bytes_read != ERR_IO_PENDING) {
request_.reset();
g_ocsp_io_loop.Get().RemoveRequest(this);
{
@@ -542,12 +543,12 @@ void OCSPIOLoop::EnsureIOLoop() {
}
void OCSPIOLoop::AddRequest(OCSPRequestSession* request) {
- DCHECK(!ContainsKey(requests_, request));
+ DCHECK(!base::ContainsKey(requests_, request));
requests_.insert(request);
}
void OCSPIOLoop::RemoveRequest(OCSPRequestSession* request) {
- DCHECK(ContainsKey(requests_, request));
+ DCHECK(base::ContainsKey(requests_, request));
requests_.erase(request);
}
diff --git a/chromium/net/cert_net/nss_ocsp_unittest.cc b/chromium/net/cert_net/nss_ocsp_unittest.cc
index c5a1e61766f..d86e6a2e91e 100644
--- a/chromium/net/cert_net/nss_ocsp_unittest.cc
+++ b/chromium/net/cert_net/nss_ocsp_unittest.cc
@@ -22,14 +22,20 @@
#include "net/cert/multi_threaded_cert_verifier.h"
#include "net/cert/test_root_certs.h"
#include "net/cert/x509_certificate.h"
+#include "net/log/net_log_with_source.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
#include "net/url_request/url_request_filter.h"
#include "net/url_request/url_request_interceptor.h"
#include "net/url_request/url_request_test_job.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -147,12 +153,12 @@ TEST_F(NssHttpTest, TestAia) {
CertVerifier::RequestParams(test_cert, "aia-host.invalid", flags,
std::string(), CertificateList()),
nullptr, &verify_result, test_callback.callback(), &request,
- BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, error);
+ NetLogWithSource());
+ ASSERT_THAT(error, IsError(ERR_IO_PENDING));
error = test_callback.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
// Ensure that NSS made an AIA request for the missing intermediate.
EXPECT_LT(0, request_count());
diff --git a/chromium/net/cookies/canonical_cookie.cc b/chromium/net/cookies/canonical_cookie.cc
index 407c9ff20a4..bbabbb771a4 100644
--- a/chromium/net/cookies/canonical_cookie.cc
+++ b/chromium/net/cookies/canonical_cookie.cc
@@ -125,35 +125,9 @@ CanonicalCookie::CanonicalCookie()
httponly_(false) {
}
-CanonicalCookie::CanonicalCookie(const GURL& url,
- const std::string& name,
- const std::string& value,
- const std::string& domain,
- const std::string& path,
- const base::Time& creation,
- const base::Time& expiration,
- const base::Time& last_access,
- bool secure,
- bool httponly,
- CookieSameSite same_site,
- CookiePriority priority)
- : source_(url.SchemeIsFile() ? url : url.GetOrigin()),
- name_(name),
- value_(value),
- domain_(domain),
- path_(path),
- creation_date_(creation),
- expiry_date_(expiration),
- last_access_date_(last_access),
- secure_(secure),
- httponly_(httponly),
- same_site_(same_site),
- priority_(priority) {}
-
CanonicalCookie::CanonicalCookie(const CanonicalCookie& other) = default;
-CanonicalCookie::~CanonicalCookie() {
-}
+CanonicalCookie::~CanonicalCookie() {}
// static
std::string CanonicalCookie::CanonPath(const GURL& url,
@@ -219,7 +193,7 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::Create(
// Per 3.2.1 of "Deprecate modification of 'secure' cookies from non-secure
// origins", if the cookie's "secure-only-flag" is "true" and the requesting
// URL does not have a secure scheme, the cookie should be thrown away.
- // https://tools.ietf.org/html/draft-west-leave-secure-cookies-alone
+ // https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone
if (options.enforce_strict_secure() && parsed_cookie.IsSecure() &&
!url.SchemeIsCryptographic()) {
VLOG(kVlogSetCookies)
@@ -247,10 +221,10 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::Create(
}
return base::WrapUnique(new CanonicalCookie(
- url, parsed_cookie.Name(), parsed_cookie.Value(), cookie_domain,
- cookie_path, creation_time, cookie_expires, creation_time,
- parsed_cookie.IsSecure(), parsed_cookie.IsHttpOnly(),
- parsed_cookie.SameSite(), parsed_cookie.Priority()));
+ parsed_cookie.Name(), parsed_cookie.Value(), cookie_domain, cookie_path,
+ creation_time, cookie_expires, creation_time, parsed_cookie.IsSecure(),
+ parsed_cookie.IsHttpOnly(), parsed_cookie.SameSite(),
+ parsed_cookie.Priority()));
}
// static
@@ -306,7 +280,7 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::Create(
canon_path_component.len);
return base::WrapUnique(new CanonicalCookie(
- url, parsed_name, parsed_value, cookie_domain, cookie_path, creation,
+ parsed_name, parsed_value, cookie_domain, cookie_path, creation,
expiration, creation, secure, http_only, same_site, priority));
}
@@ -323,9 +297,16 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::Create(
bool http_only,
CookieSameSite same_site,
CookiePriority priority) {
- return base::WrapUnique(new CanonicalCookie(
- GURL(), name, value, domain, path, creation, expiration, last_access,
- secure, http_only, same_site, priority));
+ return base::WrapUnique(
+ new CanonicalCookie(name, value, domain, path, creation, expiration,
+ last_access, secure, http_only, same_site, priority));
+}
+
+bool CanonicalCookie::IsEquivalentForSecureCookieMatching(
+ const CanonicalCookie& ecc) const {
+ return (name_ == ecc.Name() && (ecc.IsDomainMatch(DomainWithoutDot()) ||
+ IsDomainMatch(ecc.DomainWithoutDot())) &&
+ ecc.IsOnPath(Path()));
}
bool CanonicalCookie::IsOnPath(const std::string& url_path) const {
@@ -475,14 +456,37 @@ bool CanonicalCookie::FullCompare(const CanonicalCookie& other) const {
return Priority() < other.Priority();
}
+CanonicalCookie::CanonicalCookie(const std::string& name,
+ const std::string& value,
+ const std::string& domain,
+ const std::string& path,
+ const base::Time& creation,
+ const base::Time& expiration,
+ const base::Time& last_access,
+ bool secure,
+ bool httponly,
+ CookieSameSite same_site,
+ CookiePriority priority)
+ : name_(name),
+ value_(value),
+ domain_(domain),
+ path_(path),
+ creation_date_(creation),
+ expiry_date_(expiration),
+ last_access_date_(last_access),
+ secure_(secure),
+ httponly_(httponly),
+ same_site_(same_site),
+ priority_(priority) {}
+
// static
CanonicalCookie::CookiePrefix CanonicalCookie::GetCookiePrefix(
const std::string& name) {
const char kSecurePrefix[] = "__Secure-";
const char kHostPrefix[] = "__Host-";
- if (name.find(kSecurePrefix) == 0)
+ if (base::StartsWith(name, kSecurePrefix, base::CompareCase::SENSITIVE))
return CanonicalCookie::COOKIE_PREFIX_SECURE;
- if (name.find(kHostPrefix) == 0)
+ if (base::StartsWith(name, kHostPrefix, base::CompareCase::SENSITIVE))
return CanonicalCookie::COOKIE_PREFIX_HOST;
return CanonicalCookie::COOKIE_PREFIX_NONE;
}
@@ -518,4 +522,10 @@ bool CanonicalCookie::IsCookiePrefixValid(CanonicalCookie::CookiePrefix prefix,
return true;
}
+std::string CanonicalCookie::DomainWithoutDot() const {
+ if (domain_.empty() || domain_[0] != '.')
+ return domain_;
+ return domain_.substr(1);
+}
+
} // namespace net
diff --git a/chromium/net/cookies/canonical_cookie.h b/chromium/net/cookies/canonical_cookie.h
index 00a2dd8d862..4102299e425 100644
--- a/chromium/net/cookies/canonical_cookie.h
+++ b/chromium/net/cookies/canonical_cookie.h
@@ -23,24 +23,7 @@ class ParsedCookie;
class NET_EXPORT CanonicalCookie {
public:
- // These constructors do no validation or canonicalization of their inputs;
- // the resulting CanonicalCookies should not be relied on to be canonical
- // unless the caller has done appropriate validation and canonicalization
- // themselves.
CanonicalCookie();
- CanonicalCookie(const GURL& url,
- const std::string& name,
- const std::string& value,
- const std::string& domain,
- const std::string& path,
- const base::Time& creation,
- const base::Time& expiration,
- const base::Time& last_access,
- bool secure,
- bool httponly,
- CookieSameSite same_site,
- CookiePriority priority);
-
CanonicalCookie(const CanonicalCookie& other);
~CanonicalCookie();
@@ -86,7 +69,6 @@ class NET_EXPORT CanonicalCookie {
CookieSameSite same_site,
CookiePriority priority);
- const GURL& Source() const { return source_; }
const std::string& Name() const { return name_; }
const std::string& Value() const { return value_; }
const std::string& Domain() const { return domain_; }
@@ -121,17 +103,19 @@ class NET_EXPORT CanonicalCookie {
&& path_ == ecc.Path());
}
- // Checks if two cookies have the same name and domain-match per RFC 6265.
- // Note that this purposefully ignores paths, and that this function is
- // guaranteed to return |true| for a superset of the inputs that
- // IsEquivalent() above returns |true| for.
+ // Checks a looser set of equivalency rules than 'IsEquivalent()' in order
+ // to support the stricter 'Secure' behaviors specified in
+ // https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone#section-3
//
- // This is needed for the updates to RFC6265 as per
- // https://tools.ietf.org/html/draft-west-leave-secure-cookies-alone.
- bool IsEquivalentForSecureCookieMatching(const CanonicalCookie& ecc) const {
- return (name_ == ecc.Name() && (ecc.IsDomainMatch(Source().host()) ||
- IsDomainMatch(ecc.Source().host())));
- }
+ // Returns 'true' if this cookie's name matches |ecc|, and this cookie is
+ // a domain-match for |ecc| (or vice versa), and |ecc|'s path is "on" this
+ // cookie's path (as per 'IsOnPath()').
+ //
+ // Note that while the domain-match cuts both ways (e.g. 'example.com'
+ // matches 'www.example.com' in either direction), the path-match is
+ // unidirectional (e.g. '/login/en' matches '/login' and '/', but
+ // '/login' and '/' do not match '/login/en').
+ bool IsEquivalentForSecureCookieMatching(const CanonicalCookie& ecc) const;
void SetLastAccessDate(const base::Time& date) {
last_access_date_ = date;
@@ -185,6 +169,22 @@ class NET_EXPORT CanonicalCookie {
COOKIE_PREFIX_LAST
};
+ // This constructor does not validate or canonicalize their inputs;
+ // the resulting CanonicalCookies should not be relied on to be canonical
+ // unless the caller has done appropriate validation and canonicalization
+ // themselves.
+ CanonicalCookie(const std::string& name,
+ const std::string& value,
+ const std::string& domain,
+ const std::string& path,
+ const base::Time& creation,
+ const base::Time& expiration,
+ const base::Time& last_access,
+ bool secure,
+ bool httponly,
+ CookieSameSite same_site,
+ CookiePriority priority);
+
// Returns the CookiePrefix (or COOKIE_PREFIX_NONE if none) that
// applies to the given cookie |name|.
static CookiePrefix GetCookiePrefix(const std::string& name);
@@ -198,15 +198,9 @@ class NET_EXPORT CanonicalCookie {
const GURL& url,
const ParsedCookie& parsed_cookie);
- // The source member of a canonical cookie is the origin of the URL that tried
- // to set this cookie. This field is not persistent though; its only used in
- // the in-tab cookies dialog to show the user the source URL. This is used for
- // both allowed and blocked cookies.
- // When a CanonicalCookie is constructed from the backing store (common case)
- // this field will be null. CanonicalCookie consumers should not rely on
- // this field unless they guarantee that the creator of those
- // CanonicalCookies properly initialized the field.
- GURL source_;
+ // Returns the cookie's domain, with the leading dot removed, if present.
+ std::string DomainWithoutDot() const;
+
std::string name_;
std::string value_;
std::string domain_;
diff --git a/chromium/net/cookies/canonical_cookie_unittest.cc b/chromium/net/cookies/canonical_cookie_unittest.cc
index 21902c0076e..fa9eb6caa83 100644
--- a/chromium/net/cookies/canonical_cookie_unittest.cc
+++ b/chromium/net/cookies/canonical_cookie_unittest.cc
@@ -18,30 +18,28 @@ TEST(CanonicalCookieTest, Constructor) {
GURL url("http://www.example.com/test");
base::Time current_time = base::Time::Now();
- CanonicalCookie cookie(url, "A", "2", "www.example.com", "/test",
- current_time, base::Time(), current_time, false, false,
- CookieSameSite::DEFAULT_MODE, COOKIE_PRIORITY_DEFAULT);
- EXPECT_EQ(url.GetOrigin(), cookie.Source());
- EXPECT_EQ("A", cookie.Name());
- EXPECT_EQ("2", cookie.Value());
- EXPECT_EQ("www.example.com", cookie.Domain());
- EXPECT_EQ("/test", cookie.Path());
- EXPECT_FALSE(cookie.IsSecure());
- EXPECT_FALSE(cookie.IsHttpOnly());
- EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie.SameSite());
-
- CanonicalCookie cookie2(url, "A", "2", std::string(), std::string(),
- current_time, base::Time(), current_time, false,
- false, CookieSameSite::DEFAULT_MODE,
- COOKIE_PRIORITY_DEFAULT);
- EXPECT_EQ(url.GetOrigin(), cookie.Source());
- EXPECT_EQ("A", cookie2.Name());
- EXPECT_EQ("2", cookie2.Value());
- EXPECT_EQ("", cookie2.Domain());
- EXPECT_EQ("", cookie2.Path());
- EXPECT_FALSE(cookie2.IsSecure());
- EXPECT_FALSE(cookie2.IsHttpOnly());
- EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie2.SameSite());
+ std::unique_ptr<CanonicalCookie> cookie(CanonicalCookie::Create(
+ url, "A", "2", std::string(), "/test", current_time, base::Time(), false,
+ false, CookieSameSite::DEFAULT_MODE, false, COOKIE_PRIORITY_DEFAULT));
+ EXPECT_EQ("A", cookie->Name());
+ EXPECT_EQ("2", cookie->Value());
+ EXPECT_EQ("www.example.com", cookie->Domain());
+ EXPECT_EQ("/test", cookie->Path());
+ EXPECT_FALSE(cookie->IsSecure());
+ EXPECT_FALSE(cookie->IsHttpOnly());
+ EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie->SameSite());
+
+ std::unique_ptr<CanonicalCookie> cookie2(CanonicalCookie::Create(
+ url, "A", "2", ".www.example.com", std::string(), current_time,
+ base::Time(), false, false, CookieSameSite::DEFAULT_MODE, false,
+ COOKIE_PRIORITY_DEFAULT));
+ EXPECT_EQ("A", cookie2->Name());
+ EXPECT_EQ("2", cookie2->Value());
+ EXPECT_EQ(".www.example.com", cookie2->Domain());
+ EXPECT_EQ("/", cookie2->Path());
+ EXPECT_FALSE(cookie2->IsSecure());
+ EXPECT_FALSE(cookie2->IsHttpOnly());
+ EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie2->SameSite());
}
TEST(CanonicalCookieTest, Create) {
@@ -52,7 +50,6 @@ TEST(CanonicalCookieTest, Create) {
std::unique_ptr<CanonicalCookie> cookie(
CanonicalCookie::Create(url, "A=2", creation_time, options));
- EXPECT_EQ(url.GetOrigin(), cookie->Source());
EXPECT_EQ("A", cookie->Name());
EXPECT_EQ("2", cookie->Value());
EXPECT_EQ("www.example.com", cookie->Domain());
@@ -61,7 +58,6 @@ TEST(CanonicalCookieTest, Create) {
GURL url2("http://www.foo.com");
cookie = CanonicalCookie::Create(url2, "B=1", creation_time, options);
- EXPECT_EQ(url2.GetOrigin(), cookie->Source());
EXPECT_EQ("B", cookie->Name());
EXPECT_EQ("1", cookie->Value());
EXPECT_EQ("www.foo.com", cookie->Domain());
@@ -101,7 +97,6 @@ TEST(CanonicalCookieTest, Create) {
creation_time, base::Time(), false, false,
CookieSameSite::DEFAULT_MODE, false,
COOKIE_PRIORITY_DEFAULT);
- EXPECT_EQ(url.GetOrigin(), cookie->Source());
EXPECT_EQ("A", cookie->Name());
EXPECT_EQ("2", cookie->Value());
EXPECT_EQ(".www.example.com", cookie->Domain());
@@ -114,7 +109,6 @@ TEST(CanonicalCookieTest, Create) {
creation_time, base::Time(), false, false,
CookieSameSite::DEFAULT_MODE, false,
COOKIE_PRIORITY_DEFAULT);
- EXPECT_EQ(url.GetOrigin(), cookie->Source());
EXPECT_EQ("A", cookie->Name());
EXPECT_EQ("2", cookie->Value());
EXPECT_EQ(".www.example.com", cookie->Domain());
@@ -177,7 +171,7 @@ TEST(CanonicalCookieTest, IsEquivalent) {
std::string cookie_name = "A";
std::string cookie_value = "2EDA-EF";
std::string cookie_domain = ".www.example.com";
- std::string cookie_path = "/";
+ std::string cookie_path = "/path";
base::Time creation_time = base::Time::Now();
base::Time expiration_time = creation_time + base::TimeDelta::FromDays(2);
bool secure(false);
@@ -190,6 +184,7 @@ TEST(CanonicalCookieTest, IsEquivalent) {
expiration_time, secure, httponly, same_site, false,
COOKIE_PRIORITY_MEDIUM));
EXPECT_TRUE(cookie->IsEquivalent(*cookie));
+ EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*cookie));
// Test that two identical cookies are equivalent.
std::unique_ptr<CanonicalCookie> other_cookie(CanonicalCookie::Create(
@@ -197,6 +192,7 @@ TEST(CanonicalCookieTest, IsEquivalent) {
expiration_time, secure, httponly, same_site, false,
COOKIE_PRIORITY_MEDIUM));
EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
+ EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie));
// Tests that use different variations of attribute values that
// DON'T affect cookie equivalence.
@@ -205,6 +201,8 @@ TEST(CanonicalCookieTest, IsEquivalent) {
creation_time, expiration_time, secure, httponly,
same_site, false, COOKIE_PRIORITY_HIGH);
EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
+ EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
+ EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie));
base::Time other_creation_time =
creation_time + base::TimeDelta::FromMinutes(2);
@@ -213,31 +211,43 @@ TEST(CanonicalCookieTest, IsEquivalent) {
expiration_time, secure, httponly, same_site, false,
COOKIE_PRIORITY_MEDIUM);
EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
+ EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
+ EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie));
other_cookie = CanonicalCookie::Create(
url, cookie_name, cookie_name, cookie_domain, cookie_path, creation_time,
expiration_time, true, httponly, same_site, false, COOKIE_PRIORITY_LOW);
EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
+ EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
+ EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie));
other_cookie = CanonicalCookie::Create(
url, cookie_name, cookie_name, cookie_domain, cookie_path, creation_time,
expiration_time, secure, true, same_site, false, COOKIE_PRIORITY_LOW);
EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
+ EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
+ EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie));
other_cookie = CanonicalCookie::Create(
url, cookie_name, cookie_name, cookie_domain, cookie_path, creation_time,
expiration_time, secure, httponly, CookieSameSite::STRICT_MODE, false,
COOKIE_PRIORITY_LOW);
EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
+ EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
+ EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie));
- // Tests that use different variations of attribute values that
- // DO affect cookie equivalence.
+ // Cookies whose names mismatch are not equivalent.
other_cookie = CanonicalCookie::Create(
url, "B", cookie_value, cookie_domain, cookie_path, creation_time,
expiration_time, secure, httponly, same_site, false,
COOKIE_PRIORITY_MEDIUM);
EXPECT_FALSE(cookie->IsEquivalent(*other_cookie));
+ EXPECT_FALSE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
+ EXPECT_FALSE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie));
+ // A domain cookie at 'www.example.com' is not equivalent to a host cookie
+ // at the same domain. These are, however, equivalent according to the laxer
+ // rules of 'IsEquivalentForSecureCookieMatching'.
other_cookie = CanonicalCookie::Create(
url, cookie_name, cookie_value, std::string(), cookie_path, creation_time,
expiration_time, secure, httponly, same_site, false,
@@ -245,113 +255,47 @@ TEST(CanonicalCookieTest, IsEquivalent) {
EXPECT_TRUE(cookie->IsDomainCookie());
EXPECT_FALSE(other_cookie->IsDomainCookie());
EXPECT_FALSE(cookie->IsEquivalent(*other_cookie));
+ EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
+ EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie));
+ // Likewise, a cookie on 'example.com' is not equivalent to a cookie on
+ // 'www.example.com', but they are equivalent for secure cookie matching.
other_cookie = CanonicalCookie::Create(
url, cookie_name, cookie_value, ".example.com", cookie_path,
creation_time, expiration_time, secure, httponly, same_site, false,
COOKIE_PRIORITY_MEDIUM);
EXPECT_FALSE(cookie->IsEquivalent(*other_cookie));
-
- other_cookie = CanonicalCookie::Create(
- url, cookie_name, cookie_value, cookie_domain, "/test/0", creation_time,
- expiration_time, secure, httponly, same_site, false,
- COOKIE_PRIORITY_MEDIUM);
- EXPECT_FALSE(cookie->IsEquivalent(*other_cookie));
-}
-
-TEST(CanonicalCookieTest, IsEquivalentForSecureCookieMatching) {
- GURL url("http://www.example.com/");
- std::string cookie_name = "A";
- std::string cookie_value = "2EDA-EF";
- std::string cookie_domain = ".www.example.com";
- std::string cookie_path = "/";
- base::Time creation_time = base::Time::Now();
- base::Time expiration_time = creation_time + base::TimeDelta::FromDays(2);
- bool secure(false);
- bool httponly(false);
- CookieSameSite same_site(CookieSameSite::NO_RESTRICTION);
-
- // Test that a cookie is equivalent to itself.
- std::unique_ptr<CanonicalCookie> cookie(CanonicalCookie::Create(
- url, cookie_name, cookie_value, cookie_domain, cookie_path, creation_time,
- expiration_time, secure, httponly, same_site, false,
- COOKIE_PRIORITY_MEDIUM));
- EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*cookie));
-
- // Test that two identical cookies are equivalent.
- std::unique_ptr<CanonicalCookie> other_cookie(CanonicalCookie::Create(
- url, cookie_name, cookie_value, cookie_domain, cookie_path, creation_time,
- expiration_time, secure, httponly, same_site, false,
- COOKIE_PRIORITY_MEDIUM));
- EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
-
- // Tests that use different variations of attribute values that
- // DON'T affect cookie equivalence. Differs from the IsEquivalent tests above
- // as follows:
- // * Should return true even if paths differ.
- // * Should return true if the domains "domain-match" (but are not
- // identical).
- other_cookie =
- CanonicalCookie::Create(url, cookie_name, "2", cookie_domain, cookie_path,
- creation_time, expiration_time, secure, httponly,
- same_site, false, COOKIE_PRIORITY_HIGH);
EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
+ EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie));
- base::Time other_creation_time =
- creation_time + base::TimeDelta::FromMinutes(2);
+ // Paths are a bit more complicated. 'IsEquivalent' requires an exact path
+ // match, while secure cookie matching uses a more relaxed 'IsOnPath' check.
+ // That is, |cookie| set on '/path' is not equivalent in either way to
+ // |other_cookie| set on '/test' or '/path/subpath'. It is, however,
+ // equivalent for secure cookie matching to |other_cookie| set on '/'.
other_cookie = CanonicalCookie::Create(
- url, cookie_name, "2", cookie_domain, cookie_path, other_creation_time,
+ url, cookie_name, cookie_value, cookie_domain, "/test", creation_time,
expiration_time, secure, httponly, same_site, false,
COOKIE_PRIORITY_MEDIUM);
- EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
-
- other_cookie = CanonicalCookie::Create(
- url, cookie_name, cookie_name, cookie_domain, cookie_path, creation_time,
- expiration_time, true, httponly, same_site, false, COOKIE_PRIORITY_LOW);
- EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
-
- other_cookie = CanonicalCookie::Create(
- url, cookie_name, cookie_name, cookie_domain, cookie_path, creation_time,
- expiration_time, secure, true, same_site, false, COOKIE_PRIORITY_LOW);
- EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
-
- other_cookie = CanonicalCookie::Create(
- url, cookie_name, cookie_name, cookie_domain, cookie_path, creation_time,
- expiration_time, secure, httponly, CookieSameSite::STRICT_MODE, false,
- COOKIE_PRIORITY_LOW);
- EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
-
- // The following 3 tests' expected results differ from their IsEquivalent
- // counterparts above.
- other_cookie = CanonicalCookie::Create(
- url, cookie_name, cookie_value, cookie_domain, "/test/0", creation_time,
- expiration_time, secure, httponly, same_site, false,
- COOKIE_PRIORITY_MEDIUM);
- EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
-
- other_cookie = CanonicalCookie::Create(
- url, cookie_name, cookie_value, std::string(), cookie_path, creation_time,
- expiration_time, secure, httponly, same_site, false,
- COOKIE_PRIORITY_MEDIUM);
- EXPECT_TRUE(cookie->IsDomainCookie());
- EXPECT_FALSE(other_cookie->IsDomainCookie());
- EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
+ EXPECT_FALSE(cookie->IsEquivalent(*other_cookie));
+ EXPECT_FALSE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
+ EXPECT_FALSE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie));
other_cookie = CanonicalCookie::Create(
- url, cookie_name, cookie_value, ".example.com", cookie_path,
+ url, cookie_name, cookie_value, cookie_domain, cookie_path + "/subpath",
creation_time, expiration_time, secure, httponly, same_site, false,
COOKIE_PRIORITY_MEDIUM);
- EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
+ EXPECT_FALSE(cookie->IsEquivalent(*other_cookie));
+ EXPECT_FALSE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
+ EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie));
- // Tests that use different variations of attribute values that
- // DO affect cookie equivalence. Note that unlike the IsEquivalent tests
- // above, this does *not* include tests for differing paths or domains that
- // "domain-match".
other_cookie = CanonicalCookie::Create(
- url, "B", cookie_value, cookie_domain, cookie_path, creation_time,
+ url, cookie_name, cookie_value, cookie_domain, "/", creation_time,
expiration_time, secure, httponly, same_site, false,
COOKIE_PRIORITY_MEDIUM);
- EXPECT_FALSE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
+ EXPECT_FALSE(cookie->IsEquivalent(*other_cookie));
+ EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie));
+ EXPECT_FALSE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie));
}
TEST(CanonicalCookieTest, IsDomainMatch) {
diff --git a/chromium/net/cookies/cookie_monster.cc b/chromium/net/cookies/cookie_monster.cc
index 684a9653a1c..9925dbc1b97 100644
--- a/chromium/net/cookies/cookie_monster.cc
+++ b/chromium/net/cookies/cookie_monster.cc
@@ -265,48 +265,48 @@ CookieMonster::CookieItVector::iterator LowerBoundAccessDate(
LowerBoundAccessDateComparator);
}
-// Mapping between DeletionCause and CookieMonsterDelegate::ChangeCause; the
+// Mapping between DeletionCause and CookieStore::ChangeCause; the
// mapping also provides a boolean that specifies whether or not an
// OnCookieChanged notification ought to be generated.
typedef struct ChangeCausePair_struct {
- CookieMonsterDelegate::ChangeCause cause;
+ CookieStore::ChangeCause cause;
bool notify;
} ChangeCausePair;
-ChangeCausePair ChangeCauseMapping[] = {
+const ChangeCausePair kChangeCauseMapping[] = {
// DELETE_COOKIE_EXPLICIT
- {CookieMonsterDelegate::CHANGE_COOKIE_EXPLICIT, true},
+ {CookieStore::ChangeCause::EXPLICIT, true},
// DELETE_COOKIE_OVERWRITE
- {CookieMonsterDelegate::CHANGE_COOKIE_OVERWRITE, true},
+ {CookieStore::ChangeCause::OVERWRITE, true},
// DELETE_COOKIE_EXPIRED
- {CookieMonsterDelegate::CHANGE_COOKIE_EXPIRED, true},
+ {CookieStore::ChangeCause::EXPIRED, true},
// DELETE_COOKIE_EVICTED
- {CookieMonsterDelegate::CHANGE_COOKIE_EVICTED, true},
+ {CookieStore::ChangeCause::EVICTED, true},
// DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE
- {CookieMonsterDelegate::CHANGE_COOKIE_EXPLICIT, false},
+ {CookieStore::ChangeCause::EXPLICIT, false},
// DELETE_COOKIE_DONT_RECORD
- {CookieMonsterDelegate::CHANGE_COOKIE_EXPLICIT, false},
+ {CookieStore::ChangeCause::EXPLICIT, false},
// DELETE_COOKIE_EVICTED_DOMAIN
- {CookieMonsterDelegate::CHANGE_COOKIE_EVICTED, true},
+ {CookieStore::ChangeCause::EVICTED, true},
// DELETE_COOKIE_EVICTED_GLOBAL
- {CookieMonsterDelegate::CHANGE_COOKIE_EVICTED, true},
+ {CookieStore::ChangeCause::EVICTED, true},
// DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE
- {CookieMonsterDelegate::CHANGE_COOKIE_EVICTED, true},
+ {CookieStore::ChangeCause::EVICTED, true},
// DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE
- {CookieMonsterDelegate::CHANGE_COOKIE_EVICTED, true},
+ {CookieStore::ChangeCause::EVICTED, true},
// DELETE_COOKIE_EXPIRED_OVERWRITE
- {CookieMonsterDelegate::CHANGE_COOKIE_EXPIRED_OVERWRITE, true},
+ {CookieStore::ChangeCause::EXPIRED_OVERWRITE, true},
// DELETE_COOKIE_CONTROL_CHAR
- {CookieMonsterDelegate::CHANGE_COOKIE_EVICTED, true},
+ {CookieStore::ChangeCause::EVICTED, true},
// DELETE_COOKIE_NON_SECURE
- {CookieMonsterDelegate::CHANGE_COOKIE_EVICTED, true},
+ {CookieStore::ChangeCause::EVICTED, true},
// DELETE_COOKIE_LAST_ENTRY
- {CookieMonsterDelegate::CHANGE_COOKIE_EXPLICIT, false}};
+ {CookieStore::ChangeCause::EXPLICIT, false}};
void RunAsync(scoped_refptr<base::TaskRunner> proxy,
const CookieStore::CookieChangedCallback& callback,
const CanonicalCookie& cookie,
- bool removed) {
- proxy->PostTask(FROM_HERE, base::Bind(callback, cookie, removed));
+ CookieStore::ChangeCause cause) {
+ proxy->PostTask(FROM_HERE, base::Bind(callback, cookie, cause));
}
bool IsCookieEligibleForEviction(CookiePriority current_priority_level,
@@ -778,10 +778,6 @@ class CookieMonster::GetCookiesWithOptionsTask : public CookieMonsterTask {
};
void CookieMonster::GetCookiesWithOptionsTask::Run() {
- // TODO(mkwst): Remove ScopedTracker below once crbug.com/456373 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "456373 CookieMonster::GetCookiesWithOptionsTask::Run"));
std::string cookie =
this->cookie_monster()->GetCookiesWithOptions(url_, options_);
if (!callback_.is_null())
@@ -1077,7 +1073,7 @@ bool CookieMonster::SetCookieWithDetails(const GURL& url,
CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
if (enforce_strict_secure)
options.set_enforce_strict_secure();
- return SetCanonicalCookie(std::move(cc), options);
+ return SetCanonicalCookie(std::move(cc), url, options);
}
CookieList CookieMonster::GetAllCookies() {
@@ -1395,7 +1391,7 @@ void CookieMonster::StoreLoadedCookies(
if (creation_times_.insert(cookie_creation_time).second) {
CookieMap::iterator inserted =
- InternalInsertCookie(GetKey((*it)->Domain()), *it, false);
+ InternalInsertCookie(GetKey((*it)->Domain()), *it, GURL(), false);
const Time cookie_access_time((*it)->LastAccessDate());
if (earliest_access_time_.is_null() ||
cookie_access_time < earliest_access_time_)
@@ -1612,6 +1608,7 @@ void CookieMonster::FindCookiesForKey(const std::string& key,
bool CookieMonster::DeleteAnyEquivalentCookie(const std::string& key,
const CanonicalCookie& ecc,
+ const GURL& source_url,
bool skip_httponly,
bool already_expired,
bool enforce_strict_secure) {
@@ -1636,8 +1633,9 @@ bool CookieMonster::DeleteAnyEquivalentCookie(const std::string& key,
// ignoring the path attribute.
//
// See: https://tools.ietf.org/html/draft-west-leave-secure-cookies-alone
- if (enforce_strict_secure && !ecc.Source().SchemeIsCryptographic() &&
- ecc.IsEquivalentForSecureCookieMatching(*cc) && cc->IsSecure()) {
+ if (enforce_strict_secure && cc->IsSecure() &&
+ !source_url.SchemeIsCryptographic() &&
+ ecc.IsEquivalentForSecureCookieMatching(*cc)) {
skipped_secure_cookie = true;
histogram_cookie_delete_equivalent_->Add(
COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE);
@@ -1677,23 +1675,17 @@ bool CookieMonster::DeleteAnyEquivalentCookie(const std::string& key,
CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie(
const std::string& key,
CanonicalCookie* cc,
+ const GURL& source_url,
bool sync_to_store) {
DCHECK(thread_checker_.CalledOnValidThread());
- // TODO(mkwst): Remove ScopedTracker below once crbug.com/456373 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "456373 CookieMonster::InternalInsertCookie"));
-
if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() &&
sync_to_store)
store_->AddCookie(*cc);
CookieMap::iterator inserted =
cookies_.insert(CookieMap::value_type(key, cc));
- if (delegate_.get()) {
- delegate_->OnCookieChanged(*cc, false,
- CookieMonsterDelegate::CHANGE_COOKIE_EXPLICIT);
- }
+ if (delegate_.get())
+ delegate_->OnCookieChanged(*cc, false, CookieStore::ChangeCause::INSERTED);
// See InitializeHistograms() for details.
int32_t type_sample = cc->SameSite() != CookieSameSite::NO_RESTRICTION
@@ -1708,9 +1700,9 @@ CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie(
// http:// URLs, but not cookies that are cleared by http:// URLs, to
// understand if the former behavior can be deprecated for Secure
// cookies.
- if (!cc->Source().is_empty()) {
+ if (!source_url.is_empty()) {
CookieSource cookie_source_sample;
- if (cc->Source().SchemeIsCryptographic()) {
+ if (source_url.SchemeIsCryptographic()) {
cookie_source_sample =
cc->IsSecure() ? COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME
: COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME;
@@ -1723,7 +1715,7 @@ CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie(
histogram_cookie_source_scheme_->Add(cookie_source_sample);
}
- RunCookieChangedCallbacks(*cc, false);
+ RunCookieChangedCallbacks(*cc, CookieStore::ChangeCause::INSERTED);
return inserted;
}
@@ -1750,10 +1742,11 @@ bool CookieMonster::SetCookieWithCreationTimeAndOptions(
VLOG(kVlogSetCookies) << "WARNING: Failed to allocate CanonicalCookie";
return false;
}
- return SetCanonicalCookie(std::move(cc), options);
+ return SetCanonicalCookie(std::move(cc), url, options);
}
bool CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
+ const GURL& source_url,
const CookieOptions& options) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -1761,8 +1754,8 @@ bool CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
const std::string key(GetKey(cc->Domain()));
bool already_expired = cc->IsExpired(creation_time);
- if (DeleteAnyEquivalentCookie(key, *cc, options.exclude_httponly(),
- already_expired,
+ if (DeleteAnyEquivalentCookie(key, *cc, source_url,
+ options.exclude_httponly(), already_expired,
options.enforce_strict_secure())) {
std::string error;
if (options.enforce_strict_secure()) {
@@ -1789,7 +1782,7 @@ bool CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
(cc->ExpiryDate() - creation_time).InMinutes());
}
- InternalInsertCookie(key, cc.release(), true);
+ InternalInsertCookie(key, cc.release(), source_url, true);
} else {
VLOG(kVlogSetCookies) << "SetCookie() not storing already expired cookie.";
}
@@ -1811,7 +1804,8 @@ bool CookieMonster::SetCanonicalCookies(const CookieList& list) {
options.set_include_httponly();
for (const auto& cookie : list) {
- if (!SetCanonicalCookie(base::WrapUnique(new CanonicalCookie(cookie)),
+ // Use an empty GURL. This method does not support setting secure cookies.
+ if (!SetCanonicalCookie(base::MakeUnique<CanonicalCookie>(cookie), GURL(),
options)) {
return false;
}
@@ -1843,11 +1837,11 @@ void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
DeletionCause deletion_cause) {
DCHECK(thread_checker_.CalledOnValidThread());
- // Ideally, this would be asserted up where we define ChangeCauseMapping,
+ // Ideally, this would be asserted up where we define kChangeCauseMapping,
// but DeletionCause's visibility (or lack thereof) forces us to make
// this check here.
- static_assert(arraysize(ChangeCauseMapping) == DELETE_COOKIE_LAST_ENTRY + 1,
- "ChangeCauseMapping size should match DeletionCause size");
+ static_assert(arraysize(kChangeCauseMapping) == DELETE_COOKIE_LAST_ENTRY + 1,
+ "kChangeCauseMapping size should match DeletionCause size");
// See InitializeHistograms() for details.
if (deletion_cause != DELETE_COOKIE_DONT_RECORD)
@@ -1861,13 +1855,10 @@ void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() &&
sync_to_store)
store_->DeleteCookie(*cc);
- if (delegate_.get()) {
- ChangeCausePair mapping = ChangeCauseMapping[deletion_cause];
-
- if (mapping.notify)
- delegate_->OnCookieChanged(*cc, true, mapping.cause);
- }
- RunCookieChangedCallbacks(*cc, true);
+ ChangeCausePair mapping = kChangeCauseMapping[deletion_cause];
+ if (delegate_.get() && mapping.notify)
+ delegate_->OnCookieChanged(*cc, true, mapping.cause);
+ RunCookieChangedCallbacks(*cc, mapping.cause);
cookies_.erase(it);
delete cc;
}
@@ -2379,7 +2370,7 @@ void CookieMonster::RunCallback(const base::Closure& callback) {
}
void CookieMonster::RunCookieChangedCallbacks(const CanonicalCookie& cookie,
- bool removed) {
+ ChangeCause cause) {
DCHECK(thread_checker_.CalledOnValidThread());
CookieOptions opts;
@@ -2395,7 +2386,7 @@ void CookieMonster::RunCookieChangedCallbacks(const CanonicalCookie& cookie,
std::pair<GURL, std::string> key = it->first;
if (cookie.IncludeForRequestURL(key.first, opts) &&
cookie.Name() == key.second) {
- it->second->Notify(cookie, removed);
+ it->second->Notify(cookie, cause);
}
}
}
diff --git a/chromium/net/cookies/cookie_monster.h b/chromium/net/cookies/cookie_monster.h
index 850ad9422b8..087099c92b3 100644
--- a/chromium/net/cookies/cookie_monster.h
+++ b/chromium/net/cookies/cookie_monster.h
@@ -142,6 +142,9 @@ class NET_EXPORT CookieMonster : public CookieStore {
~CookieMonster() override;
// Replaces all the cookies by |list|. This method does not flush the backend.
+ // This method does not support setting secure cookies, which need source
+ // URLs.
+ // TODO(mmenke): This method is only used on iOS. Consider removing it.
void SetAllCookiesAsync(const CookieList& list,
const SetCookiesCallback& callback);
@@ -274,7 +277,7 @@ class NET_EXPORT CookieMonster : public CookieStore {
// and to provide a public cause for onCookieChange notifications.
//
// If you add or remove causes from this list, please be sure to also update
- // the CookieMonsterDelegate::ChangeCause mapping inside ChangeCauseMapping.
+ // the CookieStore::ChangeCause mapping inside ChangeCauseMapping.
// Moreover, these are used as array indexes, so avoid reordering to keep the
// histogram buckets consistent. New items (if necessary) should be added
// at the end of the list, just before DELETE_COOKIE_LAST_ENTRY.
@@ -487,6 +490,7 @@ class NET_EXPORT CookieMonster : public CookieStore {
std::vector<CanonicalCookie*>* cookies);
// Delete any cookies that are equivalent to |ecc| (same path, domain, etc).
+ // |source_url| is the URL that is attempting to set the cookie.
// If |skip_httponly| is true, httponly cookies will not be deleted. The
// return value will be true if |skip_httponly| skipped an httponly cookie or
// |enforce_strict_secure| is true and the cookie to
@@ -496,6 +500,7 @@ class NET_EXPORT CookieMonster : public CookieStore {
// NOTE: There should never be more than a single matching equivalent cookie.
bool DeleteAnyEquivalentCookie(const std::string& key,
const CanonicalCookie& ecc,
+ const GURL& source_url,
bool skip_httponly,
bool already_expired,
bool enforce_strict_secure);
@@ -504,6 +509,7 @@ class NET_EXPORT CookieMonster : public CookieStore {
// cookie in cookies_. Guarantee: all iterators to cookies_ remain valid.
CookieMap::iterator InternalInsertCookie(const std::string& key,
CanonicalCookie* cc,
+ const GURL& source_url,
bool sync_to_store);
// Helper function that sets cookies with more control.
@@ -516,7 +522,9 @@ class NET_EXPORT CookieMonster : public CookieStore {
// Helper function that sets a canonical cookie, deleting equivalents and
// performing garbage collection.
+ // |source_url| is the URL that's attempting to set the cookie.
bool SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
+ const GURL& source_url,
const CookieOptions& options);
// Helper function calling SetCanonicalCookie() for all cookies in |list|.
@@ -526,7 +534,7 @@ class NET_EXPORT CookieMonster : public CookieStore {
const base::Time& current_time);
// |deletion_cause| argument is used for collecting statistics and choosing
- // the correct CookieMonsterDelegate::ChangeCause for OnCookieChanged
+ // the correct CookieStore::ChangeCause for OnCookieChanged
// notifications. Guarantee: All iterators to cookies_ except to the
// deleted entry remain vaild.
void InternalDeleteCookie(CookieMap::iterator it,
@@ -627,7 +635,8 @@ class NET_EXPORT CookieMonster : public CookieStore {
// Run all cookie changed callbacks that are monitoring |cookie|.
// |removed| is true if the cookie was deleted.
- void RunCookieChangedCallbacks(const CanonicalCookie& cookie, bool removed);
+ void RunCookieChangedCallbacks(const CanonicalCookie& cookie,
+ CookieStore::ChangeCause cause);
// Histogram variables; see CookieMonster::InitializeHistograms() in
// cookie_monster.cc for details.
@@ -719,35 +728,21 @@ class NET_EXPORT CookieMonster : public CookieStore {
class NET_EXPORT CookieMonsterDelegate
: public base::RefCountedThreadSafe<CookieMonsterDelegate> {
public:
- // The publicly relevant reasons a cookie might be changed.
- enum ChangeCause {
- // The cookie was changed directly by a consumer's action.
- CHANGE_COOKIE_EXPLICIT,
- // The cookie was automatically removed due to an insert operation that
- // overwrote it.
- CHANGE_COOKIE_OVERWRITE,
- // The cookie was automatically removed as it expired.
- CHANGE_COOKIE_EXPIRED,
- // The cookie was automatically evicted during garbage collection.
- CHANGE_COOKIE_EVICTED,
- // The cookie was overwritten with an already-expired expiration date.
- CHANGE_COOKIE_EXPIRED_OVERWRITE
- };
-
// Will be called when a cookie is added or removed. The function is passed
// the respective |cookie| which was added to or removed from the cookies.
// If |removed| is true, the cookie was deleted, and |cause| will be set
// to the reason for its removal. If |removed| is false, the cookie was
- // added, and |cause| will be set to CHANGE_COOKIE_EXPLICIT.
+ // added, and |cause| will be set to ChangeCause::EXPLICIT.
//
// As a special case, note that updating a cookie's properties is implemented
// as a two step process: the cookie to be updated is first removed entirely,
- // generating a notification with cause CHANGE_COOKIE_OVERWRITE. Afterwards,
+ // generating a notification with cause ChangeCause::OVERWRITE. Afterwards,
// a new cookie is written with the updated values, generating a notification
- // with cause CHANGE_COOKIE_EXPLICIT.
+ // with cause ChangeCause::EXPLICIT.
virtual void OnCookieChanged(const CanonicalCookie& cookie,
bool removed,
- ChangeCause cause) = 0;
+ CookieStore::ChangeCause cause) = 0;
+
protected:
friend class base::RefCountedThreadSafe<CookieMonsterDelegate>;
virtual ~CookieMonsterDelegate() {}
diff --git a/chromium/net/cookies/cookie_monster_store_test.cc b/chromium/net/cookies/cookie_monster_store_test.cc
index 5257356e089..7a8af87c47e 100644
--- a/chromium/net/cookies/cookie_monster_store_test.cc
+++ b/chromium/net/cookies/cookie_monster_store_test.cc
@@ -116,7 +116,7 @@ MockCookieMonsterDelegate::MockCookieMonsterDelegate() {
void MockCookieMonsterDelegate::OnCookieChanged(
const CanonicalCookie& cookie,
bool removed,
- CookieMonsterDelegate::ChangeCause cause) {
+ CookieStore::ChangeCause cause) {
CookieNotification notification(cookie, removed);
changes_.push_back(notification);
}
@@ -260,7 +260,7 @@ std::unique_ptr<CookieMonster> CreateMonsterFromStoreForGC(
store->AddCookie(*cc);
}
- return base::WrapUnique(new CookieMonster(store.get(), nullptr));
+ return base::MakeUnique<CookieMonster>(store.get(), nullptr);
}
MockSimplePersistentCookieStore::~MockSimplePersistentCookieStore() {
diff --git a/chromium/net/cookies/cookie_monster_store_test.h b/chromium/net/cookies/cookie_monster_store_test.h
index 9145e184958..835ec6d0520 100644
--- a/chromium/net/cookies/cookie_monster_store_test.h
+++ b/chromium/net/cookies/cookie_monster_store_test.h
@@ -157,7 +157,7 @@ class MockCookieMonsterDelegate : public CookieMonsterDelegate {
void OnCookieChanged(const CanonicalCookie& cookie,
bool removed,
- CookieMonsterDelegate::ChangeCause cause) override;
+ CookieStore::ChangeCause cause) override;
private:
~MockCookieMonsterDelegate() override;
diff --git a/chromium/net/cookies/cookie_monster_unittest.cc b/chromium/net/cookies/cookie_monster_unittest.cc
index cd7ab02c868..9414fe11d4c 100644
--- a/chromium/net/cookies/cookie_monster_unittest.cc
+++ b/chromium/net/cookies/cookie_monster_unittest.cc
@@ -98,7 +98,7 @@ bool CookieValuePredicate(const std::string& true_value,
struct CookieMonsterTestTraits {
static std::unique_ptr<CookieStore> Create() {
- return base::WrapUnique(new CookieMonster(nullptr, nullptr));
+ return base::MakeUnique<CookieMonster>(nullptr, nullptr);
}
static const bool supports_http_only = true;
@@ -112,7 +112,7 @@ struct CookieMonsterTestTraits {
struct CookieMonsterEnforcingStrictSecure {
static std::unique_ptr<CookieStore> Create() {
- return base::WrapUnique(new CookieMonster(nullptr, nullptr));
+ return base::MakeUnique<CookieMonster>(nullptr, nullptr);
}
static const bool supports_http_only = true;
@@ -405,7 +405,7 @@ class CookieMonsterTestBase : public CookieStoreTest<T> {
base::SPLIT_WANT_ALL)) {
DCHECK(!token.empty());
- bool is_secure = token[token.size() - 1] == 'S';
+ bool is_secure = token.back() == 'S';
// The second-to-last character is the priority. Grab and discard it.
CookiePriority priority = CharToPriority(token[token.size() - 2]);
@@ -787,9 +787,8 @@ class CookieMonsterTestBase : public CookieStoreTest<T> {
bool IsCookieInList(const CanonicalCookie& cookie, const CookieList& list) {
for (CookieList::const_iterator it = list.begin(); it != list.end(); ++it) {
- if (it->Source() == cookie.Source() && it->Name() == cookie.Name() &&
- it->Value() == cookie.Value() && it->Domain() == cookie.Domain() &&
- it->Path() == cookie.Path() &&
+ if (it->Name() == cookie.Name() && it->Value() == cookie.Value() &&
+ it->Domain() == cookie.Domain() && it->Path() == cookie.Path() &&
it->CreationDate() == cookie.CreationDate() &&
it->ExpiryDate() == cookie.ExpiryDate() &&
it->LastAccessDate() == cookie.LastAccessDate() &&
@@ -2534,7 +2533,7 @@ TEST_F(CookieMonsterTest, FlushStore) {
ASSERT_EQ(0, counter->callback_count());
// Before initialization, FlushStore() should just run the callback.
- cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get()));
+ cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(0, store->flush_count());
@@ -2549,7 +2548,7 @@ TEST_F(CookieMonsterTest, FlushStore) {
// After initialization, FlushStore() should delegate to the store.
GetAllCookies(cm.get()); // Force init.
- cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get()));
+ cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(1, store->flush_count());
@@ -2570,7 +2569,7 @@ TEST_F(CookieMonsterTest, FlushStore) {
ASSERT_EQ(2, counter->callback_count());
- cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get()));
+ cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(3, counter->callback_count());
@@ -3071,16 +3070,25 @@ TEST_F(CookieMonsterStrictSecureTest, SetSecureCookies) {
EXPECT_TRUE(SetCookie(cm.get(), https_url, "A=C;"));
// If a non-secure cookie is created from a URL with an insecure scheme, and
- // a secure cookie with the same name already exists, no matter what the path
- // is, do not update the cookie.
+ // a secure cookie with the same name already exists, do not update the cookie
+ // if the new cookie's path matches the existing cookie's path.
+ //
+ // With an existing cookie whose path is '/', a cookie with the same name
+ // cannot be set on the same domain, regardless of path:
EXPECT_TRUE(SetCookie(cm.get(), https_url, "A=B; Secure"));
EXPECT_FALSE(SetCookie(cm.get(), http_url, "A=C; path=/"));
EXPECT_FALSE(SetCookie(cm.get(), http_url, "A=C; path=/my/path"));
- EXPECT_TRUE(SetCookie(cm.get(), https_url, "A=B; Secure; path=/my/path"));
- EXPECT_FALSE(SetCookie(cm.get(), http_url, "A=C"));
- EXPECT_FALSE(SetCookie(cm.get(), http_url, "A=C; path=/"));
- EXPECT_FALSE(SetCookie(cm.get(), http_url, "A=C; path=/my/path"));
+ // But if the existing cookie has a path somewhere under the root, cookies
+ // with the same name may be set for paths which don't overlap the existing
+ // cookie.
+ EXPECT_TRUE(
+ SetCookie(cm.get(), https_url, "WITH_PATH=B; Secure; path=/my/path"));
+ EXPECT_TRUE(SetCookie(cm.get(), http_url, "WITH_PATH=C"));
+ EXPECT_TRUE(SetCookie(cm.get(), http_url, "WITH_PATH=C; path=/"));
+ EXPECT_TRUE(SetCookie(cm.get(), http_url, "WITH_PATH=C; path=/your/path"));
+ EXPECT_FALSE(SetCookie(cm.get(), http_url, "WITH_PATH=C; path=/my/path"));
+ EXPECT_FALSE(SetCookie(cm.get(), http_url, "WITH_PATH=C; path=/my/path/sub"));
// If a non-secure cookie is created from a URL with an insecure scheme, and
// a secure cookie with the same name already exists, if the domain strings
@@ -3354,13 +3362,13 @@ class CookieMonsterNotificationTest : public CookieMonsterTest {
};
void RecordCookieChanges(std::vector<CanonicalCookie>* out_cookies,
- std::vector<bool>* out_removes,
+ std::vector<CookieStore::ChangeCause>* out_causes,
const CanonicalCookie& cookie,
- bool removed) {
+ CookieStore::ChangeCause cause) {
DCHECK(out_cookies);
out_cookies->push_back(cookie);
- if (out_removes)
- out_removes->push_back(removed);
+ if (out_causes)
+ out_causes->push_back(cause);
}
TEST_F(CookieMonsterNotificationTest, NoNotifyWithNoCookie) {
@@ -3387,50 +3395,50 @@ TEST_F(CookieMonsterNotificationTest, NoNotifyWithInitialCookie) {
TEST_F(CookieMonsterNotificationTest, NotifyOnSet) {
std::vector<CanonicalCookie> cookies;
- std::vector<bool> removes;
+ std::vector<CookieStore::ChangeCause> causes;
std::unique_ptr<CookieStore::CookieChangedSubscription> sub(
monster()->AddCallbackForCookie(
test_url_, "abc",
- base::Bind(&RecordCookieChanges, &cookies, &removes)));
+ base::Bind(&RecordCookieChanges, &cookies, &causes)));
SetCookie(monster(), test_url_, "abc=def");
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1U, cookies.size());
- EXPECT_EQ(1U, removes.size());
+ EXPECT_EQ(1U, causes.size());
EXPECT_EQ("abc", cookies[0].Name());
EXPECT_EQ("def", cookies[0].Value());
- EXPECT_FALSE(removes[0]);
+ EXPECT_EQ(CookieStore::ChangeCause::INSERTED, causes[0]);
}
TEST_F(CookieMonsterNotificationTest, NotifyOnDelete) {
std::vector<CanonicalCookie> cookies;
- std::vector<bool> removes;
+ std::vector<CookieStore::ChangeCause> causes;
std::unique_ptr<CookieStore::CookieChangedSubscription> sub(
monster()->AddCallbackForCookie(
test_url_, "abc",
- base::Bind(&RecordCookieChanges, &cookies, &removes)));
+ base::Bind(&RecordCookieChanges, &cookies, &causes)));
SetCookie(monster(), test_url_, "abc=def");
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1U, cookies.size());
- EXPECT_EQ(1U, removes.size());
+ EXPECT_EQ(1U, causes.size());
DeleteCookie(monster(), test_url_, "abc");
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2U, cookies.size());
- EXPECT_EQ(2U, removes.size());
+ EXPECT_EQ(2U, causes.size());
EXPECT_EQ("abc", cookies[1].Name());
EXPECT_EQ("def", cookies[1].Value());
- EXPECT_TRUE(removes[1]);
+ EXPECT_EQ(CookieStore::ChangeCause::EXPLICIT, causes[1]);
}
TEST_F(CookieMonsterNotificationTest, NotifyOnUpdate) {
std::vector<CanonicalCookie> cookies;
- std::vector<bool> removes;
+ std::vector<CookieStore::ChangeCause> causes;
std::unique_ptr<CookieStore::CookieChangedSubscription> sub(
monster()->AddCallbackForCookie(
test_url_, "abc",
- base::Bind(&RecordCookieChanges, &cookies, &removes)));
+ base::Bind(&RecordCookieChanges, &cookies, &causes)));
SetCookie(monster(), test_url_, "abc=def");
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1U, cookies.size());
@@ -3441,15 +3449,15 @@ TEST_F(CookieMonsterNotificationTest, NotifyOnUpdate) {
base::RunLoop().RunUntilIdle();
EXPECT_EQ(3U, cookies.size());
- EXPECT_EQ(3U, removes.size());
+ EXPECT_EQ(3U, causes.size());
EXPECT_EQ("abc", cookies[1].Name());
EXPECT_EQ("def", cookies[1].Value());
- EXPECT_TRUE(removes[1]);
+ EXPECT_EQ(CookieStore::ChangeCause::OVERWRITE, causes[1]);
EXPECT_EQ("abc", cookies[2].Name());
EXPECT_EQ("ghi", cookies[2].Value());
- EXPECT_FALSE(removes[2]);
+ EXPECT_EQ(CookieStore::ChangeCause::INSERTED, causes[2]);
}
TEST_F(CookieMonsterNotificationTest, MultipleNotifies) {
diff --git a/chromium/net/cookies/cookie_store.cc b/chromium/net/cookies/cookie_store.cc
index 1f1b7b96460..20f2dad64f8 100644
--- a/chromium/net/cookies/cookie_store.cc
+++ b/chromium/net/cookies/cookie_store.cc
@@ -12,6 +12,10 @@ namespace net {
CookieStore::~CookieStore() {}
+bool CookieStore::ChangeCauseIsDeletion(CookieStore::ChangeCause cause) {
+ return cause != CookieStore::ChangeCause::INSERTED;
+}
+
std::string CookieStore::BuildCookieLine(
const std::vector<CanonicalCookie>& cookies) {
std::string cookie_line;
diff --git a/chromium/net/cookies/cookie_store.h b/chromium/net/cookies/cookie_store.h
index aaf1b743e46..2b036b94024 100644
--- a/chromium/net/cookies/cookie_store.h
+++ b/chromium/net/cookies/cookie_store.h
@@ -33,14 +33,39 @@ class CookieMonster;
// Destroying the CookieStore will cancel pending async callbacks.
class NET_EXPORT CookieStore {
public:
+ // The publicly relevant reasons a cookie might be changed.
+ enum class ChangeCause {
+ // The cookie was inserted.
+ INSERTED,
+ // The cookie was changed directly by a consumer's action.
+ EXPLICIT,
+ // The cookie was deleted, but no more details are known.
+ UNKNOWN_DELETION,
+ // The cookie was automatically removed due to an insert operation that
+ // overwrote it.
+ OVERWRITE,
+ // The cookie was automatically removed as it expired.
+ EXPIRED,
+ // The cookie was automatically evicted during garbage collection.
+ EVICTED,
+ // The cookie was overwritten with an already-expired expiration date.
+ EXPIRED_OVERWRITE
+ };
+
+ // Returns whether |cause| is one that could be a reason for deleting a
+ // cookie. This function assumes that ChangeCause::EXPLICIT is a reason for
+ // deletion.
+ static bool ChangeCauseIsDeletion(ChangeCause cause);
+
// Callback definitions.
typedef base::Callback<void(const CookieList& cookies)> GetCookieListCallback;
typedef base::Callback<void(const std::string& cookie)> GetCookiesCallback;
typedef base::Callback<void(bool success)> SetCookiesCallback;
typedef base::Callback<void(int num_deleted)> DeleteCallback;
- typedef base::Callback<void(const CanonicalCookie& cookie, bool removed)>
+ typedef base::Callback<void(const CanonicalCookie& cookie, ChangeCause cause)>
CookieChangedCallback;
- typedef base::CallbackList<void(const CanonicalCookie& cookie, bool removed)>
+ typedef base::CallbackList<void(const CanonicalCookie& cookie,
+ ChangeCause cause)>
CookieChangedCallbackList;
typedef CookieChangedCallbackList::Subscription CookieChangedSubscription;
typedef base::Callback<bool(const CanonicalCookie& cookie)> CookiePredicate;
@@ -157,7 +182,7 @@ class NET_EXPORT CookieStore {
const DeleteCallback& callback) = 0;
// Deletes all of the cookies that match the given predicate and that have a
- // creation_date greater than or equal to |delete_begin| and less then
+ // creation_date greater than or equal to |delete_begin| and smaller than
// |delete_end|. This includes all http_only and secure cookies. Avoid
// deleting cookies that could leave websites with a partial set of visible
// cookies.
@@ -198,6 +223,8 @@ class NET_EXPORT CookieStore {
// (url, name) pair are removed. If this method ever needs to support an
// unbounded amount of such pairs, this contract needs to change and
// implementors need to be improved to not behave this way.
+ //
+ // The callback must not synchronously modify another cookie.
virtual std::unique_ptr<CookieChangedSubscription> AddCallbackForCookie(
const GURL& url,
const std::string& name,
diff --git a/chromium/net/cookies/cookie_store_unittest.h b/chromium/net/cookies/cookie_store_unittest.h
index 3f8b037cef8..f7ba3d8a6b3 100644
--- a/chromium/net/cookies/cookie_store_unittest.h
+++ b/chromium/net/cookies/cookie_store_unittest.h
@@ -465,6 +465,46 @@ TYPED_TEST_P(CookieStoreTest, SetCookieWithDetailsAsync) {
EXPECT_TRUE(++it == cookies.end());
}
+// The iOS networking stack uses the iOS cookie parser, which we do not
+// control. While it is spec-compliant, that does not match the practical
+// behavior of most UAs in some cases, which we try to replicate. See
+// https://crbug.com/638389 for more information.
+TYPED_TEST_P(CookieStoreTest, EmptyKeyTest) {
+#if !defined(OS_IOS)
+ CookieStore* cs = this->GetCookieStore();
+
+ GURL url1("http://foo1.bar.com");
+ EXPECT_TRUE(this->SetCookie(cs, url1, "foo"));
+ EXPECT_EQ("foo", this->GetCookies(cs, url1));
+
+ // Regression tests for https://crbug.com/601786
+ GURL url2("http://foo2.bar.com");
+ EXPECT_TRUE(this->SetCookie(cs, url2, "foo"));
+ EXPECT_TRUE(this->SetCookie(cs, url2, "\t"));
+ EXPECT_EQ("", this->GetCookies(cs, url2));
+
+ GURL url3("http://foo3.bar.com");
+ EXPECT_TRUE(this->SetCookie(cs, url3, "foo"));
+ EXPECT_TRUE(this->SetCookie(cs, url3, "="));
+ EXPECT_EQ("", this->GetCookies(cs, url3));
+
+ GURL url4("http://foo4.bar.com");
+ EXPECT_TRUE(this->SetCookie(cs, url4, "foo"));
+ EXPECT_TRUE(this->SetCookie(cs, url4, ""));
+ EXPECT_EQ("", this->GetCookies(cs, url4));
+
+ GURL url5("http://foo5.bar.com");
+ EXPECT_TRUE(this->SetCookie(cs, url5, "foo"));
+ EXPECT_TRUE(this->SetCookie(cs, url5, "; bar"));
+ EXPECT_EQ("", this->GetCookies(cs, url5));
+
+ GURL url6("http://foo6.bar.com");
+ EXPECT_TRUE(this->SetCookie(cs, url6, "foo"));
+ EXPECT_TRUE(this->SetCookie(cs, url6, " "));
+ EXPECT_EQ("", this->GetCookies(cs, url6));
+#endif
+}
+
TYPED_TEST_P(CookieStoreTest, DomainTest) {
CookieStore* cs = this->GetCookieStore();
EXPECT_TRUE(this->SetCookie(cs, this->http_www_google_.url(), "A=B"));
@@ -563,6 +603,15 @@ TYPED_TEST_P(CookieStoreTest, InvalidDomainTest) {
// More specific sub-domain than allowed.
EXPECT_FALSE(this->SetCookie(cs, url_foobar, "a=1; domain=.yo.foo.bar.com"));
+// The iOS networking stack uses the iOS cookie parser, which we do not
+// control. Its handling of multiple domain= values in cookie string varies
+// depending on iOS version. See https://crbug.com/639167
+#if !defined(OS_IOS)
+ // Regression test for https://crbug.com/601786
+ EXPECT_FALSE(
+ this->SetCookie(cs, url_foobar, "a=1; domain=.yo.foo.bar.com; domain="));
+#endif // !defined(OS_IOS)
+
EXPECT_FALSE(this->SetCookie(cs, url_foobar, "b=2; domain=.foo.com"));
EXPECT_FALSE(this->SetCookie(cs, url_foobar, "c=3; domain=.bar.foo.com"));
@@ -1374,6 +1423,7 @@ TYPED_TEST_P(CookieStoreTest, DeleteSessionCookie) {
REGISTER_TYPED_TEST_CASE_P(CookieStoreTest,
SetCookieWithDetailsAsync,
+ EmptyKeyTest,
DomainTest,
DomainWithTrailingDotTest,
ValidSubdomainTest,
diff --git a/chromium/net/cookies/parsed_cookie.cc b/chromium/net/cookies/parsed_cookie.cc
index 2175692f534..bf95a129337 100644
--- a/chromium/net/cookies/parsed_cookie.cc
+++ b/chromium/net/cookies/parsed_cookie.cc
@@ -45,7 +45,9 @@
#include "net/cookies/parsed_cookie.h"
#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
+#include "net/http/http_util.h"
namespace {
@@ -95,26 +97,6 @@ inline bool SeekBackPast(std::string::const_iterator* it,
return *it == end;
}
-// Validate whether |value| is a valid token according to [RFC7230],
-// Section 3.2.6.
-bool IsValidToken(const std::string& value) {
- if (value.empty())
- return false;
-
- // Check that |value| has no separators.
- std::string separators = "()<>@,;:\\\"/[]?={} \t";
- if (value.find_first_of(separators) != std::string::npos)
- return false;
-
- // Check that |value| has no CTLs.
- for (std::string::const_iterator i = value.begin(); i != value.end(); ++i) {
- if ((*i >= 0 && *i <= 31) || *i >= 127)
- return false;
- }
-
- return true;
-}
-
// Validate value, which may be according to RFC 6265
// cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
// cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
@@ -195,7 +177,7 @@ CookiePriority ParsedCookie::Priority() const {
}
bool ParsedCookie::SetName(const std::string& name) {
- if (!IsValidToken(name))
+ if (!name.empty() && !HttpUtil::IsToken(name))
return false;
if (pairs_.empty())
pairs_.push_back(std::make_pair("", ""));
@@ -363,12 +345,26 @@ void ParsedCookie::ParseTokenValuePairs(const std::string& cookie_line) {
// Then we can log any unexpected terminators.
std::string::const_iterator end = FindFirstTerminator(cookie_line);
+ // For an empty |cookie_line|, add an empty-key with an empty value, which
+ // has the effect of clearing any prior setting of the empty-key. This is done
+ // to match the behavior of other browsers. See https://crbug.com/601786.
+ if (it == end) {
+ pairs_.push_back(TokenValuePair("", ""));
+ return;
+ }
+
for (int pair_num = 0; pair_num < kMaxPairs && it != end; ++pair_num) {
TokenValuePair pair;
std::string::const_iterator token_start, token_end;
- if (!ParseToken(&it, end, &token_start, &token_end))
- break;
+ if (!ParseToken(&it, end, &token_start, &token_end)) {
+ // Allow first token to be treated as empty-key if unparsable
+ if (pair_num != 0)
+ break;
+
+ // If parsing failed, start the value parsing at the very beginning.
+ token_start = start;
+ }
if (it == end || *it != '=') {
// We have a token-value, we didn't have any token name.
@@ -411,6 +407,11 @@ void ParsedCookie::ParseTokenValuePairs(const std::string& cookie_line) {
break;
}
+ if (pair_num == 0) {
+ UMA_HISTOGRAM_BOOLEAN("Cookie.CookieLineCookieValueValidity",
+ IsValidCookieValue(pair.second));
+ }
+
pairs_.push_back(pair);
// We've processed a token/value pair, we're either at the end of
@@ -421,17 +422,11 @@ void ParsedCookie::ParseTokenValuePairs(const std::string& cookie_line) {
}
void ParsedCookie::SetupAttributes() {
- // Ignore Set-Cookie directive where name and value are both empty.
- if (pairs_[0].first.empty() && pairs_[0].second.empty()) {
- pairs_.clear();
- return;
- }
-
// We skip over the first token/value, the user supplied one.
for (size_t i = 1; i < pairs_.size(); ++i) {
if (pairs_[i].first == kPathTokenName) {
path_index_ = i;
- } else if (pairs_[i].first == kDomainTokenName) {
+ } else if (pairs_[i].first == kDomainTokenName && pairs_[i].second != "") {
domain_index_ = i;
} else if (pairs_[i].first == kExpiresTokenName) {
expires_index_ = i;
@@ -474,7 +469,7 @@ bool ParsedCookie::SetBool(size_t* index, const std::string& key, bool value) {
bool ParsedCookie::SetAttributePair(size_t* index,
const std::string& key,
const std::string& value) {
- if (!(IsValidToken(key) && IsValidCookieAttributeValue(value)))
+ if (!(HttpUtil::IsToken(key) && IsValidCookieAttributeValue(value)))
return false;
if (!IsValid())
return false;
diff --git a/chromium/net/cookies/parsed_cookie.h b/chromium/net/cookies/parsed_cookie.h
index f48015dbd2f..aed763502c1 100644
--- a/chromium/net/cookies/parsed_cookie.h
+++ b/chromium/net/cookies/parsed_cookie.h
@@ -84,7 +84,8 @@ class NET_EXPORT ParsedCookie {
// returns as output arguments token_start and token_end to the start and end
// positions of a cookie attribute token name parsed from the segment, and
// updates the segment iterator to point to the next segment to be parsed.
- // If no token is found, the function returns false.
+ // If no token is found, the function returns false and the segment iterator
+ // is set to end.
static bool ParseToken(std::string::const_iterator* it,
const std::string::const_iterator& end,
std::string::const_iterator* token_start,
diff --git a/chromium/net/cookies/parsed_cookie_unittest.cc b/chromium/net/cookies/parsed_cookie_unittest.cc
index 27efb99adfc..61a7d0454d6 100644
--- a/chromium/net/cookies/parsed_cookie_unittest.cc
+++ b/chromium/net/cookies/parsed_cookie_unittest.cc
@@ -18,19 +18,29 @@ TEST(ParsedCookieTest, TestBasic) {
EXPECT_EQ("b", pc.Value());
}
+// De facto standard behavior, per https://crbug.com/601786.
TEST(ParsedCookieTest, TestEmpty) {
- ParsedCookie pc1("=; path=/; secure;");
- EXPECT_FALSE(pc1.IsValid());
- ParsedCookie pc2("= ; path=/; secure;");
- EXPECT_FALSE(pc2.IsValid());
- ParsedCookie pc3(" =; path=/; secure;");
- EXPECT_FALSE(pc3.IsValid());
- ParsedCookie pc4(" = ; path=/; secure;");
- EXPECT_FALSE(pc4.IsValid());
- ParsedCookie pc5(" ; path=/; secure;");
- EXPECT_FALSE(pc5.IsValid());
- ParsedCookie pc6("; path=/; secure;");
- EXPECT_FALSE(pc6.IsValid());
+ const struct {
+ const char* cookie;
+ const char* expected_path;
+ bool expect_secure;
+ } kTestCookieLines[]{{"", "", false}, {" ", "", false},
+ {"=;", "", false}, {"=; path=/; secure;", "/", true},
+ {"= ;", "", false}, {"= ; path=/; secure;", "/", true},
+ {" =;", "", false}, {" =; path=/; secure;", "/", true},
+ {" = ;", "", false}, {" = ; path=/; secure;", "/", true},
+ {" ;", "", false}, {" ; path=/; secure;", "/", true},
+ {";", "", false}, {"; path=/; secure;", "/", true},
+ {"\t;", "", false}, {"\t; path=/; secure;", "/", true}};
+
+ for (const auto& test : kTestCookieLines) {
+ ParsedCookie pc(test.cookie);
+ EXPECT_TRUE(pc.IsValid());
+ EXPECT_EQ("", pc.Name());
+ EXPECT_EQ("", pc.Value());
+ EXPECT_EQ(test.expected_path, pc.Path());
+ EXPECT_EQ(test.expect_secure, pc.IsSecure());
+ }
}
TEST(ParsedCookieTest, TestQuoted) {
@@ -221,11 +231,6 @@ TEST(ParsedCookieTest, TooManyPairs) {
}
// TODO(erikwright): some better test cases for invalid cookies.
-TEST(ParsedCookieTest, InvalidWhitespace) {
- ParsedCookie pc(" ");
- EXPECT_FALSE(pc.IsValid());
-}
-
TEST(ParsedCookieTest, InvalidTooLong) {
std::string maxstr;
maxstr.resize(ParsedCookie::kMaxCookieSize, 'a');
@@ -237,11 +242,6 @@ TEST(ParsedCookieTest, InvalidTooLong) {
EXPECT_FALSE(pc2.IsValid());
}
-TEST(ParsedCookieTest, InvalidEmpty) {
- ParsedCookie pc((std::string()));
- EXPECT_FALSE(pc.IsValid());
-}
-
TEST(ParsedCookieTest, EmbeddedTerminator) {
ParsedCookie pc1("AAA=BB\0ZYX");
ParsedCookie pc2("AAA=BB\rZYX");
@@ -285,11 +285,11 @@ TEST(ParsedCookieTest, SerializeCookieLine) {
TEST(ParsedCookieTest, SetNameAndValue) {
ParsedCookie empty((std::string()));
- EXPECT_FALSE(empty.IsValid());
- EXPECT_FALSE(empty.SetDomain("foobar.com"));
+ EXPECT_TRUE(empty.IsValid());
+ EXPECT_TRUE(empty.SetDomain("foobar.com"));
EXPECT_TRUE(empty.SetName("name"));
EXPECT_TRUE(empty.SetValue("value"));
- EXPECT_EQ("name=value", empty.ToCookieLine());
+ EXPECT_EQ("name=value; domain=foobar.com", empty.ToCookieLine());
EXPECT_TRUE(empty.IsValid());
// We don't test
@@ -307,10 +307,6 @@ TEST(ParsedCookieTest, SetNameAndValue) {
EXPECT_EQ("name=value", pc.ToCookieLine());
EXPECT_TRUE(pc.IsValid());
- EXPECT_FALSE(pc.SetName(std::string()));
- EXPECT_EQ("name=value", pc.ToCookieLine());
- EXPECT_TRUE(pc.IsValid());
-
EXPECT_FALSE(pc.SetValue("foo bar"));
EXPECT_EQ("name=value", pc.ToCookieLine());
EXPECT_TRUE(pc.IsValid());
@@ -320,6 +316,10 @@ TEST(ParsedCookieTest, SetNameAndValue) {
EXPECT_TRUE(pc.IsValid());
// Set valid name / value
+ EXPECT_TRUE(pc.SetName(std::string()));
+ EXPECT_EQ("=value", pc.ToCookieLine());
+ EXPECT_TRUE(pc.IsValid());
+
EXPECT_TRUE(pc.SetName("test"));
EXPECT_EQ("test=value", pc.ToCookieLine());
EXPECT_TRUE(pc.IsValid());
@@ -415,6 +415,17 @@ TEST(ParsedCookieTest, SetAttributes) {
EXPECT_EQ("name2=value2", pc.ToCookieLine());
}
+// Set the domain attribute twice in a cookie line. If the second attribute's
+// value is empty, it shoud be ignored.
+//
+// This is de facto standard behavior, per https://crbug.com/601786.
+TEST(ParsedCookieTest, MultipleDomainAttributes) {
+ ParsedCookie pc1("name=value; domain=foo.com; domain=bar.com");
+ EXPECT_EQ("bar.com", pc1.Domain());
+ ParsedCookie pc2("name=value; domain=foo.com; domain=");
+ EXPECT_EQ("foo.com", pc2.Domain());
+}
+
TEST(ParsedCookieTest, SetPriority) {
ParsedCookie pc("name=value");
EXPECT_TRUE(pc.IsValid());
diff --git a/chromium/net/data/cert_issuer_source_aia_unittest/generate-certs.py b/chromium/net/data/cert_issuer_source_aia_unittest/generate-certs.py
index 534d498f6ba..e854c132b5e 100755
--- a/chromium/net/data/cert_issuer_source_aia_unittest/generate-certs.py
+++ b/chromium/net/data/cert_issuer_source_aia_unittest/generate-certs.py
@@ -15,39 +15,39 @@ import common
root = common.create_self_signed_root_certificate('Root')
-# Intermediary certificates. All have the same subject and key.
-i_base = common.create_intermediary_certificate('I', root)
+# Intermediate certificates. All have the same subject and key.
+i_base = common.create_intermediate_certificate('I', root)
common.write_string_to_file(i_base.get_cert_pem(), 'i.pem')
-i2 = common.create_intermediary_certificate('I', root)
+i2 = common.create_intermediate_certificate('I', root)
i2.set_key_path(i_base.get_key_path())
common.write_string_to_file(i2.get_cert_pem(), 'i2.pem')
-i3 = common.create_intermediary_certificate('I', root)
+i3 = common.create_intermediate_certificate('I', root)
i3.set_key_path(i_base.get_key_path())
common.write_string_to_file(i3.get_cert_pem(), 'i3.pem')
-# More Intermediary certificates, which are just to generate the proper config
+# More Intermediate certificates, which are just to generate the proper config
# files so the target certs will have the desired Authority Information Access
# values. These ones aren't saved to files.
-i_no_aia = common.create_intermediary_certificate('I', root)
+i_no_aia = common.create_intermediate_certificate('I', root)
i_no_aia.set_key_path(i_base.get_key_path())
section = i_no_aia.config.get_section('signing_ca_ext')
section.set_property('authorityInfoAccess', None)
-i_two_aia = common.create_intermediary_certificate('I', root)
+i_two_aia = common.create_intermediate_certificate('I', root)
i_two_aia.set_key_path(i_base.get_key_path())
section = i_two_aia.config.get_section('issuer_info')
section.set_property('caIssuers;URI.1', 'http://url-for-aia2/I2.foo')
-i_three_aia = common.create_intermediary_certificate('I', root)
+i_three_aia = common.create_intermediate_certificate('I', root)
i_three_aia.set_key_path(i_base.get_key_path())
section = i_three_aia.config.get_section('issuer_info')
section.set_property('caIssuers;URI.1', 'http://url-for-aia2/I2.foo')
section.set_property('caIssuers;URI.2', 'http://url-for-aia3/I3.foo')
-i_six_aia = common.create_intermediary_certificate('I', root)
+i_six_aia = common.create_intermediate_certificate('I', root)
i_six_aia.set_key_path(i_base.get_key_path())
section = i_six_aia.config.get_section('issuer_info')
section.set_property('caIssuers;URI.1', 'http://url-for-aia2/I2.foo')
@@ -56,23 +56,23 @@ section.set_property('caIssuers;URI.3', 'http://url-for-aia4/I4.foo')
section.set_property('caIssuers;URI.4', 'http://url-for-aia5/I5.foo')
section.set_property('caIssuers;URI.5', 'http://url-for-aia6/I6.foo')
-i_file_aia = common.create_intermediary_certificate('I', root)
+i_file_aia = common.create_intermediate_certificate('I', root)
i_file_aia.set_key_path(i_base.get_key_path())
section = i_file_aia.config.get_section('issuer_info')
section.set_property('caIssuers;URI.0', 'file:///dev/null')
-i_invalid_url_aia = common.create_intermediary_certificate('I', root)
+i_invalid_url_aia = common.create_intermediate_certificate('I', root)
i_invalid_url_aia.set_key_path(i_base.get_key_path())
section = i_invalid_url_aia.config.get_section('issuer_info')
section.set_property('caIssuers;URI.0', 'foobar')
-i_file_and_http_aia = common.create_intermediary_certificate('I', root)
+i_file_and_http_aia = common.create_intermediate_certificate('I', root)
i_file_and_http_aia.set_key_path(i_base.get_key_path())
section = i_file_and_http_aia.config.get_section('issuer_info')
section.set_property('caIssuers;URI.0', 'file:///dev/null')
section.set_property('caIssuers;URI.1', 'http://url-for-aia2/I2.foo')
-i_invalid_and_http_aia = common.create_intermediary_certificate('I', root)
+i_invalid_and_http_aia = common.create_intermediate_certificate('I', root)
i_invalid_and_http_aia.set_key_path(i_base.get_key_path())
section = i_invalid_and_http_aia.config.get_section('issuer_info')
section.set_property('caIssuers;URI.0', 'foobar')
diff --git a/chromium/net/data/cert_issuer_source_aia_unittest/i.pem b/chromium/net/data/cert_issuer_source_aia_unittest/i.pem
index 3b75df358aa..545e7f61355 100644
--- a/chromium/net/data/cert_issuer_source_aia_unittest/i.pem
+++ b/chromium/net/data/cert_issuer_source_aia_unittest/i.pem
@@ -12,30 +12,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:b5:e8:71:e7:b5:df:bb:21:d3:c0:0f:1a:19:d7:
- 44:16:1b:b3:57:12:9c:73:16:fc:42:28:38:87:c6:
- f8:12:16:3b:3b:c4:1d:54:0d:5e:30:32:84:b3:89:
- 6d:d0:a9:e0:46:84:70:e1:e2:2f:e2:d8:9d:d8:a6:
- a9:2f:2a:e1:13:59:1b:e1:1e:fe:f6:31:62:55:9a:
- ee:5f:05:4c:5a:97:ce:2e:05:cb:cd:06:df:ee:ef:
- 50:0f:7b:29:1b:5d:2f:94:8a:75:02:70:a1:8b:a3:
- ac:06:10:8f:26:f0:23:19:08:e9:7c:c3:ee:77:98:
- 72:03:4b:c3:ce:ff:c5:de:5e:62:4b:ff:62:71:eb:
- 65:5a:1f:90:cd:4e:ef:fa:53:71:d4:fb:31:84:bc:
- 99:40:4b:5c:6c:9b:be:bd:ac:43:77:3b:9d:6a:02:
- 37:de:b6:e5:c2:6a:d5:2e:a9:87:28:6a:37:69:fa:
- 6b:2c:b1:8a:2f:b6:07:97:9d:9d:b6:2d:ec:22:33:
- da:98:eb:fd:39:35:49:24:a6:05:dc:c9:5c:74:cb:
- 61:46:8c:44:33:99:e5:30:e7:5f:73:c9:13:ad:6f:
- 90:df:d1:4e:fe:fd:04:26:fd:10:7d:79:db:8d:5c:
- ea:99:77:37:97:cd:9d:ee:7e:17:0d:f9:71:1c:80:
- 55:69
+ 00:b2:80:e2:cb:c2:ed:80:a5:7e:ac:10:1b:64:e9:
+ 57:2b:f2:a7:73:93:a3:f6:42:ef:38:1b:cd:82:d3:
+ 51:77:c4:87:76:f5:e5:17:d8:0d:da:2b:07:07:d3:
+ 37:88:4c:fd:2f:c0:e0:f1:79:04:fb:e7:b1:b0:80:
+ f1:95:b7:1c:ef:13:ca:c0:05:b5:2d:4a:f2:78:52:
+ d8:53:56:22:cd:f3:82:fb:ac:22:e8:ae:c5:14:35:
+ df:bd:83:f6:90:84:15:c7:b3:dc:ae:6c:16:e9:db:
+ a8:62:fe:66:8a:85:c8:d3:0d:9c:03:f8:ee:71:e9:
+ ab:8b:fe:f9:71:00:09:6a:67:90:c9:d6:43:e5:d8:
+ f4:12:d6:6f:4f:83:f4:00:58:e9:7a:df:11:9c:e7:
+ 28:fb:04:83:70:a8:9d:32:80:1c:ac:33:1c:78:0f:
+ a0:26:cc:37:29:08:41:65:1d:1e:95:40:e2:26:da:
+ 3e:6d:47:0b:b5:4f:7b:67:7e:72:2b:d3:f4:f0:fd:
+ 0c:d7:0d:2a:f1:82:11:2d:c0:f9:2d:d4:a0:bf:be:
+ 69:65:ce:3d:e8:a6:b2:8b:76:cb:9c:da:f0:a6:f8:
+ 0e:6b:ae:5c:47:ff:b1:0d:cd:ef:fc:d4:27:7b:d9:
+ 17:4a:f4:16:08:ae:bc:18:36:2e:8b:24:09:e2:9e:
+ d4:27
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 5D:B4:73:AA:1B:60:10:9E:0C:BC:16:BB:A4:0A:58:0D:B6:28:0E:04
+ A4:66:E2:46:F7:3F:A1:73:9D:A2:E2:4E:29:99:DB:2E:36:36:6C:B5
X509v3 Authority Key Identifier:
- keyid:0B:35:14:81:E3:D0:95:6E:A1:38:0E:3D:04:9D:D5:04:3E:6B:24:13
+ keyid:A7:58:01:D5:D6:00:71:D8:28:17:20:E0:01:09:EC:A5:39:90:7E:6E
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -50,39 +50,39 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- af:eb:e6:42:80:33:c4:34:71:f9:d3:fe:57:4f:99:d9:2c:be:
- c1:7f:c2:3c:3e:78:fc:48:50:8d:5a:34:3d:9d:d2:10:f5:10:
- e6:3f:64:04:f6:48:57:73:f8:6b:08:2c:35:c9:47:4e:4b:47:
- 10:8d:d6:c5:ab:f5:86:7b:80:c3:9d:04:a2:d8:65:cb:61:78:
- a2:08:1b:a2:90:08:06:90:c0:76:e3:b5:7e:94:cc:1d:38:a4:
- d1:21:32:3b:af:29:56:4d:d8:7c:7e:44:1a:0a:c5:33:f5:6f:
- 6b:67:11:be:6e:ec:58:7c:6e:c7:ad:f5:37:f9:5d:26:2c:90:
- 2e:9a:ae:c7:48:ed:a8:2f:aa:57:da:3a:c9:b3:5e:60:96:90:
- 96:13:8c:9f:75:59:6c:e6:e0:62:8f:71:f0:26:8f:fc:4f:9e:
- d8:0a:42:de:5d:31:32:56:25:00:5a:0f:2f:3c:db:8b:8d:a3:
- aa:be:07:48:ec:45:63:51:d7:10:3b:d8:a5:af:20:5e:72:4e:
- 6e:8e:86:07:ed:5d:7a:bb:ea:b5:3e:d3:7b:4d:15:9e:b9:68:
- a2:46:38:37:11:a5:4b:80:9d:8c:38:2b:7d:b8:0d:f4:c4:ee:
- 28:af:b3:16:87:2e:79:ab:bc:d3:7b:f9:7e:32:7f:dc:59:ea:
- 02:20:b3:8f
+ 24:1f:8e:82:17:12:1a:5e:1b:cc:a5:e6:4e:bc:10:92:83:be:
+ 5c:04:ee:39:a7:ec:93:50:26:96:65:03:f4:2d:a8:93:5f:3b:
+ 18:fb:b4:ef:88:7d:d4:9e:fb:fa:d8:09:69:a6:79:0c:b0:01:
+ 32:66:56:43:e9:db:9a:b3:7d:8b:7d:32:a9:08:81:0e:75:fb:
+ 49:12:35:c6:23:75:5c:06:58:9a:d3:c4:fa:38:1a:8b:20:d2:
+ 2d:97:81:45:19:11:2e:4b:f4:22:ae:e2:f5:1e:fc:c7:bd:55:
+ 57:1b:68:f5:95:c4:38:e2:af:82:ee:2d:2a:9f:c7:0b:6b:97:
+ d8:8b:02:d6:d7:24:70:31:2f:bf:66:fa:9d:ad:3e:f4:18:23:
+ 8d:b1:99:10:0d:0c:f2:72:12:90:06:2a:37:68:fd:a8:6f:a0:
+ 84:c5:01:1d:6b:37:50:21:7c:ca:9c:56:ae:06:39:70:8f:9d:
+ 06:09:9e:8d:e8:de:7b:64:29:f6:9b:f0:0e:56:20:b0:fb:43:
+ 3e:9f:a8:0b:a9:ee:50:db:b8:06:56:8b:33:08:58:45:5a:9b:
+ 3b:3e:d8:a4:38:22:d9:f3:a5:fa:e6:4e:b8:30:4b:2a:2a:ee:
+ 3f:f7:29:e0:be:ed:40:52:38:ae:ca:01:6a:3b:8a:d8:00:f4:
+ f3:54:42:90
-----BEGIN CERTIFICATE-----
MIIDYjCCAkqgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDDEKMAgGA1UEAwwBSTCC
-ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALXocee137sh08APGhnXRBYb
-s1cSnHMW/EIoOIfG+BIWOzvEHVQNXjAyhLOJbdCp4EaEcOHiL+LYndimqS8q4RNZ
-G+Ee/vYxYlWa7l8FTFqXzi4Fy80G3+7vUA97KRtdL5SKdQJwoYujrAYQjybwIxkI
-6XzD7neYcgNLw87/xd5eYkv/YnHrZVofkM1O7/pTcdT7MYS8mUBLXGybvr2sQ3c7
-nWoCN9625cJq1S6phyhqN2n6ayyxii+2B5ednbYt7CIz2pjr/Tk1SSSmBdzJXHTL
-YUaMRDOZ5TDnX3PJE61vkN/RTv79BCb9EH15241c6pl3N5fNne5+Fw35cRyAVWkC
-AwEAAaOByzCByDAdBgNVHQ4EFgQUXbRzqhtgEJ4MvBa7pApYDbYoDgQwHwYDVR0j
-BBgwFoAUCzUUgePQlW6hOA49BJ3VBD5rJBMwNwYIKwYBBQUHAQEEKzApMCcGCCsG
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALKA4svC7YClfqwQG2TpVyvy
+p3OTo/ZC7zgbzYLTUXfEh3b15RfYDdorBwfTN4hM/S/A4PF5BPvnsbCA8ZW3HO8T
+ysAFtS1K8nhS2FNWIs3zgvusIuiuxRQ1372D9pCEFcez3K5sFunbqGL+ZoqFyNMN
+nAP47nHpq4v++XEACWpnkMnWQ+XY9BLWb0+D9ABY6XrfEZznKPsEg3ConTKAHKwz
+HHgPoCbMNykIQWUdHpVA4ibaPm1HC7VPe2d+civT9PD9DNcNKvGCES3A+S3UoL++
+aWXOPeimsot2y5za8Kb4DmuuXEf/sQ3N7/zUJ3vZF0r0FgiuvBg2LoskCeKe1CcC
+AwEAAaOByzCByDAdBgNVHQ4EFgQUpGbiRvc/oXOdouJOKZnbLjY2bLUwHwYDVR0j
+BBgwFoAUp1gB1dYAcdgoFyDgAQnspTmQfm4wNwYIKwYBBQUHAQEEKzApMCcGCCsG
AQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUwIzAh
oB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQEAwIB
-BjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCv6+ZCgDPENHH5
-0/5XT5nZLL7Bf8I8Pnj8SFCNWjQ9ndIQ9RDmP2QE9khXc/hrCCw1yUdOS0cQjdbF
-q/WGe4DDnQSi2GXLYXiiCBuikAgGkMB247V+lMwdOKTRITI7rylWTdh8fkQaCsUz
-9W9rZxG+buxYfG7HrfU3+V0mLJAumq7HSO2oL6pX2jrJs15glpCWE4yfdVls5uBi
-j3HwJo/8T57YCkLeXTEyViUAWg8vPNuLjaOqvgdI7EVjUdcQO9ilryBeck5ujoYH
-7V16u+q1PtN7TRWeuWiiRjg3EaVLgJ2MOCt9uA30xO4or7MWhy55q7zTe/l+Mn/c
-WeoCILOP
+BjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAkH46CFxIaXhvM
+peZOvBCSg75cBO45p+yTUCaWZQP0LaiTXzsY+7TviH3Unvv62AlppnkMsAEyZlZD
+6duas32LfTKpCIEOdftJEjXGI3VcBlia08T6OBqLINItl4FFGREuS/QiruL1HvzH
+vVVXG2j1lcQ44q+C7i0qn8cLa5fYiwLW1yRwMS+/ZvqdrT70GCONsZkQDQzychKQ
+Bio3aP2ob6CExQEdazdQIXzKnFauBjlwj50GCZ6N6N57ZCn2m/AOViCw+0M+n6gL
+qe5Q27gGVoszCFhFWps7PtikOCLZ86X65k64MEsqKu4/9yngvu1AUjiuygFqO4rY
+APTzVEKQ
-----END CERTIFICATE-----
diff --git a/chromium/net/data/cert_issuer_source_aia_unittest/i2.pem b/chromium/net/data/cert_issuer_source_aia_unittest/i2.pem
index 6fe505cd6a4..dbf13499079 100644
--- a/chromium/net/data/cert_issuer_source_aia_unittest/i2.pem
+++ b/chromium/net/data/cert_issuer_source_aia_unittest/i2.pem
@@ -12,30 +12,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:b5:e8:71:e7:b5:df:bb:21:d3:c0:0f:1a:19:d7:
- 44:16:1b:b3:57:12:9c:73:16:fc:42:28:38:87:c6:
- f8:12:16:3b:3b:c4:1d:54:0d:5e:30:32:84:b3:89:
- 6d:d0:a9:e0:46:84:70:e1:e2:2f:e2:d8:9d:d8:a6:
- a9:2f:2a:e1:13:59:1b:e1:1e:fe:f6:31:62:55:9a:
- ee:5f:05:4c:5a:97:ce:2e:05:cb:cd:06:df:ee:ef:
- 50:0f:7b:29:1b:5d:2f:94:8a:75:02:70:a1:8b:a3:
- ac:06:10:8f:26:f0:23:19:08:e9:7c:c3:ee:77:98:
- 72:03:4b:c3:ce:ff:c5:de:5e:62:4b:ff:62:71:eb:
- 65:5a:1f:90:cd:4e:ef:fa:53:71:d4:fb:31:84:bc:
- 99:40:4b:5c:6c:9b:be:bd:ac:43:77:3b:9d:6a:02:
- 37:de:b6:e5:c2:6a:d5:2e:a9:87:28:6a:37:69:fa:
- 6b:2c:b1:8a:2f:b6:07:97:9d:9d:b6:2d:ec:22:33:
- da:98:eb:fd:39:35:49:24:a6:05:dc:c9:5c:74:cb:
- 61:46:8c:44:33:99:e5:30:e7:5f:73:c9:13:ad:6f:
- 90:df:d1:4e:fe:fd:04:26:fd:10:7d:79:db:8d:5c:
- ea:99:77:37:97:cd:9d:ee:7e:17:0d:f9:71:1c:80:
- 55:69
+ 00:b2:80:e2:cb:c2:ed:80:a5:7e:ac:10:1b:64:e9:
+ 57:2b:f2:a7:73:93:a3:f6:42:ef:38:1b:cd:82:d3:
+ 51:77:c4:87:76:f5:e5:17:d8:0d:da:2b:07:07:d3:
+ 37:88:4c:fd:2f:c0:e0:f1:79:04:fb:e7:b1:b0:80:
+ f1:95:b7:1c:ef:13:ca:c0:05:b5:2d:4a:f2:78:52:
+ d8:53:56:22:cd:f3:82:fb:ac:22:e8:ae:c5:14:35:
+ df:bd:83:f6:90:84:15:c7:b3:dc:ae:6c:16:e9:db:
+ a8:62:fe:66:8a:85:c8:d3:0d:9c:03:f8:ee:71:e9:
+ ab:8b:fe:f9:71:00:09:6a:67:90:c9:d6:43:e5:d8:
+ f4:12:d6:6f:4f:83:f4:00:58:e9:7a:df:11:9c:e7:
+ 28:fb:04:83:70:a8:9d:32:80:1c:ac:33:1c:78:0f:
+ a0:26:cc:37:29:08:41:65:1d:1e:95:40:e2:26:da:
+ 3e:6d:47:0b:b5:4f:7b:67:7e:72:2b:d3:f4:f0:fd:
+ 0c:d7:0d:2a:f1:82:11:2d:c0:f9:2d:d4:a0:bf:be:
+ 69:65:ce:3d:e8:a6:b2:8b:76:cb:9c:da:f0:a6:f8:
+ 0e:6b:ae:5c:47:ff:b1:0d:cd:ef:fc:d4:27:7b:d9:
+ 17:4a:f4:16:08:ae:bc:18:36:2e:8b:24:09:e2:9e:
+ d4:27
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 5D:B4:73:AA:1B:60:10:9E:0C:BC:16:BB:A4:0A:58:0D:B6:28:0E:04
+ A4:66:E2:46:F7:3F:A1:73:9D:A2:E2:4E:29:99:DB:2E:36:36:6C:B5
X509v3 Authority Key Identifier:
- keyid:0B:35:14:81:E3:D0:95:6E:A1:38:0E:3D:04:9D:D5:04:3E:6B:24:13
+ keyid:A7:58:01:D5:D6:00:71:D8:28:17:20:E0:01:09:EC:A5:39:90:7E:6E
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -50,39 +50,39 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 59:52:db:3a:6c:2d:04:1b:03:69:d4:39:56:7f:48:70:84:33:
- 70:c2:d0:fa:5d:5a:de:f9:0b:71:35:3c:e4:57:cf:c7:25:89:
- e7:3d:cf:68:a7:53:5f:c6:67:09:ce:d1:c4:25:6f:ca:5a:c6:
- 15:d0:6c:89:0f:f5:ec:87:ec:5c:9a:61:f7:67:66:23:e6:df:
- 1b:88:fc:03:0b:02:22:5d:fa:20:92:cf:8e:1b:0d:44:48:01:
- 09:21:6c:cb:55:16:36:cd:ba:a7:48:c0:ff:fb:0e:40:75:3f:
- 1f:b4:9c:8b:9a:ed:a7:05:3b:c7:bf:86:22:a6:13:fb:8d:dd:
- 61:e0:30:1f:62:fb:12:d7:c2:ed:25:5d:70:7b:df:9a:54:b3:
- 0f:65:5c:1f:e0:2a:70:3c:38:2e:d1:bf:71:97:d5:cf:64:dd:
- d0:56:7d:b3:2b:88:31:e9:e3:79:29:9b:0a:be:ef:bf:f2:f3:
- 60:e9:20:bc:7d:60:a5:44:a5:23:8d:00:22:62:5d:ce:45:c9:
- 32:68:03:74:38:3e:00:f9:9e:c3:ae:0c:72:d8:c8:53:aa:d3:
- 40:19:68:9d:b4:03:fd:09:2d:7c:8f:2b:4b:7e:7d:48:ed:82:
- f5:07:07:4d:8c:5d:4a:87:6f:7c:30:6d:ae:5b:31:7f:20:6d:
- 03:de:37:4d
+ 84:e9:fb:28:09:4e:4e:1f:1c:ea:c4:d2:ee:54:fa:fc:eb:07:
+ 55:76:e8:ae:e2:f4:c8:a3:57:21:0e:e1:a8:3e:47:fe:57:88:
+ 3d:9a:73:71:0b:78:d6:77:32:6b:eb:9e:a8:c1:0a:11:4e:14:
+ c8:3b:e9:61:dc:7b:24:4c:44:0e:d5:23:77:9c:d3:99:98:ff:
+ 56:d3:00:f8:a5:01:d4:84:ba:9e:34:3f:25:06:b7:a9:d6:d4:
+ dd:cb:42:e5:12:4b:fc:b2:fe:3e:40:f7:d6:b6:dd:89:89:7b:
+ 06:b5:d1:02:d7:74:4a:48:5d:3d:f9:13:cd:6b:5a:76:af:ac:
+ 1b:09:d0:d2:94:e3:74:30:2f:a8:51:aa:37:6c:75:1b:7b:0d:
+ 2c:ee:34:f1:b4:17:6a:c1:fb:17:16:02:e5:3d:9b:4a:27:27:
+ 48:80:6d:cd:b7:f0:c2:97:da:f5:b2:35:c8:c6:0f:e4:28:a3:
+ d3:47:e3:33:42:d1:1f:38:bb:e0:26:36:bd:7a:b7:27:8e:fc:
+ e2:5a:8f:dd:3f:69:4e:99:6f:89:cc:40:f6:59:92:e4:13:89:
+ 7b:fe:06:7d:c0:1f:d6:bc:9d:69:e5:53:bd:9f:6f:e4:c9:a2:
+ 38:65:b7:af:15:49:f1:e4:68:e1:09:01:d2:bd:97:ff:4a:56:
+ aa:c9:5b:b0
-----BEGIN CERTIFICATE-----
MIIDYjCCAkqgAwIBAgIBAzANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDDEKMAgGA1UEAwwBSTCC
-ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALXocee137sh08APGhnXRBYb
-s1cSnHMW/EIoOIfG+BIWOzvEHVQNXjAyhLOJbdCp4EaEcOHiL+LYndimqS8q4RNZ
-G+Ee/vYxYlWa7l8FTFqXzi4Fy80G3+7vUA97KRtdL5SKdQJwoYujrAYQjybwIxkI
-6XzD7neYcgNLw87/xd5eYkv/YnHrZVofkM1O7/pTcdT7MYS8mUBLXGybvr2sQ3c7
-nWoCN9625cJq1S6phyhqN2n6ayyxii+2B5ednbYt7CIz2pjr/Tk1SSSmBdzJXHTL
-YUaMRDOZ5TDnX3PJE61vkN/RTv79BCb9EH15241c6pl3N5fNne5+Fw35cRyAVWkC
-AwEAAaOByzCByDAdBgNVHQ4EFgQUXbRzqhtgEJ4MvBa7pApYDbYoDgQwHwYDVR0j
-BBgwFoAUCzUUgePQlW6hOA49BJ3VBD5rJBMwNwYIKwYBBQUHAQEEKzApMCcGCCsG
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALKA4svC7YClfqwQG2TpVyvy
+p3OTo/ZC7zgbzYLTUXfEh3b15RfYDdorBwfTN4hM/S/A4PF5BPvnsbCA8ZW3HO8T
+ysAFtS1K8nhS2FNWIs3zgvusIuiuxRQ1372D9pCEFcez3K5sFunbqGL+ZoqFyNMN
+nAP47nHpq4v++XEACWpnkMnWQ+XY9BLWb0+D9ABY6XrfEZznKPsEg3ConTKAHKwz
+HHgPoCbMNykIQWUdHpVA4ibaPm1HC7VPe2d+civT9PD9DNcNKvGCES3A+S3UoL++
+aWXOPeimsot2y5za8Kb4DmuuXEf/sQ3N7/zUJ3vZF0r0FgiuvBg2LoskCeKe1CcC
+AwEAAaOByzCByDAdBgNVHQ4EFgQUpGbiRvc/oXOdouJOKZnbLjY2bLUwHwYDVR0j
+BBgwFoAUp1gB1dYAcdgoFyDgAQnspTmQfm4wNwYIKwYBBQUHAQEEKzApMCcGCCsG
AQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUwIzAh
oB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQEAwIB
-BjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBZUts6bC0EGwNp
-1DlWf0hwhDNwwtD6XVre+QtxNTzkV8/HJYnnPc9op1NfxmcJztHEJW/KWsYV0GyJ
-D/Xsh+xcmmH3Z2Yj5t8biPwDCwIiXfogks+OGw1ESAEJIWzLVRY2zbqnSMD/+w5A
-dT8ftJyLmu2nBTvHv4YiphP7jd1h4DAfYvsS18LtJV1we9+aVLMPZVwf4CpwPDgu
-0b9xl9XPZN3QVn2zK4gx6eN5KZsKvu+/8vNg6SC8fWClRKUjjQAiYl3ORckyaAN0
-OD4A+Z7Drgxy2MhTqtNAGWidtAP9CS18jytLfn1I7YL1BwdNjF1Kh298MG2uWzF/
-IG0D3jdN
+BjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCE6fsoCU5OHxzq
+xNLuVPr86wdVduiu4vTIo1chDuGoPkf+V4g9mnNxC3jWdzJr656owQoRThTIO+lh
+3HskTEQO1SN3nNOZmP9W0wD4pQHUhLqeND8lBrep1tTdy0LlEkv8sv4+QPfWtt2J
+iXsGtdEC13RKSF09+RPNa1p2r6wbCdDSlON0MC+oUao3bHUbew0s7jTxtBdqwfsX
+FgLlPZtKJydIgG3Nt/DCl9r1sjXIxg/kKKPTR+MzQtEfOLvgJja9ercnjvziWo/d
+P2lOmW+JzED2WZLkE4l7/gZ9wB/WvJ1p5VO9n2/kyaI4ZbevFUnx5GjhCQHSvZf/
+SlaqyVuw
-----END CERTIFICATE-----
diff --git a/chromium/net/data/cert_issuer_source_aia_unittest/i3.pem b/chromium/net/data/cert_issuer_source_aia_unittest/i3.pem
index 0b75f8cd3b6..733c03f464a 100644
--- a/chromium/net/data/cert_issuer_source_aia_unittest/i3.pem
+++ b/chromium/net/data/cert_issuer_source_aia_unittest/i3.pem
@@ -12,30 +12,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:b5:e8:71:e7:b5:df:bb:21:d3:c0:0f:1a:19:d7:
- 44:16:1b:b3:57:12:9c:73:16:fc:42:28:38:87:c6:
- f8:12:16:3b:3b:c4:1d:54:0d:5e:30:32:84:b3:89:
- 6d:d0:a9:e0:46:84:70:e1:e2:2f:e2:d8:9d:d8:a6:
- a9:2f:2a:e1:13:59:1b:e1:1e:fe:f6:31:62:55:9a:
- ee:5f:05:4c:5a:97:ce:2e:05:cb:cd:06:df:ee:ef:
- 50:0f:7b:29:1b:5d:2f:94:8a:75:02:70:a1:8b:a3:
- ac:06:10:8f:26:f0:23:19:08:e9:7c:c3:ee:77:98:
- 72:03:4b:c3:ce:ff:c5:de:5e:62:4b:ff:62:71:eb:
- 65:5a:1f:90:cd:4e:ef:fa:53:71:d4:fb:31:84:bc:
- 99:40:4b:5c:6c:9b:be:bd:ac:43:77:3b:9d:6a:02:
- 37:de:b6:e5:c2:6a:d5:2e:a9:87:28:6a:37:69:fa:
- 6b:2c:b1:8a:2f:b6:07:97:9d:9d:b6:2d:ec:22:33:
- da:98:eb:fd:39:35:49:24:a6:05:dc:c9:5c:74:cb:
- 61:46:8c:44:33:99:e5:30:e7:5f:73:c9:13:ad:6f:
- 90:df:d1:4e:fe:fd:04:26:fd:10:7d:79:db:8d:5c:
- ea:99:77:37:97:cd:9d:ee:7e:17:0d:f9:71:1c:80:
- 55:69
+ 00:b2:80:e2:cb:c2:ed:80:a5:7e:ac:10:1b:64:e9:
+ 57:2b:f2:a7:73:93:a3:f6:42:ef:38:1b:cd:82:d3:
+ 51:77:c4:87:76:f5:e5:17:d8:0d:da:2b:07:07:d3:
+ 37:88:4c:fd:2f:c0:e0:f1:79:04:fb:e7:b1:b0:80:
+ f1:95:b7:1c:ef:13:ca:c0:05:b5:2d:4a:f2:78:52:
+ d8:53:56:22:cd:f3:82:fb:ac:22:e8:ae:c5:14:35:
+ df:bd:83:f6:90:84:15:c7:b3:dc:ae:6c:16:e9:db:
+ a8:62:fe:66:8a:85:c8:d3:0d:9c:03:f8:ee:71:e9:
+ ab:8b:fe:f9:71:00:09:6a:67:90:c9:d6:43:e5:d8:
+ f4:12:d6:6f:4f:83:f4:00:58:e9:7a:df:11:9c:e7:
+ 28:fb:04:83:70:a8:9d:32:80:1c:ac:33:1c:78:0f:
+ a0:26:cc:37:29:08:41:65:1d:1e:95:40:e2:26:da:
+ 3e:6d:47:0b:b5:4f:7b:67:7e:72:2b:d3:f4:f0:fd:
+ 0c:d7:0d:2a:f1:82:11:2d:c0:f9:2d:d4:a0:bf:be:
+ 69:65:ce:3d:e8:a6:b2:8b:76:cb:9c:da:f0:a6:f8:
+ 0e:6b:ae:5c:47:ff:b1:0d:cd:ef:fc:d4:27:7b:d9:
+ 17:4a:f4:16:08:ae:bc:18:36:2e:8b:24:09:e2:9e:
+ d4:27
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 5D:B4:73:AA:1B:60:10:9E:0C:BC:16:BB:A4:0A:58:0D:B6:28:0E:04
+ A4:66:E2:46:F7:3F:A1:73:9D:A2:E2:4E:29:99:DB:2E:36:36:6C:B5
X509v3 Authority Key Identifier:
- keyid:0B:35:14:81:E3:D0:95:6E:A1:38:0E:3D:04:9D:D5:04:3E:6B:24:13
+ keyid:A7:58:01:D5:D6:00:71:D8:28:17:20:E0:01:09:EC:A5:39:90:7E:6E
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -50,39 +50,39 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 80:76:99:29:e2:95:11:a8:d8:05:69:81:46:d0:c2:fd:95:8f:
- 08:84:61:6f:80:53:6e:82:ad:70:0c:7c:7b:41:03:c8:e0:10:
- f6:61:26:3f:b9:49:5d:88:84:54:e1:4c:aa:d2:85:6f:91:96:
- d1:5a:c1:1b:74:4b:3a:fe:e0:b3:e8:01:65:69:c0:3a:a4:cd:
- d0:ca:1b:50:71:29:ef:e8:de:a6:e7:a0:89:1b:d2:36:6f:be:
- b1:32:84:29:f1:37:33:a7:62:f0:da:00:9c:51:6e:96:65:57:
- 18:5f:a8:7c:66:a9:b8:0f:8e:72:30:99:9a:db:40:eb:bd:a7:
- f4:80:10:ed:84:3b:d3:e3:64:f2:58:cf:4c:2b:ca:3c:56:ef:
- 6d:95:f5:8c:cf:86:c6:05:79:11:70:7b:24:58:60:66:60:42:
- 6f:92:75:d2:8b:1d:21:8a:5e:c6:5e:17:16:38:9f:73:6e:a0:
- a4:52:bb:17:c9:fb:c9:3d:0c:a9:a4:48:4e:b4:d7:9f:a3:34:
- 99:a0:83:6a:4f:2f:c6:a0:1c:5e:99:00:0a:24:af:6c:0b:ee:
- 2b:86:2d:9d:83:f6:3e:c1:3c:cb:8f:7d:a1:da:69:e1:18:af:
- e7:ec:0a:31:5a:42:06:46:fe:e0:d1:0a:1a:f5:eb:f2:b5:3e:
- 5d:b2:6e:86
+ 91:5a:ce:ad:61:f3:92:5b:39:09:96:fd:0d:86:7f:29:0d:a0:
+ 2b:95:a8:58:74:7d:e4:bd:c8:63:54:cc:a6:cc:0e:4c:a4:da:
+ c7:11:17:d8:0e:11:d2:a9:9d:81:02:6a:3e:f0:62:e1:93:5f:
+ a8:53:81:4c:82:a9:48:3f:cd:b3:c3:a2:4a:10:8e:f3:e6:a3:
+ 40:c2:54:ee:ce:e5:dd:66:3a:34:ff:bd:b3:dd:8d:37:da:34:
+ 77:cb:85:c6:9f:fb:cb:41:e9:60:46:76:35:62:71:a6:16:4f:
+ 88:d3:42:0a:69:3d:95:cc:85:08:ae:a8:73:0a:39:74:4c:d0:
+ 74:d2:cd:8a:d0:0d:3f:ab:ff:47:a1:a2:bb:ea:e5:7b:a2:ed:
+ c0:33:ca:17:cb:5f:2b:de:06:c6:0c:4d:5d:ca:3b:16:a2:ad:
+ 86:bd:c8:74:5e:08:19:ec:a7:cf:71:83:96:8b:e9:cb:d6:5d:
+ 35:88:0a:96:36:d3:6c:f7:56:40:a5:e2:9a:e2:f5:e6:8c:98:
+ be:27:dc:f1:f8:07:f0:d0:f0:0d:71:dc:5a:9b:7f:44:17:ad:
+ 31:c8:d2:e1:cc:e3:dc:50:a2:f5:40:2f:47:3a:00:04:e6:23:
+ cf:17:3b:f6:d2:01:f2:5f:88:ff:88:99:87:78:8d:d6:1f:45:
+ a6:21:38:cd
-----BEGIN CERTIFICATE-----
MIIDYjCCAkqgAwIBAgIBBDANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDDEKMAgGA1UEAwwBSTCC
-ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALXocee137sh08APGhnXRBYb
-s1cSnHMW/EIoOIfG+BIWOzvEHVQNXjAyhLOJbdCp4EaEcOHiL+LYndimqS8q4RNZ
-G+Ee/vYxYlWa7l8FTFqXzi4Fy80G3+7vUA97KRtdL5SKdQJwoYujrAYQjybwIxkI
-6XzD7neYcgNLw87/xd5eYkv/YnHrZVofkM1O7/pTcdT7MYS8mUBLXGybvr2sQ3c7
-nWoCN9625cJq1S6phyhqN2n6ayyxii+2B5ednbYt7CIz2pjr/Tk1SSSmBdzJXHTL
-YUaMRDOZ5TDnX3PJE61vkN/RTv79BCb9EH15241c6pl3N5fNne5+Fw35cRyAVWkC
-AwEAAaOByzCByDAdBgNVHQ4EFgQUXbRzqhtgEJ4MvBa7pApYDbYoDgQwHwYDVR0j
-BBgwFoAUCzUUgePQlW6hOA49BJ3VBD5rJBMwNwYIKwYBBQUHAQEEKzApMCcGCCsG
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALKA4svC7YClfqwQG2TpVyvy
+p3OTo/ZC7zgbzYLTUXfEh3b15RfYDdorBwfTN4hM/S/A4PF5BPvnsbCA8ZW3HO8T
+ysAFtS1K8nhS2FNWIs3zgvusIuiuxRQ1372D9pCEFcez3K5sFunbqGL+ZoqFyNMN
+nAP47nHpq4v++XEACWpnkMnWQ+XY9BLWb0+D9ABY6XrfEZznKPsEg3ConTKAHKwz
+HHgPoCbMNykIQWUdHpVA4ibaPm1HC7VPe2d+civT9PD9DNcNKvGCES3A+S3UoL++
+aWXOPeimsot2y5za8Kb4DmuuXEf/sQ3N7/zUJ3vZF0r0FgiuvBg2LoskCeKe1CcC
+AwEAAaOByzCByDAdBgNVHQ4EFgQUpGbiRvc/oXOdouJOKZnbLjY2bLUwHwYDVR0j
+BBgwFoAUp1gB1dYAcdgoFyDgAQnspTmQfm4wNwYIKwYBBQUHAQEEKzApMCcGCCsG
AQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUwIzAh
oB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQEAwIB
-BjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCAdpkp4pURqNgF
-aYFG0ML9lY8IhGFvgFNugq1wDHx7QQPI4BD2YSY/uUldiIRU4Uyq0oVvkZbRWsEb
-dEs6/uCz6AFlacA6pM3QyhtQcSnv6N6m56CJG9I2b76xMoQp8Tczp2Lw2gCcUW6W
-ZVcYX6h8Zqm4D45yMJma20Drvaf0gBDthDvT42TyWM9MK8o8Vu9tlfWMz4bGBXkR
-cHskWGBmYEJvknXSix0hil7GXhcWOJ9zbqCkUrsXyfvJPQyppEhOtNefozSZoINq
-Ty/GoBxemQAKJK9sC+4rhi2dg/Y+wTzLj32h2mnhGK/n7AoxWkIGRv7g0Qoa9evy
-tT5dsm6G
+BjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCRWs6tYfOSWzkJ
+lv0Nhn8pDaArlahYdH3kvchjVMymzA5MpNrHERfYDhHSqZ2BAmo+8GLhk1+oU4FM
+gqlIP82zw6JKEI7z5qNAwlTuzuXdZjo0/72z3Y032jR3y4XGn/vLQelgRnY1YnGm
+Fk+I00IKaT2VzIUIrqhzCjl0TNB00s2K0A0/q/9HoaK76uV7ou3AM8oXy18r3gbG
+DE1dyjsWoq2Gvch0XggZ7KfPcYOWi+nL1l01iAqWNtNs91ZApeKa4vXmjJi+J9zx
++Afw0PANcdxam39EF60xyNLhzOPcUKL1QC9HOgAE5iPPFzv20gHyX4j/iJmHeI3W
+H0WmITjN
-----END CERTIFICATE-----
diff --git a/chromium/net/data/cert_issuer_source_aia_unittest/target_file_aia.pem b/chromium/net/data/cert_issuer_source_aia_unittest/target_file_aia.pem
index 939b43264d6..d56a9ddb7b8 100644
--- a/chromium/net/data/cert_issuer_source_aia_unittest/target_file_aia.pem
+++ b/chromium/net/data/cert_issuer_source_aia_unittest/target_file_aia.pem
@@ -1,7 +1,7 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 1 (0x1)
+ Serial Number: 6 (0x6)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=I
Validity
@@ -12,30 +12,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:cb:ab:a2:68:53:6d:e0:0f:73:1a:db:9e:ce:57:
- 4a:6e:f1:b5:dc:18:b5:86:26:7d:ec:4b:9f:fd:9a:
- 66:8e:74:16:03:e9:39:f3:b6:f7:aa:fd:e9:f2:5d:
- a7:4b:62:21:65:c7:3b:5b:64:e3:ec:55:e6:bc:61:
- 3f:7e:ff:4b:b3:7a:ee:be:9f:b2:0d:84:50:dd:54:
- 65:43:0f:5b:bd:da:44:99:cc:13:94:41:aa:77:0d:
- fb:2f:69:36:ae:62:37:c9:97:1f:b5:9c:de:c8:b0:
- e4:dd:08:82:c5:a4:15:c5:aa:bb:83:ed:ac:14:fe:
- 41:7a:ee:de:0d:85:89:64:cf:bc:d5:17:2a:02:86:
- 0d:4b:a3:43:a0:3c:53:2f:34:ee:66:0e:3b:33:28:
- 7e:6d:2f:61:d3:f6:8f:a5:48:60:37:63:9d:b7:4b:
- 45:1a:f2:cb:d9:10:a6:cf:b6:6f:fb:e1:1c:98:b6:
- b9:85:cd:6e:93:a0:e2:a1:3c:f8:db:9e:4c:f7:39:
- 9e:aa:ce:b2:ae:c9:c8:44:84:75:52:7f:f4:df:2d:
- b0:7e:dd:da:01:b0:8e:d4:b4:b8:62:b1:fa:34:e3:
- dd:a0:4b:8d:b6:c6:bb:07:9f:4a:8c:2b:a1:a3:03:
- 54:2e:a0:eb:37:32:d6:61:b7:8a:32:64:c9:1e:80:
- b5:e1
+ 00:95:e3:c7:51:de:15:eb:d1:de:10:91:aa:8a:96:
+ 74:ba:7e:34:dc:7e:05:45:4e:6e:fc:0c:d9:bc:10:
+ af:cd:4d:df:b4:25:29:e7:3d:cd:3d:de:e6:e3:d9:
+ 9c:fd:ea:14:03:01:a3:76:bd:d1:5b:70:31:3d:12:
+ 1a:4b:ec:df:5f:1f:51:74:ed:3c:26:10:a7:35:88:
+ d3:02:22:d0:25:17:46:fa:b0:a9:ce:96:aa:8e:67:
+ c8:8e:8e:13:d9:0f:88:d4:61:d4:b7:07:1e:ca:26:
+ 5f:e2:a5:17:96:0a:6f:27:97:c2:5e:28:29:37:7c:
+ 1c:c7:ad:82:2b:2d:77:94:5e:85:00:b9:91:68:a2:
+ c6:27:b5:ea:83:8b:b7:ed:83:73:8b:c1:73:a7:40:
+ 72:44:51:09:58:e9:eb:ec:80:0a:12:c6:8e:45:18:
+ ce:9c:a0:2a:5f:14:0c:59:be:14:16:49:14:82:d6:
+ 40:6a:45:0a:7c:0c:3f:f3:53:cb:45:13:18:4e:0b:
+ c5:95:3c:de:e0:43:fe:5a:dc:ea:b5:44:f7:e7:6d:
+ 43:47:76:82:21:0a:60:cf:3e:28:f5:0f:c4:1a:41:
+ 62:12:30:8d:5d:92:44:91:5b:e1:cb:7f:2f:eb:12:
+ 9c:13:c5:87:d5:09:72:3d:b2:79:c1:a9:df:49:ba:
+ fd:cd
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 93:58:68:CA:53:0B:F3:5D:D1:47:89:54:CA:6D:D6:3B:18:38:66:C9
+ 82:52:F8:B3:52:A5:B3:49:4C:94:2B:57:7B:20:5D:41:1C:67:B9:00
X509v3 Authority Key Identifier:
- keyid:5D:B4:73:AA:1B:60:10:9E:0C:BC:16:BB:A4:0A:58:0D:B6:28:0E:04
+ keyid:A4:66:E2:46:F7:3F:A1:73:9D:A2:E2:4E:29:99:DB:2E:36:36:6C:B5
Authority Information Access:
CA Issuers - URI:file:///dev/null
@@ -50,39 +50,39 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 63:c8:4a:71:65:6f:3a:c1:a0:24:d9:cd:f0:2b:78:11:85:2a:
- ef:4e:c0:07:87:16:53:17:7e:5a:71:19:f7:04:73:2b:8a:20:
- 93:b3:96:43:df:ba:7a:0c:f5:d6:1d:92:8c:53:d3:4a:f8:5c:
- 82:e2:82:45:67:f0:d1:31:f9:4e:e0:27:ec:66:ec:49:a7:55:
- 96:08:e2:0b:d7:c7:c5:9a:08:3b:c5:b6:3a:f5:a7:09:57:15:
- 2f:42:8b:ca:90:d0:60:d6:e6:07:c9:65:ed:0c:4f:03:af:0f:
- e6:76:37:24:aa:ab:8f:8a:31:42:35:e5:29:41:0c:a8:d3:18:
- 8f:96:05:b6:89:61:70:6a:21:34:d9:09:e8:02:7c:11:e9:6f:
- f9:6b:5a:c4:e7:9d:3d:70:01:40:46:2e:8d:fd:f2:b4:0b:36:
- 54:d3:ce:f5:f0:ef:7e:e0:3d:35:01:75:65:bb:87:ca:36:d6:
- 5b:b8:a9:5b:ab:85:c1:9c:51:14:8b:a9:02:9b:70:ac:a3:87:
- 1c:bb:1e:0f:f6:10:87:04:28:7b:7a:0d:ed:41:0c:e6:7c:d6:
- 36:3e:79:29:26:dc:8f:b5:8b:55:3f:b8:bc:83:fb:dd:97:dc:
- 96:7f:25:46:5e:0a:eb:35:05:3c:4a:eb:c1:b3:38:99:09:5e:
- 86:1b:88:72
+ ae:95:9b:14:87:8a:f4:90:86:4f:07:95:89:88:3c:fd:4b:92:
+ 01:8b:00:4d:c4:45:b7:67:54:d8:19:0b:10:f6:c2:be:45:5b:
+ 63:f1:42:57:1a:5a:bd:f8:fc:ee:d6:d5:dc:0c:ee:73:a8:5e:
+ f2:d4:5b:f3:56:1b:28:d2:94:bc:3b:7d:a9:d5:4c:fb:5d:2f:
+ 4d:f2:04:3b:e5:12:ba:4d:9b:02:5e:6d:7e:aa:58:e6:45:3a:
+ 6f:66:10:b4:17:d1:3c:b4:c0:1d:42:f5:a7:61:00:9d:94:3f:
+ 3c:30:94:af:fe:ee:68:a7:ac:5b:d4:9a:3e:97:35:91:65:61:
+ d0:cb:0d:e6:af:0f:08:97:2f:0a:e4:97:3f:39:7a:8a:ca:9e:
+ 87:22:82:ef:c3:3e:ee:44:9a:37:95:85:76:39:37:7e:63:06:
+ b9:bd:70:ae:c0:8f:ff:6e:a2:a9:95:c2:be:91:0b:9f:70:de:
+ 4f:5b:3b:8a:c2:37:02:aa:52:ca:9d:d6:aa:48:0c:66:97:58:
+ 0e:48:f5:ab:c5:94:76:8a:c6:d9:06:20:62:72:0f:71:29:c3:
+ c5:16:57:45:12:d0:a7:7a:aa:9a:31:b4:f8:46:b6:f4:44:16:
+ 9a:5d:7d:dc:32:bf:53:77:79:4b:66:79:e5:9c:7a:30:41:6f:
+ 3f:b1:21:dc
-----BEGIN CERTIFICATE-----
-MIIDZDCCAkygAwIBAgIBATANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
+MIIDZDCCAkygAwIBAgIBBjANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
DTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowETEPMA0GA1UEAwwGdGFyZ2V0
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy6uiaFNt4A9zGtuezldK
-bvG13Bi1hiZ97Euf/ZpmjnQWA+k587b3qv3p8l2nS2IhZcc7W2Tj7FXmvGE/fv9L
-s3ruvp+yDYRQ3VRlQw9bvdpEmcwTlEGqdw37L2k2rmI3yZcftZzeyLDk3QiCxaQV
-xaq7g+2sFP5Beu7eDYWJZM+81RcqAoYNS6NDoDxTLzTuZg47Myh+bS9h0/aPpUhg
-N2Odt0tFGvLL2RCmz7Zv++EcmLa5hc1uk6DioTz4255M9zmeqs6yrsnIRIR1Un/0
-3y2wft3aAbCO1LS4YrH6NOPdoEuNtsa7B59KjCuhowNULqDrNzLWYbeKMmTJHoC1
-4QIDAQABo4HLMIHIMB0GA1UdDgQWBBSTWGjKUwvzXdFHiVTKbdY7GDhmyTAfBgNV
-HSMEGDAWgBRdtHOqG2AQngy8FrukClgNtigOBDAsBggrBgEFBQcBAQQgMB4wHAYI
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlePHUd4V69HeEJGqipZ0
+un403H4FRU5u/AzZvBCvzU3ftCUp5z3NPd7m49mc/eoUAwGjdr3RW3AxPRIaS+zf
+Xx9RdO08JhCnNYjTAiLQJRdG+rCpzpaqjmfIjo4T2Q+I1GHUtwceyiZf4qUXlgpv
+J5fCXigpN3wcx62CKy13lF6FALmRaKLGJ7Xqg4u37YNzi8Fzp0ByRFEJWOnr7IAK
+EsaORRjOnKAqXxQMWb4UFkkUgtZAakUKfAw/81PLRRMYTgvFlTze4EP+WtzqtUT3
+521DR3aCIQpgzz4o9Q/EGkFiEjCNXZJEkVvhy38v6xKcE8WH1QlyPbJ5wanfSbr9
+zQIDAQABo4HLMIHIMB0GA1UdDgQWBBSCUvizUqWzSUyUK1d7IF1BHGe5ADAfBgNV
+HSMEGDAWgBSkZuJG9z+hc52i4k4pmdsuNjZstTAsBggrBgEFBQcBAQQgMB4wHAYI
KwYBBQUHMAKGEGZpbGU6Ly8vZGV2L251bGwwKQYDVR0fBCIwIDAeoBygGoYYaHR0
cDovL3VybC1mb3ItY3JsL0kuY3JsMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAU
-BggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAGPISnFlbzrB
-oCTZzfAreBGFKu9OwAeHFlMXflpxGfcEcyuKIJOzlkPfunoM9dYdkoxT00r4XILi
-gkVn8NEx+U7gJ+xm7EmnVZYI4gvXx8WaCDvFtjr1pwlXFS9Ci8qQ0GDW5gfJZe0M
-TwOvD+Z2NySqq4+KMUI15SlBDKjTGI+WBbaJYXBqITTZCegCfBHpb/lrWsTnnT1w
-AUBGLo398rQLNlTTzvXw737gPTUBdWW7h8o21lu4qVurhcGcURSLqQKbcKyjhxy7
-Hg/2EIcEKHt6De1BDOZ81jY+eSkm3I+1i1U/uLyD+92X3JZ/JUZeCus1BTxK68Gz
-OJkJXoYbiHI=
+BggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAK6VmxSHivSQ
+hk8HlYmIPP1LkgGLAE3ERbdnVNgZCxD2wr5FW2PxQlcaWr34/O7W1dwM7nOoXvLU
+W/NWGyjSlLw7fanVTPtdL03yBDvlErpNmwJebX6qWOZFOm9mELQX0Ty0wB1C9adh
+AJ2UPzwwlK/+7minrFvUmj6XNZFlYdDLDeavDwiXLwrklz85eorKnocigu/DPu5E
+mjeVhXY5N35jBrm9cK7Aj/9uoqmVwr6RC59w3k9bO4rCNwKqUsqd1qpIDGaXWA5I
+9avFlHaKxtkGIGJyD3Epw8UWV0US0Kd6qpoxtPhGtvREFppdfdwyv1N3eUtmeeWc
+ejBBbz+xIdw=
-----END CERTIFICATE-----
diff --git a/chromium/net/data/cert_issuer_source_aia_unittest/target_file_and_http_aia.pem b/chromium/net/data/cert_issuer_source_aia_unittest/target_file_and_http_aia.pem
index fcb83805e53..01189a43268 100644
--- a/chromium/net/data/cert_issuer_source_aia_unittest/target_file_and_http_aia.pem
+++ b/chromium/net/data/cert_issuer_source_aia_unittest/target_file_and_http_aia.pem
@@ -1,7 +1,7 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 1 (0x1)
+ Serial Number: 8 (0x8)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=I
Validity
@@ -12,30 +12,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:93:55:05:d1:f9:d4:37:0d:7f:33:9d:9e:9b:c7:
- 88:e0:67:11:10:5b:29:5d:ce:b4:19:69:d6:28:90:
- 2e:0b:51:4f:4d:b9:9c:79:10:f8:25:01:01:35:9d:
- 59:e9:79:3b:c6:65:c5:c9:f2:56:4e:7c:50:14:4a:
- c8:5c:d0:87:aa:36:92:7b:74:58:e3:cd:ed:39:f0:
- 18:f7:97:5a:60:d5:81:92:a1:da:1a:9d:9c:51:bc:
- 39:86:42:d4:41:29:b7:05:4c:76:b0:50:f0:3e:58:
- 13:21:70:01:6e:9b:83:f3:26:45:de:f0:cc:e7:d6:
- dd:33:e3:72:b5:91:de:cd:09:b7:a1:b6:77:53:e2:
- 6e:16:37:3a:2c:41:e0:51:de:1d:7f:13:0d:9d:4b:
- 4e:7d:eb:a9:95:67:16:4d:7d:4d:7a:bb:81:6d:a0:
- d7:99:11:8d:1c:09:fb:ab:1a:b1:09:33:1e:61:b0:
- a6:5c:19:49:f3:95:f8:1f:c7:c3:33:7d:32:ff:59:
- 8d:84:61:6c:fd:94:1a:46:48:e1:bd:41:34:18:e2:
- de:8e:af:9f:f8:f3:08:06:9d:b0:71:a5:1e:9e:d6:
- 58:d5:7a:50:fb:ac:06:66:ab:8e:9e:53:11:79:bb:
- 98:0a:6f:94:a7:6c:5a:f4:e2:6a:1a:e0:60:3c:92:
- d4:f5
+ 00:b8:a6:54:ad:e4:b3:01:6f:af:23:15:bc:3c:aa:
+ 51:59:1e:7e:65:23:a3:06:a7:4d:76:65:61:6c:c8:
+ 4c:6e:40:d8:92:40:2a:ed:09:cd:4d:fc:b4:ee:88:
+ 68:16:66:15:bc:96:6f:65:40:02:3c:76:7c:87:f1:
+ 93:f6:fa:92:90:7d:83:8a:81:73:01:95:e5:b6:3c:
+ 34:08:e9:3e:29:0f:61:db:79:b0:c5:b0:3d:ef:ba:
+ fc:7f:9d:a1:db:ef:bc:5c:5f:67:94:03:2e:e0:f6:
+ 87:d1:6d:77:49:b0:f0:ed:6c:bd:75:c6:31:85:6e:
+ d4:09:81:93:10:81:82:3f:32:04:ad:b9:02:20:ec:
+ 1f:28:49:83:47:8a:c2:f1:3b:f4:de:52:e4:da:5f:
+ 8c:8e:69:50:fb:bd:21:cb:b2:55:69:98:a1:ec:2e:
+ 27:3e:25:95:aa:0d:0e:d7:01:28:d8:00:b8:1f:d2:
+ 85:9b:71:f6:c5:70:78:2d:c6:a4:c2:39:56:39:0a:
+ ac:89:17:6a:8d:47:a4:e4:6a:e9:84:68:14:22:4c:
+ 6e:e7:87:59:7f:40:52:c7:20:46:b0:21:bd:42:a0:
+ f0:a5:78:b9:6f:fd:5f:6e:2f:50:61:9c:88:a6:54:
+ 69:da:fe:86:ab:7b:29:34:56:8d:d1:6d:82:33:f1:
+ 87:e3
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 88:DC:98:76:9C:48:31:39:F2:B6:33:65:7A:B2:7D:26:A9:88:7F:D9
+ B6:F3:8F:73:17:0E:1C:CC:AB:23:8A:20:23:9F:27:84:1A:D9:D2:74
X509v3 Authority Key Identifier:
- keyid:5D:B4:73:AA:1B:60:10:9E:0C:BC:16:BB:A4:0A:58:0D:B6:28:0E:04
+ keyid:A4:66:E2:46:F7:3F:A1:73:9D:A2:E2:4E:29:99:DB:2E:36:36:6C:B5
Authority Information Access:
CA Issuers - URI:file:///dev/null
@@ -51,39 +51,39 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 71:d3:a2:5f:4b:d9:5a:e9:10:29:60:af:fd:40:f5:74:e0:f3:
- d3:2c:7c:37:df:05:9d:09:3f:8d:ac:1e:ca:8a:f1:ca:f6:c8:
- 00:86:0b:b1:4f:23:18:c9:c2:35:db:be:08:77:1f:66:67:b3:
- a6:28:71:d5:80:25:88:ea:8d:eb:32:c4:b5:2a:03:5b:1e:e9:
- 76:4d:22:71:b0:44:9e:c2:dc:52:11:a4:3c:23:d5:6f:0a:c8:
- 2b:91:52:1a:1b:10:d3:01:4a:f4:ec:a9:d9:5d:63:bf:41:51:
- aa:18:54:ce:70:5d:5f:db:95:7e:c4:a4:37:bf:fc:f1:72:03:
- c1:00:6e:82:e7:ae:bf:ea:2f:e4:c5:e5:69:d0:34:b3:5b:20:
- 53:8c:a5:be:d9:49:4b:1c:10:76:37:45:ef:18:3c:95:49:08:
- a0:bb:ae:d8:01:a0:22:ab:90:2b:f6:42:46:b1:5c:bd:1d:e6:
- 60:3a:b0:6a:b0:9a:70:eb:7a:27:ed:3b:af:e0:ca:2a:37:36:
- dc:6d:f2:52:b4:2c:3f:90:fe:fd:93:83:da:3e:65:ee:9b:22:
- 11:6a:02:c9:93:4e:24:c1:6c:25:09:9d:66:3f:05:13:fa:e3:
- 6e:e6:6e:43:e4:b9:04:0e:35:5f:11:cc:03:28:ed:b2:11:00:
- de:5b:b2:d7
+ 65:53:d0:30:a2:fe:7a:a1:9f:8b:56:d6:e8:0f:75:a1:5f:e1:
+ b1:e3:4c:11:9c:cc:30:a9:a9:65:cc:fa:9c:d3:c8:0a:0f:c7:
+ 4e:58:3a:8a:ce:86:65:70:81:64:2e:ff:ea:e1:f2:77:73:bb:
+ 59:64:eb:22:ee:a1:91:05:ad:09:f2:55:69:ef:27:1c:3c:79:
+ 36:9c:f5:ae:b0:73:c6:25:2b:3d:c5:0c:a8:66:44:1e:55:a4:
+ 5f:ff:e6:fc:74:3f:18:ac:cf:1a:8e:49:91:73:e8:43:e4:33:
+ 96:91:78:f5:5f:02:36:98:26:28:8a:8b:6a:33:ed:ec:b3:f3:
+ 3d:29:d5:a5:9f:d3:e5:cb:09:d9:65:da:78:10:99:dc:3b:4b:
+ 48:7f:c2:8a:14:06:2d:b0:50:d3:45:ba:8c:0c:ee:d9:44:5f:
+ fa:9d:44:00:b9:78:e6:70:76:58:98:d5:e3:81:47:3b:c3:b3:
+ 17:ef:3e:c8:14:e9:2a:4b:41:17:28:1e:7a:19:aa:8c:79:48:
+ 89:b8:7f:e2:f2:7c:aa:dc:70:ed:e0:1c:61:18:58:8a:a0:a7:
+ 86:18:36:11:8b:17:bf:59:eb:03:6c:32:e0:05:01:b7:44:9f:
+ b7:2d:fc:7d:5c:93:86:ec:b8:30:fd:be:6e:29:a2:08:2a:cd:
+ 88:29:20:8e
-----BEGIN CERTIFICATE-----
-MIIDjDCCAnSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
+MIIDjDCCAnSgAwIBAgIBCDANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
DTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowETEPMA0GA1UEAwwGdGFyZ2V0
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk1UF0fnUNw1/M52em8eI
-4GcREFspXc60GWnWKJAuC1FPTbmceRD4JQEBNZ1Z6Xk7xmXFyfJWTnxQFErIXNCH
-qjaSe3RY483tOfAY95daYNWBkqHaGp2cUbw5hkLUQSm3BUx2sFDwPlgTIXABbpuD
-8yZF3vDM59bdM+NytZHezQm3obZ3U+JuFjc6LEHgUd4dfxMNnUtOfeuplWcWTX1N
-eruBbaDXmRGNHAn7qxqxCTMeYbCmXBlJ85X4H8fDM30y/1mNhGFs/ZQaRkjhvUE0
-GOLejq+f+PMIBp2wcaUentZY1XpQ+6wGZquOnlMRebuYCm+Up2xa9OJqGuBgPJLU
-9QIDAQABo4HzMIHwMB0GA1UdDgQWBBSI3Jh2nEgxOfK2M2V6sn0mqYh/2TAfBgNV
-HSMEGDAWgBRdtHOqG2AQngy8FrukClgNtigOBDBUBggrBgEFBQcBAQRIMEYwHAYI
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKZUreSzAW+vIxW8PKpR
+WR5+ZSOjBqdNdmVhbMhMbkDYkkAq7QnNTfy07ohoFmYVvJZvZUACPHZ8h/GT9vqS
+kH2DioFzAZXltjw0COk+KQ9h23mwxbA977r8f52h2++8XF9nlAMu4PaH0W13SbDw
+7Wy9dcYxhW7UCYGTEIGCPzIErbkCIOwfKEmDR4rC8Tv03lLk2l+MjmlQ+70hy7JV
+aZih7C4nPiWVqg0O1wEo2AC4H9KFm3H2xXB4LcakwjlWOQqsiRdqjUek5GrphGgU
+Ikxu54dZf0BSxyBGsCG9QqDwpXi5b/1fbi9QYZyIplRp2v6Gq3spNFaN0W2CM/GH
+4wIDAQABo4HzMIHwMB0GA1UdDgQWBBS2849zFw4czKsjiiAjnyeEGtnSdDAfBgNV
+HSMEGDAWgBSkZuJG9z+hc52i4k4pmdsuNjZstTBUBggrBgEFBQcBAQRIMEYwHAYI
KwYBBQUHMAKGEGZpbGU6Ly8vZGV2L251bGwwJgYIKwYBBQUHMAKGGmh0dHA6Ly91
cmwtZm9yLWFpYTIvSTIuZm9vMCkGA1UdHwQiMCAwHqAcoBqGGGh0dHA6Ly91cmwt
Zm9yLWNybC9JLmNybDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUH
-AwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBx06JfS9la6RApYK/9QPV0
-4PPTLHw33wWdCT+NrB7KivHK9sgAhguxTyMYycI1274Idx9mZ7OmKHHVgCWI6o3r
-MsS1KgNbHul2TSJxsESewtxSEaQ8I9VvCsgrkVIaGxDTAUr07KnZXWO/QVGqGFTO
-cF1f25V+xKQ3v/zxcgPBAG6C566/6i/kxeVp0DSzWyBTjKW+2UlLHBB2N0XvGDyV
-SQigu67YAaAiq5Ar9kJGsVy9HeZgOrBqsJpw63on7Tuv4MoqNzbcbfJStCw/kP79
-k4PaPmXumyIRagLJk04kwWwlCZ1mPwUT+uNu5m5D5LkEDjVfEcwDKO2yEQDeW7LX
+AwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBlU9Awov56oZ+LVtboD3Wh
+X+Gx40wRnMwwqallzPqc08gKD8dOWDqKzoZlcIFkLv/q4fJ3c7tZZOsi7qGRBa0J
+8lVp7yccPHk2nPWusHPGJSs9xQyoZkQeVaRf/+b8dD8YrM8ajkmRc+hD5DOWkXj1
+XwI2mCYoiotqM+3ss/M9KdWln9PlywnZZdp4EJncO0tIf8KKFAYtsFDTRbqMDO7Z
+RF/6nUQAuXjmcHZYmNXjgUc7w7MX7z7IFOkqS0EXKB56GaqMeUiJuH/i8nyq3HDt
+4BxhGFiKoKeGGDYRixe/WesDbDLgBQG3RJ+3Lfx9XJOG7Lgw/b5uKaIIKs2IKSCO
-----END CERTIFICATE-----
diff --git a/chromium/net/data/cert_issuer_source_aia_unittest/target_invalid_and_http_aia.pem b/chromium/net/data/cert_issuer_source_aia_unittest/target_invalid_and_http_aia.pem
index 75849659373..6ed879f3fe2 100644
--- a/chromium/net/data/cert_issuer_source_aia_unittest/target_invalid_and_http_aia.pem
+++ b/chromium/net/data/cert_issuer_source_aia_unittest/target_invalid_and_http_aia.pem
@@ -1,7 +1,7 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 1 (0x1)
+ Serial Number: 9 (0x9)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=I
Validity
@@ -12,30 +12,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:ae:5d:18:71:d9:81:dc:0d:29:3f:0c:ce:dc:3e:
- 00:69:7e:c9:5a:e4:4a:f8:4d:6c:3d:f3:76:0f:ab:
- 64:37:df:e1:59:f9:ee:1e:4f:5b:5f:5a:0e:a7:00:
- 1d:60:7e:cc:35:e7:5e:00:a6:a2:33:10:af:07:14:
- 46:26:47:3a:02:cf:7f:60:e5:59:da:64:88:1e:ff:
- 89:f3:27:82:db:aa:9e:12:a0:5a:73:ea:ca:ac:8b:
- c9:03:fc:4c:76:f5:2d:b6:d0:05:42:78:2f:dc:5a:
- 47:e4:92:66:0e:8b:05:f1:2d:fb:da:3b:74:24:74:
- d4:9b:40:15:a0:a2:a4:03:0b:24:99:eb:9d:e1:b9:
- 9a:0c:6e:63:95:37:bf:c9:7a:5d:a5:3f:84:49:e0:
- d4:44:e5:17:4d:45:5f:5f:89:d8:28:98:03:1e:9c:
- 98:95:ab:7e:59:2c:3b:8f:82:92:14:d5:b4:ea:52:
- 10:e8:c5:3d:29:59:de:87:3e:d7:6f:36:41:a8:34:
- ee:9c:e5:53:fd:b1:60:18:24:05:81:d9:53:fa:12:
- 45:3e:23:17:d2:e2:6f:d4:9a:53:ac:f8:b6:26:6d:
- 88:0f:bc:f2:d9:f9:a7:bc:d3:23:b8:de:02:42:1b:
- a6:e0:93:c2:5e:ce:25:a4:4b:9b:9d:de:c9:29:b1:
- 73:6b
+ 00:b4:31:1e:0c:43:8e:90:3e:2c:0e:a0:71:58:70:
+ aa:3a:92:51:14:b6:3f:b3:43:2c:3d:0a:74:0c:30:
+ 48:34:76:90:57:e4:80:f2:8d:ec:5d:02:95:94:9e:
+ 5d:04:49:28:49:d9:6e:81:47:57:69:be:b3:4a:5e:
+ f5:65:2f:f1:66:a5:8f:63:98:ee:3b:97:09:7f:d9:
+ 65:57:00:80:55:f1:ae:42:af:a7:56:3a:b4:5b:b5:
+ 85:55:8d:40:d3:f7:7b:c8:fd:45:af:f4:95:9a:f2:
+ 72:18:89:2c:90:4d:3c:73:c2:eb:91:d0:d5:75:ec:
+ fd:80:89:c3:12:a5:99:3b:d0:00:0b:a3:c4:2a:2c:
+ 62:a0:8b:97:4f:51:2f:83:07:57:f4:8f:50:a1:62:
+ 4d:2e:69:cd:25:5a:16:30:10:de:a8:0b:3b:7b:58:
+ 64:33:08:ff:4d:e2:06:1a:03:bd:f4:02:90:d2:ed:
+ 05:0b:b5:4a:36:d1:d1:f0:f5:44:0d:16:a2:3c:ca:
+ 20:0b:36:c9:0e:70:9e:bc:d8:11:d4:fe:2b:49:71:
+ 91:6d:c8:83:6d:45:75:e7:e1:63:53:7d:74:a6:34:
+ 18:d4:66:77:c9:04:79:09:08:46:f4:b1:21:f5:19:
+ 92:53:7b:74:1b:84:83:01:6f:1e:ac:9d:09:1e:9b:
+ 2f:9d
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 70:30:09:0C:81:B0:13:AF:D5:9F:37:C7:F4:F2:B7:02:35:CD:6A:49
+ A7:11:A2:44:B9:CC:AA:AD:09:63:9D:D6:9D:E1:76:32:A9:F4:A5:7B
X509v3 Authority Key Identifier:
- keyid:5D:B4:73:AA:1B:60:10:9E:0C:BC:16:BB:A4:0A:58:0D:B6:28:0E:04
+ keyid:A4:66:E2:46:F7:3F:A1:73:9D:A2:E2:4E:29:99:DB:2E:36:36:6C:B5
Authority Information Access:
CA Issuers - URI:foobar
@@ -51,39 +51,39 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 19:45:88:2b:f2:b7:12:b2:91:06:82:b5:05:26:20:4e:2f:ce:
- c1:32:b7:2d:6b:9c:ec:68:a0:6f:73:63:d8:dc:5c:68:ea:37:
- e6:a7:cf:df:1d:70:3d:88:29:3d:03:8b:fc:09:d9:c3:ef:53:
- 35:4e:6e:8d:e1:8a:7c:cb:6d:1a:0e:64:69:bf:82:7f:b7:a5:
- 09:dc:be:2a:4a:7e:e4:91:a5:1e:41:ce:e3:47:f6:20:81:c7:
- b0:b0:5c:9c:09:bf:e7:66:8d:a8:89:53:9a:aa:c1:21:f1:e9:
- a0:1a:e0:71:c7:d9:ff:8c:b9:f2:3f:eb:9d:68:43:1b:69:18:
- fe:d9:60:54:c3:08:7c:3b:64:e7:43:fd:11:05:22:50:9d:37:
- c4:1e:cf:f4:5c:6b:0c:e9:be:c0:41:0b:83:59:4c:37:29:7e:
- d5:41:04:6d:d4:4a:b7:13:d9:2a:d2:f6:05:4d:69:5e:08:3f:
- bc:04:e7:1f:0a:d2:94:7b:35:e2:64:43:e3:0b:d6:d1:73:de:
- 57:7c:3f:a4:08:72:5b:cf:43:de:b0:3c:d8:72:34:df:6b:73:
- f3:e7:23:0e:a1:7e:e4:5c:ab:f2:66:54:d3:f3:e1:70:f5:ef:
- 1e:04:89:11:51:6f:48:77:09:13:68:2c:5a:c7:7e:36:9f:0b:
- 4b:ae:f5:f9
+ 56:74:27:6f:5f:7b:a4:b5:c4:62:98:ae:70:4e:a9:92:44:fd:
+ 78:17:54:d0:ed:02:62:ad:cd:7a:28:09:56:16:9f:42:10:e2:
+ 9b:d4:d5:3b:8d:f6:97:a5:2a:c3:42:54:14:31:e9:7a:a8:23:
+ 00:69:41:6b:9d:c3:af:e4:fb:ad:6c:a4:ff:51:0b:c5:de:ae:
+ 69:9b:d9:fd:79:50:59:8e:5f:1e:b4:e8:35:c3:de:f1:c5:6e:
+ 2f:19:98:b5:b9:31:ac:b2:f5:ef:9c:9f:11:c9:82:5d:73:36:
+ f5:74:d1:af:b4:8d:a2:c3:e1:bb:90:4c:f8:dc:fe:68:2f:ec:
+ ef:c4:b2:4c:7b:24:1d:b5:58:1f:e4:c0:70:a6:68:f8:a3:a9:
+ 4a:2c:95:35:09:2b:23:c2:4d:29:09:cc:f3:85:1f:fc:77:76:
+ eb:f4:d0:0a:6a:cb:df:aa:e1:79:6d:53:8b:0b:9a:03:99:9a:
+ 27:84:6d:25:bf:68:b2:25:0b:ca:bd:a1:01:83:45:0b:2d:3a:
+ 2f:08:07:01:85:29:10:de:e0:82:68:30:20:78:79:a2:7e:fc:
+ f0:5e:f2:f5:91:b4:55:2a:8d:89:3e:62:6f:ee:12:47:16:0b:
+ 41:e3:2d:42:e1:9f:09:10:7c:9f:62:99:b1:67:66:ce:a8:06:
+ 5a:fd:05:d3
-----BEGIN CERTIFICATE-----
-MIIDgjCCAmqgAwIBAgIBATANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
+MIIDgjCCAmqgAwIBAgIBCTANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
DTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowETEPMA0GA1UEAwwGdGFyZ2V0
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArl0YcdmB3A0pPwzO3D4A
-aX7JWuRK+E1sPfN2D6tkN9/hWfnuHk9bX1oOpwAdYH7MNedeAKaiMxCvBxRGJkc6
-As9/YOVZ2mSIHv+J8yeC26qeEqBac+rKrIvJA/xMdvUtttAFQngv3FpH5JJmDosF
-8S372jt0JHTUm0AVoKKkAwskmeud4bmaDG5jlTe/yXpdpT+ESeDUROUXTUVfX4nY
-KJgDHpyYlat+WSw7j4KSFNW06lIQ6MU9KVnehz7XbzZBqDTunOVT/bFgGCQFgdlT
-+hJFPiMX0uJv1JpTrPi2Jm2ID7zy2fmnvNMjuN4CQhum4JPCXs4lpEubnd7JKbFz
-awIDAQABo4HpMIHmMB0GA1UdDgQWBBRwMAkMgbATr9WfN8f08rcCNc1qSTAfBgNV
-HSMEGDAWgBRdtHOqG2AQngy8FrukClgNtigOBDBKBggrBgEFBQcBAQQ+MDwwEgYI
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtDEeDEOOkD4sDqBxWHCq
+OpJRFLY/s0MsPQp0DDBINHaQV+SA8o3sXQKVlJ5dBEkoSdlugUdXab6zSl71ZS/x
+ZqWPY5juO5cJf9llVwCAVfGuQq+nVjq0W7WFVY1A0/d7yP1Fr/SVmvJyGIkskE08
+c8LrkdDVdez9gInDEqWZO9AAC6PEKixioIuXT1EvgwdX9I9QoWJNLmnNJVoWMBDe
+qAs7e1hkMwj/TeIGGgO99AKQ0u0FC7VKNtHR8PVEDRaiPMogCzbJDnCevNgR1P4r
+SXGRbciDbUV15+FjU310pjQY1GZ3yQR5CQhG9LEh9RmSU3t0G4SDAW8erJ0JHpsv
+nQIDAQABo4HpMIHmMB0GA1UdDgQWBBSnEaJEucyqrQljndad4XYyqfSlezAfBgNV
+HSMEGDAWgBSkZuJG9z+hc52i4k4pmdsuNjZstTBKBggrBgEFBQcBAQQ+MDwwEgYI
KwYBBQUHMAKGBmZvb2JhcjAmBggrBgEFBQcwAoYaaHR0cDovL3VybC1mb3ItYWlh
Mi9JMi5mb28wKQYDVR0fBCIwIDAeoBygGoYYaHR0cDovL3VybC1mb3ItY3JsL0ku
Y3JsMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
-AwIwDQYJKoZIhvcNAQELBQADggEBABlFiCvytxKykQaCtQUmIE4vzsEyty1rnOxo
-oG9zY9jcXGjqN+anz98dcD2IKT0Di/wJ2cPvUzVObo3hinzLbRoOZGm/gn+3pQnc
-vipKfuSRpR5BzuNH9iCBx7CwXJwJv+dmjaiJU5qqwSHx6aAa4HHH2f+MufI/651o
-QxtpGP7ZYFTDCHw7ZOdD/REFIlCdN8Qez/RcawzpvsBBC4NZTDcpftVBBG3USrcT
-2SrS9gVNaV4IP7wE5x8K0pR7NeJkQ+ML1tFz3ld8P6QIclvPQ96wPNhyNN9rc/Pn
-Iw6hfuRcq/JmVNPz4XD17x4EiRFRb0h3CRNoLFrHfjafC0uu9fk=
+AwIwDQYJKoZIhvcNAQELBQADggEBAFZ0J29fe6S1xGKYrnBOqZJE/XgXVNDtAmKt
+zXooCVYWn0IQ4pvU1TuN9pelKsNCVBQx6XqoIwBpQWudw6/k+61spP9RC8Xermmb
+2f15UFmOXx606DXD3vHFbi8ZmLW5Mayy9e+cnxHJgl1zNvV00a+0jaLD4buQTPjc
+/mgv7O/Eskx7JB21WB/kwHCmaPijqUoslTUJKyPCTSkJzPOFH/x3duv00Apqy9+q
+4XltU4sLmgOZmieEbSW/aLIlC8q9oQGDRQstOi8IBwGFKRDe4IJoMCB4eaJ+/PBe
+8vWRtFUqjYk+Ym/uEkcWC0HjLULhnwkQfJ9imbFnZs6oBlr9BdM=
-----END CERTIFICATE-----
diff --git a/chromium/net/data/cert_issuer_source_aia_unittest/target_invalid_url_aia.pem b/chromium/net/data/cert_issuer_source_aia_unittest/target_invalid_url_aia.pem
index 772f70799c5..0eed1d0f0b1 100644
--- a/chromium/net/data/cert_issuer_source_aia_unittest/target_invalid_url_aia.pem
+++ b/chromium/net/data/cert_issuer_source_aia_unittest/target_invalid_url_aia.pem
@@ -1,7 +1,7 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 1 (0x1)
+ Serial Number: 7 (0x7)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=I
Validity
@@ -12,30 +12,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:c2:66:b1:44:0d:14:14:8a:15:54:3e:12:20:94:
- 9d:a7:97:92:dd:20:67:f0:d5:e8:2d:a4:d6:9a:e8:
- 12:04:8c:cf:a3:94:3f:9b:e6:20:7d:c0:b5:9c:50:
- f7:6f:8e:e4:a7:2a:de:ad:45:d0:87:e9:8a:05:68:
- 3a:3e:fc:16:0f:be:86:10:0a:5b:1d:7f:84:15:d9:
- ec:d9:27:20:a4:d7:93:93:3d:15:54:da:29:6e:70:
- d5:81:57:b7:50:4b:ea:83:9e:99:77:a7:bd:5d:44:
- 35:31:84:51:e1:29:2c:6f:14:56:b9:4a:7d:4f:92:
- 3a:90:60:77:0a:20:30:e6:5c:0b:f8:d9:f4:3b:ed:
- d9:64:ec:07:7f:15:5e:e5:67:43:d0:1e:06:25:a0:
- 2c:fb:89:17:61:e8:aa:99:28:3a:97:ec:37:d9:32:
- f0:a4:4e:ab:b4:d9:03:c9:33:5a:5f:7b:a7:a0:0c:
- 14:b7:34:f9:2b:59:39:29:15:48:0f:c7:47:90:ff:
- 9f:dc:fc:b7:30:35:0b:59:28:82:20:d7:9d:f0:50:
- fc:2a:2c:9b:b7:84:28:7a:74:b5:c4:14:44:ed:09:
- bd:df:51:e1:ab:b0:e0:c0:47:6c:e9:ed:48:df:ec:
- 74:6a:b2:bb:ec:45:ea:38:f9:05:c7:f1:c7:5e:ac:
- a7:2b
+ 00:c7:27:f1:17:3f:71:b3:2a:98:b1:c0:c0:45:e2:
+ 0f:da:92:27:6e:44:6d:18:4d:87:b9:eb:c0:63:c9:
+ 2d:24:75:7a:15:85:68:3a:cc:cc:a5:9b:7f:82:c0:
+ 02:86:76:f9:28:b2:f7:2c:f3:48:bb:6d:17:11:38:
+ 4d:5e:86:bf:8a:89:e8:0f:70:c6:a6:81:bd:d1:92:
+ cd:eb:c0:99:90:3c:51:ca:14:d9:dd:75:66:17:1c:
+ 52:c2:d8:3e:8a:6b:0d:94:32:54:a6:b0:35:b9:5a:
+ 58:b0:80:28:38:2e:f1:c9:2f:b2:30:80:e5:05:c5:
+ b2:5b:6f:41:30:27:fd:02:7a:89:b1:74:90:cb:1f:
+ da:25:1d:7b:b7:00:2a:bf:0b:9c:5f:8b:25:ca:ae:
+ c5:56:33:1a:a2:72:a9:3c:23:8a:bc:3d:d2:50:0f:
+ 1a:0b:09:cc:c3:49:1b:81:c6:e1:aa:a5:db:68:cc:
+ 97:02:0f:1b:0d:c3:da:e0:c2:b8:18:8d:9f:04:37:
+ c5:65:79:30:2f:58:5a:21:a4:df:b2:85:c0:ec:59:
+ cf:8c:2a:c6:f3:8e:f8:56:95:63:b6:67:6e:4e:07:
+ 61:6d:34:17:36:fe:57:e7:a2:2d:8d:ce:71:86:53:
+ 2c:a2:07:02:f7:e2:a2:b9:5b:28:fa:bd:5c:70:15:
+ 55:69
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- F1:C8:46:B7:E9:34:24:E7:C2:B4:CE:06:55:77:26:63:34:BF:0E:7F
+ 67:BE:87:AA:D9:FB:88:9C:E8:F8:14:D3:FC:8E:44:95:EE:7D:7C:4E
X509v3 Authority Key Identifier:
- keyid:5D:B4:73:AA:1B:60:10:9E:0C:BC:16:BB:A4:0A:58:0D:B6:28:0E:04
+ keyid:A4:66:E2:46:F7:3F:A1:73:9D:A2:E2:4E:29:99:DB:2E:36:36:6C:B5
Authority Information Access:
CA Issuers - URI:foobar
@@ -50,38 +50,38 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 6f:88:e2:5c:97:3f:d9:76:6e:2b:65:fb:84:21:30:e8:3c:a2:
- 6e:eb:a4:2b:42:e2:27:b3:2f:86:2f:b2:38:aa:de:74:b2:92:
- ff:d8:0d:6d:ec:9e:44:95:cb:95:1a:1e:2e:6f:6a:74:2b:81:
- 5a:13:5f:c2:21:3a:24:e6:c4:07:01:f4:f1:5c:c6:39:aa:8f:
- 2a:5f:f3:59:6f:74:de:19:06:da:0d:8d:ba:9c:6c:b8:75:97:
- 9c:dc:c8:06:33:88:fd:c4:30:4b:02:ea:2a:6c:b2:03:47:a7:
- fb:e9:8f:0b:2d:3d:98:26:6a:8d:14:7a:5d:4d:d6:4e:ad:8f:
- 1e:0d:9a:14:2f:81:5b:e6:f4:39:6a:df:a0:e0:35:ab:09:05:
- 41:30:31:aa:51:5b:26:5c:82:27:2e:5e:08:c4:97:65:1e:51:
- ad:db:7c:26:34:79:d3:ce:90:93:4e:f4:69:6d:27:ad:26:be:
- 77:5e:3b:c6:7c:7d:5d:62:e4:91:83:cf:c1:bd:4a:27:ee:b1:
- 67:1a:75:8f:cb:ac:4f:0d:da:92:98:c9:d5:73:9a:1d:10:6c:
- 1f:03:1a:0a:46:db:d5:bd:0a:f0:12:f7:39:06:44:16:27:81:
- 1b:4e:5f:45:a0:d6:8e:8a:d3:e9:63:b9:01:8a:57:ae:50:7d:
- 26:bb:1e:e6
+ 84:53:97:e8:ce:6e:20:dc:41:bf:19:7f:f6:1a:a3:53:d3:8a:
+ fa:de:74:3a:78:ca:95:55:be:b3:f8:28:af:2b:94:c6:40:bd:
+ bd:ec:fd:c0:5a:8c:66:6c:00:08:6a:2b:3b:b7:b4:25:90:de:
+ 4d:5f:d7:e7:40:3b:cf:e0:98:7a:42:f6:4e:14:9b:02:fb:fa:
+ 8e:e7:d4:88:a5:92:cc:0d:40:36:f0:f7:6e:65:f3:d0:89:26:
+ d2:76:bf:46:ea:ec:42:af:cb:f2:06:57:fb:2d:67:a5:c9:12:
+ 54:a0:3b:a3:f3:de:30:15:58:ab:0c:91:ec:d2:7f:3d:86:67:
+ df:08:6d:36:8e:65:09:fe:d1:01:00:4b:bf:71:f8:4c:6b:6d:
+ f9:61:d6:91:e0:63:9a:f2:13:f0:93:c6:45:64:23:26:1a:69:
+ 9e:13:32:0b:a1:68:9f:77:15:0e:bc:d2:14:18:22:75:84:4e:
+ 33:9d:42:c4:77:b0:9f:14:9a:b5:fb:3a:b7:c5:46:ac:4c:59:
+ 1c:0c:33:c9:c0:aa:4e:54:37:dd:53:d8:bf:34:32:cb:a9:db:
+ 17:f9:14:17:9f:c3:62:71:29:02:6a:3a:8a:48:44:c8:08:de:
+ 32:7a:70:40:ce:27:b9:d9:1e:64:33:1d:e8:fd:0a:4e:54:c4:
+ 76:12:48:66
-----BEGIN CERTIFICATE-----
-MIIDWjCCAkKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
+MIIDWjCCAkKgAwIBAgIBBzANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
DTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowETEPMA0GA1UEAwwGdGFyZ2V0
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwmaxRA0UFIoVVD4SIJSd
-p5eS3SBn8NXoLaTWmugSBIzPo5Q/m+YgfcC1nFD3b47kpyrerUXQh+mKBWg6PvwW
-D76GEApbHX+EFdns2ScgpNeTkz0VVNopbnDVgVe3UEvqg56Zd6e9XUQ1MYRR4Sks
-bxRWuUp9T5I6kGB3CiAw5lwL+Nn0O+3ZZOwHfxVe5WdD0B4GJaAs+4kXYeiqmSg6
-l+w32TLwpE6rtNkDyTNaX3unoAwUtzT5K1k5KRVID8dHkP+f3Py3MDULWSiCINed
-8FD8Kiybt4QoenS1xBRE7Qm931Hhq7DgwEds6e1I3+x0arK77EXqOPkFx/HHXqyn
-KwIDAQABo4HBMIG+MB0GA1UdDgQWBBTxyEa36TQk58K0zgZVdyZjNL8OfzAfBgNV
-HSMEGDAWgBRdtHOqG2AQngy8FrukClgNtigOBDAiBggrBgEFBQcBAQQWMBQwEgYI
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxyfxFz9xsyqYscDAReIP
+2pInbkRtGE2HuevAY8ktJHV6FYVoOszMpZt/gsAChnb5KLL3LPNIu20XEThNXoa/
+ionoD3DGpoG90ZLN68CZkDxRyhTZ3XVmFxxSwtg+imsNlDJUprA1uVpYsIAoOC7x
+yS+yMIDlBcWyW29BMCf9AnqJsXSQyx/aJR17twAqvwucX4slyq7FVjMaonKpPCOK
+vD3SUA8aCwnMw0kbgcbhqqXbaMyXAg8bDcPa4MK4GI2fBDfFZXkwL1haIaTfsoXA
+7FnPjCrG8474VpVjtmduTgdhbTQXNv5X56Itjc5xhlMsogcC9+KiuVso+r1ccBVV
+aQIDAQABo4HBMIG+MB0GA1UdDgQWBBRnvoeq2fuInOj4FNP8jkSV7n18TjAfBgNV
+HSMEGDAWgBSkZuJG9z+hc52i4k4pmdsuNjZstTAiBggrBgEFBQcBAQQWMBQwEgYI
KwYBBQUHMAKGBmZvb2JhcjApBgNVHR8EIjAgMB6gHKAahhhodHRwOi8vdXJsLWZv
ci1jcmwvSS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB
-BggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAb4jiXJc/2XZuK2X7hCEw6Dyi
-buukK0LiJ7Mvhi+yOKredLKS/9gNbeyeRJXLlRoeLm9qdCuBWhNfwiE6JObEBwH0
-8VzGOaqPKl/zWW903hkG2g2NupxsuHWXnNzIBjOI/cQwSwLqKmyyA0en++mPCy09
-mCZqjRR6XU3WTq2PHg2aFC+BW+b0OWrfoOA1qwkFQTAxqlFbJlyCJy5eCMSXZR5R
-rdt8JjR5086Qk070aW0nrSa+d147xnx9XWLkkYPPwb1KJ+6xZxp1j8usTw3akpjJ
-1XOaHRBsHwMaCkbb1b0K8BL3OQZEFieBG05fRaDWjorT6WO5AYpXrlB9Jrse5g==
+BggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAhFOX6M5uINxBvxl/9hqjU9OK
++t50OnjKlVW+s/goryuUxkC9vez9wFqMZmwACGorO7e0JZDeTV/X50A7z+CYekL2
+ThSbAvv6jufUiKWSzA1ANvD3bmXz0Ikm0na/RursQq/L8gZX+y1npckSVKA7o/Pe
+MBVYqwyR7NJ/PYZn3whtNo5lCf7RAQBLv3H4TGtt+WHWkeBjmvIT8JPGRWQjJhpp
+nhMyC6Fon3cVDrzSFBgidYROM51CxHewnxSatfs6t8VGrExZHAwzycCqTlQ33VPY
+vzQyy6nbF/kUF5/DYnEpAmo6ikhEyAjeMnpwQM4nudkeZDMd6P0KTlTEdhJIZg==
-----END CERTIFICATE-----
diff --git a/chromium/net/data/cert_issuer_source_aia_unittest/target_no_aia.pem b/chromium/net/data/cert_issuer_source_aia_unittest/target_no_aia.pem
index c34cdf31304..c9146efc993 100644
--- a/chromium/net/data/cert_issuer_source_aia_unittest/target_no_aia.pem
+++ b/chromium/net/data/cert_issuer_source_aia_unittest/target_no_aia.pem
@@ -1,7 +1,7 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 1 (0x1)
+ Serial Number: 2 (0x2)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=I
Validity
@@ -12,30 +12,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:c5:7a:06:93:cf:7e:69:04:45:15:1e:b2:5e:7d:
- 49:b4:28:6a:eb:5f:6c:78:92:d8:00:6b:95:e7:d2:
- 7d:1d:3b:a5:f1:1c:7e:0c:3a:db:51:3b:01:4a:54:
- 18:ef:2a:b9:ba:12:0f:1b:61:07:cb:c0:ce:a7:63:
- 95:a7:15:94:23:8e:fb:44:4b:73:32:7c:09:d5:b3:
- bc:b4:59:30:35:fa:3c:be:eb:f9:6c:99:a3:0b:40:
- 0d:b5:b7:cb:df:72:1c:4f:a6:7d:a8:56:dc:7f:e6:
- 40:61:99:44:c3:e9:c1:e8:27:22:18:17:20:7f:5d:
- 50:8c:d4:50:dd:65:5e:a0:24:b2:70:89:00:a4:8c:
- a9:ae:d7:23:a7:1c:fe:3e:61:0d:38:26:e5:c1:14:
- 5d:8e:85:8c:21:f2:e9:73:eb:2f:a8:79:3e:32:83:
- d5:20:72:25:27:c8:c8:85:40:b7:39:77:93:08:22:
- 47:4e:d2:15:6e:e0:d1:ea:3e:01:38:e1:cc:dd:3a:
- 91:99:b5:e6:05:af:e7:aa:09:82:c8:cc:c0:95:02:
- 73:54:f2:2a:af:88:6e:51:7c:fa:62:39:5b:df:f4:
- d9:17:f4:85:25:46:5e:7c:9d:99:32:f2:b7:a9:75:
- 00:1b:13:5d:ba:ae:a2:56:59:17:cd:4a:2a:08:6f:
- 20:fb
+ 00:c8:d2:4b:11:93:9a:57:64:a6:36:33:e6:dd:b9:
+ 4f:b0:ba:86:e5:cc:76:b6:ec:22:4d:c4:25:26:0a:
+ 3e:0b:d8:24:1f:f1:fa:0f:ac:ff:c5:d5:01:97:ab:
+ 54:fd:01:76:b4:15:bc:66:c0:f2:a4:0b:45:49:2d:
+ 9f:56:81:95:86:62:11:8e:65:39:d7:42:6a:a8:9c:
+ 57:d2:47:90:d2:32:fc:bc:ac:ce:99:70:ae:ec:24:
+ 3b:b2:e6:b7:6b:60:be:27:59:d0:75:bf:b8:f4:ce:
+ 23:94:56:79:64:32:a0:f1:20:1c:38:3d:1c:0c:ed:
+ af:86:ca:78:b9:84:e7:f1:ee:04:2a:81:1e:ad:d9:
+ 58:c7:1e:63:3e:ce:3b:80:01:5f:42:06:d2:85:d9:
+ d5:8d:b6:0a:72:c5:9c:6d:2d:ee:88:57:ab:71:8c:
+ c7:4a:40:6a:cc:7a:1e:4f:4b:a4:3d:fa:cd:aa:31:
+ 9b:4e:6e:be:6d:e0:7b:90:ba:88:f6:a3:c8:7d:a7:
+ d8:7c:84:e1:7e:a2:63:2d:28:5e:c7:af:d6:0d:a3:
+ ab:24:06:ec:97:22:f8:2f:78:1d:f6:36:49:10:c3:
+ d2:64:e3:e7:9a:f6:70:c5:19:ae:fc:fc:c7:0a:31:
+ 0b:e5:23:78:50:b2:7b:7e:d8:43:8a:6d:a7:44:94:
+ e7:35
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 79:EA:75:25:1E:88:9B:8B:CA:6F:EA:86:6B:FA:38:03:FC:B8:FD:02
+ 62:47:32:0D:D2:47:B0:F5:FF:3A:B7:07:59:69:49:D9:71:CC:9A:33
X509v3 Authority Key Identifier:
- keyid:5D:B4:73:AA:1B:60:10:9E:0C:BC:16:BB:A4:0A:58:0D:B6:28:0E:04
+ keyid:A4:66:E2:46:F7:3F:A1:73:9D:A2:E2:4E:29:99:DB:2E:36:36:6C:B5
X509v3 CRL Distribution Points:
@@ -47,38 +47,38 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 2c:cf:5e:56:d6:c4:fd:f7:0f:58:9e:30:e4:18:72:bc:d5:44:
- d2:ea:f8:21:fc:5a:cc:e6:c8:2b:39:c5:f8:a1:c5:19:06:08:
- 59:bf:cc:f9:80:f6:9d:62:77:a7:d3:96:cd:5f:5a:6c:a6:65:
- 50:0d:f1:93:27:1c:1e:b7:00:85:33:a9:27:42:ea:a1:61:ee:
- fd:da:96:df:4a:90:bc:52:7c:08:61:ca:a6:48:58:a6:58:08:
- ff:06:fb:d9:94:a5:8e:3b:c8:e1:bb:c7:d2:af:79:de:ea:97:
- a6:ad:44:46:da:3c:42:6a:70:f2:f9:fe:b9:b9:e9:a3:e5:88:
- 3e:3a:79:d9:38:7d:4a:38:eb:b2:51:0e:91:f5:42:28:30:f6:
- d9:19:bf:ba:1e:4c:e0:29:63:f8:37:97:10:7a:f7:05:6a:85:
- af:66:f8:86:79:b7:82:58:2f:f3:7d:0b:f9:43:8d:34:91:1f:
- 9a:95:46:e1:e3:f7:7c:fd:c5:c6:38:0a:ab:13:72:fe:cc:85:
- 42:87:b9:3c:6a:07:2d:eb:24:90:a7:d3:6a:bf:30:02:48:c7:
- c0:0c:5d:5b:ed:c4:aa:ed:0c:28:f6:ea:3c:e8:f5:f2:99:2f:
- 2f:96:f0:78:4e:d4:6d:2a:00:a4:9b:51:30:4c:6b:fe:13:c1:
- 6b:ed:60:b4
+ 00:e7:9b:5f:56:c4:61:39:39:ae:a8:a2:f6:c7:c1:ca:d2:e7:
+ db:4e:e1:9b:0f:ef:5c:11:88:49:9f:d7:85:69:54:86:3a:cc:
+ 40:f1:14:2a:4b:a3:75:d3:a5:8d:6d:9e:bf:8c:ce:8b:85:07:
+ 37:ef:05:5e:51:fe:28:55:db:75:ec:0e:30:c1:7e:7f:53:67:
+ e1:87:ed:df:69:75:08:27:f9:33:58:af:96:84:ab:0b:10:0f:
+ ff:3a:98:68:de:bf:9e:78:ef:92:12:40:bd:c3:a1:22:0e:ea:
+ ca:3e:52:93:5e:5b:b6:67:61:ac:b9:dd:9f:2f:26:ca:e6:b6:
+ d2:ad:a1:1a:7c:e3:c7:f6:3f:61:3d:7e:2b:35:e0:29:39:35:
+ d1:82:69:a4:4e:09:77:ab:7c:16:7b:e6:56:2b:c4:17:87:25:
+ 57:59:ed:44:d1:99:23:26:1b:d0:79:67:ad:ae:cd:df:87:7a:
+ 5f:48:fe:2f:63:90:ca:da:56:90:32:3c:6c:fa:87:8b:d2:51:
+ 2f:2e:ce:c8:a9:19:a2:8f:f1:54:03:08:ad:85:a3:dd:b2:ac:
+ e2:47:06:65:c0:47:ee:ff:f5:eb:9d:82:89:f1:03:71:d5:e1:
+ e6:87:45:5e:f5:da:f2:21:53:78:62:9a:dc:cf:74:a8:9e:12:
+ a9:ff:6c:00
-----BEGIN CERTIFICATE-----
-MIIDNjCCAh6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
+MIIDNjCCAh6gAwIBAgIBAjANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
DTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowETEPMA0GA1UEAwwGdGFyZ2V0
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxXoGk89+aQRFFR6yXn1J
-tChq619seJLYAGuV59J9HTul8Rx+DDrbUTsBSlQY7yq5uhIPG2EHy8DOp2OVpxWU
-I477REtzMnwJ1bO8tFkwNfo8vuv5bJmjC0ANtbfL33IcT6Z9qFbcf+ZAYZlEw+nB
-6CciGBcgf11QjNRQ3WVeoCSycIkApIyprtcjpxz+PmENOCblwRRdjoWMIfLpc+sv
-qHk+MoPVIHIlJ8jIhUC3OXeTCCJHTtIVbuDR6j4BOOHM3TqRmbXmBa/nqgmCyMzA
-lQJzVPIqr4huUXz6Yjlb3/TZF/SFJUZefJ2ZMvK3qXUAGxNduq6iVlkXzUoqCG8g
-+wIDAQABo4GdMIGaMB0GA1UdDgQWBBR56nUlHoibi8pv6oZr+jgD/Lj9AjAfBgNV
-HSMEGDAWgBRdtHOqG2AQngy8FrukClgNtigOBDApBgNVHR8EIjAgMB6gHKAahhho
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyNJLEZOaV2SmNjPm3blP
+sLqG5cx2tuwiTcQlJgo+C9gkH/H6D6z/xdUBl6tU/QF2tBW8ZsDypAtFSS2fVoGV
+hmIRjmU510JqqJxX0keQ0jL8vKzOmXCu7CQ7sua3a2C+J1nQdb+49M4jlFZ5ZDKg
+8SAcOD0cDO2vhsp4uYTn8e4EKoEerdlYxx5jPs47gAFfQgbShdnVjbYKcsWcbS3u
+iFercYzHSkBqzHoeT0ukPfrNqjGbTm6+beB7kLqI9qPIfafYfIThfqJjLShex6/W
+DaOrJAbslyL4L3gd9jZJEMPSZOPnmvZwxRmu/PzHCjEL5SN4ULJ7fthDim2nRJTn
+NQIDAQABo4GdMIGaMB0GA1UdDgQWBBRiRzIN0kew9f86twdZaUnZccyaMzAfBgNV
+HSMEGDAWgBSkZuJG9z+hc52i4k4pmdsuNjZstTApBgNVHR8EIjAgMB6gHKAahhho
dHRwOi8vdXJsLWZvci1jcmwvSS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
-MBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEALM9eVtbE
-/fcPWJ4w5BhyvNVE0ur4IfxazObIKznF+KHFGQYIWb/M+YD2nWJ3p9OWzV9abKZl
-UA3xkyccHrcAhTOpJ0LqoWHu/dqW30qQvFJ8CGHKpkhYplgI/wb72ZSljjvI4bvH
-0q953uqXpq1ERto8Qmpw8vn+ubnpo+WIPjp52Th9SjjrslEOkfVCKDD22Rm/uh5M
-4Clj+DeXEHr3BWqFr2b4hnm3glgv830L+UONNJEfmpVG4eP3fP3FxjgKqxNy/syF
-Qoe5PGoHLeskkKfTar8wAkjHwAxdW+3Equ0MKPbqPOj18pkvL5bweE7UbSoApJtR
-MExr/hPBa+1gtA==
+MBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAAOebX1bE
+YTk5rqii9sfBytLn207hmw/vXBGISZ/XhWlUhjrMQPEUKkujddOljW2ev4zOi4UH
+N+8FXlH+KFXbdewOMMF+f1Nn4Yft32l1CCf5M1ivloSrCxAP/zqYaN6/nnjvkhJA
+vcOhIg7qyj5Sk15btmdhrLndny8myua20q2hGnzjx/Y/YT1+KzXgKTk10YJppE4J
+d6t8FnvmVivEF4clV1ntRNGZIyYb0Hlnra7N34d6X0j+L2OQytpWkDI8bPqHi9JR
+Ly7OyKkZoo/xVAMIrYWj3bKs4kcGZcBH7v/1652CifEDcdXh5odFXvXa8iFTeGKa
+3M90qJ4Sqf9sAA==
-----END CERTIFICATE-----
diff --git a/chromium/net/data/cert_issuer_source_aia_unittest/target_one_aia.pem b/chromium/net/data/cert_issuer_source_aia_unittest/target_one_aia.pem
index e826165189c..b1664777529 100644
--- a/chromium/net/data/cert_issuer_source_aia_unittest/target_one_aia.pem
+++ b/chromium/net/data/cert_issuer_source_aia_unittest/target_one_aia.pem
@@ -12,30 +12,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:de:50:b2:e5:7b:51:e3:7e:12:af:82:81:07:5e:
- ef:a9:11:ea:1c:20:58:60:94:1c:16:d0:b1:18:bd:
- 36:cc:b6:37:c4:dc:7b:38:ad:c1:b3:2c:35:6b:95:
- a1:8f:b9:b4:cf:65:9a:e0:b5:06:23:e8:44:ab:8a:
- 39:30:87:8e:3f:5d:49:87:83:b9:ff:7b:c1:dc:26:
- a6:08:47:06:a6:19:d9:7a:fd:50:1b:c4:db:16:fa:
- 4a:eb:31:a5:24:61:36:16:4b:ed:23:d6:a1:ea:dd:
- 19:60:cc:d7:8c:cc:07:0b:d7:bd:9d:8b:92:26:ea:
- 00:74:ea:a8:9e:ab:0f:90:91:e7:07:2a:e2:c6:24:
- 95:8b:e4:2e:6b:d5:07:e2:4c:3a:e2:0b:18:d7:d9:
- 26:28:c2:12:8a:b0:7e:f6:e1:3a:07:ae:7d:9c:84:
- ec:88:59:07:84:10:db:c2:35:6c:78:6c:2d:b4:cc:
- 8f:fa:4b:5b:5a:82:9e:dc:36:3b:29:18:31:26:fb:
- 8e:99:e8:06:47:62:0b:60:bc:e6:b6:68:27:4b:b7:
- 4d:27:4e:aa:96:d0:0b:b5:67:93:e3:50:54:7e:b8:
- 9c:37:d3:b2:35:89:f3:c0:d2:2d:e2:38:2b:8d:78:
- 81:7e:d6:ce:b0:b5:d7:60:25:7b:5f:01:38:fb:a4:
- 0c:71
+ 00:bc:98:17:cf:5b:06:da:5d:7b:50:6b:c3:d5:d1:
+ c0:0a:0f:81:ef:1c:a6:31:1b:0f:75:66:71:70:73:
+ fa:69:1a:a7:bd:e7:3f:b3:50:34:9e:39:36:eb:e7:
+ 64:0c:f0:61:3a:90:35:f5:26:e5:9b:ed:d6:6e:06:
+ 01:ae:c8:1d:1b:e7:c0:54:00:17:32:87:81:55:64:
+ e6:27:72:47:d8:ed:fe:f9:9d:c0:b3:4f:a6:79:90:
+ 61:48:6b:18:3f:c7:f8:b5:ec:d8:e2:cb:64:d0:6b:
+ c9:63:9d:58:9a:17:bf:87:08:18:18:81:af:1f:ec:
+ fe:db:5a:31:4f:c1:af:a0:84:86:bb:f9:87:eb:fa:
+ 58:1a:d7:bc:4f:52:e7:29:52:5c:fc:6a:72:ca:46:
+ 3f:89:f2:d3:4c:02:b4:fb:73:be:85:f5:3d:aa:2d:
+ 4d:92:1f:27:e0:9a:59:74:83:74:12:ce:e9:02:ee:
+ fd:b1:f7:35:59:41:c2:53:3c:60:24:79:a6:46:8e:
+ 99:65:a5:91:ee:52:df:1a:b5:4e:22:3c:b2:be:cf:
+ b6:0f:d3:28:fe:2e:b7:23:87:4e:4f:b3:4a:e0:33:
+ b4:e1:ff:78:89:9f:60:7f:ac:e3:3d:a9:7d:ce:a6:
+ 8c:c3:59:56:10:51:fc:b3:f2:a1:a9:3e:7d:1f:1e:
+ 2e:37
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- C2:2B:28:21:EE:DE:41:F9:2D:DA:D4:1B:D9:C3:8B:7E:DE:9A:F6:07
+ 7B:FF:76:7A:1E:BC:68:80:7E:C7:56:AB:B2:24:6B:45:65:48:B2:21
X509v3 Authority Key Identifier:
- keyid:5D:B4:73:AA:1B:60:10:9E:0C:BC:16:BB:A4:0A:58:0D:B6:28:0E:04
+ keyid:A4:66:E2:46:F7:3F:A1:73:9D:A2:E2:4E:29:99:DB:2E:36:36:6C:B5
Authority Information Access:
CA Issuers - URI:http://url-for-aia/I.cer
@@ -50,39 +50,39 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 3b:dc:a8:d4:a5:17:f9:9a:fc:20:db:2c:a2:3e:89:78:20:aa:
- 19:e1:ca:03:5e:a3:a3:24:60:87:24:3c:cd:28:cb:5a:89:f5:
- ce:66:ca:b6:2d:79:c7:ff:1a:6d:e0:5d:aa:66:14:59:53:17:
- 62:64:4d:76:0d:01:04:52:4a:bc:ae:6c:89:5d:1c:a4:bf:ec:
- b9:a3:5d:24:77:e3:76:1f:5b:ab:d4:99:18:b8:41:ec:90:63:
- 64:b8:4c:04:f6:0a:e9:ad:1c:1c:75:7c:50:ea:3d:df:6b:4a:
- 85:ae:b1:3a:15:8b:49:84:91:7f:e8:c4:47:a5:45:89:f9:f6:
- 35:00:12:ca:5b:b6:18:0c:64:cf:65:9a:04:fb:3a:44:5a:90:
- e1:85:e3:68:c5:d7:10:2f:a3:1a:ba:88:66:25:78:60:e3:8b:
- 68:41:bb:d6:1c:be:f3:26:6a:b2:7a:22:4f:9c:e1:4f:70:bc:
- 23:c5:63:d5:de:19:7f:2e:40:ea:e7:86:47:a4:76:e0:81:96:
- 66:db:b3:62:9f:18:32:08:7e:36:c8:00:15:85:fc:3c:93:60:
- af:bb:9a:09:58:3d:a5:18:2b:5c:1d:96:08:fc:43:13:ec:1b:
- ac:bd:00:22:a5:76:68:32:76:49:7a:f6:32:c9:fa:d3:ac:9c:
- cc:16:1d:7f
+ 81:f3:ab:93:d6:70:1a:5c:e7:2c:02:7d:3f:6d:f1:58:47:f1:
+ 84:2e:07:ff:63:74:df:2b:ad:0c:a2:bc:36:e5:fb:eb:1b:f9:
+ f2:38:90:5b:9d:fd:9b:c7:dd:ca:b7:d2:27:5a:ef:19:e2:c0:
+ 1f:a3:ea:bc:7a:f8:b9:b5:d6:16:15:e7:25:58:1c:8b:69:d5:
+ 69:d6:15:d1:85:4d:ba:21:3b:e8:06:46:5f:b1:4a:b1:fe:da:
+ 59:26:bb:5d:11:96:e2:7b:e2:19:3c:11:58:67:5c:fd:91:a3:
+ 9e:84:ff:50:34:27:ba:95:a5:7c:c7:7b:63:ad:2b:72:8c:d7:
+ e2:3c:3e:c0:e8:9e:43:40:70:20:46:8c:1d:69:2f:8d:c8:1c:
+ 0d:44:9f:f0:e8:07:69:cf:08:1c:7f:ff:0c:bb:36:8e:3d:e0:
+ d8:14:8f:b9:9e:12:d9:28:c2:2c:39:3a:2d:a7:01:5d:d4:3a:
+ ca:b7:a0:66:68:be:28:c6:dc:a1:69:a6:ba:ed:04:82:2d:3d:
+ 45:42:cf:b7:58:4f:a3:1a:50:66:2d:c0:07:e6:4f:05:de:49:
+ 57:b8:81:e6:99:77:4c:0b:e8:19:4c:7a:c2:8a:a9:4b:92:63:
+ 15:91:8e:a0:fa:ce:fa:19:a5:05:4b:a0:f3:de:60:48:37:e2:
+ 92:16:06:e7
-----BEGIN CERTIFICATE-----
MIIDbDCCAlSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
DTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowETEPMA0GA1UEAwwGdGFyZ2V0
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3lCy5XtR434Sr4KBB17v
-qRHqHCBYYJQcFtCxGL02zLY3xNx7OK3Bsyw1a5Whj7m0z2Wa4LUGI+hEq4o5MIeO
-P11Jh4O5/3vB3CamCEcGphnZev1QG8TbFvpK6zGlJGE2FkvtI9ah6t0ZYMzXjMwH
-C9e9nYuSJuoAdOqonqsPkJHnByrixiSVi+Qua9UH4kw64gsY19kmKMISirB+9uE6
-B659nITsiFkHhBDbwjVseGwttMyP+ktbWoKe3DY7KRgxJvuOmegGR2ILYLzmtmgn
-S7dNJ06qltALtWeT41BUfricN9OyNYnzwNIt4jgrjXiBftbOsLXXYCV7XwE4+6QM
-cQIDAQABo4HTMIHQMB0GA1UdDgQWBBTCKygh7t5B+S3a1BvZw4t+3pr2BzAfBgNV
-HSMEGDAWgBRdtHOqG2AQngy8FrukClgNtigOBDA0BggrBgEFBQcBAQQoMCYwJAYI
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvJgXz1sG2l17UGvD1dHA
+Cg+B7xymMRsPdWZxcHP6aRqnvec/s1A0njk26+dkDPBhOpA19Sblm+3WbgYBrsgd
+G+fAVAAXMoeBVWTmJ3JH2O3++Z3As0+meZBhSGsYP8f4tezY4stk0GvJY51Ymhe/
+hwgYGIGvH+z+21oxT8GvoISGu/mH6/pYGte8T1LnKVJc/GpyykY/ifLTTAK0+3O+
+hfU9qi1Nkh8n4JpZdIN0Es7pAu79sfc1WUHCUzxgJHmmRo6ZZaWR7lLfGrVOIjyy
+vs+2D9Mo/i63I4dOT7NK4DO04f94iZ9gf6zjPal9zqaMw1lWEFH8s/KhqT59Hx4u
+NwIDAQABo4HTMIHQMB0GA1UdDgQWBBR7/3Z6HrxogH7HVquyJGtFZUiyITAfBgNV
+HSMEGDAWgBSkZuJG9z+hc52i4k4pmdsuNjZstTA0BggrBgEFBQcBAQQoMCYwJAYI
KwYBBQUHMAKGGGh0dHA6Ly91cmwtZm9yLWFpYS9JLmNlcjApBgNVHR8EIjAgMB6g
HKAahhhodHRwOi8vdXJsLWZvci1jcmwvSS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0G
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEA
-O9yo1KUX+Zr8INssoj6JeCCqGeHKA16joyRghyQ8zSjLWon1zmbKti15x/8abeBd
-qmYUWVMXYmRNdg0BBFJKvK5siV0cpL/suaNdJHfjdh9bq9SZGLhB7JBjZLhMBPYK
-6a0cHHV8UOo932tKha6xOhWLSYSRf+jER6VFifn2NQASylu2GAxkz2WaBPs6RFqQ
-4YXjaMXXEC+jGrqIZiV4YOOLaEG71hy+8yZqsnoiT5zhT3C8I8Vj1d4Zfy5A6ueG
-R6R24IGWZtuzYp8YMgh+NsgAFYX8PJNgr7uaCVg9pRgrXB2WCPxDE+wbrL0AIqV2
-aDJ2SXr2Msn606yczBYdfw==
+gfOrk9ZwGlznLAJ9P23xWEfxhC4H/2N03yutDKK8NuX76xv58jiQW539m8fdyrfS
+J1rvGeLAH6PqvHr4ubXWFhXnJVgci2nVadYV0YVNuiE76AZGX7FKsf7aWSa7XRGW
+4nviGTwRWGdc/ZGjnoT/UDQnupWlfMd7Y60rcozX4jw+wOieQ0BwIEaMHWkvjcgc
+DUSf8OgHac8IHH//DLs2jj3g2BSPuZ4S2SjCLDk6LacBXdQ6yregZmi+KMbcoWmm
+uu0Egi09RULPt1hPoxpQZi3AB+ZPBd5JV7iB5pl3TAvoGUx6woqpS5JjFZGOoPrO
++hmlBUug895gSDfikhYG5w==
-----END CERTIFICATE-----
diff --git a/chromium/net/data/cert_issuer_source_aia_unittest/target_six_aia.pem b/chromium/net/data/cert_issuer_source_aia_unittest/target_six_aia.pem
index 2e07ea173fe..79c573cc582 100644
--- a/chromium/net/data/cert_issuer_source_aia_unittest/target_six_aia.pem
+++ b/chromium/net/data/cert_issuer_source_aia_unittest/target_six_aia.pem
@@ -1,7 +1,7 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 1 (0x1)
+ Serial Number: 5 (0x5)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=I
Validity
@@ -12,30 +12,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:ad:a8:69:76:8e:4f:38:13:f9:dc:08:ea:d4:06:
- 97:0b:13:9f:21:a8:df:d6:d3:9a:a7:f7:b5:0c:10:
- 3a:3a:4a:4b:ff:d2:2e:ae:c2:1c:3e:c1:67:94:25:
- d4:cc:29:29:56:f7:32:d1:6a:1e:d9:14:09:48:36:
- 0e:14:2e:30:aa:9d:80:9f:5f:2c:1b:38:73:e7:54:
- 3d:4b:8e:d4:d0:b7:d6:5c:04:0e:be:ce:76:0d:8a:
- fc:9c:89:36:cf:ce:3f:85:b0:a0:3a:bb:8b:42:7c:
- 71:39:1a:a4:77:78:10:72:86:c9:e5:92:a3:82:32:
- 7a:e3:e7:84:98:a3:6d:77:23:d1:5b:11:62:b5:90:
- af:2f:f6:5e:ae:1d:a5:6b:83:df:d3:af:b9:14:fb:
- 38:59:48:ab:f7:6c:0b:69:2b:69:31:3f:a6:9f:4b:
- 53:69:0d:d0:26:bd:27:63:bc:f2:79:e1:51:2e:93:
- b7:2c:36:39:c9:1d:5d:af:d2:fa:f7:01:79:8e:b1:
- f3:9c:20:79:50:7c:32:43:48:18:09:e8:ab:98:79:
- bb:42:cb:36:38:13:c5:01:48:33:85:9d:c1:d0:6b:
- df:0f:e0:65:9f:10:66:ab:9b:1e:b7:10:ac:c8:a7:
- 4d:49:24:bd:ab:b3:66:2b:8c:71:72:84:48:18:69:
- 16:8d
+ 00:cd:b6:44:0e:5c:1c:cf:03:89:04:19:c9:c0:e5:
+ 0d:86:bc:44:e1:54:31:33:24:2a:9f:50:9e:68:a5:
+ d2:17:1b:e1:96:1b:31:40:e2:05:4f:8b:c3:0c:41:
+ d0:66:8a:8b:03:a6:4a:64:40:f4:8b:f9:a1:f4:84:
+ 18:fc:93:6c:7c:80:37:e2:a6:f6:93:bb:9d:14:63:
+ 63:b8:66:b0:71:b9:2c:9d:f4:4d:55:41:e3:04:ad:
+ 1f:ff:56:13:a5:7a:97:fd:12:ec:21:d4:99:85:77:
+ ec:bd:d1:13:12:2f:e3:ac:1f:34:0e:ff:cf:00:05:
+ b0:c2:40:e0:a6:ba:48:1a:a4:0b:37:7a:e5:ea:d6:
+ bf:15:e2:21:f3:6b:23:c9:16:26:44:c9:cc:61:4c:
+ 77:d4:e2:5d:04:0e:2b:f5:38:49:14:11:4b:d2:91:
+ 45:d3:b9:cd:3b:df:f7:99:fd:3c:ae:ce:f2:76:e7:
+ 80:b0:7d:b1:cd:9f:29:67:8a:61:c7:ae:1c:15:fb:
+ 46:76:d8:1c:0e:fc:82:29:85:da:4d:ae:24:1c:63:
+ 36:bb:e0:43:1a:73:7f:ac:e5:81:a5:0c:aa:bb:32:
+ 96:41:48:f4:4d:2d:f6:a2:c7:9f:d0:94:72:29:05:
+ ee:7d:69:1f:4a:ea:7f:a8:77:d4:75:c6:66:67:2e:
+ f5:d1
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 85:F3:1D:3E:B1:AC:1D:A0:34:20:CB:91:0E:FD:AF:25:B8:5E:3D:2E
+ 78:F9:75:F9:80:E3:8F:14:93:E7:8D:DC:DF:D5:72:81:19:88:83:6F
X509v3 Authority Key Identifier:
- keyid:5D:B4:73:AA:1B:60:10:9E:0C:BC:16:BB:A4:0A:58:0D:B6:28:0E:04
+ keyid:A4:66:E2:46:F7:3F:A1:73:9D:A2:E2:4E:29:99:DB:2E:36:36:6C:B5
Authority Information Access:
CA Issuers - URI:http://url-for-aia/I.cer
@@ -55,32 +55,32 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 88:87:b2:59:3c:f8:eb:17:b6:e7:87:4e:96:c6:29:9d:3c:5f:
- 1d:09:85:6d:d7:78:68:a9:84:a1:14:1b:9b:f2:36:da:68:43:
- b7:6a:99:6f:f0:de:b5:6b:65:b9:c8:a2:b2:da:fe:b6:f2:8b:
- 58:28:bd:9b:31:ff:b5:d8:c6:9a:52:3e:eb:6d:0a:c8:72:db:
- d1:9a:64:66:aa:72:91:aa:e4:e9:c4:f7:81:d7:dc:ee:83:90:
- 9c:f4:b6:0c:ce:d3:39:b2:5d:25:c7:e5:6b:5e:5f:7f:c4:2c:
- 44:fa:6e:8a:b6:5b:93:a3:de:78:89:5a:cd:a2:8c:57:0f:c2:
- 22:4a:9f:bf:e7:94:a4:13:1d:ea:7c:39:0a:1d:6d:d4:37:a9:
- b9:bd:be:2f:dd:c2:7c:d0:20:ff:57:d4:c1:2d:c6:7b:19:3a:
- 64:5d:d2:6b:01:17:cd:7f:7f:d7:43:12:70:3f:4e:60:19:ee:
- 03:eb:3e:74:00:4f:f5:f5:e9:79:e0:7b:7d:69:f7:c9:fe:19:
- f6:35:04:da:28:90:07:ff:2d:38:33:1e:63:4c:c3:f9:38:c8:
- 92:fc:9f:df:8c:ee:13:57:48:b8:6f:c2:c9:71:83:d3:4e:5c:
- b8:43:1e:04:98:10:06:9d:7b:67:d1:e9:e4:0e:11:80:06:c3:
- 8f:d8:59:d4
+ 2a:f3:04:7a:5b:af:49:a5:51:f5:29:21:1d:67:90:85:0e:50:
+ 1e:17:41:3a:47:41:8a:db:69:bb:48:42:81:9d:d5:98:71:8f:
+ 05:b7:d4:18:f7:db:1f:79:98:e5:04:67:19:47:55:f9:92:42:
+ cc:41:32:c1:9b:bc:ae:2a:04:8f:bf:5a:ab:93:e5:bb:e0:93:
+ e8:74:60:0f:ea:cc:12:5c:fa:26:67:17:03:8d:74:36:e9:85:
+ a5:e9:14:3c:60:14:97:0c:76:0e:d7:69:ea:4d:a9:20:b4:7a:
+ e7:c9:30:19:35:13:ff:c8:0c:b8:1b:30:19:60:62:76:cd:21:
+ 67:c4:65:bd:7e:9a:79:d0:3b:8e:15:fd:24:ef:5b:89:49:65:
+ 25:5e:af:f9:d5:03:87:a6:da:6d:dd:ce:75:45:7b:3c:5f:58:
+ fd:3a:cb:22:a8:02:5b:2d:83:3e:7c:e2:67:bc:5f:e4:4c:54:
+ f4:e1:f0:3b:d8:04:51:2e:3b:95:75:c2:da:b1:e5:44:cd:0d:
+ 8a:53:f0:2b:6c:1f:26:7b:1d:0e:cf:ce:fd:6b:b8:2a:b0:87:
+ af:a6:e4:55:f6:13:b3:ee:5c:70:b8:31:5d:14:b9:6c:22:a3:
+ a2:cf:76:20:0b:cf:37:c7:65:5f:93:a9:91:cb:90:89:0e:9e:
+ e8:29:62:4d
-----BEGIN CERTIFICATE-----
-MIIEOTCCAyGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
+MIIEOTCCAyGgAwIBAgIBBTANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
DTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowETEPMA0GA1UEAwwGdGFyZ2V0
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArahpdo5POBP53Ajq1AaX
-CxOfIajf1tOap/e1DBA6OkpL/9IursIcPsFnlCXUzCkpVvcy0Woe2RQJSDYOFC4w
-qp2An18sGzhz51Q9S47U0LfWXAQOvs52DYr8nIk2z84/hbCgOruLQnxxORqkd3gQ
-cobJ5ZKjgjJ64+eEmKNtdyPRWxFitZCvL/Zerh2la4Pf06+5FPs4WUir92wLaStp
-MT+mn0tTaQ3QJr0nY7zyeeFRLpO3LDY5yR1dr9L69wF5jrHznCB5UHwyQ0gYCeir
-mHm7Qss2OBPFAUgzhZ3B0GvfD+BlnxBmq5setxCsyKdNSSS9q7NmK4xxcoRIGGkW
-jQIDAQABo4IBnzCCAZswHQYDVR0OBBYEFIXzHT6xrB2gNCDLkQ79ryW4Xj0uMB8G
-A1UdIwQYMBaAFF20c6obYBCeDLwWu6QKWA22KA4EMIH+BggrBgEFBQcBAQSB8TCB
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzbZEDlwczwOJBBnJwOUN
+hrxE4VQxMyQqn1CeaKXSFxvhlhsxQOIFT4vDDEHQZoqLA6ZKZED0i/mh9IQY/JNs
+fIA34qb2k7udFGNjuGawcbksnfRNVUHjBK0f/1YTpXqX/RLsIdSZhXfsvdETEi/j
+rB80Dv/PAAWwwkDgprpIGqQLN3rl6ta/FeIh82sjyRYmRMnMYUx31OJdBA4r9ThJ
+FBFL0pFF07nNO9/3mf08rs7ydueAsH2xzZ8pZ4phx64cFftGdtgcDvyCKYXaTa4k
+HGM2u+BDGnN/rOWBpQyquzKWQUj0TS32osef0JRyKQXufWkfSup/qHfUdcZmZy71
+0QIDAQABo4IBnzCCAZswHQYDVR0OBBYEFHj5dfmA448Uk+eN3N/VcoEZiINvMB8G
+A1UdIwQYMBaAFKRm4kb3P6FznaLiTimZ2y42Nmy1MIH+BggrBgEFBQcBAQSB8TCB
7jAkBggrBgEFBQcwAoYYaHR0cDovL3VybC1mb3ItYWlhL0kuY2VyMCYGCCsGAQUF
BzAChhpodHRwOi8vdXJsLWZvci1haWEyL0kyLmZvbzAmBggrBgEFBQcwAoYaaHR0
cDovL3VybC1mb3ItYWlhMy9JMy5mb28wJgYIKwYBBQUHMAKGGmh0dHA6Ly91cmwt
@@ -88,10 +88,10 @@ Zm9yLWFpYTQvSTQuZm9vMCYGCCsGAQUFBzAChhpodHRwOi8vdXJsLWZvci1haWE1
L0k1LmZvbzAmBggrBgEFBQcwAoYaaHR0cDovL3VybC1mb3ItYWlhNi9JNi5mb28w
KQYDVR0fBCIwIDAeoBygGoYYaHR0cDovL3VybC1mb3ItY3JsL0kuY3JsMA4GA1Ud
DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZI
-hvcNAQELBQADggEBAIiHslk8+OsXtueHTpbGKZ08Xx0JhW3XeGiphKEUG5vyNtpo
-Q7dqmW/w3rVrZbnIorLa/rbyi1govZsx/7XYxppSPuttCshy29GaZGaqcpGq5OnE
-94HX3O6DkJz0tgzO0zmyXSXH5WteX3/ELET6boq2W5Oj3niJWs2ijFcPwiJKn7/n
-lKQTHep8OQodbdQ3qbm9vi/dwnzQIP9X1MEtxnsZOmRd0msBF81/f9dDEnA/TmAZ
-7gPrPnQAT/X16Xnge31p98n+GfY1BNookAf/LTgzHmNMw/k4yJL8n9+M7hNXSLhv
-wslxg9NOXLhDHgSYEAade2fR6eQOEYAGw4/YWdQ=
+hvcNAQELBQADggEBACrzBHpbr0mlUfUpIR1nkIUOUB4XQTpHQYrbabtIQoGd1Zhx
+jwW31Bj32x95mOUEZxlHVfmSQsxBMsGbvK4qBI+/WquT5bvgk+h0YA/qzBJc+iZn
+FwONdDbphaXpFDxgFJcMdg7XaepNqSC0eufJMBk1E//IDLgbMBlgYnbNIWfEZb1+
+mnnQO44V/STvW4lJZSVer/nVA4em2m3dznVFezxfWP06yyKoAlstgz584me8X+RM
+VPTh8DvYBFEuO5V1wtqx5UTNDYpT8CtsHyZ7HQ7Pzv1ruCqwh6+m5FX2E7PuXHC4
+MV0UuWwio6LPdiALzzfHZV+TqZHLkIkOnugpYk0=
-----END CERTIFICATE-----
diff --git a/chromium/net/data/cert_issuer_source_aia_unittest/target_three_aia.pem b/chromium/net/data/cert_issuer_source_aia_unittest/target_three_aia.pem
index 3379711b7ef..cf0b1e19449 100644
--- a/chromium/net/data/cert_issuer_source_aia_unittest/target_three_aia.pem
+++ b/chromium/net/data/cert_issuer_source_aia_unittest/target_three_aia.pem
@@ -1,7 +1,7 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 1 (0x1)
+ Serial Number: 4 (0x4)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=I
Validity
@@ -12,30 +12,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:a0:40:29:2b:38:18:9a:53:e0:e0:e3:14:e4:30:
- cf:f9:85:6b:f9:3a:17:c2:f9:22:f8:64:bf:b0:de:
- 85:6d:37:dd:38:9a:93:d9:cb:c6:92:8a:6e:c4:2c:
- 10:2d:cb:3d:98:d2:e8:09:59:e4:28:b3:fe:c9:75:
- 46:f7:a7:ab:de:26:d9:47:73:08:bc:91:ce:5c:5c:
- 4f:43:f1:33:53:5d:2c:3b:f3:f4:69:e7:46:d8:b5:
- 77:75:94:d3:1b:f0:8f:5e:fc:7d:ca:2a:91:f8:81:
- c2:71:b8:b9:86:09:3f:bd:e4:fb:9c:d7:26:65:76:
- b8:e6:9b:6e:b6:72:fc:75:e8:df:55:30:24:81:24:
- 3d:a5:80:50:bc:76:15:29:82:89:34:58:0b:61:57:
- 48:fd:d3:4f:3e:ad:29:c7:bc:91:ce:f7:27:7e:9a:
- f0:82:91:9f:7c:ce:58:4e:bf:03:fb:69:2c:2e:f4:
- e6:a3:a4:b7:10:62:c3:c0:28:cc:ff:dc:a1:16:49:
- c0:f5:70:da:93:09:c9:65:a7:e1:10:02:ac:c3:40:
- 5c:84:d7:db:7b:f4:5f:03:6b:4e:d3:18:10:ba:11:
- a5:dd:1f:82:85:24:5e:bd:32:a4:08:4a:9c:fd:c4:
- 93:e7:86:ad:5b:f6:0a:21:60:cc:22:8a:13:a4:77:
- 44:63
+ 00:c5:05:c8:6a:51:45:70:b5:38:56:09:b1:35:3e:
+ e6:14:d4:93:13:d1:4e:05:1d:e1:49:e6:5e:0d:7b:
+ b1:02:96:31:a0:1c:73:5a:d9:4b:2c:ea:5d:23:71:
+ 43:cf:88:5e:92:e1:35:b2:5b:4d:89:b2:b5:e4:bd:
+ ac:37:cd:f8:42:7b:53:43:9a:ab:05:82:6c:67:8d:
+ 40:2c:15:b8:67:3d:f7:fa:d4:75:40:d1:31:58:e2:
+ e8:48:f6:13:f1:c9:d1:8f:8d:78:33:00:f1:89:a9:
+ 35:8e:22:f9:ff:b3:a4:83:92:59:75:e3:43:90:d9:
+ 83:b3:a8:ce:64:04:0e:a1:1d:5c:a4:b2:c0:19:d4:
+ 03:c9:bc:39:ad:33:9c:26:e2:ca:bf:44:85:34:20:
+ 92:a8:34:60:4e:a3:ec:11:c2:5f:e4:aa:19:6c:fe:
+ 40:c0:ad:cd:41:69:c4:93:94:d6:4b:e5:cf:98:0c:
+ 68:f1:94:25:ec:8f:c7:62:7f:8b:9d:14:13:18:51:
+ 10:63:a9:bc:b8:71:24:44:86:27:01:d6:3d:84:ae:
+ 7d:da:50:db:9c:64:bf:5e:ff:35:3e:ee:90:2f:72:
+ 44:ac:86:f2:4a:78:16:00:43:06:10:bd:4f:83:ca:
+ e0:9a:07:52:b3:2c:df:eb:4b:f3:e7:72:80:21:ad:
+ 12:33
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 85:6F:DA:CE:E5:28:2A:3C:AB:88:56:08:C8:5A:83:B5:B8:7A:31:27
+ EC:26:51:40:B1:40:90:32:30:DB:5E:7C:A4:52:EE:B7:87:82:B3:0A
X509v3 Authority Key Identifier:
- keyid:5D:B4:73:AA:1B:60:10:9E:0C:BC:16:BB:A4:0A:58:0D:B6:28:0E:04
+ keyid:A4:66:E2:46:F7:3F:A1:73:9D:A2:E2:4E:29:99:DB:2E:36:36:6C:B5
Authority Information Access:
CA Issuers - URI:http://url-for-aia/I.cer
@@ -52,41 +52,41 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 4b:56:98:06:5c:27:81:3c:dd:e6:29:6f:99:f6:98:90:bb:d4:
- 8b:fd:48:d5:3a:fb:41:d5:8b:38:b8:ff:47:3d:ca:ee:e2:a4:
- c5:42:59:5c:d2:c2:07:f2:21:f9:d7:3f:91:a5:ab:16:5b:ec:
- da:6f:db:7b:0d:ea:58:e1:9b:f8:d7:4a:bf:da:e2:18:c7:3f:
- a0:e0:0b:c1:43:b9:d7:b9:b5:d6:9d:12:4b:ce:e5:8e:7f:f1:
- ce:cd:a2:11:63:65:9b:59:28:fe:7d:b9:bf:9a:1b:a9:b5:16:
- ce:da:bd:ff:cc:b5:c9:1a:4b:35:f4:d3:68:44:de:96:4c:32:
- 8c:91:e6:72:b0:0c:93:05:a7:79:af:4f:ae:dd:e7:29:00:85:
- a1:7b:89:88:1e:55:e0:0b:92:37:8b:a7:11:2a:9d:24:22:37:
- ce:bd:d9:34:6b:15:eb:fa:7c:e7:40:b0:f1:df:ee:3a:84:75:
- 95:b1:2d:35:8a:79:c5:5a:72:23:79:95:c4:05:b1:8f:9c:86:
- 34:5b:a7:c5:7b:3b:62:90:11:82:05:9a:1f:96:de:48:1a:e1:
- d5:29:4a:b1:2b:3c:84:0a:21:a6:8a:84:b8:23:ab:a2:ad:77:
- 1f:a6:7e:07:ba:46:0c:62:12:cb:ac:99:33:84:b9:5c:c9:0d:
- d7:45:bc:d4
+ 29:19:26:6f:9b:96:e4:3d:38:b7:89:84:79:9e:73:09:0c:fe:
+ f8:4a:8d:13:84:15:ae:0f:56:4a:42:fb:17:81:8b:34:52:c3:
+ 51:93:96:04:75:9b:35:54:e1:05:31:c4:9d:28:0f:20:d5:7c:
+ 18:86:6e:02:4f:d8:58:2a:02:7e:d0:72:39:16:03:24:77:34:
+ 58:98:2e:f8:9a:ef:97:a3:11:b1:06:94:ec:1f:bb:3f:00:10:
+ 0b:24:d1:10:d6:c1:87:bf:f1:1e:fa:e0:99:e7:d9:22:d3:e9:
+ 80:7c:98:be:2c:af:b4:d9:c6:a7:52:35:fb:a4:a8:34:1d:e9:
+ 00:c7:f5:79:14:06:17:40:dd:15:62:04:0f:87:84:98:72:ed:
+ 47:da:6b:0c:d3:09:51:c3:d1:ae:df:96:8c:b7:68:e7:81:b9:
+ d1:a6:e0:3c:b7:93:f4:39:d5:c1:d7:78:3a:06:95:5c:e5:a5:
+ 13:bf:27:ca:7c:3c:69:b6:f8:3b:a1:40:3e:2f:d5:28:e3:c1:
+ f8:ed:76:19:2a:93:e4:2b:a4:09:8a:9c:9a:ad:c6:36:23:fb:
+ 6d:70:02:fc:77:a9:4d:0e:c0:e9:61:f7:06:73:9e:42:4a:92:
+ b3:4e:47:c2:fe:fe:1d:46:81:d4:85:a8:e4:52:6a:92:28:18:
+ c7:8c:69:8e
-----BEGIN CERTIFICATE-----
-MIIDvzCCAqegAwIBAgIBATANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
+MIIDvzCCAqegAwIBAgIBBDANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
DTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowETEPMA0GA1UEAwwGdGFyZ2V0
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoEApKzgYmlPg4OMU5DDP
-+YVr+ToXwvki+GS/sN6FbTfdOJqT2cvGkopuxCwQLcs9mNLoCVnkKLP+yXVG96er
-3ibZR3MIvJHOXFxPQ/EzU10sO/P0aedG2LV3dZTTG/CPXvx9yiqR+IHCcbi5hgk/
-veT7nNcmZXa45ptutnL8dejfVTAkgSQ9pYBQvHYVKYKJNFgLYVdI/dNPPq0px7yR
-zvcnfprwgpGffM5YTr8D+2ksLvTmo6S3EGLDwCjM/9yhFknA9XDakwnJZafhEAKs
-w0BchNfbe/RfA2tO0xgQuhGl3R+ChSRevTKkCEqc/cST54atW/YKIWDMIooTpHdE
-YwIDAQABo4IBJTCCASEwHQYDVR0OBBYEFIVv2s7lKCo8q4hWCMhag7W4ejEnMB8G
-A1UdIwQYMBaAFF20c6obYBCeDLwWu6QKWA22KA4EMIGEBggrBgEFBQcBAQR4MHYw
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxQXIalFFcLU4VgmxNT7m
+FNSTE9FOBR3hSeZeDXuxApYxoBxzWtlLLOpdI3FDz4hekuE1sltNibK15L2sN834
+QntTQ5qrBYJsZ41ALBW4Zz33+tR1QNExWOLoSPYT8cnRj414MwDxiak1jiL5/7Ok
+g5JZdeNDkNmDs6jOZAQOoR1cpLLAGdQDybw5rTOcJuLKv0SFNCCSqDRgTqPsEcJf
+5KoZbP5AwK3NQWnEk5TWS+XPmAxo8ZQl7I/HYn+LnRQTGFEQY6m8uHEkRIYnAdY9
+hK592lDbnGS/Xv81Pu6QL3JErIbySngWAEMGEL1Pg8rgmgdSsyzf60vz53KAIa0S
+MwIDAQABo4IBJTCCASEwHQYDVR0OBBYEFOwmUUCxQJAyMNtefKRS7reHgrMKMB8G
+A1UdIwQYMBaAFKRm4kb3P6FznaLiTimZ2y42Nmy1MIGEBggrBgEFBQcBAQR4MHYw
JAYIKwYBBQUHMAKGGGh0dHA6Ly91cmwtZm9yLWFpYS9JLmNlcjAmBggrBgEFBQcw
AoYaaHR0cDovL3VybC1mb3ItYWlhMi9JMi5mb28wJgYIKwYBBQUHMAKGGmh0dHA6
Ly91cmwtZm9yLWFpYTMvSTMuZm9vMCkGA1UdHwQiMCAwHqAcoBqGGGh0dHA6Ly91
cmwtZm9yLWNybC9JLmNybDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYB
-BQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBLVpgGXCeBPN3mKW+Z
-9piQu9SL/UjVOvtB1Ys4uP9HPcru4qTFQllc0sIH8iH51z+RpasWW+zab9t7DepY
-4Zv410q/2uIYxz+g4AvBQ7nXubXWnRJLzuWOf/HOzaIRY2WbWSj+fbm/mhuptRbO
-2r3/zLXJGks19NNoRN6WTDKMkeZysAyTBad5r0+u3ecpAIWhe4mIHlXgC5I3i6cR
-Kp0kIjfOvdk0axXr+nznQLDx3+46hHWVsS01innFWnIjeZXEBbGPnIY0W6fFezti
-kBGCBZoflt5IGuHVKUqxKzyECiGmioS4I6uirXcfpn4HukYMYhLLrJkzhLlcyQ3X
-RbzU
+BQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQApGSZvm5bkPTi3iYR5
+nnMJDP74So0ThBWuD1ZKQvsXgYs0UsNRk5YEdZs1VOEFMcSdKA8g1XwYhm4CT9hY
+KgJ+0HI5FgMkdzRYmC74mu+XoxGxBpTsH7s/ABALJNEQ1sGHv/Ee+uCZ59ki0+mA
+fJi+LK+02canUjX7pKg0HekAx/V5FAYXQN0VYgQPh4SYcu1H2msM0wlRw9Gu35aM
+t2jngbnRpuA8t5P0OdXB13g6BpVc5aUTvyfKfDxptvg7oUA+L9Uo48H47XYZKpPk
+K6QJipyarcY2I/ttcAL8d6lNDsDpYfcGc55CSpKzTkfC/v4dRoHUhajkUmqSKBjH
+jGmO
-----END CERTIFICATE-----
diff --git a/chromium/net/data/cert_issuer_source_aia_unittest/target_two_aia.pem b/chromium/net/data/cert_issuer_source_aia_unittest/target_two_aia.pem
index b89a59831d9..d3c5478794f 100644
--- a/chromium/net/data/cert_issuer_source_aia_unittest/target_two_aia.pem
+++ b/chromium/net/data/cert_issuer_source_aia_unittest/target_two_aia.pem
@@ -1,7 +1,7 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 1 (0x1)
+ Serial Number: 3 (0x3)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=I
Validity
@@ -12,30 +12,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:a6:9b:8a:af:3c:e1:f4:00:96:d0:7e:c0:33:21:
- 5d:f6:89:41:a8:4b:0a:a0:4f:cd:55:4e:e7:f4:be:
- 67:c3:4f:69:41:b7:06:13:8f:a5:d9:a9:45:0f:13:
- a2:25:48:a6:0b:1f:fb:c2:61:d8:ee:3f:0e:c4:ce:
- cd:36:9f:e6:73:6b:ca:b9:6b:6d:55:f7:61:64:b1:
- 85:bb:61:ea:f3:1f:d4:6e:8b:cb:0b:47:e5:60:98:
- a4:ab:be:62:70:df:3f:dc:63:37:9f:cb:16:5e:c1:
- e7:38:5c:6c:f5:d4:f5:ce:c4:ec:82:23:0e:b4:a1:
- 96:40:c5:e8:ce:39:7f:63:be:87:39:94:a6:d3:eb:
- 43:c9:19:37:7a:97:27:03:7a:46:51:71:9d:38:04:
- 30:ae:20:bb:28:69:b4:68:b9:cc:88:29:63:e9:1c:
- 16:f4:c3:94:ec:bd:b4:b4:75:8b:05:2b:6d:98:96:
- 4a:ca:ad:55:92:fd:fa:53:09:8a:ff:4d:f5:62:e9:
- 95:3e:15:7a:7e:23:65:c5:aa:55:15:13:9b:b4:9e:
- 8a:e1:f0:01:e2:a8:2b:ac:b6:bf:aa:b2:8d:85:80:
- 30:d7:ed:0a:24:78:d2:83:46:29:b7:5c:42:8e:ad:
- 8d:3a:d9:b8:ef:d3:5e:13:6a:3b:5b:42:d1:f6:b6:
- 23:d7
+ 00:c7:7e:c5:20:13:8f:2f:6f:f4:b8:ab:93:2c:8c:
+ f5:1f:fe:91:44:a1:81:db:81:f4:12:5c:24:60:f3:
+ 7a:b2:67:a3:7e:9a:31:52:ee:7d:40:1a:3f:e5:88:
+ 12:33:55:ec:c9:6e:ac:78:01:95:d2:8b:bb:e3:8f:
+ 37:4a:3e:0c:3f:7f:ae:27:d5:26:7d:65:03:c3:2b:
+ fe:73:58:67:88:ca:53:e8:cd:2d:41:32:6d:f9:06:
+ 4a:5c:7c:02:1f:43:1a:5a:80:48:68:ea:46:fa:b5:
+ b7:cd:cb:46:9a:b9:d7:fe:1c:ba:34:c3:cc:d9:fa:
+ 29:73:81:84:33:ff:bd:25:54:4c:bc:21:76:0b:a7:
+ 02:00:8f:b0:23:b1:54:07:da:f6:10:01:3f:8d:5a:
+ 3e:fb:f5:e6:73:c0:87:c5:f8:3a:e0:d6:69:9b:d4:
+ 3b:31:29:cb:44:d7:44:db:7f:d2:62:08:b5:91:dd:
+ d9:1f:f4:7c:23:11:8e:1d:4e:5e:02:b9:7d:6f:f6:
+ b0:25:b6:a7:5b:3d:26:68:63:ee:71:b9:26:06:cf:
+ 26:34:84:5d:05:80:33:2d:c9:d7:15:eb:18:8a:7a:
+ de:60:57:05:2b:c6:fe:92:41:ec:d5:3d:e5:73:3a:
+ 02:fb:68:8c:47:81:04:68:ff:f5:a4:ac:6c:0d:4b:
+ 34:59
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 8A:A2:2E:9D:41:67:1D:60:D2:82:F7:96:D4:53:5A:97:22:83:C7:75
+ BF:E5:92:1F:97:33:C4:D7:72:C3:BC:27:2E:AE:D9:A2:62:ED:4F:A4
X509v3 Authority Key Identifier:
- keyid:5D:B4:73:AA:1B:60:10:9E:0C:BC:16:BB:A4:0A:58:0D:B6:28:0E:04
+ keyid:A4:66:E2:46:F7:3F:A1:73:9D:A2:E2:4E:29:99:DB:2E:36:36:6C:B5
Authority Information Access:
CA Issuers - URI:http://url-for-aia/I.cer
@@ -51,40 +51,40 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- a5:c4:8d:e3:9e:72:cb:88:50:df:ee:44:96:f3:3d:f3:0d:37:
- be:b8:1c:39:79:80:a3:88:ac:3b:a2:01:73:7e:97:0f:ce:dc:
- 3c:c1:34:e7:fc:c3:9d:f1:fa:13:3a:93:a1:35:31:dd:42:8b:
- 8c:0e:0a:9e:01:42:10:93:b0:a5:16:43:32:c9:f1:1c:56:bf:
- 7e:5c:e3:c5:99:7d:19:a1:0a:bf:d0:92:c8:77:f7:5b:bb:d8:
- ac:28:c8:d9:0c:9c:e4:02:b0:09:28:f0:56:e5:03:31:50:e5:
- 3d:7d:ba:8f:c8:94:9e:90:67:2c:4e:d9:2c:3d:62:b4:3c:e9:
- 5e:0a:d9:82:7b:5b:b7:19:0b:a8:6f:e1:14:c2:8f:4b:52:b4:
- 07:54:1b:d9:cf:4d:7a:ab:90:58:15:93:e6:04:53:3b:81:87:
- 20:37:53:65:27:dd:ba:ac:d5:ca:75:21:f7:5b:c1:45:8d:a6:
- 14:68:33:cf:2e:cd:19:09:9e:ad:07:15:5c:6d:52:6a:c5:fc:
- 6c:cd:39:ce:7b:8b:62:ea:cb:7d:c2:d2:8f:99:9b:af:e8:c8:
- 9a:a8:ed:08:92:00:b1:ed:c5:e4:20:55:c6:5c:ad:5e:df:2d:
- 92:b7:d9:d6:fc:9b:cc:6f:eb:ae:55:cc:53:26:8c:68:54:96:
- 35:23:eb:fd
+ 83:06:60:e4:a1:2b:c6:df:4f:7a:02:d1:b4:7d:79:c7:23:73:
+ d8:4f:35:f4:ca:18:67:13:d5:93:47:c6:8e:9f:4c:2a:5b:ea:
+ 53:db:8b:a2:64:96:3c:4c:3f:e1:e1:1b:1e:c1:14:26:6f:95:
+ 68:07:28:c9:92:c6:ea:24:a8:ea:c2:85:4b:be:a5:6c:52:86:
+ 43:47:b8:bf:a6:7b:c6:58:00:0e:eb:a7:73:3d:4b:e4:ac:2a:
+ 94:d0:5b:68:26:19:90:ad:59:78:34:27:84:d2:11:5c:67:02:
+ ba:90:bf:91:3f:99:84:c9:af:98:1b:9b:73:70:16:55:8c:d7:
+ 5f:11:8e:49:ce:14:82:20:17:ca:b3:ed:21:a1:a6:d4:dc:3d:
+ 14:67:d2:05:a2:59:81:73:42:e8:24:82:b3:97:f6:82:43:b5:
+ db:e0:a3:22:eb:bd:f9:e3:d0:de:2a:92:dc:4a:4b:b0:02:c1:
+ 3c:30:de:0a:fa:17:20:f5:9a:76:c8:c7:b7:b0:3b:52:05:d2:
+ 91:b2:39:18:74:9d:4b:77:d3:29:2d:ce:e3:c4:ba:c5:25:8d:
+ 22:17:b0:cc:42:0d:50:b0:2b:fc:99:b7:cb:d6:8a:4b:1e:a7:
+ 3b:3e:0c:c1:a4:b6:2e:da:10:0b:98:b7:f8:4b:5f:65:ca:44:
+ d7:7b:19:08
-----BEGIN CERTIFICATE-----
-MIIDlDCCAnygAwIBAgIBATANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
+MIIDlDCCAnygAwIBAgIBAzANBgkqhkiG9w0BAQsFADAMMQowCAYDVQQDDAFJMB4X
DTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowETEPMA0GA1UEAwwGdGFyZ2V0
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAppuKrzzh9ACW0H7AMyFd
-9olBqEsKoE/NVU7n9L5nw09pQbcGE4+l2alFDxOiJUimCx/7wmHY7j8OxM7NNp/m
-c2vKuWttVfdhZLGFu2Hq8x/UbovLC0flYJikq75icN8/3GM3n8sWXsHnOFxs9dT1
-zsTsgiMOtKGWQMXozjl/Y76HOZSm0+tDyRk3epcnA3pGUXGdOAQwriC7KGm0aLnM
-iClj6RwW9MOU7L20tHWLBSttmJZKyq1Vkv36UwmK/031YumVPhV6fiNlxapVFROb
-tJ6K4fAB4qgrrLa/qrKNhYAw1+0KJHjSg0Ypt1xCjq2NOtm479NeE2o7W0LR9rYj
-1wIDAQABo4H7MIH4MB0GA1UdDgQWBBSKoi6dQWcdYNKC95bUU1qXIoPHdTAfBgNV
-HSMEGDAWgBRdtHOqG2AQngy8FrukClgNtigOBDBcBggrBgEFBQcBAQRQME4wJAYI
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx37FIBOPL2/0uKuTLIz1
+H/6RRKGB24H0ElwkYPN6smejfpoxUu59QBo/5YgSM1XsyW6seAGV0ou74483Sj4M
+P3+uJ9UmfWUDwyv+c1hniMpT6M0tQTJt+QZKXHwCH0MaWoBIaOpG+rW3zctGmrnX
+/hy6NMPM2fopc4GEM/+9JVRMvCF2C6cCAI+wI7FUB9r2EAE/jVo++/Xmc8CHxfg6
+4NZpm9Q7MSnLRNdE23/SYgi1kd3ZH/R8IxGOHU5eArl9b/awJbanWz0maGPucbkm
+Bs8mNIRdBYAzLcnXFesYinreYFcFK8b+kkHs1T3lczoC+2iMR4EEaP/1pKxsDUs0
+WQIDAQABo4H7MIH4MB0GA1UdDgQWBBS/5ZIflzPE13LDvCcurtmiYu1PpDAfBgNV
+HSMEGDAWgBSkZuJG9z+hc52i4k4pmdsuNjZstTBcBggrBgEFBQcBAQRQME4wJAYI
KwYBBQUHMAKGGGh0dHA6Ly91cmwtZm9yLWFpYS9JLmNlcjAmBggrBgEFBQcwAoYa
aHR0cDovL3VybC1mb3ItYWlhMi9JMi5mb28wKQYDVR0fBCIwIDAeoBygGoYYaHR0
cDovL3VybC1mb3ItY3JsL0kuY3JsMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAU
-BggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAKXEjeOecsuI
-UN/uRJbzPfMNN764HDl5gKOIrDuiAXN+lw/O3DzBNOf8w53x+hM6k6E1Md1Ci4wO
-Cp4BQhCTsKUWQzLJ8RxWv35c48WZfRmhCr/Qksh391u72KwoyNkMnOQCsAko8Fbl
-AzFQ5T19uo/IlJ6QZyxO2Sw9YrQ86V4K2YJ7W7cZC6hv4RTCj0tStAdUG9nPTXqr
-kFgVk+YEUzuBhyA3U2Un3bqs1cp1IfdbwUWNphRoM88uzRkJnq0HFVxtUmrF/GzN
-Oc57i2Lqy33C0o+Zm6/oyJqo7QiSALHtxeQgVcZcrV7fLZK32db8m8xv665VzFMm
-jGhUljUj6/0=
+BggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAIMGYOShK8bf
+T3oC0bR9eccjc9hPNfTKGGcT1ZNHxo6fTCpb6lPbi6JkljxMP+HhGx7BFCZvlWgH
+KMmSxuokqOrChUu+pWxShkNHuL+me8ZYAA7rp3M9S+SsKpTQW2gmGZCtWXg0J4TS
+EVxnArqQv5E/mYTJr5gbm3NwFlWM118RjknOFIIgF8qz7SGhptTcPRRn0gWiWYFz
+QugkgrOX9oJDtdvgoyLrvfnj0N4qktxKS7ACwTww3gr6FyD1mnbIx7ewO1IF0pGy
+ORh0nUt30yktzuPEusUljSIXsMxCDVCwK/yZt8vWiksepzs+DMGkti7aEAuYt/hL
+X2XKRNd7GQg=
-----END CERTIFICATE-----
diff --git a/chromium/net/data/cert_issuer_source_static_unittest/generate-certs.py b/chromium/net/data/cert_issuer_source_static_unittest/generate-certs.py
index c67cc81ebe4..e15fd912f2f 100755
--- a/chromium/net/data/cert_issuer_source_static_unittest/generate-certs.py
+++ b/chromium/net/data/cert_issuer_source_static_unittest/generate-certs.py
@@ -47,16 +47,16 @@ root = common.create_self_signed_root_certificate('Root')
write_cert_to_file(root, 'root.pem')
-# Intermediary certificates
-i1_1 = common.create_intermediary_certificate('I1', root)
+# Intermediate certificates
+i1_1 = common.create_intermediate_certificate('I1', root)
write_cert_to_file(i1_1, 'i1_1.pem')
# same name (after normalization), different key
-i1_2 = common.create_intermediary_certificate('i1', root)
+i1_2 = common.create_intermediate_certificate('i1', root)
write_cert_to_file(i1_2, 'i1_2.pem')
# different name
-i2 = common.create_intermediary_certificate('I2', root)
+i2 = common.create_intermediate_certificate('I2', root)
write_cert_to_file(i2, 'i2.pem')
diff --git a/chromium/net/data/ftp/dir-listing-ls-20.expected b/chromium/net/data/ftp/dir-listing-ls-20.expected
index ffa263de195..2b51bd72abe 100644
--- a/chromium/net/data/ftp/dir-listing-ls-20.expected
+++ b/chromium/net/data/ftp/dir-listing-ls-20.expected
@@ -35,7 +35,7 @@ _READ_ME.txt
24
d
-Áåç_ëèöà_-_Face_Off-(1997)-[1080p]_[BD]
+Без_лица_-_Face_Off-(1997)-[1080p]_[BD]
-1
1994
11
@@ -44,7 +44,7 @@ d
27
d
-Ââåðõ_-_Up-(2009)-[1080p]_[BD]
+Вверх_-_Up-(2009)-[1080p]_[BD]
-1
2010
1
@@ -53,7 +53,7 @@ d
0
d
-Âñïîìíèòü_âñå_-_Total_Recall-(1990)-[1080p]_[BD]
+Вспомнить_все_-_Total_Recall-(1990)-[1080p]_[BD]
-1
1994
5
@@ -62,7 +62,7 @@ d
12
d
-Çàêîíîïîñëóøíûé_ãðàæäàíèí_[Ðàñøèðåííàÿ_âåðñèÿ]_-_Law_Abiding_Citizen_[Unrated_Edition]-(2009)-[1080p]_[BD_Remux]
+Законопослушный_гражданин_[Расширенная_версия]_-_Law_Abiding_Citizen_[Unrated_Edition]-(2009)-[1080p]_[BD_Remux]
-1
1994
5
@@ -71,7 +71,7 @@ d
28
d
-Ìîíñòðî_-_Cloverfield-(2008)-[1080p]_[BD]
+Монстро_-_Cloverfield-(2008)-[1080p]_[BD]
-1
2010
1
@@ -80,7 +80,7 @@ d
0
d
-Ïàíäîðóì_-_Pandorum-(2009)-[1080p]_[BD]
+Пандорум_-_Pandorum-(2009)-[1080p]_[BD]
-1
1994
5
@@ -89,7 +89,7 @@ d
43
d
-Ïîñëåäíèé_ñàìóðàé_-_The_Last_Samurai-(2003)-[1080p]_[BD]
+Последний_самурай_-_The_Last_Samurai-(2003)-[1080p]_[BD]
-1
1994
5
@@ -98,7 +98,7 @@ d
18
d
-Ðàéîí_9_-_District_9-(2009)-[1080p]_[BD]
+Район_9_-_District_9-(2009)-[1080p]_[BD]
-1
2010
1
@@ -107,7 +107,7 @@ d
0
d
-Ðîêêè_Àíòîëîãèÿ_-_Rocky_The_Undisputed_Collection-(1976_1979_1982_1985_1990)-[1080p]_[BD]
+Рокки_Антология_-_Rocky_The_Undisputed_Collection-(1976_1979_1982_1985_1990)-[1080p]_[BD]
-1
2010
1
@@ -116,7 +116,7 @@ d
0
d
-Ñóððîãàòû_-_Surrogates-(2009)-[1080p]_[BD]
+Суррогаты_-_Surrogates-(2009)-[1080p]_[BD]
-1
1994
5
@@ -125,7 +125,7 @@ d
57
d
-Òðîéíîé_Ôîðñàæ-Òîêèéñêèé_Äðèôò_-_The_Fast_and_the_Furious-Tokyo_Drift-(2006)-[1080p]_[BD]
+Тройной_Форсаж-Токийский_Дрифт_-_The_Fast_and_the_Furious-Tokyo_Drift-(2006)-[1080p]_[BD]
-1
2010
1
@@ -134,7 +134,7 @@ d
0
d
-Ôîðñàæ_-_The_Fast_and_the_Furious-(2001)-[1080p]_[BD]
+Форсаж_-_The_Fast_and_the_Furious-(2001)-[1080p]_[BD]
-1
2010
1
@@ -143,7 +143,7 @@ d
0
d
-Ôîðñàæ_2_-_2_Fast_2_Furious-(2003)-[1080p]_[BD]
+Форсаж_2_-_2_Fast_2_Furious-(2003)-[1080p]_[BD]
-1
2010
1
@@ -152,7 +152,7 @@ d
0
d
-Ôîðñàæ_4_-_Fast_&_Furious-(2009)-[1080p]_[BD]
+Форсаж_4_-_Fast_&_Furious-(2009)-[1080p]_[BD]
-1
1994
6
diff --git a/chromium/net/data/ftp/dir-listing-ls-21.expected b/chromium/net/data/ftp/dir-listing-ls-21.expected
index 087dac56c33..d86a006012f 100644
--- a/chromium/net/data/ftp/dir-listing-ls-21.expected
+++ b/chromium/net/data/ftp/dir-listing-ls-21.expected
@@ -26,7 +26,7 @@ _READ_ME.txt
24
d
-Àâàëîí_-_Avalon-(2001)-[1080p]_[BD_Remux]
+Авалон_-_Avalon-(2001)-[1080p]_[BD_Remux]
-1
2009
4
@@ -35,7 +35,7 @@ d
0
d
-Áðþñ_âñåìîãóùèé_-_Bruce_Almighty-(2003)-[1080p]_[BD]
+Брюс_всемогущий_-_Bruce_Almighty-(2003)-[1080p]_[BD]
-1
2009
6
@@ -44,7 +44,7 @@ d
0
d
-ÂÀËË-È_-_WALL-E-(2008)-[1080p]_[BD]
+ВАЛЛ-И_-_WALL-E-(2008)-[1080p]_[BD]
-1
2009
4
@@ -53,7 +53,7 @@ d
0
d
-Äæåéìñ_Áîíä_007-Êâàíò_ìèëîñåðäèÿ_-_James_Bond_007-Quantum_of_Solace-(2008)-[1080p]_[BD]
+Джеймс_Бонд_007-Квант_милосердия_-_James_Bond_007-Quantum_of_Solace-(2008)-[1080p]_[BD]
-1
2009
4
@@ -62,7 +62,7 @@ d
0
d
-Êîñìîñ-Òåððèòîðèÿ_cìåðòè_-_Dead_Space-Downfall-(2008)-[1080p]_[BD]
+Космос-Территория_cмерти_-_Dead_Space-Downfall-(2008)-[1080p]_[BD]
-1
2009
4
@@ -71,7 +71,7 @@ d
0
d
-Ìàäàãàñêàð_1_-_Madagascar_1-(2005)-[1080p]_[BD]
+Мадагаскар_1_-_Madagascar_1-(2005)-[1080p]_[BD]
-1
2009
7
@@ -80,7 +80,7 @@ d
0
d
-Ìàäàãàñêàð_2_-_Madagascar-Escape_2_Africa-(2008)-[1080p]_[BD]
+Мадагаскар_2_-_Madagascar-Escape_2_Africa-(2008)-[1080p]_[BD]
-1
2009
7
@@ -89,7 +89,7 @@ d
0
d
-Ìàòðèöà-Ïåðåçàãðóçêà_-_The_Matrix-Reloaded-(2003)-[1080p]_[BD]
+Матрица-Перезагрузка_-_The_Matrix-Reloaded-(2003)-[1080p]_[BD]
-1
2009
6
@@ -98,7 +98,7 @@ d
0
d
-Ìàòðèöà-Ðåâîëþöèÿ_-_The_Matrix-Revolutions-(2003)-[1080p]_[BD]
+Матрица-Революция_-_The_Matrix-Revolutions-(2003)-[1080p]_[BD]
-1
2009
6
@@ -107,7 +107,7 @@ d
0
d
-Ìàòðèöà_-_The_Matrix-(1999)-[1080p]_[BD]
+Матрица_-_The_Matrix-(1999)-[1080p]_[BD]
-1
2009
6
@@ -116,7 +116,7 @@ d
0
d
-Îáèòåëü_çëà_3_-_Resident_Evil-Extinction-(2007)-[1080p]_[BD]
+Обитель_зла_3_-_Resident_Evil-Extinction-(2007)-[1080p]_[BD]
-1
2009
7
@@ -125,7 +125,7 @@ d
0
d
-Îñòðîâ_-_The_Island-(2005)-[1080p]_[BD]
+Остров_-_The_Island-(2005)-[1080p]_[BD]
-1
2009
5
@@ -134,7 +134,7 @@ d
0
d
-Ïåðåâîç÷èê_3_-_Transporter_3-(2008)-[1080p]_[BD]
+Перевозчик_3_-_Transporter_3-(2008)-[1080p]_[BD]
-1
2009
7
@@ -143,7 +143,7 @@ d
0
d
-Ïèðàòû_Êàðèáñêîãî_ìîðÿ-Íà_êðàþ_Ñâåòà_-_Pirates_of_the_Caribbean-At_World's_End-(2007)-[1080p]_[BD]
+Пираты_Карибского_моря-На_краю_Света_-_Pirates_of_the_Caribbean-At_World's_End-(2007)-[1080p]_[BD]
-1
2009
5
@@ -152,7 +152,7 @@ d
0
d
-Ïèðàòû_Êàðèáñêîãî_ìîðÿ-Ïðîêëÿòèå_×åðíîé_Æåì÷óæèíû_-_Pirates_of_the_Caribbean-The_Curse_of_the_Black_Pearl-(2003)-[1080p]_[BD]
+Пираты_Карибского_моря-Проклятие_Черной_Жемчужины_-_Pirates_of_the_Caribbean-The_Curse_of_the_Black_Pearl-(2003)-[1080p]_[BD]
-1
2009
5
@@ -161,7 +161,7 @@ d
0
d
-Ïèðàòû_Êàðèáñêîãî_ìîðÿ-Ñóíäóê_ìåðòâåöà_-_Pirates_of_the_Caribbean-Dead_Man's_Chest-(2006)-[1080p]_[BD]
+Пираты_Карибского_моря-Сундук_мертвеца_-_Pirates_of_the_Caribbean-Dead_Man's_Chest-(2006)-[1080p]_[BD]
-1
2009
5
@@ -170,7 +170,7 @@ d
0
d
-Ïðèçðà÷íûé_ãîíùèê_-_Ghost_Rider-(2007)-[1080p]_[BD]
+Призрачный_гонщик_-_Ghost_Rider-(2007)-[1080p]_[BD]
-1
2009
5
@@ -179,7 +179,7 @@ d
0
d
-Ïðèíöåññà-íåâåñòà_-_The_Princess_Bride-(1987)-[1080p]_[BD]
+Принцесса-невеста_-_The_Princess_Bride-(1987)-[1080p]_[BD]
-1
2009
4
@@ -188,7 +188,7 @@ d
0
d
-Ñåêñ_è_101_ñìåðòü_-_Sex_and_Death_101-(2007)-[1080p]_[BD]
+Секс_и_101_смерть_-_Sex_and_Death_101-(2007)-[1080p]_[BD]
-1
2009
6
@@ -197,7 +197,7 @@ d
0
d
-Òðàíñôîðìåðû-Áîíóñ_äèñê_-_Transformers-Bonus_Disk-(2007)-[1080p]_[BD]
+Трансформеры-Бонус_диск_-_Transformers-Bonus_Disk-(2007)-[1080p]_[BD]
-1
2009
5
@@ -206,7 +206,7 @@ d
0
d
-Òðàíñôîðìåðû_-_Transformers-(2007)-[1080p]_[BD]
+Трансформеры_-_Transformers-(2007)-[1080p]_[BD]
-1
2009
4
@@ -215,7 +215,7 @@ d
0
d
-Òðèíàäöàòûé_ýòàæ_-_The_Thirteenth_Floor-(1999)-[1080p]_[BD]
+Тринадцатый_этаж_-_The_Thirteenth_Floor-(1999)-[1080p]_[BD]
-1
2009
6
@@ -224,7 +224,7 @@ d
0
d
-Óëè÷íûé_áîåö_-_Street_Fighter-(1994)-[1080p]_[BD_Remux]
+Уличный_боец_-_Street_Fighter-(1994)-[1080p]_[BD_Remux]
-1
2009
5
@@ -233,7 +233,7 @@ d
0
d
-×åãî_õîòÿò_æåíùèíû_-_What_Woman_Want-(2000)-[1080p]_[BD]
+Чего_хотят_женщины_-_What_Woman_Want-(2000)-[1080p]_[BD]
-1
2009
3
diff --git a/chromium/net/data/ftp/dir-listing-ls-22.expected b/chromium/net/data/ftp/dir-listing-ls-22.expected
index d3d9114514e..2bf724fb94b 100644
--- a/chromium/net/data/ftp/dir-listing-ls-22.expected
+++ b/chromium/net/data/ftp/dir-listing-ls-22.expected
@@ -26,7 +26,7 @@ _READ_ME.txt
23
d
-Àâàòàð_-_Avatar-(2009)-[1080p]_[BD]
+Аватар_-_Avatar-(2009)-[1080p]_[BD]
-1
1994
5
@@ -35,8 +35,8 @@ d
26
-
-Àìåðèêàíñêèé_ïèðîã_1_[Ðàñøèðåííàÿ_âåðñèÿ]_-_American_Pie_1_[Unrated_Edition]-(1999)-[1080p]_[BD_remux].ts
-17577705968
+Американский_пирог_1_[Расширенная_версия]_-_American_Pie_1_[Unrated_Edition]-(1999)-[1080p]_[BD_remux].ts
+17577705968
2009
3
8
@@ -44,8 +44,8 @@ d
0
-
-Áîëüøîé_êóø_-_Snatch-(2000)-[1080i]_[HDTV].ts
-15512934868
+Большой_куш_-_Snatch-(2000)-[1080i]_[HDTV].ts
+15512934868
2009
3
16
@@ -53,7 +53,7 @@ d
0
d
-Áîëüøîé_êóø_-_Snatch-(2000)-[1080p]_[BD_Remux]
+Большой_куш_-_Snatch-(2000)-[1080p]_[BD_Remux]
-1
1994
6
@@ -62,8 +62,8 @@ d
7
-
-Âîéíà_ìèðîâ_-_War_of_the_Worlds-(2005)-[720p]_[HDTV].mkv
-8900589105
+Война_миров_-_War_of_the_Worlds-(2005)-[720p]_[HDTV].mkv
+8900589105
2009
3
24
@@ -71,8 +71,8 @@ d
0
-
-Ãàíãñòåð_-_American_Gangster-(2007)-[1080p]_[BD_remux].mkv
-27728321654
+Гангстер_-_American_Gangster-(2007)-[1080p]_[BD_remux].mkv
+27728321654
2009
3
9
@@ -80,8 +80,8 @@ d
0
-
-Ãàíãñòåð_[Ðàñøèðåííàÿ_âåðñèÿ]_-_American_Gangster_[Unrated_Edition]-(2007)-[1080p]_[BD_remux].mkv
-31731782861
+Гангстер_[Расширенная_версия]_-_American_Gangster_[Unrated_Edition]-(2007)-[1080p]_[BD_remux].mkv
+31731782861
2009
3
9
@@ -89,8 +89,8 @@ d
0
-
-Äîðîæíîå_ïðèêëþ÷åíèå_-_Road_Trip-(2000)-[720p]_[HDTV_Rip].mkv
-5009104014
+Дорожное_приключение_-_Road_Trip-(2000)-[720p]_[HDTV_Rip].mkv
+5009104014
2009
3
24
@@ -98,8 +98,8 @@ d
0
-
-Çâ¸çäíûå_âîéíû-Ýïèçîä_2-Àòàêà_êëîíîâ_-_Star_Wars-Episode_2-Attack_of_the_Clones-(2002)-[1080i]_[HDTV].ts
-21410583980
+Звёздные_войны-Эпизод_2-Атака_клонов_-_Star_Wars-Episode_2-Attack_of_the_Clones-(2002)-[1080i]_[HDTV].ts
+21410583980
2009
3
11
@@ -107,8 +107,8 @@ d
0
-
-Çâ¸çäíûå_âîéíû-Ýïèçîä_3-Ìåñòü_Ñèòõîâ_-_Star_Wars-Episode_3-Revenge_of_the_Sith-(2005)-[1080i]_[HDTV].ts
-19858181688
+Звёздные_войны-Эпизод_3-Месть_Ситхов_-_Star_Wars-Episode_3-Revenge_of_the_Sith-(2005)-[1080i]_[HDTV].ts
+19858181688
2009
3
11
@@ -116,8 +116,8 @@ d
0
-
-Çâ¸çäíûé_äåñàíò_-_Starship_Troopers-(1997)-[1080p]_[BD_remux].mkv
-29026065728
+Звёздный_десант_-_Starship_Troopers-(1997)-[1080p]_[BD_remux].mkv
+29026065728
2009
3
16
@@ -125,8 +125,8 @@ d
0
-
-Çåðêàëà_[Ðàñøèðåííàÿ_âåðñèÿ]_-_Mirrors_[Unrated_Edition]-(2008)-[1080p]_[BD_remux].mkv
-22169179449
+Зеркала_[Расширенная_версия]_-_Mirrors_[Unrated_Edition]-(2008)-[1080p]_[BD_remux].mkv
+22169179449
2009
3
16
@@ -134,7 +134,7 @@ d
0
d
-Íèíäçÿ-óáèéöà_-_Ninja_Assassin-(2009)-[1080p]_[BD]
+Ниндзя-убийца_-_Ninja_Assassin-(2009)-[1080p]_[BD]
-1
1994
6
@@ -143,8 +143,8 @@ d
56
-
-Îáèòåëü_çëà_3_-_Resident_Evil-Extinction-(2007)-[1080p]_[BD_remux].mkv
-19717173247
+Обитель_зла_3_-_Resident_Evil-Extinction-(2007)-[1080p]_[BD_remux].mkv
+19717173247
2009
3
11
@@ -152,8 +152,8 @@ d
0
-
-Ïàòîëîãèÿ_-_Pathology-(2008)-[1080p]_[BD_remux].mkv
-18660904388
+Патология_-_Pathology-(2008)-[1080p]_[BD_remux].mkv
+18660904388
2009
3
11
@@ -161,8 +161,8 @@ d
0
-
-Ïèëà_1_[Ðåæèññ¸ðñêàÿ_âåðñèÿ]_-_Saw_I_[Director's_Cut]-(2004)-[1080p]_[HDDVD_remux].mkv
-16476154520
+Пила_1_[Режиссёрская_версия]_-_Saw_I_[Director's_Cut]-(2004)-[1080p]_[HDDVD_remux].mkv
+16476154520
2009
3
5
@@ -170,8 +170,8 @@ d
0
-
-Ïèëà_2_[Ðåæèññ¸ðñêàÿ_âåðñèÿ]_-_Saw_II_[Director's_Cut]-(2005)-[1080p]_[BD_remux].mkv
-19917510515
+Пила_2_[Режиссёрская_версия]_-_Saw_II_[Director's_Cut]-(2005)-[1080p]_[BD_remux].mkv
+19917510515
2009
3
5
@@ -179,8 +179,8 @@ d
0
-
-Ïèëà_3_[Ðåæèññ¸ðñêàÿ_âåðñèÿ]_-_Saw_III_[Director's_Cut]-(2006)-[1080p]_[BD_remux].mkv
-18085592265
+Пила_3_[Режиссёрская_версия]_-_Saw_III_[Director's_Cut]-(2006)-[1080p]_[BD_remux].mkv
+18085592265
2009
3
5
@@ -188,8 +188,8 @@ d
0
-
-Ïèëà_4_[Ðåæèññ¸ðñêàÿ_âåðñèÿ]_-_Saw_IV_[Director's_Cut]-(2007)-[1080p]_[BD_remux].flac
-3473582701
+Пила_4_[Режиссёрская_версия]_-_Saw_IV_[Director's_Cut]-(2007)-[1080p]_[BD_remux].flac
+3473582701
2009
3
5
@@ -197,8 +197,8 @@ d
0
-
-Ïèëà_4_[Ðåæèññ¸ðñêàÿ_âåðñèÿ]_-_Saw_IV_[Director's_Cut]-(2007)-[1080p]_[BD_remux].mkv
-15263958421
+Пила_4_[Режиссёрская_версия]_-_Saw_IV_[Director's_Cut]-(2007)-[1080p]_[BD_remux].mkv
+15263958421
2009
3
5
@@ -206,8 +206,8 @@ d
0
-
-Ïèëà_5_[Ðåæèññ¸ðñêàÿ_âåðñèÿ]_-_Saw_V_[Director's_Cut]-(2008)-[1080p]_[BD_remux].mkv
-19944605507
+Пила_5_[Режиссёрская_версия]_-_Saw_V_[Director's_Cut]-(2008)-[1080p]_[BD_remux].mkv
+19944605507
2009
3
16
@@ -215,8 +215,8 @@ d
0
-
-Ïèíãâèíû_èç_Ìàäàãàñêàðà-Îïåðàöèÿ_Ñ_Íîâûì_Ãîäîì!_-_The_Madagascar_Penguins_in_A_Christmas_Caper-(2005)-[1080p]_[BD_remux].ts
-3024333064
+Пингвины_из_Мадагаскара-Операция_С_Новым_Годом!_-_The_Madagascar_Penguins_in_A_Christmas_Caper-(2005)-[1080p]_[BD_remux].ts
+3024333064
2009
3
24
@@ -224,8 +224,8 @@ d
0
-
-Ïëîõîé_Ñàíòà_[Ðàñøèðåííàÿ_âåðñèÿ]_-_Bad_Santa_[Unrated_Edition]-(2003)-[1080p]_[BD_remux].srt
-125961
+Плохой_Санта_[Расширенная_версия]_-_Bad_Santa_[Unrated_Edition]-(2003)-[1080p]_[BD_remux].srt
+125961
2009
3
5
@@ -233,8 +233,8 @@ d
0
-
-Ïëîõîé_Ñàíòà_[Ðàñøèðåííàÿ_âåðñèÿ]_-_Bad_Santa_[Unrated_Edition]-(2003)-[1080p]_[BD_remux].ts
-19908695408
+Плохой_Санта_[Расширенная_версия]_-_Bad_Santa_[Unrated_Edition]-(2003)-[1080p]_[BD_remux].ts
+19908695408
2009
3
5
@@ -242,8 +242,8 @@ d
0
-
-Ïîáåã_èç_Øîóøåíêà_-_The_Shawshank_Redemption-(1994)-[1080p]_[BD_remux].mkv
-23185439267
+Побег_из_Шоушенка_-_The_Shawshank_Redemption-(1994)-[1080p]_[BD_remux].mkv
+23185439267
2009
3
11
@@ -251,8 +251,8 @@ d
0
-
-Òóïîé_è_åùå_òóïåå_[Ðàñøèðåííàÿ_âåðñèÿ]_-_Dumb_and_Dumber_[Unrated_Edition]-(1994)-[1080p]_[BD_remux].mkv
-19567287274
+Тупой_и_еще_тупее_[Расширенная_версия]_-_Dumb_and_Dumber_[Unrated_Edition]-(1994)-[1080p]_[BD_remux].mkv
+19567287274
2009
3
16
@@ -260,8 +260,8 @@ d
0
-
-Óðàãàí_-_The_Hurricane-(1999)-[1080p]_[HDDVD_Rip].mkv
-14773061093
+Ураган_-_The_Hurricane-(1999)-[1080p]_[HDDVD_Rip].mkv
+14773061093
2009
3
16
@@ -269,8 +269,8 @@ d
0
-
-Õîñòåë_2_[Ðåæèññ¸ðñêàÿ_âåðñèÿ]_-_Hostel_2_[Director's_Cut]-(2007)-[1080p]_[BD_remux].ts
-22411268500
+Хостел_2_[Режиссёрская_версия]_-_Hostel_2_[Director's_Cut]-(2007)-[1080p]_[BD_remux].ts
+22411268500
2009
3
11
@@ -278,8 +278,8 @@ d
0
-
-×óæîé_ïðîòèâ_Õèùíèêà_[Ðàñøèðåííàÿ_âåðñèÿ]_-_Alien_vs_Predator_[Unrated_Edition]-(2004)-[1080p]_[BD_remux].mkv
-23712519861
+Чужой_против_Хищника_[Расширенная_версия]_-_Alien_vs_Predator_[Unrated_Edition]-(2004)-[1080p]_[BD_remux].mkv
+23712519861
2009
3
11
diff --git a/chromium/net/data/fuzzer_data/hostnames/ipv4_1.txt b/chromium/net/data/fuzzer_data/hostnames/ipv4_1.txt
new file mode 100644
index 00000000000..9e9000284bc
--- /dev/null
+++ b/chromium/net/data/fuzzer_data/hostnames/ipv4_1.txt
@@ -0,0 +1 @@
+192.168.246.137
diff --git a/chromium/net/data/fuzzer_data/hostnames/ipv4_2.txt b/chromium/net/data/fuzzer_data/hostnames/ipv4_2.txt
new file mode 100644
index 00000000000..d05e0ac90bd
--- /dev/null
+++ b/chromium/net/data/fuzzer_data/hostnames/ipv4_2.txt
@@ -0,0 +1 @@
+192.168.9.1.2
diff --git a/chromium/net/data/fuzzer_data/hostnames/ipv4_3.txt b/chromium/net/data/fuzzer_data/hostnames/ipv4_3.txt
new file mode 100644
index 00000000000..29206d18df3
--- /dev/null
+++ b/chromium/net/data/fuzzer_data/hostnames/ipv4_3.txt
@@ -0,0 +1 @@
+0300.0250.00.01
diff --git a/chromium/net/data/fuzzer_data/hostnames/ipv4_4.txt b/chromium/net/data/fuzzer_data/hostnames/ipv4_4.txt
new file mode 100644
index 00000000000..40860426ba0
--- /dev/null
+++ b/chromium/net/data/fuzzer_data/hostnames/ipv4_4.txt
@@ -0,0 +1 @@
+0xC0.0Xa8.0x0.0x1
diff --git a/chromium/net/data/fuzzer_data/hostnames/ipv4_5.txt b/chromium/net/data/fuzzer_data/hostnames/ipv4_5.txt
new file mode 100644
index 00000000000..86a03071994
--- /dev/null
+++ b/chromium/net/data/fuzzer_data/hostnames/ipv4_5.txt
@@ -0,0 +1 @@
+192
diff --git a/chromium/net/data/fuzzer_data/hostnames/ipv4_6.txt b/chromium/net/data/fuzzer_data/hostnames/ipv4_6.txt
new file mode 100644
index 00000000000..939df6fe2c5
--- /dev/null
+++ b/chromium/net/data/fuzzer_data/hostnames/ipv4_6.txt
@@ -0,0 +1 @@
+0xC0a80001
diff --git a/chromium/net/data/fuzzer_data/hostnames/ipv4_7.txt b/chromium/net/data/fuzzer_data/hostnames/ipv4_7.txt
new file mode 100644
index 00000000000..b3b6692cb48
--- /dev/null
+++ b/chromium/net/data/fuzzer_data/hostnames/ipv4_7.txt
@@ -0,0 +1 @@
+030052000001
diff --git a/chromium/net/data/fuzzer_data/hostnames/ipv4_8.txt b/chromium/net/data/fuzzer_data/hostnames/ipv4_8.txt
new file mode 100644
index 00000000000..0d3575e55cc
--- /dev/null
+++ b/chromium/net/data/fuzzer_data/hostnames/ipv4_8.txt
@@ -0,0 +1 @@
+192.168.0.1.
diff --git a/chromium/net/data/fuzzer_data/hostnames/ipv4_9.txt b/chromium/net/data/fuzzer_data/hostnames/ipv4_9.txt
new file mode 100644
index 00000000000..60ec947c2c5
--- /dev/null
+++ b/chromium/net/data/fuzzer_data/hostnames/ipv4_9.txt
@@ -0,0 +1 @@
+0000000000000300.0x00000000000000fF.00000000000000001
diff --git a/chromium/net/data/fuzzer_data/hostnames/ipv6_1.txt b/chromium/net/data/fuzzer_data/hostnames/ipv6_1.txt
new file mode 100644
index 00000000000..b604dd2735a
--- /dev/null
+++ b/chromium/net/data/fuzzer_data/hostnames/ipv6_1.txt
@@ -0,0 +1 @@
+[2001:cdba:0000:0000:0000:0000:3257:9652]
diff --git a/chromium/net/data/fuzzer_data/hostnames/ipv6_2.txt b/chromium/net/data/fuzzer_data/hostnames/ipv6_2.txt
new file mode 100644
index 00000000000..7b4c691ef66
--- /dev/null
+++ b/chromium/net/data/fuzzer_data/hostnames/ipv6_2.txt
@@ -0,0 +1 @@
+[::ffff:192.168.0.1]
diff --git a/chromium/net/data/fuzzer_data/hostnames/ipv6_3.txt b/chromium/net/data/fuzzer_data/hostnames/ipv6_3.txt
new file mode 100644
index 00000000000..dec357b25d1
--- /dev/null
+++ b/chromium/net/data/fuzzer_data/hostnames/ipv6_3.txt
@@ -0,0 +1 @@
+[::ffff:192.1.2]
diff --git a/chromium/net/data/fuzzer_data/hostnames/ipv6_4.txt b/chromium/net/data/fuzzer_data/hostnames/ipv6_4.txt
new file mode 100644
index 00000000000..b55537d7cc0
--- /dev/null
+++ b/chromium/net/data/fuzzer_data/hostnames/ipv6_4.txt
@@ -0,0 +1 @@
+[::ffff:0xC0.0Xa8.0x0.0x1]
diff --git a/chromium/net/data/fuzzer_data/hostnames/ipv6_5.txt b/chromium/net/data/fuzzer_data/hostnames/ipv6_5.txt
new file mode 100644
index 00000000000..08d55249952
--- /dev/null
+++ b/chromium/net/data/fuzzer_data/hostnames/ipv6_5.txt
@@ -0,0 +1 @@
+[0:0::0:0:8]
diff --git a/chromium/net/data/fuzzer_dictionaries/net_dns_hosts_parse_fuzzer.dict b/chromium/net/data/fuzzer_dictionaries/net_dns_hosts_parse_fuzzer.dict
new file mode 100644
index 00000000000..dd72cefbdbe
--- /dev/null
+++ b/chromium/net/data/fuzzer_dictionaries/net_dns_hosts_parse_fuzzer.dict
@@ -0,0 +1,843 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Fuzzer dictionary targetting DNS responses.
+
+# Some 16-bit big-endian values. Useful in a number of fields. Includes
+# A, AAAA, and CNAME IDs, low values for record counts, and multiples of
+# lengths of A and AAAA data fields.
+"\x00\x00"
+"\x00\x01"
+"\x00\x02"
+"\x00\x03"
+"\x00\x04"
+"\x00\x05"
+"\x00\x08"
+"\x00\x0C"
+"\x00\x10"
+"\x00\x1C"
+"\x00\x20"
+"\x00\x30"
+
+# Some encoded domain names.
+"\x03foo\x00"
+"\x03foo\x03com\x00"
+"\x01a\x03foo\x03com\x00"
+"\x03bar\x00"
+
+# Message headers (Without message ID field).
+"\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Truncated message, requiring TCP fallback.
+"\x83\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Varying number of answers
+"\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x02\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x10\x00\x00\x00\x00"
+
+# A, AAAA, and CNAME request suffixes - appear after domain name.
+"\x00\x01\x00\x01"
+"\x00\x1c\x00\x01"
+"\x00\x05\x00\x01"
+
+# A, AAAA, and CNAME requests for foo and foo.com.
+"\x03foo\x00\x00\x01\x00\x01"
+"\x03foo\x00\x00\x1c\x00\x01"
+"\x03foo\x00\x00\x05\x00\x01"
+"\x03foo\x03com\x00\x00\x01\x00\x01"
+"\x03foo\x03com\x00\x00\x1c\x00\x01"
+"\x03foo\x03com\x00\x00\x05\x00\x01"
+
+# All of the answers below are missing the name field, which should appear
+# first.
+
+# A answer suffixes, two different IP and TTLs.
+"\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x01\x02\x03\x04"
+"\x00\x01\x00\x01\x00\x00\x00\xFF\x00\x04\x02\x03\x04\x05"
+
+# AAAA answer suffixes, two different IPs and TTLs.
+"\x00\x1C\x00\x01\x00\x00\x00\x00\x00\x08\x01\x02\x03\x04\x05\x06\x07\x08"
+"\x00\x1C\x00\x01\x00\x00\x00\xFF\x00\x08\x02\x03\x04\x05\x06\x07\x08\x09"
+
+# CDATA answer suffixes, first two truncated as well.
+"\x00\x05\x00\x01\x00\x00\x00\xFF"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03foo\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03bar\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x09\x03foo\x03com\x00"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_dns_hosts_parse_fuzzer binary, RFC 1034 and RFC 1035.
+"all"
+"QNAME=ISI.EDU.,"
+"pointing"
+"C.ISI.EDU,"
+"C.ISI.EDU."
+"C.ISI.EDU)"
+"52.0.0.10.IN-ADDR.ARPA."
+"[RFC-799]"
+"XX.LCS.MIT.EDU,"
+"XX.LCS.MIT.EDU."
+"CPU"
+"C.ISI.EDU:"
+"A.B.C.D"
+"ARPA"
+"*.X.COM"
+"IN-ADDR.ARPA"
+"0"
+"\"*.X\","
+"resources"
+"supported"
+"string"
+"returning"
+"AXFR"
+"YALE.ARPA."
+"B.C.D,"
+"list"
+"large"
+"CNAME,"
+"ASCII"
+"M."
+"YALE.EDU."
+"direct"
+"IN,"
+"[RFC-1035]."
+"\"A\""
+"\"IN-ADDR.ARPA\"."
+"HINFO"
+"RFC-1031,"
+"QCLASS=IN,"
+"Z."
+"QCLASS=IN."
+"ARPANET"
+"QNAME=65.0.6.26.IN-ADDR.ARPA.,QCLASS=IN,QTYPE=PTR"
+"section"
+"51.0.0.10.IN-ADDR.ARPA."
+"|(VAXA.ISI.EDU,VENERA.ISI.EDU,"
+"DEC-2060"
+"version"
+"[RFC-1031]."
+"TTL"
+"[RFC-742]"
+"QTYPE=NS"
+"FTP"
+"hash"
+"QTYPE=CNAME,"
+"RFC-793,"
+"address"
+"SNAME,"
+"["
+"\"NAME/FINGER\","
+"SRI-NIC.ARPA."
+"SRI-NIC.ARPA,"
+"MB"
+"SRI-NIC.ARPA:"
+"QTYPE=CNAME"
+"NOT"
+"MX"
+"[RFC-821]"
+"useful"
+"select"
+"SRI-NIC.ARPA"
+"use"
+"SNAME"
+"from"
+"to"
+"positive"
+"(QCLASS)"
+"[RFC-1032]."
+"(DNS),"
+"TELNET,"
+"call"
+"B.X,"
+"memory"
+"type"
+"[RFC-973]"
+"RFC-822."
+"QNAME=SIR-NIC.ARPA,"
+"MILNET"
+"TOPS20"
+"[IEN-116,"
+"PTR)."
+"HOSTS.TXT,"
+"COMSAT,"
+"EXPIRE."
+"must"
+"EVEN"
+"|(C.ISI.EDU,SRI-NIC.ARPA"
+"QNAME=USC-ISIC.ARPA.,"
+"this"
+"CNAME."
+"work"
+"EDU,"
+"EDU."
+"EDU"
+"following"
+"root"
+"[RFC-1010]"
+"F."
+"J.,"
+"type."
+"high"
+"[RFC-953]"
+"US"
+"allowed"
+"serial"
+"IEN-116,"
+"[RFC-1032]"
+"[RFC-1033]."
+"write"
+"NOSC"
+"VENERA.ISI.EDU.|"
+"Z.X"
+"A"
+"QTYPE,"
+"[RFC-810]"
+"QTYPE."
+"may"
+"after"
+"RFC-1032,"
+"such"
+"data"
+"\"A"
+"a"
+"UDP"
+"short"
+"(CNAME)"
+"[RFC-1002]"
+"UDEL.EDU."
+"SRI,"
+"RFC-953."
+"RFC-953,"
+"TELNET)."
+"(HOSTS.TXT)"
+"ISI.EDU"
+"MIL"
+"[RFC-952]"
+"RFC-830,"
+"pointer"
+"its"
+"STYPE"
+"before"
+"HAS"
+"RR"
+"HOSTMASTER.SRI-NIC.ARPA."
+"65.0.6.26.IN-ADDR.ARPA,"
+"65.0.6.26.IN-ADDR.ARPA."
+"RD"
+"NAMES"
+"YALE"
+"QNAME=BRL.MIL,"
+"RA,"
+"ACM,"
+"QCLASS"
+"ARPA."
+"not"
+"(QTYPE),"
+"OPCODE=SQUERY,RESPONSE"
+"name"
+"RFC,"
+"mode"
+"RFC-799,"
+"ICS.UCI"
+"RESOLVERS"
+"A.X.COM"
+"SOME"
+"CNAME"
+"UDEL"
+"(QNAME),"
+"E."
+"space"
+"L."
+"MINIMUM"
+"RDATA"
+"supports"
+"REFRESH,"
+"HOSTMASTER@SRI-NIC.ARPA."
+"This"
+"SLIST:"
+"free"
+"RFC"
+"base"
+"RFC-952"
+"received."
+"SLIST."
+"SLIST,"
+"DATA."
+"thread"
+"YALE-BULLDOG.ARPA."
+"could"
+"QCLASS,"
+"times"
+"length"
+"HOSTMASTER@SRI-NIC.ARPA"
+"MIT.EDU"
+"already"
+"CONFIGURED"
+"number"
+"one"
+"RFC-"
+"Start"
+"ISI"
+"RFC."
+"RFC-1001,"
+"open"
+"CSNET"
+"size"
+"\""
+"X."
+"A.ISI.EDU"
+"TTL)"
+"\"HOSTNAME"
+"unknown"
+"top"
+"SERVERS"
+"too"
+"RFC-953]."
+"QTYPE"
+"BBN"
+"that"
+"completed"
+"XX"
+"*.A.X.COM"
+"QTYPE=MX,"
+"MX."
+"RD."
+"K."
+"target"
+"16"
+"Z.X),"
+"LCS.MIT.EDU"
+"[RFC-1031]"
+"and"
+"[RFC-805]"
+"[RFC-811]"
+"(RCODE)"
+"have"
+"need"
+"RESPONSE,"
+"null"
+"any"
+"contents"
+"|(SRI-NIC.ARPA,"
+"SOMEONE"
+"RESOURCE"
+"73.0.0.26.IN-ADDR.ARPA."
+"DARPA"
+"ACC.ARPA."
+"RFC-812,"
+"-"
+"mechanism"
+"internal"
+"take"
+"which"
+"MIL."
+"MIL,"
+"="
+"UCI"
+"RFC-742,"
+"multiple"
+"TCP/IP"
+"USC-ISIC.ARPA."
+"QNAME=USC-ISIC.ARPA,"
+"The"
+"]"
+"class"
+"D."
+"RFC-1010,"
+"D,"
+"RFC-805,"
+"AA,"
+"VAXA.ISI.EDU."
+"QNAME=ISI.EDU,"
+"MG)."
+"\"DOD"
+"QNAME=SRI-NIC.ARPA,"
+"text"
+"labels"
+"VENERA"
+"RFC-1033,"
+"INCORRECTLY"
+"[RFC-"
+"Z"
+"[RFC-952,"
+"RECORDS"
+"implementation"
+"true"
+"cache"
+"[RFC-768]"
+"XX.LCS.MIT.EDU"
+"only"
+"PVM@ISI.EDU."
+"RETRY,"
+"get"
+"PVM@ISI.EDU"
+"ACHILLES"
+"LOUIE.UDEL.EDU."
+"IN-ADDR"
+"resource"
+"A.ISI"
+"THIS"
+"NIC"
+"(via"
+"Zones"
+"RFC-920,"
+"J."
+"RFC-920."
+"common"
+"set"
+"configured"
+"QNAME=SRI-NIC.ARPA.,"
+"this,"
+"are"
+"RFC-883]."
+"A.ISI.EDU."
+"A.ISI.EDU)"
+"INTRODUCTION"
+"TCP"
+"MIT"
+"PC"
+"unable"
+"probably"
+"C.D,"
+"103.0.3.26.IN-ADDR.ARPA."
+"available"
+"C"
+"parent"
+"RFC-830]."
+"REFRESH"
+"UNIX"
+"CH)."
+"key"
+"52.0.0.10.IN-ADDR.ARPA"
+"P."
+"AND"
+"RFC-1002,"
+"OPCODE=SQUERY"
+"ROME.UCI"
+"LCS"
+"PDP-11/70"
+"ISI.EDU,"
+"ISI.EDU."
+"MAILB"
+"[RFC-974]"
+"CONCEPTS"
+"[RFC-920]"
+"SOA,"
+"RCODE=NE"
+"DNS."
+"DNS,"
+"poll"
+"UMN-REI-UC.ARPA."
+"SNAME."
+"[RFC-883]"
+"RFC-974,"
+"RFC-1002"
+"create"
+"S.,"
+"."
+"[RFC-830]"
+"expected"
+"empty"
+"RA"
+"CH"
+"(RD)"
+"VENERA.ISI.EDU."
+"SRI"
+"A.B.X,"
+"NAME"
+"value"
+"while"
+"error"
+"loop"
+"\"NICNAME/WHOIS\","
+"is"
+"CACHE"
+"FACILITIES"
+"in"
+"|(XX.LCS.MIT.EDU,"
+"SOA"
+"binary"
+"[RFC-819]"
+")"
+"SRI-NIC"
+"V."
+"\"A\"."
+"QNAME."
+"QNAME,"
+"units"
+"(NE)."
+"used"
+"IP"
+"\"."
+"IN"
+"ID"
+"IF"
+"task"
+"SCENARIO"
+"RFC-883,"
+"HOSTS.TXT"
+"Names"
+"RFC-811,"
+"the"
+"If"
+"being"
+"EXPIRE"
+"RFC-882,"
+"|ACHILLES.MIT.EDU)"
+"XX.COM."
+"(RDATA)"
+"source"
+"CSNET."
+"build"
+"ACHILLES.MIT.EDU."
+"format"
+"read"
+"(AA)"
+"ISIC.ARPA,"
+"SERIAL"
+"VAXA.ISI"
+"found,"
+"SLIST"
+"sorting"
+"OPCODE=SQUERY,"
+"OF"
+"AUTHORITY"
+"OS"
+"AA"
+"DOMAIN"
+"because"
+"SRI-NIC.ARPA.|"
+"some"
+"back"
+"growth"
+"USC-ISIC.ARPA,"
+"RFC-821,"
+"happens"
+"for"
+"W."
+"RFC-883"
+"X.COM"
+"avoid"
+"does"
+"allocate"
+"COM"
+"assuming"
+"BRL"
+"PTR"
+"[RFC-793]"
+"be"
+"QCLASS=*"
+"MIT.EDU."
+"by"
+"C."
+"on"
+"SCLASS"
+"of"
+"FTP)"
+"FTP,"
+"UK"
+"or"
+"ACC"
+"SBELT."
+"SBELT,"
+"No"
+"(SBELT)"
+"A.X.COM."
+"A.X.COM,"
+"REFERENCES"
+"USC-ISIC.ARPA"
+"[RFC-1001]"
+"RESPONSE"
+"transfer"
+"support"
+"*"
+"NE"
+"long"
+"QTYPE=*"
+"start"
+"C.ISI.EDU"
+"TTL,"
+"RD,"
+"\"4.3.2.1.IN-ADDR.ARPA\"."
+"NS"
+"was"
+"RR."
+"RR,"
+"QTYPE=A"
+"MEMO"
+"but"
+"QNAME"
+"[RFC-1001,"
+"DNS"
+"line"
+"trying"
+"with"
+"TCP/UDP"
+"count"
+"SBELT"
+"(NIC)"
+"up"
+"classes:"
+"RFC-768,"
+"[IEN-116]"
+"VAXA"
+"NETBIOS"
+"called"
+"delete"
+"CIC"
+"USC-"
+"RETRY"
+"RFC-810,"
+"RECORDS,"
+"an"
+"To"
+"as"
+"at"
+"file"
+"[RFC-812]"
+"physical"
+"X.COM,"
+"no"
+"[RFC-882,"
+"when"
+"A,"
+"virtual"
+"RFC-952,"
+"RFC-952."
+"valid"
+"test"
+"you"
+"IP/TCP"
+"STATUS"
+"requested"
+"[RFC-974"
+"SPACE"
+"QNAME=SIR-NIC.ARPA.,"
+"RFC-819,"
+"variable"
+"[RFC-882]"
+"BIBLIOGRAPHY"
+"[RFC-1033]"
+"US."
+"\"MILNET"
+"As"
+"RFC-973,"
+"RFC-882"
+"QTYPE=MX"
+"4.0.10.18.IN-ADDR.ARPA."
+"FOO.F.ISI.ARPA,"
+"Assuming"
+"[RFC-1034],"
+"[RFC-1034]."
+"UNIX\""
+"IMPLEMENTATION"
+"EGP."
+"ANCOUNT"
+"@"
+"P"
+"TXT-DATA"
+"RMAILBX"
+"|QTYPE=A,"
+"QDCOUNT"
+"[RFC-1010]."
+"EMAILBX"
+"IN-"
+"OPCODE=IQUERY,"
+"MX)"
+"ID=997"
+"\"VENERA.ISI.EDU\";"
+"OPCODE"
+"MILNET-GW.ISI.EDU."
+"52.0.2.10.IN-ADDR.ARPA."
+"objects"
+"MD"
+"MG"
+"MF"
+"MR"
+"QNAME=10.IN-ADDR.ARPA."
+"S."
+"GGP"
+"few"
+"QTYPE=PTR,"
+"MD,"
+"F"
+"[RFC-974]."
+"MGMNAME"
+"GW.LCS.MIT.EDU."
+"GW.LCS.MIT.EDU,"
+"V"
+"\\DDD"
+"ALL"
+"10.IN-ADDR.ARPA."
+"closing"
+"EXCHANGE."
+"MADNAME."
+"$ORIGIN"
+"HIS"
+"26.IN-ADDR.ARPA."
+"(MD)"
+"QTYPES"
+"PROTOCOL"
+"26.IN-ADDR.ARPA"
+"NSCOUNT"
+"(MR)"
+"PREFERENCE"
+"<BIT"
+"$INCLUDE."
+"MR)"
+"VAXA.ISI.EDU"
+"77.0.0.10.IN-ADDR.ARPA."
+"\"IBM-PC"
+"$INCLUDE"
+"SERVER"
+"18.IN-ADDR.ARPA."
+"ADDRESS"
+"Check"
+"static"
+"GW.ISI.EDU."
+"(QNAME)."
+"GW.ISI.EDU,"
+"F.ISI.ARPA,"
+"F.ISI.ARPA."
+"time."
+"PTRDNAME"
+"HOSTMASTER@SRI-"
+"(STATUS)"
+"(MINFO)"
+"(MG)"
+"QCLASS."
+"(HS)"
+"X,"
+"MNAME"
+"QNAME=VENERA.ISI.EDU"
+"MASTER"
+"(IN)"
+"KNOWS."
+"RNAME"
+"|QR|"
+"VAXA.ISI.EDU,"
+"R"
+"1)"
+"ARCOUNT"
+"RCODE"
+"NEWNAME"
+"CLASS"
+"begin"
+"(MF)."
+"Common"
+"<RDATA>"
+"QR"
+"average"
+"QNAME=6.0.0.10.IN-ADDR.ARPA,"
+"WKS"
+"SYSTEM,"
+"MADNAME"
+"ARPANET,"
+"MINFO"
+"DEFINITIONS"
+"failed"
+"[RFC-1034]"
+"(QCLASS),"
+"SPECIFICATION"
+"X"
+"THE"
+"MILNET."
+"MILNET-"
+"bytes"
+"(MX)"
+"NSDNAME"
+"10.IN-ADDR.ARPA"
+"|AA|TC|RD|RA|"
+"QTYPE=A,"
+"corruption"
+"FOO.F.ISI.ARPA"
+"(QUERY)"
+"MF,"
+"FOO"
+"CURLEY"
+"X.Y,"
+"AXFR,"
+"S"
+"MAILA"
+"exceeds"
+"ISI.EDU:"
+"103.0.0.26.IN-ADDR.ARPA."
+"MOE"
+"[RFC-822]."
+"CHAOS"
+"NAMEDROPPERS@SRI-NIC.ARPA"
+"SOA."
+"RESOLVER"
+"A.X,"
+"EXCHANGE"
+"SMTP"
+"QCLASS=*,"
+"CS"
+"$ORIGIN,"
+"B.X"
+"(MB,"
+"TYPE"
+"Size"
+"parse"
+"ADDR.ARPA"
+"(SMTP)."
+"key."
+"MAP>"
+"OWN"
+"VENERA.ISI.EDU"
+"DDD."
+"MB."
+"NS,"
+"I"
+"OPCODE=RESPONSE,"
+"ARPA,"
+"WITHIN"
+"tables"
+"unsigned"
+"LARRY"
+"D"
+"\\X"
+"WHICH"
+"(IQUERY)"
+"QCLASS=IN"
+"discarded"
+"6.0.0.10.IN-ADDR.ARPA."
+"MAIL"
+"QTYPE=MAILB"
+"HS"
+"SUPPORT"
+"STOOGES"
+"X.Y"
+"/"
+"(SLIST)."
+"O"
+"OS,"
+"OFFSET"
+"FILES"
+"RR),"
+"$INCLUDE,"
+"guard"
+"[<TTL>]"
+"CRLF"
+"Error"
+"ERRORS-TO:"
+"22.0.2.10.IN-ADDR.ARPA."
+"default"
+"MESSAGES"
+"signed"
+"<SUBSYS>ISI-MAILBOXES.TXT"
+"MULTICS.MIT.EDU."
+"NULL"
+"application"
+"TXT"
+"TC"
+"PROTOCOL=TCP"
+"UDP."
+"UDP,"
+"F.ISI.ARPA"
+"(EXPERIMENTAL)"
+"RDLENGTH"
+"NIC.ARPA"
+
diff --git a/chromium/net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict b/chromium/net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict
new file mode 100644
index 00000000000..eb26765b526
--- /dev/null
+++ b/chromium/net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict
@@ -0,0 +1,843 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Fuzzer dictionary targetting DNS responses.
+
+# Some 16-bit big-endian values. Useful in a number of fields. Includes
+# A, AAAA, and CNAME IDs, low values for record counts, and multiples of
+# lengths of A and AAAA data fields.
+"\x00\x00"
+"\x00\x01"
+"\x00\x02"
+"\x00\x03"
+"\x00\x04"
+"\x00\x05"
+"\x00\x08"
+"\x00\x0C"
+"\x00\x10"
+"\x00\x1C"
+"\x00\x20"
+"\x00\x30"
+
+# Some encoded domain names.
+"\x03foo\x00"
+"\x03foo\x03com\x00"
+"\x01a\x03foo\x03com\x00"
+"\x03bar\x00"
+
+# Message headers (Without message ID field).
+"\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Truncated message, requiring TCP fallback.
+"\x83\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Varying number of answers
+"\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x02\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x10\x00\x00\x00\x00"
+
+# A, AAAA, and CNAME request suffixes - appear after domain name.
+"\x00\x01\x00\x01"
+"\x00\x1c\x00\x01"
+"\x00\x05\x00\x01"
+
+# A, AAAA, and CNAME requests for foo and foo.com.
+"\x03foo\x00\x00\x01\x00\x01"
+"\x03foo\x00\x00\x1c\x00\x01"
+"\x03foo\x00\x00\x05\x00\x01"
+"\x03foo\x03com\x00\x00\x01\x00\x01"
+"\x03foo\x03com\x00\x00\x1c\x00\x01"
+"\x03foo\x03com\x00\x00\x05\x00\x01"
+
+# All of the answers below are missing the name field, which should appear
+# first.
+
+# A answer suffixes, two different IP and TTLs.
+"\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x01\x02\x03\x04"
+"\x00\x01\x00\x01\x00\x00\x00\xFF\x00\x04\x02\x03\x04\x05"
+
+# AAAA answer suffixes, two different IPs and TTLs.
+"\x00\x1C\x00\x01\x00\x00\x00\x00\x00\x08\x01\x02\x03\x04\x05\x06\x07\x08"
+"\x00\x1C\x00\x01\x00\x00\x00\xFF\x00\x08\x02\x03\x04\x05\x06\x07\x08\x09"
+
+# CDATA answer suffixes, first two truncated as well.
+"\x00\x05\x00\x01\x00\x00\x00\xFF"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03foo\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03bar\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x09\x03foo\x03com\x00"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_dns_record_fuzzer binary, RFC 1034 and RFC 1035.
+"all"
+"QNAME=ISI.EDU.,"
+"pointing"
+"C.ISI.EDU,"
+"C.ISI.EDU."
+"C.ISI.EDU)"
+"52.0.0.10.IN-ADDR.ARPA."
+"[RFC-799]"
+"XX.LCS.MIT.EDU,"
+"XX.LCS.MIT.EDU."
+"CPU"
+"C.ISI.EDU:"
+"A.B.C.D"
+"ARPA"
+"*.X.COM"
+"IN-ADDR.ARPA"
+"0"
+"\"*.X\","
+"resources"
+"supported"
+"string"
+"returning"
+"AXFR"
+"YALE.ARPA."
+"B.C.D,"
+"list"
+"large"
+"CNAME,"
+"ASCII"
+"M."
+"YALE.EDU."
+"direct"
+"IN,"
+"[RFC-1035]."
+"\"A\""
+"\"IN-ADDR.ARPA\"."
+"HINFO"
+"RFC-1031,"
+"QCLASS=IN,"
+"Z."
+"QCLASS=IN."
+"ARPANET"
+"QNAME=65.0.6.26.IN-ADDR.ARPA.,QCLASS=IN,QTYPE=PTR"
+"section"
+"51.0.0.10.IN-ADDR.ARPA."
+"|(VAXA.ISI.EDU,VENERA.ISI.EDU,"
+"DEC-2060"
+"version"
+"[RFC-1031]."
+"TTL"
+"[RFC-742]"
+"QTYPE=NS"
+"FTP"
+"hash"
+"QTYPE=CNAME,"
+"RFC-793,"
+"address"
+"SNAME,"
+"["
+"\"NAME/FINGER\","
+"SRI-NIC.ARPA."
+"SRI-NIC.ARPA,"
+"MB"
+"SRI-NIC.ARPA:"
+"QTYPE=CNAME"
+"NOT"
+"MX"
+"[RFC-821]"
+"useful"
+"select"
+"SRI-NIC.ARPA"
+"use"
+"SNAME"
+"from"
+"to"
+"positive"
+"(QCLASS)"
+"[RFC-1032]."
+"(DNS),"
+"TELNET,"
+"call"
+"B.X,"
+"memory"
+"type"
+"[RFC-973]"
+"RFC-822."
+"QNAME=SIR-NIC.ARPA,"
+"MILNET"
+"TOPS20"
+"[IEN-116,"
+"PTR)."
+"HOSTS.TXT,"
+"COMSAT,"
+"EXPIRE."
+"must"
+"EVEN"
+"|(C.ISI.EDU,SRI-NIC.ARPA"
+"QNAME=USC-ISIC.ARPA.,"
+"this"
+"CNAME."
+"work"
+"EDU,"
+"EDU."
+"EDU"
+"following"
+"root"
+"[RFC-1010]"
+"F."
+"J.,"
+"type."
+"high"
+"[RFC-953]"
+"US"
+"allowed"
+"serial"
+"IEN-116,"
+"[RFC-1032]"
+"[RFC-1033]."
+"write"
+"NOSC"
+"VENERA.ISI.EDU.|"
+"Z.X"
+"A"
+"QTYPE,"
+"[RFC-810]"
+"QTYPE."
+"may"
+"after"
+"RFC-1032,"
+"such"
+"data"
+"\"A"
+"a"
+"UDP"
+"short"
+"(CNAME)"
+"[RFC-1002]"
+"UDEL.EDU."
+"SRI,"
+"RFC-953."
+"RFC-953,"
+"TELNET)."
+"(HOSTS.TXT)"
+"ISI.EDU"
+"MIL"
+"[RFC-952]"
+"RFC-830,"
+"pointer"
+"its"
+"STYPE"
+"before"
+"HAS"
+"RR"
+"HOSTMASTER.SRI-NIC.ARPA."
+"65.0.6.26.IN-ADDR.ARPA,"
+"65.0.6.26.IN-ADDR.ARPA."
+"RD"
+"NAMES"
+"YALE"
+"QNAME=BRL.MIL,"
+"RA,"
+"ACM,"
+"QCLASS"
+"ARPA."
+"not"
+"(QTYPE),"
+"OPCODE=SQUERY,RESPONSE"
+"name"
+"RFC,"
+"mode"
+"RFC-799,"
+"ICS.UCI"
+"RESOLVERS"
+"A.X.COM"
+"SOME"
+"CNAME"
+"UDEL"
+"(QNAME),"
+"E."
+"space"
+"L."
+"MINIMUM"
+"RDATA"
+"supports"
+"REFRESH,"
+"HOSTMASTER@SRI-NIC.ARPA."
+"This"
+"SLIST:"
+"free"
+"RFC"
+"base"
+"RFC-952"
+"received."
+"SLIST."
+"SLIST,"
+"DATA."
+"thread"
+"YALE-BULLDOG.ARPA."
+"could"
+"QCLASS,"
+"times"
+"length"
+"HOSTMASTER@SRI-NIC.ARPA"
+"MIT.EDU"
+"already"
+"CONFIGURED"
+"number"
+"one"
+"RFC-"
+"Start"
+"ISI"
+"RFC."
+"RFC-1001,"
+"open"
+"CSNET"
+"size"
+"\""
+"X."
+"A.ISI.EDU"
+"TTL)"
+"\"HOSTNAME"
+"unknown"
+"top"
+"SERVERS"
+"too"
+"RFC-953]."
+"QTYPE"
+"BBN"
+"that"
+"completed"
+"XX"
+"*.A.X.COM"
+"QTYPE=MX,"
+"MX."
+"RD."
+"K."
+"target"
+"16"
+"Z.X),"
+"LCS.MIT.EDU"
+"[RFC-1031]"
+"and"
+"[RFC-805]"
+"[RFC-811]"
+"(RCODE)"
+"have"
+"need"
+"RESPONSE,"
+"null"
+"any"
+"contents"
+"|(SRI-NIC.ARPA,"
+"SOMEONE"
+"RESOURCE"
+"73.0.0.26.IN-ADDR.ARPA."
+"DARPA"
+"ACC.ARPA."
+"RFC-812,"
+"-"
+"mechanism"
+"internal"
+"take"
+"which"
+"MIL."
+"MIL,"
+"="
+"UCI"
+"RFC-742,"
+"multiple"
+"TCP/IP"
+"USC-ISIC.ARPA."
+"QNAME=USC-ISIC.ARPA,"
+"The"
+"]"
+"class"
+"D."
+"RFC-1010,"
+"D,"
+"RFC-805,"
+"AA,"
+"VAXA.ISI.EDU."
+"QNAME=ISI.EDU,"
+"MG)."
+"\"DOD"
+"QNAME=SRI-NIC.ARPA,"
+"text"
+"labels"
+"VENERA"
+"RFC-1033,"
+"INCORRECTLY"
+"[RFC-"
+"Z"
+"[RFC-952,"
+"RECORDS"
+"implementation"
+"true"
+"cache"
+"[RFC-768]"
+"XX.LCS.MIT.EDU"
+"only"
+"PVM@ISI.EDU."
+"RETRY,"
+"get"
+"PVM@ISI.EDU"
+"ACHILLES"
+"LOUIE.UDEL.EDU."
+"IN-ADDR"
+"resource"
+"A.ISI"
+"THIS"
+"NIC"
+"(via"
+"Zones"
+"RFC-920,"
+"J."
+"RFC-920."
+"common"
+"set"
+"configured"
+"QNAME=SRI-NIC.ARPA.,"
+"this,"
+"are"
+"RFC-883]."
+"A.ISI.EDU."
+"A.ISI.EDU)"
+"INTRODUCTION"
+"TCP"
+"MIT"
+"PC"
+"unable"
+"probably"
+"C.D,"
+"103.0.3.26.IN-ADDR.ARPA."
+"available"
+"C"
+"parent"
+"RFC-830]."
+"REFRESH"
+"UNIX"
+"CH)."
+"key"
+"52.0.0.10.IN-ADDR.ARPA"
+"P."
+"AND"
+"RFC-1002,"
+"OPCODE=SQUERY"
+"ROME.UCI"
+"LCS"
+"PDP-11/70"
+"ISI.EDU,"
+"ISI.EDU."
+"MAILB"
+"[RFC-974]"
+"CONCEPTS"
+"[RFC-920]"
+"SOA,"
+"RCODE=NE"
+"DNS."
+"DNS,"
+"poll"
+"UMN-REI-UC.ARPA."
+"SNAME."
+"[RFC-883]"
+"RFC-974,"
+"RFC-1002"
+"create"
+"S.,"
+"."
+"[RFC-830]"
+"expected"
+"empty"
+"RA"
+"CH"
+"(RD)"
+"VENERA.ISI.EDU."
+"SRI"
+"A.B.X,"
+"NAME"
+"value"
+"while"
+"error"
+"loop"
+"\"NICNAME/WHOIS\","
+"is"
+"CACHE"
+"FACILITIES"
+"in"
+"|(XX.LCS.MIT.EDU,"
+"SOA"
+"binary"
+"[RFC-819]"
+")"
+"SRI-NIC"
+"V."
+"\"A\"."
+"QNAME."
+"QNAME,"
+"units"
+"(NE)."
+"used"
+"IP"
+"\"."
+"IN"
+"ID"
+"IF"
+"task"
+"SCENARIO"
+"RFC-883,"
+"HOSTS.TXT"
+"Names"
+"RFC-811,"
+"the"
+"If"
+"being"
+"EXPIRE"
+"RFC-882,"
+"|ACHILLES.MIT.EDU)"
+"XX.COM."
+"(RDATA)"
+"source"
+"CSNET."
+"build"
+"ACHILLES.MIT.EDU."
+"format"
+"read"
+"(AA)"
+"ISIC.ARPA,"
+"SERIAL"
+"VAXA.ISI"
+"found,"
+"SLIST"
+"sorting"
+"OPCODE=SQUERY,"
+"OF"
+"AUTHORITY"
+"OS"
+"AA"
+"DOMAIN"
+"because"
+"SRI-NIC.ARPA.|"
+"some"
+"back"
+"growth"
+"USC-ISIC.ARPA,"
+"RFC-821,"
+"happens"
+"for"
+"W."
+"RFC-883"
+"X.COM"
+"avoid"
+"does"
+"allocate"
+"COM"
+"assuming"
+"BRL"
+"PTR"
+"[RFC-793]"
+"be"
+"QCLASS=*"
+"MIT.EDU."
+"by"
+"C."
+"on"
+"SCLASS"
+"of"
+"FTP)"
+"FTP,"
+"UK"
+"or"
+"ACC"
+"SBELT."
+"SBELT,"
+"No"
+"(SBELT)"
+"A.X.COM."
+"A.X.COM,"
+"REFERENCES"
+"USC-ISIC.ARPA"
+"[RFC-1001]"
+"RESPONSE"
+"transfer"
+"support"
+"*"
+"NE"
+"long"
+"QTYPE=*"
+"start"
+"C.ISI.EDU"
+"TTL,"
+"RD,"
+"\"4.3.2.1.IN-ADDR.ARPA\"."
+"NS"
+"was"
+"RR."
+"RR,"
+"QTYPE=A"
+"MEMO"
+"but"
+"QNAME"
+"[RFC-1001,"
+"DNS"
+"line"
+"trying"
+"with"
+"TCP/UDP"
+"count"
+"SBELT"
+"(NIC)"
+"up"
+"classes:"
+"RFC-768,"
+"[IEN-116]"
+"VAXA"
+"NETBIOS"
+"called"
+"delete"
+"CIC"
+"USC-"
+"RETRY"
+"RFC-810,"
+"RECORDS,"
+"an"
+"To"
+"as"
+"at"
+"file"
+"[RFC-812]"
+"physical"
+"X.COM,"
+"no"
+"[RFC-882,"
+"when"
+"A,"
+"virtual"
+"RFC-952,"
+"RFC-952."
+"valid"
+"test"
+"you"
+"IP/TCP"
+"STATUS"
+"requested"
+"[RFC-974"
+"SPACE"
+"QNAME=SIR-NIC.ARPA.,"
+"RFC-819,"
+"variable"
+"[RFC-882]"
+"BIBLIOGRAPHY"
+"[RFC-1033]"
+"US."
+"\"MILNET"
+"As"
+"RFC-973,"
+"RFC-882"
+"QTYPE=MX"
+"4.0.10.18.IN-ADDR.ARPA."
+"FOO.F.ISI.ARPA,"
+"Assuming"
+"[RFC-1034],"
+"[RFC-1034]."
+"UNIX\""
+"IMPLEMENTATION"
+"EGP."
+"ANCOUNT"
+"@"
+"P"
+"TXT-DATA"
+"RMAILBX"
+"|QTYPE=A,"
+"QDCOUNT"
+"[RFC-1010]."
+"EMAILBX"
+"IN-"
+"OPCODE=IQUERY,"
+"MX)"
+"ID=997"
+"\"VENERA.ISI.EDU\";"
+"OPCODE"
+"MILNET-GW.ISI.EDU."
+"52.0.2.10.IN-ADDR.ARPA."
+"objects"
+"MD"
+"MG"
+"MF"
+"MR"
+"QNAME=10.IN-ADDR.ARPA."
+"S."
+"GGP"
+"few"
+"QTYPE=PTR,"
+"MD,"
+"F"
+"[RFC-974]."
+"MGMNAME"
+"GW.LCS.MIT.EDU."
+"GW.LCS.MIT.EDU,"
+"V"
+"\\DDD"
+"ALL"
+"10.IN-ADDR.ARPA."
+"closing"
+"EXCHANGE."
+"MADNAME."
+"$ORIGIN"
+"HIS"
+"26.IN-ADDR.ARPA."
+"(MD)"
+"QTYPES"
+"PROTOCOL"
+"26.IN-ADDR.ARPA"
+"NSCOUNT"
+"(MR)"
+"PREFERENCE"
+"<BIT"
+"$INCLUDE."
+"MR)"
+"VAXA.ISI.EDU"
+"77.0.0.10.IN-ADDR.ARPA."
+"\"IBM-PC"
+"$INCLUDE"
+"SERVER"
+"18.IN-ADDR.ARPA."
+"ADDRESS"
+"Check"
+"static"
+"GW.ISI.EDU."
+"(QNAME)."
+"GW.ISI.EDU,"
+"F.ISI.ARPA,"
+"F.ISI.ARPA."
+"time."
+"PTRDNAME"
+"HOSTMASTER@SRI-"
+"(STATUS)"
+"(MINFO)"
+"(MG)"
+"QCLASS."
+"(HS)"
+"X,"
+"MNAME"
+"QNAME=VENERA.ISI.EDU"
+"MASTER"
+"(IN)"
+"KNOWS."
+"RNAME"
+"|QR|"
+"VAXA.ISI.EDU,"
+"R"
+"1)"
+"ARCOUNT"
+"RCODE"
+"NEWNAME"
+"CLASS"
+"begin"
+"(MF)."
+"Common"
+"<RDATA>"
+"QR"
+"average"
+"QNAME=6.0.0.10.IN-ADDR.ARPA,"
+"WKS"
+"SYSTEM,"
+"MADNAME"
+"ARPANET,"
+"MINFO"
+"DEFINITIONS"
+"failed"
+"[RFC-1034]"
+"(QCLASS),"
+"SPECIFICATION"
+"X"
+"THE"
+"MILNET."
+"MILNET-"
+"bytes"
+"(MX)"
+"NSDNAME"
+"10.IN-ADDR.ARPA"
+"|AA|TC|RD|RA|"
+"QTYPE=A,"
+"corruption"
+"FOO.F.ISI.ARPA"
+"(QUERY)"
+"MF,"
+"FOO"
+"CURLEY"
+"X.Y,"
+"AXFR,"
+"S"
+"MAILA"
+"exceeds"
+"ISI.EDU:"
+"103.0.0.26.IN-ADDR.ARPA."
+"MOE"
+"[RFC-822]."
+"CHAOS"
+"NAMEDROPPERS@SRI-NIC.ARPA"
+"SOA."
+"RESOLVER"
+"A.X,"
+"EXCHANGE"
+"SMTP"
+"QCLASS=*,"
+"CS"
+"$ORIGIN,"
+"B.X"
+"(MB,"
+"TYPE"
+"Size"
+"parse"
+"ADDR.ARPA"
+"(SMTP)."
+"key."
+"MAP>"
+"OWN"
+"VENERA.ISI.EDU"
+"DDD."
+"MB."
+"NS,"
+"I"
+"OPCODE=RESPONSE,"
+"ARPA,"
+"WITHIN"
+"tables"
+"unsigned"
+"LARRY"
+"D"
+"\\X"
+"WHICH"
+"(IQUERY)"
+"QCLASS=IN"
+"discarded"
+"6.0.0.10.IN-ADDR.ARPA."
+"MAIL"
+"QTYPE=MAILB"
+"HS"
+"SUPPORT"
+"STOOGES"
+"X.Y"
+"/"
+"(SLIST)."
+"O"
+"OS,"
+"OFFSET"
+"FILES"
+"RR),"
+"$INCLUDE,"
+"guard"
+"[<TTL>]"
+"CRLF"
+"Error"
+"ERRORS-TO:"
+"22.0.2.10.IN-ADDR.ARPA."
+"default"
+"MESSAGES"
+"signed"
+"<SUBSYS>ISI-MAILBOXES.TXT"
+"MULTICS.MIT.EDU."
+"NULL"
+"application"
+"TXT"
+"TC"
+"PROTOCOL=TCP"
+"UDP."
+"UDP,"
+"F.ISI.ARPA"
+"(EXPERIMENTAL)"
+"RDLENGTH"
+"NIC.ARPA"
+
diff --git a/chromium/net/data/fuzzer_dictionaries/net_get_domain_and_registry_fuzzer.dict b/chromium/net/data/fuzzer_dictionaries/net_get_domain_and_registry_fuzzer.dict
new file mode 100644
index 00000000000..b5c58a5d953
--- /dev/null
+++ b/chromium/net/data/fuzzer_dictionaries/net_get_domain_and_registry_fuzzer.dict
@@ -0,0 +1,848 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Fuzzer dictionary targetting DNS responses.
+
+# Some 16-bit big-endian values. Useful in a number of fields. Includes
+# A, AAAA, and CNAME IDs, low values for record counts, and multiples of
+# lengths of A and AAAA data fields.
+"\x00\x00"
+"\x00\x01"
+"\x00\x02"
+"\x00\x03"
+"\x00\x04"
+"\x00\x05"
+"\x00\x08"
+"\x00\x0C"
+"\x00\x10"
+"\x00\x1C"
+"\x00\x20"
+"\x00\x30"
+
+# Some encoded domain names.
+"\x03foo\x00"
+"\x03foo\x03com\x00"
+"\x01a\x03foo\x03com\x00"
+"\x03bar\x00"
+
+# Message headers (Without message ID field).
+"\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Truncated message, requiring TCP fallback.
+"\x83\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Varying number of answers
+"\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x02\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x10\x00\x00\x00\x00"
+
+# A, AAAA, and CNAME request suffixes - appear after domain name.
+"\x00\x01\x00\x01"
+"\x00\x1c\x00\x01"
+"\x00\x05\x00\x01"
+
+# A, AAAA, and CNAME requests for foo and foo.com.
+"\x03foo\x00\x00\x01\x00\x01"
+"\x03foo\x00\x00\x1c\x00\x01"
+"\x03foo\x00\x00\x05\x00\x01"
+"\x03foo\x03com\x00\x00\x01\x00\x01"
+"\x03foo\x03com\x00\x00\x1c\x00\x01"
+"\x03foo\x03com\x00\x00\x05\x00\x01"
+
+# All of the answers below are missing the name field, which should appear
+# first.
+
+# A answer suffixes, two different IP and TTLs.
+"\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x01\x02\x03\x04"
+"\x00\x01\x00\x01\x00\x00\x00\xFF\x00\x04\x02\x03\x04\x05"
+
+# AAAA answer suffixes, two different IPs and TTLs.
+"\x00\x1C\x00\x01\x00\x00\x00\x00\x00\x08\x01\x02\x03\x04\x05\x06\x07\x08"
+"\x00\x1C\x00\x01\x00\x00\x00\xFF\x00\x08\x02\x03\x04\x05\x06\x07\x08\x09"
+
+# CDATA answer suffixes, first two truncated as well.
+"\x00\x05\x00\x01\x00\x00\x00\xFF"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03foo\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03bar\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x09\x03foo\x03com\x00"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_get_domain_and_registry_fuzzer binary, RFC 1034 and RFC 1035.
+"all"
+"QNAME=ISI.EDU.,"
+"pointing"
+"C.ISI.EDU,"
+"C.ISI.EDU."
+"C.ISI.EDU)"
+"52.0.0.10.IN-ADDR.ARPA."
+"[RFC-799]"
+"XX.LCS.MIT.EDU,"
+"XX.LCS.MIT.EDU."
+"CPU"
+"C.ISI.EDU:"
+"A.B.C.D"
+"ARPA"
+"*.X.COM"
+"IN-ADDR.ARPA"
+"to"
+"\"*.X\","
+"resources"
+"supported"
+"string"
+"returning"
+"AXFR"
+"YALE.ARPA."
+"B.C.D,"
+"list"
+"large"
+"CNAME,"
+"ASCII"
+"M."
+"YALE.EDU."
+"direct"
+"IN,"
+"[RFC-1035]."
+"\"A\""
+"\"IN-ADDR.ARPA\"."
+"HINFO"
+"RFC-1031,"
+"QCLASS=IN,"
+"Z."
+"QCLASS=IN."
+"ARPANET"
+"QNAME=65.0.6.26.IN-ADDR.ARPA.,QCLASS=IN,QTYPE=PTR"
+"section"
+"51.0.0.10.IN-ADDR.ARPA."
+"|(VAXA.ISI.EDU,VENERA.ISI.EDU,"
+"DEC-2060"
+"version"
+"[RFC-1031]."
+"TTL"
+"[RFC-742]"
+"QTYPE=NS"
+"FTP"
+"hash"
+"QTYPE=CNAME,"
+"RFC-793,"
+"address"
+"SNAME,"
+"["
+"\"NAME/FINGER\","
+"SRI-NIC.ARPA."
+"SRI-NIC.ARPA,"
+"MB"
+"SRI-NIC.ARPA:"
+"QTYPE=CNAME"
+"NOT"
+"MX"
+"[RFC-821]"
+"useful"
+"select"
+"SRI-NIC.ARPA"
+"use"
+"SNAME"
+"from"
+"0"
+"positive"
+"(QCLASS)"
+"[RFC-1032]."
+"(DNS),"
+"TELNET,"
+"call"
+"B.X,"
+"memory"
+"type"
+"[RFC-973]"
+"RFC-822."
+"QNAME=SIR-NIC.ARPA,"
+"MILNET"
+"TOPS20"
+"[IEN-116,"
+"PTR)."
+"HOSTS.TXT,"
+"COMSAT,"
+"EXPIRE."
+"must"
+"EVEN"
+"|(C.ISI.EDU,SRI-NIC.ARPA"
+"QNAME=USC-ISIC.ARPA.,"
+"this"
+"CNAME."
+"work"
+"EDU,"
+"EDU."
+"EDU"
+"following"
+"root"
+"[RFC-1010]"
+"F."
+"J.,"
+"type."
+"high"
+"[RFC-953]"
+"US"
+"allowed"
+"serial"
+"IEN-116,"
+"[RFC-1032]"
+"end"
+"[RFC-1033]."
+"write"
+"NOSC"
+"VENERA.ISI.EDU.|"
+"Z.X"
+"A"
+"QTYPE,"
+"[RFC-810]"
+"QTYPE."
+"may"
+"after"
+"RFC-1032,"
+"such"
+"data"
+"\"A"
+"a"
+"UDP"
+"short"
+"(CNAME)"
+"[RFC-1002]"
+"UDEL.EDU."
+"SRI,"
+"RFC-953."
+"RFC-953,"
+"TELNET)."
+"(HOSTS.TXT)"
+"ISI.EDU"
+"MIL"
+"[RFC-952]"
+"RFC-830,"
+"pointer"
+"its"
+"STYPE"
+"before"
+"HAS"
+"RR"
+"HOSTMASTER.SRI-NIC.ARPA."
+"65.0.6.26.IN-ADDR.ARPA,"
+"65.0.6.26.IN-ADDR.ARPA."
+"RD"
+"NAMES"
+"YALE"
+"QNAME=BRL.MIL,"
+"RA,"
+"ACM,"
+"QCLASS"
+"ARPA."
+"not"
+"(QTYPE),"
+"OPCODE=SQUERY,RESPONSE"
+"name"
+"RFC,"
+"mode"
+"RFC-799,"
+"ICS.UCI"
+"RESOLVERS"
+"A.X.COM"
+"SOME"
+"CNAME"
+"UDEL"
+"(QNAME),"
+"E."
+"space"
+"L."
+"MINIMUM"
+"RDATA"
+"supports"
+"REFRESH,"
+"HOSTMASTER@SRI-NIC.ARPA."
+"This"
+"SLIST:"
+"free"
+"RFC"
+"base"
+"RFC-952"
+"received."
+"SLIST."
+"SLIST,"
+"DATA."
+"thread"
+"YALE-BULLDOG.ARPA."
+"could"
+"QCLASS,"
+"times"
+"length"
+"HOSTMASTER@SRI-NIC.ARPA"
+"MIT.EDU"
+"already"
+"CONFIGURED"
+"number"
+"one"
+"RFC-"
+"Start"
+"ISI"
+"RFC."
+"RFC-1001,"
+"open"
+"CSNET"
+"size"
+"\""
+"X."
+"A.ISI.EDU"
+"TTL)"
+"\"HOSTNAME"
+"unknown"
+"top"
+"SERVERS"
+"2"
+"too"
+"RFC-953]."
+"QTYPE"
+"BBN"
+"that"
+"completed"
+"XX"
+"*.A.X.COM"
+"QTYPE=MX,"
+"MX."
+"RD."
+"K."
+"target"
+"16"
+"Z.X),"
+"LCS.MIT.EDU"
+"[RFC-1031]"
+"and"
+"[RFC-805]"
+"[RFC-811]"
+"(RCODE)"
+"have"
+"need"
+"RESPONSE,"
+"null"
+"any"
+"contents"
+"|(SRI-NIC.ARPA,"
+"SOMEONE"
+"RESOURCE"
+"73.0.0.26.IN-ADDR.ARPA."
+"DARPA"
+"ACC.ARPA."
+"RFC-812,"
+"-"
+"mechanism"
+"internal"
+"take"
+"which"
+"MIL."
+"MIL,"
+"="
+"UCI"
+"RFC-742,"
+"multiple"
+"TCP/IP"
+"USC-ISIC.ARPA."
+"QNAME=USC-ISIC.ARPA,"
+"The"
+"]"
+"class"
+"D."
+"RFC-1010,"
+"D,"
+"RFC-805,"
+"AA,"
+"VAXA.ISI.EDU."
+"QNAME=ISI.EDU,"
+"MG)."
+"\"DOD"
+"QNAME=SRI-NIC.ARPA,"
+"text"
+"labels"
+"VENERA"
+"RFC-1033,"
+"INCORRECTLY"
+"[RFC-"
+"Z"
+"[RFC-952,"
+"RECORDS"
+"implementation"
+"with"
+"cache"
+"[RFC-768]"
+"XX.LCS.MIT.EDU"
+"only"
+"PVM@ISI.EDU."
+"RETRY,"
+"get"
+"PVM@ISI.EDU"
+"ACHILLES"
+"LOUIE.UDEL.EDU."
+"IN-ADDR"
+"resource"
+"A.ISI"
+"THIS"
+"NIC"
+"(via"
+"Zones"
+"RFC-920,"
+"J."
+"RFC-920."
+"common"
+"set"
+"configured"
+"QNAME=SRI-NIC.ARPA.,"
+"this,"
+"are"
+"RFC-883]."
+"A.ISI.EDU."
+"A.ISI.EDU)"
+"INTRODUCTION"
+"TCP"
+"MIT"
+"PC"
+"3"
+"unable"
+"probably"
+"C.D,"
+"103.0.3.26.IN-ADDR.ARPA."
+"available"
+"C"
+"parent"
+"RFC-830]."
+"REFRESH"
+"UNIX"
+"CH)."
+"key"
+"52.0.0.10.IN-ADDR.ARPA"
+"P."
+"AND"
+"RFC-1002,"
+"OPCODE=SQUERY"
+"ROME.UCI"
+"LCS"
+"PDP-11/70"
+"ISI.EDU,"
+"ISI.EDU."
+"MAILB"
+"[RFC-974]"
+"CONCEPTS"
+"[RFC-920]"
+"SOA,"
+"RCODE=NE"
+"DNS."
+"DNS,"
+"poll"
+"UMN-REI-UC.ARPA."
+"SNAME."
+"[RFC-883]"
+"RFC-974,"
+"RFC-1002"
+"create"
+"S.,"
+"."
+"[RFC-830]"
+"expected"
+"empty"
+"RA"
+"CH"
+"(RD)"
+"VENERA.ISI.EDU."
+"SRI"
+"A.B.X,"
+"NAME"
+"value"
+"while"
+"error"
+"loop"
+"\"NICNAME/WHOIS\","
+"is"
+"CACHE"
+"FACILITIES"
+"in"
+"|(XX.LCS.MIT.EDU,"
+"SOA"
+"binary"
+"[RFC-819]"
+")"
+"SRI-NIC"
+"V."
+"\"A\"."
+"QNAME."
+"QNAME,"
+"units"
+"(NE)."
+"used"
+"IP"
+"\"."
+"IN"
+"ID"
+"IF"
+"task"
+"SCENARIO"
+"RFC-883,"
+"HOSTS.TXT"
+"Names"
+"RFC-811,"
+"the"
+"If"
+"being"
+"EXPIRE"
+"RFC-882,"
+"|ACHILLES.MIT.EDU)"
+"XX.COM."
+"(RDATA)"
+"source"
+"CSNET."
+"build"
+"ACHILLES.MIT.EDU."
+"format"
+"read"
+"(AA)"
+"ISIC.ARPA,"
+"SERIAL"
+"VAXA.ISI"
+"found,"
+"SLIST"
+"sorting"
+"OPCODE=SQUERY,"
+"OF"
+"AUTHORITY"
+"OS"
+"AA"
+"DOMAIN"
+"because"
+"SRI-NIC.ARPA.|"
+"some"
+"back"
+"growth"
+"USC-ISIC.ARPA,"
+"RFC-821,"
+"happens"
+"for"
+"W."
+"RFC-883"
+"X.COM"
+"avoid"
+"does"
+"allocate"
+"COM"
+"assuming"
+"BRL"
+"PTR"
+"[RFC-793]"
+"be"
+"QCLASS=*"
+"MIT.EDU."
+"by"
+"C."
+"on"
+"SCLASS"
+"of"
+"FTP)"
+"FTP,"
+"UK"
+"or"
+"ACC"
+"SBELT."
+"SBELT,"
+"No"
+"(SBELT)"
+"A.X.COM."
+"A.X.COM,"
+"REFERENCES"
+"USC-ISIC.ARPA"
+"[RFC-1001]"
+"RESPONSE"
+"transfer"
+"support"
+"*"
+"NE"
+"long"
+"QTYPE=*"
+"start"
+"C.ISI.EDU"
+"TTL,"
+"RD,"
+"\"4.3.2.1.IN-ADDR.ARPA\"."
+"NS"
+"was"
+"RR."
+"RR,"
+"QTYPE=A"
+"MEMO"
+"but"
+"QNAME"
+"[RFC-1001,"
+"DNS"
+"line"
+"trying"
+"true"
+"TCP/UDP"
+"count"
+"SBELT"
+"(NIC)"
+"up"
+"classes:"
+"RFC-768,"
+"[IEN-116]"
+"VAXA"
+"NETBIOS"
+"called"
+"delete"
+"CIC"
+"USC-"
+"RETRY"
+"RFC-810,"
+"RECORDS,"
+"an"
+"To"
+"as"
+"at"
+"file"
+"[RFC-812]"
+"physical"
+"X.COM,"
+"no"
+"[RFC-882,"
+"when"
+"A,"
+"virtual"
+"RFC-952,"
+"RFC-952."
+"valid"
+"5"
+"test"
+"you"
+"IP/TCP"
+"STATUS"
+"requested"
+"[RFC-974"
+"SPACE"
+"QNAME=SIR-NIC.ARPA.,"
+"RFC-819,"
+"variable"
+"[RFC-882]"
+"BIBLIOGRAPHY"
+"[RFC-1033]"
+"US."
+"\"MILNET"
+"As"
+"RFC-973,"
+"RFC-882"
+"QTYPE=MX"
+"4.0.10.18.IN-ADDR.ARPA."
+"FOO.F.ISI.ARPA,"
+"Assuming"
+"[RFC-1034],"
+"[RFC-1034]."
+"UNIX\""
+"IMPLEMENTATION"
+"EGP."
+"ANCOUNT"
+"@"
+"P"
+"TXT-DATA"
+"RMAILBX"
+"|QTYPE=A,"
+"QDCOUNT"
+"[RFC-1010]."
+"EMAILBX"
+"IN-"
+"OPCODE=IQUERY,"
+"MX)"
+"ID=997"
+"\"VENERA.ISI.EDU\";"
+"OPCODE"
+"MILNET-GW.ISI.EDU."
+"52.0.2.10.IN-ADDR.ARPA."
+"objects"
+"MD"
+"MG"
+"MF"
+"MR"
+"QNAME=10.IN-ADDR.ARPA."
+"OFFSET"
+"S."
+"GGP"
+"few"
+"QTYPE=PTR,"
+"MD,"
+"F"
+"[RFC-974]."
+"MGMNAME"
+"GW.LCS.MIT.EDU."
+"GW.LCS.MIT.EDU,"
+"V"
+"\\DDD"
+"ALL"
+"10.IN-ADDR.ARPA."
+"closing"
+"EXCHANGE."
+"MADNAME."
+"$ORIGIN"
+"HIS"
+"26.IN-ADDR.ARPA."
+"(MD)"
+"QTYPES"
+"PROTOCOL"
+"26.IN-ADDR.ARPA"
+"NSCOUNT"
+"(MR)"
+"PREFERENCE"
+"<BIT"
+"$INCLUDE."
+"MR)"
+"VAXA.ISI.EDU"
+"77.0.0.10.IN-ADDR.ARPA."
+"\"IBM-PC"
+"$INCLUDE"
+"SERVER"
+"18.IN-ADDR.ARPA."
+"ADDRESS"
+"Check"
+"static"
+"GW.ISI.EDU."
+"(QNAME)."
+"GW.ISI.EDU,"
+"F.ISI.ARPA,"
+"F.ISI.ARPA."
+"time."
+"PTRDNAME"
+"HOSTMASTER@SRI-"
+"(STATUS)"
+"(MINFO)"
+"(MG)"
+"QCLASS."
+"(HS)"
+"X,"
+"MNAME"
+"QNAME=VENERA.ISI.EDU"
+"MASTER"
+"(IN)"
+"KNOWS."
+"RNAME"
+"|QR|"
+"VAXA.ISI.EDU,"
+"R"
+"1)"
+"ARCOUNT"
+"RCODE"
+"NEWNAME"
+"CLASS"
+"begin"
+"(MF)."
+"Common"
+"<RDATA>"
+"QR"
+"average"
+"QNAME=6.0.0.10.IN-ADDR.ARPA,"
+"WKS"
+"SYSTEM,"
+"MADNAME"
+"ARPANET,"
+"MINFO"
+"DEFINITIONS"
+"failed"
+"[RFC-1034]"
+"(QCLASS),"
+"SPECIFICATION"
+"X"
+"THE"
+"MILNET."
+"MILNET-"
+"bytes"
+"(MX)"
+"NSDNAME"
+"10.IN-ADDR.ARPA"
+"|AA|TC|RD|RA|"
+"QTYPE=A,"
+"corruption"
+"FOO.F.ISI.ARPA"
+"(QUERY)"
+"MF,"
+"FOO"
+"CURLEY"
+"X.Y,"
+"AXFR,"
+"S"
+"MAILA"
+"exceeds"
+"ISI.EDU:"
+"103.0.0.26.IN-ADDR.ARPA."
+"MOE"
+"[RFC-822]."
+"CHAOS"
+"NAMEDROPPERS@SRI-NIC.ARPA"
+"SOA."
+"RESOLVER"
+"A.X,"
+"EXCHANGE"
+"SMTP"
+"QCLASS=*,"
+"CS"
+"$ORIGIN,"
+"B.X"
+"(MB,"
+"TYPE"
+"Size"
+"parse"
+"ADDR.ARPA"
+"(SMTP)."
+"key."
+"MAP>"
+"OWN"
+"VENERA.ISI.EDU"
+"DDD."
+"MB."
+"NS,"
+"I"
+"OPCODE=RESPONSE,"
+"ARPA,"
+"WITHIN"
+"tables"
+"unsigned"
+"LARRY"
+"D"
+"\\X"
+"WHICH"
+"(IQUERY)"
+"QCLASS=IN"
+"discarded"
+"6.0.0.10.IN-ADDR.ARPA."
+"MAIL"
+"QTYPE=MAILB"
+"HS"
+"SUPPORT"
+"STOOGES"
+"X.Y"
+"/"
+"(SLIST)."
+"O"
+"OS,"
+"offset"
+"FILES"
+"RR),"
+"$INCLUDE,"
+"guard"
+"[<TTL>]"
+"CRLF"
+"Error"
+"ERRORS-TO:"
+"22.0.2.10.IN-ADDR.ARPA."
+"default"
+"MESSAGES"
+"signed"
+"<SUBSYS>ISI-MAILBOXES.TXT"
+"MULTICS.MIT.EDU."
+"NULL"
+"application"
+"TXT"
+"TC"
+"PROTOCOL=TCP"
+"UDP."
+"UDP,"
+"F.ISI.ARPA"
+"(EXPERIMENTAL)"
+"RDLENGTH"
+"NIC.ARPA"
+
diff --git a/chromium/net/data/fuzzer_dictionaries/net_host_resolver_impl_fuzzer.dict b/chromium/net/data/fuzzer_dictionaries/net_host_resolver_impl_fuzzer.dict
new file mode 100644
index 00000000000..3e7f1d89b48
--- /dev/null
+++ b/chromium/net/data/fuzzer_dictionaries/net_host_resolver_impl_fuzzer.dict
@@ -0,0 +1,1397 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Fuzzer dictionary targetting DNS responses.
+
+# Some 16-bit big-endian values. Useful in a number of fields. Includes
+# A, AAAA, and CNAME IDs, low values for record counts, and multiples of
+# lengths of A and AAAA data fields.
+"\x00\x00"
+"\x00\x01"
+"\x00\x02"
+"\x00\x03"
+"\x00\x04"
+"\x00\x05"
+"\x00\x08"
+"\x00\x0C"
+"\x00\x10"
+"\x00\x1C"
+"\x00\x20"
+"\x00\x30"
+
+# Some encoded domain names.
+"\x03foo\x00"
+"\x03foo\x03com\x00"
+"\x01a\x03foo\x03com\x00"
+"\x03bar\x00"
+
+# Message headers (Without message ID field).
+"\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Truncated message, requiring TCP fallback.
+"\x83\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Varying number of answers
+"\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x02\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x10\x00\x00\x00\x00"
+
+# A, AAAA, and CNAME request suffixes - appear after domain name.
+"\x00\x01\x00\x01"
+"\x00\x1c\x00\x01"
+"\x00\x05\x00\x01"
+
+# A, AAAA, and CNAME requests for foo and foo.com.
+"\x03foo\x00\x00\x01\x00\x01"
+"\x03foo\x00\x00\x1c\x00\x01"
+"\x03foo\x00\x00\x05\x00\x01"
+"\x03foo\x03com\x00\x00\x01\x00\x01"
+"\x03foo\x03com\x00\x00\x1c\x00\x01"
+"\x03foo\x03com\x00\x00\x05\x00\x01"
+
+# All of the answers below are missing the name field, which should appear
+# first.
+
+# A answer suffixes, two different IP and TTLs.
+"\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x01\x02\x03\x04"
+"\x00\x01\x00\x01\x00\x00\x00\xFF\x00\x04\x02\x03\x04\x05"
+
+# AAAA answer suffixes, two different IPs and TTLs.
+"\x00\x1C\x00\x01\x00\x00\x00\x00\x00\x08\x01\x02\x03\x04\x05\x06\x07\x08"
+"\x00\x1C\x00\x01\x00\x00\x00\xFF\x00\x08\x02\x03\x04\x05\x06\x07\x08\x09"
+
+# CDATA answer suffixes, first two truncated as well.
+"\x00\x05\x00\x01\x00\x00\x00\xFF"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03foo\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03bar\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x09\x03foo\x03com\x00"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_host_resolver_impl_fuzzer binary, RFC 1034 and RFC 1035.
+"EXPIRE"
+"all"
+"code"
+"QNAME=ISI.EDU.,"
+"chain"
+"C.ISI.EDU,"
+"C.ISI.EDU."
+"results"
+"existing"
+"INTRODUCTION"
+"52.0.0.10.IN-ADDR.ARPA."
+"QCLASS"
+"[RFC-799]"
+"follow"
+"XX.LCS.MIT.EDU."
+"(which"
+"C.ISI.EDU:"
+"content"
+"A.B.X,"
+"pointing"
+"zone"
+"A.B.C.D"
+"CPU"
+"(RCODE)"
+"send"
+"IN-ADDR.ARPA"
+"0"
+"Host"
+"program"
+"under"
+"\"*.X\","
+"exit."
+"resources"
+"TOPS20"
+"labels"
+"string"
+"advantage"
+"returning"
+"very"
+"none"
+"C.ISI.EDU)"
+"AXFR"
+"YALE.ARPA."
+"difference"
+"Experimental"
+"entire"
+"did"
+"supports"
+"list"
+"large"
+"CNAME,"
+"-1"
+"delegate"
+"small"
+"ASCII"
+"C."
+"M."
+"YALE.EDU."
+"direct"
+"past"
+"likely"
+"\"A\""
+"\"IN-ADDR.ARPA\"."
+"XX.LCS.MIT.EDU,"
+"HINFO"
+"RFC-1031,"
+"IN,"
+"particular,"
+"Z."
+"errors"
+"appear"
+"ARPANET"
+"QNAME=65.0.6.26.IN-ADDR.ARPA.,QCLASS=IN,QTYPE=PTR"
+"QCLASS=*"
+"section"
+"51.0.0.10.IN-ADDR.ARPA."
+"children"
+"current"
+"DEC-2060"
+"waiting"
+"version"
+"above"
+"TTL"
+"[RFC-742]"
+"shared"
+"method"
+"QTYPE=NS"
+"FTP"
+"*.A.X.COM"
+"hash"
+"EDU."
+"exchange"
+"QTYPE=CNAME,"
+"never"
+"[RFC-"
+"here"
+"\"HOSTNAME"
+"RFC-793,"
+"address"
+"SNAME,"
+"path"
+"Distribution"
+"\"NAME/FINGER\","
+"change"
+"search"
+"SRI-NIC.ARPA."
+"[RFC-952,"
+"SRI-NIC.ARPA,"
+"MB"
+"receive"
+"changed"
+"SRI-NIC.ARPA:"
+"prior"
+"amount"
+"QTYPE=CNAME"
+"RFC-822."
+"here."
+"published"
+"NOT"
+"Serial"
+"J.,"
+"error,"
+"MX"
+"error."
+"composed"
+"named"
+"via"
+"useful"
+"addresses"
+"case."
+"ARPA"
+"When"
+"private"
+"*.X.COM"
+"total"
+"gateway"
+"select"
+"Status"
+"SRI-NIC.ARPA"
+"use"
+"SNAME"
+"from"
+"would"
+"to"
+"positive"
+"contains"
+"(QCLASS)"
+"two"
+"[RFC-1032]."
+"(DNS),"
+"TELNET,"
+"call"
+"B.X,"
+"memory"
+"type"
+"until"
+"used."
+"more"
+"sort"
+"QNAME=SIR-NIC.ARPA,"
+"MILNET"
+"name."
+"Domain"
+"[IEN-116,"
+"PTR)."
+"HOSTS.TXT,"
+"COMSAT,"
+"EXPIRE."
+"known"
+"cases"
+"must"
+"EVEN"
+"account"
+"include"
+"QCLASS=IN."
+"QNAME=USC-ISIC.ARPA.,"
+"this"
+"CNAME."
+"work"
+"EDU,"
+"can"
+"evolved"
+"EDU"
+"following"
+"original"
+"root"
+"example"
+"F."
+"history"
+"type."
+"stream"
+"Organizations"
+"process"
+"pieces"
+"high"
+"minimum"
+"[RFC-953]"
+"numbers"
+"want"
+"allowed"
+"serial"
+"keep"
+"IEN-116,"
+"returned"
+"class."
+"information"
+"class,"
+"end"
+"goal"
+"[RFC-1033]."
+"divided"
+"holds"
+"write"
+"located"
+"NOSC"
+"VENERA.ISI.EDU.|"
+"plus"
+"Z.X"
+"A"
+"map"
+"[RFC-810]"
+"QTYPE."
+"may"
+"after"
+"Request"
+"containing"
+"RFC-1032,"
+"date"
+"such"
+"[RFC-1035]."
+"data"
+"response"
+"types"
+"\"A"
+"a"
+"FTP,"
+"All"
+"short"
+"attempt"
+"IF"
+"After"
+"UDEL.EDU."
+"SRI,"
+")"
+"RFC-953,"
+"so"
+"TELNET)."
+"MIT.EDU"
+"order"
+"(HOSTS.TXT)"
+"ACHILLES"
+"ISI.EDU"
+"MIL"
+"over"
+"move"
+"vary"
+"Z.X),"
+"RFC-830,"
+"through"
+"V."
+"during"
+"still"
+"pointer"
+"its"
+"STYPE"
+"before"
+"25"
+"style"
+"HAS"
+"group"
+"RR"
+"HOSTMASTER.SRI-NIC.ARPA."
+"65.0.6.26.IN-ADDR.ARPA,"
+"fix"
+"65.0.6.26.IN-ADDR.ARPA."
+"28"
+"actually"
+"RD"
+"NAMES"
+"YALE"
+"policy"
+"mail"
+"QNAME=BRL.MIL,"
+"it."
+"them"
+"good"
+"return"
+"greater"
+"combination"
+"B.C.D,"
+"matches"
+"RA,"
+"ACM,"
+"9"
+"ARPA."
+"they"
+"half"
+"not"
+"However,"
+"parsing"
+"[RFC-973]"
+"instructions"
+"OPCODE=SQUERY,RESPONSE"
+"term"
+"name"
+"RFC,"
+"always"
+"Authority"
+"THIS"
+"RFC."
+"mode"
+"timeout"
+"RFC-799,"
+"found"
+"|"
+"mean"
+"RESOLVERS"
+"status"
+"domain"
+"From"
+"Network"
+"QTYPE,"
+"series"
+"SOME"
+"idea"
+"related"
+"CNAME"
+"UDEL"
+"happen"
+"beyond"
+"RFC-882"
+"special"
+"out"
+"try"
+"E."
+"space"
+"open"
+"since"
+"stub"
+"L."
+"MINIMUM"
+"RFC-768,"
+"RDATA"
+"get"
+"cause"
+"REFRESH,"
+"HOSTMASTER@SRI-NIC.ARPA."
+"SERVERS"
+"This"
+"SLIST:"
+"free"
+"RFC"
+"reason"
+"base"
+"put"
+"byte"
+"RFC-952"
+"received."
+"generate"
+"SLIST,"
+"RFC-883,"
+"definition"
+"DATA."
+"thread"
+"YALE-BULLDOG.ARPA."
+"could"
+"transition"
+"QCLASS,"
+"times"
+"MIT"
+"length"
+"place"
+"ICS.UCI"
+"HOSTMASTER@SRI-NIC.ARPA"
+"first"
+"origin"
+"already"
+"RD."
+"CONFIGURED"
+"number"
+"one"
+"RFC-"
+"Start"
+"ISI"
+"RFC-953."
+"construct"
+"another"
+"owner"
+"message"
+"QTYPE=*"
+"Local"
+"CSNET"
+"size"
+"doesn't"
+"given"
+"\""
+"X."
+"A.ISI.EDU"
+"service"
+"set,"
+"introduction"
+"unknown"
+"top"
+"system"
+"least"
+"parallel"
+"their"
+"intermediate"
+"master"
+"listed"
+"passed"
+"QTYPE"
+"ignored."
+"scheme"
+"Data"
+"store"
+"gives"
+"BBN"
+"that"
+"completed"
+"UDP"
+"XX"
+"part"
+"too"
+"RFC-953]."
+"(CNAME)"
+"translation"
+"copy"
+"than"
+"population"
+"wide"
+"Set"
+"K."
+"target"
+"DNS,"
+"16"
+"was"
+"require"
+"second"
+"matter"
+"See"
+"classes"
+"were"
+"[RFC-1031]"
+"result"
+"and"
+"Information"
+"[RFC-805]"
+"QNAME"
+"[RFC-811]"
+"[RFC-1032]"
+"say"
+"have"
+"need"
+"Mail"
+"1"
+"null"
+"RETRY"
+"any"
+"contents"
+"|(SRI-NIC.ARPA,"
+"SOMEONE"
+"RESOURCE"
+"73.0.0.26.IN-ADDR.ARPA."
+"min"
+"DARPA"
+"database."
+"responsible"
+"able"
+"RFC-812,"
+"mechanism"
+"client"
+"also"
+"(AA)"
+"contact"
+"take"
+"which"
+"MIL."
+"MIL,"
+"="
+"UCI"
+"added"
+"multiple"
+"Name"
+"USC-ISIC.ARPA."
+"QCLASS=IN,"
+"track"
+"object"
+"most"
+"detect"
+"connected"
+"services"
+"The"
+"]"
+"model"
+"domain."
+"D."
+"RFC-1010,"
+"D,"
+"[RFC-1010]"
+"RFC-805,"
+"AA,"
+"sometimes"
+"Some"
+"VAXA.ISI.EDU."
+"QNAME=ISI.EDU,"
+"MG)."
+"error"
+"If"
+"fact"
+"QNAME=SRI-NIC.ARPA,"
+"particularly"
+"text"
+"supported"
+"terminate"
+"VENERA"
+"attempts"
+"relation"
+"RFC-1033,"
+"Under"
+"|(VAXA.ISI.EDU,VENERA.ISI.EDU,"
+"USC-ISIC.ARPA,"
+"find"
+"cache."
+"Z"
+"based"
+"advanced"
+"RECORDS"
+"implementation"
+"("
+"cache"
+"[RFC-768]"
+"outside"
+"should"
+"XX.LCS.MIT.EDU"
+"only"
+"PVM@ISI.EDU."
+"RETRY,"
+"local"
+"do"
+"[RFC-1031]."
+"means"
+"there"
+"While"
+"cannot"
+"new"
+"2"
+"LOUIE.UDEL.EDU."
+"IN-ADDR"
+"processes"
+"resource"
+"A.ISI"
+"cached"
+"NIC"
+"generally"
+"(via"
+"ROME.UCI"
+"Zones"
+"RFC-920,"
+"J."
+"RFC-920."
+"common"
+"mapped"
+"including"
+"where"
+"valid"
+"set"
+"For"
+"configured"
+"we"
+"QNAME=SRI-NIC.ARPA.,"
+"up"
+"relative"
+"depends"
+"individual"
+"are"
+"RFC-883]."
+"close"
+"A.ISI.EDU."
+"said"
+"A.ISI.EDU)"
+"purpose"
+"TCP"
+"label"
+"PC"
+"3"
+"unable"
+"between"
+"probably"
+"boundary"
+"C.D,"
+"numerous"
+"across"
+"available"
+"C"
+"terms"
+"ability"
+"parent"
+"RFC-830]."
+"LCS.MIT.EDU"
+"negotiated"
+"REFRESH"
+"UNIX"
+"CH)."
+"key"
+"March"
+"configuration"
+"come"
+"classes."
+"AND"
+"both"
+"RFC-1002,"
+"OPCODE=SQUERY"
+"last"
+"LCS"
+"deals"
+"PDP-11/70"
+"equal"
+"against"
+"ISI.EDU."
+"MAILB"
+"[RFC-974]"
+"opcode"
+"RFC-742,"
+"C.ISI.EDU"
+"expression"
+"can't"
+"load"
+"among"
+"[RFC-920]"
+"point"
+"simple"
+"had"
+"period"
+"header"
+"[IEN-116]"
+"DNS."
+"52.0.0.10.IN-ADDR.ARPA"
+"table"
+"poll"
+"UMN-REI-UC.ARPA."
+"["
+"[RFC-883]"
+"RFC-974,"
+"RFC-1002"
+"addition"
+"P."
+"create"
+"S.,"
+"political"
+"copies"
+"been"
+"."
+"Early"
+"Introduction"
+"describes"
+"expected"
+"empty"
+"RA"
+"SLIST."
+"CH"
+"(RD)"
+"VENERA.ISI.EDU."
+"with"
+"SRI"
+"PVM@ISI.EDU"
+"[RFC-821]"
+"Using"
+"an"
+"case"
+"exception"
+"has"
+"NAME"
+"these"
+"appearance"
+"value"
+"will"
+"while"
+"replaced"
+"many"
+"loop"
+"SOA,"
+"RFC-1001,"
+"\"NICNAME/WHOIS\","
+"is"
+"CACHE"
+"it"
+"encountered"
+"FACILITIES"
+"in"
+"|(XX.LCS.MIT.EDU,"
+"RESPONSE,"
+"if"
+"SOA"
+"binary"
+"different"
+"perhaps"
+"[RFC-819]"
+"perform"
+"make"
+"hostname"
+"same"
+"orders"
+"QNAME."
+"QNAME,"
+"parts"
+"widely"
+"of:"
+"several"
+"Types"
+"(NE)."
+"development"
+"fairly"
+"used"
+"Institute"
+"IP"
+"\"."
+"CONCEPTS"
+"effect"
+"user"
+"IN"
+"infinite"
+"frequently"
+"ID"
+"recent"
+"task"
+"SCENARIO"
+"database"
+"makes"
+"depending"
+"well"
+"It"
+"HOSTS.TXT"
+"without"
+"thought"
+"edge"
+"Names"
+"RFC-811,"
+"In"
+"organization"
+"the"
+"ACC.ARPA."
+"left"
+"United"
+"protocol"
+"less"
+"being"
+"-"
+"rest"
+"A,"
+"Access"
+"CSNET."
+"stored"
+"RFC-882,"
+"Internet"
+"followed"
+"(QTYPE),"
+"previous"
+"RFC-952,"
+"|ACHILLES.MIT.EDU)"
+"majority"
+"XX.COM."
+"|(C.ISI.EDU,SRI-NIC.ARPA"
+"character"
+"capabilities"
+"(RDATA)"
+"source"
+"add"
+"internal"
+"TTL)"
+"4"
+"Although"
+"RCODE=NE"
+"5"
+"save"
+"administrative"
+"remaining"
+"match"
+"build"
+"around"
+"ACHILLES.MIT.EDU."
+"format"
+"read"
+"Of"
+"possible"
+"required."
+"alias"
+"ISIC.ARPA,"
+"integer"
+"bit"
+"VAXA.ISI"
+"found,"
+"desire"
+"SLIST"
+"sorting"
+"OPCODE=SQUERY,"
+"OF"
+"AUTHORITY"
+"server"
+"specific"
+"popular"
+"output"
+"OS"
+"Before"
+"STATUS"
+"DOMAIN"
+"because"
+"old"
+"often"
+"deal"
+"sequence"
+"RFC-821,"
+"SRI-NIC.ARPA.|"
+"Since"
+"some"
+"System"
+"growth"
+"equivalent"
+"examples"
+"loaded"
+"INCORRECTLY"
+"unless"
+"reasons"
+"TCP/IP"
+"happens"
+"ignore"
+"for"
+"W."
+"RFC-883"
+"X.COM"
+"avoid"
+"QTYPE=MX"
+"does"
+"allocate"
+"COM"
+"assuming"
+"BRL"
+"PTR"
+"[RFC-793]"
+"refer"
+"be"
+"example,"
+"MIT.EDU."
+"broken"
+"host"
+"become"
+"by"
+"SRI-NIC"
+"on"
+"about"
+"actual"
+"socket"
+"SCLASS"
+"RFC-810,"
+"of"
+"FTP)"
+"US"
+"compatible"
+"extensions"
+"\"A\"."
+"UK"
+"referred"
+"or"
+"ACC"
+"SBELT."
+"SBELT,"
+"No"
+"(SBELT)"
+"into"
+"within"
+"A.X.COM."
+"Two"
+"A.X.COM,"
+"negative"
+"included"
+"REFERENCES"
+"determine"
+"USC-ISIC.ARPA"
+"file."
+"[RFC-1001]"
+"[RFC-830]"
+"RESPONSE"
+"fast"
+"additional"
+"[RFC-812]"
+"transfer"
+"support"
+"*"
+"question"
+"NE"
+"long"
+"class"
+"start"
+"SERIAL"
+"TTL,"
+"User"
+"A.X.COM"
+"forward"
+"RD,"
+"\"4.3.2.1.IN-ADDR.ARPA\"."
+"NS"
+"sections"
+"function"
+"RR."
+"RR,"
+"QTYPE=A"
+"complete"
+"form"
+"MEMO"
+"but"
+"back"
+"failure"
+"link"
+"DNS"
+"SNAME."
+"encoded"
+"line"
+"trying"
+"true"
+"TCP/UDP"
+"[RFC-1033]"
+"count"
+"SBELT"
+"made"
+"[RFC-952]"
+"algorithm"
+"used,"
+"(NIC)"
+"official"
+"this,"
+"classes:"
+"experimental"
+"ISI.EDU,"
+"limit"
+"critical"
+"VAXA"
+"distribution"
+"NETBIOS"
+"similar"
+"called"
+"[RFC-1001,"
+"delete"
+"CIC"
+"USC-"
+"units"
+"ad"
+"RECORDS,"
+"defined"
+"request"
+"specified"
+"influence"
+"general"
+"To"
+"as"
+"exist"
+"at"
+"file"
+"MX."
+"check"
+"physical"
+"X.COM,"
+"functions"
+"QNAME=USC-ISIC.ARPA,"
+"no"
+"[RFC-882,"
+"when"
+"QTYPE=MX,"
+"virtual"
+"details."
+"field"
+"RFC-952."
+"other"
+"role"
+"test"
+"you"
+"(QNAME),"
+"IP/TCP"
+"formats"
+"AA"
+"requested"
+"[RFC-974"
+"SPACE"
+"QNAME=SIR-NIC.ARPA.,"
+"RFC-819,"
+"important"
+"variable"
+"[RFC-882]"
+"[RFC-1002]"
+"structure"
+"\"DOD"
+"BIBLIOGRAPHY"
+"lead"
+"using"
+"US."
+"\"MILNET"
+"103.0.3.26.IN-ADDR.ARPA."
+"together"
+"An"
+"As"
+"RFC-973,"
+"time"
+"failures"
+"starting"
+"having"
+"V"
+"FOO.F.ISI.ARPA,"
+"Assuming"
+"[RFC-1034]."
+"calculate"
+"IMPLEMENTATION"
+"Not"
+"ANCOUNT"
+"Secondary"
+"@"
+"ALL"
+"P"
+"TXT-DATA"
+"namespaces"
+"entries"
+"RMAILBX"
+"prevent"
+"QDCOUNT"
+"[RFC-1010]."
+"EMAILBX"
+"IN-"
+"OPCODE=IQUERY,"
+"MX)"
+"implemented"
+"port"
+"Available"
+"ID=997"
+"[RFC-1034],"
+"\"VENERA.ISI.EDU\";"
+"OPCODE"
+"MILNET-GW.ISI.EDU."
+";"
+"body"
+"52.0.2.10.IN-ADDR.ARPA."
+"reported"
+"objects"
+"strong"
+"UNIX\""
+"MD"
+"MF"
+"QNAME=10.IN-ADDR.ARPA."
+"serialize"
+"<SUBSYS>ISI-MAILBOXES.TXT"
+"X,"
+"Too"
+"77.0.0.10.IN-ADDR.ARPA."
+"spawned"
+"exception."
+"permitted"
+"RDLENGTH"
+"few"
+"duplicate"
+"QTYPE=PTR,"
+"CURLEY"
+"MD,"
+"F"
+"[RFC-974]."
+"MGMNAME"
+"validity"
+"GW.LCS.MIT.EDU,"
+"Time"
+"(back"
+"\\DDD"
+"10.IN-ADDR.ARPA."
+"closing"
+"requested,"
+"reserved"
+"EXCHANGE."
+"HIS"
+"reject"
+"ensure"
+"(MD)"
+"QTYPES"
+"PROTOCOL"
+"description"
+"26.IN-ADDR.ARPA"
+"NSCOUNT"
+"(MR)"
+"derived"
+"Foreign"
+"OWN"
+"26.IN-ADDR.ARPA."
+"TC"
+"map."
+"cases."
+"PREFERENCE"
+"don't"
+"VENERA.ISI.EDU"
+"held"
+"X"
+"below:"
+"$INCLUDE."
+"forms"
+"MR)"
+"VAXA.ISI.EDU"
+"main"
+"pending"
+"timestamp"
+"Ignoring"
+"MADNAME."
+"\\"
+"$ORIGIN"
+"\"IBM-PC"
+"document"
+"$INCLUDE"
+"SERVER"
+"ADDRESS"
+"identifier"
+"Check"
+"reduce"
+"static"
+"expect"
+"MASTER"
+"GW.ISI.EDU."
+"(QNAME)."
+"is:"
+"GW.ISI.EDU,"
+"F.ISI.ARPA,"
+"F.ISI.ARPA."
+"time."
+"PTRDNAME"
+"HOSTMASTER@SRI-"
+"(STATUS)"
+"possibility"
+"|QTYPE=A,"
+"(MINFO)"
+"initialize"
+"beginning"
+"compression"
+"(MG)"
+"created"
+"QCLASS."
+"encoding"
+"(HS)"
+"MNAME"
+"ports"
+"QNAME=VENERA.ISI.EDU"
+"(IN)"
+"Response"
+"KNOWS."
+"|QR|"
+"VAXA.ISI.EDU,"
+"Reserved"
+"14"
+"1)"
+"SOA."
+"ARCOUNT"
+"Other"
+"RCODE"
+"NEWNAME"
+"22.0.2.10.IN-ADDR.ARPA."
+"With"
+"CLASS"
+"begin"
+"(MF)."
+"Common"
+"<RDATA>"
+"Responses"
+"EGP."
+"average"
+"R"
+"QNAME=6.0.0.10.IN-ADDR.ARPA,"
+"WKS"
+"SYSTEM,"
+"ARPANET,"
+"MINFO"
+"participate"
+"DEFINITIONS"
+"failed"
+"[RFC-1034]"
+"mixture"
+"SPECIFICATION"
+"THE"
+"MILNET."
+"MILNET-"
+"<BIT"
+"bytes"
+"(MX)"
+"10.IN-ADDR.ARPA"
+"4.0.10.18.IN-ADDR.ARPA."
+"FOO.F.ISI.ARPA"
+"(QUERY)"
+"maximum"
+"existence"
+"|AA|TC|RD|RA|"
+"MADNAME"
+"subject"
+"QTYPE=A,"
+"FILES"
+"reading"
+"0."
+"corruption"
+"0,"
+"Sending"
+"MF,"
+"connection."
+"Server"
+"entries."
+"suggested"
+"reverse"
+"AXFR,"
+"according"
+"connection"
+"MAILA"
+"(QCLASS),"
+"exceeds"
+"ISI.EDU:"
+"103.0.0.26.IN-ADDR.ARPA."
+"[RFC-822]."
+"NAMEDROPPERS@SRI-NIC.ARPA"
+"RESOLVER"
+"respect"
+"throughout"
+"S"
+"FOO"
+"define"
+"enable"
+"EXCHANGE"
+"SMTP"
+"MG"
+"QCLASS=*,"
+"CS"
+"$ORIGIN,"
+"(MB,"
+"TYPE"
+"Any"
+"Size"
+"rename"
+"almost"
+"parse"
+"ADDR.ARPA"
+"(SMTP)."
+"key."
+"MAP>"
+"expired"
+"member"
+"Address"
+"DDD."
+"MB."
+"NS,"
+"I"
+"MR"
+"read,"
+"OPCODE=RESPONSE,"
+"person"
+"entry"
+"WITHIN"
+"LARRY"
+"front"
+"tables"
+"loading"
+"unsigned"
+"aspects"
+"D"
+"CHAOS"
+"WHICH"
+"(IQUERY)"
+"QCLASS=IN"
+"6.0.0.10.IN-ADDR.ARPA."
+"S."
+"QTYPE=MAILB"
+"HS"
+"SUPPORT"
+"A.X,"
+"STOOGES"
+"discarded"
+"done."
+"literals"
+"X.Y"
+"However"
+"/"
+"(SLIST)."
+"X.Y,"
+"integer."
+"ARPA,"
+"who"
+"18.IN-ADDR.ARPA."
+"B.X"
+"expansion"
+"OS,"
+"offset"
+"F.ISI.ARPA"
+"GGP"
+"O"
+"Communications"
+"RR),"
+"location"
+"MOE"
+"range"
+"value."
+"Message"
+"block"
+"$INCLUDE,"
+"guard"
+"[<TTL>]"
+"QR"
+"CRLF"
+"Error"
+"ERRORS-TO:"
+"he"
+"default"
+"MESSAGES"
+"signed"
+"storing"
+"MULTICS.MIT.EDU."
+"New"
+"NULL"
+"application"
+"OFFSET"
+"holding"
+"TXT"
+"NSDNAME"
+"PROTOCOL=TCP"
+"UDP."
+"UDP,"
+"RNAME"
+"GW.LCS.MIT.EDU."
+"(EXPERIMENTAL)"
+"\\X"
+"MAIL"
+"NIC.ARPA"
+
diff --git a/chromium/net/data/fuzzer_dictionaries/net_http_proxy_client_socket_fuzzer.dict b/chromium/net/data/fuzzer_dictionaries/net_http_proxy_client_socket_fuzzer.dict
new file mode 100644
index 00000000000..4028d26ea16
--- /dev/null
+++ b/chromium/net/data/fuzzer_dictionaries/net_http_proxy_client_socket_fuzzer.dict
@@ -0,0 +1,1088 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Fuzzer dictionary targetting HTTP/1.x responses.
+
+# Entries that are generally useful in headers
+":"
+"\x0A"
+"\x0D"
+"0"
+"50"
+"500"
+# Horizontal whitespace. Matters mostly in status line.
+" "
+"\x09"
+# Header continuation
+"\x0D\x0A\x09"
+# Used in a lot of individual headers
+";"
+"="
+","
+"\""
+"-"
+
+# Status line components
+"HTTP"
+"/1.1"
+"/1.0"
+# More interesting status codes. Leading space so can be inserted into
+# other status lines.
+" 100"
+" 200"
+" 206"
+" 301"
+" 302"
+" 303"
+" 304"
+" 307"
+" 308"
+" 401"
+" 403"
+" 404"
+" 500"
+" 501"
+" 403"
+
+# Full status lines (Some with relevant following headers)
+"HTTP/1.1 200 OK\x0A\x0A"
+"HTTP/1.1 100 Continue\x0A\x0A"
+"HTTP/1.1 401 Unauthorized\x0AWWW-Authenticate: Basic realm=\"Middle-Earth\"\x0A\xA0"
+"HTTP/1.1 407 Proxy Authentication Required\x0AProxy-Authenticate: Digest realm=\"Middle-Earth\", nonce=\"aaaaaaaaaa\"\x0A\x0A"
+"HTTP/1.0 301 Moved Permanently\x0ALocation: /a\x0A\x0A"
+"HTTP/1.1 302 Found\x0ALocation: http://lost/\x0A\x0A"
+
+# Proxy authentication headers. Note that fuzzers don't support NTLM or
+# negotiate.
+"WWW-Authenticate:"
+"Proxy-Authenticate:"
+"Basic"
+"Digest"
+"realm"
+"nonce"
+
+"Connection:"
+"Proxy-Connection:"
+"Keep-Alive"
+"Close"
+"Upgrade"
+"\x0AConnection: Keep-Alive"
+"\x0AConnection: Close"
+"\x0AProxy-Connection: Keep-Alive"
+"\x0AProxy-Connection: Close"
+
+"Content-Length:"
+"Transfer-Encoding:"
+"chunked"
+"\x0AContent-Length: 0"
+"\x0AContent-Length: 500"
+"\x0ATransfer-Encoding: chunked\x0A\x0A5\x0A12345\x0A0\x0A\x0A"
+
+"Location:"
+"\x0ALocation: http://foo/"
+"\x0ALocation: http://bar/"
+"\x0ALocation: https://foo/"
+"\x0ALocation: https://bar/"
+
+"Accept-Ranges:"
+"bytes"
+"\x0AAccept-Ranges: bytes"
+
+"Content-Range:"
+
+"Age:"
+"\x0AAge: 0"
+"\x0AAge: 3153600000"
+
+"Cache-Control:"
+"max-age"
+"no-cache"
+"no-store"
+"must-revalidate"
+"\x0ACache-Control: max-age=3153600000"
+"\x0ACache-Control: max-age=0"
+"\x0ACache-Control: no-cache"
+"\x0ACache-Control: no-store"
+"\x0ACache-Control: must-revalidate"
+
+"Content-Disposition:"
+"attachment"
+"filename"
+
+"Content-Encoding:"
+"gzip"
+"deflate"
+"sdch"
+"br"
+"\x0AContent-Encoding: gzip"
+"\x0AContent-Encoding: deflate"
+"\x0AContent-Encoding: sdch"
+"\x0AContent-Encoding: br"
+
+"Date:"
+"Fri, 01 Apr, 2050 14:14:14 GMT"
+"Mon, 28 Mar, 2016 04:04:04 GMT"
+"\x0ADate: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0ADate: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Last-Modified:"
+"\x0ALast-Modified: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0ALast-Modified: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Expires:"
+"\x0AExpires: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0AExpires: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Set-Cookie:"
+"Expires"
+"Max-Age"
+"Domain"
+"Path"
+"Secure"
+"HttpOnly"
+"Priority"
+"Low"
+"Medium"
+"High"
+"SameSite"
+"Strict"
+"Lax"
+"\x0ASet-Cookie: foo=bar"
+"\x0ASet-Cookie: foo2=bar2;HttpOnly;Priority=Low;SameSite=Strict;Path=/"
+"\x0ASet-Cookie: foo=chicken;SameSite=Lax"
+
+"Strict-Transport-Security:"
+"includeSubDomains"
+
+"Vary:"
+"\x0AVary: Cookie"
+"\x0AVary: Age"
+
+"ETag:"
+"\x0AETag: jumboshrimp"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_http_proxy_client_socket_fuzzer binary and RFC 2616.
+"all"
+"code"
+"maximum"
+"Transfer-Encoding"
+"D.,"
+"results"
+"follow"
+"(LZW)."
+"provided."
+"(which"
+"ISDN"
+"\"TE\""
+"LF>"
+"FORCE"
+"calculate"
+"\"IETF"
+"UNIX,"
+"ARPA"
+"\"OPTIONAL\""
+"environment"
+"Host"
+"program"
+"USENET"
+"TEXT"
+"Not"
+"Nov"
+"include"
+"resources"
+"CONNECT"
+"digit"
+"supported"
+"string"
+"returning"
+"ALL"
+"HTTP/1.1;"
+"SP,"
+"SP."
+"entries"
+"HTTP/1.1,"
+"HTTP/1.1."
+"difference"
+"(URI):"
+"--"
+"[CRLF]"
+"EXPRESS"
+"list"
+"HTTP/1.0\","
+"(RFC"
+"large"
+"ONLY"
+"Tag"
+"(LWS"
+"enclosing"
+"\"SHOULD\","
+"(URL)\","
+"\"A\"..\"Z\">"
+"unexpected"
+"GET)"
+"\"HEAD\""
+"direct"
+"Failed"
+"second"
+"Version"
+"\"A\""
+"allowed."
+"pass"
+"GET,"
+"tag."
+"implemented"
+"\"HTTP/1.0\""
+"INFRINGE"
+"errors"
+"ISO-8859-4,"
+"appear"
+"opaque"
+"section"
+"CPU"
+"current"
+"waiting"
+"version"
+"above"
+"TTL"
+"shared"
+"CRLF)"
+"public"
+"FTP"
+"NNTP."
+"WWW-"
+"never"
+"equals"
+"\"HTTP/1.1"
+"reported"
+"objects"
+"address"
+"active"
+"path"
+"["
+"\"POST\""
+"HTTP."
+"change"
+"MA"
+"\"AS"
+"broken"
+"BACK)"
+"NOT"
+"NNTP"
+"named"
+"useful"
+"secure"
+"family"
+"case."
+"detected."
+"\"HTTP\""
+"private"
+"CERN/3.0"
+"CTE"
+"(CTE)"
+"Too"
+"CTL"
+"PUT,"
+"user-agent"
+"PUT)"
+"byte"
+"select"
+"use"
+"TASK"
+"from"
+"exception."
+"working"
+"to"
+"value."
+"WARRANTIES"
+"two"
+"URI;"
+"User-Agent"
+"few"
+"--THIS_STRING_SEPARATES"
+"POST,"
+"call"
+"6"
+"MUST,"
+"scope"
+"type"
+"authorization"
+"more"
+"ISO-8859-9,"
+"(GMT),"
+"(TE)"
+"name."
+"initial"
+"Required"
+"RFC-850"
+"warn"
+"bytes,"
+"Found"
+"cases"
+"MHTML"
+"name:"
+"must"
+"parse"
+"lowercase"
+"MHTML,"
+"RIGHTS"
+"this"
+"NTP"
+"work"
+"--THIS_STRING_SEPARATES--"
+"Syntax"
+"paragraph"
+"can"
+"tracing"
+"following"
+"\"I"
+"closing"
+"modifier"
+"root"
+"example"
+"requested,"
+"J.,"
+"control"
+"type."
+"reserved"
+"links"
+"process"
+"attribute"
+"allowed"
+"high"
+"currency"
+"numbers"
+"want"
+"type:"
+"native"
+"LF"
+"class,"
+"end"
+"Missing"
+"HTTP-"
+"HTTP,"
+"charset"
+"1"
+"line."
+"2*N"
+"H."
+"1XX"
+"WARRANTIES,"
+"HTTP:"
+"A"
+"badly"
+"HEAD"
+"may"
+"insecure"
+"after"
+"variant"
+"different"
+"wrong"
+"[SP"
+"ANSI,"
+"date"
+"such"
+"data"
+"parallel"
+"repeat"
+"a"
+"FTP,"
+"All"
+"short"
+"\"GET\""
+"Y."
+"UA"
+"(2**N),"
+"element"
+"so"
+"cases."
+"File"
+"(LWS)"
+"\"DEFLATE"
+"order"
+"\"SHOULD"
+"don't"
+"MIC"
+"move"
+"vary"
+"satisfied"
+"CD-ROM,"
+"ended"
+"HTTP-WG."
+"LINK,"
+"pointer"
+"its"
+"digest"
+"before"
+"HTML"
+"(OK)"
+"using:"
+"MAY,"
+"fix"
+"ISO-3166"
+"actually"
+"407"
+"(GNU"
+"\"HTTP/1.1\","
+"P.,"
+"401"
+"MERCHANTABILITY"
+"DNS."
+"into"
+"\"HTTP"
+"it."
+"it,"
+"return"
+"combination"
+"URL"
+"URI"
+"number"
+"Bad"
+"not"
+"However,"
+"SSL"
+"name"
+"always"
+"decimal"
+"expectation."
+"did"
+"ISO-639"
+"]URI,"
+"found"
+"trailer"
+"mean"
+"breakdown"
+"domain"
+"From"
+"UTC"
+"(via"
+"(URI)"
+"UNLINK"
+"used"
+"expect"
+"exceeded"
+"(MIC)"
+"event"
+"out"
+"is:"
+"by"
+"E."
+"space"
+"\"MUST/MAY/SHOULD\""
+"REQUIRED"
+"ALPHA"
+"HTTP/2.4"
+"4DIGIT"
+"increase"
+"L."
+"time."
+"PATCH,"
+"supports"
+"2DIGIT"
+"K.,"
+"(A,"
+"This"
+"free"
+"\"B\""
+"RFC"
+"base"
+"proxy"
+"IMPLIED,"
+"POST"
+"received."
+"generate"
+"text/plain"
+"ISO-8859-7,"
+"\"HTTP/1.1\""
+"Partial"
+"could"
+"transition"
+"DISCLAIMS"
+"times"
+"filter"
+"HTML\","
+"length"
+"HEAD."
+"HEAD,"
+"S.,"
+"first"
+"origin"
+"\"E\""
+"already"
+"UPALPHA"
+"3DIGIT"
+"*"
+"Cache"
+"Please"
+"token."
+"one"
+"CHAR"
+"ISI"
+"another"
+"FITNESS"
+"message"
+"CSS1,"
+"open"
+"size"
+"doesn't"
+"\""
+"script"
+"unknown"
+"top"
+"header)"
+"system"
+"construct"
+"image/gif"
+"2"
+"ignored."
+"listed"
+"Date"
+"LOALPHA"
+"scheme"
+"final"
+"store"
+"too"
+"M."
+"Success"
+"that"
+"completed"
+"OPTIONAL;"
+"task"
+"tokens"
+"R"
+"pragma"
+"(IANA"
+"WAIS"
+"F.,"
+"than"
+"(A"
+"K."
+"target"
+"16"
+"require"
+"Only"
+"WWW-Authenticate"
+"HTTP/2.13,"
+"headers"
+"See"
+"GMT."
+"HTTP/2.0,"
+"were"
+"1)"
+"IS\""
+"stale"
+"1*8ALPHA"
+"are"
+"and"
+"IRC/6.9,"
+"false"
+"URL)."
+"turned"
+"ANSI"
+"B"
+"(IANA)"
+"(LWS)."
+"have"
+"MIME,"
+"need"
+"HTTP/1.1.)"
+"null"
+"any"
+"contents"
+"conversion"
+"data)"
+"(LZ77)"
+"(MIME"
+"mechanism"
+"internal"
+"(C)"
+"take"
+"which"
+"With"
+"UCI"
+"HTTP/0.9,"
+"content-"
+"200"
+"begin"
+"headers)"
+"unless"
+"TCP/IP"
+"Content-Disposition"
+"206"
+"buffer"
+"object"
+"\"MUST\","
+"regular"
+"letter"
+"entry"
+"The"
+"]"
+"the"
+"D."
+"(STD"
+"incompatible"
+"L.,"
+"(URL)"
+"left"
+"+"
+"\"MIME"
+"Note:"
+"particularly"
+"WA"
+"text"
+"labels"
+"\"C\""
+"Authentication"
+"Unrecognized"
+"CRLF."
+"PARTICULAR"
+"CRLF,"
+"SP"
+"find"
+"MUST"
+"true,"
+"cache."
+"upgrade"
+"cache)"
+"implementation"
+"("
+"[RFC"
+"cache"
+"3"
+"should"
+"failed"
+"only"
+"unable"
+"LDAP)"
+"USA"
+"US-ASCII"
+"(UA)"
+"get"
+"E.,"
+"HEREIN"
+"\"HTTP\"."
+"cannot"
+"new"
+"THE"
+"BNF"
+"DIGIT,"
+"closure"
+"PUT"
+"0)"
+"resource"
+"A.,"
+"W."
+"Content-Type:"
+"ISO-8859."
+"calling"
+"J."
+"INCLUDING"
+"common"
+"INTERNET"
+"release"
+"ISI/RR-98-463,"
+"\"CONNECT\""
+"where"
+"set"
+"IANA"
+"For"
+"\"F\""
+"configured"
+"C"
+"this,"
+"multipart"
+"close"
+"end."
+"detect"
+"GET"
+"WWW\","
+"1*DIGIT"
+"BUT"
+"MIT"
+"outside"
+"Proxy-Authorization"
+"closed"
+"between"
+"probably"
+"boundary"
+"reading"
+"\"SHALL"
+"\"RECOMMENDED\","
+"available"
+"we"
+"FOR"
+"missing"
+"importance"
+"screen"
+"connection."
+"ISO-8859-1"
+"UNIX"
+"STD"
+"key"
+"(MIME)"
+"P."
+"\"HTTP/1.1\"."
+"HTTP/1.0),"
+"AND"
+"received"
+"WWW"
+"TRACE"
+"\"MAY\","
+"many"
+"*TEXT"
+"Unsupported"
+"Rules"
+"connection"
+"Unicode"
+"*OCTET"
+"exceeds"
+"(URN)"
+"safely"
+"finds"
+"can't"
+"WARRANTY"
+"ISO-8859-8,"
+"Content-Length"
+"consume"
+"stream"
+"simple"
+"header"
+"DNS)"
+"colon"
+"adding"
+"spans"
+"1*HEX"
+"table"
+"allocated"
+"BCP"
+"application/pdf"
+"LWS:"
+"\"REQUIRED\","
+"Wed,"
+"C."
+"C,"
+"Proxy-Authenticate"
+"encryption"
+"create"
+"(MHTML)\","
+"been"
+"."
+"HTTP/12.3."
+"\"OPTIONS\""
+"\"PUT\""
+"context."
+"LWS,"
+"basic"
+"expected"
+"prototype"
+"GMT,"
+"empty"
+">"
+"URL."
+"PNG,\""
+"\"D\""
+"CA"
+"HEX"
+"N"
+"0*3DIGIT"
+"\"W/\""
+"CR"
+"\"DELETE\""
+"unnecessarily"
+"case"
+"exception"
+"save"
+"(HTTP)"
+"value"
+"Assigned"
+"while"
+"\"GZIP"
+"\"SHALL\","
+"error"
+"\"GMT\""
+"\"TRACE\""
+"resident"
+"is"
+"thus"
+"it"
+"encountered"
+"Content"
+"MIME"
+"in"
+"SIGCOMM"
+"You"
+"if"
+"result"
+"binary"
+"containing"
+"\"A"
+")"
+"CREATE"
+"expired"
+"1DIGIT"
+"same"
+"OPTIONS"
+"read"
+"BNF,"
+"unrecognized"
+"units"
+"UST"
+"status"
+"\"%"
+"extended"
+"http"
+"context"
+"I"
+"IP"
+"(O)."
+"allocation"
+"running"
+"*LWS"
+"user"
+"SMTP"
+"stack"
+"tracking"
+"IETF"
+"CR."
+"failing"
+"ANY"
+"patterns"
+"M.,"
+"Names"
+"In"
+"position"
+"model"
+"audio"
+"If"
+"US-ASCII."
+"MAY"
+"THAT"
+"being"
+"(OK)."
+"actions"
+"invalid"
+"HTTP/1.0)"
+"CRC."
+"previous"
+"tables"
+"TO"
+"<US-ASCII"
+"character"
+"source"
+"ISO-8859-2,"
+"valid"
+"location"
+"HTTP/1.0"
+"HTTP/1.1"
+"size,"
+"has"
+"match"
+"build"
+"URI."
+"tests"
+"format"
+"transfer-encoding"
+"H.,"
+"T"
+"using"
+"LIMITED"
+"OK"
+"success"
+"text/html"
+"ISO-8859-5,"
+"B,"
+"signal"
+"MIME:"
+"(HTCPCP/1.0)\","
+"server"
+"discarded"
+"true"
+"OF"
+"output"
+"page"
+"S."
+"right"
+"old"
+"sequence"
+"uppercase"
+"B.,"
+"some"
+"back"
+"HT"
+"Last-Modified"
+"growth"
+"equivalent"
+"specified"
+"multiple"
+"H.F.,"
+"HTTP/1.0."
+"(BNF)"
+"happens"
+"ignore"
+"PUT."
+"INDEX."
+"trace"
+"for"
+"avoid"
+"CR,"
+"does"
+"Authorization"
+"assuming"
+"be"
+"run"
+"GET."
+"deleted"
+"302"
+"X3.4-1986"
+"<URL:"
+"O"
+"ISO-8859-1."
+"last-modified"
+"host"
+"HTTP/1.0,"
+"LWS>"
+"INFORMATION"
+"X3.4-1986,"
+"properties"
+"ALPHA,"
+"Location"
+"on"
+"DIGIT"
+"ENGINEERING"
+"actual"
+"extension"
+"of"
+"R.,"
+"\"UTF-8,"
+"*<TEXT,"
+"OR"
+"range"
+"3ALPHA"
+"URI,"
+"positive"
+"Message"
+"DELETE"
+"content-type"
+"or"
+"UC"
+"No"
+"ISO-"
+"image"
+"ACM"
+"HEX\""
+"URL,"
+"because"
+"ISO-8859-6,"
+"T.,"
+"operator"
+"T/TCP"
+"mark"
+"file."
+"area"
+"GET\""
+"transfer"
+"support"
+"there"
+"long"
+"class"
+"start"
+"HT."
+"forward"
+"was"
+"function"
+"HT,"
+"N."
+"HTTP/1.1\","
+"memory"
+"OCTET"
+"but"
+"failure"
+"TE:"
+"IMPLIED"
+"CRLF"
+"DNS"
+"Error"
+"\"ZLIB"
+"line"
+"trying"
+"with"
+"GMT"
+"count"
+"algorithm"
+"default"
+"B."
+"ISO-8859-1,"
+"up"
+"ISO-8859-1)"
+"SHOULD"
+"PURPOSE."
+"limit"
+"used."
+"WILL"
+"DEL"
+"define"
+"called"
+"delete"
+"DELETE,"
+"storing"
+"USE"
+"image/jpeg"
+"defined"
+"LWS"
+"combining"
+"unsafe"
+"an"
+"To"
+"as"
+"warning"
+"exist"
+"at"
+"file"
+"NOT\""
+"NOT,"
+"W3C/MIT"
+"ISO-8859-1:1987."
+"SHTTP/1.3,"
+"no"
+"when"
+"A,"
+"virtual"
+"A."
+"details."
+"application"
+"other"
+"OPTIONAL"
+"Proxy"
+"LF,"
+"test"
+"MD5"
+"you"
+"TE"
+"ISO-8859-3,"
+"requested"
+"elements"
+"C)"
+"symbol"
+"T."
+"code)"
+"variable"
+"SOCIETY"
+"\"MUST"
+"TCP"
+"ISO-10646\","
+"NOT\","
+"R."
+"lead"
+"audio/basic"
+"IANA."
+"\"WAIS"
+"persistent"
+"Its"
+"As"
+"time"
+"failures"
+"\"ISO-8859-1\""
+"once"
+
diff --git a/chromium/net/data/fuzzer_dictionaries/net_http_stream_parser_fuzzer.dict b/chromium/net/data/fuzzer_dictionaries/net_http_stream_parser_fuzzer.dict
new file mode 100644
index 00000000000..cba14dc5ee9
--- /dev/null
+++ b/chromium/net/data/fuzzer_dictionaries/net_http_stream_parser_fuzzer.dict
@@ -0,0 +1,1039 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Fuzzer dictionary targetting HTTP/1.x responses.
+
+# Entries that are generally useful in headers
+":"
+"\x0A"
+"\x0D"
+"0"
+"50"
+"500"
+# Horizontal whitespace. Matters mostly in status line.
+" "
+"\x09"
+# Header continuation
+"\x0D\x0A\x09"
+# Used in a lot of individual headers
+";"
+"="
+","
+"\""
+"-"
+
+# Status line components
+"HTTP"
+"/1.1"
+"/1.0"
+# More interesting status codes. Leading space so can be inserted into
+# other status lines.
+" 100"
+" 200"
+" 206"
+" 301"
+" 302"
+" 303"
+" 304"
+" 307"
+" 308"
+" 401"
+" 403"
+" 404"
+" 500"
+" 501"
+" 403"
+
+# Full status lines (Some with relevant following headers)
+"HTTP/1.1 200 OK\x0A\x0A"
+"HTTP/1.1 100 Continue\x0A\x0A"
+"HTTP/1.1 401 Unauthorized\x0AWWW-Authenticate: Basic realm=\"Middle-Earth\"\x0A\xA0"
+"HTTP/1.1 407 Proxy Authentication Required\x0AProxy-Authenticate: Digest realm=\"Middle-Earth\", nonce=\"aaaaaaaaaa\"\x0A\x0A"
+"HTTP/1.0 301 Moved Permanently\x0ALocation: /a\x0A\x0A"
+"HTTP/1.1 302 Found\x0ALocation: http://lost/\x0A\x0A"
+
+# Proxy authentication headers. Note that fuzzers don't support NTLM or
+# negotiate.
+"WWW-Authenticate:"
+"Proxy-Authenticate:"
+"Basic"
+"Digest"
+"realm"
+"nonce"
+
+"Connection:"
+"Proxy-Connection:"
+"Keep-Alive"
+"Close"
+"Upgrade"
+"\x0AConnection: Keep-Alive"
+"\x0AConnection: Close"
+"\x0AProxy-Connection: Keep-Alive"
+"\x0AProxy-Connection: Close"
+
+"Content-Length:"
+"Transfer-Encoding:"
+"chunked"
+"\x0AContent-Length: 0"
+"\x0AContent-Length: 500"
+"\x0ATransfer-Encoding: chunked\x0A\x0A5\x0A12345\x0A0\x0A\x0A"
+
+"Location:"
+"\x0ALocation: http://foo/"
+"\x0ALocation: http://bar/"
+"\x0ALocation: https://foo/"
+"\x0ALocation: https://bar/"
+
+"Accept-Ranges:"
+"bytes"
+"\x0AAccept-Ranges: bytes"
+
+"Content-Range:"
+
+"Age:"
+"\x0AAge: 0"
+"\x0AAge: 3153600000"
+
+"Cache-Control:"
+"max-age"
+"no-cache"
+"no-store"
+"must-revalidate"
+"\x0ACache-Control: max-age=3153600000"
+"\x0ACache-Control: max-age=0"
+"\x0ACache-Control: no-cache"
+"\x0ACache-Control: no-store"
+"\x0ACache-Control: must-revalidate"
+
+"Content-Disposition:"
+"attachment"
+"filename"
+
+"Content-Encoding:"
+"gzip"
+"deflate"
+"sdch"
+"br"
+"\x0AContent-Encoding: gzip"
+"\x0AContent-Encoding: deflate"
+"\x0AContent-Encoding: sdch"
+"\x0AContent-Encoding: br"
+
+"Date:"
+"Fri, 01 Apr, 2050 14:14:14 GMT"
+"Mon, 28 Mar, 2016 04:04:04 GMT"
+"\x0ADate: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0ADate: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Last-Modified:"
+"\x0ALast-Modified: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0ALast-Modified: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Expires:"
+"\x0AExpires: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0AExpires: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Set-Cookie:"
+"Expires"
+"Max-Age"
+"Domain"
+"Path"
+"Secure"
+"HttpOnly"
+"Priority"
+"Low"
+"Medium"
+"High"
+"SameSite"
+"Strict"
+"Lax"
+"\x0ASet-Cookie: foo=bar"
+"\x0ASet-Cookie: foo2=bar2;HttpOnly;Priority=Low;SameSite=Strict;Path=/"
+"\x0ASet-Cookie: foo=chicken;SameSite=Lax"
+
+"Strict-Transport-Security:"
+"includeSubDomains"
+
+"Vary:"
+"\x0AVary: Cookie"
+"\x0AVary: Age"
+
+"ETag:"
+"\x0AETag: jumboshrimp"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_http_stream_parser_fuzzer binary and RFC 2616.
+"all"
+"code"
+"maximum"
+"Transfer-Encoding"
+"D.,"
+"results"
+"follow"
+"(LZW)."
+"provided."
+"(which"
+"ISDN"
+"\"TE\""
+"LF>"
+"FORCE"
+"calculate"
+"\"IETF"
+"UNIX,"
+"ARPA"
+"\"OPTIONAL\""
+"environment"
+"ENGINEERING"
+"program"
+"USENET"
+"TEXT"
+"Not"
+"Nov"
+"include"
+"resources"
+"(STD"
+"labels"
+"string"
+"returning"
+"HTTP/1.1;"
+"SP,"
+"SP."
+"entries"
+"HTTP/1.1,"
+"HTTP/1.1."
+"difference"
+"(URI):"
+"did"
+"[CRLF]"
+"EXPRESS"
+"list"
+"HTTP/1.0\","
+"(RFC"
+"large"
+"ONLY"
+"Tag"
+"(LWS"
+"(URL)\","
+"\"A\"..\"Z\">"
+"unexpected"
+"GET)"
+"direct"
+"Failed"
+"second"
+"Version"
+"\"A\""
+"allowed."
+"GET,"
+"tag."
+"implemented"
+"\"HTTP/1.0\""
+"errors"
+"ISO-8859-4,"
+"appear"
+"incompatible"
+"section"
+"CPU"
+"current"
+"waiting"
+"version"
+"above"
+"TTL"
+"new"
+"CRLF)"
+"public"
+"FTP"
+"NNTP."
+"WWW-"
+"never"
+"equals"
+"\"HTTP/1.1"
+"reported"
+"objects"
+"address"
+"active"
+"\"HEAD\""
+"["
+"\"POST\""
+"HTTP."
+"change"
+"MA"
+"\"AS"
+"last-modified"
+"BACK)"
+"NOT"
+"NNTP"
+"named"
+"useful"
+"secure"
+"case."
+"detected."
+"\"HTTP\""
+"private"
+"CERN/3.0"
+"CTE"
+"(CTE)"
+"Too"
+"CTL"
+"PUT,"
+"user-agent"
+"PUT)"
+"POST"
+"select"
+"use"
+"TASK"
+"from"
+"exception."
+"working"
+"to"
+"positive"
+"two"
+"URI;"
+"properties"
+"few"
+"--THIS_STRING_SEPARATES"
+"POST,"
+"call"
+"memory"
+"MUST,"
+"scope"
+"type"
+"authorization"
+"more"
+"ISO-8859-9,"
+"(GMT),"
+"(TE)"
+"name."
+"LF,"
+"RFC-850"
+"warn"
+"bytes,"
+"Found"
+"cases"
+"MHTML"
+"name:"
+"must"
+"Content"
+"ALL"
+"MHTML,"
+"RIGHTS"
+"this"
+"NTP"
+"work"
+"--THIS_STRING_SEPARATES--"
+"Syntax"
+"can"
+"of"
+"following"
+"\"I"
+"closing"
+"root"
+"example"
+"requested,"
+"J.,"
+"type."
+"reserved"
+"stream"
+"process"
+"attribute"
+"allowed"
+"high"
+"currency"
+"numbers"
+"want"
+"type:"
+"native"
+"LF"
+"class,"
+"end"
+"Missing"
+"HTTP-"
+"HTTP,"
+"links"
+"1"
+"line."
+"2*N"
+"H."
+"1XX"
+"WARRANTIES,"
+"HTTP:"
+"A"
+"badly"
+"HEAD"
+"may"
+"insecure"
+"after"
+"containing"
+"tracking"
+"wrong"
+"[SP"
+"ANSI,"
+"date"
+"such"
+"data"
+"parallel"
+"repeat"
+"a"
+"FTP,"
+"All"
+"short"
+"Y."
+"UA"
+"(2**N),"
+"element"
+"so"
+"cases."
+"File"
+"(LWS)"
+"\"DEFLATE"
+"order"
+"charset"
+"\"SHOULD"
+"don't"
+"MIC"
+"move"
+"vary"
+"satisfied"
+"CD-ROM,"
+"HTTP-WG."
+"LINK,"
+"pointer"
+"its"
+"digest"
+"before"
+"HTML"
+"(OK)"
+"Rules"
+"MAY,"
+"fix"
+"ISO-3166"
+"actually"
+"407"
+"(GNU"
+"\"HTTP/1.1\","
+"P.,"
+"401"
+"MERCHANTABILITY"
+"DNS."
+"into"
+"\"HTTP"
+"it."
+"it,"
+"return"
+"URL"
+"URI"
+"number"
+"Bad"
+"not"
+"However,"
+"SSL"
+"name"
+"always"
+"expectation."
+"--"
+"ISO-639"
+"]URI,"
+"found"
+"trailer"
+"mean"
+"breakdown"
+"From"
+"UTC"
+"(via"
+"(URI)"
+"UNLINK"
+"expect"
+"exceeded"
+"(MIC)"
+"event"
+"out"
+"is:"
+"E."
+"space"
+"\"MUST/MAY/SHOULD\""
+"REQUIRED"
+"ALPHA"
+"HTTP/2.4"
+"4DIGIT"
+"increase"
+"L."
+"time."
+"PATCH,"
+"supports"
+"2DIGIT"
+"K.,"
+"(A,"
+"This"
+"free"
+"\"B\""
+"RFC"
+"base"
+"IMPLIED,"
+"byte"
+"received."
+"generate"
+"text/plain"
+"ISO-8859-7,"
+"\"HTTP/1.1\""
+"Partial"
+"could"
+"transition"
+"DISCLAIMS"
+"times"
+"filter"
+"HTML\","
+"length"
+"HEAD."
+"HEAD,"
+"S.,"
+"first"
+"origin"
+"\"E\""
+"already"
+"UPALPHA"
+"3DIGIT"
+"Cache"
+"Please"
+"token."
+"one"
+"CHAR"
+"ISI"
+"another"
+"FITNESS"
+"message"
+"CSS1,"
+"open"
+"size"
+"doesn't"
+"\""
+"script"
+"unknown"
+"top"
+"header)"
+"system"
+"construct"
+"image/gif"
+"2"
+"ignored."
+"listed"
+"Date"
+"LOALPHA"
+"scheme"
+"store"
+"too"
+"M."
+"Success"
+"that"
+"completed"
+"OPTIONAL;"
+"R"
+"pragma"
+"(IANA"
+"WAIS"
+"F.,"
+"than"
+"K."
+"target"
+"Content-Type:"
+"require"
+"Only"
+"HTTP/2.13,"
+"headers"
+"See"
+"GMT."
+"HTTP/2.0,"
+"were"
+"1)"
+"IS\""
+"1*8ALPHA"
+"are"
+"and"
+"IRC/6.9,"
+"false"
+"turned"
+"ANSI"
+"B"
+"(IANA)"
+"tables"
+"have"
+"MIME,"
+"need"
+"HTTP/1.1.)"
+"null"
+"any"
+"contents"
+"data)"
+"(LZ77)"
+"(MIME"
+"mechanism"
+"internal"
+"(C)"
+"take"
+"which"
+"With"
+"UCI"
+"HTTP/0.9,"
+"content-"
+"200"
+"begin"
+"multiple"
+"TCP/IP"
+"Content-Disposition"
+"206"
+"buffer"
+"object"
+"\"MUST\","
+"regular"
+"entry"
+"The"
+"]"
+"model"
+"D."
+"US-ASCII"
+"L.,"
+"(URL)"
+"If"
+"+"
+"\"MIME"
+"Note:"
+"particularly"
+"WA"
+"text"
+"supported"
+"\"C\""
+"Unrecognized"
+"CRLF."
+"CRLF,"
+"SP"
+"find"
+"MUST"
+"true,"
+"cache."
+"upgrade"
+"cache)"
+"implementation"
+"("
+"[RFC"
+"cache"
+"outside"
+"should"
+"failed"
+"only"
+"URL)."
+"LDAP)"
+"USA"
+"WARRANTIES"
+"(UA)"
+"get"
+"there"
+"HEREIN"
+"\"HTTP\"."
+"cannot"
+"shared"
+"THE"
+"BNF"
+"DIGIT,"
+"closure"
+"PUT"
+"reading"
+"resource"
+"A.,"
+"W."
+"16"
+"ISO-8859."
+"calling"
+"J."
+"INCLUDING"
+"common"
+"INTERNET"
+"release"
+"ISI/RR-98-463,"
+"\"CONNECT\""
+"where"
+"set"
+"IANA"
+"For"
+"\"F\""
+"configured"
+"C"
+"this,"
+"multipart"
+"close"
+"E.,"
+"end."
+"detect"
+"GET"
+"WWW\","
+"1*DIGIT"
+"BUT"
+"MIT"
+"3"
+"unable"
+"between"
+"probably"
+"boundary"
+"0)"
+"\"SHALL"
+"\"RECOMMENDED\","
+"available"
+"we"
+"FOR"
+"missing"
+"importance"
+"screen"
+"connection."
+"PARTICULAR"
+"UNIX"
+"STD"
+"ISO-8859-1"
+"key"
+"(MIME)"
+"P."
+"\"HTTP/1.1\"."
+"HTTP/1.0),"
+"AND"
+"received"
+"WWW"
+"TRACE"
+"\"MAY\","
+"many"
+"*TEXT"
+"Unsupported"
+"using:"
+"connection"
+"Unicode"
+"*OCTET"
+"exceeds"
+"(URN)"
+"safely"
+"ANY"
+"can't"
+"WARRANTY"
+"ISO-8859-8,"
+"Content-Length"
+"consume"
+"simple"
+"header"
+"DNS)"
+"colon"
+"\"GET\""
+"spans"
+"1*HEX"
+"table"
+"allocated"
+"BCP"
+"application/pdf"
+"LWS:"
+"save"
+"\"REQUIRED\","
+"Wed,"
+"C."
+"C,"
+"encryption"
+"create"
+"(MHTML)\","
+"been"
+"."
+"HTTP/12.3."
+"\"PUT\""
+"context."
+"LWS,"
+"basic"
+"expected"
+"prototype"
+"GMT,"
+"empty"
+"define"
+"PNG,\""
+"\"D\""
+"with"
+"CA"
+"HEX"
+"N"
+"0*3DIGIT"
+"\"W/\""
+"CR"
+"\"DELETE\""
+"unnecessarily"
+"case"
+"exception"
+"(A"
+"(HTTP)"
+"value"
+"INFRINGE"
+"while"
+"\"GZIP"
+"\"SHALL\","
+"error"
+"\"GMT\""
+"(LWS)."
+"resident"
+"is"
+"thus"
+"it"
+"encountered"
+"parse"
+"MIME"
+"in"
+"SIGCOMM"
+"You"
+"if"
+"result"
+"binary"
+"different"
+"\"A"
+")"
+"CREATE"
+"expired"
+"1DIGIT"
+"same"
+"OPTIONS"
+"transfer-encoding"
+"BNF,"
+"unrecognized"
+"units"
+"UST"
+"status"
+"\"%"
+"used"
+"http"
+"context"
+"I"
+"IP"
+"(O)."
+"allocation"
+"running"
+"*LWS"
+"user"
+"SMTP"
+"\"SHOULD\","
+"stack"
+"task"
+"CR."
+"failing"
+"IETF"
+"M.,"
+"Names"
+"In"
+"position"
+"the"
+"audio"
+"left"
+"US-ASCII."
+"MAY"
+"THAT"
+"being"
+"(OK)."
+"actions"
+"invalid"
+"HTTP/1.0)"
+"CRC."
+"previous"
+"adding"
+"TO"
+"<US-ASCII"
+"source"
+"ISO-8859-2,"
+"\"OPTIONS\""
+"location"
+"HTTP/1.0"
+"HTTP/1.1"
+"size,"
+"has"
+"match"
+"build"
+"URI."
+"tests"
+"format"
+"read"
+"H.,"
+"T"
+"using"
+"LIMITED"
+"OK"
+"text/html"
+"success"
+"ISO-8859-5,"
+"B,"
+"signal"
+"MIME:"
+"(HTCPCP/1.0)\","
+"server"
+"ignore"
+"OF"
+"output"
+"page"
+"S."
+"because"
+"old"
+"sequence"
+"HT."
+"B.,"
+"some"
+"back"
+"HT"
+"Last-Modified"
+"growth"
+"DEL"
+"specified"
+"unless"
+"H.F.,"
+"HTTP/1.0."
+"(BNF)"
+"happens"
+"discarded"
+"PUT."
+"INDEX."
+"trace"
+"for"
+"avoid"
+"CR,"
+"does"
+"CONNECT"
+"assuming"
+"be"
+"run"
+"GET."
+"deleted"
+"equivalent"
+"X3.4-1986"
+"<URL:"
+"O"
+"ISO-8859-1."
+"broken"
+"host"
+"HTTP/1.0,"
+"LWS>"
+"INFORMATION"
+"X3.4-1986,"
+"by"
+"ALPHA,"
+"Location"
+"on"
+"DIGIT"
+"actual"
+"extension"
+"tracing"
+"R.,"
+"\"UTF-8,"
+"*<TEXT,"
+"OR"
+"range"
+"3ALPHA"
+"URI,"
+"value."
+"Message"
+"DELETE"
+"content-type"
+"or"
+"UC"
+"No"
+"ISO-"
+"image"
+"ACM"
+"HEX\""
+"URL,"
+"ISO-8859-6,"
+"T.,"
+"operator"
+"T/TCP"
+"file."
+"GET\""
+"transfer"
+"support"
+"*"
+"long"
+"class"
+"start"
+"forward"
+"was"
+"function"
+"HT,"
+"N."
+"HTTP/1.1\","
+"OCTET"
+"but"
+"failure"
+"TE:"
+"IMPLIED"
+"CRLF"
+"DNS"
+"Error"
+"\"ZLIB"
+"line"
+"trying"
+"true"
+"GMT"
+"count"
+"default"
+"B."
+"ISO-8859-1,"
+"up"
+"ISO-8859-1)"
+"SHOULD"
+"PURPOSE."
+"used."
+"WILL"
+">"
+"called"
+"delete"
+"DELETE,"
+"storing"
+"USE"
+"image/jpeg"
+"defined"
+"LWS"
+"URL."
+"unsafe"
+"an"
+"To"
+"as"
+"warning"
+"exist"
+"at"
+"file"
+"NOT\""
+"NOT,"
+"W3C/MIT"
+"ISO-8859-1:1987."
+"SHTTP/1.3,"
+"no"
+"when"
+"A,"
+"virtual"
+"A."
+"details."
+"application"
+"valid"
+"OPTIONAL"
+"\"TRACE\""
+"test"
+"MD5"
+"you"
+"TE"
+"ISO-8859-3,"
+"requested"
+"elements"
+"C)"
+"symbol"
+"T."
+"code)"
+"variable"
+"SOCIETY"
+"\"MUST"
+"TCP"
+"ISO-10646\","
+"NOT\","
+"R."
+"audio/basic"
+"IANA."
+"\"WAIS"
+"persistent"
+"Its"
+"As"
+"time"
+"failures"
+"\"ISO-8859-1\""
+"once"
+
diff --git a/chromium/net/data/fuzzer_dictionaries/net_mime_sniffer_fuzzer.dict b/chromium/net/data/fuzzer_dictionaries/net_mime_sniffer_fuzzer.dict
new file mode 100644
index 00000000000..2713b56fbae
--- /dev/null
+++ b/chromium/net/data/fuzzer_dictionaries/net_mime_sniffer_fuzzer.dict
@@ -0,0 +1,447 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Lines 7-299 of this file were generated with
+# testing/libfuzzer/dictionary_generator.py using net_mime_sniffer_fuzzer
+# binary and RFC 2045.
+# The rest was created semimanually based on net/base/mime_sniffer.cc.
+
+"all"
+"BASE64"
+"US-ASCII."
+"LESS"
+"being"
+"text"
+"supported"
+"\"C\""
+"TAB)"
+"X.400"
+"invalid"
+"EQUAL"
+"CRLF."
+"CRLF,"
+"A."
+"data"
+"its"
+"to"
+"before"
+"TO"
+"implementation"
+"true"
+"US-ASCII,"
+"0"
+"only"
+"internal"
+"TAB"
+"(US-ASCII)"
+"FORMATTING"
+"(A"
+"TILDE,"
+"US-ASCII"
+"(STD"
+"\"F\")"
+"V"
+"string"
+"get"
+"EXPRESSLY"
+"H"
+"L"
+"P"
+"T"
+"CONTENT-TYPE"
+"CONTENT-TRANSFER-"
+"not"
+"X"
+"D"
+"BNF"
+"ENCODING:"
+"name"
+"ON"
+"d"
+"success"
+"MAY"
+"\"=0D=0A\"."
+"bytes"
+"(RFC"
+"default"
+"ONLY"
+"RFC."
+"THE"
+"section"
+"\"0123456789ABCDEF\"."
+"ASCII"
+"*(CRLF"
+"A"
+"set"
+"NO)"
+"[RFC-821])"
+"\"=0D=0A\""
+"\"=0C\","
+"M."
+"some"
+"direct"
+"sign"
+"TEXT,"
+"\"A\""
+"are"
+"allowed."
+"\"X-\")"
+"MIME."
+"\"X-\","
+"event"
+"THAN,"
+"MUST"
+"for"
+"space"
+"+"
+"1*DIGIT"
+"/"
+"THAN"
+"may"
+"3"
+"version"
+"HISTORICAL"
+"MIME,"
+"probably"
+"CRLF)"
+"REQUIRES"
+"corruption"
+"IMPLEMENTORS:"
+"available"
+"be"
+"C"
+"G"
+"7BIT\""
+"This"
+"NO"
+"K"
+"NJ"
+"O"
+"(EXCLAMATION"
+"RFC"
+"1)"
+"[ATK],"
+"base"
+"STD"
+"ISO-8859-1"
+"W"
+"application/octet-stream"
+"\"=3D\"."
+"["
+"CA"
+"by"
+"AND"
+"on"
+"c"
+"NOTE:"
+"g"
+"of"
+"could"
+"POINT"
+"S"
+"times"
+"s"
+"MANDATORY"
+"NOT"
+"UA"
+"or"
+"CR,"
+"STRONGLY"
+"TAB,"
+"already"
+"useful"
+"*(SPACE"
+"No"
+"(MIME)"
+"number"
+"one"
+"CHAR"
+"RFC,"
+"\"=0D\""
+"because"
+"[RFC-821]),"
+"S."
+"EBCDIC."
+"[RFC-821]."
+"(SMTP)"
+"IMPORTANT:"
+"\"=0A=0D\""
+"use"
+"from"
+"USA"
+"&"
+"IETF"
+"transfer"
+"top"
+"(US-ASCII"
+"IANA"
+"long"
+"\"=0D\","
+"few"
+"2"
+"E"
+"expected"
+"type"
+">"
+"\"D\""
+"B"
+"N."
+"received"
+"[RFC-1741],"
+"completed"
+"J"
+"LF)"
+"SMTP.)"
+"but"
+"back"
+"warn"
+"R"
+"SIGN)"
+"CRLF"
+"EBCDIC"
+"BETWEEN"
+"CR"
+"line"
+"Z"
+"with"
+"unnecessarily"
+"must"
+"count"
+"(HT)"
+"GREATER"
+"16"
+"this"
+"was"
+"work"
+"value"
+"ISO-8859-1,"
+"while"
+"following"
+"IANA.>"
+"called"
+"(US-"
+"and"
+"(PEM)"
+"type."
+"UNIX"
+"RELATIONSHIP"
+"ENCODING"
+"\"E\""
+"attribute"
+"is"
+"allowed"
+"thus"
+"lost."
+"Virtual"
+"an"
+"high"
+"as"
+"MIME"
+"at"
+"have"
+"in"
+"need"
+"any"
+"contents"
+"native"
+"LF"
+"binary"
+"F"
+"\"X-\""
+"7BIT"
+"TX"
+"no"
+")"
+"FORBIDDEN"
+"2(DIGIT"
+"format"
+"when"
+"length"
+"mechanism"
+"j"
+"RESTRICTIONS:"
+"application"
+"that"
+"valid"
+"which"
+"="
+"LWSP"
+"profile"
+"ISO"
+"begin"
+"used"
+"multiple"
+"SPACE"
+"I"
+"SMTP"
+"after"
+"M"
+"\"B\""
+"Q"
+"U"
+"[X400]"
+"Y"
+"such"
+"The"
+"N"
+"]"
+"\"=0A\","
+"a"
+"short"
+"WARNING"
+"ALWAYS"
+"SPACE,"
+"NOTE"
+"As"
+"does"
+"<A"
+"the"
+"avoid"
+"If"
+"application/xhtml+xml"
+"<html xmlns=\"http://www.w3.org/1999/xhtml\""
+"application/atom+xml"
+"application/rss+xml"
+"<rss"
+"<feed"
+"\xFE\xFF"
+"\xFF\xFE"
+"\xEF\xBB\xBF"
+"unknown/unknown"
+"application/unknown"
+"*/*"
+"application/x-chrome-extension"
+"Cr24\x02\x00\x00\x00"
+"ftp"
+"content"
+"application/msword"
+"application/vnd.ms-excel"
+"application/vnd.ms-powerpoint"
+"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
+"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+"application/vnd.openxmlformats-officedocument.presentationml.presentation"
+"application/vnd.ms-excel.sheet.macroenabled.12"
+"application/vnd.ms-powerpoint.presentation.macroenabled.12"
+"application/mspowerpoint"
+"application/msexcel"
+"application/vnd.ms-word"
+"application/vnd.ms-word.document.12"
+"application/vnd.msword"
+"text/html"
+"text/xml"
+"application/xml"
+"CFB"
+"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
+"PK\x03\x04"
+"OOXML"
+"image/x-xbitmap"
+"#define"
+"image/x-icon"
+"\x00\x00\x01\x00"
+"image/svg+xml"
+"<?xml_version="
+"audio/wav"
+"RIFF....WAVEfmt "
+"video/avi"
+"RIFF....AVI LIST"
+"audio/ogg"
+"OggS"
+"video/mpeg"
+"\x00\x00\x01\xB0", "\xFF\xFF\xFF\xF0"
+"audio/mpeg"
+"\xFF\xE0", "\xFF\xE0"
+"....ftyp3g"
+"video/3gpp"
+"....ftypavcl"
+"video/mp4"
+"....ftyp"
+"video/quicktime"
+"....moov"
+"application/x-shockwave-flash"
+"CWS"
+"FWS"
+"video/x-flv"
+"FLV"
+"audio/x-flac"
+"fLaC"
+"image/x-canon-cr2"
+"II\x2a\x00\x10\x00\x00\x00CR"
+"image/x-canon-crw"
+"II\x1a\x00\x00\x00HEAPCCDR"
+"image/x-minolta-mrw"
+"\x00MRM"
+"MMOR"
+"IIRO"
+"image/x-olympus-orf"
+"IIRS"
+"image/x-fuji-raf"
+"FUJIFILMCCD-RAW"
+"image/x-panasonic-raw"
+"IIU\x00\x08\x00\x00\x00"
+"IIU\x00\x18\x00\x00\x00"
+"image/x-phaseone-raw"
+"MMMMRaw"
+"image/x-x3f"
+"FOVb"
+".doc"
+".xls"
+".docx"
+".ppt"
+".pptx"
+".xlsx"
+"<!DOCTYPE html>"
+"<script>"
+"<html>"
+"<!-->"
+"<head>"
+"<iframe>"
+"<h1>"
+"<div>"
+"<font>"
+"<table>"
+"<a>"
+"<style>"
+"<title>"
+"<b>"
+"<body>"
+"<br>"
+"<p>"
+"<?xml"
+"<!DOCTYPE"
+"application/pdf"
+"%PDF-"
+"application/postscript"
+"%!PS-Adobe-"
+"image/gif"
+"GIF87a"
+"GIF89a"
+"image/png"
+"\x89" "PNG\x0D\x0A\x1A\x0A"
+"image/jpeg"
+"\xFF\xD8\xFF"
+"image/bmp"
+"BM"
+"text/plain"
+"#!"
+"%!"
+"application/x-gzip"
+"\x1F\x8B\x08"
+"audio/x-pn-realaudio"
+"\x2E\x52\x4D\x46"
+"video/x-ms-asf"
+"image/tiff"
+"I I"
+"II*"
+"MM\x00*"
+"ID3"
+"image/webp"
+"RIFF....WEBPVP8 "
+"video/webm"
+"\x1A\x45\xDF\xA3"
+"application/zip"
+"application/x-rar-compressed"
+"Rar!\x1A\x07\x00"
+"application/x-msmetafile"
+"\xD7\xCD\xC6\x9A"
+"MZ"
diff --git a/chromium/net/data/fuzzer_dictionaries/net_parse_data_url_fuzzer.dict b/chromium/net/data/fuzzer_dictionaries/net_parse_data_url_fuzzer.dict
new file mode 100644
index 00000000000..1668f4cc752
--- /dev/null
+++ b/chromium/net/data/fuzzer_dictionaries/net_parse_data_url_fuzzer.dict
@@ -0,0 +1,449 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_parse_data_url_fuzzer binary and RFC 3986.
+"all"
+"DNS"
+"text"
+"labels"
+"DQUOTE"
+"\"%D3%81%87%A4%95%81@%C2%85%81%83%88\"."
+"[RFC2234]"
+"F.,"
+"FORCE"
+"SOCIETY"
+"\"%\""
+"with"
+"cache"
+"WINS,"
+"D.1."
+"0"
+"only"
+"HTML"
+"SPONSORED"
+"[RFC1630]."
+"D.,"
+"[RFC1123]"
+"US-ASCII"
+"(STD"
+"[RFC1808],"
+"string"
+"get"
+"=="
+"H"
+"HEREIN"
+"[BCP35]"
+"SP)"
+"SCTP)"
+"(NUL)"
+"THE"
+"(URI):"
+"REPRESENTS"
+"[RFC2732]."
+"resource"
+"A.,"
+"EXPRESS"
+"list"
+"(%2E),"
+"WILL"
+"HE/SHE"
+"J."
+"INCLUDING"
+"common"
+"segment."
+"[RFC2732]"
+"(URL)\","
+"set"
+"HTTP"
+"IANA"
+"INFORMATION"
+"(%41-%5A"
+"[RFC2518]"
+"M."
+"direct"
+"sign"
+"Only"
+"Version"
+"are"
+"allowed."
+"\"X\""
+"HTTP,"
+"(SP)."
+"2DIGIT"
+"section"
+"BUT"
+"\"UTF-8,"
+"3"
+"version"
+"[RFC1034]"
+"probably"
+"[UCS],"
+"metadata"
+"Y.,"
+"C"
+"WWW\""
+"parent"
+"0X"
+"W3C/IETF"
+"S"
+"key"
+"address"
+"INPUT"
+"["
+"P."
+"WWW:"
+"AND"
+"received"
+"WWW"
+"[BCP35]."
+"MA"
+"\"AS"
+"[RFC2718]."
+"(IDNA)\","
+"implementation"
+"TCP"
+"NOT"
+"(URN)"
+"ANY"
+"[RFC1808]"
+"WARRANTY"
+"useful"
+"[RFC1737]."
+"[STD63],"
+"\"HTTP\""
+"(MIME)"
+"TELNET"
+"[RFC1630]"
+"S."
+"D.2."
+"B.,"
+"[RFC2234]."
+"[RFC2234],"
+"BCP"
+"select"
+"[STD63];"
+"use"
+"LATIN"
+"from"
+"C."
+"to"
+"WARRANTIES"
+"(MHTML)\","
+"ENGINEERING"
+"URI;"
+"."
+"few"
+"(DNS)."
+"expected"
+"USENET"
+"type"
+"empty"
+"XML"
+"URL?\","
+"W3C/MIT"
+"F"
+"CA"
+"STD:"
+"SMTP"
+"[RFC2141],"
+"N"
+"A),"
+"flag"
+"NOTE:"
+"CR"
+"MHTML"
+"BY"
+"must"
+"ANY),"
+"ALL"
+"[STD63]"
+"RIGHTS"
+"this"
+"SP"
+"[BCP19]"
+"value"
+"INFRINGE"
+"while"
+"KATAKANA"
+"resources"
+"error"
+"following"
+"example"
+"loop"
+"J.,"
+"2E:"
+"type."
+"L."
+"have"
+"%61-%7A),"
+"is"
+"allowed"
+"thus"
+"URI,"
+"parse"
+"STEP"
+"MIME"
+"UTF-8"
+"in"
+"[RFC0952]."
+"native"
+"FOR"
+"binary"
+"ISO/IEC"
+"\"A"
+"(%5F),"
+")"
+"algorithm."
+"returning"
+"\"A\","
+"[RFC2141]"
+"BUFFER"
+"ABNF"
+"[RFC2557]."
+"I."
+"WARRANTIES,"
+"URN"
+"EBCDIC"
+"A"
+"LF"
+"used"
+"http"
+"I"
+"IP"
+"IS"
+"after"
+"L"
+"Q"
+"'A'"
+"running"
+"HEXDIG"
+"such"
+"EBCDIC,"
+"data"
+"TASK"
+"a"
+"task"
+"P"
+"[ASCII]."
+"M.,"
+"Names"
+"flag."
+"the"
+"If"
+"[RFC3490]"
+"US-ASCII."
+"2C:"
+"THAT"
+"being"
+"when"
+"E.,"
+"(%2D),"
+"\"URL:\""
+"mechanism"
+"WITH"
+"its"
+"before"
+"tables"
+"[UCS]"
+"TO"
+"BNF"
+"platform"
+"internal"
+"P.,"
+"ORGANIZATION"
+"\"HTTP"
+"URI."
+"it,"
+"D"
+"format"
+"URL"
+"S.,"
+"(0"
+"URI\""
+"URI"
+"K."
+"URI:"
+"T"
+"D.W."
+"not"
+"R."
+"LIMITED"
+"\"%3A\")"
+"name"
+"OF"
+"B."
+"[RFC1736]"
+"(R),"
+"IPR"
+"[RFC1738];"
+"OUTPUT"
+"LALR"
+"OR"
+"STD"
+"[RFC3513]"
+"because"
+"bytes"
+"DNS,"
+"some"
+"back"
+"(URI)"
+"*DIGIT"
+"[RFC2046]"
+"[RFC3305]"
+"\"%7E\""
+"W3C"
+"E."
+"for"
+"space"
+"ABNF\","
+"avoid"
+"[RFC1535]."
+"/"
+"increase"
+"may"
+"time."
+"does"
+"'F'"
+"[RFC2396]"
+"be"
+"K.,"
+"DISCLAIM"
+"G"
+"(UTF-16),"
+"This"
+"M"
+"INTERNET"
+"RFC"
+"X3.4,"
+"base"
+"(T):"
+"IMPLIED,"
+"by"
+"\"URL\""
+"on"
+"DIGIT"
+"(ABNF)"
+"WEBDAV\","
+"of"
+"could"
+"R.,"
+"(ABNF:"
+"failed"
+"or"
+"1*4HEXDIG"
+"already"
+"No"
+"CAPITAL"
+"number"
+"one"
+"ISO"
+"FITNESS"
+"message"
+"open"
+"ANSI"
+"[BCP19],"
+"\"%C3%80\","
+"IETF"
+"unknown"
+"support"
+"\"URN"
+"[RFC1123]."
+"long"
+"[RFC0952]"
+"[ASCII]"
+":"
+"was"
+"[RFC3513]."
+"[RFC2718]"
+"B"
+"N."
+"that"
+"IDNA"
+"OCTET"
+"but"
+"R"
+"POSIX"
+"LETTER"
+"CONTRIBUTOR,"
+"[RFC1738]"
+"line"
+"(C)"
+"true"
+"\"URI\""
+"PARTICULAR"
+"target"
+"16"
+"default"
+"double"
+"\"URN\""
+"[RFC2557]"
+"enabled"
+"up"
+"TCP,"
+"PURPOSE."
+"MERCHANTABILITY"
+"1)"
+"IS\""
+"\"IANA"
+"called"
+"multipart"
+"and"
+"USE"
+"false"
+"(IF"
+"USA"
+"URL,"
+"an"
+"To"
+"as"
+"(%7E)"
+"at"
+"file"
+"need"
+"any"
+"\"%E3%82%A2\"."
+"physical"
+"1*HEXDIG"
+"no"
+"[RFC1737]"
+"-"
+"invalid"
+"A."
+"application"
+"valid"
+"take"
+"which"
+"test"
+"[RFC2732],"
+"you"
+"="
+"GRAVE"
+"<URI>"
+"begin"
+"[RFC2396],"
+"multiple"
+"2B:"
+"period,"
+"UDP,"
+"[RFC1535]"
+"T."
+"(UCS)\","
+"U"
+"A-F."
+"T.,"
+"The"
+"]"
+"source"
+"D."
+"persistent"
+"traditional"
+"L.,"
+"As"
+"IMPLIED"
+"(URL)"
+"ALPHA"
+"[RFC3305]."
+"H.,"
+"\"MIME"
diff --git a/chromium/net/data/fuzzer_dictionaries/net_parse_proxy_bypass_rules_fuzzer.dict b/chromium/net/data/fuzzer_dictionaries/net_parse_proxy_bypass_rules_fuzzer.dict
new file mode 100644
index 00000000000..65c3f60f932
--- /dev/null
+++ b/chromium/net/data/fuzzer_dictionaries/net_parse_proxy_bypass_rules_fuzzer.dict
@@ -0,0 +1,9 @@
+"127.0.0.1"
+"[::1]"
+"<local>"
+"192.168.0.0/24"
+"/8"
+"/24"
+"/16"
+"http://"
+"https://0.0.0.0:8888/" \ No newline at end of file
diff --git a/chromium/net/data/fuzzer_dictionaries/net_url_request_fuzzer.dict b/chromium/net/data/fuzzer_dictionaries/net_url_request_fuzzer.dict
new file mode 100644
index 00000000000..742ae16ebf8
--- /dev/null
+++ b/chromium/net/data/fuzzer_dictionaries/net_url_request_fuzzer.dict
@@ -0,0 +1,1718 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Fuzzer dictionary targetting HTTP/1.x responses.
+
+# Entries that are generally useful in headers
+":"
+"\x0A"
+"\x0D"
+"0"
+"50"
+"500"
+# Horizontal whitespace. Matters mostly in status line.
+" "
+"\x09"
+# Header continuation
+"\x0D\x0A\x09"
+# Used in a lot of individual headers
+";"
+"="
+","
+"\""
+"-"
+
+# Status line components
+"HTTP"
+"/1.1"
+"/1.0"
+# More interesting status codes. Leading space so can be inserted into
+# other status lines.
+" 100"
+" 200"
+" 206"
+" 301"
+" 302"
+" 303"
+" 304"
+" 307"
+" 308"
+" 401"
+" 403"
+" 404"
+" 500"
+" 501"
+" 403"
+
+# Full status lines (Some with relevant following headers)
+"HTTP/1.1 200 OK\x0A\x0A"
+"HTTP/1.1 100 Continue\x0A\x0A"
+"HTTP/1.1 401 Unauthorized\x0AWWW-Authenticate: Basic realm=\"Middle-Earth\"\x0A\xA0"
+"HTTP/1.1 407 Proxy Authentication Required\x0AProxy-Authenticate: Digest realm=\"Middle-Earth\", nonce=\"aaaaaaaaaa\"\x0A\x0A"
+"HTTP/1.0 301 Moved Permanently\x0ALocation: /a\x0A\x0A"
+"HTTP/1.1 302 Found\x0ALocation: http://lost/\x0A\x0A"
+
+# Proxy authentication headers. Note that fuzzers don't support NTLM or
+# negotiate.
+"WWW-Authenticate:"
+"Proxy-Authenticate:"
+"Basic"
+"Digest"
+"realm"
+"nonce"
+
+"Connection:"
+"Proxy-Connection:"
+"Keep-Alive"
+"Close"
+"Upgrade"
+"\x0AConnection: Keep-Alive"
+"\x0AConnection: Close"
+"\x0AProxy-Connection: Keep-Alive"
+"\x0AProxy-Connection: Close"
+
+"Content-Length:"
+"Transfer-Encoding:"
+"chunked"
+"\x0AContent-Length: 0"
+"\x0AContent-Length: 500"
+"\x0ATransfer-Encoding: chunked\x0A\x0A5\x0A12345\x0A0\x0A\x0A"
+
+"Location:"
+"\x0ALocation: http://foo/"
+"\x0ALocation: http://bar/"
+"\x0ALocation: https://foo/"
+"\x0ALocation: https://bar/"
+
+"Accept-Ranges:"
+"bytes"
+"\x0AAccept-Ranges: bytes"
+
+"Content-Range:"
+
+"Age:"
+"\x0AAge: 0"
+"\x0AAge: 3153600000"
+
+"Cache-Control:"
+"max-age"
+"no-cache"
+"no-store"
+"must-revalidate"
+"\x0ACache-Control: max-age=3153600000"
+"\x0ACache-Control: max-age=0"
+"\x0ACache-Control: no-cache"
+"\x0ACache-Control: no-store"
+"\x0ACache-Control: must-revalidate"
+
+"Content-Disposition:"
+"attachment"
+"filename"
+
+"Content-Encoding:"
+"gzip"
+"deflate"
+"sdch"
+"br"
+"\x0AContent-Encoding: gzip"
+"\x0AContent-Encoding: deflate"
+"\x0AContent-Encoding: sdch"
+"\x0AContent-Encoding: br"
+
+"Date:"
+"Fri, 01 Apr, 2050 14:14:14 GMT"
+"Mon, 28 Mar, 2016 04:04:04 GMT"
+"\x0ADate: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0ADate: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Last-Modified:"
+"\x0ALast-Modified: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0ALast-Modified: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Expires:"
+"\x0AExpires: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0AExpires: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Set-Cookie:"
+"Expires"
+"Max-Age"
+"Domain"
+"Path"
+"Secure"
+"HttpOnly"
+"Priority"
+"Low"
+"Medium"
+"High"
+"SameSite"
+"Strict"
+"Lax"
+"\x0ASet-Cookie: foo=bar"
+"\x0ASet-Cookie: foo2=bar2;HttpOnly;Priority=Low;SameSite=Strict;Path=/"
+"\x0ASet-Cookie: foo=chicken;SameSite=Lax"
+
+"Strict-Transport-Security:"
+"includeSubDomains"
+
+"Vary:"
+"\x0AVary: Cookie"
+"\x0AVary: Age"
+
+"ETag:"
+"\x0AETag: jumboshrimp"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_url_request_fuzzer binary and RFC 3986.
+"all"
+"consider"
+"Transfer-Encoding"
+"D.,"
+"prefix"
+"concept"
+"CR"
+"follow"
+"RFC-850"
+"(which"
+"ISDN"
+"\"TE\""
+"increase"
+"number"
+"calculate"
+"\"IETF"
+"fixed-length"
+"\"OPTIONAL\""
+"to"
+"Host"
+"program"
+"Western"
+"under"
+"Changing"
+"(STD"
+"digit"
+"returned"
+"returning"
+"very"
+"SP,"
+"SP."
+"Validation"
+"(URI):"
+"Incomplete"
+"Origin"
+"--"
+"cause"
+"EXPRESS"
+"list"
+"large"
+"expired."
+"small"
+"(URL)\","
+"range."
+"past"
+"second"
+"Version"
+"allowed."
+"tag."
+"implemented"
+"canonical"
+"even"
+"established"
+"errors"
+"incompatible"
+"section"
+"contributed"
+"while"
+"decoding"
+"version"
+"above"
+"TTL"
+"new"
+"increasing"
+"method"
+"WWW-"
+"never"
+"equals"
+"here"
+"ranges"
+"reported"
+"compressed"
+"active"
+"path"
+"strong"
+"Index"
+"changed"
+"DISCLAIMS"
+"prior"
+"amount"
+"published"
+"NOT"
+"error,"
+"options"
+"via"
+"followed"
+"secure"
+"family"
+"\"HTTP\""
+"Unspecified"
+"replace"
+"CERN/3.0"
+"CTE"
+"(CTE)"
+"TO"
+"Too"
+"CTL"
+"PUT,"
+"total"
+"PUT)"
+"Security"
+"select"
+"languages"
+"TASK"
+"exception."
+"would"
+"contains"
+"negative"
+"User-Agent"
+"call"
+"MUST,"
+"type"
+"until"
+"authorization"
+"more"
+"ISO-8859-9,"
+"initiated"
+"composite"
+"LF,"
+"line"
+"it"
+"warn"
+"American"
+"varying"
+"known"
+"Found"
+"MHTML"
+"must"
+"parse"
+"none"
+"1999"
+"work"
+"paragraph"
+"sent"
+"evolved"
+"root"
+"example"
+"requested,"
+"history"
+"type."
+"(HTCPCP/1.0)\","
+"accept"
+"currency"
+"minimum"
+"Compromise"
+"numbers"
+"want"
+"type:"
+"times"
+"simple"
+"LF"
+"information"
+"needs"
+"end"
+"goal"
+"verify"
+"far"
+"Pragma"
+"reject"
+"A"
+"badly"
+"HEAD"
+"description"
+"number."
+"insecure"
+"after"
+"variant"
+"confirmed"
+"reflect"
+"wrong"
+"law"
+"response"
+"types"
+"a"
+"All"
+"short"
+"attempt"
+"third"
+"menu."
+")"
+"algorithms"
+"cases."
+"File"
+"\"DEFLATE"
+"order"
+"\"SHOULD"
+"help"
+"don't"
+"over"
+"vary"
+"satisfied"
+"CD-ROM,"
+"held"
+"HTTP-WG."
+"through"
+"of,"
+"existence"
+"its"
+"digest"
+"before"
+"difference"
+"20"
+"termed"
+"MAY,"
+"fix"
+"ISO-3166"
+"actually"
+"407"
+"(GNU"
+"absence"
+"\"HTTP/1.1\","
+"Sun,"
+"MERCHANTABILITY"
+"408"
+"it."
+"them"
+"good"
+"return"
+"HTTP/2.4"
+"combination"
+"URL"
+"URI"
+"Due"
+"Bad"
+"they"
+"Control"
+"always"
+"decimal"
+"refresh"
+"expectation."
+"MAY"
+"token"
+"]URI,"
+"[CRLF]"
+"found"
+"Content-Type"
+"ports"
+"trailer"
+"referred"
+"status"
+"weight"
+"series"
+"reduce"
+"(URI)"
+"expect"
+"max-age=0"
+"combining"
+"operation"
+"beyond"
+"Type"
+"event"
+"is:"
+"by"
+"E."
+"network"
+"Server:"
+"open"
+"\"MUST/MAY/SHOULD\""
+"since"
+"request/response"
+"content"
+"message."
+"PATCH,"
+"7"
+"2DIGIT"
+"available."
+"K.,"
+"linear"
+"Extension"
+"University"
+"enclosing"
+"free"
+"reason"
+"base"
+"proxy"
+"POST"
+"beginning"
+"generate"
+"text/plain"
+"definition"
+"perform"
+"Partial"
+"created"
+"UPALPHA"
+"script"
+"\"GMT\""
+"filter"
+"SSL"
+"expecting"
+"If-Modified-Since"
+"HEAD."
+"HEAD,"
+"assign"
+"user"
+"major"
+"already"
+"Copyright"
+"encoding"
+"Cache"
+"Please"
+"token."
+"TCP"
+"content-range"
+"least"
+"another"
+"FITNESS"
+"invalid."
+"\""
+"service"
+"image/gif"
+"top"
+"header)"
+"construct"
+"2"
+"ignored."
+"listed"
+"passed"
+"Delta"
+"LOALPHA"
+"scheme"
+"store"
+"too"
+"M."
+"immediate"
+"direct"
+"tokens"
+"part"
+"WAIS"
+"F.,"
+"to:"
+"distance"
+"Code"
+"target"
+"Content-Type:"
+"zero,"
+"likely"
+"WWW-Authenticate"
+"matter"
+"idle"
+"determined"
+"stale"
+"ISO-8859-8,"
+"payload"
+"ANSI"
+"B"
+"seen"
+"HTTP/1.1.)"
+"null"
+"OPTIONS"
+"contents"
+"paths"
+"data."
+"data)"
+"zero"
+"depending"
+"Acceptable"
+"responsible"
+"(MIME"
+"also"
+"internal"
+"(C)"
+"build"
+"finding"
+"With"
+"UCI"
+"Names"
+"content-"
+"added"
+"headers."
+"Content-Disposition"
+"object"
+"\"MUST\","
+"most"
+"regular"
+"ensure"
+"letter"
+"2*N"
+"services"
+"The"
+"Responses"
+"payload."
+"clear"
+"sometimes"
+"flow"
+"Client"
+"ISO-8859-3,"
+"Its"
+"incomplete"
+"\"MIME"
+"Note:"
+"particularly"
+"labels"
+"\"C\""
+"session"
+"Unrecognized"
+"find"
+"]"
+"implementation"
+"[RFC"
+"ranges."
+"BNF,"
+"user-agent"
+"failed"
+"URL)."
+"LDAP)"
+"8"
+"US-ASCII"
+"do"
+"hit"
+"stop"
+"\"HTTP\"."
+"While"
+"Set"
+"rest"
+"report"
+"during"
+"body,"
+"PUT"
+"(via"
+"public"
+"twice"
+"bad"
+"common"
+"release"
+"require"
+"set"
+"mandatory"
+"reference"
+"\"F\""
+"MIME:"
+"depends"
+"individual"
+"result"
+"J."
+"close"
+"subject"
+"said"
+"headers"
+"WWW\","
+"See"
+"BUT"
+"unable"
+"various"
+"probably"
+"0)"
+"0."
+"0,"
+"discovery"
+"available"
+"we"
+"reasons."
+"terms"
+"missing"
+"Server"
+"(MIME)"
+"OPTIONAL;"
+"AND"
+"both"
+"protect"
+"Unexpected"
+"last"
+"reverse"
+"\"MAY\","
+"*TEXT"
+"against"
+"connection"
+"became"
+"context"
+"exceeds"
+"however,"
+"mean"
+"reached."
+"finds"
+"experimental"
+"load"
+"Redirect"
+"Content-Length"
+"alternate"
+"consume"
+"point"
+"reasons"
+"had"
+"header"
+"DNS)"
+"DNS."
+"B.,"
+"(O)."
+"1.0"
+"throughout"
+"BCP"
+"["
+"application/pdf"
+"\"REQUIRED\","
+"C."
+"basis"
+"\"POST\""
+"create"
+"acceptance"
+"(MHTML)\","
+"Reason"
+"been"
+"."
+"much"
+"\"PUT\""
+"basic"
+"expected"
+"text/html;"
+"empty"
+"HTTP/1.0"
+"concerning"
+"Flow"
+"N"
+"size,"
+"\"W/\""
+"reason."
+"MA"
+"\"DELETE\""
+"unnecessarily"
+"exception"
+"handling"
+"Group,"
+"particular,"
+"technical"
+"near"
+"\"GZIP"
+"error"
+"(IANA)"
+"\"TRACE\""
+"Accept-Language"
+"played"
+"is"
+"herein"
+"encountered"
+"E-mail"
+"MIME"
+"in"
+"accepted."
+"if"
+"containing"
+"\"A"
+"lengths"
+"make"
+"format"
+"\"I"
+"unrecognized"
+"widely"
+"9"
+"several"
+"higher"
+"\"%"
+"used"
+"temporary"
+"alert"
+"action"
+"purpose"
+"characters"
+"stack"
+"recent"
+"lower"
+"task"
+"database"
+"NNTP"
+"failing"
+"person"
+"client"
+"length."
+"entry"
+"the"
+"left"
+"protocol"
+"US-ASCII."
+"THAT"
+"bandwidth"
+"inactive"
+"(TE)"
+"Internet"
+"HTTP/1.0)"
+"HTTP/1.0."
+"previous"
+"tables"
+"unique"
+"case."
+"character"
+"Trailers"
+"source"
+"ISO-8859-2,"
+"subjects"
+"WILL"
+"location"
+"0*3DIGIT"
+"input"
+"save"
+"remaining"
+"URI."
+"URI,"
+"fact,"
+"transfer-encoding"
+"possible"
+"required."
+"Assigned"
+"Length"
+"URI;"
+"integer"
+"bit"
+"Sat,"
+"desire"
+"OK"
+"success"
+"ISO-8859-5,"
+"OF"
+"signal"
+"INFRINGE"
+"H.F.,"
+"specific"
+"X3.4-1986"
+"security"
+"OR"
+"S."
+"right"
+"old"
+"often"
+"deal"
+"people"
+"successfully"
+"some"
+"back"
+"HT"
+"Last-Modified"
+"headers)"
+"DEL"
+"examples"
+"unless"
+"(BNF)"
+"TCP/IP"
+"ignore"
+"PUT."
+"INDEX."
+"headers,"
+"for"
+"track"
+"CONNECT"
+"be"
+"replaced"
+"run"
+"deleted"
+"example,"
+"<URL:"
+"O"
+"last-modified"
+"become"
+"relating"
+"permitted"
+"ALPHA,"
+"First"
+"ENGINEERING"
+"anything"
+"tracing"
+"\"UTF-8,"
+"*<TEXT,"
+"range"
+"3ALPHA"
+"extensions"
+"positive"
+"block"
+"IRC/6.9,"
+"W3C/MIT"
+"into"
+"within"
+"ACM"
+"two"
+"down"
+"file."
+"compression"
+"IETF"
+"expired"
+"support"
+"initial"
+"question"
+"long"
+"User"
+"HT."
+"forward"
+"version."
+"sections"
+"disallowed"
+"lowest"
+"HT,"
+"an"
+"form"
+"attempted"
+"registered"
+"differences"
+"URL."
+"failure"
+"server."
+"link"
+"CRLF"
+"DNS"
+"encoded"
+"Non-Authoritative"
+"true"
+"GMT"
+"reset"
+"consist"
+"versions"
+"used,"
+"maximum"
+"us"
+"used."
+"If-None-Match"
+"HTML\","
+"similar"
+"called"
+"delete"
+"DELETE,"
+"storing"
+"associated"
+"Introduction"
+"request"
+"specified"
+"influence"
+"To"
+"single"
+"warning"
+"exist"
+"New"
+"NOT,"
+"check"
+"ISO-8859-1:1987."
+"encrypt"
+"Only"
+"no"
+"May"
+"when"
+"A,"
+"invalid"
+"A."
+"MHTML,"
+"name."
+"setting"
+"role"
+"Proxy"
+"test"
+"TE"
+"pseudonym"
+"negotiation."
+"exceeded"
+"update"
+"T."
+"variable"
+"NOT\","
+"R."
+"longer"
+"algorithm"
+"IANA."
+"age"
+"packets"
+"together"
+"An"
+"As"
+"time"
+"failures"
+"requires"
+"avoid"
+"code."
+"once"
+"code"
+"partial"
+"chain"
+"TEXT"
+"results"
+"existing"
+"go"
+"(LZW)."
+"provided."
+"CPU"
+"CREATE"
+"Notice"
+"LF>"
+"\"HEAD\""
+"zone"
+"UNIX,"
+"ARPA"
+"send"
+"Standard"
+"environment"
+"USENET"
+"Not"
+"Nov"
+"include"
+"resources"
+"string"
+"advantage"
+"outside"
+"Explicit"
+"ALL"
+"HTTP/1.1;"
+"entries"
+"HTTP/1.1,"
+"HTTP/1.1."
+"entire"
+"Protocol"
+"level"
+"did"
+"button"
+"HTTP/1.0\","
+"(RFC"
+"try"
+"ONLY"
+"Tag"
+"(LWS"
+"\"SHOULD\","
+"prevent"
+"\"A\"..\"Z\">"
+"unexpected"
+"INFORMATION"
+"Failed"
+"\"A\""
+"Satisfiable"
+"port"
+"append"
+"\"HTTP/1.0\""
+"formats"
+"ISO-8859-4,"
+"appear"
+"rate"
+"opaque"
+"current"
+"waiting"
+"HTML"
+"shared"
+"CRLF)"
+"302"
+"body"
+"FTP"
+"NNTP."
+"\"SHALL"
+"following"
+"objects"
+"address"
+"1*HEX"
+"Distribution"
+"entry."
+"HTTP."
+"change"
+"cache)"
+"incoming"
+"\"AS"
+"receive"
+"larger"
+"host"
+"descended"
+"here."
+"+"
+"{"
+"makes"
+"composed"
+"named"
+"useful"
+"addresses"
+"extra"
+"detected."
+"When"
+"private"
+"session."
+"gateway"
+"Status"
+"use"
+"from"
+"stream"
+"working"
+"value."
+"next"
+"few"
+"--THIS_STRING_SEPARATES"
+"POST,"
+"memory"
+"scope"
+"means"
+"HEX\""
+"(GMT),"
+"bytes:"
+"Default"
+"Require"
+"Required"
+"DIGIT"
+"validity"
+"bytes,"
+"Connection"
+"Time"
+"cases"
+"name:"
+"behalf"
+"MD5"
+"lowercase"
+"RIGHTS"
+"this"
+"NTP"
+"--THIS_STRING_SEPARATES--"
+"Syntax"
+"values"
+"can"
+"believed"
+"making"
+"closing"
+"modifier"
+"J.,"
+"control"
+"reserved"
+"links"
+"process"
+"attribute"
+"high"
+"tag"
+"allowed"
+"Policy"
+"input,"
+"native"
+"class,"
+"Missing"
+"HTTP-"
+"HTTP,"
+"charset"
+"delay"
+"located"
+"R.,"
+"instead"
+"1XX"
+"WARRANTIES,"
+"parameter"
+"FORCE"
+"STD"
+"may"
+"Request"
+"British"
+"HEREIN"
+"Roman"
+"client's"
+"[SP"
+"ANSI,"
+"date"
+"such"
+"data"
+"HTTP/1.1\","
+"Y."
+"UA"
+"revalidate"
+"element"
+"so"
+"allow"
+"(LWS)"
+"holds"
+"move"
+"years"
+"including"
+"LINK,"
+"still"
+"pointer"
+"non-zero"
+"1"
+"negotiated"
+"Multiple"
+"line."
+"using:"
+"forms"
+"Referer"
+"P.,"
+"PNG,\""
+"cache-control"
+"policy"
+"mail"
+"\"HTTP"
+"SIGCOMM"
+"greater"
+"matches"
+"lesser"
+"not"
+"parsing"
+"matched"
+"term"
+"name"
+"establishment"
+"A.,"
+"ISO-639"
+"entirely"
+"identifier"
+"elements"
+"|"
+"successful"
+"domain"
+"From"
+"Network"
+"related"
+"UNLINK"
+"trying"
+"(LZ77)"
+"year"
+"(MIC)"
+"Parameter"
+"special"
+"out"
+"ultimately"
+"space"
+"REQUIRED"
+"416"
+"WARRANTY"
+"4DIGIT"
+"time,"
+"L."
+"time."
+"supports"
+"(A,"
+"state"
+"This"
+"derived"
+"INTERNET"
+"possibility"
+"\"B\""
+"RFC"
+"IMPLIED,"
+"byte"
+"received."
+"log"
+"ISO-8859-7,"
+"\"HTTP/1.1\""
+"language"
+"could"
+"transition"
+"programming"
+"tries"
+"keep"
+"length"
+"place"
+"S.,"
+"first"
+"origin"
+"there"
+"sent."
+"3DIGIT"
+"K."
+"one"
+"CHAR"
+"list,"
+"ISI"
+"version:"
+"message"
+"CSS1,"
+"quality"
+"size"
+"doesn't"
+"given"
+"For"
+"enabled."
+"unknown"
+"system"
+"unspecified"
+"parallel"
+"priority"
+"their"
+"attack"
+"intermediate"
+"HTTP:"
+"Date"
+"x-gzip"
+"Data"
+"Response"
+"HTTP/2.0,"
+"gives"
+"Success"
+"that"
+"completed"
+"exactly"
+"R"
+"pragma"
+"(IANA"
+"copy"
+"than"
+"History"
+"wide"
+"12"
+"14"
+"16"
+"was"
+"Universal"
+"protected"
+"servers."
+"were"
+"1)"
+"IS\""
+"SHTTP/1.3,"
+"1*8ALPHA"
+"Location"
+"and"
+"Information"
+"false"
+"1.1"
+"1.2"
+"(2**N),"
+"turned"
+"Tue,"
+"Other"
+"SP"
+"(LWS)."
+"have"
+"MIME,"
+"need"
+"Mail"
+"any"
+"Requested"
+"conversion"
+"HTTP/2.13,"
+"database."
+"After"
+"able"
+"mechanism"
+"OPTIONAL"
+"take"
+"which"
+"HTTP/0.9,"
+"201"
+"200"
+"begin"
+"multiple"
+"Name"
+"trace"
+"206"
+"buffer"
+"who"
+"connected"
+"plus"
+"HTTP/12.3."
+"\"OPTIONS\""
+"segment"
+"class"
+"D."
+"considered"
+"GET"
+"Some"
+"TE:"
+"L.,"
+"(URL)"
+"}"
+"fact"
+"Web"
+"WA"
+"violation"
+"text"
+"supported"
+"synchronous"
+"Authentication"
+"inconsistent"
+"CRLF."
+"CRLF,"
+"label"
+"Public"
+"MUST"
+"true,"
+"cache."
+"upgrade"
+"based"
+"Posting"
+"("
+"cache"
+"3"
+"should"
+"only"
+"Proxy-Authorization"
+"Byte"
+"Strong"
+"local"
+"MIC"
+"WARRANTIES"
+"(UA)"
+"<US-ASCII"
+"handle"
+"get"
+"E.,"
+"Accept-Ranges"
+"expectation"
+"(See"
+"cannot"
+"128"
+"THE"
+"conjunction"
+"BNF"
+"DIGIT,"
+"closure"
+"resource"
+"ended"
+"cached"
+"W."
+"ISO-8859."
+"calling"
+"INCLUDING"
+"contain"
+"ISI/RR-98-463,"
+"\"CONNECT\""
+"where"
+"ignored"
+"IANA"
+"exists"
+"configured"
+"C"
+"packet"
+"up"
+"relative"
+"multipart"
+"end."
+"detect"
+"has"
+"stream."
+"1*DIGIT"
+"Oct"
+"written"
+"LIMITED"
+"closed"
+"between"
+"boundary"
+"reading"
+"across"
+"\"RECOMMENDED\","
+"Body"
+"ability"
+"FOR"
+"opening"
+"importance"
+"screen"
+"connection."
+"ISO-8859-1"
+"UNIX"
+"key"
+"group"
+"configuration"
+"P."
+"valid"
+"\"HTTP/1.1\"."
+"HTTP/1.0),"
+"WWW"
+"revoked"
+"TRACE"
+"many"
+"taking"
+"(OK)"
+"equal"
+"Rules"
+"(0)"
+"Unicode"
+"*OCTET"
+"(URN)"
+"safely"
+"can't"
+"among"
+"(OK)."
+"Log"
+"period"
+"colon"
+"adding"
+"spans"
+"article"
+"table"
+"allocated"
+"LWS:"
+"Identifier"
+"Wed,"
+"USA"
+"Proxy-Authenticate"
+"encryption"
+"Jun"
+"copies"
+"But"
+"mark"
+"defined"
+"combined"
+"LWS,"
+"LWS"
+"prototype"
+">"
+"enable"
+"401"
+"content-disposition"
+"received"
+"unsafe"
+"SMTP"
+"ANY"
+"World"
+"chain."
+"case"
+"disconnected"
+"(HTTP)"
+"these"
+"Number"
+"value"
+"will"
+"Fri,"
+"\"SHALL\","
+"Any"
+"Additional"
+"resident"
+"NOT\""
+"thus"
+"it,"
+"according"
+"Content"
+"Content-Range"
+"properties"
+"Unsupported"
+"malformed"
+"PARTICULAR"
+"You"
+"binary"
+"different"
+"perhaps"
+"generic"
+"pay"
+"set."
+"00:00:00"
+"1DIGIT"
+"same"
+"parts"
+"largest"
+"units"
+"document"
+"Types"
+"residing"
+"breakdown"
+"UTC"
+"extended"
+"http"
+"I"
+"IP"
+"effect"
+"allocation"
+"running"
+"*LWS"
+"infinite"
+"frequently"
+"tracking"
+"undefined"
+"CR."
+"well"
+"It"
+"If-Range"
+"patterns"
+"without"
+"M.,"
+"CR,"
+"In"
+"position"
+"model"
+"audio"
+"If"
+"negotiation"
+"Also,"
+"Service"
+"less"
+"being"
+"generally"
+"obtain"
+"actions"
+"Access"
+"stored"
+"CRC."
+"However,"
+"application"
+"capabilities"
+"appeared"
+"add"
+"Thu,"
+"4"
+"Although"
+"HTTP/1.1"
+"usage"
+"(A"
+"match"
+"details"
+"tests"
+"aspects"
+"read"
+"Many"
+"H.,"
+"early"
+"action,"
+"T"
+"address."
+"using"
+"password"
+"loss"
+"like"
+"text/html"
+"Content-Encoding"
+"B,"
+"B."
+"\"HTTP/1.1"
+"server"
+"discarded"
+"either"
+"BACK)"
+"output"
+"Operation"
+"page"
+"\"GET\""
+"exceed"
+"because"
+"sequence"
+"uppercase"
+"Since"
+"growth"
+"Authority"
+"respect"
+"International"
+"recognition"
+"happens"
+"provided"
+"trust"
+"lead"
+"MIT"
+"highest"
+"expectation,"
+"does"
+"Authorization"
+"assuming"
+"refer"
+"GET)"
+"GET,"
+"GET."
+"equivalent"
+"Official"
+"C)"
+"ISO-8859-1."
+"broken"
+"Range"
+"HTTP/1.0,"
+"LWS>"
+"X3.4-1986,"
+"Microsoft"
+"on"
+"about"
+"actual"
+"extension"
+"of"
+"C,"
+"accepted"
+"FTP,"
+"compatible"
+"addition"
+"unidirectional"
+"Message"
+"DELETE"
+"content-type"
+"or"
+"UC"
+"final"
+"No"
+"ISO-"
+"image"
+"Two"
+"Internal"
+"times,"
+"ISO-8859-6,"
+"determine"
+"T.,"
+"operator"
+"T/TCP"
+"additional"
+"area"
+"GET\""
+"transfer"
+"*"
+"decode"
+"start"
+"describes"
+"low"
+"strict"
+"context."
+"function"
+"complete"
+"N."
+"enough"
+"OCTET"
+"but"
+"IMPLIED"
+"Error"
+"Dec"
+"with"
+"Trailer"
+"count"
+"clients."
+"made"
+"compute"
+"default"
+"GMT,"
+"ISO-8859-1,"
+"Moved"
+"this,"
+"ISO-8859-1)"
+"SHOULD"
+"PURPOSE."
+"limit"
+"GMT."
+"site"
+"problem"
+"define"
+"USE"
+"image/jpeg"
+"\"E\""
+"URL,"
+"describe"
+"general"
+"as"
+"UST"
+"at"
+"file"
+"lifetime"
+"are"
+"Accept-Encoding"
+"incorrect"
+"variety"
+"\"D\""
+"virtual"
+"details."
+"field"
+"other"
+"5"
+"Purpose"
+"you"
+"CA"
+"requested"
+"repeat"
+"HEX"
+"symbol"
+"Cache-Control"
+"Remove"
+"March"
+"important"
+"H."
+"code)"
+"included"
+"SOCIETY"
+"\"MUST"
+"ISO-10646\","
+"\"ZLIB"
+"audio/basic"
+"\"ISO-8859-1\""
+"\"WAIS"
+"persistent"
+"having"
+"directory"
+"ALPHA"
+"validation"
+"original"
+
diff --git a/chromium/net/data/fuzzer_dictionaries/net_websocket_extension_parser_fuzzer.dict b/chromium/net/data/fuzzer_dictionaries/net_websocket_extension_parser_fuzzer.dict
new file mode 100644
index 00000000000..a25f4819576
--- /dev/null
+++ b/chromium/net/data/fuzzer_dictionaries/net_websocket_extension_parser_fuzzer.dict
@@ -0,0 +1,30 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+";"
+"="
+"\""
+" "
+"\x08"
+"\x0A"
+"\x00"
+"\\"
+"()<>@,;:\\\"/[]?={} \x09"
+"permessage-deflate"
+"server_no_context_takeover"
+"client_no_context_takeover"
+"server_max_window_bits"
+"client_max_window_bits"
+"1"
+"5"
+"6"
+"7"
+"8"
+"9"
+"10"
+"11"
+"12"
+"13"
+"14"
+"15"
diff --git a/chromium/net/data/fuzzer_dictionaries/net_websocket_frame_parser_fuzzer.dict b/chromium/net/data/fuzzer_dictionaries/net_websocket_frame_parser_fuzzer.dict
new file mode 100644
index 00000000000..afba1606166
--- /dev/null
+++ b/chromium/net/data/fuzzer_dictionaries/net_websocket_frame_parser_fuzzer.dict
@@ -0,0 +1,460 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_websocket_frame_parser_fuzzer binary and RFC 6455.
+"WG"
+"all"
+"LETTER"
+"(\"MUST\","
+"Unknown"
+"supported"
+"|K|"
+"[WSAPI],"
+"[TALKING]."
+"\"UTF-8,"
+"[RFC6265]"
+"[FIPS.180-3],"
+"F.,"
+"T."
+"U+007A"
+"\"IETF"
+"implementation"
+"("
+"cache"
+"\"OPTIONAL\""
+"environment"
+"0"
+"only"
+"version"
+"G.,"
+"text"
+"G."
+"[RFC3987])."
+"string"
+"get"
+"=="
+"failed."
+"[RFC3986]."
+"(2MSL),"
+"|F|R|R|R|"
+"DIGIT)"
+"FIN"
+"(URI):"
+"SHA-1"
+"resource"
+"MAY"
+"EXAMPLE:"
+"list"
+"SYN"
+"large"
+"A.5"
+"J."
+"common"
+"RSV3:"
+"\"RECOMMENDED\","
+"ASCII"
+"(IP"
+"Y.,"
+"set"
+"HTTP"
+"IANA"
+"frame"
+"M."
+"direct"
+"this,"
+"Version"
+"are"
+"[RFC4086]"
+"GET,"
+"UTF-8-"
+"_ASCII_"
+"TLS,"
+"TLS."
+"Z)"
+"GET"
+"section"
+"[RFC3986]:"
+"TCP"
+"ABNF."
+"unable"
+"probably"
+"MUST"
+"[RFC3986],"
+"metadata"
+"available"
+"R.,"
+"C"
+"hash"
+"\"SHALL"
+"U+007E"
+"\"HTTP/1.1"
+"\"MAY\","
+"CONNECTING"
+"_ASCII"
+"key"
+"address"
+"OPTIONAL;"
+"["
+"P."
+"received"
+"NOTE:"
+"RSV1,"
+"WHATWG"
+"\"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\""
+"(IETF)"
+"IMPLEMENTATION"
+"|I|S|S|S|"
+"CLOSED"
+"NOT"
+"[RFC3629]."
+"J.,"
+"UTF-8."
+"\"REQUIRED\","
+"useful"
+"SHUT_WR"
+"(IETF)."
+"H."
+"HTTP)."
+"S."
+"ASCII)"
+"allocated"
+"poll"
+"BCP"
+"select"
+"[RFC4270])."
+"use"
+"LATIN"
+"from"
+"C."
+"certificate"
+"to"
+"\"SOCKS"
+"create"
+"S.,"
+"|N|V|V|V|"
+"[RFC2616]"
+"(IRI)"
+"call"
+"memory"
+"expected"
+"type"
+"empty"
+"with"
+"[RFC2616]."
+"OPEN"
+"[RFC4648]"
+"BNF"
+"NOT\","
+"[RFC2119]"
+"flag"
+"[RFC4270]"
+"TCP."
+"[RFC2616],"
+"\"258EAFA5-E914-47DA-"
+"CLOSING"
+"unnecessarily"
+"must"
+"high"
+"[RFC3864]."
+"ANSI"
+"this"
+"work"
+"value"
+"while"
+"\"SHALL\","
+"error"
+"following"
+"closing"
+"(NZDIGIT"
+"UTF-8"
+"type."
+"(UUID)"
+"is"
+"in"
+"thus"
+"Invalid"
+"parse"
+"key."
+"allowed"
+"Z)."
+"TLS.)"
+"failed"
+"|A|"
+"binary"
+"\"A"
+"[RFC5226]"
+")"
+"algorithm."
+"returning"
+"ISSN:"
+"U+0041"
+"write"
+"[RFC5234]"
+"I."
+"units"
+"[RFC4122]"
+"[WSAPI]"
+"URN"
+"A"
+"used"
+"XOR"
+"HTML"
+"[RFC1928]"
+"may"
+"IP"
+"after"
+"(TLS)"
+"H.,"
+"IRI"
+"running"
+"*LWS"
+"HTTPS"
+"CAPITAL"
+"SMTP"
+"such"
+"data"
+"a"
+"length:"
+"[ANSI.X3-4.1986]"
+"tracking"
+"[RFC6265]."
+"i"
+"2BX"
+"or"
+"[RFC5226]."
+"[RFC5226],"
+"M.,"
+"Names"
+"HTTP,"
+"RST"
+"the"
+"MOD"
+"If"
+"\"SHOULD"
+"being"
+"-"
+"SHA-1,"
+"E.,"
+"(IDN)"
+"ABNF)."
+"D.,"
+"mechanism"
+"[RFC4122])"
+"(GUID,"
+"RSV3"
+"its"
+"_A"
+"before"
+"U+0061"
+"[RFC2119]."
+"unsigned"
+"writing"
+"source"
+"SOCKS5"
+"P.,"
+"HTTP/1.1"
+"\"HTTP"
+"URI."
+"..."
+"format"
+"read"
+"|S|"
+"URI"
+"Bad"
+"URI:"
+"[RFC3629]"
+"not"
+"R."
+"\"IESG"
+"missing,"
+"name"
+"success"
+"C5AB0DC85B11\"."
+"signal"
+"WD-"
+"A.,"
+"API"
+"SQL"
+"page"
+"STD"
+"API),"
+"because"
+"bytes"
+"some"
+"back"
+"HYBI"
+"\"258EAFA5-"
+"RST,"
+"[RFC6066]"
+"[RFC3864]"
+"I.,"
+"RSV2,"
+"[RFC5234],"
+"for"
+"space"
+"ABNF\","
+"avoid"
+"/"
+"L."
+"time."
+"does"
+"TIME_WAIT"
+"CONNECT"
+"GUID."
+"assuming"
+"supports"
+"[RFC3986]"
+"be"
+"run"
+"This"
+"ABNF,"
+"PUB"
+"free"
+"E914-47DA-95CA-C5AB0DC85B11\""
+"RFC"
+"X3.4,"
+"base"
+"[RFC4648]),"
+"[RFC4648])."
+"[RFC6066]."
+"received."
+"by"
+"[RFC2818]."
+"on"
+"DIGIT"
+"FIN:"
+"ABNF"
+"TLS\","
+"of"
+"could"
+"&"
+"[TALKING]"
+"wrong"
+"times"
+"[RFC6202]"
+"length"
+"UI"
+"UK"
+"transfer"
+"HTTP/1.1\"."
+"[ANSI.X3-4.1986]."
+"HTTP/1.1\","
+"support"
+"[RFC5246]."
+"API\","
+"already"
+"HTTP/HTTPS"
+">="
+"E914-47DA-95CA-C5AB0DC85B11\","
+"[RFC4648])"
+"number"
+"one"
+"IDN"
+"Start"
+"NZDIGIT"
+"RFC."
+"ISO"
+"SMALL"
+"open"
+"U+0021"
+"size"
+"IETF"
+"unknown"
+"top"
+"*"
+"MASK"
+"long"
+"class"
+"start"
+"too"
+":"
+"was"
+"configured"
+"[RFC2817]."
+"TLS"
+"that"
+"completed"
+"[FIPS.180-3]"
+"but"
+"95CA-C5AB0DC85B11\""
+"BSD"
+"FIPS"
+"[RFC6454]"
+"DNS"
+"Error"
+"line"
+"trying"
+"true"
+"\"URI\""
+"target"
+"16"
+"default"
+"B."
+"up"
+"SHOULD"
+"(IESG)."
+"API."
+"called"
+"and"
+"UPGRADE"
+"false"
+"[RFC6202]."
+"[RFC2817]"
+"URI)"
+"lost."
+"[RFC2818]"
+"an"
+"To"
+"as"
+"at"
+"have"
+"need"
+"null"
+"U+005A"
+"any"
+"contents"
+"[RFC5246]"
+"\"SHOULD\","
+"no"
+"when"
+"invalid"
+"A."
+"application"
+"valid"
+"take"
+"which"
+"test"
+"you"
+"="
+"[RFC5321]"
+"requested"
+"begin"
+"multiple"
+"[RFC5234]."
+"(FIN/ACK),"
+"HTTP\","
+"[RFC3987]"
+"L-S.,"
+"\"MUST"
+"W3C"
+"\"MUST\","
+"E."
+"Common"
+"T.,"
+"The"
+"]"
+"pages"
+"D."
+"\"GET"
+"[RFC6265]),"
+"TW12"
+"IANA."
+"finished"
+"L.,"
+"As"
+"ALPHA"
+"+"
+"D.3."
+
diff --git a/chromium/net/data/http/http.dict b/chromium/net/data/http/http.dict
deleted file mode 100644
index 2e750cb8fbb..00000000000
--- a/chromium/net/data/http/http.dict
+++ /dev/null
@@ -1,163 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Fuzzer dictionary targetting HTTP/1.x responses.
-
-# Entries that are generally useful in headers
-":"
-"\x0A"
-"\x0D"
-"0"
-"50"
-"500"
-# Horizontal whitespace. Matters mostly in status line.
-" "
-"\x09"
-# Header continuation
-"\x0D\x0A\x09"
-# Used in a lot of individual headers
-";"
-"="
-","
-"\""
-"-"
-
-# Status line components
-"HTTP"
-"/1.1"
-"/1.0"
-# More interesting status codes. Leading space so can be inserted into
-# other status lines.
-" 100"
-" 200"
-" 206"
-" 301"
-" 302"
-" 303"
-" 304"
-" 307"
-" 308"
-" 401"
-" 403"
-" 404"
-" 500"
-" 501"
-" 403"
-
-# Full status lines (Some with relevant following headers)
-"HTTP/1.1 200 OK\x0A\x0A"
-"HTTP/1.1 100 Continue\x0A\x0A"
-"HTTP/1.1 401 Unauthorized\x0AWWW-Authenticate: Basic realm=\"Middle-Earth\"\x0A\xA0"
-"HTTP/1.1 407 Proxy Authentication Required\x0AProxy-Authenticate: Digest realm=\"Middle-Earth\", nonce=\"aaaaaaaaaa\"\x0A\x0A"
-"HTTP/1.0 301 Moved Permanently\x0ALocation: /a\x0A\x0A"
-"HTTP/1.1 302 Found\x0ALocation: http://lost/\x0A\x0A"
-
-# Proxy authentication headers. Note that fuzzers don't support NTLM or
-# negotiate.
-"WWW-Authenticate:"
-"Proxy-Authenticate:"
-"Basic"
-"Digest"
-"realm"
-"nonce"
-
-"Connection:"
-"Proxy-Connection:"
-"Keep-Alive"
-"Close"
-"Upgrade"
-"\x0AConnection: Keep-Alive"
-"\x0AConnection: Close"
-"\x0AProxy-Connection: Keep-Alive"
-"\x0AProxy-Connection: Close"
-
-"Content-Length:"
-"Transfer-Encoding:"
-"chunked"
-"\x0AContent-Length: 0"
-"\x0AContent-Length: 500"
-"\x0ATransfer-Encoding: chunked\x0A\x0A5\x0A12345\x0A0\x0A\x0A"
-
-"Location:"
-"\x0ALocation: http://foo/"
-"\x0ALocation: http://bar/"
-"\x0ALocation: https://foo/"
-"\x0ALocation: https://bar/"
-
-"Accept-Ranges:"
-"bytes"
-"\x0AAccept-Ranges: bytes"
-
-"Content-Range:"
-
-"Age:"
-"\x0AAge: 0"
-"\x0AAge: 3153600000"
-
-"Cache-Control:"
-"max-age"
-"no-cache"
-"no-store"
-"must-revalidate"
-"\x0ACache-Control: max-age=3153600000"
-"\x0ACache-Control: max-age=0"
-"\x0ACache-Control: no-cache"
-"\x0ACache-Control: no-store"
-"\x0ACache-Control: must-revalidate"
-
-"Content-Disposition:"
-"attachment"
-"filename"
-
-"Content-Encoding:"
-"gzip"
-"deflate"
-"sdch"
-"br"
-"\x0AContent-Encoding: gzip"
-"\x0AContent-Encoding: deflate"
-"\x0AContent-Encoding: sdch"
-"\x0AContent-Encoding: br"
-
-"Date:"
-"Fri, 01 Apr, 2050 14:14:14 GMT"
-"Mon, 28 Mar, 2016 04:04:04 GMT"
-"\x0ADate: Fri, 01 Apr, 2050 14:14:14 GMT"
-"\x0ADate: Mon, 28 Mar, 2016 04:04:04 GMT"
-
-"Last-Modified:"
-"\x0ALast-Modified: Fri, 01 Apr, 2050 14:14:14 GMT"
-"\x0ALast-Modified: Mon, 28 Mar, 2016 04:04:04 GMT"
-
-"Expires:"
-"\x0AExpires: Fri, 01 Apr, 2050 14:14:14 GMT"
-"\x0AExpires: Mon, 28 Mar, 2016 04:04:04 GMT"
-
-"Set-Cookie:"
-"Expires"
-"Max-Age"
-"Domain"
-"Path"
-"Secure"
-"HttpOnly"
-"Priority"
-"Low"
-"Medium"
-"High"
-"SameSite"
-"Strict"
-"Lax"
-"\x0ASet-Cookie: foo=bar"
-"\x0ASet-Cookie: foo2=bar2;HttpOnly;Priority=Low;SameSite=Strict;Path=/"
-"\x0ASet-Cookie: foo=chicken;SameSite=Lax"
-
-"Strict-Transport-Security:"
-"includeSubDomains"
-
-"Vary:"
-"\x0AVary: Cookie"
-"\x0AVary: Age"
-
-"ETag:"
-"\x0AETag: jumboshrimp"
diff --git a/chromium/net/data/parse_certificate_unittest/basic_constraints_ca_false.pem b/chromium/net/data/parse_certificate_unittest/basic_constraints_ca_false.pem
index e12425853ea..7344f20f227 100644
--- a/chromium/net/data/parse_certificate_unittest/basic_constraints_ca_false.pem
+++ b/chromium/net/data/parse_certificate_unittest/basic_constraints_ca_false.pem
@@ -1,6 +1,10 @@
-$ openssl asn1parse -i < [BASIC CONSTRAINTS]
- 0:d=0 hl=2 l= 3 cons: SEQUENCE
- 2:d=1 hl=2 l= 1 prim: BOOLEAN :0
------BEGIN BASIC CONSTRAINTS-----
-MAMBAQA=
------END BASIC CONSTRAINTS-----
+#-----BEGIN BASIC_CONSTRAINTS-----
+SEQUENCE {
+ BOOLEAN { `00` }
+}
+#-----END BASIC_CONSTRAINTS-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICWDCCAcGgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo1AwTjAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwEBADANBgkqhkiG9w0BAQUFAAOBgQA76HhtldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhrT5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4fj2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/basic_constraints_ca_no_path.pem b/chromium/net/data/parse_certificate_unittest/basic_constraints_ca_no_path.pem
index f74352b1ecc..da74e9129e7 100644
--- a/chromium/net/data/parse_certificate_unittest/basic_constraints_ca_no_path.pem
+++ b/chromium/net/data/parse_certificate_unittest/basic_constraints_ca_no_path.pem
@@ -1,6 +1,10 @@
-$ openssl asn1parse -i < [BASIC CONSTRAINTS]
- 0:d=0 hl=2 l= 3 cons: SEQUENCE
- 2:d=1 hl=2 l= 1 prim: BOOLEAN :255
------BEGIN BASIC CONSTRAINTS-----
-MAMBAf8=
------END BASIC CONSTRAINTS-----
+#-----BEGIN BASIC_CONSTRAINTS-----
+SEQUENCE {
+ BOOLEAN { `ff` }
+}
+#-----END BASIC_CONSTRAINTS-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICWDCCAcGgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo1AwTjAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQA76HhtldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhrT5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4fj2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/basic_constraints_ca_path_9.pem b/chromium/net/data/parse_certificate_unittest/basic_constraints_ca_path_9.pem
index 4df6f39ce74..e37e9d8c6d3 100644
--- a/chromium/net/data/parse_certificate_unittest/basic_constraints_ca_path_9.pem
+++ b/chromium/net/data/parse_certificate_unittest/basic_constraints_ca_path_9.pem
@@ -1,7 +1,11 @@
-$ openssl asn1parse -i < [BASIC CONSTRAINTS]
- 0:d=0 hl=2 l= 6 cons: SEQUENCE
- 2:d=1 hl=2 l= 1 prim: BOOLEAN :255
- 5:d=1 hl=2 l= 1 prim: INTEGER :09
------BEGIN BASIC CONSTRAINTS-----
-MAYBAf8CAQk=
------END BASIC CONSTRAINTS-----
+#-----BEGIN BASIC_CONSTRAINTS-----
+SEQUENCE {
+ BOOLEAN { `ff` }
+ INTEGER { 9 }
+}
+#-----END BASIC_CONSTRAINTS-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICWzCCAcSgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo1MwUTAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wDwYDVR0TBAgwBgEB/wIBCTANBgkqhkiG9w0BAQUFAAOBgQA76HhtldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhrT5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4fj2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/basic_constraints_negative_path.pem b/chromium/net/data/parse_certificate_unittest/basic_constraints_negative_path.pem
index 659a38f2b52..e92361d5e8d 100644
--- a/chromium/net/data/parse_certificate_unittest/basic_constraints_negative_path.pem
+++ b/chromium/net/data/parse_certificate_unittest/basic_constraints_negative_path.pem
@@ -1,7 +1,11 @@
-$ openssl asn1parse -i < [BASIC CONSTRAINTS]
- 0:d=0 hl=2 l= 6 cons: SEQUENCE
- 2:d=1 hl=2 l= 1 prim: BOOLEAN :255
- 5:d=1 hl=2 l= 1 prim: INTEGER :-01
------BEGIN BASIC CONSTRAINTS-----
-MAYBAf8CAf8=
------END BASIC CONSTRAINTS-----
+#-----BEGIN BASIC_CONSTRAINTS-----
+SEQUENCE {
+ BOOLEAN { `ff` }
+ INTEGER { -1 }
+}
+#-----END BASIC_CONSTRAINTS-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICWzCCAcSgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo1MwUTAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wDwYDVR0TBAgwBgEB/wIB/zANBgkqhkiG9w0BAQUFAAOBgQA76HhtldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhrT5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4fj2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/basic_constraints_not_ca.pem b/chromium/net/data/parse_certificate_unittest/basic_constraints_not_ca.pem
index 443914033f0..a115745cc38 100644
--- a/chromium/net/data/parse_certificate_unittest/basic_constraints_not_ca.pem
+++ b/chromium/net/data/parse_certificate_unittest/basic_constraints_not_ca.pem
@@ -1,5 +1,8 @@
-$ openssl asn1parse -i < [BASIC CONSTRAINTS]
- 0:d=0 hl=2 l= 0 cons: SEQUENCE
------BEGIN BASIC CONSTRAINTS-----
-MAA=
------END BASIC CONSTRAINTS-----
+#-----BEGIN BASIC_CONSTRAINTS-----
+SEQUENCE {}
+#-----END BASIC_CONSTRAINTS-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICVTCCAb6gAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo00wSzAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wCQYDVR0TBAIwADANBgkqhkiG9w0BAQUFAAOBgQA76HhtldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhrT5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4fj2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/basic_constraints_path_too_large.pem b/chromium/net/data/parse_certificate_unittest/basic_constraints_path_too_large.pem
index 9952047a0d0..23aeaded08b 100644
--- a/chromium/net/data/parse_certificate_unittest/basic_constraints_path_too_large.pem
+++ b/chromium/net/data/parse_certificate_unittest/basic_constraints_path_too_large.pem
@@ -1,7 +1,11 @@
-$ openssl asn1parse -i < [BASIC CONSTRAINTS]
- 0:d=0 hl=2 l= 29 cons: SEQUENCE
- 2:d=1 hl=2 l= 1 prim: BOOLEAN :255
- 5:d=1 hl=2 l= 24 prim: INTEGER :0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
------BEGIN BASIC CONSTRAINTS-----
-MB0BAf8CGA///////////////////////////////w==
------END BASIC CONSTRAINTS-----
+#-----BEGIN BASIC_CONSTRAINTS-----
+SEQUENCE {
+ BOOLEAN { `ff` }
+ INTEGER { `0fffffffffffffffffffffffffffffffffffffffffffffff` }
+}
+#-----END BASIC_CONSTRAINTS-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICcjCCAdugAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo2owaDAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wJgYDVR0TBB8wHQEB/wIYD///////////////////////////////MA0GCSqGSIb3DQEBBQUAA4GBADvoeG2V1j1q9xMZLBvCiK4iq/SNMvV8cWfPLdEcwsOH4um+iVzkNKtIkcI/la4rR54leGtPmhCkcv3P9wIMsAoIpFri5XR+ER05YGrJH2nzLmMm3J7va3oK4VRXmKpykXgEfh+PZU0fCxKsnCQPhBQaVS0fu/CdCbIIXFkyZYAm
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/basic_constraints_pathlen_255.pem b/chromium/net/data/parse_certificate_unittest/basic_constraints_pathlen_255.pem
index 01bb6961e8e..33aae650a7d 100644
--- a/chromium/net/data/parse_certificate_unittest/basic_constraints_pathlen_255.pem
+++ b/chromium/net/data/parse_certificate_unittest/basic_constraints_pathlen_255.pem
@@ -1,7 +1,11 @@
-$ openssl asn1parse -i < [BASIC CONSTRAINTS]
- 0:d=0 hl=2 l= 7 cons: SEQUENCE
- 2:d=1 hl=2 l= 1 prim: BOOLEAN :255
- 5:d=1 hl=2 l= 2 prim: INTEGER :FF
------BEGIN BASIC CONSTRAINTS-----
-MAcBAf8CAgD/
------END BASIC CONSTRAINTS-----
+#-----BEGIN BASIC_CONSTRAINTS-----
+SEQUENCE {
+ BOOLEAN { `ff` }
+ INTEGER { 255 }
+}
+#-----END BASIC_CONSTRAINTS-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICXDCCAcWgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo1QwUjAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wEAYDVR0TBAkwBwEB/wICAP8wDQYJKoZIhvcNAQEFBQADgYEAO+h4bZXWPWr3ExksG8KIriKr9I0y9XxxZ88t0RzCw4fi6b6JXOQ0q0iRwj+VritHniV4a0+aEKRy/c/3AgywCgikWuLldH4RHTlgaskfafMuYybcnu9regrhVFeYqnKReAR+H49lTR8LEqycJA+EFBpVLR+78J0JsghcWTJlgCY=
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/basic_constraints_pathlen_256.pem b/chromium/net/data/parse_certificate_unittest/basic_constraints_pathlen_256.pem
index 7a3322dea42..1768eb87320 100644
--- a/chromium/net/data/parse_certificate_unittest/basic_constraints_pathlen_256.pem
+++ b/chromium/net/data/parse_certificate_unittest/basic_constraints_pathlen_256.pem
@@ -1,7 +1,11 @@
-$ openssl asn1parse -i < [BASIC CONSTRAINTS]
- 0:d=0 hl=2 l= 7 cons: SEQUENCE
- 2:d=1 hl=2 l= 1 prim: BOOLEAN :255
- 5:d=1 hl=2 l= 2 prim: INTEGER :0100
------BEGIN BASIC CONSTRAINTS-----
-MAcBAf8CAgEA
------END BASIC CONSTRAINTS-----
+#-----BEGIN BASIC_CONSTRAINTS-----
+SEQUENCE {
+ BOOLEAN { `ff` }
+ INTEGER { 256 }
+}
+#-----END BASIC_CONSTRAINTS-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICXDCCAcWgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo1QwUjAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wEAYDVR0TBAkwBwEB/wICAQAwDQYJKoZIhvcNAQEFBQADgYEAO+h4bZXWPWr3ExksG8KIriKr9I0y9XxxZ88t0RzCw4fi6b6JXOQ0q0iRwj+VritHniV4a0+aEKRy/c/3AgywCgikWuLldH4RHTlgaskfafMuYybcnu9regrhVFeYqnKReAR+H49lTR8LEqycJA+EFBpVLR+78J0JsghcWTJlgCY=
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/basic_constraints_pathlen_not_ca.pem b/chromium/net/data/parse_certificate_unittest/basic_constraints_pathlen_not_ca.pem
index 2fa12fc759d..3aeb8b83924 100644
--- a/chromium/net/data/parse_certificate_unittest/basic_constraints_pathlen_not_ca.pem
+++ b/chromium/net/data/parse_certificate_unittest/basic_constraints_pathlen_not_ca.pem
@@ -1,6 +1,10 @@
-$ openssl asn1parse -i < [BASIC CONSTRAINTS]
- 0:d=0 hl=2 l= 3 cons: SEQUENCE
- 2:d=1 hl=2 l= 1 prim: INTEGER :01
------BEGIN BASIC CONSTRAINTS-----
-MAMCAQE=
------END BASIC CONSTRAINTS-----
+#-----BEGIN BASIC_CONSTRAINTS-----
+SEQUENCE {
+ INTEGER { 1 }
+}
+#-----END BASIC_CONSTRAINTS-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICWDCCAcGgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo1AwTjAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwIBATANBgkqhkiG9w0BAQUFAAOBgQA76HhtldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhrT5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4fj2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/basic_constraints_unconsumed_data.pem b/chromium/net/data/parse_certificate_unittest/basic_constraints_unconsumed_data.pem
index 82e7f8c824a..5fc028d2af3 100644
--- a/chromium/net/data/parse_certificate_unittest/basic_constraints_unconsumed_data.pem
+++ b/chromium/net/data/parse_certificate_unittest/basic_constraints_unconsumed_data.pem
@@ -1,6 +1,10 @@
-$ openssl asn1parse -i < [BASIC CONSTRAINTS]
- 0:d=0 hl=2 l= 2 cons: SEQUENCE
- 2:d=1 hl=2 l= 0 prim: NULL
------BEGIN BASIC CONSTRAINTS-----
-MAIFAA==
------END BASIC CONSTRAINTS-----
+#-----BEGIN BASIC_CONSTRAINTS-----
+SEQUENCE {
+ NULL {}
+}
+#-----END BASIC_CONSTRAINTS-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICVzCCAcCgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo08wTTAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wCwYDVR0TBAQwAgUAMA0GCSqGSIb3DQEBBQUAA4GBADvoeG2V1j1q9xMZLBvCiK4iq/SNMvV8cWfPLdEcwsOH4um+iVzkNKtIkcI/la4rR54leGtPmhCkcv3P9wIMsAoIpFri5XR+ER05YGrJH2nzLmMm3J7va3oK4VRXmKpykXgEfh+PZU0fCxKsnCQPhBQaVS0fu/CdCbIIXFkyZYAm
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/cert_algorithm_not_sequence.pem b/chromium/net/data/parse_certificate_unittest/cert_algorithm_not_sequence.pem
index 96f05fee492..a7a66d7c090 100644
--- a/chromium/net/data/parse_certificate_unittest/cert_algorithm_not_sequence.pem
+++ b/chromium/net/data/parse_certificate_unittest/cert_algorithm_not_sequence.pem
@@ -11,3 +11,9 @@ $ openssl asn1parse -i < [CERTIFICATE]
-----BEGIN CERTIFICATE-----
MAwwAgUAAgIFAAMCAKs=
-----END CERTIFICATE-----
+
+[Error] Couldn't read Certificate.signatureAlgorithm as SEQUENCE
+
+-----BEGIN ERRORS-----
+W0Vycm9yXSBDb3VsZG4ndCByZWFkIENlcnRpZmljYXRlLnNpZ25hdHVyZUFsZ29yaXRobSBhcyBTRVFVRU5DRQo=
+-----END ERRORS-----
diff --git a/chromium/net/data/parse_certificate_unittest/cert_data_after_signature.pem b/chromium/net/data/parse_certificate_unittest/cert_data_after_signature.pem
index 090c1267809..09f94bee5cd 100644
--- a/chromium/net/data/parse_certificate_unittest/cert_data_after_signature.pem
+++ b/chromium/net/data/parse_certificate_unittest/cert_data_after_signature.pem
@@ -13,3 +13,9 @@ $ openssl asn1parse -i < [CERTIFICATE]
-----BEGIN CERTIFICATE-----
MA4wAgUAMAIFAAMCAKwFAA==
-----END CERTIFICATE-----
+
+[Error] Unconsumed data inside Certificate SEQUENCE
+
+-----BEGIN ERRORS-----
+W0Vycm9yXSBVbmNvbnN1bWVkIGRhdGEgaW5zaWRlIENlcnRpZmljYXRlIFNFUVVFTkNFCg==
+-----END ERRORS-----
diff --git a/chromium/net/data/parse_certificate_unittest/cert_empty_sequence.pem b/chromium/net/data/parse_certificate_unittest/cert_empty_sequence.pem
index f6b7f9a8b91..fb7085abc49 100644
--- a/chromium/net/data/parse_certificate_unittest/cert_empty_sequence.pem
+++ b/chromium/net/data/parse_certificate_unittest/cert_empty_sequence.pem
@@ -7,3 +7,9 @@ $ openssl asn1parse -i < [CERTIFICATE]
-----BEGIN CERTIFICATE-----
MAA=
-----END CERTIFICATE-----
+
+[Error] Couldn't read tbsCertificate as SEQUENCE
+
+-----BEGIN ERRORS-----
+W0Vycm9yXSBDb3VsZG4ndCByZWFkIHRic0NlcnRpZmljYXRlIGFzIFNFUVVFTkNFCg==
+-----END ERRORS-----
diff --git a/chromium/net/data/parse_certificate_unittest/cert_missing_signature.pem b/chromium/net/data/parse_certificate_unittest/cert_missing_signature.pem
index 9a5960f6d18..6fa7197bc22 100644
--- a/chromium/net/data/parse_certificate_unittest/cert_missing_signature.pem
+++ b/chromium/net/data/parse_certificate_unittest/cert_missing_signature.pem
@@ -11,3 +11,9 @@ $ openssl asn1parse -i < [CERTIFICATE]
-----BEGIN CERTIFICATE-----
MAgwAgUAMAIFAA==
-----END CERTIFICATE-----
+
+[Error] Couldn't read Certificate.signatureValue as BIT STRING
+
+-----BEGIN ERRORS-----
+W0Vycm9yXSBDb3VsZG4ndCByZWFkIENlcnRpZmljYXRlLnNpZ25hdHVyZVZhbHVlIGFzIEJJVCBTVFJJTkcK
+-----END ERRORS-----
diff --git a/chromium/net/data/parse_certificate_unittest/cert_not_sequence.pem b/chromium/net/data/parse_certificate_unittest/cert_not_sequence.pem
index 3ef1bde2b1e..b556ca3af60 100644
--- a/chromium/net/data/parse_certificate_unittest/cert_not_sequence.pem
+++ b/chromium/net/data/parse_certificate_unittest/cert_not_sequence.pem
@@ -7,3 +7,9 @@ $ openssl asn1parse -i < [CERTIFICATE]
-----BEGIN CERTIFICATE-----
AhAwBgUAMAIFADACBQADAgCs
-----END CERTIFICATE-----
+
+[Error] Failed parsing Certificate SEQUENCE
+
+-----BEGIN ERRORS-----
+W0Vycm9yXSBGYWlsZWQgcGFyc2luZyBDZXJ0aWZpY2F0ZSBTRVFVRU5DRQo=
+-----END ERRORS-----
diff --git a/chromium/net/data/parse_certificate_unittest/cert_signature_not_bit_string.pem b/chromium/net/data/parse_certificate_unittest/cert_signature_not_bit_string.pem
index 5d335b9de94..8c9cc909a50 100644
--- a/chromium/net/data/parse_certificate_unittest/cert_signature_not_bit_string.pem
+++ b/chromium/net/data/parse_certificate_unittest/cert_signature_not_bit_string.pem
@@ -12,3 +12,9 @@ $ openssl asn1parse -i < [CERTIFICATE]
-----BEGIN CERTIFICATE-----
MAwwAgUAMAIFAAQCAQI=
-----END CERTIFICATE-----
+
+[Error] Couldn't read Certificate.signatureValue as BIT STRING
+
+-----BEGIN ERRORS-----
+W0Vycm9yXSBDb3VsZG4ndCByZWFkIENlcnRpZmljYXRlLnNpZ25hdHVyZVZhbHVlIGFzIEJJVCBTVFJJTkcK
+-----END ERRORS-----
diff --git a/chromium/net/data/parse_certificate_unittest/extended_key_usage.pem b/chromium/net/data/parse_certificate_unittest/extended_key_usage.pem
new file mode 100644
index 00000000000..9ad94bc1e6a
--- /dev/null
+++ b/chromium/net/data/parse_certificate_unittest/extended_key_usage.pem
@@ -0,0 +1,21 @@
+#-----BEGIN EXTENSION-----
+SEQUENCE {
+ # extKeyUsage
+ OBJECT_IDENTIFIER { 2.5.29.37 }
+ OCTET_STRING {
+ SEQUENCE {
+ # serverAuth
+ OBJECT_IDENTIFIER { 1.3.6.1.5.5.7.3.1 }
+ # clientAuth
+ OBJECT_IDENTIFIER { 1.3.6.1.5.5.7.3.2 }
+ OBJECT_IDENTIFIER { 1.3.6.1.4.1.311.10.3.3 }
+ OBJECT_IDENTIFIER { 2.16.840.1.113730.4.1 }
+ }
+ }
+}
+#-----END EXTENSION-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICkDCCAfmgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo4GHMIGEMB0GA1UdDgQWBBSLddWsywi+Dh9lt/pWvmynddqFrzAfBgNVHSMEGDAWgBSLddWsywi+Dh9lt/pWvmynddqFrzAMBgNVHRMEBTADAQH/MDQGA1UdJQQtMCsGCCsGAQUFBwMBBggrBgEFBQcDAgYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4GBADvoeG2V1j1q9xMZLBvCiK4iq/SNMvV8cWfPLdEcwsOH4um+iVzkNKtIkcI/la4rR54leGtPmhCkcv3P9wIMsAoIpFri5XR+ER05YGrJH2nzLmMm3J7va3oK4VRXmKpykXgEfh+PZU0fCxKsnCQPhBQaVS0fu/CdCbIIXFkyZYAm
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/extension_critical.pem b/chromium/net/data/parse_certificate_unittest/extension_critical.pem
index 1f79e69580e..20482b0c3cf 100644
--- a/chromium/net/data/parse_certificate_unittest/extension_critical.pem
+++ b/chromium/net/data/parse_certificate_unittest/extension_critical.pem
@@ -1,11 +1,17 @@
-This is a basic constraints extension, which is marked as critical.
+This is an unknown extension, which is marked as critical.
+#-----BEGIN EXTENSION-----
+SEQUENCE {
+ # https://davidben.net/oid
+ OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.0 }
+ BOOLEAN { `ff` }
+ OCTET_STRING {
+ SEQUENCE {}
+ }
+}
+#-----END EXTENSION-----
-$ openssl asn1parse -i < [EXTENSION]
- 0:d=0 hl=2 l= 12 cons: SEQUENCE
- 2:d=1 hl=2 l= 3 prim: OBJECT :X509v3 Basic Constraints
- 7:d=1 hl=2 l= 1 prim: BOOLEAN :255
- 10:d=1 hl=2 l= 2 prim: OCTET STRING [HEX DUMP]:3000
------BEGIN EXTENSION-----
-MAwGA1UdEwEB/wQCMAA=
------END EXTENSION-----
+
+-----BEGIN CERTIFICATE-----
+MIICbzCCAdigAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo2cwZTAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwEB/zAVBgwqhkiG9xIEAYS3CQABAf8EAjAAMA0GCSqGSIb3DQEBBQUAA4GBADvoeG2V1j1q9xMZLBvCiK4iq/SNMvV8cWfPLdEcwsOH4um+iVzkNKtIkcI/la4rR54leGtPmhCkcv3P9wIMsAoIpFri5XR+ER05YGrJH2nzLmMm3J7va3oK4VRXmKpykXgEfh+PZU0fCxKsnCQPhBQaVS0fu/CdCbIIXFkyZYAm
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/extension_critical_0.pem b/chromium/net/data/parse_certificate_unittest/extension_critical_0.pem
index 915cbbc4a1c..64836c8c011 100644
--- a/chromium/net/data/parse_certificate_unittest/extension_critical_0.pem
+++ b/chromium/net/data/parse_certificate_unittest/extension_critical_0.pem
@@ -1,14 +1,20 @@
-This is a basic constraints extension, where the critical field (BOOLEAN) is 0.
+This is an unknown extension, where the critical field (BOOLEAN) is 0.
This is not valid because the critical field has a default of FALSE, so under
DER-encoding it should be omitted.
+#-----BEGIN EXTENSION-----
+SEQUENCE {
+ # https://davidben.net/oid
+ OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.0 }
+ BOOLEAN { `00` }
+ OCTET_STRING {
+ SEQUENCE {}
+ }
+}
+#-----END EXTENSION-----
-$ openssl asn1parse -i < [EXTENSION]
- 0:d=0 hl=2 l= 12 cons: SEQUENCE
- 2:d=1 hl=2 l= 3 prim: OBJECT :X509v3 Basic Constraints
- 7:d=1 hl=2 l= 1 prim: BOOLEAN :0
- 10:d=1 hl=2 l= 2 prim: OCTET STRING [HEX DUMP]:3000
------BEGIN EXTENSION-----
-MAwGA1UdEwEBAAQCMAA=
------END EXTENSION-----
+
+-----BEGIN CERTIFICATE-----
+MIICbzCCAdigAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo2cwZTAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwEB/zAVBgwqhkiG9xIEAYS3CQABAQAEAjAAMA0GCSqGSIb3DQEBBQUAA4GBADvoeG2V1j1q9xMZLBvCiK4iq/SNMvV8cWfPLdEcwsOH4um+iVzkNKtIkcI/la4rR54leGtPmhCkcv3P9wIMsAoIpFri5XR+ER05YGrJH2nzLmMm3J7va3oK4VRXmKpykXgEfh+PZU0fCxKsnCQPhBQaVS0fu/CdCbIIXFkyZYAm
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/extension_critical_3.pem b/chromium/net/data/parse_certificate_unittest/extension_critical_3.pem
index 97b8f08ab48..c9d904ad179 100644
--- a/chromium/net/data/parse_certificate_unittest/extension_critical_3.pem
+++ b/chromium/net/data/parse_certificate_unittest/extension_critical_3.pem
@@ -1,14 +1,20 @@
-This is a basic constraints extension, where the critical field (BOOLEAN) is 3.
+This is an unknown extension, where the critical field (BOOLEAN) is 3.
This is not valid because BOOLEANs in DER-encoding should use an octet of
either all 0 bits or all 1 bits.
+#-----BEGIN EXTENSION-----
+SEQUENCE {
+ # https://davidben.net/oid
+ OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.0 }
+ BOOLEAN { `03` }
+ OCTET_STRING {
+ SEQUENCE {}
+ }
+}
+#-----END EXTENSION-----
-$ openssl asn1parse -i < [EXTENSION]
- 0:d=0 hl=2 l= 12 cons: SEQUENCE
- 2:d=1 hl=2 l= 3 prim: OBJECT :X509v3 Basic Constraints
- 7:d=1 hl=2 l= 1 prim: BOOLEAN :3
- 10:d=1 hl=2 l= 2 prim: OCTET STRING [HEX DUMP]:3000
------BEGIN EXTENSION-----
-MAwGA1UdEwEBAwQCMAA=
------END EXTENSION-----
+
+-----BEGIN CERTIFICATE-----
+MIICbzCCAdigAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo2cwZTAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwEB/zAVBgwqhkiG9xIEAYS3CQABAQMEAjAAMA0GCSqGSIb3DQEBBQUAA4GBADvoeG2V1j1q9xMZLBvCiK4iq/SNMvV8cWfPLdEcwsOH4um+iVzkNKtIkcI/la4rR54leGtPmhCkcv3P9wIMsAoIpFri5XR+ER05YGrJH2nzLmMm3J7va3oK4VRXmKpykXgEfh+PZU0fCxKsnCQPhBQaVS0fu/CdCbIIXFkyZYAm
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/extension_not_critical.pem b/chromium/net/data/parse_certificate_unittest/extension_not_critical.pem
index 7e90c7aa777..dc358f84249 100644
--- a/chromium/net/data/parse_certificate_unittest/extension_not_critical.pem
+++ b/chromium/net/data/parse_certificate_unittest/extension_not_critical.pem
@@ -1,11 +1,17 @@
-This is a modified basic constraints extension, where the critical field was
-removed (in other words, FALSE).
+This is an unknown extension, where the critical field is absent (in other
+words, FALSE).
+#-----BEGIN EXTENSION-----
+SEQUENCE {
+ # https://davidben.net/oid
+ OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.0 }
+ OCTET_STRING {
+ SEQUENCE {}
+ }
+}
+#-----END EXTENSION-----
-$ openssl asn1parse -i < [EXTENSION]
- 0:d=0 hl=2 l= 9 cons: SEQUENCE
- 2:d=1 hl=2 l= 3 prim: OBJECT :X509v3 Basic Constraints
- 7:d=1 hl=2 l= 2 prim: OCTET STRING [HEX DUMP]:3000
------BEGIN EXTENSION-----
-MAkGA1UdEwQCMAA=
------END EXTENSION-----
+
+-----BEGIN CERTIFICATE-----
+MIICbDCCAdWgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo2QwYjAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwEB/zASBgwqhkiG9xIEAYS3CQAEAjAAMA0GCSqGSIb3DQEBBQUAA4GBADvoeG2V1j1q9xMZLBvCiK4iq/SNMvV8cWfPLdEcwsOH4um+iVzkNKtIkcI/la4rR54leGtPmhCkcv3P9wIMsAoIpFri5XR+ER05YGrJH2nzLmMm3J7va3oK4VRXmKpykXgEfh+PZU0fCxKsnCQPhBQaVS0fu/CdCbIIXFkyZYAm
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/extensions_basic_constraints.pem b/chromium/net/data/parse_certificate_unittest/extensions_basic_constraints.pem
deleted file mode 100644
index 771cb4038c8..00000000000
--- a/chromium/net/data/parse_certificate_unittest/extensions_basic_constraints.pem
+++ /dev/null
@@ -1,15 +0,0 @@
-$ openssl asn1parse -i < [EXTENSIONS]
- 0:d=0 hl=2 l= 14 cons: SEQUENCE
- 2:d=1 hl=2 l= 12 cons: SEQUENCE
- 4:d=2 hl=2 l= 3 prim: OBJECT :X509v3 Basic Constraints
- 9:d=2 hl=2 l= 1 prim: BOOLEAN :255
- 12:d=2 hl=2 l= 2 prim: OCTET STRING [HEX DUMP]:3000
------BEGIN EXTENSIONS-----
-MA4wDAYDVR0TAQH/BAIwAA==
------END EXTENSIONS-----
-
-$ openssl asn1parse -i < [BASIC CONSTRAINTS]
- 0:d=0 hl=2 l= 0 cons: SEQUENCE
------BEGIN BASIC CONSTRAINTS-----
-MAA=
------END BASIC CONSTRAINTS-----
diff --git a/chromium/net/data/parse_certificate_unittest/extensions_data_after_sequence.pem b/chromium/net/data/parse_certificate_unittest/extensions_data_after_sequence.pem
index 0c56b1dafe5..ce956c86995 100644
--- a/chromium/net/data/parse_certificate_unittest/extensions_data_after_sequence.pem
+++ b/chromium/net/data/parse_certificate_unittest/extensions_data_after_sequence.pem
@@ -1,10 +1,18 @@
-$ openssl asn1parse -i < [EXTENSIONS]
- 0:d=0 hl=2 l= 18 cons: SEQUENCE
- 2:d=1 hl=2 l= 14 cons: SEQUENCE
- 4:d=2 hl=2 l= 3 prim: OBJECT :X509v3 Key Usage
- 9:d=2 hl=2 l= 1 prim: BOOLEAN :255
- 12:d=2 hl=2 l= 4 prim: OCTET STRING [HEX DUMP]:030203B8
- 18:d=1 hl=2 l= 0 prim: NULL
------BEGIN EXTENSIONS-----
-MBIwDgYDVR0PAQH/BAQDAgO4BQA=
------END EXTENSIONS-----
+#-----BEGIN EXTENSIONS-----
+SEQUENCE {
+ SEQUENCE {
+ # keyUsage
+ OBJECT_IDENTIFIER { 2.5.29.15 }
+ BOOLEAN { `ff` }
+ OCTET_STRING {
+ BIT_STRING { `03b8` }
+ }
+ }
+ NULL {}
+}
+#-----END EXTENSIONS-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICHDCCAYWgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABoxQwEjAOBgNVHQ8BAf8EBAMCA7gFADANBgkqhkiG9w0BAQUFAAOBgQA76HhtldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhrT5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4fj2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/chromium/net/data/parse_certificate_unittest/extensions_duplicate_key_usage.pem b/chromium/net/data/parse_certificate_unittest/extensions_duplicate_key_usage.pem
index 85624e999ff..c2da2b4d9e1 100644
--- a/chromium/net/data/parse_certificate_unittest/extensions_duplicate_key_usage.pem
+++ b/chromium/net/data/parse_certificate_unittest/extensions_duplicate_key_usage.pem
@@ -1,13 +1,25 @@
-$ openssl asn1parse -i < [EXTENSIONS]
- 0:d=0 hl=2 l= 32 cons: SEQUENCE
- 2:d=1 hl=2 l= 14 cons: SEQUENCE
- 4:d=2 hl=2 l= 3 prim: OBJECT :X509v3 Key Usage
- 9:d=2 hl=2 l= 1 prim: BOOLEAN :255
- 12:d=2 hl=2 l= 4 prim: OCTET STRING [HEX DUMP]:030203B8
- 18:d=1 hl=2 l= 14 cons: SEQUENCE
- 20:d=2 hl=2 l= 3 prim: OBJECT :X509v3 Key Usage
- 25:d=2 hl=2 l= 1 prim: BOOLEAN :255
- 28:d=2 hl=2 l= 4 prim: OCTET STRING [HEX DUMP]:030203B8
------BEGIN EXTENSIONS-----
-MCAwDgYDVR0PAQH/BAQDAgO4MA4GA1UdDwEB/wQEAwIDuA==
------END EXTENSIONS-----
+#-----BEGIN EXTENSIONS-----
+SEQUENCE {
+ SEQUENCE {
+ # keyUsage
+ OBJECT_IDENTIFIER { 2.5.29.15 }
+ BOOLEAN { `ff` }
+ OCTET_STRING {
+ BIT_STRING { `03b8` }
+ }
+ }
+ SEQUENCE {
+ # keyUsage
+ OBJECT_IDENTIFIER { 2.5.29.15 }
+ BOOLEAN { `ff` }
+ OCTET_STRING {
+ BIT_STRING { `03b8` }
+ }
+ }
+}
+#-----END EXTENSIONS-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICKjCCAZOgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABoyIwIDAOBgNVHQ8BAf8EBAMCA7gwDgYDVR0PAQH/BAQDAgO4MA0GCSqGSIb3DQEBBQUAA4GBADvoeG2V1j1q9xMZLBvCiK4iq/SNMvV8cWfPLdEcwsOH4um+iVzkNKtIkcI/la4rR54leGtPmhCkcv3P9wIMsAoIpFri5XR+ER05YGrJH2nzLmMm3J7va3oK4VRXmKpykXgEfh+PZU0fCxKsnCQPhBQaVS0fu/CdCbIIXFkyZYAm
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/chromium/net/data/parse_certificate_unittest/extensions_empty_sequence.pem b/chromium/net/data/parse_certificate_unittest/extensions_empty_sequence.pem
index fe021083609..debddec1254 100644
--- a/chromium/net/data/parse_certificate_unittest/extensions_empty_sequence.pem
+++ b/chromium/net/data/parse_certificate_unittest/extensions_empty_sequence.pem
@@ -1,5 +1,8 @@
-$ openssl asn1parse -i < [EXTENSIONS]
- 0:d=0 hl=2 l= 0 cons: SEQUENCE
------BEGIN EXTENSIONS-----
-MAA=
------END EXTENSIONS-----
+#-----BEGIN EXTENSIONS-----
+SEQUENCE {}
+#-----END EXTENSIONS-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICCjCCAXOgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABowIwADANBgkqhkiG9w0BAQUFAAOBgQA76HhtldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhrT5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4fj2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/chromium/net/data/parse_certificate_unittest/extensions_extended_key_usage.pem b/chromium/net/data/parse_certificate_unittest/extensions_extended_key_usage.pem
deleted file mode 100644
index 6b253cd02ca..00000000000
--- a/chromium/net/data/parse_certificate_unittest/extensions_extended_key_usage.pem
+++ /dev/null
@@ -1,19 +0,0 @@
-$ openssl asn1parse -i < [EXTENSIONS]
- 0:d=0 hl=2 l= 54 cons: SEQUENCE
- 2:d=1 hl=2 l= 52 cons: SEQUENCE
- 4:d=2 hl=2 l= 3 prim: OBJECT :X509v3 Extended Key Usage
- 9:d=2 hl=2 l= 45 prim: OCTET STRING [HEX DUMP]:302B06082B0601050507030106082B06010505070302060A2B0601040182370A030306096086480186F8420401
------BEGIN EXTENSIONS-----
-MDYwNAYDVR0lBC0wKwYIKwYBBQUHAwEGCCsGAQUFBwMCBgorBgEEAYI3CgMDBglghkgBhvhCBAE
-=
------END EXTENSIONS-----
-
-$ openssl asn1parse -i < [EXTENDED KEY USAGE]
- 0:d=0 hl=2 l= 43 cons: SEQUENCE
- 2:d=1 hl=2 l= 8 prim: OBJECT :TLS Web Server Authentication
- 12:d=1 hl=2 l= 8 prim: OBJECT :TLS Web Client Authentication
- 22:d=1 hl=2 l= 10 prim: OBJECT :Microsoft Server Gated Crypto
- 34:d=1 hl=2 l= 9 prim: OBJECT :Netscape Server Gated Crypto
------BEGIN EXTENDED KEY USAGE-----
-MCsGCCsGAQUFBwMBBggrBgEFBQcDAgYKKwYBBAGCNwoDAwYJYIZIAYb4QgQB
------END EXTENDED KEY USAGE-----
diff --git a/chromium/net/data/parse_certificate_unittest/extensions_key_usage.pem b/chromium/net/data/parse_certificate_unittest/extensions_key_usage.pem
deleted file mode 100644
index 7762c535371..00000000000
--- a/chromium/net/data/parse_certificate_unittest/extensions_key_usage.pem
+++ /dev/null
@@ -1,15 +0,0 @@
-$ openssl asn1parse -i < [EXTENSIONS]
- 0:d=0 hl=2 l= 16 cons: SEQUENCE
- 2:d=1 hl=2 l= 14 cons: SEQUENCE
- 4:d=2 hl=2 l= 3 prim: OBJECT :X509v3 Key Usage
- 9:d=2 hl=2 l= 1 prim: BOOLEAN :255
- 12:d=2 hl=2 l= 4 prim: OCTET STRING [HEX DUMP]:030205A0
------BEGIN EXTENSIONS-----
-MBAwDgYDVR0PAQH/BAQDAgWg
------END EXTENSIONS-----
-
-$ openssl asn1parse -i < [KEY USAGE]
- 0:d=0 hl=2 l= 2 prim: BIT STRING
------BEGIN KEY USAGE-----
-AwIFoA==
------END KEY USAGE-----
diff --git a/chromium/net/data/parse_certificate_unittest/extensions_not_sequence.pem b/chromium/net/data/parse_certificate_unittest/extensions_not_sequence.pem
index 4b1b625bada..f754c493cc3 100644
--- a/chromium/net/data/parse_certificate_unittest/extensions_not_sequence.pem
+++ b/chromium/net/data/parse_certificate_unittest/extensions_not_sequence.pem
@@ -1,5 +1,8 @@
-$ openssl asn1parse -i < [EXTENSIONS]
- 0:d=0 hl=2 l= 0 prim: NULL
------BEGIN EXTENSIONS-----
-BQA=
------END EXTENSIONS-----
+#-----BEGIN EXTENSIONS-----
+NULL {}
+#-----END EXTENSIONS-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICCjCCAXOgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABowIFADANBgkqhkiG9w0BAQUFAAOBgQA76HhtldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhrT5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4fj2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==
+-----END CERTIFICATE----- \ No newline at end of file
diff --git a/chromium/net/data/parse_certificate_unittest/extensions_policies.pem b/chromium/net/data/parse_certificate_unittest/extensions_policies.pem
deleted file mode 100644
index 13457bcb13c..00000000000
--- a/chromium/net/data/parse_certificate_unittest/extensions_policies.pem
+++ /dev/null
@@ -1,24 +0,0 @@
-$ openssl asn1parse -i < [EXTENSIONS]
- 0:d=0 hl=2 l= 104 cons: SEQUENCE
- 2:d=1 hl=2 l= 102 cons: SEQUENCE
- 4:d=2 hl=2 l= 3 prim: OBJECT :X509v3 Certificate Policies
- 9:d=2 hl=2 l= 95 prim: OCTET STRING [HEX DUMP]:305D304D060A2A83088C9C1E01020201303F303D06082B06010505070201163168747470733A2F2F7265706F312E7365636F6D74727573742E6E65742F73706370702F6370732F696E6465782E68746D6C300C060A2A83088C9B1B64870501
------BEGIN EXTENSIONS-----
-MGgwZgYDVR0gBF8wXTBNBgoqgwiMnB4BAgIBMD8wPQYIKwYBBQUHAgEWMWh0dHBzOi8vcmVwbzE
-uc2Vjb210cnVzdC5uZXQvc3BjcHAvY3BzL2luZGV4Lmh0bWwwDAYKKoMIjJsbZIcFAQ==
------END EXTENSIONS-----
-
-$ openssl asn1parse -i < [POLICIES]
- 0:d=0 hl=2 l= 93 cons: SEQUENCE
- 2:d=1 hl=2 l= 77 cons: SEQUENCE
- 4:d=2 hl=2 l= 10 prim: OBJECT :1.2.392.200222.1.2.2.1
- 16:d=2 hl=2 l= 63 cons: SEQUENCE
- 18:d=3 hl=2 l= 61 cons: SEQUENCE
- 20:d=4 hl=2 l= 8 prim: OBJECT :Policy Qualifier CPS
- 30:d=4 hl=2 l= 49 prim: IA5STRING :https://repo1.secomtrust.net/spcpp/cps/index.html
- 81:d=1 hl=2 l= 12 cons: SEQUENCE
- 83:d=2 hl=2 l= 10 prim: OBJECT :1.2.392.200091.100.901.1
------BEGIN POLICIES-----
-MF0wTQYKKoMIjJweAQICATA/MD0GCCsGAQUFBwIBFjFodHRwczovL3JlcG8xLnNlY29tdHJ1c3Q
-ubmV0L3NwY3BwL2Nwcy9pbmRleC5odG1sMAwGCiqDCIybG2SHBQE=
------END POLICIES-----
diff --git a/chromium/net/data/parse_certificate_unittest/extensions_real.pem b/chromium/net/data/parse_certificate_unittest/extensions_real.pem
index 5a475def8b0..9b2c15235a8 100644
--- a/chromium/net/data/parse_certificate_unittest/extensions_real.pem
+++ b/chromium/net/data/parse_certificate_unittest/extensions_real.pem
@@ -1,35 +1,85 @@
A real world extensions sequence (taken from Google's GAI2).
+#-----BEGIN EXTENSIONS-----
+SEQUENCE {
+ SEQUENCE {
+ # authorityKeyIdentifier
+ OBJECT_IDENTIFIER { 2.5.29.35 }
+ OCTET_STRING {
+ SEQUENCE {
+ [0 PRIMITIVE] { `c07a98688d89fbab05640c117daa7d65b8cacc4e` }
+ }
+ }
+ }
+ SEQUENCE {
+ # subjectKeyIdentifier
+ OBJECT_IDENTIFIER { 2.5.29.14 }
+ OCTET_STRING {
+ OCTET_STRING { `4add06161bbcf668b576f581b6bb621aba5a812f` }
+ }
+ }
+ SEQUENCE {
+ # keyUsage
+ OBJECT_IDENTIFIER { 2.5.29.15 }
+ BOOLEAN { `ff` }
+ OCTET_STRING {
+ BIT_STRING { `0106` }
+ }
+ }
+ SEQUENCE {
+ # authorityInfoAccess
+ OBJECT_IDENTIFIER { 1.3.6.1.5.5.7.1.1 }
+ OCTET_STRING {
+ SEQUENCE {
+ SEQUENCE {
+ # ocsp
+ OBJECT_IDENTIFIER { 1.3.6.1.5.5.7.48.1 }
+ [6 PRIMITIVE] { "http://g.symcd.com" }
+ }
+ }
+ }
+ }
+ SEQUENCE {
+ # basicConstraints
+ OBJECT_IDENTIFIER { 2.5.29.19 }
+ BOOLEAN { `ff` }
+ OCTET_STRING {
+ SEQUENCE {
+ BOOLEAN { `ff` }
+ INTEGER { 0 }
+ }
+ }
+ }
+ SEQUENCE {
+ # cRLDistributionPoints
+ OBJECT_IDENTIFIER { 2.5.29.31 }
+ OCTET_STRING {
+ SEQUENCE {
+ SEQUENCE {
+ [0] {
+ [0] {
+ [6 PRIMITIVE] { "http://g.symcb.com/crls/gtglobal.crl" }
+ }
+ }
+ }
+ }
+ }
+ }
+ SEQUENCE {
+ # certificatePolicies
+ OBJECT_IDENTIFIER { 2.5.29.32 }
+ OCTET_STRING {
+ SEQUENCE {
+ SEQUENCE {
+ OBJECT_IDENTIFIER { 1.3.6.1.4.1.11129.2.5.1 }
+ }
+ }
+ }
+ }
+}
+#-----END EXTENSIONS-----
-$ openssl asn1parse -i < [EXTENSIONS]
- 0:d=0 hl=3 l= 228 cons: SEQUENCE
- 3:d=1 hl=2 l= 31 cons: SEQUENCE
- 5:d=2 hl=2 l= 3 prim: OBJECT :X509v3 Authority Key Identifier
- 10:d=2 hl=2 l= 24 prim: OCTET STRING [HEX DUMP]:30168014C07A98688D89FBAB05640C117DAA7D65B8CACC4E
- 36:d=1 hl=2 l= 29 cons: SEQUENCE
- 38:d=2 hl=2 l= 3 prim: OBJECT :X509v3 Subject Key Identifier
- 43:d=2 hl=2 l= 22 prim: OCTET STRING [HEX DUMP]:04144ADD06161BBCF668B576F581B6BB621ABA5A812F
- 67:d=1 hl=2 l= 14 cons: SEQUENCE
- 69:d=2 hl=2 l= 3 prim: OBJECT :X509v3 Key Usage
- 74:d=2 hl=2 l= 1 prim: BOOLEAN :255
- 77:d=2 hl=2 l= 4 prim: OCTET STRING [HEX DUMP]:03020106
- 83:d=1 hl=2 l= 46 cons: SEQUENCE
- 85:d=2 hl=2 l= 8 prim: OBJECT :Authority Information Access
- 95:d=2 hl=2 l= 34 prim: OCTET STRING [HEX DUMP]:3020301E06082B060105050730018612687474703A2F2F672E73796D63642E636F6D
- 131:d=1 hl=2 l= 18 cons: SEQUENCE
- 133:d=2 hl=2 l= 3 prim: OBJECT :X509v3 Basic Constraints
- 138:d=2 hl=2 l= 1 prim: BOOLEAN :255
- 141:d=2 hl=2 l= 8 prim: OCTET STRING [HEX DUMP]:30060101FF020100
- 151:d=1 hl=2 l= 53 cons: SEQUENCE
- 153:d=2 hl=2 l= 3 prim: OBJECT :X509v3 CRL Distribution Points
- 158:d=2 hl=2 l= 46 prim: OCTET STRING [HEX DUMP]:302C302AA028A0268624687474703A2F2F672E73796D63622E636F6D2F63726C732F6774676C6F62616C2E63726C
- 206:d=1 hl=2 l= 23 cons: SEQUENCE
- 208:d=2 hl=2 l= 3 prim: OBJECT :X509v3 Certificate Policies
- 213:d=2 hl=2 l= 16 prim: OCTET STRING [HEX DUMP]:300E300C060A2B06010401D679020501
------BEGIN EXTENSIONS-----
-MIHkMB8GA1UdIwQYMBaAFMB6mGiNifurBWQMEX2qfWW4ysxOMB0GA1UdDgQWBBRK3QYWG7z2aLV
-29YG2u2IaulqBLzAOBgNVHQ8BAf8EBAMCAQYwLgYIKwYBBQUHAQEEIjAgMB4GCCsGAQUFBzABhh
-JodHRwOi8vZy5zeW1jZC5jb20wEgYDVR0TAQH/BAgwBgEB/wIBADA1BgNVHR8ELjAsMCqgKKAmh
-iRodHRwOi8vZy5zeW1jYi5jb20vY3Jscy9ndGdsb2JhbC5jcmwwFwYDVR0gBBAwDjAMBgorBgEE
-AdZ5AgUB
------END EXTENSIONS-----
+
+-----BEGIN CERTIFICATE-----
+MIIC8DCCAlmgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo4HnMIHkMB8GA1UdIwQYMBaAFMB6mGiNifurBWQMEX2qfWW4ysxOMB0GA1UdDgQWBBRK3QYWG7z2aLV29YG2u2IaulqBLzAOBgNVHQ8BAf8EBAMCAQYwLgYIKwYBBQUHAQEEIjAgMB4GCCsGAQUFBzABhhJodHRwOi8vZy5zeW1jZC5jb20wEgYDVR0TAQH/BAgwBgEB/wIBADA1BgNVHR8ELjAsMCqgKKAmhiRodHRwOi8vZy5zeW1jYi5jb20vY3Jscy9ndGdsb2JhbC5jcmwwFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEBBQUAA4GBADvoeG2V1j1q9xMZLBvCiK4iq/SNMvV8cWfPLdEcwsOH4um+iVzkNKtIkcI/la4rR54leGtPmhCkcv3P9wIMsAoIpFri5XR+ER05YGrJH2nzLmMm3J7va3oK4VRXmKpykXgEfh+PZU0fCxKsnCQPhBQaVS0fu/CdCbIIXFkyZYAm
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/extensions_subject_alt_name.pem b/chromium/net/data/parse_certificate_unittest/extensions_subject_alt_name.pem
deleted file mode 100644
index 98a59bd7169..00000000000
--- a/chromium/net/data/parse_certificate_unittest/extensions_subject_alt_name.pem
+++ /dev/null
@@ -1,15 +0,0 @@
-$ openssl asn1parse -i < [EXTENSIONS]
- 0:d=0 hl=2 l= 32 cons: SEQUENCE
- 2:d=1 hl=2 l= 30 cons: SEQUENCE
- 4:d=2 hl=2 l= 3 prim: OBJECT :X509v3 Subject Alternative Name
- 9:d=2 hl=2 l= 23 prim: OCTET STRING [HEX DUMP]:30158213656D657267656E6379737570706F72742E7573
------BEGIN EXTENSIONS-----
-MCAwHgYDVR0RBBcwFYITZW1lcmdlbmN5c3VwcG9ydC51cw==
------END EXTENSIONS-----
-
-$ openssl asn1parse -i < [SUBJECT ALT NAME]
- 0:d=0 hl=2 l= 21 cons: SEQUENCE
- 2:d=1 hl=2 l= 19 prim: cont [ 2 ]
------BEGIN SUBJECT ALT NAME-----
-MBWCE2VtZXJnZW5jeXN1cHBvcnQudXM=
------END SUBJECT ALT NAME-----
diff --git a/chromium/net/data/parse_certificate_unittest/extensions_unknown_critical.pem b/chromium/net/data/parse_certificate_unittest/extensions_unknown_critical.pem
deleted file mode 100644
index aa4503f5bb3..00000000000
--- a/chromium/net/data/parse_certificate_unittest/extensions_unknown_critical.pem
+++ /dev/null
@@ -1,9 +0,0 @@
-$ openssl asn1parse -i < [EXTENSIONS]
- 0:d=0 hl=2 l= 25 cons: SEQUENCE
- 2:d=1 hl=2 l= 23 cons: SEQUENCE
- 4:d=2 hl=2 l= 12 prim: OBJECT :1.2.840.113554.4.1.72585.0
- 18:d=2 hl=2 l= 1 prim: BOOLEAN :255
- 21:d=2 hl=2 l= 4 prim: OCTET STRING [HEX DUMP]:030203B8
------BEGIN EXTENSIONS-----
-MBkwFwYMKoZIhvcSBAGEtwkAAQH/BAQDAgO4
------END EXTENSIONS-----
diff --git a/chromium/net/data/parse_certificate_unittest/extensions_unknown_non_critical.pem b/chromium/net/data/parse_certificate_unittest/extensions_unknown_non_critical.pem
deleted file mode 100644
index 0814267d404..00000000000
--- a/chromium/net/data/parse_certificate_unittest/extensions_unknown_non_critical.pem
+++ /dev/null
@@ -1,8 +0,0 @@
-$ openssl asn1parse -i < [EXTENSIONS]
- 0:d=0 hl=2 l= 22 cons: SEQUENCE
- 2:d=1 hl=2 l= 20 cons: SEQUENCE
- 4:d=2 hl=2 l= 12 prim: OBJECT :1.2.840.113554.4.1.72585.0
- 18:d=2 hl=2 l= 4 prim: OCTET STRING [HEX DUMP]:030203B8
------BEGIN EXTENSIONS-----
-MBYwFAYMKoZIhvcSBAGEtwkABAQDAgO4
------END EXTENSIONS-----
diff --git a/chromium/net/data/parse_certificate_unittest/key_usage.pem b/chromium/net/data/parse_certificate_unittest/key_usage.pem
new file mode 100644
index 00000000000..be8e7f29ea7
--- /dev/null
+++ b/chromium/net/data/parse_certificate_unittest/key_usage.pem
@@ -0,0 +1,15 @@
+#-----BEGIN EXTENSION-----
+SEQUENCE {
+ # keyUsage
+ OBJECT_IDENTIFIER { 2.5.29.15 }
+ BOOLEAN { `ff` }
+ OCTET_STRING {
+ BIT_STRING { `05a0` }
+ }
+}
+#-----END EXTENSION-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICaDCCAdGgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo2AwXjAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwEB/zAOBgNVHQ8BAf8EBAMCBaAwDQYJKoZIhvcNAQEFBQADgYEAO+h4bZXWPWr3ExksG8KIriKr9I0y9XxxZ88t0RzCw4fi6b6JXOQ0q0iRwj+VritHniV4a0+aEKRy/c/3AgywCgikWuLldH4RHTlgaskfafMuYybcnu9regrhVFeYqnKReAR+H49lTR8LEqycJA+EFBpVLR+78J0JsghcWTJlgCY=
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/policies.pem b/chromium/net/data/parse_certificate_unittest/policies.pem
new file mode 100644
index 00000000000..ddf5e5decea
--- /dev/null
+++ b/chromium/net/data/parse_certificate_unittest/policies.pem
@@ -0,0 +1,27 @@
+#-----BEGIN EXTENSION-----
+SEQUENCE {
+ # certificatePolicies
+ OBJECT_IDENTIFIER { 2.5.29.32 }
+ OCTET_STRING {
+ SEQUENCE {
+ SEQUENCE {
+ OBJECT_IDENTIFIER { 1.2.392.200222.1.2.2.1 }
+ SEQUENCE {
+ SEQUENCE {
+ OBJECT_IDENTIFIER { 1.3.6.1.5.5.7.2.1 }
+ IA5String { "https://repo1.secomtrust.net/spcpp/cps/index.html" }
+ }
+ }
+ }
+ SEQUENCE {
+ OBJECT_IDENTIFIER { 1.2.392.200091.100.901.1 }
+ }
+ }
+ }
+}
+#-----END EXTENSION-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICwjCCAiugAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo4G5MIG2MB0GA1UdDgQWBBSLddWsywi+Dh9lt/pWvmynddqFrzAfBgNVHSMEGDAWgBSLddWsywi+Dh9lt/pWvmynddqFrzAMBgNVHRMEBTADAQH/MGYGA1UdIARfMF0wTQYKKoMIjJweAQICATA/MD0GCCsGAQUFBwIBFjFodHRwczovL3JlcG8xLnNlY29tdHJ1c3QubmV0L3NwY3BwL2Nwcy9pbmRleC5odG1sMAwGCiqDCIybG2SHBQEwDQYJKoZIhvcNAQEFBQADgYEAO+h4bZXWPWr3ExksG8KIriKr9I0y9XxxZ88t0RzCw4fi6b6JXOQ0q0iRwj+VritHniV4a0+aEKRy/c/3AgywCgikWuLldH4RHTlgaskfafMuYybcnu9regrhVFeYqnKReAR+H49lTR8LEqycJA+EFBpVLR+78J0JsghcWTJlgCY=
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/regenerate_pem_from_ascii.py b/chromium/net/data/parse_certificate_unittest/regenerate_pem_from_ascii.py
new file mode 100755
index 00000000000..bc9fd375cc3
--- /dev/null
+++ b/chromium/net/data/parse_certificate_unittest/regenerate_pem_from_ascii.py
@@ -0,0 +1,104 @@
+#!/usr/bin/python
+# Copyright (c) 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Given a path to a XXX.pem file, re-generates a CERTIFICATE.
+
+The .pem file is expected to contain comments that resemble:
+
+#-----BEGIN XXX-----
+<ascii-der values in here>
+#-----END XXX-----
+
+These are interpreted as substitutions to make inside of the Certificate
+template (v3_certificate_template.txt)
+"""
+
+import sys
+import os
+import re
+import base64
+import subprocess
+
+
+def read_file_to_string(path):
+ """Reads a file entirely to a string"""
+ with open(path, 'r') as f:
+ return f.read()
+
+
+def write_string_to_file(data, path):
+ """Writes a string to a file"""
+ print "Writing file %s ..." % (path)
+ with open(path, "w") as f:
+ f.write(data)
+
+
+def replace_string(original, start, end, replacement):
+ """Replaces the specified range of |original| with |replacement|"""
+ return original[0:start] + replacement + original[end:]
+
+
+def apply_substitution(template, name, value):
+ """Finds a section named |name| in |template| and replaces it with |value|."""
+ # Find the section |name| in |template|.
+ regex = re.compile(r'#-----BEGIN %s-----(.*?)#-----END %s-----' %
+ (re.escape(name), re.escape(name)), re.DOTALL)
+ m = regex.search(template)
+ if not m:
+ print "Couldn't find a section named %s in the template" % (name)
+ sys.exit(1)
+
+ return replace_string(template, m.start(1), m.end(1), value)
+
+
+def main():
+ if len(sys.argv) != 2:
+ print 'Usage: %s <PATH_TO_PEM>' % (sys.argv[0])
+ sys.exit(1)
+
+ pem_path = sys.argv[1]
+ orig = read_file_to_string(pem_path)
+
+ cert_ascii = read_file_to_string("v3_certificate_template.txt")
+
+ # Apply all substitutions described by comments in |orig|
+ regex = re.compile(r'#-----BEGIN ([\w ]+)-----(.*?)#-----END \1-----',
+ re.DOTALL)
+ num_matches = 0
+ for m in regex.finditer(orig):
+ num_matches += 1
+ cert_ascii = apply_substitution(cert_ascii, m.group(1), m.group(2))
+
+ if num_matches == 0:
+ print "Input did not contain any substitutions"
+ sys.exit(1)
+
+ # Convert the ascii-der to actual DER binary.
+ cert_der = None
+ try:
+ p = subprocess.Popen(['ascii2der'], stdout=subprocess.PIPE,
+ stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
+ cert_der = p.communicate(input=cert_ascii)[0]
+ except OSError as e:
+ print ('ERROR: Failed executing ascii2der.\n'
+ 'Make sure this is in your path\n'
+ 'Obtain it from https://github.com/google/der-ascii')
+ sys.exit(1)
+
+ # Replace the CERTIFICATE block with the newly generated one.
+ regex = re.compile(r'-----BEGIN CERTIFICATE-----\n(.*?)\n'
+ '-----END CERTIFICATE-----', re.DOTALL)
+ m = regex.search(orig)
+ if not m:
+ print "ERROR: Cannot find CERTIFICATE block in input"
+ sys.exit(1)
+ modified = replace_string(orig, m.start(1), m.end(1),
+ base64.b64encode(cert_der))
+
+ # Write back the .pem file.
+ write_string_to_file(modified, pem_path)
+
+main()
diff --git a/chromium/net/data/parse_certificate_unittest/subject_alt_name.pem b/chromium/net/data/parse_certificate_unittest/subject_alt_name.pem
new file mode 100644
index 00000000000..71033d8cd5a
--- /dev/null
+++ b/chromium/net/data/parse_certificate_unittest/subject_alt_name.pem
@@ -0,0 +1,16 @@
+#-----BEGIN EXTENSION-----
+SEQUENCE {
+ # subjectAltName
+ OBJECT_IDENTIFIER { 2.5.29.17 }
+ OCTET_STRING {
+ SEQUENCE {
+ [2 PRIMITIVE] { "emergencysupport.us" }
+ }
+ }
+}
+#-----END EXTENSION-----
+
+
+-----BEGIN CERTIFICATE-----
+MIICeDCCAeGgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo3AwbjAdBgNVHQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwEB/zAeBgNVHREEFzAVghNlbWVyZ2VuY3lzdXBwb3J0LnVzMA0GCSqGSIb3DQEBBQUAA4GBADvoeG2V1j1q9xMZLBvCiK4iq/SNMvV8cWfPLdEcwsOH4um+iVzkNKtIkcI/la4rR54leGtPmhCkcv3P9wIMsAoIpFri5XR+ER05YGrJH2nzLmMm3J7va3oK4VRXmKpykXgEfh+PZU0fCxKsnCQPhBQaVS0fu/CdCbIIXFkyZYAm
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/parse_certificate_unittest/tbs_v3_data_after_extensions.pem b/chromium/net/data/parse_certificate_unittest/tbs_v3_data_after_extensions.pem
index 7dc83279069..3981aa71cab 100644
--- a/chromium/net/data/parse_certificate_unittest/tbs_v3_data_after_extensions.pem
+++ b/chromium/net/data/parse_certificate_unittest/tbs_v3_data_after_extensions.pem
@@ -26,3 +26,9 @@ $ openssl asn1parse -i < [TBS CERTIFICATE]
MEWgAwIBAgIBATADBAEBMAMEAQUwHhcNMTIxMDE4MDMxMjAwWhcNMTMxMDE4MTQ1OTU5WjADBAG
DMAMEAfOjBTADBAHdBQA=
-----END TBS CERTIFICATE-----
+
+[Error] Unconsumed data inside TBSCertificate
+
+-----BEGIN ERRORS-----
+W0Vycm9yXSBVbmNvbnN1bWVkIGRhdGEgaW5zaWRlIFRCU0NlcnRpZmljYXRlCg==
+-----END ERRORS-----
diff --git a/chromium/net/data/parse_certificate_unittest/v3_certificate_template.txt b/chromium/net/data/parse_certificate_unittest/v3_certificate_template.txt
new file mode 100644
index 00000000000..54d2fb4d916
--- /dev/null
+++ b/chromium/net/data/parse_certificate_unittest/v3_certificate_template.txt
@@ -0,0 +1,127 @@
+# This is cert.pem from BoringSSL's tests.
+# https://boringssl.googlesource.com/boringssl/+/5acc423517ec9d53e6cf2cd1b968405e0972c745/ssl/test/runner/cert.pem
+
+# This file is itself valid ascii-der, however uses comments to name various
+# sections (using BEGIN and END). These named sections can be overlapping, and
+# are replaced for generating various test data.
+
+SEQUENCE {
+ SEQUENCE {
+ [0] {
+ INTEGER { 2 }
+ }
+ INTEGER { `00fbb04c2eab109b0c` }
+ SEQUENCE {
+ # sha1WithRSAEncryption
+ OBJECT_IDENTIFIER { 1.2.840.113549.1.1.5 }
+ NULL {}
+ }
+ SEQUENCE {
+ SET {
+ SEQUENCE {
+ # countryName
+ OBJECT_IDENTIFIER { 2.5.4.6 }
+ PrintableString { "AU" }
+ }
+ }
+ SET {
+ SEQUENCE {
+ # stateOrProvinceName
+ OBJECT_IDENTIFIER { 2.5.4.8 }
+ UTF8String { "Some-State" }
+ }
+ }
+ SET {
+ SEQUENCE {
+ # organizationName
+ OBJECT_IDENTIFIER { 2.5.4.10 }
+ UTF8String { "Internet Widgits Pty Ltd" }
+ }
+ }
+ }
+ SEQUENCE {
+ UTCTime { "140423205040Z" }
+ UTCTime { "170422205040Z" }
+ }
+ SEQUENCE {
+ SET {
+ SEQUENCE {
+ # countryName
+ OBJECT_IDENTIFIER { 2.5.4.6 }
+ PrintableString { "AU" }
+ }
+ }
+ SET {
+ SEQUENCE {
+ # stateOrProvinceName
+ OBJECT_IDENTIFIER { 2.5.4.8 }
+ UTF8String { "Some-State" }
+ }
+ }
+ SET {
+ SEQUENCE {
+ # organizationName
+ OBJECT_IDENTIFIER { 2.5.4.10 }
+ UTF8String { "Internet Widgits Pty Ltd" }
+ }
+ }
+ }
+ SEQUENCE {
+ SEQUENCE {
+ # rsaEncryption
+ OBJECT_IDENTIFIER { 1.2.840.113549.1.1.1 }
+ NULL {}
+ }
+ BIT_STRING {
+ `00`
+ SEQUENCE {
+ INTEGER { `00d82bc8a632e462ff4df3d0ad598b45a7bdf147bf09587b22bd35ae97258694a080c0b41f7691674631d01084b7221e70239172c8e96d793a8577800fc4951675c54a714cc8633fa3f2639c2a4f9afacbc1716e288528a0271e651cae07d55b6f2d43ed2b90b18caf246daee9173a05c1bfb81cae653b1b58c2d9aed6aa6788f1` }
+ INTEGER { 65537 }
+ }
+ }
+ }
+ [3] {
+#-----BEGIN EXTENSIONS-----
+ SEQUENCE {
+ SEQUENCE {
+ # subjectKeyIdentifier
+ OBJECT_IDENTIFIER { 2.5.29.14 }
+ OCTET_STRING {
+ OCTET_STRING { `8b75d5accb08be0e1f65b7fa56be6ca775da85af` }
+ }
+ }
+ SEQUENCE {
+ # authorityKeyIdentifier
+ OBJECT_IDENTIFIER { 2.5.29.35 }
+ OCTET_STRING {
+ SEQUENCE {
+ [0 PRIMITIVE] { `8b75d5accb08be0e1f65b7fa56be6ca775da85af` }
+ }
+ }
+ }
+
+ SEQUENCE {
+ # basicConstraints
+ OBJECT_IDENTIFIER { 2.5.29.19 }
+ OCTET_STRING {
+#-----BEGIN BASIC_CONSTRAINTS-----
+ SEQUENCE {
+ BOOLEAN { `ff` }
+ }
+#-----END BASIC_CONSTRAINTS-----
+ }
+ }
+#-----BEGIN EXTENSION-----
+# (For adding in another extension at the end of the list)
+#-----END EXTENSION-----
+ }
+#-----END EXTENSIONS-----
+ }
+ }
+ SEQUENCE {
+ # sha1WithRSAEncryption
+ OBJECT_IDENTIFIER { 1.2.840.113549.1.1.5 }
+ NULL {}
+ }
+ BIT_STRING { `003be8786d95d63d6af713192c1bc288ae22abf48d32f57c7167cf2dd11cc2c387e2e9be895ce434ab4891c23f95ae2b479e25786b4f9a10a472fdcff7020cb00a08a45ae2e5747e111d39606ac91f69f32e6326dc9eef6b7a0ae1545798aa729178047e1f8f654d1f0b12ac9c240f84141a552d1fbbf09d09b2085c5932658026` }
+}
diff --git a/chromium/net/data/ssl/certificates/README b/chromium/net/data/ssl/certificates/README
index 079fdbecac5..0e199edc7e8 100644
--- a/chromium/net/data/ssl/certificates/README
+++ b/chromium/net/data/ssl/certificates/README
@@ -58,6 +58,15 @@ unit tests.
- twitter-chain.pem : A certificate chain for twitter.com which should be
valid. Expires May 9 2016.
+- tripadvisor-verisign-chain.pem: A certificate chain for www.tripadvisor.com
+ issued by VeriSign Class 3 Public Primary Certification Authority - G5.
+ Expires Apr 2 2018.
+- verisign_class3_g5_crosssigned.pem: The SHA1 cross-signed version of
+ VeriSign Class 3 Public Primary Certification Authority - G5
+- verisign_class3_g5_crosssigned-trusted.keychain: OSX Keychain set to Always
+ Trust the certificate in verisign_class3_g5_crosssigned.pem (Generated by
+ scripts/generate-verisign_class3_g5_crosssigned-trusted-keychain.sh)
+
===== Manually generated certificates
- client.p12 : A PKCS #12 file containing a client certificate and a private
key created for testing. The password is "12345".
@@ -216,6 +225,11 @@ unit tests.
- client_3.key
- client_3.pk8
- client_3_ca.pem
+- client_4.pem
+- client_4.key
+- client_4.pk8
+- client_4_ca.pem
+- client_root_ca.pem
This is a set of files used to unit test SSL client certificate
authentication.
- client_1_ca.pem and client_2_ca.pem are the certificates of
@@ -230,17 +244,9 @@ unit tests.
to test wifi EAP-TLS authentication so it uses a different set
of X509v3 extensions. Specifically it includes two Subject
Alternative Name fields recognized by Chrome OS.
-
-===== From net/data/ssl/scripts/generate-android-test-key.sh
-- android-test-key-rsa.pem
-- android-test-key-dsa.pem
-- android-test-key-dsa-public.pem
-- android-test-key-ecdsa.pem
-- android-test-key-ecdsa-public.pem
- This is a set of test RSA/DSA/ECDSA keys used by the Android-specific
- unit test in net/android/keystore_unittest.c. They are used to verify
- that the OpenSSL-specific wrapper for platform PrivateKey objects
- works properly. See the generate-android-test-keys.sh script.
+ - client_4.pem is similar to client_2.pem but is a P-256 ECDSA key rather
+ than RSA.
+ - client_root_ca.pem is the CA certificate which signed client_*_ca.pem.
===== From net/data/ssl/scripts/generate-bad-eku-certs.sh
- eku-test-root.pem
@@ -260,6 +266,10 @@ unit tests.
interfere with the chain_verify_callback used by CertVerifyProcChromeOS.
See CertVerifyProcChromeOSTest.
+===== From net/data/ssl/scripts/generate-multi-root-BFE-keychain.sh
+- multi-root-BFE.keychain: An OSX Keychain containing the generated
+ certificates "multi-root-B-by-F.pem" and "multi-root-F-by-E.pem".
+
===== From net/data/ssl/scripts/generate-duplicate-cn-certs.sh
- duplicate_cn_1.p12
- duplicate_cn_1.pem
diff --git a/chromium/net/data/ssl/certificates/android-test-key-dsa-public.pem b/chromium/net/data/ssl/certificates/android-test-key-dsa-public.pem
deleted file mode 100644
index f9968099d9c..00000000000
--- a/chromium/net/data/ssl/certificates/android-test-key-dsa-public.pem
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN PUBLIC KEY-----
-MIIDRjCCAjkGByqGSM44BAEwggIsAoIBAQDaJruwQmE1uMS2WnGl6L2UQy8iHmcs
-74gWjym/8HVVdLXsC3wGoXGj0vj3Zr7DpgzrXBAWj2JILVApJgbFIbEFLAHcv6Bd
-/3PjbRrva4PMQypul1o+j9IiFn2oemeVoCz77mz5aczfq7AoiMnMpdP501qcAOF2
-gDR61r1BO8QRV9gkbOLpZHX101NB9GW+PKR7C+SJBN5rVVX2YgtxPe/Km5jFgIuS
-P76eSvxGh1kUApFDhqEDh7Gck5Slt6lJDPj399MZC74XrrdbjrZbO/jt5TsLxRac
-SvI0waX+49+UnHYb3cjPynMkBgLDl7itMluTm3nS8IkgKKgYPiEAXlKbAiEAu0Ip
-TvTF7SfYMd5me26T40Fa2mAWYzWQLF10WvqheOcCggEAarH6R0LvhcWInCB1Yr4U
-FA3QjynYWfxZZ6g+Tf/NxPQmVj720SEm+QfiZnrtSReTctBHJPkcrzHVU53LNVPx
-CxvoVJUEdUhxWUV0o0PXBUfJZB3JdVXLGEu4MlXkwFh87+S3Y/+9yeMog3SaaqDA
-cISNUQSWd+q5oiAeFdYiaTjY+qD+UGBChL/w8QSrr0BRiHF1EskKI3bFmqQzDjD7
-9xm4wEGUiMvF+dHa50rjIzD+EyWvbkq3HonB7N7DDciVQ1V/qGmI6dvP5yf/Ml90
-YDL8QIrXWP2p81FlvfU3QE9tjI6Bo5cjTavRU7WORN0it9B3pmvyL++E1EGd6hBr
-qwOCAQUAAoIBAFR3VCzbhpt1iR/LpAlN2QIeQ4r2vkng6CJaxSQZBKBc1CjFHAXy
-4QIThVpagyH+QM4I5pPIxkcXpFwEPHzuZow8/4DMA6IlPJ6R8ih1IgWGqzASzXYv
-ZrlasBUjTS4no54L9PueAfZ2G0Rc9ePZ8snH9zsQVu5Rd2+zUkAUzR0jCT/zveeQ
-t9c/px8356C4beEUAFoiXbSNMDruVdFemEwC5oCIwMBamPUxf//Og74Wg0W/0DNW
-j8ffKNht51i+537vjBjVlLd/ETXARhAZg83jcqKKG0I4hECFZE5xBl0flU82pQAf
-eKk0vNRiuAXKgxNor+pnpXC3qqMkxuwQBls=
------END PUBLIC KEY-----
diff --git a/chromium/net/data/ssl/certificates/android-test-key-dsa.pem b/chromium/net/data/ssl/certificates/android-test-key-dsa.pem
deleted file mode 100644
index 3e0ec612701..00000000000
--- a/chromium/net/data/ssl/certificates/android-test-key-dsa.pem
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN DSA PRIVATE KEY-----
-MIIDVQIBAAKCAQEA2ia7sEJhNbjEtlpxpei9lEMvIh5nLO+IFo8pv/B1VXS17At8
-BqFxo9L492a+w6YM61wQFo9iSC1QKSYGxSGxBSwB3L+gXf9z420a72uDzEMqbpda
-Po/SIhZ9qHpnlaAs++5s+WnM36uwKIjJzKXT+dNanADhdoA0eta9QTvEEVfYJGzi
-6WR19dNTQfRlvjykewvkiQTea1VV9mILcT3vypuYxYCLkj++nkr8RodZFAKRQ4ah
-A4exnJOUpbepSQz49/fTGQu+F663W462Wzv47eU7C8UWnEryNMGl/uPflJx2G93I
-z8pzJAYCw5e4rTJbk5t50vCJICioGD4hAF5SmwIhALtCKU70xe0n2DHeZntuk+NB
-WtpgFmM1kCxddFr6oXjnAoIBAGqx+kdC74XFiJwgdWK+FBQN0I8p2Fn8WWeoPk3/
-zcT0JlY+9tEhJvkH4mZ67UkXk3LQRyT5HK8x1VOdyzVT8Qsb6FSVBHVIcVlFdKND
-1wVHyWQdyXVVyxhLuDJV5MBYfO/kt2P/vcnjKIN0mmqgwHCEjVEElnfquaIgHhXW
-Imk42Pqg/lBgQoS/8PEEq69AUYhxdRLJCiN2xZqkMw4w+/cZuMBBlIjLxfnR2udK
-4yMw/hMlr25Ktx6Jwezeww3IlUNVf6hpiOnbz+cn/zJfdGAy/ECK11j9qfNRZb31
-N0BPbYyOgaOXI02r0VO1jkTdIrfQd6Zr8i/vhNRBneoQa6sCggEAVHdULNuGm3WJ
-H8ukCU3ZAh5Diva+SeDoIlrFJBkEoFzUKMUcBfLhAhOFWlqDIf5Azgjmk8jGRxek
-XAQ8fO5mjDz/gMwDoiU8npHyKHUiBYarMBLNdi9muVqwFSNNLiejngv0+54B9nYb
-RFz149nyycf3OxBW7lF3b7NSQBTNHSMJP/O955C31z+nHzfnoLht4RQAWiJdtI0w
-Ou5V0V6YTALmgIjAwFqY9TF//86DvhaDRb/QM1aPx98o2G3nWL7nfu+MGNWUt38R
-NcBGEBmDzeNyooobQjiEQIVkTnEGXR+VTzalAB94qTS81GK4BcqDE2iv6melcLeq
-oyTG7BAGWwIgUF1cgjzMuvW665RmAumSL2vvkRuNm54i8cHSq53ZVq8=
------END DSA PRIVATE KEY-----
diff --git a/chromium/net/data/ssl/certificates/android-test-key-ecdsa-public.pem b/chromium/net/data/ssl/certificates/android-test-key-ecdsa-public.pem
deleted file mode 100644
index 451262259ab..00000000000
--- a/chromium/net/data/ssl/certificates/android-test-key-ecdsa-public.pem
+++ /dev/null
@@ -1,4 +0,0 @@
------BEGIN PUBLIC KEY-----
-MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJH4uX5l3CYLPIQ7tXxBjtPZN7HVf
-l4uyPAs6VCPitxLjEcKq3w/wwnPAbhbXN7bnC6lq1Yro/5vlpa1RGB46yQ==
------END PUBLIC KEY-----
diff --git a/chromium/net/data/ssl/certificates/android-test-key-ecdsa.pem b/chromium/net/data/ssl/certificates/android-test-key-ecdsa.pem
deleted file mode 100644
index 6f128bde2bd..00000000000
--- a/chromium/net/data/ssl/certificates/android-test-key-ecdsa.pem
+++ /dev/null
@@ -1,8 +0,0 @@
------BEGIN EC PARAMETERS-----
-BggqhkjOPQMBBw==
------END EC PARAMETERS-----
------BEGIN EC PRIVATE KEY-----
-MHcCAQEEIFb6/5kje8LB6bKDjQbfr2d4wfvLjy+SNs7j4J1eEF+FoAoGCCqGSM49
-AwEHoUQDQgAEJH4uX5l3CYLPIQ7tXxBjtPZN7HVfl4uyPAs6VCPitxLjEcKq3w/w
-wnPAbhbXN7bnC6lq1Yro/5vlpa1RGB46yQ==
------END EC PRIVATE KEY-----
diff --git a/chromium/net/data/ssl/certificates/android-test-key-rsa.pem b/chromium/net/data/ssl/certificates/android-test-key-rsa.pem
deleted file mode 100644
index cd771fb6d88..00000000000
--- a/chromium/net/data/ssl/certificates/android-test-key-rsa.pem
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpAIBAAKCAQEAtGeaaS0gTqtgxhVXHEvwq04nAj8G0VCC8QjJW1ULVA576lhy
-3IfdP3CxSLUYaJ4QNlXswDkbV8U8VPwresHqd1OTcCII774hLNFw7QtTmi1dM3rL
-kOHApeCUa32VzZSuzCyu9f2/T4HvEH367GDTIxk1NEoXKSuehjMUFiqmtJEZjHSK
-agq3p8NLTP/WpMm1WfEg5QRBQaQ82hOYN8CDaRSOW2GuHw+qZAtA7n033yX8cu3H
-khPT5INk04/byZVDMNK1hbf90y+0XeZRZAKZ9rklMnz3jPJvLLsVwSMexJnRbe/G
-cQyE9V1jHN9aGeBlm+9xvv3VjddNhaxhYLDYuQIDAQABAoIBAF5MCRoQzGJSkjL3
-1KCl0Ra5swoph5bBTrBOt3FV8qXtLDhCI0fCfJM8hG5MuoV0mWTNZQLU1sX6Ap8p
-cFCqK7RTqy1hnOozp4OVtkExOnHMZHsUJHOGjPwnd2z4J+VdYkC22n0aNXWJpTwp
-nY8QzUv7USQT1ide9W2QJV+wy5J1pQt4U/TH44FD6ceYXzEKCwHb1FXK4YOS0xgR
-mW3gKFdHAYwk6OTyJOTLoa8zRL+8w7cTx2uNbf5EXeSMPjVl6SsVqJxOoBxVhi6M
-Hj/pV4xs2sF2iqRlRZLpR5nOeJEwiELCymDgSzvSh0PZKAQzEvdYbH91vSEu6d+Q
-gSGgkAECgYEA1wepPWDJyYPXPfemqeNrq7uVMwO3EI9IwlI+ouZ1sPHDEcQ3dNGw
-5/QK7mgG++Wn+EfDkD1U26qGaGiWlCHTC/YlQ1tyrw3KqqV4QT+AIHJnr52PMUTu
-vpSUJEfLMEboa8nsdHRHvScqqhijgI5fY4RJa20EVAjA0DRB/BSyEuECgYEA1scO
-Q7s0jXWIfK/Y0z8WFfcHd1+xdIEueGqfI/Qx57Gsaen6mOKC6nESzq2GOiiXdX4X
-NzdqPhZ1TWt+8FtSjDx61xFYldVf/0mSMn0skUSshKkBxZoKT65mmH2aRn9Mh1W7
-PaIN/JCi20kaZqhbaNhPi/Dd6SK2CIJco9Dx2NkCgYEAjHYqrTdeWM5QeeAd9Hfk
-S4f7TBmvKZgPVTBYThzw4Cbs39wmxZ58Suh1g4pclYtND7gBHWWS2vMnXWiEhDsc
-G4IskTVZUtRVgOcaCLUsQwW4iVUIxoxa0A9KPfDP37dR96ctWFzkx8Cf9ACoPT/D
-O8ScGRpba3FUUizwtXPnZsECgYA7ltjPU/ZdtRlcNtG6sosnJvWsWiF7CIhjInnq
-2Mqr1PDYJfHAT0AxWZP1QdG2+yIimAxK5pYUidib1VJPz5aUkAco+ogQcjYDN19X
-oMEnwNz4pYd3Uqi/uMyATIDsRE9wUQn1LKwiweJdYufvSZCrAzD2y6pWD6pfrAOV
-89fV6QKBgQDADTt1uVUPm2XpAkRAgKT7hncHnMcVqXvQsrqbHlbC7SARTbX0lUga
-eO18L/k3h5XGXSQbVeVHdo5EZOEqQkiGcQbOgtRosMp/+6XtPMyvMMxWRhjIcyAJ
-5czOAcXm8iVv7m89w+QnK+zMsLkY0j0X70lDXq7Tui+VH9lXa4wjtw==
------END RSA PRIVATE KEY-----
diff --git a/chromium/net/data/ssl/certificates/client_1.key b/chromium/net/data/ssl/certificates/client_1.key
index f09bd994ebd..ea61cc86221 100644
--- a/chromium/net/data/ssl/certificates/client_1.key
+++ b/chromium/net/data/ssl/certificates/client_1.key
@@ -1,27 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
-MIIEpAIBAAKCAQEA0b2s/Agv3LIaQmnyaOIy5BxKAagy4XYBXpSaAIkFMiKslpdj
-u2Bz56SR/k4Ee6Hpczc7f5C0XB/PTP07Mwes6si0wuGqpr8yi9KXg/4y9i1gbnEd
-FlyL4wN86Ebhf8fOvq2B97R2/sbNj0rPBBi/xL/rLPqk80xhJ9un7hjR5DcOrTsD
-6XPqPPsFLc3/5ALYWpqPnCA7Nq0PpT+/mi2Uy3lP6uIHC7rZc3CuYpnsecctoz5M
-HquPJIoytJCM5dXD5QOXdc+wvI1OdD4/V/bEAyUzd9o+1GEYrCXnmEBfBmmjfEm6
-wyOsx4Cs60S8sQ7fykGvVYi3lwDYGYvl8fSoHwIDAQABAoIBAQCtFY0ic5Mj2mpn
-Mk1Ulo6OxnWgRnCutJZOue0Y0fpStGCe6ZHo+KDNoXbFWRbD/ArOBN951y2v9KQ7
-EaL/6q6dFkJtrJMKhjAtSP22dFkT5MB2g6wQXxElpyQ1/wBqVbZcjoz5oJiuidrr
-DD4oUFA5CnQGK1ViXj6zCMbdaugTHonM7N6q4jJrWN21HOFMlMCeX4Qy47IR737i
-KWEMiOhF2TOnWZLJ/S8pVyZ4oGOkCR8TmDtAQ8DrGfMkPCfGny5PPItBosxJIBNc
-90RLUFMIFn8a9Vlf7nfk+v2YUgIB/dONpkL0hWZyFEhLJgr44VrgLp38Rygk3AKG
-CEln81qZAoGBAO4KX9xx1OU5/goFJ9V+bhqRtw5nDIH3hoLNq9n/yCIP+QHNXX2C
-C4smy9bTfc28iwiX3GxaVgXPYSS+nwj3OYVIsFhSagSXsMUJAtQHvx2pB24qfiGf
-ia9PONjuAQAK74sZOC2+/zdgrfbExDSTukbSvZWxGebiutQ4JR8vAktlAoGBAOGQ
-taN+pDwDEAYIGo4J7nG9srlBHpZNHwBK/hiN9jBhPvd8TK+6wIQaKi4OACE8iHxJ
-zkkOR8GoJyB6JwW79S1fxn/bq7MfGWDhm70/M88wvklNW5A83YwGJxUFRiIzLSjg
-SdytO/vsqcF9X6+ELEPLii/FkjlsLWdwcpul4mczAoGAA54cvtjsB1/OQJC7fj8h
-pT25rnpack80uCAwEGwWuo3Llv9sAFBNpJu+VVF5g/rtkf/c1bi5vfTc4RYUjKpV
-MXVdWLpH6jHz+cqdRGOpv+Wlu0LiD9jA2u01S/ayBTIlWdPUSr2wW0MY4bsz0Ci+
-l/zz7KZ4Yk3n0PnZdpPcURECgYBw0nzHxjRHgBCns630lasaYRPf7V5rNy/maZwm
-k/srv7hK+XUyAGsCqEOovX/7H9f0ssXnbKkfiAfqCq8yAw1jIKCcmzeKZGfBOZc4
-VUCIxYyoBXVi886slvc9YGHwAUD5TRYkttFl9L4D9b3CgI3Tax83Pc8hwaYEMw5g
-I9zWWQKBgQCPLyginR+8N2i+QjZGUNm7iHljQNh2Ws1cABhuRdk1Py5l30SpxunV
-+W5FPgJAWYeeozWcv/4XxUnsCQeCpG7gexEUnWjWzttc17fRRAN/s9EXzHf2b9r5
-SFjkgeZ85f+1CrYt7K4myurPWVS34ksaYj0PHf4ZkhsJ+JLK1lLCQw==
+MIIEpAIBAAKCAQEAm6YXgn7EzskCJawNsyffHz5P/wgyL9LkkYDzyFXqSGl2Rs66
+YlPkfBQVHAJXXcRMZL6GJ0qi32cpWgEsbXSk1zAiySVDayNej+jXNsQRoa9HE1lG
+6SvH5ojlGhiRV9r9c2a55L6HePnG3B9BTU1nPT01fGqnYpaUxVDxqwMHeG1xdfvx
+SEvrDsKWjYOSxVgbXGGDTwhMhA1rF1X+e9yimag0UxsB1IhNxd5YCJVRyaVTnxM+
+KmUe0OUYAXuKMGFGeT0W99M7YA3v6o2ZbPy3LZ07lwuP8w6egk5pjDo8v81FCUZn
+Vhv/xHVr/1JH98X+heE6eCq4yC+NXrdLiLGzywIDAQABAoIBACa5VuYHhg1wYxFe
+UfY9uDw8s4he0KWnUWiF7aDtByHG4z9QlXx7JMBd+raCOpxAh0UVRakm34i3UMls
+u1HsEErdVfo3RCO2pAMnyct9UmmogwVkU8kVNGG9s0ofzKFQAXihmSQ45tmJQxlm
+yUdjN4k73j+7BTP5BMBmmAmU8lnadWGIX97WG6hbB5mjfzIGlZM11kUlaIFnm9/f
+UbrazpB6CdTeS5eML4ikLYfSoM/5r6r1gT01B8q16ZDEW5/mSmAgTPvyEY4XdKpZ
+te2KOJFs9EfPn1VgSpN5ebnwRVnXKEYM6VRi2Ssn5YwQs8zS1+Fd95VBANVwS+yj
+rehgaqECgYEAzK6Ru/iCJj4ecSXiuIN15H9mAcAG6WQmuPCLUc0eyvUZ0Mj57yjg
+irJjflScLcotR/YdBUfUX+//XDBiQ9lVWCmFtHwWoynMBC4p+mBcVbId1LEk/kn4
+Oyx2Zkp7ccIpOe5JU8788GSroZzvQs9Ic2AI3hz/vC+igokNQJiUd5ECgYEAwqxZ
+x2tLz1vNLDlfXhaFkhpttJoUV+rQteV9SsEqcAOBLgBqk49hwFTInQELpEtrzfo9
+3IW1C7C/e378OOlw+fBnBtmkTDfPy9XJd6b+VQWHsk/t1g2D2qYO0htrfwNpIe5V
+Ns15MGiMV7kA8KELx+gAokSUws90StTqtJFG35sCgYEAxMSRr23w2IjhRQ8RzSX8
+AQWEb+xF+LriCuqcVLBniN9lyPRcadEXQ97IjRsT5WU2cLamIXxzKyOSjvKolOdr
+B00rj123eXXl/qLOkjdurKeFzAHcOWWs8F4HGMFDuRHaBioQbjRPr15oLP6seMLC
+uL+65qRkKWp1xR2yEsZb/DECgYAbwLRf4KUDH8RFPLyizjUmmgvvxlOGIRy2Acx1
+3sntBCLjav3GoZc+8xdSgralKndo+vbcvFcOHpl9wqG0f1sy1pnpeReaIg7GsWiy
+XSU++7XXrttqO60De877FxuhFNxlEPQnBu3y/8SaMO64X00tp56Hg51tlGOw01/O
+dDOVZwKBgQCKvxUHZPD6Q+M5HI/HmFxsHj9SsSl2sACErQMk7ru/aimuz9YPBXks
+KeMzjIeRqtJadK9KQCBeGWmOFTLezgt+mceXn92nfNYMfdSkLzlyKZM2FW9Kk1Z/
+7YduboDUCiGg2PMn/qZPUiko3vkR6B3es/G+VC16mCrh9GksfsGHVg==
-----END RSA PRIVATE KEY-----
diff --git a/chromium/net/data/ssl/certificates/client_1.pem b/chromium/net/data/ssl/certificates/client_1.pem
index 2d5ec769ea7..33573d35a3f 100644
--- a/chromium/net/data/ssl/certificates/client_1.pem
+++ b/chromium/net/data/ssl/certificates/client_1.pem
@@ -5,31 +5,31 @@ Certificate:
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=B CA
Validity
- Not Before: Feb 28 20:27:03 2016 GMT
- Not After : Feb 25 20:27:03 2026 GMT
+ Not Before: Oct 4 18:53:24 2016 GMT
+ Not After : Oct 2 18:53:24 2026 GMT
Subject: CN=Client Cert A
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:d1:bd:ac:fc:08:2f:dc:b2:1a:42:69:f2:68:e2:
- 32:e4:1c:4a:01:a8:32:e1:76:01:5e:94:9a:00:89:
- 05:32:22:ac:96:97:63:bb:60:73:e7:a4:91:fe:4e:
- 04:7b:a1:e9:73:37:3b:7f:90:b4:5c:1f:cf:4c:fd:
- 3b:33:07:ac:ea:c8:b4:c2:e1:aa:a6:bf:32:8b:d2:
- 97:83:fe:32:f6:2d:60:6e:71:1d:16:5c:8b:e3:03:
- 7c:e8:46:e1:7f:c7:ce:be:ad:81:f7:b4:76:fe:c6:
- cd:8f:4a:cf:04:18:bf:c4:bf:eb:2c:fa:a4:f3:4c:
- 61:27:db:a7:ee:18:d1:e4:37:0e:ad:3b:03:e9:73:
- ea:3c:fb:05:2d:cd:ff:e4:02:d8:5a:9a:8f:9c:20:
- 3b:36:ad:0f:a5:3f:bf:9a:2d:94:cb:79:4f:ea:e2:
- 07:0b:ba:d9:73:70:ae:62:99:ec:79:c7:2d:a3:3e:
- 4c:1e:ab:8f:24:8a:32:b4:90:8c:e5:d5:c3:e5:03:
- 97:75:cf:b0:bc:8d:4e:74:3e:3f:57:f6:c4:03:25:
- 33:77:da:3e:d4:61:18:ac:25:e7:98:40:5f:06:69:
- a3:7c:49:ba:c3:23:ac:c7:80:ac:eb:44:bc:b1:0e:
- df:ca:41:af:55:88:b7:97:00:d8:19:8b:e5:f1:f4:
- a8:1f
+ 00:9b:a6:17:82:7e:c4:ce:c9:02:25:ac:0d:b3:27:
+ df:1f:3e:4f:ff:08:32:2f:d2:e4:91:80:f3:c8:55:
+ ea:48:69:76:46:ce:ba:62:53:e4:7c:14:15:1c:02:
+ 57:5d:c4:4c:64:be:86:27:4a:a2:df:67:29:5a:01:
+ 2c:6d:74:a4:d7:30:22:c9:25:43:6b:23:5e:8f:e8:
+ d7:36:c4:11:a1:af:47:13:59:46:e9:2b:c7:e6:88:
+ e5:1a:18:91:57:da:fd:73:66:b9:e4:be:87:78:f9:
+ c6:dc:1f:41:4d:4d:67:3d:3d:35:7c:6a:a7:62:96:
+ 94:c5:50:f1:ab:03:07:78:6d:71:75:fb:f1:48:4b:
+ eb:0e:c2:96:8d:83:92:c5:58:1b:5c:61:83:4f:08:
+ 4c:84:0d:6b:17:55:fe:7b:dc:a2:99:a8:34:53:1b:
+ 01:d4:88:4d:c5:de:58:08:95:51:c9:a5:53:9f:13:
+ 3e:2a:65:1e:d0:e5:18:01:7b:8a:30:61:46:79:3d:
+ 16:f7:d3:3b:60:0d:ef:ea:8d:99:6c:fc:b7:2d:9d:
+ 3b:97:0b:8f:f3:0e:9e:82:4e:69:8c:3a:3c:bf:cd:
+ 45:09:46:67:56:1b:ff:c4:75:6b:ff:52:47:f7:c5:
+ fe:85:e1:3a:78:2a:b8:c8:2f:8d:5e:b7:4b:88:b1:
+ b3:cb
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints: critical
@@ -37,36 +37,36 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 45:11:56:e6:62:5f:b6:46:d3:70:ac:37:ed:44:31:75:bf:64:
- 14:6d:c3:76:a2:e4:a7:40:31:f1:78:34:1d:4a:06:ac:2f:34:
- f7:ba:2f:22:62:ed:11:c3:65:96:71:9d:03:57:97:b4:ce:d1:
- 8f:85:6a:bb:00:ed:01:d7:6d:1a:15:13:0e:63:ee:3e:6f:3b:
- bd:43:61:45:91:0a:9c:ef:f7:ca:4e:f4:c3:cc:82:48:e7:0a:
- cc:9c:5b:d4:7f:3c:ef:c6:1d:ce:1d:63:18:4a:cf:f0:82:2a:
- b7:de:14:ca:78:71:2a:e8:9c:a4:dd:bb:42:9f:2d:18:71:e7:
- 32:73:7c:86:5c:7d:74:b2:2c:d4:7e:21:e5:86:f8:82:90:3b:
- 84:4a:4f:26:14:3c:03:0f:3a:96:64:5d:08:8a:9c:c5:6c:40:
- c7:a0:8c:4b:96:6d:c6:43:1a:62:2e:81:15:e2:4f:0a:60:9a:
- 77:47:92:81:2c:5c:b1:33:a5:06:3f:3f:21:ef:69:88:3c:22:
- 69:d9:1b:8a:31:88:05:f7:55:03:bd:5c:ef:9d:89:ba:4d:fb:
- 1e:33:6f:9e:c0:a8:ab:0b:4d:06:3a:b6:7b:ac:47:05:be:dc:
- 67:29:2a:98:7f:87:24:a9:f3:5d:49:4d:58:f9:14:42:d6:78:
- 16:67:b2:21
+ 19:9b:41:39:61:cf:f8:0f:62:98:43:1a:a4:fb:0b:71:f2:f0:
+ c4:b5:39:bb:dc:d1:d7:33:44:89:66:13:ff:0a:5a:66:02:74:
+ 6a:8d:8a:dc:a0:e0:d0:cc:8d:5f:1c:c0:34:c6:58:02:76:3b:
+ b5:1a:81:a5:a7:a1:c5:81:14:52:0f:21:37:06:2d:dc:dc:9c:
+ d0:d1:98:03:ac:d3:b5:12:0b:f8:b4:84:d8:bc:be:4d:27:fa:
+ df:16:6e:dd:0a:33:b7:87:50:7e:fe:c6:8d:84:b2:2d:7f:58:
+ 88:21:af:09:64:5e:4a:2d:f0:56:d4:3e:a3:dc:4c:aa:92:41:
+ 04:c1:6e:56:46:d5:36:69:0d:2a:f6:f0:29:d3:7c:ac:b7:cf:
+ 7f:18:bc:76:fa:8c:5a:76:81:67:db:b2:91:97:05:7d:14:da:
+ 26:d5:67:fe:c5:d2:6a:2c:5f:f4:96:3a:e4:0e:f5:15:95:05:
+ 57:de:b5:e5:96:b2:10:99:4a:b2:3a:ac:d2:ae:64:30:31:54:
+ f0:b9:9f:1d:56:e8:da:e9:4e:42:e3:26:3d:f7:8c:3e:9c:dd:
+ 42:77:9d:0c:67:52:73:94:c4:73:42:c2:b7:96:a4:44:4a:d5:
+ e9:3d:b1:46:aa:38:0b:1f:7f:ae:01:c6:07:da:40:3b:c0:22:
+ 61:c4:cb:80
-----BEGIN CERTIFICATE-----
MIIC0jCCAbqgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEQiBD
-QTAeFw0xNjAyMjgyMDI3MDNaFw0yNjAyMjUyMDI3MDNaMBgxFjAUBgNVBAMMDUNs
-aWVudCBDZXJ0IEEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRvaz8
-CC/cshpCafJo4jLkHEoBqDLhdgFelJoAiQUyIqyWl2O7YHPnpJH+TgR7oelzNzt/
-kLRcH89M/TszB6zqyLTC4aqmvzKL0peD/jL2LWBucR0WXIvjA3zoRuF/x86+rYH3
-tHb+xs2PSs8EGL/Ev+ss+qTzTGEn26fuGNHkNw6tOwPpc+o8+wUtzf/kAthamo+c
-IDs2rQ+lP7+aLZTLeU/q4gcLutlzcK5imex5xy2jPkweq48kijK0kIzl1cPlA5d1
-z7C8jU50Pj9X9sQDJTN32j7UYRisJeeYQF8GaaN8SbrDI6zHgKzrRLyxDt/KQa9V
-iLeXANgZi+Xx9KgfAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYI
-KwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBFEVbmYl+2RtNw
-rDftRDF1v2QUbcN2ouSnQDHxeDQdSgasLzT3ui8iYu0Rw2WWcZ0DV5e0ztGPhWq7
-AO0B120aFRMOY+4+bzu9Q2FFkQqc7/fKTvTDzIJI5wrMnFvUfzzvxh3OHWMYSs/w
-giq33hTKeHEq6Jyk3btCny0Ycecyc3yGXH10sizUfiHlhviCkDuESk8mFDwDDzqW
-ZF0IipzFbEDHoIxLlm3GQxpiLoEV4k8KYJp3R5KBLFyxM6UGPz8h72mIPCJp2RuK
-MYgF91UDvVzvnYm6TfseM2+ewKirC00GOrZ7rEcFvtxnKSqYf4ckqfNdSU1Y+RRC
-1ngWZ7Ih
+QTAeFw0xNjEwMDQxODUzMjRaFw0yNjEwMDIxODUzMjRaMBgxFjAUBgNVBAMMDUNs
+aWVudCBDZXJ0IEEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbpheC
+fsTOyQIlrA2zJ98fPk//CDIv0uSRgPPIVepIaXZGzrpiU+R8FBUcAlddxExkvoYn
+SqLfZylaASxtdKTXMCLJJUNrI16P6Nc2xBGhr0cTWUbpK8fmiOUaGJFX2v1zZrnk
+vod4+cbcH0FNTWc9PTV8aqdilpTFUPGrAwd4bXF1+/FIS+sOwpaNg5LFWBtcYYNP
+CEyEDWsXVf573KKZqDRTGwHUiE3F3lgIlVHJpVOfEz4qZR7Q5RgBe4owYUZ5PRb3
+0ztgDe/qjZls/LctnTuXC4/zDp6CTmmMOjy/zUUJRmdWG//EdWv/Ukf3xf6F4Tp4
+KrjIL41et0uIsbPLAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYI
+KwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQAZm0E5Yc/4D2KY
+Qxqk+wtx8vDEtTm73NHXM0SJZhP/ClpmAnRqjYrcoODQzI1fHMA0xlgCdju1GoGl
+p6HFgRRSDyE3Bi3c3JzQ0ZgDrNO1Egv4tITYvL5NJ/rfFm7dCjO3h1B+/saNhLIt
+f1iIIa8JZF5KLfBW1D6j3EyqkkEEwW5WRtU2aQ0q9vAp03yst89/GLx2+oxadoFn
+27KRlwV9FNom1Wf+xdJqLF/0ljrkDvUVlQVX3rXllrIQmUqyOqzSrmQwMVTwuZ8d
+Vuja6U5C4yY994w+nN1Cd50MZ1JzlMRzQsK3lqREStXpPbFGqjgLH3+uAcYH2kA7
+wCJhxMuA
-----END CERTIFICATE-----
diff --git a/chromium/net/data/ssl/certificates/client_1.pk8 b/chromium/net/data/ssl/certificates/client_1.pk8
index 1b91cdebc3d..19db6db36b1 100644
--- a/chromium/net/data/ssl/certificates/client_1.pk8
+++ b/chromium/net/data/ssl/certificates/client_1.pk8
Binary files differ
diff --git a/chromium/net/data/ssl/certificates/client_1_ca.pem b/chromium/net/data/ssl/certificates/client_1_ca.pem
index f610002ae89..88723ce6589 100644
--- a/chromium/net/data/ssl/certificates/client_1_ca.pem
+++ b/chromium/net/data/ssl/certificates/client_1_ca.pem
@@ -5,31 +5,31 @@ Certificate:
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=C Root CA
Validity
- Not Before: Feb 28 20:27:03 2016 GMT
- Not After : Feb 25 20:27:03 2026 GMT
+ Not Before: Oct 4 18:53:24 2016 GMT
+ Not After : Oct 2 18:53:24 2026 GMT
Subject: CN=B CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:bb:12:09:89:83:8a:9d:83:1a:48:c5:c7:0e:f2:
- 93:3d:ba:25:28:c4:2e:49:7a:02:b9:58:8c:52:77:
- 69:3f:d2:0a:1f:2a:6d:2e:20:96:7e:d1:1f:c0:8f:
- 05:de:fc:a0:57:5f:84:82:90:af:0b:59:df:fa:b6:
- d7:29:03:f4:10:12:de:a1:de:d9:87:5c:25:f9:bc:
- fe:45:80:cb:90:ef:5e:4e:8d:5d:4e:2a:5f:7d:f8:
- 2a:87:c1:00:4a:60:74:0f:e2:80:41:6a:d4:fd:65:
- 1c:0b:88:7d:90:a9:31:17:d3:fa:2e:56:a2:15:6c:
- 1a:2f:1f:fc:d8:29:46:f5:5a:30:e3:4b:35:f8:30:
- e7:b9:b3:d6:56:ed:15:e0:44:21:29:97:d2:46:ec:
- b8:9c:45:42:3f:c1:c2:18:b9:ff:41:c0:11:71:bc:
- 7b:bc:cd:e1:c1:31:d3:23:d1:be:63:80:4d:17:55:
- 6f:ff:1d:5b:6a:70:38:74:49:ab:d4:79:33:43:54:
- 90:8b:13:4a:72:fb:e8:df:f3:f2:14:40:1c:cb:15:
- dc:8b:9d:0b:96:1d:ec:65:d6:d4:01:ae:f5:af:a2:
- 29:4f:90:e3:17:19:0a:88:f4:0c:2f:7d:b4:be:15:
- 2a:e8:eb:57:59:00:7a:ab:0c:73:3e:7f:74:ac:e2:
- eb:e7
+ 00:a5:56:c7:9d:32:e7:3d:17:ac:59:ca:f4:07:65:
+ 25:3e:65:7c:d9:3d:f4:0e:73:eb:b9:0b:a1:7b:4b:
+ 69:ab:ee:a3:50:49:2f:25:33:4d:2d:ac:00:32:17:
+ 34:0d:c9:bf:83:7d:b4:e5:d5:82:89:6f:ad:41:78:
+ 56:1d:05:bc:48:cc:0c:43:95:81:e3:e8:12:2d:67:
+ 74:68:12:61:8e:03:24:88:2c:57:28:8e:3d:10:77:
+ da:dc:78:b6:b4:72:92:56:0e:4a:0c:c6:f7:0a:44:
+ f5:56:5d:72:7a:a8:1d:bc:16:e8:95:25:4d:50:b6:
+ 2e:22:05:fd:d5:20:47:a4:32:37:52:38:61:90:9a:
+ aa:40:a8:db:91:80:00:89:e6:2c:17:5d:7c:5f:6f:
+ 2d:b2:b7:cf:71:a1:55:11:d8:fd:3b:9b:61:8f:1c:
+ 80:dd:da:90:8c:82:04:63:36:7c:b1:28:38:56:bc:
+ 6e:c0:b3:b9:4e:96:2b:3f:62:2a:e5:5f:f1:73:3c:
+ 53:a8:5f:03:d0:63:31:36:ac:00:61:30:ab:ad:d9:
+ aa:ab:5d:22:83:28:cc:f1:f7:88:f5:9a:be:57:c5:
+ e1:46:da:a3:88:55:a7:3c:f9:1c:17:bb:72:01:1d:
+ dd:8e:a0:b0:a3:d1:91:74:ae:94:58:c0:f5:30:63:
+ 5c:91
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints: critical
@@ -37,35 +37,35 @@ Certificate:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
Signature Algorithm: sha256WithRSAEncryption
- 82:1e:66:21:1e:36:15:96:43:c6:38:0f:e0:06:0f:0a:94:51:
- e1:bc:36:30:9b:2a:b5:d0:06:51:e0:e7:06:7c:c5:fb:45:6a:
- 23:f5:0e:9f:d4:01:ec:e6:c7:62:cd:6b:37:66:bb:0a:d8:07:
- c9:66:dc:55:53:c9:a3:c3:4c:a1:06:20:f4:b8:c0:92:87:82:
- a1:f5:40:f0:e1:a8:d9:bc:e5:ec:bb:4c:4b:48:f6:86:23:b0:
- d8:a6:fd:16:fe:88:69:08:00:c5:da:c6:de:7c:4b:3c:5b:8e:
- f3:f4:90:ca:f5:25:f2:48:65:b8:9c:f6:fc:9e:37:02:2c:a4:
- c1:48:a4:fd:c5:07:cc:b0:ca:ed:13:d2:15:ad:09:08:0b:e0:
- 9e:3b:9e:28:02:1e:93:ae:e7:c7:5e:3f:cf:1f:4b:f3:72:cf:
- f7:f2:19:55:8e:67:be:9b:5a:15:b0:80:cd:cf:dd:7f:79:7d:
- 0d:dd:ee:81:4f:47:f6:d5:87:46:15:f8:27:fc:eb:52:0d:c2:
- 99:68:91:78:17:43:7f:d3:09:0f:87:35:77:80:31:69:f7:24:
- b5:af:5c:5c:24:f2:8c:24:f5:da:bf:91:01:9d:9d:d1:a0:cb:
- 72:93:11:6e:1c:b4:f5:f9:18:d8:5f:dc:b2:7d:43:b7:4b:8e:
- 2e:11:79:0e
+ 41:1f:59:af:b3:83:87:87:bc:b3:2d:62:66:35:76:21:f2:bb:
+ e5:d4:87:23:a3:ab:4f:2b:ef:d0:ee:53:6f:17:b0:d4:6a:93:
+ 8e:74:71:7b:c5:36:f4:7b:87:3a:ab:84:b0:40:c5:3b:a0:e7:
+ a1:18:e6:3f:8d:8d:a8:49:b5:da:c7:4b:26:e4:ea:b9:2d:85:
+ b2:1d:01:70:bb:78:08:a6:c7:11:6b:0a:6f:5d:b0:d7:b5:72:
+ ec:51:46:26:bc:7e:e1:bd:1e:5e:d6:44:cf:d0:1b:55:ef:a9:
+ 5e:16:73:05:59:9f:ff:00:2e:5b:4e:29:7b:c4:2e:5c:46:9c:
+ 56:0a:78:d9:0b:10:83:9e:ff:8a:e3:57:ec:f1:d1:a3:85:26:
+ 2f:97:e6:d0:6f:5e:c8:cb:53:e7:28:64:ab:27:14:f4:b2:4b:
+ 52:80:e2:d1:ef:50:ba:db:34:5c:95:a4:3f:ac:5b:eb:15:c5:
+ d6:cb:4b:76:fb:f6:cd:2f:d9:ef:d4:cb:1c:85:52:8b:f2:2b:
+ 1b:ce:e3:0f:ed:07:44:11:8b:d8:b8:5c:41:ab:e1:36:0d:7e:
+ 3f:86:ff:0c:0f:f5:5e:ff:f6:b8:0a:ac:f0:3b:5d:c5:b7:ef:
+ f1:80:7c:26:b9:a2:ee:17:a8:e7:cb:c4:f4:5c:51:ff:57:53:
+ ee:a2:d3:66
-----BEGIN CERTIFICATE-----
MIICwjCCAaqgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAwwJQyBS
-b290IENBMB4XDTE2MDIyODIwMjcwM1oXDTI2MDIyNTIwMjcwM1owDzENMAsGA1UE
-AwwEQiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALsSCYmDip2D
-GkjFxw7ykz26JSjELkl6ArlYjFJ3aT/SCh8qbS4gln7RH8CPBd78oFdfhIKQrwtZ
-3/q21ykD9BAS3qHe2YdcJfm8/kWAy5DvXk6NXU4qX334KofBAEpgdA/igEFq1P1l
-HAuIfZCpMRfT+i5WohVsGi8f/NgpRvVaMONLNfgw57mz1lbtFeBEISmX0kbsuJxF
-Qj/Bwhi5/0HAEXG8e7zN4cEx0yPRvmOATRdVb/8dW2pwOHRJq9R5M0NUkIsTSnL7
-6N/z8hRAHMsV3IudC5Yd7GXW1AGu9a+iKU+Q4xcZCoj0DC99tL4VKujrV1kAeqsM
-cz5/dKzi6+cCAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
-AQYwDQYJKoZIhvcNAQELBQADggEBAIIeZiEeNhWWQ8Y4D+AGDwqUUeG8NjCbKrXQ
-BlHg5wZ8xftFaiP1Dp/UAezmx2LNazdmuwrYB8lm3FVTyaPDTKEGIPS4wJKHgqH1
-QPDhqNm85ey7TEtI9oYjsNim/Rb+iGkIAMXaxt58SzxbjvP0kMr1JfJIZbic9vye
-NwIspMFIpP3FB8ywyu0T0hWtCQgL4J47nigCHpOu58deP88fS/Nyz/fyGVWOZ76b
-WhWwgM3P3X95fQ3d7oFPR/bVh0YV+Cf861INwplokXgXQ3/TCQ+HNXeAMWn3JLWv
-XFwk8owk9dq/kQGdndGgy3KTEW4ctPX5GNhf3LJ9Q7dLji4ReQ4=
+b290IENBMB4XDTE2MTAwNDE4NTMyNFoXDTI2MTAwMjE4NTMyNFowDzENMAsGA1UE
+AwwEQiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKVWx50y5z0X
+rFnK9AdlJT5lfNk99A5z67kLoXtLaavuo1BJLyUzTS2sADIXNA3Jv4N9tOXVgolv
+rUF4Vh0FvEjMDEOVgePoEi1ndGgSYY4DJIgsVyiOPRB32tx4trRyklYOSgzG9wpE
+9VZdcnqoHbwW6JUlTVC2LiIF/dUgR6QyN1I4YZCaqkCo25GAAInmLBddfF9vLbK3
+z3GhVRHY/TubYY8cgN3akIyCBGM2fLEoOFa8bsCzuU6WKz9iKuVf8XM8U6hfA9Bj
+MTasAGEwq63ZqqtdIoMozPH3iPWavlfF4Ubao4hVpzz5HBe7cgEd3Y6gsKPRkXSu
+lFjA9TBjXJECAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQELBQADggEBAEEfWa+zg4eHvLMtYmY1diHyu+XUhyOjq08r
+79DuU28XsNRqk450cXvFNvR7hzqrhLBAxTug56EY5j+NjahJtdrHSybk6rkthbId
+AXC7eAimxxFrCm9dsNe1cuxRRia8fuG9Hl7WRM/QG1XvqV4WcwVZn/8ALltOKXvE
+LlxGnFYKeNkLEIOe/4rjV+zx0aOFJi+X5tBvXsjLU+coZKsnFPSyS1KA4tHvULrb
+NFyVpD+sW+sVxdbLS3b79s0v2e/UyxyFUovyKxvO4w/tB0QRi9i4XEGr4TYNfj+G
+/wwP9V7/9rgKrPA7XcW37/GAfCa5ou4XqOfLxPRcUf9XU+6i02Y=
-----END CERTIFICATE-----
diff --git a/chromium/net/data/ssl/certificates/client_2.key b/chromium/net/data/ssl/certificates/client_2.key
index 2b898f0c580..e10b152c656 100644
--- a/chromium/net/data/ssl/certificates/client_2.key
+++ b/chromium/net/data/ssl/certificates/client_2.key
@@ -1,27 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
-MIIEogIBAAKCAQEAzCwk5vzkVe8k+mJANot7xnoPsDl6LrCua/6yW3Zub4gORzVg
-85JV5hniNGixW+rRKpd4FYG0rUDmZA/lXa2Paw94PqWIU9+xg7C6i2iSR6uEHMo7
-E/Fa0wasup8Ja13LlT/CPPVYhGlb/6fbiZfWWBAMAonnVIGtV6S6R/QTNb9Nl/Z8
-u45JWjGeopWyHHt6FB2fZFmZAALl2CHYM5CsbZUY+NIkrm5F0eTin0xc4t2L/zuB
-iYRom+vPA8vlfVAAOtyVplC3+PSkVJqXn8YQ31QkYrfpaefm6i3hfJnVkCYlpbBm
-9Aux4+WcLTh5MMsYXCh42pv2lBA6ho+TG75uMwIDAQABAoIBAB18rqOxmGSU0jlb
-ITz/bhPfIw7nbi76E2bDdQzikNaIxs8f9W2YD9HYoSPCjwLgae8FyzEH94kiG2QO
-K6kY3OKwbERX8dVzNBb52icyJhY1vjHOPzQFIoHhr+aP+3NHK5TVjX7yTCNrd/73
-RiycAjfbsXBYbFF3HQrQXprvtCqJwVeH2YP33uznn6zjxfNcpVmv2D8EE431M7S7
-3eC9TT5q3b78hJcm6N4nbVFAA1E/zZuVTqJ5xuiBKPG03FqwpVmmOeKX3BU57EXy
-iDxXFxdiAen/eEwEoUuBuTGWtTUpUfvv8JyibM6FYuQYxggP7szgnvkDVriK1vZ0
-krMskhkCgYEA7xxeT2+qd1BpEBOUcGVMPJlSlFNmyH5vg/GSfbY8BWYKU6YQ2wca
-dkhk9q+OGgMUMZjdxMtrFFhICxn4QUmpPPGX2QRKALgthkSZc7B0PacgL45SHa10
-2mJbeX3e7zjUtjb0Jk6CIFQ1CRE9TS+0/+3ZlakSfm6tuIcaqIGxB8UCgYEA2pgE
-AxunlvJRnY5KICxxusCfja4VOtql6zFpHpdRaELMkl7kWiJZyZyx8iOVWc2Nt+QV
-PtFKi1nzn3wTQR0YHaRtq+w5HPl7UXSSDabMOmsMda53o47gjcjXqVUKLhmw03/i
-ng0uOAmBGJLA76qy+MqAAkfJy1iK5wKwF1E8BZcCgYA+Jfd1WibKgEHuhchNNmcM
-USWfm9XZQtOlTcKvnhAXrx/8AevbogsEt2hWneanaCl1grARmHWqgg+nowZdodG1
-H25CX9UEPtrGTUo9QZ3U8H1zHuDFCfKXWH1CJK8vKmxPOBVZZ4p28KwgQTTXvRCk
-fKPTPHCsIARTM/p/1cW3qQKBgGuGLSsONmCkr4rNzB6JXiQbziAWCnFZzhWjx255
-xlx/xzsUnETN8taeUlWmNTfoSZa0BdNRhdaIF7NSh/IWip9CG4Re/TUIbyWBLrqy
-WnE96PIWMNluVXzI13R+1TQaBQX0ORe/qgV8f1kEDw2VLNX+XftBLrzsv96kTtQZ
-bGnfAoGAHrVqcFGCpO/0tVOm6sy6jOahQhKkN0Qz8V5pbGt87M0WX1CtkrXgk6zh
-k3Ej9wRLvsyWuJfcLl7b7j6T234Y9GcfCO11ohd9T+3201ixMyjKnRkJOFM/s7VJ
-9Y7EWGHTwQJBIrRBcMeCujTQDKCLzYLghsYo738O/edxDQwVHck=
+MIIEowIBAAKCAQEA68lLXfm1qfzrGYiXtXmYfa/gwbcSGLTcu3VTD9Cow2A465PP
+wp6bs6Qu3eFgwr7mceQ72pU410+zEwxo1bqHorcc1qhemDBLEaL5cu1KEyw3GN97
+kJTxOMR4zahR8IvDpnYRzjTtmZOuLUpZ7Lo3oOouLDQ6OpoOw9mLu2I7RtVc8cQC
+iyOnQVWKeSbDQ/+or/m3DUbQq+Wyg9TTjDWAAbqxu3mP5Jf8nd8I/xAbRxe0jBSW
+8hiZ++Yxjo/kLVkI+s4TBFVV3dau2b5oHGMsFoBFCaTIyE+4KZAKZAdptvxuh1ic
+F/GhSZy3+H1w122uYmq7KA7pG32sBaQUl0iwnQIDAQABAoIBAGNOKlHwI9TuUs40
+O0ERb2owMwcjZZnGQtko9szIYuu2kQKXBH/BcW5djeehTrF22XPKXnMXOhNk29T/
++v9ZSlr7qEe4Le8HF/bbnxgKXJJqouH07gPc1yPDi+WCKNCY7NQlEia5IAD4s/kb
+QXh0jY1WVBAGByg7TlCqRTGsk66myy3qA7Ii65Y1upiGFfDczpQL5mUKaBTjz3HC
+/DMr4GRuFOw5NkhELu9SOENZGSwuzpk6gNDVYDXJ+uo9bvH9EIB9S1KIoAoa+yr2
+L9LUcG9vwOuMNh7qN66nAGxGzoI8qh6kHVgfyTcF11NwaFutSIsGQTRKeANxiq2I
+IkbT3EECgYEA/QGxkv9iC/oJfe9gWlUeEFJsqlmLp2ii0HrH9KnywT5sgicd0//3
+eCU1KI8LygABbHb3hmFQRAwf2gFq0u1MBqXQQ4nVsrNtPVzNGGOkfk5T9DIu4vBN
+L9Qw29ULYDbaHaC1BFymwnMsOOsKctiMmsiklhyCWBczcHmE+gn+6ykCgYEA7pNx
+on/qgrCp9P8mMdBqjOmc5740Pbqu5JShYJkja1fv7IVLhGEuifdwGWge6ZfjaXPV
+wq7P7mbXa2Dreqc0LkxUrdAffZitsXckhNswSDToZzf7JB9GAnkcMKlLcJHbO0Kf
+jJALGpPknLg8XbpqsT+/GAS1GBNbL4Rz/MovPFUCgYBkJEt494SDYRBovFrS5mXj
+5/wC4TaZqJzpD/AdMzdWrbKdQYZY5zO4ZmHID/aGmcH2gJAwrEvs4y+oRm9V1X8G
+EpOAaAohlUtjwlubj7UIGVC5kzNjt+GVUNOV75l1F8D1gSqk81c+GAAk90NHedcN
+XOVoVRhybZx6pF6x6UrxIQKBgDc8EbIClYO+bQrYy7n6u8B2Eaqhoays/PLU6mvX
+6Jhgmp6S2cIDUegFToHDVmzUioUOmW3iVSenzbYBkWMrNOyHJY+8QJ4ubABLSjws
+FwiQn0HOdymMyAOokHs/psSgMDaPHStI6hk0JliWWvuEPlFdJdvksxyo1pKwwr3C
+/Z6lAoGBAIr0S/O5rYrEHchJ6yr+YtJa6vIowOSUvijG2L4ghVY63v/Ke5vzwmOZ
+wuPh0D6atpKPIq5p3eGlgq12cJHGwaybVP9C3C9vD+MlhMttOy7Ez9aVFILE9nt/
+hSrOTRwYYXLs0txl7K40Ja2hjIRXw1TQU37V4wADNa+GhPpUfg9y
-----END RSA PRIVATE KEY-----
diff --git a/chromium/net/data/ssl/certificates/client_2.pem b/chromium/net/data/ssl/certificates/client_2.pem
index dc3221659b5..1f7a03aff6c 100644
--- a/chromium/net/data/ssl/certificates/client_2.pem
+++ b/chromium/net/data/ssl/certificates/client_2.pem
@@ -5,31 +5,31 @@ Certificate:
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=E CA
Validity
- Not Before: Feb 28 20:27:03 2016 GMT
- Not After : Feb 25 20:27:03 2026 GMT
+ Not Before: Oct 4 18:53:24 2016 GMT
+ Not After : Oct 2 18:53:24 2026 GMT
Subject: CN=Client Cert D
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:cc:2c:24:e6:fc:e4:55:ef:24:fa:62:40:36:8b:
- 7b:c6:7a:0f:b0:39:7a:2e:b0:ae:6b:fe:b2:5b:76:
- 6e:6f:88:0e:47:35:60:f3:92:55:e6:19:e2:34:68:
- b1:5b:ea:d1:2a:97:78:15:81:b4:ad:40:e6:64:0f:
- e5:5d:ad:8f:6b:0f:78:3e:a5:88:53:df:b1:83:b0:
- ba:8b:68:92:47:ab:84:1c:ca:3b:13:f1:5a:d3:06:
- ac:ba:9f:09:6b:5d:cb:95:3f:c2:3c:f5:58:84:69:
- 5b:ff:a7:db:89:97:d6:58:10:0c:02:89:e7:54:81:
- ad:57:a4:ba:47:f4:13:35:bf:4d:97:f6:7c:bb:8e:
- 49:5a:31:9e:a2:95:b2:1c:7b:7a:14:1d:9f:64:59:
- 99:00:02:e5:d8:21:d8:33:90:ac:6d:95:18:f8:d2:
- 24:ae:6e:45:d1:e4:e2:9f:4c:5c:e2:dd:8b:ff:3b:
- 81:89:84:68:9b:eb:cf:03:cb:e5:7d:50:00:3a:dc:
- 95:a6:50:b7:f8:f4:a4:54:9a:97:9f:c6:10:df:54:
- 24:62:b7:e9:69:e7:e6:ea:2d:e1:7c:99:d5:90:26:
- 25:a5:b0:66:f4:0b:b1:e3:e5:9c:2d:38:79:30:cb:
- 18:5c:28:78:da:9b:f6:94:10:3a:86:8f:93:1b:be:
- 6e:33
+ 00:eb:c9:4b:5d:f9:b5:a9:fc:eb:19:88:97:b5:79:
+ 98:7d:af:e0:c1:b7:12:18:b4:dc:bb:75:53:0f:d0:
+ a8:c3:60:38:eb:93:cf:c2:9e:9b:b3:a4:2e:dd:e1:
+ 60:c2:be:e6:71:e4:3b:da:95:38:d7:4f:b3:13:0c:
+ 68:d5:ba:87:a2:b7:1c:d6:a8:5e:98:30:4b:11:a2:
+ f9:72:ed:4a:13:2c:37:18:df:7b:90:94:f1:38:c4:
+ 78:cd:a8:51:f0:8b:c3:a6:76:11:ce:34:ed:99:93:
+ ae:2d:4a:59:ec:ba:37:a0:ea:2e:2c:34:3a:3a:9a:
+ 0e:c3:d9:8b:bb:62:3b:46:d5:5c:f1:c4:02:8b:23:
+ a7:41:55:8a:79:26:c3:43:ff:a8:af:f9:b7:0d:46:
+ d0:ab:e5:b2:83:d4:d3:8c:35:80:01:ba:b1:bb:79:
+ 8f:e4:97:fc:9d:df:08:ff:10:1b:47:17:b4:8c:14:
+ 96:f2:18:99:fb:e6:31:8e:8f:e4:2d:59:08:fa:ce:
+ 13:04:55:55:dd:d6:ae:d9:be:68:1c:63:2c:16:80:
+ 45:09:a4:c8:c8:4f:b8:29:90:0a:64:07:69:b6:fc:
+ 6e:87:58:9c:17:f1:a1:49:9c:b7:f8:7d:70:d7:6d:
+ ae:62:6a:bb:28:0e:e9:1b:7d:ac:05:a4:14:97:48:
+ b0:9d
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints: critical
@@ -37,36 +37,36 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- a0:17:a0:22:a1:59:44:4f:64:6f:0a:1a:f3:a9:69:82:50:60:
- 24:94:46:56:88:88:72:82:5f:d9:aa:bc:78:36:85:a2:90:d9:
- 38:d3:32:26:93:f3:82:ca:9b:b6:f9:2d:1b:ef:8d:d2:5b:84:
- 68:73:9e:ef:d2:03:71:ff:90:ac:47:e5:9b:e2:a4:12:20:f5:
- 69:29:7d:90:4a:80:93:b6:38:66:dd:93:51:ac:29:13:96:3c:
- 5d:3d:84:70:46:81:2f:ab:90:ec:e1:1c:23:a3:45:dc:95:71:
- 73:6e:33:08:fb:02:05:a3:7e:d4:bd:a1:b7:06:07:a3:19:0a:
- 35:b7:a2:a9:e1:45:56:9f:e0:23:35:34:f4:bb:e7:78:f7:be:
- 1b:07:cb:58:c7:8d:f5:16:41:d9:66:07:a2:16:29:a1:e7:ed:
- 7b:dd:38:9b:74:2f:3a:44:d4:df:46:ef:59:ef:1f:15:43:78:
- 6f:36:fb:a4:3d:88:0b:e4:db:af:f7:ec:3a:66:4c:72:9e:f3:
- d1:e4:27:a5:a9:ba:19:69:26:d6:2f:97:f0:35:0b:75:14:70:
- 19:53:a4:c3:19:31:0b:19:ad:36:59:d0:51:26:2c:f9:88:a2:
- 82:9b:ad:67:bd:94:f8:af:50:f1:56:47:df:c9:27:dc:bf:af:
- 77:b8:de:75
+ 9f:d0:6e:8b:08:58:16:b5:78:3f:05:bb:59:bc:cf:74:1c:88:
+ b0:7e:10:c5:71:9d:b5:08:05:59:ca:f0:c8:64:49:96:82:8b:
+ 14:0c:da:9d:be:a2:8b:37:df:e1:69:bc:8e:f4:be:80:3f:f9:
+ 8a:1d:7a:70:37:3c:18:a0:92:27:10:e3:74:ca:fa:b8:db:f2:
+ c6:a5:32:66:85:88:29:3a:4e:64:95:85:b4:43:37:8a:6d:48:
+ f4:12:2f:b2:d0:66:c9:b7:88:ad:b8:a7:1f:97:59:bf:d9:0d:
+ d6:ce:ff:5f:75:2f:d2:e0:69:c8:d6:17:b9:fd:3c:ed:fd:1f:
+ 47:14:f8:ef:0b:33:2a:1c:14:25:d1:82:90:d3:67:1b:ea:b0:
+ f7:5b:78:a9:9d:28:1b:d3:cd:8d:bd:30:c2:7e:12:32:dd:83:
+ cc:57:47:b3:e7:0c:79:b5:f8:a0:f4:f0:d8:29:1b:9b:fb:2f:
+ a9:1c:cb:a9:84:14:29:c7:23:b8:85:88:d9:78:5f:c7:a4:c6:
+ 1b:bd:6e:70:2e:a2:be:31:98:c7:9c:35:1d:44:59:f8:31:83:
+ 87:ee:a9:c7:ab:f5:6f:e6:8a:cc:49:5f:23:fd:7c:a4:61:01:
+ 9b:51:d8:b0:85:9a:bf:1d:9d:62:3e:b0:7c:e0:5e:57:ed:69:
+ 3c:f3:8c:54
-----BEGIN CERTIFICATE-----
MIIC0jCCAbqgAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwERSBD
-QTAeFw0xNjAyMjgyMDI3MDNaFw0yNjAyMjUyMDI3MDNaMBgxFjAUBgNVBAMMDUNs
-aWVudCBDZXJ0IEQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMLCTm
-/ORV7yT6YkA2i3vGeg+wOXousK5r/rJbdm5viA5HNWDzklXmGeI0aLFb6tEql3gV
-gbStQOZkD+VdrY9rD3g+pYhT37GDsLqLaJJHq4QcyjsT8VrTBqy6nwlrXcuVP8I8
-9ViEaVv/p9uJl9ZYEAwCiedUga1XpLpH9BM1v02X9ny7jklaMZ6ilbIce3oUHZ9k
-WZkAAuXYIdgzkKxtlRj40iSubkXR5OKfTFzi3Yv/O4GJhGib688Dy+V9UAA63JWm
-ULf49KRUmpefxhDfVCRit+lp5+bqLeF8mdWQJiWlsGb0C7Hj5ZwtOHkwyxhcKHja
-m/aUEDqGj5Mbvm4zAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYI
-KwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCgF6AioVlET2Rv
-ChrzqWmCUGAklEZWiIhygl/Zqrx4NoWikNk40zImk/OCypu2+S0b743SW4Roc57v
-0gNx/5CsR+Wb4qQSIPVpKX2QSoCTtjhm3ZNRrCkTljxdPYRwRoEvq5Ds4Rwjo0Xc
-lXFzbjMI+wIFo37UvaG3BgejGQo1t6Kp4UVWn+AjNTT0u+d4974bB8tYx431FkHZ
-ZgeiFimh5+173TibdC86RNTfRu9Z7x8VQ3hvNvukPYgL5Nuv9+w6ZkxynvPR5Cel
-qboZaSbWL5fwNQt1FHAZU6TDGTELGa02WdBRJiz5iKKCm61nvZT4r1DxVkffySfc
-v693uN51
+QTAeFw0xNjEwMDQxODUzMjRaFw0yNjEwMDIxODUzMjRaMBgxFjAUBgNVBAMMDUNs
+aWVudCBDZXJ0IEQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDryUtd
++bWp/OsZiJe1eZh9r+DBtxIYtNy7dVMP0KjDYDjrk8/CnpuzpC7d4WDCvuZx5Dva
+lTjXT7MTDGjVuoeitxzWqF6YMEsRovly7UoTLDcY33uQlPE4xHjNqFHwi8OmdhHO
+NO2Zk64tSlnsujeg6i4sNDo6mg7D2Yu7YjtG1VzxxAKLI6dBVYp5JsND/6iv+bcN
+RtCr5bKD1NOMNYABurG7eY/kl/yd3wj/EBtHF7SMFJbyGJn75jGOj+QtWQj6zhME
+VVXd1q7ZvmgcYywWgEUJpMjIT7gpkApkB2m2/G6HWJwX8aFJnLf4fXDXba5iarso
+DukbfawFpBSXSLCdAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYI
+KwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQCf0G6LCFgWtXg/
+BbtZvM90HIiwfhDFcZ21CAVZyvDIZEmWgosUDNqdvqKLN9/habyO9L6AP/mKHXpw
+NzwYoJInEON0yvq42/LGpTJmhYgpOk5klYW0QzeKbUj0Ei+y0GbJt4ituKcfl1m/
+2Q3Wzv9fdS/S4GnI1he5/Tzt/R9HFPjvCzMqHBQl0YKQ02cb6rD3W3ipnSgb082N
+vTDCfhIy3YPMV0ez5wx5tfig9PDYKRub+y+pHMuphBQpxyO4hYjZeF/HpMYbvW5w
+LqK+MZjHnDUdRFn4MYOH7qnHq/Vv5orMSV8j/XykYQGbUdiwhZq/HZ1iPrB84F5X
+7Wk884xU
-----END CERTIFICATE-----
diff --git a/chromium/net/data/ssl/certificates/client_2.pk8 b/chromium/net/data/ssl/certificates/client_2.pk8
index 9e433662596..731e39c3cc7 100644
--- a/chromium/net/data/ssl/certificates/client_2.pk8
+++ b/chromium/net/data/ssl/certificates/client_2.pk8
Binary files differ
diff --git a/chromium/net/data/ssl/certificates/client_2_ca.pem b/chromium/net/data/ssl/certificates/client_2_ca.pem
index 8753ac47571..dd58ffa7a3c 100644
--- a/chromium/net/data/ssl/certificates/client_2_ca.pem
+++ b/chromium/net/data/ssl/certificates/client_2_ca.pem
@@ -5,31 +5,31 @@ Certificate:
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=C Root CA
Validity
- Not Before: Feb 28 20:27:03 2016 GMT
- Not After : Feb 25 20:27:03 2026 GMT
+ Not Before: Oct 4 18:53:24 2016 GMT
+ Not After : Oct 2 18:53:24 2026 GMT
Subject: CN=E CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:ba:41:e9:51:55:de:d0:9a:a9:ef:4c:fc:04:a4:
- 26:76:de:1d:5a:fa:84:f9:a4:37:91:85:0b:92:d5:
- 53:de:bd:77:ec:8b:b7:20:d1:db:26:63:4b:91:4a:
- d3:93:3a:1a:1e:50:eb:02:fd:6a:c8:6d:14:72:b8:
- c4:de:5c:4a:74:93:0e:ac:06:d3:5b:f8:f9:19:cd:
- 0a:6f:3c:90:ec:7d:f8:43:9d:66:35:9a:58:e6:c2:
- 8d:10:6c:94:79:e5:b3:fa:f6:98:de:50:8e:c0:b7:
- 01:33:12:43:4c:52:57:ad:c8:0c:b1:62:e0:ae:89:
- d8:ad:d4:94:d9:78:f3:b5:0d:13:3e:64:55:73:83:
- 8b:2c:f6:6c:8c:9a:51:85:9e:cc:33:5d:aa:b0:1d:
- 94:29:d7:7b:ed:b7:77:2c:53:a3:05:83:c2:69:c9:
- 2d:ad:ce:76:62:d6:df:4e:e7:75:cb:19:2d:a8:e2:
- 18:75:08:57:d1:a9:2a:29:68:70:02:8c:03:a3:00:
- 22:37:d5:c0:7d:a2:a7:40:ce:2c:79:58:52:06:1f:
- 7a:61:b7:ce:e7:c2:83:dd:6d:cc:0a:64:17:27:cb:
- 21:56:38:c2:db:a0:ac:fd:18:b5:15:01:f5:50:25:
- 96:b7:91:ab:51:42:47:8c:fc:df:6a:54:f9:ea:49:
- a6:75
+ 00:a2:7e:a3:fd:c1:d7:78:cd:57:ac:67:54:37:69:
+ fb:72:6f:1d:8f:d0:47:0f:11:14:ab:42:d8:3d:6a:
+ 34:2b:d6:38:07:df:16:1d:c6:62:eb:d7:12:e1:86:
+ 83:f2:dd:8f:97:09:94:8f:1b:ff:3b:84:9b:48:e5:
+ 0d:43:6b:ae:bb:75:88:1c:c6:3a:7f:d8:12:d9:7c:
+ 12:18:6d:e2:f0:88:d4:3e:5a:93:b3:af:c1:79:a1:
+ b6:a3:f7:56:46:21:e6:7d:6e:36:ea:ba:4b:52:f7:
+ a9:45:0b:83:09:2c:09:22:8a:67:5a:8f:88:60:b0:
+ 11:07:25:9b:c2:6a:3c:63:4c:0e:69:45:ce:9d:ba:
+ c9:d4:01:fb:78:56:38:08:8f:e5:d6:ff:ac:e4:04:
+ fa:26:cf:d2:05:33:57:a3:8e:80:c0:b6:40:d5:d3:
+ ca:85:17:30:b2:24:f4:19:af:c5:48:a4:ed:c0:49:
+ c1:a4:b7:89:29:ba:e5:2d:37:78:1c:d6:3e:9b:03:
+ fa:bc:7b:e2:76:a6:70:f3:1b:9d:b2:4b:fc:72:7b:
+ 77:89:50:bb:88:2f:b5:b6:a2:c7:33:27:b7:d1:1a:
+ 7c:d4:58:e3:5e:88:ca:f8:49:c3:cd:cc:0f:93:4b:
+ 3c:fd:75:c3:7b:6f:bf:d3:db:ba:2e:31:7b:a7:a5:
+ 42:c5
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints: critical
@@ -37,35 +37,35 @@ Certificate:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
Signature Algorithm: sha256WithRSAEncryption
- 63:37:df:42:58:b0:4e:d1:0e:88:99:d0:c8:a0:9f:21:f6:13:
- 6a:c1:bb:8b:59:01:76:6e:01:1d:37:cb:b9:12:de:0d:78:49:
- b8:26:26:6b:9c:32:83:7d:39:bc:e3:f8:55:6b:cc:12:59:b0:
- 11:b4:70:4c:14:99:34:e5:19:ab:d2:ff:5a:41:14:99:f6:d1:
- 03:f7:28:1c:22:56:06:ef:10:ac:e0:be:45:47:c1:f5:6b:d1:
- e9:78:3a:88:4f:37:db:c5:2d:a6:95:3a:ff:84:9f:78:fc:2f:
- b8:7e:b8:e4:94:69:c9:9c:26:f5:29:2f:81:9a:a0:26:82:65:
- 50:93:63:54:71:fe:d6:d0:90:47:1d:f3:28:bc:8f:5a:e7:6e:
- 54:8a:2f:5f:e8:4a:40:77:e6:cf:46:e9:4a:da:d2:7f:70:86:
- 56:6f:10:17:7b:f1:d0:1d:d2:3d:b1:de:7c:5f:bd:fe:50:3d:
- 13:cf:5f:43:c7:d0:10:60:b9:eb:cb:55:de:60:1a:c7:b6:50:
- 37:ea:9e:cf:18:28:b0:df:c7:0e:ae:08:5a:21:25:02:c3:08:
- ca:1c:3e:b1:9f:bb:72:15:f6:5e:0a:32:bf:03:c7:05:e6:20:
- 5c:82:df:9f:9e:39:dc:86:45:f3:65:cc:f7:8c:48:08:53:a2:
- 73:b3:e7:5d
+ 92:8b:93:94:03:04:91:3f:4d:8b:f3:90:53:ee:73:b5:33:c7:
+ 61:ea:0f:a5:59:9b:f0:0d:4f:7d:48:0d:5a:58:e7:1f:68:f6:
+ d6:58:75:33:a5:d2:b7:65:6a:28:40:bc:0e:1e:78:ee:9a:13:
+ 3c:b0:8b:8f:98:72:86:50:3a:a3:bf:6d:f0:21:95:a8:73:d0:
+ dd:e5:0e:25:b1:62:76:65:69:1f:ee:26:82:ab:be:a4:a8:30:
+ a7:41:34:07:57:2f:8b:ab:25:af:cb:23:a5:79:cf:b2:a2:17:
+ 02:a7:aa:50:92:6e:0d:9b:ff:c9:22:38:b4:0f:47:94:d2:80:
+ 7f:92:30:00:ec:5b:22:e2:a6:71:5e:e8:8f:0d:2f:38:2c:29:
+ 47:6a:7f:20:0a:e2:42:cb:b7:6e:2b:29:0f:03:55:94:84:5f:
+ e7:47:bf:ae:75:88:05:4e:42:ac:78:57:9d:9c:e2:77:d2:17:
+ 42:55:ba:f8:77:ee:61:d6:e8:ec:aa:e0:7a:a6:65:c6:35:80:
+ 08:3d:39:a6:70:8c:9e:6d:7a:ee:e7:cf:36:46:98:00:c8:7b:
+ b8:84:7f:9d:9f:bd:31:4f:99:25:6e:76:9a:5d:46:3e:40:70:
+ c6:a8:03:f3:98:9c:be:fb:f6:ad:c2:8d:e3:f9:7d:93:3a:78:
+ da:b3:d7:dc
-----BEGIN CERTIFICATE-----
MIICwjCCAaqgAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAwwJQyBS
-b290IENBMB4XDTE2MDIyODIwMjcwM1oXDTI2MDIyNTIwMjcwM1owDzENMAsGA1UE
-AwwERSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALpB6VFV3tCa
-qe9M/ASkJnbeHVr6hPmkN5GFC5LVU969d+yLtyDR2yZjS5FK05M6Gh5Q6wL9asht
-FHK4xN5cSnSTDqwG01v4+RnNCm88kOx9+EOdZjWaWObCjRBslHnls/r2mN5QjsC3
-ATMSQ0xSV63IDLFi4K6J2K3UlNl487UNEz5kVXODiyz2bIyaUYWezDNdqrAdlCnX
-e+23dyxTowWDwmnJLa3OdmLW307ndcsZLajiGHUIV9GpKilocAKMA6MAIjfVwH2i
-p0DOLHlYUgYfemG3zufCg91tzApkFyfLIVY4wtugrP0YtRUB9VAllreRq1FCR4z8
-32pU+epJpnUCAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
-AQYwDQYJKoZIhvcNAQELBQADggEBAGM330JYsE7RDoiZ0MignyH2E2rBu4tZAXZu
-AR03y7kS3g14SbgmJmucMoN9Obzj+FVrzBJZsBG0cEwUmTTlGavS/1pBFJn20QP3
-KBwiVgbvEKzgvkVHwfVr0el4OohPN9vFLaaVOv+En3j8L7h+uOSUacmcJvUpL4Ga
-oCaCZVCTY1Rx/tbQkEcd8yi8j1rnblSKL1/oSkB35s9G6Ura0n9whlZvEBd78dAd
-0j2x3nxfvf5QPRPPX0PH0BBguevLVd5gGse2UDfqns8YKLDfxw6uCFohJQLDCMoc
-PrGfu3IV9l4KMr8DxwXmIFyC35+eOdyGRfNlzPeMSAhTonOz510=
+b290IENBMB4XDTE2MTAwNDE4NTMyNFoXDTI2MTAwMjE4NTMyNFowDzENMAsGA1UE
+AwwERSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKJ+o/3B13jN
+V6xnVDdp+3JvHY/QRw8RFKtC2D1qNCvWOAffFh3GYuvXEuGGg/Ldj5cJlI8b/zuE
+m0jlDUNrrrt1iBzGOn/YEtl8Ehht4vCI1D5ak7OvwXmhtqP3VkYh5n1uNuq6S1L3
+qUULgwksCSKKZ1qPiGCwEQclm8JqPGNMDmlFzp26ydQB+3hWOAiP5db/rOQE+ibP
+0gUzV6OOgMC2QNXTyoUXMLIk9BmvxUik7cBJwaS3iSm65S03eBzWPpsD+rx74nam
+cPMbnbJL/HJ7d4lQu4gvtbaixzMnt9EafNRY416IyvhJw83MD5NLPP11w3tvv9Pb
+ui4xe6elQsUCAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQELBQADggEBAJKLk5QDBJE/TYvzkFPuc7Uzx2HqD6VZm/AN
+T31IDVpY5x9o9tZYdTOl0rdlaihAvA4eeO6aEzywi4+YcoZQOqO/bfAhlahz0N3l
+DiWxYnZlaR/uJoKrvqSoMKdBNAdXL4urJa/LI6V5z7KiFwKnqlCSbg2b/8kiOLQP
+R5TSgH+SMADsWyLipnFe6I8NLzgsKUdqfyAK4kLLt24rKQ8DVZSEX+dHv651iAVO
+Qqx4V52c4nfSF0JVuvh37mHW6Oyq4HqmZcY1gAg9OaZwjJ5teu7nzzZGmADIe7iE
+f52fvTFPmSVudppdRj5AcMaoA/OYnL779q3CjeP5fZM6eNqz19w=
-----END CERTIFICATE-----
diff --git a/chromium/net/data/ssl/certificates/client_3.key b/chromium/net/data/ssl/certificates/client_3.key
index 959067c2b77..20498bab62e 100644
--- a/chromium/net/data/ssl/certificates/client_3.key
+++ b/chromium/net/data/ssl/certificates/client_3.key
@@ -1,27 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
-MIIEpgIBAAKCAQEA6z9ms1VvYWgj200gTpdKD9ufjPjNp+KddsNAURQzKKXli1Wb
-RetHQ5NRlZFhBVWKvY0BNCprl12FYZm4a9huxYbM4nlfUJFMDTtxgUAZbpPmaEPe
-u+tNRtpLJZ3hhVdokoXiPiS8MNF5jeY+ouZK1kpJByjr7S+5N/DDssBkSuFVjEUW
-8Gy7cxEPsTADkAvef92W/LDWwMH9cPXmc0aBTZuG2eisyZGb3OfEQ7cO48gShxaH
-eRui0XP8/F7zNkBFo836DEB0j3UVAo4njEG5JNSAAXAx+NVVJI9G4YInch9mbopm
-jR9uTs/KBft9STgwL+9eI/+gIONYhFmkmuUY/wIDAQABAoIBAQC0i/JMTJOxFHYA
-h472AlLLHOm1Dfb4lIn5bhzcnT4uQjSL3WXQIaSODnCc8/icWWyj0aZM3Qm6IAKQ
-R6Qs0O0jGDQC1Nf8Q6c0uJyCcCmUnlpFR2GYpByo9jyaYDOHXPBbE/nxa8wrQ3mh
-GEaWS1zAXj7yCcwYO3pRnqzzcYkHlbRlARbRZir6xzNaqYCokU7O4Euh1h37zIc3
-QEwxbHBTDUDzVAXKDKa+srjUbtSkByp8nWPTPDW63IRMnbEsFHHTdM2tGzQgIXjC
-69iVGfbl2Mrc5+RmmBfnIvzyGnO71ywiC6J4Ncgg5X+ukbskkFhpMfhk8XZMdeW+
-Uw4rGbXBAoGBAP3UxsuE4Og31TR5EqObZWVymRVm9CEKc5uNiyrsBYkPWXwMtw7X
-U6s9N0E4iWOc7m57b0PGnD39hXEWxF5kAzttgvYZLnc2/SF8aRJvd8hy/gKcA7xm
-6OmNEfGEunHLyCOgTzr4hicZ5GWFkZV1GaBiYTDPOQlk1A79/LWtOUJRAoGBAO1B
-+cAdDGDCjpKpYDShz6GN8Fx7ByG+7OuYcD4MlFb25yvZ0kgnjIKZRODHfNFsrXMf
-8QBTx13zjC187ghWY3Jtt15fecWWKuOhzyatWlgeHfHzeO62NdddP8S4AAr2FMUL
-P0pNbwrZmkVCyn+sE5Vc+u9lPIfIFJwmPEu+JQJPAoGBAJOJsscnBEdV9KIcYZ4h
-O+2cj6hmAC6YUZwvyJ15NLp25o95IIoK1MIqwcwyHYF9/QTQ0Fp3vec2TfLuxdML
-lOlc/Qsold6LYtSs6LHjgp9LX6OKpY1Dz8u4yJ42hNySE1HJ42OmguuFXEE6QuW5
-e9zCcjWZrVBtf+j67oF3H1oRAoGBAIdWgyjbaRwo3zs58u8S/mWhmeKnK0JMrskV
-g7Fha5zP6r5Q2mreZIB6/ZdbNBAidi6dodQV9jvZmbS49u86mC/F9juXKtdS+dQv
-kQL3D/oD9AD4aZuBxOS9BIsqipu2E9Lyv3+a/CSsTBwGJYz+k404JMw6a3To5RjN
-lsd+B45xAoGBAIFolC7ah49Skdfc0od0+FjxlCvwXqmubA/U8yvAYixlXSPIwsi+
-HelE1wjigyzpfm/UGMU5FnnD53ZN/uTTA0GMmnEQl11DwIQ0fIhnD0o/a5wRw5o5
-zCPydEt/BvXAoLB5bVqwY0pHO9b/Zb1R5RW4NCk13zM9mamMnsBJTYIU
+MIIEpAIBAAKCAQEAqblhT1L+ZDRTZ0fYWCIjgpdv0ILn9ws9204VFTjf3jU+66wZ
+m9iN2+j62y/68iBFkt/107YqA2so3o0kS6o7Izt+EQg+o5ZvvHM3fVSR/IGejHbt
+1fbk9o7oblbikOtRpfOQ2EXZ+h2RASE6YTE66lrE6RruAOaWYsoLpzepHDlOEj6t
+q+24LIalckzKOQNNYfwpuLzbMomVCmIaKNaObesGM5pbj+hz4S8ehCH7CzgnsYOg
+x/7tecyrV6XPW7OEDLm4GoyQIlnxvk1GDIVje6caSW+OzqL65SlkAwLcaN95tmub
+IgdZr6H/upzmXdRh3kCBLgKWAqpUJNSzxBjj/wIDAQABAoIBACvRiKYKL1N/jujj
+S5+1cKWOo3eZ1HmblWTBTAAmpuWfqZb+3720sytLgziDsq5AVrYMzFLUfRRU3kBX
+AD/ou0vlWC7dig6CEGb++ByLcQVYEa8CJXVQQNzHGIskM2pm1rWZpJOxtQ02BPHd
+ukzNgQBwXtYv9bKV1c27jDan0ClQ1nj14TK8k2LLCDYd3O9Zbfm+5fKqsJIjDFm6
+rPeltV8yFBsZPxBJAQUNTR0fnq5mYLrCm8ARWYbLxbbWSjInXStrwVuaG8P/T7Om
+sl6Jj7eRClM6HrCtJMukgAQ1f6Rg882MVKKv8sjVO0ZHIZrg+e3TLPLrngXYeLxP
+NgrJgUECgYEA2J5Ee5cVyvbJITD71dVHcZc8QcaBVFBsSCcw0ZQ4LgUmS/z3ERYq
+mpdXzU1bTAOOMujOjiv9qYXn800DqRiDML384/cQz9DNkUth2eSQjk2Ryp9x5z+Y
+CeeMrzTtPK+SRfbC12UnNkZqwg+OrVgQUswbgOt2tM/9Bx5ujo6kuDsCgYEAyJSX
+ouGtWU7wys3ffmrmYlc0G/hGXxvqunpD8YR61fxyIMb1M9FfqObbCWaD7tkboEfe
+u6l7+d+4eJO2Gv++68asqHPsNQeq0qqAVPVNVusD+Uw9DPK4yxfbtn0lbALikCAB
+VT4yudolYsZA0b6tHApSG2bZkr3lXSwLFmljCw0CgYEAtT3m6smE8Gb/7geADm/+
+8Omq/xXJy/PmRZCU5iXvw4GHg3jKd79mMiaCzkH1K2qmJa5odMgV2ysw4X8Emwzp
+Z3TvDQYBSP/Zn8HEw3zb/lSksTYrJWMuIMteCJJuFKKJ7oQCjhoSbvUICgreQ+c0
+8THZqUpZ7ftAKB6sPhbXd1UCgYEAsYjL+nBTtcOoX2j/U26dAhf7WHJVHyOfjHRh
+pOjErJhoD9jp+XZtfBrxbo2dYxApYqGaZHHr+MvrBFaBjb4lp5zO/76zKHDj4tjl
+A82nKbKUbtjrBIXlyGUSpKB6OfMHw9eANon57gRGqPmfL8bchAAiknxjQX3xAJnW
+Kn0XHBUCgYAnpq1dGwdknEcVnVMsoZQirc6UK39u8KIH6S7P2QhSzc6pXOeC8HGj
+H6zvc3LtddSj8tCWfGDGVWp4v9TIWHOZbmmg20iU93j7Xi53cL3zB6TaAa467tj9
+0JFgB4tk1zKLggwkF26Sf3m+kkPDGwm4+jmk8TfV7VZ9yCZQY5Onig==
-----END RSA PRIVATE KEY-----
diff --git a/chromium/net/data/ssl/certificates/client_3.pem b/chromium/net/data/ssl/certificates/client_3.pem
index 0a2a46b90e7..4f5ad24856c 100644
--- a/chromium/net/data/ssl/certificates/client_3.pem
+++ b/chromium/net/data/ssl/certificates/client_3.pem
@@ -5,66 +5,66 @@ Certificate:
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=E CA
Validity
- Not Before: Feb 28 20:27:03 2016 GMT
- Not After : Feb 25 20:27:03 2026 GMT
+ Not Before: Oct 4 18:53:24 2016 GMT
+ Not After : Oct 2 18:53:24 2026 GMT
Subject: CN=Client Cert F
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:eb:3f:66:b3:55:6f:61:68:23:db:4d:20:4e:97:
- 4a:0f:db:9f:8c:f8:cd:a7:e2:9d:76:c3:40:51:14:
- 33:28:a5:e5:8b:55:9b:45:eb:47:43:93:51:95:91:
- 61:05:55:8a:bd:8d:01:34:2a:6b:97:5d:85:61:99:
- b8:6b:d8:6e:c5:86:cc:e2:79:5f:50:91:4c:0d:3b:
- 71:81:40:19:6e:93:e6:68:43:de:bb:eb:4d:46:da:
- 4b:25:9d:e1:85:57:68:92:85:e2:3e:24:bc:30:d1:
- 79:8d:e6:3e:a2:e6:4a:d6:4a:49:07:28:eb:ed:2f:
- b9:37:f0:c3:b2:c0:64:4a:e1:55:8c:45:16:f0:6c:
- bb:73:11:0f:b1:30:03:90:0b:de:7f:dd:96:fc:b0:
- d6:c0:c1:fd:70:f5:e6:73:46:81:4d:9b:86:d9:e8:
- ac:c9:91:9b:dc:e7:c4:43:b7:0e:e3:c8:12:87:16:
- 87:79:1b:a2:d1:73:fc:fc:5e:f3:36:40:45:a3:cd:
- fa:0c:40:74:8f:75:15:02:8e:27:8c:41:b9:24:d4:
- 80:01:70:31:f8:d5:55:24:8f:46:e1:82:27:72:1f:
- 66:6e:8a:66:8d:1f:6e:4e:cf:ca:05:fb:7d:49:38:
- 30:2f:ef:5e:23:ff:a0:20:e3:58:84:59:a4:9a:e5:
- 18:ff
+ 00:a9:b9:61:4f:52:fe:64:34:53:67:47:d8:58:22:
+ 23:82:97:6f:d0:82:e7:f7:0b:3d:db:4e:15:15:38:
+ df:de:35:3e:eb:ac:19:9b:d8:8d:db:e8:fa:db:2f:
+ fa:f2:20:45:92:df:f5:d3:b6:2a:03:6b:28:de:8d:
+ 24:4b:aa:3b:23:3b:7e:11:08:3e:a3:96:6f:bc:73:
+ 37:7d:54:91:fc:81:9e:8c:76:ed:d5:f6:e4:f6:8e:
+ e8:6e:56:e2:90:eb:51:a5:f3:90:d8:45:d9:fa:1d:
+ 91:01:21:3a:61:31:3a:ea:5a:c4:e9:1a:ee:00:e6:
+ 96:62:ca:0b:a7:37:a9:1c:39:4e:12:3e:ad:ab:ed:
+ b8:2c:86:a5:72:4c:ca:39:03:4d:61:fc:29:b8:bc:
+ db:32:89:95:0a:62:1a:28:d6:8e:6d:eb:06:33:9a:
+ 5b:8f:e8:73:e1:2f:1e:84:21:fb:0b:38:27:b1:83:
+ a0:c7:fe:ed:79:cc:ab:57:a5:cf:5b:b3:84:0c:b9:
+ b8:1a:8c:90:22:59:f1:be:4d:46:0c:85:63:7b:a7:
+ 1a:49:6f:8e:ce:a2:fa:e5:29:64:03:02:dc:68:df:
+ 79:b6:6b:9b:22:07:59:af:a1:ff:ba:9c:e6:5d:d4:
+ 61:de:40:81:2e:02:96:02:aa:54:24:d4:b3:c4:18:
+ e3:ff
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
email:santest@example.com, othername:<unsupported>
Signature Algorithm: sha256WithRSAEncryption
- 3f:63:47:b1:7f:67:6d:14:c9:b0:84:e8:c1:67:4e:a1:18:a5:
- a6:d9:15:03:c3:5b:ec:f1:c3:ee:3d:f2:ea:01:f1:9c:07:da:
- 29:b5:62:ae:0e:6b:8e:dc:fd:67:d7:d9:b0:9f:c8:81:ce:85:
- 27:8d:80:cf:5b:ab:e6:c3:8c:37:1e:29:42:26:51:90:cf:31:
- e0:4d:49:9f:04:6d:8d:f9:ac:c4:76:1e:3f:0e:f3:70:34:79:
- c8:8e:a9:1e:06:e1:e1:4d:c3:9a:6c:fd:1a:41:66:79:ec:8c:
- 78:52:ed:74:6b:90:f1:99:d3:1e:d7:cc:c8:74:d0:72:36:25:
- 2e:fc:91:b0:13:6f:4a:53:2e:e9:72:57:f9:dd:f0:b4:60:f4:
- a4:15:57:06:e5:38:be:19:3b:a8:1a:5a:73:42:88:3e:59:ab:
- 9b:46:43:38:53:4a:1e:c7:9c:1a:4e:df:88:af:a6:92:17:81:
- 28:e1:ad:a5:43:0d:ae:f7:c1:cd:6f:e5:55:2c:c0:9a:ac:18:
- 1f:05:2f:52:f7:6c:a9:94:eb:1d:9a:a3:9f:db:44:cc:b2:e0:
- 9e:3a:d5:0a:92:70:d8:89:5e:a9:5b:43:60:69:e4:ba:fb:2f:
- 37:83:aa:27:a6:d9:b9:11:fa:58:a8:ac:23:6f:c2:a2:c5:c7:
- 51:ec:94:f0
+ 5f:d8:99:71:11:d1:1f:ae:7e:4a:fa:85:ff:f6:18:60:e0:c3:
+ e8:8c:8d:7b:51:b9:ed:ea:26:e8:2b:ff:d8:5c:1e:98:cb:c6:
+ a5:e8:ef:21:af:e5:a8:f2:47:93:5e:36:66:21:7d:84:c7:b2:
+ 2c:70:31:71:67:88:c4:a9:45:c1:20:1b:e1:47:df:75:d6:83:
+ a2:db:45:27:ca:fa:b1:11:b0:c2:33:bc:a7:2c:fb:bd:2b:06:
+ 68:0d:95:4c:d4:2f:ab:2a:5b:f8:92:4e:9b:74:30:f2:8d:7c:
+ 26:c7:f1:0f:0e:f7:f1:28:b6:84:90:db:ac:a0:1a:84:4c:3e:
+ 0b:14:39:de:90:ca:58:2c:f8:16:a4:0e:4d:cd:ba:c5:1d:bb:
+ 91:69:a6:55:83:96:20:ee:1f:33:58:8f:da:44:32:9b:84:1e:
+ 99:d3:74:60:c9:10:67:5c:a9:03:11:74:e3:82:85:99:4c:aa:
+ 4e:3d:ee:ac:91:7c:e8:b9:b1:64:08:45:48:6f:34:f4:52:8a:
+ 68:f9:80:6b:5b:b2:af:83:cb:fc:77:fd:9f:d0:aa:69:3e:bd:
+ f7:ca:05:17:f8:f4:39:d3:58:9a:04:81:43:a8:b3:66:90:9e:
+ b6:27:b3:1c:25:ad:8f:8c:c6:45:a4:f6:02:60:3a:0b:5e:6f:
+ 6b:e6:1b:3f
-----BEGIN CERTIFICATE-----
MIIC8jCCAdqgAwIBAgICEAMwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwERSBD
-QTAeFw0xNjAyMjgyMDI3MDNaFw0yNjAyMjUyMDI3MDNaMBgxFjAUBgNVBAMMDUNs
-aWVudCBDZXJ0IEYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDrP2az
-VW9haCPbTSBOl0oP25+M+M2n4p12w0BRFDMopeWLVZtF60dDk1GVkWEFVYq9jQE0
-KmuXXYVhmbhr2G7FhszieV9QkUwNO3GBQBluk+ZoQ967601G2kslneGFV2iSheI+
-JLww0XmN5j6i5krWSkkHKOvtL7k38MOywGRK4VWMRRbwbLtzEQ+xMAOQC95/3Zb8
-sNbAwf1w9eZzRoFNm4bZ6KzJkZvc58RDtw7jyBKHFod5G6LRc/z8XvM2QEWjzfoM
-QHSPdRUCjieMQbkk1IABcDH41VUkj0bhgidyH2ZuimaNH25Oz8oF+31JODAv714j
-/6Ag41iEWaSa5Rj/AgMBAAGjTzBNMEsGA1UdEQREMEKBE3NhbnRlc3RAZXhhbXBs
+QTAeFw0xNjEwMDQxODUzMjRaFw0yNjEwMDIxODUzMjRaMBgxFjAUBgNVBAMMDUNs
+aWVudCBDZXJ0IEYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpuWFP
+Uv5kNFNnR9hYIiOCl2/Qguf3Cz3bThUVON/eNT7rrBmb2I3b6PrbL/ryIEWS3/XT
+tioDayjejSRLqjsjO34RCD6jlm+8czd9VJH8gZ6Mdu3V9uT2juhuVuKQ61Gl85DY
+Rdn6HZEBITphMTrqWsTpGu4A5pZiygunN6kcOU4SPq2r7bgshqVyTMo5A01h/Cm4
+vNsyiZUKYhoo1o5t6wYzmluP6HPhLx6EIfsLOCexg6DH/u15zKtXpc9bs4QMubga
+jJAiWfG+TUYMhWN7pxpJb47OovrlKWQDAtxo33m2a5siB1mvof+6nOZd1GHeQIEu
+ApYCqlQk1LPEGOP/AgMBAAGjTzBNMEsGA1UdEQREMEKBE3NhbnRlc3RAZXhhbXBs
ZS5jb22gKwYKKwYBBAGCNxQCA6AdDBtzYW50ZXN0QGFkLmNvcnAuZXhhbXBsZS5j
-b20wDQYJKoZIhvcNAQELBQADggEBAD9jR7F/Z20UybCE6MFnTqEYpabZFQPDW+zx
-w+498uoB8ZwH2im1Yq4Oa47c/WfX2bCfyIHOhSeNgM9bq+bDjDceKUImUZDPMeBN
-SZ8EbY35rMR2Hj8O83A0eciOqR4G4eFNw5ps/RpBZnnsjHhS7XRrkPGZ0x7XzMh0
-0HI2JS78kbATb0pTLulyV/nd8LRg9KQVVwblOL4ZO6gaWnNCiD5Zq5tGQzhTSh7H
-nBpO34ivppIXgSjhraVDDa73wc1v5VUswJqsGB8FL1L3bKmU6x2ao5/bRMyy4J46
-1QqScNiJXqlbQ2Bp5Lr7LzeDqiem2bkR+liorCNvwqLFx1HslPA=
+b20wDQYJKoZIhvcNAQELBQADggEBAF/YmXER0R+ufkr6hf/2GGDgw+iMjXtRue3q
+Jugr/9hcHpjLxqXo7yGv5ajyR5NeNmYhfYTHsixwMXFniMSpRcEgG+FH33XWg6Lb
+RSfK+rERsMIzvKcs+70rBmgNlUzUL6sqW/iSTpt0MPKNfCbH8Q8O9/EotoSQ26yg
+GoRMPgsUOd6Qylgs+BakDk3NusUdu5FpplWDliDuHzNYj9pEMpuEHpnTdGDJEGdc
+qQMRdOOChZlMqk497qyRfOi5sWQIRUhvNPRSimj5gGtbsq+Dy/x3/Z/Qqmk+vffK
+BRf49DnTWJoEgUOos2aQnrYnsxwlrY+MxkWk9gJgOgteb2vmGz8=
-----END CERTIFICATE-----
diff --git a/chromium/net/data/ssl/certificates/client_3.pk8 b/chromium/net/data/ssl/certificates/client_3.pk8
index e0999f1718f..68f019a523d 100644
--- a/chromium/net/data/ssl/certificates/client_3.pk8
+++ b/chromium/net/data/ssl/certificates/client_3.pk8
Binary files differ
diff --git a/chromium/net/data/ssl/certificates/client_3_ca.pem b/chromium/net/data/ssl/certificates/client_3_ca.pem
index 8753ac47571..dd58ffa7a3c 100644
--- a/chromium/net/data/ssl/certificates/client_3_ca.pem
+++ b/chromium/net/data/ssl/certificates/client_3_ca.pem
@@ -5,31 +5,31 @@ Certificate:
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=C Root CA
Validity
- Not Before: Feb 28 20:27:03 2016 GMT
- Not After : Feb 25 20:27:03 2026 GMT
+ Not Before: Oct 4 18:53:24 2016 GMT
+ Not After : Oct 2 18:53:24 2026 GMT
Subject: CN=E CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:ba:41:e9:51:55:de:d0:9a:a9:ef:4c:fc:04:a4:
- 26:76:de:1d:5a:fa:84:f9:a4:37:91:85:0b:92:d5:
- 53:de:bd:77:ec:8b:b7:20:d1:db:26:63:4b:91:4a:
- d3:93:3a:1a:1e:50:eb:02:fd:6a:c8:6d:14:72:b8:
- c4:de:5c:4a:74:93:0e:ac:06:d3:5b:f8:f9:19:cd:
- 0a:6f:3c:90:ec:7d:f8:43:9d:66:35:9a:58:e6:c2:
- 8d:10:6c:94:79:e5:b3:fa:f6:98:de:50:8e:c0:b7:
- 01:33:12:43:4c:52:57:ad:c8:0c:b1:62:e0:ae:89:
- d8:ad:d4:94:d9:78:f3:b5:0d:13:3e:64:55:73:83:
- 8b:2c:f6:6c:8c:9a:51:85:9e:cc:33:5d:aa:b0:1d:
- 94:29:d7:7b:ed:b7:77:2c:53:a3:05:83:c2:69:c9:
- 2d:ad:ce:76:62:d6:df:4e:e7:75:cb:19:2d:a8:e2:
- 18:75:08:57:d1:a9:2a:29:68:70:02:8c:03:a3:00:
- 22:37:d5:c0:7d:a2:a7:40:ce:2c:79:58:52:06:1f:
- 7a:61:b7:ce:e7:c2:83:dd:6d:cc:0a:64:17:27:cb:
- 21:56:38:c2:db:a0:ac:fd:18:b5:15:01:f5:50:25:
- 96:b7:91:ab:51:42:47:8c:fc:df:6a:54:f9:ea:49:
- a6:75
+ 00:a2:7e:a3:fd:c1:d7:78:cd:57:ac:67:54:37:69:
+ fb:72:6f:1d:8f:d0:47:0f:11:14:ab:42:d8:3d:6a:
+ 34:2b:d6:38:07:df:16:1d:c6:62:eb:d7:12:e1:86:
+ 83:f2:dd:8f:97:09:94:8f:1b:ff:3b:84:9b:48:e5:
+ 0d:43:6b:ae:bb:75:88:1c:c6:3a:7f:d8:12:d9:7c:
+ 12:18:6d:e2:f0:88:d4:3e:5a:93:b3:af:c1:79:a1:
+ b6:a3:f7:56:46:21:e6:7d:6e:36:ea:ba:4b:52:f7:
+ a9:45:0b:83:09:2c:09:22:8a:67:5a:8f:88:60:b0:
+ 11:07:25:9b:c2:6a:3c:63:4c:0e:69:45:ce:9d:ba:
+ c9:d4:01:fb:78:56:38:08:8f:e5:d6:ff:ac:e4:04:
+ fa:26:cf:d2:05:33:57:a3:8e:80:c0:b6:40:d5:d3:
+ ca:85:17:30:b2:24:f4:19:af:c5:48:a4:ed:c0:49:
+ c1:a4:b7:89:29:ba:e5:2d:37:78:1c:d6:3e:9b:03:
+ fa:bc:7b:e2:76:a6:70:f3:1b:9d:b2:4b:fc:72:7b:
+ 77:89:50:bb:88:2f:b5:b6:a2:c7:33:27:b7:d1:1a:
+ 7c:d4:58:e3:5e:88:ca:f8:49:c3:cd:cc:0f:93:4b:
+ 3c:fd:75:c3:7b:6f:bf:d3:db:ba:2e:31:7b:a7:a5:
+ 42:c5
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints: critical
@@ -37,35 +37,35 @@ Certificate:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
Signature Algorithm: sha256WithRSAEncryption
- 63:37:df:42:58:b0:4e:d1:0e:88:99:d0:c8:a0:9f:21:f6:13:
- 6a:c1:bb:8b:59:01:76:6e:01:1d:37:cb:b9:12:de:0d:78:49:
- b8:26:26:6b:9c:32:83:7d:39:bc:e3:f8:55:6b:cc:12:59:b0:
- 11:b4:70:4c:14:99:34:e5:19:ab:d2:ff:5a:41:14:99:f6:d1:
- 03:f7:28:1c:22:56:06:ef:10:ac:e0:be:45:47:c1:f5:6b:d1:
- e9:78:3a:88:4f:37:db:c5:2d:a6:95:3a:ff:84:9f:78:fc:2f:
- b8:7e:b8:e4:94:69:c9:9c:26:f5:29:2f:81:9a:a0:26:82:65:
- 50:93:63:54:71:fe:d6:d0:90:47:1d:f3:28:bc:8f:5a:e7:6e:
- 54:8a:2f:5f:e8:4a:40:77:e6:cf:46:e9:4a:da:d2:7f:70:86:
- 56:6f:10:17:7b:f1:d0:1d:d2:3d:b1:de:7c:5f:bd:fe:50:3d:
- 13:cf:5f:43:c7:d0:10:60:b9:eb:cb:55:de:60:1a:c7:b6:50:
- 37:ea:9e:cf:18:28:b0:df:c7:0e:ae:08:5a:21:25:02:c3:08:
- ca:1c:3e:b1:9f:bb:72:15:f6:5e:0a:32:bf:03:c7:05:e6:20:
- 5c:82:df:9f:9e:39:dc:86:45:f3:65:cc:f7:8c:48:08:53:a2:
- 73:b3:e7:5d
+ 92:8b:93:94:03:04:91:3f:4d:8b:f3:90:53:ee:73:b5:33:c7:
+ 61:ea:0f:a5:59:9b:f0:0d:4f:7d:48:0d:5a:58:e7:1f:68:f6:
+ d6:58:75:33:a5:d2:b7:65:6a:28:40:bc:0e:1e:78:ee:9a:13:
+ 3c:b0:8b:8f:98:72:86:50:3a:a3:bf:6d:f0:21:95:a8:73:d0:
+ dd:e5:0e:25:b1:62:76:65:69:1f:ee:26:82:ab:be:a4:a8:30:
+ a7:41:34:07:57:2f:8b:ab:25:af:cb:23:a5:79:cf:b2:a2:17:
+ 02:a7:aa:50:92:6e:0d:9b:ff:c9:22:38:b4:0f:47:94:d2:80:
+ 7f:92:30:00:ec:5b:22:e2:a6:71:5e:e8:8f:0d:2f:38:2c:29:
+ 47:6a:7f:20:0a:e2:42:cb:b7:6e:2b:29:0f:03:55:94:84:5f:
+ e7:47:bf:ae:75:88:05:4e:42:ac:78:57:9d:9c:e2:77:d2:17:
+ 42:55:ba:f8:77:ee:61:d6:e8:ec:aa:e0:7a:a6:65:c6:35:80:
+ 08:3d:39:a6:70:8c:9e:6d:7a:ee:e7:cf:36:46:98:00:c8:7b:
+ b8:84:7f:9d:9f:bd:31:4f:99:25:6e:76:9a:5d:46:3e:40:70:
+ c6:a8:03:f3:98:9c:be:fb:f6:ad:c2:8d:e3:f9:7d:93:3a:78:
+ da:b3:d7:dc
-----BEGIN CERTIFICATE-----
MIICwjCCAaqgAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAwwJQyBS
-b290IENBMB4XDTE2MDIyODIwMjcwM1oXDTI2MDIyNTIwMjcwM1owDzENMAsGA1UE
-AwwERSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALpB6VFV3tCa
-qe9M/ASkJnbeHVr6hPmkN5GFC5LVU969d+yLtyDR2yZjS5FK05M6Gh5Q6wL9asht
-FHK4xN5cSnSTDqwG01v4+RnNCm88kOx9+EOdZjWaWObCjRBslHnls/r2mN5QjsC3
-ATMSQ0xSV63IDLFi4K6J2K3UlNl487UNEz5kVXODiyz2bIyaUYWezDNdqrAdlCnX
-e+23dyxTowWDwmnJLa3OdmLW307ndcsZLajiGHUIV9GpKilocAKMA6MAIjfVwH2i
-p0DOLHlYUgYfemG3zufCg91tzApkFyfLIVY4wtugrP0YtRUB9VAllreRq1FCR4z8
-32pU+epJpnUCAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
-AQYwDQYJKoZIhvcNAQELBQADggEBAGM330JYsE7RDoiZ0MignyH2E2rBu4tZAXZu
-AR03y7kS3g14SbgmJmucMoN9Obzj+FVrzBJZsBG0cEwUmTTlGavS/1pBFJn20QP3
-KBwiVgbvEKzgvkVHwfVr0el4OohPN9vFLaaVOv+En3j8L7h+uOSUacmcJvUpL4Ga
-oCaCZVCTY1Rx/tbQkEcd8yi8j1rnblSKL1/oSkB35s9G6Ura0n9whlZvEBd78dAd
-0j2x3nxfvf5QPRPPX0PH0BBguevLVd5gGse2UDfqns8YKLDfxw6uCFohJQLDCMoc
-PrGfu3IV9l4KMr8DxwXmIFyC35+eOdyGRfNlzPeMSAhTonOz510=
+b290IENBMB4XDTE2MTAwNDE4NTMyNFoXDTI2MTAwMjE4NTMyNFowDzENMAsGA1UE
+AwwERSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKJ+o/3B13jN
+V6xnVDdp+3JvHY/QRw8RFKtC2D1qNCvWOAffFh3GYuvXEuGGg/Ldj5cJlI8b/zuE
+m0jlDUNrrrt1iBzGOn/YEtl8Ehht4vCI1D5ak7OvwXmhtqP3VkYh5n1uNuq6S1L3
+qUULgwksCSKKZ1qPiGCwEQclm8JqPGNMDmlFzp26ydQB+3hWOAiP5db/rOQE+ibP
+0gUzV6OOgMC2QNXTyoUXMLIk9BmvxUik7cBJwaS3iSm65S03eBzWPpsD+rx74nam
+cPMbnbJL/HJ7d4lQu4gvtbaixzMnt9EafNRY416IyvhJw83MD5NLPP11w3tvv9Pb
+ui4xe6elQsUCAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQELBQADggEBAJKLk5QDBJE/TYvzkFPuc7Uzx2HqD6VZm/AN
+T31IDVpY5x9o9tZYdTOl0rdlaihAvA4eeO6aEzywi4+YcoZQOqO/bfAhlahz0N3l
+DiWxYnZlaR/uJoKrvqSoMKdBNAdXL4urJa/LI6V5z7KiFwKnqlCSbg2b/8kiOLQP
+R5TSgH+SMADsWyLipnFe6I8NLzgsKUdqfyAK4kLLt24rKQ8DVZSEX+dHv651iAVO
+Qqx4V52c4nfSF0JVuvh37mHW6Oyq4HqmZcY1gAg9OaZwjJ5teu7nzzZGmADIe7iE
+f52fvTFPmSVudppdRj5AcMaoA/OYnL779q3CjeP5fZM6eNqz19w=
-----END CERTIFICATE-----
diff --git a/chromium/net/data/ssl/certificates/client_4.key b/chromium/net/data/ssl/certificates/client_4.key
new file mode 100644
index 00000000000..b1e7e0f86c2
--- /dev/null
+++ b/chromium/net/data/ssl/certificates/client_4.key
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEILP75xbRvuB3x6CmLmO6dnAz4SzWM52MjX/ENrMfZWSEoAoGCCqGSM49
+AwEHoUQDQgAEeS7h2cVpnREfhVilcTyRzlg4kE1IhGT3MUl1BkvR5e1EgvkLapKA
+8lLte3NLOoH/gPKnhLDPmN5N2uTCEZhpzw==
+-----END EC PRIVATE KEY-----
diff --git a/chromium/net/data/ssl/certificates/client_4.pem b/chromium/net/data/ssl/certificates/client_4.pem
new file mode 100644
index 00000000000..3eeca242c95
--- /dev/null
+++ b/chromium/net/data/ssl/certificates/client_4.pem
@@ -0,0 +1,54 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 4100 (0x1004)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=E CA
+ Validity
+ Not Before: Oct 4 18:53:24 2016 GMT
+ Not After : Oct 2 18:53:24 2026 GMT
+ Subject: CN=Client Cert G
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (256 bit)
+ pub:
+ 04:79:2e:e1:d9:c5:69:9d:11:1f:85:58:a5:71:3c:
+ 91:ce:58:38:90:4d:48:84:64:f7:31:49:75:06:4b:
+ d1:e5:ed:44:82:f9:0b:6a:92:80:f2:52:ed:7b:73:
+ 4b:3a:81:ff:80:f2:a7:84:b0:cf:98:de:4d:da:e4:
+ c2:11:98:69:cf
+ ASN1 OID: prime256v1
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 70:44:30:40:b7:d6:5b:09:e6:81:a1:a7:80:cd:bc:12:5d:e1:
+ 45:7d:fb:04:5f:5f:21:b9:e5:a9:e0:79:52:5a:50:21:11:bb:
+ 8c:25:08:e1:6d:19:e3:ba:e7:69:74:db:a6:b2:41:a4:f5:39:
+ 63:18:e6:bc:ce:db:d8:3f:17:e1:90:9f:62:3a:d3:52:f4:c4:
+ 01:4d:db:ad:16:ad:8b:31:51:fe:82:68:fd:34:c4:58:dc:4d:
+ 6b:72:74:30:98:a6:03:4b:21:dd:54:1b:ed:e0:a5:3f:a9:5e:
+ 1d:e6:57:3f:13:f4:e0:dc:d0:bf:90:68:dc:e1:e7:b5:81:b4:
+ f8:d5:45:96:95:b9:cd:83:15:c8:32:a6:20:2c:fc:b5:05:42:
+ 1a:7e:26:4c:a1:9a:8b:26:2b:1b:72:c7:a5:38:f3:57:4c:b4:
+ 7f:8e:dc:d9:52:0a:52:ac:e5:d9:18:0b:ae:91:b9:c5:e0:13:
+ cb:15:8d:19:3b:e9:60:1b:6b:31:0a:c7:22:4a:5a:ed:49:cf:
+ 72:e1:dd:93:1e:43:a8:e0:3e:02:b6:06:ee:b9:a9:d3:d9:88:
+ 2d:81:f6:96:cb:13:07:a8:51:81:89:8c:6b:28:d3:0c:22:8f:
+ e9:d7:92:1d:5a:2a:d6:c0:55:6b:86:2b:a7:f9:9e:35:88:5d:
+ bb:42:eb:b8
+-----BEGIN CERTIFICATE-----
+MIICBjCB76ADAgECAgIQBDANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARFIENB
+MB4XDTE2MTAwNDE4NTMyNFoXDTI2MTAwMjE4NTMyNFowGDEWMBQGA1UEAwwNQ2xp
+ZW50IENlcnQgRzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHku4dnFaZ0RH4VY
+pXE8kc5YOJBNSIRk9zFJdQZL0eXtRIL5C2qSgPJS7XtzSzqB/4Dyp4Swz5jeTdrk
+whGYac+jLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG
+AQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBwRDBAt9ZbCeaBoaeAzbwSXeFFffsE
+X18hueWp4HlSWlAhEbuMJQjhbRnjuudpdNumskGk9TljGOa8ztvYPxfhkJ9iOtNS
+9MQBTdutFq2LMVH+gmj9NMRY3E1rcnQwmKYDSyHdVBvt4KU/qV4d5lc/E/Tg3NC/
+kGjc4ee1gbT41UWWlbnNgxXIMqYgLPy1BUIafiZMoZqLJisbcselOPNXTLR/jtzZ
+UgpSrOXZGAuukbnF4BPLFY0ZO+lgG2sxCsciSlrtSc9y4d2THkOo4D4CtgbuuanT
+2YgtgfaWyxMHqFGBiYxrKNMMIo/p15IdWirWwFVrhiun+Z41iF27Quu4
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/ssl/certificates/client_4.pk8 b/chromium/net/data/ssl/certificates/client_4.pk8
new file mode 100644
index 00000000000..20ea5cfd7bc
--- /dev/null
+++ b/chromium/net/data/ssl/certificates/client_4.pk8
Binary files differ
diff --git a/chromium/net/data/ssl/certificates/client_4_ca.pem b/chromium/net/data/ssl/certificates/client_4_ca.pem
new file mode 100644
index 00000000000..dd58ffa7a3c
--- /dev/null
+++ b/chromium/net/data/ssl/certificates/client_4_ca.pem
@@ -0,0 +1,71 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 4098 (0x1002)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=C Root CA
+ Validity
+ Not Before: Oct 4 18:53:24 2016 GMT
+ Not After : Oct 2 18:53:24 2026 GMT
+ Subject: CN=E CA
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:a2:7e:a3:fd:c1:d7:78:cd:57:ac:67:54:37:69:
+ fb:72:6f:1d:8f:d0:47:0f:11:14:ab:42:d8:3d:6a:
+ 34:2b:d6:38:07:df:16:1d:c6:62:eb:d7:12:e1:86:
+ 83:f2:dd:8f:97:09:94:8f:1b:ff:3b:84:9b:48:e5:
+ 0d:43:6b:ae:bb:75:88:1c:c6:3a:7f:d8:12:d9:7c:
+ 12:18:6d:e2:f0:88:d4:3e:5a:93:b3:af:c1:79:a1:
+ b6:a3:f7:56:46:21:e6:7d:6e:36:ea:ba:4b:52:f7:
+ a9:45:0b:83:09:2c:09:22:8a:67:5a:8f:88:60:b0:
+ 11:07:25:9b:c2:6a:3c:63:4c:0e:69:45:ce:9d:ba:
+ c9:d4:01:fb:78:56:38:08:8f:e5:d6:ff:ac:e4:04:
+ fa:26:cf:d2:05:33:57:a3:8e:80:c0:b6:40:d5:d3:
+ ca:85:17:30:b2:24:f4:19:af:c5:48:a4:ed:c0:49:
+ c1:a4:b7:89:29:ba:e5:2d:37:78:1c:d6:3e:9b:03:
+ fa:bc:7b:e2:76:a6:70:f3:1b:9d:b2:4b:fc:72:7b:
+ 77:89:50:bb:88:2f:b5:b6:a2:c7:33:27:b7:d1:1a:
+ 7c:d4:58:e3:5e:88:ca:f8:49:c3:cd:cc:0f:93:4b:
+ 3c:fd:75:c3:7b:6f:bf:d3:db:ba:2e:31:7b:a7:a5:
+ 42:c5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ 92:8b:93:94:03:04:91:3f:4d:8b:f3:90:53:ee:73:b5:33:c7:
+ 61:ea:0f:a5:59:9b:f0:0d:4f:7d:48:0d:5a:58:e7:1f:68:f6:
+ d6:58:75:33:a5:d2:b7:65:6a:28:40:bc:0e:1e:78:ee:9a:13:
+ 3c:b0:8b:8f:98:72:86:50:3a:a3:bf:6d:f0:21:95:a8:73:d0:
+ dd:e5:0e:25:b1:62:76:65:69:1f:ee:26:82:ab:be:a4:a8:30:
+ a7:41:34:07:57:2f:8b:ab:25:af:cb:23:a5:79:cf:b2:a2:17:
+ 02:a7:aa:50:92:6e:0d:9b:ff:c9:22:38:b4:0f:47:94:d2:80:
+ 7f:92:30:00:ec:5b:22:e2:a6:71:5e:e8:8f:0d:2f:38:2c:29:
+ 47:6a:7f:20:0a:e2:42:cb:b7:6e:2b:29:0f:03:55:94:84:5f:
+ e7:47:bf:ae:75:88:05:4e:42:ac:78:57:9d:9c:e2:77:d2:17:
+ 42:55:ba:f8:77:ee:61:d6:e8:ec:aa:e0:7a:a6:65:c6:35:80:
+ 08:3d:39:a6:70:8c:9e:6d:7a:ee:e7:cf:36:46:98:00:c8:7b:
+ b8:84:7f:9d:9f:bd:31:4f:99:25:6e:76:9a:5d:46:3e:40:70:
+ c6:a8:03:f3:98:9c:be:fb:f6:ad:c2:8d:e3:f9:7d:93:3a:78:
+ da:b3:d7:dc
+-----BEGIN CERTIFICATE-----
+MIICwjCCAaqgAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAwwJQyBS
+b290IENBMB4XDTE2MTAwNDE4NTMyNFoXDTI2MTAwMjE4NTMyNFowDzENMAsGA1UE
+AwwERSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKJ+o/3B13jN
+V6xnVDdp+3JvHY/QRw8RFKtC2D1qNCvWOAffFh3GYuvXEuGGg/Ldj5cJlI8b/zuE
+m0jlDUNrrrt1iBzGOn/YEtl8Ehht4vCI1D5ak7OvwXmhtqP3VkYh5n1uNuq6S1L3
+qUULgwksCSKKZ1qPiGCwEQclm8JqPGNMDmlFzp26ydQB+3hWOAiP5db/rOQE+ibP
+0gUzV6OOgMC2QNXTyoUXMLIk9BmvxUik7cBJwaS3iSm65S03eBzWPpsD+rx74nam
+cPMbnbJL/HJ7d4lQu4gvtbaixzMnt9EafNRY416IyvhJw83MD5NLPP11w3tvv9Pb
+ui4xe6elQsUCAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQELBQADggEBAJKLk5QDBJE/TYvzkFPuc7Uzx2HqD6VZm/AN
+T31IDVpY5x9o9tZYdTOl0rdlaihAvA4eeO6aEzywi4+YcoZQOqO/bfAhlahz0N3l
+DiWxYnZlaR/uJoKrvqSoMKdBNAdXL4urJa/LI6V5z7KiFwKnqlCSbg2b/8kiOLQP
+R5TSgH+SMADsWyLipnFe6I8NLzgsKUdqfyAK4kLLt24rKQ8DVZSEX+dHv651iAVO
+Qqx4V52c4nfSF0JVuvh37mHW6Oyq4HqmZcY1gAg9OaZwjJ5teu7nzzZGmADIe7iE
+f52fvTFPmSVudppdRj5AcMaoA/OYnL779q3CjeP5fZM6eNqz19w=
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/ssl/certificates/client_root_ca.pem b/chromium/net/data/ssl/certificates/client_root_ca.pem
new file mode 100644
index 00000000000..b40481033aa
--- /dev/null
+++ b/chromium/net/data/ssl/certificates/client_root_ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzjCCAbagAwIBAgIJAO+K/Ai3YiytMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
+BAMMCUMgUm9vdCBDQTAeFw0xNjEwMDQxODUzMjRaFw0yNjEwMDIxODUzMjRaMBQx
+EjAQBgNVBAMMCUMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBALKU+gX11E3vQ6CHy5bNfePr5uiJMHX+P97/I8y8DCk117+0gGxlO4adwImE
+dgA6jFmMcphJU+BPfi1eDwO2WHQVa31NALMy3CbEzv4qV1gqTAfNJdICKZk7S87E
+GbZUBauHe8q443UwD3c+R49XTsGvUSoMjh3N7K0/kNeoLi4RLW6WOZvJh954Rj+I
+EHmCibJENDfzdYWfQtLZJEYrzJv01ZdWcigvOR7qQqLdX6f2WTBaWpjgSnP5QzO/
+8gkX+rVRRUpbD/lMNdXqO9AoBcSG07tWMx1MDRnDG8SzrCQ4sScSbcPnHQDEbdDv
+suCnGXzSerruQXCqVwcCHIEHRSMCAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAHL9wuInYSfItXwoO2jG
+W08CPjcPMN1Q7yulKFtND6jU4cWB/m2xQmpMjhrahrF1hYwwiOXfwB+bxHOoekmK
+Uf+WmsiFXUQ5q9IeBMnxrrKOqZ9X2S+WaTi9GosJ52IEX4JJT7w3JDEcNTh3h66g
+FHB9cXao0EDx5fkEvSCKhcSy+tWjWzUB+GszG3ApCe0ZxbcehUSRSZTcLYvlNlXF
+NMNvEH5C1BVzCQWAZlgT4gp4miEPCFTc4Vr90pgDzJ3eFWu4V0s6snyDOip0PD9A
+N6wOvSix25wUYni46xGHFc9ZZn3x35HdhW9+IMAgJI14hMsoIHQwAgzqF4neRYvY
+RT4=
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/ssl/certificates/multi-root-BFE.keychain b/chromium/net/data/ssl/certificates/multi-root-BFE.keychain
new file mode 100644
index 00000000000..80976aa01c4
--- /dev/null
+++ b/chromium/net/data/ssl/certificates/multi-root-BFE.keychain
Binary files differ
diff --git a/chromium/net/data/ssl/certificates/ocsp-test-root.pem b/chromium/net/data/ssl/certificates/ocsp-test-root.pem
index 493fe54f9bc..cad67cb3114 100644
--- a/chromium/net/data/ssl/certificates/ocsp-test-root.pem
+++ b/chromium/net/data/ssl/certificates/ocsp-test-root.pem
@@ -2,7 +2,7 @@ Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
- Signature Algorithm: sha1WithRSAEncryption
+ Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=Testing CA
Validity
Not Before: Jan 1 06:00:00 2010 GMT
@@ -10,8 +10,8 @@ Certificate:
Subject: CN=Testing CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
- RSA Public Key: (1024 bit)
- Modulus (1024 bit):
+ Public-Key: (1024 bit)
+ Modulus:
00:a7:19:98:f2:93:0b:fe:73:d0:31:a8:7f:13:3d:
2f:37:8e:ee:ee:d5:2a:77:e4:4d:0f:c9:ff:6f:07:
ff:32:cb:f3:da:99:9d:e4:ed:65:83:2a:fc:b0:80:
@@ -28,24 +28,24 @@ Certificate:
X509v3 Certificate Policies:
Policy: 1.3.6.1.4.1.11129.2.4.1
- Signature Algorithm: sha1WithRSAEncryption
- 48:0c:c9:ab:8f:f2:cc:80:f1:1f:b3:3a:45:18:de:ab:c5:e0:
- d7:d4:64:a0:c4:86:2e:fc:58:3a:d7:86:ba:02:4e:29:95:72:
- 9f:20:5d:43:b2:41:4e:7c:a4:86:a1:df:b3:ab:7e:46:cb:af:
- 41:7d:c2:2b:b4:d3:22:d3:67:3e:13:ef:b6:9f:5c:8a:0d:3c:
- a7:58:eb:a9:21:d2:9b:6b:e5:b6:4f:d6:7c:22:a7:b3:18:82:
- b2:16:7d:d6:5c:7d:c9:46:be:91:49:e8:d2:42:95:cd:f8:8a:
- 91:50:e7:5b:2a:26:68:ef:e7:e7:c6:24:d1:3c:01:9d:6c:48:
- a4:f5
+ Signature Algorithm: sha256WithRSAEncryption
+ 72:49:8a:05:e0:02:b1:ff:13:d9:f7:02:29:60:8a:f0:39:f2:
+ 16:b0:49:15:6a:89:31:c7:bf:ba:00:82:e0:d1:ac:0e:33:0b:
+ c2:2f:b0:be:9b:ff:a2:d5:ee:70:37:29:63:34:39:44:99:48:
+ 61:37:cd:06:fd:52:50:76:9c:d6:2c:3c:c7:6f:d0:bb:38:1a:
+ e3:b3:55:fc:b8:6e:74:17:a8:c5:88:7e:54:70:f4:be:59:e4:
+ a1:fc:56:ee:54:de:88:68:39:40:9f:58:dd:6c:60:ca:1e:4b:
+ df:f6:d8:af:71:b5:1b:03:3d:2f:9d:a5:0a:3b:43:a6:68:3a:
+ 8f:28
-----BEGIN CERTIFICATE-----
-MIIB0DCCATmgAwIBAgIBATANBgkqhkiG9w0BAQUFADAVMRMwEQYDVQQDEwpUZXN0
+MIIBzTCCATagAwIBAgIBATANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwpUZXN0
aW5nIENBMB4XDTEwMDEwMTA2MDAwMFoXDTMyMTIwMTA2MDAwMFowFTETMBEGA1UE
AxMKVGVzdGluZyBDQTCBnTANBgkqhkiG9w0BAQEFAAOBiwAwgYcCgYEApxmY8pML
/nPQMah/Ez0vN47u7tUqd+RND8n/bwf/Msvz2pmd5O1lgyr8sIB/mHh1BlOdJYoM
48LHeWdlMJmpA0qbEVqHbDmoxOTtSs0MZAlZRvs57utHoHBNuwGKz0jDocS4lfxA
-n7SjQKmGsa/EVRmrnspHwwGFx3HGSqXs8H0CAQOjMjAwMBIGA1UdEwEB/wQIMAYB
-Af8CAQAwGgYDVR0gAQEABBAwDjAMBgorBgEEAdZ5AgQBMA0GCSqGSIb3DQEBBQUA
-A4GBAEgMyauP8syA8R+zOkUY3qvF4NfUZKDEhi78WDrXhroCTimVcp8gXUOyQU58
-pIah37OrfkbLr0F9wiu00yLTZz4T77afXIoNPKdY66kh0ptr5bZP1nwip7MYgrIW
-fdZcfclGvpFJ6NJClc34ipFQ51sqJmjv5+fGJNE8AZ1sSKT1
+n7SjQKmGsa/EVRmrnspHwwGFx3HGSqXs8H0CAQOjLzAtMBIGA1UdEwEB/wQIMAYB
+Af8CAQAwFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgQBMA0GCSqGSIb3DQEBCwUAA4GB
+AHJJigXgArH/E9n3AilgivA58hawSRVqiTHHv7oAguDRrA4zC8IvsL6b/6LV7nA3
+KWM0OUSZSGE3zQb9UlB2nNYsPMdv0Ls4GuOzVfy4bnQXqMWIflRw9L5Z5KH8Vu5U
+3ohoOUCfWN1sYMoeS9/22K9xtRsDPS+dpQo7Q6ZoOo8o
-----END CERTIFICATE-----
diff --git a/chromium/net/data/ssl/certificates/tripadvisor-verisign-chain.pem b/chromium/net/data/ssl/certificates/tripadvisor-verisign-chain.pem
new file mode 100644
index 00000000000..b7d053f42f8
--- /dev/null
+++ b/chromium/net/data/ssl/certificates/tripadvisor-verisign-chain.pem
@@ -0,0 +1,221 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 7c:46:cc:1b:4b:12:11:53:90:2a:cc:8b:7a:4d:95:c7
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 EV SSL CA - G3
+ Validity
+ Not Before: Feb 17 00:00:00 2016 GMT
+ Not After : Apr 2 23:59:59 2018 GMT
+ Subject: 1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=Delaware, C=US, ST=Massachusetts, L=Newton/businessCategory=Private Organization/serialNumber=3175592, O=TripAdvisor LLC, OU=IT, CN=www.tripadvisor.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:d5:ba:39:ca:90:9f:83:6c:ee:e6:ad:44:81:01:
+ de:6e:2c:6f:9e:41:33:41:af:57:2d:0d:7d:f8:92:
+ a7:a1:7b:60:33:77:fd:1c:b6:ca:65:2a:0f:32:51:
+ a2:46:d7:50:9a:7a:73:4f:e3:d9:5c:84:dd:e5:87:
+ 1b:59:d1:e9:28:24:9e:c2:9e:78:15:77:61:7e:b1:
+ 6c:c2:29:0f:1d:7e:55:e7:4b:5d:27:f8:91:73:65:
+ 44:6b:30:71:04:dd:3a:59:ba:21:0d:74:4e:2c:92:
+ 3a:29:e4:c8:12:dc:d7:a9:b2:f4:1f:65:86:bc:c1:
+ 7e:c5:b0:c2:ef:a6:d4:b1:c8:75:a4:7c:0c:43:5f:
+ 79:ee:bb:f4:04:a4:88:57:0e:f1:2c:df:2d:e0:6d:
+ 37:5d:78:8a:fc:9c:20:e7:46:8e:b6:e3:7b:35:80:
+ bf:76:9e:d0:ec:45:e7:7d:71:2e:e2:56:77:c4:fd:
+ 50:37:69:a6:9c:44:95:aa:07:e6:11:c5:ba:12:93:
+ 0f:49:b4:44:ac:8b:a2:be:e3:d4:2b:a3:92:98:10:
+ e8:51:8b:0b:3b:f6:c5:a6:66:9c:16:05:6f:65:56:
+ 6a:a9:fa:93:0c:87:11:9c:22:a1:9c:5f:bc:7f:9f:
+ 4b:dc:5b:28:3b:ef:b3:1e:83:1b:18:b9:02:f3:c8:
+ 18:7d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Alternative Name:
+ DNS:www.tripadvisor.com, DNS:tripadvisor.com
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 CRL Distribution Points:
+ URI:http://sr.symcb.com/sr.crl
+
+ X509v3 Certificate Policies:
+ Policy: 2.16.840.1.113733.1.7.23.6
+ CPS: https://d.symcb.com/cps
+ User Notice:
+ Explicit Text: https://d.symcb.com/rpa
+ Policy: 2.23.140.1.1
+
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ X509v3 Authority Key Identifier:
+ keyid:01:59:AB:E7:DD:3A:0B:59:A6:64:63:D6:CF:20:07:57:D5:91:E7:6A
+
+ Authority Information Access:
+ OCSP - URI:http://sr.symcd.com
+ CA Issuers - URI:http://sr.symcb.com/sr.crt
+
+ 1.3.6.1.4.1.11129.2.4.2:
+ [HEX DUMP]:0482016A0168007600DDEB1D2B7A0D4FA6208B81AD8168707E2E8E9D01D55C888D3D11C4CDB6ECBECC00000152EFA352B800000403004730450220084438A3CA1C0EB2216F3D2D7060893D85DEA1A9381978383A5B8A58D38E216E022100AC13863C7B699573D7802F058D512AE78E898179FD70D4EE37384ED7E8DE799B007600A4B90990B418581487BB13A2CC67700A3C359804F91BDFB8E377CD0EC80DDC1000000152EFA352CB00000403004730450221008D3B0D6275B41A26C1E54FD51B6215463672940F8442ECC6FA5A32E7C710D6E1022034606AF0C0FA24EEACF55B85EED66FDD466DDB84D6DC759AB61680240DD6F82300760068F698F81F6482BE3A8CEEB9281D4CFC71515D6793D444D10A67ACBB4F4FFBC400000152EFA352DB0000040300473045022100FE46B75EF8616827AFDACFA73CC017FDF93268B2C34DACF0C764A73D0A44EE750220743C1CC75BB648B71A51943A6BC0EE4B464330EA1371E78CF429C06AA883D224
+ Signature Algorithm: sha256WithRSAEncryption
+ 15:a2:27:7f:1c:e6:d7:02:74:c9:ab:77:dd:bf:75:f3:3a:27:
+ 6c:f5:4a:f6:43:d5:e0:db:c7:1d:12:57:a4:dd:a8:c6:f0:66:
+ ae:2d:df:bd:b4:43:cd:fa:e2:09:6a:fd:d0:55:b6:a5:d8:ef:
+ 43:34:71:1c:25:f8:ab:1b:09:63:d7:53:e7:97:70:ad:e4:60:
+ 72:92:35:18:3d:44:b2:a1:14:7b:af:52:14:e2:ed:e4:aa:72:
+ 05:99:ee:0b:e3:65:15:58:93:36:81:7a:6e:41:b1:df:5e:52:
+ 47:f6:59:2c:2f:32:ff:73:74:0b:cd:54:16:26:55:68:f3:b8:
+ f4:00:18:8e:a8:cf:25:f6:34:46:9b:d9:39:50:ff:0a:a2:65:
+ a1:b4:b8:04:67:eb:47:36:90:e0:bf:d3:71:12:84:04:d0:43:
+ fe:37:e3:c0:cb:7f:1b:2b:83:36:e6:40:a7:a4:4c:90:7e:8a:
+ b2:c0:22:d2:b7:09:53:94:9b:51:80:cc:17:37:06:d8:e3:8b:
+ ee:ac:4a:dc:4c:27:ee:01:28:10:79:dc:47:16:b6:72:90:8b:
+ a5:46:33:74:e2:fa:d8:b6:5f:20:5b:3c:1c:94:48:40:70:c8:
+ 2c:13:e3:ea:98:84:b5:92:e8:25:d1:84:a4:17:df:14:5b:1e:
+ 8e:85:f4:3a
+-----BEGIN CERTIFICATE-----
+MIIG6TCCBdGgAwIBAgIQfEbMG0sSEVOQKsyLek2VxzANBgkqhkiG9w0BAQsFADB3
+MQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd
+BgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMTH1N5bWFudGVj
+IENsYXNzIDMgRVYgU1NMIENBIC0gRzMwHhcNMTYwMjE3MDAwMDAwWhcNMTgwNDAy
+MjM1OTU5WjCB3DETMBEGCysGAQQBgjc8AgEDEwJVUzEZMBcGCysGAQQBgjc8AgEC
+DAhEZWxhd2FyZTELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMx
+DzANBgNVBAcMBk5ld3RvbjEdMBsGA1UEDxMUUHJpdmF0ZSBPcmdhbml6YXRpb24x
+EDAOBgNVBAUTBzMxNzU1OTIxGDAWBgNVBAoMD1RyaXBBZHZpc29yIExMQzELMAkG
+A1UECwwCSVQxHDAaBgNVBAMME3d3dy50cmlwYWR2aXNvci5jb20wggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVujnKkJ+DbO7mrUSBAd5uLG+eQTNBr1ct
+DX34kqehe2Azd/0ctsplKg8yUaJG11CaenNP49lchN3lhxtZ0ekoJJ7CnngVd2F+
+sWzCKQ8dflXnS10n+JFzZURrMHEE3TpZuiENdE4skjop5MgS3NepsvQfZYa8wX7F
+sMLvptSxyHWkfAxDX3nuu/QEpIhXDvEs3y3gbTddeIr8nCDnRo6243s1gL92ntDs
+Red9cS7iVnfE/VA3aaacRJWqB+YRxboSkw9JtESsi6K+49Qro5KYEOhRiws79sWm
+ZpwWBW9lVmqp+pMMhxGcIqGcX7x/n0vcWyg777MegxsYuQLzyBh9AgMBAAGjggMJ
+MIIDBTAvBgNVHREEKDAmghN3d3cudHJpcGFkdmlzb3IuY29tgg90cmlwYWR2aXNv
+ci5jb20wCQYDVR0TBAIwADAOBgNVHQ8BAf8EBAMCBaAwKwYDVR0fBCQwIjAgoB6g
+HIYaaHR0cDovL3NyLnN5bWNiLmNvbS9zci5jcmwwbwYDVR0gBGgwZjBbBgtghkgB
+hvhFAQcXBjBMMCMGCCsGAQUFBwIBFhdodHRwczovL2Quc3ltY2IuY29tL2NwczAl
+BggrBgEFBQcCAjAZDBdodHRwczovL2Quc3ltY2IuY29tL3JwYTAHBgVngQwBATAd
+BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHwYDVR0jBBgwFoAUAVmr5906
+C1mmZGPWzyAHV9WR52owVwYIKwYBBQUHAQEESzBJMB8GCCsGAQUFBzABhhNodHRw
+Oi8vc3Iuc3ltY2QuY29tMCYGCCsGAQUFBzAChhpodHRwOi8vc3Iuc3ltY2IuY29t
+L3NyLmNydDCCAX4GCisGAQQB1nkCBAIEggFuBIIBagFoAHYA3esdK3oNT6Ygi4Gt
+gWhwfi6OnQHVXIiNPRHEzbbsvswAAAFS76NSuAAABAMARzBFAiAIRDijyhwOsiFv
+PS1wYIk9hd6hqTgZeDg6W4pY044hbgIhAKwThjx7aZVz14AvBY1RKueOiYF5/XDU
+7jc4Ttfo3nmbAHYApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFS
+76NSywAABAMARzBFAiEAjTsNYnW0GibB5U/VG2IVRjZylA+EQuzG+loy58cQ1uEC
+IDRgavDA+iTurPVbhe7Wb91GbduE1tx1mrYWgCQN1vgjAHYAaPaY+B9kgr46jO65
+KB1M/HFRXWeT1ETRCmesu09P+8QAAAFS76NS2wAABAMARzBFAiEA/ka3XvhhaCev
+2s+nPMAX/fkyaLLDTazwx2SnPQpE7nUCIHQ8HMdbtki3GlGUOmvA7ktGQzDqE3Hn
+jPQpwGqog9IkMA0GCSqGSIb3DQEBCwUAA4IBAQAVoid/HObXAnTJq3fdv3XzOids
+9Ur2Q9Xg28cdElek3ajG8GauLd+9tEPN+uIJav3QVbal2O9DNHEcJfirGwlj11Pn
+l3Ct5GBykjUYPUSyoRR7r1IU4u3kqnIFme4L42UVWJM2gXpuQbHfXlJH9lksLzL/
+c3QLzVQWJlVo87j0ABiOqM8l9jRGm9k5UP8KomWhtLgEZ+tHNpDgv9NxEoQE0EP+
+N+PAy38bK4M25kCnpEyQfoqywCLStwlTlJtRgMwXNwbY44vurErcTCfuASgQedxH
+FrZykIulRjN04vrYtl8gWzwclEhAcMgsE+PqmIS1kugl0YSkF98UWx6OhfQ6
+-----END CERTIFICATE-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 7e:e1:4a:6f:6f:ef:f2:d3:7f:3f:ad:65:4d:3a:da:b4
+ 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: Oct 31 00:00:00 2013 GMT
+ Not After : Oct 30 23:59:59 2023 GMT
+ Subject: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 EV SSL CA - G3
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:d8:a1:65:74:23:e8:2b:64:e2:32:d7:33:37:3d:
+ 8e:f5:34:16:48:dd:4f:7f:87:1c:f8:44:23:13:8e:
+ fb:11:d8:44:5a:18:71:8e:60:16:26:92:9b:fd:17:
+ 0b:e1:71:70:42:fe:bf:fa:1c:c0:aa:a3:a7:b5:71:
+ e8:ff:18:83:f6:df:10:0a:13:62:c8:3d:9c:a7:de:
+ 2e:3f:0c:d9:1d:e7:2e:fb:2a:ce:c8:9a:7f:87:bf:
+ d8:4c:04:15:32:c9:d1:cc:95:71:a0:4e:28:4f:84:
+ d9:35:fb:e3:86:6f:94:53:e6:72:8a:63:67:2e:be:
+ 69:f6:f7:6e:8e:9c:60:04:eb:29:fa:c4:47:42:d2:
+ 78:98:e3:ec:0b:a5:92:dc:b7:9a:bd:80:64:2b:38:
+ 7c:38:09:5b:66:f6:2d:95:7a:86:b2:34:2e:85:9e:
+ 90:0e:5f:b7:5d:a4:51:72:46:70:13:bf:67:f2:b6:
+ a7:4d:14:1e:6c:b9:53:ee:23:1a:4e:8d:48:55:43:
+ 41:b1:89:75:6a:40:28:c5:7d:dd:d2:6e:d2:02:19:
+ 2f:7b:24:94:4b:eb:f1:1a:a9:9b:e3:23:9a:ea:fa:
+ 33:ab:0a:2c:b7:f4:60:08:dd:9f:1c:cd:dd:2d:01:
+ 66:80:af:b3:2f:29:1d:23:b8:8a:e1:a1:70:07:0c:
+ 34:0f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ Authority Information Access:
+ OCSP - URI:http://s2.symcb.com
+
+ X509v3 Basic Constraints: critical
+ CA:TRUE, pathlen:0
+ X509v3 Certificate Policies:
+ Policy: X509v3 Any Policy
+ CPS: http://www.symauth.com/cps
+ User Notice:
+ Explicit Text: http://www.symauth.com/rpa
+
+ X509v3 CRL Distribution Points:
+ URI:http://s1.symcb.com/pca3-g5.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Subject Alternative Name:
+ DirName:/CN=SymantecPKI-1-533
+ X509v3 Subject Key Identifier:
+ 01:59:AB:E7:DD:3A:0B:59:A6:64:63:D6:CF:20:07:57:D5:91:E7:6A
+ 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
+ 42:01:55:7b:d0:16:1a:5d:58:e8:bb:9b:a8:4d:d7:f3:d7:eb:
+ 13:94:86:d6:7f:21:0b:47:bc:57:9b:92:5d:4f:05:9f:38:a4:
+ 10:7c:cf:83:be:06:43:46:8d:08:bc:6a:d7:10:a6:fa:ab:af:
+ 2f:61:a8:63:f2:65:df:7f:4c:88:12:88:4f:b3:69:d9:ff:27:
+ c0:0a:97:91:8f:56:fb:89:c4:a8:bb:92:2d:1b:73:b0:c6:ab:
+ 36:f4:96:6c:20:08:ef:0a:1e:66:24:45:4f:67:00:40:c8:07:
+ 54:74:33:3b:a6:ad:bb:23:9f:66:ed:a2:44:70:34:fb:0e:ea:
+ 01:fd:cf:78:74:df:a7:ad:55:b7:5f:4d:f6:d6:3f:e0:86:ce:
+ 24:c7:42:a9:13:14:44:35:4b:b6:df:c9:60:ac:0c:7f:d9:93:
+ 21:4b:ee:9c:e4:49:02:98:d3:60:7b:5c:bc:d5:30:2f:07:ce:
+ 44:42:c4:0b:99:fe:e6:9f:fc:b0:78:86:51:6d:d1:2c:9d:c6:
+ 96:fb:85:82:bb:04:2f:f7:62:80:ef:62:da:7f:f6:0e:ac:90:
+ b8:56:bd:79:3f:f2:80:6e:a3:d9:b9:0f:5d:3a:07:1d:91:93:
+ 86:4b:29:4c:e1:dc:b5:e1:e0:33:9d:b3:cb:36:91:4b:fe:a1:
+ b4:ee:f0:f9
+-----BEGIN CERTIFICATE-----
+MIIFKzCCBBOgAwIBAgIQfuFKb2/v8tN/P61lTTratDANBgkqhkiG9w0BAQsFADCB
+yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
+ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
+U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
+ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5IC0gRzUwHhcNMTMxMDMxMDAwMDAwWhcNMjMxMDMwMjM1OTU5WjB3MQsw
+CQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNV
+BAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMTH1N5bWFudGVjIENs
+YXNzIDMgRVYgU1NMIENBIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDYoWV0I+grZOIy1zM3PY71NBZI3U9/hxz4RCMTjvsR2ERaGHGOYBYmkpv9
+FwvhcXBC/r/6HMCqo6e1cej/GIP23xAKE2LIPZyn3i4/DNkd5y77Ks7Imn+Hv9hM
+BBUyydHMlXGgTihPhNk1++OGb5RT5nKKY2cuvmn2926OnGAE6yn6xEdC0niY4+wL
+pZLct5q9gGQrOHw4CVtm9i2VeoayNC6FnpAOX7ddpFFyRnATv2fytqdNFB5suVPu
+IxpOjUhVQ0GxiXVqQCjFfd3SbtICGS97JJRL6/EaqZvjI5rq+jOrCiy39GAI3Z8c
+zd0tAWaAr7MvKR0juIrhoXAHDDQPAgMBAAGjggFdMIIBWTAvBggrBgEFBQcBAQQj
+MCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9zMi5zeW1jYi5jb20wEgYDVR0TAQH/BAgw
+BgEB/wIBADBlBgNVHSAEXjBcMFoGBFUdIAAwUjAmBggrBgEFBQcCARYaaHR0cDov
+L3d3dy5zeW1hdXRoLmNvbS9jcHMwKAYIKwYBBQUHAgIwHBoaaHR0cDovL3d3dy5z
+eW1hdXRoLmNvbS9ycGEwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3MxLnN5bWNi
+LmNvbS9wY2EzLWc1LmNybDAOBgNVHQ8BAf8EBAMCAQYwKQYDVR0RBCIwIKQeMBwx
+GjAYBgNVBAMTEVN5bWFudGVjUEtJLTEtNTMzMB0GA1UdDgQWBBQBWavn3ToLWaZk
+Y9bPIAdX1ZHnajAfBgNVHSMEGDAWgBR/02Wnwt3su/AwCfNDOfoCrzMxMzANBgkq
+hkiG9w0BAQsFAAOCAQEAQgFVe9AWGl1Y6LubqE3X89frE5SG1n8hC0e8V5uSXU8F
+nzikEHzPg74GQ0aNCLxq1xCm+quvL2GoY/Jl339MiBKIT7Np2f8nwAqXkY9W+4nE
+qLuSLRtzsMarNvSWbCAI7woeZiRFT2cAQMgHVHQzO6atuyOfZu2iRHA0+w7qAf3P
+eHTfp61Vt19N9tY/4IbOJMdCqRMURDVLtt/JYKwMf9mTIUvunORJApjTYHtcvNUw
+LwfORELEC5n+5p/8sHiGUW3RLJ3GlvuFgrsEL/digO9i2n/2DqyQuFa9eT/ygG6j
+2bkPXToHHZGThkspTOHcteHgM52zyzaRS/6htO7w+Q==
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/ssl/certificates/verisign_class3_g5_crosssigned-trusted.keychain b/chromium/net/data/ssl/certificates/verisign_class3_g5_crosssigned-trusted.keychain
new file mode 100644
index 00000000000..3b196e6ad05
--- /dev/null
+++ b/chromium/net/data/ssl/certificates/verisign_class3_g5_crosssigned-trusted.keychain
Binary files differ
diff --git a/chromium/net/data/ssl/certificates/verisign_class3_g5_crosssigned.pem b/chromium/net/data/ssl/certificates/verisign_class3_g5_crosssigned.pem
new file mode 100644
index 00000000000..386d6ca00a2
--- /dev/null
+++ b/chromium/net/data/ssl/certificates/verisign_class3_g5_crosssigned.pem
@@ -0,0 +1,92 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 25:0c:e8:e0:30:61:2e:9f:2b:89:f7:05:4d:7c:f8:fd
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority
+ Validity
+ Not Before: Nov 8 00:00:00 2006 GMT
+ Not After : Nov 7 23:59:59 2021 GMT
+ Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:af:24:08:08:29:7a:35:9e:60:0c:aa:e7:4b:3b:
+ 4e:dc:7c:bc:3c:45:1c:bb:2b:e0:fe:29:02:f9:57:
+ 08:a3:64:85:15:27:f5:f1:ad:c8:31:89:5d:22:e8:
+ 2a:aa:a6:42:b3:8f:f8:b9:55:b7:b1:b7:4b:b3:fe:
+ 8f:7e:07:57:ec:ef:43:db:66:62:15:61:cf:60:0d:
+ a4:d8:de:f8:e0:c3:62:08:3d:54:13:eb:49:ca:59:
+ 54:85:26:e5:2b:8f:1b:9f:eb:f5:a1:91:c2:33:49:
+ d8:43:63:6a:52:4b:d2:8f:e8:70:51:4d:d1:89:69:
+ 7b:c7:70:f6:b3:dc:12:74:db:7b:5d:4b:56:d3:96:
+ bf:15:77:a1:b0:f4:a2:25:f2:af:1c:92:67:18:e5:
+ f4:06:04:ef:90:b9:e4:00:e4:dd:3a:b5:19:ff:02:
+ ba:f4:3c:ee:e0:8b:eb:37:8b:ec:f4:d7:ac:f2:f6:
+ f0:3d:af:dd:75:91:33:19:1d:1c:40:cb:74:24:19:
+ 21:93:d9:14:fe:ac:2a:52:c7:8f:d5:04:49:e4:8d:
+ 63:47:88:3c:69:83:cb:fe:47:bd:2b:7e:4f:c5:95:
+ ae:0e:9d:d4:d1:43:c0:67:73:e3:14:08:7e:e5:3f:
+ 9f:73:b8:33:0a:cf:5d:3f:34:87:96:8a:ee:53:e8:
+ 25:15
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 CRL Distribution Points:
+ URI:http://crl.verisign.com/pca3.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Certificate Policies:
+ Policy: X509v3 Any Policy
+ CPS: https://www.verisign.com/cps
+
+ X509v3 Subject Key Identifier:
+ 7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33
+ 1.3.6.1.5.5.7.1.12:
+ 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif
+ Authority Information Access:
+ OCSP - URI:http://ocsp.verisign.com
+
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication, Code Signing, Netscape Server Gated Crypto, 2.16.840.1.113733.1.8.1
+ Signature Algorithm: sha1WithRSAEncryption
+ 13:02:dd:f8:e8:86:00:f2:5a:f8:f8:20:0c:59:88:62:07:ce:
+ ce:f7:4e:f9:bb:59:a1:98:e5:e1:38:dd:4e:bc:66:18:d3:ad:
+ eb:18:f2:0d:c9:6d:3e:4a:94:20:c3:3c:ba:bd:65:54:c6:af:
+ 44:b3:10:ad:2c:6b:3e:ab:d7:07:b6:b8:81:63:c5:f9:5e:2e:
+ e5:2a:67:ce:cd:33:0c:2a:d7:89:56:03:23:1f:b3:be:e8:3a:
+ 08:59:b4:ec:45:35:f7:8a:5b:ff:66:cf:50:af:c6:6d:57:8d:
+ 19:78:b7:b9:a2:d1:57:ea:1f:9a:4b:af:ba:c9:8e:12:7e:c6:
+ bd:ff
+-----BEGIN CERTIFICATE-----
+MIIE0DCCBDmgAwIBAgIQJQzo4DBhLp8rifcFTXz4/TANBgkqhkiG9w0BAQUFADBf
+MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT
+LkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
+HhcNMDYxMTA4MDAwMDAwWhcNMjExMTA3MjM1OTU5WjCByjELMAkGA1UEBhMCVVMx
+FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
+dCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZv
+ciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAz
+IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8
+RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbext0uz/o9+B1fs70Pb
+ZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhDY2pSS9KP6HBR
+TdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/
+Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNH
+iDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMB
+AAGjggGbMIIBlzAPBgNVHRMBAf8EBTADAQH/MDEGA1UdHwQqMCgwJqAkoCKGIGh0
+dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTMuY3JsMA4GA1UdDwEB/wQEAwIBBjA9
+BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVy
+aXNpZ24uY29tL2NwczAdBgNVHQ4EFgQUf9Nlp8Ld7LvwMAnzQzn6Aq8zMTMwbQYI
+KwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQU
+j+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24uY29t
+L3ZzbG9nby5naWYwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v
+b2NzcC52ZXJpc2lnbi5jb20wPgYDVR0lBDcwNQYIKwYBBQUHAwEGCCsGAQUFBwMC
+BggrBgEFBQcDAwYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEBBQUA
+A4GBABMC3fjohgDyWvj4IAxZiGIHzs73Tvm7WaGY5eE43U68ZhjTresY8g3JbT5K
+lCDDPLq9ZVTGr0SzEK0saz6r1we2uIFjxfleLuUqZ87NMwwq14lWAyMfs77oOghZ
+tOxFNfeKW/9mz1Cvxm1XjRl4t7mi0VfqH5pLr7rJjhJ+xr3/
+-----END CERTIFICATE-----
diff --git a/chromium/net/data/ssl/scripts/crlsetutil.py b/chromium/net/data/ssl/scripts/crlsetutil.py
index 49a1a860cdf..2fcad54c5a9 100755
--- a/chromium/net/data/ssl/scripts/crlsetutil.py
+++ b/chromium/net/data/ssl/scripts/crlsetutil.py
@@ -138,6 +138,18 @@ def _der_cert_to_spki(der_bytes):
return iterator.contents()
+def der_cert_to_spki_hash(der_cert):
+ """Gets the SHA-256 hash of the subjectPublicKeyInfo of a DER encoded cert
+
+ Args:
+ der_cert: A string containing the DER-encoded certificate
+
+ Returns:
+ The SHA-256 hash of the certificate, as a byte sequence
+ """
+ return hashlib.sha256(_der_cert_to_spki(der_cert)).digest()
+
+
def pem_cert_file_to_spki_hash(pem_filename):
"""Gets the SHA-256 hash of the subjectPublicKeyInfo of a cert in a file
@@ -147,8 +159,7 @@ def pem_cert_file_to_spki_hash(pem_filename):
Returns:
The SHA-256 hash of the first certificate in the file, as a byte sequence
"""
- return hashlib.sha256(
- _der_cert_to_spki(_pem_cert_to_binary(pem_filename))).digest()
+ return der_cert_to_spki_hash(_pem_cert_to_binary(pem_filename))
def main():
diff --git a/chromium/net/data/ssl/scripts/generate-android-test-keys.sh b/chromium/net/data/ssl/scripts/generate-android-test-keys.sh
deleted file mode 100755
index 1c297e3a86f..00000000000
--- a/chromium/net/data/ssl/scripts/generate-android-test-keys.sh
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/sh
-
-# Copyright (c) 2013 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 is used to generate the test keys for the unit test in
-# android/keystore_unittest.c.
-#
-# These are test RSA / DSA / ECDSA private keys in PKCS#8 format, as well
-# as the corresponding DSA / ECDSA public keys.
-#
-
-# Exit script as soon a something fails.
-set -e
-
-mkdir -p out
-rm -rf out/*
-
-# Generate a single 2048-bits RSA private key in PKCS#8 format.
-KEY=android-test-key-rsa
-openssl genrsa \
- -out out/$KEY.pem \
- 2048
-
-# Generate a 2048-bits DSA private key in PKCS#8 format,
-# as well as its public key in X.509 DER format.
-KEY=android-test-key-dsa
-openssl dsaparam \
- -out out/$KEY.param.pem \
- 2048
-
-openssl gendsa \
- -out out/$KEY.pem \
- out/$KEY.param.pem
-
-openssl dsa \
- -in out/$KEY.pem \
- -outform PEM \
- -out out/$KEY-public.pem \
- -pubout
-
-rm out/$KEY.param.pem
-
-# Generate an ECDSA private key, in PKCS#8 format,
-# as well as its public key in X.509 DER format.
-KEY=android-test-key-ecdsa
-openssl ecparam -genkey -name prime256v1 -out out/$KEY.pem
-
-openssl ec \
- -in out/$KEY.pem \
- -outform PEM \
- -out out/$KEY-public.pem \
- -pubout
-
-# We're done here.
diff --git a/chromium/net/data/ssl/scripts/generate-client-certificates.sh b/chromium/net/data/ssl/scripts/generate-client-certificates.sh
index 9fcc450c836..e7c8c0162a6 100755
--- a/chromium/net/data/ssl/scripts/generate-client-certificates.sh
+++ b/chromium/net/data/ssl/scripts/generate-client-certificates.sh
@@ -8,12 +8,14 @@
# authentication. Outputs for automated tests are stored in
# net/data/ssl/certificates, but may be re-generated for manual testing.
#
-# This script generates two chains of test client certificates:
+# This script generates several chains of test client certificates:
#
# 1. A (end-entity) -> B -> C (self-signed root)
# 2. D (end-entity) -> E -> C (self-signed root)
+# 3. F (end-entity) -> E -> C (self-signed root)
+# 4. G (end-entity, P-256) -> E -> C (self-signed root)
#
-# In which A, B, C, D, and E all have distinct keypairs. Both client
+# In which the certificates all have distinct keypairs. The client
# certificates share the same root, but are issued by different
# intermediates. The names of these intermediates are hardcoded within
# unit tests, and thus should not be changed.
@@ -42,6 +44,8 @@ do
try openssl genrsa -out out/$i.key 2048
done
+try openssl ecparam -name prime256v1 -genkey -noout -out out/G.key
+
echo Generate the C CSR
COMMON_NAME="C Root CA" \
CA_DIR=out \
@@ -104,7 +108,7 @@ COMMON_NAME="C CA" \
-config client-certs.cnf
echo Generate the leaf certs
-for id in A D F
+for id in A D F G
do
COMMON_NAME="Client Cert $id" \
ID=$id \
@@ -154,11 +158,23 @@ COMMON_NAME="E CA" \
-out out/F.pem \
-config client-certs.cnf
+echo E signs G
+COMMON_NAME="E CA" \
+ CA_DIR=out \
+ ID=E \
+ try openssl ca \
+ -batch \
+ -extensions user_cert \
+ -in out/G.csr \
+ -out out/G.pem \
+ -config client-certs.cnf
+
echo Package the client certs and private keys into PKCS12 files
# This is done for easily importing all of the certs needed for clients.
try /bin/sh -c "cat out/A.pem out/A.key out/B.pem out/C.pem > out/A-chain.pem"
try /bin/sh -c "cat out/D.pem out/D.key out/E.pem out/C.pem > out/D-chain.pem"
try /bin/sh -c "cat out/F.pem out/F.key out/E.pem out/C.pem > out/F-chain.pem"
+try /bin/sh -c "cat out/G.pem out/G.key out/E.pem out/C.pem > out/G-chain.pem"
try openssl pkcs12 \
-in out/A-chain.pem \
@@ -178,6 +194,12 @@ try openssl pkcs12 \
-export \
-passout pass:chrome
+try openssl pkcs12 \
+ -in out/G-chain.pem \
+ -out client_4.p12 \
+ -export \
+ -passout pass:chrome
+
echo Package the client certs for unit tests
try cp out/A.pem ../certificates/client_1.pem
try cp out/A.key ../certificates/client_1.key
@@ -193,3 +215,10 @@ try cp out/F.pem ../certificates/client_3.pem
try cp out/F.key ../certificates/client_3.key
try cp out/F.pk8 ../certificates/client_3.pk8
try cp out/E.pem ../certificates/client_3_ca.pem
+
+try cp out/G.pem ../certificates/client_4.pem
+try cp out/G.key ../certificates/client_4.key
+try cp out/G.pk8 ../certificates/client_4.pk8
+try cp out/E.pem ../certificates/client_4_ca.pem
+
+try cp out/C.pem ../certificates/client_root_ca.pem
diff --git a/chromium/net/data/ssl/scripts/generate-keychain.sh b/chromium/net/data/ssl/scripts/generate-keychain.sh
new file mode 100755
index 00000000000..4256cd9c81d
--- /dev/null
+++ b/chromium/net/data/ssl/scripts/generate-keychain.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+set -e -x
+
+SECURITY=/usr/bin/security
+
+KEYCHAIN="$1"
+shift
+# security create-keychain will interpret a non-absolute path relative to the
+# keychain directory rather than the current directory, and OSX doesn't have a
+# realpath command. Be lazy and make the user pass in an absolute path.
+if [ `echo "$KEYCHAIN" | cut -c1` != '/' ]; then
+ echo keychain path must be absolute
+ exit 1
+fi
+
+PASSWORD=aoeu
+
+
+# create-keychain modifes the global keychain search list, save it first.
+# (or does it?)
+SAVED_KEYCHAIN_LIST=`$SECURITY list -d user`
+echo "Saved user keychain list:"
+echo "$SAVED_KEYCHAIN_LIST"
+echo
+
+
+$SECURITY create-keychain -p "$PASSWORD" "$KEYCHAIN"
+
+trusted=0
+
+for cert in "$@"; do
+ if [ "$cert" = "--trusted" ]; then
+ trusted=1
+ continue
+ fi
+ if [ "$cert" = "--untrusted" ]; then
+ trusted=0
+ continue
+ fi
+
+ # security tool only accepts DER. If input is a PEM, convert it.
+ if grep -- "-----BEGIN CERTIFICATE-----" "$cert" ; then
+ tmpcert="${cert}.der.tmp"
+ openssl x509 -inform PEM -in "$cert" -outform DER -out "$tmpcert"
+ cert="$tmpcert"
+ fi
+
+ if [ $trusted = 1 ]; then
+ $SECURITY add-trusted-cert -r trustAsRoot -k "$KEYCHAIN" "$cert"
+ else
+ $SECURITY add-certificates -k "$KEYCHAIN" "$cert"
+ fi
+done
+
+
+
+#TODO: Would be good to restore the keychain search list on failure too.
+
+echo "pre-restore user keychain list:"
+$SECURITY list -d user
+
+# restore the original keychain search list
+/bin/echo -n "${SAVED_KEYCHAIN_LIST}" | xargs $SECURITY list -d user -s
+
+echo "Restored user keychain list:"
+$SECURITY list -d user
+echo
diff --git a/chromium/net/data/ssl/scripts/generate-multi-root-BFE-keychain.sh b/chromium/net/data/ssl/scripts/generate-multi-root-BFE-keychain.sh
new file mode 100755
index 00000000000..f98f4b01cc5
--- /dev/null
+++ b/chromium/net/data/ssl/scripts/generate-multi-root-BFE-keychain.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+rm -rf out
+mkdir out
+
+echo "Generating keychain"
+./generate-keychain.sh $PWD/out/multi-root-BFE.keychain --untrusted \
+ "../certificates/multi-root-B-by-F.pem" \
+ "../certificates/multi-root-F-by-E.pem"
+
+echo "Copying outputs"
+cp out/multi-root-BFE.keychain ../certificates
diff --git a/chromium/net/data/ssl/scripts/generate-verisign_class3_g5_crosssigned-trusted-keychain.sh b/chromium/net/data/ssl/scripts/generate-verisign_class3_g5_crosssigned-trusted-keychain.sh
new file mode 100755
index 00000000000..7ce602f5e15
--- /dev/null
+++ b/chromium/net/data/ssl/scripts/generate-verisign_class3_g5_crosssigned-trusted-keychain.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+rm -rf out
+mkdir out
+
+echo "Generating keychain"
+./generate-keychain.sh \
+ $PWD/out/verisign_class3_g5_crosssigned-trusted.keychain --trusted \
+ "../certificates/verisign_class3_g5_crosssigned.pem"
+
+echo "Copying outputs"
+cp out/verisign_class3_g5_crosssigned-trusted.keychain ../certificates
+
diff --git a/chromium/net/data/ssl/symantec/README.md b/chromium/net/data/ssl/symantec/README.md
index ac6acb04ffa..141415f4878 100644
--- a/chromium/net/data/ssl/symantec/README.md
+++ b/chromium/net/data/ssl/symantec/README.md
@@ -48,10 +48,3 @@ Note: Not issuing new certificates and can be removed after October 2016.
* [c3f697a92a293d86f9a3ee7ccb970e20e0050b8728cc83ed1b996ce9005d4c36.pem](excluded/c3f697a92a293d86f9a3ee7ccb970e20e0050b8728cc83ed1b996ce9005d4c36.pem)
-### Unicredit
-
-Audit information still undergoing review.
-[Certification Practices Statement](http://ca.unicredit.eu/CPS/cps.html)
-
- * [8c31013d19f8eea618c95fda6d21f5777c6e930c7413031559ee863d78dfe809.pem](excluded/8c31013d19f8eea618c95fda6d21f5777c6e930c7413031559ee863d78dfe809.pem)
-
diff --git a/chromium/net/data/ssl/symantec/excluded/8c31013d19f8eea618c95fda6d21f5777c6e930c7413031559ee863d78dfe809.pem b/chromium/net/data/ssl/symantec/excluded/8c31013d19f8eea618c95fda6d21f5777c6e930c7413031559ee863d78dfe809.pem
deleted file mode 100644
index a0252dfdf72..00000000000
--- a/chromium/net/data/ssl/symantec/excluded/8c31013d19f8eea618c95fda6d21f5777c6e930c7413031559ee863d78dfe809.pem
+++ /dev/null
@@ -1,96 +0,0 @@
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 146059 (0x23a8b)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA
- Validity
- Not Before: Dec 18 12:55:22 2015 GMT
- Not After : Dec 17 12:55:22 2018 GMT
- Subject: C=IT, O=UniCredit S.p.A., CN=UniCredit Subordinate External
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:ba:b0:4f:c9:1a:42:7a:50:31:17:7a:88:0a:76:
- 39:2c:e2:33:d1:0f:f7:14:ff:2a:9d:57:4d:39:c1:
- 55:f2:1e:17:c8:36:dd:e6:16:1d:e6:1f:82:58:21:
- 9b:da:1f:9e:35:f0:77:dc:fb:17:9e:52:c2:ff:cf:
- 28:77:1e:4c:06:d0:7d:0d:cb:53:e6:48:2c:f5:cf:
- 16:1e:69:66:33:3e:9d:a9:ef:2d:e0:e0:93:f8:5e:
- 70:7e:c8:36:39:0e:71:46:21:90:43:47:f0:e5:eb:
- da:b4:a0:e5:f2:91:72:f9:2c:9f:a4:26:34:ea:83:
- 0c:7c:e5:28:c9:f3:1f:c6:f1:c4:1c:b1:55:cc:83:
- 4e:90:e6:3e:c5:5d:12:cb:cf:2e:56:b8:fe:19:44:
- 73:15:77:be:de:cf:78:28:6a:04:21:96:58:96:f3:
- 9c:c0:5a:b1:75:c2:c2:a2:18:7a:f4:f3:15:2f:ac:
- e4:aa:3f:d2:dc:c1:cc:a8:3e:cc:b9:c8:70:8c:3c:
- c1:91:bd:94:a0:4d:85:d8:e8:b0:5a:f9:90:6d:6b:
- 2a:1e:b6:88:ff:40:12:cd:3b:1d:2f:46:d2:b2:f5:
- 0c:d1:74:c1:8f:04:25:49:fe:ca:58:03:f8:3f:cb:
- 99:86:d0:6d:42:e1:3b:03:64:7b:8d:4c:d4:9a:9c:
- 74:1b
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Authority Key Identifier:
- keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E
-
- X509v3 Subject Key Identifier:
- F0:56:4F:75:77:1E:74:76:35:D3:40:14:A0:12:E6:0D:5D:F5:3E:27
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- Authority Information Access:
- OCSP - URI:http://g.symcd.com
-
- X509v3 Basic Constraints: critical
- CA:TRUE, pathlen:0
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://g.symcb.com/crls/gtglobal.crl
-
- X509v3 Certificate Policies:
- Policy: 1.3.6.1.4.1.37016.1.1.1.1
- CPS: http://ca.unicredit.eu/CPS/cps.html
-
- Signature Algorithm: sha256WithRSAEncryption
- ab:0f:08:df:e0:61:2a:f7:af:5a:08:8f:fd:d9:d3:2d:63:1d:
- 6b:31:d8:09:de:aa:6a:91:90:85:73:0e:bf:4b:7d:ad:c3:ea:
- 90:87:44:39:06:71:3c:bf:37:85:dd:24:38:59:7f:4b:18:11:
- 0d:79:16:69:3d:3b:89:81:60:3a:94:43:db:9d:b1:fb:af:0a:
- 79:10:c5:0a:7d:f2:c0:eb:a2:22:6e:01:3f:f2:23:d9:38:e7:
- 09:ed:06:c4:f5:cb:83:c9:be:45:c6:05:cf:b9:3c:11:37:30:
- bb:95:38:87:65:cf:dc:50:30:a3:20:39:a6:6f:30:2d:0a:a8:
- 49:c5:cb:4f:4b:59:e1:b7:e2:bc:b5:47:83:7d:ba:18:f5:04:
- d2:89:74:03:3b:9f:b3:ef:ea:e3:84:e3:56:c4:0a:5e:b0:19:
- f5:cf:1e:a5:41:4f:16:06:aa:d1:d7:31:22:69:9b:87:bd:e5:
- 87:f1:24:07:a4:2c:69:d1:ef:c5:2f:a5:49:f1:ea:32:43:4f:
- 58:ee:a4:bb:de:a5:08:60:ec:02:3a:ea:65:e7:0c:3f:e4:5f:
- 97:33:bc:4a:db:95:6a:38:f2:2e:23:18:04:23:f7:72:05:c4:
- 50:7e:06:4f:e6:ea:ef:23:4b:f3:6b:66:a0:d4:2a:e3:e6:00:
- 8d:e7:0e:b1
------BEGIN CERTIFICATE-----
-MIIELzCCAxegAwIBAgIDAjqLMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT
-MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
-YWwgQ0EwHhcNMTUxMjE4MTI1NTIyWhcNMTgxMjE3MTI1NTIyWjBRMQswCQYDVQQG
-EwJJVDEZMBcGA1UEChMQVW5pQ3JlZGl0IFMucC5BLjEnMCUGA1UEAxMeVW5pQ3Jl
-ZGl0IFN1Ym9yZGluYXRlIEV4dGVybmFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEAurBPyRpCelAxF3qICnY5LOIz0Q/3FP8qnVdNOcFV8h4XyDbd5hYd
-5h+CWCGb2h+eNfB33PsXnlLC/88odx5MBtB9DctT5kgs9c8WHmlmMz6dqe8t4OCT
-+F5wfsg2OQ5xRiGQQ0fw5evatKDl8pFy+SyfpCY06oMMfOUoyfMfxvHEHLFVzINO
-kOY+xV0Sy88uVrj+GURzFXe+3s94KGoEIZZYlvOcwFqxdcLCohh69PMVL6zkqj/S
-3MHMqD7MuchwjDzBkb2UoE2F2OiwWvmQbWsqHraI/0ASzTsdL0bSsvUM0XTBjwQl
-Sf7KWAP4P8uZhtBtQuE7A2R7jUzUmpx0GwIDAQABo4IBHTCCARkwHwYDVR0jBBgw
-FoAUwHqYaI2J+6sFZAwRfap9ZbjKzE4wHQYDVR0OBBYEFPBWT3V3HnR2NdNAFKAS
-5g1d9T4nMA4GA1UdDwEB/wQEAwIBBjAuBggrBgEFBQcBAQQiMCAwHgYIKwYBBQUH
-MAGGEmh0dHA6Ly9nLnN5bWNkLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEAMDUGA1Ud
-HwQuMCwwKqAooCaGJGh0dHA6Ly9nLnN5bWNiLmNvbS9jcmxzL2d0Z2xvYmFsLmNy
-bDBMBgNVHSAERTBDMEEGDCsGAQQBgqEYAQEBATAxMC8GCCsGAQUFBwIBFiNodHRw
-Oi8vY2EudW5pY3JlZGl0LmV1L0NQUy9jcHMuaHRtbDANBgkqhkiG9w0BAQsFAAOC
-AQEAqw8I3+BhKvevWgiP/dnTLWMdazHYCd6qapGQhXMOv0t9rcPqkIdEOQZxPL83
-hd0kOFl/SxgRDXkWaT07iYFgOpRD252x+68KeRDFCn3ywOuiIm4BP/Ij2TjnCe0G
-xPXLg8m+RcYFz7k8ETcwu5U4h2XP3FAwoyA5pm8wLQqoScXLT0tZ4bfivLVHg326
-GPUE0ol0Azufs+/q44TjVsQKXrAZ9c8epUFPFgaq0dcxImmbh73lh/EkB6QsadHv
-xS+lSfHqMkNPWO6ku96lCGDsAjrqZecMP+RflzO8StuVajjyLiMYBCP3cgXEUH4G
-T+bq7yNL82tmoNQq4+YAjecOsQ==
------END CERTIFICATE-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/README b/chromium/net/data/verify_certificate_chain_unittest/README
index 11cc4cbef53..a529a508eff 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/README
+++ b/chromium/net/data/verify_certificate_chain_unittest/README
@@ -20,10 +20,51 @@ Runs all of the generate-*.py scripts and does some cleanup.
*.pem
===============================
-These files descibe a test case for certificate chain verification.
+Each .pem file describes the inputs for certificate chain verification, and the
+expected result. These are the PEM blocks that each file contains and their
+interpretation:
-The input file is a PEM file with blocks for:
- * The trust store
- * The certificate chain (target certificate and all intermediaries)
- * The timestamp to use when verifying
- * The expected result of verification (success or fail)
+CERTIFICATE:
+
+These PEM blocks describe the ordered chain of certificates starting from the
+target certificate and progressing towards the trust anchor (but not including
+the trust anchor).
+
+ - There must be one or more such PEM blocks
+ - Its contents are a DER-encoded X.509 certificate
+ - The first block is the target certificate
+ - The (i+1)th CERTIFICATE is (allegedly) the one which issued the ith
+ CERTIFICATE.
+
+TRUST_ANCHOR_{XXX}:
+
+This PEM block describes the trust anchor to use when verifying the chain.
+There are two possible names for this PEM block, which affect how it is
+interpreted: TRUST_ANCHOR_CONSTRAINED or TRUST_ANCHOR_UNCONSTRAINED.
+
+ - There must be exactly one TRUST_ANCHOR_{XXX} block.
+ - Its contents are a DER-encoded X.509 certificate
+ - The subject and SPKI from the certificate define the trust anchor
+ - If the block was named TRUST_ANCHOR_CONSTRAINED, then any constraints on the
+ certificate are also considered normative when verifying paths. Otherwise
+ any standard extensions provided by the root certificate are not used during
+ path validation.
+
+TIMESTAMP:
+
+This PEM block describes the time to use when verifying the chain.
+
+ - There must be exactly one such PEM block
+ - Its contents are a DER-encoded UTCTime.
+
+VERIFY_RESULT:
+
+This PEM block describes the expected result from verifying the path.
+
+ - There must be exactly one such PEM block
+ - Its contents are a string with value of either "SUCCESS" or "FAIL"
+
+ERRORS:
+
+This PEM block is a pretty-printed textual dump of all the errors, as given by
+CertErrors::ToDebugString().
diff --git a/chromium/net/data/verify_certificate_chain_unittest/basic-constraints-pathlen-0-self-issued.pem b/chromium/net/data/verify_certificate_chain_unittest/basic-constraints-pathlen-0-self-issued.pem
index 5ed112630f0..01d64cf6fcc 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/basic-constraints-pathlen-0-self-issued.pem
+++ b/chromium/net/data/verify_certificate_chain_unittest/basic-constraints-pathlen-0-self-issued.pem
@@ -1,15 +1,15 @@
[Created by: generate-basic-constraints-pathlen-0-self-issued.py]
-Certificate chain with 2 intermediaries. The first intermediary has a basic
+Certificate chain with 2 intermediates. The first intermediate has a basic
constraints path length of 0. The second one is self-issued so does not count
against the path length.
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 1 (0x1)
+ Serial Number: 2 (0x2)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
+ Issuer: CN=Intermediate
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
@@ -18,80 +18,80 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:cc:d5:1f:2f:97:16:d6:23:ca:d5:a1:c1:97:42:
- 2b:7e:3e:7f:45:44:70:b9:8d:81:76:be:b4:69:56:
- 78:a9:14:10:69:ad:60:8e:ed:80:b2:a2:f9:85:d6:
- fe:4c:81:d0:30:8e:c8:75:48:29:48:b9:ad:9f:a9:
- 83:b6:4f:c7:ba:40:f9:d5:66:9f:f9:51:48:72:0d:
- 95:38:65:da:41:8a:91:4a:e1:34:d6:1c:a0:0b:ee:
- 4d:07:69:0c:74:87:58:79:1b:e5:7b:51:ae:19:36:
- b2:6a:a6:89:81:30:bd:51:c1:7f:99:86:63:78:48:
- a6:8e:74:f6:5f:cc:fb:3f:12:ac:2e:e7:a8:75:15:
- b7:5b:37:dd:ce:54:68:ae:0d:ad:80:13:b5:d7:06:
- 98:39:a9:67:f9:fb:c1:7f:e0:f6:6b:14:f3:d3:b4:
- f4:33:2c:41:9e:69:63:de:b3:f9:cd:4e:f8:58:98:
- dd:6f:9b:9a:b7:82:19:c1:01:c9:2d:fb:d3:5a:48:
- 5f:e4:e5:c5:6e:5f:b1:3b:31:49:65:f0:0d:46:a5:
- 33:fb:57:23:fc:ca:17:51:72:fc:5a:f7:7c:44:74:
- 24:3b:cc:54:2c:e3:d4:8b:e9:9c:13:da:78:58:a1:
- d8:00:19:30:ee:3d:29:fb:2b:7a:79:b8:69:f2:3b:
- d3:19
+ 00:ec:1a:fe:56:e3:0e:27:0c:51:3b:f8:18:3a:2f:
+ 18:97:f4:9a:3c:6b:8f:7c:5e:7e:0e:07:ba:9d:f4:
+ 1e:2c:86:0f:85:8f:80:de:35:96:29:2a:64:56:0d:
+ e8:8d:2d:84:8d:78:3a:e2:ec:e7:c6:4f:ba:b8:35:
+ d4:6b:e0:02:8b:58:d5:61:90:fe:fa:13:fd:7c:63:
+ 6f:ce:4b:75:ea:cd:0d:ab:cd:75:bf:ef:c4:b0:3d:
+ 8a:64:9a:0d:e6:b3:80:09:a8:21:52:ff:dc:05:e8:
+ 4d:00:78:8d:94:43:2d:24:9b:81:a4:89:81:5f:d3:
+ 0f:e7:76:46:bf:cd:0f:24:30:0d:13:1b:49:f5:c3:
+ 90:f4:8a:d3:1a:47:75:9f:73:97:be:4b:5b:d0:7d:
+ 01:42:64:e3:16:a6:ef:86:91:78:19:a1:a8:c9:3f:
+ 41:a1:dc:ca:c0:7c:0d:a3:72:af:6b:c9:2f:1b:81:
+ ba:fa:7e:65:af:de:95:fa:5d:1f:30:22:98:79:db:
+ 4a:6a:e8:0f:99:58:e6:20:f4:68:d9:e0:21:cf:ad:
+ 3c:ad:9e:43:34:e7:26:62:e6:15:cb:95:78:6c:4b:
+ 3b:73:71:8d:b8:c0:dd:f8:52:4b:92:25:22:2e:39:
+ 04:73:24:47:09:46:07:5f:80:9a:c5:5d:69:5a:03:
+ 03:1b
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 6D:49:C7:0A:DE:44:7C:B7:07:ED:87:EF:41:DE:5D:12:91:28:3D:1C
+ 7B:92:03:28:A9:49:81:7F:C8:EC:36:25:A4:A8:31:A8:09:E0:AF:DD
X509v3 Authority Key Identifier:
- keyid:31:9F:A3:DB:EA:90:94:EB:3D:93:39:9F:BA:8A:05:7E:2C:94:23:9B
+ keyid:73:DB:AF:CB:C5:A7:D4:A3:D4:A4:0B:33:21:04:3C:37:CE:8F:BE:2D
Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
X509v3 CRL Distribution Points:
Full Name:
- URI:http://url-for-crl/Intermediary.crl
+ URI:http://url-for-crl/Intermediate.crl
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 34:51:df:38:e9:c2:df:c6:2c:01:00:7e:a1:4b:5e:d1:43:8a:
- d7:4e:ff:49:5d:17:e7:bd:e2:3c:cd:43:63:4d:a9:05:97:bf:
- 76:e2:8d:90:d2:dd:ea:6b:4c:e3:1e:c1:7b:8b:35:5a:24:cc:
- d8:b2:9a:12:07:d2:66:fa:fd:3c:79:b4:a7:d7:cb:69:af:07:
- f7:9d:66:34:ee:ed:22:1f:7d:58:9e:e1:49:90:88:95:1e:27:
- 2a:3d:dc:a9:b9:1d:2b:1f:88:b9:0c:89:a1:bc:dd:25:97:b9:
- 32:0e:02:86:fa:a3:2c:cd:8e:29:e5:68:12:3b:5b:bf:0e:cc:
- 25:ad:06:ef:77:26:d7:b4:84:cf:ba:00:55:c4:f0:95:39:88:
- ff:22:f8:a5:89:8a:d2:31:aa:e7:98:76:02:19:bd:04:bc:5c:
- 26:be:5e:eb:96:2b:f6:a2:cf:13:3e:a1:82:92:63:c0:13:bc:
- b6:f9:06:fb:77:c3:0f:cd:39:b1:af:43:b5:9d:fc:64:d4:bd:
- d0:81:5c:06:fb:8b:0e:c5:59:0b:07:d6:a7:8b:a9:8e:b3:6b:
- f5:ed:9b:ea:ea:f7:6f:ea:2b:02:df:62:92:ae:98:fb:45:ca:
- bc:1c:6b:eb:6d:33:e3:0e:32:0f:0d:e3:7f:5c:ef:e3:1b:c2:
- f6:fc:99:a4
+ 40:59:36:cb:ac:7f:e8:5f:ff:57:eb:09:f3:fc:c3:e9:2b:b2:
+ 90:6e:6b:e7:60:a9:6c:1d:02:f5:5f:cc:29:f6:ed:25:fd:63:
+ 7d:48:e2:f0:c8:ec:59:a1:8b:49:c3:a9:63:a1:12:70:7d:6f:
+ a3:04:bf:1a:83:6a:e1:21:5f:ee:6b:6f:9f:5d:4b:79:cb:4c:
+ 43:a4:92:ea:41:ea:e1:36:92:90:fd:01:0a:82:65:0e:3c:19:
+ 44:fd:b5:f3:eb:69:cd:c5:ec:9c:f6:bf:34:35:36:8d:73:c2:
+ 6f:ee:20:63:c7:c5:1b:ca:13:2a:fb:2c:dc:a0:24:49:7f:42:
+ f3:be:16:6d:62:5b:c9:88:20:bb:e4:99:11:e5:59:66:40:23:
+ bf:a2:cb:54:14:76:39:7a:7c:82:8f:dd:16:b9:4f:e4:d5:05:
+ ab:ea:eb:6b:55:64:ba:15:42:7b:4e:cf:25:68:12:8f:55:0e:
+ 47:93:bf:0b:01:b5:68:76:c3:1e:2e:1d:96:8e:f1:da:fd:13:
+ ed:29:cf:8e:30:2d:dc:9c:d6:1a:04:1b:7a:8c:c3:fd:a1:42:
+ 72:79:2e:47:c8:7f:28:b0:8e:ea:2a:b3:de:b0:0d:17:4a:e0:
+ 7b:ec:a4:93:89:aa:a4:ef:c4:6e:d2:4f:ea:6f:16:f6:4f:6f:
+ 41:d9:8e:55
-----BEGIN CERTIFICATE-----
-MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDM1R8v
-lxbWI8rVocGXQit+Pn9FRHC5jYF2vrRpVnipFBBprWCO7YCyovmF1v5MgdAwjsh1
-SClIua2fqYO2T8e6QPnVZp/5UUhyDZU4ZdpBipFK4TTWHKAL7k0HaQx0h1h5G+V7
-Ua4ZNrJqpomBML1RwX+ZhmN4SKaOdPZfzPs/Eqwu56h1FbdbN93OVGiuDa2AE7XX
-Bpg5qWf5+8F/4PZrFPPTtPQzLEGeaWPes/nNTvhYmN1vm5q3ghnBAckt+9NaSF/k
-5cVuX7E7MUll8A1GpTP7VyP8yhdRcvxa93xEdCQ7zFQs49SL6ZwT2nhYodgAGTDu
-PSn7K3p5uGnyO9MZAgMBAAGjgekwgeYwHQYDVR0OBBYEFG1JxwreRHy3B+2H70He
-XRKRKD0cMB8GA1UdIwQYMBaAFDGfo9vqkJTrPZM5n7qKBX4slCObMD8GCCsGAQUF
+MIIDjTCCAnWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDsGv5W
+4w4nDFE7+Bg6LxiX9Jo8a498Xn4OB7qd9B4shg+Fj4DeNZYpKmRWDeiNLYSNeDri
+7OfGT7q4NdRr4AKLWNVhkP76E/18Y2/OS3XqzQ2rzXW/78SwPYpkmg3ms4AJqCFS
+/9wF6E0AeI2UQy0km4GkiYFf0w/ndka/zQ8kMA0TG0n1w5D0itMaR3Wfc5e+S1vQ
+fQFCZOMWpu+GkXgZoajJP0Gh3MrAfA2jcq9ryS8bgbr6fmWv3pX6XR8wIph520pq
+6A+ZWOYg9GjZ4CHPrTytnkM05yZi5hXLlXhsSztzcY24wN34UkuSJSIuOQRzJEcJ
+RgdfgJrFXWlaAwMbAgMBAAGjgekwgeYwHQYDVR0OBBYEFHuSAyipSYF/yOw2JaSo
+MagJ4K/dMB8GA1UdIwQYMBaAFHPbr8vFp9Sj1KQLMyEEPDfOj74tMD8GCCsGAQUF
BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEANFHfOOnC38YsAQB+oUte
-0UOK107/SV0X573iPM1DY02pBZe/duKNkNLd6mtM4x7Be4s1WiTM2LKaEgfSZvr9
-PHm0p9fLaa8H951mNO7tIh99WJ7hSZCIlR4nKj3cqbkdKx+IuQyJobzdJZe5Mg4C
-hvqjLM2OKeVoEjtbvw7MJa0G73cm17SEz7oAVcTwlTmI/yL4pYmK0jGq55h2Ahm9
-BLxcJr5e65Yr9qLPEz6hgpJjwBO8tvkG+3fDD805sa9DtZ38ZNS90IFcBvuLDsVZ
-CwfWp4upjrNr9e2b6ur3b+orAt9ikq6Y+0XKvBxr620z4w4yDw3jf1zv4xvC9vyZ
-pA==
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAQFk2y6x/6F//V+sJ8/zD
+6SuykG5r52CpbB0C9V/MKfbtJf1jfUji8MjsWaGLScOpY6EScH1vowS/GoNq4SFf
+7mtvn11LectMQ6SS6kHq4TaSkP0BCoJlDjwZRP218+tpzcXsnPa/NDU2jXPCb+4g
+Y8fFG8oTKvss3KAkSX9C874WbWJbyYggu+SZEeVZZkAjv6LLVBR2OXp8go/dFrlP
+5NUFq+rra1VkuhVCe07PJWgSj1UOR5O/CwG1aHbDHi4dlo7x2v0T7SnPjjAt3JzW
+GgQbeozD/aFCcnkuR8h/KLCO6iqz3rANF0rge+ykk4mqpO/EbtJP6m8W9k9vQdmO
+VQ==
-----END CERTIFICATE-----
Certificate:
@@ -99,88 +99,88 @@ Certificate:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
+ Issuer: CN=Intermediate
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
+ Subject: CN=Intermediate
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:e6:56:91:e6:27:53:a1:d7:64:56:d8:c8:57:b7:
- 55:7c:89:a2:b4:9d:ab:72:f0:bc:03:35:16:53:77:
- 7e:ef:bf:0b:f5:91:d5:de:ae:bb:ae:ae:3a:53:00:
- ec:80:3b:a0:2b:d3:6a:ae:0c:d0:4c:a1:24:b2:b4:
- 77:de:ad:81:0f:70:f8:f4:dc:f8:c7:6e:f8:54:29:
- 84:3a:b8:83:f4:95:22:80:ae:71:b0:dd:4e:ba:82:
- 87:80:d1:c7:f3:ad:a7:45:c5:db:47:3c:8e:84:31:
- bc:c6:bd:29:77:70:39:78:f4:3b:5e:ae:8f:d9:44:
- 6b:1a:1d:cb:f9:7b:84:14:7c:5b:b8:82:3c:ed:47:
- 16:c6:4e:2b:75:5a:1b:b4:5d:0c:0a:2f:55:b6:48:
- 87:a1:25:a2:a9:5b:e4:a8:f9:bc:70:24:92:07:7f:
- 5b:94:83:3b:44:78:65:cb:62:0c:30:fa:cf:f1:f7:
- 20:9e:76:c8:52:78:8b:f8:30:62:f0:66:28:8a:7f:
- ba:74:12:f8:05:ef:29:d8:17:cb:8a:95:61:fc:af:
- 58:d2:e2:86:d7:8c:fb:3b:56:28:8d:e4:d9:27:48:
- b6:c1:fc:9a:4e:d4:24:b8:68:c3:32:5d:65:30:6e:
- a3:9e:b9:bf:6e:a7:3b:b4:3d:2e:5d:13:a1:28:4e:
- a4:0d
+ 00:bc:3f:0f:56:90:45:57:c4:d8:42:91:22:59:d4:
+ 81:5e:4b:af:73:90:fc:5f:85:cc:14:71:73:c5:76:
+ 70:2b:2c:f7:25:e7:b8:7d:a0:1d:a7:70:b4:f9:b8:
+ 08:1f:58:33:95:5f:37:73:c2:39:eb:da:ac:4b:fe:
+ 18:77:35:d5:46:e7:d3:2e:8d:d5:df:c9:21:98:c3:
+ 86:5d:22:f0:19:b1:1c:e0:49:a7:ad:d4:c7:e0:e4:
+ f1:ef:c1:b7:48:38:de:a9:d3:fc:4d:14:a4:53:b6:
+ 80:64:bf:f7:82:3e:05:9a:7e:b7:b4:5a:5f:6d:28:
+ 1a:91:86:a6:f8:f5:37:42:8a:81:7b:25:e8:1f:75:
+ e1:7f:bf:01:38:05:dd:38:ae:04:2e:8a:9e:e0:b7:
+ c5:2a:aa:7b:4e:1e:ff:87:97:c8:9e:dd:33:ef:d9:
+ f5:58:80:04:9a:e1:b6:49:d9:b9:85:40:d7:c7:fe:
+ e1:13:73:e5:70:37:cd:40:1d:eb:9b:43:52:e6:c3:
+ 31:a0:2f:fb:82:38:62:aa:9e:08:dd:bc:4d:2b:05:
+ f0:a3:31:ab:b7:47:ca:69:a6:47:14:c1:64:63:d0:
+ 0c:2d:bc:6c:e3:d2:98:e0:df:25:0d:9f:1f:9b:07:
+ 1b:80:0f:9d:da:04:67:8d:e0:cf:0b:5b:ec:f6:62:
+ 5f:51
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 31:9F:A3:DB:EA:90:94:EB:3D:93:39:9F:BA:8A:05:7E:2C:94:23:9B
+ 73:DB:AF:CB:C5:A7:D4:A3:D4:A4:0B:33:21:04:3C:37:CE:8F:BE:2D
X509v3 Authority Key Identifier:
- keyid:73:4C:95:45:4C:3B:F6:7E:7B:92:30:C9:AC:30:51:E7:7D:21:D2:BF
+ keyid:48:4D:93:8D:A1:E0:46:7F:2F:DD:60:DF:D1:DF:58:29:2C:1B:CB:4F
Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
X509v3 CRL Distribution Points:
Full Name:
- URI:http://url-for-crl/Intermediary.crl
+ URI:http://url-for-crl/Intermediate.crl
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
Signature Algorithm: sha256WithRSAEncryption
- 0d:7d:a3:df:40:cd:02:79:b5:69:5d:c5:a7:eb:bc:87:95:c3:
- 17:fc:73:dd:59:a8:c2:d3:67:71:15:09:7a:9b:f8:01:5d:a0:
- d2:a3:e5:37:1d:f5:f3:2c:fd:8d:8e:e7:6c:ca:01:2a:83:a8:
- 00:c9:65:26:8e:ab:0b:13:91:9c:00:9a:a3:60:44:8c:82:0f:
- 04:1e:74:b1:c6:4f:a6:da:37:70:16:35:03:92:f2:04:ab:c8:
- 21:97:a8:b4:e3:bf:bf:67:9e:ce:c3:24:df:6a:cc:43:d6:ea:
- 59:89:b7:3e:1c:de:ed:ab:99:ec:26:60:3b:b7:84:4b:e0:1a:
- b7:be:6d:20:7b:f4:88:a2:bf:95:3f:6e:7a:fa:ea:e1:55:72:
- 88:ae:67:b3:13:1a:3a:1f:07:16:1d:84:fd:e5:e3:1e:90:ec:
- dc:d2:ce:73:c0:50:19:69:10:dc:c7:db:91:46:f4:50:52:87:
- 94:6e:ce:ef:a6:20:57:d2:ad:36:95:1e:94:7f:a3:8f:d9:0d:
- 99:dd:8f:e3:2a:b2:2b:69:a0:f7:26:4e:cd:f2:f1:cf:05:14:
- 31:3d:aa:71:01:dd:42:24:19:62:5c:00:1b:98:ac:7d:45:f2:
- e6:14:dd:2e:10:06:74:39:61:6d:b9:3c:68:c1:e7:3d:b6:3d:
- e1:75:c9:fd
+ 02:4e:c6:b9:10:f4:c7:3a:52:73:e3:7c:02:6d:61:77:b3:f8:
+ 98:5f:c5:f2:b4:78:74:36:6b:40:6e:fc:a7:53:7c:b2:5e:e3:
+ 35:08:1b:44:6c:51:75:29:0f:d1:6c:c0:eb:92:da:11:41:6d:
+ d8:56:01:aa:81:e2:58:4f:24:bd:bd:25:6b:ab:b3:b3:0a:05:
+ 1c:db:ed:c2:34:68:11:34:67:ef:32:81:be:e1:53:0b:dd:2b:
+ ec:07:13:b8:12:b5:42:84:02:e0:56:69:f1:71:bd:6c:1a:5a:
+ 64:59:8b:4c:a5:d2:7d:13:7d:99:d5:4e:94:41:5c:69:f7:32:
+ 12:6a:c9:a9:ce:96:1f:6d:72:60:35:d1:fc:2f:c6:66:a2:2e:
+ 48:1e:6e:0a:80:07:5b:d9:b7:ec:28:78:c3:31:2d:c8:45:0d:
+ 28:94:b4:98:ba:83:1e:66:e7:f1:37:1e:f6:1d:00:50:90:c0:
+ 58:09:f2:ee:02:85:0c:10:65:0b:c8:2b:04:06:92:64:d4:34:
+ 10:36:99:f0:e4:fa:b6:b4:24:3a:57:6c:34:b4:dc:bf:48:d5:
+ df:97:a7:16:3d:3d:48:ed:c3:3c:b7:ca:e9:36:b4:43:49:e5:
+ ba:e9:c3:11:70:2f:b2:74:31:4c:60:da:b3:c4:b6:82:43:e8:
+ f1:e7:1a:4a
-----BEGIN CERTIFICATE-----
MIIDiDCCAnCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjAXMRUwEwYD
-VQQDDAxJbnRlcm1lZGlhcnkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
-AQDmVpHmJ1Oh12RW2MhXt1V8iaK0naty8LwDNRZTd37vvwv1kdXerruurjpTAOyA
-O6Ar02quDNBMoSSytHferYEPcPj03PjHbvhUKYQ6uIP0lSKArnGw3U66goeA0cfz
-radFxdtHPI6EMbzGvSl3cDl49Dtero/ZRGsaHcv5e4QUfFu4gjztRxbGTit1Whu0
-XQwKL1W2SIehJaKpW+So+bxwJJIHf1uUgztEeGXLYgww+s/x9yCedshSeIv4MGLw
-ZiiKf7p0EvgF7ynYF8uKlWH8r1jS4obXjPs7ViiN5NknSLbB/JpO1CS4aMMyXWUw
-bqOeub9upzu0PS5dE6EoTqQNAgMBAAGjgd4wgdswHQYDVR0OBBYEFDGfo9vqkJTr
-PZM5n7qKBX4slCObMB8GA1UdIwQYMBaAFHNMlUVMO/Z+e5IwyawwUed9IdK/MD8G
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjAXMRUwEwYD
+VQQDDAxJbnRlcm1lZGlhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQC8Pw9WkEVXxNhCkSJZ1IFeS69zkPxfhcwUcXPFdnArLPcl57h9oB2ncLT5uAgf
+WDOVXzdzwjnr2qxL/hh3NdVG59MujdXfySGYw4ZdIvAZsRzgSaet1Mfg5PHvwbdI
+ON6p0/xNFKRTtoBkv/eCPgWafre0Wl9tKBqRhqb49TdCioF7JegfdeF/vwE4Bd04
+rgQuip7gt8UqqntOHv+Hl8ie3TPv2fVYgASa4bZJ2bmFQNfH/uETc+VwN81AHeub
+Q1LmwzGgL/uCOGKqngjdvE0rBfCjMau3R8pppkcUwWRj0AwtvGzj0pjg3yUNnx+b
+BxuAD53aBGeN4M8LW+z2Yl9RAgMBAAGjgd4wgdswHQYDVR0OBBYEFHPbr8vFp9Sj
+1KQLMyEEPDfOj74tMB8GA1UdIwQYMBaAFEhNk42h4EZ/L91g39HfWCksG8tPMD8G
CCsGAQUFBwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0lu
-dGVybWVkaWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3It
-Y3JsL0ludGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI
-MAYBAf8CAQAwDQYJKoZIhvcNAQELBQADggEBAA19o99AzQJ5tWldxafrvIeVwxf8
-c91ZqMLTZ3EVCXqb+AFdoNKj5Tcd9fMs/Y2O52zKASqDqADJZSaOqwsTkZwAmqNg
-RIyCDwQedLHGT6baN3AWNQOS8gSryCGXqLTjv79nns7DJN9qzEPW6lmJtz4c3u2r
-mewmYDu3hEvgGre+bSB79Iiiv5U/bnr66uFVcoiuZ7MTGjofBxYdhP3l4x6Q7NzS
-znPAUBlpENzH25FG9FBSh5Ruzu+mIFfSrTaVHpR/o4/ZDZndj+MqsitpoPcmTs3y
-8c8FFDE9qnEB3UIkGWJcABuYrH1F8uYU3S4QBnQ5YW25PGjB5z22PeF1yf0=
+dGVybWVkaWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3It
+Y3JsL0ludGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI
+MAYBAf8CAQAwDQYJKoZIhvcNAQELBQADggEBAAJOxrkQ9Mc6UnPjfAJtYXez+Jhf
+xfK0eHQ2a0Bu/KdTfLJe4zUIG0RsUXUpD9FswOuS2hFBbdhWAaqB4lhPJL29JWur
+s7MKBRzb7cI0aBE0Z+8ygb7hUwvdK+wHE7gStUKEAuBWafFxvWwaWmRZi0yl0n0T
+fZnVTpRBXGn3MhJqyanOlh9tcmA10fwvxmaiLkgebgqAB1vZt+woeMMxLchFDSiU
+tJi6gx5m5/E3HvYdAFCQwFgJ8u4ChQwQZQvIKwQGkmTUNBA2mfDk+ra0JDpXbDS0
+3L9I1d+XpxY9PUjtwzy3yuk2tENJ5brpwxFwL7J0MUxg2rPEtoJD6PHnGko=
-----END CERTIFICATE-----
Certificate:
@@ -192,35 +192,35 @@ Certificate:
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
+ Subject: CN=Intermediate
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:c9:30:53:c1:b9:0f:27:7a:39:3d:39:c4:a3:7c:
- 96:bb:0e:e4:d9:fd:10:76:98:36:62:fc:33:7c:02:
- 47:6c:6f:2e:d2:61:aa:d5:e3:86:67:a2:ef:93:a3:
- fd:15:83:1c:27:90:f3:81:4a:41:f2:e6:e6:be:26:
- 9a:b0:77:1d:e5:8a:97:2d:a7:87:6b:80:49:26:0e:
- da:48:36:ba:eb:71:6a:cb:b4:82:66:42:fd:58:5f:
- bc:c9:18:30:ee:2f:0c:28:81:e7:36:b9:76:da:55:
- 8c:7a:cf:a9:1f:04:c6:6e:42:ea:d3:83:c6:8d:04:
- 26:9e:11:8a:c6:cd:25:c7:4a:58:d1:98:86:b5:37:
- 9c:3e:68:2e:17:4d:81:85:f3:d4:7d:65:e7:0f:86:
- 8a:c9:d0:2d:fc:4f:c7:40:2a:ef:48:ab:2e:4c:2e:
- b6:1c:81:4e:73:73:e9:cc:d4:ef:94:b1:17:2c:70:
- 64:b0:4c:ad:87:cf:45:13:c2:67:46:d1:c6:b3:61:
- 8d:77:af:4f:1c:b6:4f:b6:d9:2b:3c:4c:5f:72:23:
- 77:c7:85:65:1d:85:48:28:06:34:b4:f0:bd:a9:76:
- 7a:65:60:59:d6:f6:26:f6:85:99:7b:84:16:5e:91:
- 8d:f9:90:b8:75:d3:4a:77:6a:1f:f8:ed:66:67:22:
- 64:4b
+ 00:df:e8:e6:8a:d4:14:cf:36:33:e1:1b:9d:9a:cc:
+ d0:2c:1d:50:df:32:32:c7:d8:27:cc:68:21:8b:6d:
+ 1b:b0:14:8f:51:64:7f:6d:a4:ca:8d:73:b2:64:93:
+ fe:63:55:50:09:64:e6:2b:7c:e0:21:c8:39:98:13:
+ 12:34:70:60:0c:67:20:4a:35:3d:9f:9b:11:f4:8d:
+ 34:3f:b8:fb:b7:88:42:cb:70:94:a7:9f:b6:f2:46:
+ 24:21:3f:ec:26:a6:39:63:87:04:04:9a:33:01:b6:
+ dc:05:67:79:16:d6:e2:0b:fe:de:31:9a:a7:a2:07:
+ 8b:dc:1c:eb:70:ea:4a:76:b1:cd:b8:79:f8:e2:8e:
+ a4:4a:a7:c6:9b:ad:34:a6:1d:40:c9:8d:04:df:66:
+ 87:a1:d4:8b:59:4e:e9:11:42:2c:7d:19:d6:e9:bb:
+ d3:2c:b3:d5:df:69:c2:00:83:f8:3b:80:98:71:92:
+ 62:34:8b:6d:d4:fa:5d:d9:31:a6:d4:fb:ff:e2:9f:
+ e2:ad:0a:bf:15:63:55:54:96:d9:f2:46:01:c8:06:
+ a8:00:45:ad:b5:d1:4d:f0:e4:a8:f5:19:04:7b:03:
+ 33:8f:bb:94:9d:b3:23:cd:5e:73:54:62:3b:09:0f:
+ 73:8c:4f:0c:5a:2c:64:bb:33:70:49:2b:6f:cc:93:
+ 49:91
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 73:4C:95:45:4C:3B:F6:7E:7B:92:30:C9:AC:30:51:E7:7D:21:D2:BF
+ 48:4D:93:8D:A1:E0:46:7F:2F:DD:60:DF:D1:DF:58:29:2C:1B:CB:4F
X509v3 Authority Key Identifier:
- keyid:DE:10:87:7A:48:75:9E:50:89:F1:AE:40:E0:BF:BA:5F:D8:63:77:9B
+ keyid:1A:7A:32:47:1F:8A:2F:A8:FC:F7:F0:A3:67:37:3E:39:C8:F4:46:02
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -235,41 +235,41 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
Signature Algorithm: sha256WithRSAEncryption
- 3f:40:c5:c8:06:d9:35:27:63:63:e7:9c:08:1d:ee:ef:e3:b6:
- 11:a7:a2:4f:b0:bf:8b:14:2f:16:6f:47:f5:0b:d8:3d:98:7a:
- 03:7d:30:0c:85:11:80:a6:ff:fc:99:dd:a0:31:d6:fb:bf:4f:
- 09:49:64:ca:8a:34:3d:56:c3:72:b0:08:e2:b8:12:95:1e:70:
- 4f:3f:5b:1e:70:6f:06:f0:78:77:90:3b:d1:54:83:f2:b1:8e:
- 7e:25:d3:f7:21:66:8b:a9:c4:f7:f6:bb:a9:7a:3b:e0:99:4c:
- 94:b7:45:3a:fe:61:74:0a:70:de:a0:d6:c1:c4:dd:59:0e:cc:
- 81:d1:ad:da:99:1d:83:b3:e2:3a:7b:8f:5c:3a:25:52:3e:40:
- 5a:96:00:71:e6:f3:5d:9c:6a:54:be:0f:24:8e:8b:3a:14:37:
- 6a:72:0b:41:e6:06:d1:b2:3d:f9:a2:bb:d7:6e:f1:ac:70:08:
- 62:e7:f2:82:df:fb:85:e4:99:b9:cf:84:9a:34:55:e5:e8:39:
- a9:e7:e3:79:54:07:c9:6b:1d:33:aa:30:d3:ea:7b:32:07:0f:
- 23:34:10:fa:58:17:ad:e0:62:c8:ce:d6:0f:db:34:0c:a3:a9:
- f9:09:05:c6:25:d9:ce:e5:52:0a:5c:8a:f3:c9:44:72:45:71:
- 6d:5c:fc:d1
+ 94:bc:e1:64:08:ca:c2:07:5e:6e:16:0a:95:78:26:81:d1:6f:
+ 14:5d:10:b0:4a:0b:f9:04:1f:58:68:35:1b:70:cd:d3:22:58:
+ 62:7d:38:a2:f3:69:af:a3:1e:a0:22:4d:9b:5a:4b:36:3e:78:
+ 49:a0:aa:02:9d:fe:5c:ce:df:6b:e8:f4:fb:5b:05:7c:78:4f:
+ f4:66:56:0c:95:c4:31:59:33:f0:e8:be:ad:1c:5d:36:64:0d:
+ b4:ee:49:19:9f:ad:b7:f5:c4:4c:8e:58:db:61:b7:a2:a7:f7:
+ 86:22:da:2f:07:65:33:0a:23:86:59:2d:33:37:8f:e9:a9:24:
+ 84:5a:43:5f:80:5a:88:97:1c:b3:ea:50:0e:10:f4:4f:36:28:
+ 3a:6a:4a:70:0b:78:16:97:83:ea:ae:34:94:87:02:7b:6d:a0:
+ 7d:1b:8c:9b:66:3e:69:f5:d1:6e:04:83:6b:f1:68:a0:69:2b:
+ 88:7c:57:e1:42:81:d3:a8:d8:c7:7e:aa:3a:bf:37:1e:fd:64:
+ a7:3a:4a:10:3b:7e:c9:fe:d0:ac:c0:d4:f0:16:4a:78:f2:7f:
+ db:db:4c:8c:96:42:27:85:02:32:b8:71:ca:41:ac:a9:5e:11:
+ a1:f7:3b:4b:f4:ae:b0:25:ff:cc:4e:12:5b:ca:a6:ae:ed:71:
+ c8:14:47:56
-----BEGIN CERTIFICATE-----
MIIDcDCCAligAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyTBTwbkP
-J3o5PTnEo3yWuw7k2f0Qdpg2YvwzfAJHbG8u0mGq1eOGZ6Lvk6P9FYMcJ5DzgUpB
-8ubmviaasHcd5YqXLaeHa4BJJg7aSDa663Fqy7SCZkL9WF+8yRgw7i8MKIHnNrl2
-2lWMes+pHwTGbkLq04PGjQQmnhGKxs0lx0pY0ZiGtTecPmguF02BhfPUfWXnD4aK
-ydAt/E/HQCrvSKsuTC62HIFOc3PpzNTvlLEXLHBksEyth89FE8JnRtHGs2GNd69P
-HLZPttkrPExfciN3x4VlHYVIKAY0tPC9qXZ6ZWBZ1vYm9oWZe4QWXpGN+ZC4ddNK
-d2of+O1mZyJkSwIDAQABo4HOMIHLMB0GA1UdDgQWBBRzTJVFTDv2fnuSMMmsMFHn
-fSHSvzAfBgNVHSMEGDAWgBTeEId6SHWeUInxrkDgv7pf2GN3mzA3BggrBgEFBQcB
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+jmitQU
+zzYz4RudmszQLB1Q3zIyx9gnzGghi20bsBSPUWR/baTKjXOyZJP+Y1VQCWTmK3zg
+Icg5mBMSNHBgDGcgSjU9n5sR9I00P7j7t4hCy3CUp5+28kYkIT/sJqY5Y4cEBJoz
+AbbcBWd5FtbiC/7eMZqnogeL3BzrcOpKdrHNuHn44o6kSqfGm600ph1AyY0E32aH
+odSLWU7pEUIsfRnW6bvTLLPV32nCAIP4O4CYcZJiNItt1Ppd2TGm1Pv/4p/irQq/
+FWNVVJbZ8kYByAaoAEWttdFN8OSo9RkEewMzj7uUnbMjzV5zVGI7CQ9zjE8MWixk
+uzNwSStvzJNJkQIDAQABo4HOMIHLMB0GA1UdDgQWBBRITZONoeBGfy/dYN/R31gp
+LBvLTzAfBgNVHSMEGDAWgBQaejJHH4ovqPz38KNnNz45yPRGAjA3BggrBgEFBQcB
AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
VR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwDQYJKoZIhvcNAQELBQAD
-ggEBAD9AxcgG2TUnY2PnnAgd7u/jthGnok+wv4sULxZvR/UL2D2YegN9MAyFEYCm
-//yZ3aAx1vu/TwlJZMqKND1Ww3KwCOK4EpUecE8/Wx5wbwbweHeQO9FUg/Kxjn4l
-0/chZoupxPf2u6l6O+CZTJS3RTr+YXQKcN6g1sHE3VkOzIHRrdqZHYOz4jp7j1w6
-JVI+QFqWAHHm812calS+DySOizoUN2pyC0HmBtGyPfmiu9du8axwCGLn8oLf+4Xk
-mbnPhJo0VeXoOann43lUB8lrHTOqMNPqezIHDyM0EPpYF63gYsjO1g/bNAyjqfkJ
-BcYl2c7lUgpcivPJRHJFcW1c/NE=
+ggEBAJS84WQIysIHXm4WCpV4JoHRbxRdELBKC/kEH1hoNRtwzdMiWGJ9OKLzaa+j
+HqAiTZtaSzY+eEmgqgKd/lzO32vo9PtbBXx4T/RmVgyVxDFZM/Dovq0cXTZkDbTu
+SRmfrbf1xEyOWNtht6Kn94Yi2i8HZTMKI4ZZLTM3j+mpJIRaQ1+AWoiXHLPqUA4Q
+9E82KDpqSnALeBaXg+quNJSHAnttoH0bjJtmPmn10W4Eg2vxaKBpK4h8V+FCgdOo
+2Md+qjq/Nx79ZKc6ShA7fsn+0KzA1PAWSnjyf9vbTIyWQieFAjK4ccpBrKleEaH3
+O0v0rrAl/8xOElvKpq7tccgUR1Y=
-----END CERTIFICATE-----
Certificate:
@@ -286,30 +286,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:a8:11:83:b7:cc:88:e9:4c:69:28:ad:6a:95:83:
- 6a:1c:28:52:d2:02:21:00:93:f0:82:8e:fc:b8:fb:
- b9:44:e2:43:e9:fe:3f:7e:0c:01:a6:9f:12:fc:09:
- fc:66:44:03:b4:66:78:3c:36:05:37:00:6e:87:54:
- ff:61:95:ab:37:88:a0:6e:f7:8f:c2:ea:8d:e5:bf:
- 4c:21:21:1d:74:22:dd:93:52:b3:66:d7:97:33:b9:
- cb:ab:8e:38:59:52:e7:f0:5c:09:50:ad:c9:e0:e1:
- 18:d7:cc:4a:d7:2b:41:cd:91:8c:a2:b0:25:d6:6c:
- d2:7d:e8:fa:20:3f:c8:aa:15:b9:77:b6:da:ac:86:
- f8:21:52:2e:f9:e7:b6:d5:65:fd:23:ba:2f:5b:1b:
- c6:62:76:00:f1:74:4b:e2:d9:9a:d3:67:03:71:d4:
- 93:af:93:4d:4f:82:da:1c:ba:a5:a9:0f:25:6b:54:
- dd:63:8c:3e:34:75:32:9e:c8:99:44:fd:f0:47:6d:
- 98:45:3c:75:b5:ac:0b:eb:d6:30:6a:a1:6c:67:14:
- ee:62:72:93:fe:bc:4c:e8:10:a2:3c:66:33:1c:49:
- e8:dc:2f:c9:a4:64:17:88:a0:1c:a4:b0:ff:9c:8f:
- c4:c6:18:1d:0c:55:62:a9:3b:f6:bc:53:16:62:82:
- 49:c5
+ 00:da:42:ae:40:b4:79:95:43:58:4b:a9:e0:62:96:
+ d0:f2:19:7c:6e:dc:8a:96:f6:5a:ec:66:f6:c3:9d:
+ 3f:0e:18:b9:7a:60:da:df:e1:67:ce:ec:4c:8d:45:
+ 8a:76:5f:1b:c7:22:1c:2b:40:4d:83:ed:1d:94:f0:
+ 21:0f:d1:37:8e:9c:4e:98:29:94:3c:e3:e2:79:74:
+ 4d:12:91:c9:32:b8:6e:7f:7a:d8:26:44:3d:f6:3d:
+ b6:6b:0f:2a:bd:cd:3d:24:e0:34:bc:53:8b:fa:c6:
+ 86:66:ec:9e:f9:b3:c0:41:cc:23:c2:5a:72:da:de:
+ f6:56:6e:10:d0:5a:26:d1:e5:7e:f5:bb:6b:67:47:
+ 2a:01:d4:5c:d2:40:89:c5:0b:19:b7:63:32:af:d9:
+ 85:f2:79:77:6a:81:e1:27:13:c7:da:b9:94:7b:25:
+ c5:d0:ca:67:bb:26:8f:7a:0f:8d:19:67:6d:96:2f:
+ 24:7a:76:50:c3:62:fa:ae:47:99:a4:97:af:f1:ce:
+ 02:8b:fe:50:09:a2:16:07:b3:08:65:e9:35:e8:f5:
+ b6:54:c2:66:15:ac:97:76:ee:da:0d:92:6e:f1:be:
+ 18:2d:8d:c5:8e:de:fc:a7:b9:fa:27:43:19:4a:08:
+ d5:ae:0e:9c:7e:7a:8e:36:2f:1d:11:5b:70:c0:77:
+ 90:af
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- DE:10:87:7A:48:75:9E:50:89:F1:AE:40:E0:BF:BA:5F:D8:63:77:9B
+ 1A:7A:32:47:1F:8A:2F:A8:FC:F7:F0:A3:67:37:3E:39:C8:F4:46:02
X509v3 Authority Key Identifier:
- keyid:DE:10:87:7A:48:75:9E:50:89:F1:AE:40:E0:BF:BA:5F:D8:63:77:9B
+ keyid:1A:7A:32:47:1F:8A:2F:A8:FC:F7:F0:A3:67:37:3E:39:C8:F4:46:02
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -324,47 +324,49 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 27:c0:50:82:2b:1b:71:84:c6:12:ea:45:ed:21:b8:fd:7c:08:
- 68:ec:de:4a:1b:98:3b:ce:e9:a1:9e:42:9a:e0:f4:e2:09:a6:
- 5c:98:33:16:5b:65:6b:fc:b9:9b:26:90:e1:86:58:1f:0a:7e:
- 7e:0d:7d:4e:0e:8b:93:04:b9:84:f0:e8:a3:7f:34:e2:ab:f5:
- d5:bb:46:b7:df:a0:3a:81:8c:56:48:02:95:8f:06:cb:f2:cd:
- 2a:39:c6:12:5a:9d:62:e9:a9:49:55:4d:e9:17:c2:97:3d:81:
- 12:76:d8:68:18:f6:7e:a6:c4:52:a9:85:4c:83:38:94:2b:df:
- dd:39:bb:cf:e1:9e:4e:e1:a0:eb:63:8a:c0:6e:99:01:65:78:
- b5:ca:ab:2a:90:86:c5:5e:53:62:57:89:14:c1:41:8f:e6:9a:
- 60:97:e4:5c:5b:fa:28:9c:9f:e3:55:ed:42:36:b6:d0:8d:f3:
- 0c:cf:6e:87:38:aa:98:91:a9:1f:48:2a:c7:27:49:04:d6:d6:
- f8:33:c9:d0:e2:b7:87:00:9a:1f:63:af:5b:ac:70:7e:96:9f:
- b0:3b:e5:a3:f8:04:b6:f8:2c:38:54:21:06:51:33:32:78:80:
- 17:59:83:95:66:65:1d:b5:5b:f2:1b:3e:6d:9e:98:c2:09:f3:
- ec:52:20:5b
------BEGIN TRUSTED_CERTIFICATE-----
+ c4:30:1e:17:33:a6:67:a2:0f:5e:a9:53:54:f6:2f:f6:18:ad:
+ 21:b8:48:8a:81:38:62:1d:63:9f:2e:ef:a6:d2:56:c4:19:b5:
+ 00:8e:19:fd:29:35:b9:a5:c1:26:9b:81:4a:2a:a6:37:8a:bf:
+ 23:5e:2c:ca:e7:8a:a6:75:7f:fd:49:1b:cc:e8:42:99:2a:b0:
+ 44:e3:27:17:11:88:bc:1b:b1:40:f5:5c:f0:85:22:ad:41:8d:
+ a0:95:d7:94:5b:f0:a7:da:56:3a:db:5d:d3:29:d9:87:e3:1e:
+ 34:14:c3:91:f9:0b:91:fb:40:f4:9f:44:d9:e3:68:b8:fe:b7:
+ 20:8c:d4:63:da:45:60:7f:2d:42:d5:15:b5:9c:69:d6:ed:ff:
+ 2b:aa:49:43:0f:a8:52:0c:91:28:88:0f:da:7b:92:66:63:85:
+ b6:f2:29:8f:2c:aa:c4:b4:53:32:a1:00:2f:a5:1d:34:f0:32:
+ b2:59:a1:61:f4:16:42:a5:9a:fb:62:31:e3:85:3b:23:73:2d:
+ c1:cc:88:97:f6:12:95:01:52:5d:c2:06:aa:85:1c:25:78:9e:
+ f5:e6:8f:59:49:7c:d1:a6:e2:f4:1f:a2:7f:92:2b:6a:c0:44:
+ d7:c0:e5:7f:d9:44:13:82:ae:06:ee:1f:64:04:c4:7d:7f:cf:
+ 04:97:2e:41
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKgRg7fMiOlMaSitapWD
-ahwoUtICIQCT8IKO/Lj7uUTiQ+n+P34MAaafEvwJ/GZEA7RmeDw2BTcAbodU/2GV
-qzeIoG73j8LqjeW/TCEhHXQi3ZNSs2bXlzO5y6uOOFlS5/BcCVCtyeDhGNfMStcr
-Qc2RjKKwJdZs0n3o+iA/yKoVuXe22qyG+CFSLvnnttVl/SO6L1sbxmJ2APF0S+LZ
-mtNnA3HUk6+TTU+C2hy6pakPJWtU3WOMPjR1Mp7ImUT98EdtmEU8dbWsC+vWMGqh
-bGcU7mJyk/68TOgQojxmMxxJ6NwvyaRkF4igHKSw/5yPxMYYHQxVYqk79rxTFmKC
-ScUCAwEAAaOByzCByDAdBgNVHQ4EFgQU3hCHekh1nlCJ8a5A4L+6X9hjd5swHwYD
-VR0jBBgwFoAU3hCHekh1nlCJ8a5A4L+6X9hjd5swNwYIKwYBBQUHAQEEKzApMCcG
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANpCrkC0eZVDWEup4GKW
+0PIZfG7cipb2Wuxm9sOdPw4YuXpg2t/hZ87sTI1FinZfG8ciHCtATYPtHZTwIQ/R
+N46cTpgplDzj4nl0TRKRyTK4bn962CZEPfY9tmsPKr3NPSTgNLxTi/rGhmbsnvmz
+wEHMI8Jactre9lZuENBaJtHlfvW7a2dHKgHUXNJAicULGbdjMq/ZhfJ5d2qB4ScT
+x9q5lHslxdDKZ7smj3oPjRlnbZYvJHp2UMNi+q5HmaSXr/HOAov+UAmiFgezCGXp
+Nej1tlTCZhWsl3bu2g2SbvG+GC2NxY7e/Ke5+idDGUoI1a4OnH56jjYvHRFbcMB3
+kK8CAwEAAaOByzCByDAdBgNVHQ4EFgQUGnoyRx+KL6j89/CjZzc+Ocj0RgIwHwYD
+VR0jBBgwFoAUGnoyRx+KL6j89/CjZzc+Ocj0RgIwNwYIKwYBBQUHAQEEKzApMCcG
CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAnwFCCKxtx
-hMYS6kXtIbj9fAho7N5KG5g7zumhnkKa4PTiCaZcmDMWW2Vr/LmbJpDhhlgfCn5+
-DX1ODouTBLmE8OijfzTiq/XVu0a336A6gYxWSAKVjwbL8s0qOcYSWp1i6alJVU3p
-F8KXPYESdthoGPZ+psRSqYVMgziUK9/dObvP4Z5O4aDrY4rAbpkBZXi1yqsqkIbF
-XlNiV4kUwUGP5ppgl+RcW/oonJ/jVe1CNrbQjfMMz26HOKqYkakfSCrHJ0kE1tb4
-M8nQ4reHAJofY69brHB+lp+wO+Wj+AS2+Cw4VCEGUTMyeIAXWYOVZmUdtVvyGz5t
-npjCCfPsUiBb
------END TRUSTED_CERTIFICATE-----
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDEMB4XM6Zn
+og9eqVNU9i/2GK0huEiKgThiHWOfLu+m0lbEGbUAjhn9KTW5pcEmm4FKKqY3ir8j
+XizK54qmdX/9SRvM6EKZKrBE4ycXEYi8G7FA9VzwhSKtQY2gldeUW/Cn2lY6213T
+KdmH4x40FMOR+QuR+0D0n0TZ42i4/rcgjNRj2kVgfy1C1RW1nGnW7f8rqklDD6hS
+DJEoiA/ae5JmY4W28imPLKrEtFMyoQAvpR008DKyWaFh9BZCpZr7YjHjhTsjcy3B
+zIiX9hKVAVJdwgaqhRwleJ715o9ZSXzRpuL0H6J/kitqwETXwOV/2UQTgq4G7h9k
+BMR9f88Ely5B
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+150302120000Z
-----BEGIN TIME-----
MTUwMzAyMTIwMDAwWg==
-----END TIME-----
+SUCCESS
-----BEGIN VERIFY_RESULT-----
U1VDQ0VTUw==
-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/common.py b/chromium/net/data/verify_certificate_chain_unittest/common.py
index 0174ec1c1cb..c5bcd972998 100755
--- a/chromium/net/data/verify_certificate_chain_unittest/common.py
+++ b/chromium/net/data/verify_certificate_chain_unittest/common.py
@@ -53,7 +53,7 @@ g_out_dir = None
g_out_pem = None
-def GetUniquePathId(name):
+def get_unique_path_id(name):
"""Returns a base filename that contains 'name', but is unique to the output
directory"""
path_id = g_cur_path_id.get(name, 0)
@@ -67,6 +67,61 @@ def GetUniquePathId(name):
return '%s_%d' % (name, path_id)
+def get_path_in_output_dir(name, suffix):
+ return os.path.join(g_out_dir, '%s%s' % (name, suffix))
+
+
+def get_unique_path_in_output_dir(name, suffix):
+ return get_path_in_output_dir(get_unique_path_id(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 generate_rsa_key(size_bits, path=None):
+ """Generates an RSA private key and returns it as a Key object. If |path| is
+ specified the resulting key will be saved at that location."""
+ if path is None:
+ path = get_unique_path_in_output_dir('RsaKey', 'key')
+
+ # Ensure the path doesn't already exists (otherwise will be overwriting
+ # something).
+ assert not os.path.isfile(path)
+
+ subprocess.check_call(
+ ['openssl', 'genrsa', '-out', path, str(size_bits)])
+
+ return Key(path)
+
+
+def generate_ec_key(named_curve, path=None):
+ """Generates an EC private key for the certificate and returns it as a Key
+ object. |named_curve| can be something like secp384r1. If |path| is specified
+ the resulting key will be saved at that location."""
+ if path is None:
+ path = get_unique_path_in_output_dir('EcKey', 'key')
+
+ # Ensure the path doesn't already exists (otherwise will be overwriting
+ # something).
+ assert not os.path.isfile(path)
+
+ subprocess.check_call(
+ ['openssl', 'ecparam', '-out', path,
+ '-name', named_curve, '-genkey'])
+
+ return Key(path)
+
+
class Certificate(object):
"""Helper for building an X.509 certificate."""
@@ -74,10 +129,11 @@ class Certificate(object):
# 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 = GetUniquePathId(name)
+ self.path_id = get_unique_path_id(name)
- # If specified, use the key from this path instead of generating a new one.
- self.key_path = None
+ # 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.
@@ -98,7 +154,7 @@ class Certificate(object):
self.md_flags = []
# By default OpenSSL will use the current time for the start time. Instead
- # default to using a fixed timestamp for more predictabl results each time
+ # default to using a fixed timestamp for more predictable results each time
# the certificates are re-generated.
self.set_validity_range(JANUARY_1_2015_UTC, JANUARY_1_2016_UTC)
@@ -127,24 +183,10 @@ class Certificate(object):
# 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.
- write_string_to_file('01\n', self.get_serial_path())
- write_string_to_file('', self.get_database_path())
-
-
- def generate_rsa_key(self, size_bits):
- """Generates an RSA private key for the certificate."""
- assert self.key_path is None
- subprocess.check_call(
- ['openssl', 'genrsa', '-out', self.get_key_path(), str(size_bits)])
-
-
- def generate_ec_key(self, named_curve):
- """Generates an EC private key for the certificate. |named_curve| can be
- something like secp384r1"""
- assert self.key_path is None
- subprocess.check_call(
- ['openssl', 'ecparam', '-out', self.get_key_path(),
- '-name', named_curve, '-genkey'])
+ 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):
@@ -169,17 +211,30 @@ class Certificate(object):
return os.path.join(g_out_dir, '%s%s' % (self.path_id, suffix))
- def set_key_path(self, path):
- """Uses the key from the given path instead of generating a new one."""
- self.key_path = path
+ 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_output_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.get_key_path())
+ section.set_property('private_key', self.key.get_path())
- def get_key_path(self):
- if self.key_path is not None:
- return self.key_path
- return self.get_path('.key')
+ def get_key(self):
+ if self.key is None:
+ self.set_key_internal(generate_rsa_key(2048, path=self.get_path(".key")))
+ return self.key
def get_cert_path(self):
@@ -187,7 +242,7 @@ class Certificate(object):
def get_serial_path(self):
- return self.get_path('.serial')
+ return self.get_name_path('.serial')
def get_csr_path(self):
@@ -195,7 +250,7 @@ class Certificate(object):
def get_database_path(self):
- return self.get_path('.db')
+ return self.get_name_path('.db')
def get_config_path(self):
@@ -225,11 +280,9 @@ class Certificate(object):
# accessible. Note that self.issuer could be the same as self.
self.issuer.finalize()
- # Ensure the certificate has a key. Callers have the option to generate a
- # different type of key, but if that was not done default to a new 2048-bit
- # RSA key.
- if not os.path.isfile(self.get_key_path()):
- self.generate_rsa_key(2048)
+ # 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())
@@ -237,7 +290,7 @@ class Certificate(object):
# Create a CSR.
subprocess.check_call(
['openssl', 'req', '-new',
- '-key', self.get_key_path(),
+ '-key', self.key.get_path(),
'-out', self.get_csr_path(),
'-config', self.get_config_path()])
@@ -310,7 +363,6 @@ class Certificate(object):
section = self.config.get_section('root_ca')
section.set_property('certificate', self.get_cert_path())
- section.set_property('private_key', self.get_key_path())
section.set_property('new_certs_dir', g_out_dir)
section.set_property('serial', self.get_serial_path())
section.set_property('database', self.get_database_path())
@@ -358,13 +410,33 @@ class Certificate(object):
section.set_property('authorityInfoAccess', '@issuer_info')
-def data_to_pem(block_header, block_data):
- return '-----BEGIN %s-----\n%s\n-----END %s-----\n' % (block_header,
- base64.b64encode(block_data), block_header)
+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_test_file(description, chain, trusted_certs, utc_time, verify_result,
- out_pem=None):
+class TrustAnchor(object):
+ """Structure that represents a trust anchor."""
+
+ def __init__(self, cert, constrained=False):
+ self.cert = cert
+ self.constrained = constrained
+
+
+ def get_pem(self):
+ """Returns a PEM block string describing this trust anchor."""
+
+ cert_data = self.cert.get_cert_pem()
+ block_name = 'TRUST_ANCHOR_UNCONSTRAINED'
+ if self.constrained:
+ block_name = 'TRUST_ANCHOR_CONSTRAINED'
+
+ # Use a different block name in the .pem file, depending on the anchor type.
+ return cert_data.replace('CERTIFICATE', block_name)
+
+
+def write_test_file(description, chain, trust_anchor, utc_time, verify_result,
+ errors, out_pem=None):
"""Writes a test file that contains all the inputs necessary to run a
verification on a certificate chain"""
@@ -375,17 +447,14 @@ def write_test_file(description, chain, trusted_certs, utc_time, verify_result,
for cert in chain:
test_data += '\n' + cert.get_cert_pem()
- # Write the trust store.
- for cert in trusted_certs:
- cert_data = cert.get_cert_pem()
- # Use a different block type in the .pem file.
- cert_data = cert_data.replace('CERTIFICATE', 'TRUSTED_CERTIFICATE')
- test_data += '\n' + cert_data
-
- test_data += '\n' + data_to_pem('TIME', utc_time)
+ test_data += '\n' + trust_anchor.get_pem()
+ test_data += '\n' + text_data_to_pem('TIME', utc_time)
verify_result_string = 'SUCCESS' if verify_result else 'FAIL'
- test_data += '\n' + data_to_pem('VERIFY_RESULT', verify_result_string)
+ test_data += '\n' + text_data_to_pem('VERIFY_RESULT', verify_result_string)
+
+ if errors is not None:
+ test_data += '\n' + text_data_to_pem('ERRORS', errors)
write_string_to_file(test_data, out_pem if out_pem else g_out_pem)
@@ -426,7 +495,7 @@ def create_self_signed_root_certificate(name):
return Certificate(name, TYPE_CA, None)
-def create_intermediary_certificate(name, issuer):
+def create_intermediate_certificate(name, issuer):
return Certificate(name, TYPE_CA, issuer)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/constrained-non-self-signed-root.pem b/chromium/net/data/verify_certificate_chain_unittest/constrained-non-self-signed-root.pem
new file mode 100644
index 00000000000..b8f2d4e01e3
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/constrained-non-self-signed-root.pem
@@ -0,0 +1,283 @@
+[Created by: generate-constrained-non-self-signed-root.py]
+
+Certificate chain with 1 intermediate and a non-self-signed trust anchor.
+Verification should succeed, it doesn't matter that the root was not
+self-signed if it is designated as the trust anchor.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b3:aa:6c:0c:2e:35:34:f6:1f:5d:c3:8b:9e:fe:
+ f7:7e:5b:26:fd:2b:ba:20:83:92:3a:4e:02:18:7c:
+ 1d:49:c5:05:15:c1:fa:98:b3:5d:0c:e8:03:9b:60:
+ d4:e3:a6:3e:0c:ae:b3:c5:21:38:3b:a0:02:fd:80:
+ a6:05:47:29:d2:12:95:6b:41:7b:41:94:45:ce:bd:
+ 65:84:d4:5a:51:cc:81:2a:a4:03:8f:31:00:d5:15:
+ 06:13:54:07:87:99:d9:55:fa:23:a8:19:56:11:87:
+ 78:4d:62:15:55:4d:b1:5f:00:c3:ce:a1:f0:21:6f:
+ 97:01:ef:76:49:6d:21:6b:f8:50:12:e9:48:94:3e:
+ cd:01:d2:30:1f:2d:e2:25:f8:b5:ee:ad:a8:91:e9:
+ 0d:03:be:b4:11:84:1c:9f:9f:09:60:37:bf:52:c4:
+ ad:2c:12:6d:eb:2d:1f:e2:c5:64:a8:55:c3:01:e8:
+ 19:f8:be:96:07:e2:3b:32:7f:59:28:12:79:f2:fd:
+ e4:98:a7:f1:77:9f:28:13:1e:b7:2c:56:d9:af:8f:
+ a4:9c:ac:4e:7d:3a:3c:a0:a6:06:61:d2:9c:88:d0:
+ 4b:72:d4:f3:88:18:b5:53:90:ae:b2:80:dd:b4:90:
+ c4:e4:76:20:c3:ee:ed:ce:bb:44:d9:ad:39:b1:dd:
+ 27:cf
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 4C:67:B6:67:88:D3:B0:33:53:B8:A0:1F:0F:63:46:A3:28:35:A9:A3
+ X509v3 Authority Key Identifier:
+ keyid:9C:54:60:08:5E:37:A1:FA:4A:EA:A7:CB:AB:E1:74:51:84:5F:46:FD
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 26:13:cf:55:3b:59:ce:94:65:01:3e:96:fb:c5:62:d9:d8:0c:
+ 53:f2:23:12:f6:a1:a5:c7:30:f3:2b:f2:68:7d:ed:6a:c9:9d:
+ a5:21:b5:5d:1c:aa:4e:af:57:8c:3d:08:e7:72:d6:8c:20:9f:
+ 25:f5:cf:31:91:23:47:4e:cc:cc:db:9c:e3:f7:53:d4:46:8f:
+ ea:92:05:37:12:c8:4b:c8:e5:57:24:ed:86:93:0f:14:1b:ea:
+ 83:5c:87:c5:52:a4:bb:1c:48:80:4a:28:f6:ef:e6:6d:9a:0c:
+ 62:75:11:6d:87:bf:8e:79:14:ed:4a:3f:74:5c:5f:7d:f6:53:
+ f1:dc:94:9b:67:cb:ae:da:18:80:db:31:85:64:ee:b9:36:67:
+ 50:a8:26:55:0e:38:74:e3:b3:4f:19:10:b4:82:2b:90:18:34:
+ eb:89:47:3c:2a:fc:e5:06:01:99:fe:8c:56:6c:a1:5b:d6:5f:
+ 22:b5:00:c8:dd:fc:ae:43:5a:77:ee:17:1c:27:73:7f:71:a9:
+ e1:e1:0d:7c:81:31:b7:7d:8d:3f:3e:96:8a:2c:5f:bb:8d:7b:
+ ad:b3:91:3a:ce:68:f2:25:02:cf:ca:84:0b:91:4f:b3:f5:d3:
+ e2:34:b6:4a:d7:92:c4:f0:4d:d2:40:f9:46:b7:60:ff:84:95:
+ cd:da:73:73
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzqmwM
+LjU09h9dw4ue/vd+Wyb9K7ogg5I6TgIYfB1JxQUVwfqYs10M6AObYNTjpj4MrrPF
+ITg7oAL9gKYFRynSEpVrQXtBlEXOvWWE1FpRzIEqpAOPMQDVFQYTVAeHmdlV+iOo
+GVYRh3hNYhVVTbFfAMPOofAhb5cB73ZJbSFr+FAS6UiUPs0B0jAfLeIl+LXuraiR
+6Q0DvrQRhByfnwlgN79SxK0sEm3rLR/ixWSoVcMB6Bn4vpYH4jsyf1koEnny/eSY
+p/F3nygTHrcsVtmvj6ScrE59OjygpgZh0pyI0Ety1POIGLVTkK6ygN20kMTkdiDD
+7u3Ou0TZrTmx3SfPAgMBAAGjgekwgeYwHQYDVR0OBBYEFExntmeI07AzU7igHw9j
+RqMoNamjMB8GA1UdIwQYMBaAFJxUYAheN6H6Suqny6vhdFGEX0b9MD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAJhPPVTtZzpRlAT6W+8Vi
+2dgMU/IjEvahpccw8yvyaH3tasmdpSG1XRyqTq9XjD0I53LWjCCfJfXPMZEjR07M
+zNuc4/dT1EaP6pIFNxLIS8jlVyTthpMPFBvqg1yHxVKkuxxIgEoo9u/mbZoMYnUR
+bYe/jnkU7Uo/dFxfffZT8dyUm2fLrtoYgNsxhWTuuTZnUKgmVQ44dOOzTxkQtIIr
+kBg064lHPCr85QYBmf6MVmyhW9ZfIrUAyN38rkNad+4XHCdzf3Gp4eENfIExt32N
+Pz6Wiixfu417rbOROs5o8iUCz8qEC5FPs/XT4jS2SteSxPBN0kD5Rrdg/4SVzdpz
+cw==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c6:0a:10:7c:70:eb:74:84:70:54:78:38:0e:6b:
+ da:e4:e6:9c:3b:92:69:8c:5f:eb:ab:11:af:56:27:
+ 1d:59:94:21:91:c3:5c:2b:cd:67:75:95:5d:fc:d6:
+ 04:e6:65:0d:9b:4b:70:ce:e5:23:11:a8:a3:f5:61:
+ d4:5b:d0:99:b8:4b:44:51:3d:7a:ed:9d:5d:e7:82:
+ 09:25:23:60:12:16:0f:b9:9a:3d:9f:02:22:39:f3:
+ 02:85:b2:45:a6:f4:81:e7:2f:6a:f9:65:28:94:b4:
+ 61:b2:4b:04:6e:2d:dd:a9:75:3e:d4:78:16:8a:45:
+ 6f:3c:85:81:b2:f1:8d:3b:84:ff:19:bd:c5:4d:58:
+ d4:87:ec:dc:34:23:5c:e3:67:d8:26:c0:dc:ae:ad:
+ 27:34:8b:60:9d:47:bb:be:54:c1:4a:0d:56:91:c6:
+ 54:2d:07:51:d5:87:5d:e4:d5:b6:ee:1a:50:51:99:
+ c4:2d:37:2d:47:4a:3e:19:1c:4f:ba:14:2d:0b:b0:
+ e7:87:ab:d4:e4:ca:93:a7:77:13:6f:10:c6:df:dd:
+ f0:86:53:03:0d:b6:92:66:1d:bf:63:1c:84:f0:63:
+ cb:18:d3:f4:54:20:a8:e8:4c:94:21:7e:3f:b5:81:
+ 49:9f:bc:51:b9:eb:12:ab:6d:cb:03:37:d0:30:a8:
+ 1b:11
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 9C:54:60:08:5E:37:A1:FA:4A:EA:A7:CB:AB:E1:74:51:84:5F:46:FD
+ X509v3 Authority Key Identifier:
+ keyid:4E:4A:66:D2:28:27:6E:75:19:FA:97:E6:3D:38:18:C6:A6:56:68:69
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 5e:d4:51:bf:58:80:db:77:af:e6:7c:a7:03:ab:95:ae:e6:0f:
+ 26:64:63:b0:70:30:92:1c:f0:d8:7c:f8:93:13:14:e3:62:6e:
+ 45:ed:cf:dd:c0:4d:8d:b7:b7:2f:bc:29:2d:6e:c2:ed:d5:10:
+ e6:80:53:91:88:18:35:c5:88:63:69:95:c1:f2:bc:e6:5c:02:
+ 01:e7:e8:22:f4:3e:6d:91:09:82:64:12:86:80:b1:27:3c:9b:
+ ee:61:43:c2:1f:54:dc:31:9b:89:38:fe:3d:48:27:f0:fb:c6:
+ 44:58:c6:de:21:19:b1:e1:4a:70:e4:1b:aa:ea:ad:e9:d3:a8:
+ bd:23:9a:95:d8:06:3c:32:9d:21:28:7c:de:37:d7:47:a6:96:
+ a0:d1:98:04:19:f5:47:bc:19:f8:9e:b6:dc:4b:d5:39:c6:27:
+ 88:ab:9a:19:f1:f1:33:af:e0:62:36:f7:2e:5d:26:5c:70:55:
+ 5e:3c:df:20:12:42:54:64:e0:5e:5f:2e:ee:6a:85:a4:1e:15:
+ 52:0b:01:01:1b:70:19:fe:67:31:b7:6e:5e:4d:61:93:6b:3c:
+ c3:fd:c7:55:a8:f0:bc:81:5e:2b:38:84:ab:d8:b8:54:3c:a1:
+ 59:db:ae:70:2b:71:ca:f3:5f:f8:ce:d0:67:af:45:99:19:8c:
+ 25:9d:d1:e9
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxgoQfHDr
+dIRwVHg4Dmva5OacO5JpjF/rqxGvVicdWZQhkcNcK81ndZVd/NYE5mUNm0twzuUj
+Eaij9WHUW9CZuEtEUT167Z1d54IJJSNgEhYPuZo9nwIiOfMChbJFpvSB5y9q+WUo
+lLRhsksEbi3dqXU+1HgWikVvPIWBsvGNO4T/Gb3FTVjUh+zcNCNc42fYJsDcrq0n
+NItgnUe7vlTBSg1WkcZULQdR1Ydd5NW27hpQUZnELTctR0o+GRxPuhQtC7Dnh6vU
+5MqTp3cTbxDG393whlMDDbaSZh2/YxyE8GPLGNP0VCCo6EyUIX4/tYFJn7xRuesS
+q23LAzfQMKgbEQIDAQABo4HLMIHIMB0GA1UdDgQWBBScVGAIXjeh+krqp8ur4XRR
+hF9G/TAfBgNVHSMEGDAWgBROSmbSKCdudRn6l+Y9OBjGplZoaTA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AF7UUb9YgNt3r+Z8pwOrla7mDyZkY7BwMJIc8Nh8+JMTFONibkXtz93ATY23ty+8
+KS1uwu3VEOaAU5GIGDXFiGNplcHyvOZcAgHn6CL0Pm2RCYJkEoaAsSc8m+5hQ8If
+VNwxm4k4/j1IJ/D7xkRYxt4hGbHhSnDkG6rqrenTqL0jmpXYBjwynSEofN4310em
+lqDRmAQZ9Ue8GfiettxL1TnGJ4irmhnx8TOv4GI29y5dJlxwVV483yASQlRk4F5f
+Lu5qhaQeFVILAQEbcBn+ZzG3bl5NYZNrPMP9x1Wo8LyBXis4hKvYuFQ8oVnbrnAr
+ccrzX/jO0GevRZkZjCWd0ek=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=UberRoot
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:a5:1a:7b:1e:97:d2:f5:6c:17:83:73:76:62:4f:
+ 12:53:75:3d:4b:86:2d:42:77:e7:11:75:65:cd:43:
+ 69:5a:b3:80:ad:42:87:a0:8e:9e:cf:e5:9e:6a:2d:
+ 1f:3e:0a:9a:6e:2b:01:e9:aa:d5:bd:91:50:38:f8:
+ 16:04:79:d3:fe:69:1c:82:9d:e7:10:2c:19:31:8a:
+ 1b:8d:a7:ef:f2:4c:36:de:f6:2f:65:93:78:0a:77:
+ ba:1d:5b:b1:39:bf:55:71:05:43:fb:6c:d4:49:b2:
+ 35:93:85:c0:99:4e:3b:d2:4d:bf:19:4c:1b:55:b6:
+ ef:ca:40:b3:6e:6a:18:29:eb:78:fa:f5:7e:15:61:
+ 85:70:1d:1f:a4:cd:59:eb:86:c1:a5:c4:8b:74:22:
+ e1:5d:9b:80:d4:26:a1:a1:7d:40:4d:89:17:4f:ef:
+ ea:04:d0:d1:b8:7a:38:b1:a5:13:9a:08:64:4d:85:
+ 88:4e:8d:07:fc:55:0b:22:7e:b7:ab:85:28:b9:d9:
+ 71:c9:99:cb:fb:85:fb:cf:8a:2e:cd:98:90:bb:b1:
+ 17:5f:50:02:5e:23:9c:55:d7:f2:fa:76:47:d6:ee:
+ 12:44:9a:17:c4:67:83:9d:75:5f:20:b1:a8:70:c4:
+ 22:69:00:17:26:a8:9d:c5:88:1a:e5:29:bb:63:c8:
+ 02:f5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 4E:4A:66:D2:28:27:6E:75:19:FA:97:E6:3D:38:18:C6:A6:56:68:69
+ X509v3 Authority Key Identifier:
+ keyid:8F:01:DF:48:8B:1D:55:FA:61:CF:0A:EF:D6:89:C1:E7:69:7E:24:51
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/UberRoot.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/UberRoot.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ c8:bb:c7:40:ef:2b:d4:1d:61:92:65:48:61:99:5b:d4:5b:1d:
+ 8d:c6:ea:b8:d4:bf:1b:e9:ea:5a:f0:21:f3:95:b8:e7:cf:e7:
+ c3:8b:68:b2:14:53:fc:c8:07:4d:d8:fc:97:27:8d:0d:41:68:
+ 4c:5e:c8:ab:ee:e3:9c:72:d3:d5:5b:a4:3a:2b:e4:2f:e2:13:
+ c8:a5:8d:63:61:c9:f8:e1:99:3f:c4:22:36:0d:bb:88:28:85:
+ 99:23:ae:b9:0b:4e:50:7b:81:2d:28:da:9e:9e:7e:86:21:99:
+ ac:f1:a9:bc:1f:cf:6c:5f:90:91:b1:bf:76:b2:3a:5f:f3:e6:
+ 54:89:bf:db:1e:f5:3a:93:53:ec:80:75:7e:ea:81:e0:c1:8b:
+ 2d:89:f8:62:16:f0:96:ae:8e:be:d7:af:e6:fa:d4:54:b4:01:
+ bc:dd:f0:93:cc:89:b7:f2:06:81:2e:df:02:11:ac:22:21:44:
+ 77:de:22:aa:9f:2b:05:3a:4e:a9:b4:a2:15:50:13:03:b1:a1:
+ 1a:f4:de:c4:7b:2e:84:56:80:7c:98:db:82:af:a0:8e:79:a5:
+ b1:81:b7:0f:9b:60:78:5b:57:fc:eb:8e:74:91:e5:e3:58:c6:
+ b7:82:b2:88:d2:83:5f:b4:94:75:6b:97:8a:3f:88:40:ad:5d:
+ a1:18:da:7a
+-----BEGIN TRUST_ANCHOR_CONSTRAINED-----
+MIIDcTCCAlmgAwIBAgIBAjANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhVYmVy
+Um9vdDAeFw0xNTAxMDExMjAwMDBaFw0xNjAxMDExMjAwMDBaMA8xDTALBgNVBAMM
+BFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQClGnsel9L1bBeD
+c3ZiTxJTdT1Lhi1Cd+cRdWXNQ2las4CtQoegjp7P5Z5qLR8+CppuKwHpqtW9kVA4
++BYEedP+aRyCnecQLBkxihuNp+/yTDbe9i9lk3gKd7odW7E5v1VxBUP7bNRJsjWT
+hcCZTjvSTb8ZTBtVtu/KQLNuahgp63j69X4VYYVwHR+kzVnrhsGlxIt0IuFdm4DU
+JqGhfUBNiRdP7+oE0NG4ejixpROaCGRNhYhOjQf8VQsifrerhSi52XHJmcv7hfvP
+ii7NmJC7sRdfUAJeI5xV1/L6dkfW7hJEmhfEZ4OddV8gsahwxCJpABcmqJ3FiBrl
+KbtjyAL1AgMBAAGjgdMwgdAwHQYDVR0OBBYEFE5KZtIoJ251GfqX5j04GMamVmhp
+MB8GA1UdIwQYMBaAFI8B30iLHVX6Yc8K79aJwedpfiRRMDsGCCsGAQUFBwEBBC8w
+LTArBggrBgEFBQcwAoYfaHR0cDovL3VybC1mb3ItYWlhL1ViZXJSb290LmNlcjAw
+BgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vdXJsLWZvci1jcmwvVWJlclJvb3QuY3Js
+MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA
+A4IBAQDIu8dA7yvUHWGSZUhhmVvUWx2Nxuq41L8b6epa8CHzlbjnz+fDi2iyFFP8
+yAdN2PyXJ40NQWhMXsir7uOcctPVW6Q6K+Qv4hPIpY1jYcn44Zk/xCI2DbuIKIWZ
+I665C05Qe4EtKNqenn6GIZms8am8H89sX5CRsb92sjpf8+ZUib/bHvU6k1PsgHV+
+6oHgwYstifhiFvCWro6+16/m+tRUtAG83fCTzIm38gaBLt8CEawiIUR33iKqnysF
+Ok6ptKIVUBMDsaEa9N7Eey6EVoB8mNuCr6COeaWxgbcPm2B4W1f86450keXjWMa3
+grKI0oNftJR1a5eKP4hArV2hGNp6
+-----END TRUST_ANCHOR_CONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/constrained-root-basic-constraints-ca-false.pem b/chromium/net/data/verify_certificate_chain_unittest/constrained-root-basic-constraints-ca-false.pem
new file mode 100644
index 00000000000..f8842981b09
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/constrained-root-basic-constraints-ca-false.pem
@@ -0,0 +1,284 @@
+[Created by: generate-constrained-root-basic-constraints-ca-false.py]
+
+Certificate chain with 1 intermediate and a trust anchor. The trust anchor
+has a basic constraints extension that indicates it is NOT a CA. Verification
+is expected to succeed even though the trust anchor enforces constraints, since
+the CA part of basic constraints is not enforced.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b8:b6:4b:46:a5:2a:82:68:2c:9f:19:09:8f:0c:
+ c6:ad:af:bf:e1:8f:86:e5:2b:7b:b6:53:cd:bf:cf:
+ 57:f2:c9:19:55:2c:3e:d5:33:b6:5f:0c:d6:65:4b:
+ f0:37:49:28:32:68:c5:56:32:a1:8d:13:5f:2a:7e:
+ ff:b4:13:b4:69:07:df:82:04:f9:bf:9e:06:61:ad:
+ 4b:82:2c:12:3e:d6:37:ef:1f:be:4c:6e:16:5b:f1:
+ 02:ea:31:75:40:2b:f1:6d:2d:7b:fb:5c:43:7a:34:
+ 70:23:c5:dc:80:fa:76:4b:36:28:91:7c:0f:14:01:
+ 5b:66:51:89:54:79:3c:d5:c3:e3:4f:6a:a9:d6:ab:
+ ba:57:f9:6d:13:b3:cc:2c:7a:5f:87:06:62:9e:31:
+ 9b:e2:5c:5e:b7:70:e1:1a:dc:02:0a:23:cb:dc:28:
+ fb:85:03:b0:5b:a0:94:d8:4a:6a:8e:dc:02:2a:19:
+ c1:ea:32:9d:a2:9b:84:34:6c:79:90:d6:bf:9d:74:
+ 02:cd:21:a3:bf:57:46:db:4e:5a:76:3e:32:54:66:
+ 7e:2f:f1:4b:40:72:9d:bf:c3:fc:33:8b:6b:cc:a4:
+ ce:2a:dd:74:13:7b:e7:3d:31:26:ae:a8:88:83:ab:
+ 24:27:31:21:55:17:de:a9:d6:d4:ae:c1:6e:b0:ca:
+ e5:9f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ CB:79:A5:28:D4:40:7E:78:F4:F3:C5:7B:21:DA:CF:D8:4C:95:FC:EE
+ X509v3 Authority Key Identifier:
+ keyid:21:63:3C:E9:BA:5F:79:17:3D:28:91:51:B7:72:6E:26:3C:9E:9C:65
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 96:8e:91:69:58:40:6d:ef:8b:60:3f:35:57:0a:93:85:6d:e5:
+ a5:df:99:05:e4:b9:32:c6:e3:9b:e6:2e:8c:4c:b5:4d:c4:fa:
+ 40:cd:44:2c:f1:b3:bd:d2:24:9a:d7:cb:1b:64:46:b7:db:11:
+ a0:7f:49:5b:ec:fc:0e:d5:36:73:f7:60:48:82:11:be:92:1c:
+ 41:0f:96:85:ef:c3:e5:cf:3b:a6:2e:41:99:6c:77:6b:3b:74:
+ e3:a9:d0:35:9f:17:f8:7f:4d:a7:33:6c:ce:fa:a3:be:f4:0d:
+ fb:38:02:ab:10:d3:46:22:e6:ae:a6:62:5b:5f:48:98:cd:ba:
+ 4b:ef:1f:5c:3b:2a:2e:ef:48:76:8b:3d:05:d6:e4:25:2b:60:
+ 2d:a8:cd:64:98:95:73:22:62:d7:67:7f:35:93:2f:2f:cc:99:
+ ac:d2:07:1f:9d:ff:1f:e3:33:84:4f:ff:a6:b7:48:7a:fc:24:
+ c5:25:c1:22:b4:4e:f1:cd:10:10:0a:b8:9b:1d:9e:86:d9:9d:
+ 52:3c:af:04:76:b8:3b:98:83:6d:82:51:ca:b2:ff:15:e4:22:
+ 50:98:8f:fb:2c:bc:2e:77:8e:11:6b:5b:06:97:ff:da:ea:29:
+ 51:88:df:94:2f:7c:75:26:54:99:d9:0a:bc:bb:8d:a0:23:6a:
+ db:cc:85:4e
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4tktG
+pSqCaCyfGQmPDMatr7/hj4blK3u2U82/z1fyyRlVLD7VM7ZfDNZlS/A3SSgyaMVW
+MqGNE18qfv+0E7RpB9+CBPm/ngZhrUuCLBI+1jfvH75MbhZb8QLqMXVAK/FtLXv7
+XEN6NHAjxdyA+nZLNiiRfA8UAVtmUYlUeTzVw+NPaqnWq7pX+W0Ts8wsel+HBmKe
+MZviXF63cOEa3AIKI8vcKPuFA7BboJTYSmqO3AIqGcHqMp2im4Q0bHmQ1r+ddALN
+IaO/V0bbTlp2PjJUZn4v8UtAcp2/w/wzi2vMpM4q3XQTe+c9MSauqIiDqyQnMSFV
+F96p1tSuwW6wyuWfAgMBAAGjgekwgeYwHQYDVR0OBBYEFMt5pSjUQH549PPFeyHa
+z9hMlfzuMB8GA1UdIwQYMBaAFCFjPOm6X3kXPSiRUbdybiY8npxlMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAlo6RaVhAbe+LYD81VwqT
+hW3lpd+ZBeS5Msbjm+YujEy1TcT6QM1ELPGzvdIkmtfLG2RGt9sRoH9JW+z8DtU2
+c/dgSIIRvpIcQQ+Whe/D5c87pi5BmWx3azt046nQNZ8X+H9NpzNszvqjvvQN+zgC
+qxDTRiLmrqZiW19ImM26S+8fXDsqLu9Idos9BdbkJStgLajNZJiVcyJi12d/NZMv
+L8yZrNIHH53/H+MzhE//prdIevwkxSXBIrRO8c0QEAq4mx2ehtmdUjyvBHa4O5iD
+bYJRyrL/FeQiUJiP+yy8LneOEWtbBpf/2uopUYjflC98dSZUmdkKvLuNoCNq28yF
+Tg==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:a9:38:35:27:ba:37:72:ce:20:03:31:f3:dc:4e:
+ 96:e4:69:f4:d4:d1:77:8f:59:a8:93:d8:02:d3:a6:
+ 14:c1:d4:a2:8e:a2:69:0b:fa:28:1d:3c:71:f4:59:
+ de:c7:a0:80:09:7a:3e:b0:74:be:50:29:93:ce:73:
+ 66:67:64:30:5f:e0:8c:8a:05:2a:18:16:77:03:c6:
+ 09:26:b6:dd:c0:5d:d3:99:07:71:98:02:82:bd:ff:
+ d4:5a:f2:84:6c:9f:3c:90:d5:d7:fb:06:24:65:12:
+ fd:df:29:f1:2e:81:d0:b8:2f:ea:dd:0f:52:15:50:
+ 91:b4:10:6b:2d:88:d5:91:44:57:51:ff:1f:db:62:
+ 47:5d:41:9a:b1:3f:03:f6:fd:3b:79:e0:46:b0:69:
+ 01:ee:72:d9:48:22:6a:b7:59:2e:39:6f:1f:01:1b:
+ e0:b2:c4:a1:9e:b8:dc:c5:99:87:0f:84:d5:55:4d:
+ bb:0b:73:fc:85:62:a6:14:53:13:1d:d8:36:a1:96:
+ b8:7f:65:81:e6:04:20:97:e8:05:ca:c9:4e:55:9b:
+ eb:74:97:7d:cf:72:52:17:7b:ac:a2:10:0f:96:7d:
+ 0c:f3:d3:52:6d:d0:af:36:44:be:6f:18:d9:39:0c:
+ 75:b8:e0:9e:5c:38:ec:47:72:a3:61:cc:e1:e9:de:
+ a5:a9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 21:63:3C:E9:BA:5F:79:17:3D:28:91:51:B7:72:6E:26:3C:9E:9C:65
+ X509v3 Authority Key Identifier:
+ keyid:A4:4A:EF:8D:03:05:5A:85:D8:D5:43:64:B2:EE:06:D6:D1:75:36:8B
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ ad:e7:db:f0:f9:65:22:52:9d:80:63:50:03:43:15:e2:19:44:
+ 93:31:c8:7b:f3:8c:81:d4:72:84:5c:a3:b9:90:b3:97:78:c6:
+ 7c:c3:50:8c:29:e9:49:d6:f1:cc:6e:f0:20:a2:2c:ff:ab:52:
+ 15:04:90:73:b1:3f:7f:be:21:87:96:c4:31:87:ae:15:ca:33:
+ 4a:79:84:11:11:4f:2c:dd:12:36:b0:c4:03:dd:c6:a5:a4:d2:
+ 5b:71:23:40:56:4e:49:97:1f:cb:af:c3:93:69:69:a0:6d:cd:
+ ac:47:9a:65:d1:c0:2f:d8:6d:56:4e:a4:90:16:6c:8b:fb:38:
+ b7:b3:ac:52:d6:0a:17:21:8d:a6:6e:ff:f3:15:13:d4:3b:0d:
+ 74:77:4e:60:63:9c:10:6f:36:70:a6:a8:93:8a:88:ff:82:13:
+ 25:0a:ba:5e:e6:09:c9:bb:8b:3d:cb:e4:d3:c0:28:6e:c6:2d:
+ 21:82:d3:81:b1:28:41:dd:7a:aa:cd:be:66:1e:06:3a:99:cf:
+ 41:ed:02:81:0a:0e:98:a2:f4:03:4b:31:c1:d8:78:79:a0:fd:
+ 25:a1:30:09:1c:29:e5:38:3a:b3:f2:48:70:5f:82:b6:71:b7:
+ f4:cd:99:e6:62:f2:78:b7:8c:92:af:d6:ce:96:c8:0f:84:60:
+ 93:19:fa:21
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqTg1J7o3
+cs4gAzHz3E6W5Gn01NF3j1mok9gC06YUwdSijqJpC/ooHTxx9Fnex6CACXo+sHS+
+UCmTznNmZ2QwX+CMigUqGBZ3A8YJJrbdwF3TmQdxmAKCvf/UWvKEbJ88kNXX+wYk
+ZRL93ynxLoHQuC/q3Q9SFVCRtBBrLYjVkURXUf8f22JHXUGasT8D9v07eeBGsGkB
+7nLZSCJqt1kuOW8fARvgssShnrjcxZmHD4TVVU27C3P8hWKmFFMTHdg2oZa4f2WB
+5gQgl+gFyslOVZvrdJd9z3JSF3usohAPln0M89NSbdCvNkS+bxjZOQx1uOCeXDjs
+R3KjYczh6d6lqQIDAQABo4HLMIHIMB0GA1UdDgQWBBQhYzzpul95Fz0okVG3cm4m
+PJ6cZTAfBgNVHSMEGDAWgBSkSu+NAwVahdjVQ2Sy7gbW0XU2izA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AK3n2/D5ZSJSnYBjUANDFeIZRJMxyHvzjIHUcoRco7mQs5d4xnzDUIwp6UnW8cxu
+8CCiLP+rUhUEkHOxP3++IYeWxDGHrhXKM0p5hBERTyzdEjawxAPdxqWk0ltxI0BW
+TkmXH8uvw5NpaaBtzaxHmmXRwC/YbVZOpJAWbIv7OLezrFLWChchjaZu//MVE9Q7
+DXR3TmBjnBBvNnCmqJOKiP+CEyUKul7mCcm7iz3L5NPAKG7GLSGC04GxKEHdeqrN
+vmYeBjqZz0HtAoEKDpii9ANLMcHYeHmg/SWhMAkcKeU4OrPySHBfgrZxt/TNmeZi
+8ni3jJKv1s6WyA+EYJMZ+iE=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:e9:d3:1f:75:ed:64:d9:2b:d9:1c:3b:ab:db:86:
+ 88:7a:65:57:87:7c:b9:51:2f:57:7f:34:7d:73:5d:
+ 53:8f:a0:13:08:26:ec:46:0d:05:cb:91:36:4a:9b:
+ 13:65:76:9d:68:b9:30:6a:13:9e:b2:1b:95:e7:3e:
+ 11:fc:16:50:ff:6f:8e:bd:88:79:4d:9e:fa:74:20:
+ 2d:1c:f0:15:98:d7:de:f9:99:46:f3:f5:c2:17:08:
+ c2:c3:3b:e3:6e:1b:bf:c9:3f:db:c3:ff:a4:d2:ee:
+ c4:8e:91:e6:af:12:e7:5c:1c:73:af:df:0f:0f:05:
+ d8:f0:f6:21:95:5e:40:97:ee:5d:1b:df:a8:89:30:
+ f4:08:e6:e4:c6:ca:aa:58:fa:e6:8c:b4:2f:3e:56:
+ ea:9b:02:4f:bc:65:c5:a7:41:bf:8d:e2:34:dc:f3:
+ da:f3:23:36:07:32:62:96:5b:be:44:69:39:47:44:
+ 70:96:96:03:f1:d8:1b:e3:bd:32:bc:9e:3b:5a:4c:
+ 38:fa:75:d1:af:2c:30:d3:59:0b:87:43:85:b1:2e:
+ 43:15:97:13:89:8e:e7:15:c2:8b:39:be:5f:f1:59:
+ 57:45:b8:ac:e8:bd:4a:46:a6:50:5e:22:40:68:60:
+ 5a:77:81:2f:3d:be:03:13:3b:70:2c:a6:ad:eb:58:
+ c1:05
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ A4:4A:EF:8D:03:05:5A:85:D8:D5:43:64:B2:EE:06:D6:D1:75:36:8B
+ X509v3 Authority Key Identifier:
+ keyid:A4:4A:EF:8D:03:05:5A:85:D8:D5:43:64:B2:EE:06:D6:D1:75:36:8B
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ Signature Algorithm: sha256WithRSAEncryption
+ 26:9d:8a:78:1d:b6:59:cd:cc:23:10:2b:9b:2c:a1:b4:fc:53:
+ 1e:c5:57:d8:d8:05:f2:dc:a6:13:2e:4b:13:af:14:bf:fa:c0:
+ af:3e:96:24:4a:ed:38:0f:10:f0:90:a9:c4:0d:92:59:6d:c7:
+ 12:bf:17:e2:d7:1b:20:1c:74:ab:7a:50:38:52:cf:55:58:40:
+ f7:c4:ee:78:a4:c1:79:ab:50:0c:a7:90:86:09:b0:05:bd:2a:
+ ec:31:00:a5:83:43:95:45:27:06:c0:e7:49:a3:81:9e:90:56:
+ 97:29:fc:b0:f1:4d:75:68:04:93:a2:1b:8e:fd:52:e1:2d:b8:
+ 30:be:4e:3d:e9:2b:96:4e:38:a3:26:4b:fe:36:72:45:55:57:
+ f1:c9:98:a7:9d:17:e2:b6:05:c8:bb:a4:ed:5e:be:23:8b:60:
+ e0:c8:42:c6:29:5f:37:37:2c:86:7d:06:67:5e:67:44:19:7f:
+ 13:5d:d3:8a:1e:50:b7:1c:03:52:0d:ff:4e:3c:69:f6:2f:d1:
+ 70:37:47:63:fa:60:1f:34:a4:1f:d8:2f:ed:e0:0e:f2:68:f8:
+ e3:58:34:33:3b:af:8f:15:c8:fe:2e:73:17:60:a9:49:7e:7e:
+ 1a:0e:9a:a2:60:bf:09:8d:85:8c:a3:dc:77:5f:45:b4:f9:f0:
+ 6d:a0:29:2a
+-----BEGIN TRUST_ANCHOR_CONSTRAINED-----
+MIIDYjCCAkqgAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOnTH3XtZNkr2Rw7q9uG
+iHplV4d8uVEvV380fXNdU4+gEwgm7EYNBcuRNkqbE2V2nWi5MGoTnrIblec+EfwW
+UP9vjr2IeU2e+nQgLRzwFZjX3vmZRvP1whcIwsM7424bv8k/28P/pNLuxI6R5q8S
+51wcc6/fDw8F2PD2IZVeQJfuXRvfqIkw9Ajm5MbKqlj65oy0Lz5W6psCT7xlxadB
+v43iNNzz2vMjNgcyYpZbvkRpOUdEcJaWA/HYG+O9MryeO1pMOPp10a8sMNNZC4dD
+hbEuQxWXE4mO5xXCizm+X/FZV0W4rOi9SkamUF4iQGhgWneBLz2+AxM7cCymretY
+wQUCAwEAAaOByDCBxTAdBgNVHQ4EFgQUpErvjQMFWoXY1UNksu4G1tF1NoswHwYD
+VR0jBBgwFoAUpErvjQMFWoXY1UNksu4G1tF1NoswNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQAmnYp4HbZZzcwj
+ECubLKG0/FMexVfY2AXy3KYTLksTrxS/+sCvPpYkSu04DxDwkKnEDZJZbccSvxfi
+1xsgHHSrelA4Us9VWED3xO54pMF5q1AMp5CGCbAFvSrsMQClg0OVRScGwOdJo4Ge
+kFaXKfyw8U11aASTohuO/VLhLbgwvk496SuWTjijJkv+NnJFVVfxyZinnRfitgXI
+u6TtXr4ji2DgyELGKV83NyyGfQZnXmdEGX8TXdOKHlC3HANSDf9OPGn2L9FwN0dj
++mAfNKQf2C/t4A7yaPjjWDQzO6+PFcj+LnMXYKlJfn4aDpqiYL8JjYWMo9x3X0W0
++fBtoCkq
+-----END TRUST_ANCHOR_CONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/constrained-root-lacks-basic-constraints.pem b/chromium/net/data/verify_certificate_chain_unittest/constrained-root-lacks-basic-constraints.pem
new file mode 100644
index 00000000000..307b9f235db
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/constrained-root-lacks-basic-constraints.pem
@@ -0,0 +1,280 @@
+[Created by: generate-constrained-root-lacks-basic-constraints.py]
+
+Certificate chain with 1 intermediate and a trust anchor. The trust anchor
+lacks the basic constraints extension, and is loaded with anchor constraints.
+This is not a problem and verification should succeed.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ad:75:ea:d9:63:a8:36:b6:47:9e:1f:f4:c4:38:
+ b8:81:a1:cb:46:09:41:00:e8:12:9e:fd:c1:f8:92:
+ cc:cb:92:90:72:e3:8c:74:20:9a:b2:d7:17:2a:c5:
+ 91:d7:2f:99:64:ad:96:52:16:bc:cd:f0:7a:5d:c8:
+ 04:90:f9:28:ec:05:40:4a:ca:29:33:9f:6c:98:5b:
+ da:9d:be:6a:a5:2d:82:a5:78:2e:b9:a9:20:77:c0:
+ 53:3c:63:19:af:ca:1c:20:da:b6:69:bc:0b:ba:b5:
+ f0:a0:92:e7:f5:34:af:a2:41:32:86:6d:67:03:5e:
+ d5:e6:68:d0:e5:8d:54:89:5d:39:66:ae:af:f2:2f:
+ 38:e2:f6:64:a5:7c:84:fe:2b:87:73:1b:76:29:c8:
+ d9:06:a8:bf:c7:c9:90:a2:7a:ab:36:b5:96:b2:e4:
+ 1c:68:3a:27:d6:80:e8:f6:cd:61:cf:c5:a6:f8:60:
+ bf:bc:2c:8c:aa:fb:ae:a4:12:b7:3f:a5:db:cc:25:
+ f7:7e:fe:01:bf:0e:2d:26:ef:b4:da:d0:e7:31:53:
+ 88:e6:3f:bc:85:f9:e7:9d:40:a9:70:8a:73:8d:f7:
+ b3:dd:7d:67:52:a5:98:7a:22:2b:e8:15:3f:82:4e:
+ 10:27:ed:92:f8:fa:41:89:6b:26:e9:dd:93:4a:74:
+ d3:a9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 92:9A:80:3A:5C:7F:B9:45:6C:C1:79:03:FC:BE:1D:F9:00:A5:ED:9E
+ X509v3 Authority Key Identifier:
+ keyid:A4:79:C2:53:F1:7B:AF:B0:97:61:6B:AE:EA:24:7A:98:C7:D7:41:18
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 5e:39:9f:dc:2f:71:14:dc:68:84:af:52:a3:3d:07:68:3f:cc:
+ db:fa:4e:b9:d8:7e:7a:a0:7c:9a:75:81:55:a4:c2:45:4f:90:
+ 46:d4:8d:08:ca:3a:fa:64:04:b0:1c:42:e4:64:ad:4b:d3:c3:
+ 3c:57:b5:47:76:fd:7e:e4:a5:6c:22:71:4b:1c:d2:0d:23:8c:
+ b1:9a:20:18:f5:78:49:fa:06:e6:47:e5:4a:43:88:b4:8e:b8:
+ d9:23:b8:75:97:d4:cd:db:58:dd:7a:21:c6:65:47:fa:2f:f5:
+ c5:c7:c3:43:7f:e2:61:ff:55:e5:0e:1e:f7:2b:a7:1a:45:16:
+ 16:e6:bb:4b:f5:f5:2d:fd:01:f2:e3:41:b9:d1:dc:bb:52:97:
+ c5:90:cf:d1:57:70:46:46:ad:0f:e3:81:cc:18:e6:ce:05:fd:
+ 29:09:b2:eb:91:18:79:38:92:23:33:9b:0f:53:b1:fe:5d:81:
+ 65:b9:49:c9:64:6a:75:c4:e6:fe:8b:fc:3f:06:22:ab:e0:0a:
+ 18:d9:d5:5e:a6:d5:bd:2d:9f:b4:48:b5:ba:42:54:c7:75:be:
+ 8d:95:8b:ef:27:68:2a:a9:82:14:e4:9f:2c:ec:fd:27:cb:56:
+ c3:26:ec:10:96:85:f5:9b:42:b6:9c:99:ee:48:4a:3e:1b:81:
+ 9c:5f:7d:ad
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtderZ
+Y6g2tkeeH/TEOLiBoctGCUEA6BKe/cH4kszLkpBy44x0IJqy1xcqxZHXL5lkrZZS
+FrzN8HpdyASQ+SjsBUBKyikzn2yYW9qdvmqlLYKleC65qSB3wFM8Yxmvyhwg2rZp
+vAu6tfCgkuf1NK+iQTKGbWcDXtXmaNDljVSJXTlmrq/yLzji9mSlfIT+K4dzG3Yp
+yNkGqL/HyZCieqs2tZay5BxoOifWgOj2zWHPxab4YL+8LIyq+66kErc/pdvMJfd+
+/gG/Di0m77Ta0OcxU4jmP7yF+eedQKlwinON97PdfWdSpZh6IivoFT+CThAn7ZL4
++kGJaybp3ZNKdNOpAgMBAAGjgekwgeYwHQYDVR0OBBYEFJKagDpcf7lFbMF5A/y+
+HfkApe2eMB8GA1UdIwQYMBaAFKR5wlPxe6+wl2FrruokepjH10EYMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAXjmf3C9xFNxohK9Soz0H
+aD/M2/pOudh+eqB8mnWBVaTCRU+QRtSNCMo6+mQEsBxC5GStS9PDPFe1R3b9fuSl
+bCJxSxzSDSOMsZogGPV4SfoG5kflSkOItI642SO4dZfUzdtY3XohxmVH+i/1xcfD
+Q3/iYf9V5Q4e9yunGkUWFua7S/X1Lf0B8uNBudHcu1KXxZDP0VdwRkatD+OBzBjm
+zgX9KQmy65EYeTiSIzObD1Ox/l2BZblJyWRqdcTm/ov8PwYiq+AKGNnVXqbVvS2f
+tEi1ukJUx3W+jZWL7ydoKqmCFOSfLOz9J8tWwybsEJaF9ZtCtpyZ7khKPhuBnF99
+rQ==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:9b:ae:24:f7:35:a1:99:8f:a3:2e:f8:62:c1:ba:
+ f3:f3:92:a8:18:1e:57:b1:40:17:0a:3a:3b:67:64:
+ 7d:7c:97:98:ce:b0:e4:4b:aa:98:5e:66:4f:d6:4a:
+ 83:2d:c2:db:ac:4e:d0:83:3c:07:0a:f1:51:3f:7d:
+ 8f:5f:1d:48:14:e1:39:98:bf:c9:44:f6:a0:72:6c:
+ 1d:1c:13:91:cd:90:e2:19:88:80:59:2f:13:62:ac:
+ 9b:d0:19:53:a8:fe:f3:43:a7:94:fb:8c:df:98:10:
+ 48:6c:4b:20:c5:70:21:27:43:02:fe:15:ed:37:bf:
+ ee:71:d0:7d:69:f6:94:82:8e:83:a5:f8:b2:31:47:
+ bf:af:5c:94:d8:d8:a7:f8:bd:a2:fa:89:62:61:43:
+ 9e:46:10:e9:32:73:9c:32:bd:b9:a2:fe:35:96:df:
+ 10:b5:a6:8f:af:ed:4b:e0:4b:22:00:7f:e8:78:bf:
+ e9:0f:2d:26:80:d2:96:3a:0a:2e:02:b9:f7:49:57:
+ d6:7e:df:e4:97:dd:50:69:c7:49:f2:b2:74:94:1e:
+ ea:f9:7b:61:45:36:3b:7d:29:6b:09:de:ac:58:19:
+ 14:58:2c:83:b8:99:08:ba:be:78:ba:e8:f1:bb:f1:
+ 09:32:44:18:fb:72:4e:41:1c:6b:43:16:a2:73:6a:
+ 63:65
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ A4:79:C2:53:F1:7B:AF:B0:97:61:6B:AE:EA:24:7A:98:C7:D7:41:18
+ X509v3 Authority Key Identifier:
+ keyid:75:7D:62:57:BC:81:26:58:67:4D:49:F8:04:11:12:62:63:3C:3C:DC
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 93:d8:9b:e5:69:16:43:e6:5b:3b:c0:70:44:ec:1d:7d:9e:4f:
+ 28:16:99:b5:70:6f:5a:f6:f3:90:1f:e9:3c:eb:8f:bb:3b:28:
+ d0:e1:3f:60:6d:81:de:01:77:71:88:54:44:41:16:73:48:3c:
+ f6:5c:7d:6b:6d:81:e4:35:05:f6:4c:91:cb:a3:bf:06:d3:b2:
+ 33:39:06:07:4f:2d:99:ff:34:85:6b:75:02:18:5f:b1:9e:5d:
+ a7:a0:78:b9:26:aa:1e:87:51:37:3f:47:af:56:07:04:95:01:
+ cf:40:39:0a:ce:01:7b:e0:34:dc:14:e3:06:57:d8:93:0c:6c:
+ 90:51:92:51:6e:b8:f7:ff:62:81:e3:73:f1:34:5f:a0:19:7c:
+ 39:d7:d1:81:10:5a:90:52:e1:32:c7:3a:66:69:c5:5b:d7:54:
+ 15:70:d0:9b:42:bd:70:74:37:2b:a2:e7:ee:d3:20:96:3a:32:
+ ee:53:21:f0:f6:4b:c8:fb:a7:e1:ce:9d:72:cf:d0:e2:7c:e4:
+ 13:20:66:62:8d:b6:b9:9d:56:4b:c8:cc:e9:00:b6:c7:f7:e4:
+ dc:ed:2c:25:af:32:05:98:ef:56:de:7a:07:ff:eb:62:c1:7b:
+ 0b:56:95:ee:90:55:d6:6f:c9:8d:8f:15:dd:d3:65:c1:c7:8c:
+ 94:f9:82:5d
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm64k9zWh
+mY+jLvhiwbrz85KoGB5XsUAXCjo7Z2R9fJeYzrDkS6qYXmZP1kqDLcLbrE7QgzwH
+CvFRP32PXx1IFOE5mL/JRPagcmwdHBORzZDiGYiAWS8TYqyb0BlTqP7zQ6eU+4zf
+mBBIbEsgxXAhJ0MC/hXtN7/ucdB9afaUgo6DpfiyMUe/r1yU2Nin+L2i+oliYUOe
+RhDpMnOcMr25ov41lt8QtaaPr+1L4EsiAH/oeL/pDy0mgNKWOgouArn3SVfWft/k
+l91QacdJ8rJ0lB7q+XthRTY7fSlrCd6sWBkUWCyDuJkIur54uujxu/EJMkQY+3JO
+QRxrQxaic2pjZQIDAQABo4HLMIHIMB0GA1UdDgQWBBSkecJT8XuvsJdha67qJHqY
+x9dBGDAfBgNVHSMEGDAWgBR1fWJXvIEmWGdNSfgEERJiYzw83DA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AJPYm+VpFkPmWzvAcETsHX2eTygWmbVwb1r285Af6Tzrj7s7KNDhP2Btgd4Bd3GI
+VERBFnNIPPZcfWttgeQ1BfZMkcujvwbTsjM5BgdPLZn/NIVrdQIYX7GeXaegeLkm
+qh6HUTc/R69WBwSVAc9AOQrOAXvgNNwU4wZX2JMMbJBRklFuuPf/YoHjc/E0X6AZ
+fDnX0YEQWpBS4TLHOmZpxVvXVBVw0JtCvXB0Nyui5+7TIJY6Mu5TIfD2S8j7p+HO
+nXLP0OJ85BMgZmKNtrmdVkvIzOkAtsf35NztLCWvMgWY71beegf/62LBewtWle6Q
+VdZvyY2PFd3TZcHHjJT5gl0=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d6:d2:49:ce:36:d3:12:76:22:3f:67:89:7e:64:
+ 6e:09:f4:eb:b8:d7:66:3e:92:18:f2:2b:2c:4e:4a:
+ ca:77:97:83:cc:79:38:d2:50:ea:cf:7e:cf:dc:fa:
+ 83:05:61:d1:70:8f:e3:32:85:39:52:57:0b:77:62:
+ a0:63:ce:69:79:d0:a5:2c:95:06:92:38:f1:12:41:
+ 4b:5d:87:1e:8e:c5:40:28:36:16:c6:bd:fc:1f:ca:
+ 07:73:d5:1d:c5:5d:46:56:03:c7:f6:67:fb:91:ab:
+ 43:fb:53:48:a4:6f:75:e7:0b:10:f1:3d:aa:14:42:
+ 32:0b:b1:fc:10:81:d0:18:1b:1b:bd:d1:fd:e9:0d:
+ 53:64:3e:8f:3e:df:f0:07:2e:b8:b2:23:74:ea:9b:
+ 23:7c:15:42:e5:53:1a:0c:80:1e:49:dd:4e:fa:e4:
+ 50:a8:e2:74:3f:09:4f:bc:1c:71:7d:72:fe:7a:15:
+ ac:2e:0b:9b:8c:41:2b:ce:32:a4:f5:40:71:6b:e8:
+ 2c:93:a9:41:03:53:95:a0:4a:68:2d:f0:b6:1e:01:
+ da:7d:34:47:3d:d5:fb:ef:63:9a:72:df:e8:14:08:
+ 1a:29:29:aa:c3:ff:37:f4:ee:37:a4:45:da:d1:2c:
+ 94:1c:f3:df:62:41:f2:d0:00:0e:2c:06:88:12:71:
+ 8d:7f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 75:7D:62:57:BC:81:26:58:67:4D:49:F8:04:11:12:62:63:3C:3C:DC
+ X509v3 Authority Key Identifier:
+ keyid:75:7D:62:57:BC:81:26:58:67:4D:49:F8:04:11:12:62:63:3C:3C:DC
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ 52:16:ce:5c:55:aa:c3:76:80:5a:60:ee:8a:85:f5:9f:64:ca:
+ 6d:b9:66:53:73:a4:92:47:a9:d5:8e:b5:90:b2:a9:62:69:32:
+ e3:2c:f5:28:e6:d3:6c:d9:94:af:83:11:04:30:95:48:e2:9e:
+ 2d:bf:67:63:95:97:32:99:28:b7:87:3d:dc:97:41:08:72:f7:
+ 89:6a:94:bb:fe:62:cd:08:f6:d6:0b:86:60:5b:d7:4d:eb:df:
+ 40:70:d9:bd:cb:e0:24:b8:ee:62:5a:7f:58:d3:3d:11:53:63:
+ 34:aa:af:59:6b:86:30:ab:fb:55:40:cc:e3:65:0e:d6:36:b4:
+ dc:d1:db:a4:bc:1c:7a:51:cf:8a:7d:41:0a:e6:3a:16:c9:43:
+ e6:9e:41:31:f3:4f:81:c1:24:e8:fb:c5:db:87:c8:01:f5:b8:
+ 60:ed:2a:0e:fc:31:59:26:63:fb:60:26:8f:52:0c:7c:19:b7:
+ 29:18:c9:12:eb:80:6c:aa:25:46:41:92:1a:3a:e1:df:9e:94:
+ 1f:92:01:90:b0:92:2c:e0:dd:31:81:a2:c0:ae:05:ae:85:c2:
+ ee:ce:63:2c:c8:3f:41:f9:06:8b:66:56:05:e7:58:7d:3f:d0:
+ ed:05:25:ea:1e:d0:69:24:f0:e3:dd:0a:d8:2e:ba:fe:d9:1a:
+ ba:39:2b:7d
+-----BEGIN TRUST_ANCHOR_CONSTRAINED-----
+MIIDVDCCAjygAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANbSSc420xJ2Ij9niX5k
+bgn067jXZj6SGPIrLE5KyneXg8x5ONJQ6s9+z9z6gwVh0XCP4zKFOVJXC3dioGPO
+aXnQpSyVBpI48RJBS12HHo7FQCg2Fsa9/B/KB3PVHcVdRlYDx/Zn+5GrQ/tTSKRv
+decLEPE9qhRCMgux/BCB0BgbG73R/ekNU2Q+jz7f8AcuuLIjdOqbI3wVQuVTGgyA
+HkndTvrkUKjidD8JT7wccX1y/noVrC4Lm4xBK84ypPVAcWvoLJOpQQNTlaBKaC3w
+th4B2n00Rz3V++9jmnLf6BQIGikpqsP/N/TuN6RF2tEslBzz32JB8tAADiwGiBJx
+jX8CAwEAAaOBujCBtzAdBgNVHQ4EFgQUdX1iV7yBJlhnTUn4BBESYmM8PNwwHwYD
+VR0jBBgwFoAUdX1iV7yBJlhnTUn4BBESYmM8PNwwNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAUhbOXFWqw3aAWmDuioX1n2TKbblmU3Ok
+kkep1Y61kLKpYmky4yz1KObTbNmUr4MRBDCVSOKeLb9nY5WXMpkot4c93JdBCHL3
+iWqUu/5izQj21guGYFvXTevfQHDZvcvgJLjuYlp/WNM9EVNjNKqvWWuGMKv7VUDM
+42UO1ja03NHbpLwcelHPin1BCuY6FslD5p5BMfNPgcEk6PvF24fIAfW4YO0qDvwx
+WSZj+2Amj1IMfBm3KRjJEuuAbKolRkGSGjrh356UH5IBkLCSLODdMYGiwK4FroXC
+7s5jLMg/QfkGi2ZWBedYfT/Q7QUl6h7QaSTw490K2C66/tkaujkrfQ==
+-----END TRUST_ANCHOR_CONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/expired-constrained-root.pem b/chromium/net/data/verify_certificate_chain_unittest/expired-constrained-root.pem
new file mode 100644
index 00000000000..190fb56253a
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/expired-constrained-root.pem
@@ -0,0 +1,284 @@
+[Created by: generate-expired-constrained-root.py]
+
+Certificate chain with 1 intermediate, where the root certificate is expired
+(violates validity.notAfter). Verification is expected to succeed even though
+the trust anchor is initialized with anchor constraints, since validity is
+not enforced.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:a8:bc:a9:2c:1c:80:81:33:16:83:62:e9:f7:0a:
+ 0d:5a:8b:86:da:a8:45:2f:04:1c:18:c0:d6:e5:f7:
+ 33:f3:76:86:eb:a3:07:6b:83:e1:75:e5:da:6d:1c:
+ ee:99:a1:d7:38:bb:29:9a:7d:8f:54:c6:d4:0e:88:
+ dd:b7:59:b2:a8:45:c3:c8:82:42:ca:8c:e5:21:f6:
+ 94:b0:8f:59:41:64:0c:31:a2:93:f9:2a:38:fe:d8:
+ f5:e1:2e:b6:6c:f8:51:3f:9b:85:53:48:4e:34:30:
+ f1:cc:2b:c5:32:6d:ce:85:ed:69:d0:a3:53:3e:8c:
+ f7:4e:b1:d7:a6:ea:18:08:c6:23:d2:9e:13:e0:a6:
+ 50:e7:ea:da:f8:a0:d0:0f:ef:54:9b:fe:8c:3f:a1:
+ ea:c8:13:1b:84:f6:44:c1:a9:7a:69:ef:34:99:41:
+ ec:a9:1c:b0:9b:39:ae:98:4c:fc:68:2d:ba:96:68:
+ d5:b7:cf:2c:f0:2f:35:8a:0f:73:7c:8a:a0:e1:7a:
+ 0a:e4:3d:d0:05:e2:d9:d1:bd:30:d2:69:82:ba:31:
+ b4:c7:9a:29:d5:aa:97:36:e5:2a:92:85:fa:a9:87:
+ 00:ef:5b:ec:db:5e:82:2b:78:dd:89:de:99:ff:d8:
+ 35:17:eb:bc:57:c1:ae:11:52:63:ef:23:54:09:18:
+ f9:7f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 27:5D:22:BE:A2:20:5F:DC:69:8D:8A:6F:5B:CC:EF:D1:2A:AE:57:5B
+ X509v3 Authority Key Identifier:
+ keyid:9F:6B:C0:D8:24:51:E0:D7:89:F4:E0:74:B7:0D:D6:FF:8B:AF:58:04
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 1d:e0:a8:55:02:9d:d1:70:c6:ca:d2:82:75:35:ce:14:88:18:
+ 65:5d:12:42:b2:80:8d:ae:c1:24:fe:e2:c8:ca:b0:51:d0:39:
+ 24:e2:82:c1:96:bb:38:d1:54:dc:c0:51:dd:96:c0:d7:45:76:
+ cf:5c:37:fc:53:96:b0:c8:84:99:f9:4a:ad:03:98:1e:44:86:
+ 81:36:e1:4b:3a:3d:bc:f0:b5:58:4d:83:3a:30:56:45:e0:89:
+ 67:f6:61:cb:18:60:e9:53:42:a2:92:0b:dc:8f:6e:59:b2:9a:
+ bc:36:61:11:f2:90:17:72:5f:a8:e2:2f:43:22:e2:b0:7c:00:
+ 69:64:e2:3f:69:15:32:56:1a:58:c3:b3:61:ec:37:a7:58:e3:
+ df:e2:e2:f0:04:5e:37:f5:07:7d:52:aa:21:32:35:d2:18:5a:
+ b8:17:ef:7a:cc:de:10:10:2b:ae:73:a7:d8:38:a5:32:58:65:
+ 6c:9c:8e:e6:c9:93:e9:e0:54:bf:8b:01:cf:ee:a0:b6:dc:68:
+ 26:af:fe:39:48:8b:aa:37:37:ca:9c:28:97:0a:60:f6:53:dd:
+ ff:81:34:c1:68:2f:05:84:86:9e:7e:89:cd:21:a5:66:85:63:
+ 33:fb:1d:e6:70:88:56:f6:c2:34:60:0b:c3:f4:49:2a:c5:81:
+ 82:72:da:1a
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCovKks
+HICBMxaDYun3Cg1ai4baqEUvBBwYwNbl9zPzdobrowdrg+F15dptHO6Zodc4uyma
+fY9UxtQOiN23WbKoRcPIgkLKjOUh9pSwj1lBZAwxopP5Kjj+2PXhLrZs+FE/m4VT
+SE40MPHMK8Uybc6F7WnQo1M+jPdOsdem6hgIxiPSnhPgplDn6tr4oNAP71Sb/ow/
+oerIExuE9kTBqXpp7zSZQeypHLCbOa6YTPxoLbqWaNW3zyzwLzWKD3N8iqDhegrk
+PdAF4tnRvTDSaYK6MbTHminVqpc25SqShfqphwDvW+zbXoIreN2J3pn/2DUX67xX
+wa4RUmPvI1QJGPl/AgMBAAGjgekwgeYwHQYDVR0OBBYEFCddIr6iIF/caY2Kb1vM
+79EqrldbMB8GA1UdIwQYMBaAFJ9rwNgkUeDXifTgdLcN1v+Lr1gEMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAHeCoVQKd0XDGytKCdTXO
+FIgYZV0SQrKAja7BJP7iyMqwUdA5JOKCwZa7ONFU3MBR3ZbA10V2z1w3/FOWsMiE
+mflKrQOYHkSGgTbhSzo9vPC1WE2DOjBWReCJZ/Zhyxhg6VNCopIL3I9uWbKavDZh
+EfKQF3JfqOIvQyLisHwAaWTiP2kVMlYaWMOzYew3p1jj3+Li8AReN/UHfVKqITI1
+0hhauBfveszeEBArrnOn2DilMlhlbJyO5smT6eBUv4sBz+6gttxoJq/+OUiLqjc3
+ypwolwpg9lPd/4E0wWgvBYSGnn6JzSGlZoVjM/sd5nCIVvbCNGALw/RJKsWBgnLa
+Gg==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ae:5d:2a:68:be:2b:83:82:45:26:41:fc:7d:0a:
+ 0a:91:4c:d4:b6:83:35:d5:ba:81:07:57:ce:9b:2c:
+ 28:b0:e9:34:e3:60:f3:93:71:b2:a1:a7:57:9a:a4:
+ fb:5f:2f:22:c8:71:37:0a:22:de:b9:3d:d1:19:89:
+ 06:3f:cd:bd:50:8d:57:4b:86:ca:2e:2c:5a:57:dd:
+ 0d:2d:3b:83:31:d2:3a:ca:92:a1:a6:a5:79:3f:94:
+ a6:b3:b6:d0:64:31:ad:3e:28:cf:9c:6d:da:f4:df:
+ 46:55:4b:89:ce:38:b1:dc:33:1d:05:56:ad:c0:75:
+ c2:21:0e:29:f5:10:52:85:a9:dd:cd:b1:cb:b3:74:
+ d7:d6:36:13:42:8b:d1:bc:71:8a:b9:65:64:b9:b4:
+ 84:b7:49:6d:f7:95:f5:48:d9:0c:5f:84:b7:84:ab:
+ 4c:4c:78:ed:b6:70:7b:f6:0c:3d:74:00:4a:e7:68:
+ fe:c2:00:f9:2e:dc:10:e7:4e:6e:87:6f:db:c7:cb:
+ 06:53:2a:44:53:2f:84:f2:d0:2d:21:fc:60:00:69:
+ ba:fd:52:a0:86:84:c4:7e:88:7f:35:ab:41:45:38:
+ a7:c2:3f:d2:0f:20:26:3e:a4:8c:35:10:d3:93:52:
+ 70:18:44:25:ef:89:ea:f3:10:a1:ce:33:69:88:11:
+ d1:09
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 9F:6B:C0:D8:24:51:E0:D7:89:F4:E0:74:B7:0D:D6:FF:8B:AF:58:04
+ X509v3 Authority Key Identifier:
+ keyid:A8:0C:3D:AD:82:26:A9:EB:AF:61:CC:3D:E0:68:1D:82:DE:DB:D1:FD
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 69:1c:29:c5:7c:e3:18:58:86:0c:88:41:20:23:9d:75:07:22:
+ 4b:89:1d:6a:08:15:cf:85:c2:8d:f4:17:37:9e:a0:7e:67:b9:
+ 0e:95:80:b1:a8:8f:06:2d:5e:9d:67:5c:d3:a7:47:74:d3:f7:
+ 00:fb:84:75:99:d4:b9:07:ba:3b:63:2c:d9:57:04:48:35:f4:
+ 20:91:39:55:ad:86:27:4e:ba:22:17:85:9a:dd:e4:4f:dd:dd:
+ d4:d0:0a:5b:43:6c:2e:d1:4f:f8:50:32:64:a2:15:46:bb:82:
+ ef:d1:ff:17:2a:dd:13:50:81:7e:1c:5b:6e:50:7b:8c:72:03:
+ eb:58:9a:fd:e8:e6:f1:d7:c5:59:ff:18:2a:95:64:c0:53:84:
+ 0f:c1:1c:66:73:24:29:81:ae:0d:b7:b1:fc:44:2d:fb:02:89:
+ 70:97:c0:ed:91:6f:9b:57:7b:40:38:29:8c:fa:87:52:f8:db:
+ 8a:3b:1c:a2:a3:c1:08:8b:cf:9a:6e:dc:a8:b3:96:5e:31:05:
+ af:5c:1c:21:8e:d3:fe:18:17:af:a9:77:92:6f:46:93:36:d2:
+ e1:4f:a2:d9:e4:5d:bf:61:ad:db:c4:87:61:79:c3:bd:c3:e1:
+ 5b:d7:76:03:e3:fe:4a:75:a0:84:2b:ea:82:c1:d5:2c:6f:e7:
+ 55:46:1f:36
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArl0qaL4r
+g4JFJkH8fQoKkUzUtoM11bqBB1fOmywosOk042Dzk3GyoadXmqT7Xy8iyHE3CiLe
+uT3RGYkGP829UI1XS4bKLixaV90NLTuDMdI6ypKhpqV5P5Sms7bQZDGtPijPnG3a
+9N9GVUuJzjix3DMdBVatwHXCIQ4p9RBShandzbHLs3TX1jYTQovRvHGKuWVkubSE
+t0lt95X1SNkMX4S3hKtMTHjttnB79gw9dABK52j+wgD5LtwQ505uh2/bx8sGUypE
+Uy+E8tAtIfxgAGm6/VKghoTEfoh/NatBRTinwj/SDyAmPqSMNRDTk1JwGEQl74nq
+8xChzjNpiBHRCQIDAQABo4HLMIHIMB0GA1UdDgQWBBSfa8DYJFHg14n04HS3Ddb/
+i69YBDAfBgNVHSMEGDAWgBSoDD2tgiap669hzD3gaB2C3tvR/TA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AGkcKcV84xhYhgyIQSAjnXUHIkuJHWoIFc+Fwo30FzeeoH5nuQ6VgLGojwYtXp1n
+XNOnR3TT9wD7hHWZ1LkHujtjLNlXBEg19CCROVWthidOuiIXhZrd5E/d3dTQCltD
+bC7RT/hQMmSiFUa7gu/R/xcq3RNQgX4cW25Qe4xyA+tYmv3o5vHXxVn/GCqVZMBT
+hA/BHGZzJCmBrg23sfxELfsCiXCXwO2Rb5tXe0A4KYz6h1L424o7HKKjwQiLz5pu
+3Kizll4xBa9cHCGO0/4YF6+pd5JvRpM20uFPotnkXb9hrdvEh2F5w73D4VvXdgPj
+/kp1oIQr6oLB1Sxv51VGHzY=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Mar 1 12:00:00 2015 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b1:3a:fd:fa:bf:99:17:55:07:e6:61:ce:aa:d9:
+ 34:6c:24:96:c6:72:78:40:b4:98:21:ba:82:d4:3c:
+ 63:a2:17:75:45:d5:92:ee:63:e5:e1:75:16:cf:69:
+ fb:92:ee:80:a1:61:60:c4:bf:d1:a2:d8:e2:45:6b:
+ 6b:0a:a0:2b:ee:c7:d4:9e:db:c7:7e:30:93:17:d8:
+ 66:0d:c3:9e:da:d9:98:97:a2:bd:1a:3a:6e:cf:14:
+ d4:50:c6:30:60:09:9c:5c:4c:65:dd:23:5d:90:87:
+ 80:06:16:5d:8b:0a:af:37:9b:bc:e9:83:61:dd:3e:
+ 50:07:42:52:17:bc:68:de:20:d2:98:ee:5d:e5:24:
+ 4d:7a:9d:50:e7:6a:81:2c:43:3f:0a:57:c1:a7:03:
+ a8:94:2e:e7:4f:0c:29:8e:cf:a2:13:06:e9:6f:e0:
+ 22:ba:39:a9:d6:0f:0a:55:13:38:9b:67:5d:fa:59:
+ b5:6a:8c:8a:af:9e:73:b4:67:47:56:7f:1f:f6:96:
+ 81:7f:b3:7f:9c:18:1e:3c:c6:76:3a:2d:ed:b0:ea:
+ 81:60:0a:a1:d4:e3:70:c0:ef:62:58:4e:7e:43:c3:
+ 3e:8e:c4:dd:13:64:57:ee:14:df:24:93:73:27:c4:
+ df:13:9a:87:67:b5:ea:e0:7e:0c:dd:1b:b2:88:1c:
+ a5:9d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ A8:0C:3D:AD:82:26:A9:EB:AF:61:CC:3D:E0:68:1D:82:DE:DB:D1:FD
+ X509v3 Authority Key Identifier:
+ keyid:A8:0C:3D:AD:82:26:A9:EB:AF:61:CC:3D:E0:68:1D:82:DE:DB:D1:FD
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 45:91:23:ab:2f:b8:a2:2e:24:63:4b:bb:54:17:29:3d:86:9c:
+ 7d:f8:a3:9d:88:4c:9e:89:bf:e9:1a:bc:35:73:27:e1:9d:3e:
+ e4:fc:3c:87:71:21:be:a5:bd:e7:e1:dd:44:b1:67:36:b6:1f:
+ 0a:7c:a1:30:8a:57:23:5f:61:88:18:48:a4:15:0e:58:81:27:
+ a3:9a:42:f4:47:d7:f1:0c:c6:84:dd:03:8f:63:49:07:01:38:
+ 6f:88:60:33:4d:45:73:9f:02:78:a2:1d:e1:a7:75:d7:18:7c:
+ b9:89:e5:ff:30:e6:45:5f:80:5f:f9:88:b5:89:bd:8f:d4:6c:
+ 7d:af:c2:c7:4e:a1:83:74:08:cb:4d:e9:c1:e6:c6:c4:de:55:
+ 10:19:fa:6a:04:89:0a:d8:54:cf:5d:58:f0:17:63:cb:db:0a:
+ 18:6b:75:2a:36:97:3f:f9:ed:3c:c9:2d:8b:40:dd:63:3b:82:
+ f6:fa:0f:5a:31:6e:f9:4a:b8:18:ca:1a:0d:77:6b:b6:01:8e:
+ a8:4b:15:be:29:b6:9a:db:15:2a:8a:66:49:29:74:c2:68:c9:
+ 80:0b:ce:de:aa:4d:54:d2:43:c2:7f:6b:ed:80:5a:0a:c7:bf:
+ d3:95:ed:d1:c1:e8:d0:f2:1f:dc:a7:22:e6:2d:52:b0:fe:d8:
+ b7:3d:bc:d1
+-----BEGIN TRUST_ANCHOR_CONSTRAINED-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE1MDMwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALE6/fq/mRdVB+ZhzqrZ
+NGwklsZyeEC0mCG6gtQ8Y6IXdUXVku5j5eF1Fs9p+5LugKFhYMS/0aLY4kVrawqg
+K+7H1J7bx34wkxfYZg3DntrZmJeivRo6bs8U1FDGMGAJnFxMZd0jXZCHgAYWXYsK
+rzebvOmDYd0+UAdCUhe8aN4g0pjuXeUkTXqdUOdqgSxDPwpXwacDqJQu508MKY7P
+ohMG6W/gIro5qdYPClUTOJtnXfpZtWqMiq+ec7RnR1Z/H/aWgX+zf5wYHjzGdjot
+7bDqgWAKodTjcMDvYlhOfkPDPo7E3RNkV+4U3ySTcyfE3xOah2e16uB+DN0bsogc
+pZ0CAwEAAaOByzCByDAdBgNVHQ4EFgQUqAw9rYImqeuvYcw94Ggdgt7b0f0wHwYD
+VR0jBBgwFoAUqAw9rYImqeuvYcw94Ggdgt7b0f0wNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBFkSOrL7ii
+LiRjS7tUFyk9hpx9+KOdiEyeib/pGrw1cyfhnT7k/DyHcSG+pb3n4d1EsWc2th8K
+fKEwilcjX2GIGEikFQ5YgSejmkL0R9fxDMaE3QOPY0kHAThviGAzTUVznwJ4oh3h
+p3XXGHy5ieX/MOZFX4Bf+Yi1ib2P1Gx9r8LHTqGDdAjLTenB5sbE3lUQGfpqBIkK
+2FTPXVjwF2PL2woYa3UqNpc/+e08yS2LQN1jO4L2+g9aMW75SrgYyhoNd2u2AY6o
+SxW+Kbaa2xUqimZJKXTCaMmAC87eqk1U0kPCf2vtgFoKx7/Tle3RwejQ8h/cpyLm
+LVKw/ti3PbzR
+-----END TRUST_ANCHOR_CONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/expired-intermediary.pem b/chromium/net/data/verify_certificate_chain_unittest/expired-intermediary.pem
deleted file mode 100644
index f3f205429d0..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/expired-intermediary.pem
+++ /dev/null
@@ -1,280 +0,0 @@
-[Created by: generate-expired-intermediary.py]
-
-Certificate chain with 1 intermediary, where the intermediary is expired
-(violates validity.notAfter). Verification is expected to fail.
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Target
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:aa:15:ea:8b:25:e9:de:1a:5f:39:89:dd:71:6d:
- 30:a6:24:ca:59:9b:63:ab:c2:18:2d:d4:80:ea:63:
- 71:70:2e:fe:ac:c0:7d:01:b1:35:06:7c:ad:a8:8c:
- 18:5f:34:16:23:07:78:07:f1:ee:92:08:39:68:1b:
- 08:53:c0:4e:68:62:01:e3:5e:3f:6f:bf:84:18:06:
- a8:59:8d:81:cc:39:71:b9:49:a8:19:2e:44:49:7b:
- 8c:a6:71:15:2c:2a:3d:69:b9:42:5f:48:3c:1b:37:
- c0:c0:fa:11:a8:d2:5a:bc:70:43:e3:b5:04:62:42:
- 40:bc:5a:8d:f6:bb:27:7a:70:34:9b:dc:a8:12:75:
- 0d:1b:5c:1e:81:44:41:7f:57:6e:c6:40:78:f6:a6:
- 5b:98:93:61:4d:e6:dd:bd:49:8f:ba:1e:c5:ac:e9:
- 3f:b3:d1:c5:c9:dd:db:88:f0:47:5a:fc:fc:ec:b3:
- 87:2f:7f:f0:e1:a0:69:05:48:21:58:18:4b:79:e9:
- de:92:9c:5f:89:79:68:f7:5e:59:58:9c:09:88:5e:
- 7e:1c:6d:1e:ad:41:4d:f2:b9:9f:ef:9a:9b:57:8e:
- ff:35:c3:69:2c:35:eb:30:f0:e4:07:94:09:87:a6:
- ef:f4:1b:4b:61:47:64:d1:c9:8b:ba:08:e3:9a:01:
- 99:43
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 40:79:FB:A7:C3:78:BA:A4:08:EC:1C:B2:14:21:D9:DD:6A:9E:B5:29
- X509v3 Authority Key Identifier:
- keyid:6D:48:EB:C2:7F:9A:86:86:39:A3:39:79:C1:5B:A7:BD:A9:4E:23:00
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Intermediary.crl
-
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage:
- TLS Web Server Authentication, TLS Web Client Authentication
- Signature Algorithm: sha256WithRSAEncryption
- 5d:d4:68:d4:44:96:48:60:17:d4:88:12:43:df:6b:f0:b3:4c:
- b2:ab:70:57:bc:d3:98:ae:34:d2:ab:e9:a3:b7:ae:76:9b:49:
- e5:c5:bd:45:33:6a:19:e2:58:96:c7:49:98:24:0b:c1:57:5e:
- 64:a7:2d:7a:c6:1f:fb:9d:ba:a9:19:6e:25:31:2a:b1:82:41:
- 47:d4:02:47:ba:03:c3:43:d1:6b:05:10:b0:25:30:5c:0c:17:
- 3c:a6:7c:4e:6d:94:35:b4:65:e6:67:32:9a:9b:df:26:fa:c6:
- f6:f9:c0:47:62:64:a9:95:02:a3:aa:70:82:38:c3:6d:b3:cd:
- 75:37:bd:4e:c5:91:bc:a1:48:7e:47:a1:bb:39:c4:7d:06:ef:
- dc:c1:28:6b:6e:c6:d5:a3:e1:a0:d5:ec:c3:0a:ae:e5:5b:da:
- 67:14:af:f5:6e:6a:06:72:2e:0d:61:31:31:b7:d4:a4:7b:45:
- 21:50:cb:2d:30:c4:1f:c5:55:5c:e2:50:ce:35:cc:23:35:b0:
- c2:92:ae:89:16:93:66:94:36:43:ff:30:79:b1:28:4d:6f:d1:
- 01:83:a4:e5:fd:d2:d8:6f:c0:0e:e2:d1:85:e8:56:ea:a7:9a:
- d3:ec:f6:96:fc:d2:0c:ec:61:78:97:c8:2a:6d:49:67:ac:66:
- 19:37:0a:f1
------BEGIN CERTIFICATE-----
-MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqFeqL
-JeneGl85id1xbTCmJMpZm2Orwhgt1IDqY3FwLv6swH0BsTUGfK2ojBhfNBYjB3gH
-8e6SCDloGwhTwE5oYgHjXj9vv4QYBqhZjYHMOXG5SagZLkRJe4ymcRUsKj1puUJf
-SDwbN8DA+hGo0lq8cEPjtQRiQkC8Wo32uyd6cDSb3KgSdQ0bXB6BREF/V27GQHj2
-pluYk2FN5t29SY+6HsWs6T+z0cXJ3duI8Eda/Pzss4cvf/DhoGkFSCFYGEt56d6S
-nF+JeWj3XllYnAmIXn4cbR6tQU3yuZ/vmptXjv81w2ksNesw8OQHlAmHpu/0G0th
-R2TRyYu6COOaAZlDAgMBAAGjgekwgeYwHQYDVR0OBBYEFEB5+6fDeLqkCOwcshQh
-2d1qnrUpMB8GA1UdIwQYMBaAFG1I68J/moaGOaM5ecFbp72pTiMAMD8GCCsGAQUF
-BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAXdRo1ESWSGAX1IgSQ99r
-8LNMsqtwV7zTmK400qvpo7eudptJ5cW9RTNqGeJYlsdJmCQLwVdeZKctesYf+526
-qRluJTEqsYJBR9QCR7oDw0PRawUQsCUwXAwXPKZ8Tm2UNbRl5mcympvfJvrG9vnA
-R2JkqZUCo6pwgjjDbbPNdTe9TsWRvKFIfkehuznEfQbv3MEoa27G1aPhoNXswwqu
-5VvaZxSv9W5qBnIuDWExMbfUpHtFIVDLLTDEH8VVXOJQzjXMIzWwwpKuiRaTZpQ2
-Q/8webEoTW/RAYOk5f3S2G/ADuLRhehW6qea0+z2lvzSDOxheJfIKm1JZ6xmGTcK
-8Q==
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 2 (0x2)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Mar 1 12:00:00 2015 GMT
- Subject: CN=Intermediary
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:b5:a7:f6:93:6b:28:98:90:c6:36:f3:31:5e:b2:
- 6d:43:8a:03:c7:8d:9a:04:1a:23:9d:07:ee:5c:47:
- 26:da:31:7e:96:34:7e:9d:d8:29:ff:56:2c:05:f9:
- d9:ff:e9:10:26:9e:53:12:4b:cb:9d:b6:2f:9d:87:
- 33:9c:91:7e:d4:81:c7:63:cf:3a:52:b7:62:18:bb:
- b5:47:c4:ba:80:79:71:30:31:ed:08:e6:c5:85:03:
- d1:e7:05:24:bf:8b:24:f0:2d:44:3c:80:eb:da:75:
- f5:8f:a7:6e:dc:1c:46:b8:c6:bf:76:7b:20:e6:f5:
- 3d:0a:c1:32:54:c6:f1:e6:34:6c:18:c6:11:a5:16:
- 5b:29:24:75:fa:d3:ee:b9:91:56:80:88:df:fe:7f:
- 6b:fa:07:49:95:46:b0:0e:61:ce:8d:f0:a7:64:d5:
- e5:05:7a:c1:9a:6f:e9:e0:44:05:f8:75:ea:d9:64:
- c9:20:98:28:11:d0:c4:fe:31:2f:9b:a5:79:42:2c:
- ee:95:6b:7c:34:d4:15:5c:f8:68:e9:de:5c:b7:c8:
- 1c:33:aa:24:3d:29:60:6e:18:e8:c8:cb:6a:a6:ad:
- 3c:eb:36:0f:1a:81:aa:0b:8a:0e:fd:7b:e5:8b:12:
- 7b:76:04:56:7e:b7:1d:cf:cf:65:77:03:fe:a2:6d:
- 02:29
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 6D:48:EB:C2:7F:9A:86:86:39:A3:39:79:C1:5B:A7:BD:A9:4E:23:00
- X509v3 Authority Key Identifier:
- keyid:7A:B1:AA:9D:A5:49:7E:15:F6:31:BC:33:C7:B6:57:F7:FD:13:5C:CF
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- 1f:03:06:d7:ad:e1:fb:5a:3f:20:60:5d:d0:db:54:2b:b7:52:
- 1a:67:c1:06:75:a7:48:d0:de:14:02:e2:6b:c6:71:d0:da:41:
- 8e:59:c9:17:8e:c5:1e:27:2e:4a:16:2c:7c:77:1e:d4:1c:14:
- 84:85:22:b2:d4:49:90:ab:c3:86:a6:b5:52:97:53:1e:1f:2e:
- e4:ff:60:42:53:03:bb:59:e2:7e:f0:59:a6:4e:04:e6:73:3e:
- d3:2a:c3:ff:1f:69:cd:29:4b:ce:39:aa:93:b9:97:d6:f0:e6:
- e4:52:ca:30:5f:7f:2d:60:6f:93:20:ec:74:dc:d6:65:0d:5d:
- bc:49:cd:ee:56:29:4f:34:8f:9f:5d:54:b6:2b:df:7b:33:8b:
- 2a:b8:7d:f4:39:f3:e1:02:95:3f:e4:28:14:73:58:7d:88:2b:
- e5:1b:e5:0a:9e:eb:b2:e7:7c:bf:e7:1a:70:5f:0f:3d:50:d9:
- 8c:ea:4b:0a:e9:03:8e:5b:84:68:af:5f:72:6d:96:62:b3:90:
- de:f7:be:8d:95:cb:59:5e:d8:7b:41:3e:32:3a:76:a6:01:45:
- 54:9c:d5:98:78:f0:f7:bf:6b:00:4f:0e:c6:05:8b:0f:64:6a:
- ca:0d:fc:ff:db:08:d4:20:11:5e:2b:70:59:bb:5d:46:da:07:
- 94:12:e6:c7
------BEGIN CERTIFICATE-----
-MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE1MDMwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtaf2k2so
-mJDGNvMxXrJtQ4oDx42aBBojnQfuXEcm2jF+ljR+ndgp/1YsBfnZ/+kQJp5TEkvL
-nbYvnYcznJF+1IHHY886UrdiGLu1R8S6gHlxMDHtCObFhQPR5wUkv4sk8C1EPIDr
-2nX1j6du3BxGuMa/dnsg5vU9CsEyVMbx5jRsGMYRpRZbKSR1+tPuuZFWgIjf/n9r
-+gdJlUawDmHOjfCnZNXlBXrBmm/p4EQF+HXq2WTJIJgoEdDE/jEvm6V5QizulWt8
-NNQVXPho6d5ct8gcM6okPSlgbhjoyMtqpq086zYPGoGqC4oO/XvlixJ7dgRWfrcd
-z89ldwP+om0CKQIDAQABo4HLMIHIMB0GA1UdDgQWBBRtSOvCf5qGhjmjOXnBW6e9
-qU4jADAfBgNVHSMEGDAWgBR6saqdpUl+FfYxvDPHtlf3/RNczzA3BggrBgEFBQcB
-AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
-BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
-VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
-AB8DBtet4ftaPyBgXdDbVCu3UhpnwQZ1p0jQ3hQC4mvGcdDaQY5ZyReOxR4nLkoW
-LHx3HtQcFISFIrLUSZCrw4amtVKXUx4fLuT/YEJTA7tZ4n7wWaZOBOZzPtMqw/8f
-ac0pS845qpO5l9bw5uRSyjBffy1gb5Mg7HTc1mUNXbxJze5WKU80j59dVLYr33sz
-iyq4ffQ58+EClT/kKBRzWH2IK+Ub5Qqe67LnfL/nGnBfDz1Q2YzqSwrpA45bhGiv
-X3JtlmKzkN73vo2Vy1le2HtBPjI6dqYBRVSc1Zh48Pe/awBPDsYFiw9kasoN/P/b
-CNQgEV4rcFm7XUbaB5QS5sc=
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Root
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:ea:ec:57:02:47:92:bc:08:b2:1a:2b:0d:03:36:
- e3:2c:b0:4a:52:00:ed:12:f6:5d:39:61:ba:1c:fc:
- 06:9c:11:13:b6:97:b1:ae:bc:66:4c:8a:05:03:29:
- 4c:8a:59:cb:27:86:96:98:ce:5c:35:17:74:ba:ad:
- 1f:14:00:2c:84:cf:cf:2c:fa:5e:a4:70:e5:66:e1:
- 28:79:be:5a:39:42:ad:a5:bb:66:ca:f2:59:d2:cc:
- 22:30:c7:bd:aa:19:e2:ed:be:4f:67:05:26:71:a1:
- 39:96:52:e1:42:cf:fe:83:d2:87:00:e2:96:7b:34:
- 64:cb:a7:76:ed:cf:79:ca:0f:1d:44:49:9e:7c:0a:
- cb:3f:f4:f2:95:1f:07:23:12:75:0c:f7:f4:55:4e:
- 3c:39:ac:0b:93:a4:33:76:27:82:d7:fa:9e:41:17:
- d6:98:e5:c9:a8:0d:40:62:b6:80:36:e7:35:71:6a:
- aa:bb:ae:25:0d:12:b1:c7:f2:18:e6:05:3f:43:df:
- 37:0b:92:30:1c:1f:7c:55:36:01:35:0b:8b:f0:19:
- 81:39:52:70:c6:e8:51:14:41:ae:e8:90:e0:ce:78:
- 31:98:8a:ed:0c:c7:24:bb:1a:3f:ef:78:80:0e:35:
- 19:e2:57:f7:3e:f6:ca:03:c2:f5:46:25:80:32:c7:
- 44:39
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 7A:B1:AA:9D:A5:49:7E:15:F6:31:BC:33:C7:B6:57:F7:FD:13:5C:CF
- X509v3 Authority Key Identifier:
- keyid:7A:B1:AA:9D:A5:49:7E:15:F6:31:BC:33:C7:B6:57:F7:FD:13:5C:CF
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- a2:db:fb:36:6b:24:df:02:28:0c:ba:9d:88:82:7b:e7:e0:87:
- 58:75:70:78:40:3d:f6:53:b9:57:0f:a3:01:b6:aa:3e:80:34:
- 2f:b5:dc:9b:30:3e:43:44:79:70:22:48:0a:33:28:87:6d:09:
- 90:92:d8:41:d5:ca:18:72:ba:65:5d:cb:b2:25:50:1c:07:f7:
- b7:b7:23:93:2c:da:61:b4:c8:15:66:17:17:b4:d3:a8:4a:cd:
- b6:01:bf:4c:e5:84:5d:b2:fb:fe:24:98:44:e8:84:16:6b:f4:
- 04:f9:88:50:ec:42:1c:31:4b:87:1b:67:76:63:01:8f:46:0b:
- 66:1b:59:a6:83:43:ed:33:4f:f8:74:74:2e:fe:8d:2c:f4:55:
- 9f:c5:f9:c1:eb:44:9b:5b:aa:bd:98:5e:36:87:0f:c8:8e:f3:
- f7:e3:ef:08:72:a8:f6:d0:f9:86:fa:58:1e:fb:73:43:b0:ba:
- f9:8d:b0:f5:29:da:64:be:d8:e2:94:88:75:25:54:ce:e6:4d:
- 80:33:be:bc:c0:7e:76:fc:65:2e:dc:74:d7:86:64:08:47:f0:
- 6c:a1:dc:ae:69:2e:71:23:56:eb:a0:6c:f6:2a:15:2c:a7:a5:
- 05:92:68:56:16:07:cd:82:62:02:e8:77:1f:0f:85:31:02:0c:
- c0:9a:56:cd
------BEGIN TRUSTED_CERTIFICATE-----
-MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOrsVwJHkrwIshorDQM2
-4yywSlIA7RL2XTlhuhz8BpwRE7aXsa68ZkyKBQMpTIpZyyeGlpjOXDUXdLqtHxQA
-LITPzyz6XqRw5WbhKHm+WjlCraW7ZsryWdLMIjDHvaoZ4u2+T2cFJnGhOZZS4ULP
-/oPShwDilns0ZMundu3PecoPHURJnnwKyz/08pUfByMSdQz39FVOPDmsC5OkM3Yn
-gtf6nkEX1pjlyagNQGK2gDbnNXFqqruuJQ0SscfyGOYFP0PfNwuSMBwffFU2ATUL
-i/AZgTlScMboURRBruiQ4M54MZiK7QzHJLsaP+94gA41GeJX9z72ygPC9UYlgDLH
-RDkCAwEAAaOByzCByDAdBgNVHQ4EFgQUerGqnaVJfhX2Mbwzx7ZX9/0TXM8wHwYD
-VR0jBBgwFoAUerGqnaVJfhX2Mbwzx7ZX9/0TXM8wNwYIKwYBBQUHAQEEKzApMCcG
-CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
-IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCi2/s2ayTf
-AigMup2Ignvn4IdYdXB4QD32U7lXD6MBtqo+gDQvtdybMD5DRHlwIkgKMyiHbQmQ
-kthB1coYcrplXcuyJVAcB/e3tyOTLNphtMgVZhcXtNOoSs22Ab9M5YRdsvv+JJhE
-6IQWa/QE+YhQ7EIcMUuHG2d2YwGPRgtmG1mmg0PtM0/4dHQu/o0s9FWfxfnB60Sb
-W6q9mF42hw/IjvP34+8Icqj20PmG+lge+3NDsLr5jbD1KdpkvtjilIh1JVTO5k2A
-M768wH52/GUu3HTXhmQIR/BsodyuaS5xI1broGz2KhUsp6UFkmhWFgfNgmIC6Hcf
-D4UxAgzAmlbN
------END TRUSTED_CERTIFICATE-----
-
------BEGIN TIME-----
-MTUwMzAyMTIwMDAwWg==
------END TIME-----
-
------BEGIN VERIFY_RESULT-----
-RkFJTA==
------END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/expired-intermediate.pem b/chromium/net/data/verify_certificate_chain_unittest/expired-intermediate.pem
new file mode 100644
index 00000000000..5ce2527c3f7
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/expired-intermediate.pem
@@ -0,0 +1,290 @@
+[Created by: generate-expired-intermediate.py]
+
+Certificate chain with 1 intermediate, where the intermediate is expired
+(violates validity.notAfter). Verification is expected to fail.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c0:b3:a7:c8:34:e7:e2:df:55:43:80:00:33:96:
+ 78:2c:3a:ac:7e:79:5d:86:9f:df:7e:9b:7a:30:d0:
+ 5b:30:2b:26:cc:06:e7:1f:13:6c:80:36:59:ec:1c:
+ 4b:c9:70:c2:79:14:f4:83:2f:cf:39:a2:9d:96:5c:
+ f2:91:90:ae:8f:f6:63:f6:cc:fb:1b:eb:fe:53:9b:
+ b6:27:8b:52:bb:bb:94:1b:8b:e5:76:cc:5a:4d:d7:
+ 9c:96:05:62:f4:c8:bf:87:cf:a7:6e:55:fd:b5:ab:
+ 28:ae:08:c3:cd:5f:72:77:e3:d8:8d:de:1b:cb:17:
+ bb:4c:b3:3d:6d:f2:84:22:5c:fb:84:31:46:68:3e:
+ bd:b5:83:81:24:01:80:7d:eb:76:8e:1f:7b:8f:e7:
+ 77:cb:8f:ca:69:77:5a:7a:56:f3:1c:3c:16:bf:00:
+ 2b:9f:2d:f5:3a:59:e0:f5:84:91:d3:7a:3e:90:39:
+ 44:5a:65:36:ab:5f:25:5d:9b:57:1e:13:91:97:88:
+ cb:36:39:d3:10:ee:2c:54:4d:6c:d7:22:92:37:0b:
+ 04:05:8f:1d:c3:58:b4:87:7c:db:17:2b:fc:db:00:
+ eb:0f:8c:75:96:e5:12:96:37:fe:b2:d5:68:1c:67:
+ fe:fb:60:c2:30:85:ae:0d:9b:62:50:6f:32:ae:fc:
+ 85:77
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ FC:25:45:D2:F9:2D:71:1C:EA:7B:79:2C:C5:C7:37:5F:9E:2A:5F:5D
+ X509v3 Authority Key Identifier:
+ keyid:4C:33:3C:86:48:60:C6:50:02:47:AF:DE:60:2F:A0:5C:96:EE:70:7B
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 46:d0:27:3e:e6:49:d1:48:c4:0e:d3:0e:d0:3e:be:44:7f:0e:
+ a0:38:92:84:c4:ed:60:65:1c:26:3f:12:dd:d8:e3:49:c6:c8:
+ 42:86:67:95:6c:61:e7:61:8c:da:0a:db:90:d0:6f:e7:9f:05:
+ 38:a5:4a:4e:c3:40:f8:2b:ff:67:ad:9f:70:27:10:8d:68:f2:
+ ee:78:d5:a7:83:2f:e3:67:b3:47:8c:39:c9:29:97:f0:77:b7:
+ fe:7f:c7:6b:aa:6d:4c:83:39:e3:dc:bd:c3:18:e3:d8:d3:50:
+ 8a:97:d3:ee:59:3a:62:20:5b:e7:99:77:e6:d1:d2:d3:d0:d5:
+ 04:7d:86:8e:26:30:05:d1:0e:0f:d6:d2:1e:49:42:67:61:81:
+ 3d:10:75:d6:ba:c4:07:bb:e7:43:c8:a6:f7:56:e3:2b:d4:35:
+ d1:56:94:5c:0b:b6:25:02:d7:cd:74:e7:4d:1d:02:d3:43:ab:
+ dd:50:9f:c4:cf:15:4c:77:87:48:1e:57:3f:3d:7e:7e:67:9b:
+ ae:2f:79:ea:16:a9:cd:c6:76:cb:3c:75:75:a7:78:22:af:a9:
+ b4:83:d3:b2:72:e8:43:cc:4a:8d:ee:b4:5a:ac:b2:30:96:52:
+ 91:26:4b:17:29:4e:53:b4:58:df:f9:1d:53:2c:66:3d:c5:d7:
+ 11:99:b6:f5
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAs6fI
+NOfi31VDgAAzlngsOqx+eV2Gn99+m3ow0FswKybMBucfE2yANlnsHEvJcMJ5FPSD
+L885op2WXPKRkK6P9mP2zPsb6/5Tm7Yni1K7u5Qbi+V2zFpN15yWBWL0yL+Hz6du
+Vf21qyiuCMPNX3J349iN3hvLF7tMsz1t8oQiXPuEMUZoPr21g4EkAYB963aOH3uP
+53fLj8ppd1p6VvMcPBa/ACufLfU6WeD1hJHTej6QOURaZTarXyVdm1ceE5GXiMs2
+OdMQ7ixUTWzXIpI3CwQFjx3DWLSHfNsXK/zbAOsPjHWW5RKWN/6y1WgcZ/77YMIw
+ha4Nm2JQbzKu/IV3AgMBAAGjgekwgeYwHQYDVR0OBBYEFPwlRdL5LXEc6nt5LMXH
+N1+eKl9dMB8GA1UdIwQYMBaAFEwzPIZIYMZQAkev3mAvoFyW7nB7MD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEARtAnPuZJ0UjEDtMO0D6+
+RH8OoDiShMTtYGUcJj8S3djjScbIQoZnlWxh52GM2grbkNBv558FOKVKTsNA+Cv/
+Z62fcCcQjWjy7njVp4Mv42ezR4w5ySmX8He3/n/Ha6ptTIM549y9wxjj2NNQipfT
+7lk6YiBb55l35tHS09DVBH2GjiYwBdEOD9bSHklCZ2GBPRB11rrEB7vnQ8im91bj
+K9Q10VaUXAu2JQLXzXTnTR0C00Or3VCfxM8VTHeHSB5XPz1+fmebri956hapzcZ2
+yzx1dad4Iq+ptIPTsnLoQ8xKje60WqyyMJZSkSZLFylOU7RY3/kdUyxmPcXXEZm2
+9Q==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Mar 1 12:00:00 2015 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ae:f8:c2:3a:71:85:a2:bd:ca:2c:30:b7:22:3a:
+ f3:c9:24:7e:74:86:98:af:cd:13:0a:c1:4c:52:56:
+ f6:03:19:af:7d:67:73:2e:e2:99:e4:3b:f7:7a:7c:
+ dc:8d:83:61:36:c4:89:bc:14:aa:11:8d:e7:fe:3d:
+ 61:e5:1a:78:88:9b:af:63:05:30:78:f8:1e:f5:92:
+ e5:2d:02:d4:b4:cb:a4:44:a4:cc:1b:38:52:fb:55:
+ 4a:b9:37:d4:bb:d0:13:20:69:cb:1f:34:4c:d0:ca:
+ 32:04:23:f3:52:1f:39:e8:90:a3:3d:68:f5:a9:e3:
+ fc:e3:f1:e2:c3:47:55:68:ab:7e:90:77:87:90:00:
+ e9:30:05:ea:30:07:6d:66:d6:c8:98:bd:8b:81:18:
+ c6:c5:45:26:30:ce:c8:61:6a:dc:70:7a:23:8a:4d:
+ b8:ca:94:68:a7:48:ba:d6:fb:10:89:a9:9d:5e:1c:
+ 43:10:b5:de:33:68:a3:2c:91:2b:70:da:be:bd:1e:
+ b2:30:2e:b9:f7:57:fc:d9:d1:4a:92:78:34:93:df:
+ 89:6a:85:1c:df:23:f3:30:fb:7d:9f:7b:b3:cc:9d:
+ 85:98:f8:64:7a:34:ba:7a:51:80:01:eb:91:77:7f:
+ 77:f6:65:86:9e:51:5e:4e:20:6f:c9:ed:3c:50:1c:
+ cd:8f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 4C:33:3C:86:48:60:C6:50:02:47:AF:DE:60:2F:A0:5C:96:EE:70:7B
+ X509v3 Authority Key Identifier:
+ keyid:FB:59:3E:CC:A2:42:62:72:9F:53:96:95:3A:48:EA:16:80:C8:42:40
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 4f:a5:3b:98:b8:a9:83:3a:35:3d:75:a8:f6:e8:59:43:95:3a:
+ 0b:37:dc:ac:d0:12:82:31:2a:64:c8:64:81:f4:f8:d7:28:2c:
+ bf:6f:81:79:a8:21:7b:70:62:4b:7f:c8:b1:bf:69:8b:38:14:
+ e8:78:aa:61:f1:6f:6b:1a:81:93:e7:c4:7b:9f:99:75:2c:90:
+ e9:8d:3a:7e:4e:2f:09:f9:0a:20:04:cb:3e:c6:ed:59:f5:2e:
+ 2e:be:73:b4:40:4f:9d:96:f0:8c:b8:01:88:fa:bf:7a:ed:f6:
+ cc:46:c5:62:1b:bb:f3:1d:3a:4b:02:7c:aa:6e:61:1f:5b:4e:
+ 0e:d5:3f:c3:5c:c0:5f:1a:aa:fb:bb:4f:4d:a4:45:4c:2a:cd:
+ c0:c2:29:3d:1f:31:2b:0d:80:45:c7:5f:4b:09:96:88:a6:4a:
+ b0:fb:66:3f:4b:41:c3:5b:a7:f7:7f:ce:cb:b5:c9:54:62:66:
+ 61:d1:20:73:f6:c2:e0:81:11:20:b1:a0:a5:44:3f:52:4a:77:
+ 9d:b9:b9:99:e7:73:a8:23:1f:02:91:03:e5:90:ad:23:00:2a:
+ 08:99:37:16:df:ca:70:bf:da:e9:50:1d:c5:94:81:57:97:7d:
+ 3f:d2:4f:91:74:94:90:2e:5c:dd:33:13:a0:83:25:4d:c0:7e:
+ 19:97:e3:d6
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE1MDMwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArvjCOnGF
+or3KLDC3IjrzySR+dIaYr80TCsFMUlb2AxmvfWdzLuKZ5Dv3enzcjYNhNsSJvBSq
+EY3n/j1h5Rp4iJuvYwUwePge9ZLlLQLUtMukRKTMGzhS+1VKuTfUu9ATIGnLHzRM
+0MoyBCPzUh856JCjPWj1qeP84/Hiw0dVaKt+kHeHkADpMAXqMAdtZtbImL2LgRjG
+xUUmMM7IYWrccHojik24ypRop0i61vsQiamdXhxDELXeM2ijLJErcNq+vR6yMC65
+91f82dFKkng0k9+JaoUc3yPzMPt9n3uzzJ2FmPhkejS6elGAAeuRd3939mWGnlFe
+TiBvye08UBzNjwIDAQABo4HLMIHIMB0GA1UdDgQWBBRMMzyGSGDGUAJHr95gL6Bc
+lu5wezAfBgNVHSMEGDAWgBT7WT7MokJicp9TlpU6SOoWgMhCQDA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AE+lO5i4qYM6NT11qPboWUOVOgs33KzQEoIxKmTIZIH0+NcoLL9vgXmoIXtwYkt/
+yLG/aYs4FOh4qmHxb2sagZPnxHufmXUskOmNOn5OLwn5CiAEyz7G7Vn1Li6+c7RA
+T52W8Iy4AYj6v3rt9sxGxWIbu/MdOksCfKpuYR9bTg7VP8NcwF8aqvu7T02kRUwq
+zcDCKT0fMSsNgEXHX0sJloimSrD7Zj9LQcNbp/d/zsu1yVRiZmHRIHP2wuCBESCx
+oKVEP1JKd525uZnnc6gjHwKRA+WQrSMAKgiZNxbfynC/2ulQHcWUgVeXfT/ST5F0
+lJAuXN0zE6CDJU3AfhmX49Y=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c9:53:af:4f:d1:35:5f:3e:69:08:13:28:41:5b:
+ 69:25:b0:ee:39:75:73:4c:63:c4:08:42:0c:5e:04:
+ 04:62:21:1a:92:5d:c8:6d:e8:44:6a:3b:3e:c5:6a:
+ 22:56:86:db:cb:38:c8:c7:55:ed:2c:dc:bc:36:39:
+ 76:96:3f:6a:5f:3d:12:43:60:b1:94:13:75:94:02:
+ 8b:ad:f4:be:85:5b:ed:f1:c5:03:2c:3c:0c:e3:eb:
+ 7f:ab:94:4a:79:8b:48:fd:ad:7a:c3:e0:a8:de:40:
+ ea:f0:a7:87:54:40:6e:f4:74:88:aa:2b:bb:21:bf:
+ d6:7f:da:bc:cf:52:48:3d:b6:75:0d:e2:6b:ea:03:
+ 0a:d7:39:f5:78:45:63:05:1a:4b:99:40:5e:97:08:
+ 0a:5d:34:63:fa:ba:de:a7:f5:1c:e8:b2:26:96:0f:
+ c9:c1:ac:6d:ef:05:8d:1c:dc:09:0b:bc:d3:f3:fb:
+ 10:43:2f:b2:36:3e:cf:84:1a:37:1e:fc:81:67:c6:
+ 14:87:bb:87:33:16:2a:95:cf:e7:0a:b7:52:00:05:
+ 09:08:a9:a5:97:5d:be:ed:19:92:4e:6c:4f:94:7f:
+ e5:1a:34:c0:dc:3f:02:8e:ae:77:fc:b6:27:77:78:
+ 48:e7:ca:a1:bd:27:1d:3c:a3:2d:8d:46:d5:a6:9d:
+ 53:cd
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ FB:59:3E:CC:A2:42:62:72:9F:53:96:95:3A:48:EA:16:80:C8:42:40
+ X509v3 Authority Key Identifier:
+ keyid:FB:59:3E:CC:A2:42:62:72:9F:53:96:95:3A:48:EA:16:80:C8:42:40
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 34:3c:af:58:31:78:ea:c0:32:23:d8:b0:8e:84:44:9c:a3:b7:
+ 0b:b5:a4:4b:3d:21:d2:8a:02:ec:4c:ed:ab:c3:0a:17:89:50:
+ 45:fc:43:0b:db:6c:e6:69:56:3c:41:b0:c9:2d:12:19:bd:a1:
+ b6:a7:fa:25:a4:73:6f:32:06:b7:f5:ac:64:b3:b9:b6:44:65:
+ 83:b2:48:cc:3c:68:69:ae:16:0a:c0:c5:57:39:00:51:16:97:
+ 0e:03:7d:e7:02:65:f2:84:de:e9:a6:9d:d5:83:73:37:9d:f5:
+ bc:d8:ef:dc:6f:1b:48:db:f6:ca:a0:00:d5:e6:c0:f6:94:2d:
+ a9:4e:b4:4d:cf:49:7d:c4:4d:3a:68:a2:b2:d8:e8:67:77:98:
+ 6f:1c:2d:4a:74:13:2b:24:04:67:50:38:7e:e9:cb:0c:94:0d:
+ d0:07:50:52:a5:03:10:07:6a:04:ef:33:ea:b0:70:9f:27:34:
+ 47:b0:f8:41:81:7e:f2:93:0b:c0:cf:c3:d7:06:59:f1:24:2a:
+ 61:64:7f:38:f0:4f:77:d3:92:e4:1f:e4:44:a4:b6:85:40:59:
+ 3d:df:f2:cc:57:ea:1a:58:1d:f8:90:d4:2d:53:67:56:c3:88:
+ 9d:17:0f:19:19:fc:ed:4e:cc:b9:76:fa:fc:93:e5:bf:08:e7:
+ a9:d6:46:0f
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMlTr0/RNV8+aQgTKEFb
+aSWw7jl1c0xjxAhCDF4EBGIhGpJdyG3oRGo7PsVqIlaG28s4yMdV7SzcvDY5dpY/
+al89EkNgsZQTdZQCi630voVb7fHFAyw8DOPrf6uUSnmLSP2tesPgqN5A6vCnh1RA
+bvR0iKoruyG/1n/avM9SSD22dQ3ia+oDCtc59XhFYwUaS5lAXpcICl00Y/q63qf1
+HOiyJpYPycGsbe8FjRzcCQu80/P7EEMvsjY+z4QaNx78gWfGFIe7hzMWKpXP5wq3
+UgAFCQippZddvu0Zkk5sT5R/5Ro0wNw/Ao6ud/y2J3d4SOfKob0nHTyjLY1G1aad
+U80CAwEAAaOByzCByDAdBgNVHQ4EFgQU+1k+zKJCYnKfU5aVOkjqFoDIQkAwHwYD
+VR0jBBgwFoAU+1k+zKJCYnKfU5aVOkjqFoDIQkAwNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA0PK9YMXjq
+wDIj2LCOhESco7cLtaRLPSHSigLsTO2rwwoXiVBF/EML22zmaVY8QbDJLRIZvaG2
+p/olpHNvMga39axks7m2RGWDskjMPGhprhYKwMVXOQBRFpcOA33nAmXyhN7ppp3V
+g3M3nfW82O/cbxtI2/bKoADV5sD2lC2pTrRNz0l9xE06aKKy2Ohnd5hvHC1KdBMr
+JARnUDh+6csMlA3QB1BSpQMQB2oE7zPqsHCfJzRHsPhBgX7ykwvAz8PXBlnxJCph
+ZH848E9305LkH+REpLaFQFk93/LMV+oaWB34kNQtU2dWw4idFw8ZGfztTsy5dvr8
+k+W/COep1kYP
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+FAIL
+-----BEGIN VERIFY_RESULT-----
+RkFJTA==
+-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 0
+ [Error] Time is after notAfter
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMAogICAgICBbRXJyb3JdIFRpbWUgaXMgYWZ0ZXIgbm90QWZ0ZXIK
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/expired-root.pem b/chromium/net/data/verify_certificate_chain_unittest/expired-root.pem
deleted file mode 100644
index 5e9ffcf751b..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/expired-root.pem
+++ /dev/null
@@ -1,280 +0,0 @@
-[Created by: generate-expired-root.py]
-
-Certificate chain with 1 intermediary, where the root certificate is expired
-(violates validity.notAfter). Verification is expected to fail.
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Target
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:c2:5a:d7:49:58:e0:e3:06:4c:d0:8d:83:ad:7a:
- ff:86:7c:0e:00:26:64:44:8a:cb:38:bd:95:8e:b1:
- 7f:7c:48:7f:02:ef:7d:f9:b4:76:76:eb:5a:1d:71:
- 99:3a:c8:66:1a:c8:fb:24:d3:e8:9c:af:3b:5c:b5:
- 10:f0:32:7c:46:87:9a:3f:f6:57:6a:45:5c:18:6e:
- 92:54:54:16:4e:17:79:1c:a1:05:7c:21:3c:dc:89:
- 23:5d:aa:f9:1e:a1:8c:9b:9f:d7:a0:f3:c3:23:f0:
- f4:b5:12:ac:d3:57:cb:bb:f9:8e:0d:d8:e9:d5:bd:
- 71:2b:3e:38:d1:fe:f0:17:cb:f0:ce:23:8f:8a:ee:
- 56:4d:94:18:31:c3:1d:74:07:57:a4:f7:07:e8:b3:
- a4:60:53:38:96:83:f7:59:cf:03:f9:38:3c:35:87:
- 6a:71:92:8a:1b:4f:7e:f0:49:76:ba:65:42:87:fe:
- b2:21:e1:17:d6:98:50:36:5a:7f:fe:8d:f6:bf:ab:
- 46:63:fc:57:e8:57:c5:90:9b:27:07:30:fa:26:1d:
- 13:eb:f2:e1:b0:99:f9:55:39:76:0f:ca:a4:31:85:
- c6:62:df:53:cd:3e:df:bf:83:1d:a9:07:b1:a2:8a:
- be:43:f2:05:1e:f9:ca:28:2e:81:39:fa:2c:74:c5:
- 7c:b1
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 14:B3:FA:87:AB:1D:54:2D:2B:B8:C4:5D:33:57:C5:52:F4:15:B8:20
- X509v3 Authority Key Identifier:
- keyid:ED:CC:99:FA:9D:D2:85:7E:0E:02:42:8E:72:48:C3:F4:29:4B:95:D2
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Intermediary.crl
-
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage:
- TLS Web Server Authentication, TLS Web Client Authentication
- Signature Algorithm: sha256WithRSAEncryption
- 42:13:4f:10:c0:69:c9:ad:88:94:2d:df:24:e6:47:6c:d3:07:
- 33:75:77:ba:c8:40:f4:28:1f:7a:0a:49:14:93:5f:d7:6e:91:
- 49:22:a3:cb:f0:52:f9:d6:22:90:ef:62:79:3d:cc:e5:2f:d0:
- c9:c3:0e:b0:54:06:6c:31:7e:f3:9e:48:be:02:c8:f3:60:cb:
- d7:5b:65:f6:82:41:fa:b4:19:34:e2:82:9c:0a:02:ee:ec:2a:
- 53:6d:25:49:19:9a:ce:1a:6c:c4:49:e2:3b:08:fb:6f:05:00:
- 65:d6:64:29:a9:c5:9f:83:27:af:49:a8:b8:14:de:e0:43:c6:
- b4:c2:ad:49:55:d5:58:42:50:cb:20:54:df:1e:9b:0a:9d:d3:
- a0:85:4d:a2:5c:cb:07:24:1c:f0:91:d2:89:54:d1:69:7a:68:
- 05:6a:3c:80:00:e5:7d:6d:9a:0b:37:0d:d0:6b:5e:61:d4:04:
- 37:73:41:ae:48:10:0a:3b:b1:d4:67:31:19:19:43:d2:22:f4:
- 29:72:cd:8d:97:5b:f8:11:09:5b:32:07:56:fb:f4:d7:66:cc:
- 72:e4:db:f6:1d:53:70:0e:bf:4c:c2:0f:61:07:a9:f3:1d:5f:
- 03:f9:1e:9c:96:f6:49:1a:b8:51:1d:16:22:1a:f5:2b:ac:da:
- ce:5a:a6:38
------BEGIN CERTIFICATE-----
-MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCWtdJ
-WODjBkzQjYOtev+GfA4AJmREiss4vZWOsX98SH8C7335tHZ261odcZk6yGYayPsk
-0+icrztctRDwMnxGh5o/9ldqRVwYbpJUVBZOF3kcoQV8ITzciSNdqvkeoYybn9eg
-88Mj8PS1EqzTV8u7+Y4N2OnVvXErPjjR/vAXy/DOI4+K7lZNlBgxwx10B1ek9wfo
-s6RgUziWg/dZzwP5ODw1h2pxkoobT37wSXa6ZUKH/rIh4RfWmFA2Wn/+jfa/q0Zj
-/FfoV8WQmycHMPomHRPr8uGwmflVOXYPyqQxhcZi31PNPt+/gx2pB7Giir5D8gUe
-+cooLoE5+ix0xXyxAgMBAAGjgekwgeYwHQYDVR0OBBYEFBSz+oerHVQtK7jEXTNX
-xVL0FbggMB8GA1UdIwQYMBaAFO3Mmfqd0oV+DgJCjnJIw/QpS5XSMD8GCCsGAQUF
-BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAQhNPEMBpya2IlC3fJOZH
-bNMHM3V3ushA9CgfegpJFJNf126RSSKjy/BS+dYikO9ieT3M5S/QycMOsFQGbDF+
-855IvgLI82DL11tl9oJB+rQZNOKCnAoC7uwqU20lSRmazhpsxEniOwj7bwUAZdZk
-KanFn4Mnr0mouBTe4EPGtMKtSVXVWEJQyyBU3x6bCp3ToIVNolzLByQc8JHSiVTR
-aXpoBWo8gADlfW2aCzcN0GteYdQEN3NBrkgQCjux1GcxGRlD0iL0KXLNjZdb+BEJ
-WzIHVvv012bMcuTb9h1TcA6/TMIPYQep8x1fA/kenJb2SRq4UR0WIhr1K6zazlqm
-OA==
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 2 (0x2)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:b0:4e:34:a2:37:40:52:cd:58:5e:d8:18:40:f2:
- 23:9e:a8:78:10:18:db:5b:87:a3:e2:e3:c8:a5:50:
- b7:c3:1c:fa:e5:77:7f:93:b3:44:2a:90:60:39:81:
- a4:c4:63:e0:3d:8a:d8:36:c8:5d:df:04:01:c1:f1:
- b5:65:12:3d:f5:22:f9:f5:ff:c5:60:2a:48:39:90:
- 69:df:08:9f:bc:07:6c:c6:ab:3f:e4:2d:05:b5:b3:
- 11:9e:4d:5a:8d:3c:64:3f:1e:7d:df:05:1c:e2:e4:
- b7:d9:42:36:cb:86:df:53:2a:ea:51:2b:53:f8:3a:
- 07:5a:08:8b:df:fb:9d:2f:1f:94:a9:fb:07:93:87:
- 20:ee:e6:ae:d9:a5:2e:1a:eb:d9:67:0e:ce:8f:7e:
- 0b:be:3a:ca:b2:9c:40:38:54:5c:35:99:ac:07:12:
- 3e:00:a3:39:07:76:e1:fa:df:7b:81:59:0b:a3:8e:
- 4e:42:b7:1e:09:04:e2:0c:ea:eb:d5:c0:da:dd:6f:
- f0:6e:6a:34:2a:38:ae:4f:b4:f3:4f:06:17:c3:83:
- 0a:66:e8:c6:8a:54:71:86:0b:8b:39:3b:73:07:d2:
- 0b:dc:4c:86:79:da:86:44:25:3d:dc:f1:38:eb:22:
- ce:92:df:8b:9b:ff:47:eb:7a:28:0a:91:cd:ba:30:
- 77:7d
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- ED:CC:99:FA:9D:D2:85:7E:0E:02:42:8E:72:48:C3:F4:29:4B:95:D2
- X509v3 Authority Key Identifier:
- keyid:62:81:A1:85:84:13:F2:70:79:BD:48:5B:29:88:E0:F1:27:35:41:F7
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- 02:82:8b:cf:81:89:f2:15:d3:a7:a6:30:c8:2a:c8:32:c5:95:
- 7c:18:60:2e:51:48:c5:26:47:b8:5e:49:17:b4:aa:87:f7:8b:
- 22:73:2a:81:20:1d:1c:54:b7:7b:91:e1:48:40:7a:19:13:05:
- 05:6e:e4:21:75:d7:a7:a0:54:bf:da:18:a1:52:08:95:0a:c5:
- e0:36:f3:6d:ab:ed:21:69:e1:e7:4d:8f:85:85:22:ac:7b:b3:
- 7f:3f:1a:7e:44:be:06:ee:0b:f5:89:53:e3:d1:fa:f7:51:00:
- 7c:61:d2:5e:48:ab:4c:bb:47:03:a2:d4:6a:78:02:7e:33:5a:
- b9:7c:14:12:5a:c2:bb:66:91:4f:21:cb:c0:b7:80:72:4b:28:
- 6c:d9:7b:02:fa:04:26:f2:de:2a:54:7d:69:89:88:f3:b9:10:
- ab:0a:07:fa:f8:7c:1e:bb:45:0f:4f:de:2e:36:3e:a4:63:b0:
- 71:a1:be:2b:dd:0c:fa:0b:97:f0:ad:56:b0:dd:76:51:e7:45:
- aa:a3:82:cd:77:5a:07:3a:e5:bc:fd:37:8f:52:ee:e0:de:ac:
- 99:44:94:65:7d:b1:30:89:4d:12:da:73:29:06:a9:28:42:5d:
- 1f:1a:a7:44:f3:77:5b:99:4a:ca:a6:dd:3a:cd:a1:16:76:11:
- 16:44:34:c0
------BEGIN CERTIFICATE-----
-MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsE40ojdA
-Us1YXtgYQPIjnqh4EBjbW4ej4uPIpVC3wxz65Xd/k7NEKpBgOYGkxGPgPYrYNshd
-3wQBwfG1ZRI99SL59f/FYCpIOZBp3wifvAdsxqs/5C0FtbMRnk1ajTxkPx593wUc
-4uS32UI2y4bfUyrqUStT+DoHWgiL3/udLx+UqfsHk4cg7uau2aUuGuvZZw7Oj34L
-vjrKspxAOFRcNZmsBxI+AKM5B3bh+t97gVkLo45OQrceCQTiDOrr1cDa3W/wbmo0
-KjiuT7TzTwYXw4MKZujGilRxhguLOTtzB9IL3EyGedqGRCU93PE46yLOkt+Lm/9H
-63ooCpHNujB3fQIDAQABo4HLMIHIMB0GA1UdDgQWBBTtzJn6ndKFfg4CQo5ySMP0
-KUuV0jAfBgNVHSMEGDAWgBRigaGFhBPycHm9SFspiODxJzVB9zA3BggrBgEFBQcB
-AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
-BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
-VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
-AAKCi8+BifIV06emMMgqyDLFlXwYYC5RSMUmR7heSRe0qof3iyJzKoEgHRxUt3uR
-4UhAehkTBQVu5CF116egVL/aGKFSCJUKxeA2822r7SFp4edNj4WFIqx7s38/Gn5E
-vgbuC/WJU+PR+vdRAHxh0l5Iq0y7RwOi1Gp4An4zWrl8FBJawrtmkU8hy8C3gHJL
-KGzZewL6BCby3ipUfWmJiPO5EKsKB/r4fB67RQ9P3i42PqRjsHGhvivdDPoLl/Ct
-VrDddlHnRaqjgs13Wgc65bz9N49S7uDerJlElGV9sTCJTRLacykGqShCXR8ap0Tz
-d1uZSsqm3TrNoRZ2ERZENMA=
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Mar 1 12:00:00 2015 GMT
- Subject: CN=Root
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:b5:79:69:47:50:a7:53:24:79:a6:6a:35:e8:33:
- 74:57:45:da:2c:69:13:1f:76:f9:51:ce:b4:47:ad:
- a3:c3:58:50:d1:5f:d6:34:5b:3a:62:f0:6c:ea:e7:
- 86:c2:09:78:b3:53:0d:7f:45:cb:2b:8e:2e:1f:9b:
- c0:7e:47:90:e3:7b:20:cc:01:ed:b6:c3:c6:40:69:
- 74:2b:f1:db:a5:f8:f4:5b:fd:e9:84:db:1a:fc:4f:
- 91:4b:e7:f5:2e:99:d0:c9:69:f5:48:5b:8b:19:ca:
- dc:5c:0d:3d:15:25:56:77:86:b6:54:fc:d3:1d:8e:
- f8:ea:f5:ec:de:30:38:93:28:37:7c:d4:b7:29:26:
- 6f:2a:4a:56:c3:12:91:18:d6:77:cf:4f:31:4e:13:
- b3:8f:ca:bc:7b:a7:7f:f1:af:db:77:80:51:8c:42:
- 1c:27:37:18:ac:6c:45:8e:d5:21:25:16:09:fb:3b:
- 0c:84:a8:60:ea:8a:03:65:94:f5:5c:d6:62:36:ae:
- b4:de:a3:b1:ee:1b:85:12:8c:6e:ba:ee:14:94:b9:
- c7:cb:a3:f1:d1:96:ed:81:79:71:27:d0:d8:26:b4:
- 80:54:c8:07:a9:34:71:a2:a9:04:33:d6:58:02:59:
- f9:14:97:5e:a9:2b:8c:41:2a:5c:3e:ac:30:b8:63:
- 52:35
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 62:81:A1:85:84:13:F2:70:79:BD:48:5B:29:88:E0:F1:27:35:41:F7
- X509v3 Authority Key Identifier:
- keyid:62:81:A1:85:84:13:F2:70:79:BD:48:5B:29:88:E0:F1:27:35:41:F7
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- 47:20:58:cf:09:e0:8c:35:aa:91:d7:be:d1:6a:dc:06:11:ef:
- 4a:b2:f1:94:41:3b:b4:00:d5:d3:be:cb:4b:ef:67:e0:1b:91:
- 8b:c3:4f:42:92:9a:5b:8f:84:b1:8e:86:f8:9a:f8:aa:d2:66:
- 34:76:e5:bb:6f:95:4c:f4:23:e4:71:53:6a:02:8d:e4:ad:7f:
- c3:6c:77:a0:8d:00:80:c9:cf:e3:d0:96:e2:5a:1c:b6:66:96:
- 0d:2a:43:58:66:c8:53:b8:7a:6e:c2:c4:2b:c6:54:33:40:b3:
- f3:07:67:37:51:92:b2:7f:9a:e3:c1:79:36:4b:d8:9f:e9:6e:
- 04:c6:49:19:51:fd:6f:21:86:09:9a:00:76:e0:5e:73:b0:57:
- 00:25:c5:2a:12:b3:bd:9a:8b:1b:ff:46:90:47:20:76:2b:bf:
- 8e:94:7d:1a:7c:56:f6:0a:03:7b:5a:42:97:76:77:2e:a5:0c:
- 2e:a0:03:13:a8:39:79:82:a0:98:8c:da:bd:1e:7e:af:56:21:
- 95:14:26:ef:06:07:d7:ec:42:6b:2f:b1:e6:f7:97:88:30:5f:
- 79:50:99:92:b4:9e:20:d0:c2:95:8e:f7:61:64:99:c3:13:da:
- 46:a1:63:73:0b:23:e8:d7:e7:97:36:82:2b:2a:12:8e:b8:a9:
- 2d:3c:35:b3
------BEGIN TRUSTED_CERTIFICATE-----
-MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE1MDMwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALV5aUdQp1MkeaZqNegz
-dFdF2ixpEx92+VHOtEeto8NYUNFf1jRbOmLwbOrnhsIJeLNTDX9FyyuOLh+bwH5H
-kON7IMwB7bbDxkBpdCvx26X49Fv96YTbGvxPkUvn9S6Z0Mlp9UhbixnK3FwNPRUl
-VneGtlT80x2O+Or17N4wOJMoN3zUtykmbypKVsMSkRjWd89PMU4Ts4/KvHunf/Gv
-23eAUYxCHCc3GKxsRY7VISUWCfs7DISoYOqKA2WU9VzWYjautN6jse4bhRKMbrru
-FJS5x8uj8dGW7YF5cSfQ2Ca0gFTIB6k0caKpBDPWWAJZ+RSXXqkrjEEqXD6sMLhj
-UjUCAwEAAaOByzCByDAdBgNVHQ4EFgQUYoGhhYQT8nB5vUhbKYjg8Sc1QfcwHwYD
-VR0jBBgwFoAUYoGhhYQT8nB5vUhbKYjg8Sc1QfcwNwYIKwYBBQUHAQEEKzApMCcG
-CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
-IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBHIFjPCeCM
-NaqR177RatwGEe9KsvGUQTu0ANXTvstL72fgG5GLw09Ckppbj4Sxjob4mviq0mY0
-duW7b5VM9CPkcVNqAo3krX/DbHegjQCAyc/j0JbiWhy2ZpYNKkNYZshTuHpuwsQr
-xlQzQLPzB2c3UZKyf5rjwXk2S9if6W4ExkkZUf1vIYYJmgB24F5zsFcAJcUqErO9
-mosb/0aQRyB2K7+OlH0afFb2CgN7WkKXdncupQwuoAMTqDl5gqCYjNq9Hn6vViGV
-FCbvBgfX7EJrL7Hm95eIMF95UJmStJ4g0MKVjvdhZJnDE9pGoWNzCyPo1+eXNoIr
-KhKOuKktPDWz
------END TRUSTED_CERTIFICATE-----
-
------BEGIN TIME-----
-MTUwMzAyMTIwMDAwWg==
------END TIME-----
-
------BEGIN VERIFY_RESULT-----
-RkFJTA==
------END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/expired-target-notBefore.pem b/chromium/net/data/verify_certificate_chain_unittest/expired-target-notBefore.pem
index 3a1096d41c1..f73790cbf64 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/expired-target-notBefore.pem
+++ b/chromium/net/data/verify_certificate_chain_unittest/expired-target-notBefore.pem
@@ -1,6 +1,6 @@
[Created by: generate-expired-target-notBefore.py]
-Certificate chain with 1 intermediary, where the target is expired (violates
+Certificate chain with 1 intermediate, where the target is expired (violates
validity.notBefore). Verification is expected to fail.
Certificate:
@@ -8,7 +8,7 @@ Certificate:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
+ Issuer: CN=Intermediate
Validity
Not Before: Mar 2 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
@@ -17,80 +17,80 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:b8:1e:b0:de:22:2f:b4:13:ca:c4:72:10:b9:bd:
- 4c:80:81:be:17:f2:45:bb:5a:d2:b4:a1:f6:3e:1c:
- 50:00:d5:8d:fe:27:5b:a2:21:07:8b:1a:de:56:56:
- 58:88:25:41:09:4e:fd:04:bb:6c:75:c7:48:3f:98:
- 6b:4c:54:8a:22:26:28:f3:c6:76:5f:e8:bf:ad:bf:
- 4f:ad:6d:1a:1d:ba:5e:fc:0d:2f:92:b2:4f:f7:bb:
- e5:fd:3a:ff:8d:fb:f1:9f:96:90:18:46:2c:cf:7b:
- 62:75:b8:c5:e9:40:ce:67:21:e0:4b:9e:78:65:9b:
- 9e:71:50:bd:33:12:53:78:7f:ad:fd:bf:e0:ae:d2:
- 72:51:c1:18:d0:96:71:78:23:ff:a6:55:39:d5:9a:
- 89:3e:21:72:cd:9d:13:fa:04:9f:08:6f:c0:d0:c5:
- ab:b2:27:b5:b8:e2:2d:ab:31:a3:7a:c1:94:56:8b:
- 35:9c:b8:46:71:1c:d6:69:95:c1:0a:98:e4:14:96:
- 3c:2f:cb:12:ac:71:88:a4:aa:d0:c8:0e:51:98:47:
- 71:e8:0e:a0:e7:7e:01:95:b3:73:3f:9b:c4:8b:9d:
- d0:dc:17:a9:53:35:99:29:67:f3:28:d2:7f:1e:0d:
- 17:6b:5d:56:c9:91:a6:ae:e8:07:a6:76:d6:8e:2a:
- 48:47
+ 00:d8:d8:32:e7:2a:be:55:8d:e7:e8:ae:ee:1d:c6:
+ f5:3b:0c:6d:25:d9:53:8e:4a:84:0c:1e:7b:cb:30:
+ 2f:5f:1f:85:a3:e7:e0:92:79:b4:a2:35:fe:b7:71:
+ b4:a3:c0:79:dd:50:e5:e4:b0:61:b5:2c:97:2e:e6:
+ 4a:bc:c6:3c:c7:20:f3:87:20:4e:27:d8:8a:f6:0d:
+ a9:ac:0a:57:9a:53:03:9e:5f:32:ef:07:18:0a:ab:
+ f6:a7:42:4e:ef:36:9a:10:4a:db:d3:9f:49:d7:04:
+ 3a:95:61:77:ba:5e:d2:84:cb:57:ec:45:91:d0:fd:
+ be:5b:8b:4d:2f:0b:21:ab:89:ab:92:d9:fc:18:0c:
+ 44:bb:54:0a:94:5d:bd:ee:ac:a9:ee:f2:27:a8:3f:
+ 30:b1:e7:f6:fd:1a:05:86:56:db:22:de:bd:e5:a6:
+ d2:50:2d:4c:0c:ab:1c:b2:49:6c:23:9a:46:d8:f5:
+ 53:f4:9d:52:2c:f0:25:e3:a8:e7:99:d3:6d:ec:f0:
+ 0c:d1:bd:1e:73:c6:8f:5d:11:50:88:b3:63:bc:c7:
+ c5:eb:36:74:8f:03:fe:1a:36:d7:ac:5f:18:ae:73:
+ 11:7f:dc:81:dc:7c:77:17:ec:2c:91:c5:db:cc:2d:
+ 1a:a0:f1:ad:aa:d4:b6:1d:22:ee:22:bd:48:c9:f0:
+ df:7f
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 27:06:C6:75:1B:30:9B:E0:78:6C:9C:9B:F1:E1:29:B7:11:41:6D:BD
+ E6:C3:54:85:55:F1:44:F6:4B:55:D3:EA:09:69:E3:95:F6:DA:2A:FA
X509v3 Authority Key Identifier:
- keyid:7A:68:26:1F:EE:59:FA:52:EB:B0:98:D1:5D:F6:19:9F:8D:1C:F5:FB
+ keyid:EC:3F:B7:92:DD:EA:7D:97:A5:77:22:28:E9:98:4D:0D:07:69:C4:86
Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
X509v3 CRL Distribution Points:
Full Name:
- URI:http://url-for-crl/Intermediary.crl
+ URI:http://url-for-crl/Intermediate.crl
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 4e:c4:5a:b3:1f:31:4c:04:75:f8:bb:7d:7b:ed:93:07:81:e3:
- 41:b9:50:b0:c4:01:06:7d:64:f3:c5:d8:5b:96:0e:b6:c2:fa:
- 66:50:25:79:c8:6f:6c:03:f1:7b:e6:73:60:cc:68:42:0e:43:
- 85:58:46:c2:51:27:73:dd:f1:6d:9d:d1:7a:80:97:e5:cf:0c:
- 9a:85:a1:92:ed:26:3a:d6:10:fd:19:c8:f2:fb:b9:47:ee:a9:
- 63:1c:52:c5:97:1a:6b:2f:f4:dc:9c:cb:74:86:6a:48:2a:87:
- ac:24:d5:cc:8c:2b:12:9d:6d:bc:7e:be:95:3f:88:83:18:68:
- 75:59:db:79:fb:f0:c7:38:7b:8f:a3:16:e0:44:4c:19:e3:cd:
- 36:98:fb:fd:c9:17:5e:2f:9c:0c:e1:ba:f2:6e:c0:6e:91:9d:
- 5e:c0:0b:95:d8:62:7e:2e:8a:2d:4c:f9:b4:ca:17:0d:f0:d2:
- 71:b0:4d:15:79:b0:8b:9e:96:cf:2e:44:1a:84:a7:4f:61:38:
- 67:61:1c:a1:70:a0:a4:02:5b:42:f5:a0:09:95:cc:22:89:0d:
- 4e:e2:1b:dd:1d:fe:ae:d7:84:58:db:dd:07:1d:96:6b:32:11:
- da:c6:56:d9:cd:69:10:25:62:fd:91:2d:63:0f:8c:82:fe:00:
- 8a:eb:87:4f
+ 27:8e:41:9c:f0:5c:4a:e0:b0:63:c7:fa:cc:1f:d4:21:35:33:
+ 87:13:68:b7:18:08:0e:ba:22:a1:51:1a:d9:ba:31:a7:35:80:
+ c7:75:35:a4:68:c8:3e:91:79:55:e3:60:34:79:a1:0f:a9:cc:
+ 05:92:61:40:b0:66:2b:fe:c7:29:a2:54:f3:7c:71:b6:36:fe:
+ a9:fd:7b:79:ea:66:19:c0:2f:d2:56:97:2f:ca:12:a3:96:6b:
+ b3:57:c8:06:58:6f:de:53:d7:63:ee:93:d6:b2:f2:11:9c:8a:
+ a1:00:26:6c:9a:bd:dd:da:97:ea:07:61:5e:48:8e:dd:3f:10:
+ 4b:39:d1:9a:ba:8f:14:30:b3:36:3c:9f:a7:2c:68:b4:3c:da:
+ f2:90:24:4a:03:19:38:24:73:b5:72:b3:ae:31:b3:44:96:36:
+ 3d:38:c5:c7:07:62:78:06:d8:5d:01:07:d9:b3:2d:be:0f:46:
+ 13:8c:25:f9:d7:e0:84:5d:a4:62:a7:5d:3b:22:cf:e6:95:97:
+ 20:d3:24:40:cc:cf:3d:72:17:f9:c1:8e:ee:15:6f:99:8f:24:
+ d1:83:6b:f9:fe:6b:94:3a:9c:2c:02:5c:1d:70:d6:f8:d6:69:
+ 0d:99:f5:53:89:4f:21:7b:a6:34:dd:ce:27:ef:45:a5:e0:c6:
+ e5:f5:fc:5f
-----BEGIN CERTIFICATE-----
MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMzAyMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4HrDe
-Ii+0E8rEchC5vUyAgb4X8kW7WtK0ofY+HFAA1Y3+J1uiIQeLGt5WVliIJUEJTv0E
-u2x1x0g/mGtMVIoiJijzxnZf6L+tv0+tbRodul78DS+Ssk/3u+X9Ov+N+/GflpAY
-RizPe2J1uMXpQM5nIeBLnnhlm55xUL0zElN4f639v+Cu0nJRwRjQlnF4I/+mVTnV
-mok+IXLNnRP6BJ8Ib8DQxauyJ7W44i2rMaN6wZRWizWcuEZxHNZplcEKmOQUljwv
-yxKscYikqtDIDlGYR3HoDqDnfgGVs3M/m8SLndDcF6lTNZkpZ/Mo0n8eDRdrXVbJ
-kaau6AemdtaOKkhHAgMBAAGjgekwgeYwHQYDVR0OBBYEFCcGxnUbMJvgeGycm/Hh
-KbcRQW29MB8GA1UdIwQYMBaAFHpoJh/uWfpS67CY0V32GZ+NHPX7MD8GCCsGAQUF
+cm1lZGlhdGUwHhcNMTUwMzAyMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDY2DLn
+Kr5Vjeforu4dxvU7DG0l2VOOSoQMHnvLMC9fH4Wj5+CSebSiNf63cbSjwHndUOXk
+sGG1LJcu5kq8xjzHIPOHIE4n2Ir2DamsCleaUwOeXzLvBxgKq/anQk7vNpoQStvT
+n0nXBDqVYXe6XtKEy1fsRZHQ/b5bi00vCyGriauS2fwYDES7VAqUXb3urKnu8ieo
+PzCx5/b9GgWGVtsi3r3lptJQLUwMqxyySWwjmkbY9VP0nVIs8CXjqOeZ023s8AzR
+vR5zxo9dEVCIs2O8x8XrNnSPA/4aNtesXxiucxF/3IHcfHcX7CyRxdvMLRqg8a2q
+1LYdIu4ivUjJ8N9/AgMBAAGjgekwgeYwHQYDVR0OBBYEFObDVIVV8UT2S1XT6glp
+45X22ir6MB8GA1UdIwQYMBaAFOw/t5Ld6n2XpXciKOmYTQ0HacSGMD8GCCsGAQUF
BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEATsRasx8xTAR1+Lt9e+2T
-B4HjQblQsMQBBn1k88XYW5YOtsL6ZlAlechvbAPxe+ZzYMxoQg5DhVhGwlEnc93x
-bZ3ReoCX5c8MmoWhku0mOtYQ/RnI8vu5R+6pYxxSxZcaay/03JzLdIZqSCqHrCTV
-zIwrEp1tvH6+lT+IgxhodVnbefvwxzh7j6MW4ERMGePNNpj7/ckXXi+cDOG68m7A
-bpGdXsALldhifi6KLUz5tMoXDfDScbBNFXmwi56Wzy5EGoSnT2E4Z2EcoXCgpAJb
-QvWgCZXMIokNTuIb3R3+rteEWNvdBx2WazIR2sZW2c1pECVi/ZEtYw+Mgv4AiuuH
-Tw==
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAJ45BnPBcSuCwY8f6zB/U
+ITUzhxNotxgIDroioVEa2boxpzWAx3U1pGjIPpF5VeNgNHmhD6nMBZJhQLBmK/7H
+KaJU83xxtjb+qf17eepmGcAv0laXL8oSo5Zrs1fIBlhv3lPXY+6T1rLyEZyKoQAm
+bJq93dqX6gdhXkiO3T8QSznRmrqPFDCzNjyfpyxotDza8pAkSgMZOCRztXKzrjGz
+RJY2PTjFxwdieAbYXQEH2bMtvg9GE4wl+dfghF2kYqddOyLP5pWXINMkQMzPPXIX
++cGO7hVvmY8k0YNr+f5rlDqcLAJcHXDW+NZpDZn1U4lPIXumNN3OJ+9FpeDG5fX8
+Xw==
-----END CERTIFICATE-----
Certificate:
@@ -102,35 +102,35 @@ Certificate:
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
+ Subject: CN=Intermediate
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:c0:6b:09:c5:84:c2:5f:1b:c6:98:31:2d:a2:3e:
- 03:a9:13:4d:b8:4b:03:a6:1d:0a:e4:e1:ba:81:31:
- 2b:dd:92:7c:6b:81:85:c4:d4:cf:73:30:33:b2:8d:
- 9f:d9:0b:48:a0:70:51:88:93:d5:f1:ef:bd:14:6e:
- 7b:da:b6:a4:c5:a9:ca:cd:27:90:38:c8:5e:12:68:
- f8:f2:70:01:8a:da:e3:6c:2f:62:c4:67:40:e2:92:
- 20:fe:77:d9:91:f4:6b:02:0c:40:d6:b5:ef:98:85:
- 36:58:59:ec:e7:17:c8:72:53:8a:fc:2e:fa:08:70:
- ba:ab:ea:42:40:50:e0:6b:14:04:73:78:34:96:db:
- 8a:c9:22:21:f1:c1:1b:81:7c:95:c6:83:f8:d1:40:
- 1f:5d:ec:bc:d0:4e:30:7f:b2:07:b4:e2:be:3f:f7:
- 28:ab:a2:61:fd:98:3b:5a:1c:c9:61:30:13:ea:7c:
- 7d:13:99:a0:9a:a5:a5:72:3f:a7:e7:7d:3b:a6:b7:
- 09:6c:48:5c:ec:a3:d6:4c:2e:eb:21:e8:97:aa:44:
- 32:23:03:dd:24:8d:08:b4:94:df:65:5b:7c:45:59:
- 11:4b:ce:1f:78:e5:c4:bc:87:00:bb:c4:69:d7:3b:
- ae:a6:b7:80:df:4c:e2:0d:be:a4:0e:1c:05:5d:cf:
- dc:c9
+ 00:e4:7c:a3:bb:4c:6d:c3:5e:ae:62:cd:af:18:39:
+ c5:4b:6a:a3:fd:85:d0:ed:8b:25:93:bd:2b:06:22:
+ b2:6b:c1:ff:73:c9:26:dd:d6:eb:eb:ee:93:4a:6d:
+ df:10:02:b8:c5:72:d4:2f:c7:b4:1a:06:e9:38:b4:
+ 90:ae:9f:5f:69:45:47:07:68:17:b2:84:8a:65:b8:
+ 1e:ef:de:f1:b4:8a:6b:ab:de:55:79:5d:f5:2e:96:
+ 46:5b:5c:87:0b:4a:a8:53:70:4f:6f:f3:9e:9d:f4:
+ f8:38:fa:1f:a6:5f:a3:25:08:f2:e9:63:fc:3c:98:
+ 4d:91:df:77:60:e7:e2:bd:af:bb:d9:23:38:2d:6e:
+ 07:07:0c:1a:59:5e:8a:43:c7:da:b2:ce:39:3a:80:
+ c6:72:60:1f:d3:93:45:cd:63:b8:8b:96:bf:30:cd:
+ b1:f6:56:d7:a9:de:14:42:ae:42:40:f8:e9:7b:47:
+ a3:63:a1:5d:b9:2b:c0:3b:2b:81:56:11:54:ce:96:
+ 85:e6:3a:8c:66:ff:42:9f:ce:e4:a4:80:f5:59:8a:
+ 4b:ae:b2:37:c2:1f:45:9b:49:cd:db:0f:8b:a7:37:
+ 31:20:19:b4:42:20:aa:e9:e4:af:13:5a:b9:ea:d2:
+ 2c:9a:15:48:af:8d:ed:d0:fe:02:c0:a2:c6:47:bd:
+ dd:2f
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 7A:68:26:1F:EE:59:FA:52:EB:B0:98:D1:5D:F6:19:9F:8D:1C:F5:FB
+ EC:3F:B7:92:DD:EA:7D:97:A5:77:22:28:E9:98:4D:0D:07:69:C4:86
X509v3 Authority Key Identifier:
- keyid:66:52:63:09:9B:DD:07:2A:2D:E0:F3:6C:29:FB:D9:74:87:F5:02:6A
+ keyid:44:FC:9D:F0:51:F2:23:99:FE:A4:76:CB:CB:5C:39:BD:FC:68:38:45
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -145,41 +145,41 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- b2:03:09:bd:ed:73:cd:8d:d6:d0:f4:86:40:00:10:eb:b9:37:
- 74:1d:f2:b3:dc:2d:df:a4:75:77:f1:62:23:b8:2d:70:14:af:
- 33:4e:0c:8f:6d:13:db:d4:dc:92:04:8d:0e:b6:14:98:07:f6:
- 80:cb:9a:8d:d3:0e:9d:6d:13:12:c1:01:f0:14:9d:a3:c1:05:
- 45:3c:26:16:d2:39:3f:ed:3c:6c:ab:c0:2b:b2:21:29:dc:4b:
- 6b:51:cf:e9:99:ef:fa:14:3a:c4:f1:77:c0:83:f5:7f:af:11:
- 40:db:f3:3f:7c:18:26:79:e9:15:c0:62:79:06:85:15:8a:53:
- 03:be:2f:e9:5c:69:7c:c7:d7:47:6a:7b:00:c8:d8:4f:55:ce:
- d1:64:58:0f:87:ef:27:b2:7b:59:20:04:7d:4f:16:08:c7:d0:
- f0:c1:aa:b6:a9:ae:aa:fd:a7:98:2c:40:28:bb:e5:d7:91:e5:
- 72:c9:ab:0a:92:0e:b0:d5:ff:9c:db:73:5d:e1:9d:a5:fd:89:
- 4e:c8:26:8d:f8:76:0b:7e:7f:94:70:73:e4:22:b4:fb:2f:bc:
- 06:84:73:b1:99:78:fa:5f:e8:d7:20:8f:b9:cb:d9:a4:99:7e:
- be:b9:89:1c:07:0a:19:cb:0c:f0:15:70:81:51:ee:d7:8e:e8:
- f7:21:3f:fd
+ 40:21:7c:15:90:68:e9:aa:b0:ab:21:63:e7:21:f1:92:5b:75:
+ 02:34:b4:cd:06:b3:45:f4:93:07:d1:0f:f2:bc:92:ac:75:94:
+ 43:ad:a8:4f:91:6a:28:0c:cd:47:8d:01:de:54:51:aa:14:e3:
+ 35:f8:eb:d8:d4:59:f5:86:ef:55:e6:6f:54:17:47:c1:5f:e8:
+ be:0d:7f:34:d2:88:2d:b5:04:29:25:11:cc:a3:d7:0e:49:b2:
+ 9a:e3:01:1d:3f:15:89:68:41:19:4d:ee:8d:12:0e:96:ce:5e:
+ e5:08:31:64:4f:89:e0:91:1b:a9:b0:3c:4e:50:cb:83:a0:df:
+ d0:d3:df:af:53:d5:99:6b:88:dd:9c:4f:98:f1:0d:1d:f5:29:
+ f6:c5:be:18:84:4f:1f:76:ce:6f:c8:08:a0:f4:58:af:a3:ff:
+ cb:44:55:ad:2e:6e:e0:44:07:f4:a3:d4:08:9c:d1:0e:04:29:
+ 34:54:1b:bd:e8:e3:b4:56:e1:0b:05:bd:ee:6d:47:fb:10:42:
+ d2:14:12:e4:15:29:bd:06:13:7d:12:41:fa:5f:5d:01:27:69:
+ 99:76:ff:76:74:c8:c8:fe:11:c5:2e:67:44:d3:32:6d:8f:45:
+ e4:0a:5a:73:ef:74:75:6a:6c:d6:c2:c5:e8:73:bc:be:29:b3:
+ 3a:01:cf:02
-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwGsJxYTC
-XxvGmDEtoj4DqRNNuEsDph0K5OG6gTEr3ZJ8a4GFxNTPczAzso2f2QtIoHBRiJPV
-8e+9FG572rakxanKzSeQOMheEmj48nABitrjbC9ixGdA4pIg/nfZkfRrAgxA1rXv
-mIU2WFns5xfIclOK/C76CHC6q+pCQFDgaxQEc3g0ltuKySIh8cEbgXyVxoP40UAf
-Xey80E4wf7IHtOK+P/coq6Jh/Zg7WhzJYTAT6nx9E5mgmqWlcj+n5307prcJbEhc
-7KPWTC7rIeiXqkQyIwPdJI0ItJTfZVt8RVkRS84feOXEvIcAu8Rp1zuupreA30zi
-Db6kDhwFXc/cyQIDAQABo4HLMIHIMB0GA1UdDgQWBBR6aCYf7ln6UuuwmNFd9hmf
-jRz1+zAfBgNVHSMEGDAWgBRmUmMJm90HKi3g82wp+9l0h/UCajA3BggrBgEFBQcB
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5Hyju0xt
+w16uYs2vGDnFS2qj/YXQ7Yslk70rBiKya8H/c8km3dbr6+6TSm3fEAK4xXLUL8e0
+GgbpOLSQrp9faUVHB2gXsoSKZbge797xtIprq95VeV31LpZGW1yHC0qoU3BPb/Oe
+nfT4OPofpl+jJQjy6WP8PJhNkd93YOfiva+72SM4LW4HBwwaWV6KQ8fass45OoDG
+cmAf05NFzWO4i5a/MM2x9lbXqd4UQq5CQPjpe0ejY6FduSvAOyuBVhFUzpaF5jqM
+Zv9Cn87kpID1WYpLrrI3wh9Fm0nN2w+LpzcxIBm0QiCq6eSvE1q56tIsmhVIr43t
+0P4CwKLGR73dLwIDAQABo4HLMIHIMB0GA1UdDgQWBBTsP7eS3ep9l6V3IijpmE0N
+B2nEhjAfBgNVHSMEGDAWgBRE/J3wUfIjmf6kdsvLXDm9/Gg4RTA3BggrBgEFBQcB
AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
-ALIDCb3tc82N1tD0hkAAEOu5N3Qd8rPcLd+kdXfxYiO4LXAUrzNODI9tE9vU3JIE
-jQ62FJgH9oDLmo3TDp1tExLBAfAUnaPBBUU8JhbSOT/tPGyrwCuyISncS2tRz+mZ
-7/oUOsTxd8CD9X+vEUDb8z98GCZ56RXAYnkGhRWKUwO+L+lcaXzH10dqewDI2E9V
-ztFkWA+H7yeye1kgBH1PFgjH0PDBqraprqr9p5gsQCi75deR5XLJqwqSDrDV/5zb
-c13hnaX9iU7IJo34dgt+f5Rwc+QitPsvvAaEc7GZePpf6Ncgj7nL2aSZfr65iRwH
-ChnLDPAVcIFR7teO6PchP/0=
+AEAhfBWQaOmqsKshY+ch8ZJbdQI0tM0Gs0X0kwfRD/K8kqx1lEOtqE+RaigMzUeN
+Ad5UUaoU4zX469jUWfWG71Xmb1QXR8Ff6L4NfzTSiC21BCklEcyj1w5JsprjAR0/
+FYloQRlN7o0SDpbOXuUIMWRPieCRG6mwPE5Qy4Og39DT369T1ZlriN2cT5jxDR31
+KfbFvhiETx92zm/ICKD0WK+j/8tEVa0ubuBEB/Sj1Aic0Q4EKTRUG73o47RW4QsF
+ve5tR/sQQtIUEuQVKb0GE30SQfpfXQEnaZl2/3Z0yMj+EcUuZ0TTMm2PReQKWnPv
+dHVqbNbCxehzvL4pszoBzwI=
-----END CERTIFICATE-----
Certificate:
@@ -196,30 +196,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:bb:61:9d:50:28:51:f7:22:01:45:32:28:d0:d0:
- b2:c3:41:a4:3a:1f:8b:9a:b0:eb:61:31:39:1a:87:
- 5b:03:fb:02:82:15:8f:7f:d7:bb:4e:89:ae:08:df:
- 7e:6f:2f:66:87:8f:57:ab:a0:61:79:25:64:eb:20:
- 5d:e7:92:17:bd:c4:1b:e0:ea:27:e2:7b:b8:6e:05:
- 08:07:54:3d:4e:d6:80:8b:b9:50:d0:75:23:93:c3:
- e2:1b:de:f7:20:24:35:0f:d4:c3:dd:cf:07:19:29:
- 6f:08:08:a6:b3:9f:6d:2a:8b:3c:b7:6f:32:fe:81:
- 6d:1b:ad:88:96:c5:1f:a4:7a:a4:81:b5:e4:b3:9a:
- bc:42:b0:40:e5:77:8d:12:32:cc:d9:05:12:6a:47:
- 62:2b:22:5b:a8:48:fe:14:1a:a1:2f:03:34:f1:2b:
- 8f:d5:bf:3c:18:ae:f1:67:79:c8:a3:8d:29:d0:ce:
- 23:03:6f:ee:14:5e:97:dd:4d:c8:f5:1f:c4:1d:49:
- 08:b5:9c:7d:fa:e1:79:08:27:83:2d:8a:f4:43:d6:
- d6:6b:78:f4:0e:4c:42:57:72:03:61:73:b5:82:23:
- 98:2a:a9:06:f9:b3:95:cd:01:66:c2:3e:96:da:02:
- 13:95:e1:e6:51:94:67:2d:37:a5:cf:c1:18:62:fb:
- 56:15
+ 00:a0:21:1c:d1:00:97:80:26:4c:59:fe:1f:73:23:
+ 48:97:10:b0:7f:bb:bb:34:00:76:fb:5d:e6:1f:59:
+ ed:24:d9:25:9c:16:06:50:8e:83:da:d6:93:22:80:
+ 34:69:d3:d2:ee:98:9b:51:09:02:25:e4:04:fa:cc:
+ de:4f:f6:3d:9c:65:80:b3:83:19:dd:74:b7:3f:84:
+ 86:7f:77:f9:5b:bc:c9:5c:0d:98:3e:77:df:3b:f1:
+ 43:cd:3d:4a:88:81:76:08:cb:56:25:5f:ff:56:7e:
+ e1:e2:ab:41:60:9a:89:32:cf:9b:5e:3f:95:17:04:
+ 75:2d:a2:b7:e8:02:ea:6e:a0:2f:69:9f:30:a7:cd:
+ 7b:e6:e5:3d:98:01:51:b4:3e:c2:cf:87:f9:a1:e8:
+ 9d:69:43:91:37:58:b9:ec:2e:64:5f:76:21:e5:09:
+ 8c:6e:72:31:f4:c5:79:2f:14:1f:84:17:10:e3:50:
+ 0f:5d:d2:dd:f1:33:cb:57:f2:19:8c:04:96:e8:a7:
+ 3b:77:51:3a:6e:03:2b:29:2a:db:40:da:fb:41:f2:
+ bc:37:ef:31:5c:2b:0f:b2:f4:58:27:b6:0f:24:4d:
+ 1d:97:ca:bd:00:c8:5f:eb:c4:3d:5d:b7:9e:d6:58:
+ 45:8a:20:af:2f:16:fc:51:6c:55:66:24:19:21:66:
+ 38:9f
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 66:52:63:09:9B:DD:07:2A:2D:E0:F3:6C:29:FB:D9:74:87:F5:02:6A
+ 44:FC:9D:F0:51:F2:23:99:FE:A4:76:CB:CB:5C:39:BD:FC:68:38:45
X509v3 Authority Key Identifier:
- keyid:66:52:63:09:9B:DD:07:2A:2D:E0:F3:6C:29:FB:D9:74:87:F5:02:6A
+ keyid:44:FC:9D:F0:51:F2:23:99:FE:A4:76:CB:CB:5C:39:BD:FC:68:38:45
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -234,47 +234,57 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 09:c6:5a:c2:9c:aa:78:6d:66:79:43:2a:1c:a4:0b:04:42:8c:
- 54:6c:89:d7:ce:e0:fd:8e:33:5b:6c:2b:a2:ed:05:de:ea:3b:
- 11:21:bd:e9:23:45:bd:0f:e0:5c:fe:1b:11:8b:46:75:c1:24:
- 84:5a:95:15:a5:b3:73:86:6b:aa:8f:dc:46:3c:64:d9:60:9e:
- c1:7a:63:a3:d5:d6:b4:27:ed:c3:77:ea:5d:59:e7:93:05:df:
- be:58:4c:a5:92:52:61:11:d1:7f:27:e6:9b:29:3c:b8:9d:a0:
- 5c:d0:98:5f:a7:ed:39:14:f4:30:81:f6:0d:3b:cd:96:d6:dd:
- 7a:e2:b0:55:7c:ab:87:10:54:a6:5d:ac:27:5b:a6:a1:1e:ee:
- e7:26:cb:44:1d:fe:84:85:54:e0:cb:62:1b:5a:bb:ed:38:c0:
- f4:bd:1e:5d:ee:c6:d7:6e:b3:27:56:5c:8d:1f:dd:70:52:35:
- 8a:bc:07:0a:97:99:10:80:16:5b:a3:d1:de:f9:97:59:ca:5f:
- 42:10:c0:26:3e:6e:92:a9:6d:e5:09:1e:4c:92:4b:2e:a7:e8:
- 81:7f:e4:bb:b3:44:3c:71:e3:0c:ba:66:30:4a:fc:30:40:ce:
- 50:98:1b:61:52:91:02:84:ff:a1:a3:09:ad:1b:68:db:52:a6:
- cf:18:79:af
------BEGIN TRUSTED_CERTIFICATE-----
+ 94:de:4b:73:02:e3:22:7f:1e:82:0c:64:a8:de:79:70:34:96:
+ 9d:b5:e9:a0:51:bc:5c:3a:b1:97:7e:a4:0a:04:60:5a:3b:3a:
+ 88:7e:ff:67:1a:19:7f:61:c0:6a:f9:73:14:b4:6b:be:21:fd:
+ f3:e2:7a:61:56:73:15:9e:8d:c5:bb:21:47:8a:1f:fa:03:0d:
+ 0a:90:20:37:69:49:0b:2e:6a:9c:64:5b:e8:f0:ed:29:32:5f:
+ bc:f8:59:81:ad:d8:d9:71:ef:8d:bd:9c:ed:2e:c3:53:4f:12:
+ ec:f3:83:24:36:30:b1:c6:59:a7:2c:a8:6d:62:30:bc:a3:28:
+ 13:0a:09:ed:47:a9:f5:68:e9:97:33:b2:e7:e7:5c:f9:bb:c1:
+ 4b:7b:63:62:0a:0f:31:58:7e:24:88:30:f5:42:cf:3e:86:ca:
+ 48:5b:83:44:b0:04:fa:0b:e2:9c:8b:5f:9c:68:77:23:79:40:
+ 29:95:0d:6e:32:bf:ab:b4:ae:8a:2a:ca:f2:2a:92:a7:0d:b4:
+ 80:5d:ce:be:f8:68:24:00:d9:30:9c:de:ba:35:d4:22:b5:dd:
+ 15:37:70:bd:2e:7c:53:65:db:6f:1d:47:fa:53:56:dd:d0:9f:
+ e7:d5:d5:27:7f:c7:2e:9b:55:c2:70:1f:5e:66:b8:d1:2e:ac:
+ c6:e9:de:aa
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALthnVAoUfciAUUyKNDQ
-ssNBpDofi5qw62ExORqHWwP7AoIVj3/Xu06Jrgjffm8vZoePV6ugYXklZOsgXeeS
-F73EG+DqJ+J7uG4FCAdUPU7WgIu5UNB1I5PD4hve9yAkNQ/Uw93PBxkpbwgIprOf
-bSqLPLdvMv6BbRutiJbFH6R6pIG15LOavEKwQOV3jRIyzNkFEmpHYisiW6hI/hQa
-oS8DNPErj9W/PBiu8Wd5yKONKdDOIwNv7hRel91NyPUfxB1JCLWcffrheQgngy2K
-9EPW1mt49A5MQldyA2FztYIjmCqpBvmzlc0BZsI+ltoCE5Xh5lGUZy03pc/BGGL7
-VhUCAwEAAaOByzCByDAdBgNVHQ4EFgQUZlJjCZvdByot4PNsKfvZdIf1AmowHwYD
-VR0jBBgwFoAUZlJjCZvdByot4PNsKfvZdIf1AmowNwYIKwYBBQUHAQEEKzApMCcG
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKAhHNEAl4AmTFn+H3Mj
+SJcQsH+7uzQAdvtd5h9Z7STZJZwWBlCOg9rWkyKANGnT0u6Ym1EJAiXkBPrM3k/2
+PZxlgLODGd10tz+Ehn93+Vu8yVwNmD533zvxQ809SoiBdgjLViVf/1Z+4eKrQWCa
+iTLPm14/lRcEdS2it+gC6m6gL2mfMKfNe+blPZgBUbQ+ws+H+aHonWlDkTdYuewu
+ZF92IeUJjG5yMfTFeS8UH4QXEONQD13S3fEzy1fyGYwEluinO3dROm4DKykq20Da
++0HyvDfvMVwrD7L0WCe2DyRNHZfKvQDIX+vEPV23ntZYRYogry8W/FFsVWYkGSFm
+OJ8CAwEAAaOByzCByDAdBgNVHQ4EFgQURPyd8FHyI5n+pHbLy1w5vfxoOEUwHwYD
+VR0jBBgwFoAURPyd8FHyI5n+pHbLy1w5vfxoOEUwNwYIKwYBBQUHAQEEKzApMCcG
CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAJxlrCnKp4
-bWZ5QyocpAsEQoxUbInXzuD9jjNbbCui7QXe6jsRIb3pI0W9D+Bc/hsRi0Z1wSSE
-WpUVpbNzhmuqj9xGPGTZYJ7BemOj1da0J+3Dd+pdWeeTBd++WEylklJhEdF/J+ab
-KTy4naBc0Jhfp+05FPQwgfYNO82W1t164rBVfKuHEFSmXawnW6ahHu7nJstEHf6E
-hVTgy2IbWrvtOMD0vR5d7sbXbrMnVlyNH91wUjWKvAcKl5kQgBZbo9He+ZdZyl9C
-EMAmPm6SqW3lCR5Mkksup+iBf+S7s0Q8ceMMumYwSvwwQM5QmBthUpEChP+howmt
-G2jbUqbPGHmv
------END TRUSTED_CERTIFICATE-----
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCU3ktzAuMi
+fx6CDGSo3nlwNJadtemgUbxcOrGXfqQKBGBaOzqIfv9nGhl/YcBq+XMUtGu+If3z
+4nphVnMVno3FuyFHih/6Aw0KkCA3aUkLLmqcZFvo8O0pMl+8+FmBrdjZce+NvZzt
+LsNTTxLs84MkNjCxxlmnLKhtYjC8oygTCgntR6n1aOmXM7Ln51z5u8FLe2NiCg8x
+WH4kiDD1Qs8+hspIW4NEsAT6C+Kci1+caHcjeUAplQ1uMr+rtK6KKsryKpKnDbSA
+Xc6++GgkANkwnN66NdQitd0VN3C9LnxTZdtvHUf6U1bd0J/n1dUnf8cum1XCcB9e
+ZrjRLqzG6d6q
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+150301120000Z
-----BEGIN TIME-----
MTUwMzAxMTIwMDAwWg==
-----END TIME-----
+FAIL
-----BEGIN VERIFY_RESULT-----
RkFJTA==
-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 1
+ [Error] Time is before notBefore
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMQogICAgICBbRXJyb3JdIFRpbWUgaXMgYmVmb3JlIG5vdEJlZm9yZQo=
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/expired-target.pem b/chromium/net/data/verify_certificate_chain_unittest/expired-target.pem
index 8afcd0f3a7e..cb21f352b14 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/expired-target.pem
+++ b/chromium/net/data/verify_certificate_chain_unittest/expired-target.pem
@@ -1,6 +1,6 @@
[Created by: generate-expired-target.py]
-Certificate chain with 1 intermediary, where the target is expired (violates
+Certificate chain with 1 intermediate, where the target is expired (violates
validity.notAfter). Verification is expected to fail.
Certificate:
@@ -8,7 +8,7 @@ Certificate:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
+ Issuer: CN=Intermediate
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Mar 1 12:00:00 2015 GMT
@@ -17,80 +17,80 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:e3:02:17:8f:16:37:b7:e0:0b:44:86:f7:4f:de:
- 18:39:31:91:ed:11:80:67:c4:e0:18:7e:42:8e:be:
- dd:a9:0e:e7:ff:47:f2:1d:eb:a8:53:21:5b:c0:3e:
- 32:59:cf:31:24:e3:0f:00:4a:d2:f7:9a:77:31:10:
- 45:89:e3:e8:62:9c:c7:06:31:d0:c8:86:2b:3d:a7:
- 71:83:82:fa:c1:c2:cb:84:74:48:ad:c9:8a:4d:27:
- 1e:75:bb:4e:ce:54:3c:c1:b5:25:e5:02:d0:b3:8c:
- 14:f3:f5:9e:f8:30:20:ec:c6:d9:c4:a2:aa:06:f9:
- dc:ca:53:2f:76:cf:32:42:fd:7a:1a:c3:da:4a:d3:
- 82:30:84:f5:fb:02:82:f6:db:6e:87:fc:e8:69:14:
- a0:9f:2d:07:c4:ac:64:86:f5:ac:4b:22:f1:b0:d1:
- 91:2e:29:f7:cf:e0:10:aa:5d:cd:df:d7:a7:b9:9d:
- 72:cc:fd:16:d5:11:97:90:75:dc:5e:02:ab:7f:d3:
- dd:0a:a8:bc:5a:34:c6:8d:bb:8f:7a:04:d5:b6:99:
- 20:a4:72:c9:ba:00:cf:69:5e:e5:dd:bf:47:b3:3c:
- be:83:0d:4b:95:be:91:58:a4:a4:33:2e:3b:b8:da:
- 85:3d:74:66:8f:f9:0b:be:8e:9d:3e:b6:ca:8b:9b:
- 7e:19
+ 00:df:82:6a:2a:fe:30:47:00:84:06:de:48:a1:fc:
+ a5:d9:2c:d5:7d:e2:71:eb:ff:b5:7b:da:8c:c7:fc:
+ 38:8a:a3:64:5a:f8:01:70:e0:c0:26:d4:70:2c:08:
+ da:6b:5c:b4:40:41:aa:9e:b4:1d:05:9b:54:7c:54:
+ a4:b8:07:03:b0:69:95:98:c5:e6:7a:7f:71:6f:07:
+ dd:a5:21:59:79:7c:58:7c:00:0d:9d:18:6b:c0:3d:
+ 2d:fe:c6:63:58:c6:5f:29:47:01:b6:a2:dd:bb:f4:
+ 8a:8b:d0:15:3e:0b:01:18:34:0a:d4:a1:d3:e9:7a:
+ c3:5d:97:2b:c7:53:ff:49:81:34:fc:16:b4:02:f8:
+ 7c:55:6e:fa:9b:4f:cd:31:1a:f5:d2:5c:8f:92:d7:
+ bd:48:50:a9:b1:c4:89:cd:6d:c8:1d:99:77:34:d1:
+ d3:61:8f:b9:f8:3b:3e:c6:b3:2e:5f:3c:d0:f7:04:
+ 34:51:9f:83:4e:7b:1d:c9:59:53:81:6e:d9:f7:4b:
+ 36:dc:80:9e:b4:a4:cb:5d:18:1d:d3:52:3e:d8:b3:
+ 4e:28:c5:ba:2c:bd:dc:d1:e2:4a:21:e5:2a:ed:6f:
+ 97:84:a9:01:89:eb:2e:21:9e:b9:4a:6a:9b:c5:fe:
+ b0:5a:34:cf:25:0f:55:53:41:be:94:b9:8d:81:44:
+ fa:b5
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 1C:D2:85:3D:00:41:91:25:0B:8B:C2:CB:0E:D7:97:F1:14:8E:DE:01
+ A1:54:DE:B4:8A:C7:C9:C4:33:C6:9B:40:BF:3D:6E:CF:DB:47:EC:8C
X509v3 Authority Key Identifier:
- keyid:90:4B:3E:89:21:25:2A:3C:CA:35:BF:D9:A6:B1:CF:BC:1F:9D:3A:2F
+ keyid:13:F7:B3:D5:1C:C9:63:BD:3A:24:01:43:AE:4A:26:96:46:55:F5:F0
Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
X509v3 CRL Distribution Points:
Full Name:
- URI:http://url-for-crl/Intermediary.crl
+ URI:http://url-for-crl/Intermediate.crl
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 6d:36:b8:bc:75:67:0d:8a:5b:00:51:3b:06:31:af:83:23:80:
- a0:4f:eb:05:d6:5c:15:20:a3:10:7b:3e:31:0a:ba:45:b5:6b:
- 21:2b:02:bf:83:73:2c:cd:81:85:a0:38:ed:4e:bd:b7:36:dc:
- b6:69:bb:81:7b:75:74:3c:ac:5a:c2:59:74:6d:d9:64:8e:5b:
- 16:19:25:44:98:cb:9d:cd:a0:d4:6f:7f:d2:a3:11:cd:94:aa:
- b0:74:ee:c2:a3:3b:aa:98:e0:c5:0d:01:a4:f8:a2:84:ab:d0:
- db:19:9d:4d:ce:84:89:50:e8:3a:44:fb:e5:06:f3:d8:e9:d5:
- aa:81:69:af:2a:f2:9e:58:35:d5:3d:97:44:3a:79:47:22:d6:
- 9c:1b:b9:93:ea:3f:44:ac:cf:2a:54:52:86:0b:db:17:9d:f9:
- 4d:54:46:4d:af:21:92:cf:8a:01:52:14:07:96:c7:48:75:3c:
- 66:4d:74:fb:44:06:eb:a9:ab:12:2e:91:80:de:02:c1:12:5b:
- 32:76:36:46:13:16:00:31:76:c9:ee:64:e6:75:03:49:7d:63:
- d6:bf:f1:90:1f:b6:49:38:e5:af:37:63:46:e2:4d:d1:29:b8:
- b3:24:ec:f5:f8:32:c3:03:fa:1a:ad:30:1a:db:41:4d:5e:43:
- 46:ae:6d:4e
+ aa:f9:d5:79:52:fa:99:3e:d8:cd:ab:c3:e4:05:a9:85:c5:bf:
+ 78:3b:d6:14:0b:06:f4:62:77:8e:70:40:a5:b9:b4:46:52:5d:
+ 86:ad:52:52:f7:c3:1f:e9:e8:8a:e2:5b:23:63:bf:e8:5c:d8:
+ a6:11:ad:02:94:09:04:3b:67:cb:62:a3:09:67:eb:b3:68:0f:
+ 81:6d:0f:d6:4e:6c:d8:a3:e5:85:8f:8f:7e:65:a4:c7:d9:ba:
+ a8:05:22:2c:94:9d:8f:e4:d1:a5:5c:7e:c0:0f:39:3e:d7:b4:
+ 2c:df:d7:c1:ab:9e:5d:8d:28:51:d5:fa:2f:c6:fa:85:17:d4:
+ 05:d5:4d:d8:ee:6a:14:23:da:a0:cc:43:7b:65:54:71:e1:e1:
+ 79:b0:62:0a:a3:70:56:9b:53:5d:70:b7:78:6f:fd:ba:13:a7:
+ 99:0a:0a:b3:46:2a:7b:48:26:31:b2:50:aa:5e:29:d9:1b:55:
+ 1f:cb:de:2a:17:4d:ee:0d:67:2b:4e:dd:f6:54:d0:72:ec:e3:
+ 53:4e:24:26:a6:1e:17:e8:94:ca:a8:4a:3a:af:b8:48:51:1a:
+ 76:38:bd:bf:cb:c5:56:e4:a8:e4:f8:cb:cb:e9:97:ed:4e:b9:
+ af:fb:e7:92:d3:b7:ba:81:a0:13:e8:09:31:f3:45:91:2a:5c:
+ 93:12:a9:99
-----BEGIN CERTIFICATE-----
MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTUwMzAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDjAheP
-Fje34AtEhvdP3hg5MZHtEYBnxOAYfkKOvt2pDuf/R/Id66hTIVvAPjJZzzEk4w8A
-StL3mncxEEWJ4+hinMcGMdDIhis9p3GDgvrBwsuEdEityYpNJx51u07OVDzBtSXl
-AtCzjBTz9Z74MCDsxtnEoqoG+dzKUy92zzJC/Xoaw9pK04IwhPX7AoL2226H/Ohp
-FKCfLQfErGSG9axLIvGw0ZEuKffP4BCqXc3f16e5nXLM/RbVEZeQddxeAqt/090K
-qLxaNMaNu496BNW2mSCkcsm6AM9pXuXdv0ezPL6DDUuVvpFYpKQzLju42oU9dGaP
-+Qu+jp0+tsqLm34ZAgMBAAGjgekwgeYwHQYDVR0OBBYEFBzShT0AQZElC4vCyw7X
-l/EUjt4BMB8GA1UdIwQYMBaAFJBLPokhJSo8yjW/2aaxz7wfnTovMD8GCCsGAQUF
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTUwMzAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDfgmoq
+/jBHAIQG3kih/KXZLNV94nHr/7V72ozH/DiKo2Ra+AFw4MAm1HAsCNprXLRAQaqe
+tB0Fm1R8VKS4BwOwaZWYxeZ6f3FvB92lIVl5fFh8AA2dGGvAPS3+xmNYxl8pRwG2
+ot279IqL0BU+CwEYNArUodPpesNdlyvHU/9JgTT8FrQC+HxVbvqbT80xGvXSXI+S
+171IUKmxxInNbcgdmXc00dNhj7n4Oz7Gsy5fPND3BDRRn4NOex3JWVOBbtn3Szbc
+gJ60pMtdGB3TUj7Ys04oxbosvdzR4koh5Srtb5eEqQGJ6y4hnrlKapvF/rBaNM8l
+D1VTQb6UuY2BRPq1AgMBAAGjgekwgeYwHQYDVR0OBBYEFKFU3rSKx8nEM8abQL89
+bs/bR+yMMB8GA1UdIwQYMBaAFBP3s9UcyWO9OiQBQ65KJpZGVfXwMD8GCCsGAQUF
BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAbTa4vHVnDYpbAFE7BjGv
-gyOAoE/rBdZcFSCjEHs+MQq6RbVrISsCv4NzLM2BhaA47U69tzbctmm7gXt1dDys
-WsJZdG3ZZI5bFhklRJjLnc2g1G9/0qMRzZSqsHTuwqM7qpjgxQ0BpPiihKvQ2xmd
-Tc6EiVDoOkT75Qbz2OnVqoFpryrynlg11T2XRDp5RyLWnBu5k+o/RKzPKlRShgvb
-F535TVRGTa8hks+KAVIUB5bHSHU8Zk10+0QG66mrEi6RgN4CwRJbMnY2RhMWADF2
-ye5k5nUDSX1j1r/xkB+2STjlrzdjRuJN0Sm4syTs9fgywwP6Gq0wGttBTV5DRq5t
-Tg==
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAqvnVeVL6mT7YzavD5AWp
+hcW/eDvWFAsG9GJ3jnBApbm0RlJdhq1SUvfDH+noiuJbI2O/6FzYphGtApQJBDtn
+y2KjCWfrs2gPgW0P1k5s2KPlhY+PfmWkx9m6qAUiLJSdj+TRpVx+wA85Pte0LN/X
+waueXY0oUdX6L8b6hRfUBdVN2O5qFCPaoMxDe2VUceHhebBiCqNwVptTXXC3eG/9
+uhOnmQoKs0Yqe0gmMbJQql4p2RtVH8veKhdN7g1nK07d9lTQcuzjU04kJqYeF+iU
+yqhKOq+4SFEadji9v8vFVuSo5PjLy+mX7U65r/vnktO3uoGgE+gJMfNFkSpckxKp
+mQ==
-----END CERTIFICATE-----
Certificate:
@@ -102,35 +102,35 @@ Certificate:
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
+ Subject: CN=Intermediate
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:c1:92:e2:bf:d0:e9:8f:c6:45:f0:c9:ef:51:cc:
- 97:cc:cb:80:ac:c1:7c:da:7e:28:12:0c:84:45:6b:
- db:fb:4f:ba:16:3e:33:8b:a1:14:70:42:99:ca:4e:
- 8e:55:ac:13:e5:ac:d4:30:9e:25:dc:19:d9:b9:de:
- 46:7a:84:80:29:bd:a1:11:f8:f2:af:ce:c1:0c:73:
- 43:29:37:c3:76:61:32:70:6d:e7:29:bf:dd:9f:68:
- ed:9e:c2:b9:8c:f6:16:7c:b9:06:4b:65:ff:57:26:
- 9d:62:48:ee:0b:0f:4c:5e:fb:d7:a9:e3:d8:4b:a9:
- 0c:01:b6:00:f8:48:27:64:03:b6:73:d0:85:10:92:
- 4c:50:f8:f4:33:95:ea:52:30:72:b0:c1:e1:d3:1e:
- 8e:67:2a:64:42:c8:61:b8:3f:76:d2:01:1d:e6:dc:
- d2:66:09:41:24:c3:22:b4:55:3a:f0:5e:3d:82:af:
- 5d:0d:b7:d7:96:02:dc:94:e4:d2:24:dc:49:f8:d3:
- dc:b9:78:0e:ce:cf:8f:1a:3f:06:8b:57:e4:51:91:
- 7f:64:1b:cd:db:4d:80:88:26:21:dc:da:64:ae:64:
- bb:03:21:1c:de:ce:44:eb:a7:b4:43:50:51:cc:67:
- da:16:91:93:94:e4:d0:ed:28:dc:8a:16:8b:3d:d8:
- cd:19
+ 00:ba:33:55:c9:1e:c0:91:17:3a:eb:30:8c:ed:23:
+ cc:1d:6d:1e:e7:6e:4e:ac:23:63:23:ae:48:87:13:
+ 61:0f:0c:0b:ee:72:f7:c2:7b:95:2e:7b:25:34:08:
+ b6:e1:f5:ae:50:bf:8f:cf:81:6e:e6:26:9f:92:61:
+ c4:fb:44:9e:23:09:df:13:80:bc:38:5b:db:08:6c:
+ 68:60:46:d4:e3:e0:41:91:c4:42:d5:d9:75:d2:c4:
+ df:29:b8:04:bb:96:dc:9d:e4:0b:f7:de:ab:cf:90:
+ ad:22:c8:ab:56:65:84:00:3b:b9:e6:29:b5:e2:96:
+ 88:bd:95:e5:10:6d:57:ab:be:d1:f4:61:bb:1d:b4:
+ 7f:f9:02:db:48:d3:21:9d:f1:03:77:bf:f9:ca:f3:
+ 4e:2d:44:1c:28:1d:c5:4f:30:1b:0a:8b:71:0e:5f:
+ 86:0a:3f:97:7f:47:a6:a2:3c:60:02:c6:e8:bd:e9:
+ 52:b1:0b:cb:53:d4:09:f4:b6:20:23:b4:89:09:ff:
+ 1a:61:e8:dd:ac:19:4d:be:94:1e:60:24:d4:6c:89:
+ 03:3a:c4:44:5b:dd:7c:59:37:b7:0c:83:40:24:0e:
+ ed:ab:02:cf:cd:93:d2:3d:5d:e0:c6:c4:c5:1d:1a:
+ 01:d1:e1:77:58:62:90:e1:83:af:d2:ee:31:f3:29:
+ 0c:1f
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 90:4B:3E:89:21:25:2A:3C:CA:35:BF:D9:A6:B1:CF:BC:1F:9D:3A:2F
+ 13:F7:B3:D5:1C:C9:63:BD:3A:24:01:43:AE:4A:26:96:46:55:F5:F0
X509v3 Authority Key Identifier:
- keyid:C3:6A:BF:B8:BB:62:64:F0:4C:4C:28:47:94:45:0F:15:0D:DC:CD:5A
+ keyid:5F:B1:E2:C5:58:EB:EF:73:DC:15:A3:0F:8E:24:0C:6C:67:65:00:04
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -145,41 +145,41 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- bd:cb:4f:22:e2:7a:50:05:dd:e3:d6:41:19:2b:6d:4a:3e:a8:
- 90:27:4f:ce:eb:ee:83:4f:d5:b6:ea:a5:18:1c:00:83:84:76:
- 92:76:a7:2c:54:5f:94:a7:fc:4c:2f:38:08:c5:24:3f:95:57:
- e4:55:e2:a5:96:b7:c0:7b:cc:8f:ce:a1:81:e2:d2:51:17:d3:
- 7f:6b:76:ed:f5:41:2a:7a:56:e2:d1:ed:55:94:38:2e:9f:cb:
- 9b:a3:8b:d8:d7:42:24:81:55:97:82:a1:77:52:7c:1f:70:db:
- 0b:bf:a5:eb:96:2e:d4:fb:9c:d5:6a:6e:9b:60:75:01:e1:fe:
- f1:14:64:42:82:2a:f5:ea:b3:e1:2e:40:fe:b2:af:9f:c5:66:
- 25:d8:7d:8c:5f:00:3d:04:b4:02:8c:c7:99:30:d0:c0:02:e4:
- 5f:3b:75:01:59:76:1c:3c:95:5b:28:49:90:2f:c0:af:45:f0:
- 4c:62:ca:40:66:80:7e:25:89:ab:91:55:ee:41:71:af:05:4c:
- 7e:31:2c:99:24:50:c9:dd:97:79:73:97:f9:5a:79:79:05:ff:
- c6:83:b7:e3:4d:86:b6:a3:60:1d:7c:e6:89:80:a3:50:8f:b1:
- 4a:43:d2:a9:89:92:8b:38:20:71:64:0a:41:8b:fd:2f:4b:ab:
- 3c:45:99:0f
+ a5:43:87:2e:d0:2c:51:df:a7:aa:48:b4:38:fc:1d:6f:c9:db:
+ 23:32:75:f2:d1:52:45:ea:4a:89:1f:e9:10:0c:22:0d:70:3e:
+ f0:c1:cf:b7:a8:cd:af:d4:33:99:14:6e:62:b9:a8:0f:a6:2c:
+ 75:dd:d8:79:88:fc:cb:c4:7e:64:b1:2f:7a:0b:b2:a4:6c:82:
+ 29:7d:23:32:d3:de:a8:90:a8:77:f8:33:13:e9:3e:42:0b:32:
+ e8:50:e0:af:31:2f:b9:e5:be:b7:c7:16:ca:a7:96:9e:95:24:
+ d2:c1:b3:df:70:5f:7b:8a:33:6b:55:76:e8:18:32:66:0e:9a:
+ 60:cf:dc:30:1e:38:15:05:6e:cc:4a:1e:e7:2e:e0:5a:de:ea:
+ 84:a1:ce:04:fd:db:74:d6:fe:b6:4d:6b:86:38:22:78:f1:3e:
+ ba:dc:8b:85:a6:2f:56:10:1f:7d:b8:96:00:4c:d6:a3:fa:93:
+ fd:1b:29:64:40:7c:f8:65:3f:73:8a:7e:3e:72:c7:ce:19:74:
+ 51:21:26:5d:2d:41:a0:95:c9:8f:70:fd:2a:60:7a:b0:fc:e5:
+ 14:65:9a:3e:68:2c:4a:47:1b:5a:97:8a:31:a9:1a:1a:c9:fc:
+ e3:be:c9:dd:65:0f:33:2b:f9:d9:68:5b:54:22:c4:dc:a6:21:
+ 42:6c:ec:64
-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwZLiv9Dp
-j8ZF8MnvUcyXzMuArMF82n4oEgyERWvb+0+6Fj4zi6EUcEKZyk6OVawT5azUMJ4l
-3BnZud5GeoSAKb2hEfjyr87BDHNDKTfDdmEycG3nKb/dn2jtnsK5jPYWfLkGS2X/
-VyadYkjuCw9MXvvXqePYS6kMAbYA+EgnZAO2c9CFEJJMUPj0M5XqUjBysMHh0x6O
-ZypkQshhuD920gEd5tzSZglBJMMitFU68F49gq9dDbfXlgLclOTSJNxJ+NPcuXgO
-zs+PGj8Gi1fkUZF/ZBvN202AiCYh3NpkrmS7AyEc3s5E66e0Q1BRzGfaFpGTlOTQ
-7SjcihaLPdjNGQIDAQABo4HLMIHIMB0GA1UdDgQWBBSQSz6JISUqPMo1v9mmsc+8
-H506LzAfBgNVHSMEGDAWgBTDar+4u2Jk8ExMKEeURQ8VDdzNWjA3BggrBgEFBQcB
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAujNVyR7A
+kRc66zCM7SPMHW0e525OrCNjI65IhxNhDwwL7nL3wnuVLnslNAi24fWuUL+Pz4Fu
+5iafkmHE+0SeIwnfE4C8OFvbCGxoYEbU4+BBkcRC1dl10sTfKbgEu5bcneQL996r
+z5CtIsirVmWEADu55im14paIvZXlEG1Xq77R9GG7HbR/+QLbSNMhnfEDd7/5yvNO
+LUQcKB3FTzAbCotxDl+GCj+Xf0emojxgAsbovelSsQvLU9QJ9LYgI7SJCf8aYejd
+rBlNvpQeYCTUbIkDOsREW918WTe3DINAJA7tqwLPzZPSPV3gxsTFHRoB0eF3WGKQ
+4YOv0u4x8ykMHwIDAQABo4HLMIHIMB0GA1UdDgQWBBQT97PVHMljvTokAUOuSiaW
+RlX18DAfBgNVHSMEGDAWgBRfseLFWOvvc9wVow+OJAxsZ2UABDA3BggrBgEFBQcB
AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
-AL3LTyLielAF3ePWQRkrbUo+qJAnT87r7oNP1bbqpRgcAIOEdpJ2pyxUX5Sn/Ewv
-OAjFJD+VV+RV4qWWt8B7zI/OoYHi0lEX039rdu31QSp6VuLR7VWUOC6fy5uji9jX
-QiSBVZeCoXdSfB9w2wu/peuWLtT7nNVqbptgdQHh/vEUZEKCKvXqs+EuQP6yr5/F
-ZiXYfYxfAD0EtAKMx5kw0MAC5F87dQFZdhw8lVsoSZAvwK9F8ExiykBmgH4liauR
-Ve5Bca8FTH4xLJkkUMndl3lzl/laeXkF/8aDt+NNhrajYB185omAo1CPsUpD0qmJ
-kos4IHFkCkGL/S9LqzxFmQ8=
+AKVDhy7QLFHfp6pItDj8HW/J2yMydfLRUkXqSokf6RAMIg1wPvDBz7eoza/UM5kU
+bmK5qA+mLHXd2HmI/MvEfmSxL3oLsqRsgil9IzLT3qiQqHf4MxPpPkILMuhQ4K8x
+L7nlvrfHFsqnlp6VJNLBs99wX3uKM2tVdugYMmYOmmDP3DAeOBUFbsxKHucu4Fre
+6oShzgT923TW/rZNa4Y4InjxPrrci4WmL1YQH324lgBM1qP6k/0bKWRAfPhlP3OK
+fj5yx84ZdFEhJl0tQaCVyY9w/SpgerD85RRlmj5oLEpHG1qXijGpGhrJ/OO+yd1l
+DzMr+dloW1QixNymIUJs7GQ=
-----END CERTIFICATE-----
Certificate:
@@ -196,30 +196,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:fa:da:12:88:da:6c:4d:a4:17:2e:e6:c7:c7:f6:
- fc:0b:41:94:b9:ad:5e:72:7f:53:82:c3:9b:bd:f0:
- 39:fd:6c:be:42:2f:28:fe:76:7e:e6:24:f7:6b:32:
- 42:c7:0e:6f:b3:9b:4d:61:ab:f3:f1:76:67:29:77:
- a5:6a:b9:64:65:40:42:0a:ad:dc:27:16:7a:94:ae:
- 8f:f0:d2:db:e7:7c:71:21:c9:ca:f0:64:94:58:32:
- b7:fa:d3:27:bc:84:95:ce:d2:81:43:dc:7d:b3:e8:
- 76:aa:eb:0a:a6:c1:03:1f:ae:19:db:8a:c4:ef:a1:
- bd:f3:d6:e9:e7:20:a8:83:1c:78:d5:85:c2:be:9f:
- c9:e2:4e:ab:e6:a8:53:6b:c7:5d:d6:57:6f:4f:2d:
- db:75:89:c6:10:a3:96:36:22:8d:c3:0a:20:7b:5f:
- 75:04:a6:4a:8d:24:d3:21:0b:16:fe:70:ae:34:d4:
- bd:33:27:86:cb:b3:c8:b8:9a:80:70:0c:01:38:af:
- e8:dc:0a:32:ca:a8:da:6c:a7:0a:2d:f3:b6:f7:cb:
- 7f:ea:59:38:66:ce:9d:93:f2:75:89:d3:5f:43:5c:
- 9b:29:1c:d4:e9:37:6d:7c:79:ee:ad:c9:70:62:58:
- 4f:25:f6:21:20:44:a8:0b:c6:52:9d:2f:ea:a5:f8:
- b3:cf
+ 00:df:9c:45:02:46:38:eb:d4:64:cd:8e:95:65:63:
+ d5:e6:71:8b:67:13:d8:bc:6d:64:73:d7:40:17:79:
+ 80:a4:8d:8e:5f:bf:5e:48:b0:2f:bc:49:08:71:b4:
+ 80:38:00:cd:e9:ee:2e:6e:73:8a:77:56:b4:b3:d0:
+ e3:0c:40:c9:ca:1f:9b:a0:89:68:07:34:cd:f4:f4:
+ b9:a2:c1:ca:42:0e:da:90:cf:95:89:3a:3c:de:ad:
+ a6:ff:49:6c:e2:5e:f5:0b:ff:be:06:ee:ab:e1:81:
+ e9:da:a3:b8:d5:63:af:5e:10:63:49:23:0a:1d:ca:
+ 3e:bc:96:6e:82:5c:4f:ce:56:a7:8f:53:34:65:cb:
+ 47:88:3e:38:4d:71:b6:8a:06:e4:ed:4f:d2:df:59:
+ 3e:a7:03:a7:be:c2:14:a6:cf:9e:4b:c8:a3:25:21:
+ b2:3e:f8:cd:65:de:fc:0e:52:fd:fa:cf:d3:07:af:
+ 79:53:11:bf:e6:77:ce:d8:1a:4b:4f:cb:d2:35:28:
+ f8:5a:4b:05:a2:dd:88:e1:54:ac:1a:15:8d:54:a2:
+ b7:ac:66:7a:f8:4a:2a:75:94:15:b3:44:c2:05:ff:
+ e3:a0:34:40:84:00:39:6d:6d:e1:8e:16:f3:d3:60:
+ 2b:95:2f:fc:74:6e:b1:83:b7:0b:9d:9e:d8:34:45:
+ 21:f7
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- C3:6A:BF:B8:BB:62:64:F0:4C:4C:28:47:94:45:0F:15:0D:DC:CD:5A
+ 5F:B1:E2:C5:58:EB:EF:73:DC:15:A3:0F:8E:24:0C:6C:67:65:00:04
X509v3 Authority Key Identifier:
- keyid:C3:6A:BF:B8:BB:62:64:F0:4C:4C:28:47:94:45:0F:15:0D:DC:CD:5A
+ keyid:5F:B1:E2:C5:58:EB:EF:73:DC:15:A3:0F:8E:24:0C:6C:67:65:00:04
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -234,47 +234,57 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 48:d9:ed:17:dd:a3:7c:5f:6b:aa:90:6d:f5:d4:61:a3:27:8e:
- 83:92:15:7a:6c:d7:87:71:95:6a:e4:e0:d9:11:4e:2a:af:14:
- 5c:11:ba:a0:2e:15:bd:f0:c6:2d:72:0a:17:ce:02:1a:3b:61:
- 16:5d:1a:ff:e8:45:4d:d6:f2:93:9d:09:ce:e6:ec:a8:c8:de:
- e6:40:dc:26:cc:15:89:38:b9:59:06:27:d0:93:af:0e:83:08:
- 9f:c3:50:1c:b1:e0:88:69:b2:43:61:c3:4c:bc:d9:19:d7:87:
- 57:c3:e6:99:7b:f0:02:09:ac:e1:f0:a1:55:d5:53:0c:fc:c4:
- b3:3c:49:67:30:70:d5:c7:cd:94:a6:07:f0:cd:89:fd:68:b4:
- 29:9d:63:91:f6:bf:79:da:6a:93:6d:b5:52:57:d8:1a:62:18:
- 9f:ed:71:5c:d2:5d:53:0b:04:56:5c:05:81:6b:16:9a:dd:ff:
- fe:5d:98:32:97:07:c1:7b:9c:d5:08:07:2e:b9:17:ab:1e:a3:
- ea:64:b1:02:1b:04:ca:5f:4c:fd:1f:45:91:d9:f6:de:c7:78:
- 9d:aa:5d:b7:cc:6f:58:7f:2d:71:cc:5c:3a:8c:e5:db:51:3e:
- af:77:1f:d1:e1:81:cb:74:c0:36:46:be:51:4e:55:94:98:65:
- 7d:33:c0:5e
------BEGIN TRUSTED_CERTIFICATE-----
+ 98:24:67:cd:0c:c3:0f:c5:09:c1:b3:b2:c3:eb:90:d5:1b:7e:
+ ce:45:7e:e8:f9:ae:bd:54:46:58:4e:0f:b3:65:30:45:98:3e:
+ 02:bf:a0:a9:e6:9c:69:f7:94:c8:bc:3d:33:ed:ac:52:5e:65:
+ 58:f1:ef:4d:bd:bf:39:65:62:e1:75:35:b2:27:92:fa:9b:3d:
+ 92:ed:51:f3:73:9a:73:2f:2f:61:2a:1d:34:e0:a1:fa:fc:b3:
+ dc:24:40:af:14:fd:d5:26:d0:5e:cb:fd:05:8b:88:f5:5c:0f:
+ 6f:75:68:c5:32:f1:1d:cd:a2:be:b2:66:0c:1a:4c:d6:df:1b:
+ e4:09:b9:bf:32:41:59:ca:bc:48:33:b1:ec:6a:fa:4d:dc:72:
+ ae:96:15:29:35:78:85:96:f9:64:05:75:50:b3:3e:b0:f8:15:
+ 7c:06:54:ff:36:98:2a:6d:4f:33:b0:78:1c:d3:be:12:2d:5b:
+ b4:37:2b:04:1b:d8:ce:28:db:9c:6d:49:e8:6f:f6:45:75:0a:
+ fb:69:dc:71:63:cd:c6:17:84:4b:8a:14:a0:ef:42:6a:6f:f2:
+ a8:76:e9:c6:4b:94:d2:24:f5:aa:80:d2:b6:81:17:c6:7d:7d:
+ 88:36:fe:26:44:cf:36:5a:5e:de:c4:34:da:54:1e:89:1f:d6:
+ 98:9e:3c:f7
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPraEojabE2kFy7mx8f2
-/AtBlLmtXnJ/U4LDm73wOf1svkIvKP52fuYk92syQscOb7ObTWGr8/F2Zyl3pWq5
-ZGVAQgqt3CcWepSuj/DS2+d8cSHJyvBklFgyt/rTJ7yElc7SgUPcfbPodqrrCqbB
-Ax+uGduKxO+hvfPW6ecgqIMceNWFwr6fyeJOq+aoU2vHXdZXb08t23WJxhCjljYi
-jcMKIHtfdQSmSo0k0yELFv5wrjTUvTMnhsuzyLiagHAMATiv6NwKMsqo2mynCi3z
-tvfLf+pZOGbOnZPydYnTX0Ncmykc1Ok3bXx57q3JcGJYTyX2ISBEqAvGUp0v6qX4
-s88CAwEAAaOByzCByDAdBgNVHQ4EFgQUw2q/uLtiZPBMTChHlEUPFQ3czVowHwYD
-VR0jBBgwFoAUw2q/uLtiZPBMTChHlEUPFQ3czVowNwYIKwYBBQUHAQEEKzApMCcG
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN+cRQJGOOvUZM2OlWVj
+1eZxi2cT2LxtZHPXQBd5gKSNjl+/XkiwL7xJCHG0gDgAzenuLm5zindWtLPQ4wxA
+ycofm6CJaAc0zfT0uaLBykIO2pDPlYk6PN6tpv9JbOJe9Qv/vgbuq+GB6dqjuNVj
+r14QY0kjCh3KPryWboJcT85Wp49TNGXLR4g+OE1xtooG5O1P0t9ZPqcDp77CFKbP
+nkvIoyUhsj74zWXe/A5S/frP0weveVMRv+Z3ztgaS0/L0jUo+FpLBaLdiOFUrBoV
+jVSit6xmevhKKnWUFbNEwgX/46A0QIQAOW1t4Y4W89NgK5Uv/HRusYO3C52e2DRF
+IfcCAwEAAaOByzCByDAdBgNVHQ4EFgQUX7HixVjr73PcFaMPjiQMbGdlAAQwHwYD
+VR0jBBgwFoAUX7HixVjr73PcFaMPjiQMbGdlAAQwNwYIKwYBBQUHAQEEKzApMCcG
CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBI2e0X3aN8
-X2uqkG311GGjJ46DkhV6bNeHcZVq5ODZEU4qrxRcEbqgLhW98MYtcgoXzgIaO2EW
-XRr/6EVN1vKTnQnO5uyoyN7mQNwmzBWJOLlZBifQk68Ogwifw1AcseCIabJDYcNM
-vNkZ14dXw+aZe/ACCazh8KFV1VMM/MSzPElnMHDVx82UpgfwzYn9aLQpnWOR9r95
-2mqTbbVSV9gaYhif7XFc0l1TCwRWXAWBaxaa3f/+XZgylwfBe5zVCAcuuRerHqPq
-ZLECGwTKX0z9H0WR2fbex3idql23zG9Yfy1xzFw6jOXbUT6vdx/R4YHLdMA2Rr5R
-TlWUmGV9M8Be
------END TRUSTED_CERTIFICATE-----
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCYJGfNDMMP
+xQnBs7LD65DVG37ORX7o+a69VEZYTg+zZTBFmD4Cv6Cp5pxp95TIvD0z7axSXmVY
+8e9Nvb85ZWLhdTWyJ5L6mz2S7VHzc5pzLy9hKh004KH6/LPcJECvFP3VJtBey/0F
+i4j1XA9vdWjFMvEdzaK+smYMGkzW3xvkCbm/MkFZyrxIM7HsavpN3HKulhUpNXiF
+lvlkBXVQsz6w+BV8BlT/NpgqbU8zsHgc074SLVu0NysEG9jOKNucbUnob/ZFdQr7
+adxxY83GF4RLihSg70Jqb/KodunGS5TSJPWqgNK2gRfGfX2INv4mRM82Wl7exDTa
+VB6JH9aYnjz3
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+150302120000Z
-----BEGIN TIME-----
MTUwMzAyMTIwMDAwWg==
-----END TIME-----
+FAIL
-----BEGIN VERIFY_RESULT-----
RkFJTA==
-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 1
+ [Error] Time is after notAfter
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMQogICAgICBbRXJyb3JdIFRpbWUgaXMgYWZ0ZXIgbm90QWZ0ZXIK
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/expired-unconstrained-root.pem b/chromium/net/data/verify_certificate_chain_unittest/expired-unconstrained-root.pem
new file mode 100644
index 00000000000..cdb2edebb3a
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/expired-unconstrained-root.pem
@@ -0,0 +1,284 @@
+[Created by: generate-expired-unconstrained-root.py]
+
+Certificate chain with 1 intermediate, where the root certificate is expired
+(violates validity.notAfter). Verification is expected to succeed as
+the trust anchor has no constraints (so expiration of the certificate is not
+enforced).
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b3:fa:1c:ab:da:95:23:00:c5:f7:9d:3e:fa:be:
+ 50:46:36:b3:b8:6c:9b:ed:57:22:ae:c1:19:65:f5:
+ 53:9b:55:48:bd:9f:59:95:8f:a6:a8:33:25:87:f8:
+ 69:be:58:ac:73:1f:aa:5b:0d:8d:ed:65:53:a8:fd:
+ a4:99:92:d7:9f:a2:ce:9d:09:a7:af:65:dd:e7:1c:
+ 18:9d:61:6e:3f:05:7c:09:10:03:50:90:03:3a:20:
+ 7c:b5:80:f3:16:8b:d8:1e:c9:e4:53:5d:1c:6e:e2:
+ b3:b3:9d:87:fa:2b:47:25:fe:ee:8b:4e:22:35:cc:
+ 22:59:94:78:13:57:67:69:ab:99:14:70:94:2c:0e:
+ 32:e3:bc:89:b4:e4:b1:09:4b:ae:bd:6d:7e:cd:a8:
+ ff:ee:37:8b:1a:25:5e:ae:21:51:e2:cb:9c:6a:a5:
+ 27:23:62:c7:62:89:a1:69:13:c3:03:ec:f9:a7:5a:
+ 90:e2:e0:c5:c7:6d:ec:76:f5:76:88:f5:15:1a:4d:
+ 00:da:38:51:ea:03:16:a4:90:74:87:6e:ba:23:3a:
+ 91:58:a0:94:6c:3c:8c:f1:c6:2f:69:9e:41:1a:50:
+ ea:3b:d1:a6:d2:9b:50:04:63:ca:b7:c1:eb:04:07:
+ 89:40:43:07:1e:84:d5:6c:08:01:50:7f:7b:aa:9e:
+ c4:4d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ BD:E0:2F:8E:DD:4A:65:2F:EE:52:E4:0F:3B:8A:28:80:D6:17:C4:76
+ X509v3 Authority Key Identifier:
+ keyid:A8:9E:04:25:6D:55:C9:D7:11:47:D3:DD:67:71:0E:7E:88:89:49:71
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 95:07:d3:f3:57:d3:2d:c3:f9:d5:4a:d4:54:85:1f:25:3d:3c:
+ e8:34:6f:6e:bc:5a:b3:50:fd:4f:b5:cf:87:54:26:7b:ab:4d:
+ 5d:28:af:29:d1:24:ad:75:5d:3f:5b:68:63:b3:c0:20:82:8e:
+ c4:7f:58:7c:74:ea:d8:0d:50:11:63:43:ee:67:af:9f:16:c3:
+ 89:f1:15:a6:94:a9:72:bb:0c:40:48:54:25:87:e7:94:6f:34:
+ f5:83:03:ed:2a:6f:b6:2d:b7:70:4d:8b:6e:31:80:0c:dd:3d:
+ 9a:84:5a:55:ce:b7:08:a9:15:59:66:ec:a9:a1:4f:79:73:16:
+ a2:6a:44:1f:7a:6d:69:f2:de:a0:50:07:da:01:4b:22:2e:40:
+ f4:8b:e7:7c:f3:cd:27:fd:92:eb:fd:e8:4a:da:32:91:6a:ec:
+ b8:0c:49:db:f8:73:5e:a4:83:a2:c2:40:dd:e0:78:f9:3c:83:
+ 39:e4:22:88:7c:d1:cf:58:4a:4c:f1:0b:4f:21:94:c4:fb:4e:
+ a8:c4:84:ce:6a:7c:ff:0c:9b:1f:c6:db:67:22:6d:29:2f:28:
+ 81:60:c2:a3:ab:af:fa:f9:a5:55:83:35:97:1d:17:23:2a:32:
+ 75:92:7b:2b:67:99:3c:25:f4:b5:c8:74:ac:05:7e:59:43:5c:
+ 47:38:16:9b
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+hyr
+2pUjAMX3nT76vlBGNrO4bJvtVyKuwRll9VObVUi9n1mVj6aoMyWH+Gm+WKxzH6pb
+DY3tZVOo/aSZktefos6dCaevZd3nHBidYW4/BXwJEANQkAM6IHy1gPMWi9geyeRT
+XRxu4rOznYf6K0cl/u6LTiI1zCJZlHgTV2dpq5kUcJQsDjLjvIm05LEJS669bX7N
+qP/uN4saJV6uIVHiy5xqpScjYsdiiaFpE8MD7PmnWpDi4MXHbex29XaI9RUaTQDa
+OFHqAxakkHSHbrojOpFYoJRsPIzxxi9pnkEaUOo70abSm1AEY8q3wesEB4lAQwce
+hNVsCAFQf3uqnsRNAgMBAAGjgekwgeYwHQYDVR0OBBYEFL3gL47dSmUv7lLkDzuK
+KIDWF8R2MB8GA1UdIwQYMBaAFKieBCVtVcnXEUfT3WdxDn6IiUlxMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAlQfT81fTLcP51UrUVIUf
+JT086DRvbrxas1D9T7XPh1Qme6tNXSivKdEkrXVdP1toY7PAIIKOxH9YfHTq2A1Q
+EWND7mevnxbDifEVppSpcrsMQEhUJYfnlG809YMD7Spvti23cE2LbjGADN09moRa
+Vc63CKkVWWbsqaFPeXMWompEH3ptafLeoFAH2gFLIi5A9IvnfPPNJ/2S6/3oStoy
+kWrsuAxJ2/hzXqSDosJA3eB4+TyDOeQiiHzRz1hKTPELTyGUxPtOqMSEzmp8/wyb
+H8bbZyJtKS8ogWDCo6uv+vmlVYM1lx0XIyoydZJ7K2eZPCX0tch0rAV+WUNcRzgW
+mw==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c0:b1:53:c8:38:a8:e5:4e:90:c9:19:52:07:46:
+ ec:7c:87:46:9e:ac:a4:c9:51:89:9c:55:43:98:a0:
+ 58:60:59:ce:73:e2:53:df:4a:e5:fb:ee:57:a9:9c:
+ da:d3:c4:76:6b:82:77:94:ee:83:39:e5:d6:6e:ed:
+ e1:3f:6e:80:a0:51:82:85:79:14:53:b6:aa:15:d8:
+ d7:7a:1a:96:26:8f:09:b8:29:b4:c8:6c:a7:80:e6:
+ 10:18:ec:d7:f7:b0:ff:59:19:45:f8:37:de:28:bd:
+ 56:4f:67:53:c1:80:44:7d:80:b5:dd:d6:6f:bf:3b:
+ 1f:02:f3:00:67:88:7d:36:65:13:39:7d:3e:a8:35:
+ 13:54:e4:91:c8:ee:f1:53:fd:af:f7:3b:f8:59:e0:
+ bc:e0:1e:ac:41:01:d1:b8:01:ee:ae:d2:39:b8:fa:
+ 57:6e:b2:7a:98:5f:51:ac:d6:6a:38:80:6b:01:64:
+ 13:96:d7:0b:74:5f:76:82:d9:44:9d:47:26:cc:59:
+ 9a:22:3c:72:eb:20:9a:d9:2b:b1:dd:cd:0a:54:0b:
+ 77:0b:83:2c:0d:bf:b4:62:4a:fc:87:84:4f:29:8d:
+ fc:6c:b9:3a:4c:8b:45:85:2b:48:7d:2c:33:1f:ac:
+ 8b:77:39:8c:cb:0c:f4:08:93:4c:ec:34:15:be:81:
+ 09:a3
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ A8:9E:04:25:6D:55:C9:D7:11:47:D3:DD:67:71:0E:7E:88:89:49:71
+ X509v3 Authority Key Identifier:
+ keyid:29:13:82:EE:25:10:7F:40:23:D6:A7:1B:28:25:35:8A:E8:B6:AA:28
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 57:37:54:5c:fd:ce:4e:4c:0f:b5:37:13:0d:0e:5f:dd:d8:4c:
+ 17:53:38:e6:07:65:6c:67:80:e0:75:25:26:78:7b:2e:b8:1a:
+ 6c:31:44:a1:5f:73:83:6d:34:1e:ff:76:42:d5:ad:ab:c0:b9:
+ cc:25:9e:88:7f:be:29:db:49:25:08:5d:3b:7d:43:2e:85:66:
+ ff:fe:b5:d4:aa:21:7a:b8:5a:b4:49:ab:c6:ef:8d:28:64:f4:
+ ea:be:64:33:c4:94:c6:31:f5:cc:55:cb:f1:20:be:e6:85:03:
+ 32:99:61:e0:09:3c:e6:df:61:9a:c5:45:ea:f8:a3:f8:c1:6d:
+ ff:7b:44:04:8e:7f:74:89:ab:39:5a:fc:a6:09:77:9c:5d:1c:
+ 99:a8:db:bc:2a:8e:19:25:8d:e3:10:37:94:42:e7:37:9c:16:
+ ba:be:4b:67:94:5f:18:2e:ae:e3:fd:ef:15:12:7d:4b:5a:47:
+ b7:45:7a:ee:27:3f:e1:6b:42:02:75:40:36:50:fd:6c:1e:de:
+ 8a:b9:f7:d5:f8:69:0c:fd:58:65:35:64:a2:ca:c5:1e:b3:aa:
+ a0:4b:42:22:00:e3:d8:e7:b4:e8:69:48:37:42:55:60:24:48:
+ 9a:d8:42:9e:d9:cf:2b:3c:9e:b1:fc:2f:39:5d:b5:fe:e3:72:
+ 44:e4:00:50
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwLFTyDio
+5U6QyRlSB0bsfIdGnqykyVGJnFVDmKBYYFnOc+JT30rl++5XqZza08R2a4J3lO6D
+OeXWbu3hP26AoFGChXkUU7aqFdjXehqWJo8JuCm0yGyngOYQGOzX97D/WRlF+Dfe
+KL1WT2dTwYBEfYC13dZvvzsfAvMAZ4h9NmUTOX0+qDUTVOSRyO7xU/2v9zv4WeC8
+4B6sQQHRuAHurtI5uPpXbrJ6mF9RrNZqOIBrAWQTltcLdF92gtlEnUcmzFmaIjxy
+6yCa2Sux3c0KVAt3C4MsDb+0Ykr8h4RPKY38bLk6TItFhStIfSwzH6yLdzmMywz0
+CJNM7DQVvoEJowIDAQABo4HLMIHIMB0GA1UdDgQWBBSongQlbVXJ1xFH091ncQ5+
+iIlJcTAfBgNVHSMEGDAWgBQpE4LuJRB/QCPWpxsoJTWK6LaqKDA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AFc3VFz9zk5MD7U3Ew0OX93YTBdTOOYHZWxngOB1JSZ4ey64GmwxRKFfc4NtNB7/
+dkLVravAucwlnoh/vinbSSUIXTt9Qy6FZv/+tdSqIXq4WrRJq8bvjShk9Oq+ZDPE
+lMYx9cxVy/EgvuaFAzKZYeAJPObfYZrFRer4o/jBbf97RASOf3SJqzla/KYJd5xd
+HJmo27wqjhkljeMQN5RC5zecFrq+S2eUXxguruP97xUSfUtaR7dFeu4nP+FrQgJ1
+QDZQ/Wwe3oq599X4aQz9WGU1ZKLKxR6zqqBLQiIA49jntOhpSDdCVWAkSJrYQp7Z
+zys8nrH8Lzldtf7jckTkAFA=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Mar 1 12:00:00 2015 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b4:d2:a3:a5:24:1a:21:0c:58:52:09:77:f1:ab:
+ 2d:49:cb:b0:e5:e2:3c:12:9a:bd:a8:df:36:37:fe:
+ be:97:6f:18:b0:8e:51:08:94:c1:8e:3e:8f:f0:ae:
+ 23:19:5e:0a:eb:5e:02:a1:bb:be:61:83:39:cb:52:
+ e1:8f:0e:ba:61:c4:4b:53:09:c3:f7:38:a3:95:fc:
+ 89:86:06:59:bc:0c:b5:e1:a2:d3:6d:d8:84:de:75:
+ 80:7b:1d:04:04:b0:94:03:07:42:b4:73:52:96:b0:
+ 68:3c:08:e3:b3:af:e9:29:60:f6:4f:6f:8a:42:fc:
+ 85:63:f6:18:d6:12:6c:6e:94:eb:c3:c0:60:12:19:
+ f8:61:d6:47:72:46:1a:cd:ed:6a:0b:65:cc:91:68:
+ ec:a7:c7:f1:c8:7a:44:5c:1e:e8:8e:2b:ed:50:82:
+ a2:1d:31:31:be:bd:06:56:52:20:bf:37:25:3d:cf:
+ 18:7f:87:94:ba:c7:9d:6e:68:7f:96:29:20:b7:dc:
+ fc:73:d9:26:82:6e:f1:97:c2:48:9d:71:35:5c:3e:
+ b6:86:69:e5:b5:1a:e9:08:4e:dc:dd:c5:0d:e1:4e:
+ 08:97:0a:41:1a:39:56:b1:31:02:0f:c2:e2:94:a0:
+ 3a:e0:d8:77:6e:a9:b6:fe:1d:8e:38:ad:52:e6:de:
+ 59:e3
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 29:13:82:EE:25:10:7F:40:23:D6:A7:1B:28:25:35:8A:E8:B6:AA:28
+ X509v3 Authority Key Identifier:
+ keyid:29:13:82:EE:25:10:7F:40:23:D6:A7:1B:28:25:35:8A:E8:B6:AA:28
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 6a:88:6c:4d:9f:ee:e6:a5:ec:19:64:e7:b9:86:03:c5:f0:32:
+ 92:69:3b:35:03:b8:87:12:db:48:78:5d:44:3b:75:e2:3b:87:
+ 7d:ef:96:83:93:06:93:fc:17:58:71:3e:c6:b0:8b:5b:13:2b:
+ c7:97:42:ed:3e:de:4a:96:cd:f1:df:3a:90:96:7f:f1:21:72:
+ 90:58:9b:77:cc:80:2d:19:5a:b1:6f:d6:dd:c8:fc:b7:32:1d:
+ 8f:77:d4:5e:f0:9d:e4:05:8a:ae:d9:7c:58:fa:00:6e:9f:f9:
+ 9a:2e:11:25:8b:28:5c:4b:76:ef:62:4d:ff:55:bc:aa:77:fa:
+ 87:33:3c:f5:a9:87:b5:d5:7f:e0:ef:51:a5:74:9a:04:5b:e9:
+ 35:f8:e6:43:d0:82:9a:db:4a:90:df:56:20:1d:31:b1:56:bc:
+ 73:0b:5e:91:bb:a6:62:37:fc:ba:dd:f7:24:69:54:95:c3:28:
+ 41:68:21:16:9f:d6:32:b6:17:88:29:52:f6:d3:2b:98:2f:28:
+ 78:c3:67:b3:76:83:df:a9:86:01:cd:c2:bf:e0:84:61:56:76:
+ f5:1f:12:d4:d1:fb:9e:c0:1b:22:c8:9e:05:4c:34:3b:93:54:
+ 1e:0a:db:41:91:9a:07:8d:aa:f8:fd:8d:89:ec:eb:32:b3:10:
+ 4f:52:53:68
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE1MDMwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALTSo6UkGiEMWFIJd/Gr
+LUnLsOXiPBKavajfNjf+vpdvGLCOUQiUwY4+j/CuIxleCuteAqG7vmGDOctS4Y8O
+umHES1MJw/c4o5X8iYYGWbwMteGi023YhN51gHsdBASwlAMHQrRzUpawaDwI47Ov
+6Slg9k9vikL8hWP2GNYSbG6U68PAYBIZ+GHWR3JGGs3tagtlzJFo7KfH8ch6RFwe
+6I4r7VCCoh0xMb69BlZSIL83JT3PGH+HlLrHnW5of5YpILfc/HPZJoJu8ZfCSJ1x
+NVw+toZp5bUa6QhO3N3FDeFOCJcKQRo5VrExAg/C4pSgOuDYd26ptv4djjitUube
+WeMCAwEAAaOByzCByDAdBgNVHQ4EFgQUKROC7iUQf0Aj1qcbKCU1iui2qigwHwYD
+VR0jBBgwFoAUKROC7iUQf0Aj1qcbKCU1iui2qigwNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBqiGxNn+7m
+pewZZOe5hgPF8DKSaTs1A7iHEttIeF1EO3XiO4d975aDkwaT/BdYcT7GsItbEyvH
+l0LtPt5Kls3x3zqQln/xIXKQWJt3zIAtGVqxb9bdyPy3Mh2Pd9Re8J3kBYqu2XxY
++gBun/maLhEliyhcS3bvYk3/Vbyqd/qHMzz1qYe11X/g71GldJoEW+k1+OZD0IKa
+20qQ31YgHTGxVrxzC16Ru6ZiN/y63fckaVSVwyhBaCEWn9YytheIKVL20yuYLyh4
+w2ezdoPfqYYBzcK/4IRhVnb1HxLU0fuewBsiyJ4FTDQ7k1QeCttBkZoHjar4/Y2J
+7OsysxBPUlNo
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-basic-constraints-pathlen-0-self-issued.py b/chromium/net/data/verify_certificate_chain_unittest/generate-basic-constraints-pathlen-0-self-issued.py
index 03c6eb50d71..1d71f77ca21 100755
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-basic-constraints-pathlen-0-self-issued.py
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-basic-constraints-pathlen-0-self-issued.py
@@ -3,33 +3,34 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Certificate chain with 2 intermediaries. The first intermediary has a basic
+"""Certificate chain with 2 intermediates. The first intermediate has a basic
constraints path length of 0. The second one is self-issued so does not count
against the path length."""
import common
-# Self-signed root certificate (part of trust store).
+# Self-signed root certificate (used as trust anchor).
root = common.create_self_signed_root_certificate('Root')
-# Intermediary with pathlen 0
-intermediary1 = common.create_intermediary_certificate('Intermediary', root)
-intermediary1.get_extensions().set_property('basicConstraints',
+# Intermediate with pathlen 0
+intermediate1 = common.create_intermediate_certificate('Intermediate', root)
+intermediate1.get_extensions().set_property('basicConstraints',
'critical,CA:true,pathlen:0')
-# Another intermediary (with the same pathlen restriction).
+# Another intermediate (with the same pathlen restriction).
# Note that this is self-issued but NOT self-signed.
-intermediary2 = common.create_intermediary_certificate('Intermediary',
- intermediary1)
-intermediary2.get_extensions().set_property('basicConstraints',
+intermediate2 = common.create_intermediate_certificate('Intermediate',
+ intermediate1)
+intermediate2.get_extensions().set_property('basicConstraints',
'critical,CA:true,pathlen:0')
# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary2)
+target = common.create_end_entity_certificate('Target', intermediate2)
-chain = [target, intermediary2, intermediary1]
-trusted = [root]
+chain = [target, intermediate2, intermediate1]
+trusted = common.TrustAnchor(root, constrained=False)
time = common.DEFAULT_TIME
verify_result = True
+errors = None
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-constrained-non-self-signed-root.py b/chromium/net/data/verify_certificate_chain_unittest/generate-constrained-non-self-signed-root.py
new file mode 100755
index 00000000000..fe2378d10f4
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-constrained-non-self-signed-root.py
@@ -0,0 +1,30 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate and a non-self-signed trust anchor.
+Verification should succeed, it doesn't matter that the root was not
+self-signed if it is designated as the trust anchor."""
+
+import common
+
+uber_root = common.create_self_signed_root_certificate('UberRoot')
+
+# Non-self-signed root certificate (used as trust anchor)
+root = common.create_intermediate_certificate('Root', uber_root)
+
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=True)
+time = common.DEFAULT_TIME
+verify_result = True
+errors = None
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
+
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-constrained-root-basic-constraints-ca-false.py b/chromium/net/data/verify_certificate_chain_unittest/generate-constrained-root-basic-constraints-ca-false.py
new file mode 100755
index 00000000000..dd4ae514d64
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-constrained-root-basic-constraints-ca-false.py
@@ -0,0 +1,30 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate and a trust anchor. The trust anchor
+has a basic constraints extension that indicates it is NOT a CA. Verification
+is expected to succeed even though the trust anchor enforces constraints, since
+the CA part of basic constraints is not enforced."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor) with non-CA basic
+# constraints.
+root = common.create_self_signed_root_certificate('Root')
+root.get_extensions().set_property('basicConstraints', 'critical,CA:false')
+
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=True)
+time = common.DEFAULT_TIME
+verify_result = True
+errors = None
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-constrained-root-lacks-basic-constraints.py b/chromium/net/data/verify_certificate_chain_unittest/generate-constrained-root-lacks-basic-constraints.py
new file mode 100755
index 00000000000..b646d26f109
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-constrained-root-lacks-basic-constraints.py
@@ -0,0 +1,28 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate and a trust anchor. The trust anchor
+lacks the basic constraints extension, and is loaded with anchor constraints.
+This is not a problem and verification should succeed."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor).
+root = common.create_self_signed_root_certificate('Root')
+root.get_extensions().remove_property('basicConstraints')
+
+# Intermediate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=True)
+time = common.DEFAULT_TIME
+verify_result = True
+errors = None
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-expired-constrained-root.py b/chromium/net/data/verify_certificate_chain_unittest/generate-expired-constrained-root.py
new file mode 100755
index 00000000000..bee2c1e6e46
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-expired-constrained-root.py
@@ -0,0 +1,35 @@
+#!/usr/bin/python
+# Copyright (c) 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Certificate chain with 1 intermediate, where the root certificate is expired
+(violates validity.notAfter). Verification is expected to succeed even though
+the trust anchor is initialized with anchor constraints, since validity is
+not enforced."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor).
+root = common.create_self_signed_root_certificate('Root')
+root.set_validity_range(common.JANUARY_1_2015_UTC, common.MARCH_1_2015_UTC)
+
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+intermediate.set_validity_range(common.JANUARY_1_2015_UTC,
+ common.JANUARY_1_2016_UTC)
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+target.set_validity_range(common.JANUARY_1_2015_UTC, common.JANUARY_1_2016_UTC)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=True)
+
+# Both the target and intermediate are valid at this time, however the
+# root is not.
+time = common.MARCH_2_2015_UTC
+verify_result = True
+errors = None
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-expired-intermediary.py b/chromium/net/data/verify_certificate_chain_unittest/generate-expired-intermediary.py
deleted file mode 100755
index 463a37bf0e3..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-expired-intermediary.py
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/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.
-
-"""Certificate chain with 1 intermediary, where the intermediary is expired
-(violates validity.notAfter). Verification is expected to fail."""
-
-import common
-
-# Self-signed root certificate (part of trust store).
-root = common.create_self_signed_root_certificate('Root')
-root.set_validity_range(common.JANUARY_1_2015_UTC, common.JANUARY_1_2016_UTC)
-
-# Intermediary certificate.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
-intermediary.set_validity_range(common.JANUARY_1_2015_UTC,
- common.MARCH_1_2015_UTC)
-
-# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
-target.set_validity_range(common.JANUARY_1_2015_UTC, common.JANUARY_1_2016_UTC)
-
-chain = [target, intermediary]
-trusted = [root]
-
-# Both the root and target are valid at this time, however the
-# intermediary certificate is not.
-time = common.MARCH_2_2015_UTC
-verify_result = False
-
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-expired-intermediate.py b/chromium/net/data/verify_certificate_chain_unittest/generate-expired-intermediate.py
new file mode 100755
index 00000000000..c2aed479b26
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-expired-intermediate.py
@@ -0,0 +1,36 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate, where the intermediate is expired
+(violates validity.notAfter). Verification is expected to fail."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor).
+root = common.create_self_signed_root_certificate('Root')
+root.set_validity_range(common.JANUARY_1_2015_UTC, common.JANUARY_1_2016_UTC)
+
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+intermediate.set_validity_range(common.JANUARY_1_2015_UTC,
+ common.MARCH_1_2015_UTC)
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+target.set_validity_range(common.JANUARY_1_2015_UTC, common.JANUARY_1_2016_UTC)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
+
+# Both the root and target are valid at this time, however the
+# intermediate certificate is not.
+time = common.MARCH_2_2015_UTC
+verify_result = False
+errors = """[Context] Processing Certificate
+ index: 0
+ [Error] Time is after notAfter
+"""
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-expired-root.py b/chromium/net/data/verify_certificate_chain_unittest/generate-expired-root.py
deleted file mode 100755
index 83f79171f37..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-expired-root.py
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/python
-# Copyright (c) 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Certificate chain with 1 intermediary, where the root certificate is expired
-(violates validity.notAfter). Verification is expected to fail."""
-
-import common
-
-# Self-signed root certificate (part of trust store).
-root = common.create_self_signed_root_certificate('Root')
-root.set_validity_range(common.JANUARY_1_2015_UTC, common.MARCH_1_2015_UTC)
-
-# Intermediary certificate.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
-intermediary.set_validity_range(common.JANUARY_1_2015_UTC,
- common.JANUARY_1_2016_UTC)
-
-# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
-target.set_validity_range(common.JANUARY_1_2015_UTC, common.JANUARY_1_2016_UTC)
-
-chain = [target, intermediary]
-trusted = [root]
-
-# Both the target and intermediary are valid at this time, however the
-# root is not.
-time = common.MARCH_2_2015_UTC
-verify_result = False
-
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-expired-target-notBefore.py b/chromium/net/data/verify_certificate_chain_unittest/generate-expired-target-notBefore.py
index fae1831ca5e..da5d0718e57 100755
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-expired-target-notBefore.py
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-expired-target-notBefore.py
@@ -3,30 +3,34 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Certificate chain with 1 intermediary, where the target is expired (violates
+"""Certificate chain with 1 intermediate, where the target is expired (violates
validity.notBefore). Verification is expected to fail."""
import common
-# Self-signed root certificate (part of trust store).
+# Self-signed root certificate (used as trust anchor).
root = common.create_self_signed_root_certificate('Root')
root.set_validity_range(common.JANUARY_1_2015_UTC, common.JANUARY_1_2016_UTC)
-# Intermediary certificate.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
-intermediary.set_validity_range(common.JANUARY_1_2015_UTC,
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+intermediate.set_validity_range(common.JANUARY_1_2015_UTC,
common.JANUARY_1_2016_UTC)
# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
+target = common.create_end_entity_certificate('Target', intermediate)
target.set_validity_range(common.MARCH_2_2015_UTC, common.JANUARY_1_2016_UTC)
-chain = [target, intermediary]
-trusted = [root]
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
-# Both the root and intermediary are valid at this time, however the
+# Both the root and intermediate are valid at this time, however the
# target is not.
time = common.MARCH_1_2015_UTC
verify_result = False
+errors = """[Context] Processing Certificate
+ index: 1
+ [Error] Time is before notBefore
+"""
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-expired-target.py b/chromium/net/data/verify_certificate_chain_unittest/generate-expired-target.py
index eaa94d33e58..679e0dd3f84 100755
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-expired-target.py
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-expired-target.py
@@ -3,30 +3,34 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Certificate chain with 1 intermediary, where the target is expired (violates
+"""Certificate chain with 1 intermediate, where the target is expired (violates
validity.notAfter). Verification is expected to fail."""
import common
-# Self-signed root certificate (part of trust store).
+# Self-signed root certificate (used as trust anchor).
root = common.create_self_signed_root_certificate('Root')
root.set_validity_range(common.JANUARY_1_2015_UTC, common.JANUARY_1_2016_UTC)
-# Intermediary certificate.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
-intermediary.set_validity_range(common.JANUARY_1_2015_UTC,
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+intermediate.set_validity_range(common.JANUARY_1_2015_UTC,
common.JANUARY_1_2016_UTC)
# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
+target = common.create_end_entity_certificate('Target', intermediate)
target.set_validity_range(common.JANUARY_1_2015_UTC, common.MARCH_1_2015_UTC)
-chain = [target, intermediary]
-trusted = [root]
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
-# Both the root and intermediary are valid at this time, however the
+# Both the root and intermediate are valid at this time, however the
# target is not.
time = common.MARCH_2_2015_UTC
verify_result = False
+errors = """[Context] Processing Certificate
+ index: 1
+ [Error] Time is after notAfter
+"""
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-expired-unconstrained-root.py b/chromium/net/data/verify_certificate_chain_unittest/generate-expired-unconstrained-root.py
new file mode 100755
index 00000000000..7585cb2c42d
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-expired-unconstrained-root.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python
+# Copyright (c) 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Certificate chain with 1 intermediate, where the root certificate is expired
+(violates validity.notAfter). Verification is expected to succeed as
+the trust anchor has no constraints (so expiration of the certificate is not
+enforced)."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor).
+root = common.create_self_signed_root_certificate('Root')
+root.set_validity_range(common.JANUARY_1_2015_UTC, common.MARCH_1_2015_UTC)
+
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+intermediate.set_validity_range(common.JANUARY_1_2015_UTC,
+ common.JANUARY_1_2016_UTC)
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+target.set_validity_range(common.JANUARY_1_2015_UTC, common.JANUARY_1_2016_UTC)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
+
+# Both the target and intermediate are valid at this time, however the
+# root is not. This doesn't matter since the root certificate is
+# just a delivery mechanism for the name + SPKI.
+time = common.MARCH_2_2015_UTC
+verify_result = True
+errors = None
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-incorrect-trust-anchor.py b/chromium/net/data/verify_certificate_chain_unittest/generate-incorrect-trust-anchor.py
new file mode 100755
index 00000000000..22a1e0acf96
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-incorrect-trust-anchor.py
@@ -0,0 +1,35 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate, but the trust anchor used is
+incorrect (neither subject nor signature matches). Verification is expected to
+fail."""
+
+import common
+
+# Self-signed root certificate, which is NOT saved as the trust anchor.
+root = common.create_self_signed_root_certificate('Root')
+
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+
+# Self-signed root certificate, not part of chain, which is saved as trust
+# anchor.
+bogus_root = common.create_self_signed_root_certificate('BogusRoot')
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(bogus_root, constrained=False)
+time = common.DEFAULT_TIME
+verify_result = False
+errors = """[Context] Processing Certificate
+ index: 0
+ [Error] Signature verification failed
+ [Error] VerifySignedData failed
+"""
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-basic-constraints-ca-false.py b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-basic-constraints-ca-false.py
deleted file mode 100755
index 4375f0e36b4..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-basic-constraints-ca-false.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/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.
-
-"""Certificate chain with 1 intermediary and a trusted root. The intermediary
-has a basic constraints extension that indicates it is NOT a CA. Verification
-is expected to fail."""
-
-import common
-
-# Self-signed root certificate (part of trust store).
-root = common.create_self_signed_root_certificate('Root')
-
-# Intermediary with incorrect basic constraints.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
-intermediary.get_extensions().set_property('basicConstraints',
- 'critical,CA:false')
-
-# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
-
-chain = [target, intermediary]
-trusted = [root]
-time = common.DEFAULT_TIME
-verify_result = False
-
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-basic-constraints-not-critical.py b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-basic-constraints-not-critical.py
deleted file mode 100755
index 284354fd6eb..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-basic-constraints-not-critical.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/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.
-
-"""Certificate chain with 1 intermediary and a trusted root. The intermediary
-has a basic constraints extension but does not mark it as critical.
-Verification is expected to succeed, since although not critical, the
-basicConstraints indicates CA=true as expected."""
-
-import common
-
-# Self-signed root certificate (part of trust store).
-root = common.create_self_signed_root_certificate('Root')
-
-# Intermediary with non-critical basic constarints.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
-intermediary.get_extensions().set_property('basicConstraints', 'CA:true')
-
-# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
-
-chain = [target, intermediary]
-trusted = [root]
-time = common.DEFAULT_TIME
-verify_result = True
-
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-lacks-basic-constraints.py b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-lacks-basic-constraints.py
deleted file mode 100755
index 1faced54a1c..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-lacks-basic-constraints.py
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/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.
-
-"""Certificate chain with 1 intermediary and a trusted root. The intermediary
-lacks the basic constraints extension, and hence is expected to fail validation
-(RFC 5280 requires v3 signing certificates have a BasicConstaints)."""
-
-import common
-
-# Self-signed root certificate (part of trust store).
-root = common.create_self_signed_root_certificate('Root')
-
-# Intermediary that lacks basic constraints.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
-intermediary.get_extensions().remove_property('basicConstraints')
-
-# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
-
-chain = [target, intermediary]
-trusted = [root]
-time = common.DEFAULT_TIME
-verify_result = False
-
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-lacks-signing-key-usage.py b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-lacks-signing-key-usage.py
deleted file mode 100755
index 4c3d8e8898e..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-lacks-signing-key-usage.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/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.
-
-"""Certificate chain with 1 intermediary and a trusted root. The intermediary
-contains a keyUsage extension, HOWEVER it does not contain the keyCertSign bit.
-Hence validation is expected to fail."""
-
-import common
-
-# Self-signed root certificate (part of trust store).
-root = common.create_self_signed_root_certificate('Root')
-
-# Intermediary that is missing keyCertSign.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
-intermediary.get_extensions().set_property('keyUsage',
- 'critical,digitalSignature,keyEncipherment')
-
-# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
-
-chain = [target, intermediary]
-trusted = [root]
-time = common.DEFAULT_TIME
-verify_result = False
-
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-signed-with-md5.py b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-signed-with-md5.py
deleted file mode 100755
index 8a59e6516d8..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-signed-with-md5.py
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/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.
-
-"""Certificate chain with 1 intermediary and a trusted root. The intermediary
-however is signed using the MD5 hash. Verification is expected to fail because
-MD5 is too weak."""
-
-import common
-
-# Self-signed root certificate (part of trust store).
-root = common.create_self_signed_root_certificate('Root')
-
-# Intermediary.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
-intermediary.set_signature_hash('md5')
-
-# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
-
-chain = [target, intermediary]
-trusted = [root]
-time = common.DEFAULT_TIME
-verify_result = False
-
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-unknown-critical-extension.py b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-unknown-critical-extension.py
deleted file mode 100755
index 39c059736d3..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-unknown-critical-extension.py
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/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.
-
-"""Certificate chain with 1 intermediary and a trusted root. The intermediary
-has an unknown X.509v3 extension (OID=1.2.3.4) that is marked as critical.
-Verifying this certificate chain is expected to fail because there is an
-unrecognized critical extension."""
-
-import common
-
-# Self-signed root certificate (part of trust store).
-root = common.create_self_signed_root_certificate('Root')
-
-# Intermediary that has an unknown critical extension.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
-intermediary.get_extensions().add_property('1.2.3.4',
- 'critical,DER:01:02:03:04')
-
-# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
-
-chain = [target, intermediary]
-trusted = [root]
-time = common.DEFAULT_TIME
-verify_result = False
-
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-unknown-non-critical-extension.py b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-unknown-non-critical-extension.py
deleted file mode 100755
index 874a6585a08..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediary-unknown-non-critical-extension.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/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.
-
-"""Certificate chain with 1 intermediary and a trusted root. The intermediary
-has an unknown X.509v3 extension that is marked as non-critical. Verification
-is expected to succeed because although unrecognized, the extension is not
-critical."""
-
-import common
-
-# Self-signed root certificate (part of trust store).
-root = common.create_self_signed_root_certificate('Root')
-intermediary = common.create_intermediary_certificate('Intermediary', root)
-
-# Intermediary that has an unknown non-critical extension.
-intermediary.get_extensions().add_property('1.2.3.4', 'DER:01:02:03:04')
-
-# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
-
-chain = [target, intermediary]
-trusted = [root]
-time = common.DEFAULT_TIME
-verify_result = True
-
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-basic-constraints-ca-false.py b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-basic-constraints-ca-false.py
new file mode 100755
index 00000000000..7796e878def
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-basic-constraints-ca-false.py
@@ -0,0 +1,32 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate and a trusted root. The intermediate
+has a basic constraints extension that indicates it is NOT a CA. Verification
+is expected to fail."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor).
+root = common.create_self_signed_root_certificate('Root')
+
+# Intermediate with incorrect basic constraints.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+intermediate.get_extensions().set_property('basicConstraints',
+ 'critical,CA:false')
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
+time = common.DEFAULT_TIME
+verify_result = False
+errors = """[Context] Processing Certificate
+ index: 0
+ [Error] Basic Constraints indicates not a CA
+"""
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-basic-constraints-not-critical.py b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-basic-constraints-not-critical.py
new file mode 100755
index 00000000000..1e9bb3fb43d
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-basic-constraints-not-critical.py
@@ -0,0 +1,29 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate and a trusted root. The intermediate
+has a basic constraints extension but does not mark it as critical.
+Verification is expected to succeed, since although not critical, the
+basicConstraints indicates CA=true as expected."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor).
+root = common.create_self_signed_root_certificate('Root')
+
+# Intermediate with non-critical basic constarints.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+intermediate.get_extensions().set_property('basicConstraints', 'CA:true')
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
+time = common.DEFAULT_TIME
+verify_result = True
+errors = None
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-lacks-basic-constraints.py b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-lacks-basic-constraints.py
new file mode 100755
index 00000000000..c836417d123
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-lacks-basic-constraints.py
@@ -0,0 +1,31 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate and a trusted root. The intermediate
+lacks the basic constraints extension, and hence is expected to fail validation
+(RFC 5280 requires v3 signing certificates have a BasicConstaints)."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor).
+root = common.create_self_signed_root_certificate('Root')
+
+# Intermediate that lacks basic constraints.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+intermediate.get_extensions().remove_property('basicConstraints')
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
+time = common.DEFAULT_TIME
+verify_result = False
+errors = """[Context] Processing Certificate
+ index: 0
+ [Error] Does not have Basic Constraints
+"""
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-lacks-signing-key-usage.py b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-lacks-signing-key-usage.py
new file mode 100755
index 00000000000..f38f6af07c1
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-lacks-signing-key-usage.py
@@ -0,0 +1,32 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate and a trusted root. The intermediate
+contains a keyUsage extension, HOWEVER it does not contain the keyCertSign bit.
+Hence validation is expected to fail."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor).
+root = common.create_self_signed_root_certificate('Root')
+
+# Intermediate that is missing keyCertSign.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+intermediate.get_extensions().set_property('keyUsage',
+ 'critical,digitalSignature,keyEncipherment')
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
+time = common.DEFAULT_TIME
+verify_result = False
+errors = """[Context] Processing Certificate
+ index: 0
+ [Error] keyCertSign bit is not set
+"""
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-signed-with-md5.py b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-signed-with-md5.py
new file mode 100755
index 00000000000..7323cddc68a
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-signed-with-md5.py
@@ -0,0 +1,32 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate and a trusted root. The intermediate
+however is signed using the MD5 hash. Verification is expected to fail because
+MD5 is too weak."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor).
+root = common.create_self_signed_root_certificate('Root')
+
+# Intermediate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+intermediate.set_signature_hash('md5')
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
+time = common.DEFAULT_TIME
+verify_result = False
+errors = """[Context] Processing Certificate
+ index: 0
+ [Error] Invalid or unsupported signature algorithm
+ algorithm: 300D06092A864886F70D0101040500
+"""
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-unknown-critical-extension.py b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-unknown-critical-extension.py
new file mode 100755
index 00000000000..0d9378f1012
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-unknown-critical-extension.py
@@ -0,0 +1,35 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate and a trusted root. The intermediate
+has an unknown X.509v3 extension (OID=1.2.3.4) that is marked as critical.
+Verifying this certificate chain is expected to fail because there is an
+unrecognized critical extension."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor).
+root = common.create_self_signed_root_certificate('Root')
+
+# Intermediate that has an unknown critical extension.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+intermediate.get_extensions().add_property('1.2.3.4',
+ 'critical,DER:01:02:03:04')
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
+time = common.DEFAULT_TIME
+verify_result = False
+errors = """[Context] Processing Certificate
+ index: 0
+ [Error] Unconsumed critical extension
+ oid: 2A0304
+ value: 01020304
+"""
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-unknown-non-critical-extension.py b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-unknown-non-critical-extension.py
new file mode 100755
index 00000000000..67879f65097
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-intermediate-unknown-non-critical-extension.py
@@ -0,0 +1,29 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate and a trusted root. The intermediate
+has an unknown X.509v3 extension that is marked as non-critical. Verification
+is expected to succeed because although unrecognized, the extension is not
+critical."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor).
+root = common.create_self_signed_root_certificate('Root')
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+
+# Intermediate that has an unknown non-critical extension.
+intermediate.get_extensions().add_property('1.2.3.4', 'DER:01:02:03:04')
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
+time = common.DEFAULT_TIME
+verify_result = True
+errors = None
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-key-rollover.py b/chromium/net/data/verify_certificate_chain_unittest/generate-key-rollover.py
new file mode 100755
index 00000000000..686e53e9cc1
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-key-rollover.py
@@ -0,0 +1,92 @@
+#!/usr/bin/python
+# Copyright (c) 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""A certificate tree with two self-signed root certificates(oldroot, newroot),
+and a third root certificate (newrootrollover) which has the same key as newroot
+but is signed by oldroot, all with the same subject and issuer.
+There are two intermediates with the same key, subject and issuer
+(oldintermediate signed by oldroot, and newintermediate signed by newroot).
+The target certificate is signed by the intermediate key.
+
+
+In graphical form:
+
+ oldroot-------->newrootrollover newroot
+ | | |
+ v v v
+oldintermediate newintermediate
+ | |
+ +------------+-------------+
+ |
+ v
+ target
+
+
+Several chains are output:
+ key-rollover-oldchain.pem:
+ target<-oldintermediate<-oldroot
+ key-rollover-rolloverchain.pem:
+ target<-newintermediate<-newrootrollover<-oldroot
+ key-rollover-longrolloverchain.pem:
+ target<-newintermediate<-newroot<-newrootrollover<-oldroot
+ key-rollover-newchain.pem:
+ target<-newintermediate<-newroot
+
+All of these chains should verify successfully.
+"""
+
+import common
+
+# The new certs should have a newer notbefore date than "old" certs. This should
+# affect path builder sorting, but otherwise won't matter.
+JANUARY_2_2015_UTC = '150102120000Z'
+
+# Self-signed root certificates. Same name, different keys.
+oldroot = common.create_self_signed_root_certificate('Root')
+oldroot.set_validity_range(common.JANUARY_1_2015_UTC, common.JANUARY_1_2016_UTC)
+newroot = common.create_self_signed_root_certificate('Root')
+newroot.set_validity_range(JANUARY_2_2015_UTC, common.JANUARY_1_2016_UTC)
+# Root with the new key signed by the old key.
+newrootrollover = common.create_intermediate_certificate('Root', oldroot)
+newrootrollover.set_key(newroot.get_key())
+newrootrollover.set_validity_range(JANUARY_2_2015_UTC,
+ common.JANUARY_1_2016_UTC)
+
+# Intermediate signed by oldroot.
+oldintermediate = common.create_intermediate_certificate('Intermediate',
+ oldroot)
+oldintermediate.set_validity_range(common.JANUARY_1_2015_UTC,
+ common.JANUARY_1_2016_UTC)
+# Intermediate signed by newroot. Same key as oldintermediate.
+newintermediate = common.create_intermediate_certificate('Intermediate',
+ newroot)
+newintermediate.set_key(oldintermediate.get_key())
+newintermediate.set_validity_range(JANUARY_2_2015_UTC,
+ common.JANUARY_1_2016_UTC)
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', oldintermediate)
+
+oldchain = [target, oldintermediate]
+rolloverchain = [target, newintermediate, newrootrollover]
+longrolloverchain = [target, newintermediate, newroot, newrootrollover]
+oldtrusted = common.TrustAnchor(oldroot, constrained=False)
+
+newchain = [target, newintermediate]
+newtrusted = common.TrustAnchor(newroot, constrained=False)
+
+time = common.DEFAULT_TIME
+verify_result = True
+errors = None
+
+common.write_test_file(__doc__, oldchain, oldtrusted, time, verify_result,
+ errors, out_pem="key-rollover-oldchain.pem")
+common.write_test_file(__doc__, rolloverchain, oldtrusted, time, verify_result,
+ errors, out_pem="key-rollover-rolloverchain.pem")
+common.write_test_file(__doc__, longrolloverchain, oldtrusted, time,
+ verify_result, errors,
+ out_pem="key-rollover-longrolloverchain.pem")
+common.write_test_file(__doc__, newchain, newtrusted, time, verify_result,
+ errors, out_pem="key-rollover-newchain.pem")
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-non-self-signed-root.py b/chromium/net/data/verify_certificate_chain_unittest/generate-non-self-signed-root.py
index 355f61e47aa..d30e5308dc4 100755
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-non-self-signed-root.py
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-non-self-signed-root.py
@@ -3,7 +3,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Certificate chain with 1 intermediary and a trusted root. The trusted root
+"""Certificate chain with 1 intermediate and a trusted root. The trusted root
is NOT self signed, however its issuer is not included in the chain or root
store. Verification is expected to succeed since the root is trusted."""
@@ -12,17 +12,18 @@ import common
shadow_root = common.create_self_signed_root_certificate('ShadowRoot')
# Non-self-signed root (part of trust store).
-root = common.create_intermediary_certificate('Root', shadow_root)
+root = common.create_intermediate_certificate('Root', shadow_root)
-# Intermediary certificate.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
+target = common.create_end_entity_certificate('Target', intermediate)
-chain = [target, intermediary]
-trusted = [root]
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
time = common.DEFAULT_TIME
verify_result = True
+errors = None
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-target-and-intermediary.py b/chromium/net/data/verify_certificate_chain_unittest/generate-target-and-intermediary.py
deleted file mode 100755
index 94525cc25e7..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-target-and-intermediary.py
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/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.
-
-"""Certificate chain with 1 intermediary and a trusted root. Verification is
-expected to succeed."""
-
-import common
-
-# Self-signed root certificate (part of trust store).
-root = common.create_self_signed_root_certificate('Root')
-
-# Intermediary certificate.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
-
-# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
-
-chain = [target, intermediary]
-trusted = [root]
-time = common.DEFAULT_TIME
-verify_result = True
-
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-target-and-intermediate.py b/chromium/net/data/verify_certificate_chain_unittest/generate-target-and-intermediate.py
new file mode 100755
index 00000000000..1b5c80e22ce
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-target-and-intermediate.py
@@ -0,0 +1,26 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate and a trusted root. Verification is
+expected to succeed."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor).
+root = common.create_self_signed_root_certificate('Root')
+
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
+time = common.DEFAULT_TIME
+verify_result = True
+errors = None
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-target-has-keycertsign-but-not-ca.py b/chromium/net/data/verify_certificate_chain_unittest/generate-target-has-keycertsign-but-not-ca.py
index fa3cafb4022..026c704d85c 100755
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-target-has-keycertsign-but-not-ca.py
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-target-has-keycertsign-but-not-ca.py
@@ -3,28 +3,32 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Certificate chain with 1 intermediary, a trusted root, and a target
+"""Certificate chain with 1 intermediate, a trusted root, and a target
certificate that is not a CA, and yet has the keyCertSign bit set. Verification
is expected to fail, since keyCertSign should only be asserted when CA is
true."""
import common
-# Self-signed root certificate (part of trust store).
+# Self-signed root certificate (used as trust anchor).
root = common.create_self_signed_root_certificate('Root')
-# Intermediary certificate.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
# Target certificate (end entity but has keyCertSign bit set).
-target = common.create_end_entity_certificate('Target', intermediary)
+target = common.create_end_entity_certificate('Target', intermediate)
target.get_extensions().set_property('keyUsage',
'critical,digitalSignature,keyEncipherment,keyCertSign')
-chain = [target, intermediary]
-trusted = [root]
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
time = common.DEFAULT_TIME
verify_result = False
+errors = """[Context] Processing Certificate
+ index: 1
+ [Error] Target certificate looks like a CA but does not set all CA properties
+"""
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-target-has-pathlen-but-not-ca.py b/chromium/net/data/verify_certificate_chain_unittest/generate-target-has-pathlen-but-not-ca.py
index 5d297393262..d35ce7bf263 100755
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-target-has-pathlen-but-not-ca.py
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-target-has-pathlen-but-not-ca.py
@@ -3,27 +3,31 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Certificate chain with 1 intermediary, a trusted root, and a target
+"""Certificate chain with 1 intermediate, a trusted root, and a target
certificate that is not a CA, and yet has a pathlen set. Verification is
expected to fail, since pathlen should only be set for CAs."""
import common
-# Self-signed root certificate (part of trust store).
+# Self-signed root certificate (used as trust anchor).
root = common.create_self_signed_root_certificate('Root')
-# Intermediary certificate.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
# Target certificate (end entity, but has pathlen set).
-target = common.create_end_entity_certificate('Target', intermediary)
+target = common.create_end_entity_certificate('Target', intermediate)
target.get_extensions().set_property('basicConstraints',
'critical,CA:false,pathlen:1')
-chain = [target, intermediary]
-trusted = [root]
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
time = common.DEFAULT_TIME
verify_result = False
+errors = """[Context] Processing Certificate
+ index: 1
+ [Error] Target certificate looks like a CA but does not set all CA properties
+"""
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-target-not-end-entity.py b/chromium/net/data/verify_certificate_chain_unittest/generate-target-not-end-entity.py
index 83573ad9649..a9e17d0a338 100755
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-target-not-end-entity.py
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-target-not-end-entity.py
@@ -3,24 +3,25 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Certificate chain with 1 intermediary, a trusted root, and a target
+"""Certificate chain with 1 intermediate, a trusted root, and a target
certificate that is also a CA. Verification is expected to succeed, as the test
code accepts any target certificate."""
import common
-# Self-signed root certificate (part of trust store).
+# Self-signed root certificate (used as trust anchor).
root = common.create_self_signed_root_certificate('Root')
-# Intermediary certificate.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
# Target certificate (is also a CA)
-target = common.create_intermediary_certificate('Target', intermediary)
+target = common.create_intermediate_certificate('Target', intermediate)
-chain = [target, intermediary]
-trusted = [root]
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
time = common.DEFAULT_TIME
verify_result = True
+errors = None
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-target-signed-by-512bit-rsa.py b/chromium/net/data/verify_certificate_chain_unittest/generate-target-signed-by-512bit-rsa.py
index 75144a0d8ea..c59751535fe 100755
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-target-signed-by-512bit-rsa.py
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-target-signed-by-512bit-rsa.py
@@ -3,25 +3,33 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Certificate chain with 1 intermediary and a trusted root. The target
+"""Certificate chain with 1 intermediate and a trusted root. The target
certificate is signed using a weak RSA key (512-bit modulus), and so
verification is expected to fail."""
import common
-# Self-signed root certificate (part of trust store).
+# Self-signed root certificate (used as trust anchor).
root = common.create_self_signed_root_certificate('Root')
-# Intermediary with a very weak key size (512-bit RSA).
-intermediary = common.create_intermediary_certificate('Intermediary', root)
-intermediary.generate_rsa_key(512)
+# Intermediate with a very weak key size (512-bit RSA).
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+intermediate.set_key(common.generate_rsa_key(512))
# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
+target = common.create_end_entity_certificate('Target', intermediate)
-chain = [target, intermediary]
-trusted = [root]
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
time = common.DEFAULT_TIME
verify_result = False
+errors = """[Context] Processing Certificate
+ index: 1
+ [Error] RSA modulus too small
+ actual: 512
+ minimum: 1024
+ [Error] Unacceptable modulus length for RSA key
+ [Error] VerifySignedData failed
+"""
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-target-signed-using-ecdsa.py b/chromium/net/data/verify_certificate_chain_unittest/generate-target-signed-using-ecdsa.py
index 562ebb1fc27..b0a9fd247b7 100755
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-target-signed-using-ecdsa.py
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-target-signed-using-ecdsa.py
@@ -3,24 +3,25 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Certificate chain with a trusted root using RSA, and intermediary using EC,
+"""Certificate chain with a trusted root using RSA, and intermediate using EC,
and a target certificate using RSA. Verification is expected to succeed."""
import common
-# Self-signed root certificate (part of trust store), using RSA.
+# Self-signed root certificate (used as trust anchor). using RSA.
root = common.create_self_signed_root_certificate('Root')
-# Intermediary using an EC key for the P-384 curve.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
-intermediary.generate_ec_key('secp384r1')
+# Intermediate using an EC key for the P-384 curve.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+intermediate.set_key(common.generate_ec_key('secp384r1'))
# Target certificate contains an RSA key (but is signed using ECDSA).
-target = common.create_end_entity_certificate('Target', intermediary)
+target = common.create_end_entity_certificate('Target', intermediate)
-chain = [target, intermediary]
-trusted = [root]
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
time = common.DEFAULT_TIME
verify_result = True
+errors = None
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-target-signed-with-md5.py b/chromium/net/data/verify_certificate_chain_unittest/generate-target-signed-with-md5.py
index 743ad25b283..8d2c8f6c8e9 100755
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-target-signed-with-md5.py
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-target-signed-with-md5.py
@@ -3,24 +3,29 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Certificate chain with an intermediary that uses MD5 to sign the target
+"""Certificate chain with an intermediate that uses MD5 to sign the target
certificate. This is expected to fail because MD5 is too weak."""
import common
-# Self-signed root certificate (part of trust store).
+# Self-signed root certificate (used as trust anchor).
root = common.create_self_signed_root_certificate('Root')
-# Intermediary.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
+# Intermediate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
+target = common.create_end_entity_certificate('Target', intermediate)
target.set_signature_hash('md5')
-chain = [target, intermediary]
-trusted = [root]
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
time = common.DEFAULT_TIME
verify_result = False
+errors = """[Context] Processing Certificate
+ index: 1
+ [Error] Invalid or unsupported signature algorithm
+ algorithm: 300D06092A864886F70D0101040500
+"""
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-target-unknown-critical-extension.py b/chromium/net/data/verify_certificate_chain_unittest/generate-target-unknown-critical-extension.py
index 725429920c8..a94f41878bc 100755
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-target-unknown-critical-extension.py
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-target-unknown-critical-extension.py
@@ -3,27 +3,33 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Certificate chain with 1 intermediary and a trusted root. The target
+"""Certificate chain with 1 intermediate and a trusted root. The target
certificate has an unknown X.509v3 extension (OID=1.2.3.4) that is marked as
critical. Verifying this certificate chain is expected to fail because there is
an unrecognized critical extension."""
import common
-# Self-signed root certificate (part of trust store).
+# Self-signed root certificate (used as trust anchor).
root = common.create_self_signed_root_certificate('Root')
-# Intermediary certificate.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
# Target certificate (has unknown critical extension).
-target = common.create_end_entity_certificate('Target', intermediary)
+target = common.create_end_entity_certificate('Target', intermediate)
target.get_extensions().add_property('1.2.3.4',
'critical,DER:01:02:03:04')
-chain = [target, intermediary]
-trusted = [root]
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
time = common.DEFAULT_TIME
verify_result = False
+errors = """[Context] Processing Certificate
+ index: 1
+ [Error] Unconsumed critical extension
+ oid: 2A0304
+ value: 01020304
+"""
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-target-wrong-signature.py b/chromium/net/data/verify_certificate_chain_unittest/generate-target-wrong-signature.py
index 162f7160bc7..4f09b14ef8f 100755
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-target-wrong-signature.py
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-target-wrong-signature.py
@@ -9,24 +9,29 @@ certificate is wrong."""
import common
-# Self-signed root certificate (part of trust store).
+# Self-signed root certificate (used as trust anchor).
root = common.create_self_signed_root_certificate('Root')
-# Intermediary certificate to include in the certificate chain.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
+# Intermediate certificate to include in the certificate chain.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
# Actual intermediate that was used to sign the target certificate. It has the
# same subject as expected, but a different RSA key from the certificate
# included in the actual chain.
-wrong_intermediary = common.create_intermediary_certificate('Intermediary',
+wrong_intermediate = common.create_intermediate_certificate('Intermediate',
root)
-# Target certificate, signed using |wrong_intermediary| NOT |intermediary|.
-target = common.create_end_entity_certificate('Target', wrong_intermediary)
+# Target certificate, signed using |wrong_intermediate| NOT |intermediate|.
+target = common.create_end_entity_certificate('Target', wrong_intermediate)
-chain = [target, intermediary]
-trusted = [root]
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
time = common.DEFAULT_TIME
verify_result = False
+errors = """[Context] Processing Certificate
+ index: 1
+ [Error] Signature verification failed
+ [Error] VerifySignedData failed
+"""
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-unconstrained-non-self-signed-root.py b/chromium/net/data/verify_certificate_chain_unittest/generate-unconstrained-non-self-signed-root.py
new file mode 100755
index 00000000000..4d433a772b1
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-unconstrained-non-self-signed-root.py
@@ -0,0 +1,30 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate and a non-self-signed trust anchor.
+Verification should succeed, it doesn't matter that the root was not
+self-signed if it is designated as the trust anchor."""
+
+import common
+
+uber_root = common.create_self_signed_root_certificate('UberRoot')
+
+# Non-self-signed root certificate (used as trust anchor)
+root = common.create_intermediate_certificate('Root', uber_root)
+
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
+time = common.DEFAULT_TIME
+verify_result = True
+errors = None
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
+
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-unconstrained-root-basic-constraints-ca-false.py b/chromium/net/data/verify_certificate_chain_unittest/generate-unconstrained-root-basic-constraints-ca-false.py
new file mode 100755
index 00000000000..ba48dd86610
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-unconstrained-root-basic-constraints-ca-false.py
@@ -0,0 +1,31 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate and a trust anchor. The trust anchor
+has a basic constraints extension that indicates it is NOT a CA. Verification
+is expected to succeed as constraints on the root certificate are not applied
+to the trust anchor."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor) with non-CA basic
+# constraints.
+root = common.create_self_signed_root_certificate('Root')
+root.get_extensions().set_property('basicConstraints', 'critical,CA:false')
+
+# Intermediate certificate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
+time = common.DEFAULT_TIME
+verify_result = True
+errors = None
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
+
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-unconstrained-root-lacks-basic-constraints.py b/chromium/net/data/verify_certificate_chain_unittest/generate-unconstrained-root-lacks-basic-constraints.py
new file mode 100755
index 00000000000..dbd1802de8f
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-unconstrained-root-lacks-basic-constraints.py
@@ -0,0 +1,28 @@
+#!/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.
+
+"""Certificate chain with 1 intermediate and a trust anchor. The trust anchor
+lacks the basic constraints extension. This is not a problem and verification
+should succeed."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor).
+root = common.create_self_signed_root_certificate('Root')
+root.get_extensions().remove_property('basicConstraints')
+
+# Intermediate.
+intermediate = common.create_intermediate_certificate('Intermediate', root)
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate)
+
+chain = [target, intermediate]
+trusted = common.TrustAnchor(root, constrained=False)
+time = common.DEFAULT_TIME
+verify_result = True
+errors = None
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-unknown-root.py b/chromium/net/data/verify_certificate_chain_unittest/generate-unknown-root.py
deleted file mode 100755
index 4f0b5f5098d..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-unknown-root.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/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.
-
-"""Certificate chain with 1 intermediary, but the root is not in trust store.
-Verification is expected to fail because the final intermediary (Intermediary)
-does not chain to a known root."""
-
-import common
-
-# Self-signed root certificate, which is NOT added to the trust store.
-root = common.create_self_signed_root_certificate('Root')
-
-# Intermediary certificate.
-intermediary = common.create_intermediary_certificate('Intermediary', root)
-
-# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary)
-
-chain = [target, intermediary]
-trusted = [] # Note that this lacks |root|
-time = common.DEFAULT_TIME
-verify_result = False
-
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-violates-basic-constraints-pathlen-0.py b/chromium/net/data/verify_certificate_chain_unittest/generate-violates-basic-constraints-pathlen-0.py
index 0298956edb3..64e03555577 100755
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-violates-basic-constraints-pathlen-0.py
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-violates-basic-constraints-pathlen-0.py
@@ -3,32 +3,36 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Certificate chain with 2 intermediaries. The first intermediary has a basic
+"""Certificate chain with 2 intermediates. The first intermediate has a basic
constraints path length of 0, so it is a violation for it to have a subordinate
-intermediary."""
+intermediate."""
import common
-# Self-signed root certificate (part of trust store).
+# Self-signed root certificate (used as trust anchor).
root = common.create_self_signed_root_certificate('Root')
-# Intermediary with pathlen 0
-intermediary1 = common.create_intermediary_certificate('Intermediary1', root)
-intermediary1.get_extensions().set_property('basicConstraints',
+# Intermediate with pathlen 0
+intermediate1 = common.create_intermediate_certificate('Intermediate1', root)
+intermediate1.get_extensions().set_property('basicConstraints',
'critical,CA:true,pathlen:0')
-# Another intermediary (with the same pathlen restriction)
-intermediary2 = common.create_intermediary_certificate('Intermediary2',
- intermediary1)
-intermediary2.get_extensions().set_property('basicConstraints',
+# Another intermediate (with the same pathlen restriction)
+intermediate2 = common.create_intermediate_certificate('Intermediate2',
+ intermediate1)
+intermediate2.get_extensions().set_property('basicConstraints',
'critical,CA:true,pathlen:0')
# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary2)
+target = common.create_end_entity_certificate('Target', intermediate2)
-chain = [target, intermediary2, intermediary1]
-trusted = [root]
+chain = [target, intermediate2, intermediate1]
+trusted = common.TrustAnchor(root, constrained=False)
time = common.DEFAULT_TIME
verify_result = False
+errors = """[Context] Processing Certificate
+ index: 1
+ [Error] max_path_length reached
+"""
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-violates-pathlen-1-constrained-root.py b/chromium/net/data/verify_certificate_chain_unittest/generate-violates-pathlen-1-constrained-root.py
new file mode 100755
index 00000000000..27bd109f60c
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-violates-pathlen-1-constrained-root.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python
+# Copyright (c) 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Certificate chain with 2 intermediates and one end entity certificate. The
+root certificate has a pathlen:1 restriction, and constraints are enforced
+on this trust anchor making it an invalid chain."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor).
+root = common.create_self_signed_root_certificate('Root')
+root.get_extensions().set_property('basicConstraints',
+ 'critical,CA:true,pathlen:1')
+
+# Intermediate 1 (no pathlen restriction).
+intermediate1 = common.create_intermediate_certificate('Intermediate1', root)
+
+# Intermediate 2 (no pathlen restriction).
+intermediate2 = common.create_intermediate_certificate('Intermediate2',
+ intermediate1)
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate2)
+
+chain = [target, intermediate2, intermediate1]
+trusted = common.TrustAnchor(root, constrained=True)
+time = common.DEFAULT_TIME
+verify_result = False
+errors = """[Context] Processing Certificate
+ index: 1
+ [Error] max_path_length reached
+"""
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-violates-pathlen-1-root.py b/chromium/net/data/verify_certificate_chain_unittest/generate-violates-pathlen-1-root.py
deleted file mode 100755
index bda9c25d9ee..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/generate-violates-pathlen-1-root.py
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/python
-# Copyright (c) 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Certificate chain with 2 intermediaries and one end entity certificate. The
-root certificate has a pathlen:1 restriction so this is an invalid chain."""
-
-import common
-
-# Self-signed root certificate (part of trust store).
-root = common.create_self_signed_root_certificate('Root')
-root.get_extensions().set_property('basicConstraints',
- 'critical,CA:true,pathlen:1')
-
-# Intermediary 1 (no pathlen restriction).
-intermediary1 = common.create_intermediary_certificate('Intermediary1', root)
-
-# Intermediary 2 (no pathlen restriction).
-intermediary2 = common.create_intermediary_certificate('Intermediary2',
- intermediary1)
-
-# Target certificate.
-target = common.create_end_entity_certificate('Target', intermediary2)
-
-chain = [target, intermediary2, intermediary1]
-trusted = [root]
-time = common.DEFAULT_TIME
-verify_result = False
-
-common.write_test_file(__doc__, chain, trusted, time, verify_result)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/generate-violates-pathlen-1-unconstrained-root.py b/chromium/net/data/verify_certificate_chain_unittest/generate-violates-pathlen-1-unconstrained-root.py
new file mode 100755
index 00000000000..d51a38a45fb
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/generate-violates-pathlen-1-unconstrained-root.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+# Copyright (c) 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Certificate chain with 2 intermediates and one end entity certificate. The
+root certificate has a pathlen:1 restriction. Ordinarily this would be an
+invalid chain, however constraints on this trust anchor are not enforced."""
+
+import common
+
+# Self-signed root certificate (used as trust anchor).
+root = common.create_self_signed_root_certificate('Root')
+root.get_extensions().set_property('basicConstraints',
+ 'critical,CA:true,pathlen:1')
+
+# Intermediate 1 (no pathlen restriction).
+intermediate1 = common.create_intermediate_certificate('Intermediate1', root)
+
+# Intermediate 2 (no pathlen restriction).
+intermediate2 = common.create_intermediate_certificate('Intermediate2',
+ intermediate1)
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', intermediate2)
+
+chain = [target, intermediate2, intermediate1]
+trusted = common.TrustAnchor(root, constrained=False)
+time = common.DEFAULT_TIME
+verify_result = True
+errors = None
+
+common.write_test_file(__doc__, chain, trusted, time, verify_result, errors)
diff --git a/chromium/net/data/verify_certificate_chain_unittest/incorrect-trust-anchor.pem b/chromium/net/data/verify_certificate_chain_unittest/incorrect-trust-anchor.pem
new file mode 100644
index 00000000000..ba601d6c436
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/incorrect-trust-anchor.pem
@@ -0,0 +1,292 @@
+[Created by: generate-incorrect-trust-anchor.py]
+
+Certificate chain with 1 intermediate, but the trust anchor used is
+incorrect (neither subject nor signature matches). Verification is expected to
+fail.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:a3:7b:69:ed:ad:13:3f:59:75:63:cf:2a:9e:b0:
+ 78:06:62:e2:5e:40:3f:12:2e:61:1c:7f:2e:f8:4f:
+ 0e:92:28:80:18:d8:e2:e2:f4:b4:63:84:c8:0b:4d:
+ ae:1b:f0:4d:d5:49:91:89:b9:a4:11:b3:77:72:ba:
+ 12:16:3e:29:7c:51:28:99:37:69:57:6d:3b:68:e1:
+ 58:83:c0:ad:13:af:63:2e:85:63:ab:92:11:7a:92:
+ 8b:fa:66:33:f9:3b:c9:ab:22:75:9f:6c:91:1b:22:
+ 6b:c9:2d:c8:6d:58:2b:bc:a9:f3:cf:24:8f:7a:37:
+ 9b:83:67:e5:b2:eb:ea:35:c6:9d:e4:a8:24:74:18:
+ 5b:8b:62:6b:cd:92:d7:c3:6c:b1:40:e1:2f:a3:16:
+ 52:92:df:59:70:bc:cc:37:27:8f:8e:3d:b9:fc:d6:
+ ca:fb:63:89:b3:d0:64:24:2b:97:e3:a7:bc:6f:76:
+ 7e:e6:82:36:9f:c4:ea:b2:96:60:ac:86:57:09:55:
+ d7:3b:45:a8:23:b8:b1:4a:92:f8:a9:66:1f:1a:0f:
+ c5:f6:da:4e:6d:02:56:1b:8a:9f:52:9f:bd:b5:16:
+ a6:fb:85:3d:fa:04:1d:8e:25:b4:03:9e:74:e4:98:
+ 4a:da:39:7b:d0:f2:7d:f9:f4:97:ce:d1:d8:4d:31:
+ 88:47
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 94:D6:3E:50:DE:FF:47:B8:65:1A:C6:33:78:79:87:8D:F2:32:32:BA
+ X509v3 Authority Key Identifier:
+ keyid:CC:11:88:FF:DF:7E:14:06:07:B5:10:B6:C1:BC:CB:2B:65:FC:83:77
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ b4:9a:15:da:2b:7d:d4:26:f2:41:a2:04:1e:13:f3:b3:28:bf:
+ a3:85:34:fc:42:b1:57:05:0f:97:e5:f5:d9:d4:0e:eb:43:e8:
+ 63:ce:5b:23:8b:48:ab:2f:25:03:81:43:ba:7e:9a:14:e4:4e:
+ 9c:5b:d3:08:56:b7:00:7c:7f:fd:9e:ab:50:ce:09:95:2c:21:
+ 00:74:22:26:83:fb:08:47:34:1b:67:0e:eb:e0:c4:ab:3d:00:
+ 76:b2:9a:b1:00:c8:d0:17:0d:2e:81:43:71:51:f8:d7:f5:ad:
+ e9:f0:81:12:2a:e0:6f:c7:10:11:d7:f4:55:73:a4:7c:cb:97:
+ 6c:fd:2b:34:bf:7e:a9:57:d8:e1:a9:05:01:5a:09:2b:49:bf:
+ bc:99:a3:a5:7c:b0:df:7a:32:0f:c2:94:0f:e0:15:f2:86:8f:
+ c3:19:44:49:02:10:56:f6:a9:58:38:7f:4d:f1:66:58:00:f9:
+ 17:18:ab:b4:0c:c1:9e:f3:8d:5d:61:4d:02:8c:3a:97:89:8d:
+ 5f:d0:98:f3:57:5c:85:35:b0:94:f8:02:7c:6f:bf:69:bf:7b:
+ 91:5a:c3:38:88:0d:ec:42:3b:b5:29:6b:0a:2d:10:19:ae:bc:
+ 6c:18:95:2e:cd:74:04:af:95:79:ab:8e:4a:cc:53:6e:4d:ad:
+ 83:58:6d:c5
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCje2nt
+rRM/WXVjzyqesHgGYuJeQD8SLmEcfy74Tw6SKIAY2OLi9LRjhMgLTa4b8E3VSZGJ
+uaQRs3dyuhIWPil8USiZN2lXbTto4ViDwK0Tr2MuhWOrkhF6kov6ZjP5O8mrInWf
+bJEbImvJLchtWCu8qfPPJI96N5uDZ+Wy6+o1xp3kqCR0GFuLYmvNktfDbLFA4S+j
+FlKS31lwvMw3J4+OPbn81sr7Y4mz0GQkK5fjp7xvdn7mgjafxOqylmCshlcJVdc7
+RagjuLFKkvipZh8aD8X22k5tAlYbip9Sn721Fqb7hT36BB2OJbQDnnTkmEraOXvQ
+8n359JfO0dhNMYhHAgMBAAGjgekwgeYwHQYDVR0OBBYEFJTWPlDe/0e4ZRrGM3h5
+h43yMjK6MB8GA1UdIwQYMBaAFMwRiP/ffhQGB7UQtsG8yytl/IN3MD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAtJoV2it91CbyQaIEHhPz
+syi/o4U0/EKxVwUPl+X12dQO60PoY85bI4tIqy8lA4FDun6aFOROnFvTCFa3AHx/
+/Z6rUM4JlSwhAHQiJoP7CEc0G2cO6+DEqz0AdrKasQDI0BcNLoFDcVH41/Wt6fCB
+Eirgb8cQEdf0VXOkfMuXbP0rNL9+qVfY4akFAVoJK0m/vJmjpXyw33oyD8KUD+AV
+8oaPwxlESQIQVvapWDh/TfFmWAD5FxirtAzBnvONXWFNAow6l4mNX9CY81dchTWw
+lPgCfG+/ab97kVrDOIgN7EI7tSlrCi0QGa68bBiVLs10BK+VeauOSsxTbk2tg1ht
+xQ==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b6:cf:57:a5:6e:7c:9a:78:f2:c1:bd:99:eb:7c:
+ af:6a:c8:38:2e:8e:cf:e5:20:c0:f9:57:5c:e2:83:
+ 29:33:2c:b1:9d:2b:91:ce:4c:da:27:62:5f:18:08:
+ a8:f1:03:eb:0e:be:f2:1e:00:8c:63:f2:8f:d3:c1:
+ e4:df:0a:d3:d4:82:0d:6c:c4:98:87:eb:5b:81:66:
+ 43:f3:38:5e:d4:8b:91:47:70:8b:89:90:a0:0b:9d:
+ 63:56:4f:58:4b:e2:36:e1:97:df:37:71:7a:90:f5:
+ 62:2c:3e:57:71:6a:75:db:10:66:22:4c:fd:e9:a0:
+ 78:5e:4c:e3:8c:d5:c2:c9:a0:10:3d:ec:bd:7b:76:
+ 9f:5f:54:e3:c3:88:9b:d7:7f:8c:80:79:87:0f:3c:
+ aa:28:d9:f5:63:e8:f3:a5:6b:2b:e0:45:1c:af:94:
+ 00:84:b4:e4:fc:3a:5d:9c:bc:05:c2:04:b7:3a:23:
+ 84:56:66:a2:50:fc:8d:00:06:52:7f:a2:d3:9e:0b:
+ fa:d5:ba:1b:1e:10:e9:13:60:56:a6:cd:ab:67:90:
+ 66:0c:3d:71:c0:46:42:13:48:74:a8:a8:6d:0c:a8:
+ 6d:7b:6b:57:f1:ba:c0:c5:c8:cd:d9:75:20:d3:59:
+ ed:32:ed:5c:b6:63:b4:9b:0b:3a:05:7b:ad:38:70:
+ e4:3d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ CC:11:88:FF:DF:7E:14:06:07:B5:10:B6:C1:BC:CB:2B:65:FC:83:77
+ X509v3 Authority Key Identifier:
+ keyid:A7:26:DB:0B:03:E6:0B:32:0B:8C:34:AD:CE:60:CD:4C:89:9B:59:6E
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 69:10:d5:c3:ff:f0:65:c6:79:55:be:ba:6b:7c:7f:49:a2:47:
+ b0:d7:e9:28:9f:14:f6:11:6a:d7:1f:e3:11:30:c1:d0:0c:21:
+ 8c:b3:21:95:c1:f3:2e:7c:8a:34:f6:d6:c7:49:9a:75:4c:93:
+ 35:c4:88:f7:be:d6:ed:e0:75:22:29:4d:0f:59:80:1a:1b:9b:
+ a4:fd:86:af:1e:76:44:03:f9:42:f2:74:1e:6b:74:fc:fa:64:
+ 67:33:4a:14:93:fc:84:1f:92:0c:62:ac:aa:e1:f0:6f:3e:09:
+ 90:d5:67:68:2a:28:9c:5f:86:29:8d:48:ef:3e:a5:48:60:08:
+ b5:cf:ac:ba:ff:ba:d7:7d:9a:8e:b4:63:10:e3:14:12:12:89:
+ 37:00:42:fb:4c:e5:b7:0d:e5:b8:28:5b:9f:79:48:aa:e4:ef:
+ 17:ec:eb:f1:c3:82:d9:48:ec:cd:f4:f7:1f:8f:e2:9e:ec:71:
+ a6:7a:ce:c0:fc:14:8f:48:17:56:10:02:27:aa:d9:10:bb:fc:
+ 6d:e2:d8:b6:66:27:08:e5:31:4d:fb:24:45:0f:da:7a:9c:8d:
+ e5:91:0c:80:91:1e:44:78:01:28:ca:db:40:87:db:38:0f:18:
+ 1a:a9:ff:68:8c:03:b2:89:82:e2:80:ee:3c:77:e2:4e:85:a5:
+ cf:72:3f:24
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAts9XpW58
+mnjywb2Z63yvasg4Lo7P5SDA+Vdc4oMpMyyxnSuRzkzaJ2JfGAio8QPrDr7yHgCM
+Y/KP08Hk3wrT1IINbMSYh+tbgWZD8zhe1IuRR3CLiZCgC51jVk9YS+I24ZffN3F6
+kPViLD5XcWp12xBmIkz96aB4XkzjjNXCyaAQPey9e3afX1Tjw4ib13+MgHmHDzyq
+KNn1Y+jzpWsr4EUcr5QAhLTk/DpdnLwFwgS3OiOEVmaiUPyNAAZSf6LTngv61bob
+HhDpE2BWps2rZ5BmDD1xwEZCE0h0qKhtDKhte2tX8brAxcjN2XUg01ntMu1ctmO0
+mws6BXutOHDkPQIDAQABo4HLMIHIMB0GA1UdDgQWBBTMEYj/334UBge1ELbBvMsr
+ZfyDdzAfBgNVHSMEGDAWgBSnJtsLA+YLMguMNK3OYM1MiZtZbjA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AGkQ1cP/8GXGeVW+umt8f0miR7DX6SifFPYRatcf4xEwwdAMIYyzIZXB8y58ijT2
+1sdJmnVMkzXEiPe+1u3gdSIpTQ9ZgBobm6T9hq8edkQD+ULydB5rdPz6ZGczShST
+/IQfkgxirKrh8G8+CZDVZ2gqKJxfhimNSO8+pUhgCLXPrLr/utd9mo60YxDjFBIS
+iTcAQvtM5bcN5bgoW595SKrk7xfs6/HDgtlI7M309x+P4p7scaZ6zsD8FI9IF1YQ
+Aieq2RC7/G3i2LZmJwjlMU37JEUP2nqcjeWRDICRHkR4ASjK20CH2zgPGBqp/2iM
+A7KJguKA7jx34k6Fpc9yPyQ=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=BogusRoot
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=BogusRoot
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:a6:2e:77:a3:0d:0b:86:02:e4:79:46:6d:76:0e:
+ de:ba:55:19:76:07:90:e5:7a:4b:9a:99:70:f2:91:
+ f2:28:94:e7:e0:8b:aa:c4:a5:c1:82:36:d8:30:be:
+ 84:43:45:ae:2a:60:e7:fe:d4:a0:a1:a7:e9:30:56:
+ d0:c9:5d:f8:5f:86:9c:ba:c9:ad:cc:29:77:15:0c:
+ e8:7b:78:52:42:ec:69:db:db:38:d6:f5:25:75:50:
+ 6f:21:a0:9a:b2:4e:3a:33:6c:47:60:b2:a4:e7:ec:
+ bc:c0:9f:d7:46:1b:bb:82:43:2a:22:6d:fb:65:0d:
+ b5:cf:48:b9:a6:e3:2b:26:77:32:db:a6:80:b6:a7:
+ 63:f5:b9:d7:bf:f3:37:bd:2b:88:15:b5:50:06:0c:
+ c9:6f:05:2b:97:ac:ff:01:d9:9e:55:b8:2d:90:62:
+ a4:38:d4:d3:19:87:8f:b0:dd:88:4d:ca:19:f3:c9:
+ 2f:95:22:a8:19:be:98:38:6d:0f:17:65:d7:ee:5b:
+ 82:73:f8:c5:28:43:76:96:a6:ef:00:9c:5e:d0:9d:
+ cc:52:dc:c8:6c:d6:4a:8e:2c:5a:c0:9b:e0:b4:1b:
+ f4:5f:43:84:b7:ad:7d:d1:07:c6:79:16:d8:01:c2:
+ 73:e7:ad:dc:4c:d4:a5:bc:ab:99:60:6d:18:34:14:
+ ed:07
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 60:21:11:AF:90:99:E9:F8:9A:0B:80:16:9C:63:C3:DC:45:08:84:91
+ X509v3 Authority Key Identifier:
+ keyid:60:21:11:AF:90:99:E9:F8:9A:0B:80:16:9C:63:C3:DC:45:08:84:91
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/BogusRoot.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/BogusRoot.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 97:aa:1c:16:64:05:60:ea:e0:5b:ae:7e:31:f3:6e:04:07:fe:
+ ba:34:6d:fd:b3:c9:74:d1:f8:b4:da:c2:97:1e:00:da:05:b6:
+ 08:de:e3:8e:6e:5e:a9:9b:15:62:41:0b:2f:d2:bc:24:4a:47:
+ e9:7a:0c:6b:ba:c9:04:7c:82:ea:c5:89:5c:03:6f:8a:e6:a1:
+ 13:4c:02:1a:5b:2e:ae:48:8b:16:f5:6d:01:89:89:66:29:06:
+ 40:49:fe:b9:51:19:9e:ea:6d:76:ce:a7:78:7e:72:bf:04:4c:
+ bf:f6:17:b0:bc:79:3e:67:47:89:ec:d9:07:40:55:6e:5b:7c:
+ 79:6e:7f:97:e9:1b:d3:df:b6:54:e5:53:44:32:e2:39:17:ea:
+ 17:be:6c:82:8a:b6:c2:6a:b4:c5:b7:8c:6d:38:34:b4:b8:27:
+ 66:1f:4f:70:1d:65:77:6c:73:d8:69:24:6f:06:09:d4:f9:a9:
+ 7a:eb:47:cb:9b:3e:ec:42:89:2e:f4:2b:20:36:f1:fc:70:e2:
+ 3b:83:0a:e0:3a:04:1e:bf:53:cb:b6:ca:fe:2f:25:d5:c6:aa:
+ 71:39:a9:8e:25:4a:75:bb:15:fc:29:4f:ba:d6:a9:02:c7:8d:
+ d8:06:48:aa:6d:0b:34:bd:36:19:ea:87:a9:50:e5:a8:d8:31:
+ 73:a2:30:44
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDeTCCAmGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlCb2d1
+c1Jvb3QwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjAUMRIwEAYDVQQD
+DAlCb2d1c1Jvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmLnej
+DQuGAuR5Rm12Dt66VRl2B5DlekuamXDykfIolOfgi6rEpcGCNtgwvoRDRa4qYOf+
+1KChp+kwVtDJXfhfhpy6ya3MKXcVDOh7eFJC7Gnb2zjW9SV1UG8hoJqyTjozbEdg
+sqTn7LzAn9dGG7uCQyoibftlDbXPSLmm4ysmdzLbpoC2p2P1ude/8ze9K4gVtVAG
+DMlvBSuXrP8B2Z5VuC2QYqQ41NMZh4+w3YhNyhnzyS+VIqgZvpg4bQ8XZdfuW4Jz
++MUoQ3aWpu8AnF7QncxS3Mhs1kqOLFrAm+C0G/RfQ4S3rX3RB8Z5FtgBwnPnrdxM
+1KW8q5lgbRg0FO0HAgMBAAGjgdUwgdIwHQYDVR0OBBYEFGAhEa+Qmen4mguAFpxj
+w9xFCISRMB8GA1UdIwQYMBaAFGAhEa+Qmen4mguAFpxjw9xFCISRMDwGCCsGAQUF
+BwEBBDAwLjAsBggrBgEFBQcwAoYgaHR0cDovL3VybC1mb3ItYWlhL0JvZ3VzUm9v
+dC5jZXIwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDovL3VybC1mb3ItY3JsL0JvZ3Vz
+Um9vdC5jcmwwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAJeqHBZkBWDq4FuufjHzbgQH/ro0bf2zyXTR+LTawpceANoF
+tgje445uXqmbFWJBCy/SvCRKR+l6DGu6yQR8gurFiVwDb4rmoRNMAhpbLq5Iixb1
+bQGJiWYpBkBJ/rlRGZ7qbXbOp3h+cr8ETL/2F7C8eT5nR4ns2QdAVW5bfHluf5fp
+G9PftlTlU0Qy4jkX6he+bIKKtsJqtMW3jG04NLS4J2YfT3AdZXdsc9hpJG8GCdT5
+qXrrR8ubPuxCiS70KyA28fxw4juDCuA6BB6/U8u2yv4vJdXGqnE5qY4lSnW7Ffwp
+T7rWqQLHjdgGSKptCzS9Nhnqh6lQ5ajYMXOiMEQ=
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+FAIL
+-----BEGIN VERIFY_RESULT-----
+RkFJTA==
+-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 0
+ [Error] Signature verification failed
+ [Error] VerifySignedData failed
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMAogICAgICBbRXJyb3JdIFNpZ25hdHVyZSB2ZXJpZmljYXRpb24gZmFpbGVkCiAgICAgIFtFcnJvcl0gVmVyaWZ5U2lnbmVkRGF0YSBmYWlsZWQK
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/intermediary-basic-constraints-ca-false.pem b/chromium/net/data/verify_certificate_chain_unittest/intermediary-basic-constraints-ca-false.pem
deleted file mode 100644
index 04bbffe7844..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/intermediary-basic-constraints-ca-false.pem
+++ /dev/null
@@ -1,281 +0,0 @@
-[Created by: generate-intermediary-basic-constraints-ca-false.py]
-
-Certificate chain with 1 intermediary and a trusted root. The intermediary
-has a basic constraints extension that indicates it is NOT a CA. Verification
-is expected to fail.
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Target
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:d7:2c:b6:2c:cc:74:93:54:76:43:6a:c8:78:5d:
- c4:cc:30:ab:d1:16:46:84:b6:d8:28:13:74:4f:7f:
- 6c:e1:ef:0c:12:07:c8:f5:2b:bd:98:3e:5f:ec:3c:
- 6b:96:6b:7d:42:d1:a0:1c:e3:9a:c5:04:10:9f:f6:
- d8:d2:e9:0b:98:3b:40:f1:3d:9f:39:fd:70:7b:d3:
- f6:af:83:14:48:89:1c:87:aa:f1:21:fc:ab:f4:1e:
- b3:66:3b:1e:ae:f9:9b:5d:9b:6d:6c:19:14:e2:38:
- 09:36:99:be:b6:c0:27:50:91:33:c5:8d:11:4b:83:
- 95:db:21:d6:3b:a8:7c:d9:a7:6b:04:cc:d4:81:28:
- 8e:bb:57:76:2a:d9:d9:fa:31:07:62:dc:34:af:2d:
- ec:7d:2f:8c:73:b9:57:44:cc:86:3b:49:d5:45:df:
- bd:11:97:4e:b5:d2:07:17:71:39:0c:54:5b:c7:76:
- db:69:64:e6:0d:3d:a2:c8:bc:45:35:06:f4:6f:fb:
- ff:e5:23:53:9d:36:92:b5:15:2e:c7:62:62:22:69:
- 66:62:2c:51:ee:1c:b7:2e:10:82:14:e2:ff:3f:f9:
- 4e:a5:ad:70:fe:c8:26:d3:99:fb:ee:ea:67:f9:8a:
- 06:b8:a1:60:99:4f:ef:95:0e:96:3a:c2:35:11:e9:
- 4e:7d
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 34:A4:95:47:59:7D:2A:43:E3:DD:5F:55:F7:D0:F4:C0:25:E5:AD:8E
- X509v3 Authority Key Identifier:
- keyid:9F:6B:93:D1:46:61:07:80:55:0A:40:C8:FE:A8:D8:DD:8E:B1:EF:DD
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Intermediary.crl
-
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage:
- TLS Web Server Authentication, TLS Web Client Authentication
- Signature Algorithm: sha256WithRSAEncryption
- 75:a4:8c:02:02:da:03:71:90:d9:46:cc:6a:21:36:ef:86:21:
- 68:60:4a:a9:ce:af:f6:49:cf:f4:6b:b0:96:42:60:d5:02:91:
- 62:93:01:8b:cb:0b:eb:a5:b0:b8:49:6c:8e:54:84:c2:53:d4:
- 46:09:d6:db:29:96:a0:45:e5:09:5b:c1:b7:ba:be:8a:43:62:
- f9:8b:e4:47:d5:a9:d9:03:0e:83:86:78:19:81:c8:3b:20:86:
- 1d:72:98:cd:06:73:fa:b1:e4:df:fd:08:9c:52:bb:f6:48:61:
- bc:6f:3f:1e:1c:ef:f5:4e:94:5b:ee:e7:96:44:ff:1a:8d:6c:
- a6:9c:d1:77:17:1f:c7:e1:53:d5:5e:a5:d8:55:c8:36:48:f6:
- 8c:25:c3:1b:27:09:58:8e:30:6a:ad:ad:5e:0a:2e:5f:6f:5a:
- cb:1a:fb:fe:c9:03:1f:bf:37:9c:b5:c3:93:b7:4c:a2:d5:e2:
- ac:af:94:91:85:22:8c:c7:8b:b0:39:4a:67:f0:82:dc:db:fe:
- 39:3c:1d:50:4c:70:44:7e:aa:73:e4:fd:51:48:12:ea:9c:18:
- b1:27:6b:96:e7:aa:cf:f6:58:bf:05:d0:a4:51:71:27:b6:2c:
- 3d:a7:50:4d:93:1a:8d:04:84:7e:d3:9f:0d:b5:a5:6b:d3:db:
- d4:3a:03:fb
------BEGIN CERTIFICATE-----
-MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDXLLYs
-zHSTVHZDash4XcTMMKvRFkaEttgoE3RPf2zh7wwSB8j1K72YPl/sPGuWa31C0aAc
-45rFBBCf9tjS6QuYO0DxPZ85/XB70/avgxRIiRyHqvEh/Kv0HrNmOx6u+Ztdm21s
-GRTiOAk2mb62wCdQkTPFjRFLg5XbIdY7qHzZp2sEzNSBKI67V3Yq2dn6MQdi3DSv
-Lex9L4xzuVdEzIY7SdVF370Rl0610gcXcTkMVFvHdttpZOYNPaLIvEU1BvRv+//l
-I1OdNpK1FS7HYmIiaWZiLFHuHLcuEIIU4v8/+U6lrXD+yCbTmfvu6mf5iga4oWCZ
-T++VDpY6wjUR6U59AgMBAAGjgekwgeYwHQYDVR0OBBYEFDSklUdZfSpD491fVffQ
-9MAl5a2OMB8GA1UdIwQYMBaAFJ9rk9FGYQeAVQpAyP6o2N2Ose/dMD8GCCsGAQUF
-BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAdaSMAgLaA3GQ2UbMaiE2
-74YhaGBKqc6v9knP9GuwlkJg1QKRYpMBi8sL66WwuElsjlSEwlPURgnW2ymWoEXl
-CVvBt7q+ikNi+YvkR9Wp2QMOg4Z4GYHIOyCGHXKYzQZz+rHk3/0InFK79khhvG8/
-Hhzv9U6UW+7nlkT/Go1sppzRdxcfx+FT1V6l2FXINkj2jCXDGycJWI4waq2tXgou
-X29ayxr7/skDH783nLXDk7dMotXirK+UkYUijMeLsDlKZ/CC3Nv+OTwdUExwRH6q
-c+T9UUgS6pwYsSdrlueqz/ZYvwXQpFFxJ7YsPadQTZMajQSEftOfDbWla9Pb1DoD
-+w==
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 2 (0x2)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:b6:2b:92:72:9f:d2:59:95:3f:16:fd:eb:d3:37:
- 3e:4d:fa:bf:05:3a:e3:8b:b5:32:90:42:9c:d7:69:
- c5:30:e6:0f:d3:6d:fb:93:c0:0e:30:f2:9f:42:8d:
- 83:17:62:e0:ac:41:c4:2b:29:4f:e6:c7:64:27:a8:
- ca:c0:46:16:50:ba:e1:de:3a:ed:4b:1e:49:84:cf:
- 16:2c:5d:84:0c:8e:0d:42:c0:d2:01:e3:94:2a:79:
- d7:da:d7:a6:51:75:fe:a3:e5:1a:95:f5:38:a3:5b:
- f8:5c:8a:a9:90:f1:f9:83:4a:13:25:61:bc:33:fb:
- 19:69:71:c1:c1:a6:45:4a:bd:7f:3f:a6:92:43:fe:
- db:88:a2:15:a9:41:cf:9d:62:9b:b4:fc:71:8f:4f:
- be:5d:4a:48:8a:7a:de:57:11:82:44:49:a6:5c:25:
- a0:8c:0b:f0:ec:74:51:76:ae:f4:5c:14:c6:d0:90:
- b9:93:64:93:f8:04:82:99:28:98:fa:c8:a2:e8:98:
- 20:2d:7d:cd:d9:99:ef:74:eb:7a:63:06:4c:7a:86:
- 1e:e8:4b:8f:d0:8d:ab:d9:3a:8e:bc:ec:f2:2a:0d:
- e1:5f:89:54:0f:ef:b8:28:ff:d5:f6:ef:a7:14:94:
- 52:72:48:50:29:85:5b:d9:fd:1e:14:59:c8:69:df:
- 89:47
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 9F:6B:93:D1:46:61:07:80:55:0A:40:C8:FE:A8:D8:DD:8E:B1:EF:DD
- X509v3 Authority Key Identifier:
- keyid:D8:01:99:4C:28:49:4B:7F:FB:30:0A:92:A8:90:6F:8B:9C:45:05:7F
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:FALSE
- Signature Algorithm: sha256WithRSAEncryption
- 7f:36:da:7c:f5:4a:3b:37:53:82:b4:98:99:0b:d7:c0:73:b9:
- 05:89:75:fa:97:e4:cc:9d:73:61:18:ad:f2:bd:57:3f:6b:d0:
- 45:a2:45:2a:27:68:13:f1:a3:80:15:85:13:52:4b:c6:8f:12:
- 78:ba:21:51:fb:9d:1c:88:5d:5c:f5:0b:e5:66:ef:b4:72:67:
- 16:cb:3d:79:83:56:9b:90:50:91:fe:f2:0c:f9:36:88:dd:14:
- ef:b7:d2:1e:a3:54:d3:67:9f:3e:bc:7b:8c:45:be:12:c0:a9:
- 21:cf:b7:ea:e9:9e:ec:e8:79:02:a0:48:3e:a8:b9:fc:62:9d:
- a3:ab:74:b6:22:97:ab:78:7f:60:8e:67:96:02:ff:13:6d:66:
- b9:df:a4:55:c7:e4:82:a9:f7:0d:30:d4:e9:6b:a9:25:68:f8:
- 3c:2f:73:38:cf:07:af:b5:ef:82:5a:5f:34:0c:d9:0a:56:ad:
- 30:c4:8a:2a:90:5c:92:e6:01:f5:49:4e:58:a0:13:0c:81:46:
- ef:01:bc:8f:48:15:49:da:5d:20:28:a7:2a:b9:2b:85:9c:f8:
- c4:5e:76:6f:ff:67:c0:2a:ee:96:91:2e:8d:b3:be:6b:66:51:
- 0e:d5:7f:c9:21:c0:af:79:cc:07:0a:cc:dc:85:00:85:cf:74:
- 9e:6f:2f:31
------BEGIN CERTIFICATE-----
-MIIDajCCAlKgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtiuScp/S
-WZU/Fv3r0zc+Tfq/BTrji7UykEKc12nFMOYP0237k8AOMPKfQo2DF2LgrEHEKylP
-5sdkJ6jKwEYWULrh3jrtSx5JhM8WLF2EDI4NQsDSAeOUKnnX2temUXX+o+UalfU4
-o1v4XIqpkPH5g0oTJWG8M/sZaXHBwaZFSr1/P6aSQ/7biKIVqUHPnWKbtPxxj0++
-XUpIinreVxGCREmmXCWgjAvw7HRRdq70XBTG0JC5k2ST+ASCmSiY+sii6JggLX3N
-2ZnvdOt6YwZMeoYe6EuP0I2r2TqOvOzyKg3hX4lUD++4KP/V9u+nFJRSckhQKYVb
-2f0eFFnIad+JRwIDAQABo4HIMIHFMB0GA1UdDgQWBBSfa5PRRmEHgFUKQMj+qNjd
-jrHv3TAfBgNVHSMEGDAWgBTYAZlMKElLf/swCpKokG+LnEUFfzA3BggrBgEFBQcB
-AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
-BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
-VR0PAQH/BAQDAgEGMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBAH82
-2nz1Sjs3U4K0mJkL18BzuQWJdfqX5Mydc2EYrfK9Vz9r0EWiRSonaBPxo4AVhRNS
-S8aPEni6IVH7nRyIXVz1C+Vm77RyZxbLPXmDVpuQUJH+8gz5NojdFO+30h6jVNNn
-nz68e4xFvhLAqSHPt+rpnuzoeQKgSD6oufxinaOrdLYil6t4f2COZ5YC/xNtZrnf
-pFXH5IKp9w0w1OlrqSVo+DwvczjPB6+174JaXzQM2QpWrTDEiiqQXJLmAfVJTlig
-EwyBRu8BvI9IFUnaXSAopyq5K4Wc+MRedm//Z8Aq7paRLo2zvmtmUQ7Vf8khwK95
-zAcKzNyFAIXPdJ5vLzE=
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Root
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:a6:91:a5:68:ad:ba:89:8f:b6:5c:19:a1:3d:10:
- ad:55:97:10:17:06:9a:7d:59:e7:7c:56:3d:1d:5f:
- 17:c7:a2:e5:e7:80:52:a8:cd:ef:ca:82:4a:77:e4:
- ac:77:7c:35:f1:1b:b3:7a:9a:58:78:9e:1c:00:c9:
- 67:9d:4d:d0:f4:92:f1:0a:82:8a:f0:d4:57:04:04:
- cc:12:e4:86:95:93:12:a7:9b:ee:6f:d2:85:5d:63:
- 3c:5c:94:91:db:d0:3c:f1:a8:ca:05:19:22:98:e0:
- ef:29:22:35:40:3c:7c:c4:74:5c:df:24:2b:e4:b8:
- bc:23:ba:db:aa:6b:ef:ba:bb:aa:c2:ab:ce:9f:07:
- 2e:36:da:21:67:4d:80:71:ba:4a:7b:62:16:08:51:
- 29:35:dd:c8:1d:8c:60:d8:8c:05:a2:ec:f0:5e:af:
- f4:f2:e8:95:03:c1:79:77:3e:ff:f4:31:ed:ab:cc:
- 1b:dd:7e:f6:2c:71:3a:1c:e3:ab:ab:a4:ab:79:12:
- 59:a5:f6:84:00:83:ff:8c:e5:3b:a0:4f:37:2a:b1:
- c4:a5:19:69:46:2c:87:bc:a5:0e:ee:31:13:2e:0e:
- ed:d2:e2:19:be:d0:14:b3:68:b5:34:c6:3f:6e:95:
- da:eb:2c:55:30:92:3d:f8:93:df:4e:ec:85:a7:b3:
- 06:71
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- D8:01:99:4C:28:49:4B:7F:FB:30:0A:92:A8:90:6F:8B:9C:45:05:7F
- X509v3 Authority Key Identifier:
- keyid:D8:01:99:4C:28:49:4B:7F:FB:30:0A:92:A8:90:6F:8B:9C:45:05:7F
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- 38:6a:c5:72:2a:2b:2b:2c:d4:6f:07:a5:14:46:10:e5:3b:68:
- 80:3c:d9:60:ef:12:ed:e6:1a:c0:76:4a:3d:9c:e1:86:71:b5:
- 15:de:eb:47:51:d6:85:3e:14:ef:18:e6:b0:3c:ac:6b:0b:48:
- 42:0f:76:3d:59:89:84:63:61:fe:6a:a0:47:0a:75:1a:64:92:
- e3:09:14:12:d9:af:36:ec:f4:c5:79:37:22:cd:88:b8:f8:3c:
- 55:0a:28:2e:21:26:45:cf:95:41:e4:6c:5a:ad:23:0a:cc:fd:
- 83:71:76:7d:63:e2:9f:6c:f2:07:ee:6e:e3:fd:dd:87:f0:23:
- 9c:04:5e:19:b2:67:38:00:91:ea:05:4c:3c:db:cd:19:d3:f6:
- 7c:fd:fa:1d:86:fc:49:fe:45:ac:99:28:b1:a6:e7:fb:90:a2:
- 98:59:a7:12:bc:26:ce:6d:b5:0f:62:19:40:a4:67:45:06:ec:
- 18:1e:c5:83:e4:a1:fb:e6:58:3c:6c:a3:12:29:46:22:0d:8a:
- 07:75:72:ab:6a:a9:c3:1c:0c:d3:a3:0b:fd:50:af:37:89:0b:
- f6:70:57:1c:fb:d6:e7:0f:e6:52:5e:f6:1f:02:1c:73:bb:2b:
- eb:21:1e:f0:aa:fe:b1:50:c0:12:fc:76:8c:d0:94:0a:ab:3b:
- a8:0a:6c:28
------BEGIN TRUSTED_CERTIFICATE-----
-MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKaRpWituomPtlwZoT0Q
-rVWXEBcGmn1Z53xWPR1fF8ei5eeAUqjN78qCSnfkrHd8NfEbs3qaWHieHADJZ51N
-0PSS8QqCivDUVwQEzBLkhpWTEqeb7m/ShV1jPFyUkdvQPPGoygUZIpjg7ykiNUA8
-fMR0XN8kK+S4vCO626pr77q7qsKrzp8HLjbaIWdNgHG6SntiFghRKTXdyB2MYNiM
-BaLs8F6v9PLolQPBeXc+//Qx7avMG91+9ixxOhzjq6ukq3kSWaX2hACD/4zlO6BP
-NyqxxKUZaUYsh7ylDu4xEy4O7dLiGb7QFLNotTTGP26V2ussVTCSPfiT307shaez
-BnECAwEAAaOByzCByDAdBgNVHQ4EFgQU2AGZTChJS3/7MAqSqJBvi5xFBX8wHwYD
-VR0jBBgwFoAU2AGZTChJS3/7MAqSqJBvi5xFBX8wNwYIKwYBBQUHAQEEKzApMCcG
-CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
-IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA4asVyKisr
-LNRvB6UURhDlO2iAPNlg7xLt5hrAdko9nOGGcbUV3utHUdaFPhTvGOawPKxrC0hC
-D3Y9WYmEY2H+aqBHCnUaZJLjCRQS2a827PTFeTcizYi4+DxVCiguISZFz5VB5Gxa
-rSMKzP2DcXZ9Y+KfbPIH7m7j/d2H8COcBF4Zsmc4AJHqBUw8280Z0/Z8/fodhvxJ
-/kWsmSixpuf7kKKYWacSvCbObbUPYhlApGdFBuwYHsWD5KH75lg8bKMSKUYiDYoH
-dXKraqnDHAzTowv9UK83iQv2cFcc+9bnD+ZSXvYfAhxzuyvrIR7wqv6xUMAS/HaM
-0JQKqzuoCmwo
------END TRUSTED_CERTIFICATE-----
-
------BEGIN TIME-----
-MTUwMzAyMTIwMDAwWg==
------END TIME-----
-
------BEGIN VERIFY_RESULT-----
-RkFJTA==
------END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/intermediary-basic-constraints-not-critical.pem b/chromium/net/data/verify_certificate_chain_unittest/intermediary-basic-constraints-not-critical.pem
deleted file mode 100644
index 3ff36828983..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/intermediary-basic-constraints-not-critical.pem
+++ /dev/null
@@ -1,282 +0,0 @@
-[Created by: generate-intermediary-basic-constraints-not-critical.py]
-
-Certificate chain with 1 intermediary and a trusted root. The intermediary
-has a basic constraints extension but does not mark it as critical.
-Verification is expected to succeed, since although not critical, the
-basicConstraints indicates CA=true as expected.
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Target
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:d2:25:d5:a0:7a:94:e6:21:0b:8b:e5:68:21:06:
- c4:a7:fe:fd:de:97:31:a6:80:a2:3d:be:f0:03:c2:
- de:d5:a1:a6:3f:6e:19:3b:fe:f4:66:8f:8f:c8:d3:
- e4:7f:73:fc:e7:1c:2f:b4:9f:5e:bf:25:71:2d:d0:
- 65:60:76:0d:a6:be:af:1a:1f:3c:00:bf:cd:8e:de:
- 04:6f:6c:8d:25:c5:7a:64:71:31:d7:4a:e9:bd:5f:
- fa:e6:b8:e8:55:a2:c7:2b:b4:7d:4e:e3:bc:23:c9:
- 0f:79:29:86:dd:4d:b3:dd:12:c5:1a:d3:fc:4a:31:
- 54:47:7b:62:20:f5:bb:7c:47:6d:7f:67:d5:69:4b:
- f8:99:4f:dd:13:56:a4:9d:0a:fc:d0:da:b5:bd:e0:
- 0c:c8:50:d6:e1:73:d8:59:37:95:99:70:31:3d:46:
- 44:d5:68:7b:45:4b:9e:4a:fd:25:33:05:7c:24:05:
- 0f:6c:00:4b:3e:0c:cf:56:e8:88:ef:67:bc:bd:66:
- b4:7c:bc:db:c6:4e:8b:44:0b:65:8f:c6:a9:57:d7:
- b0:8e:88:19:fc:d6:b7:02:b9:50:a0:e2:06:61:1d:
- d1:03:7a:ce:75:09:d2:64:d5:c6:61:3b:f1:28:5b:
- 4b:de:08:2f:b9:96:55:d9:4c:8c:48:d0:c6:2b:ee:
- 59:33
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- F9:45:14:0B:10:A3:AC:77:3B:19:DE:FB:66:FE:CF:E3:9A:F4:57:1A
- X509v3 Authority Key Identifier:
- keyid:73:DC:40:FE:F8:8F:F4:BD:DE:B0:63:30:AF:05:0B:6C:4E:99:54:7F
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Intermediary.crl
-
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage:
- TLS Web Server Authentication, TLS Web Client Authentication
- Signature Algorithm: sha256WithRSAEncryption
- 41:3c:ca:d6:88:67:86:f8:dc:35:ab:37:d0:40:96:7b:4e:70:
- 2a:6b:cc:15:31:fd:06:87:ac:81:6d:89:ce:66:b2:26:73:bc:
- 71:3e:af:be:b2:ba:d5:bc:a5:b7:64:0c:7d:31:9b:0c:e1:0c:
- 73:14:0c:e0:fe:95:d3:ca:1d:d1:51:8a:fb:b1:e1:8d:68:58:
- 30:51:a6:2f:86:57:61:a6:20:7c:1f:0c:7f:14:c7:fe:fa:88:
- 14:7b:d9:41:5c:20:da:16:3c:ce:77:b8:ee:7c:33:d8:cf:2e:
- 6e:e3:43:01:00:0a:c0:1c:a0:eb:6b:36:a0:d6:bd:6e:91:a9:
- e1:8d:8d:b2:4e:12:d3:fa:56:84:be:eb:65:d8:9d:e2:c7:d4:
- 36:a2:7e:b8:b2:d4:5c:2f:c2:47:1e:ca:7a:fd:b4:30:3a:59:
- 19:8d:ca:7e:44:65:86:97:2d:f4:65:3b:f0:12:4b:d0:74:48:
- f9:dd:d3:d3:89:97:83:c6:4c:bb:da:e7:ce:e7:5e:93:f3:51:
- 4c:22:95:31:59:a9:3d:82:ec:8d:4c:8e:44:42:5f:13:d0:56:
- c2:35:e1:07:11:6d:23:92:3c:de:b1:3e:1c:4e:0e:e3:c6:06:
- 09:e1:dc:b8:4c:89:82:35:3c:51:60:1f:06:65:11:39:8b:b4:
- 20:04:f0:90
------BEGIN CERTIFICATE-----
-MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSJdWg
-epTmIQuL5WghBsSn/v3elzGmgKI9vvADwt7VoaY/bhk7/vRmj4/I0+R/c/znHC+0
-n16/JXEt0GVgdg2mvq8aHzwAv82O3gRvbI0lxXpkcTHXSum9X/rmuOhVoscrtH1O
-47wjyQ95KYbdTbPdEsUa0/xKMVRHe2Ig9bt8R21/Z9VpS/iZT90TVqSdCvzQ2rW9
-4AzIUNbhc9hZN5WZcDE9RkTVaHtFS55K/SUzBXwkBQ9sAEs+DM9W6IjvZ7y9ZrR8
-vNvGTotEC2WPxqlX17COiBn81rcCuVCg4gZhHdEDes51CdJk1cZhO/EoW0veCC+5
-llXZTIxI0MYr7lkzAgMBAAGjgekwgeYwHQYDVR0OBBYEFPlFFAsQo6x3Oxne+2b+
-z+Oa9FcaMB8GA1UdIwQYMBaAFHPcQP74j/S93rBjMK8FC2xOmVR/MD8GCCsGAQUF
-BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAQTzK1ohnhvjcNas30ECW
-e05wKmvMFTH9BoesgW2JzmayJnO8cT6vvrK61bylt2QMfTGbDOEMcxQM4P6V08od
-0VGK+7HhjWhYMFGmL4ZXYaYgfB8MfxTH/vqIFHvZQVwg2hY8zne47nwz2M8ubuND
-AQAKwByg62s2oNa9bpGp4Y2Nsk4S0/pWhL7rZdid4sfUNqJ+uLLUXC/CRx7Kev20
-MDpZGY3KfkRlhpct9GU78BJL0HRI+d3T04mXg8ZMu9rnzudek/NRTCKVMVmpPYLs
-jUyOREJfE9BWwjXhBxFtI5I83rE+HE4O48YGCeHcuEyJgjU8UWAfBmUROYu0IATw
-kA==
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 2 (0x2)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:d5:4a:96:98:34:e1:a8:92:88:9a:0c:d0:b7:e3:
- a0:dc:71:4b:32:cd:59:a1:b9:9c:d5:e5:30:1b:ad:
- 7e:41:7f:e7:39:81:25:d1:e7:66:c2:5f:79:80:ea:
- ff:6b:ef:b9:95:9e:8b:a0:0c:6a:b6:c8:4b:50:2c:
- 7d:f1:ad:46:ed:9a:7c:7d:6a:65:70:de:c2:45:7e:
- 1b:28:af:dc:eb:3d:bb:4c:98:a9:8c:b3:a3:35:a1:
- 2b:cd:bb:8e:2a:2b:74:6d:0c:91:72:36:c2:2f:0e:
- 46:2a:77:34:ab:98:f8:28:c9:02:42:78:2f:b2:e0:
- 9a:0d:ae:03:94:c0:31:79:1e:72:ce:8b:7c:21:c8:
- d5:1c:9b:94:04:29:ce:1c:5f:22:e3:f0:20:62:2b:
- 7d:7d:c2:fa:29:5c:8b:2a:dd:0f:08:31:49:58:7d:
- 85:76:21:b4:46:0e:d8:26:dc:26:f9:0a:9b:58:a2:
- b8:29:b4:df:c0:4e:10:56:28:96:02:54:7c:e9:a3:
- 3f:84:12:6a:89:ed:f0:0d:a0:03:54:0c:b2:33:6d:
- 1b:a7:84:f2:a0:b0:57:5e:4b:c1:2f:6d:e9:22:52:
- 50:b1:3b:a7:7d:ee:a7:dc:6e:6a:bd:b6:a6:ea:66:
- f8:1f:30:60:18:d8:5b:a6:dd:9d:9b:d3:4e:2b:0a:
- c4:0b
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 73:DC:40:FE:F8:8F:F4:BD:DE:B0:63:30:AF:05:0B:6C:4E:99:54:7F
- X509v3 Authority Key Identifier:
- keyid:6C:05:B0:A0:A8:03:A4:A1:90:D1:A5:74:D2:13:D9:2E:57:83:36:73
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints:
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- 81:08:b8:48:94:05:02:aa:61:ea:32:48:55:02:31:f6:e0:5d:
- 05:6f:32:9b:6a:a0:3b:6f:0e:1d:2a:01:1a:14:20:a2:1e:23:
- b4:70:61:86:55:b5:4c:5b:61:3f:dd:1e:38:a4:98:3f:bd:61:
- e4:1e:56:54:ed:0e:51:65:6c:73:af:99:86:fc:a7:50:48:87:
- 95:6f:5a:93:0d:c9:7a:ff:fb:39:d1:f4:40:2c:fe:1f:28:aa:
- 85:cf:12:bd:7b:df:2b:12:56:4a:91:4e:e4:80:00:52:4c:bb:
- b2:e6:05:27:47:e2:3f:bb:a4:d7:cc:92:c2:27:02:10:50:10:
- 0c:f8:ee:4c:93:90:89:8d:db:8a:f9:05:f1:ec:d7:cf:67:20:
- a4:da:90:e0:38:34:fd:79:9b:6b:04:a8:bd:6f:e8:82:4a:d9:
- 37:49:b3:10:50:e6:c5:56:d9:ac:9b:e8:97:52:41:a1:66:be:
- cb:64:1d:12:0d:86:8b:34:42:26:9a:ad:c3:8a:14:ff:35:0d:
- 82:8f:96:e0:af:b7:e7:20:30:3e:b3:fe:57:4a:80:5e:53:8b:
- ec:15:ca:a8:db:b7:c6:87:b7:ab:81:8b:42:23:4a:74:9c:9e:
- 59:b8:3c:8d:0e:d2:f3:9d:79:45:9a:0e:fd:8c:6b:9e:b5:c8:
- e7:03:64:79
------BEGIN CERTIFICATE-----
-MIIDajCCAlKgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1UqWmDTh
-qJKImgzQt+Og3HFLMs1Zobmc1eUwG61+QX/nOYEl0edmwl95gOr/a++5lZ6LoAxq
-tshLUCx98a1G7Zp8fWplcN7CRX4bKK/c6z27TJipjLOjNaErzbuOKit0bQyRcjbC
-Lw5GKnc0q5j4KMkCQngvsuCaDa4DlMAxeR5yzot8IcjVHJuUBCnOHF8i4/AgYit9
-fcL6KVyLKt0PCDFJWH2FdiG0Rg7YJtwm+QqbWKK4KbTfwE4QViiWAlR86aM/hBJq
-ie3wDaADVAyyM20bp4TyoLBXXkvBL23pIlJQsTunfe6n3G5qvbam6mb4HzBgGNhb
-pt2dm9NOKwrECwIDAQABo4HIMIHFMB0GA1UdDgQWBBRz3ED++I/0vd6wYzCvBQts
-TplUfzAfBgNVHSMEGDAWgBRsBbCgqAOkoZDRpXTSE9kuV4M2czA3BggrBgEFBQcB
-AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
-BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
-VR0PAQH/BAQDAgEGMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAIEI
-uEiUBQKqYeoySFUCMfbgXQVvMptqoDtvDh0qARoUIKIeI7RwYYZVtUxbYT/dHjik
-mD+9YeQeVlTtDlFlbHOvmYb8p1BIh5VvWpMNyXr/+znR9EAs/h8oqoXPEr173ysS
-VkqRTuSAAFJMu7LmBSdH4j+7pNfMksInAhBQEAz47kyTkImN24r5BfHs189nIKTa
-kOA4NP15m2sEqL1v6IJK2TdJsxBQ5sVW2ayb6JdSQaFmvstkHRINhos0QiaarcOK
-FP81DYKPluCvt+cgMD6z/ldKgF5Ti+wVyqjbt8aHt6uBi0IjSnScnlm4PI0O0vOd
-eUWaDv2Ma561yOcDZHk=
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Root
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:b6:f1:d2:f8:c9:10:d5:cf:0c:55:ce:8c:38:a2:
- 8f:f5:f1:cf:20:85:56:92:df:42:8c:5c:1a:db:8e:
- 1d:2e:b4:b3:95:72:e4:67:76:7c:c5:61:62:2b:cf:
- 97:f7:84:29:80:ff:df:e8:e7:da:f6:05:11:1d:40:
- 1e:73:76:ff:e4:eb:fa:45:59:20:d9:35:cb:c7:4f:
- 2b:49:2a:61:7c:45:a1:fe:da:8c:89:05:38:84:ab:
- cb:0b:c9:36:3b:e5:3e:31:5e:0b:a6:27:63:b1:c2:
- 34:88:3a:e5:e3:43:93:0b:46:69:03:dd:31:16:65:
- 18:6e:64:4c:84:e4:a1:37:6b:15:ef:f3:8f:57:e8:
- 57:f6:a8:86:62:9b:92:d0:67:d3:ed:0f:89:d3:4e:
- 09:aa:e8:74:ab:ce:4b:51:63:52:55:f1:24:9d:42:
- 70:cb:14:0f:e3:b4:7f:ba:6a:3c:87:27:eb:3b:82:
- 64:99:6a:f9:be:20:5a:9e:b9:8a:8b:ab:94:ed:f3:
- 33:eb:ea:42:5c:7e:20:df:f4:9d:82:8f:ac:8e:52:
- 99:06:db:d0:9f:01:38:e7:b9:0c:d2:b4:ca:7f:74:
- 03:e2:f7:0b:0e:a9:40:14:6c:7f:1b:15:00:77:0a:
- 98:76:ee:bd:62:24:f6:a7:8b:d4:7e:4b:8d:c9:eb:
- 04:a7
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 6C:05:B0:A0:A8:03:A4:A1:90:D1:A5:74:D2:13:D9:2E:57:83:36:73
- X509v3 Authority Key Identifier:
- keyid:6C:05:B0:A0:A8:03:A4:A1:90:D1:A5:74:D2:13:D9:2E:57:83:36:73
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- 52:82:fe:3f:2b:71:41:fd:4c:9b:db:c5:b1:60:72:a7:cf:f4:
- 29:91:36:0f:ce:92:72:95:3e:34:ab:84:0c:af:23:e8:e1:28:
- 35:29:c9:c8:78:9a:12:d7:f1:22:1c:21:e1:b0:b4:df:af:36:
- c4:ca:71:2a:6e:6f:4a:d5:65:58:31:7a:c2:d1:30:66:e0:0a:
- 61:54:e0:61:97:7b:41:72:58:d9:02:da:22:8b:21:e6:d5:31:
- 4c:d2:3c:11:d8:0d:12:f0:dc:eb:e0:1d:16:3a:74:de:9c:b4:
- b2:bb:69:ed:e1:53:14:9e:1c:06:3f:ff:e7:2f:8a:d1:f6:37:
- 89:76:b2:61:60:5f:48:ce:a3:8f:e0:b5:6f:92:18:21:e4:a8:
- 1f:12:70:86:54:2a:da:78:3d:5d:3c:13:b8:b4:7f:a5:81:f0:
- 55:cf:ea:56:b4:0a:8a:ca:2b:ca:be:08:9e:a6:4c:12:99:5f:
- 23:93:08:58:70:8f:c8:fb:88:11:fe:d6:16:c7:a3:3b:1f:6b:
- 78:b0:05:29:9f:7d:4c:01:ba:ed:8a:5f:a8:38:e9:a4:c2:44:
- ce:e8:37:1d:d8:1f:16:e4:ef:84:bb:1f:4b:3a:b0:9a:00:57:
- aa:ba:52:1c:f4:da:f7:69:5d:ef:8d:35:ef:5c:03:fa:8d:87:
- fc:92:60:28
------BEGIN TRUSTED_CERTIFICATE-----
-MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALbx0vjJENXPDFXOjDii
-j/XxzyCFVpLfQoxcGtuOHS60s5Vy5Gd2fMVhYivPl/eEKYD/3+jn2vYFER1AHnN2
-/+Tr+kVZINk1y8dPK0kqYXxFof7ajIkFOISrywvJNjvlPjFeC6YnY7HCNIg65eND
-kwtGaQPdMRZlGG5kTITkoTdrFe/zj1foV/aohmKbktBn0+0PidNOCarodKvOS1Fj
-UlXxJJ1CcMsUD+O0f7pqPIcn6zuCZJlq+b4gWp65iourlO3zM+vqQlx+IN/0nYKP
-rI5SmQbb0J8BOOe5DNK0yn90A+L3Cw6pQBRsfxsVAHcKmHbuvWIk9qeL1H5Ljcnr
-BKcCAwEAAaOByzCByDAdBgNVHQ4EFgQUbAWwoKgDpKGQ0aV00hPZLleDNnMwHwYD
-VR0jBBgwFoAUbAWwoKgDpKGQ0aV00hPZLleDNnMwNwYIKwYBBQUHAQEEKzApMCcG
-CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
-IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBSgv4/K3FB
-/Uyb28WxYHKnz/QpkTYPzpJylT40q4QMryPo4Sg1KcnIeJoS1/EiHCHhsLTfrzbE
-ynEqbm9K1WVYMXrC0TBm4AphVOBhl3tBcljZAtoiiyHm1TFM0jwR2A0S8Nzr4B0W
-OnTenLSyu2nt4VMUnhwGP//nL4rR9jeJdrJhYF9IzqOP4LVvkhgh5KgfEnCGVCra
-eD1dPBO4tH+lgfBVz+pWtAqKyivKvgiepkwSmV8jkwhYcI/I+4gR/tYWx6M7H2t4
-sAUpn31MAbrtil+oOOmkwkTO6Dcd2B8W5O+Eux9LOrCaAFequlIc9Nr3aV3vjTXv
-XAP6jYf8kmAo
------END TRUSTED_CERTIFICATE-----
-
------BEGIN TIME-----
-MTUwMzAyMTIwMDAwWg==
------END TIME-----
-
------BEGIN VERIFY_RESULT-----
-U1VDQ0VTUw==
------END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/intermediary-lacks-basic-constraints.pem b/chromium/net/data/verify_certificate_chain_unittest/intermediary-lacks-basic-constraints.pem
deleted file mode 100644
index 016f94e14fd..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/intermediary-lacks-basic-constraints.pem
+++ /dev/null
@@ -1,278 +0,0 @@
-[Created by: generate-intermediary-lacks-basic-constraints.py]
-
-Certificate chain with 1 intermediary and a trusted root. The intermediary
-lacks the basic constraints extension, and hence is expected to fail validation
-(RFC 5280 requires v3 signing certificates have a BasicConstaints).
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Target
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:f3:d6:19:96:48:0c:01:e2:21:3d:98:21:52:df:
- 5a:79:95:01:e5:c2:ab:77:e4:7b:10:17:64:75:a4:
- ca:b6:69:cc:a9:4a:1d:b6:7f:a0:16:89:32:21:c2:
- 2a:c2:58:28:d2:f3:ef:a5:2d:81:92:47:17:d5:61:
- 65:ab:43:22:ce:59:5b:20:31:be:6e:84:23:19:d5:
- 7e:a8:70:50:6c:de:06:b8:58:09:97:fd:02:98:31:
- 2d:3b:ab:1b:4a:82:6c:28:ab:c5:a3:6b:ea:40:2b:
- 48:02:73:e4:ce:ea:f6:3b:6a:80:1f:5b:59:30:86:
- 1b:5e:64:61:b5:94:d2:f0:c8:bb:88:b1:90:05:1a:
- e8:e6:97:dc:7d:e8:53:c8:9f:88:09:69:82:1f:1e:
- e2:d1:70:f3:85:06:63:18:0a:d2:f1:71:a3:25:a3:
- 42:76:3a:5e:02:78:e6:7a:c6:a4:82:dd:79:35:5a:
- da:8e:37:92:82:bf:01:13:1b:6e:52:97:97:32:f1:
- b2:4e:95:bc:55:89:61:61:73:b4:64:30:b1:89:87:
- 51:17:29:f3:67:de:5b:99:ee:47:71:07:8c:d5:17:
- 55:e0:70:bc:b6:06:6e:eb:7a:c6:69:69:97:e1:3d:
- 1d:be:93:da:a0:fa:cb:2f:f0:ed:5c:da:18:0e:67:
- 89:8d
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- FD:C8:4E:91:CD:73:65:1D:13:F9:EC:F0:91:13:F1:D0:01:AD:1E:7C
- X509v3 Authority Key Identifier:
- keyid:60:E7:1E:8E:53:95:1F:8F:00:D1:F7:9F:36:01:26:15:86:53:0E:F2
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Intermediary.crl
-
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage:
- TLS Web Server Authentication, TLS Web Client Authentication
- Signature Algorithm: sha256WithRSAEncryption
- 88:1d:e7:e6:1e:4b:93:a9:79:59:0e:10:43:1e:f7:79:a4:c7:
- 68:55:81:b6:b4:6d:b0:5b:b6:46:13:8b:4e:1c:d4:79:17:b1:
- 71:46:b6:69:21:92:fa:bf:bd:76:cc:6c:b1:04:58:28:41:79:
- 34:4f:09:e7:17:5c:d0:ac:fc:c5:2e:1e:5c:31:ca:ed:55:ea:
- df:4a:43:9a:72:37:0a:8a:69:dd:4e:e9:a3:ef:dd:48:45:41:
- 7b:55:e3:d1:98:69:a5:ec:0b:43:32:24:da:33:cd:fd:35:74:
- 17:81:b1:61:37:b1:12:5d:51:86:e6:a2:08:e5:c7:99:aa:f7:
- 23:c4:5f:83:c0:59:9c:36:f9:a0:4c:03:f7:40:42:fb:90:39:
- 5a:45:e5:e2:94:a3:58:c2:a1:d8:c9:aa:3e:83:98:b0:32:a1:
- 85:9a:b1:34:c7:67:a4:03:67:6e:5b:d7:83:b8:92:0f:af:81:
- b5:00:50:c4:0f:f6:bb:cd:7d:0f:a8:cd:28:bb:48:b8:32:82:
- ef:d1:cf:96:74:e4:25:74:ce:5e:4c:75:d2:80:55:a3:6b:a6:
- 76:eb:aa:3e:2b:55:d3:c9:bd:2b:32:d3:1d:01:00:cb:8d:c4:
- c0:b9:29:0b:10:e5:ab:34:2f:30:63:29:df:a8:4f:b3:28:dd:
- 0b:8c:ea:14
------BEGIN CERTIFICATE-----
-MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDz1hmW
-SAwB4iE9mCFS31p5lQHlwqt35HsQF2R1pMq2acypSh22f6AWiTIhwirCWCjS8++l
-LYGSRxfVYWWrQyLOWVsgMb5uhCMZ1X6ocFBs3ga4WAmX/QKYMS07qxtKgmwoq8Wj
-a+pAK0gCc+TO6vY7aoAfW1kwhhteZGG1lNLwyLuIsZAFGujml9x96FPIn4gJaYIf
-HuLRcPOFBmMYCtLxcaMlo0J2Ol4CeOZ6xqSC3Xk1WtqON5KCvwETG25Sl5cy8bJO
-lbxViWFhc7RkMLGJh1EXKfNn3luZ7kdxB4zVF1XgcLy2Bm7resZpaZfhPR2+k9qg
-+ssv8O1c2hgOZ4mNAgMBAAGjgekwgeYwHQYDVR0OBBYEFP3ITpHNc2UdE/ns8JET
-8dABrR58MB8GA1UdIwQYMBaAFGDnHo5TlR+PANH3nzYBJhWGUw7yMD8GCCsGAQUF
-BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAiB3n5h5Lk6l5WQ4QQx73
-eaTHaFWBtrRtsFu2RhOLThzUeRexcUa2aSGS+r+9dsxssQRYKEF5NE8J5xdc0Kz8
-xS4eXDHK7VXq30pDmnI3Copp3U7po+/dSEVBe1Xj0ZhppewLQzIk2jPN/TV0F4Gx
-YTexEl1RhuaiCOXHmar3I8Rfg8BZnDb5oEwD90BC+5A5WkXl4pSjWMKh2MmqPoOY
-sDKhhZqxNMdnpANnblvXg7iSD6+BtQBQxA/2u819D6jNKLtIuDKC79HPlnTkJXTO
-Xkx10oBVo2umduuqPitV08m9KzLTHQEAy43EwLkpCxDlqzQvMGMp36hPsyjdC4zq
-FA==
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 2 (0x2)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:a0:8f:6c:dd:c5:0d:76:a9:8a:da:5d:9f:94:cf:
- 9a:18:cd:32:ee:e1:c3:88:29:0d:40:7d:8b:37:9c:
- 18:b9:ed:11:81:5b:cc:8c:7c:4a:f3:e2:b9:eb:f7:
- 3c:74:5a:5c:78:37:e3:7e:a8:b9:34:d7:da:d2:dc:
- 52:de:c6:bb:ca:cd:39:c3:ea:8e:84:1b:e5:ad:4b:
- 67:1b:70:bd:70:0e:5e:20:95:37:bf:ae:d1:f4:b0:
- 97:c0:8a:d3:e5:2a:04:d8:eb:1d:c8:f0:95:1b:25:
- d4:49:ae:d4:5f:d9:bc:ea:19:2d:38:d3:d2:c4:8b:
- 77:37:45:ae:f9:70:b2:43:93:85:06:58:e0:3e:38:
- 11:32:d2:bc:a5:d4:df:09:2d:e9:c4:16:a7:f9:5b:
- 25:8d:57:f7:bf:01:4e:c8:25:b4:f8:5d:33:1d:7a:
- 04:4b:9d:fe:71:d4:65:78:4b:8d:52:ef:04:80:d4:
- 45:18:1d:d8:53:8e:2a:e8:23:3f:14:a4:b4:f1:00:
- ff:30:be:06:c5:61:ac:13:e8:cb:4c:ef:77:f7:6b:
- 1d:da:5a:d4:7f:f8:5a:87:cb:4b:45:05:8c:06:73:
- 7b:65:d5:71:c9:35:c7:6e:07:ce:0b:e2:54:e1:43:
- f0:da:a9:51:b8:ad:fe:da:de:29:8c:5f:2d:40:06:
- 7f:39
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 60:E7:1E:8E:53:95:1F:8F:00:D1:F7:9F:36:01:26:15:86:53:0E:F2
- X509v3 Authority Key Identifier:
- keyid:73:D9:03:F6:54:EA:FC:42:DA:77:EC:19:89:AD:6D:D2:A3:3E:E9:FD
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- Signature Algorithm: sha256WithRSAEncryption
- 43:31:7d:91:39:1d:8a:88:6c:d2:2d:36:b1:92:53:1d:18:24:
- e9:42:27:c3:d3:f1:77:69:6f:67:7b:39:46:32:fb:36:a1:8d:
- 07:ee:16:6b:ac:09:e3:78:38:7a:a7:4b:fe:3f:81:eb:f2:85:
- aa:d6:3e:5a:68:57:e3:98:0d:ae:ee:45:84:d1:ed:6d:9c:78:
- fe:63:50:94:55:5e:b5:41:ef:c9:16:ed:4f:38:03:cb:73:3c:
- 79:c1:c4:0c:c1:95:43:11:49:c0:bc:7e:9a:6a:05:d2:43:c4:
- 66:72:66:57:69:46:ed:a7:10:af:bf:e9:bb:48:72:4b:00:a2:
- 46:78:38:68:dd:6b:a9:ac:62:70:4b:0b:f3:29:fa:a7:a2:42:
- 4b:d7:88:1f:97:1f:71:60:20:82:89:d6:3a:60:d5:4b:08:28:
- 6a:6a:97:2e:c9:93:d8:a7:32:b7:e1:68:be:07:7a:3c:76:3b:
- 2c:1b:10:17:4c:c9:ea:ee:48:c9:ad:ac:2e:61:dd:16:eb:62:
- 1e:33:1d:6c:8a:b4:56:0f:3d:04:35:f3:8f:d0:12:f9:66:8d:
- 39:95:e9:44:41:32:7e:f3:17:2e:58:c9:0c:23:b1:e3:db:f7:
- ed:da:bd:94:0e:00:27:34:3d:3d:c6:48:d8:e4:a3:66:57:d9:
- 5e:13:3e:59
------BEGIN CERTIFICATE-----
-MIIDXDCCAkSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoI9s3cUN
-dqmK2l2flM+aGM0y7uHDiCkNQH2LN5wYue0RgVvMjHxK8+K56/c8dFpceDfjfqi5
-NNfa0txS3sa7ys05w+qOhBvlrUtnG3C9cA5eIJU3v67R9LCXwIrT5SoE2OsdyPCV
-GyXUSa7UX9m86hktONPSxIt3N0Wu+XCyQ5OFBljgPjgRMtK8pdTfCS3pxBan+Vsl
-jVf3vwFOyCW0+F0zHXoES53+cdRleEuNUu8EgNRFGB3YU44q6CM/FKS08QD/ML4G
-xWGsE+jLTO9392sd2lrUf/hah8tLRQWMBnN7ZdVxyTXHbgfOC+JU4UPw2qlRuK3+
-2t4pjF8tQAZ/OQIDAQABo4G6MIG3MB0GA1UdDgQWBBRg5x6OU5UfjwDR9582ASYV
-hlMO8jAfBgNVHSMEGDAWgBRz2QP2VOr8Qtp37BmJrW3Soz7p/TA3BggrBgEFBQcB
-AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
-BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
-VR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQBDMX2ROR2KiGzSLTaxklMd
-GCTpQifD0/F3aW9nezlGMvs2oY0H7hZrrAnjeDh6p0v+P4Hr8oWq1j5aaFfjmA2u
-7kWE0e1tnHj+Y1CUVV61Qe/JFu1POAPLczx5wcQMwZVDEUnAvH6aagXSQ8RmcmZX
-aUbtpxCvv+m7SHJLAKJGeDho3WuprGJwSwvzKfqnokJL14gflx9xYCCCidY6YNVL
-CChqapcuyZPYpzK34Wi+B3o8djssGxAXTMnq7kjJrawuYd0W62IeMx1sirRWDz0E
-NfOP0BL5Zo05lelEQTJ+8xcuWMkMI7Hj2/ft2r2UDgAnND09xkjY5KNmV9leEz5Z
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Root
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:ea:c6:b8:66:62:c2:1a:2a:7d:83:ca:b2:7b:11:
- e4:92:4a:b8:3a:39:35:73:aa:89:55:7d:f4:ec:40:
- 4b:2c:c7:56:58:ac:9d:25:ef:c3:26:86:98:c4:74:
- a4:3a:94:36:d8:78:7c:1a:f4:f7:5c:a0:56:69:fc:
- 23:c0:a4:06:5f:5b:ce:ea:cb:32:9b:c3:21:89:fd:
- 9f:4e:38:a2:b9:f4:de:af:44:1e:53:02:09:41:44:
- 92:bc:a5:4f:70:86:23:85:48:2a:51:01:70:ab:b0:
- c4:bd:97:3c:2f:d0:2c:3e:9c:be:40:2e:ee:be:f8:
- ed:63:a2:1b:fd:e2:0f:d1:b2:3b:b3:ce:da:84:59:
- 56:bb:77:17:93:ef:c0:b7:b4:11:db:b9:6e:b0:4a:
- 28:55:fb:56:4e:ed:22:b6:e3:4d:5b:ad:6a:af:ff:
- df:33:f9:18:a6:91:0a:b8:89:d3:28:55:18:c7:71:
- 19:32:bc:88:a8:ee:5b:c8:34:84:e5:f5:fe:6e:5e:
- c0:3b:73:9b:a4:bc:4c:6a:8a:5a:31:c0:34:f3:c3:
- 89:e0:57:97:64:01:dd:c2:9f:75:8e:e3:fd:b3:58:
- b5:0b:e3:4d:8f:94:e8:9b:0c:c2:12:af:13:31:30:
- d1:a6:1c:2c:f1:0a:7a:a4:17:e2:2f:6f:73:cb:22:
- 15:67
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 73:D9:03:F6:54:EA:FC:42:DA:77:EC:19:89:AD:6D:D2:A3:3E:E9:FD
- X509v3 Authority Key Identifier:
- keyid:73:D9:03:F6:54:EA:FC:42:DA:77:EC:19:89:AD:6D:D2:A3:3E:E9:FD
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- e0:b7:24:3a:ee:4c:8d:42:9f:b9:52:2b:7d:21:c5:7b:dd:2b:
- bc:6a:5d:86:57:ee:d5:1f:27:e6:e1:08:e3:72:a3:10:2b:97:
- 1b:98:b9:39:18:6e:7f:b8:b0:1c:f1:f5:d9:7e:1d:05:3f:5b:
- f4:cd:1e:66:7f:77:ed:ab:d0:51:b6:ad:6c:a6:66:ab:fc:31:
- a1:ac:ee:66:ae:3b:af:4e:3c:c6:29:07:dc:1a:ac:b5:10:3f:
- 3f:ad:27:1b:bc:32:19:ab:b3:75:62:47:23:d1:b8:60:78:ac:
- 96:0c:4f:b8:31:7b:40:7e:f3:f7:ba:a9:ae:9b:65:ef:c5:e3:
- fc:c8:28:c6:c0:74:48:00:33:48:a4:e6:3c:0c:5b:a0:1e:c2:
- 57:c5:0c:24:34:c3:36:c0:8a:f3:a6:c3:16:24:32:c3:dc:81:
- 76:54:3e:00:68:c8:6a:b6:ee:9f:ab:44:64:64:37:54:ff:1b:
- b9:a5:c2:bf:ff:a5:68:b3:5a:ef:d7:bc:64:39:24:2e:ad:c7:
- a3:9c:ef:60:cb:ab:de:45:f1:40:65:95:01:0c:52:ea:a8:d6:
- 8b:77:e0:2e:1f:2b:4f:a3:bc:b8:80:6b:8d:92:42:66:17:10:
- 4b:d4:b0:2d:8d:4c:77:50:74:83:0e:9a:4c:0d:3b:6b:3d:c6:
- 0a:2e:f6:5c
------BEGIN TRUSTED_CERTIFICATE-----
-MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOrGuGZiwhoqfYPKsnsR
-5JJKuDo5NXOqiVV99OxASyzHVlisnSXvwyaGmMR0pDqUNth4fBr091ygVmn8I8Ck
-Bl9bzurLMpvDIYn9n044orn03q9EHlMCCUFEkrylT3CGI4VIKlEBcKuwxL2XPC/Q
-LD6cvkAu7r747WOiG/3iD9GyO7PO2oRZVrt3F5PvwLe0Edu5brBKKFX7Vk7tIrbj
-TVutaq//3zP5GKaRCriJ0yhVGMdxGTK8iKjuW8g0hOX1/m5ewDtzm6S8TGqKWjHA
-NPPDieBXl2QB3cKfdY7j/bNYtQvjTY+U6JsMwhKvEzEw0aYcLPEKeqQX4i9vc8si
-FWcCAwEAAaOByzCByDAdBgNVHQ4EFgQUc9kD9lTq/ELad+wZia1t0qM+6f0wHwYD
-VR0jBBgwFoAUc9kD9lTq/ELad+wZia1t0qM+6f0wNwYIKwYBBQUHAQEEKzApMCcG
-CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
-IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDgtyQ67kyN
-Qp+5Uit9IcV73Su8al2GV+7VHyfm4QjjcqMQK5cbmLk5GG5/uLAc8fXZfh0FP1v0
-zR5mf3ftq9BRtq1spmar/DGhrO5mrjuvTjzGKQfcGqy1ED8/rScbvDIZq7N1Ykcj
-0bhgeKyWDE+4MXtAfvP3uqmum2XvxeP8yCjGwHRIADNIpOY8DFugHsJXxQwkNMM2
-wIrzpsMWJDLD3IF2VD4AaMhqtu6fq0RkZDdU/xu5pcK//6Vos1rv17xkOSQurcej
-nO9gy6veRfFAZZUBDFLqqNaLd+AuHytPo7y4gGuNkkJmFxBL1LAtjUx3UHSDDppM
-DTtrPcYKLvZc
------END TRUSTED_CERTIFICATE-----
-
------BEGIN TIME-----
-MTUwMzAyMTIwMDAwWg==
------END TIME-----
-
------BEGIN VERIFY_RESULT-----
-RkFJTA==
------END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/intermediary-lacks-signing-key-usage.pem b/chromium/net/data/verify_certificate_chain_unittest/intermediary-lacks-signing-key-usage.pem
deleted file mode 100644
index 63275452fce..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/intermediary-lacks-signing-key-usage.pem
+++ /dev/null
@@ -1,281 +0,0 @@
-[Created by: generate-intermediary-lacks-signing-key-usage.py]
-
-Certificate chain with 1 intermediary and a trusted root. The intermediary
-contains a keyUsage extension, HOWEVER it does not contain the keyCertSign bit.
-Hence validation is expected to fail.
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Target
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:b6:80:03:5a:ee:21:94:59:e3:bf:eb:26:bb:b5:
- 2e:39:80:35:38:e7:7e:1d:e6:17:d2:fb:50:be:d2:
- 03:33:14:ee:1f:a2:f8:78:bb:d0:60:e2:0c:ff:59:
- 80:52:fb:5a:3d:38:2d:26:9e:d6:af:df:f2:ff:49:
- f7:ec:8a:02:2b:51:02:d3:53:f9:6e:2b:ed:68:5e:
- 90:54:03:7b:f7:0c:08:93:59:9f:41:2c:27:05:6c:
- dd:dc:f8:a8:ea:78:c0:6d:a1:c8:11:cd:e8:40:cc:
- 6c:65:db:16:50:20:07:68:00:c0:7f:c5:89:fe:e8:
- 6a:0c:36:6a:ad:5a:ab:40:8e:4c:0e:e9:51:a0:6b:
- 28:b8:df:c0:7c:3c:6c:a7:b8:8b:9e:07:1f:e5:29:
- 01:5b:81:76:ca:53:80:b8:a4:8f:1a:35:66:b7:96:
- 24:ac:fb:44:a1:4c:71:c6:28:6d:91:75:59:1a:bf:
- e4:8e:15:71:43:3f:24:3f:b4:db:a0:2c:5e:af:46:
- 16:65:7e:25:0c:90:5e:16:7b:e3:a6:47:0f:03:fe:
- 31:cc:06:dc:ba:0e:0b:fa:6b:e5:4a:53:11:c4:00:
- 54:d5:76:09:97:12:38:31:12:9d:27:49:e8:4d:01:
- 18:0c:54:b3:c7:a8:c3:fc:60:3f:92:0b:ef:9f:72:
- 8e:59
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 76:E3:64:67:6F:B9:A6:B7:6E:DC:62:12:09:FE:30:0A:19:F4:BF:B3
- X509v3 Authority Key Identifier:
- keyid:5A:C6:0B:DA:37:A3:BB:21:85:17:C5:EF:0C:FA:BF:A9:79:B1:FE:29
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Intermediary.crl
-
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage:
- TLS Web Server Authentication, TLS Web Client Authentication
- Signature Algorithm: sha256WithRSAEncryption
- 92:d5:77:f8:65:61:e9:66:0d:f7:00:9b:46:28:26:52:37:9f:
- 3c:15:33:01:95:61:b9:0c:a1:c3:e7:f5:09:6a:4c:ba:0f:3b:
- 80:3a:65:c3:22:e7:9d:e7:4d:c3:ca:3a:bc:88:98:6c:a3:8e:
- 56:4e:64:98:b7:85:a7:aa:d3:e8:9a:b3:e4:2f:7d:18:bf:74:
- c7:29:d9:51:a7:39:4a:4b:e1:94:14:0b:f9:af:e9:89:26:98:
- cb:b2:b7:64:d4:ab:42:f5:68:cb:40:78:72:91:02:13:fe:05:
- 41:68:42:c2:e0:d5:ea:bd:56:52:6f:76:b3:20:f4:e6:39:2a:
- 83:ea:7a:c9:d2:37:4a:45:c4:ad:ac:6a:24:38:6e:fd:d6:ed:
- 4c:42:cf:87:2c:7d:21:e5:18:ee:3a:c0:1e:83:ac:25:70:9a:
- f5:fd:e7:4e:ab:67:0e:5d:00:9f:44:e4:e5:d6:d9:02:43:05:
- 91:c3:66:a6:1f:8a:ce:ae:c8:2b:4d:c6:0e:9e:5f:d7:ff:e7:
- b6:39:a7:f1:19:b0:3a:59:33:6a:72:a6:03:6b:42:e7:f8:07:
- a3:0d:2d:f7:31:c3:f4:e5:cf:8b:24:42:0c:29:40:5a:7d:df:
- 65:81:8c:0f:cb:86:e6:2b:39:26:58:0b:18:b8:4c:87:6c:10:
- 03:0b:7c:c4
------BEGIN CERTIFICATE-----
-MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2gANa
-7iGUWeO/6ya7tS45gDU4534d5hfS+1C+0gMzFO4fovh4u9Bg4gz/WYBS+1o9OC0m
-ntav3/L/SffsigIrUQLTU/luK+1oXpBUA3v3DAiTWZ9BLCcFbN3c+KjqeMBtocgR
-zehAzGxl2xZQIAdoAMB/xYn+6GoMNmqtWqtAjkwO6VGgayi438B8PGynuIueBx/l
-KQFbgXbKU4C4pI8aNWa3liSs+0ShTHHGKG2RdVkav+SOFXFDPyQ/tNugLF6vRhZl
-fiUMkF4We+OmRw8D/jHMBty6Dgv6a+VKUxHEAFTVdgmXEjgxEp0nSehNARgMVLPH
-qMP8YD+SC++fco5ZAgMBAAGjgekwgeYwHQYDVR0OBBYEFHbjZGdvuaa3btxiEgn+
-MAoZ9L+zMB8GA1UdIwQYMBaAFFrGC9o3o7shhRfF7wz6v6l5sf4pMD8GCCsGAQUF
-BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAktV3+GVh6WYN9wCbRigm
-UjefPBUzAZVhuQyhw+f1CWpMug87gDplwyLnnedNw8o6vIiYbKOOVk5kmLeFp6rT
-6Jqz5C99GL90xynZUac5SkvhlBQL+a/piSaYy7K3ZNSrQvVoy0B4cpECE/4FQWhC
-wuDV6r1WUm92syD05jkqg+p6ydI3SkXEraxqJDhu/dbtTELPhyx9IeUY7jrAHoOs
-JXCa9f3nTqtnDl0An0Tk5dbZAkMFkcNmph+Kzq7IK03GDp5f1//ntjmn8RmwOlkz
-anKmA2tC5/gHow0t9zHD9OXPiyRCDClAWn3fZYGMD8uG5is5JlgLGLhMh2wQAwt8
-xA==
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 2 (0x2)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:9b:71:4d:95:69:ff:1c:81:da:58:66:90:29:ae:
- 15:48:a6:43:09:a2:05:75:ca:16:d1:a5:69:e0:77:
- c8:c1:f4:e5:e2:4d:97:c6:09:e4:e0:98:64:c2:b7:
- 7f:11:5a:ee:7a:3e:c5:d8:24:b0:b8:a2:98:ac:05:
- bd:71:07:71:6a:11:67:17:55:5c:2d:d3:fe:4b:d0:
- e1:f3:d5:08:de:7e:c2:56:ff:e6:95:6f:11:7f:5a:
- 34:e7:0c:1c:e3:82:f6:f4:e1:ed:4e:ce:60:2f:f7:
- 5d:b8:b1:54:f0:c8:aa:28:5d:56:90:24:7b:cf:a7:
- 01:de:d9:63:16:a3:7b:5e:34:c9:8c:35:50:57:fc:
- be:6c:48:70:83:7a:52:d9:19:f8:e8:a2:91:f3:23:
- 34:f3:14:b6:3d:59:e6:86:05:9b:26:ec:14:fa:78:
- d3:91:a4:af:f7:c5:01:15:c0:3c:84:b8:5f:09:62:
- ab:c3:b3:51:df:14:20:47:ee:0b:5f:85:06:42:4d:
- b3:5a:e0:08:14:32:d8:0a:8b:7a:41:f5:0e:34:cc:
- 4a:a3:79:be:6d:b5:cd:d1:b8:e0:71:2a:81:e1:22:
- bc:6c:fe:89:59:97:ee:71:ad:d7:e1:d4:ea:01:85:
- 0a:ae:83:a1:09:65:3c:2e:68:29:e1:3f:b0:c2:c7:
- 90:85
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 5A:C6:0B:DA:37:A3:BB:21:85:17:C5:EF:0C:FA:BF:A9:79:B1:FE:29
- X509v3 Authority Key Identifier:
- keyid:D3:3B:10:26:28:99:EC:09:2A:08:9C:53:7D:24:9F:B1:F1:04:0B:B5
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- 53:21:fb:72:d3:86:6c:af:f6:75:07:5c:bc:0c:7a:97:8f:05:
- b8:86:af:ee:af:ca:9b:c0:89:2f:28:cd:79:a7:a3:70:04:37:
- 8b:ca:4d:84:3a:72:d5:9a:2e:f9:85:64:59:5b:7f:7e:b4:bf:
- 09:74:af:fe:f1:d1:8c:47:3a:1b:87:9d:73:ce:a1:de:8f:33:
- f7:ad:b4:7d:83:d5:e2:60:ff:f4:b2:79:ee:6b:fb:db:ae:c5:
- f5:1c:e9:20:9a:b9:71:31:c9:55:02:a1:e1:9b:a6:b7:dd:c0:
- cc:e1:66:02:91:fe:a1:59:67:bf:3b:45:32:20:08:a0:08:66:
- eb:47:2d:db:24:6f:ab:3c:53:9b:96:81:5f:61:4a:fa:bb:70:
- 2a:31:a1:2b:ff:cc:ae:1c:c9:be:e5:a6:f1:6a:6e:b1:3f:4b:
- 30:59:e3:a7:9f:f2:6e:6d:9d:ed:5f:b9:cf:b2:07:66:84:63:
- 53:f4:64:c7:d1:b2:62:63:c6:ec:a2:09:89:c5:bc:75:96:bc:
- d2:a5:86:f7:9c:28:1c:47:45:30:e6:90:87:c6:e3:2b:be:d3:
- 8e:b7:89:30:f3:f3:83:14:f6:56:be:0c:e7:34:6e:6f:b4:f3:
- 0c:17:87:dd:a8:e2:8b:ec:34:24:dc:0c:16:dc:e4:c4:21:da:
- dc:ba:9d:a6
------BEGIN CERTIFICATE-----
-MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm3FNlWn/
-HIHaWGaQKa4VSKZDCaIFdcoW0aVp4HfIwfTl4k2Xxgnk4Jhkwrd/EVruej7F2CSw
-uKKYrAW9cQdxahFnF1VcLdP+S9Dh89UI3n7CVv/mlW8Rf1o05wwc44L29OHtTs5g
-L/dduLFU8MiqKF1WkCR7z6cB3tljFqN7XjTJjDVQV/y+bEhwg3pS2Rn46KKR8yM0
-8xS2PVnmhgWbJuwU+njTkaSv98UBFcA8hLhfCWKrw7NR3xQgR+4LX4UGQk2zWuAI
-FDLYCot6QfUONMxKo3m+bbXN0bjgcSqB4SK8bP6JWZfuca3X4dTqAYUKroOhCWU8
-Lmgp4T+wwseQhQIDAQABo4HLMIHIMB0GA1UdDgQWBBRaxgvaN6O7IYUXxe8M+r+p
-ebH+KTAfBgNVHSMEGDAWgBTTOxAmKJnsCSoInFN9JJ+x8QQLtTA3BggrBgEFBQcB
-AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
-BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
-VR0PAQH/BAQDAgWgMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
-AFMh+3LThmyv9nUHXLwMepePBbiGr+6vypvAiS8ozXmno3AEN4vKTYQ6ctWaLvmF
-ZFlbf360vwl0r/7x0YxHOhuHnXPOod6PM/ettH2D1eJg//Syee5r+9uuxfUc6SCa
-uXExyVUCoeGbprfdwMzhZgKR/qFZZ787RTIgCKAIZutHLdskb6s8U5uWgV9hSvq7
-cCoxoSv/zK4cyb7lpvFqbrE/SzBZ46ef8m5tne1fuc+yB2aEY1P0ZMfRsmJjxuyi
-CYnFvHWWvNKlhvecKBxHRTDmkIfG4yu+0463iTDz84MU9la+DOc0bm+08wwXh92o
-4ovsNCTcDBbc5MQh2ty6naY=
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Root
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:99:27:87:07:8d:52:53:4f:bc:b6:55:16:e3:64:
- 12:13:89:32:c4:f9:6f:a2:9c:93:06:fc:4c:a9:4d:
- 09:1a:04:8a:24:58:74:7a:53:ad:d6:c6:29:0e:19:
- f2:cc:1e:02:72:2d:7f:52:4c:3a:88:dd:35:fc:c5:
- e6:d4:41:1a:b0:76:a7:b9:c1:db:d9:7a:a0:56:d8:
- e7:4c:a6:ed:45:ca:99:eb:4c:dd:44:5b:52:79:00:
- 1b:f0:ca:fc:19:c9:39:d7:1c:24:e5:90:f8:77:f7:
- 4a:cd:0c:ec:dc:c5:15:6d:43:de:43:b4:f9:03:b9:
- fa:b9:8f:4f:b4:e2:9f:dd:e8:d5:af:9f:ab:79:ce:
- 32:2f:be:04:85:e8:2f:5e:91:26:b5:08:a1:ef:11:
- f5:20:28:8d:09:9f:4e:b9:5a:ef:cf:45:b3:aa:6e:
- 14:1b:fe:1e:c3:4b:39:ad:76:9a:58:b5:be:c4:ae:
- ce:0e:03:ef:8e:5d:a7:03:00:e7:ed:88:0e:97:8e:
- 2d:bd:82:6e:d8:39:7f:c0:7e:4e:c8:1e:eb:60:cb:
- f7:97:dd:fb:79:ee:a8:00:4a:40:b7:1c:2f:1a:59:
- 5a:51:36:a9:aa:0b:97:a0:d0:d5:87:5e:b9:36:73:
- 5c:31:fc:b6:8c:ef:f1:2a:f5:ea:6d:2b:05:d2:8c:
- 60:87
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- D3:3B:10:26:28:99:EC:09:2A:08:9C:53:7D:24:9F:B1:F1:04:0B:B5
- X509v3 Authority Key Identifier:
- keyid:D3:3B:10:26:28:99:EC:09:2A:08:9C:53:7D:24:9F:B1:F1:04:0B:B5
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- 2e:84:d8:57:d4:09:e8:0e:8f:b5:9c:8f:48:ef:62:40:49:3e:
- 9a:2e:b9:85:1c:77:f6:94:f3:73:0e:06:58:d4:63:5d:20:90:
- e4:4b:c8:39:64:ca:ec:04:8c:bb:dd:b2:58:81:3e:89:05:1d:
- 42:19:f9:d4:92:24:de:03:6c:69:36:74:95:65:b3:a4:06:83:
- 2b:9f:93:72:57:dc:53:09:be:d2:fb:23:39:df:85:73:9a:c2:
- c4:2d:7e:aa:36:01:dd:4e:a6:4f:fe:61:99:21:9c:89:a4:e7:
- f8:8e:03:92:f6:cc:24:08:db:c8:59:41:6e:ea:c2:c3:4a:54:
- d6:93:e5:3d:17:ff:24:a4:f7:55:2b:3c:d2:40:a7:2a:67:df:
- 67:66:f5:37:ef:aa:20:d2:5a:da:d1:19:08:43:be:ae:11:f3:
- 43:80:8a:ce:15:af:04:c5:b5:10:21:7c:f6:5e:7a:68:8e:59:
- 40:ca:4b:be:c7:59:1b:48:a4:a1:ee:ef:57:b4:5b:d9:93:3b:
- a2:36:3b:b6:f2:54:1e:c8:97:7e:5c:62:99:6c:f6:b0:bf:df:
- af:5a:52:64:99:39:93:20:dc:4f:5e:a6:fe:8d:19:e2:21:1f:
- 95:9d:7c:e8:8e:05:eb:74:ed:60:8e:ee:76:17:a8:40:56:36:
- ac:bf:61:b9
------BEGIN TRUSTED_CERTIFICATE-----
-MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJknhweNUlNPvLZVFuNk
-EhOJMsT5b6Kckwb8TKlNCRoEiiRYdHpTrdbGKQ4Z8sweAnItf1JMOojdNfzF5tRB
-GrB2p7nB29l6oFbY50ym7UXKmetM3URbUnkAG/DK/BnJOdccJOWQ+Hf3Ss0M7NzF
-FW1D3kO0+QO5+rmPT7Tin93o1a+fq3nOMi++BIXoL16RJrUIoe8R9SAojQmfTrla
-789Fs6puFBv+HsNLOa12mli1vsSuzg4D745dpwMA5+2IDpeOLb2Cbtg5f8B+Tsge
-62DL95fd+3nuqABKQLccLxpZWlE2qaoLl6DQ1YdeuTZzXDH8tozv8Sr16m0rBdKM
-YIcCAwEAAaOByzCByDAdBgNVHQ4EFgQU0zsQJiiZ7AkqCJxTfSSfsfEEC7UwHwYD
-VR0jBBgwFoAU0zsQJiiZ7AkqCJxTfSSfsfEEC7UwNwYIKwYBBQUHAQEEKzApMCcG
-CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
-IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAuhNhX1Ano
-Do+1nI9I72JAST6aLrmFHHf2lPNzDgZY1GNdIJDkS8g5ZMrsBIy73bJYgT6JBR1C
-GfnUkiTeA2xpNnSVZbOkBoMrn5NyV9xTCb7S+yM534VzmsLELX6qNgHdTqZP/mGZ
-IZyJpOf4jgOS9swkCNvIWUFu6sLDSlTWk+U9F/8kpPdVKzzSQKcqZ99nZvU376og
-0lra0RkIQ76uEfNDgIrOFa8ExbUQIXz2XnpojllAyku+x1kbSKSh7u9XtFvZkzui
-Nju28lQeyJd+XGKZbPawv9+vWlJkmTmTINxPXqb+jRniIR+VnXzojgXrdO1gju52
-F6hAVjasv2G5
------END TRUSTED_CERTIFICATE-----
-
------BEGIN TIME-----
-MTUwMzAyMTIwMDAwWg==
------END TIME-----
-
------BEGIN VERIFY_RESULT-----
-RkFJTA==
------END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/intermediary-signed-with-md5.pem b/chromium/net/data/verify_certificate_chain_unittest/intermediary-signed-with-md5.pem
deleted file mode 100644
index d15448165e2..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/intermediary-signed-with-md5.pem
+++ /dev/null
@@ -1,281 +0,0 @@
-[Created by: generate-intermediary-signed-with-md5.py]
-
-Certificate chain with 1 intermediary and a trusted root. The intermediary
-however is signed using the MD5 hash. Verification is expected to fail because
-MD5 is too weak.
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Target
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:e9:b3:cb:c4:9b:c5:59:0a:ca:5e:ca:b3:7b:e1:
- bb:ec:3d:4b:10:7b:d4:ee:71:92:1c:c0:24:af:0b:
- c4:5e:55:3b:af:aa:e3:43:a3:d3:ae:1c:db:7b:fe:
- 2a:35:d0:d8:49:77:09:f5:5d:65:9b:84:42:93:da:
- 64:a4:12:f7:f5:6d:91:2f:7c:96:aa:7b:50:09:67:
- 1d:f6:76:a2:4f:64:6c:d7:78:c6:78:f4:5c:83:3a:
- 01:64:3c:15:37:4e:2a:b9:48:2a:ce:42:36:35:59:
- b0:b0:f6:4c:db:21:59:14:87:91:09:d8:18:76:b8:
- fb:0c:b4:e4:ab:5a:24:27:e5:47:9c:c7:eb:d0:74:
- 17:5b:13:9a:f7:96:b7:1d:de:84:8c:6a:fd:c7:92:
- 53:09:72:31:66:aa:54:07:3d:1c:2c:86:e9:68:d8:
- 12:f6:22:ec:37:b5:58:6c:26:fe:79:c5:d0:f7:42:
- 79:f9:ad:7a:3a:f4:0a:52:3e:5a:5b:45:d9:a8:d1:
- 18:35:db:9d:56:81:11:49:f9:77:0d:ff:a7:1e:39:
- 63:14:3b:64:3d:d0:2f:1b:47:c6:ad:6a:a8:d8:c9:
- 09:cd:58:0b:5d:de:ad:aa:56:38:bd:42:0f:f9:c6:
- 9d:c0:da:b0:06:03:a5:3f:43:5f:e1:83:74:cc:a7:
- ab:9f
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- E8:2D:DF:58:DB:57:BD:6D:98:31:15:C9:58:49:E0:02:47:79:10:9D
- X509v3 Authority Key Identifier:
- keyid:0E:AF:B4:0B:04:28:C3:55:B4:F8:2D:EB:A1:62:49:26:60:A2:A7:D8
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Intermediary.crl
-
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage:
- TLS Web Server Authentication, TLS Web Client Authentication
- Signature Algorithm: sha256WithRSAEncryption
- a2:d6:e1:fe:94:8d:78:bc:5b:9e:53:1a:b9:6b:76:32:2e:66:
- 0b:b3:ce:8f:96:9a:33:37:b6:e2:fb:99:56:2e:3b:cb:3d:d3:
- 96:c7:b8:05:9a:00:e4:f4:72:f6:97:b2:b3:72:08:3d:17:59:
- af:98:b3:16:a2:cb:e7:b8:bf:c1:5b:49:92:28:9c:47:bd:29:
- 9e:56:f8:52:67:eb:de:23:69:52:79:32:1f:ba:b5:58:d3:b6:
- 19:58:ac:62:04:a5:29:9a:7b:df:90:ad:c1:b1:42:c4:6c:a6:
- 16:db:af:5e:ee:85:83:9e:c9:02:ba:c6:3c:63:55:93:58:36:
- b4:86:b8:fa:e4:09:6f:98:6f:23:2a:2c:98:04:e4:2c:fd:69:
- 61:b2:36:88:8f:a2:70:ec:2a:47:6d:e0:cb:f8:5c:07:25:71:
- f4:f6:af:50:a7:d7:49:d8:c8:08:4a:09:12:8c:21:bc:d7:54:
- f2:04:fc:f0:33:2f:aa:b1:a7:d3:0a:d0:96:0f:69:7c:a4:a8:
- cd:a5:a6:d3:d2:6a:b1:f2:b1:0a:81:18:68:18:23:c1:6f:9c:
- 40:9f:d2:2d:6d:e2:52:36:05:4e:99:ae:b2:e1:b3:da:40:99:
- 1f:c6:9f:ae:9b:43:1d:e3:db:58:7c:96:b5:b8:cc:b6:b7:e9:
- 1b:57:a0:61
------BEGIN CERTIFICATE-----
-MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDps8vE
-m8VZCspeyrN74bvsPUsQe9TucZIcwCSvC8ReVTuvquNDo9OuHNt7/io10NhJdwn1
-XWWbhEKT2mSkEvf1bZEvfJaqe1AJZx32dqJPZGzXeMZ49FyDOgFkPBU3Tiq5SCrO
-QjY1WbCw9kzbIVkUh5EJ2Bh2uPsMtOSrWiQn5Uecx+vQdBdbE5r3lrcd3oSMav3H
-klMJcjFmqlQHPRwshulo2BL2Iuw3tVhsJv55xdD3Qnn5rXo69ApSPlpbRdmo0Rg1
-251WgRFJ+XcN/6ceOWMUO2Q90C8bR8ataqjYyQnNWAtd3q2qVji9Qg/5xp3A2rAG
-A6U/Q1/hg3TMp6ufAgMBAAGjgekwgeYwHQYDVR0OBBYEFOgt31jbV71tmDEVyVhJ
-4AJHeRCdMB8GA1UdIwQYMBaAFA6vtAsEKMNVtPgt66FiSSZgoqfYMD8GCCsGAQUF
-BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAotbh/pSNeLxbnlMauWt2
-Mi5mC7POj5aaMze24vuZVi47yz3Tlse4BZoA5PRy9peys3IIPRdZr5izFqLL57i/
-wVtJkiicR70pnlb4Umfr3iNpUnkyH7q1WNO2GVisYgSlKZp735CtwbFCxGymFtuv
-Xu6Fg57JArrGPGNVk1g2tIa4+uQJb5hvIyosmATkLP1pYbI2iI+icOwqR23gy/hc
-ByVx9PavUKfXSdjICEoJEowhvNdU8gT88DMvqrGn0wrQlg9pfKSozaWm09JqsfKx
-CoEYaBgjwW+cQJ/SLW3iUjYFTpmusuGz2kCZH8afrptDHePbWHyWtbjMtrfpG1eg
-YQ==
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 2 (0x2)
- Signature Algorithm: md5WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:e9:c2:e1:d4:1c:a8:bf:ff:07:7f:17:bf:a4:f7:
- f5:bc:e3:1f:76:32:e2:a3:e4:5c:a2:5d:83:a4:ad:
- c7:19:12:8a:20:dc:5c:d3:db:22:97:e5:59:09:d8:
- 7f:95:bc:79:61:c2:66:d1:69:02:fc:98:02:12:8e:
- f4:4e:63:4d:1f:d0:df:f9:25:f0:86:f0:17:ba:3d:
- 1c:5c:7d:7c:0a:f5:fc:f5:f3:a1:1f:44:45:30:e5:
- f2:02:b8:e2:04:69:50:f7:b8:10:1d:35:92:56:3b:
- 06:42:fc:a7:e5:45:40:b0:0c:2f:2c:61:dd:0e:55:
- cb:23:7d:8b:48:b6:ac:68:b3:e3:3b:fc:07:a4:89:
- 17:3e:e3:fc:74:12:e6:2f:15:b8:78:dc:a2:6b:6b:
- 98:e2:36:f6:69:26:71:21:20:d1:60:4d:44:ea:32:
- fd:54:64:4a:f1:6a:94:f3:51:43:e8:f9:5f:68:9e:
- 03:a8:a8:6c:a2:0e:55:e5:d8:87:ad:62:db:61:5b:
- a8:4b:1a:dc:f3:14:9f:97:24:5c:32:98:e4:9b:8b:
- 1e:32:d4:12:d0:5b:a1:c1:f6:2e:85:42:c4:dc:60:
- 8f:b1:b2:8b:7a:63:3e:ad:95:62:60:2a:0e:88:dc:
- 5c:10:c6:90:ab:6b:75:d2:42:f4:b2:a9:81:5a:d8:
- 0e:41
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 0E:AF:B4:0B:04:28:C3:55:B4:F8:2D:EB:A1:62:49:26:60:A2:A7:D8
- X509v3 Authority Key Identifier:
- keyid:DE:7E:F6:82:CA:37:00:C9:C3:30:07:35:D1:BA:48:C5:9B:B6:2D:A7
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: md5WithRSAEncryption
- 03:a2:90:68:d8:0d:83:e4:1c:83:20:2e:0b:ff:60:1c:01:a9:
- ec:66:71:cd:3b:61:2c:10:95:ab:42:4e:fc:05:bb:40:d3:8c:
- 00:34:72:b3:8f:74:de:21:67:0a:e8:b4:93:3d:c3:a2:a0:a0:
- f0:4b:d9:7d:c6:2b:4f:dd:31:12:ad:72:3c:54:58:5c:21:3f:
- 75:39:46:80:da:f3:20:1d:93:a3:ef:bb:00:91:bd:8d:22:16:
- d9:5e:c7:a1:45:39:1a:76:d9:7d:e6:86:6c:65:0e:29:50:4b:
- 5f:40:ec:79:9c:9a:d0:d9:fa:6a:6a:90:62:db:fa:9e:28:1a:
- 40:e4:b3:45:90:41:26:09:d4:7c:f7:5c:58:ce:c5:67:6a:d1:
- 41:86:73:df:6e:cb:79:70:75:5f:d2:54:53:07:e0:53:d1:45:
- d9:4b:e7:f6:2b:60:fb:56:b4:17:79:be:2a:7e:98:0d:ad:ea:
- d1:79:5d:87:80:65:84:15:61:d8:dd:a8:3c:5f:f0:90:a6:0b:
- d8:c5:ca:d8:8d:fb:2f:1b:f8:a2:4d:ea:33:71:c2:30:a5:3b:
- 56:a4:73:79:51:b7:7a:e7:6c:f7:23:52:48:61:1c:82:54:97:
- 0d:54:e5:80:07:bb:84:d7:ee:90:ee:4d:85:df:f7:34:fb:d3:
- d8:bf:19:7f
------BEGIN CERTIFICATE-----
-MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQQFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6cLh1Byo
-v/8Hfxe/pPf1vOMfdjLio+Rcol2DpK3HGRKKINxc09sil+VZCdh/lbx5YcJm0WkC
-/JgCEo70TmNNH9Df+SXwhvAXuj0cXH18CvX89fOhH0RFMOXyArjiBGlQ97gQHTWS
-VjsGQvyn5UVAsAwvLGHdDlXLI32LSLasaLPjO/wHpIkXPuP8dBLmLxW4eNyia2uY
-4jb2aSZxISDRYE1E6jL9VGRK8WqU81FD6PlfaJ4DqKhsog5V5diHrWLbYVuoSxrc
-8xSflyRcMpjkm4seMtQS0FuhwfYuhULE3GCPsbKLemM+rZViYCoOiNxcEMaQq2t1
-0kL0sqmBWtgOQQIDAQABo4HLMIHIMB0GA1UdDgQWBBQOr7QLBCjDVbT4LeuhYkkm
-YKKn2DAfBgNVHSMEGDAWgBTefvaCyjcAycMwBzXRukjFm7YtpzA3BggrBgEFBQcB
-AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
-BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
-VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEB
-AAOikGjYDYPkHIMgLgv/YBwBqexmcc07YSwQlatCTvwFu0DTjAA0crOPdN4hZwro
-tJM9w6KgoPBL2X3GK0/dMRKtcjxUWFwhP3U5RoDa8yAdk6PvuwCRvY0iFtlex6FF
-ORp22X3mhmxlDilQS19A7HmcmtDZ+mpqkGLb+p4oGkDks0WQQSYJ1Hz3XFjOxWdq
-0UGGc99uy3lwdV/SVFMH4FPRRdlL5/YrYPtWtBd5vip+mA2t6tF5XYeAZYQVYdjd
-qDxf8JCmC9jFytiN+y8b+KJN6jNxwjClO1akc3lRt3rnbPcjUkhhHIJUlw1U5YAH
-u4TX7pDuTYXf9zT709i/GX8=
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Root
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:c6:d0:57:18:e0:d7:81:35:67:b0:a4:a1:5b:fd:
- 8f:32:51:4f:d9:76:67:02:84:59:10:4d:4a:b9:ed:
- 1d:ef:fe:5e:d4:69:c1:24:e3:1f:91:08:d8:15:de:
- 68:ca:dc:c7:fc:ea:6f:27:a5:60:45:af:0f:f1:44:
- b8:d7:c7:96:70:d9:e1:dd:84:aa:ea:65:52:62:67:
- e1:06:cd:d9:18:ad:eb:a3:0a:60:4b:cd:76:71:44:
- 26:3c:22:c7:44:74:77:31:50:a5:b3:c4:ef:ac:14:
- 1e:ea:ff:74:a0:7b:e4:7a:ca:87:dd:45:0b:bc:75:
- 4b:92:44:0f:e8:f3:d2:6d:3e:47:4b:cf:77:a2:e9:
- ff:f9:e2:79:9f:88:d7:ff:e5:cc:93:91:91:24:e1:
- 9f:ef:a4:13:15:cc:03:3e:06:ba:9d:4c:de:52:b9:
- de:c6:57:af:76:d8:9e:4b:37:11:1d:52:57:fe:af:
- 8e:11:1d:fd:a8:55:3b:84:c9:10:ac:dc:51:62:e8:
- c8:54:5b:3d:60:0b:8e:ad:66:2a:26:92:81:c6:a1:
- be:31:51:d3:28:b1:9e:86:67:ca:c4:f2:88:47:1c:
- 03:c9:f8:ee:f8:87:4c:b4:9e:24:9d:c0:48:d8:ec:
- a7:8b:52:7a:d0:65:cf:06:2a:63:7f:1c:c9:15:44:
- 48:01
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- DE:7E:F6:82:CA:37:00:C9:C3:30:07:35:D1:BA:48:C5:9B:B6:2D:A7
- X509v3 Authority Key Identifier:
- keyid:DE:7E:F6:82:CA:37:00:C9:C3:30:07:35:D1:BA:48:C5:9B:B6:2D:A7
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- 8c:97:4a:f9:c2:c2:57:2a:4b:a1:69:03:9e:c1:17:fb:4c:f2:
- 8e:36:0f:e2:c4:f6:4d:42:9c:ac:7f:67:7b:fd:7e:fd:14:3b:
- fb:df:08:3d:0e:23:fa:d1:47:d5:68:14:b2:1f:5c:40:db:fe:
- 8d:e6:fc:17:3a:c6:2f:5e:96:1a:3c:32:fa:63:c5:e5:cf:fc:
- db:6b:59:71:b8:f7:d2:70:78:cc:7f:8c:54:5f:c6:69:ba:98:
- 77:92:32:b3:a1:18:84:ed:3c:93:3f:12:93:64:e6:7f:92:8a:
- 4f:db:42:1d:c0:7c:0d:4a:d6:ef:ca:05:a3:5b:26:47:79:7e:
- 91:b0:e6:35:92:91:e2:2f:4d:18:17:44:b5:a7:de:8a:92:86:
- 4c:0c:de:0e:23:53:c0:30:1f:7a:c5:70:59:94:19:02:8a:f1:
- 23:f9:88:fb:09:af:b8:90:d6:c6:d5:46:92:74:44:8b:8e:66:
- b1:79:cb:82:3d:80:cc:cf:d9:03:5a:a3:71:a6:f5:f0:75:9f:
- 79:38:f0:fe:66:e5:d1:a1:9d:0a:48:e1:45:a1:42:fb:d3:16:
- 53:91:b9:c9:0d:27:8a:34:e0:59:8d:4f:e0:e7:7d:7d:0c:e6:
- ec:a1:ea:66:23:77:55:fc:f1:d0:13:32:1d:9e:0c:fd:3b:38:
- 1d:dc:2c:2b
------BEGIN TRUSTED_CERTIFICATE-----
-MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbQVxjg14E1Z7CkoVv9
-jzJRT9l2ZwKEWRBNSrntHe/+XtRpwSTjH5EI2BXeaMrcx/zqbyelYEWvD/FEuNfH
-lnDZ4d2EquplUmJn4QbN2Rit66MKYEvNdnFEJjwix0R0dzFQpbPE76wUHur/dKB7
-5HrKh91FC7x1S5JED+jz0m0+R0vPd6Lp//nieZ+I1//lzJORkSThn++kExXMAz4G
-up1M3lK53sZXr3bYnks3ER1SV/6vjhEd/ahVO4TJEKzcUWLoyFRbPWALjq1mKiaS
-gcahvjFR0yixnoZnysTyiEccA8n47viHTLSeJJ3ASNjsp4tSetBlzwYqY38cyRVE
-SAECAwEAAaOByzCByDAdBgNVHQ4EFgQU3n72gso3AMnDMAc10bpIxZu2LacwHwYD
-VR0jBBgwFoAU3n72gso3AMnDMAc10bpIxZu2LacwNwYIKwYBBQUHAQEEKzApMCcG
-CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
-IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCMl0r5wsJX
-KkuhaQOewRf7TPKONg/ixPZNQpysf2d7/X79FDv73wg9DiP60UfVaBSyH1xA2/6N
-5vwXOsYvXpYaPDL6Y8Xlz/zba1lxuPfScHjMf4xUX8Zpuph3kjKzoRiE7TyTPxKT
-ZOZ/kopP20IdwHwNStbvygWjWyZHeX6RsOY1kpHiL00YF0S1p96KkoZMDN4OI1PA
-MB96xXBZlBkCivEj+Yj7Ca+4kNbG1UaSdESLjmaxecuCPYDMz9kDWqNxpvXwdZ95
-OPD+ZuXRoZ0KSOFFoUL70xZTkbnJDSeKNOBZjU/g5319DObsoepmI3dV/PHQEzId
-ngz9Ozgd3Cwr
------END TRUSTED_CERTIFICATE-----
-
------BEGIN TIME-----
-MTUwMzAyMTIwMDAwWg==
------END TIME-----
-
------BEGIN VERIFY_RESULT-----
-RkFJTA==
------END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/intermediary-unknown-critical-extension.pem b/chromium/net/data/verify_certificate_chain_unittest/intermediary-unknown-critical-extension.pem
deleted file mode 100644
index 7e7045c1158..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/intermediary-unknown-critical-extension.pem
+++ /dev/null
@@ -1,284 +0,0 @@
-[Created by: generate-intermediary-unknown-critical-extension.py]
-
-Certificate chain with 1 intermediary and a trusted root. The intermediary
-has an unknown X.509v3 extension (OID=1.2.3.4) that is marked as critical.
-Verifying this certificate chain is expected to fail because there is an
-unrecognized critical extension.
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Target
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:cf:51:a6:c4:9e:d4:eb:c4:eb:d6:57:2b:80:e5:
- da:cd:db:3a:cf:b0:43:c5:18:9c:4e:b7:c4:9c:18:
- 73:e6:85:e6:00:00:76:25:9f:5d:8f:28:19:f2:05:
- 02:a9:5c:75:65:12:38:d7:7a:eb:e3:46:42:07:3d:
- 3b:c4:5d:32:7b:26:fb:1e:69:cb:36:ca:c2:da:2f:
- b4:ec:e3:bf:5e:9a:d3:8a:6d:3e:f2:53:dc:da:40:
- 3c:fe:fd:02:36:32:f5:b2:17:bf:05:97:f0:3e:8b:
- b7:15:a2:10:be:27:79:62:30:82:3e:57:60:60:13:
- 8e:fc:33:8e:72:cd:d9:d9:50:e9:62:04:8c:e4:db:
- f8:cf:1b:da:a2:f7:ee:4c:b8:7f:b2:bf:92:c9:2c:
- 44:a7:b5:ad:b9:75:06:c0:24:5a:0b:44:ca:4f:af:
- f6:2f:c2:00:12:bb:7b:0c:c4:54:47:f1:73:53:64:
- 72:40:9d:51:40:b3:21:73:ce:82:c5:f3:b7:14:ef:
- 31:50:5b:d5:0b:b7:92:0e:08:5c:ea:ed:73:86:e3:
- b1:6d:63:7f:56:7d:74:3e:3b:90:8c:2f:a2:6e:65:
- b9:4e:38:a3:54:fb:7b:de:69:6f:c0:57:ea:51:c0:
- 09:83:b4:a8:4d:ec:74:a6:ea:31:97:0c:9a:66:b7:
- 58:0f
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 89:EB:AF:F5:F3:C7:53:ED:03:95:5A:DB:94:4A:E0:BF:C3:D2:CE:FA
- X509v3 Authority Key Identifier:
- keyid:21:32:55:0D:16:9C:AD:C4:16:5D:BE:40:67:0D:B6:40:4E:E2:75:60
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Intermediary.crl
-
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage:
- TLS Web Server Authentication, TLS Web Client Authentication
- Signature Algorithm: sha256WithRSAEncryption
- 17:7b:87:2f:11:ac:6d:68:03:d3:07:31:20:18:b7:d4:9d:98:
- e4:aa:10:6d:f2:41:2f:3e:cf:1f:50:f9:f9:3f:6e:61:c2:b7:
- dd:e0:f6:5a:d6:66:bb:2d:31:98:6a:12:0a:17:e8:a1:4e:cd:
- fd:c4:ed:3e:01:a3:1c:ef:18:9e:fb:f8:46:c6:1b:ad:a4:ce:
- ba:84:79:a6:84:f0:2c:84:d4:6c:3f:f9:ff:f8:66:f1:9b:82:
- 8c:83:c8:79:5b:bd:f0:dd:e0:e5:76:55:92:97:d2:46:64:ea:
- 3e:99:bc:9d:b8:8f:15:41:f8:3f:1b:c0:df:cd:d5:01:88:74:
- 37:8e:58:f8:ad:7d:75:70:59:98:cc:c4:bd:fc:b9:bd:f5:69:
- fe:09:08:be:ea:e8:f3:ee:53:d8:05:4f:d5:d1:85:dc:7e:58:
- 64:cf:d4:41:c1:d0:ec:c4:2a:ca:ae:39:8e:57:63:e3:03:ff:
- 4f:d4:42:92:ec:ac:e8:f6:83:e5:51:0e:32:2c:6f:2d:15:72:
- 21:37:f0:18:77:3b:97:f5:71:84:1f:07:e0:76:b6:a0:f4:34:
- 16:b9:53:e2:4f:48:45:b6:7d:b3:0f:30:06:e6:89:89:a4:3f:
- e8:4c:2a:9c:1f:9c:91:c9:66:4e:28:39:3d:5b:21:19:03:dc:
- 02:56:69:e9
------BEGIN CERTIFICATE-----
-MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPUabE
-ntTrxOvWVyuA5drN2zrPsEPFGJxOt8ScGHPmheYAAHYln12PKBnyBQKpXHVlEjjX
-euvjRkIHPTvEXTJ7Jvseacs2ysLaL7Ts479emtOKbT7yU9zaQDz+/QI2MvWyF78F
-l/A+i7cVohC+J3liMII+V2BgE478M45yzdnZUOliBIzk2/jPG9qi9+5MuH+yv5LJ
-LESnta25dQbAJFoLRMpPr/YvwgASu3sMxFRH8XNTZHJAnVFAsyFzzoLF87cU7zFQ
-W9ULt5IOCFzq7XOG47FtY39WfXQ+O5CML6JuZblOOKNU+3veaW/AV+pRwAmDtKhN
-7HSm6jGXDJpmt1gPAgMBAAGjgekwgeYwHQYDVR0OBBYEFInrr/Xzx1PtA5Va25RK
-4L/D0s76MB8GA1UdIwQYMBaAFCEyVQ0WnK3EFl2+QGcNtkBO4nVgMD8GCCsGAQUF
-BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAF3uHLxGsbWgD0wcxIBi3
-1J2Y5KoQbfJBLz7PH1D5+T9uYcK33eD2WtZmuy0xmGoSChfooU7N/cTtPgGjHO8Y
-nvv4RsYbraTOuoR5poTwLITUbD/5//hm8ZuCjIPIeVu98N3g5XZVkpfSRmTqPpm8
-nbiPFUH4PxvA383VAYh0N45Y+K19dXBZmMzEvfy5vfVp/gkIvuro8+5T2AVP1dGF
-3H5YZM/UQcHQ7MQqyq45jldj4wP/T9RCkuys6PaD5VEOMixvLRVyITfwGHc7l/Vx
-hB8H4Ha2oPQ0FrlT4k9IRbZ9sw8wBuaJiaQ/6EwqnB+ckclmTig5PVshGQPcAlZp
-6Q==
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 2 (0x2)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:c7:80:3b:a7:4e:4e:fa:0a:39:4f:5b:5c:af:ba:
- 84:27:6a:8d:34:95:5e:91:93:c8:d0:1f:64:84:5f:
- 25:d9:3b:5d:f9:31:5f:4f:6f:04:be:50:35:09:5e:
- 78:f3:9a:15:b5:27:fa:24:70:04:26:29:08:95:a5:
- dd:b1:ee:4f:ee:d8:a0:59:51:ab:75:70:c2:7b:42:
- 06:e2:4d:d7:91:ec:e5:e7:f8:34:1e:01:63:45:11:
- 6a:fe:45:3e:e7:16:59:86:e7:4b:91:67:ec:1f:c1:
- 13:a4:62:cb:f6:0d:9b:2b:e5:1e:df:c4:35:f3:94:
- 60:9b:99:e1:54:ce:ff:7d:92:f1:9d:d4:f6:0e:99:
- 8c:dc:7b:b1:95:54:04:6f:40:1c:23:42:50:ab:96:
- f5:9e:93:27:f1:5c:e5:97:9c:c1:e4:ae:a8:cb:f9:
- 42:7e:14:02:e1:32:4b:4d:03:2d:2a:a6:7e:a1:77:
- c3:4e:4e:46:18:1a:95:d7:0d:48:8d:a1:d3:bb:b7:
- 55:07:01:d9:c0:27:fd:f7:ec:61:3a:57:84:b6:91:
- 78:dc:a9:19:a6:d4:83:c5:57:67:bd:b7:a0:6a:ec:
- 7b:83:1e:d9:bf:2f:b7:bf:d6:ce:18:5a:54:cf:8b:
- 1a:fc:5a:03:63:bc:d2:3a:01:db:91:e0:ce:96:19:
- 55:19
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 21:32:55:0D:16:9C:AD:C4:16:5D:BE:40:67:0D:B6:40:4E:E2:75:60
- X509v3 Authority Key Identifier:
- keyid:BA:1F:26:2C:E0:77:F2:16:78:6D:83:49:A1:30:9E:B4:AB:10:6A:22
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- 1.2.3.4: critical
- ....
- Signature Algorithm: sha256WithRSAEncryption
- 02:57:1a:5a:82:9a:29:1e:39:b4:aa:c4:e3:04:2b:6f:1c:0a:
- 79:df:d3:f8:c9:9f:94:b6:c1:7e:e5:47:8d:35:72:e2:09:ce:
- 6f:61:f1:7e:93:f3:37:11:0d:c0:28:05:bc:8d:dc:f8:2a:22:
- 0e:dc:79:b9:71:99:38:f5:c2:81:ac:0b:47:c2:39:96:2e:2b:
- 35:0a:fe:80:fe:50:da:74:03:1c:4b:36:be:4b:23:70:4f:a1:
- 1f:c8:3b:9a:6b:92:3d:61:9b:67:9a:8b:ea:0b:b0:8c:aa:6a:
- 02:fd:27:6f:a8:be:8f:d0:78:f2:84:76:da:e2:c5:10:3c:9f:
- 61:c4:3f:50:8e:40:ac:d8:aa:87:b6:7c:da:42:c5:05:c0:82:
- bc:9f:35:ae:22:34:32:11:71:ab:fd:27:af:ef:42:ec:cd:b7:
- d1:66:14:5f:f1:e5:10:c2:1f:ac:e4:96:1f:a9:9c:5a:ad:97:
- 4d:90:40:df:cb:77:15:ba:d5:f4:76:94:9f:d6:c2:4f:53:60:
- 3b:c3:a3:9c:02:4d:03:28:32:58:3d:0f:62:36:a9:7b:70:d9:
- f8:2b:05:cd:ca:c7:17:68:76:6b:cd:ad:7f:f1:65:a6:d1:be:
- b7:4c:83:bb:0d:5d:98:6e:02:d3:b6:ea:82:b6:44:0d:a1:b2:
- 37:4b:a0:a3
------BEGIN CERTIFICATE-----
-MIIDfTCCAmWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx4A7p05O
-+go5T1tcr7qEJ2qNNJVekZPI0B9khF8l2Ttd+TFfT28EvlA1CV5485oVtSf6JHAE
-JikIlaXdse5P7tigWVGrdXDCe0IG4k3Xkezl5/g0HgFjRRFq/kU+5xZZhudLkWfs
-H8ETpGLL9g2bK+Ue38Q185Rgm5nhVM7/fZLxndT2DpmM3HuxlVQEb0AcI0JQq5b1
-npMn8Vzll5zB5K6oy/lCfhQC4TJLTQMtKqZ+oXfDTk5GGBqV1w1IjaHTu7dVBwHZ
-wCf99+xhOleEtpF43KkZptSDxVdnvbegaux7gx7Zvy+3v9bOGFpUz4sa/FoDY7zS
-OgHbkeDOlhlVGQIDAQABo4HbMIHYMB0GA1UdDgQWBBQhMlUNFpytxBZdvkBnDbZA
-TuJ1YDAfBgNVHSMEGDAWgBS6HyYs4HfyFnhtg0mhMJ60qxBqIjA3BggrBgEFBQcB
-AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
-BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
-VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDgYDKgMEAQH/BAQBAgMEMA0G
-CSqGSIb3DQEBCwUAA4IBAQACVxpagpopHjm0qsTjBCtvHAp539P4yZ+UtsF+5UeN
-NXLiCc5vYfF+k/M3EQ3AKAW8jdz4KiIO3Hm5cZk49cKBrAtHwjmWLis1Cv6A/lDa
-dAMcSza+SyNwT6EfyDuaa5I9YZtnmovqC7CMqmoC/SdvqL6P0HjyhHba4sUQPJ9h
-xD9QjkCs2KqHtnzaQsUFwIK8nzWuIjQyEXGr/Sev70LszbfRZhRf8eUQwh+s5JYf
-qZxarZdNkEDfy3cVutX0dpSf1sJPU2A7w6OcAk0DKDJYPQ9iNql7cNn4KwXNyscX
-aHZrza1/8WWm0b63TIO7DV2YbgLTtuqCtkQNobI3S6Cj
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Root
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:9f:42:45:62:cb:c5:f3:07:65:8a:9b:4c:d4:91:
- 4a:66:e6:89:24:24:6f:91:3e:4a:50:63:42:47:e3:
- 67:10:71:ac:f3:81:82:3b:9f:56:7c:6a:36:a6:87:
- be:d5:e6:03:4b:bb:d3:c8:90:6a:6b:1d:4c:16:a1:
- c3:98:58:f7:39:de:90:27:df:40:c5:03:10:b2:b4:
- 1b:cb:28:5d:80:a4:83:60:f2:c0:ac:f5:1f:81:4d:
- 31:84:6f:04:96:7b:26:bf:b6:55:78:33:06:23:65:
- 1c:bc:65:ac:a3:31:27:49:38:ce:92:73:87:a7:b4:
- 53:4b:85:71:29:7a:f5:09:fc:03:9a:90:56:14:b1:
- b7:89:03:c4:61:b6:49:fc:3d:30:62:84:a2:46:66:
- 22:37:32:fd:a3:62:bb:99:62:53:ca:fc:1f:e9:29:
- c6:d4:8c:09:6f:02:d5:de:7c:de:12:d8:00:dd:df:
- 04:94:d4:36:b5:f6:d9:fe:a7:ff:46:e7:07:da:3e:
- d0:e3:ea:90:4c:7c:b7:ff:bc:85:99:d5:1f:46:f5:
- ac:57:e9:09:03:61:8c:0b:9d:a8:82:9c:17:43:27:
- de:80:d2:59:e3:ca:ed:23:41:1a:32:48:83:ca:bd:
- 8e:cb:bf:9c:f0:03:7d:e0:41:ce:72:05:27:59:3c:
- 10:5b
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- BA:1F:26:2C:E0:77:F2:16:78:6D:83:49:A1:30:9E:B4:AB:10:6A:22
- X509v3 Authority Key Identifier:
- keyid:BA:1F:26:2C:E0:77:F2:16:78:6D:83:49:A1:30:9E:B4:AB:10:6A:22
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- 70:b4:15:ff:b7:d9:b7:51:10:ce:fa:e5:61:0e:f6:c7:b6:d7:
- be:59:ed:07:d5:77:95:e1:ef:3f:80:9e:99:d2:2c:1b:9a:a7:
- 35:1c:ec:84:9e:ce:27:52:3a:2c:00:06:4d:60:62:aa:4b:a7:
- 61:32:e3:64:f1:96:c7:d2:3f:fe:78:bc:f4:da:76:f9:44:d2:
- 9b:1a:94:1f:44:9a:49:c9:c0:1c:de:a9:63:d0:23:4a:c3:fb:
- 60:45:76:dd:12:ef:c1:95:4f:8e:bd:48:56:b8:f9:74:e2:5c:
- ae:90:5a:19:9e:90:13:0b:97:ff:cd:a9:45:54:68:aa:fa:f6:
- ea:3f:2e:fa:2a:40:48:42:cd:10:cc:c8:e6:a4:34:9d:8f:1c:
- 74:55:58:b2:99:cf:35:40:23:bf:90:5f:4c:60:30:5f:a0:b4:
- d6:0f:4f:42:03:71:82:f7:d3:f5:72:bb:a8:cf:24:ab:10:7e:
- c5:e1:84:a9:7e:25:b1:8a:80:db:ae:0e:49:f1:03:fb:11:1a:
- 63:58:42:7f:73:9b:f3:f8:d6:ae:81:0b:59:ca:98:ec:3d:9c:
- 85:6b:7d:70:e8:c2:04:47:f0:b6:7e:4a:96:70:c9:a8:11:b7:
- 23:54:55:d3:57:c3:7e:47:66:35:91:26:56:fd:37:14:35:a4:
- 6b:29:38:ee
------BEGIN TRUSTED_CERTIFICATE-----
-MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ9CRWLLxfMHZYqbTNSR
-SmbmiSQkb5E+SlBjQkfjZxBxrPOBgjufVnxqNqaHvtXmA0u708iQamsdTBahw5hY
-9znekCffQMUDELK0G8soXYCkg2DywKz1H4FNMYRvBJZ7Jr+2VXgzBiNlHLxlrKMx
-J0k4zpJzh6e0U0uFcSl69Qn8A5qQVhSxt4kDxGG2Sfw9MGKEokZmIjcy/aNiu5li
-U8r8H+kpxtSMCW8C1d583hLYAN3fBJTUNrX22f6n/0bnB9o+0OPqkEx8t/+8hZnV
-H0b1rFfpCQNhjAudqIKcF0Mn3oDSWePK7SNBGjJIg8q9jsu/nPADfeBBznIFJ1k8
-EFsCAwEAAaOByzCByDAdBgNVHQ4EFgQUuh8mLOB38hZ4bYNJoTCetKsQaiIwHwYD
-VR0jBBgwFoAUuh8mLOB38hZ4bYNJoTCetKsQaiIwNwYIKwYBBQUHAQEEKzApMCcG
-CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
-IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBwtBX/t9m3
-URDO+uVhDvbHtte+We0H1XeV4e8/gJ6Z0iwbmqc1HOyEns4nUjosAAZNYGKqS6dh
-MuNk8ZbH0j/+eLz02nb5RNKbGpQfRJpJycAc3qlj0CNKw/tgRXbdEu/BlU+OvUhW
-uPl04lyukFoZnpATC5f/zalFVGiq+vbqPy76KkBIQs0QzMjmpDSdjxx0VViymc81
-QCO/kF9MYDBfoLTWD09CA3GC99P1cruozySrEH7F4YSpfiWxioDbrg5J8QP7ERpj
-WEJ/c5vz+NaugQtZypjsPZyFa31w6MIER/C2fkqWcMmoEbcjVFXTV8N+R2Y1kSZW
-/TcUNaRrKTju
------END TRUSTED_CERTIFICATE-----
-
------BEGIN TIME-----
-MTUwMzAyMTIwMDAwWg==
------END TIME-----
-
------BEGIN VERIFY_RESULT-----
-RkFJTA==
------END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/intermediary-unknown-non-critical-extension.pem b/chromium/net/data/verify_certificate_chain_unittest/intermediary-unknown-non-critical-extension.pem
deleted file mode 100644
index dffed19e120..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/intermediary-unknown-non-critical-extension.pem
+++ /dev/null
@@ -1,284 +0,0 @@
-[Created by: generate-intermediary-unknown-non-critical-extension.py]
-
-Certificate chain with 1 intermediary and a trusted root. The intermediary
-has an unknown X.509v3 extension that is marked as non-critical. Verification
-is expected to succeed because although unrecognized, the extension is not
-critical.
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Target
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:e2:f4:a3:48:79:59:87:08:4d:c1:84:b4:97:67:
- 5d:f6:24:2b:74:f1:f0:1a:13:e0:a5:28:30:1f:c6:
- 04:fc:ce:9b:73:4a:95:1f:56:a0:9d:26:07:97:8f:
- 7c:06:c7:a2:fb:5f:85:41:d3:bd:50:83:61:72:5e:
- a0:f9:e1:39:c6:ae:77:05:8c:f7:8e:6f:ae:5d:14:
- 69:97:12:4a:c7:40:de:e7:ab:7a:83:9b:b3:e8:15:
- 90:ab:52:3a:ee:c4:36:9b:58:eb:51:c3:1d:c5:c8:
- eb:f7:65:e9:15:56:93:e4:55:37:97:29:f1:88:da:
- fc:1c:53:5f:24:07:f9:3e:14:86:b3:50:c6:94:06:
- 8e:b1:b1:ab:32:d4:f3:98:ee:f8:42:ed:65:43:36:
- bb:4f:59:a0:4d:77:a5:9e:a9:c2:40:40:df:cc:3c:
- d7:dc:56:bd:d4:2c:fe:b5:20:d6:a8:74:cd:99:4f:
- bf:eb:71:0b:20:95:f2:c3:21:92:42:d7:e6:ff:5b:
- 87:0b:c2:89:5c:e7:d6:30:77:cd:8d:c7:92:0d:74:
- 6f:88:d6:81:49:e8:f6:25:de:6d:51:3e:db:cd:e4:
- 91:99:98:5a:ff:7a:61:46:da:7a:ec:9b:22:a5:5f:
- 16:6e:cd:7a:ec:3b:b0:aa:1b:af:65:a6:3a:85:fc:
- a6:e9
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 82:EC:E0:87:C2:A2:2A:EF:4B:E0:B5:F8:75:6A:18:32:51:B4:0D:54
- X509v3 Authority Key Identifier:
- keyid:60:BD:98:38:CE:C3:01:40:CA:86:14:C7:F4:E4:D5:72:BA:ED:80:31
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Intermediary.crl
-
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage:
- TLS Web Server Authentication, TLS Web Client Authentication
- Signature Algorithm: sha256WithRSAEncryption
- 89:1e:64:8c:61:b5:87:aa:76:6d:f6:ef:87:b6:ca:3b:0f:47:
- a9:bb:9a:91:7f:7a:d8:65:e9:c7:b1:1a:ea:13:fb:9c:79:5e:
- df:33:f5:d9:bc:f1:f8:89:bc:59:31:27:c2:2d:3e:47:e9:13:
- 27:65:c8:cb:ba:e1:da:51:60:7a:93:aa:28:92:d5:81:89:09:
- b7:22:e7:4b:4f:82:0e:fb:2f:62:19:b4:ea:f5:47:34:fd:60:
- 7e:4c:e6:be:08:8e:f8:fd:89:62:ff:97:89:27:69:37:7f:e3:
- 76:ea:72:30:ca:de:73:bb:c7:65:1c:6d:5e:ab:f8:ba:da:57:
- 7d:28:1f:6a:64:76:aa:89:6b:ac:57:a3:e9:e2:c1:ca:f8:4b:
- 7c:0b:21:57:cc:71:c8:9b:7f:25:8f:09:61:6e:5c:a8:9b:0b:
- 79:98:7a:1e:82:95:22:fd:9e:9c:cd:20:73:0d:0e:d9:21:cb:
- 67:3d:e9:1e:24:ae:4f:84:1f:de:3e:27:ee:54:41:66:71:9c:
- b6:6b:08:7a:16:e7:c1:c7:7a:71:24:ed:c0:2a:d9:fd:2b:ff:
- e6:41:c9:63:93:90:52:35:21:4a:72:be:f9:9c:27:49:0d:b7:
- 01:af:cb:5f:53:ee:ef:58:69:16:ba:e6:5b:12:45:e0:d4:3d:
- ea:58:fe:a5
------BEGIN CERTIFICATE-----
-MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDi9KNI
-eVmHCE3BhLSXZ132JCt08fAaE+ClKDAfxgT8zptzSpUfVqCdJgeXj3wGx6L7X4VB
-071Qg2FyXqD54TnGrncFjPeOb65dFGmXEkrHQN7nq3qDm7PoFZCrUjruxDabWOtR
-wx3FyOv3ZekVVpPkVTeXKfGI2vwcU18kB/k+FIazUMaUBo6xsasy1POY7vhC7WVD
-NrtPWaBNd6WeqcJAQN/MPNfcVr3ULP61INaodM2ZT7/rcQsglfLDIZJC1+b/W4cL
-wolc59Ywd82Nx5INdG+I1oFJ6PYl3m1RPtvN5JGZmFr/emFG2nrsmyKlXxZuzXrs
-O7CqG69lpjqF/KbpAgMBAAGjgekwgeYwHQYDVR0OBBYEFILs4IfCoirvS+C1+HVq
-GDJRtA1UMB8GA1UdIwQYMBaAFGC9mDjOwwFAyoYUx/Tk1XK67YAxMD8GCCsGAQUF
-BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAiR5kjGG1h6p2bfbvh7bK
-Ow9HqbuakX962GXpx7Ea6hP7nHle3zP12bzx+Im8WTEnwi0+R+kTJ2XIy7rh2lFg
-epOqKJLVgYkJtyLnS0+CDvsvYhm06vVHNP1gfkzmvgiO+P2JYv+XiSdpN3/jdupy
-MMrec7vHZRxtXqv4utpXfSgfamR2qolrrFej6eLByvhLfAshV8xxyJt/JY8JYW5c
-qJsLeZh6HoKVIv2enM0gcw0O2SHLZz3pHiSuT4Qf3j4n7lRBZnGctmsIehbnwcd6
-cSTtwCrZ/Sv/5kHJY5OQUjUhSnK++ZwnSQ23Aa/LX1Pu71hpFrrmWxJF4NQ96lj+
-pQ==
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 2 (0x2)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:de:7c:cd:1c:92:c3:9a:ff:be:f3:03:37:c7:6a:
- 3a:d4:ac:56:50:3a:b1:17:0d:73:09:ef:d9:16:4b:
- 38:de:a4:82:46:61:a8:ed:f8:b9:a0:21:7e:3c:26:
- f6:a8:c5:d3:34:99:9c:58:c6:e1:de:f6:1c:eb:49:
- a3:34:65:71:29:95:3a:2e:b4:5f:33:dd:2a:0b:5f:
- 7a:e0:47:3f:bc:00:15:a1:24:26:9f:c6:c7:d7:eb:
- e3:f3:37:19:d5:30:48:f2:7d:c5:77:11:cc:cc:17:
- 7e:91:c4:20:f8:a6:c3:28:00:ec:23:53:40:7b:0e:
- dc:14:6e:57:a5:ca:52:9f:2b:3b:34:ea:e4:ae:5c:
- ed:b4:8d:25:9a:08:00:26:d0:e4:34:d2:94:36:8c:
- e1:df:ef:31:f8:18:5b:ed:80:57:44:77:94:a2:fa:
- ae:5c:e0:ea:e1:30:e3:24:03:da:7c:5b:66:90:c7:
- 01:f1:f8:8d:ca:bc:d7:e3:25:35:28:3c:f6:f4:83:
- 13:2a:73:d0:f7:c2:69:11:b1:ed:43:6d:71:28:7e:
- 43:8d:f5:f0:78:e2:5a:31:39:38:ae:92:05:29:e0:
- 1f:04:6f:9d:a0:a1:b4:29:80:af:87:1c:0c:e5:7d:
- 6d:11:59:63:43:af:7f:a4:32:fa:0a:d1:7e:88:86:
- cd:61
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 60:BD:98:38:CE:C3:01:40:CA:86:14:C7:F4:E4:D5:72:BA:ED:80:31
- X509v3 Authority Key Identifier:
- keyid:B2:41:26:7A:EF:3A:C9:BF:FE:6A:E7:7F:04:60:B0:34:62:08:E3:93
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- 1.2.3.4:
- ....
- Signature Algorithm: sha256WithRSAEncryption
- 68:5c:74:6c:fd:93:14:86:9f:d9:3a:4b:67:1d:6e:2b:78:2f:
- 89:b4:b0:76:ac:3f:aa:ea:4a:ea:42:04:40:96:09:1a:b7:b7:
- 01:93:fb:55:0d:44:30:0e:16:b3:e8:bb:b2:77:17:79:93:37:
- 17:b5:62:c9:5b:15:76:90:2d:74:3d:1f:7e:59:61:59:e2:61:
- 81:18:46:6b:94:42:be:be:d3:1e:37:16:68:49:db:9e:f0:f1:
- 24:bb:e0:00:e0:57:e0:27:3f:59:e9:a8:92:31:80:2a:7a:cc:
- b1:47:5b:8d:3b:55:f5:5a:f0:9a:56:90:1a:8e:d2:ab:51:e2:
- 15:ca:9f:cb:a9:ec:10:f1:5d:58:72:84:75:63:bd:a7:7c:bf:
- 5b:80:65:d6:97:77:e2:8a:89:8a:ea:5b:1f:da:55:5e:7b:33:
- 37:e2:60:09:02:13:89:a3:ca:0f:bf:17:8e:47:fb:c1:8d:a8:
- fb:9f:20:64:a6:a4:a0:86:da:fa:7f:6a:e1:50:10:41:9b:21:
- e6:8e:9f:29:9c:cc:0b:83:a3:65:47:2a:15:8b:47:6a:48:89:
- e4:2c:97:d7:81:51:bb:bb:e0:db:22:e2:be:bf:53:63:26:77:
- 08:c3:b6:04:c7:9b:9c:03:91:00:63:bd:70:cb:e2:6c:c8:a7:
- 2c:5b:f6:28
------BEGIN CERTIFICATE-----
-MIIDejCCAmKgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3nzNHJLD
-mv++8wM3x2o61KxWUDqxFw1zCe/ZFks43qSCRmGo7fi5oCF+PCb2qMXTNJmcWMbh
-3vYc60mjNGVxKZU6LrRfM90qC1964Ec/vAAVoSQmn8bH1+vj8zcZ1TBI8n3FdxHM
-zBd+kcQg+KbDKADsI1NAew7cFG5XpcpSnys7NOrkrlzttI0lmggAJtDkNNKUNozh
-3+8x+Bhb7YBXRHeUovquXODq4TDjJAPafFtmkMcB8fiNyrzX4yU1KDz29IMTKnPQ
-98JpEbHtQ21xKH5DjfXweOJaMTk4rpIFKeAfBG+doKG0KYCvhxwM5X1tEVljQ69/
-pDL6CtF+iIbNYQIDAQABo4HYMIHVMB0GA1UdDgQWBBRgvZg4zsMBQMqGFMf05NVy
-uu2AMTAfBgNVHSMEGDAWgBSyQSZ67zrJv/5q538EYLA0YgjjkzA3BggrBgEFBQcB
-AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
-BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
-VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wCwYDKgMEBAQBAgMEMA0GCSqG
-SIb3DQEBCwUAA4IBAQBoXHRs/ZMUhp/ZOktnHW4reC+JtLB2rD+q6krqQgRAlgka
-t7cBk/tVDUQwDhaz6Luydxd5kzcXtWLJWxV2kC10PR9+WWFZ4mGBGEZrlEK+vtMe
-NxZoSdue8PEku+AA4FfgJz9Z6aiSMYAqesyxR1uNO1X1WvCaVpAajtKrUeIVyp/L
-qewQ8V1YcoR1Y72nfL9bgGXWl3fiiomK6lsf2lVeezM34mAJAhOJo8oPvxeOR/vB
-jaj7nyBkpqSghtr6f2rhUBBBmyHmjp8pnMwLg6NlRyoVi0dqSInkLJfXgVG7u+Db
-IuK+v1NjJncIw7YEx5ucA5EAY71wy+JsyKcsW/Yo
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Root
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:a8:e9:07:4a:9e:20:9a:c5:14:9a:16:49:17:bf:
- 0b:c1:7d:b6:91:54:cd:60:e6:df:bf:81:e1:bb:24:
- 47:df:ea:c8:27:93:bb:49:b7:b7:e6:48:ff:11:43:
- c1:8d:cb:54:f8:0d:49:05:e7:4b:a9:0d:cb:79:b8:
- 49:26:6b:1c:ad:7d:2c:e5:a3:0a:1b:ad:99:9c:d4:
- c2:d6:2c:de:ae:74:42:b7:06:ca:e0:57:06:e6:46:
- 5a:80:70:6f:f7:0c:76:c5:8f:de:cc:35:85:bf:f5:
- 79:29:63:79:22:fd:c0:48:1e:a0:4f:86:6b:2f:07:
- 72:55:1f:96:dc:81:c7:19:8d:bf:7f:56:21:fc:05:
- 6e:1a:3d:6d:f2:a7:37:6f:8d:c9:f5:5e:79:3a:89:
- 6b:b5:6b:d4:14:eb:c4:de:3d:68:8c:e6:f8:96:e3:
- b3:cb:73:09:6a:d1:8d:46:9e:c6:9f:1d:01:30:69:
- ea:a4:2a:3c:90:fe:40:92:9d:61:81:88:96:67:cb:
- ae:4c:f5:3d:31:37:8b:31:0a:a0:cf:87:80:f7:50:
- eb:93:32:bf:64:13:3e:0a:d8:98:80:4b:b7:b1:a9:
- 87:fe:b8:d3:d2:3b:a2:7d:20:cb:ff:6b:4e:67:88:
- 52:03:4c:a2:2a:81:0d:63:4e:d0:f8:2e:f6:38:c9:
- 9b:03
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- B2:41:26:7A:EF:3A:C9:BF:FE:6A:E7:7F:04:60:B0:34:62:08:E3:93
- X509v3 Authority Key Identifier:
- keyid:B2:41:26:7A:EF:3A:C9:BF:FE:6A:E7:7F:04:60:B0:34:62:08:E3:93
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- 91:be:af:fa:3e:50:a9:b4:7e:d5:c6:a9:91:2f:d3:63:11:bc:
- 07:35:35:31:76:8e:69:e4:39:7d:82:65:be:6b:b0:9e:42:ce:
- 0c:02:5a:0d:73:93:ce:89:c1:c7:27:cb:19:26:a0:77:85:53:
- b5:1e:a8:60:9f:0c:b9:b4:fa:34:9f:4f:3a:0e:d6:ab:d3:a6:
- 47:32:d8:ec:c9:80:90:2e:7c:fa:5f:16:96:f6:ba:fd:13:10:
- 73:ec:3e:b0:3c:f5:7a:e1:8f:e3:32:59:d2:f1:3c:36:8c:92:
- 21:a1:29:21:39:1c:08:b1:f6:85:35:ab:36:97:56:fc:4c:85:
- 11:bc:69:72:05:f6:21:b8:85:bb:1e:cf:69:1a:3c:98:dd:93:
- 58:53:e0:f1:ce:d0:2a:68:d9:b3:b9:26:71:d9:61:01:a8:cd:
- bb:53:48:06:a5:c4:3f:d6:3b:aa:01:4d:01:fc:f2:79:96:a9:
- 13:d3:ba:25:2c:2a:3d:e5:bd:e1:f7:ae:f9:3a:ea:59:77:8c:
- 27:3c:f5:a4:01:f8:08:97:1b:28:1a:81:cb:ce:36:6b:2f:1e:
- 41:05:f6:d6:d9:4d:84:87:16:61:e4:34:4c:06:7e:a8:2b:2b:
- b5:a1:93:de:ca:52:f7:74:d9:ce:f7:f7:2b:0f:5d:f8:b6:9f:
- 93:34:b2:00
------BEGIN TRUSTED_CERTIFICATE-----
-MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKjpB0qeIJrFFJoWSRe/
-C8F9tpFUzWDm37+B4bskR9/qyCeTu0m3t+ZI/xFDwY3LVPgNSQXnS6kNy3m4SSZr
-HK19LOWjChutmZzUwtYs3q50QrcGyuBXBuZGWoBwb/cMdsWP3sw1hb/1eSljeSL9
-wEgeoE+Gay8HclUfltyBxxmNv39WIfwFbho9bfKnN2+NyfVeeTqJa7Vr1BTrxN49
-aIzm+Jbjs8tzCWrRjUaexp8dATBp6qQqPJD+QJKdYYGIlmfLrkz1PTE3izEKoM+H
-gPdQ65Myv2QTPgrYmIBLt7Gph/6409I7on0gy/9rTmeIUgNMoiqBDWNO0Pgu9jjJ
-mwMCAwEAAaOByzCByDAdBgNVHQ4EFgQUskEmeu86yb/+aud/BGCwNGII45MwHwYD
-VR0jBBgwFoAUskEmeu86yb/+aud/BGCwNGII45MwNwYIKwYBBQUHAQEEKzApMCcG
-CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
-IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCRvq/6PlCp
-tH7VxqmRL9NjEbwHNTUxdo5p5Dl9gmW+a7CeQs4MAloNc5POicHHJ8sZJqB3hVO1
-Hqhgnwy5tPo0n086Dtar06ZHMtjsyYCQLnz6XxaW9rr9ExBz7D6wPPV64Y/jMlnS
-8Tw2jJIhoSkhORwIsfaFNas2l1b8TIURvGlyBfYhuIW7Hs9pGjyY3ZNYU+DxztAq
-aNmzuSZx2WEBqM27U0gGpcQ/1juqAU0B/PJ5lqkT07olLCo95b3h9675OupZd4wn
-PPWkAfgIlxsoGoHLzjZrLx5BBfbW2U2EhxZh5DRMBn6oKyu1oZPeylL3dNnO9/cr
-D134tp+TNLIA
------END TRUSTED_CERTIFICATE-----
-
------BEGIN TIME-----
-MTUwMzAyMTIwMDAwWg==
------END TIME-----
-
------BEGIN VERIFY_RESULT-----
-U1VDQ0VTUw==
------END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/intermediate-basic-constraints-ca-false.pem b/chromium/net/data/verify_certificate_chain_unittest/intermediate-basic-constraints-ca-false.pem
new file mode 100644
index 00000000000..0d4171644b7
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/intermediate-basic-constraints-ca-false.pem
@@ -0,0 +1,291 @@
+[Created by: generate-intermediate-basic-constraints-ca-false.py]
+
+Certificate chain with 1 intermediate and a trusted root. The intermediate
+has a basic constraints extension that indicates it is NOT a CA. Verification
+is expected to fail.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b7:1c:6d:3b:54:28:d0:fa:14:25:fe:22:77:55:
+ 16:d3:25:34:af:cd:e7:5a:8a:38:4b:82:99:95:6d:
+ e1:99:f7:f3:1d:53:2d:8e:90:b2:d5:4e:7e:e7:0c:
+ 9d:73:98:5e:3b:ed:bc:4f:fe:c7:38:f7:8a:ce:b7:
+ 08:0f:bd:78:18:9a:ec:f2:21:9e:25:ba:bc:24:3f:
+ 22:73:60:f7:2c:fa:9a:e9:aa:f8:75:65:4e:af:4e:
+ d9:01:f3:27:3e:c8:f5:b5:27:98:bd:a2:f6:34:ad:
+ 70:c8:5e:fb:3f:87:08:dc:d0:a6:30:c1:35:ee:95:
+ 7b:f2:7a:59:03:7e:03:39:fb:51:be:b3:13:54:cc:
+ 15:68:e1:b7:97:40:cf:e4:ff:84:a2:10:75:6d:d5:
+ 29:f8:91:8d:38:0a:92:c6:34:89:89:c2:d4:49:84:
+ 35:94:f9:08:ad:8c:44:10:3e:49:40:21:53:bb:6e:
+ 1b:20:1c:ce:e3:c8:a7:c7:e9:ab:4f:3f:f2:21:47:
+ 3a:d5:0a:59:6f:a9:59:42:ff:c5:7c:6a:c5:fc:79:
+ 29:05:a0:07:47:64:39:d0:bc:a1:86:64:c8:4c:08:
+ ec:f2:03:47:7c:00:ce:02:ff:5a:02:59:d3:ee:2c:
+ db:35:32:e9:24:a2:c2:f8:50:c8:3e:10:b1:dd:0a:
+ 5d:1b
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 03:34:C9:78:9C:53:67:7A:2C:96:D9:3F:63:F2:18:3D:49:A8:44:87
+ X509v3 Authority Key Identifier:
+ keyid:9C:93:40:54:48:97:2B:0C:3B:AF:CE:5C:79:97:26:EC:32:33:4C:FB
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 72:78:37:46:b3:e3:d4:01:73:3a:59:1c:5f:13:27:10:46:dd:
+ ec:b1:9e:7c:6d:d8:a7:ac:b1:62:36:57:2a:44:17:d4:64:22:
+ 18:67:ae:84:0b:6b:53:49:76:15:a3:d3:7e:69:ae:d4:54:5d:
+ 46:11:0a:15:1c:ee:91:ab:da:6a:88:24:b0:ae:21:ee:a2:e6:
+ de:c4:cb:79:93:62:18:7d:4e:ee:d8:83:7d:65:63:f3:9c:08:
+ ca:28:5c:af:51:9f:36:b2:c3:06:3c:ec:cf:35:84:c5:9e:bc:
+ 75:03:be:e5:23:4e:7f:67:7d:86:14:df:21:4d:5e:d3:b7:86:
+ d6:14:cd:84:3a:3d:29:4f:de:e5:db:ac:96:a9:58:cf:02:e4:
+ c4:b1:26:08:34:f5:a4:3f:47:a1:0f:b3:0b:69:29:78:50:ba:
+ a9:eb:4a:44:fc:e7:bf:e9:ce:ba:8b:dc:b9:6a:25:c6:11:32:
+ 24:a0:59:7c:6e:4d:6c:cf:1b:f2:06:0f:5f:d7:4d:35:b1:f9:
+ a2:f7:c4:b0:b4:bb:ab:58:b5:ba:09:39:0d:50:d9:c2:a4:eb:
+ d9:79:23:40:ed:51:97:75:de:f5:14:c0:dc:ea:9f:6a:80:70:
+ ef:4e:b8:52:26:46:fc:70:e8:83:9c:2c:e8:63:b0:7f:81:a3:
+ 4e:91:35:02
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3HG07
+VCjQ+hQl/iJ3VRbTJTSvzedaijhLgpmVbeGZ9/MdUy2OkLLVTn7nDJ1zmF477bxP
+/sc494rOtwgPvXgYmuzyIZ4lurwkPyJzYPcs+prpqvh1ZU6vTtkB8yc+yPW1J5i9
+ovY0rXDIXvs/hwjc0KYwwTXulXvyelkDfgM5+1G+sxNUzBVo4beXQM/k/4SiEHVt
+1Sn4kY04CpLGNImJwtRJhDWU+QitjEQQPklAIVO7bhsgHM7jyKfH6atPP/IhRzrV
+CllvqVlC/8V8asX8eSkFoAdHZDnQvKGGZMhMCOzyA0d8AM4C/1oCWdPuLNs1Mukk
+osL4UMg+ELHdCl0bAgMBAAGjgekwgeYwHQYDVR0OBBYEFAM0yXicU2d6LJbZP2Py
+GD1JqESHMB8GA1UdIwQYMBaAFJyTQFRIlysMO6/OXHmXJuwyM0z7MD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAcng3RrPj1AFzOlkcXxMn
+EEbd7LGefG3Yp6yxYjZXKkQX1GQiGGeuhAtrU0l2FaPTfmmu1FRdRhEKFRzukava
+aogksK4h7qLm3sTLeZNiGH1O7tiDfWVj85wIyihcr1GfNrLDBjzszzWExZ68dQO+
+5SNOf2d9hhTfIU1e07eG1hTNhDo9KU/e5duslqlYzwLkxLEmCDT1pD9HoQ+zC2kp
+eFC6qetKRPznv+nOuovcuWolxhEyJKBZfG5NbM8b8gYPX9dNNbH5ovfEsLS7q1i1
+ugk5DVDZwqTr2XkjQO1Rl3Xe9RTA3OqfaoBw7064UiZG/HDog5ws6GOwf4GjTpE1
+Ag==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c6:22:75:92:c4:7c:6f:77:4d:46:f7:17:84:1b:
+ e2:08:1f:ff:71:7e:4d:6d:a4:e7:0f:58:46:84:61:
+ 22:02:70:4e:b8:45:3a:e2:10:d1:cf:ff:91:7c:12:
+ 8e:7d:19:ab:0a:46:ac:1b:d6:d6:05:b6:99:43:9b:
+ ab:e5:cf:ee:62:e9:94:21:84:72:5b:63:6e:5a:e1:
+ 25:42:c3:b7:ee:31:5f:e0:e7:69:19:01:a2:d5:54:
+ 70:f8:aa:aa:24:5b:3b:4d:2b:cd:2f:e4:2a:a4:be:
+ ba:2f:ab:a2:b6:f8:84:71:f3:23:bc:12:68:26:1e:
+ 49:d0:87:3e:46:46:33:47:70:f2:42:d4:3f:ba:9c:
+ 89:7d:4f:6e:a5:35:cf:d9:46:a8:63:c4:35:4a:e7:
+ 4f:f2:e0:51:90:8e:08:ed:2e:ae:18:ac:5d:16:44:
+ 25:32:fa:1b:3c:14:e9:37:69:9f:72:48:01:a5:1b:
+ f3:e1:e7:75:ec:ca:92:83:48:a4:67:e1:8d:c1:dd:
+ 15:02:e4:4a:82:93:d3:f3:27:9e:66:ce:a8:3a:17:
+ d2:c6:a7:08:31:ba:d2:e8:e7:fa:53:b6:4f:09:d8:
+ 7e:e4:53:b2:f1:03:d9:c4:31:0c:6d:32:a0:9d:08:
+ d3:c4:bb:db:45:11:68:80:ba:f8:52:dc:19:9e:67:
+ 68:99
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 9C:93:40:54:48:97:2B:0C:3B:AF:CE:5C:79:97:26:EC:32:33:4C:FB
+ X509v3 Authority Key Identifier:
+ keyid:6F:25:CD:4D:1F:09:D0:5A:D5:3A:23:08:72:F1:9D:08:8A:1D:CA:34
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ Signature Algorithm: sha256WithRSAEncryption
+ 14:4a:f9:6f:29:a6:a1:1b:2b:d7:3d:5d:14:83:05:1a:46:ac:
+ 73:64:d5:b7:09:87:0f:08:1d:b2:ac:1c:db:79:05:e4:62:fa:
+ 37:7d:78:82:c9:7c:44:f3:01:9a:a6:31:78:ac:af:1e:53:9e:
+ 84:ab:95:f0:2e:48:62:d6:3e:a3:95:35:1e:18:c6:9e:0d:15:
+ 9e:94:0f:bd:8c:1b:f6:de:48:d8:cd:7c:9b:23:4d:bb:d0:f6:
+ df:bb:27:a6:55:82:07:3e:27:2e:80:6e:b3:67:06:67:6d:b6:
+ f8:5f:60:58:ab:d8:9d:f6:4b:6b:a8:9a:be:9e:c3:69:e8:15:
+ 00:61:9f:b2:24:6d:bd:d5:e3:7e:c7:83:66:4e:12:58:b7:c1:
+ c1:0e:de:1a:dc:ae:4d:19:78:b8:6c:48:fb:5b:fc:a2:86:0b:
+ 60:77:d7:cb:d6:e6:c9:13:5f:cf:d6:98:6c:ab:9e:9b:9d:99:
+ 4c:87:91:3e:d1:4a:ad:ef:84:f6:45:cc:da:99:fa:ff:57:df:
+ be:44:70:f9:0c:38:63:c0:31:44:45:05:46:9a:63:db:dd:a0:
+ f5:dc:1b:f8:51:d8:30:e5:47:23:29:d1:79:a5:e6:1e:87:2b:
+ c3:f8:0e:fe:de:13:bb:cd:a5:14:f3:d8:0b:34:73:47:68:07:
+ 8a:ac:e0:65
+-----BEGIN CERTIFICATE-----
+MIIDajCCAlKgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxiJ1ksR8
+b3dNRvcXhBviCB//cX5NbaTnD1hGhGEiAnBOuEU64hDRz/+RfBKOfRmrCkasG9bW
+BbaZQ5ur5c/uYumUIYRyW2NuWuElQsO37jFf4OdpGQGi1VRw+KqqJFs7TSvNL+Qq
+pL66L6uitviEcfMjvBJoJh5J0Ic+RkYzR3DyQtQ/upyJfU9upTXP2UaoY8Q1SudP
+8uBRkI4I7S6uGKxdFkQlMvobPBTpN2mfckgBpRvz4ed17MqSg0ikZ+GNwd0VAuRK
+gpPT8yeeZs6oOhfSxqcIMbrS6Of6U7ZPCdh+5FOy8QPZxDEMbTKgnQjTxLvbRRFo
+gLr4UtwZnmdomQIDAQABo4HIMIHFMB0GA1UdDgQWBBSck0BUSJcrDDuvzlx5lybs
+MjNM+zAfBgNVHSMEGDAWgBRvJc1NHwnQWtU6Iwhy8Z0Iih3KNDA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBABRK
++W8ppqEbK9c9XRSDBRpGrHNk1bcJhw8IHbKsHNt5BeRi+jd9eILJfETzAZqmMXis
+rx5TnoSrlfAuSGLWPqOVNR4Yxp4NFZ6UD72MG/beSNjNfJsjTbvQ9t+7J6ZVggc+
+Jy6AbrNnBmdttvhfYFir2J32S2uomr6ew2noFQBhn7Ikbb3V437Hg2ZOEli3wcEO
+3hrcrk0ZeLhsSPtb/KKGC2B318vW5skTX8/WmGyrnpudmUyHkT7RSq3vhPZFzNqZ
++v9X375EcPkMOGPAMURFBUaaY9vdoPXcG/hR2DDlRyMp0Xml5h6HK8P4Dv7eE7vN
+pRTz2As0c0doB4qs4GU=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c4:3e:31:36:4f:df:d0:36:0e:06:5c:89:2c:c8:
+ 01:c6:18:a4:e7:1f:82:11:af:30:66:28:7c:c3:14:
+ b2:ff:a4:6c:6a:c0:f4:ae:58:82:5f:91:e6:78:19:
+ d7:d2:87:5c:9e:75:3a:af:c0:fd:e8:18:c4:81:b4:
+ 51:be:f7:c3:0d:74:d7:8a:53:01:28:c9:da:93:f4:
+ a6:da:51:6a:d1:23:78:1b:ab:17:46:e6:bb:71:4e:
+ 33:8b:9d:e1:75:7e:56:3b:00:02:74:fe:1f:49:01:
+ 81:0f:59:05:d6:2a:a0:48:db:9f:fc:29:6e:77:6e:
+ e3:78:63:4d:12:9f:f5:54:63:a5:1e:b2:c4:83:62:
+ ac:79:76:bd:80:d9:4c:dd:99:44:91:c3:31:fd:0f:
+ 3a:d8:13:6d:3c:4f:98:5b:50:e0:1a:84:b5:3b:e2:
+ 0f:52:89:7f:b0:de:97:e2:f9:e5:0b:2c:c4:61:9a:
+ f3:4b:15:e3:f2:a3:30:44:b0:d4:a6:1a:dd:60:c0:
+ 85:21:30:ed:b5:1e:6f:9f:50:db:ad:42:a6:3a:04:
+ 7c:3f:ae:94:ed:eb:43:2a:d9:85:c8:1d:72:f4:61:
+ d5:27:7a:a4:62:93:56:37:4b:4e:d5:44:02:f0:29:
+ 1f:70:2c:76:fb:2f:5b:d4:dc:86:09:03:fe:d9:13:
+ 5f:27
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 6F:25:CD:4D:1F:09:D0:5A:D5:3A:23:08:72:F1:9D:08:8A:1D:CA:34
+ X509v3 Authority Key Identifier:
+ keyid:6F:25:CD:4D:1F:09:D0:5A:D5:3A:23:08:72:F1:9D:08:8A:1D:CA:34
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 5e:dc:6f:dc:d9:7f:6f:75:c7:c8:27:62:2f:02:7c:c2:26:35:
+ 82:6c:5e:93:88:34:9b:e2:fc:8a:89:9e:0a:a0:89:aa:08:e4:
+ 1c:59:38:4b:c7:5c:ba:92:d5:ce:1a:b0:30:25:ba:69:c9:52:
+ 6e:29:78:31:d6:49:c5:b3:64:e3:49:28:2d:3c:41:8a:10:c4:
+ 77:f1:a8:77:37:50:52:ec:ed:bb:1a:61:3f:29:ad:3e:1a:56:
+ 06:48:a0:89:17:91:77:67:bc:4d:68:9a:ac:a8:a8:ad:4a:05:
+ 2a:33:18:7a:5e:b9:32:f5:c4:7b:c0:23:90:fb:78:9a:0a:18:
+ f3:9b:46:f1:3c:c5:f0:3c:1b:06:56:39:3b:ba:da:5e:7e:5f:
+ 42:47:bc:fd:a6:bb:64:2d:db:9a:5b:60:61:e6:9d:a6:ac:c9:
+ 24:20:ff:cd:b7:5d:ee:8e:04:92:a1:10:34:26:48:b2:b6:3a:
+ c7:9a:66:2e:f0:64:f0:61:64:ef:28:85:c9:94:46:6b:fb:c5:
+ 0f:b9:f5:ef:51:5a:61:be:27:39:00:4c:00:7f:8a:49:14:7b:
+ 1a:40:e5:e7:fe:d6:d0:a7:df:33:5c:86:1e:e5:4a:64:ff:e8:
+ 8f:1f:9e:3c:d8:a9:a2:d2:0b:c3:53:b7:cf:f6:d1:92:84:be:
+ d9:e6:67:06
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQ+MTZP39A2DgZciSzI
+AcYYpOcfghGvMGYofMMUsv+kbGrA9K5Ygl+R5ngZ19KHXJ51Oq/A/egYxIG0Ub73
+ww1014pTASjJ2pP0ptpRatEjeBurF0bmu3FOM4ud4XV+VjsAAnT+H0kBgQ9ZBdYq
+oEjbn/wpbndu43hjTRKf9VRjpR6yxINirHl2vYDZTN2ZRJHDMf0POtgTbTxPmFtQ
+4BqEtTviD1KJf7Del+L55QssxGGa80sV4/KjMESw1KYa3WDAhSEw7bUeb59Q261C
+pjoEfD+ulO3rQyrZhcgdcvRh1Sd6pGKTVjdLTtVEAvApH3AsdvsvW9TchgkD/tkT
+XycCAwEAAaOByzCByDAdBgNVHQ4EFgQUbyXNTR8J0FrVOiMIcvGdCIodyjQwHwYD
+VR0jBBgwFoAUbyXNTR8J0FrVOiMIcvGdCIodyjQwNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBe3G/c2X9v
+dcfIJ2IvAnzCJjWCbF6TiDSb4vyKiZ4KoImqCOQcWThLx1y6ktXOGrAwJbppyVJu
+KXgx1knFs2TjSSgtPEGKEMR38ah3N1BS7O27GmE/Ka0+GlYGSKCJF5F3Z7xNaJqs
+qKitSgUqMxh6Xrky9cR7wCOQ+3iaChjzm0bxPMXwPBsGVjk7utpefl9CR7z9prtk
+LduaW2Bh5p2mrMkkIP/Nt13ujgSSoRA0JkiytjrHmmYu8GTwYWTvKIXJlEZr+8UP
+ufXvUVphvic5AEwAf4pJFHsaQOXn/tbQp98zXIYe5Upk/+iPH5482Kmi0gvDU7fP
+9tGShL7Z5mcG
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+FAIL
+-----BEGIN VERIFY_RESULT-----
+RkFJTA==
+-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 0
+ [Error] Basic Constraints indicates not a CA
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMAogICAgICBbRXJyb3JdIEJhc2ljIENvbnN0cmFpbnRzIGluZGljYXRlcyBub3QgYSBDQQo=
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/intermediate-basic-constraints-not-critical.pem b/chromium/net/data/verify_certificate_chain_unittest/intermediate-basic-constraints-not-critical.pem
new file mode 100644
index 00000000000..8a1ec44a84f
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/intermediate-basic-constraints-not-critical.pem
@@ -0,0 +1,284 @@
+[Created by: generate-intermediate-basic-constraints-not-critical.py]
+
+Certificate chain with 1 intermediate and a trusted root. The intermediate
+has a basic constraints extension but does not mark it as critical.
+Verification is expected to succeed, since although not critical, the
+basicConstraints indicates CA=true as expected.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:9f:2f:38:1d:84:e6:1c:ed:c4:47:2b:63:0b:41:
+ 73:dd:fe:74:c7:1a:d2:c8:7f:c1:90:ae:bf:6b:82:
+ a1:17:93:80:a1:92:39:52:66:81:93:90:e6:15:d7:
+ d6:bc:a4:03:eb:fc:50:b2:dc:f6:29:f7:a9:32:b6:
+ 23:6c:d4:d0:3e:d9:56:6e:9d:a0:91:10:2c:8a:1e:
+ 93:8d:38:37:ef:3e:7d:7a:de:15:07:c2:6c:62:1c:
+ 76:81:ce:a7:9e:be:44:57:1b:77:77:ed:fa:2f:e1:
+ c5:53:83:65:74:c6:11:3c:f2:4d:84:89:1d:3b:54:
+ 93:5e:38:44:f1:d4:03:ad:03:69:fd:eb:da:02:aa:
+ cf:6f:04:ea:22:0a:3f:a1:68:bc:56:a4:51:aa:93:
+ 8a:f2:22:47:42:04:98:48:68:40:2e:f6:a6:8d:38:
+ 84:ba:1a:56:0c:bc:53:85:77:b4:ba:e2:03:ac:10:
+ 0f:1d:52:64:ad:f5:92:20:38:dc:fa:dd:8b:c6:8d:
+ 96:30:ea:72:e2:aa:ff:5d:c3:fc:dc:1a:43:c6:da:
+ 48:56:f6:4c:d4:8d:00:da:28:5f:01:23:9b:b1:eb:
+ b7:92:b7:35:43:5e:c0:21:96:22:b6:bd:c6:5f:1b:
+ 0b:58:88:44:a5:ee:90:f4:e6:d0:94:41:2c:44:8c:
+ af:e9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 05:31:5F:95:5B:3C:43:02:74:27:C6:2E:06:50:92:FF:5C:54:AE:73
+ X509v3 Authority Key Identifier:
+ keyid:77:27:6B:15:A8:06:86:AD:0D:67:E0:D6:5B:82:3A:F8:6B:00:A3:A7
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 00:ba:cd:3c:7b:0f:eb:b3:b1:5f:5b:0a:83:12:4d:d6:28:7e:
+ ff:d9:65:2c:23:f8:d2:68:cc:25:14:0c:6e:9b:37:bb:72:66:
+ 13:54:ff:b9:2f:f4:c8:9e:77:5b:31:2b:93:e6:94:cf:e9:bd:
+ 43:1a:e8:f6:c3:c5:61:fa:ff:a7:72:09:ba:2b:08:02:e4:a5:
+ 62:24:b1:b1:3b:0a:c0:bb:72:19:af:73:2d:9a:66:8e:f7:0f:
+ 30:9f:49:0f:aa:83:87:ed:45:9e:75:3a:50:32:d6:c4:cf:20:
+ a0:31:73:16:98:69:e9:d7:16:5b:6f:6f:0a:d8:96:82:a3:d6:
+ a8:a4:84:d7:1a:50:22:bd:14:d7:61:d9:43:a9:58:cf:46:e8:
+ 64:e9:1c:a9:d6:d3:49:45:1e:53:16:71:05:a7:0b:ae:d7:c0:
+ 43:8c:24:02:07:6f:99:ed:4b:f6:89:a8:31:f5:ba:56:e3:db:
+ 00:10:7e:0d:e0:46:96:b2:27:be:60:29:e8:91:e9:55:43:b1:
+ e6:74:e9:17:4e:bd:db:32:ec:61:7e:b0:d1:17:27:90:29:d9:
+ 2e:53:6a:8f:de:77:ae:f4:ff:f4:96:84:e6:8d:37:43:63:17:
+ 87:6a:8c:55:bd:ea:fd:2c:b2:83:10:3c:d7:f0:bd:21:45:ad:
+ ba:36:6d:43
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfLzgd
+hOYc7cRHK2MLQXPd/nTHGtLIf8GQrr9rgqEXk4ChkjlSZoGTkOYV19a8pAPr/FCy
+3PYp96kytiNs1NA+2VZunaCRECyKHpONODfvPn163hUHwmxiHHaBzqeevkRXG3d3
+7fov4cVTg2V0xhE88k2EiR07VJNeOETx1AOtA2n969oCqs9vBOoiCj+haLxWpFGq
+k4ryIkdCBJhIaEAu9qaNOIS6GlYMvFOFd7S64gOsEA8dUmSt9ZIgONz63YvGjZYw
+6nLiqv9dw/zcGkPG2khW9kzUjQDaKF8BI5ux67eStzVDXsAhliK2vcZfGwtYiESl
+7pD05tCUQSxEjK/pAgMBAAGjgekwgeYwHQYDVR0OBBYEFAUxX5VbPEMCdCfGLgZQ
+kv9cVK5zMB8GA1UdIwQYMBaAFHcnaxWoBoatDWfg1luCOvhrAKOnMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAALrNPHsP67OxX1sKgxJN
+1ih+/9llLCP40mjMJRQMbps3u3JmE1T/uS/0yJ53WzErk+aUz+m9Qxro9sPFYfr/
+p3IJuisIAuSlYiSxsTsKwLtyGa9zLZpmjvcPMJ9JD6qDh+1FnnU6UDLWxM8goDFz
+Fphp6dcWW29vCtiWgqPWqKSE1xpQIr0U12HZQ6lYz0boZOkcqdbTSUUeUxZxBacL
+rtfAQ4wkAgdvme1L9omoMfW6VuPbABB+DeBGlrInvmAp6JHpVUOx5nTpF0692zLs
+YX6w0RcnkCnZLlNqj953rvT/9JaE5o03Q2MXh2qMVb3q/SyygxA81/C9IUWtujZt
+Qw==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:94:4c:ba:e4:24:50:f0:02:98:a7:42:66:d3:d6:
+ 53:4d:ad:3f:76:fa:4f:72:61:fd:79:cc:43:e2:d6:
+ 2f:d9:99:84:0b:da:34:6f:65:ca:78:2b:a9:22:98:
+ 04:ba:93:89:e9:8c:d0:71:62:cd:a4:3a:35:e2:8c:
+ 2d:8a:48:36:2b:d1:99:52:27:c7:44:34:30:2c:87:
+ a7:47:e3:df:74:a3:6c:c6:3c:d2:ba:5c:3c:04:79:
+ 1f:11:36:58:7a:86:65:60:cc:a1:4c:ba:f9:72:7e:
+ 80:d3:1b:12:18:8a:44:b3:f3:fa:20:f8:8c:3d:63:
+ e3:96:0a:6b:0a:32:a1:f1:75:7c:6b:76:5f:1b:ef:
+ bd:64:c3:34:fd:2e:27:89:dd:ef:e5:74:08:08:a4:
+ 96:92:7b:f3:4b:f5:ee:eb:91:0b:bb:ca:53:e8:ed:
+ 48:a8:bb:7c:f8:9f:30:f7:15:05:32:7d:73:62:37:
+ 4f:f7:a1:d4:de:45:e2:f7:49:86:b9:c9:f8:84:cc:
+ 67:b2:f0:34:48:e6:54:e4:5d:1f:fb:03:fc:d8:15:
+ a1:17:0e:53:0d:c8:c9:a6:99:bf:f8:93:df:af:35:
+ e3:10:91:91:24:f3:eb:88:0b:d8:4f:16:36:a3:28:
+ ad:21:bd:22:bf:46:59:0a:ea:f0:fb:fc:01:c3:ba:
+ 42:e9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 77:27:6B:15:A8:06:86:AD:0D:67:E0:D6:5B:82:3A:F8:6B:00:A3:A7
+ X509v3 Authority Key Identifier:
+ keyid:6C:17:23:18:CA:A6:A4:28:C6:08:4C:AA:9A:3F:18:FB:7B:67:B2:36
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints:
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ af:80:f1:f7:93:98:cd:84:13:e3:eb:ab:2d:ff:91:4c:72:5d:
+ d9:a9:b7:96:e8:bc:e9:f3:31:a0:46:7c:0d:49:a3:1f:5a:6a:
+ aa:82:9a:c2:1f:37:7a:9a:37:1a:96:fb:8e:fa:28:e1:eb:b8:
+ a3:d0:66:2d:9e:6e:ff:8e:c3:0a:17:23:ae:60:d5:9b:d2:fb:
+ 23:2b:a9:b0:22:cb:e6:85:29:11:d3:b5:71:3e:30:9a:9c:60:
+ 24:c5:a8:42:66:4f:5c:10:8b:fa:61:ad:d7:14:2b:51:0e:53:
+ 24:1a:c7:5f:d9:12:97:6a:8c:da:d5:f9:35:41:4c:d4:0e:a8:
+ 98:c6:e8:61:db:7b:95:d5:ca:26:ff:60:01:e2:c6:4e:f7:67:
+ ee:36:1f:2b:71:82:46:f5:11:44:ce:7b:ac:85:06:f1:09:35:
+ 07:62:08:36:ad:b6:5b:c6:70:a0:bb:f0:5b:2e:47:09:a2:69:
+ 79:a6:f1:77:fd:3c:b9:57:f4:c7:e6:f8:80:18:ba:d0:a0:c1:
+ b1:6f:b9:c8:3b:a2:c1:83:5c:e7:3a:05:19:36:c5:ae:54:dc:
+ df:1d:ad:18:e0:52:dd:71:ba:53:3e:2c:7d:eb:09:3a:cb:25:
+ 10:b3:52:50:7f:42:2b:a8:2c:a7:cc:02:8e:17:99:af:7e:d2:
+ 75:f4:15:f1
+-----BEGIN CERTIFICATE-----
+MIIDajCCAlKgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlEy65CRQ
+8AKYp0Jm09ZTTa0/dvpPcmH9ecxD4tYv2ZmEC9o0b2XKeCupIpgEupOJ6YzQcWLN
+pDo14owtikg2K9GZUifHRDQwLIenR+PfdKNsxjzSulw8BHkfETZYeoZlYMyhTLr5
+cn6A0xsSGIpEs/P6IPiMPWPjlgprCjKh8XV8a3ZfG++9ZMM0/S4nid3v5XQICKSW
+knvzS/Xu65ELu8pT6O1IqLt8+J8w9xUFMn1zYjdP96HU3kXi90mGucn4hMxnsvA0
+SOZU5F0f+wP82BWhFw5TDcjJppm/+JPfrzXjEJGRJPPriAvYTxY2oyitIb0iv0ZZ
+Curw+/wBw7pC6QIDAQABo4HIMIHFMB0GA1UdDgQWBBR3J2sVqAaGrQ1n4NZbgjr4
+awCjpzAfBgNVHSMEGDAWgBRsFyMYyqakKMYITKqaPxj7e2eyNjA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAK+A
+8feTmM2EE+Prqy3/kUxyXdmpt5bovOnzMaBGfA1Jox9aaqqCmsIfN3qaNxqW+476
+KOHruKPQZi2ebv+OwwoXI65g1ZvS+yMrqbAiy+aFKRHTtXE+MJqcYCTFqEJmT1wQ
+i/phrdcUK1EOUyQax1/ZEpdqjNrV+TVBTNQOqJjG6GHbe5XVyib/YAHixk73Z+42
+Hytxgkb1EUTOe6yFBvEJNQdiCDattlvGcKC78FsuRwmiaXmm8Xf9PLlX9Mfm+IAY
+utCgwbFvucg7osGDXOc6BRk2xa5U3N8drRjgUt1xulM+LH3rCTrLJRCzUlB/Qiuo
+LKfMAo4Xma9+0nX0FfE=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:e2:4c:a9:08:30:3f:0e:6a:ec:ec:80:8e:07:cb:
+ fa:9b:01:b9:8a:37:f0:b1:f2:c2:43:79:90:7e:70:
+ 76:ac:5c:41:60:55:66:fb:4f:e6:79:c8:18:01:7f:
+ d5:bd:9a:d5:58:5a:00:bf:81:86:37:1e:68:1a:92:
+ da:dd:e8:20:1a:47:43:78:bb:7e:5c:82:c6:59:1b:
+ 37:c9:99:b2:ac:bb:d2:c0:cf:58:5a:25:13:a6:6b:
+ 9a:79:be:dc:f6:6f:6c:80:5d:58:c2:b5:67:ae:09:
+ 1b:ba:2a:f3:2a:00:d2:43:b6:59:df:38:7c:ef:c1:
+ be:1b:a1:e0:7d:9b:20:27:04:67:94:45:b3:2d:f6:
+ 77:91:3c:c4:94:5f:78:7a:79:2c:4b:21:23:8b:f4:
+ d3:60:73:10:59:c7:a1:84:3f:5a:4e:82:43:90:68:
+ 77:2a:f6:b1:d2:d4:cc:cd:76:36:13:95:c5:a7:f4:
+ 46:d8:b7:ee:ef:59:07:2c:69:4d:9c:22:e4:2d:f1:
+ a9:2c:50:35:50:c2:91:ea:37:d9:6c:b6:f2:ff:cd:
+ 7e:00:ae:51:e3:b4:10:5f:87:e3:92:fe:9e:62:a5:
+ 34:fe:15:c4:19:20:3a:68:fd:3c:be:ae:aa:a3:52:
+ 48:d3:05:95:99:f8:38:18:c5:44:d6:71:c4:bf:34:
+ e5:c7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 6C:17:23:18:CA:A6:A4:28:C6:08:4C:AA:9A:3F:18:FB:7B:67:B2:36
+ X509v3 Authority Key Identifier:
+ keyid:6C:17:23:18:CA:A6:A4:28:C6:08:4C:AA:9A:3F:18:FB:7B:67:B2:36
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ d2:00:6a:7a:21:40:79:ad:84:23:e8:62:29:b5:47:0a:7a:91:
+ 08:3d:f3:af:0a:14:e9:93:08:7a:81:bf:44:6f:e9:59:5b:d6:
+ 8f:e1:bd:cd:9f:46:94:2e:7e:79:df:53:9e:85:e3:86:e0:15:
+ 65:e4:fd:b9:10:f7:19:6c:f1:ba:39:3b:2e:49:97:18:7d:95:
+ a9:e5:14:49:65:44:31:39:5b:75:c7:09:75:1f:b3:5a:5b:fe:
+ 09:1a:4a:af:ec:6b:58:5a:7b:ef:44:58:37:ab:23:72:bd:97:
+ 7b:02:63:65:cf:3d:f6:13:62:44:49:04:dc:85:fc:6f:31:80:
+ c7:e0:1e:5b:77:90:29:cb:06:67:4e:99:41:b1:66:d7:4b:a3:
+ fa:85:5c:bc:2e:c5:fa:a0:a1:8d:07:ba:52:31:cf:5e:2a:98:
+ f1:ba:dc:56:4b:b3:cc:11:b2:d1:2d:0a:eb:75:a8:fe:f6:02:
+ d8:9b:0f:5b:7e:11:50:b1:51:b9:31:11:c5:4b:fa:bf:34:4d:
+ 46:e9:27:39:61:ca:09:41:b2:67:fc:54:8a:38:0b:50:7d:f0:
+ e4:7a:a4:30:08:12:86:b3:fc:d2:43:0c:b5:50:4b:45:ee:cf:
+ 90:5b:3e:39:47:11:b6:6b:a6:24:fe:02:17:07:7c:06:15:23:
+ 0f:d8:0e:7b
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOJMqQgwPw5q7OyAjgfL
++psBuYo38LHywkN5kH5wdqxcQWBVZvtP5nnIGAF/1b2a1VhaAL+BhjceaBqS2t3o
+IBpHQ3i7flyCxlkbN8mZsqy70sDPWFolE6Zrmnm+3PZvbIBdWMK1Z64JG7oq8yoA
+0kO2Wd84fO/Bvhuh4H2bICcEZ5RFsy32d5E8xJRfeHp5LEshI4v002BzEFnHoYQ/
+Wk6CQ5Bodyr2sdLUzM12NhOVxaf0Rti37u9ZByxpTZwi5C3xqSxQNVDCkeo32Wy2
+8v/NfgCuUeO0EF+H45L+nmKlNP4VxBkgOmj9PL6uqqNSSNMFlZn4OBjFRNZxxL80
+5ccCAwEAAaOByzCByDAdBgNVHQ4EFgQUbBcjGMqmpCjGCEyqmj8Y+3tnsjYwHwYD
+VR0jBBgwFoAUbBcjGMqmpCjGCEyqmj8Y+3tnsjYwNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDSAGp6IUB5
+rYQj6GIptUcKepEIPfOvChTpkwh6gb9Eb+lZW9aP4b3Nn0aULn5531OeheOG4BVl
+5P25EPcZbPG6OTsuSZcYfZWp5RRJZUQxOVt1xwl1H7NaW/4JGkqv7GtYWnvvRFg3
+qyNyvZd7AmNlzz32E2JESQTchfxvMYDH4B5bd5ApywZnTplBsWbXS6P6hVy8LsX6
+oKGNB7pSMc9eKpjxutxWS7PMEbLRLQrrdaj+9gLYmw9bfhFQsVG5MRHFS/q/NE1G
+6Sc5YcoJQbJn/FSKOAtQffDkeqQwCBKGs/zSQwy1UEtF7s+QWz45RxG2a6Yk/gIX
+B3wGFSMP2A57
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/intermediate-lacks-basic-constraints.pem b/chromium/net/data/verify_certificate_chain_unittest/intermediate-lacks-basic-constraints.pem
new file mode 100644
index 00000000000..ceb0487cb28
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/intermediate-lacks-basic-constraints.pem
@@ -0,0 +1,288 @@
+[Created by: generate-intermediate-lacks-basic-constraints.py]
+
+Certificate chain with 1 intermediate and a trusted root. The intermediate
+lacks the basic constraints extension, and hence is expected to fail validation
+(RFC 5280 requires v3 signing certificates have a BasicConstaints).
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ac:3c:48:cb:8e:9b:00:37:e3:06:36:23:5e:3c:
+ 24:0b:d2:57:0e:52:8f:53:d0:48:ca:38:67:91:a7:
+ 10:d3:35:2d:67:f4:ad:2c:9e:c1:ee:f5:6b:62:23:
+ 34:03:32:76:29:96:fd:db:cc:a4:9a:d8:b6:97:c4:
+ a9:73:c1:a1:57:2f:cd:80:d1:d9:db:39:82:11:bb:
+ 95:3e:1b:b3:1e:ac:e7:c0:67:f3:1e:cb:4f:d4:a6:
+ c7:01:32:c5:45:ca:53:ff:cf:46:e1:b3:4f:55:01:
+ ef:76:44:92:55:55:d8:a4:db:5c:80:8f:48:51:86:
+ 6c:d9:b6:b7:5c:74:56:06:00:38:3f:d9:ee:c3:ae:
+ 78:a0:57:ff:fa:41:02:14:63:00:bb:1f:98:9a:f5:
+ 39:50:51:50:78:03:5d:13:a2:fd:a3:08:b0:ff:69:
+ ee:60:c8:af:1c:1e:8a:13:4b:0e:b9:48:29:92:f2:
+ 95:0a:d9:85:2f:ff:17:ab:c7:6f:e0:32:d1:16:9e:
+ 66:ae:81:87:b8:7e:70:ac:73:8c:67:de:dd:1a:e0:
+ 0e:0e:bb:ab:bc:f5:ef:38:d9:37:49:71:d1:7c:e6:
+ 64:f7:00:10:e4:83:ed:1e:58:05:44:89:f2:a9:a2:
+ 1d:57:5c:b5:db:bc:55:39:35:d7:f3:a5:b8:28:d1:
+ 45:5d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 9E:25:C3:B0:61:AE:69:26:DE:05:F4:15:3C:58:B0:7C:6D:91:5C:5B
+ X509v3 Authority Key Identifier:
+ keyid:E5:AE:8F:CC:87:F7:B5:85:86:1E:4B:A6:CF:FC:B9:CA:10:C8:79:90
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ c5:3c:97:21:6a:dc:f8:0c:23:76:c2:4e:33:63:f4:7e:d1:61:
+ bd:f8:cf:6d:b5:ef:d6:f1:96:a0:84:07:42:ab:e2:34:90:3a:
+ 95:2a:db:f6:19:28:bd:19:22:65:20:b0:25:b0:f0:ca:d0:d3:
+ 44:41:fe:03:f2:9f:0c:df:02:dc:64:c6:47:13:1e:26:dd:6a:
+ 5d:52:8a:fe:d3:0a:9a:d1:8c:a5:93:ec:1a:d4:d5:ad:ba:cd:
+ 6b:c2:99:6b:04:b7:06:98:a8:53:dc:d9:97:97:da:ac:29:bb:
+ 09:4a:25:ca:08:83:eb:ed:1f:a7:ae:28:fc:51:09:a9:e4:95:
+ f2:66:97:f2:97:48:9e:01:44:40:5b:4a:91:a5:ed:f9:86:6b:
+ fb:e2:47:c8:47:aa:ad:8d:aa:79:30:fb:4f:f1:a7:7c:c3:23:
+ b3:23:4d:15:a3:04:67:ff:26:b1:50:c0:5a:13:f4:8a:61:da:
+ 98:a2:35:0e:ec:4f:2b:e7:e0:dc:29:0a:07:20:e4:22:97:b1:
+ da:0d:73:6f:32:03:f1:cd:4b:a2:7b:9b:c3:62:a8:dd:55:02:
+ 57:6b:2f:a4:d6:46:20:bc:bd:f7:52:e7:44:8e:3d:2c:73:05:
+ 55:ac:35:8b:af:39:32:a1:07:da:fd:bb:8c:bb:35:e0:e6:bb:
+ 0c:49:1a:e4
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsPEjL
+jpsAN+MGNiNePCQL0lcOUo9T0EjKOGeRpxDTNS1n9K0snsHu9WtiIzQDMnYplv3b
+zKSa2LaXxKlzwaFXL82A0dnbOYIRu5U+G7MerOfAZ/Mey0/UpscBMsVFylP/z0bh
+s09VAe92RJJVVdik21yAj0hRhmzZtrdcdFYGADg/2e7DrnigV//6QQIUYwC7H5ia
+9TlQUVB4A10Tov2jCLD/ae5gyK8cHooTSw65SCmS8pUK2YUv/xerx2/gMtEWnmau
+gYe4fnCsc4xn3t0a4A4Ou6u89e842TdJcdF85mT3ABDkg+0eWAVEifKpoh1XXLXb
+vFU5Ndfzpbgo0UVdAgMBAAGjgekwgeYwHQYDVR0OBBYEFJ4lw7Bhrmkm3gX0FTxY
+sHxtkVxbMB8GA1UdIwQYMBaAFOWuj8yH97WFhh5Lps/8ucoQyHmQMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAxTyXIWrc+AwjdsJOM2P0
+ftFhvfjPbbXv1vGWoIQHQqviNJA6lSrb9hkovRkiZSCwJbDwytDTREH+A/KfDN8C
+3GTGRxMeJt1qXVKK/tMKmtGMpZPsGtTVrbrNa8KZawS3BpioU9zZl5farCm7CUol
+ygiD6+0fp64o/FEJqeSV8maX8pdIngFEQFtKkaXt+YZr++JHyEeqrY2qeTD7T/Gn
+fMMjsyNNFaMEZ/8msVDAWhP0imHamKI1DuxPK+fg3CkKByDkIpex2g1zbzID8c1L
+onubw2Ko3VUCV2svpNZGILy991LnRI49LHMFVaw1i685MqEH2v27jLs14Oa7DEka
+5A==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c5:bf:ce:e4:8e:d2:b9:92:d9:78:eb:36:78:b0:
+ d4:2b:a9:22:cd:83:57:58:a2:0f:5b:e5:c8:e4:f4:
+ d6:41:2c:1f:5a:08:6b:12:7b:f6:8f:39:44:0f:f4:
+ d2:3e:56:cd:63:87:13:b1:88:1a:da:f1:13:2f:4a:
+ d0:76:78:61:6f:71:08:e0:0c:a2:9a:6a:6b:c7:8c:
+ 81:6f:e1:ea:22:09:83:fd:09:53:78:f0:1d:4e:f7:
+ b3:17:17:7e:fc:dc:a5:21:83:7f:46:8c:81:af:07:
+ 68:91:14:54:43:bf:d2:85:fa:58:91:61:cc:87:bc:
+ 8d:b3:97:c1:a5:42:de:73:49:29:c9:0c:48:92:15:
+ d9:0e:6b:3d:4a:4c:50:c6:8b:a5:69:6c:b2:2f:02:
+ 9e:0a:4f:27:1a:d0:1c:0e:b8:d9:fc:a7:62:92:69:
+ 0c:40:ec:49:3b:59:a5:38:fc:8e:cb:2f:91:9f:09:
+ 76:2c:b8:d4:25:7e:83:71:56:89:29:2c:a3:d8:bf:
+ 95:70:99:f5:cb:20:df:fa:fd:b8:89:e6:42:82:a9:
+ 01:d8:e0:42:f2:d2:c3:78:26:cc:fb:05:30:90:a0:
+ 83:bd:ce:b3:6d:bb:01:ae:84:aa:71:4f:d9:37:38:
+ 7e:07:35:6f:ed:88:c7:52:17:38:ac:c6:44:b5:fe:
+ 4a:b3
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ E5:AE:8F:CC:87:F7:B5:85:86:1E:4B:A6:CF:FC:B9:CA:10:C8:79:90
+ X509v3 Authority Key Identifier:
+ keyid:0F:59:3C:0D:B8:B1:5B:C5:96:9D:B4:E8:4F:CF:4B:A6:B3:AD:33:E7
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ 12:11:99:0b:59:f6:cd:61:bf:99:bc:25:83:b2:e7:4b:42:ec:
+ ee:1d:03:3b:cf:5d:76:95:19:2c:d1:41:d0:f6:5c:08:9d:6f:
+ 66:50:07:ea:07:fa:88:01:96:05:39:8d:6a:e0:34:27:1e:a2:
+ 80:c2:9b:91:ba:17:35:49:ef:8c:42:9d:59:ac:42:3f:52:fa:
+ ef:5f:51:aa:3a:dc:b6:ee:d6:8c:20:89:de:36:7d:a2:e2:ff:
+ eb:13:9d:dc:99:d1:62:33:c5:82:19:12:18:d4:94:5b:5f:c4:
+ f7:74:55:f0:be:fa:0e:4d:7a:01:7e:53:b3:2d:4d:09:b6:7b:
+ 8e:0a:7c:3e:b9:39:a1:ee:b6:3d:3f:e8:4a:b0:1d:e4:ee:7b:
+ 96:75:19:b5:71:6a:ae:e0:af:14:59:9f:fc:2b:13:dd:70:c9:
+ da:dd:a9:3c:14:3e:f1:69:3b:ce:42:b4:c5:3f:12:f8:37:eb:
+ bf:0c:9d:48:a4:6e:4c:9f:e7:3c:4f:a5:91:32:8b:7f:2e:5f:
+ e7:bf:bc:f4:a0:5f:43:f7:3a:1f:78:a3:0e:8e:c0:46:16:9e:
+ 58:6a:0f:7e:e0:69:af:94:ec:bc:3a:7f:8b:44:ef:19:f8:14:
+ 16:a4:1d:bd:49:c6:96:da:ba:11:a8:bc:36:11:c7:ad:ab:e0:
+ a5:e2:05:77
+-----BEGIN CERTIFICATE-----
+MIIDXDCCAkSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxb/O5I7S
+uZLZeOs2eLDUK6kizYNXWKIPW+XI5PTWQSwfWghrEnv2jzlED/TSPlbNY4cTsYga
+2vETL0rQdnhhb3EI4Ayimmprx4yBb+HqIgmD/QlTePAdTvezFxd+/NylIYN/RoyB
+rwdokRRUQ7/ShfpYkWHMh7yNs5fBpULec0kpyQxIkhXZDms9SkxQxoulaWyyLwKe
+Ck8nGtAcDrjZ/KdikmkMQOxJO1mlOPyOyy+Rnwl2LLjUJX6DcVaJKSyj2L+VcJn1
+yyDf+v24ieZCgqkB2OBC8tLDeCbM+wUwkKCDvc6zbbsBroSqcU/ZNzh+BzVv7YjH
+Uhc4rMZEtf5KswIDAQABo4G6MIG3MB0GA1UdDgQWBBTlro/Mh/e1hYYeS6bP/LnK
+EMh5kDAfBgNVHSMEGDAWgBQPWTwNuLFbxZadtOhPz0ums60z5zA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQASEZkLWfbNYb+ZvCWDsudL
+QuzuHQM7z112lRks0UHQ9lwInW9mUAfqB/qIAZYFOY1q4DQnHqKAwpuRuhc1Se+M
+Qp1ZrEI/UvrvX1GqOty27taMIIneNn2i4v/rE53cmdFiM8WCGRIY1JRbX8T3dFXw
+vvoOTXoBflOzLU0JtnuOCnw+uTmh7rY9P+hKsB3k7nuWdRm1cWqu4K8UWZ/8KxPd
+cMna3ak8FD7xaTvOQrTFPxL4N+u/DJ1IpG5Mn+c8T6WRMot/Ll/nv7z0oF9D9zof
+eKMOjsBGFp5Yag9+4GmvlOy8On+LRO8Z+BQWpB29ScaW2roRqLw2Ecetq+Cl4gV3
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c3:da:da:10:95:78:5c:73:c8:43:66:41:23:8e:
+ 3e:3f:a1:00:57:de:60:d9:2a:84:57:85:08:c6:60:
+ 79:65:2d:51:c9:93:c1:e7:fa:5b:1a:eb:6f:79:44:
+ d5:71:f6:bd:f4:8c:86:0b:d9:e3:49:dd:a6:f3:5d:
+ 48:8a:25:4a:2a:20:80:c1:83:da:b8:c5:e0:20:de:
+ 40:67:bc:22:38:51:72:df:e3:b7:82:aa:47:ed:c9:
+ 74:a0:82:97:71:35:a8:2f:73:01:86:56:43:e8:88:
+ 42:f9:cc:9b:69:71:09:45:8c:39:82:14:db:2e:08:
+ 17:85:96:c5:69:46:73:55:9b:d8:12:4b:5f:32:70:
+ cc:52:4e:7e:77:94:78:0e:f4:dd:40:ff:d7:3b:cc:
+ f7:df:a9:a7:a1:a3:a3:4e:25:c8:e4:68:1c:e3:90:
+ c2:c5:bb:66:3a:c1:8b:e3:1b:df:b9:8c:0c:9a:3a:
+ 6a:a9:8e:8d:b3:54:49:14:af:28:51:29:b2:5b:7b:
+ 68:34:4c:f3:bb:a5:5d:51:0b:99:6b:b1:fe:b3:16:
+ d1:ef:2f:18:ee:8a:f8:05:9b:df:0d:92:3a:e0:62:
+ 7b:1d:bc:fb:60:45:ce:f9:e0:46:f6:16:39:08:a7:
+ 68:b5:da:e5:9f:7c:db:07:15:dc:47:e6:5d:a3:8c:
+ 06:7b
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 0F:59:3C:0D:B8:B1:5B:C5:96:9D:B4:E8:4F:CF:4B:A6:B3:AD:33:E7
+ X509v3 Authority Key Identifier:
+ keyid:0F:59:3C:0D:B8:B1:5B:C5:96:9D:B4:E8:4F:CF:4B:A6:B3:AD:33:E7
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 3e:f9:8e:c2:1a:d7:ea:b1:71:03:6d:6d:a9:de:e9:45:1d:ab:
+ a3:26:4c:95:4b:15:ad:9d:be:94:aa:20:57:83:b2:32:96:06:
+ c1:37:9a:6a:18:41:ad:13:3b:52:23:a1:0a:1f:fc:8c:fa:3b:
+ 88:43:d1:5e:1e:59:80:06:a5:0a:5e:95:66:3d:3d:cb:4a:b4:
+ 38:77:a6:fa:04:29:e8:c1:b8:b5:f7:49:07:ae:53:dd:62:64:
+ 3c:70:4c:64:b5:54:84:4d:04:3f:6d:86:80:9d:e2:2b:a4:88:
+ 1c:38:74:fc:83:c3:60:c8:86:64:f5:d7:29:f7:e4:8e:02:a9:
+ 47:a6:e1:46:0f:c4:b5:22:59:f1:a7:1b:ae:86:7c:70:32:d4:
+ 8c:19:7f:a7:6d:82:0b:f3:42:37:02:b5:3d:f3:41:d5:7d:67:
+ 97:80:78:9a:e2:06:54:18:bc:b0:7f:5d:77:15:bb:89:cb:4d:
+ 29:0c:02:ab:b3:b7:40:44:3a:2c:4a:2e:54:43:7f:ff:b0:5f:
+ da:c5:5f:38:0e:ce:4e:18:ed:f3:f9:99:f0:7c:01:69:ca:0e:
+ 15:85:1e:ff:b7:2d:04:6c:3b:5b:f9:7f:70:bc:0c:ac:16:b7:
+ d1:b4:f1:74:84:ad:73:e7:9f:c7:c9:ea:93:d9:f1:c6:a7:59:
+ bf:92:4e:ec
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMPa2hCVeFxzyENmQSOO
+Pj+hAFfeYNkqhFeFCMZgeWUtUcmTwef6Wxrrb3lE1XH2vfSMhgvZ40ndpvNdSIol
+SioggMGD2rjF4CDeQGe8IjhRct/jt4KqR+3JdKCCl3E1qC9zAYZWQ+iIQvnMm2lx
+CUWMOYIU2y4IF4WWxWlGc1Wb2BJLXzJwzFJOfneUeA703UD/1zvM99+pp6Gjo04l
+yORoHOOQwsW7ZjrBi+Mb37mMDJo6aqmOjbNUSRSvKFEpslt7aDRM87ulXVELmWux
+/rMW0e8vGO6K+AWb3w2SOuBiex28+2BFzvngRvYWOQinaLXa5Z982wcV3EfmXaOM
+BnsCAwEAAaOByzCByDAdBgNVHQ4EFgQUD1k8DbixW8WWnbToT89LprOtM+cwHwYD
+VR0jBBgwFoAUD1k8DbixW8WWnbToT89LprOtM+cwNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA++Y7CGtfq
+sXEDbW2p3ulFHaujJkyVSxWtnb6UqiBXg7IylgbBN5pqGEGtEztSI6EKH/yM+juI
+Q9FeHlmABqUKXpVmPT3LSrQ4d6b6BCnowbi190kHrlPdYmQ8cExktVSETQQ/bYaA
+neIrpIgcOHT8g8NgyIZk9dcp9+SOAqlHpuFGD8S1IlnxpxuuhnxwMtSMGX+nbYIL
+80I3ArU980HVfWeXgHia4gZUGLywf113FbuJy00pDAKrs7dARDosSi5UQ3//sF/a
+xV84Ds5OGO3z+ZnwfAFpyg4VhR7/ty0EbDtb+X9wvAysFrfRtPF0hK1z55/HyeqT
+2fHGp1m/kk7s
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+FAIL
+-----BEGIN VERIFY_RESULT-----
+RkFJTA==
+-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 0
+ [Error] Does not have Basic Constraints
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMAogICAgICBbRXJyb3JdIERvZXMgbm90IGhhdmUgQmFzaWMgQ29uc3RyYWludHMK
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/intermediate-lacks-signing-key-usage.pem b/chromium/net/data/verify_certificate_chain_unittest/intermediate-lacks-signing-key-usage.pem
new file mode 100644
index 00000000000..eea8741f725
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/intermediate-lacks-signing-key-usage.pem
@@ -0,0 +1,291 @@
+[Created by: generate-intermediate-lacks-signing-key-usage.py]
+
+Certificate chain with 1 intermediate and a trusted root. The intermediate
+contains a keyUsage extension, HOWEVER it does not contain the keyCertSign bit.
+Hence validation is expected to fail.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:a3:21:17:35:c0:77:f1:a3:51:77:11:45:3e:92:
+ 5f:97:65:eb:99:cc:26:e2:8c:f8:4a:d8:3d:71:17:
+ a2:eb:6a:cf:2f:07:a8:fa:27:c1:f8:c5:50:22:42:
+ a2:6f:92:4b:67:c3:0c:a7:ec:35:87:05:ac:eb:e3:
+ 27:cd:62:3d:c4:2e:80:f6:2a:af:31:05:c7:1b:0f:
+ 3b:71:6d:90:77:0d:b4:48:e7:26:2e:4a:44:af:bb:
+ 76:e0:62:ec:e6:61:cc:5b:61:ea:03:ce:4d:46:d0:
+ 96:e2:d5:d9:67:6f:0c:f2:06:e3:9a:14:04:68:82:
+ 88:d6:8b:c1:7f:fb:81:8c:e6:dc:88:20:f7:53:ef:
+ d5:56:5b:5e:00:b3:5b:e8:ce:d0:d2:6a:ed:b8:4a:
+ f2:4b:56:fb:63:75:d4:6b:a3:8a:d4:3f:e6:9e:29:
+ 1b:a7:23:61:ba:f0:d6:19:fb:8c:ad:40:2f:7c:14:
+ 36:0f:4b:f1:6e:f0:b8:6e:7d:cc:82:11:63:48:15:
+ 2f:34:00:99:cd:be:b4:1a:be:d8:73:38:00:ac:c1:
+ 09:41:a2:c4:ec:74:69:15:52:c4:45:2d:20:ff:b5:
+ ce:d0:41:be:a2:b2:4d:ef:a7:3b:f1:df:9d:78:1a:
+ 9d:2c:6c:61:26:2e:f7:82:ab:50:76:6d:a3:d3:33:
+ 46:07
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 95:3C:F4:24:9F:9C:4A:CB:16:AA:A4:8A:AB:DF:D7:9D:6D:BA:AC:FA
+ X509v3 Authority Key Identifier:
+ keyid:29:73:E8:7F:69:DE:63:14:43:C6:6D:55:6C:C2:AE:84:FA:D5:FC:8C
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ a7:dc:31:88:64:26:72:62:34:8d:3a:75:7a:71:d4:ae:7a:2c:
+ f4:2d:44:e9:e9:e8:c5:4d:79:b2:dc:12:ea:75:60:44:cb:6e:
+ df:22:47:d5:ae:f6:03:dc:c4:6b:cf:90:75:29:49:50:04:e0:
+ 94:2a:b3:bf:d4:ae:e2:08:ad:52:22:65:91:33:09:79:cf:c9:
+ 27:9b:52:dd:a8:0d:f5:21:b6:58:c4:5f:1b:79:72:69:7a:7b:
+ 49:7d:64:67:d0:d6:1c:21:fe:e9:ae:39:1c:b4:3f:f2:f6:6d:
+ 7e:30:15:76:a3:af:eb:43:c0:ed:f3:8a:bc:48:5c:47:fc:44:
+ 09:da:7d:9a:20:f1:e2:1d:4d:40:34:0c:e1:68:16:9e:47:57:
+ 1a:6a:19:e4:b2:6e:dd:7c:69:5f:b8:2b:bd:e7:cb:e4:9c:9c:
+ 79:e1:a5:b3:82:a1:c9:5b:fd:73:d6:a8:1d:1d:d8:31:d6:37:
+ 00:e9:7a:d2:a2:ee:c0:42:21:22:da:70:6e:a8:8c:fa:0c:24:
+ c9:70:4b:49:0a:c1:db:35:f2:71:d7:30:41:a7:6b:05:92:c6:
+ cd:8c:d4:de:c2:6b:aa:b8:70:d2:fa:cf:9a:01:af:34:80:95:
+ ad:ab:59:86:f2:56:6d:d8:43:95:24:e3:f7:7b:b9:83:89:ed:
+ e7:7a:2f:35
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCjIRc1
+wHfxo1F3EUU+kl+XZeuZzCbijPhK2D1xF6Lras8vB6j6J8H4xVAiQqJvkktnwwyn
+7DWHBazr4yfNYj3ELoD2Kq8xBccbDztxbZB3DbRI5yYuSkSvu3bgYuzmYcxbYeoD
+zk1G0Jbi1dlnbwzyBuOaFARogojWi8F/+4GM5tyIIPdT79VWW14As1voztDSau24
+SvJLVvtjddRro4rUP+aeKRunI2G68NYZ+4ytQC98FDYPS/Fu8LhufcyCEWNIFS80
+AJnNvrQavthzOACswQlBosTsdGkVUsRFLSD/tc7QQb6isk3vpzvx3514Gp0sbGEm
+LveCq1B2baPTM0YHAgMBAAGjgekwgeYwHQYDVR0OBBYEFJU89CSfnErLFqqkiqvf
+151tuqz6MB8GA1UdIwQYMBaAFClz6H9p3mMUQ8ZtVWzCroT61fyMMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAp9wxiGQmcmI0jTp1enHU
+rnos9C1E6enoxU15stwS6nVgRMtu3yJH1a72A9zEa8+QdSlJUATglCqzv9Su4git
+UiJlkTMJec/JJ5tS3agN9SG2WMRfG3lyaXp7SX1kZ9DWHCH+6a45HLQ/8vZtfjAV
+dqOv60PA7fOKvEhcR/xECdp9miDx4h1NQDQM4WgWnkdXGmoZ5LJu3XxpX7grvefL
+5JyceeGls4KhyVv9c9aoHR3YMdY3AOl60qLuwEIhItpwbqiM+gwkyXBLSQrB2zXy
+cdcwQadrBZLGzYzU3sJrqrhw0vrPmgGvNICVratZhvJWbdhDlSTj93u5g4nt53ov
+NQ==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:cf:bd:56:f0:dc:36:bc:a8:05:9b:fd:e3:c1:86:
+ da:96:c5:0b:b0:7f:fd:e5:6d:f4:df:44:46:82:ed:
+ 45:60:4b:5d:c6:27:5a:d8:f1:3c:28:a5:eb:3f:a9:
+ 5f:bc:b2:a9:20:fe:09:fa:39:76:5f:2a:91:b2:ef:
+ c9:47:70:c9:d0:ce:66:57:25:d0:72:12:c5:2a:ab:
+ 5c:bc:b3:9a:ba:c8:e9:cb:81:6a:16:f1:7d:a9:9f:
+ e8:9a:0a:47:29:53:34:f7:99:70:14:c6:63:4c:aa:
+ ba:96:7c:78:c4:11:d1:cc:3b:35:56:e8:7f:41:9c:
+ 41:69:d2:b0:dd:36:00:ed:dd:a2:bd:e2:56:29:c5:
+ 8d:4e:7b:71:fb:f5:a1:7b:37:df:d2:66:d4:fe:c8:
+ 24:6d:a3:c4:43:e9:d3:3e:e3:08:78:95:e9:86:e3:
+ 73:09:f9:04:fe:1a:25:19:5b:7c:a8:da:62:05:aa:
+ 56:1b:2a:d4:33:ff:4f:a2:fe:34:90:ec:e9:94:f5:
+ 0a:92:e9:b3:bf:c4:d3:78:80:0a:5e:4e:11:58:94:
+ 66:a8:52:b8:6e:49:64:cb:45:ee:7c:46:80:d7:3d:
+ 40:df:9e:69:54:ce:a5:7f:db:6b:73:42:c5:9c:6e:
+ 7c:b6:9f:ac:b9:8c:cd:7f:da:00:7b:3b:c2:dd:4d:
+ 44:c7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 29:73:E8:7F:69:DE:63:14:43:C6:6D:55:6C:C2:AE:84:FA:D5:FC:8C
+ X509v3 Authority Key Identifier:
+ keyid:77:B3:BD:49:4D:67:D0:7E:4F:67:C3:26:C7:1E:66:42:F9:6D:E4:08
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ ad:b2:08:36:77:a1:da:aa:e4:31:7d:a8:61:03:be:0a:86:a2:
+ 15:3b:08:bb:c8:86:eb:f8:52:c0:63:27:db:5c:25:16:98:05:
+ b1:84:dc:12:74:ce:25:a6:2e:be:32:2c:1f:0a:04:4e:9e:bb:
+ a1:b6:34:ef:20:2d:a3:fe:cc:b3:40:2e:75:9c:2d:c3:c0:e7:
+ 8e:aa:9f:18:60:a9:61:18:4f:a5:d8:3d:c7:d3:09:62:6c:b8:
+ 5a:99:3b:34:70:7b:7d:61:cc:f8:c9:71:97:2c:59:96:d2:1a:
+ c5:4e:ce:df:65:cf:18:05:bd:9f:bc:86:ba:16:55:79:58:d8:
+ f7:32:44:b6:59:32:9f:5d:ef:04:25:2a:2d:54:36:9e:62:0f:
+ c4:df:1c:10:64:02:ba:64:f2:ea:3d:cc:5c:ea:2e:4d:72:fa:
+ e9:72:0f:77:af:5d:1e:32:b9:64:7c:c5:b2:77:36:64:e5:ba:
+ d0:a0:8c:97:7d:b3:76:6c:c1:15:70:f8:0c:50:b8:3c:d4:6c:
+ 4f:33:32:f2:c8:b8:35:cd:80:a2:3a:49:55:ba:2e:5b:c9:9a:
+ b6:77:fb:0f:01:2e:72:21:bc:88:f6:e3:71:8c:68:59:f3:1b:
+ d8:e1:d3:e3:6c:15:5d:8d:82:a3:db:84:44:58:3e:2f:a9:88:
+ 56:2a:a6:4b
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz71W8Nw2
+vKgFm/3jwYbalsULsH/95W3030RGgu1FYEtdxida2PE8KKXrP6lfvLKpIP4J+jl2
+XyqRsu/JR3DJ0M5mVyXQchLFKqtcvLOausjpy4FqFvF9qZ/omgpHKVM095lwFMZj
+TKq6lnx4xBHRzDs1Vuh/QZxBadKw3TYA7d2iveJWKcWNTntx+/Whezff0mbU/sgk
+baPEQ+nTPuMIeJXphuNzCfkE/holGVt8qNpiBapWGyrUM/9Pov40kOzplPUKkumz
+v8TTeIAKXk4RWJRmqFK4bklky0XufEaA1z1A355pVM6lf9trc0LFnG58tp+suYzN
+f9oAezvC3U1ExwIDAQABo4HLMIHIMB0GA1UdDgQWBBQpc+h/ad5jFEPGbVVswq6E
++tX8jDAfBgNVHSMEGDAWgBR3s71JTWfQfk9nwybHHmZC+W3kCDA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgWgMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AK2yCDZ3odqq5DF9qGEDvgqGohU7CLvIhuv4UsBjJ9tcJRaYBbGE3BJ0ziWmLr4y
+LB8KBE6eu6G2NO8gLaP+zLNALnWcLcPA546qnxhgqWEYT6XYPcfTCWJsuFqZOzRw
+e31hzPjJcZcsWZbSGsVOzt9lzxgFvZ+8hroWVXlY2PcyRLZZMp9d7wQlKi1UNp5i
+D8TfHBBkArpk8uo9zFzqLk1y+ulyD3evXR4yuWR8xbJ3NmTlutCgjJd9s3ZswRVw
++AxQuDzUbE8zMvLIuDXNgKI6SVW6LlvJmrZ3+w8BLnIhvIj243GMaFnzG9jh0+Ns
+FV2NgqPbhERYPi+piFYqpks=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b3:13:19:f8:ad:c0:ff:5e:86:19:9a:3c:7f:0c:
+ 04:81:2c:bd:c4:ee:fe:6c:bb:b5:a2:ee:08:10:bd:
+ bb:b6:d1:6c:0d:e7:49:6a:45:0f:0f:46:2b:b6:49:
+ 49:92:7d:c8:b8:81:c1:3f:70:80:39:8a:29:de:77:
+ f0:a3:3e:ef:8f:8d:9c:74:ca:05:c6:5f:12:fc:d4:
+ 4f:47:64:5d:ea:4d:84:af:f0:d0:88:ff:58:98:ad:
+ 7f:6f:c0:22:bc:8e:a4:44:7b:2c:d3:3e:08:45:2a:
+ 13:20:90:1d:b6:0b:2c:4e:a4:40:c3:76:66:6f:eb:
+ 5c:49:fc:1d:81:8e:a7:cc:a3:91:bd:6f:fa:22:73:
+ 84:35:99:08:2c:3e:8e:0b:74:a6:16:79:b3:37:2f:
+ 66:5c:b1:4c:55:76:af:65:9c:cc:e6:af:b0:8c:c3:
+ 28:24:c9:a0:f2:b4:d0:74:d3:e0:72:af:0d:86:f0:
+ 21:4a:9e:4a:9f:95:7b:7a:73:4c:a9:b5:0a:ac:23:
+ f7:63:64:88:fc:00:9b:69:23:33:1a:75:bd:6d:f6:
+ f2:62:c7:68:19:d0:d1:55:2c:6d:f4:41:d8:3b:79:
+ 41:5f:44:97:b9:8f:5a:b4:0a:12:b9:94:0e:34:c7:
+ a7:93:cf:dd:f1:3d:bb:0f:11:33:fc:c8:c4:76:2d:
+ 9e:cd
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 77:B3:BD:49:4D:67:D0:7E:4F:67:C3:26:C7:1E:66:42:F9:6D:E4:08
+ X509v3 Authority Key Identifier:
+ keyid:77:B3:BD:49:4D:67:D0:7E:4F:67:C3:26:C7:1E:66:42:F9:6D:E4:08
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 5d:bb:5a:36:f5:74:9c:51:8c:7c:b3:e0:71:91:0d:51:59:45:
+ 92:b8:3c:f1:0a:42:ac:c3:c7:9f:4e:2a:61:09:7d:46:27:c7:
+ a6:23:09:39:39:18:9e:78:3f:94:cf:d6:44:5e:8e:9f:c4:4e:
+ fd:b4:ab:4f:56:ea:90:6d:4d:51:88:55:e2:56:c0:03:14:a2:
+ 99:d2:1d:67:03:75:6d:5c:a0:c5:5c:78:a6:c5:8e:96:6e:7a:
+ 4f:a1:b0:4e:29:62:92:bc:44:88:a4:72:8d:64:16:da:ff:c4:
+ e8:4c:d3:eb:a6:03:85:eb:a8:42:ee:ae:c0:87:f2:43:41:05:
+ 43:e2:d5:ad:b6:59:dd:59:51:6c:2b:77:f3:51:a9:e0:9b:3e:
+ ba:04:64:d3:f3:ce:59:5a:ad:b1:56:da:91:80:89:d9:62:81:
+ 99:9c:a4:49:24:7a:bc:91:4e:ab:86:e6:0b:76:0d:34:2d:75:
+ fa:7b:13:f5:b3:52:22:c1:57:7c:cd:79:0c:2b:ba:8b:87:83:
+ 52:59:5b:69:55:9d:c4:0a:98:b0:b0:dd:88:86:8c:28:c3:b2:
+ bd:35:85:b1:f0:78:6a:99:ac:63:52:08:5b:69:97:55:c0:87:
+ 81:be:bd:09:7f:eb:56:a9:84:9f:f6:9c:df:f2:19:41:60:f1:
+ 06:d1:77:38
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALMTGfitwP9ehhmaPH8M
+BIEsvcTu/my7taLuCBC9u7bRbA3nSWpFDw9GK7ZJSZJ9yLiBwT9wgDmKKd538KM+
+74+NnHTKBcZfEvzUT0dkXepNhK/w0Ij/WJitf2/AIryOpER7LNM+CEUqEyCQHbYL
+LE6kQMN2Zm/rXEn8HYGOp8yjkb1v+iJzhDWZCCw+jgt0phZ5szcvZlyxTFV2r2Wc
+zOavsIzDKCTJoPK00HTT4HKvDYbwIUqeSp+Ve3pzTKm1Cqwj92NkiPwAm2kjMxp1
+vW328mLHaBnQ0VUsbfRB2Dt5QV9El7mPWrQKErmUDjTHp5PP3fE9uw8RM/zIxHYt
+ns0CAwEAAaOByzCByDAdBgNVHQ4EFgQUd7O9SU1n0H5PZ8Mmxx5mQvlt5AgwHwYD
+VR0jBBgwFoAUd7O9SU1n0H5PZ8Mmxx5mQvlt5AgwNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBdu1o29XSc
+UYx8s+BxkQ1RWUWSuDzxCkKsw8efTiphCX1GJ8emIwk5ORieeD+Uz9ZEXo6fxE79
+tKtPVuqQbU1RiFXiVsADFKKZ0h1nA3VtXKDFXHimxY6WbnpPobBOKWKSvESIpHKN
+ZBba/8ToTNPrpgOF66hC7q7Ah/JDQQVD4tWttlndWVFsK3fzUangmz66BGTT885Z
+Wq2xVtqRgInZYoGZnKRJJHq8kU6rhuYLdg00LXX6exP1s1IiwVd8zXkMK7qLh4NS
+WVtpVZ3ECpiwsN2Ihowow7K9NYWx8HhqmaxjUghbaZdVwIeBvr0Jf+tWqYSf9pzf
+8hlBYPEG0Xc4
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+FAIL
+-----BEGIN VERIFY_RESULT-----
+RkFJTA==
+-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 0
+ [Error] keyCertSign bit is not set
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMAogICAgICBbRXJyb3JdIGtleUNlcnRTaWduIGJpdCBpcyBub3Qgc2V0Cg==
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/intermediate-signed-with-md5.pem b/chromium/net/data/verify_certificate_chain_unittest/intermediate-signed-with-md5.pem
new file mode 100644
index 00000000000..9e343d0736d
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/intermediate-signed-with-md5.pem
@@ -0,0 +1,292 @@
+[Created by: generate-intermediate-signed-with-md5.py]
+
+Certificate chain with 1 intermediate and a trusted root. The intermediate
+however is signed using the MD5 hash. Verification is expected to fail because
+MD5 is too weak.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:bf:20:16:45:28:21:d2:a5:63:de:24:67:38:92:
+ 4c:f1:a4:c8:45:30:94:b8:aa:5f:7c:1a:3f:6c:28:
+ 2f:31:7e:a6:bb:af:45:46:68:a2:f2:5d:a4:94:4b:
+ 9b:c9:4c:e0:5d:be:ce:34:5e:08:df:a7:50:c0:30:
+ 94:98:0f:52:ec:ec:91:23:91:bc:24:60:65:9d:b7:
+ 74:38:7f:9d:d4:20:94:5c:1b:6f:71:82:e1:b5:98:
+ 95:3c:33:48:7e:6a:c6:e0:59:e6:a2:c5:0b:95:78:
+ 0e:7e:e3:a8:16:93:0a:43:df:ec:d7:03:c0:f1:60:
+ 13:45:9d:52:b5:37:66:03:79:78:8f:d6:53:87:7c:
+ dd:50:8a:16:54:33:bb:62:f2:42:a0:fa:49:c3:c1:
+ e2:c4:c8:d7:db:49:16:43:c8:69:0e:88:e2:f1:2d:
+ c6:59:c6:5a:e3:d8:57:e9:a7:10:48:73:c8:c8:f7:
+ a1:6d:57:25:b3:04:43:05:6a:90:1d:87:36:67:7f:
+ 3e:97:eb:5b:66:03:3a:10:56:32:1d:04:cc:43:90:
+ 82:9c:ed:d2:b4:4d:ba:d0:ac:23:26:f9:25:5e:63:
+ 6c:e1:83:07:2b:ec:38:9a:d1:82:bc:38:a0:64:58:
+ 19:c2:77:3c:e9:bd:20:d5:45:43:8d:ee:51:ba:98:
+ 95:65
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 7E:D1:A4:40:CE:81:CA:14:BD:C9:25:39:E5:F7:21:B6:24:90:61:1D
+ X509v3 Authority Key Identifier:
+ keyid:60:72:15:4D:8C:1A:E1:CD:8F:EF:00:AA:9B:37:4C:00:57:29:66:15
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 6f:98:46:c6:44:e8:ba:f3:06:49:81:74:87:9e:d5:a1:0c:54:
+ 66:56:88:7d:89:5e:cd:2f:1a:06:af:d8:c7:ed:9e:ad:8c:7a:
+ b0:3d:eb:93:3a:59:49:89:ba:ec:27:15:0e:08:d0:cd:ff:40:
+ 57:3f:c2:77:c1:08:cb:5d:4f:40:ec:20:b3:96:9b:43:fa:96:
+ 00:42:cd:dc:db:27:3e:98:fd:8a:45:80:ef:5c:86:20:12:a5:
+ 83:b3:74:66:09:57:1c:4d:7e:0e:00:c4:57:dc:86:c0:2b:db:
+ fb:3a:77:1c:5f:7d:8f:ae:47:16:96:85:48:a7:95:4c:bc:b1:
+ 18:09:34:c4:78:76:57:46:db:1e:b7:12:16:78:54:ec:2d:eb:
+ 44:00:54:48:1d:6b:b0:d1:98:a8:58:ab:3d:f2:f2:5b:06:44:
+ d1:d5:d6:f5:d1:f2:c4:46:93:9a:9b:29:a8:9f:91:3d:e5:16:
+ d6:d6:ba:55:76:1c:2d:90:76:2f:92:a1:e4:52:a4:f3:f3:2a:
+ 3c:b3:11:78:f6:9a:ce:17:c3:8f:da:57:fc:a2:02:06:59:9f:
+ 18:10:ba:45:b4:0d:3d:64:aa:6c:ae:5b:a6:c8:f3:8b:d0:b0:
+ b6:1b:4a:cc:6c:fe:f9:d6:e4:15:da:28:1b:22:b3:ce:b4:6f:
+ bf:39:9b:34
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/IBZF
+KCHSpWPeJGc4kkzxpMhFMJS4ql98Gj9sKC8xfqa7r0VGaKLyXaSUS5vJTOBdvs40
+Xgjfp1DAMJSYD1Ls7JEjkbwkYGWdt3Q4f53UIJRcG29xguG1mJU8M0h+asbgWeai
+xQuVeA5+46gWkwpD3+zXA8DxYBNFnVK1N2YDeXiP1lOHfN1QihZUM7ti8kKg+knD
+weLEyNfbSRZDyGkOiOLxLcZZxlrj2FfppxBIc8jI96FtVyWzBEMFapAdhzZnfz6X
+61tmAzoQVjIdBMxDkIKc7dK0TbrQrCMm+SVeY2zhgwcr7Dia0YK8OKBkWBnCdzzp
+vSDVRUON7lG6mJVlAgMBAAGjgekwgeYwHQYDVR0OBBYEFH7RpEDOgcoUvcklOeX3
+IbYkkGEdMB8GA1UdIwQYMBaAFGByFU2MGuHNj+8Aqps3TABXKWYVMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAb5hGxkTouvMGSYF0h57V
+oQxUZlaIfYlezS8aBq/Yx+2erYx6sD3rkzpZSYm67CcVDgjQzf9AVz/Cd8EIy11P
+QOwgs5abQ/qWAELN3NsnPpj9ikWA71yGIBKlg7N0ZglXHE1+DgDEV9yGwCvb+zp3
+HF99j65HFpaFSKeVTLyxGAk0xHh2V0bbHrcSFnhU7C3rRABUSB1rsNGYqFirPfLy
+WwZE0dXW9dHyxEaTmpspqJ+RPeUW1ta6VXYcLZB2L5Kh5FKk8/MqPLMRePaazhfD
+j9pX/KICBlmfGBC6RbQNPWSqbK5bpsjzi9CwthtKzGz++dbkFdooGyKzzrRvvzmb
+NA==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: md5WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c7:04:ea:a3:74:51:66:9f:f2:6b:5d:9a:3d:96:
+ bd:5c:b3:9e:9c:df:64:42:c7:85:1e:56:7a:3e:d5:
+ 3d:c9:f3:17:46:a3:a0:98:f6:80:df:f4:54:ca:e2:
+ d5:e9:15:b8:3a:19:4e:1e:26:67:00:80:96:d5:bc:
+ 1e:af:a4:f3:23:de:15:72:89:1f:50:3f:8c:e1:62:
+ 6d:e1:0d:42:9f:67:76:aa:f5:20:b4:4d:58:fd:3d:
+ 63:57:bc:9c:23:fa:db:31:0c:09:37:0d:7c:f4:d1:
+ 06:c4:7f:b1:22:d1:df:05:43:a4:12:94:e2:02:ee:
+ b7:ae:cd:48:04:00:39:4f:dc:40:f7:62:a7:d9:3e:
+ 81:9c:5d:98:6f:8d:0f:da:b6:0e:ad:1d:5b:ff:b6:
+ 50:90:ab:55:c7:2a:db:d8:67:6c:0f:87:68:8a:2a:
+ 79:24:a7:64:d8:c1:72:15:ff:6e:ca:31:f1:92:42:
+ 2e:78:a5:ce:2b:07:8a:4b:a0:80:88:14:76:d6:e1:
+ ad:b2:75:9d:79:9b:d6:c2:cc:ac:74:67:d2:5b:90:
+ 6f:c4:8f:50:4c:ce:50:89:a4:69:ab:ca:d4:d1:a4:
+ 47:ae:0d:46:f3:5f:28:91:66:27:02:f0:7a:da:aa:
+ 80:be:c2:e7:83:89:06:49:de:9d:60:03:a3:fc:11:
+ e2:2b
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 60:72:15:4D:8C:1A:E1:CD:8F:EF:00:AA:9B:37:4C:00:57:29:66:15
+ X509v3 Authority Key Identifier:
+ keyid:60:B4:95:7F:EA:F1:29:B2:E9:9D:64:83:A9:C8:A3:49:6F:3E:18:53
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: md5WithRSAEncryption
+ 0b:ea:a8:1e:f0:70:66:9b:e0:48:9a:fa:62:3b:80:b0:9f:41:
+ e3:60:35:9c:b4:6e:0c:32:17:9d:38:72:b3:de:69:45:69:b1:
+ 4b:87:2a:e1:68:59:d6:b9:03:c4:88:7e:e0:77:26:3d:c5:ad:
+ 55:3f:13:bc:13:42:0f:9c:be:f7:70:3e:19:79:96:3b:b8:12:
+ d6:8a:a2:04:d2:17:ee:bd:78:db:cc:9f:54:87:26:89:61:c9:
+ f1:3e:8f:2f:19:55:49:05:c0:35:b2:ea:c4:ec:9a:11:d6:88:
+ f2:4b:ad:68:0a:32:75:42:42:a0:6a:51:cb:0f:63:32:20:4a:
+ 59:89:e5:f9:61:ee:63:80:e0:71:03:d1:58:ea:d6:31:24:11:
+ ef:03:44:02:76:86:67:99:a5:71:18:a8:4e:be:fe:78:63:20:
+ 67:b1:5a:1d:52:2a:48:fb:8a:ee:99:af:8f:57:37:43:67:1c:
+ 54:00:d0:50:8c:ce:18:e0:ef:7b:cc:e1:13:d1:cc:3f:ea:3c:
+ ce:cf:07:fc:6e:4a:09:b1:1c:54:70:a4:21:47:5d:70:7d:b4:
+ 04:3e:30:50:1d:86:2a:a6:67:3f:bd:b0:cb:57:e0:26:81:45:
+ c0:9a:86:8c:e6:ab:d0:87:9a:05:ee:2c:c5:eb:c6:c7:c0:94:
+ 68:4a:48:20
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQQFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxwTqo3RR
+Zp/ya12aPZa9XLOenN9kQseFHlZ6PtU9yfMXRqOgmPaA3/RUyuLV6RW4OhlOHiZn
+AICW1bwer6TzI94VcokfUD+M4WJt4Q1Cn2d2qvUgtE1Y/T1jV7ycI/rbMQwJNw18
+9NEGxH+xItHfBUOkEpTiAu63rs1IBAA5T9xA92Kn2T6BnF2Yb40P2rYOrR1b/7ZQ
+kKtVxyrb2GdsD4doiip5JKdk2MFyFf9uyjHxkkIueKXOKweKS6CAiBR21uGtsnWd
+eZvWwsysdGfSW5BvxI9QTM5QiaRpq8rU0aRHrg1G818okWYnAvB62qqAvsLng4kG
+Sd6dYAOj/BHiKwIDAQABo4HLMIHIMB0GA1UdDgQWBBRgchVNjBrhzY/vAKqbN0wA
+VylmFTAfBgNVHSMEGDAWgBRgtJV/6vEpsumdZIOpyKNJbz4YUzA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEB
+AAvqqB7wcGab4Eia+mI7gLCfQeNgNZy0bgwyF504crPeaUVpsUuHKuFoWda5A8SI
+fuB3Jj3FrVU/E7wTQg+cvvdwPhl5lju4EtaKogTSF+69eNvMn1SHJolhyfE+jy8Z
+VUkFwDWy6sTsmhHWiPJLrWgKMnVCQqBqUcsPYzIgSlmJ5flh7mOA4HED0Vjq1jEk
+Ee8DRAJ2hmeZpXEYqE6+/nhjIGexWh1SKkj7iu6Zr49XN0NnHFQA0FCMzhjg73vM
+4RPRzD/qPM7PB/xuSgmxHFRwpCFHXXB9tAQ+MFAdhiqmZz+9sMtX4CaBRcCahozm
+q9CHmgXuLMXrxsfAlGhKSCA=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d3:ee:d0:8d:92:7d:ce:5f:4e:f2:0c:55:4d:bd:
+ 2f:b3:ff:6a:ab:2c:28:5e:c6:bd:49:ae:80:f0:e6:
+ 2c:30:e8:0a:e7:2b:3f:d7:1e:a8:6d:f1:c4:46:0e:
+ f5:1d:3c:e1:05:5d:a9:91:69:57:43:22:33:bc:c1:
+ 18:6e:b1:48:1f:13:64:18:03:c1:63:14:97:21:5a:
+ 65:49:52:6a:57:9d:ad:7b:f6:06:6e:f0:af:a0:6d:
+ 2c:6d:53:9a:ad:82:56:2a:95:e1:a7:5a:a3:b4:77:
+ c7:d7:97:39:73:c8:de:a8:19:09:ba:69:69:01:25:
+ e6:68:e3:d0:5a:84:5d:3e:f0:8a:3b:c6:31:26:34:
+ 38:ed:8d:40:80:0f:5f:84:d7:e5:4f:24:ca:ff:c1:
+ 48:f5:74:3a:b3:1e:9f:b5:ef:bb:24:cb:91:f3:81:
+ 47:bd:80:eb:ef:dd:45:39:fd:d2:c3:be:3e:ba:e6:
+ 5b:09:e0:88:98:27:91:e5:9a:5b:88:d6:5e:17:7f:
+ 08:e2:2d:f4:3c:3f:08:54:7b:10:53:f4:7d:ef:67:
+ 04:6f:d6:74:08:d1:b9:03:2d:89:5d:ca:cf:de:3d:
+ d0:e5:e2:e5:2a:7f:21:29:23:7e:b2:75:d9:ea:5c:
+ 73:45:7e:33:83:b6:62:5e:01:3b:dd:11:99:c7:c5:
+ 7b:65
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 60:B4:95:7F:EA:F1:29:B2:E9:9D:64:83:A9:C8:A3:49:6F:3E:18:53
+ X509v3 Authority Key Identifier:
+ keyid:60:B4:95:7F:EA:F1:29:B2:E9:9D:64:83:A9:C8:A3:49:6F:3E:18:53
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 49:67:dc:58:22:e3:ee:0a:e8:1a:3d:38:1a:13:dd:d7:e0:45:
+ 67:69:b1:44:49:e2:96:15:86:94:8b:d4:fb:8a:94:d5:22:39:
+ 20:48:97:d2:09:a7:16:4b:40:f3:3c:37:3e:e8:81:28:08:cf:
+ 4a:2c:3e:79:d0:0d:90:4d:63:a5:63:ce:24:75:03:41:7f:79:
+ 17:3f:4d:df:60:98:a5:a3:c1:39:14:4b:7e:b7:0d:8a:9f:d6:
+ a4:0b:0c:34:c9:fe:3b:c0:89:9e:5e:27:3d:d8:3d:d5:28:46:
+ e4:b9:f5:28:39:b4:cf:1a:ea:fd:d3:14:bd:8b:87:78:35:80:
+ a1:bb:4e:59:cc:2a:f7:f7:40:bc:b7:75:cc:35:f5:3d:95:bb:
+ 32:7a:0c:9d:67:c7:ff:b0:da:e6:05:e6:12:d5:1e:19:3c:69:
+ 5d:d8:08:5e:bc:fe:df:ab:36:a4:70:3f:2c:6c:1c:8e:e3:f1:
+ 0b:b3:22:e4:5b:fd:86:23:7a:bd:9b:b9:56:08:e3:a2:6d:2b:
+ e3:cb:42:93:6f:c8:5f:57:bd:66:41:51:8a:5d:4b:7e:0f:36:
+ 82:61:8e:e0:4e:2c:9a:7a:45:e3:21:1c:b8:86:cf:a0:35:1b:
+ bf:55:36:86:05:1c:df:b0:e2:85:3b:a4:c7:7c:69:f9:56:b3:
+ 20:28:e4:c2
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANPu0I2Sfc5fTvIMVU29
+L7P/aqssKF7GvUmugPDmLDDoCucrP9ceqG3xxEYO9R084QVdqZFpV0MiM7zBGG6x
+SB8TZBgDwWMUlyFaZUlSaledrXv2Bm7wr6BtLG1Tmq2CViqV4adao7R3x9eXOXPI
+3qgZCbppaQEl5mjj0FqEXT7wijvGMSY0OO2NQIAPX4TX5U8kyv/BSPV0OrMen7Xv
+uyTLkfOBR72A6+/dRTn90sO+PrrmWwngiJgnkeWaW4jWXhd/COIt9Dw/CFR7EFP0
+fe9nBG/WdAjRuQMtiV3Kz9490OXi5Sp/ISkjfrJ12epcc0V+M4O2Yl4BO90RmcfF
+e2UCAwEAAaOByzCByDAdBgNVHQ4EFgQUYLSVf+rxKbLpnWSDqcijSW8+GFMwHwYD
+VR0jBBgwFoAUYLSVf+rxKbLpnWSDqcijSW8+GFMwNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBJZ9xYIuPu
+CugaPTgaE93X4EVnabFESeKWFYaUi9T7ipTVIjkgSJfSCacWS0DzPDc+6IEoCM9K
+LD550A2QTWOlY84kdQNBf3kXP03fYJilo8E5FEt+tw2Kn9akCww0yf47wImeXic9
+2D3VKEbkufUoObTPGur90xS9i4d4NYChu05ZzCr390C8t3XMNfU9lbsyegydZ8f/
+sNrmBeYS1R4ZPGld2AhevP7fqzakcD8sbByO4/ELsyLkW/2GI3q9m7lWCOOibSvj
+y0KTb8hfV71mQVGKXUt+DzaCYY7gTiyaekXjIRy4hs+gNRu/VTaGBRzfsOKFO6TH
+fGn5VrMgKOTC
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+FAIL
+-----BEGIN VERIFY_RESULT-----
+RkFJTA==
+-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 0
+ [Error] Invalid or unsupported signature algorithm
+ algorithm: 300D06092A864886F70D0101040500
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMAogICAgICBbRXJyb3JdIEludmFsaWQgb3IgdW5zdXBwb3J0ZWQgc2lnbmF0dXJlIGFsZ29yaXRobQogICAgICAgIGFsZ29yaXRobTogMzAwRDA2MDkyQTg2NDg4NkY3MEQwMTAxMDQwNTAwCg==
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/intermediate-unknown-critical-extension.pem b/chromium/net/data/verify_certificate_chain_unittest/intermediate-unknown-critical-extension.pem
new file mode 100644
index 00000000000..3d65c7e2f6a
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/intermediate-unknown-critical-extension.pem
@@ -0,0 +1,296 @@
+[Created by: generate-intermediate-unknown-critical-extension.py]
+
+Certificate chain with 1 intermediate and a trusted root. The intermediate
+has an unknown X.509v3 extension (OID=1.2.3.4) that is marked as critical.
+Verifying this certificate chain is expected to fail because there is an
+unrecognized critical extension.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c7:8a:82:ba:91:ca:1e:03:94:8f:9d:68:98:8b:
+ 95:3b:c1:e3:d1:5b:82:45:bf:72:24:cb:6f:de:91:
+ 2e:e3:49:ba:31:7b:57:db:90:36:32:e6:b4:41:8f:
+ 38:89:c6:6b:82:60:dc:98:e7:4b:06:55:41:db:9c:
+ a8:e0:97:15:5a:3c:06:ac:37:89:f5:9b:65:b6:93:
+ a7:2e:45:f3:b3:15:59:a7:6d:64:d5:cb:93:da:46:
+ b1:97:8a:79:f6:48:4b:4c:18:d6:38:cf:55:5b:6b:
+ 78:c2:f5:f0:37:54:67:8d:90:43:81:ec:15:1e:e7:
+ 75:55:57:7e:6a:74:71:73:6d:b4:d5:37:b5:28:40:
+ 2e:6f:a6:64:b8:77:fd:2c:6c:25:2c:27:cf:db:fa:
+ b4:c9:39:c2:d1:1e:e2:a1:73:bb:ec:81:dc:c3:ec:
+ d0:a0:08:1e:81:53:88:51:d2:83:d2:ba:33:3f:79:
+ 1e:2a:6f:80:7b:21:d8:bb:80:93:68:ea:f4:a9:d5:
+ 88:b8:ac:0b:ff:90:bd:cc:8a:6b:e7:e5:27:47:d9:
+ a0:68:5d:38:3c:b0:a3:4a:ae:5a:d9:a6:f8:51:61:
+ 28:fb:21:5c:01:aa:72:76:60:f6:e0:88:a1:44:b5:
+ fa:85:27:45:67:0f:c6:b1:11:00:81:23:3c:aa:a1:
+ 58:65
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 94:30:C8:2B:C4:EC:EB:81:5B:D2:2B:62:ED:34:29:BB:3C:40:FD:4B
+ X509v3 Authority Key Identifier:
+ keyid:C8:5D:13:08:EB:15:BB:7B:35:8E:74:DF:D3:C3:55:51:78:E1:4A:D3
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ ca:46:c4:08:c9:4e:1b:3f:96:fd:d7:9c:89:d6:ea:7f:76:53:
+ ac:03:55:eb:9a:d5:86:f8:66:cd:39:54:f0:7b:d1:74:62:83:
+ c7:58:46:b1:ad:da:b7:fd:03:94:3b:b8:a5:4a:01:45:53:2c:
+ c6:ae:55:52:08:78:de:66:49:a0:40:eb:7d:43:03:00:46:03:
+ 1d:6d:c5:83:57:f6:92:a5:c6:04:76:f1:de:bf:ec:90:8b:3b:
+ 99:70:80:41:10:93:07:2c:eb:cd:5b:b5:e6:12:76:41:db:81:
+ ab:f5:6a:a5:e4:67:45:39:fa:14:bf:0d:e7:e4:a9:f3:9a:57:
+ 4c:20:4e:68:fd:1a:35:00:66:b7:c6:fd:2f:14:db:7b:28:3a:
+ 59:31:5a:9d:96:d1:2e:27:d1:7a:c3:eb:b4:28:f1:e2:9a:d1:
+ 1d:be:6b:9d:81:4e:4c:7f:5d:fe:5f:20:8f:bb:f0:85:ee:bb:
+ 2d:66:40:bb:ec:40:c1:51:4f:f9:1d:24:4e:64:ad:64:1c:e5:
+ 68:3f:cb:b2:6c:c5:82:c9:e7:5d:7d:73:8d:ec:d9:b7:af:06:
+ 71:53:92:dd:aa:23:28:38:f0:06:d6:64:cb:f5:ac:f2:4c:e2:
+ 5a:55:c3:a6:d7:7e:32:21:19:54:c4:aa:cd:21:60:fd:b7:45:
+ 81:a1:53:ae
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHioK6
+kcoeA5SPnWiYi5U7wePRW4JFv3Iky2/ekS7jSboxe1fbkDYy5rRBjziJxmuCYNyY
+50sGVUHbnKjglxVaPAasN4n1m2W2k6cuRfOzFVmnbWTVy5PaRrGXinn2SEtMGNY4
+z1Vba3jC9fA3VGeNkEOB7BUe53VVV35qdHFzbbTVN7UoQC5vpmS4d/0sbCUsJ8/b
++rTJOcLRHuKhc7vsgdzD7NCgCB6BU4hR0oPSujM/eR4qb4B7Idi7gJNo6vSp1Yi4
+rAv/kL3Mimvn5SdH2aBoXTg8sKNKrlrZpvhRYSj7IVwBqnJ2YPbgiKFEtfqFJ0Vn
+D8axEQCBIzyqoVhlAgMBAAGjgekwgeYwHQYDVR0OBBYEFJQwyCvE7OuBW9IrYu00
+Kbs8QP1LMB8GA1UdIwQYMBaAFMhdEwjrFbt7NY5039PDVVF44UrTMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAykbECMlOGz+W/decidbq
+f3ZTrANV65rVhvhmzTlU8HvRdGKDx1hGsa3at/0DlDu4pUoBRVMsxq5VUgh43mZJ
+oEDrfUMDAEYDHW3Fg1f2kqXGBHbx3r/skIs7mXCAQRCTByzrzVu15hJ2QduBq/Vq
+peRnRTn6FL8N5+Sp85pXTCBOaP0aNQBmt8b9LxTbeyg6WTFanZbRLifResPrtCjx
+4prRHb5rnYFOTH9d/l8gj7vwhe67LWZAu+xAwVFP+R0kTmStZBzlaD/LsmzFgsnn
+XX1zjezZt68GcVOS3aojKDjwBtZky/Ws8kziWlXDptd+MiEZVMSqzSFg/bdFgaFT
+rg==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:da:1c:0d:74:40:2d:01:10:9c:e0:0c:aa:01:c7:
+ ed:a4:03:b5:a0:b0:1d:c0:70:70:9a:76:6d:5d:4d:
+ 16:ed:39:87:76:43:e1:c1:3f:b9:f8:20:63:40:02:
+ d4:0f:f4:f5:4a:97:eb:46:ad:8c:29:cb:45:a7:33:
+ 16:b0:10:b3:bc:f6:9e:fb:e6:61:d5:7d:43:ce:27:
+ 43:ae:4f:b1:d1:47:6b:13:e5:20:66:09:b9:10:83:
+ a3:d4:40:6d:cc:fb:cb:28:1e:6e:bc:75:46:7b:9d:
+ f9:b4:5f:c9:43:24:d6:d7:c1:a8:6b:d6:52:1e:6d:
+ 9d:89:d6:41:eb:9f:db:32:e3:05:21:b1:b7:77:78:
+ e1:d4:f9:95:c5:84:63:91:88:ce:31:66:2c:51:89:
+ f3:a4:a3:0d:11:b2:a2:45:fd:59:1b:09:a9:bc:48:
+ 38:0d:25:c7:dd:c9:6a:15:5f:c5:5f:60:5e:c0:28:
+ 5d:19:ff:51:17:86:ea:b5:56:f6:1e:cc:ee:80:93:
+ f2:82:7b:2f:fa:96:1f:4b:15:b0:34:23:81:bb:b9:
+ a4:83:1a:2f:e0:6d:ee:48:96:4d:f1:7b:09:3e:1f:
+ 43:c6:76:8f:56:fd:1e:5f:21:6f:6f:49:b0:94:fa:
+ c9:be:76:61:f6:f8:51:72:40:99:d5:f2:f6:09:f7:
+ d9:8b
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ C8:5D:13:08:EB:15:BB:7B:35:8E:74:DF:D3:C3:55:51:78:E1:4A:D3
+ X509v3 Authority Key Identifier:
+ keyid:3F:B3:AA:13:E1:86:96:B3:E3:8D:20:EC:BE:70:71:D0:1B:F8:67:9A
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ 1.2.3.4: critical
+ ....
+ Signature Algorithm: sha256WithRSAEncryption
+ dc:d2:aa:62:74:fa:cf:eb:4f:b3:cd:aa:a9:52:b0:fe:7a:0d:
+ 96:e4:07:8f:b6:d4:6d:ad:33:a6:4e:ad:2f:a5:ff:83:a0:75:
+ d1:ed:fc:c0:80:a6:73:73:49:6d:0d:3f:84:b5:d4:cf:07:74:
+ 3e:aa:bf:38:59:e4:fa:b6:d2:45:07:b3:a6:0b:b0:43:47:03:
+ 7e:45:c1:7b:f1:84:10:c3:0b:d7:2f:c9:be:ff:96:da:1b:4b:
+ cb:fa:05:ca:22:d2:e4:f0:f7:32:91:4f:95:05:6c:5d:be:6c:
+ 64:7b:cb:6d:a1:a9:d0:9c:5b:1d:3a:bd:4a:50:69:e2:06:fa:
+ 89:2b:3b:2e:12:f6:3f:d7:79:f1:36:ec:e3:6c:12:67:b2:a3:
+ b0:89:16:8c:2c:02:04:0d:89:e1:ca:69:d0:86:7e:fd:14:9d:
+ c8:ef:06:42:fc:46:b9:88:25:e2:b5:b7:8a:6b:ab:d6:1f:ec:
+ d1:12:b3:28:cd:9e:9f:56:8d:7c:49:6c:06:96:93:66:25:43:
+ b0:76:b0:9a:59:f8:9c:35:29:8c:db:a7:74:d7:ac:e7:99:ea:
+ 11:34:0b:6f:cf:bb:5e:28:2a:ab:9a:13:83:44:d7:01:3c:61:
+ c8:10:dd:0d:ef:66:3d:be:ee:72:70:d3:27:a2:b0:f7:f1:bc:
+ 50:e1:ac:3e
+-----BEGIN CERTIFICATE-----
+MIIDfTCCAmWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2hwNdEAt
+ARCc4AyqAcftpAO1oLAdwHBwmnZtXU0W7TmHdkPhwT+5+CBjQALUD/T1SpfrRq2M
+KctFpzMWsBCzvPae++Zh1X1DzidDrk+x0UdrE+UgZgm5EIOj1EBtzPvLKB5uvHVG
+e535tF/JQyTW18Goa9ZSHm2didZB65/bMuMFIbG3d3jh1PmVxYRjkYjOMWYsUYnz
+pKMNEbKiRf1ZGwmpvEg4DSXH3clqFV/FX2BewChdGf9RF4bqtVb2HszugJPygnsv
++pYfSxWwNCOBu7mkgxov4G3uSJZN8XsJPh9DxnaPVv0eXyFvb0mwlPrJvnZh9vhR
+ckCZ1fL2CffZiwIDAQABo4HbMIHYMB0GA1UdDgQWBBTIXRMI6xW7ezWOdN/Tw1VR
+eOFK0zAfBgNVHSMEGDAWgBQ/s6oT4YaWs+ONIOy+cHHQG/hnmjA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDgYDKgMEAQH/BAQBAgMEMA0G
+CSqGSIb3DQEBCwUAA4IBAQDc0qpidPrP60+zzaqpUrD+eg2W5AePttRtrTOmTq0v
+pf+DoHXR7fzAgKZzc0ltDT+EtdTPB3Q+qr84WeT6ttJFB7OmC7BDRwN+RcF78YQQ
+wwvXL8m+/5baG0vL+gXKItLk8PcykU+VBWxdvmxke8ttoanQnFsdOr1KUGniBvqJ
+KzsuEvY/13nxNuzjbBJnsqOwiRaMLAIEDYnhymnQhn79FJ3I7wZC/Ea5iCXitbeK
+a6vWH+zRErMozZ6fVo18SWwGlpNmJUOwdrCaWficNSmM26d016znmeoRNAtvz7te
+KCqrmhODRNcBPGHIEN0N72Y9vu5ycNMnorD38bxQ4aw+
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:e7:de:8d:6f:81:af:35:2d:99:eb:62:b4:41:d8:
+ dd:55:5f:5a:12:02:46:8f:41:14:fe:f5:b0:32:ab:
+ fa:96:2a:e2:ba:e6:3a:1d:89:80:8f:20:6a:40:4a:
+ 5f:97:d3:5d:7f:e8:eb:26:f1:f9:1b:a2:a7:cd:54:
+ c0:d9:64:77:dc:ba:90:a4:b7:86:3f:8c:72:c2:ad:
+ 96:6c:f0:c0:30:d8:e0:71:f5:ff:f3:8c:18:34:3a:
+ 07:b2:79:32:92:91:d4:51:95:c4:bb:62:78:2e:30:
+ f8:b5:f1:91:26:9a:28:07:27:cc:57:d5:a2:1c:e9:
+ 20:ac:fa:3d:db:3b:70:81:17:3d:4b:54:a8:fe:2f:
+ 18:f7:7f:de:cb:4f:ec:70:c8:fa:a9:ed:64:41:36:
+ c2:74:a7:dd:e6:27:2b:af:79:ce:76:86:57:3a:2c:
+ d9:52:b8:bf:87:de:f1:5e:80:81:70:10:78:e7:89:
+ 0a:d1:14:74:f4:f0:93:cf:89:68:66:8f:d4:2a:8a:
+ c8:ff:96:fb:f6:cc:ee:dd:a6:62:f0:73:43:a6:29:
+ 7a:51:7e:63:e1:8f:d9:83:10:23:ed:1b:d4:26:2d:
+ 40:62:c5:ed:c5:af:4f:d9:9b:87:5b:3a:7e:2c:43:
+ 59:e3:f4:91:2f:ab:d0:04:a3:5e:da:ac:b0:c1:e2:
+ 15:99
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 3F:B3:AA:13:E1:86:96:B3:E3:8D:20:EC:BE:70:71:D0:1B:F8:67:9A
+ X509v3 Authority Key Identifier:
+ keyid:3F:B3:AA:13:E1:86:96:B3:E3:8D:20:EC:BE:70:71:D0:1B:F8:67:9A
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 84:9a:7d:63:f9:44:d8:2c:4e:b0:24:86:af:0c:ba:0e:29:33:
+ 67:68:7d:a2:1d:46:99:b0:fb:9d:65:69:da:f8:46:67:d9:c4:
+ 30:72:eb:57:79:4a:e8:2d:7b:57:d4:c2:18:13:19:d1:36:8c:
+ 45:9f:49:1e:a6:83:c5:41:41:fd:29:ac:a0:12:c7:0f:6e:a6:
+ 45:70:64:c3:9d:b0:22:2e:ed:c0:8d:6c:68:c0:94:d9:ba:e0:
+ 2f:5a:1c:29:ed:d0:d6:ec:0e:bb:41:ce:1e:e3:93:c4:85:80:
+ aa:a1:67:31:76:80:24:a4:70:ec:f3:6e:a3:63:8c:71:fd:38:
+ 65:1f:56:e9:75:74:15:3c:69:f3:e3:d3:9d:9a:9c:7d:f6:00:
+ 71:98:61:68:13:7c:23:79:e1:84:68:a6:3d:ce:19:1c:0a:62:
+ 48:d9:f9:4c:92:ff:b7:5b:e8:1d:e4:66:00:50:4d:38:c8:3a:
+ e3:e1:8e:ae:aa:32:30:65:78:25:b3:d0:eb:4f:de:ab:9d:51:
+ 40:7e:6f:d4:15:87:cf:41:7d:be:3d:32:45:a2:f1:a8:7c:11:
+ 97:90:a4:ea:d8:aa:c2:b7:08:34:a3:62:23:4b:a5:e3:9e:4d:
+ 90:7f:d7:4c:dc:4f:c8:ac:b2:b6:de:42:fd:05:98:f6:33:90:
+ 54:c3:6a:3f
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOfejW+BrzUtmetitEHY
+3VVfWhICRo9BFP71sDKr+pYq4rrmOh2JgI8gakBKX5fTXX/o6ybx+Ruip81UwNlk
+d9y6kKS3hj+McsKtlmzwwDDY4HH1//OMGDQ6B7J5MpKR1FGVxLtieC4w+LXxkSaa
+KAcnzFfVohzpIKz6Pds7cIEXPUtUqP4vGPd/3stP7HDI+qntZEE2wnSn3eYnK695
+znaGVzos2VK4v4fe8V6AgXAQeOeJCtEUdPTwk8+JaGaP1CqKyP+W+/bM7t2mYvBz
+Q6YpelF+Y+GP2YMQI+0b1CYtQGLF7cWvT9mbh1s6fixDWeP0kS+r0ASjXtqssMHi
+FZkCAwEAAaOByzCByDAdBgNVHQ4EFgQUP7OqE+GGlrPjjSDsvnBx0Bv4Z5owHwYD
+VR0jBBgwFoAUP7OqE+GGlrPjjSDsvnBx0Bv4Z5owNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCEmn1j+UTY
+LE6wJIavDLoOKTNnaH2iHUaZsPudZWna+EZn2cQwcutXeUroLXtX1MIYExnRNoxF
+n0kepoPFQUH9KaygEscPbqZFcGTDnbAiLu3AjWxowJTZuuAvWhwp7dDW7A67Qc4e
+45PEhYCqoWcxdoAkpHDs826jY4xx/ThlH1bpdXQVPGnz49Odmpx99gBxmGFoE3wj
+eeGEaKY9zhkcCmJI2flMkv+3W+gd5GYAUE04yDrj4Y6uqjIwZXgls9DrT96rnVFA
+fm/UFYfPQX2+PTJFovGofBGXkKTq2KrCtwg0o2IjS6Xjnk2Qf9dM3E/IrLK23kL9
+BZj2M5BUw2o/
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+FAIL
+-----BEGIN VERIFY_RESULT-----
+RkFJTA==
+-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 0
+ [Error] Unconsumed critical extension
+ oid: 2A0304
+ value: 01020304
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMAogICAgICBbRXJyb3JdIFVuY29uc3VtZWQgY3JpdGljYWwgZXh0ZW5zaW9uCiAgICAgICAgb2lkOiAyQTAzMDQKICAgICAgICB2YWx1ZTogMDEwMjAzMDQK
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/intermediate-unknown-non-critical-extension.pem b/chromium/net/data/verify_certificate_chain_unittest/intermediate-unknown-non-critical-extension.pem
new file mode 100644
index 00000000000..7c4e66447a3
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/intermediate-unknown-non-critical-extension.pem
@@ -0,0 +1,286 @@
+[Created by: generate-intermediate-unknown-non-critical-extension.py]
+
+Certificate chain with 1 intermediate and a trusted root. The intermediate
+has an unknown X.509v3 extension that is marked as non-critical. Verification
+is expected to succeed because although unrecognized, the extension is not
+critical.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b6:04:af:e9:58:68:65:f6:6e:cd:e3:fe:93:35:
+ d3:c0:06:53:75:df:15:59:23:d3:fd:42:8c:36:a1:
+ df:6b:35:3f:7d:63:57:e4:17:d9:2a:63:77:7f:d6:
+ f5:b0:85:00:70:ab:f9:5e:f3:00:4d:0f:5e:28:b8:
+ 56:7b:15:f1:4e:eb:32:e0:bf:e4:83:2b:49:ff:ac:
+ 3e:09:38:40:75:73:11:ee:0c:8c:d9:e6:c6:d2:44:
+ ce:99:74:78:8b:90:19:b5:32:75:45:ba:e0:76:55:
+ 5f:c9:44:27:e2:91:8e:9a:21:aa:3d:be:e7:cf:1e:
+ af:08:4b:b0:cc:03:b8:c6:2b:92:ae:d6:1e:61:fa:
+ 18:4e:b5:98:cc:0b:55:16:77:4c:9c:26:99:0f:3b:
+ 91:22:87:19:36:b9:4f:72:c9:40:bb:d0:2b:8e:d7:
+ c3:1b:eb:2e:e4:82:a8:0e:7d:45:a1:c7:6a:e9:db:
+ d2:f7:30:9b:ad:4f:a7:04:17:2b:78:85:15:1a:8f:
+ f1:77:6c:51:c0:a8:fc:53:70:f0:32:8c:86:09:8b:
+ 00:9c:3f:32:ff:cc:86:4f:4c:32:6a:f9:53:5d:36:
+ f9:55:34:8c:e4:0e:56:af:bf:f6:92:25:8a:4e:d5:
+ 66:53:66:7b:b0:16:08:04:d2:56:de:c6:b0:75:2c:
+ b5:d5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ A7:25:2F:78:CA:01:CA:68:1D:8F:FF:93:D6:FA:FA:A3:9C:BB:C8:0E
+ X509v3 Authority Key Identifier:
+ keyid:D5:16:02:7F:4F:D3:7F:21:1A:9D:CC:55:09:30:CF:EF:6C:08:1F:53
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 6a:e8:e9:eb:26:54:d4:51:72:d0:4d:a3:7c:e4:5e:8d:bd:c7:
+ 5e:0a:ab:46:a0:88:20:15:68:56:3f:43:0d:13:60:30:eb:65:
+ 86:45:5b:0d:8b:c4:b0:7f:2f:18:fe:27:a7:6e:4b:10:99:05:
+ 25:f8:4b:9a:80:a3:36:f6:35:5e:0a:dc:0a:81:3c:fc:be:32:
+ 71:fc:ed:8c:d9:77:ce:25:3c:74:af:b7:ad:50:ee:dc:fe:35:
+ 91:15:cc:79:91:f0:48:74:68:8b:a0:e2:70:95:df:1d:b3:e5:
+ c5:48:bc:9c:c3:4c:95:50:94:8d:3c:42:9a:13:e3:03:b3:df:
+ 43:32:bf:0f:cd:50:d9:2c:52:1c:30:9e:5f:30:02:69:66:bc:
+ e5:92:63:43:ca:62:e8:d2:ae:dd:2a:e1:ac:ce:00:f0:d7:54:
+ 81:6b:b8:1f:b1:0e:e7:57:2b:71:17:50:4b:fb:e4:f0:37:2a:
+ da:37:e2:80:4a:87:9b:d6:d5:6d:6b:b4:af:4b:43:c9:08:9d:
+ 57:f1:98:3c:2a:b6:58:7d:a8:83:d3:f0:b1:df:c5:bd:8b:0c:
+ a8:48:91:0c:c8:eb:29:f8:54:70:b0:49:b7:f4:e3:80:cc:2e:
+ 37:23:23:f4:49:21:8d:22:12:8c:3e:24:a2:11:66:15:cd:68:
+ 96:19:3b:5f
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2BK/p
+WGhl9m7N4/6TNdPABlN13xVZI9P9Qow2od9rNT99Y1fkF9kqY3d/1vWwhQBwq/le
+8wBND14ouFZ7FfFO6zLgv+SDK0n/rD4JOEB1cxHuDIzZ5sbSRM6ZdHiLkBm1MnVF
+uuB2VV/JRCfikY6aIao9vufPHq8IS7DMA7jGK5Ku1h5h+hhOtZjMC1UWd0ycJpkP
+O5Eihxk2uU9yyUC70CuO18Mb6y7kgqgOfUWhx2rp29L3MJutT6cEFyt4hRUaj/F3
+bFHAqPxTcPAyjIYJiwCcPzL/zIZPTDJq+VNdNvlVNIzkDlavv/aSJYpO1WZTZnuw
+FggE0lbexrB1LLXVAgMBAAGjgekwgeYwHQYDVR0OBBYEFKclL3jKAcpoHY//k9b6
++qOcu8gOMB8GA1UdIwQYMBaAFNUWAn9P038hGp3MVQkwz+9sCB9TMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAaujp6yZU1FFy0E2jfORe
+jb3HXgqrRqCIIBVoVj9DDRNgMOtlhkVbDYvEsH8vGP4np25LEJkFJfhLmoCjNvY1
+XgrcCoE8/L4ycfztjNl3ziU8dK+3rVDu3P41kRXMeZHwSHRoi6DicJXfHbPlxUi8
+nMNMlVCUjTxCmhPjA7PfQzK/D81Q2SxSHDCeXzACaWa85ZJjQ8pi6NKu3SrhrM4A
+8NdUgWu4H7EO51crcRdQS/vk8Dcq2jfigEqHm9bVbWu0r0tDyQidV/GYPCq2WH2o
+g9Pwsd/FvYsMqEiRDMjrKfhUcLBJt/TjgMwuNyMj9EkhjSISjD4kohFmFc1olhk7
+Xw==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:94:b0:d4:b6:63:20:79:6f:d7:5f:3e:0a:32:b1:
+ 79:0a:be:db:d4:86:23:8d:f8:17:0d:3e:b8:49:ed:
+ d3:6a:39:db:e4:16:6b:f6:c9:03:d6:0f:60:a0:ae:
+ 6c:86:18:2d:50:06:70:48:5f:9b:14:17:4d:2b:d5:
+ e4:e9:8c:19:0b:78:19:0e:d9:82:39:8f:92:f8:bc:
+ 7f:cc:7a:6e:06:7c:75:e3:7e:7e:24:71:7e:19:ba:
+ 64:2f:7b:60:e5:ab:c0:1a:9a:44:9d:a4:db:eb:d5:
+ 5b:69:31:ab:9f:86:9c:ec:90:2f:c2:29:ea:19:15:
+ fb:85:50:89:71:67:28:70:46:f7:e4:1e:6d:e6:81:
+ 49:15:7e:e9:2e:9f:14:d6:f9:02:c9:91:8f:d1:a9:
+ 65:8a:cc:29:57:7b:e5:a8:08:db:19:a6:27:2f:89:
+ 4b:e1:ca:3e:1e:c4:f6:65:4f:b0:26:c4:29:13:44:
+ 3f:6c:49:ba:b7:99:2c:70:0c:54:7b:c2:9a:06:ce:
+ 95:51:62:16:a3:0c:9e:2c:34:d0:04:65:32:41:d7:
+ db:6e:38:e9:12:8c:91:a5:0d:fe:b2:c6:b7:74:f4:
+ 23:65:d9:ae:88:af:0f:12:6a:28:f0:7b:db:2b:e4:
+ 6d:1b:74:de:93:e9:f6:72:f1:1c:28:8f:8a:32:37:
+ a2:65
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ D5:16:02:7F:4F:D3:7F:21:1A:9D:CC:55:09:30:CF:EF:6C:08:1F:53
+ X509v3 Authority Key Identifier:
+ keyid:99:38:AC:DE:DD:17:19:E4:9D:92:02:FD:01:4D:40:C5:2C:4E:B7:4A
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ 1.2.3.4:
+ ....
+ Signature Algorithm: sha256WithRSAEncryption
+ 0b:1e:08:36:25:d9:1b:97:a3:07:63:ca:17:a1:df:42:14:a5:
+ 6d:75:63:a8:ba:b5:94:b1:59:0b:5c:18:a7:e2:8f:a7:8b:40:
+ f0:0f:cf:4d:8d:87:a0:77:44:b3:0a:b6:b2:a2:aa:25:0e:a5:
+ cf:4b:6b:77:6e:e1:e2:06:19:0d:97:d9:a9:95:72:26:24:07:
+ e5:cd:8c:c8:e1:c5:1f:6c:8e:42:dd:93:da:4c:6e:07:e5:6e:
+ b2:e0:e6:c2:04:1d:1f:e0:4f:f0:5d:00:63:2c:ea:35:e3:dc:
+ c3:14:6d:8f:86:23:ab:a8:d1:29:81:98:1e:b7:fb:34:4c:65:
+ 18:27:fa:f5:5e:54:e6:3e:1e:b9:24:4c:86:cd:94:81:8d:60:
+ 49:d7:a7:a7:de:a5:4d:30:32:88:0a:95:a9:36:01:51:20:1e:
+ 2f:e2:1f:b8:fb:fb:14:77:9a:37:c3:96:21:e5:8b:96:a9:a0:
+ 97:24:b8:1c:f5:dd:a2:1b:bb:04:c4:f3:b0:22:56:38:cc:20:
+ e1:5b:51:90:7c:14:5c:5e:ce:df:b1:a9:57:a2:3b:d6:0f:56:
+ 3b:96:94:7e:c5:c7:a8:6e:eb:77:fe:50:1e:21:c8:0b:c2:3f:
+ 6f:48:d0:dd:d4:f5:29:39:3f:e1:a7:bd:c8:ba:35:d3:28:72:
+ 92:d4:e6:33
+-----BEGIN CERTIFICATE-----
+MIIDejCCAmKgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlLDUtmMg
+eW/XXz4KMrF5Cr7b1IYjjfgXDT64Se3Tajnb5BZr9skD1g9goK5shhgtUAZwSF+b
+FBdNK9Xk6YwZC3gZDtmCOY+S+Lx/zHpuBnx1435+JHF+GbpkL3tg5avAGppEnaTb
+69VbaTGrn4ac7JAvwinqGRX7hVCJcWcocEb35B5t5oFJFX7pLp8U1vkCyZGP0all
+iswpV3vlqAjbGaYnL4lL4co+HsT2ZU+wJsQpE0Q/bEm6t5kscAxUe8KaBs6VUWIW
+owyeLDTQBGUyQdfbbjjpEoyRpQ3+ssa3dPQjZdmuiK8PEmoo8HvbK+RtG3Tek+n2
+cvEcKI+KMjeiZQIDAQABo4HYMIHVMB0GA1UdDgQWBBTVFgJ/T9N/IRqdzFUJMM/v
+bAgfUzAfBgNVHSMEGDAWgBSZOKze3RcZ5J2SAv0BTUDFLE63SjA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wCwYDKgMEBAQBAgMEMA0GCSqG
+SIb3DQEBCwUAA4IBAQALHgg2Jdkbl6MHY8oXod9CFKVtdWOourWUsVkLXBin4o+n
+i0DwD89NjYegd0SzCrayoqolDqXPS2t3buHiBhkNl9mplXImJAflzYzI4cUfbI5C
+3ZPaTG4H5W6y4ObCBB0f4E/wXQBjLOo149zDFG2PhiOrqNEpgZget/s0TGUYJ/r1
+XlTmPh65JEyGzZSBjWBJ16en3qVNMDKICpWpNgFRIB4v4h+4+/sUd5o3w5Yh5YuW
+qaCXJLgc9d2iG7sExPOwIlY4zCDhW1GQfBRcXs7fsalXojvWD1Y7lpR+xceobut3
+/lAeIcgLwj9vSNDd1PUpOT/hp73IujXTKHKS1OYz
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:a3:83:87:29:55:0b:8e:0a:7e:d7:d3:74:4f:6c:
+ 58:a6:8c:5c:09:8d:13:65:8b:94:04:8e:52:13:93:
+ 9e:8c:75:2b:37:f7:9f:ca:64:92:f2:42:e9:8d:d6:
+ 36:19:ab:14:e4:f3:76:16:65:68:3d:3b:51:eb:e5:
+ d0:33:af:8e:26:5b:f2:5c:4e:3d:7e:11:46:b6:2a:
+ 6d:fd:3a:54:57:91:8b:6c:e1:fb:8b:08:b8:80:d3:
+ 0d:2d:d0:b8:2e:1e:f0:b3:33:c5:15:0b:b0:ad:de:
+ 27:68:a4:3d:3b:6c:8d:4c:a6:d0:5c:7e:58:52:01:
+ 8f:fe:fb:86:5e:ce:ea:fc:33:77:28:c5:4c:ee:d0:
+ 0b:cb:a7:97:7f:05:70:53:a3:61:06:fa:b3:9d:7e:
+ d5:dd:3f:ef:58:04:f8:3c:91:fc:8d:fa:ca:cd:97:
+ a4:3b:44:ac:dd:64:a7:32:08:87:0f:73:36:d7:14:
+ e0:1d:b8:29:11:97:cb:9d:79:1f:bc:c8:cc:28:ae:
+ 8e:9a:2f:39:62:1f:28:aa:b9:c7:81:7c:34:96:44:
+ 39:e6:00:4b:5b:0e:4b:7a:fd:ca:bf:5d:67:50:91:
+ 3a:59:89:1b:3a:12:7c:7e:b9:58:54:e5:4f:97:00:
+ 35:c8:a7:b9:fd:3f:5e:08:5e:ac:0c:ba:61:e8:42:
+ 34:33
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 99:38:AC:DE:DD:17:19:E4:9D:92:02:FD:01:4D:40:C5:2C:4E:B7:4A
+ X509v3 Authority Key Identifier:
+ keyid:99:38:AC:DE:DD:17:19:E4:9D:92:02:FD:01:4D:40:C5:2C:4E:B7:4A
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 47:a7:24:e7:1f:29:34:d7:8e:3a:e1:af:aa:d3:3b:32:f4:d6:
+ 7d:ec:ab:7c:34:59:0b:b1:33:80:6a:d4:36:4a:78:d3:3a:d6:
+ 97:0d:8b:81:54:09:91:b5:30:79:78:e7:52:11:ba:e8:57:af:
+ f3:f8:f0:ff:17:9a:e3:d0:a0:89:81:50:e8:67:47:9b:b5:68:
+ ed:99:10:1b:d6:31:58:24:dd:74:3c:8b:76:77:46:a3:b9:ca:
+ b6:4b:3d:ca:b9:5b:ac:e7:92:8c:d3:f2:4a:ba:4b:2f:c6:11:
+ cf:38:15:59:5a:fa:2d:d2:72:31:8f:54:a4:7e:44:a7:26:9d:
+ 1b:38:e0:ac:75:72:9c:71:4c:78:54:80:8f:74:b7:11:b0:5c:
+ c7:69:a5:03:1e:cd:5e:c5:cd:60:0e:80:32:19:02:e0:8c:b4:
+ 76:e7:00:a1:e5:bc:29:31:61:a6:55:f0:72:92:78:69:6f:26:
+ 08:96:71:b9:42:a9:eb:cc:54:8e:d6:55:1a:26:2c:a0:b5:a6:
+ df:52:86:a1:df:26:da:26:86:d5:17:5b:c9:9b:90:c0:6c:ab:
+ 23:1a:82:2d:ff:b6:83:ae:3c:c1:c3:85:5e:49:aa:d6:ef:fd:
+ f4:4a:22:7c:90:b8:46:2e:15:63:93:0c:c5:2d:9e:f6:32:03:
+ 53:10:30:36
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKODhylVC44KftfTdE9s
+WKaMXAmNE2WLlASOUhOTnox1Kzf3n8pkkvJC6Y3WNhmrFOTzdhZlaD07Uevl0DOv
+jiZb8lxOPX4RRrYqbf06VFeRi2zh+4sIuIDTDS3QuC4e8LMzxRULsK3eJ2ikPTts
+jUym0Fx+WFIBj/77hl7O6vwzdyjFTO7QC8unl38FcFOjYQb6s51+1d0/71gE+DyR
+/I36ys2XpDtErN1kpzIIhw9zNtcU4B24KRGXy515H7zIzCiujpovOWIfKKq5x4F8
+NJZEOeYAS1sOS3r9yr9dZ1CROlmJGzoSfH65WFTlT5cANcinuf0/XgherAy6YehC
+NDMCAwEAAaOByzCByDAdBgNVHQ4EFgQUmTis3t0XGeSdkgL9AU1AxSxOt0owHwYD
+VR0jBBgwFoAUmTis3t0XGeSdkgL9AU1AxSxOt0owNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBHpyTnHyk0
+14464a+q0zsy9NZ97Kt8NFkLsTOAatQ2SnjTOtaXDYuBVAmRtTB5eOdSEbroV6/z
++PD/F5rj0KCJgVDoZ0ebtWjtmRAb1jFYJN10PIt2d0ajucq2Sz3KuVus55KM0/JK
+uksvxhHPOBVZWvot0nIxj1SkfkSnJp0bOOCsdXKccUx4VICPdLcRsFzHaaUDHs1e
+xc1gDoAyGQLgjLR25wCh5bwpMWGmVfByknhpbyYIlnG5QqnrzFSO1lUaJiygtabf
+Uoah3ybaJobVF1vJm5DAbKsjGoIt/7aDrjzBw4VeSarW7/30SiJ8kLhGLhVjkwzF
+LZ72MgNTEDA2
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/issuer-and-subject-not-byte-for-byte-equal-anchor.pem b/chromium/net/data/verify_certificate_chain_unittest/issuer-and-subject-not-byte-for-byte-equal-anchor.pem
index f4c1086a8de..6ecd8bb41c9 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/issuer-and-subject-not-byte-for-byte-equal-anchor.pem
+++ b/chromium/net/data/verify_certificate_chain_unittest/issuer-and-subject-not-byte-for-byte-equal-anchor.pem
@@ -253,7 +253,7 @@ Certificate:
36:8b:f6:6c:f7:61:b9:08:ee:30:ad:1a:a8:44:f1:2e:32:ec:
83:a2:48:48:3a:67:5f:e9:6f:1b:17:33:08:2a:c1:c9:c3:67:
9a:0e:85:67
------BEGIN TRUSTED_CERTIFICATE-----
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
MIIDijCCAnKgAwIBAgIQRfjg5AHFPnHmvXFtl5xBIzANBgkqhkiG9w0BAQUFADBPMQswCQYDVQQ
GEwJLUjEcMBoGA1UEChMTR292ZXJubWVudCBvZiBLb3JlYTENMAsGA1UECxMER1BLSTETMBEGA1
UEAxMKR1BLSVJvb3RDQTAeFw0wNzAzMTUwNjAwMDRaFw0xNzAzMTUwNjAwMDRaME8xCzAJBgNVB
@@ -271,7 +271,7 @@ U4E+EkraqIqj9MaczSMlb9hPYFhbrHz+lTgaTOtkGZTCW+o0G26Ea9Cv6D2jwwSt8nQXXCUI70i
+RkPwOazhbsnWpV5xXZPWYIKT/1DAE5M4fkMkvwd9aVrjLqqq0v+u49yJKTcE19GW9eLxveBtWO
oHoDfXCpRcw041Xd8ulwUyxMN00uKuSCiICNov2bPdhuQjuMK0aqETxLjLsg6JISDpnX+lvGxcz
CCrBycNnmg6FZw==
------END TRUSTED_CERTIFICATE-----
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
-----BEGIN TIME-----
MTIwNTAyMDQ1ODU0Wg==
diff --git a/chromium/net/data/verify_certificate_chain_unittest/issuer-and-subject-not-byte-for-byte-equal.pem b/chromium/net/data/verify_certificate_chain_unittest/issuer-and-subject-not-byte-for-byte-equal.pem
index 631061037a9..1611b2f1bc4 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/issuer-and-subject-not-byte-for-byte-equal.pem
+++ b/chromium/net/data/verify_certificate_chain_unittest/issuer-and-subject-not-byte-for-byte-equal.pem
@@ -423,7 +423,7 @@ Certificate:
e9:b8:c9:66:f4:db:26:f3:3a:a4:74:f2:49:24:5b:c9:b0:d0:
57:c1:fa:3e:7a:e1:97:c9
------BEGIN TRUSTED_CERTIFICATE-----
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRU
wEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHh
cNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU
@@ -451,7 +451,7 @@ id392qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG
2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPI
vSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0F
fB+j564ZfJ
------END TRUSTED_CERTIFICATE-----
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
-----BEGIN TIME-----
MTMwNTIwMTUxODMzWg==
diff --git a/chromium/net/data/verify_certificate_chain_unittest/key-rollover-longrolloverchain.pem b/chromium/net/data/verify_certificate_chain_unittest/key-rollover-longrolloverchain.pem
new file mode 100644
index 00000000000..7446d9f4a2d
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/key-rollover-longrolloverchain.pem
@@ -0,0 +1,491 @@
+[Created by: generate-key-rollover.py]
+
+A certificate tree with two self-signed root certificates(oldroot, newroot),
+and a third root certificate (newrootrollover) which has the same key as newroot
+but is signed by oldroot, all with the same subject and issuer.
+There are two intermediates with the same key, subject and issuer
+(oldintermediate signed by oldroot, and newintermediate signed by newroot).
+The target certificate is signed by the intermediate key.
+
+
+In graphical form:
+
+ oldroot-------->newrootrollover newroot
+ | | |
+ v v v
+oldintermediate newintermediate
+ | |
+ +------------+-------------+
+ |
+ v
+ target
+
+
+Several chains are output:
+ key-rollover-oldchain.pem:
+ target<-oldintermediate<-oldroot
+ key-rollover-rolloverchain.pem:
+ target<-newintermediate<-newrootrollover<-oldroot
+ key-rollover-longrolloverchain.pem:
+ target<-newintermediate<-newroot<-newrootrollover<-oldroot
+ key-rollover-newchain.pem:
+ target<-newintermediate<-newroot
+
+All of these chains should verify successfully.
+
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d0:14:31:90:c4:c6:d0:b9:10:9e:e4:7a:e2:bc:
+ 16:ab:d2:5e:d7:3d:00:11:bf:25:0b:32:17:57:c4:
+ fb:f6:60:0d:5a:7c:43:08:88:e6:35:f7:39:0f:dc:
+ d7:ef:22:18:52:5b:de:27:35:10:93:ab:c0:ae:98:
+ 1b:e1:c7:40:a8:be:84:2a:e6:69:7c:c4:68:1e:c4:
+ 0d:29:97:55:12:fb:30:86:a3:8f:03:0c:d4:4b:22:
+ 76:ac:a8:db:fd:20:4c:46:ea:21:9b:59:4f:ea:9c:
+ 20:6f:ff:e1:7c:7d:64:5c:4b:91:4d:ac:56:1d:19:
+ 12:6c:af:f2:99:40:21:9d:06:b9:a2:90:2c:7b:bc:
+ af:fe:c0:40:a1:06:89:62:f3:f3:fd:a0:07:61:aa:
+ c2:f9:e1:0e:13:96:92:ac:53:ba:ed:a5:36:c9:b9:
+ 04:e7:13:67:bc:0e:63:dc:22:29:53:e2:e3:59:ab:
+ 5c:25:cd:d9:fb:46:4e:91:70:dd:41:4b:35:87:a4:
+ fd:2c:66:be:75:7e:03:e9:12:61:66:cb:19:88:a1:
+ 61:b7:13:b4:ab:51:a6:d5:58:9c:db:8c:a2:1a:da:
+ c3:6f:cb:b6:b1:65:d8:a3:a3:d1:87:d8:b9:bb:b8:
+ c1:83:f1:83:38:2a:fd:a3:f6:a6:59:f2:27:f1:e3:
+ 50:29
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 01:D0:19:F4:6B:86:BC:17:3B:FB:74:95:0F:53:BD:BD:4E:CA:10:D6
+ X509v3 Authority Key Identifier:
+ keyid:D3:97:C6:F7:B9:E5:17:69:6D:78:39:77:3A:0A:AD:32:2D:40:AC:07
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 0e:b6:ad:85:34:3d:cf:9c:2f:8c:e7:90:80:33:f6:12:99:40:
+ 6d:89:7b:5c:08:c9:a9:fc:40:24:1e:14:ac:6c:6a:11:aa:3e:
+ ea:c1:19:32:75:67:26:fe:c0:f9:55:e9:b6:04:74:c9:e3:22:
+ 59:3a:06:5a:5f:25:6d:1d:df:48:62:a4:ee:d0:87:df:20:9d:
+ 9c:95:aa:4e:77:05:28:e6:66:ac:ae:23:e4:74:df:5a:b4:21:
+ e7:3d:0f:95:61:84:11:7e:d8:72:66:dd:85:c7:41:fe:44:12:
+ da:4c:c7:1b:ab:7d:4b:3d:c4:38:2d:b9:54:8a:26:1e:76:1b:
+ f6:0b:8a:e9:fa:9f:0a:e6:cc:6d:c5:55:f1:a5:29:20:42:05:
+ d4:5a:4f:27:ab:b6:e4:c4:ea:4d:8b:97:53:67:03:75:32:1f:
+ 9d:1e:b8:72:e1:c4:5a:09:15:d7:ce:a3:59:ed:cc:4d:0f:ea:
+ c0:1d:57:1a:43:d7:7a:63:86:b0:b8:5c:4f:34:29:a4:be:90:
+ c4:6b:39:20:c9:25:96:7d:a1:cc:ee:f7:57:04:69:d7:21:66:
+ 1d:cc:4e:6c:10:1a:6e:87:11:f3:e3:ae:9e:5b:64:04:ee:ac:
+ c6:0a:24:80:e4:0a:0e:89:49:9d:0f:1d:74:b2:f6:db:7e:25:
+ a1:d0:6e:7e
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQFDGQ
+xMbQuRCe5HrivBar0l7XPQARvyULMhdXxPv2YA1afEMIiOY19zkP3NfvIhhSW94n
+NRCTq8CumBvhx0CovoQq5ml8xGgexA0pl1US+zCGo48DDNRLInasqNv9IExG6iGb
+WU/qnCBv/+F8fWRcS5FNrFYdGRJsr/KZQCGdBrmikCx7vK/+wEChBoli8/P9oAdh
+qsL54Q4TlpKsU7rtpTbJuQTnE2e8DmPcIilT4uNZq1wlzdn7Rk6RcN1BSzWHpP0s
+Zr51fgPpEmFmyxmIoWG3E7SrUabVWJzbjKIa2sNvy7axZdijo9GH2Lm7uMGD8YM4
+Kv2j9qZZ8ifx41ApAgMBAAGjgekwgeYwHQYDVR0OBBYEFAHQGfRrhrwXO/t0lQ9T
+vb1OyhDWMB8GA1UdIwQYMBaAFNOXxve55RdpbXg5dzoKrTItQKwHMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEADrathTQ9z5wvjOeQgDP2
+EplAbYl7XAjJqfxAJB4UrGxqEao+6sEZMnVnJv7A+VXptgR0yeMiWToGWl8lbR3f
+SGKk7tCH3yCdnJWqTncFKOZmrK4j5HTfWrQh5z0PlWGEEX7YcmbdhcdB/kQS2kzH
+G6t9Sz3EOC25VIomHnYb9guK6fqfCubMbcVV8aUpIEIF1FpPJ6u25MTqTYuXU2cD
+dTIfnR64cuHEWgkV186jWe3MTQ/qwB1XGkPXemOGsLhcTzQppL6QxGs5IMklln2h
+zO73VwRp1yFmHcxObBAabocR8+OunltkBO6sxgokgOQKDolJnQ8ddLL2234lodBu
+fg==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 4 (0x4)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 2 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:bf:ca:00:55:10:61:e4:0e:a3:f8:57:b8:7b:19:
+ 34:5a:77:b8:06:39:88:07:0c:ec:d0:3b:4a:53:02:
+ 3c:d1:d3:da:48:ae:8a:1a:1c:3d:30:bb:b3:36:80:
+ a1:6f:cd:32:fd:54:26:b9:77:d7:1e:11:30:6c:eb:
+ d7:11:9a:d9:af:54:7e:0e:37:c3:8d:f3:0a:5d:ec:
+ 82:d6:6e:f3:46:f4:2a:82:24:e4:28:38:c2:fa:6a:
+ a6:f7:38:cd:94:50:20:bd:ee:50:9e:3a:a3:40:1a:
+ 49:77:eb:b2:05:8c:01:46:e6:ef:8f:55:91:0a:7a:
+ 44:10:62:b8:9f:3e:81:31:ae:08:95:29:37:47:53:
+ ec:f3:c7:9c:f0:be:64:70:b3:81:f0:04:f4:a4:aa:
+ 41:ad:16:8f:13:31:af:9b:eb:55:dc:93:6d:56:cf:
+ d6:f0:0a:fb:11:9e:32:59:d4:07:28:e1:fe:60:73:
+ bf:43:bf:ff:c9:dc:f2:ca:3a:e1:0c:bd:90:0b:c2:
+ ab:91:d5:2e:72:5d:5e:f0:f8:45:7b:3d:37:89:d1:
+ 16:bd:9b:4f:c9:c4:34:c7:c4:23:a4:04:4b:13:db:
+ 1a:b5:82:d0:f6:cd:99:fe:f3:0d:98:81:65:5e:2f:
+ 9e:a4:c1:5b:2b:67:b5:07:2a:24:a6:e7:06:5f:49:
+ d6:d5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ D3:97:C6:F7:B9:E5:17:69:6D:78:39:77:3A:0A:AD:32:2D:40:AC:07
+ X509v3 Authority Key Identifier:
+ keyid:64:90:93:CD:AC:C7:37:36:4D:6B:14:D6:67:D0:54:3A:59:45:3A:FC
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ d2:35:f4:84:23:56:e3:2f:d1:54:fa:eb:85:02:e1:b7:aa:94:
+ a9:73:95:1d:29:9a:35:64:ac:4a:28:a3:87:24:e1:cd:3e:9f:
+ 53:14:92:ce:86:d6:ae:d5:3f:1d:97:59:ae:c4:1c:ae:78:29:
+ d7:45:a5:14:58:b6:ac:28:3e:20:e6:27:56:22:b2:bf:80:24:
+ 8d:bd:ef:17:67:8f:59:74:8b:7e:41:f1:fc:4d:a8:7b:d4:cf:
+ 0c:ec:41:c6:7a:2b:fc:c3:c2:92:dc:49:f6:7a:3d:bd:b0:41:
+ 0c:d3:0c:dd:58:1a:42:62:80:10:ad:95:ec:a0:8a:cb:b4:b8:
+ 8e:5d:45:c7:d2:82:4b:eb:cb:1a:0e:f5:40:46:0d:dd:35:a3:
+ 9b:d1:3e:55:95:b1:ab:96:63:31:ac:01:b4:ef:20:bc:0d:86:
+ 88:b2:e5:94:64:6b:f1:1a:73:3e:09:b0:4c:57:87:3a:65:5a:
+ 84:17:af:1c:cd:a5:4e:72:8e:19:8b:50:0a:97:4b:df:69:2c:
+ 4c:21:d4:d1:7e:81:74:94:60:5b:b0:5e:56:53:14:b4:52:3d:
+ c9:45:a5:47:10:74:15:86:a0:52:ba:ff:b5:32:01:ef:dd:0e:
+ 17:d6:73:35:aa:1e:ca:9a:8b:2e:28:cf:fa:1b:79:be:a7:87:
+ 4b:b4:0a:26
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBBDANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMjEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv8oAVRBh
+5A6j+Fe4exk0Wne4BjmIBwzs0DtKUwI80dPaSK6KGhw9MLuzNoChb80y/VQmuXfX
+HhEwbOvXEZrZr1R+DjfDjfMKXeyC1m7zRvQqgiTkKDjC+mqm9zjNlFAgve5Qnjqj
+QBpJd+uyBYwBRubvj1WRCnpEEGK4nz6BMa4IlSk3R1Ps88ec8L5kcLOB8AT0pKpB
+rRaPEzGvm+tV3JNtVs/W8Ar7EZ4yWdQHKOH+YHO/Q7//ydzyyjrhDL2QC8KrkdUu
+cl1e8PhFez03idEWvZtPycQ0x8QjpARLE9satYLQ9s2Z/vMNmIFlXi+epMFbK2e1
+ByokpucGX0nW1QIDAQABo4HLMIHIMB0GA1UdDgQWBBTTl8b3ueUXaW14OXc6Cq0y
+LUCsBzAfBgNVHSMEGDAWgBRkkJPNrMc3Nk1rFNZn0FQ6WUU6/DA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+ANI19IQjVuMv0VT664UC4beqlKlzlR0pmjVkrEooo4ck4c0+n1MUks6G1q7VPx2X
+Wa7EHK54KddFpRRYtqwoPiDmJ1Yisr+AJI297xdnj1l0i35B8fxNqHvUzwzsQcZ6
+K/zDwpLcSfZ6Pb2wQQzTDN1YGkJigBCtleygisu0uI5dRcfSgkvryxoO9UBGDd01
+o5vRPlWVsauWYzGsAbTvILwNhoiy5ZRka/Eacz4JsExXhzplWoQXrxzNpU5yjhmL
+UAqXS99pLEwh1NF+gXSUYFuwXlZTFLRSPclFpUcQdBWGoFK6/7UyAe/dDhfWczWq
+Hsqaiy4oz/obeb6nh0u0CiY=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 3 (0x3)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 2 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ea:cc:2d:c4:88:54:07:90:da:62:ef:77:23:b2:
+ 83:c9:54:06:25:70:65:43:f2:29:a3:f3:22:f2:09:
+ 92:31:25:77:79:63:4a:7f:d8:e5:1f:16:1a:25:bc:
+ d4:4b:9a:b3:a0:61:7e:c3:a5:90:32:97:5a:5b:59:
+ cf:97:d6:ac:2c:86:a7:70:ed:2d:e0:bf:e8:44:6f:
+ 41:29:55:b0:40:a8:10:d6:4d:67:2b:01:1f:7a:33:
+ 2b:ce:8f:c8:fb:54:99:e2:11:2d:75:7d:ff:f5:fb:
+ 53:e5:6b:7e:ca:b8:fc:1f:bc:8f:32:29:6d:d2:6b:
+ a1:9b:d9:7f:b2:f6:e9:18:72:fe:45:a2:23:dc:bf:
+ 5d:1e:43:5d:2b:80:2a:71:b4:cb:67:30:cc:aa:54:
+ 76:fc:4b:a3:2b:ab:99:31:66:bf:5c:09:44:e6:c9:
+ 27:42:3a:58:b5:fd:db:06:0f:11:04:0d:2d:36:4a:
+ 02:d5:50:4d:4d:7c:ed:a4:51:49:e3:fe:44:54:30:
+ 84:b6:1f:54:28:1f:9e:41:b2:20:23:75:e5:d4:e4:
+ bf:79:a6:ab:84:aa:dc:56:38:cf:2c:d3:8e:13:48:
+ 43:5a:eb:eb:3b:a0:36:d5:89:0c:68:e2:fb:8f:3a:
+ 82:ad:01:4b:f8:bb:b0:2e:3d:b7:6e:91:a3:70:9a:
+ d0:41
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 64:90:93:CD:AC:C7:37:36:4D:6B:14:D6:67:D0:54:3A:59:45:3A:FC
+ X509v3 Authority Key Identifier:
+ keyid:64:90:93:CD:AC:C7:37:36:4D:6B:14:D6:67:D0:54:3A:59:45:3A:FC
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 77:d8:b1:3b:e5:c4:ce:c7:37:c6:fa:d7:a7:a1:cf:66:0e:19:
+ 49:ea:06:f2:ec:8d:92:7d:e2:de:43:32:22:55:b4:84:f5:30:
+ bb:44:91:c1:81:2a:aa:ae:e1:3c:86:17:20:28:15:a1:d0:dc:
+ ce:7c:62:67:4e:d5:a8:e0:e3:44:91:af:96:24:58:0d:eb:26:
+ 1f:42:37:82:de:d6:84:40:36:c7:78:7d:6c:f7:fa:54:a0:70:
+ d0:b9:41:a8:f2:3b:19:f1:cc:36:97:69:78:66:3c:ad:03:1e:
+ 70:e7:81:23:11:d6:98:d7:ba:e5:98:d8:12:c7:4b:1d:5b:b1:
+ cd:91:5c:49:f0:d3:99:dd:9e:ab:db:7b:32:f6:8c:be:fe:0b:
+ 2b:1e:96:8d:6e:7e:4a:69:71:f3:b6:f7:44:5f:a1:2f:62:67:
+ f0:55:b0:a2:d1:db:7f:58:3b:10:05:4f:e1:00:9d:45:4f:5d:
+ 1e:b8:a8:83:bd:33:bd:14:07:34:23:5e:99:bb:16:3e:ee:de:
+ 84:96:53:bf:29:e7:a5:52:a9:b6:6a:76:db:a6:ee:45:34:3f:
+ f7:48:d8:8a:12:46:c6:6c:ba:31:85:e8:45:07:85:23:37:85:
+ ff:15:de:0b:a8:97:40:60:11:9d:20:a8:fc:53:38:66:ea:9e:
+ d4:1b:9f:34
+-----BEGIN CERTIFICATE-----
+MIIDZTCCAk2gAwIBAgIBAzANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMjEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOrMLcSIVAeQ2mLvdyOy
+g8lUBiVwZUPyKaPzIvIJkjEld3ljSn/Y5R8WGiW81Euas6BhfsOlkDKXWltZz5fW
+rCyGp3DtLeC/6ERvQSlVsECoENZNZysBH3ozK86PyPtUmeIRLXV9//X7U+Vrfsq4
+/B+8jzIpbdJroZvZf7L26Rhy/kWiI9y/XR5DXSuAKnG0y2cwzKpUdvxLoyurmTFm
+v1wJRObJJ0I6WLX92wYPEQQNLTZKAtVQTU187aRRSeP+RFQwhLYfVCgfnkGyICN1
+5dTkv3mmq4Sq3FY4zyzTjhNIQ1rr6zugNtWJDGji+486gq0BS/i7sC49t26Ro3Ca
+0EECAwEAAaOByzCByDAdBgNVHQ4EFgQUZJCTzazHNzZNaxTWZ9BUOllFOvwwHwYD
+VR0jBBgwFoAUZJCTzazHNzZNaxTWZ9BUOllFOvwwNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB32LE75cTO
+xzfG+tenoc9mDhlJ6gby7I2SfeLeQzIiVbSE9TC7RJHBgSqqruE8hhcgKBWh0NzO
+fGJnTtWo4ONEka+WJFgN6yYfQjeC3taEQDbHeH1s9/pUoHDQuUGo8jsZ8cw2l2l4
+ZjytAx5w54EjEdaY17rlmNgSx0sdW7HNkVxJ8NOZ3Z6r23sy9oy+/gsrHpaNbn5K
+aXHztvdEX6EvYmfwVbCi0dt/WDsQBU/hAJ1FT10euKiDvTO9FAc0I16ZuxY+7t6E
+llO/KeelUqm2anbbpu5FND/3SNiKEkbGbLoxhehFB4UjN4X/Fd4LqJdAYBGdIKj8
+Uzhm6p7UG580
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 5 (0x5)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 2 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ea:cc:2d:c4:88:54:07:90:da:62:ef:77:23:b2:
+ 83:c9:54:06:25:70:65:43:f2:29:a3:f3:22:f2:09:
+ 92:31:25:77:79:63:4a:7f:d8:e5:1f:16:1a:25:bc:
+ d4:4b:9a:b3:a0:61:7e:c3:a5:90:32:97:5a:5b:59:
+ cf:97:d6:ac:2c:86:a7:70:ed:2d:e0:bf:e8:44:6f:
+ 41:29:55:b0:40:a8:10:d6:4d:67:2b:01:1f:7a:33:
+ 2b:ce:8f:c8:fb:54:99:e2:11:2d:75:7d:ff:f5:fb:
+ 53:e5:6b:7e:ca:b8:fc:1f:bc:8f:32:29:6d:d2:6b:
+ a1:9b:d9:7f:b2:f6:e9:18:72:fe:45:a2:23:dc:bf:
+ 5d:1e:43:5d:2b:80:2a:71:b4:cb:67:30:cc:aa:54:
+ 76:fc:4b:a3:2b:ab:99:31:66:bf:5c:09:44:e6:c9:
+ 27:42:3a:58:b5:fd:db:06:0f:11:04:0d:2d:36:4a:
+ 02:d5:50:4d:4d:7c:ed:a4:51:49:e3:fe:44:54:30:
+ 84:b6:1f:54:28:1f:9e:41:b2:20:23:75:e5:d4:e4:
+ bf:79:a6:ab:84:aa:dc:56:38:cf:2c:d3:8e:13:48:
+ 43:5a:eb:eb:3b:a0:36:d5:89:0c:68:e2:fb:8f:3a:
+ 82:ad:01:4b:f8:bb:b0:2e:3d:b7:6e:91:a3:70:9a:
+ d0:41
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 64:90:93:CD:AC:C7:37:36:4D:6B:14:D6:67:D0:54:3A:59:45:3A:FC
+ X509v3 Authority Key Identifier:
+ keyid:5D:A1:03:3D:8F:13:F9:08:AF:1E:83:6C:BC:DE:6F:A3:B5:C2:1A:EA
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 08:18:04:78:4e:5e:99:54:0e:de:99:06:87:4d:3f:7b:98:bc:
+ ac:92:ec:e2:60:54:35:c8:65:68:09:3d:8d:d9:23:ed:c3:f3:
+ 7b:fd:8a:60:fb:8b:dc:66:96:3f:69:81:5b:7c:cd:1d:cd:44:
+ 8d:3a:93:e4:18:94:c4:a8:56:6a:fd:ea:07:ce:b1:a0:05:b2:
+ cd:fd:bf:05:e6:52:2b:26:36:9d:e2:f2:25:f2:c8:27:5b:52:
+ 13:c6:3e:55:5b:72:58:34:a1:1c:5b:17:15:69:b1:82:78:a8:
+ 6b:80:81:cc:73:40:5b:c0:ad:de:a8:ec:53:4f:72:f0:1b:a6:
+ d4:ea:e6:c0:35:96:df:ef:38:15:c5:0e:e9:92:22:c4:97:0d:
+ d5:37:6f:7e:af:1f:6e:53:45:1e:3e:21:8c:25:d3:4c:aa:0d:
+ 5b:08:e1:5f:aa:dc:49:1c:84:b3:30:21:ea:b6:9c:95:d4:16:
+ 1c:9a:0b:17:47:a1:8c:7d:04:a0:e5:df:7d:e7:69:b7:81:2d:
+ 31:09:9b:ae:da:b2:1d:13:36:ad:f1:19:7e:92:6a:1b:70:01:
+ 8b:ee:88:5e:54:56:d6:dd:6e:78:b1:53:06:89:3b:e3:7e:45:
+ 2c:b5:9c:c9:92:5a:0d:c2:85:d0:e1:89:20:94:c7:ef:3c:01:
+ ab:25:5c:4b
+-----BEGIN CERTIFICATE-----
+MIIDZTCCAk2gAwIBAgIBBTANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMjEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOrMLcSIVAeQ2mLvdyOy
+g8lUBiVwZUPyKaPzIvIJkjEld3ljSn/Y5R8WGiW81Euas6BhfsOlkDKXWltZz5fW
+rCyGp3DtLeC/6ERvQSlVsECoENZNZysBH3ozK86PyPtUmeIRLXV9//X7U+Vrfsq4
+/B+8jzIpbdJroZvZf7L26Rhy/kWiI9y/XR5DXSuAKnG0y2cwzKpUdvxLoyurmTFm
+v1wJRObJJ0I6WLX92wYPEQQNLTZKAtVQTU187aRRSeP+RFQwhLYfVCgfnkGyICN1
+5dTkv3mmq4Sq3FY4zyzTjhNIQ1rr6zugNtWJDGji+486gq0BS/i7sC49t26Ro3Ca
+0EECAwEAAaOByzCByDAdBgNVHQ4EFgQUZJCTzazHNzZNaxTWZ9BUOllFOvwwHwYD
+VR0jBBgwFoAUXaEDPY8T+QivHoNsvN5vo7XCGuowNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAIGAR4Tl6Z
+VA7emQaHTT97mLyskuziYFQ1yGVoCT2N2SPtw/N7/Ypg+4vcZpY/aYFbfM0dzUSN
+OpPkGJTEqFZq/eoHzrGgBbLN/b8F5lIrJjad4vIl8sgnW1ITxj5VW3JYNKEcWxcV
+abGCeKhrgIHMc0BbwK3eqOxTT3LwG6bU6ubANZbf7zgVxQ7pkiLElw3VN29+rx9u
+U0UePiGMJdNMqg1bCOFfqtxJHISzMCHqtpyV1BYcmgsXR6GMfQSg5d9952m3gS0x
+CZuu2rIdEzat8Rl+kmobcAGL7oheVFbW3W54sVMGiTvjfkUstZzJkloNwoXQ4Ykg
+lMfvPAGrJVxL
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:a7:67:cf:1d:f5:54:e9:96:54:bc:65:8c:b7:9e:
+ 72:39:05:68:3d:44:e5:93:d8:4b:61:b1:a4:b4:b4:
+ 4c:c6:a0:92:b6:4d:06:3a:5b:b2:0a:8a:27:cb:b1:
+ e7:c3:35:47:ef:ac:2d:a7:d0:9c:b2:50:6a:58:3d:
+ 12:a4:85:dc:77:a9:08:e5:f4:1f:c0:ef:00:51:cd:
+ 68:62:d5:e5:cc:01:be:be:42:8b:35:fb:00:9c:30:
+ 84:0c:d7:35:7d:88:d1:1b:43:78:19:79:aa:06:b3:
+ ac:5c:69:a0:23:f0:69:dc:89:59:97:05:df:01:ae:
+ 5b:8f:01:a0:78:4f:05:4e:36:ac:00:b4:8d:e8:79:
+ 05:07:f2:76:a4:63:3f:95:21:06:57:61:a9:f0:43:
+ 04:d1:92:d3:9d:bb:b3:8f:5b:ef:ab:81:a0:23:11:
+ 38:b5:02:b2:95:1d:ac:da:b8:36:60:d7:d7:01:6d:
+ e8:ed:32:21:b4:84:97:33:7c:67:88:0e:44:c7:12:
+ 87:85:6a:49:80:82:cb:1e:16:2b:2f:6d:98:82:a0:
+ a0:30:cc:55:df:93:65:e0:9a:08:24:8a:47:cc:69:
+ 53:3c:b7:62:fa:df:11:64:d0:3f:52:43:80:f8:cf:
+ 7b:6f:d0:65:20:fb:22:d0:43:ca:fc:fc:0f:bd:1c:
+ 42:b9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 5D:A1:03:3D:8F:13:F9:08:AF:1E:83:6C:BC:DE:6F:A3:B5:C2:1A:EA
+ X509v3 Authority Key Identifier:
+ keyid:5D:A1:03:3D:8F:13:F9:08:AF:1E:83:6C:BC:DE:6F:A3:B5:C2:1A:EA
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 7f:ec:13:f0:46:53:d5:75:08:a5:37:44:9c:47:19:9e:05:ef:
+ d6:30:68:1e:0b:c8:3c:84:93:51:36:25:48:60:56:d4:79:1f:
+ b6:2c:91:e3:6f:61:f9:e7:7d:c8:b6:7b:70:7f:27:6d:2c:38:
+ ec:73:e4:8c:86:f4:48:8e:1b:09:0d:9f:f8:5a:1f:95:ed:f1:
+ 03:ea:99:64:d6:2d:46:4e:b8:0b:67:10:98:8e:19:2e:31:e1:
+ e3:d6:fe:7c:97:e9:a3:7a:18:25:9c:d4:4f:ce:a9:11:1d:f0:
+ 53:32:8a:e8:8e:8d:80:fb:f1:c1:c1:6a:c1:cf:d2:36:a2:b1:
+ f9:32:9e:05:fd:73:1a:b9:37:e5:55:b2:1e:78:84:a5:04:45:
+ 4a:d5:24:ad:20:39:fe:ab:ce:38:dd:c0:1e:2f:dd:ce:b4:5c:
+ 49:1d:ab:7a:e1:bd:e9:a6:d2:02:64:8a:a9:97:36:89:42:c2:
+ 82:14:ec:aa:dd:77:be:b1:d6:d2:4f:8b:a4:fe:5b:06:28:1c:
+ 2f:4e:83:15:1f:10:a9:c6:ce:8e:a6:ca:bb:2c:01:6a:ae:99:
+ 59:44:05:fc:a5:7e:fe:73:5f:df:b5:0b:48:b5:43:b6:10:9f:
+ 42:2e:8b:65:f6:47:25:27:66:ef:a6:a0:ca:d3:cc:9c:ac:2d:
+ 22:5b:87:5c
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKdnzx31VOmWVLxljLee
+cjkFaD1E5ZPYS2GxpLS0TMagkrZNBjpbsgqKJ8ux58M1R++sLafQnLJQalg9EqSF
+3HepCOX0H8DvAFHNaGLV5cwBvr5CizX7AJwwhAzXNX2I0RtDeBl5qgazrFxpoCPw
+adyJWZcF3wGuW48BoHhPBU42rAC0jeh5BQfydqRjP5UhBldhqfBDBNGS0527s49b
+76uBoCMROLUCspUdrNq4NmDX1wFt6O0yIbSElzN8Z4gORMcSh4VqSYCCyx4WKy9t
+mIKgoDDMVd+TZeCaCCSKR8xpUzy3YvrfEWTQP1JDgPjPe2/QZSD7ItBDyvz8D70c
+QrkCAwEAAaOByzCByDAdBgNVHQ4EFgQUXaEDPY8T+QivHoNsvN5vo7XCGuowHwYD
+VR0jBBgwFoAUXaEDPY8T+QivHoNsvN5vo7XCGuowNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB/7BPwRlPV
+dQilN0ScRxmeBe/WMGgeC8g8hJNRNiVIYFbUeR+2LJHjb2H5533ItntwfydtLDjs
+c+SMhvRIjhsJDZ/4Wh+V7fED6plk1i1GTrgLZxCYjhkuMeHj1v58l+mjehglnNRP
+zqkRHfBTMorojo2A+/HBwWrBz9I2orH5Mp4F/XMauTflVbIeeISlBEVK1SStIDn+
+q8443cAeL93OtFxJHat64b3pptICZIqplzaJQsKCFOyq3Xe+sdbST4uk/lsGKBwv
+ToMVHxCpxs6Opsq7LAFqrplZRAX8pX7+c1/ftQtItUO2EJ9CLotl9kclJ2bvpqDK
+08ycrC0iW4dc
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/key-rollover-newchain.pem b/chromium/net/data/verify_certificate_chain_unittest/key-rollover-newchain.pem
new file mode 100644
index 00000000000..7afc4c8c46c
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/key-rollover-newchain.pem
@@ -0,0 +1,313 @@
+[Created by: generate-key-rollover.py]
+
+A certificate tree with two self-signed root certificates(oldroot, newroot),
+and a third root certificate (newrootrollover) which has the same key as newroot
+but is signed by oldroot, all with the same subject and issuer.
+There are two intermediates with the same key, subject and issuer
+(oldintermediate signed by oldroot, and newintermediate signed by newroot).
+The target certificate is signed by the intermediate key.
+
+
+In graphical form:
+
+ oldroot-------->newrootrollover newroot
+ | | |
+ v v v
+oldintermediate newintermediate
+ | |
+ +------------+-------------+
+ |
+ v
+ target
+
+
+Several chains are output:
+ key-rollover-oldchain.pem:
+ target<-oldintermediate<-oldroot
+ key-rollover-rolloverchain.pem:
+ target<-newintermediate<-newrootrollover<-oldroot
+ key-rollover-longrolloverchain.pem:
+ target<-newintermediate<-newroot<-newrootrollover<-oldroot
+ key-rollover-newchain.pem:
+ target<-newintermediate<-newroot
+
+All of these chains should verify successfully.
+
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d0:14:31:90:c4:c6:d0:b9:10:9e:e4:7a:e2:bc:
+ 16:ab:d2:5e:d7:3d:00:11:bf:25:0b:32:17:57:c4:
+ fb:f6:60:0d:5a:7c:43:08:88:e6:35:f7:39:0f:dc:
+ d7:ef:22:18:52:5b:de:27:35:10:93:ab:c0:ae:98:
+ 1b:e1:c7:40:a8:be:84:2a:e6:69:7c:c4:68:1e:c4:
+ 0d:29:97:55:12:fb:30:86:a3:8f:03:0c:d4:4b:22:
+ 76:ac:a8:db:fd:20:4c:46:ea:21:9b:59:4f:ea:9c:
+ 20:6f:ff:e1:7c:7d:64:5c:4b:91:4d:ac:56:1d:19:
+ 12:6c:af:f2:99:40:21:9d:06:b9:a2:90:2c:7b:bc:
+ af:fe:c0:40:a1:06:89:62:f3:f3:fd:a0:07:61:aa:
+ c2:f9:e1:0e:13:96:92:ac:53:ba:ed:a5:36:c9:b9:
+ 04:e7:13:67:bc:0e:63:dc:22:29:53:e2:e3:59:ab:
+ 5c:25:cd:d9:fb:46:4e:91:70:dd:41:4b:35:87:a4:
+ fd:2c:66:be:75:7e:03:e9:12:61:66:cb:19:88:a1:
+ 61:b7:13:b4:ab:51:a6:d5:58:9c:db:8c:a2:1a:da:
+ c3:6f:cb:b6:b1:65:d8:a3:a3:d1:87:d8:b9:bb:b8:
+ c1:83:f1:83:38:2a:fd:a3:f6:a6:59:f2:27:f1:e3:
+ 50:29
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 01:D0:19:F4:6B:86:BC:17:3B:FB:74:95:0F:53:BD:BD:4E:CA:10:D6
+ X509v3 Authority Key Identifier:
+ keyid:D3:97:C6:F7:B9:E5:17:69:6D:78:39:77:3A:0A:AD:32:2D:40:AC:07
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 0e:b6:ad:85:34:3d:cf:9c:2f:8c:e7:90:80:33:f6:12:99:40:
+ 6d:89:7b:5c:08:c9:a9:fc:40:24:1e:14:ac:6c:6a:11:aa:3e:
+ ea:c1:19:32:75:67:26:fe:c0:f9:55:e9:b6:04:74:c9:e3:22:
+ 59:3a:06:5a:5f:25:6d:1d:df:48:62:a4:ee:d0:87:df:20:9d:
+ 9c:95:aa:4e:77:05:28:e6:66:ac:ae:23:e4:74:df:5a:b4:21:
+ e7:3d:0f:95:61:84:11:7e:d8:72:66:dd:85:c7:41:fe:44:12:
+ da:4c:c7:1b:ab:7d:4b:3d:c4:38:2d:b9:54:8a:26:1e:76:1b:
+ f6:0b:8a:e9:fa:9f:0a:e6:cc:6d:c5:55:f1:a5:29:20:42:05:
+ d4:5a:4f:27:ab:b6:e4:c4:ea:4d:8b:97:53:67:03:75:32:1f:
+ 9d:1e:b8:72:e1:c4:5a:09:15:d7:ce:a3:59:ed:cc:4d:0f:ea:
+ c0:1d:57:1a:43:d7:7a:63:86:b0:b8:5c:4f:34:29:a4:be:90:
+ c4:6b:39:20:c9:25:96:7d:a1:cc:ee:f7:57:04:69:d7:21:66:
+ 1d:cc:4e:6c:10:1a:6e:87:11:f3:e3:ae:9e:5b:64:04:ee:ac:
+ c6:0a:24:80:e4:0a:0e:89:49:9d:0f:1d:74:b2:f6:db:7e:25:
+ a1:d0:6e:7e
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQFDGQ
+xMbQuRCe5HrivBar0l7XPQARvyULMhdXxPv2YA1afEMIiOY19zkP3NfvIhhSW94n
+NRCTq8CumBvhx0CovoQq5ml8xGgexA0pl1US+zCGo48DDNRLInasqNv9IExG6iGb
+WU/qnCBv/+F8fWRcS5FNrFYdGRJsr/KZQCGdBrmikCx7vK/+wEChBoli8/P9oAdh
+qsL54Q4TlpKsU7rtpTbJuQTnE2e8DmPcIilT4uNZq1wlzdn7Rk6RcN1BSzWHpP0s
+Zr51fgPpEmFmyxmIoWG3E7SrUabVWJzbjKIa2sNvy7axZdijo9GH2Lm7uMGD8YM4
+Kv2j9qZZ8ifx41ApAgMBAAGjgekwgeYwHQYDVR0OBBYEFAHQGfRrhrwXO/t0lQ9T
+vb1OyhDWMB8GA1UdIwQYMBaAFNOXxve55RdpbXg5dzoKrTItQKwHMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEADrathTQ9z5wvjOeQgDP2
+EplAbYl7XAjJqfxAJB4UrGxqEao+6sEZMnVnJv7A+VXptgR0yeMiWToGWl8lbR3f
+SGKk7tCH3yCdnJWqTncFKOZmrK4j5HTfWrQh5z0PlWGEEX7YcmbdhcdB/kQS2kzH
+G6t9Sz3EOC25VIomHnYb9guK6fqfCubMbcVV8aUpIEIF1FpPJ6u25MTqTYuXU2cD
+dTIfnR64cuHEWgkV186jWe3MTQ/qwB1XGkPXemOGsLhcTzQppL6QxGs5IMklln2h
+zO73VwRp1yFmHcxObBAabocR8+OunltkBO6sxgokgOQKDolJnQ8ddLL2234lodBu
+fg==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 4 (0x4)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 2 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:bf:ca:00:55:10:61:e4:0e:a3:f8:57:b8:7b:19:
+ 34:5a:77:b8:06:39:88:07:0c:ec:d0:3b:4a:53:02:
+ 3c:d1:d3:da:48:ae:8a:1a:1c:3d:30:bb:b3:36:80:
+ a1:6f:cd:32:fd:54:26:b9:77:d7:1e:11:30:6c:eb:
+ d7:11:9a:d9:af:54:7e:0e:37:c3:8d:f3:0a:5d:ec:
+ 82:d6:6e:f3:46:f4:2a:82:24:e4:28:38:c2:fa:6a:
+ a6:f7:38:cd:94:50:20:bd:ee:50:9e:3a:a3:40:1a:
+ 49:77:eb:b2:05:8c:01:46:e6:ef:8f:55:91:0a:7a:
+ 44:10:62:b8:9f:3e:81:31:ae:08:95:29:37:47:53:
+ ec:f3:c7:9c:f0:be:64:70:b3:81:f0:04:f4:a4:aa:
+ 41:ad:16:8f:13:31:af:9b:eb:55:dc:93:6d:56:cf:
+ d6:f0:0a:fb:11:9e:32:59:d4:07:28:e1:fe:60:73:
+ bf:43:bf:ff:c9:dc:f2:ca:3a:e1:0c:bd:90:0b:c2:
+ ab:91:d5:2e:72:5d:5e:f0:f8:45:7b:3d:37:89:d1:
+ 16:bd:9b:4f:c9:c4:34:c7:c4:23:a4:04:4b:13:db:
+ 1a:b5:82:d0:f6:cd:99:fe:f3:0d:98:81:65:5e:2f:
+ 9e:a4:c1:5b:2b:67:b5:07:2a:24:a6:e7:06:5f:49:
+ d6:d5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ D3:97:C6:F7:B9:E5:17:69:6D:78:39:77:3A:0A:AD:32:2D:40:AC:07
+ X509v3 Authority Key Identifier:
+ keyid:64:90:93:CD:AC:C7:37:36:4D:6B:14:D6:67:D0:54:3A:59:45:3A:FC
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ d2:35:f4:84:23:56:e3:2f:d1:54:fa:eb:85:02:e1:b7:aa:94:
+ a9:73:95:1d:29:9a:35:64:ac:4a:28:a3:87:24:e1:cd:3e:9f:
+ 53:14:92:ce:86:d6:ae:d5:3f:1d:97:59:ae:c4:1c:ae:78:29:
+ d7:45:a5:14:58:b6:ac:28:3e:20:e6:27:56:22:b2:bf:80:24:
+ 8d:bd:ef:17:67:8f:59:74:8b:7e:41:f1:fc:4d:a8:7b:d4:cf:
+ 0c:ec:41:c6:7a:2b:fc:c3:c2:92:dc:49:f6:7a:3d:bd:b0:41:
+ 0c:d3:0c:dd:58:1a:42:62:80:10:ad:95:ec:a0:8a:cb:b4:b8:
+ 8e:5d:45:c7:d2:82:4b:eb:cb:1a:0e:f5:40:46:0d:dd:35:a3:
+ 9b:d1:3e:55:95:b1:ab:96:63:31:ac:01:b4:ef:20:bc:0d:86:
+ 88:b2:e5:94:64:6b:f1:1a:73:3e:09:b0:4c:57:87:3a:65:5a:
+ 84:17:af:1c:cd:a5:4e:72:8e:19:8b:50:0a:97:4b:df:69:2c:
+ 4c:21:d4:d1:7e:81:74:94:60:5b:b0:5e:56:53:14:b4:52:3d:
+ c9:45:a5:47:10:74:15:86:a0:52:ba:ff:b5:32:01:ef:dd:0e:
+ 17:d6:73:35:aa:1e:ca:9a:8b:2e:28:cf:fa:1b:79:be:a7:87:
+ 4b:b4:0a:26
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBBDANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMjEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv8oAVRBh
+5A6j+Fe4exk0Wne4BjmIBwzs0DtKUwI80dPaSK6KGhw9MLuzNoChb80y/VQmuXfX
+HhEwbOvXEZrZr1R+DjfDjfMKXeyC1m7zRvQqgiTkKDjC+mqm9zjNlFAgve5Qnjqj
+QBpJd+uyBYwBRubvj1WRCnpEEGK4nz6BMa4IlSk3R1Ps88ec8L5kcLOB8AT0pKpB
+rRaPEzGvm+tV3JNtVs/W8Ar7EZ4yWdQHKOH+YHO/Q7//ydzyyjrhDL2QC8KrkdUu
+cl1e8PhFez03idEWvZtPycQ0x8QjpARLE9satYLQ9s2Z/vMNmIFlXi+epMFbK2e1
+ByokpucGX0nW1QIDAQABo4HLMIHIMB0GA1UdDgQWBBTTl8b3ueUXaW14OXc6Cq0y
+LUCsBzAfBgNVHSMEGDAWgBRkkJPNrMc3Nk1rFNZn0FQ6WUU6/DA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+ANI19IQjVuMv0VT664UC4beqlKlzlR0pmjVkrEooo4ck4c0+n1MUks6G1q7VPx2X
+Wa7EHK54KddFpRRYtqwoPiDmJ1Yisr+AJI297xdnj1l0i35B8fxNqHvUzwzsQcZ6
+K/zDwpLcSfZ6Pb2wQQzTDN1YGkJigBCtleygisu0uI5dRcfSgkvryxoO9UBGDd01
+o5vRPlWVsauWYzGsAbTvILwNhoiy5ZRka/Eacz4JsExXhzplWoQXrxzNpU5yjhmL
+UAqXS99pLEwh1NF+gXSUYFuwXlZTFLRSPclFpUcQdBWGoFK6/7UyAe/dDhfWczWq
+Hsqaiy4oz/obeb6nh0u0CiY=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 3 (0x3)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 2 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ea:cc:2d:c4:88:54:07:90:da:62:ef:77:23:b2:
+ 83:c9:54:06:25:70:65:43:f2:29:a3:f3:22:f2:09:
+ 92:31:25:77:79:63:4a:7f:d8:e5:1f:16:1a:25:bc:
+ d4:4b:9a:b3:a0:61:7e:c3:a5:90:32:97:5a:5b:59:
+ cf:97:d6:ac:2c:86:a7:70:ed:2d:e0:bf:e8:44:6f:
+ 41:29:55:b0:40:a8:10:d6:4d:67:2b:01:1f:7a:33:
+ 2b:ce:8f:c8:fb:54:99:e2:11:2d:75:7d:ff:f5:fb:
+ 53:e5:6b:7e:ca:b8:fc:1f:bc:8f:32:29:6d:d2:6b:
+ a1:9b:d9:7f:b2:f6:e9:18:72:fe:45:a2:23:dc:bf:
+ 5d:1e:43:5d:2b:80:2a:71:b4:cb:67:30:cc:aa:54:
+ 76:fc:4b:a3:2b:ab:99:31:66:bf:5c:09:44:e6:c9:
+ 27:42:3a:58:b5:fd:db:06:0f:11:04:0d:2d:36:4a:
+ 02:d5:50:4d:4d:7c:ed:a4:51:49:e3:fe:44:54:30:
+ 84:b6:1f:54:28:1f:9e:41:b2:20:23:75:e5:d4:e4:
+ bf:79:a6:ab:84:aa:dc:56:38:cf:2c:d3:8e:13:48:
+ 43:5a:eb:eb:3b:a0:36:d5:89:0c:68:e2:fb:8f:3a:
+ 82:ad:01:4b:f8:bb:b0:2e:3d:b7:6e:91:a3:70:9a:
+ d0:41
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 64:90:93:CD:AC:C7:37:36:4D:6B:14:D6:67:D0:54:3A:59:45:3A:FC
+ X509v3 Authority Key Identifier:
+ keyid:64:90:93:CD:AC:C7:37:36:4D:6B:14:D6:67:D0:54:3A:59:45:3A:FC
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 77:d8:b1:3b:e5:c4:ce:c7:37:c6:fa:d7:a7:a1:cf:66:0e:19:
+ 49:ea:06:f2:ec:8d:92:7d:e2:de:43:32:22:55:b4:84:f5:30:
+ bb:44:91:c1:81:2a:aa:ae:e1:3c:86:17:20:28:15:a1:d0:dc:
+ ce:7c:62:67:4e:d5:a8:e0:e3:44:91:af:96:24:58:0d:eb:26:
+ 1f:42:37:82:de:d6:84:40:36:c7:78:7d:6c:f7:fa:54:a0:70:
+ d0:b9:41:a8:f2:3b:19:f1:cc:36:97:69:78:66:3c:ad:03:1e:
+ 70:e7:81:23:11:d6:98:d7:ba:e5:98:d8:12:c7:4b:1d:5b:b1:
+ cd:91:5c:49:f0:d3:99:dd:9e:ab:db:7b:32:f6:8c:be:fe:0b:
+ 2b:1e:96:8d:6e:7e:4a:69:71:f3:b6:f7:44:5f:a1:2f:62:67:
+ f0:55:b0:a2:d1:db:7f:58:3b:10:05:4f:e1:00:9d:45:4f:5d:
+ 1e:b8:a8:83:bd:33:bd:14:07:34:23:5e:99:bb:16:3e:ee:de:
+ 84:96:53:bf:29:e7:a5:52:a9:b6:6a:76:db:a6:ee:45:34:3f:
+ f7:48:d8:8a:12:46:c6:6c:ba:31:85:e8:45:07:85:23:37:85:
+ ff:15:de:0b:a8:97:40:60:11:9d:20:a8:fc:53:38:66:ea:9e:
+ d4:1b:9f:34
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDZTCCAk2gAwIBAgIBAzANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMjEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOrMLcSIVAeQ2mLvdyOy
+g8lUBiVwZUPyKaPzIvIJkjEld3ljSn/Y5R8WGiW81Euas6BhfsOlkDKXWltZz5fW
+rCyGp3DtLeC/6ERvQSlVsECoENZNZysBH3ozK86PyPtUmeIRLXV9//X7U+Vrfsq4
+/B+8jzIpbdJroZvZf7L26Rhy/kWiI9y/XR5DXSuAKnG0y2cwzKpUdvxLoyurmTFm
+v1wJRObJJ0I6WLX92wYPEQQNLTZKAtVQTU187aRRSeP+RFQwhLYfVCgfnkGyICN1
+5dTkv3mmq4Sq3FY4zyzTjhNIQ1rr6zugNtWJDGji+486gq0BS/i7sC49t26Ro3Ca
+0EECAwEAAaOByzCByDAdBgNVHQ4EFgQUZJCTzazHNzZNaxTWZ9BUOllFOvwwHwYD
+VR0jBBgwFoAUZJCTzazHNzZNaxTWZ9BUOllFOvwwNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB32LE75cTO
+xzfG+tenoc9mDhlJ6gby7I2SfeLeQzIiVbSE9TC7RJHBgSqqruE8hhcgKBWh0NzO
+fGJnTtWo4ONEka+WJFgN6yYfQjeC3taEQDbHeH1s9/pUoHDQuUGo8jsZ8cw2l2l4
+ZjytAx5w54EjEdaY17rlmNgSx0sdW7HNkVxJ8NOZ3Z6r23sy9oy+/gsrHpaNbn5K
+aXHztvdEX6EvYmfwVbCi0dt/WDsQBU/hAJ1FT10euKiDvTO9FAc0I16ZuxY+7t6E
+llO/KeelUqm2anbbpu5FND/3SNiKEkbGbLoxhehFB4UjN4X/Fd4LqJdAYBGdIKj8
+Uzhm6p7UG580
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/key-rollover-oldchain.pem b/chromium/net/data/verify_certificate_chain_unittest/key-rollover-oldchain.pem
new file mode 100644
index 00000000000..b9f9182007d
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/key-rollover-oldchain.pem
@@ -0,0 +1,313 @@
+[Created by: generate-key-rollover.py]
+
+A certificate tree with two self-signed root certificates(oldroot, newroot),
+and a third root certificate (newrootrollover) which has the same key as newroot
+but is signed by oldroot, all with the same subject and issuer.
+There are two intermediates with the same key, subject and issuer
+(oldintermediate signed by oldroot, and newintermediate signed by newroot).
+The target certificate is signed by the intermediate key.
+
+
+In graphical form:
+
+ oldroot-------->newrootrollover newroot
+ | | |
+ v v v
+oldintermediate newintermediate
+ | |
+ +------------+-------------+
+ |
+ v
+ target
+
+
+Several chains are output:
+ key-rollover-oldchain.pem:
+ target<-oldintermediate<-oldroot
+ key-rollover-rolloverchain.pem:
+ target<-newintermediate<-newrootrollover<-oldroot
+ key-rollover-longrolloverchain.pem:
+ target<-newintermediate<-newroot<-newrootrollover<-oldroot
+ key-rollover-newchain.pem:
+ target<-newintermediate<-newroot
+
+All of these chains should verify successfully.
+
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d0:14:31:90:c4:c6:d0:b9:10:9e:e4:7a:e2:bc:
+ 16:ab:d2:5e:d7:3d:00:11:bf:25:0b:32:17:57:c4:
+ fb:f6:60:0d:5a:7c:43:08:88:e6:35:f7:39:0f:dc:
+ d7:ef:22:18:52:5b:de:27:35:10:93:ab:c0:ae:98:
+ 1b:e1:c7:40:a8:be:84:2a:e6:69:7c:c4:68:1e:c4:
+ 0d:29:97:55:12:fb:30:86:a3:8f:03:0c:d4:4b:22:
+ 76:ac:a8:db:fd:20:4c:46:ea:21:9b:59:4f:ea:9c:
+ 20:6f:ff:e1:7c:7d:64:5c:4b:91:4d:ac:56:1d:19:
+ 12:6c:af:f2:99:40:21:9d:06:b9:a2:90:2c:7b:bc:
+ af:fe:c0:40:a1:06:89:62:f3:f3:fd:a0:07:61:aa:
+ c2:f9:e1:0e:13:96:92:ac:53:ba:ed:a5:36:c9:b9:
+ 04:e7:13:67:bc:0e:63:dc:22:29:53:e2:e3:59:ab:
+ 5c:25:cd:d9:fb:46:4e:91:70:dd:41:4b:35:87:a4:
+ fd:2c:66:be:75:7e:03:e9:12:61:66:cb:19:88:a1:
+ 61:b7:13:b4:ab:51:a6:d5:58:9c:db:8c:a2:1a:da:
+ c3:6f:cb:b6:b1:65:d8:a3:a3:d1:87:d8:b9:bb:b8:
+ c1:83:f1:83:38:2a:fd:a3:f6:a6:59:f2:27:f1:e3:
+ 50:29
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 01:D0:19:F4:6B:86:BC:17:3B:FB:74:95:0F:53:BD:BD:4E:CA:10:D6
+ X509v3 Authority Key Identifier:
+ keyid:D3:97:C6:F7:B9:E5:17:69:6D:78:39:77:3A:0A:AD:32:2D:40:AC:07
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 0e:b6:ad:85:34:3d:cf:9c:2f:8c:e7:90:80:33:f6:12:99:40:
+ 6d:89:7b:5c:08:c9:a9:fc:40:24:1e:14:ac:6c:6a:11:aa:3e:
+ ea:c1:19:32:75:67:26:fe:c0:f9:55:e9:b6:04:74:c9:e3:22:
+ 59:3a:06:5a:5f:25:6d:1d:df:48:62:a4:ee:d0:87:df:20:9d:
+ 9c:95:aa:4e:77:05:28:e6:66:ac:ae:23:e4:74:df:5a:b4:21:
+ e7:3d:0f:95:61:84:11:7e:d8:72:66:dd:85:c7:41:fe:44:12:
+ da:4c:c7:1b:ab:7d:4b:3d:c4:38:2d:b9:54:8a:26:1e:76:1b:
+ f6:0b:8a:e9:fa:9f:0a:e6:cc:6d:c5:55:f1:a5:29:20:42:05:
+ d4:5a:4f:27:ab:b6:e4:c4:ea:4d:8b:97:53:67:03:75:32:1f:
+ 9d:1e:b8:72:e1:c4:5a:09:15:d7:ce:a3:59:ed:cc:4d:0f:ea:
+ c0:1d:57:1a:43:d7:7a:63:86:b0:b8:5c:4f:34:29:a4:be:90:
+ c4:6b:39:20:c9:25:96:7d:a1:cc:ee:f7:57:04:69:d7:21:66:
+ 1d:cc:4e:6c:10:1a:6e:87:11:f3:e3:ae:9e:5b:64:04:ee:ac:
+ c6:0a:24:80:e4:0a:0e:89:49:9d:0f:1d:74:b2:f6:db:7e:25:
+ a1:d0:6e:7e
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQFDGQ
+xMbQuRCe5HrivBar0l7XPQARvyULMhdXxPv2YA1afEMIiOY19zkP3NfvIhhSW94n
+NRCTq8CumBvhx0CovoQq5ml8xGgexA0pl1US+zCGo48DDNRLInasqNv9IExG6iGb
+WU/qnCBv/+F8fWRcS5FNrFYdGRJsr/KZQCGdBrmikCx7vK/+wEChBoli8/P9oAdh
+qsL54Q4TlpKsU7rtpTbJuQTnE2e8DmPcIilT4uNZq1wlzdn7Rk6RcN1BSzWHpP0s
+Zr51fgPpEmFmyxmIoWG3E7SrUabVWJzbjKIa2sNvy7axZdijo9GH2Lm7uMGD8YM4
+Kv2j9qZZ8ifx41ApAgMBAAGjgekwgeYwHQYDVR0OBBYEFAHQGfRrhrwXO/t0lQ9T
+vb1OyhDWMB8GA1UdIwQYMBaAFNOXxve55RdpbXg5dzoKrTItQKwHMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEADrathTQ9z5wvjOeQgDP2
+EplAbYl7XAjJqfxAJB4UrGxqEao+6sEZMnVnJv7A+VXptgR0yeMiWToGWl8lbR3f
+SGKk7tCH3yCdnJWqTncFKOZmrK4j5HTfWrQh5z0PlWGEEX7YcmbdhcdB/kQS2kzH
+G6t9Sz3EOC25VIomHnYb9guK6fqfCubMbcVV8aUpIEIF1FpPJ6u25MTqTYuXU2cD
+dTIfnR64cuHEWgkV186jWe3MTQ/qwB1XGkPXemOGsLhcTzQppL6QxGs5IMklln2h
+zO73VwRp1yFmHcxObBAabocR8+OunltkBO6sxgokgOQKDolJnQ8ddLL2234lodBu
+fg==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:bf:ca:00:55:10:61:e4:0e:a3:f8:57:b8:7b:19:
+ 34:5a:77:b8:06:39:88:07:0c:ec:d0:3b:4a:53:02:
+ 3c:d1:d3:da:48:ae:8a:1a:1c:3d:30:bb:b3:36:80:
+ a1:6f:cd:32:fd:54:26:b9:77:d7:1e:11:30:6c:eb:
+ d7:11:9a:d9:af:54:7e:0e:37:c3:8d:f3:0a:5d:ec:
+ 82:d6:6e:f3:46:f4:2a:82:24:e4:28:38:c2:fa:6a:
+ a6:f7:38:cd:94:50:20:bd:ee:50:9e:3a:a3:40:1a:
+ 49:77:eb:b2:05:8c:01:46:e6:ef:8f:55:91:0a:7a:
+ 44:10:62:b8:9f:3e:81:31:ae:08:95:29:37:47:53:
+ ec:f3:c7:9c:f0:be:64:70:b3:81:f0:04:f4:a4:aa:
+ 41:ad:16:8f:13:31:af:9b:eb:55:dc:93:6d:56:cf:
+ d6:f0:0a:fb:11:9e:32:59:d4:07:28:e1:fe:60:73:
+ bf:43:bf:ff:c9:dc:f2:ca:3a:e1:0c:bd:90:0b:c2:
+ ab:91:d5:2e:72:5d:5e:f0:f8:45:7b:3d:37:89:d1:
+ 16:bd:9b:4f:c9:c4:34:c7:c4:23:a4:04:4b:13:db:
+ 1a:b5:82:d0:f6:cd:99:fe:f3:0d:98:81:65:5e:2f:
+ 9e:a4:c1:5b:2b:67:b5:07:2a:24:a6:e7:06:5f:49:
+ d6:d5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ D3:97:C6:F7:B9:E5:17:69:6D:78:39:77:3A:0A:AD:32:2D:40:AC:07
+ X509v3 Authority Key Identifier:
+ keyid:5D:A1:03:3D:8F:13:F9:08:AF:1E:83:6C:BC:DE:6F:A3:B5:C2:1A:EA
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 9f:f2:71:1d:88:6c:57:db:19:12:ed:da:7c:5e:ef:81:90:30:
+ 2f:f8:9a:df:de:90:bc:9d:6b:26:64:10:87:b8:45:78:8d:8d:
+ 37:fe:c8:86:75:d0:a2:c5:88:78:b6:8d:30:f7:8c:63:5e:3f:
+ 8d:7d:54:81:68:80:34:dd:cf:37:73:24:91:ef:42:7a:5c:ed:
+ 94:9a:b9:6f:a6:13:1d:04:9d:0a:e6:53:eb:6c:2d:7b:24:06:
+ b3:d4:3a:79:94:17:68:9e:c2:36:91:b7:30:f2:cf:c3:6c:22:
+ 2d:73:2c:e6:ca:d0:97:db:a1:f6:7e:2e:e2:5b:27:d5:86:a9:
+ ec:92:3b:f9:5d:ae:bd:f9:a7:d6:a9:dd:f9:93:49:2d:f1:99:
+ a6:98:10:43:0e:2f:98:97:e0:17:36:86:57:75:22:63:65:39:
+ eb:69:e9:cc:4d:9c:9b:35:63:5b:1b:04:fb:7a:b4:91:30:a2:
+ 5c:4e:c0:a8:7c:94:ce:4c:d8:eb:f2:fe:34:be:e6:76:bc:fe:
+ 8c:9e:d3:3b:6d:ae:62:92:8b:0f:41:9c:d7:65:0d:7b:1b:c5:
+ e9:5f:11:a2:f1:18:22:5e:0d:e7:9b:b7:b7:c5:34:77:ef:32:
+ b5:94:ef:dd:a6:6e:a7:07:43:c9:7f:b8:04:2a:88:53:44:93:
+ a2:db:05:93
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv8oAVRBh
+5A6j+Fe4exk0Wne4BjmIBwzs0DtKUwI80dPaSK6KGhw9MLuzNoChb80y/VQmuXfX
+HhEwbOvXEZrZr1R+DjfDjfMKXeyC1m7zRvQqgiTkKDjC+mqm9zjNlFAgve5Qnjqj
+QBpJd+uyBYwBRubvj1WRCnpEEGK4nz6BMa4IlSk3R1Ps88ec8L5kcLOB8AT0pKpB
+rRaPEzGvm+tV3JNtVs/W8Ar7EZ4yWdQHKOH+YHO/Q7//ydzyyjrhDL2QC8KrkdUu
+cl1e8PhFez03idEWvZtPycQ0x8QjpARLE9satYLQ9s2Z/vMNmIFlXi+epMFbK2e1
+ByokpucGX0nW1QIDAQABo4HLMIHIMB0GA1UdDgQWBBTTl8b3ueUXaW14OXc6Cq0y
+LUCsBzAfBgNVHSMEGDAWgBRdoQM9jxP5CK8eg2y83m+jtcIa6jA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AJ/ycR2IbFfbGRLt2nxe74GQMC/4mt/ekLydayZkEIe4RXiNjTf+yIZ10KLFiHi2
+jTD3jGNeP419VIFogDTdzzdzJJHvQnpc7ZSauW+mEx0EnQrmU+tsLXskBrPUOnmU
+F2iewjaRtzDyz8NsIi1zLObK0JfbofZ+LuJbJ9WGqeySO/ldrr35p9ap3fmTSS3x
+maaYEEMOL5iX4Bc2hld1ImNlOetp6cxNnJs1Y1sbBPt6tJEwolxOwKh8lM5M2Ovy
+/jS+5na8/oye0zttrmKSiw9BnNdlDXsbxelfEaLxGCJeDeebt7fFNHfvMrWU792m
+bqcHQ8l/uAQqiFNEk6LbBZM=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:a7:67:cf:1d:f5:54:e9:96:54:bc:65:8c:b7:9e:
+ 72:39:05:68:3d:44:e5:93:d8:4b:61:b1:a4:b4:b4:
+ 4c:c6:a0:92:b6:4d:06:3a:5b:b2:0a:8a:27:cb:b1:
+ e7:c3:35:47:ef:ac:2d:a7:d0:9c:b2:50:6a:58:3d:
+ 12:a4:85:dc:77:a9:08:e5:f4:1f:c0:ef:00:51:cd:
+ 68:62:d5:e5:cc:01:be:be:42:8b:35:fb:00:9c:30:
+ 84:0c:d7:35:7d:88:d1:1b:43:78:19:79:aa:06:b3:
+ ac:5c:69:a0:23:f0:69:dc:89:59:97:05:df:01:ae:
+ 5b:8f:01:a0:78:4f:05:4e:36:ac:00:b4:8d:e8:79:
+ 05:07:f2:76:a4:63:3f:95:21:06:57:61:a9:f0:43:
+ 04:d1:92:d3:9d:bb:b3:8f:5b:ef:ab:81:a0:23:11:
+ 38:b5:02:b2:95:1d:ac:da:b8:36:60:d7:d7:01:6d:
+ e8:ed:32:21:b4:84:97:33:7c:67:88:0e:44:c7:12:
+ 87:85:6a:49:80:82:cb:1e:16:2b:2f:6d:98:82:a0:
+ a0:30:cc:55:df:93:65:e0:9a:08:24:8a:47:cc:69:
+ 53:3c:b7:62:fa:df:11:64:d0:3f:52:43:80:f8:cf:
+ 7b:6f:d0:65:20:fb:22:d0:43:ca:fc:fc:0f:bd:1c:
+ 42:b9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 5D:A1:03:3D:8F:13:F9:08:AF:1E:83:6C:BC:DE:6F:A3:B5:C2:1A:EA
+ X509v3 Authority Key Identifier:
+ keyid:5D:A1:03:3D:8F:13:F9:08:AF:1E:83:6C:BC:DE:6F:A3:B5:C2:1A:EA
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 7f:ec:13:f0:46:53:d5:75:08:a5:37:44:9c:47:19:9e:05:ef:
+ d6:30:68:1e:0b:c8:3c:84:93:51:36:25:48:60:56:d4:79:1f:
+ b6:2c:91:e3:6f:61:f9:e7:7d:c8:b6:7b:70:7f:27:6d:2c:38:
+ ec:73:e4:8c:86:f4:48:8e:1b:09:0d:9f:f8:5a:1f:95:ed:f1:
+ 03:ea:99:64:d6:2d:46:4e:b8:0b:67:10:98:8e:19:2e:31:e1:
+ e3:d6:fe:7c:97:e9:a3:7a:18:25:9c:d4:4f:ce:a9:11:1d:f0:
+ 53:32:8a:e8:8e:8d:80:fb:f1:c1:c1:6a:c1:cf:d2:36:a2:b1:
+ f9:32:9e:05:fd:73:1a:b9:37:e5:55:b2:1e:78:84:a5:04:45:
+ 4a:d5:24:ad:20:39:fe:ab:ce:38:dd:c0:1e:2f:dd:ce:b4:5c:
+ 49:1d:ab:7a:e1:bd:e9:a6:d2:02:64:8a:a9:97:36:89:42:c2:
+ 82:14:ec:aa:dd:77:be:b1:d6:d2:4f:8b:a4:fe:5b:06:28:1c:
+ 2f:4e:83:15:1f:10:a9:c6:ce:8e:a6:ca:bb:2c:01:6a:ae:99:
+ 59:44:05:fc:a5:7e:fe:73:5f:df:b5:0b:48:b5:43:b6:10:9f:
+ 42:2e:8b:65:f6:47:25:27:66:ef:a6:a0:ca:d3:cc:9c:ac:2d:
+ 22:5b:87:5c
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKdnzx31VOmWVLxljLee
+cjkFaD1E5ZPYS2GxpLS0TMagkrZNBjpbsgqKJ8ux58M1R++sLafQnLJQalg9EqSF
+3HepCOX0H8DvAFHNaGLV5cwBvr5CizX7AJwwhAzXNX2I0RtDeBl5qgazrFxpoCPw
+adyJWZcF3wGuW48BoHhPBU42rAC0jeh5BQfydqRjP5UhBldhqfBDBNGS0527s49b
+76uBoCMROLUCspUdrNq4NmDX1wFt6O0yIbSElzN8Z4gORMcSh4VqSYCCyx4WKy9t
+mIKgoDDMVd+TZeCaCCSKR8xpUzy3YvrfEWTQP1JDgPjPe2/QZSD7ItBDyvz8D70c
+QrkCAwEAAaOByzCByDAdBgNVHQ4EFgQUXaEDPY8T+QivHoNsvN5vo7XCGuowHwYD
+VR0jBBgwFoAUXaEDPY8T+QivHoNsvN5vo7XCGuowNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB/7BPwRlPV
+dQilN0ScRxmeBe/WMGgeC8g8hJNRNiVIYFbUeR+2LJHjb2H5533ItntwfydtLDjs
+c+SMhvRIjhsJDZ/4Wh+V7fED6plk1i1GTrgLZxCYjhkuMeHj1v58l+mjehglnNRP
+zqkRHfBTMorojo2A+/HBwWrBz9I2orH5Mp4F/XMauTflVbIeeISlBEVK1SStIDn+
+q8443cAeL93OtFxJHat64b3pptICZIqplzaJQsKCFOyq3Xe+sdbST4uk/lsGKBwv
+ToMVHxCpxs6Opsq7LAFqrplZRAX8pX7+c1/ftQtItUO2EJ9CLotl9kclJ2bvpqDK
+08ycrC0iW4dc
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/key-rollover-rolloverchain.pem b/chromium/net/data/verify_certificate_chain_unittest/key-rollover-rolloverchain.pem
new file mode 100644
index 00000000000..2ae242ebfa7
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/key-rollover-rolloverchain.pem
@@ -0,0 +1,402 @@
+[Created by: generate-key-rollover.py]
+
+A certificate tree with two self-signed root certificates(oldroot, newroot),
+and a third root certificate (newrootrollover) which has the same key as newroot
+but is signed by oldroot, all with the same subject and issuer.
+There are two intermediates with the same key, subject and issuer
+(oldintermediate signed by oldroot, and newintermediate signed by newroot).
+The target certificate is signed by the intermediate key.
+
+
+In graphical form:
+
+ oldroot-------->newrootrollover newroot
+ | | |
+ v v v
+oldintermediate newintermediate
+ | |
+ +------------+-------------+
+ |
+ v
+ target
+
+
+Several chains are output:
+ key-rollover-oldchain.pem:
+ target<-oldintermediate<-oldroot
+ key-rollover-rolloverchain.pem:
+ target<-newintermediate<-newrootrollover<-oldroot
+ key-rollover-longrolloverchain.pem:
+ target<-newintermediate<-newroot<-newrootrollover<-oldroot
+ key-rollover-newchain.pem:
+ target<-newintermediate<-newroot
+
+All of these chains should verify successfully.
+
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d0:14:31:90:c4:c6:d0:b9:10:9e:e4:7a:e2:bc:
+ 16:ab:d2:5e:d7:3d:00:11:bf:25:0b:32:17:57:c4:
+ fb:f6:60:0d:5a:7c:43:08:88:e6:35:f7:39:0f:dc:
+ d7:ef:22:18:52:5b:de:27:35:10:93:ab:c0:ae:98:
+ 1b:e1:c7:40:a8:be:84:2a:e6:69:7c:c4:68:1e:c4:
+ 0d:29:97:55:12:fb:30:86:a3:8f:03:0c:d4:4b:22:
+ 76:ac:a8:db:fd:20:4c:46:ea:21:9b:59:4f:ea:9c:
+ 20:6f:ff:e1:7c:7d:64:5c:4b:91:4d:ac:56:1d:19:
+ 12:6c:af:f2:99:40:21:9d:06:b9:a2:90:2c:7b:bc:
+ af:fe:c0:40:a1:06:89:62:f3:f3:fd:a0:07:61:aa:
+ c2:f9:e1:0e:13:96:92:ac:53:ba:ed:a5:36:c9:b9:
+ 04:e7:13:67:bc:0e:63:dc:22:29:53:e2:e3:59:ab:
+ 5c:25:cd:d9:fb:46:4e:91:70:dd:41:4b:35:87:a4:
+ fd:2c:66:be:75:7e:03:e9:12:61:66:cb:19:88:a1:
+ 61:b7:13:b4:ab:51:a6:d5:58:9c:db:8c:a2:1a:da:
+ c3:6f:cb:b6:b1:65:d8:a3:a3:d1:87:d8:b9:bb:b8:
+ c1:83:f1:83:38:2a:fd:a3:f6:a6:59:f2:27:f1:e3:
+ 50:29
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 01:D0:19:F4:6B:86:BC:17:3B:FB:74:95:0F:53:BD:BD:4E:CA:10:D6
+ X509v3 Authority Key Identifier:
+ keyid:D3:97:C6:F7:B9:E5:17:69:6D:78:39:77:3A:0A:AD:32:2D:40:AC:07
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 0e:b6:ad:85:34:3d:cf:9c:2f:8c:e7:90:80:33:f6:12:99:40:
+ 6d:89:7b:5c:08:c9:a9:fc:40:24:1e:14:ac:6c:6a:11:aa:3e:
+ ea:c1:19:32:75:67:26:fe:c0:f9:55:e9:b6:04:74:c9:e3:22:
+ 59:3a:06:5a:5f:25:6d:1d:df:48:62:a4:ee:d0:87:df:20:9d:
+ 9c:95:aa:4e:77:05:28:e6:66:ac:ae:23:e4:74:df:5a:b4:21:
+ e7:3d:0f:95:61:84:11:7e:d8:72:66:dd:85:c7:41:fe:44:12:
+ da:4c:c7:1b:ab:7d:4b:3d:c4:38:2d:b9:54:8a:26:1e:76:1b:
+ f6:0b:8a:e9:fa:9f:0a:e6:cc:6d:c5:55:f1:a5:29:20:42:05:
+ d4:5a:4f:27:ab:b6:e4:c4:ea:4d:8b:97:53:67:03:75:32:1f:
+ 9d:1e:b8:72:e1:c4:5a:09:15:d7:ce:a3:59:ed:cc:4d:0f:ea:
+ c0:1d:57:1a:43:d7:7a:63:86:b0:b8:5c:4f:34:29:a4:be:90:
+ c4:6b:39:20:c9:25:96:7d:a1:cc:ee:f7:57:04:69:d7:21:66:
+ 1d:cc:4e:6c:10:1a:6e:87:11:f3:e3:ae:9e:5b:64:04:ee:ac:
+ c6:0a:24:80:e4:0a:0e:89:49:9d:0f:1d:74:b2:f6:db:7e:25:
+ a1:d0:6e:7e
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQFDGQ
+xMbQuRCe5HrivBar0l7XPQARvyULMhdXxPv2YA1afEMIiOY19zkP3NfvIhhSW94n
+NRCTq8CumBvhx0CovoQq5ml8xGgexA0pl1US+zCGo48DDNRLInasqNv9IExG6iGb
+WU/qnCBv/+F8fWRcS5FNrFYdGRJsr/KZQCGdBrmikCx7vK/+wEChBoli8/P9oAdh
+qsL54Q4TlpKsU7rtpTbJuQTnE2e8DmPcIilT4uNZq1wlzdn7Rk6RcN1BSzWHpP0s
+Zr51fgPpEmFmyxmIoWG3E7SrUabVWJzbjKIa2sNvy7axZdijo9GH2Lm7uMGD8YM4
+Kv2j9qZZ8ifx41ApAgMBAAGjgekwgeYwHQYDVR0OBBYEFAHQGfRrhrwXO/t0lQ9T
+vb1OyhDWMB8GA1UdIwQYMBaAFNOXxve55RdpbXg5dzoKrTItQKwHMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEADrathTQ9z5wvjOeQgDP2
+EplAbYl7XAjJqfxAJB4UrGxqEao+6sEZMnVnJv7A+VXptgR0yeMiWToGWl8lbR3f
+SGKk7tCH3yCdnJWqTncFKOZmrK4j5HTfWrQh5z0PlWGEEX7YcmbdhcdB/kQS2kzH
+G6t9Sz3EOC25VIomHnYb9guK6fqfCubMbcVV8aUpIEIF1FpPJ6u25MTqTYuXU2cD
+dTIfnR64cuHEWgkV186jWe3MTQ/qwB1XGkPXemOGsLhcTzQppL6QxGs5IMklln2h
+zO73VwRp1yFmHcxObBAabocR8+OunltkBO6sxgokgOQKDolJnQ8ddLL2234lodBu
+fg==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 4 (0x4)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 2 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:bf:ca:00:55:10:61:e4:0e:a3:f8:57:b8:7b:19:
+ 34:5a:77:b8:06:39:88:07:0c:ec:d0:3b:4a:53:02:
+ 3c:d1:d3:da:48:ae:8a:1a:1c:3d:30:bb:b3:36:80:
+ a1:6f:cd:32:fd:54:26:b9:77:d7:1e:11:30:6c:eb:
+ d7:11:9a:d9:af:54:7e:0e:37:c3:8d:f3:0a:5d:ec:
+ 82:d6:6e:f3:46:f4:2a:82:24:e4:28:38:c2:fa:6a:
+ a6:f7:38:cd:94:50:20:bd:ee:50:9e:3a:a3:40:1a:
+ 49:77:eb:b2:05:8c:01:46:e6:ef:8f:55:91:0a:7a:
+ 44:10:62:b8:9f:3e:81:31:ae:08:95:29:37:47:53:
+ ec:f3:c7:9c:f0:be:64:70:b3:81:f0:04:f4:a4:aa:
+ 41:ad:16:8f:13:31:af:9b:eb:55:dc:93:6d:56:cf:
+ d6:f0:0a:fb:11:9e:32:59:d4:07:28:e1:fe:60:73:
+ bf:43:bf:ff:c9:dc:f2:ca:3a:e1:0c:bd:90:0b:c2:
+ ab:91:d5:2e:72:5d:5e:f0:f8:45:7b:3d:37:89:d1:
+ 16:bd:9b:4f:c9:c4:34:c7:c4:23:a4:04:4b:13:db:
+ 1a:b5:82:d0:f6:cd:99:fe:f3:0d:98:81:65:5e:2f:
+ 9e:a4:c1:5b:2b:67:b5:07:2a:24:a6:e7:06:5f:49:
+ d6:d5
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ D3:97:C6:F7:B9:E5:17:69:6D:78:39:77:3A:0A:AD:32:2D:40:AC:07
+ X509v3 Authority Key Identifier:
+ keyid:64:90:93:CD:AC:C7:37:36:4D:6B:14:D6:67:D0:54:3A:59:45:3A:FC
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ d2:35:f4:84:23:56:e3:2f:d1:54:fa:eb:85:02:e1:b7:aa:94:
+ a9:73:95:1d:29:9a:35:64:ac:4a:28:a3:87:24:e1:cd:3e:9f:
+ 53:14:92:ce:86:d6:ae:d5:3f:1d:97:59:ae:c4:1c:ae:78:29:
+ d7:45:a5:14:58:b6:ac:28:3e:20:e6:27:56:22:b2:bf:80:24:
+ 8d:bd:ef:17:67:8f:59:74:8b:7e:41:f1:fc:4d:a8:7b:d4:cf:
+ 0c:ec:41:c6:7a:2b:fc:c3:c2:92:dc:49:f6:7a:3d:bd:b0:41:
+ 0c:d3:0c:dd:58:1a:42:62:80:10:ad:95:ec:a0:8a:cb:b4:b8:
+ 8e:5d:45:c7:d2:82:4b:eb:cb:1a:0e:f5:40:46:0d:dd:35:a3:
+ 9b:d1:3e:55:95:b1:ab:96:63:31:ac:01:b4:ef:20:bc:0d:86:
+ 88:b2:e5:94:64:6b:f1:1a:73:3e:09:b0:4c:57:87:3a:65:5a:
+ 84:17:af:1c:cd:a5:4e:72:8e:19:8b:50:0a:97:4b:df:69:2c:
+ 4c:21:d4:d1:7e:81:74:94:60:5b:b0:5e:56:53:14:b4:52:3d:
+ c9:45:a5:47:10:74:15:86:a0:52:ba:ff:b5:32:01:ef:dd:0e:
+ 17:d6:73:35:aa:1e:ca:9a:8b:2e:28:cf:fa:1b:79:be:a7:87:
+ 4b:b4:0a:26
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBBDANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMjEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv8oAVRBh
+5A6j+Fe4exk0Wne4BjmIBwzs0DtKUwI80dPaSK6KGhw9MLuzNoChb80y/VQmuXfX
+HhEwbOvXEZrZr1R+DjfDjfMKXeyC1m7zRvQqgiTkKDjC+mqm9zjNlFAgve5Qnjqj
+QBpJd+uyBYwBRubvj1WRCnpEEGK4nz6BMa4IlSk3R1Ps88ec8L5kcLOB8AT0pKpB
+rRaPEzGvm+tV3JNtVs/W8Ar7EZ4yWdQHKOH+YHO/Q7//ydzyyjrhDL2QC8KrkdUu
+cl1e8PhFez03idEWvZtPycQ0x8QjpARLE9satYLQ9s2Z/vMNmIFlXi+epMFbK2e1
+ByokpucGX0nW1QIDAQABo4HLMIHIMB0GA1UdDgQWBBTTl8b3ueUXaW14OXc6Cq0y
+LUCsBzAfBgNVHSMEGDAWgBRkkJPNrMc3Nk1rFNZn0FQ6WUU6/DA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+ANI19IQjVuMv0VT664UC4beqlKlzlR0pmjVkrEooo4ck4c0+n1MUks6G1q7VPx2X
+Wa7EHK54KddFpRRYtqwoPiDmJ1Yisr+AJI297xdnj1l0i35B8fxNqHvUzwzsQcZ6
+K/zDwpLcSfZ6Pb2wQQzTDN1YGkJigBCtleygisu0uI5dRcfSgkvryxoO9UBGDd01
+o5vRPlWVsauWYzGsAbTvILwNhoiy5ZRka/Eacz4JsExXhzplWoQXrxzNpU5yjhmL
+UAqXS99pLEwh1NF+gXSUYFuwXlZTFLRSPclFpUcQdBWGoFK6/7UyAe/dDhfWczWq
+Hsqaiy4oz/obeb6nh0u0CiY=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 5 (0x5)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 2 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ea:cc:2d:c4:88:54:07:90:da:62:ef:77:23:b2:
+ 83:c9:54:06:25:70:65:43:f2:29:a3:f3:22:f2:09:
+ 92:31:25:77:79:63:4a:7f:d8:e5:1f:16:1a:25:bc:
+ d4:4b:9a:b3:a0:61:7e:c3:a5:90:32:97:5a:5b:59:
+ cf:97:d6:ac:2c:86:a7:70:ed:2d:e0:bf:e8:44:6f:
+ 41:29:55:b0:40:a8:10:d6:4d:67:2b:01:1f:7a:33:
+ 2b:ce:8f:c8:fb:54:99:e2:11:2d:75:7d:ff:f5:fb:
+ 53:e5:6b:7e:ca:b8:fc:1f:bc:8f:32:29:6d:d2:6b:
+ a1:9b:d9:7f:b2:f6:e9:18:72:fe:45:a2:23:dc:bf:
+ 5d:1e:43:5d:2b:80:2a:71:b4:cb:67:30:cc:aa:54:
+ 76:fc:4b:a3:2b:ab:99:31:66:bf:5c:09:44:e6:c9:
+ 27:42:3a:58:b5:fd:db:06:0f:11:04:0d:2d:36:4a:
+ 02:d5:50:4d:4d:7c:ed:a4:51:49:e3:fe:44:54:30:
+ 84:b6:1f:54:28:1f:9e:41:b2:20:23:75:e5:d4:e4:
+ bf:79:a6:ab:84:aa:dc:56:38:cf:2c:d3:8e:13:48:
+ 43:5a:eb:eb:3b:a0:36:d5:89:0c:68:e2:fb:8f:3a:
+ 82:ad:01:4b:f8:bb:b0:2e:3d:b7:6e:91:a3:70:9a:
+ d0:41
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 64:90:93:CD:AC:C7:37:36:4D:6B:14:D6:67:D0:54:3A:59:45:3A:FC
+ X509v3 Authority Key Identifier:
+ keyid:5D:A1:03:3D:8F:13:F9:08:AF:1E:83:6C:BC:DE:6F:A3:B5:C2:1A:EA
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 08:18:04:78:4e:5e:99:54:0e:de:99:06:87:4d:3f:7b:98:bc:
+ ac:92:ec:e2:60:54:35:c8:65:68:09:3d:8d:d9:23:ed:c3:f3:
+ 7b:fd:8a:60:fb:8b:dc:66:96:3f:69:81:5b:7c:cd:1d:cd:44:
+ 8d:3a:93:e4:18:94:c4:a8:56:6a:fd:ea:07:ce:b1:a0:05:b2:
+ cd:fd:bf:05:e6:52:2b:26:36:9d:e2:f2:25:f2:c8:27:5b:52:
+ 13:c6:3e:55:5b:72:58:34:a1:1c:5b:17:15:69:b1:82:78:a8:
+ 6b:80:81:cc:73:40:5b:c0:ad:de:a8:ec:53:4f:72:f0:1b:a6:
+ d4:ea:e6:c0:35:96:df:ef:38:15:c5:0e:e9:92:22:c4:97:0d:
+ d5:37:6f:7e:af:1f:6e:53:45:1e:3e:21:8c:25:d3:4c:aa:0d:
+ 5b:08:e1:5f:aa:dc:49:1c:84:b3:30:21:ea:b6:9c:95:d4:16:
+ 1c:9a:0b:17:47:a1:8c:7d:04:a0:e5:df:7d:e7:69:b7:81:2d:
+ 31:09:9b:ae:da:b2:1d:13:36:ad:f1:19:7e:92:6a:1b:70:01:
+ 8b:ee:88:5e:54:56:d6:dd:6e:78:b1:53:06:89:3b:e3:7e:45:
+ 2c:b5:9c:c9:92:5a:0d:c2:85:d0:e1:89:20:94:c7:ef:3c:01:
+ ab:25:5c:4b
+-----BEGIN CERTIFICATE-----
+MIIDZTCCAk2gAwIBAgIBBTANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMjEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOrMLcSIVAeQ2mLvdyOy
+g8lUBiVwZUPyKaPzIvIJkjEld3ljSn/Y5R8WGiW81Euas6BhfsOlkDKXWltZz5fW
+rCyGp3DtLeC/6ERvQSlVsECoENZNZysBH3ozK86PyPtUmeIRLXV9//X7U+Vrfsq4
+/B+8jzIpbdJroZvZf7L26Rhy/kWiI9y/XR5DXSuAKnG0y2cwzKpUdvxLoyurmTFm
+v1wJRObJJ0I6WLX92wYPEQQNLTZKAtVQTU187aRRSeP+RFQwhLYfVCgfnkGyICN1
+5dTkv3mmq4Sq3FY4zyzTjhNIQ1rr6zugNtWJDGji+486gq0BS/i7sC49t26Ro3Ca
+0EECAwEAAaOByzCByDAdBgNVHQ4EFgQUZJCTzazHNzZNaxTWZ9BUOllFOvwwHwYD
+VR0jBBgwFoAUXaEDPY8T+QivHoNsvN5vo7XCGuowNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAIGAR4Tl6Z
+VA7emQaHTT97mLyskuziYFQ1yGVoCT2N2SPtw/N7/Ypg+4vcZpY/aYFbfM0dzUSN
+OpPkGJTEqFZq/eoHzrGgBbLN/b8F5lIrJjad4vIl8sgnW1ITxj5VW3JYNKEcWxcV
+abGCeKhrgIHMc0BbwK3eqOxTT3LwG6bU6ubANZbf7zgVxQ7pkiLElw3VN29+rx9u
+U0UePiGMJdNMqg1bCOFfqtxJHISzMCHqtpyV1BYcmgsXR6GMfQSg5d9952m3gS0x
+CZuu2rIdEzat8Rl+kmobcAGL7oheVFbW3W54sVMGiTvjfkUstZzJkloNwoXQ4Ykg
+lMfvPAGrJVxL
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:a7:67:cf:1d:f5:54:e9:96:54:bc:65:8c:b7:9e:
+ 72:39:05:68:3d:44:e5:93:d8:4b:61:b1:a4:b4:b4:
+ 4c:c6:a0:92:b6:4d:06:3a:5b:b2:0a:8a:27:cb:b1:
+ e7:c3:35:47:ef:ac:2d:a7:d0:9c:b2:50:6a:58:3d:
+ 12:a4:85:dc:77:a9:08:e5:f4:1f:c0:ef:00:51:cd:
+ 68:62:d5:e5:cc:01:be:be:42:8b:35:fb:00:9c:30:
+ 84:0c:d7:35:7d:88:d1:1b:43:78:19:79:aa:06:b3:
+ ac:5c:69:a0:23:f0:69:dc:89:59:97:05:df:01:ae:
+ 5b:8f:01:a0:78:4f:05:4e:36:ac:00:b4:8d:e8:79:
+ 05:07:f2:76:a4:63:3f:95:21:06:57:61:a9:f0:43:
+ 04:d1:92:d3:9d:bb:b3:8f:5b:ef:ab:81:a0:23:11:
+ 38:b5:02:b2:95:1d:ac:da:b8:36:60:d7:d7:01:6d:
+ e8:ed:32:21:b4:84:97:33:7c:67:88:0e:44:c7:12:
+ 87:85:6a:49:80:82:cb:1e:16:2b:2f:6d:98:82:a0:
+ a0:30:cc:55:df:93:65:e0:9a:08:24:8a:47:cc:69:
+ 53:3c:b7:62:fa:df:11:64:d0:3f:52:43:80:f8:cf:
+ 7b:6f:d0:65:20:fb:22:d0:43:ca:fc:fc:0f:bd:1c:
+ 42:b9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 5D:A1:03:3D:8F:13:F9:08:AF:1E:83:6C:BC:DE:6F:A3:B5:C2:1A:EA
+ X509v3 Authority Key Identifier:
+ keyid:5D:A1:03:3D:8F:13:F9:08:AF:1E:83:6C:BC:DE:6F:A3:B5:C2:1A:EA
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 7f:ec:13:f0:46:53:d5:75:08:a5:37:44:9c:47:19:9e:05:ef:
+ d6:30:68:1e:0b:c8:3c:84:93:51:36:25:48:60:56:d4:79:1f:
+ b6:2c:91:e3:6f:61:f9:e7:7d:c8:b6:7b:70:7f:27:6d:2c:38:
+ ec:73:e4:8c:86:f4:48:8e:1b:09:0d:9f:f8:5a:1f:95:ed:f1:
+ 03:ea:99:64:d6:2d:46:4e:b8:0b:67:10:98:8e:19:2e:31:e1:
+ e3:d6:fe:7c:97:e9:a3:7a:18:25:9c:d4:4f:ce:a9:11:1d:f0:
+ 53:32:8a:e8:8e:8d:80:fb:f1:c1:c1:6a:c1:cf:d2:36:a2:b1:
+ f9:32:9e:05:fd:73:1a:b9:37:e5:55:b2:1e:78:84:a5:04:45:
+ 4a:d5:24:ad:20:39:fe:ab:ce:38:dd:c0:1e:2f:dd:ce:b4:5c:
+ 49:1d:ab:7a:e1:bd:e9:a6:d2:02:64:8a:a9:97:36:89:42:c2:
+ 82:14:ec:aa:dd:77:be:b1:d6:d2:4f:8b:a4:fe:5b:06:28:1c:
+ 2f:4e:83:15:1f:10:a9:c6:ce:8e:a6:ca:bb:2c:01:6a:ae:99:
+ 59:44:05:fc:a5:7e:fe:73:5f:df:b5:0b:48:b5:43:b6:10:9f:
+ 42:2e:8b:65:f6:47:25:27:66:ef:a6:a0:ca:d3:cc:9c:ac:2d:
+ 22:5b:87:5c
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKdnzx31VOmWVLxljLee
+cjkFaD1E5ZPYS2GxpLS0TMagkrZNBjpbsgqKJ8ux58M1R++sLafQnLJQalg9EqSF
+3HepCOX0H8DvAFHNaGLV5cwBvr5CizX7AJwwhAzXNX2I0RtDeBl5qgazrFxpoCPw
+adyJWZcF3wGuW48BoHhPBU42rAC0jeh5BQfydqRjP5UhBldhqfBDBNGS0527s49b
+76uBoCMROLUCspUdrNq4NmDX1wFt6O0yIbSElzN8Z4gORMcSh4VqSYCCyx4WKy9t
+mIKgoDDMVd+TZeCaCCSKR8xpUzy3YvrfEWTQP1JDgPjPe2/QZSD7ItBDyvz8D70c
+QrkCAwEAAaOByzCByDAdBgNVHQ4EFgQUXaEDPY8T+QivHoNsvN5vo7XCGuowHwYD
+VR0jBBgwFoAUXaEDPY8T+QivHoNsvN5vo7XCGuowNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB/7BPwRlPV
+dQilN0ScRxmeBe/WMGgeC8g8hJNRNiVIYFbUeR+2LJHjb2H5533ItntwfydtLDjs
+c+SMhvRIjhsJDZ/4Wh+V7fED6plk1i1GTrgLZxCYjhkuMeHj1v58l+mjehglnNRP
+zqkRHfBTMorojo2A+/HBwWrBz9I2orH5Mp4F/XMauTflVbIeeISlBEVK1SStIDn+
+q8443cAeL93OtFxJHat64b3pptICZIqplzaJQsKCFOyq3Xe+sdbST4uk/lsGKBwv
+ToMVHxCpxs6Opsq7LAFqrplZRAX8pX7+c1/ftQtItUO2EJ9CLotl9kclJ2bvpqDK
+08ycrC0iW4dc
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/non-self-signed-root.pem b/chromium/net/data/verify_certificate_chain_unittest/non-self-signed-root.pem
index 11dddad4fe4..bc2fec46393 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/non-self-signed-root.pem
+++ b/chromium/net/data/verify_certificate_chain_unittest/non-self-signed-root.pem
@@ -1,6 +1,6 @@
-[Created by: ./generate-non-self-signed-root.py]
+[Created by: generate-non-self-signed-root.py]
-Certificate chain with 1 intermediary and a trusted root. The trusted root
+Certificate chain with 1 intermediate and a trusted root. The trusted root
is NOT self signed, however its issuer is not included in the chain or root
store. Verification is expected to succeed since the root is trusted.
@@ -9,7 +9,7 @@ Certificate:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
+ Issuer: CN=Intermediate
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
@@ -18,80 +18,80 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:c2:27:87:8d:77:16:37:79:6a:b5:5d:e7:ee:9f:
- a4:5e:f6:f3:9e:a0:f9:9c:05:1a:5f:67:d8:72:c7:
- 89:73:a5:21:d5:d6:df:39:0d:f7:e7:cb:1e:82:ec:
- ae:15:ee:5a:bf:57:12:29:b2:44:8b:40:4b:d6:ea:
- a5:34:05:34:5f:37:2e:32:c0:ed:6a:0c:21:ac:c5:
- 16:80:61:96:e1:82:e3:15:62:34:23:0a:de:ca:ee:
- 43:f8:3a:e7:42:5f:3a:79:f4:bc:cf:e7:da:c4:3a:
- d6:d0:5f:bf:13:58:e7:69:0f:bc:38:7c:05:82:a9:
- 92:b8:eb:f5:fb:2a:53:ef:5d:12:5e:dc:55:12:b1:
- 66:67:3f:7c:00:89:b9:50:ea:9c:7f:90:48:02:40:
- b3:f5:98:0d:73:ca:d8:f7:3d:0b:48:fe:99:12:90:
- 92:37:93:34:5b:75:60:1c:16:c2:98:ec:2f:9a:f8:
- e3:1f:8d:56:ea:c6:35:14:67:66:21:e5:83:69:59:
- ce:c3:a6:f5:1e:94:e8:14:ce:73:83:52:af:ed:df:
- 63:58:d2:45:07:87:18:ec:7c:11:85:c8:22:b8:ff:
- b2:6d:05:2c:70:86:d1:5b:f9:8a:94:22:73:58:f1:
- 9e:b2:4f:ea:50:7e:7c:db:2e:6a:ab:bc:b5:73:b5:
- 49:3f
+ 00:a5:fd:12:f2:87:40:5c:07:a7:7c:a8:7a:2c:2c:
+ 9e:de:bc:e5:8e:c6:55:90:ce:5d:a9:e6:c8:7d:5a:
+ 9f:b1:f7:32:b4:90:9c:80:12:a2:43:fa:71:95:54:
+ 76:45:b3:28:cc:93:05:f1:f4:e9:5d:1d:4e:5d:1a:
+ a1:ad:a5:4b:4f:50:7a:c2:cd:63:2c:de:5d:54:74:
+ 09:8b:d2:5b:1f:0e:49:b4:ce:cc:24:f4:9d:f7:ca:
+ 65:6e:58:02:c0:8d:06:35:81:01:b1:2d:37:07:1e:
+ 9b:07:fa:a3:12:6b:32:bb:98:f1:41:03:2f:17:b5:
+ 5a:d3:bd:b0:2a:0c:be:2f:34:29:ba:87:44:a5:d9:
+ b7:1c:c0:ff:c5:dd:bf:21:78:38:71:ce:7a:54:d1:
+ 97:d9:aa:86:84:eb:2c:17:bf:61:1b:4b:10:54:a2:
+ a1:a6:ec:01:04:f8:f3:c8:6c:2f:30:15:e0:da:94:
+ 49:98:01:de:e6:c4:04:57:bb:f5:6d:09:53:e1:ff:
+ 76:94:cc:ba:2c:74:70:b7:f9:d4:10:35:8a:b0:8c:
+ 4c:5b:5f:5c:db:e3:a5:b6:c9:d5:b4:13:7c:17:77:
+ fd:ac:0d:65:fb:0a:a4:d4:0e:a5:2e:8f:ef:0d:5c:
+ c1:9b:00:c1:dd:0d:4f:c3:7e:3b:3b:a7:4a:d2:99:
+ f0:e3
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 0B:2F:1A:F2:F7:59:E8:BE:B9:20:D5:71:5F:D3:A1:CA:FB:88:4B:65
+ 8E:F7:4C:4C:A6:3A:4A:DA:FB:BE:DE:D3:24:D2:56:B5:3D:55:43:18
X509v3 Authority Key Identifier:
- keyid:A5:03:4B:C2:60:A5:9F:86:00:2A:8E:36:33:89:B2:7B:17:24:C2:BC
+ keyid:25:1D:DB:44:41:CD:DE:76:AA:96:3B:9B:5B:17:24:39:86:B7:DD:E0
Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
X509v3 CRL Distribution Points:
Full Name:
- URI:http://url-for-crl/Intermediary.crl
+ URI:http://url-for-crl/Intermediate.crl
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 12:45:9a:a3:e1:5b:0d:8f:1c:b7:39:60:63:7a:e0:fd:34:46:
- 7e:44:1b:32:44:c7:7f:03:fb:94:68:a2:6b:a1:7f:06:c2:60:
- 8d:be:65:fc:a3:45:f9:15:2c:17:16:25:98:03:a2:85:88:b6:
- 4b:4d:86:26:ae:8a:0b:43:46:cd:cc:a3:28:5f:44:3c:92:8a:
- ae:f3:de:02:93:1b:b7:a3:8e:6e:79:d5:a0:09:d2:c4:65:ff:
- 1b:f5:80:16:66:20:c7:1d:0c:af:32:ff:ec:f6:a4:0f:53:79:
- 41:0c:b6:57:9f:b9:1b:81:9c:56:29:3e:62:f6:f5:75:9f:97:
- ff:0a:9f:5c:c8:58:f5:d0:e7:ad:c1:4b:ba:62:c1:a3:c6:59:
- 9a:01:11:46:40:c1:54:b6:23:ae:33:58:f9:05:6b:f2:32:0d:
- 09:2e:5f:ff:74:c5:7d:ce:c9:96:a5:8d:ba:4c:d7:49:3c:8b:
- 13:73:36:05:12:56:bf:f8:ad:b5:7a:0a:82:ca:bc:b4:00:d2:
- 9f:39:88:2b:b8:d0:c0:49:8a:f6:3a:e3:3e:3e:fe:b4:4e:20:
- 1e:60:e8:cb:4d:18:80:94:26:47:bf:be:49:8a:2d:e2:41:4a:
- cd:c3:7e:23:82:90:ba:43:a6:8b:7e:b3:57:f8:ec:59:3c:97:
- 38:52:a0:0d
+ 6e:29:ba:73:d2:ce:13:e8:a8:61:cc:1c:c9:63:c3:e5:62:72:
+ 3d:bd:19:d9:10:ce:04:5c:b4:1a:0c:52:c6:57:4d:d0:a7:2d:
+ a7:11:90:78:72:8c:1c:56:4f:e4:be:4e:de:6e:f3:e1:eb:7e:
+ 9c:05:86:e4:f2:22:69:7b:7d:43:df:4e:a9:11:4d:8a:68:33:
+ a3:7d:9b:b1:04:9c:c2:bf:d4:9f:78:d9:8f:a5:51:9a:20:8a:
+ 79:c8:40:49:e4:30:d1:b9:9b:09:5e:3d:5e:93:f5:84:e5:2b:
+ 9f:1e:56:1c:2d:ef:09:34:8c:db:a0:b6:f0:91:88:91:6b:1f:
+ 4e:86:11:b6:62:33:63:8b:03:b2:40:d2:b8:28:33:e1:33:5d:
+ ae:e4:0c:08:4b:ab:05:08:6c:4a:b2:b7:cd:cd:28:7f:4a:5c:
+ 4c:9d:fa:93:c7:00:fa:47:4e:00:ca:2d:2b:c9:ed:da:e8:33:
+ 23:b6:98:f1:e5:6f:1b:cc:8b:e2:27:b2:1d:46:53:39:29:45:
+ 46:1a:50:94:c0:e7:5e:a4:ef:a3:ee:13:7a:81:89:e2:4e:f9:
+ 5e:1c:e3:ee:fe:d9:6d:7b:85:c6:99:ed:b0:30:d4:ef:16:65:
+ 1f:37:d9:f9:c1:54:c2:d9:18:3f:e9:89:a3:28:6a:ad:fc:a2:
+ 01:b8:82:d3
-----BEGIN CERTIFICATE-----
MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCJ4eN
-dxY3eWq1Xefun6Re9vOeoPmcBRpfZ9hyx4lzpSHV1t85Dffnyx6C7K4V7lq/VxIp
-skSLQEvW6qU0BTRfNy4ywO1qDCGsxRaAYZbhguMVYjQjCt7K7kP4OudCXzp59LzP
-59rEOtbQX78TWOdpD7w4fAWCqZK46/X7KlPvXRJe3FUSsWZnP3wAiblQ6px/kEgC
-QLP1mA1zytj3PQtI/pkSkJI3kzRbdWAcFsKY7C+a+OMfjVbqxjUUZ2Yh5YNpWc7D
-pvUelOgUznODUq/t32NY0kUHhxjsfBGFyCK4/7JtBSxwhtFb+YqUInNY8Z6yT+pQ
-fnzbLmqrvLVztUk/AgMBAAGjgekwgeYwHQYDVR0OBBYEFAsvGvL3Wei+uSDVcV/T
-ocr7iEtlMB8GA1UdIwQYMBaAFKUDS8JgpZ+GACqONjOJsnsXJMK8MD8GCCsGAQUF
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCl/RLy
+h0BcB6d8qHosLJ7evOWOxlWQzl2p5sh9Wp+x9zK0kJyAEqJD+nGVVHZFsyjMkwXx
+9OldHU5dGqGtpUtPUHrCzWMs3l1UdAmL0lsfDkm0zswk9J33ymVuWALAjQY1gQGx
+LTcHHpsH+qMSazK7mPFBAy8XtVrTvbAqDL4vNCm6h0Sl2bccwP/F3b8heDhxznpU
+0ZfZqoaE6ywXv2EbSxBUoqGm7AEE+PPIbC8wFeDalEmYAd7mxARXu/VtCVPh/3aU
+zLosdHC3+dQQNYqwjExbX1zb46W2ydW0E3wXd/2sDWX7CqTUDqUuj+8NXMGbAMHd
+DU/Dfjs7p0rSmfDjAgMBAAGjgekwgeYwHQYDVR0OBBYEFI73TEymOkra+77e0yTS
+VrU9VUMYMB8GA1UdIwQYMBaAFCUd20RBzd52qpY7m1sXJDmGt93gMD8GCCsGAQUF
BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAEkWao+FbDY8ctzlgY3rg
-/TRGfkQbMkTHfwP7lGiia6F/BsJgjb5l/KNF+RUsFxYlmAOihYi2S02GJq6KC0NG
-zcyjKF9EPJKKrvPeApMbt6OObnnVoAnSxGX/G/WAFmYgxx0MrzL/7PakD1N5QQy2
-V5+5G4GcVik+Yvb1dZ+X/wqfXMhY9dDnrcFLumLBo8ZZmgERRkDBVLYjrjNY+QVr
-8jINCS5f/3TFfc7JlqWNukzXSTyLE3M2BRJWv/ittXoKgsq8tADSnzmIK7jQwEmK
-9jrjPj7+tE4gHmDoy00YgJQmR7++SYot4kFKzcN+I4KQukOmi36zV/jsWTyXOFKg
-DQ==
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAbim6c9LOE+ioYcwcyWPD
+5WJyPb0Z2RDOBFy0GgxSxldN0KctpxGQeHKMHFZP5L5O3m7z4et+nAWG5PIiaXt9
+Q99OqRFNimgzo32bsQScwr/Un3jZj6VRmiCKechASeQw0bmbCV49XpP1hOUrnx5W
+HC3vCTSM26C28JGIkWsfToYRtmIzY4sDskDSuCgz4TNdruQMCEurBQhsSrK3zc0o
+f0pcTJ36k8cA+kdOAMotK8nt2ugzI7aY8eVvG8yL4ieyHUZTOSlFRhpQlMDnXqTv
+o+4TeoGJ4k75Xhzj7v7ZbXuFxpntsDDU7xZlHzfZ+cFUwtkYP+mJoyhqrfyiAbiC
+0w==
-----END CERTIFICATE-----
Certificate:
@@ -103,35 +103,35 @@ Certificate:
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
+ Subject: CN=Intermediate
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:b0:65:a4:4b:a6:56:90:82:42:cf:e8:65:86:d1:
- 96:7f:13:8d:b9:46:5a:16:ce:c2:fa:0d:52:ae:93:
- 62:dc:72:05:a2:31:b7:29:88:77:31:c3:2e:3f:4d:
- 17:16:08:3a:96:d2:49:1b:bf:0f:a0:56:ac:d2:5a:
- b8:ff:e3:46:f1:56:83:c3:72:32:8a:7d:f6:55:a5:
- 05:8a:68:ca:2e:9b:2a:80:63:4d:fd:46:f2:9f:c9:
- 95:43:06:79:c4:88:78:b3:73:fb:05:0c:4f:57:75:
- 9c:ef:eb:9f:b3:5e:65:b6:b3:b1:b7:8d:1c:c4:d9:
- 03:76:72:4f:b8:4f:dc:36:19:4c:62:d8:0c:e4:c1:
- 9b:9f:0c:3e:e2:54:69:f5:a6:53:a1:16:88:be:ee:
- a8:3e:20:28:3d:a9:3c:12:41:cc:91:ca:b7:fc:d7:
- 15:d3:1c:63:9e:7b:1d:c4:b4:08:65:2e:bc:b5:61:
- b8:84:de:3b:69:05:9c:52:6e:60:d1:79:17:36:69:
- 06:21:ed:43:07:bf:21:28:0a:6b:48:79:53:21:da:
- 02:07:79:b6:30:4c:f2:6f:9f:30:55:a2:20:ae:cf:
- 8c:ac:c6:b0:30:b0:01:80:83:ed:b0:5a:9b:92:35:
- d9:7d:51:c5:f5:76:1e:c5:53:c1:33:71:41:35:40:
- 55:d7
+ 00:dd:9f:7d:91:ef:30:35:17:fe:58:20:b0:99:23:
+ d3:ce:e4:f6:b2:05:82:69:5b:4c:e4:94:40:41:ad:
+ d6:6b:b3:44:08:50:be:9f:b3:f4:26:d6:10:50:52:
+ e3:a4:71:bd:3d:ed:f0:a8:30:da:21:06:aa:d9:ae:
+ 62:51:ed:06:c1:6e:f5:e2:23:a8:62:db:04:b7:0f:
+ 69:84:39:1f:3d:46:28:ae:a0:56:fe:aa:9b:68:0e:
+ 30:65:6a:38:f8:a6:66:12:78:99:cc:8e:c9:80:15:
+ ab:5a:66:75:71:42:4d:8c:32:2c:15:a7:6d:c9:51:
+ c8:d8:88:28:56:03:e4:ab:98:3b:52:d9:01:f0:4d:
+ 18:71:cf:d3:82:cb:62:af:6c:12:8a:a2:4b:44:c7:
+ a7:61:fd:d6:34:89:c6:f0:6e:2c:77:fd:cc:93:a9:
+ 90:5b:85:e7:46:1c:04:41:3d:df:02:79:c3:e6:98:
+ 66:28:b0:39:9b:59:ce:5e:8c:d1:63:b1:28:a3:05:
+ a3:79:93:3a:dd:92:8b:d2:07:15:96:61:27:98:ae:
+ 53:78:3f:da:79:09:01:e7:dc:03:c4:05:8f:e5:52:
+ b3:bc:d8:8f:6d:0a:89:21:a6:cf:b5:db:1c:65:67:
+ 4c:5f:5e:33:24:d7:3c:3e:61:ce:9a:4e:6e:e7:a5:
+ 30:9f
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- A5:03:4B:C2:60:A5:9F:86:00:2A:8E:36:33:89:B2:7B:17:24:C2:BC
+ 25:1D:DB:44:41:CD:DE:76:AA:96:3B:9B:5B:17:24:39:86:B7:DD:E0
X509v3 Authority Key Identifier:
- keyid:D4:83:FC:D5:EF:E0:C4:8E:32:6D:A2:30:65:12:B4:CD:3A:B2:95:88
+ keyid:63:A2:D5:4E:83:BA:38:5F:50:C5:93:E5:5C:93:9D:DE:55:08:73:A9
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -146,41 +146,41 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 67:ed:d6:55:16:b2:0d:af:79:6e:53:48:70:4c:93:be:5e:ed:
- 50:ea:d7:92:e4:7c:6c:78:05:0c:00:90:15:de:10:18:e5:cc:
- 50:24:23:e6:3e:5f:b0:f4:6f:f9:74:44:db:38:d1:45:c5:84:
- 59:58:cc:b6:f9:e9:1f:ed:41:e8:b9:aa:4b:d8:6e:88:76:d9:
- 2f:44:bf:5d:4f:6e:72:8f:b8:35:d3:e6:a3:a2:ef:3d:e6:f3:
- be:90:73:a8:80:ed:72:bb:ac:20:96:38:c6:3f:d1:fe:64:3e:
- 1a:ce:21:65:cd:1f:28:54:4a:fb:44:dc:43:cc:b4:61:dd:58:
- 83:1b:08:0c:31:f6:bc:bf:02:99:45:16:88:84:68:91:13:aa:
- af:f6:6d:4e:8d:dd:26:1d:3a:35:ab:75:7e:f7:64:62:8c:b7:
- 34:f9:5b:73:9b:e9:40:12:1c:f2:32:b9:e0:8c:86:fc:f2:b0:
- 33:6d:56:f2:a0:f7:9c:ea:d7:45:41:8d:de:49:26:90:45:32:
- 35:cf:e2:ce:43:b0:af:28:35:6a:0f:86:87:2b:57:eb:88:92:
- 89:7a:9d:b5:f3:3c:46:11:56:2e:fc:73:32:56:a9:4b:c1:87:
- f7:f8:46:d5:5d:ad:b2:e7:a2:88:5d:7d:b5:68:b4:ea:a7:1f:
- 35:1d:f9:a6
+ c5:e9:f1:a5:8e:03:ae:78:a2:51:87:0b:ee:26:02:97:5e:31:
+ 41:72:f2:7c:00:46:1b:45:51:02:03:4e:16:d0:69:61:e9:7e:
+ aa:fc:5f:5e:6b:63:99:98:c0:cf:36:96:ae:82:56:70:13:33:
+ 8d:f2:00:7a:b3:50:c7:15:ad:56:1b:ab:1a:6f:27:a4:e1:65:
+ da:22:4c:11:32:02:23:30:f8:7c:63:4d:c6:3b:5f:5b:55:37:
+ 82:29:0d:74:ff:49:4c:10:25:60:4b:3f:e8:06:1f:47:67:38:
+ 26:df:c4:92:d8:c4:9a:c8:bd:e6:1f:b9:52:2e:70:f7:21:48:
+ 43:6b:f5:40:07:c7:fd:15:51:80:54:c6:c8:74:14:a9:56:bd:
+ ad:b4:d4:da:a3:1d:b4:c4:91:73:0a:3d:1e:71:e0:97:e2:d4:
+ 79:8d:00:42:a7:8a:28:a2:2c:49:94:3f:23:e6:66:75:42:88:
+ 66:e5:98:14:b0:8d:76:d3:80:32:60:e9:05:18:65:ff:c8:4d:
+ 3b:ea:b3:d1:77:1b:7f:d1:99:c9:b5:58:72:ea:49:d4:31:68:
+ 28:2d:04:3c:49:99:f0:3a:74:11:91:0e:82:46:84:c7:54:7c:
+ 0b:9b:1a:64:ea:e3:9c:d4:c2:b9:90:e8:0e:2c:82:8b:2a:e1:
+ d1:03:32:77
-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsGWkS6ZW
-kIJCz+hlhtGWfxONuUZaFs7C+g1SrpNi3HIFojG3KYh3McMuP00XFgg6ltJJG78P
-oFas0lq4/+NG8VaDw3Iyin32VaUFimjKLpsqgGNN/Ubyn8mVQwZ5xIh4s3P7BQxP
-V3Wc7+ufs15ltrOxt40cxNkDdnJPuE/cNhlMYtgM5MGbnww+4lRp9aZToRaIvu6o
-PiAoPak8EkHMkcq3/NcV0xxjnnsdxLQIZS68tWG4hN47aQWcUm5g0XkXNmkGIe1D
-B78hKAprSHlTIdoCB3m2MEzyb58wVaIgrs+MrMawMLABgIPtsFqbkjXZfVHF9XYe
-xVPBM3FBNUBV1wIDAQABo4HLMIHIMB0GA1UdDgQWBBSlA0vCYKWfhgAqjjYzibJ7
-FyTCvDAfBgNVHSMEGDAWgBTUg/zV7+DEjjJtojBlErTNOrKViDA3BggrBgEFBQcB
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3Z99ke8w
+NRf+WCCwmSPTzuT2sgWCaVtM5JRAQa3Wa7NECFC+n7P0JtYQUFLjpHG9Pe3wqDDa
+IQaq2a5iUe0GwW714iOoYtsEtw9phDkfPUYorqBW/qqbaA4wZWo4+KZmEniZzI7J
+gBWrWmZ1cUJNjDIsFadtyVHI2IgoVgPkq5g7UtkB8E0Ycc/Tgstir2wSiqJLRMen
+Yf3WNInG8G4sd/3Mk6mQW4XnRhwEQT3fAnnD5phmKLA5m1nOXozRY7EoowWjeZM6
+3ZKL0gcVlmEnmK5TeD/aeQkB59wDxAWP5VKzvNiPbQqJIabPtdscZWdMX14zJNc8
+PmHOmk5u56UwnwIDAQABo4HLMIHIMB0GA1UdDgQWBBQlHdtEQc3edqqWO5tbFyQ5
+hrfd4DAfBgNVHSMEGDAWgBRjotVOg7o4X1DFk+Vck53eVQhzqTA3BggrBgEFBQcB
AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
-AGft1lUWsg2veW5TSHBMk75e7VDq15LkfGx4BQwAkBXeEBjlzFAkI+Y+X7D0b/l0
-RNs40UXFhFlYzLb56R/tQei5qkvYboh22S9Ev11PbnKPuDXT5qOi7z3m876Qc6iA
-7XK7rCCWOMY/0f5kPhrOIWXNHyhUSvtE3EPMtGHdWIMbCAwx9ry/AplFFoiEaJET
-qq/2bU6N3SYdOjWrdX73ZGKMtzT5W3Ob6UASHPIyueCMhvzysDNtVvKg95zq10VB
-jd5JJpBFMjXP4s5DsK8oNWoPhocrV+uIkol6nbXzPEYRVi78czJWqUvBh/f4RtVd
-rbLnoohdfbVotOqnHzUd+aY=
+AMXp8aWOA654olGHC+4mApdeMUFy8nwARhtFUQIDThbQaWHpfqr8X15rY5mYwM82
+lq6CVnATM43yAHqzUMcVrVYbqxpvJ6ThZdoiTBEyAiMw+HxjTcY7X1tVN4IpDXT/
+SUwQJWBLP+gGH0dnOCbfxJLYxJrIveYfuVIucPchSENr9UAHx/0VUYBUxsh0FKlW
+va201NqjHbTEkXMKPR5x4Jfi1HmNAEKniiiiLEmUPyPmZnVCiGblmBSwjXbTgDJg
+6QUYZf/ITTvqs9F3G3/Rmcm1WHLqSdQxaCgtBDxJmfA6dBGRDoJGhMdUfAubGmTq
+45zUwrmQ6A4sgosq4dEDMnc=
-----END CERTIFICATE-----
Certificate:
@@ -197,30 +197,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:a6:37:9c:ac:42:96:1c:fb:44:86:df:16:85:d2:
- de:49:73:74:b8:5b:3e:8c:34:4b:42:57:7e:7a:9a:
- fd:cf:7f:03:c7:39:22:02:3f:44:1b:62:4b:4a:1b:
- 9b:d8:8e:7b:a5:b5:92:39:a1:03:bc:3c:1a:1f:5f:
- 36:54:9d:b4:6d:98:c2:24:a9:fd:f7:6e:8e:41:18:
- e1:9b:ae:ef:61:98:5f:91:53:f0:8a:8e:d4:18:cf:
- 4f:dd:ff:75:01:16:10:f1:76:10:28:ba:70:96:8b:
- b7:ac:df:17:68:61:03:56:77:e5:bd:04:58:d8:44:
- d6:65:21:97:28:46:5d:a3:62:6d:3d:a1:03:6d:da:
- f7:46:f5:76:5c:1a:cd:19:b4:25:cd:17:d7:0e:ac:
- 6a:3c:d1:35:a0:20:cc:5e:62:7b:e1:11:d6:92:09:
- 34:3e:1d:d7:d5:27:b9:3b:5b:42:1e:11:f4:1a:2f:
- de:93:81:2f:6b:d1:9f:40:9f:d7:8e:7c:9b:37:7b:
- d8:3f:ba:e3:00:d7:f7:3c:20:0e:81:b4:df:cc:46:
- 3c:10:0d:04:8a:b5:ef:ba:e7:ec:7e:0b:98:a1:18:
- fb:39:db:2c:76:ae:1b:91:94:22:f4:35:b0:1a:73:
- 4d:7b:eb:c5:b3:80:80:74:90:79:b9:2f:fd:35:39:
- 02:ad
+ 00:d4:fa:c0:4f:fa:75:57:2e:07:a4:26:6d:43:48:
+ a2:47:06:03:dd:a3:f2:10:d1:66:21:4f:fa:28:42:
+ b9:4f:c1:f5:4c:fa:dc:ad:92:30:50:2a:ce:ac:db:
+ 05:cd:c2:19:26:b8:de:46:0e:ec:14:9b:27:92:71:
+ bd:e9:a5:28:55:eb:27:71:dc:ff:d7:2b:ea:ed:f0:
+ 5b:e3:38:bc:35:f8:7b:ec:5d:ba:67:8d:d8:8a:95:
+ bb:a2:01:32:3e:a6:d2:d3:a2:c7:70:f5:7c:fb:53:
+ 6f:b8:11:48:af:0c:a0:60:87:98:43:87:ff:d2:c2:
+ 18:b5:50:67:18:ee:06:8f:80:ff:4b:02:c6:c3:01:
+ 34:e2:7e:fa:60:62:23:2c:8a:68:ae:5a:0f:ad:1a:
+ 52:1f:7f:58:ae:9a:50:6e:fb:c7:53:1a:b6:b7:92:
+ 5d:ba:65:53:4c:73:b4:ed:c5:b5:b4:3a:f6:cb:79:
+ b3:87:f9:69:ac:29:e5:e4:bb:54:89:bf:45:bf:0c:
+ b9:83:6c:31:3e:a5:6e:7d:50:f1:68:f8:3d:ca:c2:
+ 3f:9f:5c:61:35:21:bc:6a:a2:77:2c:53:22:71:2e:
+ 96:70:f9:c2:c3:f6:3a:8c:3a:a4:00:f9:55:d4:01:
+ 6e:be:fc:f9:9a:2b:78:7e:3c:25:e9:09:87:47:5e:
+ a5:4d
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- D4:83:FC:D5:EF:E0:C4:8E:32:6D:A2:30:65:12:B4:CD:3A:B2:95:88
+ 63:A2:D5:4E:83:BA:38:5F:50:C5:93:E5:5C:93:9D:DE:55:08:73:A9
X509v3 Authority Key Identifier:
- keyid:EE:5C:5F:80:3F:59:C4:A6:5B:70:C2:1C:BA:E4:5D:40:F9:E9:60:8D
+ keyid:F9:8A:EA:DF:3D:59:DD:70:5F:B5:B8:D5:24:99:76:02:DC:6E:30:8F
Authority Information Access:
CA Issuers - URI:http://url-for-aia/ShadowRoot.cer
@@ -235,47 +235,49 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 8c:2a:1f:ee:90:15:b8:41:8b:cc:b4:45:2b:6f:5b:9e:49:f7:
- a1:9f:9e:2a:ce:8a:c3:ae:57:95:62:b5:f2:c9:a4:6a:57:49:
- 39:00:32:c4:23:4c:b8:15:21:4a:8f:0a:83:98:d8:ba:83:dc:
- da:88:4c:7e:60:21:1a:ed:75:6d:5e:5d:83:90:e0:71:23:13:
- 4f:2d:94:c0:fb:91:7f:b6:59:41:d6:b3:3e:42:ef:31:02:23:
- 18:a6:d2:9b:00:c6:8c:5a:3d:2c:cb:5e:dc:53:69:ac:71:b8:
- 68:90:62:5a:ba:2f:1f:20:9d:77:f3:b0:aa:2e:52:61:a5:60:
- 53:5b:5c:ab:c9:56:7e:01:4c:bf:26:ab:13:47:c1:28:72:13:
- a5:d8:b8:4c:65:09:9f:7f:a1:67:93:fc:0d:71:a3:4c:1d:3f:
- 95:9c:4a:28:8d:52:0d:48:fe:34:04:c2:d2:80:61:86:1c:e6:
- 18:cd:bb:62:ca:d2:e6:76:a8:f3:14:e3:41:75:5d:3b:e7:5a:
- 29:6c:6e:2c:bc:53:6f:39:e8:82:ab:73:d1:d5:b9:d3:f8:30:
- 5c:d7:19:d3:49:11:25:7c:01:3a:2a:a6:7f:19:b3:08:bf:0f:
- dc:4f:7b:fa:5b:20:b8:7e:eb:ea:8f:0a:56:c4:16:cd:e1:2b:
- a2:bb:66:f0
------BEGIN TRUSTED_CERTIFICATE-----
+ ce:fc:9e:82:80:f8:42:20:0d:93:e5:35:7d:8b:44:89:7b:dd:
+ a6:2b:dd:69:ee:16:da:2c:98:76:31:ae:7e:b3:c2:30:e5:9d:
+ 6b:be:11:48:70:d8:bd:d6:01:22:93:c7:14:da:0f:46:2f:98:
+ e7:b1:0b:33:10:75:77:3e:3a:e4:ba:ee:10:98:bd:b3:0a:34:
+ f7:85:09:d2:73:d4:7f:61:e1:5d:e4:eb:d6:7b:c6:f3:a9:a0:
+ 4d:15:46:f9:de:c5:31:10:5b:87:c4:58:99:51:64:7e:0b:31:
+ 22:73:ca:54:34:bd:e6:30:44:0a:59:01:ba:1a:7a:e6:83:76:
+ 3c:5e:8b:d4:06:72:b6:a8:62:07:eb:01:97:02:2d:69:95:4a:
+ 2b:77:27:a3:30:e5:22:7d:96:81:c9:ba:90:22:f4:fe:6c:bc:
+ a2:eb:96:81:4c:1a:83:4f:af:9e:21:77:5e:68:87:f3:eb:f8:
+ 10:7d:38:00:9b:83:0c:2d:9f:7f:b8:93:23:c4:f4:b2:77:c7:
+ cf:1d:bb:12:e4:30:f3:bb:5c:ec:82:1c:47:bf:31:93:93:b2:
+ a0:6f:f8:d2:ec:67:7e:95:4e:f5:eb:d4:64:c5:32:2c:0f:b4:
+ 6c:e4:64:ef:b5:a5:07:cf:f8:b2:f1:c9:67:10:e6:1a:0d:a3:
+ 9c:44:65:6e
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
MIIDdzCCAl+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDDApTaGFk
b3dSb290MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UE
-AwwEUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKY3nKxClhz7
-RIbfFoXS3klzdLhbPow0S0JXfnqa/c9/A8c5IgI/RBtiS0obm9iOe6W1kjmhA7w8
-Gh9fNlSdtG2YwiSp/fdujkEY4Zuu72GYX5FT8IqO1BjPT93/dQEWEPF2ECi6cJaL
-t6zfF2hhA1Z35b0EWNhE1mUhlyhGXaNibT2hA23a90b1dlwazRm0Jc0X1w6sajzR
-NaAgzF5ie+ER1pIJND4d19UnuTtbQh4R9Bov3pOBL2vRn0Cf1458mzd72D+64wDX
-9zwgDoG038xGPBANBIq177rn7H4LmKEY+znbLHauG5GUIvQ1sBpzTXvrxbOAgHSQ
-ebkv/TU5Aq0CAwEAAaOB1zCB1DAdBgNVHQ4EFgQU1IP81e/gxI4ybaIwZRK0zTqy
-lYgwHwYDVR0jBBgwFoAU7lxfgD9ZxKZbcMIcuuRdQPnpYI0wPQYIKwYBBQUHAQEE
+AwwEUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANT6wE/6dVcu
+B6QmbUNIokcGA92j8hDRZiFP+ihCuU/B9Uz63K2SMFAqzqzbBc3CGSa43kYO7BSb
+J5JxvemlKFXrJ3Hc/9cr6u3wW+M4vDX4e+xdumeN2IqVu6IBMj6m0tOix3D1fPtT
+b7gRSK8MoGCHmEOH/9LCGLVQZxjuBo+A/0sCxsMBNOJ++mBiIyyKaK5aD60aUh9/
+WK6aUG77x1MatreSXbplU0xztO3FtbQ69st5s4f5aawp5eS7VIm/Rb8MuYNsMT6l
+bn1Q8Wj4PcrCP59cYTUhvGqidyxTInEulnD5wsP2Oow6pAD5VdQBbr78+ZoreH48
+JekJh0depU0CAwEAAaOB1zCB1DAdBgNVHQ4EFgQUY6LVToO6OF9QxZPlXJOd3lUI
+c6kwHwYDVR0jBBgwFoAU+Yrq3z1Z3XBftbjVJJl2AtxuMI8wPQYIKwYBBQUHAQEE
MTAvMC0GCCsGAQUFBzAChiFodHRwOi8vdXJsLWZvci1haWEvU2hhZG93Um9vdC5j
ZXIwMgYDVR0fBCswKTAnoCWgI4YhaHR0cDovL3VybC1mb3ItY3JsL1NoYWRvd1Jv
b3QuY3JsMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
-DQEBCwUAA4IBAQCMKh/ukBW4QYvMtEUrb1ueSfehn54qzorDrleVYrXyyaRqV0k5
-ADLEI0y4FSFKjwqDmNi6g9zaiEx+YCEa7XVtXl2DkOBxIxNPLZTA+5F/tllB1rM+
-Qu8xAiMYptKbAMaMWj0sy17cU2mscbhokGJaui8fIJ1387CqLlJhpWBTW1yryVZ+
-AUy/JqsTR8EochOl2LhMZQmff6Fnk/wNcaNMHT+VnEoojVINSP40BMLSgGGGHOYY
-zbtiytLmdqjzFONBdV0751opbG4svFNvOeiCq3PR1bnT+DBc1xnTSRElfAE6KqZ/
-GbMIvw/cT3v6WyC4fuvqjwpWxBbN4Suiu2bw
------END TRUSTED_CERTIFICATE-----
+DQEBCwUAA4IBAQDO/J6CgPhCIA2T5TV9i0SJe92mK91p7hbaLJh2Ma5+s8Iw5Z1r
+vhFIcNi91gEik8cU2g9GL5jnsQszEHV3Pjrkuu4QmL2zCjT3hQnSc9R/YeFd5OvW
+e8bzqaBNFUb53sUxEFuHxFiZUWR+CzEic8pUNL3mMEQKWQG6Gnrmg3Y8XovUBnK2
+qGIH6wGXAi1plUordyejMOUifZaBybqQIvT+bLyi65aBTBqDT6+eIXdeaIfz6/gQ
+fTgAm4MMLZ9/uJMjxPSyd8fPHbsS5DDzu1zsghxHvzGTk7Kgb/jS7Gd+lU7169Rk
+xTIsD7Rs5GTvtaUHz/iy8clnEOYaDaOcRGVu
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+150302120000Z
-----BEGIN TIME-----
MTUwMzAyMTIwMDAwWg==
-----END TIME-----
+SUCCESS
-----BEGIN VERIFY_RESULT-----
U1VDQ0VTUw==
-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/rebase-errors.py b/chromium/net/data/verify_certificate_chain_unittest/rebase-errors.py
new file mode 100755
index 00000000000..537052afd6f
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/rebase-errors.py
@@ -0,0 +1,177 @@
+#!/usr/bin/python
+# Copyright (c) 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Helper script to update the test error expectations based on actual results.
+
+This is useful for regenerating test expectations after making changes to the
+error format.
+
+To use this run the affected tests, and then pass the input to this script
+(either via stdin, or as the first argument). For instance:
+
+ $ ./out/Release/net_unittests --gtest_filter="*VerifyCertificateChain*" | \
+ net/data/verify_certificate_chain_unittest/rebase-errors.py
+
+The script works by scanning the stdout looking for gtest failures when
+comparing "errors.ToDebugString()". The C++ test side should have been
+instrumented to dump out the test file's path on mismatch.
+
+This script will then update the corresponding file(s) -- a .pem file, and
+possibly an accompanying .py file.
+"""
+
+import common
+import os
+import sys
+import re
+
+
+# Regular expression to find the failed errors in test stdout.
+# * Group 1 of the match is the actual error text (backslash-escaped)
+# * Group 2 of the match is file path (relative to //src) where the expected
+# errors were read from.
+failed_test_regex = re.compile(r"""
+Value of: errors.ToDebugString\(\)
+ Actual: "(.*)"
+(?:.|\n)+?
+Test file: (.*)
+""", re.MULTILINE)
+
+
+# Regular expression to find the ERRORS block (and any text above it) in a PEM
+# file. The assumption is that ERRORS is not the very first block in the file
+# (since it looks for an -----END to precede it).
+# * Group 1 of the match is the ERRORS block content and any comments
+# immediately above it.
+errors_block_regex = re.compile(r""".*
+-----END .*?-----
+
+(.*?
+-----BEGIN ERRORS-----
+.*?
+-----END ERRORS-----
+)""", re.MULTILINE | re.DOTALL)
+
+
+def read_file_to_string(path):
+ """Reads a file entirely to a string"""
+ with open(path, 'r') as f:
+ return f.read()
+
+
+def write_string_to_file(data, path):
+ """Writes a string to a file"""
+ print "Writing file %s ..." % (path)
+ with open(path, "w") as f:
+ f.write(data)
+
+
+def get_py_path(pem_path):
+ """Returns the .py filepath used to generate the given .pem path, which may
+ or may not exist.
+
+ Some test files (notably those in verify_certificate_chain_unittest/ have a
+ "generate-XXX.py" script that builds the "XXX.pem" file. Build the path to
+ the corresponding "generate-XXX.py" (which may or may not exist)."""
+ file_name = os.path.basename(pem_path)
+ file_name_no_extension = os.path.splitext(file_name)[0]
+ py_file_name = 'generate-' + file_name_no_extension + '.py'
+ return os.path.join(os.path.dirname(pem_path), py_file_name)
+
+
+def replace_string(original, start, end, replacement):
+ """Replaces the specified range of |original| with |replacement|"""
+ return original[0:start] + replacement + original[end:]
+
+
+def fixup_pem_file(path, actual_errors):
+ """Updates the ERRORS block in the test .pem file"""
+ contents = read_file_to_string(path)
+
+ m = errors_block_regex.search(contents)
+
+ if not m:
+ contents += '\n' + common.text_data_to_pem('ERRORS', actual_errors)
+ else:
+ contents = replace_string(contents, m.start(1), m.end(1),
+ common.text_data_to_pem('ERRORS', actual_errors))
+
+ # Update the file.
+ write_string_to_file(contents, path)
+
+
+def fixup_py_file(path, actual_errors):
+ """Replaces the 'errors = XXX' section of the test's python script"""
+ contents = read_file_to_string(path)
+
+ # This assumes that the errors variable uses triple quotes.
+ prog = re.compile(r'^errors = """(.*?)"""', re.MULTILINE | re.DOTALL)
+ result = prog.search(contents)
+
+ # Replace the stuff in between the triple quotes with the actual errors.
+ contents = replace_string(contents, result.start(1), result.end(1),
+ actual_errors)
+
+ # Update the file.
+ write_string_to_file(contents, path)
+
+
+def get_src_root():
+ """Returns the path to the enclosing //src directory. This assumes the
+ current script is inside the source tree."""
+ cur_dir = os.path.dirname(os.path.realpath(__file__))
+
+ while True:
+ parent_dir, dirname = os.path.split(cur_dir)
+ # Check if it looks like the src/ root.
+ if dirname == "src" and os.path.isdir(os.path.join(cur_dir, "net")):
+ return cur_dir
+ if not parent_dir or parent_dir == cur_dir:
+ break
+ cur_dir = parent_dir
+
+ print "Couldn't find src dir"
+ sys.exit(1)
+
+
+def get_abs_path(rel_path):
+ """Converts |rel_path| (relative to src) to a full path"""
+ return os.path.join(get_src_root(), rel_path)
+
+
+def fixup_errors_for_file(actual_errors, pem_path):
+ """Updates the errors in |test_file_path| (.pem file) to match
+ |actual_errors|"""
+
+ fixup_pem_file(pem_path, actual_errors)
+
+ # If the test has a generator script update it too.
+ py_path = get_py_path(pem_path)
+ if os.path.isfile(py_path):
+ fixup_py_file(py_path, actual_errors)
+
+
+def main():
+ if len(sys.argv) > 2:
+ print 'Usage: %s [path-to-unittest-stdout]' % (sys.argv[0])
+ sys.exit(1)
+
+ # Read the input either from a file, or from stdin.
+ test_stdout = None
+ if len(sys.argv) == 2:
+ test_stdout = read_file_to_string(sys.argv[1])
+ else:
+ print 'Reading input from stdin...'
+ test_stdout = sys.stdin.read()
+
+ for m in failed_test_regex.finditer(test_stdout):
+ actual_errors = m.group(1)
+ actual_errors = actual_errors.decode('string-escape')
+ relative_test_path = m.group(2)
+ fixup_errors_for_file(actual_errors, get_abs_path(relative_test_path))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/chromium/net/data/verify_certificate_chain_unittest/target-and-intermediary.pem b/chromium/net/data/verify_certificate_chain_unittest/target-and-intermediary.pem
deleted file mode 100644
index 51446abd1fc..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/target-and-intermediary.pem
+++ /dev/null
@@ -1,280 +0,0 @@
-[Created by: generate-target-and-intermediary.py]
-
-Certificate chain with 1 intermediary and a trusted root. Verification is
-expected to succeed.
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Target
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:dc:50:a0:d0:af:3b:b6:d5:af:48:be:31:08:db:
- 91:81:c5:c8:d7:22:88:d4:74:1e:12:de:7a:79:79:
- 10:71:de:b5:8a:4e:d1:1d:46:6b:46:62:e8:de:f8:
- 01:f5:9d:6b:35:f6:a6:b7:f2:7f:4c:5f:f9:ad:10:
- f6:7e:9c:87:dc:27:e5:3f:19:1c:f0:c5:69:06:51:
- 96:bf:d0:c5:ef:b8:e3:2c:47:6a:8f:44:68:70:ed:
- 18:b9:f1:85:7b:2e:42:bc:44:5d:e3:d3:df:95:93:
- 8c:1d:ad:bc:9e:45:ad:6e:4f:78:68:6e:8f:ee:16:
- a9:6e:9d:50:6b:9c:72:a0:d7:fe:ff:68:4b:1c:df:
- 18:fd:26:fb:65:be:c9:63:30:30:15:7d:f9:83:95:
- c4:5e:2e:e5:d1:f0:ce:9c:5e:4a:6c:ec:6f:26:f6:
- 79:38:bc:15:e2:50:68:f0:46:c2:7f:7d:0a:c2:79:
- 08:b7:ea:41:18:d5:65:29:3e:6d:bb:80:8e:a2:0d:
- c3:c4:8a:e2:dd:3c:19:01:e9:ea:0c:bb:db:6c:c7:
- ed:6d:c5:7e:78:5f:5d:e2:87:d9:fa:90:3a:1d:c3:
- b6:d8:7f:78:77:7b:e8:2c:bb:ed:04:18:72:a7:0f:
- b2:ef:96:65:b4:39:a0:e9:59:b3:64:f4:db:9d:53:
- 42:9f
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 86:F0:37:63:2C:67:7D:F8:D4:71:4D:9B:A3:47:47:BA:F5:F0:0E:90
- X509v3 Authority Key Identifier:
- keyid:42:1A:C3:C4:D6:79:39:E2:20:E5:63:13:EB:41:7B:8C:0E:28:72:8E
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Intermediary.crl
-
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage:
- TLS Web Server Authentication, TLS Web Client Authentication
- Signature Algorithm: sha256WithRSAEncryption
- 4e:86:be:e0:4b:d5:15:99:49:09:6c:9a:6d:9a:82:e2:41:3e:
- 99:a5:e3:23:dd:43:d7:22:8d:c6:4f:4c:51:47:cb:32:44:b8:
- 3a:f0:b6:88:0c:fd:08:d1:ea:0d:b0:72:fe:a0:48:6b:5d:a2:
- 9e:f2:2d:12:6a:bf:68:ce:2e:d0:35:5f:da:32:c9:74:4b:29:
- 53:81:69:a1:a1:1a:de:c8:5e:c1:73:21:b6:02:81:d8:57:ef:
- 68:c3:24:f7:05:fa:ae:ed:d7:8a:62:e3:09:bf:fc:d0:41:93:
- e8:12:a5:fc:c3:46:d8:2b:f6:e3:cc:36:a7:39:cd:32:9e:9d:
- e1:79:68:ff:15:b9:10:5f:86:ad:4d:a0:dc:60:2f:1f:36:6f:
- d3:7a:60:81:c5:38:71:d0:fa:28:ae:ba:80:0e:cf:9c:ef:4d:
- 1f:d4:0c:27:0f:55:a8:49:65:c1:d6:af:6d:b1:1d:fb:90:38:
- ad:8b:5e:ba:82:68:60:2a:e4:7a:b8:07:aa:91:37:84:d6:18:
- 38:ba:37:a6:d9:bb:3b:45:da:59:8c:c5:90:11:1d:85:fe:af:
- fa:62:87:84:5d:5a:90:91:c3:6c:53:e1:d3:74:e7:51:19:b6:
- b5:e7:12:1a:73:35:34:16:dd:e4:31:62:58:de:3a:fb:40:80:
- 21:4f:f5:13
------BEGIN CERTIFICATE-----
-MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDcUKDQ
-rzu21a9IvjEI25GBxcjXIojUdB4S3np5eRBx3rWKTtEdRmtGYuje+AH1nWs19qa3
-8n9MX/mtEPZ+nIfcJ+U/GRzwxWkGUZa/0MXvuOMsR2qPRGhw7Ri58YV7LkK8RF3j
-09+Vk4wdrbyeRa1uT3hobo/uFqlunVBrnHKg1/7/aEsc3xj9JvtlvsljMDAVffmD
-lcReLuXR8M6cXkps7G8m9nk4vBXiUGjwRsJ/fQrCeQi36kEY1WUpPm27gI6iDcPE
-iuLdPBkB6eoMu9tsx+1txX54X13ih9n6kDodw7bYf3h3e+gsu+0EGHKnD7LvlmW0
-OaDpWbNk9NudU0KfAgMBAAGjgekwgeYwHQYDVR0OBBYEFIbwN2MsZ3341HFNm6NH
-R7r18A6QMB8GA1UdIwQYMBaAFEIaw8TWeTniIOVjE+tBe4wOKHKOMD8GCCsGAQUF
-BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAToa+4EvVFZlJCWyabZqC
-4kE+maXjI91D1yKNxk9MUUfLMkS4OvC2iAz9CNHqDbBy/qBIa12invItEmq/aM4u
-0DVf2jLJdEspU4FpoaEa3shewXMhtgKB2FfvaMMk9wX6ru3XimLjCb/80EGT6BKl
-/MNG2Cv248w2pznNMp6d4Xlo/xW5EF+GrU2g3GAvHzZv03pggcU4cdD6KK66gA7P
-nO9NH9QMJw9VqEllwdavbbEd+5A4rYteuoJoYCrkergHqpE3hNYYOLo3ptm7O0Xa
-WYzFkBEdhf6v+mKHhF1akJHDbFPh03TnURm2tecSGnM1NBbd5DFiWN46+0CAIU/1
-Ew==
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 2 (0x2)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:a4:16:0d:45:92:8b:7b:8e:42:07:a1:f4:01:dc:
- 31:0e:68:b4:3f:f3:b7:0d:8f:08:f4:f0:bb:2b:45:
- 37:98:b4:3b:6f:61:7c:23:2e:6e:cf:33:a3:d1:09:
- 16:74:3f:ac:4f:59:f1:92:42:35:e6:8a:e9:98:5e:
- 39:a2:0d:45:26:8f:7d:bb:ad:bf:f8:66:a3:b0:eb:
- 7f:eb:79:60:9a:70:03:5d:9f:46:a8:47:64:7d:a9:
- eb:a7:7d:77:60:3a:f5:5f:e8:bc:54:f3:d7:25:5e:
- 5b:62:3a:4a:df:f3:21:df:e4:bc:89:69:26:fa:d7:
- 24:16:f1:06:d0:57:a1:a0:aa:f2:bd:9f:0c:59:50:
- 57:c2:5d:25:24:05:eb:91:58:bb:1a:82:df:eb:03:
- ec:55:ed:d4:46:b5:fe:2e:fa:08:14:d7:76:71:99:
- 2b:34:10:2d:20:21:ed:78:91:f9:05:04:14:42:a0:
- ed:95:46:a3:a2:e6:55:1e:87:0b:1b:57:8e:e4:7c:
- c5:c5:39:83:b1:c6:91:e1:54:8a:6f:6a:9b:a5:80:
- 93:ec:00:81:6f:20:70:6c:31:95:42:76:a3:82:17:
- d8:d2:ff:3a:09:53:be:76:ea:e1:a9:fb:a9:a5:5f:
- 2b:5f:f9:5a:78:97:2e:f9:9d:31:42:2a:f9:1c:26:
- 16:7d
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 42:1A:C3:C4:D6:79:39:E2:20:E5:63:13:EB:41:7B:8C:0E:28:72:8E
- X509v3 Authority Key Identifier:
- keyid:FE:3F:EE:E8:53:09:31:CA:D4:66:C1:C7:FE:E0:74:C3:D7:81:44:5F
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- af:11:72:82:33:e5:f9:b1:10:fc:c2:4a:9e:c8:8e:b4:16:51:
- 62:8d:b5:e3:e3:c7:30:32:52:52:55:aa:6b:c4:c2:67:de:71:
- 37:2d:85:68:80:c8:b7:9b:4b:05:6f:97:e1:82:03:f4:b7:07:
- b8:c2:a8:02:7a:60:34:c8:07:9b:7e:c3:02:bd:11:26:51:b4:
- 4d:e2:6c:e4:38:bc:4c:e7:35:91:24:f1:40:6e:69:7f:ac:b4:
- ee:12:8a:1c:41:f6:96:13:93:67:c4:11:18:67:80:e6:41:ef:
- 2b:3e:47:1a:57:b1:66:ac:87:93:ed:6c:fe:a2:c4:5a:47:75:
- d0:1b:01:b6:74:b6:f8:7b:aa:e3:91:c3:45:56:2b:a4:d2:67:
- 94:18:71:e7:ea:41:14:bb:12:4e:56:d8:5a:95:89:bc:e6:89:
- be:9a:03:8c:b8:2b:18:56:7c:41:db:2d:e3:86:b5:de:aa:cb:
- 11:da:91:8f:f2:75:1d:d2:b6:0b:bd:d6:b5:65:a5:96:1a:44:
- fd:66:80:89:bf:a5:a9:c4:fb:3f:2b:cc:f5:e7:a6:e6:bd:5f:
- e3:df:51:76:e3:e8:1c:e5:53:e9:6e:cf:e8:54:5f:f3:7f:ca:
- 3a:b2:b2:07:7d:6c:29:a9:01:17:cf:f9:e8:0a:13:88:13:d3:
- ad:ac:be:ad
------BEGIN CERTIFICATE-----
-MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApBYNRZKL
-e45CB6H0AdwxDmi0P/O3DY8I9PC7K0U3mLQ7b2F8Iy5uzzOj0QkWdD+sT1nxkkI1
-5orpmF45og1FJo99u62/+GajsOt/63lgmnADXZ9GqEdkfanrp313YDr1X+i8VPPX
-JV5bYjpK3/Mh3+S8iWkm+tckFvEG0FehoKryvZ8MWVBXwl0lJAXrkVi7GoLf6wPs
-Ve3URrX+LvoIFNd2cZkrNBAtICHteJH5BQQUQqDtlUajouZVHocLG1eO5HzFxTmD
-scaR4VSKb2qbpYCT7ACBbyBwbDGVQnajghfY0v86CVO+durhqfuppV8rX/laeJcu
-+Z0xQir5HCYWfQIDAQABo4HLMIHIMB0GA1UdDgQWBBRCGsPE1nk54iDlYxPrQXuM
-DihyjjAfBgNVHSMEGDAWgBT+P+7oUwkxytRmwcf+4HTD14FEXzA3BggrBgEFBQcB
-AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
-BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
-VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
-AK8RcoIz5fmxEPzCSp7IjrQWUWKNtePjxzAyUlJVqmvEwmfecTcthWiAyLebSwVv
-l+GCA/S3B7jCqAJ6YDTIB5t+wwK9ESZRtE3ibOQ4vEznNZEk8UBuaX+stO4SihxB
-9pYTk2fEERhngOZB7ys+RxpXsWash5PtbP6ixFpHddAbAbZ0tvh7quORw0VWK6TS
-Z5QYcefqQRS7Ek5W2FqVibzmib6aA4y4KxhWfEHbLeOGtd6qyxHakY/ydR3Stgu9
-1rVlpZYaRP1mgIm/panE+z8rzPXnpua9X+PfUXbj6BzlU+luz+hUX/N/yjqysgd9
-bCmpARfP+egKE4gT062svq0=
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Root
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:ea:28:d6:83:e1:ad:7f:df:9a:70:91:b6:2a:45:
- 28:bb:1a:00:d2:1f:0c:6e:14:10:27:c0:65:c9:90:
- 40:45:83:6c:af:9a:66:ed:cb:59:2f:f7:82:67:74:
- aa:1d:73:ec:f3:98:cb:38:9c:f6:6b:4f:bc:6b:5d:
- f7:15:89:ed:02:f8:ed:17:69:df:a2:8d:ee:f5:d1:
- 84:92:42:b8:9f:fe:77:fd:d5:06:7b:6f:59:8a:2a:
- c7:32:f5:ff:ad:f9:8a:59:e7:93:11:79:fe:f6:2a:
- cb:99:db:a9:d7:05:a8:be:af:db:2e:b1:8a:56:8e:
- f7:ec:b4:b0:a3:a4:96:39:79:69:3c:3b:ce:fe:42:
- 15:a8:56:bb:88:94:42:a5:0b:04:b4:e9:fa:c9:1a:
- 14:7d:c0:82:d5:d8:3a:de:ec:6f:a6:be:5c:43:6d:
- 85:f8:84:57:cd:06:b0:e1:63:a5:ab:05:14:2f:2d:
- fb:04:99:fb:7e:ce:06:cf:3b:29:27:7a:70:1a:6b:
- fb:6a:f3:a6:23:31:dd:93:80:67:b9:09:03:92:e2:
- a9:c4:71:85:1b:a5:f9:1c:ff:86:b0:72:e3:23:58:
- 15:6c:4e:55:7f:89:91:35:0a:b3:41:ba:3c:17:76:
- da:e6:39:6e:58:92:67:9d:06:c5:c8:84:e0:61:49:
- ea:b3
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- FE:3F:EE:E8:53:09:31:CA:D4:66:C1:C7:FE:E0:74:C3:D7:81:44:5F
- X509v3 Authority Key Identifier:
- keyid:FE:3F:EE:E8:53:09:31:CA:D4:66:C1:C7:FE:E0:74:C3:D7:81:44:5F
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- 9f:ae:51:c1:f5:31:bf:30:6c:e1:b5:38:07:b5:c2:56:38:6b:
- 3c:f3:49:50:93:5f:75:9e:94:15:5c:15:0a:91:87:6a:c1:fa:
- 36:d6:4a:72:6f:cd:8c:9d:77:e7:61:96:14:88:4f:b2:71:d7:
- 81:8f:06:9f:c7:14:49:0c:de:7c:73:ba:00:c8:44:58:ac:0a:
- 4b:27:bb:3d:cb:fd:4d:14:dd:f7:61:b7:a0:f4:00:8a:ff:54:
- 6b:c0:6a:6d:21:43:b8:9b:cb:f9:ad:9d:fe:2a:09:3d:a1:dd:
- de:17:7d:6f:74:44:79:0c:12:4e:d0:68:4f:b2:35:60:ef:95:
- da:a5:25:f8:e4:4c:ea:83:38:c1:26:83:db:13:78:58:1c:50:
- e3:20:93:b0:c8:5e:a0:76:5f:c2:fe:cc:16:3d:f6:2f:33:08:
- fe:61:af:57:cd:c6:ae:8a:d2:7b:98:e8:eb:98:9b:89:ff:47:
- 24:d6:bf:a3:29:f6:e3:7e:e2:08:0b:a6:06:11:36:07:ea:61:
- 5f:58:16:d3:c1:29:b4:c8:39:7c:32:98:17:82:e7:8c:0f:2e:
- 34:bc:a3:78:62:15:29:95:4e:ca:c4:40:8b:29:2e:5c:8c:9b:
- 14:ee:90:68:08:91:ef:64:fe:8f:61:89:cd:6b:44:dd:24:cf:
- 7c:3d:a3:86
------BEGIN TRUSTED_CERTIFICATE-----
-MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOoo1oPhrX/fmnCRtipF
-KLsaANIfDG4UECfAZcmQQEWDbK+aZu3LWS/3gmd0qh1z7POYyzic9mtPvGtd9xWJ
-7QL47Rdp36KN7vXRhJJCuJ/+d/3VBntvWYoqxzL1/635ilnnkxF5/vYqy5nbqdcF
-qL6v2y6xilaO9+y0sKOkljl5aTw7zv5CFahWu4iUQqULBLTp+skaFH3AgtXYOt7s
-b6a+XENthfiEV80GsOFjpasFFC8t+wSZ+37OBs87KSd6cBpr+2rzpiMx3ZOAZ7kJ
-A5LiqcRxhRul+Rz/hrBy4yNYFWxOVX+JkTUKs0G6PBd22uY5bliSZ50GxciE4GFJ
-6rMCAwEAAaOByzCByDAdBgNVHQ4EFgQU/j/u6FMJMcrUZsHH/uB0w9eBRF8wHwYD
-VR0jBBgwFoAU/j/u6FMJMcrUZsHH/uB0w9eBRF8wNwYIKwYBBQUHAQEEKzApMCcG
-CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
-IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCfrlHB9TG/
-MGzhtTgHtcJWOGs880lQk191npQVXBUKkYdqwfo21kpyb82MnXfnYZYUiE+ycdeB
-jwafxxRJDN58c7oAyERYrApLJ7s9y/1NFN33Ybeg9ACK/1RrwGptIUO4m8v5rZ3+
-Kgk9od3eF31vdER5DBJO0GhPsjVg75XapSX45EzqgzjBJoPbE3hYHFDjIJOwyF6g
-dl/C/swWPfYvMwj+Ya9XzcauitJ7mOjrmJuJ/0ck1r+jKfbjfuIIC6YGETYH6mFf
-WBbTwSm0yDl8MpgXgueMDy40vKN4YhUplU7KxECLKS5cjJsU7pBoCJHvZP6PYYnN
-a0TdJM98PaOG
------END TRUSTED_CERTIFICATE-----
-
------BEGIN TIME-----
-MTUwMzAyMTIwMDAwWg==
------END TIME-----
-
------BEGIN VERIFY_RESULT-----
-U1VDQ0VTUw==
------END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/target-and-intermediate.pem b/chromium/net/data/verify_certificate_chain_unittest/target-and-intermediate.pem
new file mode 100644
index 00000000000..5fbfbccb98a
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/target-and-intermediate.pem
@@ -0,0 +1,282 @@
+[Created by: generate-target-and-intermediate.py]
+
+Certificate chain with 1 intermediate and a trusted root. Verification is
+expected to succeed.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:99:a4:c0:d4:dd:a9:aa:60:8b:ae:df:d6:20:ae:
+ b9:f2:f2:ae:44:0e:1f:13:9c:cc:bb:03:81:36:91:
+ 75:72:b4:f8:36:61:2b:7d:70:a9:da:e5:35:7e:e5:
+ 39:a6:fa:da:45:37:fd:77:04:af:21:c3:43:c4:15:
+ 9e:07:a1:4e:19:04:66:e7:bf:ae:76:b1:95:8a:9b:
+ b8:79:12:b7:ca:d3:ec:72:16:4b:47:08:89:1f:d5:
+ 5d:cf:e2:a6:1e:c3:c9:28:54:41:f6:68:e4:01:a9:
+ df:4a:f1:ab:d5:45:26:1a:4e:f9:f7:11:1e:c2:43:
+ 52:d9:2e:95:52:35:71:dc:6a:eb:56:ee:81:73:6a:
+ 86:5b:bd:4f:a6:8f:4b:b3:4e:35:06:d5:35:8a:aa:
+ d5:f7:bd:6a:e1:79:6a:61:37:dc:a8:06:d9:5a:31:
+ ea:3b:2e:8c:8f:de:1e:47:02:c7:ca:27:00:b9:49:
+ 7b:29:c4:f4:82:f2:bc:58:52:bb:f2:36:1c:10:4f:
+ a7:93:fa:46:d0:92:80:15:e7:b9:da:1d:70:21:2b:
+ 9c:47:9c:17:5a:26:2d:94:8a:ce:ae:ba:ac:cb:31:
+ 96:a9:e8:9e:51:73:4f:8c:bf:8c:57:d8:c8:61:0e:
+ c0:45:09:e4:56:a0:47:f9:df:97:af:9c:76:63:54:
+ c6:9b
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 05:BE:F6:16:F8:E7:6A:1B:E6:6D:6D:5A:A4:AF:01:89:8B:98:88:E3
+ X509v3 Authority Key Identifier:
+ keyid:6E:35:75:BC:3A:85:BC:B6:F7:B8:01:75:BD:9E:A8:36:8D:1E:C7:D9
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ a4:7d:30:26:06:98:4b:33:c7:b7:84:04:cb:1b:1f:29:1c:b4:
+ 44:6e:6f:b2:5e:40:ce:e9:5d:e5:3d:ed:5c:a4:34:67:08:c0:
+ 10:55:f3:c8:90:43:65:d9:fc:b9:64:43:1a:fc:cb:6c:3f:fc:
+ 2a:48:87:60:6b:95:a6:4f:d6:6f:ac:e3:39:19:54:5d:96:6b:
+ 80:15:db:e3:9f:84:90:4d:23:b1:74:f2:f8:d1:4e:8e:6b:05:
+ 2c:28:94:05:03:90:04:98:08:e3:73:34:b6:05:1e:8e:b0:52:
+ 33:cf:41:ff:99:cd:26:70:12:b1:0a:5c:c7:ed:d3:87:be:fa:
+ f1:24:34:42:22:35:a0:e5:7c:ef:18:b8:61:ce:a1:0a:99:7a:
+ 2d:3f:b9:48:36:a2:3c:5e:70:e4:36:32:a2:9d:1d:3a:37:fa:
+ bf:e4:b4:89:0d:48:e7:9d:f5:9f:48:13:ec:6a:8b:e6:b3:3f:
+ 23:f7:94:b1:2d:cf:b4:26:f4:1b:b5:01:3b:92:bb:63:4e:d6:
+ ee:ed:c0:2e:77:53:5b:3e:a5:8c:c6:b9:40:67:bb:cd:67:65:
+ 6b:41:46:7e:90:f9:2a:a7:5f:09:92:37:13:23:19:2d:66:cb:
+ 73:7e:a3:42:dd:da:ed:f6:08:8a:8a:97:ef:4b:f7:5d:22:81:
+ 82:95:87:7c
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCZpMDU
+3amqYIuu39Ygrrny8q5EDh8TnMy7A4E2kXVytPg2YSt9cKna5TV+5Tmm+tpFN/13
+BK8hw0PEFZ4HoU4ZBGbnv652sZWKm7h5ErfK0+xyFktHCIkf1V3P4qYew8koVEH2
+aOQBqd9K8avVRSYaTvn3ER7CQ1LZLpVSNXHcautW7oFzaoZbvU+mj0uzTjUG1TWK
+qtX3vWrheWphN9yoBtlaMeo7LoyP3h5HAsfKJwC5SXspxPSC8rxYUrvyNhwQT6eT
++kbQkoAV57naHXAhK5xHnBdaJi2Uis6uuqzLMZap6J5Rc0+Mv4xX2MhhDsBFCeRW
+oEf535evnHZjVMabAgMBAAGjgekwgeYwHQYDVR0OBBYEFAW+9hb452ob5m1tWqSv
+AYmLmIjjMB8GA1UdIwQYMBaAFG41dbw6hby297gBdb2eqDaNHsfZMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEApH0wJgaYSzPHt4QEyxsf
+KRy0RG5vsl5Azuld5T3tXKQ0ZwjAEFXzyJBDZdn8uWRDGvzLbD/8KkiHYGuVpk/W
+b6zjORlUXZZrgBXb45+EkE0jsXTy+NFOjmsFLCiUBQOQBJgI43M0tgUejrBSM89B
+/5nNJnASsQpcx+3Th7768SQ0QiI1oOV87xi4Yc6hCpl6LT+5SDaiPF5w5DYyop0d
+Ojf6v+S0iQ1I5531n0gT7GqL5rM/I/eUsS3PtCb0G7UBO5K7Y07W7u3ALndTWz6l
+jMa5QGe7zWdla0FGfpD5KqdfCZI3EyMZLWbLc36jQt3a7fYIioqX70v3XSKBgpWH
+fA==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d2:ee:b5:26:40:84:3d:98:ee:bc:3e:62:1a:09:
+ 5e:53:b1:72:28:f6:70:c0:a1:08:65:6f:54:24:4c:
+ fc:bf:fe:14:25:fa:5d:a5:17:f1:00:64:b3:33:6f:
+ 09:3a:0f:cc:25:87:f6:20:e4:f4:49:f3:5a:5d:a4:
+ d5:02:e7:db:20:c9:66:b4:cf:44:4d:58:4b:48:13:
+ 7b:83:60:14:28:f7:5a:5b:f8:f5:34:40:81:32:bd:
+ d2:8c:34:4f:d6:5d:5f:65:dd:74:56:7a:07:7a:82:
+ c3:0b:42:d5:cb:09:30:76:41:6e:08:28:ad:0c:27:
+ 51:9c:86:e1:fe:e8:85:68:aa:59:d0:f8:39:c2:59:
+ 6e:95:90:de:c9:f8:df:77:5e:56:3f:d5:9d:f8:09:
+ 29:ed:7c:cc:92:e7:c3:40:27:76:fc:08:4f:ae:98:
+ c9:7c:95:43:05:cc:1f:f5:b2:0b:51:ec:09:cd:22:
+ 3d:7e:e4:5a:b9:4f:86:62:76:d7:c0:42:23:bb:97:
+ e1:b3:ae:af:9d:56:89:00:68:01:b0:cb:11:cc:f4:
+ ea:cd:1e:7d:32:81:d9:93:20:00:22:ed:31:78:3c:
+ 62:de:73:3f:1d:38:17:4e:04:a2:58:45:36:26:95:
+ 93:ab:36:f1:54:01:81:b1:c2:70:f5:06:17:47:40:
+ 0e:fb
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 6E:35:75:BC:3A:85:BC:B6:F7:B8:01:75:BD:9E:A8:36:8D:1E:C7:D9
+ X509v3 Authority Key Identifier:
+ keyid:4F:DE:F3:E5:5E:F5:98:0D:CA:3A:20:2B:E9:C8:B4:5D:D0:1D:86:BF
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 10:e4:01:2e:8b:a4:ea:e0:cc:ac:c2:57:68:b7:97:98:e2:57:
+ d6:ff:e2:70:d9:de:bd:7e:44:59:da:3c:cc:1e:62:5d:a8:77:
+ 70:b5:fc:4c:21:50:b1:5f:4d:d8:dc:18:bf:d7:1e:40:fa:11:
+ 8e:40:e6:b8:38:87:a3:10:ed:97:93:ae:a6:7f:6c:cf:75:43:
+ e1:88:b9:84:b3:f3:73:05:fb:24:de:2b:f1:20:65:3f:70:25:
+ 87:4d:e0:66:73:ca:29:52:60:88:e9:e3:5f:cc:2b:83:1c:b3:
+ 8c:4d:12:7b:35:70:fd:d1:1a:08:85:94:77:39:3c:b0:c5:d7:
+ 7e:a5:71:f3:ca:a7:98:30:69:62:f6:96:d4:f9:30:07:aa:56:
+ da:ba:16:fc:1b:57:24:a0:f1:84:e2:4a:a2:97:a4:a1:82:05:
+ 1a:02:c7:41:2f:98:c8:e5:27:b4:85:98:72:d0:a0:e1:b5:c1:
+ 57:ab:aa:6b:71:79:d0:4d:91:68:18:25:f8:b4:b7:cb:1d:0c:
+ 74:6a:77:66:48:3f:24:b0:92:d9:22:6f:6e:54:b7:f8:8c:21:
+ 57:0e:a9:cc:52:ff:56:2e:42:fa:08:2e:fe:29:3c:f1:86:8b:
+ 74:88:68:82:3f:16:2d:06:12:57:a6:e2:b1:b7:1b:5d:3a:a1:
+ 75:c7:24:d7
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0u61JkCE
+PZjuvD5iGgleU7FyKPZwwKEIZW9UJEz8v/4UJfpdpRfxAGSzM28JOg/MJYf2IOT0
+SfNaXaTVAufbIMlmtM9ETVhLSBN7g2AUKPdaW/j1NECBMr3SjDRP1l1fZd10VnoH
+eoLDC0LVywkwdkFuCCitDCdRnIbh/uiFaKpZ0Pg5wllulZDeyfjfd15WP9Wd+Akp
+7XzMkufDQCd2/AhPrpjJfJVDBcwf9bILUewJzSI9fuRauU+GYnbXwEIju5fhs66v
+nVaJAGgBsMsRzPTqzR59MoHZkyAAIu0xeDxi3nM/HTgXTgSiWEU2JpWTqzbxVAGB
+scJw9QYXR0AO+wIDAQABo4HLMIHIMB0GA1UdDgQWBBRuNXW8OoW8tve4AXW9nqg2
+jR7H2TAfBgNVHSMEGDAWgBRP3vPlXvWYDco6ICvpyLRd0B2GvzA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+ABDkAS6LpOrgzKzCV2i3l5jiV9b/4nDZ3r1+RFnaPMweYl2od3C1/EwhULFfTdjc
+GL/XHkD6EY5A5rg4h6MQ7ZeTrqZ/bM91Q+GIuYSz83MF+yTeK/EgZT9wJYdN4GZz
+yilSYIjp41/MK4Mcs4xNEns1cP3RGgiFlHc5PLDF136lcfPKp5gwaWL2ltT5MAeq
+Vtq6FvwbVySg8YTiSqKXpKGCBRoCx0EvmMjlJ7SFmHLQoOG1wVerqmtxedBNkWgY
+Jfi0t8sdDHRqd2ZIPySwktkib25Ut/iMIVcOqcxS/1YuQvoILv4pPPGGi3SIaII/
+Fi0GElem4rG3G106oXXHJNc=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ba:0d:d2:51:af:0c:48:94:37:cf:ea:83:8f:d6:
+ 39:b5:c9:58:fe:59:5b:e5:61:b6:21:98:86:16:a0:
+ 85:e6:cd:c8:21:81:65:4c:65:97:55:72:76:2f:c6:
+ 0d:25:f8:c8:28:9f:20:d1:56:4c:06:99:ff:6d:0f:
+ 24:d3:92:f1:31:25:5a:13:6c:be:4b:19:6a:65:af:
+ 2f:32:be:a9:0f:f8:9b:6d:6f:10:7c:e9:24:61:4d:
+ fe:ba:e9:b5:b4:54:5e:82:f7:02:7a:e2:e2:d7:53:
+ 6a:69:f4:9a:41:27:0f:50:dc:64:a1:47:84:53:3f:
+ f1:38:cd:80:a3:5a:2b:dd:96:81:8a:ea:e3:94:72:
+ f7:aa:f8:2f:cc:a9:d0:9e:36:9f:56:0c:45:ec:dd:
+ 6a:05:52:85:60:99:d7:94:9f:76:7e:1d:8f:3f:50:
+ fb:33:bc:ca:f8:10:2e:db:15:b2:49:57:d8:f4:59:
+ fa:73:3b:03:32:86:a7:f1:46:a1:62:ac:67:10:73:
+ 70:51:07:ff:d2:04:33:d8:7c:e2:a8:ff:8e:53:24:
+ e8:e4:96:da:fb:d1:ea:2f:9c:a9:b5:8f:c5:50:fb:
+ 90:67:b1:8c:5b:8d:f7:5f:af:da:a4:fa:3c:fb:4f:
+ 05:bf:56:4c:dd:d6:6e:43:54:fd:f4:a0:c9:13:93:
+ 55:07
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 4F:DE:F3:E5:5E:F5:98:0D:CA:3A:20:2B:E9:C8:B4:5D:D0:1D:86:BF
+ X509v3 Authority Key Identifier:
+ keyid:4F:DE:F3:E5:5E:F5:98:0D:CA:3A:20:2B:E9:C8:B4:5D:D0:1D:86:BF
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 75:4e:86:e1:25:9e:a8:7b:0e:65:db:bb:ca:49:e3:0c:70:df:
+ 07:bd:1a:83:d8:48:e1:b7:0b:39:ed:da:61:a0:98:1d:de:9b:
+ 5f:66:a6:33:79:43:46:1b:7d:bf:b4:e4:37:8c:96:5e:89:a8:
+ 8f:92:04:0f:c5:e4:0d:81:a3:76:98:c1:b0:b2:70:70:11:f6:
+ 8e:34:3a:82:ae:6b:7d:e9:ff:b4:58:85:20:b0:85:fc:86:89:
+ 40:08:62:e5:0f:34:83:82:90:da:2a:59:e4:53:53:ee:61:ac:
+ 46:51:ab:cb:81:1d:c1:f7:f0:c2:64:55:b9:fd:2a:67:44:3a:
+ 6a:af:f9:c2:55:c8:35:e6:8b:3a:d1:06:82:8f:14:ee:f1:11:
+ 25:db:a2:98:cc:be:bd:63:21:65:77:6e:6a:f8:d1:7e:a1:c6:
+ df:48:0e:74:0d:e3:03:51:ff:f9:98:92:3c:f8:36:75:90:5e:
+ 09:6c:7f:3f:c1:5e:40:03:72:de:ab:ed:6f:bb:fe:f7:9d:14:
+ 92:5c:69:13:ba:cf:7a:d8:4b:f1:29:04:6e:bc:5f:c9:8e:52:
+ b6:db:58:41:bb:8d:32:e7:5b:4b:74:bf:4c:8d:ec:07:0b:7d:
+ 3c:d6:2f:4d:27:11:31:15:6f:38:0d:ba:2a:53:76:2a:47:e6:
+ 32:52:df:ea
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALoN0lGvDEiUN8/qg4/W
+ObXJWP5ZW+VhtiGYhhaghebNyCGBZUxll1Vydi/GDSX4yCifINFWTAaZ/20PJNOS
+8TElWhNsvksZamWvLzK+qQ/4m21vEHzpJGFN/rrptbRUXoL3Anri4tdTamn0mkEn
+D1DcZKFHhFM/8TjNgKNaK92WgYrq45Ry96r4L8yp0J42n1YMRezdagVShWCZ15Sf
+dn4djz9Q+zO8yvgQLtsVsklX2PRZ+nM7AzKGp/FGoWKsZxBzcFEH/9IEM9h84qj/
+jlMk6OSW2vvR6i+cqbWPxVD7kGexjFuN91+v2qT6PPtPBb9WTN3WbkNU/fSgyROT
+VQcCAwEAAaOByzCByDAdBgNVHQ4EFgQUT97z5V71mA3KOiAr6ci0XdAdhr8wHwYD
+VR0jBBgwFoAUT97z5V71mA3KOiAr6ci0XdAdhr8wNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB1TobhJZ6o
+ew5l27vKSeMMcN8HvRqD2Ejhtws57dphoJgd3ptfZqYzeUNGG32/tOQ3jJZeiaiP
+kgQPxeQNgaN2mMGwsnBwEfaONDqCrmt96f+0WIUgsIX8holACGLlDzSDgpDaKlnk
+U1PuYaxGUavLgR3B9/DCZFW5/SpnRDpqr/nCVcg15os60QaCjxTu8REl26KYzL69
+YyFld25q+NF+ocbfSA50DeMDUf/5mJI8+DZ1kF4JbH8/wV5AA3Leq+1vu/73nRSS
+XGkTus962EvxKQRuvF/JjlK221hBu40y51tLdL9MjewHC3081i9NJxExFW84Dboq
+U3YqR+YyUt/q
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/target-has-keycertsign-but-not-ca.pem b/chromium/net/data/verify_certificate_chain_unittest/target-has-keycertsign-but-not-ca.pem
index f008c4e8727..019d3042794 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/target-has-keycertsign-but-not-ca.pem
+++ b/chromium/net/data/verify_certificate_chain_unittest/target-has-keycertsign-but-not-ca.pem
@@ -1,6 +1,6 @@
-[Created by: ./generate-target-has-keycertsign-but-not-ca.py]
+[Created by: generate-target-has-keycertsign-but-not-ca.py]
-Certificate chain with 1 intermediary, a trusted root, and a target
+Certificate chain with 1 intermediate, a trusted root, and a target
certificate that is not a CA, and yet has the keyCertSign bit set. Verification
is expected to fail, since keyCertSign should only be asserted when CA is
true.
@@ -10,7 +10,7 @@ Certificate:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
+ Issuer: CN=Intermediate
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
@@ -19,80 +19,80 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:a6:ec:9f:55:56:11:c4:7a:fc:00:75:b9:b4:bb:
- 08:8f:8f:88:ad:df:22:e4:5d:b4:f1:7d:af:a4:62:
- df:64:86:46:34:cb:a4:32:21:b0:53:7c:94:5e:8a:
- e6:6d:56:8b:28:93:23:79:ef:0b:7f:96:5a:19:09:
- 3a:b7:30:77:e3:db:54:a5:c0:f7:df:3c:bd:f5:26:
- 9f:ab:73:f9:c5:02:e8:67:cf:4d:d5:0e:31:4d:ab:
- b7:d5:55:1a:f2:dc:1a:87:45:61:3c:ea:56:19:a3:
- a7:f7:34:82:30:6f:48:54:fd:ce:05:cc:fe:95:2b:
- a3:d8:b5:8f:20:26:60:e9:22:07:2e:e3:54:22:fe:
- e2:2e:fc:33:2b:9d:6d:ed:1f:56:6d:7b:4a:69:15:
- c0:f3:d5:0a:f8:c2:9b:82:b0:91:36:7c:5a:06:6b:
- eb:02:85:58:5c:15:14:c4:c9:72:8c:21:29:29:e7:
- 23:ca:56:07:7e:28:fa:f0:99:69:ad:10:bc:6c:43:
- 31:1c:d1:bc:79:51:dd:92:54:f9:f3:0c:f8:ee:a4:
- 8a:96:1d:17:ef:70:64:71:f4:30:54:b5:77:53:26:
- 11:80:ce:dc:cb:38:98:98:69:20:e1:ae:f7:1b:61:
- 53:32:59:27:8d:e9:84:b8:6f:c1:9f:03:95:ac:9a:
- 8c:35
+ 00:aa:e6:1b:b4:96:49:1d:88:99:c3:be:30:44:ed:
+ 2a:6e:80:18:66:5a:66:26:44:14:8f:1a:1d:69:81:
+ 8b:44:fb:ee:76:a1:c6:6d:e1:c1:ad:50:aa:99:a2:
+ d5:ce:ac:f4:86:04:93:02:d9:33:aa:24:ef:36:ef:
+ 5c:93:9a:69:00:45:95:c3:82:37:67:df:25:3e:ea:
+ dc:d0:fb:08:7f:89:aa:ad:df:a6:b6:c8:09:a3:74:
+ dc:17:12:b4:03:7d:7d:86:7d:57:1e:ff:d2:16:f7:
+ 9f:85:79:6e:5c:01:e3:cf:64:9d:55:e1:77:2c:43:
+ 89:30:d1:eb:d0:2e:68:e6:d1:c1:2a:92:58:c8:e2:
+ 9b:95:be:f6:d0:42:2d:38:fe:c8:17:a3:cf:37:76:
+ af:b1:0e:32:a5:6d:58:c9:de:4b:f4:2f:fa:8c:e4:
+ 9c:c6:1c:88:7c:55:01:4b:48:81:b0:0f:4f:19:f7:
+ fa:12:e7:9e:27:27:85:47:e6:b8:07:d9:59:a3:9a:
+ ac:3f:7d:a6:14:16:c8:8b:8d:70:d7:7b:fa:46:d4:
+ 32:fc:50:c7:83:82:e3:18:69:a5:a4:56:df:24:a3:
+ c5:7d:d5:f3:24:a4:67:22:4c:c8:b6:93:c2:05:fc:
+ 01:1b:ae:9d:a4:76:f4:bb:d6:b6:a9:32:2c:3a:fe:
+ 91:93
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 64:67:70:1F:EA:D4:3D:30:5E:54:D3:BF:DF:83:3D:14:94:C3:DD:58
+ 55:B5:67:E4:CD:8D:51:AD:5E:A2:25:B0:94:40:72:52:F4:17:24:4E
X509v3 Authority Key Identifier:
- keyid:F3:98:98:C6:42:9E:AB:03:53:76:3F:43:FB:C9:9D:E4:0B:FF:BF:B5
+ keyid:71:AE:42:1C:8C:C1:FB:35:F7:C0:9F:63:95:A7:7B:4F:9D:8E:D2:7A
Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
X509v3 CRL Distribution Points:
Full Name:
- URI:http://url-for-crl/Intermediary.crl
+ URI:http://url-for-crl/Intermediate.crl
X509v3 Key Usage: critical
Digital Signature, Key Encipherment, Certificate Sign
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 65:55:d3:04:1b:96:89:b8:44:32:01:15:ee:43:85:c0:c9:ee:
- f9:19:6c:ef:f4:5a:92:22:b2:62:b1:18:38:c5:42:06:e5:c7:
- be:83:9c:96:6b:72:d7:2a:0c:68:40:d6:30:91:4b:4e:e1:d4:
- 13:05:c5:5a:91:c1:11:ce:57:2e:31:87:2a:f3:70:e4:77:3a:
- 60:82:fa:58:56:18:1f:bf:4a:dd:89:48:c6:ab:4c:01:06:d5:
- ec:8d:aa:55:eb:07:0f:bd:bd:2b:67:f6:3f:43:15:c7:a4:77:
- 88:fa:f8:9f:3b:fa:0b:a2:fe:55:7c:f1:0b:49:da:b7:08:24:
- 34:68:db:a8:76:37:60:02:be:32:54:29:b4:b7:69:c4:05:66:
- 60:a4:86:9f:a1:13:d7:c3:f6:ed:a0:97:37:17:35:97:05:c9:
- ce:f9:af:e0:42:c3:e5:32:15:d7:1e:6c:3b:41:93:df:ba:b0:
- aa:60:e8:66:46:55:b3:00:65:e2:1c:70:85:c7:81:21:3f:8e:
- 41:69:19:a0:ac:8b:54:bc:d0:4b:78:db:f8:11:d7:93:eb:a4:
- 48:04:1b:76:96:e2:ae:d5:2b:dd:ea:e4:a5:02:ca:02:86:11:
- 82:cc:3c:70:10:3a:35:81:0e:52:ad:71:11:be:d9:f2:9c:3f:
- 85:53:b8:df
+ 25:e8:87:e7:07:ba:bd:47:c3:dd:5a:3c:29:bc:af:cb:fb:cd:
+ c6:55:e6:9c:7b:cd:0e:8f:1a:0a:e4:cb:06:db:42:44:02:e5:
+ 37:6e:1a:a3:7d:23:96:c6:b2:67:cb:5a:1e:71:a1:e3:4f:15:
+ 80:7f:a1:0d:59:60:b0:6f:c9:ab:0f:ef:20:d3:c2:45:e0:99:
+ aa:7e:e1:b7:31:dc:4b:b2:16:78:c5:06:27:a8:5e:c5:7b:3b:
+ dc:81:81:0d:eb:31:13:d5:4b:23:2e:4e:2c:86:fd:ce:58:96:
+ b5:cc:33:80:5c:7b:8a:ce:74:97:aa:df:fc:7c:1e:42:7d:12:
+ 58:bb:84:0f:2d:30:7c:a9:0c:1e:5c:c4:c6:ce:2b:c0:9d:bb:
+ 7d:c2:51:04:5d:70:c3:63:43:59:57:40:e4:69:52:be:72:79:
+ b4:c5:74:51:30:af:9c:30:8e:33:89:be:69:69:4a:01:03:07:
+ d9:df:8b:0c:69:ff:cc:57:45:7c:c6:23:e5:4a:1f:19:94:19:
+ 25:9d:eb:87:04:51:06:ba:9c:6b:72:da:2b:05:ef:72:21:e9:
+ 95:5e:61:83:6a:7a:b6:30:f8:97:a1:99:dd:12:ea:47:50:ee:
+ 26:02:3b:81:94:a8:19:29:a7:ad:b6:7c:28:10:53:09:53:a4:
+ 61:74:57:ed
-----BEGIN CERTIFICATE-----
MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCm7J9V
-VhHEevwAdbm0uwiPj4it3yLkXbTxfa+kYt9khkY0y6QyIbBTfJReiuZtVosokyN5
-7wt/lloZCTq3MHfj21SlwPffPL31Jp+rc/nFAuhnz03VDjFNq7fVVRry3BqHRWE8
-6lYZo6f3NIIwb0hU/c4FzP6VK6PYtY8gJmDpIgcu41Qi/uIu/DMrnW3tH1Zte0pp
-FcDz1Qr4wpuCsJE2fFoGa+sChVhcFRTEyXKMISkp5yPKVgd+KPrwmWmtELxsQzEc
-0bx5Ud2SVPnzDPjupIqWHRfvcGRx9DBUtXdTJhGAztzLOJiYaSDhrvcbYVMyWSeN
-6YS4b8GfA5Wsmow1AgMBAAGjgekwgeYwHQYDVR0OBBYEFGRncB/q1D0wXlTTv9+D
-PRSUw91YMB8GA1UdIwQYMBaAFPOYmMZCnqsDU3Y/Q/vJneQL/7+1MD8GCCsGAQUF
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCq5hu0
+lkkdiJnDvjBE7SpugBhmWmYmRBSPGh1pgYtE++52ocZt4cGtUKqZotXOrPSGBJMC
+2TOqJO8271yTmmkARZXDgjdn3yU+6tzQ+wh/iaqt36a2yAmjdNwXErQDfX2GfVce
+/9IW95+FeW5cAePPZJ1V4XcsQ4kw0evQLmjm0cEqkljI4puVvvbQQi04/sgXo883
+dq+xDjKlbVjJ3kv0L/qM5JzGHIh8VQFLSIGwD08Z9/oS554nJ4VH5rgH2Vmjmqw/
+faYUFsiLjXDXe/pG1DL8UMeDguMYaaWkVt8ko8V91fMkpGciTMi2k8IF/AEbrp2k
+dvS71rapMiw6/pGTAgMBAAGjgekwgeYwHQYDVR0OBBYEFFW1Z+TNjVGtXqIlsJRA
+clL0FyROMB8GA1UdIwQYMBaAFHGuQhyMwfs198CfY5Wne0+djtJ6MD8GCCsGAQUF
BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgKkMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAZVXTBBuWibhEMgEV7kOF
-wMnu+Rls7/RakiKyYrEYOMVCBuXHvoOclmty1yoMaEDWMJFLTuHUEwXFWpHBEc5X
-LjGHKvNw5Hc6YIL6WFYYH79K3YlIxqtMAQbV7I2qVesHD729K2f2P0MVx6R3iPr4
-nzv6C6L+VXzxC0natwgkNGjbqHY3YAK+MlQptLdpxAVmYKSGn6ET18P27aCXNxc1
-lwXJzvmv4ELD5TIV1x5sO0GT37qwqmDoZkZVswBl4hxwhceBIT+OQWkZoKyLVLzQ
-S3jb+BHXk+ukSAQbdpbirtUr3erkpQLKAoYRgsw8cBA6NYEOUq1xEb7Z8pw/hVO4
-3w==
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgKkMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAJeiH5we6vUfD3Vo8Kbyv
+y/vNxlXmnHvNDo8aCuTLBttCRALlN24ao30jlsayZ8taHnGh408VgH+hDVlgsG/J
+qw/vINPCReCZqn7htzHcS7IWeMUGJ6hexXs73IGBDesxE9VLIy5OLIb9zliWtcwz
+gFx7is50l6rf/HweQn0SWLuEDy0wfKkMHlzExs4rwJ27fcJRBF1ww2NDWVdA5GlS
+vnJ5tMV0UTCvnDCOM4m+aWlKAQMH2d+LDGn/zFdFfMYj5UofGZQZJZ3rhwRRBrqc
+a3LaKwXvciHplV5hg2p6tjD4l6GZ3RLqR1DuJgI7gZSoGSmnrbZ8KBBTCVOkYXRX
+7Q==
-----END CERTIFICATE-----
Certificate:
@@ -104,35 +104,35 @@ Certificate:
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
+ Subject: CN=Intermediate
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:a8:d0:63:48:13:03:82:fe:27:31:f5:c0:25:67:
- 0e:46:56:3b:d0:db:01:06:88:ae:64:12:2a:b3:8f:
- 79:c1:20:87:75:e7:11:2d:97:09:b4:55:e6:c4:14:
- 7e:61:4e:98:6c:1d:dc:ec:2c:ef:16:40:99:d1:29:
- dd:0d:74:77:c7:f9:2f:5f:bd:55:63:35:3c:a2:36:
- e1:42:12:49:a1:83:0b:7b:53:f1:9d:53:02:97:3e:
- cf:27:50:2e:41:63:3a:6f:c2:b0:2a:b6:f9:bd:bb:
- d8:0a:42:0d:99:e5:5a:ea:c8:26:bc:54:6f:b6:36:
- d2:28:d4:d6:53:b5:f6:0e:8d:dd:e0:46:98:32:61:
- 42:20:ee:44:f0:a1:06:e4:9e:8c:c3:b6:cd:1b:7e:
- ef:3c:68:d6:80:5e:49:b4:66:3f:2a:5c:e1:c3:fd:
- 43:ce:b7:c7:ec:fa:1f:1d:94:e4:21:4e:51:5f:5d:
- 5a:fd:3f:84:a5:15:2a:64:2c:d5:70:4f:24:dd:96:
- 67:43:c6:1d:62:53:ed:2f:ef:64:8c:a9:b2:c3:c7:
- f3:a2:55:08:ed:dc:2a:5f:51:50:05:59:e8:e2:0e:
- cf:8d:06:5b:7b:19:56:b9:3b:dc:75:ce:b0:4e:74:
- 62:d7:31:a4:7b:1f:44:ca:3f:79:8d:5c:b7:41:a6:
- c0:bf
+ 00:c4:8f:d1:37:69:c5:65:2a:c8:df:6e:82:4d:1a:
+ ea:2c:59:9d:43:07:8b:d1:c3:01:3a:1d:7a:9f:81:
+ ad:b8:fb:10:35:ae:84:80:07:69:5b:47:eb:af:1c:
+ 7b:43:21:f3:3c:13:8a:3b:62:c0:20:fa:96:06:9b:
+ 50:04:82:05:c2:7a:e3:53:d1:34:ab:2e:94:a9:6b:
+ 5f:6c:a9:66:0d:df:d0:73:79:f0:bd:ac:9c:99:68:
+ e7:1c:25:6f:c6:68:36:07:99:57:23:17:a8:8e:4e:
+ 8c:b9:41:ef:25:7e:92:3d:08:8a:82:c2:de:fe:a3:
+ cc:05:ed:b5:8b:b8:2f:09:eb:87:29:4d:55:f1:4e:
+ ee:3a:91:54:dc:6f:6a:9e:d8:17:2a:3a:46:00:65:
+ f4:4d:ae:26:35:72:97:06:41:ef:4e:bd:af:83:ec:
+ 9b:e2:96:24:61:2b:88:71:77:a7:e8:cf:2e:3e:79:
+ 5b:a2:33:11:94:aa:e7:65:6b:06:a2:4e:94:c8:d7:
+ 56:0f:cc:12:b9:9c:c1:b5:f6:bf:2a:a0:f8:b1:74:
+ 34:54:0e:cb:f0:87:87:f6:93:3f:f4:5f:10:81:90:
+ 78:51:ae:41:19:6e:c9:89:8c:9d:d9:85:64:18:de:
+ e5:d6:8c:a8:5a:4b:60:b0:44:5f:7a:1e:f4:d1:5b:
+ 94:97
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- F3:98:98:C6:42:9E:AB:03:53:76:3F:43:FB:C9:9D:E4:0B:FF:BF:B5
+ 71:AE:42:1C:8C:C1:FB:35:F7:C0:9F:63:95:A7:7B:4F:9D:8E:D2:7A
X509v3 Authority Key Identifier:
- keyid:97:E9:16:F3:C4:AD:14:F3:56:CD:F3:E6:E5:60:D4:8F:EF:F7:BA:06
+ keyid:F7:A4:4C:CA:BB:81:7B:10:63:6B:CC:BC:73:ED:C6:1C:56:55:40:1C
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -147,41 +147,41 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 05:1f:e8:41:f2:76:1f:cd:2a:92:f9:cc:61:a9:6f:14:40:12:
- 69:19:1c:44:1d:3e:2e:c5:d0:a8:25:e3:bc:62:a3:6c:0f:e8:
- b9:dc:b0:92:cd:7a:ae:1d:4e:de:cc:90:3f:97:98:d4:d4:b0:
- a2:73:f7:b4:83:94:fb:ac:83:d3:39:af:13:64:61:bd:80:8d:
- dc:de:af:50:1a:15:12:c2:99:04:d4:c6:b8:31:12:2c:15:0a:
- 7c:13:ad:c8:be:37:fb:fa:43:ae:70:fd:64:70:a8:fb:77:fd:
- 09:7e:7e:e1:ff:27:e6:91:d8:c4:62:54:ad:cd:04:51:b0:da:
- 09:df:99:ac:91:0b:f8:31:e3:2e:18:64:f4:76:55:dd:d9:b3:
- 90:3a:07:91:e5:89:f7:83:48:15:5d:b3:bb:76:e6:d6:4a:1f:
- 3b:a4:3e:89:36:de:a8:80:09:2c:1f:23:a7:8a:cb:c3:e7:46:
- f3:f3:1e:0f:8b:88:bb:a9:87:9e:a7:64:2e:64:be:48:c1:91:
- d2:ef:c1:82:b9:1a:f4:08:d9:b1:a0:1f:ff:16:af:c4:b2:bc:
- 01:0f:e4:a0:f0:eb:81:aa:37:32:70:61:16:52:01:f6:39:10:
- a3:b0:8c:ec:2c:3f:ac:1b:cd:12:91:44:2f:6a:2e:4f:d4:8d:
- 92:a5:55:1b
+ 7b:29:bd:b8:c7:76:7f:09:90:d3:5d:e7:20:9e:f6:a0:bd:dc:
+ a1:cb:7c:c8:c8:17:d5:80:81:79:6a:88:e5:e8:c8:e3:56:37:
+ 60:3f:9c:2a:14:86:fe:e0:79:2f:d6:ec:67:51:d4:d8:65:9d:
+ ce:3b:59:b6:42:06:7b:c8:2a:79:7f:40:2f:ed:fb:50:d3:78:
+ 9e:99:fe:1d:fe:a1:4f:1d:58:c9:2d:b4:75:72:3f:6a:7a:db:
+ 2e:7b:81:3b:00:3f:e4:95:47:63:42:90:fd:25:ba:db:53:0a:
+ 01:37:28:78:7d:c6:cf:54:5e:2b:94:88:79:bb:4c:f7:06:e3:
+ 7a:be:44:29:c3:2e:17:ea:61:c4:8f:16:f0:b6:e0:60:fe:19:
+ 08:48:fd:a8:bf:95:ef:e5:32:1c:cf:e5:59:6b:04:1d:4c:6d:
+ ea:9b:4d:b4:f9:14:c2:00:a3:32:d6:1b:54:00:5a:17:29:8f:
+ 85:0c:eb:ed:41:70:6f:52:f8:37:92:ed:2b:ae:8c:b8:e4:51:
+ aa:68:62:12:9b:97:62:1a:5b:27:46:b5:5f:8c:0e:c9:93:15:
+ d7:d8:85:99:67:56:ef:31:4a:55:1f:67:7c:09:fc:03:c9:a0:
+ 67:b8:ed:32:d7:c0:0b:bd:b6:47:b9:50:78:f2:0a:ec:1d:bd:
+ d5:e9:06:b3
-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqNBjSBMD
-gv4nMfXAJWcORlY70NsBBoiuZBIqs495wSCHdecRLZcJtFXmxBR+YU6YbB3c7Czv
-FkCZ0SndDXR3x/kvX71VYzU8ojbhQhJJoYMLe1PxnVMClz7PJ1AuQWM6b8KwKrb5
-vbvYCkINmeVa6sgmvFRvtjbSKNTWU7X2Do3d4EaYMmFCIO5E8KEG5J6Mw7bNG37v
-PGjWgF5JtGY/Klzhw/1DzrfH7PofHZTkIU5RX11a/T+EpRUqZCzVcE8k3ZZnQ8Yd
-YlPtL+9kjKmyw8fzolUI7dwqX1FQBVno4g7PjQZbexlWuTvcdc6wTnRi1zGkex9E
-yj95jVy3QabAvwIDAQABo4HLMIHIMB0GA1UdDgQWBBTzmJjGQp6rA1N2P0P7yZ3k
-C/+/tTAfBgNVHSMEGDAWgBSX6RbzxK0U81bN8+blYNSP7/e6BjA3BggrBgEFBQcB
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxI/RN2nF
+ZSrI326CTRrqLFmdQweL0cMBOh16n4GtuPsQNa6EgAdpW0frrxx7QyHzPBOKO2LA
+IPqWBptQBIIFwnrjU9E0qy6UqWtfbKlmDd/Qc3nwvaycmWjnHCVvxmg2B5lXIxeo
+jk6MuUHvJX6SPQiKgsLe/qPMBe21i7gvCeuHKU1V8U7uOpFU3G9qntgXKjpGAGX0
+Ta4mNXKXBkHvTr2vg+yb4pYkYSuIcXen6M8uPnlbojMRlKrnZWsGok6UyNdWD8wS
+uZzBtfa/KqD4sXQ0VA7L8IeH9pM/9F8QgZB4Ua5BGW7JiYyd2YVkGN7l1oyoWktg
+sERfeh700VuUlwIDAQABo4HLMIHIMB0GA1UdDgQWBBRxrkIcjMH7NffAn2OVp3tP
+nY7SejAfBgNVHSMEGDAWgBT3pEzKu4F7EGNrzLxz7cYcVlVAHDA3BggrBgEFBQcB
AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
-AAUf6EHydh/NKpL5zGGpbxRAEmkZHEQdPi7F0Kgl47xio2wP6LncsJLNeq4dTt7M
-kD+XmNTUsKJz97SDlPusg9M5rxNkYb2Ajdzer1AaFRLCmQTUxrgxEiwVCnwTrci+
-N/v6Q65w/WRwqPt3/Ql+fuH/J+aR2MRiVK3NBFGw2gnfmayRC/gx4y4YZPR2Vd3Z
-s5A6B5HlifeDSBVds7t25tZKHzukPok23qiACSwfI6eKy8PnRvPzHg+LiLuph56n
-ZC5kvkjBkdLvwYK5GvQI2bGgH/8Wr8SyvAEP5KDw64GqNzJwYRZSAfY5EKOwjOws
-P6wbzRKRRC9qLk/UjZKlVRs=
+AHspvbjHdn8JkNNd5yCe9qC93KHLfMjIF9WAgXlqiOXoyONWN2A/nCoUhv7geS/W
+7GdR1Nhlnc47WbZCBnvIKnl/QC/t+1DTeJ6Z/h3+oU8dWMkttHVyP2p62y57gTsA
+P+SVR2NCkP0luttTCgE3KHh9xs9UXiuUiHm7TPcG43q+RCnDLhfqYcSPFvC24GD+
+GQhI/ai/le/lMhzP5VlrBB1MbeqbTbT5FMIAozLWG1QAWhcpj4UM6+1BcG9S+DeS
+7SuujLjkUapoYhKbl2IaWydGtV+MDsmTFdfYhZlnVu8xSlUfZ3wJ/APJoGe47TLX
+wAu9tke5UHjyCuwdvdXpBrM=
-----END CERTIFICATE-----
Certificate:
@@ -198,30 +198,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:ba:52:6a:89:3e:75:9b:d6:ed:f4:d1:1c:fb:aa:
- 99:8f:5e:89:59:2a:75:5a:54:77:9c:b5:91:d5:2a:
- f8:8a:a3:74:d2:75:39:24:cc:c5:f7:42:83:11:a7:
- 6c:cd:c2:2b:e1:18:84:b6:26:d8:12:fd:e2:a8:6a:
- 4d:4d:8f:a1:25:07:08:d2:73:a0:17:c7:54:11:a5:
- fb:0e:36:cd:e2:24:a8:dc:85:a1:22:a2:7c:c3:20:
- 02:60:ec:40:ba:1e:5b:03:51:68:d7:f2:28:f6:3d:
- 3f:b3:30:34:0e:33:6c:44:c4:31:a9:ee:cf:42:96:
- c2:eb:06:52:92:86:80:b9:0b:99:41:4b:64:aa:b7:
- 55:2b:21:25:92:46:1d:e2:31:3d:0b:54:ad:a9:c7:
- 2a:29:be:5c:bb:ba:99:59:69:70:71:75:bb:9a:a1:
- 7c:fa:36:79:bd:b4:f3:6c:4b:6c:c9:ea:32:03:dd:
- 64:9e:94:82:33:d1:d9:f8:48:04:ae:79:35:5c:a4:
- 43:54:c1:ec:3c:97:bf:3a:40:f6:e6:9d:7b:bf:a1:
- 67:b0:59:de:78:ff:33:94:f2:2b:15:d0:0a:89:0c:
- 2c:ee:9f:dc:f8:48:f0:68:0c:19:59:86:86:41:1c:
- 19:02:89:4f:0c:ea:43:b2:a8:b9:c9:c1:1d:76:c0:
- 3d:19
+ 00:cd:6b:8f:1c:b6:4c:54:b3:0d:f7:e0:b8:5a:a6:
+ d3:cc:0b:63:89:cb:3a:5a:87:3c:39:65:aa:63:32:
+ 79:fe:5c:67:f6:00:8c:32:b6:75:01:2f:7b:45:d3:
+ a4:53:f4:7a:47:7e:2d:ca:5a:d2:22:eb:22:8c:02:
+ e3:c1:91:ad:71:f8:67:43:62:8f:f1:60:17:77:ea:
+ a3:d6:78:64:b2:58:c2:fd:20:e0:a2:06:d5:18:a8:
+ 36:9e:2e:b0:97:20:c7:72:a4:51:0d:d5:f0:f0:1f:
+ b2:05:8e:82:98:9e:b5:67:dd:55:bb:c1:03:e1:9f:
+ 45:73:74:d7:11:aa:5b:de:c1:5d:5e:f2:29:85:29:
+ 03:e3:14:fa:e8:91:f5:29:a3:8c:c0:78:1c:4c:18:
+ 2b:49:2b:20:31:1e:bf:e1:55:7f:ed:76:25:4d:95:
+ a5:40:4c:cc:f4:8e:de:85:d3:88:0a:86:27:95:f4:
+ c8:4b:00:8d:16:b7:33:e9:76:12:aa:85:43:1e:89:
+ bb:ae:16:f2:f1:26:c4:a7:b9:44:89:76:1b:1a:2c:
+ 34:50:4b:e0:68:bc:f1:fb:be:22:14:b0:2b:67:78:
+ 22:f0:71:07:43:21:a3:24:d7:4e:28:a0:7d:04:16:
+ b1:a2:d8:35:2a:2b:2e:13:8e:6b:e9:c9:7f:78:7e:
+ 98:df
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 97:E9:16:F3:C4:AD:14:F3:56:CD:F3:E6:E5:60:D4:8F:EF:F7:BA:06
+ F7:A4:4C:CA:BB:81:7B:10:63:6B:CC:BC:73:ED:C6:1C:56:55:40:1C
X509v3 Authority Key Identifier:
- keyid:97:E9:16:F3:C4:AD:14:F3:56:CD:F3:E6:E5:60:D4:8F:EF:F7:BA:06
+ keyid:F7:A4:4C:CA:BB:81:7B:10:63:6B:CC:BC:73:ED:C6:1C:56:55:40:1C
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -236,47 +236,57 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- a5:32:dc:be:9a:58:7d:66:69:99:07:13:d9:ec:20:99:72:37:
- c1:8b:4d:e1:8e:79:0b:7f:ed:1c:89:a1:9b:18:66:bd:1b:fe:
- ec:74:f6:aa:7b:57:71:06:07:ea:02:41:6e:83:b4:68:39:15:
- c8:c5:16:d7:4e:10:75:f5:05:b4:f2:c6:e4:bd:b4:64:21:16:
- c8:14:dd:06:88:f7:81:89:76:44:c8:70:99:70:f2:67:e6:4c:
- 72:3e:75:24:d7:2f:83:b2:4e:6b:f8:4d:f0:e7:16:25:02:16:
- c3:fa:8a:9c:c2:75:60:6b:ed:40:1d:b2:14:97:6a:26:a1:72:
- b9:53:f1:95:fb:6e:d9:11:b3:d4:67:ff:ba:0a:06:c3:5b:fb:
- 84:e7:b1:48:07:fb:db:d7:6f:c9:7e:6f:e6:b4:3b:8c:e0:3c:
- 73:fe:80:8e:cd:35:3c:4f:51:f8:ac:fc:b4:d0:0a:5e:b9:d7:
- 95:f2:e6:fb:a8:de:25:ab:20:da:d5:e6:e2:d3:5b:6b:9b:db:
- 2c:77:0e:59:01:7a:29:07:1f:53:72:2b:f3:06:86:1b:04:a0:
- 01:82:aa:59:4f:a5:e6:8b:2a:01:24:8b:77:5b:bb:8d:36:94:
- 4a:02:ab:61:5c:0a:ba:87:ee:53:53:a7:5d:e3:6a:bc:73:9f:
- fe:e9:fc:9f
------BEGIN TRUSTED_CERTIFICATE-----
+ 50:5f:b0:32:ec:41:85:3d:75:ff:8d:05:17:be:20:98:81:da:
+ 48:39:17:20:24:a7:31:cf:63:35:90:29:26:d0:60:29:e1:68:
+ fe:35:fd:6c:61:c0:3a:cd:08:92:9b:cc:ad:73:d4:dd:a5:51:
+ 0e:a9:65:04:7d:16:77:8b:b8:b4:9d:fb:c4:7a:4a:ab:8a:9e:
+ d0:70:47:45:74:a4:57:ab:c2:cd:b3:c5:44:6b:7e:3b:78:8f:
+ 5b:7f:f0:f7:c3:ef:24:a2:40:fe:c6:71:cd:a8:a6:ac:63:22:
+ 57:39:f5:98:c3:91:79:bf:47:6a:0b:c6:b1:61:c6:35:1b:1c:
+ 10:cc:e7:bc:20:83:f6:48:26:4a:80:47:e0:22:fa:04:1f:b0:
+ 06:9c:54:fa:46:45:9b:d5:20:a2:f0:ee:be:b5:a2:83:92:86:
+ 5d:f5:40:f5:32:d0:85:35:eb:af:5d:9b:04:5d:21:b3:35:90:
+ e8:5f:0a:6c:90:85:eb:86:31:e4:89:81:c6:aa:73:4d:1e:3e:
+ af:40:07:f1:38:ae:30:ab:2d:aa:6d:2f:b2:1d:ff:d8:18:2e:
+ f3:d0:74:8e:ff:6d:24:97:30:cb:b6:e5:6f:cb:6b:c2:27:5e:
+ a5:f1:63:c0:d9:0d:c5:08:7f:86:8c:47:c4:9b:cb:e2:d9:da:
+ 17:51:5b:12
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALpSaok+dZvW7fTRHPuq
-mY9eiVkqdVpUd5y1kdUq+IqjdNJ1OSTMxfdCgxGnbM3CK+EYhLYm2BL94qhqTU2P
-oSUHCNJzoBfHVBGl+w42zeIkqNyFoSKifMMgAmDsQLoeWwNRaNfyKPY9P7MwNA4z
-bETEManuz0KWwusGUpKGgLkLmUFLZKq3VSshJZJGHeIxPQtUranHKim+XLu6mVlp
-cHF1u5qhfPo2eb2082xLbMnqMgPdZJ6UgjPR2fhIBK55NVykQ1TB7DyXvzpA9uad
-e7+hZ7BZ3nj/M5TyKxXQCokMLO6f3PhI8GgMGVmGhkEcGQKJTwzqQ7KoucnBHXbA
-PRkCAwEAAaOByzCByDAdBgNVHQ4EFgQUl+kW88StFPNWzfPm5WDUj+/3ugYwHwYD
-VR0jBBgwFoAUl+kW88StFPNWzfPm5WDUj+/3ugYwNwYIKwYBBQUHAQEEKzApMCcG
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM1rjxy2TFSzDffguFqm
+08wLY4nLOlqHPDllqmMyef5cZ/YAjDK2dQEve0XTpFP0ekd+Lcpa0iLrIowC48GR
+rXH4Z0Nij/FgF3fqo9Z4ZLJYwv0g4KIG1RioNp4usJcgx3KkUQ3V8PAfsgWOgpie
+tWfdVbvBA+GfRXN01xGqW97BXV7yKYUpA+MU+uiR9SmjjMB4HEwYK0krIDEev+FV
+f+12JU2VpUBMzPSO3oXTiAqGJ5X0yEsAjRa3M+l2EqqFQx6Ju64W8vEmxKe5RIl2
+GxosNFBL4Gi88fu+IhSwK2d4IvBxB0MhoyTXTiigfQQWsaLYNSorLhOOa+nJf3h+
+mN8CAwEAAaOByzCByDAdBgNVHQ4EFgQU96RMyruBexBja8y8c+3GHFZVQBwwHwYD
+VR0jBBgwFoAU96RMyruBexBja8y8c+3GHFZVQBwwNwYIKwYBBQUHAQEEKzApMCcG
CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQClMty+mlh9
-ZmmZBxPZ7CCZcjfBi03hjnkLf+0ciaGbGGa9G/7sdPaqe1dxBgfqAkFug7RoORXI
-xRbXThB19QW08sbkvbRkIRbIFN0GiPeBiXZEyHCZcPJn5kxyPnUk1y+Dsk5r+E3w
-5xYlAhbD+oqcwnVga+1AHbIUl2omoXK5U/GV+27ZEbPUZ/+6CgbDW/uE57FIB/vb
-12/Jfm/mtDuM4Dxz/oCOzTU8T1H4rPy00ApeudeV8ub7qN4lqyDa1ebi01trm9ss
-dw5ZAXopBx9TcivzBoYbBKABgqpZT6XmiyoBJIt3W7uNNpRKAqthXAq6h+5TU6dd
-42q8c5/+6fyf
------END TRUSTED_CERTIFICATE-----
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBQX7Ay7EGF
+PXX/jQUXviCYgdpIORcgJKcxz2M1kCkm0GAp4Wj+Nf1sYcA6zQiSm8ytc9TdpVEO
+qWUEfRZ3i7i0nfvEekqrip7QcEdFdKRXq8LNs8VEa347eI9bf/D3w+8kokD+xnHN
+qKasYyJXOfWYw5F5v0dqC8axYcY1GxwQzOe8IIP2SCZKgEfgIvoEH7AGnFT6RkWb
+1SCi8O6+taKDkoZd9UD1MtCFNeuvXZsEXSGzNZDoXwpskIXrhjHkiYHGqnNNHj6v
+QAfxOK4wqy2qbS+yHf/YGC7z0HSO/20klzDLtuVvy2vCJ16l8WPA2Q3FCH+GjEfE
+m8vi2doXUVsS
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+150302120000Z
-----BEGIN TIME-----
MTUwMzAyMTIwMDAwWg==
-----END TIME-----
+FAIL
-----BEGIN VERIFY_RESULT-----
RkFJTA==
-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 1
+ [Error] Target certificate looks like a CA but does not set all CA properties
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMQogICAgICBbRXJyb3JdIFRhcmdldCBjZXJ0aWZpY2F0ZSBsb29rcyBsaWtlIGEgQ0EgYnV0IGRvZXMgbm90IHNldCBhbGwgQ0EgcHJvcGVydGllcwo=
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/target-has-pathlen-but-not-ca.pem b/chromium/net/data/verify_certificate_chain_unittest/target-has-pathlen-but-not-ca.pem
index 34c777c0e4d..398314c8b06 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/target-has-pathlen-but-not-ca.pem
+++ b/chromium/net/data/verify_certificate_chain_unittest/target-has-pathlen-but-not-ca.pem
@@ -1,6 +1,6 @@
-[Created by: ./generate-target-has-pathlen-but-not-ca.py]
+[Created by: generate-target-has-pathlen-but-not-ca.py]
-Certificate chain with 1 intermediary, a trusted root, and a target
+Certificate chain with 1 intermediate, a trusted root, and a target
certificate that is not a CA, and yet has a pathlen set. Verification is
expected to fail, since pathlen should only be set for CAs.
@@ -9,7 +9,7 @@ Certificate:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
+ Issuer: CN=Intermediate
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
@@ -18,82 +18,82 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:e4:03:84:57:5e:99:af:4e:fe:20:15:48:81:f8:
- 76:01:11:a3:33:b0:2e:ff:3d:ec:69:be:76:8d:9b:
- c6:9b:5d:cb:b1:a6:eb:84:60:8e:99:fd:31:c1:66:
- 9f:bb:3d:bb:16:e0:c8:d8:f5:cd:23:10:8a:c5:96:
- e7:df:ed:96:d9:76:eb:82:23:e2:8c:7d:00:a9:71:
- ff:71:df:2e:14:b4:ab:3e:29:e8:11:c2:44:75:f9:
- 9f:e9:cd:cf:2f:0c:db:7b:47:b2:80:c1:90:45:a8:
- 01:6d:26:88:ff:3b:d8:54:7b:cd:ff:dc:aa:bd:38:
- 49:b0:02:d8:80:e2:79:07:33:5a:74:cd:ce:8e:df:
- 75:33:41:e7:5e:fb:25:c0:45:fb:48:32:78:47:1a:
- 70:03:d6:56:66:32:6e:2d:35:6b:76:8c:a6:33:4c:
- 1d:60:91:10:5f:70:f3:13:ec:b4:03:4f:cf:99:f9:
- 8e:e8:99:85:23:0b:cc:3d:17:5b:ec:df:aa:eb:8a:
- a7:52:67:10:dd:66:c5:b2:95:9f:72:2b:4e:fa:19:
- 31:99:62:d7:60:fd:9d:9e:e0:ca:29:13:ec:e3:c6:
- af:47:e0:84:73:ab:3b:2d:58:f5:d8:d1:0c:ee:f6:
- 23:b1:5c:55:1e:33:40:87:84:f9:d8:8a:ac:ac:46:
- ed:93
+ 00:ca:73:f9:c5:cb:c6:2c:26:07:85:8f:4b:a4:ac:
+ 52:18:84:42:ca:cb:34:59:92:5a:d8:f7:1f:df:51:
+ ed:6a:d5:e2:e1:dc:06:fb:72:0d:f3:e7:9f:38:0d:
+ 46:f4:19:77:31:33:4c:5b:ac:dd:6c:8c:06:68:4c:
+ 48:84:e2:c7:17:28:a9:0b:4e:07:07:b6:7b:cc:a9:
+ ef:6c:ae:22:6e:03:d6:d4:5b:f1:d9:aa:9e:61:54:
+ c7:14:79:cb:d6:c2:8f:da:87:e8:ae:d2:b3:66:4f:
+ d3:4c:56:b8:e0:80:f8:45:b7:11:35:53:ec:d4:49:
+ f8:05:70:f3:5b:56:b2:05:6d:3e:46:f8:be:67:71:
+ 48:a6:65:dd:55:62:a3:23:b0:94:e1:f2:3b:17:54:
+ 40:cc:37:90:d9:78:5a:d8:29:99:3f:02:16:a8:5b:
+ 5e:64:f4:f2:84:ad:25:c6:cf:2c:5b:e7:6c:bf:88:
+ 63:0c:8a:9b:fb:d9:b1:30:5a:21:74:1f:e4:5a:54:
+ 23:3a:a1:02:34:97:2c:a2:af:08:05:f0:db:52:58:
+ 7f:86:80:12:a3:f9:78:c0:ad:d6:8b:12:53:72:55:
+ 24:ca:3e:70:f2:7f:78:8f:b7:a1:32:f1:2c:7f:23:
+ db:7b:ce:79:cf:cc:6d:d8:f7:14:54:5c:e0:db:7d:
+ 60:b3
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 3F:B5:B3:28:77:02:A4:B0:9D:4B:DE:37:42:2E:E6:59:0A:D8:38:84
+ 99:D8:C1:91:A6:13:EB:0F:B4:6F:F2:B0:C4:0C:D9:0A:25:8E:53:10
X509v3 Authority Key Identifier:
- keyid:77:62:DF:59:FD:79:52:7B:9A:CF:99:3C:7C:BD:87:CE:41:27:57:F6
+ keyid:5B:9F:DF:D5:C6:FF:4F:39:52:EA:EF:97:5B:C1:ED:E1:CC:44:4E:B6
Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
X509v3 CRL Distribution Points:
Full Name:
- URI:http://url-for-crl/Intermediary.crl
+ URI:http://url-for-crl/Intermediate.crl
X509v3 Key Usage: critical
- Digital Signature, Key Encipherment, Certificate Sign
+ Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE, pathlen:1
Signature Algorithm: sha256WithRSAEncryption
- 0f:6a:84:9e:41:23:9d:77:90:68:4b:93:39:8e:74:cc:f5:3f:
- 0a:1c:8f:d9:45:bc:5d:42:d1:23:11:e6:a6:2f:52:58:23:5f:
- ba:ef:a2:3a:c7:3e:bd:24:a3:47:d3:5a:f7:00:37:0d:a4:c8:
- cd:ee:92:73:67:4c:d0:3f:63:08:c4:90:a8:42:5f:0e:cb:1e:
- 96:ae:c7:16:5f:4d:69:e4:3c:8c:a9:47:7e:ad:aa:52:dd:b3:
- 77:d8:f6:bf:f3:e3:c5:46:ec:c3:21:af:52:62:76:e5:99:0a:
- ba:a2:1c:54:62:8f:3f:0b:b8:c1:9e:e3:6e:50:4e:36:17:d0:
- ee:e1:a2:2e:29:c0:1e:a3:94:a3:69:1f:4d:13:50:4c:44:5c:
- 0f:c3:80:94:3f:6f:60:02:98:da:4f:3a:40:e4:ee:01:af:f1:
- b3:7b:4a:2e:3a:57:3b:8e:9c:8a:0c:3e:4c:49:e2:22:09:ef:
- dc:ea:fc:e2:04:20:5c:8e:a5:82:a9:0e:83:b3:ef:cc:09:ff:
- a9:bc:fa:47:0f:61:3f:7f:d6:df:ec:57:b2:da:16:70:42:8e:
- 68:28:f5:4d:cb:fb:85:16:e4:78:3b:5e:8a:96:f0:73:d6:f7:
- b0:ce:4d:18:6a:b9:1b:99:33:01:15:ce:90:c2:13:8e:14:e6:
- 0e:32:84:28
+ 70:43:96:4c:98:6f:28:18:8a:59:39:82:cc:24:47:f8:58:f8:
+ f8:43:04:09:1e:a6:51:59:bc:60:36:ff:a1:41:51:e1:4c:40:
+ 6b:5e:8b:73:3c:c4:37:65:f4:b0:57:01:8f:c6:ba:0c:5b:97:
+ a1:6b:3a:ea:53:79:8f:9a:99:f8:ca:01:a5:15:ac:60:4c:a7:
+ a7:68:07:72:3c:ed:06:70:d8:a4:d0:c0:5f:88:f2:6a:c0:a1:
+ 2b:e7:58:68:23:d3:7e:f0:98:99:7d:3d:91:25:e3:84:4f:ef:
+ 55:a4:ee:f7:1f:dc:f2:af:a8:74:96:6c:26:c4:d8:b6:84:dc:
+ b7:e7:7d:9d:2b:7b:3b:e6:e4:ad:76:e0:aa:ea:a4:26:97:4b:
+ 20:cd:b1:bd:a8:6e:b3:08:47:31:a2:01:7b:b5:6c:72:d0:f0:
+ 12:ac:bd:4f:be:de:23:cb:34:14:d2:11:42:3f:d5:70:76:4c:
+ 99:db:ce:bc:0e:d5:2e:4b:6f:c3:1b:5d:c6:58:89:74:5f:1d:
+ 62:cf:df:1e:4c:13:08:88:cb:66:6f:00:c2:c5:6f:bb:b4:9e:
+ 1f:8a:7d:9d:0b:a6:11:6f:28:bb:5e:46:ab:71:d4:eb:00:8c:
+ 71:6b:32:85:3d:17:ca:d0:15:90:66:7a:b2:96:0c:c1:9d:2e:
+ 53:36:97:5b
-----BEGIN CERTIFICATE-----
MIIDnjCCAoagAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkA4RX
-XpmvTv4gFUiB+HYBEaMzsC7/PexpvnaNm8abXcuxpuuEYI6Z/THBZp+7PbsW4MjY
-9c0jEIrFluff7ZbZduuCI+KMfQCpcf9x3y4UtKs+KegRwkR1+Z/pzc8vDNt7R7KA
-wZBFqAFtJoj/O9hUe83/3Kq9OEmwAtiA4nkHM1p0zc6O33UzQede+yXARftIMnhH
-GnAD1lZmMm4tNWt2jKYzTB1gkRBfcPMT7LQDT8+Z+Y7omYUjC8w9F1vs36rriqdS
-ZxDdZsWylZ9yK076GTGZYtdg/Z2e4MopE+zjxq9H4IRzqzstWPXY0Qzu9iOxXFUe
-M0CHhPnYiqysRu2TAgMBAAGjgfowgfcwHQYDVR0OBBYEFD+1syh3AqSwnUveN0Iu
-5lkK2DiEMB8GA1UdIwQYMBaAFHdi31n9eVJ7ms+ZPHy9h85BJ1f2MD8GCCsGAQUF
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKc/nF
+y8YsJgeFj0ukrFIYhELKyzRZklrY9x/fUe1q1eLh3Ab7cg3z5584DUb0GXcxM0xb
+rN1sjAZoTEiE4scXKKkLTgcHtnvMqe9sriJuA9bUW/HZqp5hVMcUecvWwo/ah+iu
+0rNmT9NMVrjggPhFtxE1U+zUSfgFcPNbVrIFbT5G+L5ncUimZd1VYqMjsJTh8jsX
+VEDMN5DZeFrYKZk/AhaoW15k9PKErSXGzyxb52y/iGMMipv72bEwWiF0H+RaVCM6
+oQI0lyyirwgF8NtSWH+GgBKj+XjArdaLElNyVSTKPnDyf3iPt6Ey8Sx/I9t7znnP
+zG3Y9xRUXODbfWCzAgMBAAGjgfowgfcwHQYDVR0OBBYEFJnYwZGmE+sPtG/ysMQM
+2QoljlMQMB8GA1UdIwQYMBaAFFuf39XG/085Uurvl1vB7eHMRE62MD8GCCsGAQUF
BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgKkMB0GA1UdJQQWMBQGCCsGAQUF
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
BwMBBggrBgEFBQcDAjAPBgNVHRMBAf8EBTADAgEBMA0GCSqGSIb3DQEBCwUAA4IB
-AQAPaoSeQSOdd5BoS5M5jnTM9T8KHI/ZRbxdQtEjEeamL1JYI1+676I6xz69JKNH
-01r3ADcNpMjN7pJzZ0zQP2MIxJCoQl8Oyx6WrscWX01p5DyMqUd+rapS3bN32Pa/
-8+PFRuzDIa9SYnblmQq6ohxUYo8/C7jBnuNuUE42F9Du4aIuKcAeo5SjaR9NE1BM
-RFwPw4CUP29gApjaTzpA5O4Br/Gze0ouOlc7jpyKDD5MSeIiCe/c6vziBCBcjqWC
-qQ6Ds+/MCf+pvPpHD2E/f9bf7Fey2hZwQo5oKPVNy/uFFuR4O16KlvBz1vewzk0Y
-arkbmTMBFc6QwhOOFOYOMoQo
+AQBwQ5ZMmG8oGIpZOYLMJEf4WPj4QwQJHqZRWbxgNv+hQVHhTEBrXotzPMQ3ZfSw
+VwGPxroMW5ehazrqU3mPmpn4ygGlFaxgTKenaAdyPO0GcNik0MBfiPJqwKEr51ho
+I9N+8JiZfT2RJeOET+9VpO73H9zyr6h0lmwmxNi2hNy3532dK3s75uStduCq6qQm
+l0sgzbG9qG6zCEcxogF7tWxy0PASrL1Pvt4jyzQU0hFCP9VwdkyZ2868DtUuS2/D
+G13GWIl0Xx1iz98eTBMIiMtmbwDCxW+7tJ4fin2dC6YRbyi7XkarcdTrAIxxazKF
+PRfK0BWQZnqylgzBnS5TNpdb
-----END CERTIFICATE-----
Certificate:
@@ -105,35 +105,35 @@ Certificate:
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
+ Subject: CN=Intermediate
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:cd:be:5e:d6:3b:af:1c:51:0b:b8:31:41:16:86:
- a1:04:5b:d4:c3:d1:e8:16:12:b0:7a:f8:d4:b6:61:
- 9b:5a:51:bb:7d:a5:e6:cf:70:48:1d:4e:21:74:de:
- f8:de:c7:8d:b2:e1:b5:a0:b9:4a:7c:76:b1:24:e6:
- 6d:7b:17:79:28:99:85:44:d5:9c:c7:b3:7c:64:fd:
- 3a:97:76:94:88:aa:dc:eb:c3:6e:ab:43:42:d2:89:
- b3:cb:56:dc:89:f6:4c:65:e0:be:1e:72:01:c7:c6:
- 50:e6:5b:df:a2:de:4f:43:9d:3d:e8:c8:25:2e:50:
- 1b:61:0e:2c:45:22:f0:93:7b:d6:05:9f:a4:23:fb:
- 78:b1:15:49:fe:eb:73:29:b0:eb:9f:e8:6e:3b:92:
- 86:c0:d0:20:e7:4c:b7:69:7f:d3:0f:54:39:05:3a:
- 46:9b:47:4d:fa:7e:8c:ce:45:a5:1f:2c:6f:f7:33:
- 36:10:bc:67:d9:b6:15:86:71:5f:7a:7a:af:4e:71:
- 59:1d:46:d1:76:96:d8:4b:fc:a0:b9:11:e4:5f:5d:
- fe:f4:bf:c8:48:54:66:60:be:4b:8b:70:4a:33:e0:
- ea:02:7a:cd:a1:37:3d:67:ad:93:f3:d0:a5:9e:f2:
- a4:ff:18:3e:77:97:d2:2c:58:12:a5:d6:55:03:6d:
- a1:cb
+ 00:c8:43:a7:fe:04:ff:78:d4:be:60:bd:16:7d:46:
+ a2:cf:a8:74:42:6b:2b:49:13:61:2e:78:e7:7c:49:
+ 52:0b:df:bf:b0:e1:5e:dd:f5:39:99:11:ff:d2:14:
+ 8f:db:de:10:55:90:29:05:b3:49:db:80:87:d1:82:
+ 6b:15:97:4b:da:5e:d7:da:11:0c:84:1e:db:d9:57:
+ 4d:52:cf:31:a0:1f:bd:4f:79:22:7a:ee:5a:ae:9d:
+ 22:df:71:d3:20:12:e5:c8:7e:1e:76:d3:6f:07:6e:
+ 5c:c3:89:11:a2:35:50:05:4d:6f:30:d8:3c:ef:38:
+ 80:51:e3:ee:7d:66:81:7f:7c:c4:e7:d0:d4:53:1d:
+ 00:3d:03:cb:87:f4:3d:b9:13:cd:16:ef:b2:51:3f:
+ 1c:96:0a:71:90:ca:25:c4:10:71:aa:ba:27:c8:67:
+ 94:af:63:7c:29:2a:2e:a8:4e:03:7e:6c:5c:2f:96:
+ 8d:9d:ca:c5:6f:f1:e7:8d:92:a9:ed:aa:87:3a:74:
+ 12:c7:ea:3f:ad:a2:6a:76:d8:f6:c9:96:27:6e:8b:
+ a3:b8:cc:d4:2b:9b:61:be:2b:11:c5:bb:da:ef:14:
+ 23:5d:5d:96:69:c0:a7:7a:16:db:3a:4e:e4:22:84:
+ 55:02:26:7b:a5:8e:84:12:e4:36:fc:c5:07:d9:ee:
+ c5:19
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 77:62:DF:59:FD:79:52:7B:9A:CF:99:3C:7C:BD:87:CE:41:27:57:F6
+ 5B:9F:DF:D5:C6:FF:4F:39:52:EA:EF:97:5B:C1:ED:E1:CC:44:4E:B6
X509v3 Authority Key Identifier:
- keyid:AA:16:BC:F9:7E:AD:F4:71:D6:D4:94:D9:61:4B:01:38:B2:95:8B:84
+ keyid:8A:85:CE:7E:DC:AF:15:B7:01:C2:5C:81:3F:3D:14:49:D2:38:08:AB
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -148,41 +148,41 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 4f:dc:80:b5:cb:13:5d:2d:af:b6:6d:7b:51:4e:81:36:16:d1:
- 36:bb:5d:37:be:6e:4d:40:87:57:5e:db:a9:75:ae:46:e4:74:
- c4:dc:e5:fd:bc:04:2f:ca:7f:b4:67:db:65:f7:d6:37:94:74:
- a4:f9:8a:e2:da:d5:64:9e:00:4d:85:39:07:6f:e0:96:d7:2b:
- ef:73:d3:a4:77:6b:e1:ee:d4:f7:54:ba:30:23:a3:95:2c:c8:
- 38:21:0c:14:fb:f4:44:27:9a:f3:81:2f:89:59:3e:12:52:52:
- bf:4e:7c:93:7c:db:b7:df:9b:fb:b6:3c:70:fc:67:07:a6:42:
- 99:6d:95:c0:64:f8:99:50:aa:2f:b6:19:d8:63:80:0f:22:c3:
- b4:d6:b0:09:9b:62:a0:37:0e:21:e5:ef:c2:61:ed:7e:2f:f5:
- 7d:09:19:f4:6f:8a:c8:7a:0e:0a:44:41:9b:22:01:d4:7c:c9:
- a8:da:d5:91:d9:a6:1f:1f:b8:4a:6a:bd:bc:7e:36:33:7a:e0:
- 9c:58:c1:75:71:9f:14:04:ce:c9:1f:e6:dc:40:95:ee:ed:b3:
- 6c:77:5c:31:9a:90:bd:99:80:ab:8f:ef:8d:a6:e0:64:ba:16:
- 03:a2:21:5d:75:bd:d9:50:7f:d2:02:44:58:9e:b5:c2:1d:37:
- 50:8f:27:21
+ 14:37:73:58:3c:37:40:b3:ff:a3:e4:f3:2d:f1:26:6b:c9:82:
+ 17:c5:97:4d:bd:84:6a:19:25:08:20:a9:7d:38:fb:3d:a4:7f:
+ 06:80:7e:fb:6e:7e:bf:26:90:4b:96:ab:a7:f9:49:a5:d6:77:
+ 67:b5:ab:bb:ad:ea:84:5a:43:13:f9:b3:1a:80:b1:59:cc:d4:
+ 1d:33:e8:0d:b0:af:9a:80:44:0e:a6:01:f3:a4:e2:87:2b:db:
+ 47:be:0f:28:08:d9:ab:7c:d9:4c:86:d0:ba:bc:1b:dc:99:9b:
+ 33:ea:a7:3e:ef:52:b8:70:a8:27:e7:83:59:cd:57:38:7f:a1:
+ 36:53:4f:a0:1b:69:7d:e4:fa:9f:2b:52:50:09:23:62:c6:c0:
+ 01:a6:85:76:45:80:6a:b6:54:bd:60:5d:5a:3a:04:92:ab:e3:
+ bd:0c:94:7f:5f:79:9c:3f:6e:12:c3:96:b0:78:44:9b:03:1e:
+ 79:11:fb:8d:a5:1d:55:c9:b3:e5:a0:26:18:10:68:92:b8:54:
+ 68:d0:2d:e1:99:0c:08:9c:cc:40:50:34:69:9f:13:e6:d7:87:
+ 85:e7:57:63:3e:17:0f:ce:02:7b:78:e5:18:ef:1a:55:b1:6a:
+ 55:f8:44:3e:92:1d:08:a1:7d:bb:fc:00:be:e3:1b:83:aa:b8:
+ 75:f0:05:45
-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzb5e1juv
-HFELuDFBFoahBFvUw9HoFhKwevjUtmGbWlG7faXmz3BIHU4hdN743seNsuG1oLlK
-fHaxJOZtexd5KJmFRNWcx7N8ZP06l3aUiKrc68Nuq0NC0omzy1bcifZMZeC+HnIB
-x8ZQ5lvfot5PQ5096MglLlAbYQ4sRSLwk3vWBZ+kI/t4sRVJ/utzKbDrn+huO5KG
-wNAg50y3aX/TD1Q5BTpGm0dN+n6MzkWlHyxv9zM2ELxn2bYVhnFfenqvTnFZHUbR
-dpbYS/yguRHkX13+9L/ISFRmYL5Li3BKM+DqAnrNoTc9Z62T89ClnvKk/xg+d5fS
-LFgSpdZVA22hywIDAQABo4HLMIHIMB0GA1UdDgQWBBR3Yt9Z/XlSe5rPmTx8vYfO
-QSdX9jAfBgNVHSMEGDAWgBSqFrz5fq30cdbUlNlhSwE4spWLhDA3BggrBgEFBQcB
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyEOn/gT/
+eNS+YL0WfUaiz6h0QmsrSRNhLnjnfElSC9+/sOFe3fU5mRH/0hSP294QVZApBbNJ
+24CH0YJrFZdL2l7X2hEMhB7b2VdNUs8xoB+9T3kieu5arp0i33HTIBLlyH4edtNv
+B25cw4kRojVQBU1vMNg87ziAUePufWaBf3zE59DUUx0APQPLh/Q9uRPNFu+yUT8c
+lgpxkMolxBBxqronyGeUr2N8KSouqE4DfmxcL5aNncrFb/HnjZKp7aqHOnQSx+o/
+raJqdtj2yZYnboujuMzUK5thvisRxbva7xQjXV2WacCnehbbOk7kIoRVAiZ7pY6E
+EuQ2/MUH2e7FGQIDAQABo4HLMIHIMB0GA1UdDgQWBBRbn9/Vxv9POVLq75dbwe3h
+zEROtjAfBgNVHSMEGDAWgBSKhc5+3K8VtwHCXIE/PRRJ0jgIqzA3BggrBgEFBQcB
AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
-AE/cgLXLE10tr7Zte1FOgTYW0Ta7XTe+bk1Ah1de26l1rkbkdMTc5f28BC/Kf7Rn
-22X31jeUdKT5iuLa1WSeAE2FOQdv4JbXK+9z06R3a+Hu1PdUujAjo5UsyDghDBT7
-9EQnmvOBL4lZPhJSUr9OfJN827ffm/u2PHD8ZwemQpltlcBk+JlQqi+2GdhjgA8i
-w7TWsAmbYqA3DiHl78Jh7X4v9X0JGfRvish6DgpEQZsiAdR8yaja1ZHZph8fuEpq
-vbx+NjN64JxYwXVxnxQEzskf5txAle7ts2x3XDGakL2ZgKuP742m4GS6FgOiIV11
-vdlQf9ICRFietcIdN1CPJyE=
+ABQ3c1g8N0Cz/6Pk8y3xJmvJghfFl029hGoZJQggqX04+z2kfwaAfvtufr8mkEuW
+q6f5SaXWd2e1q7ut6oRaQxP5sxqAsVnM1B0z6A2wr5qARA6mAfOk4ocr20e+DygI
+2at82UyG0Lq8G9yZmzPqpz7vUrhwqCfng1nNVzh/oTZTT6AbaX3k+p8rUlAJI2LG
+wAGmhXZFgGq2VL1gXVo6BJKr470MlH9feZw/bhLDlrB4RJsDHnkR+42lHVXJs+Wg
+JhgQaJK4VGjQLeGZDAiczEBQNGmfE+bXh4XnV2M+Fw/OAnt45RjvGlWxalX4RD6S
+HQihfbv8AL7jG4OquHXwBUU=
-----END CERTIFICATE-----
Certificate:
@@ -199,30 +199,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:eb:e2:5f:c7:d4:38:fe:e8:6d:64:82:8e:c6:d8:
- d7:a5:a4:ca:65:5f:55:b6:c5:5c:9c:f6:cc:af:d6:
- 4b:ec:a1:5c:c3:55:08:19:1c:0e:99:4a:4d:b2:14:
- 22:36:a0:db:eb:c3:1c:6f:d6:05:69:a5:5b:61:59:
- 7a:fb:88:da:28:1d:95:c6:fe:31:51:06:ac:f7:41:
- a6:10:08:25:7f:41:f1:01:39:48:27:c1:34:73:2f:
- c2:05:b1:97:42:80:de:d4:3a:44:db:a0:34:8c:b8:
- 5c:de:ab:42:c8:1e:f1:08:7e:10:3a:ee:16:8e:61:
- ee:ab:aa:f5:7a:2b:ab:af:a2:69:da:f4:b5:95:32:
- 17:bc:cf:ba:ad:a7:7b:fc:ea:9b:43:bc:ae:07:c3:
- 92:15:ce:4a:fb:ee:33:e6:89:7d:09:88:f9:a5:af:
- 0b:4d:c1:7f:28:30:d8:93:75:92:b5:27:2c:01:bd:
- 52:05:5d:42:a5:dc:f3:1f:1e:b2:3c:a1:17:19:9b:
- 30:ec:18:85:41:e3:72:d2:93:ef:a0:4d:0b:d4:8a:
- fa:89:0d:b6:46:fe:bc:f0:82:de:99:4c:1e:57:1c:
- 8d:71:b3:9c:41:ea:03:8f:a1:d6:f2:a4:9d:1c:b8:
- 50:c8:c0:19:6a:18:4d:c0:7f:7d:f8:b3:af:c6:62:
- 09:9b
+ 00:d3:fa:b1:7f:2b:e4:ff:ad:10:e9:54:54:ef:6a:
+ 81:02:0b:b6:83:70:89:ae:d9:4d:54:ea:95:99:88:
+ 3d:59:7d:97:1e:fd:b9:9b:53:8b:14:1e:a4:68:07:
+ ed:68:65:68:7d:4f:ba:28:38:ff:87:33:98:2c:32:
+ d0:e5:00:78:0f:6a:20:32:7d:9e:7d:9b:af:e9:39:
+ fe:5c:bc:04:1c:06:1a:11:1a:46:24:34:f7:e3:af:
+ 56:6d:38:8f:46:39:a6:01:fa:56:f9:d7:9e:73:35:
+ 1a:23:94:12:0f:0d:d3:ec:fe:09:57:f6:a0:9c:18:
+ a7:ba:4b:c9:37:a3:0c:60:77:4b:77:5f:c8:9c:7e:
+ b1:5c:b3:43:72:da:c9:6c:c8:71:24:ab:2f:c4:83:
+ bd:b0:4f:60:af:46:0d:7b:34:8f:e9:70:a2:85:ed:
+ 6e:05:df:e3:c1:40:3d:17:b1:f0:a3:7d:e2:17:6f:
+ 3d:fe:11:81:90:1f:c2:f8:bc:2c:d5:9c:fc:04:47:
+ 24:c4:5e:cf:20:0f:31:e8:7d:ea:b5:69:b8:0f:35:
+ 19:5d:13:08:db:d6:a2:dc:7a:33:92:b3:9c:fc:35:
+ de:cf:55:96:f7:52:6e:a9:e2:93:b0:52:07:8d:0f:
+ 95:9c:0e:0d:1b:48:0e:b8:41:4f:eb:68:da:e5:6d:
+ a1:63
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- AA:16:BC:F9:7E:AD:F4:71:D6:D4:94:D9:61:4B:01:38:B2:95:8B:84
+ 8A:85:CE:7E:DC:AF:15:B7:01:C2:5C:81:3F:3D:14:49:D2:38:08:AB
X509v3 Authority Key Identifier:
- keyid:AA:16:BC:F9:7E:AD:F4:71:D6:D4:94:D9:61:4B:01:38:B2:95:8B:84
+ keyid:8A:85:CE:7E:DC:AF:15:B7:01:C2:5C:81:3F:3D:14:49:D2:38:08:AB
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -237,47 +237,57 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 07:d5:33:48:84:04:40:42:f1:f2:ff:d9:07:5e:5f:bf:d9:72:
- 07:6f:a9:6a:f1:5f:f3:59:69:99:41:cd:9d:37:65:cb:2e:c8:
- 06:f3:0a:0c:da:46:28:6d:d6:06:08:20:5b:ca:ed:c9:14:6e:
- 11:5a:9f:df:33:06:67:44:e7:63:ba:b2:42:53:2e:31:0b:ce:
- ef:c1:74:60:76:96:0b:3f:da:9b:f2:a1:d1:89:99:34:f0:f9:
- ae:8c:39:fd:3d:a6:be:7f:f5:82:f0:25:62:b0:b7:b4:bc:1b:
- 51:c3:60:05:af:bc:22:b9:62:49:c0:27:12:72:c2:ac:d9:1e:
- 17:ff:e7:57:f6:b2:f8:37:dd:76:1a:dc:e0:89:4f:b3:8a:74:
- 0b:76:5f:48:fc:6c:af:6d:42:85:25:b4:44:ca:27:ed:2e:fb:
- d8:df:1a:a1:82:bd:6c:25:35:62:cb:50:db:27:9e:b2:65:cc:
- 58:fa:fd:1e:6a:2a:77:cd:3f:b4:6b:e6:71:ec:85:f5:7b:73:
- a9:73:05:78:1f:26:21:dc:8b:a4:f5:e1:06:a6:97:13:9f:5f:
- 84:03:12:59:37:81:17:21:2d:39:db:b7:b0:f4:17:73:90:7c:
- a1:2f:53:c0:4a:af:53:54:2c:5b:9c:8a:e3:66:80:40:30:96:
- e3:d8:b2:23
------BEGIN TRUSTED_CERTIFICATE-----
+ 3b:f2:cd:03:ef:d9:61:67:ea:7b:dd:e9:88:13:07:8d:94:51:
+ 62:bb:56:d6:c1:be:8a:d0:a0:81:fe:1d:90:6d:85:94:2c:ac:
+ 33:fb:5d:f6:c9:74:72:7b:f7:5a:b8:e4:b6:dd:30:bb:93:3b:
+ 74:22:e9:fe:e9:5c:b2:8b:d4:a1:21:0c:e6:3c:ee:86:ae:9e:
+ 8a:fd:88:bb:a7:fd:20:bb:9c:ff:d4:ca:6f:66:60:19:14:d1:
+ d1:f2:d6:f3:b2:58:c8:4d:15:30:e1:e0:fc:40:ad:55:25:ba:
+ 8d:25:68:26:c4:64:68:7e:94:e6:f4:96:5a:c4:e6:ba:85:5b:
+ b2:32:d1:82:32:8b:f4:3f:6f:4e:d5:de:2e:d7:09:3c:1f:7e:
+ 93:3a:22:d8:ef:40:41:47:28:80:03:77:0d:f9:51:28:28:b6:
+ 53:24:66:f7:3b:56:6c:53:58:55:b2:49:7c:c4:1a:3d:a1:37:
+ 29:19:8a:9a:99:84:7f:63:ac:21:85:f5:02:5a:5a:1c:7c:0a:
+ 8b:bc:83:ff:80:57:2e:ce:62:c5:79:58:24:12:e8:af:a4:6c:
+ ce:a8:92:2b:25:c4:e3:b6:27:f7:d5:dd:e6:fa:cc:91:6c:59:
+ 5e:f5:a4:e2:4f:0b:18:fa:4e:9c:88:66:20:25:af:87:14:01:
+ 27:08:89:6a
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOviX8fUOP7obWSCjsbY
-16WkymVfVbbFXJz2zK/WS+yhXMNVCBkcDplKTbIUIjag2+vDHG/WBWmlW2FZevuI
-2igdlcb+MVEGrPdBphAIJX9B8QE5SCfBNHMvwgWxl0KA3tQ6RNugNIy4XN6rQsge
-8Qh+EDruFo5h7quq9Xorq6+iadr0tZUyF7zPuq2ne/zqm0O8rgfDkhXOSvvuM+aJ
-fQmI+aWvC03Bfygw2JN1krUnLAG9UgVdQqXc8x8esjyhFxmbMOwYhUHjctKT76BN
-C9SK+okNtkb+vPCC3plMHlccjXGznEHqA4+h1vKknRy4UMjAGWoYTcB/ffizr8Zi
-CZsCAwEAAaOByzCByDAdBgNVHQ4EFgQUqha8+X6t9HHW1JTZYUsBOLKVi4QwHwYD
-VR0jBBgwFoAUqha8+X6t9HHW1JTZYUsBOLKVi4QwNwYIKwYBBQUHAQEEKzApMCcG
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANP6sX8r5P+tEOlUVO9q
+gQILtoNwia7ZTVTqlZmIPVl9lx79uZtTixQepGgH7WhlaH1Puig4/4czmCwy0OUA
+eA9qIDJ9nn2br+k5/ly8BBwGGhEaRiQ09+OvVm04j0Y5pgH6VvnXnnM1GiOUEg8N
+0+z+CVf2oJwYp7pLyTejDGB3S3dfyJx+sVyzQ3LayWzIcSSrL8SDvbBPYK9GDXs0
+j+lwooXtbgXf48FAPRex8KN94hdvPf4RgZAfwvi8LNWc/ARHJMRezyAPMeh96rVp
+uA81GV0TCNvWotx6M5KznPw13s9VlvdSbqnik7BSB40PlZwODRtIDrhBT+to2uVt
+oWMCAwEAAaOByzCByDAdBgNVHQ4EFgQUioXOftyvFbcBwlyBPz0USdI4CKswHwYD
+VR0jBBgwFoAUioXOftyvFbcBwlyBPz0USdI4CKswNwYIKwYBBQUHAQEEKzApMCcG
CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAH1TNIhARA
-QvHy/9kHXl+/2XIHb6lq8V/zWWmZQc2dN2XLLsgG8woM2kYobdYGCCBbyu3JFG4R
-Wp/fMwZnROdjurJCUy4xC87vwXRgdpYLP9qb8qHRiZk08PmujDn9Paa+f/WC8CVi
-sLe0vBtRw2AFr7wiuWJJwCcScsKs2R4X/+dX9rL4N912GtzgiU+zinQLdl9I/Gyv
-bUKFJbREyiftLvvY3xqhgr1sJTViy1DbJ56yZcxY+v0eaip3zT+0a+Zx7IX1e3Op
-cwV4HyYh3Iuk9eEGppcTn1+EAxJZN4EXIS0527ew9BdzkHyhL1PASq9TVCxbnIrj
-ZoBAMJbj2LIj
------END TRUSTED_CERTIFICATE-----
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA78s0D79lh
+Z+p73emIEweNlFFiu1bWwb6K0KCB/h2QbYWULKwz+132yXRye/dauOS23TC7kzt0
+Iun+6Vyyi9ShIQzmPO6Grp6K/Yi7p/0gu5z/1MpvZmAZFNHR8tbzsljITRUw4eD8
+QK1VJbqNJWgmxGRofpTm9JZaxOa6hVuyMtGCMov0P29O1d4u1wk8H36TOiLY70BB
+RyiAA3cN+VEoKLZTJGb3O1ZsU1hVskl8xBo9oTcpGYqamYR/Y6whhfUCWlocfAqL
+vIP/gFcuzmLFeVgkEuivpGzOqJIrJcTjtif31d3m+syRbFle9aTiTwsY+k6ciGYg
+Ja+HFAEnCIlq
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+150302120000Z
-----BEGIN TIME-----
MTUwMzAyMTIwMDAwWg==
-----END TIME-----
+FAIL
-----BEGIN VERIFY_RESULT-----
RkFJTA==
-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 1
+ [Error] Target certificate looks like a CA but does not set all CA properties
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMQogICAgICBbRXJyb3JdIFRhcmdldCBjZXJ0aWZpY2F0ZSBsb29rcyBsaWtlIGEgQ0EgYnV0IGRvZXMgbm90IHNldCBhbGwgQ0EgcHJvcGVydGllcwo=
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/target-not-end-entity.pem b/chromium/net/data/verify_certificate_chain_unittest/target-not-end-entity.pem
index 249d42a467d..4cb7258fc21 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/target-not-end-entity.pem
+++ b/chromium/net/data/verify_certificate_chain_unittest/target-not-end-entity.pem
@@ -1,6 +1,6 @@
-[Created by: ./generate-target-not-end-entity.py]
+[Created by: generate-target-not-end-entity.py]
-Certificate chain with 1 intermediary, a trusted root, and a target
+Certificate chain with 1 intermediate, a trusted root, and a target
certificate that is also a CA. Verification is expected to succeed, as the test
code accepts any target certificate.
@@ -9,7 +9,7 @@ Certificate:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
+ Issuer: CN=Intermediate
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
@@ -18,79 +18,79 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:ee:c2:63:d9:42:ea:55:e7:60:10:b7:7a:07:f3:
- 2c:85:b7:38:91:0c:ec:29:d5:fd:ca:14:ad:58:8b:
- 12:c2:fd:b6:2e:fb:50:dc:04:e9:c3:20:d1:db:23:
- da:0e:5e:93:94:cf:82:54:fd:e7:5d:9a:ee:01:37:
- 84:67:e9:f4:93:7b:ef:be:b1:e1:a3:5a:5a:eb:31:
- b1:29:8e:05:1a:90:d5:15:aa:5e:de:29:1b:1f:80:
- eb:17:fa:89:4b:d4:5b:77:0f:d1:e0:7b:f2:8d:a6:
- b4:aa:22:44:42:3e:bb:af:b7:5e:06:ae:0b:c0:20:
- 6e:ea:90:ef:4c:cb:34:5a:6b:37:29:a7:07:0c:66:
- 65:16:36:29:f0:d7:c8:e7:cc:88:2f:cc:bd:63:33:
- 2d:f5:91:8d:9b:69:f6:f3:05:d3:ca:87:96:ed:79:
- e4:0f:85:a4:41:62:aa:f2:f9:89:fe:a7:92:e5:7c:
- 0a:6e:74:70:b0:be:b2:67:12:2c:c4:44:77:54:f0:
- d6:07:26:aa:ad:8f:9c:f2:12:c2:c1:23:2d:54:8c:
- 09:df:94:59:7c:8b:e0:62:f1:2d:7b:cc:26:f3:11:
- 7b:97:04:3b:2a:02:c5:8f:2f:28:c5:c4:52:dc:4c:
- 5b:6f:0b:8c:e4:89:0a:85:d0:a3:d4:02:74:35:48:
- c7:c5
+ 00:f5:cd:3c:3f:41:74:34:24:e9:1d:74:42:a1:a8:
+ 16:8e:38:0b:ef:74:5b:38:0c:fb:18:b5:f6:08:f3:
+ 7e:d6:03:ac:02:7c:38:07:dc:c2:3e:78:bd:a7:2d:
+ 44:3d:6b:b4:74:42:71:c4:0c:93:c7:9a:ba:83:e9:
+ 6a:12:39:ab:fd:63:f5:e9:d7:97:33:93:7c:1b:77:
+ 78:c6:7a:7b:32:31:c3:68:aa:b0:b9:78:7b:c2:5a:
+ 85:0b:04:b4:c1:2b:fd:ce:71:02:6a:b1:0c:f6:1a:
+ 65:99:58:29:6e:95:21:69:7c:2a:c0:ff:18:90:28:
+ 92:ad:40:f5:83:67:63:04:14:21:aa:d2:29:35:22:
+ 03:f8:28:27:8a:69:82:de:aa:f4:1e:5e:93:19:27:
+ 74:4a:6b:d5:82:d3:2e:66:cb:23:e9:34:d1:70:0f:
+ 84:cb:1d:87:55:9e:1c:f2:b9:5a:e8:d0:43:dc:89:
+ a3:5c:28:61:fc:89:97:ab:ff:4a:2c:bc:c0:58:f2:
+ 68:f8:d7:9f:3e:e8:b1:8c:70:5a:d0:f7:1a:d3:dd:
+ d1:24:ba:fe:15:f8:bd:ea:16:8d:ee:9e:7e:99:30:
+ 22:6c:24:21:67:d1:fa:50:61:ce:65:48:5f:0e:79:
+ 02:0d:e9:b1:69:d3:4c:e7:2d:5d:57:8b:d5:e8:42:
+ d4:e7
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 75:E4:93:1E:26:35:79:D3:34:F7:E2:FD:A3:1C:38:1C:68:8B:F6:CD
+ B4:44:21:DE:96:81:AA:7F:9A:5B:79:CB:57:AA:3D:13:A5:4B:6A:93
X509v3 Authority Key Identifier:
- keyid:58:01:24:B6:3B:E6:E7:85:87:83:6F:54:23:6A:C2:D4:E0:9D:6C:37
+ keyid:01:CB:1D:FC:13:00:C9:67:B2:D6:76:F2:0A:4F:9D:6A:D4:E2:9D:3D
Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
X509v3 CRL Distribution Points:
Full Name:
- URI:http://url-for-crl/Intermediary.crl
+ URI:http://url-for-crl/Intermediate.crl
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 86:0e:74:e2:4f:1c:93:23:8a:9c:37:4a:42:ff:ab:4b:7b:5c:
- 38:c3:67:11:1d:60:03:b3:1e:57:15:8f:1f:b2:94:45:f0:44:
- 31:f1:7e:30:0e:f9:cc:48:7b:a3:27:2b:bf:9a:bd:e9:a1:69:
- e2:1f:e7:91:ef:98:e9:58:5e:f8:7c:a0:8d:e5:81:85:af:8c:
- a6:04:c5:57:3e:cb:5f:33:dc:ca:b6:72:5b:e7:82:9b:68:91:
- 73:aa:f2:47:b9:6b:e2:7d:12:b4:85:87:2a:a9:49:a0:cd:79:
- 41:8d:60:33:43:e8:aa:55:4b:60:8a:41:26:ca:e1:75:35:bd:
- 45:00:a7:1a:2e:16:15:14:1f:be:9d:aa:25:54:e2:0d:f2:da:
- 96:27:72:2c:75:4b:d7:06:5f:9d:47:37:25:08:7f:1f:ad:df:
- e7:6f:1d:f6:95:63:e8:08:02:c9:51:dc:ae:4a:31:eb:c5:61:
- 24:79:4c:d1:88:79:1f:04:ae:35:79:24:bc:29:4d:0c:c0:05:
- 99:91:db:f3:83:af:95:4f:f3:13:35:b4:a9:40:04:81:cb:f5:
- 39:e1:55:96:cf:42:86:68:26:f8:cc:82:6a:b9:10:77:41:55:
- 03:16:9d:0e:57:37:33:a0:53:ca:7e:0b:1c:85:9e:c2:81:8d:
- c8:3e:b8:62
+ 0e:8f:41:87:a8:42:bd:13:c8:62:be:1d:f6:ad:a4:cd:00:5d:
+ 21:61:73:5f:75:27:67:16:98:11:ca:0f:cd:9d:bf:96:2a:75:
+ 62:35:68:e0:af:f7:6f:c4:75:69:f2:a7:89:27:96:64:4f:0e:
+ 7e:f0:82:89:65:1e:a2:08:cd:8b:f1:e5:a0:32:c5:93:2a:62:
+ 4c:3c:d2:9f:95:55:5d:87:a8:fe:ef:fa:92:aa:08:76:38:67:
+ 0a:d3:f9:0a:b9:93:69:e6:d3:78:ab:9f:eb:ef:35:a7:24:ae:
+ 10:d7:3d:17:bd:86:07:c0:64:0f:d6:fc:55:c1:54:70:6c:22:
+ 4f:ae:c1:64:ca:fc:dc:97:eb:8b:d2:22:52:d8:52:2c:4d:d4:
+ 5c:df:10:52:ab:ab:b2:89:10:e8:ed:00:19:8a:65:e8:4e:8c:
+ e2:5d:5b:cd:35:4c:55:24:30:be:57:f7:f0:51:ef:52:9d:34:
+ 60:0d:1e:f5:ba:8a:33:83:ac:db:dc:d9:2b:0b:f3:46:1c:98:
+ 3a:5e:5c:c7:36:7e:62:62:a4:13:68:2e:35:32:a1:bd:9d:e9:
+ 67:bb:58:85:3b:ea:94:1f:c7:91:35:b0:2c:ce:25:2b:9c:9f:
+ 60:7a:09:fa:32:1c:9d:4e:ca:ef:20:9d:ca:e1:ad:20:cd:63:
+ 20:ce:48:fd
-----BEGIN CERTIFICATE-----
MIIDfzCCAmegAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDuwmPZ
-QupV52AQt3oH8yyFtziRDOwp1f3KFK1YixLC/bYu+1DcBOnDINHbI9oOXpOUz4JU
-/eddmu4BN4Rn6fSTe+++seGjWlrrMbEpjgUakNUVql7eKRsfgOsX+olL1Ft3D9Hg
-e/KNprSqIkRCPruvt14GrgvAIG7qkO9MyzRaazcppwcMZmUWNinw18jnzIgvzL1j
-My31kY2bafbzBdPKh5bteeQPhaRBYqry+Yn+p5LlfApudHCwvrJnEizERHdU8NYH
-Jqqtj5zyEsLBIy1UjAnflFl8i+Bi8S17zCbzEXuXBDsqAsWPLyjFxFLcTFtvC4zk
-iQqF0KPUAnQ1SMfFAgMBAAGjgdswgdgwHQYDVR0OBBYEFHXkkx4mNXnTNPfi/aMc
-OBxoi/bNMB8GA1UdIwQYMBaAFFgBJLY75ueFh4NvVCNqwtTgnWw3MD8GCCsGAQUF
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD1zTw/
+QXQ0JOkddEKhqBaOOAvvdFs4DPsYtfYI837WA6wCfDgH3MI+eL2nLUQ9a7R0QnHE
+DJPHmrqD6WoSOav9Y/Xp15czk3wbd3jGensyMcNoqrC5eHvCWoULBLTBK/3OcQJq
+sQz2GmWZWClulSFpfCrA/xiQKJKtQPWDZ2MEFCGq0ik1IgP4KCeKaYLeqvQeXpMZ
+J3RKa9WC0y5myyPpNNFwD4TLHYdVnhzyuVro0EPciaNcKGH8iZer/0osvMBY8mj4
+158+6LGMcFrQ9xrT3dEkuv4V+L3qFo3unn6ZMCJsJCFn0fpQYc5lSF8OeQIN6bFp
+00znLV1Xi9XoQtTnAgMBAAGjgdswgdgwHQYDVR0OBBYEFLREId6Wgap/mlt5y1eq
+PROlS2qTMB8GA1UdIwQYMBaAFAHLHfwTAMlnstZ28gpPnWrU4p09MD8GCCsGAQUF
BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
-DQYJKoZIhvcNAQELBQADggEBAIYOdOJPHJMjipw3SkL/q0t7XDjDZxEdYAOzHlcV
-jx+ylEXwRDHxfjAO+cxIe6MnK7+avemhaeIf55HvmOlYXvh8oI3lgYWvjKYExVc+
-y18z3Mq2clvngptokXOq8ke5a+J9ErSFhyqpSaDNeUGNYDND6KpVS2CKQSbK4XU1
-vUUApxouFhUUH76dqiVU4g3y2pYncix1S9cGX51HNyUIfx+t3+dvHfaVY+gIAslR
-3K5KMevFYSR5TNGIeR8ErjV5JLwpTQzABZmR2/ODr5VP8xM1tKlABIHL9TnhVZbP
-QoZoJvjMgmq5EHdBVQMWnQ5XNzOgU8p+CxyFnsKBjcg+uGI=
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
+DQYJKoZIhvcNAQELBQADggEBAA6PQYeoQr0TyGK+HfatpM0AXSFhc191J2cWmBHK
+D82dv5YqdWI1aOCv92/EdWnyp4knlmRPDn7wgollHqIIzYvx5aAyxZMqYkw80p+V
+VV2HqP7v+pKqCHY4ZwrT+Qq5k2nm03irn+vvNackrhDXPRe9hgfAZA/W/FXBVHBs
+Ik+uwWTK/NyX64vSIlLYUixN1FzfEFKrq7KJEOjtABmKZehOjOJdW801TFUkML5X
+9/BR71KdNGANHvW6ijODrNvc2SsL80YcmDpeXMc2fmJipBNoLjUyob2d6We7WIU7
+6pQfx5E1sCzOJSucn2B6CfoyHJ1Oyu8gncrhrSDNYyDOSP0=
-----END CERTIFICATE-----
Certificate:
@@ -102,35 +102,35 @@ Certificate:
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
+ Subject: CN=Intermediate
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:c7:c3:50:5c:f2:60:57:55:0d:be:39:c4:be:74:
- 76:26:ce:b2:4c:be:ac:dc:17:ac:a0:a4:c3:5f:ae:
- 64:59:da:20:77:7c:88:28:0e:75:7e:ef:70:80:9c:
- 0c:8e:94:1c:48:ea:4f:b3:34:1e:e4:cf:af:f8:29:
- 13:06:6f:19:0f:e7:9a:df:59:8c:44:d3:0e:26:70:
- 5f:c7:a5:3a:36:4d:4b:50:9c:bd:14:fb:21:4a:f8:
- d6:2b:49:94:2b:df:4c:8c:89:32:d7:53:f8:59:14:
- e9:23:76:f3:fb:b4:27:2d:c9:28:17:cc:fe:06:2c:
- bd:b5:97:30:83:40:9e:c7:ff:9e:0a:99:a7:f0:e8:
- 0c:c7:73:ca:3f:48:3a:75:97:bd:de:9a:84:6d:5b:
- 13:dc:0c:64:1e:66:4f:72:10:28:cd:34:bb:15:f1:
- ca:65:3f:03:db:aa:fa:4d:4c:26:64:8a:3f:6f:67:
- 51:fa:15:2d:71:7c:fd:0b:12:9e:12:c2:77:9c:f2:
- a8:86:78:f2:6f:9f:79:c9:50:51:28:41:13:79:79:
- 7c:a1:93:dd:71:f7:08:92:99:f7:9c:37:ff:2b:82:
- b6:4e:a9:93:47:83:dc:36:83:40:13:22:96:eb:5e:
- 2f:ad:a1:d6:70:38:c5:2b:3a:0b:ce:4c:fc:81:c1:
- 49:f5
+ 00:d0:8e:2e:ba:a1:8d:d9:60:16:cd:17:31:c9:08:
+ 43:93:94:76:48:55:a2:78:19:17:70:8e:95:25:ac:
+ f9:b9:81:33:66:8c:2c:79:b7:d9:f5:89:92:1b:d2:
+ 4e:01:e9:69:e6:61:b4:d7:96:78:6d:a0:23:cf:67:
+ 11:cd:fb:fe:3d:d6:b8:ad:64:3f:f6:b9:f5:17:05:
+ 89:1c:fb:3d:94:c3:18:43:e4:1e:15:0f:8d:26:25:
+ de:db:f0:c0:d6:67:cc:90:f8:33:1c:d1:81:4b:63:
+ 3e:c9:76:61:65:80:b4:13:97:9d:2e:99:ca:a2:6b:
+ cc:10:a6:3b:2f:20:90:ee:a5:6c:cf:f6:a0:7a:7b:
+ ce:59:c6:19:42:3f:9f:69:ab:f3:c1:2f:26:8d:fe:
+ ac:b8:ec:33:d2:d6:bb:4e:3f:80:c0:d9:12:33:35:
+ 05:2d:30:ce:6b:1c:12:ea:89:6f:8a:93:15:0e:0c:
+ c0:10:7a:99:1e:3f:fb:85:88:09:82:16:f0:62:ed:
+ fb:26:63:93:71:72:9b:15:11:19:c3:36:5b:10:c1:
+ b1:12:51:2e:6a:af:c1:d1:9d:fd:8b:7f:13:19:5d:
+ ce:00:49:3d:33:32:d1:6b:c5:14:4e:10:92:4d:1f:
+ 28:07:01:29:8f:fe:5d:ff:98:b8:2f:99:fc:68:21:
+ 1d:1f
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 58:01:24:B6:3B:E6:E7:85:87:83:6F:54:23:6A:C2:D4:E0:9D:6C:37
+ 01:CB:1D:FC:13:00:C9:67:B2:D6:76:F2:0A:4F:9D:6A:D4:E2:9D:3D
X509v3 Authority Key Identifier:
- keyid:92:00:23:C7:C3:33:14:62:3D:59:C9:52:A4:CC:A0:5C:16:DD:35:2D
+ keyid:2D:38:72:D3:21:CA:2A:39:AD:2D:B4:9A:10:5C:CB:58:56:82:C4:AA
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -145,41 +145,41 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 3d:c9:5f:4a:71:a9:28:ca:c0:27:47:f1:23:b0:87:2c:5f:4c:
- 20:de:1e:60:8b:6d:c3:42:2c:bf:ed:82:26:00:b6:f8:4f:7e:
- ac:37:ec:43:ea:7a:a5:58:fc:34:cd:af:54:2d:3e:30:e8:44:
- 8d:37:8d:5b:5c:b8:52:bd:f1:d5:ab:c7:61:d9:83:b5:f5:51:
- 41:ed:f0:1c:02:c7:ae:4f:57:60:49:c8:6d:3e:44:53:13:ce:
- 97:47:78:b5:04:23:fd:0a:49:e5:99:67:90:07:e7:a5:66:61:
- 2b:93:5f:b5:dd:d0:fe:92:e8:36:3e:4f:cb:a7:f0:64:d2:88:
- 11:e5:78:42:89:a7:3f:b6:fe:93:3a:d8:52:d0:8c:9d:ea:89:
- 21:56:67:04:21:c5:c2:83:42:13:43:ee:5c:1c:2f:00:97:45:
- 56:4a:18:21:ad:2d:b3:b6:38:ed:5e:df:fe:13:43:53:90:2a:
- 05:ab:47:6a:dd:9e:9e:51:a2:f2:98:08:03:4c:3f:17:5f:55:
- e7:b0:f3:ae:62:be:a3:0f:5f:d2:3c:b9:c3:48:55:a9:f6:0d:
- 4b:fd:15:54:f5:0b:57:30:c7:f5:fb:61:ff:0a:82:35:58:21:
- f0:05:90:a2:d6:52:d4:6b:53:a8:ea:98:68:53:59:0c:11:db:
- b2:af:fd:3e
+ 11:b8:7a:ac:f4:c5:c5:cc:bc:46:f9:9e:03:6d:69:f7:3c:15:
+ 71:be:be:15:0d:a4:b9:23:cd:e0:15:a4:51:36:86:2a:65:7e:
+ 7e:29:bc:58:d1:9d:11:2d:0e:22:61:65:ca:a4:9e:61:3f:16:
+ 23:ca:ff:91:62:34:55:56:1c:b8:83:b7:62:cb:9a:07:46:53:
+ 35:53:8a:04:7e:fa:12:72:af:af:04:1d:18:a4:c1:ba:5b:c7:
+ db:01:97:58:01:d1:73:e9:85:fb:16:27:0f:d2:eb:ce:35:7e:
+ e1:a1:91:52:d7:91:03:59:ab:c0:ed:a6:bc:7b:70:bc:af:73:
+ 20:10:a6:a8:f4:45:28:0e:8b:a8:f7:e8:03:64:c6:f1:3d:12:
+ dc:f2:30:75:85:a9:68:44:ad:fb:ab:36:ed:8f:84:25:79:d3:
+ d6:f1:c8:10:1a:ac:c4:fc:65:6b:0c:77:ef:d3:61:de:91:74:
+ df:da:f3:f2:f1:07:93:5f:e0:c9:6a:6d:58:29:e1:ef:98:93:
+ 3a:13:82:09:ec:90:82:5a:d7:ef:1d:d4:50:b8:e6:ff:ef:8f:
+ 8f:9e:38:72:e5:f3:58:f9:04:90:b3:a9:a3:fd:dc:82:ab:44:
+ be:bc:47:f7:79:15:31:91:1c:c1:3c:5c:86:d1:78:bc:1e:0c:
+ 9e:af:18:60
-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx8NQXPJg
-V1UNvjnEvnR2Js6yTL6s3BesoKTDX65kWdogd3yIKA51fu9wgJwMjpQcSOpPszQe
-5M+v+CkTBm8ZD+ea31mMRNMOJnBfx6U6Nk1LUJy9FPshSvjWK0mUK99MjIky11P4
-WRTpI3bz+7QnLckoF8z+Biy9tZcwg0Cex/+eCpmn8OgMx3PKP0g6dZe93pqEbVsT
-3AxkHmZPchAozTS7FfHKZT8D26r6TUwmZIo/b2dR+hUtcXz9CxKeEsJ3nPKohnjy
-b595yVBRKEETeXl8oZPdcfcIkpn3nDf/K4K2TqmTR4PcNoNAEyKW614vraHWcDjF
-KzoLzkz8gcFJ9QIDAQABo4HLMIHIMB0GA1UdDgQWBBRYASS2O+bnhYeDb1QjasLU
-4J1sNzAfBgNVHSMEGDAWgBSSACPHwzMUYj1ZyVKkzKBcFt01LTA3BggrBgEFBQcB
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0I4uuqGN
+2WAWzRcxyQhDk5R2SFWieBkXcI6VJaz5uYEzZowsebfZ9YmSG9JOAelp5mG015Z4
+baAjz2cRzfv+Pda4rWQ/9rn1FwWJHPs9lMMYQ+QeFQ+NJiXe2/DA1mfMkPgzHNGB
+S2M+yXZhZYC0E5edLpnKomvMEKY7LyCQ7qVsz/agenvOWcYZQj+faavzwS8mjf6s
+uOwz0ta7Tj+AwNkSMzUFLTDOaxwS6olvipMVDgzAEHqZHj/7hYgJghbwYu37JmOT
+cXKbFREZwzZbEMGxElEuaq/B0Z39i38TGV3OAEk9MzLRa8UUThCSTR8oBwEpj/5d
+/5i4L5n8aCEdHwIDAQABo4HLMIHIMB0GA1UdDgQWBBQByx38EwDJZ7LWdvIKT51q
+1OKdPTAfBgNVHSMEGDAWgBQtOHLTIcoqOa0ttJoQXMtYVoLEqjA3BggrBgEFBQcB
AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
-AD3JX0pxqSjKwCdH8SOwhyxfTCDeHmCLbcNCLL/tgiYAtvhPfqw37EPqeqVY/DTN
-r1QtPjDoRI03jVtcuFK98dWrx2HZg7X1UUHt8BwCx65PV2BJyG0+RFMTzpdHeLUE
-I/0KSeWZZ5AH56VmYSuTX7Xd0P6S6DY+T8un8GTSiBHleEKJpz+2/pM62FLQjJ3q
-iSFWZwQhxcKDQhND7lwcLwCXRVZKGCGtLbO2OO1e3/4TQ1OQKgWrR2rdnp5RovKY
-CANMPxdfVeew865ivqMPX9I8ucNIVan2DUv9FVT1C1cwx/X7Yf8KgjVYIfAFkKLW
-UtRrU6jqmGhTWQwR27Kv/T4=
+ABG4eqz0xcXMvEb5ngNtafc8FXG+vhUNpLkjzeAVpFE2hiplfn4pvFjRnREtDiJh
+ZcqknmE/FiPK/5FiNFVWHLiDt2LLmgdGUzVTigR++hJyr68EHRikwbpbx9sBl1gB
+0XPphfsWJw/S6841fuGhkVLXkQNZq8Dtprx7cLyvcyAQpqj0RSgOi6j36ANkxvE9
+EtzyMHWFqWhErfurNu2PhCV509bxyBAarMT8ZWsMd+/TYd6RdN/a8/LxB5Nf4Mlq
+bVgp4e+YkzoTggnskIJa1+8d1FC45v/vj4+eOHLl81j5BJCzqaP93IKrRL68R/d5
+FTGRHME8XIbReLweDJ6vGGA=
-----END CERTIFICATE-----
Certificate:
@@ -196,30 +196,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:9d:bb:c1:61:ff:52:46:21:fd:d7:06:43:c7:e0:
- 5d:5c:c8:02:0a:44:68:63:45:92:58:8d:2f:d6:b3:
- 86:f1:01:ee:fd:34:97:4b:d6:64:fc:4f:8f:88:50:
- 56:1a:e6:20:00:9f:8c:8d:e0:c0:30:41:28:99:10:
- 14:b6:28:6c:b9:37:ef:5c:c4:ee:eb:37:ff:06:07:
- f3:5c:17:8b:aa:d6:5c:8e:19:01:8d:66:3b:8f:c9:
- e2:83:0a:0f:8c:7b:21:da:cb:4d:ea:81:11:17:92:
- 83:f5:35:19:d5:b5:92:49:3d:08:a5:c3:95:37:76:
- ad:38:9c:fd:11:ff:d4:7f:09:60:10:ea:07:93:5c:
- 2f:4c:95:53:a1:cb:3b:b1:a8:9a:9d:b9:a4:87:af:
- 78:78:6e:dc:76:bb:00:74:cd:54:75:6a:17:45:b8:
- 55:d8:87:87:88:7a:d4:98:30:05:92:df:65:07:aa:
- d7:08:b7:18:b8:35:79:bb:5e:13:e2:c3:07:65:42:
- d4:52:e3:91:41:9d:38:cb:1e:9e:5d:3b:51:7d:95:
- f4:3b:6f:31:77:57:4b:e8:74:59:82:47:60:f9:91:
- 83:19:20:54:03:a0:cb:76:5e:50:32:ec:32:57:f6:
- d0:1d:f7:46:7d:c1:ff:a7:b8:1d:80:66:f0:d9:c9:
- 59:d9
+ 00:c4:68:12:a9:88:50:04:f4:70:9b:0a:1e:d1:83:
+ 30:a0:36:08:fe:20:f5:bc:b4:a5:32:74:dd:4c:ab:
+ cc:73:a4:ce:25:ab:04:38:71:2d:5c:06:de:3b:c3:
+ 2f:b8:d9:91:f3:28:9a:70:f4:7f:be:d5:0e:4e:00:
+ db:ce:d7:c6:9f:b2:aa:0b:5e:3a:b5:e3:ad:80:78:
+ 53:f1:38:61:05:7f:00:19:e4:ec:77:b5:1d:b6:c9:
+ 35:10:ca:18:c2:71:ae:c8:34:77:dc:46:26:a1:60:
+ a4:f0:dc:49:5a:fe:af:91:98:41:1c:90:50:7d:be:
+ 94:61:0e:58:b6:21:48:83:2e:5f:c1:a6:0c:a6:72:
+ 95:4a:a5:c5:a1:d9:bd:14:dd:7c:f4:1a:db:b1:1c:
+ 09:0c:2b:60:e7:28:c0:fc:e1:36:0a:f4:68:dc:ee:
+ 89:d8:0f:47:9c:e4:7b:ca:fe:65:57:2c:3b:3b:e5:
+ b4:89:c5:04:52:55:02:dc:09:44:fd:6a:19:fc:e4:
+ 52:6f:78:96:41:79:3f:b8:85:5a:fe:7f:8f:5d:fc:
+ ee:ba:35:1d:eb:64:2d:e0:7b:f2:8c:17:d3:33:21:
+ 9c:2d:e6:85:d2:e3:2c:0f:5b:57:2c:c5:c6:de:93:
+ 24:a2:6e:1b:72:49:f5:c8:05:e2:0e:ae:68:7a:f6:
+ b5:09
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 92:00:23:C7:C3:33:14:62:3D:59:C9:52:A4:CC:A0:5C:16:DD:35:2D
+ 2D:38:72:D3:21:CA:2A:39:AD:2D:B4:9A:10:5C:CB:58:56:82:C4:AA
X509v3 Authority Key Identifier:
- keyid:92:00:23:C7:C3:33:14:62:3D:59:C9:52:A4:CC:A0:5C:16:DD:35:2D
+ keyid:2D:38:72:D3:21:CA:2A:39:AD:2D:B4:9A:10:5C:CB:58:56:82:C4:AA
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -234,47 +234,49 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 7a:76:9e:1b:08:ba:ae:df:d7:32:30:27:f7:6d:e0:00:f2:4f:
- f0:cf:dd:b5:3e:65:71:d9:97:18:5c:fc:5f:a4:61:88:41:73:
- e6:45:d2:09:3a:a5:6d:09:ab:29:13:dc:0a:43:fd:8a:1f:be:
- 7f:a5:a2:07:cc:9c:63:d5:30:51:93:eb:fc:27:17:08:d4:15:
- 80:84:1c:5e:1b:bd:00:a0:21:0d:08:8a:44:64:40:73:6c:b5:
- 50:2b:82:5f:c8:d8:fd:26:f6:91:38:df:d2:58:20:a0:ae:f2:
- 14:54:e5:d2:ff:ef:87:57:7d:bd:5e:68:b8:1b:62:e0:ae:f4:
- 08:cd:53:35:1e:a4:cf:3c:21:22:55:1e:e4:51:87:f9:74:38:
- 10:29:86:64:87:8b:55:9b:96:5a:81:e4:93:2d:c0:fb:06:7f:
- dd:17:b1:d3:24:75:73:97:df:31:d6:01:a4:be:70:e2:af:ee:
- c3:bc:fc:a1:cd:93:2d:4d:b6:b5:95:02:28:38:68:27:59:38:
- 95:d9:64:20:1e:e5:46:f1:bb:f3:5a:2c:b3:f8:d8:cc:fd:34:
- 09:fb:0b:02:b7:e5:de:0f:ea:2a:2b:0d:81:55:4d:84:d6:f6:
- ba:a4:47:fe:f1:f9:7d:3f:f9:a1:46:bf:fd:dd:89:8b:b4:22:
- 1d:86:9f:c5
------BEGIN TRUSTED_CERTIFICATE-----
+ 09:ee:80:43:2f:77:6c:2b:2f:51:79:35:59:ad:f0:a5:51:45:
+ 22:6a:0a:20:c7:eb:d1:98:c2:43:06:5a:5c:92:cb:44:24:7b:
+ 97:8e:18:b8:23:3c:8b:31:6d:54:0e:73:11:90:9e:8b:2c:a4:
+ 78:53:e6:8e:55:93:64:cc:14:04:54:a1:b6:ec:28:59:67:3a:
+ 64:0f:9d:51:ec:ba:35:06:af:5f:96:b5:3c:fe:62:0e:13:5a:
+ ee:29:af:55:d9:22:71:b3:c8:61:1a:36:4c:c8:f9:39:80:c2:
+ 06:c2:54:93:fb:2f:1b:f7:01:66:42:2a:e2:08:7b:ee:3e:0d:
+ e0:c6:07:fd:f1:cf:5e:d1:77:b2:46:21:c6:c5:9f:db:15:75:
+ 7e:ea:ec:5d:da:02:2a:42:35:7a:b5:a2:2e:86:08:8b:29:ea:
+ e9:f3:b5:cd:9d:46:96:86:c7:82:ed:64:ab:74:29:53:1c:3e:
+ f5:69:51:5b:11:1c:0d:c4:f0:01:31:a6:32:d2:68:af:1d:52:
+ c1:c4:d9:a2:9e:da:a2:bd:19:71:fa:26:f5:28:43:6a:fd:5c:
+ 97:d2:bb:e0:cd:56:0e:b8:0e:f9:4d:d5:dd:a0:4e:ae:46:68:
+ 00:93:d6:fd:ec:85:78:f4:c9:93:96:34:65:cc:f0:72:e7:0e:
+ 00:3d:d0:6b
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ27wWH/UkYh/dcGQ8fg
-XVzIAgpEaGNFkliNL9azhvEB7v00l0vWZPxPj4hQVhrmIACfjI3gwDBBKJkQFLYo
-bLk371zE7us3/wYH81wXi6rWXI4ZAY1mO4/J4oMKD4x7IdrLTeqBEReSg/U1GdW1
-kkk9CKXDlTd2rTic/RH/1H8JYBDqB5NcL0yVU6HLO7Gomp25pIeveHhu3Ha7AHTN
-VHVqF0W4VdiHh4h61JgwBZLfZQeq1wi3GLg1ebteE+LDB2VC1FLjkUGdOMsenl07
-UX2V9DtvMXdXS+h0WYJHYPmRgxkgVAOgy3ZeUDLsMlf20B33Rn3B/6e4HYBm8NnJ
-WdkCAwEAAaOByzCByDAdBgNVHQ4EFgQUkgAjx8MzFGI9WclSpMygXBbdNS0wHwYD
-VR0jBBgwFoAUkgAjx8MzFGI9WclSpMygXBbdNS0wNwYIKwYBBQUHAQEEKzApMCcG
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMRoEqmIUAT0cJsKHtGD
+MKA2CP4g9by0pTJ03UyrzHOkziWrBDhxLVwG3jvDL7jZkfMomnD0f77VDk4A287X
+xp+yqgteOrXjrYB4U/E4YQV/ABnk7He1HbbJNRDKGMJxrsg0d9xGJqFgpPDcSVr+
+r5GYQRyQUH2+lGEOWLYhSIMuX8GmDKZylUqlxaHZvRTdfPQa27EcCQwrYOcowPzh
+Ngr0aNzuidgPR5zke8r+ZVcsOzvltInFBFJVAtwJRP1qGfzkUm94lkF5P7iFWv5/
+j1387ro1HetkLeB78owX0zMhnC3mhdLjLA9bVyzFxt6TJKJuG3JJ9cgF4g6uaHr2
+tQkCAwEAAaOByzCByDAdBgNVHQ4EFgQULThy0yHKKjmtLbSaEFzLWFaCxKowHwYD
+VR0jBBgwFoAULThy0yHKKjmtLbSaEFzLWFaCxKowNwYIKwYBBQUHAQEEKzApMCcG
CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB6dp4bCLqu
-39cyMCf3beAA8k/wz921PmVx2ZcYXPxfpGGIQXPmRdIJOqVtCaspE9wKQ/2KH75/
-paIHzJxj1TBRk+v8JxcI1BWAhBxeG70AoCENCIpEZEBzbLVQK4JfyNj9JvaRON/S
-WCCgrvIUVOXS/++HV329Xmi4G2LgrvQIzVM1HqTPPCEiVR7kUYf5dDgQKYZkh4tV
-m5ZageSTLcD7Bn/dF7HTJHVzl98x1gGkvnDir+7DvPyhzZMtTba1lQIoOGgnWTiV
-2WQgHuVG8bvzWiyz+NjM/TQJ+wsCt+XeD+oqKw2BVU2E1va6pEf+8fl9P/mhRr/9
-3YmLtCIdhp/F
------END TRUSTED_CERTIFICATE-----
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAJ7oBDL3ds
+Ky9ReTVZrfClUUUiagogx+vRmMJDBlpckstEJHuXjhi4IzyLMW1UDnMRkJ6LLKR4
+U+aOVZNkzBQEVKG27ChZZzpkD51R7Lo1Bq9flrU8/mIOE1ruKa9V2SJxs8hhGjZM
+yPk5gMIGwlST+y8b9wFmQiriCHvuPg3gxgf98c9e0XeyRiHGxZ/bFXV+6uxd2gIq
+QjV6taIuhgiLKerp87XNnUaWhseC7WSrdClTHD71aVFbERwNxPABMaYy0mivHVLB
+xNmintqivRlx+ib1KENq/VyX0rvgzVYOuA75TdXdoE6uRmgAk9b97IV49MmTljRl
+zPBy5w4APdBr
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+150302120000Z
-----BEGIN TIME-----
MTUwMzAyMTIwMDAwWg==
-----END TIME-----
+SUCCESS
-----BEGIN VERIFY_RESULT-----
U1VDQ0VTUw==
-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/target-signed-by-512bit-rsa.pem b/chromium/net/data/verify_certificate_chain_unittest/target-signed-by-512bit-rsa.pem
index 8c8bd2428ef..916d5a22561 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/target-signed-by-512bit-rsa.pem
+++ b/chromium/net/data/verify_certificate_chain_unittest/target-signed-by-512bit-rsa.pem
@@ -1,6 +1,6 @@
[Created by: generate-target-signed-by-512bit-rsa.py]
-Certificate chain with 1 intermediary and a trusted root. The target
+Certificate chain with 1 intermediate and a trusted root. The target
certificate is signed using a weak RSA key (512-bit modulus), and so
verification is expected to fail.
@@ -9,7 +9,7 @@ Certificate:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
+ Issuer: CN=Intermediate
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
@@ -18,64 +18,64 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:a0:09:f8:e1:95:28:53:9e:e3:c1:a5:c0:76:05:
- 74:88:fb:fb:d0:c9:c2:3e:61:e3:a1:e3:b0:c8:81:
- a3:d1:bf:0c:f4:d8:06:3d:8f:58:45:e1:f0:00:8e:
- b1:8c:ab:bc:83:ae:d1:39:3d:6c:52:ef:76:f1:6f:
- 93:b0:b2:26:b7:b4:ab:fd:25:44:94:85:4a:c1:ad:
- 2a:6c:59:11:3c:33:63:39:e9:f1:c6:96:05:7a:a4:
- 8b:3c:74:10:cb:ae:19:eb:cd:df:eb:b0:68:91:cd:
- 5c:56:8d:41:d4:b4:4f:db:45:50:4d:01:01:10:09:
- be:84:a3:3a:98:55:a2:a6:ea:6b:fc:c7:4f:ae:cd:
- 31:60:80:2b:86:27:cf:64:f8:4f:35:32:83:02:57:
- ab:85:9e:ae:e0:39:06:03:d8:8e:c5:6f:01:5f:f6:
- 08:1f:ae:c9:a1:32:65:35:c5:9b:d7:2c:e1:6f:93:
- 41:f7:40:ff:b1:36:08:5e:35:9e:42:2b:a4:d8:0a:
- c2:ce:e4:94:cf:51:7c:76:18:d0:0a:4e:e8:37:b3:
- 44:f4:0b:31:fa:49:96:94:c8:c0:ef:3a:10:ca:4d:
- eb:ed:24:a7:d4:ec:bf:d5:5d:80:ed:d7:3a:b1:7c:
- 3f:0f:b7:cb:48:59:73:fb:af:43:5e:3e:6b:e7:a5:
- ed:01
+ 00:b8:8a:4e:71:4c:e6:58:02:9d:bc:08:20:2d:8d:
+ 74:e3:04:2f:59:9e:43:73:e0:ca:83:1b:3a:e2:30:
+ 78:de:f8:07:a1:17:62:5d:4e:35:e8:03:40:2a:1e:
+ 2e:8e:91:a4:96:bf:a7:34:45:13:19:b2:d7:b0:72:
+ d0:10:e2:ad:ab:a8:f8:41:c5:ec:ee:1c:14:cb:cf:
+ 4f:cd:37:71:bd:2d:11:8d:95:e4:fa:2b:16:8c:bf:
+ 82:1c:22:85:25:4a:88:01:af:1e:fe:e7:53:d5:03:
+ d4:36:14:ae:81:d2:3d:73:6c:96:e0:e7:d2:a4:fb:
+ 17:1d:df:6a:93:68:b5:f8:a8:70:df:d0:b6:9d:fb:
+ e5:80:a3:a8:85:df:82:f3:05:23:9f:b6:62:89:b7:
+ 72:0c:99:49:5b:07:bd:c5:fb:4c:f4:32:83:a5:3c:
+ c6:8c:6b:c1:a1:c0:ab:73:68:fb:91:14:12:3a:c5:
+ 31:89:ac:a2:4b:b6:20:3b:03:1f:50:48:ff:7b:3b:
+ be:53:e5:46:e2:ad:18:7a:d3:3e:f9:bb:d0:0b:ac:
+ 0c:23:d8:9c:92:07:6c:ee:a6:64:0d:77:ef:aa:f4:
+ 64:5a:aa:ed:52:cb:20:9a:57:d5:ab:be:8c:07:71:
+ b3:a4:43:8b:d9:7e:6f:46:2c:70:9f:c0:e3:68:89:
+ e5:2b
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 01:E0:D2:38:1C:28:DC:51:7E:F9:E6:25:7A:C5:47:ED:81:6C:FC:5F
+ 3D:5B:07:9A:2F:A5:14:87:32:C3:F8:54:71:62:3F:A1:E6:60:7F:D0
X509v3 Authority Key Identifier:
- keyid:B8:D0:79:3D:EA:8A:56:E5:90:68:D6:6C:E9:91:14:0C:AE:5A:48:10
+ keyid:7C:0E:01:A5:04:38:CE:0F:6A:AB:34:B2:CD:77:19:DB:84:C1:EC:44
Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
X509v3 CRL Distribution Points:
Full Name:
- URI:http://url-for-crl/Intermediary.crl
+ URI:http://url-for-crl/Intermediate.crl
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- be:ba:eb:82:1f:02:6b:d0:9e:c9:55:09:b1:e9:e1:82:8c:50:
- 39:7e:f5:ff:0f:4f:ef:d8:7d:52:10:07:5e:c1:c4:0e:d5:94:
- 67:d2:0e:2e:22:e6:5a:91:b5:f7:05:e3:a4:be:bc:6c:fb:38:
- 2c:df:47:55:61:bc:4c:39:14:68
+ 6a:f4:be:75:7e:66:b3:42:6e:fb:64:ed:d2:a1:d8:3d:08:04:
+ bf:93:17:0b:9b:79:df:ca:73:95:b4:5a:78:e3:96:d0:7f:5e:
+ 3c:2c:df:00:da:37:fc:61:22:9a:81:d1:bb:5d:13:6a:e4:21:
+ 18:bf:dc:49:36:4e:7a:aa:b8:6f
-----BEGIN CERTIFICATE-----
MIICyzCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgCfjh
-lShTnuPBpcB2BXSI+/vQycI+YeOh47DIgaPRvwz02AY9j1hF4fAAjrGMq7yDrtE5
-PWxS73bxb5Owsia3tKv9JUSUhUrBrSpsWRE8M2M56fHGlgV6pIs8dBDLrhnrzd/r
-sGiRzVxWjUHUtE/bRVBNAQEQCb6EozqYVaKm6mv8x0+uzTFggCuGJ89k+E81MoMC
-V6uFnq7gOQYD2I7FbwFf9ggfrsmhMmU1xZvXLOFvk0H3QP+xNgheNZ5CK6TYCsLO
-5JTPUXx2GNAKTug3s0T0CzH6SZaUyMDvOhDKTevtJKfU7L/VXYDt1zqxfD8Pt8tI
-WXP7r0NePmvnpe0BAgMBAAGjgekwgeYwHQYDVR0OBBYEFAHg0jgcKNxRfvnmJXrF
-R+2BbPxfMB8GA1UdIwQYMBaAFLjQeT3qilblkGjWbOmRFAyuWkgQMD8GCCsGAQUF
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4ik5x
+TOZYAp28CCAtjXTjBC9ZnkNz4MqDGzriMHje+AehF2JdTjXoA0AqHi6OkaSWv6c0
+RRMZstewctAQ4q2rqPhBxezuHBTLz0/NN3G9LRGNleT6KxaMv4IcIoUlSogBrx7+
+51PVA9Q2FK6B0j1zbJbg59Kk+xcd32qTaLX4qHDf0Lad++WAo6iF34LzBSOftmKJ
+t3IMmUlbB73F+0z0MoOlPMaMa8GhwKtzaPuRFBI6xTGJrKJLtiA7Ax9QSP97O75T
+5UbirRh60z75u9ALrAwj2JySB2zupmQNd++q9GRaqu1SyyCaV9WrvowHcbOkQ4vZ
+fm9GLHCfwONoieUrAgMBAAGjgekwgeYwHQYDVR0OBBYEFD1bB5ovpRSHMsP4VHFi
+P6HmYH/QMB8GA1UdIwQYMBaAFHwOAaUEOM4Paqs0ss13GduEwexEMD8GCCsGAQUF
BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAANBAL6664IfAmvQnslVCbHp4YKM
-UDl+9f8PT+/YfVIQB17BxA7VlGfSDi4i5lqRtfcF46S+vGz7OCzfR1VhvEw5FGg=
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAANBAGr0vnV+ZrNCbvtk7dKh2D0I
+BL+TFwubed/Kc5W0WnjjltB/Xjws3wDaN/xhIpqB0btdE2rkIRi/3Ek2TnqquG8=
-----END CERTIFICATE-----
Certificate:
@@ -87,22 +87,22 @@ Certificate:
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
+ Subject: CN=Intermediate
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (512 bit)
Modulus:
- 00:da:fa:51:64:db:d4:40:cf:aa:60:3f:0b:9a:0e:
- 26:21:59:0e:f1:8b:e2:75:11:de:2d:1c:e5:dc:9b:
- e2:16:ce:cf:50:a1:aa:c9:e0:19:9f:5c:e5:44:69:
- 0d:f9:0c:d7:c5:1e:cf:11:65:77:cd:37:5f:d8:fe:
- 6f:e0:99:b3:f7
+ 00:ba:89:53:56:03:c7:9f:d6:cc:d0:48:7d:3b:52:
+ 02:ee:7e:58:eb:d8:9c:8e:3c:d6:65:b2:8d:94:0d:
+ 87:48:e1:65:65:56:91:5b:1a:52:3a:84:96:46:2a:
+ 8b:1b:7d:0c:43:57:04:0d:38:55:21:5b:0b:45:06:
+ a6:1e:67:ca:5b
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- B8:D0:79:3D:EA:8A:56:E5:90:68:D6:6C:E9:91:14:0C:AE:5A:48:10
+ 7C:0E:01:A5:04:38:CE:0F:6A:AB:34:B2:CD:77:19:DB:84:C1:EC:44
X509v3 Authority Key Identifier:
- keyid:68:06:12:0B:9D:1F:3A:7C:E5:87:20:3C:ED:A3:49:5D:3E:74:28:69
+ keyid:71:59:49:4D:A5:43:49:C5:0E:E4:78:E9:5C:B7:4E:80:A8:A3:BB:5E
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -117,37 +117,37 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 8c:35:af:f3:d9:62:41:91:93:ed:8b:f6:42:3e:94:80:cf:31:
- ed:0f:a5:52:2e:51:3f:f3:3f:56:38:c5:f0:25:c5:f1:13:8c:
- 6a:80:28:58:79:e1:eb:39:25:5a:af:31:07:24:da:8c:ae:17:
- c7:56:fd:c1:d4:3a:2c:7e:7e:a4:ff:eb:66:74:96:66:e8:26:
- 52:1d:c5:d6:0a:64:ea:cd:b7:df:b8:49:b1:c4:44:c6:d0:e3:
- 94:0f:b2:b2:cb:75:5a:bf:48:c6:ad:82:46:74:a7:53:bd:55:
- 00:67:6e:ba:2c:b8:15:43:30:64:d8:10:3a:67:b0:31:df:f6:
- 9e:7e:7c:0b:63:d6:6d:b0:5d:9a:61:96:51:03:71:d3:fb:da:
- 30:b8:d1:a6:8a:4a:a2:36:58:84:34:c0:30:5a:d8:51:30:d0:
- 89:8c:1e:c3:45:32:85:17:ba:01:4d:60:04:91:23:ee:df:71:
- 0d:82:90:67:2f:04:4e:e2:64:a9:48:55:03:e7:0b:a1:b4:e3:
- e7:e9:54:3b:bc:83:f0:b3:bb:3f:1a:fd:03:95:28:0e:d2:3b:
- 8b:62:fe:bb:b7:9a:1d:15:d3:96:47:be:c9:4e:21:77:63:60:
- 3b:27:b3:3d:7e:8b:fd:3b:55:17:cf:8b:99:81:6d:92:66:5b:
- 35:62:4a:96
+ 8e:cc:d3:f3:5a:fb:ca:83:4e:55:e3:ae:2a:b7:b7:ac:9e:87:
+ f0:62:58:23:29:3d:63:7e:8d:42:60:ea:dc:3e:ec:66:19:4b:
+ e6:d6:a7:b7:e1:ea:33:88:3c:ea:8b:87:b9:e7:64:0d:35:b3:
+ 0e:ab:81:71:0c:1c:0a:f3:0a:49:23:4e:d6:21:de:7f:e5:fd:
+ 6d:8b:7a:33:2f:a6:ab:4e:b8:02:cc:01:1e:18:9a:90:f3:56:
+ f8:8a:b5:2f:68:12:c6:83:b2:91:59:00:51:86:75:68:45:3b:
+ 27:c4:e0:0d:ed:e7:51:2d:47:60:26:19:02:fd:43:27:81:ad:
+ 33:cb:eb:98:9a:a1:2e:81:d3:81:52:4a:1d:19:e9:30:f9:fc:
+ 6b:e7:26:c8:c1:6c:65:e4:66:d4:cc:82:16:0a:a6:b9:68:3a:
+ eb:ee:cd:86:aa:a7:80:ed:4f:77:47:d2:c6:1b:eb:53:de:f3:
+ eb:24:60:41:ac:77:08:43:1b:76:ce:a6:4b:f1:4e:1d:32:2b:
+ 31:bd:59:52:f1:60:e7:f5:db:6d:bf:be:af:55:9b:11:63:f7:
+ 6e:19:2c:17:4b:db:fe:40:27:ae:02:f5:c2:17:62:21:7b:ac:
+ 38:d6:17:3e:5c:80:61:6d:95:63:e4:64:d3:07:23:9f:14:bb:
+ df:b2:eb:c2
-----BEGIN CERTIFICATE-----
MIICpTCCAY2gAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANr6UWTb1EDPqmA/C5oO
-JiFZDvGL4nUR3i0c5dyb4hbOz1ChqsngGZ9c5URpDfkM18UezxFld803X9j+b+CZ
-s/cCAwEAAaOByzCByDAdBgNVHQ4EFgQUuNB5PeqKVuWQaNZs6ZEUDK5aSBAwHwYD
-VR0jBBgwFoAUaAYSC50fOnzlhyA87aNJXT50KGkwNwYIKwYBBQUHAQEEKzApMCcG
+ZXJtZWRpYXRlMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALqJU1YDx5/WzNBIfTtS
+Au5+WOvYnI481mWyjZQNh0jhZWVWkVsaUjqElkYqixt9DENXBA04VSFbC0UGph5n
+ylsCAwEAAaOByzCByDAdBgNVHQ4EFgQUfA4BpQQ4zg9qqzSyzXcZ24TB7EQwHwYD
+VR0jBBgwFoAUcVlJTaVDScUO5HjpXLdOgKiju14wNwYIKwYBBQUHAQEEKzApMCcG
CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCMNa/z2WJB
-kZPti/ZCPpSAzzHtD6VSLlE/8z9WOMXwJcXxE4xqgChYeeHrOSVarzEHJNqMrhfH
-Vv3B1Dosfn6k/+tmdJZm6CZSHcXWCmTqzbffuEmxxETG0OOUD7Kyy3Vav0jGrYJG
-dKdTvVUAZ266LLgVQzBk2BA6Z7Ax3/aefnwLY9ZtsF2aYZZRA3HT+9owuNGmikqi
-NliENMAwWthRMNCJjB7DRTKFF7oBTWAEkSPu33ENgpBnLwRO4mSpSFUD5wuhtOPn
-6VQ7vIPws7s/Gv0DlSgO0juLYv67t5odFdOWR77JTiF3Y2A7J7M9fov9O1UXz4uZ
-gW2SZls1YkqW
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCOzNPzWvvK
+g05V464qt7esnofwYlgjKT1jfo1CYOrcPuxmGUvm1qe34eoziDzqi4e552QNNbMO
+q4FxDBwK8wpJI07WId5/5f1ti3ozL6arTrgCzAEeGJqQ81b4irUvaBLGg7KRWQBR
+hnVoRTsnxOAN7edRLUdgJhkC/UMnga0zy+uYmqEugdOBUkodGekw+fxr5ybIwWxl
+5GbUzIIWCqa5aDrr7s2GqqeA7U93R9LGG+tT3vPrJGBBrHcIQxt2zqZL8U4dMisx
+vVlS8WDn9dttv76vVZsRY/duGSwXS9v+QCeuAvXCF2Ihe6w41hc+XIBhbZVj5GTT
+ByOfFLvfsuvC
-----END CERTIFICATE-----
Certificate:
@@ -164,30 +164,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:cc:43:57:ce:f5:69:b5:17:2d:24:1e:10:48:61:
- 1e:6e:27:06:10:ae:6d:cd:70:97:4c:39:7b:0d:68:
- 76:49:5b:2a:56:cf:24:d3:35:e4:f9:44:b0:60:c2:
- db:ee:58:f0:2c:3f:25:53:95:bf:fc:3b:cf:1a:5c:
- de:94:67:30:7f:6b:7b:c1:9c:d9:55:91:8b:34:57:
- a7:4f:d0:d7:38:8c:e6:57:ae:f6:61:66:bb:fb:4e:
- d3:b0:d0:c0:74:83:e3:43:7a:15:ab:29:fa:3f:65:
- b5:58:3b:0b:76:cf:b9:85:d9:2a:5b:bf:81:4d:d7:
- bb:72:cf:30:91:1a:0a:4f:6c:64:48:13:fe:cc:14:
- 21:f0:74:b8:90:73:f7:d5:fe:5b:dd:b2:7a:71:1a:
- e3:c3:22:5a:37:38:db:d0:39:62:b3:87:0e:7d:a8:
- 93:68:82:01:29:36:eb:30:20:66:d9:2a:f8:e9:7d:
- 53:ac:93:c1:68:c1:21:66:26:9e:4d:34:8a:14:c2:
- 38:c0:6e:57:9a:c8:93:c1:7d:7d:d8:22:6e:bb:5e:
- ff:dd:e0:af:e4:af:32:6d:f2:e7:57:d4:53:8d:ea:
- f9:ca:72:d3:3a:4e:19:e3:b8:b7:4f:fb:d8:5b:41:
- da:0e:17:59:e2:88:cd:c2:b7:6b:d4:64:50:f0:1e:
- 36:9d
+ 00:ca:5e:08:17:b7:7c:c4:55:39:a2:1c:7f:97:49:
+ b0:bb:88:3e:9e:ed:46:36:41:c2:a7:5e:2b:ce:bb:
+ 7b:d2:d2:a8:3b:a3:53:27:39:ac:3a:76:48:a2:85:
+ 97:3f:ba:98:9f:14:f9:b9:31:64:e5:27:a8:9a:23:
+ ae:7d:12:39:65:c0:10:f3:6d:2d:a3:45:3d:c3:69:
+ e6:cf:3e:4d:8a:5c:37:a5:6c:32:17:7c:ab:8f:62:
+ 0e:e4:57:6b:e1:64:22:8d:3b:ad:c6:93:60:4a:c4:
+ 32:6d:be:c4:6b:06:e1:4b:e0:89:3c:ef:ad:78:94:
+ bd:3d:d1:bb:19:1a:86:98:43:0e:84:bb:68:11:47:
+ 9a:06:49:33:e9:48:e6:f2:00:0e:ef:e7:4d:2a:1b:
+ b2:aa:5b:a8:8d:59:ac:b7:c8:77:5d:c9:9f:d3:e8:
+ c7:f2:88:0a:ce:6e:34:b5:8f:5a:63:24:68:42:2f:
+ 60:2c:a5:82:44:e9:12:1f:c3:7a:01:c3:e7:e3:24:
+ 97:0b:bc:5e:48:e1:33:4b:a0:cd:fa:ce:75:90:97:
+ 20:f4:0b:4c:8e:69:c5:8b:cd:1c:ac:8a:7f:d4:18:
+ 22:c7:10:09:52:dc:3a:17:3d:3a:5c:03:99:ee:f8:
+ 9d:a0:bf:ef:72:33:df:43:8d:9f:1b:1c:e3:22:24:
+ 73:99
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 68:06:12:0B:9D:1F:3A:7C:E5:87:20:3C:ED:A3:49:5D:3E:74:28:69
+ 71:59:49:4D:A5:43:49:C5:0E:E4:78:E9:5C:B7:4E:80:A8:A3:BB:5E
X509v3 Authority Key Identifier:
- keyid:68:06:12:0B:9D:1F:3A:7C:E5:87:20:3C:ED:A3:49:5D:3E:74:28:69
+ keyid:71:59:49:4D:A5:43:49:C5:0E:E4:78:E9:5C:B7:4E:80:A8:A3:BB:5E
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -202,47 +202,61 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 2a:56:07:28:0a:b2:16:a5:3e:e3:cc:7e:10:47:8d:88:04:be:
- 92:d6:ef:fa:c2:e3:5f:5f:57:3a:75:5a:8e:8e:62:e0:94:26:
- 32:d2:ab:d3:d7:88:7e:d0:14:b1:1b:1a:5d:15:87:15:45:ae:
- 47:50:0b:50:dd:52:55:03:0b:cb:91:13:b0:96:20:24:c5:aa:
- 13:f5:4f:60:20:b6:46:6a:a6:cf:9d:4e:88:09:77:ad:4d:6f:
- ea:d6:18:81:ac:7c:ad:59:9c:bb:f5:c5:62:e5:e4:b3:61:b2:
- fb:f4:22:4e:38:a4:42:3a:e1:00:54:78:dd:24:90:20:47:d2:
- 74:2b:89:44:64:04:02:3b:f9:8b:fa:35:aa:90:c1:73:82:95:
- 94:fa:5f:85:e9:af:e1:3e:33:2b:1b:91:31:1d:94:ee:1c:0c:
- e5:22:de:48:d4:2d:f7:3a:16:7e:f2:40:dc:ce:ec:3e:41:0d:
- 12:3e:9c:ff:15:2b:9b:b3:80:87:02:50:76:ae:e1:05:dd:89:
- 72:fc:49:e5:81:1f:91:cc:c8:27:b7:2c:b2:ef:71:a0:97:76:
- 49:da:71:75:24:5e:45:2d:5b:2b:79:d2:b0:a3:b8:85:13:d5:
- 68:d7:53:f0:d1:b8:87:d1:84:7c:9e:e1:18:23:f4:cc:2a:8d:
- f3:93:51:5e
------BEGIN TRUSTED_CERTIFICATE-----
+ 20:51:cc:39:0f:3c:0c:67:47:0c:73:f0:00:0d:57:fb:6f:fe:
+ 4c:e3:c1:d1:a6:f7:40:54:4c:91:0f:ca:e1:eb:b3:7a:44:0e:
+ 57:f5:81:1f:9a:4f:81:57:d8:91:01:7b:09:6a:61:19:04:8f:
+ 00:7a:d1:5b:3f:cb:1b:c0:53:a4:da:dc:40:a5:ef:9b:59:1a:
+ fc:99:b2:0d:66:22:ee:d7:da:69:72:4d:b1:44:e9:2d:57:84:
+ 52:d5:2b:c5:77:ac:a7:d0:f2:27:12:6b:5c:42:7a:3d:fc:e8:
+ 04:91:98:aa:1d:3f:40:9d:9b:e2:43:24:47:7b:b8:24:23:a3:
+ 47:24:cd:9a:44:87:f8:a7:c4:07:90:9a:73:60:e1:0e:7b:82:
+ a1:ef:73:4e:02:46:6d:06:e2:58:8f:79:47:79:a6:59:75:cf:
+ ac:5d:e2:37:6c:88:3f:bf:57:00:f5:fb:09:53:f4:5f:06:42:
+ 58:5e:75:48:96:7d:4f:dd:3b:45:d3:7c:61:8f:75:20:17:a0:
+ 2e:1c:08:4b:22:3f:37:be:d7:43:89:da:59:ac:79:87:1e:6a:
+ cc:53:4d:5b:e9:0a:d6:40:a5:a0:28:99:57:44:5d:d2:7b:bf:
+ 02:38:a3:c4:df:14:a9:c1:b2:ec:15:21:7b:84:a1:a1:56:f8:
+ b9:45:42:cd
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMxDV871abUXLSQeEEhh
-Hm4nBhCubc1wl0w5ew1odklbKlbPJNM15PlEsGDC2+5Y8Cw/JVOVv/w7zxpc3pRn
-MH9re8Gc2VWRizRXp0/Q1ziM5leu9mFmu/tO07DQwHSD40N6Fasp+j9ltVg7C3bP
-uYXZKlu/gU3Xu3LPMJEaCk9sZEgT/swUIfB0uJBz99X+W92yenEa48MiWjc429A5
-YrOHDn2ok2iCASk26zAgZtkq+Ol9U6yTwWjBIWYmnk00ihTCOMBuV5rIk8F9fdgi
-brte/93gr+SvMm3y51fUU43q+cpy0zpOGeO4t0/72FtB2g4XWeKIzcK3a9RkUPAe
-Np0CAwEAAaOByzCByDAdBgNVHQ4EFgQUaAYSC50fOnzlhyA87aNJXT50KGkwHwYD
-VR0jBBgwFoAUaAYSC50fOnzlhyA87aNJXT50KGkwNwYIKwYBBQUHAQEEKzApMCcG
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMpeCBe3fMRVOaIcf5dJ
+sLuIPp7tRjZBwqdeK867e9LSqDujUyc5rDp2SKKFlz+6mJ8U+bkxZOUnqJojrn0S
+OWXAEPNtLaNFPcNp5s8+TYpcN6VsMhd8q49iDuRXa+FkIo07rcaTYErEMm2+xGsG
+4UvgiTzvrXiUvT3RuxkahphDDoS7aBFHmgZJM+lI5vIADu/nTSobsqpbqI1ZrLfI
+d13Jn9Pox/KICs5uNLWPWmMkaEIvYCylgkTpEh/DegHD5+Mklwu8XkjhM0ugzfrO
+dZCXIPQLTI5pxYvNHKyKf9QYIscQCVLcOhc9OlwDme74naC/73Iz30ONnxsc4yIk
+c5kCAwEAAaOByzCByDAdBgNVHQ4EFgQUcVlJTaVDScUO5HjpXLdOgKiju14wHwYD
+VR0jBBgwFoAUcVlJTaVDScUO5HjpXLdOgKiju14wNwYIKwYBBQUHAQEEKzApMCcG
CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAqVgcoCrIW
-pT7jzH4QR42IBL6S1u/6wuNfX1c6dVqOjmLglCYy0qvT14h+0BSxGxpdFYcVRa5H
-UAtQ3VJVAwvLkROwliAkxaoT9U9gILZGaqbPnU6ICXetTW/q1hiBrHytWZy79cVi
-5eSzYbL79CJOOKRCOuEAVHjdJJAgR9J0K4lEZAQCO/mL+jWqkMFzgpWU+l+F6a/h
-PjMrG5ExHZTuHAzlIt5I1C33OhZ+8kDczuw+QQ0SPpz/FSubs4CHAlB2ruEF3Yly
-/EnlgR+RzMgntyyy73Ggl3ZJ2nF1JF5FLVsredKwo7iFE9Vo11Pw0biH0YR8nuEY
-I/TMKo3zk1Fe
------END TRUSTED_CERTIFICATE-----
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAgUcw5DzwM
+Z0cMc/AADVf7b/5M48HRpvdAVEyRD8rh67N6RA5X9YEfmk+BV9iRAXsJamEZBI8A
+etFbP8sbwFOk2txApe+bWRr8mbINZiLu19ppck2xROktV4RS1SvFd6yn0PInEmtc
+Qno9/OgEkZiqHT9AnZviQyRHe7gkI6NHJM2aRIf4p8QHkJpzYOEOe4Kh73NOAkZt
+BuJYj3lHeaZZdc+sXeI3bIg/v1cA9fsJU/RfBkJYXnVIln1P3TtF03xhj3UgF6Au
+HAhLIj83vtdDidpZrHmHHmrMU01b6QrWQKWgKJlXRF3Se78COKPE3xSpwbLsFSF7
+hKGhVvi5RULN
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+150302120000Z
-----BEGIN TIME-----
MTUwMzAyMTIwMDAwWg==
-----END TIME-----
+FAIL
-----BEGIN VERIFY_RESULT-----
RkFJTA==
-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 1
+ [Error] RSA modulus too small
+ actual: 512
+ minimum: 1024
+ [Error] Unacceptable modulus length for RSA key
+ [Error] VerifySignedData failed
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMQogICAgICBbRXJyb3JdIFJTQSBtb2R1bHVzIHRvbyBzbWFsbAogICAgICAgIGFjdHVhbDogNTEyCiAgICAgICAgbWluaW11bTogMTAyNAogICAgICBbRXJyb3JdIFVuYWNjZXB0YWJsZSBtb2R1bHVzIGxlbmd0aCBmb3IgUlNBIGtleQogICAgICBbRXJyb3JdIFZlcmlmeVNpZ25lZERhdGEgZmFpbGVkCg==
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/target-signed-using-ecdsa.pem b/chromium/net/data/verify_certificate_chain_unittest/target-signed-using-ecdsa.pem
index 6109796debb..95a19b157a2 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/target-signed-using-ecdsa.pem
+++ b/chromium/net/data/verify_certificate_chain_unittest/target-signed-using-ecdsa.pem
@@ -1,6 +1,6 @@
[Created by: generate-target-signed-using-ecdsa.py]
-Certificate chain with a trusted root using RSA, and intermediary using EC,
+Certificate chain with a trusted root using RSA, and intermediate using EC,
and a target certificate using RSA. Verification is expected to succeed.
Certificate:
@@ -8,7 +8,7 @@ Certificate:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: ecdsa-with-SHA256
- Issuer: CN=Intermediary
+ Issuer: CN=Intermediate
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
@@ -17,67 +17,67 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:f5:15:82:5b:5b:ef:98:fd:63:b3:5b:08:9c:21:
- 8b:be:10:f1:3a:ab:17:e8:f2:9c:37:24:80:41:6a:
- 87:71:1d:9a:ea:c3:a6:f7:25:e3:09:03:3f:92:2e:
- e1:bc:9e:fd:70:65:e9:29:21:4f:46:01:12:20:e2:
- 08:d9:bd:86:40:5d:3d:b9:6a:c5:ad:3f:dc:82:00:
- 75:7b:da:26:a1:c9:49:f2:b5:30:6c:40:07:94:c6:
- f4:41:1f:88:3a:d7:89:ab:86:79:50:cc:85:8e:f6:
- a4:fc:7b:03:70:74:1e:6e:09:98:ff:b4:8a:ea:c0:
- c1:e3:07:ff:8d:f8:e8:bc:f5:fd:6e:aa:db:fc:26:
- 2e:44:bd:52:e3:66:f5:58:6d:ea:0c:30:19:ed:8f:
- db:cd:1f:40:20:2f:36:35:d7:63:b5:d7:2c:e8:4b:
- d3:e2:90:82:2f:27:4d:22:8a:94:e3:fb:c7:40:77:
- e2:e0:56:c7:70:b6:ae:9b:e9:7c:fa:b5:d0:40:34:
- dd:0b:59:96:0d:ba:84:47:87:62:c1:3e:1f:21:5b:
- 3b:15:56:3a:8b:e8:4e:6c:02:c8:da:dc:b3:2b:a3:
- b9:7e:c6:dc:06:94:9b:0c:ea:fc:7e:02:d3:3f:d2:
- 87:30:da:c4:41:1a:5f:1f:89:c9:6f:39:96:e5:fd:
- 3a:c9
+ 00:c1:2c:42:ca:d9:bd:0d:55:79:40:9a:cf:f4:1b:
+ de:4e:e7:8b:77:40:55:83:bf:2c:27:72:58:db:62:
+ 24:12:e2:e5:4e:36:09:95:e0:0d:5b:09:d9:f8:bf:
+ e5:f8:3a:d4:9a:c9:5a:ff:16:44:16:21:15:bc:cf:
+ f6:99:ad:5c:bf:74:9a:02:3e:91:99:28:2b:76:eb:
+ fe:14:8c:24:a2:f9:41:b3:7a:86:b2:15:34:a4:fc:
+ 93:49:42:b6:ee:20:70:61:f8:8e:ae:8b:55:aa:4f:
+ 3f:ec:1e:63:45:24:c4:01:c1:68:c2:cf:a7:c5:29:
+ 58:a7:c2:cc:89:00:25:b0:1a:b1:a0:dd:52:e4:3c:
+ 41:ff:2a:3b:97:07:63:70:13:01:3d:eb:1d:a1:12:
+ f2:27:0a:c0:47:8a:96:f4:c9:f0:2f:b1:2a:7a:fa:
+ 57:f8:60:98:c5:b8:03:ce:36:fc:32:73:39:13:46:
+ 5b:71:02:42:22:45:4c:11:1d:3d:e1:77:53:9c:8d:
+ 0b:a0:bf:68:67:b4:b2:2b:6a:9a:1f:da:dd:dd:c2:
+ 0d:0c:12:00:ff:d9:d2:36:77:52:72:32:30:ea:68:
+ bb:62:55:37:24:aa:13:92:a4:b5:8c:9d:71:19:6b:
+ 4a:1a:38:b0:21:79:14:70:d3:e9:7e:92:91:fc:8a:
+ c7:35
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 0A:36:4B:AA:5E:42:C2:6B:CE:3C:58:0C:33:53:9B:ED:09:42:89:B9
+ E2:9C:21:ED:AF:F9:55:73:3F:68:B8:CD:03:B2:45:FB:C8:4F:35:8C
X509v3 Authority Key Identifier:
- keyid:A4:A1:01:1C:8F:94:62:C3:11:19:36:76:04:DC:A9:AF:6F:B6:11:9C
+ keyid:71:4E:D7:4E:A8:0A:43:13:41:FE:F4:50:09:92:D0:56:1D:44:8A:3F
Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
X509v3 CRL Distribution Points:
Full Name:
- URI:http://url-for-crl/Intermediary.crl
+ URI:http://url-for-crl/Intermediate.crl
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: ecdsa-with-SHA256
- 30:64:02:30:3b:0e:cc:c2:70:77:25:fe:01:46:fb:e7:fe:ee:
- 68:07:50:f1:14:b8:9a:6f:53:bb:1f:4f:7f:ba:62:d2:76:06:
- 4b:d4:93:8a:1b:f6:3c:96:91:8c:57:90:a2:99:5d:0b:02:30:
- 3e:98:92:c5:01:13:f9:d4:21:bc:44:14:a6:9b:b9:8e:f0:86:
- ec:67:c8:12:07:74:41:8c:f0:f3:e8:b7:cc:e3:23:a0:a1:05:
- 2f:66:73:be:62:9b:1c:ce:70:fe:eb:09
+ 30:65:02:30:16:0c:16:b2:2c:2e:68:f7:e6:c9:e6:fc:25:67:
+ ab:1b:cd:65:0b:30:ca:d4:92:0b:0a:26:40:cd:7b:47:b5:37:
+ 8b:84:12:b2:51:53:3e:a9:b8:d0:fa:0b:e5:ec:54:2e:02:31:
+ 00:e5:d7:43:9b:58:f1:7e:90:79:de:63:49:7f:5b:fe:7a:34:
+ 2e:5a:d1:92:13:66:3a:e0:1c:ea:77:e1:98:1c:a9:38:d5:ce:
+ 98:7b:1f:5b:8a:d4:01:cb:35:7a:d5:74:8a
-----BEGIN CERTIFICATE-----
-MIIC6zCCAnKgAwIBAgIBATAKBggqhkjOPQQDAjAXMRUwEwYDVQQDDAxJbnRlcm1l
-ZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYDVQQD
-DAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD1FYJbW++Y
-/WOzWwicIYu+EPE6qxfo8pw3JIBBaodxHZrqw6b3JeMJAz+SLuG8nv1wZekpIU9G
-ARIg4gjZvYZAXT25asWtP9yCAHV72iahyUnytTBsQAeUxvRBH4g614mrhnlQzIWO
-9qT8ewNwdB5uCZj/tIrqwMHjB/+N+Oi89f1uqtv8Ji5EvVLjZvVYbeoMMBntj9vN
-H0AgLzY112O11yzoS9PikIIvJ00iipTj+8dAd+LgVsdwtq6b6Xz6tdBANN0LWZYN
-uoRHh2LBPh8hWzsVVjqL6E5sAsja3LMro7l+xtwGlJsM6vx+AtM/0ocw2sRBGl8f
-iclvOZbl/TrJAgMBAAGjgekwgeYwHQYDVR0OBBYEFAo2S6peQsJrzjxYDDNTm+0J
-Qom5MB8GA1UdIwQYMBaAFKShARyPlGLDERk2dgTcqa9vthGcMD8GCCsGAQUFBwEB
-BDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVkaWFy
-eS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0ludGVy
-bWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB
-BggrBgEFBQcDAjAKBggqhkjOPQQDAgNnADBkAjA7DszCcHcl/gFG++f+7mgHUPEU
-uJpvU7sfT3+6YtJ2BkvUk4ob9jyWkYxXkKKZXQsCMD6YksUBE/nUIbxEFKabuY7w
-huxnyBIHdEGM8PPot8zjI6ChBS9mc75imxzOcP7rCQ==
+MIIC7DCCAnKgAwIBAgIBATAKBggqhkjOPQQDAjAXMRUwEwYDVQQDDAxJbnRlcm1l
+ZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYDVQQD
+DAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBLELK2b0N
+VXlAms/0G95O54t3QFWDvywncljbYiQS4uVONgmV4A1bCdn4v+X4OtSayVr/FkQW
+IRW8z/aZrVy/dJoCPpGZKCt26/4UjCSi+UGzeoayFTSk/JNJQrbuIHBh+I6ui1Wq
+Tz/sHmNFJMQBwWjCz6fFKVinwsyJACWwGrGg3VLkPEH/KjuXB2NwEwE96x2hEvIn
+CsBHipb0yfAvsSp6+lf4YJjFuAPONvwyczkTRltxAkIiRUwRHT3hd1OcjQugv2hn
+tLIrapof2t3dwg0MEgD/2dI2d1JyMjDqaLtiVTckqhOSpLWMnXEZa0oaOLAheRRw
+0+l+kpH8isc1AgMBAAGjgekwgeYwHQYDVR0OBBYEFOKcIe2v+VVzP2i4zQOyRfvI
+TzWMMB8GA1UdIwQYMBaAFHFO106oCkMTQf70UAmS0FYdRIo/MD8GCCsGAQUFBwEB
+BDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVkaWF0
+ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0ludGVy
+bWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB
+BggrBgEFBQcDAjAKBggqhkjOPQQDAgNoADBlAjAWDBayLC5o9+bJ5vwlZ6sbzWUL
+MMrUkgsKJkDNe0e1N4uEErJRUz6puND6C+XsVC4CMQDl10ObWPF+kHneY0l/W/56
+NC5a0ZITZjrgHOp34ZgcqTjVzph7H1uK1AHLNXrVdIo=
-----END CERTIFICATE-----
Certificate:
@@ -89,24 +89,24 @@ Certificate:
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
+ Subject: CN=Intermediate
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (384 bit)
pub:
- 04:ca:bc:6c:d5:4b:51:ef:d3:7d:8a:46:12:ab:5f:
- d4:f3:3c:7d:eb:40:8b:de:0f:79:6d:6f:a4:40:0f:
- 96:51:8a:00:20:48:7a:d3:d4:30:2e:5b:1d:9f:e1:
- 00:3e:54:cb:93:62:21:7c:09:57:2e:43:38:08:77:
- 5c:1c:8b:aa:17:c1:22:c0:db:01:bf:c0:80:0a:24:
- 68:0d:2d:ce:51:e4:a3:2a:c9:42:0b:7c:57:82:31:
- 94:2f:b7:a8:42:9c:4e
+ 04:ff:41:5f:16:8c:e0:75:59:3b:4a:9c:84:3e:79:
+ 93:48:a5:98:7e:93:58:58:d5:c9:ca:60:b8:6d:0c:
+ 84:81:40:de:22:95:f1:6e:56:49:8f:02:45:ce:fe:
+ e8:71:71:02:25:a7:47:5f:63:0e:4a:46:4d:e0:b3:
+ 73:9e:d8:91:2a:ad:51:47:80:b0:f5:4a:5e:0d:93:
+ a6:78:93:a7:f9:1d:ad:b6:23:78:2e:23:e0:62:f6:
+ 77:f8:1c:db:31:82:c1
ASN1 OID: secp384r1
X509v3 extensions:
X509v3 Subject Key Identifier:
- A4:A1:01:1C:8F:94:62:C3:11:19:36:76:04:DC:A9:AF:6F:B6:11:9C
+ 71:4E:D7:4E:A8:0A:43:13:41:FE:F4:50:09:92:D0:56:1D:44:8A:3F
X509v3 Authority Key Identifier:
- keyid:E9:AC:73:09:B6:86:CD:95:42:29:5D:E5:EC:C7:99:29:12:91:8C:53
+ keyid:39:BF:53:7E:B4:7B:97:5D:7A:E5:12:6D:FA:8B:79:C5:67:3E:1E:E4
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -121,37 +121,37 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 22:50:e8:71:34:bf:8b:44:c5:4e:82:31:fd:50:48:f4:fa:3a:
- 01:4a:f9:71:a6:a9:a2:d0:1e:bc:d3:1d:dc:ac:8f:4e:db:58:
- 8a:6b:a2:64:29:6e:f5:1b:0b:87:2e:f5:bd:dd:92:7a:5f:4e:
- a6:aa:1d:b4:7c:f2:eb:5a:2b:17:83:99:29:1f:2b:12:45:9b:
- 1a:cd:d3:b1:71:a3:d9:7d:cf:78:f4:64:ce:03:a5:0b:c7:98:
- e8:73:58:e2:26:47:5c:c0:ed:ac:c0:11:b8:39:11:19:39:fc:
- 01:b6:4c:a2:f5:4a:ae:a3:9e:3c:82:73:3e:b5:2c:28:63:ec:
- 14:a2:9f:a7:d7:4b:3e:f3:56:50:f6:9e:87:9b:d1:38:fa:78:
- 2e:7f:29:fe:4a:a8:d6:43:c4:05:d6:d6:67:7f:52:90:36:53:
- ff:a6:78:1f:7f:f7:ad:66:65:7d:4b:57:3c:d6:b3:19:9d:08:
- af:d2:5b:1a:76:42:ff:b2:6b:2c:0d:d1:1d:05:c0:d8:28:02:
- 9b:cb:f6:1d:7a:35:93:b9:c9:76:2d:d3:ef:f4:07:bf:d6:8b:
- 33:2a:83:69:8a:68:63:0a:b9:45:f6:e4:12:38:37:87:d6:53:
- 46:33:ae:f8:72:d3:e5:e9:93:bb:ba:db:8d:73:01:b1:79:0f:
- d8:1c:a0:d0
+ d2:53:ac:75:a8:06:52:55:48:4f:d0:a3:92:51:d4:23:06:f7:
+ 98:2b:b4:15:2e:65:26:44:c0:75:64:c5:df:73:cd:dc:a3:5a:
+ 7f:86:f6:e8:6b:bd:8f:3a:7e:20:6e:b9:df:4c:07:78:f5:1d:
+ b4:4c:d0:8b:0b:71:ad:74:6d:f7:48:fb:a8:45:e6:2f:87:d8:
+ 89:e3:de:b4:15:fa:71:47:19:c6:88:a2:9c:66:cd:44:05:22:
+ f8:d8:0b:1f:72:4d:ef:98:76:15:7d:41:20:53:2b:ef:e1:35:
+ 31:7c:b7:8e:70:c0:23:5a:ab:9a:58:5e:0b:02:d6:9c:7c:6e:
+ d0:29:ad:19:95:e2:1f:e8:18:c7:c3:25:cf:21:30:52:28:32:
+ fa:cf:07:4a:19:f2:39:bd:bb:05:96:4e:11:91:9f:b4:ae:5c:
+ 9e:bc:ac:f4:4a:b8:9a:73:40:4b:88:05:6d:3c:9e:c7:7d:0a:
+ 16:4f:d1:96:67:17:fa:e6:43:8c:0e:4c:26:2e:4c:51:8b:18:
+ ee:8d:e4:69:09:ca:7f:ea:8d:33:38:fa:45:e5:d7:06:74:1d:
+ bd:05:32:c7:1f:fd:84:9e:42:f7:7d:f2:24:ab:54:50:ba:69:
+ 3e:84:15:fe:f9:20:5a:77:8a:20:af:f3:97:35:1e:16:ee:92:
+ ef:9d:c7:5d
-----BEGIN CERTIFICATE-----
MIICvzCCAaegAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEyrxs1UtR79N9ikYSq1/U
-8zx960CL3g95bW+kQA+WUYoAIEh609QwLlsdn+EAPlTLk2IhfAlXLkM4CHdcHIuq
-F8EiwNsBv8CACiRoDS3OUeSjKslCC3xXgjGUL7eoQpxOo4HLMIHIMB0GA1UdDgQW
-BBSkoQEcj5RiwxEZNnYE3Kmvb7YRnDAfBgNVHSMEGDAWgBTprHMJtobNlUIpXeXs
-x5kpEpGMUzA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwt
+ZXJtZWRpYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE/0FfFozgdVk7SpyEPnmT
+SKWYfpNYWNXJymC4bQyEgUDeIpXxblZJjwJFzv7ocXECJadHX2MOSkZN4LNzntiR
+Kq1RR4Cw9UpeDZOmeJOn+R2ttiN4LiPgYvZ3+BzbMYLBo4HLMIHIMB0GA1UdDgQW
+BBRxTtdOqApDE0H+9FAJktBWHUSKPzAfBgNVHSMEGDAWgBQ5v1N+tHuXXXrlEm36
+i3nFZz4e5DA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwt
Zm9yLWFpYS9Sb290LmNlcjAsBgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZv
ci1jcmwvUm9vdC5jcmwwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
-DQYJKoZIhvcNAQELBQADggEBACJQ6HE0v4tExU6CMf1QSPT6OgFK+XGmqaLQHrzT
-Hdysj07bWIpromQpbvUbC4cu9b3dknpfTqaqHbR88utaKxeDmSkfKxJFmxrN07Fx
-o9l9z3j0ZM4DpQvHmOhzWOImR1zA7azAEbg5ERk5/AG2TKL1Sq6jnjyCcz61LChj
-7BSin6fXSz7zVlD2noeb0Tj6eC5/Kf5KqNZDxAXW1md/UpA2U/+meB9/961mZX1L
-VzzWsxmdCK/SWxp2Qv+yaywN0R0FwNgoApvL9h16NZO5yXYt0+/0B7/WizMqg2mK
-aGMKuUX25BI4N4fWU0Yzrvhy0+Xpk7u6241zAbF5D9gcoNA=
+DQYJKoZIhvcNAQELBQADggEBANJTrHWoBlJVSE/Qo5JR1CMG95grtBUuZSZEwHVk
+xd9zzdyjWn+G9uhrvY86fiBuud9MB3j1HbRM0IsLca10bfdI+6hF5i+H2Inj3rQV
++nFHGcaIopxmzUQFIvjYCx9yTe+YdhV9QSBTK+/hNTF8t45wwCNaq5pYXgsC1px8
+btAprRmV4h/oGMfDJc8hMFIoMvrPB0oZ8jm9uwWWThGRn7SuXJ68rPRKuJpzQEuI
+BW08nsd9ChZP0ZZnF/rmQ4wOTCYuTFGLGO6N5GkJyn/qjTM4+kXl1wZ0Hb0FMscf
+/YSeQvd98iSrVFC6aT6EFf75IFp3iiCv85c1Hhbuku+dx10=
-----END CERTIFICATE-----
Certificate:
@@ -168,30 +168,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:b8:3c:af:88:6d:5e:96:7e:58:90:09:5d:40:54:
- 11:4f:55:ff:bb:e7:94:1b:ba:d7:df:b9:47:c3:ff:
- 84:71:22:da:a8:89:e6:98:71:4b:ae:d8:c1:19:df:
- 4f:69:bf:c2:3d:da:0a:a8:65:08:a8:c3:2c:aa:34:
- c7:a2:b9:00:45:6f:2e:69:6e:90:ee:9b:a2:f6:20:
- 0d:75:17:c2:33:e0:59:2c:7d:d6:3d:23:34:0e:e6:
- e0:49:74:3b:21:04:9f:6b:25:92:1a:2e:0f:e5:4a:
- 0a:96:85:0d:69:dc:ab:31:23:19:b7:d0:54:e6:18:
- c6:a1:ef:c6:e1:8b:da:a4:c2:78:7a:61:19:d7:83:
- 5f:81:34:37:3e:1a:e2:b4:56:64:eb:db:af:7c:83:
- c7:67:58:f1:69:c4:02:3a:05:1c:d9:56:5c:32:32:
- bd:a7:e9:5f:82:b3:bb:1e:a6:e8:9c:86:86:ee:de:
- 9b:19:d7:19:4f:89:cf:98:76:81:6d:dc:10:7d:d3:
- 92:b8:7b:0d:c8:2f:2d:fc:ee:d7:68:fb:d5:87:7e:
- 64:9a:32:73:57:58:5b:31:fc:da:d3:2c:2c:22:1d:
- d6:db:71:a6:58:0b:84:0d:28:de:82:ad:d1:4e:2c:
- 4b:b4:df:1d:78:34:59:52:a3:16:bd:0b:77:26:4d:
- 4b:6f
+ 00:dd:a5:d8:2e:59:ed:a6:74:62:3b:71:d5:2f:0c:
+ b5:e6:a8:d6:d3:d2:f3:38:d5:6a:14:e4:ec:7e:d0:
+ 46:81:35:0e:27:96:4e:25:0c:9f:81:85:18:03:d2:
+ 22:1b:14:cc:54:4b:96:0e:35:0c:4c:0f:20:69:3d:
+ ff:48:26:b4:28:6c:6a:1f:95:87:df:09:9e:ab:60:
+ 43:97:3c:3a:7b:4a:d3:c6:66:ba:1a:79:71:58:29:
+ cb:78:38:19:de:12:c6:09:fa:f9:fd:13:a0:e1:0e:
+ d5:e6:c2:36:d9:dc:c5:f4:ef:08:42:e8:bf:43:d1:
+ b5:8a:c9:81:b1:9c:16:8f:8d:b2:aa:9e:61:30:ed:
+ fc:12:f0:a6:f5:9e:6a:1e:6e:d7:7c:3f:ff:76:fa:
+ 6f:53:8b:49:08:84:9a:69:37:bc:f5:ee:e7:ba:ee:
+ 39:5b:31:28:05:5a:39:d3:75:5a:1a:b2:5a:ef:48:
+ d4:f5:5c:ab:99:b0:41:cd:50:cd:f4:36:c3:4d:e9:
+ 42:2c:9d:2c:86:ea:a8:e4:d0:c9:1f:d0:c3:92:1b:
+ ef:c0:2c:a2:ed:2a:23:2f:ba:c0:27:a5:13:98:1d:
+ d3:ba:71:91:29:ae:2c:85:44:ff:bd:b5:c2:bc:e3:
+ fc:ff:c1:78:51:57:e9:5e:ee:1e:c2:29:d1:8c:91:
+ 60:9d
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- E9:AC:73:09:B6:86:CD:95:42:29:5D:E5:EC:C7:99:29:12:91:8C:53
+ 39:BF:53:7E:B4:7B:97:5D:7A:E5:12:6D:FA:8B:79:C5:67:3E:1E:E4
X509v3 Authority Key Identifier:
- keyid:E9:AC:73:09:B6:86:CD:95:42:29:5D:E5:EC:C7:99:29:12:91:8C:53
+ keyid:39:BF:53:7E:B4:7B:97:5D:7A:E5:12:6D:FA:8B:79:C5:67:3E:1E:E4
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -206,47 +206,49 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 76:62:2d:4c:94:4e:63:cb:7f:35:52:08:e2:8a:f3:d1:03:55:
- 31:f4:e8:e0:79:68:23:f0:19:d5:7f:b2:dd:27:0a:a2:bb:6c:
- f3:85:ae:48:83:3c:37:7e:62:69:e9:af:e0:4d:60:f0:8b:bf:
- 1b:2c:da:90:10:fc:8c:83:b1:55:46:a6:fe:d1:d1:21:6f:91:
- e1:cc:d6:c6:8c:1e:b1:03:e5:d7:5b:5f:3c:a7:2d:16:a1:71:
- 54:e1:8a:4b:62:61:18:42:b1:f4:ec:6e:33:5a:3b:52:2a:8e:
- 1a:60:75:73:89:78:72:86:9f:42:82:e5:d7:0e:5c:ce:36:a7:
- 2d:8e:78:0a:e9:95:2d:72:d2:42:6f:b6:7c:7e:28:29:2d:85:
- 3c:46:ab:6f:04:a8:f4:a2:ec:c4:24:7e:7a:a9:96:ec:b3:49:
- 8b:ec:2a:00:88:c0:a6:50:01:a5:f0:df:ef:1c:6c:f8:bf:8e:
- 64:ab:ff:43:bf:05:ce:82:b6:d4:cc:30:47:d8:74:7f:4e:4c:
- dc:cc:a6:92:e3:96:37:97:b1:03:27:93:38:62:4d:b7:ae:fe:
- a2:2b:61:05:32:27:28:27:c3:1f:e9:50:91:0a:4a:4b:ca:a3:
- b0:8e:d4:56:30:ad:e8:76:49:e4:0e:36:83:15:22:8a:bc:59:
- 27:1c:62:f3
------BEGIN TRUSTED_CERTIFICATE-----
+ 0d:d6:63:36:cb:eb:0f:98:6d:d8:0a:17:d2:6e:77:43:17:e8:
+ e6:36:c6:2a:40:2c:1e:64:f3:84:13:31:b9:fd:b7:6f:1d:b0:
+ d3:49:55:4b:76:ac:9d:6b:9c:3e:2b:fd:c6:d2:0c:df:9b:ef:
+ 4a:cf:2b:9c:61:5e:6b:2a:7d:b4:08:8e:a7:2a:aa:a9:a5:0d:
+ 8e:e1:0a:99:fc:f7:fa:f2:34:50:6a:aa:3b:30:ac:7c:93:b1:
+ dc:56:9e:2c:98:12:05:26:51:ff:c5:bf:06:44:24:7e:98:21:
+ aa:32:5e:f6:25:74:6d:31:f4:6b:f6:b0:70:30:87:04:b6:89:
+ 3d:a0:0f:cc:a6:d4:bd:93:df:98:bc:a9:92:ca:3f:ff:ef:29:
+ 4b:f1:3a:6a:c8:69:89:a6:93:01:54:49:af:20:4f:4d:4d:df:
+ 8a:4e:4a:ba:4b:a8:5e:85:46:96:a2:64:6f:78:f9:d7:6b:e5:
+ db:fb:39:42:3a:18:c7:08:ce:93:41:e3:3c:78:01:64:36:8b:
+ de:78:9e:13:42:52:72:13:f6:81:df:5e:7a:45:08:4f:0d:99:
+ f8:af:1e:71:d6:55:85:3a:2c:79:17:e3:df:8e:46:8d:39:13:
+ a4:c9:e7:3d:f2:9d:ef:e7:b9:12:6e:e3:76:3f:e7:c6:5c:fe:
+ 1e:af:1b:50
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALg8r4htXpZ+WJAJXUBU
-EU9V/7vnlBu619+5R8P/hHEi2qiJ5phxS67YwRnfT2m/wj3aCqhlCKjDLKo0x6K5
-AEVvLmlukO6bovYgDXUXwjPgWSx91j0jNA7m4El0OyEEn2slkhouD+VKCpaFDWnc
-qzEjGbfQVOYYxqHvxuGL2qTCeHphGdeDX4E0Nz4a4rRWZOvbr3yDx2dY8WnEAjoF
-HNlWXDIyvafpX4Kzux6m6JyGhu7emxnXGU+Jz5h2gW3cEH3Tkrh7DcgvLfzu12j7
-1Yd+ZJoyc1dYWzH82tMsLCId1ttxplgLhA0o3oKt0U4sS7TfHXg0WVKjFr0LdyZN
-S28CAwEAAaOByzCByDAdBgNVHQ4EFgQU6axzCbaGzZVCKV3l7MeZKRKRjFMwHwYD
-VR0jBBgwFoAU6axzCbaGzZVCKV3l7MeZKRKRjFMwNwYIKwYBBQUHAQEEKzApMCcG
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2l2C5Z7aZ0Yjtx1S8M
+teao1tPS8zjVahTk7H7QRoE1DieWTiUMn4GFGAPSIhsUzFRLlg41DEwPIGk9/0gm
+tChsah+Vh98JnqtgQ5c8OntK08Zmuhp5cVgpy3g4Gd4Sxgn6+f0ToOEO1ebCNtnc
+xfTvCELov0PRtYrJgbGcFo+NsqqeYTDt/BLwpvWeah5u13w//3b6b1OLSQiEmmk3
+vPXu57ruOVsxKAVaOdN1WhqyWu9I1PVcq5mwQc1QzfQ2w03pQiydLIbqqOTQyR/Q
+w5Ib78Asou0qIy+6wCelE5gd07pxkSmuLIVE/721wrzj/P/BeFFX6V7uHsIp0YyR
+YJ0CAwEAAaOByzCByDAdBgNVHQ4EFgQUOb9TfrR7l1165RJt+ot5xWc+HuQwHwYD
+VR0jBBgwFoAUOb9TfrR7l1165RJt+ot5xWc+HuQwNwYIKwYBBQUHAQEEKzApMCcG
CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB2Yi1MlE5j
-y381UgjiivPRA1Ux9OjgeWgj8BnVf7LdJwqiu2zzha5Igzw3fmJp6a/gTWDwi78b
-LNqQEPyMg7FVRqb+0dEhb5HhzNbGjB6xA+XXW188py0WoXFU4YpLYmEYQrH07G4z
-WjtSKo4aYHVziXhyhp9CguXXDlzONqctjngK6ZUtctJCb7Z8figpLYU8RqtvBKj0
-ouzEJH56qZbss0mL7CoAiMCmUAGl8N/vHGz4v45kq/9DvwXOgrbUzDBH2HR/Tkzc
-zKaS45Y3l7EDJ5M4Yk23rv6iK2EFMicoJ8Mf6VCRCkpLyqOwjtRWMK3odknkDjaD
-FSKKvFknHGLz
------END TRUSTED_CERTIFICATE-----
-
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAN1mM2y+sP
+mG3YChfSbndDF+jmNsYqQCweZPOEEzG5/bdvHbDTSVVLdqyda5w+K/3G0gzfm+9K
+zyucYV5rKn20CI6nKqqppQ2O4QqZ/Pf68jRQaqo7MKx8k7HcVp4smBIFJlH/xb8G
+RCR+mCGqMl72JXRtMfRr9rBwMIcEtok9oA/MptS9k9+YvKmSyj//7ylL8TpqyGmJ
+ppMBVEmvIE9NTd+KTkq6S6hehUaWomRvePnXa+Xb+zlCOhjHCM6TQeM8eAFkNove
+eJ4TQlJyE/aB3156RQhPDZn4rx5x1lWFOix5F+PfjkaNOROkyec98p3v57kSbuN2
+P+fGXP4erxtQ
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
-----BEGIN TIME-----
MTUwMzAyMTIwMDAwWg==
-----END TIME-----
+SUCCESS
-----BEGIN VERIFY_RESULT-----
U1VDQ0VTUw==
-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/target-signed-with-md5.pem b/chromium/net/data/verify_certificate_chain_unittest/target-signed-with-md5.pem
index dd82071d7b0..ce40a4f08c9 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/target-signed-with-md5.pem
+++ b/chromium/net/data/verify_certificate_chain_unittest/target-signed-with-md5.pem
@@ -1,6 +1,6 @@
[Created by: generate-target-signed-with-md5.py]
-Certificate chain with an intermediary that uses MD5 to sign the target
+Certificate chain with an intermediate that uses MD5 to sign the target
certificate. This is expected to fail because MD5 is too weak.
Certificate:
@@ -8,7 +8,7 @@ Certificate:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: md5WithRSAEncryption
- Issuer: CN=Intermediary
+ Issuer: CN=Intermediate
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
@@ -17,80 +17,80 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:c5:55:ac:42:f6:5f:21:93:e6:93:07:6a:dc:a0:
- 4c:66:21:42:8c:2e:f4:d0:61:30:ac:bf:9a:3b:b3:
- 59:21:e4:29:9f:33:5d:5e:6f:a1:de:4d:c2:b3:22:
- f3:16:0a:81:f0:51:90:f8:45:e0:5e:9b:7d:3a:e4:
- 60:d2:a8:a1:b1:2f:13:8c:41:dc:c3:58:1d:66:6c:
- 67:13:5e:21:51:f7:49:21:5d:29:dd:91:fd:a7:36:
- 10:bb:d1:30:71:16:ee:4b:7f:1b:ba:02:c3:79:0c:
- 4d:e7:98:59:b1:0f:c8:61:a3:f9:5c:fa:03:08:29:
- 41:af:60:50:b8:80:3b:f6:fe:75:0f:bb:d4:92:d9:
- f5:3a:25:41:12:f1:cd:ad:2c:08:c9:f9:a3:17:78:
- 86:2a:18:13:b1:20:15:83:de:04:ac:2a:c6:42:5c:
- d1:f9:e6:12:1c:1b:51:7a:2c:cd:40:94:c8:76:17:
- d7:20:4a:f8:e4:c8:3c:57:7c:c8:c6:6d:bd:2a:5e:
- a9:03:7e:14:9d:a5:4e:1f:b1:aa:94:2f:64:34:6e:
- d1:cb:5f:41:84:f7:86:95:04:90:ce:77:27:f6:7d:
- 8e:5b:9c:52:7a:5e:dd:e2:f6:e6:fd:10:8d:e2:7d:
- 34:f0:54:1b:c2:54:45:fe:01:97:90:f7:33:03:db:
- 0c:bd
+ 00:bc:8a:b8:3e:5c:f9:f0:cc:33:10:6f:ab:ec:81:
+ 53:1c:4f:d3:c7:e2:c6:ac:57:9b:b0:a1:37:3d:2a:
+ b8:4f:eb:23:8b:64:6d:2f:5b:f5:02:dc:5b:d5:11:
+ ea:29:38:4c:76:40:f4:b0:b0:47:9f:6c:8d:89:91:
+ f4:0d:e5:cb:bb:c2:2a:cc:c1:9b:3a:56:f6:26:8e:
+ 4a:df:2c:b3:7c:35:3f:71:a9:37:49:3c:1a:40:fd:
+ 5e:6f:1b:5e:a0:61:64:d1:40:80:d7:dd:2b:d4:32:
+ 4c:80:f8:5a:8c:b2:ff:b6:ea:91:73:59:00:5e:02:
+ a8:49:1b:2b:fa:c2:9b:35:44:79:74:7b:02:8e:68:
+ 47:76:43:8d:23:d0:d0:f9:c4:8c:a1:aa:99:cb:55:
+ 24:a1:11:1c:88:0d:8a:5c:d9:46:a6:8f:ac:3f:83:
+ e3:4e:35:90:03:fe:0e:2d:d7:c6:9b:a3:36:d7:7f:
+ af:32:89:83:94:40:e7:87:1b:fe:f5:1b:1e:75:ba:
+ f2:b5:70:f3:75:f8:85:b3:58:9d:5f:56:6b:60:0f:
+ 53:12:82:dc:01:67:28:66:2c:3e:f6:df:08:fb:b9:
+ da:ce:00:60:b3:b4:65:fd:1d:1e:14:7c:90:9b:0b:
+ d4:ca:ff:96:12:c0:2c:cd:fb:c3:4f:62:d0:67:59:
+ bc:71
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- DF:16:6B:0E:36:1E:E4:F1:15:A2:3A:9E:07:4A:F9:6D:81:82:7A:D5
+ 2F:67:2E:92:9E:39:55:C4:47:23:6A:10:A9:37:87:97:74:0F:55:57
X509v3 Authority Key Identifier:
- keyid:E2:CD:39:61:AF:F5:B9:CE:D9:7C:36:97:5D:28:36:61:63:0B:CA:49
+ keyid:A7:A7:7E:EF:32:C8:D1:7C:DF:CA:EE:F4:4F:7A:EA:67:43:53:57:CF
Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
X509v3 CRL Distribution Points:
Full Name:
- URI:http://url-for-crl/Intermediary.crl
+ URI:http://url-for-crl/Intermediate.crl
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: md5WithRSAEncryption
- 35:9f:32:4a:5f:2e:b6:3f:d4:03:97:8f:0d:70:8b:5a:8d:62:
- 30:77:44:37:e0:85:5f:e8:fc:8a:f6:e2:cb:df:05:f3:08:2d:
- 05:dc:bb:16:1f:69:06:2e:4b:2b:1b:6f:a1:b3:77:02:1e:7d:
- 49:da:a0:d9:6a:ac:bd:5e:4d:65:10:51:ee:e6:2a:33:e5:b9:
- b5:5b:83:67:3d:c1:9d:c5:a6:c4:6e:7b:3b:ad:88:02:dc:ef:
- 98:c4:cf:1d:cc:ab:45:23:53:27:ee:7f:87:f4:e6:13:5a:3a:
- 3d:30:1e:66:b7:6e:67:e7:ae:1b:c6:4e:26:14:0f:cf:71:8a:
- 0c:ee:60:14:25:45:a1:4b:2f:46:73:41:11:59:9f:e7:9f:12:
- 01:7e:dc:e4:68:96:31:a5:c0:cc:03:fc:e3:b0:c5:c2:65:57:
- ef:48:a4:85:eb:6e:d9:95:2f:d8:b1:48:46:b1:d5:30:84:d6:
- c0:aa:32:41:a2:8a:be:35:b4:97:e5:1d:f7:36:f4:47:36:68:
- f9:6b:10:39:1f:13:e8:b3:f5:7c:57:71:df:a8:e8:40:28:ed:
- 65:3a:ba:7a:98:fa:4d:14:e9:5e:f5:a3:92:03:aa:d5:0b:72:
- 29:7e:30:80:03:40:b9:eb:72:e2:ac:43:3a:2c:f6:c9:a3:13:
- c7:c9:05:b9
+ 30:9f:40:ac:31:10:78:0f:06:4b:ed:6d:de:05:20:c6:29:64:
+ 66:a8:2a:4d:ac:b3:3d:40:d5:70:80:24:08:13:00:73:0b:90:
+ 32:c3:fe:35:b3:8c:77:bb:d6:79:a9:84:e3:76:89:d9:0f:19:
+ 2e:68:6a:ec:09:ef:9c:57:32:ee:9f:e5:0e:5e:4c:6b:87:eb:
+ e0:7b:e9:ed:b0:db:ef:34:7a:41:aa:7b:0d:b7:37:89:17:99:
+ b8:43:db:93:19:30:91:7c:25:fe:1d:cd:69:02:b8:6d:c6:08:
+ fa:7f:d8:3c:e5:9a:9d:fd:af:13:53:5a:54:a7:5d:d1:e3:46:
+ 3a:c9:8b:ac:e3:cb:e8:67:a8:e0:cf:bb:ab:45:5c:d6:d5:51:
+ d2:2a:d2:b2:f8:3f:05:d2:20:e8:95:17:7d:43:fe:af:cd:1c:
+ fa:d2:8f:8f:3b:b1:2b:3d:22:06:d8:c7:0d:00:64:8a:35:40:
+ 32:6e:2c:07:be:5f:e7:9d:06:4f:b1:99:a9:fb:2e:03:80:79:
+ 5e:19:60:a9:7f:e5:12:bb:ba:a8:f2:34:d7:00:29:11:ab:8d:
+ 51:52:67:33:99:5c:08:de:85:a6:ea:42:9d:08:76:d1:f1:23:
+ fa:c0:4c:ff:38:5a:de:1b:7a:16:e7:79:cf:a0:d0:2f:b7:e5:
+ d4:8e:92:4f
-----BEGIN CERTIFICATE-----
MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQQFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFVaxC
-9l8hk+aTB2rcoExmIUKMLvTQYTCsv5o7s1kh5CmfM11eb6HeTcKzIvMWCoHwUZD4
-ReBem3065GDSqKGxLxOMQdzDWB1mbGcTXiFR90khXSndkf2nNhC70TBxFu5Lfxu6
-AsN5DE3nmFmxD8hho/lc+gMIKUGvYFC4gDv2/nUPu9SS2fU6JUES8c2tLAjJ+aMX
-eIYqGBOxIBWD3gSsKsZCXNH55hIcG1F6LM1AlMh2F9cgSvjkyDxXfMjGbb0qXqkD
-fhSdpU4fsaqUL2Q0btHLX0GE94aVBJDOdyf2fY5bnFJ6Xt3i9ub9EI3ifTTwVBvC
-VEX+AZeQ9zMD2wy9AgMBAAGjgekwgeYwHQYDVR0OBBYEFN8Waw42HuTxFaI6ngdK
-+W2BgnrVMB8GA1UdIwQYMBaAFOLNOWGv9bnO2Xw2l10oNmFjC8pJMD8GCCsGAQUF
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8irg+
+XPnwzDMQb6vsgVMcT9PH4sasV5uwoTc9KrhP6yOLZG0vW/UC3FvVEeopOEx2QPSw
+sEefbI2JkfQN5cu7wirMwZs6VvYmjkrfLLN8NT9xqTdJPBpA/V5vG16gYWTRQIDX
+3SvUMkyA+FqMsv+26pFzWQBeAqhJGyv6wps1RHl0ewKOaEd2Q40j0ND5xIyhqpnL
+VSShERyIDYpc2Uamj6w/g+NONZAD/g4t18abozbXf68yiYOUQOeHG/71Gx51uvK1
+cPN1+IWzWJ1fVmtgD1MSgtwBZyhmLD723wj7udrOAGCztGX9HR4UfJCbC9TK/5YS
+wCzN+8NPYtBnWbxxAgMBAAGjgekwgeYwHQYDVR0OBBYEFC9nLpKeOVXERyNqEKk3
+h5d0D1VXMB8GA1UdIwQYMBaAFKenfu8yyNF838ru9E966mdDU1fPMD8GCCsGAQUF
BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQQFAAOCAQEANZ8ySl8utj/UA5ePDXCL
-Wo1iMHdEN+CFX+j8ivbiy98F8wgtBdy7Fh9pBi5LKxtvobN3Ah59Sdqg2WqsvV5N
-ZRBR7uYqM+W5tVuDZz3BncWmxG57O62IAtzvmMTPHcyrRSNTJ+5/h/TmE1o6PTAe
-ZrduZ+euG8ZOJhQPz3GKDO5gFCVFoUsvRnNBEVmf558SAX7c5GiWMaXAzAP847DF
-wmVX70ikhetu2ZUv2LFIRrHVMITWwKoyQaKKvjW0l+Ud9zb0RzZo+WsQOR8T6LP1
-fFdx36joQCjtZTq6epj6TRTpXvWjkgOq1QtyKX4wgANAuety4qxDOiz2yaMTx8kF
-uQ==
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQQFAAOCAQEAMJ9ArDEQeA8GS+1t3gUg
+xilkZqgqTayzPUDVcIAkCBMAcwuQMsP+NbOMd7vWeamE43aJ2Q8ZLmhq7AnvnFcy
+7p/lDl5Ma4fr4Hvp7bDb7zR6Qap7Dbc3iReZuEPbkxkwkXwl/h3NaQK4bcYI+n/Y
+POWanf2vE1NaVKdd0eNGOsmLrOPL6Geo4M+7q0Vc1tVR0irSsvg/BdIg6JUXfUP+
+r80c+tKPjzuxKz0iBtjHDQBkijVAMm4sB75f550GT7GZqfsuA4B5XhlgqX/lEru6
+qPI01wApEauNUVJnM5lcCN6FpupCnQh20fEj+sBM/zha3ht6Fud5z6DQL7fl1I6S
+Tw==
-----END CERTIFICATE-----
Certificate:
@@ -102,35 +102,35 @@ Certificate:
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
+ Subject: CN=Intermediate
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:b0:67:b9:ee:01:e6:50:d2:01:11:81:3a:70:41:
- c3:36:af:95:28:11:ed:90:02:37:9a:f9:fe:23:38:
- d6:72:c5:38:da:62:a4:84:dc:50:12:0e:03:e2:34:
- 4d:d8:88:b7:aa:09:31:14:71:b5:e5:f9:80:06:c5:
- 72:8a:1a:dd:72:a8:c9:76:79:3b:14:34:0a:bc:7a:
- d4:a6:75:58:c0:f1:77:d7:23:bb:5b:a1:54:d2:cf:
- ec:0f:b7:ab:53:01:7d:1d:54:40:68:12:fb:75:68:
- 56:d5:0d:5c:00:de:81:5f:a5:14:fd:5d:77:b8:1f:
- 3e:ee:84:99:a5:b5:0d:13:9a:fe:cf:b8:b0:e1:4c:
- db:87:64:e1:36:a0:04:02:5d:fd:58:9e:e5:70:85:
- 63:65:50:93:b8:3e:6c:85:10:67:bc:3d:e2:77:38:
- b2:75:b5:e3:57:55:b2:44:68:3c:ab:65:2b:cb:8b:
- 11:29:d5:7c:b8:24:88:25:d1:80:0b:04:3f:0e:e9:
- 1d:79:db:39:7d:ab:81:67:fb:cf:ae:a3:da:ea:f1:
- 12:ac:cd:87:96:5c:ed:fd:db:bc:e2:3a:4e:33:05:
- af:1a:d3:03:85:ec:74:23:04:12:7e:62:a1:56:4c:
- 45:9c:95:80:55:b6:2f:13:82:27:24:c4:a0:68:33:
- e6:71
+ 00:b1:0a:34:0b:b1:d9:65:b5:ea:7a:ac:f5:96:11:
+ 68:ba:f0:c9:6b:57:c7:97:7e:f4:bb:5d:31:4e:43:
+ 9b:04:7f:a7:2e:fd:4c:e0:03:c7:0d:ac:70:24:0e:
+ bc:26:a2:5d:48:71:04:9b:43:8c:97:e4:2c:df:7c:
+ 59:39:eb:a3:94:b3:5b:87:d5:11:b6:c1:4a:e9:7b:
+ e8:f8:c5:31:3b:2c:4d:f0:47:34:75:a8:88:6d:22:
+ a9:24:dc:00:1f:a0:36:1e:e3:a7:92:b1:00:9d:f8:
+ ef:27:46:63:60:23:67:48:e6:5d:66:b3:3d:b6:84:
+ 04:3f:b1:1b:2f:b7:8e:71:26:28:32:ff:de:fa:b0:
+ cb:e2:90:5a:72:9a:83:1d:de:c7:ad:b1:5d:68:11:
+ 9e:6a:ac:44:6b:06:cc:93:6c:a9:13:af:a4:72:e2:
+ 34:4d:c4:d7:8f:ee:99:f4:e4:db:d1:19:45:bf:97:
+ 76:59:7d:b9:32:63:07:a0:1c:e3:19:98:f6:aa:d8:
+ ba:44:f6:ec:5f:eb:46:d1:63:70:56:00:a1:f1:ce:
+ 18:c3:a5:77:27:81:e6:18:65:78:9a:c4:87:f9:36:
+ 2e:b6:fc:5c:75:a9:a9:59:6a:df:99:26:07:c9:1d:
+ 1a:a8:4f:6e:b6:10:92:4f:96:c1:74:30:4a:5c:8b:
+ bd:7b
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- E2:CD:39:61:AF:F5:B9:CE:D9:7C:36:97:5D:28:36:61:63:0B:CA:49
+ A7:A7:7E:EF:32:C8:D1:7C:DF:CA:EE:F4:4F:7A:EA:67:43:53:57:CF
X509v3 Authority Key Identifier:
- keyid:BD:2A:00:54:BB:89:72:89:4F:27:75:12:AA:89:38:AB:A0:06:F7:D1
+ keyid:7F:7A:CD:B2:58:B8:B5:62:1A:C2:DE:B4:6B:B5:74:E9:B8:DC:77:87
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -145,41 +145,41 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 3d:9a:bd:e5:a7:4d:e4:0e:ea:6a:34:da:9e:48:c7:8a:e4:34:
- 6c:19:fe:d0:2f:2f:7b:01:14:46:3a:45:d7:a7:46:6e:83:bb:
- 54:cc:4e:af:cf:ef:fc:6d:90:e4:54:38:94:2d:cb:55:85:bd:
- 1d:9f:9e:cd:ac:68:b3:7f:ed:bb:1f:30:30:14:15:ba:17:e4:
- 62:db:6b:70:5a:1f:c2:e7:43:c6:30:d0:0f:be:78:06:4e:09:
- 0b:00:96:63:d2:14:84:93:88:5d:e6:bf:93:1c:e9:18:9d:df:
- 7d:db:34:39:e5:94:f8:c9:84:b6:ff:a0:e7:5c:51:5e:ba:40:
- 82:5a:7e:64:ca:bf:e3:0e:c8:76:0b:5c:be:29:b1:62:79:18:
- b2:d6:c3:ee:d0:05:61:96:be:a8:dc:c5:65:72:cc:f7:f8:6e:
- 27:85:c3:9b:68:6d:3d:a5:e5:34:20:ff:19:12:62:7c:5d:b8:
- 95:8f:a8:a8:a8:90:41:e0:83:f1:e3:3f:67:26:bc:b1:6c:76:
- b1:5e:25:60:49:7d:78:bf:bb:11:22:43:ac:d3:5f:c0:c9:73:
- 76:d5:9c:97:b0:ec:17:36:0d:4b:83:3e:77:d0:84:62:76:98:
- af:6d:42:ac:cb:40:bb:04:1d:9e:0a:a3:97:11:f2:b0:3f:6b:
- b6:fd:ff:da
+ 96:e8:cf:14:ab:83:41:2e:62:24:7e:03:ad:0e:ae:8e:6a:93:
+ ed:3d:86:68:84:b5:76:2b:88:c3:67:b6:15:b6:38:b2:27:f3:
+ 2a:1b:83:42:60:11:ee:94:ba:d8:d8:35:74:92:c1:5f:b4:b3:
+ f0:fc:5e:eb:51:93:be:00:11:79:db:94:86:0f:19:26:bb:f6:
+ b1:ec:93:66:34:df:3e:7e:6e:80:17:3e:4a:9b:53:04:05:22:
+ 88:de:65:e3:50:c1:81:fa:1d:fc:76:09:f6:25:89:9d:4f:d3:
+ ff:76:b0:3e:81:d3:79:8f:05:48:68:36:93:43:ac:b8:41:37:
+ 98:54:bc:71:90:ed:12:c0:1f:f7:b4:a7:7b:56:34:e3:97:01:
+ 41:56:9a:c6:37:3f:8e:34:9b:51:37:77:4f:67:d6:72:66:d1:
+ 89:64:10:80:5f:13:15:34:03:a9:c5:6e:07:6c:77:78:99:27:
+ f4:e0:44:0e:5f:a0:67:dd:f7:4d:4a:93:b3:71:d2:8e:1b:d6:
+ 29:5a:8f:f1:f7:c8:9c:33:ae:28:15:7b:10:ee:92:bd:d5:3c:
+ b3:81:5a:52:5d:96:43:ae:bd:03:83:36:e8:c5:f8:23:03:26:
+ eb:2f:70:4a:bb:d8:e1:6a:a0:7d:23:b1:4f:32:28:65:23:84:
+ 02:95:8e:2d
-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsGe57gHm
-UNIBEYE6cEHDNq+VKBHtkAI3mvn+IzjWcsU42mKkhNxQEg4D4jRN2Ii3qgkxFHG1
-5fmABsVyihrdcqjJdnk7FDQKvHrUpnVYwPF31yO7W6FU0s/sD7erUwF9HVRAaBL7
-dWhW1Q1cAN6BX6UU/V13uB8+7oSZpbUNE5r+z7iw4Uzbh2ThNqAEAl39WJ7lcIVj
-ZVCTuD5shRBnvD3idziydbXjV1WyRGg8q2Ury4sRKdV8uCSIJdGACwQ/Dukdeds5
-fauBZ/vPrqPa6vESrM2Hllzt/du84jpOMwWvGtMDhex0IwQSfmKhVkxFnJWAVbYv
-E4InJMSgaDPmcQIDAQABo4HLMIHIMB0GA1UdDgQWBBTizTlhr/W5ztl8NpddKDZh
-YwvKSTAfBgNVHSMEGDAWgBS9KgBUu4lyiU8ndRKqiTiroAb30TA3BggrBgEFBQcB
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsQo0C7HZ
+ZbXqeqz1lhFouvDJa1fHl370u10xTkObBH+nLv1M4APHDaxwJA68JqJdSHEEm0OM
+l+Qs33xZOeujlLNbh9URtsFK6Xvo+MUxOyxN8Ec0daiIbSKpJNwAH6A2HuOnkrEA
+nfjvJ0ZjYCNnSOZdZrM9toQEP7EbL7eOcSYoMv/e+rDL4pBacpqDHd7HrbFdaBGe
+aqxEawbMk2ypE6+kcuI0TcTXj+6Z9OTb0RlFv5d2WX25MmMHoBzjGZj2qti6RPbs
+X+tG0WNwVgCh8c4Yw6V3J4HmGGV4msSH+TYutvxcdampWWrfmSYHyR0aqE9uthCS
+T5bBdDBKXIu9ewIDAQABo4HLMIHIMB0GA1UdDgQWBBSnp37vMsjRfN/K7vRPeupn
+Q1NXzzAfBgNVHSMEGDAWgBR/es2yWLi1YhrC3rRrtXTpuNx3hzA3BggrBgEFBQcB
AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
-AD2aveWnTeQO6mo02p5Ix4rkNGwZ/tAvL3sBFEY6RdenRm6Du1TMTq/P7/xtkORU
-OJQty1WFvR2fns2saLN/7bsfMDAUFboX5GLba3BaH8LnQ8Yw0A++eAZOCQsAlmPS
-FISTiF3mv5Mc6Rid333bNDnllPjJhLb/oOdcUV66QIJafmTKv+MOyHYLXL4psWJ5
-GLLWw+7QBWGWvqjcxWVyzPf4bieFw5tobT2l5TQg/xkSYnxduJWPqKiokEHgg/Hj
-P2cmvLFsdrFeJWBJfXi/uxEiQ6zTX8DJc3bVnJew7Bc2DUuDPnfQhGJ2mK9tQqzL
-QLsEHZ4Ko5cR8rA/a7b9/9o=
+AJbozxSrg0EuYiR+A60Oro5qk+09hmiEtXYriMNnthW2OLIn8yobg0JgEe6UutjY
+NXSSwV+0s/D8XutRk74AEXnblIYPGSa79rHsk2Y03z5+boAXPkqbUwQFIojeZeNQ
+wYH6Hfx2CfYliZ1P0/92sD6B03mPBUhoNpNDrLhBN5hUvHGQ7RLAH/e0p3tWNOOX
+AUFWmsY3P440m1E3d09n1nJm0YlkEIBfExU0A6nFbgdsd3iZJ/TgRA5foGfd901K
+k7Nx0o4b1ilaj/H3yJwzrigVexDukr3VPLOBWlJdlkOuvQODNujF+CMDJusvcEq7
+2OFqoH0jsU8yKGUjhAKVji0=
-----END CERTIFICATE-----
Certificate:
@@ -196,30 +196,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:a0:9b:ff:8c:74:7b:c9:1e:3c:34:5b:7c:c0:35:
- a4:88:6a:26:ed:0b:52:e9:58:e6:b5:bd:fd:f6:ae:
- 0f:08:09:24:ef:62:fb:1c:61:7f:8a:ca:5f:d4:b5:
- 2b:45:c2:21:1f:1a:a1:ef:f9:d8:0d:be:31:88:bd:
- d7:35:8e:0d:de:e8:be:60:63:f6:3c:6a:cd:e7:1d:
- 78:36:86:91:a1:e9:5c:2d:c6:9a:95:b9:e7:c3:66:
- 6f:b5:0c:4b:aa:9a:51:ea:b3:a3:9e:57:d6:17:c9:
- ae:4c:3f:32:ef:28:5a:99:6a:dc:50:54:f5:cc:80:
- 51:76:6c:50:4d:52:01:45:92:af:a2:ca:a7:c1:9e:
- 76:24:29:9c:d1:73:95:0a:a1:16:73:0f:56:9d:e8:
- fe:c2:bb:e4:64:99:a3:d4:46:7d:7a:f7:25:d3:49:
- c0:da:38:18:78:9c:2a:40:60:c2:b8:98:8a:84:ed:
- d2:84:e0:39:a6:31:64:36:2a:59:ca:ba:dc:c2:6d:
- a2:ac:1a:93:58:27:76:95:ea:5d:12:8d:7a:a5:b6:
- 50:3b:1c:25:3f:75:ee:eb:db:12:78:67:47:0d:86:
- 49:77:ce:f5:d0:37:03:55:eb:98:93:bf:f1:10:5b:
- 87:aa:a1:ef:76:30:e1:e4:77:54:b1:52:e8:c9:81:
- 4d:5b
+ 00:a7:f5:bd:ee:ad:ff:30:37:e6:5a:68:20:1a:22:
+ b1:f5:bb:5e:24:38:bd:b7:c1:34:d4:97:8b:16:97:
+ 34:17:bc:61:df:ff:ff:6b:9c:b6:34:79:7d:5a:e7:
+ 3b:cf:07:73:b8:2d:03:59:56:68:4a:85:25:58:f4:
+ 68:01:61:84:52:99:2f:6a:7e:cb:13:61:8b:6e:3b:
+ f5:8e:c2:48:cc:1e:50:28:4f:5f:4b:6b:32:d3:f3:
+ 76:c9:6f:a3:aa:40:1b:06:59:19:cd:42:70:f4:85:
+ fe:86:38:ca:84:42:5f:bb:d3:a7:41:42:46:59:14:
+ 3f:11:1d:62:d9:e1:16:3f:06:a7:59:f3:ff:ba:f1:
+ 88:7b:0c:68:10:49:ac:8d:75:87:08:94:f6:ec:ce:
+ 4c:6d:e6:77:85:25:c8:8f:42:0a:1d:d3:00:cc:89:
+ 31:dc:32:07:d7:2e:62:16:73:8b:5d:c4:c9:1b:87:
+ 7c:46:64:2d:cc:e0:fb:69:d2:e1:bd:23:2b:d9:15:
+ 62:22:a4:cd:75:64:f1:78:76:cc:07:11:59:08:60:
+ 03:dd:cb:67:3e:a7:b8:12:fa:96:54:6f:6d:9f:05:
+ 11:89:71:13:50:94:bb:bb:17:7e:80:ed:40:b1:ba:
+ f2:36:2d:45:bb:73:78:5e:b7:5e:2f:e7:f8:66:ec:
+ 1f:17
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- BD:2A:00:54:BB:89:72:89:4F:27:75:12:AA:89:38:AB:A0:06:F7:D1
+ 7F:7A:CD:B2:58:B8:B5:62:1A:C2:DE:B4:6B:B5:74:E9:B8:DC:77:87
X509v3 Authority Key Identifier:
- keyid:BD:2A:00:54:BB:89:72:89:4F:27:75:12:AA:89:38:AB:A0:06:F7:D1
+ keyid:7F:7A:CD:B2:58:B8:B5:62:1A:C2:DE:B4:6B:B5:74:E9:B8:DC:77:87
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -234,47 +234,58 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 43:7c:24:ea:dc:11:3a:08:d7:6e:dd:8c:b9:21:1a:d7:88:d8:
- f1:4c:90:a0:b7:67:a7:3c:d2:8d:a4:68:50:34:db:a4:f1:69:
- d4:e0:8b:4c:b3:39:62:11:b5:4a:df:3a:60:87:eb:f6:79:2c:
- ef:4d:67:91:93:5f:b3:d1:63:1b:2e:12:74:4e:e2:60:d8:c1:
- 1f:e8:b2:5d:d4:56:2d:85:27:64:36:b0:e4:17:5e:d1:9c:ce:
- 56:e2:f4:68:d3:80:6f:44:d6:e4:7b:5b:c6:5e:3e:ea:69:9d:
- 97:4b:0d:83:3b:a7:52:f5:78:96:9f:af:15:e2:bf:59:a7:5f:
- 5b:d4:21:d1:49:b2:f4:b5:26:b1:b1:cf:74:d0:ba:26:b1:2e:
- 0e:ef:74:29:ed:f5:35:18:2f:cc:8b:80:39:41:8f:ea:ab:81:
- 6a:89:71:b8:22:e6:bc:e5:33:34:f7:dd:6c:37:0a:e1:21:a7:
- 7f:2d:29:f6:aa:02:d8:47:3f:a6:3d:0e:85:20:59:f8:5f:49:
- 06:f7:3a:9a:b8:d9:3a:08:ce:9a:60:aa:dd:72:07:1e:bb:8f:
- 86:fd:6a:3e:dc:4a:3f:5e:c2:b7:e6:0e:89:75:08:89:e3:bf:
- 2b:6c:cc:02:63:e0:1c:04:21:79:64:c0:7c:89:73:2b:e9:85:
- 49:80:5e:f4
------BEGIN TRUSTED_CERTIFICATE-----
+ a6:5d:56:c1:c7:29:8f:3a:1d:86:2c:5f:1e:ff:83:7a:c0:44:
+ 81:81:f7:16:9d:84:70:66:f8:1a:f4:8e:50:a7:dd:d2:1a:2e:
+ f9:6e:cc:e6:39:7c:fb:7e:29:54:24:3d:4a:82:e1:a5:d6:7e:
+ 4c:c8:58:b8:d6:f7:d2:90:ca:d9:8f:e9:c8:59:bc:73:1c:37:
+ 19:7c:a4:2b:ec:68:de:e9:04:fa:14:f0:07:bd:2f:3f:16:a4:
+ 50:8f:e8:89:ea:c1:31:d1:ce:6e:b1:21:11:5b:69:dc:28:e7:
+ 8a:33:8d:40:52:f8:86:8e:b0:a1:7a:a5:46:f2:8d:d7:d1:2e:
+ c8:2f:0f:ac:20:38:25:d6:4e:b2:72:fc:88:f3:47:93:bc:ec:
+ 47:0c:1c:cf:22:65:40:04:70:15:fa:79:ec:09:a2:69:a9:09:
+ 78:f7:3e:84:f3:7f:fa:a2:11:ad:45:72:5d:9d:55:58:fa:b1:
+ c6:67:4e:41:b4:bd:88:a0:e2:55:ae:26:3a:72:78:3d:e4:ab:
+ ad:f7:83:69:24:cd:22:4f:2e:23:a1:05:19:bd:57:d3:e8:b3:
+ 3d:9f:bd:ed:0b:95:bf:e5:47:8f:da:dd:9d:6b:27:61:bd:49:
+ 15:9c:9d:6b:40:2b:54:5f:3f:56:d5:08:29:6c:46:49:2d:3f:
+ d1:91:ff:f8
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKCb/4x0e8kePDRbfMA1
-pIhqJu0LUulY5rW9/fauDwgJJO9i+xxhf4rKX9S1K0XCIR8aoe/52A2+MYi91zWO
-Dd7ovmBj9jxqzecdeDaGkaHpXC3GmpW558Nmb7UMS6qaUeqzo55X1hfJrkw/Mu8o
-Wplq3FBU9cyAUXZsUE1SAUWSr6LKp8GediQpnNFzlQqhFnMPVp3o/sK75GSZo9RG
-fXr3JdNJwNo4GHicKkBgwriYioTt0oTgOaYxZDYqWcq63MJtoqwak1gndpXqXRKN
-eqW2UDscJT917uvbEnhnRw2GSXfO9dA3A1XrmJO/8RBbh6qh73Yw4eR3VLFS6MmB
-TVsCAwEAAaOByzCByDAdBgNVHQ4EFgQUvSoAVLuJcolPJ3USqok4q6AG99EwHwYD
-VR0jBBgwFoAUvSoAVLuJcolPJ3USqok4q6AG99EwNwYIKwYBBQUHAQEEKzApMCcG
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKf1ve6t/zA35lpoIBoi
+sfW7XiQ4vbfBNNSXixaXNBe8Yd///2uctjR5fVrnO88Hc7gtA1lWaEqFJVj0aAFh
+hFKZL2p+yxNhi2479Y7CSMweUChPX0trMtPzdslvo6pAGwZZGc1CcPSF/oY4yoRC
+X7vTp0FCRlkUPxEdYtnhFj8Gp1nz/7rxiHsMaBBJrI11hwiU9uzOTG3md4UlyI9C
+Ch3TAMyJMdwyB9cuYhZzi13EyRuHfEZkLczg+2nS4b0jK9kVYiKkzXVk8Xh2zAcR
+WQhgA93LZz6nuBL6llRvbZ8FEYlxE1CUu7sXfoDtQLG68jYtRbtzeF63Xi/n+Gbs
+HxcCAwEAAaOByzCByDAdBgNVHQ4EFgQUf3rNsli4tWIawt60a7V06bjcd4cwHwYD
+VR0jBBgwFoAUf3rNsli4tWIawt60a7V06bjcd4cwNwYIKwYBBQUHAQEEKzApMCcG
CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBDfCTq3BE6
-CNdu3Yy5IRrXiNjxTJCgt2enPNKNpGhQNNuk8WnU4ItMszliEbVK3zpgh+v2eSzv
-TWeRk1+z0WMbLhJ0TuJg2MEf6LJd1FYthSdkNrDkF17RnM5W4vRo04BvRNbke1vG
-Xj7qaZ2XSw2DO6dS9XiWn68V4r9Zp19b1CHRSbL0tSaxsc900LomsS4O73Qp7fU1
-GC/Mi4A5QY/qq4FqiXG4Iua85TM0991sNwrhIad/LSn2qgLYRz+mPQ6FIFn4X0kG
-9zqauNk6CM6aYKrdcgceu4+G/Wo+3Eo/XsK35g6JdQiJ478rbMwCY+AcBCF5ZMB8
-iXMr6YVJgF70
------END TRUSTED_CERTIFICATE-----
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCmXVbBxymP
+Oh2GLF8e/4N6wESBgfcWnYRwZvga9I5Qp93SGi75bszmOXz7filUJD1KguGl1n5M
+yFi41vfSkMrZj+nIWbxzHDcZfKQr7Gje6QT6FPAHvS8/FqRQj+iJ6sEx0c5usSER
+W2ncKOeKM41AUviGjrCheqVG8o3X0S7ILw+sIDgl1k6ycvyI80eTvOxHDBzPImVA
+BHAV+nnsCaJpqQl49z6E83/6ohGtRXJdnVVY+rHGZ05BtL2IoOJVriY6cng95Kut
+94NpJM0iTy4joQUZvVfT6LM9n73tC5W/5UeP2t2daydhvUkVnJ1rQCtUXz9W1Qgp
+bEZJLT/Rkf/4
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+150302120000Z
-----BEGIN TIME-----
MTUwMzAyMTIwMDAwWg==
-----END TIME-----
+FAIL
-----BEGIN VERIFY_RESULT-----
RkFJTA==
-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 1
+ [Error] Invalid or unsupported signature algorithm
+ algorithm: 300D06092A864886F70D0101040500
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMQogICAgICBbRXJyb3JdIEludmFsaWQgb3IgdW5zdXBwb3J0ZWQgc2lnbmF0dXJlIGFsZ29yaXRobQogICAgICAgIGFsZ29yaXRobTogMzAwRDA2MDkyQTg2NDg4NkY3MEQwMTAxMDQwNTAwCg==
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/target-unknown-critical-extension.pem b/chromium/net/data/verify_certificate_chain_unittest/target-unknown-critical-extension.pem
index f02ac62135d..a5afd225886 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/target-unknown-critical-extension.pem
+++ b/chromium/net/data/verify_certificate_chain_unittest/target-unknown-critical-extension.pem
@@ -1,16 +1,16 @@
-[Created by: ./generate-target-unknown-critical-extension.py]
+[Created by: generate-target-unknown-critical-extension.py]
-Certificate chain with 1 intermediary and a trusted root. The intermediary
-has an unknown X.509v3 extension (OID=1.2.3.4) that is marked as critical.
-Verifying this certificate chain is expected to fail because there is an
-unrecognized critical extension.
+Certificate chain with 1 intermediate and a trusted root. The target
+certificate has an unknown X.509v3 extension (OID=1.2.3.4) that is marked as
+critical. Verifying this certificate chain is expected to fail because there is
+an unrecognized critical extension.
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
+ Issuer: CN=Intermediate
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
@@ -19,38 +19,38 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:c9:42:1d:0f:19:4b:d8:78:b9:3f:4d:43:a8:a9:
- 92:67:ed:f3:55:a4:f5:9e:f4:d0:21:3c:25:cc:28:
- 1d:db:22:5c:c0:eb:e8:78:fe:6c:71:72:ed:0c:cd:
- 76:80:44:dc:72:d1:92:29:7d:e8:7f:e0:42:60:d6:
- cb:b1:53:06:0d:6c:8b:f4:d3:ce:42:af:34:bc:57:
- 63:34:dd:b2:00:26:3f:a9:7f:c8:ce:f6:1a:66:75:
- db:7c:b6:57:ef:ee:3d:e7:d7:b8:38:3a:83:5d:7a:
- 63:1f:91:c4:f1:15:da:9b:e9:f7:ef:d5:d6:26:16:
- 96:c1:94:55:3f:3e:67:13:26:bf:3d:0c:93:ab:1b:
- a2:58:10:38:60:11:18:15:c5:3c:db:71:62:ef:27:
- 1f:a9:62:61:1f:f6:55:51:d9:7c:2d:b6:e3:2d:c3:
- 86:2b:cd:5c:30:d3:a0:0d:a4:e4:34:fb:bb:59:09:
- d5:7b:8f:b2:49:10:0d:d7:2d:0e:34:72:25:7b:b4:
- 0e:e9:fd:cb:ce:50:ee:d2:71:40:14:3d:06:ad:71:
- 52:43:cc:e9:77:4e:c4:8c:af:8c:a2:41:40:4a:82:
- 82:83:a2:58:e3:5e:40:fa:74:f0:fb:bd:46:aa:55:
- 9d:6d:5b:db:af:6a:1f:7c:46:cf:1a:1f:d3:17:c3:
- 02:2f
+ 00:d5:9d:3b:85:e5:81:69:52:70:67:33:4a:2b:76:
+ 6a:e5:61:db:af:e5:32:74:85:dd:54:d2:c7:76:5a:
+ 5c:38:d8:46:fc:b4:33:f5:9d:8e:80:83:ab:31:96:
+ 41:c4:c2:52:af:8c:4d:0e:5c:69:c5:5d:cc:b4:1b:
+ ef:de:61:58:88:e2:c4:bf:6a:cb:74:bd:f5:bd:61:
+ 57:1c:22:9f:6d:e8:38:c6:70:b8:1e:a5:2b:4f:35:
+ 9f:65:fc:c1:36:17:3e:d7:fa:33:21:70:fb:e0:ce:
+ ab:23:41:3f:fc:7b:74:1d:6b:ba:21:b7:5b:fd:a1:
+ 77:11:1a:8d:5b:2a:be:38:2e:79:a0:b7:2d:45:5c:
+ d7:32:fd:4c:70:f1:95:1c:38:a3:15:4f:57:f3:75:
+ 59:fe:75:14:39:ea:44:16:b9:2e:06:df:67:30:dd:
+ 5a:b1:7e:95:09:fd:12:cc:87:b1:66:fa:7e:b9:e5:
+ b5:38:0a:46:73:53:1a:b2:aa:12:e3:6d:99:56:e8:
+ c7:cc:eb:6b:00:9b:c1:ba:02:23:2b:32:be:9b:f8:
+ ab:b2:b5:be:50:f6:7f:95:b6:6b:1c:e6:ad:f1:69:
+ 5a:e0:41:1e:85:64:91:37:7b:9a:28:43:a5:ee:33:
+ 25:ab:82:97:03:07:94:b8:d3:34:95:bf:33:d2:14:
+ b1:61
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 07:DB:E2:A1:15:3D:67:0C:54:ED:D5:22:AD:DE:59:73:9E:0F:F5:24
+ B3:FD:B6:08:AB:82:83:50:E7:F0:85:51:1C:CC:78:E5:22:50:91:60
X509v3 Authority Key Identifier:
- keyid:07:D2:5E:3F:28:F7:AD:46:16:25:D0:4D:DD:6D:77:7B:26:81:89:85
+ keyid:5B:B2:D8:DC:1B:60:39:B5:6B:10:A5:70:37:93:E7:3C:F5:52:46:C8
Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
X509v3 CRL Distribution Points:
Full Name:
- URI:http://url-for-crl/Intermediary.crl
+ URI:http://url-for-crl/Intermediate.crl
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
@@ -59,42 +59,42 @@ Certificate:
1.2.3.4: critical
....
Signature Algorithm: sha256WithRSAEncryption
- 66:78:33:4b:09:c3:20:05:e2:d2:a3:7f:90:2f:96:15:b8:d0:
- ca:7e:97:c6:12:53:4b:18:92:03:77:b6:2c:8b:57:8e:84:7d:
- 14:ee:df:cc:99:0d:f9:2e:21:dd:ca:4d:00:77:87:88:4d:13:
- 28:36:4a:88:82:52:d2:b8:1d:75:67:1f:b5:0a:ea:bd:6a:b8:
- 98:79:ea:cf:6e:2c:5f:21:94:e4:a9:29:d5:37:87:58:6a:d7:
- 5b:0b:f5:35:59:c9:68:dd:f9:e7:c6:67:1a:ef:26:17:cf:89:
- e7:18:8c:be:41:c4:07:d3:b7:1a:20:44:4f:20:12:8c:2e:5a:
- 39:7c:8b:f3:12:f7:bd:b6:f1:7b:8c:48:7f:c5:29:7f:7a:9e:
- 1e:28:13:08:36:56:ca:8d:17:f2:37:ce:59:0a:e7:ca:19:90:
- c7:c8:b4:45:ab:3b:f7:0e:10:db:81:4b:2d:74:05:46:ab:5c:
- 7e:c2:88:83:87:09:4d:5a:a3:40:56:f5:d5:da:fd:a2:2d:99:
- 8c:d1:bf:0b:d0:8c:ce:79:12:0c:37:fc:b2:08:68:b2:fe:5e:
- cc:3e:99:85:40:74:27:88:7f:f6:43:0f:60:dd:b7:6e:31:e3:
- d4:39:87:8e:b1:cf:2d:b7:2f:bb:f9:ec:f8:86:96:1e:fc:68:
- 0d:45:21:2c
+ 39:19:04:31:e9:20:03:1b:e9:d3:91:25:94:68:4f:8d:07:16:
+ 08:e8:7f:99:01:37:56:8d:f4:15:6b:a8:7c:e4:3d:32:ad:3d:
+ 62:0f:5e:93:6f:b9:21:ba:e8:c3:48:13:e5:eb:ad:26:f0:9b:
+ 4c:fe:76:8e:73:a2:be:01:b5:48:7c:11:7e:cc:47:4b:0c:0c:
+ 17:65:54:ab:0e:79:6c:e5:75:67:52:ab:f7:26:97:36:3d:71:
+ 6d:88:54:b9:ef:b1:00:42:56:64:88:db:0f:9c:be:25:e0:6e:
+ 2b:df:c6:55:3a:89:af:92:1c:21:71:6e:22:ab:5a:b8:de:53:
+ a1:8d:84:0f:0e:55:43:08:45:0b:fd:4a:6f:fa:e4:89:55:a0:
+ 8d:10:c0:3a:06:42:7c:f1:b8:7a:19:a7:61:cc:c0:b1:e2:f1:
+ 14:d5:bd:ff:41:a5:50:f6:ac:a4:3f:ec:6a:6a:3e:7b:60:29:
+ f4:9d:c8:57:81:12:59:7b:0f:b2:2a:43:29:03:a5:eb:e7:e8:
+ cd:15:fe:53:07:e0:12:0a:35:29:e8:fe:7f:51:ae:19:98:d5:
+ 89:9c:05:0a:ba:51:89:0f:1f:3c:8e:2a:eb:e7:93:0a:fd:c1:
+ f3:0e:ce:67:5b:f2:73:dc:e6:2e:db:2b:88:11:3b:07:d8:ff:
+ 79:0c:6a:e1
-----BEGIN CERTIFICATE-----
MIIDnTCCAoWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJQh0P
-GUvYeLk/TUOoqZJn7fNVpPWe9NAhPCXMKB3bIlzA6+h4/mxxcu0MzXaARNxy0ZIp
-feh/4EJg1suxUwYNbIv0085CrzS8V2M03bIAJj+pf8jO9hpmddt8tlfv7j3n17g4
-OoNdemMfkcTxFdqb6ffv1dYmFpbBlFU/PmcTJr89DJOrG6JYEDhgERgVxTzbcWLv
-Jx+pYmEf9lVR2XwttuMtw4YrzVww06ANpOQ0+7tZCdV7j7JJEA3XLQ40ciV7tA7p
-/cvOUO7ScUAUPQatcVJDzOl3TsSMr4yiQUBKgoKDoljjXkD6dPD7vUaqVZ1tW9uv
-ah98Rs8aH9MXwwIvAgMBAAGjgfkwgfYwHQYDVR0OBBYEFAfb4qEVPWcMVO3VIq3e
-WXOeD/UkMB8GA1UdIwQYMBaAFAfSXj8o961GFiXQTd1td3smgYmFMD8GCCsGAQUF
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVnTuF
+5YFpUnBnM0ordmrlYduv5TJ0hd1U0sd2Wlw42Eb8tDP1nY6Ag6sxlkHEwlKvjE0O
+XGnFXcy0G+/eYViI4sS/ast0vfW9YVccIp9t6DjGcLgepStPNZ9l/ME2Fz7X+jMh
+cPvgzqsjQT/8e3Qda7oht1v9oXcRGo1bKr44Lnmgty1FXNcy/Uxw8ZUcOKMVT1fz
+dVn+dRQ56kQWuS4G32cw3VqxfpUJ/RLMh7Fm+n655bU4CkZzUxqyqhLjbZlW6MfM
+62sAm8G6AiMrMr6b+Kuytb5Q9n+Vtmsc5q3xaVrgQR6FZJE3e5ooQ6XuMyWrgpcD
+B5S40zSVvzPSFLFhAgMBAAGjgfkwgfYwHQYDVR0OBBYEFLP9tgirgoNQ5/CFURzM
+eOUiUJFgMB8GA1UdIwQYMBaAFFuy2NwbYDm1axClcDeT5zz1UkbIMD8GCCsGAQUF
BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
BwMBBggrBgEFBQcDAjAOBgMqAwQBAf8EBAECAwQwDQYJKoZIhvcNAQELBQADggEB
-AGZ4M0sJwyAF4tKjf5AvlhW40Mp+l8YSU0sYkgN3tiyLV46EfRTu38yZDfkuId3K
-TQB3h4hNEyg2SoiCUtK4HXVnH7UK6r1quJh56s9uLF8hlOSpKdU3h1hq11sL9TVZ
-yWjd+efGZxrvJhfPiecYjL5BxAfTtxogRE8gEowuWjl8i/MS97228XuMSH/FKX96
-nh4oEwg2VsqNF/I3zlkK58oZkMfItEWrO/cOENuBSy10BUarXH7CiIOHCU1ao0BW
-9dXa/aItmYzRvwvQjM55Egw3/LIIaLL+Xsw+mYVAdCeIf/ZDD2Ddt24x49Q5h46x
-zy23L7v57PiGlh78aA1FISw=
+ADkZBDHpIAMb6dORJZRoT40HFgjof5kBN1aN9BVrqHzkPTKtPWIPXpNvuSG66MNI
+E+XrrSbwm0z+do5zor4BtUh8EX7MR0sMDBdlVKsOeWzldWdSq/cmlzY9cW2IVLnv
+sQBCVmSI2w+cviXgbivfxlU6ia+SHCFxbiKrWrjeU6GNhA8OVUMIRQv9Sm/65IlV
+oI0QwDoGQnzxuHoZp2HMwLHi8RTVvf9BpVD2rKQ/7GpqPntgKfSdyFeBEll7D7Iq
+QykDpevn6M0V/lMH4BIKNSno/n9RrhmY1YmcBQq6UYkPHzyOKuvnkwr9wfMOzmdb
+8nPc5i7bK4gROwfY/3kMauE=
-----END CERTIFICATE-----
Certificate:
@@ -106,35 +106,35 @@ Certificate:
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
+ Subject: CN=Intermediate
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:e1:3b:e0:9e:b3:37:a6:d2:5d:5a:cf:1d:6c:d4:
- e7:9d:92:0e:29:b6:da:7e:48:32:ea:dd:a8:6e:a5:
- 4f:d4:07:23:be:f5:b2:e2:e9:57:1b:a1:bc:67:5a:
- 27:15:9d:f7:51:07:23:d9:0a:0f:21:36:4b:b1:c3:
- 48:71:f5:f8:67:6f:a4:9c:54:8b:e8:d2:79:da:6e:
- 70:06:b8:ae:b5:6f:82:ab:89:5a:68:19:56:c7:8a:
- 93:25:f9:4b:7e:8b:de:2f:1a:92:c4:be:c4:9f:ea:
- 34:fe:95:f5:74:ab:fc:47:8b:34:7d:28:d3:7a:7b:
- 29:70:3e:aa:b9:d9:be:53:fe:79:3a:ea:79:c7:d7:
- 1d:b1:c3:47:e6:7d:8e:ed:40:2a:47:d9:71:5f:c2:
- 6c:cb:52:be:1b:83:01:de:06:97:d4:98:ea:37:67:
- f6:fb:67:69:c7:b1:fe:07:ad:be:0a:f8:c8:a8:5d:
- 98:0b:f6:02:7b:cb:19:f6:23:58:79:f9:d3:8c:a5:
- 09:73:c9:2b:ae:76:33:3f:2d:a9:49:93:39:89:92:
- bc:5e:27:1c:ae:a6:29:43:97:a1:04:d0:6c:b6:b6:
- b8:c3:62:5e:43:7c:ca:27:50:e2:91:da:bb:cc:c6:
- e5:7b:5a:31:62:77:a6:4d:6a:ee:84:ea:7a:87:de:
- a9:bd
+ 00:b9:ec:7c:da:f2:c7:b4:02:ee:82:a9:58:98:60:
+ 67:07:a2:c2:9d:2c:a1:76:50:f7:4a:0a:04:80:45:
+ 7b:3d:f6:31:fe:1d:e9:45:40:76:1d:38:df:c9:e1:
+ 42:df:13:7e:16:26:2b:41:14:6b:6e:5e:f3:39:4e:
+ 61:9d:fd:5f:bf:2a:f9:b7:cf:3f:af:34:b1:17:ef:
+ 97:1f:bf:3d:4c:0a:93:91:bd:ee:11:7a:64:ee:69:
+ 22:75:60:8b:c3:10:cd:9e:91:8a:d8:54:c7:43:f4:
+ fb:88:db:09:7a:22:5d:26:58:ab:7d:d0:41:11:47:
+ 10:62:ed:cc:e6:bb:d2:da:a4:7c:e9:0a:39:5b:9f:
+ 93:b0:06:27:50:38:ea:63:e2:6b:a0:eb:c5:d3:7f:
+ 87:71:d8:08:64:d5:87:0a:6e:59:99:d7:74:7c:da:
+ eb:30:68:9d:f8:09:31:c7:66:5f:9a:fb:2d:9b:f1:
+ c1:ff:cb:57:67:46:03:99:a3:4b:e0:bc:2b:17:f4:
+ 0b:7b:61:3f:5e:cf:c9:41:9b:15:ee:f9:90:46:ad:
+ b4:a2:86:3f:87:3c:dd:7e:97:6f:97:30:88:f8:e6:
+ 88:83:15:ad:77:6a:fd:1e:f1:ae:88:a2:f5:52:6d:
+ 6e:d9:5d:5d:c1:1b:0a:49:10:f4:5a:e8:42:53:67:
+ d1:cd
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 07:D2:5E:3F:28:F7:AD:46:16:25:D0:4D:DD:6D:77:7B:26:81:89:85
+ 5B:B2:D8:DC:1B:60:39:B5:6B:10:A5:70:37:93:E7:3C:F5:52:46:C8
X509v3 Authority Key Identifier:
- keyid:C8:0F:45:73:03:B2:2C:B8:35:14:0F:C4:D7:4B:E4:E2:9D:B2:AB:CE
+ keyid:50:25:07:BE:12:C8:A2:18:2F:32:21:59:CC:2B:5A:A7:4E:19:5D:55
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -149,41 +149,41 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 2a:af:ec:1b:fc:c9:ad:bf:ad:97:8d:ed:f4:44:87:7f:72:86:
- c0:4d:85:dd:eb:6c:d3:c7:17:df:11:0a:f5:e5:2b:c2:53:41:
- 58:73:66:da:29:8a:43:af:5e:24:b2:16:26:b6:89:7e:4a:6f:
- 46:13:05:c4:3f:13:6c:ed:b8:37:a7:a9:f6:c9:c8:b9:b3:a1:
- 7c:eb:99:57:fb:8d:12:c5:47:ff:1e:02:b2:47:dc:e9:6f:41:
- 17:0a:3b:ff:ba:14:76:cc:14:35:ec:71:b0:1a:d4:eb:b0:6c:
- a3:96:eb:7d:50:59:d7:01:a0:ee:67:b8:c8:b6:ed:78:02:b1:
- 0b:72:9c:ea:c3:3b:14:3d:89:fc:89:c2:af:6c:18:ae:b0:13:
- 31:04:a2:89:4f:a6:99:58:00:c6:00:e1:39:79:d4:31:0b:0f:
- d5:92:86:a2:e7:ec:c6:b8:f2:62:21:bb:0d:d5:91:b8:f2:5f:
- db:dc:b1:b2:b2:28:fd:d5:14:54:a6:cf:8d:bd:33:ca:22:27:
- 72:d8:27:85:03:21:7f:8e:4f:2d:e6:bf:22:08:86:03:a8:f3:
- 9f:42:2f:81:8f:1e:44:39:e3:23:b2:9d:3d:64:7e:e2:b3:93:
- 8d:46:a0:b7:08:4e:d5:e6:14:af:1d:5d:b6:74:7c:91:36:37:
- 0c:c0:ab:14
+ 12:72:ee:b6:62:1b:0d:70:52:a6:02:3c:13:2a:88:cf:cb:9a:
+ e2:07:5f:cf:3e:be:75:d3:f9:a6:23:47:ca:fb:88:87:bd:e1:
+ 52:8e:8b:fe:e9:c1:7a:8c:30:91:c5:0c:fe:9d:31:fa:fc:c0:
+ d7:fe:7a:7a:18:6f:3c:67:50:b0:22:b2:09:48:ca:dc:d7:d3:
+ 29:86:eb:f4:cf:e0:3e:6e:d1:88:fa:20:93:b3:05:4c:c6:29:
+ 06:df:4a:8b:72:3e:c8:3c:2b:33:56:26:de:91:1a:11:bc:21:
+ 7b:b8:b5:b6:7c:ca:0d:f7:d6:e8:b0:a8:99:e8:7a:2b:f0:c4:
+ 78:e5:54:9e:3f:73:dc:85:41:97:11:36:45:73:b9:f2:49:8d:
+ d7:83:cf:b4:1a:ed:33:dc:0b:cd:7e:83:77:ce:aa:2f:0e:1f:
+ 4d:e0:19:96:cd:74:79:de:18:8b:ad:9f:0c:96:20:14:63:5e:
+ e2:58:8e:4a:d8:fd:59:0d:a6:a4:02:85:ac:23:d4:43:b2:da:
+ 2d:6b:87:79:9e:2e:1e:f4:d3:95:ef:3d:91:7a:f7:17:16:c7:
+ 9f:1f:b7:42:7e:f4:fa:d9:81:18:26:23:03:1e:86:99:7d:28:
+ ef:a3:ac:be:bb:55:fa:38:62:3c:e6:6e:47:4b:f1:45:ef:de:
+ 38:ea:c3:a3
-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4TvgnrM3
-ptJdWs8dbNTnnZIOKbbafkgy6t2obqVP1AcjvvWy4ulXG6G8Z1onFZ33UQcj2QoP
-ITZLscNIcfX4Z2+knFSL6NJ52m5wBriutW+Cq4laaBlWx4qTJflLfoveLxqSxL7E
-n+o0/pX1dKv8R4s0fSjTenspcD6qudm+U/55Oup5x9cdscNH5n2O7UAqR9lxX8Js
-y1K+G4MB3gaX1JjqN2f2+2dpx7H+B62+CvjIqF2YC/YCe8sZ9iNYefnTjKUJc8kr
-rnYzPy2pSZM5iZK8XiccrqYpQ5ehBNBstra4w2JeQ3zKJ1Dikdq7zMble1oxYnem
-TWruhOp6h96pvQIDAQABo4HLMIHIMB0GA1UdDgQWBBQH0l4/KPetRhYl0E3dbXd7
-JoGJhTAfBgNVHSMEGDAWgBTID0VzA7IsuDUUD8TXS+TinbKrzjA3BggrBgEFBQcB
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuex82vLH
+tALugqlYmGBnB6LCnSyhdlD3SgoEgEV7PfYx/h3pRUB2HTjfyeFC3xN+FiYrQRRr
+bl7zOU5hnf1fvyr5t88/rzSxF++XH789TAqTkb3uEXpk7mkidWCLwxDNnpGK2FTH
+Q/T7iNsJeiJdJlirfdBBEUcQYu3M5rvS2qR86Qo5W5+TsAYnUDjqY+JroOvF03+H
+cdgIZNWHCm5Zmdd0fNrrMGid+Akxx2Zfmvstm/HB/8tXZ0YDmaNL4LwrF/QLe2E/
+Xs/JQZsV7vmQRq20ooY/hzzdfpdvlzCI+OaIgxWtd2r9HvGuiKL1Um1u2V1dwRsK
+SRD0WuhCU2fRzQIDAQABo4HLMIHIMB0GA1UdDgQWBBRbstjcG2A5tWsQpXA3k+c8
+9VJGyDAfBgNVHSMEGDAWgBRQJQe+EsiiGC8yIVnMK1qnThldVTA3BggrBgEFBQcB
AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
-ACqv7Bv8ya2/rZeN7fREh39yhsBNhd3rbNPHF98RCvXlK8JTQVhzZtopikOvXiSy
-Fia2iX5Kb0YTBcQ/E2ztuDenqfbJyLmzoXzrmVf7jRLFR/8eArJH3OlvQRcKO/+6
-FHbMFDXscbAa1OuwbKOW631QWdcBoO5nuMi27XgCsQtynOrDOxQ9ifyJwq9sGK6w
-EzEEoolPpplYAMYA4Tl51DELD9WShqLn7Ma48mIhuw3VkbjyX9vcsbKyKP3VFFSm
-z429M8oiJ3LYJ4UDIX+OTy3mvyIIhgOo859CL4GPHkQ54yOynT1kfuKzk41GoLcI
-TtXmFK8dXbZ0fJE2NwzAqxQ=
+ABJy7rZiGw1wUqYCPBMqiM/LmuIHX88+vnXT+aYjR8r7iIe94VKOi/7pwXqMMJHF
+DP6dMfr8wNf+enoYbzxnULAisglIytzX0ymG6/TP4D5u0Yj6IJOzBUzGKQbfSoty
+Psg8KzNWJt6RGhG8IXu4tbZ8yg331uiwqJnoeivwxHjlVJ4/c9yFQZcRNkVzufJJ
+jdeDz7Qa7TPcC81+g3fOqi8OH03gGZbNdHneGIutnwyWIBRjXuJYjkrY/VkNpqQC
+hawj1EOy2i1rh3meLh7005XvPZF69xcWx58ft0J+9PrZgRgmIwMehpl9KO+jrL67
+Vfo4YjzmbkdL8UXv3jjqw6M=
-----END CERTIFICATE-----
Certificate:
@@ -200,30 +200,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:dc:6a:1a:05:36:f1:a3:7c:28:e9:97:2f:7b:85:
- d5:c1:91:33:0a:72:2d:bb:45:ae:c6:29:54:22:05:
- c2:e9:f4:be:f2:39:ec:e0:64:66:1d:e3:c9:42:3e:
- 6c:c8:3b:65:0a:e4:2c:74:e4:c9:17:c8:8b:27:6e:
- c0:4c:9a:b4:85:ae:ff:3f:e3:1e:d0:21:1c:8b:84:
- e0:3b:f6:59:00:a7:ab:59:f3:58:67:d7:af:97:74:
- a9:b1:1f:78:80:ad:e3:09:31:81:c2:11:55:10:d0:
- 93:ca:eb:de:a7:72:76:09:33:6a:89:f9:51:b1:de:
- ca:4a:48:e8:9f:1c:5f:df:bc:7d:a7:f5:27:6b:77:
- a3:53:e5:c3:e4:3d:9e:82:72:9e:d2:1b:76:52:8c:
- f0:53:b6:98:5f:6c:54:1b:da:9a:72:14:ee:c3:51:
- b4:c7:6b:f0:75:b2:2c:6e:b4:b7:29:54:92:ab:69:
- 57:af:3c:6d:96:e8:05:c8:a4:d0:7a:c2:42:7d:8b:
- 7f:3c:8f:9d:1d:c1:35:af:41:7b:f5:0e:60:88:72:
- 90:22:ac:37:2f:7b:b4:47:01:62:b8:fe:73:4b:d2:
- 7b:56:8d:b2:37:d3:18:2f:dc:fb:d1:fb:e9:14:19:
- b1:d8:76:eb:34:d2:c0:40:a8:22:68:33:44:a7:84:
- 90:e1
+ 00:a9:09:72:27:8b:f5:e4:bb:33:ee:14:1d:da:11:
+ 7c:b1:f1:53:3a:a3:77:3f:b2:f5:1f:b6:23:a3:69:
+ f8:9d:52:97:4c:92:af:07:46:c5:82:3f:97:a5:b2:
+ fc:e0:b3:3e:29:53:e5:75:07:04:30:7b:bb:55:a3:
+ af:ec:c3:bd:a0:c5:f1:58:4b:a8:5a:77:49:c7:fc:
+ a2:13:97:5c:3a:95:58:9b:95:4c:a0:18:b3:3a:18:
+ 1d:fe:5f:c1:c7:9b:d3:9a:0d:f3:4c:a6:3d:28:21:
+ 50:9d:ae:90:ae:aa:96:23:d6:4f:9b:ec:ff:59:67:
+ 0a:ff:8a:89:df:bc:99:ff:f6:75:b5:da:c7:79:d8:
+ 54:c8:f3:96:3a:c6:e9:60:0c:ee:9e:52:e1:e9:5f:
+ 58:1e:29:a3:1a:c3:4f:91:8c:2e:85:33:87:f0:c7:
+ c6:74:91:cc:fb:dd:ca:1e:71:6f:e2:c1:41:bc:ef:
+ e8:7f:48:07:a9:5c:aa:21:60:43:fd:3e:98:8b:4c:
+ 8d:95:55:48:3b:35:1a:2a:f4:e3:ef:85:01:11:c4:
+ f4:a3:15:e3:68:df:bb:94:f9:26:10:35:83:96:83:
+ 00:ce:cf:71:d4:e9:01:18:80:c2:dd:f0:9d:52:f6:
+ fa:11:de:a1:7f:79:d9:13:a6:eb:33:3e:04:57:b6:
+ 75:b9
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- C8:0F:45:73:03:B2:2C:B8:35:14:0F:C4:D7:4B:E4:E2:9D:B2:AB:CE
+ 50:25:07:BE:12:C8:A2:18:2F:32:21:59:CC:2B:5A:A7:4E:19:5D:55
X509v3 Authority Key Identifier:
- keyid:C8:0F:45:73:03:B2:2C:B8:35:14:0F:C4:D7:4B:E4:E2:9D:B2:AB:CE
+ keyid:50:25:07:BE:12:C8:A2:18:2F:32:21:59:CC:2B:5A:A7:4E:19:5D:55
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -238,47 +238,59 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 54:39:78:5b:30:97:aa:99:fb:e5:0a:39:27:2a:ea:ad:9f:37:
- 3e:aa:5a:b8:c4:51:66:83:6e:36:5c:c3:1b:da:de:cd:a7:6e:
- bd:55:47:7c:3e:53:12:6a:51:02:13:c2:98:03:32:b6:5b:d9:
- 5e:26:b2:9a:d1:21:ca:39:cd:20:be:ad:d8:3a:23:a2:de:d7:
- 18:b2:99:bb:d4:1a:82:43:7c:6e:20:3c:01:f1:22:5f:72:ac:
- 43:9a:87:07:37:5d:a8:34:26:19:89:aa:f3:18:e3:ee:c6:67:
- 43:49:64:e4:b3:d8:2c:11:8c:f7:8b:48:7f:fd:e1:6b:e9:a5:
- 87:55:bf:f1:9d:54:fe:b5:7f:c4:5c:8b:08:cf:4f:47:21:58:
- 06:5e:ab:40:be:b7:28:0c:27:55:82:6b:e8:17:5e:dd:f8:79:
- 61:f2:7e:18:59:7a:24:7e:e3:08:3c:d9:d1:81:73:36:51:99:
- a1:ea:bf:18:ff:94:40:d7:ff:5f:1a:8a:b1:ae:78:c1:91:7b:
- 55:1a:d8:b1:91:02:b6:5e:94:32:84:5f:77:f8:89:89:00:5c:
- 74:be:77:1b:95:3e:60:2d:6a:67:a3:e9:42:03:51:af:1f:10:
- d8:21:6f:36:29:33:72:90:f4:7e:05:17:bb:a5:aa:fb:d6:56:
- fc:40:2e:0e
------BEGIN TRUSTED_CERTIFICATE-----
+ 3d:e1:85:32:4c:43:1e:f2:0d:ff:d3:ec:90:97:7d:8f:9c:16:
+ b1:6e:cb:55:f1:4f:d9:46:1c:c8:d7:3c:3e:8c:2c:8a:21:b8:
+ 38:a4:a9:a8:ac:69:51:32:3c:99:57:f8:73:2a:56:4a:ba:6e:
+ 6a:a8:89:f0:03:14:d2:7f:d2:22:55:84:47:e7:05:9c:3b:72:
+ 5d:39:02:b0:fc:68:90:14:02:12:d8:9b:85:1c:cf:77:92:c7:
+ 73:80:38:e4:f4:f9:72:b7:dd:ca:0f:3d:f2:1c:6a:82:1f:21:
+ 90:d3:e3:77:e5:ee:e9:0e:23:9e:69:f6:29:38:51:4f:e9:73:
+ 7d:3d:32:54:b2:96:04:9b:62:36:99:8b:ea:9c:3f:87:7f:5e:
+ e8:ed:28:c8:15:ac:59:f8:f5:d9:3b:b3:fd:d4:a9:e4:55:1b:
+ 07:ee:d9:18:77:d4:68:8d:b0:ce:a3:60:fe:60:2c:ca:b4:2f:
+ 08:8a:19:1a:fc:a3:6b:1b:b4:72:28:7a:63:cc:cc:cd:18:ae:
+ 99:86:4d:67:12:48:a6:33:f3:19:ce:fa:5a:a5:d7:0d:4d:50:
+ c6:1f:f2:d9:e6:41:d6:29:4a:a6:3c:ff:80:4f:e6:e8:90:f5:
+ ab:cb:bf:93:3b:90:da:e6:fb:d5:59:c3:9f:ec:91:bf:3e:0a:
+ a3:23:ef:ee
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxqGgU28aN8KOmXL3uF
-1cGRMwpyLbtFrsYpVCIFwun0vvI57OBkZh3jyUI+bMg7ZQrkLHTkyRfIiyduwEya
-tIWu/z/jHtAhHIuE4Dv2WQCnq1nzWGfXr5d0qbEfeICt4wkxgcIRVRDQk8rr3qdy
-dgkzaon5UbHeykpI6J8cX9+8faf1J2t3o1Plw+Q9noJyntIbdlKM8FO2mF9sVBva
-mnIU7sNRtMdr8HWyLG60tylUkqtpV688bZboBcik0HrCQn2LfzyPnR3BNa9Be/UO
-YIhykCKsNy97tEcBYrj+c0vSe1aNsjfTGC/c+9H76RQZsdh26zTSwECoImgzRKeE
-kOECAwEAAaOByzCByDAdBgNVHQ4EFgQUyA9FcwOyLLg1FA/E10vk4p2yq84wHwYD
-VR0jBBgwFoAUyA9FcwOyLLg1FA/E10vk4p2yq84wNwYIKwYBBQUHAQEEKzApMCcG
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkJcieL9eS7M+4UHdoR
+fLHxUzqjdz+y9R+2I6Np+J1Sl0ySrwdGxYI/l6Wy/OCzPilT5XUHBDB7u1Wjr+zD
+vaDF8VhLqFp3Scf8ohOXXDqVWJuVTKAYszoYHf5fwceb05oN80ymPSghUJ2ukK6q
+liPWT5vs/1lnCv+Kid+8mf/2dbXax3nYVMjzljrG6WAM7p5S4elfWB4poxrDT5GM
+LoUzh/DHxnSRzPvdyh5xb+LBQbzv6H9IB6lcqiFgQ/0+mItMjZVVSDs1Gir04++F
+ARHE9KMV42jfu5T5JhA1g5aDAM7PcdTpARiAwt3wnVL2+hHeoX952ROm6zM+BFe2
+dbkCAwEAAaOByzCByDAdBgNVHQ4EFgQUUCUHvhLIohgvMiFZzCtap04ZXVUwHwYD
+VR0jBBgwFoAUUCUHvhLIohgvMiFZzCtap04ZXVUwNwYIKwYBBQUHAQEEKzApMCcG
CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBUOXhbMJeq
-mfvlCjknKuqtnzc+qlq4xFFmg242XMMb2t7Np269VUd8PlMSalECE8KYAzK2W9le
-JrKa0SHKOc0gvq3YOiOi3tcYspm71BqCQ3xuIDwB8SJfcqxDmocHN12oNCYZiarz
-GOPuxmdDSWTks9gsEYz3i0h//eFr6aWHVb/xnVT+tX/EXIsIz09HIVgGXqtAvrco
-DCdVgmvoF17d+Hlh8n4YWXokfuMIPNnRgXM2UZmh6r8Y/5RA1/9fGoqxrnjBkXtV
-GtixkQK2XpQyhF93+ImJAFx0vncblT5gLWpno+lCA1GvHxDYIW82KTNykPR+BRe7
-par71lb8QC4O
------END TRUSTED_CERTIFICATE-----
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA94YUyTEMe
+8g3/0+yQl32PnBaxbstV8U/ZRhzI1zw+jCyKIbg4pKmorGlRMjyZV/hzKlZKum5q
+qInwAxTSf9IiVYRH5wWcO3JdOQKw/GiQFAIS2JuFHM93ksdzgDjk9Plyt93KDz3y
+HGqCHyGQ0+N35e7pDiOeafYpOFFP6XN9PTJUspYEm2I2mYvqnD+Hf17o7SjIFaxZ
++PXZO7P91KnkVRsH7tkYd9RojbDOo2D+YCzKtC8Iihka/KNrG7RyKHpjzMzNGK6Z
+hk1nEkimM/MZzvpapdcNTVDGH/LZ5kHWKUqmPP+AT+bokPWry7+TO5Da5vvVWcOf
+7JG/PgqjI+/u
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+150302120000Z
-----BEGIN TIME-----
MTUwMzAyMTIwMDAwWg==
-----END TIME-----
+FAIL
-----BEGIN VERIFY_RESULT-----
RkFJTA==
-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 1
+ [Error] Unconsumed critical extension
+ oid: 2A0304
+ value: 01020304
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMQogICAgICBbRXJyb3JdIFVuY29uc3VtZWQgY3JpdGljYWwgZXh0ZW5zaW9uCiAgICAgICAgb2lkOiAyQTAzMDQKICAgICAgICB2YWx1ZTogMDEwMjAzMDQK
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/target-wrong-signature.pem b/chromium/net/data/verify_certificate_chain_unittest/target-wrong-signature.pem
index 9d162b0dc55..191a6c70270 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/target-wrong-signature.pem
+++ b/chromium/net/data/verify_certificate_chain_unittest/target-wrong-signature.pem
@@ -9,7 +9,7 @@ Certificate:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
+ Issuer: CN=Intermediate
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
@@ -18,80 +18,80 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:cd:40:90:3b:6e:2e:d4:5d:a8:08:3e:d4:69:a0:
- ec:3b:62:99:ec:81:30:1b:6e:d0:92:8b:bd:df:17:
- 3a:fb:ce:bd:2a:32:5b:bb:5e:da:53:6c:b9:3d:4b:
- a8:0b:12:41:61:d3:f9:3f:23:b9:71:3f:33:8a:bf:
- 57:48:bd:99:e1:5d:c7:99:72:fd:ac:f4:4f:e1:cd:
- ca:b8:0c:81:57:64:c5:56:1f:d9:ed:f8:df:c6:60:
- 70:82:ee:b5:23:4a:a4:b5:d6:b4:e3:84:74:c9:ca:
- da:d7:a7:11:51:c4:56:36:6c:b4:53:0e:35:e5:63:
- fa:fd:75:df:72:01:31:17:e9:4d:35:8c:ae:a9:c1:
- 3b:ae:ac:06:75:e0:77:2b:36:97:e5:bb:99:34:b6:
- dc:f4:11:f6:2f:33:4e:db:4b:73:18:78:51:e6:12:
- d1:be:94:2a:02:33:d9:bc:8a:36:dc:12:f0:2f:ae:
- 57:4b:66:f0:ba:e6:1b:65:01:de:95:06:63:22:9b:
- d0:58:42:55:99:34:06:ec:5a:00:f2:77:ed:71:23:
- 24:7d:66:9a:e0:8c:d3:64:91:0a:a6:5b:36:43:36:
- e3:07:33:a0:c3:fa:46:9c:3e:81:b2:2c:a6:51:92:
- a7:7a:01:cb:95:1a:ea:cf:3c:fa:93:2d:81:5b:29:
- 98:d5
+ 00:95:c5:73:7e:a9:8f:9f:25:a3:b1:9f:29:c6:2e:
+ d6:b2:3d:5b:a4:10:08:53:40:f7:91:79:45:96:d0:
+ 66:85:85:ea:56:e6:db:07:fd:82:1d:e3:e6:11:f2:
+ da:13:64:45:bf:c6:e1:a7:4c:da:29:e7:ba:2f:27:
+ d8:cd:59:3d:69:a3:af:d6:64:4b:3e:a4:12:07:5d:
+ d4:7d:07:85:6d:9c:9d:fe:fd:8f:ff:74:b3:c9:c9:
+ 86:64:7c:ee:ca:74:1b:2f:3f:7c:37:8b:d9:fa:05:
+ 0a:3a:9b:93:45:d0:8d:16:3e:7a:ce:0b:bb:8f:1b:
+ cc:15:4b:a2:76:08:f5:fb:e0:98:cc:1d:a4:1a:c1:
+ f5:23:b0:28:1c:fe:5f:a4:24:68:59:fc:1d:63:bc:
+ 60:9a:a6:16:2c:db:0d:66:9d:d7:6e:13:6a:53:8c:
+ 5b:61:a7:3f:9f:be:c8:2a:f9:ce:ea:47:d2:d2:1b:
+ 95:de:af:5d:b0:39:3d:71:f5:be:5f:80:bd:3b:3e:
+ 2e:79:e8:a2:de:9c:2b:da:e5:88:cd:4e:9c:cf:cd:
+ bc:88:2e:cc:9e:3b:e4:52:2b:49:0f:31:90:3f:15:
+ 0d:b5:68:ea:5e:7e:6e:f9:6c:ba:57:bd:41:33:51:
+ 27:66:f9:2b:3f:ae:7c:87:07:a1:19:a5:0f:ba:bd:
+ f8:b7
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 7F:F7:32:82:5E:B7:BD:FB:F8:64:38:93:2A:B1:6E:10:D6:4A:B4:28
+ 5E:72:8E:7C:0B:A6:A7:E8:2C:3E:36:CA:37:EF:8E:4E:46:CB:97:34
X509v3 Authority Key Identifier:
- keyid:E1:EB:47:46:C2:78:53:C4:B6:58:28:94:20:81:58:06:93:17:36:7F
+ keyid:DF:46:5C:25:13:E9:22:B2:C9:E4:1A:32:22:C4:97:1F:E6:0C:55:AA
Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
X509v3 CRL Distribution Points:
Full Name:
- URI:http://url-for-crl/Intermediary.crl
+ URI:http://url-for-crl/Intermediate.crl
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 80:dc:43:74:98:bf:da:2c:ea:5f:60:45:7f:d9:90:46:b1:f1:
- ba:ea:9f:e3:39:40:4e:43:51:30:f1:a6:1a:c7:52:48:ed:de:
- 2a:d8:6d:0d:b6:b2:69:a7:d7:e6:e9:4d:c3:73:c6:e5:3f:56:
- 06:04:79:d2:a5:56:b7:a6:a5:a8:a2:2c:4f:0e:fa:fe:4f:39:
- 11:5a:83:76:af:5e:0f:5d:df:0e:c6:c2:ea:79:19:04:92:a1:
- c7:57:b2:16:83:c3:44:d1:47:89:e1:14:eb:1c:2c:f0:a9:63:
- ed:31:fc:43:d0:93:c5:4c:7f:d3:68:6e:9b:81:2c:4f:70:71:
- 90:af:98:ce:f6:73:97:5b:dc:13:d3:d9:01:8e:5f:34:a8:00:
- 1d:71:89:a7:6e:12:f3:df:9d:4b:18:1f:0f:84:59:2b:7f:d0:
- 05:5d:5f:e7:97:b7:26:ab:c1:12:87:19:28:6a:43:dc:c0:76:
- 38:8a:fc:16:93:92:d3:2e:69:1f:9b:f3:1d:75:0d:32:89:f6:
- ca:a4:8c:f2:c6:0a:17:e4:29:c3:bc:a6:33:df:c2:cd:42:97:
- 28:65:1f:99:c9:6b:41:0e:4b:59:de:32:f2:1e:f7:62:88:66:
- c6:d1:e7:9a:25:78:86:7d:e3:f3:4e:f7:18:11:ce:bc:37:56:
- 78:f4:04:b1
+ 15:7a:35:37:ba:ff:11:3b:c0:ad:82:51:d0:e9:23:50:77:06:
+ 56:e0:84:94:2d:e4:76:94:d5:af:65:26:26:06:77:f2:6c:03:
+ f4:77:6c:a3:ba:92:26:c7:a0:ea:24:06:98:78:18:24:70:44:
+ 08:03:d0:ef:0b:db:d9:f2:3d:35:38:17:41:69:46:62:1a:af:
+ a7:44:be:1d:27:02:b3:79:1a:30:ab:06:79:6a:bd:3f:72:21:
+ f2:34:47:07:ef:08:69:ae:40:1f:61:68:a7:a8:a8:5c:85:6e:
+ 39:61:39:ad:8a:3a:a5:d8:64:94:bd:e2:dc:1f:68:45:f0:2c:
+ bf:08:d0:74:75:1c:80:30:86:87:b0:f4:eb:69:e8:16:52:45:
+ bc:c3:3b:08:c9:90:9f:f8:c9:01:9b:2f:29:2b:dc:2c:af:59:
+ cb:3e:07:8a:e7:e0:ca:64:2a:43:39:bf:a5:0e:d6:14:08:e9:
+ 9a:c1:76:7d:fb:a1:39:05:a6:43:0a:ba:ed:70:5b:f5:b8:ac:
+ 15:91:a4:37:24:c7:1e:d2:69:41:08:e2:2f:76:bb:e1:f8:b9:
+ 0d:7a:a9:57:af:25:8c:5c:73:f2:d8:2b:a6:23:c8:42:b4:28:
+ ed:fe:79:2b:11:4a:2e:3c:ef:3f:13:e6:51:68:d8:1a:c3:3b:
+ b3:22:62:c9
-----BEGIN CERTIFICATE-----
MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNQJA7
-bi7UXagIPtRpoOw7YpnsgTAbbtCSi73fFzr7zr0qMlu7XtpTbLk9S6gLEkFh0/k/
-I7lxPzOKv1dIvZnhXceZcv2s9E/hzcq4DIFXZMVWH9nt+N/GYHCC7rUjSqS11rTj
-hHTJytrXpxFRxFY2bLRTDjXlY/r9dd9yATEX6U01jK6pwTuurAZ14HcrNpflu5k0
-ttz0EfYvM07bS3MYeFHmEtG+lCoCM9m8ijbcEvAvrldLZvC65htlAd6VBmMim9BY
-QlWZNAbsWgDyd+1xIyR9ZprgjNNkkQqmWzZDNuMHM6DD+kacPoGyLKZRkqd6AcuV
-GurPPPqTLYFbKZjVAgMBAAGjgekwgeYwHQYDVR0OBBYEFH/3MoJet737+GQ4kyqx
-bhDWSrQoMB8GA1UdIwQYMBaAFOHrR0bCeFPEtlgolCCBWAaTFzZ/MD8GCCsGAQUF
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVxXN+
+qY+fJaOxnynGLtayPVukEAhTQPeReUWW0GaFhepW5tsH/YId4+YR8toTZEW/xuGn
+TNop57ovJ9jNWT1po6/WZEs+pBIHXdR9B4VtnJ3+/Y//dLPJyYZkfO7KdBsvP3w3
+i9n6BQo6m5NF0I0WPnrOC7uPG8wVS6J2CPX74JjMHaQawfUjsCgc/l+kJGhZ/B1j
+vGCaphYs2w1mndduE2pTjFthpz+fvsgq+c7qR9LSG5Xer12wOT1x9b5fgL07Pi55
+6KLenCva5YjNTpzPzbyILsyeO+RSK0kPMZA/FQ21aOpefm75bLpXvUEzUSdm+Ss/
+rnyHB6EZpQ+6vfi3AgMBAAGjgekwgeYwHQYDVR0OBBYEFF5yjnwLpqfoLD42yjfv
+jk5Gy5c0MB8GA1UdIwQYMBaAFN9GXCUT6SKyyeQaMiLElx/mDFWqMD8GCCsGAQUF
BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAgNxDdJi/2izqX2BFf9mQ
-RrHxuuqf4zlATkNRMPGmGsdSSO3eKthtDbayaafX5ulNw3PG5T9WBgR50qVWt6al
-qKIsTw76/k85EVqDdq9eD13fDsbC6nkZBJKhx1eyFoPDRNFHieEU6xws8Klj7TH8
-Q9CTxUx/02hum4EsT3BxkK+YzvZzl1vcE9PZAY5fNKgAHXGJp24S89+dSxgfD4RZ
-K3/QBV1f55e3JqvBEocZKGpD3MB2OIr8FpOS0y5pH5vzHXUNMon2yqSM8sYKF+Qp
-w7ymM9/CzUKXKGUfmclrQQ5LWd4y8h73YohmxtHnmiV4hn3j8073GBHOvDdWePQE
-sQ==
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAFXo1N7r/ETvArYJR0Okj
+UHcGVuCElC3kdpTVr2UmJgZ38mwD9Hdso7qSJseg6iQGmHgYJHBECAPQ7wvb2fI9
+NTgXQWlGYhqvp0S+HScCs3kaMKsGeWq9P3Ih8jRHB+8Iaa5AH2Fop6ioXIVuOWE5
+rYo6pdhklL3i3B9oRfAsvwjQdHUcgDCGh7D062noFlJFvMM7CMmQn/jJAZsvKSvc
+LK9Zyz4HiufgymQqQzm/pQ7WFAjpmsF2ffuhOQWmQwq67XBb9bisFZGkNyTHHtJp
+QQjiL3a74fi5DXqpV68ljFxz8tgrpiPIQrQo7f55KxFKLjzvPxPmUWjYGsM7syJi
+yQ==
-----END CERTIFICATE-----
Certificate:
@@ -103,35 +103,35 @@ Certificate:
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
+ Subject: CN=Intermediate
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:c8:7f:42:62:ee:29:ef:bb:58:84:48:c3:aa:61:
- ca:32:b1:ec:f0:e6:34:0b:f4:7e:d2:21:46:bb:bb:
- b5:fb:43:ef:e8:66:88:2e:a3:86:4f:2e:95:51:f8:
- 82:dd:c4:7a:9f:3b:6e:81:4d:32:eb:a6:c7:05:4a:
- 1d:f1:bd:31:9a:2d:45:0b:2e:a9:9b:d4:13:a4:55:
- 40:1c:12:db:4b:76:2b:31:cc:8b:fb:f7:a4:52:e1:
- de:f7:0f:b8:17:47:a4:0a:1e:53:b9:7c:a6:cc:ac:
- ed:40:72:d1:9c:93:85:05:2e:77:1e:60:ab:7d:fc:
- 46:0f:f1:47:65:09:53:62:c6:90:db:5d:4e:ee:cd:
- e9:ea:f0:18:f0:ba:a3:91:e2:bf:7b:24:e9:eb:13:
- 48:4e:05:63:f4:40:b8:f1:84:7b:d6:91:e9:90:50:
- c2:7a:f7:44:2e:70:ad:73:c1:5a:3c:32:5e:3c:9b:
- 15:5f:9a:b2:48:03:50:a6:72:2f:10:94:81:e5:27:
- bf:28:01:6a:a2:ef:3f:6c:10:b0:a2:02:72:27:d8:
- 1c:0c:d4:4d:06:55:48:19:ab:6d:67:56:cd:2d:55:
- 63:e5:50:63:02:7d:cc:c6:28:ef:29:ed:db:50:f2:
- 31:23:dd:52:f3:27:7e:fd:e1:5f:6f:f5:0f:69:58:
- 2b:01
+ 00:ba:c2:3e:70:32:82:15:bd:6f:24:c3:e0:9f:a9:
+ af:46:01:cb:23:03:07:17:d8:73:73:d0:8d:46:88:
+ 3f:9b:40:30:ea:cb:76:d1:dc:e5:79:c6:ed:5e:94:
+ 68:49:fe:8e:be:ff:74:b4:b1:a0:fd:ec:3f:4c:f5:
+ 26:40:97:d8:b2:fd:a8:e1:9a:1e:47:48:58:8a:39:
+ 0f:a8:53:76:1d:d8:55:b7:ff:15:7a:1a:28:70:a7:
+ 50:6f:f7:2f:d8:dd:22:bf:08:32:82:66:33:fd:7d:
+ df:55:7f:71:5b:bd:c0:c6:f4:cd:a4:52:30:a9:bd:
+ a1:a3:61:e3:7a:93:40:a7:41:b3:10:43:0f:79:12:
+ 50:34:0a:a4:ad:07:53:e6:7a:b6:8c:a5:00:82:0c:
+ 9f:eb:c9:f8:51:68:2c:4e:3a:da:7e:7d:6d:15:b1:
+ ff:37:dd:e6:25:cf:5e:8f:fe:b1:09:7e:f8:60:3b:
+ 20:3e:99:64:e1:9a:58:ee:01:28:71:cf:ac:dd:66:
+ 40:0d:d9:7b:85:8f:f2:35:90:2a:75:26:96:b4:3a:
+ f2:ef:5c:06:f1:2c:ec:07:83:d6:23:a4:ab:f4:28:
+ ad:1f:8d:cf:e2:d8:b9:1f:48:76:6f:7c:e7:8a:17:
+ 5b:b5:9b:ff:17:13:6e:f4:05:47:78:91:c7:7a:03:
+ 33:15
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- C4:E1:12:23:5E:5D:61:E9:F8:C1:9E:0E:57:94:54:97:B2:4E:0B:65
+ D0:3F:2D:C4:6A:01:B8:7A:61:4F:B0:35:18:E6:D0:F9:55:5D:7B:B7
X509v3 Authority Key Identifier:
- keyid:81:56:F3:D5:96:CB:97:DE:87:18:26:E0:E7:E9:59:9E:58:FC:8B:76
+ keyid:D4:FF:80:DD:86:D2:53:18:54:65:B3:62:9A:07:67:BB:21:7D:19:77
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -146,41 +146,41 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 4a:7b:2a:d9:aa:69:78:28:dc:2d:46:22:f2:ec:d3:09:b7:b7:
- 91:2b:6d:a0:07:b9:8a:9e:5c:11:73:ba:1d:61:ed:07:b2:a3:
- 7e:3c:48:f3:95:59:ed:98:e9:40:9c:88:47:47:23:9e:37:ce:
- f3:49:b5:53:51:be:4a:8b:77:ac:ef:76:2a:3b:11:d1:92:61:
- cc:f4:04:85:09:c2:83:db:21:cc:20:a6:49:3d:54:da:e8:ba:
- e2:0f:f6:15:fd:cb:83:8a:82:17:b2:c3:43:dd:a4:0a:42:61:
- 59:75:5c:c6:5b:7e:5f:97:e6:ea:7e:bc:19:17:5b:df:9e:72:
- a4:31:fd:64:6d:34:5b:05:39:5d:f3:2d:35:44:0a:cc:da:cb:
- af:86:06:14:0f:ae:47:9e:ff:f1:55:dc:32:4b:9b:43:df:60:
- d9:ee:0a:09:95:08:43:c3:c3:18:30:c6:56:f1:d0:b9:17:c9:
- 19:5f:a5:c3:a2:76:c0:ad:b2:73:24:0e:34:03:f0:83:17:a5:
- ac:b1:4f:9e:38:3d:7d:82:f6:90:ca:43:f5:37:c4:1a:19:2e:
- a5:a9:40:64:0a:fb:d1:eb:42:c2:42:f1:08:26:6b:d6:c3:59:
- bc:14:99:95:b3:62:80:92:93:49:4f:95:fe:71:e8:7c:3d:ee:
- 21:99:7a:aa
+ 44:69:05:6c:d0:10:da:90:f7:62:5f:8a:80:93:39:f0:ee:6f:
+ c5:18:df:47:40:d0:b4:73:8a:d6:68:7f:99:92:e4:34:bd:ef:
+ d7:c8:8c:d9:09:b1:24:06:86:ab:9f:58:1a:d3:38:73:9b:80:
+ f3:9b:a9:8c:db:ef:0d:94:54:91:45:04:42:9b:98:3c:fc:39:
+ 53:85:36:1d:06:59:c5:1e:50:7c:1e:e0:ec:ad:d8:44:98:13:
+ a2:6b:bc:10:39:3e:3e:5b:3a:30:de:2a:a0:08:05:21:cd:d1:
+ 57:50:05:c2:84:c3:e8:0d:69:59:76:3d:32:aa:9a:82:0d:59:
+ c6:1a:8e:fa:08:3c:18:08:b2:8b:f2:39:05:02:0e:af:7c:28:
+ 7e:16:44:d8:b2:e0:32:19:d7:c5:54:4c:e9:87:e0:1f:30:73:
+ 6a:2b:ef:9f:9d:5e:31:a6:02:39:9d:5b:e1:c5:b6:d1:cd:95:
+ ba:ee:5c:3a:97:58:49:ef:26:cf:e6:eb:72:47:5b:6e:f4:cc:
+ 3b:1c:08:c7:2e:89:f6:91:ef:94:e3:33:83:7c:9b:d8:10:01:
+ d7:ac:0f:4c:c6:01:c7:0d:84:48:bd:a7:e8:4d:09:40:a8:b2:
+ f3:0a:21:71:74:0f:ab:ca:23:aa:99:80:6d:0c:42:73:14:00:
+ 31:1e:67:51
-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIBAzANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyH9CYu4p
-77tYhEjDqmHKMrHs8OY0C/R+0iFGu7u1+0Pv6GaILqOGTy6VUfiC3cR6nztugU0y
-66bHBUod8b0xmi1FCy6pm9QTpFVAHBLbS3YrMcyL+/ekUuHe9w+4F0ekCh5TuXym
-zKztQHLRnJOFBS53HmCrffxGD/FHZQlTYsaQ211O7s3p6vAY8LqjkeK/eyTp6xNI
-TgVj9EC48YR71pHpkFDCevdELnCtc8FaPDJePJsVX5qySANQpnIvEJSB5Se/KAFq
-ou8/bBCwogJyJ9gcDNRNBlVIGattZ1bNLVVj5VBjAn3MxijvKe3bUPIxI91S8yd+
-/eFfb/UPaVgrAQIDAQABo4HLMIHIMB0GA1UdDgQWBBTE4RIjXl1h6fjBng5XlFSX
-sk4LZTAfBgNVHSMEGDAWgBSBVvPVlsuX3ocYJuDn6VmeWPyLdjA3BggrBgEFBQcB
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAusI+cDKC
+Fb1vJMPgn6mvRgHLIwMHF9hzc9CNRog/m0Aw6st20dzlecbtXpRoSf6Ovv90tLGg
+/ew/TPUmQJfYsv2o4ZoeR0hYijkPqFN2HdhVt/8VehoocKdQb/cv2N0ivwgygmYz
+/X3fVX9xW73AxvTNpFIwqb2ho2HjepNAp0GzEEMPeRJQNAqkrQdT5nq2jKUAggyf
+68n4UWgsTjrafn1tFbH/N93mJc9ej/6xCX74YDsgPplk4ZpY7gEocc+s3WZADdl7
+hY/yNZAqdSaWtDry71wG8SzsB4PWI6Sr9CitH43P4ti5H0h2b3znihdbtZv/FxNu
+9AVHeJHHegMzFQIDAQABo4HLMIHIMB0GA1UdDgQWBBTQPy3EagG4emFPsDUY5tD5
+VV17tzAfBgNVHSMEGDAWgBTU/4DdhtJTGFRls2KaB2e7IX0ZdzA3BggrBgEFBQcB
AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
-AEp7KtmqaXgo3C1GIvLs0wm3t5ErbaAHuYqeXBFzuh1h7Qeyo348SPOVWe2Y6UCc
-iEdHI543zvNJtVNRvkqLd6zvdio7EdGSYcz0BIUJwoPbIcwgpkk9VNrouuIP9hX9
-y4OKgheyw0PdpApCYVl1XMZbfl+X5up+vBkXW9+ecqQx/WRtNFsFOV3zLTVECsza
-y6+GBhQPrkee//FV3DJLm0PfYNnuCgmVCEPDwxgwxlbx0LkXyRlfpcOidsCtsnMk
-DjQD8IMXpayxT544PX2C9pDKQ/U3xBoZLqWpQGQK+9HrQsJC8Qgma9bDWbwUmZWz
-YoCSk0lPlf5x6Hw97iGZeqo=
+AERpBWzQENqQ92JfioCTOfDub8UY30dA0LRzitZof5mS5DS979fIjNkJsSQGhquf
+WBrTOHObgPObqYzb7w2UVJFFBEKbmDz8OVOFNh0GWcUeUHwe4Oyt2ESYE6JrvBA5
+Pj5bOjDeKqAIBSHN0VdQBcKEw+gNaVl2PTKqmoINWcYajvoIPBgIsovyOQUCDq98
+KH4WRNiy4DIZ18VUTOmH4B8wc2or75+dXjGmAjmdW+HFttHNlbruXDqXWEnvJs/m
+63JHW270zDscCMcuifaR75TjM4N8m9gQAdesD0zGAccNhEi9p+hNCUCosvMKIXF0
+D6vKI6qZgG0MQnMUADEeZ1E=
-----END CERTIFICATE-----
Certificate:
@@ -197,30 +197,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:ce:b8:01:ca:69:e8:5c:e1:16:2a:54:88:85:15:
- 66:e9:09:2e:04:cf:e8:7f:98:b0:63:1a:39:b9:25:
- 0d:dd:d8:81:f6:e3:d3:3b:98:39:70:09:eb:ed:63:
- 35:91:6a:bf:c4:4e:38:fa:04:a7:1c:bd:32:92:3b:
- 5b:2b:29:f3:94:bc:b2:e6:69:7c:32:57:40:36:1b:
- 6a:1f:9d:12:10:96:db:75:2b:77:bb:50:95:0e:03:
- 65:d7:28:85:12:c8:54:89:38:be:2c:83:81:59:31:
- c7:36:d8:d8:89:28:f3:87:7d:ab:b8:24:c0:d9:43:
- a8:c8:0d:18:fa:98:4c:32:90:73:4c:86:ec:b1:c1:
- 52:1f:af:03:73:84:7c:80:ee:72:56:4e:49:91:0e:
- 1d:16:bc:ad:39:5a:dd:52:96:cb:87:09:e0:15:6a:
- a4:ac:24:5c:c0:93:13:4b:09:1e:b7:bd:a6:0b:0a:
- 94:96:5d:b5:7f:3a:ea:25:cd:c3:c5:7a:49:6a:89:
- 42:db:e6:b5:71:fc:46:45:19:d2:33:d8:e4:95:a4:
- 53:12:fd:09:f1:94:d8:24:28:d3:cc:ec:21:bd:cb:
- 46:1b:24:d9:5a:70:86:1d:cb:7f:6c:be:24:7c:e4:
- 37:72:3e:4f:c5:3e:01:68:d8:3b:ae:4a:ab:b2:90:
- 3c:cd
+ 00:c8:51:b0:c3:f3:b1:5d:6e:4a:c2:41:9e:b7:88:
+ 48:d3:62:d1:49:3a:0b:ab:c9:26:f3:8a:bb:ee:1e:
+ b8:4a:cb:9a:47:3f:8c:87:a2:81:f5:91:05:7c:47:
+ 45:d6:5f:a1:7d:e7:dd:cd:33:eb:4e:90:65:be:31:
+ d7:2d:98:03:45:48:03:03:72:8f:0f:43:3d:3a:ad:
+ cf:bc:f5:f5:bb:7d:1d:94:1d:d4:2c:b6:3b:4a:68:
+ 9e:30:54:c2:c1:69:10:f8:7c:d5:73:ae:2f:22:65:
+ 94:5c:17:1e:41:eb:5a:10:80:6c:eb:04:1d:09:0e:
+ 79:51:71:ce:e7:4f:90:23:4f:84:b5:4e:97:70:79:
+ eb:28:47:0a:8c:b8:43:a6:f5:df:4d:fd:44:46:18:
+ 06:97:6c:52:65:4a:89:25:af:73:6e:43:6a:93:b0:
+ ec:29:97:63:a4:36:95:db:71:b6:61:c3:25:0d:3f:
+ 53:2f:de:d0:b4:16:c2:b6:70:3a:34:53:02:3d:50:
+ eb:32:4a:22:62:3c:9a:74:da:b2:60:af:37:41:4c:
+ c1:df:90:74:5a:ae:5d:a4:48:dd:1b:86:06:0f:cb:
+ 3e:e5:4d:ec:62:86:04:1a:cb:0f:2a:04:a0:45:d5:
+ c1:79:9e:07:df:5d:2d:c3:0c:c4:57:0a:be:7e:41:
+ 43:3d
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 81:56:F3:D5:96:CB:97:DE:87:18:26:E0:E7:E9:59:9E:58:FC:8B:76
+ D4:FF:80:DD:86:D2:53:18:54:65:B3:62:9A:07:67:BB:21:7D:19:77
X509v3 Authority Key Identifier:
- keyid:81:56:F3:D5:96:CB:97:DE:87:18:26:E0:E7:E9:59:9E:58:FC:8B:76
+ keyid:D4:FF:80:DD:86:D2:53:18:54:65:B3:62:9A:07:67:BB:21:7D:19:77
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -235,47 +235,58 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 49:ab:00:40:12:3b:b6:18:a4:f7:c0:e3:94:db:49:b3:45:02:
- 45:ac:38:50:2c:4f:b9:a3:31:4f:99:e5:1a:3d:a7:76:23:1f:
- 47:83:c4:ea:11:1e:98:f4:a5:d2:d3:76:d1:e7:47:23:09:5f:
- e6:de:ef:d3:9e:aa:fa:42:4f:2e:14:2e:78:ee:0f:3f:ac:53:
- 1c:d5:7f:b2:ec:4e:34:bd:c6:10:f4:be:fa:31:e4:a3:67:7e:
- 3e:31:e7:55:ad:17:8c:b3:72:e0:19:5e:77:59:06:bb:56:8e:
- 81:ec:c8:b5:c1:95:d6:6c:53:9c:86:a0:19:72:1d:47:ea:be:
- ad:bc:4d:cd:26:f8:87:75:ff:08:1d:9a:d5:f8:7c:ae:3f:57:
- 97:3a:54:aa:90:5a:b5:93:97:3f:47:be:34:2d:14:bf:7d:fd:
- be:67:88:22:7e:b7:b5:3a:a0:3a:b0:d2:0f:9d:28:1e:fb:1a:
- c0:11:ed:ba:a6:4e:c5:6f:2a:4b:90:84:26:1d:2b:f0:14:40:
- 7a:55:22:c7:7d:39:ee:42:30:7f:b5:4a:0b:d5:1b:12:42:36:
- 62:86:b2:02:68:24:8a:c3:a6:7e:18:b1:15:5d:d4:f0:62:2c:
- cf:09:0d:7d:8f:80:a5:13:8d:9a:53:87:70:f0:94:b1:62:71:
- e3:b9:b0:d1
------BEGIN TRUSTED_CERTIFICATE-----
+ 46:ee:68:7d:1f:94:16:70:57:11:6b:6b:18:96:45:c3:d7:17:
+ 50:9b:f1:e6:b1:bf:ad:97:3f:ca:3e:75:37:4e:c6:b6:d3:68:
+ 57:f5:59:a6:44:b4:3f:e5:fe:a3:05:65:02:f5:7c:dc:da:8e:
+ 1f:2d:fb:9c:23:f0:c0:a6:fc:f5:f3:a9:80:f9:eb:64:f0:8b:
+ 2a:f1:f5:68:8d:8c:c2:37:c4:8e:d5:bb:5b:e6:fb:ec:06:f9:
+ 80:28:56:c2:de:9c:16:78:3f:a8:16:15:e9:26:72:8f:45:c3:
+ e7:d4:78:84:3c:b4:a0:72:5e:5d:09:d8:d1:7f:66:ca:74:d6:
+ 26:c0:72:c0:2a:89:fa:b4:5f:fe:92:4f:01:97:0e:81:88:01:
+ 6b:2e:ed:af:36:30:c7:62:fd:42:63:10:3f:c4:ad:eb:ee:c5:
+ fd:bc:57:08:0f:a3:0c:e5:8c:de:ab:05:b5:b4:e9:c9:d1:c8:
+ 66:e2:ea:4a:b0:33:e5:a4:47:22:67:7c:70:e9:02:e0:22:75:
+ 35:4a:39:0e:2c:27:e5:29:d6:d2:f5:39:c9:03:39:7a:35:f5:
+ ff:1d:88:8d:e1:be:6b:6b:c7:4c:0c:6d:02:d4:33:7a:f5:ea:
+ 29:55:a9:79:94:bc:a3:01:64:4a:99:99:fc:c6:e5:38:a2:8f:
+ 18:cc:e7:1f
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM64Acpp6FzhFipUiIUV
-ZukJLgTP6H+YsGMaObklDd3Ygfbj0zuYOXAJ6+1jNZFqv8ROOPoEpxy9MpI7Wysp
-85S8suZpfDJXQDYbah+dEhCW23Urd7tQlQ4DZdcohRLIVIk4viyDgVkxxzbY2Iko
-84d9q7gkwNlDqMgNGPqYTDKQc0yG7LHBUh+vA3OEfIDuclZOSZEOHRa8rTla3VKW
-y4cJ4BVqpKwkXMCTE0sJHre9pgsKlJZdtX866iXNw8V6SWqJQtvmtXH8RkUZ0jPY
-5JWkUxL9CfGU2CQo08zsIb3LRhsk2Vpwhh3Lf2y+JHzkN3I+T8U+AWjYO65Kq7KQ
-PM0CAwEAAaOByzCByDAdBgNVHQ4EFgQUgVbz1ZbLl96HGCbg5+lZnlj8i3YwHwYD
-VR0jBBgwFoAUgVbz1ZbLl96HGCbg5+lZnlj8i3YwNwYIKwYBBQUHAQEEKzApMCcG
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMhRsMPzsV1uSsJBnreI
+SNNi0Uk6C6vJJvOKu+4euErLmkc/jIeigfWRBXxHRdZfoX3n3c0z606QZb4x1y2Y
+A0VIAwNyjw9DPTqtz7z19bt9HZQd1Cy2O0ponjBUwsFpEPh81XOuLyJllFwXHkHr
+WhCAbOsEHQkOeVFxzudPkCNPhLVOl3B56yhHCoy4Q6b13039REYYBpdsUmVKiSWv
+c25DapOw7CmXY6Q2ldtxtmHDJQ0/Uy/e0LQWwrZwOjRTAj1Q6zJKImI8mnTasmCv
+N0FMwd+QdFquXaRI3RuGBg/LPuVN7GKGBBrLDyoEoEXVwXmeB99dLcMMxFcKvn5B
+Qz0CAwEAAaOByzCByDAdBgNVHQ4EFgQU1P+A3YbSUxhUZbNimgdnuyF9GXcwHwYD
+VR0jBBgwFoAU1P+A3YbSUxhUZbNimgdnuyF9GXcwNwYIKwYBBQUHAQEEKzApMCcG
CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBJqwBAEju2
-GKT3wOOU20mzRQJFrDhQLE+5ozFPmeUaPad2Ix9Hg8TqER6Y9KXS03bR50cjCV/m
-3u/Tnqr6Qk8uFC547g8/rFMc1X+y7E40vcYQ9L76MeSjZ34+MedVrReMs3LgGV53
-WQa7Vo6B7Mi1wZXWbFOchqAZch1H6r6tvE3NJviHdf8IHZrV+HyuP1eXOlSqkFq1
-k5c/R740LRS/ff2+Z4gifre1OqA6sNIPnSge+xrAEe26pk7FbypLkIQmHSvwFEB6
-VSLHfTnuQjB/tUoL1RsSQjZihrICaCSKw6Z+GLEVXdTwYizPCQ19j4ClE42aU4dw
-8JSxYnHjubDR
------END TRUSTED_CERTIFICATE-----
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBG7mh9H5QW
+cFcRa2sYlkXD1xdQm/Hmsb+tlz/KPnU3Tsa202hX9VmmRLQ/5f6jBWUC9Xzc2o4f
+LfucI/DApvz186mA+etk8Isq8fVojYzCN8SO1btb5vvsBvmAKFbC3pwWeD+oFhXp
+JnKPRcPn1HiEPLSgcl5dCdjRf2bKdNYmwHLAKon6tF/+kk8Blw6BiAFrLu2vNjDH
+Yv1CYxA/xK3r7sX9vFcID6MM5YzeqwW1tOnJ0chm4upKsDPlpEciZ3xw6QLgInU1
+SjkOLCflKdbS9TnJAzl6NfX/HYiN4b5ra8dMDG0C1DN69eopVal5lLyjAWRKmZn8
+xuU4oo8YzOcf
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+150302120000Z
-----BEGIN TIME-----
MTUwMzAyMTIwMDAwWg==
-----END TIME-----
+FAIL
-----BEGIN VERIFY_RESULT-----
RkFJTA==
-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 1
+ [Error] Signature verification failed
+ [Error] VerifySignedData failed
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMQogICAgICBbRXJyb3JdIFNpZ25hdHVyZSB2ZXJpZmljYXRpb24gZmFpbGVkCiAgICAgIFtFcnJvcl0gVmVyaWZ5U2lnbmVkRGF0YSBmYWlsZWQK
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/unconstrained-non-self-signed-root.pem b/chromium/net/data/verify_certificate_chain_unittest/unconstrained-non-self-signed-root.pem
new file mode 100644
index 00000000000..e6fccf50051
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/unconstrained-non-self-signed-root.pem
@@ -0,0 +1,283 @@
+[Created by: generate-unconstrained-non-self-signed-root.py]
+
+Certificate chain with 1 intermediate and a non-self-signed trust anchor.
+Verification should succeed, it doesn't matter that the root was not
+self-signed if it is designated as the trust anchor.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:e2:dd:d4:9d:10:ff:0e:87:2d:ba:eb:b5:34:02:
+ 80:b9:83:16:1c:74:27:2b:f1:71:fe:5a:15:ad:26:
+ 7c:80:a6:06:a3:5c:81:30:5f:63:4b:7b:41:c4:2f:
+ ad:6b:31:21:5f:23:1e:a3:6b:41:36:88:6e:cc:97:
+ 5d:ad:67:8e:c5:1c:8f:e4:d0:e5:2b:02:da:e6:7d:
+ 65:6b:a8:fd:90:78:aa:0a:85:31:7c:4e:92:0e:af:
+ 45:00:bb:48:20:22:0e:24:d4:a3:2a:fd:d7:3f:05:
+ 21:70:18:1e:a0:7b:24:25:d9:e5:63:20:dd:59:73:
+ 27:24:9c:a4:4e:8f:93:5d:3c:27:b2:93:7d:1d:15:
+ 09:28:59:f3:70:55:8b:7f:f8:5d:69:0e:3a:0c:a4:
+ 54:7c:32:d4:0e:d4:0b:58:c1:12:74:8a:b6:38:b0:
+ 1d:0e:b2:8e:18:29:ae:8f:75:7b:f3:48:c5:2e:aa:
+ af:e4:0a:a0:fd:c8:8e:fb:a6:17:28:21:36:2e:5d:
+ 20:b4:21:83:a2:6d:7a:ec:7a:14:24:eb:99:90:0e:
+ a0:af:4f:8d:f9:11:36:01:3a:8f:18:4e:15:d4:fe:
+ 12:65:f4:af:11:00:f0:4f:86:11:f3:7c:f6:5d:7b:
+ 28:5c:4f:b1:49:68:3b:de:17:2d:6a:5a:09:5e:1d:
+ 8d:29
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ CF:A5:99:53:C2:5B:C6:BD:10:84:1E:39:95:94:A2:01:79:D4:DA:DD
+ X509v3 Authority Key Identifier:
+ keyid:A3:6A:AF:46:74:A6:CD:26:44:76:D1:81:2A:03:CE:B7:51:58:33:29
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 1c:9c:e2:fa:bd:20:4e:a4:91:63:8d:46:7e:10:1c:d1:ce:5a:
+ c0:dc:cb:8f:c9:fa:54:69:3d:e8:4b:45:a8:34:3d:fb:1b:fe:
+ 8a:08:ce:1c:d3:37:cd:d3:c6:76:41:f4:88:9d:4a:cc:72:45:
+ 00:bf:5f:11:02:49:a5:e7:f4:69:17:ea:ac:8c:9d:75:cb:2e:
+ 35:c7:77:2a:b5:ee:13:aa:ad:84:48:24:77:7d:8b:0b:98:22:
+ 7b:2e:36:2f:41:de:ec:4c:37:96:b2:5d:ce:f1:bc:d9:62:ec:
+ 5c:07:1c:10:8d:65:1a:09:74:a4:f9:d5:5e:c1:06:f7:7c:b2:
+ ae:86:74:04:8f:43:b5:7f:de:9e:9c:10:5e:78:5b:a4:05:de:
+ d8:9a:33:8d:62:23:a9:3c:e8:6a:ad:5d:d9:f1:5b:9f:34:d8:
+ 4a:56:c3:76:1d:9e:d8:05:95:a8:65:00:7a:ad:bd:3d:18:94:
+ f8:07:50:cc:11:39:05:e1:13:a0:9c:8d:17:41:79:76:77:85:
+ b7:6a:c3:bd:db:ee:fe:7e:46:1b:08:e0:05:e4:c5:78:77:f2:
+ 49:b1:02:2c:df:d0:f5:ce:76:f6:63:14:65:f8:df:22:2c:fc:
+ fa:9c:2b:91:32:39:92:8b:31:a7:cf:2a:23:e1:43:ea:fd:ff:
+ f2:d7:b1:f7
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDi3dSd
+EP8Ohy2667U0AoC5gxYcdCcr8XH+WhWtJnyApgajXIEwX2NLe0HEL61rMSFfIx6j
+a0E2iG7Ml12tZ47FHI/k0OUrAtrmfWVrqP2QeKoKhTF8TpIOr0UAu0ggIg4k1KMq
+/dc/BSFwGB6geyQl2eVjIN1ZcycknKROj5NdPCeyk30dFQkoWfNwVYt/+F1pDjoM
+pFR8MtQO1AtYwRJ0irY4sB0Oso4YKa6PdXvzSMUuqq/kCqD9yI77phcoITYuXSC0
+IYOibXrsehQk65mQDqCvT435ETYBOo8YThXU/hJl9K8RAPBPhhHzfPZdeyhcT7FJ
+aDveFy1qWgleHY0pAgMBAAGjgekwgeYwHQYDVR0OBBYEFM+lmVPCW8a9EIQeOZWU
+ogF51NrdMB8GA1UdIwQYMBaAFKNqr0Z0ps0mRHbRgSoDzrdRWDMpMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAHJzi+r0gTqSRY41GfhAc
+0c5awNzLj8n6VGk96EtFqDQ9+xv+igjOHNM3zdPGdkH0iJ1KzHJFAL9fEQJJpef0
+aRfqrIyddcsuNcd3KrXuE6qthEgkd32LC5giey42L0He7Ew3lrJdzvG82WLsXAcc
+EI1lGgl0pPnVXsEG93yyroZ0BI9DtX/enpwQXnhbpAXe2JozjWIjqTzoaq1d2fFb
+nzTYSlbDdh2e2AWVqGUAeq29PRiU+AdQzBE5BeEToJyNF0F5dneFt2rDvdvu/n5G
+GwjgBeTFeHfySbECLN/Q9c529mMUZfjfIiz8+pwrkTI5kosxp88qI+FD6v3/8tex
+9w==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:cc:28:1f:e1:1a:a3:da:34:65:45:b7:bb:c1:3b:
+ c8:3b:92:22:e1:fb:0a:82:86:f8:0c:41:c4:8b:33:
+ cd:b7:17:55:25:9c:b6:09:98:cb:ed:6d:81:99:88:
+ 76:c7:ba:11:ec:af:61:b6:73:cf:7c:5a:5c:5f:08:
+ 2e:e4:6f:d8:74:b0:8f:11:8f:6d:56:cd:03:2e:70:
+ f7:59:59:c9:a7:0c:aa:06:d2:f3:a2:99:a1:1a:a2:
+ 56:b8:88:17:13:d5:de:ee:e8:f8:b5:82:23:15:62:
+ 18:c9:68:02:70:3d:d2:b4:90:4b:28:87:31:ad:b7:
+ 4a:9c:07:b5:ea:52:fd:66:dd:15:64:d7:88:25:e1:
+ 92:0b:77:86:af:73:d8:3b:34:aa:02:bf:8d:a5:06:
+ 50:55:2d:55:bc:bb:ca:01:1b:c3:5d:8d:62:35:b2:
+ 64:cd:4b:70:61:cc:cd:85:6f:50:4a:a2:41:d4:5a:
+ a5:30:aa:32:3e:50:02:67:aa:99:ee:24:c7:7b:f8:
+ fd:54:23:3a:4a:b7:67:67:2d:f7:30:4f:b4:d0:28:
+ a7:f9:64:5b:d8:d9:20:c2:a9:75:ed:0b:ff:b6:f1:
+ 75:bc:3b:be:58:da:f6:93:6c:4d:ba:15:cd:ce:4c:
+ de:8f:22:89:d2:ac:15:6d:60:da:b3:8b:5a:ea:e6:
+ ba:75
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ A3:6A:AF:46:74:A6:CD:26:44:76:D1:81:2A:03:CE:B7:51:58:33:29
+ X509v3 Authority Key Identifier:
+ keyid:1E:88:21:E6:C7:6E:DC:76:90:45:43:56:DD:DA:B3:5F:50:3D:CA:BB
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 76:a9:bf:ab:a6:23:d0:73:52:0f:ac:fb:15:27:2a:ac:cb:2a:
+ 99:80:f2:d7:29:ca:e7:5b:68:72:53:df:ea:c7:fb:f6:cb:c4:
+ 56:af:e1:95:ec:d7:19:b1:94:42:19:d3:71:6f:8b:19:08:46:
+ 0b:ac:05:e3:b2:cb:81:d5:78:37:92:0b:77:75:73:b0:78:0b:
+ 2f:b0:ae:a9:39:80:fa:f1:26:62:28:73:18:c9:33:f8:db:1b:
+ 90:20:54:a8:18:fd:50:4f:63:3c:4f:a7:6e:aa:11:7c:07:f4:
+ 7c:ad:84:fd:a0:f2:d8:63:84:be:c9:ed:b6:c1:2d:2e:23:8f:
+ 7e:5f:e3:63:46:89:1f:56:a4:ea:e4:af:85:62:77:29:d6:ce:
+ 3b:27:69:7b:2f:be:ef:ec:56:59:a8:ea:cf:b9:a0:1d:07:43:
+ 01:84:0e:37:fd:6b:95:39:7e:be:57:9d:33:89:ed:5d:5d:6a:
+ f8:32:3d:59:1b:9a:0c:1c:46:70:80:57:ba:30:6d:a6:b0:70:
+ de:aa:9a:33:bf:5b:ae:33:f3:ee:4d:92:b9:23:22:99:f4:81:
+ 08:7f:ef:4f:8b:37:ae:27:4c:9b:6d:b5:ac:62:8d:7d:b2:7e:
+ 2b:89:dc:eb:5d:14:c9:f6:64:b0:cd:5b:4b:38:f1:b3:58:b5:
+ 07:5d:1a:d9
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzCgf4Rqj
+2jRlRbe7wTvIO5Ii4fsKgob4DEHEizPNtxdVJZy2CZjL7W2BmYh2x7oR7K9htnPP
+fFpcXwgu5G/YdLCPEY9tVs0DLnD3WVnJpwyqBtLzopmhGqJWuIgXE9Xe7uj4tYIj
+FWIYyWgCcD3StJBLKIcxrbdKnAe16lL9Zt0VZNeIJeGSC3eGr3PYOzSqAr+NpQZQ
+VS1VvLvKARvDXY1iNbJkzUtwYczNhW9QSqJB1FqlMKoyPlACZ6qZ7iTHe/j9VCM6
+SrdnZy33ME+00Cin+WRb2Nkgwql17Qv/tvF1vDu+WNr2k2xNuhXNzkzejyKJ0qwV
+bWDas4ta6ua6dQIDAQABo4HLMIHIMB0GA1UdDgQWBBSjaq9GdKbNJkR20YEqA863
+UVgzKTAfBgNVHSMEGDAWgBQeiCHmx27cdpBFQ1bd2rNfUD3KuzA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AHapv6umI9BzUg+s+xUnKqzLKpmA8tcpyudbaHJT3+rH+/bLxFav4ZXs1xmxlEIZ
+03FvixkIRgusBeOyy4HVeDeSC3d1c7B4Cy+wrqk5gPrxJmIocxjJM/jbG5AgVKgY
+/VBPYzxPp26qEXwH9HythP2g8thjhL7J7bbBLS4jj35f42NGiR9WpOrkr4VidynW
+zjsnaXsvvu/sVlmo6s+5oB0HQwGEDjf9a5U5fr5XnTOJ7V1davgyPVkbmgwcRnCA
+V7owbaawcN6qmjO/W64z8+5NkrkjIpn0gQh/70+LN64nTJtttaxijX2yfiuJ3Otd
+FMn2ZLDNW0s48bNYtQddGtk=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=UberRoot
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d2:ee:04:1f:69:cf:1f:13:bf:0c:7f:3b:65:1c:
+ e6:e3:c6:3d:be:86:27:a6:1a:98:44:9e:76:a7:c7:
+ d0:fd:bc:0e:92:3e:f8:a1:6e:6a:ac:19:80:26:f8:
+ 96:2b:27:fb:c1:4f:10:24:6e:9f:53:0f:6e:52:0f:
+ 59:d1:af:cb:1f:bf:fa:92:6b:d8:bb:9d:5b:48:66:
+ 4f:8c:5b:72:98:f1:eb:62:59:23:d6:12:dc:de:2b:
+ e2:78:61:23:2f:21:e5:f5:0b:5c:98:69:f5:15:73:
+ 3d:a6:9c:f5:c2:77:3b:a0:70:af:48:39:5c:21:ff:
+ e2:19:34:82:a0:c4:77:6e:45:11:c6:0d:f3:74:a0:
+ 53:bc:d6:37:6e:17:62:83:43:0c:c8:6e:6a:a3:8f:
+ 83:b4:85:4f:8b:ce:12:55:f5:f1:80:7b:b3:6c:a1:
+ 3a:20:0a:7a:9d:7d:ef:35:e7:15:b4:7a:90:04:54:
+ 68:2d:7a:2d:72:88:99:e7:03:09:55:42:13:9c:55:
+ e7:f4:3f:3c:66:ab:7c:3d:8b:50:c1:d2:2c:eb:d4:
+ b8:f4:13:d1:a7:92:b2:97:29:76:94:a6:49:57:d2:
+ 55:17:86:f1:20:7c:a9:a5:7d:ba:48:cc:87:7e:b4:
+ 14:27:48:d1:72:c5:18:c2:f8:80:4c:ca:1b:92:94:
+ 5f:f3
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 1E:88:21:E6:C7:6E:DC:76:90:45:43:56:DD:DA:B3:5F:50:3D:CA:BB
+ X509v3 Authority Key Identifier:
+ keyid:EA:25:A5:9F:40:47:93:DB:8C:A0:6D:18:4A:47:09:4E:05:93:5F:34
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/UberRoot.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/UberRoot.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 6f:ff:d2:4d:45:07:b2:52:cf:4b:79:b4:37:b8:08:47:37:0e:
+ 6d:db:82:92:14:fe:68:31:c1:cc:4a:6f:55:98:8d:8a:47:32:
+ d5:e4:08:16:eb:68:d2:44:06:55:ec:b7:8b:24:b5:91:c4:a8:
+ 8d:5b:f5:b2:a3:55:a8:01:a7:ae:bc:a9:71:88:53:c9:81:93:
+ d8:73:42:4a:eb:fd:07:5a:ee:89:1f:2f:40:c7:45:24:46:1c:
+ 70:58:12:48:e0:7c:8e:aa:fc:9e:4b:92:83:a0:2f:9a:7e:af:
+ 18:67:38:18:16:d8:4f:69:11:2e:ee:11:30:a6:4f:41:65:a1:
+ 1b:a1:0f:04:bd:ec:7a:e4:a5:d1:a3:fe:3c:6f:9a:f1:cd:85:
+ f3:f5:2d:05:20:08:ff:61:80:14:47:95:b9:00:39:df:dd:61:
+ 55:2b:12:99:60:2a:d1:f4:54:c8:57:77:b3:0d:32:c3:b0:e3:
+ 6b:fd:b4:12:91:bc:e7:a1:55:e3:9c:52:a5:7a:e5:a4:66:d0:
+ f9:a8:23:54:06:fd:73:53:0e:1a:3d:80:0b:6b:71:a0:da:e5:
+ c9:fc:6f:77:ca:87:c0:3b:24:0b:af:24:46:e6:5a:78:05:1b:
+ 4f:c6:c2:bc:e3:b0:6f:6e:5a:7e:c3:d0:a5:7c:6d:48:66:bc:
+ 69:7b:97:d2
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDcTCCAlmgAwIBAgIBAjANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhVYmVy
+Um9vdDAeFw0xNTAxMDExMjAwMDBaFw0xNjAxMDExMjAwMDBaMA8xDTALBgNVBAMM
+BFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDS7gQfac8fE78M
+fztlHObjxj2+hiemGphEnnanx9D9vA6SPvihbmqsGYAm+JYrJ/vBTxAkbp9TD25S
+D1nRr8sfv/qSa9i7nVtIZk+MW3KY8etiWSPWEtzeK+J4YSMvIeX1C1yYafUVcz2m
+nPXCdzugcK9IOVwh/+IZNIKgxHduRRHGDfN0oFO81jduF2KDQwzIbmqjj4O0hU+L
+zhJV9fGAe7NsoTogCnqdfe815xW0epAEVGgtei1yiJnnAwlVQhOcVef0Pzxmq3w9
+i1DB0izr1Lj0E9GnkrKXKXaUpklX0lUXhvEgfKmlfbpIzId+tBQnSNFyxRjC+IBM
+yhuSlF/zAgMBAAGjgdMwgdAwHQYDVR0OBBYEFB6IIebHbtx2kEVDVt3as19QPcq7
+MB8GA1UdIwQYMBaAFOolpZ9AR5PbjKBtGEpHCU4Fk180MDsGCCsGAQUFBwEBBC8w
+LTArBggrBgEFBQcwAoYfaHR0cDovL3VybC1mb3ItYWlhL1ViZXJSb290LmNlcjAw
+BgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vdXJsLWZvci1jcmwvVWJlclJvb3QuY3Js
+MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA
+A4IBAQBv/9JNRQeyUs9LebQ3uAhHNw5t24KSFP5oMcHMSm9VmI2KRzLV5AgW62jS
+RAZV7LeLJLWRxKiNW/Wyo1WoAaeuvKlxiFPJgZPYc0JK6/0HWu6JHy9Ax0UkRhxw
+WBJI4HyOqvyeS5KDoC+afq8YZzgYFthPaREu7hEwpk9BZaEboQ8Evex65KXRo/48
+b5rxzYXz9S0FIAj/YYAUR5W5ADnf3WFVKxKZYCrR9FTIV3ezDTLDsONr/bQSkbzn
+oVXjnFKleuWkZtD5qCNUBv1zUw4aPYALa3Gg2uXJ/G93yofAOyQLryRG5lp4BRtP
+xsK847Bvblp+w9ClfG1IZrxpe5fS
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/unconstrained-root-basic-constraints-ca-false.pem b/chromium/net/data/verify_certificate_chain_unittest/unconstrained-root-basic-constraints-ca-false.pem
new file mode 100644
index 00000000000..65bdb9c8f26
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/unconstrained-root-basic-constraints-ca-false.pem
@@ -0,0 +1,284 @@
+[Created by: generate-unconstrained-root-basic-constraints-ca-false.py]
+
+Certificate chain with 1 intermediate and a trust anchor. The trust anchor
+has a basic constraints extension that indicates it is NOT a CA. Verification
+is expected to succeed as constraints on the root certificate are not applied
+to the trust anchor.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c8:04:f4:49:c8:99:48:ae:4b:8a:66:a6:19:29:
+ b8:4f:52:af:29:88:34:6c:07:db:a9:a7:99:7e:09:
+ bb:07:7a:7b:35:11:39:a5:4d:f9:54:e3:b7:8e:9c:
+ 66:37:62:bc:5f:2d:f4:1f:ba:b0:fd:4b:0b:a6:59:
+ 0c:94:d6:53:aa:7b:97:fc:bd:7f:72:e6:99:a7:04:
+ a5:b2:02:67:3d:9f:cb:c1:2c:48:f7:a4:a3:d4:30:
+ b6:8b:96:a9:ad:78:9c:1d:19:2a:28:ac:89:46:81:
+ eb:32:f1:11:bc:44:32:f0:3b:70:8d:53:4b:5e:ed:
+ 9b:e2:f8:2d:a5:e0:69:cf:11:6b:0b:3e:33:02:f9:
+ 66:e8:2e:93:15:d9:42:81:04:71:17:10:c8:04:81:
+ cb:11:6b:20:7c:f8:ef:71:8c:04:3a:51:ae:e7:69:
+ 7a:66:3b:fc:52:53:19:97:39:51:38:d3:5c:9b:93:
+ 48:09:e8:5d:18:3a:45:66:70:b1:f2:05:3d:15:ef:
+ fd:8e:c7:b2:37:da:97:15:04:ec:02:f6:9d:40:b2:
+ 22:02:bc:09:68:70:e8:4d:85:7a:c9:dd:d0:9b:85:
+ a8:06:2c:ce:15:e7:53:df:79:c6:ad:57:83:c4:8a:
+ a1:eb:ef:ac:d0:b8:54:93:54:f3:24:91:41:a9:b2:
+ 92:0d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 58:5A:D4:08:69:E1:A6:80:04:B2:43:1E:B5:EA:25:03:CC:A6:5A:EF
+ X509v3 Authority Key Identifier:
+ keyid:24:F8:6B:40:18:23:4E:B7:94:1D:E3:CA:38:B3:BF:9D:67:F2:7E:16
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 8c:66:31:d0:85:64:e5:17:c7:fa:55:f9:9d:b9:1b:b2:07:b6:
+ c4:7a:ca:9b:94:12:46:af:4e:07:5a:60:26:07:e5:a8:c7:c2:
+ e1:8d:e3:cc:79:b4:f0:f5:c5:7f:6f:35:5b:be:94:6a:b0:51:
+ 66:ce:b6:46:69:66:2b:f5:46:92:10:18:2d:28:8d:5b:eb:61:
+ ad:37:2e:03:b0:46:03:e0:b3:2e:28:3f:b6:c7:94:fc:a1:c4:
+ 57:97:23:4c:51:39:d6:66:83:aa:1e:57:37:70:b5:89:c9:33:
+ ad:d4:be:97:95:57:89:3a:32:e3:dc:83:ef:5d:78:f8:fa:e0:
+ 26:12:6e:b2:f4:00:f1:ac:af:e4:be:7c:e7:8e:60:53:b6:e2:
+ e1:99:bb:ba:35:ff:8d:08:52:a1:7d:2d:0b:46:56:4e:6b:9a:
+ 9e:f4:0e:eb:95:a4:95:e7:7b:08:d3:55:3f:95:c8:76:34:12:
+ c3:27:9a:f0:bb:0d:8c:0f:c7:56:b1:2c:c9:34:94:22:b6:c6:
+ a9:df:72:57:88:9e:06:01:e6:52:45:16:e6:aa:1d:ac:93:6e:
+ c0:5c:eb:b4:91:d7:01:8e:27:8c:00:7f:17:0a:f5:84:42:12:
+ d3:54:01:b5:bd:7e:0d:29:24:ee:2a:03:07:76:86:42:10:e1:
+ 5c:ac:32:9c
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIBPRJ
+yJlIrkuKZqYZKbhPUq8piDRsB9upp5l+CbsHens1ETmlTflU47eOnGY3YrxfLfQf
+urD9SwumWQyU1lOqe5f8vX9y5pmnBKWyAmc9n8vBLEj3pKPUMLaLlqmteJwdGSoo
+rIlGgesy8RG8RDLwO3CNU0te7Zvi+C2l4GnPEWsLPjMC+WboLpMV2UKBBHEXEMgE
+gcsRayB8+O9xjAQ6Ua7naXpmO/xSUxmXOVE401ybk0gJ6F0YOkVmcLHyBT0V7/2O
+x7I32pcVBOwC9p1AsiICvAlocOhNhXrJ3dCbhagGLM4V51PfecatV4PEiqHr76zQ
+uFSTVPMkkUGpspINAgMBAAGjgekwgeYwHQYDVR0OBBYEFFha1Ahp4aaABLJDHrXq
+JQPMplrvMB8GA1UdIwQYMBaAFCT4a0AYI063lB3jyjizv51n8n4WMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAjGYx0IVk5RfH+lX5nbkb
+sge2xHrKm5QSRq9OB1pgJgflqMfC4Y3jzHm08PXFf281W76UarBRZs62RmlmK/VG
+khAYLSiNW+thrTcuA7BGA+CzLig/tseU/KHEV5cjTFE51maDqh5XN3C1ickzrdS+
+l5VXiToy49yD7114+PrgJhJusvQA8ayv5L58545gU7bi4Zm7ujX/jQhSoX0tC0ZW
+TmuanvQO65Wkled7CNNVP5XIdjQSwyea8LsNjA/HVrEsyTSUIrbGqd9yV4ieBgHm
+UkUW5qodrJNuwFzrtJHXAY4njAB/Fwr1hEIS01QBtb1+DSkk7ioDB3aGQhDhXKwy
+nA==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b4:44:74:3c:31:93:a2:8c:74:39:b1:50:1d:1c:
+ 86:f8:ac:e7:45:73:11:9a:9c:8e:31:4a:84:81:0b:
+ 6a:4b:38:13:eb:63:47:85:e7:2f:81:98:d2:f9:73:
+ a7:3b:3f:33:6e:21:51:7e:d1:36:4a:84:6f:b5:ce:
+ 26:c5:1c:b6:fd:75:77:e4:8f:73:1a:3f:f9:e5:88:
+ d2:74:a8:6c:6e:50:f0:56:a5:58:ad:5a:69:0f:4a:
+ d1:fd:58:53:0a:e3:86:17:ff:37:48:7a:3b:a7:6d:
+ f5:c2:eb:f5:c7:60:17:d1:36:69:99:34:b8:a3:f7:
+ 4b:a2:02:b1:0e:b9:81:2a:80:e9:da:e4:d8:40:82:
+ a3:e8:da:00:53:8e:89:32:e8:71:61:a0:1b:ee:a2:
+ f2:c7:fc:bb:0c:6b:71:d6:90:dc:a7:dd:bd:6f:97:
+ 5f:5c:d5:bb:1a:d3:6f:d2:6b:30:32:6d:b0:eb:9f:
+ 92:17:6d:b9:7f:e3:20:a0:16:43:6b:a2:4c:7f:37:
+ 4e:26:04:8e:5c:1a:cc:2b:e3:37:8e:90:75:1b:b9:
+ b7:45:e2:41:1f:b0:af:b3:d1:85:56:a2:b0:b1:ad:
+ 73:07:de:64:60:56:c4:8c:9f:48:d8:50:63:f8:c1:
+ 6b:c5:f1:f3:11:9e:5e:1d:56:55:60:12:82:9c:93:
+ 61:91
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 24:F8:6B:40:18:23:4E:B7:94:1D:E3:CA:38:B3:BF:9D:67:F2:7E:16
+ X509v3 Authority Key Identifier:
+ keyid:3E:6C:67:DF:AB:EE:20:0E:C6:98:F6:9A:1E:AD:BE:AF:AD:72:D8:86
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ a2:28:e4:cb:e5:d2:31:bd:7a:6c:60:60:75:59:27:9a:3a:11:
+ 52:17:37:53:82:12:4d:f6:0c:d5:bf:45:51:4d:eb:8e:8a:c7:
+ 01:c3:55:3e:9f:16:48:69:84:f2:e7:ad:7a:a4:32:66:c4:19:
+ 39:1e:7c:31:01:42:59:3c:92:b9:aa:59:a5:b9:40:56:e5:4d:
+ 0f:49:de:79:a9:72:77:95:5b:c3:de:b0:36:84:08:60:ea:21:
+ b9:d5:b4:bc:bf:f7:f0:f7:ea:5f:5f:fe:c8:3e:dc:b0:54:0e:
+ 16:dd:c0:c2:d4:9f:c4:a0:e1:b3:52:0c:ee:43:0e:e7:a0:2f:
+ 5e:25:92:51:6c:e7:a1:70:f8:f1:7e:83:e3:ea:a4:5d:a9:fb:
+ 3a:c0:64:43:06:b5:a5:7e:48:e8:d3:20:52:df:06:4c:15:2e:
+ bb:54:49:7e:26:e5:eb:5b:82:80:8f:27:d3:e0:d0:28:5f:e8:
+ c0:7d:40:e5:e3:81:bf:2d:83:8f:7f:c4:7c:9b:24:f1:e7:1c:
+ 81:90:bf:15:5a:db:4c:e8:09:f8:9b:9a:ba:f4:ad:b0:d7:66:
+ d5:b8:af:15:02:a1:e0:84:12:8c:68:24:9e:47:3c:4d:b8:da:
+ 60:44:a1:fb:1d:d1:4b:b6:3a:22:a4:b9:6c:27:65:24:a6:6e:
+ 57:c6:62:b9
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtER0PDGT
+oox0ObFQHRyG+KznRXMRmpyOMUqEgQtqSzgT62NHhecvgZjS+XOnOz8zbiFRftE2
+SoRvtc4mxRy2/XV35I9zGj/55YjSdKhsblDwVqVYrVppD0rR/VhTCuOGF/83SHo7
+p231wuv1x2AX0TZpmTS4o/dLogKxDrmBKoDp2uTYQIKj6NoAU46JMuhxYaAb7qLy
+x/y7DGtx1pDcp929b5dfXNW7GtNv0mswMm2w65+SF225f+MgoBZDa6JMfzdOJgSO
+XBrMK+M3jpB1G7m3ReJBH7Cvs9GFVqKwsa1zB95kYFbEjJ9I2FBj+MFrxfHzEZ5e
+HVZVYBKCnJNhkQIDAQABo4HLMIHIMB0GA1UdDgQWBBQk+GtAGCNOt5Qd48o4s7+d
+Z/J+FjAfBgNVHSMEGDAWgBQ+bGffq+4gDsaY9poerb6vrXLYhjA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AKIo5Mvl0jG9emxgYHVZJ5o6EVIXN1OCEk32DNW/RVFN646KxwHDVT6fFkhphPLn
+rXqkMmbEGTkefDEBQlk8krmqWaW5QFblTQ9J3nmpcneVW8PesDaECGDqIbnVtLy/
+9/D36l9f/sg+3LBUDhbdwMLUn8Sg4bNSDO5DDuegL14lklFs56Fw+PF+g+PqpF2p
++zrAZEMGtaV+SOjTIFLfBkwVLrtUSX4m5etbgoCPJ9Pg0Chf6MB9QOXjgb8tg49/
+xHybJPHnHIGQvxVa20zoCfibmrr0rbDXZtW4rxUCoeCEEoxoJJ5HPE242mBEofsd
+0Uu2OiKkuWwnZSSmblfGYrk=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:d0:70:df:1f:ab:c3:a1:05:6d:4c:e7:9b:5b:c7:
+ c7:b4:36:f5:e7:c7:00:14:94:c6:8d:6c:a9:3d:0d:
+ bb:44:8b:d7:50:29:90:e5:58:b5:6f:71:47:54:52:
+ 85:46:7a:c6:36:9c:57:39:dc:75:d3:1b:f8:69:db:
+ da:21:11:db:8b:c1:e7:ac:86:7b:20:10:e7:3f:6e:
+ 0b:c8:33:71:00:bb:4c:a9:7b:41:a8:54:4a:c7:48:
+ cb:6a:aa:cd:d9:a3:dd:5d:f9:80:df:c3:6d:4b:55:
+ 4d:7c:c5:d3:de:bc:c1:c9:4e:50:fa:98:70:e0:84:
+ 4b:fc:fc:9b:eb:fa:e3:7c:4b:0a:94:e6:5f:41:0c:
+ 35:e1:d7:2c:54:27:24:22:9e:f7:c6:6d:72:d2:43:
+ 06:52:d4:fb:94:ac:79:51:0b:da:1d:83:bf:a1:bc:
+ 04:a5:a7:4c:a8:03:d0:01:7f:42:43:31:d9:7e:46:
+ 74:2b:46:5a:a4:0d:ff:7a:e0:69:d1:dd:d7:29:0d:
+ b8:12:3d:99:ac:f5:ce:97:d7:3f:2e:15:5c:51:47:
+ 1d:d4:da:f5:ce:a3:12:46:43:74:da:70:bb:a2:83:
+ e3:b8:ac:e1:b0:8c:88:cd:d8:d9:42:fa:e8:57:a3:
+ 5b:d8:4d:72:a8:7f:be:22:8a:d3:cf:1a:75:53:fc:
+ 32:c9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 3E:6C:67:DF:AB:EE:20:0E:C6:98:F6:9A:1E:AD:BE:AF:AD:72:D8:86
+ X509v3 Authority Key Identifier:
+ keyid:3E:6C:67:DF:AB:EE:20:0E:C6:98:F6:9A:1E:AD:BE:AF:AD:72:D8:86
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ Signature Algorithm: sha256WithRSAEncryption
+ 27:dc:b7:a3:09:a6:ab:07:74:62:e6:57:46:5a:75:a7:8d:c7:
+ 77:47:a4:5e:9b:9b:85:69:5c:a7:92:b6:30:de:b6:c5:e5:c2:
+ 57:c2:05:ec:dd:7b:76:8f:20:dc:89:75:b9:6a:6e:d8:5f:4b:
+ b9:85:f1:b1:1e:33:33:18:ff:c6:bc:1d:0a:29:ac:46:c1:77:
+ 36:ae:8f:ae:81:fa:c3:5d:b9:de:4a:4f:8e:fc:b6:ed:c4:93:
+ 1f:87:34:39:ba:c3:76:fa:03:38:c6:57:c4:1d:41:cb:4b:8c:
+ 26:9d:60:b3:e9:0f:5a:7d:22:0f:58:4d:60:72:a4:23:77:bf:
+ 58:b4:f4:8e:dc:8c:42:2e:46:f9:67:0a:b5:b9:a6:60:06:16:
+ 8b:28:e2:e7:95:ff:c8:e2:d9:50:17:88:45:1e:13:20:bd:20:
+ 03:f8:46:17:21:5d:ba:1a:3c:fd:ec:25:cf:04:2e:90:db:b6:
+ 0f:0f:db:d5:ff:5a:8b:fd:4f:85:ab:7e:fc:a7:a3:10:b1:84:
+ 6e:e4:20:11:bf:d4:b1:3c:a3:58:2a:f5:56:45:e2:86:f0:ae:
+ 67:05:d9:b6:57:79:3c:e2:03:26:70:27:fb:e6:0f:96:a7:40:
+ 9c:a6:cb:fa:de:bd:8b:f9:e2:ad:7d:9d:b5:ac:27:bf:83:9b:
+ 10:94:f2:71
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDYjCCAkqgAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANBw3x+rw6EFbUznm1vH
+x7Q29efHABSUxo1sqT0Nu0SL11ApkOVYtW9xR1RShUZ6xjacVzncddMb+Gnb2iER
+24vB56yGeyAQ5z9uC8gzcQC7TKl7QahUSsdIy2qqzdmj3V35gN/DbUtVTXzF0968
+wclOUPqYcOCES/z8m+v643xLCpTmX0EMNeHXLFQnJCKe98ZtctJDBlLU+5SseVEL
+2h2Dv6G8BKWnTKgD0AF/QkMx2X5GdCtGWqQN/3rgadHd1ykNuBI9maz1zpfXPy4V
+XFFHHdTa9c6jEkZDdNpwu6KD47is4bCMiM3Y2UL66FejW9hNcqh/viKK088adVP8
+MskCAwEAAaOByDCBxTAdBgNVHQ4EFgQUPmxn36vuIA7GmPaaHq2+r61y2IYwHwYD
+VR0jBBgwFoAUPmxn36vuIA7GmPaaHq2+r61y2IYwNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQAn3LejCaarB3Ri
+5ldGWnWnjcd3R6Rem5uFaVynkrYw3rbF5cJXwgXs3Xt2jyDciXW5am7YX0u5hfGx
+HjMzGP/GvB0KKaxGwXc2ro+ugfrDXbneSk+O/LbtxJMfhzQ5usN2+gM4xlfEHUHL
+S4wmnWCz6Q9afSIPWE1gcqQjd79YtPSO3IxCLkb5Zwq1uaZgBhaLKOLnlf/I4tlQ
+F4hFHhMgvSAD+EYXIV26Gjz97CXPBC6Q27YPD9vV/1qL/U+Fq378p6MQsYRu5CAR
+v9SxPKNYKvVWReKG8K5nBdm2V3k84gMmcCf75g+Wp0Ccpsv63r2L+eKtfZ21rCe/
+g5sQlPJx
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/unconstrained-root-lacks-basic-constraints.pem b/chromium/net/data/verify_certificate_chain_unittest/unconstrained-root-lacks-basic-constraints.pem
new file mode 100644
index 00000000000..24d08c5b839
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/unconstrained-root-lacks-basic-constraints.pem
@@ -0,0 +1,280 @@
+[Created by: generate-unconstrained-root-lacks-basic-constraints.py]
+
+Certificate chain with 1 intermediate and a trust anchor. The trust anchor
+lacks the basic constraints extension. This is not a problem and verification
+should succeed.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:bc:1b:31:ef:84:8e:64:39:4e:02:f3:81:fc:75:
+ 0b:07:af:5b:57:53:6b:df:27:87:03:1c:3d:ea:b3:
+ 6a:b5:14:e9:98:1d:13:16:fc:51:5b:04:c5:72:81:
+ 3e:26:05:54:9b:19:f8:7e:c0:ee:c8:49:eb:e2:9d:
+ 78:82:c8:e9:c5:af:eb:fc:10:85:e2:5f:e6:6a:8e:
+ 51:19:69:69:10:5e:aa:99:31:64:c4:3d:0f:3e:f0:
+ 5a:2a:cd:dd:b7:27:ff:5a:ee:91:c3:ad:92:9e:da:
+ 91:df:7d:7f:77:f1:79:d8:6e:60:48:ad:57:f1:2d:
+ 6e:67:5b:fe:20:5c:b9:56:a7:70:8d:63:80:5a:99:
+ cf:3d:6e:14:f5:d8:29:b9:25:81:61:c7:bb:be:3b:
+ 08:38:c5:5d:40:aa:e7:15:51:8a:84:d3:78:64:f5:
+ 3b:09:7b:a9:f2:ed:a5:05:ed:3a:67:21:45:f1:78:
+ 78:e2:92:74:20:e0:41:10:f7:ab:9e:0e:fd:22:af:
+ ad:8f:b4:81:cb:d9:28:b1:49:90:05:fa:f7:96:a8:
+ b7:96:3d:5b:87:d9:6b:cc:82:7a:85:26:ba:e6:86:
+ 40:53:44:09:38:27:4d:8a:98:5d:ce:56:a1:93:38:
+ 08:fd:02:92:ef:9b:0c:d5:c0:9d:12:e8:21:08:9d:
+ ba:e1
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ A4:68:89:3F:A2:F7:48:BC:C6:C4:9C:7E:78:B9:E6:06:A7:37:2E:A2
+ X509v3 Authority Key Identifier:
+ keyid:A0:FF:6A:B0:DB:6D:76:3D:1F:D2:A3:83:33:02:BE:32:A2:71:34:85
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 2b:b6:4e:ac:b6:8d:bb:7c:cc:0b:6f:77:9c:54:ed:88:25:34:
+ c7:42:88:7c:35:23:74:c7:e7:7d:86:7d:fd:f0:0b:40:e2:64:
+ 5b:a3:1b:a2:34:77:09:b4:7d:5e:7b:a4:85:7f:23:b5:2f:43:
+ f8:0f:33:6c:86:9c:7a:ee:0d:54:45:fb:1c:57:c8:01:91:60:
+ 27:0b:bb:ac:8c:23:c4:5f:18:42:2e:df:24:cb:12:77:2c:0c:
+ 6c:d1:8f:34:ee:a8:06:e3:8a:fe:34:e6:ca:bc:25:e5:33:a4:
+ 23:df:00:4f:f4:e4:af:d9:7f:08:1a:78:a5:ba:80:81:49:bf:
+ 8f:7c:ee:ee:27:ac:fc:d8:91:69:36:2b:dc:33:ae:d6:ad:47:
+ 8d:5d:4c:c0:a5:a2:61:b8:db:b0:7b:92:79:b5:61:64:78:92:
+ 02:05:68:16:2b:9f:81:66:5a:8e:e6:82:55:5b:83:87:26:e2:
+ da:d0:95:91:06:6d:f9:dc:b6:04:fe:ed:ae:f7:3e:db:a7:38:
+ 31:af:a4:c5:79:f7:d0:3b:b9:2c:79:60:0a:1d:ec:68:8d:3f:
+ 7b:d7:e9:1a:79:de:da:97:42:04:c7:b1:f2:fe:72:68:00:fa:
+ 30:41:0e:1c:26:65:f5:eb:2e:7d:fe:19:05:99:5b:6f:3d:51:
+ 4c:57:c3:cb
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8GzHv
+hI5kOU4C84H8dQsHr1tXU2vfJ4cDHD3qs2q1FOmYHRMW/FFbBMVygT4mBVSbGfh+
+wO7ISevinXiCyOnFr+v8EIXiX+ZqjlEZaWkQXqqZMWTEPQ8+8Foqzd23J/9a7pHD
+rZKe2pHffX938XnYbmBIrVfxLW5nW/4gXLlWp3CNY4Bamc89bhT12Cm5JYFhx7u+
+Owg4xV1AqucVUYqE03hk9TsJe6ny7aUF7TpnIUXxeHjiknQg4EEQ96ueDv0ir62P
+tIHL2SixSZAF+veWqLeWPVuH2WvMgnqFJrrmhkBTRAk4J02KmF3OVqGTOAj9ApLv
+mwzVwJ0S6CEInbrhAgMBAAGjgekwgeYwHQYDVR0OBBYEFKRoiT+i90i8xsScfni5
+5ganNy6iMB8GA1UdIwQYMBaAFKD/arDbbXY9H9KjgzMCvjKicTSFMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAK7ZOrLaNu3zMC293nFTt
+iCU0x0KIfDUjdMfnfYZ9/fALQOJkW6MbojR3CbR9XnukhX8jtS9D+A8zbIaceu4N
+VEX7HFfIAZFgJwu7rIwjxF8YQi7fJMsSdywMbNGPNO6oBuOK/jTmyrwl5TOkI98A
+T/Tkr9l/CBp4pbqAgUm/j3zu7ies/NiRaTYr3DOu1q1HjV1MwKWiYbjbsHuSebVh
+ZHiSAgVoFiufgWZajuaCVVuDhybi2tCVkQZt+dy2BP7trvc+26c4Ma+kxXn30Du5
+LHlgCh3saI0/e9fpGnne2pdCBMex8v5yaAD6MEEOHCZl9esuff4ZBZlbbz1RTFfD
+yw==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:bd:4b:25:64:f8:46:3e:e8:fc:85:3a:e2:4a:dc:
+ 9a:58:70:6f:65:27:93:14:2f:5d:08:b3:ba:dc:2d:
+ b0:8c:0e:98:f6:21:26:8d:ff:bb:59:2d:db:72:bc:
+ 07:38:8f:11:34:cc:e8:07:0f:07:ed:82:1e:60:be:
+ d8:67:17:98:cb:81:55:40:5e:d9:a0:bd:a5:98:88:
+ 71:17:8e:65:70:3e:8a:9f:b3:23:56:9f:98:a8:db:
+ 64:6a:1b:e1:1a:2c:b1:94:6d:d3:4b:28:fd:e4:1c:
+ d3:7d:93:91:53:5c:3d:89:67:13:04:58:21:64:c9:
+ 89:c7:12:58:91:dc:2f:0f:56:ec:a7:00:4f:60:89:
+ 0a:b9:af:52:8e:20:bc:b3:16:e8:a6:06:ca:3b:07:
+ a5:76:59:7e:4b:17:33:b2:db:8e:d8:31:29:d8:ba:
+ 08:06:51:e1:a1:43:6d:cd:2d:61:e1:03:54:62:1d:
+ 43:28:b9:48:b6:3b:bb:24:47:d0:56:df:ce:ac:d3:
+ ac:a9:0c:13:a5:c8:76:a3:ee:67:0c:79:35:92:5d:
+ 49:8f:a5:4f:8f:ae:79:09:6c:11:15:3f:3a:01:a3:
+ 4d:54:df:93:50:b5:fe:ed:be:53:87:be:b7:65:55:
+ 96:4c:7c:5b:a0:e3:1e:18:e8:9e:8c:95:d1:4a:ea:
+ 5a:4f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ A0:FF:6A:B0:DB:6D:76:3D:1F:D2:A3:83:33:02:BE:32:A2:71:34:85
+ X509v3 Authority Key Identifier:
+ keyid:0A:E1:71:15:DF:ED:0D:98:EB:75:A8:37:BC:F1:EE:E3:65:79:AB:C2
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 13:0e:3c:0e:69:c2:bf:7d:aa:a4:8f:47:a6:90:69:0e:d8:b7:
+ 50:2a:c7:95:78:1d:7f:71:41:51:8d:a4:a9:cf:f2:d2:c6:c0:
+ 8f:dd:56:c4:53:94:34:3f:07:e3:b0:4c:71:55:5b:14:a2:de:
+ 8f:1e:3b:15:73:e2:9a:49:df:c8:0e:04:dc:76:76:61:0d:c5:
+ 29:35:12:c4:71:d3:2d:6d:ac:b6:62:53:75:57:44:cf:0b:d2:
+ 1d:66:0a:be:01:b5:a6:58:a0:42:f5:ce:62:3c:d8:21:fd:c6:
+ c7:27:66:b1:2f:d4:04:c2:29:44:32:3a:3b:b2:3c:08:a5:66:
+ 3e:4c:27:c2:36:71:c5:31:05:e7:e9:f8:47:b4:81:33:57:7d:
+ c2:ce:ac:de:c4:15:11:1a:f2:c9:59:72:cd:a4:a8:54:41:ef:
+ d5:d5:67:cf:6e:e3:a0:07:62:ba:83:f7:46:fa:4b:10:7c:91:
+ 9f:ff:aa:1a:c9:46:f9:26:14:c4:01:58:9d:35:75:f0:78:0e:
+ 75:4e:7f:03:e8:83:1b:87:82:99:e0:52:b3:9f:34:a7:26:34:
+ 76:9c:e7:3e:69:d5:9b:e6:9a:45:06:34:19:03:05:b0:15:ca:
+ a2:59:7c:ac:fe:9c:c4:29:54:e2:c8:9c:e1:98:7e:16:7a:b9:
+ f3:9e:aa:d1
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvUslZPhG
+Puj8hTriStyaWHBvZSeTFC9dCLO63C2wjA6Y9iEmjf+7WS3bcrwHOI8RNMzoBw8H
+7YIeYL7YZxeYy4FVQF7ZoL2lmIhxF45lcD6Kn7MjVp+YqNtkahvhGiyxlG3TSyj9
+5BzTfZORU1w9iWcTBFghZMmJxxJYkdwvD1bspwBPYIkKua9SjiC8sxbopgbKOwel
+dll+SxczstuO2DEp2LoIBlHhoUNtzS1h4QNUYh1DKLlItju7JEfQVt/OrNOsqQwT
+pch2o+5nDHk1kl1Jj6VPj655CWwRFT86AaNNVN+TULX+7b5Th763ZVWWTHxboOMe
+GOiejJXRSupaTwIDAQABo4HLMIHIMB0GA1UdDgQWBBSg/2qw2212PR/So4MzAr4y
+onE0hTAfBgNVHSMEGDAWgBQK4XEV3+0NmOt1qDe88e7jZXmrwjA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+ABMOPA5pwr99qqSPR6aQaQ7Yt1Aqx5V4HX9xQVGNpKnP8tLGwI/dVsRTlDQ/B+Ow
+THFVWxSi3o8eOxVz4ppJ38gOBNx2dmENxSk1EsRx0y1trLZiU3VXRM8L0h1mCr4B
+taZYoEL1zmI82CH9xscnZrEv1ATCKUQyOjuyPAilZj5MJ8I2ccUxBefp+Ee0gTNX
+fcLOrN7EFREa8slZcs2kqFRB79XVZ89u46AHYrqD90b6SxB8kZ//qhrJRvkmFMQB
+WJ01dfB4DnVOfwPogxuHgpngUrOfNKcmNHac5z5p1ZvmmkUGNBkDBbAVyqJZfKz+
+nMQpVOLInOGYfhZ6ufOeqtE=
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:99:74:ca:c8:3e:26:66:b5:bc:e5:cc:0b:41:30:
+ 7b:cb:99:a5:31:5f:e6:3f:44:81:d3:c5:16:0e:ac:
+ db:2e:cf:5a:08:79:5a:44:c4:f1:bc:e5:74:06:42:
+ 57:35:4b:e7:90:88:ef:dd:59:b7:82:40:b5:ff:c2:
+ 03:32:1b:4d:1c:6d:ee:34:60:a8:c5:24:ab:b0:0f:
+ a6:19:22:86:ae:e3:12:dd:3e:99:3a:36:65:6a:ea:
+ 5d:aa:b0:2d:e9:db:9a:22:83:cb:50:8b:1a:04:cb:
+ 4b:83:83:46:95:e1:45:a7:17:d3:16:ab:70:e6:62:
+ 85:79:ff:73:35:3e:7e:4d:1d:3b:6d:e1:60:0e:15:
+ 3c:12:cf:7a:d7:eb:af:04:0a:43:3b:5f:78:de:df:
+ ba:51:60:4d:20:61:32:2c:f4:61:d3:e2:48:02:8d:
+ a1:d5:05:ec:f4:d0:7d:3d:2e:f8:5f:3b:57:76:21:
+ d8:55:1a:61:34:53:af:2f:de:32:ff:27:7e:12:41:
+ 96:56:0a:9d:d2:e5:3f:38:14:9e:20:50:58:4c:00:
+ 7d:16:4d:2d:b8:f3:75:c5:c4:b3:80:a7:d9:e4:60:
+ e1:8f:b5:b8:a4:82:db:72:b2:7c:0b:a2:ef:5e:98:
+ 22:48:b2:f9:7c:4a:82:e5:59:fa:0d:93:34:34:88:
+ 93:a7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 0A:E1:71:15:DF:ED:0D:98:EB:75:A8:37:BC:F1:EE:E3:65:79:AB:C2
+ X509v3 Authority Key Identifier:
+ keyid:0A:E1:71:15:DF:ED:0D:98:EB:75:A8:37:BC:F1:EE:E3:65:79:AB:C2
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ Signature Algorithm: sha256WithRSAEncryption
+ 6d:66:a8:f5:13:4c:3a:8d:26:f2:30:1a:59:72:f3:dd:7a:17:
+ cf:8d:6e:76:cf:23:db:be:a3:85:e9:78:63:1d:4c:d8:78:93:
+ 9e:57:61:0d:78:2a:5a:67:c3:d8:73:d1:69:72:24:66:e6:9b:
+ b3:fb:b8:31:7e:c0:4b:8c:03:48:fb:36:b7:ac:42:39:66:94:
+ 26:22:d7:fb:d3:11:67:29:d6:32:9c:c3:9e:bd:b1:43:2e:6f:
+ a1:a5:4c:ec:5d:df:5e:b6:49:0c:81:9c:2f:09:81:03:97:16:
+ 80:5a:da:c1:25:d6:c8:3e:d9:11:ed:1a:1d:8d:ac:46:90:e9:
+ 1c:e1:23:70:95:2d:b3:19:a5:ba:97:7b:47:4f:af:cc:ed:80:
+ 4e:46:26:8e:39:86:5a:6d:f4:94:56:42:05:49:fc:ef:48:2e:
+ fa:04:78:34:0f:5a:c9:56:dc:eb:88:3a:fc:d6:8b:73:d7:81:
+ 27:57:e3:27:6f:6b:74:af:6e:42:16:c9:30:a8:3d:8f:24:43:
+ 55:40:9b:fc:39:43:3a:b5:50:6b:11:c3:b8:a1:06:f4:63:3e:
+ 45:01:db:7c:db:b7:35:df:38:c1:eb:83:e8:4e:78:3b:99:66:
+ e9:d1:14:68:b2:f6:7e:2d:80:eb:f7:e0:87:6a:43:c1:3a:23:
+ 8f:aa:05:5d
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDVDCCAjygAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJl0ysg+Jma1vOXMC0Ew
+e8uZpTFf5j9EgdPFFg6s2y7PWgh5WkTE8bzldAZCVzVL55CI791Zt4JAtf/CAzIb
+TRxt7jRgqMUkq7APphkihq7jEt0+mTo2ZWrqXaqwLenbmiKDy1CLGgTLS4ODRpXh
+RacX0xarcOZihXn/czU+fk0dO23hYA4VPBLPetfrrwQKQztfeN7fulFgTSBhMiz0
+YdPiSAKNodUF7PTQfT0u+F87V3Yh2FUaYTRTry/eMv8nfhJBllYKndLlPzgUniBQ
+WEwAfRZNLbjzdcXEs4Cn2eRg4Y+1uKSC23KyfAui716YIkiy+XxKguVZ+g2TNDSI
+k6cCAwEAAaOBujCBtzAdBgNVHQ4EFgQUCuFxFd/tDZjrdag3vPHu42V5q8IwHwYD
+VR0jBBgwFoAUCuFxFd/tDZjrdag3vPHu42V5q8IwNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAbWao9RNMOo0m8jAaWXLz3XoXz41uds8j
+276jhel4Yx1M2HiTnldhDXgqWmfD2HPRaXIkZuabs/u4MX7AS4wDSPs2t6xCOWaU
+JiLX+9MRZynWMpzDnr2xQy5voaVM7F3fXrZJDIGcLwmBA5cWgFrawSXWyD7ZEe0a
+HY2sRpDpHOEjcJUtsxmlupd7R0+vzO2ATkYmjjmGWm30lFZCBUn870gu+gR4NA9a
+yVbc64g6/NaLc9eBJ1fjJ29rdK9uQhbJMKg9jyRDVUCb/DlDOrVQaxHDuKEG9GM+
+RQHbfNu3Nd84weuD6E54O5lm6dEUaLL2fi2A6/fgh2pDwTojj6oFXQ==
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/unknown-root.pem b/chromium/net/data/verify_certificate_chain_unittest/unknown-root.pem
deleted file mode 100644
index a3ee2f7d83f..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/unknown-root.pem
+++ /dev/null
@@ -1,192 +0,0 @@
-[Created by: generate-unknown-root.py]
-
-Certificate chain with 1 intermediary, but the root is not in trust store.
-Verification is expected to fail because the final intermediary (Intermediary)
-does not chain to a known root.
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Target
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:f3:f6:f4:c5:f5:4f:a3:17:ee:19:45:0e:97:90:
- 31:60:2a:a5:31:0d:e4:c7:f4:fa:4d:e4:99:f5:3c:
- db:ad:6b:2d:f2:8d:07:4f:dc:c1:e3:3f:53:b6:48:
- 31:8e:8e:a6:b3:d6:a4:3c:fb:21:00:01:a6:35:79:
- 50:a6:d0:43:10:8d:13:1b:6f:a9:4b:a3:9b:77:11:
- af:0f:7c:f9:f0:e6:03:c5:b5:b4:49:7a:9d:8f:a1:
- 42:89:a5:41:5d:c7:e1:7d:4a:e5:af:8f:66:ad:93:
- b0:f6:60:52:f4:0c:2d:d1:60:ca:a4:4c:fa:0d:55:
- 0d:46:60:69:10:a7:8e:06:bd:ad:28:65:63:a5:63:
- 36:d8:eb:8e:e1:cc:fd:53:76:80:d3:1d:e2:b8:46:
- f9:24:e7:3a:86:30:f9:14:34:a2:42:81:b7:2b:a4:
- 41:14:7a:9c:77:83:51:cb:b9:08:31:29:a2:b0:25:
- 92:1e:7f:43:90:1c:6a:43:ca:64:04:37:c8:26:b7:
- 7b:ae:cb:8b:2e:e7:6f:09:c4:3e:87:0d:b1:ef:70:
- 58:cd:b5:d7:c7:6b:dd:7b:3c:46:0c:4d:5f:21:1d:
- 78:b9:cf:46:5e:f8:35:48:7d:14:0b:3e:a4:2a:1c:
- 4e:78:6d:27:76:61:e5:c5:74:16:fb:f1:77:9c:f3:
- 51:7f
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- F8:48:56:E7:65:49:C4:48:98:8E:F0:F5:EA:01:C4:01:C8:4D:56:D9
- X509v3 Authority Key Identifier:
- keyid:41:D3:BE:10:2F:EE:43:B6:25:B0:04:4E:39:CF:78:F9:0E:ED:E1:9D
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Intermediary.crl
-
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage:
- TLS Web Server Authentication, TLS Web Client Authentication
- Signature Algorithm: sha256WithRSAEncryption
- 48:65:f4:55:86:82:85:93:a0:4d:b0:ce:b8:b2:21:f5:bf:56:
- 66:ef:e3:f5:24:52:da:a5:15:21:f7:b4:a1:7c:2f:69:de:1e:
- 6a:90:8d:98:e9:38:29:b8:51:44:7b:43:68:92:95:e4:50:7c:
- 32:94:72:6c:96:4a:77:07:ce:0c:55:df:19:50:29:e5:ee:ff:
- c4:54:c9:75:2d:c2:fd:f1:41:5c:c4:28:3c:15:df:1a:12:73:
- aa:a6:af:2a:3e:f5:a6:17:68:5b:80:d8:6d:fa:6d:37:26:a1:
- 01:0e:0a:c1:a8:ed:ef:2b:65:1c:43:4d:dd:aa:7b:e1:6d:a6:
- a6:23:66:11:58:73:f0:e2:98:d2:ba:db:94:ed:c9:fc:41:6f:
- 4b:99:7c:be:2e:e9:57:e2:c6:26:24:db:2a:02:4e:3c:7e:8b:
- d8:96:27:43:7b:b4:1e:25:2f:19:c0:e4:05:b9:5e:0e:57:29:
- 9e:81:9c:1e:d8:48:4b:d0:c8:ff:1a:a7:7f:71:4a:9f:51:0d:
- 8a:11:6e:74:86:8e:89:d8:fd:a4:69:bb:67:78:2d:2d:44:75:
- 9b:63:31:ef:b1:3e:38:11:ce:01:ae:b0:fa:a4:3f:b0:df:be:
- 13:9a:5e:11:f6:bb:eb:8e:3a:7d:09:be:76:9b:e5:d4:91:f3:
- dc:e5:23:df
------BEGIN CERTIFICATE-----
-MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
-cm1lZGlhcnkwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
-VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDz9vTF
-9U+jF+4ZRQ6XkDFgKqUxDeTH9PpN5Jn1PNutay3yjQdP3MHjP1O2SDGOjqaz1qQ8
-+yEAAaY1eVCm0EMQjRMbb6lLo5t3Ea8PfPnw5gPFtbRJep2PoUKJpUFdx+F9SuWv
-j2atk7D2YFL0DC3RYMqkTPoNVQ1GYGkQp44Gva0oZWOlYzbY647hzP1TdoDTHeK4
-Rvkk5zqGMPkUNKJCgbcrpEEUepx3g1HLuQgxKaKwJZIef0OQHGpDymQEN8gmt3uu
-y4su528JxD6HDbHvcFjNtdfHa917PEYMTV8hHXi5z0Ze+DVIfRQLPqQqHE54bSd2
-YeXFdBb78Xec81F/AgMBAAGjgekwgeYwHQYDVR0OBBYEFPhIVudlScRImI7w9eoB
-xAHITVbZMB8GA1UdIwQYMBaAFEHTvhAv7kO2JbAETjnPePkO7eGdMD8GCCsGAQUF
-BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
-aWFyeS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
-dGVybWVkaWFyeS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEASGX0VYaChZOgTbDOuLIh
-9b9WZu/j9SRS2qUVIfe0oXwvad4eapCNmOk4KbhRRHtDaJKV5FB8MpRybJZKdwfO
-DFXfGVAp5e7/xFTJdS3C/fFBXMQoPBXfGhJzqqavKj71phdoW4DYbfptNyahAQ4K
-wajt7ytlHENN3ap74W2mpiNmEVhz8OKY0rrblO3J/EFvS5l8vi7pV+LGJiTbKgJO
-PH6L2JYnQ3u0HiUvGcDkBbleDlcpnoGcHthIS9DI/xqnf3FKn1ENihFudIaOidj9
-pGm7Z3gtLUR1m2Mx77E+OBHOAa6w+qQ/sN++E5peEfa76446fQm+dpvl1JHz3OUj
-3w==
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 2 (0x2)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:cd:6f:e8:b3:ea:d4:9e:d9:23:03:8a:4a:f3:6c:
- 84:cd:0c:28:7c:c2:07:60:89:c5:9a:9f:74:b8:d0:
- ac:e4:30:f1:4b:1c:c5:7f:9d:d2:0f:4e:e0:e5:45:
- 4a:cc:93:70:a0:df:3c:4c:fc:0c:a5:d5:c9:86:fd:
- ba:4e:67:c0:af:c3:04:98:cb:bb:f6:25:a6:af:7f:
- 7b:a3:29:b9:86:60:87:80:67:90:ab:e7:64:86:ec:
- e6:30:f6:dd:5b:3a:69:4f:b1:58:f8:4b:15:ae:13:
- c8:84:24:bf:9a:a0:6c:8a:b3:36:31:84:2f:a4:3e:
- 4a:f2:9f:07:91:a4:8b:dc:fa:5b:65:3c:4e:93:19:
- 02:a5:3a:78:5d:f2:51:bd:d7:96:16:6e:c5:8b:17:
- d0:21:77:2f:96:4a:44:c8:17:2d:73:d5:da:24:40:
- d1:a4:b7:f2:c4:b2:e2:16:6a:19:9b:72:cb:58:62:
- eb:30:2f:2f:c5:35:1c:74:2f:ba:e6:93:7e:dc:78:
- bc:ad:e3:89:c9:72:9a:f5:01:95:61:02:9f:82:40:
- f9:c1:c8:6e:36:b7:14:4a:13:36:bb:d0:1b:25:bd:
- d6:5e:11:e7:d9:ea:a7:db:6d:d3:92:98:b1:2a:c1:
- cf:00:52:c1:78:c9:0a:30:41:30:09:c8:90:0a:04:
- 8f:0d
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 41:D3:BE:10:2F:EE:43:B6:25:B0:04:4E:39:CF:78:F9:0E:ED:E1:9D
- X509v3 Authority Key Identifier:
- keyid:A7:80:43:01:58:B0:DD:7A:AD:7C:38:10:73:02:DE:2C:E6:E4:9E:A9
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- 90:b6:a5:85:fe:d4:51:b9:f7:92:ae:60:80:ab:54:09:3d:63:
- 43:fd:ce:e0:ea:e3:f2:c0:db:f5:1b:a7:db:f1:b3:21:d0:e4:
- 7f:63:c1:75:13:ca:3d:6b:70:76:55:23:cc:c8:74:80:b8:82:
- c0:cd:63:41:77:4c:27:8a:32:34:f7:9d:8d:0e:9f:15:ee:22:
- 4f:ed:d7:32:f2:c9:95:bd:35:87:d8:c5:58:19:ba:06:58:a4:
- 96:bc:2d:4e:1b:ed:2f:23:ac:b1:2f:b7:e0:88:a9:fc:68:c0:
- 8d:8a:41:e6:d3:ba:b9:88:77:54:37:5a:e5:a9:b3:f2:85:7b:
- b4:7d:69:83:37:81:12:54:21:4c:d1:69:98:a2:fd:ef:a3:65:
- e9:32:f6:63:1e:54:ce:a9:75:74:53:61:b4:f0:78:72:c4:f0:
- 04:f0:f3:a8:70:93:f6:35:89:0f:6f:49:7a:0e:57:e0:af:33:
- 35:89:b6:cd:ef:81:aa:8c:10:11:e9:57:a1:66:4c:30:9c:11:
- 6a:c6:85:4b:d1:94:88:6e:aa:5f:8e:fb:d2:31:3d:ee:19:19:
- 01:3c:4a:05:72:9c:aa:ae:ef:af:b0:f1:9f:e0:ae:d6:8e:09:
- d1:05:ee:6b:77:08:11:52:8c:91:a0:2f:9b:ac:88:98:14:14:
- a4:08:b5:7d
------BEGIN CERTIFICATE-----
-MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
-ZXJtZWRpYXJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzW/os+rU
-ntkjA4pK82yEzQwofMIHYInFmp90uNCs5DDxSxzFf53SD07g5UVKzJNwoN88TPwM
-pdXJhv26TmfAr8MEmMu79iWmr397oym5hmCHgGeQq+dkhuzmMPbdWzppT7FY+EsV
-rhPIhCS/mqBsirM2MYQvpD5K8p8HkaSL3PpbZTxOkxkCpTp4XfJRvdeWFm7FixfQ
-IXcvlkpEyBctc9XaJEDRpLfyxLLiFmoZm3LLWGLrMC8vxTUcdC+65pN+3Hi8reOJ
-yXKa9QGVYQKfgkD5wchuNrcUShM2u9AbJb3WXhHn2eqn223TkpixKsHPAFLBeMkK
-MEEwCciQCgSPDQIDAQABo4HLMIHIMB0GA1UdDgQWBBRB074QL+5DtiWwBE45z3j5
-Du3hnTAfBgNVHSMEGDAWgBSngEMBWLDdeq18OBBzAt4s5uSeqTA3BggrBgEFBQcB
-AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
-BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
-VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
-AJC2pYX+1FG595KuYICrVAk9Y0P9zuDq4/LA2/Ubp9vxsyHQ5H9jwXUTyj1rcHZV
-I8zIdIC4gsDNY0F3TCeKMjT3nY0OnxXuIk/t1zLyyZW9NYfYxVgZugZYpJa8LU4b
-7S8jrLEvt+CIqfxowI2KQebTurmId1Q3WuWps/KFe7R9aYM3gRJUIUzRaZii/e+j
-Zeky9mMeVM6pdXRTYbTweHLE8ATw86hwk/Y1iQ9vSXoOV+CvMzWJts3vgaqMEBHp
-V6FmTDCcEWrGhUvRlIhuql+O+9IxPe4ZGQE8SgVynKqu76+w8Z/grtaOCdEF7mt3
-CBFSjJGgL5usiJgUFKQItX0=
------END CERTIFICATE-----
-
------BEGIN TIME-----
-MTUwMzAyMTIwMDAwWg==
------END TIME-----
-
------BEGIN VERIFY_RESULT-----
-RkFJTA==
------END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/violates-basic-constraints-pathlen-0.pem b/chromium/net/data/verify_certificate_chain_unittest/violates-basic-constraints-pathlen-0.pem
index a0cd187e5ce..ba825fe79d2 100644
--- a/chromium/net/data/verify_certificate_chain_unittest/violates-basic-constraints-pathlen-0.pem
+++ b/chromium/net/data/verify_certificate_chain_unittest/violates-basic-constraints-pathlen-0.pem
@@ -1,15 +1,15 @@
[Created by: generate-violates-basic-constraints-pathlen-0.py]
-Certificate chain with 2 intermediaries. The first intermediary has a basic
+Certificate chain with 2 intermediates. The first intermediate has a basic
constraints path length of 0, so it is a violation for it to have a subordinate
-intermediary.
+intermediate.
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary2
+ Issuer: CN=Intermediate2
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
@@ -18,80 +18,80 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:b2:f1:24:bb:4b:3d:6d:80:7f:67:ad:2e:0e:e8:
- 07:e4:4b:6c:28:0d:2e:d9:9d:9d:e5:31:0a:7f:37:
- 3f:9c:c1:c3:03:8e:b8:72:5a:1c:52:d4:4e:84:7a:
- 9c:4d:f6:2a:a8:4b:f2:5c:5b:6c:f4:23:73:b3:4e:
- 0a:b9:66:16:ae:e4:c4:8b:d7:1b:b5:d0:5e:5f:03:
- 21:ce:63:b8:3a:da:e0:3c:f8:0a:7e:4b:99:f9:c6:
- 0d:01:a2:ab:18:d8:a7:a0:84:8c:3f:09:fd:10:41:
- 7c:6f:b0:51:34:4f:5d:39:b5:3f:6d:a0:68:87:6d:
- 09:47:db:0d:2a:62:99:83:02:0c:b9:d7:93:0b:bf:
- 17:5f:06:58:22:27:62:fc:1c:d9:02:b9:1e:e9:f0:
- fb:e1:a4:cc:fd:e3:9e:a8:a5:2d:f9:af:8b:b8:1e:
- 68:dc:f1:52:a2:55:94:20:da:82:14:b7:c0:a0:c5:
- 53:ff:00:0f:76:f9:fd:bf:53:71:99:60:2f:00:c9:
- 9e:d0:07:eb:3c:d0:47:5c:7b:65:cb:62:db:9b:74:
- ed:b8:51:a0:ed:ed:af:e9:6f:44:0e:8c:a4:42:ee:
- fc:92:bb:19:1a:b3:42:74:27:39:47:b8:d4:06:ed:
- bd:99:72:0c:83:15:10:ff:4a:66:66:0f:d6:14:ef:
- dd:17
+ 00:c3:d8:cf:ca:eb:7a:63:bc:cd:53:50:a0:a5:e7:
+ 24:1c:5e:ab:ee:eb:48:d3:60:73:ab:a5:c3:b5:e0:
+ ea:b2:71:0b:99:48:4c:0c:78:6f:67:a8:98:13:f7:
+ 99:59:a0:fc:78:d8:7e:05:cc:1c:4c:4d:ff:c0:a7:
+ 85:8f:c0:f8:c2:10:51:a2:a6:9b:38:a1:a8:7f:e3:
+ 7c:df:be:f7:8c:62:9a:83:c6:a5:ab:63:26:9e:71:
+ 25:26:7d:dc:05:09:b3:76:e8:de:90:07:6d:6d:d1:
+ 33:a5:3a:64:90:c0:50:2e:d6:a9:84:2e:f2:7c:11:
+ 49:4c:c5:e2:50:c3:b9:9c:0f:ac:8f:07:19:74:63:
+ 00:12:8a:ec:6f:4f:86:8a:9b:af:2a:c2:21:f1:98:
+ 88:eb:4a:23:2c:7d:25:9f:fd:2a:3e:b0:3d:f5:66:
+ bf:a7:07:42:7d:04:70:62:d3:4b:88:92:af:74:6e:
+ 20:4c:55:5e:9e:de:29:a6:58:66:1a:8d:c4:af:b5:
+ 22:44:29:ee:b6:03:66:8e:4b:a6:ca:77:3d:91:08:
+ c0:b2:e0:70:c8:e6:d1:fb:db:09:86:7c:ad:f5:20:
+ 76:10:1d:fc:bf:98:05:0b:b1:6e:47:d8:ce:4b:aa:
+ 02:7c:ec:3e:8a:b0:22:f9:3d:fc:8e:60:45:1b:cc:
+ c9:a5
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 33:73:C0:44:EE:71:53:CD:C0:EA:D9:FC:FF:BE:B7:DD:16:66:19:84
+ 4C:E1:88:56:8D:23:98:7B:19:E1:6E:D8:1C:E5:06:73:6B:D5:1E:03
X509v3 Authority Key Identifier:
- keyid:FD:31:C0:C5:57:AB:1E:A5:78:24:73:72:58:9F:75:7D:78:17:42:AC
+ keyid:CB:CE:B8:91:FA:EC:E9:A4:15:CA:75:30:F1:C6:9A:B8:19:35:FA:29
Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary2.cer
+ CA Issuers - URI:http://url-for-aia/Intermediate2.cer
X509v3 CRL Distribution Points:
Full Name:
- URI:http://url-for-crl/Intermediary2.crl
+ URI:http://url-for-crl/Intermediate2.crl
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 61:39:30:49:95:f7:63:44:f3:a5:97:35:48:84:ea:94:cd:94:
- 37:ce:09:7a:b1:58:21:3e:f8:9c:a4:a9:65:bf:1d:a1:cb:eb:
- 09:95:f7:f6:ad:a4:65:95:a1:51:c4:18:06:43:d2:93:eb:16:
- 41:65:33:8a:42:cc:90:9d:e9:66:1f:d6:98:31:f1:48:f4:a8:
- a3:89:50:29:bc:f2:2d:af:8b:f7:af:9e:62:02:21:06:75:3d:
- 4a:8d:98:a0:df:4d:5d:db:9a:af:2a:0f:32:50:aa:61:c3:19:
- 87:99:54:60:3a:16:c5:46:ea:ed:54:ab:91:34:5f:8e:60:33:
- 10:e4:e1:4d:05:8d:36:5b:47:1c:c3:f2:58:7f:22:07:c7:95:
- 02:24:8e:03:f4:1f:06:25:d7:49:76:f8:f1:02:25:7c:9a:cf:
- 0f:4d:8f:08:e7:bf:fd:13:31:43:e5:56:20:eb:0a:43:ca:41:
- 0d:7c:4f:68:f6:d1:d1:67:ca:24:4f:e3:8e:8e:12:39:2f:7b:
- e8:9a:5c:c9:b5:19:01:1a:46:7e:54:21:ad:7e:c5:cd:e2:40:
- c3:13:aa:b5:e5:16:b3:18:dc:c8:61:d7:73:b7:3b:23:00:04:
- ce:dc:5a:22:1a:0b:da:8a:99:10:96:33:32:ae:4e:83:f4:d0:
- 93:e7:75:56
+ a6:96:6f:71:a0:4e:f8:17:93:ad:30:1f:2e:e5:6e:bc:4e:83:
+ 32:07:95:9f:f6:02:e8:06:5e:a6:51:0a:23:f6:46:06:3c:3d:
+ e6:4d:cc:ac:8c:29:e8:ce:0e:a4:db:11:7d:4f:6e:b7:78:e2:
+ 40:1e:0e:74:83:d5:16:7c:c5:6e:3e:41:59:be:d5:0c:ab:05:
+ 9f:2f:22:8c:3b:58:ed:72:49:11:b0:0b:21:b9:5d:e0:b8:3f:
+ cd:a0:a0:95:64:c6:8e:45:7d:aa:1b:67:69:13:54:40:0d:99:
+ 74:da:b1:9f:5b:9f:ba:e3:b6:aa:5b:e4:b6:d9:6c:46:d3:50:
+ 1a:d9:5a:54:b9:2d:a1:da:97:00:7a:6a:71:2a:8e:45:9c:6d:
+ e8:3d:a2:cb:29:44:45:11:5c:a9:64:60:81:88:e4:93:a2:61:
+ ec:87:74:69:bc:9c:61:92:94:eb:42:33:12:29:82:5d:fe:30:
+ 9b:9c:bf:47:50:a9:f6:ae:ea:d4:97:39:87:d5:02:c4:45:09:
+ a8:f3:f3:bf:e0:35:45:89:a9:bc:57:34:bf:d4:81:a0:09:4e:
+ 2d:15:61:39:0c:43:53:2e:50:fb:31:ab:91:0d:ce:9c:cb:c1:
+ e2:39:e2:76:60:ab:6b:5d:33:b6:0f:a7:c8:f0:61:ed:37:81:
+ 83:3a:2b:b4
-----BEGIN CERTIFICATE-----
MIIDkDCCAnigAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1JbnRl
-cm1lZGlhcnkyMB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowETEPMA0G
-A1UEAwwGVGFyZ2V0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsvEk
-u0s9bYB/Z60uDugH5EtsKA0u2Z2d5TEKfzc/nMHDA464clocUtROhHqcTfYqqEvy
-XFts9CNzs04KuWYWruTEi9cbtdBeXwMhzmO4OtrgPPgKfkuZ+cYNAaKrGNinoISM
-Pwn9EEF8b7BRNE9dObU/baBoh20JR9sNKmKZgwIMudeTC78XXwZYIidi/BzZArke
-6fD74aTM/eOeqKUt+a+LuB5o3PFSolWUINqCFLfAoMVT/wAPdvn9v1NxmWAvAMme
-0AfrPNBHXHtly2Lbm3TtuFGg7e2v6W9EDoykQu78krsZGrNCdCc5R7jUBu29mXIM
-gxUQ/0pmZg/WFO/dFwIDAQABo4HrMIHoMB0GA1UdDgQWBBQzc8BE7nFTzcDq2fz/
-vrfdFmYZhDAfBgNVHSMEGDAWgBT9McDFV6sepXgkc3JYn3V9eBdCrDBABggrBgEF
+cm1lZGlhdGUyMB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowETEPMA0G
+A1UEAwwGVGFyZ2V0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw9jP
+yut6Y7zNU1CgpeckHF6r7utI02Bzq6XDteDqsnELmUhMDHhvZ6iYE/eZWaD8eNh+
+BcwcTE3/wKeFj8D4whBRoqabOKGof+N83773jGKag8alq2MmnnElJn3cBQmzduje
+kAdtbdEzpTpkkMBQLtaphC7yfBFJTMXiUMO5nA+sjwcZdGMAEorsb0+GipuvKsIh
+8ZiI60ojLH0ln/0qPrA99Wa/pwdCfQRwYtNLiJKvdG4gTFVent4pplhmGo3Er7Ui
+RCnutgNmjkumync9kQjAsuBwyObR+9sJhnyt9SB2EB38v5gFC7FuR9jOS6oCfOw+
+irAi+T38jmBFG8zJpQIDAQABo4HrMIHoMB0GA1UdDgQWBBRM4YhWjSOYexnhbtgc
+5QZza9UeAzAfBgNVHSMEGDAWgBTLzriR+uzppBXKdTDxxpq4GTX6KTBABggrBgEF
BQcBAQQ0MDIwMAYIKwYBBQUHMAKGJGh0dHA6Ly91cmwtZm9yLWFpYS9JbnRlcm1l
-ZGlhcnkyLmNlcjA1BgNVHR8ELjAsMCqgKKAmhiRodHRwOi8vdXJsLWZvci1jcmwv
-SW50ZXJtZWRpYXJ5Mi5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsG
-AQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAYTkwSZX3Y0TzpZc1
-SITqlM2UN84JerFYIT74nKSpZb8docvrCZX39q2kZZWhUcQYBkPSk+sWQWUzikLM
-kJ3pZh/WmDHxSPSoo4lQKbzyLa+L96+eYgIhBnU9So2YoN9NXduaryoPMlCqYcMZ
-h5lUYDoWxUbq7VSrkTRfjmAzEOThTQWNNltHHMPyWH8iB8eVAiSOA/QfBiXXSXb4
-8QIlfJrPD02PCOe//RMxQ+VWIOsKQ8pBDXxPaPbR0WfKJE/jjo4SOS976JpcybUZ
-ARpGflQhrX7FzeJAwxOqteUWsxjcyGHXc7c7IwAEztxaIhoL2oqZEJYzMq5Og/TQ
-k+d1Vg==
+ZGlhdGUyLmNlcjA1BgNVHR8ELjAsMCqgKKAmhiRodHRwOi8vdXJsLWZvci1jcmwv
+SW50ZXJtZWRpYXRlMi5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsG
+AQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAppZvcaBO+BeTrTAf
+LuVuvE6DMgeVn/YC6AZeplEKI/ZGBjw95k3MrIwp6M4OpNsRfU9ut3jiQB4OdIPV
+FnzFbj5BWb7VDKsFny8ijDtY7XJJEbALIbld4Lg/zaCglWTGjkV9qhtnaRNUQA2Z
+dNqxn1ufuuO2qlvkttlsRtNQGtlaVLktodqXAHpqcSqORZxt6D2iyylERRFcqWRg
+gYjkk6Jh7Id0abycYZKU60IzEimCXf4wm5y/R1Cp9q7q1Jc5h9UCxEUJqPPzv+A1
+RYmpvFc0v9SBoAlOLRVhOQxDUy5Q+zGrkQ3OnMvB4jnidmCra10ztg+nyPBh7TeB
+gzortA==
-----END CERTIFICATE-----
Certificate:
@@ -99,88 +99,88 @@ Certificate:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary1
+ Issuer: CN=Intermediate1
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary2
+ Subject: CN=Intermediate2
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:b9:4e:dc:bd:a8:9e:1d:81:d7:bb:c3:4d:8a:5d:
- 34:3f:b2:71:12:c0:0d:76:05:d6:b3:6a:b6:3d:b5:
- 97:a8:8d:a0:ba:d9:2f:3c:da:b0:8f:5f:18:f0:83:
- fb:59:ef:91:8d:5a:57:57:63:36:a1:ff:54:9a:f5:
- 10:ab:4a:6b:16:fc:c6:f2:4e:9f:97:ec:22:6f:97:
- dd:0e:63:ef:ce:71:4f:f6:8e:04:68:22:c9:6d:b4:
- d2:fe:7b:46:aa:e9:05:a0:c0:b0:25:42:cd:ba:e8:
- 8d:bb:cb:3e:5f:e4:54:b7:dd:48:c6:08:52:30:54:
- e2:f4:c1:ae:ee:71:71:a7:33:ce:c1:b1:55:e4:77:
- 15:72:c5:ea:5f:ed:b3:a6:ef:a7:cc:f6:eb:6c:42:
- 1d:45:c3:75:15:d5:bd:09:44:52:b9:f5:5d:1f:10:
- e1:fc:31:9e:37:90:ca:7c:8d:16:c4:f7:76:39:b7:
- 57:ea:5b:75:3d:6c:50:60:26:ed:8b:2a:e4:a2:b8:
- a2:34:ba:51:89:ce:3c:e3:68:c3:3c:4a:58:cb:be:
- 79:34:54:2d:61:38:7b:7a:89:3f:4c:5f:3f:c9:c6:
- fc:d0:81:de:0c:21:2e:5a:2a:74:cd:fe:d7:c9:de:
- b3:3a:60:d6:16:e7:91:13:87:a4:f4:f8:67:4b:17:
- e6:13
+ 00:ad:d8:fa:e5:f4:8b:41:38:13:dc:61:ad:db:db:
+ 3d:f6:be:e2:fd:9d:63:a2:eb:4a:8d:c8:03:6b:d2:
+ c3:18:29:e6:93:92:5f:d0:c5:b2:3c:05:cd:79:c9:
+ 25:dd:e8:fc:68:83:f1:d9:95:15:22:8f:27:eb:bf:
+ 1f:ed:78:ce:34:b7:60:66:ee:4a:40:9f:e3:95:d0:
+ 32:47:67:80:6c:37:1c:3d:3a:e8:3e:14:2d:5b:97:
+ b3:40:85:28:a9:10:f0:fb:c9:eb:51:be:b6:c6:8a:
+ ca:60:cd:31:b7:b0:d3:bd:eb:5c:8a:14:89:38:47:
+ cb:18:2b:11:f7:a7:9e:9d:f3:76:82:97:c4:78:61:
+ 8c:ec:90:ac:f2:a8:2e:bf:d8:30:48:52:94:7f:48:
+ f6:fb:4b:e6:0a:63:89:ad:8a:4d:8d:3e:dc:45:06:
+ 89:e9:94:24:5b:d4:94:50:de:05:cf:87:59:66:fb:
+ 70:62:84:3c:fe:d9:1b:02:92:30:80:cb:45:43:e4:
+ 55:47:97:2e:99:59:22:86:6f:51:3a:24:13:26:e8:
+ 10:c9:92:35:13:6f:4a:39:c5:71:d2:c3:63:a5:11:
+ f8:6e:dc:fa:75:5c:4b:29:24:04:9f:e3:f4:f0:49:
+ 55:7e:0a:8c:6c:44:b4:a4:35:c7:b0:54:10:a4:b1:
+ 6f:95
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- FD:31:C0:C5:57:AB:1E:A5:78:24:73:72:58:9F:75:7D:78:17:42:AC
+ CB:CE:B8:91:FA:EC:E9:A4:15:CA:75:30:F1:C6:9A:B8:19:35:FA:29
X509v3 Authority Key Identifier:
- keyid:09:87:C1:14:11:81:04:D8:AF:CF:66:4A:4F:8D:1C:A5:BB:04:CF:DA
+ keyid:58:20:BB:27:E1:6D:B0:95:1A:D3:40:A1:81:79:89:63:34:21:9F:13
Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary1.cer
+ CA Issuers - URI:http://url-for-aia/Intermediate1.cer
X509v3 CRL Distribution Points:
Full Name:
- URI:http://url-for-crl/Intermediary1.crl
+ URI:http://url-for-crl/Intermediate1.crl
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
Signature Algorithm: sha256WithRSAEncryption
- 51:f3:32:1a:03:bd:bd:a1:40:7d:4a:55:ef:6e:5e:58:57:8c:
- 50:75:7c:e6:d0:44:ff:7e:0c:f7:9d:c2:67:99:83:e2:da:19:
- e6:0b:54:8a:61:7d:16:86:99:2d:b7:32:2d:c6:a0:7a:1a:e2:
- c2:46:8c:a1:b7:f8:bb:d4:22:b1:ae:d0:2f:a9:98:32:4e:14:
- 20:6c:22:cf:df:c8:08:ce:f4:4c:8b:5c:03:33:0a:d1:32:2b:
- 5a:0d:d2:99:18:79:a1:e8:ed:8d:31:85:9e:dd:30:52:30:1f:
- ff:af:1f:09:08:98:a0:75:11:02:e6:6c:2b:7e:67:df:89:91:
- 1e:57:b4:a2:ba:1e:7b:86:68:f3:62:7a:69:c1:4e:b3:76:58:
- 74:e5:84:3d:0f:6d:1b:22:97:e9:7f:0b:c7:2f:00:c5:4d:1a:
- fd:47:ff:9f:c0:84:0b:ee:dc:cd:c2:43:7f:0f:7a:a6:28:6e:
- c3:2c:7a:a1:cf:4f:16:3f:f5:fc:40:c7:65:91:a5:bc:5c:82:
- 9c:a0:fb:0a:1d:69:89:85:e5:9e:10:41:7e:4d:83:02:4f:64:
- 54:04:86:97:d7:5e:6c:e1:ef:65:b0:a4:69:b8:e3:d4:0e:cd:
- 20:04:1a:05:56:e9:e1:c3:e9:2f:9a:7b:43:59:73:ff:0b:82:
- 38:e8:b3:b5
+ 5c:fb:a9:0c:98:92:b4:e2:3c:b1:57:ae:7d:4c:17:b3:44:0e:
+ df:f8:c5:96:e3:1c:10:c2:1b:cf:26:b8:b8:45:3b:e2:3a:54:
+ d9:2a:ce:2d:70:ef:7d:e7:0a:f8:c4:3e:c2:11:65:58:c2:9c:
+ 57:0f:82:6f:ad:d5:c3:75:fe:7a:eb:3e:51:13:a9:04:18:37:
+ 6a:e1:86:11:7f:3b:9d:5a:eb:29:ec:ef:d1:3b:df:13:f4:66:
+ 87:31:2e:b7:75:b0:31:02:b6:47:98:d6:f5:3d:35:7e:18:ac:
+ 53:86:4e:d2:d4:93:ac:7a:20:04:8f:58:9b:15:58:ad:7a:b3:
+ 3e:a0:11:57:92:96:2a:d4:b9:16:e9:f0:8b:70:67:4b:21:58:
+ 80:8e:43:21:ba:62:22:46:96:d2:f0:48:82:69:c5:51:ba:22:
+ 32:a0:50:cf:48:1f:1a:35:05:41:23:4e:93:a2:43:e6:83:d9:
+ ae:32:1e:95:72:24:61:79:09:4c:62:d0:1c:42:60:c5:8c:0c:
+ 6f:a1:8c:29:8c:68:e3:b8:da:44:83:f6:04:ab:e2:85:e4:6a:
+ f6:ca:ed:95:e3:a0:81:4e:79:1e:cb:46:a1:83:4b:19:23:52:
+ ae:b3:80:d7:7c:4f:05:8c:78:55:e2:fc:ec:80:74:5b:3e:7d:
+ 16:e3:71:5a
-----BEGIN CERTIFICATE-----
MIIDjDCCAnSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1JbnRl
-cm1lZGlhcnkxMB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowGDEWMBQG
-A1UEAwwNSW50ZXJtZWRpYXJ5MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBALlO3L2onh2B17vDTYpdND+ycRLADXYF1rNqtj21l6iNoLrZLzzasI9fGPCD
-+1nvkY1aV1djNqH/VJr1EKtKaxb8xvJOn5fsIm+X3Q5j785xT/aOBGgiyW200v57
-RqrpBaDAsCVCzbrojbvLPl/kVLfdSMYIUjBU4vTBru5xcaczzsGxVeR3FXLF6l/t
-s6bvp8z262xCHUXDdRXVvQlEUrn1XR8Q4fwxnjeQynyNFsT3djm3V+pbdT1sUGAm
-7Ysq5KK4ojS6UYnOPONowzxKWMu+eTRULWE4e3qJP0xfP8nG/NCB3gwhLloqdM3+
-18neszpg1hbnkROHpPT4Z0sX5hMCAwEAAaOB4DCB3TAdBgNVHQ4EFgQU/THAxVer
-HqV4JHNyWJ91fXgXQqwwHwYDVR0jBBgwFoAUCYfBFBGBBNivz2ZKT40cpbsEz9ow
+cm1lZGlhdGUxMB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowGDEWMBQG
+A1UEAwwNSW50ZXJtZWRpYXRlMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAK3Y+uX0i0E4E9xhrdvbPfa+4v2dY6LrSo3IA2vSwxgp5pOSX9DFsjwFzXnJ
+Jd3o/GiD8dmVFSKPJ+u/H+14zjS3YGbuSkCf45XQMkdngGw3HD066D4ULVuXs0CF
+KKkQ8PvJ61G+tsaKymDNMbew073rXIoUiThHyxgrEfennp3zdoKXxHhhjOyQrPKo
+Lr/YMEhSlH9I9vtL5gpjia2KTY0+3EUGiemUJFvUlFDeBc+HWWb7cGKEPP7ZGwKS
+MIDLRUPkVUeXLplZIoZvUTokEyboEMmSNRNvSjnFcdLDY6UR+G7c+nVcSykkBJ/j
+9PBJVX4KjGxEtKQ1x7BUEKSxb5UCAwEAAaOB4DCB3TAdBgNVHQ4EFgQUy864kfrs
+6aQVynUw8caauBk1+ikwHwYDVR0jBBgwFoAUWCC7J+FtsJUa00ChgXmJYzQhnxMw
QAYIKwYBBQUHAQEENDAyMDAGCCsGAQUFBzAChiRodHRwOi8vdXJsLWZvci1haWEv
-SW50ZXJtZWRpYXJ5MS5jZXIwNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL3VybC1m
-b3ItY3JsL0ludGVybWVkaWFyeTEuY3JsMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMB
-Af8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBCwUAA4IBAQBR8zIaA729oUB9SlXvbl5Y
-V4xQdXzm0ET/fgz3ncJnmYPi2hnmC1SKYX0WhpkttzItxqB6GuLCRoyht/i71CKx
-rtAvqZgyThQgbCLP38gIzvRMi1wDMwrRMitaDdKZGHmh6O2NMYWe3TBSMB//rx8J
-CJigdREC5mwrfmffiZEeV7Siuh57hmjzYnppwU6zdlh05YQ9D20bIpfpfwvHLwDF
-TRr9R/+fwIQL7tzNwkN/D3qmKG7DLHqhz08WP/X8QMdlkaW8XIKcoPsKHWmJheWe
-EEF+TYMCT2RUBIaX115s4e9lsKRpuOPUDs0gBBoFVunhw+kvmntDWXP/C4I46LO1
+SW50ZXJtZWRpYXRlMS5jZXIwNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL3VybC1m
+b3ItY3JsL0ludGVybWVkaWF0ZTEuY3JsMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMB
+Af8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBCwUAA4IBAQBc+6kMmJK04jyxV659TBez
+RA7f+MWW4xwQwhvPJri4RTviOlTZKs4tcO995wr4xD7CEWVYwpxXD4JvrdXDdf56
+6z5RE6kEGDdq4YYRfzudWusp7O/RO98T9GaHMS63dbAxArZHmNb1PTV+GKxThk7S
+1JOseiAEj1ibFViterM+oBFXkpYq1LkW6fCLcGdLIViAjkMhumIiRpbS8EiCacVR
+uiIyoFDPSB8aNQVBI06TokPmg9muMh6VciRheQlMYtAcQmDFjAxvoYwpjGjjuNpE
+g/YEq+KF5Gr2yu2V46CBTnkey0ahg0sZI1Kus4DXfE8FjHhV4vzsgHRbPn0W43Fa
-----END CERTIFICATE-----
Certificate:
@@ -192,35 +192,35 @@ Certificate:
Validity
Not Before: Jan 1 12:00:00 2015 GMT
Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary1
+ Subject: CN=Intermediate1
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:ab:e9:a0:28:67:38:13:72:12:a0:3b:f2:f9:13:
- c2:2b:c1:a2:07:e6:45:35:cf:ff:1a:46:b0:d2:58:
- 12:63:fc:3d:b3:85:50:68:9c:57:21:ff:31:ff:24:
- 48:db:13:de:b1:f4:f8:39:7a:f3:34:dd:51:58:1a:
- 12:73:9d:85:e0:d0:f8:be:fd:9d:e2:34:ce:36:e0:
- a0:48:53:36:23:bf:52:d2:ac:da:d1:ef:6c:da:9f:
- 11:3b:6c:e1:67:6a:f1:df:97:2c:1a:12:c7:c3:72:
- 0f:98:21:6a:40:2b:f0:28:b8:c2:ef:7f:cb:ee:7a:
- e9:8f:17:fe:0a:a1:ff:d5:15:4c:63:5b:53:55:15:
- 01:b9:5d:91:77:b0:23:03:0e:45:00:84:52:33:2b:
- 11:51:99:e8:0d:5b:45:ef:d2:e2:c9:0e:a2:ae:43:
- c2:92:5c:b0:36:76:06:21:91:d0:42:e8:0f:6f:80:
- 61:98:12:a6:c0:c3:b7:64:7e:77:0c:76:12:1f:50:
- 73:f8:bb:28:1a:5d:7b:68:36:01:fa:09:e7:9a:90:
- b6:c5:3d:e9:16:a0:7b:c2:76:19:f0:e9:bc:15:0d:
- 55:df:ea:67:2a:b2:e0:69:f8:c1:49:c4:a6:51:e9:
- 43:d2:df:2a:de:e3:a0:66:3f:0c:18:b8:f8:8d:bb:
- 43:15
+ 00:e6:65:53:d1:2e:4e:ad:28:ff:05:13:1b:64:08:
+ aa:e6:b7:44:64:94:4c:0e:a4:68:80:12:7d:07:ce:
+ 6a:ec:c8:4b:cc:a1:3f:af:f4:c8:45:0e:b2:66:46:
+ b3:fd:ef:68:5d:04:c0:95:e9:71:45:b2:26:12:16:
+ 78:b1:75:15:39:a1:da:2a:b0:d7:7c:52:11:8b:1a:
+ b0:46:19:fb:71:d0:8f:13:3d:2e:ee:bc:75:97:4d:
+ b1:b6:7b:d5:b6:36:44:5b:75:d1:00:b3:a3:60:9f:
+ 92:34:c1:50:52:30:89:54:35:24:fa:7d:ea:5a:32:
+ ca:11:aa:12:1c:55:74:fd:5b:98:ad:0d:04:d3:b3:
+ 12:cd:a4:f9:7c:54:e1:1f:01:cd:ad:c6:0e:cc:ae:
+ 8c:89:d3:ff:a6:f7:2b:9f:67:d8:55:c2:a9:4a:5f:
+ e8:d6:96:0d:14:68:79:23:84:d0:5f:59:99:f6:8e:
+ 9c:34:da:b6:d2:37:cc:de:8d:44:ba:e4:bb:f0:6f:
+ f1:60:d2:0d:22:28:41:98:e8:9a:dd:18:b5:30:45:
+ fd:3b:7a:27:0f:16:08:07:02:83:aa:e0:68:ba:47:
+ 44:48:84:ea:da:51:c1:ec:7b:cb:1e:25:11:3d:fd:
+ ce:53:1a:39:0a:fc:42:82:3d:cc:a5:93:00:c6:27:
+ 62:75
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- 09:87:C1:14:11:81:04:D8:AF:CF:66:4A:4F:8D:1C:A5:BB:04:CF:DA
+ 58:20:BB:27:E1:6D:B0:95:1A:D3:40:A1:81:79:89:63:34:21:9F:13
X509v3 Authority Key Identifier:
- keyid:A4:9D:E4:F8:B0:AF:D5:A4:2F:B9:3F:42:B8:C3:D5:60:9D:64:C2:8C
+ keyid:7A:3D:6D:AF:22:3F:64:CA:5C:C8:B3:3D:D5:E5:3B:32:A0:02:CF:29
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -235,41 +235,41 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
Signature Algorithm: sha256WithRSAEncryption
- 7d:97:b6:93:81:ef:63:d9:d6:31:8d:ba:e0:61:36:7c:06:cd:
- b5:2f:3f:4a:04:84:c2:c4:51:07:49:55:53:4f:22:b6:2f:15:
- d9:62:8a:65:97:15:84:a1:e2:2e:4e:66:59:02:b2:8f:b6:d6:
- 84:d6:ed:d4:df:45:a3:75:93:58:88:76:8d:6c:01:81:cc:c5:
- 91:99:cc:9c:65:f9:c9:f0:86:ed:3a:fe:d0:a0:2e:6c:04:d2:
- 49:f8:d4:31:9f:ce:db:93:bb:5a:73:4d:5d:24:83:4b:55:fe:
- 49:79:67:64:83:18:56:d9:ad:90:96:0b:ab:49:de:08:80:7a:
- 93:54:b1:38:19:c2:0b:6f:e1:b1:50:52:19:67:15:a9:aa:5a:
- c5:ed:73:30:63:1a:64:24:d4:8b:95:c9:c4:54:78:62:ce:42:
- f7:98:f1:94:2e:4d:93:7e:df:6f:cd:6f:41:c4:ef:c8:ed:f7:
- 73:92:af:ee:19:b5:e5:47:82:f7:47:41:35:29:8c:88:3b:62:
- 18:c0:f6:80:56:3f:f8:9e:b4:6e:33:2c:ce:41:da:56:83:c7:
- c7:30:c6:0f:f5:49:f5:79:d6:7b:c5:33:4c:0f:2a:e9:13:27:
- 0b:e3:b8:63:74:14:c0:2e:19:24:00:a4:f8:17:d7:cd:b5:1b:
- c1:38:25:9a
+ 37:db:eb:ca:f7:4c:e8:8d:30:46:40:83:77:7b:84:85:66:06:
+ 20:10:22:e9:f3:f0:5e:41:27:7d:dd:01:2a:c0:20:74:a6:f5:
+ d3:30:01:40:4a:4c:60:b0:9d:da:2f:71:90:c5:19:97:cc:af:
+ a2:e3:cc:fe:6e:e6:fa:5d:11:50:e6:ef:a9:b0:15:f8:da:26:
+ 51:b9:2e:1e:82:44:ec:13:e5:8d:27:2d:b1:31:97:cd:43:04:
+ 8a:70:ca:51:e3:2c:9e:93:9a:48:36:a1:46:56:08:e1:43:1c:
+ d7:96:aa:44:c2:3a:a2:e7:91:ac:91:28:fb:03:9c:e7:13:d1:
+ eb:c0:33:7b:3b:ff:c2:fc:af:68:36:54:57:f4:b8:2a:9d:de:
+ 78:3c:8e:ad:0d:d8:dd:4b:e7:50:41:0a:ae:7a:08:d7:5e:3b:
+ 2a:71:d5:88:ec:99:02:b3:cd:5a:31:26:41:79:e2:3a:49:55:
+ 40:7f:26:7f:34:f6:7a:76:28:5e:3d:e9:20:1e:a2:f4:6b:d5:
+ e0:6d:bd:2e:30:1a:69:70:ae:03:d3:ce:b3:76:04:2f:ef:86:
+ 4f:77:44:19:6f:94:6a:09:86:60:28:75:63:22:3a:13:5a:d5:
+ 13:af:23:08:9c:1f:0d:dc:0f:62:b4:97:85:05:5a:ea:c5:60:
+ 8a:02:4d:51
-----BEGIN CERTIFICATE-----
MIIDcTCCAlmgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowGDEWMBQGA1UEAwwNSW50
-ZXJtZWRpYXJ5MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKvpoChn
-OBNyEqA78vkTwivBogfmRTXP/xpGsNJYEmP8PbOFUGicVyH/Mf8kSNsT3rH0+Dl6
-8zTdUVgaEnOdheDQ+L79neI0zjbgoEhTNiO/UtKs2tHvbNqfETts4Wdq8d+XLBoS
-x8NyD5ghakAr8Ci4wu9/y+566Y8X/gqh/9UVTGNbU1UVAbldkXewIwMORQCEUjMr
-EVGZ6A1bRe/S4skOoq5DwpJcsDZ2BiGR0ELoD2+AYZgSpsDDt2R+dwx2Eh9Qc/i7
-KBpde2g2AfoJ55qQtsU96Rage8J2GfDpvBUNVd/qZyqy4Gn4wUnEplHpQ9LfKt7j
-oGY/DBi4+I27QxUCAwEAAaOBzjCByzAdBgNVHQ4EFgQUCYfBFBGBBNivz2ZKT40c
-pbsEz9owHwYDVR0jBBgwFoAUpJ3k+LCv1aQvuT9CuMPVYJ1kwowwNwYIKwYBBQUH
+ZXJtZWRpYXRlMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOZlU9Eu
+Tq0o/wUTG2QIqua3RGSUTA6kaIASfQfOauzIS8yhP6/0yEUOsmZGs/3vaF0EwJXp
+cUWyJhIWeLF1FTmh2iqw13xSEYsasEYZ+3HQjxM9Lu68dZdNsbZ71bY2RFt10QCz
+o2CfkjTBUFIwiVQ1JPp96loyyhGqEhxVdP1bmK0NBNOzEs2k+XxU4R8Bza3GDsyu
+jInT/6b3K59n2FXCqUpf6NaWDRRoeSOE0F9ZmfaOnDTattI3zN6NRLrku/Bv8WDS
+DSIoQZjomt0YtTBF/Tt6Jw8WCAcCg6rgaLpHREiE6tpRwex7yx4lET39zlMaOQr8
+QoI9zKWTAMYnYnUCAwEAAaOBzjCByzAdBgNVHQ4EFgQUWCC7J+FtsJUa00ChgXmJ
+YzQhnxMwHwYDVR0jBBgwFoAUej1tryI/ZMpcyLM91eU7MqACzykwNwYIKwYBBQUH
AQEEKzApMCcGCCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIw
LAYDVR0fBCUwIzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4G
A1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBCwUA
-A4IBAQB9l7aTge9j2dYxjbrgYTZ8Bs21Lz9KBITCxFEHSVVTTyK2LxXZYopllxWE
-oeIuTmZZArKPttaE1u3U30WjdZNYiHaNbAGBzMWRmcycZfnJ8IbtOv7QoC5sBNJJ
-+NQxn87bk7tac01dJINLVf5JeWdkgxhW2a2QlgurSd4IgHqTVLE4GcILb+GxUFIZ
-ZxWpqlrF7XMwYxpkJNSLlcnEVHhizkL3mPGULk2Tft9vzW9BxO/I7fdzkq/uGbXl
-R4L3R0E1KYyIO2IYwPaAVj/4nrRuMyzOQdpWg8fHMMYP9Un1edZ7xTNMDyrpEycL
-47hjdBTALhkkAKT4F9fNtRvBOCWa
+A4IBAQA32+vK90zojTBGQIN3e4SFZgYgECLp8/BeQSd93QEqwCB0pvXTMAFASkxg
+sJ3aL3GQxRmXzK+i48z+bub6XRFQ5u+psBX42iZRuS4egkTsE+WNJy2xMZfNQwSK
+cMpR4yyek5pINqFGVgjhQxzXlqpEwjqi55GskSj7A5znE9HrwDN7O//C/K9oNlRX
+9Lgqnd54PI6tDdjdS+dQQQquegjXXjsqcdWI7JkCs81aMSZBeeI6SVVAfyZ/NPZ6
+dihePekgHqL0a9Xgbb0uMBppcK4D086zdgQv74ZPd0QZb5RqCYZgKHVjIjoTWtUT
+ryMInB8N3A9itJeFBVrqxWCKAk1R
-----END CERTIFICATE-----
Certificate:
@@ -286,30 +286,30 @@ Certificate:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
- 00:9e:1f:9a:ec:aa:50:56:02:47:76:c8:ff:b9:91:
- c0:58:8d:08:b9:87:d9:ac:9e:7c:6e:2e:b7:60:68:
- d6:ab:1c:3d:f3:e2:a8:e6:05:58:ff:52:27:7c:f9:
- 7e:96:2d:19:71:35:84:eb:8d:3c:db:27:f7:5f:2f:
- d1:56:af:73:a8:26:84:f5:bb:7f:7a:7c:40:81:66:
- e9:e5:c1:53:eb:ac:d5:65:47:3d:a1:0a:67:c6:c8:
- 3b:cb:2f:a9:1e:9c:d5:30:6b:7b:50:cb:ad:46:6b:
- 33:44:91:14:94:20:ad:e2:79:1b:62:bb:1d:7e:a7:
- 2a:45:03:4b:d4:64:1b:15:82:c6:dc:cb:48:84:c5:
- 77:22:2a:20:6d:d8:bd:25:8d:55:11:95:46:73:97:
- fa:53:66:2e:ec:1a:73:66:09:f7:ef:e4:f8:df:ea:
- ce:90:c8:f8:38:67:bb:3c:c2:48:e7:69:01:98:6b:
- c1:3e:8f:17:05:0f:c0:d0:eb:49:f1:c7:ab:c6:07:
- 49:85:a7:57:ac:11:42:e5:de:bf:a1:65:4b:e6:ba:
- e8:44:64:2d:84:d8:a4:4a:ba:62:56:76:49:bf:67:
- 19:91:e1:29:e9:fb:aa:de:ef:df:58:01:08:65:14:
- 8e:71:b5:3b:43:fb:6c:65:9a:d6:6e:42:65:24:2d:
- f4:99
+ 00:cd:87:9d:f4:66:f8:77:5c:e3:56:6d:cb:12:dc:
+ a9:36:79:d5:1b:11:9f:92:20:8d:e6:d7:7d:41:8e:
+ 90:90:2a:a8:63:3d:59:25:a6:7a:86:73:7f:10:da:
+ 9f:c1:a5:69:4d:a3:67:61:b8:f8:9b:9b:ec:4a:3a:
+ f1:73:f1:83:c4:ab:34:1f:0b:ed:05:f3:6d:c5:ee:
+ 64:18:34:69:5f:09:1f:48:e5:d2:2d:12:4c:17:a3:
+ 7e:74:9f:93:04:ea:00:15:e3:b9:0d:ef:c5:ed:19:
+ 97:2b:12:05:7f:5c:32:2d:c5:30:46:7c:a7:02:27:
+ 29:b2:99:e1:43:95:f6:67:1c:ee:ad:9b:8e:fb:f8:
+ 57:1a:47:13:5a:1a:2f:27:e8:d5:03:2a:e5:f9:92:
+ 53:1d:03:5f:d6:2f:18:65:ce:3a:6e:ab:bf:b6:c5:
+ 72:e1:c9:a0:d6:3c:a2:8e:4f:3e:8f:06:52:19:a8:
+ 1a:f0:06:55:d2:f9:be:23:27:0a:de:33:26:ec:a0:
+ 41:d3:6b:56:25:70:09:ac:28:45:82:33:cb:db:85:
+ 59:50:61:9c:12:e0:04:cc:c5:81:3c:77:d7:9d:8e:
+ 59:d3:70:4d:4e:47:0a:f7:ef:6c:33:54:db:61:ee:
+ 31:cb:8d:43:59:ec:a1:3d:a4:c6:06:6e:05:b2:14:
+ d6:ad
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
- A4:9D:E4:F8:B0:AF:D5:A4:2F:B9:3F:42:B8:C3:D5:60:9D:64:C2:8C
+ 7A:3D:6D:AF:22:3F:64:CA:5C:C8:B3:3D:D5:E5:3B:32:A0:02:CF:29
X509v3 Authority Key Identifier:
- keyid:A4:9D:E4:F8:B0:AF:D5:A4:2F:B9:3F:42:B8:C3:D5:60:9D:64:C2:8C
+ keyid:7A:3D:6D:AF:22:3F:64:CA:5C:C8:B3:3D:D5:E5:3B:32:A0:02:CF:29
Authority Information Access:
CA Issuers - URI:http://url-for-aia/Root.cer
@@ -324,47 +324,57 @@ Certificate:
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
- 39:75:b8:af:a2:4e:d6:2f:15:08:4e:6d:06:1f:e7:65:29:96:
- c2:77:96:ed:1b:b2:48:e3:f9:cf:fd:8c:40:d1:67:37:1a:7c:
- e8:40:f0:ca:ee:72:9e:ef:6d:eb:e7:e9:5c:c4:61:e5:65:0e:
- 25:62:8e:ca:b1:5d:08:d2:21:6d:cb:0f:d6:f3:41:4a:66:56:
- 5b:06:3a:a7:6e:df:ad:6c:4d:18:01:95:b4:c9:7e:f4:80:e7:
- 75:17:e0:41:25:7e:03:1b:5b:bd:a0:2d:1c:f8:f5:18:e6:0b:
- 4c:69:7e:aa:54:78:f3:b4:84:b8:eb:8c:37:e9:60:dd:df:b8:
- f8:43:57:37:99:db:b1:ed:99:2e:1f:f2:af:94:33:97:86:83:
- 58:6d:e6:37:56:36:f8:68:e6:32:70:3f:5b:9b:13:75:a5:fc:
- c0:5a:e5:61:61:37:d2:b6:d8:d5:5c:55:21:d5:8e:3a:ed:bf:
- 83:81:76:e7:71:2b:3f:5b:0f:77:43:20:3a:d2:f6:ef:53:c8:
- 29:19:2c:0a:4d:a6:2e:fb:9b:3b:10:73:e1:dc:ac:0e:8d:e4:
- bd:36:da:e9:1e:0a:e6:57:b4:1d:ea:d8:cd:a0:dd:e3:88:8d:
- a5:b4:43:7f:fd:b1:3c:29:e5:6a:b4:c9:4e:e6:77:83:ae:c6:
- f7:04:47:a2
------BEGIN TRUSTED_CERTIFICATE-----
+ 20:3e:c4:b6:78:84:bd:36:33:6b:38:8e:f2:1f:1a:46:a7:d9:
+ 02:86:39:d2:3f:14:bd:a9:82:21:b0:9d:da:a9:4f:0a:e8:65:
+ 0b:7f:b7:cd:d9:3c:de:7f:08:d6:d9:60:ba:b2:be:4d:8a:77:
+ e4:4d:fe:8c:5d:27:e6:8a:0c:6c:e1:3c:7b:e2:d2:4c:ac:34:
+ fe:1e:b1:28:e6:b7:49:a8:09:bf:67:80:0f:8f:02:49:d4:52:
+ 6e:bf:d1:a7:b8:b4:22:90:f8:83:d5:85:7f:46:99:2d:df:cb:
+ 56:31:0c:0e:92:9b:eb:28:6e:c2:7c:ba:37:5d:3f:f0:f8:b5:
+ e2:0a:02:ea:78:c3:5c:8d:24:92:95:52:bf:68:3e:2b:fc:17:
+ bc:bb:3c:7c:38:f8:6e:5f:d3:1d:9e:4c:c5:3a:47:93:4d:a6:
+ c2:00:f2:2a:7a:a1:f0:76:48:5a:ef:77:1c:47:10:40:d8:d5:
+ 84:45:13:f6:5e:7c:d2:0e:bd:e3:e3:b1:3d:d5:93:e1:c4:95:
+ a1:ba:84:0d:a0:1c:b0:cd:b6:b4:a2:52:2e:37:c2:f3:30:3e:
+ 91:0b:24:9d:3d:77:02:ce:83:b0:73:21:ba:3f:f6:b9:c7:5d:
+ 08:5c:f0:33:8d:de:1e:56:e8:82:2f:5d:e6:8c:0c:ac:77:c7:
+ bf:91:2a:25
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ4fmuyqUFYCR3bI/7mR
-wFiNCLmH2ayefG4ut2Bo1qscPfPiqOYFWP9SJ3z5fpYtGXE1hOuNPNsn918v0Vav
-c6gmhPW7f3p8QIFm6eXBU+us1WVHPaEKZ8bIO8svqR6c1TBre1DLrUZrM0SRFJQg
-reJ5G2K7HX6nKkUDS9RkGxWCxtzLSITFdyIqIG3YvSWNVRGVRnOX+lNmLuwac2YJ
-9+/k+N/qzpDI+DhnuzzCSOdpAZhrwT6PFwUPwNDrSfHHq8YHSYWnV6wRQuXev6Fl
-S+a66ERkLYTYpEq6YlZ2Sb9nGZHhKen7qt7v31gBCGUUjnG1O0P7bGWa1m5CZSQt
-9JkCAwEAAaOByzCByDAdBgNVHQ4EFgQUpJ3k+LCv1aQvuT9CuMPVYJ1kwowwHwYD
-VR0jBBgwFoAUpJ3k+LCv1aQvuT9CuMPVYJ1kwowwNwYIKwYBBQUHAQEEKzApMCcG
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM2HnfRm+Hdc41ZtyxLc
+qTZ51RsRn5IgjebXfUGOkJAqqGM9WSWmeoZzfxDan8GlaU2jZ2G4+Jub7Eo68XPx
+g8SrNB8L7QXzbcXuZBg0aV8JH0jl0i0STBejfnSfkwTqABXjuQ3vxe0ZlysSBX9c
+Mi3FMEZ8pwInKbKZ4UOV9mcc7q2bjvv4VxpHE1oaLyfo1QMq5fmSUx0DX9YvGGXO
+Om6rv7bFcuHJoNY8oo5PPo8GUhmoGvAGVdL5viMnCt4zJuygQdNrViVwCawoRYIz
+y9uFWVBhnBLgBMzFgTx3152OWdNwTU5HCvfvbDNU22HuMcuNQ1nsoT2kxgZuBbIU
+1q0CAwEAAaOByzCByDAdBgNVHQ4EFgQUej1tryI/ZMpcyLM91eU7MqACzykwHwYD
+VR0jBBgwFoAUej1tryI/ZMpcyLM91eU7MqACzykwNwYIKwYBBQUHAQEEKzApMCcG
CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA5dbivok7W
-LxUITm0GH+dlKZbCd5btG7JI4/nP/YxA0Wc3GnzoQPDK7nKe723r5+lcxGHlZQ4l
-Yo7KsV0I0iFtyw/W80FKZlZbBjqnbt+tbE0YAZW0yX70gOd1F+BBJX4DG1u9oC0c
-+PUY5gtMaX6qVHjztIS464w36WDd37j4Q1c3mdux7ZkuH/KvlDOXhoNYbeY3Vjb4
-aOYycD9bmxN1pfzAWuVhYTfSttjVXFUh1Y467b+DgXbncSs/Ww93QyA60vbvU8gp
-GSwKTaYu+5s7EHPh3KwOjeS9NtrpHgrmV7Qd6tjNoN3jiI2ltEN//bE8KeVqtMlO
-5neDrsb3BEei
------END TRUSTED_CERTIFICATE-----
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAgPsS2eIS9
+NjNrOI7yHxpGp9kChjnSPxS9qYIhsJ3aqU8K6GULf7fN2TzefwjW2WC6sr5Ninfk
+Tf6MXSfmigxs4Tx74tJMrDT+HrEo5rdJqAm/Z4APjwJJ1FJuv9GnuLQikPiD1YV/
+Rpkt38tWMQwOkpvrKG7CfLo3XT/w+LXiCgLqeMNcjSSSlVK/aD4r/Be8uzx8OPhu
+X9MdnkzFOkeTTabCAPIqeqHwdkha73ccRxBA2NWERRP2XnzSDr3j47E91ZPhxJWh
+uoQNoBywzba0olIuN8LzMD6RCySdPXcCzoOwcyG6P/a5x10IXPAzjd4eVuiCL13m
+jAysd8e/kSol
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+150302120000Z
-----BEGIN TIME-----
MTUwMzAyMTIwMDAwWg==
-----END TIME-----
+FAIL
-----BEGIN VERIFY_RESULT-----
RkFJTA==
-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 1
+ [Error] max_path_length reached
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMQogICAgICBbRXJyb3JdIG1heF9wYXRoX2xlbmd0aCByZWFjaGVkCg==
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/violates-pathlen-1-constrained-root.pem b/chromium/net/data/verify_certificate_chain_unittest/violates-pathlen-1-constrained-root.pem
new file mode 100644
index 00000000000..60c04ac1e36
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/violates-pathlen-1-constrained-root.pem
@@ -0,0 +1,380 @@
+[Created by: generate-violates-pathlen-1-constrained-root.py]
+
+Certificate chain with 2 intermediates and one end entity certificate. The
+root certificate has a pathlen:1 restriction, and constraints are enforced
+on this trust anchor making it an invalid chain.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate2
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:b3:a3:d6:09:6c:d5:c4:2b:7b:c6:2d:9f:d3:91:
+ 39:f1:53:f0:93:49:96:8d:97:0c:d5:36:1d:7c:86:
+ 4f:2c:12:2c:5a:c9:32:b8:ff:21:71:f4:47:06:6f:
+ 30:08:2e:76:71:04:ec:f1:9d:f1:b0:59:36:03:64:
+ 1f:35:b0:a4:e6:ef:e6:aa:94:4e:d8:6e:aa:9f:92:
+ 63:a6:9a:42:47:fc:30:99:a5:c5:90:11:bb:b5:9d:
+ b1:b0:ec:12:c2:1f:29:42:57:d7:90:97:78:5f:5c:
+ 28:ab:49:7f:24:f3:2a:0f:68:a2:0a:e5:2a:54:8e:
+ 90:04:71:e2:13:9e:52:2e:c7:e6:ff:35:36:e7:01:
+ d7:2b:7f:5b:54:c0:20:e6:b3:09:16:e7:13:bb:96:
+ 3e:b7:45:3d:8d:5e:3b:6a:fe:c2:cb:5b:0d:bf:ed:
+ 92:98:74:9e:f1:7b:94:71:d0:b1:50:ec:81:06:3d:
+ 12:39:f2:00:d3:60:9c:3c:9c:5a:a1:58:cc:56:b1:
+ 4f:a7:a1:ec:c7:c5:52:70:81:99:99:a4:ef:de:f4:
+ 0d:c1:c5:ff:c6:83:c6:e8:d4:bd:f8:27:f9:86:e0:
+ 3c:d4:7b:31:17:4d:49:c8:ce:c0:27:6a:4f:0a:fb:
+ 79:75:93:47:b0:05:f8:2e:10:f4:0b:39:ce:f6:43:
+ 87:07
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ FD:9F:2A:24:CC:3C:CE:DA:6D:41:F0:3B:79:09:11:71:B2:29:31:17
+ X509v3 Authority Key Identifier:
+ keyid:4D:F0:7D:C0:A0:7D:84:3E:38:63:E2:76:18:78:25:8C:09:DD:12:36
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate2.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate2.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 2b:4d:3f:19:05:a2:6b:66:7e:85:21:18:9a:0c:f0:81:cd:f7:
+ 81:71:50:38:95:f4:d0:68:d6:e2:02:9b:f3:08:1e:8c:4a:57:
+ b6:2b:e3:57:7c:ca:70:74:48:ee:d6:5f:2e:f7:b5:fc:95:75:
+ fa:c3:1d:5c:e1:aa:dc:85:cc:4c:2f:a7:05:b6:4f:38:a7:50:
+ 44:8c:4a:1f:2c:fc:37:f4:96:a9:03:77:65:b0:5d:a4:36:f9:
+ 29:ab:6e:1e:64:47:9b:cd:89:45:85:84:d3:4a:0f:97:87:99:
+ 83:15:67:cb:42:80:69:8d:17:89:d0:1a:c5:e5:48:60:86:b3:
+ 20:2e:9a:40:7b:ec:90:53:fd:b4:6e:6b:d2:82:2b:5a:5c:e4:
+ fe:ee:16:ec:15:20:f8:4d:07:b6:f0:9a:95:6c:08:d4:d0:b2:
+ 09:3d:67:40:13:a6:5b:21:5f:03:4b:d7:c5:83:a9:2d:a1:1b:
+ 93:c6:5b:6d:36:85:f7:4c:9c:65:33:ab:e1:8f:e1:18:c1:6b:
+ ec:4c:c7:a4:de:8a:b8:a1:66:a3:94:e3:40:5e:8c:cd:42:e5:
+ f2:8a:e0:5b:19:01:5b:ba:74:eb:11:3b:ac:56:04:6b:a7:22:
+ 35:9b:ac:3e:da:12:3f:42:39:3d:7e:7d:ac:1e:3c:c6:7b:09:
+ 8f:97:f2:f2
+-----BEGIN CERTIFICATE-----
+MIIDkDCCAnigAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1JbnRl
+cm1lZGlhdGUyMB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowETEPMA0G
+A1UEAwwGVGFyZ2V0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs6PW
+CWzVxCt7xi2f05E58VPwk0mWjZcM1TYdfIZPLBIsWskyuP8hcfRHBm8wCC52cQTs
+8Z3xsFk2A2QfNbCk5u/mqpRO2G6qn5JjpppCR/wwmaXFkBG7tZ2xsOwSwh8pQlfX
+kJd4X1woq0l/JPMqD2iiCuUqVI6QBHHiE55SLsfm/zU25wHXK39bVMAg5rMJFucT
+u5Y+t0U9jV47av7Cy1sNv+2SmHSe8XuUcdCxUOyBBj0SOfIA02CcPJxaoVjMVrFP
+p6Hsx8VScIGZmaTv3vQNwcX/xoPG6NS9+Cf5huA81HsxF01JyM7AJ2pPCvt5dZNH
+sAX4LhD0CznO9kOHBwIDAQABo4HrMIHoMB0GA1UdDgQWBBT9nyokzDzO2m1B8Dt5
+CRFxsikxFzAfBgNVHSMEGDAWgBRN8H3AoH2EPjhj4nYYeCWMCd0SNjBABggrBgEF
+BQcBAQQ0MDIwMAYIKwYBBQUHMAKGJGh0dHA6Ly91cmwtZm9yLWFpYS9JbnRlcm1l
+ZGlhdGUyLmNlcjA1BgNVHR8ELjAsMCqgKKAmhiRodHRwOi8vdXJsLWZvci1jcmwv
+SW50ZXJtZWRpYXRlMi5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsG
+AQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAK00/GQWia2Z+hSEY
+mgzwgc33gXFQOJX00GjW4gKb8wgejEpXtivjV3zKcHRI7tZfLve1/JV1+sMdXOGq
+3IXMTC+nBbZPOKdQRIxKHyz8N/SWqQN3ZbBdpDb5KatuHmRHm82JRYWE00oPl4eZ
+gxVny0KAaY0XidAaxeVIYIazIC6aQHvskFP9tG5r0oIrWlzk/u4W7BUg+E0HtvCa
+lWwI1NCyCT1nQBOmWyFfA0vXxYOpLaEbk8ZbbTaF90ycZTOr4Y/hGMFr7EzHpN6K
+uKFmo5TjQF6MzULl8orgWxkBW7p06xE7rFYEa6ciNZusPtoSP0I5PX59rB48xnsJ
+j5fy8g==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate1
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c9:f0:db:40:19:44:5e:67:d4:e7:dd:4f:67:12:
+ 71:af:2a:42:76:de:6a:c0:ce:e6:9f:78:4e:90:f9:
+ 62:6a:14:9d:5e:63:3a:55:8e:88:a4:83:34:f6:f1:
+ 35:19:d1:fe:94:61:b6:9a:c6:b0:47:81:95:69:21:
+ ff:ca:c9:c9:79:4c:ac:ee:f6:08:ba:eb:ae:fe:96:
+ 8a:dc:97:11:c1:2f:8b:55:9f:58:cb:b1:8f:c3:2a:
+ 36:0b:4b:d2:17:36:45:0d:33:64:b0:58:27:45:a1:
+ 71:f1:db:2c:d7:de:6f:6d:f5:bc:38:62:c3:5a:9d:
+ f5:95:58:1d:ef:c2:00:6a:e5:c2:97:84:f7:ac:cc:
+ 19:18:f0:f8:cb:1a:b0:7b:b4:63:cc:35:5d:8c:cf:
+ f0:0c:a6:7e:fa:19:96:a9:dd:8a:26:ef:31:e9:38:
+ 44:11:62:ff:30:35:fe:86:2a:5f:52:20:93:2a:a8:
+ 5c:a9:c6:16:08:3e:c1:da:34:4e:83:28:a1:d4:6c:
+ 78:58:06:a0:ef:65:69:4c:19:65:0a:82:98:d4:cf:
+ 56:22:d2:47:b1:82:40:8f:fc:50:5d:52:c5:12:a8:
+ 0f:17:0c:18:3b:ef:9b:8c:3c:da:c4:c2:2d:63:44:
+ 59:08:8e:54:4a:5d:1d:e7:ba:2f:7a:d7:92:40:8d:
+ f4:9f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 4D:F0:7D:C0:A0:7D:84:3E:38:63:E2:76:18:78:25:8C:09:DD:12:36
+ X509v3 Authority Key Identifier:
+ keyid:C5:16:E8:6A:00:06:4F:0B:E0:6E:86:89:50:32:72:E0:22:08:AE:60
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate1.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate1.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 52:00:7b:6d:93:e0:12:f4:bd:3e:1e:67:ac:a2:a2:46:dd:68:
+ 7f:41:c5:7e:a4:04:07:d2:5b:1a:d3:26:b7:9d:6a:62:9c:51:
+ a5:19:55:7d:1d:42:4d:88:12:39:21:a5:fe:59:27:94:92:7c:
+ 4c:54:f6:85:f7:7d:3b:ac:23:51:63:67:05:66:b3:5e:4e:c2:
+ db:e9:33:e6:5a:7c:08:96:16:b9:33:af:83:02:15:d0:eb:2f:
+ 02:98:18:5a:53:ca:f5:ee:a8:3c:95:44:bd:c7:bf:47:f4:7b:
+ 22:e5:b2:df:ee:e1:e2:eb:50:89:a9:ad:72:e2:03:74:f7:82:
+ 90:2a:6e:36:39:f6:06:95:81:52:56:e1:7e:35:32:43:90:78:
+ 57:54:00:fc:df:39:e6:f6:92:d6:57:5d:01:ee:69:a0:fb:8c:
+ df:75:9b:8c:0e:e7:af:27:d4:11:01:c3:9d:56:7b:52:0b:06:
+ 57:1f:40:13:12:76:2a:40:b1:97:47:5f:6d:c4:5a:45:99:cd:
+ 96:61:ce:52:47:5f:8d:66:14:6d:a2:3c:bb:6e:0f:9c:3c:ba:
+ 9e:fb:75:92:32:eb:f3:71:16:d5:c6:84:e4:7d:c5:79:3f:ce:
+ 08:57:96:5b:56:c5:28:d5:96:41:f0:bc:a7:72:a1:18:6f:ab:
+ d9:e5:47:93
+-----BEGIN CERTIFICATE-----
+MIIDiTCCAnGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1JbnRl
+cm1lZGlhdGUxMB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowGDEWMBQG
+A1UEAwwNSW50ZXJtZWRpYXRlMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMnw20AZRF5n1OfdT2cSca8qQnbeasDO5p94TpD5YmoUnV5jOlWOiKSDNPbx
+NRnR/pRhtprGsEeBlWkh/8rJyXlMrO72CLrrrv6WityXEcEvi1WfWMuxj8MqNgtL
+0hc2RQ0zZLBYJ0WhcfHbLNfeb231vDhiw1qd9ZVYHe/CAGrlwpeE96zMGRjw+Msa
+sHu0Y8w1XYzP8AymfvoZlqndiibvMek4RBFi/zA1/oYqX1IgkyqoXKnGFgg+wdo0
+ToMoodRseFgGoO9laUwZZQqCmNTPViLSR7GCQI/8UF1SxRKoDxcMGDvvm4w82sTC
+LWNEWQiOVEpdHee6L3rXkkCN9J8CAwEAAaOB3TCB2jAdBgNVHQ4EFgQUTfB9wKB9
+hD44Y+J2GHgljAndEjYwHwYDVR0jBBgwFoAUxRboagAGTwvgboaJUDJy4CIIrmAw
+QAYIKwYBBQUHAQEENDAyMDAGCCsGAQUFBzAChiRodHRwOi8vdXJsLWZvci1haWEv
+SW50ZXJtZWRpYXRlMS5jZXIwNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL3VybC1m
+b3ItY3JsL0ludGVybWVkaWF0ZTEuY3JsMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
+Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBSAHttk+AS9L0+HmesoqJG3Wh/
+QcV+pAQH0lsa0ya3nWpinFGlGVV9HUJNiBI5IaX+WSeUknxMVPaF9307rCNRY2cF
+ZrNeTsLb6TPmWnwIlha5M6+DAhXQ6y8CmBhaU8r17qg8lUS9x79H9Hsi5bLf7uHi
+61CJqa1y4gN094KQKm42OfYGlYFSVuF+NTJDkHhXVAD83znm9pLWV10B7mmg+4zf
+dZuMDuevJ9QRAcOdVntSCwZXH0ATEnYqQLGXR19txFpFmc2WYc5SR1+NZhRtojy7
+bg+cPLqe+3WSMuvzcRbVxoTkfcV5P84IV5ZbVsUo1ZZB8LyncqEYb6vZ5UeT
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:e9:9a:81:41:08:cf:b0:5d:90:15:7b:33:d8:14:
+ e0:04:05:c4:86:6c:65:6d:fa:9c:cb:68:e8:d3:3f:
+ 1f:02:00:4c:b0:8d:21:ab:fb:f4:ea:e4:d5:10:84:
+ 73:99:ed:ac:1a:d8:96:66:21:0b:8a:40:56:54:37:
+ 1e:49:b4:96:d8:be:63:8a:b2:5c:16:a1:c6:79:d0:
+ 30:3d:ee:83:da:58:e3:cf:7b:fd:37:d6:29:74:6a:
+ 69:8a:62:9f:1a:6f:22:7b:2b:68:51:b8:af:91:d3:
+ 48:7a:a1:d1:cb:ea:d7:c2:54:f7:09:55:a4:7f:cf:
+ 33:87:43:80:bb:04:2d:be:77:ea:db:e4:59:a6:4b:
+ c4:9e:d4:6a:54:b6:45:4d:4e:28:c0:13:33:d2:0a:
+ 12:49:4a:d7:e0:60:a7:88:0b:3d:54:61:5a:e1:e5:
+ f3:56:56:42:f0:3c:4e:65:dc:b9:c3:07:7f:56:da:
+ 4a:45:c4:e4:ba:e7:66:e2:09:e3:4d:84:5d:24:af:
+ bc:d2:2b:24:39:e3:04:bd:7c:1d:cf:71:5b:60:64:
+ dc:f3:75:e3:18:44:3b:8f:b1:70:72:20:ab:da:30:
+ bb:18:0d:d1:ed:fd:e8:87:5c:58:2d:de:11:e6:e8:
+ 0a:99:66:fd:a3:c3:b9:6b:02:ac:07:0c:35:c1:90:
+ 66:2d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ C5:16:E8:6A:00:06:4F:0B:E0:6E:86:89:50:32:72:E0:22:08:AE:60
+ X509v3 Authority Key Identifier:
+ keyid:E8:DD:B2:61:D1:FC:02:1F:CD:68:F1:34:9D:6E:55:E7:97:B5:3A:23
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 68:ca:ff:4f:17:59:d1:14:01:ad:bd:21:09:39:d3:de:3f:9e:
+ 12:71:16:9c:49:f6:e1:2d:d2:d3:4f:93:d3:60:a0:6f:9e:ac:
+ 49:99:a2:2c:ad:fc:29:1a:e1:5a:6e:07:e8:83:67:67:e1:23:
+ c4:01:e2:b5:c3:c1:28:f3:71:3e:49:e7:1e:dc:ee:66:fb:eb:
+ 64:3d:5c:2f:e2:1d:fd:55:f6:98:ff:fc:af:82:aa:45:d0:be:
+ 89:bd:73:4b:87:fb:a8:9e:c7:03:75:77:7c:d1:8c:50:f0:03:
+ e2:7a:2e:f5:f8:dd:53:33:9f:86:d3:f3:32:83:d2:2a:70:67:
+ ca:8a:f1:df:15:b0:fd:38:bf:67:4e:22:e2:6f:73:6c:a6:b9:
+ 27:c9:89:ce:a3:9e:00:7c:82:55:44:d5:e6:2a:3d:1c:80:e1:
+ ef:37:f5:ab:e0:ea:25:b4:45:4c:28:50:2d:cb:ed:bb:6b:1d:
+ 06:3e:16:e4:f0:b8:15:16:6e:7a:91:cd:f3:1c:39:2c:ec:d3:
+ 7e:0b:e0:de:2a:f1:d5:27:78:a6:9c:3a:3f:b8:cc:b2:f6:9c:
+ 8f:f1:9b:ce:c6:67:eb:9f:f5:4b:39:87:89:ef:d2:2f:ba:73:
+ d8:af:cc:90:95:9d:95:e4:1c:a5:fb:3a:85:f6:f8:cc:69:ae:
+ 2e:6a:fc:6e
+-----BEGIN CERTIFICATE-----
+MIIDbjCCAlagAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowGDEWMBQGA1UEAwwNSW50
+ZXJtZWRpYXRlMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOmagUEI
+z7BdkBV7M9gU4AQFxIZsZW36nMto6NM/HwIATLCNIav79Ork1RCEc5ntrBrYlmYh
+C4pAVlQ3Hkm0lti+Y4qyXBahxnnQMD3ug9pY4897/TfWKXRqaYpinxpvInsraFG4
+r5HTSHqh0cvq18JU9wlVpH/PM4dDgLsELb536tvkWaZLxJ7UalS2RU1OKMATM9IK
+EklK1+Bgp4gLPVRhWuHl81ZWQvA8TmXcucMHf1baSkXE5LrnZuIJ402EXSSvvNIr
+JDnjBL18Hc9xW2Bk3PN14xhEO4+xcHIgq9owuxgN0e396IdcWC3eEeboCplm/aPD
+uWsCrAcMNcGQZi0CAwEAAaOByzCByDAdBgNVHQ4EFgQUxRboagAGTwvgboaJUDJy
+4CIIrmAwHwYDVR0jBBgwFoAU6N2yYdH8Ah/NaPE0nW5V55e1OiMwNwYIKwYBBQUH
+AQEEKzApMCcGCCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIw
+LAYDVR0fBCUwIzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4G
+A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IB
+AQBoyv9PF1nRFAGtvSEJOdPeP54ScRacSfbhLdLTT5PTYKBvnqxJmaIsrfwpGuFa
+bgfog2dn4SPEAeK1w8Eo83E+Sece3O5m++tkPVwv4h39VfaY//yvgqpF0L6JvXNL
+h/uonscDdXd80YxQ8APiei71+N1TM5+G0/Myg9IqcGfKivHfFbD9OL9nTiLib3Ns
+prknyYnOo54AfIJVRNXmKj0cgOHvN/Wr4OoltEVMKFAty+27ax0GPhbk8LgVFm56
+kc3zHDks7NN+C+DeKvHVJ3imnDo/uMyy9pyP8ZvOxmfrn/VLOYeJ79IvunPYr8yQ
+lZ2V5Byl+zqF9vjMaa4uavxu
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ca:b8:37:0e:d3:aa:65:77:fd:8d:e5:02:89:2e:
+ 62:d3:50:7d:1b:05:5b:f1:d5:5d:b2:94:57:c2:c2:
+ 70:a5:fa:cb:02:e0:02:c0:d7:de:1b:2d:2d:b0:46:
+ 2e:d8:8e:69:7b:51:a7:cf:47:cf:bb:25:1e:ed:ed:
+ 67:ba:e8:a5:f7:85:59:d7:a2:fb:4f:55:00:22:05:
+ 84:e3:31:20:2b:e0:ff:72:9e:99:de:be:67:48:60:
+ ac:86:35:3a:da:85:06:5b:92:29:7c:da:50:1c:e0:
+ 34:d8:5e:81:26:18:7e:de:07:20:c2:59:3b:43:f1:
+ bd:02:29:d4:ae:29:6e:bb:dc:be:48:2c:9a:15:18:
+ 33:86:6f:c3:26:2e:88:46:35:ce:92:b1:c2:a6:96:
+ cc:2c:e0:60:87:1f:9b:e2:a0:ce:7f:af:53:04:d8:
+ 24:cb:da:19:ca:3b:fe:02:f1:11:05:e7:40:af:2d:
+ eb:df:c4:53:1e:64:5a:73:b5:93:42:46:64:72:a5:
+ d9:d4:e0:70:65:f5:89:c3:07:83:17:0d:83:a8:aa:
+ 69:b5:56:57:20:1b:38:49:72:16:fb:a0:b4:d9:55:
+ 32:0a:e7:1c:1f:ec:3d:fc:7a:b9:81:02:d8:9e:57:
+ cd:97:18:16:6e:de:36:fe:d2:63:73:b3:8a:6e:57:
+ 93:a9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ E8:DD:B2:61:D1:FC:02:1F:CD:68:F1:34:9D:6E:55:E7:97:B5:3A:23
+ X509v3 Authority Key Identifier:
+ keyid:E8:DD:B2:61:D1:FC:02:1F:CD:68:F1:34:9D:6E:55:E7:97:B5:3A:23
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE, pathlen:1
+ Signature Algorithm: sha256WithRSAEncryption
+ a5:51:20:51:70:47:97:be:a8:b8:d8:76:64:ac:f1:47:36:3c:
+ 4d:c2:d1:b1:23:81:dc:2e:c0:36:d1:83:97:af:94:c3:46:fd:
+ bb:5e:9b:ca:e2:42:06:bb:ff:d4:68:f0:53:7f:96:43:cb:6f:
+ 24:09:53:a0:fb:d2:79:10:0f:f9:f8:3d:04:cb:23:40:50:37:
+ 5a:29:67:da:8a:b7:30:5b:62:b2:62:ce:70:43:81:29:c1:79:
+ 91:c8:b6:80:76:cf:93:45:70:ee:6b:22:a1:69:29:a6:e3:62:
+ d0:3d:27:67:86:26:dc:71:49:e3:1a:98:05:63:26:d8:e5:80:
+ b7:d9:38:db:1b:97:fc:0b:97:1f:5a:59:24:ea:6c:f6:c2:f6:
+ c1:ee:b8:02:48:1a:23:97:1d:3f:24:45:9c:f4:37:6f:ee:73:
+ 1b:bf:d3:c1:ed:a1:50:37:48:28:2f:ee:68:bc:d6:a8:35:a5:
+ 1c:00:a1:52:29:b5:a4:2a:79:f4:f9:a0:a5:30:6f:3f:01:ca:
+ 47:f0:08:8a:3f:3e:a9:bf:3e:4c:ef:e3:c3:ec:35:c5:5b:f3:
+ 58:18:80:be:08:e9:c2:77:a6:17:5c:62:3c:77:fe:a6:69:0e:
+ de:ca:96:dd:ed:13:01:ef:20:85:2f:94:a2:7d:30:df:c5:4d:
+ 84:e2:4d:1c
+-----BEGIN TRUST_ANCHOR_CONSTRAINED-----
+MIIDaDCCAlCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMq4Nw7TqmV3/Y3lAoku
+YtNQfRsFW/HVXbKUV8LCcKX6ywLgAsDX3hstLbBGLtiOaXtRp89Hz7slHu3tZ7ro
+pfeFWdei+09VACIFhOMxICvg/3Kemd6+Z0hgrIY1OtqFBluSKXzaUBzgNNhegSYY
+ft4HIMJZO0PxvQIp1K4pbrvcvkgsmhUYM4ZvwyYuiEY1zpKxwqaWzCzgYIcfm+Kg
+zn+vUwTYJMvaGco7/gLxEQXnQK8t69/EUx5kWnO1k0JGZHKl2dTgcGX1icMHgxcN
+g6iqabVWVyAbOElyFvugtNlVMgrnHB/sPfx6uYEC2J5XzZcYFm7eNv7SY3Ozim5X
+k6kCAwEAAaOBzjCByzAdBgNVHQ4EFgQU6N2yYdH8Ah/NaPE0nW5V55e1OiMwHwYD
+VR0jBBgwFoAU6N2yYdH8Ah/NaPE0nW5V55e1OiMwNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQClUSBR
+cEeXvqi42HZkrPFHNjxNwtGxI4HcLsA20YOXr5TDRv27XpvK4kIGu//UaPBTf5ZD
+y28kCVOg+9J5EA/5+D0EyyNAUDdaKWfaircwW2KyYs5wQ4EpwXmRyLaAds+TRXDu
+ayKhaSmm42LQPSdnhibccUnjGpgFYybY5YC32TjbG5f8C5cfWlkk6mz2wvbB7rgC
+SBojlx0/JEWc9Ddv7nMbv9PB7aFQN0goL+5ovNaoNaUcAKFSKbWkKnn0+aClMG8/
+AcpH8AiKPz6pvz5M7+PD7DXFW/NYGIC+COnCd6YXXGI8d/6maQ7eypbd7RMB7yCF
+L5SifTDfxU2E4k0c
+-----END TRUST_ANCHOR_CONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+FAIL
+-----BEGIN VERIFY_RESULT-----
+RkFJTA==
+-----END VERIFY_RESULT-----
+
+[Context] Processing Certificate
+ index: 1
+ [Error] max_path_length reached
+
+-----BEGIN ERRORS-----
+W0NvbnRleHRdIFByb2Nlc3NpbmcgQ2VydGlmaWNhdGUKICBpbmRleDogMQogICAgICBbRXJyb3JdIG1heF9wYXRoX2xlbmd0aCByZWFjaGVkCg==
+-----END ERRORS-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/violates-pathlen-1-root.pem b/chromium/net/data/verify_certificate_chain_unittest/violates-pathlen-1-root.pem
deleted file mode 100644
index c639e56f786..00000000000
--- a/chromium/net/data/verify_certificate_chain_unittest/violates-pathlen-1-root.pem
+++ /dev/null
@@ -1,369 +0,0 @@
-[Created by: generate-violates-pathlen-1-root.py]
-
-Certificate chain with 2 intermediaries and one end entity certificate. The
-root certificate has a pathlen:1 restriction so this is an invalid chain.
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary2
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Target
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:bf:b8:e9:8b:9f:2a:8d:58:f0:93:6a:7a:d2:d4:
- 29:ec:ce:35:c9:5e:c0:f7:27:2a:78:a3:76:53:25:
- 54:09:43:e0:30:df:a1:f3:e2:a2:45:21:d7:b0:e6:
- ff:d0:cc:81:eb:2b:78:9a:b6:85:97:87:d5:b2:9f:
- 3b:f2:d7:55:3d:fe:0f:ba:20:39:a6:0d:c8:7c:ea:
- 23:8a:63:38:8e:70:44:ff:d2:18:66:3e:ad:10:68:
- ee:ec:21:f7:18:e4:7f:37:09:c6:e6:a8:d1:a2:4c:
- 1f:e5:7a:69:04:13:df:09:5e:13:61:7c:15:09:9c:
- 55:af:27:66:87:0e:bd:fc:2a:9d:7f:1c:73:b5:84:
- c2:d6:2b:d9:5d:f6:19:52:58:bb:8c:8c:5f:a7:9c:
- de:d7:8d:5f:ef:8f:f3:24:e1:0d:10:59:58:c6:72:
- 8c:d7:fc:fe:bc:22:a7:58:4d:83:f2:48:4b:cd:55:
- 36:45:28:e4:cf:93:75:78:0f:5e:35:c0:b7:52:e5:
- e2:91:42:04:bb:9c:0c:cf:eb:89:66:5f:90:46:b2:
- 76:b0:82:c4:af:34:fd:a6:fd:93:7f:54:ce:4f:be:
- a4:32:8e:9c:3f:40:c9:6c:db:be:85:0c:e6:df:2b:
- 7c:9b:ef:8b:7a:4b:15:dc:09:10:3b:b1:b7:e7:c7:
- c1:21
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 11:74:6B:48:F5:42:3C:04:F3:A2:04:42:E5:F2:BC:1C:AD:AB:CB:E2
- X509v3 Authority Key Identifier:
- keyid:9A:80:A6:AF:E0:4A:48:D1:70:0A:10:7A:0D:74:57:B8:CE:48:5B:7D
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary2.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Intermediary2.crl
-
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage:
- TLS Web Server Authentication, TLS Web Client Authentication
- Signature Algorithm: sha256WithRSAEncryption
- 6e:0e:da:63:ae:72:b5:ee:9b:ee:f6:34:18:30:e5:4c:9b:b7:
- a8:21:ef:fe:fe:55:c9:27:4d:13:ab:32:be:89:76:93:b8:2a:
- be:c2:3f:6d:f6:23:6d:ed:b2:4f:77:7e:b7:7c:f4:5a:a3:de:
- 80:09:f6:c0:3b:87:34:2d:97:5c:1a:a0:0d:e4:9f:28:93:d4:
- d6:38:ca:ea:c8:4e:ec:71:07:b8:c7:cb:c0:59:77:e5:99:80:
- 34:7b:9f:77:8f:63:b0:d0:3d:ce:a9:c4:aa:ba:49:02:5e:31:
- 84:a3:7f:8e:51:5c:06:a4:44:49:04:c4:27:7e:04:f7:13:18:
- 61:67:d1:4d:23:b0:16:f2:47:79:bd:e5:40:52:77:06:73:8b:
- 4b:c6:c4:5c:09:46:29:a3:36:b5:3c:75:6d:94:71:13:db:ff:
- e8:62:e4:76:59:06:88:9d:c5:5b:d7:af:ae:16:72:80:60:6a:
- 23:01:4d:fa:90:33:ad:01:38:47:d6:5d:91:28:9f:78:6f:ba:
- da:62:5b:17:fa:9f:5a:6e:28:5f:59:96:de:64:a8:3b:b7:de:
- fe:f7:b5:3c:79:e9:fe:15:b2:73:0f:65:5f:83:2e:6b:85:55:
- 04:42:da:87:48:6b:7d:1c:a2:b0:e2:60:7f:c9:22:70:d1:a4:
- 51:94:40:3c
------BEGIN CERTIFICATE-----
-MIIDkDCCAnigAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1JbnRl
-cm1lZGlhcnkyMB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowETEPMA0G
-A1UEAwwGVGFyZ2V0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv7jp
-i58qjVjwk2p60tQp7M41yV7A9ycqeKN2UyVUCUPgMN+h8+KiRSHXsOb/0MyB6yt4
-mraFl4fVsp878tdVPf4PuiA5pg3IfOojimM4jnBE/9IYZj6tEGju7CH3GOR/NwnG
-5qjRokwf5XppBBPfCV4TYXwVCZxVrydmhw69/CqdfxxztYTC1ivZXfYZUli7jIxf
-p5ze141f74/zJOENEFlYxnKM1/z+vCKnWE2D8khLzVU2RSjkz5N1eA9eNcC3UuXi
-kUIEu5wMz+uJZl+QRrJ2sILErzT9pv2Tf1TOT76kMo6cP0DJbNu+hQzm3yt8m++L
-eksV3AkQO7G358fBIQIDAQABo4HrMIHoMB0GA1UdDgQWBBQRdGtI9UI8BPOiBELl
-8rwcravL4jAfBgNVHSMEGDAWgBSagKav4EpI0XAKEHoNdFe4zkhbfTBABggrBgEF
-BQcBAQQ0MDIwMAYIKwYBBQUHMAKGJGh0dHA6Ly91cmwtZm9yLWFpYS9JbnRlcm1l
-ZGlhcnkyLmNlcjA1BgNVHR8ELjAsMCqgKKAmhiRodHRwOi8vdXJsLWZvci1jcmwv
-SW50ZXJtZWRpYXJ5Mi5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsG
-AQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAbg7aY65yte6b7vY0
-GDDlTJu3qCHv/v5VySdNE6syvol2k7gqvsI/bfYjbe2yT3d+t3z0WqPegAn2wDuH
-NC2XXBqgDeSfKJPU1jjK6shO7HEHuMfLwFl35ZmANHufd49jsNA9zqnEqrpJAl4x
-hKN/jlFcBqRESQTEJ34E9xMYYWfRTSOwFvJHeb3lQFJ3BnOLS8bEXAlGKaM2tTx1
-bZRxE9v/6GLkdlkGiJ3FW9evrhZygGBqIwFN+pAzrQE4R9ZdkSifeG+62mJbF/qf
-Wm4oX1mW3mSoO7fe/ve1PHnp/hWycw9lX4Mua4VVBELah0hrfRyisOJgf8kicNGk
-UZRAPA==
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Intermediary1
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary2
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:9b:e8:f6:41:79:62:c9:06:fd:13:2c:f5:cc:07:
- a9:dd:5c:1e:90:76:a5:71:fa:f3:5c:34:1f:c9:3a:
- 33:77:05:a0:27:7b:6a:eb:8b:d8:de:25:65:6f:b6:
- d6:e1:82:34:0a:7b:13:d3:85:37:7d:d9:70:04:43:
- b3:e3:46:8b:60:e1:99:ba:28:5b:ef:c2:7e:b3:c4:
- 20:6f:94:f2:47:79:66:ce:0f:5d:79:58:aa:f7:62:
- 80:38:14:4a:17:34:59:86:39:1d:ed:38:b8:14:f4:
- 10:0c:1f:2c:8e:49:e5:5d:fd:d2:0f:37:5c:b8:e5:
- a9:86:07:0e:5e:27:ee:05:a0:ad:b5:b6:86:43:30:
- 8b:0d:35:b5:86:cd:98:98:e8:d6:04:53:4e:2b:81:
- be:d2:96:6f:cf:2f:72:2d:f5:6c:c8:ba:f5:42:7a:
- f1:67:33:03:bb:cf:6d:67:03:f3:1a:3c:39:d9:cf:
- 8f:ad:03:ca:2c:dc:e3:33:92:24:18:46:86:8e:dc:
- 27:b8:76:57:3a:7d:a2:89:96:18:07:96:04:d9:75:
- 8c:e6:1b:cf:1f:e9:6c:5d:8d:77:2f:4d:9d:00:bb:
- 16:e9:c5:da:7d:5f:45:e8:3d:17:d8:72:a6:bf:68:
- 1f:0a:a5:88:c1:74:45:53:b9:0c:d5:05:a5:ba:ed:
- 55:73
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 9A:80:A6:AF:E0:4A:48:D1:70:0A:10:7A:0D:74:57:B8:CE:48:5B:7D
- X509v3 Authority Key Identifier:
- keyid:1D:4A:1C:48:70:30:B6:65:73:56:A7:6E:A0:48:35:81:6E:3B:95:8A
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Intermediary1.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Intermediary1.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- 47:1c:62:1b:7e:69:aa:b6:d8:6c:50:44:09:e8:15:b5:fe:ee:
- 86:5c:69:6d:4c:7a:90:1f:2e:4f:e8:21:a3:44:38:d6:07:0b:
- 43:cf:dd:13:64:64:42:a9:ae:62:f6:1b:ea:03:2e:3b:4f:ed:
- 8a:45:8e:ec:09:d8:1a:67:eb:ef:c6:77:fc:cf:03:9f:b4:4a:
- 59:76:4e:2b:b0:d3:41:5a:a0:8c:bb:1c:61:67:52:7d:48:2e:
- 3f:c2:7d:a6:60:95:25:75:47:9c:1a:c3:1e:25:cd:e9:7d:2b:
- 71:26:fc:97:f1:2e:c6:2f:d4:2a:bb:27:d4:76:7e:c9:bc:05:
- 92:24:86:56:46:27:e0:14:af:d7:c6:72:d2:dc:be:93:2f:b3:
- 44:d3:e1:4a:08:75:47:50:16:e6:50:36:61:e3:6f:b7:a6:40:
- 1c:61:14:ae:66:20:93:0b:fb:6d:b1:a9:4d:d5:ec:8d:2b:d6:
- 84:36:c4:61:70:e5:99:4f:7e:af:97:d2:42:91:11:a7:1f:0e:
- 32:fc:09:37:44:a2:c9:bb:35:82:73:85:e5:90:b4:80:a7:4b:
- 40:ce:cb:62:ca:e1:2b:36:f6:e7:bc:3a:67:71:6d:ab:4b:87:
- cf:72:70:ad:ef:7a:85:ab:72:5d:c7:c1:ac:5e:b5:81:dc:ff:
- 96:6f:08:02
------BEGIN CERTIFICATE-----
-MIIDiTCCAnGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1JbnRl
-cm1lZGlhcnkxMB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowGDEWMBQG
-A1UEAwwNSW50ZXJtZWRpYXJ5MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAJvo9kF5YskG/RMs9cwHqd1cHpB2pXH681w0H8k6M3cFoCd7auuL2N4lZW+2
-1uGCNAp7E9OFN33ZcARDs+NGi2DhmbooW+/CfrPEIG+U8kd5Zs4PXXlYqvdigDgU
-Shc0WYY5He04uBT0EAwfLI5J5V390g83XLjlqYYHDl4n7gWgrbW2hkMwiw01tYbN
-mJjo1gRTTiuBvtKWb88vci31bMi69UJ68WczA7vPbWcD8xo8OdnPj60Dyizc4zOS
-JBhGho7cJ7h2Vzp9oomWGAeWBNl1jOYbzx/pbF2Ndy9NnQC7FunF2n1fReg9F9hy
-pr9oHwqliMF0RVO5DNUFpbrtVXMCAwEAAaOB3TCB2jAdBgNVHQ4EFgQUmoCmr+BK
-SNFwChB6DXRXuM5IW30wHwYDVR0jBBgwFoAUHUocSHAwtmVzVqduoEg1gW47lYow
-QAYIKwYBBQUHAQEENDAyMDAGCCsGAQUFBzAChiRodHRwOi8vdXJsLWZvci1haWEv
-SW50ZXJtZWRpYXJ5MS5jZXIwNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL3VybC1m
-b3ItY3JsL0ludGVybWVkaWFyeTEuY3JsMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
-Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBHHGIbfmmqtthsUEQJ6BW1/u6G
-XGltTHqQHy5P6CGjRDjWBwtDz90TZGRCqa5i9hvqAy47T+2KRY7sCdgaZ+vvxnf8
-zwOftEpZdk4rsNNBWqCMuxxhZ1J9SC4/wn2mYJUldUecGsMeJc3pfStxJvyX8S7G
-L9QquyfUdn7JvAWSJIZWRifgFK/XxnLS3L6TL7NE0+FKCHVHUBbmUDZh42+3pkAc
-YRSuZiCTC/ttsalN1eyNK9aENsRhcOWZT36vl9JCkRGnHw4y/Ak3RKLJuzWCc4Xl
-kLSAp0tAzstiyuErNvbnvDpncW2rS4fPcnCt73qFq3Jdx8GsXrWB3P+WbwgC
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 2 (0x2)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Intermediary1
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:b9:d1:e1:e9:55:23:09:13:95:52:d6:31:f6:16:
- 49:28:4d:e9:02:bd:42:73:3b:f6:9a:d4:05:86:6e:
- fd:c4:26:b1:59:d5:e1:be:64:f0:84:39:f0:d9:cf:
- 0a:62:98:68:c6:7b:a1:6c:73:4c:79:5e:92:88:ba:
- db:e2:16:f9:0a:5b:46:f7:ef:6b:77:4b:98:d9:40:
- ca:1b:2d:7b:fa:9a:92:11:fe:85:6c:ef:2e:39:6f:
- 2f:16:32:cc:45:c7:a7:bd:62:2a:d7:49:9d:c1:cc:
- 0d:a8:b1:91:e0:f7:b8:e5:77:f4:0a:ef:01:de:e1:
- 65:4c:e0:e6:29:3f:2d:3f:aa:0d:a4:38:69:90:5d:
- 83:b4:e9:b0:04:c4:f4:a4:b9:5f:c0:a8:88:68:13:
- 86:a1:9b:fe:24:d3:ef:cc:34:be:3d:bb:70:58:64:
- 74:54:7d:c8:6a:a3:d3:37:9e:91:5c:fe:16:15:5f:
- 00:45:2f:f9:81:3a:7f:ef:bb:03:60:b8:08:ce:9f:
- 88:20:62:ba:4d:8a:18:8a:57:1d:ea:12:1e:62:d7:
- eb:01:80:e6:a9:72:d2:2f:84:aa:16:20:e8:f8:47:
- e1:4e:43:46:16:20:51:cd:20:39:a3:47:70:0f:9f:
- 4e:e6:7b:fa:5d:c2:9e:67:ce:22:e1:e8:1c:89:bd:
- a0:49
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 1D:4A:1C:48:70:30:B6:65:73:56:A7:6E:A0:48:35:81:6E:3B:95:8A
- X509v3 Authority Key Identifier:
- keyid:88:1C:D6:E6:0D:8F:83:DE:9D:9C:2E:3E:1E:E5:61:82:EA:2D:11:F6
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE
- Signature Algorithm: sha256WithRSAEncryption
- 7c:45:39:85:85:2e:2a:47:1a:05:7c:45:0b:9d:1c:94:58:c9:
- a6:ab:95:85:fb:64:da:a3:cf:96:98:80:8c:c4:fe:5d:10:db:
- 94:df:6c:eb:15:45:d3:e8:d1:80:39:0e:b9:28:4a:b8:0c:aa:
- 87:cc:4b:b2:14:4d:fe:2c:a6:36:5e:40:5c:10:49:e2:90:1d:
- 46:ad:d1:b5:25:85:35:3d:99:da:0b:da:ad:f0:9d:94:50:6e:
- b8:4c:1c:86:d6:68:cc:d9:7f:7e:b8:8d:0c:43:0c:e9:6a:05:
- 00:0e:7d:00:88:62:70:4f:f9:a1:68:48:9f:c4:c7:cd:78:63:
- c6:6c:ec:84:c3:09:65:64:14:27:f4:f9:df:a1:f4:bc:c1:43:
- 88:88:ba:98:ba:14:66:8a:47:42:49:dc:9a:35:84:e0:8b:17:
- 9e:5b:bd:8f:4f:b3:01:2e:61:3e:12:45:ab:63:38:77:b1:f2:
- 21:57:04:49:53:e4:23:4b:58:81:23:42:9a:a5:fe:1c:08:7b:
- d6:bf:7e:ec:9d:b1:15:b7:27:2a:f2:96:81:05:52:ad:97:92:
- 71:20:34:33:99:77:a3:e9:92:e1:68:73:ea:31:eb:54:cb:f9:
- 97:61:03:56:de:4c:35:c5:cd:d4:75:a7:e4:f2:5c:66:f5:5d:
- 34:ab:8f:f8
------BEGIN CERTIFICATE-----
-MIIDbjCCAlagAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowGDEWMBQGA1UEAwwNSW50
-ZXJtZWRpYXJ5MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALnR4elV
-IwkTlVLWMfYWSShN6QK9QnM79prUBYZu/cQmsVnV4b5k8IQ58NnPCmKYaMZ7oWxz
-THlekoi62+IW+QpbRvfva3dLmNlAyhste/qakhH+hWzvLjlvLxYyzEXHp71iKtdJ
-ncHMDaixkeD3uOV39ArvAd7hZUzg5ik/LT+qDaQ4aZBdg7TpsATE9KS5X8CoiGgT
-hqGb/iTT78w0vj27cFhkdFR9yGqj0zeekVz+FhVfAEUv+YE6f++7A2C4CM6fiCBi
-uk2KGIpXHeoSHmLX6wGA5qly0i+EqhYg6PhH4U5DRhYgUc0gOaNHcA+fTuZ7+l3C
-nmfOIuHoHIm9oEkCAwEAAaOByzCByDAdBgNVHQ4EFgQUHUocSHAwtmVzVqduoEg1
-gW47lYowHwYDVR0jBBgwFoAUiBzW5g2Pg96dnC4+HuVhguotEfYwNwYIKwYBBQUH
-AQEEKzApMCcGCCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIw
-LAYDVR0fBCUwIzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4G
-A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IB
-AQB8RTmFhS4qRxoFfEULnRyUWMmmq5WF+2Tao8+WmICMxP5dENuU32zrFUXT6NGA
-OQ65KEq4DKqHzEuyFE3+LKY2XkBcEEnikB1GrdG1JYU1PZnaC9qt8J2UUG64TByG
-1mjM2X9+uI0MQwzpagUADn0AiGJwT/mhaEifxMfNeGPGbOyEwwllZBQn9PnfofS8
-wUOIiLqYuhRmikdCSdyaNYTgixeeW72PT7MBLmE+EkWrYzh3sfIhVwRJU+QjS1iB
-I0Kapf4cCHvWv37snbEVtycq8paBBVKtl5JxIDQzmXej6ZLhaHPqMetUy/mXYQNW
-3kw1xc3Udafk8lxm9V00q4/4
------END CERTIFICATE-----
-
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: CN=Root
- Validity
- Not Before: Jan 1 12:00:00 2015 GMT
- Not After : Jan 1 12:00:00 2016 GMT
- Subject: CN=Root
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:a3:90:0c:56:93:34:da:26:53:6e:a9:d5:07:b9:
- 83:30:70:85:69:ed:18:67:72:bb:1d:c4:06:ff:a8:
- b8:00:75:fd:38:ac:f1:e2:4a:86:21:4d:01:77:fc:
- f3:2d:90:94:7e:14:2c:8a:89:c2:cd:42:a5:ae:fe:
- 7a:ca:9d:44:78:21:f6:ab:6d:d3:c8:8a:07:57:eb:
- 22:10:cf:1e:44:f2:a4:23:e7:10:46:1e:d4:21:60:
- 9c:01:72:ff:ca:20:c8:48:c4:ad:b0:17:28:f3:14:
- af:49:65:52:52:58:9a:1b:68:1a:9d:77:e9:61:52:
- 54:0b:81:e4:0b:c7:2d:b3:2d:aa:9e:16:1f:51:ec:
- 7d:e7:2d:2c:e6:c4:88:81:3e:1b:e1:e7:1f:21:12:
- 21:47:ec:14:a5:d9:ab:a2:2b:ac:1f:3c:b2:a5:c1:
- 69:4e:55:88:66:e8:5a:4d:9d:08:27:1c:fe:cd:62:
- b0:95:62:c4:4b:ff:12:11:4c:d8:10:66:a4:d0:29:
- da:d5:79:b7:ee:19:d5:b9:33:92:c5:61:89:56:a8:
- 4f:48:cf:9a:a0:3e:95:f0:1f:b7:c9:de:82:89:09:
- b0:87:a5:c5:71:2c:71:3b:72:4a:0a:51:c4:c4:7d:
- ac:84:c3:9b:60:3d:ff:0c:52:05:23:4d:57:57:06:
- 60:17
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- 88:1C:D6:E6:0D:8F:83:DE:9D:9C:2E:3E:1E:E5:61:82:EA:2D:11:F6
- X509v3 Authority Key Identifier:
- keyid:88:1C:D6:E6:0D:8F:83:DE:9D:9C:2E:3E:1E:E5:61:82:EA:2D:11:F6
-
- Authority Information Access:
- CA Issuers - URI:http://url-for-aia/Root.cer
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://url-for-crl/Root.crl
-
- X509v3 Key Usage: critical
- Certificate Sign, CRL Sign
- X509v3 Basic Constraints: critical
- CA:TRUE, pathlen:1
- Signature Algorithm: sha256WithRSAEncryption
- 2e:81:16:b6:af:49:9b:93:4d:84:34:9c:f0:43:ee:76:91:f5:
- 88:9e:6b:cd:a8:95:f2:5e:10:19:f0:41:98:b2:ac:38:2a:ac:
- 3e:4c:0f:49:0b:b9:fd:97:d3:c9:61:6c:8b:7d:26:06:1d:65:
- 7e:e8:92:23:07:82:cc:3c:c9:c7:32:7b:2e:e2:3e:e8:42:52:
- 29:9f:6d:8f:7d:34:57:37:7a:71:8f:f1:28:33:70:aa:59:88:
- 12:95:74:82:60:d0:14:50:b5:d4:5a:ad:7c:03:85:ab:84:c9:
- e5:bf:7a:4a:3e:1a:d0:44:0b:bc:e1:ae:3b:48:e9:00:1c:92:
- 1b:b5:40:a4:e6:65:88:ec:3b:6e:ab:da:37:10:b7:6d:45:e5:
- 70:89:eb:e4:21:68:2e:77:e6:de:25:e3:5d:7a:a0:f1:33:4c:
- cc:e2:8b:a9:c8:fd:dc:0b:4b:9e:4c:5c:7c:86:0f:d4:ab:f9:
- e0:c8:c0:82:76:38:55:d3:dc:4d:57:d0:ca:76:63:9f:92:5c:
- ff:5f:1b:bd:b6:39:5e:0f:5f:93:0b:86:23:9e:08:d3:e4:11:
- 02:5f:5f:bd:00:af:d3:22:c0:14:3a:f4:4b:8b:fb:be:5e:b7:
- 1c:34:e1:20:69:5d:7c:d9:f5:86:28:ab:92:a6:31:6b:fe:1d:
- 03:00:f0:89
------BEGIN TRUSTED_CERTIFICATE-----
-MIIDaDCCAlCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
-MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKOQDFaTNNomU26p1Qe5
-gzBwhWntGGdyux3EBv+ouAB1/Tis8eJKhiFNAXf88y2QlH4ULIqJws1Cpa7+esqd
-RHgh9qtt08iKB1frIhDPHkTypCPnEEYe1CFgnAFy/8ogyEjErbAXKPMUr0llUlJY
-mhtoGp136WFSVAuB5AvHLbMtqp4WH1HsfectLObEiIE+G+HnHyESIUfsFKXZq6Ir
-rB88sqXBaU5ViGboWk2dCCcc/s1isJVixEv/EhFM2BBmpNAp2tV5t+4Z1bkzksVh
-iVaoT0jPmqA+lfAft8negokJsIelxXEscTtySgpRxMR9rITDm2A9/wxSBSNNV1cG
-YBcCAwEAAaOBzjCByzAdBgNVHQ4EFgQUiBzW5g2Pg96dnC4+HuVhguotEfYwHwYD
-VR0jBBgwFoAUiBzW5g2Pg96dnC4+HuVhguotEfYwNwYIKwYBBQUHAQEEKzApMCcG
-CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
-IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
-AwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQAugRa2
-r0mbk02ENJzwQ+52kfWInmvNqJXyXhAZ8EGYsqw4Kqw+TA9JC7n9l9PJYWyLfSYG
-HWV+6JIjB4LMPMnHMnsu4j7oQlIpn22PfTRXN3pxj/EoM3CqWYgSlXSCYNAUULXU
-Wq18A4WrhMnlv3pKPhrQRAu84a47SOkAHJIbtUCk5mWI7Dtuq9o3ELdtReVwievk
-IWgud+beJeNdeqDxM0zM4oupyP3cC0ueTFx8hg/Uq/ngyMCCdjhV09xNV9DKdmOf
-klz/Xxu9tjleD1+TC4YjngjT5BECX1+9AK/TIsAUOvRLi/u+XrccNOEgaV182fWG
-KKuSpjFr/h0DAPCJ
------END TRUSTED_CERTIFICATE-----
-
------BEGIN TIME-----
-MTUwMzAyMTIwMDAwWg==
------END TIME-----
-
------BEGIN VERIFY_RESULT-----
-RkFJTA==
------END VERIFY_RESULT-----
diff --git a/chromium/net/data/verify_certificate_chain_unittest/violates-pathlen-1-unconstrained-root.pem b/chromium/net/data/verify_certificate_chain_unittest/violates-pathlen-1-unconstrained-root.pem
new file mode 100644
index 00000000000..a9f4c307f54
--- /dev/null
+++ b/chromium/net/data/verify_certificate_chain_unittest/violates-pathlen-1-unconstrained-root.pem
@@ -0,0 +1,372 @@
+[Created by: generate-violates-pathlen-1-unconstrained-root.py]
+
+Certificate chain with 2 intermediates and one end entity certificate. The
+root certificate has a pathlen:1 restriction. Ordinarily this would be an
+invalid chain, however constraints on this trust anchor are not enforced.
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate2
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Target
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:c7:02:89:18:09:bc:9f:9c:9a:41:35:a9:5f:f7:
+ c2:22:3e:b2:39:fe:ba:57:1d:95:2e:dd:65:23:45:
+ ce:33:77:99:dd:f1:d7:69:0b:fb:a7:0e:89:98:02:
+ 7a:94:58:7b:61:e6:10:98:69:1a:09:2b:9f:73:3a:
+ d8:70:18:64:e2:8a:85:87:c5:69:f3:45:1e:70:d8:
+ c0:5e:23:6c:a6:7d:8f:77:23:8a:5d:74:a0:0b:d5:
+ 7f:a7:dd:f5:21:2d:02:c2:0f:e0:c8:f8:29:20:f5:
+ 5e:33:58:2a:38:c8:41:a6:25:66:ac:cf:c4:03:cb:
+ 03:25:db:e6:65:3d:bd:ab:da:fb:8f:b5:0e:d8:ba:
+ 3d:14:2b:9b:07:62:13:d4:1c:ea:b1:d5:7d:4d:54:
+ 04:c0:13:fb:d1:df:c2:36:e3:00:cf:fa:49:0b:44:
+ 9c:05:80:19:75:02:25:41:3d:e0:e6:cd:87:d8:63:
+ d7:84:3d:0c:3a:c8:ec:e8:58:22:62:2f:18:e9:ad:
+ 45:ce:b8:a6:63:c2:65:29:69:1e:21:08:8d:3a:da:
+ 96:e0:89:27:09:cc:35:e9:f1:f0:d8:f3:61:c5:05:
+ 3e:b1:d0:00:3c:7e:25:4a:36:e3:1d:b4:95:37:2d:
+ 44:ac:9e:79:38:67:e7:c7:ac:0c:71:d3:d1:60:86:
+ 44:09
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ C6:CC:7E:B5:7C:7A:51:EC:1C:35:E1:CD:3C:A7:FC:06:31:53:CA:06
+ X509v3 Authority Key Identifier:
+ keyid:48:BF:34:63:E8:E4:FB:87:49:F2:0E:A0:23:38:D2:BE:6A:3D:45:3C
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate2.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate2.crl
+
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ Signature Algorithm: sha256WithRSAEncryption
+ 51:8c:f9:c8:cb:cc:14:e3:54:cd:63:1a:f0:1e:0b:a3:6e:60:
+ 99:68:06:fe:e6:97:f5:68:e7:d8:7a:e1:b1:78:48:3e:03:57:
+ e4:84:5a:24:08:47:9f:fb:73:1a:7f:76:66:40:5d:ac:2f:f4:
+ f0:9e:b1:21:b0:15:5f:d1:68:4a:b6:fe:84:23:05:51:7d:d3:
+ 22:95:81:d0:76:87:29:9c:24:e8:3f:e0:41:a0:bb:57:96:1d:
+ 7e:92:2d:22:b3:98:67:4c:87:5e:42:f5:c9:08:fb:b9:05:25:
+ 73:b8:f0:9a:45:62:96:c6:48:b6:fe:ac:6c:42:a4:9e:41:aa:
+ fd:55:86:8e:4f:85:9e:b7:26:75:e3:79:28:ed:09:8d:63:35:
+ b5:55:78:13:46:43:17:3d:e8:12:c8:c3:c6:2f:88:f9:ce:b5:
+ df:af:6d:70:6f:6b:f6:1e:ff:1a:44:84:b6:51:7a:b1:7c:4f:
+ b4:7a:19:83:4c:85:b8:d0:e7:65:2e:0e:e2:ed:92:33:c4:f9:
+ cd:35:78:96:d6:8e:06:2c:17:18:0e:bf:be:f0:c5:7f:d3:85:
+ 71:62:94:83:d8:1b:51:c4:77:37:d3:6a:fd:43:b4:54:44:fe:
+ f9:da:01:3e:59:d4:7b:a4:26:32:e4:ba:9a:bf:f3:2b:6c:71:
+ d2:1e:2c:c4
+-----BEGIN CERTIFICATE-----
+MIIDkDCCAnigAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1JbnRl
+cm1lZGlhdGUyMB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowETEPMA0G
+A1UEAwwGVGFyZ2V0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxwKJ
+GAm8n5yaQTWpX/fCIj6yOf66Vx2VLt1lI0XOM3eZ3fHXaQv7pw6JmAJ6lFh7YeYQ
+mGkaCSufczrYcBhk4oqFh8Vp80UecNjAXiNspn2PdyOKXXSgC9V/p931IS0Cwg/g
+yPgpIPVeM1gqOMhBpiVmrM/EA8sDJdvmZT29q9r7j7UO2Lo9FCubB2IT1BzqsdV9
+TVQEwBP70d/CNuMAz/pJC0ScBYAZdQIlQT3g5s2H2GPXhD0MOsjs6FgiYi8Y6a1F
+zrimY8JlKWkeIQiNOtqW4IknCcw16fHw2PNhxQU+sdAAPH4lSjbjHbSVNy1ErJ55
+OGfnx6wMcdPRYIZECQIDAQABo4HrMIHoMB0GA1UdDgQWBBTGzH61fHpR7Bw14c08
+p/wGMVPKBjAfBgNVHSMEGDAWgBRIvzRj6OT7h0nyDqAjONK+aj1FPDBABggrBgEF
+BQcBAQQ0MDIwMAYIKwYBBQUHMAKGJGh0dHA6Ly91cmwtZm9yLWFpYS9JbnRlcm1l
+ZGlhdGUyLmNlcjA1BgNVHR8ELjAsMCqgKKAmhiRodHRwOi8vdXJsLWZvci1jcmwv
+SW50ZXJtZWRpYXRlMi5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsG
+AQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAUYz5yMvMFONUzWMa
+8B4Lo25gmWgG/uaX9Wjn2HrhsXhIPgNX5IRaJAhHn/tzGn92ZkBdrC/08J6xIbAV
+X9FoSrb+hCMFUX3TIpWB0HaHKZwk6D/gQaC7V5YdfpItIrOYZ0yHXkL1yQj7uQUl
+c7jwmkVilsZItv6sbEKknkGq/VWGjk+FnrcmdeN5KO0JjWM1tVV4E0ZDFz3oEsjD
+xi+I+c61369tcG9r9h7/GkSEtlF6sXxPtHoZg0yFuNDnZS4O4u2SM8T5zTV4ltaO
+BiwXGA6/vvDFf9OFcWKUg9gbUcR3N9Nq/UO0VET++doBPlnUe6QmMuS6mr/zK2xx
+0h4sxA==
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Intermediate1
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate2
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:9b:46:28:e2:70:56:b6:e1:f2:57:56:40:07:c9:
+ 66:0f:15:6f:6a:e9:b6:35:a4:f1:a7:17:4c:86:a4:
+ 8c:b7:74:55:0f:f2:cb:b0:43:11:4a:61:e0:9f:ea:
+ 8a:2b:c2:75:0f:b6:50:49:bc:ad:5c:3f:6c:92:4c:
+ 64:dc:50:2e:4d:66:65:eb:ba:9f:17:b7:d1:7e:ff:
+ 5d:d2:41:1f:9d:37:94:97:e1:f6:22:88:26:e2:8a:
+ 65:0f:0d:16:1d:b1:cc:df:e4:b1:78:87:f0:c6:f5:
+ f0:21:c9:f6:69:34:64:4c:cd:5b:27:ad:ee:0b:3d:
+ e3:ee:7a:6b:35:21:23:2b:6d:a4:82:c1:e0:37:f1:
+ 46:3c:16:c4:b9:20:29:16:13:14:26:05:41:c7:1e:
+ 21:e9:57:69:a4:3a:7b:b1:fe:92:c4:72:75:f7:bc:
+ c0:ef:ba:4a:0c:73:37:c1:48:e2:4d:07:c4:14:da:
+ ae:26:31:39:06:b8:43:6b:ec:2a:df:c8:db:02:af:
+ 24:9a:f2:af:28:98:1b:f3:0f:0d:57:2c:a5:c5:80:
+ ef:71:41:9f:99:16:20:d1:e2:f7:1d:59:1d:84:e2:
+ 0b:2d:23:f7:2f:05:9e:51:c3:c9:65:84:ba:db:23:
+ 2e:7e:43:b4:c1:eb:12:63:f4:3c:32:2e:18:dd:4c:
+ ad:8b
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 48:BF:34:63:E8:E4:FB:87:49:F2:0E:A0:23:38:D2:BE:6A:3D:45:3C
+ X509v3 Authority Key Identifier:
+ keyid:87:09:94:1A:5F:B2:4B:AE:02:70:24:A9:73:76:78:FD:C0:0E:DC:56
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Intermediate1.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Intermediate1.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ be:14:33:c3:9f:0f:7b:fa:15:2f:1d:2c:29:52:bc:27:de:b3:
+ 7a:f5:d2:e4:3a:51:38:97:8f:90:b2:ce:5d:50:88:77:5c:e8:
+ ae:35:01:68:13:3a:ca:5b:6c:ab:a2:ac:f0:e0:97:37:6f:ff:
+ 15:d2:4a:f7:ff:80:7c:64:c8:6a:11:c1:02:f0:4b:0e:97:24:
+ 81:7e:90:a4:38:41:af:8d:0b:eb:0b:24:2b:dc:89:4d:32:d1:
+ 0b:b1:7c:67:6e:4f:43:bf:e0:63:9b:e8:f4:42:9c:3b:db:7e:
+ ec:f7:64:82:28:73:8c:a0:2e:73:d2:45:dd:3a:ad:6a:6a:5e:
+ ae:6d:f3:cd:be:4a:95:5c:d0:0d:87:54:b6:83:40:ed:14:e5:
+ d7:9d:23:e2:04:d1:6c:a0:2c:0a:ca:42:57:cc:f7:0b:66:4e:
+ 35:ef:e3:93:5f:87:e9:0e:64:c7:52:c9:22:16:61:f9:ec:f7:
+ f0:4a:7a:b8:ef:d6:34:d4:6c:3d:b5:a9:6c:0b:f4:19:a8:9b:
+ 04:d5:04:9f:fc:04:fe:60:7a:14:70:6f:38:92:80:be:8a:a6:
+ c4:57:a2:40:5d:bc:06:53:83:6d:f3:5f:f5:22:4a:22:10:a2:
+ 82:00:87:35:77:07:f1:34:81:2f:86:0b:1a:3b:8f:3d:88:0c:
+ 3a:a0:15:25
+-----BEGIN CERTIFICATE-----
+MIIDiTCCAnGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1JbnRl
+cm1lZGlhdGUxMB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowGDEWMBQG
+A1UEAwwNSW50ZXJtZWRpYXRlMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAJtGKOJwVrbh8ldWQAfJZg8Vb2rptjWk8acXTIakjLd0VQ/yy7BDEUph4J/q
+iivCdQ+2UEm8rVw/bJJMZNxQLk1mZeu6nxe30X7/XdJBH503lJfh9iKIJuKKZQ8N
+Fh2xzN/ksXiH8Mb18CHJ9mk0ZEzNWyet7gs94+56azUhIyttpILB4DfxRjwWxLkg
+KRYTFCYFQcceIelXaaQ6e7H+ksRydfe8wO+6SgxzN8FI4k0HxBTariYxOQa4Q2vs
+Kt/I2wKvJJryryiYG/MPDVcspcWA73FBn5kWINHi9x1ZHYTiCy0j9y8FnlHDyWWE
+utsjLn5DtMHrEmP0PDIuGN1MrYsCAwEAAaOB3TCB2jAdBgNVHQ4EFgQUSL80Y+jk
++4dJ8g6gIzjSvmo9RTwwHwYDVR0jBBgwFoAUhwmUGl+yS64CcCSpc3Z4/cAO3FYw
+QAYIKwYBBQUHAQEENDAyMDAGCCsGAQUFBzAChiRodHRwOi8vdXJsLWZvci1haWEv
+SW50ZXJtZWRpYXRlMS5jZXIwNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL3VybC1m
+b3ItY3JsL0ludGVybWVkaWF0ZTEuY3JsMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
+Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQC+FDPDnw97+hUvHSwpUrwn3rN6
+9dLkOlE4l4+Qss5dUIh3XOiuNQFoEzrKW2yroqzw4Jc3b/8V0kr3/4B8ZMhqEcEC
+8EsOlySBfpCkOEGvjQvrCyQr3IlNMtELsXxnbk9Dv+Bjm+j0Qpw7237s92SCKHOM
+oC5z0kXdOq1qal6ubfPNvkqVXNANh1S2g0DtFOXXnSPiBNFsoCwKykJXzPcLZk41
+7+OTX4fpDmTHUskiFmH57PfwSnq479Y01Gw9talsC/QZqJsE1QSf/AT+YHoUcG84
+koC+iqbEV6JAXbwGU4Nt81/1IkoiEKKCAIc1dwfxNIEvhgsaO489iAw6oBUl
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Intermediate1
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:cc:c9:7a:84:dc:8e:0c:4b:60:fc:fb:35:ff:5c:
+ 72:00:1d:25:df:87:50:fa:65:2e:fa:40:a2:c7:9a:
+ cb:b5:2e:b6:0d:d8:80:6c:54:ef:44:c9:2f:a4:20:
+ 60:07:c7:0a:f9:0f:62:0c:30:9e:ff:9b:3f:a7:35:
+ 6a:ab:a3:56:ca:1b:ea:62:90:0f:ef:e3:29:52:dc:
+ 88:06:a5:65:1f:29:ba:73:11:b5:98:70:dd:88:7f:
+ 83:a6:0b:4c:da:42:92:e6:08:45:da:f4:54:e0:8d:
+ 67:6c:97:0b:fd:8c:13:65:81:6a:1b:49:1b:4e:c7:
+ de:dc:b5:68:1d:14:57:23:98:33:7b:43:a2:bf:da:
+ bf:ef:e7:58:43:27:d3:d6:a9:45:d0:8d:e7:d7:48:
+ b1:dc:f1:00:9b:85:8a:66:3e:20:f3:fc:e1:0f:89:
+ 9f:28:a6:2d:2c:f7:a2:44:e8:47:5a:0a:fa:cd:8e:
+ 40:2a:75:06:6d:ca:38:89:b6:9d:1f:15:d9:42:36:
+ 14:7e:2b:c4:e3:d7:03:a6:cf:4c:cb:34:c0:ce:e9:
+ ad:05:da:8c:73:91:25:d3:23:3e:70:ab:16:e7:fe:
+ 8b:95:69:f6:4f:98:68:86:04:d6:70:bd:0f:9a:37:
+ 0b:35:b9:ad:18:27:aa:15:b7:08:d0:54:1e:94:af:
+ ed:f9
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 87:09:94:1A:5F:B2:4B:AE:02:70:24:A9:73:76:78:FD:C0:0E:DC:56
+ X509v3 Authority Key Identifier:
+ keyid:0F:0F:6A:FA:74:D2:B6:49:DD:B5:2E:25:97:97:E3:E0:51:F7:1E:2A
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ db:01:1b:5b:f9:4f:9a:03:74:cb:a6:84:16:ab:ba:bb:63:7d:
+ 22:94:f5:70:03:dd:6d:fa:53:f2:23:c6:7b:a2:d2:62:96:ba:
+ 5a:95:f8:c8:a0:1f:f5:37:01:ce:a5:56:ef:19:5e:da:30:3a:
+ 81:ac:13:37:74:dd:5d:1b:b0:4a:cc:c0:b5:8f:d0:ce:6e:06:
+ 2b:74:c0:c4:70:fa:3b:90:d1:7b:c3:10:b3:8f:e1:69:42:ec:
+ 82:5c:09:ad:5b:0e:8d:4a:18:83:ec:f8:82:dc:e9:d8:5c:fa:
+ cc:f9:c9:6d:cc:b4:db:b0:d8:99:b9:fb:30:d2:28:a0:46:b8:
+ 77:fc:c2:12:eb:75:52:20:81:85:da:a6:ed:71:49:db:5c:4f:
+ a5:31:0f:59:c2:73:8d:da:10:be:ec:0c:4a:f8:d4:35:c7:13:
+ 5c:eb:f3:c8:42:19:d7:22:07:13:ac:71:46:9f:12:73:9e:0d:
+ 2e:c6:75:2d:fc:00:b4:99:13:e4:35:be:7f:7a:2f:2c:7b:44:
+ 57:3f:0f:2b:bb:06:25:45:94:2c:2d:af:c0:9f:e2:29:14:61:
+ 53:9d:ac:89:d2:04:c6:b9:52:a0:21:70:6f:b1:c0:9c:c9:6d:
+ 07:ab:14:d3:d3:49:05:bb:1e:4d:47:b6:62:6d:a2:35:3c:47:
+ 3e:32:1c:11
+-----BEGIN CERTIFICATE-----
+MIIDbjCCAlagAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowGDEWMBQGA1UEAwwNSW50
+ZXJtZWRpYXRlMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMzJeoTc
+jgxLYPz7Nf9ccgAdJd+HUPplLvpAoseay7Uutg3YgGxU70TJL6QgYAfHCvkPYgww
+nv+bP6c1aqujVsob6mKQD+/jKVLciAalZR8punMRtZhw3Yh/g6YLTNpCkuYIRdr0
+VOCNZ2yXC/2ME2WBahtJG07H3ty1aB0UVyOYM3tDor/av+/nWEMn09apRdCN59dI
+sdzxAJuFimY+IPP84Q+JnyimLSz3okToR1oK+s2OQCp1Bm3KOIm2nR8V2UI2FH4r
+xOPXA6bPTMs0wM7prQXajHORJdMjPnCrFuf+i5Vp9k+YaIYE1nC9D5o3CzW5rRgn
+qhW3CNBUHpSv7fkCAwEAAaOByzCByDAdBgNVHQ4EFgQUhwmUGl+yS64CcCSpc3Z4
+/cAO3FYwHwYDVR0jBBgwFoAUDw9q+nTStkndtS4ll5fj4FH3HiowNwYIKwYBBQUH
+AQEEKzApMCcGCCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIw
+LAYDVR0fBCUwIzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4G
+A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IB
+AQDbARtb+U+aA3TLpoQWq7q7Y30ilPVwA91t+lPyI8Z7otJilrpalfjIoB/1NwHO
+pVbvGV7aMDqBrBM3dN1dG7BKzMC1j9DObgYrdMDEcPo7kNF7wxCzj+FpQuyCXAmt
+Ww6NShiD7PiC3OnYXPrM+cltzLTbsNiZufsw0iigRrh3/MIS63VSIIGF2qbtcUnb
+XE+lMQ9ZwnON2hC+7AxK+NQ1xxNc6/PIQhnXIgcTrHFGnxJzng0uxnUt/AC0mRPk
+Nb5/ei8se0RXPw8ruwYlRZQsLa/An+IpFGFTnayJ0gTGuVKgIXBvscCcyW0HqxTT
+00kFux5NR7ZibaI1PEc+MhwR
+-----END CERTIFICATE-----
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: CN=Root
+ Validity
+ Not Before: Jan 1 12:00:00 2015 GMT
+ Not After : Jan 1 12:00:00 2016 GMT
+ Subject: CN=Root
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:f1:6d:df:8a:62:88:18:33:0e:b6:95:4d:a7:53:
+ 82:ad:ec:81:5e:c7:e1:d8:b9:38:a5:eb:3f:8e:d8:
+ 97:bb:ed:29:77:b2:d6:ac:34:96:a0:cd:a2:33:d8:
+ 88:49:88:6b:ce:aa:91:02:b9:33:51:52:d5:e7:b6:
+ ef:55:d3:d6:6a:f3:3f:87:d9:1b:60:b2:e3:b3:78:
+ be:e2:8c:b4:30:f3:60:75:eb:30:c5:71:51:49:90:
+ b9:99:5c:2c:78:9e:72:0d:02:3f:16:bb:6d:f7:f7:
+ 9e:07:d2:b4:47:85:ea:b0:92:3e:b6:8a:41:71:6a:
+ 4c:f6:ba:6d:60:4f:7c:29:b3:82:1d:04:07:76:32:
+ bc:25:38:2c:e4:be:29:2d:80:c3:20:62:a3:65:31:
+ f2:14:93:2d:92:9d:54:8b:96:4e:4d:df:4e:f7:80:
+ b2:e7:88:fd:06:32:30:3e:64:9d:e4:96:e0:0e:3a:
+ ea:c3:4f:ca:df:4a:46:22:1f:df:92:bd:24:82:59:
+ 20:36:95:62:82:92:2e:d9:d7:a7:93:1e:a7:75:fb:
+ a9:22:a6:98:4d:e6:f2:b4:12:d0:76:0c:b8:a2:fc:
+ c3:5e:e7:df:fb:c0:b5:90:5b:a8:1a:1d:33:ae:ab:
+ e3:25:3d:87:b5:58:c6:bc:e4:fa:db:e9:50:67:3f:
+ ad:ad
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 0F:0F:6A:FA:74:D2:B6:49:DD:B5:2E:25:97:97:E3:E0:51:F7:1E:2A
+ X509v3 Authority Key Identifier:
+ keyid:0F:0F:6A:FA:74:D2:B6:49:DD:B5:2E:25:97:97:E3:E0:51:F7:1E:2A
+
+ Authority Information Access:
+ CA Issuers - URI:http://url-for-aia/Root.cer
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://url-for-crl/Root.crl
+
+ X509v3 Key Usage: critical
+ Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE, pathlen:1
+ Signature Algorithm: sha256WithRSAEncryption
+ 38:cf:2c:95:d8:1b:14:a6:43:13:ed:9b:a2:9f:54:eb:33:64:
+ 2b:a6:c0:04:81:23:52:27:f1:17:12:a1:9a:f0:d2:77:dd:06:
+ 95:90:a5:bb:be:e1:98:f7:f0:11:a3:fc:71:80:c7:d0:72:f3:
+ d4:dc:3f:36:51:52:66:5f:92:a8:fa:ca:4f:8f:8f:2a:3d:93:
+ 12:8a:4f:94:69:99:6f:60:0b:86:81:91:00:98:cd:00:37:a7:
+ c7:60:e9:f4:07:85:5b:db:35:9b:61:bb:b6:aa:ca:a2:af:1c:
+ a4:e2:f8:0d:2b:84:2a:9f:7f:53:b6:25:31:ff:31:b8:e6:03:
+ 3c:f3:a1:5c:1a:51:4b:3e:d6:82:c9:24:d2:e8:3c:06:6b:b7:
+ f9:f5:77:55:67:fd:75:93:1a:d4:07:5d:6c:7c:6a:ed:12:9c:
+ b5:d6:f2:df:0c:39:a9:05:b9:11:b9:ca:21:31:26:5c:63:ac:
+ c3:bb:a7:e7:87:82:80:10:3a:32:fb:3a:9a:a8:0d:cf:af:94:
+ a4:a2:8a:0e:1c:1d:89:05:82:53:b6:86:1d:80:b4:00:de:31:
+ f1:20:4e:77:65:16:28:70:95:78:6b:d3:2e:e5:30:40:32:d2:
+ f6:b6:5c:30:de:07:70:5f:87:6b:51:31:85:4b:cf:8c:d9:0e:
+ 01:9a:12:6c
+-----BEGIN TRUST_ANCHOR_UNCONSTRAINED-----
+MIIDaDCCAlCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPFt34piiBgzDraVTadT
+gq3sgV7H4di5OKXrP47Yl7vtKXey1qw0lqDNojPYiEmIa86qkQK5M1FS1ee271XT
+1mrzP4fZG2Cy47N4vuKMtDDzYHXrMMVxUUmQuZlcLHiecg0CPxa7bff3ngfStEeF
+6rCSPraKQXFqTPa6bWBPfCmzgh0EB3YyvCU4LOS+KS2AwyBio2Ux8hSTLZKdVIuW
+Tk3fTveAsueI/QYyMD5kneSW4A466sNPyt9KRiIf35K9JIJZIDaVYoKSLtnXp5Me
+p3X7qSKmmE3m8rQS0HYMuKL8w17n3/vAtZBbqBodM66r4yU9h7VYxrzk+tvpUGc/
+ra0CAwEAAaOBzjCByzAdBgNVHQ4EFgQUDw9q+nTStkndtS4ll5fj4FH3HiowHwYD
+VR0jBBgwFoAUDw9q+nTStkndtS4ll5fj4FH3HiowNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQA4zyyV
+2BsUpkMT7Zuin1TrM2QrpsAEgSNSJ/EXEqGa8NJ33QaVkKW7vuGY9/ARo/xxgMfQ
+cvPU3D82UVJmX5Ko+spPj48qPZMSik+UaZlvYAuGgZEAmM0AN6fHYOn0B4Vb2zWb
+Ybu2qsqirxyk4vgNK4Qqn39TtiUx/zG45gM886FcGlFLPtaCySTS6DwGa7f59XdV
+Z/11kxrUB11sfGrtEpy11vLfDDmpBbkRucohMSZcY6zDu6fnh4KAEDoy+zqaqA3P
+r5SkoooOHB2JBYJTtoYdgLQA3jHxIE53ZRYocJV4a9Mu5TBAMtL2tlww3gdwX4dr
+UTGFS8+M2Q4BmhJs
+-----END TRUST_ANCHOR_UNCONSTRAINED-----
+
+150302120000Z
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+SUCCESS
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/chromium/net/der/encode_values.cc b/chromium/net/der/encode_values.cc
new file mode 100644
index 00000000000..3c217d35860
--- /dev/null
+++ b/chromium/net/der/encode_values.cc
@@ -0,0 +1,30 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time/time.h"
+#include "net/der/encode_values.h"
+
+namespace net {
+
+namespace der {
+
+bool EncodeTimeAsGeneralizedTime(const base::Time& time,
+ der::GeneralizedTime* generalized_time) {
+ base::Time::Exploded exploded;
+ time.UTCExplode(&exploded);
+ if (!exploded.HasValidValues())
+ return false;
+
+ generalized_time->year = exploded.year;
+ generalized_time->month = exploded.month;
+ generalized_time->day = exploded.day_of_month;
+ generalized_time->hours = exploded.hour;
+ generalized_time->minutes = exploded.minute;
+ generalized_time->seconds = exploded.second;
+ return true;
+}
+
+} // namespace der
+
+} // namespace net
diff --git a/chromium/net/der/encode_values.h b/chromium/net/der/encode_values.h
new file mode 100644
index 00000000000..f931d0e8f3d
--- /dev/null
+++ b/chromium/net/der/encode_values.h
@@ -0,0 +1,28 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_DER_ENCODE_VALUES_H_
+#define NET_DER_ENCODE_VALUES_H_
+
+#include "net/base/net_export.h"
+#include "net/der/parse_values.h"
+
+namespace base {
+class Time;
+}
+
+namespace net {
+
+namespace der {
+
+// Encodes |time|, a UTC-based time, to DER |generalized_time|, for comparing
+// against other GeneralizedTime objects.
+NET_EXPORT bool EncodeTimeAsGeneralizedTime(const base::Time& time,
+ GeneralizedTime* generalized_time);
+
+} // namespace der
+
+} // namespace net
+
+#endif // NET_DER_ENCODE_VALUES_H
diff --git a/chromium/net/der/encode_values_unittest.cc b/chromium/net/der/encode_values_unittest.cc
new file mode 100644
index 00000000000..940e1f54547
--- /dev/null
+++ b/chromium/net/der/encode_values_unittest.cc
@@ -0,0 +1,98 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time/time.h"
+#include "net/der/encode_values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace der {
+namespace test {
+
+TEST(EncodeValuesTest, EncodeTimeAsGeneralizedTime) {
+ // Fri, 24 Jun 2016 17:04:54 GMT
+ base::Time time =
+ base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(1466787894);
+ GeneralizedTime generalized_time;
+ ASSERT_TRUE(EncodeTimeAsGeneralizedTime(time, &generalized_time));
+ EXPECT_EQ(2016, generalized_time.year);
+ EXPECT_EQ(6, generalized_time.month);
+ EXPECT_EQ(24, generalized_time.day);
+ EXPECT_EQ(17, generalized_time.hours);
+ EXPECT_EQ(4, generalized_time.minutes);
+ EXPECT_EQ(54, generalized_time.seconds);
+}
+
+// ASN.1 GeneralizedTime can represent dates from year 0000 to 9999, and
+// although base::Time can represent times from before the Windows epoch and
+// after the 32-bit time_t maximum, the conversion between base::Time and
+// der::GeneralizedTime goes through the time representation of the underlying
+// platform, which might not be able to handle the full GeneralizedTime date
+// range. Out-of-range times should not be converted to der::GeneralizedTime. In
+// tests, possibly-out-of-range test times are specified as a
+// base::Time::Exploded, and then converted to a base::Time. If the conversion
+// fails, this signals the underlying platform cannot handle the time, and the
+// test aborts early. If the underlying platform can represent the time, then
+// the conversion is successful, and the encoded GeneralizedTime can should
+// match the test time.
+//
+// Thu, 1 Jan 1570 00:00:00 GMT. This time is unrepresentable by the Windows
+// native time libraries.
+TEST(EncodeValuesTest, EncodeTimeFromBeforeWindowsEpoch) {
+ base::Time::Exploded exploded;
+ exploded.year = 1570;
+ exploded.month = 1;
+ exploded.day_of_week = 5;
+ exploded.day_of_month = 1;
+ exploded.hour = 0;
+ exploded.minute = 0;
+ exploded.second = 0;
+ exploded.millisecond = 0;
+
+ base::Time time;
+ if (!base::Time::FromUTCExploded(exploded, &time))
+ return;
+
+ GeneralizedTime generalized_time;
+ ASSERT_TRUE(EncodeTimeAsGeneralizedTime(time, &generalized_time));
+ EXPECT_EQ(1570, generalized_time.year);
+ EXPECT_EQ(1, generalized_time.month);
+ EXPECT_EQ(1, generalized_time.day);
+ EXPECT_EQ(0, generalized_time.hours);
+ EXPECT_EQ(0, generalized_time.minutes);
+ EXPECT_EQ(0, generalized_time.seconds);
+}
+
+// Sat, 1 Jan 2039 00:00:00 GMT. See above comment. This time may be
+// unrepresentable on 32-bit systems.
+TEST(EncodeValuesTest, EncodeTimeAfterTimeTMax) {
+ base::Time::Exploded exploded;
+ exploded.year = 2039;
+ exploded.month = 1;
+ exploded.day_of_week = 7;
+ exploded.day_of_month = 1;
+ exploded.hour = 0;
+ exploded.minute = 0;
+ exploded.second = 0;
+ exploded.millisecond = 0;
+
+ base::Time time;
+ if (!base::Time::FromUTCExploded(exploded, &time))
+ return;
+
+ GeneralizedTime generalized_time;
+ ASSERT_TRUE(EncodeTimeAsGeneralizedTime(time, &generalized_time));
+ EXPECT_EQ(2039, generalized_time.year);
+ EXPECT_EQ(1, generalized_time.month);
+ EXPECT_EQ(1, generalized_time.day);
+ EXPECT_EQ(0, generalized_time.hours);
+ EXPECT_EQ(0, generalized_time.minutes);
+ EXPECT_EQ(0, generalized_time.seconds);
+}
+
+} // namespace test
+
+} // namespace der
+
+} // namespace net
diff --git a/chromium/net/disk_cache/backend_unittest.cc b/chromium/net/disk_cache/backend_unittest.cc
index d9e6c2dc5dc..e92dd9b2f59 100644
--- a/chromium/net/disk_cache/backend_unittest.cc
+++ b/chromium/net/disk_cache/backend_unittest.cc
@@ -6,6 +6,7 @@
#include "base/files/file.h"
#include "base/files/file_util.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
@@ -36,8 +37,13 @@
#include "net/disk_cache/simple/simple_synchronous_entry.h"
#include "net/disk_cache/simple/simple_test_util.h"
#include "net/disk_cache/simple/simple_util.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
#if defined(OS_WIN)
#include "base/win/scoped_handle.h"
#endif
@@ -114,6 +120,7 @@ class DiskCacheBackendTest : public DiskCacheTestWithCache {
void BackendTrimInvalidEntry2();
void BackendEnumerations();
void BackendEnumerations2();
+ void BackendDoomMidEnumeration();
void BackendInvalidEntryEnumeration();
void BackendFixEnumerators();
void BackendDoomRecent();
@@ -191,7 +198,7 @@ void DiskCacheBackendTest::InitSparseCache(base::Time* doomed_start,
InitCache();
const int kSize = 50;
- // This must be greater then MemEntryImpl::kMaxSparseEntrySize.
+ // This must be greater than MemEntryImpl::kMaxSparseEntrySize.
const int kOffset = 10 + 1024 * 1024;
disk_cache::Entry* entry0 = NULL;
@@ -201,7 +208,7 @@ void DiskCacheBackendTest::InitSparseCache(base::Time* doomed_start,
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize));
CacheTestFillBuffer(buffer->data(), kSize, false);
- ASSERT_EQ(net::OK, CreateEntry("zeroth", &entry0));
+ ASSERT_THAT(CreateEntry("zeroth", &entry0), IsOk());
ASSERT_EQ(kSize, WriteSparseData(entry0, 0, buffer.get(), kSize));
ASSERT_EQ(kSize,
WriteSparseData(entry0, kOffset + kSize, buffer.get(), kSize));
@@ -214,13 +221,13 @@ void DiskCacheBackendTest::InitSparseCache(base::Time* doomed_start,
// Order in rankings list:
// first_part1, first_part2, second_part1, second_part2
- ASSERT_EQ(net::OK, CreateEntry("first", &entry1));
+ ASSERT_THAT(CreateEntry("first", &entry1), IsOk());
ASSERT_EQ(kSize, WriteSparseData(entry1, 0, buffer.get(), kSize));
ASSERT_EQ(kSize,
WriteSparseData(entry1, kOffset + kSize, buffer.get(), kSize));
entry1->Close();
- ASSERT_EQ(net::OK, CreateEntry("second", &entry2));
+ ASSERT_THAT(CreateEntry("second", &entry2), IsOk());
ASSERT_EQ(kSize, WriteSparseData(entry2, 0, buffer.get(), kSize));
ASSERT_EQ(kSize,
WriteSparseData(entry2, kOffset + kSize, buffer.get(), kSize));
@@ -235,9 +242,9 @@ void DiskCacheBackendTest::InitSparseCache(base::Time* doomed_start,
// third_part1, fourth_part1, third_part2, fourth_part2
disk_cache::Entry* entry3 = NULL;
disk_cache::Entry* entry4 = NULL;
- ASSERT_EQ(net::OK, CreateEntry("third", &entry3));
+ ASSERT_THAT(CreateEntry("third", &entry3), IsOk());
ASSERT_EQ(kSize, WriteSparseData(entry3, 0, buffer.get(), kSize));
- ASSERT_EQ(net::OK, CreateEntry("fourth", &entry4));
+ ASSERT_THAT(CreateEntry("fourth", &entry4), IsOk());
ASSERT_EQ(kSize, WriteSparseData(entry4, 0, buffer.get(), kSize));
ASSERT_EQ(kSize,
WriteSparseData(entry3, kOffset + kSize, buffer.get(), kSize));
@@ -311,44 +318,44 @@ void DiskCacheBackendTest::BackendBasics() {
InitCache();
disk_cache::Entry *entry1 = NULL, *entry2 = NULL;
EXPECT_NE(net::OK, OpenEntry("the first key", &entry1));
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry1));
+ ASSERT_THAT(CreateEntry("the first key", &entry1), IsOk());
ASSERT_TRUE(NULL != entry1);
entry1->Close();
entry1 = NULL;
- ASSERT_EQ(net::OK, OpenEntry("the first key", &entry1));
+ ASSERT_THAT(OpenEntry("the first key", &entry1), IsOk());
ASSERT_TRUE(NULL != entry1);
entry1->Close();
entry1 = NULL;
EXPECT_NE(net::OK, CreateEntry("the first key", &entry1));
- ASSERT_EQ(net::OK, OpenEntry("the first key", &entry1));
+ ASSERT_THAT(OpenEntry("the first key", &entry1), IsOk());
EXPECT_NE(net::OK, OpenEntry("some other key", &entry2));
- ASSERT_EQ(net::OK, CreateEntry("some other key", &entry2));
+ ASSERT_THAT(CreateEntry("some other key", &entry2), IsOk());
ASSERT_TRUE(NULL != entry1);
ASSERT_TRUE(NULL != entry2);
EXPECT_EQ(2, cache_->GetEntryCount());
disk_cache::Entry* entry3 = NULL;
- ASSERT_EQ(net::OK, OpenEntry("some other key", &entry3));
+ ASSERT_THAT(OpenEntry("some other key", &entry3), IsOk());
ASSERT_TRUE(NULL != entry3);
EXPECT_TRUE(entry2 == entry3);
EXPECT_EQ(2, cache_->GetEntryCount());
- EXPECT_EQ(net::OK, DoomEntry("some other key"));
+ EXPECT_THAT(DoomEntry("some other key"), IsOk());
EXPECT_EQ(1, cache_->GetEntryCount());
entry1->Close();
entry2->Close();
entry3->Close();
- EXPECT_EQ(net::OK, DoomEntry("the first key"));
+ EXPECT_THAT(DoomEntry("the first key"), IsOk());
EXPECT_EQ(0, cache_->GetEntryCount());
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry1));
- ASSERT_EQ(net::OK, CreateEntry("some other key", &entry2));
+ ASSERT_THAT(CreateEntry("the first key", &entry1), IsOk());
+ ASSERT_THAT(CreateEntry("some other key", &entry2), IsOk());
entry1->Doom();
entry1->Close();
- EXPECT_EQ(net::OK, DoomEntry("some other key"));
+ EXPECT_THAT(DoomEntry("some other key"), IsOk());
EXPECT_EQ(0, cache_->GetEntryCount());
entry2->Close();
}
@@ -382,25 +389,25 @@ void DiskCacheBackendTest::BackendKeying() {
const char kName1[] = "the first key";
const char kName2[] = "the first Key";
disk_cache::Entry *entry1, *entry2;
- ASSERT_EQ(net::OK, CreateEntry(kName1, &entry1));
+ ASSERT_THAT(CreateEntry(kName1, &entry1), IsOk());
- ASSERT_EQ(net::OK, CreateEntry(kName2, &entry2));
+ ASSERT_THAT(CreateEntry(kName2, &entry2), IsOk());
EXPECT_TRUE(entry1 != entry2) << "Case sensitive";
entry2->Close();
char buffer[30];
base::strlcpy(buffer, kName1, arraysize(buffer));
- ASSERT_EQ(net::OK, OpenEntry(buffer, &entry2));
+ ASSERT_THAT(OpenEntry(buffer, &entry2), IsOk());
EXPECT_TRUE(entry1 == entry2);
entry2->Close();
base::strlcpy(buffer + 1, kName1, arraysize(buffer) - 1);
- ASSERT_EQ(net::OK, OpenEntry(buffer + 1, &entry2));
+ ASSERT_THAT(OpenEntry(buffer + 1, &entry2), IsOk());
EXPECT_TRUE(entry1 == entry2);
entry2->Close();
base::strlcpy(buffer + 3, kName1, arraysize(buffer) - 3);
- ASSERT_EQ(net::OK, OpenEntry(buffer + 3, &entry2));
+ ASSERT_THAT(OpenEntry(buffer + 3, &entry2), IsOk());
EXPECT_TRUE(entry1 == entry2);
entry2->Close();
@@ -467,7 +474,7 @@ TEST_F(DiskCacheTest, CreateBackend) {
NULL,
&cache,
cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
ASSERT_TRUE(cache.get());
cache.reset();
@@ -476,7 +483,7 @@ TEST_F(DiskCacheTest, CreateBackend) {
base::FilePath(), 0,
false, NULL, NULL, &cache,
cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
ASSERT_TRUE(cache.get());
cache.reset();
}
@@ -498,7 +505,7 @@ TEST_F(DiskCacheBackendTest, CreateBackend_MissingFile) {
std::unique_ptr<disk_cache::BackendImpl> cache(new disk_cache::BackendImpl(
cache_path_, cache_thread.task_runner(), NULL));
int rv = cache->Init(cb.callback());
- EXPECT_EQ(net::ERR_FAILED, cb.GetResult(rv));
+ EXPECT_THAT(cb.GetResult(rv), IsError(net::ERR_FAILED));
base::ThreadRestrictions::SetIOAllowed(prev);
cache.reset();
@@ -517,7 +524,7 @@ TEST_F(DiskCacheBackendTest, ExternalFiles) {
// Now let's create a file with the cache.
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry("key", &entry));
+ ASSERT_THAT(CreateEntry("key", &entry), IsOk());
ASSERT_EQ(0, WriteData(entry, 0, 20000, buffer1.get(), 0, false));
entry->Close();
@@ -589,16 +596,10 @@ TEST_F(DiskCacheBackendTest, MultipleInstancesWithPendingFileIO) {
net::TestCompletionCallback cb;
std::unique_ptr<disk_cache::Backend> extra_cache;
- int rv = disk_cache::CreateCacheBackend(net::DISK_CACHE,
- net::CACHE_BACKEND_DEFAULT,
- store.path(),
- 0,
- false,
- base::ThreadTaskRunnerHandle::Get(),
- NULL,
- &extra_cache,
- cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ int rv = disk_cache::CreateCacheBackend(
+ net::DISK_CACHE, net::CACHE_BACKEND_DEFAULT, store.GetPath(), 0, false,
+ base::ThreadTaskRunnerHandle::Get(), NULL, &extra_cache, cb.callback());
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
ASSERT_TRUE(extra_cache.get() != NULL);
ASSERT_TRUE(CleanupCacheDir());
@@ -640,7 +641,7 @@ void DiskCacheBackendTest::BackendShutdownWithPendingIO(bool fast) {
disk_cache::Entry* entry;
int rv = cache_->CreateEntry("some key", &entry, cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
entry->Close();
@@ -682,7 +683,7 @@ void DiskCacheBackendTest::BackendShutdownWithPendingCreate(bool fast) {
disk_cache::Entry* entry;
int rv = cache_->CreateEntry("some key", &entry, cb.callback());
- ASSERT_EQ(net::ERR_IO_PENDING, rv);
+ ASSERT_THAT(rv, IsError(net::ERR_IO_PENDING));
cache_.reset();
EXPECT_FALSE(cb.have_result());
@@ -719,12 +720,12 @@ void DiskCacheBackendTest::BackendShutdownWithPendingDoom() {
disk_cache::Entry* entry;
int rv = cache_->CreateEntry("some key", &entry, cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
entry->Close();
entry = nullptr;
rv = cache_->DoomEntry("some key", cb.callback());
- ASSERT_EQ(net::ERR_IO_PENDING, rv);
+ ASSERT_THAT(rv, IsError(net::ERR_IO_PENDING));
cache_.reset();
EXPECT_FALSE(cb.have_result());
@@ -775,7 +776,7 @@ void DiskCacheBackendTest::BackendSetSize() {
std::string first("some key");
std::string second("something else");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(first, &entry));
+ ASSERT_THAT(CreateEntry(first, &entry), IsOk());
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(cache_size));
memset(buffer->data(), 0, cache_size);
@@ -803,12 +804,12 @@ void DiskCacheBackendTest::BackendSetSize() {
// The cache is 95% full.
- ASSERT_EQ(net::OK, CreateEntry(second, &entry));
+ ASSERT_THAT(CreateEntry(second, &entry), IsOk());
EXPECT_EQ(cache_size / 10,
WriteData(entry, 0, 0, buffer.get(), cache_size / 10, false));
disk_cache::Entry* entry2;
- ASSERT_EQ(net::OK, CreateEntry("an extra key", &entry2));
+ ASSERT_THAT(CreateEntry("an extra key", &entry2), IsOk());
EXPECT_EQ(cache_size / 10,
WriteData(entry2, 0, 0, buffer.get(), cache_size / 10, false));
entry2->Close(); // This will trigger the cache trim.
@@ -819,7 +820,7 @@ void DiskCacheBackendTest::BackendSetSize() {
FlushQueueForTest(); // We may have posted two tasks to evict stuff.
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(second, &entry));
+ ASSERT_THAT(OpenEntry(second, &entry), IsOk());
EXPECT_EQ(cache_size / 10, entry->GetDataSize(0));
entry->Close();
}
@@ -846,7 +847,7 @@ void DiskCacheBackendTest::BackendLoad() {
disk_cache::Entry* entries[100];
for (int i = 0; i < 100; i++) {
std::string key = GenerateKey(true);
- ASSERT_EQ(net::OK, CreateEntry(key, &entries[i]));
+ ASSERT_THAT(CreateEntry(key, &entries[i]), IsOk());
}
EXPECT_EQ(100, cache_->GetEntryCount());
@@ -860,7 +861,7 @@ void DiskCacheBackendTest::BackendLoad() {
for (int i = 0; i < 100; i++) {
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, OpenEntry(entries[i]->GetKey(), &entry));
+ ASSERT_THAT(OpenEntry(entries[i]->GetKey(), &entry), IsOk());
EXPECT_TRUE(entry == entries[i]);
entry->Close();
entries[i]->Doom();
@@ -914,9 +915,9 @@ void DiskCacheBackendTest::BackendChain() {
InitCache();
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry("The first key", &entry));
+ ASSERT_THAT(CreateEntry("The first key", &entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, CreateEntry("The Second key", &entry));
+ ASSERT_THAT(CreateEntry("The Second key", &entry), IsOk());
entry->Close();
}
@@ -946,11 +947,11 @@ TEST_F(DiskCacheBackendTest, NewEvictionTrim) {
disk_cache::Entry* entry;
for (int i = 0; i < 100; i++) {
std::string name(base::StringPrintf("Key %d", i));
- ASSERT_EQ(net::OK, CreateEntry(name, &entry));
+ ASSERT_THAT(CreateEntry(name, &entry), IsOk());
entry->Close();
if (i < 90) {
// Entries 0 to 89 are in list 1; 90 to 99 are in list 0.
- ASSERT_EQ(net::OK, OpenEntry(name, &entry));
+ ASSERT_THAT(OpenEntry(name, &entry), IsOk());
entry->Close();
}
}
@@ -963,9 +964,9 @@ TEST_F(DiskCacheBackendTest, NewEvictionTrim) {
EXPECT_NE(net::OK, OpenEntry("Key 90", &entry));
// Double check that we still have the list tails.
- ASSERT_EQ(net::OK, OpenEntry("Key 1", &entry));
+ ASSERT_THAT(OpenEntry("Key 1", &entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry("Key 91", &entry));
+ ASSERT_THAT(OpenEntry("Key 91", &entry), IsOk());
entry->Close();
}
@@ -975,7 +976,7 @@ void DiskCacheBackendTest::BackendValidEntry() {
std::string key("Some key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize = 50;
scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize));
@@ -985,7 +986,7 @@ void DiskCacheBackendTest::BackendValidEntry() {
entry->Close();
SimulateCrash();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize));
memset(buffer2->data(), 0, kSize);
@@ -1011,7 +1012,7 @@ void DiskCacheBackendTest::BackendInvalidEntry() {
std::string key("Some key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize = 50;
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize));
@@ -1055,7 +1056,7 @@ void DiskCacheBackendTest::BackendInvalidEntryRead() {
std::string key("Some key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize = 50;
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize));
@@ -1063,14 +1064,14 @@ void DiskCacheBackendTest::BackendInvalidEntryRead() {
base::strlcpy(buffer->data(), "And the data to save", kSize);
EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer.get(), kSize, false));
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
EXPECT_EQ(kSize, ReadData(entry, 0, 0, buffer.get(), kSize));
SimulateCrash();
if (type_ == net::APP_CACHE) {
// Reading an entry and crashing should not make it dirty.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
EXPECT_EQ(1, cache_->GetEntryCount());
entry->Close();
} else {
@@ -1116,7 +1117,7 @@ void DiskCacheBackendTest::BackendInvalidEntryWithLoad() {
disk_cache::Entry* entries[kNumEntries];
for (int i = 0; i < kNumEntries; i++) {
std::string key = GenerateKey(true);
- ASSERT_EQ(net::OK, CreateEntry(key, &entries[i]));
+ ASSERT_THAT(CreateEntry(key, &entries[i]), IsOk());
}
EXPECT_EQ(kNumEntries, cache_->GetEntryCount());
@@ -1144,7 +1145,7 @@ void DiskCacheBackendTest::BackendInvalidEntryWithLoad() {
for (int i = 0; i < kNumEntries / 2; i++) {
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, OpenEntry(keys[i], &entry));
+ ASSERT_THAT(OpenEntry(keys[i], &entry), IsOk());
entry->Close();
}
@@ -1183,7 +1184,7 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry() {
std::string first("some key");
std::string second("something else");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(first, &entry));
+ ASSERT_THAT(CreateEntry(first, &entry), IsOk());
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize));
memset(buffer->data(), 0, kSize);
@@ -1192,7 +1193,7 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry() {
// Simulate a crash.
SimulateCrash();
- ASSERT_EQ(net::OK, CreateEntry(second, &entry));
+ ASSERT_THAT(CreateEntry(second, &entry), IsOk());
EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer.get(), kSize, false));
EXPECT_EQ(2, cache_->GetEntryCount());
@@ -1241,17 +1242,17 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry2() {
// Writing 32 entries to this cache chains most of them.
for (int i = 0; i < 32; i++) {
std::string key(base::StringPrintf("some key %d", i));
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer.get(), kSize, false));
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
// Note that we are not closing the entries.
}
// Simulate a crash.
SimulateCrash();
- ASSERT_EQ(net::OK, CreateEntry("Something else", &entry));
+ ASSERT_THAT(CreateEntry("Something else", &entry), IsOk());
EXPECT_EQ(kSize, WriteData(entry, 0, 0, buffer.get(), kSize, false));
FlushQueueForTest();
@@ -1261,7 +1262,7 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry2() {
// For the new eviction code, all corrupt entries are on the second list so
// they are not going away that easy.
if (new_eviction_) {
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
}
entry->Close(); // Trim the cache.
@@ -1297,7 +1298,7 @@ void DiskCacheBackendTest::BackendEnumerations() {
for (int i = 0; i < kNumEntries; i++) {
std::string key = GenerateKey(true);
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
entry->Close();
}
EXPECT_EQ(kNumEntries, cache_->GetEntryCount());
@@ -1367,17 +1368,17 @@ void DiskCacheBackendTest::BackendEnumerations2() {
const std::string first("first");
const std::string second("second");
disk_cache::Entry *entry1, *entry2;
- ASSERT_EQ(net::OK, CreateEntry(first, &entry1));
+ ASSERT_THAT(CreateEntry(first, &entry1), IsOk());
entry1->Close();
- ASSERT_EQ(net::OK, CreateEntry(second, &entry2));
+ ASSERT_THAT(CreateEntry(second, &entry2), IsOk());
entry2->Close();
FlushQueueForTest();
// Make sure that the timestamp is not the same.
AddDelay();
- ASSERT_EQ(net::OK, OpenEntry(second, &entry1));
+ ASSERT_THAT(OpenEntry(second, &entry1), IsOk());
std::unique_ptr<TestIterator> iter = CreateIterator();
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry2));
+ ASSERT_THAT(iter->OpenNextEntry(&entry2), IsOk());
EXPECT_EQ(entry2->GetKey(), second);
// Two entries and the iterator pointing at "first".
@@ -1385,15 +1386,15 @@ void DiskCacheBackendTest::BackendEnumerations2() {
entry2->Close();
// The iterator should still be valid, so we should not crash.
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry2));
+ ASSERT_THAT(iter->OpenNextEntry(&entry2), IsOk());
EXPECT_EQ(entry2->GetKey(), first);
entry2->Close();
iter = CreateIterator();
// Modify the oldest entry and get the newest element.
- ASSERT_EQ(net::OK, OpenEntry(first, &entry1));
+ ASSERT_THAT(OpenEntry(first, &entry1), IsOk());
EXPECT_EQ(0, WriteData(entry1, 0, 200, NULL, 0, false));
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry2));
+ ASSERT_THAT(iter->OpenNextEntry(&entry2), IsOk());
if (type_ == net::APP_CACHE) {
// The list is not updated.
EXPECT_EQ(entry2->GetKey(), second);
@@ -1414,11 +1415,6 @@ TEST_F(DiskCacheBackendTest, NewEvictionEnumerations2) {
BackendEnumerations2();
}
-TEST_F(DiskCacheBackendTest, MemoryOnlyEnumerations2) {
- SetMemoryOnlyMode();
- BackendEnumerations2();
-}
-
TEST_F(DiskCacheBackendTest, AppCacheEnumerations2) {
SetCacheType(net::APP_CACHE);
BackendEnumerations2();
@@ -1429,6 +1425,70 @@ TEST_F(DiskCacheBackendTest, ShaderCacheEnumerations2) {
BackendEnumerations2();
}
+void DiskCacheBackendTest::BackendDoomMidEnumeration() {
+ InitCache();
+
+ const int kNumEntries = 100;
+ std::set<std::string> keys;
+ for (int i = 0; i < kNumEntries; i++) {
+ std::string key = GenerateKey(true);
+ keys.insert(key);
+ disk_cache::Entry* entry;
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
+ entry->Close();
+ }
+
+ disk_cache::Entry* entry;
+ std::unique_ptr<TestIterator> iter = CreateIterator();
+ int count = 0;
+ while (iter->OpenNextEntry(&entry) == net::OK) {
+ if (count == 0) {
+ // Delete a random entry from the cache while in the midst of iteration.
+ auto key_to_doom = keys.begin();
+ while (*key_to_doom == entry->GetKey())
+ key_to_doom++;
+ ASSERT_THAT(DoomEntry(*key_to_doom), IsOk());
+ ASSERT_EQ(1u, keys.erase(*key_to_doom));
+ }
+ ASSERT_NE(nullptr, entry);
+ EXPECT_EQ(1u, keys.erase(entry->GetKey()));
+ entry->Close();
+ count++;
+ };
+
+ EXPECT_EQ(kNumEntries - 1, cache_->GetEntryCount());
+ EXPECT_EQ(0u, keys.size());
+}
+
+TEST_F(DiskCacheBackendTest, DoomEnumerations) {
+ BackendDoomMidEnumeration();
+}
+
+TEST_F(DiskCacheBackendTest, NewEvictionDoomEnumerations) {
+ SetNewEviction();
+ BackendDoomMidEnumeration();
+}
+
+TEST_F(DiskCacheBackendTest, MemoryOnlyDoomEnumerations) {
+ SetMemoryOnlyMode();
+ BackendDoomMidEnumeration();
+}
+
+TEST_F(DiskCacheBackendTest, ShaderCacheDoomEnumerations) {
+ SetCacheType(net::SHADER_CACHE);
+ BackendDoomMidEnumeration();
+}
+
+TEST_F(DiskCacheBackendTest, AppCacheDoomEnumerations) {
+ SetCacheType(net::APP_CACHE);
+ BackendDoomMidEnumeration();
+}
+
+TEST_F(DiskCacheBackendTest, SimpleDoomEnumerations) {
+ SetSimpleCacheMode();
+ BackendDoomMidEnumeration();
+}
+
// Verify that ReadData calls do not update the LRU cache
// when using the SHADER_CACHE type.
TEST_F(DiskCacheBackendTest, ShaderCacheEnumerationReadData) {
@@ -1440,12 +1500,12 @@ TEST_F(DiskCacheBackendTest, ShaderCacheEnumerationReadData) {
const int kSize = 50;
scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize));
- ASSERT_EQ(net::OK, CreateEntry(first, &entry1));
+ ASSERT_THAT(CreateEntry(first, &entry1), IsOk());
memset(buffer1->data(), 0, kSize);
base::strlcpy(buffer1->data(), "And the data to save", kSize);
EXPECT_EQ(kSize, WriteData(entry1, 0, 0, buffer1.get(), kSize, false));
- ASSERT_EQ(net::OK, CreateEntry(second, &entry2));
+ ASSERT_THAT(CreateEntry(second, &entry2), IsOk());
entry2->Close();
FlushQueueForTest();
@@ -1458,7 +1518,7 @@ TEST_F(DiskCacheBackendTest, ShaderCacheEnumerationReadData) {
entry1->Close();
std::unique_ptr<TestIterator> iter = CreateIterator();
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry2));
+ ASSERT_THAT(iter->OpenNextEntry(&entry2), IsOk());
EXPECT_EQ(entry2->GetKey(), second);
entry2->Close();
}
@@ -1471,7 +1531,7 @@ void DiskCacheBackendTest::BackendInvalidEntryEnumeration() {
std::string key("Some key");
disk_cache::Entry *entry, *entry1, *entry2;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry1));
+ ASSERT_THAT(CreateEntry(key, &entry1), IsOk());
const int kSize = 50;
scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize));
@@ -1479,11 +1539,11 @@ void DiskCacheBackendTest::BackendInvalidEntryEnumeration() {
base::strlcpy(buffer1->data(), "And the data to save", kSize);
EXPECT_EQ(kSize, WriteData(entry1, 0, 0, buffer1.get(), kSize, false));
entry1->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry1));
+ ASSERT_THAT(OpenEntry(key, &entry1), IsOk());
EXPECT_EQ(kSize, ReadData(entry1, 0, 0, buffer1.get(), kSize));
std::string key2("Another key");
- ASSERT_EQ(net::OK, CreateEntry(key2, &entry2));
+ ASSERT_THAT(CreateEntry(key2, &entry2), IsOk());
entry2->Close();
ASSERT_EQ(2, cache_->GetEntryCount());
@@ -1525,7 +1585,7 @@ void DiskCacheBackendTest::BackendFixEnumerators() {
for (int i = 0; i < kNumEntries; i++) {
std::string key = GenerateKey(true);
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
entry->Close();
}
EXPECT_EQ(kNumEntries, cache_->GetEntryCount());
@@ -1533,7 +1593,7 @@ void DiskCacheBackendTest::BackendFixEnumerators() {
disk_cache::Entry *entry1, *entry2;
std::unique_ptr<TestIterator> iter1 = CreateIterator(),
iter2 = CreateIterator();
- ASSERT_EQ(net::OK, iter1->OpenNextEntry(&entry1));
+ ASSERT_THAT(iter1->OpenNextEntry(&entry1), IsOk());
ASSERT_TRUE(NULL != entry1);
entry1->Close();
entry1 = NULL;
@@ -1542,17 +1602,17 @@ void DiskCacheBackendTest::BackendFixEnumerators() {
for (int i = 0; i < kNumEntries / 2; i++) {
if (entry1)
entry1->Close();
- ASSERT_EQ(net::OK, iter1->OpenNextEntry(&entry1));
+ ASSERT_THAT(iter1->OpenNextEntry(&entry1), IsOk());
ASSERT_TRUE(NULL != entry1);
- ASSERT_EQ(net::OK, iter2->OpenNextEntry(&entry2));
+ ASSERT_THAT(iter2->OpenNextEntry(&entry2), IsOk());
ASSERT_TRUE(NULL != entry2);
entry2->Close();
}
// Messing up with entry1 will modify entry2->next.
entry1->Doom();
- ASSERT_EQ(net::OK, iter2->OpenNextEntry(&entry2));
+ ASSERT_THAT(iter2->OpenNextEntry(&entry2), IsOk());
ASSERT_TRUE(NULL != entry2);
// The link entry2->entry1 should be broken.
@@ -1561,7 +1621,7 @@ void DiskCacheBackendTest::BackendFixEnumerators() {
entry2->Close();
// And the second iterator should keep working.
- ASSERT_EQ(net::OK, iter2->OpenNextEntry(&entry2));
+ ASSERT_THAT(iter2->OpenNextEntry(&entry2), IsOk());
ASSERT_TRUE(NULL != entry2);
entry2->Close();
}
@@ -1579,18 +1639,18 @@ void DiskCacheBackendTest::BackendDoomRecent() {
InitCache();
disk_cache::Entry *entry;
- ASSERT_EQ(net::OK, CreateEntry("first", &entry));
+ ASSERT_THAT(CreateEntry("first", &entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, CreateEntry("second", &entry));
+ ASSERT_THAT(CreateEntry("second", &entry), IsOk());
entry->Close();
FlushQueueForTest();
AddDelay();
Time middle = Time::Now();
- ASSERT_EQ(net::OK, CreateEntry("third", &entry));
+ ASSERT_THAT(CreateEntry("third", &entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, CreateEntry("fourth", &entry));
+ ASSERT_THAT(CreateEntry("fourth", &entry), IsOk());
entry->Close();
FlushQueueForTest();
@@ -1598,13 +1658,13 @@ void DiskCacheBackendTest::BackendDoomRecent() {
Time final = Time::Now();
ASSERT_EQ(4, cache_->GetEntryCount());
- EXPECT_EQ(net::OK, DoomEntriesSince(final));
+ EXPECT_THAT(DoomEntriesSince(final), IsOk());
ASSERT_EQ(4, cache_->GetEntryCount());
- EXPECT_EQ(net::OK, DoomEntriesSince(middle));
+ EXPECT_THAT(DoomEntriesSince(middle), IsOk());
ASSERT_EQ(2, cache_->GetEntryCount());
- ASSERT_EQ(net::OK, OpenEntry("second", &entry));
+ ASSERT_THAT(OpenEntry("second", &entry), IsOk());
entry->Close();
}
@@ -1643,13 +1703,13 @@ TEST_F(DiskCacheBackendTest, DoomEntriesSinceSparse) {
TEST_F(DiskCacheBackendTest, MemoryOnlyDoomAllSparse) {
SetMemoryOnlyMode();
InitSparseCache(NULL, NULL);
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
EXPECT_EQ(0, cache_->GetEntryCount());
}
TEST_F(DiskCacheBackendTest, DoomAllSparse) {
InitSparseCache(NULL, NULL);
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
EXPECT_EQ(0, cache_->GetEntryCount());
}
@@ -1657,25 +1717,25 @@ void DiskCacheBackendTest::BackendDoomBetween() {
InitCache();
disk_cache::Entry *entry;
- ASSERT_EQ(net::OK, CreateEntry("first", &entry));
+ ASSERT_THAT(CreateEntry("first", &entry), IsOk());
entry->Close();
FlushQueueForTest();
AddDelay();
Time middle_start = Time::Now();
- ASSERT_EQ(net::OK, CreateEntry("second", &entry));
+ ASSERT_THAT(CreateEntry("second", &entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, CreateEntry("third", &entry));
+ ASSERT_THAT(CreateEntry("third", &entry), IsOk());
entry->Close();
FlushQueueForTest();
AddDelay();
Time middle_end = Time::Now();
- ASSERT_EQ(net::OK, CreateEntry("fourth", &entry));
+ ASSERT_THAT(CreateEntry("fourth", &entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry("fourth", &entry));
+ ASSERT_THAT(OpenEntry("fourth", &entry), IsOk());
entry->Close();
FlushQueueForTest();
@@ -1683,16 +1743,16 @@ void DiskCacheBackendTest::BackendDoomBetween() {
Time final = Time::Now();
ASSERT_EQ(4, cache_->GetEntryCount());
- EXPECT_EQ(net::OK, DoomEntriesBetween(middle_start, middle_end));
+ EXPECT_THAT(DoomEntriesBetween(middle_start, middle_end), IsOk());
ASSERT_EQ(2, cache_->GetEntryCount());
- ASSERT_EQ(net::OK, OpenEntry("fourth", &entry));
+ ASSERT_THAT(OpenEntry("fourth", &entry), IsOk());
entry->Close();
- EXPECT_EQ(net::OK, DoomEntriesBetween(middle_start, final));
+ EXPECT_THAT(DoomEntriesBetween(middle_start, final), IsOk());
ASSERT_EQ(1, cache_->GetEntryCount());
- ASSERT_EQ(net::OK, OpenEntry("first", &entry));
+ ASSERT_THAT(OpenEntry("first", &entry), IsOk());
entry->Close();
}
@@ -1754,7 +1814,7 @@ void DiskCacheBackendTest::BackendCalculateSizeOfAllEntries() {
// Alternate between writing to first two streams to test that we do not
// take only one stream into account.
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
ASSERT_EQ(count, WriteData(entry, count % 2, 0, buffer.get(), count, true));
entry->Close();
@@ -1777,7 +1837,7 @@ void DiskCacheBackendTest::BackendCalculateSizeOfAllEntries() {
disk_cache::Entry* entry;
std::string key = GenerateKey(true);
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
ASSERT_EQ(last_entry_size,
WriteData(entry, 0, 0, buffer.get(), last_entry_size, true));
entry->Close();
@@ -1791,7 +1851,7 @@ void DiskCacheBackendTest::BackendCalculateSizeOfAllEntries() {
}
// After dooming the entries, the size should be back to zero.
- ASSERT_EQ(net::OK, DoomAllEntries());
+ ASSERT_THAT(DoomAllEntries(), IsOk());
EXPECT_EQ(0, CalculateSizeOfAllEntries());
}
@@ -1978,7 +2038,7 @@ TEST_F(DiskCacheTest, WrongVersion) {
std::unique_ptr<disk_cache::BackendImpl> cache(new disk_cache::BackendImpl(
cache_path_, cache_thread.task_runner(), NULL));
int rv = cache->Init(cb.callback());
- ASSERT_EQ(net::ERR_FAILED, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsError(net::ERR_FAILED));
}
// Tests that the disk cache successfully joins the control group, dropping the
@@ -1998,7 +2058,8 @@ TEST_F(DiskCacheTest, SimpleCacheControlJoin) {
// Instantiate the SimpleCacheTrial, forcing this run into the
// ExperimentControl group.
- base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
+ base::FieldTrialList field_trial_list(
+ base::MakeUnique<base::MockEntropyProvider>());
base::FieldTrialList::CreateFieldTrial("SimpleCacheTrial",
"ExperimentControl");
net::TestCompletionCallback cb;
@@ -2012,7 +2073,7 @@ TEST_F(DiskCacheTest, SimpleCacheControlJoin) {
NULL,
&base_cache,
cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
EXPECT_EQ(0, base_cache->GetEntryCount());
}
#endif
@@ -2022,7 +2083,8 @@ TEST_F(DiskCacheTest, SimpleCacheControlJoin) {
TEST_F(DiskCacheTest, SimpleCacheControlRestart) {
// Instantiate the SimpleCacheTrial, forcing this run into the
// ExperimentControl group.
- base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
+ base::FieldTrialList field_trial_list(
+ base::MakeUnique<base::MockEntropyProvider>());
base::FieldTrialList::CreateFieldTrial("SimpleCacheTrial",
"ExperimentControl");
@@ -2041,12 +2103,12 @@ TEST_F(DiskCacheTest, SimpleCacheControlRestart) {
cache.reset(new disk_cache::BackendImpl(cache_path_,
cache_thread.task_runner(), NULL));
int rv = cache->Init(cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
EXPECT_EQ(1, cache->GetEntryCount());
disk_cache::Entry* entry = NULL;
rv = cache->OpenEntry(kExistingEntryKey, &entry, cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
EXPECT_NE(nullptr, entry);
entry->Close();
}
@@ -2062,7 +2124,8 @@ TEST_F(DiskCacheTest, SimpleCacheControlLeave) {
{
// Instantiate the SimpleCacheTrial, forcing this run into the
// ExperimentControl group.
- base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
+ base::FieldTrialList field_trial_list(
+ base::MakeUnique<base::MockEntropyProvider>());
base::FieldTrialList::CreateFieldTrial("SimpleCacheTrial",
"ExperimentControl");
@@ -2073,7 +2136,8 @@ TEST_F(DiskCacheTest, SimpleCacheControlLeave) {
// Instantiate the SimpleCacheTrial, forcing this run into the
// ExperimentNo group.
- base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
+ base::FieldTrialList field_trial_list(
+ base::MakeUnique<base::MockEntropyProvider>());
base::FieldTrialList::CreateFieldTrial("SimpleCacheTrial", "ExperimentNo");
net::TestCompletionCallback cb;
@@ -2082,12 +2146,12 @@ TEST_F(DiskCacheTest, SimpleCacheControlLeave) {
std::unique_ptr<disk_cache::BackendImpl> cache(new disk_cache::BackendImpl(
cache_path_, cache_thread.task_runner(), NULL));
int rv = cache->Init(cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
EXPECT_EQ(1, cache->GetEntryCount());
disk_cache::Entry* entry = NULL;
rv = cache->OpenEntry(kExistingEntryKey, &entry, cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
EXPECT_NE(nullptr, entry);
entry->Close();
}
@@ -2117,7 +2181,7 @@ TEST_F(DiskCacheBackendTest, DeleteOld) {
&cache_,
cb.callback());
path.clear(); // Make sure path was captured by the previous call.
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
base::ThreadRestrictions::SetIOAllowed(prev);
cache_.reset();
EXPECT_TRUE(CheckCacheIntegrity(cache_path_, new_eviction_, mask_));
@@ -2131,7 +2195,7 @@ void DiskCacheBackendTest::BackendInvalidEntry2() {
InitCache();
disk_cache::Entry *entry1, *entry2;
- ASSERT_EQ(net::OK, OpenEntry("the first key", &entry1));
+ ASSERT_THAT(OpenEntry("the first key", &entry1), IsOk());
EXPECT_NE(net::OK, OpenEntry("some other key", &entry2));
entry1->Close();
@@ -2227,12 +2291,12 @@ TEST_F(DiskCacheBackendTest, BadNextEntry1) {
// though the index, but it is at the head of the LRU.
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry("The first key", &entry));
+ ASSERT_THAT(CreateEntry("The first key", &entry), IsOk());
entry->Close();
TrimForTest(false);
TrimForTest(false);
- ASSERT_EQ(net::OK, OpenEntry("The first key", &entry));
+ ASSERT_THAT(OpenEntry("The first key", &entry), IsOk());
entry->Close();
EXPECT_EQ(1, cache_->GetEntryCount());
}
@@ -2261,14 +2325,14 @@ TEST_F(DiskCacheBackendTest, NewEvictionInvalidEntry6) {
// The second entry is dirty, but removing it should not corrupt the list.
disk_cache::Entry* entry;
ASSERT_NE(net::OK, OpenEntry("the second key", &entry));
- ASSERT_EQ(net::OK, OpenEntry("the first key", &entry));
+ ASSERT_THAT(OpenEntry("the first key", &entry), IsOk());
// This should not delete the cache.
entry->Doom();
FlushQueueForTest();
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry("some other key", &entry));
+ ASSERT_THAT(OpenEntry("some other key", &entry), IsOk());
entry->Close();
}
@@ -2282,9 +2346,9 @@ void DiskCacheBackendTest::BackendInvalidEntry7() {
std::string first("some key");
std::string second("something else");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(first, &entry));
+ ASSERT_THAT(CreateEntry(first, &entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, CreateEntry(second, &entry));
+ ASSERT_THAT(CreateEntry(second, &entry), IsOk());
// Corrupt this entry.
disk_cache::EntryImpl* entry_impl =
@@ -2326,9 +2390,9 @@ void DiskCacheBackendTest::BackendInvalidEntry8() {
std::string first("some key");
std::string second("something else");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(first, &entry));
+ ASSERT_THAT(CreateEntry(first, &entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, CreateEntry(second, &entry));
+ ASSERT_THAT(CreateEntry(second, &entry), IsOk());
// Corrupt this entry.
disk_cache::EntryImpl* entry_impl =
@@ -2346,7 +2410,7 @@ void DiskCacheBackendTest::BackendInvalidEntry8() {
// We should not delete the cache.
std::unique_ptr<TestIterator> iter = CreateIterator();
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry));
+ ASSERT_THAT(iter->OpenNextEntry(&entry), IsOk());
entry->Close();
EXPECT_NE(net::OK, iter->OpenNextEntry(&entry));
EXPECT_EQ(1, cache_->GetEntryCount());
@@ -2373,9 +2437,9 @@ void DiskCacheBackendTest::BackendInvalidEntry9(bool eviction) {
std::string first("some key");
std::string second("something else");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(first, &entry));
+ ASSERT_THAT(CreateEntry(first, &entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, CreateEntry(second, &entry));
+ ASSERT_THAT(CreateEntry(second, &entry), IsOk());
// Corrupt this entry.
disk_cache::EntryImpl* entry_impl =
@@ -2399,7 +2463,7 @@ void DiskCacheBackendTest::BackendInvalidEntry9(bool eviction) {
EXPECT_NE(net::OK, iter->OpenNextEntry(&entry));
// Now a full iteration will work, and return one entry.
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry));
+ ASSERT_THAT(iter->OpenNextEntry(&entry), IsOk());
entry->Close();
EXPECT_NE(net::OK, iter->OpenNextEntry(&entry));
@@ -2438,12 +2502,12 @@ void DiskCacheBackendTest::BackendInvalidEntry10(bool eviction) {
std::string first("some key");
std::string second("something else");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(first, &entry));
+ ASSERT_THAT(CreateEntry(first, &entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(first, &entry));
+ ASSERT_THAT(OpenEntry(first, &entry), IsOk());
EXPECT_EQ(0, WriteData(entry, 0, 200, NULL, 0, false));
entry->Close();
- ASSERT_EQ(net::OK, CreateEntry(second, &entry));
+ ASSERT_THAT(CreateEntry(second, &entry), IsOk());
// Corrupt this entry.
disk_cache::EntryImpl* entry_impl =
@@ -2452,7 +2516,7 @@ void DiskCacheBackendTest::BackendInvalidEntry10(bool eviction) {
entry_impl->entry()->Data()->state = 0xbad;
entry_impl->entry()->Store();
entry->Close();
- ASSERT_EQ(net::OK, CreateEntry("third", &entry));
+ ASSERT_THAT(CreateEntry("third", &entry), IsOk());
entry->Close();
EXPECT_EQ(3, cache_->GetEntryCount());
@@ -2473,9 +2537,9 @@ void DiskCacheBackendTest::BackendInvalidEntry10(bool eviction) {
// We should detect the problem through the list, but we should not delete
// the entry.
std::unique_ptr<TestIterator> iter = CreateIterator();
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry));
+ ASSERT_THAT(iter->OpenNextEntry(&entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry));
+ ASSERT_THAT(iter->OpenNextEntry(&entry), IsOk());
EXPECT_EQ(first, entry->GetKey());
entry->Close();
EXPECT_NE(net::OK, iter->OpenNextEntry(&entry));
@@ -2501,14 +2565,14 @@ void DiskCacheBackendTest::BackendInvalidEntry11(bool eviction) {
std::string first("some key");
std::string second("something else");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(first, &entry));
+ ASSERT_THAT(CreateEntry(first, &entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(first, &entry));
+ ASSERT_THAT(OpenEntry(first, &entry), IsOk());
EXPECT_EQ(0, WriteData(entry, 0, 200, NULL, 0, false));
entry->Close();
- ASSERT_EQ(net::OK, CreateEntry(second, &entry));
+ ASSERT_THAT(CreateEntry(second, &entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(second, &entry));
+ ASSERT_THAT(OpenEntry(second, &entry), IsOk());
EXPECT_EQ(0, WriteData(entry, 0, 200, NULL, 0, false));
// Corrupt this entry.
@@ -2518,7 +2582,7 @@ void DiskCacheBackendTest::BackendInvalidEntry11(bool eviction) {
entry_impl->entry()->Data()->state = 0xbad;
entry_impl->entry()->Store();
entry->Close();
- ASSERT_EQ(net::OK, CreateEntry("third", &entry));
+ ASSERT_THAT(CreateEntry("third", &entry), IsOk());
entry->Close();
FlushQueueForTest();
EXPECT_EQ(3, cache_->GetEntryCount());
@@ -2540,14 +2604,14 @@ void DiskCacheBackendTest::BackendInvalidEntry11(bool eviction) {
// We should detect the problem through the list, but we should not delete
// the entry, just fail the iteration.
std::unique_ptr<TestIterator> iter = CreateIterator();
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry));
+ ASSERT_THAT(iter->OpenNextEntry(&entry), IsOk());
entry->Close();
EXPECT_NE(net::OK, iter->OpenNextEntry(&entry));
// Now a full iteration will work, and return two entries.
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry));
+ ASSERT_THAT(iter->OpenNextEntry(&entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry));
+ ASSERT_THAT(iter->OpenNextEntry(&entry), IsOk());
entry->Close();
EXPECT_NE(net::OK, iter->OpenNextEntry(&entry));
}
@@ -2571,9 +2635,9 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry12() {
std::string first("some key");
std::string second("something else");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(first, &entry));
+ ASSERT_THAT(CreateEntry(first, &entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, CreateEntry(second, &entry));
+ ASSERT_THAT(CreateEntry(second, &entry), IsOk());
// Corrupt this entry.
disk_cache::EntryImpl* entry_impl =
@@ -2582,9 +2646,9 @@ void DiskCacheBackendTest::BackendTrimInvalidEntry12() {
entry_impl->entry()->Data()->state = 0xbad;
entry_impl->entry()->Store();
entry->Close();
- ASSERT_EQ(net::OK, CreateEntry("third", &entry));
+ ASSERT_THAT(CreateEntry("third", &entry), IsOk());
entry->Close();
- ASSERT_EQ(net::OK, CreateEntry("fourth", &entry));
+ ASSERT_THAT(CreateEntry("fourth", &entry), IsOk());
TrimForTest(true);
EXPECT_EQ(1, cache_->GetEntryCount());
entry->Close();
@@ -2608,7 +2672,7 @@ void DiskCacheBackendTest::BackendInvalidRankings2() {
disk_cache::Entry *entry1, *entry2;
EXPECT_NE(net::OK, OpenEntry("the first key", &entry1));
- ASSERT_EQ(net::OK, OpenEntry("some other key", &entry2));
+ ASSERT_THAT(OpenEntry("some other key", &entry2), IsOk());
entry2->Close();
// CheckCacheIntegrity will fail at this point.
@@ -2628,7 +2692,7 @@ TEST_F(DiskCacheBackendTest, NewEvictionInvalidRankings2) {
void DiskCacheBackendTest::BackendInvalidRankings() {
disk_cache::Entry* entry;
std::unique_ptr<TestIterator> iter = CreateIterator();
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry));
+ ASSERT_THAT(iter->OpenNextEntry(&entry), IsOk());
entry->Close();
EXPECT_EQ(2, cache_->GetEntryCount());
@@ -2673,7 +2737,7 @@ TEST_F(DiskCacheBackendTest, NewEvictionInvalidRankingsFailure) {
void DiskCacheBackendTest::BackendDisable() {
disk_cache::Entry *entry1, *entry2;
std::unique_ptr<TestIterator> iter = CreateIterator();
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry1));
+ ASSERT_THAT(iter->OpenNextEntry(&entry1), IsOk());
EXPECT_NE(net::OK, iter->OpenNextEntry(&entry2));
EXPECT_EQ(0, cache_->GetEntryCount());
@@ -2773,13 +2837,13 @@ void DiskCacheBackendTest::BackendDisable3() {
disk_cache::Entry *entry1, *entry2;
std::unique_ptr<TestIterator> iter = CreateIterator();
EXPECT_EQ(2, cache_->GetEntryCount());
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry1));
+ ASSERT_THAT(iter->OpenNextEntry(&entry1), IsOk());
entry1->Close();
EXPECT_NE(net::OK, iter->OpenNextEntry(&entry2));
FlushQueueForTest();
- ASSERT_EQ(net::OK, CreateEntry("Something new", &entry2));
+ ASSERT_THAT(CreateEntry("Something new", &entry2), IsOk());
entry2->Close();
EXPECT_EQ(1, cache_->GetEntryCount());
@@ -2806,7 +2870,7 @@ TEST_F(DiskCacheBackendTest, NewEvictionDisableSuccess3) {
void DiskCacheBackendTest::BackendDisable4() {
disk_cache::Entry *entry1, *entry2, *entry3, *entry4;
std::unique_ptr<TestIterator> iter = CreateIterator();
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry1));
+ ASSERT_THAT(iter->OpenNextEntry(&entry1), IsOk());
char key2[2000];
char key3[20000];
@@ -2814,8 +2878,8 @@ void DiskCacheBackendTest::BackendDisable4() {
CacheTestFillBuffer(key3, sizeof(key3), true);
key2[sizeof(key2) - 1] = '\0';
key3[sizeof(key3) - 1] = '\0';
- ASSERT_EQ(net::OK, CreateEntry(key2, &entry2));
- ASSERT_EQ(net::OK, CreateEntry(key3, &entry3));
+ ASSERT_THAT(CreateEntry(key2, &entry2), IsOk());
+ ASSERT_THAT(CreateEntry(key3, &entry3), IsOk());
const int kBufSize = 20000;
scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kBufSize));
@@ -2873,7 +2937,7 @@ void DiskCacheBackendTest::BackendDisabledAPI() {
disk_cache::Entry* entry1, *entry2;
std::unique_ptr<TestIterator> iter = CreateIterator();
EXPECT_EQ(2, cache_->GetEntryCount());
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry1));
+ ASSERT_THAT(iter->OpenNextEntry(&entry1), IsOk());
entry1->Close();
EXPECT_NE(net::OK, iter->OpenNextEntry(&entry2));
FlushQueueForTest();
@@ -2932,7 +2996,7 @@ void DiskCacheBackendTest::BackendEviction() {
for (int i = 0; i < kWriteEntryCount; ++i) {
AddDelay();
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key_prefix + base::IntToString(i), &entry));
+ ASSERT_THAT(CreateEntry(key_prefix + base::IntToString(i), &entry), IsOk());
disk_cache::ScopedEntryPtr entry_closer(entry);
EXPECT_EQ(kWriteSize,
WriteData(entry, 1, 0, buffer.get(), kWriteSize, false));
@@ -2971,7 +3035,7 @@ TEST_F(DiskCacheBackendTest, MemoryOnlyUseAfterFree) {
// Create an entry to be our sparse entry that gets written later.
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry("first parent", &entry));
+ ASSERT_THAT(CreateEntry("first parent", &entry), IsOk());
disk_cache::ScopedEntryPtr first_parent(entry);
// Create a ton of entries, and keep them open, to put the cache well above
@@ -2980,7 +3044,7 @@ TEST_F(DiskCacheBackendTest, MemoryOnlyUseAfterFree) {
std::list<disk_cache::ScopedEntryPtr> open_entries;
std::string key_prefix("prefix");
for (int i = 0; i < kTooManyEntriesCount; ++i) {
- ASSERT_EQ(net::OK, CreateEntry(key_prefix + base::IntToString(i), &entry));
+ ASSERT_THAT(CreateEntry(key_prefix + base::IntToString(i), &entry), IsOk());
EXPECT_EQ(kWriteSize,
WriteData(entry, 1, 0, buffer.get(), kWriteSize, false));
open_entries.push_back(disk_cache::ScopedEntryPtr(entry));
@@ -3001,7 +3065,7 @@ TEST_F(DiskCacheTest, Backend_UsageStatsTimer) {
cache_path_, base::ThreadTaskRunnerHandle::Get(), NULL));
ASSERT_TRUE(NULL != cache.get());
cache->SetUnitTestMode();
- ASSERT_EQ(net::OK, cache->SyncInit());
+ ASSERT_THAT(cache->SyncInit(), IsOk());
// Wait for a callback that never comes... about 2 secs :). The message loop
// has to run to allow invocation of the usage timer.
@@ -3026,7 +3090,7 @@ TEST_F(DiskCacheBackendTest, TimerNotCreated) {
TEST_F(DiskCacheBackendTest, Backend_UsageStats) {
InitCache();
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry("key", &entry));
+ ASSERT_THAT(CreateEntry("key", &entry), IsOk());
entry->Close();
FlushQueueForTest();
@@ -3055,16 +3119,16 @@ void DiskCacheBackendTest::BackendDoomAll() {
InitCache();
disk_cache::Entry *entry1, *entry2;
- ASSERT_EQ(net::OK, CreateEntry("first", &entry1));
- ASSERT_EQ(net::OK, CreateEntry("second", &entry2));
+ ASSERT_THAT(CreateEntry("first", &entry1), IsOk());
+ ASSERT_THAT(CreateEntry("second", &entry2), IsOk());
entry1->Close();
entry2->Close();
- ASSERT_EQ(net::OK, CreateEntry("third", &entry1));
- ASSERT_EQ(net::OK, CreateEntry("fourth", &entry2));
+ ASSERT_THAT(CreateEntry("third", &entry1), IsOk());
+ ASSERT_THAT(CreateEntry("fourth", &entry2), IsOk());
ASSERT_EQ(4, cache_->GetEntryCount());
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
ASSERT_EQ(0, cache_->GetEntryCount());
// We should stop posting tasks at some point (if we post any).
@@ -3072,10 +3136,10 @@ void DiskCacheBackendTest::BackendDoomAll() {
disk_cache::Entry *entry3, *entry4;
EXPECT_NE(net::OK, OpenEntry("third", &entry3));
- ASSERT_EQ(net::OK, CreateEntry("third", &entry3));
- ASSERT_EQ(net::OK, CreateEntry("fourth", &entry4));
+ ASSERT_THAT(CreateEntry("third", &entry3), IsOk());
+ ASSERT_THAT(CreateEntry("fourth", &entry4), IsOk());
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
ASSERT_EQ(0, cache_->GetEntryCount());
entry1->Close();
@@ -3085,16 +3149,16 @@ void DiskCacheBackendTest::BackendDoomAll() {
entry4->Close();
// Now try with all references released.
- ASSERT_EQ(net::OK, CreateEntry("third", &entry1));
- ASSERT_EQ(net::OK, CreateEntry("fourth", &entry2));
+ ASSERT_THAT(CreateEntry("third", &entry1), IsOk());
+ ASSERT_THAT(CreateEntry("fourth", &entry2), IsOk());
entry1->Close();
entry2->Close();
ASSERT_EQ(2, cache_->GetEntryCount());
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
ASSERT_EQ(0, cache_->GetEntryCount());
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
}
TEST_F(DiskCacheBackendTest, DoomAll) {
@@ -3124,10 +3188,10 @@ TEST_F(DiskCacheBackendTest, ShaderCacheOnlyDoomAll) {
// If the index size changes when we doom the cache, we should not crash.
void DiskCacheBackendTest::BackendDoomAll2() {
EXPECT_EQ(2, cache_->GetEntryCount());
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry("Something new", &entry));
+ ASSERT_THAT(CreateEntry("Something new", &entry), IsOk());
entry->Close();
EXPECT_EQ(1, cache_->GetEntryCount());
@@ -3165,26 +3229,14 @@ TEST_F(DiskCacheTest, MultipleInstances) {
const int kNumberOfCaches = 2;
std::unique_ptr<disk_cache::Backend> cache[kNumberOfCaches];
- int rv = disk_cache::CreateCacheBackend(net::DISK_CACHE,
- net::CACHE_BACKEND_DEFAULT,
- store1.path(),
- 0,
- false,
- cache_thread.task_runner(),
- NULL,
- &cache[0],
- cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
- rv = disk_cache::CreateCacheBackend(net::MEDIA_CACHE,
- net::CACHE_BACKEND_DEFAULT,
- store2.path(),
- 0,
- false,
- cache_thread.task_runner(),
- NULL,
- &cache[1],
- cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ int rv = disk_cache::CreateCacheBackend(
+ net::DISK_CACHE, net::CACHE_BACKEND_DEFAULT, store1.GetPath(), 0, false,
+ cache_thread.task_runner(), NULL, &cache[0], cb.callback());
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
+ rv = disk_cache::CreateCacheBackend(
+ net::MEDIA_CACHE, net::CACHE_BACKEND_DEFAULT, store2.GetPath(), 0, false,
+ cache_thread.task_runner(), NULL, &cache[1], cb.callback());
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
ASSERT_TRUE(cache[0].get() != NULL && cache[1].get() != NULL);
@@ -3192,7 +3244,7 @@ TEST_F(DiskCacheTest, MultipleInstances) {
disk_cache::Entry* entry;
for (int i = 0; i < kNumberOfCaches; i++) {
rv = cache[i]->CreateEntry(key, &entry, cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
entry->Close();
}
}
@@ -3263,7 +3315,7 @@ TEST_F(DiskCacheBackendTest, TotalBuffersSize1) {
InitCache();
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize = 200;
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize));
@@ -3285,7 +3337,7 @@ TEST_F(DiskCacheBackendTest, TotalBuffersSize1) {
// Delete the second buffer, writing 10 bytes to disk.
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
}
entry->Close();
@@ -3365,7 +3417,7 @@ TEST_F(DiskCacheBackendTest, UpdateRankForExternalCacheHit) {
for (int i = 0; i < 2; ++i) {
std::string key = base::StringPrintf("key%d", i);
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
entry->Close();
}
@@ -3376,7 +3428,7 @@ TEST_F(DiskCacheBackendTest, UpdateRankForExternalCacheHit) {
// Make sure the older key remains.
EXPECT_EQ(1, cache_->GetEntryCount());
- ASSERT_EQ(net::OK, OpenEntry("key0", &entry));
+ ASSERT_THAT(OpenEntry("key0", &entry), IsOk());
entry->Close();
}
@@ -3388,7 +3440,7 @@ TEST_F(DiskCacheBackendTest, ShaderCacheUpdateRankForExternalCacheHit) {
for (int i = 0; i < 2; ++i) {
std::string key = base::StringPrintf("key%d", i);
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
entry->Close();
}
@@ -3399,7 +3451,7 @@ TEST_F(DiskCacheBackendTest, ShaderCacheUpdateRankForExternalCacheHit) {
// Make sure the older key remains.
EXPECT_EQ(1, cache_->GetEntryCount());
- ASSERT_EQ(net::OK, OpenEntry("key0", &entry));
+ ASSERT_THAT(OpenEntry("key0", &entry), IsOk());
entry->Close();
}
@@ -3493,14 +3545,14 @@ TEST_F(DiskCacheBackendTest, SimpleCacheOpenMissingFile) {
const char key[] = "the first key";
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
ASSERT_TRUE(entry != NULL);
entry->Close();
entry = NULL;
// To make sure the file creation completed we need to call open again so that
// we block until it actually created the files.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
ASSERT_TRUE(entry != NULL);
entry->Close();
entry = NULL;
@@ -3512,7 +3564,7 @@ TEST_F(DiskCacheBackendTest, SimpleCacheOpenMissingFile) {
EXPECT_TRUE(disk_cache::DeleteCacheFile(to_delete_file));
// Failing to open the entry should delete the rest of these files.
- ASSERT_EQ(net::ERR_FAILED, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsError(net::ERR_FAILED));
// Confirm the rest of the files are gone.
for (int i = 1; i < disk_cache::kSimpleEntryFileCount; ++i) {
@@ -3529,7 +3581,7 @@ TEST_F(DiskCacheBackendTest, SimpleCacheOpenBadFile) {
const char key[] = "the first key";
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
disk_cache::Entry* null = NULL;
ASSERT_NE(null, entry);
entry->Close();
@@ -3537,7 +3589,7 @@ TEST_F(DiskCacheBackendTest, SimpleCacheOpenBadFile) {
// To make sure the file creation completed we need to call open again so that
// we block until it actually created the files.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
ASSERT_NE(null, entry);
entry->Close();
entry = NULL;
@@ -3555,7 +3607,7 @@ TEST_F(DiskCacheBackendTest, SimpleCacheOpenBadFile) {
EXPECT_EQ(static_cast<int>(sizeof(header)),
base::WriteFile(entry_file1_path, reinterpret_cast<char*>(&header),
sizeof(header)));
- ASSERT_EQ(net::ERR_FAILED, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsError(net::ERR_FAILED));
}
// Tests that the Simple Cache Backend fails to initialize with non-matching
@@ -3567,7 +3619,7 @@ TEST_F(DiskCacheBackendTest, SimpleCacheOverBlockfileCache) {
const int kSize = 50;
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize));
CacheTestFillBuffer(buffer->data(), kSize, false);
- ASSERT_EQ(net::OK, CreateEntry("key", &entry));
+ ASSERT_THAT(CreateEntry("key", &entry), IsOk());
ASSERT_EQ(0, WriteData(entry, 0, 0, buffer.get(), 0, false));
entry->Close();
cache_.reset();
@@ -3596,7 +3648,7 @@ TEST_F(DiskCacheBackendTest, BlockfileCacheOverSimpleCache) {
const int kSize = 50;
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize));
CacheTestFillBuffer(buffer->data(), kSize, false);
- ASSERT_EQ(net::OK, CreateEntry("key", &entry));
+ ASSERT_THAT(CreateEntry("key", &entry), IsOk());
ASSERT_EQ(0, WriteData(entry, 0, 0, buffer.get(), 0, false));
entry->Close();
cache_.reset();
@@ -3642,7 +3694,7 @@ TEST_F(DiskCacheBackendTest, SimpleCacheEnumerationBasics) {
iter = CreateIterator();
count = 0;
disk_cache::Entry* entry_opened_before;
- ASSERT_EQ(net::OK, OpenEntry(*(key_pool.begin()), &entry_opened_before));
+ ASSERT_THAT(OpenEntry(*(key_pool.begin()), &entry_opened_before), IsOk());
ASSERT_TRUE(EnumerateAndMatchKeys(key_pool.size()/2,
iter.get(),
&keys_to_match,
@@ -3688,6 +3740,8 @@ TEST_F(DiskCacheBackendTest, SimpleCacheEnumerationWhileDoomed) {
EXPECT_TRUE(keys_to_match.empty());
}
+// This test is flaky on Android Marshmallow crbug.com/638891.
+#if !defined(OS_ANDROID)
// Tests that enumerations are not affected by corrupt files.
TEST_F(DiskCacheBackendTest, SimpleCacheEnumerationCorruption) {
SetSimpleCacheMode();
@@ -3698,7 +3752,7 @@ TEST_F(DiskCacheBackendTest, SimpleCacheEnumerationCorruption) {
const std::string key = "the key";
disk_cache::Entry* corrupted_entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &corrupted_entry));
+ ASSERT_THAT(CreateEntry(key, &corrupted_entry), IsOk());
ASSERT_TRUE(corrupted_entry);
const int kSize = 50;
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize));
@@ -3725,6 +3779,7 @@ TEST_F(DiskCacheBackendTest, SimpleCacheEnumerationCorruption) {
EXPECT_EQ(key_pool.size(), count);
EXPECT_TRUE(keys_to_match.empty());
}
+#endif
// Tests that enumerations don't leak memory when the backend is destructed
// mid-enumeration.
@@ -3736,7 +3791,7 @@ TEST_F(DiskCacheBackendTest, SimpleCacheEnumerationDestruction) {
std::unique_ptr<TestIterator> iter = CreateIterator();
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, iter->OpenNextEntry(&entry));
+ ASSERT_THAT(iter->OpenNextEntry(&entry), IsOk());
EXPECT_TRUE(entry);
disk_cache::ScopedEntryPtr entry_closer(entry);
@@ -3756,7 +3811,7 @@ TEST_F(DiskCacheBackendTest, SimpleCacheEnumerationLongKeys) {
std::string long_key(long_key_length, 'X');
key_pool.insert(long_key);
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, CreateEntry(long_key.c_str(), &entry));
+ ASSERT_THAT(CreateEntry(long_key.c_str(), &entry), IsOk());
entry->Close();
std::unique_ptr<TestIterator> iter = CreateIterator();
@@ -3782,8 +3837,8 @@ TEST_F(DiskCacheBackendTest, SimpleCacheLateDoom) {
InitCache();
disk_cache::Entry *entry1, *entry2;
- ASSERT_EQ(net::OK, CreateEntry("first", &entry1));
- ASSERT_EQ(net::OK, CreateEntry("second", &entry2));
+ ASSERT_THAT(CreateEntry("first", &entry1), IsOk());
+ ASSERT_THAT(CreateEntry("second", &entry2), IsOk());
entry1->Close();
// Ensure that the directory mtime is flushed to disk before serializing the
diff --git a/chromium/net/disk_cache/blockfile/backend_impl.cc b/chromium/net/disk_cache/blockfile/backend_impl.cc
index e52900844f6..f0cdb0c9048 100644
--- a/chromium/net/disk_cache/blockfile/backend_impl.cc
+++ b/chromium/net/disk_cache/blockfile/backend_impl.cc
@@ -1421,9 +1421,7 @@ void BackendImpl::AdjustMaxCacheSize(int table_len) {
return;
// If we already have a table, adjust the size to it.
- int current_max_size = MaxStorageSizeForTable(table_len);
- if (max_size_ > current_max_size)
- max_size_= current_max_size;
+ max_size_ = std::min(max_size_, MaxStorageSizeForTable(table_len));
}
bool BackendImpl::InitStats() {
@@ -1493,7 +1491,7 @@ void BackendImpl::RestartCache(bool failure) {
PrepareForRestart();
if (failure) {
DCHECK(!num_refs_);
- DCHECK(!open_entries_.size());
+ DCHECK(open_entries_.empty());
DelayedCacheCleanup(path_);
} else {
DeleteCache(path_, false);
@@ -1501,9 +1499,9 @@ void BackendImpl::RestartCache(bool failure) {
// Don't call Init() if directed by the unit test: we are simulating a failure
// trying to re-enable the cache.
- if (unit_test_)
+ if (unit_test_) {
init_ = true; // Let the destructor do proper cleanup.
- else if (SyncInit() == net::OK) {
+ } else if (SyncInit() == net::OK) {
stats_.SetCounter(Stats::FATAL_ERROR, errors);
stats_.SetCounter(Stats::DOOM_CACHE, full_dooms);
stats_.SetCounter(Stats::DOOM_RECENT, partial_dooms);
diff --git a/chromium/net/disk_cache/blockfile/backend_impl.h b/chromium/net/disk_cache/blockfile/backend_impl.h
index 5ecd3072ae7..4b44ace5fd4 100644
--- a/chromium/net/disk_cache/blockfile/backend_impl.h
+++ b/chromium/net/disk_cache/blockfile/backend_impl.h
@@ -15,6 +15,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/timer/timer.h"
+#include "net/base/net_export.h"
#include "net/disk_cache/blockfile/block_files.h"
#include "net/disk_cache/blockfile/eviction.h"
#include "net/disk_cache/blockfile/in_flight_backend_io.h"
diff --git a/chromium/net/disk_cache/blockfile/disk_format_base.h b/chromium/net/disk_cache/blockfile/disk_format_base.h
index bd7a12b4c4e..88dcfe091c0 100644
--- a/chromium/net/disk_cache/blockfile/disk_format_base.h
+++ b/chromium/net/disk_cache/blockfile/disk_format_base.h
@@ -22,8 +22,6 @@
#include <stdint.h>
-#include "net/base/net_export.h"
-
namespace disk_cache {
typedef uint32_t CacheAddr;
diff --git a/chromium/net/disk_cache/blockfile/entry_impl.cc b/chromium/net/disk_cache/blockfile/entry_impl.cc
index b20e10423c2..562efdf63f2 100644
--- a/chromium/net/disk_cache/blockfile/entry_impl.cc
+++ b/chromium/net/disk_cache/blockfile/entry_impl.cc
@@ -19,6 +19,9 @@
#include "net/disk_cache/blockfile/sparse_control.h"
#include "net/disk_cache/cache_util.h"
#include "net/disk_cache/net_log_parameters.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source_type.h"
// Provide a BackendImpl object to macros from histogram_macros.h.
#define CACHE_UMA_BACKEND_IMPL_OBJ backend_
@@ -38,11 +41,15 @@ class SyncCallback: public disk_cache::FileIOCallback {
public:
// |end_event_type| is the event type to log on completion. Logs nothing on
// discard, or when the NetLog is not set to log all events.
- SyncCallback(disk_cache::EntryImpl* entry, net::IOBuffer* buffer,
+ SyncCallback(disk_cache::EntryImpl* entry,
+ net::IOBuffer* buffer,
const net::CompletionCallback& callback,
- net::NetLog::EventType end_event_type)
- : entry_(entry), callback_(callback), buf_(buffer),
- start_(TimeTicks::Now()), end_event_type_(end_event_type) {
+ net::NetLogEventType end_event_type)
+ : entry_(entry),
+ callback_(callback),
+ buf_(buffer),
+ start_(TimeTicks::Now()),
+ end_event_type_(end_event_type) {
entry->AddRef();
entry->IncrementIoCount();
}
@@ -56,7 +63,7 @@ class SyncCallback: public disk_cache::FileIOCallback {
net::CompletionCallback callback_;
scoped_refptr<net::IOBuffer> buf_;
TimeTicks start_;
- const net::NetLog::EventType end_event_type_;
+ const net::NetLogEventType end_event_type_;
DISALLOW_COPY_AND_ASSIGN(SyncCallback);
};
@@ -319,16 +326,15 @@ int EntryImpl::ReadDataImpl(int index, int offset, IOBuffer* buf, int buf_len,
const CompletionCallback& callback) {
if (net_log_.IsCapturing()) {
net_log_.BeginEvent(
- net::NetLog::TYPE_ENTRY_READ_DATA,
+ net::NetLogEventType::ENTRY_READ_DATA,
CreateNetLogReadWriteDataCallback(index, offset, buf_len, false));
}
int result = InternalReadData(index, offset, buf, buf_len, callback);
if (result != net::ERR_IO_PENDING && net_log_.IsCapturing()) {
- net_log_.EndEvent(
- net::NetLog::TYPE_ENTRY_READ_DATA,
- CreateNetLogReadWriteCompleteCallback(result));
+ net_log_.EndEvent(net::NetLogEventType::ENTRY_READ_DATA,
+ CreateNetLogReadWriteCompleteCallback(result));
}
return result;
}
@@ -338,7 +344,7 @@ int EntryImpl::WriteDataImpl(int index, int offset, IOBuffer* buf, int buf_len,
bool truncate) {
if (net_log_.IsCapturing()) {
net_log_.BeginEvent(
- net::NetLog::TYPE_ENTRY_WRITE_DATA,
+ net::NetLogEventType::ENTRY_WRITE_DATA,
CreateNetLogReadWriteDataCallback(index, offset, buf_len, truncate));
}
@@ -346,9 +352,8 @@ int EntryImpl::WriteDataImpl(int index, int offset, IOBuffer* buf, int buf_len,
truncate);
if (result != net::ERR_IO_PENDING && net_log_.IsCapturing()) {
- net_log_.EndEvent(
- net::NetLog::TYPE_ENTRY_WRITE_DATA,
- CreateNetLogReadWriteCompleteCallback(result));
+ net_log_.EndEvent(net::NetLogEventType::ENTRY_WRITE_DATA,
+ CreateNetLogReadWriteCompleteCallback(result));
}
return result;
}
@@ -466,7 +471,7 @@ bool EntryImpl::IsSameEntry(const std::string& key, uint32_t hash) {
}
void EntryImpl::InternalDoom() {
- net_log_.AddEvent(net::NetLog::TYPE_ENTRY_DOOM);
+ net_log_.AddEvent(net::NetLogEventType::ENTRY_DOOM);
DCHECK(node_.HasData());
if (!node_.Data()->dirty) {
node_.Data()->dirty = backend_->GetCurrentEntryId();
@@ -731,14 +736,13 @@ void EntryImpl::ReportIOTime(Operation op, const base::TimeTicks& start) {
void EntryImpl::BeginLogging(net::NetLog* net_log, bool created) {
DCHECK(!net_log_.net_log());
- net_log_ = net::BoundNetLog::Make(
- net_log, net::NetLog::SOURCE_DISK_CACHE_ENTRY);
- net_log_.BeginEvent(
- net::NetLog::TYPE_DISK_CACHE_ENTRY_IMPL,
- CreateNetLogEntryCreationCallback(this, created));
+ net_log_ = net::NetLogWithSource::Make(
+ net_log, net::NetLogSourceType::DISK_CACHE_ENTRY);
+ net_log_.BeginEvent(net::NetLogEventType::DISK_CACHE_ENTRY_IMPL,
+ CreateNetLogEntryCreationCallback(this, created));
}
-const net::BoundNetLog& EntryImpl::net_log() const {
+const net::NetLogWithSource& EntryImpl::net_log() const {
return net_log_;
}
@@ -951,7 +955,7 @@ EntryImpl::~EntryImpl() {
#if defined(NET_BUILD_STRESS_CACHE)
SanityCheck();
#endif
- net_log_.AddEvent(net::NetLog::TYPE_ENTRY_CLOSE);
+ net_log_.AddEvent(net::NetLogEventType::ENTRY_CLOSE);
bool ret = true;
for (int index = 0; index < kNumStreams; index++) {
if (user_buffers_[index].get()) {
@@ -978,7 +982,7 @@ EntryImpl::~EntryImpl() {
}
Trace("~EntryImpl out 0x%p", reinterpret_cast<void*>(this));
- net_log_.EndEvent(net::NetLog::TYPE_DISK_CACHE_ENTRY_IMPL);
+ net_log_.EndEvent(net::NetLogEventType::DISK_CACHE_ENTRY_IMPL);
backend_->OnEntryDestroyEnd();
}
@@ -1046,7 +1050,7 @@ int EntryImpl::InternalReadData(int index, int offset,
SyncCallback* io_callback = NULL;
if (!callback.is_null()) {
io_callback = new SyncCallback(this, buf, callback,
- net::NetLog::TYPE_ENTRY_READ_DATA);
+ net::NetLogEventType::ENTRY_READ_DATA);
}
TimeTicks start_async = TimeTicks::Now();
@@ -1150,7 +1154,7 @@ int EntryImpl::InternalWriteData(int index, int offset,
SyncCallback* io_callback = NULL;
if (!callback.is_null()) {
io_callback = new SyncCallback(this, buf, callback,
- net::NetLog::TYPE_ENTRY_WRITE_DATA);
+ net::NetLogEventType::ENTRY_WRITE_DATA);
}
TimeTicks start_async = TimeTicks::Now();
diff --git a/chromium/net/disk_cache/blockfile/entry_impl.h b/chromium/net/disk_cache/blockfile/entry_impl.h
index 55f68e7c7c2..f3f63cf5d76 100644
--- a/chromium/net/disk_cache/blockfile/entry_impl.h
+++ b/chromium/net/disk_cache/blockfile/entry_impl.h
@@ -8,13 +8,19 @@
#include <stdint.h>
#include <memory>
+#include <string>
#include "base/macros.h"
+#include "net/base/net_export.h"
#include "net/disk_cache/blockfile/disk_format.h"
#include "net/disk_cache/blockfile/storage_block-inl.h"
#include "net/disk_cache/blockfile/storage_block.h"
#include "net/disk_cache/disk_cache.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
+
+namespace net {
+class NetLog;
+}
namespace disk_cache {
@@ -149,7 +155,7 @@ class NET_EXPORT_PRIVATE EntryImpl
// created rather than opened.
void BeginLogging(net::NetLog* net_log, bool created);
- const net::BoundNetLog& net_log() const;
+ const net::NetLogWithSource& net_log() const;
// Returns the number of blocks needed to store an EntryStore.
static int NumBlocksForEntry(int key_size);
@@ -288,7 +294,7 @@ class NET_EXPORT_PRIVATE EntryImpl
bool dirty_; // True if we detected that this is a dirty entry.
std::unique_ptr<SparseControl> sparse_; // Support for sparse entries.
- net::BoundNetLog net_log_;
+ net::NetLogWithSource net_log_;
DISALLOW_COPY_AND_ASSIGN(EntryImpl);
};
diff --git a/chromium/net/disk_cache/blockfile/eviction.cc b/chromium/net/disk_cache/blockfile/eviction.cc
index 860b8b11006..52fca5fb7d0 100644
--- a/chromium/net/disk_cache/blockfile/eviction.cc
+++ b/chromium/net/disk_cache/blockfile/eviction.cc
@@ -36,6 +36,7 @@
#include "base/compiler_specific.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/net/disk_cache/blockfile/file_posix.cc b/chromium/net/disk_cache/blockfile/file_posix.cc
index 5a3ad455478..cdde5b0d45e 100644
--- a/chromium/net/disk_cache/blockfile/file_posix.cc
+++ b/chromium/net/disk_cache/blockfile/file_posix.cc
@@ -25,7 +25,10 @@ const int kMaxThreads = 5;
class FileWorkerPool : public base::SequencedWorkerPool {
public:
- FileWorkerPool() : base::SequencedWorkerPool(kMaxThreads, "CachePool") {}
+ FileWorkerPool()
+ : base::SequencedWorkerPool(kMaxThreads,
+ "CachePool",
+ base::TaskPriority::USER_BLOCKING) {}
protected:
~FileWorkerPool() override {}
diff --git a/chromium/net/disk_cache/blockfile/rankings.cc b/chromium/net/disk_cache/blockfile/rankings.cc
index c5593508ab4..c0d023c7bc1 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 "net/base/net_export.h"
#include "net/disk_cache/blockfile/backend_impl.h"
#include "net/disk_cache/blockfile/disk_format.h"
#include "net/disk_cache/blockfile/entry_impl.h"
diff --git a/chromium/net/disk_cache/blockfile/sparse_control.cc b/chromium/net/disk_cache/blockfile/sparse_control.cc
index 62c2996cf26..a293f29df01 100644
--- a/chromium/net/disk_cache/blockfile/sparse_control.cc
+++ b/chromium/net/disk_cache/blockfile/sparse_control.cc
@@ -22,6 +22,9 @@
#include "net/disk_cache/blockfile/entry_impl.h"
#include "net/disk_cache/blockfile/file.h"
#include "net/disk_cache/net_log_parameters.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
using base::Time;
@@ -147,34 +150,34 @@ void ChildrenDeleter::DeleteChildren() {
}
// Returns the NetLog event type corresponding to a SparseOperation.
-net::NetLog::EventType GetSparseEventType(
+net::NetLogEventType GetSparseEventType(
disk_cache::SparseControl::SparseOperation operation) {
switch (operation) {
case disk_cache::SparseControl::kReadOperation:
- return net::NetLog::TYPE_SPARSE_READ;
+ return net::NetLogEventType::SPARSE_READ;
case disk_cache::SparseControl::kWriteOperation:
- return net::NetLog::TYPE_SPARSE_WRITE;
+ return net::NetLogEventType::SPARSE_WRITE;
case disk_cache::SparseControl::kGetRangeOperation:
- return net::NetLog::TYPE_SPARSE_GET_RANGE;
+ return net::NetLogEventType::SPARSE_GET_RANGE;
default:
NOTREACHED();
- return net::NetLog::TYPE_CANCELLED;
+ return net::NetLogEventType::CANCELLED;
}
}
// Logs the end event for |operation| on a child entry. Range operations log
// no events for each child they search through.
-void LogChildOperationEnd(const net::BoundNetLog& net_log,
+void LogChildOperationEnd(const net::NetLogWithSource& net_log,
disk_cache::SparseControl::SparseOperation operation,
int result) {
if (net_log.IsCapturing()) {
- net::NetLog::EventType event_type;
+ net::NetLogEventType event_type;
switch (operation) {
case disk_cache::SparseControl::kReadOperation:
- event_type = net::NetLog::TYPE_SPARSE_READ_CHILD_DATA;
+ event_type = net::NetLogEventType::SPARSE_READ_CHILD_DATA;
break;
case disk_cache::SparseControl::kWriteOperation:
- event_type = net::NetLog::TYPE_SPARSE_WRITE_CHILD_DATA;
+ event_type = net::NetLogEventType::SPARSE_WRITE_CHILD_DATA;
break;
case disk_cache::SparseControl::kGetRangeOperation:
return;
@@ -359,7 +362,7 @@ void SparseControl::DeleteChildren(EntryImpl* entry) {
if (!buffer && !address.is_initialized())
return;
- entry->net_log().AddEvent(net::NetLog::TYPE_SPARSE_DELETE_CHILDREN);
+ entry->net_log().AddEvent(net::NetLogEventType::SPARSE_DELETE_CHILDREN);
DCHECK(entry->backend_.get());
ChildrenDeleter* deleter = new ChildrenDeleter(entry->backend_.get(),
@@ -689,7 +692,7 @@ void SparseControl::DoChildrenIO() {
// |finished_| to true.
if (kGetRangeOperation == operation_ && entry_->net_log().IsCapturing()) {
entry_->net_log().EndEvent(
- net::NetLog::TYPE_SPARSE_GET_RANGE,
+ net::NetLogEventType::SPARSE_GET_RANGE,
CreateNetLogGetAvailableRangeResultCallback(offset_, result_));
}
if (finished_) {
@@ -725,7 +728,7 @@ bool SparseControl::DoChildIO() {
case kReadOperation:
if (entry_->net_log().IsCapturing()) {
entry_->net_log().BeginEvent(
- net::NetLog::TYPE_SPARSE_READ_CHILD_DATA,
+ net::NetLogEventType::SPARSE_READ_CHILD_DATA,
CreateNetLogSparseReadWriteCallback(child_->net_log().source(),
child_len_));
}
@@ -735,7 +738,7 @@ bool SparseControl::DoChildIO() {
case kWriteOperation:
if (entry_->net_log().IsCapturing()) {
entry_->net_log().BeginEvent(
- net::NetLog::TYPE_SPARSE_WRITE_CHILD_DATA,
+ net::NetLogEventType::SPARSE_WRITE_CHILD_DATA,
CreateNetLogSparseReadWriteCallback(child_->net_log().source(),
child_len_));
}
@@ -864,7 +867,7 @@ void SparseControl::OnChildIOCompleted(int result) {
// the bytes to read or write, but the user cancelled the operation.
abort_ = false;
if (entry_->net_log().IsCapturing()) {
- entry_->net_log().AddEvent(net::NetLog::TYPE_CANCELLED);
+ entry_->net_log().AddEvent(net::NetLogEventType::CANCELLED);
entry_->net_log().EndEvent(GetSparseEventType(operation_));
}
// We have an indirect reference to this object for every callback so if
diff --git a/chromium/net/disk_cache/cache_util_unittest.cc b/chromium/net/disk_cache/cache_util_unittest.cc
index 073c152e79c..3eaae84ddd8 100644
--- a/chromium/net/disk_cache/cache_util_unittest.cc
+++ b/chromium/net/disk_cache/cache_util_unittest.cc
@@ -15,7 +15,7 @@ class CacheUtilTest : public PlatformTest {
void SetUp() override {
PlatformTest::SetUp();
ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir());
- cache_dir_ = tmp_dir_.path().Append(FILE_PATH_LITERAL("Cache"));
+ cache_dir_ = tmp_dir_.GetPath().Append(FILE_PATH_LITERAL("Cache"));
file1_ = base::FilePath(cache_dir_.Append(FILE_PATH_LITERAL("file01")));
file2_ = base::FilePath(cache_dir_.Append(FILE_PATH_LITERAL(".file02")));
dir1_ = base::FilePath(cache_dir_.Append(FILE_PATH_LITERAL("dir01")));
@@ -31,7 +31,7 @@ class CacheUtilTest : public PlatformTest {
fp = base::OpenFile(file3_, "w");
ASSERT_TRUE(fp != NULL);
base::CloseFile(fp);
- dest_dir_ = tmp_dir_.path().Append(FILE_PATH_LITERAL("old_Cache_001"));
+ dest_dir_ = tmp_dir_.GetPath().Append(FILE_PATH_LITERAL("old_Cache_001"));
dest_file1_ = base::FilePath(dest_dir_.Append(FILE_PATH_LITERAL("file01")));
dest_file2_ =
base::FilePath(dest_dir_.Append(FILE_PATH_LITERAL(".file02")));
diff --git a/chromium/net/disk_cache/disk_cache_test_base.cc b/chromium/net/disk_cache/disk_cache_test_base.cc
index 7480cf45848..84ba9c676f2 100644
--- a/chromium/net/disk_cache/disk_cache_test_base.cc
+++ b/chromium/net/disk_cache/disk_cache_test_base.cc
@@ -22,10 +22,15 @@
#include "net/disk_cache/memory/mem_backend_impl.h"
#include "net/disk_cache/simple/simple_backend_impl.h"
#include "net/disk_cache/simple/simple_index.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using net::test::IsOk;
DiskCacheTest::DiskCacheTest() {
CHECK(temp_dir_.CreateUniqueTempDir());
- cache_path_ = temp_dir_.path();
+ cache_path_ = temp_dir_.GetPath();
if (!base::MessageLoop::current())
message_loop_.reset(new base::MessageLoopForIO());
}
@@ -103,7 +108,7 @@ void DiskCacheTestWithCache::SimulateCrash() {
ASSERT_TRUE(!memory_only_);
net::TestCompletionCallback cb;
int rv = cache_impl_->FlushQueueForTest(cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
cache_impl_->ClearRefCountForTest();
cache_.reset();
@@ -186,7 +191,7 @@ void DiskCacheTestWithCache::FlushQueueForTest() {
net::TestCompletionCallback cb;
int rv = cache_impl_->FlushQueueForTest(cb.callback());
- EXPECT_EQ(net::OK, cb.GetResult(rv));
+ EXPECT_THAT(cb.GetResult(rv), IsOk());
}
void DiskCacheTestWithCache::RunTaskForTest(const base::Closure& closure) {
@@ -197,7 +202,7 @@ void DiskCacheTestWithCache::RunTaskForTest(const base::Closure& closure) {
net::TestCompletionCallback cb;
int rv = cache_impl_->RunTaskForTest(closure, cb.callback());
- EXPECT_EQ(net::OK, cb.GetResult(rv));
+ EXPECT_THAT(cb.GetResult(rv), IsOk());
}
int DiskCacheTestWithCache::ReadData(disk_cache::Entry* entry, int index,
@@ -317,14 +322,14 @@ void DiskCacheTestWithCache::CreateBackend(uint32_t flags,
new disk_cache::SimpleBackendImpl(cache_path_, size_, type_, runner,
NULL));
int rv = simple_backend->Init(cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
simple_cache_impl_ = simple_backend.get();
cache_ = std::move(simple_backend);
if (simple_cache_wait_for_index_) {
net::TestCompletionCallback wait_for_index_cb;
rv = simple_cache_impl_->index()->ExecuteWhenReady(
wait_for_index_cb.callback());
- ASSERT_EQ(net::OK, wait_for_index_cb.GetResult(rv));
+ ASSERT_THAT(wait_for_index_cb.GetResult(rv), IsOk());
}
return;
}
@@ -343,5 +348,5 @@ void DiskCacheTestWithCache::CreateBackend(uint32_t flags,
cache_impl_->SetFlags(flags);
net::TestCompletionCallback cb;
int rv = cache_impl_->Init(cb.callback());
- ASSERT_EQ(net::OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
}
diff --git a/chromium/net/disk_cache/entry_unittest.cc b/chromium/net/disk_cache/entry_unittest.cc
index 758e777a739..fca62e354c1 100644
--- a/chromium/net/disk_cache/entry_unittest.cc
+++ b/chromium/net/disk_cache/entry_unittest.cc
@@ -28,8 +28,13 @@
#include "net/disk_cache/simple/simple_synchronous_entry.h"
#include "net/disk_cache/simple/simple_test_util.h"
#include "net/disk_cache/simple/simple_util.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
using base::Time;
using disk_cache::ScopedEntryPtr;
@@ -141,7 +146,7 @@ void DiskCacheEntryTest::InternalSyncIOBackground(disk_cache::Entry* entry) {
// (see sparse_control.cc, for example).
void DiskCacheEntryTest::InternalSyncIO() {
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
+ ASSERT_THAT(CreateEntry("the first key", &entry), IsOk());
ASSERT_TRUE(NULL != entry);
// The bulk of the test runs from within the callback, on the cache thread.
@@ -169,7 +174,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyInternalSyncIO) {
void DiskCacheEntryTest::InternalAsyncIO() {
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
+ ASSERT_THAT(CreateEntry("the first key", &entry), IsOk());
ASSERT_TRUE(NULL != entry);
// Avoid using internal buffers for the test. We have to write something to
@@ -180,7 +185,7 @@ void DiskCacheEntryTest::InternalAsyncIO() {
EXPECT_EQ(0, WriteData(entry, 0, 15 * 1024, NULL, 0, false));
EXPECT_EQ(0, WriteData(entry, 1, 15 * 1024, NULL, 0, false));
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry("the first key", &entry));
+ ASSERT_THAT(OpenEntry("the first key", &entry), IsOk());
MessageLoopHelper helper;
// Let's verify that each IO goes to the right callback object.
@@ -424,7 +429,7 @@ void DiskCacheEntryTest::ExternalSyncIOBackground(disk_cache::Entry* entry) {
void DiskCacheEntryTest::ExternalSyncIO() {
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
+ ASSERT_THAT(CreateEntry("the first key", &entry), IsOk());
// The bulk of the test runs from within the callback, on the cache thread.
RunTaskForTest(base::Bind(&DiskCacheEntryTest::ExternalSyncIOBackground,
@@ -456,7 +461,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyExternalSyncIO) {
void DiskCacheEntryTest::ExternalAsyncIO() {
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
+ ASSERT_THAT(CreateEntry("the first key", &entry), IsOk());
int expected = 0;
@@ -623,7 +628,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyExternalAsyncIO) {
// Tests that IOBuffers are not referenced after IO completes.
void DiskCacheEntryTest::ReleaseBuffer(int stream_index) {
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
+ ASSERT_THAT(CreateEntry("the first key", &entry), IsOk());
ASSERT_TRUE(NULL != entry);
const int kBufferSize = 1024;
@@ -651,7 +656,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyReleaseBuffer) {
void DiskCacheEntryTest::StreamAccess() {
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, CreateEntry("the first key", &entry));
+ ASSERT_THAT(CreateEntry("the first key", &entry), IsOk());
ASSERT_TRUE(NULL != entry);
const int kBufferSize = 1024;
@@ -676,7 +681,7 @@ void DiskCacheEntryTest::StreamAccess() {
entry->Close();
// Open the entry and read it in chunks, including a read past the end.
- ASSERT_EQ(net::OK, OpenEntry("the first key", &entry));
+ ASSERT_THAT(OpenEntry("the first key", &entry), IsOk());
ASSERT_TRUE(NULL != entry);
const int kReadBufferSize = 600;
const int kFinalReadSize = kBufferSize - kReadBufferSize;
@@ -718,7 +723,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyStreamAccess) {
void DiskCacheEntryTest::GetKey() {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_EQ(key, entry->GetKey()) << "short key";
entry->Close();
@@ -730,14 +735,14 @@ void DiskCacheEntryTest::GetKey() {
key_buffer[1000] = '\0';
key = key_buffer;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_TRUE(key == entry->GetKey()) << "1000 bytes key";
entry->Close();
key_buffer[1000] = 'p';
key_buffer[3000] = '\0';
key = key_buffer;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_TRUE(key == entry->GetKey()) << "medium size key";
entry->Close();
@@ -745,7 +750,7 @@ void DiskCacheEntryTest::GetKey() {
key_buffer[19999] = '\0';
key = key_buffer;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_TRUE(key == entry->GetKey()) << "long key";
entry->Close();
@@ -753,7 +758,7 @@ void DiskCacheEntryTest::GetKey() {
key_buffer[0x4000] = '\0';
key = key_buffer;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_TRUE(key == entry->GetKey()) << "16KB key";
entry->Close();
}
@@ -774,7 +779,7 @@ void DiskCacheEntryTest::GetTimes(int stream_index) {
disk_cache::Entry* entry;
Time t1 = Time::Now();
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_TRUE(entry->GetLastModified() >= t1);
EXPECT_TRUE(entry->GetLastModified() == entry->GetLastUsed());
@@ -834,7 +839,7 @@ TEST_F(DiskCacheEntryTest, ShaderCacheGetTimes) {
void DiskCacheEntryTest::GrowData(int stream_index) {
std::string key1("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry));
+ ASSERT_THAT(CreateEntry(key1, &entry), IsOk());
const int kSize = 20000;
scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize));
@@ -863,13 +868,13 @@ void DiskCacheEntryTest::GrowData(int stream_index) {
memset(buffer2->data(), 0, kSize);
std::string key2("Second key");
- ASSERT_EQ(net::OK, CreateEntry(key2, &entry));
+ ASSERT_THAT(CreateEntry(key2, &entry), IsOk());
EXPECT_EQ(10, WriteData(entry, stream_index, 0, buffer1.get(), 10, false));
EXPECT_EQ(10, entry->GetDataSize(stream_index));
entry->Close();
// Go from an internal address to a bigger block size.
- ASSERT_EQ(net::OK, OpenEntry(key2, &entry));
+ ASSERT_THAT(OpenEntry(key2, &entry), IsOk());
EXPECT_EQ(2000,
WriteData(entry, stream_index, 0, buffer1.get(), 2000, false));
EXPECT_EQ(2000, entry->GetDataSize(stream_index));
@@ -879,7 +884,7 @@ void DiskCacheEntryTest::GrowData(int stream_index) {
memset(buffer2->data(), 0, kSize);
// Go from an internal address to an external one.
- ASSERT_EQ(net::OK, OpenEntry(key2, &entry));
+ ASSERT_THAT(OpenEntry(key2, &entry), IsOk());
EXPECT_EQ(20000,
WriteData(entry, stream_index, 0, buffer1.get(), kSize, false));
EXPECT_EQ(20000, entry->GetDataSize(stream_index));
@@ -888,7 +893,7 @@ void DiskCacheEntryTest::GrowData(int stream_index) {
entry->Close();
// Double check the size from disk.
- ASSERT_EQ(net::OK, OpenEntry(key2, &entry));
+ ASSERT_THAT(OpenEntry(key2, &entry), IsOk());
EXPECT_EQ(20000, entry->GetDataSize(stream_index));
// Now extend the entry without actual data.
@@ -896,7 +901,7 @@ void DiskCacheEntryTest::GrowData(int stream_index) {
entry->Close();
// And check again from disk.
- ASSERT_EQ(net::OK, OpenEntry(key2, &entry));
+ ASSERT_THAT(OpenEntry(key2, &entry), IsOk());
EXPECT_EQ(45500, entry->GetDataSize(stream_index));
entry->Close();
}
@@ -921,7 +926,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyGrowData) {
void DiskCacheEntryTest::TruncateData(int stream_index) {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize1 = 20000;
const int kSize2 = 20000;
@@ -943,7 +948,7 @@ void DiskCacheEntryTest::TruncateData(int stream_index) {
EXPECT_EQ(0, WriteData(entry, stream_index, 0, buffer1.get(), 0, true));
EXPECT_EQ(0, entry->GetDataSize(stream_index));
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
// Go to an external file.
EXPECT_EQ(20000,
@@ -1003,7 +1008,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyTruncateData) {
void DiskCacheEntryTest::ZeroLengthIO(int stream_index) {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_EQ(0, ReadData(entry, stream_index, 0, NULL, 0));
EXPECT_EQ(0, WriteData(entry, stream_index, 0, NULL, 0, false));
@@ -1060,7 +1065,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyZeroLengthIO) {
void DiskCacheEntryTest::Buffering() {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize = 200;
scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize));
@@ -1072,7 +1077,7 @@ void DiskCacheEntryTest::Buffering() {
entry->Close();
// Write a little more and read what we wrote before.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
EXPECT_EQ(kSize, WriteData(entry, 1, 5000, buffer1.get(), kSize, false));
EXPECT_EQ(kSize, ReadData(entry, 1, 0, buffer2.get(), kSize));
EXPECT_TRUE(!memcmp(buffer2->data(), buffer1->data(), kSize));
@@ -1082,7 +1087,7 @@ void DiskCacheEntryTest::Buffering() {
entry->Close();
// Write something else and verify old data.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
EXPECT_EQ(kSize, WriteData(entry, 1, 10000, buffer1.get(), kSize, false));
CacheTestFillBuffer(buffer2->data(), kSize, true);
EXPECT_EQ(kSize, ReadData(entry, 1, 5000, buffer2.get(), kSize));
@@ -1099,7 +1104,7 @@ void DiskCacheEntryTest::Buffering() {
entry->Close();
// And now make sure that we can deal with data in both places (ram/disk).
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
EXPECT_EQ(kSize, WriteData(entry, 1, 17000, buffer1.get(), kSize, false));
// We should not overwrite the data at 18000 with this.
@@ -1148,7 +1153,7 @@ TEST_F(DiskCacheEntryTest, BufferingNoBuffer) {
void DiskCacheEntryTest::SizeAtCreate() {
const char key[] = "the first key";
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kNumStreams = 3;
for (int i = 0; i < kNumStreams; ++i)
@@ -1172,7 +1177,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlySizeAtCreate) {
void DiskCacheEntryTest::SizeChanges(int stream_index) {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize = 200;
const char zeros[kSize] = {};
@@ -1190,7 +1195,7 @@ void DiskCacheEntryTest::SizeChanges(int stream_index) {
entry->Close();
// Extend the file and read between the old size and the new write.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
EXPECT_EQ(23000 + kSize, entry->GetDataSize(stream_index));
EXPECT_EQ(kSize,
WriteData(entry, stream_index, 25000, buffer1.get(), kSize, true));
@@ -1249,7 +1254,7 @@ void DiskCacheEntryTest::SizeChanges(int stream_index) {
// Verify that the actual file is truncated.
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
EXPECT_EQ(19000 + kSize, entry->GetDataSize(stream_index));
// Extend the newly opened file with a zero length write, expect zero fill.
@@ -1279,11 +1284,11 @@ TEST_F(DiskCacheEntryTest, SizeChangesNoBuffer) {
void DiskCacheEntryTest::ReuseEntry(int size, int stream_index) {
std::string key1("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry));
+ ASSERT_THAT(CreateEntry(key1, &entry), IsOk());
entry->Close();
std::string key2("the second key");
- ASSERT_EQ(net::OK, CreateEntry(key2, &entry));
+ ASSERT_THAT(CreateEntry(key2, &entry), IsOk());
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(size));
CacheTestFillBuffer(buffer->data(), size, false);
@@ -1293,7 +1298,7 @@ void DiskCacheEntryTest::ReuseEntry(int size, int stream_index) {
EXPECT_EQ(size,
WriteData(entry, stream_index, 0, buffer.get(), size, false));
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(key2, &entry));
+ ASSERT_THAT(OpenEntry(key2, &entry), IsOk());
}
entry->Close();
@@ -1331,7 +1336,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyReuseInternalEntry) {
void DiskCacheEntryTest::InvalidData(int stream_index) {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize1 = 20000;
const int kSize2 = 20000;
@@ -1350,7 +1355,7 @@ void DiskCacheEntryTest::InvalidData(int stream_index) {
EXPECT_EQ(100, ReadData(entry, stream_index, 300, buffer3.get(), 100));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer2->data(), 100));
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
// The entry is now on disk. Load it and extend it.
EXPECT_EQ(200,
@@ -1359,7 +1364,7 @@ void DiskCacheEntryTest::InvalidData(int stream_index) {
EXPECT_EQ(100, ReadData(entry, stream_index, 700, buffer3.get(), 100));
EXPECT_TRUE(!memcmp(buffer3->data(), buffer2->data(), 100));
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
// This time using truncate.
EXPECT_EQ(200,
@@ -1420,7 +1425,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyInvalidData) {
void DiskCacheEntryTest::ReadWriteDestroyBuffer(int stream_index) {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize = 200;
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize));
@@ -1456,7 +1461,7 @@ TEST_F(DiskCacheEntryTest, ReadWriteDestroyBuffer) {
void DiskCacheEntryTest::DoomNormalEntry() {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
entry->Doom();
entry->Close();
@@ -1466,7 +1471,7 @@ void DiskCacheEntryTest::DoomNormalEntry() {
buffer->data()[19999] = '\0';
key = buffer->data();
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_EQ(20000, WriteData(entry, 0, 0, buffer.get(), kSize, false));
EXPECT_EQ(20000, WriteData(entry, 1, 0, buffer.get(), kSize, false));
entry->Doom();
@@ -1491,24 +1496,24 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyDoomEntry) {
void DiskCacheEntryTest::DoomEntryNextToOpenEntry() {
disk_cache::Entry* entry1;
disk_cache::Entry* entry2;
- ASSERT_EQ(net::OK, CreateEntry("fixed", &entry1));
+ ASSERT_THAT(CreateEntry("fixed", &entry1), IsOk());
entry1->Close();
- ASSERT_EQ(net::OK, CreateEntry("foo", &entry1));
+ ASSERT_THAT(CreateEntry("foo", &entry1), IsOk());
entry1->Close();
- ASSERT_EQ(net::OK, CreateEntry("bar", &entry1));
+ ASSERT_THAT(CreateEntry("bar", &entry1), IsOk());
entry1->Close();
- ASSERT_EQ(net::OK, OpenEntry("foo", &entry1));
- ASSERT_EQ(net::OK, OpenEntry("bar", &entry2));
+ ASSERT_THAT(OpenEntry("foo", &entry1), IsOk());
+ ASSERT_THAT(OpenEntry("bar", &entry2), IsOk());
entry2->Doom();
entry2->Close();
- ASSERT_EQ(net::OK, OpenEntry("foo", &entry2));
+ ASSERT_THAT(OpenEntry("foo", &entry2), IsOk());
entry2->Doom();
entry2->Close();
entry1->Close();
- ASSERT_EQ(net::OK, OpenEntry("fixed", &entry1));
+ ASSERT_THAT(OpenEntry("fixed", &entry1), IsOk());
entry1->Close();
}
@@ -1533,7 +1538,7 @@ TEST_F(DiskCacheEntryTest, AppCacheDoomEntryNextToOpenEntry) {
void DiskCacheEntryTest::DoomedEntry(int stream_index) {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
entry->Doom();
FlushQueueForTest();
@@ -1576,7 +1581,7 @@ TEST_F(DiskCacheEntryTest, MissingData) {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
// Write to an external file.
const int kSize = 20000;
@@ -1591,7 +1596,7 @@ TEST_F(DiskCacheEntryTest, MissingData) {
EXPECT_TRUE(base::DeleteFile(name, false));
// Attempt to read the data.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
EXPECT_EQ(net::ERR_FILE_NOT_FOUND,
ReadData(entry, 0, 0, buffer.get(), kSize));
entry->Close();
@@ -1612,7 +1617,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyEnumerationWithSparseEntries) {
std::string key("the first key");
disk_cache::Entry* parent_entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &parent_entry));
+ ASSERT_THAT(CreateEntry(key, &parent_entry), IsOk());
// Writes to the parent entry.
EXPECT_EQ(kSize,
@@ -1680,7 +1685,7 @@ void VerifyContentSparseIO(disk_cache::Entry* entry,
void DiskCacheEntryTest::BasicSparseIO() {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize = 2048;
scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(kSize));
@@ -1699,7 +1704,7 @@ void DiskCacheEntryTest::BasicSparseIO() {
entry->Close();
// Check everything again.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
VerifyContentSparseIO(entry, 0, buf_1->data(), kSize);
VerifyContentSparseIO(entry, 0x400000, buf_1->data(), kSize);
VerifyContentSparseIO(entry, 0x800000000LL, buf_1->data(), kSize);
@@ -1720,7 +1725,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyBasicSparseIO) {
void DiskCacheEntryTest::HugeSparseIO() {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
// Write 1.2 MB so that we cover multiple entries.
const int kSize = 1200 * 1024;
@@ -1733,7 +1738,7 @@ void DiskCacheEntryTest::HugeSparseIO() {
entry->Close();
// Check it again.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
VerifyContentSparseIO(entry, 0x20F0000, buf_1->data(), kSize);
entry->Close();
}
@@ -1752,7 +1757,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyHugeSparseIO) {
void DiskCacheEntryTest::GetAvailableRange() {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize = 16 * 1024;
scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize));
@@ -1829,7 +1834,7 @@ TEST_F(DiskCacheEntryTest, SparseWriteDropped) {
InitCache();
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize = 180;
scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(kSize));
@@ -1886,7 +1891,7 @@ TEST_F(DiskCacheEntryTest, SparseSquentialWriteNotDropped) {
InitCache();
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize = 180;
scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(kSize));
@@ -1915,7 +1920,7 @@ TEST_F(DiskCacheEntryTest, SparseSquentialWriteNotDropped) {
FlushQueueForTest();
// Verify again the last write made.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
offset -= kSize;
rv = entry->GetAvailableRange(offset, kSize, &start, cb.callback());
EXPECT_EQ(kSize, cb.GetResult(rv));
@@ -1931,7 +1936,7 @@ TEST_F(DiskCacheEntryTest, SparseSquentialWriteNotDropped) {
void DiskCacheEntryTest::CouldBeSparse() {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize = 16 * 1024;
scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize));
@@ -1943,13 +1948,13 @@ void DiskCacheEntryTest::CouldBeSparse() {
EXPECT_TRUE(entry->CouldBeSparse());
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
EXPECT_TRUE(entry->CouldBeSparse());
entry->Close();
// Now verify a regular entry.
key.assign("another key");
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_FALSE(entry->CouldBeSparse());
EXPECT_EQ(kSize, WriteData(entry, 0, 0, buf.get(), kSize, false));
@@ -1959,7 +1964,7 @@ void DiskCacheEntryTest::CouldBeSparse() {
EXPECT_FALSE(entry->CouldBeSparse());
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
EXPECT_FALSE(entry->CouldBeSparse());
entry->Close();
}
@@ -1986,7 +1991,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyMisalignedSparseIO) {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
// This loop writes back to back starting from offset 0 and 9000.
for (int i = 0; i < kSize; i += 1024) {
@@ -2016,7 +2021,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyMisalignedGetAvailableRange) {
disk_cache::Entry* entry;
std::string key("the first key");
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
// Writes in the middle of an entry.
EXPECT_EQ(
@@ -2075,7 +2080,7 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyMisalignedGetAvailableRange) {
void DiskCacheEntryTest::UpdateSparseEntry() {
std::string key("the first key");
disk_cache::Entry* entry1;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry1));
+ ASSERT_THAT(CreateEntry(key, &entry1), IsOk());
const int kSize = 2048;
scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(kSize));
@@ -2087,11 +2092,11 @@ void DiskCacheEntryTest::UpdateSparseEntry() {
entry1->Close();
// Write at offset 2048.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry1));
+ ASSERT_THAT(OpenEntry(key, &entry1), IsOk());
VerifySparseIO(entry1, 2048, buf_1.get(), kSize, buf_2.get());
disk_cache::Entry* entry2;
- ASSERT_EQ(net::OK, CreateEntry("the second key", &entry2));
+ ASSERT_THAT(CreateEntry("the second key", &entry2), IsOk());
entry1->Close();
entry2->Close();
@@ -2119,8 +2124,8 @@ void DiskCacheEntryTest::DoomSparseEntry() {
std::string key1("the first key");
std::string key2("the second key");
disk_cache::Entry *entry1, *entry2;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry1));
- ASSERT_EQ(net::OK, CreateEntry(key2, &entry2));
+ ASSERT_THAT(CreateEntry(key1, &entry1), IsOk());
+ ASSERT_THAT(CreateEntry(key2, &entry2), IsOk());
const int kSize = 4 * 1024;
scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize));
@@ -2148,7 +2153,7 @@ void DiskCacheEntryTest::DoomSparseEntry() {
entry2->Close();
// Doom the second entry after it's fully saved.
- EXPECT_EQ(net::OK, DoomEntry(key2));
+ EXPECT_THAT(DoomEntry(key2), IsOk());
// Make sure we do all needed work. This may fail for entry2 if between Close
// and DoomEntry the system decides to remove all traces of the file from the
@@ -2208,7 +2213,7 @@ TEST_F(DiskCacheEntryTest, DoomSparseEntry2) {
InitCache();
std::string key("the key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize = 4 * 1024;
scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize));
@@ -2228,14 +2233,14 @@ TEST_F(DiskCacheEntryTest, DoomSparseEntry2) {
disk_cache::Backend* cache = cache_.get();
SparseTestCompletionCallback cb(std::move(cache_));
int rv = cache->DoomEntry(key, cb.callback());
- EXPECT_EQ(net::ERR_IO_PENDING, rv);
- EXPECT_EQ(net::OK, cb.WaitForResult());
+ EXPECT_THAT(rv, IsError(net::ERR_IO_PENDING));
+ EXPECT_THAT(cb.WaitForResult(), IsOk());
}
void DiskCacheEntryTest::PartialSparseEntry() {
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
// We should be able to deal with IO that is not aligned to the block size
// of a sparse entry, at least to write a big range without leaving holes.
@@ -2252,7 +2257,7 @@ void DiskCacheEntryTest::PartialSparseEntry() {
EXPECT_EQ(kSmallSize,
WriteSparseData(entry, 1080321, buf1.get(), kSmallSize));
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
scoped_refptr<net::IOBuffer> buf2(new net::IOBuffer(kSize));
memset(buf2->data(), 0, kSize);
@@ -2341,7 +2346,7 @@ TEST_F(DiskCacheEntryTest, CleanupSparseEntry) {
InitCache();
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize = 4 * 1024;
scoped_refptr<net::IOBuffer> buf1(new net::IOBuffer(kSize));
@@ -2365,14 +2370,14 @@ TEST_F(DiskCacheEntryTest, CleanupSparseEntry) {
entry->Close();
}
for (int i = 0; i < 2; i++) {
- ASSERT_EQ(net::OK, OpenEntry(child_key[i], &entry));
+ ASSERT_THAT(OpenEntry(child_key[i], &entry), IsOk());
// Overwrite the header's magic and signature.
EXPECT_EQ(12, WriteData(entry, 2, 0, buf1.get(), 12, false));
entry->Close();
}
EXPECT_EQ(4, cache_->GetEntryCount());
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
// Two children should be gone. One while reading and one while writing.
EXPECT_EQ(0, ReadSparseData(entry, 2 * k1Meg + 8192, buf1.get(), kSize));
@@ -2392,7 +2397,7 @@ TEST_F(DiskCacheEntryTest, CancelSparseIO) {
InitCache();
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const int kSize = 40 * 1024;
scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize));
@@ -2402,7 +2407,7 @@ TEST_F(DiskCacheEntryTest, CancelSparseIO) {
net::TestCompletionCallback cb1, cb2, cb3, cb4, cb5;
int rv = entry->WriteSparseData(
1024 * 1024 - 4096, buf.get(), kSize, cb1.callback());
- EXPECT_EQ(net::ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(net::ERR_IO_PENDING));
int64_t offset = 0;
rv = entry->GetAvailableRange(offset, kSize, &offset, cb5.callback());
@@ -2410,15 +2415,18 @@ TEST_F(DiskCacheEntryTest, CancelSparseIO) {
if (!cb1.have_result()) {
// We may or may not have finished writing to the entry. If we have not,
// we cannot start another operation at this time.
- EXPECT_EQ(net::ERR_CACHE_OPERATION_NOT_SUPPORTED, rv);
+ EXPECT_THAT(rv, IsError(net::ERR_CACHE_OPERATION_NOT_SUPPORTED));
}
// We cancel the pending operation, and register multiple notifications.
entry->CancelSparseIO();
- EXPECT_EQ(net::ERR_IO_PENDING, entry->ReadyForSparseIO(cb2.callback()));
- EXPECT_EQ(net::ERR_IO_PENDING, entry->ReadyForSparseIO(cb3.callback()));
+ EXPECT_THAT(entry->ReadyForSparseIO(cb2.callback()),
+ IsError(net::ERR_IO_PENDING));
+ EXPECT_THAT(entry->ReadyForSparseIO(cb3.callback()),
+ IsError(net::ERR_IO_PENDING));
entry->CancelSparseIO(); // Should be a no op at this point.
- EXPECT_EQ(net::ERR_IO_PENDING, entry->ReadyForSparseIO(cb4.callback()));
+ EXPECT_THAT(entry->ReadyForSparseIO(cb4.callback()),
+ IsError(net::ERR_IO_PENDING));
if (!cb1.have_result()) {
EXPECT_EQ(net::ERR_CACHE_OPERATION_NOT_SUPPORTED,
@@ -2433,9 +2441,9 @@ TEST_F(DiskCacheEntryTest, CancelSparseIO) {
// to write everything (unless the timing of the system is really weird).
rv = cb1.WaitForResult();
EXPECT_TRUE(rv == 4096 || rv == kSize);
- EXPECT_EQ(net::OK, cb2.WaitForResult());
- EXPECT_EQ(net::OK, cb3.WaitForResult());
- EXPECT_EQ(net::OK, cb4.WaitForResult());
+ EXPECT_THAT(cb2.WaitForResult(), IsOk());
+ EXPECT_THAT(cb3.WaitForResult(), IsOk());
+ EXPECT_THAT(cb4.WaitForResult(), IsOk());
rv = entry->GetAvailableRange(offset, kSize, &offset, cb5.callback());
EXPECT_EQ(0, cb5.GetResult(rv));
@@ -2449,7 +2457,7 @@ TEST_F(DiskCacheEntryTest, KeySanityCheck) {
InitCache();
std::string key("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
disk_cache::EntryImpl* entry_impl =
static_cast<disk_cache::EntryImpl*>(entry);
@@ -2484,7 +2492,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheReleaseBuffer) {
SetSimpleCacheMode();
InitCache();
for (int i = 0; i < disk_cache::kSimpleEntryStreamCount; ++i) {
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
ReleaseBuffer(i);
}
}
@@ -2505,7 +2513,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheGetTimes) {
SetSimpleCacheMode();
InitCache();
for (int i = 0; i < disk_cache::kSimpleEntryStreamCount; ++i) {
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
GetTimes(i);
}
}
@@ -2514,7 +2522,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheGrowData) {
SetSimpleCacheMode();
InitCache();
for (int i = 0; i < disk_cache::kSimpleEntryStreamCount; ++i) {
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
GrowData(i);
}
}
@@ -2523,7 +2531,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheTruncateData) {
SetSimpleCacheMode();
InitCache();
for (int i = 0; i < disk_cache::kSimpleEntryStreamCount; ++i) {
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
TruncateData(i);
}
}
@@ -2532,7 +2540,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheZeroLengthIO) {
SetSimpleCacheMode();
InitCache();
for (int i = 0; i < disk_cache::kSimpleEntryStreamCount; ++i) {
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
ZeroLengthIO(i);
}
}
@@ -2548,7 +2556,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheReuseExternalEntry) {
SetMaxSize(200 * 1024);
InitCache();
for (int i = 0; i < disk_cache::kSimpleEntryStreamCount; ++i) {
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
ReuseEntry(20 * 1024, i);
}
}
@@ -2558,7 +2566,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheReuseInternalEntry) {
SetMaxSize(100 * 1024);
InitCache();
for (int i = 0; i < disk_cache::kSimpleEntryStreamCount; ++i) {
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
ReuseEntry(10 * 1024, i);
}
}
@@ -2567,7 +2575,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheSizeChanges) {
SetSimpleCacheMode();
InitCache();
for (int i = 0; i < disk_cache::kSimpleEntryStreamCount; ++i) {
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
SizeChanges(i);
}
}
@@ -2576,7 +2584,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheInvalidData) {
SetSimpleCacheMode();
InitCache();
for (int i = 0; i < disk_cache::kSimpleEntryStreamCount; ++i) {
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
InvalidData(i);
}
}
@@ -2590,7 +2598,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheReadWriteDestroyBuffer) {
SetSimpleCacheMode();
InitCache();
for (int i = 1; i < disk_cache::kSimpleEntryStreamCount; ++i) {
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
ReadWriteDestroyBuffer(i);
}
}
@@ -2613,7 +2621,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheDoomedEntry) {
// Stream 2 is excluded because the implementation does not support writing to
// it on a doomed entry, if it was previously lazily omitted.
for (int i = 0; i < disk_cache::kSimpleEntryStreamCount - 1; ++i) {
- EXPECT_EQ(net::OK, DoomAllEntries());
+ EXPECT_THAT(DoomAllEntries(), IsOk());
DoomedEntry(i);
}
}
@@ -2665,7 +2673,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheBadChecksum) {
disk_cache::Entry* entry = NULL;
// Open the entry.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
ScopedEntryPtr entry_closer(entry);
const int kReadBufferSize = 200;
@@ -2687,7 +2695,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheErrorThenDoom) {
disk_cache::Entry* entry = NULL;
// Open the entry, forcing an IO error.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
ScopedEntryPtr entry_closer(entry);
const int kReadBufferSize = 200;
@@ -2713,7 +2721,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheNoEOF) {
const std::string key("the first key");
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
disk_cache::Entry* null = NULL;
EXPECT_NE(null, entry);
entry->Close();
@@ -2721,7 +2729,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheNoEOF) {
// Force the entry to flush to disk, so subsequent platform file operations
// succed.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
entry->Close();
entry = NULL;
@@ -2733,7 +2741,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheNoEOF) {
const int64_t invalid_size = disk_cache::simple_util::GetFileSizeFromDataSize(
key.size(), kTruncationBytes);
EXPECT_TRUE(TruncatePath(entry_path, invalid_size));
- EXPECT_EQ(net::ERR_FAILED, OpenEntry(key, &entry));
+ EXPECT_THAT(OpenEntry(key, &entry), IsError(net::ERR_FAILED));
DisableIntegrityCheck();
}
@@ -2746,7 +2754,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheNonOptimisticOperationsBasic) {
disk_cache::Entry* const null_entry = NULL;
disk_cache::Entry* entry = NULL;
- EXPECT_EQ(net::OK, CreateEntry("my key", &entry));
+ EXPECT_THAT(CreateEntry("my key", &entry), IsOk());
ASSERT_NE(null_entry, entry);
ScopedEntryPtr entry_closer(entry);
@@ -2781,7 +2789,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheNonOptimisticOperationsDontBlock) {
new net::IOBufferWithSize(kBufferSize));
disk_cache::Entry* entry = NULL;
- EXPECT_EQ(net::OK, CreateEntry("my key", &entry));
+ EXPECT_THAT(CreateEntry("my key", &entry), IsOk());
ASSERT_NE(null_entry, entry);
ScopedEntryPtr entry_closer(entry);
@@ -2794,7 +2802,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheNonOptimisticOperationsDontBlock) {
write_buffer->size(),
base::Bind(&CallbackTest::Run, base::Unretained(&write_callback)),
false);
- ASSERT_EQ(net::ERR_IO_PENDING, ret);
+ ASSERT_THAT(ret, IsError(net::ERR_IO_PENDING));
helper.WaitUntilCacheIoFinished(++expected_callback_runs);
}
@@ -2811,7 +2819,7 @@ TEST_F(DiskCacheEntryTest,
disk_cache::Entry* entry = NULL;
// Note that |entry| is only set once CreateEntry() completed which is why we
// have to wait (i.e. use the helper CreateEntry() function).
- EXPECT_EQ(net::OK, CreateEntry("my key", &entry));
+ EXPECT_THAT(CreateEntry("my key", &entry), IsOk());
ASSERT_NE(null_entry, entry);
ScopedEntryPtr entry_closer(entry);
@@ -2827,7 +2835,7 @@ TEST_F(DiskCacheEntryTest,
write_buffer->size(),
base::Bind(&CallbackTest::Run, base::Unretained(&write_callback)),
false);
- EXPECT_EQ(net::ERR_IO_PENDING, ret);
+ EXPECT_THAT(ret, IsError(net::ERR_IO_PENDING));
int expected_callback_runs = 1;
scoped_refptr<net::IOBufferWithSize> read_buffer(
@@ -2839,7 +2847,7 @@ TEST_F(DiskCacheEntryTest,
read_buffer.get(),
read_buffer->size(),
base::Bind(&CallbackTest::Run, base::Unretained(&read_callback)));
- EXPECT_EQ(net::ERR_IO_PENDING, ret);
+ EXPECT_THAT(ret, IsError(net::ERR_IO_PENDING));
++expected_callback_runs;
helper.WaitUntilCacheIoFinished(expected_callback_runs);
@@ -2995,7 +3003,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheOptimistic3) {
disk_cache::Entry* entry2 = NULL;
ASSERT_EQ(net::ERR_IO_PENDING,
cache_->OpenEntry(key, &entry2, cb.callback()));
- ASSERT_EQ(net::OK, cb.GetResult(net::ERR_IO_PENDING));
+ ASSERT_THAT(cb.GetResult(net::ERR_IO_PENDING), IsOk());
ScopedEntryPtr entry_closer(entry2);
EXPECT_NE(null, entry2);
@@ -3030,7 +3038,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheOptimistic4) {
EXPECT_EQ(
net::ERR_IO_PENDING,
entry->WriteData(1, 0, buffer1.get(), kSize1, cb.callback(), false));
- EXPECT_EQ(net::ERR_FAILED, cb.GetResult(net::ERR_IO_PENDING));
+ EXPECT_THAT(cb.GetResult(net::ERR_IO_PENDING), IsError(net::ERR_FAILED));
// Finish running the pending tasks so that we fully complete the close
// operation and destroy the entry object.
@@ -3041,13 +3049,13 @@ TEST_F(DiskCacheEntryTest, SimpleCacheOptimistic4) {
disk_cache::Entry* entry2 = NULL;
ASSERT_EQ(net::ERR_IO_PENDING,
cache_->OpenEntry(key, &entry2, cb.callback()));
- ASSERT_EQ(net::OK, cb.GetResult(net::ERR_IO_PENDING));
+ ASSERT_THAT(cb.GetResult(net::ERR_IO_PENDING), IsOk());
EXPECT_NE(null, entry2);
disk_cache::Entry* entry3 = NULL;
ASSERT_EQ(net::ERR_IO_PENDING,
cache_->OpenEntry(key, &entry3, cb.callback()));
- ASSERT_EQ(net::OK, cb.GetResult(net::ERR_IO_PENDING));
+ ASSERT_THAT(cb.GetResult(net::ERR_IO_PENDING), IsOk());
EXPECT_NE(null, entry3);
EXPECT_EQ(entry2, entry3);
entry3->Close();
@@ -3197,8 +3205,9 @@ TEST_F(DiskCacheEntryTest, SimpleCacheCreateDoomRace) {
cache_->CreateEntry(key, &entry, net::CompletionCallback()));
EXPECT_NE(null, entry);
- EXPECT_EQ(net::ERR_IO_PENDING, cache_->DoomEntry(key, cb.callback()));
- EXPECT_EQ(net::OK, cb.GetResult(net::ERR_IO_PENDING));
+ EXPECT_THAT(cache_->DoomEntry(key, cb.callback()),
+ IsError(net::ERR_IO_PENDING));
+ EXPECT_THAT(cb.GetResult(net::ERR_IO_PENDING), IsOk());
EXPECT_EQ(
kSize1,
@@ -3246,7 +3255,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheDoomCreateRace) {
create_callback.GetResult(
cache_->CreateEntry(key, &entry2, create_callback.callback())));
ScopedEntryPtr entry2_closer(entry2);
- EXPECT_EQ(net::OK, doom_callback.GetResult(net::ERR_IO_PENDING));
+ EXPECT_THAT(doom_callback.GetResult(net::ERR_IO_PENDING), IsOk());
}
TEST_F(DiskCacheEntryTest, SimpleCacheDoomDoom) {
@@ -3259,14 +3268,14 @@ TEST_F(DiskCacheEntryTest, SimpleCacheDoomDoom) {
const char key[] = "the first key";
disk_cache::Entry* entry1 = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry1));
+ ASSERT_THAT(CreateEntry(key, &entry1), IsOk());
ScopedEntryPtr entry1_closer(entry1);
EXPECT_NE(null, entry1);
- EXPECT_EQ(net::OK, DoomEntry(key));
+ EXPECT_THAT(DoomEntry(key), IsOk());
disk_cache::Entry* entry2 = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry2));
+ ASSERT_THAT(CreateEntry(key, &entry2), IsOk());
ScopedEntryPtr entry2_closer(entry2);
EXPECT_NE(null, entry2);
@@ -3278,7 +3287,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheDoomDoom) {
cb.GetResult(simple_entry1->DoomEntry(cb.callback())));
disk_cache::Entry* entry3 = NULL;
- ASSERT_EQ(net::OK, OpenEntry(key, &entry3));
+ ASSERT_THAT(OpenEntry(key, &entry3), IsOk());
ScopedEntryPtr entry3_closer(entry3);
EXPECT_NE(null, entry3);
}
@@ -3294,14 +3303,14 @@ TEST_F(DiskCacheEntryTest, SimpleCacheDoomCreateDoom) {
const char key[] = "the first key";
disk_cache::Entry* entry1 = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry1));
+ ASSERT_THAT(CreateEntry(key, &entry1), IsOk());
ScopedEntryPtr entry1_closer(entry1);
EXPECT_NE(null, entry1);
entry1->Doom();
disk_cache::Entry* entry2 = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry2));
+ ASSERT_THAT(CreateEntry(key, &entry2), IsOk());
ScopedEntryPtr entry2_closer(entry2);
EXPECT_NE(null, entry2);
@@ -3320,7 +3329,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheDoomCloseCreateCloseOpen) {
const char key[] = "this is a key";
disk_cache::Entry* entry1 = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry1));
+ ASSERT_THAT(CreateEntry(key, &entry1), IsOk());
ScopedEntryPtr entry1_closer(entry1);
EXPECT_NE(null, entry1);
@@ -3329,7 +3338,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheDoomCloseCreateCloseOpen) {
entry1 = NULL;
disk_cache::Entry* entry2 = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry2));
+ ASSERT_THAT(CreateEntry(key, &entry2), IsOk());
ScopedEntryPtr entry2_closer(entry2);
EXPECT_NE(null, entry2);
@@ -3337,7 +3346,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheDoomCloseCreateCloseOpen) {
entry2 = NULL;
disk_cache::Entry* entry3 = NULL;
- ASSERT_EQ(net::OK, OpenEntry(key, &entry3));
+ ASSERT_THAT(OpenEntry(key, &entry3), IsOk());
ScopedEntryPtr entry3_closer(entry3);
EXPECT_NE(null, entry3);
}
@@ -3356,7 +3365,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheOptimisticCreateFailsOnOpen) {
EXPECT_TRUE(disk_cache::simple_util::CreateCorruptFileForTests(
key, cache_path_));
- EXPECT_EQ(net::OK, cache_->CreateEntry(key, &entry, cb.callback()));
+ EXPECT_THAT(cache_->CreateEntry(key, &entry, cb.callback()), IsOk());
ASSERT_TRUE(entry);
ScopedEntryPtr entry_closer(entry);
ASSERT_NE(net::OK, OpenEntry(key, &entry2));
@@ -3382,7 +3391,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheEvictOldEntries) {
std::string key1("the first key");
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key1, &entry));
+ ASSERT_THAT(CreateEntry(key1, &entry), IsOk());
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kWriteSize));
CacheTestFillBuffer(buffer->data(), kWriteSize, false);
EXPECT_EQ(kWriteSize,
@@ -3397,7 +3406,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheEvictOldEntries) {
// will be checked for outliving the eviction.
AddDelay();
}
- ASSERT_EQ(net::OK, CreateEntry(key2 + base::IntToString(i), &entry));
+ ASSERT_THAT(CreateEntry(key2 + base::IntToString(i), &entry), IsOk());
ScopedEntryPtr entry_closer(entry);
EXPECT_EQ(kWriteSize,
WriteData(entry, 1, 0, buffer.get(), kWriteSize, false));
@@ -3432,14 +3441,14 @@ TEST_F(DiskCacheEntryTest, SimpleCacheInFlightTruncate) {
CacheTestFillBuffer(write_buffer->data(), kBufferSize, false);
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_EQ(kBufferSize,
WriteData(entry, 1, 0, write_buffer.get(), kBufferSize, false));
entry->Close();
entry = NULL;
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
ScopedEntryPtr entry_closer(entry);
MessageLoopHelper helper;
@@ -3545,8 +3554,8 @@ TEST_F(DiskCacheEntryTest, SimpleCacheOpenCreateRaceWithNoIndex) {
int rv1 = cache_->OpenEntry("key", &entry1, cb1.callback());
int rv2 = cache_->CreateEntry("key", &entry2, cb2.callback());
- EXPECT_EQ(net::ERR_FAILED, cb1.GetResult(rv1));
- ASSERT_EQ(net::OK, cb2.GetResult(rv2));
+ EXPECT_THAT(cb1.GetResult(rv1), IsError(net::ERR_FAILED));
+ ASSERT_THAT(cb2.GetResult(rv2), IsOk());
entry2->Close();
}
@@ -3566,13 +3575,13 @@ TEST_F(DiskCacheEntryTest, SimpleCacheMultipleReadersCheckCRC2) {
// Advance the first reader a little.
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
ScopedEntryPtr entry_closer(entry);
EXPECT_EQ(1, ReadData(entry, 1, 0, read_buffer1.get(), 1));
// Advance the 2nd reader by the same amount.
disk_cache::Entry* entry2 = NULL;
- EXPECT_EQ(net::OK, OpenEntry(key, &entry2));
+ EXPECT_THAT(OpenEntry(key, &entry2), IsOk());
ScopedEntryPtr entry2_closer(entry2);
EXPECT_EQ(1, ReadData(entry2, 1, 0, read_buffer2.get(), 1));
@@ -3601,14 +3610,14 @@ TEST_F(DiskCacheEntryTest, SimpleCacheReadCombineCRC) {
CacheTestFillBuffer(buffer1->data(), kSize, false);
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_NE(null, entry);
EXPECT_EQ(kSize, WriteData(entry, 1, 0, buffer1.get(), kSize, false));
entry->Close();
disk_cache::Entry* entry2 = NULL;
- ASSERT_EQ(net::OK, OpenEntry(key, &entry2));
+ ASSERT_THAT(OpenEntry(key, &entry2), IsOk());
EXPECT_EQ(entry, entry2);
// Read the first half of the data.
@@ -3654,10 +3663,10 @@ TEST_F(DiskCacheEntryTest, SimpleCacheNonSequentialWrite) {
memcpy(buffer2->data(), buffer1_data, kHalfSize);
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
entry->Close();
for (int i = 0; i < disk_cache::kSimpleEntryStreamCount; ++i) {
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
EXPECT_NE(null, entry);
int offset = kHalfSize;
@@ -3671,7 +3680,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheNonSequentialWrite) {
WriteData(entry, i, offset, buffer1.get(), buf_len, false));
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
scoped_refptr<net::IOBuffer> buffer1_read1(new net::IOBuffer(kSize));
EXPECT_EQ(kSize, ReadData(entry, i, 0, buffer1_read1.get(), kSize));
@@ -3695,7 +3704,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheStream1SizeChanges) {
scoped_refptr<net::IOBuffer> buffer_read(new net::IOBuffer(kSize));
CacheTestFillBuffer(buffer->data(), kSize, false);
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_TRUE(entry);
// Write something into stream0.
@@ -3705,7 +3714,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheStream1SizeChanges) {
entry->Close();
// Extend stream1.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
int stream1_size = 100;
EXPECT_EQ(0, WriteData(entry, 1, stream1_size, buffer.get(), 0, false));
EXPECT_EQ(stream1_size, entry->GetDataSize(1));
@@ -3716,7 +3725,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheStream1SizeChanges) {
// The entry needs to be reopened before checking the crc: Open will perform
// the synchronization with the previous Close. This ensures the EOF records
// have been written to disk before we attempt to read them independently.
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
base::FilePath entry_file0_path = cache_path_.AppendASCII(
disk_cache::simple_util::GetFilenameFromKeyAndFileIndex(key, 0));
base::File entry_file0(entry_file0_path,
@@ -3748,7 +3757,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheStream1SizeChanges) {
// Check that stream0 data has not been modified.
buffer_read = new net::IOBuffer(kSize);
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
EXPECT_EQ(kSize, ReadData(entry, 0, 0, buffer_read.get(), kSize));
EXPECT_EQ(0, memcmp(buffer->data(), buffer_read->data(), kSize));
entry->Close();
@@ -3774,12 +3783,12 @@ TEST_F(DiskCacheEntryTest, SimpleCacheCRCRewrite) {
CacheTestFillBuffer(buffer2->data(), kHalfSize, false);
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_NE(null, entry);
entry->Close();
for (int i = 0; i < disk_cache::kSimpleEntryStreamCount; ++i) {
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
int offset = 0;
int buf_len = kSize;
@@ -3791,7 +3800,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheCRCRewrite) {
WriteData(entry, i, offset, buffer2.get(), buf_len, false));
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
scoped_refptr<net::IOBuffer> buffer1_read1(new net::IOBuffer(kSize));
EXPECT_EQ(kSize, ReadData(entry, i, 0, buffer1_read1.get(), kSize));
@@ -3831,7 +3840,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheOmittedThirdStream1) {
// Create entry and close without writing: third stream file should be
// omitted, since the stream is empty.
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
entry->Close();
EXPECT_FALSE(SimpleCacheThirdStreamFileExists(key));
@@ -3856,7 +3865,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheOmittedThirdStream2) {
// Create entry, write empty buffer to third stream, and close: third stream
// should still be omitted, since the entry ignores writes that don't modify
// data or change the length.
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_EQ(0, WriteData(entry, 2, 0, buffer.get(), 0, true));
entry->Close();
EXPECT_FALSE(SimpleCacheThirdStreamFileExists(key));
@@ -3882,12 +3891,12 @@ TEST_F(DiskCacheEntryTest, SimpleCacheOmittedThirdStream3) {
// Create entry, write data to third stream, and close: third stream should
// not be omitted, since it contains data. Re-open entry and ensure there
// are that many bytes in the third stream.
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_EQ(kHalfSize, WriteData(entry, 2, 0, buffer1.get(), kHalfSize, true));
entry->Close();
EXPECT_TRUE(SimpleCacheThirdStreamFileExists(key));
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
EXPECT_EQ(kHalfSize, ReadData(entry, 2, 0, buffer2.get(), kSize));
EXPECT_EQ(0, memcmp(buffer1->data(), buffer2->data(), kHalfSize));
entry->Close();
@@ -3918,13 +3927,13 @@ TEST_F(DiskCacheEntryTest, SimpleCacheOmittedThirdStream4) {
// creates the file when the first significant write comes in, and only
// removes it on open if it is empty. Reopen, ensure that the file is
// deleted, and that there's no data in the third stream.
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_EQ(kHalfSize, WriteData(entry, 2, 0, buffer1.get(), kHalfSize, true));
EXPECT_EQ(0, WriteData(entry, 2, 0, buffer1.get(), 0, true));
entry->Close();
EXPECT_TRUE(SimpleCacheThirdStreamFileExists(key));
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
EXPECT_FALSE(SimpleCacheThirdStreamFileExists(key));
EXPECT_EQ(0, ReadData(entry, 2, 0, buffer2.get(), kSize));
entry->Close();
@@ -3951,7 +3960,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheOmittedThirdStream5) {
// Create entry, doom entry, write data to third stream, and close: third
// stream should not exist. (Note: We don't care if the write fails, just
// that it doesn't cause the file to be created on disk.)
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
entry->Doom();
WriteData(entry, 2, 0, buffer.get(), kHalfSize, true);
entry->Close();
@@ -3976,16 +3985,16 @@ TEST_F(DiskCacheEntryTest, SimpleCacheDoomOptimisticWritesRace) {
// The race only happens on stream 1 and stream 2.
for (int i = 0; i < disk_cache::kSimpleEntryStreamCount; ++i) {
- ASSERT_EQ(net::OK, DoomAllEntries());
+ ASSERT_THAT(DoomAllEntries(), IsOk());
disk_cache::Entry* entry = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_NE(null, entry);
entry->Close();
entry = NULL;
- ASSERT_EQ(net::OK, DoomAllEntries());
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(DoomAllEntries(), IsOk());
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_NE(null, entry);
int offset = 0;
@@ -4000,7 +4009,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheDoomOptimisticWritesRace) {
WriteData(entry, i, offset, buffer2.get(), buf_len, false));
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
EXPECT_NE(null, entry);
entry->Close();
@@ -4019,13 +4028,13 @@ TEST_F(DiskCacheEntryTest, SimpleCachePreserveActiveEntries) {
const char key[] = "this is a key";
disk_cache::Entry* entry1 = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry1));
+ ASSERT_THAT(CreateEntry(key, &entry1), IsOk());
ScopedEntryPtr entry1_closer(entry1);
EXPECT_NE(null, entry1);
entry1->Doom();
disk_cache::Entry* entry2 = NULL;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry2));
+ ASSERT_THAT(CreateEntry(key, &entry2), IsOk());
ScopedEntryPtr entry2_closer(entry2);
EXPECT_NE(null, entry2);
entry2_closer.reset();
@@ -4033,7 +4042,7 @@ TEST_F(DiskCacheEntryTest, SimpleCachePreserveActiveEntries) {
// Closing then reopening entry2 insures that entry2 is serialized, and so
// it can be opened from files without error.
entry2 = NULL;
- ASSERT_EQ(net::OK, OpenEntry(key, &entry2));
+ ASSERT_THAT(OpenEntry(key, &entry2), IsOk());
EXPECT_NE(null, entry2);
entry2_closer.reset(entry2);
@@ -4063,7 +4072,7 @@ TEST_F(DiskCacheEntryTest, SimpleCachePreserveActiveEntries) {
// In the bug case, this new entry ends up being a duplicate object pointing
// at the same underlying files.
disk_cache::Entry* entry3 = NULL;
- EXPECT_EQ(net::OK, OpenEntry(key, &entry3));
+ EXPECT_THAT(OpenEntry(key, &entry3), IsOk());
ScopedEntryPtr entry3_closer(entry3);
EXPECT_NE(null, entry3);
@@ -4120,7 +4129,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheTruncateLargeSparseFile) {
const char key[] = "key";
disk_cache::Entry* null = NULL;
disk_cache::Entry* entry;
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
EXPECT_NE(null, entry);
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize));
@@ -4156,7 +4165,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheTruncateLargeSparseFile) {
// Close and reopen the entry and make sure the first entry is still absent
// and the second entry is still present.
entry->Close();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
ret = entry->ReadSparseData(0, buffer.get(), kSize, callback.callback());
EXPECT_EQ(0, callback.GetResult(ret));
@@ -4174,7 +4183,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheReadWithoutKeySHA256) {
InitCache();
disk_cache::Entry* entry;
std::string key("a key");
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
const std::string stream_0_data = "data for stream zero";
scoped_refptr<net::IOBuffer> stream_0_iobuffer(
@@ -4196,7 +4205,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheReadWithoutKeySHA256) {
EXPECT_TRUE(
disk_cache::simple_util::RemoveKeySHA256FromEntry(key, cache_path_));
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
ScopedEntryPtr entry_closer(entry);
EXPECT_EQ(static_cast<int>(stream_0_data.size()), entry->GetDataSize(0));
@@ -4227,7 +4236,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheDoubleOpenWithoutKeySHA256) {
InitCache();
disk_cache::Entry* entry;
std::string key("a key");
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
entry->Close();
base::RunLoop().RunUntilIdle();
@@ -4236,14 +4245,14 @@ TEST_F(DiskCacheEntryTest, SimpleCacheDoubleOpenWithoutKeySHA256) {
EXPECT_TRUE(
disk_cache::simple_util::RemoveKeySHA256FromEntry(key, cache_path_));
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
entry->Close();
base::RunLoop().RunUntilIdle();
disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting();
base::RunLoop().RunUntilIdle();
- ASSERT_EQ(net::OK, OpenEntry(key, &entry));
+ ASSERT_THAT(OpenEntry(key, &entry), IsOk());
entry->Close();
}
@@ -4254,7 +4263,7 @@ TEST_F(DiskCacheEntryTest, SimpleCacheReadCorruptKeySHA256) {
InitCache();
disk_cache::Entry* entry;
std::string key("a key");
- ASSERT_EQ(net::OK, CreateEntry(key, &entry));
+ ASSERT_THAT(CreateEntry(key, &entry), IsOk());
entry->Close();
base::RunLoop().RunUntilIdle();
diff --git a/chromium/net/disk_cache/memory/mem_backend_impl.cc b/chromium/net/disk_cache/memory/mem_backend_impl.cc
index 0ba2d3fef1c..ad9dfedcfab 100644
--- a/chromium/net/disk_cache/memory/mem_backend_impl.cc
+++ b/chromium/net/disk_cache/memory/mem_backend_impl.cc
@@ -9,6 +9,7 @@
#include <utility>
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/sys_info.h"
#include "net/base/net_errors.h"
#include "net/disk_cache/cache_util.h"
@@ -208,38 +209,48 @@ int MemBackendImpl::CalculateSizeOfAllEntries(
class MemBackendImpl::MemIterator final : public Backend::Iterator {
public:
explicit MemIterator(base::WeakPtr<MemBackendImpl> backend)
- : backend_(backend), current_(nullptr) {}
+ : backend_(backend) {}
int OpenNextEntry(Entry** next_entry,
const CompletionCallback& callback) override {
if (!backend_)
return net::ERR_FAILED;
- // Iterate using |lru_list_|, from most recently used to least recently
- // used, for compatibility with the unit tests that assume this behaviour.
- // Consider the last element if we are beginning an iteration, otherwise
- // progressively move earlier in the LRU list.
- current_ = current_ ? current_->previous() : backend_->lru_list_.tail();
-
- // We should never return a child entry so iterate until we hit a parent
- // entry.
- while (current_ != backend_->lru_list_.end() &&
- current_->value()->type() != MemEntryImpl::PARENT_ENTRY) {
- current_ = current_->previous();
- }
- if (current_ == backend_->lru_list_.end()) {
- *next_entry = nullptr;
- return net::ERR_FAILED;
+ if (!backend_keys_) {
+ backend_keys_ = base::MakeUnique<Strings>(backend_->entries_.size());
+ for (const auto& iter : backend_->entries_)
+ backend_keys_->push_back(iter.first);
+ current_ = backend_keys_->begin();
+ } else {
+ current_++;
}
- current_->value()->Open();
- *next_entry = current_->value();
- return net::OK;
+ while (true) {
+ if (current_ == backend_keys_->end()) {
+ *next_entry = nullptr;
+ backend_keys_.reset();
+ return net::ERR_FAILED;
+ }
+
+ const auto& entry_iter = backend_->entries_.find(*current_);
+ if (entry_iter == backend_->entries_.end()) {
+ // The key is no longer in the cache, move on to the next key.
+ current_++;
+ continue;
+ }
+
+ entry_iter->second->Open();
+ *next_entry = entry_iter->second;
+ return net::OK;
+ }
}
private:
+ using Strings = std::vector<std::string>;
+
base::WeakPtr<MemBackendImpl> backend_;
- base::LinkNode<MemEntryImpl>* current_;
+ std::unique_ptr<Strings> backend_keys_;
+ Strings::iterator current_;
};
std::unique_ptr<Backend::Iterator> MemBackendImpl::CreateIterator() {
diff --git a/chromium/net/disk_cache/memory/mem_backend_impl.h b/chromium/net/disk_cache/memory/mem_backend_impl.h
index f6ebbf7b0ce..30417c69cab 100644
--- a/chromium/net/disk_cache/memory/mem_backend_impl.h
+++ b/chromium/net/disk_cache/memory/mem_backend_impl.h
@@ -18,6 +18,7 @@
#include "base/memory/weak_ptr.h"
#include "base/strings/string_split.h"
#include "base/time/time.h"
+#include "net/base/net_export.h"
#include "net/disk_cache/disk_cache.h"
#include "net/disk_cache/memory/mem_entry_impl.h"
diff --git a/chromium/net/disk_cache/memory/mem_entry_impl.cc b/chromium/net/disk_cache/memory/mem_entry_impl.cc
index f1efa334af4..cfe23e75cf7 100644
--- a/chromium/net/disk_cache/memory/mem_entry_impl.cc
+++ b/chromium/net/disk_cache/memory/mem_entry_impl.cc
@@ -15,6 +15,8 @@
#include "net/base/net_errors.h"
#include "net/disk_cache/memory/mem_backend_impl.h"
#include "net/disk_cache/net_log_parameters.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source_type.h"
using base::Time;
@@ -129,7 +131,7 @@ void MemEntryImpl::Doom() {
if (!doomed_) {
doomed_ = true;
backend_->OnEntryDoomed(this);
- net_log_.AddEvent(net::NetLog::TYPE_ENTRY_DOOM);
+ net_log_.AddEvent(net::NetLogEventType::ENTRY_DOOM);
}
if (!ref_count_)
delete this;
@@ -167,16 +169,15 @@ int MemEntryImpl::ReadData(int index, int offset, IOBuffer* buf, int buf_len,
const CompletionCallback& callback) {
if (net_log_.IsCapturing()) {
net_log_.BeginEvent(
- net::NetLog::TYPE_ENTRY_READ_DATA,
+ net::NetLogEventType::ENTRY_READ_DATA,
CreateNetLogReadWriteDataCallback(index, offset, buf_len, false));
}
int result = InternalReadData(index, offset, buf, buf_len);
if (net_log_.IsCapturing()) {
- net_log_.EndEvent(
- net::NetLog::TYPE_ENTRY_READ_DATA,
- CreateNetLogReadWriteCompleteCallback(result));
+ net_log_.EndEvent(net::NetLogEventType::ENTRY_READ_DATA,
+ CreateNetLogReadWriteCompleteCallback(result));
}
return result;
}
@@ -185,16 +186,15 @@ int MemEntryImpl::WriteData(int index, int offset, IOBuffer* buf, int buf_len,
const CompletionCallback& callback, bool truncate) {
if (net_log_.IsCapturing()) {
net_log_.BeginEvent(
- net::NetLog::TYPE_ENTRY_WRITE_DATA,
+ net::NetLogEventType::ENTRY_WRITE_DATA,
CreateNetLogReadWriteDataCallback(index, offset, buf_len, truncate));
}
int result = InternalWriteData(index, offset, buf, buf_len, truncate);
if (net_log_.IsCapturing()) {
- net_log_.EndEvent(
- net::NetLog::TYPE_ENTRY_WRITE_DATA,
- CreateNetLogReadWriteCompleteCallback(result));
+ net_log_.EndEvent(net::NetLogEventType::ENTRY_WRITE_DATA,
+ CreateNetLogReadWriteCompleteCallback(result));
}
return result;
}
@@ -204,13 +204,12 @@ int MemEntryImpl::ReadSparseData(int64_t offset,
int buf_len,
const CompletionCallback& callback) {
if (net_log_.IsCapturing()) {
- net_log_.BeginEvent(
- net::NetLog::TYPE_SPARSE_READ,
- CreateNetLogSparseOperationCallback(offset, buf_len));
+ net_log_.BeginEvent(net::NetLogEventType::SPARSE_READ,
+ CreateNetLogSparseOperationCallback(offset, buf_len));
}
int result = InternalReadSparseData(offset, buf, buf_len);
if (net_log_.IsCapturing())
- net_log_.EndEvent(net::NetLog::TYPE_SPARSE_READ);
+ net_log_.EndEvent(net::NetLogEventType::SPARSE_READ);
return result;
}
@@ -219,13 +218,12 @@ int MemEntryImpl::WriteSparseData(int64_t offset,
int buf_len,
const CompletionCallback& callback) {
if (net_log_.IsCapturing()) {
- net_log_.BeginEvent(
- net::NetLog::TYPE_SPARSE_WRITE,
- CreateNetLogSparseOperationCallback(offset, buf_len));
+ net_log_.BeginEvent(net::NetLogEventType::SPARSE_WRITE,
+ CreateNetLogSparseOperationCallback(offset, buf_len));
}
int result = InternalWriteSparseData(offset, buf, buf_len);
if (net_log_.IsCapturing())
- net_log_.EndEvent(net::NetLog::TYPE_SPARSE_WRITE);
+ net_log_.EndEvent(net::NetLogEventType::SPARSE_WRITE);
return result;
}
@@ -234,14 +232,13 @@ int MemEntryImpl::GetAvailableRange(int64_t offset,
int64_t* start,
const CompletionCallback& callback) {
if (net_log_.IsCapturing()) {
- net_log_.BeginEvent(
- net::NetLog::TYPE_SPARSE_GET_RANGE,
- CreateNetLogSparseOperationCallback(offset, len));
+ net_log_.BeginEvent(net::NetLogEventType::SPARSE_GET_RANGE,
+ CreateNetLogSparseOperationCallback(offset, len));
}
int result = InternalGetAvailableRange(offset, len, start);
if (net_log_.IsCapturing()) {
net_log_.EndEvent(
- net::NetLog::TYPE_SPARSE_GET_RANGE,
+ net::NetLogEventType::SPARSE_GET_RANGE,
CreateNetLogGetAvailableRangeResultCallback(*start, result));
}
return result;
@@ -273,9 +270,9 @@ MemEntryImpl::MemEntryImpl(MemBackendImpl* backend,
backend_(backend),
doomed_(false) {
backend_->OnEntryInserted(this);
- net_log_ =
- net::BoundNetLog::Make(net_log, net::NetLog::SOURCE_MEMORY_CACHE_ENTRY);
- net_log_.BeginEvent(net::NetLog::TYPE_DISK_CACHE_MEM_ENTRY_IMPL,
+ net_log_ = net::NetLogWithSource::Make(
+ net_log, net::NetLogSourceType::MEMORY_CACHE_ENTRY);
+ net_log_.BeginEvent(net::NetLogEventType::DISK_CACHE_MEM_ENTRY_IMPL,
base::Bind(&NetLogEntryCreationCallback, this));
}
@@ -297,7 +294,7 @@ MemEntryImpl::~MemEntryImpl() {
} else {
parent_->children_->erase(child_id_);
}
- net_log_.EndEvent(net::NetLog::TYPE_DISK_CACHE_MEM_ENTRY_IMPL);
+ net_log_.EndEvent(net::NetLogEventType::DISK_CACHE_MEM_ENTRY_IMPL);
}
int MemEntryImpl::InternalReadData(int index, int offset, IOBuffer* buf,
@@ -392,7 +389,7 @@ int MemEntryImpl::InternalReadSparseData(int64_t offset,
break;
if (net_log_.IsCapturing()) {
net_log_.BeginEvent(
- net::NetLog::TYPE_SPARSE_READ_CHILD_DATA,
+ net::NetLogEventType::SPARSE_READ_CHILD_DATA,
CreateNetLogSparseReadWriteCallback(child->net_log_.source(),
io_buf->BytesRemaining()));
}
@@ -400,7 +397,7 @@ int MemEntryImpl::InternalReadSparseData(int64_t offset,
io_buf->BytesRemaining(), CompletionCallback());
if (net_log_.IsCapturing()) {
net_log_.EndEventWithNetErrorCode(
- net::NetLog::TYPE_SPARSE_READ_CHILD_DATA, ret);
+ net::NetLogEventType::SPARSE_READ_CHILD_DATA, ret);
}
// If we encounter an error in one entry, return immediately.
@@ -448,7 +445,7 @@ int MemEntryImpl::InternalWriteSparseData(int64_t offset,
int data_size = child->GetDataSize(kSparseData);
if (net_log_.IsCapturing()) {
- net_log_.BeginEvent(net::NetLog::TYPE_SPARSE_WRITE_CHILD_DATA,
+ net_log_.BeginEvent(net::NetLogEventType::SPARSE_WRITE_CHILD_DATA,
CreateNetLogSparseReadWriteCallback(
child->net_log_.source(), write_len));
}
@@ -461,7 +458,7 @@ int MemEntryImpl::InternalWriteSparseData(int64_t offset,
write_len, CompletionCallback(), true);
if (net_log_.IsCapturing()) {
net_log_.EndEventWithNetErrorCode(
- net::NetLog::TYPE_SPARSE_WRITE_CHILD_DATA, ret);
+ net::NetLogEventType::SPARSE_WRITE_CHILD_DATA, ret);
}
if (ret < 0)
return ret;
diff --git a/chromium/net/disk_cache/memory/mem_entry_impl.h b/chromium/net/disk_cache/memory/mem_entry_impl.h
index b366065be18..3a3f9416986 100644
--- a/chromium/net/disk_cache/memory/mem_entry_impl.h
+++ b/chromium/net/disk_cache/memory/mem_entry_impl.h
@@ -16,8 +16,13 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/time/time.h"
+#include "net/base/net_export.h"
#include "net/disk_cache/disk_cache.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
+
+namespace net {
+class NetLog;
+}
namespace disk_cache {
@@ -179,7 +184,7 @@ class NET_EXPORT_PRIVATE MemEntryImpl final
MemBackendImpl* backend_; // Back pointer to the cache.
bool doomed_; // True if this entry was removed from the cache.
- net::BoundNetLog net_log_;
+ net::NetLogWithSource net_log_;
DISALLOW_COPY_AND_ASSIGN(MemEntryImpl);
};
diff --git a/chromium/net/disk_cache/net_log_parameters.cc b/chromium/net/disk_cache/net_log_parameters.cc
index 9ab448ff92c..db92e851d9e 100644
--- a/chromium/net/disk_cache/net_log_parameters.cc
+++ b/chromium/net/disk_cache/net_log_parameters.cc
@@ -12,6 +12,8 @@
#include "base/values.h"
#include "net/base/net_errors.h"
#include "net/disk_cache/disk_cache.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_source.h"
namespace {
@@ -66,7 +68,7 @@ std::unique_ptr<base::Value> NetLogSparseOperationCallback(
}
std::unique_ptr<base::Value> NetLogSparseReadWriteCallback(
- const net::NetLog::Source& source,
+ const net::NetLogSource& source,
int child_len,
net::NetLogCaptureMode /* capture_mode */) {
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
@@ -93,40 +95,39 @@ std::unique_ptr<base::Value> NetLogGetAvailableRangeResultCallback(
namespace disk_cache {
-net::NetLog::ParametersCallback CreateNetLogEntryCreationCallback(
+net::NetLogParametersCallback CreateNetLogEntryCreationCallback(
const Entry* entry,
bool created) {
DCHECK(entry);
return base::Bind(&NetLogEntryCreationCallback, entry, created);
}
-net::NetLog::ParametersCallback CreateNetLogReadWriteDataCallback(
- int index,
- int offset,
- int buf_len,
- bool truncate) {
+net::NetLogParametersCallback CreateNetLogReadWriteDataCallback(int index,
+ int offset,
+ int buf_len,
+ bool truncate) {
return base::Bind(&NetLogReadWriteDataCallback,
index, offset, buf_len, truncate);
}
-net::NetLog::ParametersCallback CreateNetLogReadWriteCompleteCallback(
+net::NetLogParametersCallback CreateNetLogReadWriteCompleteCallback(
int bytes_copied) {
return base::Bind(&NetLogReadWriteCompleteCallback, bytes_copied);
}
-net::NetLog::ParametersCallback CreateNetLogSparseOperationCallback(
+net::NetLogParametersCallback CreateNetLogSparseOperationCallback(
int64_t offset,
int buf_len) {
return base::Bind(&NetLogSparseOperationCallback, offset, buf_len);
}
-net::NetLog::ParametersCallback CreateNetLogSparseReadWriteCallback(
- const net::NetLog::Source& source,
+net::NetLogParametersCallback CreateNetLogSparseReadWriteCallback(
+ const net::NetLogSource& source,
int child_len) {
return base::Bind(&NetLogSparseReadWriteCallback, source, child_len);
}
-net::NetLog::ParametersCallback CreateNetLogGetAvailableRangeResultCallback(
+net::NetLogParametersCallback CreateNetLogGetAvailableRangeResultCallback(
int64_t start,
int result) {
return base::Bind(&NetLogGetAvailableRangeResultCallback, start, result);
diff --git a/chromium/net/disk_cache/net_log_parameters.h b/chromium/net/disk_cache/net_log_parameters.h
index 2bbed1232d5..86c5c3cc5b1 100644
--- a/chromium/net/disk_cache/net_log_parameters.h
+++ b/chromium/net/disk_cache/net_log_parameters.h
@@ -9,9 +9,13 @@
#include <string>
-#include "net/log/net_log.h"
+#include "net/log/net_log_parameters_callback.h"
-// This file contains a set of functions to create NetLog::ParametersCallbacks
+namespace net {
+struct NetLogSource;
+}
+
+// This file contains a set of functions to create NetLogParametersCallbacks
// shared by EntryImpls and MemEntryImpls.
namespace disk_cache {
@@ -21,41 +25,40 @@ class Entry;
// Entry. Contains the Entry's key and whether it was created or opened.
// |entry| can't be NULL, must support GetKey(), and must outlive the returned
// callback.
-net::NetLog::ParametersCallback CreateNetLogEntryCreationCallback(
+net::NetLogParametersCallback CreateNetLogEntryCreationCallback(
const Entry* entry,
bool created);
// Creates a NetLog callback that returns parameters for start of a non-sparse
// read or write of an Entry. For reads, |truncate| must be false.
-net::NetLog::ParametersCallback CreateNetLogReadWriteDataCallback(
- int index,
- int offset,
- int buf_len,
- bool truncate);
+net::NetLogParametersCallback CreateNetLogReadWriteDataCallback(int index,
+ int offset,
+ int buf_len,
+ bool truncate);
// Creates a NetLog callback that returns parameters for when a non-sparse
// read or write completes. For reads, |truncate| must be false.
// |bytes_copied| is either the number of bytes copied or a network error
// code. |bytes_copied| must not be ERR_IO_PENDING, as it's not a valid
// result for an operation.
-net::NetLog::ParametersCallback CreateNetLogReadWriteCompleteCallback(
+net::NetLogParametersCallback CreateNetLogReadWriteCompleteCallback(
int bytes_copied);
// Creates a NetLog callback that returns parameters for when a sparse
// operation is started.
-net::NetLog::ParametersCallback CreateNetLogSparseOperationCallback(
+net::NetLogParametersCallback CreateNetLogSparseOperationCallback(
int64_t offset,
int buf_len);
// Creates a NetLog callback that returns parameters for when a read or write
// for a sparse entry's child is started.
-net::NetLog::ParametersCallback CreateNetLogSparseReadWriteCallback(
- const net::NetLog::Source& source,
+net::NetLogParametersCallback CreateNetLogSparseReadWriteCallback(
+ const net::NetLogSource& source,
int child_len);
// Creates a NetLog callback that returns parameters for when a call to
// GetAvailableRange returns.
-net::NetLog::ParametersCallback CreateNetLogGetAvailableRangeResultCallback(
+net::NetLogParametersCallback CreateNetLogGetAvailableRangeResultCallback(
int64_t start,
int result);
diff --git a/chromium/net/disk_cache/simple/simple_backend_impl.cc b/chromium/net/disk_cache/simple/simple_backend_impl.cc
index 4587bf9a3f8..6d1d1311d6c 100644
--- a/chromium/net/disk_cache/simple/simple_backend_impl.cc
+++ b/chromium/net/disk_cache/simple/simple_backend_impl.cc
@@ -65,7 +65,9 @@ class LeakySequencedWorkerPool {
public:
LeakySequencedWorkerPool()
: sequenced_worker_pool_(
- new SequencedWorkerPool(kMaxWorkerThreads, kThreadNamePrefix)) {}
+ new SequencedWorkerPool(kMaxWorkerThreads,
+ kThreadNamePrefix,
+ base::TaskPriority::USER_BLOCKING)) {}
void FlushForTesting() { sequenced_worker_pool_->FlushForTesting(); }
@@ -253,8 +255,8 @@ int SimpleBackendImpl::Init(const CompletionCallback& completion_callback) {
index_.reset(new SimpleIndex(
base::ThreadTaskRunnerHandle::Get(), this, cache_type_,
- base::WrapUnique(new SimpleIndexFile(cache_thread_, worker_pool_.get(),
- cache_type_, path_))));
+ base::MakeUnique<SimpleIndexFile>(cache_thread_, worker_pool_.get(),
+ cache_type_, path_)));
index_->ExecuteWhenReady(
base::Bind(&RecordIndexLoad, cache_type_, base::TimeTicks::Now()));
diff --git a/chromium/net/disk_cache/simple/simple_backend_impl.h b/chromium/net/disk_cache/simple/simple_backend_impl.h
index e491359392b..d636ff8e27f 100644
--- a/chromium/net/disk_cache/simple/simple_backend_impl.h
+++ b/chromium/net/disk_cache/simple/simple_backend_impl.h
@@ -22,6 +22,7 @@
#include "base/task_runner.h"
#include "base/time/time.h"
#include "net/base/cache_type.h"
+#include "net/base/net_export.h"
#include "net/disk_cache/disk_cache.h"
#include "net/disk_cache/simple/simple_entry_impl.h"
#include "net/disk_cache/simple/simple_index_delegate.h"
diff --git a/chromium/net/disk_cache/simple/simple_entry_impl.cc b/chromium/net/disk_cache/simple/simple_entry_impl.cc
index 8169b05a6b1..8bc20fcbbde 100644
--- a/chromium/net/disk_cache/simple/simple_entry_impl.cc
+++ b/chromium/net/disk_cache/simple/simple_entry_impl.cc
@@ -29,6 +29,8 @@
#include "net/disk_cache/simple/simple_net_log_parameters.h"
#include "net/disk_cache/simple/simple_synchronous_entry.h"
#include "net/disk_cache/simple/simple_util.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_source_type.h"
#include "third_party/zlib/zlib.h"
namespace disk_cache {
@@ -183,8 +185,9 @@ SimpleEntryImpl::SimpleEntryImpl(net::CacheType cache_type,
doomed_(false),
state_(STATE_UNINITIALIZED),
synchronous_entry_(NULL),
- net_log_(net::BoundNetLog::Make(net_log,
- net::NetLog::SOURCE_DISK_CACHE_ENTRY)),
+ net_log_(
+ net::NetLogWithSource::Make(net_log,
+ net::NetLogSourceType::DISK_CACHE_ENTRY)),
stream_0_data_(new net::GrowableIOBuffer()) {
static_assert(arraysize(data_size_) == arraysize(crc32s_end_offset_),
"arrays should be the same size");
@@ -195,8 +198,8 @@ SimpleEntryImpl::SimpleEntryImpl(net::CacheType cache_type,
static_assert(arraysize(data_size_) == arraysize(crc_check_state_),
"arrays should be the same size");
MakeUninitialized();
- net_log_.BeginEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY,
- CreateNetLogSimpleEntryConstructionCallback(this));
+ net_log_.BeginEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY,
+ CreateNetLogSimpleEntryConstructionCallback(this));
}
void SimpleEntryImpl::SetActiveEntryProxy(
@@ -209,7 +212,7 @@ int SimpleEntryImpl::OpenEntry(Entry** out_entry,
const CompletionCallback& callback) {
DCHECK(backend_.get());
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_OPEN_CALL);
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_OPEN_CALL);
bool have_index = backend_->index()->initialized();
// This enumeration is used in histograms, add entries only at end.
@@ -233,8 +236,7 @@ int SimpleEntryImpl::OpenEntry(Entry** out_entry,
// If entry is not known to the index, initiate fast failover to the network.
if (open_entry_index_enum == INDEX_MISS) {
net_log_.AddEventWithNetErrorCode(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_OPEN_END,
- net::ERR_FAILED);
+ net::NetLogEventType::SIMPLE_CACHE_ENTRY_OPEN_END, net::ERR_FAILED);
return net::ERR_FAILED;
}
@@ -249,13 +251,14 @@ int SimpleEntryImpl::CreateEntry(Entry** out_entry,
DCHECK(backend_.get());
DCHECK_EQ(entry_hash_, simple_util::GetEntryHashKey(key_));
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CREATE_CALL);
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_CREATE_CALL);
bool have_index = backend_->index()->initialized();
int ret_value = net::ERR_FAILED;
if (use_optimistic_operations_ &&
state_ == STATE_UNINITIALIZED && pending_operations_.size() == 0) {
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CREATE_OPTIMISTIC);
+ net_log_.AddEvent(
+ net::NetLogEventType::SIMPLE_CACHE_ENTRY_CREATE_OPTIMISTIC);
ReturnEntryToCaller(out_entry);
pending_operations_.push(SimpleEntryOperation::CreateOperation(
@@ -281,8 +284,8 @@ int SimpleEntryImpl::CreateEntry(Entry** out_entry,
int SimpleEntryImpl::DoomEntry(const CompletionCallback& callback) {
if (doomed_)
return net::OK;
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_DOOM_CALL);
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_DOOM_BEGIN);
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_DOOM_CALL);
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_DOOM_BEGIN);
MarkAsDoomed();
if (backend_.get())
@@ -294,8 +297,8 @@ int SimpleEntryImpl::DoomEntry(const CompletionCallback& callback) {
void SimpleEntryImpl::SetKey(const std::string& key) {
key_ = key;
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_SET_KEY,
- net::NetLog::StringCallback("key", &key));
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_SET_KEY,
+ net::NetLog::StringCallback("key", &key));
}
void SimpleEntryImpl::Doom() {
@@ -306,7 +309,7 @@ void SimpleEntryImpl::Close() {
DCHECK(io_thread_checker_.CalledOnValidThread());
DCHECK_LT(0, open_count_);
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CLOSE_CALL);
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_CLOSE_CALL);
if (--open_count_ > 0) {
DCHECK(!HasOneRef());
@@ -349,15 +352,16 @@ int SimpleEntryImpl::ReadData(int stream_index,
DCHECK(io_thread_checker_.CalledOnValidThread());
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_CALL,
- CreateNetLogReadWriteDataCallback(stream_index, offset, buf_len,
- false));
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_READ_CALL,
+ CreateNetLogReadWriteDataCallback(stream_index, offset,
+ buf_len, false));
}
if (stream_index < 0 || stream_index >= kSimpleEntryStreamCount ||
buf_len < 0) {
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_END,
+ net_log_.AddEvent(
+ net::NetLogEventType::SIMPLE_CACHE_ENTRY_READ_END,
CreateNetLogReadWriteCompleteCallback(net::ERR_INVALID_ARGUMENT));
}
@@ -367,8 +371,8 @@ int SimpleEntryImpl::ReadData(int stream_index,
if (pending_operations_.empty() && (offset >= GetDataSize(stream_index) ||
offset < 0 || !buf_len)) {
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_END,
- CreateNetLogReadWriteCompleteCallback(0));
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_READ_END,
+ CreateNetLogReadWriteCompleteCallback(0));
}
RecordReadResult(cache_type_, READ_RESULT_NONBLOCK_EMPTY_RETURN);
@@ -396,17 +400,16 @@ int SimpleEntryImpl::WriteData(int stream_index,
DCHECK(io_thread_checker_.CalledOnValidThread());
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_CALL,
- CreateNetLogReadWriteDataCallback(stream_index, offset, buf_len,
- truncate));
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_WRITE_CALL,
+ CreateNetLogReadWriteDataCallback(stream_index, offset,
+ buf_len, truncate));
}
if (stream_index < 0 || stream_index >= kSimpleEntryStreamCount ||
offset < 0 || buf_len < 0) {
if (net_log_.IsCapturing()) {
net_log_.AddEvent(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_END,
+ net::NetLogEventType::SIMPLE_CACHE_ENTRY_WRITE_END,
CreateNetLogReadWriteCompleteCallback(net::ERR_INVALID_ARGUMENT));
}
RecordWriteResult(cache_type_, WRITE_RESULT_INVALID_ARGUMENT);
@@ -414,9 +417,8 @@ int SimpleEntryImpl::WriteData(int stream_index,
}
if (backend_.get() && offset + buf_len > backend_->GetMaxFileSize()) {
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_END,
- CreateNetLogReadWriteCompleteCallback(net::ERR_FAILED));
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_WRITE_END,
+ CreateNetLogReadWriteCompleteCallback(net::ERR_FAILED));
}
RecordWriteResult(cache_type_, WRITE_RESULT_OVER_MAX_SIZE);
return net::ERR_FAILED;
@@ -457,7 +459,7 @@ int SimpleEntryImpl::WriteData(int stream_index,
ret_value = buf_len;
if (net_log_.IsCapturing()) {
net_log_.AddEvent(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_OPTIMISTIC,
+ net::NetLogEventType::SIMPLE_CACHE_ENTRY_WRITE_OPTIMISTIC,
CreateNetLogReadWriteCompleteCallback(buf_len));
}
}
@@ -480,7 +482,7 @@ int SimpleEntryImpl::ReadSparseData(int64_t offset,
DCHECK(io_thread_checker_.CalledOnValidThread());
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_SPARSE_CALL,
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_READ_SPARSE_CALL,
CreateNetLogSparseOperationCallback(offset, buf_len));
}
@@ -497,8 +499,9 @@ int SimpleEntryImpl::WriteSparseData(int64_t offset,
DCHECK(io_thread_checker_.CalledOnValidThread());
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_SPARSE_CALL,
- CreateNetLogSparseOperationCallback(offset, buf_len));
+ net_log_.AddEvent(
+ net::NetLogEventType::SIMPLE_CACHE_ENTRY_WRITE_SPARSE_CALL,
+ CreateNetLogSparseOperationCallback(offset, buf_len));
}
ScopedOperationRunner operation_runner(this);
@@ -545,7 +548,7 @@ SimpleEntryImpl::~SimpleEntryImpl() {
DCHECK_EQ(0U, pending_operations_.size());
DCHECK(state_ == STATE_UNINITIALIZED || state_ == STATE_FAILURE);
DCHECK(!synchronous_entry_);
- net_log_.EndEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY);
+ net_log_.EndEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY);
}
void SimpleEntryImpl::PostClientCallback(const CompletionCallback& callback,
@@ -671,20 +674,19 @@ void SimpleEntryImpl::OpenEntryInternal(bool have_index,
Entry** out_entry) {
ScopedOperationRunner operation_runner(this);
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_OPEN_BEGIN);
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_OPEN_BEGIN);
if (state_ == STATE_READY) {
ReturnEntryToCaller(out_entry);
PostClientCallback(callback, net::OK);
- net_log_.AddEvent(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_OPEN_END,
- CreateNetLogSimpleEntryCreationCallback(this, net::OK));
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_OPEN_END,
+ CreateNetLogSimpleEntryCreationCallback(this, net::OK));
return;
}
if (state_ == STATE_FAILURE) {
PostClientCallback(callback, net::ERR_FAILED);
net_log_.AddEvent(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_OPEN_END,
+ net::NetLogEventType::SIMPLE_CACHE_ENTRY_OPEN_END,
CreateNetLogSimpleEntryCreationCallback(this, net::ERR_FAILED));
return;
}
@@ -702,7 +704,7 @@ void SimpleEntryImpl::OpenEntryInternal(bool have_index,
Closure reply =
base::Bind(&SimpleEntryImpl::CreationOperationComplete, this, callback,
start_time, base::Passed(&results), out_entry,
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_OPEN_END);
+ net::NetLogEventType::SIMPLE_CACHE_ENTRY_OPEN_END);
worker_pool_->PostTaskAndReply(FROM_HERE, task, reply);
}
@@ -711,12 +713,12 @@ void SimpleEntryImpl::CreateEntryInternal(bool have_index,
Entry** out_entry) {
ScopedOperationRunner operation_runner(this);
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CREATE_BEGIN);
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_CREATE_BEGIN);
if (state_ != STATE_UNINITIALIZED) {
// There is already an active normal entry.
net_log_.AddEvent(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CREATE_END,
+ net::NetLogEventType::SIMPLE_CACHE_ENTRY_CREATE_END,
CreateNetLogSimpleEntryCreationCallback(this, net::ERR_FAILED));
PostClientCallback(callback, net::ERR_FAILED);
return;
@@ -745,13 +747,10 @@ void SimpleEntryImpl::CreateEntryInternal(bool have_index,
entry_hash_,
have_index,
results.get());
- Closure reply = base::Bind(&SimpleEntryImpl::CreationOperationComplete,
- this,
- callback,
- start_time,
- base::Passed(&results),
- out_entry,
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CREATE_END);
+ Closure reply =
+ base::Bind(&SimpleEntryImpl::CreationOperationComplete, this, callback,
+ start_time, base::Passed(&results), out_entry,
+ net::NetLogEventType::SIMPLE_CACHE_ENTRY_CREATE_END);
worker_pool_->PostTaskAndReply(FROM_HERE, task, reply);
}
@@ -761,7 +760,7 @@ void SimpleEntryImpl::CloseInternal() {
std::unique_ptr<std::vector<CRCRecord>> crc32s_to_write(
new std::vector<CRCRecord>());
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CLOSE_BEGIN);
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_CLOSE_BEGIN);
if (state_ == STATE_READY) {
DCHECK(synchronous_entry_);
@@ -811,10 +810,9 @@ void SimpleEntryImpl::ReadDataInternal(int stream_index,
ScopedOperationRunner operation_runner(this);
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_BEGIN,
- CreateNetLogReadWriteDataCallback(stream_index, offset, buf_len,
- false));
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_READ_BEGIN,
+ CreateNetLogReadWriteDataCallback(stream_index, offset,
+ buf_len, false));
}
if (state_ == STATE_FAILURE || state_ == STATE_UNINITIALIZED) {
@@ -827,9 +825,8 @@ void SimpleEntryImpl::ReadDataInternal(int stream_index,
FROM_HERE, base::Bind(callback, net::ERR_FAILED));
}
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_END,
- CreateNetLogReadWriteCompleteCallback(net::ERR_FAILED));
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_READ_END,
+ CreateNetLogReadWriteCompleteCallback(net::ERR_FAILED));
}
return;
}
@@ -889,18 +886,16 @@ void SimpleEntryImpl::WriteDataInternal(int stream_index,
ScopedOperationRunner operation_runner(this);
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_BEGIN,
- CreateNetLogReadWriteDataCallback(stream_index, offset, buf_len,
- truncate));
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_WRITE_BEGIN,
+ CreateNetLogReadWriteDataCallback(stream_index, offset,
+ buf_len, truncate));
}
if (state_ == STATE_FAILURE || state_ == STATE_UNINITIALIZED) {
RecordWriteResult(cache_type_, WRITE_RESULT_BAD_STATE);
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_END,
- CreateNetLogReadWriteCompleteCallback(net::ERR_FAILED));
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_WRITE_END,
+ CreateNetLogReadWriteCompleteCallback(net::ERR_FAILED));
}
if (!callback.is_null()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -985,7 +980,7 @@ void SimpleEntryImpl::ReadSparseDataInternal(
if (net_log_.IsCapturing()) {
net_log_.AddEvent(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_SPARSE_BEGIN,
+ net::NetLogEventType::SIMPLE_CACHE_ENTRY_READ_SPARSE_BEGIN,
CreateNetLogSparseOperationCallback(sparse_offset, buf_len));
}
@@ -1017,7 +1012,7 @@ void SimpleEntryImpl::WriteSparseDataInternal(
if (net_log_.IsCapturing()) {
net_log_.AddEvent(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_SPARSE_BEGIN,
+ net::NetLogEventType::SIMPLE_CACHE_ENTRY_WRITE_SPARSE_BEGIN,
CreateNetLogSparseOperationCallback(sparse_offset, buf_len));
}
@@ -1110,7 +1105,7 @@ void SimpleEntryImpl::CreationOperationComplete(
const base::TimeTicks& start_time,
std::unique_ptr<SimpleEntryCreationResults> in_results,
Entry** out_entry,
- net::NetLog::EventType end_event_type) {
+ net::NetLogEventType end_event_type) {
DCHECK(io_thread_checker_.CalledOnValidThread());
DCHECK_EQ(state_, STATE_IO_PENDING);
DCHECK(in_results);
@@ -1214,7 +1209,8 @@ void SimpleEntryImpl::ReadOperationComplete(
// entry has a single reader, the normal pattern is to read from start
// to finish.
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CHECKSUM_BEGIN);
+ net_log_.AddEvent(
+ net::NetLogEventType::SIMPLE_CACHE_ENTRY_CHECKSUM_BEGIN);
std::unique_ptr<int> new_result(new int());
Closure task = base::Bind(&SimpleSynchronousEntry::CheckEOFRecord,
@@ -1247,9 +1243,8 @@ void SimpleEntryImpl::ReadOperationComplete(
}
}
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_END,
- CreateNetLogReadWriteCompleteCallback(*result));
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_READ_END,
+ CreateNetLogReadWriteCompleteCallback(*result));
}
EntryOperationComplete(completion_callback, *entry_stat, std::move(result));
@@ -1265,8 +1260,8 @@ void SimpleEntryImpl::WriteOperationComplete(
else
RecordWriteResult(cache_type_, WRITE_RESULT_SYNC_WRITE_FAILURE);
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_END,
- CreateNetLogReadWriteCompleteCallback(*result));
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_WRITE_END,
+ CreateNetLogReadWriteCompleteCallback(*result));
}
if (*result < 0) {
@@ -1285,7 +1280,7 @@ void SimpleEntryImpl::ReadSparseOperationComplete(
DCHECK(result);
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_SPARSE_END,
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_READ_SPARSE_END,
CreateNetLogReadWriteCompleteCallback(*result));
}
@@ -1303,7 +1298,7 @@ void SimpleEntryImpl::WriteSparseOperationComplete(
DCHECK(result);
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_WRITE_SPARSE_END,
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_WRITE_SPARSE_END,
CreateNetLogReadWriteCompleteCallback(*result));
}
@@ -1327,7 +1322,7 @@ void SimpleEntryImpl::DoomOperationComplete(
State state_to_restore,
int result) {
state_ = state_to_restore;
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_DOOM_END);
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_DOOM_END);
PostClientCallback(callback, result);
RunNextOperationIfNeeded();
if (backend_)
@@ -1346,8 +1341,7 @@ void SimpleEntryImpl::ChecksumOperationComplete(
if (net_log_.IsCapturing()) {
net_log_.AddEventWithNetErrorCode(
- net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CHECKSUM_END,
- *result);
+ net::NetLogEventType::SIMPLE_CACHE_ENTRY_CHECKSUM_END, *result);
}
if (*result == net::OK) {
@@ -1360,8 +1354,8 @@ void SimpleEntryImpl::ChecksumOperationComplete(
RecordReadResult(cache_type_, READ_RESULT_SYNC_CHECKSUM_FAILURE);
}
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_READ_END,
- CreateNetLogReadWriteCompleteCallback(*result));
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_READ_END,
+ CreateNetLogReadWriteCompleteCallback(*result));
}
SimpleEntryStat entry_stat(last_used_, last_modified_, data_size_,
@@ -1374,7 +1368,7 @@ void SimpleEntryImpl::CloseOperationComplete() {
DCHECK_EQ(0, open_count_);
DCHECK(STATE_IO_PENDING == state_ || STATE_FAILURE == state_ ||
STATE_UNINITIALIZED == state_);
- net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CLOSE_END);
+ net_log_.AddEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY_CLOSE_END);
AdjustOpenEntryCountBy(cache_type_, -1);
MakeUninitialized();
RunNextOperationIfNeeded();
@@ -1392,8 +1386,10 @@ void SimpleEntryImpl::UpdateDataFromEntryStat(
data_size_[i] = entry_stat.data_size(i);
}
sparse_data_size_ = entry_stat.sparse_data_size();
- if (!doomed_ && backend_.get())
- backend_->index()->UpdateEntrySize(entry_hash_, GetDiskUsage());
+ if (!doomed_ && backend_.get()) {
+ backend_->index()->UpdateEntrySize(
+ entry_hash_, base::checked_cast<uint32_t>(GetDiskUsage()));
+ }
}
int64_t SimpleEntryImpl::GetDiskUsage() const {
diff --git a/chromium/net/disk_cache/simple/simple_entry_impl.h b/chromium/net/disk_cache/simple/simple_entry_impl.h
index 3a0317c0ddb..7df3f4f0eb3 100644
--- a/chromium/net/disk_cache/simple/simple_entry_impl.h
+++ b/chromium/net/disk_cache/simple/simple_entry_impl.h
@@ -19,7 +19,8 @@
#include "net/disk_cache/disk_cache.h"
#include "net/disk_cache/simple/simple_entry_format.h"
#include "net/disk_cache/simple/simple_entry_operation.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
namespace base {
class TaskRunner;
@@ -28,6 +29,7 @@ class TaskRunner;
namespace net {
class GrowableIOBuffer;
class IOBuffer;
+class NetLog;
}
namespace disk_cache {
@@ -226,7 +228,7 @@ class NET_EXPORT_PRIVATE SimpleEntryImpl : public Entry,
const base::TimeTicks& start_time,
std::unique_ptr<SimpleEntryCreationResults> in_results,
Entry** out_entry,
- net::NetLog::EventType end_event_type);
+ net::NetLogEventType end_event_type);
// Called after we've closed and written the EOF record to our entry. Until
// this point it hasn't been safe to OpenEntry() the same entry, but from this
@@ -368,7 +370,7 @@ class NET_EXPORT_PRIVATE SimpleEntryImpl : public Entry,
std::queue<SimpleEntryOperation> pending_operations_;
- net::BoundNetLog net_log_;
+ net::NetLogWithSource net_log_;
std::unique_ptr<SimpleEntryOperation> executing_operation_;
diff --git a/chromium/net/disk_cache/simple/simple_entry_operation.h b/chromium/net/disk_cache/simple/simple_entry_operation.h
index a9b3a0fb1f5..7582addf11c 100644
--- a/chromium/net/disk_cache/simple/simple_entry_operation.h
+++ b/chromium/net/disk_cache/simple/simple_entry_operation.h
@@ -9,7 +9,6 @@
#include "base/memory/ref_counted.h"
#include "net/base/completion_callback.h"
-#include "net/log/net_log.h"
namespace net {
class IOBuffer;
diff --git a/chromium/net/disk_cache/simple/simple_index.cc b/chromium/net/disk_cache/simple/simple_index.cc
index be3208b74a7..e68e7468f20 100644
--- a/chromium/net/disk_cache/simple/simple_index.cc
+++ b/chromium/net/disk_cache/simple/simple_index.cc
@@ -83,9 +83,9 @@ EntryMetadata::EntryMetadata()
entry_size_(0) {
}
-EntryMetadata::EntryMetadata(base::Time last_used_time, uint64_t entry_size)
- : last_used_time_seconds_since_epoch_(0),
- entry_size_(base::checked_cast<int32_t>(entry_size)) {
+EntryMetadata::EntryMetadata(base::Time last_used_time,
+ base::StrictNumeric<uint32_t> entry_size)
+ : last_used_time_seconds_since_epoch_(0), entry_size_(entry_size) {
SetLastUsedTime(last_used_time);
}
@@ -112,12 +112,12 @@ void EntryMetadata::SetLastUsedTime(const base::Time& last_used_time) {
last_used_time_seconds_since_epoch_ = 1;
}
-uint64_t EntryMetadata::GetEntrySize() const {
+uint32_t EntryMetadata::GetEntrySize() const {
return entry_size_;
}
-void EntryMetadata::SetEntrySize(uint64_t entry_size) {
- entry_size_ = base::checked_cast<int32_t>(entry_size);
+void EntryMetadata::SetEntrySize(base::StrictNumeric<uint32_t> entry_size) {
+ entry_size_ = entry_size;
}
void EntryMetadata::Serialize(base::Pickle* pickle) const {
@@ -132,11 +132,10 @@ bool EntryMetadata::Deserialize(base::PickleIterator* it) {
int64_t tmp_last_used_time;
uint64_t tmp_entry_size;
if (!it->ReadInt64(&tmp_last_used_time) || !it->ReadUInt64(&tmp_entry_size) ||
- tmp_entry_size >
- static_cast<uint64_t>(std::numeric_limits<int32_t>::max()))
+ tmp_entry_size > std::numeric_limits<decltype(entry_size_)>::max())
return false;
SetLastUsedTime(base::Time::FromInternalValue(tmp_last_used_time));
- entry_size_ = static_cast<int32_t>(tmp_entry_size);
+ entry_size_ = static_cast<uint32_t>(tmp_entry_size);
return true;
}
@@ -254,8 +253,8 @@ void SimpleIndex::Insert(uint64_t entry_hash) {
// Upon insert we don't know yet the size of the entry.
// It will be updated later when the SimpleEntryImpl finishes opening or
// creating the new entry, and then UpdateEntrySize will be called.
- InsertInEntrySet(
- entry_hash, EntryMetadata(base::Time::Now(), 0), &entries_set_);
+ InsertInEntrySet(entry_hash, EntryMetadata(base::Time::Now(), 0u),
+ &entries_set_);
if (!initialized_)
removed_entries_.erase(entry_hash);
PostponeWritingToDisk();
@@ -265,7 +264,7 @@ void SimpleIndex::Remove(uint64_t entry_hash) {
DCHECK(io_thread_checker_.CalledOnValidThread());
EntrySet::iterator it = entries_set_.find(entry_hash);
if (it != entries_set_.end()) {
- UpdateEntryIteratorSize(&it, 0);
+ UpdateEntryIteratorSize(&it, 0u);
entries_set_.erase(it);
}
@@ -342,7 +341,8 @@ void SimpleIndex::StartEvictionIfNeeded() {
AsWeakPtr()));
}
-bool SimpleIndex::UpdateEntrySize(uint64_t entry_hash, int64_t entry_size) {
+bool SimpleIndex::UpdateEntrySize(uint64_t entry_hash,
+ base::StrictNumeric<uint32_t> entry_size) {
DCHECK(io_thread_checker_.CalledOnValidThread());
EntrySet::iterator it = entries_set_.find(entry_hash);
if (it == entries_set_.end())
@@ -387,13 +387,14 @@ void SimpleIndex::PostponeWritingToDisk() {
FROM_HERE, base::TimeDelta::FromMilliseconds(delay), write_to_disk_cb_);
}
-void SimpleIndex::UpdateEntryIteratorSize(EntrySet::iterator* it,
- int64_t entry_size) {
+void SimpleIndex::UpdateEntryIteratorSize(
+ EntrySet::iterator* it,
+ base::StrictNumeric<uint32_t> entry_size) {
// Update the total cache size with the new entry size.
DCHECK(io_thread_checker_.CalledOnValidThread());
DCHECK_GE(cache_size_, (*it)->second.GetEntrySize());
cache_size_ -= (*it)->second.GetEntrySize();
- cache_size_ += entry_size;
+ cache_size_ += static_cast<uint32_t>(entry_size);
(*it)->second.SetEntrySize(entry_size);
}
@@ -440,6 +441,20 @@ void SimpleIndex::MergeInitializingSet(
SIMPLE_CACHE_UMA(CUSTOM_COUNTS,
"IndexInitializationWaiters", cache_type_,
to_run_when_initialized_.size(), 0, 100, 20);
+ SIMPLE_CACHE_UMA(CUSTOM_COUNTS, "IndexNumEntriesOnInit", cache_type_,
+ entries_set_.size(), 0, 100000, 50);
+ SIMPLE_CACHE_UMA(
+ MEMORY_KB, "CacheSizeOnInit", cache_type_,
+ static_cast<base::HistogramBase::Sample>(cache_size_ / kBytesInKb));
+ SIMPLE_CACHE_UMA(
+ MEMORY_KB, "MaxCacheSizeOnInit", cache_type_,
+ static_cast<base::HistogramBase::Sample>(max_size_ / kBytesInKb));
+ if (max_size_ > 0) {
+ SIMPLE_CACHE_UMA(PERCENTAGE, "PercentFullOnInit", cache_type_,
+ static_cast<base::HistogramBase::Sample>(
+ (cache_size_ * 100) / max_size_));
+ }
+
// Run all callbacks waiting for the index to come up.
for (CallbackList::iterator it = to_run_when_initialized_.begin(),
end = to_run_when_initialized_.end(); it != end; ++it) {
diff --git a/chromium/net/disk_cache/simple/simple_index.h b/chromium/net/disk_cache/simple/simple_index.h
index 724891bfaeb..fee2a1e93e0 100644
--- a/chromium/net/disk_cache/simple/simple_index.h
+++ b/chromium/net/disk_cache/simple/simple_index.h
@@ -18,6 +18,7 @@
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/numerics/safe_conversions.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
@@ -44,13 +45,14 @@ struct SimpleIndexLoadResult;
class NET_EXPORT_PRIVATE EntryMetadata {
public:
EntryMetadata();
- EntryMetadata(base::Time last_used_time, uint64_t entry_size);
+ EntryMetadata(base::Time last_used_time,
+ base::StrictNumeric<uint32_t> entry_size);
base::Time GetLastUsedTime() const;
void SetLastUsedTime(const base::Time& last_used_time);
- uint64_t GetEntrySize() const;
- void SetEntrySize(uint64_t entry_size);
+ uint32_t GetEntrySize() const;
+ void SetEntrySize(base::StrictNumeric<uint32_t> entry_size);
// Serialize the data into the provided pickle.
void Serialize(base::Pickle* pickle) const;
@@ -71,7 +73,7 @@ class NET_EXPORT_PRIVATE EntryMetadata {
// are originally calculated as >32-bit types, the actual necessary size for
// each shouldn't exceed 32 bits, so we use 32-bit types here.
uint32_t last_used_time_seconds_since_epoch_;
- int32_t entry_size_; // Storage size in bytes.
+ uint32_t entry_size_; // Storage size in bytes.
};
static_assert(sizeof(EntryMetadata) == 8, "incorrect metadata size");
@@ -124,7 +126,8 @@ class NET_EXPORT_PRIVATE SimpleIndex
// Update the size (in bytes) of an entry, in the metadata stored in the
// index. This should be the total disk-file size including all streams of the
// entry.
- bool UpdateEntrySize(uint64_t entry_hash, int64_t entry_size);
+ bool UpdateEntrySize(uint64_t entry_hash,
+ base::StrictNumeric<uint32_t> entry_size);
using EntrySet = std::unordered_map<uint64_t, EntryMetadata>;
@@ -169,7 +172,8 @@ class NET_EXPORT_PRIVATE SimpleIndex
void PostponeWritingToDisk();
- void UpdateEntryIteratorSize(EntrySet::iterator* it, int64_t entry_size);
+ void UpdateEntryIteratorSize(EntrySet::iterator* it,
+ base::StrictNumeric<uint32_t> entry_size);
// Must run on IO Thread.
void MergeInitializingSet(std::unique_ptr<SimpleIndexLoadResult> load_result);
diff --git a/chromium/net/disk_cache/simple/simple_index_file.cc b/chromium/net/disk_cache/simple/simple_index_file.cc
index 99eafc36fe2..7925a7adc33 100644
--- a/chromium/net/disk_cache/simple/simple_index_file.cc
+++ b/chromium/net/disk_cache/simple/simple_index_file.cc
@@ -152,16 +152,17 @@ void ProcessEntryFile(SimpleIndex::EntrySet* entries,
if (last_used_time.is_null())
last_used_time = file_info.last_modified;
- int64_t file_size = file_info.size;
SimpleIndex::EntrySet::iterator it = entries->find(hash_key);
+ base::CheckedNumeric<uint32_t> total_entry_size = file_info.size;
+
if (it == entries->end()) {
SimpleIndex::InsertInEntrySet(
- hash_key,
- EntryMetadata(last_used_time, file_size),
+ hash_key, EntryMetadata(last_used_time, total_entry_size.ValueOrDie()),
entries);
} else {
// Summing up the total size of the entry through all the *_[0-1] files
- it->second.SetEntrySize(it->second.GetEntrySize() + file_size);
+ total_entry_size += it->second.GetEntrySize();
+ it->second.SetEntrySize(total_entry_size.ValueOrDie());
}
}
diff --git a/chromium/net/disk_cache/simple/simple_index_file_unittest.cc b/chromium/net/disk_cache/simple/simple_index_file_unittest.cc
index 187ef7796a3..ab626b222df 100644
--- a/chromium/net/disk_cache/simple/simple_index_file_unittest.cc
+++ b/chromium/net/disk_cache/simple/simple_index_file_unittest.cc
@@ -28,8 +28,12 @@
#include "net/disk_cache/simple/simple_index.h"
#include "net/disk_cache/simple/simple_util.h"
#include "net/disk_cache/simple/simple_version_upgrade.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsOk;
+
using base::Time;
using disk_cache::SimpleIndexFile;
using disk_cache::SimpleIndex;
@@ -166,7 +170,9 @@ TEST_F(SimpleIndexFileTest, Serialize) {
static_cast<uint64_t>(kNumHashes), 456);
for (size_t i = 0; i < kNumHashes; ++i) {
uint64_t hash = kHashes[i];
- metadata_entries[i] = EntryMetadata(Time(), hash);
+ // TODO(eroman): Should restructure the test so no casting here (and same
+ // elsewhere where a hash is cast to an entry size).
+ metadata_entries[i] = EntryMetadata(Time(), static_cast<uint32_t>(hash));
SimpleIndex::InsertInEntrySet(hash, metadata_entries[i], &entries);
}
@@ -197,7 +203,7 @@ TEST_F(SimpleIndexFileTest, LegacyIsIndexFileStale) {
base::ScopedTempDir cache_dir;
ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
base::Time cache_mtime;
- const base::FilePath cache_path = cache_dir.path();
+ const base::FilePath cache_path = cache_dir.GetPath();
ASSERT_TRUE(simple_util::GetMTime(cache_path, &cache_mtime));
WrappedSimpleIndexFile simple_index_file(cache_path);
@@ -236,14 +242,14 @@ TEST_F(SimpleIndexFileTest, WriteThenLoadIndex) {
EntryMetadata metadata_entries[kNumHashes];
for (size_t i = 0; i < kNumHashes; ++i) {
uint64_t hash = kHashes[i];
- metadata_entries[i] = EntryMetadata(Time(), hash);
+ metadata_entries[i] = EntryMetadata(Time(), static_cast<uint32_t>(hash));
SimpleIndex::InsertInEntrySet(hash, metadata_entries[i], &entries);
}
const uint64_t kCacheSize = 456U;
net::TestClosure closure;
{
- WrappedSimpleIndexFile simple_index_file(cache_dir.path());
+ WrappedSimpleIndexFile simple_index_file(cache_dir.GetPath());
simple_index_file.WriteToDisk(SimpleIndex::INDEX_WRITE_REASON_SHUTDOWN,
entries, kCacheSize, base::TimeTicks(), false,
closure.closure());
@@ -251,9 +257,9 @@ TEST_F(SimpleIndexFileTest, WriteThenLoadIndex) {
EXPECT_TRUE(base::PathExists(simple_index_file.GetIndexFilePath()));
}
- WrappedSimpleIndexFile simple_index_file(cache_dir.path());
+ WrappedSimpleIndexFile simple_index_file(cache_dir.GetPath());
base::Time fake_cache_mtime;
- ASSERT_TRUE(simple_util::GetMTime(cache_dir.path(), &fake_cache_mtime));
+ ASSERT_TRUE(simple_util::GetMTime(cache_dir.GetPath(), &fake_cache_mtime));
SimpleIndexLoadResult load_index_result;
simple_index_file.LoadIndexEntries(fake_cache_mtime, closure.closure(),
&load_index_result);
@@ -272,7 +278,7 @@ TEST_F(SimpleIndexFileTest, LoadCorruptIndex) {
base::ScopedTempDir cache_dir;
ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
- WrappedSimpleIndexFile simple_index_file(cache_dir.path());
+ WrappedSimpleIndexFile simple_index_file(cache_dir.GetPath());
ASSERT_TRUE(simple_index_file.CreateIndexFileDirectory());
const base::FilePath& index_path = simple_index_file.GetIndexFilePath();
const std::string kDummyData = "nothing to be seen here";
@@ -298,7 +304,7 @@ TEST_F(SimpleIndexFileTest, LoadCorruptIndex) {
TEST_F(SimpleIndexFileTest, SimpleCacheUpgrade) {
base::ScopedTempDir cache_dir;
ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
- const base::FilePath cache_path = cache_dir.path();
+ const base::FilePath cache_path = cache_dir.GetPath();
// Write an old fake index file.
base::File file(cache_path.AppendASCII("index"),
@@ -333,9 +339,9 @@ TEST_F(SimpleIndexFileTest, SimpleCacheUpgrade) {
cache_thread.task_runner().get(), NULL);
net::TestCompletionCallback cb;
int rv = simple_cache->Init(cb.callback());
- EXPECT_EQ(net::OK, cb.GetResult(rv));
+ EXPECT_THAT(cb.GetResult(rv), IsOk());
rv = simple_cache->index()->ExecuteWhenReady(cb.callback());
- EXPECT_EQ(net::OK, cb.GetResult(rv));
+ EXPECT_THAT(cb.GetResult(rv), IsOk());
delete simple_cache;
// The backend flushes the index on destruction and does so on the cache
@@ -368,7 +374,7 @@ TEST_F(SimpleIndexFileTest, SimpleCacheUpgrade) {
TEST_F(SimpleIndexFileTest, OverwritesStaleTempFile) {
base::ScopedTempDir cache_dir;
ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
- const base::FilePath cache_path = cache_dir.path();
+ const base::FilePath cache_path = cache_dir.GetPath();
WrappedSimpleIndexFile simple_index_file(cache_path);
ASSERT_TRUE(simple_index_file.CreateIndexFileDirectory());
@@ -383,7 +389,7 @@ TEST_F(SimpleIndexFileTest, OverwritesStaleTempFile) {
// Write the index file.
SimpleIndex::EntrySet entries;
- SimpleIndex::InsertInEntrySet(11, EntryMetadata(Time(), 11), &entries);
+ SimpleIndex::InsertInEntrySet(11, EntryMetadata(Time(), 11u), &entries);
net::TestClosure closure;
simple_index_file.WriteToDisk(SimpleIndex::INDEX_WRITE_REASON_SHUTDOWN,
entries, 120U, base::TimeTicks(), false,
diff --git a/chromium/net/disk_cache/simple/simple_index_unittest.cc b/chromium/net/disk_cache/simple/simple_index_unittest.cc
index 1b0aee75235..9f7d4094e10 100644
--- a/chromium/net/disk_cache/simple/simple_index_unittest.cc
+++ b/chromium/net/disk_cache/simple/simple_index_unittest.cc
@@ -30,7 +30,7 @@ namespace {
const base::Time kTestLastUsedTime =
base::Time::UnixEpoch() + base::TimeDelta::FromDays(20);
-const uint64_t kTestEntrySize = 789;
+const uint32_t kTestEntrySize = 789;
} // namespace
@@ -143,7 +143,8 @@ class SimpleIndexTest : public testing::Test, public SimpleIndexDelegate {
base::Time last_used_time,
int entry_size) {
index_file_->load_result()->entries.insert(std::make_pair(
- hash_key, EntryMetadata(last_used_time, entry_size)));
+ hash_key, EntryMetadata(last_used_time,
+ base::checked_cast<uint32_t>(entry_size))));
}
void ReturnIndexFile() {
@@ -219,11 +220,11 @@ TEST_F(EntryMetadataTest, Serialize) {
TEST_F(SimpleIndexTest, IndexSizeCorrectOnMerge) {
index()->SetMaxSize(100);
index()->Insert(hashes_.at<2>());
- index()->UpdateEntrySize(hashes_.at<2>(), 2);
+ index()->UpdateEntrySize(hashes_.at<2>(), 2u);
index()->Insert(hashes_.at<3>());
- index()->UpdateEntrySize(hashes_.at<3>(), 3);
+ index()->UpdateEntrySize(hashes_.at<3>(), 3u);
index()->Insert(hashes_.at<4>());
- index()->UpdateEntrySize(hashes_.at<4>(), 4);
+ index()->UpdateEntrySize(hashes_.at<4>(), 4u);
EXPECT_EQ(9U, index()->cache_size_);
{
std::unique_ptr<SimpleIndexLoadResult> result(new SimpleIndexLoadResult());
@@ -236,10 +237,10 @@ TEST_F(SimpleIndexTest, IndexSizeCorrectOnMerge) {
result->did_load = true;
const uint64_t new_hash_key = hashes_.at<11>();
result->entries.insert(
- std::make_pair(new_hash_key, EntryMetadata(base::Time::Now(), 11)));
+ std::make_pair(new_hash_key, EntryMetadata(base::Time::Now(), 11u)));
const uint64_t redundant_hash_key = hashes_.at<4>();
- result->entries.insert(std::make_pair(redundant_hash_key,
- EntryMetadata(base::Time::Now(), 4)));
+ result->entries.insert(std::make_pair(
+ redundant_hash_key, EntryMetadata(base::Time::Now(), 4u)));
index()->MergeInitializingSet(std::move(result));
}
EXPECT_EQ(2U + 3U + 4U + 11U, index()->cache_size_);
@@ -541,7 +542,7 @@ TEST_F(SimpleIndexTest, BasicEviction) {
now - base::TimeDelta::FromDays(2),
475u);
index()->Insert(hashes_.at<2>());
- index()->UpdateEntrySize(hashes_.at<2>(), 475);
+ index()->UpdateEntrySize(hashes_.at<2>(), 475u);
ReturnIndexFile();
WaitForTimeChange();
@@ -558,7 +559,7 @@ TEST_F(SimpleIndexTest, BasicEviction) {
// TODO(rdsmith): This is dependent on the innards of the implementation
// as to at exactly what point we trigger eviction. Not sure how to fix
// that.
- index()->UpdateEntrySize(hashes_.at<3>(), 475);
+ index()->UpdateEntrySize(hashes_.at<3>(), 475u);
EXPECT_EQ(1, doom_entries_calls());
EXPECT_EQ(1, index()->GetEntryCount());
EXPECT_FALSE(index()->Has(hashes_.at<1>()));
@@ -585,7 +586,7 @@ TEST_F(SimpleIndexTest, DiskWriteQueued) {
EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
index()->write_to_disk_timer_.Stop();
- index()->UpdateEntrySize(kHash1, 20);
+ index()->UpdateEntrySize(kHash1, 20u);
EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
index()->write_to_disk_timer_.Stop();
@@ -602,7 +603,7 @@ TEST_F(SimpleIndexTest, DiskWriteExecuted) {
const uint64_t kHash1 = hashes_.at<1>();
index()->Insert(kHash1);
- index()->UpdateEntrySize(kHash1, 20);
+ index()->UpdateEntrySize(kHash1, 20u);
EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
base::Closure user_task(index()->write_to_disk_timer_.user_task());
index()->write_to_disk_timer_.Stop();
@@ -630,7 +631,7 @@ TEST_F(SimpleIndexTest, DiskWritePostponed) {
EXPECT_FALSE(index()->write_to_disk_timer_.IsRunning());
index()->Insert(hashes_.at<1>());
- index()->UpdateEntrySize(hashes_.at<1>(), 20);
+ index()->UpdateEntrySize(hashes_.at<1>(), 20u);
EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
base::TimeTicks expected_trigger(
index()->write_to_disk_timer_.desired_run_time());
@@ -638,7 +639,7 @@ TEST_F(SimpleIndexTest, DiskWritePostponed) {
WaitForTimeChange();
EXPECT_EQ(expected_trigger, index()->write_to_disk_timer_.desired_run_time());
index()->Insert(hashes_.at<2>());
- index()->UpdateEntrySize(hashes_.at<2>(), 40);
+ index()->UpdateEntrySize(hashes_.at<2>(), 40u);
EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
EXPECT_LT(expected_trigger, index()->write_to_disk_timer_.desired_run_time());
index()->write_to_disk_timer_.Stop();
diff --git a/chromium/net/disk_cache/simple/simple_net_log_parameters.cc b/chromium/net/disk_cache/simple/simple_net_log_parameters.cc
index fe565ef91da..f39a11210db 100644
--- a/chromium/net/disk_cache/simple/simple_net_log_parameters.cc
+++ b/chromium/net/disk_cache/simple/simple_net_log_parameters.cc
@@ -14,6 +14,7 @@
#include "base/values.h"
#include "net/base/net_errors.h"
#include "net/disk_cache/simple/simple_entry_impl.h"
+#include "net/log/net_log_capture_mode.h"
namespace {
@@ -41,13 +42,13 @@ std::unique_ptr<base::Value> NetLogSimpleEntryCreationCallback(
namespace disk_cache {
-net::NetLog::ParametersCallback CreateNetLogSimpleEntryConstructionCallback(
+net::NetLogParametersCallback CreateNetLogSimpleEntryConstructionCallback(
const SimpleEntryImpl* entry) {
DCHECK(entry);
return base::Bind(&NetLogSimpleEntryConstructionCallback, entry);
}
-net::NetLog::ParametersCallback CreateNetLogSimpleEntryCreationCallback(
+net::NetLogParametersCallback CreateNetLogSimpleEntryCreationCallback(
const SimpleEntryImpl* entry,
int net_error) {
DCHECK(entry);
diff --git a/chromium/net/disk_cache/simple/simple_net_log_parameters.h b/chromium/net/disk_cache/simple/simple_net_log_parameters.h
index a8e46ecf244..ac9d003650a 100644
--- a/chromium/net/disk_cache/simple/simple_net_log_parameters.h
+++ b/chromium/net/disk_cache/simple/simple_net_log_parameters.h
@@ -5,7 +5,7 @@
#ifndef NET_DISK_CACHE_SIMPLE_NET_LOG_PARAMETERS_H_
#define NET_DISK_CACHE_SIMPLE_NET_LOG_PARAMETERS_H_
-#include "net/log/net_log.h"
+#include "net/log/net_log_parameters_callback.h"
// This file augments the functions in net/disk_cache/net_log_parameters.h to
// include ones that deal with specifics of the Simple Cache backend.
@@ -16,14 +16,14 @@ class SimpleEntryImpl;
// Creates a NetLog callback that returns parameters for the construction of a
// SimpleEntryImpl. Contains the entry's hash. |entry| can't be NULL and must
// outlive the returned callback.
-net::NetLog::ParametersCallback CreateNetLogSimpleEntryConstructionCallback(
+net::NetLogParametersCallback CreateNetLogSimpleEntryConstructionCallback(
const SimpleEntryImpl* entry);
// Creates a NetLog callback that returns parameters for the result of calling
// |CreateEntry| or |OpenEntry| on a SimpleEntryImpl. Contains the |net_error|
// and, if successful, the entry's key. |entry| can't be NULL and must outlive
// the returned callback.
-net::NetLog::ParametersCallback CreateNetLogSimpleEntryCreationCallback(
+net::NetLogParametersCallback CreateNetLogSimpleEntryCreationCallback(
const SimpleEntryImpl* entry,
int net_error);
diff --git a/chromium/net/disk_cache/simple/simple_version_upgrade_unittest.cc b/chromium/net/disk_cache/simple/simple_version_upgrade_unittest.cc
index 4aef6f1b4d4..8f11eab4ed7 100644
--- a/chromium/net/disk_cache/simple/simple_version_upgrade_unittest.cc
+++ b/chromium/net/disk_cache/simple/simple_version_upgrade_unittest.cc
@@ -47,7 +47,7 @@ bool WriteFakeIndexFileV5(const base::FilePath& cache_path) {
TEST(SimpleVersionUpgradeTest, FailsToMigrateBackwards) {
base::ScopedTempDir cache_dir;
ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
- const base::FilePath cache_path = cache_dir.path();
+ const base::FilePath cache_path = cache_dir.GetPath();
disk_cache::FakeIndexData data;
data.version = 100500;
@@ -58,13 +58,13 @@ TEST(SimpleVersionUpgradeTest, FailsToMigrateBackwards) {
ASSERT_EQ(static_cast<int>(sizeof(data)),
base::WriteFile(file_name, reinterpret_cast<const char*>(&data),
sizeof(data)));
- EXPECT_FALSE(disk_cache::UpgradeSimpleCacheOnDisk(cache_dir.path()));
+ EXPECT_FALSE(disk_cache::UpgradeSimpleCacheOnDisk(cache_dir.GetPath()));
}
TEST(SimpleVersionUpgradeTest, FakeIndexVersionGetsUpdated) {
base::ScopedTempDir cache_dir;
ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
- const base::FilePath cache_path = cache_dir.path();
+ const base::FilePath cache_path = cache_dir.GetPath();
WriteFakeIndexFileV5(cache_path);
const std::string file_contents("incorrectly serialized data");
@@ -91,7 +91,7 @@ TEST(SimpleVersionUpgradeTest, FakeIndexVersionGetsUpdated) {
TEST(SimpleVersionUpgradeTest, UpgradeV5V6IndexMustDisappear) {
base::ScopedTempDir cache_dir;
ASSERT_TRUE(cache_dir.CreateUniqueTempDir());
- const base::FilePath cache_path = cache_dir.path();
+ const base::FilePath cache_path = cache_dir.GetPath();
WriteFakeIndexFileV5(cache_path);
const std::string file_contents("incorrectly serialized data");
diff --git a/chromium/net/dns/address_sorter_posix.cc b/chromium/net/dns/address_sorter_posix.cc
index 38a7d74ddb9..730fb4fb23a 100644
--- a/chromium/net/dns/address_sorter_posix.cc
+++ b/chromium/net/dns/address_sorter_posix.cc
@@ -23,6 +23,7 @@
#include "base/logging.h"
#include "net/base/net_errors.h"
+#include "net/log/net_log_source.h"
#include "net/socket/client_socket_factory.h"
#include "net/udp/datagram_client_socket.h"
@@ -269,7 +270,7 @@ void AddressSorterPosix::Sort(const AddressList& list,
std::unique_ptr<DatagramClientSocket> socket(
socket_factory_->CreateDatagramClientSocket(
DatagramSocket::DEFAULT_BIND, RandIntCallback(), NULL /* NetLog */,
- NetLog::Source()));
+ NetLogSource()));
// Even though no packets are sent, cannot use port 0 in Connect.
IPEndPoint dest(info->address, 80 /* port */);
diff --git a/chromium/net/dns/address_sorter_posix_unittest.cc b/chromium/net/dns/address_sorter_posix_unittest.cc
index 997ac483dcd..203f76f0a52 100644
--- a/chromium/net/dns/address_sorter_posix_unittest.cc
+++ b/chromium/net/dns/address_sorter_posix_unittest.cc
@@ -10,6 +10,7 @@
#include "net/base/ip_address.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/socket_performance_watcher.h"
#include "net/socket/ssl_client_socket.h"
@@ -47,6 +48,7 @@ class TestUDPClientSocket : public DatagramClientSocket {
}
int SetReceiveBufferSize(int32_t) override { return OK; }
int SetSendBufferSize(int32_t) override { return OK; }
+ int SetDoNotFragment() override { return OK; }
void Close() override {}
int GetPeerAddress(IPEndPoint* address) const override {
@@ -59,6 +61,7 @@ class TestUDPClientSocket : public DatagramClientSocket {
*address = local_endpoint_;
return OK;
}
+ void UseNonBlockingIO() override {}
int ConnectUsingNetwork(NetworkChangeNotifier::NetworkHandle network,
const IPEndPoint& address) override {
NOTIMPLEMENTED();
@@ -83,10 +86,10 @@ class TestUDPClientSocket : public DatagramClientSocket {
return OK;
}
- const BoundNetLog& NetLog() const override { return net_log_; }
+ const NetLogWithSource& NetLog() const override { return net_log_; }
private:
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
const AddressMapping* mapping_;
bool connected_;
IPEndPoint local_endpoint_;
@@ -104,7 +107,7 @@ class TestSocketFactory : public ClientSocketFactory {
DatagramSocket::BindType,
const RandIntCallback&,
NetLog*,
- const NetLog::Source&) override {
+ const NetLogSource&) override {
return std::unique_ptr<DatagramClientSocket>(
new TestUDPClientSocket(&mapping_));
}
@@ -112,7 +115,7 @@ class TestSocketFactory : public ClientSocketFactory {
const AddressList&,
std::unique_ptr<SocketPerformanceWatcher>,
NetLog*,
- const NetLog::Source&) override {
+ const NetLogSource&) override {
NOTIMPLEMENTED();
return std::unique_ptr<StreamSocket>();
}
diff --git a/chromium/net/dns/dns_client.cc b/chromium/net/dns/dns_client.cc
index 274cefa19d0..109c3af1e69 100644
--- a/chromium/net/dns/dns_client.cc
+++ b/chromium/net/dns/dns_client.cc
@@ -14,9 +14,12 @@
#include "net/dns/dns_session.h"
#include "net/dns/dns_socket_pool.h"
#include "net/dns/dns_transaction.h"
-#include "net/log/net_log.h"
#include "net/socket/client_socket_factory.h"
+namespace base {
+class Value;
+}
+
namespace net {
namespace {
@@ -56,6 +59,18 @@ class DnsClientImpl : public DnsClient {
AddressSorter* GetAddressSorter() override { return address_sorter_.get(); }
+ std::unique_ptr<const base::Value> GetPersistentData() const override {
+ if (!session_)
+ return std::unique_ptr<const base::Value>();
+ return session_->GetPersistentData();
+ }
+
+ void ApplyPersistentData(const base::Value& data) override {
+ if (!session_)
+ return;
+ session_->ApplyPersistentData(data);
+ }
+
private:
scoped_refptr<DnsSession> session_;
std::unique_ptr<DnsTransactionFactory> factory_;
diff --git a/chromium/net/dns/dns_client.h b/chromium/net/dns/dns_client.h
index bb63aaa5411..303d68e6775 100644
--- a/chromium/net/dns/dns_client.h
+++ b/chromium/net/dns/dns_client.h
@@ -7,6 +7,7 @@
#include <memory>
+#include "base/values.h"
#include "net/base/net_export.h"
#include "net/base/rand_callback.h"
@@ -38,6 +39,13 @@ class NET_EXPORT DnsClient {
// Returns NULL if the current config is not valid.
virtual AddressSorter* GetAddressSorter() = 0;
+ // Does nothing if the current config is not valid.
+ virtual void ApplyPersistentData(const base::Value& data) = 0;
+
+ // Returns std::unique_ptr<const Value>(NULL) if the current config is not
+ // valid.
+ virtual std::unique_ptr<const base::Value> GetPersistentData() const = 0;
+
// Creates default client.
static std::unique_ptr<DnsClient> CreateClient(NetLog* net_log);
diff --git a/chromium/net/dns/dns_config_service_posix_unittest.cc b/chromium/net/dns/dns_config_service_posix_unittest.cc
index 88448b16567..35fcbab3500 100644
--- a/chromium/net/dns/dns_config_service_posix_unittest.cc
+++ b/chromium/net/dns/dns_config_service_posix_unittest.cc
@@ -4,8 +4,12 @@
#include <resolv.h>
+#include <memory>
+
#include "base/cancelable_callback.h"
#include "base/files/file_util.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
#include "base/sys_byteorder.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
@@ -207,7 +211,7 @@ class DnsConfigServicePosixTest : public testing::Test {
void OnConfigChanged(const DnsConfig& config) {
EXPECT_TRUE(config.IsValid());
seen_config_ = true;
- base::MessageLoop::current()->QuitWhenIdle();
+ run_loop_->QuitWhenIdle();
}
void WriteMockHostsFile(const char* hosts_string) {
@@ -266,7 +270,8 @@ class DnsConfigServicePosixTest : public testing::Test {
void ExpectChange() {
EXPECT_FALSE(seen_config_);
- base::MessageLoop::current()->Run();
+ run_loop_ = base::MakeUnique<base::RunLoop>();
+ run_loop_->Run();
EXPECT_TRUE(seen_config_);
seen_config_ = false;
}
@@ -276,6 +281,7 @@ class DnsConfigServicePosixTest : public testing::Test {
base::FilePath temp_file_;
std::unique_ptr<DnsConfigServicePosix> service_;
DnsConfig test_config_;
+ std::unique_ptr<base::RunLoop> run_loop_;
};
TEST_F(DnsConfigServicePosixTest, SeenChangeSinceNetworkChange) {
diff --git a/chromium/net/dns/dns_hosts.cc b/chromium/net/dns/dns_hosts.cc
index 098c6172511..568a9ce5558 100644
--- a/chromium/net/dns/dns_hosts.cc
+++ b/chromium/net/dns/dns_hosts.cc
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
+#include "net/dns/dns_util.h"
using base::StringPiece;
@@ -155,6 +156,8 @@ void ParseHostsWithCommaMode(const std::string& contents,
}
} else {
DnsHostsKey key(parser.token().as_string(), family);
+ if (!IsValidDNSDomain(key.first))
+ continue;
key.first = base::ToLowerASCII(key.first);
IPAddress* mapped_ip = &(*dns_hosts)[key];
if (mapped_ip->empty())
diff --git a/chromium/net/dns/dns_hosts_unittest.cc b/chromium/net/dns/dns_hosts_unittest.cc
index 9e52f0e229a..72722017206 100644
--- a/chromium/net/dns/dns_hosts_unittest.cc
+++ b/chromium/net/dns/dns_hosts_unittest.cc
@@ -48,22 +48,26 @@ TEST(DnsHostsTest, ParseHosts) {
"256.0.0.0 cache3 # bogus IP should not clear parsed IP cache\n"
"127.0.0.1 cache4 # should still be reused\n"
"127.0.0.2 cache5\n"
+ "127.0.0.3 .foo # entries with leading dot are ignored\n"
+ "127.0.0.3 . # just a dot is ignored\n"
+ "127.0.0.4 bar. # trailing dot is allowed, for now\n"
"gibberish";
const ExpectedHostsEntry kEntries[] = {
- { "localhost", ADDRESS_FAMILY_IPV4, "127.0.0.1" },
- { "localhost.localdomain", ADDRESS_FAMILY_IPV4, "127.0.0.1" },
- { "company", ADDRESS_FAMILY_IPV4, "1.0.0.1" },
- { "localhost", ADDRESS_FAMILY_IPV6, "::1" },
- { "ip6-localhost", ADDRESS_FAMILY_IPV6, "::1" },
- { "ip6-loopback", ADDRESS_FAMILY_IPV6, "::1" },
- { "ip6-localnet", ADDRESS_FAMILY_IPV6, "fe00::0" },
- { "company", ADDRESS_FAMILY_IPV6, "2048::1" },
- { "example", ADDRESS_FAMILY_IPV6, "2048::2" },
- { "cache1", ADDRESS_FAMILY_IPV4, "127.0.0.1" },
- { "cache2", ADDRESS_FAMILY_IPV4, "127.0.0.1" },
- { "cache4", ADDRESS_FAMILY_IPV4, "127.0.0.1" },
- { "cache5", ADDRESS_FAMILY_IPV4, "127.0.0.2" },
+ {"localhost", ADDRESS_FAMILY_IPV4, "127.0.0.1"},
+ {"localhost.localdomain", ADDRESS_FAMILY_IPV4, "127.0.0.1"},
+ {"company", ADDRESS_FAMILY_IPV4, "1.0.0.1"},
+ {"localhost", ADDRESS_FAMILY_IPV6, "::1"},
+ {"ip6-localhost", ADDRESS_FAMILY_IPV6, "::1"},
+ {"ip6-loopback", ADDRESS_FAMILY_IPV6, "::1"},
+ {"ip6-localnet", ADDRESS_FAMILY_IPV6, "fe00::0"},
+ {"company", ADDRESS_FAMILY_IPV6, "2048::1"},
+ {"example", ADDRESS_FAMILY_IPV6, "2048::2"},
+ {"cache1", ADDRESS_FAMILY_IPV4, "127.0.0.1"},
+ {"cache2", ADDRESS_FAMILY_IPV4, "127.0.0.1"},
+ {"cache4", ADDRESS_FAMILY_IPV4, "127.0.0.1"},
+ {"cache5", ADDRESS_FAMILY_IPV4, "127.0.0.2"},
+ {"bar.", ADDRESS_FAMILY_IPV4, "127.0.0.4"},
};
DnsHosts expected_hosts, actual_hosts;
diff --git a/chromium/net/dns/dns_session.cc b/chromium/net/dns/dns_session.cc
index 82b947e12f7..b022907c4db 100644
--- a/chromium/net/dns/dns_session.cc
+++ b/chromium/net/dns/dns_session.cc
@@ -19,11 +19,15 @@
#include "base/rand_util.h"
#include "base/stl_util.h"
#include "base/time/time.h"
+#include "base/values.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/dns/dns_config_service.h"
#include "net/dns/dns_socket_pool.h"
#include "net/dns/dns_util.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/stream_socket.h"
#include "net/udp/datagram_client_socket.h"
@@ -109,8 +113,8 @@ DnsSession::DnsSession(const DnsConfig& config,
net_log_(net_log),
server_index_(0) {
socket_pool_->Initialize(&config_.nameservers, net_log);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "AsyncDNS.ServerCount", config_.nameservers.size(), 0, 10, 11);
+ UMA_HISTOGRAM_CUSTOM_COUNTS("AsyncDNS.ServerCount",
+ config_.nameservers.size(), 1, 10, 11);
UpdateTimeouts(NetworkChangeNotifier::GetConnectionType());
InitializeServerStats();
NetworkChangeNotifier::AddConnectionTypeObserver(this);
@@ -132,8 +136,8 @@ void DnsSession::UpdateTimeouts(NetworkChangeNotifier::ConnectionType type) {
void DnsSession::InitializeServerStats() {
server_stats_.clear();
for (size_t i = 0; i < config_.nameservers.size(); ++i) {
- server_stats_.push_back(base::WrapUnique(
- new ServerStats(initial_timeout_, rtt_buckets_.Pointer())));
+ server_stats_.push_back(base::MakeUnique<ServerStats>(
+ initial_timeout_, rtt_buckets_.Pointer()));
}
}
@@ -187,8 +191,8 @@ unsigned DnsSession::NextGoodServerIndex(unsigned server_index) {
}
void DnsSession::RecordServerFailure(unsigned server_index) {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "AsyncDNS.ServerFailureIndex", server_index, 0, 10, 11);
+ UMA_HISTOGRAM_CUSTOM_COUNTS("AsyncDNS.ServerFailureIndex", server_index, 1,
+ 10, 11);
++(server_stats_[server_index]->last_failure_count);
server_stats_[server_index]->last_failure = base::Time::Now();
}
@@ -269,14 +273,14 @@ base::TimeDelta DnsSession::NextTimeout(unsigned server_index, int attempt) {
// Allocate a socket, already connected to the server address.
std::unique_ptr<DnsSession::SocketLease> DnsSession::AllocateSocket(
unsigned server_index,
- const NetLog::Source& source) {
+ const NetLogSource& source) {
std::unique_ptr<DatagramClientSocket> socket;
socket = socket_pool_->AllocateSocket(server_index);
if (!socket.get())
return std::unique_ptr<SocketLease>();
- socket->NetLog().BeginEvent(NetLog::TYPE_SOCKET_IN_USE,
+ socket->NetLog().BeginEvent(NetLogEventType::SOCKET_IN_USE,
source.ToEventParametersCallback());
SocketLease* lease = new SocketLease(this, server_index, std::move(socket));
@@ -285,16 +289,22 @@ std::unique_ptr<DnsSession::SocketLease> DnsSession::AllocateSocket(
std::unique_ptr<StreamSocket> DnsSession::CreateTCPSocket(
unsigned server_index,
- const NetLog::Source& source) {
+ const NetLogSource& source) {
return socket_pool_->CreateTCPSocket(server_index, source);
}
+void DnsSession::ApplyPersistentData(const base::Value& data) {}
+
+std::unique_ptr<const base::Value> DnsSession::GetPersistentData() const {
+ return std::unique_ptr<const base::Value>();
+}
+
// Release a socket.
void DnsSession::FreeSocket(unsigned server_index,
std::unique_ptr<DatagramClientSocket> socket) {
DCHECK(socket.get());
- socket->NetLog().EndEvent(NetLog::TYPE_SOCKET_IN_USE);
+ socket->NetLog().EndEvent(NetLogEventType::SOCKET_IN_USE);
socket_pool_->FreeSocket(server_index, std::move(socket));
}
diff --git a/chromium/net/dns/dns_session.h b/chromium/net/dns/dns_session.h
index 43228e4c5f1..1ffa40c219d 100644
--- a/chromium/net/dns/dns_session.h
+++ b/chromium/net/dns/dns_session.h
@@ -31,6 +31,7 @@ namespace net {
class ClientSocketFactory;
class DatagramClientSocket;
class NetLog;
+struct NetLogSource;
class StreamSocket;
// Session parameters and state shared between DNS transactions.
@@ -103,12 +104,15 @@ class NET_EXPORT_PRIVATE DnsSession
// Allocate a socket, already connected to the server address.
// When the SocketLease is destroyed, the socket will be freed.
std::unique_ptr<SocketLease> AllocateSocket(unsigned server_index,
- const NetLog::Source& source);
+ const NetLogSource& source);
// Creates a StreamSocket from the factory for a transaction over TCP. These
// sockets are not pooled.
std::unique_ptr<StreamSocket> CreateTCPSocket(unsigned server_index,
- const NetLog::Source& source);
+ const NetLogSource& source);
+
+ void ApplyPersistentData(const base::Value& data);
+ std::unique_ptr<const base::Value> GetPersistentData() const;
private:
friend class base::RefCounted<DnsSession>;
diff --git a/chromium/net/dns/dns_session_unittest.cc b/chromium/net/dns/dns_session_unittest.cc
index d22a937f784..c75e30e98cb 100644
--- a/chromium/net/dns/dns_session_unittest.cc
+++ b/chromium/net/dns/dns_session_unittest.cc
@@ -14,7 +14,7 @@
#include "net/base/ip_address.h"
#include "net/dns/dns_protocol.h"
#include "net/dns/dns_socket_pool.h"
-#include "net/log/net_log.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/ssl_client_socket.h"
@@ -33,13 +33,13 @@ class TestClientSocketFactory : public ClientSocketFactory {
DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
NetLog* net_log,
- const NetLog::Source& source) override;
+ const NetLogSource& source) override;
std::unique_ptr<StreamSocket> CreateTransportClientSocket(
const AddressList& addresses,
std::unique_ptr<SocketPerformanceWatcher>,
NetLog*,
- const NetLog::Source&) override {
+ const NetLogSource&) override {
NOTIMPLEMENTED();
return std::unique_ptr<StreamSocket>();
}
@@ -79,7 +79,7 @@ class DnsSessionTest : public testing::Test {
DnsConfig config_;
std::unique_ptr<TestClientSocketFactory> test_client_socket_factory_;
scoped_refptr<DnsSession> session_;
- NetLog::Source source_;
+ NetLogSource source_;
private:
bool ExpectEvent(const PoolEvent& event);
@@ -183,7 +183,7 @@ TestClientSocketFactory::CreateDatagramClientSocket(
DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
NetLog* net_log,
- const NetLog::Source& source) {
+ const NetLogSource& source) {
// We're not actually expecting to send or receive any data, so use the
// simplest SocketDataProvider with no data supplied.
SocketDataProvider* data_provider = new StaticSocketDataProvider();
@@ -194,7 +194,7 @@ TestClientSocketFactory::CreateDatagramClientSocket(
}
TestClientSocketFactory::~TestClientSocketFactory() {
- STLDeleteElements(&data_providers_);
+ base::STLDeleteElements(&data_providers_);
}
TEST_F(DnsSessionTest, AllocateFree) {
diff --git a/chromium/net/dns/dns_socket_pool.cc b/chromium/net/dns/dns_socket_pool.cc
index 4017e2a09a8..2d42ad78e4c 100644
--- a/chromium/net/dns/dns_socket_pool.cc
+++ b/chromium/net/dns/dns_socket_pool.cc
@@ -11,6 +11,7 @@
#include "net/base/address_list.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
+#include "net/log/net_log_source.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/stream_socket.h"
#include "net/udp/datagram_client_socket.h"
@@ -59,7 +60,7 @@ void DnsSocketPool::InitializeInternal(
std::unique_ptr<StreamSocket> DnsSocketPool::CreateTCPSocket(
unsigned server_index,
- const NetLog::Source& source) {
+ const NetLogSource& source) {
DCHECK_LT(server_index, nameservers_->size());
return std::unique_ptr<StreamSocket>(
@@ -73,7 +74,7 @@ std::unique_ptr<DatagramClientSocket> DnsSocketPool::CreateConnectedSocket(
std::unique_ptr<DatagramClientSocket> socket;
- NetLog::Source no_source;
+ NetLogSource no_source;
socket = socket_factory_->CreateDatagramClientSocket(
kBindType, rand_int_callback_, net_log_, no_source);
@@ -152,6 +153,8 @@ class DefaultDnsSocketPool : public DnsSocketPool {
DISALLOW_COPY_AND_ASSIGN(DefaultDnsSocketPool);
};
+DnsSocketPool::~DnsSocketPool() {}
+
// static
std::unique_ptr<DnsSocketPool> DnsSocketPool::CreateDefault(
ClientSocketFactory* factory,
@@ -176,7 +179,7 @@ DefaultDnsSocketPool::~DefaultDnsSocketPool() {
unsigned num_servers = pools_.size();
for (unsigned server_index = 0; server_index < num_servers; ++server_index) {
SocketVector& pool = pools_[server_index];
- STLDeleteElements(&pool);
+ base::STLDeleteElements(&pool);
}
}
diff --git a/chromium/net/dns/dns_socket_pool.h b/chromium/net/dns/dns_socket_pool.h
index 973a9508a80..f4f00bba6e4 100644
--- a/chromium/net/dns/dns_socket_pool.h
+++ b/chromium/net/dns/dns_socket_pool.h
@@ -11,7 +11,6 @@
#include "base/macros.h"
#include "net/base/net_export.h"
#include "net/base/rand_callback.h"
-#include "net/log/net_log.h"
namespace net {
@@ -19,6 +18,7 @@ class ClientSocketFactory;
class DatagramClientSocket;
class IPEndPoint;
class NetLog;
+struct NetLogSource;
class StreamSocket;
// A DnsSocketPool is an abstraction layer around a ClientSocketFactory that
@@ -26,7 +26,7 @@ class StreamSocket;
// to DNS servers.
class NET_EXPORT_PRIVATE DnsSocketPool {
public:
- virtual ~DnsSocketPool() { }
+ virtual ~DnsSocketPool();
// Creates a DnsSocketPool that implements the default strategy for managing
// sockets. (This varies by platform; see DnsSocketPoolImpl in
@@ -53,7 +53,7 @@ class NET_EXPORT_PRIVATE DnsSocketPool {
NetLog* net_log) = 0;
// Allocates a socket that is already connected to the nameserver referenced
- // by |server_index|. May return a scoped_ptr to NULL if no sockets are
+ // by |server_index|. May return a std::unique_ptr to NULL if no sockets are
// available to reuse and the factory fails to produce a socket (or produces
// one on which Connect fails).
virtual std::unique_ptr<DatagramClientSocket> AllocateSocket(
@@ -67,7 +67,7 @@ class NET_EXPORT_PRIVATE DnsSocketPool {
// Creates a StreamSocket from the factory for a transaction over TCP. These
// sockets are not pooled.
std::unique_ptr<StreamSocket> CreateTCPSocket(unsigned server_index,
- const NetLog::Source& source);
+ const NetLogSource& source);
protected:
DnsSocketPool(ClientSocketFactory* socket_factory,
@@ -85,7 +85,7 @@ class NET_EXPORT_PRIVATE DnsSocketPool {
private:
ClientSocketFactory* socket_factory_;
- const RandIntCallback& rand_int_callback_;
+ const RandIntCallback rand_int_callback_;
NetLog* net_log_;
const std::vector<IPEndPoint>* nameservers_;
bool initialized_;
diff --git a/chromium/net/dns/dns_test_util.cc b/chromium/net/dns/dns_test_util.cc
index 6f94b7f9e29..24ce6fbb375 100644
--- a/chromium/net/dns/dns_test_util.cc
+++ b/chromium/net/dns/dns_test_util.cc
@@ -171,7 +171,7 @@ class MockTransactionFactory : public DnsTransactionFactory {
const std::string& hostname,
uint16_t qtype,
const DnsTransactionFactory::CallbackType& callback,
- const BoundNetLog&) override {
+ const NetLogWithSource&) override {
MockTransaction* transaction =
new MockTransaction(rules_, hostname, qtype, callback);
if (transaction->delayed())
@@ -221,6 +221,12 @@ AddressSorter* MockDnsClient::GetAddressSorter() {
return address_sorter_.get();
}
+void MockDnsClient::ApplyPersistentData(const base::Value& data) {}
+
+std::unique_ptr<const base::Value> MockDnsClient::GetPersistentData() const {
+ return std::unique_ptr<const base::Value>();
+}
+
void MockDnsClient::CompleteDelayedTransactions() {
factory_->CompleteDelayedTransactions();
}
diff --git a/chromium/net/dns/dns_test_util.h b/chromium/net/dns/dns_test_util.h
index d28c9e44609..21769fc1231 100644
--- a/chromium/net/dns/dns_test_util.h
+++ b/chromium/net/dns/dns_test_util.h
@@ -195,6 +195,8 @@ class MockDnsClient : public DnsClient {
const DnsConfig* GetConfig() const override;
DnsTransactionFactory* GetTransactionFactory() override;
AddressSorter* GetAddressSorter() override;
+ void ApplyPersistentData(const base::Value& data) override;
+ std::unique_ptr<const base::Value> GetPersistentData() const override;
// Completes all DnsTransactions that were delayed by a rule.
void CompleteDelayedTransactions();
diff --git a/chromium/net/dns/dns_transaction.cc b/chromium/net/dns/dns_transaction.cc
index a3aa8e12e67..7d0c044bcac 100644
--- a/chromium/net/dns/dns_transaction.cc
+++ b/chromium/net/dns/dns_transaction.cc
@@ -17,7 +17,7 @@
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/profiler/scoped_tracker.h"
#include "base/rand_util.h"
#include "base/single_thread_task_runner.h"
@@ -38,6 +38,10 @@
#include "net/dns/dns_session.h"
#include "net/dns/dns_util.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/stream_socket.h"
#include "net/udp/datagram_client_socket.h"
@@ -71,7 +75,7 @@ std::unique_ptr<base::Value> NetLogStartCallback(
dict->SetString("hostname", *hostname);
dict->SetInteger("query_type", qtype);
return std::move(dict);
-};
+}
// ----------------------------------------------------------------------------
@@ -96,7 +100,7 @@ class DnsAttempt {
virtual const DnsResponse* GetResponse() const = 0;
// Returns the net log bound to the source of the socket.
- virtual const BoundNetLog& GetSocketNetLog() const = 0;
+ virtual const NetLogWithSource& GetSocketNetLog() const = 0;
// Returns the index of the destination server within DnsConfig::nameservers.
unsigned server_index() const { return server_index_; }
@@ -164,7 +168,7 @@ class DnsUDPAttempt : public DnsAttempt {
return (resp != NULL && resp->IsValid()) ? resp : NULL;
}
- const BoundNetLog& GetSocketNetLog() const override {
+ const NetLogWithSource& GetSocketNetLog() const override {
return socket_lease_->socket()->NetLog();
}
@@ -333,7 +337,7 @@ class DnsTCPAttempt : public DnsAttempt {
return (resp != NULL && resp->IsValid()) ? resp : NULL;
}
- const BoundNetLog& GetSocketNetLog() const override {
+ const NetLogWithSource& GetSocketNetLog() const override {
return socket_->NetLog();
}
@@ -562,7 +566,7 @@ class DnsTransactionImpl : public DnsTransaction,
const std::string& hostname,
uint16_t qtype,
const DnsTransactionFactory::CallbackType& callback,
- const BoundNetLog& net_log)
+ const NetLogWithSource& net_log)
: session_(session),
hostname_(hostname),
qtype_(qtype),
@@ -580,7 +584,7 @@ class DnsTransactionImpl : public DnsTransaction,
~DnsTransactionImpl() override {
if (!callback_.is_null()) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION,
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::DNS_TRANSACTION,
ERR_ABORTED);
} // otherwise logged in DoCallback or Start
}
@@ -598,7 +602,7 @@ class DnsTransactionImpl : public DnsTransaction,
void Start() override {
DCHECK(!callback_.is_null());
DCHECK(attempts_.empty());
- net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION,
+ net_log_.BeginEvent(NetLogEventType::DNS_TRANSACTION,
base::Bind(&NetLogStartCallback, &hostname_, qtype_));
AttemptResult result(PrepareSearch(), NULL);
if (result.rv == OK) {
@@ -634,7 +638,7 @@ class DnsTransactionImpl : public DnsTransaction,
if (!DNSDomainFromDot(hostname_, &labeled_hostname))
return ERR_INVALID_ARGUMENT;
- if (hostname_[hostname_.size() - 1] == '.') {
+ if (hostname_.back() == '.') {
// It's a fully-qualified name, no suffix search.
qnames_.push_back(labeled_hostname);
return OK;
@@ -697,7 +701,8 @@ class DnsTransactionImpl : public DnsTransaction,
DnsTransactionFactory::CallbackType callback = callback_;
callback_.Reset();
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::DNS_TRANSACTION,
+ result.rv);
callback.Run(this, result.rv, response);
}
@@ -736,7 +741,7 @@ class DnsTransactionImpl : public DnsTransaction,
return AttemptResult(ERR_CONNECTION_REFUSED, NULL);
net_log_.AddEvent(
- NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
+ NetLogEventType::DNS_TRANSACTION_ATTEMPT,
attempt->GetSocketNetLog().source().ToEventParametersCallback());
int rv = attempt->Start(
@@ -779,7 +784,7 @@ class DnsTransactionImpl : public DnsTransaction,
had_tcp_attempt_ = true;
net_log_.AddEvent(
- NetLog::TYPE_DNS_TRANSACTION_TCP_ATTEMPT,
+ NetLogEventType::DNS_TRANSACTION_TCP_ATTEMPT,
attempt->GetSocketNetLog().source().ToEventParametersCallback());
int rv = attempt->Start(base::Bind(&DnsTransactionImpl::OnAttemptComplete,
@@ -796,7 +801,7 @@ class DnsTransactionImpl : public DnsTransaction,
// Begins query for the current name. Makes the first attempt.
AttemptResult StartQuery() {
std::string dotted_qname = DNSDomainToString(qnames_.front());
- net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION_QUERY,
+ net_log_.BeginEvent(NetLogEventType::DNS_TRANSACTION_QUERY,
NetLog::StringCallback("qname", &dotted_qname));
first_server_index_ = session_->NextFirstServerIndex();
@@ -856,10 +861,9 @@ class DnsTransactionImpl : public DnsTransaction,
void LogResponse(const DnsAttempt* attempt) {
if (attempt && attempt->GetResponse()) {
- net_log_.AddEvent(
- NetLog::TYPE_DNS_TRANSACTION_RESPONSE,
- base::Bind(&DnsAttempt::NetLogResponseCallback,
- base::Unretained(attempt)));
+ net_log_.AddEvent(NetLogEventType::DNS_TRANSACTION_RESPONSE,
+ base::Bind(&DnsAttempt::NetLogResponseCallback,
+ base::Unretained(attempt)));
}
}
@@ -879,15 +883,15 @@ class DnsTransactionImpl : public DnsTransaction,
switch (result.rv) {
case OK:
session_->RecordServerSuccess(result.attempt->server_index());
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION_QUERY,
- result.rv);
+ net_log_.EndEventWithNetErrorCode(
+ NetLogEventType::DNS_TRANSACTION_QUERY, result.rv);
DCHECK(result.attempt);
DCHECK(result.attempt->GetResponse());
return result;
case ERR_NAME_NOT_RESOLVED:
session_->RecordServerSuccess(result.attempt->server_index());
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION_QUERY,
- result.rv);
+ net_log_.EndEventWithNetErrorCode(
+ NetLogEventType::DNS_TRANSACTION_QUERY, result.rv);
// Try next suffix.
qnames_.pop_front();
if (qnames_.empty()) {
@@ -949,7 +953,7 @@ class DnsTransactionImpl : public DnsTransaction,
// Cleared in DoCallback.
DnsTransactionFactory::CallbackType callback_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
// Search list of fully-qualified DNS names to query next (in DNS format).
std::deque<std::string> qnames_;
@@ -983,7 +987,7 @@ class DnsTransactionFactoryImpl : public DnsTransactionFactory {
const std::string& hostname,
uint16_t qtype,
const CallbackType& callback,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
return std::unique_ptr<DnsTransaction>(new DnsTransactionImpl(
session_.get(), hostname, qtype, callback, net_log));
}
diff --git a/chromium/net/dns/dns_transaction.h b/chromium/net/dns/dns_transaction.h
index fdd05421ccf..f81cc554086 100644
--- a/chromium/net/dns/dns_transaction.h
+++ b/chromium/net/dns/dns_transaction.h
@@ -16,9 +16,9 @@
namespace net {
-class BoundNetLog;
class DnsResponse;
class DnsSession;
+class NetLogWithSource;
// DnsTransaction implements a stub DNS resolver as defined in RFC 1034.
// The DnsTransaction takes care of retransmissions, name server fallback (or
@@ -66,7 +66,7 @@ class NET_EXPORT_PRIVATE DnsTransactionFactory {
const std::string& hostname,
uint16_t qtype,
const CallbackType& callback,
- const BoundNetLog& net_log) WARN_UNUSED_RESULT = 0;
+ const NetLogWithSource& net_log) WARN_UNUSED_RESULT = 0;
// Creates a DnsTransactionFactory which creates DnsTransactionImpl using the
// |session|.
diff --git a/chromium/net/dns/dns_transaction_unittest.cc b/chromium/net/dns/dns_transaction_unittest.cc
index b33c8a65521..9c356a885af 100644
--- a/chromium/net/dns/dns_transaction_unittest.cc
+++ b/chromium/net/dns/dns_transaction_unittest.cc
@@ -24,12 +24,18 @@
#include "net/dns/dns_session.h"
#include "net/dns/dns_test_util.h"
#include "net/dns/dns_util.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/socket_test_util.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsOk;
+
namespace net {
+class NetLog;
+
namespace {
std::string DomainFromDot(const base::StringPiece& dotted) {
@@ -93,8 +99,8 @@ class DnsSocketData {
// Adds pre-built response from |data| buffer.
void AddResponseData(const uint8_t* data, size_t length, IoMode mode) {
CHECK(!provider_.get());
- AddResponse(base::WrapUnique(new DnsResponse(
- reinterpret_cast<const char*>(data), length, 0)),
+ AddResponse(base::MakeUnique<DnsResponse>(
+ reinterpret_cast<const char*>(data), length, 0),
mode);
}
@@ -191,7 +197,7 @@ class TestSocketFactory : public MockClientSocketFactory {
DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
NetLog* net_log,
- const NetLog::Source& source) override {
+ const NetLogSource& source) override {
if (fail_next_socket_) {
fail_next_socket_ = false;
return std::unique_ptr<DatagramClientSocket>(
@@ -248,11 +254,9 @@ class TransactionHelper {
void StartTransaction(DnsTransactionFactory* factory) {
EXPECT_EQ(NULL, transaction_.get());
transaction_ = factory->CreateTransaction(
- hostname_,
- qtype_,
- base::Bind(&TransactionHelper::OnTransactionComplete,
- base::Unretained(this)),
- BoundNetLog());
+ hostname_, qtype_, base::Bind(&TransactionHelper::OnTransactionComplete,
+ base::Unretained(this)),
+ NetLogWithSource());
EXPECT_EQ(hostname_, transaction_->GetHostname());
EXPECT_EQ(qtype_, transaction_->GetType());
transaction_->Start();
@@ -281,7 +285,7 @@ class TransactionHelper {
base::MessageLoop::current()->QuitWhenIdle();
if (expected_answer_count_ >= 0) {
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
ASSERT_TRUE(response != NULL);
EXPECT_EQ(static_cast<unsigned>(expected_answer_count_),
response->answer_count());
@@ -906,9 +910,9 @@ TEST_F(DnsTransactionTest, TCPMalformed) {
// examine the answer section until asked to parse it, so truncating it in
// the answer section would result in the DnsTransaction itself succeeding.
data->AddResponseWithLength(
- base::WrapUnique(
- new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram),
- arraysize(kT0ResponseDatagram), 0)),
+ base::MakeUnique<DnsResponse>(
+ reinterpret_cast<const char*>(kT0ResponseDatagram),
+ arraysize(kT0ResponseDatagram), 0),
ASYNC, static_cast<uint16_t>(kT0QuerySize - 1));
AddSocketData(std::move(data));
@@ -921,8 +925,8 @@ TEST_F(DnsTransactionTest, TCPTimeout) {
ConfigureFactory();
AddAsyncQueryAndRcode(kT0HostName, kT0Qtype,
dns_protocol::kRcodeNOERROR | dns_protocol::kFlagTC);
- AddSocketData(base::WrapUnique(
- new DnsSocketData(1 /* id */, kT0HostName, kT0Qtype, ASYNC, true)));
+ AddSocketData(base::MakeUnique<DnsSocketData>(1 /* id */, kT0HostName,
+ kT0Qtype, ASYNC, true));
TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT);
EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
@@ -935,9 +939,9 @@ TEST_F(DnsTransactionTest, TCPReadReturnsZeroAsync) {
new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true));
// Return all but the last byte of the response.
data->AddResponseWithLength(
- base::WrapUnique(
- new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram),
- arraysize(kT0ResponseDatagram) - 1, 0)),
+ base::MakeUnique<DnsResponse>(
+ reinterpret_cast<const char*>(kT0ResponseDatagram),
+ arraysize(kT0ResponseDatagram) - 1, 0),
ASYNC, static_cast<uint16_t>(arraysize(kT0ResponseDatagram)));
// Then return a 0-length read.
data->AddReadError(0, ASYNC);
@@ -954,9 +958,9 @@ TEST_F(DnsTransactionTest, TCPReadReturnsZeroSynchronous) {
new DnsSocketData(0 /* id */, kT0HostName, kT0Qtype, ASYNC, true));
// Return all but the last byte of the response.
data->AddResponseWithLength(
- base::WrapUnique(
- new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram),
- arraysize(kT0ResponseDatagram) - 1, 0)),
+ base::MakeUnique<DnsResponse>(
+ reinterpret_cast<const char*>(kT0ResponseDatagram),
+ arraysize(kT0ResponseDatagram) - 1, 0),
SYNCHRONOUS, static_cast<uint16_t>(arraysize(kT0ResponseDatagram)));
// Then return a 0-length read.
data->AddReadError(0, SYNCHRONOUS);
diff --git a/chromium/net/dns/dns_util.cc b/chromium/net/dns/dns_util.cc
index 48be035c0e3..217aedc5001 100644
--- a/chromium/net/dns/dns_util.cc
+++ b/chromium/net/dns/dns_util.cc
@@ -83,6 +83,11 @@ bool DNSDomainFromDot(const base::StringPiece& dotted, std::string* out) {
return true;
}
+bool IsValidDNSDomain(const base::StringPiece& dotted) {
+ std::string dns_formatted;
+ return DNSDomainFromDot(dotted, &dns_formatted);
+}
+
std::string DNSDomainToString(const base::StringPiece& domain) {
std::string ret;
diff --git a/chromium/net/dns/dns_util.h b/chromium/net/dns/dns_util.h
index 470242c0ced..c81ffde34ad 100644
--- a/chromium/net/dns/dns_util.h
+++ b/chromium/net/dns/dns_util.h
@@ -24,6 +24,9 @@ class AddressList;
NET_EXPORT_PRIVATE bool DNSDomainFromDot(const base::StringPiece& dotted,
std::string* out);
+// Checks that a hostname is valid. Simple wrapper around DNSDomainFromDot.
+NET_EXPORT_PRIVATE bool IsValidDNSDomain(const base::StringPiece& dotted);
+
// DNSDomainToString converts a domain in DNS format to a dotted string.
// Excludes the dot at the end.
NET_EXPORT_PRIVATE std::string DNSDomainToString(
diff --git a/chromium/net/dns/fuzzed_host_resolver.cc b/chromium/net/dns/fuzzed_host_resolver.cc
index 63248e3cf14..d8e02325206 100644
--- a/chromium/net/dns/fuzzed_host_resolver.cc
+++ b/chromium/net/dns/fuzzed_host_resolver.cc
@@ -14,9 +14,9 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
+#include "base/test/fuzzed_data_provider.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/address_list.h"
-#include "net/base/fuzzed_data_provider.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
@@ -29,19 +29,19 @@ namespace net {
namespace {
// Returns a fuzzed non-zero port number.
-uint16_t FuzzPort(FuzzedDataProvider* data_provider) {
+uint16_t FuzzPort(base::FuzzedDataProvider* data_provider) {
return data_provider->ConsumeUint16();
}
// Returns a fuzzed IPv4 address. Can return invalid / reserved addresses.
-IPAddress FuzzIPv4Address(FuzzedDataProvider* data_provider) {
+IPAddress FuzzIPv4Address(base::FuzzedDataProvider* data_provider) {
return IPAddress(data_provider->ConsumeUint8(), data_provider->ConsumeUint8(),
data_provider->ConsumeUint8(),
data_provider->ConsumeUint8());
}
// Returns a fuzzed IPv6 address. Can return invalid / reserved addresses.
-IPAddress FuzzIPv6Address(FuzzedDataProvider* data_provider) {
+IPAddress FuzzIPv6Address(base::FuzzedDataProvider* data_provider) {
return IPAddress(data_provider->ConsumeUint8(), data_provider->ConsumeUint8(),
data_provider->ConsumeUint8(), data_provider->ConsumeUint8(),
data_provider->ConsumeUint8(), data_provider->ConsumeUint8(),
@@ -55,7 +55,7 @@ IPAddress FuzzIPv6Address(FuzzedDataProvider* data_provider) {
// Returns a fuzzed address, which can be either IPv4 or IPv6. Can return
// invalid / reserved addresses.
-IPAddress FuzzIPAddress(FuzzedDataProvider* data_provider) {
+IPAddress FuzzIPAddress(base::FuzzedDataProvider* data_provider) {
if (data_provider->ConsumeBool())
return FuzzIPv4Address(data_provider);
return FuzzIPv6Address(data_provider);
@@ -69,7 +69,7 @@ class FuzzedHostResolverProc : public HostResolverProc {
// happen if a request is issued but the code never waits for the result
// before the test ends.
explicit FuzzedHostResolverProc(
- base::WeakPtr<FuzzedDataProvider> data_provider)
+ base::WeakPtr<base::FuzzedDataProvider> data_provider)
: HostResolverProc(nullptr),
data_provider_(data_provider),
network_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
@@ -127,7 +127,7 @@ class FuzzedHostResolverProc : public HostResolverProc {
private:
~FuzzedHostResolverProc() override {}
- base::WeakPtr<FuzzedDataProvider> data_provider_;
+ base::WeakPtr<base::FuzzedDataProvider> data_provider_;
// Just used for thread-safety checks.
scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
@@ -139,7 +139,7 @@ class FuzzedHostResolverProc : public HostResolverProc {
FuzzedHostResolver::FuzzedHostResolver(const Options& options,
NetLog* net_log,
- FuzzedDataProvider* data_provider)
+ base::FuzzedDataProvider* data_provider)
: HostResolverImpl(options, net_log, base::ThreadTaskRunnerHandle::Get()),
data_provider_(data_provider),
socket_factory_(data_provider),
@@ -217,13 +217,13 @@ void FuzzedHostResolver::SetDnsClientEnabled(bool enabled) {
std::unique_ptr<DnsClient> dns_client = DnsClient::CreateClientForTesting(
net_log_, &socket_factory_,
- base::Bind(&FuzzedDataProvider::ConsumeInt32InRange,
+ base::Bind(&base::FuzzedDataProvider::ConsumeInt32InRange,
base::Unretained(data_provider_)));
dns_client->SetConfig(config);
SetDnsClient(std::move(dns_client));
}
-bool FuzzedHostResolver::IsIPv6Reachable(const BoundNetLog& net_log) {
+bool FuzzedHostResolver::IsIPv6Reachable(const NetLogWithSource& net_log) {
return is_ipv6_reachable_;
}
diff --git a/chromium/net/dns/fuzzed_host_resolver.h b/chromium/net/dns/fuzzed_host_resolver.h
index 5ce13cb58bb..945225b7a67 100644
--- a/chromium/net/dns/fuzzed_host_resolver.h
+++ b/chromium/net/dns/fuzzed_host_resolver.h
@@ -16,6 +16,10 @@
#include "net/dns/host_resolver_impl.h"
#include "net/socket/fuzzed_socket_factory.h"
+namespace base {
+class FuzzedDataProvider;
+}
+
namespace net {
class AddressList;
@@ -46,7 +50,7 @@ class FuzzedHostResolver : public HostResolverImpl {
// |data_provider| and |net_log| must outlive the FuzzedHostResolver.
FuzzedHostResolver(const Options& options,
NetLog* net_log,
- FuzzedDataProvider* data_provider);
+ base::FuzzedDataProvider* data_provider);
~FuzzedHostResolver() override;
// Enable / disable the async resolver. When enabled, installs a
@@ -56,10 +60,10 @@ class FuzzedHostResolver : public HostResolverImpl {
private:
// HostResolverImpl implementation:
- bool IsIPv6Reachable(const BoundNetLog& net_log) override;
+ bool IsIPv6Reachable(const NetLogWithSource& net_log) override;
void RunLoopbackProbeJob() override;
- FuzzedDataProvider* data_provider_;
+ base::FuzzedDataProvider* data_provider_;
// Used for UDP and TCP sockets if the async resolver is enabled.
FuzzedSocketFactory socket_factory_;
@@ -69,7 +73,7 @@ class FuzzedHostResolver : public HostResolverImpl {
NetLog* net_log_;
- base::WeakPtrFactory<FuzzedDataProvider> data_provider_weak_factory_;
+ base::WeakPtrFactory<base::FuzzedDataProvider> data_provider_weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FuzzedHostResolver);
};
diff --git a/chromium/net/dns/host_cache.cc b/chromium/net/dns/host_cache.cc
index ee3d96215f3..881f5140b6f 100644
--- a/chromium/net/dns/host_cache.cc
+++ b/chromium/net/dns/host_cache.cc
@@ -198,6 +198,28 @@ void HostCache::clear() {
entries_.clear();
}
+void HostCache::ClearForHosts(
+ const base::Callback<bool(const std::string&)>& host_filter) {
+ DCHECK(CalledOnValidThread());
+
+ if (host_filter.is_null()) {
+ clear();
+ return;
+ }
+
+ base::TimeTicks now = base::TimeTicks::Now();
+ for (EntryMap::iterator it = entries_.begin(); it != entries_.end();) {
+ EntryMap::iterator next_it = std::next(it);
+
+ if (host_filter.Run(it->first.hostname)) {
+ RecordErase(ERASE_CLEAR, now, it->second);
+ entries_.erase(it);
+ }
+
+ it = next_it;
+ }
+}
+
size_t HostCache::size() const {
DCHECK(CalledOnValidThread());
return entries_.size();
@@ -234,6 +256,8 @@ void HostCache::EvictOneEntry(base::TimeTicks now) {
oldest_it = it;
}
+ if (!eviction_callback_.is_null())
+ eviction_callback_.Run(oldest_it->first, oldest_it->second);
RecordErase(ERASE_EVICT, now, oldest_it->second);
entries_.erase(oldest_it);
}
diff --git a/chromium/net/dns/host_cache.h b/chromium/net/dns/host_cache.h
index 700d5c2e801..ccda0eb9a92 100644
--- a/chromium/net/dns/host_cache.h
+++ b/chromium/net/dns/host_cache.h
@@ -113,6 +113,7 @@ class NET_EXPORT HostCache : NON_EXPORTED_BASE(public base::NonThreadSafe) {
};
using EntryMap = std::map<Key, Entry>;
+ using EvictionCallback = base::Callback<void(const Key&, const Entry&)>;
// Constructs a HostCache that stores up to |max_entries|.
explicit HostCache(size_t max_entries);
@@ -141,9 +142,17 @@ class NET_EXPORT HostCache : NON_EXPORTED_BASE(public base::NonThreadSafe) {
// Marks all entries as stale on account of a network change.
void OnNetworkChange();
- // Empties the cache
+ void set_eviction_callback(const EvictionCallback& callback) {
+ eviction_callback_ = callback;
+ }
+
+ // Empties the cache.
void clear();
+ // Clears hosts matching |host_filter| from the cache.
+ void ClearForHosts(
+ const base::Callback<bool(const std::string&)>& host_filter);
+
// Returns the number of entries in the cache.
size_t size() const;
@@ -186,6 +195,7 @@ class NET_EXPORT HostCache : NON_EXPORTED_BASE(public base::NonThreadSafe) {
EntryMap entries_;
size_t max_entries_;
int network_changes_;
+ EvictionCallback eviction_callback_;
DISALLOW_COPY_AND_ASSIGN(HostCache);
};
diff --git a/chromium/net/dns/host_cache_unittest.cc b/chromium/net/dns/host_cache_unittest.cc
index c34627b1696..30efd2d3eb9 100644
--- a/chromium/net/dns/host_cache_unittest.cc
+++ b/chromium/net/dns/host_cache_unittest.cc
@@ -4,6 +4,10 @@
#include "net/dns/host_cache.h"
+#include <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
#include "base/format_macros.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
@@ -22,6 +26,10 @@ HostCache::Key Key(const std::string& hostname) {
return HostCache::Key(hostname, ADDRESS_FAMILY_UNSPECIFIED, 0);
}
+bool FoobarIndexIsOdd(const std::string& foobarx_com) {
+ return (foobarx_com[6] - '0') % 2 == 1;
+}
+
} // namespace
TEST(HostCacheTest, Basic) {
@@ -296,6 +304,40 @@ TEST(HostCacheTest, Clear) {
EXPECT_EQ(0u, cache.size());
}
+TEST(HostCacheTest, ClearForHosts) {
+ const base::TimeDelta kTTL = base::TimeDelta::FromSeconds(10);
+
+ HostCache cache(kMaxCacheEntries);
+
+ // Set t=0.
+ base::TimeTicks now;
+
+ HostCache::Entry entry = HostCache::Entry(OK, AddressList());
+
+ EXPECT_EQ(0u, cache.size());
+
+ // Add several entries.
+ cache.Set(Key("foobar1.com"), entry, now, kTTL);
+ cache.Set(Key("foobar2.com"), entry, now, kTTL);
+ cache.Set(Key("foobar3.com"), entry, now, kTTL);
+ cache.Set(Key("foobar4.com"), entry, now, kTTL);
+ cache.Set(Key("foobar5.com"), entry, now, kTTL);
+
+ EXPECT_EQ(5u, cache.size());
+
+ // Clear the hosts matching a certain predicate, such as the number being odd.
+ cache.ClearForHosts(base::Bind(&FoobarIndexIsOdd));
+
+ EXPECT_EQ(2u, cache.size());
+ EXPECT_TRUE(cache.Lookup(Key("foobar2.com"), now));
+ EXPECT_TRUE(cache.Lookup(Key("foobar4.com"), now));
+
+ // Passing null callback will delete all hosts.
+ cache.ClearForHosts(base::Callback<bool(const std::string&)>());
+
+ EXPECT_EQ(0u, cache.size());
+}
+
// Try to add too many entries to cache; it should evict the one with the oldest
// expiration time.
TEST(HostCacheTest, Evict) {
@@ -329,6 +371,57 @@ TEST(HostCacheTest, Evict) {
EXPECT_TRUE(cache.Lookup(key3, now));
}
+void TestEvictionCallback(int* evict_count,
+ HostCache::Key* key_out,
+ const HostCache::Key& key,
+ const HostCache::Entry& entry) {
+ ++*evict_count;
+ *key_out = key;
+}
+
+// Try to add too many entries to cache; it should evict the one with the oldest
+// expiration time.
+TEST(HostCacheTest, EvictWithCallback) {
+ HostCache cache(2);
+
+ int evict_count = 0;
+ HostCache::Key evicted_key = Key("nothingevicted.com");
+ cache.set_eviction_callback(
+ base::Bind(&TestEvictionCallback, &evict_count, &evicted_key));
+
+ base::TimeTicks now;
+
+ HostCache::Key key1 = Key("foobar.com");
+ HostCache::Key key2 = Key("foobar2.com");
+ HostCache::Key key3 = Key("foobar3.com");
+ HostCache::Entry entry = HostCache::Entry(OK, AddressList());
+
+ EXPECT_EQ(0u, cache.size());
+ EXPECT_FALSE(cache.Lookup(key1, now));
+ EXPECT_FALSE(cache.Lookup(key2, now));
+ EXPECT_FALSE(cache.Lookup(key3, now));
+
+ // |key1| expires in 10 seconds, but |key2| in just 5.
+ cache.Set(key1, entry, now, base::TimeDelta::FromSeconds(10));
+ cache.Set(key2, entry, now, base::TimeDelta::FromSeconds(5));
+ EXPECT_EQ(2u, cache.size());
+ EXPECT_TRUE(cache.Lookup(key1, now));
+ EXPECT_TRUE(cache.Lookup(key2, now));
+ EXPECT_FALSE(cache.Lookup(key3, now));
+
+ EXPECT_EQ(0, evict_count);
+
+ // |key2| should be chosen for eviction, since it expires sooner.
+ cache.Set(key3, entry, now, base::TimeDelta::FromSeconds(10));
+ EXPECT_EQ(2u, cache.size());
+ EXPECT_TRUE(cache.Lookup(key1, now));
+ EXPECT_FALSE(cache.Lookup(key2, now));
+ EXPECT_TRUE(cache.Lookup(key3, now));
+
+ EXPECT_EQ(1, evict_count);
+ EXPECT_EQ(key2.hostname, evicted_key.hostname);
+}
+
// Try to retrieve stale entries from the cache. They should be returned by
// |LookupStale()| but not |Lookup()|, with correct |EntryStaleness| data.
TEST(HostCacheTest, Stale) {
diff --git a/chromium/net/dns/host_resolver.cc b/chromium/net/dns/host_resolver.cc
index be393b047e4..df958933d79 100644
--- a/chromium/net/dns/host_resolver.cc
+++ b/chromium/net/dns/host_resolver.cc
@@ -5,6 +5,7 @@
#include "net/dns/host_resolver.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
@@ -91,8 +92,23 @@ HostResolver::Options::Options()
}
HostResolver::RequestInfo::RequestInfo(const HostPortPair& host_port_pair)
- : host_port_pair_(host_port_pair),
- address_family_(ADDRESS_FAMILY_UNSPECIFIED),
+ : RequestInfo() {
+ host_port_pair_ = host_port_pair;
+}
+
+HostResolver::RequestInfo::RequestInfo(const RequestInfo& request_info)
+ : host_port_pair_(request_info.host_port_pair_),
+ address_family_(request_info.address_family_),
+ host_resolver_flags_(request_info.host_resolver_flags_),
+ allow_cached_response_(request_info.allow_cached_response_),
+ is_speculative_(request_info.is_speculative_),
+ is_my_ip_address_(request_info.is_my_ip_address_),
+ cache_hit_callback_(request_info.cache_hit_callback_) {}
+
+HostResolver::RequestInfo::~RequestInfo() {}
+
+HostResolver::RequestInfo::RequestInfo()
+ : address_family_(ADDRESS_FAMILY_UNSPECIFIED),
host_resolver_flags_(0),
allow_cached_response_(true),
is_speculative_(false),
@@ -104,11 +120,6 @@ HostResolver::~HostResolver() {
void HostResolver::SetDnsClientEnabled(bool enabled) {
}
-void HostResolver::ChangeRequestPriority(RequestHandle req,
- RequestPriority priority) {
- NOTIMPLEMENTED();
-}
-
HostCache* HostResolver::GetHostCache() {
return nullptr;
}
@@ -117,21 +128,37 @@ std::unique_ptr<base::Value> HostResolver::GetDnsConfigAsValue() const {
return nullptr;
}
+void HostResolver::InitializePersistence(
+ const PersistCallback& persist_callback,
+ std::unique_ptr<const base::Value> old_data) {}
+
// static
std::unique_ptr<HostResolver> HostResolver::CreateSystemResolver(
const Options& options,
NetLog* net_log) {
- return std::unique_ptr<HostResolver>(new HostResolverImpl(options, net_log));
+ return std::unique_ptr<HostResolver>(
+ CreateSystemResolverImpl(options, net_log).release());
+}
+
+// static
+std::unique_ptr<HostResolverImpl> HostResolver::CreateSystemResolverImpl(
+ const Options& options,
+ NetLog* net_log) {
+ return base::WrapUnique(new HostResolverImpl(options, net_log));
}
// static
std::unique_ptr<HostResolver> HostResolver::CreateDefaultResolver(
NetLog* net_log) {
- return std::unique_ptr<HostResolver>(
- new HostResolverImpl(Options(), net_log));
+ return CreateSystemResolver(Options(), net_log);
}
-HostResolver::HostResolver() {
+// static
+std::unique_ptr<HostResolverImpl> HostResolver::CreateDefaultResolverImpl(
+ NetLog* net_log) {
+ return CreateSystemResolverImpl(Options(), net_log);
}
+HostResolver::HostResolver() {}
+
} // namespace net
diff --git a/chromium/net/dns/host_resolver.h b/chromium/net/dns/host_resolver.h
index 5c371e43ad5..fe38138f5c6 100644
--- a/chromium/net/dns/host_resolver.h
+++ b/chromium/net/dns/host_resolver.h
@@ -27,9 +27,10 @@ class Value;
namespace net {
class AddressList;
-class BoundNetLog;
+class HostResolverImpl;
class HostResolverProc;
class NetLog;
+class NetLogWithSource;
// This class represents the task of resolving hostnames (or IP address
// literal) to an AddressList object.
@@ -42,6 +43,18 @@ class NetLog;
// goes out of scope).
class NET_EXPORT HostResolver {
public:
+ // HostResolver::Request class is used to cancel the request and change it's
+ // priority. It must be owned by consumer. Deletion cancels the request.
+ class Request {
+ public:
+ virtual ~Request() {}
+
+ // Changes the priority of the specified request. Can be called after
+ // Resolve() is called. Can't be called once the request is cancelled or
+ // completed.
+ virtual void ChangeRequestPriority(RequestPriority priority) = 0;
+ };
+
// |max_concurrent_resolves| is how many resolve requests will be allowed to
// run in parallel. Pass HostResolver::kDefaultParallelism to choose a
// default value.
@@ -64,6 +77,8 @@ class NET_EXPORT HostResolver {
class NET_EXPORT RequestInfo {
public:
explicit RequestInfo(const HostPortPair& host_port_pair);
+ RequestInfo(const RequestInfo& request_info);
+ ~RequestInfo();
const HostPortPair& host_port_pair() const { return host_port_pair_; }
void set_host_port_pair(const HostPortPair& host_port_pair) {
@@ -94,7 +109,17 @@ class NET_EXPORT HostResolver {
bool is_my_ip_address() const { return is_my_ip_address_; }
void set_is_my_ip_address(bool b) { is_my_ip_address_ = b; }
+ using CacheHitCallback = base::Callback<void(const RequestInfo&)>;
+ const CacheHitCallback& cache_hit_callback() const {
+ return cache_hit_callback_;
+ }
+ void set_cache_hit_callback(const CacheHitCallback& callback) {
+ cache_hit_callback_ = callback;
+ }
+
private:
+ RequestInfo();
+
// The hostname to resolve, and the port to use in resulting sockaddrs.
HostPortPair host_port_pair_;
@@ -113,10 +138,11 @@ class NET_EXPORT HostResolver {
// Indicates a request for myIpAddress (to differentiate from other requests
// for localhost, currently used by Chrome OS).
bool is_my_ip_address_;
- };
- // Opaque type used to cancel a request.
- typedef void* RequestHandle;
+ // A callback that will be called when another request reads the cache data
+ // returned (and possibly written) by this request.
+ CacheHitCallback cache_hit_callback_;
+ };
// Set Options.max_concurrent_resolves to this to select a default level
// of concurrency.
@@ -143,29 +169,20 @@ class NET_EXPORT HostResolver {
// callback. Otherwise the result code is returned immediately from this
// call.
//
- // If |out_req| is non-NULL, then |*out_req| will be filled with a handle to
- // the async request. This handle is not valid after the request has
- // completed.
+ // [out_req] must be owned by a caller. If the request is not completed
+ // synchronously, it will be filled with a handle to the request. It must be
+ // completed before the HostResolver itself is destroyed.
+ //
+ // Requests can be cancelled any time by deletion of the [out_req]. Deleting
+ // |out_req| will cancel the request, and cause |callback| not to be invoked.
//
// Profiling information for the request is saved to |net_log| if non-NULL.
virtual int Resolve(const RequestInfo& info,
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) = 0;
-
- // Changes the priority of the specified request. |req| is the handle returned
- // by Resolve(). ChangeRequestPriority must NOT be called after the request's
- // completion callback has already run or the request was canceled.
- virtual void ChangeRequestPriority(RequestHandle req,
- RequestPriority priority);
-
- // Cancels the specified request. |req| is the handle returned by Resolve().
- // After a request is canceled, its completion callback will not be called.
- // CancelRequest must NOT be called after the request's completion callback
- // has already run or the request was canceled.
- virtual void CancelRequest(RequestHandle req) = 0;
+ std::unique_ptr<Request>* out_req,
+ const NetLogWithSource& net_log) = 0;
// Resolves the given hostname (or IP address literal) out of cache or HOSTS
// file (if enabled) only. This is guaranteed to complete synchronously.
@@ -173,7 +190,7 @@ class NET_EXPORT HostResolver {
// or HOSTS entry exists. Otherwise, ERR_DNS_CACHE_MISS is returned.
virtual int ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& net_log) = 0;
+ const NetLogWithSource& net_log) = 0;
// Enable or disable the built-in asynchronous DnsClient.
virtual void SetDnsClientEnabled(bool enabled);
@@ -186,15 +203,34 @@ class NET_EXPORT HostResolver {
// nullptr if it's configured to always use the system host resolver.
virtual std::unique_ptr<base::Value> GetDnsConfigAsValue() const;
+ typedef base::Callback<void(std::unique_ptr<const base::Value>)>
+ PersistCallback;
+ // Configures the HostResolver to be able to persist data (e.g. observed
+ // performance) between sessions. |persist_callback| is a callback that will
+ // be called when the HostResolver wants to persist data; |old_data| is the
+ // data last persisted by the resolver on the previous session.
+ virtual void InitializePersistence(
+ const PersistCallback& persist_callback,
+ std::unique_ptr<const base::Value> old_data);
+
// Creates a HostResolver implementation that queries the underlying system.
// (Except if a unit-test has changed the global HostResolverProc using
// ScopedHostResolverProc to intercept requests to the system).
static std::unique_ptr<HostResolver> CreateSystemResolver(
const Options& options,
NetLog* net_log);
+ // Same, but explicitly returns the HostResolverImpl. Only used by
+ // StaleHostResolver in cronet.
+ static std::unique_ptr<HostResolverImpl> CreateSystemResolverImpl(
+ const Options& options,
+ NetLog* net_log);
// As above, but uses default parameters.
static std::unique_ptr<HostResolver> CreateDefaultResolver(NetLog* net_log);
+ // Same, but explicitly returns the HostResolverImpl. Only used by
+ // StaleHostResolver in cronet.
+ static std::unique_ptr<HostResolverImpl> CreateDefaultResolverImpl(
+ NetLog* net_log);
protected:
HostResolver();
diff --git a/chromium/net/dns/host_resolver_impl.cc b/chromium/net/dns/host_resolver_impl.cc
index dc280656c05..4a5be1834ff 100644
--- a/chromium/net/dns/host_resolver_impl.cc
+++ b/chromium/net/dns/host_resolver_impl.cc
@@ -4,11 +4,6 @@
#include "net/dns/host_resolver_impl.h"
-#include <memory>
-#include <utility>
-
-#include "base/memory/ptr_util.h"
-
#if defined(OS_WIN)
#include <Winsock2.h>
#elif defined(OS_POSIX)
@@ -16,12 +11,14 @@
#endif
#include <cmath>
+#include <memory>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/compiler_specific.h"
#include "base/debug/debugger.h"
#include "base/debug/leak_annotations.h"
@@ -58,6 +55,12 @@
#include "net/dns/dns_util.h"
#include "net/dns/host_resolver_proc.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_parameters_callback.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/client_socket_factory.h"
#include "net/udp/datagram_client_socket.h"
#include "url/url_canon_ip.h"
@@ -195,7 +198,7 @@ bool ResemblesMulticastDNSName(const std::string& hostname) {
const char kSuffix[] = ".local.";
const size_t kSuffixLen = sizeof(kSuffix) - 1;
const size_t kSuffixLenTrimmed = kSuffixLen - 1;
- if (hostname[hostname.size() - 1] == '.') {
+ if (hostname.back() == '.') {
return hostname.size() > kSuffixLen &&
!hostname.compare(hostname.size() - kSuffixLen, kSuffixLen, kSuffix);
}
@@ -205,7 +208,8 @@ bool ResemblesMulticastDNSName(const std::string& hostname) {
}
// Attempts to connect a UDP socket to |dest|:53.
-bool IsGloballyReachable(const IPAddress& dest, const BoundNetLog& net_log) {
+bool IsGloballyReachable(const IPAddress& dest,
+ const NetLogWithSource& net_log) {
// TODO(eroman): Remove ScopedTracker below once crbug.com/455942 is fixed.
tracked_objects::ScopedTracker tracking_profile_1(
FROM_HERE_WITH_EXPLICIT_FUNCTION("455942 IsGloballyReachable"));
@@ -367,10 +371,10 @@ std::unique_ptr<base::Value> NetLogDnsTaskFailedCallback(
if (dns_error)
dict->SetInteger("dns_error", dns_error);
return std::move(dict);
-};
+}
// Creates NetLog parameters containing the information in a RequestInfo object,
-// along with the associated NetLog::Source.
+// along with the associated NetLogSource.
std::unique_ptr<base::Value> NetLogRequestInfoCallback(
const HostResolver::RequestInfo* info,
NetLogCaptureMode /* capture_mode */) {
@@ -386,7 +390,7 @@ std::unique_ptr<base::Value> NetLogRequestInfoCallback(
// Creates NetLog parameters for the creation of a HostResolverImpl::Job.
std::unique_ptr<base::Value> NetLogJobCreationCallback(
- const NetLog::Source& source,
+ const NetLogSource& source,
const std::string* host,
NetLogCaptureMode /* capture_mode */) {
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
@@ -397,7 +401,7 @@ std::unique_ptr<base::Value> NetLogJobCreationCallback(
// Creates NetLog parameters for HOST_RESOLVER_IMPL_JOB_ATTACH/DETACH events.
std::unique_ptr<base::Value> NetLogJobAttachCallback(
- const NetLog::Source& source,
+ const NetLogSource& source,
RequestPriority priority,
NetLogCaptureMode /* capture_mode */) {
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
@@ -427,26 +431,25 @@ std::unique_ptr<base::Value> NetLogIPv6AvailableCallback(
// without a Request object.
// Logs when a request has just been started.
-void LogStartRequest(const BoundNetLog& source_net_log,
+void LogStartRequest(const NetLogWithSource& source_net_log,
const HostResolver::RequestInfo& info) {
- source_net_log.BeginEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
- base::Bind(&NetLogRequestInfoCallback, &info));
+ source_net_log.BeginEvent(NetLogEventType::HOST_RESOLVER_IMPL_REQUEST,
+ base::Bind(&NetLogRequestInfoCallback, &info));
}
// Logs when a request has just completed (before its callback is run).
-void LogFinishRequest(const BoundNetLog& source_net_log,
+void LogFinishRequest(const NetLogWithSource& source_net_log,
const HostResolver::RequestInfo& info,
int net_error) {
source_net_log.EndEventWithNetErrorCode(
- NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, net_error);
+ NetLogEventType::HOST_RESOLVER_IMPL_REQUEST, net_error);
}
// Logs when a request has been cancelled.
-void LogCancelRequest(const BoundNetLog& source_net_log,
+void LogCancelRequest(const NetLogWithSource& source_net_log,
const HostResolverImpl::RequestInfo& info) {
- source_net_log.AddEvent(NetLog::TYPE_CANCELLED);
- source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST);
+ source_net_log.AddEvent(NetLogEventType::CANCELLED);
+ source_net_log.EndEvent(NetLogEventType::HOST_RESOLVER_IMPL_REQUEST);
}
//-----------------------------------------------------------------------------
@@ -480,7 +483,8 @@ class PriorityTracker {
--total_count_;
--counts_[req_priority];
size_t i;
- for (i = highest_priority_; i > MINIMUM_PRIORITY && !counts_[i]; --i);
+ for (i = highest_priority_; i > MINIMUM_PRIORITY && !counts_[i]; --i) {
+ }
highest_priority_ = static_cast<RequestPriority>(i);
// In absence of requests, default to MINIMUM_PRIORITY.
@@ -502,6 +506,9 @@ void MakeNotStale(HostCache::EntryStaleness* stale_info) {
stale_info->stale_hits = 0;
}
+// Persist data every five minutes (potentially, cache and learned RTT).
+const int64_t kPersistDelaySec = 300;
+
} // namespace
//-----------------------------------------------------------------------------
@@ -528,46 +535,41 @@ const unsigned HostResolverImpl::kMaximumDnsFailures = 16;
// Holds the data for a request that could not be completed synchronously.
// It is owned by a Job. Canceled Requests are only marked as canceled rather
// than removed from the Job's |requests_| list.
-class HostResolverImpl::Request {
+class HostResolverImpl::RequestImpl : public HostResolver::Request {
public:
- Request(const BoundNetLog& source_net_log,
- const RequestInfo& info,
- RequestPriority priority,
- const CompletionCallback& callback,
- AddressList* addresses)
+ RequestImpl(const NetLogWithSource& source_net_log,
+ const RequestInfo& info,
+ RequestPriority priority,
+ const CompletionCallback& callback,
+ AddressList* addresses,
+ Job* job)
: source_net_log_(source_net_log),
info_(info),
priority_(priority),
- job_(nullptr),
+ job_(job),
callback_(callback),
addresses_(addresses),
request_time_(base::TimeTicks::Now()) {}
- // Mark the request as canceled.
- void MarkAsCanceled() {
+ ~RequestImpl() override;
+
+ void ChangeRequestPriority(RequestPriority priority) override;
+
+ void OnJobCancelled(Job* job) {
+ DCHECK_EQ(job_, job);
job_ = nullptr;
addresses_ = nullptr;
callback_.Reset();
}
- bool was_canceled() const {
- return callback_.is_null();
- }
-
- void set_job(Job* job) {
- DCHECK(job);
- // Identify which job the request is waiting on.
- job_ = job;
- }
-
// Prepare final AddressList and call completion callback.
- void OnComplete(int error, const AddressList& addr_list) {
- DCHECK(!was_canceled());
+ void OnJobCompleted(Job* job, int error, const AddressList& addr_list) {
+ DCHECK_EQ(job_, job);
if (error == OK)
*addresses_ = EnsurePortOnAddressList(addr_list, info_.port());
- CompletionCallback callback = callback_;
- MarkAsCanceled();
- callback.Run(error);
+ job_ = nullptr;
+ addresses_ = nullptr;
+ base::ResetAndReturn(&callback_).Run(error);
}
Job* job() const {
@@ -575,9 +577,7 @@ class HostResolverImpl::Request {
}
// NetLog for the source, passed in HostResolver::Resolve.
- const BoundNetLog& source_net_log() {
- return source_net_log_;
- }
+ const NetLogWithSource& source_net_log() { return source_net_log_; }
const RequestInfo& info() const {
return info_;
@@ -589,7 +589,7 @@ class HostResolverImpl::Request {
base::TimeTicks request_time() const { return request_time_; }
private:
- const BoundNetLog source_net_log_;
+ const NetLogWithSource source_net_log_;
// The request info that started the request.
const RequestInfo info_;
@@ -607,7 +607,7 @@ class HostResolverImpl::Request {
const base::TimeTicks request_time_;
- DISALLOW_COPY_AND_ASSIGN(Request);
+ DISALLOW_COPY_AND_ASSIGN(RequestImpl);
};
//------------------------------------------------------------------------------
@@ -633,7 +633,7 @@ class HostResolverImpl::ProcTask
const ProcTaskParams& params,
const Callback& callback,
scoped_refptr<base::TaskRunner> worker_task_runner,
- const BoundNetLog& job_net_log)
+ const NetLogWithSource& job_net_log)
: key_(key),
params_(params),
callback_(callback),
@@ -653,7 +653,7 @@ class HostResolverImpl::ProcTask
void Start() {
DCHECK(network_task_runner_->BelongsToCurrentThread());
- net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK);
+ net_log_.BeginEvent(NetLogEventType::HOST_RESOLVER_IMPL_PROC_TASK);
StartLookupAttempt();
}
@@ -667,7 +667,7 @@ class HostResolverImpl::ProcTask
return;
callback_.Reset();
- net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK);
+ net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_IMPL_PROC_TASK);
}
void set_had_non_speculative_request() {
@@ -709,7 +709,7 @@ class HostResolverImpl::ProcTask
return;
}
- net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED,
+ net_log_.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_ATTEMPT_STARTED,
NetLog::IntCallback("attempt_number", attempt_number_));
// If the results aren't received within a given time, RetryIfNotComplete
@@ -796,7 +796,7 @@ class HostResolverImpl::ProcTask
if (was_canceled())
return;
- NetLog::ParametersCallback net_log_callback;
+ NetLogParametersCallback net_log_callback;
if (error != OK) {
net_log_callback = base::Bind(&NetLogProcTaskFailedCallback,
attempt_number,
@@ -805,7 +805,7 @@ class HostResolverImpl::ProcTask
} else {
net_log_callback = NetLog::IntCallback("attempt_number", attempt_number);
}
- net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED,
+ net_log_.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_ATTEMPT_FINISHED,
net_log_callback);
if (was_completed())
@@ -828,7 +828,7 @@ class HostResolverImpl::ProcTask
} else {
net_log_callback = results_.CreateNetLogCallback();
}
- net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK,
+ net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_IMPL_PROC_TASK,
net_log_callback);
callback_.Run(error, results_);
@@ -859,7 +859,7 @@ class HostResolverImpl::ProcTask
// Log DNS lookups based on |address_family|. This will help us determine
// if IPv4 or IPv4/6 lookups are faster or slower.
- switch(key_.address_family) {
+ switch (key_.address_family) {
case ADDRESS_FAMILY_IPV4:
DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV4", duration);
break;
@@ -880,7 +880,7 @@ class HostResolverImpl::ProcTask
}
// Log DNS lookups based on |address_family|. This will help us determine
// if IPv4 or IPv4/6 lookups are faster or slower.
- switch(key_.address_family) {
+ switch (key_.address_family) {
case ADDRESS_FAMILY_IPV4:
DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV4", duration);
break;
@@ -992,7 +992,7 @@ class HostResolverImpl::ProcTask
AddressList results_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
DISALLOW_COPY_AND_ASSIGN(ProcTask);
};
@@ -1070,7 +1070,7 @@ class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
DnsTask(DnsClient* client,
const Key& key,
Delegate* delegate,
- const BoundNetLog& job_net_log)
+ const NetLogWithSource& job_net_log)
: client_(client),
key_(key),
delegate_(delegate),
@@ -1091,7 +1091,7 @@ class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
void StartFirstTransaction() {
DCHECK_EQ(0u, num_completed_transactions_);
- net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK);
+ net_log_.BeginEvent(NetLogEventType::HOST_RESOLVER_IMPL_DNS_TASK);
if (key_.address_family == ADDRESS_FAMILY_IPV6) {
StartAAAA();
} else {
@@ -1236,14 +1236,14 @@ class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
void OnFailure(int net_error, DnsResponse::Result result) {
DCHECK_NE(OK, net_error);
net_log_.EndEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
+ NetLogEventType::HOST_RESOLVER_IMPL_DNS_TASK,
base::Bind(&NetLogDnsTaskFailedCallback, net_error, result));
delegate_->OnDnsTaskComplete(task_start_time_, net_error, AddressList(),
base::TimeDelta());
}
void OnSuccess(const AddressList& addr_list) {
- net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
+ net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_IMPL_DNS_TASK,
addr_list.CreateNetLogCallback());
delegate_->OnDnsTaskComplete(task_start_time_, OK, addr_list, ttl_);
}
@@ -1253,7 +1253,7 @@ class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
// The listener to the results of this DnsTask.
Delegate* delegate_;
- const BoundNetLog net_log_;
+ const NetLogWithSource net_log_;
std::unique_ptr<DnsTransaction> transaction_a_;
std::unique_ptr<DnsTransaction> transaction_aaaa_;
@@ -1282,7 +1282,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
const Key& key,
RequestPriority priority,
scoped_refptr<base::TaskRunner> worker_task_runner,
- const BoundNetLog& source_net_log)
+ const NetLogWithSource& source_net_log)
: resolver_(resolver),
key_(key),
priority_tracker_(priority),
@@ -1293,15 +1293,14 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
dns_task_error_(OK),
creation_time_(base::TimeTicks::Now()),
priority_change_time_(creation_time_),
- net_log_(BoundNetLog::Make(source_net_log.net_log(),
- NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
- source_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB);
+ net_log_(
+ NetLogWithSource::Make(source_net_log.net_log(),
+ NetLogSourceType::HOST_RESOLVER_IMPL_JOB)) {
+ source_net_log.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_CREATE_JOB);
- net_log_.BeginEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
- base::Bind(&NetLogJobCreationCallback,
- source_net_log.source(),
- &key_.hostname));
+ net_log_.BeginEvent(NetLogEventType::HOST_RESOLVER_IMPL_JOB,
+ base::Bind(&NetLogJobCreationCallback,
+ source_net_log.source(), &key_.hostname));
}
~Job() override {
@@ -1314,22 +1313,23 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
}
// Clean up now for nice NetLog.
KillDnsTask();
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::HOST_RESOLVER_IMPL_JOB,
ERR_ABORTED);
} else if (is_queued()) {
// |resolver_| was destroyed without running this Job.
// TODO(szym): is there any benefit in having this distinction?
- net_log_.AddEvent(NetLog::TYPE_CANCELLED);
- net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB);
+ net_log_.AddEvent(NetLogEventType::CANCELLED);
+ net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_IMPL_JOB);
}
// else CompleteRequests logged EndEvent.
-
- // Log any remaining Requests as cancelled.
- for (const std::unique_ptr<Request>& req : requests_) {
- if (req->was_canceled())
- continue;
- DCHECK_EQ(this, req->job());
- LogCancelRequest(req->source_net_log(), req->info());
+ if (!requests_.empty()) {
+ // Log any remaining Requests as cancelled.
+ for (RequestImpl* req : requests_) {
+ DCHECK_EQ(this, req->job());
+ LogCancelRequest(req->source_net_log(), req->info());
+ req->OnJobCancelled(this);
+ }
+ requests_.clear();
}
}
@@ -1352,37 +1352,34 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
}
}
- void AddRequest(std::unique_ptr<Request> req) {
- DCHECK_EQ(key_.hostname, req->info().hostname());
+ void AddRequest(RequestImpl* request) {
+ DCHECK_EQ(key_.hostname, request->info().hostname());
- req->set_job(this);
- priority_tracker_.Add(req->priority());
+ priority_tracker_.Add(request->priority());
- req->source_net_log().AddEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
+ request->source_net_log().AddEvent(
+ NetLogEventType::HOST_RESOLVER_IMPL_JOB_ATTACH,
net_log_.source().ToEventParametersCallback());
net_log_.AddEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH,
- base::Bind(&NetLogJobAttachCallback,
- req->source_net_log().source(),
+ NetLogEventType::HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH,
+ base::Bind(&NetLogJobAttachCallback, request->source_net_log().source(),
priority()));
// TODO(szym): Check if this is still needed.
- if (!req->info().is_speculative()) {
+ if (!request->info().is_speculative()) {
had_non_speculative_request_ = true;
if (proc_task_.get())
proc_task_->set_had_non_speculative_request();
}
- requests_.push_back(std::move(req));
+ requests_.push_back(request);
UpdatePriority();
}
- void ChangeRequestPriority(Request* req, RequestPriority priority) {
+ void ChangeRequestPriority(RequestImpl* req, RequestPriority priority) {
DCHECK_EQ(key_.hostname, req->info().hostname());
- DCHECK(!req->was_canceled());
priority_tracker_.Remove(req->priority());
req->set_priority(priority);
@@ -1390,24 +1387,23 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
UpdatePriority();
}
- // Marks |req| as cancelled. If it was the last active Request, also finishes
- // this Job, marking it as cancelled, and deletes it.
- void CancelRequest(Request* req) {
- DCHECK_EQ(key_.hostname, req->info().hostname());
- DCHECK(!req->was_canceled());
+ // Detach cancelled request. If it was the last active Request, also finishes
+ // this Job.
+ void CancelRequest(RequestImpl* request) {
+ DCHECK_EQ(key_.hostname, request->info().hostname());
+ DCHECK(!requests_.empty());
- // Don't remove it from |requests_| just mark it canceled.
- req->MarkAsCanceled();
- LogCancelRequest(req->source_net_log(), req->info());
+ LogCancelRequest(request->source_net_log(), request->info());
- priority_tracker_.Remove(req->priority());
- net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
- base::Bind(&NetLogJobAttachCallback,
- req->source_net_log().source(),
- priority()));
+ priority_tracker_.Remove(request->priority());
+ net_log_.AddEvent(
+ NetLogEventType::HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
+ base::Bind(&NetLogJobAttachCallback, request->source_net_log().source(),
+ priority()));
if (num_active_requests() > 0) {
UpdatePriority();
+ RemoveRequest(request);
} else {
// If we were called from a Request's callback within CompleteRequests,
// that Request could not have been cancelled, so num_active_requests()
@@ -1416,6 +1412,12 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
}
}
+ void RemoveRequest(RequestImpl* request) {
+ auto it = std::find(requests_.begin(), requests_.end(), request);
+ DCHECK(it != requests_.end());
+ requests_.erase(it);
+ }
+
// Called from AbortAllInProgressJobs. Completes all requests and destroys
// the job. This currently assumes the abort is due to a network change.
// TODO This should not delete |this|.
@@ -1440,7 +1442,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
DCHECK(is_queued());
handle_.Reset();
- net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_EVICTED);
+ net_log_.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_JOB_EVICTED);
// This signals to CompleteRequests that this job never ran.
CompleteRequestsWithError(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE);
@@ -1525,7 +1527,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
DCHECK(!is_running());
- net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED);
+ net_log_.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_JOB_STARTED);
had_dns_config_ = resolver_->HaveDnsConfig();
@@ -1686,7 +1688,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
}
DNS_HISTOGRAM("AsyncDNS.ResolveSuccess", duration);
// Log DNS lookups based on |address_family|.
- switch(key_.address_family) {
+ switch (key_.address_family) {
case ADDRESS_FAMILY_IPV4:
DNS_HISTOGRAM("AsyncDNS.ResolveSuccess_FAMILY_IPV4", duration);
break;
@@ -1753,15 +1755,17 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
}
if (num_active_requests() == 0) {
- net_log_.AddEvent(NetLog::TYPE_CANCELLED);
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
+ net_log_.AddEvent(NetLogEventType::CANCELLED);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::HOST_RESOLVER_IMPL_JOB,
OK);
return;
}
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::HOST_RESOLVER_IMPL_JOB,
entry.error());
+ resolver_->SchedulePersist();
+
DCHECK(!requests_.empty());
if (entry.error() == OK) {
@@ -1773,23 +1777,28 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
bool did_complete = (entry.error() != ERR_NETWORK_CHANGED) &&
(entry.error() != ERR_HOST_RESOLVER_QUEUE_TOO_LARGE);
- if (did_complete)
+ if (did_complete) {
resolver_->CacheResult(key_, entry, ttl);
+ // Erase any previous cache hit callbacks, since a new DNS request went
+ // out since they were set.
+ resolver_->cache_hit_callbacks_.erase(key_);
+ }
- // Complete all of the requests that were attached to the job.
- for (const std::unique_ptr<Request>& req : requests_) {
- if (req->was_canceled())
- continue;
-
+ // Complete all of the requests that were attached to the job and
+ // detach them.
+ while (!requests_.empty()) {
+ RequestImpl* req = requests_.front();
+ requests_.pop_front();
DCHECK_EQ(this, req->job());
// Update the net log and notify registered observers.
LogFinishRequest(req->source_net_log(), req->info(), entry.error());
if (did_complete) {
+ resolver_->MaybeAddCacheHitCallback(key_, req->info());
// Record effective total time from creation to completion.
RecordTotalTime(had_dns_config_, req->info().is_speculative(),
base::TimeTicks::Now() - req->request_time());
}
- req->OnComplete(entry.error(), entry.addresses());
+ req->OnJobCompleted(this, entry.error(), entry.addresses());
// Check if the resolver was destroyed as a result of running the
// callback. If it was, we could continue, but we choose to bail.
@@ -1841,7 +1850,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
const base::TimeTicks creation_time_;
base::TimeTicks priority_change_time_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
// Resolves the host using a HostResolverProc.
scoped_refptr<ProcTask> proc_task_;
@@ -1850,7 +1859,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
std::unique_ptr<DnsTask> dns_task_;
// All Requests waiting for the result of this Job. Some can be canceled.
- std::vector<std::unique_ptr<Request>> requests_;
+ std::deque<RequestImpl*> requests_;
// A handle used in |HostResolverImpl::dispatcher_|.
PrioritizedDispatcher::Handle handle_;
@@ -1888,7 +1897,7 @@ HostResolverImpl::~HostResolverImpl() {
dispatcher_->SetLimitsToZero();
// It's now safe for Jobs to call KillDsnTask on destruction, because
// OnJobComplete will not start any new jobs.
- STLDeleteValues(&jobs_);
+ base::STLDeleteValues(&jobs_);
NetworkChangeNotifier::RemoveIPAddressObserver(this);
NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
@@ -1905,15 +1914,15 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& source_net_log) {
+ std::unique_ptr<Request>* out_req,
+ const NetLogWithSource& source_net_log) {
DCHECK(addresses);
DCHECK(CalledOnValidThread());
DCHECK_EQ(false, callback.is_null());
+ DCHECK(out_req);
// Check that the caller supplied a valid hostname to resolve.
- std::string labeled_hostname;
- if (!DNSDomainFromDot(info.hostname(), &labeled_hostname))
+ if (!IsValidDNSDomain(info.hostname()))
return ERR_NAME_NOT_RESOLVED;
LogStartRequest(source_net_log, info);
@@ -1930,6 +1939,7 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
int rv = ResolveHelper(key, info, ip_address_ptr, addresses, false, nullptr,
source_net_log);
if (rv != ERR_DNS_CACHE_MISS) {
+ MaybeAddCacheHitCallback(key, info);
LogFinishRequest(source_net_log, info, rv);
RecordTotalTime(HaveDnsConfig(), info.is_speculative(), base::TimeDelta());
return rv;
@@ -1962,12 +1972,11 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
}
// Can't complete synchronously. Create and attach request.
- std::unique_ptr<Request> req(
- new Request(source_net_log, info, priority, callback, addresses));
- if (out_req)
- *out_req = reinterpret_cast<RequestHandle>(req.get());
+ std::unique_ptr<RequestImpl> req(new RequestImpl(
+ source_net_log, info, priority, callback, addresses, job));
+ job->AddRequest(req.get());
+ *out_req = std::move(req);
- job->AddRequest(std::move(req));
// Completion happens during Job::CompleteRequests().
return ERR_IO_PENDING;
}
@@ -1987,6 +1996,7 @@ HostResolverImpl::HostResolverImpl(
additional_resolver_flags_(0),
fallback_to_proctask_(true),
worker_task_runner_(std::move(worker_task_runner)),
+ persist_initialized_(false),
weak_ptr_factory_(this),
probe_weak_ptr_factory_(this) {
if (options.enable_caching)
@@ -2039,7 +2049,7 @@ int HostResolverImpl::ResolveHelper(const Key& key,
AddressList* addresses,
bool allow_stale,
HostCache::EntryStaleness* stale_info,
- const BoundNetLog& source_net_log) {
+ const NetLogWithSource& source_net_log) {
DCHECK(allow_stale == !!stale_info);
// The result of |getaddrinfo| for empty hosts is inconsistent across systems.
// On Windows it gives the default interface's address, whereas on Linux it
@@ -2056,14 +2066,15 @@ int HostResolverImpl::ResolveHelper(const Key& key,
}
if (ServeFromCache(key, info, &net_error, addresses, allow_stale,
stale_info)) {
- source_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT);
+ source_net_log.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_CACHE_HIT);
// |ServeFromCache()| will set |*stale_info| as needed.
+ RunCacheHitCallbacks(key, info);
return net_error;
}
// TODO(szym): Do not do this if nsswitch.conf instructs not to.
// http://crbug.com/117655
if (ServeFromHosts(key, info, addresses)) {
- source_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT);
+ source_net_log.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_HOSTS_HIT);
MakeNotStale(stale_info);
return OK;
}
@@ -2078,7 +2089,7 @@ int HostResolverImpl::ResolveHelper(const Key& key,
int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& source_net_log) {
+ const NetLogWithSource& source_net_log) {
DCHECK(CalledOnValidThread());
DCHECK(addresses);
@@ -2098,25 +2109,6 @@ int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
return rv;
}
-void HostResolverImpl::ChangeRequestPriority(RequestHandle req_handle,
- RequestPriority priority) {
- DCHECK(CalledOnValidThread());
- Request* req = reinterpret_cast<Request*>(req_handle);
- DCHECK(req);
- Job* job = req->job();
- DCHECK(job);
- job->ChangeRequestPriority(req, priority);
-}
-
-void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
- DCHECK(CalledOnValidThread());
- Request* req = reinterpret_cast<Request*>(req_handle);
- DCHECK(req);
- Job* job = req->job();
- DCHECK(job);
- job->CancelRequest(req);
-}
-
void HostResolverImpl::SetDnsClientEnabled(bool enabled) {
DCHECK(CalledOnValidThread());
#if defined(ENABLE_BUILT_IN_DNS)
@@ -2141,7 +2133,7 @@ std::unique_ptr<base::Value> HostResolverImpl::GetDnsConfigAsValue() const {
// for it.
const DnsConfig* dns_config = dns_client_->GetConfig();
if (!dns_config)
- return base::WrapUnique(new base::DictionaryValue());
+ return base::MakeUnique<base::DictionaryValue>();
return dns_config->ToValue();
}
@@ -2150,7 +2142,7 @@ int HostResolverImpl::ResolveStaleFromCache(
const RequestInfo& info,
AddressList* addresses,
HostCache::EntryStaleness* stale_info,
- const BoundNetLog& source_net_log) {
+ const NetLogWithSource& source_net_log) {
DCHECK(CalledOnValidThread());
DCHECK(addresses);
DCHECK(stale_info);
@@ -2318,7 +2310,7 @@ void HostResolverImpl::RemoveJob(Job* job) {
HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
const RequestInfo& info,
const IPAddress* ip_address,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
HostResolverFlags effective_flags =
info.host_resolver_flags() | additional_resolver_flags_;
AddressFamily effective_address_family = info.address_family();
@@ -2342,7 +2334,7 @@ HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
return Key(info.hostname(), effective_address_family, effective_flags);
}
-bool HostResolverImpl::IsIPv6Reachable(const BoundNetLog& net_log) {
+bool HostResolverImpl::IsIPv6Reachable(const NetLogWithSource& net_log) {
base::TimeTicks now = base::TimeTicks::Now();
bool cached = true;
if ((now - last_ipv6_probe_time_).InMilliseconds() > kIPv6ProbePeriodMs) {
@@ -2351,7 +2343,7 @@ bool HostResolverImpl::IsIPv6Reachable(const BoundNetLog& net_log) {
last_ipv6_probe_time_ = now;
cached = false;
}
- net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_IPV6_REACHABILITY_CHECK,
+ net_log.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_IPV6_REACHABILITY_CHECK,
base::Bind(&NetLogIPv6AvailableCallback,
last_ipv6_probe_result_, cached));
return last_ipv6_probe_result_;
@@ -2434,8 +2426,10 @@ void HostResolverImpl::OnIPAddressChanged() {
last_ipv6_probe_time_ = base::TimeTicks();
// Abandon all ProbeJobs.
probe_weak_ptr_factory_.InvalidateWeakPtrs();
- if (cache_.get())
+ if (cache_.get()) {
cache_->clear();
+ cache_hit_callbacks_.clear();
+ }
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
RunLoopbackProbeJob();
#endif
@@ -2465,9 +2459,8 @@ void HostResolverImpl::UpdateDNSConfig(bool config_changed) {
NetworkChangeNotifier::GetDnsConfig(&dns_config);
if (net_log_) {
- net_log_->AddGlobalEntry(
- NetLog::TYPE_DNS_CONFIG_CHANGED,
- base::Bind(&NetLogDnsConfigCallback, &dns_config));
+ net_log_->AddGlobalEntry(NetLogEventType::DNS_CONFIG_CHANGED,
+ base::Bind(&NetLogDnsConfigCallback, &dns_config));
}
// TODO(szym): Remove once http://crbug.com/137914 is resolved.
@@ -2494,8 +2487,10 @@ void HostResolverImpl::UpdateDNSConfig(bool config_changed) {
// have to drop our internal cache :( Note that OS level DNS caches, such
// as NSCD's cache should be dropped automatically by the OS when
// resolv.conf changes so we don't need to do anything to clear that cache.
- if (cache_.get())
+ if (cache_.get()) {
cache_->clear();
+ cache_hit_callbacks_.clear();
+ }
// Life check to bail once |this| is deleted.
base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
@@ -2541,6 +2536,28 @@ void HostResolverImpl::OnDnsTaskResolve(int net_error) {
std::abs(net_error));
}
+void HostResolverImpl::OnCacheEntryEvicted(const HostCache::Key& key,
+ const HostCache::Entry& entry) {
+ cache_hit_callbacks_.erase(key);
+}
+
+void HostResolverImpl::MaybeAddCacheHitCallback(const HostCache::Key& key,
+ const RequestInfo& info) {
+ const RequestInfo::CacheHitCallback& callback = info.cache_hit_callback();
+ if (callback.is_null())
+ return;
+ cache_hit_callbacks_[key].push_back(callback);
+}
+
+void HostResolverImpl::RunCacheHitCallbacks(const HostCache::Key& key,
+ const RequestInfo& info) {
+ auto it = cache_hit_callbacks_.find(key);
+ if (it == cache_hit_callbacks_.end())
+ return;
+ for (auto& callback : it->second)
+ callback.Run(info);
+}
+
void HostResolverImpl::SetDnsClient(std::unique_ptr<DnsClient> dns_client) {
// DnsClient and config must be updated before aborting DnsTasks, since doing
// so may start new jobs.
@@ -2558,4 +2575,44 @@ void HostResolverImpl::SetDnsClient(std::unique_ptr<DnsClient> dns_client) {
AbortDnsTasks();
}
+void HostResolverImpl::InitializePersistence(
+ const PersistCallback& persist_callback,
+ std::unique_ptr<const base::Value> old_data) {
+ DCHECK(!persist_initialized_);
+ persist_callback_ = persist_callback;
+ persist_initialized_ = true;
+ if (old_data)
+ ApplyPersistentData(std::move(old_data));
+}
+
+void HostResolverImpl::ApplyPersistentData(
+ std::unique_ptr<const base::Value> data) {}
+
+std::unique_ptr<const base::Value> HostResolverImpl::GetPersistentData() {
+ return std::unique_ptr<const base::Value>();
+}
+
+void HostResolverImpl::SchedulePersist() {
+ if (!persist_initialized_ || persist_timer_.IsRunning())
+ return;
+ persist_timer_.Start(
+ FROM_HERE, base::TimeDelta::FromSeconds(kPersistDelaySec),
+ base::Bind(&HostResolverImpl::DoPersist, weak_ptr_factory_.GetWeakPtr()));
+}
+
+void HostResolverImpl::DoPersist() {
+ DCHECK(persist_initialized_);
+ persist_callback_.Run(GetPersistentData());
+}
+
+HostResolverImpl::RequestImpl::~RequestImpl() {
+ if (job_)
+ job_->CancelRequest(this);
+}
+
+void HostResolverImpl::RequestImpl::ChangeRequestPriority(
+ RequestPriority priority) {
+ job_->ChangeRequestPriority(this, priority);
+}
+
} // namespace net
diff --git a/chromium/net/dns/host_resolver_impl.h b/chromium/net/dns/host_resolver_impl.h
index 9ab01ca03ea..373f2297ea0 100644
--- a/chromium/net/dns/host_resolver_impl.h
+++ b/chromium/net/dns/host_resolver_impl.h
@@ -16,6 +16,7 @@
#include "base/strings/string_piece.h"
#include "base/threading/non_thread_safe.h"
#include "base/time/time.h"
+#include "base/timer/timer.h"
#include "net/base/net_export.h"
#include "net/base/network_change_notifier.h"
#include "net/dns/host_cache.h"
@@ -25,10 +26,10 @@
namespace net {
class AddressList;
-class BoundNetLog;
class DnsClient;
class IPAddress;
class NetLog;
+class NetLogWithSource;
// For each hostname that is requested, HostResolver creates a
// HostResolverImpl::Job. When this job gets dispatched it creates a ProcTask
@@ -136,14 +137,11 @@ class NET_EXPORT HostResolverImpl
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& source_net_log) override;
- void ChangeRequestPriority(RequestHandle req,
- RequestPriority priority) override;
- void CancelRequest(RequestHandle req) override;
+ std::unique_ptr<Request>* out_req,
+ const NetLogWithSource& source_net_log) override;
int ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& source_net_log) override;
+ const NetLogWithSource& source_net_log) override;
void SetDnsClientEnabled(bool enabled) override;
HostCache* GetHostCache() override;
std::unique_ptr<base::Value> GetDnsConfigAsValue() const override;
@@ -154,7 +152,11 @@ class NET_EXPORT HostResolverImpl
int ResolveStaleFromCache(const RequestInfo& info,
AddressList* addresses,
HostCache::EntryStaleness* stale_info,
- const BoundNetLog& source_net_log);
+ const NetLogWithSource& source_net_log);
+
+ void InitializePersistence(
+ const PersistCallback& persist_callback,
+ std::unique_ptr<const base::Value> old_data) override;
void set_proc_params_for_test(const ProcTaskParams& proc_params) {
proc_params_ = proc_params;
@@ -176,7 +178,7 @@ class NET_EXPORT HostResolverImpl
class ProcTask;
class LoopbackProbeJob;
class DnsTask;
- class Request;
+ class RequestImpl;
typedef HostCache::Key Key;
typedef std::map<Key, Job*> JobMap;
@@ -202,7 +204,7 @@ class NET_EXPORT HostResolverImpl
AddressList* addresses,
bool allow_stale,
HostCache::EntryStaleness* stale_info,
- const BoundNetLog& request_net_log);
+ const NetLogWithSource& request_net_log);
// Tries to resolve |key| as an IP, returns true and sets |net_error| if
// succeeds, returns false otherwise.
@@ -246,12 +248,12 @@ class NET_EXPORT HostResolverImpl
// family when the request leaves it unspecified.
Key GetEffectiveKeyForRequest(const RequestInfo& info,
const IPAddress* ip_address,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Probes IPv6 support and returns true if IPv6 support is enabled.
// Results are cached, i.e. when called repeatedly this method returns result
// from the first probe for some time before probing again.
- virtual bool IsIPv6Reachable(const BoundNetLog& net_log);
+ virtual bool IsIPv6Reachable(const NetLogWithSource& net_log);
// Asynchronously checks if only loopback IPs are available.
virtual void RunLoopbackProbeJob();
@@ -297,6 +299,19 @@ class NET_EXPORT HostResolverImpl
// and resulted in |net_error|.
void OnDnsTaskResolve(int net_error);
+ void OnCacheEntryEvicted(const HostCache::Key& key,
+ const HostCache::Entry& entry);
+ void ClearCacheHitCallbacks(const HostCache::Key& key);
+ void MaybeAddCacheHitCallback(const HostCache::Key& key,
+ const RequestInfo& info);
+ void RunCacheHitCallbacks(const HostCache::Key& key, const RequestInfo& info);
+
+ void ApplyPersistentData(std::unique_ptr<const base::Value>);
+ std::unique_ptr<const base::Value> GetPersistentData();
+
+ void SchedulePersist();
+ void DoPersist();
+
// Allows the tests to catch slots leaking out of the dispatcher. One
// HostResolverImpl::Job could occupy multiple PrioritizedDispatcher job
// slots.
@@ -353,6 +368,13 @@ class NET_EXPORT HostResolverImpl
// tasks, but can be overridden for tests.
scoped_refptr<base::TaskRunner> worker_task_runner_;
+ std::map<const HostCache::Key, std::vector<RequestInfo::CacheHitCallback>>
+ cache_hit_callbacks_;
+
+ bool persist_initialized_;
+ PersistCallback persist_callback_;
+ base::OneShotTimer persist_timer_;
+
base::WeakPtrFactory<HostResolverImpl> weak_ptr_factory_;
base::WeakPtrFactory<HostResolverImpl> probe_weak_ptr_factory_;
diff --git a/chromium/net/dns/host_resolver_impl_fuzzer.cc b/chromium/net/dns/host_resolver_impl_fuzzer.cc
index c9c9e170649..dad559fac55 100644
--- a/chromium/net/dns/host_resolver_impl_fuzzer.cc
+++ b/chromium/net/dns/host_resolver_impl_fuzzer.cc
@@ -11,13 +11,14 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/run_loop.h"
+#include "base/test/fuzzed_data_provider.h"
#include "net/base/address_family.h"
#include "net/base/address_list.h"
-#include "net/base/fuzzed_data_provider.h"
#include "net/base/net_errors.h"
#include "net/base/request_priority.h"
#include "net/dns/fuzzed_host_resolver.h"
#include "net/dns/host_resolver.h"
+#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
namespace {
@@ -33,24 +34,20 @@ net::AddressFamily kAddressFamilies[] = {
class DnsRequest {
public:
DnsRequest(net::HostResolver* host_resolver,
- net::FuzzedDataProvider* data_provider,
+ base::FuzzedDataProvider* data_provider,
std::vector<std::unique_ptr<DnsRequest>>* dns_requests)
: host_resolver_(host_resolver),
data_provider_(data_provider),
dns_requests_(dns_requests),
- handle_(nullptr),
is_running_(false) {}
- ~DnsRequest() {
- if (is_running_)
- Cancel();
- }
+ ~DnsRequest() {}
// Creates and starts a DNS request using fuzzed parameters. If the request
// doesn't complete synchronously, adds it to |dns_requests|.
static void CreateRequest(
net::HostResolver* host_resolver,
- net::FuzzedDataProvider* data_provider,
+ base::FuzzedDataProvider* data_provider,
std::vector<std::unique_ptr<DnsRequest>>* dns_requests) {
std::unique_ptr<DnsRequest> dns_request(
new DnsRequest(host_resolver, data_provider, dns_requests));
@@ -62,7 +59,7 @@ class DnsRequest {
// If |dns_requests| is non-empty, waits for a randomly chosen one of the
// requests to complete and removes it from |dns_requests|.
static void WaitForRequestComplete(
- net::FuzzedDataProvider* data_provider,
+ base::FuzzedDataProvider* data_provider,
std::vector<std::unique_ptr<DnsRequest>>* dns_requests) {
if (dns_requests->empty())
return;
@@ -81,7 +78,7 @@ class DnsRequest {
// complete, just removes it from the list.
static void CancelRequest(
net::HostResolver* host_resolver,
- net::FuzzedDataProvider* data_provider,
+ base::FuzzedDataProvider* data_provider,
std::vector<std::unique_ptr<DnsRequest>>* dns_requests) {
if (dns_requests->empty())
return;
@@ -97,6 +94,7 @@ class DnsRequest {
CHECK_NE(net::ERR_IO_PENDING, result);
is_running_ = false;
+ request_.reset();
// Remove |this| from |dns_requests| and take ownership of it, if it wasn't
// already removed from the vector. It may have been removed if this is in a
@@ -149,14 +147,14 @@ class DnsRequest {
// Decide if should be a cache-only resolution.
if (data_provider_->ConsumeBool()) {
return host_resolver_->ResolveFromCache(info, &address_list_,
- net::BoundNetLog());
+ net::NetLogWithSource());
}
info.set_allow_cached_response(data_provider_->ConsumeBool());
return host_resolver_->Resolve(
info, priority, &address_list_,
- base::Bind(&DnsRequest::OnCallback, base::Unretained(this)), &handle_,
- net::BoundNetLog());
+ base::Bind(&DnsRequest::OnCallback, base::Unretained(this)), &request_,
+ net::NetLogWithSource());
}
// Waits until the request is done, if it isn't done already.
@@ -166,22 +164,21 @@ class DnsRequest {
run_loop_.reset(new base::RunLoop());
run_loop_->Run();
run_loop_.reset();
- CHECK(!is_running_);
+ DCHECK(request_);
}
}
// Cancel the request, if not already completed. Otherwise, does nothing.
void Cancel() {
- if (is_running_)
- host_resolver_->CancelRequest(handle_);
+ request_.reset();
is_running_ = false;
}
net::HostResolver* host_resolver_;
- net::FuzzedDataProvider* data_provider_;
+ base::FuzzedDataProvider* data_provider_;
std::vector<std::unique_ptr<DnsRequest>>* dns_requests_;
- net::HostResolver::RequestHandle handle_;
+ std::unique_ptr<net::HostResolver::Request> request_;
net::AddressList address_list_;
bool is_running_;
@@ -202,7 +199,7 @@ class DnsRequest {
// async resolver while lookups are active as a result of the change.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
{
- net::FuzzedDataProvider data_provider(data, size);
+ base::FuzzedDataProvider data_provider(data, size);
net::TestNetLog net_log;
net::HostResolver::Options options;
diff --git a/chromium/net/dns/host_resolver_impl_unittest.cc b/chromium/net/dns/host_resolver_impl_unittest.cc
index b89db66b4ff..0dbed080e9e 100644
--- a/chromium/net/dns/host_resolver_impl_unittest.cc
+++ b/chromium/net/dns/host_resolver_impl_unittest.cc
@@ -32,9 +32,17 @@
#include "net/dns/dns_client.h"
#include "net/dns/dns_test_util.h"
#include "net/dns/mock_host_resolver.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -219,50 +227,45 @@ class Request {
resolver_(resolver),
handler_(handler),
quit_on_complete_(false),
- result_(ERR_UNEXPECTED),
- handle_(NULL) {}
+ result_(ERR_UNEXPECTED) {}
int Resolve() {
DCHECK(resolver_);
- DCHECK(!handle_);
+ DCHECK(!request_);
list_ = AddressList();
result_ = resolver_->Resolve(
- info_,
- priority_,
- &list_,
- base::Bind(&Request::OnComplete, base::Unretained(this)),
- &handle_,
- BoundNetLog());
+ info_, priority_, &list_,
+ base::Bind(&Request::OnComplete, base::Unretained(this)), &request_,
+ NetLogWithSource());
if (!list_.empty())
- EXPECT_EQ(OK, result_);
+ EXPECT_THAT(result_, IsOk());
return result_;
}
int ResolveFromCache() {
DCHECK(resolver_);
- DCHECK(!handle_);
- return resolver_->ResolveFromCache(info_, &list_, BoundNetLog());
+ DCHECK(!request_);
+ return resolver_->ResolveFromCache(info_, &list_, NetLogWithSource());
}
int ResolveStaleFromCache() {
DCHECK(resolver_);
- DCHECK(!handle_);
+ DCHECK(!request_);
return resolver_->ResolveStaleFromCache(info_, &list_, &staleness_,
- BoundNetLog());
+ NetLogWithSource());
}
void ChangePriority(RequestPriority priority) {
DCHECK(resolver_);
- DCHECK(handle_);
- resolver_->ChangeRequestPriority(handle_, priority);
+ DCHECK(request_);
+ request_->ChangeRequestPriority(priority);
priority_ = priority;
}
void Cancel() {
DCHECK(resolver_);
- DCHECK(handle_);
- resolver_->CancelRequest(handle_);
- handle_ = NULL;
+ DCHECK(request_);
+ request_.reset();
}
const HostResolver::RequestInfo& info() const { return info_; }
@@ -271,7 +274,7 @@ class Request {
int result() const { return result_; }
const HostCache::EntryStaleness staleness() const { return staleness_; }
bool completed() const { return result_ != ERR_IO_PENDING; }
- bool pending() const { return handle_ != NULL; }
+ bool pending() const { return request_ != nullptr; }
bool HasAddress(const std::string& address, uint16_t port) const {
return AddressListContains(list_, address, port);
@@ -307,12 +310,12 @@ class Request {
private:
void OnComplete(int rv) {
EXPECT_TRUE(pending());
- EXPECT_EQ(ERR_IO_PENDING, result_);
+ EXPECT_THAT(result_, IsError(ERR_IO_PENDING));
EXPECT_NE(ERR_IO_PENDING, rv);
result_ = rv;
- handle_ = NULL;
+ request_.reset();
if (!list_.empty()) {
- EXPECT_EQ(OK, result_);
+ EXPECT_THAT(result_, IsOk());
EXPECT_EQ(info_.port(), list_.front().port());
}
if (handler_)
@@ -332,7 +335,7 @@ class Request {
AddressList list_;
int result_;
- HostResolver::RequestHandle handle_;
+ std::unique_ptr<HostResolver::Request> request_;
HostCache::EntryStaleness staleness_;
DISALLOW_COPY_AND_ASSIGN(Request);
@@ -459,7 +462,7 @@ class TestHostResolverImpl : public HostResolverImpl {
private:
const bool ipv6_reachable_;
- bool IsIPv6Reachable(const BoundNetLog& net_log) override {
+ bool IsIPv6Reachable(const NetLogWithSource& net_log) override {
return ipv6_reachable_;
}
};
@@ -562,8 +565,8 @@ class HostResolverImplTest : public testing::Test {
// not start until released by |proc_->SignalXXX|.
Request* CreateRequest(const HostResolver::RequestInfo& info,
RequestPriority priority) {
- requests_.push_back(base::WrapUnique(new Request(
- info, priority, requests_.size(), resolver_.get(), handler_.get())));
+ requests_.push_back(base::MakeUnique<Request>(
+ info, priority, requests_.size(), resolver_.get(), handler_.get()));
return requests_.back().get();
}
@@ -610,7 +613,7 @@ class HostResolverImplTest : public testing::Test {
return HostResolverImpl::kMaximumDnsFailures;
}
- bool IsIPv6Reachable(const BoundNetLog& net_log) {
+ bool IsIPv6Reachable(const NetLogWithSource& net_log) {
return resolver_->IsIPv6Reachable(net_log);
}
@@ -631,11 +634,10 @@ TEST_F(HostResolverImplTest, AsynchronousLookup) {
proc_->SignalMultiple(1u);
Request* req = CreateRequest("just.testing", 80);
- EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
- EXPECT_EQ(OK, req->WaitForResult());
+ EXPECT_THAT(req->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(req->WaitForResult(), IsOk());
EXPECT_TRUE(req->HasOneAddress("192.168.1.42", 80));
-
EXPECT_EQ("just.testing", proc_->GetCaptureList()[0].hostname);
}
@@ -648,41 +650,41 @@ TEST_F(HostResolverImplTest, LocalhostLookup) {
proc_->AddRuleForAllFamilies("localhost.", "192.168.1.42");
Request* req0 = CreateRequest("foo.localhost", 80);
- EXPECT_EQ(OK, req0->Resolve());
+ EXPECT_THAT(req0->Resolve(), IsOk());
EXPECT_TRUE(req0->HasAddress("127.0.0.1", 80));
EXPECT_TRUE(req0->HasAddress("::1", 80));
Request* req1 = CreateRequest("localhost", 80);
- EXPECT_EQ(OK, req1->Resolve());
+ EXPECT_THAT(req1->Resolve(), IsOk());
EXPECT_TRUE(req1->HasAddress("127.0.0.1", 80));
EXPECT_TRUE(req1->HasAddress("::1", 80));
Request* req2 = CreateRequest("localhost.", 80);
- EXPECT_EQ(OK, req2->Resolve());
+ EXPECT_THAT(req2->Resolve(), IsOk());
EXPECT_TRUE(req2->HasAddress("127.0.0.1", 80));
EXPECT_TRUE(req2->HasAddress("::1", 80));
}
TEST_F(HostResolverImplTest, LocalhostIPV4IPV6Lookup) {
Request* req1 = CreateRequest("localhost6", 80, MEDIUM, ADDRESS_FAMILY_IPV4);
- EXPECT_EQ(OK, req1->Resolve());
+ EXPECT_THAT(req1->Resolve(), IsOk());
EXPECT_EQ(0u, req1->NumberOfAddresses());
Request* req2 = CreateRequest("localhost6", 80, MEDIUM, ADDRESS_FAMILY_IPV6);
- EXPECT_EQ(OK, req2->Resolve());
+ EXPECT_THAT(req2->Resolve(), IsOk());
EXPECT_TRUE(req2->HasOneAddress("::1", 80));
Request* req3 =
CreateRequest("localhost6", 80, MEDIUM, ADDRESS_FAMILY_UNSPECIFIED);
- EXPECT_EQ(OK, req3->Resolve());
+ EXPECT_THAT(req3->Resolve(), IsOk());
EXPECT_TRUE(req3->HasOneAddress("::1", 80));
Request* req4 = CreateRequest("localhost", 80, MEDIUM, ADDRESS_FAMILY_IPV4);
- EXPECT_EQ(OK, req4->Resolve());
+ EXPECT_THAT(req4->Resolve(), IsOk());
EXPECT_TRUE(req4->HasOneAddress("127.0.0.1", 80));
Request* req5 = CreateRequest("localhost", 80, MEDIUM, ADDRESS_FAMILY_IPV6);
- EXPECT_EQ(OK, req5->Resolve());
+ EXPECT_THAT(req5->Resolve(), IsOk());
EXPECT_TRUE(req5->HasOneAddress("::1", 80));
}
@@ -697,7 +699,7 @@ TEST_F(HostResolverImplTest, ResolveIPLiteralWithHostResolverSystemOnly) {
info_bypass.set_host_resolver_flags(HOST_RESOLVER_SYSTEM_ONLY);
Request* req = CreateRequest(info_bypass, MEDIUM);
- EXPECT_EQ(OK, req->Resolve());
+ EXPECT_THAT(req->Resolve(), IsOk());
EXPECT_TRUE(req->HasAddress(kIpLiteral, 80));
}
@@ -707,8 +709,8 @@ TEST_F(HostResolverImplTest, EmptyListMeansNameNotResolved) {
proc_->SignalMultiple(1u);
Request* req = CreateRequest("just.testing", 80);
- EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req->WaitForResult());
+ EXPECT_THAT(req->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(req->WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED));
EXPECT_EQ(0u, req->NumberOfAddresses());
EXPECT_EQ("just.testing", proc_->GetCaptureList()[0].hostname);
}
@@ -719,18 +721,18 @@ TEST_F(HostResolverImplTest, FailedAsynchronousLookup) {
proc_->SignalMultiple(1u);
Request* req = CreateRequest("just.testing", 80);
- EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req->WaitForResult());
+ EXPECT_THAT(req->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(req->WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED));
EXPECT_EQ("just.testing", proc_->GetCaptureList()[0].hostname);
// Also test that the error is not cached.
- EXPECT_EQ(ERR_DNS_CACHE_MISS, req->ResolveFromCache());
+ EXPECT_THAT(req->ResolveFromCache(), IsError(ERR_DNS_CACHE_MISS));
}
TEST_F(HostResolverImplTest, AbortedAsynchronousLookup) {
Request* req0 = CreateRequest("just.testing", 80);
- EXPECT_EQ(ERR_IO_PENDING, req0->Resolve());
+ EXPECT_THAT(req0->Resolve(), IsError(ERR_IO_PENDING));
EXPECT_TRUE(proc_->WaitFor(1u));
@@ -742,11 +744,11 @@ TEST_F(HostResolverImplTest, AbortedAsynchronousLookup) {
// To ensure there was no spurious callback, complete with a new resolver.
CreateResolver();
Request* req1 = CreateRequest("just.testing", 80);
- EXPECT_EQ(ERR_IO_PENDING, req1->Resolve());
+ EXPECT_THAT(req1->Resolve(), IsError(ERR_IO_PENDING));
proc_->SignalMultiple(2u);
- EXPECT_EQ(OK, req1->WaitForResult());
+ EXPECT_THAT(req1->WaitForResult(), IsOk());
// This request was canceled.
EXPECT_FALSE(req0->completed());
@@ -761,7 +763,7 @@ TEST_F(HostResolverImplTest, AbortedAsynchronousLookup) {
TEST_F(HostResolverImplTest, MAYBE_NumericIPv4Address) {
// Stevens says dotted quads with AI_UNSPEC resolve to a single sockaddr_in.
Request* req = CreateRequest("127.1.2.3", 5555);
- EXPECT_EQ(OK, req->Resolve());
+ EXPECT_THAT(req->Resolve(), IsOk());
EXPECT_TRUE(req->HasOneAddress("127.1.2.3", 5555));
}
@@ -776,7 +778,7 @@ TEST_F(HostResolverImplTest, MAYBE_NumericIPv6Address) {
// Resolve a plain IPv6 address. Don't worry about [brackets], because
// the caller should have removed them.
Request* req = CreateRequest("2001:db8::1", 5555);
- EXPECT_EQ(OK, req->Resolve());
+ EXPECT_THAT(req->Resolve(), IsOk());
EXPECT_TRUE(req->HasOneAddress("2001:db8::1", 5555));
}
@@ -789,7 +791,7 @@ TEST_F(HostResolverImplTest, MAYBE_NumericIPv6Address) {
#endif
TEST_F(HostResolverImplTest, MAYBE_EmptyHost) {
Request* req = CreateRequest(std::string(), 5555);
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req->Resolve());
+ EXPECT_THAT(req->Resolve(), IsError(ERR_NAME_NOT_RESOLVED));
}
#if defined(THREAD_SANITIZER)
@@ -804,7 +806,7 @@ TEST_F(HostResolverImplTest, MAYBE_EmptyHost) {
TEST_F(HostResolverImplTest, MAYBE_EmptyDotsHost) {
for (int i = 0; i < 16; ++i) {
Request* req = CreateRequest(std::string(i, '.'), 5555);
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req->Resolve());
+ EXPECT_THAT(req->Resolve(), IsError(ERR_NAME_NOT_RESOLVED));
}
}
@@ -818,17 +820,17 @@ TEST_F(HostResolverImplTest, MAYBE_EmptyDotsHost) {
#endif
TEST_F(HostResolverImplTest, MAYBE_LongHost) {
Request* req = CreateRequest(std::string(4097, 'a'), 5555);
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req->Resolve());
+ EXPECT_THAT(req->Resolve(), IsError(ERR_NAME_NOT_RESOLVED));
}
TEST_F(HostResolverImplTest, DeDupeRequests) {
// Start 5 requests, duplicating hosts "a" and "b". Since the resolver_proc is
// blocked, these should all pile up until we signal it.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("a", 80)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("b", 80)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("b", 81)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("a", 82)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("b", 83)->Resolve());
+ EXPECT_THAT(CreateRequest("a", 80)->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("b", 80)->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("b", 81)->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("a", 82)->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("b", 83)->Resolve(), IsError(ERR_IO_PENDING));
proc_->SignalMultiple(2u); // One for "a", one for "b".
@@ -838,11 +840,11 @@ TEST_F(HostResolverImplTest, DeDupeRequests) {
}
TEST_F(HostResolverImplTest, CancelMultipleRequests) {
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("a", 80)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("b", 80)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("b", 81)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("a", 82)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("b", 83)->Resolve());
+ EXPECT_THAT(CreateRequest("a", 80)->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("b", 80)->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("b", 81)->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("a", 82)->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("b", 83)->Resolve(), IsError(ERR_IO_PENDING));
// Cancel everything except request for ("a", 82).
requests_[0]->Cancel();
@@ -852,7 +854,7 @@ TEST_F(HostResolverImplTest, CancelMultipleRequests) {
proc_->SignalMultiple(2u); // One for "a", one for "b".
- EXPECT_EQ(OK, requests_[3]->WaitForResult());
+ EXPECT_THAT(requests_[3]->WaitForResult(), IsOk());
}
TEST_F(HostResolverImplTest, CanceledRequestsReleaseJobSlots) {
@@ -860,8 +862,10 @@ TEST_F(HostResolverImplTest, CanceledRequestsReleaseJobSlots) {
for (unsigned i = 0; i < kMaxJobs + 1; ++i) {
std::string hostname = "a_";
hostname[1] = 'a' + i;
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest(hostname, 80)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest(hostname, 81)->Resolve());
+ EXPECT_THAT(CreateRequest(hostname, 80)->Resolve(),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest(hostname, 81)->Resolve(),
+ IsError(ERR_IO_PENDING));
}
EXPECT_TRUE(proc_->WaitFor(kMaxJobs));
@@ -876,8 +880,8 @@ TEST_F(HostResolverImplTest, CanceledRequestsReleaseJobSlots) {
proc_->SignalAll();
size_t num_requests = requests_.size();
- EXPECT_EQ(OK, requests_[num_requests - 1]->WaitForResult());
- EXPECT_EQ(OK, requests_[num_requests - 2]->result());
+ EXPECT_THAT(requests_[num_requests - 1]->WaitForResult(), IsOk());
+ EXPECT_THAT(requests_[num_requests - 2]->result(), IsOk());
}
TEST_F(HostResolverImplTest, CancelWithinCallback) {
@@ -901,11 +905,11 @@ TEST_F(HostResolverImplTest, CancelWithinCallback) {
proc_->SignalMultiple(2u); // One for "a". One for "finalrequest".
- EXPECT_EQ(OK, requests_[0]->WaitForResult());
+ EXPECT_THAT(requests_[0]->WaitForResult(), IsOk());
Request* final_request = CreateRequest("finalrequest", 70);
- EXPECT_EQ(ERR_IO_PENDING, final_request->Resolve());
- EXPECT_EQ(OK, final_request->WaitForResult());
+ EXPECT_THAT(final_request->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(final_request->WaitForResult(), IsOk());
EXPECT_TRUE(requests_[3]->completed());
}
@@ -952,12 +956,12 @@ TEST_F(HostResolverImplTest, DeleteWithinAbortedCallback) {
set_handler(new MyHandler());
// This test assumes that the Jobs will be Aborted in order ["a", "b"]
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("a", 80)->Resolve());
+ EXPECT_THAT(CreateRequest("a", 80)->Resolve(), IsError(ERR_IO_PENDING));
// HostResolverImpl will be deleted before later Requests can complete.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("a", 81)->Resolve());
+ EXPECT_THAT(CreateRequest("a", 81)->Resolve(), IsError(ERR_IO_PENDING));
// Job for 'b' will be aborted before it can complete.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("b", 82)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("b", 83)->Resolve());
+ EXPECT_THAT(CreateRequest("b", 82)->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("b", 83)->Resolve(), IsError(ERR_IO_PENDING));
EXPECT_TRUE(proc_->WaitFor(1u));
@@ -967,10 +971,10 @@ TEST_F(HostResolverImplTest, DeleteWithinAbortedCallback) {
// |MyHandler| will send quit message once all the requests have finished.
base::RunLoop().Run();
- EXPECT_EQ(ERR_NETWORK_CHANGED, requests_[0]->result());
- EXPECT_EQ(ERR_IO_PENDING, requests_[1]->result());
- EXPECT_EQ(ERR_IO_PENDING, requests_[2]->result());
- EXPECT_EQ(ERR_IO_PENDING, requests_[3]->result());
+ EXPECT_THAT(requests_[0]->result(), IsError(ERR_NETWORK_CHANGED));
+ EXPECT_THAT(requests_[1]->result(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(requests_[2]->result(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(requests_[3]->result(), IsError(ERR_IO_PENDING));
// Clean up.
proc_->SignalMultiple(requests_.size());
}
@@ -981,7 +985,7 @@ TEST_F(HostResolverImplTest, StartWithinCallback) {
if (req->index() == 0) {
// On completing the first request, start another request for "a".
// Since caching is disabled, this will result in another async request.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("a", 70)->Resolve());
+ EXPECT_THAT(CreateRequest("a", 70)->Resolve(), IsError(ERR_IO_PENDING));
}
}
};
@@ -999,9 +1003,9 @@ TEST_F(HostResolverImplTest, StartWithinCallback) {
proc_->SignalMultiple(2u); // One for "a". One for the second "a".
- EXPECT_EQ(OK, requests_[0]->WaitForResult());
+ EXPECT_THAT(requests_[0]->WaitForResult(), IsOk());
ASSERT_EQ(5u, requests_.size());
- EXPECT_EQ(OK, requests_.back()->WaitForResult());
+ EXPECT_THAT(requests_.back()->WaitForResult(), IsOk());
EXPECT_EQ(2u, proc_->GetCaptureList().size());
}
@@ -1013,8 +1017,8 @@ TEST_F(HostResolverImplTest, BypassCache) {
// On completing the first request, start another request for "a".
// Since caching is enabled, this should complete synchronously.
std::string hostname = req->info().hostname();
- EXPECT_EQ(OK, CreateRequest(hostname, 70)->Resolve());
- EXPECT_EQ(OK, CreateRequest(hostname, 75)->ResolveFromCache());
+ EXPECT_THAT(CreateRequest(hostname, 70)->Resolve(), IsOk());
+ EXPECT_THAT(CreateRequest(hostname, 75)->ResolveFromCache(), IsOk());
// Ok good. Now make sure that if we ask to bypass the cache, it can no
// longer service the request synchronously.
@@ -1032,7 +1036,7 @@ TEST_F(HostResolverImplTest, BypassCache) {
};
set_handler(new MyHandler());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("a", 80)->Resolve());
+ EXPECT_THAT(CreateRequest("a", 80)->Resolve(), IsError(ERR_IO_PENDING));
proc_->SignalMultiple(3u); // Only need two, but be generous.
// |verifier| will send quit message once all the requests have finished.
@@ -1046,16 +1050,16 @@ TEST_F(HostResolverImplTest, FlushCacheOnIPAddressChange) {
proc_->SignalMultiple(2u); // One before the flush, one after.
Request* req = CreateRequest("host1", 70);
- EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
- EXPECT_EQ(OK, req->WaitForResult());
+ EXPECT_THAT(req->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(req->WaitForResult(), IsOk());
req = CreateRequest("host1", 75);
- EXPECT_EQ(OK, req->Resolve()); // Should complete synchronously.
+ EXPECT_THAT(req->Resolve(), IsOk()); // Should complete synchronously.
// Verify initial DNS config read does not flush cache.
NetworkChangeNotifier::NotifyObserversOfInitialDNSConfigReadForTests();
req = CreateRequest("host1", 75);
- EXPECT_EQ(OK, req->Resolve()); // Should complete synchronously.
+ EXPECT_THAT(req->Resolve(), IsOk()); // Should complete synchronously.
// Flush cache by triggering an IP address change.
NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
@@ -1064,14 +1068,14 @@ TEST_F(HostResolverImplTest, FlushCacheOnIPAddressChange) {
// Resolve "host1" again -- this time it won't be served from cache, so it
// will complete asynchronously.
req = CreateRequest("host1", 80);
- EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
- EXPECT_EQ(OK, req->WaitForResult());
+ EXPECT_THAT(req->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(req->WaitForResult(), IsOk());
}
// Test that IP address changes send ERR_NETWORK_CHANGED to pending requests.
TEST_F(HostResolverImplTest, AbortOnIPAddressChanged) {
Request* req = CreateRequest("host1", 70);
- EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
+ EXPECT_THAT(req->Resolve(), IsError(ERR_IO_PENDING));
EXPECT_TRUE(proc_->WaitFor(1u));
// Triggering an IP address change.
@@ -1079,14 +1083,14 @@ TEST_F(HostResolverImplTest, AbortOnIPAddressChanged) {
base::RunLoop().RunUntilIdle(); // Notification happens async.
proc_->SignalAll();
- EXPECT_EQ(ERR_NETWORK_CHANGED, req->WaitForResult());
+ EXPECT_THAT(req->WaitForResult(), IsError(ERR_NETWORK_CHANGED));
EXPECT_EQ(0u, resolver_->GetHostCache()->size());
}
// Test that initial DNS config read signals do not abort pending requests.
TEST_F(HostResolverImplTest, DontAbortOnInitialDNSConfigRead) {
Request* req = CreateRequest("host1", 70);
- EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
+ EXPECT_THAT(req->Resolve(), IsError(ERR_IO_PENDING));
EXPECT_TRUE(proc_->WaitFor(1u));
// Triggering initial DNS config read signal.
@@ -1094,16 +1098,16 @@ TEST_F(HostResolverImplTest, DontAbortOnInitialDNSConfigRead) {
base::RunLoop().RunUntilIdle(); // Notification happens async.
proc_->SignalAll();
- EXPECT_EQ(OK, req->WaitForResult());
+ EXPECT_THAT(req->WaitForResult(), IsOk());
}
// Obey pool constraints after IP address has changed.
TEST_F(HostResolverImplTest, ObeyPoolConstraintsAfterIPAddressChange) {
// Runs at most one job at a time.
CreateSerialResolver();
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("a")->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("b")->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("c")->Resolve());
+ EXPECT_THAT(CreateRequest("a")->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("b")->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("c")->Resolve(), IsError(ERR_IO_PENDING));
EXPECT_TRUE(proc_->WaitFor(1u));
// Triggering an IP address change.
@@ -1111,15 +1115,15 @@ TEST_F(HostResolverImplTest, ObeyPoolConstraintsAfterIPAddressChange) {
base::RunLoop().RunUntilIdle(); // Notification happens async.
proc_->SignalMultiple(3u); // Let the false-start go so that we can catch it.
- EXPECT_EQ(ERR_NETWORK_CHANGED, requests_[0]->WaitForResult());
+ EXPECT_THAT(requests_[0]->WaitForResult(), IsError(ERR_NETWORK_CHANGED));
EXPECT_EQ(1u, num_running_dispatcher_jobs());
EXPECT_FALSE(requests_[1]->completed());
EXPECT_FALSE(requests_[2]->completed());
- EXPECT_EQ(OK, requests_[2]->WaitForResult());
- EXPECT_EQ(OK, requests_[1]->result());
+ EXPECT_THAT(requests_[2]->WaitForResult(), IsOk());
+ EXPECT_THAT(requests_[1]->result(), IsOk());
}
// Tests that a new Request made from the callback of a previously aborted one
@@ -1143,9 +1147,9 @@ TEST_F(HostResolverImplTest, AbortOnlyExistingRequestsOnIPAddressChange) {
};
set_handler(new MyHandler());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("bbb")->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("eee")->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ccc")->Resolve());
+ EXPECT_THAT(CreateRequest("bbb")->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("eee")->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("ccc")->Resolve(), IsError(ERR_IO_PENDING));
// Wait until all are blocked;
EXPECT_TRUE(proc_->WaitFor(3u));
@@ -1153,16 +1157,16 @@ TEST_F(HostResolverImplTest, AbortOnlyExistingRequestsOnIPAddressChange) {
NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
// This should abort all running jobs.
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(ERR_NETWORK_CHANGED, requests_[0]->result());
- EXPECT_EQ(ERR_NETWORK_CHANGED, requests_[1]->result());
- EXPECT_EQ(ERR_NETWORK_CHANGED, requests_[2]->result());
+ EXPECT_THAT(requests_[0]->result(), IsError(ERR_NETWORK_CHANGED));
+ EXPECT_THAT(requests_[1]->result(), IsError(ERR_NETWORK_CHANGED));
+ EXPECT_THAT(requests_[2]->result(), IsError(ERR_NETWORK_CHANGED));
ASSERT_EQ(6u, requests_.size());
// Unblock all calls to proc.
proc_->SignalMultiple(requests_.size());
// Run until the re-started requests finish.
- EXPECT_EQ(OK, requests_[3]->WaitForResult());
- EXPECT_EQ(OK, requests_[4]->WaitForResult());
- EXPECT_EQ(OK, requests_[5]->WaitForResult());
+ EXPECT_THAT(requests_[3]->WaitForResult(), IsOk());
+ EXPECT_THAT(requests_[4]->WaitForResult(), IsOk());
+ EXPECT_THAT(requests_[5]->WaitForResult(), IsOk());
// Verify that results of aborted Jobs were not cached.
EXPECT_EQ(6u, proc_->GetCaptureList().size());
EXPECT_EQ(3u, resolver_->GetHostCache()->size());
@@ -1224,9 +1228,9 @@ TEST_F(HostResolverImplTest, ChangePriority) {
// req0 starts immediately; without ChangePriority, req1 and then req2 should
// run.
- EXPECT_EQ(ERR_IO_PENDING, requests_[0]->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, requests_[1]->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, requests_[2]->Resolve());
+ EXPECT_THAT(requests_[0]->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(requests_[1]->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(requests_[2]->Resolve(), IsError(ERR_IO_PENDING));
// Changing req2 to HIGH should make it run before req1.
// (It can't run before req0, since req0 started immediately.)
@@ -1235,9 +1239,9 @@ TEST_F(HostResolverImplTest, ChangePriority) {
// Let all 3 requests finish.
proc_->SignalMultiple(3u);
- EXPECT_EQ(OK, requests_[0]->WaitForResult());
- EXPECT_EQ(OK, requests_[1]->WaitForResult());
- EXPECT_EQ(OK, requests_[2]->WaitForResult());
+ EXPECT_THAT(requests_[0]->WaitForResult(), IsOk());
+ EXPECT_THAT(requests_[1]->WaitForResult(), IsOk());
+ EXPECT_THAT(requests_[2]->WaitForResult(), IsOk());
MockHostResolverProc::CaptureList capture_list = proc_->GetCaptureList();
ASSERT_EQ(3u, capture_list.size());
@@ -1301,10 +1305,14 @@ TEST_F(HostResolverImplTest, QueueOverflow) {
// Note that at this point the MockHostResolverProc is blocked, so any
// requests we make will not complete.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("req0", 80, LOWEST)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("req1", 80, HIGHEST)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("req2", 80, MEDIUM)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("req3", 80, MEDIUM)->Resolve());
+ EXPECT_THAT(CreateRequest("req0", 80, LOWEST)->Resolve(),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("req1", 80, HIGHEST)->Resolve(),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("req2", 80, MEDIUM)->Resolve(),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("req3", 80, MEDIUM)->Resolve(),
+ IsError(ERR_IO_PENDING));
// At this point, there are 3 enqueued jobs.
// Insertion of subsequent requests will cause evictions
@@ -1313,21 +1321,27 @@ TEST_F(HostResolverImplTest, QueueOverflow) {
EXPECT_EQ(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE,
CreateRequest("req4", 80, LOW)->Resolve()); // Evicts itself!
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("req5", 80, MEDIUM)->Resolve());
- EXPECT_EQ(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE, requests_[2]->result());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("req6", 80, HIGHEST)->Resolve());
- EXPECT_EQ(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE, requests_[3]->result());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("req7", 80, MEDIUM)->Resolve());
- EXPECT_EQ(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE, requests_[5]->result());
+ EXPECT_THAT(CreateRequest("req5", 80, MEDIUM)->Resolve(),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(requests_[2]->result(),
+ IsError(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE));
+ EXPECT_THAT(CreateRequest("req6", 80, HIGHEST)->Resolve(),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(requests_[3]->result(),
+ IsError(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE));
+ EXPECT_THAT(CreateRequest("req7", 80, MEDIUM)->Resolve(),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(requests_[5]->result(),
+ IsError(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE));
// Unblock the resolver thread so the requests can run.
proc_->SignalMultiple(4u);
// The rest should succeed.
- EXPECT_EQ(OK, requests_[7]->WaitForResult());
- EXPECT_EQ(OK, requests_[0]->result());
- EXPECT_EQ(OK, requests_[1]->result());
- EXPECT_EQ(OK, requests_[6]->result());
+ EXPECT_THAT(requests_[7]->WaitForResult(), IsOk());
+ EXPECT_THAT(requests_[0]->result(), IsOk());
+ EXPECT_THAT(requests_[1]->result(), IsOk());
+ EXPECT_THAT(requests_[6]->result(), IsOk());
// Verify that they called out the the resolver proc (which runs on the
// resolver thread) in the expected order.
@@ -1352,25 +1366,25 @@ TEST_F(HostResolverImplTest, QueueOverflow) {
TEST_F(HostResolverImplTest, AddressFamilyWithRawIPs) {
Request* request =
CreateRequest("127.0.0.1", 80, MEDIUM, ADDRESS_FAMILY_IPV4);
- EXPECT_EQ(OK, request->Resolve());
+ EXPECT_THAT(request->Resolve(), IsOk());
EXPECT_TRUE(request->HasOneAddress("127.0.0.1", 80));
request = CreateRequest("127.0.0.1", 80, MEDIUM, ADDRESS_FAMILY_IPV6);
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, request->Resolve());
+ EXPECT_THAT(request->Resolve(), IsError(ERR_NAME_NOT_RESOLVED));
request = CreateRequest("127.0.0.1", 80, MEDIUM, ADDRESS_FAMILY_UNSPECIFIED);
- EXPECT_EQ(OK, request->Resolve());
+ EXPECT_THAT(request->Resolve(), IsOk());
EXPECT_TRUE(request->HasOneAddress("127.0.0.1", 80));
request = CreateRequest("::1", 80, MEDIUM, ADDRESS_FAMILY_IPV4);
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, request->Resolve());
+ EXPECT_THAT(request->Resolve(), IsError(ERR_NAME_NOT_RESOLVED));
request = CreateRequest("::1", 80, MEDIUM, ADDRESS_FAMILY_IPV6);
- EXPECT_EQ(OK, request->Resolve());
+ EXPECT_THAT(request->Resolve(), IsOk());
EXPECT_TRUE(request->HasOneAddress("::1", 80));
request = CreateRequest("::1", 80, MEDIUM, ADDRESS_FAMILY_UNSPECIFIED);
- EXPECT_EQ(OK, request->Resolve());
+ EXPECT_THAT(request->Resolve(), IsOk());
EXPECT_TRUE(request->HasOneAddress("::1", 80));
}
@@ -1385,11 +1399,13 @@ TEST_F(HostResolverImplTest, ResolveFromCache) {
CreateRequest(info, DEFAULT_PRIORITY)->ResolveFromCache());
// This time, we fetch normally.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info, DEFAULT_PRIORITY)->Resolve());
- EXPECT_EQ(OK, requests_[1]->WaitForResult());
+ EXPECT_THAT(CreateRequest(info, DEFAULT_PRIORITY)->Resolve(),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(requests_[1]->WaitForResult(), IsOk());
// Now we should be able to fetch from the cache.
- EXPECT_EQ(OK, CreateRequest(info, DEFAULT_PRIORITY)->ResolveFromCache());
+ EXPECT_THAT(CreateRequest(info, DEFAULT_PRIORITY)->ResolveFromCache(),
+ IsOk());
EXPECT_TRUE(requests_[2]->HasOneAddress("192.168.1.42", 80));
}
@@ -1404,13 +1420,16 @@ TEST_F(HostResolverImplTest, ResolveStaleFromCache) {
CreateRequest(info, DEFAULT_PRIORITY)->ResolveFromCache());
// This time, we fetch normally.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info, DEFAULT_PRIORITY)->Resolve());
- EXPECT_EQ(OK, requests_[1]->WaitForResult());
+ EXPECT_THAT(CreateRequest(info, DEFAULT_PRIORITY)->Resolve(),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(requests_[1]->WaitForResult(), IsOk());
// Now we should be able to fetch from the cache.
- EXPECT_EQ(OK, CreateRequest(info, DEFAULT_PRIORITY)->ResolveFromCache());
+ EXPECT_THAT(CreateRequest(info, DEFAULT_PRIORITY)->ResolveFromCache(),
+ IsOk());
EXPECT_TRUE(requests_[2]->HasOneAddress("192.168.1.42", 80));
- EXPECT_EQ(OK, CreateRequest(info, DEFAULT_PRIORITY)->ResolveStaleFromCache());
+ EXPECT_THAT(CreateRequest(info, DEFAULT_PRIORITY)->ResolveStaleFromCache(),
+ IsOk());
EXPECT_TRUE(requests_[3]->HasOneAddress("192.168.1.42", 80));
EXPECT_FALSE(requests_[3]->staleness().is_stale());
@@ -1420,7 +1439,8 @@ TEST_F(HostResolverImplTest, ResolveStaleFromCache) {
// ResolveStaleFromCache.
EXPECT_EQ(ERR_DNS_CACHE_MISS,
CreateRequest(info, DEFAULT_PRIORITY)->ResolveFromCache());
- EXPECT_EQ(OK, CreateRequest(info, DEFAULT_PRIORITY)->ResolveStaleFromCache());
+ EXPECT_THAT(CreateRequest(info, DEFAULT_PRIORITY)->ResolveStaleFromCache(),
+ IsOk());
EXPECT_TRUE(requests_[5]->HasOneAddress("192.168.1.42", 80));
EXPECT_TRUE(requests_[5]->staleness().is_stale());
}
@@ -1451,7 +1471,7 @@ TEST_F(HostResolverImplTest, MultipleAttempts) {
// Resolve "host1".
HostResolver::RequestInfo info(HostPortPair("host1", 70));
Request* req = CreateRequest(info, DEFAULT_PRIORITY);
- EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
+ EXPECT_THAT(req->Resolve(), IsError(ERR_IO_PENDING));
// Resolve returns -4 to indicate that 3rd attempt has resolved the host.
EXPECT_EQ(-4, req->WaitForResult());
@@ -1480,35 +1500,35 @@ TEST_F(HostResolverImplTest, NameCollision127_0_53_53) {
Request* request;
request = CreateRequest("single");
- EXPECT_EQ(ERR_IO_PENDING, request->Resolve());
- EXPECT_EQ(ERR_ICANN_NAME_COLLISION, request->WaitForResult());
+ EXPECT_THAT(request->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(request->WaitForResult(), IsError(ERR_ICANN_NAME_COLLISION));
request = CreateRequest("multiple");
- EXPECT_EQ(ERR_IO_PENDING, request->Resolve());
- EXPECT_EQ(ERR_ICANN_NAME_COLLISION, request->WaitForResult());
+ EXPECT_THAT(request->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(request->WaitForResult(), IsError(ERR_ICANN_NAME_COLLISION));
// Resolving an IP literal of 127.0.53.53 however is allowed.
- EXPECT_EQ(OK, CreateRequest("127.0.53.53")->Resolve());
+ EXPECT_THAT(CreateRequest("127.0.53.53")->Resolve(), IsOk());
// Moreover the address should not be recognized when embedded in an IPv6
// address.
request = CreateRequest("ipv6");
- EXPECT_EQ(ERR_IO_PENDING, request->Resolve());
- EXPECT_EQ(OK, request->WaitForResult());
+ EXPECT_THAT(request->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(request->WaitForResult(), IsOk());
// Try some other IPs which are similar, but NOT an exact match on
// 127.0.53.53.
request = CreateRequest("not_reserved1");
- EXPECT_EQ(ERR_IO_PENDING, request->Resolve());
- EXPECT_EQ(OK, request->WaitForResult());
+ EXPECT_THAT(request->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(request->WaitForResult(), IsOk());
request = CreateRequest("not_reserved2");
- EXPECT_EQ(ERR_IO_PENDING, request->Resolve());
- EXPECT_EQ(OK, request->WaitForResult());
+ EXPECT_THAT(request->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(request->WaitForResult(), IsOk());
request = CreateRequest("not_reserved3");
- EXPECT_EQ(ERR_IO_PENDING, request->Resolve());
- EXPECT_EQ(OK, request->WaitForResult());
+ EXPECT_THAT(request->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(request->WaitForResult(), IsOk());
}
TEST_F(HostResolverImplTest, IsIPv6Reachable) {
@@ -1517,18 +1537,20 @@ TEST_F(HostResolverImplTest, IsIPv6Reachable) {
resolver_.reset(new HostResolverImpl(DefaultOptions(), nullptr));
// Verify that two consecutive calls return the same value.
- TestNetLog net_log;
- BoundNetLog bound_net_log = BoundNetLog::Make(&net_log, NetLog::SOURCE_NONE);
- bool result1 = IsIPv6Reachable(bound_net_log);
- bool result2 = IsIPv6Reachable(bound_net_log);
+ TestNetLog test_net_log;
+ NetLogWithSource net_log =
+ NetLogWithSource::Make(&test_net_log, NetLogSourceType::NONE);
+ bool result1 = IsIPv6Reachable(net_log);
+ bool result2 = IsIPv6Reachable(net_log);
EXPECT_EQ(result1, result2);
// Filter reachability check events and verify that there are two of them.
TestNetLogEntry::List event_list;
- net_log.GetEntries(&event_list);
+ test_net_log.GetEntries(&event_list);
TestNetLogEntry::List probe_event_list;
for (const auto& event : event_list) {
- if (event.type == NetLog::TYPE_HOST_RESOLVER_IMPL_IPV6_REACHABILITY_CHECK) {
+ if (event.type ==
+ NetLogEventType::HOST_RESOLVER_IMPL_IPV6_REACHABILITY_CHECK) {
probe_event_list.push_back(event);
}
}
@@ -1637,10 +1659,10 @@ TEST_F(HostResolverImplDnsTest, DnsTask) {
// All other hostnames will fail in proc_.
// Initially there is no config, so client should not be invoked.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok_fail", 80)->Resolve());
+ EXPECT_THAT(CreateRequest("ok_fail", 80)->Resolve(), IsError(ERR_IO_PENDING));
proc_->SignalMultiple(requests_.size());
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, requests_[0]->WaitForResult());
+ EXPECT_THAT(requests_[0]->WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED));
ChangeDnsConfig(CreateValidDnsConfig());
@@ -1656,12 +1678,12 @@ TEST_F(HostResolverImplDnsTest, DnsTask) {
for (size_t i = 1; i < requests_.size(); ++i)
EXPECT_NE(ERR_UNEXPECTED, requests_[i]->WaitForResult()) << i;
- EXPECT_EQ(OK, requests_[1]->result());
+ EXPECT_THAT(requests_[1]->result(), IsOk());
// Resolved by MockDnsClient.
EXPECT_TRUE(requests_[1]->HasOneAddress("127.0.0.1", 80));
// Fallback to ProcTask.
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, requests_[2]->result());
- EXPECT_EQ(OK, requests_[3]->result());
+ EXPECT_THAT(requests_[2]->result(), IsError(ERR_NAME_NOT_RESOLVED));
+ EXPECT_THAT(requests_[3]->result(), IsOk());
EXPECT_TRUE(requests_[3]->HasOneAddress("192.168.1.102", 80));
}
@@ -1676,13 +1698,14 @@ TEST_F(HostResolverImplDnsTest, NoFallbackToProcTask) {
// Set empty DnsConfig.
ChangeDnsConfig(DnsConfig());
// Initially there is no config, so client should not be invoked.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok_fail", 80)->Resolve());
+ EXPECT_THAT(CreateRequest("ok_fail", 80)->Resolve(), IsError(ERR_IO_PENDING));
// There is no config, so fallback to ProcTask must work.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("nx_succeed", 80)->Resolve());
+ EXPECT_THAT(CreateRequest("nx_succeed", 80)->Resolve(),
+ IsError(ERR_IO_PENDING));
proc_->SignalMultiple(requests_.size());
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, requests_[0]->WaitForResult());
- EXPECT_EQ(OK, requests_[1]->WaitForResult());
+ EXPECT_THAT(requests_[0]->WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED));
+ EXPECT_THAT(requests_[1]->WaitForResult(), IsOk());
EXPECT_TRUE(requests_[1]->HasOneAddress("192.168.1.102", 80));
ChangeDnsConfig(CreateValidDnsConfig());
@@ -1707,37 +1730,39 @@ TEST_F(HostResolverImplDnsTest, NoFallbackToProcTask) {
proc_->SignalMultiple(requests_.size());
// Aborted due to Network Change.
- EXPECT_EQ(ERR_NETWORK_CHANGED, requests_[2]->WaitForResult());
- EXPECT_EQ(ERR_NETWORK_CHANGED, requests_[3]->WaitForResult());
+ EXPECT_THAT(requests_[2]->WaitForResult(), IsError(ERR_NETWORK_CHANGED));
+ EXPECT_THAT(requests_[3]->WaitForResult(), IsError(ERR_NETWORK_CHANGED));
// Resolved by MockDnsClient.
- EXPECT_EQ(OK, requests_[4]->WaitForResult());
+ EXPECT_THAT(requests_[4]->WaitForResult(), IsOk());
EXPECT_TRUE(requests_[4]->HasOneAddress("127.0.0.1", 80));
// Fallback to ProcTask is disabled.
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, requests_[5]->WaitForResult());
+ EXPECT_THAT(requests_[5]->WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED));
}
// Test behavior of OnDnsTaskFailure when Job is aborted.
TEST_F(HostResolverImplDnsTest, OnDnsTaskFailureAbortedJob) {
ChangeDnsConfig(CreateValidDnsConfig());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("nx_abort", 80)->Resolve());
+ EXPECT_THAT(CreateRequest("nx_abort", 80)->Resolve(),
+ IsError(ERR_IO_PENDING));
// Abort all jobs here.
CreateResolver();
proc_->SignalMultiple(requests_.size());
// Run to completion.
base::RunLoop().RunUntilIdle(); // Notification happens async.
// It shouldn't crash during OnDnsTaskFailure callbacks.
- EXPECT_EQ(ERR_IO_PENDING, requests_[0]->result());
+ EXPECT_THAT(requests_[0]->result(), IsError(ERR_IO_PENDING));
// Repeat test with Fallback to ProcTask disabled
set_fallback_to_proctask(false);
ChangeDnsConfig(CreateValidDnsConfig());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("nx_abort", 80)->Resolve());
+ EXPECT_THAT(CreateRequest("nx_abort", 80)->Resolve(),
+ IsError(ERR_IO_PENDING));
// Abort all jobs here.
CreateResolver();
// Run to completion.
base::RunLoop().RunUntilIdle(); // Notification happens async.
// It shouldn't crash during OnDnsTaskFailure callbacks.
- EXPECT_EQ(ERR_IO_PENDING, requests_[1]->result());
+ EXPECT_THAT(requests_[1]->result(), IsError(ERR_IO_PENDING));
}
TEST_F(HostResolverImplDnsTest, DnsTaskUnspec) {
@@ -1746,10 +1771,10 @@ TEST_F(HostResolverImplDnsTest, DnsTaskUnspec) {
proc_->AddRuleForAllFamilies("4nx", "192.168.1.101");
// All other hostnames will fail in proc_.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4ok", 80)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("6ok", 80)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4nx", 80)->Resolve());
+ EXPECT_THAT(CreateRequest("ok", 80)->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("4ok", 80)->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("6ok", 80)->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("4nx", 80)->Resolve(), IsError(ERR_IO_PENDING));
proc_->SignalMultiple(requests_.size());
@@ -1777,8 +1802,8 @@ TEST_F(HostResolverImplDnsTest, ServeFromHosts) {
proc_->SignalMultiple(1u); // For the first request which misses.
Request* req0 = CreateRequest("nx_ipv4", 80);
- EXPECT_EQ(ERR_IO_PENDING, req0->Resolve());
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req0->WaitForResult());
+ EXPECT_THAT(req0->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(req0->WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED));
IPAddress local_ipv4 = IPAddress::IPv4Localhost();
IPAddress local_ipv6 = IPAddress::IPv6Localhost();
@@ -1794,30 +1819,30 @@ TEST_F(HostResolverImplDnsTest, ServeFromHosts) {
ChangeDnsConfig(config);
Request* req1 = CreateRequest("nx_ipv4", 80);
- EXPECT_EQ(OK, req1->Resolve());
+ EXPECT_THAT(req1->Resolve(), IsOk());
EXPECT_TRUE(req1->HasOneAddress("127.0.0.1", 80));
Request* req2 = CreateRequest("nx_ipv6", 80);
- EXPECT_EQ(OK, req2->Resolve());
+ EXPECT_THAT(req2->Resolve(), IsOk());
EXPECT_TRUE(req2->HasOneAddress("::1", 80));
Request* req3 = CreateRequest("nx_both", 80);
- EXPECT_EQ(OK, req3->Resolve());
+ EXPECT_THAT(req3->Resolve(), IsOk());
EXPECT_TRUE(req3->HasAddress("127.0.0.1", 80) &&
req3->HasAddress("::1", 80));
// Requests with specified AddressFamily.
Request* req4 = CreateRequest("nx_ipv4", 80, MEDIUM, ADDRESS_FAMILY_IPV4);
- EXPECT_EQ(OK, req4->Resolve());
+ EXPECT_THAT(req4->Resolve(), IsOk());
EXPECT_TRUE(req4->HasOneAddress("127.0.0.1", 80));
Request* req5 = CreateRequest("nx_ipv6", 80, MEDIUM, ADDRESS_FAMILY_IPV6);
- EXPECT_EQ(OK, req5->Resolve());
+ EXPECT_THAT(req5->Resolve(), IsOk());
EXPECT_TRUE(req5->HasOneAddress("::1", 80));
// Request with upper case.
Request* req6 = CreateRequest("nx_IPV4", 80);
- EXPECT_EQ(OK, req6->Resolve());
+ EXPECT_THAT(req6->Resolve(), IsOk());
EXPECT_TRUE(req6->HasOneAddress("127.0.0.1", 80));
}
@@ -1827,11 +1852,14 @@ TEST_F(HostResolverImplDnsTest, BypassDnsTask) {
proc_->AddRuleForAllFamilies(std::string(),
std::string()); // Default to failures.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok.local", 80)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok.local.", 80)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("oklocal", 80)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("oklocal.", 80)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
+ EXPECT_THAT(CreateRequest("ok.local", 80)->Resolve(),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("ok.local.", 80)->Resolve(),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("oklocal", 80)->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("oklocal.", 80)->Resolve(),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("ok", 80)->Resolve(), IsError(ERR_IO_PENDING));
proc_->SignalMultiple(requests_.size());
@@ -1849,15 +1877,16 @@ TEST_F(HostResolverImplDnsTest, SystemOnlyBypassesDnsTask) {
HostResolver::RequestInfo info_bypass(HostPortPair("ok", 80));
info_bypass.set_host_resolver_flags(HOST_RESOLVER_SYSTEM_ONLY);
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info_bypass, MEDIUM)->Resolve());
+ EXPECT_THAT(CreateRequest(info_bypass, MEDIUM)->Resolve(),
+ IsError(ERR_IO_PENDING));
HostResolver::RequestInfo info(HostPortPair("ok", 80));
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info, MEDIUM)->Resolve());
+ EXPECT_THAT(CreateRequest(info, MEDIUM)->Resolve(), IsError(ERR_IO_PENDING));
proc_->SignalMultiple(requests_.size());
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, requests_[0]->WaitForResult());
- EXPECT_EQ(OK, requests_[1]->WaitForResult());
+ EXPECT_THAT(requests_[0]->WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED));
+ EXPECT_THAT(requests_[1]->WaitForResult(), IsOk());
}
TEST_F(HostResolverImplDnsTest, DisableDnsClientOnPersistentFailure) {
@@ -1868,8 +1897,8 @@ TEST_F(HostResolverImplDnsTest, DisableDnsClientOnPersistentFailure) {
// Check that DnsTask works.
Request* req = CreateRequest("ok_1", 80);
- EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
- EXPECT_EQ(OK, req->WaitForResult());
+ EXPECT_THAT(req->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(req->WaitForResult(), IsOk());
for (unsigned i = 0; i < maximum_dns_failures(); ++i) {
// Use custom names to require separate Jobs.
@@ -1888,15 +1917,15 @@ TEST_F(HostResolverImplDnsTest, DisableDnsClientOnPersistentFailure) {
// DnsTask should be disabled by now.
req = CreateRequest("ok_2", 80);
- EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
+ EXPECT_THAT(req->Resolve(), IsError(ERR_IO_PENDING));
proc_->SignalMultiple(1u);
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req->WaitForResult());
+ EXPECT_THAT(req->WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED));
// Check that it is re-enabled after DNS change.
ChangeDnsConfig(CreateValidDnsConfig());
req = CreateRequest("ok_3", 80);
- EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
- EXPECT_EQ(OK, req->WaitForResult());
+ EXPECT_THAT(req->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(req->WaitForResult(), IsOk());
}
TEST_F(HostResolverImplDnsTest, DontDisableDnsClientOnSporadicFailure) {
@@ -1922,8 +1951,8 @@ TEST_F(HostResolverImplDnsTest, DontDisableDnsClientOnSporadicFailure) {
// DnsTask should still be enabled.
Request* req = CreateRequest("ok_last", 80);
- EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
- EXPECT_EQ(OK, req->WaitForResult());
+ EXPECT_THAT(req->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(req->WaitForResult(), IsOk());
}
// Confirm that resolving "localhost" is unrestricted even if there are no
@@ -1962,7 +1991,7 @@ TEST_F(HostResolverImplDnsTest, DualFamilyLocalhost) {
info_proc.set_host_resolver_flags(HOST_RESOLVER_SYSTEM_ONLY);
Request* req = CreateRequest(info_proc, DEFAULT_PRIORITY);
- EXPECT_EQ(OK, req->Resolve());
+ EXPECT_THAT(req->Resolve(), IsOk());
EXPECT_TRUE(req->HasAddress("127.0.0.1", 80));
EXPECT_TRUE(req->HasAddress("::1", 80));
@@ -1983,7 +2012,7 @@ TEST_F(HostResolverImplDnsTest, DualFamilyLocalhost) {
info_hosts.set_address_family(ADDRESS_FAMILY_UNSPECIFIED);
req = CreateRequest(info_hosts, DEFAULT_PRIORITY);
// Expect synchronous resolution from DnsHosts.
- EXPECT_EQ(OK, req->Resolve());
+ EXPECT_THAT(req->Resolve(), IsOk());
EXPECT_EQ(saw_ipv4, req->HasAddress("127.0.0.1", 80));
EXPECT_EQ(saw_ipv6, req->HasAddress("::1", 80));
@@ -2006,7 +2035,7 @@ TEST_F(HostResolverImplDnsTest, CancelWithOneTransactionActiveOnePending) {
CreateSerialResolver();
ChangeDnsConfig(CreateValidDnsConfig());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
+ EXPECT_THAT(CreateRequest("ok", 80)->Resolve(), IsError(ERR_IO_PENDING));
EXPECT_EQ(1u, num_running_dispatcher_jobs());
requests_[0]->Cancel();
@@ -2017,7 +2046,7 @@ TEST_F(HostResolverImplDnsTest, CancelWithOneTransactionActiveOnePending) {
TEST_F(HostResolverImplDnsTest, CancelWithTwoTransactionsActive) {
ChangeDnsConfig(CreateValidDnsConfig());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
+ EXPECT_THAT(CreateRequest("ok", 80)->Resolve(), IsError(ERR_IO_PENDING));
EXPECT_EQ(2u, num_running_dispatcher_jobs());
requests_[0]->Cancel();
@@ -2051,7 +2080,8 @@ TEST_F(HostResolverImplDnsTest, DeleteWithActiveTransactions) {
TEST_F(HostResolverImplDnsTest, CancelWithIPv6TransactionActive) {
ChangeDnsConfig(CreateValidDnsConfig());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("6slow_ok", 80)->Resolve());
+ EXPECT_THAT(CreateRequest("6slow_ok", 80)->Resolve(),
+ IsError(ERR_IO_PENDING));
EXPECT_EQ(2u, num_running_dispatcher_jobs());
// The IPv4 request should complete, the IPv6 request is still pending.
@@ -2067,7 +2097,8 @@ TEST_F(HostResolverImplDnsTest, CancelWithIPv4TransactionPending) {
set_fallback_to_proctask(false);
ChangeDnsConfig(CreateValidDnsConfig());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_ok", 80)->Resolve());
+ EXPECT_THAT(CreateRequest("4slow_ok", 80)->Resolve(),
+ IsError(ERR_IO_PENDING));
EXPECT_EQ(2u, num_running_dispatcher_jobs());
// The IPv6 request should complete, the IPv4 request is still pending.
@@ -2082,10 +2113,14 @@ TEST_F(HostResolverImplDnsTest, AAAACompletesFirst) {
set_fallback_to_proctask(false);
ChangeDnsConfig(CreateValidDnsConfig());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_ok", 80)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_4ok", 80)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_4timeout", 80)->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_6timeout", 80)->Resolve());
+ EXPECT_THAT(CreateRequest("4slow_ok", 80)->Resolve(),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("4slow_4ok", 80)->Resolve(),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("4slow_4timeout", 80)->Resolve(),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("4slow_6timeout", 80)->Resolve(),
+ IsError(ERR_IO_PENDING));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(requests_[0]->completed());
@@ -2094,23 +2129,23 @@ TEST_F(HostResolverImplDnsTest, AAAACompletesFirst) {
// The IPv6 of the third request should have failed and resulted in cancelling
// the IPv4 request.
EXPECT_TRUE(requests_[3]->completed());
- EXPECT_EQ(ERR_DNS_TIMED_OUT, requests_[3]->result());
+ EXPECT_THAT(requests_[3]->result(), IsError(ERR_DNS_TIMED_OUT));
EXPECT_EQ(3u, num_running_dispatcher_jobs());
dns_client_->CompleteDelayedTransactions();
EXPECT_TRUE(requests_[0]->completed());
- EXPECT_EQ(OK, requests_[0]->result());
+ EXPECT_THAT(requests_[0]->result(), IsOk());
EXPECT_EQ(2u, requests_[0]->NumberOfAddresses());
EXPECT_TRUE(requests_[0]->HasAddress("127.0.0.1", 80));
EXPECT_TRUE(requests_[0]->HasAddress("::1", 80));
EXPECT_TRUE(requests_[1]->completed());
- EXPECT_EQ(OK, requests_[1]->result());
+ EXPECT_THAT(requests_[1]->result(), IsOk());
EXPECT_EQ(1u, requests_[1]->NumberOfAddresses());
EXPECT_TRUE(requests_[1]->HasAddress("127.0.0.1", 80));
EXPECT_TRUE(requests_[2]->completed());
- EXPECT_EQ(ERR_DNS_TIMED_OUT, requests_[2]->result());
+ EXPECT_THAT(requests_[2]->result(), IsError(ERR_DNS_TIMED_OUT));
}
// Test the case where only a single transaction slot is available.
@@ -2119,12 +2154,12 @@ TEST_F(HostResolverImplDnsTest, SerialResolver) {
set_fallback_to_proctask(false);
ChangeDnsConfig(CreateValidDnsConfig());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
+ EXPECT_THAT(CreateRequest("ok", 80)->Resolve(), IsError(ERR_IO_PENDING));
EXPECT_EQ(1u, num_running_dispatcher_jobs());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(requests_[0]->completed());
- EXPECT_EQ(OK, requests_[0]->result());
+ EXPECT_THAT(requests_[0]->result(), IsOk());
EXPECT_EQ(2u, requests_[0]->NumberOfAddresses());
EXPECT_TRUE(requests_[0]->HasAddress("127.0.0.1", 80));
EXPECT_TRUE(requests_[0]->HasAddress("::1", 80));
@@ -2153,7 +2188,7 @@ TEST_F(HostResolverImplDnsTest, AAAAStartsAfterOtherJobFinishes) {
dns_client_->CompleteDelayedTransactions();
EXPECT_TRUE(requests_[1]->completed());
- EXPECT_EQ(OK, requests_[1]->result());
+ EXPECT_THAT(requests_[1]->result(), IsOk());
EXPECT_EQ(2u, requests_[1]->NumberOfAddresses());
EXPECT_TRUE(requests_[1]->HasAddress("127.0.0.1", 80));
EXPECT_TRUE(requests_[1]->HasAddress("::1", 80));
@@ -2168,7 +2203,7 @@ TEST_F(HostResolverImplDnsTest, IPv4EmptyFallback) {
EXPECT_EQ(ERR_IO_PENDING,
CreateRequest("empty_fallback", 80, MEDIUM,
ADDRESS_FAMILY_IPV4)->Resolve());
- EXPECT_EQ(OK, requests_[0]->WaitForResult());
+ EXPECT_THAT(requests_[0]->WaitForResult(), IsOk());
EXPECT_TRUE(requests_[0]->HasOneAddress("192.168.0.1", 80));
}
@@ -2181,7 +2216,7 @@ TEST_F(HostResolverImplDnsTest, UnspecEmptyFallback) {
EXPECT_EQ(ERR_IO_PENDING,
CreateRequest("empty_fallback", 80, MEDIUM,
ADDRESS_FAMILY_UNSPECIFIED)->Resolve());
- EXPECT_EQ(OK, requests_[0]->WaitForResult());
+ EXPECT_THAT(requests_[0]->WaitForResult(), IsOk());
EXPECT_TRUE(requests_[0]->HasOneAddress("192.168.0.1", 80));
}
@@ -2200,24 +2235,24 @@ TEST_F(HostResolverImplDnsTest, InvalidDnsConfigWithPendingRequests) {
proc_->AddRuleForAllFamilies("ok", "192.168.0.3");
// First active job gets two slots.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_nx1")->Resolve());
+ EXPECT_THAT(CreateRequest("slow_nx1")->Resolve(), IsError(ERR_IO_PENDING));
// Next job gets one slot, and waits on another.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_nx2")->Resolve());
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok")->Resolve());
+ EXPECT_THAT(CreateRequest("slow_nx2")->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(CreateRequest("ok")->Resolve(), IsError(ERR_IO_PENDING));
EXPECT_EQ(3u, num_running_dispatcher_jobs());
// Clear DNS config. Two in-progress jobs should be aborted, and the next one
// should use a ProcTask.
ChangeDnsConfig(DnsConfig());
- EXPECT_EQ(ERR_NETWORK_CHANGED, requests_[0]->WaitForResult());
- EXPECT_EQ(ERR_NETWORK_CHANGED, requests_[1]->WaitForResult());
+ EXPECT_THAT(requests_[0]->WaitForResult(), IsError(ERR_NETWORK_CHANGED));
+ EXPECT_THAT(requests_[1]->WaitForResult(), IsError(ERR_NETWORK_CHANGED));
// Finish up the third job. Should bypass the DnsClient, and get its results
// from MockHostResolverProc.
EXPECT_FALSE(requests_[2]->completed());
proc_->SignalMultiple(1u);
- EXPECT_EQ(OK, requests_[2]->WaitForResult());
+ EXPECT_THAT(requests_[2]->WaitForResult(), IsOk());
EXPECT_TRUE(requests_[2]->HasOneAddress("192.168.0.3", 80));
}
@@ -2240,31 +2275,31 @@ TEST_F(HostResolverImplDnsTest,
for (unsigned i = 0u; i < maximum_dns_failures(); ++i) {
std::string host = base::StringPrintf("nx%u", i);
proc_->AddRuleForAllFamilies(host, "192.168.0.1");
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest(host)->Resolve());
+ EXPECT_THAT(CreateRequest(host)->Resolve(), IsError(ERR_IO_PENDING));
}
// These requests should all bypass DnsTasks, due to the above failures,
// so should end up using ProcTasks.
proc_->AddRuleForAllFamilies("slow_ok1", "192.168.0.2");
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_ok1")->Resolve());
+ EXPECT_THAT(CreateRequest("slow_ok1")->Resolve(), IsError(ERR_IO_PENDING));
proc_->AddRuleForAllFamilies("slow_ok2", "192.168.0.3");
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_ok2")->Resolve());
+ EXPECT_THAT(CreateRequest("slow_ok2")->Resolve(), IsError(ERR_IO_PENDING));
proc_->AddRuleForAllFamilies("slow_ok3", "192.168.0.4");
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_ok3")->Resolve());
+ EXPECT_THAT(CreateRequest("slow_ok3")->Resolve(), IsError(ERR_IO_PENDING));
proc_->SignalMultiple(maximum_dns_failures() + 3);
for (size_t i = 0u; i < maximum_dns_failures(); ++i) {
- EXPECT_EQ(OK, requests_[i]->WaitForResult());
+ EXPECT_THAT(requests_[i]->WaitForResult(), IsOk());
EXPECT_TRUE(requests_[i]->HasOneAddress("192.168.0.1", 80));
}
- EXPECT_EQ(OK, requests_[maximum_dns_failures()]->WaitForResult());
+ EXPECT_THAT(requests_[maximum_dns_failures()]->WaitForResult(), IsOk());
EXPECT_TRUE(requests_[maximum_dns_failures()]->HasOneAddress(
"192.168.0.2", 80));
- EXPECT_EQ(OK, requests_[maximum_dns_failures() + 1]->WaitForResult());
+ EXPECT_THAT(requests_[maximum_dns_failures() + 1]->WaitForResult(), IsOk());
EXPECT_TRUE(requests_[maximum_dns_failures() + 1]->HasOneAddress(
"192.168.0.3", 80));
- EXPECT_EQ(OK, requests_[maximum_dns_failures() + 2]->WaitForResult());
+ EXPECT_THAT(requests_[maximum_dns_failures() + 2]->WaitForResult(), IsOk());
EXPECT_TRUE(requests_[maximum_dns_failures() + 2]->HasOneAddress(
"192.168.0.4", 80));
requests_.clear();
@@ -2286,11 +2321,11 @@ TEST_F(HostResolverImplDnsTest, ManuallyDisableDnsClientWithPendingRequests) {
proc_->AddRuleForAllFamilies("ok", "192.168.0.3");
// First active job gets two slots.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_ok1")->Resolve());
+ EXPECT_THAT(CreateRequest("slow_ok1")->Resolve(), IsError(ERR_IO_PENDING));
// Next job gets one slot, and waits on another.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_ok2")->Resolve());
+ EXPECT_THAT(CreateRequest("slow_ok2")->Resolve(), IsError(ERR_IO_PENDING));
// Next one is queued.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok")->Resolve());
+ EXPECT_THAT(CreateRequest("ok")->Resolve(), IsError(ERR_IO_PENDING));
EXPECT_EQ(3u, num_running_dispatcher_jobs());
@@ -2302,11 +2337,11 @@ TEST_F(HostResolverImplDnsTest, ManuallyDisableDnsClientWithPendingRequests) {
EXPECT_EQ(3u, num_running_dispatcher_jobs());
proc_->SignalMultiple(3u);
- EXPECT_EQ(OK, requests_[0]->WaitForResult());
+ EXPECT_THAT(requests_[0]->WaitForResult(), IsOk());
EXPECT_TRUE(requests_[0]->HasOneAddress("192.168.0.1", 80));
- EXPECT_EQ(OK, requests_[1]->WaitForResult());
+ EXPECT_THAT(requests_[1]->WaitForResult(), IsOk());
EXPECT_TRUE(requests_[1]->HasOneAddress("192.168.0.2", 80));
- EXPECT_EQ(OK, requests_[2]->WaitForResult());
+ EXPECT_THAT(requests_[2]->WaitForResult(), IsOk());
EXPECT_TRUE(requests_[2]->HasOneAddress("192.168.0.3", 80));
}
@@ -2368,4 +2403,63 @@ TEST_F(HostResolverImplTest, ResolveLocalHostname) {
ResolveLocalHostname("foo.localhoste", kLocalhostLookupPort, &addresses));
}
+void TestCacheHitCallback(int* callback_count,
+ HostResolver::RequestInfo* last_request_info,
+ const HostResolver::RequestInfo& request_info) {
+ ++*callback_count;
+ *last_request_info = request_info;
+}
+
+TEST_F(HostResolverImplTest, CacheHitCallback) {
+ proc_->AddRuleForAllFamilies("just.testing", "192.168.1.42");
+ proc_->SignalMultiple(5u);
+
+ HostResolver::RequestInfo last_request_info(HostPortPair("unassigned", 80));
+
+ // Set a cache hit callback.
+ int count1 = 0;
+ HostResolver::RequestInfo info_callback1(HostPortPair("just.testing", 80));
+ info_callback1.set_cache_hit_callback(
+ base::Bind(&TestCacheHitCallback, &count1, &last_request_info));
+ Request* req = CreateRequest(info_callback1, MEDIUM);
+ EXPECT_THAT(req->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(req->WaitForResult(), IsOk());
+ EXPECT_EQ(0, count1);
+
+ // Make sure the cache hit callback is called, and set another one.
+ // Future requests should call *both* callbacks.
+ int count2 = 0;
+ HostResolver::RequestInfo info_callback2(HostPortPair("just.testing", 80));
+ info_callback2.set_cache_hit_callback(
+ base::Bind(&TestCacheHitCallback, &count2, &last_request_info));
+ req = CreateRequest(info_callback2, MEDIUM);
+ EXPECT_THAT(req->Resolve(), IsOk());
+ EXPECT_EQ(1, count1);
+ EXPECT_EQ(0, count2);
+
+ // Make another request to make sure both callbacks are called.
+ req = CreateRequest("just.testing", 80);
+ EXPECT_THAT(req->Resolve(), IsOk());
+ EXPECT_EQ(2, count1);
+ EXPECT_EQ(1, count2);
+
+ // Make an uncached request to clear the cache hit callbacks.
+ // (They should be cleared because the uncached request will write a new
+ // result into the cache.)
+ // It should not call the callbacks itself, since it doesn't hit the cache.
+ HostResolver::RequestInfo info_uncached(HostPortPair("just.testing", 80));
+ info_uncached.set_allow_cached_response(false);
+ req = CreateRequest(info_uncached, MEDIUM);
+ EXPECT_THAT(req->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(req->WaitForResult(), IsOk());
+ EXPECT_EQ(2, count1);
+ EXPECT_EQ(1, count2);
+
+ // Make another request to make sure both callbacks were cleared.
+ req = CreateRequest("just.testing", 80);
+ EXPECT_THAT(req->Resolve(), IsOk());
+ EXPECT_EQ(2, count1);
+ EXPECT_EQ(1, count2);
+}
+
} // namespace net
diff --git a/chromium/net/dns/host_resolver_mojo.cc b/chromium/net/dns/host_resolver_mojo.cc
index 42801461c0a..aeca31baf2e 100644
--- a/chromium/net/dns/host_resolver_mojo.cc
+++ b/chromium/net/dns/host_resolver_mojo.cc
@@ -6,11 +6,11 @@
#include <utility>
+#include "base/callback_helpers.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "net/base/address_list.h"
#include "net/base/net_errors.h"
#include "net/dns/mojo_host_type_converters.h"
-#include "net/log/net_log.h"
namespace net {
namespace {
@@ -51,6 +51,18 @@ class HostResolverMojo::Job : public interfaces::HostResolverRequestClient {
base::WeakPtr<HostCache> host_cache_;
};
+class HostResolverMojo::RequestImpl : public HostResolver::Request {
+ public:
+ explicit RequestImpl(std::unique_ptr<Job> job) : job_(std::move(job)) {}
+
+ ~RequestImpl() override {}
+
+ void ChangeRequestPriority(RequestPriority priority) override {}
+
+ private:
+ std::unique_ptr<Job> job_;
+};
+
HostResolverMojo::HostResolverMojo(Impl* impl)
: impl_(impl),
host_cache_(HostCache::CreateDefaultCache()),
@@ -63,9 +75,10 @@ int HostResolverMojo::Resolve(const RequestInfo& info,
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* request_handle,
- const BoundNetLog& source_net_log) {
+ std::unique_ptr<Request>* request,
+ const NetLogWithSource& source_net_log) {
DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(request);
DVLOG(1) << "Resolve " << info.host_port_pair().ToString();
HostCache::Key key = CacheKeyForRequest(info);
@@ -77,8 +90,11 @@ int HostResolverMojo::Resolve(const RequestInfo& info,
}
interfaces::HostResolverRequestClientPtr handle;
- *request_handle = new Job(key, addresses, callback, mojo::GetProxy(&handle),
- host_cache_weak_factory_.GetWeakPtr());
+ std::unique_ptr<Job> job(new Job(key, addresses, callback,
+ mojo::GetProxy(&handle),
+ host_cache_weak_factory_.GetWeakPtr()));
+ request->reset(new RequestImpl(std::move(job)));
+
impl_->ResolveDns(interfaces::HostResolverRequestInfo::From(info),
std::move(handle));
return ERR_IO_PENDING;
@@ -86,24 +102,12 @@ int HostResolverMojo::Resolve(const RequestInfo& info,
int HostResolverMojo::ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& source_net_log) {
+ const NetLogWithSource& source_net_log) {
DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(1) << "ResolveFromCache " << info.host_port_pair().ToString();
return ResolveFromCacheInternal(info, CacheKeyForRequest(info), addresses);
}
-void HostResolverMojo::ChangeRequestPriority(RequestHandle req,
- RequestPriority priority) {
- // Do nothing, since Resolve() discarded the priority anyway.
-}
-
-void HostResolverMojo::CancelRequest(RequestHandle req) {
- DCHECK(thread_checker_.CalledOnValidThread());
- // Deleting the Job closes the HostResolverRequestClient connection,
- // signalling cancellation of the request.
- delete static_cast<Job*>(req);
-}
-
HostCache* HostResolverMojo::GetHostCache() {
return host_cache_.get();
}
@@ -149,8 +153,9 @@ void HostResolverMojo::Job::ReportResult(
HostCache::Entry entry(error, *addresses_, ttl);
host_cache_->Set(key_, entry, base::TimeTicks::Now(), ttl);
}
- callback_.Run(error);
- delete this;
+ if (binding_.is_bound())
+ binding_.Close();
+ base::ResetAndReturn(&callback_).Run(error);
}
void HostResolverMojo::Job::OnConnectionError() {
diff --git a/chromium/net/dns/host_resolver_mojo.h b/chromium/net/dns/host_resolver_mojo.h
index 08519d2fc42..de674990d16 100644
--- a/chromium/net/dns/host_resolver_mojo.h
+++ b/chromium/net/dns/host_resolver_mojo.h
@@ -14,7 +14,7 @@
namespace net {
class AddressList;
-class BoundNetLog;
+class NetLogWithSource;
// A HostResolver implementation that converts requests to mojo types and
// forwards them to a mojo Impl interface.
@@ -37,18 +37,16 @@ class HostResolverMojo : public HostResolver {
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* request_handle,
- const BoundNetLog& source_net_log) override;
+ std::unique_ptr<Request>* request,
+ const NetLogWithSource& source_net_log) override;
int ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& source_net_log) override;
- void ChangeRequestPriority(RequestHandle req,
- RequestPriority priority) override;
- void CancelRequest(RequestHandle req) override;
+ const NetLogWithSource& source_net_log) override;
HostCache* GetHostCache() override;
private:
class Job;
+ class RequestImpl;
int ResolveFromCacheInternal(const RequestInfo& info,
const HostCache::Key& key,
diff --git a/chromium/net/dns/host_resolver_mojo_unittest.cc b/chromium/net/dns/host_resolver_mojo_unittest.cc
index 0c791a101f3..eac52768625 100644
--- a/chromium/net/dns/host_resolver_mojo_unittest.cc
+++ b/chromium/net/dns/host_resolver_mojo_unittest.cc
@@ -15,9 +15,15 @@
#include "net/base/request_priority.h"
#include "net/base/test_completion_callback.h"
#include "net/dns/mojo_host_type_converters.h"
+#include "net/log/net_log_with_source.h"
#include "net/test/event_waiter.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -161,17 +167,18 @@ class HostResolverMojoTest : public testing::Test {
int Resolve(const HostResolver::RequestInfo& request_info,
AddressList* result) {
- HostResolver::RequestHandle request_handle = nullptr;
TestCompletionCallback callback;
- return callback.GetResult(resolver_->Resolve(
- request_info, DEFAULT_PRIORITY, result, callback.callback(),
- &request_handle, BoundNetLog()));
+ return callback.GetResult(
+ resolver_->Resolve(request_info, DEFAULT_PRIORITY, result,
+ callback.callback(), &request_, NetLogWithSource()));
}
std::unique_ptr<MockMojoHostResolver> mock_resolver_;
std::unique_ptr<HostResolverMojo> resolver_;
+ std::unique_ptr<HostResolver::Request> request_;
+
Waiter waiter_;
};
@@ -185,7 +192,7 @@ TEST_F(HostResolverMojoTest, Basic) {
HostResolver::RequestInfo request_info(
HostPortPair::FromString("example.com:12345"));
AddressList result;
- EXPECT_EQ(OK, Resolve(request_info, &result));
+ EXPECT_THAT(Resolve(request_info, &result), IsOk());
ASSERT_EQ(2u, result.size());
EXPECT_EQ(address_list[0], result[0]);
EXPECT_EQ(address_list[1], result[1]);
@@ -208,12 +215,12 @@ TEST_F(HostResolverMojoTest, ResolveCachedResult) {
HostResolver::RequestInfo request_info(
HostPortPair::FromString("example.com:12345"));
AddressList result;
- ASSERT_EQ(OK, Resolve(request_info, &result));
+ ASSERT_THAT(Resolve(request_info, &result), IsOk());
ASSERT_EQ(1u, mock_resolver_->requests().size());
result.clear();
request_info.set_host_port_pair(HostPortPair::FromString("example.com:6789"));
- EXPECT_EQ(OK, Resolve(request_info, &result));
+ EXPECT_THAT(Resolve(request_info, &result), IsOk());
ASSERT_EQ(2u, result.size());
address_list.clear();
address_list.push_back(IPEndPoint(address, 6789));
@@ -226,7 +233,7 @@ TEST_F(HostResolverMojoTest, ResolveCachedResult) {
mock_resolver_->AddAction(HostResolverAction::ReturnResult(address_list));
result.clear();
request_info.set_allow_cached_response(false);
- EXPECT_EQ(OK, Resolve(request_info, &result));
+ EXPECT_THAT(Resolve(request_info, &result), IsOk());
ASSERT_EQ(2u, result.size());
EXPECT_EQ(address_list[0], result[0]);
EXPECT_EQ(address_list[1], result[1]);
@@ -249,37 +256,34 @@ TEST_F(HostResolverMojoTest, Multiple) {
request_info2.set_address_family(ADDRESS_FAMILY_IPV6);
AddressList result1;
AddressList result2;
- HostResolver::RequestHandle request_handle1 = nullptr;
- HostResolver::RequestHandle request_handle2 = nullptr;
+ std::unique_ptr<HostResolver::Request> request1;
+ std::unique_ptr<HostResolver::Request> request2;
TestCompletionCallback callback1;
TestCompletionCallback callback2;
- ASSERT_EQ(ERR_IO_PENDING,
- resolver_->Resolve(request_info1, DEFAULT_PRIORITY, &result1,
- callback1.callback(), &request_handle1,
- BoundNetLog()));
- ASSERT_EQ(ERR_IO_PENDING,
- resolver_->Resolve(request_info2, DEFAULT_PRIORITY, &result2,
- callback2.callback(), &request_handle2,
- BoundNetLog()));
- EXPECT_EQ(OK, callback1.GetResult(ERR_IO_PENDING));
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback2.GetResult(ERR_IO_PENDING));
+ ASSERT_EQ(ERR_IO_PENDING, resolver_->Resolve(request_info1, DEFAULT_PRIORITY,
+ &result1, callback1.callback(),
+ &request1, NetLogWithSource()));
+ ASSERT_EQ(ERR_IO_PENDING, resolver_->Resolve(request_info2, DEFAULT_PRIORITY,
+ &result2, callback2.callback(),
+ &request2, NetLogWithSource()));
+ EXPECT_THAT(callback1.GetResult(ERR_IO_PENDING), IsOk());
+ EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING),
+ IsError(ERR_NAME_NOT_RESOLVED));
ASSERT_EQ(1u, result1.size());
EXPECT_EQ(address_list[0], result1[0]);
ASSERT_EQ(0u, result2.size());
ASSERT_EQ(2u, mock_resolver_->requests().size());
- interfaces::HostResolverRequestInfo& request1 =
- *mock_resolver_->requests()[0];
- EXPECT_EQ("example.com", request1.host.To<std::string>());
- EXPECT_EQ(12345, request1.port);
- EXPECT_EQ(interfaces::AddressFamily::IPV4, request1.address_family);
- EXPECT_TRUE(request1.is_my_ip_address);
- interfaces::HostResolverRequestInfo& request2 =
- *mock_resolver_->requests()[1];
- EXPECT_EQ("example.org", request2.host.To<std::string>());
- EXPECT_EQ(80, request2.port);
- EXPECT_EQ(interfaces::AddressFamily::IPV6, request2.address_family);
- EXPECT_FALSE(request2.is_my_ip_address);
+ interfaces::HostResolverRequestInfo& info1 = *mock_resolver_->requests()[0];
+ EXPECT_EQ("example.com", info1.host.To<std::string>());
+ EXPECT_EQ(12345, info1.port);
+ EXPECT_EQ(interfaces::AddressFamily::IPV4, info1.address_family);
+ EXPECT_TRUE(info1.is_my_ip_address);
+ interfaces::HostResolverRequestInfo& info2 = *mock_resolver_->requests()[1];
+ EXPECT_EQ("example.org", info2.host.To<std::string>());
+ EXPECT_EQ(80, info2.port);
+ EXPECT_EQ(interfaces::AddressFamily::IPV6, info2.address_family);
+ EXPECT_FALSE(info2.is_my_ip_address);
}
TEST_F(HostResolverMojoTest, Error) {
@@ -289,7 +293,7 @@ TEST_F(HostResolverMojoTest, Error) {
HostPortPair::FromString("example.com:8080"));
request_info.set_address_family(ADDRESS_FAMILY_IPV4);
AddressList result;
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, Resolve(request_info, &result));
+ EXPECT_THAT(Resolve(request_info, &result), IsError(ERR_NAME_NOT_RESOLVED));
EXPECT_TRUE(result.empty());
ASSERT_EQ(1u, mock_resolver_->requests().size());
@@ -305,7 +309,7 @@ TEST_F(HostResolverMojoTest, EmptyResult) {
HostResolver::RequestInfo request_info(
HostPortPair::FromString("example.com:8080"));
AddressList result;
- EXPECT_EQ(OK, Resolve(request_info, &result));
+ EXPECT_THAT(Resolve(request_info, &result), IsOk());
EXPECT_TRUE(result.empty());
ASSERT_EQ(1u, mock_resolver_->requests().size());
@@ -317,19 +321,19 @@ TEST_F(HostResolverMojoTest, Cancel) {
HostPortPair::FromString("example.com:80"));
request_info.set_address_family(ADDRESS_FAMILY_IPV6);
AddressList result;
- HostResolver::RequestHandle request_handle = nullptr;
+ std::unique_ptr<HostResolver::Request> request;
resolver_->Resolve(request_info, DEFAULT_PRIORITY, &result, base::Bind(&Fail),
- &request_handle, BoundNetLog());
- resolver_->CancelRequest(request_handle);
+ &request, NetLogWithSource());
+ request.reset();
waiter_.WaitForEvent(ConnectionErrorSource::REQUEST);
EXPECT_TRUE(result.empty());
ASSERT_EQ(1u, mock_resolver_->requests().size());
- interfaces::HostResolverRequestInfo& request = *mock_resolver_->requests()[0];
- EXPECT_EQ("example.com", request.host.To<std::string>());
- EXPECT_EQ(80, request.port);
- EXPECT_EQ(interfaces::AddressFamily::IPV6, request.address_family);
- EXPECT_FALSE(request.is_my_ip_address);
+ interfaces::HostResolverRequestInfo& info1 = *mock_resolver_->requests()[0];
+ EXPECT_EQ("example.com", info1.host.To<std::string>());
+ EXPECT_EQ(80, info1.port);
+ EXPECT_EQ(interfaces::AddressFamily::IPV6, info1.address_family);
+ EXPECT_FALSE(info1.is_my_ip_address);
}
TEST_F(HostResolverMojoTest, ImplDropsClientConnection) {
@@ -337,23 +341,23 @@ TEST_F(HostResolverMojoTest, ImplDropsClientConnection) {
HostResolver::RequestInfo request_info(
HostPortPair::FromString("example.com:1"));
AddressList result;
- EXPECT_EQ(ERR_FAILED, Resolve(request_info, &result));
+ EXPECT_THAT(Resolve(request_info, &result), IsError(ERR_FAILED));
EXPECT_TRUE(result.empty());
ASSERT_EQ(1u, mock_resolver_->requests().size());
- interfaces::HostResolverRequestInfo& request = *mock_resolver_->requests()[0];
- EXPECT_EQ("example.com", request.host.To<std::string>());
- EXPECT_EQ(1, request.port);
- EXPECT_EQ(interfaces::AddressFamily::UNSPECIFIED, request.address_family);
- EXPECT_FALSE(request.is_my_ip_address);
+ interfaces::HostResolverRequestInfo& info2 = *mock_resolver_->requests()[0];
+ EXPECT_EQ("example.com", info2.host.To<std::string>());
+ EXPECT_EQ(1, info2.port);
+ EXPECT_EQ(interfaces::AddressFamily::UNSPECIFIED, info2.address_family);
+ EXPECT_FALSE(info2.is_my_ip_address);
}
TEST_F(HostResolverMojoTest, ResolveFromCache_Miss) {
HostResolver::RequestInfo request_info(
HostPortPair::FromString("example.com:8080"));
AddressList result;
- EXPECT_EQ(ERR_DNS_CACHE_MISS,
- resolver_->ResolveFromCache(request_info, &result, BoundNetLog()));
+ EXPECT_EQ(ERR_DNS_CACHE_MISS, resolver_->ResolveFromCache(
+ request_info, &result, NetLogWithSource()));
EXPECT_TRUE(result.empty());
}
@@ -367,12 +371,12 @@ TEST_F(HostResolverMojoTest, ResolveFromCache_Hit) {
HostResolver::RequestInfo request_info(
HostPortPair::FromString("example.com:12345"));
AddressList result;
- ASSERT_EQ(OK, Resolve(request_info, &result));
+ ASSERT_THAT(Resolve(request_info, &result), IsOk());
EXPECT_EQ(1u, mock_resolver_->requests().size());
result.clear();
- EXPECT_EQ(OK,
- resolver_->ResolveFromCache(request_info, &result, BoundNetLog()));
+ EXPECT_EQ(OK, resolver_->ResolveFromCache(request_info, &result,
+ NetLogWithSource()));
ASSERT_EQ(2u, result.size());
EXPECT_EQ(address_list[0], result[0]);
EXPECT_EQ(address_list[1], result[1]);
@@ -389,13 +393,13 @@ TEST_F(HostResolverMojoTest, ResolveFromCache_CacheNotAllowed) {
HostResolver::RequestInfo request_info(
HostPortPair::FromString("example.com:12345"));
AddressList result;
- ASSERT_EQ(OK, Resolve(request_info, &result));
+ ASSERT_THAT(Resolve(request_info, &result), IsOk());
EXPECT_EQ(1u, mock_resolver_->requests().size());
result.clear();
request_info.set_allow_cached_response(false);
- EXPECT_EQ(ERR_DNS_CACHE_MISS,
- resolver_->ResolveFromCache(request_info, &result, BoundNetLog()));
+ EXPECT_EQ(ERR_DNS_CACHE_MISS, resolver_->ResolveFromCache(
+ request_info, &result, NetLogWithSource()));
EXPECT_TRUE(result.empty());
}
diff --git a/chromium/net/dns/mapped_host_resolver.cc b/chromium/net/dns/mapped_host_resolver.cc
index e102d502444..e29c85ea75c 100644
--- a/chromium/net/dns/mapped_host_resolver.cc
+++ b/chromium/net/dns/mapped_host_resolver.cc
@@ -23,19 +23,19 @@ int MappedHostResolver::Resolve(const RequestInfo& original_info,
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) {
+ std::unique_ptr<Request>* request,
+ const NetLogWithSource& net_log) {
RequestInfo info = original_info;
int rv = ApplyRules(&info);
if (rv != OK)
return rv;
- return impl_->Resolve(info, priority, addresses, callback, out_req, net_log);
+ return impl_->Resolve(info, priority, addresses, callback, request, net_log);
}
int MappedHostResolver::ResolveFromCache(const RequestInfo& original_info,
AddressList* addresses,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
RequestInfo info = original_info;
int rv = ApplyRules(&info);
if (rv != OK)
@@ -44,10 +44,6 @@ int MappedHostResolver::ResolveFromCache(const RequestInfo& original_info,
return impl_->ResolveFromCache(info, addresses, net_log);
}
-void MappedHostResolver::CancelRequest(RequestHandle req) {
- impl_->CancelRequest(req);
-}
-
void MappedHostResolver::SetDnsClientEnabled(bool enabled) {
impl_->SetDnsClientEnabled(enabled);
}
diff --git a/chromium/net/dns/mapped_host_resolver.h b/chromium/net/dns/mapped_host_resolver.h
index 20c249f7b09..ddc753bed1c 100644
--- a/chromium/net/dns/mapped_host_resolver.h
+++ b/chromium/net/dns/mapped_host_resolver.h
@@ -49,12 +49,11 @@ class NET_EXPORT MappedHostResolver : public HostResolver {
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) override;
+ std::unique_ptr<Request>* request,
+ const NetLogWithSource& net_log) override;
int ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& net_log) override;
- void CancelRequest(RequestHandle req) override;
+ const NetLogWithSource& net_log) override;
void SetDnsClientEnabled(bool enabled) override;
HostCache* GetHostCache() override;
std::unique_ptr<base::Value> GetDnsConfigAsValue() const override;
diff --git a/chromium/net/dns/mapped_host_resolver_unittest.cc b/chromium/net/dns/mapped_host_resolver_unittest.cc
index f7840047e96..4833fd934b9 100644
--- a/chromium/net/dns/mapped_host_resolver_unittest.cc
+++ b/chromium/net/dns/mapped_host_resolver_unittest.cc
@@ -10,9 +10,14 @@
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/dns/mock_host_resolver.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -24,6 +29,8 @@ std::string FirstAddress(const AddressList& address_list) {
}
TEST(MappedHostResolverTest, Inclusion) {
+ // Outstanding request.
+ std::unique_ptr<HostResolver::Request> request;
// Create a mock host resolver, with specific hostname to IP mappings.
std::unique_ptr<MockHostResolver> resolver_impl(new MockHostResolver());
resolver_impl->rules()->AddSimulatedFailure("*google.com");
@@ -43,43 +50,37 @@ TEST(MappedHostResolverTest, Inclusion) {
TestCompletionCallback callback;
rv = resolver->Resolve(
HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
- DEFAULT_PRIORITY,
- &address_list,
- callback.callback(),
- NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ DEFAULT_PRIORITY, &address_list, callback.callback(), &request,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
+ EXPECT_THAT(rv, IsError(ERR_NAME_NOT_RESOLVED));
// Remap *.google.com to baz.com.
EXPECT_TRUE(resolver->AddRuleFromString("map *.google.com baz.com"));
+ request.reset();
// Try resolving "www.google.com:80". Should be remapped to "baz.com:80".
rv = resolver->Resolve(
HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
- DEFAULT_PRIORITY,
- &address_list,
- callback.callback(),
- NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ DEFAULT_PRIORITY, &address_list, callback.callback(), &request,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("192.168.1.5:80", FirstAddress(address_list));
+ request.reset();
// Try resolving "foo.com:77". This will NOT be remapped, so result
// is "foo.com:77".
rv = resolver->Resolve(HostResolver::RequestInfo(HostPortPair("foo.com", 77)),
- DEFAULT_PRIORITY,
- &address_list,
- callback.callback(),
- NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ DEFAULT_PRIORITY, &address_list, callback.callback(),
+ &request, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("192.168.1.8:77", FirstAddress(address_list));
+ request.reset();
// Remap "*.org" to "proxy:99".
EXPECT_TRUE(resolver->AddRuleFromString("Map *.org proxy:99"));
@@ -87,19 +88,18 @@ TEST(MappedHostResolverTest, Inclusion) {
// Try resolving "chromium.org:61". Should be remapped to "proxy:99".
rv = resolver->Resolve(
HostResolver::RequestInfo(HostPortPair("chromium.org", 61)),
- DEFAULT_PRIORITY,
- &address_list,
- callback.callback(),
- NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ DEFAULT_PRIORITY, &address_list, callback.callback(), &request,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("192.168.1.11:99", FirstAddress(address_list));
}
// Tests that exclusions are respected.
TEST(MappedHostResolverTest, Exclusion) {
+ // Outstanding request.
+ std::unique_ptr<HostResolver::Request> request;
// Create a mock host resolver, with specific hostname to IP mappings.
std::unique_ptr<MockHostResolver> resolver_impl(new MockHostResolver());
resolver_impl->rules()->AddRule("baz", "192.168.1.5");
@@ -122,31 +122,28 @@ TEST(MappedHostResolverTest, Exclusion) {
// Try resolving "www.google.com". Should not be remapped due to exclusion).
rv = resolver->Resolve(
HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
- DEFAULT_PRIORITY,
- &address_list,
- callback.callback(),
- NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ DEFAULT_PRIORITY, &address_list, callback.callback(), &request,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("192.168.1.3:80", FirstAddress(address_list));
+ request.reset();
// Try resolving "chrome.com:80". Should be remapped to "baz:80".
rv = resolver->Resolve(
HostResolver::RequestInfo(HostPortPair("chrome.com", 80)),
- DEFAULT_PRIORITY,
- &address_list,
- callback.callback(),
- NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ DEFAULT_PRIORITY, &address_list, callback.callback(), &request,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("192.168.1.5:80", FirstAddress(address_list));
}
TEST(MappedHostResolverTest, SetRulesFromString) {
+ // Outstanding request.
+ std::unique_ptr<HostResolver::Request> request;
// Create a mock host resolver, with specific hostname to IP mappings.
std::unique_ptr<MockHostResolver> resolver_impl(new MockHostResolver());
resolver_impl->rules()->AddRule("baz", "192.168.1.7");
@@ -166,27 +163,22 @@ TEST(MappedHostResolverTest, SetRulesFromString) {
// Try resolving "www.google.com". Should be remapped to "baz".
rv = resolver->Resolve(
HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
- DEFAULT_PRIORITY,
- &address_list,
- callback.callback(),
- NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ DEFAULT_PRIORITY, &address_list, callback.callback(), &request,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("192.168.1.7:80", FirstAddress(address_list));
+ request.reset();
// Try resolving "chrome.net:80". Should be remapped to "bar:60".
rv = resolver->Resolve(
HostResolver::RequestInfo(HostPortPair("chrome.net", 80)),
- DEFAULT_PRIORITY,
- &address_list,
- callback.callback(),
- NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ DEFAULT_PRIORITY, &address_list, callback.callback(), &request,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("192.168.1.9:60", FirstAddress(address_list));
}
@@ -207,6 +199,8 @@ TEST(MappedHostResolverTest, ParseInvalidRules) {
// Test mapping hostnames to resolving failures.
TEST(MappedHostResolverTest, MapToError) {
+ // Outstanding request.
+ std::unique_ptr<HostResolver::Request> request;
std::unique_ptr<MockHostResolver> resolver_impl(new MockHostResolver());
resolver_impl->rules()->AddRule("*", "192.168.1.5");
@@ -223,25 +217,20 @@ TEST(MappedHostResolverTest, MapToError) {
TestCompletionCallback callback1;
rv = resolver->Resolve(
HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
- DEFAULT_PRIORITY,
- &address_list,
- callback1.callback(),
- NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
+ DEFAULT_PRIORITY, &address_list, callback1.callback(), &request,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_NAME_NOT_RESOLVED));
+ request.reset();
// Try resolving www.foo.com --> Should succeed.
TestCompletionCallback callback2;
rv = resolver->Resolve(
HostResolver::RequestInfo(HostPortPair("www.foo.com", 80)),
- DEFAULT_PRIORITY,
- &address_list,
- callback2.callback(),
- NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ DEFAULT_PRIORITY, &address_list, callback2.callback(), &request,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("192.168.1.5:80", FirstAddress(address_list));
}
diff --git a/chromium/net/dns/mdns_client.cc b/chromium/net/dns/mdns_client.cc
index 6add12c4fed..2e18945d375 100644
--- a/chromium/net/dns/mdns_client.cc
+++ b/chromium/net/dns/mdns_client.cc
@@ -9,6 +9,7 @@
#include "net/base/network_interfaces.h"
#include "net/dns/dns_protocol.h"
#include "net/dns/mdns_client_impl.h"
+#include "net/log/net_log_source.h"
namespace net {
@@ -88,7 +89,7 @@ std::unique_ptr<DatagramServerSocket> CreateAndBindMDnsSocket(
AddressFamily address_family,
uint32_t interface_index) {
std::unique_ptr<DatagramServerSocket> socket(
- new UDPServerSocket(NULL, NetLog::Source()));
+ new UDPServerSocket(NULL, NetLogSource()));
IPEndPoint multicast_addr = GetMDnsIPEndPoint(address_family);
int rv = Bind(multicast_addr, interface_index, socket.get());
diff --git a/chromium/net/dns/mdns_client.h b/chromium/net/dns/mdns_client.h
index 8d2e6597809..180ae8a0d3a 100644
--- a/chromium/net/dns/mdns_client.h
+++ b/chromium/net/dns/mdns_client.h
@@ -13,6 +13,7 @@
#include "base/callback.h"
#include "net/base/ip_endpoint.h"
+#include "net/base/net_export.h"
#include "net/dns/dns_query.h"
#include "net/dns/dns_response.h"
#include "net/dns/record_parsed.h"
diff --git a/chromium/net/dns/mdns_client_impl.cc b/chromium/net/dns/mdns_client_impl.cc
index 346b7bc702d..634822e83fc 100644
--- a/chromium/net/dns/mdns_client_impl.cc
+++ b/chromium/net/dns/mdns_client_impl.cc
@@ -23,7 +23,6 @@
#include "net/dns/dns_protocol.h"
#include "net/dns/dns_util.h"
#include "net/dns/record_rdata.h"
-#include "net/log/net_log.h"
#include "net/udp/datagram_socket.h"
// TODO(gene): Remove this temporary method of disabling NSEC support once it
@@ -209,7 +208,7 @@ MDnsClientImpl::Core::Core(base::Clock* clock, base::Timer* timer)
}
MDnsClientImpl::Core::~Core() {
- STLDeleteValues(&listeners_);
+ base::STLDeleteValues(&listeners_);
}
bool MDnsClientImpl::Core::Init(MDnsSocketFactory* socket_factory) {
diff --git a/chromium/net/dns/mdns_client_impl.h b/chromium/net/dns/mdns_client_impl.h
index 9db82b0d6d3..1f064129ea7 100644
--- a/chromium/net/dns/mdns_client_impl.h
+++ b/chromium/net/dns/mdns_client_impl.h
@@ -20,6 +20,7 @@
#include "base/observer_list.h"
#include "net/base/io_buffer.h"
#include "net/base/ip_endpoint.h"
+#include "net/base/net_export.h"
#include "net/dns/mdns_cache.h"
#include "net/dns/mdns_client.h"
#include "net/udp/datagram_server_socket.h"
diff --git a/chromium/net/dns/mdns_client_unittest.cc b/chromium/net/dns/mdns_client_unittest.cc
index d0e6dfb6adc..8edf48e7ecc 100644
--- a/chromium/net/dns/mdns_client_unittest.cc
+++ b/chromium/net/dns/mdns_client_unittest.cc
@@ -11,6 +11,7 @@
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/clock.h"
@@ -465,7 +466,7 @@ void MDnsTest::RunFor(base::TimeDelta time_period) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, callback.callback(), time_period);
- base::MessageLoop::current()->Run();
+ base::RunLoop().Run();
callback.Cancel();
}
@@ -1185,7 +1186,7 @@ TEST_F(MDnsConnectionTest, ReceiveAsynchronous) {
EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet_));
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
TEST_F(MDnsConnectionTest, Error) {
@@ -1200,7 +1201,7 @@ TEST_F(MDnsConnectionTest, Error) {
EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
callback.Run(ERR_SOCKET_NOT_CONNECTED);
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
class MDnsConnectionSendTest : public MDnsConnectionTest {
@@ -1235,7 +1236,7 @@ TEST_F(MDnsConnectionSendTest, SendError) {
connection_.Send(sample_buffer_, sample_packet_.size());
EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
- base::MessageLoop::current()->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
TEST_F(MDnsConnectionSendTest, SendQueued) {
diff --git a/chromium/net/dns/mock_host_resolver.cc b/chromium/net/dns/mock_host_resolver.cc
index 01030aa3537..10258b3d910 100644
--- a/chromium/net/dns/mock_host_resolver.cc
+++ b/chromium/net/dns/mock_host_resolver.cc
@@ -8,6 +8,7 @@
#include <vector>
#include "base/bind.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
@@ -55,42 +56,78 @@ int ParseAddressList(const std::string& host_list,
return OK;
}
-struct MockHostResolverBase::Request {
- Request(const RequestInfo& req_info,
- AddressList* addr,
- const CompletionCallback& cb)
- : info(req_info), addresses(addr), callback(cb) {}
- RequestInfo info;
- AddressList* addresses;
- CompletionCallback callback;
+class MockHostResolverBase::RequestImpl : public HostResolver::Request {
+ public:
+ RequestImpl(const RequestInfo& req_info,
+ AddressList* addr,
+ const CompletionCallback& cb,
+ MockHostResolverBase* resolver,
+ size_t id)
+ : info_(req_info),
+ addresses_(addr),
+ callback_(cb),
+ resolver_(resolver),
+ id_(id) {}
+
+ ~RequestImpl() override {
+ if (resolver_)
+ resolver_->DetachRequest(id_);
+ }
+
+ void ChangeRequestPriority(RequestPriority priority) override {}
+
+ void OnResolveCompleted(MockHostResolverBase* resolver, int error) {
+ DCHECK_EQ(resolver_, resolver);
+ resolver_ = nullptr;
+ addresses_ = nullptr;
+ base::ResetAndReturn(&callback_).Run(error);
+ }
+
+ RequestInfo info() { return info_; }
+
+ AddressList* addresses() { return addresses_; }
+
+ private:
+ RequestInfo info_;
+ AddressList* addresses_;
+ CompletionCallback callback_;
+ MockHostResolverBase* resolver_;
+ size_t id_;
+
+ DISALLOW_COPY_AND_ASSIGN(RequestImpl);
};
MockHostResolverBase::~MockHostResolverBase() {
- STLDeleteValues(&requests_);
+ DCHECK(requests_.empty());
}
int MockHostResolverBase::Resolve(const RequestInfo& info,
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* handle,
- const BoundNetLog& net_log) {
+ std::unique_ptr<Request>* request,
+ const NetLogWithSource& net_log) {
DCHECK(CalledOnValidThread());
+ DCHECK(request);
last_request_priority_ = priority;
num_resolve_++;
size_t id = next_request_id_++;
int rv = ResolveFromIPLiteralOrCache(info, addresses);
- if (rv != ERR_DNS_CACHE_MISS) {
+ if (rv != ERR_DNS_CACHE_MISS)
return rv;
- }
- if (synchronous_mode_) {
- return ResolveProc(id, info, addresses);
- }
+
+ // Just like the real resolver, refuse to do anything with invalid hostnames.
+ if (!IsValidDNSDomain(info.hostname()))
+ return ERR_NAME_NOT_RESOLVED;
+
+ if (synchronous_mode_)
+ return ResolveProc(info, addresses);
+
// Store the request for asynchronous resolution
- Request* req = new Request(info, addresses, callback);
- requests_[id] = req;
- if (handle)
- *handle = reinterpret_cast<RequestHandle>(id);
+ std::unique_ptr<RequestImpl> req(
+ new RequestImpl(info, addresses, callback, this, id));
+ requests_[id] = req.get();
+ *request = std::move(req);
if (!ondemand_mode_) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -103,7 +140,7 @@ int MockHostResolverBase::Resolve(const RequestInfo& info,
int MockHostResolverBase::ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
num_resolve_from_cache_++;
DCHECK(CalledOnValidThread());
next_request_id_++;
@@ -111,17 +148,10 @@ int MockHostResolverBase::ResolveFromCache(const RequestInfo& info,
return rv;
}
-void MockHostResolverBase::CancelRequest(RequestHandle handle) {
- DCHECK(CalledOnValidThread());
- size_t id = reinterpret_cast<size_t>(handle);
+void MockHostResolverBase::DetachRequest(size_t id) {
RequestMap::iterator it = requests_.find(id);
- if (it != requests_.end()) {
- std::unique_ptr<Request> req(it->second);
- requests_.erase(it);
- } else {
- NOTREACHED() << "CancelRequest must NOT be called after request is "
- "complete or canceled.";
- }
+ CHECK(it != requests_.end());
+ requests_.erase(it);
}
HostCache* MockHostResolverBase::GetHostCache() {
@@ -183,15 +213,11 @@ int MockHostResolverBase::ResolveFromIPLiteralOrCache(const RequestInfo& info,
return rv;
}
-int MockHostResolverBase::ResolveProc(size_t id,
- const RequestInfo& info,
+int MockHostResolverBase::ResolveProc(const RequestInfo& info,
AddressList* addresses) {
AddressList addr;
- int rv = rules_->Resolve(info.hostname(),
- info.address_family(),
- info.host_resolver_flags(),
- &addr,
- NULL);
+ int rv = rules_->Resolve(info.hostname(), info.address_family(),
+ info.host_resolver_flags(), &addr, nullptr);
if (cache_.get()) {
HostCache::Key key(info.hostname(),
info.address_family(),
@@ -212,11 +238,11 @@ void MockHostResolverBase::ResolveNow(size_t id) {
if (it == requests_.end())
return; // was canceled
- std::unique_ptr<Request> req(it->second);
+ RequestImpl* req = it->second;
requests_.erase(it);
- int rv = ResolveProc(id, req->info, req->addresses);
- if (!req->callback.is_null())
- req->callback.Run(rv);
+
+ int error = ResolveProc(req->info(), req->addresses());
+ req->OnResolveCompleted(this, error);
}
//-----------------------------------------------------------------------------
@@ -425,14 +451,14 @@ int HangingHostResolver::Resolve(const RequestInfo& info,
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) {
+ std::unique_ptr<Request>* request,
+ const NetLogWithSource& net_log) {
return ERR_IO_PENDING;
}
int HangingHostResolver::ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
return ERR_DNS_CACHE_MISS;
}
diff --git a/chromium/net/dns/mock_host_resolver.h b/chromium/net/dns/mock_host_resolver.h
index c4312fb2151..cca300acbc6 100644
--- a/chromium/net/dns/mock_host_resolver.h
+++ b/chromium/net/dns/mock_host_resolver.h
@@ -58,6 +58,9 @@ int ParseAddressList(const std::string& host_list,
class MockHostResolverBase : public HostResolver,
public base::SupportsWeakPtr<MockHostResolverBase>,
public base::NonThreadSafe {
+ private:
+ class RequestImpl;
+
public:
~MockHostResolverBase() override;
@@ -82,14 +85,16 @@ class MockHostResolverBase : public HostResolver,
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) override;
+ std::unique_ptr<Request>* request,
+ const NetLogWithSource& net_log) override;
int ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& net_log) override;
- void CancelRequest(RequestHandle req) override;
+ const NetLogWithSource& net_log) override;
HostCache* GetHostCache() override;
+ // Detach cancelled request.
+ void DetachRequest(size_t id);
+
// Resolves all pending requests. It is only valid to invoke this if
// set_ondemand_mode was set before. The requests are resolved asynchronously,
// after this call returns.
@@ -119,15 +124,14 @@ class MockHostResolverBase : public HostResolver,
explicit MockHostResolverBase(bool use_caching);
private:
- struct Request;
- typedef std::map<size_t, Request*> RequestMap;
+ typedef std::map<size_t, RequestImpl*> RequestMap;
// Resolve as IP or from |cache_| return cached error or
// DNS_CACHE_MISS if failed.
int ResolveFromIPLiteralOrCache(const RequestInfo& info,
AddressList* addresses);
// Resolve via |proc_|.
- int ResolveProc(size_t id, const RequestInfo& info, AddressList* addresses);
+ int ResolveProc(const RequestInfo& info, AddressList* addresses);
// Resolve request stored in |requests_|. Pass rv to callback.
void ResolveNow(size_t id);
@@ -239,12 +243,11 @@ class HangingHostResolver : public HostResolver {
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) override;
+ std::unique_ptr<Request>* out_req,
+ const NetLogWithSource& net_log) override;
int ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& net_log) override;
- void CancelRequest(RequestHandle req) override {}
+ const NetLogWithSource& net_log) override;
};
// This class sets the default HostResolverProc for a particular scope. The
diff --git a/chromium/net/dns/mock_mdns_socket_factory.h b/chromium/net/dns/mock_mdns_socket_factory.h
index a55d51734fa..059a93aa754 100644
--- a/chromium/net/dns/mock_mdns_socket_factory.h
+++ b/chromium/net/dns/mock_mdns_socket_factory.h
@@ -12,6 +12,7 @@
#include <vector>
#include "net/dns/mdns_client_impl.h"
+#include "net/log/net_log_with_source.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace net {
@@ -43,12 +44,14 @@ class MockMDnsDatagramServerSocket : public DatagramServerSocket {
MOCK_METHOD1(SetReceiveBufferSize, int(int32_t size));
MOCK_METHOD1(SetSendBufferSize, int(int32_t size));
+ MOCK_METHOD0(SetDoNotFragment, int());
MOCK_METHOD0(Close, void());
MOCK_CONST_METHOD1(GetPeerAddress, int(IPEndPoint* address));
int GetLocalAddress(IPEndPoint* address) const override;
- MOCK_CONST_METHOD0(NetLog, const BoundNetLog&());
+ MOCK_METHOD0(UseNonBlockingIO, void());
+ MOCK_CONST_METHOD0(NetLog, const NetLogWithSource&());
MOCK_METHOD0(AllowAddressReuse, void());
MOCK_METHOD0(AllowBroadcast, void());
diff --git a/chromium/net/dns/mojo_host_resolver_impl.cc b/chromium/net/dns/mojo_host_resolver_impl.cc
index 13f61d51dd4..1e32639ec38 100644
--- a/chromium/net/dns/mojo_host_resolver_impl.cc
+++ b/chromium/net/dns/mojo_host_resolver_impl.cc
@@ -23,7 +23,7 @@ class MojoHostResolverImpl::Job {
Job(MojoHostResolverImpl* resolver_service,
net::HostResolver* resolver,
const net::HostResolver::RequestInfo& request_info,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
interfaces::HostResolverRequestClientPtr client);
~Job();
@@ -39,21 +39,20 @@ class MojoHostResolverImpl::Job {
MojoHostResolverImpl* resolver_service_;
net::HostResolver* resolver_;
net::HostResolver::RequestInfo request_info_;
- const BoundNetLog net_log_;
+ const NetLogWithSource net_log_;
interfaces::HostResolverRequestClientPtr client_;
- net::HostResolver::RequestHandle handle_;
+ std::unique_ptr<net::HostResolver::Request> request_;
AddressList result_;
base::ThreadChecker thread_checker_;
};
MojoHostResolverImpl::MojoHostResolverImpl(net::HostResolver* resolver,
- const BoundNetLog& net_log)
- : resolver_(resolver), net_log_(net_log) {
-}
+ const NetLogWithSource& net_log)
+ : resolver_(resolver), net_log_(net_log) {}
MojoHostResolverImpl::~MojoHostResolverImpl() {
DCHECK(thread_checker_.CalledOnValidThread());
- STLDeleteElements(&pending_jobs_);
+ base::STLDeleteElements(&pending_jobs_);
}
void MojoHostResolverImpl::Resolve(
@@ -85,14 +84,13 @@ MojoHostResolverImpl::Job::Job(
MojoHostResolverImpl* resolver_service,
net::HostResolver* resolver,
const net::HostResolver::RequestInfo& request_info,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
interfaces::HostResolverRequestClientPtr client)
: resolver_service_(resolver_service),
resolver_(resolver),
request_info_(request_info),
net_log_(net_log),
- client_(std::move(client)),
- handle_(nullptr) {
+ client_(std::move(client)) {
client_.set_connection_error_handler(base::Bind(
&MojoHostResolverImpl::Job::OnConnectionError, base::Unretained(this)));
}
@@ -103,21 +101,18 @@ void MojoHostResolverImpl::Job::Start() {
resolver_->Resolve(request_info_, DEFAULT_PRIORITY, &result_,
base::Bind(&MojoHostResolverImpl::Job::OnResolveDone,
base::Unretained(this)),
- &handle_, net_log_);
+ &request_, net_log_);
if (result != ERR_IO_PENDING)
OnResolveDone(result);
}
MojoHostResolverImpl::Job::~Job() {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (handle_)
- resolver_->CancelRequest(handle_);
}
void MojoHostResolverImpl::Job::OnResolveDone(int result) {
DCHECK(thread_checker_.CalledOnValidThread());
- handle_ = nullptr;
+ request_.reset();
DVLOG(1) << "Resolved " << request_info_.host_port_pair().ToString()
<< " with error " << result << " and " << result_.size()
<< " results!";
diff --git a/chromium/net/dns/mojo_host_resolver_impl.h b/chromium/net/dns/mojo_host_resolver_impl.h
index b0b11abb50b..68eb893e47c 100644
--- a/chromium/net/dns/mojo_host_resolver_impl.h
+++ b/chromium/net/dns/mojo_host_resolver_impl.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "base/threading/thread_checker.h"
#include "net/interfaces/host_resolver_service.mojom.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
namespace net {
@@ -24,7 +24,8 @@ class HostResolver;
class MojoHostResolverImpl {
public:
// |resolver| is expected to outlive |this|.
- MojoHostResolverImpl(net::HostResolver* resolver, const BoundNetLog& net_log);
+ MojoHostResolverImpl(net::HostResolver* resolver,
+ const NetLogWithSource& net_log);
~MojoHostResolverImpl();
void Resolve(interfaces::HostResolverRequestInfoPtr request_info,
@@ -41,8 +42,8 @@ class MojoHostResolverImpl {
// Resolver for resolving incoming requests. Not owned.
net::HostResolver* resolver_;
- // The BoundNetLog to be passed to |resolver_| for all requests.
- const BoundNetLog net_log_;
+ // The NetLogWithSource to be passed to |resolver_| for all requests.
+ const NetLogWithSource net_log_;
// All pending jobs, so they can be cancelled when this service is destroyed.
// Owns all jobs.
diff --git a/chromium/net/dns/mojo_host_resolver_impl_unittest.cc b/chromium/net/dns/mojo_host_resolver_impl_unittest.cc
index 0bb28a97257..9b7425ab0fa 100644
--- a/chromium/net/dns/mojo_host_resolver_impl_unittest.cc
+++ b/chromium/net/dns/mojo_host_resolver_impl_unittest.cc
@@ -16,9 +16,13 @@
#include "net/base/net_errors.h"
#include "net/dns/mock_host_resolver.h"
#include "net/dns/mojo_host_type_converters.h"
-#include "net/log/net_log.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -100,8 +104,8 @@ class CallbackMockHostResolver : public MockHostResolver {
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) override;
+ std::unique_ptr<Request>* request,
+ const NetLogWithSource& net_log) override;
private:
base::Closure resolve_callback_;
@@ -111,10 +115,10 @@ int CallbackMockHostResolver::Resolve(const RequestInfo& info,
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) {
+ std::unique_ptr<Request>* request,
+ const NetLogWithSource& net_log) {
int result = MockHostResolver::Resolve(info, priority, addresses, callback,
- out_req, net_log);
+ request, net_log);
if (!resolve_callback_.is_null()) {
resolve_callback_.Run();
resolve_callback_.Reset();
@@ -132,7 +136,7 @@ class MojoHostResolverImplTest : public testing::Test {
mock_host_resolver_.rules()->AddSimulatedFailure("failure.fail");
resolver_service_.reset(
- new MojoHostResolverImpl(&mock_host_resolver_, BoundNetLog()));
+ new MojoHostResolverImpl(&mock_host_resolver_, NetLogWithSource()));
}
interfaces::HostResolverRequestInfoPtr CreateRequest(const std::string& host,
@@ -169,7 +173,7 @@ TEST_F(MojoHostResolverImplTest, Resolve) {
resolver_service_->Resolve(std::move(request), std::move(client_ptr));
client.WaitForResult();
- EXPECT_EQ(net::OK, client.error_);
+ EXPECT_THAT(client.error_, IsOk());
AddressList address_list = (*client.results_).To<AddressList>();
EXPECT_EQ(1U, address_list.size());
EXPECT_EQ("1.2.3.4:80", address_list[0].ToString());
@@ -186,7 +190,7 @@ TEST_F(MojoHostResolverImplTest, ResolveSynchronous) {
resolver_service_->Resolve(std::move(request), std::move(client_ptr));
client.WaitForResult();
- EXPECT_EQ(net::OK, client.error_);
+ EXPECT_THAT(client.error_, IsOk());
AddressList address_list = (*client.results_).To<AddressList>();
EXPECT_EQ(1U, address_list.size());
EXPECT_EQ("1.2.3.4:80", address_list[0].ToString());
@@ -212,11 +216,11 @@ TEST_F(MojoHostResolverImplTest, ResolveMultiple) {
client1.WaitForResult();
client2.WaitForResult();
- EXPECT_EQ(net::OK, client1.error_);
+ EXPECT_THAT(client1.error_, IsOk());
AddressList address_list = (*client1.results_).To<AddressList>();
EXPECT_EQ(1U, address_list.size());
EXPECT_EQ("1.2.3.4:80", address_list[0].ToString());
- EXPECT_EQ(net::OK, client2.error_);
+ EXPECT_THAT(client2.error_, IsOk());
address_list = (*client2.results_).To<AddressList>();
EXPECT_EQ(1U, address_list.size());
EXPECT_EQ("8.8.8.8:80", address_list[0].ToString());
@@ -242,11 +246,11 @@ TEST_F(MojoHostResolverImplTest, ResolveDuplicate) {
client1.WaitForResult();
client2.WaitForResult();
- EXPECT_EQ(net::OK, client1.error_);
+ EXPECT_THAT(client1.error_, IsOk());
AddressList address_list = (*client1.results_).To<AddressList>();
EXPECT_EQ(1U, address_list.size());
EXPECT_EQ("1.2.3.4:80", address_list[0].ToString());
- EXPECT_EQ(net::OK, client2.error_);
+ EXPECT_THAT(client2.error_, IsOk());
address_list = (*client2.results_).To<AddressList>();
EXPECT_EQ(1U, address_list.size());
EXPECT_EQ("1.2.3.4:80", address_list[0].ToString());
@@ -261,7 +265,7 @@ TEST_F(MojoHostResolverImplTest, ResolveFailure) {
resolver_service_->Resolve(std::move(request), std::move(client_ptr));
client.WaitForResult();
- EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, client.error_);
+ EXPECT_THAT(client.error_, IsError(net::ERR_NAME_NOT_RESOLVED));
EXPECT_TRUE(client.results_.is_null());
}
diff --git a/chromium/net/dns/record_rdata.h b/chromium/net/dns/record_rdata.h
index d2ca587c5e7..0aa29d57866 100644
--- a/chromium/net/dns/record_rdata.h
+++ b/chromium/net/dns/record_rdata.h
@@ -12,6 +12,7 @@
#include <vector>
#include "base/compiler_specific.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "net/base/ip_address.h"
@@ -198,7 +199,11 @@ class NET_EXPORT_PRIVATE NsecRecordRdata : public RecordRdata {
uint16_t Type() const override;
// Length of the bitmap in bits.
- unsigned bitmap_length() const { return bitmap_.size() * 8; }
+ // This will be between 8 and 256, per RFC 3845, Section 2.1.2.
+ uint16_t bitmap_length() const {
+ DCHECK_LE(bitmap_.size(), 32u);
+ return static_cast<uint16_t>(bitmap_.size() * 8);
+ }
// Returns bit i-th bit in the bitmap, where bits withing a byte are organized
// most to least significant. If it is set, a record with rrtype i exists for
diff --git a/chromium/net/dns/record_rdata_unittest.cc b/chromium/net/dns/record_rdata_unittest.cc
index c41e39aa5e6..f73853ed5a7 100644
--- a/chromium/net/dns/record_rdata_unittest.cc
+++ b/chromium/net/dns/record_rdata_unittest.cc
@@ -17,9 +17,6 @@ base::StringPiece MakeStringPiece(const uint8_t* data, unsigned size) {
}
TEST(RecordRdataTest, ParseSrvRecord) {
- std::unique_ptr<SrvRecordRdata> record1_obj;
- std::unique_ptr<SrvRecordRdata> record2_obj;
-
// These are just the rdata portions of the DNS records, rather than complete
// records, but it works well enough for this test.
@@ -40,7 +37,8 @@ TEST(RecordRdataTest, ParseSrvRecord) {
base::StringPiece record2_strpiece = MakeStringPiece(
record + first_record_len, sizeof(record) - first_record_len);
- record1_obj = SrvRecordRdata::Create(record1_strpiece, parser);
+ std::unique_ptr<SrvRecordRdata> record1_obj =
+ SrvRecordRdata::Create(record1_strpiece, parser);
ASSERT_TRUE(record1_obj != NULL);
ASSERT_EQ(1, record1_obj->priority());
ASSERT_EQ(2, record1_obj->weight());
@@ -48,7 +46,8 @@ TEST(RecordRdataTest, ParseSrvRecord) {
ASSERT_EQ("www.google.com", record1_obj->target());
- record2_obj = SrvRecordRdata::Create(record2_strpiece, parser);
+ std::unique_ptr<SrvRecordRdata> record2_obj =
+ SrvRecordRdata::Create(record2_strpiece, parser);
ASSERT_TRUE(record2_obj != NULL);
ASSERT_EQ(257, record2_obj->priority());
ASSERT_EQ(258, record2_obj->weight());
@@ -61,8 +60,6 @@ TEST(RecordRdataTest, ParseSrvRecord) {
}
TEST(RecordRdataTest, ParseARecord) {
- std::unique_ptr<ARecordRdata> record_obj;
-
// These are just the rdata portions of the DNS records, rather than complete
// records, but it works well enough for this test.
@@ -73,7 +70,8 @@ TEST(RecordRdataTest, ParseARecord) {
DnsRecordParser parser(record, sizeof(record), 0);
base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
- record_obj = ARecordRdata::Create(record_strpiece, parser);
+ std::unique_ptr<ARecordRdata> record_obj =
+ ARecordRdata::Create(record_strpiece, parser);
ASSERT_TRUE(record_obj != NULL);
ASSERT_EQ("127.0.0.1", record_obj->address().ToString());
@@ -82,8 +80,6 @@ TEST(RecordRdataTest, ParseARecord) {
}
TEST(RecordRdataTest, ParseAAAARecord) {
- std::unique_ptr<AAAARecordRdata> record_obj;
-
// These are just the rdata portions of the DNS records, rather than complete
// records, but it works well enough for this test.
@@ -95,7 +91,8 @@ TEST(RecordRdataTest, ParseAAAARecord) {
DnsRecordParser parser(record, sizeof(record), 0);
base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
- record_obj = AAAARecordRdata::Create(record_strpiece, parser);
+ std::unique_ptr<AAAARecordRdata> record_obj =
+ AAAARecordRdata::Create(record_strpiece, parser);
ASSERT_TRUE(record_obj != NULL);
ASSERT_EQ("1234:5678::9", record_obj->address().ToString());
@@ -104,8 +101,6 @@ TEST(RecordRdataTest, ParseAAAARecord) {
}
TEST(RecordRdataTest, ParseCnameRecord) {
- std::unique_ptr<CnameRecordRdata> record_obj;
-
// These are just the rdata portions of the DNS records, rather than complete
// records, but it works well enough for this test.
@@ -115,7 +110,8 @@ TEST(RecordRdataTest, ParseCnameRecord) {
DnsRecordParser parser(record, sizeof(record), 0);
base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
- record_obj = CnameRecordRdata::Create(record_strpiece, parser);
+ std::unique_ptr<CnameRecordRdata> record_obj =
+ CnameRecordRdata::Create(record_strpiece, parser);
ASSERT_TRUE(record_obj != NULL);
ASSERT_EQ("www.google.com", record_obj->cname());
@@ -124,8 +120,6 @@ TEST(RecordRdataTest, ParseCnameRecord) {
}
TEST(RecordRdataTest, ParsePtrRecord) {
- std::unique_ptr<PtrRecordRdata> record_obj;
-
// These are just the rdata portions of the DNS records, rather than complete
// records, but it works well enough for this test.
@@ -135,7 +129,8 @@ TEST(RecordRdataTest, ParsePtrRecord) {
DnsRecordParser parser(record, sizeof(record), 0);
base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
- record_obj = PtrRecordRdata::Create(record_strpiece, parser);
+ std::unique_ptr<PtrRecordRdata> record_obj =
+ PtrRecordRdata::Create(record_strpiece, parser);
ASSERT_TRUE(record_obj != NULL);
ASSERT_EQ("www.google.com", record_obj->ptrdomain());
@@ -144,8 +139,6 @@ TEST(RecordRdataTest, ParsePtrRecord) {
}
TEST(RecordRdataTest, ParseTxtRecord) {
- std::unique_ptr<TxtRecordRdata> record_obj;
-
// These are just the rdata portions of the DNS records, rather than complete
// records, but it works well enough for this test.
@@ -155,7 +148,8 @@ TEST(RecordRdataTest, ParseTxtRecord) {
DnsRecordParser parser(record, sizeof(record), 0);
base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
- record_obj = TxtRecordRdata::Create(record_strpiece, parser);
+ std::unique_ptr<TxtRecordRdata> record_obj =
+ TxtRecordRdata::Create(record_strpiece, parser);
ASSERT_TRUE(record_obj != NULL);
std::vector<std::string> expected;
@@ -169,8 +163,6 @@ TEST(RecordRdataTest, ParseTxtRecord) {
}
TEST(RecordRdataTest, ParseNsecRecord) {
- std::unique_ptr<NsecRecordRdata> record_obj;
-
// These are just the rdata portions of the DNS records, rather than complete
// records, but it works well enough for this test.
@@ -181,7 +173,8 @@ TEST(RecordRdataTest, ParseNsecRecord) {
DnsRecordParser parser(record, sizeof(record), 0);
base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
- record_obj = NsecRecordRdata::Create(record_strpiece, parser);
+ std::unique_ptr<NsecRecordRdata> record_obj =
+ NsecRecordRdata::Create(record_strpiece, parser);
ASSERT_TRUE(record_obj != NULL);
ASSERT_EQ(16u, record_obj->bitmap_length());
@@ -196,5 +189,39 @@ TEST(RecordRdataTest, ParseNsecRecord) {
ASSERT_TRUE(record_obj->IsEqual(record_obj.get()));
}
+TEST(RecordRdataTest, CreateNsecRecordWithEmptyBitmapReturnsNull) {
+ // These are just the rdata portions of the DNS records, rather than complete
+ // records, but it works well enough for this test.
+ // This record has a bitmap that is 0 bytes long.
+ const uint8_t record[] = {0x03, 'w', 'w', 'w', 0x06, 'g', 'o', 'o', 'g',
+ 'l', 'e', 0x03, 'c', 'o', 'm', 0x00, 0x00, 0x00};
+
+ DnsRecordParser parser(record, sizeof(record), 0);
+ base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
+
+ std::unique_ptr<NsecRecordRdata> record_obj =
+ NsecRecordRdata::Create(record_strpiece, parser);
+ ASSERT_FALSE(record_obj);
+}
+
+TEST(RecordRdataTest, CreateNsecRecordWithOversizedBitmapReturnsNull) {
+ // These are just the rdata portions of the DNS records, rather than complete
+ // records, but it works well enough for this test.
+ // This record has a bitmap that is 33 bytes long. The maximum size allowed by
+ // RFC 3845, Section 2.1.2, is 32 bytes.
+ const uint8_t record[] = {
+ 0x03, 'w', 'w', 'w', 0x06, 'g', 'o', 'o', 'g', 'l', 'e',
+ 0x03, 'c', 'o', 'm', 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ DnsRecordParser parser(record, sizeof(record), 0);
+ base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
+
+ std::unique_ptr<NsecRecordRdata> record_obj =
+ NsecRecordRdata::Create(record_strpiece, parser);
+ ASSERT_FALSE(record_obj);
+}
} // namespace net
diff --git a/chromium/net/dns/single_request_host_resolver.cc b/chromium/net/dns/single_request_host_resolver.cc
deleted file mode 100644
index 7974abafeef..00000000000
--- a/chromium/net/dns/single_request_host_resolver.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/dns/single_request_host_resolver.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "net/base/net_errors.h"
-
-namespace net {
-
-SingleRequestHostResolver::SingleRequestHostResolver(HostResolver* resolver)
- : resolver_(resolver),
- cur_request_(NULL),
- callback_(
- base::Bind(&SingleRequestHostResolver::OnResolveCompletion,
- base::Unretained(this))) {
- DCHECK(resolver_ != NULL);
-}
-
-SingleRequestHostResolver::~SingleRequestHostResolver() {
- Cancel();
-}
-
-int SingleRequestHostResolver::Resolve(const HostResolver::RequestInfo& info,
- RequestPriority priority,
- AddressList* addresses,
- const CompletionCallback& callback,
- const BoundNetLog& net_log) {
- DCHECK(addresses);
- DCHECK_EQ(false, callback.is_null());
- DCHECK(cur_request_callback_.is_null()) << "resolver already in use";
-
- HostResolver::RequestHandle request = NULL;
-
- // We need to be notified of completion before |callback| is called, so that
- // we can clear out |cur_request_*|.
- CompletionCallback transient_callback =
- callback.is_null() ? CompletionCallback() : callback_;
-
- int rv = resolver_->Resolve(
- info, priority, addresses, transient_callback, &request, net_log);
-
- if (rv == ERR_IO_PENDING) {
- DCHECK_EQ(false, callback.is_null());
- // Cleared in OnResolveCompletion().
- cur_request_ = request;
- cur_request_callback_ = callback;
- }
-
- return rv;
-}
-
-void SingleRequestHostResolver::Cancel() {
- if (!cur_request_callback_.is_null()) {
- resolver_->CancelRequest(cur_request_);
- cur_request_ = NULL;
- cur_request_callback_.Reset();
- }
-}
-
-void SingleRequestHostResolver::OnResolveCompletion(int result) {
- DCHECK(cur_request_);
- DCHECK_EQ(false, cur_request_callback_.is_null());
-
- CompletionCallback callback = cur_request_callback_;
-
- // Clear the outstanding request information.
- cur_request_ = NULL;
- cur_request_callback_.Reset();
-
- // Call the user's original callback.
- callback.Run(result);
-}
-
-} // namespace net
diff --git a/chromium/net/dns/single_request_host_resolver.h b/chromium/net/dns/single_request_host_resolver.h
deleted file mode 100644
index f2843093fc8..00000000000
--- a/chromium/net/dns/single_request_host_resolver.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_DNS_SINGLE_REQUEST_HOST_RESOLVER_H_
-#define NET_DNS_SINGLE_REQUEST_HOST_RESOLVER_H_
-
-#include "base/macros.h"
-#include "net/base/completion_callback.h"
-#include "net/base/net_export.h"
-#include "net/base/request_priority.h"
-#include "net/dns/host_resolver.h"
-
-namespace net {
-
-class AddressList;
-class BoundNetLog;
-
-// This class represents the task of resolving a hostname (or IP address
-// literal) to an AddressList object. It wraps HostResolver to resolve only a
-// single hostname at a time and cancels this request when going out of scope.
-class NET_EXPORT SingleRequestHostResolver {
- public:
- // |resolver| must remain valid for the lifetime of |this|.
- explicit SingleRequestHostResolver(HostResolver* resolver);
-
- // If a completion callback is pending when the resolver is destroyed, the
- // host resolution is cancelled, and the completion callback will not be
- // called.
- ~SingleRequestHostResolver();
-
- // Resolves the given hostname (or IP address literal), filling out the
- // |addresses| object upon success. See HostResolver::Resolve() for details.
- int Resolve(const HostResolver::RequestInfo& info,
- RequestPriority priority,
- AddressList* addresses,
- const CompletionCallback& callback,
- const BoundNetLog& net_log);
-
- // Cancels the in-progress request, if any. This prevents the callback
- // from being invoked. Resolve() can be called again after cancelling.
- void Cancel();
-
- private:
- // Callback for when the request to |resolver_| completes, so we dispatch
- // to the user's callback.
- void OnResolveCompletion(int result);
-
- // The actual host resolver that will handle the request.
- HostResolver* const resolver_;
-
- // The current request (if any).
- HostResolver::RequestHandle cur_request_;
- CompletionCallback cur_request_callback_;
-
- // Completion callback for when request to |resolver_| completes.
- CompletionCallback callback_;
-
- DISALLOW_COPY_AND_ASSIGN(SingleRequestHostResolver);
-};
-
-} // namespace net
-
-#endif // NET_DNS_SINGLE_REQUEST_HOST_RESOLVER_H_
diff --git a/chromium/net/dns/single_request_host_resolver_unittest.cc b/chromium/net/dns/single_request_host_resolver_unittest.cc
deleted file mode 100644
index c5bb9f1ae6b..00000000000
--- a/chromium/net/dns/single_request_host_resolver_unittest.cc
+++ /dev/null
@@ -1,127 +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/dns/single_request_host_resolver.h"
-
-#include "base/macros.h"
-#include "net/base/address_list.h"
-#include "net/base/net_errors.h"
-#include "net/base/test_completion_callback.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/log/net_log.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-namespace {
-
-// Helper class used by SingleRequestHostResolverTest.Cancel test.
-// It checks that only one request is outstanding at a time, and that
-// it is cancelled before the class is destroyed.
-class HangingHostResolver : public HostResolver {
- public:
- HangingHostResolver() : outstanding_request_(NULL) {}
-
- ~HangingHostResolver() override { EXPECT_TRUE(!has_outstanding_request()); }
-
- bool has_outstanding_request() const {
- return outstanding_request_ != NULL;
- }
-
- int Resolve(const RequestInfo& info,
- RequestPriority priority,
- AddressList* addresses,
- const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) override {
- EXPECT_FALSE(has_outstanding_request());
- outstanding_request_ = reinterpret_cast<RequestHandle>(0x1234);
- *out_req = outstanding_request_;
-
- // Never complete this request! Caller is expected to cancel it
- // before destroying the resolver.
- return ERR_IO_PENDING;
- }
-
- int ResolveFromCache(const RequestInfo& info,
- AddressList* addresses,
- const BoundNetLog& net_log) override {
- NOTIMPLEMENTED();
- return ERR_UNEXPECTED;
- }
-
- void CancelRequest(RequestHandle req) override {
- EXPECT_TRUE(has_outstanding_request());
- EXPECT_EQ(req, outstanding_request_);
- outstanding_request_ = NULL;
- }
-
- private:
- RequestHandle outstanding_request_;
-
- DISALLOW_COPY_AND_ASSIGN(HangingHostResolver);
-};
-
-// Test that a regular end-to-end lookup returns the expected result.
-TEST(SingleRequestHostResolverTest, NormalResolve) {
- // Create a host resolver dependency that returns address "199.188.1.166"
- // for resolutions of "watsup".
- MockHostResolver resolver;
- resolver.rules()->AddIPLiteralRule("watsup", "199.188.1.166", std::string());
-
- SingleRequestHostResolver single_request_resolver(&resolver);
-
- // Resolve "watsup:90" using our SingleRequestHostResolver.
- AddressList addrlist;
- TestCompletionCallback callback;
- HostResolver::RequestInfo request(HostPortPair("watsup", 90));
- int rv = single_request_resolver.Resolve(
- request, DEFAULT_PRIORITY, &addrlist, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
-
- // Verify that the result is what we specified in the MockHostResolver.
- ASSERT_FALSE(addrlist.empty());
- EXPECT_EQ("199.188.1.166", addrlist.front().ToStringWithoutPort());
-}
-
-// Test that the Cancel() method cancels any outstanding request.
-TEST(SingleRequestHostResolverTest, Cancel) {
- HangingHostResolver resolver;
-
- {
- SingleRequestHostResolver single_request_resolver(&resolver);
-
- // Resolve "watsup:90" using our SingleRequestHostResolver.
- AddressList addrlist;
- TestCompletionCallback callback;
- HostResolver::RequestInfo request(HostPortPair("watsup", 90));
- int rv = single_request_resolver.Resolve(request,
- DEFAULT_PRIORITY,
- &addrlist,
- callback.callback(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_TRUE(resolver.has_outstanding_request());
- }
-
- // Now that the SingleRequestHostResolver has been destroyed, the
- // in-progress request should have been aborted.
- EXPECT_FALSE(resolver.has_outstanding_request());
-}
-
-// Test that the Cancel() method is a no-op when there is no outstanding
-// request.
-TEST(SingleRequestHostResolverTest, CancelWhileNoPendingRequest) {
- HangingHostResolver resolver;
- SingleRequestHostResolver single_request_resolver(&resolver);
- single_request_resolver.Cancel();
-
- // To pass, HangingHostResolver should not have received a cancellation
- // request (since there is nothing to cancel). If it does, it will crash.
-}
-
-} // namespace
-
-} // namespace net
diff --git a/chromium/net/docs/crash-course-in-net-internals.md b/chromium/net/docs/crash-course-in-net-internals.md
index fa2094c6bf9..529c7d2c2a7 100644
--- a/chromium/net/docs/crash-course-in-net-internals.md
+++ b/chromium/net/docs/crash-course-in-net-internals.md
@@ -34,7 +34,7 @@ covers), but it's good to be aware of this distinction.
The Event View shows events logged by the NetLog. The NetLog model is that
long-lived network stack objects, called sources, emit events over their
-lifetime. When looking at the code, a "BoundNetLog" object contains a source
+lifetime. When looking at the code, a "NetLogWithSource" object contains a source
ID, and a pointer to the NetLog the source emits events to. Some events have a
beginning and end point (during which other subevents may occur), and some only
occur at a single point in time. Generally only one event can be occuring for a
diff --git a/chromium/net/docs/filter.md b/chromium/net/docs/filter.md
new file mode 100644
index 00000000000..3cab81fa193
--- /dev/null
+++ b/chromium/net/docs/filter.md
@@ -0,0 +1,36 @@
+The network stack implements support for Content-Encodings using
+"source streams", which can be composed together and mutate all the incoming
+bytes from a URLRequestJob. Currently, the following streams are implemented:
+
+* gzip (handling "deflate" and "gzip" Content-Encodings)
+* sdch (handling "sdch" Content-Encoding)
+* brotli (handling "br" Content-Encoding)
+
+Source streams conceptually form a chain, with the URLRequestJob as both the
+beginning and end of the chain, meaning the URLRequestJob produces raw bytes at
+the end and consumes unencoded bytes at the beginning. For example, to support a
+hypothetical "Content-Encoding: bar,foo", streams would be arranged like so,
+with "X <-- Y" meaning "data flows from Y to X", "X reads data from Y", or
+"X is downstream from Y".
+
+ URLRequestJob <-- BarSourceStream <-- FooSourceStream <-- URLRequestJob
+ (URLRequestSourceStream)
+
+Here URLRequestJob pulls filtered bytes from its upstream, BarSourceStream,
+which pulls filtered bytes from FooSourceStream, which in turn pulls raw bytes
+from URLRequestJob. URLRequestSourceStream is the ultimate upstream, which
+produces the raw data. Every stream in the chain owns its upstream. In this
+case, the ultimate downstream, URLRequestJob, owns its upstream,
+BarSourceStream, which in turn owns FooSourceStream. FooSourceStream owns its
+upstream, URLRequestSourceStream.
+
+All source streams conform to the following interface (named SourceStream in the
+tree):
+
+ int Read(IOBuffer* dest_buffer, size_t buffer_size,
+ const OnReadCompleteCallback& callback);
+
+This function can return either synchronously or asynchronously via the supplied
+callback. The source stream chain is "pull-based", in that data does not
+propagate through the chain until requested by the final consumer of the
+filtered data.
diff --git a/chromium/net/extras/sqlite/sqlite_channel_id_store_unittest.cc b/chromium/net/extras/sqlite/sqlite_channel_id_store_unittest.cc
index 98c2d96c1d5..8be7a4b5f03 100644
--- a/chromium/net/extras/sqlite/sqlite_channel_id_store_unittest.cc
+++ b/chromium/net/extras/sqlite/sqlite_channel_id_store_unittest.cc
@@ -104,7 +104,7 @@ class SQLiteChannelIDStoreTest : public testing::Test {
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
store_ = new SQLiteChannelIDStore(
- temp_dir_.path().Append(kTestChannelIDFilename),
+ temp_dir_.GetPath().Append(kTestChannelIDFilename),
base::ThreadTaskRunnerHandle::Get());
std::vector<std::unique_ptr<DefaultChannelIDStore::ChannelID>> channel_ids;
Load(&channel_ids);
@@ -134,9 +134,9 @@ TEST_F(SQLiteChannelIDStoreTest, TestPersistence) {
store_ = NULL;
// Make sure we wait until the destructor has run.
base::RunLoop().RunUntilIdle();
- store_ =
- new SQLiteChannelIDStore(temp_dir_.path().Append(kTestChannelIDFilename),
- base::ThreadTaskRunnerHandle::Get());
+ store_ = new SQLiteChannelIDStore(
+ temp_dir_.GetPath().Append(kTestChannelIDFilename),
+ base::ThreadTaskRunnerHandle::Get());
// Reload and test for persistence
Load(&channel_ids);
@@ -164,9 +164,9 @@ TEST_F(SQLiteChannelIDStoreTest, TestPersistence) {
// Make sure we wait until the destructor has run.
base::RunLoop().RunUntilIdle();
channel_ids.clear();
- store_ =
- new SQLiteChannelIDStore(temp_dir_.path().Append(kTestChannelIDFilename),
- base::ThreadTaskRunnerHandle::Get());
+ store_ = new SQLiteChannelIDStore(
+ temp_dir_.GetPath().Append(kTestChannelIDFilename),
+ base::ThreadTaskRunnerHandle::Get());
// Reload and check if the keypair has been removed.
Load(&channel_ids);
@@ -190,9 +190,9 @@ TEST_F(SQLiteChannelIDStoreTest, TestDeleteAll) {
store_ = NULL;
// Make sure we wait until the destructor has run.
base::RunLoop().RunUntilIdle();
- store_ =
- new SQLiteChannelIDStore(temp_dir_.path().Append(kTestChannelIDFilename),
- base::ThreadTaskRunnerHandle::Get());
+ store_ = new SQLiteChannelIDStore(
+ temp_dir_.GetPath().Append(kTestChannelIDFilename),
+ base::ThreadTaskRunnerHandle::Get());
// Reload and test for persistence
Load(&channel_ids);
@@ -208,9 +208,9 @@ TEST_F(SQLiteChannelIDStoreTest, TestDeleteAll) {
// Make sure we wait until the destructor has run.
base::RunLoop().RunUntilIdle();
channel_ids.clear();
- store_ =
- new SQLiteChannelIDStore(temp_dir_.path().Append(kTestChannelIDFilename),
- base::ThreadTaskRunnerHandle::Get());
+ store_ = new SQLiteChannelIDStore(
+ temp_dir_.GetPath().Append(kTestChannelIDFilename),
+ base::ThreadTaskRunnerHandle::Get());
// Reload and check that only foo.com persisted in store.
Load(&channel_ids);
@@ -226,7 +226,7 @@ TEST_F(SQLiteChannelIDStoreTest, TestUpgradeV1) {
// Reset the store. We'll be using a different database for this test.
store_ = NULL;
- base::FilePath v1_db_path(temp_dir_.path().AppendASCII("v1db"));
+ base::FilePath v1_db_path(temp_dir_.GetPath().AppendASCII("v1db"));
std::string key_data;
std::string cert_data;
@@ -294,7 +294,7 @@ TEST_F(SQLiteChannelIDStoreTest, TestUpgradeV2) {
// Reset the store. We'll be using a different database for this test.
store_ = NULL;
- base::FilePath v2_db_path(temp_dir_.path().AppendASCII("v2db"));
+ base::FilePath v2_db_path(temp_dir_.GetPath().AppendASCII("v2db"));
std::string key_data;
std::string cert_data;
@@ -370,7 +370,7 @@ TEST_F(SQLiteChannelIDStoreTest, TestUpgradeV3) {
// Reset the store. We'll be using a different database for this test.
store_ = NULL;
- base::FilePath v3_db_path(temp_dir_.path().AppendASCII("v3db"));
+ base::FilePath v3_db_path(temp_dir_.GetPath().AppendASCII("v3db"));
std::string key_data;
std::string cert_data;
@@ -448,7 +448,7 @@ TEST_F(SQLiteChannelIDStoreTest, TestUpgradeV4) {
// Reset the store. We'll be using a different database for this test.
store_ = NULL;
- base::FilePath v4_db_path(temp_dir_.path().AppendASCII("v4db"));
+ base::FilePath v4_db_path(temp_dir_.GetPath().AppendASCII("v4db"));
std::string key_data;
std::string cert_data;
diff --git a/chromium/net/extras/sqlite/sqlite_persistent_cookie_store_perftest.cc b/chromium/net/extras/sqlite/sqlite_persistent_cookie_store_perftest.cc
index 2fbe8dff5ee..2af8d037146 100644
--- a/chromium/net/extras/sqlite/sqlite_persistent_cookie_store_perftest.cc
+++ b/chromium/net/extras/sqlite/sqlite_persistent_cookie_store_perftest.cc
@@ -33,7 +33,7 @@ const base::FilePath::CharType cookie_filename[] = FILE_PATH_LITERAL("Cookies");
class SQLitePersistentCookieStorePerfTest : public testing::Test {
public:
SQLitePersistentCookieStorePerfTest()
- : pool_owner_(new base::SequencedWorkerPoolOwner(1, "Background Pool")),
+ : pool_owner_(new base::SequencedWorkerPoolOwner(2, "SetupPool")),
loaded_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED),
key_loaded_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
@@ -68,7 +68,7 @@ class SQLitePersistentCookieStorePerfTest : public testing::Test {
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
store_ = new SQLitePersistentCookieStore(
- temp_dir_.path().Append(cookie_filename), client_task_runner(),
+ temp_dir_.GetPath().Append(cookie_filename), client_task_runner(),
background_task_runner(), false, NULL);
std::vector<CanonicalCookie*> cookies;
Load();
@@ -93,10 +93,10 @@ class SQLitePersistentCookieStorePerfTest : public testing::Test {
// Shut down the pool, causing deferred (no-op) commits to be discarded.
pool_owner_->pool()->Shutdown();
// ~SequencedWorkerPoolOwner blocks on pool shutdown.
- pool_owner_.reset(new base::SequencedWorkerPoolOwner(1, "pool"));
+ pool_owner_.reset(new base::SequencedWorkerPoolOwner(2, "TestPool"));
store_ = new SQLitePersistentCookieStore(
- temp_dir_.path().Append(cookie_filename), client_task_runner(),
+ temp_dir_.GetPath().Append(cookie_filename), client_task_runner(),
background_task_runner(), false, NULL);
}
diff --git a/chromium/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc b/chromium/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
index 6389e4ba675..1ccba74e81e 100644
--- a/chromium/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
+++ b/chromium/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
@@ -144,7 +144,7 @@ class SQLitePersistentCookieStoreTest : public testing::Test {
cookie_crypto_delegate_.reset(new CookieCryptor());
store_ = new SQLitePersistentCookieStore(
- temp_dir_.path().Append(kCookieFilename), client_task_runner(),
+ temp_dir_.GetPath().Append(kCookieFilename), client_task_runner(),
background_task_runner(), restore_old_session_cookies,
cookie_crypto_delegate_.get());
}
@@ -192,7 +192,7 @@ class SQLitePersistentCookieStoreTest : public testing::Test {
std::string ReadRawDBContents() {
std::string contents;
- if (!base::ReadFileToString(temp_dir_.path().Append(kCookieFilename),
+ if (!base::ReadFileToString(temp_dir_.GetPath().Append(kCookieFilename),
&contents))
return std::string();
return contents;
@@ -229,12 +229,12 @@ TEST_F(SQLitePersistentCookieStoreTest, TestInvalidMetaTableRecovery) {
ASSERT_STREQ("A", cookies[0]->Name().c_str());
ASSERT_STREQ("B", cookies[0]->Value().c_str());
DestroyStore();
- STLDeleteElements(&cookies);
+ base::STLDeleteElements(&cookies);
// Now corrupt the meta table.
{
sql::Connection db;
- ASSERT_TRUE(db.Open(temp_dir_.path().Append(kCookieFilename)));
+ ASSERT_TRUE(db.Open(temp_dir_.GetPath().Append(kCookieFilename)));
sql::MetaTable meta_table_;
meta_table_.Init(&db, 1, 1);
ASSERT_TRUE(db.Execute("DELETE FROM meta"));
@@ -254,7 +254,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestInvalidMetaTableRecovery) {
ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str());
ASSERT_STREQ("X", cookies[0]->Name().c_str());
ASSERT_STREQ("Y", cookies[0]->Value().c_str());
- STLDeleteElements(&cookies);
+ base::STLDeleteElements(&cookies);
}
// Test if data is stored as expected in the SQLite database.
@@ -277,7 +277,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestPersistance) {
// Now delete the cookie and check persistence again.
store_->DeleteCookie(*cookies[0]);
DestroyStore();
- STLDeleteElements(&cookies);
+ base::STLDeleteElements(&cookies);
// Reload and check if the cookie has been removed.
CreateAndLoad(false, false, &cookies);
@@ -318,7 +318,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestSessionCookiesDeletedOnStartup) {
// Load the store a second time. Before the store finishes loading, add a
// transient cookie and flush it to disk.
store_ = new SQLitePersistentCookieStore(
- temp_dir_.path().Append(kCookieFilename), client_task_runner(),
+ temp_dir_.GetPath().Append(kCookieFilename), client_task_runner(),
background_task_runner(), false, nullptr);
// Posting a blocking task to db_thread_ makes sure that the DB thread waits
@@ -346,20 +346,20 @@ TEST_F(SQLitePersistentCookieStoreTest, TestSessionCookiesDeletedOnStartup) {
db_thread_event_.Signal();
event.Wait();
loaded_event_.Wait();
- STLDeleteElements(&cookies_);
+ base::STLDeleteElements(&cookies_);
DestroyStore();
// Load the store a third time, this time restoring session cookies. The
// store should contain exactly 4 cookies: the 3 persistent, and "c.com",
// which was added during the second cookie store load.
store_ = new SQLitePersistentCookieStore(
- temp_dir_.path().Append(kCookieFilename), client_task_runner(),
+ temp_dir_.GetPath().Append(kCookieFilename), client_task_runner(),
background_task_runner(), true, nullptr);
store_->Load(base::Bind(&SQLitePersistentCookieStoreTest::OnLoaded,
base::Unretained(this)));
loaded_event_.Wait();
ASSERT_EQ(4u, cookies_.size());
- STLDeleteElements(&cookies_);
+ base::STLDeleteElements(&cookies_);
}
// Test that priority load of cookies for a specfic domain key could be
@@ -377,7 +377,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestLoadCookiesForKey) {
DestroyStore();
store_ = new SQLitePersistentCookieStore(
- temp_dir_.path().Append(kCookieFilename), client_task_runner(),
+ temp_dir_.GetPath().Append(kCookieFilename), client_task_runner(),
background_task_runner(), false, nullptr);
// Posting a blocking task to db_thread_ makes sure that the DB thread waits
@@ -409,7 +409,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestLoadCookiesForKey) {
it != cookies_.end(); ++it) {
cookies_loaded.insert((*it)->Domain().c_str());
}
- STLDeleteElements(&cookies_);
+ base::STLDeleteElements(&cookies_);
ASSERT_GT(4U, cookies_loaded.size());
ASSERT_EQ(true, cookies_loaded.find("www.aaa.com") != cookies_loaded.end());
ASSERT_EQ(true,
@@ -424,7 +424,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestLoadCookiesForKey) {
ASSERT_EQ(4U, cookies_loaded.size());
ASSERT_EQ(cookies_loaded.find("foo.bar") != cookies_loaded.end(), true);
ASSERT_EQ(cookies_loaded.find("www.bbb.com") != cookies_loaded.end(), true);
- STLDeleteElements(&cookies_);
+ base::STLDeleteElements(&cookies_);
}
// Test that we can force the database to be written by calling Flush().
@@ -432,7 +432,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestFlush) {
InitializeStore(false, false);
// File timestamps don't work well on all platforms, so we'll determine
// whether the DB file has been modified by checking its size.
- base::FilePath path = temp_dir_.path().Append(kCookieFilename);
+ base::FilePath path = temp_dir_.GetPath().Append(kCookieFilename);
base::File::Info info;
ASSERT_TRUE(base::GetFileInfo(path, &info));
int64_t base_size = info.size;
@@ -477,7 +477,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestLoadOldSessionCookies) {
ASSERT_STREQ("D", cookies[0]->Value().c_str());
ASSERT_EQ(COOKIE_PRIORITY_DEFAULT, cookies[0]->Priority());
- STLDeleteElements(&cookies);
+ base::STLDeleteElements(&cookies);
}
// Test loading old session cookies from the disk.
@@ -550,7 +550,7 @@ TEST_F(SQLitePersistentCookieStoreTest, PersistIsPersistent) {
ASSERT_TRUE(it != cookie_map.end());
EXPECT_TRUE(cookie_map[kPersistentName]->IsPersistent());
- STLDeleteElements(&cookies);
+ base::STLDeleteElements(&cookies);
}
TEST_F(SQLitePersistentCookieStoreTest, PriorityIsPersistent) {
@@ -614,7 +614,7 @@ TEST_F(SQLitePersistentCookieStoreTest, PriorityIsPersistent) {
ASSERT_TRUE(it != cookie_map.end());
EXPECT_EQ(COOKIE_PRIORITY_HIGH, cookie_map[kHighName]->Priority());
- STLDeleteElements(&cookies);
+ base::STLDeleteElements(&cookies);
}
TEST_F(SQLitePersistentCookieStoreTest, SameSiteIsPersistent) {
@@ -672,7 +672,7 @@ TEST_F(SQLitePersistentCookieStoreTest, SameSiteIsPersistent) {
ASSERT_EQ(1u, cookie_map.count(kStrictName));
EXPECT_EQ(CookieSameSite::STRICT_MODE, cookie_map[kStrictName]->SameSite());
- STLDeleteElements(&cookies);
+ base::STLDeleteElements(&cookies);
}
TEST_F(SQLitePersistentCookieStoreTest, UpdateToEncryption) {
@@ -691,7 +691,7 @@ TEST_F(SQLitePersistentCookieStoreTest, UpdateToEncryption) {
EXPECT_NE(contents.find("value123XYZ"), std::string::npos);
// Create encrypted cookie store and ensure old cookie still reads.
- STLDeleteElements(&cookies_);
+ base::STLDeleteElements(&cookies_);
EXPECT_EQ(0U, cookies_.size());
CreateAndLoad(true, false, &cookies);
EXPECT_EQ(1U, cookies_.size());
@@ -705,7 +705,7 @@ TEST_F(SQLitePersistentCookieStoreTest, UpdateToEncryption) {
AddCookie(GURL("http://foo.bar"), "other", "something456ABC", std::string(),
"/", base::Time::Now() + base::TimeDelta::FromInternalValue(10));
DestroyStore();
- STLDeleteElements(&cookies_);
+ base::STLDeleteElements(&cookies_);
CreateAndLoad(true, false, &cookies);
EXPECT_EQ(2U, cookies_.size());
CanonicalCookie* cookie_name = nullptr;
@@ -720,13 +720,13 @@ TEST_F(SQLitePersistentCookieStoreTest, UpdateToEncryption) {
EXPECT_EQ("encrypted_value123XYZ", cookie_name->Value());
EXPECT_EQ("something456ABC", cookie_other->Value());
DestroyStore();
- STLDeleteElements(&cookies_);
+ base::STLDeleteElements(&cookies_);
// Examine the real record to make sure plaintext version doesn't exist.
sql::Connection db;
sql::Statement smt;
int resultcount = 0;
- ASSERT_TRUE(db.Open(temp_dir_.path().Append(kCookieFilename)));
+ ASSERT_TRUE(db.Open(temp_dir_.GetPath().Append(kCookieFilename)));
smt.Assign(db.GetCachedStatement(SQL_FROM_HERE,
"SELECT * "
"FROM cookies "
@@ -762,7 +762,7 @@ TEST_F(SQLitePersistentCookieStoreTest, UpdateFromEncryption) {
EXPECT_EQ(contents.find("value123XYZ"), std::string::npos);
// Create encrypted cookie store and ensure old cookie still reads.
- STLDeleteElements(&cookies_);
+ base::STLDeleteElements(&cookies_);
EXPECT_EQ(0U, cookies_.size());
CreateAndLoad(true, false, &cookies);
EXPECT_EQ(1U, cookies_.size());
@@ -777,7 +777,7 @@ TEST_F(SQLitePersistentCookieStoreTest, UpdateFromEncryption) {
AddCookie(GURL("http://foo.bar"), "other", "something456ABC", std::string(),
"/", base::Time::Now() + base::TimeDelta::FromInternalValue(10));
DestroyStore();
- STLDeleteElements(&cookies_);
+ base::STLDeleteElements(&cookies_);
CreateAndLoad(true, false, &cookies);
EXPECT_EQ(2U, cookies_.size());
CanonicalCookie* cookie_name = nullptr;
@@ -792,7 +792,7 @@ TEST_F(SQLitePersistentCookieStoreTest, UpdateFromEncryption) {
EXPECT_EQ("plaintext_value123XYZ", cookie_name->Value());
EXPECT_EQ("something456ABC", cookie_other->Value());
DestroyStore();
- STLDeleteElements(&cookies_);
+ base::STLDeleteElements(&cookies_);
// Verify that "value" is now visible in the file.
contents = ReadRawDBContents();
diff --git a/chromium/net/features.gni b/chromium/net/features.gni
new file mode 100644
index 00000000000..938c07e0612
--- /dev/null
+++ b/chromium/net/features.gni
@@ -0,0 +1,23 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+
+declare_args() {
+ # Disables support for file URLs. File URL support requires use of icu.
+ disable_file_support = false
+
+ # WebSockets and socket stream code are not used on iOS and are optional in
+ # cronet.
+ enable_websockets = !is_ios
+ disable_ftp_support = is_ios || is_chromecast
+
+ # Enable Kerberos authentication. It is disabled by default on ChromeOS, iOS,
+ # Chromecast, at least for now. This feature needs configuration (krb5.conf
+ # and so on).
+ use_kerberos = !is_chromeos && !is_ios && !is_chromecast
+
+ # Do not disable brotli filter by default.
+ disable_brotli_filter = false
+}
diff --git a/chromium/net/filter/brotli_source_stream.cc b/chromium/net/filter/brotli_source_stream.cc
new file mode 100644
index 00000000000..a7f7283f6ab
--- /dev/null
+++ b/chromium/net/filter/brotli_source_stream.cc
@@ -0,0 +1,191 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/filter/brotli_source_stream.h"
+
+#include "base/bind.h"
+#include "base/bit_cast.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "net/base/io_buffer.h"
+#include "third_party/brotli/dec/decode.h"
+
+namespace net {
+
+namespace {
+
+const char kBrotli[] = "BROTLI";
+const uint8_t kGzipHeader[] = {0x1f, 0x8b, 0x08};
+
+// BrotliSourceStream applies Brotli content decoding to a data stream.
+// Brotli format specification: http://www.ietf.org/id/draft-alakuijala-brotli.
+class BrotliSourceStream : public FilterSourceStream {
+ public:
+ explicit BrotliSourceStream(std::unique_ptr<SourceStream> upstream)
+ : FilterSourceStream(SourceStream::TYPE_BROTLI, std::move(upstream)),
+ decoding_status_(DecodingStatus::DECODING_IN_PROGRESS),
+ used_memory_(0),
+ used_memory_maximum_(0),
+ consumed_bytes_(0),
+ produced_bytes_(0),
+ gzip_header_detected_(true) {
+ brotli_state_ = BrotliCreateState(AllocateMemory, FreeMemory, this);
+ CHECK(brotli_state_);
+ }
+
+ ~BrotliSourceStream() override {
+ BrotliErrorCode error_code = BrotliGetErrorCode(brotli_state_);
+ BrotliDestroyState(brotli_state_);
+ brotli_state_ = nullptr;
+ DCHECK_EQ(0u, used_memory_);
+
+ // Don't report that gzip header was detected in case of lack of input.
+ gzip_header_detected_ &= (consumed_bytes_ >= sizeof(kGzipHeader));
+
+ UMA_HISTOGRAM_ENUMERATION(
+ "BrotliFilter.Status", static_cast<int>(decoding_status_),
+ static_cast<int>(DecodingStatus::DECODING_STATUS_COUNT));
+ UMA_HISTOGRAM_BOOLEAN("BrotliFilter.GzipHeaderDetected",
+ gzip_header_detected_);
+ if (decoding_status_ == DecodingStatus::DECODING_DONE) {
+ // CompressionPercent is undefined when there is no output produced.
+ if (produced_bytes_ != 0) {
+ UMA_HISTOGRAM_PERCENTAGE(
+ "BrotliFilter.CompressionPercent",
+ static_cast<int>((consumed_bytes_ * 100) / produced_bytes_));
+ }
+ }
+ if (error_code < 0) {
+ UMA_HISTOGRAM_ENUMERATION("BrotliFilter.ErrorCode",
+ -static_cast<int>(error_code),
+ 1 - BROTLI_LAST_ERROR_CODE);
+ }
+
+ // All code here is for gathering stats, and can be removed when
+ // BrotliSourceStream is considered stable.
+ const int kBuckets = 48;
+ const int64_t kMaxKb = 1 << (kBuckets / 3); // 64MiB in KiB
+ UMA_HISTOGRAM_CUSTOM_COUNTS("BrotliFilter.UsedMemoryKB",
+ used_memory_maximum_ / 1024, 1, kMaxKb,
+ kBuckets);
+ }
+
+ private:
+ // Reported in UMA and must be kept in sync with the histograms.xml file.
+ enum class DecodingStatus : int {
+ DECODING_IN_PROGRESS = 0,
+ DECODING_DONE,
+ DECODING_ERROR,
+
+ DECODING_STATUS_COUNT
+ // DECODING_STATUS_COUNT must always be the last element in this enum.
+ };
+
+ // SourceStream implementation
+ std::string GetTypeAsString() const override { return kBrotli; }
+
+ int FilterData(IOBuffer* output_buffer,
+ int output_buffer_size,
+ IOBuffer* input_buffer,
+ int input_buffer_size,
+ int* consumed_bytes,
+ bool /*upstream_eof_reached*/) override {
+ const uint8_t* next_in = bit_cast<uint8_t*>(input_buffer->data());
+ size_t available_in = input_buffer_size;
+ uint8_t* next_out = bit_cast<uint8_t*>(output_buffer->data());
+ size_t available_out = output_buffer_size;
+ size_t total_out = 0;
+ // Check if start of the input stream looks like gzip stream.
+ for (size_t i = consumed_bytes_; i < sizeof(kGzipHeader); ++i) {
+ if (!gzip_header_detected_)
+ break;
+ size_t j = i - consumed_bytes_;
+ if (j < available_in && kGzipHeader[i] != next_in[j])
+ gzip_header_detected_ = false;
+ }
+
+ BrotliResult result =
+ BrotliDecompressStream(&available_in, &next_in, &available_out,
+ &next_out, &total_out, brotli_state_);
+
+ size_t bytes_used = input_buffer_size - available_in;
+ size_t bytes_written = output_buffer_size - available_out;
+ CHECK_GE(bytes_used, 0u);
+ CHECK_GE(bytes_written, 0u);
+ produced_bytes_ += bytes_written;
+ consumed_bytes_ += bytes_used;
+
+ *consumed_bytes = bytes_used;
+
+ switch (result) {
+ case BROTLI_RESULT_NEEDS_MORE_OUTPUT:
+ return bytes_written;
+ case BROTLI_RESULT_SUCCESS:
+ decoding_status_ = DecodingStatus::DECODING_DONE;
+ return bytes_written;
+ case BROTLI_RESULT_NEEDS_MORE_INPUT:
+ // Decompress needs more input has consumed all existing input.
+ DCHECK_EQ(*consumed_bytes, input_buffer_size);
+ decoding_status_ = DecodingStatus::DECODING_IN_PROGRESS;
+ return bytes_written;
+ // If the decompressor threw an error, fail synchronously.
+ default:
+ decoding_status_ = DecodingStatus::DECODING_ERROR;
+ return ERR_CONTENT_DECODING_FAILED;
+ }
+ }
+
+ static void* AllocateMemory(void* opaque, size_t size) {
+ BrotliSourceStream* filter = reinterpret_cast<BrotliSourceStream*>(opaque);
+ return filter->AllocateMemoryInternal(size);
+ }
+
+ static void FreeMemory(void* opaque, void* address) {
+ BrotliSourceStream* filter = reinterpret_cast<BrotliSourceStream*>(opaque);
+ filter->FreeMemoryInternal(address);
+ }
+
+ void* AllocateMemoryInternal(size_t size) {
+ size_t* array = reinterpret_cast<size_t*>(malloc(size + sizeof(size_t)));
+ if (!array)
+ return nullptr;
+ used_memory_ += size;
+ if (used_memory_maximum_ < used_memory_)
+ used_memory_maximum_ = used_memory_;
+ array[0] = size;
+ return &array[1];
+ }
+
+ void FreeMemoryInternal(void* address) {
+ if (!address)
+ return;
+ size_t* array = reinterpret_cast<size_t*>(address);
+ used_memory_ -= array[-1];
+ free(&array[-1]);
+ }
+
+ BrotliState* brotli_state_;
+
+ DecodingStatus decoding_status_;
+
+ size_t used_memory_;
+ size_t used_memory_maximum_;
+ size_t consumed_bytes_;
+ size_t produced_bytes_;
+
+ bool gzip_header_detected_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrotliSourceStream);
+};
+
+} // namespace
+
+std::unique_ptr<FilterSourceStream> CreateBrotliSourceStream(
+ std::unique_ptr<SourceStream> previous) {
+ return base::WrapUnique(new BrotliSourceStream(std::move(previous)));
+}
+
+} // namespace net
diff --git a/chromium/net/filter/brotli_source_stream.h b/chromium/net/filter/brotli_source_stream.h
new file mode 100644
index 00000000000..d09c3e148d2
--- /dev/null
+++ b/chromium/net/filter/brotli_source_stream.h
@@ -0,0 +1,21 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_FILTER_BROTLI_SOURCE_STREAM_H_
+#define NET_FILTER_BROTLI_SOURCE_STREAM_H_
+
+#include <memory>
+
+#include "net/base/net_export.h"
+#include "net/filter/filter_source_stream.h"
+#include "net/filter/source_stream.h"
+
+namespace net {
+
+NET_EXPORT_PRIVATE std::unique_ptr<FilterSourceStream> CreateBrotliSourceStream(
+ std::unique_ptr<SourceStream> upstream);
+
+} // namespace net
+
+#endif // NET_FILTER_BROTLI_SOURCE_STREAM_H_
diff --git a/chromium/net/filter/brotli_source_stream_disabled.cc b/chromium/net/filter/brotli_source_stream_disabled.cc
new file mode 100644
index 00000000000..986397cb94e
--- /dev/null
+++ b/chromium/net/filter/brotli_source_stream_disabled.cc
@@ -0,0 +1,14 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/filter/brotli_source_stream.h"
+
+namespace net {
+
+std::unique_ptr<FilterSourceStream> CreateBrotliSourceStream(
+ std::unique_ptr<SourceStream> previous) {
+ return nullptr;
+}
+
+} // namespace net
diff --git a/chromium/net/filter/brotli_source_stream_unittest.cc b/chromium/net/filter/brotli_source_stream_unittest.cc
new file mode 100644
index 00000000000..4a0fd1e70f3
--- /dev/null
+++ b/chromium/net/filter/brotli_source_stream_unittest.cc
@@ -0,0 +1,275 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/bit_cast.h"
+#include "base/callback.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "net/base/io_buffer.h"
+#include "net/base/test_completion_callback.h"
+#include "net/filter/brotli_source_stream.h"
+#include "net/filter/mock_source_stream.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace net {
+
+namespace {
+
+const size_t kDefaultBufferSize = 4096;
+const size_t kSmallBufferSize = 128;
+
+} // namespace
+
+class BrotliSourceStreamTest : public PlatformTest {
+ protected:
+ void SetUp() override {
+ PlatformTest::SetUp();
+
+ // Get the path of data directory.
+ base::FilePath data_dir;
+ PathService::Get(base::DIR_SOURCE_ROOT, &data_dir);
+ data_dir = data_dir.AppendASCII("net");
+ data_dir = data_dir.AppendASCII("data");
+ data_dir = data_dir.AppendASCII("filter_unittests");
+
+ // Read data from the original file into buffer.
+ base::FilePath file_path;
+ file_path = data_dir.AppendASCII("google.txt");
+ ASSERT_TRUE(base::ReadFileToString(file_path, &source_data_));
+ ASSERT_GE(kDefaultBufferSize, source_data_.size());
+
+ // Read data from the encoded file into buffer.
+ base::FilePath encoded_file_path;
+ encoded_file_path = data_dir.AppendASCII("google.br");
+ ASSERT_TRUE(base::ReadFileToString(encoded_file_path, &encoded_buffer_));
+ ASSERT_GE(kDefaultBufferSize, encoded_buffer_.size());
+
+ std::unique_ptr<MockSourceStream> source(new MockSourceStream);
+ source_ = source.get();
+ brotli_stream_ = CreateBrotliSourceStream(std::move(source));
+ }
+
+ int ReadStream(const TestCompletionCallback& callback) {
+ return brotli_stream_->Read(out_buffer(), out_data_size(),
+ callback.callback());
+ }
+
+ IOBuffer* out_buffer() { return out_buffer_.get(); }
+ char* out_data() { return out_buffer_->data(); }
+ size_t out_data_size() { return out_buffer_->size(); }
+
+ std::string source_data() { return source_data_; }
+
+ size_t source_data_len() { return source_data_.length(); }
+
+ char* encoded_buffer() { return &encoded_buffer_[0]; }
+
+ size_t encoded_len() { return encoded_buffer_.length(); }
+
+ MockSourceStream* source() { return source_; }
+ SourceStream* brotli_stream() { return brotli_stream_.get(); }
+ scoped_refptr<IOBufferWithSize> out_buffer_;
+
+ private:
+ MockSourceStream* source_;
+ std::unique_ptr<SourceStream> brotli_stream_;
+ std::unique_ptr<base::RunLoop> loop_;
+
+ std::string source_data_;
+ std::string encoded_buffer_;
+};
+
+// Basic scenario: decoding brotli data with big enough buffer.
+TEST_F(BrotliSourceStreamTest, DecodeBrotliOneBlockSync) {
+ source()->AddReadResult(encoded_buffer(), encoded_len(), OK,
+ MockSourceStream::SYNC);
+ out_buffer_ = new IOBufferWithSize(kDefaultBufferSize);
+ TestCompletionCallback callback;
+ int bytes_read = ReadStream(callback);
+
+ EXPECT_EQ(static_cast<int>(source_data_len()), bytes_read);
+ EXPECT_EQ(0, memcmp(out_data(), source_data().c_str(), source_data_len()));
+ EXPECT_EQ("BROTLI", brotli_stream()->Description());
+}
+
+// Basic scenario: decoding brotli data with big enough buffer.
+TEST_F(BrotliSourceStreamTest, DecodeBrotliTwoBlockSync) {
+ source()->AddReadResult(encoded_buffer(), 10, OK, MockSourceStream::SYNC);
+ source()->AddReadResult(encoded_buffer() + 10, encoded_len() - 10, OK,
+ MockSourceStream::SYNC);
+ out_buffer_ = new IOBufferWithSize(kDefaultBufferSize);
+ TestCompletionCallback callback;
+ int bytes_read = ReadStream(callback);
+ EXPECT_EQ(static_cast<int>(source_data_len()), bytes_read);
+ EXPECT_EQ(0, memcmp(out_data(), source_data().c_str(), source_data_len()));
+ EXPECT_EQ("BROTLI", brotli_stream()->Description());
+}
+
+// Basic scenario: decoding brotli data with big enough buffer.
+TEST_F(BrotliSourceStreamTest, DecodeBrotliOneBlockAsync) {
+ source()->AddReadResult(encoded_buffer(), encoded_len(), OK,
+ MockSourceStream::ASYNC);
+ out_buffer_ = new IOBufferWithSize(kDefaultBufferSize);
+ TestCompletionCallback callback;
+ int bytes_read = ReadStream(callback);
+
+ EXPECT_EQ(ERR_IO_PENDING, bytes_read);
+ source()->CompleteNextRead();
+ int rv = callback.WaitForResult();
+ EXPECT_EQ(static_cast<int>(source_data_len()), rv);
+ EXPECT_EQ(0, memcmp(out_data(), source_data().c_str(), source_data_len()));
+ EXPECT_EQ("BROTLI", brotli_stream()->Description());
+}
+
+// Tests we can call filter repeatedly to get all the data decoded.
+// To do that, we create a filter with a small buffer that can not hold all
+// the input data.
+TEST_F(BrotliSourceStreamTest, DecodeWithSmallBufferSync) {
+ source()->AddReadResult(encoded_buffer(), encoded_len(), OK,
+ MockSourceStream::SYNC);
+ // Add a 0 byte read to signal EOF.
+ source()->AddReadResult(encoded_buffer(), 0, OK, MockSourceStream::SYNC);
+
+ out_buffer_ = new IOBufferWithSize(kSmallBufferSize);
+
+ scoped_refptr<IOBuffer> buffer = new IOBufferWithSize(source_data_len());
+ size_t total_bytes_read = 0;
+ int bytes_read = 0;
+ TestCompletionCallback callback;
+ do {
+ bytes_read = ReadStream(callback);
+ EXPECT_LE(OK, bytes_read);
+ EXPECT_GE(kSmallBufferSize, static_cast<size_t>(bytes_read));
+ memcpy(buffer->data() + total_bytes_read, out_data(), bytes_read);
+ total_bytes_read += bytes_read;
+ } while (bytes_read > 0);
+ EXPECT_EQ(source_data_len(), total_bytes_read);
+ EXPECT_EQ(0, memcmp(buffer->data(), source_data().c_str(), total_bytes_read));
+ EXPECT_EQ("BROTLI", brotli_stream()->Description());
+}
+
+// Tests we can call filter repeatedly to get all the data decoded.
+// To do that, we create a filter with a small buffer that can not hold all
+// the input data.
+TEST_F(BrotliSourceStreamTest, DecodeWithSmallBufferAsync) {
+ source()->AddReadResult(encoded_buffer(), encoded_len(), OK,
+ MockSourceStream::ASYNC);
+ // Add a 0 byte read to signal EOF.
+ source()->AddReadResult(encoded_buffer(), 0, OK, MockSourceStream::ASYNC);
+
+ out_buffer_ = new IOBufferWithSize(kSmallBufferSize);
+
+ scoped_refptr<IOBuffer> buffer = new IOBufferWithSize(source_data_len());
+ size_t total_bytes_read = 0;
+ int bytes_read = 0;
+ do {
+ TestCompletionCallback callback;
+ bytes_read = ReadStream(callback);
+ if (bytes_read == ERR_IO_PENDING) {
+ source()->CompleteNextRead();
+ bytes_read = callback.WaitForResult();
+ }
+ EXPECT_GE(static_cast<int>(kSmallBufferSize), bytes_read);
+ memcpy(buffer->data() + total_bytes_read, out_data(), bytes_read);
+ total_bytes_read += bytes_read;
+ } while (bytes_read > 0);
+ EXPECT_EQ(source_data_len(), total_bytes_read);
+ EXPECT_EQ(0, memcmp(buffer->data(), source_data().c_str(), total_bytes_read));
+ EXPECT_EQ("BROTLI", brotli_stream()->Description());
+}
+
+// Tests we can still decode with just 1 byte buffer in the filter.
+// The purpose of this test: sometimes the filter will consume input without
+// generating output. Verify filter can handle it correctly.
+TEST_F(BrotliSourceStreamTest, DecodeWithOneByteBuffer) {
+ source()->AddReadResult(encoded_buffer(), encoded_len(), OK,
+ MockSourceStream::SYNC);
+ // Add a 0 byte read to signal EOF.
+ source()->AddReadResult(encoded_buffer(), 0, OK, MockSourceStream::SYNC);
+ out_buffer_ = new IOBufferWithSize(1);
+ scoped_refptr<IOBuffer> buffer = new IOBufferWithSize(source_data_len());
+ size_t total_bytes_read = 0;
+ int bytes_read = 0;
+ do {
+ TestCompletionCallback callback;
+ bytes_read = ReadStream(callback);
+ EXPECT_NE(ERR_IO_PENDING, bytes_read);
+ EXPECT_GE(1, bytes_read);
+ memcpy(buffer->data() + total_bytes_read, out_data(), bytes_read);
+ total_bytes_read += bytes_read;
+ } while (bytes_read > 0);
+ EXPECT_EQ(source_data_len(), total_bytes_read);
+ EXPECT_EQ(0,
+ memcmp(buffer->data(), source_data().c_str(), source_data_len()));
+ EXPECT_EQ("BROTLI", brotli_stream()->Description());
+}
+
+// Decoding deflate stream with corrupted data.
+TEST_F(BrotliSourceStreamTest, DecodeCorruptedData) {
+ char corrupt_data[kDefaultBufferSize];
+ int corrupt_data_len = encoded_len();
+ memcpy(corrupt_data, encoded_buffer(), encoded_len());
+ int pos = corrupt_data_len / 2;
+ corrupt_data[pos] = !corrupt_data[pos];
+
+ source()->AddReadResult(corrupt_data, corrupt_data_len, OK,
+ MockSourceStream::SYNC);
+ out_buffer_ = new IOBufferWithSize(kDefaultBufferSize);
+ int error = OK;
+ do {
+ TestCompletionCallback callback;
+ error = ReadStream(callback);
+ EXPECT_NE(ERR_IO_PENDING, error);
+ } while (error > 0);
+ // Expect failures
+ EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, error);
+ EXPECT_EQ("BROTLI", brotli_stream()->Description());
+}
+
+// Decoding deflate stream with missing data.
+TEST_F(BrotliSourceStreamTest, DecodeMissingData) {
+ char corrupt_data[kDefaultBufferSize];
+ int corrupt_data_len = encoded_len();
+ memcpy(corrupt_data, encoded_buffer(), encoded_len());
+
+ int pos = corrupt_data_len / 2;
+ int len = corrupt_data_len - pos - 1;
+ memmove(&corrupt_data[pos], &corrupt_data[pos + 1], len);
+ --corrupt_data_len;
+
+ // Decode the corrupted data with filter
+ source()->AddReadResult(corrupt_data, corrupt_data_len, OK,
+ MockSourceStream::SYNC);
+ out_buffer_ = new IOBufferWithSize(kDefaultBufferSize);
+ int error = OK;
+ do {
+ TestCompletionCallback callback;
+ error = ReadStream(callback);
+ EXPECT_NE(ERR_IO_PENDING, error);
+ } while (error > 0);
+ // Expect failures
+ EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, error);
+ EXPECT_EQ("BROTLI", brotli_stream()->Description());
+}
+
+// Decoding brotli stream with empty output data.
+TEST_F(BrotliSourceStreamTest, DecodeEmptyData) {
+ char data[1] = {6}; // WBITS = 16, ISLAST = 1, ISLASTEMPTY = 1
+ int data_len = 1;
+
+ source()->AddReadResult(data, data_len, OK, MockSourceStream::SYNC);
+ source()->AddReadResult(data, 0, OK, MockSourceStream::SYNC);
+ out_buffer_ = new IOBufferWithSize(kDefaultBufferSize);
+ TestCompletionCallback callback;
+ int bytes_read = ReadStream(callback);
+ EXPECT_EQ(OK, bytes_read);
+ EXPECT_EQ("BROTLI", brotli_stream()->Description());
+}
+
+} // namespace net
diff --git a/chromium/net/filter/filter.cc b/chromium/net/filter/filter.cc
index ea7eca6bc72..31a9d1a6fb4 100644
--- a/chromium/net/filter/filter.cc
+++ b/chromium/net/filter/filter.cc
@@ -31,6 +31,8 @@
#include "net/filter/brotli_filter.h"
#include "net/filter/gzip_filter.h"
#include "net/filter/sdch_filter.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/url_request/url_request_context.h"
#include "url/gurl.h"
@@ -58,7 +60,7 @@ void LogSdchProblem(const FilterContext& filter_context,
SdchProblemCode problem) {
SdchManager::SdchErrorRecovery(problem);
filter_context.GetNetLog().AddEvent(
- NetLog::TYPE_SDCH_DECODING_ERROR,
+ NetLogEventType::SDCH_DECODING_ERROR,
base::Bind(&NetLogSdchResourceProblemCallback, problem));
}
diff --git a/chromium/net/filter/filter.h b/chromium/net/filter/filter.h
index 78b8c34b02e..91875a242c9 100644
--- a/chromium/net/filter/filter.h
+++ b/chromium/net/filter/filter.h
@@ -63,8 +63,8 @@ class GURL;
namespace net {
-class BoundNetLog;
class IOBuffer;
+class NetLogWithSource;
class URLRequestContext;
//------------------------------------------------------------------------------
@@ -128,12 +128,12 @@ class NET_EXPORT_PRIVATE FilterContext {
// statistics as selected by the argument.
virtual void RecordPacketStats(StatisticSelector statistic) const = 0;
- // The BoundNetLog of the associated request.
- virtual const BoundNetLog& GetNetLog() const = 0;
+ // The NetLogWithSource of the associated request.
+ virtual const NetLogWithSource& GetNetLog() const = 0;
};
//------------------------------------------------------------------------------
-class NET_EXPORT_PRIVATE Filter {
+class NET_EXPORT Filter {
public:
// Return values of function ReadFilteredData.
enum FilterStatus {
diff --git a/chromium/net/filter/filter_source_stream.cc b/chromium/net/filter/filter_source_stream.cc
new file mode 100644
index 00000000000..43bd67d424c
--- /dev/null
+++ b/chromium/net/filter/filter_source_stream.cc
@@ -0,0 +1,176 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/filter/filter_source_stream.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_util.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+
+namespace net {
+
+namespace {
+
+const size_t kBufferSize = 32 * 1024;
+
+} // namespace
+
+FilterSourceStream::FilterSourceStream(SourceType type,
+ std::unique_ptr<SourceStream> upstream)
+ : SourceStream(type),
+ upstream_(std::move(upstream)),
+ next_state_(STATE_NONE),
+ output_buffer_size_(0),
+ upstream_end_reached_(false) {
+ DCHECK(upstream_);
+}
+
+FilterSourceStream::~FilterSourceStream() {}
+
+int FilterSourceStream::Read(IOBuffer* read_buffer,
+ int read_buffer_size,
+ const CompletionCallback& callback) {
+ DCHECK_EQ(STATE_NONE, next_state_);
+ DCHECK(read_buffer);
+ DCHECK_LT(0, read_buffer_size);
+
+ // Allocate a BlockBuffer during first Read().
+ if (!input_buffer_) {
+ input_buffer_ = new IOBufferWithSize(kBufferSize);
+ // This is first Read(), start with reading data from |upstream_|.
+ next_state_ = STATE_READ_DATA;
+ } else {
+ // Otherwise start with filtering data, which will tell us whether this
+ // stream needs input data.
+ next_state_ = STATE_FILTER_DATA;
+ }
+
+ output_buffer_ = read_buffer;
+ output_buffer_size_ = read_buffer_size;
+ int rv = DoLoop(OK);
+
+ if (rv == ERR_IO_PENDING)
+ callback_ = callback;
+ return rv;
+}
+
+std::string FilterSourceStream::Description() const {
+ std::string next_type_string = upstream_->Description();
+ if (next_type_string.empty())
+ return GetTypeAsString();
+ return next_type_string + "," + GetTypeAsString();
+}
+
+int FilterSourceStream::DoLoop(int result) {
+ DCHECK_NE(STATE_NONE, next_state_);
+
+ int rv = result;
+ do {
+ State state = next_state_;
+ next_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_READ_DATA:
+ rv = DoReadData();
+ break;
+ case STATE_READ_DATA_COMPLETE:
+ rv = DoReadDataComplete(rv);
+ break;
+ case STATE_FILTER_DATA:
+ DCHECK_LE(0, rv);
+ rv = DoFilterData();
+ break;
+ default:
+ NOTREACHED() << "bad state: " << state;
+ rv = ERR_UNEXPECTED;
+ break;
+ }
+ } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
+ return rv;
+}
+
+int FilterSourceStream::DoReadData() {
+ // Read more data means subclasses have consumed all input or this is the
+ // first read in which case the |drainable_input_buffer_| is not initialized.
+ DCHECK(drainable_input_buffer_ == nullptr ||
+ 0 == drainable_input_buffer_->BytesRemaining());
+
+ next_state_ = STATE_READ_DATA_COMPLETE;
+ // Use base::Unretained here is safe because |this| owns |upstream_|.
+ int rv = upstream_->Read(
+ input_buffer_.get(), kBufferSize,
+ base::Bind(&FilterSourceStream::OnIOComplete, base::Unretained(this)));
+
+ return rv;
+}
+
+int FilterSourceStream::DoReadDataComplete(int result) {
+ DCHECK_NE(ERR_IO_PENDING, result);
+
+ if (result >= OK) {
+ drainable_input_buffer_ =
+ new DrainableIOBuffer(input_buffer_.get(), result);
+ next_state_ = STATE_FILTER_DATA;
+ }
+ if (result <= OK)
+ upstream_end_reached_ = true;
+ return result;
+}
+
+int FilterSourceStream::DoFilterData() {
+ DCHECK(output_buffer_);
+ DCHECK(drainable_input_buffer_);
+
+ int consumed_bytes = 0;
+ int bytes_output = FilterData(output_buffer_.get(), output_buffer_size_,
+ drainable_input_buffer_.get(),
+ drainable_input_buffer_->BytesRemaining(),
+ &consumed_bytes, upstream_end_reached_);
+ DCHECK_LE(consumed_bytes, drainable_input_buffer_->BytesRemaining());
+ DCHECK(bytes_output != 0 ||
+ consumed_bytes == drainable_input_buffer_->BytesRemaining());
+
+ if (bytes_output == ERR_CONTENT_DECODING_FAILED) {
+ UMA_HISTOGRAM_ENUMERATION("Net.ContentDecodingFailed.FilterType", type(),
+ TYPE_MAX);
+ }
+ // FilterData() is not allowed to return ERR_IO_PENDING.
+ DCHECK_NE(ERR_IO_PENDING, bytes_output);
+
+ if (consumed_bytes > 0)
+ drainable_input_buffer_->DidConsume(consumed_bytes);
+
+ // Received data or encountered an error.
+ if (bytes_output != 0)
+ return bytes_output;
+ // If no data is returned, continue reading if |this| needs more input.
+ if (NeedMoreData()) {
+ DCHECK_EQ(0, drainable_input_buffer_->BytesRemaining());
+ next_state_ = STATE_READ_DATA;
+ }
+ return bytes_output;
+}
+
+void FilterSourceStream::OnIOComplete(int result) {
+ DCHECK_EQ(STATE_READ_DATA_COMPLETE, next_state_);
+
+ int rv = DoLoop(result);
+ if (rv == ERR_IO_PENDING)
+ return;
+
+ output_buffer_ = nullptr;
+ output_buffer_size_ = 0;
+
+ base::ResetAndReturn(&callback_).Run(rv);
+}
+
+bool FilterSourceStream::NeedMoreData() const {
+ return !upstream_end_reached_;
+}
+
+} // namespace net
diff --git a/chromium/net/filter/filter_source_stream.h b/chromium/net/filter/filter_source_stream.h
new file mode 100644
index 00000000000..3d24bd1a921
--- /dev/null
+++ b/chromium/net/filter/filter_source_stream.h
@@ -0,0 +1,119 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_FILTER_FILTER_SOURCE_STREAM_H_
+#define NET_FILTER_FILTER_SOURCE_STREAM_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_export.h"
+#include "net/filter/source_stream.h"
+
+namespace net {
+
+class DrainableIOBuffer;
+class IOBuffer;
+
+// FilterSourceStream represents SourceStreams that always have an upstream
+// from which undecoded input can be read. Except the ultimate upstream in
+// the filter chain, all other streams should implement FilterSourceStream
+// instead of SourceStream.
+class NET_EXPORT_PRIVATE FilterSourceStream : public SourceStream {
+ public:
+ // |upstream| is the SourceStream from which |this| will read data.
+ // |upstream| cannot be null.
+ FilterSourceStream(SourceType type, std::unique_ptr<SourceStream> upstream);
+
+ ~FilterSourceStream() override;
+
+ int Read(IOBuffer* read_buffer,
+ int read_buffer_size,
+ const CompletionCallback& callback) override;
+
+ std::string Description() const override;
+
+ private:
+ enum State {
+ STATE_NONE,
+ // Reading data from |upstream_| into |input_buffer_|.
+ STATE_READ_DATA,
+ // Reading data from |upstream_| completed.
+ STATE_READ_DATA_COMPLETE,
+ // Filtering data contained in |input_buffer_|.
+ STATE_FILTER_DATA,
+ // Filtering data contained in |input_buffer_| completed.
+ STATE_FILTER_DATA_COMPLETE,
+ STATE_DONE,
+ };
+
+ int DoLoop(int result);
+ int DoReadData();
+ int DoReadDataComplete(int result);
+ int DoFilterData();
+
+ // Helper method used as a callback argument passed to |upstream_->Read()|.
+ void OnIOComplete(int result);
+
+ // Subclasses should implement this method to filter data from
+ // |input_buffer| and write to |output_buffer|.
+ // This method must complete synchronously (i.e. It cannot return
+ // ERR_IO_PENDING). If an unrecoverable error occurred, this should return
+ // ERR_CONTENT_DECODING_FAILED or a more specific error code.
+ //
+ // If FilterData() returns 0, *|consumed_bytes| must be equal to
+ // |input_buffer_size|. Upstream EOF is reached when FilterData() is called
+ // with |upstream_eof_reached| = true.
+ // TODO(xunjieli): consider allowing asynchronous response via callback
+ // to support off-thread decompression.
+ virtual int FilterData(IOBuffer* output_buffer,
+ int output_buffer_size,
+ IOBuffer* input_buffer,
+ int input_buffer_size,
+ int* consumed_bytes,
+ bool upstream_eof_reached) = 0;
+
+ // Returns a string representation of the type of this FilterSourceStream.
+ // This is for UMA logging.
+ virtual std::string GetTypeAsString() const = 0;
+
+ // Returns whether |this| still needs more input data from |upstream_|.
+ // By default, |this| will continue reading until |upstream_| returns an error
+ // or EOF. Subclass can override this to return false to skip reading all the
+ // input from |upstream_|.
+ virtual bool NeedMoreData() const;
+
+ // The SourceStream from which |this| will read data from. Data flows from
+ // |upstream_| to |this_|.
+ std::unique_ptr<SourceStream> upstream_;
+
+ State next_state_;
+
+ // Buffer for reading data out of |upstream_| and then for use by |this|
+ // before the filtered data is returned through Read().
+ scoped_refptr<IOBuffer> input_buffer_;
+
+ // Wrapper around |input_buffer_| that makes visible only the unread data.
+ // Keep this as a member because subclass might not drain everything in a
+ // single FilterData().
+ scoped_refptr<DrainableIOBuffer> drainable_input_buffer_;
+
+ // Not null if there is a pending Read.
+ scoped_refptr<IOBuffer> output_buffer_;
+ int output_buffer_size_;
+ CompletionCallback callback_;
+
+ // Reading from |upstream_| has returned 0 byte or an error code.
+ bool upstream_end_reached_;
+
+ DISALLOW_COPY_AND_ASSIGN(FilterSourceStream);
+};
+
+} // namespace net
+
+#endif // NET_FILTER_FILTER_SOURCE_STREAM_H_
diff --git a/chromium/net/filter/filter_source_stream_unittest.cc b/chromium/net/filter/filter_source_stream_unittest.cc
new file mode 100644
index 00000000000..70a6d12a19d
--- /dev/null
+++ b/chromium/net/filter/filter_source_stream_unittest.cc
@@ -0,0 +1,547 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <algorithm>
+#include <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/filter/filter_source_stream.h"
+#include "net/filter/mock_source_stream.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+const size_t kDefaultBufferSize = 4096;
+const size_t kSmallBufferSize = 1;
+
+class TestFilterSourceStreamBase : public FilterSourceStream {
+ public:
+ TestFilterSourceStreamBase(std::unique_ptr<SourceStream> upstream)
+ : FilterSourceStream(SourceStream::TYPE_NONE, std::move(upstream)) {}
+ ~TestFilterSourceStreamBase() override { DCHECK(buffer_.empty()); }
+ std::string GetTypeAsString() const override { return type_string_; }
+
+ void set_type_string(const std::string& type_string) {
+ type_string_ = type_string;
+ }
+
+ protected:
+ // Writes contents of |buffer_| to |output_buffer| and returns the number of
+ // bytes written or an error code. Additionally removes consumed data from
+ // |buffer_|.
+ int WriteBufferToOutput(IOBuffer* output_buffer, int output_buffer_size) {
+ size_t bytes_to_filter =
+ std::min(buffer_.length(), static_cast<size_t>(output_buffer_size));
+ memcpy(output_buffer->data(), buffer_.data(), bytes_to_filter);
+ buffer_.erase(0, bytes_to_filter);
+ return base::checked_cast<int>(bytes_to_filter);
+ }
+
+ // Buffer used by subclasses to hold data that is yet to be passed to the
+ // caller.
+ std::string buffer_;
+
+ private:
+ std::string type_string_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestFilterSourceStreamBase);
+};
+
+// A FilterSourceStream that needs all input data before it can return non-zero
+// bytes read.
+class NeedsAllInputFilterSourceStream : public TestFilterSourceStreamBase {
+ public:
+ NeedsAllInputFilterSourceStream(std::unique_ptr<SourceStream> upstream,
+ size_t expected_input_bytes)
+ : TestFilterSourceStreamBase(std::move(upstream)),
+ expected_input_bytes_(expected_input_bytes) {}
+ int FilterData(IOBuffer* output_buffer,
+ int output_buffer_size,
+ IOBuffer* input_buffer,
+ int input_buffer_size,
+ int* consumed_bytes,
+ bool upstream_eof_reached) override {
+ buffer_.append(input_buffer->data(), input_buffer_size);
+ EXPECT_GE(expected_input_bytes_, input_buffer_size);
+ expected_input_bytes_ -= input_buffer_size;
+ *consumed_bytes = input_buffer_size;
+ if (!upstream_eof_reached) {
+ // Keep returning 0 bytes read until all input has been consumed.
+ return 0;
+ }
+ EXPECT_EQ(0, expected_input_bytes_);
+ return WriteBufferToOutput(output_buffer, output_buffer_size);
+ }
+
+ private:
+ // Expected remaining bytes to be received from |upstream|.
+ int expected_input_bytes_;
+
+ DISALLOW_COPY_AND_ASSIGN(NeedsAllInputFilterSourceStream);
+};
+
+// A FilterSourceStream that repeat every input byte by |multiplier| amount of
+// times.
+class MultiplySourceStream : public TestFilterSourceStreamBase {
+ public:
+ MultiplySourceStream(std::unique_ptr<SourceStream> upstream, int multiplier)
+ : TestFilterSourceStreamBase(std::move(upstream)),
+ multiplier_(multiplier) {}
+ int FilterData(IOBuffer* output_buffer,
+ int output_buffer_size,
+ IOBuffer* input_buffer,
+ int input_buffer_size,
+ int* consumed_bytes,
+ bool /*upstream_eof_reached*/) override {
+ for (int i = 0; i < input_buffer_size; i++) {
+ for (int j = 0; j < multiplier_; j++)
+ buffer_.append(input_buffer->data() + i, 1);
+ }
+ *consumed_bytes = input_buffer_size;
+ return WriteBufferToOutput(output_buffer, output_buffer_size);
+ }
+
+ private:
+ int multiplier_;
+
+ DISALLOW_COPY_AND_ASSIGN(MultiplySourceStream);
+};
+
+// A FilterSourceStream passes through data unchanged to consumer.
+class PassThroughFilterSourceStream : public TestFilterSourceStreamBase {
+ public:
+ explicit PassThroughFilterSourceStream(std::unique_ptr<SourceStream> upstream)
+ : TestFilterSourceStreamBase(std::move(upstream)) {}
+ int FilterData(IOBuffer* output_buffer,
+ int output_buffer_size,
+ IOBuffer* input_buffer,
+ int input_buffer_size,
+ int* consumed_bytes,
+ bool /*upstream_eof_reached*/) override {
+ buffer_.append(input_buffer->data(), input_buffer_size);
+ *consumed_bytes = input_buffer_size;
+ return WriteBufferToOutput(output_buffer, output_buffer_size);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PassThroughFilterSourceStream);
+};
+
+// A FilterSourceStream passes throttle input data such that it returns them to
+// caller only one bytes at a time.
+class ThrottleSourceStream : public TestFilterSourceStreamBase {
+ public:
+ explicit ThrottleSourceStream(std::unique_ptr<SourceStream> upstream)
+ : TestFilterSourceStreamBase(std::move(upstream)) {}
+ int FilterData(IOBuffer* output_buffer,
+ int output_buffer_size,
+ IOBuffer* input_buffer,
+ int input_buffer_size,
+ int* consumed_bytes,
+ bool /*upstream_eof_reached*/) override {
+ buffer_.append(input_buffer->data(), input_buffer_size);
+ *consumed_bytes = input_buffer_size;
+ int bytes_to_read = std::min(1, static_cast<int>(buffer_.size()));
+ memcpy(output_buffer->data(), buffer_.data(), bytes_to_read);
+ buffer_.erase(0, bytes_to_read);
+ return bytes_to_read;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ThrottleSourceStream);
+};
+
+// A FilterSourceStream that consumes all input data but return no output.
+class NoOutputSourceStream : public TestFilterSourceStreamBase {
+ public:
+ NoOutputSourceStream(std::unique_ptr<SourceStream> upstream,
+ size_t expected_input_size)
+ : TestFilterSourceStreamBase(std::move(upstream)),
+ expected_input_size_(expected_input_size),
+ consumed_all_input_(false) {}
+ int FilterData(IOBuffer* output_buffer,
+ int output_buffer_size,
+ IOBuffer* input_buffer,
+ int input_buffer_size,
+ int* consumed_bytes,
+ bool /*upstream_eof_reached*/) override {
+ expected_input_size_ -= input_buffer_size;
+ *consumed_bytes = input_buffer_size;
+ EXPECT_LE(0, expected_input_size_);
+ consumed_all_input_ = (expected_input_size_ == 0);
+ return OK;
+ }
+
+ bool consumed_all_input() const { return consumed_all_input_; }
+
+ private:
+ // Expected remaining bytes to be received from |upstream|.
+ int expected_input_size_;
+ bool consumed_all_input_;
+
+ DISALLOW_COPY_AND_ASSIGN(NoOutputSourceStream);
+};
+
+// A FilterSourceStream return an error code in FilterData().
+class ErrorFilterSourceStream : public FilterSourceStream {
+ public:
+ explicit ErrorFilterSourceStream(std::unique_ptr<SourceStream> upstream)
+ : FilterSourceStream(SourceStream::TYPE_NONE, std::move(upstream)) {}
+
+ int FilterData(IOBuffer* output_buffer,
+ int output_buffer_size,
+ IOBuffer* input_buffer,
+ int input_buffer_size,
+ int* consumed_bytes,
+ bool /*upstream_eof_reached*/) override {
+ return ERR_CONTENT_DECODING_FAILED;
+ }
+ std::string GetTypeAsString() const override { return ""; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ErrorFilterSourceStream);
+};
+
+} // namespace
+
+class FilterSourceStreamTest
+ : public ::testing::TestWithParam<MockSourceStream::Mode> {
+ protected:
+ // If MockSourceStream::Mode is ASYNC, completes |num_reads| from
+ // |mock_stream| and wait for |callback| to complete. If Mode is not ASYNC,
+ // does nothing and returns |previous_result|.
+ int CompleteReadIfAsync(int previous_result,
+ TestCompletionCallback* callback,
+ MockSourceStream* mock_stream,
+ size_t num_reads) {
+ if (GetParam() == MockSourceStream::ASYNC) {
+ EXPECT_EQ(ERR_IO_PENDING, previous_result);
+ while (num_reads > 0) {
+ mock_stream->CompleteNextRead();
+ num_reads--;
+ }
+ return callback->WaitForResult();
+ }
+ return previous_result;
+ }
+};
+
+INSTANTIATE_TEST_CASE_P(FilterSourceStreamTests,
+ FilterSourceStreamTest,
+ ::testing::Values(MockSourceStream::SYNC,
+ MockSourceStream::ASYNC));
+
+// Tests that a FilterSourceStream subclass (NeedsAllInputFilterSourceStream)
+// can return 0 bytes for FilterData()s when it has not consumed EOF from the
+// upstream. In this case, FilterSourceStream should continue reading from
+// upstream to complete filtering.
+TEST_P(FilterSourceStreamTest, FilterDataReturnNoBytesExceptLast) {
+ std::unique_ptr<MockSourceStream> source(new MockSourceStream);
+ std::string input("hello, world!");
+ size_t read_size = 2;
+ size_t num_reads = 0;
+ // Add a sequence of small reads.
+ for (size_t offset = 0; offset < input.length(); offset += read_size) {
+ source->AddReadResult(input.data() + offset,
+ std::min(read_size, input.length() - offset), OK,
+ GetParam());
+ num_reads++;
+ }
+ source->AddReadResult(input.data(), 0, OK, GetParam()); // EOF
+ num_reads++;
+
+ MockSourceStream* mock_stream = source.get();
+ NeedsAllInputFilterSourceStream stream(std::move(source), input.length());
+ scoped_refptr<IOBufferWithSize> output_buffer =
+ new IOBufferWithSize(kDefaultBufferSize);
+ TestCompletionCallback callback;
+ std::string actual_output;
+ while (true) {
+ int rv = stream.Read(output_buffer.get(), output_buffer->size(),
+ callback.callback());
+ if (rv == ERR_IO_PENDING)
+ rv = CompleteReadIfAsync(rv, &callback, mock_stream, num_reads);
+ if (rv == OK)
+ break;
+ ASSERT_GT(rv, OK);
+ actual_output.append(output_buffer->data(), rv);
+ }
+ EXPECT_EQ(input, actual_output);
+}
+
+// Tests that FilterData() returns 0 byte read because the upstream gives an
+// EOF.
+TEST_P(FilterSourceStreamTest, FilterDataReturnNoByte) {
+ std::unique_ptr<MockSourceStream> source(new MockSourceStream);
+ std::string input;
+ source->AddReadResult(input.data(), 0, OK, GetParam());
+ MockSourceStream* mock_stream = source.get();
+ PassThroughFilterSourceStream stream(std::move(source));
+ scoped_refptr<IOBufferWithSize> output_buffer =
+ new IOBufferWithSize(kDefaultBufferSize);
+ TestCompletionCallback callback;
+ int rv = stream.Read(output_buffer.get(), output_buffer->size(),
+ callback.callback());
+ rv = CompleteReadIfAsync(rv, &callback, mock_stream, 1);
+ EXPECT_EQ(OK, rv);
+}
+
+// Tests that FilterData() returns 0 byte filtered even though the upstream
+// produces data.
+TEST_P(FilterSourceStreamTest, FilterDataOutputNoData) {
+ std::unique_ptr<MockSourceStream> source(new MockSourceStream);
+ std::string input = "hello, world!";
+ size_t read_size = 2;
+ size_t num_reads = 0;
+ // Add a sequence of small reads.
+ for (size_t offset = 0; offset < input.length(); offset += read_size) {
+ source->AddReadResult(input.data() + offset,
+ std::min(read_size, input.length() - offset), OK,
+ GetParam());
+ num_reads++;
+ }
+ // Add a 0 byte read to signal EOF.
+ source->AddReadResult(input.data() + input.length(), 0, OK, GetParam());
+ num_reads++;
+ MockSourceStream* mock_stream = source.get();
+ NoOutputSourceStream stream(std::move(source), input.length());
+ scoped_refptr<IOBufferWithSize> output_buffer =
+ new IOBufferWithSize(kDefaultBufferSize);
+ TestCompletionCallback callback;
+ int rv = stream.Read(output_buffer.get(), output_buffer->size(),
+ callback.callback());
+ rv = CompleteReadIfAsync(rv, &callback, mock_stream, num_reads);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(stream.consumed_all_input());
+}
+
+// Tests that FilterData() returns non-zero bytes because the upstream
+// returns data.
+TEST_P(FilterSourceStreamTest, FilterDataReturnData) {
+ std::unique_ptr<MockSourceStream> source(new MockSourceStream);
+ std::string input = "hello, world!";
+ size_t read_size = 2;
+ // Add a sequence of small reads.
+ for (size_t offset = 0; offset < input.length(); offset += read_size) {
+ source->AddReadResult(input.data() + offset,
+ std::min(read_size, input.length() - offset), OK,
+ GetParam());
+ }
+ // Add a 0 byte read to signal EOF.
+ source->AddReadResult(input.data() + input.length(), 0, OK, GetParam());
+ MockSourceStream* mock_stream = source.get();
+ PassThroughFilterSourceStream stream(std::move(source));
+ scoped_refptr<IOBufferWithSize> output_buffer =
+ new IOBufferWithSize(kDefaultBufferSize);
+ TestCompletionCallback callback;
+ std::string actual_output;
+ while (true) {
+ int rv = stream.Read(output_buffer.get(), output_buffer->size(),
+ callback.callback());
+ rv = CompleteReadIfAsync(rv, &callback, mock_stream, /*num_reads=*/1);
+ if (rv == OK)
+ break;
+ ASSERT_GE(static_cast<int>(read_size), rv);
+ ASSERT_GT(rv, OK);
+ actual_output.append(output_buffer->data(), rv);
+ }
+ EXPECT_EQ(input, actual_output);
+}
+
+// Tests that FilterData() returns more data than what it consumed.
+TEST_P(FilterSourceStreamTest, FilterDataReturnMoreData) {
+ std::unique_ptr<MockSourceStream> source(new MockSourceStream);
+ std::string input = "hello, world!";
+ size_t read_size = 2;
+ // Add a sequence of small reads.
+ for (size_t offset = 0; offset < input.length(); offset += read_size) {
+ source->AddReadResult(input.data() + offset,
+ std::min(read_size, input.length() - offset), OK,
+ GetParam());
+ }
+ // Add a 0 byte read to signal EOF.
+ source->AddReadResult(input.data() + input.length(), 0, OK, GetParam());
+ MockSourceStream* mock_stream = source.get();
+ int multiplier = 2;
+ MultiplySourceStream stream(std::move(source), multiplier);
+ scoped_refptr<IOBufferWithSize> output_buffer =
+ new IOBufferWithSize(kDefaultBufferSize);
+ TestCompletionCallback callback;
+ std::string actual_output;
+ while (true) {
+ int rv = stream.Read(output_buffer.get(), output_buffer->size(),
+ callback.callback());
+ rv = CompleteReadIfAsync(rv, &callback, mock_stream, /*num_reads=*/1);
+ if (rv == OK)
+ break;
+ ASSERT_GE(static_cast<int>(read_size) * multiplier, rv);
+ ASSERT_GT(rv, OK);
+ actual_output.append(output_buffer->data(), rv);
+ }
+ EXPECT_EQ("hheelllloo,, wwoorrlldd!!", actual_output);
+}
+
+// Tests that FilterData() returns non-zero bytes and output buffer size is
+// smaller than the number of bytes read from the upstream.
+TEST_P(FilterSourceStreamTest, FilterDataOutputSpace) {
+ std::unique_ptr<MockSourceStream> source(new MockSourceStream);
+ std::string input = "hello, world!";
+ size_t read_size = 2;
+ // Add a sequence of small reads.
+ for (size_t offset = 0; offset < input.length(); offset += read_size) {
+ source->AddReadResult(input.data() + offset,
+ std::min(read_size, input.length() - offset), OK,
+ GetParam());
+ }
+ // Add a 0 byte read to signal EOF.
+ source->AddReadResult(input.data() + input.length(), 0, OK, GetParam());
+ // Use an extremely small buffer size, so FilterData will need more output
+ // space.
+ scoped_refptr<IOBufferWithSize> output_buffer =
+ new IOBufferWithSize(kSmallBufferSize);
+ MockSourceStream* mock_stream = source.get();
+ PassThroughFilterSourceStream stream(std::move(source));
+ TestCompletionCallback callback;
+ std::string actual_output;
+ while (true) {
+ int rv = stream.Read(output_buffer.get(), output_buffer->size(),
+ callback.callback());
+ if (rv == ERR_IO_PENDING)
+ rv = CompleteReadIfAsync(rv, &callback, mock_stream, /*num_reads=*/1);
+ if (rv == OK)
+ break;
+ ASSERT_GT(rv, OK);
+ ASSERT_GE(kSmallBufferSize, static_cast<size_t>(rv));
+ actual_output.append(output_buffer->data(), rv);
+ }
+ EXPECT_EQ(input, actual_output);
+}
+
+// Tests that FilterData() returns an error code, which is then surfaced as
+// the result of calling Read().
+TEST_P(FilterSourceStreamTest, FilterDataReturnError) {
+ std::unique_ptr<MockSourceStream> source(new MockSourceStream);
+ std::string input;
+ source->AddReadResult(input.data(), 0, OK, GetParam());
+ scoped_refptr<IOBufferWithSize> output_buffer =
+ new IOBufferWithSize(kDefaultBufferSize);
+ MockSourceStream* mock_stream = source.get();
+ ErrorFilterSourceStream stream(std::move(source));
+ TestCompletionCallback callback;
+ int rv = stream.Read(output_buffer.get(), output_buffer->size(),
+ callback.callback());
+ rv = CompleteReadIfAsync(rv, &callback, mock_stream, /*num_reads=*/1);
+ EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, rv);
+ // Reading from |stream| again should return the same error.
+ rv = stream.Read(output_buffer.get(), output_buffer->size(),
+ callback.callback());
+ EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, rv);
+}
+
+TEST_P(FilterSourceStreamTest, FilterChaining) {
+ std::unique_ptr<MockSourceStream> source(new MockSourceStream);
+ std::string input = "hello, world!";
+ source->AddReadResult(input.data(), input.length(), OK, GetParam());
+ source->AddReadResult(input.data(), 0, OK, GetParam()); // EOF
+
+ MockSourceStream* mock_stream = source.get();
+ std::unique_ptr<PassThroughFilterSourceStream> pass_through_source(
+ new PassThroughFilterSourceStream(std::move(source)));
+ pass_through_source->set_type_string("FIRST_PASS_THROUGH");
+ std::unique_ptr<NeedsAllInputFilterSourceStream> needs_all_input_source(
+ new NeedsAllInputFilterSourceStream(std::move(pass_through_source),
+ input.length()));
+ needs_all_input_source->set_type_string("NEEDS_ALL");
+ std::unique_ptr<PassThroughFilterSourceStream> second_pass_through_source(
+ new PassThroughFilterSourceStream(std::move(needs_all_input_source)));
+ second_pass_through_source->set_type_string("SECOND_PASS_THROUGH");
+ scoped_refptr<IOBufferWithSize> output_buffer =
+ new IOBufferWithSize(kDefaultBufferSize);
+
+ TestCompletionCallback callback;
+ std::string actual_output;
+ while (true) {
+ int rv = second_pass_through_source->Read(
+ output_buffer.get(), output_buffer->size(), callback.callback());
+ if (rv == ERR_IO_PENDING)
+ rv = CompleteReadIfAsync(rv, &callback, mock_stream, /*num_reads=*/2);
+ if (rv == OK)
+ break;
+ ASSERT_GT(rv, OK);
+ actual_output.append(output_buffer->data(), rv);
+ }
+ EXPECT_EQ(input, actual_output);
+ // Type string (from left to right) should be the order of data flow.
+ EXPECT_EQ("FIRST_PASS_THROUGH,NEEDS_ALL,SECOND_PASS_THROUGH",
+ second_pass_through_source->Description());
+}
+
+// Tests that FilterData() returns multiple times for a single MockStream
+// read, because there is not enough output space.
+TEST_P(FilterSourceStreamTest, OutputSpaceForOneRead) {
+ std::unique_ptr<MockSourceStream> source(new MockSourceStream);
+ std::string input = "hello, world!";
+ source->AddReadResult(input.data(), input.length(), OK, GetParam());
+ // Add a 0 byte read to signal EOF.
+ source->AddReadResult(input.data() + input.length(), 0, OK, GetParam());
+ // Use an extremely small buffer size (1 byte), so FilterData will need more
+ // output space.
+ scoped_refptr<IOBufferWithSize> output_buffer =
+ new IOBufferWithSize(kSmallBufferSize);
+ MockSourceStream* mock_stream = source.get();
+ PassThroughFilterSourceStream stream(std::move(source));
+ TestCompletionCallback callback;
+ std::string actual_output;
+ while (true) {
+ int rv = stream.Read(output_buffer.get(), output_buffer->size(),
+ callback.callback());
+ if (rv == ERR_IO_PENDING)
+ rv = CompleteReadIfAsync(rv, &callback, mock_stream, /*num_reads=*/1);
+ if (rv == OK)
+ break;
+ ASSERT_GT(rv, OK);
+ ASSERT_GE(kSmallBufferSize, static_cast<size_t>(rv));
+ actual_output.append(output_buffer->data(), rv);
+ }
+ EXPECT_EQ(input, actual_output);
+}
+
+// Tests that FilterData() returns multiple times for a single MockStream
+// read, because the filter returns one byte at a time.
+TEST_P(FilterSourceStreamTest, ThrottleSourceStream) {
+ std::unique_ptr<MockSourceStream> source(new MockSourceStream);
+ std::string input = "hello, world!";
+ source->AddReadResult(input.data(), input.length(), OK, GetParam());
+ // Add a 0 byte read to signal EOF.
+ source->AddReadResult(input.data() + input.length(), 0, OK, GetParam());
+ scoped_refptr<IOBufferWithSize> output_buffer =
+ new IOBufferWithSize(kDefaultBufferSize);
+ MockSourceStream* mock_stream = source.get();
+ ThrottleSourceStream stream(std::move(source));
+ TestCompletionCallback callback;
+ std::string actual_output;
+ while (true) {
+ int rv = stream.Read(output_buffer.get(), output_buffer->size(),
+ callback.callback());
+ if (rv == ERR_IO_PENDING)
+ rv = CompleteReadIfAsync(rv, &callback, mock_stream, /*num_reads=*/1);
+ if (rv == OK)
+ break;
+ ASSERT_GT(rv, OK);
+ // ThrottleSourceStream returns 1 byte at a time.
+ ASSERT_GE(1u, static_cast<size_t>(rv));
+ actual_output.append(output_buffer->data(), rv);
+ }
+ EXPECT_EQ(input, actual_output);
+}
+
+} // namespace net
diff --git a/chromium/net/filter/gzip_header.h b/chromium/net/filter/gzip_header.h
index 91d695522ed..e9ecd0406c5 100644
--- a/chromium/net/filter/gzip_header.h
+++ b/chromium/net/filter/gzip_header.h
@@ -18,10 +18,11 @@
#include <stdint.h>
#include "base/macros.h"
+#include "net/base/net_export.h"
namespace net {
-class GZipHeader {
+class NET_EXPORT GZipHeader {
public:
enum Status {
INCOMPLETE_HEADER, // don't have all the bits yet...
diff --git a/chromium/net/filter/gzip_source_stream.cc b/chromium/net/filter/gzip_source_stream.cc
new file mode 100644
index 00000000000..7a0ac0cefb5
--- /dev/null
+++ b/chromium/net/filter/gzip_source_stream.cc
@@ -0,0 +1,221 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/filter/gzip_source_stream.h"
+
+#include "base/bind.h"
+#include "base/bit_cast.h"
+#include "base/logging.h"
+#include "net/base/io_buffer.h"
+#include "third_party/zlib/zlib.h"
+
+namespace net {
+
+namespace {
+
+const char kDeflate[] = "DEFLATE";
+const char kGzip[] = "GZIP";
+const char kGzipFallback[] = "GZIP_FALLBACK";
+
+} // namespace
+
+GzipSourceStream::~GzipSourceStream() {
+ if (zlib_stream_)
+ inflateEnd(zlib_stream_.get());
+}
+
+std::unique_ptr<GzipSourceStream> GzipSourceStream::Create(
+ std::unique_ptr<SourceStream> upstream,
+ SourceStream::SourceType type) {
+ std::unique_ptr<GzipSourceStream> source(
+ new GzipSourceStream(std::move(upstream), type));
+
+ if (!source->Init())
+ return nullptr;
+ return source;
+}
+
+GzipSourceStream::GzipSourceStream(std::unique_ptr<SourceStream> upstream,
+ SourceStream::SourceType type)
+ : FilterSourceStream(type, std::move(upstream)),
+ zlib_header_added_(false),
+ gzip_footer_bytes_left_(0),
+ input_state_(STATE_START) {}
+
+bool GzipSourceStream::Init() {
+ zlib_stream_.reset(new z_stream);
+ if (!zlib_stream_)
+ return false;
+ memset(zlib_stream_.get(), 0, sizeof(z_stream));
+
+ int ret;
+ if (type() == TYPE_GZIP || type() == TYPE_GZIP_FALLBACK) {
+ ret = inflateInit2(zlib_stream_.get(), -MAX_WBITS);
+ } else {
+ ret = inflateInit(zlib_stream_.get());
+ }
+ DCHECK_NE(Z_VERSION_ERROR, ret);
+ return ret == Z_OK;
+}
+
+std::string GzipSourceStream::GetTypeAsString() const {
+ switch (type()) {
+ case TYPE_GZIP:
+ return kGzip;
+ case TYPE_GZIP_FALLBACK:
+ return kGzipFallback;
+ case TYPE_DEFLATE:
+ return kDeflate;
+ default:
+ NOTREACHED();
+ return "";
+ }
+}
+
+int GzipSourceStream::FilterData(IOBuffer* output_buffer,
+ int output_buffer_size,
+ IOBuffer* input_buffer,
+ int input_buffer_size,
+ int* consumed_bytes,
+ bool /*upstream_end_reached*/) {
+ *consumed_bytes = 0;
+ char* input_data = input_buffer->data();
+ int input_data_size = input_buffer_size;
+ int bytes_out = 0;
+ bool state_compressed_entered = false;
+ while (input_data_size > 0) {
+ InputState state = input_state_;
+ switch (state) {
+ case STATE_START: {
+ if (type() == TYPE_DEFLATE) {
+ input_state_ = STATE_COMPRESSED_BODY;
+ break;
+ }
+ // If this stream is not really gzipped as detected by
+ // ShouldFallbackToPlain, pretend that the zlib stream has ended.
+ DCHECK_LT(0, input_data_size);
+ if (ShouldFallbackToPlain(input_data[0])) {
+ input_state_ = STATE_UNCOMPRESSED_BODY;
+ } else {
+ input_state_ = STATE_GZIP_HEADER;
+ }
+ break;
+ }
+ case STATE_GZIP_HEADER: {
+ const size_t kGzipFooterBytes = 8;
+ const char* end = nullptr;
+ GZipHeader::Status status =
+ gzip_header_.ReadMore(input_data, input_data_size, &end);
+ if (status == GZipHeader::INCOMPLETE_HEADER) {
+ input_data += input_data_size;
+ input_data_size = 0;
+ } else if (status == GZipHeader::COMPLETE_HEADER) {
+ // If there is a valid header, there should also be a valid footer.
+ gzip_footer_bytes_left_ = kGzipFooterBytes;
+ int bytes_consumed = end - input_data;
+ input_data += bytes_consumed;
+ input_data_size -= bytes_consumed;
+ input_state_ = STATE_COMPRESSED_BODY;
+ } else if (status == GZipHeader::INVALID_HEADER) {
+ return ERR_CONTENT_DECODING_FAILED;
+ }
+ break;
+ }
+ case STATE_COMPRESSED_BODY: {
+ DCHECK(!state_compressed_entered);
+ DCHECK_LE(0, input_data_size);
+
+ state_compressed_entered = true;
+ zlib_stream_.get()->next_in = bit_cast<Bytef*>(input_data);
+ zlib_stream_.get()->avail_in = input_data_size;
+ zlib_stream_.get()->next_out = bit_cast<Bytef*>(output_buffer->data());
+ zlib_stream_.get()->avail_out = output_buffer_size;
+
+ int ret = inflate(zlib_stream_.get(), Z_NO_FLUSH);
+
+ // Sometimes misconfigured servers omit the zlib header, relying on
+ // clients to splice it back in.
+ if (ret < 0 && !zlib_header_added_) {
+ zlib_header_added_ = true;
+ if (!InsertZlibHeader())
+ return ERR_CONTENT_DECODING_FAILED;
+
+ zlib_stream_.get()->next_in = bit_cast<Bytef*>(input_data);
+ zlib_stream_.get()->avail_in = input_data_size;
+ zlib_stream_.get()->next_out =
+ bit_cast<Bytef*>(output_buffer->data());
+ zlib_stream_.get()->avail_out = output_buffer_size;
+
+ ret = inflate(zlib_stream_.get(), Z_NO_FLUSH);
+ // TODO(xunjieli): add a histogram to see how often this happens. The
+ // original bug for this behavior was ancient and maybe it doesn't
+ // happen in the wild any more? crbug.com/649339
+ }
+ if (ret != Z_STREAM_END && ret != Z_OK)
+ return ERR_CONTENT_DECODING_FAILED;
+
+ int bytes_used = input_data_size - zlib_stream_.get()->avail_in;
+ bytes_out = output_buffer_size - zlib_stream_.get()->avail_out;
+ input_data_size -= bytes_used;
+ input_data += bytes_used;
+ if (ret == Z_STREAM_END) {
+ input_state_ = STATE_GZIP_FOOTER;
+ break;
+ }
+ // Return early here since zlib has written as much data to
+ // |output_buffer| as it could. There might still be some unconsumed
+ // data in |input_buffer| if there is no space in |output_buffer|.
+ DCHECK_EQ(Z_OK, ret);
+ *consumed_bytes = input_buffer_size - input_data_size;
+ return bytes_out;
+ }
+ case STATE_GZIP_FOOTER: {
+ size_t to_read = std::min(gzip_footer_bytes_left_,
+ base::checked_cast<size_t>(input_data_size));
+ gzip_footer_bytes_left_ -= to_read;
+ input_data_size -= to_read;
+ input_data += to_read;
+ if (gzip_footer_bytes_left_ == 0)
+ input_state_ = STATE_UNCOMPRESSED_BODY;
+ break;
+ }
+ case STATE_UNCOMPRESSED_BODY: {
+ int to_copy = std::min(input_data_size, output_buffer_size - bytes_out);
+ memcpy(output_buffer->data() + bytes_out, input_data, to_copy);
+ input_data_size -= to_copy;
+ input_data += to_copy;
+ bytes_out += to_copy;
+ break;
+ }
+ }
+ }
+ *consumed_bytes = input_buffer_size - input_data_size;
+ return bytes_out;
+}
+
+bool GzipSourceStream::InsertZlibHeader() {
+ char dummy_header[] = {0x78, 0x01};
+ char dummy_output[4];
+
+ inflateReset(zlib_stream_.get());
+ zlib_stream_.get()->next_in = bit_cast<Bytef*>(&dummy_header[0]);
+ zlib_stream_.get()->avail_in = sizeof(dummy_header);
+ zlib_stream_.get()->next_out = bit_cast<Bytef*>(&dummy_output[0]);
+ zlib_stream_.get()->avail_out = sizeof(dummy_output);
+
+ int ret = inflate(zlib_stream_.get(), Z_NO_FLUSH);
+ return ret == Z_OK;
+}
+
+// Dumb heuristic. Gzip files always start with a two-byte magic value per RFC
+// 1952 2.3.1, so if the first byte isn't the first byte of the gzip magic, and
+// this filter is checking whether it should fallback, then fallback.
+bool GzipSourceStream::ShouldFallbackToPlain(char first_byte) {
+ if (type() != TYPE_GZIP_FALLBACK)
+ return false;
+ static const char kGzipFirstByte = 0x1f;
+ return first_byte != kGzipFirstByte;
+}
+
+} // namespace net
diff --git a/chromium/net/filter/gzip_source_stream.h b/chromium/net/filter/gzip_source_stream.h
new file mode 100644
index 00000000000..556fd97b403
--- /dev/null
+++ b/chromium/net/filter/gzip_source_stream.h
@@ -0,0 +1,105 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_FILTER_GZIP_SOURCE_STREAM_H_
+#define NET_FILTER_GZIP_SOURCE_STREAM_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_export.h"
+#include "net/filter/filter_source_stream.h"
+#include "net/filter/gzip_header.h"
+
+typedef struct z_stream_s z_stream;
+
+namespace net {
+
+class IOBuffer;
+
+// GZipSourceStream applies gzip and deflate content encoding/decoding to a data
+// stream. As specified by HTTP 1.1, with gzip encoding the content is
+// wrapped with a gzip header, and with deflate encoding the content is in
+// a raw, headerless DEFLATE stream.
+//
+// Internally GZipSourceStream uses zlib inflate to do decoding.
+//
+class NET_EXPORT_PRIVATE GzipSourceStream : public FilterSourceStream {
+ public:
+ ~GzipSourceStream() override;
+
+ // Creates a GzipSourceStream. Return nullptr if initialization fails.
+ static std::unique_ptr<GzipSourceStream> Create(
+ std::unique_ptr<SourceStream> previous,
+ SourceStream::SourceType type);
+
+ private:
+ enum InputState {
+ // Starts processing the input stream. Checks whether the stream is valid
+ // and whether a fallback to plain data is needed.
+ STATE_START,
+ // Gzip header of the input stream is being processed.
+ STATE_GZIP_HEADER,
+ // The input stream is being decoded.
+ STATE_COMPRESSED_BODY,
+ // Gzip footer of the input stream is being processed.
+ STATE_GZIP_FOOTER,
+ // The input stream is being passed through undecoded.
+ STATE_UNCOMPRESSED_BODY,
+ };
+
+ GzipSourceStream(std::unique_ptr<SourceStream> previous,
+ SourceStream::SourceType type);
+
+ // Returns true if initialization is successful, false otherwise.
+ // For instance, this method returns false if there is not enough memory or
+ // if there is a version mismatch.
+ bool Init();
+
+ // SourceStream implementation
+ std::string GetTypeAsString() const override;
+ int FilterData(IOBuffer* output_buffer,
+ int output_buffer_size,
+ IOBuffer* input_buffer,
+ int input_buffer_size,
+ int* consumed_bytes,
+ bool upstream_end_reached) override;
+
+ // Inserts a zlib header to the data stream before calling zlib inflate.
+ // This is used to work around server bugs. The function returns true on
+ // success.
+ bool InsertZlibHeader();
+
+ // Returns whether this stream looks like it could be plain text (ie, not
+ // actually gzipped). Right now this uses an extremely simple heuristic; see
+ // the source for details. This method checks the first byte of the stream.
+ bool ShouldFallbackToPlain(char first_byte);
+
+ // The control block of zlib which actually does the decoding.
+ // This data structure is initialized by Init and updated only by
+ // FilterData(), with InsertZlibHeader() being the exception as a workaround.
+ std::unique_ptr<z_stream> zlib_stream_;
+
+ // A flag used by FilterData() to record whether we've successfully added
+ // a zlib header to this stream.
+ bool zlib_header_added_;
+
+ // Used to parse the gzip header in gzip stream.
+ // It is used when the decoding mode is GZIP_SOURCE_STREAM_GZIP.
+ GZipHeader gzip_header_;
+
+ // Tracks how many bytes of gzip footer are yet to be filtered.
+ size_t gzip_footer_bytes_left_;
+
+ // Tracks the state of the input stream.
+ InputState input_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(GzipSourceStream);
+};
+
+} // namespace net
+
+#endif // NET_FILTER_GZIP_SOURCE_STREAM_H__
diff --git a/chromium/net/filter/gzip_source_stream_unittest.cc b/chromium/net/filter/gzip_source_stream_unittest.cc
new file mode 100644
index 00000000000..4d31c88e16d
--- /dev/null
+++ b/chromium/net/filter/gzip_source_stream_unittest.cc
@@ -0,0 +1,420 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/bit_cast.h"
+#include "base/callback.h"
+#include "net/base/completion_callback.h"
+#include "net/base/io_buffer.h"
+#include "net/base/test_completion_callback.h"
+#include "net/filter/gzip_source_stream.h"
+#include "net/filter/mock_source_stream.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/zlib/zlib.h"
+
+namespace net {
+
+namespace {
+
+const int kBufferSize = 4096;
+const int kSmallBufferSize = 1;
+
+// How many bytes to leave unused at the end of |source_data_|. This margin is
+// present so that tests that need to append data after the zlib EOF do not run
+// out of room in the output buffer.
+const size_t kEOFMargin = 64;
+
+} // namespace
+
+class GzipSourceStreamTest
+ : public ::testing::TestWithParam<MockSourceStream::Mode> {
+ protected:
+ GzipSourceStreamTest() : output_buffer_size_(kBufferSize) {}
+ // If |allow_gzip_fallback| is true, will use
+ // GZIP_SOURCE_STREAM_GZIP_WITH_FALLBACK when constructing |gzip_stream_|.
+ void Init(bool allow_gzip_fallback) {
+ source_data_len_ = kBufferSize - kEOFMargin;
+
+ for (size_t i = 0; i < source_data_len_; i++)
+ source_data_[i] = i % 256;
+
+ deflated_data_len_ = kBufferSize;
+ Compress(source_data_, source_data_len_, deflated_data_,
+ &deflated_data_len_, false);
+
+ gzipped_data_len_ = kBufferSize;
+ Compress(source_data_, source_data_len_, gzipped_data_, &gzipped_data_len_,
+ true);
+
+ output_buffer_ = new IOBuffer(output_buffer_size_);
+ std::unique_ptr<MockSourceStream> deflate_source(new MockSourceStream);
+ deflate_source_ = deflate_source.get();
+ deflate_stream_ = GzipSourceStream::Create(std::move(deflate_source),
+ SourceStream::TYPE_DEFLATE);
+ std::unique_ptr<MockSourceStream> gzip_source(new MockSourceStream);
+ gzip_source_ = gzip_source.get();
+ if (allow_gzip_fallback) {
+ gzip_stream_ = GzipSourceStream::Create(std::move(gzip_source),
+ SourceStream::TYPE_GZIP_FALLBACK);
+ } else {
+ gzip_stream_ = GzipSourceStream::Create(std::move(gzip_source),
+ SourceStream::TYPE_GZIP);
+ }
+ }
+
+ // Compress |source| with length |source_len|. Write output into |dest|, and
+ // output length into |dest_len|. If |gzip_framing| is true, header will be
+ // added.
+ void Compress(char* source,
+ size_t source_len,
+ char* dest,
+ size_t* dest_len,
+ bool gzip_framing) {
+ size_t dest_left = *dest_len;
+ z_stream zlib_stream;
+ memset(&zlib_stream, 0, sizeof(zlib_stream));
+ int code;
+ if (gzip_framing) {
+ const int kMemLevel = 8; // the default, see deflateInit2(3)
+ code = deflateInit2(&zlib_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
+ -MAX_WBITS, kMemLevel, Z_DEFAULT_STRATEGY);
+ } else {
+ code = deflateInit(&zlib_stream, Z_DEFAULT_COMPRESSION);
+ }
+ DCHECK_EQ(Z_OK, code);
+
+ // If compressing with gzip framing, prepend a gzip header. See RFC 1952 2.2
+ // and 2.3 for more information.
+ if (gzip_framing) {
+ const unsigned char gzip_header[] = {
+ 0x1f,
+ 0x8b, // magic number
+ 0x08, // CM 0x08 == "deflate"
+ 0x00, // FLG 0x00 == nothing
+ 0x00, 0x00, 0x00,
+ 0x00, // MTIME 0x00000000 == no mtime
+ 0x00, // XFL 0x00 == nothing
+ 0xff, // OS 0xff == unknown
+ };
+ DCHECK_GE(dest_left, sizeof(gzip_header));
+ memcpy(dest, gzip_header, sizeof(gzip_header));
+ dest += sizeof(gzip_header);
+ dest_left -= sizeof(gzip_header);
+ }
+
+ zlib_stream.next_in = bit_cast<Bytef*>(source);
+ zlib_stream.avail_in = source_len;
+ zlib_stream.next_out = bit_cast<Bytef*>(dest);
+ zlib_stream.avail_out = dest_left;
+
+ code = deflate(&zlib_stream, Z_FINISH);
+ DCHECK_EQ(Z_STREAM_END, code);
+ dest_left = zlib_stream.avail_out;
+
+ deflateEnd(&zlib_stream);
+ *dest_len -= dest_left;
+ }
+
+ // If MockSourceStream::Mode is ASYNC, completes 1 read from |mock_stream| and
+ // wait for |callback| to complete. If Mode is not ASYNC, does nothing and
+ // returns |previous_result|.
+ int CompleteReadIfAsync(int previous_result,
+ TestCompletionCallback* callback,
+ MockSourceStream* mock_stream) {
+ if (GetParam() == MockSourceStream::ASYNC) {
+ EXPECT_EQ(ERR_IO_PENDING, previous_result);
+ mock_stream->CompleteNextRead();
+ return callback->WaitForResult();
+ }
+ return previous_result;
+ }
+
+ void set_output_buffer_size(int output_buffer_size) {
+ output_buffer_size_ = output_buffer_size;
+ }
+
+ char* source_data() { return source_data_; }
+ size_t source_data_len() { return source_data_len_; }
+
+ char* deflated_data() { return deflated_data_; }
+ size_t deflated_data_len() { return deflated_data_len_; }
+
+ char* gzipped_data() { return gzipped_data_; }
+ size_t gzipped_data_len() { return gzipped_data_len_; }
+
+ IOBuffer* output_buffer() { return output_buffer_.get(); }
+ char* output_data() { return output_buffer_->data(); }
+ size_t output_buffer_size() { return output_buffer_size_; }
+
+ MockSourceStream* deflate_source() { return deflate_source_; }
+ GzipSourceStream* deflate_stream() { return deflate_stream_.get(); }
+ MockSourceStream* gzip_source() { return gzip_source_; }
+ GzipSourceStream* gzip_stream() { return gzip_stream_.get(); }
+
+ void AddTrailingDeflatedData(const char* data, size_t data_len) {
+ DCHECK_LE(data_len, kBufferSize - deflated_data_len_);
+ memcpy(deflated_data_ + deflated_data_len_, data, data_len);
+ deflated_data_len_ += data_len;
+ }
+
+ int ReadStream(GzipSourceStream* stream, const CompletionCallback& callback) {
+ return stream->Read(output_buffer(), output_buffer_size(), callback);
+ }
+
+ int ReadDeflateStream(const CompletionCallback& callback) {
+ return ReadStream(deflate_stream_.get(), callback);
+ }
+
+ int ReadGzipStream(const CompletionCallback& callback) {
+ return ReadStream(gzip_stream_.get(), callback);
+ }
+
+ private:
+ char source_data_[kBufferSize];
+ size_t source_data_len_;
+
+ char deflated_data_[kBufferSize];
+ size_t deflated_data_len_;
+
+ char gzipped_data_[kBufferSize];
+ size_t gzipped_data_len_;
+
+ scoped_refptr<IOBuffer> output_buffer_;
+ int output_buffer_size_;
+
+ MockSourceStream* deflate_source_;
+ std::unique_ptr<GzipSourceStream> deflate_stream_;
+ MockSourceStream* gzip_source_;
+ std::unique_ptr<GzipSourceStream> gzip_stream_;
+};
+
+INSTANTIATE_TEST_CASE_P(GzipSourceStreamTests,
+ GzipSourceStreamTest,
+ ::testing::Values(MockSourceStream::SYNC,
+ MockSourceStream::ASYNC));
+
+TEST_P(GzipSourceStreamTest, EmptyStream) {
+ Init(/*allow_gzip_fallback=*/false);
+ deflate_source()->AddReadResult("", 0, OK, GetParam());
+ TestCompletionCallback callback;
+ int result = ReadDeflateStream(callback.callback());
+ result = CompleteReadIfAsync(result, &callback, deflate_source());
+ EXPECT_EQ(OK, result);
+ EXPECT_EQ("DEFLATE", deflate_stream()->Description());
+}
+
+TEST_P(GzipSourceStreamTest, DeflateOneBlock) {
+ Init(/*allow_gzip_fallback=*/false);
+ deflate_source()->AddReadResult(deflated_data(), deflated_data_len(), OK,
+ GetParam());
+ TestCompletionCallback callback;
+ int rv = ReadDeflateStream(callback.callback());
+ rv = CompleteReadIfAsync(rv, &callback, deflate_source());
+ EXPECT_EQ(static_cast<int>(source_data_len()), rv);
+ EXPECT_EQ(0, memcmp(output_data(), source_data(), source_data_len()));
+ EXPECT_EQ("DEFLATE", deflate_stream()->Description());
+}
+
+TEST_P(GzipSourceStreamTest, GzipOneBloc) {
+ Init(/*allow_gzip_fallback=*/false);
+ gzip_source()->AddReadResult(gzipped_data(), gzipped_data_len(), OK,
+ GetParam());
+ TestCompletionCallback callback;
+ int rv = ReadGzipStream(callback.callback());
+ rv = CompleteReadIfAsync(rv, &callback, gzip_source());
+ EXPECT_EQ(static_cast<int>(source_data_len()), rv);
+ EXPECT_EQ(0, memcmp(output_data(), source_data(), source_data_len()));
+ EXPECT_EQ("GZIP", gzip_stream()->Description());
+}
+
+TEST_P(GzipSourceStreamTest, DeflateTwoBlocks) {
+ Init(/*allow_gzip_fallback=*/false);
+ deflate_source()->AddReadResult(deflated_data(), 10, OK, GetParam());
+ deflate_source()->AddReadResult(deflated_data() + 10,
+ deflated_data_len() - 10, OK, GetParam());
+ deflate_source()->AddReadResult(deflated_data() + deflated_data_len(), 0, OK,
+ GetParam());
+ std::string actual_output;
+ while (true) {
+ TestCompletionCallback callback;
+ int rv = ReadDeflateStream(callback.callback());
+ if (rv == ERR_IO_PENDING)
+ rv = CompleteReadIfAsync(rv, &callback, deflate_source());
+ if (rv == OK)
+ break;
+ ASSERT_GT(rv, OK);
+ actual_output.append(output_data(), rv);
+ }
+ EXPECT_EQ(source_data_len(), actual_output.size());
+ EXPECT_EQ(std::string(source_data(), source_data_len()), actual_output);
+ EXPECT_EQ("DEFLATE", deflate_stream()->Description());
+}
+
+TEST_P(GzipSourceStreamTest, PassThroughAfterEOF) {
+ Init(/*allow_gzip_fallback=*/false);
+ char test_data[] = "Hello, World!";
+ AddTrailingDeflatedData(test_data, sizeof(test_data));
+ deflate_source()->AddReadResult(deflated_data(), deflated_data_len(), OK,
+ GetParam());
+ // Compressed and uncompressed data get returned as separate Read() results,
+ // so this test has to call Read twice.
+ TestCompletionCallback callback;
+ int rv = ReadDeflateStream(callback.callback());
+ rv = CompleteReadIfAsync(rv, &callback, deflate_source());
+ EXPECT_EQ(static_cast<int>(source_data_len() + sizeof(test_data)), rv);
+ EXPECT_EQ(0, memcmp(output_data(), source_data(), source_data_len()));
+ EXPECT_EQ(0, memcmp(output_data() + source_data_len(), test_data,
+ sizeof(test_data)));
+ EXPECT_EQ("DEFLATE", deflate_stream()->Description());
+}
+
+TEST_P(GzipSourceStreamTest, MissingZlibHeader) {
+ Init(/*allow_gzip_fallback=*/false);
+ const size_t kZlibHeaderLen = 2;
+ deflate_source()->AddReadResult(deflated_data() + kZlibHeaderLen,
+ deflated_data_len() - kZlibHeaderLen, OK,
+ GetParam());
+ TestCompletionCallback callback;
+ int rv = ReadDeflateStream(callback.callback());
+ rv = CompleteReadIfAsync(rv, &callback, deflate_source());
+ EXPECT_EQ(static_cast<int>(source_data_len()), rv);
+ EXPECT_EQ(0, memcmp(output_data(), source_data(), source_data_len()));
+ EXPECT_EQ("DEFLATE", deflate_stream()->Description());
+}
+
+TEST_P(GzipSourceStreamTest, CorruptGzipHeader) {
+ Init(/*allow_gzip_fallback=*/false);
+ gzipped_data()[0] = 0;
+ gzip_source()->AddReadResult(gzipped_data(), gzipped_data_len(), OK,
+ GetParam());
+ TestCompletionCallback callback;
+ int rv = ReadGzipStream(callback.callback());
+ rv = CompleteReadIfAsync(rv, &callback, gzip_source());
+ EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, rv);
+ EXPECT_EQ("GZIP", gzip_stream()->Description());
+}
+
+TEST_P(GzipSourceStreamTest, GzipFallback) {
+ Init(/*allow_gzip_fallback=*/true);
+ gzip_source()->AddReadResult(source_data(), source_data_len(), OK,
+ GetParam());
+ TestCompletionCallback callback;
+ int rv = ReadGzipStream(callback.callback());
+ rv = CompleteReadIfAsync(rv, &callback, gzip_source());
+ EXPECT_EQ(static_cast<int>(source_data_len()), rv);
+ EXPECT_EQ(0, memcmp(output_data(), source_data(), source_data_len()));
+ EXPECT_EQ("GZIP_FALLBACK", gzip_stream()->Description());
+}
+
+// This test checks that the gzip stream source works correctly on 'golden' data
+// as produced by gzip(1).
+TEST_P(GzipSourceStreamTest, GzipCorrectness) {
+ Init(/*allow_gzip_fallback=*/false);
+ char plain_data[] = "Hello, World!";
+ unsigned char gzip_data[] = {
+ // From:
+ // echo -n 'Hello, World!' | gzip | xxd -i | sed -e 's/^/ /'
+ // The footer is the last 8 bytes.
+ 0x1f, 0x8b, 0x08, 0x00, 0x2b, 0x02, 0x84, 0x55, 0x00, 0x03, 0xf3,
+ 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51, 0x08, 0xcf, 0x2f, 0xca, 0x49,
+ 0x51, 0x04, 0x00, 0xd0, 0xc3, 0x4a, 0xec, 0x0d, 0x00, 0x00, 0x00};
+ gzip_source()->AddReadResult(reinterpret_cast<char*>(gzip_data),
+ sizeof(gzip_data), OK, GetParam());
+ TestCompletionCallback callback;
+ int rv = ReadGzipStream(callback.callback());
+ rv = CompleteReadIfAsync(rv, &callback, gzip_source());
+ EXPECT_EQ(static_cast<int>(strlen(plain_data)), rv);
+ EXPECT_EQ(0, memcmp(output_data(), plain_data, strlen(plain_data)));
+ EXPECT_EQ("GZIP", gzip_stream()->Description());
+}
+
+TEST_P(GzipSourceStreamTest, GzipCorrectnessWithSmallOutputBuffer) {
+ set_output_buffer_size(kSmallBufferSize);
+ Init(/*allow_gzip_fallback=*/false);
+ char plain_data[] = "Hello, World!";
+ unsigned char gzip_data[] = {
+ // From:
+ // echo -n 'Hello, World!' | gzip | xxd -i | sed -e 's/^/ /'
+ // The footer is the last 8 bytes.
+ 0x1f, 0x8b, 0x08, 0x00, 0x2b, 0x02, 0x84, 0x55, 0x00, 0x03, 0xf3,
+ 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51, 0x08, 0xcf, 0x2f, 0xca, 0x49,
+ 0x51, 0x04, 0x00, 0xd0, 0xc3, 0x4a, 0xec, 0x0d, 0x00, 0x00, 0x00};
+ gzip_source()->AddReadResult(reinterpret_cast<char*>(gzip_data),
+ sizeof(gzip_data), OK, GetParam());
+ gzip_source()->AddReadResult(
+ reinterpret_cast<char*>(gzip_data) + sizeof(gzip_data), 0, OK,
+ GetParam());
+ std::string actual_output;
+ while (true) {
+ TestCompletionCallback callback;
+ int rv = ReadGzipStream(callback.callback());
+ if (rv == ERR_IO_PENDING)
+ rv = CompleteReadIfAsync(rv, &callback, gzip_source());
+ if (rv == OK)
+ break;
+ ASSERT_GT(rv, OK);
+ actual_output.append(output_data(), rv);
+ }
+ EXPECT_EQ(plain_data, actual_output);
+ EXPECT_EQ("GZIP", gzip_stream()->Description());
+}
+
+// Only test synchronous read because it's not straightforward to know how many
+// MockSourceStream reads to complete in order for GzipSourceStream to return.
+TEST_P(GzipSourceStreamTest, GzipCorrectnessWithSmallInputBuffer) {
+ Init(/*allow_gzip_fallback=*/false);
+ char plain_data[] = "Hello, World!";
+ unsigned char gzip_data[] = {
+ // From:
+ // echo -n 'Hello, World!' | gzip | xxd -i | sed -e 's/^/ /'
+ // The footer is the last 8 bytes.
+ 0x1f, 0x8b, 0x08, 0x00, 0x2b, 0x02, 0x84, 0x55, 0x00, 0x03, 0xf3,
+ 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51, 0x08, 0xcf, 0x2f, 0xca, 0x49,
+ 0x51, 0x04, 0x00, 0xd0, 0xc3, 0x4a, 0xec, 0x0d, 0x00, 0x00, 0x00};
+ size_t gzip_data_len = sizeof(gzip_data);
+ // Add a sequence of small reads.
+ for (size_t i = 0; i < gzip_data_len; i++) {
+ gzip_source()->AddReadResult(reinterpret_cast<char*>(gzip_data) + i, 1, OK,
+ MockSourceStream::SYNC);
+ }
+ gzip_source()->AddReadResult(
+ reinterpret_cast<char*>(gzip_data) + gzip_data_len, 0, OK,
+ MockSourceStream::SYNC);
+ TestCompletionCallback callback;
+ std::string actual_output;
+ while (true) {
+ int rv = ReadGzipStream(callback.callback());
+ if (rv == OK)
+ break;
+ ASSERT_GT(rv, OK);
+ actual_output.append(output_data(), rv);
+ }
+ EXPECT_EQ(strlen(plain_data), actual_output.size());
+ EXPECT_EQ(plain_data, actual_output);
+ EXPECT_EQ("GZIP", gzip_stream()->Description());
+}
+
+// Same as GzipCorrectness except that last 8 bytes are removed to test that the
+// implementation can handle missing footer.
+TEST_P(GzipSourceStreamTest, GzipCorrectnessWithoutFooter) {
+ Init(/*allow_gzip_fallback=*/false);
+ char plain_data[] = "Hello, World!";
+ unsigned char gzip_data[] = {
+ // From:
+ // echo -n 'Hello, World!' | gzip | xxd -i | sed -e 's/^/ /'
+ // with the 8 footer bytes removed.
+ 0x1f, 0x8b, 0x08, 0x00, 0x2b, 0x02, 0x84, 0x55, 0x00,
+ 0x03, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51, 0x08,
+ 0xcf, 0x2f, 0xca, 0x49, 0x51, 0x04, 0x00};
+ gzip_source()->AddReadResult(reinterpret_cast<char*>(gzip_data),
+ sizeof(gzip_data), OK, GetParam());
+ TestCompletionCallback callback;
+ int rv = ReadGzipStream(callback.callback());
+ rv = CompleteReadIfAsync(rv, &callback, gzip_source());
+ EXPECT_EQ(static_cast<int>(strlen(plain_data)), rv);
+ EXPECT_EQ(0, memcmp(output_data(), plain_data, strlen(plain_data)));
+ EXPECT_EQ("GZIP", gzip_stream()->Description());
+}
+
+} // namespace
diff --git a/chromium/net/filter/mock_filter_context.cc b/chromium/net/filter/mock_filter_context.cc
index 2165aa05136..c31140dfc1e 100644
--- a/chromium/net/filter/mock_filter_context.cc
+++ b/chromium/net/filter/mock_filter_context.cc
@@ -58,7 +58,7 @@ const URLRequestContext* MockFilterContext::GetURLRequestContext() const {
return context_.get();
}
-const BoundNetLog& MockFilterContext::GetNetLog() const {
+const NetLogWithSource& MockFilterContext::GetNetLog() const {
return net_log_;
}
diff --git a/chromium/net/filter/mock_filter_context.h b/chromium/net/filter/mock_filter_context.h
index 3237829fab4..ad36a2263e9 100644
--- a/chromium/net/filter/mock_filter_context.h
+++ b/chromium/net/filter/mock_filter_context.h
@@ -14,7 +14,7 @@
#include "base/macros.h"
#include "net/base/sdch_manager.h"
#include "net/filter/filter.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "url/gurl.h"
namespace net {
@@ -68,7 +68,7 @@ class MockFilterContext : public FilterContext {
void RecordPacketStats(StatisticSelector statistic) const override {}
- const BoundNetLog& GetNetLog() const override;
+ const NetLogWithSource& GetNetLog() const override;
private:
std::string mime_type_;
@@ -79,7 +79,7 @@ class MockFilterContext : public FilterContext {
bool ok_to_call_get_url_;
int response_code_;
std::unique_ptr<URLRequestContext> context_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
DISALLOW_COPY_AND_ASSIGN(MockFilterContext);
};
diff --git a/chromium/net/filter/mock_source_stream.cc b/chromium/net/filter/mock_source_stream.cc
new file mode 100644
index 00000000000..8b6e6f23b3b
--- /dev/null
+++ b/chromium/net/filter/mock_source_stream.cc
@@ -0,0 +1,78 @@
+// Copyright 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.
+
+#include "net/filter/mock_source_stream.h"
+
+#include "base/logging.h"
+#include "net/base/io_buffer.h"
+
+namespace net {
+
+MockSourceStream::MockSourceStream()
+ : SourceStream(SourceStream::TYPE_NONE),
+ awaiting_completion_(false),
+ dest_buffer_(nullptr),
+ dest_buffer_size_(0) {}
+
+MockSourceStream::~MockSourceStream() {
+ DCHECK(!awaiting_completion_);
+ DCHECK(results_.empty());
+}
+
+int MockSourceStream::Read(IOBuffer* dest_buffer,
+ int buffer_size,
+ const CompletionCallback& callback) {
+ DCHECK(!awaiting_completion_);
+ DCHECK(!results_.empty());
+
+ if (results_.empty())
+ return ERR_UNEXPECTED;
+
+ QueuedResult r = results_.front();
+ DCHECK_GE(buffer_size, r.len);
+ if (r.mode == ASYNC) {
+ awaiting_completion_ = true;
+ dest_buffer_ = dest_buffer;
+ dest_buffer_size_ = buffer_size;
+ callback_ = callback;
+ return ERR_IO_PENDING;
+ }
+
+ results_.pop();
+ memcpy(dest_buffer->data(), r.data, r.len);
+ return r.error == OK ? r.len : r.error;
+}
+
+std::string MockSourceStream::Description() const {
+ return "";
+}
+
+MockSourceStream::QueuedResult::QueuedResult(const char* data,
+ int len,
+ Error error,
+ Mode mode)
+ : data(data), len(len), error(error), mode(mode) {}
+
+void MockSourceStream::AddReadResult(const char* data,
+ int len,
+ Error error,
+ Mode mode) {
+ QueuedResult result(data, len, error, mode);
+ results_.push(result);
+}
+
+void MockSourceStream::CompleteNextRead() {
+ DCHECK(awaiting_completion_);
+
+ awaiting_completion_ = false;
+ QueuedResult r = results_.front();
+ DCHECK_EQ(ASYNC, r.mode);
+ results_.pop();
+ DCHECK_GE(dest_buffer_size_, r.len);
+ memcpy(dest_buffer_->data(), r.data, r.len);
+ dest_buffer_ = nullptr;
+ callback_.Run(r.error == OK ? r.len : r.error);
+}
+
+} // namespace net
diff --git a/chromium/net/filter/mock_source_stream.h b/chromium/net/filter/mock_source_stream.h
new file mode 100644
index 00000000000..9c88bef7cb8
--- /dev/null
+++ b/chromium/net/filter/mock_source_stream.h
@@ -0,0 +1,70 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_FILTER_MOCK_SOURCE_STREAM_H_
+#define NET_FILTER_MOCK_SOURCE_STREAM_H_
+
+#include <queue>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_errors.h"
+#include "net/filter/source_stream.h"
+
+namespace net {
+
+class IOBuffer;
+
+// A SourceStream implementation used in tests. This allows tests to specify
+// what data to return for each Read() call.
+class MockSourceStream : public SourceStream {
+ public:
+ enum Mode {
+ SYNC,
+ ASYNC,
+ };
+ MockSourceStream();
+ // The destructor will crash in debug build if there is any pending read.
+ ~MockSourceStream() override;
+
+ // SourceStream implementation
+ int Read(IOBuffer* dest_buffer,
+ int buffer_size,
+ const CompletionCallback& callback) override;
+ std::string Description() const override;
+
+ // Enqueues a result to be returned by |Read|. This method does not make a
+ // copy of |data|, so |data| must outlive this object. If |mode| is SYNC,
+ // |Read| will return the supplied data synchronously; otherwise, consumer
+ // needs to call |CompleteNextRead|
+ void AddReadResult(const char* data, int len, Error error, Mode mode);
+
+ // Completes a pending Read() call. Crash in debug build if there is no
+ // pending read.
+ void CompleteNextRead();
+
+ private:
+ struct QueuedResult {
+ QueuedResult(const char* data, int len, Error error, Mode mode);
+
+ const char* data;
+ const int len;
+ const Error error;
+ const Mode mode;
+ };
+
+ std::queue<QueuedResult> results_;
+ bool awaiting_completion_;
+ scoped_refptr<IOBuffer> dest_buffer_;
+ CompletionCallback callback_;
+ int dest_buffer_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockSourceStream);
+};
+
+} // namespace net
+
+#endif // NET_FILTER_MOCK_SOURCE_STREAM_H_
diff --git a/chromium/net/filter/sdch_filter.cc b/chromium/net/filter/sdch_filter.cc
index 85be8905fa7..5353777ab67 100644
--- a/chromium/net/filter/sdch_filter.cc
+++ b/chromium/net/filter/sdch_filter.cc
@@ -15,6 +15,9 @@
#include "net/base/sdch_manager.h"
#include "net/base/sdch_net_log_params.h"
#include "net/base/sdch_problem_codes.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/url_request/url_request_context.h"
#include "sdch/open-vcdiff/src/google/vcdecoder.h"
@@ -338,7 +341,7 @@ Filter::FilterStatus SdchFilter::ReadFilteredData(char* dest_buffer,
"Sdch3.ResponseCorruptionDetection.Uncached", cause, RESPONSE_MAX);
}
filter_context_.GetNetLog().AddEvent(
- NetLog::TYPE_SDCH_RESPONSE_CORRUPTION_DETECTION,
+ NetLogEventType::SDCH_RESPONSE_CORRUPTION_DETECTION,
base::Bind(&NetLogSdchResponseCorruptionDetectionCallback, cause,
filter_context_.IsCachedContent()));
@@ -561,7 +564,7 @@ int SdchFilter::OutputBufferExcess(char* const dest_buffer,
void SdchFilter::LogSdchProblem(SdchProblemCode problem) {
SdchManager::SdchErrorRecovery(problem);
filter_context_.GetNetLog().AddEvent(
- NetLog::TYPE_SDCH_DECODING_ERROR,
+ NetLogEventType::SDCH_DECODING_ERROR,
base::Bind(&NetLogSdchResourceProblemCallback, problem));
}
diff --git a/chromium/net/filter/source_stream.cc b/chromium/net/filter/source_stream.cc
new file mode 100644
index 00000000000..e2c4e6e2539
--- /dev/null
+++ b/chromium/net/filter/source_stream.cc
@@ -0,0 +1,17 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/filter/source_stream.h"
+
+namespace net {
+
+SourceStream::SourceStream(SourceType type) : type_(type) {}
+
+SourceStream::~SourceStream() {}
+
+std::string SourceStream::Description() const {
+ return "";
+}
+
+} // namespace net
diff --git a/chromium/net/filter/source_stream.h b/chromium/net/filter/source_stream.h
new file mode 100644
index 00000000000..be30c141a43
--- /dev/null
+++ b/chromium/net/filter/source_stream.h
@@ -0,0 +1,67 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_FILTER_SOURCE_STREAM_H_
+#define NET_FILTER_SOURCE_STREAM_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+class IOBuffer;
+
+// The SourceStream class implements a producer of bytes.
+class NET_EXPORT_PRIVATE SourceStream {
+ public:
+ enum SourceType {
+#define SOURCE_STREAM_TYPE(label) TYPE_##label,
+#include "net/filter/source_stream_type_list.h"
+#undef SOURCE_STREAM_TYPE
+ // Used for UMA.
+ TYPE_MAX,
+ };
+
+ // |type| is the type of the SourceStream.
+ explicit SourceStream(SourceType type);
+
+ virtual ~SourceStream();
+
+ // Initiaties a read from the stream.
+ // If it completes synchronously, it:
+ // - Returns an int representing the number of bytes read. If 0, EOF has
+ // been reached
+ // - Bytes will be written into |*dest_buffer|
+ // - Does not call |callback|
+ // If it completes asynchronously, it:
+ // - Returns ERR_IO_PENDING
+ // - Calls |callback| when it does complete, with an error code or a count
+ // of bytes read and written into |*dest_buffer|.
+ // This method takes a reference to |*dest_buffer| if it completes
+ // asynchronously to ensure it does not get freed mid-read.
+ virtual int Read(IOBuffer* dest_buffer,
+ int buffer_size,
+ const CompletionCallback& callback) = 0;
+
+ // Returns a string that represents stream. This is for UMA and NetLog
+ // logging.
+ virtual std::string Description() const = 0;
+
+ SourceType type() const { return type_; }
+
+ private:
+ SourceType type_;
+
+ DISALLOW_COPY_AND_ASSIGN(SourceStream);
+};
+
+} // namespace net
+
+#endif // NET_FILTER_SOURCE_STREAM_H_
diff --git a/chromium/net/filter/source_stream_type_list.h b/chromium/net/filter/source_stream_type_list.h
new file mode 100644
index 00000000000..39e1932e9fa
--- /dev/null
+++ b/chromium/net/filter/source_stream_type_list.h
@@ -0,0 +1,11 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+SOURCE_STREAM_TYPE(BROTLI)
+SOURCE_STREAM_TYPE(DEFLATE)
+SOURCE_STREAM_TYPE(GZIP)
+SOURCE_STREAM_TYPE(SDCH)
+SOURCE_STREAM_TYPE(GZIP_FALLBACK)
+SOURCE_STREAM_TYPE(INVALID)
+SOURCE_STREAM_TYPE(NONE)
diff --git a/chromium/net/ftp/ftp_ctrl_response_buffer.cc b/chromium/net/ftp/ftp_ctrl_response_buffer.cc
index 1195d66b54a..f2cc5f535b0 100644
--- a/chromium/net/ftp/ftp_ctrl_response_buffer.cc
+++ b/chromium/net/ftp/ftp_ctrl_response_buffer.cc
@@ -12,6 +12,7 @@
#include "base/strings/string_piece.h"
#include "base/values.h"
#include "net/base/net_errors.h"
+#include "net/log/net_log_event_type.h"
namespace net {
@@ -24,10 +25,8 @@ FtpCtrlResponse::FtpCtrlResponse(const FtpCtrlResponse& other) = default;
FtpCtrlResponse::~FtpCtrlResponse() {}
-FtpCtrlResponseBuffer::FtpCtrlResponseBuffer(const BoundNetLog& net_log)
- : multiline_(false),
- net_log_(net_log) {
-}
+FtpCtrlResponseBuffer::FtpCtrlResponseBuffer(const NetLogWithSource& net_log)
+ : multiline_(false), net_log_(net_log) {}
FtpCtrlResponseBuffer::~FtpCtrlResponseBuffer() {}
@@ -101,7 +100,7 @@ FtpCtrlResponse FtpCtrlResponseBuffer::PopResponse() {
FtpCtrlResponse result = responses_.front();
responses_.pop();
- net_log_.AddEvent(NetLog::TYPE_FTP_CONTROL_RESPONSE,
+ net_log_.AddEvent(NetLogEventType::FTP_CONTROL_RESPONSE,
base::Bind(&NetLogFtpCtrlResponseCallback, &result));
return result;
diff --git a/chromium/net/ftp/ftp_ctrl_response_buffer.h b/chromium/net/ftp/ftp_ctrl_response_buffer.h
index b53b7a91783..e8683ec88ab 100644
--- a/chromium/net/ftp/ftp_ctrl_response_buffer.h
+++ b/chromium/net/ftp/ftp_ctrl_response_buffer.h
@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "net/base/net_export.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
namespace net {
@@ -28,7 +28,7 @@ struct NET_EXPORT_PRIVATE FtpCtrlResponse {
class NET_EXPORT_PRIVATE FtpCtrlResponseBuffer {
public:
- FtpCtrlResponseBuffer(const BoundNetLog& net_log);
+ FtpCtrlResponseBuffer(const NetLogWithSource& net_log);
~FtpCtrlResponseBuffer();
// Called when data is received from the control socket. Returns error code.
@@ -92,7 +92,7 @@ class NET_EXPORT_PRIVATE FtpCtrlResponseBuffer {
// As we read full responses (possibly multiline), we add them to the queue.
std::queue<FtpCtrlResponse> responses_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
DISALLOW_COPY_AND_ASSIGN(FtpCtrlResponseBuffer);
};
diff --git a/chromium/net/ftp/ftp_ctrl_response_buffer_unittest.cc b/chromium/net/ftp/ftp_ctrl_response_buffer_unittest.cc
index 759ed87205d..a133aa441d7 100644
--- a/chromium/net/ftp/ftp_ctrl_response_buffer_unittest.cc
+++ b/chromium/net/ftp/ftp_ctrl_response_buffer_unittest.cc
@@ -7,15 +7,20 @@
#include <string.h>
#include "net/base/net_errors.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
class FtpCtrlResponseBufferTest : public testing::Test {
public:
- FtpCtrlResponseBufferTest() : buffer_(BoundNetLog()) {}
+ FtpCtrlResponseBufferTest() : buffer_(NetLogWithSource()) {}
protected:
int PushDataToBuffer(const char* data) {
@@ -28,7 +33,7 @@ class FtpCtrlResponseBufferTest : public testing::Test {
TEST_F(FtpCtrlResponseBufferTest, Basic) {
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("200 Status Text\r\n"));
+ EXPECT_THAT(PushDataToBuffer("200 Status Text\r\n"), IsOk());
EXPECT_TRUE(buffer_.ResponseAvailable());
FtpCtrlResponse response = buffer_.PopResponse();
@@ -39,15 +44,15 @@ TEST_F(FtpCtrlResponseBufferTest, Basic) {
}
TEST_F(FtpCtrlResponseBufferTest, Chunks) {
- EXPECT_EQ(OK, PushDataToBuffer("20"));
+ EXPECT_THAT(PushDataToBuffer("20"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("0 Status"));
+ EXPECT_THAT(PushDataToBuffer("0 Status"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer(" Text"));
+ EXPECT_THAT(PushDataToBuffer(" Text"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("\r"));
+ EXPECT_THAT(PushDataToBuffer("\r"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("\n"));
+ EXPECT_THAT(PushDataToBuffer("\n"), IsOk());
EXPECT_TRUE(buffer_.ResponseAvailable());
FtpCtrlResponse response = buffer_.PopResponse();
@@ -58,13 +63,13 @@ TEST_F(FtpCtrlResponseBufferTest, Chunks) {
}
TEST_F(FtpCtrlResponseBufferTest, Continuation) {
- EXPECT_EQ(OK, PushDataToBuffer("230-FirstLine\r\n"));
+ EXPECT_THAT(PushDataToBuffer("230-FirstLine\r\n"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("230-SecondLine\r\n"));
+ EXPECT_THAT(PushDataToBuffer("230-SecondLine\r\n"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("230 LastLine\r\n"));
+ EXPECT_THAT(PushDataToBuffer("230 LastLine\r\n"), IsOk());
EXPECT_TRUE(buffer_.ResponseAvailable());
FtpCtrlResponse response = buffer_.PopResponse();
@@ -77,19 +82,19 @@ TEST_F(FtpCtrlResponseBufferTest, Continuation) {
}
TEST_F(FtpCtrlResponseBufferTest, MultilineContinuation) {
- EXPECT_EQ(OK, PushDataToBuffer("230-FirstLine\r\n"));
+ EXPECT_THAT(PushDataToBuffer("230-FirstLine\r\n"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("Continued\r\n"));
+ EXPECT_THAT(PushDataToBuffer("Continued\r\n"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("230-SecondLine\r\n"));
+ EXPECT_THAT(PushDataToBuffer("230-SecondLine\r\n"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("215 Continued\r\n"));
+ EXPECT_THAT(PushDataToBuffer("215 Continued\r\n"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("230 LastLine\r\n"));
+ EXPECT_THAT(PushDataToBuffer("230 LastLine\r\n"), IsOk());
EXPECT_TRUE(buffer_.ResponseAvailable());
FtpCtrlResponse response = buffer_.PopResponse();
@@ -103,13 +108,13 @@ TEST_F(FtpCtrlResponseBufferTest, MultilineContinuation) {
TEST_F(FtpCtrlResponseBufferTest, MultilineContinuationZeroLength) {
// For the corner case from bug 29322.
- EXPECT_EQ(OK, PushDataToBuffer("230-\r\n"));
+ EXPECT_THAT(PushDataToBuffer("230-\r\n"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("example.com\r\n"));
+ EXPECT_THAT(PushDataToBuffer("example.com\r\n"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("230 LastLine\r\n"));
+ EXPECT_THAT(PushDataToBuffer("230 LastLine\r\n"), IsOk());
EXPECT_TRUE(buffer_.ResponseAvailable());
FtpCtrlResponse response = buffer_.PopResponse();
@@ -121,15 +126,15 @@ TEST_F(FtpCtrlResponseBufferTest, MultilineContinuationZeroLength) {
}
TEST_F(FtpCtrlResponseBufferTest, SimilarContinuation) {
- EXPECT_EQ(OK, PushDataToBuffer("230-FirstLine\r\n"));
+ EXPECT_THAT(PushDataToBuffer("230-FirstLine\r\n"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
// Notice the space at the start of the line. It should be recognized
// as a continuation, and not the last line.
- EXPECT_EQ(OK, PushDataToBuffer(" 230 Continued\r\n"));
+ EXPECT_THAT(PushDataToBuffer(" 230 Continued\r\n"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("230 TrueLastLine\r\n"));
+ EXPECT_THAT(PushDataToBuffer("230 TrueLastLine\r\n"), IsOk());
EXPECT_TRUE(buffer_.ResponseAvailable());
FtpCtrlResponse response = buffer_.PopResponse();
@@ -142,16 +147,16 @@ TEST_F(FtpCtrlResponseBufferTest, SimilarContinuation) {
// The nesting of multi-line responses is not allowed.
TEST_F(FtpCtrlResponseBufferTest, NoNesting) {
- EXPECT_EQ(OK, PushDataToBuffer("230-FirstLine\r\n"));
+ EXPECT_THAT(PushDataToBuffer("230-FirstLine\r\n"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("300-Continuation\r\n"));
+ EXPECT_THAT(PushDataToBuffer("300-Continuation\r\n"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("300 Still continuation\r\n"));
+ EXPECT_THAT(PushDataToBuffer("300 Still continuation\r\n"), IsOk());
EXPECT_FALSE(buffer_.ResponseAvailable());
- EXPECT_EQ(OK, PushDataToBuffer("230 Real End\r\n"));
+ EXPECT_THAT(PushDataToBuffer("230 Real End\r\n"), IsOk());
ASSERT_TRUE(buffer_.ResponseAvailable());
FtpCtrlResponse response = buffer_.PopResponse();
@@ -164,12 +169,13 @@ TEST_F(FtpCtrlResponseBufferTest, NoNesting) {
}
TEST_F(FtpCtrlResponseBufferTest, NonNumericResponse) {
- EXPECT_EQ(ERR_INVALID_RESPONSE, PushDataToBuffer("Non-numeric\r\n"));
+ EXPECT_THAT(PushDataToBuffer("Non-numeric\r\n"),
+ IsError(ERR_INVALID_RESPONSE));
EXPECT_FALSE(buffer_.ResponseAvailable());
}
TEST_F(FtpCtrlResponseBufferTest, OutOfRangeResponse) {
- EXPECT_EQ(ERR_INVALID_RESPONSE, PushDataToBuffer("777 OK?\r\n"));
+ EXPECT_THAT(PushDataToBuffer("777 OK?\r\n"), IsError(ERR_INVALID_RESPONSE));
EXPECT_FALSE(buffer_.ResponseAvailable());
}
diff --git a/chromium/net/ftp/ftp_ctrl_response_fuzzer.cc b/chromium/net/ftp/ftp_ctrl_response_fuzzer.cc
index 227cfa28497..f3a9ee3c6df 100644
--- a/chromium/net/ftp/ftp_ctrl_response_fuzzer.cc
+++ b/chromium/net/ftp/ftp_ctrl_response_fuzzer.cc
@@ -6,11 +6,10 @@
#include <stdint.h>
#include "net/ftp/ftp_ctrl_response_buffer.h"
-#include "net/log/net_log.h"
// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- const net::BoundNetLog log;
+ const net::NetLogWithSource log;
net::FtpCtrlResponseBuffer buffer(log);
if (!buffer.ConsumeData(reinterpret_cast<const char*>(data), size)) {
return 0;
diff --git a/chromium/net/ftp/ftp_directory_listing_parser.cc b/chromium/net/ftp/ftp_directory_listing_parser.cc
index a1aabf3f971..151c1b9df56 100644
--- a/chromium/net/ftp/ftp_directory_listing_parser.cc
+++ b/chromium/net/ftp/ftp_directory_listing_parser.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/i18n/icu_encoding_detection.h"
+#include "base/i18n/encoding_detection.h"
#include "base/i18n/icu_string_conversions.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
@@ -45,8 +45,8 @@ int ParseListing(const base::string16& text,
const base::Time& current_time,
std::vector<FtpDirectoryListingEntry>* entries,
FtpServerType* server_type) {
- std::vector<base::string16> lines;
- base::SplitStringUsingSubstr(text, newline_separator, &lines);
+ std::vector<base::string16> lines = base::SplitStringUsingSubstr(
+ text, newline_separator, base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
struct {
base::Callback<bool(void)> callback;
@@ -84,29 +84,23 @@ int DecodeAndParse(const std::string& text,
const base::Time& current_time,
std::vector<FtpDirectoryListingEntry>* entries,
FtpServerType* server_type) {
- const char* const kNewlineSeparators[] = { "\n", "\r\n" };
-
- std::vector<std::string> encodings;
- if (!base::DetectAllEncodings(text, &encodings))
+ std::string encoding;
+ if (!base::DetectEncoding(text, &encoding))
return ERR_ENCODING_DETECTION_FAILED;
-
- // Use first encoding that can be used to decode the text.
- for (size_t i = 0; i < encodings.size(); i++) {
- base::string16 converted_text;
- if (base::CodepageToUTF16(text,
- encodings[i].c_str(),
- base::OnStringConversionError::FAIL,
- &converted_text)) {
- for (size_t j = 0; j < arraysize(kNewlineSeparators); j++) {
- int rv = ParseListing(converted_text,
- base::ASCIIToUTF16(kNewlineSeparators[j]),
- encodings[i],
- current_time,
- entries,
- server_type);
- if (rv == OK)
- return rv;
- }
+ const char* encoding_name = encoding.c_str();
+
+ base::string16 converted_text;
+ if (base::CodepageToUTF16(text, encoding_name,
+ base::OnStringConversionError::FAIL,
+ &converted_text)) {
+ const char* const kNewlineSeparators[] = {"\n", "\r\n"};
+
+ for (size_t j = 0; j < arraysize(kNewlineSeparators); j++) {
+ int rv = ParseListing(converted_text,
+ base::ASCIIToUTF16(kNewlineSeparators[j]),
+ encoding_name, current_time, entries, server_type);
+ if (rv == OK)
+ return rv;
}
}
diff --git a/chromium/net/ftp/ftp_directory_listing_parser_unittest.cc b/chromium/net/ftp/ftp_directory_listing_parser_unittest.cc
index 5c98c23f630..583426d98d7 100644
--- a/chromium/net/ftp/ftp_directory_listing_parser_unittest.cc
+++ b/chromium/net/ftp/ftp_directory_listing_parser_unittest.cc
@@ -69,8 +69,8 @@ TEST_P(FtpDirectoryListingParserTest, Parse) {
test_dir.AppendASCII(std::string(param.name) + ".expected"),
&expected_listing));
- std::vector<std::string> lines;
- base::SplitStringUsingSubstr(expected_listing, "\r\n", &lines);
+ std::vector<std::string> lines = base::SplitStringUsingSubstr(
+ expected_listing, "\r\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
// Special case for empty listings.
if (lines.size() == 1 && lines[0].empty())
diff --git a/chromium/net/ftp/ftp_network_layer.cc b/chromium/net/ftp/ftp_network_layer.cc
index bc9c25a0b7f..2c11fc7b5ba 100644
--- a/chromium/net/ftp/ftp_network_layer.cc
+++ b/chromium/net/ftp/ftp_network_layer.cc
@@ -23,8 +23,8 @@ std::unique_ptr<FtpTransaction> FtpNetworkLayer::CreateTransaction() {
if (suspended_)
return std::unique_ptr<FtpTransaction>();
- return base::WrapUnique(new FtpNetworkTransaction(
- session_->host_resolver(), ClientSocketFactory::GetDefaultFactory()));
+ return base::MakeUnique<FtpNetworkTransaction>(
+ session_->host_resolver(), ClientSocketFactory::GetDefaultFactory());
}
void FtpNetworkLayer::Suspend(bool suspend) {
diff --git a/chromium/net/ftp/ftp_network_transaction.cc b/chromium/net/ftp/ftp_network_transaction.cc
index 32cd5d40455..8ecde3104de 100644
--- a/chromium/net/ftp/ftp_network_transaction.cc
+++ b/chromium/net/ftp/ftp_network_transaction.cc
@@ -21,6 +21,8 @@
#include "net/ftp/ftp_request_info.h"
#include "net/ftp/ftp_util.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/stream_socket.h"
#include "url/url_constants.h"
@@ -237,7 +239,7 @@ int FtpNetworkTransaction::Stop(int error) {
int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info,
const CompletionCallback& callback,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
net_log_ = net_log;
request_ = request_info;
@@ -462,7 +464,7 @@ int FtpNetworkTransaction::SendFtpCommand(const std::string& command,
memcpy(write_command_buf_->data(), command.data(), command.length());
memcpy(write_command_buf_->data() + command.length(), kCRLF, 2);
- net_log_.AddEvent(NetLog::TYPE_FTP_COMMAND_SENT,
+ net_log_.AddEvent(NetLogEventType::FTP_COMMAND_SENT,
NetLog::StringCallback("command", &command_for_log));
next_state_ = STATE_CTRL_WRITE;
@@ -637,12 +639,10 @@ int FtpNetworkTransaction::DoCtrlResolveHost() {
HostResolver::RequestInfo info(HostPortPair::FromURL(request_->url));
// No known referrer.
- return resolver_.Resolve(
- info,
- DEFAULT_PRIORITY,
- &addresses_,
+ return resolver_->Resolve(
+ info, DEFAULT_PRIORITY, &addresses_,
base::Bind(&FtpNetworkTransaction::OnIOComplete, base::Unretained(this)),
- net_log_);
+ &resolve_request_, net_log_);
}
int FtpNetworkTransaction::DoCtrlResolveHostComplete(int result) {
@@ -656,7 +656,7 @@ int FtpNetworkTransaction::DoCtrlConnect() {
ctrl_socket_ = socket_factory_->CreateTransportClientSocket(
addresses_, NULL, net_log_.net_log(), net_log_.source());
net_log_.AddEvent(
- NetLog::TYPE_FTP_CONTROL_CONNECTION,
+ NetLogEventType::FTP_CONTROL_CONNECTION,
ctrl_socket_->NetLog().source().ToEventParametersCallback());
return ctrl_socket_->Connect(io_callback_);
}
@@ -1233,7 +1233,7 @@ int FtpNetworkTransaction::DoDataConnect() {
data_socket_ = socket_factory_->CreateTransportClientSocket(
data_address, NULL, net_log_.net_log(), net_log_.source());
net_log_.AddEvent(
- NetLog::TYPE_FTP_DATA_CONNECTION,
+ NetLogEventType::FTP_DATA_CONNECTION,
data_socket_->NetLog().source().ToEventParametersCallback());
return data_socket_->Connect(io_callback_);
}
diff --git a/chromium/net/ftp/ftp_network_transaction.h b/chromium/net/ftp/ftp_network_transaction.h
index d5fc67d4b49..02c45c23645 100644
--- a/chromium/net/ftp/ftp_network_transaction.h
+++ b/chromium/net/ftp/ftp_network_transaction.h
@@ -16,12 +16,12 @@
#include "base/memory/ref_counted.h"
#include "net/base/address_list.h"
#include "net/base/auth.h"
+#include "net/base/net_export.h"
#include "net/dns/host_resolver.h"
-#include "net/dns/single_request_host_resolver.h"
#include "net/ftp/ftp_ctrl_response_buffer.h"
#include "net/ftp/ftp_response_info.h"
#include "net/ftp/ftp_transaction.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
namespace net {
@@ -39,7 +39,7 @@ class NET_EXPORT_PRIVATE FtpNetworkTransaction : public FtpTransaction {
// FtpTransaction methods:
int Start(const FtpRequestInfo* request_info,
const CompletionCallback& callback,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
int RestartWithAuth(const AuthCredentials& credentials,
const CompletionCallback& callback) override;
int Read(IOBuffer* buf,
@@ -202,13 +202,14 @@ class NET_EXPORT_PRIVATE FtpNetworkTransaction : public FtpTransaction {
CompletionCallback io_callback_;
CompletionCallback user_callback_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
const FtpRequestInfo* request_;
FtpResponseInfo response_;
// Cancels the outstanding request on destruction.
- SingleRequestHostResolver resolver_;
+ HostResolver* resolver_;
AddressList addresses_;
+ std::unique_ptr<HostResolver::Request> resolve_request_;
// User buffer passed to the Read method for control socket.
scoped_refptr<IOBuffer> read_ctrl_buf_;
diff --git a/chromium/net/ftp/ftp_network_transaction_unittest.cc b/chromium/net/ftp/ftp_network_transaction_unittest.cc
index 1c0cc8970d4..3c75f42fda8 100644
--- a/chromium/net/ftp/ftp_network_transaction_unittest.cc
+++ b/chromium/net/ftp/ftp_network_transaction_unittest.cc
@@ -17,9 +17,14 @@
#include "net/dns/mock_host_resolver.h"
#include "net/ftp/ftp_request_info.h"
#include "net/socket/socket_test_util.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace {
// Size we use for IOBuffers used to receive data from the test data socket.
@@ -892,7 +897,7 @@ class FtpNetworkTransactionTest
EXPECT_EQ(LOAD_STATE_IDLE, transaction_.GetLoadState());
ASSERT_EQ(ERR_IO_PENDING,
transaction_.Start(&request_info, callback_.callback(),
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_NE(LOAD_STATE_IDLE, transaction_.GetLoadState());
ASSERT_EQ(expected_result, callback_.WaitForResult());
if (expected_result == OK) {
@@ -944,8 +949,8 @@ TEST_P(FtpNetworkTransactionTest, FailedLookup) {
EXPECT_EQ(LOAD_STATE_IDLE, transaction_.GetLoadState());
ASSERT_EQ(ERR_IO_PENDING,
transaction_.Start(&request_info, callback_.callback(),
- BoundNetLog()));
- ASSERT_EQ(ERR_NAME_NOT_RESOLVED, callback_.WaitForResult());
+ NetLogWithSource()));
+ ASSERT_THAT(callback_.WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED));
EXPECT_EQ(LOAD_STATE_IDLE, transaction_.GetLoadState());
}
@@ -1175,8 +1180,8 @@ TEST_P(FtpNetworkTransactionTest, DownloadTransactionEvilPasvUnsafeHost) {
// Start the transaction.
ASSERT_EQ(ERR_IO_PENDING,
transaction_.Start(&request_info, callback_.callback(),
- BoundNetLog()));
- ASSERT_EQ(OK, callback_.WaitForResult());
+ NetLogWithSource()));
+ ASSERT_THAT(callback_.WaitForResult(), IsOk());
// The transaction fires the callback when we can start reading data. That
// means that the data socket should be open.
@@ -1360,8 +1365,8 @@ TEST_P(FtpNetworkTransactionTest, EvilRestartUser) {
ASSERT_EQ(ERR_IO_PENDING,
transaction_.Start(&request_info, callback_.callback(),
- BoundNetLog()));
- ASSERT_EQ(ERR_FTP_FAILED, callback_.WaitForResult());
+ NetLogWithSource()));
+ ASSERT_THAT(callback_.WaitForResult(), IsError(ERR_FTP_FAILED));
MockRead ctrl_reads[] = {
MockRead("220 host TestFTPd\r\n"),
@@ -1380,7 +1385,7 @@ TEST_P(FtpNetworkTransactionTest, EvilRestartUser) {
base::ASCIIToUTF16("foo\nownz0red"),
base::ASCIIToUTF16("innocent")),
callback_.callback()));
- EXPECT_EQ(ERR_MALFORMED_IDENTITY, callback_.WaitForResult());
+ EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_MALFORMED_IDENTITY));
}
TEST_P(FtpNetworkTransactionTest, EvilRestartPassword) {
@@ -1394,8 +1399,8 @@ TEST_P(FtpNetworkTransactionTest, EvilRestartPassword) {
ASSERT_EQ(ERR_IO_PENDING,
transaction_.Start(&request_info, callback_.callback(),
- BoundNetLog()));
- ASSERT_EQ(ERR_FTP_FAILED, callback_.WaitForResult());
+ NetLogWithSource()));
+ ASSERT_THAT(callback_.WaitForResult(), IsError(ERR_FTP_FAILED));
MockRead ctrl_reads[] = {
MockRead("220 host TestFTPd\r\n"),
@@ -1415,7 +1420,7 @@ TEST_P(FtpNetworkTransactionTest, EvilRestartPassword) {
AuthCredentials(base::ASCIIToUTF16("innocent"),
base::ASCIIToUTF16("foo\nownz0red")),
callback_.callback()));
- EXPECT_EQ(ERR_MALFORMED_IDENTITY, callback_.WaitForResult());
+ EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_MALFORMED_IDENTITY));
}
TEST_P(FtpNetworkTransactionTest, Escaping) {
diff --git a/chromium/net/ftp/ftp_transaction.h b/chromium/net/ftp/ftp_transaction.h
index 07401896fb6..1da3aeff205 100644
--- a/chromium/net/ftp/ftp_transaction.h
+++ b/chromium/net/ftp/ftp_transaction.h
@@ -17,7 +17,7 @@ namespace net {
class AuthCredentials;
class FtpResponseInfo;
class FtpRequestInfo;
-class BoundNetLog;
+class NetLogWithSource;
// Represents a single FTP transaction.
class NET_EXPORT_PRIVATE FtpTransaction {
@@ -42,7 +42,7 @@ 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 BoundNetLog& net_log) = 0;
+ const NetLogWithSource& net_log) = 0;
// Restarts the FTP transaction with authentication credentials.
virtual int RestartWithAuth(const AuthCredentials& credentials,
diff --git a/chromium/net/ftp/ftp_util.cc b/chromium/net/ftp/ftp_util.cc
index d7f759ce786..00b23b7c10b 100644
--- a/chromium/net/ftp/ftp_util.cc
+++ b/chromium/net/ftp/ftp_util.cc
@@ -61,7 +61,7 @@ std::string FtpUtil::UnixFilePathToVMS(const std::string& unix_path) {
for (size_t i = 2; i < tokens.size() - 1; i++)
result.append("." + tokens[i]);
}
- result.append("]" + tokens[tokens.size() - 1]);
+ result.append("]" + tokens.back());
return result;
}
@@ -71,7 +71,7 @@ std::string FtpUtil::UnixFilePathToVMS(const std::string& unix_path) {
std::string result("[");
for (size_t i = 0; i < tokens.size() - 1; i++)
result.append("." + tokens[i]);
- result.append("]" + tokens[tokens.size() - 1]);
+ result.append("]" + tokens.back());
return result;
}
@@ -373,4 +373,4 @@ base::string16 FtpUtil::GetStringPartAfterColumns(const base::string16& text,
return result;
}
-} // namespace
+} // namespace net
diff --git a/chromium/net/http/bidirectional_stream.cc b/chromium/net/http/bidirectional_stream.cc
index c514da32539..8153044933f 100644
--- a/chromium/net/http/bidirectional_stream.cc
+++ b/chromium/net/http/bidirectional_stream.cc
@@ -11,8 +11,8 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/values.h"
#include "net/base/load_flags.h"
@@ -22,7 +22,10 @@
#include "net/http/http_network_session.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_stream.h"
+#include "net/log/net_log.h"
#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source_type.h"
#include "net/spdy/spdy_header_block.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/ssl/ssl_cert_request_info.h"
@@ -70,7 +73,7 @@ BidirectionalStream::BidirectionalStream(
session,
send_request_headers_automatically,
delegate,
- base::WrapUnique(new base::Timer(false, false))) {}
+ base::MakeUnique<base::Timer>(false, false)) {}
BidirectionalStream::BidirectionalStream(
std::unique_ptr<BidirectionalStreamRequestInfo> request_info,
@@ -79,8 +82,8 @@ BidirectionalStream::BidirectionalStream(
Delegate* delegate,
std::unique_ptr<base::Timer> timer)
: request_info_(std::move(request_info)),
- net_log_(BoundNetLog::Make(session->net_log(),
- NetLog::SOURCE_BIDIRECTIONAL_STREAM)),
+ net_log_(NetLogWithSource::Make(session->net_log(),
+ NetLogSourceType::BIDIRECTIONAL_STREAM)),
session_(session),
send_request_headers_automatically_(send_request_headers_automatically),
request_headers_sent_(false),
@@ -90,9 +93,13 @@ BidirectionalStream::BidirectionalStream(
DCHECK(delegate_);
DCHECK(request_info_);
+ // Start time should be measured before connect.
+ load_timing_info_.request_start_time = base::Time::Now();
+ load_timing_info_.request_start = base::TimeTicks::Now();
+
if (net_log_.IsCapturing()) {
net_log_.BeginEvent(
- NetLog::TYPE_BIDIRECTIONAL_STREAM_ALIVE,
+ NetLogEventType::BIDIRECTIONAL_STREAM_ALIVE,
base::Bind(&NetLogCallback, &request_info_->url, &request_info_->method,
base::Unretained(&request_info_->extra_headers)));
}
@@ -100,7 +107,6 @@ BidirectionalStream::BidirectionalStream(
SSLConfig server_ssl_config;
session->ssl_config_service()->GetSSLConfig(&server_ssl_config);
session->GetAlpnProtos(&server_ssl_config.alpn_protos);
- session->GetNpnProtos(&server_ssl_config.npn_protos);
if (!request_info_->url.SchemeIs(url::kHttpsScheme)) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -126,9 +132,9 @@ BidirectionalStream::BidirectionalStream(
}
BidirectionalStream::~BidirectionalStream() {
- Cancel();
+ UpdateHistograms();
if (net_log_.IsCapturing()) {
- net_log_.EndEvent(NetLog::TYPE_BIDIRECTIONAL_STREAM_ALIVE);
+ net_log_.EndEvent(NetLogEventType::BIDIRECTIONAL_STREAM_ALIVE);
}
}
@@ -145,12 +151,17 @@ int BidirectionalStream::ReadData(IOBuffer* buf, int buf_len) {
int rv = stream_impl_->ReadData(buf, buf_len);
if (rv > 0) {
+ read_end_time_ = base::TimeTicks::Now();
net_log_.AddByteTransferEvent(
- NetLog::TYPE_BIDIRECTIONAL_STREAM_BYTES_RECEIVED, rv, buf->data());
+ NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_RECEIVED, rv, buf->data());
} else if (rv == ERR_IO_PENDING) {
read_buffer_ = buf;
// Bytes will be logged in OnDataRead().
}
+ if (net_log_.IsCapturing()) {
+ net_log_.AddEvent(NetLogEventType::BIDIRECTIONAL_STREAM_READ_DATA,
+ NetLog::IntCallback("rv", rv));
+ }
return rv;
}
@@ -161,6 +172,9 @@ void BidirectionalStream::SendData(const scoped_refptr<IOBuffer>& data,
DCHECK(write_buffer_list_.empty());
DCHECK(write_buffer_len_list_.empty());
+ if (net_log_.IsCapturing()) {
+ net_log_.AddEvent(NetLogEventType::BIDIRECTIONAL_STREAM_SEND_DATA);
+ }
stream_impl_->SendData(data, length, end_stream);
write_buffer_list_.push_back(data);
write_buffer_len_list_.push_back(length);
@@ -175,6 +189,10 @@ void BidirectionalStream::SendvData(
DCHECK(write_buffer_list_.empty());
DCHECK(write_buffer_len_list_.empty());
+ if (net_log_.IsCapturing()) {
+ net_log_.AddEvent(NetLogEventType::BIDIRECTIONAL_STREAM_SENDV_DATA,
+ NetLog::IntCallback("num_buffers", buffers.size()));
+ }
stream_impl_->SendvData(buffers, lengths, end_stream);
for (size_t i = 0; i < buffers.size(); ++i) {
write_buffer_list_.push_back(buffers[i]);
@@ -182,14 +200,6 @@ void BidirectionalStream::SendvData(
}
}
-void BidirectionalStream::Cancel() {
- stream_request_.reset();
- if (stream_impl_) {
- stream_impl_->Cancel();
- stream_impl_.reset();
- }
-}
-
NextProto BidirectionalStream::GetProtocol() const {
if (!stream_impl_)
return kProtoUnknown;
@@ -211,28 +221,46 @@ int64_t BidirectionalStream::GetTotalSentBytes() const {
return stream_impl_->GetTotalSentBytes();
}
+void BidirectionalStream::GetLoadTimingInfo(
+ LoadTimingInfo* load_timing_info) const {
+ *load_timing_info = load_timing_info_;
+}
+
void BidirectionalStream::OnStreamReady(bool request_headers_sent) {
request_headers_sent_ = request_headers_sent;
if (net_log_.IsCapturing()) {
net_log_.AddEvent(
- NetLog::TYPE_BIDIRECTIONAL_STREAM_READY,
+ NetLogEventType::BIDIRECTIONAL_STREAM_READY,
NetLog::BoolCallback("request_headers_sent", request_headers_sent));
}
+ load_timing_info_.send_start = base::TimeTicks::Now();
+ load_timing_info_.send_end = load_timing_info_.send_start;
delegate_->OnStreamReady(request_headers_sent);
}
void BidirectionalStream::OnHeadersReceived(
const SpdyHeaderBlock& response_headers) {
HttpResponseInfo response_info;
- if (!SpdyHeadersToHttpResponse(response_headers, HTTP2, &response_info)) {
+ if (!SpdyHeadersToHttpResponse(response_headers, &response_info)) {
DLOG(WARNING) << "Invalid headers";
NotifyFailed(ERR_FAILED);
return;
}
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(NetLog::TYPE_BIDIRECTIONAL_STREAM_RECV_HEADERS,
+ net_log_.AddEvent(NetLogEventType::BIDIRECTIONAL_STREAM_RECV_HEADERS,
base::Bind(&NetLogHeadersCallback, &response_headers));
}
+ // Impl should only provide |connect_timing| and |socket_reused| info,
+ // so use a copy to get these information only.
+ LoadTimingInfo impl_load_timing_info;
+ bool has_load_timing =
+ stream_impl_->GetLoadTimingInfo(&impl_load_timing_info);
+ if (has_load_timing) {
+ load_timing_info_.connect_timing = impl_load_timing_info.connect_timing;
+ load_timing_info_.socket_reused = impl_load_timing_info.socket_reused;
+ }
+ load_timing_info_.receive_headers_end = base::TimeTicks::Now();
+ read_end_time_ = load_timing_info_.receive_headers_end;
session_->http_stream_factory()->ProcessAlternativeServices(
session_, response_info.headers.get(),
url::SchemeHostPort(request_info_->url));
@@ -244,9 +272,10 @@ void BidirectionalStream::OnDataRead(int bytes_read) {
if (net_log_.IsCapturing()) {
net_log_.AddByteTransferEvent(
- NetLog::TYPE_BIDIRECTIONAL_STREAM_BYTES_RECEIVED, bytes_read,
+ NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_RECEIVED, bytes_read,
read_buffer_->data());
}
+ read_end_time_ = base::TimeTicks::Now();
read_buffer_ = nullptr;
delegate_->OnDataRead(bytes_read);
}
@@ -258,19 +287,21 @@ void BidirectionalStream::OnDataSent() {
if (net_log_.IsCapturing()) {
if (write_buffer_list_.size() > 1) {
net_log_.BeginEvent(
- NetLog::TYPE_BIDIRECTIONAL_STREAM_BYTES_SENT_COALESCED,
+ NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT_COALESCED,
NetLog::IntCallback("num_buffers_coalesced",
write_buffer_list_.size()));
}
for (size_t i = 0; i < write_buffer_list_.size(); ++i) {
net_log_.AddByteTransferEvent(
- NetLog::TYPE_BIDIRECTIONAL_STREAM_BYTES_SENT,
+ NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT,
write_buffer_len_list_[i], write_buffer_list_[i]->data());
}
if (write_buffer_list_.size() > 1) {
- net_log_.EndEvent(NetLog::TYPE_BIDIRECTIONAL_STREAM_BYTES_SENT_COALESCED);
+ net_log_.EndEvent(
+ NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT_COALESCED);
}
}
+ load_timing_info_.send_end = base::TimeTicks::Now();
write_buffer_list_.clear();
write_buffer_len_list_.clear();
delegate_->OnDataSent();
@@ -278,15 +309,16 @@ void BidirectionalStream::OnDataSent() {
void BidirectionalStream::OnTrailersReceived(const SpdyHeaderBlock& trailers) {
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(NetLog::TYPE_BIDIRECTIONAL_STREAM_RECV_TRAILERS,
+ net_log_.AddEvent(NetLogEventType::BIDIRECTIONAL_STREAM_RECV_TRAILERS,
base::Bind(&NetLogHeadersCallback, &trailers));
}
+ read_end_time_ = base::TimeTicks::Now();
delegate_->OnTrailersReceived(trailers);
}
void BidirectionalStream::OnFailed(int status) {
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(NetLog::TYPE_BIDIRECTIONAL_STREAM_FAILED,
+ net_log_.AddEvent(NetLogEventType::BIDIRECTIONAL_STREAM_FAILED,
NetLog::IntCallback("net_error", status));
}
NotifyFailed(status);
@@ -370,4 +402,48 @@ void BidirectionalStream::NotifyFailed(int error) {
delegate_->OnFailed(error);
}
+void BidirectionalStream::UpdateHistograms() {
+ // If the request failed before response is started, treat the metrics as
+ // bogus and skip logging.
+ if (load_timing_info_.request_start.is_null() ||
+ load_timing_info_.receive_headers_end.is_null() ||
+ read_end_time_.is_null() || load_timing_info_.send_start.is_null() ||
+ load_timing_info_.send_end.is_null()) {
+ return;
+ }
+ if (GetProtocol() == kProtoHTTP2) {
+ UMA_HISTOGRAM_TIMES("Net.BidirectionalStream.TimeToReadStart.HTTP2",
+ load_timing_info_.receive_headers_end -
+ load_timing_info_.request_start);
+ UMA_HISTOGRAM_TIMES("Net.BidirectionalStream.TimeToReadEnd.HTTP2",
+ read_end_time_ - load_timing_info_.request_start);
+ UMA_HISTOGRAM_TIMES(
+ "Net.BidirectionalStream.TimeToSendStart.HTTP2",
+ load_timing_info_.send_start - load_timing_info_.request_start);
+ UMA_HISTOGRAM_TIMES(
+ "Net.BidirectionalStream.TimeToSendEnd.HTTP2",
+ load_timing_info_.send_end - load_timing_info_.request_start);
+ UMA_HISTOGRAM_COUNTS("Net.BidirectionalStream.ReceivedBytes.HTTP2",
+ stream_impl_->GetTotalReceivedBytes());
+ UMA_HISTOGRAM_COUNTS("Net.BidirectionalStream.SentBytes.HTTP2",
+ stream_impl_->GetTotalSentBytes());
+ } else if (GetProtocol() == kProtoQUIC1SPDY3) {
+ UMA_HISTOGRAM_TIMES("Net.BidirectionalStream.TimeToReadStart.QUIC",
+ load_timing_info_.receive_headers_end -
+ load_timing_info_.request_start);
+ UMA_HISTOGRAM_TIMES("Net.BidirectionalStream.TimeToReadEnd.QUIC",
+ read_end_time_ - load_timing_info_.request_start);
+ UMA_HISTOGRAM_TIMES(
+ "Net.BidirectionalStream.TimeToSendStart.QUIC",
+ load_timing_info_.send_start - load_timing_info_.request_start);
+ UMA_HISTOGRAM_TIMES(
+ "Net.BidirectionalStream.TimeToSendEnd.QUIC",
+ load_timing_info_.send_end - load_timing_info_.request_start);
+ UMA_HISTOGRAM_COUNTS("Net.BidirectionalStream.ReceivedBytes.QUIC",
+ stream_impl_->GetTotalReceivedBytes());
+ UMA_HISTOGRAM_COUNTS("Net.BidirectionalStream.SentBytes.QUIC",
+ stream_impl_->GetTotalSentBytes());
+ }
+}
+
} // namespace net
diff --git a/chromium/net/http/bidirectional_stream.h b/chromium/net/http/bidirectional_stream.h
index 635cf5b7951..e7fdd6e4ae9 100644
--- a/chromium/net/http/bidirectional_stream.h
+++ b/chromium/net/http/bidirectional_stream.h
@@ -13,9 +13,12 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "net/base/load_timing_info.h"
+#include "net/base/net_export.h"
#include "net/http/bidirectional_stream_impl.h"
#include "net/http/http_stream_factory.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
class GURL;
@@ -154,11 +157,6 @@ class NET_EXPORT BidirectionalStream
const std::vector<int>& lengths,
bool end_stream);
- // If |stream_request_| is non-NULL, cancel it. If |stream_impl_| is
- // established, cancel it. No delegate method will be called after Cancel().
- // Any pending operations may or may not succeed.
- void Cancel();
-
// Returns the protocol used by this stream. If stream has not been
// established, return kProtoUnknown.
NextProto GetProtocol() const;
@@ -175,8 +173,8 @@ class NET_EXPORT BidirectionalStream
// not associated with any stream, and are not included in this value.
int64_t GetTotalSentBytes() const;
- // TODO(xunjieli): Implement a method to do flow control and a method to ping
- // remote end point.
+ // Gets LoadTimingInfo of this stream.
+ void GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const;
private:
// BidirectionalStreamImpl::Delegate implementation:
@@ -218,9 +216,11 @@ class NET_EXPORT BidirectionalStream
// Helper method to notify delegate if there is an error.
void NotifyFailed(int error);
+ void UpdateHistograms();
+
// BidirectionalStreamRequestInfo used when requesting the stream.
std::unique_ptr<BidirectionalStreamRequestInfo> request_info_;
- const BoundNetLog net_log_;
+ const NetLogWithSource net_log_;
HttpNetworkSession* session_;
@@ -248,6 +248,13 @@ class NET_EXPORT BidirectionalStream
// List of buffer length.
std::vector<int> write_buffer_len_list_;
+ // TODO(xunjieli): Remove this once LoadTimingInfo has response end.
+ base::TimeTicks read_end_time_;
+
+ // Load timing info of this stream. |connect_timing| is obtained when headers
+ // are received. Other fields are populated at different stages of the request
+ LoadTimingInfo load_timing_info_;
+
base::WeakPtrFactory<BidirectionalStream> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(BidirectionalStream);
diff --git a/chromium/net/http/bidirectional_stream_impl.h b/chromium/net/http/bidirectional_stream_impl.h
index 4f53918ef1d..54f9d044e31 100644
--- a/chromium/net/http/bidirectional_stream_impl.h
+++ b/chromium/net/http/bidirectional_stream_impl.h
@@ -8,9 +8,11 @@
#include <stdint.h>
#include <memory>
+#include <vector>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "net/base/load_timing_info.h"
#include "net/base/net_export.h"
#include "net/socket/next_proto.h"
@@ -20,8 +22,8 @@ class Timer;
namespace net {
-class BoundNetLog;
class IOBuffer;
+class NetLogWithSource;
class SpdyHeaderBlock;
struct BidirectionalStreamRequestInfo;
@@ -97,7 +99,7 @@ class NET_EXPORT_PRIVATE BidirectionalStreamImpl {
// sent only when SendRequestHeaders() is invoked or with next
// SendData/SendvData.
virtual void Start(const BidirectionalStreamRequestInfo* request_info,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
bool send_request_headers_automatically,
BidirectionalStreamImpl::Delegate* delegate,
std::unique_ptr<base::Timer> timer) = 0;
@@ -134,10 +136,6 @@ class NET_EXPORT_PRIVATE BidirectionalStreamImpl {
const std::vector<int>& lengths,
bool end_stream) = 0;
- // Cancels the stream. No Delegate method will be called. Any pending
- // operations may or may not succeed.
- virtual void Cancel() = 0;
-
// Returns the protocol used by this stream. If stream has not been
// established, return kProtoUnknown.
virtual NextProto GetProtocol() const = 0;
@@ -153,6 +151,11 @@ class NET_EXPORT_PRIVATE BidirectionalStreamImpl {
// not associated with any stream, and are not included in this value.
virtual int64_t GetTotalSentBytes() const = 0;
+ // Populates the connection establishment part of |load_timing_info|, and
+ // socket reuse info. Return true if LoadTimingInfo is obtained successfully
+ // and false otherwise.
+ virtual bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const = 0;
+
private:
DISALLOW_COPY_AND_ASSIGN(BidirectionalStreamImpl);
};
diff --git a/chromium/net/http/bidirectional_stream_unittest.cc b/chromium/net/http/bidirectional_stream_unittest.cc
index bd12c8de6c3..01881e34434 100644
--- a/chromium/net/http/bidirectional_stream_unittest.cc
+++ b/chromium/net/http/bidirectional_stream_unittest.cc
@@ -14,22 +14,31 @@
#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "base/timer/mock_timer.h"
+#include "net/base/load_timing_info.h"
+#include "net/base/load_timing_info_test_util.h"
#include "net/base/net_errors.h"
#include "net/http/bidirectional_stream_request_info.h"
#include "net/http/http_network_session.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_server_properties.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source_type.h"
#include "net/log/test_net_log.h"
#include "net/log/test_net_log_util.h"
#include "net/socket/socket_test_util.h"
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_test_util_common.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -39,13 +48,45 @@ const size_t kBodyDataSize = arraysize(kBodyData);
// Size of the buffer to be allocated for each read.
const size_t kReadBufferSize = 4096;
+// Expects that fields of |load_timing_info| are valid time stamps.
+void ExpectLoadTimingValid(const LoadTimingInfo& load_timing_info) {
+ EXPECT_FALSE(load_timing_info.request_start.is_null());
+ EXPECT_FALSE(load_timing_info.request_start_time.is_null());
+ EXPECT_FALSE(load_timing_info.receive_headers_end.is_null());
+ EXPECT_FALSE(load_timing_info.send_start.is_null());
+ EXPECT_FALSE(load_timing_info.send_end.is_null());
+ EXPECT_TRUE(load_timing_info.request_start <
+ load_timing_info.receive_headers_end);
+ EXPECT_TRUE(load_timing_info.send_start <= load_timing_info.send_end);
+}
+
+// Tests the load timing of a stream that's connected and is not the first
+// request sent on a connection.
+void TestLoadTimingReused(const LoadTimingInfo& load_timing_info) {
+ EXPECT_TRUE(load_timing_info.socket_reused);
+
+ ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
+ ExpectLoadTimingValid(load_timing_info);
+}
+
+// Tests the load timing of a stream that's connected and using a fresh
+// connection.
+void TestLoadTimingNotReused(const LoadTimingInfo& load_timing_info) {
+ EXPECT_FALSE(load_timing_info.socket_reused);
+
+ ExpectConnectTimingHasTimes(
+ load_timing_info.connect_timing,
+ CONNECT_TIMING_HAS_SSL_TIMES | CONNECT_TIMING_HAS_DNS_TIMES);
+ ExpectLoadTimingValid(load_timing_info);
+}
+
// Delegate that reads data but does not send any data.
class TestDelegateBase : public BidirectionalStream::Delegate {
public:
TestDelegateBase(IOBuffer* read_buf, int read_buf_len)
: TestDelegateBase(read_buf,
read_buf_len,
- base::WrapUnique(new base::Timer(false, false))) {}
+ base::MakeUnique<base::Timer>(false, false)) {}
TestDelegateBase(IOBuffer* read_buf,
int read_buf_len,
@@ -54,6 +95,8 @@ class TestDelegateBase : public BidirectionalStream::Delegate {
read_buf_len_(read_buf_len),
timer_(std::move(timer)),
loop_(nullptr),
+ received_bytes_(0),
+ sent_bytes_(0),
error_(OK),
on_data_read_count_(0),
on_data_sent_count_(0),
@@ -77,6 +120,7 @@ class TestDelegateBase : public BidirectionalStream::Delegate {
CHECK(!not_expect_callback_);
response_headers_ = response_headers.Clone();
+
if (!do_not_start_read_)
StartOrContinueReading();
}
@@ -130,9 +174,11 @@ class TestDelegateBase : public BidirectionalStream::Delegate {
stream_.reset(new BidirectionalStream(std::move(request_info), session,
true, this, std::move(timer_)));
if (run_until_completion_)
- loop_->Run();
+ WaitUntilCompletion();
}
+ void WaitUntilCompletion() { loop_->Run(); }
+
void SendData(const scoped_refptr<IOBuffer>& data,
int length,
bool end_of_stream) {
@@ -170,19 +216,40 @@ class TestDelegateBase : public BidirectionalStream::Delegate {
return rv;
}
- // Cancels |stream_|.
- void CancelStream() { stream_->Cancel(); }
-
// Deletes |stream_|.
- void DeleteStream() { stream_.reset(); }
+ void DeleteStream() {
+ next_proto_ = stream_->GetProtocol();
+ received_bytes_ = stream_->GetTotalReceivedBytes();
+ sent_bytes_ = stream_->GetTotalSentBytes();
+ stream_->GetLoadTimingInfo(&load_timing_info_);
+ stream_.reset();
+ }
- NextProto GetProtocol() const { return stream_->GetProtocol(); }
+ NextProto GetProtocol() const {
+ if (stream_)
+ return stream_->GetProtocol();
+ return next_proto_;
+ }
int64_t GetTotalReceivedBytes() const {
- return stream_->GetTotalReceivedBytes();
+ if (stream_)
+ return stream_->GetTotalReceivedBytes();
+ return received_bytes_;
+ }
+
+ int64_t GetTotalSentBytes() const {
+ if (stream_)
+ return stream_->GetTotalSentBytes();
+ return sent_bytes_;
}
- int64_t GetTotalSentBytes() const { return stream_->GetTotalSentBytes(); }
+ void GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
+ if (stream_) {
+ stream_->GetLoadTimingInfo(load_timing_info);
+ return;
+ }
+ *load_timing_info = load_timing_info_;
+ }
// Const getters for internal states.
const std::string& data_received() const { return data_received_; }
@@ -215,6 +282,10 @@ class TestDelegateBase : public BidirectionalStream::Delegate {
std::unique_ptr<base::RunLoop> loop_;
SpdyHeaderBlock response_headers_;
SpdyHeaderBlock trailers_;
+ NextProto next_proto_;
+ int64_t received_bytes_;
+ int64_t sent_bytes_;
+ LoadTimingInfo load_timing_info_;
int error_;
int on_data_read_count_;
int on_data_sent_count_;
@@ -229,7 +300,7 @@ class TestDelegateBase : public BidirectionalStream::Delegate {
};
// A delegate that deletes the stream in a particular callback.
-class CancelOrDeleteStreamDelegate : public TestDelegateBase {
+class DeleteStreamDelegate : public TestDelegateBase {
public:
// Specifies in which callback the stream can be deleted.
enum Phase {
@@ -239,17 +310,14 @@ class CancelOrDeleteStreamDelegate : public TestDelegateBase {
ON_FAILED,
};
- CancelOrDeleteStreamDelegate(IOBuffer* buf,
- int buf_len,
- Phase phase,
- bool do_cancel)
- : TestDelegateBase(buf, buf_len), phase_(phase), do_cancel_(do_cancel) {}
- ~CancelOrDeleteStreamDelegate() override {}
+ DeleteStreamDelegate(IOBuffer* buf, int buf_len, Phase phase)
+ : TestDelegateBase(buf, buf_len), phase_(phase) {}
+ ~DeleteStreamDelegate() override {}
void OnHeadersReceived(const SpdyHeaderBlock& response_headers) override {
TestDelegateBase::OnHeadersReceived(response_headers);
if (phase_ == ON_HEADERS_RECEIVED) {
- CancelOrDelete();
+ DeleteStream();
QuitLoop();
}
}
@@ -263,7 +331,7 @@ class CancelOrDeleteStreamDelegate : public TestDelegateBase {
}
TestDelegateBase::OnDataRead(bytes_read);
if (phase_ == ON_DATA_READ) {
- CancelOrDelete();
+ DeleteStream();
QuitLoop();
}
}
@@ -275,7 +343,7 @@ class CancelOrDeleteStreamDelegate : public TestDelegateBase {
}
TestDelegateBase::OnTrailersReceived(trailers);
if (phase_ == ON_TRAILERS_RECEIVED) {
- CancelOrDelete();
+ DeleteStream();
QuitLoop();
}
}
@@ -286,26 +354,16 @@ class CancelOrDeleteStreamDelegate : public TestDelegateBase {
return;
}
TestDelegateBase::OnFailed(error);
- CancelOrDelete();
+ DeleteStream();
QuitLoop();
}
private:
- void CancelOrDelete() {
- if (do_cancel_) {
- CancelStream();
- } else {
- DeleteStream();
- }
- }
-
// Indicates in which callback the delegate should cancel or delete the
// stream.
Phase phase_;
- // Indicates whether to cancel or delete the stream.
- bool do_cancel_;
- DISALLOW_COPY_AND_ASSIGN(CancelOrDeleteStreamDelegate);
+ DISALLOW_COPY_AND_ASSIGN(DeleteStreamDelegate);
};
// A Timer that does not start a delayed task unless the timer is fired.
@@ -331,13 +389,11 @@ class MockTimer : public base::MockTimer {
class BidirectionalStreamTest : public testing::TestWithParam<bool> {
public:
BidirectionalStreamTest()
- : spdy_util_(kProtoHTTP2, true),
- session_deps_(kProtoHTTP2),
- default_url_(kDefaultUrl),
+ : default_url_(kDefaultUrl),
host_port_pair_(HostPortPair::FromURL(default_url_)),
key_(host_port_pair_, ProxyServer::Direct(), PRIVACY_MODE_DISABLED),
ssl_data_(SSLSocketDataProvider(ASYNC, OK)) {
- ssl_data_.SetNextProto(kProtoHTTP2);
+ ssl_data_.next_proto = kProtoHTTP2;
ssl_data_.cert = ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
net_log_.SetCaptureMode(NetLogCaptureMode::IncludeSocketBytes());
}
@@ -393,7 +449,109 @@ TEST_F(BidirectionalStreamTest, CreateInsecureStream) {
delegate.SetRunUntilCompletion(true);
delegate.Start(std::move(request_info), session.get());
- EXPECT_EQ(ERR_DISALLOWED_URL_SCHEME, delegate.error());
+ EXPECT_THAT(delegate.error(), IsError(ERR_DISALLOWED_URL_SCHEME));
+}
+
+TEST_F(BidirectionalStreamTest, SimplePostRequest) {
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
+ kDefaultUrl, 1, kBodyDataSize, LOW, nullptr, 0));
+ SpdySerializedFrame data_frame(spdy_util_.ConstructSpdyDataFrame(
+ 1, kBodyData, kBodyDataSize, /*fin=*/true));
+ MockWrite writes[] = {
+ CreateMockWrite(req, 0), CreateMockWrite(data_frame, 3),
+ };
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
+ SpdySerializedFrame response_body_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, /*fin=*/true));
+ MockRead reads[] = {
+ CreateMockRead(resp, 1),
+ MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
+ CreateMockRead(response_body_frame, 4), MockRead(ASYNC, 0, 5),
+ };
+ InitSession(reads, arraysize(reads), writes, arraysize(writes));
+
+ std::unique_ptr<BidirectionalStreamRequestInfo> request_info(
+ new BidirectionalStreamRequestInfo);
+ request_info->method = "POST";
+ request_info->url = default_url_;
+ request_info->extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
+ base::SizeTToString(kBodyDataSize));
+ scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
+ std::unique_ptr<TestDelegateBase> delegate(
+ new TestDelegateBase(read_buffer.get(), kReadBufferSize));
+ delegate->Start(std::move(request_info), http_session_.get());
+ sequenced_data_->RunUntilPaused();
+
+ scoped_refptr<StringIOBuffer> write_buffer(
+ new StringIOBuffer(std::string(kBodyData, kBodyDataSize)));
+ delegate->SendData(write_buffer.get(), write_buffer->size(), true);
+ sequenced_data_->Resume();
+ base::RunLoop().RunUntilIdle();
+ LoadTimingInfo load_timing_info;
+ delegate->GetLoadTimingInfo(&load_timing_info);
+ TestLoadTimingNotReused(load_timing_info);
+
+ EXPECT_EQ(1, delegate->on_data_read_count());
+ EXPECT_EQ(1, delegate->on_data_sent_count());
+ EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
+ EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
+ delegate->GetTotalReceivedBytes());
+}
+
+TEST_F(BidirectionalStreamTest, LoadTimingTwoRequests) {
+ SpdySerializedFrame req(
+ spdy_util_.ConstructSpdyGet(nullptr, 0, /*stream_id=*/1, LOW, true));
+ SpdySerializedFrame req2(
+ spdy_util_.ConstructSpdyGet(nullptr, 0, /*stream_id=*/3, LOW, true));
+ MockWrite writes[] = {
+ CreateMockWrite(req, 0), CreateMockWrite(req2, 2),
+ };
+ SpdySerializedFrame resp(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, /*stream_id=*/1));
+ SpdySerializedFrame resp2(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, /*stream_id=*/3));
+ SpdySerializedFrame resp_body(
+ spdy_util_.ConstructSpdyDataFrame(/*stream_id=*/1, /*fin=*/true));
+ SpdySerializedFrame resp_body2(
+ spdy_util_.ConstructSpdyDataFrame(/*stream_id=*/3, /*fin=*/true));
+ MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(resp_body, 3),
+ CreateMockRead(resp2, 4), CreateMockRead(resp_body2, 5),
+ MockRead(ASYNC, 0, 6)};
+ InitSession(reads, arraysize(reads), writes, arraysize(writes));
+
+ std::unique_ptr<BidirectionalStreamRequestInfo> request_info(
+ new BidirectionalStreamRequestInfo);
+ request_info->method = "GET";
+ request_info->url = default_url_;
+ request_info->end_stream_on_headers = true;
+ std::unique_ptr<BidirectionalStreamRequestInfo> request_info2(
+ new BidirectionalStreamRequestInfo);
+ request_info2->method = "GET";
+ request_info2->url = default_url_;
+ request_info2->end_stream_on_headers = true;
+
+ scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
+ scoped_refptr<IOBuffer> read_buffer2(new IOBuffer(kReadBufferSize));
+ std::unique_ptr<TestDelegateBase> delegate(
+ new TestDelegateBase(read_buffer.get(), kReadBufferSize));
+ std::unique_ptr<TestDelegateBase> delegate2(
+ new TestDelegateBase(read_buffer2.get(), kReadBufferSize));
+ delegate->Start(std::move(request_info), http_session_.get());
+ delegate2->Start(std::move(request_info2), http_session_.get());
+ delegate->SetRunUntilCompletion(true);
+ delegate2->SetRunUntilCompletion(true);
+ base::RunLoop().RunUntilIdle();
+
+ delegate->WaitUntilCompletion();
+ delegate2->WaitUntilCompletion();
+ LoadTimingInfo load_timing_info;
+ delegate->GetLoadTimingInfo(&load_timing_info);
+ TestLoadTimingNotReused(load_timing_info);
+ LoadTimingInfo load_timing_info2;
+ delegate2->GetLoadTimingInfo(&load_timing_info2);
+ TestLoadTimingReused(load_timing_info2);
}
// Creates a BidirectionalStream with an insecure scheme. Destroy the stream
@@ -419,33 +577,31 @@ TEST_F(BidirectionalStreamTest,
// Simulates user calling ReadData after END_STREAM has been received in
// BidirectionalStreamSpdyImpl.
TEST_F(BidirectionalStreamTest, TestReadDataAfterClose) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
// Empty DATA frame with an END_STREAM flag.
- std::unique_ptr<SpdySerializedFrame> end_stream(
- spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
+ SpdySerializedFrame end_stream(
+ spdy_util_.ConstructSpdyDataFrame(1, nullptr, 0, true));
MockWrite writes[] = {
- CreateMockWrite(*req.get(), 0),
+ CreateMockWrite(req, 0),
};
const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
+ SpdySerializedFrame resp(
+ spdy_util_.ConstructSpdyGetReply(kExtraResponseHeaders, 1, 1));
- std::unique_ptr<SpdySerializedFrame> body_frame(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
+ SpdySerializedFrame body_frame(spdy_util_.ConstructSpdyDataFrame(1, false));
// Last body frame has END_STREAM flag set.
- std::unique_ptr<SpdySerializedFrame> last_body_frame(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame last_body_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
+ CreateMockRead(resp, 1),
MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
- CreateMockRead(*body_frame, 3),
+ CreateMockRead(body_frame, 3),
MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause.
- CreateMockRead(*body_frame, 5),
- CreateMockRead(*last_body_frame, 6),
+ CreateMockRead(body_frame, 5),
+ CreateMockRead(last_body_frame, 6),
MockRead(SYNCHRONOUS, 0, 7),
};
@@ -473,7 +629,7 @@ TEST_F(BidirectionalStreamTest, TestReadDataAfterClose) {
EXPECT_FALSE(timer->IsRunning());
// ReadData returns asynchronously because no data is buffered.
int rv = delegate->ReadData();
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Deliver a DATA frame.
sequenced_data_->Resume();
base::RunLoop().RunUntilIdle();
@@ -490,7 +646,7 @@ TEST_F(BidirectionalStreamTest, TestReadDataAfterClose) {
rv = delegate->ReadData();
EXPECT_EQ(kUploadDataSize * 2, rv);
rv = delegate->ReadData();
- EXPECT_EQ(OK, rv); // EOF.
+ EXPECT_THAT(rv, IsOk()); // EOF.
const SpdyHeaderBlock& response_headers = delegate->response_headers();
EXPECT_EQ("200", response_headers.find(":status")->second);
@@ -506,35 +662,32 @@ TEST_F(BidirectionalStreamTest, TestReadDataAfterClose) {
// Tests that the NetLog contains correct entries.
TEST_F(BidirectionalStreamTest, TestNetLogContainEntries) {
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
-
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kBodyDataSize * 3, LOWEST, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> data_frame(
- framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_FIN));
+ SpdySerializedFrame data_frame(spdy_util_.ConstructSpdyDataFrame(
+ 1, kBodyData, kBodyDataSize, /*fin=*/true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*data_frame, 3),
+ CreateMockWrite(req, 0), CreateMockWrite(data_frame, 3),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> response_body_frame1(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
- std::unique_ptr<SpdySerializedFrame> response_body_frame2(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame response_body_frame1(
+ spdy_util_.ConstructSpdyDataFrame(1, false));
+ SpdySerializedFrame response_body_frame2(
+ spdy_util_.ConstructSpdyDataFrame(1, false));
SpdyHeaderBlock trailers;
trailers["foo"] = "bar";
- std::unique_ptr<SpdySerializedFrame> response_trailers(
+ SpdySerializedFrame response_trailers(
spdy_util_.ConstructSpdyResponseHeaders(1, std::move(trailers), true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
+ CreateMockRead(resp, 1),
MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
- CreateMockRead(*response_body_frame1, 4),
+ CreateMockRead(response_body_frame1, 4),
MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause.
- CreateMockRead(*response_body_frame2, 6),
- CreateMockRead(*response_trailers, 7),
+ CreateMockRead(response_body_frame2, 6),
+ CreateMockRead(response_trailers, 7),
MockRead(ASYNC, 0, 8),
};
@@ -564,7 +717,7 @@ TEST_F(BidirectionalStreamTest, TestNetLogContainEntries) {
delegate->SendData(buf, buf->size(), true);
// ReadData returns asynchronously because no data is buffered.
int rv = delegate->ReadData();
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Deliver the first DATA frame.
sequenced_data_->Resume();
sequenced_data_->RunUntilPaused();
@@ -599,73 +752,84 @@ TEST_F(BidirectionalStreamTest, TestNetLogContainEntries) {
net_log_.GetEntries(&entries);
size_t index = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_BIDIRECTIONAL_STREAM_ALIVE, NetLog::PHASE_BEGIN);
+ entries, 0, NetLogEventType::BIDIRECTIONAL_STREAM_ALIVE,
+ NetLogEventPhase::BEGIN);
// HTTP_STREAM_REQUEST is nested inside in BIDIRECTIONAL_STREAM_ALIVE.
- index = ExpectLogContainsSomewhere(
- entries, index, NetLog::TYPE_HTTP_STREAM_REQUEST, NetLog::PHASE_BEGIN);
- index = ExpectLogContainsSomewhere(
- entries, index, NetLog::TYPE_HTTP_STREAM_REQUEST, NetLog::PHASE_END);
+ index = ExpectLogContainsSomewhere(entries, index,
+ NetLogEventType::HTTP_STREAM_REQUEST,
+ NetLogEventPhase::BEGIN);
+ index = ExpectLogContainsSomewhere(entries, index,
+ NetLogEventType::HTTP_STREAM_REQUEST,
+ NetLogEventPhase::END);
// Headers received should happen after HTTP_STREAM_REQUEST.
index = ExpectLogContainsSomewhere(
- entries, index, NetLog::TYPE_BIDIRECTIONAL_STREAM_RECV_HEADERS,
- NetLog::PHASE_NONE);
+ entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_RECV_HEADERS,
+ NetLogEventPhase::NONE);
// Trailers received should happen after headers received. It might happen
// before the reads complete.
- ExpectLogContainsSomewhere(entries, index,
- NetLog::TYPE_BIDIRECTIONAL_STREAM_RECV_TRAILERS,
- NetLog::PHASE_NONE);
- // Sent bytes. Sending data is always asynchronous.
+ ExpectLogContainsSomewhere(
+ entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_RECV_TRAILERS,
+ NetLogEventPhase::NONE);
+ index = ExpectLogContainsSomewhere(
+ entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_SEND_DATA,
+ NetLogEventPhase::NONE);
index = ExpectLogContainsSomewhere(
- entries, index, NetLog::TYPE_BIDIRECTIONAL_STREAM_BYTES_SENT,
- NetLog::PHASE_NONE);
+ entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_READ_DATA,
+ NetLogEventPhase::NONE);
TestNetLogEntry entry = entries[index];
- EXPECT_EQ(NetLog::SOURCE_BIDIRECTIONAL_STREAM, entry.source.type);
+ int read_result = 0;
+ EXPECT_TRUE(entry.params->GetInteger("rv", &read_result));
+ EXPECT_EQ(ERR_IO_PENDING, read_result);
+
+ // Sent bytes. Sending data is always asynchronous.
+ index = ExpectLogContainsSomewhere(
+ entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT,
+ NetLogEventPhase::NONE);
+ entry = entries[index];
+ EXPECT_EQ(NetLogSourceType::BIDIRECTIONAL_STREAM, entry.source.type);
// Received bytes for asynchronous read.
index = ExpectLogContainsSomewhere(
- entries, index, NetLog::TYPE_BIDIRECTIONAL_STREAM_BYTES_RECEIVED,
- NetLog::PHASE_NONE);
+ entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_RECEIVED,
+ NetLogEventPhase::NONE);
entry = entries[index];
- EXPECT_EQ(NetLog::SOURCE_BIDIRECTIONAL_STREAM, entry.source.type);
+ EXPECT_EQ(NetLogSourceType::BIDIRECTIONAL_STREAM, entry.source.type);
// Received bytes for synchronous read.
index = ExpectLogContainsSomewhere(
- entries, index, NetLog::TYPE_BIDIRECTIONAL_STREAM_BYTES_RECEIVED,
- NetLog::PHASE_NONE);
+ entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_RECEIVED,
+ NetLogEventPhase::NONE);
entry = entries[index];
- EXPECT_EQ(NetLog::SOURCE_BIDIRECTIONAL_STREAM, entry.source.type);
+ EXPECT_EQ(NetLogSourceType::BIDIRECTIONAL_STREAM, entry.source.type);
ExpectLogContainsSomewhere(entries, index,
- NetLog::TYPE_BIDIRECTIONAL_STREAM_ALIVE,
- NetLog::PHASE_END);
+ NetLogEventType::BIDIRECTIONAL_STREAM_ALIVE,
+ NetLogEventPhase::END);
}
TEST_F(BidirectionalStreamTest, TestInterleaveReadDataAndSendData) {
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
-
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kBodyDataSize * 3, LOWEST, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> data_frame1(
- framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
- std::unique_ptr<SpdySerializedFrame> data_frame2(
- framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
- std::unique_ptr<SpdySerializedFrame> data_frame3(
- framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_FIN));
+ SpdySerializedFrame data_frame1(spdy_util_.ConstructSpdyDataFrame(
+ 1, kBodyData, kBodyDataSize, /*fin=*/false));
+ SpdySerializedFrame data_frame2(spdy_util_.ConstructSpdyDataFrame(
+ 1, kBodyData, kBodyDataSize, /*fin=*/false));
+ SpdySerializedFrame data_frame3(spdy_util_.ConstructSpdyDataFrame(
+ 1, kBodyData, kBodyDataSize, /*fin=*/true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*data_frame1, 3),
- CreateMockWrite(*data_frame2, 6), CreateMockWrite(*data_frame3, 9),
+ CreateMockWrite(req, 0), CreateMockWrite(data_frame1, 3),
+ CreateMockWrite(data_frame2, 6), CreateMockWrite(data_frame3, 9),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> response_body_frame1(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
- std::unique_ptr<SpdySerializedFrame> response_body_frame2(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame response_body_frame1(
+ spdy_util_.ConstructSpdyDataFrame(1, false));
+ SpdySerializedFrame response_body_frame2(
+ spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
+ CreateMockRead(resp, 1),
MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
- CreateMockRead(*response_body_frame1, 4),
+ CreateMockRead(response_body_frame1, 4),
MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause.
- CreateMockRead(*response_body_frame2, 7),
+ CreateMockRead(response_body_frame2, 7),
MockRead(ASYNC, ERR_IO_PENDING, 8), // Force a pause.
MockRead(ASYNC, 0, 10),
};
@@ -698,7 +862,7 @@ TEST_F(BidirectionalStreamTest, TestInterleaveReadDataAndSendData) {
delegate->SendData(buf, buf->size(), false);
// ReadData and it should return asynchronously because no data is buffered.
int rv = delegate->ReadData();
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Deliver a DATA frame, and fire the timer.
sequenced_data_->Resume();
sequenced_data_->RunUntilPaused();
@@ -711,7 +875,7 @@ TEST_F(BidirectionalStreamTest, TestInterleaveReadDataAndSendData) {
delegate->SendData(buf, buf->size(), false);
// ReadData and it should return asynchronously because no data is buffered.
rv = delegate->ReadData();
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Deliver a DATA frame, and fire the timer.
sequenced_data_->Resume();
sequenced_data_->RunUntilPaused();
@@ -729,7 +893,7 @@ TEST_F(BidirectionalStreamTest, TestInterleaveReadDataAndSendData) {
// OnClose is invoked since both sides are closed.
rv = delegate->ReadData();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
EXPECT_EQ(2, delegate->on_data_read_count());
@@ -742,25 +906,22 @@ TEST_F(BidirectionalStreamTest, TestInterleaveReadDataAndSendData) {
}
TEST_F(BidirectionalStreamTest, TestCoalesceSmallDataBuffers) {
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
-
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kBodyDataSize * 1, LOWEST, nullptr, 0));
std::string body_data = "some really long piece of data";
- std::unique_ptr<SpdySerializedFrame> data_frame1(framer.CreateDataFrame(
- 1, body_data.c_str(), body_data.size(), DATA_FLAG_FIN));
+ SpdySerializedFrame data_frame1(spdy_util_.ConstructSpdyDataFrame(
+ 1, body_data.c_str(), body_data.size(), /*fin=*/true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*data_frame1, 1),
+ CreateMockWrite(req, 0), CreateMockWrite(data_frame1, 1),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> response_body_frame1(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame response_body_frame1(
+ spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 2),
+ CreateMockRead(resp, 2),
MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause.
- CreateMockRead(*response_body_frame1, 4), MockRead(ASYNC, 0, 5),
+ CreateMockRead(response_body_frame1, 4), MockRead(ASYNC, 0, 5),
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
@@ -790,7 +951,7 @@ TEST_F(BidirectionalStreamTest, TestCoalesceSmallDataBuffers) {
delegate->SendvData({buf, buf2.get()}, {buf->size(), buf2->size()}, true);
sequenced_data_->RunUntilPaused(); // OnHeadersReceived.
// ReadData and it should return asynchronously because no data is buffered.
- EXPECT_EQ(ERR_IO_PENDING, delegate->ReadData());
+ EXPECT_THAT(delegate->ReadData(), IsError(ERR_IO_PENDING));
sequenced_data_->Resume();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, delegate->on_data_sent_count());
@@ -808,56 +969,64 @@ TEST_F(BidirectionalStreamTest, TestCoalesceSmallDataBuffers) {
TestNetLogEntry::List entries;
net_log_.GetEntries(&entries);
size_t index = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_BIDIRECTIONAL_STREAM_BYTES_SENT_COALESCED,
- NetLog::PHASE_BEGIN);
+ entries, 0, NetLogEventType::BIDIRECTIONAL_STREAM_SENDV_DATA,
+ NetLogEventPhase::NONE);
TestNetLogEntry entry = entries[index];
+ int num_buffers = 0;
+ EXPECT_TRUE(entry.params->GetInteger("num_buffers", &num_buffers));
+ EXPECT_EQ(2, num_buffers);
+
+ index = ExpectLogContainsSomewhereAfter(
+ entries, index,
+ NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT_COALESCED,
+ NetLogEventPhase::BEGIN);
+ entry = entries[index];
int num_buffers_coalesced = 0;
EXPECT_TRUE(entry.params->GetInteger("num_buffers_coalesced",
&num_buffers_coalesced));
EXPECT_EQ(2, num_buffers_coalesced);
index = ExpectLogContainsSomewhereAfter(
- entries, index, NetLog::TYPE_BIDIRECTIONAL_STREAM_BYTES_SENT,
- NetLog::PHASE_NONE);
+ entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT,
+ NetLogEventPhase::NONE);
entry = entries[index];
int byte_count = 0;
EXPECT_TRUE(entry.params->GetInteger("byte_count", &byte_count));
EXPECT_EQ(buf->size(), byte_count);
index = ExpectLogContainsSomewhereAfter(
- entries, index + 1, NetLog::TYPE_BIDIRECTIONAL_STREAM_BYTES_SENT,
- NetLog::PHASE_NONE);
+ entries, index + 1, NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT,
+ NetLogEventPhase::NONE);
entry = entries[index];
byte_count = 0;
EXPECT_TRUE(entry.params->GetInteger("byte_count", &byte_count));
EXPECT_EQ(buf2->size(), byte_count);
ExpectLogContainsSomewhere(
- entries, index, NetLog::TYPE_BIDIRECTIONAL_STREAM_BYTES_SENT_COALESCED,
- NetLog::PHASE_END);
+ entries, index,
+ NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT_COALESCED,
+ NetLogEventPhase::END);
}
// Tests that BidirectionalStreamSpdyImpl::OnClose will complete any remaining
// read even if the read queue is empty.
TEST_F(BidirectionalStreamTest, TestCompleteAsyncRead) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
// Empty DATA frame with an END_STREAM flag.
- std::unique_ptr<SpdySerializedFrame> end_stream(
- spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
+ SpdySerializedFrame end_stream(
+ spdy_util_.ConstructSpdyDataFrame(1, nullptr, 0, true));
- MockWrite writes[] = {CreateMockWrite(*req.get(), 0)};
+ MockWrite writes[] = {CreateMockWrite(req, 0)};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> response_body_frame(
- spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
+ SpdySerializedFrame response_body_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, nullptr, 0, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
+ CreateMockRead(resp, 1),
MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
- CreateMockRead(*response_body_frame, 3), MockRead(SYNCHRONOUS, 0, 4),
+ CreateMockRead(response_body_frame, 3), MockRead(SYNCHRONOUS, 0, 4),
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
@@ -881,7 +1050,7 @@ TEST_F(BidirectionalStreamTest, TestCompleteAsyncRead) {
// ReadData should return asynchronously because no data is buffered.
int rv = delegate->ReadData();
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Deliver END_STREAM.
// OnClose should trigger completion of the remaining read.
sequenced_data_->Resume();
@@ -899,31 +1068,29 @@ TEST_F(BidirectionalStreamTest, TestCompleteAsyncRead) {
}
TEST_F(BidirectionalStreamTest, TestBuffering) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
// Empty DATA frame with an END_STREAM flag.
- std::unique_ptr<SpdySerializedFrame> end_stream(
- spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
+ SpdySerializedFrame end_stream(
+ spdy_util_.ConstructSpdyDataFrame(1, nullptr, 0, true));
- MockWrite writes[] = {CreateMockWrite(*req.get(), 0)};
+ MockWrite writes[] = {CreateMockWrite(req, 0)};
const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
+ SpdySerializedFrame resp(
+ spdy_util_.ConstructSpdyGetReply(kExtraResponseHeaders, 1, 1));
- std::unique_ptr<SpdySerializedFrame> body_frame(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
+ SpdySerializedFrame body_frame(spdy_util_.ConstructSpdyDataFrame(1, false));
// Last body frame has END_STREAM flag set.
- std::unique_ptr<SpdySerializedFrame> last_body_frame(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame last_body_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body_frame, 2),
- CreateMockRead(*body_frame, 3),
+ CreateMockRead(resp, 1),
+ CreateMockRead(body_frame, 2),
+ CreateMockRead(body_frame, 3),
MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause.
- CreateMockRead(*last_body_frame, 5),
+ CreateMockRead(last_body_frame, 5),
MockRead(SYNCHRONOUS, 0, 6),
};
@@ -980,36 +1147,34 @@ TEST_F(BidirectionalStreamTest, TestBuffering) {
}
TEST_F(BidirectionalStreamTest, TestBufferingWithTrailers) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
// Empty DATA frame with an END_STREAM flag.
- std::unique_ptr<SpdySerializedFrame> end_stream(
- spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
+ SpdySerializedFrame end_stream(
+ spdy_util_.ConstructSpdyDataFrame(1, nullptr, 0, true));
MockWrite writes[] = {
- CreateMockWrite(*req.get(), 0),
+ CreateMockWrite(req, 0),
};
const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
+ SpdySerializedFrame resp(
+ spdy_util_.ConstructSpdyGetReply(kExtraResponseHeaders, 1, 1));
- std::unique_ptr<SpdySerializedFrame> body_frame(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
+ SpdySerializedFrame body_frame(spdy_util_.ConstructSpdyDataFrame(1, false));
SpdyHeaderBlock trailers;
trailers["foo"] = "bar";
- std::unique_ptr<SpdySerializedFrame> response_trailers(
+ SpdySerializedFrame response_trailers(
spdy_util_.ConstructSpdyResponseHeaders(1, std::move(trailers), true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body_frame, 2),
- CreateMockRead(*body_frame, 3),
- CreateMockRead(*body_frame, 4),
+ CreateMockRead(resp, 1),
+ CreateMockRead(body_frame, 2),
+ CreateMockRead(body_frame, 3),
+ CreateMockRead(body_frame, 4),
MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause.
- CreateMockRead(*response_trailers, 6),
+ CreateMockRead(response_trailers, 6),
MockRead(SYNCHRONOUS, 0, 7),
};
@@ -1059,28 +1224,25 @@ TEST_F(BidirectionalStreamTest, TestBufferingWithTrailers) {
delegate->GetTotalReceivedBytes());
}
-TEST_F(BidirectionalStreamTest, CancelStreamAfterSendData) {
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
-
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+TEST_F(BidirectionalStreamTest, DeleteStreamAfterSendData) {
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kBodyDataSize * 3, LOWEST, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> data_frame(
- framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame data_frame(spdy_util_.ConstructSpdyDataFrame(
+ 1, kBodyData, kBodyDataSize, /*fin=*/false));
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*data_frame, 3),
- CreateMockWrite(*rst, 5),
+ CreateMockWrite(req, 0), CreateMockWrite(data_frame, 3),
+ CreateMockWrite(rst, 5),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> response_body_frame(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame response_body_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, false));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
+ CreateMockRead(resp, 1),
MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause.
MockRead(ASYNC, 0, 6),
@@ -1111,44 +1273,40 @@ TEST_F(BidirectionalStreamTest, CancelStreamAfterSendData) {
delegate->SendData(buf, buf->size(), false);
sequenced_data_->Resume();
base::RunLoop().RunUntilIdle();
- // Cancel the stream.
- delegate->CancelStream();
+
+ delegate->DeleteStream();
sequenced_data_->Resume();
base::RunLoop().RunUntilIdle();
EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
EXPECT_EQ(0, delegate->on_data_read_count());
- // EXPECT_EQ(1, delegate->on_data_send_count());
// OnDataSent may or may not have been invoked.
- // Calling after stream is canceled gives kProtoUnknown.
- EXPECT_EQ(kProtoUnknown, delegate->GetProtocol());
- EXPECT_EQ(0, delegate->GetTotalSentBytes());
- EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
+ EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
+ // Bytes sent excludes the RST frame.
+ EXPECT_EQ(CountWriteBytes(writes, arraysize(writes) - 1),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
+ delegate->GetTotalReceivedBytes());
}
-TEST_F(BidirectionalStreamTest, CancelStreamDuringReadData) {
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
-
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+TEST_F(BidirectionalStreamTest, DeleteStreamDuringReadData) {
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kBodyDataSize * 3, LOWEST, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> data_frame(
- framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> response_body_frame(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame response_body_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, false));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
+ CreateMockRead(resp, 1),
MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
- CreateMockRead(*response_body_frame, 3), MockRead(ASYNC, 0, 5),
+ CreateMockRead(response_body_frame, 3), MockRead(ASYNC, 0, 5),
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
@@ -1170,40 +1328,44 @@ TEST_F(BidirectionalStreamTest, CancelStreamDuringReadData) {
base::RunLoop().RunUntilIdle();
EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
- // Cancel the stream after ReadData returns ERR_IO_PENDING.
+ // Delete the stream after ReadData returns ERR_IO_PENDING.
int rv = delegate->ReadData();
EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- delegate->CancelStream();
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ delegate->DeleteStream();
sequenced_data_->Resume();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, delegate->on_data_read_count());
EXPECT_EQ(0, delegate->on_data_sent_count());
- // Calling after stream is canceled gives kProtoUnknown.
- EXPECT_EQ(kProtoUnknown, delegate->GetProtocol());
- EXPECT_EQ(0, delegate->GetTotalSentBytes());
- EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
+ EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
+ // Bytes sent excludes the RST frame.
+ EXPECT_EQ(CountWriteBytes(writes, arraysize(writes) - 1),
+ delegate->GetTotalSentBytes());
+ // Response body frame isn't read becase stream is deleted once read returns
+ // ERR_IO_PENDING.
+ EXPECT_EQ(CountReadBytes(reads, arraysize(reads) - 2),
+ delegate->GetTotalReceivedBytes());
}
// Receiving a header with uppercase ASCII will result in a protocol error,
// which should be propagated via Delegate::OnFailed.
TEST_F(BidirectionalStreamTest, PropagateProtocolError) {
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kBodyDataSize * 3, LOW, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
};
const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
+ SpdySerializedFrame resp(
+ spdy_util_.ConstructSpdyGetReply(kExtraHeaders, 1, 1));
MockRead reads[] = {
- CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3),
+ CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3),
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
@@ -1222,7 +1384,7 @@ TEST_F(BidirectionalStreamTest, PropagateProtocolError) {
delegate->Start(std::move(request_info), http_session_.get());
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate->error());
+ EXPECT_THAT(delegate->error(), IsError(ERR_SPDY_PROTOCOL_ERROR));
EXPECT_EQ(delegate->response_headers().end(),
delegate->response_headers().find(":status"));
EXPECT_EQ(0, delegate->on_data_read_count());
@@ -1238,43 +1400,39 @@ TEST_F(BidirectionalStreamTest, PropagateProtocolError) {
net_log_.GetEntries(&entries);
size_t index = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_BIDIRECTIONAL_STREAM_READY, NetLog::PHASE_NONE);
+ entries, 0, NetLogEventType::BIDIRECTIONAL_STREAM_READY,
+ NetLogEventPhase::NONE);
TestNetLogEntry entry = entries[index];
bool request_headers_sent = false;
EXPECT_TRUE(
entry.params->GetBoolean("request_headers_sent", &request_headers_sent));
EXPECT_TRUE(request_headers_sent);
- index = ExpectLogContainsSomewhere(entries, index,
- NetLog::TYPE_BIDIRECTIONAL_STREAM_FAILED,
- NetLog::PHASE_NONE);
+ index = ExpectLogContainsSomewhere(
+ entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_FAILED,
+ NetLogEventPhase::NONE);
entry = entries[index];
int net_error = OK;
EXPECT_TRUE(entry.params->GetInteger("net_error", &net_error));
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, net_error);
+ EXPECT_THAT(net_error, IsError(ERR_SPDY_PROTOCOL_ERROR));
}
-INSTANTIATE_TEST_CASE_P(CancelOrDeleteTests,
- BidirectionalStreamTest,
- ::testing::Values(true, false));
-
-TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnHeadersReceived) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
+TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnHeadersReceived) {
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
};
const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
+ SpdySerializedFrame resp(
+ spdy_util_.ConstructSpdyGetReply(kExtraResponseHeaders, 1, 1));
MockRead reads[] = {
- CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3),
+ CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3),
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
@@ -1287,11 +1445,9 @@ TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnHeadersReceived) {
request_info->end_stream_on_headers = true;
scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
- std::unique_ptr<CancelOrDeleteStreamDelegate> delegate(
- new CancelOrDeleteStreamDelegate(
- read_buffer.get(), kReadBufferSize,
- CancelOrDeleteStreamDelegate::Phase::ON_HEADERS_RECEIVED,
- GetParam()));
+ std::unique_ptr<DeleteStreamDelegate> delegate(new DeleteStreamDelegate(
+ read_buffer.get(), kReadBufferSize,
+ DeleteStreamDelegate::Phase::ON_HEADERS_RECEIVED));
delegate->SetRunUntilCompletion(true);
delegate->Start(std::move(request_info), http_session_.get());
// Makes sure delegate does not get called.
@@ -1303,34 +1459,33 @@ TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnHeadersReceived) {
EXPECT_EQ(0, delegate->on_data_sent_count());
EXPECT_EQ(0, delegate->on_data_read_count());
- // If stream is destroyed, do not call into stream.
- if (!GetParam())
- return;
- EXPECT_EQ(0, delegate->GetTotalSentBytes());
- EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
- EXPECT_EQ(kProtoUnknown, delegate->GetProtocol());
+ EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
+ // Bytes sent excludes the RST frame.
+ EXPECT_EQ(CountWriteBytes(writes, arraysize(writes) - 1),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
+ delegate->GetTotalReceivedBytes());
}
-TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnDataRead) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
+TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnDataRead) {
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 3),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 3),
};
const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
+ SpdySerializedFrame resp(
+ spdy_util_.ConstructSpdyGetReply(kExtraResponseHeaders, 1, 1));
- std::unique_ptr<SpdySerializedFrame> response_body_frame(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
+ SpdySerializedFrame response_body_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, false));
MockRead reads[] = {
- CreateMockRead(*resp, 1), CreateMockRead(*response_body_frame, 2),
+ CreateMockRead(resp, 1), CreateMockRead(response_body_frame, 2),
MockRead(ASYNC, 0, 4),
};
@@ -1344,10 +1499,9 @@ TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnDataRead) {
request_info->end_stream_on_headers = true;
scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
- std::unique_ptr<CancelOrDeleteStreamDelegate> delegate(
- new CancelOrDeleteStreamDelegate(
- read_buffer.get(), kReadBufferSize,
- CancelOrDeleteStreamDelegate::Phase::ON_DATA_READ, GetParam()));
+ std::unique_ptr<DeleteStreamDelegate> delegate(
+ new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize,
+ DeleteStreamDelegate::Phase::ON_DATA_READ));
delegate->SetRunUntilCompletion(true);
delegate->Start(std::move(request_info), http_session_.get());
// Makes sure delegate does not get called.
@@ -1359,40 +1513,39 @@ TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnDataRead) {
static_cast<int>(delegate->data_received().size()));
EXPECT_EQ(0, delegate->on_data_sent_count());
- // If stream is destroyed, do not call into stream.
- if (!GetParam())
- return;
- EXPECT_EQ(0, delegate->GetTotalSentBytes());
- EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
- EXPECT_EQ(kProtoUnknown, delegate->GetProtocol());
+ EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
+ // Bytes sent excludes the RST frame.
+ EXPECT_EQ(CountWriteBytes(writes, arraysize(writes) - 1),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
+ delegate->GetTotalReceivedBytes());
}
-TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnTrailersReceived) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
+TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnTrailersReceived) {
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
};
const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
+ SpdySerializedFrame resp(
+ spdy_util_.ConstructSpdyGetReply(kExtraResponseHeaders, 1, 1));
- std::unique_ptr<SpdySerializedFrame> response_body_frame(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
+ SpdySerializedFrame response_body_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, false));
SpdyHeaderBlock trailers;
trailers["foo"] = "bar";
- std::unique_ptr<SpdySerializedFrame> response_trailers(
+ SpdySerializedFrame response_trailers(
spdy_util_.ConstructSpdyResponseHeaders(1, std::move(trailers), true));
MockRead reads[] = {
- CreateMockRead(*resp, 1), CreateMockRead(*response_body_frame, 2),
- CreateMockRead(*response_trailers, 3), MockRead(ASYNC, 0, 5),
+ CreateMockRead(resp, 1), CreateMockRead(response_body_frame, 2),
+ CreateMockRead(response_trailers, 3), MockRead(ASYNC, 0, 5),
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
@@ -1405,11 +1558,9 @@ TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnTrailersReceived) {
request_info->end_stream_on_headers = true;
scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
- std::unique_ptr<CancelOrDeleteStreamDelegate> delegate(
- new CancelOrDeleteStreamDelegate(
- read_buffer.get(), kReadBufferSize,
- CancelOrDeleteStreamDelegate::Phase::ON_TRAILERS_RECEIVED,
- GetParam()));
+ std::unique_ptr<DeleteStreamDelegate> delegate(new DeleteStreamDelegate(
+ read_buffer.get(), kReadBufferSize,
+ DeleteStreamDelegate::Phase::ON_TRAILERS_RECEIVED));
delegate->SetRunUntilCompletion(true);
delegate->Start(std::move(request_info), http_session_.get());
// Makes sure delegate does not get called.
@@ -1420,33 +1571,31 @@ TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnTrailersReceived) {
EXPECT_EQ("bar", delegate->trailers().find("foo")->second);
EXPECT_EQ(0, delegate->on_data_sent_count());
// OnDataRead may or may not have been fired before the stream is
- // canceled/deleted.
-
- // If stream is destroyed, do not call into stream.
- if (!GetParam())
- return;
- EXPECT_EQ(0, delegate->GetTotalSentBytes());
- EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
- EXPECT_EQ(kProtoUnknown, delegate->GetProtocol());
+ // deleted.
+ EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
+ // Bytes sent excludes the RST frame.
+ EXPECT_EQ(CountWriteBytes(writes, arraysize(writes) - 1),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
+ delegate->GetTotalReceivedBytes());
}
-TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnFailed) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
+TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnFailed) {
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
};
const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
+ SpdySerializedFrame resp(
+ spdy_util_.ConstructSpdyGetReply(kExtraHeaders, 1, 1));
MockRead reads[] = {
- CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3),
+ CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3),
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
@@ -1459,10 +1608,9 @@ TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnFailed) {
request_info->end_stream_on_headers = true;
scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
- std::unique_ptr<CancelOrDeleteStreamDelegate> delegate(
- new CancelOrDeleteStreamDelegate(
- read_buffer.get(), kReadBufferSize,
- CancelOrDeleteStreamDelegate::Phase::ON_FAILED, GetParam()));
+ std::unique_ptr<DeleteStreamDelegate> delegate(
+ new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize,
+ DeleteStreamDelegate::Phase::ON_FAILED));
delegate->SetRunUntilCompletion(true);
delegate->Start(std::move(request_info), http_session_.get());
// Makes sure delegate does not get called.
@@ -1471,37 +1619,35 @@ TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnFailed) {
delegate->response_headers().find(":status"));
EXPECT_EQ(0, delegate->on_data_sent_count());
EXPECT_EQ(0, delegate->on_data_read_count());
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate->error());
-
- // If stream is destroyed, do not call into stream.
- if (!GetParam())
- return;
- EXPECT_EQ(0, delegate->GetTotalSentBytes());
- EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
- EXPECT_EQ(kProtoUnknown, delegate->GetProtocol());
+ EXPECT_THAT(delegate->error(), IsError(ERR_SPDY_PROTOCOL_ERROR));
+
+ EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
+ // Bytes sent excludes the RST frame.
+ EXPECT_EQ(CountWriteBytes(writes, arraysize(writes) - 1),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
+ delegate->GetTotalReceivedBytes());
}
TEST_F(BidirectionalStreamTest, TestHonorAlternativeServiceHeader) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
// Empty DATA frame with an END_STREAM flag.
- std::unique_ptr<SpdySerializedFrame> end_stream(
- spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
+ SpdySerializedFrame end_stream(
+ spdy_util_.ConstructSpdyDataFrame(1, nullptr, 0, true));
- MockWrite writes[] = {CreateMockWrite(*req.get(), 0)};
+ MockWrite writes[] = {CreateMockWrite(req, 0)};
std::string alt_svc_header_value = AlternateProtocolToString(QUIC);
alt_svc_header_value.append("=\"www.example.org:443\"");
const char* const kExtraResponseHeaders[] = {"alt-svc",
alt_svc_header_value.c_str()};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
- std::unique_ptr<SpdySerializedFrame> body_frame(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(
+ spdy_util_.ConstructSpdyGetReply(kExtraResponseHeaders, 1, 1));
+ SpdySerializedFrame body_frame(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1), CreateMockRead(*body_frame, 2),
+ CreateMockRead(resp, 1), CreateMockRead(body_frame, 2),
MockRead(SYNCHRONOUS, 0, 3),
};
diff --git a/chromium/net/http/disk_cache_based_quic_server_info.cc b/chromium/net/http/disk_cache_based_quic_server_info.cc
index 2ba6cf8e0dc..0b4d9b03567 100644
--- a/chromium/net/http/disk_cache_based_quic_server_info.cc
+++ b/chromium/net/http/disk_cache_based_quic_server_info.cc
@@ -14,7 +14,7 @@
#include "net/base/net_errors.h"
#include "net/http/http_cache.h"
#include "net/http/http_network_session.h"
-#include "net/quic/quic_server_id.h"
+#include "net/quic/core/quic_server_id.h"
namespace net {
diff --git a/chromium/net/http/disk_cache_based_quic_server_info.h b/chromium/net/http/disk_cache_based_quic_server_info.h
index 9403d6f4687..ebdd65ffdb8 100644
--- a/chromium/net/http/disk_cache_based_quic_server_info.h
+++ b/chromium/net/http/disk_cache_based_quic_server_info.h
@@ -13,8 +13,9 @@
#include "base/threading/non_thread_safe.h"
#include "base/time/time.h"
#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
#include "net/disk_cache/disk_cache.h"
-#include "net/quic/crypto/quic_server_info.h"
+#include "net/quic/core/crypto/quic_server_info.h"
namespace net {
@@ -61,36 +62,6 @@ class NET_EXPORT_PRIVATE DiskCacheBasedQuicServerInfo
NONE,
};
- // Enum to track number of times data read/parse/write API calls of
- // QuicServerInfo to and from disk cache is called.
- enum QuicServerInfoAPICall {
- QUIC_SERVER_INFO_START = 0,
- QUIC_SERVER_INFO_WAIT_FOR_DATA_READY = 1,
- QUIC_SERVER_INFO_PARSE = 2,
- QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL = 3,
- QUIC_SERVER_INFO_READY_TO_PERSIST = 4,
- QUIC_SERVER_INFO_PERSIST = 5,
- QUIC_SERVER_INFO_EXTERNAL_CACHE_HIT = 6,
- QUIC_SERVER_INFO_NUM_OF_API_CALLS = 7,
- };
-
- // Enum to track failure reasons to read/load/write of QuicServerInfo to
- // and from disk cache.
- enum FailureReason {
- WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE = 0,
- GET_BACKEND_FAILURE = 1,
- OPEN_FAILURE = 2,
- CREATE_OR_OPEN_FAILURE = 3,
- PARSE_NO_DATA_FAILURE = 4,
- PARSE_FAILURE = 5,
- READ_FAILURE = 6,
- READY_TO_PERSIST_FAILURE = 7,
- PERSIST_NO_BACKEND_FAILURE = 8,
- WRITE_FAILURE = 9,
- NO_FAILURE = 10,
- NUM_OF_FAILURES = 11,
- };
-
~DiskCacheBasedQuicServerInfo() override;
// Persists |pending_write_data_| if it is not empty, otherwise serializes the
diff --git a/chromium/net/http/disk_cache_based_quic_server_info_unittest.cc b/chromium/net/http/disk_cache_based_quic_server_info_unittest.cc
index ce4d5526f5e..569b86522a1 100644
--- a/chromium/net/http/disk_cache_based_quic_server_info_unittest.cc
+++ b/chromium/net/http/disk_cache_based_quic_server_info_unittest.cc
@@ -12,10 +12,15 @@
#include "base/run_loop.h"
#include "net/base/net_errors.h"
#include "net/http/mock_http_cache.h"
-#include "net/quic/crypto/quic_server_info.h"
-#include "net/quic/quic_server_id.h"
+#include "net/quic/core/crypto/quic_server_info.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
using std::string;
namespace net {
@@ -96,10 +101,10 @@ TEST(DiskCacheBasedQuicServerInfo, DeleteInCallback) {
quic_server_info->Start();
TestCompletionCallback callback;
int rv = quic_server_info->WaitForDataReady(callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Now complete the backend creation and let the callback run.
factory->FinishCreation();
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
}
// Tests the basic logic of storing, retrieving and updating data.
@@ -113,7 +118,7 @@ TEST(DiskCacheBasedQuicServerInfo, Update) {
new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
quic_server_info->Start();
int rv = quic_server_info->WaitForDataReady(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
QuicServerInfo::State* state = quic_server_info->mutable_state();
EXPECT_TRUE(state->certs.empty());
@@ -141,7 +146,7 @@ TEST(DiskCacheBasedQuicServerInfo, Update) {
new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
quic_server_info->Start();
rv = quic_server_info->WaitForDataReady(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
// And now update the data.
state = quic_server_info->mutable_state();
@@ -157,7 +162,7 @@ TEST(DiskCacheBasedQuicServerInfo, Update) {
new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
quic_server_info->Start();
rv = quic_server_info->WaitForDataReady(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(quic_server_info->IsDataReady());
const QuicServerInfo::State& state1 = quic_server_info->state();
@@ -186,7 +191,7 @@ TEST(DiskCacheBasedQuicServerInfo, UpdateDifferentPorts) {
new DiskCacheBasedQuicServerInfo(server_id1, cache.http_cache()));
quic_server_info1->Start();
int rv = quic_server_info1->WaitForDataReady(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
QuicServerInfo::State* state1 = quic_server_info1->mutable_state();
EXPECT_TRUE(state1->certs.empty());
@@ -214,7 +219,7 @@ TEST(DiskCacheBasedQuicServerInfo, UpdateDifferentPorts) {
new DiskCacheBasedQuicServerInfo(server_id2, cache.http_cache()));
quic_server_info2->Start();
rv = quic_server_info2->WaitForDataReady(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
QuicServerInfo::State* state2 = quic_server_info2->mutable_state();
EXPECT_TRUE(state2->certs.empty());
@@ -241,7 +246,7 @@ TEST(DiskCacheBasedQuicServerInfo, UpdateDifferentPorts) {
new DiskCacheBasedQuicServerInfo(server_id1, cache.http_cache()));
quic_server_info->Start();
rv = quic_server_info->WaitForDataReady(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(quic_server_info->IsDataReady());
const QuicServerInfo::State& state_a = quic_server_info->state();
@@ -258,7 +263,7 @@ TEST(DiskCacheBasedQuicServerInfo, UpdateDifferentPorts) {
new DiskCacheBasedQuicServerInfo(server_id2, cache.http_cache()));
quic_server_info->Start();
rv = quic_server_info->WaitForDataReady(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(quic_server_info->IsDataReady());
const QuicServerInfo::State& state_b = quic_server_info->state();
@@ -286,7 +291,7 @@ TEST(DiskCacheBasedQuicServerInfo, IsReadyToPersist) {
EXPECT_FALSE(quic_server_info->IsDataReady());
quic_server_info->Start();
int rv = quic_server_info->WaitForDataReady(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(quic_server_info->IsDataReady());
QuicServerInfo::State* state = quic_server_info->mutable_state();
@@ -321,7 +326,7 @@ TEST(DiskCacheBasedQuicServerInfo, IsReadyToPersist) {
new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
quic_server_info->Start();
rv = quic_server_info->WaitForDataReady(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(quic_server_info->IsDataReady());
const QuicServerInfo::State& state1 = quic_server_info->state();
@@ -348,7 +353,7 @@ TEST(DiskCacheBasedQuicServerInfo, MultiplePersist) {
EXPECT_FALSE(quic_server_info->IsDataReady());
quic_server_info->Start();
int rv = quic_server_info->WaitForDataReady(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(quic_server_info->IsDataReady());
// Persist data once.
@@ -411,7 +416,7 @@ TEST(DiskCacheBasedQuicServerInfo, MultiplePersist) {
new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
quic_server_info->Start();
rv = quic_server_info->WaitForDataReady(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(quic_server_info->IsDataReady());
const QuicServerInfo::State& state1 = quic_server_info->state();
@@ -436,7 +441,7 @@ TEST(DiskCacheBasedQuicServerInfo, CancelWaitForDataReady) {
EXPECT_FALSE(quic_server_info->IsDataReady());
quic_server_info->Start();
int rv = quic_server_info->WaitForDataReady(callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Now cancel the callback.
quic_server_info->CancelWaitForDataReadyCallback();
EXPECT_FALSE(quic_server_info->IsDataReady());
@@ -457,7 +462,7 @@ TEST(DiskCacheBasedQuicServerInfo, CancelWaitForDataReadyButDataIsReady) {
quic_server_info->Start();
int rv = quic_server_info->WaitForDataReady(callback.callback());
quic_server_info->CancelWaitForDataReadyCallback();
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(quic_server_info->IsDataReady());
RemoveMockTransaction(&kHostInfoTransaction1);
}
@@ -476,7 +481,7 @@ TEST(DiskCacheBasedQuicServerInfo, CancelWaitForDataReadyAfterDeleteCache) {
quic_server_info->Start();
int rv = quic_server_info->WaitForDataReady(callback.callback());
quic_server_info->CancelWaitForDataReadyCallback();
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(quic_server_info->IsDataReady());
RemoveMockTransaction(&kHostInfoTransaction1);
}
@@ -533,7 +538,7 @@ TEST(DiskCacheBasedQuicServerInfo, StartAndPersist) {
quic_server_info->Start();
TestCompletionCallback callback;
int rv = quic_server_info->WaitForDataReady(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(quic_server_info->IsDataReady());
const QuicServerInfo::State& state1 = quic_server_info->state();
@@ -597,7 +602,7 @@ TEST(DiskCacheBasedQuicServerInfo, PersistWhenNotReadyToPersist) {
new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
quic_server_info->Start();
int rv = quic_server_info->WaitForDataReady(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(quic_server_info->IsDataReady());
const QuicServerInfo::State& state1 = quic_server_info->state();
@@ -623,7 +628,7 @@ TEST(DiskCacheBasedQuicServerInfo, MultiplePersistsWithoutWaiting) {
EXPECT_FALSE(quic_server_info->IsDataReady());
quic_server_info->Start();
int rv = quic_server_info->WaitForDataReady(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(quic_server_info->IsDataReady());
// Persist data once.
@@ -677,7 +682,7 @@ TEST(DiskCacheBasedQuicServerInfo, MultiplePersistsWithoutWaiting) {
new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
quic_server_info->Start();
rv = quic_server_info->WaitForDataReady(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(quic_server_info->IsDataReady());
// Verify the second time persisted data is persisted.
@@ -707,10 +712,10 @@ TEST(DiskCacheBasedQuicServerInfo, DeleteServerInfoInCallback) {
DeleteCacheCompletionCallback cb(quic_server_info);
quic_server_info->Start();
int rv = quic_server_info->WaitForDataReady(cb.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Now complete the backend creation and let the callback run.
factory->FinishCreation();
- EXPECT_EQ(OK, cb.GetResult(rv));
+ EXPECT_THAT(cb.GetResult(rv), IsOk());
}
} // namespace net
diff --git a/chromium/net/http/failing_http_transaction_factory.cc b/chromium/net/http/failing_http_transaction_factory.cc
index 6af41741182..7d49327a57a 100644
--- a/chromium/net/http/failing_http_transaction_factory.cc
+++ b/chromium/net/http/failing_http_transaction_factory.cc
@@ -14,16 +14,15 @@
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/load_timing_info.h"
#include "net/base/net_error_details.h"
-#include "net/base/upload_progress.h"
#include "net/http/http_response_info.h"
#include "net/socket/connection_attempts.h"
namespace net {
class AuthCredentials;
-class BoundNetLog;
class HttpRequestHeaders;
class IOBuffer;
+class NetLogWithSource;
class SSLPrivateKey;
class X509Certificate;
@@ -40,7 +39,7 @@ class FailingHttpTransaction : public HttpTransaction {
// HttpTransaction
int Start(const HttpRequestInfo* request_info,
const CompletionCallback& callback,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
int RestartIgnoringLastError(const CompletionCallback& callback) override;
int RestartWithCertificate(X509Certificate* client_cert,
SSLPrivateKey* client_private_key,
@@ -58,7 +57,6 @@ class FailingHttpTransaction : public HttpTransaction {
void DoneReading() override;
const HttpResponseInfo* GetResponseInfo() const override;
LoadState GetLoadState() const override;
- UploadProgress GetUploadProgress() const override;
void SetQuicServerInfo(QuicServerInfo* quic_server_info) override;
bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
bool GetRemoteEndpoint(IPEndPoint* endpoint) const override;
@@ -86,7 +84,7 @@ FailingHttpTransaction::~FailingHttpTransaction() {}
int FailingHttpTransaction::Start(const HttpRequestInfo* request_info,
const CompletionCallback& callback,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
base::Bind(callback, error_));
return ERR_IO_PENDING;
@@ -147,10 +145,6 @@ LoadState FailingHttpTransaction::GetLoadState() const {
return LOAD_STATE_IDLE;
}
-UploadProgress FailingHttpTransaction::GetUploadProgress() const {
- return UploadProgress();
-}
-
void FailingHttpTransaction::SetQuicServerInfo(
QuicServerInfo* quic_server_info) {
}
diff --git a/chromium/net/http/failing_http_transaction_factory.h b/chromium/net/http/failing_http_transaction_factory.h
index 6b85d28d841..47156a2abe2 100644
--- a/chromium/net/http/failing_http_transaction_factory.h
+++ b/chromium/net/http/failing_http_transaction_factory.h
@@ -8,6 +8,7 @@
#include <memory>
#include "net/base/net_errors.h"
+#include "net/base/net_export.h"
#include "net/base/request_priority.h"
#include "net/http/http_transaction.h"
#include "net/http/http_transaction_factory.h"
diff --git a/chromium/net/http/http_auth.cc b/chromium/net/http/http_auth.cc
index 738c1b8d7d0..bd8f9228cdb 100644
--- a/chromium/net/http/http_auth.cc
+++ b/chromium/net/http/http_auth.cc
@@ -29,7 +29,7 @@ void HttpAuth::ChooseBestChallenge(
Target target,
const GURL& origin,
const std::set<Scheme>& disabled_schemes,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) {
DCHECK(http_auth_handler_factory);
DCHECK(handler->get() == NULL);
diff --git a/chromium/net/http/http_auth.h b/chromium/net/http/http_auth.h
index 464a39e1b79..bf63af6e562 100644
--- a/chromium/net/http/http_auth.h
+++ b/chromium/net/http/http_auth.h
@@ -17,10 +17,10 @@ template <class T> class scoped_refptr;
namespace net {
-class BoundNetLog;
class HttpAuthHandler;
class HttpAuthHandlerFactory;
class HttpResponseHeaders;
+class NetLogWithSource;
class SSLInfo;
// Utility class for http authentication.
@@ -142,7 +142,7 @@ class NET_EXPORT_PRIVATE HttpAuth {
Target target,
const GURL& origin,
const std::set<Scheme>& disabled_schemes,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler);
// Handle a 401/407 response from a server/proxy after a previous
diff --git a/chromium/net/http/http_auth_cache.cc b/chromium/net/http/http_auth_cache.cc
index 7a3a4e0f671..9c073bdf58e 100644
--- a/chromium/net/http/http_auth_cache.cc
+++ b/chromium/net/http/http_auth_cache.cc
@@ -252,8 +252,11 @@ bool HttpAuthCache::Remove(const GURL& origin,
return false;
}
-void HttpAuthCache::Clear() {
- entries_.clear();
+void HttpAuthCache::ClearEntriesAddedWithin(base::TimeDelta duration) {
+ base::TimeTicks begin_time = base::TimeTicks::Now() - duration;
+ entries_.remove_if([begin_time](const Entry& entry) {
+ return entry.creation_time_ >= begin_time;
+ });
}
bool HttpAuthCache::UpdateStaleChallenge(const GURL& origin,
diff --git a/chromium/net/http/http_auth_cache.h b/chromium/net/http/http_auth_cache.h
index 9190e42c508..e620cb08ac4 100644
--- a/chromium/net/http/http_auth_cache.h
+++ b/chromium/net/http/http_auth_cache.h
@@ -27,9 +27,9 @@ namespace net {
// - the last auth handler used (contains realm and authentication scheme)
// - the list of paths which used this realm
// Entries can be looked up by either (origin, realm, scheme) or (origin, path).
-class NET_EXPORT_PRIVATE HttpAuthCache {
+class NET_EXPORT HttpAuthCache {
public:
- class NET_EXPORT_PRIVATE Entry {
+ class NET_EXPORT Entry {
public:
Entry(const Entry& other);
~Entry();
@@ -60,6 +60,10 @@ class NET_EXPORT_PRIVATE HttpAuthCache {
void UpdateStaleChallenge(const std::string& auth_challenge);
+ void set_creation_time_for_testing(base::TimeTicks creation_time) {
+ creation_time_ = creation_time;
+ }
+
private:
friend class HttpAuthCache;
FRIEND_TEST_ALL_PREFIXES(HttpAuthCacheTest, AddPath);
@@ -162,8 +166,8 @@ class NET_EXPORT_PRIVATE HttpAuthCache {
HttpAuth::Scheme scheme,
const AuthCredentials& credentials);
- // Clears the cache.
- void Clear();
+ // Clears cache entries created within |duration| of base::TimeTicks::Now().
+ void ClearEntriesAddedWithin(base::TimeDelta duration);
// Updates a stale digest entry on server |origin| for realm |realm| and
// scheme |scheme|. The cached auth challenge is replaced with
diff --git a/chromium/net/http/http_auth_cache_unittest.cc b/chromium/net/http/http_auth_cache_unittest.cc
index c0509ce1d50..6ab67c4c902 100644
--- a/chromium/net/http/http_auth_cache_unittest.cc
+++ b/chromium/net/http/http_auth_cache_unittest.cc
@@ -377,6 +377,44 @@ TEST(HttpAuthCacheTest, Remove) {
EXPECT_FALSE(NULL == entry);
}
+TEST(HttpAuthCacheTest, ClearEntriesAddedWithin) {
+ GURL origin("http://foobar.com");
+
+ HttpAuthCache cache;
+ base::TimeTicks old_creation_time =
+ base::TimeTicks::Now() - base::TimeDelta::FromMinutes(2);
+ cache
+ .Add(origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, "basic realm=Realm1",
+ AuthCredentials(kAlice, k123), "/")
+ ->set_creation_time_for_testing(old_creation_time);
+ cache
+ .Add(origin, kRealm2, HttpAuth::AUTH_SCHEME_BASIC, "basic realm=Realm2",
+ AuthCredentials(kRoot, kWileCoyote), "/")
+ ->set_creation_time_for_testing(old_creation_time);
+
+ cache.Add(origin, kRealm3, HttpAuth::AUTH_SCHEME_BASIC, "basic realm=Realm3",
+ AuthCredentials(kAlice2, k1234), "/");
+ cache.Add(origin, kRealm4, HttpAuth::AUTH_SCHEME_BASIC, "basic realm=Realm4",
+ AuthCredentials(kUsername, kPassword), "/");
+ // Add path to existing entry.
+ cache.Add(origin, kRealm2, HttpAuth::AUTH_SCHEME_BASIC, "basic realm=Realm2",
+ AuthCredentials(kAdmin, kPassword), "/baz/");
+
+ cache.ClearEntriesAddedWithin(base::TimeDelta::FromMinutes(1));
+
+ EXPECT_NE(nullptr,
+ cache.Lookup(origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC));
+ EXPECT_NE(nullptr,
+ cache.Lookup(origin, kRealm2, HttpAuth::AUTH_SCHEME_BASIC));
+ // Creation time is set for a whole entry rather than for a particular path.
+ // Path added within the requested duration isn't be removed.
+ EXPECT_NE(nullptr, cache.LookupByPath(origin, "/baz/"));
+ EXPECT_EQ(nullptr,
+ cache.Lookup(origin, kRealm3, HttpAuth::AUTH_SCHEME_BASIC));
+ EXPECT_EQ(nullptr,
+ cache.Lookup(origin, kRealm4, HttpAuth::AUTH_SCHEME_BASIC));
+}
+
TEST(HttpAuthCacheTest, UpdateStaleChallenge) {
HttpAuthCache cache;
GURL origin("http://foobar2.com");
diff --git a/chromium/net/http/http_auth_challenge_tokenizer_fuzzer.cc b/chromium/net/http/http_auth_challenge_tokenizer_fuzzer.cc
new file mode 100644
index 00000000000..92813449b50
--- /dev/null
+++ b/chromium/net/http/http_auth_challenge_tokenizer_fuzzer.cc
@@ -0,0 +1,18 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "net/http/http_auth_challenge_tokenizer.h"
+#include "net/http/http_util.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ std::string input(reinterpret_cast<const char*>(data), size);
+ net::HttpAuthChallengeTokenizer tokenizer(input.begin(), input.end());
+ net::HttpUtil::NameValuePairsIterator parameters = tokenizer.param_pairs();
+ while (parameters.GetNext()) {
+ }
+ tokenizer.base64_param();
+ return 0;
+}
diff --git a/chromium/net/http/http_auth_controller.cc b/chromium/net/http/http_auth_controller.cc
index d5c0c891da6..d7d5f0608f9 100644
--- a/chromium/net/http/http_auth_controller.cc
+++ b/chromium/net/http/http_auth_controller.cc
@@ -142,8 +142,9 @@ HttpAuthController::~HttpAuthController() {
}
int HttpAuthController::MaybeGenerateAuthToken(
- const HttpRequestInfo* request, const CompletionCallback& callback,
- const BoundNetLog& net_log) {
+ const HttpRequestInfo* request,
+ const CompletionCallback& callback,
+ const NetLogWithSource& net_log) {
DCHECK(CalledOnValidThread());
bool needs_auth = HaveAuth() || SelectPreemptiveAuth(net_log);
if (!needs_auth)
@@ -155,18 +156,19 @@ int HttpAuthController::MaybeGenerateAuthToken(
DCHECK(callback_.is_null());
int rv = handler_->GenerateAuthToken(
credentials, request,
- base::Bind(&HttpAuthController::OnIOComplete, base::Unretained(this)),
+ base::Bind(&HttpAuthController::OnGenerateAuthTokenDone,
+ base::Unretained(this)),
&auth_token_);
- if (DisableOnAuthHandlerResult(rv))
- rv = OK;
- if (rv == ERR_IO_PENDING)
+
+ if (rv == ERR_IO_PENDING) {
callback_ = callback;
- else
- OnIOComplete(rv);
- return rv;
+ return rv;
+ }
+
+ return HandleGenerateTokenResult(rv);
}
-bool HttpAuthController::SelectPreemptiveAuth(const BoundNetLog& net_log) {
+bool HttpAuthController::SelectPreemptiveAuth(const NetLogWithSource& net_log) {
DCHECK(CalledOnValidThread());
DCHECK(!HaveAuth());
DCHECK(identity_.invalid);
@@ -221,7 +223,7 @@ int HttpAuthController::HandleAuthChallenge(
const SSLInfo& ssl_info,
bool do_not_send_server_auth,
bool establishing_tunnel,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
DCHECK(CalledOnValidThread());
DCHECK(headers.get());
DCHECK(auth_origin_.is_valid());
@@ -470,10 +472,29 @@ void HttpAuthController::PopulateAuthChallenge() {
auth_info_->realm = handler_->realm();
}
-bool HttpAuthController::DisableOnAuthHandlerResult(int result) {
+int HttpAuthController::HandleGenerateTokenResult(int result) {
DCHECK(CalledOnValidThread());
-
switch (result) {
+ // Occurs if the credential handle is found to be invalid at the point it is
+ // exercised (i.e. GenerateAuthToken stage). We are going to consider this
+ // to be an error that invalidates the identity but not necessarily the
+ // scheme. Doing so allows a different identity to be used with the same
+ // scheme. See https://crbug.com/648366.
+ case ERR_INVALID_HANDLE:
+
+ // If the GenerateAuthToken call fails with this error, this means that the
+ // handler can no longer be used. However, the authentication scheme is
+ // considered still usable. This allows a scheme that attempted and failed
+ // to use default credentials to recover and use explicit credentials.
+ //
+ // The current handler may be tied to external state that is no longer
+ // valid, hence should be discarded. Since the scheme is still valid, a new
+ // handler can be created for the current scheme.
+ case ERR_INVALID_AUTH_CREDENTIALS:
+ InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS);
+ auth_token_.clear();
+ return OK;
+
// Occurs with GSSAPI, if the user has not already logged in.
case ERR_MISSING_AUTH_CREDENTIALS:
@@ -491,19 +512,18 @@ bool HttpAuthController::DisableOnAuthHandlerResult(int result) {
// In these cases, disable the current scheme as it cannot
// succeed.
- DisableAuthScheme(handler_->auth_scheme());
+ InvalidateCurrentHandler(INVALIDATE_HANDLER_AND_DISABLE_SCHEME);
auth_token_.clear();
- return true;
+ return OK;
default:
- return false;
+ return result;
}
}
-void HttpAuthController::OnIOComplete(int result) {
+void HttpAuthController::OnGenerateAuthTokenDone(int result) {
DCHECK(CalledOnValidThread());
- if (DisableOnAuthHandlerResult(result))
- result = OK;
+ result = HandleGenerateTokenResult(result);
if (!callback_.is_null()) {
CompletionCallback c = callback_;
callback_.Reset();
diff --git a/chromium/net/http/http_auth_controller.h b/chromium/net/http/http_auth_controller.h
index 04f3264e70c..dbc078e323a 100644
--- a/chromium/net/http/http_auth_controller.h
+++ b/chromium/net/http/http_auth_controller.h
@@ -14,7 +14,6 @@
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
#include "net/http/http_auth.h"
-#include "net/log/net_log.h"
#include "url/gurl.h"
namespace net {
@@ -25,6 +24,7 @@ class HttpAuthHandler;
class HttpAuthHandlerFactory;
class HttpAuthCache;
class HttpRequestHeaders;
+class NetLogWithSource;
struct HttpRequestInfo;
class SSLInfo;
@@ -45,7 +45,7 @@ class NET_EXPORT_PRIVATE HttpAuthController
// were necessary.
virtual int MaybeGenerateAuthToken(const HttpRequestInfo* request,
const CompletionCallback& callback,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Adds either the proxy auth header, or the origin server auth header,
// as specified by |target_|.
@@ -59,7 +59,7 @@ class NET_EXPORT_PRIVATE HttpAuthController
const SSLInfo& ssl_info,
bool do_not_send_server_auth,
bool establishing_tunnel,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Store the supplied credentials and prepare to restart the auth.
virtual void ResetAuth(const AuthCredentials& credentials);
@@ -90,7 +90,7 @@ class NET_EXPORT_PRIVATE HttpAuthController
// Searches the auth cache for an entry that encompasses the request's path.
// If such an entry is found, updates |identity_| and |handler_| with the
// cache entry's data and returns true.
- bool SelectPreemptiveAuth(const BoundNetLog& net_log);
+ bool SelectPreemptiveAuth(const NetLogWithSource& net_log);
// Invalidates the current handler. If |action| is
// INVALIDATE_HANDLER_AND_CACHED_CREDENTIALS, then also invalidate
@@ -110,12 +110,12 @@ class NET_EXPORT_PRIVATE HttpAuthController
// URLRequestHttpJob can prompt for credentials.
void PopulateAuthChallenge();
- // If |result| indicates a permanent failure, disables the current
- // auth scheme for this controller and returns true. Returns false
- // otherwise.
- bool DisableOnAuthHandlerResult(int result);
+ // Handle the result of calling GenerateAuthToken on an HttpAuthHandler. The
+ // return value of this function should be used as the return value of the
+ // GenerateAuthToken operation.
+ int HandleGenerateTokenResult(int result);
- void OnIOComplete(int result);
+ void OnGenerateAuthTokenDone(int result);
// Indicates if this handler is for Proxy auth or Server auth.
HttpAuth::Target target_;
diff --git a/chromium/net/http/http_auth_controller_unittest.cc b/chromium/net/http/http_auth_controller_unittest.cc
index b3d1ca3c7a6..eeeb60a7975 100644
--- a/chromium/net/http/http_auth_controller_unittest.cc
+++ b/chromium/net/http/http_auth_controller_unittest.cc
@@ -13,7 +13,7 @@
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/ssl/ssl_info.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -50,7 +50,7 @@ void RunSingleRoundAuthTest(HandlerRunMode run_mode,
int handler_rv,
int expected_controller_rv,
SchemeState scheme_state) {
- BoundNetLog dummy_log;
+ NetLogWithSource dummy_log;
HttpAuthCache dummy_auth_cache;
HttpRequestInfo request;
@@ -114,8 +114,15 @@ TEST(HttpAuthControllerTest, PermanentErrors) {
// If a non-permanent error is returned by the handler, then the
// controller should report it unchanged.
- RunSingleRoundAuthTest(RUN_HANDLER_ASYNC, ERR_INVALID_AUTH_CREDENTIALS,
- ERR_INVALID_AUTH_CREDENTIALS, SCHEME_IS_ENABLED);
+ RunSingleRoundAuthTest(RUN_HANDLER_ASYNC, ERR_UNEXPECTED, ERR_UNEXPECTED,
+ SCHEME_IS_ENABLED);
+
+ // ERR_INVALID_AUTH_CREDENTIALS is special. It's a non-permanet error, but
+ // the error isn't propagated, nor is the auth scheme disabled. This allows
+ // the scheme to re-attempt the authentication attempt using a different set
+ // of credentials.
+ RunSingleRoundAuthTest(RUN_HANDLER_ASYNC, ERR_INVALID_AUTH_CREDENTIALS, OK,
+ SCHEME_IS_ENABLED);
}
// If an HttpAuthHandler indicates that it doesn't allow explicit
@@ -164,7 +171,7 @@ TEST(HttpAuthControllerTest, NoExplicitCredentialsAllowed) {
HttpAuth::Scheme expected_scheme_;
};
- BoundNetLog dummy_log;
+ NetLogWithSource dummy_log;
HttpAuthCache dummy_auth_cache;
HttpRequestInfo request;
request.method = "GET";
diff --git a/chromium/net/http/http_auth_handler.cc b/chromium/net/http/http_auth_handler.cc
index 32af2d2fdbf..265309e053c 100644
--- a/chromium/net/http/http_auth_handler.cc
+++ b/chromium/net/http/http_auth_handler.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth_challenge_tokenizer.h"
+#include "net/log/net_log_event_type.h"
namespace net {
@@ -26,7 +27,7 @@ bool HttpAuthHandler::InitFromChallenge(HttpAuthChallengeTokenizer* challenge,
HttpAuth::Target target,
const SSLInfo& ssl_info,
const GURL& origin,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
origin_ = origin;
target_ = target;
score_ = -1;
@@ -47,15 +48,15 @@ bool HttpAuthHandler::InitFromChallenge(HttpAuthChallengeTokenizer* challenge,
namespace {
-NetLog::EventType EventTypeFromAuthTarget(HttpAuth::Target target) {
+NetLogEventType EventTypeFromAuthTarget(HttpAuth::Target target) {
switch (target) {
case HttpAuth::AUTH_PROXY:
- return NetLog::TYPE_AUTH_PROXY;
+ return NetLogEventType::AUTH_PROXY;
case HttpAuth::AUTH_SERVER:
- return NetLog::TYPE_AUTH_SERVER;
+ return NetLogEventType::AUTH_SERVER;
default:
NOTREACHED();
- return NetLog::TYPE_CANCELLED;
+ return NetLogEventType::CANCELLED;
}
}
diff --git a/chromium/net/http/http_auth_handler.h b/chromium/net/http/http_auth_handler.h
index 4a6cb79e389..8d521b428b2 100644
--- a/chromium/net/http/http_auth_handler.h
+++ b/chromium/net/http/http_auth_handler.h
@@ -10,7 +10,7 @@
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
#include "net/http/http_auth.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
namespace net {
@@ -35,7 +35,7 @@ class NET_EXPORT_PRIVATE HttpAuthHandler {
HttpAuth::Target target,
const SSLInfo& ssl_info,
const GURL& origin,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Determines how the previous authorization attempt was received.
//
@@ -190,7 +190,7 @@ class NET_EXPORT_PRIVATE HttpAuthHandler {
// A bitmask of the properties of the authentication scheme.
int properties_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
private:
void OnGenerateAuthTokenComplete(int rv);
diff --git a/chromium/net/http/http_auth_handler_basic.cc b/chromium/net/http/http_auth_handler_basic.cc
index 276c128b125..f756f05fbc3 100644
--- a/chromium/net/http/http_auth_handler_basic.cc
+++ b/chromium/net/http/http_auth_handler_basic.cc
@@ -114,7 +114,7 @@ int HttpAuthHandlerBasic::Factory::CreateAuthHandler(
const GURL& origin,
CreateReason reason,
int digest_nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) {
// TODO(cbentzel): Move towards model of parsing in the factory
// method and only constructing when valid.
diff --git a/chromium/net/http/http_auth_handler_basic.h b/chromium/net/http/http_auth_handler_basic.h
index 98415f14b66..970e99f89c7 100644
--- a/chromium/net/http/http_auth_handler_basic.h
+++ b/chromium/net/http/http_auth_handler_basic.h
@@ -27,7 +27,7 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerBasic : public HttpAuthHandler {
const GURL& origin,
CreateReason reason,
int digest_nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) override;
};
diff --git a/chromium/net/http/http_auth_handler_basic_unittest.cc b/chromium/net/http/http_auth_handler_basic_unittest.cc
index 4b8c9ff5a99..be5c2e857b8 100644
--- a/chromium/net/http/http_auth_handler_basic_unittest.cc
+++ b/chromium/net/http/http_auth_handler_basic_unittest.cc
@@ -13,9 +13,14 @@
#include "net/base/test_completion_callback.h"
#include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/http_request_info.h"
+#include "net/log/net_log_with_source.h"
#include "net/ssl/ssl_info.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsOk;
+
namespace net {
TEST(HttpAuthHandlerBasicTest, GenerateAuthToken) {
@@ -40,7 +45,7 @@ TEST(HttpAuthHandlerBasicTest, GenerateAuthToken) {
std::unique_ptr<HttpAuthHandler> basic;
EXPECT_EQ(OK, factory.CreateAuthHandlerFromString(
challenge, HttpAuth::AUTH_SERVER, null_ssl_info, origin,
- BoundNetLog(), &basic));
+ NetLogWithSource(), &basic));
AuthCredentials credentials(base::ASCIIToUTF16(tests[i].username),
base::ASCIIToUTF16(tests[i].password));
HttpRequestInfo request_info;
@@ -48,7 +53,7 @@ TEST(HttpAuthHandlerBasicTest, GenerateAuthToken) {
TestCompletionCallback callback;
int rv = basic->GenerateAuthToken(&credentials, &request_info,
callback.callback(), &auth_token);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_STREQ(tests[i].expected_credentials, auth_token.c_str());
}
}
@@ -94,7 +99,7 @@ TEST(HttpAuthHandlerBasicTest, HandleAnotherChallenge) {
std::unique_ptr<HttpAuthHandler> basic;
EXPECT_EQ(OK, factory.CreateAuthHandlerFromString(
tests[0].challenge, HttpAuth::AUTH_SERVER, null_ssl_info,
- origin, BoundNetLog(), &basic));
+ origin, NetLogWithSource(), &basic));
for (size_t i = 0; i < arraysize(tests); ++i) {
std::string challenge(tests[i].challenge);
@@ -194,8 +199,8 @@ TEST(HttpAuthHandlerBasicTest, InitFromChallenge) {
SSLInfo null_ssl_info;
std::unique_ptr<HttpAuthHandler> basic;
int rv = factory.CreateAuthHandlerFromString(
- challenge, HttpAuth::AUTH_SERVER, null_ssl_info, origin, BoundNetLog(),
- &basic);
+ challenge, HttpAuth::AUTH_SERVER, null_ssl_info, origin,
+ NetLogWithSource(), &basic);
EXPECT_EQ(tests[i].expected_rv, rv);
if (rv == OK)
EXPECT_EQ(tests[i].expected_realm, basic->realm());
diff --git a/chromium/net/http/http_auth_handler_digest.cc b/chromium/net/http/http_auth_handler_digest.cc
index e4c8c16f0f0..39015ae7cd7 100644
--- a/chromium/net/http/http_auth_handler_digest.cc
+++ b/chromium/net/http/http_auth_handler_digest.cc
@@ -97,7 +97,7 @@ int HttpAuthHandlerDigest::Factory::CreateAuthHandler(
const GURL& origin,
CreateReason reason,
int digest_nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) {
// TODO(cbentzel): Move towards model of parsing in the factory
// method and only constructing when valid.
diff --git a/chromium/net/http/http_auth_handler_digest.h b/chromium/net/http/http_auth_handler_digest.h
index c5c172ab967..d196f2fe1f2 100644
--- a/chromium/net/http/http_auth_handler_digest.h
+++ b/chromium/net/http/http_auth_handler_digest.h
@@ -71,7 +71,7 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerDigest : public HttpAuthHandler {
const GURL& origin,
CreateReason reason,
int digest_nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) override;
private:
diff --git a/chromium/net/http/http_auth_handler_digest_unittest.cc b/chromium/net/http/http_auth_handler_digest_unittest.cc
index 3f7e44211a0..10b969068e0 100644
--- a/chromium/net/http/http_auth_handler_digest_unittest.cc
+++ b/chromium/net/http/http_auth_handler_digest_unittest.cc
@@ -11,9 +11,14 @@
#include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/http_auth_handler_digest.h"
#include "net/http/http_request_info.h"
+#include "net/log/net_log_with_source.h"
#include "net/ssl/ssl_info.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -56,8 +61,8 @@ bool RespondToChallenge(HttpAuth::Target target,
SSLInfo null_ssl_info;
GURL url_origin(target == HttpAuth::AUTH_SERVER ? request_url : proxy_name);
int rv_create = factory->CreateAuthHandlerFromString(
- challenge, target, null_ssl_info, url_origin.GetOrigin(), BoundNetLog(),
- &handler);
+ challenge, target, null_ssl_info, url_origin.GetOrigin(),
+ NetLogWithSource(), &handler);
if (rv_create != OK || handler.get() == NULL) {
ADD_FAILURE() << "Unable to create auth handler.";
return false;
@@ -358,9 +363,9 @@ TEST(HttpAuthHandlerDigestTest, ParseChallenge) {
std::unique_ptr<HttpAuthHandler> handler;
int rv = factory->CreateAuthHandlerFromString(
tests[i].challenge, HttpAuth::AUTH_SERVER, null_ssl_info, origin,
- BoundNetLog(), &handler);
+ NetLogWithSource(), &handler);
if (tests[i].parsed_success) {
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
} else {
EXPECT_NE(OK, rv);
EXPECT_TRUE(handler.get() == NULL);
@@ -522,8 +527,8 @@ TEST(HttpAuthHandlerDigestTest, AssembleCredentials) {
std::unique_ptr<HttpAuthHandler> handler;
int rv = factory->CreateAuthHandlerFromString(
tests[i].challenge, HttpAuth::AUTH_SERVER, null_ssl_info, origin,
- BoundNetLog(), &handler);
- EXPECT_EQ(OK, rv);
+ NetLogWithSource(), &handler);
+ EXPECT_THAT(rv, IsOk());
ASSERT_TRUE(handler != NULL);
HttpAuthHandlerDigest* digest =
@@ -551,8 +556,8 @@ TEST(HttpAuthHandlerDigest, HandleAnotherChallenge) {
SSLInfo null_ssl_info;
int rv = factory->CreateAuthHandlerFromString(
default_challenge, HttpAuth::AUTH_SERVER, null_ssl_info, origin,
- BoundNetLog(), &handler);
- EXPECT_EQ(OK, rv);
+ NetLogWithSource(), &handler);
+ EXPECT_THAT(rv, IsOk());
ASSERT_TRUE(handler.get() != NULL);
HttpAuthChallengeTokenizer tok_default(default_challenge.begin(),
default_challenge.end());
diff --git a/chromium/net/http/http_auth_handler_factory.cc b/chromium/net/http/http_auth_handler_factory.cc
index a30f7e62469..5a48aa222ab 100644
--- a/chromium/net/http/http_auth_handler_factory.cc
+++ b/chromium/net/http/http_auth_handler_factory.cc
@@ -28,7 +28,7 @@ int HttpAuthHandlerFactory::CreateAuthHandlerFromString(
HttpAuth::Target target,
const SSLInfo& ssl_info,
const GURL& origin,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) {
HttpAuthChallengeTokenizer props(challenge.begin(), challenge.end());
return CreateAuthHandler(&props, target, ssl_info, origin, CREATE_CHALLENGE,
@@ -40,7 +40,7 @@ int HttpAuthHandlerFactory::CreatePreemptiveAuthHandlerFromString(
HttpAuth::Target target,
const GURL& origin,
int digest_nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) {
HttpAuthChallengeTokenizer props(challenge.begin(), challenge.end());
SSLInfo null_ssl_info;
@@ -86,10 +86,10 @@ CreateAuthHandlerRegistryFactory(const HttpAuthPreferences& prefs,
HttpAuthHandlerNegotiate::Factory* negotiate_factory =
new HttpAuthHandlerNegotiate::Factory();
#if defined(OS_WIN)
- negotiate_factory->set_library(base::WrapUnique(new SSPILibraryDefault()));
+ negotiate_factory->set_library(base::MakeUnique<SSPILibraryDefault>());
#elif defined(OS_POSIX) && !defined(OS_ANDROID)
negotiate_factory->set_library(
- base::WrapUnique(new GSSAPISharedLibrary(prefs.GssapiLibraryName())));
+ base::MakeUnique<GSSAPISharedLibrary>(prefs.GssapiLibraryName()));
#endif // defined(OS_POSIX) && !defined(OS_ANDROID)
negotiate_factory->set_host_resolver(host_resolver);
registry_factory->RegisterSchemeFactory(kNegotiateAuthScheme,
@@ -170,7 +170,7 @@ int HttpAuthHandlerRegistryFactory::CreateAuthHandler(
const GURL& origin,
CreateReason reason,
int digest_nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) {
std::string scheme = challenge->scheme();
if (scheme.empty()) {
diff --git a/chromium/net/http/http_auth_handler_factory.h b/chromium/net/http/http_auth_handler_factory.h
index f17adc57874..df0cfcfdfb1 100644
--- a/chromium/net/http/http_auth_handler_factory.h
+++ b/chromium/net/http/http_auth_handler_factory.h
@@ -19,12 +19,12 @@ class GURL;
namespace net {
-class BoundNetLog;
-class HttpAuthPreferences;
class HostResolver;
class HttpAuthChallengeTokenizer;
class HttpAuthHandler;
class HttpAuthHandlerRegistryFactory;
+class HttpAuthPreferences;
+class NetLogWithSource;
// An HttpAuthHandlerFactory is used to create HttpAuthHandler objects.
// The HttpAuthHandlerFactory object _must_ outlive any of the HttpAuthHandler
@@ -88,7 +88,7 @@ class NET_EXPORT HttpAuthHandlerFactory {
const GURL& origin,
CreateReason create_reason,
int digest_nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) = 0;
// Creates an HTTP authentication handler based on the authentication
@@ -100,7 +100,7 @@ class NET_EXPORT HttpAuthHandlerFactory {
HttpAuth::Target target,
const SSLInfo& ssl_info,
const GURL& origin,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler);
// Creates an HTTP authentication handler based on the authentication
@@ -113,7 +113,7 @@ class NET_EXPORT HttpAuthHandlerFactory {
HttpAuth::Target target,
const GURL& origin,
int digest_nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler);
// Creates a standard HttpAuthHandlerRegistryFactory. The caller is
@@ -186,7 +186,7 @@ class NET_EXPORT HttpAuthHandlerRegistryFactory
const GURL& origin,
CreateReason reason,
int digest_nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) override;
private:
diff --git a/chromium/net/http/http_auth_handler_factory_unittest.cc b/chromium/net/http/http_auth_handler_factory_unittest.cc
index 6ed7c2fc9c9..1995e60df98 100644
--- a/chromium/net/http/http_auth_handler_factory_unittest.cc
+++ b/chromium/net/http/http_auth_handler_factory_unittest.cc
@@ -12,9 +12,15 @@
#include "net/http/http_auth_scheme.h"
#include "net/http/mock_allow_http_auth_preferences.h"
#include "net/http/url_security_manager.h"
+#include "net/log/net_log_with_source.h"
#include "net/ssl/ssl_info.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -31,7 +37,7 @@ class MockHttpAuthHandlerFactory : public HttpAuthHandlerFactory {
const GURL& origin,
CreateReason reason,
int nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) override {
handler->reset();
return return_code_;
@@ -65,42 +71,42 @@ TEST(HttpAuthHandlerFactoryTest, RegistryFactory) {
EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME,
registry_factory.CreateAuthHandlerFromString(
"Basic", HttpAuth::AUTH_SERVER, null_ssl_info, gurl,
- BoundNetLog(), &handler));
+ NetLogWithSource(), &handler));
// Test what happens with a single scheme.
registry_factory.RegisterSchemeFactory("Basic", mock_factory_basic);
EXPECT_EQ(kBasicReturnCode, registry_factory.CreateAuthHandlerFromString(
"Basic", HttpAuth::AUTH_SERVER, null_ssl_info,
- gurl, BoundNetLog(), &handler));
+ gurl, NetLogWithSource(), &handler));
EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME,
registry_factory.CreateAuthHandlerFromString(
"Digest", HttpAuth::AUTH_SERVER, null_ssl_info, gurl,
- BoundNetLog(), &handler));
+ NetLogWithSource(), &handler));
// Test multiple schemes
registry_factory.RegisterSchemeFactory("Digest", mock_factory_digest);
EXPECT_EQ(kBasicReturnCode, registry_factory.CreateAuthHandlerFromString(
"Basic", HttpAuth::AUTH_SERVER, null_ssl_info,
- gurl, BoundNetLog(), &handler));
+ gurl, NetLogWithSource(), &handler));
EXPECT_EQ(kDigestReturnCode,
registry_factory.CreateAuthHandlerFromString(
"Digest", HttpAuth::AUTH_SERVER, null_ssl_info, gurl,
- BoundNetLog(), &handler));
+ NetLogWithSource(), &handler));
// Test case-insensitivity
EXPECT_EQ(kBasicReturnCode, registry_factory.CreateAuthHandlerFromString(
"basic", HttpAuth::AUTH_SERVER, null_ssl_info,
- gurl, BoundNetLog(), &handler));
+ gurl, NetLogWithSource(), &handler));
// Test replacement of existing auth scheme
registry_factory.RegisterSchemeFactory("Digest", mock_factory_digest_replace);
EXPECT_EQ(kBasicReturnCode, registry_factory.CreateAuthHandlerFromString(
"Basic", HttpAuth::AUTH_SERVER, null_ssl_info,
- gurl, BoundNetLog(), &handler));
+ gurl, NetLogWithSource(), &handler));
EXPECT_EQ(kDigestReturnCodeReplace,
registry_factory.CreateAuthHandlerFromString(
"Digest", HttpAuth::AUTH_SERVER, null_ssl_info, gurl,
- BoundNetLog(), &handler));
+ NetLogWithSource(), &handler));
}
TEST(HttpAuthHandlerFactoryTest, DefaultFactory) {
@@ -117,8 +123,8 @@ TEST(HttpAuthHandlerFactoryTest, DefaultFactory) {
std::unique_ptr<HttpAuthHandler> handler;
int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
"Basic realm=\"FooBar\"", HttpAuth::AUTH_SERVER, null_ssl_info,
- server_origin, BoundNetLog(), &handler);
- EXPECT_EQ(OK, rv);
+ server_origin, NetLogWithSource(), &handler);
+ EXPECT_THAT(rv, IsOk());
ASSERT_FALSE(handler.get() == NULL);
EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, handler->auth_scheme());
EXPECT_STREQ("FooBar", handler->realm().c_str());
@@ -130,16 +136,16 @@ TEST(HttpAuthHandlerFactoryTest, DefaultFactory) {
std::unique_ptr<HttpAuthHandler> handler;
int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
"UNSUPPORTED realm=\"FooBar\"", HttpAuth::AUTH_SERVER, null_ssl_info,
- server_origin, BoundNetLog(), &handler);
- EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, rv);
+ server_origin, NetLogWithSource(), &handler);
+ EXPECT_THAT(rv, IsError(ERR_UNSUPPORTED_AUTH_SCHEME));
EXPECT_TRUE(handler.get() == NULL);
}
{
std::unique_ptr<HttpAuthHandler> handler;
int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
"Digest realm=\"FooBar\", nonce=\"xyz\"", HttpAuth::AUTH_PROXY,
- null_ssl_info, proxy_origin, BoundNetLog(), &handler);
- EXPECT_EQ(OK, rv);
+ null_ssl_info, proxy_origin, NetLogWithSource(), &handler);
+ EXPECT_THAT(rv, IsOk());
ASSERT_FALSE(handler.get() == NULL);
EXPECT_EQ(HttpAuth::AUTH_SCHEME_DIGEST, handler->auth_scheme());
EXPECT_STREQ("FooBar", handler->realm().c_str());
@@ -151,8 +157,8 @@ TEST(HttpAuthHandlerFactoryTest, DefaultFactory) {
std::unique_ptr<HttpAuthHandler> handler;
int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
"NTLM", HttpAuth::AUTH_SERVER, null_ssl_info, server_origin,
- BoundNetLog(), &handler);
- EXPECT_EQ(OK, rv);
+ NetLogWithSource(), &handler);
+ EXPECT_THAT(rv, IsOk());
ASSERT_FALSE(handler.get() == NULL);
EXPECT_EQ(HttpAuth::AUTH_SCHEME_NTLM, handler->auth_scheme());
EXPECT_STREQ("", handler->realm().c_str());
@@ -164,10 +170,10 @@ TEST(HttpAuthHandlerFactoryTest, DefaultFactory) {
std::unique_ptr<HttpAuthHandler> handler;
int rv = http_auth_handler_factory->CreateAuthHandlerFromString(
"Negotiate", HttpAuth::AUTH_SERVER, null_ssl_info, server_origin,
- BoundNetLog(), &handler);
+ NetLogWithSource(), &handler);
// Note the default factory doesn't support Kerberos on Android
#if defined(USE_KERBEROS) && !defined(OS_ANDROID)
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
ASSERT_FALSE(handler.get() == NULL);
EXPECT_EQ(HttpAuth::AUTH_SCHEME_NEGOTIATE, handler->auth_scheme());
EXPECT_STREQ("", handler->realm().c_str());
@@ -175,7 +181,7 @@ TEST(HttpAuthHandlerFactoryTest, DefaultFactory) {
EXPECT_TRUE(handler->encrypts_identity());
EXPECT_TRUE(handler->is_connection_based());
#else
- EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, rv);
+ EXPECT_THAT(rv, IsError(ERR_UNSUPPORTED_AUTH_SCHEME));
EXPECT_TRUE(handler.get() == NULL);
#endif // defined(USE_KERBEROS) && !defined(OS_ANDROID)
}
diff --git a/chromium/net/http/http_auth_handler_mock.cc b/chromium/net/http/http_auth_handler_mock.cc
index 073e71c3aae..061f99bb595 100644
--- a/chromium/net/http/http_auth_handler_mock.cc
+++ b/chromium/net/http/http_auth_handler_mock.cc
@@ -13,22 +13,43 @@
#include "net/base/net_errors.h"
#include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/http_request_info.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
-HttpAuthHandlerMock::HttpAuthHandlerMock()
- : resolve_(RESOLVE_INIT),
- generate_async_(false),
- generate_rv_(OK),
- auth_token_(NULL),
- first_round_(true),
- connection_based_(false),
- allows_default_credentials_(false),
- allows_explicit_credentials_(true),
- weak_factory_(this) {
+void PrintTo(const HttpAuthHandlerMock::State& state, ::std::ostream* os) {
+ switch (state) {
+ case HttpAuthHandlerMock::State::WAIT_FOR_INIT:
+ *os << "WAIT_FOR_INIT";
+ break;
+ case HttpAuthHandlerMock::State::WAIT_FOR_CHALLENGE:
+ *os << "WAIT_FOR_CHALLENGE";
+ break;
+ case HttpAuthHandlerMock::State::WAIT_FOR_GENERATE_AUTH_TOKEN:
+ *os << "WAIT_FOR_GENERATE_AUTH_TOKEN";
+ break;
+ case HttpAuthHandlerMock::State::TOKEN_PENDING:
+ *os << "TOKEN_PENDING";
+ break;
+ case HttpAuthHandlerMock::State::DONE:
+ *os << "DONE";
+ break;
+ }
}
+HttpAuthHandlerMock::HttpAuthHandlerMock()
+ : state_(State::WAIT_FOR_INIT),
+ resolve_(RESOLVE_INIT),
+ generate_async_(false),
+ generate_rv_(OK),
+ auth_token_(NULL),
+ first_round_(true),
+ connection_based_(false),
+ allows_default_credentials_(false),
+ allows_explicit_credentials_(true),
+ weak_factory_(this) {}
+
HttpAuthHandlerMock::~HttpAuthHandlerMock() {
}
@@ -81,12 +102,21 @@ void HttpAuthHandlerMock::SetGenerateExpectation(bool async, int rv) {
HttpAuth::AuthorizationResult HttpAuthHandlerMock::HandleAnotherChallenge(
HttpAuthChallengeTokenizer* challenge) {
+ EXPECT_THAT(state_, ::testing::AnyOf(State::WAIT_FOR_CHALLENGE,
+ State::WAIT_FOR_GENERATE_AUTH_TOKEN));
// If we receive an empty challenge for a connection based scheme, or a second
// challenge for a non connection based scheme, assume it's a rejection.
- if (!is_connection_based() || challenge->base64_param().empty())
+ if (!is_connection_based() || challenge->base64_param().empty()) {
+ state_ = State::DONE;
return HttpAuth::AUTHORIZATION_RESULT_REJECT;
- if (!base::LowerCaseEqualsASCII(challenge->scheme(), "mock"))
+ }
+
+ if (!base::LowerCaseEqualsASCII(challenge->scheme(), "mock")) {
+ state_ = State::DONE;
return HttpAuth::AUTHORIZATION_RESULT_INVALID;
+ }
+
+ state_ = State::WAIT_FOR_GENERATE_AUTH_TOKEN;
return HttpAuth::AUTHORIZATION_RESULT_ACCEPT;
}
@@ -104,6 +134,8 @@ bool HttpAuthHandlerMock::AllowsExplicitCredentials() {
bool HttpAuthHandlerMock::Init(HttpAuthChallengeTokenizer* challenge,
const SSLInfo& ssl_info) {
+ EXPECT_EQ(State::WAIT_FOR_INIT, state_);
+ state_ = State::WAIT_FOR_GENERATE_AUTH_TOKEN;
auth_scheme_ = HttpAuth::AUTH_SCHEME_MOCK;
score_ = 1;
properties_ = connection_based_ ? IS_CONNECTION_BASED : 0;
@@ -115,6 +147,7 @@ int HttpAuthHandlerMock::GenerateAuthTokenImpl(
const HttpRequestInfo* request,
const CompletionCallback& callback,
std::string* auth_token) {
+ EXPECT_EQ(State::WAIT_FOR_GENERATE_AUTH_TOKEN, state_);
first_round_ = false;
request_url_ = request->url;
if (generate_async_) {
@@ -125,10 +158,16 @@ int HttpAuthHandlerMock::GenerateAuthTokenImpl(
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&HttpAuthHandlerMock::OnGenerateAuthToken,
weak_factory_.GetWeakPtr()));
+ state_ = State::TOKEN_PENDING;
return ERR_IO_PENDING;
} else {
- if (generate_rv_ == OK)
+ if (generate_rv_ == OK) {
*auth_token = "auth_token";
+ state_ = is_connection_based() ? State::WAIT_FOR_CHALLENGE
+ : State::WAIT_FOR_GENERATE_AUTH_TOKEN;
+ } else {
+ state_ = State::DONE;
+ }
return generate_rv_;
}
}
@@ -145,8 +184,14 @@ void HttpAuthHandlerMock::OnResolveCanonicalName() {
void HttpAuthHandlerMock::OnGenerateAuthToken() {
EXPECT_TRUE(generate_async_);
EXPECT_TRUE(!callback_.is_null());
- if (generate_rv_ == OK)
+ EXPECT_EQ(State::TOKEN_PENDING, state_);
+ if (generate_rv_ == OK) {
*auth_token_ = "auth_token";
+ state_ = is_connection_based() ? State::WAIT_FOR_CHALLENGE
+ : State::WAIT_FOR_GENERATE_AUTH_TOKEN;
+ } else {
+ state_ = State::DONE;
+ }
auth_token_ = NULL;
CompletionCallback callback = callback_;
callback_.Reset();
@@ -173,7 +218,7 @@ int HttpAuthHandlerMock::Factory::CreateAuthHandler(
const GURL& origin,
CreateReason reason,
int nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) {
if (handlers_[target].empty())
return ERR_UNEXPECTED;
diff --git a/chromium/net/http/http_auth_handler_mock.h b/chromium/net/http/http_auth_handler_mock.h
index 06546af012e..6a1e58e8f2e 100644
--- a/chromium/net/http/http_auth_handler_mock.h
+++ b/chromium/net/http/http_auth_handler_mock.h
@@ -6,6 +6,7 @@
#define NET_HTTP_HTTP_AUTH_HANDLER_MOCK_H_
#include <memory>
+#include <ostream>
#include <string>
#include <vector>
@@ -21,6 +22,14 @@ class HostResolver;
// MockAuthHandler is used in tests to reliably trigger edge cases.
class HttpAuthHandlerMock : public HttpAuthHandler {
public:
+ enum class State {
+ WAIT_FOR_INIT,
+ WAIT_FOR_CHALLENGE,
+ WAIT_FOR_GENERATE_AUTH_TOKEN,
+ TOKEN_PENDING,
+ DONE
+ };
+
enum Resolve {
RESOLVE_INIT,
RESOLVE_SKIP,
@@ -49,7 +58,7 @@ class HttpAuthHandlerMock : public HttpAuthHandler {
const GURL& origin,
CreateReason reason,
int nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) override;
private:
@@ -88,6 +97,8 @@ class HttpAuthHandlerMock : public HttpAuthHandler {
return request_url_;
}
+ State state() const { return state_; }
+
// HttpAuthHandler:
HttpAuth::AuthorizationResult HandleAnotherChallenge(
HttpAuthChallengeTokenizer* challenge) override;
@@ -109,6 +120,7 @@ class HttpAuthHandlerMock : public HttpAuthHandler {
void OnGenerateAuthToken();
+ State state_;
Resolve resolve_;
CompletionCallback callback_;
bool generate_async_;
@@ -122,6 +134,8 @@ class HttpAuthHandlerMock : public HttpAuthHandler {
base::WeakPtrFactory<HttpAuthHandlerMock> weak_factory_;
};
+void PrintTo(const HttpAuthHandlerMock::State& state, ::std::ostream* os);
+
} // namespace net
#endif // NET_HTTP_HTTP_AUTH_HANDLER_MOCK_H_
diff --git a/chromium/net/http/http_auth_handler_negotiate.cc b/chromium/net/http/http_auth_handler_negotiate.cc
index ca1cddce9f8..e957676fc40 100644
--- a/chromium/net/http/http_auth_handler_negotiate.cc
+++ b/chromium/net/http/http_auth_handler_negotiate.cc
@@ -15,10 +15,11 @@
#include "net/base/net_errors.h"
#include "net/cert/x509_util.h"
#include "net/dns/host_resolver.h"
-#include "net/dns/single_request_host_resolver.h"
#include "net/http/http_auth_filter.h"
#include "net/http/http_auth_preferences.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/ssl/ssl_info.h"
namespace net {
@@ -41,7 +42,7 @@ std::unique_ptr<base::Value> NetLogParameterChannelBindings(
} // namespace
HttpAuthHandlerNegotiate::Factory::Factory()
- : resolver_(NULL),
+ : resolver_(nullptr),
#if defined(OS_WIN)
max_token_length_(0),
#endif
@@ -63,7 +64,7 @@ int HttpAuthHandlerNegotiate::Factory::CreateAuthHandler(
const GURL& origin,
CreateReason reason,
int digest_nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) {
#if defined(OS_WIN)
if (is_unsupported_ || reason == CREATE_PREEMPTIVE)
@@ -241,7 +242,7 @@ bool HttpAuthHandlerNegotiate::Init(HttpAuthChallengeTokenizer* challenge,
&channel_bindings_);
if (!channel_bindings_.empty())
net_log_.AddEvent(
- NetLog::TYPE_AUTH_CHANNEL_BINDINGS,
+ NetLogEventType::AUTH_CHANNEL_BINDINGS,
base::Bind(&NetLogParameterChannelBindings, channel_bindings_));
return true;
}
@@ -324,17 +325,12 @@ int HttpAuthHandlerNegotiate::DoResolveCanonicalName() {
return OK;
// TODO(cbentzel): Add reverse DNS lookup for numeric addresses.
- DCHECK(!single_resolve_.get());
HostResolver::RequestInfo info(HostPortPair(origin_.host(), 0));
info.set_host_resolver_flags(HOST_RESOLVER_CANONNAME);
- single_resolve_.reset(new SingleRequestHostResolver(resolver_));
- return single_resolve_->Resolve(
- info,
- DEFAULT_PRIORITY,
- &address_list_,
- base::Bind(&HttpAuthHandlerNegotiate::OnIOComplete,
- base::Unretained(this)),
- net_log_);
+ return resolver_->Resolve(info, DEFAULT_PRIORITY, &address_list_,
+ base::Bind(&HttpAuthHandlerNegotiate::OnIOComplete,
+ base::Unretained(this)),
+ &request_, net_log_);
}
int HttpAuthHandlerNegotiate::DoResolveCanonicalNameComplete(int rv) {
diff --git a/chromium/net/http/http_auth_handler_negotiate.h b/chromium/net/http/http_auth_handler_negotiate.h
index 0f9154e1246..17c7d51885e 100644
--- a/chromium/net/http/http_auth_handler_negotiate.h
+++ b/chromium/net/http/http_auth_handler_negotiate.h
@@ -11,6 +11,7 @@
#include "build/build_config.h"
#include "net/base/address_list.h"
#include "net/base/net_export.h"
+#include "net/dns/host_resolver.h"
#include "net/http/http_auth_handler.h"
#include "net/http/http_auth_handler_factory.h"
@@ -25,8 +26,6 @@
namespace net {
class HttpAuthPreferences;
-class HostResolver;
-class SingleRequestHostResolver;
// Handler for WWW-Authenticate: Negotiate protocol.
//
@@ -67,7 +66,7 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerNegotiate : public HttpAuthHandler {
const GURL& origin,
CreateReason reason,
int digest_nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) override;
private:
@@ -137,7 +136,7 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerNegotiate : public HttpAuthHandler {
// Members which are needed for DNS lookup + SPN.
AddressList address_list_;
- std::unique_ptr<SingleRequestHostResolver> single_resolve_;
+ std::unique_ptr<net::HostResolver::Request> request_;
// Things which should be consistent after first call to GenerateAuthToken.
bool already_called_;
diff --git a/chromium/net/http/http_auth_handler_negotiate_unittest.cc b/chromium/net/http/http_auth_handler_negotiate_unittest.cc
index 775a5b4606b..7471ed158ab 100644
--- a/chromium/net/http/http_auth_handler_negotiate_unittest.cc
+++ b/chromium/net/http/http_auth_handler_negotiate_unittest.cc
@@ -14,7 +14,10 @@
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_request_info.h"
#include "net/http/mock_allow_http_auth_preferences.h"
+#include "net/log/net_log_with_source.h"
#include "net/ssl/ssl_info.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -26,6 +29,9 @@
#include "net/http/mock_gssapi_library_posix.h"
#endif
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
#if defined(OS_ANDROID)
@@ -211,8 +217,8 @@ class HttpAuthHandlerNegotiateTest : public PlatformTest {
std::unique_ptr<HttpAuthHandler> generic_handler;
SSLInfo null_ssl_info;
int rv = factory_->CreateAuthHandlerFromString(
- "Negotiate", HttpAuth::AUTH_SERVER, null_ssl_info, gurl, BoundNetLog(),
- &generic_handler);
+ "Negotiate", HttpAuth::AUTH_SERVER, null_ssl_info, gurl,
+ NetLogWithSource(), &generic_handler);
if (rv != OK)
return rv;
HttpAuthHandlerNegotiate* negotiate_handler =
@@ -320,7 +326,7 @@ TEST_F(HttpAuthHandlerNegotiateTest, CnameAsync) {
std::string token;
EXPECT_EQ(ERR_IO_PENDING, auth_handler->GenerateAuthToken(
NULL, &request_info, callback.callback(), &token));
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
#if defined(OS_WIN)
EXPECT_EQ("HTTP/canonical.example.com", auth_handler->spn());
#elif defined(OS_POSIX)
@@ -343,7 +349,7 @@ TEST_F(HttpAuthHandlerNegotiateTest, ServerNotInKerberosDatabase) {
std::string token;
EXPECT_EQ(ERR_IO_PENDING, auth_handler->GenerateAuthToken(
NULL, &request_info, callback.callback(), &token));
- EXPECT_EQ(ERR_MISSING_AUTH_CREDENTIALS, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_MISSING_AUTH_CREDENTIALS));
}
// This test is only for GSSAPI, as we can't use explicit credentials with
@@ -359,7 +365,7 @@ TEST_F(HttpAuthHandlerNegotiateTest, NoKerberosCredentials) {
std::string token;
EXPECT_EQ(ERR_IO_PENDING, auth_handler->GenerateAuthToken(
NULL, &request_info, callback.callback(), &token));
- EXPECT_EQ(ERR_MISSING_AUTH_CREDENTIALS, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_MISSING_AUTH_CREDENTIALS));
}
#if defined(DLOPEN_KERBEROS)
@@ -370,18 +376,15 @@ TEST_F(HttpAuthHandlerNegotiateTest, MissingGSSAPI) {
new HttpAuthHandlerNegotiate::Factory());
negotiate_factory->set_host_resolver(host_resolver);
negotiate_factory->set_http_auth_preferences(&http_auth_preferences);
- negotiate_factory->set_library(base::WrapUnique(
- new GSSAPISharedLibrary("/this/library/does/not/exist")));
+ negotiate_factory->set_library(
+ base::MakeUnique<GSSAPISharedLibrary>("/this/library/does/not/exist"));
GURL gurl("http://www.example.com");
std::unique_ptr<HttpAuthHandler> generic_handler;
int rv = negotiate_factory->CreateAuthHandlerFromString(
- "Negotiate",
- HttpAuth::AUTH_SERVER,
- gurl,
- BoundNetLog(),
+ "Negotiate", HttpAuth::AUTH_SERVER, gurl, NetLogWithSource(),
&generic_handler);
- EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, rv);
+ EXPECT_THAT(rv, IsError(ERR_UNSUPPORTED_AUTH_SCHEME));
EXPECT_TRUE(generic_handler.get() == NULL);
}
#endif // defined(DLOPEN_KERBEROS)
diff --git a/chromium/net/http/http_auth_handler_ntlm.h b/chromium/net/http/http_auth_handler_ntlm.h
index d1d2314f8c0..fed6303f834 100644
--- a/chromium/net/http/http_auth_handler_ntlm.h
+++ b/chromium/net/http/http_auth_handler_ntlm.h
@@ -28,6 +28,7 @@
#include <string>
#include "base/strings/string16.h"
+#include "net/base/net_export.h"
#include "net/http/http_auth_handler.h"
#include "net/http/http_auth_handler_factory.h"
@@ -49,7 +50,7 @@ class NET_EXPORT_PRIVATE HttpAuthHandlerNTLM : public HttpAuthHandler {
const GURL& origin,
CreateReason reason,
int digest_nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) override;
#if defined(NTLM_SSPI)
// Set the SSPILibrary to use. Typically the only callers which need to use
diff --git a/chromium/net/http/http_auth_handler_ntlm_portable.cc b/chromium/net/http/http_auth_handler_ntlm_portable.cc
index 5c4e0100fe0..487e89cc8ee 100644
--- a/chromium/net/http/http_auth_handler_ntlm_portable.cc
+++ b/chromium/net/http/http_auth_handler_ntlm_portable.cc
@@ -718,7 +718,7 @@ int HttpAuthHandlerNTLM::Factory::CreateAuthHandler(
const GURL& origin,
CreateReason reason,
int digest_nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) {
if (reason == CREATE_PREEMPTIVE)
return ERR_UNSUPPORTED_AUTH_SCHEME;
diff --git a/chromium/net/http/http_auth_handler_ntlm_win.cc b/chromium/net/http/http_auth_handler_ntlm_win.cc
index c069f736c3d..70f8d317bfe 100644
--- a/chromium/net/http/http_auth_handler_ntlm_win.cc
+++ b/chromium/net/http/http_auth_handler_ntlm_win.cc
@@ -54,7 +54,7 @@ int HttpAuthHandlerNTLM::Factory::CreateAuthHandler(
const GURL& origin,
CreateReason reason,
int digest_nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) {
if (is_unsupported_ || reason == CREATE_PREEMPTIVE)
return ERR_UNSUPPORTED_AUTH_SCHEME;
diff --git a/chromium/net/http/http_auth_handler_unittest.cc b/chromium/net/http/http_auth_handler_unittest.cc
index 1bb384ff1cd..b684cb2dba8 100644
--- a/chromium/net/http/http_auth_handler_unittest.cc
+++ b/chromium/net/http/http_auth_handler_unittest.cc
@@ -11,6 +11,8 @@
#include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/http_auth_handler_mock.h"
#include "net/http/http_request_info.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source_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"
@@ -35,18 +37,18 @@ TEST(HttpAuthHandlerTest, NetLog) {
TestCompletionCallback test_callback;
HttpAuth::Target target =
(k == 0) ? HttpAuth::AUTH_PROXY : HttpAuth::AUTH_SERVER;
- NetLog::EventType event_type =
- (k == 0) ? NetLog::TYPE_AUTH_PROXY : NetLog::TYPE_AUTH_SERVER;
+ NetLogEventType event_type = (k == 0) ? NetLogEventType::AUTH_PROXY
+ : NetLogEventType::AUTH_SERVER;
HttpAuthChallengeTokenizer tokenizer(
challenge.begin(), challenge.end());
HttpAuthHandlerMock mock_handler;
TestNetLog test_net_log;
- BoundNetLog bound_net_log(
- BoundNetLog::Make(&test_net_log, NetLog::SOURCE_NONE));
+ NetLogWithSource net_log(
+ NetLogWithSource::Make(&test_net_log, NetLogSourceType::NONE));
SSLInfo empty_ssl_info;
mock_handler.InitFromChallenge(&tokenizer, target, empty_ssl_info,
- origin, bound_net_log);
+ origin, net_log);
mock_handler.SetGenerateExpectation(async, rv);
mock_handler.GenerateAuthToken(&credentials, &request,
test_callback.callback(), &auth_token);
diff --git a/chromium/net/http/http_auth_scheme.cc b/chromium/net/http/http_auth_scheme.cc
index 75debb310c9..4adfc7465ca 100644
--- a/chromium/net/http/http_auth_scheme.cc
+++ b/chromium/net/http/http_auth_scheme.cc
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/base/net_export.h"
#include "net/http/http_auth_scheme.h"
namespace net {
diff --git a/chromium/net/http/http_auth_scheme.h b/chromium/net/http/http_auth_scheme.h
index 98e17857a99..fc74da99a4f 100644
--- a/chromium/net/http/http_auth_scheme.h
+++ b/chromium/net/http/http_auth_scheme.h
@@ -5,6 +5,8 @@
#ifndef NET_HTTP_HTTP_AUTH_SCHEME_H_
#define NET_HTTP_HTTP_AUTH_SCHEME_H_
+#include "net/base/net_export.h"
+
namespace net {
NET_EXPORT extern const char kBasicAuthScheme[];
NET_EXPORT extern const char kDigestAuthScheme[];
diff --git a/chromium/net/http/http_auth_sspi_win_unittest.cc b/chromium/net/http/http_auth_sspi_win_unittest.cc
index c2841732283..c9d6cfc54c8 100644
--- a/chromium/net/http/http_auth_sspi_win_unittest.cc
+++ b/chromium/net/http/http_auth_sspi_win_unittest.cc
@@ -6,8 +6,13 @@
#include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/http_auth_sspi_win.h"
#include "net/http/mock_sspi_library_win.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -46,7 +51,7 @@ TEST(HttpAuthSSPITest, DetermineMaxTokenLength_Normal) {
mock_library.ExpectQuerySecurityPackageInfo(L"NTLM", SEC_E_OK, &package_info);
ULONG max_token_length = kMaxTokenLength;
int rv = DetermineMaxTokenLength(&mock_library, L"NTLM", &max_token_length);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ(1337u, max_token_length);
}
@@ -56,7 +61,7 @@ TEST(HttpAuthSSPITest, DetermineMaxTokenLength_InvalidPackage) {
NULL);
ULONG max_token_length = kMaxTokenLength;
int rv = DetermineMaxTokenLength(&mock_library, L"Foo", &max_token_length);
- EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME, rv);
+ EXPECT_THAT(rv, IsError(ERR_UNSUPPORTED_AUTH_SCHEME));
// |DetermineMaxTokenLength()| interface states that |max_token_length| should
// not change on failure.
EXPECT_EQ(100u, max_token_length);
diff --git a/chromium/net/http/http_auth_unittest.cc b/chromium/net/http/http_auth_unittest.cc
index ca9410fb4a4..b6a24af2ad2 100644
--- a/chromium/net/http/http_auth_unittest.cc
+++ b/chromium/net/http/http_auth_unittest.cc
@@ -21,6 +21,7 @@
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/http/mock_allow_http_auth_preferences.h"
+#include "net/log/net_log_with_source.h"
#include "net/ssl/ssl_info.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -36,8 +37,9 @@ HttpAuthHandlerMock* CreateMockHandler(bool connection_based) {
challenge_text.end());
GURL origin("www.example.com");
SSLInfo null_ssl_info;
- EXPECT_TRUE(auth_handler->InitFromChallenge(
- &challenge, HttpAuth::AUTH_SERVER, null_ssl_info, origin, BoundNetLog()));
+ EXPECT_TRUE(auth_handler->InitFromChallenge(&challenge, HttpAuth::AUTH_SERVER,
+ null_ssl_info, origin,
+ NetLogWithSource()));
return auth_handler;
}
@@ -138,7 +140,8 @@ TEST(HttpAuthTest, ChooseBestChallenge) {
std::unique_ptr<HttpAuthHandler> handler;
HttpAuth::ChooseBestChallenge(http_auth_handler_factory.get(), *headers,
null_ssl_info, HttpAuth::AUTH_SERVER, origin,
- disabled_schemes, BoundNetLog(), &handler);
+ disabled_schemes, NetLogWithSource(),
+ &handler);
if (handler.get()) {
EXPECT_EQ(tests[i].challenge_scheme, handler->auth_scheme());
diff --git a/chromium/net/http/http_basic_state.cc b/chromium/net/http/http_basic_state.cc
index 2e5ca06ebe8..3e7b63e5679 100644
--- a/chromium/net/http/http_basic_state.cc
+++ b/chromium/net/http/http_basic_state.cc
@@ -17,22 +17,28 @@
namespace net {
-HttpBasicState::HttpBasicState(ClientSocketHandle* connection, bool using_proxy)
+HttpBasicState::HttpBasicState(std::unique_ptr<ClientSocketHandle> connection,
+ bool using_proxy,
+ bool http_09_on_non_default_ports_enabled)
: read_buf_(new GrowableIOBuffer()),
- connection_(connection),
+ connection_(std::move(connection)),
using_proxy_(using_proxy),
- request_info_(NULL) {}
+ http_09_on_non_default_ports_enabled_(
+ http_09_on_non_default_ports_enabled),
+ request_info_(nullptr) {}
HttpBasicState::~HttpBasicState() {}
int HttpBasicState::Initialize(const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback) {
DCHECK(!parser_.get());
request_info_ = request_info;
parser_.reset(new HttpStreamParser(
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_);
return OK;
}
diff --git a/chromium/net/http/http_basic_state.h b/chromium/net/http/http_basic_state.h
index b21548040f9..ac8ac376462 100644
--- a/chromium/net/http/http_basic_state.h
+++ b/chromium/net/http/http_basic_state.h
@@ -19,27 +19,33 @@
namespace net {
-class BoundNetLog;
class ClientSocketHandle;
class GrowableIOBuffer;
class HttpStreamParser;
struct HttpRequestInfo;
+class NetLogWithSource;
class NET_EXPORT_PRIVATE HttpBasicState {
public:
- HttpBasicState(ClientSocketHandle* connection, bool using_proxy);
+ HttpBasicState(std::unique_ptr<ClientSocketHandle> connection,
+ bool using_proxy,
+ bool http_09_on_non_default_ports_enabled);
~HttpBasicState();
// Initialize() must be called before using any of the other methods.
int Initialize(const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback);
HttpStreamParser* parser() const { return parser_.get(); }
bool using_proxy() const { return using_proxy_; }
+ bool http_09_on_non_default_ports_enabled() const {
+ return http_09_on_non_default_ports_enabled_;
+ }
+
// Deletes |parser_| and sets it to NULL.
void DeleteParser();
@@ -62,6 +68,8 @@ class NET_EXPORT_PRIVATE HttpBasicState {
const bool using_proxy_;
+ const bool http_09_on_non_default_ports_enabled_;
+
const HttpRequestInfo* request_info_;
DISALLOW_COPY_AND_ASSIGN(HttpBasicState);
diff --git a/chromium/net/http/http_basic_state_unittest.cc b/chromium/net/http/http_basic_state_unittest.cc
index 98540e0e232..9eac5107aae 100644
--- a/chromium/net/http/http_basic_state_unittest.cc
+++ b/chromium/net/http/http_basic_state_unittest.cc
@@ -4,9 +4,11 @@
#include "net/http/http_basic_state.h"
+#include "base/memory/ptr_util.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_with_source.h"
#include "net/socket/client_socket_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -15,20 +17,26 @@ namespace {
TEST(HttpBasicStateTest, ConstructsProperly) {
ClientSocketHandle* const handle = new ClientSocketHandle;
- // Ownership of handle is passed to |state|.
- const HttpBasicState state(handle, true);
+ // Ownership of |handle| is passed to |state|.
+ const HttpBasicState state(base::WrapUnique(handle), true /* using_proxy */,
+ false /* http_09_on_non_default_ports_enabled */);
EXPECT_EQ(handle, state.connection());
EXPECT_TRUE(state.using_proxy());
+ EXPECT_FALSE(state.http_09_on_non_default_ports_enabled());
}
-TEST(HttpBasicStateTest, UsingProxyCanBeFalse) {
- const HttpBasicState state(new ClientSocketHandle(), false);
+TEST(HttpBasicStateTest, ConstructsProperlyWithDifferentOptions) {
+ const HttpBasicState state(base::MakeUnique<ClientSocketHandle>(),
+ false /* using_proxy */,
+ true /* http_09_on_non_default_ports_enabled */);
EXPECT_FALSE(state.using_proxy());
+ EXPECT_TRUE(state.http_09_on_non_default_ports_enabled());
}
TEST(HttpBasicStateTest, ReleaseConnectionWorks) {
ClientSocketHandle* const handle = new ClientSocketHandle;
- HttpBasicState state(handle, false);
+ // Ownership of |handle| is passed to |state|.
+ HttpBasicState state(base::WrapUnique(handle), false, false);
const std::unique_ptr<ClientSocketHandle> released_connection(
state.ReleaseConnection());
EXPECT_EQ(NULL, state.connection());
@@ -36,18 +44,18 @@ TEST(HttpBasicStateTest, ReleaseConnectionWorks) {
}
TEST(HttpBasicStateTest, InitializeWorks) {
- HttpBasicState state(new ClientSocketHandle(), false);
+ HttpBasicState state(base::MakeUnique<ClientSocketHandle>(), false, false);
const HttpRequestInfo request_info;
- EXPECT_EQ(OK,
- state.Initialize(
- &request_info, LOW, BoundNetLog(), CompletionCallback()));
+ EXPECT_EQ(OK, state.Initialize(&request_info, LOW, NetLogWithSource(),
+ CompletionCallback()));
EXPECT_TRUE(state.parser());
}
TEST(HttpBasicStateTest, DeleteParser) {
- HttpBasicState state(new ClientSocketHandle(), false);
+ HttpBasicState state(base::MakeUnique<ClientSocketHandle>(), false, false);
const HttpRequestInfo request_info;
- state.Initialize(&request_info, LOW, BoundNetLog(), CompletionCallback());
+ state.Initialize(&request_info, LOW, NetLogWithSource(),
+ CompletionCallback());
EXPECT_TRUE(state.parser());
state.DeleteParser();
EXPECT_EQ(NULL, state.parser());
@@ -55,21 +63,25 @@ TEST(HttpBasicStateTest, DeleteParser) {
TEST(HttpBasicStateTest, GenerateRequestLineNoProxy) {
const bool use_proxy = false;
- HttpBasicState state(new ClientSocketHandle(), use_proxy);
+ HttpBasicState state(base::MakeUnique<ClientSocketHandle>(), use_proxy,
+ false);
HttpRequestInfo request_info;
request_info.url = GURL("http://www.example.com/path?foo=bar#hoge");
request_info.method = "PUT";
- state.Initialize(&request_info, LOW, BoundNetLog(), CompletionCallback());
+ state.Initialize(&request_info, LOW, NetLogWithSource(),
+ CompletionCallback());
EXPECT_EQ("PUT /path?foo=bar HTTP/1.1\r\n", state.GenerateRequestLine());
}
TEST(HttpBasicStateTest, GenerateRequestLineWithProxy) {
const bool use_proxy = true;
- HttpBasicState state(new ClientSocketHandle(), use_proxy);
+ HttpBasicState state(base::MakeUnique<ClientSocketHandle>(), use_proxy,
+ false);
HttpRequestInfo request_info;
request_info.url = GURL("http://www.example.com/path?foo=bar#hoge");
request_info.method = "PUT";
- state.Initialize(&request_info, LOW, BoundNetLog(), CompletionCallback());
+ state.Initialize(&request_info, 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 a82f9fccaf4..c805d7cf989 100644
--- a/chromium/net/http/http_basic_stream.cc
+++ b/chromium/net/http/http_basic_stream.cc
@@ -4,7 +4,7 @@
#include "net/http/http_basic_stream.h"
-#include <memory>
+#include <utility>
#include "net/http/http_request_info.h"
#include "net/http/http_response_body_drainer.h"
@@ -13,15 +13,18 @@
namespace net {
-HttpBasicStream::HttpBasicStream(ClientSocketHandle* connection,
- bool using_proxy)
- : state_(connection, using_proxy) {}
+HttpBasicStream::HttpBasicStream(std::unique_ptr<ClientSocketHandle> connection,
+ bool using_proxy,
+ bool http_09_on_non_default_ports_enabled)
+ : state_(std::move(connection),
+ using_proxy,
+ http_09_on_non_default_ports_enabled) {}
HttpBasicStream::~HttpBasicStream() {}
int HttpBasicStream::InitializeStream(const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback) {
state_.Initialize(request_info, priority, net_log, callback);
return OK;
@@ -35,10 +38,6 @@ int HttpBasicStream::SendRequest(const HttpRequestHeaders& headers,
state_.GenerateRequestLine(), headers, response, callback);
}
-UploadProgress HttpBasicStream::GetUploadProgress() const {
- return parser()->GetUploadProgress();
-}
-
int HttpBasicStream::ReadResponseHeaders(const CompletionCallback& callback) {
return parser()->ReadResponseHeaders(callback);
}
@@ -60,8 +59,8 @@ HttpStream* HttpBasicStream::RenewStreamForAuth() {
// be extra-sure it doesn't touch the connection again, delete it here rather
// than leaving it until the destructor is called.
state_.DeleteParser();
- return new HttpBasicStream(state_.ReleaseConnection().release(),
- state_.using_proxy());
+ return new HttpBasicStream(state_.ReleaseConnection(), state_.using_proxy(),
+ state_.http_09_on_non_default_ports_enabled());
}
bool HttpBasicStream::IsResponseBodyComplete() const {
@@ -112,9 +111,10 @@ bool HttpBasicStream::GetRemoteEndpoint(IPEndPoint* endpoint) {
return state_.connection()->socket()->GetPeerAddress(endpoint) == OK;
}
-Error HttpBasicStream::GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) {
- return parser()->GetSignedEKMForTokenBinding(key, out);
+Error HttpBasicStream::GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) {
+ return parser()->GetTokenBindingSignature(key, tb_type, out);
}
void HttpBasicStream::Drain(HttpNetworkSession* session) {
diff --git a/chromium/net/http/http_basic_stream.h b/chromium/net/http/http_basic_stream.h
index cb3ea2fd517..4f595c92f8a 100644
--- a/chromium/net/http/http_basic_stream.h
+++ b/chromium/net/http/http_basic_stream.h
@@ -11,6 +11,7 @@
#include <stdint.h>
+#include <memory>
#include <string>
#include "base/macros.h"
@@ -20,33 +21,33 @@
namespace net {
-class BoundNetLog;
class ClientSocketHandle;
class HttpResponseInfo;
struct HttpRequestInfo;
class HttpRequestHeaders;
class HttpStreamParser;
class IOBuffer;
+class NetLogWithSource;
class NET_EXPORT_PRIVATE HttpBasicStream : public HttpStream {
public:
// Constructs a new HttpBasicStream. InitializeStream must be called to
// initialize it correctly.
- HttpBasicStream(ClientSocketHandle* connection, bool using_proxy);
+ HttpBasicStream(std::unique_ptr<ClientSocketHandle> connection,
+ bool using_proxy,
+ bool http_09_on_non_default_ports_enabled);
~HttpBasicStream() override;
// HttpStream methods:
int InitializeStream(const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback) override;
int SendRequest(const HttpRequestHeaders& headers,
HttpResponseInfo* response,
const CompletionCallback& callback) override;
- UploadProgress GetUploadProgress() const override;
-
int ReadResponseHeaders(const CompletionCallback& callback) override;
int ReadResponseBody(IOBuffer* buf,
@@ -77,8 +78,9 @@ class NET_EXPORT_PRIVATE HttpBasicStream : public HttpStream {
bool GetRemoteEndpoint(IPEndPoint* endpoint) override;
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) override;
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) override;
void Drain(HttpNetworkSession* session) override;
diff --git a/chromium/net/http/http_cache.cc b/chromium/net/http/http_cache.cc
index 6d83854f774..fc2d7065fcf 100644
--- a/chromium/net/http/http_cache.cc
+++ b/chromium/net/http/http_cache.cc
@@ -43,7 +43,8 @@
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "net/http/http_util.h"
-#include "net/quic/crypto/quic_server_info.h"
+#include "net/log/net_log_with_source.h"
+#include "net/quic/core/crypto/quic_server_info.h"
#if defined(OS_POSIX)
#include <unistd.h>
@@ -240,7 +241,7 @@ void HttpCache::MetadataWriter::Write(const GURL& url,
int rv = transaction_->Start(
&request_info_,
base::Bind(&MetadataWriter::OnIOComplete, base::Unretained(this)),
- BoundNetLog());
+ NetLogWithSource());
if (rv != ERR_IO_PENDING)
VerifyResponse(rv);
}
@@ -293,7 +294,7 @@ class HttpCache::QuicServerInfoFactoryAdaptor : public QuicServerInfoFactory {
HttpCache::HttpCache(HttpNetworkSession* session,
std::unique_ptr<BackendFactory> backend_factory,
bool set_up_quic_server_info)
- : HttpCache(base::WrapUnique(new HttpNetworkLayer(session)),
+ : HttpCache(base::MakeUnique<HttpNetworkLayer>(session),
std::move(backend_factory),
set_up_quic_server_info) {}
@@ -342,7 +343,7 @@ HttpCache::~HttpCache() {
DeactivateEntry(entry);
}
- STLDeleteElements(&doomed_entries_);
+ base::STLDeleteElements(&doomed_entries_);
// Before deleting pending_ops_, we have to make sure that the disk cache is
// done with said operations, or it will attempt to use deleted data.
@@ -366,7 +367,7 @@ HttpCache::~HttpCache() {
pending_op->callback.Reset();
}
- STLDeleteElements(&pending_op->pending_queue);
+ base::STLDeleteElements(&pending_op->pending_queue);
if (delete_pending_op)
delete pending_op;
}
diff --git a/chromium/net/http/http_cache_transaction.cc b/chromium/net/http/http_cache_transaction.cc
index 489e49605fd..45f3db6aed3 100644
--- a/chromium/net/http/http_cache_transaction.cc
+++ b/chromium/net/http/http_cache_transaction.cc
@@ -39,6 +39,7 @@
#include "net/http/http_network_session.h"
#include "net/http/http_request_info.h"
#include "net/http/http_util.h"
+#include "net/log/net_log_event_type.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/ssl/ssl_config_service.h"
@@ -65,7 +66,7 @@ bool NonErrorResponse(int status_code) {
void RecordNoStoreHeaderHistogram(int load_flags,
const HttpResponseInfo* response) {
- if (load_flags & LOAD_MAIN_FRAME) {
+ if (load_flags & LOAD_MAIN_FRAME_DEPRECATED) {
UMA_HISTOGRAM_BOOLEAN(
"Net.MainFrameNoStore",
response->headers->HasHeaderValue("cache-control", "no-store"));
@@ -81,6 +82,21 @@ enum ExternallyConditionalizedType {
} // namespace
+#define CACHE_STATUS_HISTOGRAMS(type) \
+ do { \
+ UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern" type, cache_entry_status_, \
+ CacheEntryStatus::ENTRY_MAX); \
+ if (validation_request) { \
+ UMA_HISTOGRAM_ENUMERATION("HttpCache.ValidationCause" type, \
+ validation_cause_, VALIDATION_CAUSE_MAX); \
+ } \
+ if (stale_request) { \
+ UMA_HISTOGRAM_COUNTS( \
+ "HttpCache.StaleEntry.FreshnessPeriodsSinceLastUsed" type, \
+ freshness_periods_since_last_used); \
+ } \
+ } while (0)
+
struct HeaderNameAndValue {
const char* name;
const char* value;
@@ -248,13 +264,13 @@ LoadState HttpCache::Transaction::GetWriterLoadState() const {
return LOAD_STATE_WAITING_FOR_CACHE;
}
-const BoundNetLog& HttpCache::Transaction::net_log() const {
+const NetLogWithSource& HttpCache::Transaction::net_log() const {
return net_log_;
}
int HttpCache::Transaction::Start(const HttpRequestInfo* request,
const CompletionCallback& callback,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
DCHECK(request);
DCHECK(!callback.is_null());
@@ -472,12 +488,6 @@ LoadState HttpCache::Transaction::GetLoadState() const {
return LOAD_STATE_IDLE;
}
-UploadProgress HttpCache::Transaction::GetUploadProgress() const {
- if (network_trans_.get())
- return network_trans_->GetUploadProgress();
- return final_upload_progress_;
-}
-
void HttpCache::Transaction::SetQuicServerInfo(
QuicServerInfo* quic_server_info) {}
@@ -877,13 +887,13 @@ int HttpCache::Transaction::DoLoop(int result) {
int HttpCache::Transaction::DoGetBackend() {
cache_pending_ = true;
next_state_ = STATE_GET_BACKEND_COMPLETE;
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_GET_BACKEND);
+ net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_GET_BACKEND);
return cache_->GetBackendForTransaction(this);
}
int HttpCache::Transaction::DoGetBackendComplete(int result) {
DCHECK(result == OK || result == ERR_FAILED);
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_GET_BACKEND,
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_GET_BACKEND,
result);
cache_pending_ = false;
@@ -892,6 +902,10 @@ int HttpCache::Transaction::DoGetBackendComplete(int result) {
// Requested cache access mode.
if (effective_load_flags_ & LOAD_ONLY_FROM_CACHE) {
+ if (effective_load_flags_ & LOAD_BYPASS_CACHE) {
+ // The client has asked for nonsense.
+ return ERR_CACHE_MISS;
+ }
mode_ = READ;
} else if (effective_load_flags_ & LOAD_BYPASS_CACHE) {
mode_ = WRITE;
@@ -965,7 +979,7 @@ int HttpCache::Transaction::DoOpenEntry() {
DCHECK(!new_entry_);
next_state_ = STATE_OPEN_ENTRY_COMPLETE;
cache_pending_ = true;
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY);
+ net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_OPEN_ENTRY);
first_cache_access_since_ = TimeTicks::Now();
return cache_->OpenEntry(cache_key_, &new_entry_, this);
}
@@ -974,7 +988,8 @@ int HttpCache::Transaction::DoOpenEntryComplete(int result) {
// It is important that we go to STATE_ADD_TO_ENTRY whenever the result is
// OK, otherwise the cache will end up with an active entry without any
// transaction attached.
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY, result);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_OPEN_ENTRY,
+ result);
cache_pending_ = false;
if (result == OK) {
next_state_ = STATE_ADD_TO_ENTRY;
@@ -1016,12 +1031,13 @@ int HttpCache::Transaction::DoDoomEntry() {
cache_pending_ = true;
if (first_cache_access_since_.is_null())
first_cache_access_since_ = TimeTicks::Now();
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY);
+ net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_DOOM_ENTRY);
return cache_->DoomEntry(cache_key_, this);
}
int HttpCache::Transaction::DoDoomEntryComplete(int result) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY, result);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_DOOM_ENTRY,
+ result);
next_state_ = STATE_CREATE_ENTRY;
cache_pending_ = false;
if (result == ERR_CACHE_RACE)
@@ -1033,7 +1049,7 @@ int HttpCache::Transaction::DoCreateEntry() {
DCHECK(!new_entry_);
next_state_ = STATE_CREATE_ENTRY_COMPLETE;
cache_pending_ = true;
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY);
+ net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_CREATE_ENTRY);
return cache_->CreateEntry(cache_key_, &new_entry_, this);
}
@@ -1041,7 +1057,7 @@ int HttpCache::Transaction::DoCreateEntryComplete(int result) {
// It is important that we go to STATE_ADD_TO_ENTRY whenever the result is
// OK, otherwise the cache will end up with an active entry without any
// transaction attached.
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY,
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_CREATE_ENTRY,
result);
cache_pending_ = false;
switch (result) {
@@ -1071,7 +1087,7 @@ int HttpCache::Transaction::DoAddToEntry() {
DCHECK(new_entry_);
cache_pending_ = true;
next_state_ = STATE_ADD_TO_ENTRY_COMPLETE;
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY);
+ net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY);
DCHECK(entry_lock_waiting_since_.is_null());
entry_lock_waiting_since_ = TimeTicks::Now();
int rv = cache_->AddTransactionToEntry(new_entry_, this);
@@ -1109,7 +1125,7 @@ int HttpCache::Transaction::DoAddToEntry() {
}
int HttpCache::Transaction::DoAddToEntryComplete(int result) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY,
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY,
result);
const TimeDelta entry_lock_wait =
TimeTicks::Now() - entry_lock_waiting_since_;
@@ -1167,13 +1183,14 @@ int HttpCache::Transaction::DoCacheReadResponse() {
io_buf_len_ = entry_->disk_entry->GetDataSize(kResponseInfoIndex);
read_buf_ = new IOBuffer(io_buf_len_);
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_INFO);
+ net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_READ_INFO);
return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_.get(),
io_buf_len_, io_callback_);
}
int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_READ_INFO,
+ result);
if (result != io_buf_len_ ||
!HttpCache::ParseResponseInfo(read_buf_->data(), io_buf_len_, &response_,
&truncated_)) {
@@ -1423,7 +1440,7 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() {
// If we have an authentication response, we are exposed to weird things
// hapenning if the user cancels the authentication before we receive
// the new response.
- net_log_.AddEvent(NetLog::TYPE_HTTP_CACHE_RE_SEND_PARTIAL_REQUEST);
+ net_log_.AddEvent(NetLogEventType::HTTP_CACHE_RE_SEND_PARTIAL_REQUEST);
UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
SetResponse(HttpResponseInfo());
ResetNetworkTransaction();
@@ -1551,7 +1568,6 @@ int HttpCache::Transaction::DoUpdateCachedResponseComplete(int result) {
mode_ = READ;
}
// We no longer need the network transaction, so destroy it.
- final_upload_progress_ = network_trans_->GetUploadProgress();
ResetNetworkTransaction();
} else if (entry_ && handling_206_ && truncated_ &&
partial_->initial_validation()) {
@@ -1617,7 +1633,7 @@ int HttpCache::Transaction::DoTruncateCachedData() {
if (!entry_)
return OK;
if (net_log_.IsCapturing())
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_DATA);
+ net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_WRITE_DATA);
// Truncate the stream.
return WriteToEntry(kResponseContentIndex, 0, NULL, 0, io_callback_);
}
@@ -1625,7 +1641,7 @@ int HttpCache::Transaction::DoTruncateCachedData() {
int HttpCache::Transaction::DoTruncateCachedDataComplete(int result) {
if (entry_) {
if (net_log_.IsCapturing()) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA,
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_WRITE_DATA,
result);
}
}
@@ -1640,14 +1656,14 @@ int HttpCache::Transaction::DoTruncateCachedMetadata() {
return OK;
if (net_log_.IsCapturing())
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO);
+ net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_WRITE_INFO);
return WriteToEntry(kMetadataIndex, 0, NULL, 0, io_callback_);
}
int HttpCache::Transaction::DoTruncateCachedMetadataComplete(int result) {
if (entry_) {
if (net_log_.IsCapturing()) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_INFO,
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_WRITE_INFO,
result);
}
}
@@ -1686,7 +1702,7 @@ int HttpCache::Transaction::DoCacheReadMetadata() {
response_.metadata =
new IOBufferWithSize(entry_->disk_entry->GetDataSize(kMetadataIndex));
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_INFO);
+ net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_READ_INFO);
return entry_->disk_entry->ReadData(kMetadataIndex, 0,
response_.metadata.get(),
response_.metadata->size(),
@@ -1694,7 +1710,8 @@ int HttpCache::Transaction::DoCacheReadMetadata() {
}
int HttpCache::Transaction::DoCacheReadMetadataComplete(int result) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_READ_INFO,
+ result);
if (result != response_.metadata->size())
return OnCacheReadError(result, false);
return OK;
@@ -1728,7 +1745,7 @@ int HttpCache::Transaction::DoCacheReadData() {
next_state_ = STATE_CACHE_READ_DATA_COMPLETE;
if (net_log_.IsCapturing())
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_DATA);
+ net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_READ_DATA);
if (partial_) {
return partial_->CacheRead(entry_->disk_entry, read_buf_.get(), io_buf_len_,
io_callback_);
@@ -1741,7 +1758,7 @@ int HttpCache::Transaction::DoCacheReadData() {
int HttpCache::Transaction::DoCacheReadDataComplete(int result) {
if (net_log_.IsCapturing()) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_DATA,
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_READ_DATA,
result);
}
@@ -1772,7 +1789,7 @@ int HttpCache::Transaction::DoCacheWriteData(int num_bytes) {
write_len_ = num_bytes;
if (entry_) {
if (net_log_.IsCapturing())
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_DATA);
+ net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_WRITE_DATA);
}
if (!entry_ || !num_bytes)
@@ -1786,7 +1803,7 @@ int HttpCache::Transaction::DoCacheWriteData(int num_bytes) {
int HttpCache::Transaction::DoCacheWriteDataComplete(int result) {
if (entry_) {
if (net_log_.IsCapturing()) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA,
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_WRITE_DATA,
result);
}
}
@@ -1838,7 +1855,7 @@ int HttpCache::Transaction::DoCacheWriteTruncatedResponseComplete(int result) {
//-----------------------------------------------------------------------------
-void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log,
+void HttpCache::Transaction::SetRequest(const NetLogWithSource& net_log,
const HttpRequestInfo* request) {
net_log_ = net_log;
request_ = request;
@@ -1900,7 +1917,7 @@ void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log,
// Log the headers before request_ is modified.
std::string empty;
net_log_.AddEvent(
- NetLog::TYPE_HTTP_CACHE_CALLER_REQUEST_HEADERS,
+ NetLogEventType::HTTP_CACHE_CALLER_REQUEST_HEADERS,
base::Bind(&HttpRequestHeaders::NetLogCallback,
base::Unretained(&request_->extra_headers), &empty));
}
@@ -2523,7 +2540,7 @@ int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) {
return OK;
if (net_log_.IsCapturing())
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO);
+ net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_WRITE_INFO);
// Do not cache no-store content. Do not cache content with cert errors
// either. This is to prevent not reporting net errors when loading a
@@ -2538,7 +2555,7 @@ int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) {
IsCertStatusError(response_.ssl_info.cert_status)) {
DoneWritingToEntry(false);
if (net_log_.IsCapturing())
- net_log_.EndEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO);
+ net_log_.EndEvent(NetLogEventType::HTTP_CACHE_WRITE_INFO);
return OK;
}
@@ -2560,7 +2577,7 @@ int HttpCache::Transaction::OnWriteResponseInfoToEntryComplete(int result) {
if (!entry_)
return OK;
if (net_log_.IsCapturing()) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_INFO,
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_WRITE_INFO,
result);
}
@@ -2661,7 +2678,7 @@ int HttpCache::Transaction::DoPartialCacheReadCompleted(int result) {
int HttpCache::Transaction::DoRestartPartialRequest() {
// The stored data cannot be used. Get rid of it and restart this request.
- net_log_.AddEvent(NetLog::TYPE_HTTP_CACHE_RESTART_PARTIAL_REQUEST);
+ net_log_.AddEvent(NetLogEventType::HTTP_CACHE_RESTART_PARTIAL_REQUEST);
// WRITE + Doom + STATE_INIT_ENTRY == STATE_CREATE_ENTRY (without an attempt
// to Doom the entry again).
@@ -2792,9 +2809,6 @@ void HttpCache::Transaction::RecordHistograms() {
freshness_periods_since_last_used =
(time_since_use * 1000) / stale_entry_freshness_;
- UMA_HISTOGRAM_COUNTS("HttpCache.StaleEntry.FreshnessPeriodsSinceLastUsed",
- freshness_periods_since_last_used);
-
if (validation_request) {
int64_t age_in_freshness_periods =
(stale_entry_age_ * 100) / stale_entry_freshness_;
@@ -2821,124 +2835,39 @@ void HttpCache::Transaction::RecordHistograms() {
// Record the cache pattern by resource type. The type is inferred by
// response header mime type, which could be incorrect, so this is just an
// estimate.
- if (mime_type == "text/html" && (request_->load_flags & LOAD_MAIN_FRAME)) {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern.MainFrameHTML",
- cache_entry_status_,
- CacheEntryStatus::ENTRY_MAX);
- if (validation_request) {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.ValidationCause.MainFrameHTML",
- validation_cause_, VALIDATION_CAUSE_MAX);
- }
- if (stale_request) {
- UMA_HISTOGRAM_COUNTS(
- "HttpCache.StaleEntry.FreshnessPeriodsSinceLastUsed.MainFrameHTML",
- freshness_periods_since_last_used);
- }
+ if (mime_type == "text/html" &&
+ (request_->load_flags & LOAD_MAIN_FRAME_DEPRECATED)) {
+ CACHE_STATUS_HISTOGRAMS(".MainFrameHTML");
} else if (mime_type == "text/html") {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern.NonMainFrameHTML",
- cache_entry_status_,
- CacheEntryStatus::ENTRY_MAX);
- if (validation_request) {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.ValidationCause.NonMainFrameHTML",
- validation_cause_, VALIDATION_CAUSE_MAX);
- }
- if (stale_request) {
- UMA_HISTOGRAM_COUNTS(
- "HttpCache.StaleEntry.FreshnessPeriodsSinceLastUsed."
- "NonMainFrameHTML",
- freshness_periods_since_last_used);
- }
+ CACHE_STATUS_HISTOGRAMS(".NonMainFrameHTML");
} else if (mime_type == "text/css") {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern.CSS", cache_entry_status_,
- CacheEntryStatus::ENTRY_MAX);
- if (validation_request) {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.ValidationCause.CSS",
- validation_cause_, VALIDATION_CAUSE_MAX);
- }
- if (stale_request) {
- UMA_HISTOGRAM_COUNTS(
- "HttpCache.StaleEntry.FreshnessPeriodsSinceLastUsed.CSS",
- freshness_periods_since_last_used);
- }
+ CACHE_STATUS_HISTOGRAMS(".CSS");
} else if (base::StartsWith(mime_type, "image/",
base::CompareCase::SENSITIVE)) {
int64_t content_length = response_headers->GetContentLength();
if (content_length >= 0 && content_length < 100) {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern.TinyImage",
- cache_entry_status_,
- CacheEntryStatus::ENTRY_MAX);
- if (validation_request) {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.ValidationCause.TinyImage",
- validation_cause_, VALIDATION_CAUSE_MAX);
- }
- if (stale_request) {
- UMA_HISTOGRAM_COUNTS(
- "HttpCache.StaleEntry.FreshnessPeriodsSinceLastUsed.TinyImage",
- freshness_periods_since_last_used);
- }
+ CACHE_STATUS_HISTOGRAMS(".TinyImage");
} else if (content_length >= 100) {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern.NonTinyImage",
- cache_entry_status_,
- CacheEntryStatus::ENTRY_MAX);
- if (validation_request) {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.ValidationCause.NonTinyImage",
- validation_cause_, VALIDATION_CAUSE_MAX);
- }
- if (stale_request) {
- UMA_HISTOGRAM_COUNTS(
- "HttpCache.StaleEntry.FreshnessPeriodsSinceLastUsed.NonTinyImage",
- freshness_periods_since_last_used);
- }
- }
- UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern.Image", cache_entry_status_,
- CacheEntryStatus::ENTRY_MAX);
- if (validation_request) {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.ValidationCause.Image",
- validation_cause_, VALIDATION_CAUSE_MAX);
- }
- if (stale_request) {
- UMA_HISTOGRAM_COUNTS(
- "HttpCache.StaleEntry.FreshnessPeriodsSinceLastUsed.Image",
- freshness_periods_since_last_used);
+ CACHE_STATUS_HISTOGRAMS(".NonTinyImage");
}
+ CACHE_STATUS_HISTOGRAMS(".Image");
} else if (base::EndsWith(mime_type, "javascript",
base::CompareCase::SENSITIVE) ||
base::EndsWith(mime_type, "ecmascript",
base::CompareCase::SENSITIVE)) {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern.JavaScript",
- cache_entry_status_,
- CacheEntryStatus::ENTRY_MAX);
- if (validation_request) {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.ValidationCause.JavaScript",
- validation_cause_, VALIDATION_CAUSE_MAX);
- }
- if (stale_request) {
- UMA_HISTOGRAM_COUNTS(
- "HttpCache.StaleEntry.FreshnessPeriodsSinceLastUsed.JavaScript",
- freshness_periods_since_last_used);
- }
+ CACHE_STATUS_HISTOGRAMS(".JavaScript");
} else if (mime_type.find("font") != std::string::npos) {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern.Font", cache_entry_status_,
- CacheEntryStatus::ENTRY_MAX);
- if (validation_request) {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.ValidationCause.Font",
- validation_cause_, VALIDATION_CAUSE_MAX);
- }
- if (stale_request) {
- UMA_HISTOGRAM_COUNTS(
- "HttpCache.StaleEntry.FreshnessPeriodsSinceLastUsed.Font",
- freshness_periods_since_last_used);
- }
+ CACHE_STATUS_HISTOGRAMS(".Font");
+ } else if (base::StartsWith(mime_type, "audio/",
+ base::CompareCase::SENSITIVE)) {
+ CACHE_STATUS_HISTOGRAMS(".Audio");
+ } else if (base::StartsWith(mime_type, "video/",
+ base::CompareCase::SENSITIVE)) {
+ CACHE_STATUS_HISTOGRAMS(".Video");
}
}
- UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern", cache_entry_status_,
- CacheEntryStatus::ENTRY_MAX);
-
- if (validation_request) {
- UMA_HISTOGRAM_ENUMERATION("HttpCache.ValidationCause", validation_cause_,
- VALIDATION_CAUSE_MAX);
- }
+ CACHE_STATUS_HISTOGRAMS("");
if (cache_entry_status_ == CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE) {
UMA_HISTOGRAM_ENUMERATION("HttpCache.CantConditionalizeCause",
diff --git a/chromium/net/http/http_cache_transaction.h b/chromium/net/http/http_cache_transaction.h
index 44b0065c444..32bb23571f4 100644
--- a/chromium/net/http/http_cache_transaction.h
+++ b/chromium/net/http/http_cache_transaction.h
@@ -24,14 +24,13 @@
#include "net/base/load_states.h"
#include "net/base/net_error_details.h"
#include "net/base/request_priority.h"
-#include "net/base/upload_progress.h"
#include "net/http/http_cache.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "net/http/http_transaction.h"
#include "net/http/partial_data.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/connection_attempts.h"
#include "net/websockets/websocket_handshake_stream_base.h"
@@ -118,7 +117,7 @@ class HttpCache::Transaction : public HttpTransaction {
const CompletionCallback& io_callback() { return io_callback_; }
- const BoundNetLog& net_log() const;
+ const NetLogWithSource& net_log() const;
// Bypasses the cache lock whenever there is lock contention.
void BypassLockForTest() {
@@ -133,7 +132,7 @@ class HttpCache::Transaction : public HttpTransaction {
// HttpTransaction methods:
int Start(const HttpRequestInfo* request_info,
const CompletionCallback& callback,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
int RestartIgnoringLastError(const CompletionCallback& callback) override;
int RestartWithCertificate(X509Certificate* client_cert,
SSLPrivateKey* client_private_key,
@@ -151,7 +150,6 @@ class HttpCache::Transaction : public HttpTransaction {
void DoneReading() override;
const HttpResponseInfo* GetResponseInfo() const override;
LoadState GetLoadState() const override;
- UploadProgress GetUploadProgress(void) const override;
void SetQuicServerInfo(QuicServerInfo* quic_server_info) override;
bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
bool GetRemoteEndpoint(IPEndPoint* endpoint) const override;
@@ -295,7 +293,8 @@ class HttpCache::Transaction : public HttpTransaction {
int DoCacheWriteTruncatedResponseComplete(int result);
// Sets request_ and fields derived from it.
- void SetRequest(const BoundNetLog& net_log, const HttpRequestInfo* request);
+ void SetRequest(const NetLogWithSource& net_log,
+ const HttpRequestInfo* request);
// Returns true if the request should be handled exclusively by the network
// layer (skipping the cache entirely).
@@ -433,7 +432,7 @@ class HttpCache::Transaction : public HttpTransaction {
State next_state_;
const HttpRequestInfo* request_;
RequestPriority priority_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
std::unique_ptr<HttpRequestInfo> custom_request_;
HttpRequestHeaders request_headers_copy_;
// If extra_headers specified a "if-modified-since" or "if-none-match",
@@ -467,7 +466,6 @@ class HttpCache::Transaction : public HttpTransaction {
int effective_load_flags_;
int write_len_;
std::unique_ptr<PartialData> partial_; // We are dealing with range requests.
- UploadProgress final_upload_progress_;
CompletionCallback io_callback_;
// Members used to track data for histograms.
diff --git a/chromium/net/http/http_cache_unittest.cc b/chromium/net/http/http_cache_unittest.cc
index 3fd601aa68d..62040a32a05 100644
--- a/chromium/net/http/http_cache_unittest.cc
+++ b/chromium/net/http/http_cache_unittest.cc
@@ -43,6 +43,9 @@
#include "net/http/http_transaction_test_util.h"
#include "net/http/http_util.h"
#include "net/http/mock_http_cache.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
#include "net/log/test_net_log_entry.h"
#include "net/log/test_net_log_util.h"
@@ -50,10 +53,15 @@
#include "net/ssl/ssl_cert_request_info.h"
#include "net/ssl/ssl_connection_status_flags.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
#include "net/websockets/websocket_handshake_stream_base.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
using base::Time;
namespace net {
@@ -66,7 +74,7 @@ namespace {
// MockNetworkTransaction.
void TestLoadTimingNetworkRequest(const LoadTimingInfo& load_timing_info) {
EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null());
EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null());
@@ -87,7 +95,7 @@ void TestLoadTimingNetworkRequest(const LoadTimingInfo& load_timing_info) {
// Tests the load timing values of a request that receives a cached response.
void TestLoadTimingCachedResponse(const LoadTimingInfo& load_timing_info) {
EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_EQ(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_EQ(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null());
EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null());
@@ -135,7 +143,7 @@ void ReadAndVerifyTransaction(HttpTransaction* trans,
std::string content;
int rv = ReadTransaction(trans, &content);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
std::string expected(trans_info.data);
EXPECT_EQ(expected, content);
}
@@ -144,7 +152,7 @@ void RunTransactionTestBase(HttpCache* cache,
const MockTransaction& trans_info,
const MockHttpRequest& request,
HttpResponseInfo* response_info,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
LoadTimingInfo* load_timing_info,
int64_t* sent_bytes,
int64_t* received_bytes,
@@ -155,7 +163,7 @@ void RunTransactionTestBase(HttpCache* cache,
std::unique_ptr<HttpTransaction> trans;
int rv = cache->CreateTransaction(DEFAULT_PRIORITY, &trans);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
ASSERT_TRUE(trans.get());
rv = trans->Start(&request, callback.callback(), net_log);
@@ -196,12 +204,13 @@ void RunTransactionTestWithRequest(HttpCache* cache,
const MockHttpRequest& request,
HttpResponseInfo* response_info) {
RunTransactionTestBase(cache, trans_info, request, response_info,
- BoundNetLog(), nullptr, nullptr, nullptr, nullptr);
+ NetLogWithSource(), nullptr, nullptr, nullptr,
+ nullptr);
}
void RunTransactionTestAndGetTiming(HttpCache* cache,
const MockTransaction& trans_info,
- const BoundNetLog& log,
+ const NetLogWithSource& log,
LoadTimingInfo* load_timing_info) {
RunTransactionTestBase(cache, trans_info, MockHttpRequest(trans_info),
nullptr, log, load_timing_info, nullptr, nullptr,
@@ -211,7 +220,7 @@ void RunTransactionTestAndGetTiming(HttpCache* cache,
void RunTransactionTestAndGetTimingAndConnectedSocketAddress(
HttpCache* cache,
const MockTransaction& trans_info,
- const BoundNetLog& log,
+ const NetLogWithSource& log,
LoadTimingInfo* load_timing_info,
IPEndPoint* remote_endpoint) {
RunTransactionTestBase(cache, trans_info, MockHttpRequest(trans_info),
@@ -220,12 +229,13 @@ void RunTransactionTestAndGetTimingAndConnectedSocketAddress(
}
void RunTransactionTest(HttpCache* cache, const MockTransaction& trans_info) {
- RunTransactionTestAndGetTiming(cache, trans_info, BoundNetLog(), nullptr);
+ RunTransactionTestAndGetTiming(cache, trans_info, NetLogWithSource(),
+ nullptr);
}
void RunTransactionTestWithLog(HttpCache* cache,
const MockTransaction& trans_info,
- const BoundNetLog& log) {
+ const NetLogWithSource& log) {
RunTransactionTestAndGetTiming(cache, trans_info, log, nullptr);
}
@@ -240,7 +250,7 @@ void RunTransactionTestWithResponseInfoAndGetTiming(
HttpCache* cache,
const MockTransaction& trans_info,
HttpResponseInfo* response,
- const BoundNetLog& log,
+ const NetLogWithSource& log,
LoadTimingInfo* load_timing_info) {
RunTransactionTestBase(cache, trans_info, MockHttpRequest(trans_info),
response, log, load_timing_info, nullptr, nullptr,
@@ -259,7 +269,7 @@ void RunTransactionTestWithResponseAndGetTiming(
HttpCache* cache,
const MockTransaction& trans_info,
std::string* response_headers,
- const BoundNetLog& log,
+ const NetLogWithSource& log,
LoadTimingInfo* load_timing_info) {
HttpResponseInfo response;
RunTransactionTestBase(cache, trans_info, MockHttpRequest(trans_info),
@@ -587,16 +597,16 @@ class FakeWebSocketHandshakeStreamCreateHelper
};
// Returns true if |entry| is not one of the log types paid attention to in this
-// test. Note that TYPE_HTTP_CACHE_WRITE_INFO and TYPE_HTTP_CACHE_*_DATA are
+// test. Note that HTTP_CACHE_WRITE_INFO and HTTP_CACHE_*_DATA are
// ignored.
bool ShouldIgnoreLogEntry(const TestNetLogEntry& entry) {
switch (entry.type) {
- case NetLog::TYPE_HTTP_CACHE_GET_BACKEND:
- case NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY:
- case NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY:
- case NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY:
- case NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY:
- case NetLog::TYPE_HTTP_CACHE_READ_INFO:
+ case NetLogEventType::HTTP_CACHE_GET_BACKEND:
+ case NetLogEventType::HTTP_CACHE_OPEN_ENTRY:
+ case NetLogEventType::HTTP_CACHE_CREATE_ENTRY:
+ case NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY:
+ case NetLogEventType::HTTP_CACHE_DOOM_ENTRY:
+ case NetLogEventType::HTTP_CACHE_READ_INFO:
return false;
default:
return true;
@@ -612,7 +622,7 @@ void FilterLogEntries(TestNetLogEntry::List* entries) {
}
bool LogContainsEventType(const BoundTestNetLog& log,
- NetLog::EventType expected) {
+ NetLogEventType expected) {
TestNetLogEntry::List entries;
log.GetEntries(&entries);
for (size_t i = 0; i < entries.size(); i++) {
@@ -632,7 +642,7 @@ TEST(HttpCache, CreateThenDestroy) {
MockHttpCache cache;
std::unique_ptr<HttpTransaction> trans;
- EXPECT_EQ(OK, cache.CreateTransaction(&trans));
+ EXPECT_THAT(cache.CreateTransaction(&trans), IsOk());
ASSERT_TRUE(trans.get());
}
@@ -643,7 +653,7 @@ TEST(HttpCache, GetBackend) {
TestCompletionCallback cb;
// This will lazily initialize the backend.
int rv = cache.http_cache()->GetBackend(&backend, cb.callback());
- EXPECT_EQ(OK, cb.GetResult(rv));
+ EXPECT_THAT(cb.GetResult(rv), IsOk());
}
TEST(HttpCache, SimpleGET) {
@@ -680,18 +690,18 @@ TEST(HttpCache, SimpleGETNoDiskCache) {
FilterLogEntries(&entries);
EXPECT_EQ(6u, entries.size());
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 0,
+ NetLogEventType::HTTP_CACHE_GET_BACKEND));
EXPECT_TRUE(
- LogContainsBeginEvent(entries, 0, NetLog::TYPE_HTTP_CACHE_GET_BACKEND));
- EXPECT_TRUE(
- LogContainsEndEvent(entries, 1, NetLog::TYPE_HTTP_CACHE_GET_BACKEND));
- EXPECT_TRUE(
- LogContainsBeginEvent(entries, 2, NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
- EXPECT_TRUE(
- LogContainsEndEvent(entries, 3, NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
+ LogContainsEndEvent(entries, 1, NetLogEventType::HTTP_CACHE_GET_BACKEND));
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 2,
+ NetLogEventType::HTTP_CACHE_OPEN_ENTRY));
EXPECT_TRUE(
- LogContainsBeginEvent(entries, 4, NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
- EXPECT_TRUE(
- LogContainsEndEvent(entries, 5, NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
+ LogContainsEndEvent(entries, 3, NetLogEventType::HTTP_CACHE_OPEN_ENTRY));
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 4,
+ NetLogEventType::HTTP_CACHE_CREATE_ENTRY));
+ EXPECT_TRUE(LogContainsEndEvent(entries, 5,
+ NetLogEventType::HTTP_CACHE_CREATE_ENTRY));
EXPECT_EQ(1, cache.network_layer()->transaction_count());
EXPECT_EQ(0, cache.disk_cache()->open_count());
@@ -723,14 +733,14 @@ TEST(HttpCache, ReleaseBuffer) {
MockHttpRequest request(kSimpleGET_Transaction);
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.CreateTransaction(&trans));
+ ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
const int kBufferSize = 10;
scoped_refptr<IOBuffer> buffer(new IOBuffer(kBufferSize));
ReleaseBufferCompletionCallback cb(buffer.get());
- int rv = trans->Start(&request, cb.callback(), BoundNetLog());
- EXPECT_EQ(OK, cb.GetResult(rv));
+ int rv = trans->Start(&request, cb.callback(), NetLogWithSource());
+ EXPECT_THAT(cb.GetResult(rv), IsOk());
rv = trans->Read(buffer.get(), kBufferSize, cb.callback());
EXPECT_EQ(kBufferSize, cb.GetResult(rv));
@@ -765,10 +775,10 @@ TEST(HttpCache, SimpleGETWithDiskFailures2) {
std::unique_ptr<Context> c(new Context());
int rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = c->callback.WaitForResult();
// Start failing request now.
@@ -810,11 +820,11 @@ TEST(HttpCache, SimpleGETWithDiskFailures3) {
// Now fail to read from the cache.
std::unique_ptr<Context> c(new Context());
int rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
MockHttpRequest request(kSimpleGET_Transaction);
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, c->callback.GetResult(rv));
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+ EXPECT_THAT(c->callback.GetResult(rv), IsOk());
// Now verify that the entry was removed from the cache.
cache.disk_cache()->set_soft_failures(false);
@@ -846,22 +856,22 @@ TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Hit) {
FilterLogEntries(&entries);
EXPECT_EQ(8u, entries.size());
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 0,
+ NetLogEventType::HTTP_CACHE_GET_BACKEND));
EXPECT_TRUE(
- LogContainsBeginEvent(entries, 0, NetLog::TYPE_HTTP_CACHE_GET_BACKEND));
- EXPECT_TRUE(
- LogContainsEndEvent(entries, 1, NetLog::TYPE_HTTP_CACHE_GET_BACKEND));
- EXPECT_TRUE(
- LogContainsBeginEvent(entries, 2, NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
- EXPECT_TRUE(
- LogContainsEndEvent(entries, 3, NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
+ LogContainsEndEvent(entries, 1, NetLogEventType::HTTP_CACHE_GET_BACKEND));
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 2,
+ NetLogEventType::HTTP_CACHE_OPEN_ENTRY));
EXPECT_TRUE(
- LogContainsBeginEvent(entries, 4, NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
- EXPECT_TRUE(
- LogContainsEndEvent(entries, 5, NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
- EXPECT_TRUE(
- LogContainsBeginEvent(entries, 6, NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY));
- EXPECT_TRUE(
- LogContainsEndEvent(entries, 7, NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY));
+ LogContainsEndEvent(entries, 3, NetLogEventType::HTTP_CACHE_OPEN_ENTRY));
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 4,
+ NetLogEventType::HTTP_CACHE_CREATE_ENTRY));
+ EXPECT_TRUE(LogContainsEndEvent(entries, 5,
+ NetLogEventType::HTTP_CACHE_CREATE_ENTRY));
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 6,
+ NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY));
+ EXPECT_TRUE(LogContainsEndEvent(entries, 7,
+ NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY));
TestLoadTimingNetworkRequest(load_timing_info);
@@ -879,22 +889,22 @@ TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Hit) {
FilterLogEntries(&entries);
EXPECT_EQ(8u, entries.size());
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 0,
+ NetLogEventType::HTTP_CACHE_GET_BACKEND));
EXPECT_TRUE(
- LogContainsBeginEvent(entries, 0, NetLog::TYPE_HTTP_CACHE_GET_BACKEND));
- EXPECT_TRUE(
- LogContainsEndEvent(entries, 1, NetLog::TYPE_HTTP_CACHE_GET_BACKEND));
+ LogContainsEndEvent(entries, 1, NetLogEventType::HTTP_CACHE_GET_BACKEND));
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 2,
+ NetLogEventType::HTTP_CACHE_OPEN_ENTRY));
EXPECT_TRUE(
- LogContainsBeginEvent(entries, 2, NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
+ LogContainsEndEvent(entries, 3, NetLogEventType::HTTP_CACHE_OPEN_ENTRY));
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 4,
+ NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY));
+ EXPECT_TRUE(LogContainsEndEvent(entries, 5,
+ NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY));
EXPECT_TRUE(
- LogContainsEndEvent(entries, 3, NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
+ LogContainsBeginEvent(entries, 6, NetLogEventType::HTTP_CACHE_READ_INFO));
EXPECT_TRUE(
- LogContainsBeginEvent(entries, 4, NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY));
- EXPECT_TRUE(
- LogContainsEndEvent(entries, 5, NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY));
- EXPECT_TRUE(
- LogContainsBeginEvent(entries, 6, NetLog::TYPE_HTTP_CACHE_READ_INFO));
- EXPECT_TRUE(
- LogContainsEndEvent(entries, 7, NetLog::TYPE_HTTP_CACHE_READ_INFO));
+ LogContainsEndEvent(entries, 7, NetLogEventType::HTTP_CACHE_READ_INFO));
EXPECT_EQ(1, cache.network_layer()->transaction_count());
EXPECT_EQ(1, cache.disk_cache()->open_count());
@@ -913,12 +923,12 @@ TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Miss) {
TestCompletionCallback callback;
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.CreateTransaction(&trans));
+ ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
- ASSERT_EQ(ERR_CACHE_MISS, rv);
+ ASSERT_THAT(rv, IsError(ERR_CACHE_MISS));
trans.reset();
@@ -1031,10 +1041,10 @@ TEST(HttpCache, SimpleGET_CacheSignal_Failure) {
TestCompletionCallback callback;
std::unique_ptr<HttpTransaction> trans;
int rv = cache.http_cache()->CreateTransaction(DEFAULT_PRIORITY, &trans);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
ASSERT_TRUE(trans.get());
- rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_FAILED, callback.GetResult(rv));
+ rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsError(ERR_FAILED));
const HttpResponseInfo* response_info = trans->GetResponseInfo();
ASSERT_TRUE(response_info);
@@ -1107,22 +1117,22 @@ TEST(HttpCache, SimpleGET_LoadBypassCache) {
FilterLogEntries(&entries);
EXPECT_EQ(8u, entries.size());
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 0,
+ NetLogEventType::HTTP_CACHE_GET_BACKEND));
EXPECT_TRUE(
- LogContainsBeginEvent(entries, 0, NetLog::TYPE_HTTP_CACHE_GET_BACKEND));
- EXPECT_TRUE(
- LogContainsEndEvent(entries, 1, NetLog::TYPE_HTTP_CACHE_GET_BACKEND));
+ LogContainsEndEvent(entries, 1, NetLogEventType::HTTP_CACHE_GET_BACKEND));
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 2,
+ NetLogEventType::HTTP_CACHE_DOOM_ENTRY));
EXPECT_TRUE(
- LogContainsBeginEvent(entries, 2, NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY));
- EXPECT_TRUE(
- LogContainsEndEvent(entries, 3, NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY));
- EXPECT_TRUE(
- LogContainsBeginEvent(entries, 4, NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
- EXPECT_TRUE(
- LogContainsEndEvent(entries, 5, NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
- EXPECT_TRUE(
- LogContainsBeginEvent(entries, 6, NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY));
- EXPECT_TRUE(
- LogContainsEndEvent(entries, 7, NetLog::TYPE_HTTP_CACHE_ADD_TO_ENTRY));
+ LogContainsEndEvent(entries, 3, NetLogEventType::HTTP_CACHE_DOOM_ENTRY));
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 4,
+ NetLogEventType::HTTP_CACHE_CREATE_ENTRY));
+ EXPECT_TRUE(LogContainsEndEvent(entries, 5,
+ NetLogEventType::HTTP_CACHE_CREATE_ENTRY));
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 6,
+ NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY));
+ EXPECT_TRUE(LogContainsEndEvent(entries, 7,
+ NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY));
EXPECT_EQ(2, cache.network_layer()->transaction_count());
EXPECT_EQ(0, cache.disk_cache()->open_count());
@@ -1272,11 +1282,11 @@ TEST(HttpCache, SimpleGET_ManyReaders) {
Context* c = context_list[i];
c->result = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, c->result);
+ ASSERT_THAT(c->result, IsOk());
EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
c->result =
- c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
}
// All requests are waiting for the active entry.
@@ -1340,14 +1350,14 @@ TEST(HttpCache, SimpleGET_RacingReaders) {
Context* c = context_list[i];
c->result = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, c->result);
+ ASSERT_THAT(c->result, IsOk());
MockHttpRequest* this_request = &request;
if (i == 1 || i == 2)
this_request = &reader_request;
- c->result =
- c->trans->Start(this_request, c->callback.callback(), BoundNetLog());
+ c->result = c->trans->Start(this_request, c->callback.callback(),
+ NetLogWithSource());
}
// Allow all requests to move from the Create queue to the active entry.
@@ -1361,7 +1371,7 @@ TEST(HttpCache, SimpleGET_RacingReaders) {
EXPECT_EQ(1, cache.disk_cache()->create_count());
Context* c = context_list[0];
- ASSERT_EQ(ERR_IO_PENDING, c->result);
+ ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
c->result = c->callback.WaitForResult();
ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
@@ -1372,7 +1382,7 @@ TEST(HttpCache, SimpleGET_RacingReaders) {
context_list[3]->trans->GetLoadState());
c = context_list[1];
- ASSERT_EQ(ERR_IO_PENDING, c->result);
+ ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
c->result = c->callback.WaitForResult();
if (c->result == OK)
ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
@@ -1424,14 +1434,14 @@ TEST(HttpCache, SimpleGET_DoomWithPending) {
Context* c = context_list[i].get();
c->result = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, c->result);
+ ASSERT_THAT(c->result, IsOk());
MockHttpRequest* this_request = &request;
if (i == 3)
this_request = &writer_request;
- c->result =
- c->trans->Start(this_request, c->callback.callback(), BoundNetLog());
+ c->result = c->trans->Start(this_request, c->callback.callback(),
+ NetLogWithSource());
}
// The first request should be a writer at this point, and the two subsequent
@@ -1446,7 +1456,7 @@ TEST(HttpCache, SimpleGET_DoomWithPending) {
if (i == 1)
continue;
Context* c = context_list[i].get();
- ASSERT_EQ(ERR_IO_PENDING, c->result);
+ ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
c->result = c->callback.WaitForResult();
ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
}
@@ -1471,10 +1481,10 @@ TEST(HttpCache, FastNoStoreGET_DoneWithPending) {
Context* c = context_list[i];
c->result = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, c->result);
+ ASSERT_THAT(c->result, IsOk());
c->result =
- c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
}
// Allow all requests to move from the Create queue to the active entry.
@@ -1518,10 +1528,10 @@ TEST(HttpCache, SimpleGET_ManyWriters_CancelFirst) {
Context* c = context_list[i];
c->result = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, c->result);
+ ASSERT_THAT(c->result, IsOk());
c->result =
- c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
}
// Allow all requests to move from the Create queue to the active entry.
@@ -1578,10 +1588,10 @@ TEST(HttpCache, SimpleGET_ManyWriters_CancelCreate) {
Context* c = context_list[i];
c->result = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, c->result);
+ ASSERT_THAT(c->result, IsOk());
c->result =
- c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
}
// The first request should be creating the disk cache entry and the others
@@ -1629,10 +1639,11 @@ TEST(HttpCache, SimpleGET_CancelCreate) {
Context* c = new Context();
c->result = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, c->result);
+ ASSERT_THAT(c->result, IsOk());
- c->result = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, c->result);
+ c->result =
+ c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+ EXPECT_THAT(c->result, IsError(ERR_IO_PENDING));
// Release the reference that the mock disk cache keeps for this entry, so
// that we test that the http cache handles the cancellation correctly.
@@ -1658,10 +1669,10 @@ TEST(HttpCache, SimpleGET_ManyWriters_BypassCache) {
Context* c = context_list[i];
c->result = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, c->result);
+ ASSERT_THAT(c->result, IsOk());
c->result =
- c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
}
// The first request should be deleting the disk cache entry and the others
@@ -1697,12 +1708,12 @@ TEST(HttpCache, SimpleGET_WriterTimeout) {
MockHttpRequest request(kSimpleGET_Transaction);
Context c1, c2;
- ASSERT_EQ(OK, cache.CreateTransaction(&c1.trans));
- ASSERT_EQ(ERR_IO_PENDING,
- c1.trans->Start(&request, c1.callback.callback(), BoundNetLog()));
- ASSERT_EQ(OK, cache.CreateTransaction(&c2.trans));
- ASSERT_EQ(ERR_IO_PENDING,
- c2.trans->Start(&request, c2.callback.callback(), BoundNetLog()));
+ ASSERT_THAT(cache.CreateTransaction(&c1.trans), IsOk());
+ ASSERT_EQ(ERR_IO_PENDING, c1.trans->Start(&request, c1.callback.callback(),
+ NetLogWithSource()));
+ ASSERT_THAT(cache.CreateTransaction(&c2.trans), IsOk());
+ ASSERT_EQ(ERR_IO_PENDING, c2.trans->Start(&request, c2.callback.callback(),
+ NetLogWithSource()));
// The second request is queued after the first one.
@@ -1724,15 +1735,15 @@ TEST(HttpCache, SimpleGET_AbandonedCacheRead) {
TestCompletionCallback callback;
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.CreateTransaction(&trans));
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
scoped_refptr<IOBuffer> buf(new IOBuffer(256));
rv = trans->Read(buf.get(), 256, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Test that destroying the transaction while it is reading from the cache
// works properly.
@@ -1759,10 +1770,10 @@ TEST(HttpCache, SimpleGET_ManyWriters_DeleteCache) {
Context* c = context_list[i];
c->result = cache->CreateTransaction(&c->trans);
- ASSERT_EQ(OK, c->result);
+ ASSERT_THAT(c->result, IsOk());
c->result =
- c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
}
// The first request should be creating the disk cache entry and the others
@@ -1798,15 +1809,15 @@ TEST(HttpCache, SimpleGET_WaitForBackend) {
Context* c = context_list[i];
c->result = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, c->result);
+ ASSERT_THAT(c->result, IsOk());
}
context_list[0]->result = context_list[0]->trans->Start(
- &request0, context_list[0]->callback.callback(), BoundNetLog());
+ &request0, context_list[0]->callback.callback(), NetLogWithSource());
context_list[1]->result = context_list[1]->trans->Start(
- &request1, context_list[1]->callback.callback(), BoundNetLog());
+ &request1, context_list[1]->callback.callback(), NetLogWithSource());
context_list[2]->result = context_list[2]->trans->Start(
- &request2, context_list[2]->callback.callback(), BoundNetLog());
+ &request2, context_list[2]->callback.callback(), NetLogWithSource());
// Just to make sure that everything is still pending.
base::RunLoop().RunUntilIdle();
@@ -1844,15 +1855,15 @@ TEST(HttpCache, SimpleGET_WaitForBackend_CancelCreate) {
Context* c = context_list[i];
c->result = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, c->result);
+ ASSERT_THAT(c->result, IsOk());
}
context_list[0]->result = context_list[0]->trans->Start(
- &request0, context_list[0]->callback.callback(), BoundNetLog());
+ &request0, context_list[0]->callback.callback(), NetLogWithSource());
context_list[1]->result = context_list[1]->trans->Start(
- &request1, context_list[1]->callback.callback(), BoundNetLog());
+ &request1, context_list[1]->callback.callback(), NetLogWithSource());
context_list[2]->result = context_list[2]->trans->Start(
- &request2, context_list[2]->callback.callback(), BoundNetLog());
+ &request2, context_list[2]->callback.callback(), NetLogWithSource());
// Just to make sure that everything is still pending.
base::RunLoop().RunUntilIdle();
@@ -1891,9 +1902,9 @@ TEST(HttpCache, DeleteCacheWaitingForBackend) {
std::unique_ptr<Context> c(new Context());
c->result = cache->CreateTransaction(&c->trans);
- ASSERT_EQ(OK, c->result);
+ ASSERT_THAT(c->result, IsOk());
- c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
// Just to make sure that everything is still pending.
base::RunLoop().RunUntilIdle();
@@ -1922,21 +1933,21 @@ TEST(HttpCache, DeleteCacheWaitingForBackend2) {
DeleteCacheCompletionCallback cb(cache);
disk_cache::Backend* backend;
int rv = cache->http_cache()->GetBackend(&backend, cb.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Now let's queue a regular transaction
MockHttpRequest request(kSimpleGET_Transaction);
std::unique_ptr<Context> c(new Context());
c->result = cache->CreateTransaction(&c->trans);
- ASSERT_EQ(OK, c->result);
+ ASSERT_THAT(c->result, IsOk());
- c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
// And another direct backend request.
TestCompletionCallback cb2;
rv = cache->http_cache()->GetBackend(&backend, cb2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Just to make sure that everything is still pending.
base::RunLoop().RunUntilIdle();
@@ -1950,7 +1961,7 @@ TEST(HttpCache, DeleteCacheWaitingForBackend2) {
// The cache should be gone by now.
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(OK, c->callback.GetResult(c->result));
+ EXPECT_THAT(c->callback.GetResult(c->result), IsOk());
EXPECT_FALSE(cb2.have_result());
}
@@ -2906,11 +2917,11 @@ TEST(HttpCache, SimplePOST_LoadOnlyFromCache_Miss) {
TestCompletionCallback callback;
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.CreateTransaction(&trans));
+ ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
ASSERT_TRUE(trans.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- ASSERT_EQ(ERR_CACHE_MISS, callback.GetResult(rv));
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ ASSERT_THAT(callback.GetResult(rv), IsError(ERR_CACHE_MISS));
trans.reset();
@@ -2930,7 +2941,7 @@ TEST(HttpCache, SimplePOST_LoadOnlyFromCache_Hit) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
element_readers.push_back(
- base::WrapUnique(new UploadBytesElementReader("hello", 5)));
+ base::MakeUnique<UploadBytesElementReader>("hello", 5));
ElementsUploadDataStream upload_data_stream(std::move(element_readers),
kUploadId);
MockHttpRequest request(transaction);
@@ -3161,11 +3172,11 @@ TEST(HttpCache, SimpleHEAD_LoadOnlyFromCache_Miss) {
TestCompletionCallback callback;
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.CreateTransaction(&trans));
+ ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
ASSERT_TRUE(trans.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- ASSERT_EQ(ERR_CACHE_MISS, callback.GetResult(rv));
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ ASSERT_THAT(callback.GetResult(rv), IsError(ERR_CACHE_MISS));
trans.reset();
@@ -3792,7 +3803,7 @@ TEST(HttpCache, SimpleGET_DoesntLogHeaders) {
log.bound());
EXPECT_FALSE(LogContainsEventType(
- log, NetLog::TYPE_HTTP_CACHE_CALLER_REQUEST_HEADERS));
+ log, NetLogEventType::HTTP_CACHE_CALLER_REQUEST_HEADERS));
}
TEST(HttpCache, RangeGET_LogsHeaders) {
@@ -3803,7 +3814,7 @@ TEST(HttpCache, RangeGET_LogsHeaders) {
log.bound());
EXPECT_TRUE(LogContainsEventType(
- log, NetLog::TYPE_HTTP_CACHE_CALLER_REQUEST_HEADERS));
+ log, NetLogEventType::HTTP_CACHE_CALLER_REQUEST_HEADERS));
}
TEST(HttpCache, ExternalValidation_LogsHeaders) {
@@ -3815,7 +3826,7 @@ TEST(HttpCache, ExternalValidation_LogsHeaders) {
RunTransactionTestWithLog(cache.http_cache(), transaction, log.bound());
EXPECT_TRUE(LogContainsEventType(
- log, NetLog::TYPE_HTTP_CACHE_CALLER_REQUEST_HEADERS));
+ log, NetLogEventType::HTTP_CACHE_CALLER_REQUEST_HEADERS));
}
TEST(HttpCache, SpecialHeaders_LogsHeaders) {
@@ -3827,7 +3838,7 @@ TEST(HttpCache, SpecialHeaders_LogsHeaders) {
RunTransactionTestWithLog(cache.http_cache(), transaction, log.bound());
EXPECT_TRUE(LogContainsEventType(
- log, NetLog::TYPE_HTTP_CACHE_CALLER_REQUEST_HEADERS));
+ log, NetLogEventType::HTTP_CACHE_CALLER_REQUEST_HEADERS));
}
// Tests that receiving 206 for a regular request is handled correctly.
@@ -3943,7 +3954,7 @@ TEST(HttpCache, RangeGET_NoValidation_LogsRestart) {
log.bound());
EXPECT_TRUE(LogContainsEventType(
- log, NetLog::TYPE_HTTP_CACHE_RESTART_PARTIAL_REQUEST));
+ log, NetLogEventType::HTTP_CACHE_RESTART_PARTIAL_REQUEST));
}
// Tests that a failure to conditionalize a regular request (no range) with a
@@ -5165,9 +5176,9 @@ TEST(HttpCache, MAYBE_RangeGET_Cancel) {
Context* c = new Context();
int rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = c->callback.WaitForResult();
@@ -5210,9 +5221,9 @@ TEST(HttpCache, MAYBE_RangeGET_Cancel2) {
Context* c = new Context();
int rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = c->callback.WaitForResult();
@@ -5226,7 +5237,7 @@ TEST(HttpCache, MAYBE_RangeGET_Cancel2) {
rv = c->trans->Read(buf.get(), buf->size(), c->callback.callback());
EXPECT_EQ(5, c->callback.GetResult(rv));
rv = c->trans->Read(buf.get(), buf->size(), c->callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Destroy the transaction before completing the read.
delete c;
@@ -5255,10 +5266,10 @@ TEST(HttpCache, RangeGET_Cancel3) {
Context* c = new Context();
int rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = c->callback.WaitForResult();
EXPECT_EQ(2, cache.network_layer()->transaction_count());
@@ -5271,7 +5282,7 @@ TEST(HttpCache, RangeGET_Cancel3) {
rv = c->trans->Read(buf.get(), buf->size(), c->callback.callback());
EXPECT_EQ(5, c->callback.GetResult(rv));
rv = c->trans->Read(buf.get(), buf->size(), c->callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Destroy the transaction before completing the read.
delete c;
@@ -5282,10 +5293,10 @@ TEST(HttpCache, RangeGET_Cancel3) {
c = new Context();
rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
MockDiskEntry::IgnoreCallbacks(true);
base::RunLoop().RunUntilIdle();
@@ -5493,7 +5504,7 @@ TEST(HttpCache, RangeGET_FastFlakyServer) {
EXPECT_EQ(1, cache.disk_cache()->open_count());
EXPECT_EQ(1, cache.disk_cache()->create_count());
EXPECT_TRUE(LogContainsEventType(
- log, NetLog::TYPE_HTTP_CACHE_RE_SEND_PARTIAL_REQUEST));
+ log, NetLogEventType::HTTP_CACHE_RE_SEND_PARTIAL_REQUEST));
}
// Tests that when the server gives us less data than expected, we don't keep
@@ -5557,13 +5568,13 @@ TEST(HttpCache, RangeGET_OK_LoadOnlyFromCache) {
std::unique_ptr<HttpTransaction> trans;
int rv = cache.http_cache()->CreateTransaction(DEFAULT_PRIORITY, &trans);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
ASSERT_TRUE(trans.get());
- rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ rv = trans->Start(&request, callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
- ASSERT_EQ(ERR_CACHE_MISS, rv);
+ ASSERT_THAT(rv, IsError(ERR_CACHE_MISS));
trans.reset();
@@ -5635,9 +5646,9 @@ TEST(HttpCache, DoomOnDestruction) {
Context* c = new Context();
int rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
c->result = c->callback.WaitForResult();
@@ -5665,9 +5676,9 @@ TEST(HttpCache, DoomOnDestruction2) {
Context* c = new Context();
int rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = c->callback.WaitForResult();
@@ -5708,9 +5719,9 @@ TEST(HttpCache, DoomOnDestruction3) {
Context* c = new Context();
int rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = c->callback.WaitForResult();
@@ -5751,9 +5762,9 @@ TEST(HttpCache, SetTruncatedFlag) {
std::unique_ptr<Context> c(new Context());
int rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = c->callback.WaitForResult();
@@ -5770,7 +5781,7 @@ TEST(HttpCache, SetTruncatedFlag) {
// We want to cancel the request when the transaction is busy.
rv = c->trans->Read(buf.get(), buf->size(), c->callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(c->callback.have_result());
MockHttpCache::SetTestMode(TEST_MODE_SYNC_ALL);
@@ -5803,10 +5814,10 @@ TEST(HttpCache, DontSetTruncatedFlag) {
std::unique_ptr<Context> c(new Context());
int rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, c->callback.GetResult(rv));
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+ EXPECT_THAT(c->callback.GetResult(rv), IsOk());
// Read everything.
scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(22));
@@ -5831,10 +5842,10 @@ TEST(HttpCache, RangeGET_DontTruncate) {
std::unique_ptr<HttpTransaction> trans;
int rv = cache.http_cache()->CreateTransaction(DEFAULT_PRIORITY, &trans);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
TestCompletionCallback cb;
- rv = trans->Start(request.get(), cb.callback(), BoundNetLog());
+ rv = trans->Start(request.get(), cb.callback(), NetLogWithSource());
EXPECT_EQ(0, cb.GetResult(rv));
scoped_refptr<IOBuffer> buf(new IOBuffer(10));
@@ -5858,10 +5869,10 @@ TEST(HttpCache, RangeGET_DontTruncate2) {
std::unique_ptr<HttpTransaction> trans;
int rv = cache.http_cache()->CreateTransaction(DEFAULT_PRIORITY, &trans);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
TestCompletionCallback cb;
- rv = trans->Start(request.get(), cb.callback(), BoundNetLog());
+ rv = trans->Start(request.get(), cb.callback(), NetLogWithSource());
EXPECT_EQ(0, cb.GetResult(rv));
scoped_refptr<IOBuffer> buf(new IOBuffer(10));
@@ -5979,20 +5990,20 @@ TEST(HttpCache, GET_IncompleteResource_Cancel) {
Context* c = new Context();
int rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
// Queue another request to this transaction. We have to start this request
// before the first one gets the response from the server and dooms the entry,
// otherwise it will just create a new entry without being queued to the first
// request.
Context* pending = new Context();
- ASSERT_EQ(OK, cache.CreateTransaction(&pending->trans));
+ ASSERT_THAT(cache.CreateTransaction(&pending->trans), IsOk());
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
EXPECT_EQ(ERR_IO_PENDING,
pending->trans->Start(&request, pending->callback.callback(),
- BoundNetLog()));
- EXPECT_EQ(OK, c->callback.GetResult(rv));
+ NetLogWithSource()));
+ EXPECT_THAT(c->callback.GetResult(rv), IsOk());
// Make sure that the entry has some data stored.
scoped_refptr<IOBufferWithSize> buf(new IOBufferWithSize(5));
@@ -6070,11 +6081,11 @@ TEST(HttpCache, GET_IncompleteResource3) {
std::unique_ptr<Context> c(new Context);
int rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
MockHttpRequest request(transaction);
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, c->callback.GetResult(rv));
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+ EXPECT_THAT(c->callback.GetResult(rv), IsOk());
// We should have checked with the server before finishing Start().
EXPECT_EQ(1, cache.network_layer()->transaction_count());
@@ -6105,17 +6116,17 @@ TEST(HttpCache, GET_IncompleteResourceWithAuth) {
std::unique_ptr<Context> c(new Context);
int rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
MockHttpRequest request(transaction);
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, c->callback.GetResult(rv));
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+ EXPECT_THAT(c->callback.GetResult(rv), IsOk());
const HttpResponseInfo* response = c->trans->GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_EQ(401, response->headers->response_code());
rv = c->trans->RestartWithAuth(AuthCredentials(), c->callback.callback());
- EXPECT_EQ(OK, c->callback.GetResult(rv));
+ EXPECT_THAT(c->callback.GetResult(rv), IsOk());
response = c->trans->GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_EQ(200, response->headers->response_code());
@@ -6156,16 +6167,16 @@ TEST(HttpCache, TransactionRetryLimit) {
std::unique_ptr<Context> c(new Context);
int rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
MockHttpRequest request(transaction);
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = c->callback.WaitForResult();
std::string content;
rv = ReadTransaction(c->trans.get(), &content);
- EXPECT_EQ(ERR_CACHE_AUTH_FAILURE_AFTER_READ, rv);
+ EXPECT_THAT(rv, IsError(ERR_CACHE_AUTH_FAILURE_AFTER_READ));
}
// Tests that we cache a 200 response to the validation request.
@@ -6215,10 +6226,10 @@ TEST(HttpCache, GET_CancelIncompleteResource) {
MockHttpRequest request(transaction);
Context* c = new Context();
int rv = cache.CreateTransaction(&c->trans);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
- rv = c->trans->Start(&request, c->callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, c->callback.GetResult(rv));
+ rv = c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
+ EXPECT_THAT(c->callback.GetResult(rv), IsOk());
// Read 20 bytes from the cache, and 10 from the net.
scoped_refptr<IOBuffer> buf(new IOBuffer(100));
@@ -6284,13 +6295,13 @@ TEST(HttpCache, SyncRead) {
c2(DEFAULT_PRIORITY, cache.http_cache()),
c3(DEFAULT_PRIORITY, cache.http_cache());
- c1.Start(&r1, BoundNetLog());
+ c1.Start(&r1, NetLogWithSource());
r2.load_flags |= LOAD_ONLY_FROM_CACHE;
- c2.Start(&r2, BoundNetLog());
+ c2.Start(&r2, NetLogWithSource());
r3.load_flags |= LOAD_ONLY_FROM_CACHE;
- c3.Start(&r3, BoundNetLog());
+ c3.Start(&r3, NetLogWithSource());
base::RunLoop().Run();
@@ -6298,9 +6309,9 @@ TEST(HttpCache, SyncRead) {
EXPECT_TRUE(c2.is_done());
EXPECT_TRUE(c3.is_done());
- EXPECT_EQ(OK, c1.error());
- EXPECT_EQ(OK, c2.error());
- EXPECT_EQ(OK, c3.error());
+ EXPECT_THAT(c1.error(), IsOk());
+ EXPECT_THAT(c2.error(), IsOk());
+ EXPECT_THAT(c3.error(), IsOk());
}
TEST(HttpCache, ValidationResultsIn200) {
@@ -6334,12 +6345,12 @@ TEST(HttpCache, CachedRedirect) {
// Write to the cache.
{
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.CreateTransaction(&trans));
+ ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
const HttpResponseInfo* info = trans->GetResponseInfo();
ASSERT_TRUE(info);
@@ -6368,12 +6379,12 @@ TEST(HttpCache, CachedRedirect) {
// Read from the cache.
{
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.CreateTransaction(&trans));
+ ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
const HttpResponseInfo* info = trans->GetResponseInfo();
ASSERT_TRUE(info);
@@ -6549,12 +6560,12 @@ TEST(HttpCache, SimpleGET_SSLError) {
TestCompletionCallback callback;
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.CreateTransaction(&trans));
+ ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
- ASSERT_EQ(ERR_CACHE_MISS, rv);
+ ASSERT_THAT(rv, IsError(ERR_CACHE_MISS));
}
// Ensure that we don't crash by if left-behind transactions.
@@ -6562,7 +6573,7 @@ TEST(HttpCache, OutlivedTransactions) {
MockHttpCache* cache = new MockHttpCache;
std::unique_ptr<HttpTransaction> trans;
- EXPECT_EQ(OK, cache->CreateTransaction(&trans));
+ EXPECT_THAT(cache->CreateTransaction(&trans), IsOk());
delete cache;
trans.reset();
@@ -6733,6 +6744,22 @@ TEST(HttpCache, WriteMetadata_Fail) {
EXPECT_EQ(1, cache.disk_cache()->create_count());
}
+TEST(HttpCache, InvalidLoadFlagCombination) {
+ MockHttpCache cache;
+
+ // Put the resource in the cache.
+ RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction);
+
+ // Now try to fetch it again, but with a flag combination disallowing both
+ // cache and network access.
+ ScopedMockTransaction transaction(kSimpleGET_Transaction);
+ // DevTools relies on this combination of flags for "disable cache" mode
+ // when a resource is only supposed to be loaded from cache.
+ transaction.load_flags = LOAD_ONLY_FROM_CACHE | LOAD_BYPASS_CACHE;
+ transaction.return_code = ERR_CACHE_MISS;
+ RunTransactionTest(cache.http_cache(), transaction);
+}
+
// Tests that we can read metadata after validating the entry and with READ mode
// transactions.
TEST(HttpCache, ReadMetadata) {
@@ -6803,11 +6830,11 @@ TEST(HttpCache, FilterCompletion) {
{
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.CreateTransaction(&trans));
+ ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
MockHttpRequest request(kSimpleGET_Transaction);
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
scoped_refptr<IOBuffer> buf(new IOBuffer(256));
rv = trans->Read(buf.get(), 256, callback.callback());
@@ -6839,11 +6866,11 @@ TEST(HttpCache, DoneReading) {
transaction.data = "";
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.CreateTransaction(&trans));
+ ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
MockHttpRequest request(transaction);
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
trans->DoneReading();
// Leave the transaction around.
@@ -6867,10 +6894,10 @@ TEST(HttpCache, StopCachingDeletesEntry) {
{
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.CreateTransaction(&trans));
+ ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
scoped_refptr<IOBuffer> buf(new IOBuffer(256));
rv = trans->Read(buf.get(), 10, callback.callback());
@@ -6905,10 +6932,10 @@ TEST(HttpCache, StopCachingThenDoneReadingDeletesEntry) {
{
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.CreateTransaction(&trans));
+ ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
scoped_refptr<IOBuffer> buf(new IOBuffer(256));
rv = trans->Read(buf.get(), 10, callback.callback());
@@ -6948,10 +6975,10 @@ TEST(HttpCache, StopCachingWithAuthDeletesEntry) {
{
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.CreateTransaction(&trans));
+ ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
trans->StopCaching();
@@ -6980,7 +7007,7 @@ TEST(HttpCache, StopCachingSavesEntry) {
{
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.CreateTransaction(&trans));
+ ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
// Force a response that can be resumed.
ScopedMockTransaction mock_transaction(kSimpleGET_Transaction);
@@ -6989,8 +7016,8 @@ TEST(HttpCache, StopCachingSavesEntry) {
"Content-Length: 42\n"
"Etag: \"foo\"\n";
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
scoped_refptr<IOBuffer> buf(new IOBuffer(256));
rv = trans->Read(buf.get(), 10, callback.callback());
@@ -7028,10 +7055,10 @@ TEST(HttpCache, StopCachingTruncatedEntry) {
{
// Now make a regular request.
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.CreateTransaction(&trans));
+ ASSERT_THAT(cache.CreateTransaction(&trans), IsOk());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
scoped_refptr<IOBuffer> buf(new IOBuffer(256));
rv = trans->Read(buf.get(), 10, callback.callback());
@@ -7285,7 +7312,7 @@ TEST_P(HttpCacheHugeResourceTest,
}
rv = http_transaction->Start(&request, callback.callback(),
- net::BoundNetLog());
+ NetLogWithSource());
rv = callback.GetResult(rv);
ASSERT_EQ(net::OK, rv);
@@ -7370,7 +7397,7 @@ TEST(HttpCache, SetPriority) {
MockHttpCache cache;
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.http_cache()->CreateTransaction(IDLE, &trans));
+ ASSERT_THAT(cache.http_cache()->CreateTransaction(IDLE, &trans), IsOk());
// Shouldn't crash, but doesn't do anything either.
trans->SetPriority(LOW);
@@ -7383,7 +7410,7 @@ TEST(HttpCache, SetPriority) {
info.url = GURL(kSimpleGET_Transaction.url);
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
- trans->Start(&info, callback.callback(), BoundNetLog()));
+ trans->Start(&info, callback.callback(), NetLogWithSource()));
EXPECT_TRUE(cache.network_layer()->last_transaction());
if (cache.network_layer()->last_transaction()) {
@@ -7398,7 +7425,7 @@ TEST(HttpCache, SetPriority) {
EXPECT_EQ(HIGHEST, cache.network_layer()->last_transaction()->priority());
}
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
}
// Make sure that calling SetWebSocketHandshakeStreamCreateHelper on a cache
@@ -7408,7 +7435,7 @@ TEST(HttpCache, SetWebSocketHandshakeStreamCreateHelper) {
FakeWebSocketHandshakeStreamCreateHelper create_helper;
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.http_cache()->CreateTransaction(IDLE, &trans));
+ ASSERT_THAT(cache.http_cache()->CreateTransaction(IDLE, &trans), IsOk());
EXPECT_FALSE(cache.network_layer()->last_transaction());
@@ -7416,7 +7443,7 @@ TEST(HttpCache, SetWebSocketHandshakeStreamCreateHelper) {
info.url = GURL(kSimpleGET_Transaction.url);
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
- trans->Start(&info, callback.callback(), BoundNetLog()));
+ trans->Start(&info, callback.callback(), NetLogWithSource()));
ASSERT_TRUE(cache.network_layer()->last_transaction());
EXPECT_FALSE(cache.network_layer()->last_transaction()->
@@ -7425,7 +7452,7 @@ TEST(HttpCache, SetWebSocketHandshakeStreamCreateHelper) {
EXPECT_EQ(&create_helper,
cache.network_layer()->last_transaction()->
websocket_handshake_stream_create_helper());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
}
// Make sure that a cache transaction passes on its priority to
@@ -7448,15 +7475,15 @@ TEST(HttpCache, SetPriorityNewTransaction) {
transaction.data = kFullRangeData;
std::unique_ptr<HttpTransaction> trans;
- ASSERT_EQ(OK, cache.http_cache()->CreateTransaction(MEDIUM, &trans));
+ ASSERT_THAT(cache.http_cache()->CreateTransaction(MEDIUM, &trans), IsOk());
EXPECT_EQ(DEFAULT_PRIORITY,
cache.network_layer()->last_create_transaction_priority());
MockHttpRequest info(transaction);
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
- trans->Start(&info, callback.callback(), BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
+ trans->Start(&info, callback.callback(), NetLogWithSource()));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(MEDIUM, cache.network_layer()->last_create_transaction_priority());
@@ -7476,9 +7503,9 @@ void RunTransactionAndGetNetworkBytes(MockHttpCache& cache,
const MockTransaction& trans_info,
int64_t* sent_bytes,
int64_t* received_bytes) {
- RunTransactionTestBase(cache.http_cache(), trans_info,
- MockHttpRequest(trans_info), nullptr, BoundNetLog(),
- nullptr, sent_bytes, received_bytes, nullptr);
+ RunTransactionTestBase(
+ cache.http_cache(), trans_info, MockHttpRequest(trans_info), nullptr,
+ NetLogWithSource(), nullptr, sent_bytes, received_bytes, nullptr);
}
} // namespace
@@ -7842,11 +7869,11 @@ TEST(HttpCache, RangeGET_MultipleRequests) {
TestCompletionCallback callback;
std::unique_ptr<HttpTransaction> trans;
int rv = cache.http_cache()->CreateTransaction(DEFAULT_PRIORITY, &trans);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
ASSERT_TRUE(trans.get());
// Start our transaction.
- trans->Start(&request, callback.callback(), BoundNetLog());
+ trans->Start(&request, callback.callback(), NetLogWithSource());
// A second transaction on a different part of the file (the default
// kRangeGET_TransactionOK requests 40-49) should not be blocked by
@@ -7871,10 +7898,10 @@ TEST(HttpCache, NoStoreResponseShouldNotBlockFollowingRequests) {
std::unique_ptr<Context> first(new Context);
first->result = cache.CreateTransaction(&first->trans);
- ASSERT_EQ(OK, first->result);
+ ASSERT_THAT(first->result, IsOk());
EXPECT_EQ(LOAD_STATE_IDLE, first->trans->GetLoadState());
- first->result =
- first->trans->Start(&request, first->callback.callback(), BoundNetLog());
+ first->result = first->trans->Start(&request, first->callback.callback(),
+ NetLogWithSource());
EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, first->trans->GetLoadState());
base::RunLoop().RunUntilIdle();
@@ -7887,10 +7914,10 @@ TEST(HttpCache, NoStoreResponseShouldNotBlockFollowingRequests) {
// Let us create the second (read) transaction.
std::unique_ptr<Context> second(new Context);
second->result = cache.CreateTransaction(&second->trans);
- ASSERT_EQ(OK, second->result);
+ ASSERT_THAT(second->result, IsOk());
EXPECT_EQ(LOAD_STATE_IDLE, second->trans->GetLoadState());
second->result = second->trans->Start(&request, second->callback.callback(),
- BoundNetLog());
+ NetLogWithSource());
// Here the second transaction proceeds without reading the first body.
EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, second->trans->GetLoadState());
diff --git a/chromium/net/http/http_chunked_decoder.cc b/chromium/net/http/http_chunked_decoder.cc
index 7aa4a965cd7..fab94342adb 100644
--- a/chromium/net/http/http_chunked_decoder.cc
+++ b/chromium/net/http/http_chunked_decoder.cc
@@ -69,9 +69,12 @@ HttpChunkedDecoder::HttpChunkedDecoder()
int HttpChunkedDecoder::FilterBuf(char* buf, int buf_len) {
int result = 0;
- while (buf_len) {
- if (chunk_remaining_) {
- int num = std::min(chunk_remaining_, buf_len);
+ while (buf_len > 0) {
+ if (chunk_remaining_ > 0) {
+ // Since |chunk_remaining_| is positive and |buf_len| an int, the minimum
+ // of the two must be an int.
+ int num = static_cast<int>(
+ std::min(chunk_remaining_, static_cast<int64_t>(buf_len)));
buf_len -= num;
chunk_remaining_ -= num;
@@ -79,8 +82,8 @@ int HttpChunkedDecoder::FilterBuf(char* buf, int buf_len) {
result += num;
buf += num;
- // After each chunk's data there should be a CRLF
- if (!chunk_remaining_)
+ // After each chunk's data there should be a CRLF.
+ if (chunk_remaining_ == 0)
chunk_terminator_remaining_ = true;
continue;
} else if (reached_eof_) {
@@ -93,7 +96,7 @@ int HttpChunkedDecoder::FilterBuf(char* buf, int buf_len) {
return bytes_consumed; // Error
buf_len -= bytes_consumed;
- if (buf_len)
+ if (buf_len > 0)
memmove(buf, buf + bytes_consumed, buf_len);
}
@@ -121,17 +124,17 @@ int HttpChunkedDecoder::ScanForChunkRemaining(const char* buf, int buf_len) {
}
if (reached_last_chunk_) {
- if (buf_len)
+ if (buf_len > 0)
DVLOG(1) << "ignoring http trailer";
else
reached_eof_ = true;
} else if (chunk_terminator_remaining_) {
- if (buf_len) {
+ if (buf_len > 0) {
DLOG(ERROR) << "chunk data not terminated properly";
return ERR_INVALID_CHUNKED_ENCODING;
}
chunk_terminator_remaining_ = false;
- } else if (buf_len) {
+ } else if (buf_len > 0) {
// Ignore any chunk-extensions.
size_t index_of_semicolon = base::StringPiece(buf, buf_len).find(';');
if (index_of_semicolon != base::StringPiece::npos)
@@ -189,14 +192,16 @@ int HttpChunkedDecoder::ScanForChunkRemaining(const char* buf, int buf_len) {
// known sites.
//
// Us: ^\X+[ ]*$
-bool HttpChunkedDecoder::ParseChunkSize(const char* start, int len, int* out) {
+bool HttpChunkedDecoder::ParseChunkSize(const char* start,
+ int len,
+ int64_t* out) {
DCHECK_GE(len, 0);
// Strip trailing spaces
- while (len && start[len - 1] == ' ')
+ while (len > 0 && start[len - 1] == ' ')
len--;
- // Be more restrictive than HexStringToInt;
+ // Be more restrictive than HexStringToInt64;
// don't allow inputs with leading "-", "+", "0x", "0X"
base::StringPiece chunk_size(start, len);
if (chunk_size.find_first_not_of("0123456789abcdefABCDEF")
@@ -204,8 +209,8 @@ bool HttpChunkedDecoder::ParseChunkSize(const char* start, int len, int* out) {
return false;
}
- int parsed_number;
- bool ok = base::HexStringToInt(chunk_size, &parsed_number);
+ int64_t parsed_number;
+ bool ok = base::HexStringToInt64(chunk_size, &parsed_number);
if (ok && parsed_number >= 0) {
*out = parsed_number;
return true;
diff --git a/chromium/net/http/http_chunked_decoder.h b/chromium/net/http/http_chunked_decoder.h
index 87412deb102..2ff55f98291 100644
--- a/chromium/net/http/http_chunked_decoder.h
+++ b/chromium/net/http/http_chunked_decoder.h
@@ -46,6 +46,7 @@
#define NET_HTTP_HTTP_CHUNKED_DECODER_H_
#include <stddef.h>
+#include <stdint.h>
#include <string>
@@ -107,10 +108,10 @@ class NET_EXPORT_PRIVATE HttpChunkedDecoder {
// Converts string |start| of length |len| to a numeric value.
// |start| is a string of type "chunk-size" (hex string).
// If the conversion succeeds, returns true and places the result in |out|.
- static bool ParseChunkSize(const char* start, int len, int* out);
+ static bool ParseChunkSize(const char* start, int len, int64_t* out);
// Indicates the number of bytes remaining for the current chunk.
- int chunk_remaining_;
+ int64_t chunk_remaining_;
// A small buffer used to store a partial chunk marker.
std::string line_buf_;
diff --git a/chromium/net/http/http_chunked_decoder_unittest.cc b/chromium/net/http/http_chunked_decoder_unittest.cc
index 2cd4fc172d3..2d2898c3347 100644
--- a/chromium/net/http/http_chunked_decoder_unittest.cc
+++ b/chromium/net/http/http_chunked_decoder_unittest.cc
@@ -5,10 +5,19 @@
#include "net/http/http_chunked_decoder.h"
#include <memory>
+#include <string>
+#include <vector>
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
#include "net/base/net_errors.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -49,7 +58,7 @@ void RunTestUntilFailure(const char* const inputs[],
std::string input = inputs[i];
int n = decoder.FilterBuf(&input[0], static_cast<int>(input.size()));
if (n < 0) {
- EXPECT_EQ(ERR_INVALID_CHUNKED_ENCODING, n);
+ EXPECT_THAT(n, IsError(ERR_INVALID_CHUNKED_ENCODING));
EXPECT_EQ(fail_index, i);
return;
}
@@ -286,10 +295,70 @@ TEST(HttpChunkedDecoderTest, InvalidConsecutiveCRLFs) {
RunTestUntilFailure(inputs, arraysize(inputs), 1);
}
-TEST(HttpChunkedDecoderTest, ExcessiveChunkLen) {
- const char* const inputs[] = {
- "c0000000\r\nhello\r\n"
+TEST(HttpChunkedDecoderTest, ReallyBigChunks) {
+ // Number of bytes sent through the chunked decoder per loop iteration. To
+ // minimize runtime, should be the square root of the chunk lengths, below.
+ const int64_t kWrittenBytesPerIteration = 0x10000;
+
+ // Length of chunks to test. Must be multiples of kWrittenBytesPerIteration.
+ int64_t kChunkLengths[] = {
+ // Overflows when cast to a signed int32.
+ 0x0c0000000,
+ // Overflows when cast to an unsigned int32.
+ 0x100000000,
};
+
+ for (int64_t chunk_length : kChunkLengths) {
+ HttpChunkedDecoder decoder;
+ EXPECT_FALSE(decoder.reached_eof());
+
+ // Feed just the header to the decode.
+ std::string chunk_header =
+ base::StringPrintf("%" PRIx64 "\r\n", chunk_length);
+ std::vector<char> data(chunk_header.begin(), chunk_header.end());
+ EXPECT_EQ(OK, decoder.FilterBuf(data.data(), data.size()));
+ EXPECT_FALSE(decoder.reached_eof());
+
+ // Set |data| to be kWrittenBytesPerIteration long, and have a repeating
+ // pattern.
+ data.clear();
+ data.reserve(kWrittenBytesPerIteration);
+ for (size_t i = 0; i < kWrittenBytesPerIteration; i++) {
+ data.push_back(static_cast<char>(i));
+ }
+
+ // Repeatedly feed the data to the chunked decoder. Since the data doesn't
+ // include any chunk lengths, the decode will never have to move the data,
+ // and should run fairly quickly.
+ for (int64_t total_written = 0; total_written < chunk_length;
+ total_written += kWrittenBytesPerIteration) {
+ EXPECT_EQ(kWrittenBytesPerIteration,
+ decoder.FilterBuf(data.data(), kWrittenBytesPerIteration));
+ EXPECT_FALSE(decoder.reached_eof());
+ }
+
+ // Chunk terminator and the final chunk.
+ char final_chunk[] = "\r\n0\r\n\r\n";
+ EXPECT_EQ(OK, decoder.FilterBuf(final_chunk, arraysize(final_chunk)));
+ EXPECT_TRUE(decoder.reached_eof());
+
+ // Since |data| never included any chunk headers, it should not have been
+ // modified.
+ for (size_t i = 0; i < kWrittenBytesPerIteration; i++) {
+ EXPECT_EQ(static_cast<char>(i), data[i]);
+ }
+ }
+}
+
+TEST(HttpChunkedDecoderTest, ExcessiveChunkLen) {
+ // Smallest number that can't be represented as a signed int64.
+ const char* const inputs[] = {"8000000000000000\r\nhello\r\n"};
+ RunTestUntilFailure(inputs, arraysize(inputs), 0);
+}
+
+TEST(HttpChunkedDecoderTest, ExcessiveChunkLen2) {
+ // Smallest number that can't be represented as an unsigned int64.
+ const char* const inputs[] = {"10000000000000000\r\nhello\r\n"};
RunTestUntilFailure(inputs, arraysize(inputs), 0);
}
diff --git a/chromium/net/http/http_content_disposition.cc b/chromium/net/http/http_content_disposition.cc
index 3f7d6b5f8a1..05f3e1930d3 100644
--- a/chromium/net/http/http_content_disposition.cc
+++ b/chromium/net/http/http_content_disposition.cc
@@ -6,6 +6,7 @@
#include "base/base64.h"
#include "base/logging.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
@@ -344,33 +345,30 @@ HttpContentDisposition::~HttpContentDisposition() {
std::string::const_iterator HttpContentDisposition::ConsumeDispositionType(
std::string::const_iterator begin, std::string::const_iterator end) {
DCHECK(type_ == INLINE);
- std::string::const_iterator delimiter = std::find(begin, end, ';');
-
- std::string::const_iterator type_begin = begin;
- std::string::const_iterator type_end = delimiter;
- HttpUtil::TrimLWS(&type_begin, &type_end);
+ base::StringPiece header(begin, end);
+ size_t delimiter = header.find(';');
+ base::StringPiece type = header.substr(0, delimiter);
+ type = HttpUtil::TrimLWS(type);
// If the disposition-type isn't a valid token the then the
// Content-Disposition header is malformed, and we treat the first bytes as
// a parameter rather than a disposition-type.
- if (!HttpUtil::IsToken(type_begin, type_end))
+ if (type.empty() || !HttpUtil::IsToken(type))
return begin;
parse_result_flags_ |= HAS_DISPOSITION_TYPE;
- DCHECK(std::find(type_begin, type_end, '=') == type_end);
+ DCHECK(type.find('=') == base::StringPiece::npos);
- if (base::LowerCaseEqualsASCII(base::StringPiece(type_begin, type_end),
- "inline")) {
+ if (base::LowerCaseEqualsASCII(type, "inline")) {
type_ = INLINE;
- } else if (base::LowerCaseEqualsASCII(base::StringPiece(type_begin, type_end),
- "attachment")) {
+ } else if (base::LowerCaseEqualsASCII(type, "attachment")) {
type_ = ATTACHMENT;
} else {
parse_result_flags_ |= HAS_UNKNOWN_DISPOSITION_TYPE;
type_ = ATTACHMENT;
}
- return delimiter;
+ return begin + (type.data() + type.size() - header.data());
}
// http://tools.ietf.org/html/rfc6266
diff --git a/chromium/net/http/http_log_util.cc b/chromium/net/http/http_log_util.cc
index 9d86c4de31d..f92d3eee9e7 100644
--- a/chromium/net/http/http_log_util.cc
+++ b/chromium/net/http/http_log_util.cc
@@ -11,6 +11,7 @@
#include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/http_auth_scheme.h"
#include "net/http/http_util.h"
+#include "net/log/net_log_capture_mode.h"
namespace net {
diff --git a/chromium/net/http/http_log_util.h b/chromium/net/http/http_log_util.h
index ce4713930a7..3b8103c2223 100644
--- a/chromium/net/http/http_log_util.h
+++ b/chromium/net/http/http_log_util.h
@@ -9,7 +9,6 @@
#include "base/strings/string_piece.h"
#include "net/base/net_export.h"
-#include "net/log/net_log.h"
#include "net/spdy/spdy_header_block.h"
namespace base {
@@ -18,6 +17,8 @@ class ListValue;
namespace net {
+class NetLogCaptureMode;
+
// Given an HTTP header |header| with value |value|, returns the elided version
// of the header value at |log_level|.
NET_EXPORT_PRIVATE std::string ElideHeaderValueForNetLog(
diff --git a/chromium/net/http/http_log_util_unittest.cc b/chromium/net/http/http_log_util_unittest.cc
index 6b8d48e378f..5905f973c98 100644
--- a/chromium/net/http/http_log_util_unittest.cc
+++ b/chromium/net/http/http_log_util_unittest.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "net/http/http_log_util.h"
+
+#include "net/log/net_log_capture_mode.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
diff --git a/chromium/net/http/http_network_layer_unittest.cc b/chromium/net/http/http_network_layer_unittest.cc
index 19fb17c323f..f3dd8cbfa65 100644
--- a/chromium/net/http/http_network_layer_unittest.cc
+++ b/chromium/net/http/http_network_layer_unittest.cc
@@ -15,14 +15,19 @@
#include "net/http/http_server_properties_impl.h"
#include "net/http/http_transaction_test_util.h"
#include "net/http/transport_security_state.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_service.h"
#include "net/socket/socket_test_util.h"
#include "net/spdy/spdy_session_pool.h"
#include "net/ssl/ssl_config_service_defaults.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -66,16 +71,16 @@ class HttpNetworkLayerTest : public PlatformTest {
std::unique_ptr<HttpTransaction> trans;
int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
+ rv = trans->Start(&request_info, callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
std::string contents;
rv = ReadTransaction(trans.get(), &contents);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ(content, contents);
if (!header.empty()) {
@@ -273,28 +278,28 @@ class HttpNetworkLayerTest : public PlatformTest {
TEST_F(HttpNetworkLayerTest, CreateAndDestroy) {
std::unique_ptr<HttpTransaction> trans;
int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(trans.get() != NULL);
}
TEST_F(HttpNetworkLayerTest, Suspend) {
std::unique_ptr<HttpTransaction> trans;
int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
trans.reset();
factory_->OnSuspend();
rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans);
- EXPECT_EQ(ERR_NETWORK_IO_SUSPENDED, rv);
+ EXPECT_THAT(rv, IsError(ERR_NETWORK_IO_SUSPENDED));
ASSERT_TRUE(trans == NULL);
factory_->OnResume();
rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
TEST_F(HttpNetworkLayerTest, GET) {
@@ -324,15 +329,15 @@ TEST_F(HttpNetworkLayerTest, GET) {
std::unique_ptr<HttpTransaction> trans;
int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
+ rv = trans->Start(&request_info, callback.callback(), NetLogWithSource());
rv = callback.GetResult(rv);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
std::string contents;
rv = ReadTransaction(trans.get(), &contents);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("hello world", contents);
}
@@ -363,10 +368,10 @@ TEST_F(HttpNetworkLayerTest, NetworkVerified) {
std::unique_ptr<HttpTransaction> trans;
int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
- ASSERT_EQ(OK, callback.GetResult(rv));
+ rv = trans->Start(&request_info, callback.callback(), NetLogWithSource());
+ ASSERT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(trans->GetResponseInfo()->network_accessed);
}
@@ -396,10 +401,10 @@ TEST_F(HttpNetworkLayerTest, NetworkUnVerified) {
std::unique_ptr<HttpTransaction> trans;
int rv = factory_->CreateTransaction(DEFAULT_PRIORITY, &trans);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
- ASSERT_EQ(ERR_CONNECTION_RESET, callback.GetResult(rv));
+ rv = trans->Start(&request_info, callback.callback(), NetLogWithSource());
+ ASSERT_THAT(callback.GetResult(rv), IsError(ERR_CONNECTION_RESET));
// network_accessed is true; the HTTP stack did try to make a connection.
EXPECT_TRUE(trans->GetResponseInfo()->network_accessed);
diff --git a/chromium/net/http/http_network_session.cc b/chromium/net/http/http_network_session.cc
index 77b2ebd1af1..d6152b27ef0 100644
--- a/chromium/net/http/http_network_session.cc
+++ b/chromium/net/http/http_network_session.cc
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/debug/stack_trace.h"
#include "base/logging.h"
+#include "base/memory/memory_coordinator_client_registry.h"
#include "base/profiler/scoped_tracker.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@@ -20,12 +21,12 @@
#include "net/http/http_stream_factory_impl.h"
#include "net/http/url_security_manager.h"
#include "net/proxy/proxy_service.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_crypto_client_stream_factory.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_stream_factory.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/chromium/quic_stream_factory.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_crypto_client_stream_factory.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_utils.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/client_socket_pool_manager_impl.h"
#include "net/socket/next_proto.h"
@@ -66,11 +67,6 @@ const int32_t kSpdyStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
// and does not consume "too much" memory.
const int32_t kQuicSocketReceiveBufferSize = 1024 * 1024; // 1MB
-// Number of recent connections to consider for certain thresholds
-// that trigger disabling QUIC. E.g. disable QUIC if PUBLIC_RESET was
-// received post handshake for at least 2 of 20 recent connections.
-const int32_t kQuicMaxRecentDisabledReasons = 20;
-
HttpNetworkSession::Params::Params()
: client_socket_factory(NULL),
host_resolver(NULL),
@@ -90,16 +86,12 @@ HttpNetworkSession::Params::Params()
testing_fixed_https_port(0),
enable_tcp_fast_open_for_ssl(false),
enable_spdy_ping_based_connection_checking(true),
- spdy_default_protocol(kProtoUnknown),
- enable_spdy31(false),
enable_http2(true),
spdy_session_max_recv_window_size(kSpdySessionMaxRecvWindowSize),
spdy_stream_max_recv_window_size(kSpdyStreamMaxRecvWindowSize),
time_func(&base::TimeTicks::Now),
enable_http2_alternative_service_with_different_host(false),
enable_quic_alternative_service_with_different_host(true),
- enable_npn(false),
- enable_priority_dependencies(true),
enable_quic(false),
disable_quic_on_timeout_with_open_streams(false),
enable_quic_port_selection(true),
@@ -110,8 +102,6 @@ HttpNetworkSession::Params::Params()
quic_enable_non_blocking_io(false),
quic_disable_disk_cache(false),
quic_prefer_aes(false),
- quic_max_number_of_lossy_connections(0),
- quic_packet_loss_threshold(1.0f),
quic_socket_receive_buffer_size(kQuicSocketReceiveBufferSize),
quic_delay_tcp_race(true),
quic_max_server_configs_stored_in_properties(0u),
@@ -121,18 +111,23 @@ HttpNetworkSession::Params::Params()
enable_user_alternate_protocol_ports(false),
quic_crypto_client_stream_factory(
QuicCryptoClientStreamFactory::GetDefaultFactory()),
- quic_max_recent_disabled_reasons(kQuicMaxRecentDisabledReasons),
- quic_threshold_public_resets_post_handshake(0),
- quic_threshold_timeouts_streams_open(0),
quic_close_sessions_on_ip_change(false),
quic_idle_connection_timeout_seconds(kIdleConnectionTimeoutSeconds),
+ quic_reduced_ping_timeout_seconds(kPingTimeoutSecs),
+ quic_packet_reader_yield_after_duration_milliseconds(
+ kQuicYieldAfterDurationMilliseconds),
quic_disable_preconnect_if_0rtt(false),
quic_migrate_sessions_on_network_change(false),
quic_migrate_sessions_early(false),
+ quic_allow_server_migration(false),
quic_disable_bidirectional_streams(false),
+ quic_force_hol_blocking(false),
+ quic_race_cert_verification(false),
+ quic_do_not_fragment(false),
proxy_delegate(NULL),
- enable_token_binding(false) {
- quic_supported_versions.push_back(QUIC_VERSION_34);
+ enable_token_binding(false),
+ http_09_on_non_default_ports_enabled(false) {
+ quic_supported_versions.push_back(QUIC_VERSION_35);
}
HttpNetworkSession::Params::Params(const Params& other) = default;
@@ -155,6 +150,7 @@ HttpNetworkSession::HttpNetworkSession(const Params& params)
? params.client_socket_factory
: ClientSocketFactory::GetDefaultFactory(),
params.http_server_properties,
+ params.proxy_delegate,
params.cert_verifier,
params.ct_policy_enforcer,
params.channel_id_service,
@@ -175,19 +171,20 @@ HttpNetworkSession::HttpNetworkSession(const Params& params)
params.quic_enable_non_blocking_io,
params.quic_disable_disk_cache,
params.quic_prefer_aes,
- params.quic_max_number_of_lossy_connections,
- params.quic_packet_loss_threshold,
- params.quic_max_recent_disabled_reasons,
- params.quic_threshold_public_resets_post_handshake,
- params.quic_threshold_timeouts_streams_open,
params.quic_socket_receive_buffer_size,
params.quic_delay_tcp_race,
params.quic_max_server_configs_stored_in_properties,
params.quic_close_sessions_on_ip_change,
params.disable_quic_on_timeout_with_open_streams,
params.quic_idle_connection_timeout_seconds,
+ params.quic_reduced_ping_timeout_seconds,
+ params.quic_packet_reader_yield_after_duration_milliseconds,
params.quic_migrate_sessions_on_network_change,
params.quic_migrate_sessions_early,
+ params.quic_allow_server_migration,
+ params.quic_force_hol_blocking,
+ params.quic_race_cert_verification,
+ params.quic_do_not_fragment,
params.quic_connection_options,
params.enable_token_binding),
spdy_session_pool_(params.host_resolver,
@@ -195,8 +192,6 @@ HttpNetworkSession::HttpNetworkSession(const Params& params)
params.http_server_properties,
params.transport_security_state,
params.enable_spdy_ping_based_connection_checking,
- params.enable_priority_dependencies,
- params.spdy_default_protocol,
params.spdy_session_max_recv_window_size,
params.spdy_stream_max_recv_window_size,
params.time_func,
@@ -215,53 +210,34 @@ HttpNetworkSession::HttpNetworkSession(const Params& params)
websocket_socket_pool_manager_.reset(CreateSocketPoolManager(
WEBSOCKET_SOCKET_POOL, params, ssl_session_cache_shard));
- for (int i = ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION;
- i <= ALTERNATE_PROTOCOL_MAXIMUM_VALID_VERSION; ++i) {
- enabled_protocols_[i - ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION] = false;
- }
-
- // TODO(rtenneti): https://crbug.com/116575
- // Consider combining the NextProto and AlternateProtocol.
if (params_.enable_http2) {
next_protos_.push_back(kProtoHTTP2);
- AlternateProtocol alternate = AlternateProtocolFromNextProto(kProtoHTTP2);
- enabled_protocols_[alternate - ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION] =
- true;
- }
-
- if (params_.enable_spdy31) {
- next_protos_.push_back(kProtoSPDY31);
- AlternateProtocol alternate = AlternateProtocolFromNextProto(kProtoSPDY31);
- enabled_protocols_[alternate - ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION] =
- true;
- }
-
- if (params_.enable_quic) {
- AlternateProtocol alternate =
- AlternateProtocolFromNextProto(kProtoQUIC1SPDY3);
- enabled_protocols_[alternate - ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION] =
- true;
}
next_protos_.push_back(kProtoHTTP11);
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))));
+ base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this);
}
HttpNetworkSession::~HttpNetworkSession() {
- STLDeleteElements(&response_drainers_);
+ base::STLDeleteElements(&response_drainers_);
spdy_session_pool_.CloseAllSessions();
+ base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(this);
}
void HttpNetworkSession::AddResponseDrainer(HttpResponseBodyDrainer* drainer) {
- DCHECK(!ContainsKey(response_drainers_, drainer));
+ DCHECK(!base::ContainsKey(response_drainers_, drainer));
response_drainers_.insert(drainer);
}
void HttpNetworkSession::RemoveResponseDrainer(
HttpResponseBodyDrainer* drainer) {
- DCHECK(ContainsKey(response_drainers_, drainer));
+ DCHECK(base::ContainsKey(response_drainers_, drainer));
response_drainers_.erase(drainer);
}
@@ -332,20 +308,24 @@ std::unique_ptr<base::Value> HttpNetworkSession::QuicInfoToValue() const {
params_.quic_enable_connection_racing);
dict->SetBoolean("disable_disk_cache", params_.quic_disable_disk_cache);
dict->SetBoolean("prefer_aes", params_.quic_prefer_aes);
- dict->SetInteger("max_number_of_lossy_connections",
- params_.quic_max_number_of_lossy_connections);
- dict->SetDouble("packet_loss_threshold", params_.quic_packet_loss_threshold);
dict->SetBoolean("delay_tcp_race", params_.quic_delay_tcp_race);
dict->SetInteger("max_server_configs_stored_in_properties",
params_.quic_max_server_configs_stored_in_properties);
dict->SetInteger("idle_connection_timeout_seconds",
params_.quic_idle_connection_timeout_seconds);
+ dict->SetInteger("reduced_ping_timeout_seconds",
+ params_.quic_reduced_ping_timeout_seconds);
+ dict->SetInteger(
+ "packet_reader_yield_after_duration_milliseconds",
+ params_.quic_packet_reader_yield_after_duration_milliseconds);
dict->SetBoolean("disable_preconnect_if_0rtt",
params_.quic_disable_preconnect_if_0rtt);
dict->SetBoolean("disable_quic_on_timeout_with_open_streams",
params_.disable_quic_on_timeout_with_open_streams);
- dict->SetString("disabled_reason",
- quic_stream_factory_.QuicDisabledReasonString());
+ dict->SetBoolean("is_quic_disabled", quic_stream_factory_.IsQuicDisabled());
+ dict->SetBoolean("force_hol_blocking", params_.quic_force_hol_blocking);
+ dict->SetBoolean("race_cert_verification",
+ params_.quic_race_cert_verification);
return std::move(dict);
}
@@ -363,31 +343,21 @@ void HttpNetworkSession::CloseIdleConnections() {
}
bool HttpNetworkSession::IsProtocolEnabled(AlternateProtocol protocol) const {
- DCHECK(IsAlternateProtocolValid(protocol));
- return enabled_protocols_[
- protocol - ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION];
-}
-
-void HttpNetworkSession::GetAlpnProtos(NextProtoVector* alpn_protos) const {
- if (HttpStreamFactory::spdy_enabled()) {
- *alpn_protos = next_protos_;
- } else {
- // HttpStreamFactory::spdy_enabled() only affects SPDY/3.1,
- // but not other ALPN protocols.
- alpn_protos->clear();
- for (auto proto : next_protos_) {
- if (proto != kProtoSPDY31)
- alpn_protos->push_back(proto);
- }
+ switch (protocol) {
+ case NPN_HTTP_2:
+ return params_.enable_http2;
+ case QUIC:
+ return params_.enable_quic;
+ case UNINITIALIZED_ALTERNATE_PROTOCOL:
+ NOTREACHED();
+ return false;
}
+ NOTREACHED();
+ return false;
}
-void HttpNetworkSession::GetNpnProtos(NextProtoVector* npn_protos) const {
- if (HttpStreamFactory::spdy_enabled() && params_.enable_npn) {
- *npn_protos = next_protos_;
- } else {
- npn_protos->clear();
- }
+void HttpNetworkSession::GetAlpnProtos(NextProtoVector* alpn_protos) const {
+ *alpn_protos = next_protos_;
}
void HttpNetworkSession::GetSSLConfig(const HttpRequestInfo& request,
@@ -395,7 +365,6 @@ void HttpNetworkSession::GetSSLConfig(const HttpRequestInfo& request,
SSLConfig* proxy_config) const {
ssl_config_service_->GetSSLConfig(server_config);
GetAlpnProtos(&server_config->alpn_protos);
- GetNpnProtos(&server_config->npn_protos);
*proxy_config = *server_config;
if (request.privacy_mode == PRIVACY_MODE_ENABLED) {
server_config->channel_id_enabled = false;
@@ -418,4 +387,34 @@ ClientSocketPoolManager* HttpNetworkSession::GetSocketPoolManager(
return NULL;
}
+void HttpNetworkSession::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+ switch (memory_pressure_level) {
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+ break;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+ CloseIdleConnections();
+ break;
+ }
+}
+
+void HttpNetworkSession::OnMemoryStateChange(base::MemoryState state) {
+ // TODO(hajimehoshi): When the state changes, adjust the sizes of the caches
+ // to reduce the limits. HttpNetworkSession doesn't have the ability to limit
+ // at present.
+ switch (state) {
+ case base::MemoryState::NORMAL:
+ break;
+ case base::MemoryState::THROTTLED:
+ CloseIdleConnections();
+ break;
+ case base::MemoryState::SUSPENDED:
+ // Note: Not supported at present. Fall through.
+ case base::MemoryState::UNKNOWN:
+ NOTREACHED();
+ break;
+ }
+}
+
} // namespace net
diff --git a/chromium/net/http/http_network_session.h b/chromium/net/http/http_network_session.h
index fd3b0961dce..07a7d72f8d2 100644
--- a/chromium/net/http/http_network_session.h
+++ b/chromium/net/http/http_network_session.h
@@ -13,6 +13,9 @@
#include <unordered_set>
#include <vector>
+#include "base/bind.h"
+#include "base/memory/memory_coordinator_client.h"
+#include "base/memory/memory_pressure_monitor.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/non_thread_safe.h"
@@ -21,7 +24,7 @@
#include "net/dns/host_resolver.h"
#include "net/http/http_auth_cache.h"
#include "net/http/http_stream_factory.h"
-#include "net/quic/quic_stream_factory.h"
+#include "net/quic/chromium/quic_stream_factory.h"
#include "net/socket/next_proto.h"
#include "net/spdy/spdy_session_pool.h"
#include "net/ssl/ssl_client_auth_cache.h"
@@ -59,7 +62,8 @@ class TransportSecurityState;
// This class holds session objects used by HttpNetworkTransaction objects.
class NET_EXPORT HttpNetworkSession
- : NON_EXPORTED_BASE(public base::NonThreadSafe) {
+ : NON_EXPORTED_BASE(public base::NonThreadSafe),
+ public base::MemoryCoordinatorClient {
public:
struct NET_EXPORT Params {
Params();
@@ -87,8 +91,6 @@ class NET_EXPORT HttpNetworkSession
// Use SPDY ping frames to test for connection health after idle.
bool enable_spdy_ping_based_connection_checking;
- NextProto spdy_default_protocol;
- bool enable_spdy31;
bool enable_http2;
size_t spdy_session_max_recv_window_size;
size_t spdy_stream_max_recv_window_size;
@@ -101,12 +103,6 @@ class NET_EXPORT HttpNetworkSession
// of the origin.
bool enable_quic_alternative_service_with_different_host;
- // Enables NPN support. Note that ALPN is always enabled.
- bool enable_npn;
-
- // Enable setting of HTTP/2 dependencies based on priority.
- bool enable_priority_dependencies;
-
// Enables QUIC support.
bool enable_quic;
// Disable QUIC if a connection times out with open streams.
@@ -131,12 +127,6 @@ class NET_EXPORT HttpNetworkSession
bool quic_disable_disk_cache;
// Prefer AES-GCM to ChaCha20 even if no hardware support is present.
bool quic_prefer_aes;
- // Specifies the maximum number of connections with high packet loss in
- // a row after which QUIC will be disabled.
- int quic_max_number_of_lossy_connections;
- // Specifies packet loss rate in fraction after which a connection is
- // closed and is considered as a lossy connection.
- float quic_packet_loss_threshold;
// Size in bytes of the QUIC DUP socket receive buffer.
int quic_socket_receive_buffer_size;
// Delay starting a TCP connection when QUIC believes it can speak
@@ -161,15 +151,18 @@ class NET_EXPORT HttpNetworkSession
QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory;
// Versions of QUIC which may be used.
QuicVersionVector quic_supported_versions;
- int quic_max_recent_disabled_reasons;
- int quic_threshold_public_resets_post_handshake;
- int quic_threshold_timeouts_streams_open;
// Set of QUIC tags to send in the handshake's connection options.
QuicTagVector quic_connection_options;
// If true, all QUIC sessions are closed when any local IP address changes.
bool quic_close_sessions_on_ip_change;
- // Specifes QUIC idle connection state lifetime.
+ // Specifies QUIC idle connection state lifetime.
int quic_idle_connection_timeout_seconds;
+ // Specifies the reduced ping timeout subsequent connections should use when
+ // a connection was timed out with open streams.
+ int quic_reduced_ping_timeout_seconds;
+ // Specifies the maximum time duration that QUIC packet reader can perform
+ // consecutive packets reading.
+ int quic_packet_reader_yield_after_duration_milliseconds;
// If true, disable preconnections if QUIC can do 0RTT.
bool quic_disable_preconnect_if_0rtt;
// List of hosts for which QUIC is explicitly whitelisted.
@@ -180,12 +173,25 @@ class NET_EXPORT HttpNetworkSession
// If true, active QUIC sessions experiencing poor connectivity may be
// migrated onto a new network.
bool quic_migrate_sessions_early;
+ // If true, allows migration of QUIC connections to a server-specified
+ // alternate server address.
+ bool quic_allow_server_migration;
// If true, bidirectional streams over QUIC will be disabled.
bool quic_disable_bidirectional_streams;
+ // If true, enable force HOL blocking. For measurement purposes.
+ bool quic_force_hol_blocking;
+ // If true, race cert verification with host resolution.
+ bool quic_race_cert_verification;
+ // If true, configure QUIC sockets to not fragment packets.
+ bool quic_do_not_fragment;
ProxyDelegate* proxy_delegate;
// Enable support for Token Binding.
bool enable_token_binding;
+
+ // 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;
};
enum SocketPoolType {
@@ -195,7 +201,7 @@ class NET_EXPORT HttpNetworkSession
};
explicit HttpNetworkSession(const Params& params);
- ~HttpNetworkSession();
+ ~HttpNetworkSession() override;
HttpAuthCache* http_auth_cache() { return &http_auth_cache_; }
SSLClientAuthCache* ssl_client_auth_cache() {
@@ -260,9 +266,6 @@ class NET_EXPORT HttpNetworkSession
// Populates |*alpn_protos| with protocols to be used with ALPN.
void GetAlpnProtos(NextProtoVector* alpn_protos) const;
- // Populates |*npn_protos| with protocols to be used with NPN.
- void GetNpnProtos(NextProtoVector* npn_protos) const;
-
// Populates |server_config| and |proxy_config| based on this session and
// |request|.
void GetSSLConfig(const HttpRequestInfo& request,
@@ -274,6 +277,13 @@ class NET_EXPORT HttpNetworkSession
ClientSocketPoolManager* GetSocketPoolManager(SocketPoolType pool_type);
+ // Flush sockets on low memory notifications callback.
+ void OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
+
+ // base::MemoryCoordinatorClient implementation:
+ void OnMemoryStateChange(base::MemoryState state) override;
+
NetLog* const net_log_;
HttpServerProperties* const http_server_properties_;
CertVerifier* const cert_verifier_;
@@ -294,9 +304,10 @@ class NET_EXPORT HttpNetworkSession
std::set<HttpResponseBodyDrainer*> response_drainers_;
NextProtoVector next_protos_;
- bool enabled_protocols_[NUM_VALID_ALTERNATE_PROTOCOLS];
Params params_;
+
+ std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
};
} // namespace net
diff --git a/chromium/net/http/http_network_session_peer.cc b/chromium/net/http/http_network_session_peer.cc
index df729762345..2cfd3d63c75 100644
--- a/chromium/net/http/http_network_session_peer.cc
+++ b/chromium/net/http/http_network_session_peer.cc
@@ -24,10 +24,6 @@ void HttpNetworkSessionPeer::SetClientSocketPoolManager(
session_->normal_socket_pool_manager_.swap(socket_pool_manager);
}
-void HttpNetworkSessionPeer::SetProxyService(ProxyService* proxy_service) {
- session_->proxy_service_ = proxy_service;
-}
-
void HttpNetworkSessionPeer::SetHttpStreamFactory(
std::unique_ptr<HttpStreamFactory> http_stream_factory) {
session_->http_stream_factory_.swap(http_stream_factory);
diff --git a/chromium/net/http/http_network_session_peer.h b/chromium/net/http/http_network_session_peer.h
index da057f06ab9..8de0bc3f113 100644
--- a/chromium/net/http/http_network_session_peer.h
+++ b/chromium/net/http/http_network_session_peer.h
@@ -27,8 +27,6 @@ class NET_EXPORT_PRIVATE HttpNetworkSessionPeer {
void SetClientSocketPoolManager(
std::unique_ptr<ClientSocketPoolManager> socket_pool_manager);
- void SetProxyService(ProxyService* proxy_service);
-
void SetHttpStreamFactory(
std::unique_ptr<HttpStreamFactory> http_stream_factory);
void SetHttpStreamFactoryForWebSocket(
diff --git a/chromium/net/http/http_network_transaction.cc b/chromium/net/http/http_network_transaction.cc
index 530a1715745..77f925301c3 100644
--- a/chromium/net/http/http_network_transaction.cc
+++ b/chromium/net/http/http_network_transaction.cc
@@ -52,6 +52,8 @@
#include "net/http/http_util.h"
#include "net/http/transport_security_state.h"
#include "net/http/url_security_manager.h"
+#include "net/log/net_log_event_type.h"
+#include "net/proxy/proxy_server.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/socks_client_socket_pool.h"
#include "net/socket/ssl_client_socket.h"
@@ -127,7 +129,7 @@ HttpNetworkTransaction::~HttpNetworkTransaction() {
int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
const CompletionCallback& callback,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
net_log_ = net_log;
request_ = request_info;
@@ -377,13 +379,6 @@ LoadState HttpNetworkTransaction::GetLoadState() const {
}
}
-UploadProgress HttpNetworkTransaction::GetUploadProgress() const {
- if (!stream_.get())
- return UploadProgress();
-
- return stream_->GetUploadProgress();
-}
-
void HttpNetworkTransaction::SetQuicServerInfo(
QuicServerInfo* quic_server_info) {}
@@ -401,7 +396,7 @@ bool HttpNetworkTransaction::GetLoadTimingInfo(
}
bool HttpNetworkTransaction::GetRemoteEndpoint(IPEndPoint* endpoint) const {
- if (!remote_endpoint_.address().size())
+ if (remote_endpoint_.address().empty())
return false;
*endpoint = remote_endpoint_;
@@ -456,13 +451,17 @@ void HttpNetworkTransaction::OnStreamReady(const SSLConfig& used_ssl_config,
stream_.reset(stream);
server_ssl_config_ = used_ssl_config;
proxy_info_ = used_proxy_info;
- response_.was_npn_negotiated = stream_request_->was_npn_negotiated();
- response_.npn_negotiated_protocol = SSLClientSocket::NextProtoToString(
- stream_request_->protocol_negotiated());
+ response_.was_alpn_negotiated = stream_request_->was_alpn_negotiated();
+ response_.alpn_negotiated_protocol = SSLClientSocket::NextProtoToString(
+ stream_request_->negotiated_protocol());
response_.was_fetched_via_spdy = stream_request_->using_spdy();
response_.was_fetched_via_proxy = !proxy_info_.is_direct();
if (response_.was_fetched_via_proxy && !proxy_info_.is_empty())
- response_.proxy_server = proxy_info_.proxy_server().host_port_pair();
+ response_.proxy_server = proxy_info_.proxy_server();
+ else if (!response_.was_fetched_via_proxy && proxy_info_.is_direct())
+ response_.proxy_server = ProxyServer::Direct();
+ else
+ response_.proxy_server = ProxyServer();
OnIOComplete(OK);
}
@@ -699,7 +698,7 @@ int HttpNetworkTransaction::DoLoop(int result) {
break;
case STATE_BUILD_REQUEST:
DCHECK_EQ(OK, rv);
- net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST);
+ net_log_.BeginEvent(NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST);
rv = DoBuildRequest();
break;
case STATE_BUILD_REQUEST_COMPLETE:
@@ -712,38 +711,38 @@ int HttpNetworkTransaction::DoLoop(int result) {
case STATE_SEND_REQUEST_COMPLETE:
rv = DoSendRequestComplete(rv);
net_log_.EndEventWithNetErrorCode(
- NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, rv);
+ NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST, rv);
break;
case STATE_READ_HEADERS:
DCHECK_EQ(OK, rv);
- net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS);
+ net_log_.BeginEvent(NetLogEventType::HTTP_TRANSACTION_READ_HEADERS);
rv = DoReadHeaders();
break;
case STATE_READ_HEADERS_COMPLETE:
rv = DoReadHeadersComplete(rv);
net_log_.EndEventWithNetErrorCode(
- NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, rv);
+ NetLogEventType::HTTP_TRANSACTION_READ_HEADERS, rv);
break;
case STATE_READ_BODY:
DCHECK_EQ(OK, rv);
- net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_READ_BODY);
+ net_log_.BeginEvent(NetLogEventType::HTTP_TRANSACTION_READ_BODY);
rv = DoReadBody();
break;
case STATE_READ_BODY_COMPLETE:
rv = DoReadBodyComplete(rv);
net_log_.EndEventWithNetErrorCode(
- NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, rv);
+ NetLogEventType::HTTP_TRANSACTION_READ_BODY, rv);
break;
case STATE_DRAIN_BODY_FOR_AUTH_RESTART:
DCHECK_EQ(OK, rv);
net_log_.BeginEvent(
- NetLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART);
+ NetLogEventType::HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART);
rv = DoDrainBodyForAuthRestart();
break;
case STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE:
rv = DoDrainBodyForAuthRestartComplete(rv);
net_log_.EndEventWithNetErrorCode(
- NetLog::TYPE_HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART, rv);
+ NetLogEventType::HTTP_TRANSACTION_DRAIN_BODY_FOR_AUTH_RESTART, rv);
break;
default:
NOTREACHED() << "bad state";
@@ -914,7 +913,7 @@ int HttpNetworkTransaction::DoGetProvidedTokenBindingKey() {
if (!IsTokenBindingEnabled())
return OK;
- net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_GET_TOKEN_BINDING_KEY);
+ net_log_.BeginEvent(NetLogEventType::HTTP_TRANSACTION_GET_TOKEN_BINDING_KEY);
ChannelIDService* channel_id_service = session_->params().channel_id_service;
return channel_id_service->GetOrCreateChannelID(
request_->url.host(), &provided_token_binding_key_, io_callback_,
@@ -925,7 +924,7 @@ int HttpNetworkTransaction::DoGetProvidedTokenBindingKeyComplete(int rv) {
DCHECK_NE(ERR_IO_PENDING, rv);
if (IsTokenBindingEnabled()) {
net_log_.EndEventWithNetErrorCode(
- NetLog::TYPE_HTTP_TRANSACTION_GET_TOKEN_BINDING_KEY, rv);
+ NetLogEventType::HTTP_TRANSACTION_GET_TOKEN_BINDING_KEY, rv);
}
if (rv == OK)
@@ -938,7 +937,7 @@ int HttpNetworkTransaction::DoGetReferredTokenBindingKey() {
if (!IsTokenBindingEnabled() || request_->token_binding_referrer.empty())
return OK;
- net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_GET_TOKEN_BINDING_KEY);
+ net_log_.BeginEvent(NetLogEventType::HTTP_TRANSACTION_GET_TOKEN_BINDING_KEY);
ChannelIDService* channel_id_service = session_->params().channel_id_service;
return channel_id_service->GetOrCreateChannelID(
request_->token_binding_referrer, &referred_token_binding_key_,
@@ -949,7 +948,7 @@ int HttpNetworkTransaction::DoGetReferredTokenBindingKeyComplete(int rv) {
DCHECK_NE(ERR_IO_PENDING, rv);
if (IsTokenBindingEnabled() && !request_->token_binding_referrer.empty()) {
net_log_.EndEventWithNetErrorCode(
- NetLog::TYPE_HTTP_TRANSACTION_GET_TOKEN_BINDING_KEY, rv);
+ NetLogEventType::HTTP_TRANSACTION_GET_TOKEN_BINDING_KEY, rv);
}
if (rv == OK)
next_state_ = STATE_INIT_REQUEST_BODY;
@@ -1028,8 +1027,9 @@ int HttpNetworkTransaction::BuildRequestHeaders(
int HttpNetworkTransaction::BuildTokenBindingHeader(std::string* out) {
base::TimeTicks start = base::TimeTicks::Now();
std::vector<uint8_t> signed_ekm;
- int rv = stream_->GetSignedEKMForTokenBinding(
- provided_token_binding_key_.get(), &signed_ekm);
+ int rv = stream_->GetTokenBindingSignature(provided_token_binding_key_.get(),
+ TokenBindingType::PROVIDED,
+ &signed_ekm);
if (rv != OK)
return rv;
std::string provided_token_binding;
@@ -1045,8 +1045,9 @@ int HttpNetworkTransaction::BuildTokenBindingHeader(std::string* out) {
std::string referred_token_binding;
if (referred_token_binding_key_) {
std::vector<uint8_t> referred_signed_ekm;
- int rv = stream_->GetSignedEKMForTokenBinding(
- referred_token_binding_key_.get(), &referred_signed_ekm);
+ int rv = stream_->GetTokenBindingSignature(
+ referred_token_binding_key_.get(), TokenBindingType::REFERRED,
+ &referred_signed_ekm);
if (rv != OK)
return rv;
rv = BuildTokenBinding(TokenBindingType::REFERRED,
@@ -1060,8 +1061,7 @@ int HttpNetworkTransaction::BuildTokenBindingHeader(std::string* out) {
rv = BuildTokenBindingMessageFromTokenBindings(token_bindings, &header);
if (rv != OK)
return rv;
- base::Base64UrlEncode(header, base::Base64UrlEncodePolicy::INCLUDE_PADDING,
- out);
+ base::Base64UrlEncode(header, base::Base64UrlEncodePolicy::OMIT_PADDING, out);
base::TimeDelta header_creation_time = base::TimeTicks::Now() - start;
UMA_HISTOGRAM_CUSTOM_TIMES("Net.TokenBinding.HeaderCreationTime",
header_creation_time,
@@ -1074,7 +1074,7 @@ int HttpNetworkTransaction::DoInitRequestBody() {
next_state_ = STATE_INIT_REQUEST_BODY_COMPLETE;
int rv = OK;
if (request_->upload_data_stream)
- rv = request_->upload_data_stream->Init(io_callback_);
+ rv = request_->upload_data_stream->Init(io_callback_, net_log_);
return rv;
}
@@ -1182,7 +1182,7 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
if (response_.headers.get() && response_.headers->response_code() == 408 &&
stream_->IsConnectionReused()) {
net_log_.AddEventWithNetErrorCode(
- NetLog::TYPE_HTTP_TRANSACTION_RESTART_AFTER_ERROR,
+ NetLogEventType::HTTP_TRANSACTION_RESTART_AFTER_ERROR,
response_.headers->response_code());
// This will close the socket - it would be weird to try and reuse it, even
// if the server doesn't actually close it.
@@ -1191,14 +1191,14 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
}
// Like Net.HttpResponseCode, but only for MAIN_FRAME loads.
- if (request_->load_flags & LOAD_MAIN_FRAME) {
+ if (request_->load_flags & LOAD_MAIN_FRAME_DEPRECATED) {
const int response_code = response_.headers->response_code();
UMA_HISTOGRAM_ENUMERATION(
"Net.HttpResponseCode_Nxx_MainFrame", response_code/100, 10);
}
net_log_.AddEvent(
- NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
+ NetLogEventType::HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers));
if (response_.headers->GetHttpVersion() < HttpVersion(1, 0)) {
@@ -1422,7 +1422,7 @@ int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
(error == ERR_SSL_VERSION_OR_CIPHER_MISMATCH ||
error == ERR_CONNECTION_CLOSED || error == ERR_CONNECTION_RESET)) {
net_log_.AddEvent(
- NetLog::TYPE_SSL_CIPHER_FALLBACK,
+ NetLogEventType::SSL_CIPHER_FALLBACK,
base::Bind(&NetLogSSLCipherFallbackCallback, &request_->url, error));
server_ssl_config_.deprecated_cipher_suites_enabled = true;
ResetConnectionAndRequestForResend();
@@ -1463,7 +1463,7 @@ int HttpNetworkTransaction::HandleIOError(int error) {
case ERR_EMPTY_RESPONSE:
if (ShouldResendRequest()) {
net_log_.AddEventWithNetErrorCode(
- NetLog::TYPE_HTTP_TRANSACTION_RESTART_AFTER_ERROR, error);
+ NetLogEventType::HTTP_TRANSACTION_RESTART_AFTER_ERROR, error);
ResetConnectionAndRequestForResend();
error = OK;
}
@@ -1472,7 +1472,7 @@ int HttpNetworkTransaction::HandleIOError(int error) {
case ERR_SPDY_SERVER_REFUSED_STREAM:
case ERR_QUIC_HANDSHAKE_FAILED:
net_log_.AddEventWithNetErrorCode(
- NetLog::TYPE_HTTP_TRANSACTION_RESTART_AFTER_ERROR, error);
+ NetLogEventType::HTTP_TRANSACTION_RESTART_AFTER_ERROR, error);
ResetConnectionAndRequestForResend();
error = OK;
break;
@@ -1631,40 +1631,6 @@ bool HttpNetworkTransaction::ForWebSocketHandshake() const {
request_->url.SchemeIsWSOrWSS();
}
-#define STATE_CASE(s) \
- case s: \
- description = base::StringPrintf("%s (0x%08X)", #s, s); \
- break
-
-std::string HttpNetworkTransaction::DescribeState(State state) {
- std::string description;
- switch (state) {
- STATE_CASE(STATE_NOTIFY_BEFORE_CREATE_STREAM);
- STATE_CASE(STATE_CREATE_STREAM);
- STATE_CASE(STATE_CREATE_STREAM_COMPLETE);
- STATE_CASE(STATE_INIT_REQUEST_BODY);
- STATE_CASE(STATE_INIT_REQUEST_BODY_COMPLETE);
- STATE_CASE(STATE_BUILD_REQUEST);
- STATE_CASE(STATE_BUILD_REQUEST_COMPLETE);
- STATE_CASE(STATE_SEND_REQUEST);
- STATE_CASE(STATE_SEND_REQUEST_COMPLETE);
- STATE_CASE(STATE_READ_HEADERS);
- STATE_CASE(STATE_READ_HEADERS_COMPLETE);
- STATE_CASE(STATE_READ_BODY);
- STATE_CASE(STATE_READ_BODY_COMPLETE);
- STATE_CASE(STATE_DRAIN_BODY_FOR_AUTH_RESTART);
- STATE_CASE(STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE);
- STATE_CASE(STATE_NONE);
- default:
- description = base::StringPrintf("Unknown state 0x%08X (%u)", state,
- state);
- break;
- }
- return description;
-}
-
-#undef STATE_CASE
-
void HttpNetworkTransaction::CopyConnectionAttemptsFromStreamRequest() {
DCHECK(stream_request_);
diff --git a/chromium/net/http/http_network_transaction.h b/chromium/net/http/http_network_transaction.h
index 87dc819ec61..ec2b5cef2b5 100644
--- a/chromium/net/http/http_network_transaction.h
+++ b/chromium/net/http/http_network_transaction.h
@@ -16,13 +16,14 @@
#include "base/time/time.h"
#include "crypto/ec_private_key.h"
#include "net/base/net_error_details.h"
+#include "net/base/net_export.h"
#include "net/base/request_priority.h"
#include "net/http/http_auth.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_info.h"
#include "net/http/http_stream_factory.h"
#include "net/http/http_transaction.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_service.h"
#include "net/socket/connection_attempts.h"
#include "net/ssl/channel_id_service.h"
@@ -59,7 +60,7 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
// HttpTransaction methods:
int Start(const HttpRequestInfo* request_info,
const CompletionCallback& callback,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
int RestartIgnoringLastError(const CompletionCallback& callback) override;
int RestartWithCertificate(X509Certificate* client_cert,
SSLPrivateKey* client_private_key,
@@ -78,7 +79,6 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
void DoneReading() override;
const HttpResponseInfo* GetResponseInfo() const override;
LoadState GetLoadState() const override;
- UploadProgress GetUploadProgress() const override;
void SetQuicServerInfo(QuicServerInfo* quic_server_info) override;
bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
bool GetRemoteEndpoint(IPEndPoint* endpoint) const override;
@@ -294,9 +294,6 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
// Returns true if this transaction is for a WebSocket handshake
bool ForWebSocketHandshake() const;
- // Debug helper.
- static std::string DescribeState(State state);
-
void SetStream(HttpStream* stream);
void CopyConnectionAttemptsFromStreamRequest();
@@ -314,7 +311,7 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction
HttpNetworkSession* session_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
const HttpRequestInfo* request_;
RequestPriority priority_;
HttpResponseInfo response_;
diff --git a/chromium/net/http/http_network_transaction_ssl_unittest.cc b/chromium/net/http/http_network_transaction_ssl_unittest.cc
index eed939f434d..01ada788a03 100644
--- a/chromium/net/http/http_network_transaction_ssl_unittest.cc
+++ b/chromium/net/http/http_network_transaction_ssl_unittest.cc
@@ -19,11 +19,16 @@
#include "net/http/http_request_info.h"
#include "net/http/http_server_properties_impl.h"
#include "net/http/transport_security_state.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_service.h"
#include "net/socket/socket_test_util.h"
#include "net/ssl/default_channel_id_store.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -145,8 +150,8 @@ TEST_F(HttpNetworkTransactionSSLTest, TokenBinding) {
TestCompletionCallback callback;
int rv = callback.GetResult(
trans1.Start(GetRequestInfo("https://www.example.com/"),
- callback.callback(), BoundNetLog()));
- EXPECT_EQ(OK, rv);
+ callback.callback(), NetLogWithSource()));
+ EXPECT_THAT(rv, IsOk());
HttpRequestHeaders headers1;
ASSERT_TRUE(trans1.GetFullRequestHeaders(&headers1));
@@ -163,8 +168,8 @@ TEST_F(HttpNetworkTransactionSSLTest, TokenBinding) {
rv = callback.GetResult(
trans2.Start(GetRequestInfo("https://www.example.com/"),
- callback.callback(), BoundNetLog()));
- EXPECT_EQ(OK, rv);
+ callback.callback(), NetLogWithSource()));
+ EXPECT_THAT(rv, IsOk());
HttpRequestHeaders headers2;
ASSERT_TRUE(trans2.GetFullRequestHeaders(&headers2));
@@ -197,8 +202,8 @@ TEST_F(HttpNetworkTransactionSSLTest, NoTokenBindingOverHttp) {
TestCompletionCallback callback;
int rv =
callback.GetResult(trans.Start(GetRequestInfo("http://www.example.com/"),
- callback.callback(), BoundNetLog()));
- EXPECT_EQ(OK, rv);
+ callback.callback(), NetLogWithSource()));
+ EXPECT_THAT(rv, IsOk());
HttpRequestHeaders headers;
ASSERT_TRUE(trans.GetFullRequestHeaders(&headers));
diff --git a/chromium/net/http/http_network_transaction_unittest.cc b/chromium/net/http/http_network_transaction_unittest.cc
index db94e0faecb..ee5b5e691b2 100644
--- a/chromium/net/http/http_network_transaction_unittest.cc
+++ b/chromium/net/http/http_network_transaction_unittest.cc
@@ -60,6 +60,8 @@
#include "net/http/http_stream_parser.h"
#include "net/http/http_transaction_test_util.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
#include "net/log/test_net_log.h"
#include "net/log/test_net_log_entry.h"
#include "net/log/test_net_log_util.h"
@@ -88,6 +90,7 @@
#include "net/ssl/ssl_info.h"
#include "net/ssl/ssl_private_key.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
#include "net/websockets/websocket_handshake_stream_base.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -95,6 +98,9 @@
#include "testing/platform_test.h"
#include "url/gurl.h"
+using net::test::IsError;
+using net::test::IsOk;
+
using base::ASCIIToUTF16;
//-----------------------------------------------------------------------------
@@ -103,19 +109,6 @@ namespace net {
namespace {
-enum TestCase {
- // Test using the SPDY/3.1 protocol.
- kTestCaseSPDY31,
-
- // Test using the HTTP/2 protocol, without specifying a stream
- // dependency based on the RequestPriority.
- kTestCaseHTTP2NoPriorityDependencies,
-
- // Test using the HTTP/2 protocol, specifying a stream
- // dependency based on the RequestPriority.
- kTestCaseHTTP2PriorityDependencies
-};
-
const base::string16 kBar(ASCIIToUTF16("bar"));
const base::string16 kBar2(ASCIIToUTF16("bar2"));
const base::string16 kBar3(ASCIIToUTF16("bar3"));
@@ -129,6 +122,9 @@ const base::string16 kSecond(ASCIIToUTF16("second"));
const base::string16 kTestingNTLM(ASCIIToUTF16("testing-ntlm"));
const base::string16 kWrongPassword(ASCIIToUTF16("wrongpassword"));
+const char kAlternativeServiceHttpHeader[] =
+ "Alt-Svc: h2=\"mail.example.org:443\"\r\n";
+
int GetIdleSocketCountInTransportSocketPool(HttpNetworkSession* session) {
return session->GetTransportSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL)
->IdleSocketCount();
@@ -163,7 +159,7 @@ bool GetHeaders(base::DictionaryValue* params, std::string* headers) {
// used.
void TestLoadTimingReused(const LoadTimingInfo& load_timing_info) {
EXPECT_TRUE(load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null());
EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null());
@@ -184,7 +180,7 @@ void TestLoadTimingReused(const LoadTimingInfo& load_timing_info) {
void TestLoadTimingNotReused(const LoadTimingInfo& load_timing_info,
int connect_timing_flags) {
EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null());
EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null());
@@ -206,7 +202,7 @@ void TestLoadTimingNotReused(const LoadTimingInfo& load_timing_info,
// used.
void TestLoadTimingReusedWithPac(const LoadTimingInfo& load_timing_info) {
EXPECT_TRUE(load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
@@ -228,7 +224,7 @@ void TestLoadTimingReusedWithPac(const LoadTimingInfo& load_timing_info) {
void TestLoadTimingNotReusedWithPac(const LoadTimingInfo& load_timing_info,
int connect_timing_flags) {
EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
EXPECT_FALSE(load_timing_info.proxy_resolve_start.is_null());
EXPECT_LE(load_timing_info.proxy_resolve_start,
@@ -263,11 +259,9 @@ std::unique_ptr<HttpNetworkSession> CreateSession(
} // namespace
-class HttpNetworkTransactionTest
- : public PlatformTest,
- public ::testing::WithParamInterface<TestCase> {
+class HttpNetworkTransactionTest : public PlatformTest {
public:
- virtual ~HttpNetworkTransactionTest() {
+ ~HttpNetworkTransactionTest() override {
// Important to restore the per-pool limit first, since the pool limit must
// always be greater than group limit, and the tests reduce both limits.
ClientSocketPoolManager::set_max_sockets_per_pool(
@@ -278,13 +272,11 @@ class HttpNetworkTransactionTest
protected:
HttpNetworkTransactionTest()
- : spdy_util_(GetProtocol(), GetDependenciesFromPriority()),
- session_deps_(GetProtocol()),
+ : ssl_(ASYNC, OK),
old_max_group_sockets_(ClientSocketPoolManager::max_sockets_per_group(
HttpNetworkSession::NORMAL_SOCKET_POOL)),
old_max_pool_sockets_(ClientSocketPoolManager::max_sockets_per_pool(
HttpNetworkSession::NORMAL_SOCKET_POOL)) {
- session_deps_.enable_priority_dependencies = GetDependenciesFromPriority();
session_deps_.enable_http2_alternative_service_with_different_host = true;
}
@@ -314,24 +306,6 @@ class HttpNetworkTransactionTest
base::RunLoop().RunUntilIdle();
}
- NextProto GetProtocol() const {
- return GetParam() == kTestCaseSPDY31 ? kProtoSPDY31 : kProtoHTTP2;
- }
-
- bool GetDependenciesFromPriority() const {
- return GetParam() == kTestCaseHTTP2PriorityDependencies;
- }
-
- const char* GetAlternateProtocolFromParam() {
- return AlternateProtocolToString(
- AlternateProtocolFromNextProto(GetProtocol()));
- }
-
- std::string GetAlternativeServiceHttpHeader() {
- return std::string("Alt-Svc: ") + GetAlternateProtocolFromParam() +
- "=\"mail.example.org:443\"\r\n";
- }
-
// Either |write_failure| specifies a write failure or |read_failure|
// specifies a read failure when using a reused socket. In either case, the
// failure should cause the network transaction to resend the request, and the
@@ -359,8 +333,7 @@ class HttpNetworkTransactionTest
BoundTestNetLog log;
session_deps_.net_log = log.bound().net_log();
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
for (size_t i = 0; i < data_count; ++i) {
session_deps_.socket_factory->AddSocketDataProvider(data[i]);
@@ -369,22 +342,22 @@ class HttpNetworkTransactionTest
TestCompletionCallback callback;
EXPECT_TRUE(log.bound().IsCapturing());
- int rv = trans->Start(&request, callback.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), log.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
out.rv = callback.WaitForResult();
- out.total_received_bytes = trans->GetTotalReceivedBytes();
- out.total_sent_bytes = trans->GetTotalSentBytes();
+ out.total_received_bytes = trans.GetTotalReceivedBytes();
+ out.total_sent_bytes = trans.GetTotalSentBytes();
// Even in the failure cases that use this function, connections are always
// successfully established before the error.
- EXPECT_TRUE(trans->GetLoadTimingInfo(&out.load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&out.load_timing_info));
TestLoadTimingNotReused(out.load_timing_info, CONNECT_TIMING_HAS_DNS_TIMES);
if (out.rv != OK)
return out;
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
// Can't use ASSERT_* inside helper functions like this, so
// return an error.
if (!response || !response->headers) {
@@ -397,29 +370,28 @@ class HttpNetworkTransactionTest
EXPECT_EQ(80, response->socket_address.port());
bool got_endpoint =
- trans->GetRemoteEndpoint(&out.remote_endpoint_after_start);
+ trans.GetRemoteEndpoint(&out.remote_endpoint_after_start);
EXPECT_EQ(got_endpoint,
out.remote_endpoint_after_start.address().size() > 0);
- rv = ReadTransaction(trans.get(), &out.response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &out.response_data);
+ EXPECT_THAT(rv, IsOk());
TestNetLogEntry::List entries;
log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
- NetLog::PHASE_NONE);
+ entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
+ NetLogEventPhase::NONE);
ExpectLogContainsSomewhere(
- entries, pos,
- NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
- NetLog::PHASE_NONE);
+ entries, pos, NetLogEventType::HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
+ NetLogEventPhase::NONE);
std::string line;
EXPECT_TRUE(entries[pos].GetStringValue("line", &line));
EXPECT_EQ("GET / HTTP/1.1\r\n", line);
HttpRequestHeaders request_headers;
- EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers));
+ EXPECT_TRUE(trans.GetFullRequestHeaders(&request_headers));
std::string value;
EXPECT_TRUE(request_headers.GetHeader("Host", &value));
EXPECT_EQ("www.example.org", value);
@@ -431,11 +403,11 @@ class HttpNetworkTransactionTest
EXPECT_EQ("['Host: www.example.org','Connection: keep-alive']",
response_headers);
- out.total_received_bytes = trans->GetTotalReceivedBytes();
+ out.total_received_bytes = trans.GetTotalReceivedBytes();
// The total number of sent bytes should not have changed.
- EXPECT_EQ(out.total_sent_bytes, trans->GetTotalSentBytes());
+ EXPECT_EQ(out.total_sent_bytes, trans.GetTotalSentBytes());
- trans->GetConnectionAttempts(&out.connection_attempts);
+ trans.GetConnectionAttempts(&out.connection_attempts);
return out;
}
@@ -457,6 +429,13 @@ class HttpNetworkTransactionTest
return out;
}
+ void AddSSLSocketData() {
+ ssl_.next_proto = kProtoHTTP2;
+ ssl_.cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
+ ASSERT_TRUE(ssl_.cert);
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_);
+ }
+
void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
int expected_status);
@@ -468,6 +447,7 @@ class HttpNetworkTransactionTest
SpdyTestUtil spdy_util_;
SpdySessionDependencies session_deps_;
+ SSLSocketDataProvider ssl_;
// Original socket limits. Some tests set these. Safest to always restore
// them once each test has been run.
@@ -475,36 +455,8 @@ class HttpNetworkTransactionTest
int old_max_pool_sockets_;
};
-INSTANTIATE_TEST_CASE_P(ProtoPlusDepend,
- HttpNetworkTransactionTest,
- testing::Values(kTestCaseSPDY31,
- kTestCaseHTTP2NoPriorityDependencies,
- kTestCaseHTTP2PriorityDependencies));
-
namespace {
-class BeforeNetworkStartHandler {
- public:
- explicit BeforeNetworkStartHandler(bool defer)
- : defer_on_before_network_start_(defer),
- observed_before_network_start_(false) {}
-
- void OnBeforeNetworkStart(bool* defer) {
- *defer = defer_on_before_network_start_;
- observed_before_network_start_ = true;
- }
-
- bool observed_before_network_start() const {
- return observed_before_network_start_;
- }
-
- private:
- const bool defer_on_before_network_start_;
- bool observed_before_network_start_;
-
- DISALLOW_COPY_AND_ASSIGN(BeforeNetworkStartHandler);
-};
-
class BeforeHeadersSentHandler {
public:
BeforeHeadersSentHandler()
@@ -602,7 +554,7 @@ class CaptureGroupNameSocketPool : public ParentPool {
ClientSocketPool::RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
last_group_name_ = group_name;
return ERR_IO_PENDING;
}
@@ -728,13 +680,12 @@ bool CheckNTLMServerAuth(const AuthChallengeInfo* auth_challenge) {
} // namespace
-TEST_P(HttpNetworkTransactionTest, Basic) {
+TEST_F(HttpNetworkTransactionTest, Basic) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
}
-TEST_P(HttpNetworkTransactionTest, SimpleGET) {
+TEST_F(HttpNetworkTransactionTest, SimpleGET) {
MockRead data_reads[] = {
MockRead("HTTP/1.0 200 OK\r\n\r\n"),
MockRead("hello world"),
@@ -742,7 +693,7 @@ TEST_P(HttpNetworkTransactionTest, SimpleGET) {
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.0 200 OK", out.status_line);
EXPECT_EQ("hello world", out.response_data);
int64_t reads_size = CountReadBytes(data_reads, arraysize(data_reads));
@@ -753,29 +704,81 @@ TEST_P(HttpNetworkTransactionTest, SimpleGET) {
}
// Response with no status line.
-TEST_P(HttpNetworkTransactionTest, SimpleGETNoHeaders) {
+TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeaders) {
MockRead data_reads[] = {
MockRead("hello world"),
MockRead(SYNCHRONOUS, OK),
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
EXPECT_EQ("hello world", out.response_data);
int64_t reads_size = CountReadBytes(data_reads, arraysize(data_reads));
EXPECT_EQ(reads_size, out.total_received_bytes);
}
+// Response with no status line, and a weird port. Should fail by default.
+TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeadersWeirdPort) {
+ MockRead data_reads[] = {
+ MockRead("hello world"), MockRead(SYNCHRONOUS, OK),
+ };
+
+ StaticSocketDataProvider data(data_reads, arraysize(data_reads), nullptr, 0);
+ session_deps_.socket_factory->AddSocketDataProvider(&data);
+
+ std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+
+ std::unique_ptr<HttpTransaction> trans(
+ new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.example.com:2000/");
+ TestCompletionCallback callback;
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsError(ERR_INVALID_HTTP_RESPONSE));
+}
+
+// Response with no status line, and a weird port. Option to allow weird ports
+// enabled.
+TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeadersWeirdPortAllowed) {
+ MockRead data_reads[] = {
+ MockRead("hello world"), MockRead(SYNCHRONOUS, OK),
+ };
+
+ StaticSocketDataProvider data(data_reads, arraysize(data_reads), nullptr, 0);
+ session_deps_.socket_factory->AddSocketDataProvider(&data);
+ session_deps_.http_09_on_non_default_ports_enabled = true;
+ std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+
+ std::unique_ptr<HttpTransaction> trans(
+ new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.example.com:2000/");
+ TestCompletionCallback callback;
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
+
+ const HttpResponseInfo* info = trans->GetResponseInfo();
+ ASSERT_TRUE(info->headers);
+ EXPECT_EQ("HTTP/0.9 200 OK", info->headers->GetStatusLine());
+
+ // Don't bother to read the body - that's verified elsewhere, important thing
+ // is that the option to allow HTTP/0.9 on non-default ports is respected.
+}
+
// Allow up to 4 bytes of junk to precede status line.
-TEST_P(HttpNetworkTransactionTest, StatusLineJunk3Bytes) {
+TEST_F(HttpNetworkTransactionTest, StatusLineJunk3Bytes) {
MockRead data_reads[] = {
MockRead("xxxHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
MockRead(SYNCHRONOUS, OK),
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
EXPECT_EQ("DATA", out.response_data);
int64_t reads_size = CountReadBytes(data_reads, arraysize(data_reads));
@@ -783,14 +786,14 @@ TEST_P(HttpNetworkTransactionTest, StatusLineJunk3Bytes) {
}
// Allow up to 4 bytes of junk to precede status line.
-TEST_P(HttpNetworkTransactionTest, StatusLineJunk4Bytes) {
+TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes) {
MockRead data_reads[] = {
MockRead("\n\nQJHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
MockRead(SYNCHRONOUS, OK),
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
EXPECT_EQ("DATA", out.response_data);
int64_t reads_size = CountReadBytes(data_reads, arraysize(data_reads));
@@ -798,14 +801,14 @@ TEST_P(HttpNetworkTransactionTest, StatusLineJunk4Bytes) {
}
// Beyond 4 bytes of slop and it should fail to find a status line.
-TEST_P(HttpNetworkTransactionTest, StatusLineJunk5Bytes) {
+TEST_F(HttpNetworkTransactionTest, StatusLineJunk5Bytes) {
MockRead data_reads[] = {
MockRead("xxxxxHTTP/1.1 404 Not Found\nServer: blah"),
MockRead(SYNCHRONOUS, OK),
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
EXPECT_EQ("xxxxxHTTP/1.1 404 Not Found\nServer: blah", out.response_data);
int64_t reads_size = CountReadBytes(data_reads, arraysize(data_reads));
@@ -813,7 +816,7 @@ TEST_P(HttpNetworkTransactionTest, StatusLineJunk5Bytes) {
}
// Same as StatusLineJunk4Bytes, except the read chunks are smaller.
-TEST_P(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) {
+TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) {
MockRead data_reads[] = {
MockRead("\n"),
MockRead("\n"),
@@ -824,7 +827,7 @@ TEST_P(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) {
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
EXPECT_EQ("DATA", out.response_data);
int64_t reads_size = CountReadBytes(data_reads, arraysize(data_reads));
@@ -832,14 +835,14 @@ TEST_P(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) {
}
// Close the connection before enough bytes to have a status line.
-TEST_P(HttpNetworkTransactionTest, StatusLinePartial) {
+TEST_F(HttpNetworkTransactionTest, StatusLinePartial) {
MockRead data_reads[] = {
MockRead("HTT"),
MockRead(SYNCHRONOUS, OK),
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
EXPECT_EQ("HTT", out.response_data);
int64_t reads_size = CountReadBytes(data_reads, arraysize(data_reads));
@@ -849,7 +852,7 @@ TEST_P(HttpNetworkTransactionTest, StatusLinePartial) {
// Simulate a 204 response, lacking a Content-Length header, sent over a
// persistent connection. The response should still terminate since a 204
// cannot have a response body.
-TEST_P(HttpNetworkTransactionTest, StopsReading204) {
+TEST_F(HttpNetworkTransactionTest, StopsReading204) {
char junk[] = "junk";
MockRead data_reads[] = {
MockRead("HTTP/1.1 204 No Content\r\n\r\n"),
@@ -858,7 +861,7 @@ TEST_P(HttpNetworkTransactionTest, StopsReading204) {
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line);
EXPECT_EQ("", out.response_data);
int64_t reads_size = CountReadBytes(data_reads, arraysize(data_reads));
@@ -867,7 +870,7 @@ TEST_P(HttpNetworkTransactionTest, StopsReading204) {
}
// A simple request using chunked encoding with some extra data after.
-TEST_P(HttpNetworkTransactionTest, ChunkedEncoding) {
+TEST_F(HttpNetworkTransactionTest, ChunkedEncoding) {
std::string final_chunk = "0\r\n\r\n";
std::string extra_data = "HTTP/1.1 200 OK\r\n";
std::string last_read = final_chunk + extra_data;
@@ -882,7 +885,7 @@ TEST_P(HttpNetworkTransactionTest, ChunkedEncoding) {
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
EXPECT_EQ("Hello world", out.response_data);
int64_t reads_size = CountReadBytes(data_reads, arraysize(data_reads));
@@ -892,7 +895,7 @@ TEST_P(HttpNetworkTransactionTest, ChunkedEncoding) {
// Next tests deal with http://crbug.com/56344.
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
MultipleContentLengthHeadersNoTransferEncoding) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
@@ -901,10 +904,10 @@ TEST_P(HttpNetworkTransactionTest,
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH));
}
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
DuplicateContentLengthHeadersNoTransferEncoding) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
@@ -914,12 +917,12 @@ TEST_P(HttpNetworkTransactionTest,
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
EXPECT_EQ("Hello", out.response_data);
}
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
ComplexContentLengthHeadersNoTransferEncoding) {
// More than 2 dupes.
{
@@ -932,7 +935,7 @@ TEST_P(HttpNetworkTransactionTest,
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
EXPECT_EQ("Hello", out.response_data);
}
@@ -947,7 +950,7 @@ TEST_P(HttpNetworkTransactionTest,
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.0 200 OK", out.status_line);
EXPECT_EQ("Hello", out.response_data);
}
@@ -961,11 +964,11 @@ TEST_P(HttpNetworkTransactionTest,
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH));
}
}
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
MultipleContentLengthHeadersTransferEncoding) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
@@ -981,7 +984,7 @@ TEST_P(HttpNetworkTransactionTest,
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
EXPECT_EQ("Hello world", out.response_data);
}
@@ -989,7 +992,7 @@ TEST_P(HttpNetworkTransactionTest,
// Next tests deal with http://crbug.com/98895.
// Checks that a single Content-Disposition header results in no error.
-TEST_P(HttpNetworkTransactionTest, SingleContentDispositionHeader) {
+TEST_F(HttpNetworkTransactionTest, SingleContentDispositionHeader) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
MockRead("Content-Disposition: attachment;filename=\"salutations.txt\"r\n"),
@@ -998,14 +1001,13 @@ TEST_P(HttpNetworkTransactionTest, SingleContentDispositionHeader) {
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
EXPECT_EQ("Hello", out.response_data);
}
// Checks that two identical Content-Disposition headers result in no error.
-TEST_P(HttpNetworkTransactionTest,
- TwoIdenticalContentDispositionHeaders) {
+TEST_F(HttpNetworkTransactionTest, TwoIdenticalContentDispositionHeaders) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"),
@@ -1015,13 +1017,13 @@ TEST_P(HttpNetworkTransactionTest,
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
EXPECT_EQ("Hello", out.response_data);
}
// Checks that two distinct Content-Disposition headers result in an error.
-TEST_P(HttpNetworkTransactionTest, TwoDistinctContentDispositionHeaders) {
+TEST_F(HttpNetworkTransactionTest, TwoDistinctContentDispositionHeaders) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"),
@@ -1031,12 +1033,13 @@ TEST_P(HttpNetworkTransactionTest, TwoDistinctContentDispositionHeaders) {
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION, out.rv);
+ EXPECT_THAT(out.rv,
+ IsError(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION));
}
// Checks that two identical Location headers result in no error.
// Also tests Location header behavior.
-TEST_P(HttpNetworkTransactionTest, TwoIdenticalLocationHeaders) {
+TEST_F(HttpNetworkTransactionTest, TwoIdenticalLocationHeaders) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 302 Redirect\r\n"),
MockRead("Location: http://good.com/\r\n"),
@@ -1051,31 +1054,30 @@ TEST_P(HttpNetworkTransactionTest, TwoIdenticalLocationHeaders) {
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 302 Redirect", response->headers->GetStatusLine());
std::string url;
EXPECT_TRUE(response->headers->IsRedirect(&url));
EXPECT_EQ("http://good.com/", url);
- EXPECT_TRUE(response->proxy_server.IsEmpty());
+ EXPECT_TRUE(response->proxy_server.is_direct());
}
// Checks that two distinct Location headers result in an error.
-TEST_P(HttpNetworkTransactionTest, TwoDistinctLocationHeaders) {
+TEST_F(HttpNetworkTransactionTest, TwoDistinctLocationHeaders) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 302 Redirect\r\n"),
MockRead("Location: http://good.com/\r\n"),
@@ -1085,22 +1087,21 @@ TEST_P(HttpNetworkTransactionTest, TwoDistinctLocationHeaders) {
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION));
}
// Do a request using the HEAD method. Verify that we don't try to read the
// message body (since HEAD has none).
-TEST_P(HttpNetworkTransactionTest, Head) {
+TEST_F(HttpNetworkTransactionTest, Head) {
HttpRequestInfo request;
request.method = "HEAD";
request.url = GURL("http://www.example.org/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
BeforeHeadersSentHandler headers_handler;
- trans->SetBeforeHeadersSentCallback(
+ trans.SetBeforeHeadersSentCallback(
base::Bind(&BeforeHeadersSentHandler::OnBeforeHeadersSent,
base::Unretained(&headers_handler)));
@@ -1123,20 +1124,20 @@ TEST_P(HttpNetworkTransactionTest, Head) {
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
// Check that the headers got parsed.
EXPECT_TRUE(response->headers);
EXPECT_EQ(1234, response->headers->GetContentLength());
EXPECT_EQ("HTTP/1.1 404 Not Found", response->headers->GetStatusLine());
- EXPECT_TRUE(response->proxy_server.IsEmpty());
+ EXPECT_TRUE(response->proxy_server.is_direct());
EXPECT_TRUE(headers_handler.observed_before_headers_sent());
EXPECT_FALSE(headers_handler.observed_before_headers_sent_with_proxy());
@@ -1150,12 +1151,12 @@ TEST_P(HttpNetworkTransactionTest, Head) {
// Reading should give EOF right away, since there is no message body
// (despite non-zero content-length).
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("", response_data);
}
-TEST_P(HttpNetworkTransactionTest, ReuseConnection) {
+TEST_F(HttpNetworkTransactionTest, ReuseConnection) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
MockRead data_reads[] = {
@@ -1178,35 +1179,34 @@ TEST_P(HttpNetworkTransactionTest, ReuseConnection) {
request.url = GURL("http://www.example.org/");
request.load_flags = 0;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_TRUE(response->proxy_server.IsEmpty());
+ EXPECT_TRUE(response->proxy_server.is_direct());
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ(kExpectedResponseData[i], response_data);
}
}
-TEST_P(HttpNetworkTransactionTest, Ignores100) {
+TEST_F(HttpNetworkTransactionTest, Ignores100) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
element_readers.push_back(
- base::WrapUnique(new UploadBytesElementReader("foo", 3)));
+ base::MakeUnique<UploadBytesElementReader>("foo", 3));
ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
HttpRequestInfo request;
@@ -1215,9 +1215,13 @@ TEST_P(HttpNetworkTransactionTest, Ignores100) {
request.upload_data_stream = &upload_data_stream;
request.load_flags = 0;
+ // Check the upload progress returned before initialization is correct.
+ UploadProgress progress = request.upload_data_stream->GetUploadProgress();
+ EXPECT_EQ(0u, progress.size());
+ EXPECT_EQ(0u, progress.position());
+
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockRead data_reads[] = {
MockRead("HTTP/1.0 100 Continue\r\n\r\n"),
@@ -1230,36 +1234,35 @@ TEST_P(HttpNetworkTransactionTest, Ignores100) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("hello world", response_data);
}
// This test is almost the same as Ignores100 above, but the response contains
// a 102 instead of a 100. Also, instead of HTTP/1.0 the response is
// HTTP/1.1 and the two status headers are read in one read.
-TEST_P(HttpNetworkTransactionTest, Ignores1xx) {
+TEST_F(HttpNetworkTransactionTest, Ignores1xx) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.foo.com/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockRead data_reads[] = {
MockRead("HTTP/1.1 102 Unspecified status code\r\n\r\n"
@@ -1272,33 +1275,32 @@ TEST_P(HttpNetworkTransactionTest, Ignores1xx) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("hello world", response_data);
}
-TEST_P(HttpNetworkTransactionTest, Incomplete100ThenEOF) {
+TEST_F(HttpNetworkTransactionTest, Incomplete100ThenEOF) {
HttpRequestInfo request;
request.method = "POST";
request.url = GURL("http://www.foo.com/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockRead data_reads[] = {
MockRead(SYNCHRONOUS, "HTTP/1.0 100 Continue\r\n"),
@@ -1309,27 +1311,26 @@ TEST_P(HttpNetworkTransactionTest, Incomplete100ThenEOF) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("", response_data);
}
-TEST_P(HttpNetworkTransactionTest, EmptyResponse) {
+TEST_F(HttpNetworkTransactionTest, EmptyResponse) {
HttpRequestInfo request;
request.method = "POST";
request.url = GURL("http://www.foo.com/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockRead data_reads[] = {
MockRead(ASYNC, 0),
@@ -1339,11 +1340,11 @@ TEST_P(HttpNetworkTransactionTest, EmptyResponse) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_EMPTY_RESPONSE, rv);
+ EXPECT_THAT(rv, IsError(ERR_EMPTY_RESPONSE));
}
void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest(
@@ -1399,21 +1400,20 @@ void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest(
"hello", "world"
};
- uint32_t first_socket_log_id = NetLog::Source::kInvalidId;
+ uint32_t first_socket_log_id = NetLogSource::kInvalidId;
for (int i = 0; i < 2; ++i) {
TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_DNS_TIMES);
if (i == 0) {
first_socket_log_id = load_timing_info.socket_log_id;
@@ -1422,15 +1422,16 @@ void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest(
EXPECT_NE(first_socket_log_id, load_timing_info.socket_log_id);
}
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers);
+ EXPECT_TRUE(response->proxy_server.is_direct());
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ(kExpectedResponseData[i], response_data);
}
}
@@ -1451,19 +1452,19 @@ void HttpNetworkTransactionTest::PreconnectErrorResendRequestTest(
SSLSocketDataProvider ssl1(ASYNC, OK);
SSLSocketDataProvider ssl2(ASYNC, OK);
if (use_spdy) {
- ssl1.SetNextProto(GetProtocol());
- ssl2.SetNextProto(GetProtocol());
+ ssl1.next_proto = kProtoHTTP2;
+ ssl2.next_proto = kProtoHTTP2;
}
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
// SPDY versions of the request and response.
- std::unique_ptr<SpdySerializedFrame> spdy_request(spdy_util_.ConstructSpdyGet(
+ SpdySerializedFrame spdy_request(spdy_util_.ConstructSpdyGet(
request.url.spec().c_str(), 1, DEFAULT_PRIORITY));
- std::unique_ptr<SpdySerializedFrame> spdy_response(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> spdy_data(
- spdy_util_.ConstructSpdyBodyFrame(1, "hello", 5, true));
+ SpdySerializedFrame spdy_response(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame spdy_data(
+ spdy_util_.ConstructSpdyDataFrame(1, "hello", 5, true));
// HTTP/1.1 versions of the request and response.
const char kHttpRequest[] = "GET / HTTP/1.1\r\n"
@@ -1481,7 +1482,7 @@ void HttpNetworkTransactionTest::PreconnectErrorResendRequestTest(
} else {
ASSERT_TRUE(read_failure);
if (use_spdy) {
- data1_writes.push_back(CreateMockWrite(*spdy_request));
+ data1_writes.push_back(CreateMockWrite(spdy_request));
} else {
data1_writes.push_back(MockWrite(kHttpRequest));
}
@@ -1496,10 +1497,10 @@ void HttpNetworkTransactionTest::PreconnectErrorResendRequestTest(
std::vector<MockWrite> data2_writes;
if (use_spdy) {
- data2_writes.push_back(CreateMockWrite(*spdy_request, 0, ASYNC));
+ data2_writes.push_back(CreateMockWrite(spdy_request, 0, ASYNC));
- data2_reads.push_back(CreateMockRead(*spdy_response, 1, ASYNC));
- data2_reads.push_back(CreateMockRead(*spdy_data, 2, ASYNC));
+ data2_reads.push_back(CreateMockRead(spdy_response, 1, ASYNC));
+ data2_reads.push_back(CreateMockRead(spdy_data, 2, ASYNC));
data2_reads.push_back(MockRead(ASYNC, OK, 3));
} else {
data2_writes.push_back(
@@ -1524,22 +1525,21 @@ void HttpNetworkTransactionTest::PreconnectErrorResendRequestTest(
// Make the request.
TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReused(
load_timing_info,
CONNECT_TIMING_HAS_DNS_TIMES|CONNECT_TIMING_HAS_SSL_TIMES);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers);
@@ -1550,30 +1550,29 @@ void HttpNetworkTransactionTest::PreconnectErrorResendRequestTest(
}
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ(kHttpData, response_data);
}
-TEST_P(HttpNetworkTransactionTest,
- KeepAliveConnectionNotConnectedOnWrite) {
+TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionNotConnectedOnWrite) {
MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED);
KeepAliveConnectionResendRequestTest(&write_failure, NULL);
}
-TEST_P(HttpNetworkTransactionTest, KeepAliveConnectionReset) {
+TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionReset) {
MockRead read_failure(ASYNC, ERR_CONNECTION_RESET);
KeepAliveConnectionResendRequestTest(NULL, &read_failure);
}
-TEST_P(HttpNetworkTransactionTest, KeepAliveConnectionEOF) {
+TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionEOF) {
MockRead read_failure(SYNCHRONOUS, OK); // EOF
KeepAliveConnectionResendRequestTest(NULL, &read_failure);
}
// Make sure that on a 408 response (Request Timeout), the request is retried,
// if the socket was a reused keep alive socket.
-TEST_P(HttpNetworkTransactionTest, KeepAlive408) {
+TEST_F(HttpNetworkTransactionTest, KeepAlive408) {
MockRead read_failure(SYNCHRONOUS,
"HTTP/1.1 408 Request Timeout\r\n"
"Connection: Keep-Alive\r\n"
@@ -1582,30 +1581,29 @@ TEST_P(HttpNetworkTransactionTest, KeepAlive408) {
KeepAliveConnectionResendRequestTest(NULL, &read_failure);
}
-TEST_P(HttpNetworkTransactionTest,
- PreconnectErrorNotConnectedOnWrite) {
+TEST_F(HttpNetworkTransactionTest, PreconnectErrorNotConnectedOnWrite) {
MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED);
PreconnectErrorResendRequestTest(&write_failure, NULL, false);
}
-TEST_P(HttpNetworkTransactionTest, PreconnectErrorReset) {
+TEST_F(HttpNetworkTransactionTest, PreconnectErrorReset) {
MockRead read_failure(ASYNC, ERR_CONNECTION_RESET);
PreconnectErrorResendRequestTest(NULL, &read_failure, false);
}
-TEST_P(HttpNetworkTransactionTest, PreconnectErrorEOF) {
+TEST_F(HttpNetworkTransactionTest, PreconnectErrorEOF) {
MockRead read_failure(SYNCHRONOUS, OK); // EOF
PreconnectErrorResendRequestTest(NULL, &read_failure, false);
}
-TEST_P(HttpNetworkTransactionTest, PreconnectErrorAsyncEOF) {
+TEST_F(HttpNetworkTransactionTest, PreconnectErrorAsyncEOF) {
MockRead read_failure(ASYNC, OK); // EOF
PreconnectErrorResendRequestTest(NULL, &read_failure, false);
}
// Make sure that on a 408 response (Request Timeout), the request is retried,
// if the socket was a preconnected (UNUSED_IDLE) socket.
-TEST_P(HttpNetworkTransactionTest, RetryOnIdle408) {
+TEST_F(HttpNetworkTransactionTest, RetryOnIdle408) {
MockRead read_failure(SYNCHRONOUS,
"HTTP/1.1 408 Request Timeout\r\n"
"Connection: Keep-Alive\r\n"
@@ -1615,36 +1613,34 @@ TEST_P(HttpNetworkTransactionTest, RetryOnIdle408) {
PreconnectErrorResendRequestTest(NULL, &read_failure, false);
}
-TEST_P(HttpNetworkTransactionTest,
- SpdyPreconnectErrorNotConnectedOnWrite) {
+TEST_F(HttpNetworkTransactionTest, SpdyPreconnectErrorNotConnectedOnWrite) {
MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED);
PreconnectErrorResendRequestTest(&write_failure, NULL, true);
}
-TEST_P(HttpNetworkTransactionTest, SpdyPreconnectErrorReset) {
+TEST_F(HttpNetworkTransactionTest, SpdyPreconnectErrorReset) {
MockRead read_failure(ASYNC, ERR_CONNECTION_RESET);
PreconnectErrorResendRequestTest(NULL, &read_failure, true);
}
-TEST_P(HttpNetworkTransactionTest, SpdyPreconnectErrorEOF) {
+TEST_F(HttpNetworkTransactionTest, SpdyPreconnectErrorEOF) {
MockRead read_failure(SYNCHRONOUS, OK); // EOF
PreconnectErrorResendRequestTest(NULL, &read_failure, true);
}
-TEST_P(HttpNetworkTransactionTest, SpdyPreconnectErrorAsyncEOF) {
+TEST_F(HttpNetworkTransactionTest, SpdyPreconnectErrorAsyncEOF) {
MockRead read_failure(ASYNC, OK); // EOF
PreconnectErrorResendRequestTest(NULL, &read_failure, true);
}
-TEST_P(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) {
+TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockRead data_reads[] = {
MockRead(ASYNC, ERR_CONNECTION_RESET),
@@ -1657,14 +1653,14 @@ TEST_P(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
IPEndPoint endpoint;
- EXPECT_TRUE(trans->GetRemoteEndpoint(&endpoint));
+ EXPECT_TRUE(trans.GetRemoteEndpoint(&endpoint));
EXPECT_LT(0u, endpoint.address().size());
}
@@ -1677,7 +1673,7 @@ TEST_P(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) {
// Opera 9.52: after five attempts, blank page
// Us with WinHTTP: error page (ERR_INVALID_RESPONSE)
// Us: error page (EMPTY_RESPONSE)
-TEST_P(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) {
+TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) {
MockRead data_reads[] = {
MockRead(SYNCHRONOUS, OK), // EOF
MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
@@ -1686,98 +1682,21 @@ TEST_P(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) {
};
SimpleGetHelperResult out = SimpleGetHelper(data_reads,
arraysize(data_reads));
- EXPECT_EQ(ERR_EMPTY_RESPONSE, out.rv);
-}
-
-// Test that network access can be deferred and resumed.
-TEST_P(HttpNetworkTransactionTest, ThrottleBeforeNetworkStart) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.load_flags = 0;
-
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
-
- // Defer on OnBeforeNetworkStart.
- BeforeNetworkStartHandler net_start_handler(true); // defer
- trans->SetBeforeNetworkStartCallback(
- base::Bind(&BeforeNetworkStartHandler::OnBeforeNetworkStart,
- base::Unretained(&net_start_handler)));
-
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead("hello"),
- MockRead(SYNCHRONOUS, 0),
- };
- StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
-
- TestCompletionCallback callback;
-
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- base::RunLoop().RunUntilIdle();
-
- // Should have deferred for network start.
- EXPECT_TRUE(net_start_handler.observed_before_network_start());
- EXPECT_EQ(LOAD_STATE_WAITING_FOR_DELEGATE, trans->GetLoadState());
-
- trans->ResumeNetworkStart();
- rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
- EXPECT_TRUE(trans->GetResponseInfo());
-
- scoped_refptr<IOBufferWithSize> io_buf(new IOBufferWithSize(100));
- rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback());
- if (rv == ERR_IO_PENDING)
- rv = callback.WaitForResult();
- EXPECT_EQ(5, rv);
- trans.reset();
-}
-
-// Test that network use can be deferred and canceled.
-TEST_P(HttpNetworkTransactionTest, ThrottleAndCancelBeforeNetworkStart) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.load_flags = 0;
-
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
-
- // Defer on OnBeforeNetworkStart.
- BeforeNetworkStartHandler net_start_handler(true); // defer
- trans->SetBeforeNetworkStartCallback(
- base::Bind(&BeforeNetworkStartHandler::OnBeforeNetworkStart,
- base::Unretained(&net_start_handler)));
-
- TestCompletionCallback callback;
-
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- base::RunLoop().RunUntilIdle();
-
- // Should have deferred for network start.
- EXPECT_TRUE(net_start_handler.observed_before_network_start());
- EXPECT_EQ(LOAD_STATE_WAITING_FOR_DELEGATE, trans->GetLoadState());
+ EXPECT_THAT(out.rv, IsError(ERR_EMPTY_RESPONSE));
}
// Next 2 cases (KeepAliveEarlyClose and KeepAliveEarlyClose2) are regression
// tests. There was a bug causing HttpNetworkTransaction to hang in the
// destructor in such situations.
// See http://crbug.com/154712 and http://crbug.com/156609.
-TEST_P(HttpNetworkTransactionTest, KeepAliveEarlyClose) {
+TEST_F(HttpNetworkTransactionTest, KeepAliveEarlyClose) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
MockRead data_reads[] = {
@@ -1792,11 +1711,11 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveEarlyClose) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
scoped_refptr<IOBufferWithSize> io_buf(new IOBufferWithSize(100));
rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback());
@@ -1804,21 +1723,21 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveEarlyClose) {
rv = callback.WaitForResult();
EXPECT_EQ(5, rv);
rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback());
- EXPECT_EQ(ERR_CONTENT_LENGTH_MISMATCH, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONTENT_LENGTH_MISMATCH));
trans.reset();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
}
-TEST_P(HttpNetworkTransactionTest, KeepAliveEarlyClose2) {
+TEST_F(HttpNetworkTransactionTest, KeepAliveEarlyClose2) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
MockRead data_reads[] = {
@@ -1832,17 +1751,17 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveEarlyClose2) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
scoped_refptr<IOBufferWithSize> io_buf(new IOBufferWithSize(100));
rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_CONTENT_LENGTH_MISMATCH, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONTENT_LENGTH_MISMATCH));
trans.reset();
base::RunLoop().RunUntilIdle();
@@ -1851,7 +1770,7 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveEarlyClose2) {
// Test that we correctly reuse a keep-alive connection after not explicitly
// reading the body.
-TEST_P(HttpNetworkTransactionTest, KeepAliveAfterUnreadBody) {
+TEST_F(HttpNetworkTransactionTest, KeepAliveAfterUnreadBody) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.foo.com/");
@@ -1922,15 +1841,15 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveAfterUnreadBody) {
const int kNumUnreadBodies = arraysize(data_writes) - 1;
std::string response_lines[kNumUnreadBodies];
- uint32_t first_socket_log_id = NetLog::Source::kInvalidId;
+ uint32_t first_socket_log_id = NetLogSource::kInvalidId;
for (size_t i = 0; i < kNumUnreadBodies; ++i) {
TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
LoadTimingInfo load_timing_info;
EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
@@ -1973,23 +1892,22 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveAfterUnreadBody) {
EXPECT_EQ(kStatusLines[i], response_lines[i]);
TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
+ 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("HTTP/1.1 200 OK", response->headers->GetStatusLine());
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("hello", response_data);
}
// Sockets that receive extra data after a response is complete should not be
// reused.
-TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData1) {
+TEST_F(HttpNetworkTransactionTest, KeepAliveWithUnusedData1) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
MockWrite data_writes1[] = {
MockWrite("HEAD / HTTP/1.1\r\n"
@@ -2027,10 +1945,10 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData1) {
request1.method = "HEAD";
request1.url = GURL("http://www.borked.com/");
- std::unique_ptr<HttpTransaction> trans1(
+ std::unique_ptr<HttpNetworkTransaction> trans1(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans1->Start(&request1, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
const HttpResponseInfo* response1 = trans1->GetResponseInfo();
ASSERT_TRUE(response1);
@@ -2039,7 +1957,7 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData1) {
EXPECT_TRUE(response1->headers->IsKeepAlive());
std::string response_data1;
- EXPECT_EQ(OK, ReadTransaction(trans1.get(), &response_data1));
+ EXPECT_THAT(ReadTransaction(trans1.get(), &response_data1), IsOk());
EXPECT_EQ("", response_data1);
// Deleting the transaction attempts to release the socket back into the
// socket pool.
@@ -2049,10 +1967,10 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData1) {
request2.method = "GET";
request2.url = GURL("http://www.borked.com/foo");
- std::unique_ptr<HttpTransaction> trans2(
+ std::unique_ptr<HttpNetworkTransaction> trans2(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- rv = trans2->Start(&request2, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ rv = trans2->Start(&request2, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
const HttpResponseInfo* response2 = trans2->GetResponseInfo();
ASSERT_TRUE(response2);
@@ -2060,11 +1978,11 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData1) {
EXPECT_EQ(200, response2->headers->response_code());
std::string response_data2;
- EXPECT_EQ(OK, ReadTransaction(trans2.get(), &response_data2));
+ EXPECT_THAT(ReadTransaction(trans2.get(), &response_data2), IsOk());
EXPECT_EQ("foo", response_data2);
}
-TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData2) {
+TEST_F(HttpNetworkTransactionTest, KeepAliveWithUnusedData2) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
MockWrite data_writes1[] = {
MockWrite("GET / HTTP/1.1\r\n"
@@ -2103,10 +2021,10 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData2) {
request1.method = "GET";
request1.url = GURL("http://www.borked.com/");
- std::unique_ptr<HttpTransaction> trans1(
+ std::unique_ptr<HttpNetworkTransaction> trans1(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans1->Start(&request1, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
const HttpResponseInfo* response1 = trans1->GetResponseInfo();
ASSERT_TRUE(response1);
@@ -2115,7 +2033,7 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData2) {
EXPECT_TRUE(response1->headers->IsKeepAlive());
std::string response_data1;
- EXPECT_EQ(OK, ReadTransaction(trans1.get(), &response_data1));
+ EXPECT_THAT(ReadTransaction(trans1.get(), &response_data1), IsOk());
EXPECT_EQ("This server is borked.", response_data1);
// Deleting the transaction attempts to release the socket back into the
// socket pool.
@@ -2125,10 +2043,10 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData2) {
request2.method = "GET";
request2.url = GURL("http://www.borked.com/foo");
- std::unique_ptr<HttpTransaction> trans2(
+ std::unique_ptr<HttpNetworkTransaction> trans2(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- rv = trans2->Start(&request2, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ rv = trans2->Start(&request2, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
const HttpResponseInfo* response2 = trans2->GetResponseInfo();
ASSERT_TRUE(response2);
@@ -2136,11 +2054,11 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData2) {
EXPECT_EQ(200, response2->headers->response_code());
std::string response_data2;
- EXPECT_EQ(OK, ReadTransaction(trans2.get(), &response_data2));
+ EXPECT_THAT(ReadTransaction(trans2.get(), &response_data2), IsOk());
EXPECT_EQ("foo", response_data2);
}
-TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData3) {
+TEST_F(HttpNetworkTransactionTest, KeepAliveWithUnusedData3) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
MockWrite data_writes1[] = {
MockWrite("GET / HTTP/1.1\r\n"
@@ -2179,10 +2097,10 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData3) {
request1.method = "GET";
request1.url = GURL("http://www.borked.com/");
- std::unique_ptr<HttpTransaction> trans1(
+ std::unique_ptr<HttpNetworkTransaction> trans1(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans1->Start(&request1, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
const HttpResponseInfo* response1 = trans1->GetResponseInfo();
ASSERT_TRUE(response1);
@@ -2191,7 +2109,7 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData3) {
EXPECT_TRUE(response1->headers->IsKeepAlive());
std::string response_data1;
- EXPECT_EQ(OK, ReadTransaction(trans1.get(), &response_data1));
+ EXPECT_THAT(ReadTransaction(trans1.get(), &response_data1), IsOk());
EXPECT_EQ("This server is borked.", response_data1);
// Deleting the transaction attempts to release the socket back into the
// socket pool.
@@ -2201,10 +2119,10 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData3) {
request2.method = "GET";
request2.url = GURL("http://www.borked.com/foo");
- std::unique_ptr<HttpTransaction> trans2(
+ std::unique_ptr<HttpNetworkTransaction> trans2(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- rv = trans2->Start(&request2, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ rv = trans2->Start(&request2, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
const HttpResponseInfo* response2 = trans2->GetResponseInfo();
ASSERT_TRUE(response2);
@@ -2212,7 +2130,7 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData3) {
EXPECT_EQ(200, response2->headers->response_code());
std::string response_data2;
- EXPECT_EQ(OK, ReadTransaction(trans2.get(), &response_data2));
+ EXPECT_THAT(ReadTransaction(trans2.get(), &response_data2), IsOk());
EXPECT_EQ("foo", response_data2);
}
@@ -2220,7 +2138,7 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData3) {
// HttpStreamParser doesn't know if there's extra data on a socket or not when
// the HttpNetworkTransaction is torn down, because the response body hasn't
// been read from yet, but the request goes through the HttpResponseBodyDrainer.
-TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData4) {
+TEST_F(HttpNetworkTransactionTest, KeepAliveWithUnusedData4) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
MockWrite data_writes1[] = {
MockWrite("GET / HTTP/1.1\r\n"
@@ -2244,10 +2162,10 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData4) {
request1.method = "GET";
request1.url = GURL("http://www.borked.com/");
- std::unique_ptr<HttpTransaction> trans1(
+ std::unique_ptr<HttpNetworkTransaction> trans1(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans1->Start(&request1, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
const HttpResponseInfo* response1 = trans1->GetResponseInfo();
ASSERT_TRUE(response1);
@@ -2269,7 +2187,7 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveWithUnusedData4) {
// Test the request-challenge-retry sequence for basic auth.
// (basic auth is the easiest to mock, because it has no randomness).
-TEST_P(HttpNetworkTransactionTest, BasicAuth) {
+TEST_F(HttpNetworkTransactionTest, BasicAuth) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -2278,8 +2196,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuth) {
TestNetLog log;
session_deps_.net_log = &log;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes1[] = {
MockWrite(
@@ -2328,36 +2245,35 @@ TEST_P(HttpNetworkTransactionTest, BasicAuth) {
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
LoadTimingInfo load_timing_info1;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info1));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info1));
TestLoadTimingNotReused(load_timing_info1, CONNECT_TIMING_HAS_DNS_TIMES);
int64_t writes_size1 = CountWriteBytes(data_writes1, arraysize(data_writes1));
- EXPECT_EQ(writes_size1, trans->GetTotalSentBytes());
+ EXPECT_EQ(writes_size1, trans.GetTotalSentBytes());
int64_t reads_size1 = CountReadBytes(data_reads1, arraysize(data_reads1));
- EXPECT_EQ(reads_size1, trans->GetTotalReceivedBytes());
+ EXPECT_EQ(reads_size1, trans.GetTotalReceivedBytes());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get()));
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
LoadTimingInfo load_timing_info2;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info2));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info2));
TestLoadTimingNotReused(load_timing_info2, CONNECT_TIMING_HAS_DNS_TIMES);
// The load timing after restart should have a new socket ID, and times after
// those of the first load timing.
@@ -2366,11 +2282,11 @@ TEST_P(HttpNetworkTransactionTest, BasicAuth) {
EXPECT_NE(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
int64_t writes_size2 = CountWriteBytes(data_writes2, arraysize(data_writes2));
- EXPECT_EQ(writes_size1 + writes_size2, trans->GetTotalSentBytes());
+ EXPECT_EQ(writes_size1 + writes_size2, trans.GetTotalSentBytes());
int64_t reads_size2 = CountReadBytes(data_reads2, arraysize(data_reads2));
- EXPECT_EQ(reads_size1 + reads_size2, trans->GetTotalReceivedBytes());
+ EXPECT_EQ(reads_size1 + reads_size2, trans.GetTotalReceivedBytes());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(100, response->headers->GetContentLength());
@@ -2378,7 +2294,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuth) {
// Test the request-challenge-retry sequence for basic auth.
// (basic auth is the easiest to mock, because it has no randomness).
-TEST_P(HttpNetworkTransactionTest, BasicAuthWithAddressChange) {
+TEST_F(HttpNetworkTransactionTest, BasicAuthWithAddressChange) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -2389,8 +2305,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthWithAddressChange) {
session_deps_.net_log = &log;
session_deps_.host_resolver.reset(resolver);
std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
resolver->rules()->ClearRules();
resolver->rules()->AddRule("www.example.org", "127.0.0.1");
@@ -2439,24 +2354,24 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthWithAddressChange) {
TestCompletionCallback callback1;
- EXPECT_EQ(OK, callback1.GetResult(trans->Start(&request, callback1.callback(),
- BoundNetLog())));
+ EXPECT_EQ(OK, callback1.GetResult(trans.Start(&request, callback1.callback(),
+ NetLogWithSource())));
LoadTimingInfo load_timing_info1;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info1));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info1));
TestLoadTimingNotReused(load_timing_info1, CONNECT_TIMING_HAS_DNS_TIMES);
int64_t writes_size1 = CountWriteBytes(data_writes1, arraysize(data_writes1));
- EXPECT_EQ(writes_size1, trans->GetTotalSentBytes());
+ EXPECT_EQ(writes_size1, trans.GetTotalSentBytes());
int64_t reads_size1 = CountReadBytes(data_reads1, arraysize(data_reads1));
- EXPECT_EQ(reads_size1, trans->GetTotalReceivedBytes());
+ EXPECT_EQ(reads_size1, trans.GetTotalReceivedBytes());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get()));
IPEndPoint endpoint;
- EXPECT_TRUE(trans->GetRemoteEndpoint(&endpoint));
+ EXPECT_TRUE(trans.GetRemoteEndpoint(&endpoint));
ASSERT_FALSE(endpoint.address().empty());
EXPECT_EQ("127.0.0.1:80", endpoint.ToString());
@@ -2465,11 +2380,11 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthWithAddressChange) {
TestCompletionCallback callback2;
- EXPECT_EQ(OK, callback2.GetResult(trans->RestartWithAuth(
+ EXPECT_EQ(OK, callback2.GetResult(trans.RestartWithAuth(
AuthCredentials(kFoo, kBar), callback2.callback())));
LoadTimingInfo load_timing_info2;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info2));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info2));
TestLoadTimingNotReused(load_timing_info2, CONNECT_TIMING_HAS_DNS_TIMES);
// The load timing after restart should have a new socket ID, and times after
// those of the first load timing.
@@ -2478,29 +2393,28 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthWithAddressChange) {
EXPECT_NE(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
int64_t writes_size2 = CountWriteBytes(data_writes2, arraysize(data_writes2));
- EXPECT_EQ(writes_size1 + writes_size2, trans->GetTotalSentBytes());
+ EXPECT_EQ(writes_size1 + writes_size2, trans.GetTotalSentBytes());
int64_t reads_size2 = CountReadBytes(data_reads2, arraysize(data_reads2));
- EXPECT_EQ(reads_size1 + reads_size2, trans->GetTotalReceivedBytes());
+ EXPECT_EQ(reads_size1 + reads_size2, trans.GetTotalReceivedBytes());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(100, response->headers->GetContentLength());
- EXPECT_TRUE(trans->GetRemoteEndpoint(&endpoint));
+ EXPECT_TRUE(trans.GetRemoteEndpoint(&endpoint));
ASSERT_FALSE(endpoint.address().empty());
EXPECT_EQ("127.0.0.2:80", endpoint.ToString());
}
-TEST_P(HttpNetworkTransactionTest, DoNotSendAuth) {
+TEST_F(HttpNetworkTransactionTest, DoNotSendAuth) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
request.load_flags = LOAD_DO_NOT_SEND_AUTH_DATA;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite(
@@ -2523,25 +2437,25 @@ TEST_P(HttpNetworkTransactionTest, DoNotSendAuth) {
session_deps_.socket_factory->AddSocketDataProvider(&data);
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
EXPECT_EQ(0, rv);
int64_t writes_size = CountWriteBytes(data_writes, arraysize(data_writes));
- EXPECT_EQ(writes_size, trans->GetTotalSentBytes());
+ EXPECT_EQ(writes_size, trans.GetTotalSentBytes());
int64_t reads_size = CountReadBytes(data_reads, arraysize(data_reads));
- EXPECT_EQ(reads_size, trans->GetTotalReceivedBytes());
+ EXPECT_EQ(reads_size, trans.GetTotalReceivedBytes());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
}
// Test the request-challenge-retry sequence for basic auth, over a keep-alive
// connection.
-TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
+TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
// On the second pass, the body read of the auth challenge is synchronous, so
// IsConnectedAndIdle returns false. The socket should still be drained and
// reused. See http://crbug.com/544255.
@@ -2561,7 +2475,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
"Host: www.example.org\r\n"
"Connection: keep-alive\r\n\r\n"),
- // After calling trans->RestartWithAuth(), this is the request we should
+ // After calling trans.RestartWithAuth(), this is the request we should
// be issuing -- the final header line contains the credentials.
MockWrite(ASYNC, 6,
"GET / HTTP/1.1\r\n"
@@ -2591,27 +2505,26 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- ASSERT_EQ(OK, callback1.GetResult(rv));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ ASSERT_THAT(callback1.GetResult(rv), IsOk());
LoadTimingInfo load_timing_info1;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info1));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info1));
TestLoadTimingNotReused(load_timing_info1, CONNECT_TIMING_HAS_DNS_TIMES);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get()));
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar),
- callback2.callback());
- ASSERT_EQ(OK, callback2.GetResult(rv));
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar),
+ callback2.callback());
+ ASSERT_THAT(callback2.GetResult(rv), IsOk());
LoadTimingInfo load_timing_info2;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info2));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info2));
TestLoadTimingReused(load_timing_info2);
// The load timing after restart should have the same socket ID, and times
// those of the first load timing.
@@ -2619,24 +2532,24 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
load_timing_info2.send_start);
EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(5, response->headers->GetContentLength());
std::string response_data;
- EXPECT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ EXPECT_THAT(ReadTransaction(&trans, &response_data), IsOk());
int64_t writes_size = CountWriteBytes(data_writes, arraysize(data_writes));
- EXPECT_EQ(writes_size, trans->GetTotalSentBytes());
+ EXPECT_EQ(writes_size, trans.GetTotalSentBytes());
int64_t reads_size = CountReadBytes(data_reads, arraysize(data_reads));
- EXPECT_EQ(reads_size, trans->GetTotalReceivedBytes());
+ EXPECT_EQ(reads_size, trans.GetTotalReceivedBytes());
}
}
// Test the request-challenge-retry sequence for basic auth, over a keep-alive
// connection and with no response body to drain.
-TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
+TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -2645,18 +2558,16 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
MockWrite data_writes1[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.example.org\r\n"
+ "Connection: keep-alive\r\n\r\n"),
- // After calling trans->RestartWithAuth(), this is the request we should
+ // After calling trans.RestartWithAuth(), this is the request we should
// be issuing -- the final header line contains the credentials.
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.example.org\r\n"
+ "Connection: keep-alive\r\n"
+ "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
};
MockRead data_reads1[] = {
@@ -2685,28 +2596,26 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get()));
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(5, response->headers->GetContentLength());
@@ -2714,7 +2623,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
// Test the request-challenge-retry sequence for basic auth, over a keep-alive
// connection and with a large response body to drain.
-TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
+TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -2723,18 +2632,16 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
MockWrite data_writes1[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.example.org\r\n"
+ "Connection: keep-alive\r\n\r\n"),
- // After calling trans->RestartWithAuth(), this is the request we should
+ // After calling trans.RestartWithAuth(), this is the request we should
// be issuing -- the final header line contains the credentials.
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.example.org\r\n"
+ "Connection: keep-alive\r\n"
+ "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
};
// Respond with 5 kb of response body.
@@ -2771,28 +2678,26 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get()));
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(5, response->headers->GetContentLength());
@@ -2800,7 +2705,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
// Test the request-challenge-retry sequence for basic auth, over a keep-alive
// connection, but the server gets impatient and closes the connection.
-TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) {
+TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -2833,7 +2738,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) {
MockRead(SYNCHRONOUS, OK), // The server closes the connection.
};
- // After calling trans->RestartWithAuth(), this is the request we should
+ // After calling trans.RestartWithAuth(), this is the request we should
// be issuing -- the final header line contains the credentials.
MockWrite data_writes2[] = {
MockWrite(
@@ -2860,28 +2765,26 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get()));
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(5, response->headers->GetContentLength());
@@ -2889,7 +2792,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) {
// Test the request-challenge-retry sequence for basic auth, over a connection
// that requires a restart when setting up an SSL tunnel.
-TEST_P(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAliveHttp10) {
+TEST_F(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAliveHttp10) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -2953,22 +2856,23 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAliveHttp10) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
TestNetLogEntry::List entries;
log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLog::PHASE_NONE);
+ entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLogEventPhase::NONE);
ExpectLogContainsSomewhere(
- entries, pos, NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLog::PHASE_NONE);
+ entries, pos,
+ NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLogEventPhase::NONE);
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -2987,10 +2891,10 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAliveHttp10) {
rv =
trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -3013,7 +2917,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAliveHttp10) {
// Test the request-challenge-retry sequence for basic auth, over a connection
// that requires a restart when setting up an SSL tunnel.
-TEST_P(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAliveHttp11) {
+TEST_F(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAliveHttp11) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -3076,23 +2980,23 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAliveHttp11) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
TestNetLogEntry::List entries;
log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLog::PHASE_NONE);
+ entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLogEventPhase::NONE);
ExpectLogContainsSomewhere(
entries, pos,
- NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLog::PHASE_NONE);
+ NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLogEventPhase::NONE);
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -3111,10 +3015,10 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAliveHttp11) {
rv = trans->RestartWithAuth(
AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -3137,7 +3041,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAliveHttp11) {
// Test the request-challenge-retry sequence for basic auth, over a keep-alive
// proxy connection with HTTP/1.0 responses, when setting up an SSL tunnel.
-TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp10) {
+TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp10) {
// On the second pass, the body read of the auth challenge is synchronous, so
// IsConnectedAndIdle returns false. The socket should still be drained and
// reused. See http://crbug.com/544255.
@@ -3155,8 +3059,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp10) {
session_deps_.net_log = log.bound().net_log();
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Since we have proxy, should try to establish tunnel.
MockWrite data_writes1[] = {
@@ -3165,7 +3068,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp10) {
"Host: www.example.org:443\r\n"
"Proxy-Connection: keep-alive\r\n\r\n"),
- // After calling trans->RestartWithAuth(), this is the request we should
+ // After calling trans.RestartWithAuth(), this is the request we should
// be issuing -- the final header line contains the credentials.
MockWrite(ASYNC, 3,
"CONNECT www.example.org:443 HTTP/1.1\r\n"
@@ -3202,20 +3105,20 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp10) {
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(OK, callback1.GetResult(rv));
+ int rv = trans.Start(&request, callback1.callback(), log.bound());
+ EXPECT_THAT(callback1.GetResult(rv), IsOk());
TestNetLogEntry::List entries;
log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLog::PHASE_NONE);
+ entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLogEventPhase::NONE);
ExpectLogContainsSomewhere(
entries, pos,
- NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLog::PHASE_NONE);
+ NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLogEventPhase::NONE);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_TRUE(response->headers->IsKeepAlive());
@@ -3227,11 +3130,11 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp10) {
TestCompletionCallback callback2;
// Wrong password (should be "bar").
- rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBaz),
- callback2.callback());
- EXPECT_EQ(OK, callback2.GetResult(rv));
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBaz),
+ callback2.callback());
+ EXPECT_THAT(callback2.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_TRUE(response->headers->IsKeepAlive());
@@ -3248,7 +3151,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp10) {
// Test the request-challenge-retry sequence for basic auth, over a keep-alive
// proxy connection with HTTP/1.1 responses, when setting up an SSL tunnel.
-TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp11) {
+TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp11) {
// On the second pass, the body read of the auth challenge is synchronous, so
// IsConnectedAndIdle returns false. The socket should still be drained and
// reused. See http://crbug.com/544255.
@@ -3266,8 +3169,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp11) {
session_deps_.net_log = log.bound().net_log();
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Since we have proxy, should try to establish tunnel.
MockWrite data_writes1[] = {
@@ -3276,7 +3178,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp11) {
"Host: www.example.org:443\r\n"
"Proxy-Connection: keep-alive\r\n\r\n"),
- // After calling trans->RestartWithAuth(), this is the request we should
+ // After calling trans.RestartWithAuth(), this is the request we should
// be issuing -- the final header line contains the credentials.
MockWrite(ASYNC, 3,
"CONNECT www.example.org:443 HTTP/1.1\r\n"
@@ -3311,20 +3213,20 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp11) {
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(OK, callback1.GetResult(rv));
+ int rv = trans.Start(&request, callback1.callback(), log.bound());
+ EXPECT_THAT(callback1.GetResult(rv), IsOk());
TestNetLogEntry::List entries;
log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLog::PHASE_NONE);
+ entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLogEventPhase::NONE);
ExpectLogContainsSomewhere(
entries, pos,
- NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLog::PHASE_NONE);
+ NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLogEventPhase::NONE);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_TRUE(response->headers->IsKeepAlive());
@@ -3336,11 +3238,11 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp11) {
TestCompletionCallback callback2;
// Wrong password (should be "bar").
- rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBaz),
- callback2.callback());
- EXPECT_EQ(OK, callback2.GetResult(rv));
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBaz),
+ callback2.callback());
+ EXPECT_THAT(callback2.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_TRUE(response->headers->IsKeepAlive());
@@ -3359,7 +3261,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp11) {
// proxy connection with HTTP/1.1 responses, when setting up an SSL tunnel, in
// the case the server sends extra data on the original socket, so it can't be
// reused.
-TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveExtraData) {
+TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveExtraData) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -3431,21 +3333,21 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveExtraData) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(OK, callback1.GetResult(rv));
+ EXPECT_THAT(callback1.GetResult(rv), IsOk());
TestNetLogEntry::List entries;
log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLog::PHASE_NONE);
+ entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLogEventPhase::NONE);
ExpectLogContainsSomewhere(
entries, pos,
- NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLog::PHASE_NONE);
+ NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLogEventPhase::NONE);
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -3464,7 +3366,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveExtraData) {
rv =
trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_EQ(OK, callback2.GetResult(rv));
+ EXPECT_THAT(callback2.GetResult(rv), IsOk());
EXPECT_TRUE(response->headers->IsKeepAlive());
EXPECT_EQ(200, response->headers->response_code());
@@ -3484,7 +3386,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveExtraData) {
// Test the case a proxy closes a socket while the challenge body is being
// drained.
-TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHangupDuringBody) {
+TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHangupDuringBody) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -3496,8 +3398,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHangupDuringBody) {
session_deps_.proxy_service = ProxyService::CreateFixed("myproxy:70");
std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Since we have proxy, should try to establish tunnel.
MockWrite data_writes1[] = {
@@ -3518,7 +3419,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHangupDuringBody) {
};
MockWrite data_writes2[] = {
- // After calling trans->RestartWithAuth(), this is the request we should
+ // After calling trans.RestartWithAuth(), this is the request we should
// be issuing -- the final header line contains the credentials.
MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
"Host: www.example.org:443\r\n"
@@ -3550,32 +3451,32 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHangupDuringBody) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_TRUE(response->headers->IsKeepAlive());
EXPECT_EQ(407, response->headers->response_code());
EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get()));
- rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_TRUE(response->headers->IsKeepAlive());
EXPECT_EQ(200, response->headers->response_code());
std::string body;
- EXPECT_EQ(OK, ReadTransaction(trans.get(), &body));
+ EXPECT_THAT(ReadTransaction(&trans, &body), IsOk());
EXPECT_EQ("hello", body);
}
// Test that we don't read the response body when we fail to establish a tunnel,
// even if the user cancels the proxy's auth attempt.
-TEST_P(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) {
+TEST_F(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -3586,8 +3487,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Since we have proxy, should try to establish tunnel.
MockWrite data_writes[] = {
@@ -3611,13 +3511,13 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_TRUE(response->headers->IsKeepAlive());
@@ -3625,8 +3525,8 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) {
EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
// Flush the idle socket before the HttpNetworkTransaction goes out of scope.
session->CloseAllConnections();
@@ -3634,7 +3534,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) {
// Test that we don't pass extraneous headers from the proxy's response to the
// caller when the proxy responds to CONNECT with 407.
-TEST_P(HttpNetworkTransactionTest, SanitizeProxyAuthHeaders) {
+TEST_F(HttpNetworkTransactionTest, SanitizeProxyAuthHeaders) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -3645,8 +3545,7 @@ TEST_P(HttpNetworkTransactionTest, SanitizeProxyAuthHeaders) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Since we have proxy, should try to establish tunnel.
MockWrite data_writes[] = {
@@ -3671,13 +3570,13 @@ TEST_P(HttpNetworkTransactionTest, SanitizeProxyAuthHeaders) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_TRUE(response->headers->IsKeepAlive());
@@ -3687,8 +3586,8 @@ TEST_P(HttpNetworkTransactionTest, SanitizeProxyAuthHeaders) {
EXPECT_FALSE(response->headers->HasHeader("Set-Cookie"));
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
// Flush the idle socket before the HttpNetworkTransaction goes out of scope.
session->CloseAllConnections();
@@ -3696,7 +3595,7 @@ TEST_P(HttpNetworkTransactionTest, SanitizeProxyAuthHeaders) {
// Test when a server (non-proxy) returns a 407 (proxy-authenticate).
// The request should fail with ERR_UNEXPECTED_PROXY_AUTH.
-TEST_P(HttpNetworkTransactionTest, UnexpectedProxyAuth) {
+TEST_F(HttpNetworkTransactionTest, UnexpectedProxyAuth) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -3704,8 +3603,7 @@ TEST_P(HttpNetworkTransactionTest, UnexpectedProxyAuth) {
// We are using a DIRECT connection (i.e. no proxy) for this session.
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes1[] = {
MockWrite(
@@ -3728,11 +3626,11 @@ TEST_P(HttpNetworkTransactionTest, UnexpectedProxyAuth) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv);
+ EXPECT_THAT(rv, IsError(ERR_UNEXPECTED_PROXY_AUTH));
}
// Tests when an HTTPS server (non-proxy) returns a 407 (proxy-authentication)
@@ -3742,8 +3640,7 @@ TEST_P(HttpNetworkTransactionTest, UnexpectedProxyAuth) {
// a non-authenticating proxy - there is nothing to indicate whether the
// response came from the proxy or the server, so it is treated as if the proxy
// issued the challenge.
-TEST_P(HttpNetworkTransactionTest,
- HttpsServerRequestsProxyAuthThroughProxy) {
+TEST_F(HttpNetworkTransactionTest, HttpsServerRequestsProxyAuthThroughProxy) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -3781,28 +3678,27 @@ TEST_P(HttpNetworkTransactionTest,
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), log.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv);
+ EXPECT_THAT(rv, IsError(ERR_UNEXPECTED_PROXY_AUTH));
TestNetLogEntry::List entries;
log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLog::PHASE_NONE);
+ entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLogEventPhase::NONE);
ExpectLogContainsSomewhere(
entries, pos,
- NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLog::PHASE_NONE);
+ NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLogEventPhase::NONE);
}
// Test a proxy auth scheme that allows default credentials and a proxy server
// that uses non-persistent connections.
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
AuthAllowsDefaultCredentialsTunnelConnectionClose) {
HttpRequestInfo request;
request.method = "GET";
@@ -3875,12 +3771,12 @@ TEST_P(HttpNetworkTransactionTest,
SSLSocketDataProvider ssl(ASYNC, OK);
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -3897,7 +3793,7 @@ TEST_P(HttpNetworkTransactionTest,
EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info));
rv = trans->RestartWithAuth(AuthCredentials(), callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
response = trans->GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
@@ -3919,7 +3815,7 @@ TEST_P(HttpNetworkTransactionTest,
// Test a proxy auth scheme that allows default credentials and a proxy server
// that hangs up when credentials are initially sent.
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
AuthAllowsDefaultCredentialsTunnelServerClosesConnection) {
HttpRequestInfo request;
request.method = "GET";
@@ -3995,12 +3891,12 @@ TEST_P(HttpNetworkTransactionTest,
SSLSocketDataProvider ssl(ASYNC, OK);
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -4017,7 +3913,7 @@ TEST_P(HttpNetworkTransactionTest,
EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info));
rv = trans->RestartWithAuth(AuthCredentials(), callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -4041,7 +3937,7 @@ TEST_P(HttpNetworkTransactionTest,
// Test a proxy auth scheme that allows default credentials and a proxy server
// that hangs up when credentials are initially sent, and hangs up again when
// they are retried.
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
AuthAllowsDefaultCredentialsTunnelServerClosesConnectionTwice) {
HttpRequestInfo request;
request.method = "GET";
@@ -4110,12 +4006,12 @@ TEST_P(HttpNetworkTransactionTest,
data_writes2, arraysize(data_writes2));
session_deps_.socket_factory->AddSocketDataProvider(&data2);
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -4130,7 +4026,7 @@ TEST_P(HttpNetworkTransactionTest,
EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info));
rv = trans->RestartWithAuth(AuthCredentials(), callback.callback());
- EXPECT_EQ(ERR_EMPTY_RESPONSE, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsError(ERR_EMPTY_RESPONSE));
trans.reset();
session->CloseAllConnections();
@@ -4139,7 +4035,7 @@ TEST_P(HttpNetworkTransactionTest,
// Test a proxy auth scheme that allows default credentials and a proxy server
// that hangs up when credentials are initially sent, and sends a challenge
// again they are retried.
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
AuthAllowsDefaultCredentialsTunnelServerChallengesTwice) {
HttpRequestInfo request;
request.method = "GET";
@@ -4209,12 +4105,12 @@ TEST_P(HttpNetworkTransactionTest,
SSLSocketDataProvider ssl(ASYNC, OK);
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -4228,7 +4124,7 @@ TEST_P(HttpNetworkTransactionTest,
EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info));
rv = trans->RestartWithAuth(AuthCredentials(), callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
response = trans->GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
@@ -4240,8 +4136,140 @@ TEST_P(HttpNetworkTransactionTest,
session->CloseAllConnections();
}
+// A more nuanced test than GenerateAuthToken test which asserts that
+// ERR_INVALID_AUTH_CREDENTIALS does not cause the auth scheme to be
+// unnecessarily invalidated, and that if the server co-operates, the
+// authentication handshake can continue with the same scheme but with a
+// different identity.
+TEST_F(HttpNetworkTransactionTest, NonPermanentGenerateAuthTokenError) {
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.example.org/");
+
+ std::unique_ptr<HttpAuthHandlerMock::Factory> auth_handler_factory(
+ new HttpAuthHandlerMock::Factory());
+ auth_handler_factory->set_do_init_from_challenge(true);
+
+ // First handler. Uses default credentials, but barfs at generate auth token.
+ std::unique_ptr<HttpAuthHandlerMock> mock_handler(new HttpAuthHandlerMock());
+ mock_handler->set_allows_default_credentials(true);
+ mock_handler->set_allows_explicit_credentials(true);
+ mock_handler->set_connection_based(true);
+ mock_handler->SetGenerateExpectation(true, ERR_INVALID_AUTH_CREDENTIALS);
+ auth_handler_factory->AddMockHandler(mock_handler.release(),
+ HttpAuth::AUTH_SERVER);
+
+ // Add another handler for the second challenge. It supports default
+ // credentials, but they shouldn't be used, since they were already tried.
+ mock_handler.reset(new HttpAuthHandlerMock());
+ mock_handler->set_allows_default_credentials(true);
+ mock_handler->set_allows_explicit_credentials(true);
+ mock_handler->set_connection_based(true);
+ auth_handler_factory->AddMockHandler(mock_handler.release(),
+ HttpAuth::AUTH_SERVER);
+ session_deps_.http_auth_handler_factory = std::move(auth_handler_factory);
+
+ std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
+
+ MockWrite data_writes1[] = {
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.example.org\r\n"
+ "Connection: keep-alive\r\n\r\n"),
+ };
+
+ MockRead data_reads1[] = {
+ MockRead("HTTP/1.1 401 Authentication Required\r\n"
+ "WWW-Authenticate: Mock\r\n"
+ "Connection: keep-alive\r\n\r\n"),
+ };
+
+ // Identical to data_writes1[]. The AuthHandler encounters a
+ // ERR_INVALID_AUTH_CREDENTIALS during the GenerateAuthToken stage, so the
+ // transaction procceds without an authorization header.
+ MockWrite data_writes2[] = {
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.example.org\r\n"
+ "Connection: keep-alive\r\n\r\n"),
+ };
+
+ MockRead data_reads2[] = {
+ MockRead("HTTP/1.1 401 Authentication Required\r\n"
+ "WWW-Authenticate: Mock\r\n"
+ "Connection: keep-alive\r\n\r\n"),
+ };
+
+ MockWrite data_writes3[] = {
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.example.org\r\n"
+ "Connection: keep-alive\r\n"
+ "Authorization: auth_token\r\n\r\n"),
+ };
+
+ MockRead data_reads3[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"
+ "Content-Length: 5\r\n"
+ "Content-Type: text/plain\r\n"
+ "Connection: keep-alive\r\n\r\n"
+ "Hello"),
+ };
+
+ StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
+ data_writes1, arraysize(data_writes1));
+ session_deps_.socket_factory->AddSocketDataProvider(&data1);
+
+ StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
+ data_writes2, arraysize(data_writes2));
+ session_deps_.socket_factory->AddSocketDataProvider(&data2);
+
+ StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3),
+ data_writes3, arraysize(data_writes3));
+ session_deps_.socket_factory->AddSocketDataProvider(&data3);
+
+ std::unique_ptr<HttpNetworkTransaction> trans(
+ new 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_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
+
+ // The following three tests assert that an authentication challenge was
+ // received and that the stack is ready to respond to the challenge using
+ // ambient credentials.
+ EXPECT_EQ(401, response->headers->response_code());
+ EXPECT_TRUE(trans->IsReadyToRestartForAuth());
+ EXPECT_FALSE(response->auth_challenge);
+
+ rv = trans->RestartWithAuth(AuthCredentials(), callback.callback());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
+ response = trans->GetResponseInfo();
+ ASSERT_TRUE(response);
+ ASSERT_TRUE(response->headers);
+
+ // The following three tests assert that an authentication challenge was
+ // received and that the stack needs explicit credentials before it is ready
+ // to respond to the challenge.
+ EXPECT_EQ(401, response->headers->response_code());
+ EXPECT_FALSE(trans->IsReadyToRestartForAuth());
+ EXPECT_TRUE(response->auth_challenge);
+
+ rv = trans->RestartWithAuth(AuthCredentials(), callback.callback());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
+ response = trans->GetResponseInfo();
+ ASSERT_TRUE(response);
+ ASSERT_TRUE(response->headers);
+ EXPECT_EQ(200, response->headers->response_code());
+
+ trans.reset();
+ session->CloseAllConnections();
+}
+
// Test the load timing for HTTPS requests with an HTTP proxy.
-TEST_P(HttpNetworkTransactionTest, HttpProxyLoadTimingNoPacTwoRequests) {
+TEST_F(HttpNetworkTransactionTest, HttpProxyLoadTimingNoPacTwoRequests) {
HttpRequestInfo request1;
request1.method = "GET";
request1.url = GURL("https://www.example.org/1");
@@ -4292,17 +4320,18 @@ TEST_P(HttpNetworkTransactionTest, HttpProxyLoadTimingNoPacTwoRequests) {
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans1(
+ std::unique_ptr<HttpNetworkTransaction> trans1(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
int rv = trans1->Start(&request1, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
const HttpResponseInfo* response1 = trans1->GetResponseInfo();
ASSERT_TRUE(response1);
+ EXPECT_TRUE(response1->proxy_server.is_http());
ASSERT_TRUE(response1->headers);
EXPECT_EQ(1, response1->headers->GetContentLength());
@@ -4313,17 +4342,18 @@ TEST_P(HttpNetworkTransactionTest, HttpProxyLoadTimingNoPacTwoRequests) {
trans1.reset();
TestCompletionCallback callback2;
- std::unique_ptr<HttpTransaction> trans2(
+ std::unique_ptr<HttpNetworkTransaction> trans2(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
rv = trans2->Start(&request2, callback2.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
const HttpResponseInfo* response2 = trans2->GetResponseInfo();
ASSERT_TRUE(response2);
+ EXPECT_TRUE(response2->proxy_server.is_http());
ASSERT_TRUE(response2->headers);
EXPECT_EQ(2, response2->headers->GetContentLength());
@@ -4338,7 +4368,7 @@ TEST_P(HttpNetworkTransactionTest, HttpProxyLoadTimingNoPacTwoRequests) {
}
// Test the load timing for HTTPS requests with an HTTP proxy and a PAC script.
-TEST_P(HttpNetworkTransactionTest, HttpProxyLoadTimingWithPacTwoRequests) {
+TEST_F(HttpNetworkTransactionTest, HttpProxyLoadTimingWithPacTwoRequests) {
HttpRequestInfo request1;
request1.method = "GET";
request1.url = GURL("https://www.example.org/1");
@@ -4390,14 +4420,14 @@ TEST_P(HttpNetworkTransactionTest, HttpProxyLoadTimingWithPacTwoRequests) {
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans1(
+ std::unique_ptr<HttpNetworkTransaction> trans1(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
int rv = trans1->Start(&request1, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
const HttpResponseInfo* response1 = trans1->GetResponseInfo();
ASSERT_TRUE(response1);
@@ -4412,14 +4442,14 @@ TEST_P(HttpNetworkTransactionTest, HttpProxyLoadTimingWithPacTwoRequests) {
trans1.reset();
TestCompletionCallback callback2;
- std::unique_ptr<HttpTransaction> trans2(
+ std::unique_ptr<HttpNetworkTransaction> trans2(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
rv = trans2->Start(&request2, callback2.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
const HttpResponseInfo* response2 = trans2->GetResponseInfo();
ASSERT_TRUE(response2);
@@ -4437,7 +4467,7 @@ TEST_P(HttpNetworkTransactionTest, HttpProxyLoadTimingWithPacTwoRequests) {
}
// Test a simple get through an HTTPS Proxy.
-TEST_P(HttpNetworkTransactionTest, HttpsProxyGet) {
+TEST_F(HttpNetworkTransactionTest, HttpsProxyGet) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -4471,23 +4501,23 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxyGet) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), log.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReused(load_timing_info,
CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
+ EXPECT_TRUE(response->proxy_server.is_https());
EXPECT_TRUE(response->headers->IsKeepAlive());
EXPECT_EQ(200, response->headers->response_code());
EXPECT_EQ(100, response->headers->GetContentLength());
@@ -4498,7 +4528,7 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxyGet) {
}
// Test a SPDY get through an HTTPS Proxy.
-TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGet) {
+TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGet) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -4511,16 +4541,14 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGet) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
// fetch http://www.example.org/ via SPDY
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet("http://www.example.org/", 1, LOWEST));
- MockWrite spdy_writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite spdy_writes[] = {CreateMockWrite(req, 0)};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> data(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead spdy_reads[] = {
- CreateMockRead(*resp, 1), CreateMockRead(*data, 2), MockRead(ASYNC, 0, 3),
+ CreateMockRead(resp, 1), CreateMockRead(data, 2), MockRead(ASYNC, 0, 3),
};
SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
@@ -4528,39 +4556,39 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGet) {
session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
+ ssl.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), log.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReused(load_timing_info,
CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
+ EXPECT_TRUE(response->proxy_server.is_https());
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
EXPECT_EQ(kUploadData, response_data);
}
// Verifies that a session which races and wins against the owning transaction
// (completing prior to host resolution), doesn't fail the transaction.
// Regression test for crbug.com/334413.
-TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGetWithSessionRace) {
+TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGetWithSessionRace) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -4573,16 +4601,14 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGetWithSessionRace) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
// Fetch http://www.example.org/ through the SPDY proxy.
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet("http://www.example.org/", 1, LOWEST));
- MockWrite spdy_writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite spdy_writes[] = {CreateMockWrite(req, 0)};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> data(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead spdy_reads[] = {
- CreateMockRead(*resp, 1), CreateMockRead(*data, 2), MockRead(ASYNC, 0, 3),
+ CreateMockRead(resp, 1), CreateMockRead(data, 2), MockRead(ASYNC, 0, 3),
};
SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
@@ -4590,20 +4616,19 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGetWithSessionRace) {
session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
+ ssl.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Stall the hostname resolution begun by the transaction.
session_deps_.host_resolver->set_synchronous_mode(false);
session_deps_.host_resolver->set_ondemand_mode(true);
- int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), log.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Race a session to the proxy, which completes first.
session_deps_.host_resolver->set_ondemand_mode(false);
@@ -4618,20 +4643,20 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGetWithSessionRace) {
EXPECT_FALSE(callback1.have_result());
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
EXPECT_EQ(kUploadData, response_data);
}
// Test a SPDY get through an HTTPS Proxy.
-TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) {
+TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -4646,18 +4671,17 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) {
// The first request will be a bare GET, the second request will be a
// GET with a Proxy-Authorization header.
spdy_util_.set_default_url(request.url);
- std::unique_ptr<SpdySerializedFrame> req_get(
+ SpdySerializedFrame req_get(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, false));
spdy_util_.UpdateWithStreamDestruction(1);
const char* const kExtraAuthorizationHeaders[] = {
"proxy-authorization", "Basic Zm9vOmJhcg=="
};
- std::unique_ptr<SpdySerializedFrame> req_get_authorization(
- spdy_util_.ConstructSpdyGet(kExtraAuthorizationHeaders,
- arraysize(kExtraAuthorizationHeaders) / 2, 3,
- LOWEST, false));
+ SpdySerializedFrame req_get_authorization(spdy_util_.ConstructSpdyGet(
+ kExtraAuthorizationHeaders, arraysize(kExtraAuthorizationHeaders) / 2, 3,
+ LOWEST, false));
MockWrite spdy_writes[] = {
- CreateMockWrite(*req_get, 0), CreateMockWrite(*req_get_authorization, 3),
+ CreateMockWrite(req_get, 0), CreateMockWrite(req_get_authorization, 3),
};
// The first response is a 407 proxy authentication challenge, and the second
@@ -4666,21 +4690,18 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) {
const char* const kExtraAuthenticationHeaders[] = {
"proxy-authenticate", "Basic realm=\"MyRealm1\""
};
- std::unique_ptr<SpdySerializedFrame> resp_authentication(
- spdy_util_.ConstructSpdySynReplyError(
- "407 Proxy Authentication Required", kExtraAuthenticationHeaders,
- arraysize(kExtraAuthenticationHeaders) / 2, 1));
- std::unique_ptr<SpdySerializedFrame> body_authentication(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> resp_data(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> body_data(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
+ SpdySerializedFrame resp_authentication(spdy_util_.ConstructSpdyReplyError(
+ "407 Proxy Authentication Required", kExtraAuthenticationHeaders,
+ arraysize(kExtraAuthenticationHeaders) / 2, 1));
+ SpdySerializedFrame body_authentication(
+ spdy_util_.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame resp_data(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame body_data(spdy_util_.ConstructSpdyDataFrame(3, true));
MockRead spdy_reads[] = {
- CreateMockRead(*resp_authentication, 1),
- CreateMockRead(*body_authentication, 2),
- CreateMockRead(*resp_data, 4),
- CreateMockRead(*body_data, 5),
+ CreateMockRead(resp_authentication, 1),
+ CreateMockRead(body_authentication, 2),
+ CreateMockRead(resp_data, 4),
+ CreateMockRead(body_data, 5),
MockRead(ASYNC, 0, 6),
};
@@ -4689,21 +4710,20 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) {
session_deps_.socket_factory->AddSocketDataProvider(&data);
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
+ ssl.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), log.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* const response = trans->GetResponseInfo();
+ const HttpResponseInfo* const response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
@@ -4713,14 +4733,13 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) {
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* const response_restart = trans->GetResponseInfo();
+ const HttpResponseInfo* const response_restart = trans.GetResponseInfo();
ASSERT_TRUE(response_restart);
ASSERT_TRUE(response_restart->headers);
@@ -4730,7 +4749,7 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) {
}
// Test a SPDY CONNECT through an HTTPS Proxy to an HTTPS (non-SPDY) Server.
-TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyConnectHttps) {
+TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectHttps) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -4742,11 +4761,10 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyConnectHttps) {
session_deps_.net_log = log.bound().net_log();
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// CONNECT to www.example.org:443 via SPDY
- std::unique_ptr<SpdySerializedFrame> connect(spdy_util_.ConstructSpdyConnect(
+ SpdySerializedFrame connect(spdy_util_.ConstructSpdyConnect(
NULL, 0, 1, LOWEST, HostPortPair("www.example.org", 443)));
// fetch https://www.example.org/ via HTTP
@@ -4754,30 +4772,28 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyConnectHttps) {
"GET / HTTP/1.1\r\n"
"Host: www.example.org\r\n"
"Connection: keep-alive\r\n\r\n";
- std::unique_ptr<SpdySerializedFrame> wrapped_get(
- spdy_util_.ConstructSpdyBodyFrame(1, get, strlen(get), false));
- std::unique_ptr<SpdySerializedFrame> conn_resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame wrapped_get(
+ spdy_util_.ConstructSpdyDataFrame(1, get, strlen(get), false));
+ SpdySerializedFrame conn_resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
const char resp[] = "HTTP/1.1 200 OK\r\n"
"Content-Length: 10\r\n\r\n";
- std::unique_ptr<SpdySerializedFrame> wrapped_get_resp(
- spdy_util_.ConstructSpdyBodyFrame(1, resp, strlen(resp), false));
- std::unique_ptr<SpdySerializedFrame> wrapped_body(
- spdy_util_.ConstructSpdyBodyFrame(1, "1234567890", 10, false));
- std::unique_ptr<SpdySerializedFrame> window_update(
- spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp->size()));
+ SpdySerializedFrame wrapped_get_resp(
+ spdy_util_.ConstructSpdyDataFrame(1, resp, strlen(resp), false));
+ SpdySerializedFrame wrapped_body(
+ spdy_util_.ConstructSpdyDataFrame(1, "1234567890", 10, false));
+ SpdySerializedFrame window_update(
+ spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp.size()));
MockWrite spdy_writes[] = {
- CreateMockWrite(*connect, 0),
- CreateMockWrite(*wrapped_get, 2),
- CreateMockWrite(*window_update, 6),
+ CreateMockWrite(connect, 0), CreateMockWrite(wrapped_get, 2),
+ CreateMockWrite(window_update, 6),
};
MockRead spdy_reads[] = {
- CreateMockRead(*conn_resp, 1, ASYNC),
- CreateMockRead(*wrapped_get_resp, 3, ASYNC),
- CreateMockRead(*wrapped_body, 4, ASYNC),
- CreateMockRead(*wrapped_body, 5, ASYNC),
+ CreateMockRead(conn_resp, 1, ASYNC),
+ CreateMockRead(wrapped_get_resp, 3, ASYNC),
+ CreateMockRead(wrapped_body, 4, ASYNC),
+ CreateMockRead(wrapped_body, 5, ASYNC),
MockRead(ASYNC, 0, 7),
};
@@ -4786,36 +4802,36 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyConnectHttps) {
session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
+ ssl.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
SSLSocketDataProvider ssl2(ASYNC, OK);
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), log.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_SSL_TIMES);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
EXPECT_EQ("1234567890", response_data);
}
// Test a SPDY CONNECT through an HTTPS Proxy to a SPDY server.
-TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyConnectSpdy) {
- SpdyTestUtil spdy_util_wrapped(GetProtocol(), GetDependenciesFromPriority());
+TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectSpdy) {
+ SpdyTestUtil spdy_util_wrapped;
HttpRequestInfo request;
request.method = "GET";
@@ -4828,45 +4844,40 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyConnectSpdy) {
session_deps_.net_log = log.bound().net_log();
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// CONNECT to www.example.org:443 via SPDY
- std::unique_ptr<SpdySerializedFrame> connect(spdy_util_.ConstructSpdyConnect(
+ SpdySerializedFrame connect(spdy_util_.ConstructSpdyConnect(
NULL, 0, 1, LOWEST, HostPortPair("www.example.org", 443)));
// fetch https://www.example.org/ via SPDY
const char kMyUrl[] = "https://www.example.org/";
- std::unique_ptr<SpdySerializedFrame> get(
+ SpdySerializedFrame get(
spdy_util_wrapped.ConstructSpdyGet(kMyUrl, 1, LOWEST));
- std::unique_ptr<SpdySerializedFrame> wrapped_get(
- spdy_util_.ConstructWrappedSpdyFrame(get, 1));
- std::unique_ptr<SpdySerializedFrame> conn_resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> get_resp(
- spdy_util_wrapped.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> wrapped_get_resp(
+ SpdySerializedFrame wrapped_get(spdy_util_.ConstructWrappedSpdyFrame(get, 1));
+ SpdySerializedFrame conn_resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame get_resp(
+ spdy_util_wrapped.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame wrapped_get_resp(
spdy_util_.ConstructWrappedSpdyFrame(get_resp, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_wrapped.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> wrapped_body(
+ SpdySerializedFrame body(spdy_util_wrapped.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame wrapped_body(
spdy_util_.ConstructWrappedSpdyFrame(body, 1));
- std::unique_ptr<SpdySerializedFrame> window_update_get_resp(
- spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp->size()));
- std::unique_ptr<SpdySerializedFrame> window_update_body(
- spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_body->size()));
+ SpdySerializedFrame window_update_get_resp(
+ spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp.size()));
+ SpdySerializedFrame window_update_body(
+ spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_body.size()));
MockWrite spdy_writes[] = {
- CreateMockWrite(*connect, 0),
- CreateMockWrite(*wrapped_get, 2),
- CreateMockWrite(*window_update_get_resp, 6),
- CreateMockWrite(*window_update_body, 7),
+ CreateMockWrite(connect, 0), CreateMockWrite(wrapped_get, 2),
+ CreateMockWrite(window_update_get_resp, 6),
+ CreateMockWrite(window_update_body, 7),
};
MockRead spdy_reads[] = {
- CreateMockRead(*conn_resp, 1, ASYNC),
+ CreateMockRead(conn_resp, 1, ASYNC),
MockRead(ASYNC, ERR_IO_PENDING, 3),
- CreateMockRead(*wrapped_get_resp, 4, ASYNC),
- CreateMockRead(*wrapped_body, 5, ASYNC),
+ CreateMockRead(wrapped_get_resp, 4, ASYNC),
+ CreateMockRead(wrapped_body, 5, ASYNC),
MockRead(ASYNC, 0, 8),
};
@@ -4875,40 +4886,40 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyConnectSpdy) {
session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
+ ssl.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
SSLSocketDataProvider ssl2(ASYNC, OK);
- ssl2.SetNextProto(GetProtocol());
+ ssl2.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), log.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Allow the SpdyProxyClientSocket's write callback to complete.
base::RunLoop().RunUntilIdle();
// Now allow the read of the response to complete.
spdy_data.Resume();
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_SSL_TIMES);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
EXPECT_EQ(kUploadData, response_data);
}
// Test a SPDY CONNECT failure through an HTTPS Proxy.
-TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyConnectFailure) {
+TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectFailure) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -4920,25 +4931,22 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyConnectFailure) {
session_deps_.net_log = log.bound().net_log();
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// CONNECT to www.example.org:443 via SPDY
- std::unique_ptr<SpdySerializedFrame> connect(spdy_util_.ConstructSpdyConnect(
+ SpdySerializedFrame connect(spdy_util_.ConstructSpdyConnect(
NULL, 0, 1, LOWEST, HostPortPair("www.example.org", 443)));
- std::unique_ptr<SpdySerializedFrame> get(
+ SpdySerializedFrame get(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite spdy_writes[] = {
- CreateMockWrite(*connect, 0), CreateMockWrite(*get, 2),
+ CreateMockWrite(connect, 0), CreateMockWrite(get, 2),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdySynReplyError(1));
- std::unique_ptr<SpdySerializedFrame> data(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyReplyError(1));
+ SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead spdy_reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, 0, 3),
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, 0, 3),
};
SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
@@ -4946,26 +4954,26 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyConnectFailure) {
session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
+ ssl.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
SSLSocketDataProvider ssl2(ASYNC, OK);
- ssl2.SetNextProto(GetProtocol());
+ ssl2.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), log.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
+ EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
// TODO(juliatuttle): Anything else to check here?
}
// Test load timing in the case of two HTTPS (non-SPDY) requests through a SPDY
// HTTPS Proxy to different servers.
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
HttpsProxySpdyConnectHttpsLoadTimingTwoRequestsTwoServers) {
// Configure against https proxy server "proxy:70".
session_deps_.proxy_service = ProxyService::CreateFixed("https://proxy:70");
@@ -4985,72 +4993,62 @@ TEST_P(HttpNetworkTransactionTest,
request2.load_flags = 0;
// CONNECT to www.example.org:443 via SPDY.
- std::unique_ptr<SpdySerializedFrame> connect1(spdy_util_.ConstructSpdyConnect(
+ SpdySerializedFrame connect1(spdy_util_.ConstructSpdyConnect(
NULL, 0, 1, LOWEST, HostPortPair("www.example.org", 443)));
- std::unique_ptr<SpdySerializedFrame> conn_resp1(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame conn_resp1(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
// Fetch https://www.example.org/ via HTTP.
const char get1[] =
"GET / HTTP/1.1\r\n"
"Host: www.example.org\r\n"
"Connection: keep-alive\r\n\r\n";
- std::unique_ptr<SpdySerializedFrame> wrapped_get1(
- spdy_util_.ConstructSpdyBodyFrame(1, get1, strlen(get1), false));
+ SpdySerializedFrame wrapped_get1(
+ spdy_util_.ConstructSpdyDataFrame(1, get1, strlen(get1), false));
const char resp1[] = "HTTP/1.1 200 OK\r\n"
"Content-Length: 1\r\n\r\n";
- std::unique_ptr<SpdySerializedFrame> wrapped_get_resp1(
- spdy_util_.ConstructSpdyBodyFrame(1, resp1, strlen(resp1), false));
- std::unique_ptr<SpdySerializedFrame> wrapped_body1(
- spdy_util_.ConstructSpdyBodyFrame(1, "1", 1, false));
- std::unique_ptr<SpdySerializedFrame> window_update(
- spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp1->size()));
+ SpdySerializedFrame wrapped_get_resp1(
+ spdy_util_.ConstructSpdyDataFrame(1, resp1, strlen(resp1), false));
+ SpdySerializedFrame wrapped_body1(
+ spdy_util_.ConstructSpdyDataFrame(1, "1", 1, false));
+ SpdySerializedFrame window_update(
+ spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp1.size()));
// CONNECT to mail.example.org:443 via SPDY.
SpdyHeaderBlock connect2_block;
- spdy_util_.MaybeAddVersionHeader(&connect2_block);
connect2_block[spdy_util_.GetMethodKey()] = "CONNECT";
- if (GetProtocol() == kProtoHTTP2) {
- connect2_block[spdy_util_.GetHostKey()] = "mail.example.org:443";
- } else {
- connect2_block[spdy_util_.GetHostKey()] = "mail.example.org";
- connect2_block[spdy_util_.GetPathKey()] = "mail.example.org:443";
- }
- std::unique_ptr<SpdySerializedFrame> connect2(
- spdy_util_.ConstructSpdySyn(3, std::move(connect2_block), LOWEST, false));
+ connect2_block[spdy_util_.GetHostKey()] = "mail.example.org:443";
+ SpdySerializedFrame connect2(spdy_util_.ConstructSpdyHeaders(
+ 3, std::move(connect2_block), LOWEST, false));
- std::unique_ptr<SpdySerializedFrame> conn_resp2(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
+ SpdySerializedFrame conn_resp2(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
// Fetch https://mail.example.org/ via HTTP.
const char get2[] =
"GET / HTTP/1.1\r\n"
"Host: mail.example.org\r\n"
"Connection: keep-alive\r\n\r\n";
- std::unique_ptr<SpdySerializedFrame> wrapped_get2(
- spdy_util_.ConstructSpdyBodyFrame(3, get2, strlen(get2), false));
+ SpdySerializedFrame wrapped_get2(
+ spdy_util_.ConstructSpdyDataFrame(3, get2, strlen(get2), false));
const char resp2[] = "HTTP/1.1 200 OK\r\n"
"Content-Length: 2\r\n\r\n";
- std::unique_ptr<SpdySerializedFrame> wrapped_get_resp2(
- spdy_util_.ConstructSpdyBodyFrame(3, resp2, strlen(resp2), false));
- std::unique_ptr<SpdySerializedFrame> wrapped_body2(
- spdy_util_.ConstructSpdyBodyFrame(3, "22", 2, false));
+ SpdySerializedFrame wrapped_get_resp2(
+ spdy_util_.ConstructSpdyDataFrame(3, resp2, strlen(resp2), false));
+ SpdySerializedFrame wrapped_body2(
+ spdy_util_.ConstructSpdyDataFrame(3, "22", 2, false));
MockWrite spdy_writes[] = {
- CreateMockWrite(*connect1, 0),
- CreateMockWrite(*wrapped_get1, 2),
- CreateMockWrite(*connect2, 5),
- CreateMockWrite(*wrapped_get2, 7),
+ CreateMockWrite(connect1, 0), CreateMockWrite(wrapped_get1, 2),
+ CreateMockWrite(connect2, 5), CreateMockWrite(wrapped_get2, 7),
};
MockRead spdy_reads[] = {
- CreateMockRead(*conn_resp1, 1, ASYNC),
- CreateMockRead(*wrapped_get_resp1, 3, ASYNC),
- CreateMockRead(*wrapped_body1, 4, ASYNC),
- CreateMockRead(*conn_resp2, 6, ASYNC),
- CreateMockRead(*wrapped_get_resp2, 8, ASYNC),
- CreateMockRead(*wrapped_body2, 9, ASYNC),
- MockRead(ASYNC, 0, 10),
+ CreateMockRead(conn_resp1, 1, ASYNC),
+ CreateMockRead(wrapped_get_resp1, 3, ASYNC),
+ CreateMockRead(wrapped_body1, 4, ASYNC),
+ CreateMockRead(conn_resp2, 6, ASYNC),
+ CreateMockRead(wrapped_get_resp2, 8, ASYNC),
+ CreateMockRead(wrapped_body2, 9, ASYNC),
+ MockRead(ASYNC, 0, 10),
};
SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
@@ -5058,7 +5056,7 @@ TEST_P(HttpNetworkTransactionTest,
session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
+ ssl.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
SSLSocketDataProvider ssl2(ASYNC, OK);
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
@@ -5067,32 +5065,30 @@ TEST_P(HttpNetworkTransactionTest,
TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans->Start(&request1, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
+ int rv = trans.Start(&request1, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_SSL_TIMES);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
std::string response_data;
scoped_refptr<IOBuffer> buf(new IOBuffer(256));
- rv = trans->Read(buf.get(), 256, callback.callback());
+ rv = trans.Read(buf.get(), 256, callback.callback());
EXPECT_EQ(1, callback.GetResult(rv));
- std::unique_ptr<HttpTransaction> trans2(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- rv = trans2->Start(&request2, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
+ rv = trans2.Start(&request2, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
LoadTimingInfo load_timing_info2;
- EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2));
+ EXPECT_TRUE(trans2.GetLoadTimingInfo(&load_timing_info2));
// Even though the SPDY connection is reused, a new tunnelled connection has
// to be created, so the socket's load timing looks like a fresh connection.
TestLoadTimingNotReused(load_timing_info2, CONNECT_TIMING_HAS_SSL_TIMES);
@@ -5101,13 +5097,13 @@ TEST_P(HttpNetworkTransactionTest,
// separate stream.
EXPECT_NE(load_timing_info.socket_log_id, load_timing_info2.socket_log_id);
- rv = trans2->Read(buf.get(), 256, callback.callback());
+ rv = trans2.Read(buf.get(), 256, callback.callback());
EXPECT_EQ(2, callback.GetResult(rv));
}
// Test load timing in the case of two HTTPS (non-SPDY) requests through a SPDY
// HTTPS Proxy to the same server.
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
HttpsProxySpdyConnectHttpsLoadTimingTwoRequestsSameServer) {
// Configure against https proxy server "proxy:70".
session_deps_.proxy_service = ProxyService::CreateFixed("https://proxy:70");
@@ -5127,54 +5123,52 @@ TEST_P(HttpNetworkTransactionTest,
request2.load_flags = 0;
// CONNECT to www.example.org:443 via SPDY.
- std::unique_ptr<SpdySerializedFrame> connect1(spdy_util_.ConstructSpdyConnect(
+ SpdySerializedFrame connect1(spdy_util_.ConstructSpdyConnect(
NULL, 0, 1, LOWEST, HostPortPair("www.example.org", 443)));
- std::unique_ptr<SpdySerializedFrame> conn_resp1(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame conn_resp1(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
// Fetch https://www.example.org/ via HTTP.
const char get1[] =
"GET / HTTP/1.1\r\n"
"Host: www.example.org\r\n"
"Connection: keep-alive\r\n\r\n";
- std::unique_ptr<SpdySerializedFrame> wrapped_get1(
- spdy_util_.ConstructSpdyBodyFrame(1, get1, strlen(get1), false));
+ SpdySerializedFrame wrapped_get1(
+ spdy_util_.ConstructSpdyDataFrame(1, get1, strlen(get1), false));
const char resp1[] = "HTTP/1.1 200 OK\r\n"
"Content-Length: 1\r\n\r\n";
- std::unique_ptr<SpdySerializedFrame> wrapped_get_resp1(
- spdy_util_.ConstructSpdyBodyFrame(1, resp1, strlen(resp1), false));
- std::unique_ptr<SpdySerializedFrame> wrapped_body1(
- spdy_util_.ConstructSpdyBodyFrame(1, "1", 1, false));
- std::unique_ptr<SpdySerializedFrame> window_update(
- spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp1->size()));
+ SpdySerializedFrame wrapped_get_resp1(
+ spdy_util_.ConstructSpdyDataFrame(1, resp1, strlen(resp1), false));
+ SpdySerializedFrame wrapped_body1(
+ spdy_util_.ConstructSpdyDataFrame(1, "1", 1, false));
+ SpdySerializedFrame window_update(
+ spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp1.size()));
// Fetch https://www.example.org/2 via HTTP.
const char get2[] =
"GET /2 HTTP/1.1\r\n"
"Host: www.example.org\r\n"
"Connection: keep-alive\r\n\r\n";
- std::unique_ptr<SpdySerializedFrame> wrapped_get2(
- spdy_util_.ConstructSpdyBodyFrame(1, get2, strlen(get2), false));
+ SpdySerializedFrame wrapped_get2(
+ spdy_util_.ConstructSpdyDataFrame(1, get2, strlen(get2), false));
const char resp2[] = "HTTP/1.1 200 OK\r\n"
"Content-Length: 2\r\n\r\n";
- std::unique_ptr<SpdySerializedFrame> wrapped_get_resp2(
- spdy_util_.ConstructSpdyBodyFrame(1, resp2, strlen(resp2), false));
- std::unique_ptr<SpdySerializedFrame> wrapped_body2(
- spdy_util_.ConstructSpdyBodyFrame(1, "22", 2, false));
+ SpdySerializedFrame wrapped_get_resp2(
+ spdy_util_.ConstructSpdyDataFrame(1, resp2, strlen(resp2), false));
+ SpdySerializedFrame wrapped_body2(
+ spdy_util_.ConstructSpdyDataFrame(1, "22", 2, false));
MockWrite spdy_writes[] = {
- CreateMockWrite(*connect1, 0),
- CreateMockWrite(*wrapped_get1, 2),
- CreateMockWrite(*wrapped_get2, 5),
+ CreateMockWrite(connect1, 0), CreateMockWrite(wrapped_get1, 2),
+ CreateMockWrite(wrapped_get2, 5),
};
MockRead spdy_reads[] = {
- CreateMockRead(*conn_resp1, 1, ASYNC),
- CreateMockRead(*wrapped_get_resp1, 3, ASYNC),
- CreateMockRead(*wrapped_body1, 4, ASYNC),
- CreateMockRead(*wrapped_get_resp2, 6, ASYNC),
- CreateMockRead(*wrapped_body2, 7, ASYNC),
- MockRead(ASYNC, 0, 8),
+ CreateMockRead(conn_resp1, 1, ASYNC),
+ CreateMockRead(wrapped_get_resp1, 3, ASYNC),
+ CreateMockRead(wrapped_body1, 4, ASYNC),
+ CreateMockRead(wrapped_get_resp2, 6, ASYNC),
+ CreateMockRead(wrapped_body2, 7, ASYNC),
+ MockRead(ASYNC, 0, 8),
};
SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
@@ -5182,20 +5176,20 @@ TEST_P(HttpNetworkTransactionTest,
session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
+ ssl.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
SSLSocketDataProvider ssl2(ASYNC, OK);
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans->Start(&request1, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&request1, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
LoadTimingInfo load_timing_info;
EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
@@ -5211,13 +5205,13 @@ TEST_P(HttpNetworkTransactionTest,
EXPECT_EQ(1, trans->Read(buf.get(), 256, callback.callback()));
trans.reset();
- std::unique_ptr<HttpTransaction> trans2(
+ std::unique_ptr<HttpNetworkTransaction> trans2(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- rv = trans2->Start(&request2, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans2->Start(&request2, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
LoadTimingInfo load_timing_info2;
EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2));
@@ -5231,7 +5225,7 @@ TEST_P(HttpNetworkTransactionTest,
// Test load timing in the case of of two HTTP requests through a SPDY HTTPS
// Proxy to different servers.
-TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyLoadTimingTwoHttpRequests) {
+TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyLoadTimingTwoHttpRequests) {
// Configure against https proxy server "proxy:70".
session_deps_.proxy_service = ProxyService::CreateFixed("https://proxy:70");
BoundTestNetLog log;
@@ -5252,35 +5246,31 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyLoadTimingTwoHttpRequests) {
// http://www.example.org/
SpdyHeaderBlock headers(
spdy_util_.ConstructGetHeaderBlockForProxy("http://www.example.org/"));
- std::unique_ptr<SpdySerializedFrame> get1(
- spdy_util_.ConstructSpdySyn(1, std::move(headers), LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> get_resp1(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body1(
- spdy_util_.ConstructSpdyBodyFrame(1, "1", 1, true));
+ SpdySerializedFrame get1(
+ spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
+ SpdySerializedFrame get_resp1(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, "1", 1, true));
spdy_util_.UpdateWithStreamDestruction(1);
// http://mail.example.org/
SpdyHeaderBlock headers2(
spdy_util_.ConstructGetHeaderBlockForProxy("http://mail.example.org/"));
- std::unique_ptr<SpdySerializedFrame> get2(
- spdy_util_.ConstructSpdySyn(3, std::move(headers2), LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> get_resp2(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(3, "22", 2, true));
+ SpdySerializedFrame get2(
+ spdy_util_.ConstructSpdyHeaders(3, std::move(headers2), LOWEST, true));
+ SpdySerializedFrame get_resp2(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame body2(
+ spdy_util_.ConstructSpdyDataFrame(3, "22", 2, true));
MockWrite spdy_writes[] = {
- CreateMockWrite(*get1, 0),
- CreateMockWrite(*get2, 3),
+ CreateMockWrite(get1, 0), CreateMockWrite(get2, 3),
};
MockRead spdy_reads[] = {
- CreateMockRead(*get_resp1, 1, ASYNC),
- CreateMockRead(*body1, 2, ASYNC),
- CreateMockRead(*get_resp2, 4, ASYNC),
- CreateMockRead(*body2, 5, ASYNC),
- MockRead(ASYNC, 0, 6),
+ CreateMockRead(get_resp1, 1, ASYNC),
+ CreateMockRead(body1, 2, ASYNC),
+ CreateMockRead(get_resp2, 4, ASYNC),
+ CreateMockRead(body2, 5, ASYNC),
+ MockRead(ASYNC, 0, 6),
};
SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
@@ -5288,15 +5278,15 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyLoadTimingTwoHttpRequests) {
session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
+ ssl.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans->Start(&request1, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans->Start(&request1, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
LoadTimingInfo load_timing_info;
EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
@@ -5315,24 +5305,23 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyLoadTimingTwoHttpRequests) {
// Delete the first request, so the second one can reuse the socket.
trans.reset();
- std::unique_ptr<HttpTransaction> trans2(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- rv = trans2->Start(&request2, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
+ rv = trans2.Start(&request2, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
LoadTimingInfo load_timing_info2;
- EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2));
+ EXPECT_TRUE(trans2.GetLoadTimingInfo(&load_timing_info2));
TestLoadTimingReused(load_timing_info2);
// The requests should have the same ID.
EXPECT_EQ(load_timing_info.socket_log_id, load_timing_info2.socket_log_id);
- rv = trans2->Read(buf.get(), 256, callback.callback());
+ rv = trans2.Read(buf.get(), 256, callback.callback());
EXPECT_EQ(2, callback.GetResult(rv));
}
// Test the challenge-response-retry sequence through an HTTPS Proxy
-TEST_P(HttpNetworkTransactionTest, HttpsProxyAuthRetry) {
+TEST_F(HttpNetworkTransactionTest, HttpsProxyAuthRetry) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -5347,18 +5336,16 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxyAuthRetry) {
// Since we have proxy, should use full url
MockWrite data_writes1[] = {
- MockWrite(
- "GET http://www.example.org/ HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
+ MockWrite("GET http://www.example.org/ HTTP/1.1\r\n"
+ "Host: www.example.org\r\n"
+ "Proxy-Connection: keep-alive\r\n\r\n"),
- // After calling trans->RestartWithAuth(), this is the request we should
+ // After calling trans.RestartWithAuth(), this is the request we should
// be issuing -- the final header line contains the credentials.
- MockWrite(
- "GET http://www.example.org/ HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
+ MockWrite("GET http://www.example.org/ HTTP/1.1\r\n"
+ "Host: www.example.org\r\n"
+ "Proxy-Connection: keep-alive\r\n"
+ "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
};
// The proxy responds to the GET with a 407, using a persistent
@@ -5384,21 +5371,20 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxyAuthRetry) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), log.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReused(load_timing_info,
CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ(407, response->headers->response_code());
@@ -5407,19 +5393,18 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxyAuthRetry) {
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
load_timing_info = LoadTimingInfo();
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
// Retrying with HTTP AUTH is considered to be reusing a socket.
TestLoadTimingReused(load_timing_info);
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers->IsKeepAlive());
@@ -5461,11 +5446,10 @@ void HttpNetworkTransactionTest::ConnectStatusHelperWithExpectedStatus(
TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
EXPECT_EQ(expected_status, rv);
@@ -5477,178 +5461,178 @@ void HttpNetworkTransactionTest::ConnectStatusHelper(
status, ERR_TUNNEL_CONNECTION_FAILED);
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus100) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus100) {
ConnectStatusHelper(MockRead("HTTP/1.1 100 Continue\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus101) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus101) {
ConnectStatusHelper(MockRead("HTTP/1.1 101 Switching Protocols\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus201) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus201) {
ConnectStatusHelper(MockRead("HTTP/1.1 201 Created\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus202) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus202) {
ConnectStatusHelper(MockRead("HTTP/1.1 202 Accepted\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus203) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus203) {
ConnectStatusHelper(
MockRead("HTTP/1.1 203 Non-Authoritative Information\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus204) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus204) {
ConnectStatusHelper(MockRead("HTTP/1.1 204 No Content\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus205) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus205) {
ConnectStatusHelper(MockRead("HTTP/1.1 205 Reset Content\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus206) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus206) {
ConnectStatusHelper(MockRead("HTTP/1.1 206 Partial Content\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus300) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus300) {
ConnectStatusHelper(MockRead("HTTP/1.1 300 Multiple Choices\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus301) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus301) {
ConnectStatusHelper(MockRead("HTTP/1.1 301 Moved Permanently\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus302) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus302) {
ConnectStatusHelper(MockRead("HTTP/1.1 302 Found\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus303) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus303) {
ConnectStatusHelper(MockRead("HTTP/1.1 303 See Other\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus304) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus304) {
ConnectStatusHelper(MockRead("HTTP/1.1 304 Not Modified\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus305) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus305) {
ConnectStatusHelper(MockRead("HTTP/1.1 305 Use Proxy\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus306) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus306) {
ConnectStatusHelper(MockRead("HTTP/1.1 306\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus307) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus307) {
ConnectStatusHelper(MockRead("HTTP/1.1 307 Temporary Redirect\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus308) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus308) {
ConnectStatusHelper(MockRead("HTTP/1.1 308 Permanent Redirect\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus400) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus400) {
ConnectStatusHelper(MockRead("HTTP/1.1 400 Bad Request\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus401) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus401) {
ConnectStatusHelper(MockRead("HTTP/1.1 401 Unauthorized\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus402) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus402) {
ConnectStatusHelper(MockRead("HTTP/1.1 402 Payment Required\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus403) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus403) {
ConnectStatusHelper(MockRead("HTTP/1.1 403 Forbidden\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus404) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus404) {
ConnectStatusHelper(MockRead("HTTP/1.1 404 Not Found\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus405) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus405) {
ConnectStatusHelper(MockRead("HTTP/1.1 405 Method Not Allowed\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus406) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus406) {
ConnectStatusHelper(MockRead("HTTP/1.1 406 Not Acceptable\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus407) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus407) {
ConnectStatusHelperWithExpectedStatus(
MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
ERR_PROXY_AUTH_UNSUPPORTED);
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus408) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus408) {
ConnectStatusHelper(MockRead("HTTP/1.1 408 Request Timeout\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus409) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus409) {
ConnectStatusHelper(MockRead("HTTP/1.1 409 Conflict\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus410) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus410) {
ConnectStatusHelper(MockRead("HTTP/1.1 410 Gone\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus411) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus411) {
ConnectStatusHelper(MockRead("HTTP/1.1 411 Length Required\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus412) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus412) {
ConnectStatusHelper(MockRead("HTTP/1.1 412 Precondition Failed\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus413) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus413) {
ConnectStatusHelper(MockRead("HTTP/1.1 413 Request Entity Too Large\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus414) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus414) {
ConnectStatusHelper(MockRead("HTTP/1.1 414 Request-URI Too Long\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus415) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus415) {
ConnectStatusHelper(MockRead("HTTP/1.1 415 Unsupported Media Type\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus416) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus416) {
ConnectStatusHelper(
MockRead("HTTP/1.1 416 Requested Range Not Satisfiable\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus417) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus417) {
ConnectStatusHelper(MockRead("HTTP/1.1 417 Expectation Failed\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus500) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus500) {
ConnectStatusHelper(MockRead("HTTP/1.1 500 Internal Server Error\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus501) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus501) {
ConnectStatusHelper(MockRead("HTTP/1.1 501 Not Implemented\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus502) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus502) {
ConnectStatusHelper(MockRead("HTTP/1.1 502 Bad Gateway\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus503) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus503) {
ConnectStatusHelper(MockRead("HTTP/1.1 503 Service Unavailable\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus504) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus504) {
ConnectStatusHelper(MockRead("HTTP/1.1 504 Gateway Timeout\r\n"));
}
-TEST_P(HttpNetworkTransactionTest, ConnectStatus505) {
+TEST_F(HttpNetworkTransactionTest, ConnectStatus505) {
ConnectStatusHelper(MockRead("HTTP/1.1 505 HTTP Version Not Supported\r\n"));
}
// Test the flow when both the proxy server AND origin server require
// authentication. Again, this uses basic auth for both since that is
// the simplest to mock.
-TEST_P(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
+TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -5658,8 +5642,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
session_deps_.proxy_service = ProxyService::CreateFixed("myproxy:70");
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes1[] = {
MockWrite(
@@ -5681,7 +5664,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
MockRead(SYNCHRONOUS, ERR_FAILED),
};
- // After calling trans->RestartWithAuth() the first time, this is the
+ // After calling trans.RestartWithAuth() the first time, this is the
// request we should be issuing -- the final header line contains the
// proxy's credentials.
MockWrite data_writes2[] = {
@@ -5704,7 +5687,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
MockRead(SYNCHRONOUS, ERR_FAILED), // Won't be reached.
};
- // After calling trans->RestartWithAuth() the second time, we should send
+ // After calling trans.RestartWithAuth() the second time, we should send
// the credentials for both the proxy and origin server.
MockWrite data_writes3[] = {
MockWrite(
@@ -5735,39 +5718,38 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get()));
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get()));
TestCompletionCallback callback3;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo2, kBar2), callback3.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo2, kBar2),
+ callback3.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback3.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(100, response->headers->GetContentLength());
}
@@ -5781,7 +5763,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
// bytes in the debugger.
// Enter the correct password and authenticate successfully.
-TEST_P(HttpNetworkTransactionTest, NTLMAuth1) {
+TEST_F(HttpNetworkTransactionTest, NTLMAuth1) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://172.22.68.17/kids/login.aspx");
@@ -5814,26 +5796,26 @@ TEST_P(HttpNetworkTransactionTest, NTLMAuth1) {
};
MockWrite data_writes2[] = {
- // After restarting with a null identity, this is the
- // request we should be issuing -- the final header line contains a Type
- // 1 message.
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: 172.22.68.17\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: NTLM "
- "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
-
- // After calling trans->RestartWithAuth(), we should send a Type 3 message
- // (the credentials for the origin server). The second request continues
- // on the same connection.
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: 172.22.68.17\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
- "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
- "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBVKW"
- "Yma5xzVAAAAAAAAAAAAAAAAAAAAACH+gWcm+YsP9Tqb9zCR3WAeZZX"
- "ahlhx5I=\r\n\r\n"),
+ // After restarting with a null identity, this is the
+ // request we should be issuing -- the final header line contains a Type
+ // 1 message.
+ MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
+ "Host: 172.22.68.17\r\n"
+ "Connection: keep-alive\r\n"
+ "Authorization: NTLM "
+ "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
+
+ // After calling trans.RestartWithAuth(), we should send a Type 3 message
+ // (the credentials for the origin server). The second request continues
+ // on the same connection.
+ MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
+ "Host: 172.22.68.17\r\n"
+ "Connection: keep-alive\r\n"
+ "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
+ "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
+ "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBVKW"
+ "Yma5xzVAAAAAAAAAAAAAAAAAAAAACH+gWcm+YsP9Tqb9zCR3WAeZZX"
+ "ahlhx5I=\r\n\r\n"),
};
MockRead data_reads2[] = {
@@ -5868,52 +5850,51 @@ TEST_P(HttpNetworkTransactionTest, NTLMAuth1) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- EXPECT_FALSE(trans->IsReadyToRestartForAuth());
+ EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get()));
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kTestingNTLM),
- callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kTestingNTLM, kTestingNTLM),
+ callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans->IsReadyToRestartForAuth());
+ EXPECT_TRUE(trans.IsReadyToRestartForAuth());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
TestCompletionCallback callback3;
- rv = trans->RestartWithAuth(AuthCredentials(), callback3.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(), callback3.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback3.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(13, response->headers->GetContentLength());
}
// Enter a wrong password, and then the correct one.
-TEST_P(HttpNetworkTransactionTest, NTLMAuth2) {
+TEST_F(HttpNetworkTransactionTest, NTLMAuth2) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://172.22.68.17/kids/login.aspx");
@@ -5943,26 +5924,26 @@ TEST_P(HttpNetworkTransactionTest, NTLMAuth2) {
};
MockWrite data_writes2[] = {
- // After restarting with a null identity, this is the
- // request we should be issuing -- the final header line contains a Type
- // 1 message.
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: 172.22.68.17\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: NTLM "
- "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
-
- // After calling trans->RestartWithAuth(), we should send a Type 3 message
- // (the credentials for the origin server). The second request continues
- // on the same connection.
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: 172.22.68.17\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
- "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
- "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwCWeY"
- "XnSZNwoQAAAAAAAAAAAAAAAAAAAADLa34/phTTKzNTWdub+uyFleOj"
- "4Ww7b7E=\r\n\r\n"),
+ // After restarting with a null identity, this is the
+ // request we should be issuing -- the final header line contains a Type
+ // 1 message.
+ MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
+ "Host: 172.22.68.17\r\n"
+ "Connection: keep-alive\r\n"
+ "Authorization: NTLM "
+ "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
+
+ // After calling trans.RestartWithAuth(), we should send a Type 3 message
+ // (the credentials for the origin server). The second request continues
+ // on the same connection.
+ MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
+ "Host: 172.22.68.17\r\n"
+ "Connection: keep-alive\r\n"
+ "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
+ "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
+ "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwCWeY"
+ "XnSZNwoQAAAAAAAAAAAAAAAAAAAADLa34/phTTKzNTWdub+uyFleOj"
+ "4Ww7b7E=\r\n\r\n"),
};
MockRead data_reads2[] = {
@@ -5991,26 +5972,26 @@ TEST_P(HttpNetworkTransactionTest, NTLMAuth2) {
};
MockWrite data_writes3[] = {
- // After restarting with a null identity, this is the
- // request we should be issuing -- the final header line contains a Type
- // 1 message.
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: 172.22.68.17\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: NTLM "
- "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
-
- // After calling trans->RestartWithAuth(), we should send a Type 3 message
- // (the credentials for the origin server). The second request continues
- // on the same connection.
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: 172.22.68.17\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
- "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
- "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBO54"
- "dFMVvTHwAAAAAAAAAAAAAAAAAAAACS7sT6Uzw7L0L//WUqlIaVWpbI"
- "+4MUm7c=\r\n\r\n"),
+ // After restarting with a null identity, this is the
+ // request we should be issuing -- the final header line contains a Type
+ // 1 message.
+ MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
+ "Host: 172.22.68.17\r\n"
+ "Connection: keep-alive\r\n"
+ "Authorization: NTLM "
+ "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
+
+ // After calling trans.RestartWithAuth(), we should send a Type 3 message
+ // (the credentials for the origin server). The second request continues
+ // on the same connection.
+ MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
+ "Host: 172.22.68.17\r\n"
+ "Connection: keep-alive\r\n"
+ "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
+ "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
+ "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBO54"
+ "dFMVvTHwAAAAAAAAAAAAAAAAAAAACS7sT6Uzw7L0L//WUqlIaVWpbI"
+ "+4MUm7c=\r\n\r\n"),
};
MockRead data_reads3[] = {
@@ -6048,65 +6029,64 @@ TEST_P(HttpNetworkTransactionTest, NTLMAuth2) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- EXPECT_FALSE(trans->IsReadyToRestartForAuth());
+ EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get()));
TestCompletionCallback callback2;
// Enter the wrong password.
- rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kWrongPassword),
- callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kTestingNTLM, kWrongPassword),
+ callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans->IsReadyToRestartForAuth());
+ EXPECT_TRUE(trans.IsReadyToRestartForAuth());
TestCompletionCallback callback3;
- rv = trans->RestartWithAuth(AuthCredentials(), callback3.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(), callback3.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback3.WaitForResult();
- EXPECT_EQ(OK, rv);
- EXPECT_FALSE(trans->IsReadyToRestartForAuth());
+ EXPECT_THAT(rv, IsOk());
+ EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get()));
TestCompletionCallback callback4;
// Now enter the right password.
- rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kTestingNTLM),
- callback4.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kTestingNTLM, kTestingNTLM),
+ callback4.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback4.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans->IsReadyToRestartForAuth());
+ EXPECT_TRUE(trans.IsReadyToRestartForAuth());
TestCompletionCallback callback5;
// One more roundtrip
- rv = trans->RestartWithAuth(AuthCredentials(), callback5.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(), callback5.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback5.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(13, response->headers->GetContentLength());
}
@@ -6115,15 +6095,14 @@ TEST_P(HttpNetworkTransactionTest, NTLMAuth2) {
// Test reading a server response which has only headers, and no body.
// After some maximum number of bytes is consumed, the transaction should
// fail with ERR_RESPONSE_HEADERS_TOO_BIG.
-TEST_P(HttpNetworkTransactionTest, LargeHeadersNoBody) {
+TEST_F(HttpNetworkTransactionTest, LargeHeadersNoBody) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Respond with 300 kb of headers (we should fail after 256 kb).
std::string large_headers_string;
@@ -6140,18 +6119,17 @@ TEST_P(HttpNetworkTransactionTest, LargeHeadersNoBody) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_RESPONSE_HEADERS_TOO_BIG, rv);
+ EXPECT_THAT(rv, IsError(ERR_RESPONSE_HEADERS_TOO_BIG));
}
// Make sure that we don't try to reuse a TCPClientSocket when failing to
// establish tunnel.
// http://code.google.com/p/chromium/issues/detail?id=3772
-TEST_P(HttpNetworkTransactionTest,
- DontRecycleTransportSocketForSSLTunnel) {
+TEST_F(HttpNetworkTransactionTest, DontRecycleTransportSocketForSSLTunnel) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -6162,7 +6140,7 @@ TEST_P(HttpNetworkTransactionTest,
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
// Since we have proxy, should try to establish tunnel.
@@ -6187,11 +6165,11 @@ TEST_P(HttpNetworkTransactionTest,
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
+ EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
// Empty the current queue. This is necessary because idle sockets are
// added to the connection pool asynchronously with a PostTask.
@@ -6207,7 +6185,7 @@ TEST_P(HttpNetworkTransactionTest,
}
// Make sure that we recycle a socket after reading all of the response body.
-TEST_P(HttpNetworkTransactionTest, RecycleSocket) {
+TEST_F(HttpNetworkTransactionTest, RecycleSocket) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -6215,8 +6193,7 @@ TEST_P(HttpNetworkTransactionTest, RecycleSocket) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockRead data_reads[] = {
// A part of the response body is received with the response headers.
@@ -6233,13 +6210,13 @@ TEST_P(HttpNetworkTransactionTest, RecycleSocket) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers);
@@ -6249,8 +6226,8 @@ TEST_P(HttpNetworkTransactionTest, RecycleSocket) {
EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ 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
@@ -6263,7 +6240,7 @@ TEST_P(HttpNetworkTransactionTest, RecycleSocket) {
// Make sure that we recycle a SSL socket after reading all of the response
// body.
-TEST_P(HttpNetworkTransactionTest, RecycleSSLSocket) {
+TEST_F(HttpNetworkTransactionTest, RecycleSSLSocket) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -6293,15 +6270,14 @@ TEST_P(HttpNetworkTransactionTest, RecycleSSLSocket) {
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
@@ -6309,8 +6285,8 @@ TEST_P(HttpNetworkTransactionTest, RecycleSSLSocket) {
EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ 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
@@ -6323,7 +6299,7 @@ TEST_P(HttpNetworkTransactionTest, RecycleSSLSocket) {
// Grab a SSL socket, use it, and put it back into the pool. Then, reuse it
// from the pool and make sure that we recover okay.
-TEST_P(HttpNetworkTransactionTest, RecycleDeadSSLSocket) {
+TEST_F(HttpNetworkTransactionTest, RecycleDeadSSLSocket) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -6359,13 +6335,13 @@ TEST_P(HttpNetworkTransactionTest, RecycleDeadSSLSocket) {
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -6376,7 +6352,7 @@ TEST_P(HttpNetworkTransactionTest, RecycleDeadSSLSocket) {
std::string response_data;
rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("hello world", response_data);
// Empty the current queue. This is necessary because idle sockets are
@@ -6390,10 +6366,10 @@ TEST_P(HttpNetworkTransactionTest, RecycleDeadSSLSocket) {
trans.reset(new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -6403,7 +6379,134 @@ TEST_P(HttpNetworkTransactionTest, RecycleDeadSSLSocket) {
EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ 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, GetIdleSocketCountInSSLSocketPool(session.get()));
+}
+
+// Grab a 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, FlushSocketPoolOnLowMemoryNotifications) {
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.example.org/");
+ request.load_flags = 0;
+
+ 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 be flushed now.
+ base::MemoryPressureListener::NotifyMemoryPressure(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(0, 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) {
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("https://www.example.org/");
+ request.load_flags = 0;
+
+ MockWrite data_writes[] = {
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.example.org\r\n"
+ "Connection: keep-alive\r\n\r\n"),
+ };
+
+ MockRead data_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"), MockRead("Content-Length: 11\r\n\r\n"),
+ MockRead("hello world"), MockRead(ASYNC, ERR_CONNECTION_CLOSED)};
+
+ SSLSocketDataProvider ssl(ASYNC, OK);
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+
+ StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes,
+ arraysize(data_writes));
+ session_deps_.socket_factory->AddSocketDataProvider(&data);
+
+ TestCompletionCallback callback;
+
+ std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
+
+ EXPECT_EQ(0, GetIdleSocketCountInSSLSocketPool(session.get()));
+ 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("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+
+ // 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();
+
+ EXPECT_EQ(0, GetIdleSocketCountInSSLSocketPool(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
@@ -6412,11 +6515,18 @@ TEST_P(HttpNetworkTransactionTest, RecycleDeadSSLSocket) {
// We now check to make sure the socket was added back to the pool.
EXPECT_EQ(1, GetIdleSocketCountInSSLSocketPool(session.get()));
+
+ // Make memory notification once again and ensure idle socket is closed.
+ base::MemoryPressureListener::NotifyMemoryPressure(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(0, GetIdleSocketCountInSSLSocketPool(session.get()));
}
// Make sure that we recycle a socket after a zero-length response.
// http://crbug.com/9880
-TEST_P(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) {
+TEST_F(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL(
@@ -6441,18 +6551,17 @@ TEST_P(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) {
// Transaction must be created after the MockReads, so it's destroyed before
// them.
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers);
@@ -6462,8 +6571,8 @@ TEST_P(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) {
EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("", response_data);
// Empty the current queue. This is necessary because idle sockets are
@@ -6474,10 +6583,10 @@ TEST_P(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) {
EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
}
-TEST_P(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) {
+TEST_F(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
element_readers.push_back(
- base::WrapUnique(new UploadBytesElementReader("foo", 3)));
+ base::MakeUnique<UploadBytesElementReader>("foo", 3));
ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
HttpRequestInfo request[2];
@@ -6540,26 +6649,25 @@ TEST_P(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) {
};
for (int i = 0; i < 2; ++i) {
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- int rv = trans->Start(&request[i], callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request[i], callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ(kExpectedResponseData[i], response_data);
}
}
@@ -6567,15 +6675,14 @@ TEST_P(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) {
// Test the request-challenge-retry sequence for basic auth when there is
// an identity in the URL. The request should be sent as normal, but when
// it fails the identity from the URL is used to answer the challenge.
-TEST_P(HttpNetworkTransactionTest, AuthIdentityInURL) {
+TEST_F(HttpNetworkTransactionTest, AuthIdentityInURL) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://foo:b@r@www.example.org/");
request.load_flags = LOAD_NORMAL;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// The password contains an escaped character -- for this test to pass it
// will need to be unescaped by HttpNetworkTransaction.
@@ -6619,20 +6726,20 @@ TEST_P(HttpNetworkTransactionTest, AuthIdentityInURL) {
session_deps_.socket_factory->AddSocketDataProvider(&data2);
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
- EXPECT_TRUE(trans->IsReadyToRestartForAuth());
+ EXPECT_THAT(rv, IsOk());
+ EXPECT_TRUE(trans.IsReadyToRestartForAuth());
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(AuthCredentials(), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(), callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
- EXPECT_FALSE(trans->IsReadyToRestartForAuth());
+ EXPECT_THAT(rv, IsOk());
+ EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
// There is no challenge info, since the identity in URL worked.
@@ -6647,7 +6754,7 @@ TEST_P(HttpNetworkTransactionTest, AuthIdentityInURL) {
// Test the request-challenge-retry sequence for basic auth when there is an
// incorrect identity in the URL. The identity from the URL should be used only
// once.
-TEST_P(HttpNetworkTransactionTest, WrongAuthIdentityInURL) {
+TEST_F(HttpNetworkTransactionTest, WrongAuthIdentityInURL) {
HttpRequestInfo request;
request.method = "GET";
// Note: the URL has a username:password in it. The password "baz" is
@@ -6657,8 +6764,7 @@ TEST_P(HttpNetworkTransactionTest, WrongAuthIdentityInURL) {
request.load_flags = LOAD_NORMAL;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes1[] = {
MockWrite(
@@ -6719,33 +6825,32 @@ TEST_P(HttpNetworkTransactionTest, WrongAuthIdentityInURL) {
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans->IsReadyToRestartForAuth());
+ EXPECT_TRUE(trans.IsReadyToRestartForAuth());
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(AuthCredentials(), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(), callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
- EXPECT_FALSE(trans->IsReadyToRestartForAuth());
+ EXPECT_THAT(rv, IsOk());
+ EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get()));
TestCompletionCallback callback3;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo, kBar), callback3.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback3.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback3.WaitForResult();
- EXPECT_EQ(OK, rv);
- EXPECT_FALSE(trans->IsReadyToRestartForAuth());
+ EXPECT_THAT(rv, IsOk());
+ EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
// There is no challenge info, since the identity worked.
@@ -6761,15 +6866,14 @@ TEST_P(HttpNetworkTransactionTest, WrongAuthIdentityInURL) {
// Test the request-challenge-retry sequence for basic auth when there is a
// correct identity in the URL, but its use is being suppressed. The identity
// from the URL should never be used.
-TEST_P(HttpNetworkTransactionTest, AuthIdentityInURLSuppressed) {
+TEST_F(HttpNetworkTransactionTest, AuthIdentityInURLSuppressed) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://foo:bar@www.example.org/");
request.load_flags = LOAD_DO_NOT_USE_EMBEDDED_IDENTITY;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes1[] = {
MockWrite(
@@ -6810,25 +6914,24 @@ TEST_P(HttpNetworkTransactionTest, AuthIdentityInURLSuppressed) {
session_deps_.socket_factory->AddSocketDataProvider(&data3);
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
- EXPECT_FALSE(trans->IsReadyToRestartForAuth());
+ EXPECT_THAT(rv, IsOk());
+ EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get()));
TestCompletionCallback callback3;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo, kBar), callback3.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback3.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback3.WaitForResult();
- EXPECT_EQ(OK, rv);
- EXPECT_FALSE(trans->IsReadyToRestartForAuth());
+ EXPECT_THAT(rv, IsOk());
+ EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
// There is no challenge info, since the identity worked.
@@ -6840,7 +6943,7 @@ TEST_P(HttpNetworkTransactionTest, AuthIdentityInURLSuppressed) {
}
// Test that previously tried username/passwords for a realm get re-used.
-TEST_P(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
+TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
// Transaction 1: authenticate (foo, bar) on MyRealm1
@@ -6850,8 +6953,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
request.url = GURL("http://www.example.org/x/y/z");
request.load_flags = 0;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes1[] = {
MockWrite(
@@ -6892,26 +6994,26 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get()));
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar),
+ callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(100, response->headers->GetContentLength());
@@ -6928,8 +7030,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
request.url = GURL("http://www.example.org/x/y/a/b");
request.load_flags = 0;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes1[] = {
MockWrite(
@@ -6974,13 +7075,13 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->auth_challenge);
EXPECT_FALSE(response->auth_challenge->is_proxy);
@@ -6991,14 +7092,14 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo2, kBar2), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo2, kBar2),
+ callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(100, response->headers->GetContentLength());
@@ -7014,8 +7115,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
request.url = GURL("http://www.example.org/x/y/z2");
request.load_flags = 0;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes1[] = {
MockWrite(
@@ -7040,13 +7140,13 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
@@ -7063,8 +7163,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
request.url = GURL("http://www.example.org/x/1");
request.load_flags = 0;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes1[] = {
MockWrite(
@@ -7105,21 +7204,21 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans->IsReadyToRestartForAuth());
+ EXPECT_TRUE(trans.IsReadyToRestartForAuth());
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(AuthCredentials(), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(), callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
- EXPECT_FALSE(trans->IsReadyToRestartForAuth());
+ EXPECT_THAT(rv, IsOk());
+ EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(100, response->headers->GetContentLength());
@@ -7135,8 +7234,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
request.url = GURL("http://www.example.org/p/q/t");
request.load_flags = 0;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes1[] = {
MockWrite(
@@ -7198,34 +7296,34 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans->IsReadyToRestartForAuth());
+ EXPECT_TRUE(trans.IsReadyToRestartForAuth());
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(AuthCredentials(), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(), callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
- EXPECT_FALSE(trans->IsReadyToRestartForAuth());
+ EXPECT_THAT(rv, IsOk());
+ EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get()));
TestCompletionCallback callback3;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo3, kBar3), callback3.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo3, kBar3),
+ callback3.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback3.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(100, response->headers->GetContentLength());
@@ -7234,7 +7332,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
// Tests that nonce count increments when multiple auth attempts
// are started with the same nonce.
-TEST_P(HttpNetworkTransactionTest, DigestPreAuthNonceCount) {
+TEST_F(HttpNetworkTransactionTest, DigestPreAuthNonceCount) {
HttpAuthHandlerDigest::Factory* digest_factory =
new HttpAuthHandlerDigest::Factory();
HttpAuthHandlerDigest::FixedNonceGenerator* nonce_generator =
@@ -7250,8 +7348,7 @@ TEST_P(HttpNetworkTransactionTest, DigestPreAuthNonceCount) {
request.url = GURL("http://www.example.org/x/y/z");
request.load_flags = 0;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes1[] = {
MockWrite(
@@ -7294,26 +7391,26 @@ TEST_P(HttpNetworkTransactionTest, DigestPreAuthNonceCount) {
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckDigestServerAuth(response->auth_challenge.get()));
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar),
+ callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
}
@@ -7331,8 +7428,7 @@ TEST_P(HttpNetworkTransactionTest, DigestPreAuthNonceCount) {
request.url = GURL("http://www.example.org/x/y/a/b");
request.load_flags = 0;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes1[] = {
MockWrite(
@@ -7358,32 +7454,31 @@ TEST_P(HttpNetworkTransactionTest, DigestPreAuthNonceCount) {
TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
}
}
// Test the ResetStateForRestart() private method.
-TEST_P(HttpNetworkTransactionTest, ResetStateForRestart) {
+TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) {
// Create a transaction (the dependencies aren't important).
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Setup some state (which we expect ResetStateForRestart() will clear).
- trans->read_buf_ = new IOBuffer(15);
- trans->read_buf_len_ = 15;
- trans->request_headers_.SetHeader("Authorization", "NTLM");
+ trans.read_buf_ = new IOBuffer(15);
+ trans.read_buf_len_ = 15;
+ trans.request_headers_.SetHeader("Authorization", "NTLM");
// Setup state in response_
- HttpResponseInfo* response = &trans->response_;
+ HttpResponseInfo* response = &trans.response_;
response->auth_challenge = new AuthChallengeInfo();
response->ssl_info.cert_status = static_cast<CertStatus>(-1); // Nonsensical.
response->response_time = base::Time::Now();
@@ -7400,12 +7495,12 @@ TEST_P(HttpNetworkTransactionTest, ResetStateForRestart) {
}
// Cause the above state to be reset.
- trans->ResetStateForRestart();
+ trans.ResetStateForRestart();
// Verify that the state that needed to be reset, has been reset.
- EXPECT_FALSE(trans->read_buf_);
- EXPECT_EQ(0, trans->read_buf_len_);
- EXPECT_TRUE(trans->request_headers_.IsEmpty());
+ EXPECT_FALSE(trans.read_buf_);
+ EXPECT_EQ(0, trans.read_buf_len_);
+ EXPECT_TRUE(trans.request_headers_.IsEmpty());
EXPECT_FALSE(response->auth_challenge);
EXPECT_FALSE(response->headers);
EXPECT_FALSE(response->was_cached);
@@ -7414,15 +7509,14 @@ TEST_P(HttpNetworkTransactionTest, ResetStateForRestart) {
}
// Test HTTPS connections to a site with a bad certificate
-TEST_P(HttpNetworkTransactionTest, HTTPSBadCertificate) {
+TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificate) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite(
@@ -7451,19 +7545,19 @@ TEST_P(HttpNetworkTransactionTest, HTTPSBadCertificate) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv);
+ EXPECT_THAT(rv, IsError(ERR_CERT_AUTHORITY_INVALID));
- rv = trans->RestartIgnoringLastError(callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartIgnoringLastError(callback.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_EQ(100, response->headers->GetContentLength());
@@ -7471,7 +7565,7 @@ TEST_P(HttpNetworkTransactionTest, HTTPSBadCertificate) {
// Test HTTPS connections to a site with a bad certificate, going through a
// proxy
-TEST_P(HttpNetworkTransactionTest, HTTPSBadCertificateViaProxy) {
+TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaProxy) {
session_deps_.proxy_service = ProxyService::CreateFixed("myproxy:70");
HttpRequestInfo request;
@@ -7526,22 +7620,21 @@ TEST_P(HttpNetworkTransactionTest, HTTPSBadCertificateViaProxy) {
session_deps_.socket_factory->ResetNextMockIndexes();
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv);
+ EXPECT_THAT(rv, IsError(ERR_CERT_AUTHORITY_INVALID));
- rv = trans->RestartIgnoringLastError(callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartIgnoringLastError(callback.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_EQ(100, response->headers->GetContentLength());
@@ -7550,7 +7643,7 @@ TEST_P(HttpNetworkTransactionTest, HTTPSBadCertificateViaProxy) {
// Test HTTPS connections to a site, going through an HTTPS proxy
-TEST_P(HttpNetworkTransactionTest, HTTPSViaHttpsProxy) {
+TEST_F(HttpNetworkTransactionTest, HTTPSViaHttpsProxy) {
session_deps_.proxy_service =
ProxyService::CreateFixedFromPacResult("HTTPS proxy:70");
TestNetLog net_log;
@@ -7590,31 +7683,31 @@ TEST_P(HttpNetworkTransactionTest, HTTPSViaHttpsProxy) {
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ EXPECT_THAT(rv, IsOk());
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
+ EXPECT_TRUE(response->proxy_server.is_https());
EXPECT_TRUE(response->headers->IsKeepAlive());
EXPECT_EQ(200, response->headers->response_code());
EXPECT_EQ(100, response->headers->GetContentLength());
EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReusedWithPac(load_timing_info,
CONNECT_TIMING_HAS_SSL_TIMES);
}
// Test an HTTPS Proxy's ability to redirect a CONNECT request
-TEST_P(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaHttpsProxy) {
+TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaHttpsProxy) {
session_deps_.proxy_service =
ProxyService::CreateFixedFromPacResult("HTTPS proxy:70");
TestNetLog net_log;
@@ -7648,15 +7741,14 @@ TEST_P(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaHttpsProxy) {
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ EXPECT_THAT(rv, IsOk());
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
@@ -7670,10 +7762,10 @@ TEST_P(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaHttpsProxy) {
// and no send / receive times.
// See HttpNetworkTransaction::OnHttpsProxyTunnelResponse.
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
EXPECT_FALSE(load_timing_info.proxy_resolve_start.is_null());
EXPECT_LE(load_timing_info.proxy_resolve_start,
@@ -7690,7 +7782,7 @@ TEST_P(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaHttpsProxy) {
}
// Test an HTTPS (SPDY) Proxy's ability to redirect a CONNECT request
-TEST_P(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaSpdyProxy) {
+TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaSpdyProxy) {
session_deps_.proxy_service = ProxyService::CreateFixed("https://proxy:70");
HttpRequestInfo request;
@@ -7698,30 +7790,29 @@ TEST_P(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaSpdyProxy) {
request.url = GURL("https://www.example.org/");
request.load_flags = 0;
- std::unique_ptr<SpdySerializedFrame> conn(spdy_util_.ConstructSpdyConnect(
+ SpdySerializedFrame conn(spdy_util_.ConstructSpdyConnect(
NULL, 0, 1, LOWEST, HostPortPair("www.example.org", 443)));
- std::unique_ptr<SpdySerializedFrame> goaway(
+ SpdySerializedFrame goaway(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite data_writes[] = {
- CreateMockWrite(*conn.get(), 0, SYNCHRONOUS),
- CreateMockWrite(*goaway.get(), 2, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
+ CreateMockWrite(goaway, 2, SYNCHRONOUS),
};
static const char* const kExtraHeaders[] = {
"location",
"http://login.example.com/",
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdySynReplyError("302 Redirect", kExtraHeaders,
- arraysize(kExtraHeaders) / 2, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyReplyError(
+ "302 Redirect", kExtraHeaders, arraysize(kExtraHeaders) / 2, 1));
MockRead data_reads[] = {
- CreateMockRead(*resp.get(), 1), MockRead(ASYNC, 0, 3), // EOF
+ CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3), // EOF
};
SequencedSocketData data(data_reads, arraysize(data_reads), data_writes,
arraysize(data_writes));
SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy
- proxy_ssl.SetNextProto(GetProtocol());
+ proxy_ssl.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSocketDataProvider(&data);
session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl);
@@ -7729,15 +7820,14 @@ TEST_P(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaSpdyProxy) {
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ EXPECT_THAT(rv, IsOk());
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
@@ -7748,8 +7838,7 @@ TEST_P(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaSpdyProxy) {
}
// Test that an HTTPS proxy's response to a CONNECT request is filtered.
-TEST_P(HttpNetworkTransactionTest,
- ErrorResponseToHttpsConnectViaHttpsProxy) {
+TEST_F(HttpNetworkTransactionTest, ErrorResponseToHttpsConnectViaHttpsProxy) {
session_deps_.proxy_service = ProxyService::CreateFixed("https://proxy:70");
HttpRequestInfo request;
@@ -7780,21 +7869,19 @@ TEST_P(HttpNetworkTransactionTest,
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
+ EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
// TODO(juliatuttle): Anything else to check here?
}
// Test that a SPDY proxy's response to a CONNECT request is filtered.
-TEST_P(HttpNetworkTransactionTest,
- ErrorResponseToHttpsConnectViaSpdyProxy) {
+TEST_F(HttpNetworkTransactionTest, ErrorResponseToHttpsConnectViaSpdyProxy) {
session_deps_.proxy_service = ProxyService::CreateFixed("https://proxy:70");
HttpRequestInfo request;
@@ -7802,33 +7889,31 @@ TEST_P(HttpNetworkTransactionTest,
request.url = GURL("https://www.example.org/");
request.load_flags = 0;
- std::unique_ptr<SpdySerializedFrame> conn(spdy_util_.ConstructSpdyConnect(
+ SpdySerializedFrame conn(spdy_util_.ConstructSpdyConnect(
NULL, 0, 1, LOWEST, HostPortPair("www.example.org", 443)));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite data_writes[] = {
- CreateMockWrite(*conn.get(), 0), CreateMockWrite(*rst.get(), 3),
+ CreateMockWrite(conn, 0), CreateMockWrite(rst, 3),
};
static const char* const kExtraHeaders[] = {
"location",
"http://login.example.com/",
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdySynReplyError("404 Not Found", kExtraHeaders,
- arraysize(kExtraHeaders) / 2, 1));
- std::unique_ptr<SpdySerializedFrame> body(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyReplyError(
+ "404 Not Found", kExtraHeaders, arraysize(kExtraHeaders) / 2, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(
1, "The host does not exist", 23, true));
MockRead data_reads[] = {
- CreateMockRead(*resp.get(), 1),
- CreateMockRead(*body.get(), 2),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
MockRead(ASYNC, 0, 4), // EOF
};
SequencedSocketData data(data_reads, arraysize(data_reads), data_writes,
arraysize(data_writes));
SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy
- proxy_ssl.SetNextProto(GetProtocol());
+ proxy_ssl.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSocketDataProvider(&data);
session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl);
@@ -7836,21 +7921,20 @@ TEST_P(HttpNetworkTransactionTest,
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
+ EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
// TODO(juliatuttle): Anything else to check here?
}
// Test the request-challenge-retry sequence for basic auth, through
// a SPDY proxy over a single SPDY session.
-TEST_P(HttpNetworkTransactionTest, BasicAuthSpdyProxy) {
+TEST_F(HttpNetworkTransactionTest, BasicAuthSpdyProxy) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -7865,18 +7949,18 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthSpdyProxy) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
// Since we have proxy, should try to establish tunnel.
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyConnect(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
NULL, 0, 1, LOWEST, HostPortPair("www.example.org", 443)));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
spdy_util_.UpdateWithStreamDestruction(1);
- // After calling trans->RestartWithAuth(), this is the request we should
+ // After calling trans.RestartWithAuth(), this is the request we should
// be issuing -- the final header line contains the credentials.
const char* const kAuthCredentials[] = {
"proxy-authorization", "Basic Zm9vOmJhcg==",
};
- std::unique_ptr<SpdySerializedFrame> connect2(spdy_util_.ConstructSpdyConnect(
+ SpdySerializedFrame connect2(spdy_util_.ConstructSpdyConnect(
kAuthCredentials, arraysize(kAuthCredentials) / 2, 3, LOWEST,
HostPortPair("www.example.org", 443)));
// fetch https://www.example.org/ via HTTP
@@ -7884,14 +7968,12 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthSpdyProxy) {
"GET / HTTP/1.1\r\n"
"Host: www.example.org\r\n"
"Connection: keep-alive\r\n\r\n";
- std::unique_ptr<SpdySerializedFrame> wrapped_get(
- spdy_util_.ConstructSpdyBodyFrame(3, get, strlen(get), false));
+ SpdySerializedFrame wrapped_get(
+ spdy_util_.ConstructSpdyDataFrame(3, get, strlen(get), false));
MockWrite spdy_writes[] = {
- CreateMockWrite(*req, 0, ASYNC),
- CreateMockWrite(*rst, 2, ASYNC),
- CreateMockWrite(*connect2, 3),
- CreateMockWrite(*wrapped_get, 5),
+ CreateMockWrite(req, 0, ASYNC), CreateMockWrite(rst, 2, ASYNC),
+ CreateMockWrite(connect2, 3), CreateMockWrite(wrapped_get, 5),
};
// The proxy responds to the connect with a 407, using a persistent
@@ -7900,24 +7982,22 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthSpdyProxy) {
const char* const kAuthChallenge[] = {
"proxy-authenticate", "Basic realm=\"MyRealm1\"",
};
- std::unique_ptr<SpdySerializedFrame> conn_auth_resp(
- spdy_util_.ConstructSpdySynReplyError(kAuthStatus, kAuthChallenge,
- arraysize(kAuthChallenge) / 2, 1));
+ SpdySerializedFrame conn_auth_resp(spdy_util_.ConstructSpdyReplyError(
+ kAuthStatus, kAuthChallenge, arraysize(kAuthChallenge) / 2, 1));
- std::unique_ptr<SpdySerializedFrame> conn_resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
+ SpdySerializedFrame conn_resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
const char resp[] = "HTTP/1.1 200 OK\r\n"
"Content-Length: 5\r\n\r\n";
- std::unique_ptr<SpdySerializedFrame> wrapped_get_resp(
- spdy_util_.ConstructSpdyBodyFrame(3, resp, strlen(resp), false));
- std::unique_ptr<SpdySerializedFrame> wrapped_body(
- spdy_util_.ConstructSpdyBodyFrame(3, "hello", 5, false));
+ SpdySerializedFrame wrapped_get_resp(
+ spdy_util_.ConstructSpdyDataFrame(3, resp, strlen(resp), false));
+ SpdySerializedFrame wrapped_body(
+ spdy_util_.ConstructSpdyDataFrame(3, "hello", 5, false));
MockRead spdy_reads[] = {
- CreateMockRead(*conn_auth_resp, 1, ASYNC),
- CreateMockRead(*conn_resp, 4, ASYNC),
- CreateMockRead(*wrapped_get_resp, 6, ASYNC),
- CreateMockRead(*wrapped_body, 7, ASYNC),
+ CreateMockRead(conn_auth_resp, 1, ASYNC),
+ CreateMockRead(conn_resp, 4, ASYNC),
+ CreateMockRead(wrapped_get_resp, 6, ASYNC),
+ CreateMockRead(wrapped_body, 7, ASYNC),
MockRead(ASYNC, OK, 8), // EOF. May or may not be read.
};
@@ -7926,7 +8006,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthSpdyProxy) {
session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
// Negotiate SPDY to the proxy
SSLSocketDataProvider proxy(ASYNC, OK);
- proxy.SetNextProto(GetProtocol());
+ proxy.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy);
// Vanilla SSL to the server
SSLSocketDataProvider server(ASYNC, OK);
@@ -7934,23 +8014,23 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthSpdyProxy) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
TestNetLogEntry::List entries;
log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLog::PHASE_NONE);
+ entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLogEventPhase::NONE);
ExpectLogContainsSomewhere(
entries, pos,
- NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLog::PHASE_NONE);
+ NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLogEventPhase::NONE);
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -7964,10 +8044,10 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthSpdyProxy) {
rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar),
callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -7991,7 +8071,7 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthSpdyProxy) {
// Test that an explicitly trusted SPDY proxy can push a resource from an
// origin that is different from that of its associated resource.
-TEST_P(HttpNetworkTransactionTest, CrossOriginSPDYProxyPush) {
+TEST_F(HttpNetworkTransactionTest, CrossOriginSPDYProxyPush) {
// Configure the proxy delegate to allow cross-origin SPDY pushes.
std::unique_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
proxy_delegate->set_trusted_spdy_proxy(net::ProxyServer::FromURI(
@@ -8014,31 +8094,29 @@ TEST_P(HttpNetworkTransactionTest, CrossOriginSPDYProxyPush) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet("http://www.example.org/", 1, LOWEST));
MockWrite spdy_writes[] = {
- CreateMockWrite(*stream1_syn, 0, ASYNC),
+ CreateMockWrite(stream1_syn, 0, ASYNC),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush(
NULL, 0, 2, 1, "http://www.another-origin.com/foo.dat"));
const char kPushedData[] = "pushed";
- std::unique_ptr<SpdySerializedFrame> stream2_body(
- spdy_util_.ConstructSpdyBodyFrame(2, kPushedData, strlen(kPushedData),
- true));
+ 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(*stream1_body, 3, ASYNC),
- CreateMockRead(*stream2_body, 4, ASYNC),
+ CreateMockRead(stream1_reply, 1, ASYNC),
+ CreateMockRead(stream2_syn, 2, ASYNC),
+ CreateMockRead(stream1_body, 3, ASYNC),
+ CreateMockRead(stream2_body, 4, ASYNC),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a hang
};
@@ -8047,26 +8125,26 @@ TEST_P(HttpNetworkTransactionTest, CrossOriginSPDYProxyPush) {
session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
// Negotiate SPDY to the proxy
SSLSocketDataProvider proxy(ASYNC, OK);
- proxy.SetNextProto(GetProtocol());
+ proxy.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy);
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
TestCompletionCallback callback;
int rv = trans->Start(&request, callback.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
const HttpResponseInfo* response = trans->GetResponseInfo();
- std::unique_ptr<HttpTransaction> push_trans(
+ std::unique_ptr<HttpNetworkTransaction> push_trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
rv = push_trans->Start(&push_request, callback.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
const HttpResponseInfo* push_response = push_trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -8077,7 +8155,7 @@ TEST_P(HttpNetworkTransactionTest, CrossOriginSPDYProxyPush) {
std::string response_data;
rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("hello!", response_data);
LoadTimingInfo load_timing_info;
@@ -8090,7 +8168,7 @@ TEST_P(HttpNetworkTransactionTest, CrossOriginSPDYProxyPush) {
EXPECT_EQ(200, push_response->headers->response_code());
rv = ReadTransaction(push_trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("pushed", response_data);
LoadTimingInfo push_load_timing_info;
@@ -8107,7 +8185,7 @@ TEST_P(HttpNetworkTransactionTest, CrossOriginSPDYProxyPush) {
}
// Test that an explicitly trusted SPDY proxy cannot push HTTPS content.
-TEST_P(HttpNetworkTransactionTest, CrossOriginProxyPushCorrectness) {
+TEST_F(HttpNetworkTransactionTest, CrossOriginProxyPushCorrectness) {
// Configure the proxy delegate to allow cross-origin SPDY pushes.
std::unique_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
proxy_delegate->set_trusted_spdy_proxy(net::ProxyServer::FromURI(
@@ -8127,29 +8205,28 @@ TEST_P(HttpNetworkTransactionTest, CrossOriginProxyPushCorrectness) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet("http://www.example.org/", 1, LOWEST));
- std::unique_ptr<SpdySerializedFrame> push_rst(
+ SpdySerializedFrame push_rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
MockWrite spdy_writes[] = {
- CreateMockWrite(*stream1_syn, 0, ASYNC), CreateMockWrite(*push_rst, 3),
+ CreateMockWrite(stream1_syn, 0, ASYNC), CreateMockWrite(push_rst, 3),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush(
NULL, 0, 2, 1, "https://www.another-origin.com/foo.dat"));
MockRead spdy_reads[] = {
- CreateMockRead(*stream1_reply, 1, ASYNC),
- CreateMockRead(*stream2_syn, 2, ASYNC),
- CreateMockRead(*stream1_body, 4, ASYNC),
+ CreateMockRead(stream1_reply, 1, ASYNC),
+ CreateMockRead(stream2_syn, 2, ASYNC),
+ CreateMockRead(stream1_body, 4, ASYNC),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a hang
};
@@ -8158,17 +8235,17 @@ TEST_P(HttpNetworkTransactionTest, CrossOriginProxyPushCorrectness) {
session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
// Negotiate SPDY to the proxy
SSLSocketDataProvider proxy(ASYNC, OK);
- proxy.SetNextProto(GetProtocol());
+ proxy.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy);
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
TestCompletionCallback callback;
int rv = trans->Start(&request, callback.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -8179,7 +8256,7 @@ TEST_P(HttpNetworkTransactionTest, CrossOriginProxyPushCorrectness) {
std::string response_data;
rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("hello!", response_data);
trans.reset();
@@ -8188,7 +8265,7 @@ TEST_P(HttpNetworkTransactionTest, CrossOriginProxyPushCorrectness) {
// Test that an explicitly trusted SPDY proxy can push same-origin HTTPS
// resources.
-TEST_P(HttpNetworkTransactionTest, SameOriginProxyPushCorrectness) {
+TEST_F(HttpNetworkTransactionTest, SameOriginProxyPushCorrectness) {
// Configure the proxy delegate to allow cross-origin SPDY pushes.
std::unique_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
proxy_delegate->set_trusted_spdy_proxy(
@@ -8209,33 +8286,31 @@ TEST_P(HttpNetworkTransactionTest, SameOriginProxyPushCorrectness) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet("http://www.example.org/", 1, LOWEST));
MockWrite spdy_writes[] = {
- CreateMockWrite(*stream1_syn, 0, ASYNC),
+ CreateMockWrite(stream1_syn, 0, ASYNC),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush(
nullptr, 0, 2, 1, "https://myproxy:70/foo.dat"));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> stream2_reply(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame stream2_reply(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream2_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream2_body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead spdy_reads[] = {
- CreateMockRead(*stream1_reply, 1, ASYNC),
- CreateMockRead(*stream2_syn, 2, ASYNC),
- CreateMockRead(*stream1_body, 3, ASYNC),
- CreateMockRead(*stream2_body, 4, ASYNC),
+ CreateMockRead(stream1_reply, 1, ASYNC),
+ CreateMockRead(stream2_syn, 2, ASYNC),
+ CreateMockRead(stream1_body, 3, ASYNC),
+ CreateMockRead(stream2_body, 4, ASYNC),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a hang
};
@@ -8244,17 +8319,17 @@ TEST_P(HttpNetworkTransactionTest, SameOriginProxyPushCorrectness) {
session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
// Negotiate SPDY to the proxy
SSLSocketDataProvider proxy(ASYNC, OK);
- proxy.SetNextProto(GetProtocol());
+ proxy.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy);
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
TestCompletionCallback callback;
int rv = trans->Start(&request, callback.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -8265,7 +8340,7 @@ TEST_P(HttpNetworkTransactionTest, SameOriginProxyPushCorrectness) {
std::string response_data;
rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("hello!", response_data);
trans.reset();
@@ -8274,7 +8349,7 @@ TEST_P(HttpNetworkTransactionTest, SameOriginProxyPushCorrectness) {
// Test HTTPS connections to a site with a bad certificate, going through an
// HTTPS proxy
-TEST_P(HttpNetworkTransactionTest, HTTPSBadCertificateViaHttpsProxy) {
+TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaHttpsProxy) {
session_deps_.proxy_service = ProxyService::CreateFixed("https://proxy:70");
HttpRequestInfo request;
@@ -8333,28 +8408,27 @@ TEST_P(HttpNetworkTransactionTest, HTTPSBadCertificateViaHttpsProxy) {
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv);
+ EXPECT_THAT(rv, IsError(ERR_CERT_AUTHORITY_INVALID));
- rv = trans->RestartIgnoringLastError(callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartIgnoringLastError(callback.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_EQ(100, response->headers->GetContentLength());
}
-TEST_P(HttpNetworkTransactionTest, BuildRequest_UserAgent) {
+TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgent) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -8362,8 +8436,7 @@ TEST_P(HttpNetworkTransactionTest, BuildRequest_UserAgent) {
"Chromium Ultra Awesome X Edition");
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite(
@@ -8387,14 +8460,14 @@ TEST_P(HttpNetworkTransactionTest, BuildRequest_UserAgent) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
-TEST_P(HttpNetworkTransactionTest, BuildRequest_UserAgentOverTunnel) {
+TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgentOverTunnel) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -8403,8 +8476,7 @@ TEST_P(HttpNetworkTransactionTest, BuildRequest_UserAgentOverTunnel) {
session_deps_.proxy_service = ProxyService::CreateFixed("myproxy:70");
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
@@ -8426,14 +8498,14 @@ TEST_P(HttpNetworkTransactionTest, BuildRequest_UserAgentOverTunnel) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
-TEST_P(HttpNetworkTransactionTest, BuildRequest_Referer) {
+TEST_F(HttpNetworkTransactionTest, BuildRequest_Referer) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -8442,8 +8514,7 @@ TEST_P(HttpNetworkTransactionTest, BuildRequest_Referer) {
"http://the.previous.site.com/");
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite(
@@ -8467,21 +8538,20 @@ TEST_P(HttpNetworkTransactionTest, BuildRequest_Referer) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
-TEST_P(HttpNetworkTransactionTest, BuildRequest_PostContentLengthZero) {
+TEST_F(HttpNetworkTransactionTest, BuildRequest_PostContentLengthZero) {
HttpRequestInfo request;
request.method = "POST";
request.url = GURL("http://www.example.org/");
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite(
@@ -8505,21 +8575,20 @@ TEST_P(HttpNetworkTransactionTest, BuildRequest_PostContentLengthZero) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
-TEST_P(HttpNetworkTransactionTest, BuildRequest_PutContentLengthZero) {
+TEST_F(HttpNetworkTransactionTest, BuildRequest_PutContentLengthZero) {
HttpRequestInfo request;
request.method = "PUT";
request.url = GURL("http://www.example.org/");
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite(
@@ -8543,21 +8612,20 @@ TEST_P(HttpNetworkTransactionTest, BuildRequest_PutContentLengthZero) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
-TEST_P(HttpNetworkTransactionTest, BuildRequest_HeadContentLengthZero) {
+TEST_F(HttpNetworkTransactionTest, BuildRequest_HeadContentLengthZero) {
HttpRequestInfo request;
request.method = "HEAD";
request.url = GURL("http://www.example.org/");
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite("HEAD / HTTP/1.1\r\n"
@@ -8579,22 +8647,21 @@ TEST_P(HttpNetworkTransactionTest, BuildRequest_HeadContentLengthZero) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
-TEST_P(HttpNetworkTransactionTest, BuildRequest_CacheControlNoCache) {
+TEST_F(HttpNetworkTransactionTest, BuildRequest_CacheControlNoCache) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
request.load_flags = LOAD_BYPASS_CACHE;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite(
@@ -8619,23 +8686,21 @@ TEST_P(HttpNetworkTransactionTest, BuildRequest_CacheControlNoCache) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
-TEST_P(HttpNetworkTransactionTest,
- BuildRequest_CacheControlValidateCache) {
+TEST_F(HttpNetworkTransactionTest, BuildRequest_CacheControlValidateCache) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
request.load_flags = LOAD_VALIDATE_CACHE;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite(
@@ -8659,22 +8724,21 @@ TEST_P(HttpNetworkTransactionTest,
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
-TEST_P(HttpNetworkTransactionTest, BuildRequest_ExtraHeaders) {
+TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeaders) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
request.extra_headers.SetHeader("FooHeader", "Bar");
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite(
@@ -8698,14 +8762,14 @@ TEST_P(HttpNetworkTransactionTest, BuildRequest_ExtraHeaders) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
-TEST_P(HttpNetworkTransactionTest, BuildRequest_ExtraHeadersStripped) {
+TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeadersStripped) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -8714,8 +8778,7 @@ TEST_P(HttpNetworkTransactionTest, BuildRequest_ExtraHeadersStripped) {
request.extra_headers.SetHeader("FoO", "bar");
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite(
@@ -8741,14 +8804,14 @@ TEST_P(HttpNetworkTransactionTest, BuildRequest_ExtraHeadersStripped) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
-TEST_P(HttpNetworkTransactionTest, SOCKS4_HTTP_GET) {
+TEST_F(HttpNetworkTransactionTest, SOCKS4_HTTP_GET) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -8760,8 +8823,7 @@ TEST_P(HttpNetworkTransactionTest, SOCKS4_HTTP_GET) {
session_deps_.net_log = &net_log;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
char write_buffer[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 };
char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
@@ -8787,27 +8849,28 @@ TEST_P(HttpNetworkTransactionTest, SOCKS4_HTTP_GET) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
+ EXPECT_EQ(ProxyServer::SCHEME_SOCKS4, response->proxy_server.scheme());
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReusedWithPac(load_timing_info,
CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
std::string response_text;
- rv = ReadTransaction(trans.get(), &response_text);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_text);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("Payload", response_text);
}
-TEST_P(HttpNetworkTransactionTest, SOCKS4_SSL_GET) {
+TEST_F(HttpNetworkTransactionTest, SOCKS4_SSL_GET) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -8819,8 +8882,7 @@ TEST_P(HttpNetworkTransactionTest, SOCKS4_SSL_GET) {
session_deps_.net_log = &net_log;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
unsigned char write_buffer[] = { 0x04, 0x01, 0x01, 0xBB, 127, 0, 0, 1, 0 };
unsigned char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
@@ -8851,27 +8913,28 @@ TEST_P(HttpNetworkTransactionTest, SOCKS4_SSL_GET) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReusedWithPac(load_timing_info,
CONNECT_TIMING_HAS_SSL_TIMES);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
+ EXPECT_EQ(ProxyServer::SCHEME_SOCKS4, response->proxy_server.scheme());
std::string response_text;
- rv = ReadTransaction(trans.get(), &response_text);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_text);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("Payload", response_text);
}
-TEST_P(HttpNetworkTransactionTest, SOCKS4_HTTP_GET_no_PAC) {
+TEST_F(HttpNetworkTransactionTest, SOCKS4_HTTP_GET_no_PAC) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -8883,8 +8946,7 @@ TEST_P(HttpNetworkTransactionTest, SOCKS4_HTTP_GET_no_PAC) {
session_deps_.net_log = &net_log;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
char write_buffer[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 };
char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
@@ -8910,27 +8972,27 @@ TEST_P(HttpNetworkTransactionTest, SOCKS4_HTTP_GET_no_PAC) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReused(load_timing_info,
CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
std::string response_text;
- rv = ReadTransaction(trans.get(), &response_text);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_text);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("Payload", response_text);
}
-TEST_P(HttpNetworkTransactionTest, SOCKS5_HTTP_GET) {
+TEST_F(HttpNetworkTransactionTest, SOCKS5_HTTP_GET) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -8942,8 +9004,7 @@ TEST_P(HttpNetworkTransactionTest, SOCKS5_HTTP_GET) {
session_deps_.net_log = &net_log;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 };
const char kSOCKS5GreetResponse[] = { 0x05, 0x00 };
@@ -8982,27 +9043,28 @@ TEST_P(HttpNetworkTransactionTest, SOCKS5_HTTP_GET) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
+ EXPECT_EQ(ProxyServer::SCHEME_SOCKS5, response->proxy_server.scheme());
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReusedWithPac(load_timing_info,
CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
std::string response_text;
- rv = ReadTransaction(trans.get(), &response_text);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_text);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("Payload", response_text);
}
-TEST_P(HttpNetworkTransactionTest, SOCKS5_SSL_GET) {
+TEST_F(HttpNetworkTransactionTest, SOCKS5_SSL_GET) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -9014,8 +9076,7 @@ TEST_P(HttpNetworkTransactionTest, SOCKS5_SSL_GET) {
session_deps_.net_log = &net_log;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 };
const char kSOCKS5GreetResponse[] = { 0x05, 0x00 };
@@ -9059,23 +9120,24 @@ TEST_P(HttpNetworkTransactionTest, SOCKS5_SSL_GET) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
+ EXPECT_EQ(ProxyServer::SCHEME_SOCKS5, response->proxy_server.scheme());
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReusedWithPac(load_timing_info,
CONNECT_TIMING_HAS_SSL_TIMES);
std::string response_text;
- rv = ReadTransaction(trans.get(), &response_text);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_text);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("Payload", response_text);
}
@@ -9091,14 +9153,13 @@ struct GroupNameTest {
};
std::unique_ptr<HttpNetworkSession> SetupSessionForGroupNameTests(
- NextProto next_proto,
SpdySessionDependencies* session_deps_) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(session_deps_));
HttpServerProperties* http_server_properties =
session->http_server_properties();
AlternativeService alternative_service(
- AlternateProtocolFromNextProto(next_proto), "", 444);
+ AlternateProtocolFromNextProto(kProtoHTTP2), "", 444);
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
http_server_properties->SetAlternativeService(
url::SchemeHostPort("https", "host.with.alternate", 443),
@@ -9114,18 +9175,17 @@ int GroupNameTransactionHelper(const std::string& url,
request.url = GURL(url);
request.load_flags = 0;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session);
TestCompletionCallback callback;
// We do not complete this request, the dtor will clean the transaction up.
- return trans->Start(&request, callback.callback(), BoundNetLog());
+ return trans.Start(&request, callback.callback(), NetLogWithSource());
}
} // namespace
-TEST_P(HttpNetworkTransactionTest, GroupNameForDirectConnections) {
+TEST_F(HttpNetworkTransactionTest, GroupNameForDirectConnections) {
const GroupNameTest tests[] = {
{
"", // unused
@@ -9165,7 +9225,7 @@ TEST_P(HttpNetworkTransactionTest, GroupNameForDirectConnections) {
session_deps_.proxy_service =
ProxyService::CreateFixed(tests[i].proxy_server);
std::unique_ptr<HttpNetworkSession> session(
- SetupSessionForGroupNameTests(GetProtocol(), &session_deps_));
+ SetupSessionForGroupNameTests(&session_deps_));
HttpNetworkSessionPeer peer(session.get());
CaptureGroupNameTransportSocketPool* transport_conn_pool =
@@ -9189,7 +9249,7 @@ TEST_P(HttpNetworkTransactionTest, GroupNameForDirectConnections) {
}
}
-TEST_P(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) {
+TEST_F(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) {
const GroupNameTest tests[] = {
{
"http_proxy",
@@ -9225,7 +9285,7 @@ TEST_P(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) {
session_deps_.proxy_service =
ProxyService::CreateFixed(tests[i].proxy_server);
std::unique_ptr<HttpNetworkSession> session(
- SetupSessionForGroupNameTests(GetProtocol(), &session_deps_));
+ SetupSessionForGroupNameTests(&session_deps_));
HttpNetworkSessionPeer peer(session.get());
@@ -9237,8 +9297,10 @@ TEST_P(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) {
std::unique_ptr<MockClientSocketPoolManager> mock_pool_manager(
new MockClientSocketPoolManager);
- mock_pool_manager->SetSocketPoolForHTTPProxy(proxy_host, http_proxy_pool);
- mock_pool_manager->SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool);
+ mock_pool_manager->SetSocketPoolForHTTPProxy(
+ proxy_host, base::WrapUnique(http_proxy_pool));
+ mock_pool_manager->SetSocketPoolForSSLWithProxy(
+ proxy_host, base::WrapUnique(ssl_conn_pool));
peer.SetClientSocketPoolManager(std::move(mock_pool_manager));
EXPECT_EQ(ERR_IO_PENDING,
@@ -9252,7 +9314,7 @@ TEST_P(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) {
}
}
-TEST_P(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) {
+TEST_F(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) {
const GroupNameTest tests[] = {
{
"socks4://socks_proxy:1080",
@@ -9293,7 +9355,7 @@ TEST_P(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) {
session_deps_.proxy_service =
ProxyService::CreateFixed(tests[i].proxy_server);
std::unique_ptr<HttpNetworkSession> session(
- SetupSessionForGroupNameTests(GetProtocol(), &session_deps_));
+ SetupSessionForGroupNameTests(&session_deps_));
HttpNetworkSessionPeer peer(session.get());
@@ -9305,12 +9367,13 @@ TEST_P(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) {
std::unique_ptr<MockClientSocketPoolManager> mock_pool_manager(
new MockClientSocketPoolManager);
- mock_pool_manager->SetSocketPoolForSOCKSProxy(proxy_host, socks_conn_pool);
- mock_pool_manager->SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool);
+ mock_pool_manager->SetSocketPoolForSOCKSProxy(
+ proxy_host, base::WrapUnique(socks_conn_pool));
+ mock_pool_manager->SetSocketPoolForSSLWithProxy(
+ proxy_host, base::WrapUnique(ssl_conn_pool));
peer.SetClientSocketPoolManager(std::move(mock_pool_manager));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
EXPECT_EQ(ERR_IO_PENDING,
GroupNameTransactionHelper(tests[i].url, session.get()));
@@ -9323,7 +9386,7 @@ TEST_P(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) {
}
}
-TEST_P(HttpNetworkTransactionTest, ReconsiderProxyAfterFailedConnection) {
+TEST_F(HttpNetworkTransactionTest, ReconsiderProxyAfterFailedConnection) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -9336,16 +9399,15 @@ TEST_P(HttpNetworkTransactionTest, ReconsiderProxyAfterFailedConnection) {
session_deps_.host_resolver->rules()->AddSimulatedFailure("*");
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, rv);
+ EXPECT_THAT(rv, IsError(ERR_PROXY_CONNECTION_FAILED));
}
// Base test to make sure that when the load flags for a request specify to
@@ -9353,34 +9415,37 @@ TEST_P(HttpNetworkTransactionTest, ReconsiderProxyAfterFailedConnection) {
void HttpNetworkTransactionTest::BypassHostCacheOnRefreshHelper(
int load_flags) {
// Issue a request, asking to bypass the cache(s).
- HttpRequestInfo request;
- request.method = "GET";
- request.load_flags = load_flags;
- request.url = GURL("http://www.example.org/");
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.load_flags = load_flags;
+ request_info.url = GURL("http://www.example.org/");
// Select a host resolver that does caching.
session_deps_.host_resolver.reset(new MockCachingHostResolver);
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Warm up the host cache so it has an entry for "www.example.org".
AddressList addrlist;
TestCompletionCallback callback;
+ std::unique_ptr<HostResolver::Request> request1;
int rv = session_deps_.host_resolver->Resolve(
HostResolver::RequestInfo(HostPortPair("www.example.org", 80)),
- DEFAULT_PRIORITY, &addrlist, callback.callback(), NULL, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ DEFAULT_PRIORITY, &addrlist, callback.callback(), &request1,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Verify that it was added to host cache, by doing a subsequent async lookup
// and confirming it completes synchronously.
+ std::unique_ptr<HostResolver::Request> request2;
rv = session_deps_.host_resolver->Resolve(
HostResolver::RequestInfo(HostPortPair("www.example.org", 80)),
- DEFAULT_PRIORITY, &addrlist, callback.callback(), NULL, BoundNetLog());
- ASSERT_EQ(OK, rv);
+ DEFAULT_PRIORITY, &addrlist, callback.callback(), &request2,
+ NetLogWithSource());
+ ASSERT_THAT(rv, IsOk());
// Inject a failure the next time that "www.example.org" is resolved. This way
// we can tell if the next lookup hit the cache, or the "network".
@@ -9394,31 +9459,31 @@ void HttpNetworkTransactionTest::BypassHostCacheOnRefreshHelper(
session_deps_.socket_factory->AddSocketDataProvider(&data);
// Run the request.
- rv = trans->Start(&request, callback.callback(), BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.Start(&request_info, callback.callback(), NetLogWithSource());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
// If we bypassed the cache, we would have gotten a failure while resolving
// "www.example.org".
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
+ EXPECT_THAT(rv, IsError(ERR_NAME_NOT_RESOLVED));
}
// There are multiple load flags that should trigger the host cache bypass.
// Test each in isolation:
-TEST_P(HttpNetworkTransactionTest, BypassHostCacheOnRefresh1) {
+TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh1) {
BypassHostCacheOnRefreshHelper(LOAD_BYPASS_CACHE);
}
-TEST_P(HttpNetworkTransactionTest, BypassHostCacheOnRefresh2) {
+TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh2) {
BypassHostCacheOnRefreshHelper(LOAD_VALIDATE_CACHE);
}
-TEST_P(HttpNetworkTransactionTest, BypassHostCacheOnRefresh3) {
+TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh3) {
BypassHostCacheOnRefreshHelper(LOAD_DISABLE_CACHE);
}
// Make sure we can handle an error when writing the request.
-TEST_P(HttpNetworkTransactionTest, RequestWriteError) {
+TEST_F(HttpNetworkTransactionTest, RequestWriteError) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.foo.com/");
@@ -9434,22 +9499,21 @@ TEST_P(HttpNetworkTransactionTest, RequestWriteError) {
TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
IPEndPoint endpoint;
- EXPECT_TRUE(trans->GetRemoteEndpoint(&endpoint));
+ EXPECT_TRUE(trans.GetRemoteEndpoint(&endpoint));
EXPECT_LT(0u, endpoint.address().size());
}
// Check that a connection closed after the start of the headers finishes ok.
-TEST_P(HttpNetworkTransactionTest, ConnectionClosedAfterStartOfHeaders) {
+TEST_F(HttpNetworkTransactionTest, ConnectionClosedAfterStartOfHeaders) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.foo.com/");
@@ -9466,34 +9530,33 @@ TEST_P(HttpNetworkTransactionTest, ConnectionClosedAfterStartOfHeaders) {
TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("", response_data);
IPEndPoint endpoint;
- EXPECT_TRUE(trans->GetRemoteEndpoint(&endpoint));
+ EXPECT_TRUE(trans.GetRemoteEndpoint(&endpoint));
EXPECT_LT(0u, endpoint.address().size());
}
// Make sure that a dropped connection while draining the body for auth
// restart does the right thing.
-TEST_P(HttpNetworkTransactionTest, DrainResetOK) {
+TEST_F(HttpNetworkTransactionTest, DrainResetOK) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -9519,7 +9582,7 @@ TEST_P(HttpNetworkTransactionTest, DrainResetOK) {
data_writes1, arraysize(data_writes1));
session_deps_.socket_factory->AddSocketDataProvider(&data1);
- // After calling trans->RestartWithAuth(), this is the request we should
+ // After calling trans.RestartWithAuth(), this is the request we should
// be issuing -- the final header line contains the credentials.
MockWrite data_writes2[] = {
MockWrite(
@@ -9544,36 +9607,34 @@ TEST_P(HttpNetworkTransactionTest, DrainResetOK) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get()));
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- response = trans->GetResponseInfo();
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(100, response->headers->GetContentLength());
}
// Test HTTPS connections going through a proxy that sends extra data.
-TEST_P(HttpNetworkTransactionTest, HTTPSViaProxyWithExtraData) {
+TEST_F(HttpNetworkTransactionTest, HTTPSViaProxyWithExtraData) {
session_deps_.proxy_service = ProxyService::CreateFixed("myproxy:70");
HttpRequestInfo request;
@@ -9597,25 +9658,23 @@ TEST_P(HttpNetworkTransactionTest, HTTPSViaProxyWithExtraData) {
session_deps_.socket_factory->ResetNextMockIndexes();
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
+ EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
}
-TEST_P(HttpNetworkTransactionTest, LargeContentLengthThenClose) {
+TEST_F(HttpNetworkTransactionTest, LargeContentLengthThenClose) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockRead data_reads[] = {
MockRead("HTTP/1.0 200 OK\r\nContent-Length:6719476739\r\n\r\n"),
@@ -9627,23 +9686,23 @@ TEST_P(HttpNetworkTransactionTest, LargeContentLengthThenClose) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(ERR_CONTENT_LENGTH_MISMATCH, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsError(ERR_CONTENT_LENGTH_MISMATCH));
}
-TEST_P(HttpNetworkTransactionTest, UploadFileSmallerThanLength) {
+TEST_F(HttpNetworkTransactionTest, UploadFileSmallerThanLength) {
base::FilePath temp_file_path;
ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path));
const uint64_t kFakeSize = 100000; // file is actually blank
@@ -9651,9 +9710,9 @@ TEST_P(HttpNetworkTransactionTest, UploadFileSmallerThanLength) {
overriding_content_length(kFakeSize);
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(base::WrapUnique(new UploadFileElementReader(
+ element_readers.push_back(base::MakeUnique<UploadFileElementReader>(
base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
- std::numeric_limits<uint64_t>::max(), base::Time())));
+ std::numeric_limits<uint64_t>::max(), base::Time()));
ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
HttpRequestInfo request;
@@ -9663,8 +9722,7 @@ TEST_P(HttpNetworkTransactionTest, UploadFileSmallerThanLength) {
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockRead data_reads[] = {
MockRead("HTTP/1.0 200 OK\r\n\r\n"),
@@ -9676,13 +9734,13 @@ TEST_P(HttpNetworkTransactionTest, UploadFileSmallerThanLength) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_UPLOAD_FILE_CHANGED, rv);
+ EXPECT_THAT(rv, IsError(ERR_UPLOAD_FILE_CHANGED));
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->headers);
@@ -9690,7 +9748,7 @@ TEST_P(HttpNetworkTransactionTest, UploadFileSmallerThanLength) {
base::DeleteFile(temp_file_path, false);
}
-TEST_P(HttpNetworkTransactionTest, UploadUnreadableFile) {
+TEST_F(HttpNetworkTransactionTest, UploadUnreadableFile) {
base::FilePath temp_file;
ASSERT_TRUE(base::CreateTemporaryFile(&temp_file));
std::string temp_file_content("Unreadable file.");
@@ -9699,9 +9757,9 @@ TEST_P(HttpNetworkTransactionTest, UploadUnreadableFile) {
ASSERT_TRUE(base::MakeFileUnreadable(temp_file));
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(base::WrapUnique(new UploadFileElementReader(
+ element_readers.push_back(base::MakeUnique<UploadFileElementReader>(
base::ThreadTaskRunnerHandle::Get().get(), temp_file, 0,
- std::numeric_limits<uint64_t>::max(), base::Time())));
+ std::numeric_limits<uint64_t>::max(), base::Time()));
ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
HttpRequestInfo request;
@@ -9712,24 +9770,23 @@ TEST_P(HttpNetworkTransactionTest, UploadUnreadableFile) {
// If we try to upload an unreadable file, the transaction should fail.
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
StaticSocketDataProvider data(NULL, 0, NULL, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_ACCESS_DENIED, rv);
+ EXPECT_THAT(rv, IsError(ERR_ACCESS_DENIED));
base::DeleteFile(temp_file, false);
}
-TEST_P(HttpNetworkTransactionTest, CancelDuringInitRequestBody) {
+TEST_F(HttpNetworkTransactionTest, CancelDuringInitRequestBody) {
class FakeUploadElementReader : public UploadElementReader {
public:
FakeUploadElementReader() {}
@@ -9766,15 +9823,15 @@ TEST_P(HttpNetworkTransactionTest, CancelDuringInitRequestBody) {
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
StaticSocketDataProvider data;
session_deps_.socket_factory->AddSocketDataProvider(&data);
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
base::RunLoop().RunUntilIdle();
// Transaction is pending on request body initialization.
@@ -9786,7 +9843,7 @@ TEST_P(HttpNetworkTransactionTest, CancelDuringInitRequestBody) {
}
// Tests that changes to Auth realms are treated like auth rejections.
-TEST_P(HttpNetworkTransactionTest, ChangeAuthRealms) {
+TEST_F(HttpNetworkTransactionTest, ChangeAuthRealms) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -9807,7 +9864,7 @@ TEST_P(HttpNetworkTransactionTest, ChangeAuthRealms) {
"\r\n"),
};
- // After calling trans->RestartWithAuth(), provide an Authentication header
+ // After calling trans.RestartWithAuth(), provide an Authentication header
// for first_realm. The server will reject and provide a challenge with
// second_realm.
MockWrite data_writes2[] = {
@@ -9873,17 +9930,16 @@ TEST_P(HttpNetworkTransactionTest, ChangeAuthRealms) {
TestCompletionCallback callback1;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Issue the first request with Authorize headers. There should be a
// password prompt for first_realm waiting to be filled in after the
// transaction completes.
- int rv = trans->Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ EXPECT_THAT(rv, IsOk());
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
const AuthChallengeInfo* challenge = response->auth_challenge.get();
ASSERT_TRUE(challenge);
@@ -9896,12 +9952,12 @@ TEST_P(HttpNetworkTransactionTest, ChangeAuthRealms) {
// password prompt for second_realm waiting to be filled in after the
// transaction completes.
TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFirst, kBaz), callback2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFirst, kBaz),
+ callback2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback2.WaitForResult();
- EXPECT_EQ(OK, rv);
- response = trans->GetResponseInfo();
+ EXPECT_THAT(rv, IsOk());
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
challenge = response->auth_challenge.get();
ASSERT_TRUE(challenge);
@@ -9915,12 +9971,12 @@ TEST_P(HttpNetworkTransactionTest, ChangeAuthRealms) {
// prompt is not present, it indicates that the HttpAuthCacheEntry for
// first_realm was not correctly removed.
TestCompletionCallback callback3;
- rv = trans->RestartWithAuth(
- AuthCredentials(kSecond, kFou), callback3.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kSecond, kFou),
+ callback3.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback3.WaitForResult();
- EXPECT_EQ(OK, rv);
- response = trans->GetResponseInfo();
+ EXPECT_THAT(rv, IsOk());
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
challenge = response->auth_challenge.get();
ASSERT_TRUE(challenge);
@@ -9931,23 +9987,20 @@ TEST_P(HttpNetworkTransactionTest, ChangeAuthRealms) {
// Issue the fourth request with the correct password and username.
TestCompletionCallback callback4;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFirst, kBar), callback4.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithAuth(AuthCredentials(kFirst, kBar),
+ callback4.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback4.WaitForResult();
- EXPECT_EQ(OK, rv);
- response = trans->GetResponseInfo();
+ EXPECT_THAT(rv, IsOk());
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
}
-TEST_P(HttpNetworkTransactionTest, HonorAlternativeServiceHeader) {
- std::string alternative_service_http_header =
- GetAlternativeServiceHttpHeader();
-
+TEST_F(HttpNetworkTransactionTest, HonorAlternativeServiceHeader) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(alternative_service_http_header.c_str()),
+ MockRead(kAlternativeServiceHttpHeader),
MockRead("\r\n"),
MockRead("hello world"),
MockRead(SYNCHRONOUS, OK),
@@ -9967,11 +10020,10 @@ TEST_P(HttpNetworkTransactionTest, HonorAlternativeServiceHeader) {
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
url::SchemeHostPort test_server(request.url);
HttpServerProperties* http_server_properties =
@@ -9980,37 +10032,34 @@ TEST_P(HttpNetworkTransactionTest, HonorAlternativeServiceHeader) {
http_server_properties->GetAlternativeServices(test_server);
EXPECT_TRUE(alternative_service_vector.empty());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_FALSE(response->was_npn_negotiated);
+ EXPECT_FALSE(response->was_alpn_negotiated);
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
EXPECT_EQ("hello world", response_data);
alternative_service_vector =
http_server_properties->GetAlternativeServices(test_server);
ASSERT_EQ(1u, alternative_service_vector.size());
- EXPECT_EQ(AlternateProtocolFromNextProto(GetProtocol()),
+ EXPECT_EQ(AlternateProtocolFromNextProto(kProtoHTTP2),
alternative_service_vector[0].protocol);
EXPECT_EQ("mail.example.org", alternative_service_vector[0].host);
EXPECT_EQ(443, alternative_service_vector[0].port);
}
// Regression test for https://crbug.com/615497.
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
DoNotParseAlternativeServiceHeaderOnInsecureRequest) {
- std::string alternative_service_http_header =
- GetAlternativeServiceHttpHeader();
-
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(alternative_service_http_header.c_str()),
+ MockRead(kAlternativeServiceHttpHeader),
MockRead("\r\n"),
MockRead("hello world"),
MockRead(SYNCHRONOUS, OK),
@@ -10027,8 +10076,7 @@ TEST_P(HttpNetworkTransactionTest,
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
url::SchemeHostPort test_server(request.url);
HttpServerProperties* http_server_properties =
@@ -10037,19 +10085,19 @@ TEST_P(HttpNetworkTransactionTest,
http_server_properties->GetAlternativeServices(test_server);
EXPECT_TRUE(alternative_service_vector.empty());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_FALSE(response->was_npn_negotiated);
+ EXPECT_FALSE(response->was_alpn_negotiated);
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
EXPECT_EQ("hello world", response_data);
alternative_service_vector =
@@ -10060,7 +10108,7 @@ TEST_P(HttpNetworkTransactionTest,
// HTTP/2 Alternative Services should be disabled if alternative service
// hostname is different from that of origin.
// TODO(bnc): Remove when https://crbug.com/615413 is fixed.
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
DisableHTTP2AlternativeServicesWithDifferentHost) {
session_deps_.enable_http2_alternative_service_with_different_host = false;
@@ -10074,7 +10122,7 @@ TEST_P(HttpNetworkTransactionTest,
first_data.set_connect_data(mock_connect);
session_deps_.socket_factory->AddSocketDataProvider(&first_data);
SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.SetNextProto(kProtoHTTP11);
+ ssl_http11.next_proto = kProtoHTTP11;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
MockRead data_reads[] = {
@@ -10090,24 +10138,23 @@ TEST_P(HttpNetworkTransactionTest,
HttpServerProperties* http_server_properties =
session->http_server_properties();
AlternativeService alternative_service(
- AlternateProtocolFromNextProto(GetProtocol()), "different.example.org",
+ AlternateProtocolFromNextProto(kProtoHTTP2), "different.example.org",
444);
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
http_server_properties->SetAlternativeService(
url::SchemeHostPort(request.url), alternative_service, expiration);
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
// Alternative service is not used, request fails.
- EXPECT_EQ(ERR_CONNECTION_REFUSED, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsError(ERR_CONNECTION_REFUSED));
}
// Regression test for https://crbug.com/615497:
// Alternative Services should be disabled for http origin.
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
DisableAlternativeServicesForInsecureOrigin) {
HttpRequestInfo request;
request.method = "GET";
@@ -10132,21 +10179,20 @@ TEST_P(HttpNetworkTransactionTest,
HttpServerProperties* http_server_properties =
session->http_server_properties();
AlternativeService alternative_service(
- AlternateProtocolFromNextProto(GetProtocol()), "", 444);
+ AlternateProtocolFromNextProto(kProtoHTTP2), "", 444);
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
http_server_properties->SetAlternativeService(
url::SchemeHostPort(request.url), alternative_service, expiration);
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
// Alternative service is not used, request fails.
- EXPECT_EQ(ERR_CONNECTION_REFUSED, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsError(ERR_CONNECTION_REFUSED));
}
-TEST_P(HttpNetworkTransactionTest, ClearAlternativeServices) {
+TEST_F(HttpNetworkTransactionTest, ClearAlternativeServices) {
// Set an alternative service for origin.
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
HttpServerProperties* http_server_properties =
@@ -10181,21 +10227,20 @@ TEST_P(HttpNetworkTransactionTest, ClearAlternativeServices) {
TestCompletionCallback callback;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_FALSE(response->was_npn_negotiated);
+ EXPECT_FALSE(response->was_alpn_negotiated);
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
EXPECT_EQ("hello world", response_data);
alternative_service_vector =
@@ -10203,14 +10248,11 @@ TEST_P(HttpNetworkTransactionTest, ClearAlternativeServices) {
EXPECT_TRUE(alternative_service_vector.empty());
}
-TEST_P(HttpNetworkTransactionTest, HonorMultipleAlternativeServiceHeaders) {
+TEST_F(HttpNetworkTransactionTest, HonorMultipleAlternativeServiceHeaders) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Alt-Svc: "),
- MockRead(GetAlternateProtocolFromParam()),
- MockRead("=\"www.example.com:443\","),
- MockRead(GetAlternateProtocolFromParam()),
- MockRead("=\":1234\"\r\n\r\n"),
+ MockRead("Alt-Svc: h2=\"www.example.com:443\","),
+ MockRead("h2=\":1234\"\r\n\r\n"),
MockRead("hello world"),
MockRead(SYNCHRONOUS, OK),
};
@@ -10229,11 +10271,10 @@ TEST_P(HttpNetworkTransactionTest, HonorMultipleAlternativeServiceHeaders) {
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
url::SchemeHostPort test_server("https", "www.example.org", 443);
HttpServerProperties* http_server_properties =
@@ -10242,33 +10283,33 @@ TEST_P(HttpNetworkTransactionTest, HonorMultipleAlternativeServiceHeaders) {
http_server_properties->GetAlternativeServices(test_server);
EXPECT_TRUE(alternative_service_vector.empty());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_FALSE(response->was_npn_negotiated);
+ EXPECT_FALSE(response->was_alpn_negotiated);
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
EXPECT_EQ("hello world", response_data);
alternative_service_vector =
http_server_properties->GetAlternativeServices(test_server);
ASSERT_EQ(2u, alternative_service_vector.size());
- EXPECT_EQ(AlternateProtocolFromNextProto(GetProtocol()),
+ EXPECT_EQ(AlternateProtocolFromNextProto(kProtoHTTP2),
alternative_service_vector[0].protocol);
EXPECT_EQ("www.example.com", alternative_service_vector[0].host);
EXPECT_EQ(443, alternative_service_vector[0].port);
- EXPECT_EQ(AlternateProtocolFromNextProto(GetProtocol()),
+ EXPECT_EQ(AlternateProtocolFromNextProto(kProtoHTTP2),
alternative_service_vector[1].protocol);
EXPECT_EQ("www.example.org", alternative_service_vector[1].host);
EXPECT_EQ(1234, alternative_service_vector[1].port);
}
-TEST_P(HttpNetworkTransactionTest, IdentifyQuicBroken) {
+TEST_F(HttpNetworkTransactionTest, IdentifyQuicBroken) {
url::SchemeHostPort server("https", "origin.example.org", 443);
HostPortPair alternative("alternative.example.org", 443);
std::string origin_url = "https://origin.example.org:443";
@@ -10276,7 +10317,7 @@ TEST_P(HttpNetworkTransactionTest, IdentifyQuicBroken) {
// Negotiate HTTP/1.1 with alternative.example.org.
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(kProtoHTTP11);
+ ssl.next_proto = kProtoHTTP11;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
// HTTP/1.1 data for request.
@@ -10311,8 +10352,7 @@ TEST_P(HttpNetworkTransactionTest, IdentifyQuicBroken) {
// Mark the QUIC alternative service as broken.
http_server_properties->MarkAlternativeServiceBroken(alternative_service);
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
HttpRequestInfo request;
request.method = "GET";
request.url = GURL(origin_url);
@@ -10321,12 +10361,12 @@ TEST_P(HttpNetworkTransactionTest, IdentifyQuicBroken) {
NetErrorDetails details;
EXPECT_FALSE(details.quic_broken);
- trans->Start(&request, callback.callback(), BoundNetLog());
- trans->PopulateNetErrorDetails(&details);
+ trans.Start(&request, callback.callback(), NetLogWithSource());
+ trans.PopulateNetErrorDetails(&details);
EXPECT_TRUE(details.quic_broken);
}
-TEST_P(HttpNetworkTransactionTest, IdentifyQuicNotBroken) {
+TEST_F(HttpNetworkTransactionTest, IdentifyQuicNotBroken) {
url::SchemeHostPort server("https", "origin.example.org", 443);
HostPortPair alternative1("alternative1.example.org", 443);
HostPortPair alternative2("alternative2.example.org", 443);
@@ -10336,7 +10376,7 @@ TEST_P(HttpNetworkTransactionTest, IdentifyQuicNotBroken) {
// Negotiate HTTP/1.1 with alternative1.example.org.
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(kProtoHTTP11);
+ ssl.next_proto = kProtoHTTP11;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
// HTTP/1.1 data for request.
@@ -10386,8 +10426,7 @@ TEST_P(HttpNetworkTransactionTest, IdentifyQuicNotBroken) {
const AlternativeServiceVector alternative_service_vector =
http_server_properties->GetAlternativeServices(server);
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
HttpRequestInfo request;
request.method = "GET";
request.url = GURL(origin_url);
@@ -10396,13 +10435,12 @@ TEST_P(HttpNetworkTransactionTest, IdentifyQuicNotBroken) {
NetErrorDetails details;
EXPECT_FALSE(details.quic_broken);
- trans->Start(&request, callback.callback(), BoundNetLog());
- trans->PopulateNetErrorDetails(&details);
+ trans.Start(&request, callback.callback(), NetLogWithSource());
+ trans.PopulateNetErrorDetails(&details);
EXPECT_FALSE(details.quic_broken);
}
-TEST_P(HttpNetworkTransactionTest,
- MarkBrokenAlternateProtocolAndFallback) {
+TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocolAndFallback) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -10413,7 +10451,7 @@ TEST_P(HttpNetworkTransactionTest,
first_data.set_connect_data(mock_connect);
session_deps_.socket_factory->AddSocketDataProvider(&first_data);
SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.SetNextProto(kProtoHTTP11);
+ ssl_http11.next_proto = kProtoHTTP11;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
MockRead data_reads[] = {
@@ -10433,27 +10471,26 @@ TEST_P(HttpNetworkTransactionTest,
// Port must be < 1024, or the header will be ignored (since initial port was
// port 80 (another restricted port).
const AlternativeService alternative_service(
- AlternateProtocolFromNextProto(GetProtocol()), "www.example.org",
+ AlternateProtocolFromNextProto(kProtoHTTP2), "www.example.org",
666); // Port is ignored by MockConnect anyway.
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
http_server_properties->SetAlternativeService(server, alternative_service,
expiration);
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
EXPECT_EQ("hello world", response_data);
const AlternativeServiceVector alternative_service_vector =
@@ -10468,8 +10505,7 @@ TEST_P(HttpNetworkTransactionTest,
// to an unrestricted (port >= 1024) when the original traffic was on a
// restricted port (port < 1024). Ensure that we can redirect in all other
// cases.
-TEST_P(HttpNetworkTransactionTest,
- AlternateProtocolPortRestrictedBlocked) {
+TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortRestrictedBlocked) {
HttpRequestInfo restricted_port_request;
restricted_port_request.method = "GET";
restricted_port_request.url = GURL("https://www.example.org:1023/");
@@ -10489,7 +10525,7 @@ TEST_P(HttpNetworkTransactionTest,
data_reads, arraysize(data_reads), NULL, 0);
session_deps_.socket_factory->AddSocketDataProvider(&second_data);
SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.SetNextProto(kProtoHTTP11);
+ ssl_http11.next_proto = kProtoHTTP11;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
@@ -10498,30 +10534,27 @@ TEST_P(HttpNetworkTransactionTest,
session->http_server_properties();
const int kUnrestrictedAlternatePort = 1024;
AlternativeService alternative_service(
- AlternateProtocolFromNextProto(GetProtocol()), "www.example.org",
+ AlternateProtocolFromNextProto(kProtoHTTP2), "www.example.org",
kUnrestrictedAlternatePort);
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
http_server_properties->SetAlternativeService(
url::SchemeHostPort(restricted_port_request.url), alternative_service,
expiration);
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- int rv = trans->Start(
- &restricted_port_request,
- callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&restricted_port_request, callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Invalid change to unrestricted port should fail.
- EXPECT_EQ(ERR_CONNECTION_REFUSED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_REFUSED));
}
// Ensure that we are allowed to redirect traffic via an alternate protocol to
// an unrestricted (port >= 1024) when the original traffic was on a restricted
// port (port < 1024) if we set |enable_user_alternate_protocol_ports|.
-TEST_P(HttpNetworkTransactionTest,
- AlternateProtocolPortRestrictedPermitted) {
+TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortRestrictedPermitted) {
session_deps_.enable_user_alternate_protocol_ports = true;
HttpRequestInfo restricted_port_request;
@@ -10543,7 +10576,7 @@ TEST_P(HttpNetworkTransactionTest,
data_reads, arraysize(data_reads), NULL, 0);
session_deps_.socket_factory->AddSocketDataProvider(&second_data);
SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.SetNextProto(kProtoHTTP11);
+ ssl_http11.next_proto = kProtoHTTP11;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
@@ -10552,30 +10585,28 @@ TEST_P(HttpNetworkTransactionTest,
session->http_server_properties();
const int kUnrestrictedAlternatePort = 1024;
AlternativeService alternative_service(
- AlternateProtocolFromNextProto(GetProtocol()), "www.example.org",
+ AlternateProtocolFromNextProto(kProtoHTTP2), "www.example.org",
kUnrestrictedAlternatePort);
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
http_server_properties->SetAlternativeService(
url::SchemeHostPort(restricted_port_request.url), alternative_service,
expiration);
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, trans->Start(
- &restricted_port_request,
- callback.callback(), BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ trans.Start(&restricted_port_request, callback.callback(),
+ NetLogWithSource()));
// Change to unrestricted port should succeed.
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
}
// Ensure that we are not allowed to redirect traffic via an alternate protocol
// to an unrestricted (port >= 1024) when the original traffic was on a
// restricted port (port < 1024). Ensure that we can redirect in all other
// cases.
-TEST_P(HttpNetworkTransactionTest,
- AlternateProtocolPortRestrictedAllowed) {
+TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortRestrictedAllowed) {
HttpRequestInfo restricted_port_request;
restricted_port_request.method = "GET";
restricted_port_request.url = GURL("https://www.example.org:1023/");
@@ -10604,31 +10635,28 @@ TEST_P(HttpNetworkTransactionTest,
session->http_server_properties();
const int kRestrictedAlternatePort = 80;
AlternativeService alternative_service(
- AlternateProtocolFromNextProto(GetProtocol()), "www.example.org",
+ AlternateProtocolFromNextProto(kProtoHTTP2), "www.example.org",
kRestrictedAlternatePort);
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
http_server_properties->SetAlternativeService(
url::SchemeHostPort(restricted_port_request.url), alternative_service,
expiration);
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- int rv = trans->Start(
- &restricted_port_request,
- callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&restricted_port_request, callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Valid change to restricted port should pass.
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
}
// Ensure that we are not allowed to redirect traffic via an alternate protocol
// to an unrestricted (port >= 1024) when the original traffic was on a
// restricted port (port < 1024). Ensure that we can redirect in all other
// cases.
-TEST_P(HttpNetworkTransactionTest,
- AlternateProtocolPortUnrestrictedAllowed1) {
+TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortUnrestrictedAllowed1) {
HttpRequestInfo unrestricted_port_request;
unrestricted_port_request.method = "GET";
unrestricted_port_request.url = GURL("https://www.example.org:1024/");
@@ -10648,7 +10676,7 @@ TEST_P(HttpNetworkTransactionTest,
data_reads, arraysize(data_reads), NULL, 0);
session_deps_.socket_factory->AddSocketDataProvider(&second_data);
SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.SetNextProto(kProtoHTTP11);
+ ssl_http11.next_proto = kProtoHTTP11;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
@@ -10657,30 +10685,28 @@ TEST_P(HttpNetworkTransactionTest,
session->http_server_properties();
const int kRestrictedAlternatePort = 80;
AlternativeService alternative_service(
- AlternateProtocolFromNextProto(GetProtocol()), "www.example.org",
+ AlternateProtocolFromNextProto(kProtoHTTP2), "www.example.org",
kRestrictedAlternatePort);
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
http_server_properties->SetAlternativeService(
url::SchemeHostPort(unrestricted_port_request.url), alternative_service,
expiration);
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- int rv = trans->Start(
- &unrestricted_port_request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&unrestricted_port_request, callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Valid change to restricted port should pass.
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
}
// Ensure that we are not allowed to redirect traffic via an alternate protocol
// to an unrestricted (port >= 1024) when the original traffic was on a
// restricted port (port < 1024). Ensure that we can redirect in all other
// cases.
-TEST_P(HttpNetworkTransactionTest,
- AlternateProtocolPortUnrestrictedAllowed2) {
+TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortUnrestrictedAllowed2) {
HttpRequestInfo unrestricted_port_request;
unrestricted_port_request.method = "GET";
unrestricted_port_request.url = GURL("https://www.example.org:1024/");
@@ -10709,28 +10735,27 @@ TEST_P(HttpNetworkTransactionTest,
session->http_server_properties();
const int kUnrestrictedAlternatePort = 1025;
AlternativeService alternative_service(
- AlternateProtocolFromNextProto(GetProtocol()), "www.example.org",
+ AlternateProtocolFromNextProto(kProtoHTTP2), "www.example.org",
kUnrestrictedAlternatePort);
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
http_server_properties->SetAlternativeService(
url::SchemeHostPort(unrestricted_port_request.url), alternative_service,
expiration);
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- int rv = trans->Start(
- &unrestricted_port_request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&unrestricted_port_request, callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Valid change to an unrestricted port should pass.
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
}
// Ensure that we are not allowed to redirect traffic via an alternate protocol
// to an unsafe port, and that we resume the second HttpStreamFactoryImpl::Job
// once the alternate protocol request fails.
-TEST_P(HttpNetworkTransactionTest, AlternateProtocolUnsafeBlocked) {
+TEST_F(HttpNetworkTransactionTest, AlternateProtocolUnsafeBlocked) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -10753,43 +10778,39 @@ TEST_P(HttpNetworkTransactionTest, AlternateProtocolUnsafeBlocked) {
session->http_server_properties();
const int kUnsafePort = 7;
AlternativeService alternative_service(
- AlternateProtocolFromNextProto(GetProtocol()), "www.example.org",
+ AlternateProtocolFromNextProto(kProtoHTTP2), "www.example.org",
kUnsafePort);
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
http_server_properties->SetAlternativeService(
url::SchemeHostPort(request.url), alternative_service, expiration);
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// The HTTP request should succeed.
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
EXPECT_EQ("hello world", response_data);
}
-TEST_P(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
+TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
request.load_flags = 0;
- std::string alternative_service_http_header =
- GetAlternativeServiceHttpHeader();
-
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(alternative_service_http_header.c_str()),
+ MockRead(kAlternativeServiceHttpHeader),
MockRead("\r\n"),
MockRead("hello world"),
MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
@@ -10799,26 +10820,19 @@ TEST_P(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
data_reads, arraysize(data_reads), NULL, 0);
session_deps_.socket_factory->AddSocketDataProvider(&first_transaction);
SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.SetNextProto(kProtoHTTP11);
+ ssl_http11.next_proto = kProtoHTTP11;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
- SSLSocketDataProvider ssl_http2(ASYNC, OK);
- ssl_http2.SetNextProto(GetProtocol());
- ssl_http2.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
- ASSERT_TRUE(ssl_http2.cert.get());
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http2);
+ AddSSLSocketData();
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet("https://www.example.org/", 1, LOWEST));
- MockWrite spdy_writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite spdy_writes[] = {CreateMockWrite(req, 0)};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> data(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead spdy_reads[] = {
- CreateMockRead(*resp, 1), CreateMockRead(*data, 2), MockRead(ASYNC, 0, 3),
+ CreateMockRead(resp, 1), CreateMockRead(data, 2), MockRead(ASYNC, 0, 3),
};
SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
@@ -10836,12 +10850,12 @@ TEST_P(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -10849,39 +10863,36 @@ TEST_P(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
EXPECT_EQ("hello world", response_data);
trans.reset(new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
response = trans->GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
+ EXPECT_TRUE(response->was_alpn_negotiated);
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
}
-TEST_P(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) {
+TEST_F(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
request.load_flags = 0;
// First transaction receives Alt-Svc header over HTTP/1.1.
- std::string alternative_service_http_header =
- GetAlternativeServiceHttpHeader();
-
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(alternative_service_http_header.c_str()),
+ MockRead(kAlternativeServiceHttpHeader),
MockRead("\r\n"),
MockRead("hello world"),
MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
@@ -10909,26 +10920,20 @@ TEST_P(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) {
// Third transaction starts an alternative and a non-alternative job.
// The non-alternative job hangs, but the alternative one succeeds.
// The second transaction, still pending, binds to this socket.
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet("https://www.example.org/", 1, LOWEST));
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet("https://www.example.org/", 3, LOWEST));
MockWrite spdy_writes[] = {
- CreateMockWrite(*req1, 0), CreateMockWrite(*req2, 1),
- };
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> data1(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> data2(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
+ CreateMockWrite(req1, 0), CreateMockWrite(req2, 1),
+ };
+ SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame data1(spdy_util_.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame data2(spdy_util_.ConstructSpdyDataFrame(3, true));
MockRead spdy_reads[] = {
- CreateMockRead(*resp1, 2),
- CreateMockRead(*data1, 3),
- CreateMockRead(*resp2, 4),
- CreateMockRead(*data2, 5),
+ CreateMockRead(resp1, 2), CreateMockRead(data1, 3),
+ CreateMockRead(resp2, 4), CreateMockRead(data2, 5),
MockRead(ASYNC, 0, 6),
};
@@ -10936,12 +10941,7 @@ TEST_P(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) {
arraysize(spdy_writes));
session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- SSLSocketDataProvider ssl_http2(ASYNC, OK);
- ssl_http2.SetNextProto(GetProtocol());
- ssl_http2.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
- ASSERT_TRUE(ssl_http2.cert);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http2);
+ AddSSLSocketData();
StaticSocketDataProvider hanging_socket3(NULL, 0, NULL, 0);
hanging_socket3.set_connect_data(never_finishing_connect);
@@ -10951,9 +10951,9 @@ TEST_P(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) {
TestCompletionCallback callback1;
HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get());
- int rv = trans1.Start(&request, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback1.WaitForResult());
+ int rv = trans1.Start(&request, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
const HttpResponseInfo* response = trans1.GetResponseInfo();
ASSERT_TRUE(response);
@@ -10961,29 +10961,29 @@ TEST_P(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) {
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data));
+ ASSERT_THAT(ReadTransaction(&trans1, &response_data), IsOk());
EXPECT_EQ("hello world", response_data);
TestCompletionCallback callback2;
HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
- rv = trans2.Start(&request, callback2.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans2.Start(&request, callback2.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestCompletionCallback callback3;
HttpNetworkTransaction trans3(DEFAULT_PRIORITY, session.get());
- rv = trans3.Start(&request, callback3.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans3.Start(&request, callback3.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_EQ(OK, callback2.WaitForResult());
- EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
+ EXPECT_THAT(callback3.WaitForResult(), IsOk());
response = trans2.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
- ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data));
+ EXPECT_TRUE(response->was_alpn_negotiated);
+ ASSERT_THAT(ReadTransaction(&trans2, &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
response = trans3.GetResponseInfo();
@@ -10991,23 +10991,20 @@ TEST_P(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) {
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
- ASSERT_EQ(OK, ReadTransaction(&trans3, &response_data));
+ EXPECT_TRUE(response->was_alpn_negotiated);
+ ASSERT_THAT(ReadTransaction(&trans3, &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
}
-TEST_P(HttpNetworkTransactionTest, StallAlternativeServiceForNpnSpdy) {
+TEST_F(HttpNetworkTransactionTest, StallAlternativeServiceForNpnSpdy) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
request.load_flags = 0;
- std::string alternative_service_http_header =
- GetAlternativeServiceHttpHeader();
-
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(alternative_service_http_header.c_str()),
+ MockRead(kAlternativeServiceHttpHeader),
MockRead("\r\n"),
MockRead("hello world"),
MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
@@ -11038,12 +11035,12 @@ TEST_P(HttpNetworkTransactionTest, StallAlternativeServiceForNpnSpdy) {
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -11051,23 +11048,23 @@ TEST_P(HttpNetworkTransactionTest, StallAlternativeServiceForNpnSpdy) {
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
EXPECT_EQ("hello world", response_data);
trans.reset(new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
response = trans->GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_FALSE(response->was_npn_negotiated);
+ EXPECT_FALSE(response->was_alpn_negotiated);
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
EXPECT_EQ("hello world", response_data);
}
@@ -11080,7 +11077,7 @@ class CapturingProxyResolver : public ProxyResolver {
ProxyInfo* results,
const CompletionCallback& callback,
RequestHandle* request,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
ProxyServer proxy_server(ProxyServer::SCHEME_HTTP,
HostPortPair("myproxy", 80));
results->UseProxyServer(proxy_server);
@@ -11121,17 +11118,104 @@ class CapturingProxyResolverFactory : public ProxyResolverFactory {
ProxyResolver* resolver_;
};
-TEST_P(HttpNetworkTransactionTest, UseAlternativeServiceForTunneledNpnSpdy) {
+// Test that proxy is resolved using the origin url,
+// regardless of the alternative server.
+TEST_F(HttpNetworkTransactionTest, UseOriginNotAlternativeForProxy) {
+ // Configure proxy to bypass www.example.org, which is the origin URL.
+ ProxyConfig proxy_config;
+ proxy_config.proxy_rules().ParseFromString("myproxy:70");
+ proxy_config.proxy_rules().bypass_rules.AddRuleFromString("www.example.org");
+ auto proxy_config_service =
+ base::MakeUnique<ProxyConfigServiceFixed>(proxy_config);
+
+ CapturingProxyResolver capturing_proxy_resolver;
+ auto proxy_resolver_factory = base::MakeUnique<CapturingProxyResolverFactory>(
+ &capturing_proxy_resolver);
+
+ TestNetLog net_log;
+
+ session_deps_.proxy_service = base::MakeUnique<ProxyService>(
+ std::move(proxy_config_service), std::move(proxy_resolver_factory),
+ &net_log);
+
+ session_deps_.net_log = &net_log;
+
+ // Configure alternative service with a hostname that is not bypassed by the
+ // proxy.
+ std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+ HttpServerProperties* http_server_properties =
+ session->http_server_properties();
+ url::SchemeHostPort server("https", "www.example.org", 443);
+ HostPortPair alternative("www.example.com", 443);
+ AlternativeService alternative_service(
+ AlternateProtocolFromNextProto(kProtoHTTP2), alternative);
+ base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
+ http_server_properties->SetAlternativeService(server, alternative_service,
+ expiration);
+
+ // Non-alternative job should hang.
+ MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
+ StaticSocketDataProvider hanging_alternate_protocol_socket(nullptr, 0,
+ nullptr, 0);
+ hanging_alternate_protocol_socket.set_connect_data(never_finishing_connect);
+ session_deps_.socket_factory->AddSocketDataProvider(
+ &hanging_alternate_protocol_socket);
+
+ AddSSLSocketData();
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("https://www.example.org/");
+ request.load_flags = 0;
+
+ SpdySerializedFrame req(
+ spdy_util_.ConstructSpdyGet("https://www.example.org/", 1, LOWEST));
+
+ MockWrite spdy_writes[] = {CreateMockWrite(req, 0)};
+
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
+ MockRead spdy_reads[] = {
+ CreateMockRead(resp, 1), CreateMockRead(data, 2), MockRead(ASYNC, 0, 3),
+ };
+
+ SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
+ arraysize(spdy_writes));
+ session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
+
+ TestCompletionCallback callback;
+
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
+
+ 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("HTTP/1.1 200", response->headers->GetStatusLine());
+ EXPECT_TRUE(response->was_fetched_via_spdy);
+ EXPECT_TRUE(response->was_alpn_negotiated);
+
+ std::string response_data;
+ ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
+ EXPECT_EQ("hello!", response_data);
+
+ // Origin host bypasses proxy, no resolution should have happened.
+ ASSERT_TRUE(capturing_proxy_resolver.resolved().empty());
+}
+
+TEST_F(HttpNetworkTransactionTest, UseAlternativeServiceForTunneledNpnSpdy) {
ProxyConfig proxy_config;
proxy_config.set_auto_detect(true);
proxy_config.set_pac_url(GURL("http://fooproxyurl"));
CapturingProxyResolver capturing_proxy_resolver;
- session_deps_.proxy_service.reset(new ProxyService(
- base::WrapUnique(new ProxyConfigServiceFixed(proxy_config)),
- base::WrapUnique(
- new CapturingProxyResolverFactory(&capturing_proxy_resolver)),
- NULL));
+ session_deps_.proxy_service.reset(
+ new ProxyService(base::MakeUnique<ProxyConfigServiceFixed>(proxy_config),
+ base::MakeUnique<CapturingProxyResolverFactory>(
+ &capturing_proxy_resolver),
+ NULL));
TestNetLog net_log;
session_deps_.net_log = &net_log;
@@ -11140,12 +11224,9 @@ TEST_P(HttpNetworkTransactionTest, UseAlternativeServiceForTunneledNpnSpdy) {
request.url = GURL("https://www.example.org/");
request.load_flags = 0;
- std::string alternative_service_http_header =
- GetAlternativeServiceHttpHeader();
-
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(alternative_service_http_header.c_str()),
+ MockRead(kAlternativeServiceHttpHeader),
MockRead("\r\n"),
MockRead("hello world"),
MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
@@ -11156,35 +11237,28 @@ TEST_P(HttpNetworkTransactionTest, UseAlternativeServiceForTunneledNpnSpdy) {
data_reads, arraysize(data_reads), NULL, 0);
session_deps_.socket_factory->AddSocketDataProvider(&first_transaction);
SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.SetNextProto(kProtoHTTP11);
+ ssl_http11.next_proto = kProtoHTTP11;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
- SSLSocketDataProvider ssl_http2(ASYNC, OK);
- ssl_http2.SetNextProto(GetProtocol());
- ssl_http2.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
- ASSERT_TRUE(ssl_http2.cert);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http2);
+ AddSSLSocketData();
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet("https://www.example.org/", 1, LOWEST));
MockWrite spdy_writes[] = {
MockWrite(ASYNC, 0,
"CONNECT www.example.org:443 HTTP/1.1\r\n"
"Host: www.example.org:443\r\n"
"Proxy-Connection: keep-alive\r\n\r\n"),
- CreateMockWrite(*req, 2),
+ CreateMockWrite(req, 2),
};
const char kCONNECTResponse[] = "HTTP/1.1 200 Connected\r\n\r\n";
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> data(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead spdy_reads[] = {
- MockRead(ASYNC, 1, kCONNECTResponse), CreateMockRead(*resp.get(), 3),
- CreateMockRead(*data.get(), 4), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),
+ MockRead(ASYNC, 1, kCONNECTResponse), CreateMockRead(resp, 3),
+ CreateMockRead(data, 4), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),
};
SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
@@ -11202,38 +11276,38 @@ TEST_P(HttpNetworkTransactionTest, UseAlternativeServiceForTunneledNpnSpdy) {
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/0.9 200 OK", response->headers->GetStatusLine());
EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
+ EXPECT_TRUE(response->was_alpn_negotiated);
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
EXPECT_EQ("hello world", response_data);
trans.reset(new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
response = trans->GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
+ EXPECT_TRUE(response->was_alpn_negotiated);
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
ASSERT_EQ(2u, capturing_proxy_resolver.resolved().size());
EXPECT_EQ("https://www.example.org/",
@@ -11247,19 +11321,16 @@ TEST_P(HttpNetworkTransactionTest, UseAlternativeServiceForTunneledNpnSpdy) {
CONNECT_TIMING_HAS_SSL_TIMES);
}
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
UseAlternativeServiceForNpnSpdyWithExistingSpdySession) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
request.load_flags = 0;
- std::string alternative_service_http_header =
- GetAlternativeServiceHttpHeader();
-
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(alternative_service_http_header.c_str()),
+ MockRead(kAlternativeServiceHttpHeader),
MockRead("\r\n"),
MockRead("hello world"),
MockRead(ASYNC, OK),
@@ -11269,26 +11340,19 @@ TEST_P(HttpNetworkTransactionTest,
data_reads, arraysize(data_reads), NULL, 0);
session_deps_.socket_factory->AddSocketDataProvider(&first_transaction);
SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.SetNextProto(kProtoHTTP11);
+ ssl_http11.next_proto = kProtoHTTP11;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
- SSLSocketDataProvider ssl_http2(ASYNC, OK);
- ssl_http2.SetNextProto(GetProtocol());
- ssl_http2.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
- ASSERT_TRUE(ssl_http2.cert);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http2);
+ AddSSLSocketData();
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet("https://www.example.org/", 1, LOWEST));
- MockWrite spdy_writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite spdy_writes[] = {CreateMockWrite(req, 0)};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> data(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead spdy_reads[] = {
- CreateMockRead(*resp, 1), CreateMockRead(*data, 2), MockRead(ASYNC, 0, 3),
+ CreateMockRead(resp, 1), CreateMockRead(data, 2), MockRead(ASYNC, 0, 3),
};
SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
@@ -11299,12 +11363,12 @@ TEST_P(HttpNetworkTransactionTest,
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -11312,7 +11376,7 @@ TEST_P(HttpNetworkTransactionTest,
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
EXPECT_EQ("hello world", response_data);
// Set up an initial SpdySession in the pool to reuse.
@@ -11320,22 +11384,22 @@ TEST_P(HttpNetworkTransactionTest,
SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
PRIVACY_MODE_DISABLED);
base::WeakPtr<SpdySession> spdy_session =
- CreateSecureSpdySession(session.get(), key, BoundNetLog());
+ CreateSecureSpdySession(session.get(), key, NetLogWithSource());
trans.reset(new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
response = trans->GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
+ EXPECT_TRUE(response->was_alpn_negotiated);
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
}
@@ -11355,11 +11419,10 @@ TEST_P(HttpNetworkTransactionTest,
// potentially running up to three rounds in each of the tests. The TestConfig
// specifies both the configuration for the test as well as the expectations
// for the results.
-TEST_P(HttpNetworkTransactionTest, GenerateAuthToken) {
+TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) {
static const char kServer[] = "http://www.example.com";
static const char kSecureServer[] = "https://www.example.com";
static const char kProxy[] = "myproxy:70";
- const int kAuthErr = ERR_INVALID_AUTH_CREDENTIALS;
enum AuthTiming {
AUTH_NONE,
@@ -11466,202 +11529,697 @@ TEST_P(HttpNetworkTransactionTest, GenerateAuthToken) {
static const int kNoSSL = 500;
struct TestConfig {
+ int line_number;
const char* const proxy_url;
AuthTiming proxy_auth_timing;
- int proxy_auth_rv;
+ int first_generate_proxy_token_rv;
const char* const server_url;
AuthTiming server_auth_timing;
- int server_auth_rv;
+ int first_generate_server_token_rv;
int num_auth_rounds;
int first_ssl_round;
- TestRound rounds[3];
+ TestRound rounds[4];
} test_configs[] = {
- // Non-authenticating HTTP server with a direct connection.
- { NULL, AUTH_NONE, OK, kServer, AUTH_NONE, OK, 1, kNoSSL,
- { TestRound(kGet, kSuccess, OK)}},
- // Authenticating HTTP server with a direct connection.
- { NULL, AUTH_NONE, OK, kServer, AUTH_SYNC, OK, 2, kNoSSL,
- { TestRound(kGet, kServerChallenge, OK),
+ // Non-authenticating HTTP server with a direct connection.
+ {__LINE__,
+ nullptr,
+ AUTH_NONE,
+ OK,
+ kServer,
+ AUTH_NONE,
+ OK,
+ 1,
+ kNoSSL,
+ {TestRound(kGet, kSuccess, OK)}},
+ // Authenticating HTTP server with a direct connection.
+ {__LINE__,
+ nullptr,
+ AUTH_NONE,
+ OK,
+ kServer,
+ AUTH_SYNC,
+ OK,
+ 2,
+ kNoSSL,
+ {TestRound(kGet, kServerChallenge, OK),
+ TestRound(kGetAuth, kSuccess, OK)}},
+ {__LINE__,
+ nullptr,
+ AUTH_NONE,
+ OK,
+ kServer,
+ AUTH_SYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 3,
+ kNoSSL,
+ {TestRound(kGet, kServerChallenge, OK),
+ TestRound(kGet, kServerChallenge, OK),
+ TestRound(kGetAuth, kSuccess, OK)}},
+ {__LINE__,
+ nullptr,
+ AUTH_NONE,
+ OK,
+ kServer,
+ AUTH_SYNC,
+ ERR_UNSUPPORTED_AUTH_SCHEME,
+ 2,
+ kNoSSL,
+ {TestRound(kGet, kServerChallenge, OK), TestRound(kGet, kSuccess, OK)}},
+ {__LINE__,
+ nullptr,
+ AUTH_NONE,
+ OK,
+ kServer,
+ AUTH_SYNC,
+ ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS,
+ 2,
+ kNoSSL,
+ {TestRound(kGet, kServerChallenge, OK), TestRound(kGet, kSuccess, OK)}},
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ ERR_FAILED,
+ kServer,
+ AUTH_NONE,
+ OK,
+ 2,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
+ TestRound(kGetProxy, kFailure, ERR_FAILED)}},
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ ERR_FAILED,
+ kServer,
+ AUTH_NONE,
+ OK,
+ 2,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
+ TestRound(kGetProxy, kFailure, ERR_FAILED)}},
+ {__LINE__,
+ nullptr,
+ AUTH_NONE,
+ OK,
+ kServer,
+ AUTH_SYNC,
+ ERR_FAILED,
+ 2,
+ kNoSSL,
+ {TestRound(kGet, kServerChallenge, OK),
+ TestRound(kGet, kFailure, ERR_FAILED)}},
+ {__LINE__,
+ nullptr,
+ AUTH_NONE,
+ OK,
+ kServer,
+ AUTH_ASYNC,
+ ERR_FAILED,
+ 2,
+ kNoSSL,
+ {TestRound(kGet, kServerChallenge, OK),
+ TestRound(kGet, kFailure, ERR_FAILED)}},
+ {__LINE__,
+ nullptr,
+ AUTH_NONE,
+ OK,
+ kServer,
+ AUTH_ASYNC,
+ OK,
+ 2,
+ kNoSSL,
+ {TestRound(kGet, kServerChallenge, OK),
TestRound(kGetAuth, kSuccess, OK)}},
- { NULL, AUTH_NONE, OK, kServer, AUTH_SYNC, kAuthErr, 2, kNoSSL,
- { TestRound(kGet, kServerChallenge, OK),
- TestRound(kGetAuth, kFailure, kAuthErr)}},
- { NULL, AUTH_NONE, OK, kServer, AUTH_ASYNC, OK, 2, kNoSSL,
- { TestRound(kGet, kServerChallenge, OK),
+ {__LINE__,
+ nullptr,
+ AUTH_NONE,
+ OK,
+ kServer,
+ AUTH_ASYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 3,
+ kNoSSL,
+ {TestRound(kGet, kServerChallenge, OK),
+ // The second round uses a HttpAuthHandlerMock that always succeeds.
+ TestRound(kGet, kServerChallenge, OK),
TestRound(kGetAuth, kSuccess, OK)}},
- { NULL, AUTH_NONE, OK, kServer, AUTH_ASYNC, kAuthErr, 2, kNoSSL,
- { TestRound(kGet, kServerChallenge, OK),
- TestRound(kGetAuth, kFailure, kAuthErr)}},
- // Non-authenticating HTTP server through a non-authenticating proxy.
- { kProxy, AUTH_NONE, OK, kServer, AUTH_NONE, OK, 1, kNoSSL,
- { TestRound(kGetProxy, kSuccess, OK)}},
- // Authenticating HTTP server through a non-authenticating proxy.
- { kProxy, AUTH_NONE, OK, kServer, AUTH_SYNC, OK, 2, kNoSSL,
- { TestRound(kGetProxy, kServerChallenge, OK),
+ // Non-authenticating HTTP server through a non-authenticating proxy.
+ {__LINE__,
+ kProxy,
+ AUTH_NONE,
+ OK,
+ kServer,
+ AUTH_NONE,
+ OK,
+ 1,
+ kNoSSL,
+ {TestRound(kGetProxy, kSuccess, OK)}},
+ // Authenticating HTTP server through a non-authenticating proxy.
+ {__LINE__,
+ kProxy,
+ AUTH_NONE,
+ OK,
+ kServer,
+ AUTH_SYNC,
+ OK,
+ 2,
+ kNoSSL,
+ {TestRound(kGetProxy, kServerChallenge, OK),
TestRound(kGetAuthThroughProxy, kSuccess, OK)}},
- { kProxy, AUTH_NONE, OK, kServer, AUTH_SYNC, kAuthErr, 2, kNoSSL,
- { TestRound(kGetProxy, kServerChallenge, OK),
- TestRound(kGetAuthThroughProxy, kFailure, kAuthErr)}},
- { kProxy, AUTH_NONE, OK, kServer, AUTH_ASYNC, OK, 2, kNoSSL,
- { TestRound(kGetProxy, kServerChallenge, OK),
+ {__LINE__,
+ kProxy,
+ AUTH_NONE,
+ OK,
+ kServer,
+ AUTH_SYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 3,
+ kNoSSL,
+ {TestRound(kGetProxy, kServerChallenge, OK),
+ TestRound(kGetProxy, kServerChallenge, OK),
TestRound(kGetAuthThroughProxy, kSuccess, OK)}},
- { kProxy, AUTH_NONE, OK, kServer, AUTH_ASYNC, kAuthErr, 2, kNoSSL,
- { TestRound(kGetProxy, kServerChallenge, OK),
- TestRound(kGetAuthThroughProxy, kFailure, kAuthErr)}},
- // Non-authenticating HTTP server through an authenticating proxy.
- { kProxy, AUTH_SYNC, OK, kServer, AUTH_NONE, OK, 2, kNoSSL,
- { TestRound(kGetProxy, kProxyChallenge, OK),
+ {__LINE__,
+ kProxy,
+ AUTH_NONE,
+ OK,
+ kServer,
+ AUTH_ASYNC,
+ OK,
+ 2,
+ kNoSSL,
+ {TestRound(kGetProxy, kServerChallenge, OK),
+ TestRound(kGetAuthThroughProxy, kSuccess, OK)}},
+ {__LINE__,
+ kProxy,
+ AUTH_NONE,
+ OK,
+ kServer,
+ AUTH_ASYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 2,
+ kNoSSL,
+ {TestRound(kGetProxy, kServerChallenge, OK),
+ TestRound(kGetProxy, kSuccess, OK)}},
+ // Non-authenticating HTTP server through an authenticating proxy.
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ OK,
+ kServer,
+ AUTH_NONE,
+ OK,
+ 2,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
+ TestRound(kGetProxyAuth, kSuccess, OK)}},
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ kServer,
+ AUTH_NONE,
+ OK,
+ 2,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
+ TestRound(kGetProxy, kSuccess, OK)}},
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ OK,
+ kServer,
+ AUTH_NONE,
+ OK,
+ 2,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
TestRound(kGetProxyAuth, kSuccess, OK)}},
- { kProxy, AUTH_SYNC, kAuthErr, kServer, AUTH_NONE, OK, 2, kNoSSL,
- { TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxyAuth, kFailure, kAuthErr)}},
- { kProxy, AUTH_ASYNC, OK, kServer, AUTH_NONE, OK, 2, kNoSSL,
- { TestRound(kGetProxy, kProxyChallenge, OK),
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ kServer,
+ AUTH_NONE,
+ OK,
+ 2,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
+ TestRound(kGetProxy, kSuccess, OK)}},
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ kServer,
+ AUTH_NONE,
+ OK,
+ 3,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
+ TestRound(kGetProxy, kProxyChallenge, OK),
TestRound(kGetProxyAuth, kSuccess, OK)}},
- { kProxy, AUTH_ASYNC, kAuthErr, kServer, AUTH_NONE, OK, 2, kNoSSL,
- { TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxyAuth, kFailure, kAuthErr)}},
- // Authenticating HTTP server through an authenticating proxy.
- { kProxy, AUTH_SYNC, OK, kServer, AUTH_SYNC, OK, 3, kNoSSL,
- { TestRound(kGetProxy, kProxyChallenge, OK),
+ // Authenticating HTTP server through an authenticating proxy.
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ OK,
+ kServer,
+ AUTH_SYNC,
+ OK,
+ 3,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
TestRound(kGetProxyAuth, kServerChallenge, OK),
TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}},
- { kProxy, AUTH_SYNC, OK, kServer, AUTH_SYNC, kAuthErr, 3, kNoSSL,
- { TestRound(kGetProxy, kProxyChallenge, OK),
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ OK,
+ kServer,
+ AUTH_SYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 3,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
TestRound(kGetProxyAuth, kServerChallenge, OK),
- TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}},
- { kProxy, AUTH_ASYNC, OK, kServer, AUTH_SYNC, OK, 3, kNoSSL,
- { TestRound(kGetProxy, kProxyChallenge, OK),
+ TestRound(kGetProxyAuth, kSuccess, OK)}},
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ OK,
+ kServer,
+ AUTH_SYNC,
+ OK,
+ 3,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
TestRound(kGetProxyAuth, kServerChallenge, OK),
TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}},
- { kProxy, AUTH_ASYNC, OK, kServer, AUTH_SYNC, kAuthErr, 3, kNoSSL,
- { TestRound(kGetProxy, kProxyChallenge, OK),
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ OK,
+ kServer,
+ AUTH_SYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 3,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
TestRound(kGetProxyAuth, kServerChallenge, OK),
- TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}},
- { kProxy, AUTH_SYNC, OK, kServer, AUTH_ASYNC, OK, 3, kNoSSL,
- { TestRound(kGetProxy, kProxyChallenge, OK),
+ TestRound(kGetProxyAuth, kSuccess, OK)}},
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ OK,
+ kServer,
+ AUTH_ASYNC,
+ OK,
+ 3,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
TestRound(kGetProxyAuth, kServerChallenge, OK),
TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}},
- { kProxy, AUTH_SYNC, OK, kServer, AUTH_ASYNC, kAuthErr, 3, kNoSSL,
- { TestRound(kGetProxy, kProxyChallenge, OK),
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ kServer,
+ AUTH_ASYNC,
+ OK,
+ 4,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
+ TestRound(kGetProxy, kProxyChallenge, OK),
TestRound(kGetProxyAuth, kServerChallenge, OK),
- TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}},
- { kProxy, AUTH_ASYNC, OK, kServer, AUTH_ASYNC, OK, 3, kNoSSL,
- { TestRound(kGetProxy, kProxyChallenge, OK),
+ TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}},
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ OK,
+ kServer,
+ AUTH_ASYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 3,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
+ TestRound(kGetProxyAuth, kServerChallenge, OK),
+ TestRound(kGetProxyAuth, kSuccess, OK)}},
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ OK,
+ kServer,
+ AUTH_ASYNC,
+ OK,
+ 3,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
TestRound(kGetProxyAuth, kServerChallenge, OK),
TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}},
- { kProxy, AUTH_ASYNC, OK, kServer, AUTH_ASYNC, kAuthErr, 3, kNoSSL,
- { TestRound(kGetProxy, kProxyChallenge, OK),
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ OK,
+ kServer,
+ AUTH_ASYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 3,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
+ TestRound(kGetProxyAuth, kServerChallenge, OK),
+ TestRound(kGetProxyAuth, kSuccess, OK)}},
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ kServer,
+ AUTH_ASYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 4,
+ kNoSSL,
+ {TestRound(kGetProxy, kProxyChallenge, OK),
+ TestRound(kGetProxy, kProxyChallenge, OK),
TestRound(kGetProxyAuth, kServerChallenge, OK),
- TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}},
- // Non-authenticating HTTPS server with a direct connection.
- { NULL, AUTH_NONE, OK, kSecureServer, AUTH_NONE, OK, 1, 0,
- { TestRound(kGet, kSuccess, OK)}},
- // Authenticating HTTPS server with a direct connection.
- { NULL, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, OK, 2, 0,
- { TestRound(kGet, kServerChallenge, OK),
+ TestRound(kGetProxyAuth, kSuccess, OK)}},
+ // Non-authenticating HTTPS server with a direct connection.
+ {__LINE__,
+ nullptr,
+ AUTH_NONE,
+ OK,
+ kSecureServer,
+ AUTH_NONE,
+ OK,
+ 1,
+ 0,
+ {TestRound(kGet, kSuccess, OK)}},
+ // Authenticating HTTPS server with a direct connection.
+ {__LINE__,
+ nullptr,
+ AUTH_NONE,
+ OK,
+ kSecureServer,
+ AUTH_SYNC,
+ OK,
+ 2,
+ 0,
+ {TestRound(kGet, kServerChallenge, OK),
TestRound(kGetAuth, kSuccess, OK)}},
- { NULL, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, kAuthErr, 2, 0,
- { TestRound(kGet, kServerChallenge, OK),
- TestRound(kGetAuth, kFailure, kAuthErr)}},
- { NULL, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, OK, 2, 0,
- { TestRound(kGet, kServerChallenge, OK),
+ {__LINE__,
+ nullptr,
+ AUTH_NONE,
+ OK,
+ kSecureServer,
+ AUTH_SYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 2,
+ 0,
+ {TestRound(kGet, kServerChallenge, OK), TestRound(kGet, kSuccess, OK)}},
+ {__LINE__,
+ nullptr,
+ AUTH_NONE,
+ OK,
+ kSecureServer,
+ AUTH_ASYNC,
+ OK,
+ 2,
+ 0,
+ {TestRound(kGet, kServerChallenge, OK),
TestRound(kGetAuth, kSuccess, OK)}},
- { NULL, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 2, 0,
- { TestRound(kGet, kServerChallenge, OK),
- TestRound(kGetAuth, kFailure, kAuthErr)}},
- // Non-authenticating HTTPS server with a non-authenticating proxy.
- { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_NONE, OK, 1, 0,
- { TestRound(kConnect, kProxyConnected, OK, &kGet, &kSuccess)}},
- // Authenticating HTTPS server through a non-authenticating proxy.
- { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, OK, 2, 0,
- { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
+ {__LINE__,
+ nullptr,
+ AUTH_NONE,
+ OK,
+ kSecureServer,
+ AUTH_ASYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 2,
+ 0,
+ {TestRound(kGet, kServerChallenge, OK), TestRound(kGet, kSuccess, OK)}},
+ // Non-authenticating HTTPS server with a non-authenticating proxy.
+ {__LINE__,
+ kProxy,
+ AUTH_NONE,
+ OK,
+ kSecureServer,
+ AUTH_NONE,
+ OK,
+ 1,
+ 0,
+ {TestRound(kConnect, kProxyConnected, OK, &kGet, &kSuccess)}},
+ // Authenticating HTTPS server through a non-authenticating proxy.
+ {__LINE__,
+ kProxy,
+ AUTH_NONE,
+ OK,
+ kSecureServer,
+ AUTH_SYNC,
+ OK,
+ 2,
+ 0,
+ {TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
TestRound(kGetAuth, kSuccess, OK)}},
- { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, kAuthErr, 2, 0,
- { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
- TestRound(kGetAuth, kFailure, kAuthErr)}},
- { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, OK, 2, 0,
- { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
+ {__LINE__,
+ kProxy,
+ AUTH_NONE,
+ OK,
+ kSecureServer,
+ AUTH_SYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 2,
+ 0,
+ {TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
+ TestRound(kGet, kSuccess, OK)}},
+ {__LINE__,
+ kProxy,
+ AUTH_NONE,
+ OK,
+ kSecureServer,
+ AUTH_ASYNC,
+ OK,
+ 2,
+ 0,
+ {TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
TestRound(kGetAuth, kSuccess, OK)}},
- { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 2, 0,
- { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
- TestRound(kGetAuth, kFailure, kAuthErr)}},
- // Non-Authenticating HTTPS server through an authenticating proxy.
- { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_NONE, OK, 2, 1,
- { TestRound(kConnect, kProxyChallenge, OK),
+ {__LINE__,
+ kProxy,
+ AUTH_NONE,
+ OK,
+ kSecureServer,
+ AUTH_ASYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 2,
+ 0,
+ {TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
+ TestRound(kGet, kSuccess, OK)}},
+ // Non-Authenticating HTTPS server through an authenticating proxy.
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ OK,
+ kSecureServer,
+ AUTH_NONE,
+ OK,
+ 2,
+ 1,
+ {TestRound(kConnect, kProxyChallenge, OK),
TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet, &kSuccess)}},
- { kProxy, AUTH_SYNC, kAuthErr, kSecureServer, AUTH_NONE, OK, 2, kNoSSL,
- { TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kFailure, kAuthErr)}},
- { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_NONE, OK, 2, 1,
- { TestRound(kConnect, kProxyChallenge, OK),
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ kSecureServer,
+ AUTH_NONE,
+ OK,
+ 2,
+ kNoSSL,
+ {TestRound(kConnect, kProxyChallenge, OK),
+ TestRound(kConnect, kProxyConnected, OK, &kGet, &kSuccess)}},
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ ERR_UNSUPPORTED_AUTH_SCHEME,
+ kSecureServer,
+ AUTH_NONE,
+ OK,
+ 2,
+ kNoSSL,
+ {TestRound(kConnect, kProxyChallenge, OK),
+ TestRound(kConnect, kProxyConnected, OK, &kGet, &kSuccess)}},
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ ERR_UNEXPECTED,
+ kSecureServer,
+ AUTH_NONE,
+ OK,
+ 2,
+ kNoSSL,
+ {TestRound(kConnect, kProxyChallenge, OK),
+ TestRound(kConnect, kProxyConnected, ERR_UNEXPECTED)}},
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ OK,
+ kSecureServer,
+ AUTH_NONE,
+ OK,
+ 2,
+ 1,
+ {TestRound(kConnect, kProxyChallenge, OK),
TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet, &kSuccess)}},
- { kProxy, AUTH_ASYNC, kAuthErr, kSecureServer, AUTH_NONE, OK, 2, kNoSSL,
- { TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kFailure, kAuthErr)}},
- // Authenticating HTTPS server through an authenticating proxy.
- { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_SYNC, OK, 3, 1,
- { TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK,
- &kGet, &kServerChallenge),
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ kSecureServer,
+ AUTH_NONE,
+ OK,
+ 2,
+ kNoSSL,
+ {TestRound(kConnect, kProxyChallenge, OK),
+ TestRound(kConnect, kProxyConnected, OK, &kGet, &kSuccess)}},
+ // Authenticating HTTPS server through an authenticating proxy.
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ OK,
+ kSecureServer,
+ AUTH_SYNC,
+ OK,
+ 3,
+ 1,
+ {TestRound(kConnect, kProxyChallenge, OK),
+ TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
+ &kServerChallenge),
TestRound(kGetAuth, kSuccess, OK)}},
- { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_SYNC, kAuthErr, 3, 1,
- { TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK,
- &kGet, &kServerChallenge),
- TestRound(kGetAuth, kFailure, kAuthErr)}},
- { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_SYNC, OK, 3, 1,
- { TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK,
- &kGet, &kServerChallenge),
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ OK,
+ kSecureServer,
+ AUTH_SYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 3,
+ 1,
+ {TestRound(kConnect, kProxyChallenge, OK),
+ TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
+ &kServerChallenge),
+ TestRound(kGet, kSuccess, OK)}},
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ OK,
+ kSecureServer,
+ AUTH_SYNC,
+ OK,
+ 3,
+ 1,
+ {TestRound(kConnect, kProxyChallenge, OK),
+ TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
+ &kServerChallenge),
TestRound(kGetAuth, kSuccess, OK)}},
- { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_SYNC, kAuthErr, 3, 1,
- { TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK,
- &kGet, &kServerChallenge),
- TestRound(kGetAuth, kFailure, kAuthErr)}},
- { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_ASYNC, OK, 3, 1,
- { TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK,
- &kGet, &kServerChallenge),
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ OK,
+ kSecureServer,
+ AUTH_SYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 3,
+ 1,
+ {TestRound(kConnect, kProxyChallenge, OK),
+ TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
+ &kServerChallenge),
+ TestRound(kGet, kSuccess, OK)}},
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ OK,
+ kSecureServer,
+ AUTH_ASYNC,
+ OK,
+ 3,
+ 1,
+ {TestRound(kConnect, kProxyChallenge, OK),
+ TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
+ &kServerChallenge),
TestRound(kGetAuth, kSuccess, OK)}},
- { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 3, 1,
- { TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK,
- &kGet, &kServerChallenge),
- TestRound(kGetAuth, kFailure, kAuthErr)}},
- { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_ASYNC, OK, 3, 1,
- { TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK,
- &kGet, &kServerChallenge),
+ {__LINE__,
+ kProxy,
+ AUTH_SYNC,
+ OK,
+ kSecureServer,
+ AUTH_ASYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 3,
+ 1,
+ {TestRound(kConnect, kProxyChallenge, OK),
+ TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
+ &kServerChallenge),
+ TestRound(kGet, kSuccess, OK)}},
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ OK,
+ kSecureServer,
+ AUTH_ASYNC,
+ OK,
+ 3,
+ 1,
+ {TestRound(kConnect, kProxyChallenge, OK),
+ TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
+ &kServerChallenge),
TestRound(kGetAuth, kSuccess, OK)}},
- { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 3, 1,
- { TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK,
- &kGet, &kServerChallenge),
- TestRound(kGetAuth, kFailure, kAuthErr)}},
- };
-
- for (size_t i = 0; i < arraysize(test_configs); ++i) {
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ OK,
+ kSecureServer,
+ AUTH_ASYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 3,
+ 1,
+ {TestRound(kConnect, kProxyChallenge, OK),
+ TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
+ &kServerChallenge),
+ TestRound(kGet, kSuccess, OK)}},
+ {__LINE__,
+ kProxy,
+ AUTH_ASYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ kSecureServer,
+ AUTH_ASYNC,
+ ERR_INVALID_AUTH_CREDENTIALS,
+ 4,
+ 2,
+ {TestRound(kConnect, kProxyChallenge, OK),
+ TestRound(kConnect, kProxyChallenge, OK),
+ TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
+ &kServerChallenge),
+ TestRound(kGet, kSuccess, OK)}},
+ };
+
+ for (const auto& test_config : test_configs) {
+ SCOPED_TRACE(::testing::Message() << "Test config at "
+ << test_config.line_number);
HttpAuthHandlerMock::Factory* auth_factory(
new HttpAuthHandlerMock::Factory());
session_deps_.http_auth_handler_factory.reset(auth_factory);
SSLInfo empty_ssl_info;
- const TestConfig& test_config = test_configs[i];
// Set up authentication handlers as necessary.
if (test_config.proxy_auth_timing != AUTH_NONE) {
- for (int n = 0; n < 2; n++) {
+ for (int n = 0; n < 3; n++) {
HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock());
std::string auth_challenge = "Mock realm=proxy";
GURL origin(test_config.proxy_url);
HttpAuthChallengeTokenizer tokenizer(auth_challenge.begin(),
auth_challenge.end());
auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_PROXY,
- empty_ssl_info, origin, BoundNetLog());
+ empty_ssl_info, origin,
+ NetLogWithSource());
auth_handler->SetGenerateExpectation(
test_config.proxy_auth_timing == AUTH_ASYNC,
- test_config.proxy_auth_rv);
+ n == 0 ? test_config.first_generate_proxy_token_rv : OK);
auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_PROXY);
}
}
@@ -11672,11 +12230,24 @@ TEST_P(HttpNetworkTransactionTest, GenerateAuthToken) {
HttpAuthChallengeTokenizer tokenizer(auth_challenge.begin(),
auth_challenge.end());
auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER,
- empty_ssl_info, origin, BoundNetLog());
+ empty_ssl_info, origin,
+ NetLogWithSource());
auth_handler->SetGenerateExpectation(
test_config.server_auth_timing == AUTH_ASYNC,
- test_config.server_auth_rv);
+ test_config.first_generate_server_token_rv);
auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_SERVER);
+
+ // The second handler always succeeds. It should only be used where there
+ // are multiple auth sessions for server auth in the same network
+ // transaction using the same auth scheme.
+ std::unique_ptr<HttpAuthHandlerMock> second_handler =
+ base::MakeUnique<HttpAuthHandlerMock>();
+ second_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER,
+ empty_ssl_info, origin,
+ NetLogWithSource());
+ second_handler->SetGenerateExpectation(true, OK);
+ auth_factory->AddMockHandler(second_handler.release(),
+ HttpAuth::AUTH_SERVER);
}
if (test_config.proxy_url) {
session_deps_.proxy_service =
@@ -11742,7 +12313,7 @@ TEST_P(HttpNetworkTransactionTest, GenerateAuthToken) {
TestCompletionCallback callback;
int rv;
if (round == 0) {
- rv = trans.Start(&request, callback.callback(), BoundNetLog());
+ rv = trans.Start(&request, callback.callback(), NetLogWithSource());
} else {
rv = trans.RestartWithAuth(
AuthCredentials(kFoo, kBar), callback.callback());
@@ -11751,7 +12322,7 @@ TEST_P(HttpNetworkTransactionTest, GenerateAuthToken) {
rv = callback.WaitForResult();
// Compare results with expected data.
- EXPECT_EQ(read_write_round.expected_rv, rv);
+ EXPECT_THAT(rv, IsError(read_write_round.expected_rv));
const HttpResponseInfo* response = trans.GetResponseInfo();
if (read_write_round.expected_rv != OK) {
EXPECT_EQ(round + 1, test_config.num_auth_rounds);
@@ -11761,12 +12332,13 @@ TEST_P(HttpNetworkTransactionTest, GenerateAuthToken) {
EXPECT_TRUE(response->auth_challenge);
} else {
EXPECT_FALSE(response->auth_challenge);
+ EXPECT_FALSE(trans.IsReadyToRestartForAuth());
}
}
}
}
-TEST_P(HttpNetworkTransactionTest, MultiRoundAuth) {
+TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) {
// Do multi-round authentication and make sure it works correctly.
HttpAuthHandlerMock::Factory* auth_factory(
new HttpAuthHandlerMock::Factory());
@@ -11783,7 +12355,7 @@ TEST_P(HttpNetworkTransactionTest, MultiRoundAuth) {
auth_challenge.end());
SSLInfo empty_ssl_info;
auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER,
- empty_ssl_info, origin, BoundNetLog());
+ empty_ssl_info, origin, NetLogWithSource());
auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_SERVER);
int rv = OK;
@@ -11809,8 +12381,7 @@ TEST_P(HttpNetworkTransactionTest, MultiRoundAuth) {
mock_pool_manager->SetTransportSocketPool(transport_pool);
session_peer.SetClientSocketPoolManager(std::move(mock_pool_manager));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
const MockWrite kGet(
@@ -11867,69 +12438,80 @@ TEST_P(HttpNetworkTransactionTest, MultiRoundAuth) {
// First round of authentication.
auth_handler->SetGenerateExpectation(false, OK);
- rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ rv = trans.Start(&request, callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
- response = trans->GetResponseInfo();
+ EXPECT_THAT(rv, IsOk());
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->auth_challenge);
EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup));
+ EXPECT_EQ(HttpAuthHandlerMock::State::WAIT_FOR_GENERATE_AUTH_TOKEN,
+ auth_handler->state());
// In between rounds, another request comes in for the same domain.
// It should not be able to grab the TCP socket that trans has already
// claimed.
- std::unique_ptr<HttpTransaction> trans_compete(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans_compete(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback_compete;
- rv = trans_compete->Start(
- &request, callback_compete.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = trans_compete.Start(&request, callback_compete.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// callback_compete.WaitForResult at this point would stall forever,
// since the HttpNetworkTransaction does not release the request back to
// the pool until after authentication completes.
// Second round of authentication.
auth_handler->SetGenerateExpectation(false, OK);
- rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback());
+ rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
- response = trans->GetResponseInfo();
+ EXPECT_THAT(rv, IsOk());
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup));
+ EXPECT_EQ(HttpAuthHandlerMock::State::WAIT_FOR_GENERATE_AUTH_TOKEN,
+ auth_handler->state());
// Third round of authentication.
auth_handler->SetGenerateExpectation(false, OK);
- rv = trans->RestartWithAuth(AuthCredentials(), callback.callback());
+ rv = trans.RestartWithAuth(AuthCredentials(), callback.callback());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
- response = trans->GetResponseInfo();
+ EXPECT_THAT(rv, IsOk());
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup));
+ EXPECT_EQ(HttpAuthHandlerMock::State::WAIT_FOR_GENERATE_AUTH_TOKEN,
+ auth_handler->state());
// Fourth round of authentication, which completes successfully.
auth_handler->SetGenerateExpectation(false, OK);
- rv = trans->RestartWithAuth(AuthCredentials(), callback.callback());
+ rv = trans.RestartWithAuth(AuthCredentials(), callback.callback());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
- response = trans->GetResponseInfo();
+ EXPECT_THAT(rv, IsOk());
+ response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_FALSE(response->auth_challenge);
EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup));
+ // In WAIT_FOR_CHALLENGE, although in reality the auth handler is done. A real
+ // auth handler should transition to a DONE state in concert with the remote
+ // server. But that's not something we can test here with a mock handler.
+ EXPECT_EQ(HttpAuthHandlerMock::State::WAIT_FOR_CHALLENGE,
+ auth_handler->state());
+
// Read the body since the fourth round was successful. This will also
// release the socket back to the pool.
scoped_refptr<IOBufferWithSize> io_buf(new IOBufferWithSize(50));
- rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback());
+ rv = trans.Read(io_buf.get(), io_buf->size(), callback.callback());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_EQ(3, rv);
- rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback());
+ rv = trans.Read(io_buf.get(), io_buf->size(), callback.callback());
EXPECT_EQ(0, rv);
// There are still 0 idle sockets, since the trans_compete transaction
// will be handed it immediately after trans releases it to the group.
@@ -11938,12 +12520,12 @@ TEST_P(HttpNetworkTransactionTest, MultiRoundAuth) {
// The competing request can now finish. Wait for the headers and then
// read the body.
rv = callback_compete.WaitForResult();
- EXPECT_EQ(OK, rv);
- rv = trans_compete->Read(io_buf.get(), io_buf->size(), callback.callback());
+ EXPECT_THAT(rv, IsOk());
+ rv = trans_compete.Read(io_buf.get(), io_buf->size(), callback.callback());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_EQ(3, rv);
- rv = trans_compete->Read(io_buf.get(), io_buf->size(), callback.callback());
+ rv = trans_compete.Read(io_buf.get(), io_buf->size(), callback.callback());
EXPECT_EQ(0, rv);
// Finally, the socket is released to the group.
@@ -11952,7 +12534,7 @@ TEST_P(HttpNetworkTransactionTest, MultiRoundAuth) {
// This tests the case that a request is issued via http instead of spdy after
// npn is negotiated.
-TEST_P(HttpNetworkTransactionTest, NpnWithHttpOverSSL) {
+TEST_F(HttpNetworkTransactionTest, NpnWithHttpOverSSL) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
@@ -11965,19 +12547,16 @@ TEST_P(HttpNetworkTransactionTest, NpnWithHttpOverSSL) {
"Connection: keep-alive\r\n\r\n"),
};
- std::string alternative_service_http_header =
- GetAlternativeServiceHttpHeader();
-
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(alternative_service_http_header.c_str()),
+ MockRead(kAlternativeServiceHttpHeader),
MockRead("\r\n"),
MockRead("hello world"),
MockRead(SYNCHRONOUS, OK),
};
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(kProtoHTTP11);
+ ssl.next_proto = kProtoHTTP11;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
@@ -11988,43 +12567,42 @@ TEST_P(HttpNetworkTransactionTest, NpnWithHttpOverSSL) {
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
EXPECT_EQ("hello world", response_data);
EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
+ EXPECT_TRUE(response->was_alpn_negotiated);
}
// Simulate the SSL handshake completing with an NPN negotiation followed by an
// immediate server closing of the socket.
// Regression test for https://crbug.com/46369.
-TEST_P(HttpNetworkTransactionTest, SpdyPostNPNServerHangup) {
+TEST_F(HttpNetworkTransactionTest, SpdyPostNPNServerHangup) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org/");
request.load_flags = 0;
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
+ ssl.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- MockWrite spdy_writes[] = {CreateMockWrite(*req, 1)};
+ MockWrite spdy_writes[] = {CreateMockWrite(req, 1)};
MockRead spdy_reads[] = {
MockRead(SYNCHRONOUS, 0, 0) // Not async - return 0 immediately.
@@ -12037,12 +12615,11 @@ TEST_P(HttpNetworkTransactionTest, SpdyPostNPNServerHangup) {
TestCompletionCallback callback;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.WaitForResult());
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
}
// A subclass of HttpAuthHandlerMock that records the request URL when
@@ -12070,7 +12647,7 @@ class UrlRecordingHttpAuthHandlerMock : public HttpAuthHandlerMock {
// Test that if we cancel the transaction as the connection is completing, that
// everything tears down correctly.
-TEST_P(HttpNetworkTransactionTest, SimpleCancel) {
+TEST_F(HttpNetworkTransactionTest, SimpleCancel) {
// Setup everything about the connection to complete synchronously, so that
// after calling HttpNetworkTransaction::Start, the only thing we're waiting
// for is the callback from the HttpStreamRequest.
@@ -12090,7 +12667,7 @@ TEST_P(HttpNetworkTransactionTest, SimpleCancel) {
session_deps_.host_resolver->set_synchronous_mode(true);
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
@@ -12101,7 +12678,7 @@ TEST_P(HttpNetworkTransactionTest, SimpleCancel) {
BoundTestNetLog log;
int rv = trans->Start(&request, callback.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
trans.reset(); // Cancel the transaction here.
base::RunLoop().RunUntilIdle();
@@ -12113,7 +12690,7 @@ TEST_P(HttpNetworkTransactionTest, SimpleCancel) {
// from after the HttpNetworkTransaction and the objects it owns have been
// deleted.
// See http://crbug.com/368418
-TEST_P(HttpNetworkTransactionTest, CancelAfterHeaders) {
+TEST_F(HttpNetworkTransactionTest, CancelAfterHeaders) {
MockRead data_reads[] = {
MockRead(ASYNC, "HTTP/1.1 200 OK\r\n"),
MockRead(ASYNC, "Content-Length: 2\r\n"),
@@ -12138,8 +12715,8 @@ TEST_P(HttpNetworkTransactionTest, CancelAfterHeaders) {
HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
callback.WaitForResult();
const HttpResponseInfo* response = trans.GetResponseInfo();
@@ -12158,7 +12735,7 @@ TEST_P(HttpNetworkTransactionTest, CancelAfterHeaders) {
}
// Test a basic GET request through a proxy.
-TEST_P(HttpNetworkTransactionTest, ProxyGet) {
+TEST_F(HttpNetworkTransactionTest, ProxyGet) {
session_deps_.proxy_service =
ProxyService::CreateFixedFromPacResult("PROXY myproxy:70");
BoundTestNetLog log;
@@ -12189,41 +12766,41 @@ TEST_P(HttpNetworkTransactionTest, ProxyGet) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
BeforeHeadersSentHandler headers_handler;
- trans->SetBeforeHeadersSentCallback(
+ trans.SetBeforeHeadersSentCallback(
base::Bind(&BeforeHeadersSentHandler::OnBeforeHeadersSent,
base::Unretained(&headers_handler)));
- int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), log.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers->IsKeepAlive());
EXPECT_EQ(200, response->headers->response_code());
EXPECT_EQ(100, response->headers->GetContentLength());
EXPECT_TRUE(response->was_fetched_via_proxy);
- EXPECT_TRUE(
- response->proxy_server.Equals(HostPortPair::FromString("myproxy:70")));
+ EXPECT_EQ(ProxyServer(ProxyServer::SCHEME_HTTP,
+ HostPortPair::FromString("myproxy:70")),
+ response->proxy_server);
EXPECT_TRUE(headers_handler.observed_before_headers_sent());
EXPECT_TRUE(headers_handler.observed_before_headers_sent_with_proxy());
EXPECT_EQ("myproxy:70", headers_handler.observed_proxy_server_uri());
EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReusedWithPac(load_timing_info,
CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
}
// Test a basic HTTPS GET request through a proxy.
-TEST_P(HttpNetworkTransactionTest, ProxyTunnelGet) {
+TEST_F(HttpNetworkTransactionTest, ProxyTunnelGet) {
session_deps_.proxy_service =
ProxyService::CreateFixedFromPacResult("PROXY myproxy:70");
BoundTestNetLog log;
@@ -12262,29 +12839,28 @@ TEST_P(HttpNetworkTransactionTest, ProxyTunnelGet) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
BeforeHeadersSentHandler headers_handler;
- trans->SetBeforeHeadersSentCallback(
+ trans.SetBeforeHeadersSentCallback(
base::Bind(&BeforeHeadersSentHandler::OnBeforeHeadersSent,
base::Unretained(&headers_handler)));
- int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), log.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
TestNetLogEntry::List entries;
log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLog::PHASE_NONE);
+ entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLogEventPhase::NONE);
ExpectLogContainsSomewhere(
entries, pos,
- NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLog::PHASE_NONE);
+ NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLogEventPhase::NONE);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers->IsKeepAlive());
@@ -12292,21 +12868,22 @@ TEST_P(HttpNetworkTransactionTest, ProxyTunnelGet) {
EXPECT_EQ(100, response->headers->GetContentLength());
EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
EXPECT_TRUE(response->was_fetched_via_proxy);
- EXPECT_TRUE(
- response->proxy_server.Equals(HostPortPair::FromString("myproxy:70")));
+ EXPECT_EQ(ProxyServer(ProxyServer::SCHEME_HTTP,
+ HostPortPair::FromString("myproxy:70")),
+ response->proxy_server);
EXPECT_TRUE(headers_handler.observed_before_headers_sent());
EXPECT_TRUE(headers_handler.observed_before_headers_sent_with_proxy());
EXPECT_EQ("myproxy:70", headers_handler.observed_proxy_server_uri());
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReusedWithPac(load_timing_info,
CONNECT_TIMING_HAS_SSL_TIMES);
}
// Test a basic HTTPS GET request through a proxy, connecting to an IPv6
// literal host.
-TEST_P(HttpNetworkTransactionTest, ProxyTunnelGetIPv6) {
+TEST_F(HttpNetworkTransactionTest, ProxyTunnelGetIPv6) {
session_deps_.proxy_service =
ProxyService::CreateFixedFromPacResult("PROXY myproxy:70");
BoundTestNetLog log;
@@ -12345,24 +12922,24 @@ TEST_P(HttpNetworkTransactionTest, ProxyTunnelGetIPv6) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), log.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
TestNetLogEntry::List entries;
log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLog::PHASE_NONE);
+ entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLogEventPhase::NONE);
ExpectLogContainsSomewhere(
- entries, pos, NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLog::PHASE_NONE);
+ entries, pos,
+ NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLogEventPhase::NONE);
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers->IsKeepAlive());
@@ -12370,18 +12947,19 @@ TEST_P(HttpNetworkTransactionTest, ProxyTunnelGetIPv6) {
EXPECT_EQ(100, response->headers->GetContentLength());
EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
EXPECT_TRUE(response->was_fetched_via_proxy);
- EXPECT_TRUE(
- response->proxy_server.Equals(HostPortPair::FromString("myproxy:70")));
+ EXPECT_EQ(ProxyServer(ProxyServer::SCHEME_HTTP,
+ HostPortPair::FromString("myproxy:70")),
+ response->proxy_server);
LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+ EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
TestLoadTimingNotReusedWithPac(load_timing_info,
CONNECT_TIMING_HAS_SSL_TIMES);
}
// Test a basic HTTPS GET request through a proxy, but the server hangs up
// while establishing the tunnel.
-TEST_P(HttpNetworkTransactionTest, ProxyTunnelGetHangup) {
+TEST_F(HttpNetworkTransactionTest, ProxyTunnelGetHangup) {
session_deps_.proxy_service = ProxyService::CreateFixed("myproxy:70");
BoundTestNetLog log;
session_deps_.net_log = log.bound().net_log();
@@ -12416,37 +12994,34 @@ TEST_P(HttpNetworkTransactionTest, ProxyTunnelGetHangup) {
TestCompletionCallback callback1;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback1.callback(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback1.callback(), log.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback1.WaitForResult();
- EXPECT_EQ(ERR_EMPTY_RESPONSE, rv);
+ EXPECT_THAT(rv, IsError(ERR_EMPTY_RESPONSE));
TestNetLogEntry::List entries;
log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLog::PHASE_NONE);
+ entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLogEventPhase::NONE);
ExpectLogContainsSomewhere(
entries, pos,
- NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLog::PHASE_NONE);
+ NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLogEventPhase::NONE);
}
// Test for crbug.com/55424.
-TEST_P(HttpNetworkTransactionTest, PreconnectWithExistingSpdySession) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(HttpNetworkTransactionTest, PreconnectWithExistingSpdySession) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
- MockWrite spdy_writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite spdy_writes[] = {CreateMockWrite(req, 0)};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> data(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead spdy_reads[] = {
- CreateMockRead(*resp, 1), CreateMockRead(*data, 2), MockRead(ASYNC, 0, 3),
+ CreateMockRead(resp, 1), CreateMockRead(data, 2), MockRead(ASYNC, 0, 3),
};
SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
@@ -12454,7 +13029,7 @@ TEST_P(HttpNetworkTransactionTest, PreconnectWithExistingSpdySession) {
session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
+ ssl.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
@@ -12464,7 +13039,7 @@ TEST_P(HttpNetworkTransactionTest, PreconnectWithExistingSpdySession) {
SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
PRIVACY_MODE_DISABLED);
base::WeakPtr<SpdySession> spdy_session =
- CreateInsecureSpdySession(session.get(), key, BoundNetLog());
+ CreateSecureSpdySession(session.get(), key, NetLogWithSource());
HttpRequestInfo request;
request.method = "GET";
@@ -12474,17 +13049,16 @@ TEST_P(HttpNetworkTransactionTest, PreconnectWithExistingSpdySession) {
// This is the important line that marks this as a preconnect.
request.motivation = HttpRequestInfo::PRECONNECT_MOTIVATED;
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
}
// Given a net error, cause that error to be returned from the first Write()
-// call and verify that the HttpTransaction fails with that error.
+// call and verify that the HttpNetworkTransaction fails with that error.
void HttpNetworkTransactionTest::CheckErrorIsPassedBack(
int error, IoMode mode) {
HttpRequestInfo request_info;
@@ -12501,17 +13075,16 @@ void HttpNetworkTransactionTest::CheckErrorIsPassedBack(
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data);
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
- int rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
+ int rv = trans.Start(&request_info, callback.callback(), NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
ASSERT_EQ(error, rv);
}
-TEST_P(HttpNetworkTransactionTest, SSLWriteCertError) {
+TEST_F(HttpNetworkTransactionTest, SSLWriteCertError) {
// Just check a grab bag of cert errors.
static const int kErrors[] = {
ERR_CERT_COMMON_NAME_INVALID,
@@ -12530,8 +13103,7 @@ TEST_P(HttpNetworkTransactionTest, SSLWriteCertError) {
// 2) TLS False Start is disabled.
// 3) The initial TLS handshake requests a client certificate.
// 4) The client supplies an invalid/unacceptable certificate.
-TEST_P(HttpNetworkTransactionTest,
- ClientAuthCertCache_Direct_NoFalseStart) {
+TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Direct_NoFalseStart) {
HttpRequestInfo request_info;
request_info.url = GURL("https://www.example.com/");
request_info.method = "GET";
@@ -12588,25 +13160,24 @@ TEST_P(HttpNetworkTransactionTest,
session_deps_.socket_factory->AddSocketDataProvider(&data4);
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Begin the SSL handshake with the peer. This consumes ssl_data1.
TestCompletionCallback callback;
- int rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request_info, callback.callback(), NetLogWithSource());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
// Complete the SSL handshake, which should abort due to requiring a
// client certificate.
rv = callback.WaitForResult();
- ASSERT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
+ ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
// Indicate that no certificate should be supplied. From the perspective
// of SSLClientCertCache, NULL is just as meaningful as a real
// certificate, so this is the same as supply a
// legitimate-but-unacceptable certificate.
- rv = trans->RestartWithCertificate(NULL, NULL, callback.callback());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithCertificate(NULL, NULL, callback.callback());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
// Ensure the certificate was added to the client auth cache before
// allowing the connection to continue restarting.
@@ -12620,7 +13191,7 @@ TEST_P(HttpNetworkTransactionTest,
// then consume ssl_data3 and ssl_data4, both of which should also fail.
// The result code is checked against what ssl_data4 should return.
rv = callback.WaitForResult();
- ASSERT_EQ(ERR_SSL_PROTOCOL_ERROR, rv);
+ ASSERT_THAT(rv, IsError(ERR_SSL_PROTOCOL_ERROR));
// Ensure that the client certificate is removed from the cache on a
// handshake failure.
@@ -12634,8 +13205,7 @@ TEST_P(HttpNetworkTransactionTest,
// 2) TLS False Start is enabled.
// 3) The initial TLS handshake requests a client certificate.
// 4) The client supplies an invalid/unacceptable certificate.
-TEST_P(HttpNetworkTransactionTest,
- ClientAuthCertCache_Direct_FalseStart) {
+TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Direct_FalseStart) {
HttpRequestInfo request_info;
request_info.url = GURL("https://www.example.com/");
request_info.method = "GET";
@@ -12706,25 +13276,24 @@ TEST_P(HttpNetworkTransactionTest,
session_deps_.socket_factory->AddSocketDataProvider(&data5);
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Begin the initial SSL handshake.
TestCompletionCallback callback;
- int rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request_info, callback.callback(), NetLogWithSource());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
// Complete the SSL handshake, which should abort due to requiring a
// client certificate.
rv = callback.WaitForResult();
- ASSERT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
+ ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
// Indicate that no certificate should be supplied. From the perspective
// of SSLClientCertCache, NULL is just as meaningful as a real
// certificate, so this is the same as supply a
// legitimate-but-unacceptable certificate.
- rv = trans->RestartWithCertificate(NULL, NULL, callback.callback());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithCertificate(NULL, NULL, callback.callback());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
// Ensure the certificate was added to the client auth cache before
// allowing the connection to continue restarting.
@@ -12738,7 +13307,7 @@ TEST_P(HttpNetworkTransactionTest,
// then consume ssl_data3 and ssl_data4, both of which should also fail.
// The result code is checked against what ssl_data4 should return.
rv = callback.WaitForResult();
- ASSERT_EQ(ERR_SSL_PROTOCOL_ERROR, rv);
+ ASSERT_THAT(rv, IsError(ERR_SSL_PROTOCOL_ERROR));
// Ensure that the client certificate is removed from the cache on a
// handshake failure.
@@ -12754,7 +13323,7 @@ TEST_P(HttpNetworkTransactionTest,
// proxy.
// The test is repeated twice, first for connecting to an HTTPS endpoint,
// then for connecting to an HTTP endpoint.
-TEST_P(HttpNetworkTransactionTest, ClientAuthCertCache_Proxy_Fail) {
+TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Proxy_Fail) {
session_deps_.proxy_service = ProxyService::CreateFixed("https://proxy:70");
BoundTestNetLog log;
session_deps_.net_log = log.bound().net_log();
@@ -12799,25 +13368,24 @@ TEST_P(HttpNetworkTransactionTest, ClientAuthCertCache_Proxy_Fail) {
for (size_t i = 0; i < arraysize(requests); ++i) {
session_deps_.socket_factory->ResetNextMockIndexes();
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Begin the SSL handshake with the proxy.
TestCompletionCallback callback;
- int rv = trans->Start(&requests[i], callback.callback(), BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&requests[i], callback.callback(), NetLogWithSource());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
// Complete the SSL handshake, which should abort due to requiring a
// client certificate.
rv = callback.WaitForResult();
- ASSERT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
+ ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
// Indicate that no certificate should be supplied. From the perspective
// of SSLClientCertCache, NULL is just as meaningful as a real
// certificate, so this is the same as supply a
// legitimate-but-unacceptable certificate.
- rv = trans->RestartWithCertificate(NULL, NULL, callback.callback());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ rv = trans.RestartWithCertificate(NULL, NULL, callback.callback());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
// Ensure the certificate was added to the client auth cache before
// allowing the connection to continue restarting.
@@ -12836,7 +13404,7 @@ TEST_P(HttpNetworkTransactionTest, ClientAuthCertCache_Proxy_Fail) {
// then consume ssl_data3, which should also fail. The result code is
// checked against what ssl_data3 should return.
rv = callback.WaitForResult();
- ASSERT_EQ(ERR_PROXY_CONNECTION_FAILED, rv);
+ ASSERT_THAT(rv, IsError(ERR_PROXY_CONNECTION_FAILED));
// Now that the new handshake has failed, ensure that the client
// certificate was removed from the client auth cache.
@@ -12848,38 +13416,30 @@ TEST_P(HttpNetworkTransactionTest, ClientAuthCertCache_Proxy_Fail) {
}
}
-TEST_P(HttpNetworkTransactionTest, UseIPConnectionPooling) {
+TEST_F(HttpNetworkTransactionTest, UseIPConnectionPooling) {
// Set up a special HttpNetworkSession with a MockCachingHostResolver.
session_deps_.host_resolver.reset(new MockCachingHostResolver());
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- SpdySessionPoolPeer pool_peer(session->spdy_session_pool());
- pool_peer.DisableDomainAuthenticationVerification();
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+ AddSSLSocketData();
- std::unique_ptr<SpdySerializedFrame> host1_req(
+ SpdySerializedFrame host1_req(
spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
spdy_util_.UpdateWithStreamDestruction(1);
- std::unique_ptr<SpdySerializedFrame> host2_req(
- spdy_util_.ConstructSpdyGet("https://www.gmail.com", 3, LOWEST));
+ SpdySerializedFrame host2_req(
+ spdy_util_.ConstructSpdyGet("https://mail.example.com", 3, LOWEST));
MockWrite spdy_writes[] = {
- CreateMockWrite(*host1_req, 0), CreateMockWrite(*host2_req, 3),
- };
- std::unique_ptr<SpdySerializedFrame> host1_resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> host1_resp_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> host2_resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> host2_resp_body(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
+ CreateMockWrite(host1_req, 0), CreateMockWrite(host2_req, 3),
+ };
+ SpdySerializedFrame host1_resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame host1_resp_body(
+ spdy_util_.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame host2_resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame host2_resp_body(
+ spdy_util_.ConstructSpdyDataFrame(3, true));
MockRead spdy_reads[] = {
- CreateMockRead(*host1_resp, 1),
- CreateMockRead(*host1_resp_body, 2),
- CreateMockRead(*host2_resp, 4),
- CreateMockRead(*host2_resp_body, 5),
+ CreateMockRead(host1_resp, 1), CreateMockRead(host1_resp_body, 2),
+ CreateMockRead(host2_resp, 4), CreateMockRead(host2_resp_body, 5),
MockRead(ASYNC, 0, 6),
};
@@ -12896,9 +13456,9 @@ TEST_P(HttpNetworkTransactionTest, UseIPConnectionPooling) {
request1.load_flags = 0;
HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get());
- int rv = trans1.Start(&request1, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ int rv = trans1.Start(&request1, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
const HttpResponseInfo* response = trans1.GetResponseInfo();
ASSERT_TRUE(response);
@@ -12906,75 +13466,65 @@ TEST_P(HttpNetworkTransactionTest, UseIPConnectionPooling) {
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data));
+ ASSERT_THAT(ReadTransaction(&trans1, &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
- // Preload www.gmail.com into HostCache.
- HostPortPair host_port("www.gmail.com", 443);
+ // Preload mail.example.com into HostCache.
+ HostPortPair host_port("mail.example.com", 443);
HostResolver::RequestInfo resolve_info(host_port);
AddressList ignored;
- rv = session_deps_.host_resolver->Resolve(resolve_info,
- DEFAULT_PRIORITY,
- &ignored,
- callback.callback(),
- NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ std::unique_ptr<HostResolver::Request> request;
+ rv = session_deps_.host_resolver->Resolve(resolve_info, DEFAULT_PRIORITY,
+ &ignored, callback.callback(),
+ &request, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
HttpRequestInfo request2;
request2.method = "GET";
- request2.url = GURL("https://www.gmail.com/");
+ request2.url = GURL("https://mail.example.com/");
request2.load_flags = 0;
HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
- rv = trans2.Start(&request2, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ rv = trans2.Start(&request2, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
response = trans2.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
- ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data));
+ EXPECT_TRUE(response->was_alpn_negotiated);
+ ASSERT_THAT(ReadTransaction(&trans2, &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
}
-TEST_P(HttpNetworkTransactionTest, UseIPConnectionPoolingAfterResolution) {
+TEST_F(HttpNetworkTransactionTest, UseIPConnectionPoolingAfterResolution) {
// Set up a special HttpNetworkSession with a MockCachingHostResolver.
session_deps_.host_resolver.reset(new MockCachingHostResolver());
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- SpdySessionPoolPeer pool_peer(session->spdy_session_pool());
- pool_peer.DisableDomainAuthenticationVerification();
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+ AddSSLSocketData();
- std::unique_ptr<SpdySerializedFrame> host1_req(
+ SpdySerializedFrame host1_req(
spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
spdy_util_.UpdateWithStreamDestruction(1);
- std::unique_ptr<SpdySerializedFrame> host2_req(
- spdy_util_.ConstructSpdyGet("https://www.gmail.com", 3, LOWEST));
+ SpdySerializedFrame host2_req(
+ spdy_util_.ConstructSpdyGet("https://mail.example.com", 3, LOWEST));
MockWrite spdy_writes[] = {
- CreateMockWrite(*host1_req, 0), CreateMockWrite(*host2_req, 3),
- };
- std::unique_ptr<SpdySerializedFrame> host1_resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> host1_resp_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> host2_resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> host2_resp_body(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
+ CreateMockWrite(host1_req, 0), CreateMockWrite(host2_req, 3),
+ };
+ SpdySerializedFrame host1_resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame host1_resp_body(
+ spdy_util_.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame host2_resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame host2_resp_body(
+ spdy_util_.ConstructSpdyDataFrame(3, true));
MockRead spdy_reads[] = {
- CreateMockRead(*host1_resp, 1),
- CreateMockRead(*host1_resp_body, 2),
- CreateMockRead(*host2_resp, 4),
- CreateMockRead(*host2_resp_body, 5),
+ CreateMockRead(host1_resp, 1), CreateMockRead(host1_resp_body, 2),
+ CreateMockRead(host2_resp, 4), CreateMockRead(host2_resp_body, 5),
MockRead(ASYNC, 0, 6),
};
@@ -12991,9 +13541,9 @@ TEST_P(HttpNetworkTransactionTest, UseIPConnectionPoolingAfterResolution) {
request1.load_flags = 0;
HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get());
- int rv = trans1.Start(&request1, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ int rv = trans1.Start(&request1, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
const HttpResponseInfo* response = trans1.GetResponseInfo();
ASSERT_TRUE(response);
@@ -13001,26 +13551,26 @@ TEST_P(HttpNetworkTransactionTest, UseIPConnectionPoolingAfterResolution) {
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data));
+ ASSERT_THAT(ReadTransaction(&trans1, &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
HttpRequestInfo request2;
request2.method = "GET";
- request2.url = GURL("https://www.gmail.com/");
+ request2.url = GURL("https://mail.example.com/");
request2.load_flags = 0;
HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
- rv = trans2.Start(&request2, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ rv = trans2.Start(&request2, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
response = trans2.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
- ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data));
+ EXPECT_TRUE(response->was_alpn_negotiated);
+ ASSERT_THAT(ReadTransaction(&trans2, &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
}
@@ -13037,25 +13587,21 @@ class OneTimeCachingHostResolver : public HostResolver {
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) override {
+ std::unique_ptr<Request>* out_req,
+ const NetLogWithSource& net_log) override {
return host_resolver_.Resolve(
info, priority, addresses, callback, out_req, net_log);
}
int ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
int rv = host_resolver_.ResolveFromCache(info, addresses, net_log);
if (rv == OK && info.host_port_pair().Equals(host_port_))
host_resolver_.GetHostCache()->clear();
return rv;
}
- void CancelRequest(RequestHandle req) override {
- host_resolver_.CancelRequest(req);
- }
-
MockCachingHostResolver* GetMockHostResolver() {
return &host_resolver_;
}
@@ -13065,42 +13611,35 @@ class OneTimeCachingHostResolver : public HostResolver {
const HostPortPair host_port_;
};
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
UseIPConnectionPoolingWithHostCacheExpiration) {
// Set up a special HttpNetworkSession with a OneTimeCachingHostResolver.
- OneTimeCachingHostResolver host_resolver(HostPortPair("www.gmail.com", 443));
+ OneTimeCachingHostResolver host_resolver(
+ HostPortPair("mail.example.com", 443));
HttpNetworkSession::Params params =
SpdySessionDependencies::CreateSessionParams(&session_deps_);
params.host_resolver = &host_resolver;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- SpdySessionPoolPeer pool_peer(session->spdy_session_pool());
- pool_peer.DisableDomainAuthenticationVerification();
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+ AddSSLSocketData();
- std::unique_ptr<SpdySerializedFrame> host1_req(
+ SpdySerializedFrame host1_req(
spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
spdy_util_.UpdateWithStreamDestruction(1);
- std::unique_ptr<SpdySerializedFrame> host2_req(
- spdy_util_.ConstructSpdyGet("https://www.gmail.com", 3, LOWEST));
+ SpdySerializedFrame host2_req(
+ spdy_util_.ConstructSpdyGet("https://mail.example.com", 3, LOWEST));
MockWrite spdy_writes[] = {
- CreateMockWrite(*host1_req, 0), CreateMockWrite(*host2_req, 3),
- };
- std::unique_ptr<SpdySerializedFrame> host1_resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> host1_resp_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> host2_resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> host2_resp_body(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
+ CreateMockWrite(host1_req, 0), CreateMockWrite(host2_req, 3),
+ };
+ SpdySerializedFrame host1_resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame host1_resp_body(
+ spdy_util_.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame host2_resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame host2_resp_body(
+ spdy_util_.ConstructSpdyDataFrame(3, true));
MockRead spdy_reads[] = {
- CreateMockRead(*host1_resp, 1),
- CreateMockRead(*host1_resp_body, 2),
- CreateMockRead(*host2_resp, 4),
- CreateMockRead(*host2_resp_body, 5),
+ CreateMockRead(host1_resp, 1), CreateMockRead(host1_resp_body, 2),
+ CreateMockRead(host2_resp, 4), CreateMockRead(host2_resp_body, 5),
MockRead(ASYNC, 0, 6),
};
@@ -13117,9 +13656,9 @@ TEST_P(HttpNetworkTransactionTest,
request1.load_flags = 0;
HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get());
- int rv = trans1.Start(&request1, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ int rv = trans1.Start(&request1, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
const HttpResponseInfo* response = trans1.GetResponseInfo();
ASSERT_TRUE(response);
@@ -13127,59 +13666,54 @@ TEST_P(HttpNetworkTransactionTest,
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data));
+ ASSERT_THAT(ReadTransaction(&trans1, &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
// Preload cache entries into HostCache.
- HostResolver::RequestInfo resolve_info(HostPortPair("www.gmail.com", 443));
+ HostResolver::RequestInfo resolve_info(HostPortPair("mail.example.com", 443));
AddressList ignored;
- rv = host_resolver.Resolve(resolve_info,
- DEFAULT_PRIORITY,
- &ignored,
- callback.callback(),
- NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ std::unique_ptr<HostResolver::Request> request;
+ rv = host_resolver.Resolve(resolve_info, DEFAULT_PRIORITY, &ignored,
+ callback.callback(), &request, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
HttpRequestInfo request2;
request2.method = "GET";
- request2.url = GURL("https://www.gmail.com/");
+ request2.url = GURL("https://mail.example.com/");
request2.load_flags = 0;
HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
- rv = trans2.Start(&request2, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ rv = trans2.Start(&request2, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
response = trans2.GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
- ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data));
+ EXPECT_TRUE(response->was_alpn_negotiated);
+ ASSERT_THAT(ReadTransaction(&trans2, &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
}
-TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttp) {
+TEST_F(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttp) {
const std::string https_url = "https://www.example.org:8080/";
const std::string http_url = "http://www.example.org:8080/";
// SPDY GET for HTTPS URL
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(https_url.c_str(), 1, LOWEST));
MockWrite writes1[] = {
- CreateMockWrite(*req1, 0),
+ CreateMockWrite(req1, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body1(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- MockRead reads1[] = {CreateMockRead(*resp1, 1), CreateMockRead(*body1, 2),
+ SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
+ MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
SequencedSocketData data1(reads1, arraysize(reads1), writes1,
@@ -13205,7 +13739,7 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttp) {
arraysize(writes2));
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
+ ssl.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
session_deps_.socket_factory->AddSocketDataProvider(&data1);
session_deps_.socket_factory->AddSocketDataProvider(&data2);
@@ -13220,10 +13754,10 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttp) {
HttpNetworkTransaction trans1(LOWEST, session.get());
TestCompletionCallback callback1;
EXPECT_EQ(ERR_IO_PENDING,
- trans1.Start(&request1, callback1.callback(), BoundNetLog()));
+ trans1.Start(&request1, callback1.callback(), NetLogWithSource()));
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_TRUE(trans1.GetResponseInfo()->was_fetched_via_spdy);
// Now, start the HTTP request
@@ -13234,183 +13768,22 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttp) {
HttpNetworkTransaction trans2(MEDIUM, session.get());
TestCompletionCallback callback2;
EXPECT_EQ(ERR_IO_PENDING,
- trans2.Start(&request2, callback2.callback(), BoundNetLog()));
+ trans2.Start(&request2, callback2.callback(), NetLogWithSource()));
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_FALSE(trans2.GetResponseInfo()->was_fetched_via_spdy);
}
-class AltSvcCertificateVerificationTest : public HttpNetworkTransactionTest {
- public:
- void Run(bool pooling, bool valid) {
- url::SchemeHostPort server(GURL(valid ? "https://mail.example.org:443"
- : "https://invalid.example.org:443"));
- HostPortPair alternative("www.example.org", 443);
-
- base::FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> cert(
- ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
- ASSERT_TRUE(cert);
- bool common_name_fallback_used;
- EXPECT_EQ(valid,
- cert->VerifyNameMatch(server.host(), &common_name_fallback_used));
- EXPECT_TRUE(
- cert->VerifyNameMatch(alternative.host(), &common_name_fallback_used));
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetProtocol());
- ssl.cert = cert;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
-
- // If pooling, then start a request to alternative first to create a
- // SpdySession.
- std::string url0 = "https://www.example.org:443";
- // Second request to server, which has an alternative service, and could
- // open a connection to the alternative host or pool to the existing one.
- std::string url1("https://");
- url1.append(server.host());
- url1.append(":443");
-
- std::unique_ptr<SpdySerializedFrame> req0;
- std::unique_ptr<SpdySerializedFrame> req1;
- std::unique_ptr<SpdySerializedFrame> resp0;
- std::unique_ptr<SpdySerializedFrame> body0;
- std::unique_ptr<SpdySerializedFrame> resp1;
- std::unique_ptr<SpdySerializedFrame> body1;
- std::vector<MockWrite> writes;
- std::vector<MockRead> reads;
-
- if (pooling) {
- req0.reset(spdy_util_.ConstructSpdyGet(url0.c_str(), 1, LOWEST));
- spdy_util_.UpdateWithStreamDestruction(1);
- req1.reset(spdy_util_.ConstructSpdyGet(url1.c_str(), 3, LOWEST));
-
- writes.push_back(CreateMockWrite(*req0, 0));
- writes.push_back(CreateMockWrite(*req1, 3));
-
- resp0.reset(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- body0.reset(spdy_util_.ConstructSpdyBodyFrame(1, true));
- resp1.reset(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- body1.reset(spdy_util_.ConstructSpdyBodyFrame(3, true));
-
- reads.push_back(CreateMockRead(*resp0, 1));
- reads.push_back(CreateMockRead(*body0, 2));
- reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, 4));
- reads.push_back(CreateMockRead(*resp1, 5));
- reads.push_back(CreateMockRead(*body1, 6));
- reads.push_back(MockRead(ASYNC, OK, 7));
- } else {
- req1.reset(spdy_util_.ConstructSpdyGet(url1.c_str(), 1, LOWEST));
-
- writes.push_back(CreateMockWrite(*req1, 0));
-
- resp1.reset(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- body1.reset(spdy_util_.ConstructSpdyBodyFrame(1, true));
-
- reads.push_back(CreateMockRead(*resp1, 1));
- reads.push_back(CreateMockRead(*body1, 2));
- reads.push_back(MockRead(ASYNC, OK, 3));
- }
-
- SequencedSocketData data(reads.data(), reads.size(), writes.data(),
- writes.size());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
-
- // Connection to the server fails.
- MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED);
- StaticSocketDataProvider data_refused;
- data_refused.set_connect_data(mock_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&data_refused);
-
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- AlternativeService alternative_service(
- AlternateProtocolFromNextProto(GetProtocol()), alternative);
- base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
- http_server_properties->SetAlternativeService(server, alternative_service,
- expiration);
-
- // First request to alternative.
- if (pooling) {
- std::unique_ptr<HttpTransaction> trans0(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- HttpRequestInfo request0;
- request0.method = "GET";
- request0.url = GURL(url0);
- request0.load_flags = 0;
- TestCompletionCallback callback0;
-
- int rv = trans0->Start(&request0, callback0.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- rv = callback0.WaitForResult();
- EXPECT_EQ(OK, rv);
- }
-
- // Second request to origin.
- std::unique_ptr<HttpTransaction> trans1(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL(url1);
- request1.load_flags = 0;
- TestCompletionCallback callback1;
-
- int rv = trans1->Start(&request1, callback1.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- base::RunLoop().RunUntilIdle();
- if (data.IsPaused())
- data.Resume();
- rv = callback1.WaitForResult();
- if (valid) {
- EXPECT_EQ(OK, rv);
- } else {
- if (pooling) {
- EXPECT_EQ(ERR_CONNECTION_REFUSED, rv);
- } else {
- EXPECT_EQ(ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN, rv);
- }
- }
- }
-};
-
-INSTANTIATE_TEST_CASE_P(ProtoPlusDepend,
- AltSvcCertificateVerificationTest,
- testing::Values(kTestCaseSPDY31,
- kTestCaseHTTP2NoPriorityDependencies,
- kTestCaseHTTP2PriorityDependencies));
-
-// The alternative service host must exhibit a certificate that is valid for the
-// origin host. Test that this is enforced when pooling to an existing
-// connection.
-TEST_P(AltSvcCertificateVerificationTest, PoolingValid) {
- Run(true, true);
-}
-
-TEST_P(AltSvcCertificateVerificationTest, PoolingInvalid) {
- Run(true, false);
-}
-
-// The alternative service host must exhibit a certificate that is valid for the
-// origin host. Test that this is enforced when opening a new connection.
-TEST_P(AltSvcCertificateVerificationTest, NewConnectionValid) {
- Run(false, true);
-}
-
-// TODO(bnc): Re-enable when https://crbug.com/615413 is fixed.
-TEST_P(AltSvcCertificateVerificationTest, DISABLED_NewConnectionInvalid) {
- Run(false, false);
-}
-
// Alternative service requires HTTP/2 (or SPDY), but HTTP/1.1 is negotiated
// with the alternative server. That connection should not be used.
-TEST_P(HttpNetworkTransactionTest, AlternativeServiceNotOnHttp11) {
+TEST_F(HttpNetworkTransactionTest, AlternativeServiceNotOnHttp11) {
url::SchemeHostPort server("https", "www.example.org", 443);
HostPortPair alternative("www.example.org", 444);
// Negotiate HTTP/1.1 with alternative.
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(kProtoHTTP11);
+ ssl.next_proto = kProtoHTTP11;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
// No data should be read from the alternative, because HTTP/1.1 is
@@ -13430,13 +13803,12 @@ TEST_P(HttpNetworkTransactionTest, AlternativeServiceNotOnHttp11) {
HttpServerProperties* http_server_properties =
session->http_server_properties();
AlternativeService alternative_service(
- AlternateProtocolFromNextProto(GetProtocol()), alternative);
+ AlternateProtocolFromNextProto(kProtoHTTP2), alternative);
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
http_server_properties->SetAlternativeService(server, alternative_service,
expiration);
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("https://www.example.org:443");
@@ -13444,22 +13816,22 @@ TEST_P(HttpNetworkTransactionTest, AlternativeServiceNotOnHttp11) {
TestCompletionCallback callback;
// HTTP/2 (or SPDY) is required for alternative service, if HTTP/1.1 is
- // negotiated, the alternate Job should fail with ERR_NPN_NEGOTIATION_FAILED.
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_NPN_NEGOTIATION_FAILED, callback.GetResult(rv));
+ // negotiated, the alternate Job should fail with ERR_ALPN_NEGOTIATION_FAILED.
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsError(ERR_ALPN_NEGOTIATION_FAILED));
}
// A request to a server with an alternative service fires two Jobs: one to the
// server, and an alternate one to the alternative server. If the former
// succeeds, the request should succeed, even if the latter fails because
// HTTP/1.1 is negotiated which is insufficient for alternative service.
-TEST_P(HttpNetworkTransactionTest, FailedAlternativeServiceIsNotUserVisible) {
+TEST_F(HttpNetworkTransactionTest, FailedAlternativeServiceIsNotUserVisible) {
url::SchemeHostPort server("https", "www.example.org", 443);
HostPortPair alternative("www.example.org", 444);
// Negotiate HTTP/1.1 with alternative.
SSLSocketDataProvider alternative_ssl(ASYNC, OK);
- alternative_ssl.SetNextProto(kProtoHTTP11);
+ alternative_ssl.next_proto = kProtoHTTP11;
session_deps_.socket_factory->AddSSLSocketDataProvider(&alternative_ssl);
// No data should be read from the alternative, because HTTP/1.1 is
@@ -13469,7 +13841,7 @@ TEST_P(HttpNetworkTransactionTest, FailedAlternativeServiceIsNotUserVisible) {
// Negotiate HTTP/1.1 with server.
SSLSocketDataProvider origin_ssl(ASYNC, OK);
- origin_ssl.SetNextProto(kProtoHTTP11);
+ origin_ssl.next_proto = kProtoHTTP11;
session_deps_.socket_factory->AddSSLSocketDataProvider(&origin_ssl);
MockWrite http_writes[] = {
@@ -13500,7 +13872,7 @@ TEST_P(HttpNetworkTransactionTest, FailedAlternativeServiceIsNotUserVisible) {
HttpServerProperties* http_server_properties =
session->http_server_properties();
AlternativeService alternative_service(
- AlternateProtocolFromNextProto(GetProtocol()), alternative);
+ AlternateProtocolFromNextProto(kProtoHTTP2), alternative);
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
http_server_properties->SetAlternativeService(server, alternative_service,
expiration);
@@ -13512,9 +13884,9 @@ TEST_P(HttpNetworkTransactionTest, FailedAlternativeServiceIsNotUserVisible) {
request1.load_flags = 0;
TestCompletionCallback callback1;
- int rv = trans1.Start(&request1, callback1.callback(), BoundNetLog());
+ int rv = trans1.Start(&request1, callback1.callback(), NetLogWithSource());
rv = callback1.GetResult(rv);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
const HttpResponseInfo* response1 = trans1.GetResponseInfo();
ASSERT_TRUE(response1);
@@ -13522,7 +13894,7 @@ TEST_P(HttpNetworkTransactionTest, FailedAlternativeServiceIsNotUserVisible) {
EXPECT_EQ("HTTP/1.1 200 OK", response1->headers->GetStatusLine());
std::string response_data1;
- ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data1));
+ ASSERT_THAT(ReadTransaction(&trans1, &response_data1), IsOk());
EXPECT_EQ("foobar", response_data1);
// Alternative should be marked as broken, because HTTP/1.1 is not sufficient
@@ -13540,9 +13912,9 @@ TEST_P(HttpNetworkTransactionTest, FailedAlternativeServiceIsNotUserVisible) {
request2.load_flags = 0;
TestCompletionCallback callback2;
- rv = trans2.Start(&request2, callback2.callback(), BoundNetLog());
+ rv = trans2.Start(&request2, callback2.callback(), NetLogWithSource());
rv = callback2.GetResult(rv);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
const HttpResponseInfo* response2 = trans2.GetResponseInfo();
ASSERT_TRUE(response2);
@@ -13550,14 +13922,14 @@ TEST_P(HttpNetworkTransactionTest, FailedAlternativeServiceIsNotUserVisible) {
EXPECT_EQ("HTTP/1.1 200 OK", response2->headers->GetStatusLine());
std::string response_data2;
- ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data2));
+ ASSERT_THAT(ReadTransaction(&trans2, &response_data2), IsOk());
EXPECT_EQ("another", response_data2);
}
// Alternative service requires HTTP/2 (or SPDY), but there is already a
// HTTP/1.1 socket open to the alternative server. That socket should not be
// used.
-TEST_P(HttpNetworkTransactionTest, AlternativeServiceShouldNotPoolToHttp11) {
+TEST_F(HttpNetworkTransactionTest, AlternativeServiceShouldNotPoolToHttp11) {
url::SchemeHostPort server("https", "origin.example.org", 443);
HostPortPair alternative("alternative.example.org", 443);
std::string origin_url = "https://origin.example.org:443";
@@ -13565,7 +13937,7 @@ TEST_P(HttpNetworkTransactionTest, AlternativeServiceShouldNotPoolToHttp11) {
// Negotiate HTTP/1.1 with alternative.example.org.
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(kProtoHTTP11);
+ ssl.next_proto = kProtoHTTP11;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
// HTTP/1.1 data for |request1| and |request2|.
@@ -13608,30 +13980,29 @@ TEST_P(HttpNetworkTransactionTest, AlternativeServiceShouldNotPoolToHttp11) {
HttpServerProperties* http_server_properties =
session->http_server_properties();
AlternativeService alternative_service(
- AlternateProtocolFromNextProto(GetProtocol()), alternative);
+ AlternateProtocolFromNextProto(kProtoHTTP2), alternative);
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
http_server_properties->SetAlternativeService(server, alternative_service,
expiration);
// First transaction to alternative to open an HTTP/1.1 socket.
- std::unique_ptr<HttpTransaction> trans1(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get());
HttpRequestInfo request1;
request1.method = "GET";
request1.url = GURL(alternative_url);
request1.load_flags = 0;
TestCompletionCallback callback1;
- int rv = trans1->Start(&request1, callback1.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback1.GetResult(rv));
- const HttpResponseInfo* response1 = trans1->GetResponseInfo();
+ int rv = trans1.Start(&request1, callback1.callback(), NetLogWithSource());
+ EXPECT_THAT(callback1.GetResult(rv), IsOk());
+ const HttpResponseInfo* response1 = trans1.GetResponseInfo();
ASSERT_TRUE(response1);
ASSERT_TRUE(response1->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response1->headers->GetStatusLine());
- EXPECT_TRUE(response1->was_npn_negotiated);
+ EXPECT_TRUE(response1->was_alpn_negotiated);
EXPECT_FALSE(response1->was_fetched_via_spdy);
std::string response_data1;
- ASSERT_EQ(OK, ReadTransaction(trans1.get(), &response_data1));
+ ASSERT_THAT(ReadTransaction(&trans1, &response_data1), IsOk());
EXPECT_EQ("first HTTP/1.1 response from alternative", response_data1);
// Request for origin.example.org, which has an alternative service. This
@@ -13639,93 +14010,87 @@ TEST_P(HttpNetworkTransactionTest, AlternativeServiceShouldNotPoolToHttp11) {
// finds one which is HTTP/1.1, and should ignore it, and should not try to
// open other connections to alternative server. The Job to server fails, so
// this request fails.
- std::unique_ptr<HttpTransaction> trans2(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
HttpRequestInfo request2;
request2.method = "GET";
request2.url = GURL(origin_url);
request2.load_flags = 0;
TestCompletionCallback callback2;
- rv = trans2->Start(&request2, callback2.callback(), BoundNetLog());
- EXPECT_EQ(ERR_CONNECTION_REFUSED, callback2.GetResult(rv));
+ rv = trans2.Start(&request2, callback2.callback(), NetLogWithSource());
+ EXPECT_THAT(callback2.GetResult(rv), IsError(ERR_CONNECTION_REFUSED));
// Another transaction to alternative. This is to test that the HTTP/1.1
// socket is still open and in the pool.
- std::unique_ptr<HttpTransaction> trans3(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans3(DEFAULT_PRIORITY, session.get());
HttpRequestInfo request3;
request3.method = "GET";
request3.url = GURL(alternative_url);
request3.load_flags = 0;
TestCompletionCallback callback3;
- rv = trans3->Start(&request3, callback3.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback3.GetResult(rv));
- const HttpResponseInfo* response3 = trans3->GetResponseInfo();
+ rv = trans3.Start(&request3, callback3.callback(), NetLogWithSource());
+ EXPECT_THAT(callback3.GetResult(rv), IsOk());
+ const HttpResponseInfo* response3 = trans3.GetResponseInfo();
ASSERT_TRUE(response3);
ASSERT_TRUE(response3->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response3->headers->GetStatusLine());
- EXPECT_TRUE(response3->was_npn_negotiated);
+ EXPECT_TRUE(response3->was_alpn_negotiated);
EXPECT_FALSE(response3->was_fetched_via_spdy);
std::string response_data3;
- ASSERT_EQ(OK, ReadTransaction(trans3.get(), &response_data3));
+ ASSERT_THAT(ReadTransaction(&trans3, &response_data3), IsOk());
EXPECT_EQ("second HTTP/1.1 response from alternative", response_data3);
}
-TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttpOverTunnel) {
+TEST_F(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttpOverTunnel) {
const std::string https_url = "https://www.example.org:8080/";
const std::string http_url = "http://www.example.org:8080/";
// Separate SPDY util instance for naked and wrapped requests.
- SpdyTestUtil spdy_util_wrapped(GetProtocol(), GetDependenciesFromPriority());
+ SpdyTestUtil spdy_util_wrapped;
// SPDY GET for HTTPS URL (through CONNECT tunnel)
const HostPortPair host_port_pair("www.example.org", 8080);
- std::unique_ptr<SpdySerializedFrame> connect(
+ SpdySerializedFrame connect(
spdy_util_.ConstructSpdyConnect(NULL, 0, 1, LOWEST, host_port_pair));
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_wrapped.ConstructSpdyGet(https_url.c_str(), 1, LOWEST));
- std::unique_ptr<SpdySerializedFrame> wrapped_req1(
+ SpdySerializedFrame wrapped_req1(
spdy_util_.ConstructWrappedSpdyFrame(req1, 1));
// SPDY GET for HTTP URL (through the proxy, but not the tunnel).
SpdyHeaderBlock req2_block;
- spdy_util_.MaybeAddVersionHeader(&req2_block);
req2_block[spdy_util_.GetMethodKey()] = "GET";
req2_block[spdy_util_.GetHostKey()] = "www.example.org:8080";
req2_block[spdy_util_.GetSchemeKey()] = "http";
req2_block[spdy_util_.GetPathKey()] = "/";
- std::unique_ptr<SpdySerializedFrame> req2(
- spdy_util_.ConstructSpdySyn(3, std::move(req2_block), MEDIUM, true));
+ SpdySerializedFrame req2(
+ spdy_util_.ConstructSpdyHeaders(3, std::move(req2_block), MEDIUM, true));
MockWrite writes1[] = {
- CreateMockWrite(*connect, 0), CreateMockWrite(*wrapped_req1, 2),
- CreateMockWrite(*req2, 6),
+ CreateMockWrite(connect, 0), CreateMockWrite(wrapped_req1, 2),
+ CreateMockWrite(req2, 6),
};
- std::unique_ptr<SpdySerializedFrame> conn_resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_wrapped.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body1(
- spdy_util_wrapped.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> wrapped_resp1(
+ SpdySerializedFrame conn_resp(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame resp1(
+ spdy_util_wrapped.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame body1(spdy_util_wrapped.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame wrapped_resp1(
spdy_util_wrapped.ConstructWrappedSpdyFrame(resp1, 1));
- std::unique_ptr<SpdySerializedFrame> wrapped_body1(
+ SpdySerializedFrame wrapped_body1(
spdy_util_wrapped.ConstructWrappedSpdyFrame(body1, 1));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
MockRead reads1[] = {
- CreateMockRead(*conn_resp, 1),
+ CreateMockRead(conn_resp, 1),
MockRead(ASYNC, ERR_IO_PENDING, 3),
- CreateMockRead(*wrapped_resp1, 4),
- CreateMockRead(*wrapped_body1, 5),
+ CreateMockRead(wrapped_resp1, 4),
+ CreateMockRead(wrapped_body1, 5),
MockRead(ASYNC, ERR_IO_PENDING, 7),
- CreateMockRead(*resp2, 8),
- CreateMockRead(*body2, 9),
+ CreateMockRead(resp2, 8),
+ CreateMockRead(body2, 9),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 10),
};
@@ -13739,10 +14104,10 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttpOverTunnel) {
TestNetLog log;
session_deps_.net_log = &log;
SSLSocketDataProvider ssl1(ASYNC, OK); // to the proxy
- ssl1.SetNextProto(GetProtocol());
+ ssl1.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
SSLSocketDataProvider ssl2(ASYNC, OK); // to the server
- ssl2.SetNextProto(GetProtocol());
+ ssl2.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
session_deps_.socket_factory->AddSocketDataProvider(&data1);
@@ -13755,13 +14120,13 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttpOverTunnel) {
request1.load_flags = 0;
HttpNetworkTransaction trans1(LOWEST, session.get());
TestCompletionCallback callback1;
- int rv = trans1.Start(&request1, callback1.callback(), BoundNetLog());
+ int rv = trans1.Start(&request1, callback1.callback(), NetLogWithSource());
// This pause is a hack to avoid running into https://crbug.com/497228.
data1.RunUntilPaused();
base::RunLoop().RunUntilIdle();
data1.Resume();
- EXPECT_EQ(OK, callback1.GetResult(rv));
+ EXPECT_THAT(callback1.GetResult(rv), IsOk());
EXPECT_TRUE(trans1.GetResponseInfo()->was_fetched_via_spdy);
LoadTimingInfo load_timing_info1;
@@ -13776,13 +14141,13 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttpOverTunnel) {
request2.load_flags = 0;
HttpNetworkTransaction trans2(MEDIUM, session.get());
TestCompletionCallback callback2;
- rv = trans2.Start(&request2, callback2.callback(), BoundNetLog());
+ rv = trans2.Start(&request2, callback2.callback(), NetLogWithSource());
// This pause is a hack to avoid running into https://crbug.com/497228.
data1.RunUntilPaused();
base::RunLoop().RunUntilIdle();
data1.Resume();
- EXPECT_EQ(OK, callback2.GetResult(rv));
+ EXPECT_THAT(callback2.GetResult(rv), IsOk());
EXPECT_TRUE(trans2.GetResponseInfo()->was_fetched_via_spdy);
@@ -13799,31 +14164,29 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttpOverTunnel) {
// that we do not pool other origins that resolve to the same IP when
// the certificate does not match the new origin.
// http://crbug.com/134690
-TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionIfCertDoesNotMatch) {
+TEST_F(HttpNetworkTransactionTest, DoNotUseSpdySessionIfCertDoesNotMatch) {
const std::string url1 = "http://www.example.org/";
const std::string url2 = "https://news.example.org/";
const std::string ip_addr = "1.2.3.4";
// Second SpdyTestUtil instance for the second socket.
- SpdyTestUtil spdy_util_secure(GetProtocol(), GetDependenciesFromPriority());
+ SpdyTestUtil spdy_util_secure;
// SPDY GET for HTTP URL (through SPDY proxy)
SpdyHeaderBlock headers(
spdy_util_.ConstructGetHeaderBlockForProxy("http://www.example.org/"));
- std::unique_ptr<SpdySerializedFrame> req1(
- spdy_util_.ConstructSpdySyn(1, std::move(headers), LOWEST, true));
+ SpdySerializedFrame req1(
+ spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
MockWrite writes1[] = {
- CreateMockWrite(*req1, 0),
+ CreateMockWrite(req1, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body1(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads1[] = {
- MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(*resp1, 2),
- CreateMockRead(*body1, 3), MockRead(ASYNC, OK, 4), // EOF
+ MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(resp1, 2),
+ CreateMockRead(body1, 3), MockRead(ASYNC, OK, 4), // EOF
};
SequencedSocketData data1(reads1, arraysize(reads1), writes1,
@@ -13835,18 +14198,16 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionIfCertDoesNotMatch) {
data1.set_connect_data(connect_data1);
// SPDY GET for HTTPS URL (direct)
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_secure.ConstructSpdyGet(url2.c_str(), 1, MEDIUM));
MockWrite writes2[] = {
- CreateMockWrite(*req2, 0),
+ CreateMockWrite(req2, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_secure.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_secure.ConstructSpdyBodyFrame(1, true));
- MockRead reads2[] = {CreateMockRead(*resp2, 1), CreateMockRead(*body2, 2),
+ SpdySerializedFrame resp2(spdy_util_secure.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body2(spdy_util_secure.ConstructSpdyDataFrame(1, true));
+ MockRead reads2[] = {CreateMockRead(resp2, 1), CreateMockRead(body2, 2),
MockRead(ASYNC, OK, 3)};
SequencedSocketData data2(reads2, arraysize(reads2), writes2,
@@ -13863,7 +14224,7 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionIfCertDoesNotMatch) {
NULL));
SSLSocketDataProvider ssl1(ASYNC, OK); // to the proxy
- ssl1.SetNextProto(GetProtocol());
+ ssl1.next_proto = kProtoHTTP2;
// Load a valid cert. Note, that this does not need to
// be valid for proxy because the MockSSLClientSocket does
// not actually verify it. But SpdySession will use this
@@ -13874,7 +14235,7 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionIfCertDoesNotMatch) {
session_deps_.socket_factory->AddSocketDataProvider(&data1);
SSLSocketDataProvider ssl2(ASYNC, OK); // to the server
- ssl2.SetNextProto(GetProtocol());
+ ssl2.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
session_deps_.socket_factory->AddSocketDataProvider(&data2);
@@ -13892,13 +14253,13 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionIfCertDoesNotMatch) {
HttpNetworkTransaction trans1(LOWEST, session.get());
TestCompletionCallback callback1;
ASSERT_EQ(ERR_IO_PENDING,
- trans1.Start(&request1, callback1.callback(), BoundNetLog()));
+ trans1.Start(&request1, callback1.callback(), NetLogWithSource()));
// This pause is a hack to avoid running into https://crbug.com/497228.
data1.RunUntilPaused();
base::RunLoop().RunUntilIdle();
data1.Resume();
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_TRUE(trans1.GetResponseInfo()->was_fetched_via_spdy);
// Now, start the HTTP request
@@ -13909,11 +14270,11 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionIfCertDoesNotMatch) {
HttpNetworkTransaction trans2(MEDIUM, session.get());
TestCompletionCallback callback2;
EXPECT_EQ(ERR_IO_PENDING,
- trans2.Start(&request2, callback2.callback(), BoundNetLog()));
+ trans2.Start(&request2, callback2.callback(), NetLogWithSource()));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(callback2.have_result());
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_TRUE(trans2.GetResponseInfo()->was_fetched_via_spdy);
}
@@ -13921,7 +14282,7 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionIfCertDoesNotMatch) {
// error) in SPDY session, removes the socket from pool and closes the SPDY
// session. Verify that new url's from the same HttpNetworkSession (and a new
// SpdySession) do work. http://crbug.com/224701
-TEST_P(HttpNetworkTransactionTest, ErrorSocketNotConnected) {
+TEST_F(HttpNetworkTransactionTest, ErrorSocketNotConnected) {
const std::string https_url = "https://www.example.org/";
MockRead reads1[] = {
@@ -13930,32 +14291,29 @@ TEST_P(HttpNetworkTransactionTest, ErrorSocketNotConnected) {
SequencedSocketData data1(reads1, arraysize(reads1), NULL, 0);
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(https_url.c_str(), 1, MEDIUM));
MockWrite writes2[] = {
- CreateMockWrite(*req2, 0),
+ CreateMockWrite(req2, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads2[] = {
- CreateMockRead(*resp2, 1),
- CreateMockRead(*body2, 2),
- MockRead(ASYNC, OK, 3) // EOF
+ CreateMockRead(resp2, 1), CreateMockRead(body2, 2),
+ MockRead(ASYNC, OK, 3) // EOF
};
SequencedSocketData data2(reads2, arraysize(reads2), writes2,
arraysize(writes2));
SSLSocketDataProvider ssl1(ASYNC, OK);
- ssl1.SetNextProto(GetProtocol());
+ ssl1.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
session_deps_.socket_factory->AddSocketDataProvider(&data1);
SSLSocketDataProvider ssl2(ASYNC, OK);
- ssl2.SetNextProto(GetProtocol());
+ ssl2.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
session_deps_.socket_factory->AddSocketDataProvider(&data2);
@@ -13971,8 +14329,8 @@ TEST_P(HttpNetworkTransactionTest, ErrorSocketNotConnected) {
HttpNetworkTransaction trans1(MEDIUM, session.get());
TestCompletionCallback callback1;
EXPECT_EQ(ERR_IO_PENDING,
- trans1.Start(&request1, callback1.callback(), BoundNetLog()));
- EXPECT_EQ(ERR_CONNECTION_CLOSED, callback1.WaitForResult());
+ trans1.Start(&request1, callback1.callback(), NetLogWithSource()));
+ EXPECT_THAT(callback1.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
// Now, start the second request and make sure it succeeds.
HttpRequestInfo request2;
@@ -13982,13 +14340,13 @@ TEST_P(HttpNetworkTransactionTest, ErrorSocketNotConnected) {
HttpNetworkTransaction trans2(MEDIUM, session.get());
TestCompletionCallback callback2;
EXPECT_EQ(ERR_IO_PENDING,
- trans2.Start(&request2, callback2.callback(), BoundNetLog()));
+ trans2.Start(&request2, callback2.callback(), NetLogWithSource()));
- ASSERT_EQ(OK, callback2.WaitForResult());
+ ASSERT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_TRUE(trans2.GetResponseInfo()->was_fetched_via_spdy);
}
-TEST_P(HttpNetworkTransactionTest, CloseIdleSpdySessionToOpenNewOne) {
+TEST_F(HttpNetworkTransactionTest, CloseIdleSpdySessionToOpenNewOne) {
ClientSocketPoolManager::set_max_sockets_per_group(
HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
ClientSocketPoolManager::set_max_sockets_per_pool(
@@ -14000,45 +14358,43 @@ TEST_P(HttpNetworkTransactionTest, CloseIdleSpdySessionToOpenNewOne) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
SSLSocketDataProvider ssl1(ASYNC, OK);
- ssl1.SetNextProto(GetProtocol());
+ ssl1.next_proto = kProtoHTTP2;
SSLSocketDataProvider ssl2(ASYNC, OK);
- ssl2.SetNextProto(GetProtocol());
+ ssl2.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- std::unique_ptr<SpdySerializedFrame> host1_req(
+ SpdySerializedFrame host1_req(
spdy_util_.ConstructSpdyGet("https://www.a.com", 1, DEFAULT_PRIORITY));
MockWrite spdy1_writes[] = {
- CreateMockWrite(*host1_req, 0),
+ CreateMockWrite(host1_req, 0),
};
- std::unique_ptr<SpdySerializedFrame> host1_resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> host1_resp_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame host1_resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame host1_resp_body(
+ spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead spdy1_reads[] = {
- CreateMockRead(*host1_resp, 1), CreateMockRead(*host1_resp_body, 2),
+ CreateMockRead(host1_resp, 1), CreateMockRead(host1_resp_body, 2),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3),
};
// Use a separate test instance for the separate SpdySession that will be
// created.
- SpdyTestUtil spdy_util_2(GetProtocol(), GetDependenciesFromPriority());
+ SpdyTestUtil spdy_util_2;
std::unique_ptr<SequencedSocketData> spdy1_data(
new SequencedSocketData(spdy1_reads, arraysize(spdy1_reads), spdy1_writes,
arraysize(spdy1_writes)));
session_deps_.socket_factory->AddSocketDataProvider(spdy1_data.get());
- std::unique_ptr<SpdySerializedFrame> host2_req(
+ SpdySerializedFrame host2_req(
spdy_util_2.ConstructSpdyGet("https://www.b.com", 1, DEFAULT_PRIORITY));
MockWrite spdy2_writes[] = {
- CreateMockWrite(*host2_req, 0),
+ CreateMockWrite(host2_req, 0),
};
- std::unique_ptr<SpdySerializedFrame> host2_resp(
- spdy_util_2.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> host2_resp_body(
- spdy_util_2.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame host2_resp(spdy_util_2.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame host2_resp_body(
+ spdy_util_2.ConstructSpdyDataFrame(1, true));
MockRead spdy2_reads[] = {
- CreateMockRead(*host2_resp, 1), CreateMockRead(*host2_resp_body, 2),
+ CreateMockRead(host2_resp, 1), CreateMockRead(host2_resp_body, 2),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3),
};
@@ -14077,19 +14433,19 @@ TEST_P(HttpNetworkTransactionTest, CloseIdleSpdySessionToOpenNewOne) {
std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans->Start(&request1, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ int rv = trans->Start(&request1, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
+ EXPECT_TRUE(response->was_alpn_negotiated);
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
trans.reset();
EXPECT_TRUE(
@@ -14106,17 +14462,17 @@ TEST_P(HttpNetworkTransactionTest, CloseIdleSpdySessionToOpenNewOne) {
request2.load_flags = 0;
trans.reset(new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- rv = trans->Start(&request2, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ rv = trans->Start(&request2, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
response = trans->GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ EXPECT_TRUE(response->was_alpn_negotiated);
+ ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
EXPECT_FALSE(
HasSpdySession(session->spdy_session_pool(), spdy_session_key_a));
@@ -14134,17 +14490,17 @@ TEST_P(HttpNetworkTransactionTest, CloseIdleSpdySessionToOpenNewOne) {
request3.load_flags = 0;
trans.reset(new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- rv = trans->Start(&request3, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ rv = trans->Start(&request3, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
response = trans->GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_FALSE(response->was_npn_negotiated);
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ EXPECT_FALSE(response->was_alpn_negotiated);
+ ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
EXPECT_FALSE(
HasSpdySession(session->spdy_session_pool(), spdy_session_key_a));
@@ -14152,15 +14508,14 @@ TEST_P(HttpNetworkTransactionTest, CloseIdleSpdySessionToOpenNewOne) {
HasSpdySession(session->spdy_session_pool(), spdy_session_key_b));
}
-TEST_P(HttpNetworkTransactionTest, HttpSyncConnectError) {
+TEST_F(HttpNetworkTransactionTest, HttpSyncConnectError) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockConnect mock_connect(SYNCHRONOUS, ERR_NAME_NOT_RESOLVED);
StaticSocketDataProvider data;
@@ -14169,35 +14524,34 @@ TEST_P(HttpNetworkTransactionTest, HttpSyncConnectError) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
+ EXPECT_THAT(rv, IsError(ERR_NAME_NOT_RESOLVED));
// We don't care whether this succeeds or fails, but it shouldn't crash.
HttpRequestHeaders request_headers;
- trans->GetFullRequestHeaders(&request_headers);
+ trans.GetFullRequestHeaders(&request_headers);
ConnectionAttempts attempts;
- trans->GetConnectionAttempts(&attempts);
+ trans.GetConnectionAttempts(&attempts);
ASSERT_EQ(1u, attempts.size());
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, attempts[0].result);
+ EXPECT_THAT(attempts[0].result, IsError(ERR_NAME_NOT_RESOLVED));
IPEndPoint endpoint;
- EXPECT_FALSE(trans->GetRemoteEndpoint(&endpoint));
+ EXPECT_FALSE(trans.GetRemoteEndpoint(&endpoint));
EXPECT_TRUE(endpoint.address().empty());
}
-TEST_P(HttpNetworkTransactionTest, HttpAsyncConnectError) {
+TEST_F(HttpNetworkTransactionTest, HttpAsyncConnectError) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockConnect mock_connect(ASYNC, ERR_NAME_NOT_RESOLVED);
StaticSocketDataProvider data;
@@ -14206,35 +14560,34 @@ TEST_P(HttpNetworkTransactionTest, HttpAsyncConnectError) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
+ EXPECT_THAT(rv, IsError(ERR_NAME_NOT_RESOLVED));
// We don't care whether this succeeds or fails, but it shouldn't crash.
HttpRequestHeaders request_headers;
- trans->GetFullRequestHeaders(&request_headers);
+ trans.GetFullRequestHeaders(&request_headers);
ConnectionAttempts attempts;
- trans->GetConnectionAttempts(&attempts);
+ trans.GetConnectionAttempts(&attempts);
ASSERT_EQ(1u, attempts.size());
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, attempts[0].result);
+ EXPECT_THAT(attempts[0].result, IsError(ERR_NAME_NOT_RESOLVED));
IPEndPoint endpoint;
- EXPECT_FALSE(trans->GetRemoteEndpoint(&endpoint));
+ EXPECT_FALSE(trans.GetRemoteEndpoint(&endpoint));
EXPECT_TRUE(endpoint.address().empty());
}
-TEST_P(HttpNetworkTransactionTest, HttpSyncWriteError) {
+TEST_F(HttpNetworkTransactionTest, HttpSyncWriteError) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
@@ -14249,26 +14602,25 @@ TEST_P(HttpNetworkTransactionTest, HttpSyncWriteError) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
HttpRequestHeaders request_headers;
- EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers));
+ EXPECT_TRUE(trans.GetFullRequestHeaders(&request_headers));
EXPECT_TRUE(request_headers.HasHeader("Host"));
}
-TEST_P(HttpNetworkTransactionTest, HttpAsyncWriteError) {
+TEST_F(HttpNetworkTransactionTest, HttpAsyncWriteError) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite(ASYNC, ERR_CONNECTION_RESET),
@@ -14283,26 +14635,25 @@ TEST_P(HttpNetworkTransactionTest, HttpAsyncWriteError) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
HttpRequestHeaders request_headers;
- EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers));
+ EXPECT_TRUE(trans.GetFullRequestHeaders(&request_headers));
EXPECT_TRUE(request_headers.HasHeader("Host"));
}
-TEST_P(HttpNetworkTransactionTest, HttpSyncReadError) {
+TEST_F(HttpNetworkTransactionTest, HttpSyncReadError) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite(
@@ -14320,26 +14671,25 @@ TEST_P(HttpNetworkTransactionTest, HttpSyncReadError) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
HttpRequestHeaders request_headers;
- EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers));
+ EXPECT_TRUE(trans.GetFullRequestHeaders(&request_headers));
EXPECT_TRUE(request_headers.HasHeader("Host"));
}
-TEST_P(HttpNetworkTransactionTest, HttpAsyncReadError) {
+TEST_F(HttpNetworkTransactionTest, HttpAsyncReadError) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite(
@@ -14357,18 +14707,18 @@ TEST_P(HttpNetworkTransactionTest, HttpAsyncReadError) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
HttpRequestHeaders request_headers;
- EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers));
+ EXPECT_TRUE(trans.GetFullRequestHeaders(&request_headers));
EXPECT_TRUE(request_headers.HasHeader("Host"));
}
-TEST_P(HttpNetworkTransactionTest, GetFullRequestHeadersIncludesExtraHeader) {
+TEST_F(HttpNetworkTransactionTest, GetFullRequestHeadersIncludesExtraHeader) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.example.org/");
@@ -14376,8 +14726,7 @@ TEST_P(HttpNetworkTransactionTest, GetFullRequestHeadersIncludesExtraHeader) {
request.extra_headers.SetHeader("X-Foo", "bar");
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite(
@@ -14399,14 +14748,14 @@ TEST_P(HttpNetworkTransactionTest, GetFullRequestHeadersIncludesExtraHeader) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
HttpRequestHeaders request_headers;
- EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers));
+ EXPECT_TRUE(trans.GetFullRequestHeaders(&request_headers));
std::string foo;
EXPECT_TRUE(request_headers.GetHeader("X-Foo", &foo));
EXPECT_EQ("bar", foo);
@@ -14425,7 +14774,7 @@ class FakeStream : public HttpStream,
int InitializeStream(const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback) override {
return ERR_IO_PENDING;
}
@@ -14488,8 +14837,9 @@ class FakeStream : public HttpStream,
bool GetRemoteEndpoint(IPEndPoint* endpoint) override { return false; }
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) override {
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) override {
ADD_FAILURE();
return ERR_NOT_IMPLEMENTED;
}
@@ -14500,8 +14850,6 @@ class FakeStream : public HttpStream,
void SetPriority(RequestPriority priority) override { priority_ = priority; }
- UploadProgress GetUploadProgress() const override { return UploadProgress(); }
-
HttpStream* RenewStreamForAuth() override { return NULL; }
private:
@@ -14560,9 +14908,9 @@ class FakeStreamRequest : public HttpStreamRequest,
void SetPriority(RequestPriority priority) override { priority_ = priority; }
- bool was_npn_negotiated() const override { return false; }
+ bool was_alpn_negotiated() const override { return false; }
- NextProto protocol_negotiated() const override { return kProtoUnknown; }
+ NextProto negotiated_protocol() const override { return kProtoUnknown; }
bool using_spdy() const override { return false; }
@@ -14596,7 +14944,7 @@ class FakeStreamFactory : public HttpStreamFactory {
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::Delegate* delegate,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
FakeStreamRequest* fake_request = new FakeStreamRequest(priority, delegate);
last_stream_request_ = fake_request->AsWeakPtr();
return fake_request;
@@ -14608,7 +14956,7 @@ class FakeStreamFactory : public HttpStreamFactory {
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::Delegate* delegate,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
NOTREACHED();
return nullptr;
}
@@ -14620,7 +14968,7 @@ class FakeStreamFactory : public HttpStreamFactory {
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::Delegate* delegate,
WebSocketHandshakeStreamBase::CreateHelper* create_helper,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
FakeStreamRequest* fake_request =
new FakeStreamRequest(priority, delegate, create_helper);
last_stream_request_ = fake_request->AsWeakPtr();
@@ -14650,7 +14998,7 @@ class FakeWebSocketBasicHandshakeStream : public WebSocketHandshakeStreamBase {
FakeWebSocketBasicHandshakeStream(
std::unique_ptr<ClientSocketHandle> connection,
bool using_proxy)
- : state_(connection.release(), using_proxy) {}
+ : state_(std::move(connection), using_proxy, false) {}
// Fake implementation of HttpStreamBase methods.
// This ends up being quite "real" because this object has to really send data
@@ -14659,7 +15007,7 @@ class FakeWebSocketBasicHandshakeStream : public WebSocketHandshakeStreamBase {
// difficult.
int InitializeStream(const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback) override {
state_.Initialize(request_info, priority, net_log, callback);
return OK;
@@ -14724,8 +15072,9 @@ class FakeWebSocketBasicHandshakeStream : public WebSocketHandshakeStreamBase {
bool GetRemoteEndpoint(IPEndPoint* endpoint) override { return false; }
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) override {
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) override {
ADD_FAILURE();
return ERR_NOT_IMPLEMENTED;
}
@@ -14736,11 +15085,6 @@ class FakeWebSocketBasicHandshakeStream : public WebSocketHandshakeStreamBase {
void SetPriority(RequestPriority priority) override { NOTREACHED(); }
- UploadProgress GetUploadProgress() const override {
- NOTREACHED();
- return UploadProgress();
- }
-
HttpStream* RenewStreamForAuth() override {
NOTREACHED();
return nullptr;
@@ -14790,7 +15134,7 @@ class FakeWebSocketStreamCreateHelper :
// Make sure that HttpNetworkTransaction passes on its priority to its
// stream request on start.
-TEST_P(HttpNetworkTransactionTest, SetStreamRequestPriorityOnStart) {
+TEST_F(HttpNetworkTransactionTest, SetStreamRequestPriorityOnStart) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
HttpNetworkSessionPeer peer(session.get());
FakeStreamFactory* fake_factory = new FakeStreamFactory();
@@ -14803,7 +15147,7 @@ TEST_P(HttpNetworkTransactionTest, SetStreamRequestPriorityOnStart) {
HttpRequestInfo request;
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
- trans.Start(&request, callback.callback(), BoundNetLog()));
+ trans.Start(&request, callback.callback(), NetLogWithSource()));
base::WeakPtr<FakeStreamRequest> fake_request =
fake_factory->last_stream_request();
@@ -14813,7 +15157,7 @@ TEST_P(HttpNetworkTransactionTest, SetStreamRequestPriorityOnStart) {
// Make sure that HttpNetworkTransaction passes on its priority
// updates to its stream request.
-TEST_P(HttpNetworkTransactionTest, SetStreamRequestPriority) {
+TEST_F(HttpNetworkTransactionTest, SetStreamRequestPriority) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
HttpNetworkSessionPeer peer(session.get());
FakeStreamFactory* fake_factory = new FakeStreamFactory();
@@ -14824,7 +15168,7 @@ TEST_P(HttpNetworkTransactionTest, SetStreamRequestPriority) {
HttpRequestInfo request;
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
- trans.Start(&request, callback.callback(), BoundNetLog()));
+ trans.Start(&request, callback.callback(), NetLogWithSource()));
base::WeakPtr<FakeStreamRequest> fake_request =
fake_factory->last_stream_request();
@@ -14838,7 +15182,7 @@ TEST_P(HttpNetworkTransactionTest, SetStreamRequestPriority) {
// Make sure that HttpNetworkTransaction passes on its priority
// updates to its stream.
-TEST_P(HttpNetworkTransactionTest, SetStreamPriority) {
+TEST_F(HttpNetworkTransactionTest, SetStreamPriority) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
HttpNetworkSessionPeer peer(session.get());
FakeStreamFactory* fake_factory = new FakeStreamFactory();
@@ -14849,7 +15193,7 @@ TEST_P(HttpNetworkTransactionTest, SetStreamPriority) {
HttpRequestInfo request;
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
- trans.Start(&request, callback.callback(), BoundNetLog()));
+ trans.Start(&request, callback.callback(), NetLogWithSource()));
base::WeakPtr<FakeStreamRequest> fake_request =
fake_factory->last_stream_request();
@@ -14862,7 +15206,7 @@ TEST_P(HttpNetworkTransactionTest, SetStreamPriority) {
EXPECT_EQ(LOWEST, fake_stream->priority());
}
-TEST_P(HttpNetworkTransactionTest, CreateWebSocketHandshakeStream) {
+TEST_F(HttpNetworkTransactionTest, CreateWebSocketHandshakeStream) {
// The same logic needs to be tested for both ws: and wss: schemes, but this
// test is already parameterised on NextProto, so it uses a loop to verify
// that the different schemes work.
@@ -14886,7 +15230,7 @@ TEST_P(HttpNetworkTransactionTest, CreateWebSocketHandshakeStream) {
request.url = GURL(test_cases[i]);
EXPECT_EQ(ERR_IO_PENDING,
- trans.Start(&request, callback.callback(), BoundNetLog()));
+ trans.Start(&request, callback.callback(), NetLogWithSource()));
base::WeakPtr<FakeStreamRequest> fake_request =
fake_factory->last_stream_request();
@@ -14898,7 +15242,7 @@ TEST_P(HttpNetworkTransactionTest, CreateWebSocketHandshakeStream) {
// Tests that when a used socket is returned to the SSL socket pool, it's closed
// if the transport socket pool is stalled on the global socket limit.
-TEST_P(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest) {
+TEST_F(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest) {
ClientSocketPoolManager::set_max_sockets_per_group(
HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
ClientSocketPoolManager::set_max_sockets_per_pool(
@@ -14955,25 +15299,23 @@ TEST_P(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest) {
// Start the SSL request.
TestCompletionCallback ssl_callback;
- std::unique_ptr<HttpTransaction> ssl_trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction ssl_trans(DEFAULT_PRIORITY, session.get());
ASSERT_EQ(ERR_IO_PENDING,
- ssl_trans->Start(&ssl_request, ssl_callback.callback(),
- BoundNetLog()));
+ ssl_trans.Start(&ssl_request, ssl_callback.callback(),
+ NetLogWithSource()));
// Start the HTTP request. Pool should stall.
TestCompletionCallback http_callback;
- std::unique_ptr<HttpTransaction> http_trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction http_trans(DEFAULT_PRIORITY, session.get());
ASSERT_EQ(ERR_IO_PENDING,
- http_trans->Start(&http_request, http_callback.callback(),
- BoundNetLog()));
+ http_trans.Start(&http_request, http_callback.callback(),
+ NetLogWithSource()));
EXPECT_TRUE(IsTransportSocketPoolStalled(session.get()));
// Wait for response from SSL request.
- ASSERT_EQ(OK, ssl_callback.WaitForResult());
+ ASSERT_THAT(ssl_callback.WaitForResult(), IsOk());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(ssl_trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(&ssl_trans, &response_data), IsOk());
EXPECT_EQ("hello world", response_data);
// The SSL socket should automatically be closed, so the HTTP request can
@@ -14982,8 +15324,8 @@ TEST_P(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest) {
ASSERT_FALSE(IsTransportSocketPoolStalled(session.get()));
// The HTTP request can now complete.
- ASSERT_EQ(OK, http_callback.WaitForResult());
- ASSERT_EQ(OK, ReadTransaction(http_trans.get(), &response_data));
+ ASSERT_THAT(http_callback.WaitForResult(), IsOk());
+ ASSERT_THAT(ReadTransaction(&http_trans, &response_data), IsOk());
EXPECT_EQ("falafel", response_data);
EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
@@ -14992,7 +15334,7 @@ TEST_P(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest) {
// Tests that when a SSL connection is established but there's no corresponding
// request that needs it, the new socket is closed if the transport socket pool
// is stalled on the global socket limit.
-TEST_P(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest2) {
+TEST_F(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest2) {
ClientSocketPoolManager::set_max_sockets_per_group(
HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
ClientSocketPoolManager::set_max_sockets_per_pool(
@@ -15043,27 +15385,26 @@ TEST_P(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest2) {
// Start the HTTP request. Pool should stall.
TestCompletionCallback http_callback;
- std::unique_ptr<HttpTransaction> http_trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction http_trans(DEFAULT_PRIORITY, session.get());
ASSERT_EQ(ERR_IO_PENDING,
- http_trans->Start(&http_request, http_callback.callback(),
- BoundNetLog()));
+ http_trans.Start(&http_request, http_callback.callback(),
+ NetLogWithSource()));
EXPECT_TRUE(IsTransportSocketPoolStalled(session.get()));
// The SSL connection will automatically be closed once the connection is
// established, to let the HTTP request start.
- ASSERT_EQ(OK, http_callback.WaitForResult());
+ ASSERT_THAT(http_callback.WaitForResult(), IsOk());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(http_trans.get(), &response_data));
+ ASSERT_THAT(ReadTransaction(&http_trans, &response_data), IsOk());
EXPECT_EQ("falafel", response_data);
EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
}
-TEST_P(HttpNetworkTransactionTest, PostReadsErrorResponseAfterReset) {
+TEST_F(HttpNetworkTransactionTest, PostReadsErrorResponseAfterReset) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
element_readers.push_back(
- base::WrapUnique(new UploadBytesElementReader("foo", 3)));
+ base::MakeUnique<UploadBytesElementReader>("foo", 3));
ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
HttpRequestInfo request;
@@ -15073,8 +15414,7 @@ TEST_P(HttpNetworkTransactionTest, PostReadsErrorResponseAfterReset) {
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Send headers successfully, but get an error while sending the body.
MockWrite data_writes[] = {
MockWrite("POST / HTTP/1.1\r\n"
@@ -15095,27 +15435,27 @@ TEST_P(HttpNetworkTransactionTest, PostReadsErrorResponseAfterReset) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.0 400 Not OK", response->headers->GetStatusLine());
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("hello world", response_data);
}
// This test makes sure the retry logic doesn't trigger when reading an error
// response from a server that rejected a POST with a CONNECTION_RESET.
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
PostReadsErrorResponseAfterResetOnReusedSocket) {
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
MockWrite data_writes[] = {
@@ -15148,13 +15488,13 @@ TEST_P(HttpNetworkTransactionTest,
request1.url = GURL("http://www.foo.com/");
request1.load_flags = 0;
- std::unique_ptr<HttpTransaction> trans1(
+ std::unique_ptr<HttpNetworkTransaction> trans1(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- int rv = trans1->Start(&request1, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
const HttpResponseInfo* response1 = trans1->GetResponseInfo();
ASSERT_TRUE(response1);
@@ -15164,7 +15504,7 @@ TEST_P(HttpNetworkTransactionTest,
std::string response_data1;
rv = ReadTransaction(trans1.get(), &response_data1);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("first response", response_data1);
// Delete the transaction to release the socket back into the socket pool.
trans1.reset();
@@ -15180,31 +15520,30 @@ TEST_P(HttpNetworkTransactionTest,
request2.upload_data_stream = &upload_data_stream;
request2.load_flags = 0;
- std::unique_ptr<HttpTransaction> trans2(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
- rv = trans2->Start(&request2, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
+ rv = trans2.Start(&request2, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response2 = trans2->GetResponseInfo();
+ const HttpResponseInfo* response2 = trans2.GetResponseInfo();
ASSERT_TRUE(response2);
EXPECT_TRUE(response2->headers);
EXPECT_EQ("HTTP/1.1 400 Not OK", response2->headers->GetStatusLine());
std::string response_data2;
- rv = ReadTransaction(trans2.get(), &response_data2);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans2, &response_data2);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("second response", response_data2);
}
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
PostReadsErrorResponseAfterResetPartialBodySent) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
element_readers.push_back(
- base::WrapUnique(new UploadBytesElementReader("foo", 3)));
+ base::MakeUnique<UploadBytesElementReader>("foo", 3));
ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
HttpRequestInfo request;
@@ -15214,8 +15553,7 @@ TEST_P(HttpNetworkTransactionTest,
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Send headers successfully, but get an error while sending the body.
MockWrite data_writes[] = {
MockWrite("POST / HTTP/1.1\r\n"
@@ -15237,27 +15575,27 @@ TEST_P(HttpNetworkTransactionTest,
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.0 400 Not OK", response->headers->GetStatusLine());
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("hello world", response_data);
}
// This tests the more common case than the previous test, where headers and
// body are not merged into a single request.
-TEST_P(HttpNetworkTransactionTest, ChunkedPostReadsErrorResponseAfterReset) {
+TEST_F(HttpNetworkTransactionTest, ChunkedPostReadsErrorResponseAfterReset) {
ChunkedUploadDataStream upload_data_stream(0);
HttpRequestInfo request;
@@ -15267,8 +15605,7 @@ TEST_P(HttpNetworkTransactionTest, ChunkedPostReadsErrorResponseAfterReset) {
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Send headers successfully, but get an error while sending the body.
MockWrite data_writes[] = {
MockWrite("POST / HTTP/1.1\r\n"
@@ -15289,8 +15626,8 @@ TEST_P(HttpNetworkTransactionTest, ChunkedPostReadsErrorResponseAfterReset) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Make sure the headers are sent before adding a chunk. This ensures that
// they can't be merged with the body in a single send. Not currently
// necessary since a chunked body is never merged with headers, but this makes
@@ -15300,24 +15637,24 @@ TEST_P(HttpNetworkTransactionTest, ChunkedPostReadsErrorResponseAfterReset) {
upload_data_stream.AppendData("last chunk", 10, true);
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.0 400 Not OK", response->headers->GetStatusLine());
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("hello world", response_data);
}
-TEST_P(HttpNetworkTransactionTest, PostReadsErrorResponseAfterResetAnd100) {
+TEST_F(HttpNetworkTransactionTest, PostReadsErrorResponseAfterResetAnd100) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
element_readers.push_back(
- base::WrapUnique(new UploadBytesElementReader("foo", 3)));
+ base::MakeUnique<UploadBytesElementReader>("foo", 3));
ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
HttpRequestInfo request;
@@ -15327,8 +15664,7 @@ TEST_P(HttpNetworkTransactionTest, PostReadsErrorResponseAfterResetAnd100) {
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite("POST / HTTP/1.1\r\n"
@@ -15350,28 +15686,28 @@ TEST_P(HttpNetworkTransactionTest, PostReadsErrorResponseAfterResetAnd100) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers);
EXPECT_EQ("HTTP/1.0 400 Not OK", response->headers->GetStatusLine());
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("hello world", response_data);
}
-TEST_P(HttpNetworkTransactionTest, PostIgnoresNonErrorResponseAfterReset) {
+TEST_F(HttpNetworkTransactionTest, PostIgnoresNonErrorResponseAfterReset) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
element_readers.push_back(
- base::WrapUnique(new UploadBytesElementReader("foo", 3)));
+ base::MakeUnique<UploadBytesElementReader>("foo", 3));
ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
HttpRequestInfo request;
@@ -15381,8 +15717,7 @@ TEST_P(HttpNetworkTransactionTest, PostIgnoresNonErrorResponseAfterReset) {
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Send headers successfully, but get an error while sending the body.
MockWrite data_writes[] = {
MockWrite("POST / HTTP/1.1\r\n"
@@ -15403,18 +15738,18 @@ TEST_P(HttpNetworkTransactionTest, PostIgnoresNonErrorResponseAfterReset) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
}
-TEST_P(HttpNetworkTransactionTest,
+TEST_F(HttpNetworkTransactionTest,
PostIgnoresNonErrorResponseAfterResetAnd100) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
element_readers.push_back(
- base::WrapUnique(new UploadBytesElementReader("foo", 3)));
+ base::MakeUnique<UploadBytesElementReader>("foo", 3));
ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
HttpRequestInfo request;
@@ -15424,8 +15759,7 @@ TEST_P(HttpNetworkTransactionTest,
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Send headers successfully, but get an error while sending the body.
MockWrite data_writes[] = {
MockWrite("POST / HTTP/1.1\r\n"
@@ -15448,17 +15782,17 @@ TEST_P(HttpNetworkTransactionTest,
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
}
-TEST_P(HttpNetworkTransactionTest, PostIgnoresHttp09ResponseAfterReset) {
+TEST_F(HttpNetworkTransactionTest, PostIgnoresHttp09ResponseAfterReset) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
element_readers.push_back(
- base::WrapUnique(new UploadBytesElementReader("foo", 3)));
+ base::MakeUnique<UploadBytesElementReader>("foo", 3));
ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
HttpRequestInfo request;
@@ -15468,8 +15802,7 @@ TEST_P(HttpNetworkTransactionTest, PostIgnoresHttp09ResponseAfterReset) {
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Send headers successfully, but get an error while sending the body.
MockWrite data_writes[] = {
MockWrite("POST / HTTP/1.1\r\n"
@@ -15489,17 +15822,17 @@ TEST_P(HttpNetworkTransactionTest, PostIgnoresHttp09ResponseAfterReset) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
}
-TEST_P(HttpNetworkTransactionTest, PostIgnoresPartial400HeadersAfterReset) {
+TEST_F(HttpNetworkTransactionTest, PostIgnoresPartial400HeadersAfterReset) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
element_readers.push_back(
- base::WrapUnique(new UploadBytesElementReader("foo", 3)));
+ base::MakeUnique<UploadBytesElementReader>("foo", 3));
ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
HttpRequestInfo request;
@@ -15509,8 +15842,7 @@ TEST_P(HttpNetworkTransactionTest, PostIgnoresPartial400HeadersAfterReset) {
request.load_flags = 0;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Send headers successfully, but get an error while sending the body.
MockWrite data_writes[] = {
MockWrite("POST / HTTP/1.1\r\n"
@@ -15530,16 +15862,16 @@ TEST_P(HttpNetworkTransactionTest, PostIgnoresPartial400HeadersAfterReset) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
}
// Verify that proxy headers are not sent to the destination server when
// establishing a tunnel for a secure WebSocket connection.
-TEST_P(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWssTunnel) {
+TEST_F(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWssTunnel) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("wss://www.example.org/");
@@ -15596,7 +15928,7 @@ TEST_P(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWssTunnel) {
SSLSocketDataProvider ssl(ASYNC, OK);
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
FakeWebSocketStreamCreateHelper websocket_stream_create_helper;
trans->SetWebSocketHandshakeStreamCreateHelper(
@@ -15605,11 +15937,11 @@ TEST_P(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWssTunnel) {
{
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
const HttpResponseInfo* response = trans->GetResponseInfo();
@@ -15622,10 +15954,10 @@ TEST_P(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWssTunnel) {
int rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar),
callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
response = trans->GetResponseInfo();
@@ -15643,7 +15975,7 @@ TEST_P(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWssTunnel) {
// This requires the authentication info to be injected into the auth cache
// due to crbug.com/395064
// TODO(ricea): Change to use a 407 response once issue 395064 is fixed.
-TEST_P(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWsTunnel) {
+TEST_F(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWsTunnel) {
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("ws://www.example.org/");
@@ -15695,7 +16027,7 @@ TEST_P(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWsTunnel) {
GURL("http://myproxy:70/"), "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC,
"Basic realm=MyRealm1", AuthCredentials(kFoo, kBar), "/");
- std::unique_ptr<HttpTransaction> trans(
+ std::unique_ptr<HttpNetworkTransaction> trans(
new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
FakeWebSocketStreamCreateHelper websocket_stream_create_helper;
trans->SetWebSocketHandshakeStreamCreateHelper(
@@ -15703,11 +16035,11 @@ TEST_P(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWsTunnel) {
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -15719,10 +16051,10 @@ TEST_P(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWsTunnel) {
session->CloseAllConnections();
}
-TEST_P(HttpNetworkTransactionTest, TotalNetworkBytesPost) {
+TEST_F(HttpNetworkTransactionTest, TotalNetworkBytesPost) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
element_readers.push_back(
- base::WrapUnique(new UploadBytesElementReader("foo", 3)));
+ base::MakeUnique<UploadBytesElementReader>("foo", 3));
ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
HttpRequestInfo request;
@@ -15731,8 +16063,7 @@ TEST_P(HttpNetworkTransactionTest, TotalNetworkBytesPost) {
request.upload_data_stream = &upload_data_stream;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite("POST / HTTP/1.1\r\n"
"Host: www.foo.com\r\n"
@@ -15752,22 +16083,22 @@ TEST_P(HttpNetworkTransactionTest, TotalNetworkBytesPost) {
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
- trans->Start(&request, callback.callback(), BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
+ trans.Start(&request, callback.callback(), NetLogWithSource()));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
std::string response_data;
- EXPECT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ EXPECT_THAT(ReadTransaction(&trans, &response_data), IsOk());
EXPECT_EQ(CountWriteBytes(data_writes, arraysize(data_writes)),
- trans->GetTotalSentBytes());
+ trans.GetTotalSentBytes());
EXPECT_EQ(CountReadBytes(data_reads, arraysize(data_reads)),
- trans->GetTotalReceivedBytes());
+ trans.GetTotalReceivedBytes());
}
-TEST_P(HttpNetworkTransactionTest, TotalNetworkBytesPost100Continue) {
+TEST_F(HttpNetworkTransactionTest, TotalNetworkBytesPost100Continue) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
element_readers.push_back(
- base::WrapUnique(new UploadBytesElementReader("foo", 3)));
+ base::MakeUnique<UploadBytesElementReader>("foo", 3));
ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
HttpRequestInfo request;
@@ -15776,8 +16107,7 @@ TEST_P(HttpNetworkTransactionTest, TotalNetworkBytesPost100Continue) {
request.upload_data_stream = &upload_data_stream;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
MockWrite data_writes[] = {
MockWrite("POST / HTTP/1.1\r\n"
"Host: www.foo.com\r\n"
@@ -15798,19 +16128,19 @@ TEST_P(HttpNetworkTransactionTest, TotalNetworkBytesPost100Continue) {
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
- trans->Start(&request, callback.callback(), BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
+ trans.Start(&request, callback.callback(), NetLogWithSource()));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
std::string response_data;
- EXPECT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ EXPECT_THAT(ReadTransaction(&trans, &response_data), IsOk());
EXPECT_EQ(CountWriteBytes(data_writes, arraysize(data_writes)),
- trans->GetTotalSentBytes());
+ trans.GetTotalSentBytes());
EXPECT_EQ(CountReadBytes(data_reads, arraysize(data_reads)),
- trans->GetTotalReceivedBytes());
+ trans.GetTotalReceivedBytes());
}
-TEST_P(HttpNetworkTransactionTest, TotalNetworkBytesChunkedPost) {
+TEST_F(HttpNetworkTransactionTest, TotalNetworkBytesChunkedPost) {
ChunkedUploadDataStream upload_data_stream(0);
HttpRequestInfo request;
@@ -15819,8 +16149,7 @@ TEST_P(HttpNetworkTransactionTest, TotalNetworkBytesChunkedPost) {
request.upload_data_stream = &upload_data_stream;
std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
// Send headers successfully, but get an error while sending the body.
MockWrite data_writes[] = {
MockWrite("POST / HTTP/1.1\r\n"
@@ -15841,7 +16170,7 @@ TEST_P(HttpNetworkTransactionTest, TotalNetworkBytesChunkedPost) {
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
- trans->Start(&request, callback.callback(), BoundNetLog()));
+ trans.Start(&request, callback.callback(), NetLogWithSource()));
base::RunLoop().RunUntilIdle();
upload_data_stream.AppendData("f", 1, false);
@@ -15849,50 +16178,19 @@ TEST_P(HttpNetworkTransactionTest, TotalNetworkBytesChunkedPost) {
base::RunLoop().RunUntilIdle();
upload_data_stream.AppendData("oo", 2, true);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
std::string response_data;
- EXPECT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ EXPECT_THAT(ReadTransaction(&trans, &response_data), IsOk());
EXPECT_EQ(CountWriteBytes(data_writes, arraysize(data_writes)),
- trans->GetTotalSentBytes());
+ trans.GetTotalSentBytes());
EXPECT_EQ(CountReadBytes(data_reads, arraysize(data_reads)),
- trans->GetTotalReceivedBytes());
-}
-
-TEST_P(HttpNetworkTransactionTest, EnableNPN) {
- session_deps_.enable_npn = true;
-
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- HttpRequestInfo request;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- trans.Start(&request, callback.callback(), BoundNetLog()));
-
- EXPECT_THAT(trans.server_ssl_config_.alpn_protos,
- testing::ElementsAre(kProtoHTTP2, kProtoSPDY31, kProtoHTTP11));
- EXPECT_THAT(trans.server_ssl_config_.npn_protos,
- testing::ElementsAre(kProtoHTTP2, kProtoSPDY31, kProtoHTTP11));
-}
-
-TEST_P(HttpNetworkTransactionTest, DisableNPN) {
- session_deps_.enable_npn = false;
-
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- HttpRequestInfo request;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- trans.Start(&request, callback.callback(), BoundNetLog()));
-
- EXPECT_THAT(trans.server_ssl_config_.alpn_protos,
- testing::ElementsAre(kProtoHTTP2, kProtoSPDY31, kProtoHTTP11));
- EXPECT_TRUE(trans.server_ssl_config_.npn_protos.empty());
+ trans.GetTotalReceivedBytes());
}
#if !defined(OS_IOS)
-TEST_P(HttpNetworkTransactionTest, TokenBindingSpdy) {
+TEST_F(HttpNetworkTransactionTest, TokenBindingSpdy) {
const std::string https_url = "https://www.example.com";
HttpRequestInfo request;
request.url = GURL(https_url);
@@ -15901,14 +16199,12 @@ TEST_P(HttpNetworkTransactionTest, TokenBindingSpdy) {
SSLSocketDataProvider ssl(ASYNC, OK);
ssl.token_binding_negotiated = true;
ssl.token_binding_key_param = TB_PARAM_ECDSAP256;
- ssl.SetNextProto(GetProtocol());
+ ssl.next_proto = kProtoHTTP2;
session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- MockRead reads[] = {CreateMockRead(*resp), CreateMockRead(*body),
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
+ MockRead reads[] = {CreateMockRead(resp), CreateMockRead(body),
MockRead(ASYNC, ERR_IO_PENDING)};
StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
@@ -15919,7 +16215,7 @@ TEST_P(HttpNetworkTransactionTest, TokenBindingSpdy) {
HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
- trans.Start(&request, callback.callback(), BoundNetLog()));
+ trans.Start(&request, callback.callback(), NetLogWithSource()));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(trans.GetResponseInfo()->was_fetched_via_spdy);
diff --git a/chromium/net/http/http_proxy_client_socket.cc b/chromium/net/http/http_proxy_client_socket.cc
index 5105a7001ba..82538dff80e 100644
--- a/chromium/net/http/http_proxy_client_socket.cc
+++ b/chromium/net/http/http_proxy_client_socket.cc
@@ -21,6 +21,7 @@
#include "net/http/http_stream_parser.h"
#include "net/http/proxy_connect_redirect_http_stream.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
#include "net/socket/client_socket_handle.h"
#include "url/gurl.h"
@@ -34,7 +35,7 @@ HttpProxyClientSocket::HttpProxyClientSocket(
HttpAuthController* http_auth_controller,
bool tunnel,
bool using_spdy,
- NextProto protocol_negotiated,
+ NextProto negotiated_protocol,
ProxyDelegate* proxy_delegate,
bool is_https_proxy)
: io_callback_(base::Bind(&HttpProxyClientSocket::OnIOComplete,
@@ -45,7 +46,7 @@ HttpProxyClientSocket::HttpProxyClientSocket(
auth_(http_auth_controller),
tunnel_(tunnel),
using_spdy_(using_spdy),
- protocol_negotiated_(protocol_negotiated),
+ negotiated_protocol_(negotiated_protocol),
is_https_proxy_(is_https_proxy),
redirect_has_load_timing_info_(false),
proxy_server_(proxy_server),
@@ -89,8 +90,8 @@ bool HttpProxyClientSocket::IsUsingSpdy() const {
return using_spdy_;
}
-NextProto HttpProxyClientSocket::GetProtocolNegotiated() const {
- return protocol_negotiated_;
+NextProto HttpProxyClientSocket::GetProxyNegotiatedProtocol() const {
+ return negotiated_protocol_;
}
const HttpResponseInfo* HttpProxyClientSocket::GetConnectResponseInfo() const {
@@ -146,7 +147,7 @@ bool HttpProxyClientSocket::IsConnectedAndIdle() const {
transport_->socket()->IsConnectedAndIdle();
}
-const BoundNetLog& HttpProxyClientSocket::NetLog() const {
+const NetLogWithSource& HttpProxyClientSocket::NetLog() const {
return net_log_;
}
@@ -335,24 +336,24 @@ int HttpProxyClientSocket::DoLoop(int last_io_result) {
case STATE_SEND_REQUEST:
DCHECK_EQ(OK, rv);
net_log_.BeginEvent(
- NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST);
+ NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST);
rv = DoSendRequest();
break;
case STATE_SEND_REQUEST_COMPLETE:
rv = DoSendRequestComplete(rv);
net_log_.EndEventWithNetErrorCode(
- NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
+ NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
break;
case STATE_READ_HEADERS:
DCHECK_EQ(OK, rv);
net_log_.BeginEvent(
- NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS);
+ NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS);
rv = DoReadHeaders();
break;
case STATE_READ_HEADERS_COMPLETE:
rv = DoReadHeadersComplete(rv);
net_log_.EndEventWithNetErrorCode(
- NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
+ NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
break;
case STATE_DRAIN_BODY:
DCHECK_EQ(OK, rv);
@@ -408,10 +409,9 @@ int HttpProxyClientSocket::DoSendRequest() {
&request_line_, &request_headers_);
net_log_.AddEvent(
- NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
base::Bind(&HttpRequestHeaders::NetLogCallback,
- base::Unretained(&request_headers_),
- &request_line_));
+ base::Unretained(&request_headers_), &request_line_));
}
parser_buf_ = new GrowableIOBuffer();
@@ -443,7 +443,7 @@ int HttpProxyClientSocket::DoReadHeadersComplete(int result) {
return ERR_TUNNEL_CONNECTION_FAILED;
net_log_.AddEvent(
- NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers));
if (proxy_delegate_) {
@@ -511,7 +511,6 @@ int HttpProxyClientSocket::DoReadHeadersComplete(int result) {
int HttpProxyClientSocket::DoDrainBody() {
DCHECK(drain_buf_.get());
- DCHECK(transport_->is_initialized());
next_state_ = STATE_DRAIN_BODY_COMPLETE;
return http_stream_parser_->ReadResponseBody(
drain_buf_.get(), kDrainBodyBufferSize, io_callback_);
diff --git a/chromium/net/http/http_proxy_client_socket.h b/chromium/net/http/http_proxy_client_socket.h
index 1c433eadd14..e383dd796b7 100644
--- a/chromium/net/http/http_proxy_client_socket.h
+++ b/chromium/net/http/http_proxy_client_socket.h
@@ -20,7 +20,7 @@
#include "net/http/http_request_info.h"
#include "net/http/http_response_info.h"
#include "net/http/proxy_client_socket.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/ssl_client_socket.h"
namespace net {
@@ -45,7 +45,7 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocket : public ProxyClientSocket {
HttpAuthController* http_auth_controller,
bool tunnel,
bool using_spdy,
- NextProto protocol_negotiated,
+ NextProto negotiated_protocol,
ProxyDelegate* proxy_delegate,
bool is_https_proxy);
@@ -58,14 +58,14 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocket : public ProxyClientSocket {
int RestartWithAuth(const CompletionCallback& callback) override;
const scoped_refptr<HttpAuthController>& GetAuthController() const override;
bool IsUsingSpdy() const override;
- NextProto GetProtocolNegotiated() const override;
+ NextProto GetProxyNegotiatedProtocol() const override;
// StreamSocket implementation.
int Connect(const CompletionCallback& callback) override;
void Disconnect() override;
bool IsConnected() const override;
bool IsConnectedAndIdle() const override;
- const BoundNetLog& NetLog() const override;
+ const NetLogWithSource& NetLog() const override;
void SetSubresourceSpeculation() override;
void SetOmniboxSpeculation() override;
bool WasEverUsed() const override;
@@ -150,7 +150,7 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocket : public ProxyClientSocket {
// If true, then the connection to the proxy is a SPDY connection.
const bool using_spdy_;
// Protocol negotiated with the server.
- NextProto protocol_negotiated_;
+ NextProto negotiated_protocol_;
// If true, then SSL is used to communicate with this proxy
const bool is_https_proxy_;
@@ -166,7 +166,7 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocket : public ProxyClientSocket {
// This delegate must outlive this proxy client socket.
ProxyDelegate* proxy_delegate_;
- const BoundNetLog net_log_;
+ 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 8c4b80e8ec3..a9b57a66383 100644
--- a/chromium/net/http/http_proxy_client_socket_fuzzer.cc
+++ b/chromium/net/http/http_proxy_client_socket_fuzzer.cc
@@ -12,9 +12,9 @@
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/fuzzed_data_provider.h"
#include "net/base/address_list.h"
#include "net/base/auth.h"
-#include "net/base/fuzzed_data_provider.h"
#include "net/base/host_port_pair.h"
#include "net/base/test_completion_callback.h"
#include "net/http/http_auth_cache.h"
@@ -36,7 +36,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Use a test NetLog, to exercise logging code.
net::TestNetLog test_net_log;
- net::FuzzedDataProvider data_provider(data, size);
+ base::FuzzedDataProvider data_provider(data, size);
net::TestCompletionCallback callback;
std::unique_ptr<net::FuzzedSocket> fuzzed_socket(
diff --git a/chromium/net/http/http_proxy_client_socket_pool.cc b/chromium/net/http/http_proxy_client_socket_pool.cc
index 11bf04d0935..ad69060925d 100644
--- a/chromium/net/http/http_proxy_client_socket_pool.cc
+++ b/chromium/net/http/http_proxy_client_socket_pool.cc
@@ -15,6 +15,8 @@
#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"
+#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/client_socket_pool_base.h"
@@ -83,12 +85,13 @@ HttpProxyConnectJob::HttpProxyConnectJob(
SSLClientSocketPool* ssl_pool,
Delegate* delegate,
NetLog* net_log)
- : ConnectJob(group_name,
- base::TimeDelta() /* The socket takes care of timeouts */,
- priority,
- respect_limits,
- delegate,
- BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
+ : ConnectJob(
+ group_name,
+ base::TimeDelta() /* The socket takes care of timeouts */,
+ priority,
+ respect_limits,
+ delegate,
+ NetLogWithSource::Make(net_log, NetLogSourceType::CONNECT_JOB)),
client_socket_(new HttpProxyClientSocketWrapper(
group_name,
priority,
@@ -216,7 +219,7 @@ int HttpProxyClientSocketPool::RequestSocket(const std::string& group_name,
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
const scoped_refptr<HttpProxySocketParams>* casted_socket_params =
static_cast<const scoped_refptr<HttpProxySocketParams>*>(socket_params);
@@ -228,7 +231,7 @@ void HttpProxyClientSocketPool::RequestSockets(
const std::string& group_name,
const void* params,
int num_sockets,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
const scoped_refptr<HttpProxySocketParams>* casted_params =
static_cast<const scoped_refptr<HttpProxySocketParams>*>(params);
diff --git a/chromium/net/http/http_proxy_client_socket_pool.h b/chromium/net/http/http_proxy_client_socket_pool.h
index 167aa615d47..4373fd207d5 100644
--- a/chromium/net/http/http_proxy_client_socket_pool.h
+++ b/chromium/net/http/http_proxy_client_socket_pool.h
@@ -27,6 +27,7 @@ namespace net {
class HttpAuthCache;
class HttpAuthHandlerFactory;
class HttpProxyClientSocketWrapper;
+class NetLog;
class ProxyDelegate;
class SSLClientSocketPool;
class SSLSocketParams;
@@ -154,12 +155,12 @@ class NET_EXPORT_PRIVATE HttpProxyClientSocketPool
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void RequestSockets(const std::string& group_name,
const void* params,
int num_sockets,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void CancelRequest(const std::string& group_name,
ClientSocketHandle* handle) override;
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 15524bd37aa..d798e8e7ec8 100644
--- a/chromium/net/http/http_proxy_client_socket_pool_unittest.cc
+++ b/chromium/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -17,13 +17,19 @@
#include "net/http/http_network_session.h"
#include "net/http/http_proxy_client_socket.h"
#include "net/http/http_response_headers.h"
+#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_test_util.h"
#include "net/spdy/spdy_protocol.h"
#include "net/spdy/spdy_test_util_common.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -41,37 +47,16 @@ enum HttpProxyType {
SPDY
};
-struct HttpProxyClientSocketPoolTestParams {
- HttpProxyClientSocketPoolTestParams()
- : proxy_type(HTTP),
- protocol(kProtoSPDY31),
- priority_to_dependency(false) {}
-
- HttpProxyClientSocketPoolTestParams(HttpProxyType proxy_type,
- NextProto protocol,
- bool priority_to_dependency)
- : proxy_type(proxy_type),
- protocol(protocol),
- priority_to_dependency(priority_to_dependency) {}
-
- HttpProxyType proxy_type;
- NextProto protocol;
- bool priority_to_dependency;
-};
-
-typedef ::testing::TestWithParam<HttpProxyType> TestWithHttpParam;
-
const char kHttpProxyHost[] = "httpproxy.example.com";
const char kHttpsProxyHost[] = "httpsproxy.example.com";
} // namespace
class HttpProxyClientSocketPoolTest
- : public ::testing::TestWithParam<HttpProxyClientSocketPoolTestParams> {
+ : public ::testing::TestWithParam<HttpProxyType> {
protected:
HttpProxyClientSocketPoolTest()
- : session_deps_(GetParam().protocol),
- transport_socket_pool_(kMaxSockets,
+ : transport_socket_pool_(kMaxSockets,
kMaxSocketsPerGroup,
session_deps_.socket_factory.get()),
ssl_socket_pool_(kMaxSockets,
@@ -87,15 +72,12 @@ class HttpProxyClientSocketPoolTest
NULL,
NULL,
session_deps_.ssl_config_service.get(),
- BoundNetLog().net_log()),
- spdy_util_(GetParam().protocol, GetParam().priority_to_dependency),
+ NetLogWithSource().net_log()),
pool_(kMaxSockets,
kMaxSocketsPerGroup,
&transport_socket_pool_,
&ssl_socket_pool_,
NULL) {
- session_deps_.enable_priority_dependencies =
- GetParam().priority_to_dependency;
session_ = CreateNetworkSession();
}
@@ -104,9 +86,9 @@ class HttpProxyClientSocketPoolTest
void AddAuthToCache() {
const base::string16 kFoo(base::ASCIIToUTF16("foo"));
const base::string16 kBar(base::ASCIIToUTF16("bar"));
- GURL proxy_url(GetParam().proxy_type == HTTP ?
- (std::string("http://") + kHttpProxyHost) :
- (std::string("https://") + kHttpsProxyHost));
+ GURL proxy_url(GetParam() == HTTP
+ ? (std::string("http://") + kHttpProxyHost)
+ : (std::string("https://") + kHttpsProxyHost));
session_->http_auth_cache()->Add(proxy_url,
"MyRealm1",
HttpAuth::AUTH_SCHEME_BASIC,
@@ -116,7 +98,7 @@ class HttpProxyClientSocketPoolTest
}
scoped_refptr<TransportSocketParams> CreateHttpProxyParams() const {
- if (GetParam().proxy_type != HTTP)
+ if (GetParam() != HTTP)
return NULL;
return new TransportSocketParams(
HostPortPair(kHttpProxyHost, 80),
@@ -126,7 +108,7 @@ class HttpProxyClientSocketPoolTest
}
scoped_refptr<SSLSocketParams> CreateHttpsProxyParams() const {
- if (GetParam().proxy_type == HTTP)
+ if (GetParam() == HTTP)
return NULL;
return new SSLSocketParams(
new TransportSocketParams(
@@ -178,7 +160,7 @@ class HttpProxyClientSocketPoolTest
MockWrite* writes, size_t writes_count,
MockRead* spdy_reads, size_t spdy_reads_count,
MockWrite* spdy_writes, size_t spdy_writes_count) {
- if (GetParam().proxy_type == SPDY) {
+ if (GetParam() == SPDY) {
data_.reset(new SequencedSocketData(spdy_reads, spdy_reads_count,
spdy_writes, spdy_writes_count));
} else {
@@ -190,18 +172,16 @@ class HttpProxyClientSocketPoolTest
socket_factory()->AddSocketDataProvider(data_.get());
- if (GetParam().proxy_type != HTTP) {
+ if (GetParam() != HTTP) {
ssl_data_.reset(new SSLSocketDataProvider(SYNCHRONOUS, OK));
- if (GetParam().proxy_type == SPDY) {
+ if (GetParam() == SPDY) {
InitializeSpdySsl();
}
socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
}
}
- void InitializeSpdySsl() {
- ssl_data_->SetNextProto(GetParam().protocol);
- }
+ void InitializeSpdySsl() { ssl_data_->next_proto = kProtoHTTP2; }
std::unique_ptr<HttpNetworkSession> CreateNetworkSession() {
return SpdySessionDependencies::SpdyCreateSession(&session_deps_);
@@ -230,25 +210,11 @@ class HttpProxyClientSocketPoolTest
TestCompletionCallback callback_;
};
-//-----------------------------------------------------------------------------
// All tests are run with three different proxy types: HTTP, HTTPS (non-SPDY)
// and SPDY.
-//
-// TODO(akalin): Use ::testing::Combine() when we are able to use
-// <tr1/tuple>.
-INSTANTIATE_TEST_CASE_P(
- HttpProxyClientSocketPoolTests,
- HttpProxyClientSocketPoolTest,
- ::testing::Values(
- HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY31, false),
- HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY31, false),
- HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY31, false),
- HttpProxyClientSocketPoolTestParams(HTTP, kProtoHTTP2, false),
- HttpProxyClientSocketPoolTestParams(HTTP, kProtoHTTP2, true),
- HttpProxyClientSocketPoolTestParams(HTTPS, kProtoHTTP2, false),
- HttpProxyClientSocketPoolTestParams(HTTPS, kProtoHTTP2, true),
- HttpProxyClientSocketPoolTestParams(SPDY, kProtoHTTP2, false),
- HttpProxyClientSocketPoolTestParams(SPDY, kProtoHTTP2, true)));
+INSTANTIATE_TEST_CASE_P(HttpProxyType,
+ HttpProxyClientSocketPoolTest,
+ ::testing::Values(HTTP, HTTPS, SPDY));
TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) {
Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
@@ -256,8 +222,8 @@ TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) {
std::unique_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
int rv = handle_.Init("a", CreateNoTunnelParams(proxy_delegate.get()), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- CompletionCallback(), &pool_, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ CompletionCallback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(handle_.is_initialized());
ASSERT_TRUE(handle_.socket());
EXPECT_TRUE(handle_.socket()->IsConnected());
@@ -272,7 +238,7 @@ TEST_P(HttpProxyClientSocketPoolTest, SetSocketRequestPriorityOnInit) {
Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
EXPECT_EQ(OK, handle_.Init("a", CreateNoTunnelParams(NULL), HIGHEST,
ClientSocketPool::RespectLimits::ENABLED,
- CompletionCallback(), &pool_, BoundNetLog()));
+ CompletionCallback(), &pool_, NetLogWithSource()));
EXPECT_EQ(HIGHEST, GetLastTransportRequestPriority());
}
@@ -290,25 +256,21 @@ TEST_P(HttpProxyClientSocketPoolTest, NeedAuth) {
MockRead(ASYNC, 3, "Content-Length: 10\r\n\r\n"),
MockRead(ASYNC, 4, "0123456789"),
};
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyConnect(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
NULL, 0, 1, LOW, HostPortPair("www.google.com", 443)));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite spdy_writes[] = {
- CreateMockWrite(*req, 0, ASYNC),
- CreateMockWrite(*rst, 2, ASYNC),
+ CreateMockWrite(req, 0, ASYNC), CreateMockWrite(rst, 2, ASYNC),
};
SpdyHeaderBlock resp_block;
resp_block[spdy_util_.GetStatusKey()] = "407";
resp_block["proxy-authenticate"] = "Basic realm=\"MyRealm1\"";
- spdy_util_.MaybeAddVersionHeader(&resp_block);
- std::unique_ptr<SpdySerializedFrame> resp(
+ SpdySerializedFrame resp(
spdy_util_.ConstructSpdyReply(1, std::move(resp_block)));
- MockRead spdy_reads[] = {
- CreateMockRead(*resp, 1, ASYNC),
- MockRead(ASYNC, 0, 3)
- };
+ MockRead spdy_reads[] = {CreateMockRead(resp, 1, ASYNC),
+ MockRead(ASYNC, 0, 3)};
Initialize(reads, arraysize(reads), writes, arraysize(writes),
spdy_reads, arraysize(spdy_reads), spdy_writes,
@@ -316,18 +278,18 @@ TEST_P(HttpProxyClientSocketPoolTest, NeedAuth) {
int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- callback_.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback_.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
rv = callback_.WaitForResult();
- EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, rv);
+ EXPECT_THAT(rv, IsError(ERR_PROXY_AUTH_REQUESTED));
EXPECT_TRUE(handle_.is_initialized());
ASSERT_TRUE(handle_.socket());
ProxyClientSocket* tunnel_socket =
static_cast<ProxyClientSocket*>(handle_.socket());
- if (GetParam().proxy_type == SPDY) {
+ if (GetParam() == SPDY) {
EXPECT_TRUE(tunnel_socket->IsConnected());
EXPECT_TRUE(tunnel_socket->IsUsingSpdy());
} else {
@@ -339,12 +301,11 @@ TEST_P(HttpProxyClientSocketPoolTest, NeedAuth) {
TEST_P(HttpProxyClientSocketPoolTest, HaveAuth) {
// It's pretty much impossible to make the SPDY case behave synchronously
// so we skip this test for SPDY
- if (GetParam().proxy_type == SPDY)
+ if (GetParam() == SPDY)
return;
- std::string proxy_host_port =
- GetParam().proxy_type == HTTP ?
- (kHttpProxyHost + std::string(":80")) :
- (kHttpsProxyHost + std::string(":443"));
+ std::string proxy_host_port = GetParam() == HTTP
+ ? (kHttpProxyHost + std::string(":80"))
+ : (kHttpsProxyHost + std::string(":443"));
std::string request =
"CONNECT www.google.com:443 HTTP/1.1\r\n"
"Host: www.google.com:443\r\n"
@@ -366,8 +327,8 @@ TEST_P(HttpProxyClientSocketPoolTest, HaveAuth) {
std::unique_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
int rv = handle_.Init("a", CreateTunnelParams(proxy_delegate.get()), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- callback_.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ callback_.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(handle_.is_initialized());
ASSERT_TRUE(handle_.socket());
EXPECT_TRUE(handle_.socket()->IsConnected());
@@ -381,10 +342,9 @@ TEST_P(HttpProxyClientSocketPoolTest, HaveAuth) {
}
TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) {
- std::string proxy_host_port =
- GetParam().proxy_type == HTTP ?
- (kHttpProxyHost + std::string(":80")) :
- (kHttpsProxyHost + std::string(":443"));
+ std::string proxy_host_port = GetParam() == HTTP
+ ? (kHttpProxyHost + std::string(":80"))
+ : (kHttpsProxyHost + std::string(":443"));
std::string request =
"CONNECT www.google.com:443 HTTP/1.1\r\n"
"Host: www.google.com:443\r\n"
@@ -399,16 +359,13 @@ TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) {
MockRead(ASYNC, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
HostPortPair("www.google.com", 443)));
- MockWrite spdy_writes[] = {
- CreateMockWrite(*req, 0, ASYNC)
- };
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ MockWrite spdy_writes[] = {CreateMockWrite(req, 0, ASYNC)};
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
MockRead spdy_reads[] = {
- CreateMockRead(*resp, 1, ASYNC),
+ CreateMockRead(resp, 1, ASYNC),
// Connection stays open.
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
};
@@ -421,12 +378,12 @@ TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) {
std::unique_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
int rv = handle_.Init("a", CreateTunnelParams(proxy_delegate.get()), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- callback_.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback_.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
- EXPECT_EQ(OK, callback_.WaitForResult());
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
EXPECT_TRUE(handle_.is_initialized());
ASSERT_TRUE(handle_.socket());
EXPECT_TRUE(handle_.socket()->IsConnected());
@@ -439,21 +396,16 @@ TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) {
// SPDY session's socket request on Init (if applicable).
TEST_P(HttpProxyClientSocketPoolTest,
SetSpdySessionSocketRequestPriorityOnInit) {
- if (GetParam().proxy_type != SPDY)
+ if (GetParam() != SPDY)
return;
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, MEDIUM,
HostPortPair("www.google.com", 443)));
- MockWrite spdy_writes[] = {
- CreateMockWrite(*req, 0, ASYNC)
- };
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- MockRead spdy_reads[] = {
- CreateMockRead(*resp, 1, ASYNC),
- MockRead(ASYNC, 0, 2)
- };
+ MockWrite spdy_writes[] = {CreateMockWrite(req, 0, ASYNC)};
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ MockRead spdy_reads[] = {CreateMockRead(resp, 1, ASYNC),
+ MockRead(ASYNC, 0, 2)};
Initialize(NULL, 0, NULL, 0,
spdy_reads, arraysize(spdy_reads),
@@ -463,14 +415,15 @@ TEST_P(HttpProxyClientSocketPoolTest,
EXPECT_EQ(ERR_IO_PENDING,
handle_.Init("a", CreateTunnelParams(NULL), MEDIUM,
ClientSocketPool::RespectLimits::ENABLED,
- callback_.callback(), &pool_, BoundNetLog()));
+ callback_.callback(), &pool_, NetLogWithSource()));
EXPECT_EQ(MEDIUM, GetLastTransportRequestPriority());
- EXPECT_EQ(OK, callback_.WaitForResult());
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
}
TEST_P(HttpProxyClientSocketPoolTest, TCPError) {
- if (GetParam().proxy_type == SPDY) return;
+ if (GetParam() == SPDY)
+ return;
data_.reset(new SequencedSocketData(NULL, 0, NULL, 0));
data_->set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_CLOSED));
@@ -478,64 +431,68 @@ TEST_P(HttpProxyClientSocketPoolTest, TCPError) {
int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- callback_.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback_.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
- EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback_.WaitForResult());
+ EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_PROXY_CONNECTION_FAILED));
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
}
TEST_P(HttpProxyClientSocketPoolTest, SSLError) {
- if (GetParam().proxy_type == HTTP) return;
+ if (GetParam() == HTTP)
+ return;
data_.reset(new SequencedSocketData(NULL, 0, NULL, 0));
data_->set_connect_data(MockConnect(ASYNC, OK));
socket_factory()->AddSocketDataProvider(data_.get());
ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
ERR_CERT_AUTHORITY_INVALID));
- if (GetParam().proxy_type == SPDY) {
+ if (GetParam() == SPDY) {
InitializeSpdySsl();
}
socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- callback_.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback_.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
- EXPECT_EQ(ERR_PROXY_CERTIFICATE_INVALID, callback_.WaitForResult());
+ EXPECT_THAT(callback_.WaitForResult(),
+ IsError(ERR_PROXY_CERTIFICATE_INVALID));
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
}
TEST_P(HttpProxyClientSocketPoolTest, SslClientAuth) {
- if (GetParam().proxy_type == HTTP) return;
+ if (GetParam() == HTTP)
+ return;
data_.reset(new SequencedSocketData(NULL, 0, NULL, 0));
data_->set_connect_data(MockConnect(ASYNC, OK));
socket_factory()->AddSocketDataProvider(data_.get());
ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
- if (GetParam().proxy_type == SPDY) {
+ if (GetParam() == SPDY) {
InitializeSpdySsl();
}
socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- callback_.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback_.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
- EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, callback_.WaitForResult());
+ EXPECT_THAT(callback_.WaitForResult(),
+ IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
@@ -553,12 +510,10 @@ TEST_P(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) {
MockRead(ASYNC, 1, "HTTP/1.1 200 Conn"),
MockRead(ASYNC, ERR_CONNECTION_CLOSED, 2),
};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
HostPortPair("www.google.com", 443)));
- MockWrite spdy_writes[] = {
- CreateMockWrite(*req, 0, ASYNC)
- };
+ MockWrite spdy_writes[] = {CreateMockWrite(req, 0, ASYNC)};
MockRead spdy_reads[] = {
MockRead(ASYNC, ERR_CONNECTION_CLOSED, 1),
};
@@ -570,17 +525,18 @@ TEST_P(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) {
int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- callback_.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback_.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
- if (GetParam().proxy_type == SPDY) {
+ if (GetParam() == SPDY) {
// SPDY cannot process a headers block unless it's complete and so it
// returns ERR_CONNECTION_CLOSED in this case.
- EXPECT_EQ(ERR_CONNECTION_CLOSED, callback_.WaitForResult());
+ EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
} else {
- EXPECT_EQ(ERR_RESPONSE_HEADERS_TRUNCATED, callback_.WaitForResult());
+ EXPECT_THAT(callback_.WaitForResult(),
+ IsError(ERR_RESPONSE_HEADERS_TRUNCATED));
}
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
@@ -588,7 +544,7 @@ TEST_P(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) {
TEST_P(HttpProxyClientSocketPoolTest, Tunnel1xxResponse) {
// Tests that 1xx responses are rejected for a CONNECT request.
- if (GetParam().proxy_type == SPDY) {
+ if (GetParam() == SPDY) {
// SPDY doesn't have 1xx responses.
return;
}
@@ -609,12 +565,12 @@ TEST_P(HttpProxyClientSocketPoolTest, Tunnel1xxResponse) {
int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- callback_.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback_.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, callback_.WaitForResult());
+ EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_TUNNEL_CONNECTION_FAILED));
}
TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupError) {
@@ -628,20 +584,17 @@ TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupError) {
MockRead reads[] = {
MockRead(ASYNC, 1, "HTTP/1.1 304 Not Modified\r\n\r\n"),
};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
HostPortPair("www.google.com", 443)));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite spdy_writes[] = {
- CreateMockWrite(*req, 0, ASYNC),
- CreateMockWrite(*rst, 2, ASYNC),
+ CreateMockWrite(req, 0, ASYNC), CreateMockWrite(rst, 2, ASYNC),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdySynReplyError(1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyReplyError(1));
MockRead spdy_reads[] = {
- CreateMockRead(*resp, 1, ASYNC),
- MockRead(ASYNC, 0, 3),
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, 0, 3),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes),
@@ -651,14 +604,14 @@ TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupError) {
int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- callback_.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback_.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
rv = callback_.WaitForResult();
// All Proxy CONNECT responses are not trustworthy
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
+ EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
}
@@ -680,15 +633,14 @@ TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupRedirect) {
MockRead reads[] = {
MockRead(ASYNC, 1, responseText.c_str()),
};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW,
HostPortPair("www.google.com", 443)));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite spdy_writes[] = {
- CreateMockWrite(*req, 0, ASYNC),
- CreateMockWrite(*rst, 3, ASYNC),
+ CreateMockWrite(req, 0, ASYNC), CreateMockWrite(rst, 3, ASYNC),
};
const char* const responseHeaders[] = {
@@ -696,12 +648,10 @@ TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupRedirect) {
"set-cookie", "foo=bar",
};
const int responseHeadersSize = arraysize(responseHeaders) / 2;
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdySynReplyError("302 Found", responseHeaders,
- responseHeadersSize, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyReplyError(
+ "302 Found", responseHeaders, responseHeadersSize, 1));
MockRead spdy_reads[] = {
- CreateMockRead(*resp, 1, ASYNC),
- MockRead(ASYNC, 0, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, 0, 2),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes),
@@ -711,21 +661,21 @@ TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupRedirect) {
int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- callback_.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback_.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
rv = callback_.WaitForResult();
- if (GetParam().proxy_type == HTTP) {
+ if (GetParam() == HTTP) {
// We don't trust 302 responses to CONNECT from HTTP proxies.
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
+ EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
EXPECT_FALSE(handle_.is_initialized());
EXPECT_FALSE(handle_.socket());
} else {
// Expect ProxyClientSocket to return the proxy's response, sanitized.
- EXPECT_EQ(ERR_HTTPS_PROXY_TUNNEL_RESPONSE, rv);
+ EXPECT_THAT(rv, IsError(ERR_HTTPS_PROXY_TUNNEL_RESPONSE));
EXPECT_TRUE(handle_.is_initialized());
ASSERT_TRUE(handle_.socket());
diff --git a/chromium/net/http/http_proxy_client_socket_wrapper.cc b/chromium/net/http/http_proxy_client_socket_wrapper.cc
index b857f0fef47..f389141d2f7 100644
--- a/chromium/net/http/http_proxy_client_socket_wrapper.cc
+++ b/chromium/net/http/http_proxy_client_socket_wrapper.cc
@@ -15,6 +15,9 @@
#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"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
#include "net/socket/client_socket_handle.h"
#include "net/spdy/spdy_proxy_client_socket.h"
#include "net/spdy/spdy_session.h"
@@ -42,7 +45,7 @@ HttpProxyClientSocketWrapper::HttpProxyClientSocketWrapper(
SpdySessionPool* spdy_session_pool,
bool tunnel,
ProxyDelegate* proxy_delegate,
- const BoundNetLog& net_log)
+ const NetLogWithSource& net_log)
: next_state_(STATE_NONE),
group_name_(group_name),
priority_(priority),
@@ -67,9 +70,10 @@ HttpProxyClientSocketWrapper::HttpProxyClientSocketWrapper(
http_auth_cache,
http_auth_handler_factory)
: nullptr),
- net_log_(BoundNetLog::Make(net_log.net_log(),
- NetLog::SOURCE_PROXY_CLIENT_SOCKET_WRAPPER)) {
- net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
+ net_log_(NetLogWithSource::Make(
+ net_log.net_log(),
+ NetLogSourceType::PROXY_CLIENT_SOCKET_WRAPPER)) {
+ net_log_.BeginEvent(NetLogEventType::SOCKET_ALIVE,
net_log.source().ToEventParametersCallback());
DCHECK(transport_params || ssl_params);
DCHECK(!transport_params || !ssl_params);
@@ -79,7 +83,7 @@ HttpProxyClientSocketWrapper::~HttpProxyClientSocketWrapper() {
// Make sure no sockets are returned to the lower level socket pools.
Disconnect();
- net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
+ net_log_.EndEvent(NetLogEventType::SOCKET_ALIVE);
}
LoadState HttpProxyClientSocketWrapper::GetConnectLoadState() const {
@@ -147,9 +151,9 @@ bool HttpProxyClientSocketWrapper::IsUsingSpdy() const {
return false;
}
-NextProto HttpProxyClientSocketWrapper::GetProtocolNegotiated() const {
+NextProto HttpProxyClientSocketWrapper::GetProxyNegotiatedProtocol() const {
if (transport_socket_)
- return transport_socket_->GetProtocolNegotiated();
+ return transport_socket_->GetProxyNegotiatedProtocol();
return kProtoUnknown;
}
@@ -204,7 +208,7 @@ bool HttpProxyClientSocketWrapper::IsConnectedAndIdle() const {
return false;
}
-const BoundNetLog& HttpProxyClientSocketWrapper::NetLog() const {
+const NetLogWithSource& HttpProxyClientSocketWrapper::NetLog() const {
return net_log_;
}
@@ -470,8 +474,8 @@ int HttpProxyClientSocketWrapper::DoSSLConnectComplete(int result) {
SSLClientSocket* ssl =
static_cast<SSLClientSocket*>(transport_socket_handle_->socket());
- protocol_negotiated_ = ssl->GetNegotiatedProtocol();
- using_spdy_ = NextProtoIsSPDY(protocol_negotiated_);
+ negotiated_protocol_ = ssl->GetNegotiatedProtocol();
+ using_spdy_ = negotiated_protocol_ == kProtoHTTP2;
// Reset the timer to just the length of time allowed for HttpProxy handshake
// so that a fast SSL connection plus a slow HttpProxy failure doesn't take
@@ -499,7 +503,7 @@ int HttpProxyClientSocketWrapper::DoHttpProxyConnect() {
transport_socket_.reset(new HttpProxyClientSocket(
transport_socket_handle_.release(), user_agent_, endpoint_,
GetDestination().host_port_pair(), http_auth_controller_.get(), tunnel_,
- using_spdy_, protocol_negotiated_, proxy_delegate_,
+ using_spdy_, negotiated_protocol_, proxy_delegate_,
ssl_params_.get() != nullptr));
return transport_socket_->Connect(base::Bind(
&HttpProxyClientSocketWrapper::OnIOComplete, base::Unretained(this)));
@@ -529,7 +533,7 @@ int HttpProxyClientSocketWrapper::DoSpdyProxyCreateStream() {
} else {
// Create a session direct to the proxy itself
spdy_session = spdy_session_pool_->CreateAvailableSessionFromSocket(
- key, std::move(transport_socket_handle_), net_log_, OK,
+ key, std::move(transport_socket_handle_), net_log_,
/*using_ssl_*/ true);
DCHECK(spdy_session);
}
diff --git a/chromium/net/http/http_proxy_client_socket_wrapper.h b/chromium/net/http/http_proxy_client_socket_wrapper.h
index 6e4bc803af2..eb8dd7ac2a7 100644
--- a/chromium/net/http/http_proxy_client_socket_wrapper.h
+++ b/chromium/net/http/http_proxy_client_socket_wrapper.h
@@ -19,7 +19,7 @@
#include "net/base/load_timing_info.h"
#include "net/http/http_auth_controller.h"
#include "net/http/proxy_client_socket.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/next_proto.h"
#include "net/socket/ssl_client_socket.h"
#include "net/socket/ssl_client_socket_pool.h"
@@ -69,7 +69,7 @@ class HttpProxyClientSocketWrapper : public ProxyClientSocket {
SpdySessionPool* spdy_session_pool,
bool tunnel,
ProxyDelegate* proxy_delegate,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// On destruction Disconnect() is called.
~HttpProxyClientSocketWrapper() override;
@@ -86,14 +86,14 @@ class HttpProxyClientSocketWrapper : public ProxyClientSocket {
int RestartWithAuth(const CompletionCallback& callback) override;
const scoped_refptr<HttpAuthController>& GetAuthController() const override;
bool IsUsingSpdy() const override;
- NextProto GetProtocolNegotiated() const override;
+ NextProto GetProxyNegotiatedProtocol() const override;
// StreamSocket implementation.
int Connect(const CompletionCallback& callback) override;
void Disconnect() override;
bool IsConnected() const override;
bool IsConnectedAndIdle() const override;
- const BoundNetLog& NetLog() const override;
+ const NetLogWithSource& NetLog() const override;
void SetSubresourceSpeculation() override;
void SetOmniboxSpeculation() override;
bool WasEverUsed() const override;
@@ -185,7 +185,7 @@ class HttpProxyClientSocketWrapper : public ProxyClientSocket {
ProxyDelegate* const proxy_delegate_;
bool using_spdy_;
- NextProto protocol_negotiated_;
+ NextProto negotiated_protocol_;
std::unique_ptr<HttpResponseInfo> error_response_info_;
@@ -201,7 +201,7 @@ class HttpProxyClientSocketWrapper : public ProxyClientSocket {
scoped_refptr<HttpAuthController> http_auth_controller_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
base::OneShotTimer connect_timer_;
diff --git a/chromium/net/http/http_request_headers.cc b/chromium/net/http/http_request_headers.cc
index c6fcaad6366..8e667fc4886 100644
--- a/chromium/net/http/http_request_headers.cc
+++ b/chromium/net/http/http_request_headers.cc
@@ -13,6 +13,7 @@
#include "base/values.h"
#include "net/http/http_log_util.h"
#include "net/http/http_util.h"
+#include "net/log/net_log_capture_mode.h"
namespace net {
@@ -89,8 +90,8 @@ void HttpRequestHeaders::Clear() {
void HttpRequestHeaders::SetHeader(const base::StringPiece& key,
const base::StringPiece& value) {
- DCHECK(HttpUtil::IsValidHeaderName(key.as_string()));
- DCHECK(HttpUtil::IsValidHeaderValue(value.as_string()));
+ DCHECK(HttpUtil::IsValidHeaderName(key));
+ DCHECK(HttpUtil::IsValidHeaderValue(value));
HeaderVector::iterator it = FindHeader(key);
if (it != headers_.end())
it->value.assign(value.data(), value.size());
@@ -100,8 +101,8 @@ void HttpRequestHeaders::SetHeader(const base::StringPiece& key,
void HttpRequestHeaders::SetHeaderIfMissing(const base::StringPiece& key,
const base::StringPiece& value) {
- DCHECK(HttpUtil::IsValidHeaderName(key.as_string()));
- DCHECK(HttpUtil::IsValidHeaderValue(value.as_string()));
+ DCHECK(HttpUtil::IsValidHeaderName(key));
+ DCHECK(HttpUtil::IsValidHeaderValue(value));
HeaderVector::iterator it = FindHeader(key);
if (it == headers_.end())
headers_.push_back(HeaderKeyValuePair(key, value));
@@ -130,26 +131,22 @@ void HttpRequestHeaders::AddHeaderFromString(
}
const base::StringPiece header_key(header_line.data(), key_end_index);
+ if (!HttpUtil::IsValidHeaderName(header_key)) {
+ LOG(DFATAL) << "\"" << header_line << "\" has invalid header key.";
+ return;
+ }
const std::string::size_type value_index = key_end_index + 1;
if (value_index < header_line.size()) {
- std::string header_value(header_line.data() + value_index,
- header_line.size() - value_index);
- std::string::const_iterator header_value_begin =
- header_value.begin();
- std::string::const_iterator header_value_end =
- header_value.end();
- HttpUtil::TrimLWS(&header_value_begin, &header_value_end);
-
- if (header_value_begin == header_value_end) {
- // Value was all LWS.
- SetHeader(header_key, "");
- } else {
- SetHeader(header_key,
- base::StringPiece(&*header_value_begin,
- header_value_end - header_value_begin));
+ base::StringPiece header_value(header_line.data() + value_index,
+ header_line.size() - value_index);
+ header_value = HttpUtil::TrimLWS(header_value);
+ if (!HttpUtil::IsValidHeaderValue(header_value)) {
+ LOG(DFATAL) << "\"" << header_line << "\" has invalid header value.";
+ return;
}
+ SetHeader(header_key, header_value);
} else if (value_index == header_line.size()) {
SetHeader(header_key, "");
} else {
diff --git a/chromium/net/http/http_request_headers.h b/chromium/net/http/http_request_headers.h
index 62ec37cab9f..3a051022364 100644
--- a/chromium/net/http/http_request_headers.h
+++ b/chromium/net/http/http_request_headers.h
@@ -10,16 +10,22 @@
#ifndef NET_HTTP_HTTP_REQUEST_HEADERS_H_
#define NET_HTTP_HTTP_REQUEST_HEADERS_H_
+#include <memory>
#include <string>
#include <vector>
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "net/base/net_export.h"
-#include "net/log/net_log.h"
+
+namespace base {
+class Value;
+}
namespace net {
+class NetLogCaptureMode;
+
class NET_EXPORT HttpRequestHeaders {
public:
struct HeaderKeyValuePair {
@@ -100,6 +106,8 @@ class NET_EXPORT HttpRequestHeaders {
// Sets the header value pair for |key| and |value|. If |key| already exists,
// then the header value is modified, but the key is untouched, and the order
// in the vector remains the same. When comparing |key|, case is ignored.
+ // The caller must ensure that |key| passes HttpUtil::IsValidHeaderName() and
+ // |value| passes HttpUtil::IsValidHeaderValue().
void SetHeader(const base::StringPiece& key, const base::StringPiece& value);
// Sets the header value pair for |key| and |value|, if |key| does not exist.
diff --git a/chromium/net/http/http_request_headers_unittest.cc b/chromium/net/http/http_request_headers_unittest.cc
index 6a09e4631e7..ef4b7b0b4b0 100644
--- a/chromium/net/http/http_request_headers_unittest.cc
+++ b/chromium/net/http/http_request_headers_unittest.cc
@@ -7,6 +7,7 @@
#include <memory>
#include "base/values.h"
+#include "net/log/net_log_capture_mode.h"
#include "testing/gtest/include/gtest/gtest.h"
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 078f9a1c4fc..6b725dad891 100644
--- a/chromium/net/http/http_response_body_drainer_unittest.cc
+++ b/chromium/net/http/http_response_body_drainer_unittest.cc
@@ -90,7 +90,7 @@ class MockHttpStream : public HttpStream {
// HttpStream implementation.
int InitializeStream(const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback) override {
return ERR_UNEXPECTED;
}
@@ -99,7 +99,6 @@ class MockHttpStream : public HttpStream {
const CompletionCallback& callback) override {
return ERR_UNEXPECTED;
}
- UploadProgress GetUploadProgress() const override { return UploadProgress(); }
int ReadResponseHeaders(const CompletionCallback& callback) override {
return ERR_UNEXPECTED;
}
@@ -112,8 +111,9 @@ class MockHttpStream : public HttpStream {
void GetSSLInfo(SSLInfo* ssl_info) override {}
void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override {}
bool GetRemoteEndpoint(IPEndPoint* endpoint) override { return false; }
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) override {
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) override {
ADD_FAILURE();
return ERR_NOT_IMPLEMENTED;
}
diff --git a/chromium/net/http/http_response_headers.cc b/chromium/net/http/http_response_headers.cc
index 03cef6ef745..dd0977c3dca 100644
--- a/chromium/net/http/http_response_headers.cc
+++ b/chromium/net/http/http_response_headers.cc
@@ -28,6 +28,7 @@
#include "net/http/http_byte_range.h"
#include "net/http/http_log_util.h"
#include "net/http/http_util.h"
+#include "net/log/net_log_capture_mode.h"
using base::StringPiece;
using base::Time;
diff --git a/chromium/net/http/http_response_headers.h b/chromium/net/http/http_response_headers.h
index fd6af1707e7..39404cfd9f2 100644
--- a/chromium/net/http/http_response_headers.h
+++ b/chromium/net/http/http_response_headers.h
@@ -15,20 +15,22 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string_piece.h"
+#include "base/time/time.h"
#include "net/base/net_export.h"
#include "net/http/http_version.h"
-#include "net/log/net_log.h"
namespace base {
class Pickle;
class PickleIterator;
class Time;
class TimeDelta;
+class Value;
}
namespace net {
class HttpByteRange;
+class NetLogCaptureMode;
enum ValidationType {
VALIDATION_NONE, // The resource is fresh.
diff --git a/chromium/net/http/http_response_headers_unittest.cc b/chromium/net/http/http_response_headers_unittest.cc
index a9567c6512a..041972b76df 100644
--- a/chromium/net/http/http_response_headers_unittest.cc
+++ b/chromium/net/http/http_response_headers_unittest.cc
@@ -15,6 +15,7 @@
#include "base/time/time.h"
#include "base/values.h"
#include "net/http/http_byte_range.h"
+#include "net/log/net_log_capture_mode.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
diff --git a/chromium/net/http/http_response_info.cc b/chromium/net/http/http_response_info.cc
index 8c9127b2056..2adfe692c6f 100644
--- a/chromium/net/http/http_response_info.cc
+++ b/chromium/net/http/http_response_info.cc
@@ -4,16 +4,20 @@
#include "net/http/http_response_info.h"
+#include <openssl/ssl.h>
+
#include "base/logging.h"
#include "base/pickle.h"
#include "base/time/time.h"
#include "net/base/auth.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
+#include "net/cert/sct_status_flags.h"
#include "net/cert/signed_certificate_timestamp.h"
#include "net/cert/x509_certificate.h"
#include "net/http/http_response_headers.h"
#include "net/ssl/ssl_cert_request_info.h"
+#include "net/ssl/ssl_connection_status_flags.h"
using base::Time;
@@ -33,6 +37,19 @@ X509Certificate::PickleType GetPickleTypeForVersion(int version) {
}
}
+bool KeyExchangeGroupIsValid(int ssl_connection_status) {
+ // TLS 1.3 and later always treat the field correctly.
+ if (SSLConnectionStatusToVersion(ssl_connection_status) >=
+ SSL_CONNECTION_VERSION_TLS1_3) {
+ return true;
+ }
+
+ // Prior to TLS 1.3, only ECDHE ciphers have groups.
+ const SSL_CIPHER* cipher = SSL_get_cipher_by_value(
+ SSLConnectionStatusToCipherSuite(ssl_connection_status));
+ return cipher && SSL_CIPHER_is_ECDHE(cipher);
+}
+
} // namespace
// These values can be bit-wise combined to form the flags field of the
@@ -68,8 +85,8 @@ enum {
// This bit is set if the response was received via SPDY.
RESPONSE_INFO_WAS_SPDY = 1 << 13,
- // This bit is set if the request has NPN negotiated.
- RESPONSE_INFO_WAS_NPN = 1 << 14,
+ // This bit is set if the request has ALPN negotiated.
+ RESPONSE_INFO_WAS_ALPN = 1 << 14,
// This bit is set if the request was fetched via an explicit proxy.
RESPONSE_INFO_WAS_PROXY = 1 << 15,
@@ -80,7 +97,7 @@ enum {
RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS = 1 << 16,
// This bit is set if the response info has protocol version.
- RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL = 1 << 17,
+ RESPONSE_INFO_HAS_ALPN_NEGOTIATED_PROTOCOL = 1 << 17,
// This bit is set if the response info has connection info.
RESPONSE_INFO_HAS_CONNECTION_INFO = 1 << 18,
@@ -93,8 +110,8 @@ enum {
RESPONSE_INFO_UNUSED_SINCE_PREFETCH = 1 << 21,
- // This bit is set if the response has a key-exchange-info field at the end.
- RESPONSE_INFO_HAS_KEY_EXCHANGE_INFO = 1 << 22,
+ // This bit is set if the response has a key exchange group.
+ RESPONSE_INFO_HAS_KEY_EXCHANGE_GROUP = 1 << 22,
// This bit is set if ssl_info recorded that PKP was bypassed due to a local
// trust anchor.
@@ -110,7 +127,7 @@ HttpResponseInfo::HttpResponseInfo()
server_data_unavailable(false),
network_accessed(false),
was_fetched_via_spdy(false),
- was_npn_negotiated(false),
+ was_alpn_negotiated(false),
was_fetched_via_proxy(false),
did_use_http_auth(false),
unused_since_prefetch(false),
@@ -123,14 +140,14 @@ HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs)
server_data_unavailable(rhs.server_data_unavailable),
network_accessed(rhs.network_accessed),
was_fetched_via_spdy(rhs.was_fetched_via_spdy),
- was_npn_negotiated(rhs.was_npn_negotiated),
+ was_alpn_negotiated(rhs.was_alpn_negotiated),
was_fetched_via_proxy(rhs.was_fetched_via_proxy),
proxy_server(rhs.proxy_server),
did_use_http_auth(rhs.did_use_http_auth),
unused_since_prefetch(rhs.unused_since_prefetch),
async_revalidation_required(rhs.async_revalidation_required),
socket_address(rhs.socket_address),
- npn_negotiated_protocol(rhs.npn_negotiated_protocol),
+ alpn_negotiated_protocol(rhs.alpn_negotiated_protocol),
connection_info(rhs.connection_info),
request_time(rhs.request_time),
response_time(rhs.response_time),
@@ -151,13 +168,13 @@ HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) {
network_accessed = rhs.network_accessed;
was_fetched_via_spdy = rhs.was_fetched_via_spdy;
proxy_server = rhs.proxy_server;
- was_npn_negotiated = rhs.was_npn_negotiated;
+ was_alpn_negotiated = rhs.was_alpn_negotiated;
was_fetched_via_proxy = rhs.was_fetched_via_proxy;
did_use_http_auth = rhs.did_use_http_auth;
unused_since_prefetch = rhs.unused_since_prefetch;
async_revalidation_required = rhs.async_revalidation_required;
socket_address = rhs.socket_address;
- npn_negotiated_protocol = rhs.npn_negotiated_protocol;
+ alpn_negotiated_protocol = rhs.alpn_negotiated_protocol;
connection_info = rhs.connection_info;
request_time = rhs.request_time;
response_time = rhs.response_time;
@@ -239,6 +256,8 @@ bool HttpResponseInfo::InitFromPickle(const base::Pickle& pickle,
uint16_t status;
if (!sct.get() || !iter.ReadUInt16(&status))
return false;
+ if (!net::ct::IsValidSCTStatus(status))
+ return false;
ssl_info.signed_certificate_timestamps.push_back(
SignedCertificateTimestampAndStatus(
sct, static_cast<ct::SCTVerifyStatus>(status)));
@@ -266,8 +285,8 @@ bool HttpResponseInfo::InitFromPickle(const base::Pickle& pickle,
}
// Read protocol-version.
- if (flags & RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL) {
- if (!iter.ReadString(&npn_negotiated_protocol))
+ if (flags & RESPONSE_INFO_HAS_ALPN_NEGOTIATED_PROTOCOL) {
+ if (!iter.ReadString(&alpn_negotiated_protocol))
return false;
}
@@ -283,17 +302,22 @@ bool HttpResponseInfo::InitFromPickle(const base::Pickle& pickle,
}
}
- // Read key_exchange_info
- if (flags & RESPONSE_INFO_HAS_KEY_EXCHANGE_INFO) {
- int key_exchange_info;
- if (!iter.ReadInt(&key_exchange_info))
+ // Read key_exchange_group
+ if (flags & RESPONSE_INFO_HAS_KEY_EXCHANGE_GROUP) {
+ int key_exchange_group;
+ if (!iter.ReadInt(&key_exchange_group))
return false;
- ssl_info.key_exchange_info = key_exchange_info;
+
+ // Historically, the key_exchange_group field was key_exchange_info which
+ // conflated a number of different values based on the cipher suite, so some
+ // values must be discarded. See https://crbug.com/639421.
+ if (KeyExchangeGroupIsValid(ssl_info.connection_status))
+ ssl_info.key_exchange_group = key_exchange_group;
}
was_fetched_via_spdy = (flags & RESPONSE_INFO_WAS_SPDY) != 0;
- was_npn_negotiated = (flags & RESPONSE_INFO_WAS_NPN) != 0;
+ was_alpn_negotiated = (flags & RESPONSE_INFO_WAS_ALPN) != 0;
was_fetched_via_proxy = (flags & RESPONSE_INFO_WAS_PROXY) != 0;
@@ -317,8 +341,8 @@ void HttpResponseInfo::Persist(base::Pickle* pickle,
flags |= RESPONSE_INFO_HAS_CERT_STATUS;
if (ssl_info.security_bits != -1)
flags |= RESPONSE_INFO_HAS_SECURITY_BITS;
- if (ssl_info.key_exchange_info != 0)
- flags |= RESPONSE_INFO_HAS_KEY_EXCHANGE_INFO;
+ if (ssl_info.key_exchange_group != 0)
+ flags |= RESPONSE_INFO_HAS_KEY_EXCHANGE_GROUP;
if (ssl_info.connection_status != 0)
flags |= RESPONSE_INFO_HAS_SSL_CONNECTION_STATUS;
}
@@ -328,9 +352,9 @@ void HttpResponseInfo::Persist(base::Pickle* pickle,
flags |= RESPONSE_INFO_TRUNCATED;
if (was_fetched_via_spdy)
flags |= RESPONSE_INFO_WAS_SPDY;
- if (was_npn_negotiated) {
- flags |= RESPONSE_INFO_WAS_NPN;
- flags |= RESPONSE_INFO_HAS_NPN_NEGOTIATED_PROTOCOL;
+ if (was_alpn_negotiated) {
+ flags |= RESPONSE_INFO_WAS_ALPN;
+ flags |= RESPONSE_INFO_HAS_ALPN_NEGOTIATED_PROTOCOL;
}
if (was_fetched_via_proxy)
flags |= RESPONSE_INFO_WAS_PROXY;
@@ -387,21 +411,19 @@ void HttpResponseInfo::Persist(base::Pickle* pickle,
pickle->WriteString(socket_address.host());
pickle->WriteUInt16(socket_address.port());
- if (was_npn_negotiated)
- pickle->WriteString(npn_negotiated_protocol);
+ if (was_alpn_negotiated)
+ pickle->WriteString(alpn_negotiated_protocol);
if (connection_info != CONNECTION_INFO_UNKNOWN)
pickle->WriteInt(static_cast<int>(connection_info));
- if (ssl_info.is_valid() && ssl_info.key_exchange_info != 0)
- pickle->WriteInt(ssl_info.key_exchange_info);
+ if (ssl_info.is_valid() && ssl_info.key_exchange_group != 0)
+ pickle->WriteInt(ssl_info.key_exchange_group);
}
HttpResponseInfo::ConnectionInfo HttpResponseInfo::ConnectionInfoFromNextProto(
NextProto next_proto) {
switch (next_proto) {
- case kProtoSPDY31:
- return CONNECTION_INFO_SPDY3;
case kProtoHTTP2:
return CONNECTION_INFO_HTTP2;
case kProtoQUIC1SPDY3:
@@ -427,14 +449,14 @@ std::string HttpResponseInfo::ConnectionInfoToString(
case CONNECTION_INFO_DEPRECATED_SPDY2:
NOTREACHED();
return "";
- case CONNECTION_INFO_SPDY3:
+ case CONNECTION_INFO_DEPRECATED_SPDY3:
return "spdy/3";
// Since ConnectionInfo is persisted to disk, deprecated values have to be
// handled. Note that h2-14 and h2-15 are essentially wire compatible with
// h2.
// Intentional fallthrough.
- case CONNECTION_INFO_HTTP2_14:
- case CONNECTION_INFO_HTTP2_15:
+ case CONNECTION_INFO_DEPRECATED_HTTP2_14:
+ case CONNECTION_INFO_DEPRECATED_HTTP2_15:
case CONNECTION_INFO_HTTP2:
return "h2";
case CONNECTION_INFO_QUIC1_SPDY3:
diff --git a/chromium/net/http/http_response_info.h b/chromium/net/http/http_response_info.h
index 046774250f6..1a8f059428c 100644
--- a/chromium/net/http/http_response_info.h
+++ b/chromium/net/http/http_response_info.h
@@ -8,9 +8,9 @@
#include <string>
#include "base/time/time.h"
-#include "net/base/host_port_pair.h"
#include "net/base/net_export.h"
#include "net/http/http_vary_data.h"
+#include "net/proxy/proxy_server.h"
#include "net/socket/next_proto.h"
#include "net/ssl/ssl_info.h"
@@ -36,11 +36,11 @@ class NET_EXPORT HttpResponseInfo {
CONNECTION_INFO_UNKNOWN = 0,
CONNECTION_INFO_HTTP1_1 = 1,
CONNECTION_INFO_DEPRECATED_SPDY2 = 2,
- CONNECTION_INFO_SPDY3 = 3,
+ CONNECTION_INFO_DEPRECATED_SPDY3 = 3,
CONNECTION_INFO_HTTP2 = 4, // HTTP/2.
CONNECTION_INFO_QUIC1_SPDY3 = 5,
- CONNECTION_INFO_HTTP2_14 = 6, // HTTP/2 draft-14.
- CONNECTION_INFO_HTTP2_15 = 7, // HTTP/2 draft-15.
+ CONNECTION_INFO_DEPRECATED_HTTP2_14 = 6, // HTTP/2 draft-14.
+ CONNECTION_INFO_DEPRECATED_HTTP2_15 = 7, // HTTP/2 draft-15.
CONNECTION_INFO_HTTP0_9 = 8,
CONNECTION_INFO_HTTP1_0 = 9,
NUM_OF_CONNECTION_INFOS,
@@ -120,15 +120,16 @@ class NET_EXPORT HttpResponseInfo {
// True if the request was fetched over a SPDY channel.
bool was_fetched_via_spdy;
- // True if the npn was negotiated for this request.
- bool was_npn_negotiated;
+ // True if ALPN was negotiated for this request.
+ bool was_alpn_negotiated;
// True if the request was fetched via an explicit proxy. The proxy could
// be any type of proxy, HTTP or SOCKS. Note, we do not know if a
// transparent proxy may have been involved. If true, |proxy_server| contains
- // the name of the proxy server that was used.
+ // the proxy server that was used.
+ // TODO(tbansal): crbug.com/653354. Remove |was_fetched_via_proxy|.
bool was_fetched_via_proxy;
- HostPortPair proxy_server;
+ ProxyServer proxy_server;
// Whether the request use http proxy or server authentication.
bool did_use_http_auth;
@@ -152,7 +153,7 @@ class NET_EXPORT HttpResponseInfo {
HostPortPair socket_address;
// Protocol negotiated with the server.
- std::string npn_negotiated_protocol;
+ std::string alpn_negotiated_protocol;
// The type of connection used for this response.
ConnectionInfo connection_info;
diff --git a/chromium/net/http/http_response_info_unittest.cc b/chromium/net/http/http_response_info_unittest.cc
index 75ae43532c4..3490834ccc7 100644
--- a/chromium/net/http/http_response_info_unittest.cc
+++ b/chromium/net/http/http_response_info_unittest.cc
@@ -5,7 +5,13 @@
#include "net/http/http_response_info.h"
#include "base/pickle.h"
+#include "net/cert/signed_certificate_timestamp.h"
+#include "net/cert/signed_certificate_timestamp_and_status.h"
#include "net/http/http_response_headers.h"
+#include "net/ssl/ssl_connection_status_flags.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/ct_test_util.h"
+#include "net/test/test_data_directory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -23,7 +29,7 @@ class HttpResponseInfoTest : public testing::Test {
base::Pickle pickle;
response_info.Persist(&pickle, false, false);
bool truncated = false;
- restored_response_info->InitFromPickle(pickle, &truncated);
+ EXPECT_TRUE(restored_response_info->InitFromPickle(pickle, &truncated));
}
HttpResponseInfo response_info_;
@@ -90,6 +96,97 @@ TEST_F(HttpResponseInfoTest, AsyncRevalidationRequiredNotPersisted) {
EXPECT_FALSE(restored_response_info.async_revalidation_required);
}
+TEST_F(HttpResponseInfoTest, FailsInitFromPickleWithInvalidSCTStatus) {
+ // A valid certificate is needed for ssl_info.is_valid() to be true
+ // so that the SCTs would be serialized.
+ response_info_.ssl_info.cert =
+ ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
+
+ scoped_refptr<ct::SignedCertificateTimestamp> sct;
+ ct::GetX509CertSCT(&sct);
+
+ response_info_.ssl_info.signed_certificate_timestamps.push_back(
+ SignedCertificateTimestampAndStatus(
+ sct, ct::SCTVerifyStatus::SCT_STATUS_LOG_UNKNOWN));
+
+ base::Pickle pickle;
+ response_info_.Persist(&pickle, false, false);
+ bool truncated = false;
+ net::HttpResponseInfo restored_response_info;
+ EXPECT_TRUE(restored_response_info.InitFromPickle(pickle, &truncated));
+
+ response_info_.ssl_info.signed_certificate_timestamps.push_back(
+ SignedCertificateTimestampAndStatus(sct,
+ static_cast<ct::SCTVerifyStatus>(2)));
+ base::Pickle pickle_invalid;
+ response_info_.Persist(&pickle_invalid, false, false);
+ net::HttpResponseInfo restored_invalid_response;
+ EXPECT_FALSE(
+ restored_invalid_response.InitFromPickle(pickle_invalid, &truncated));
+}
+
+// Test that key_exchange_group is preserved for ECDHE ciphers.
+TEST_F(HttpResponseInfoTest, KeyExchangeGroupECDHE) {
+ response_info_.ssl_info.cert =
+ ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
+ SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_TLS1_2,
+ &response_info_.ssl_info.connection_status);
+ SSLConnectionStatusSetCipherSuite(
+ 0xcca8 /* TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 */,
+ &response_info_.ssl_info.connection_status);
+ response_info_.ssl_info.key_exchange_group = 23; // X25519
+ net::HttpResponseInfo restored_response_info;
+ PickleAndRestore(response_info_, &restored_response_info);
+ EXPECT_EQ(23, restored_response_info.ssl_info.key_exchange_group);
+}
+
+// Test that key_exchange_group is preserved for TLS 1.3.
+TEST_F(HttpResponseInfoTest, KeyExchangeGroupTLS13) {
+ response_info_.ssl_info.cert =
+ ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
+ SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_TLS1_3,
+ &response_info_.ssl_info.connection_status);
+ SSLConnectionStatusSetCipherSuite(0x1303 /* TLS_CHACHA20_POLY1305_SHA256 */,
+ &response_info_.ssl_info.connection_status);
+ response_info_.ssl_info.key_exchange_group = 23; // X25519
+ net::HttpResponseInfo restored_response_info;
+ PickleAndRestore(response_info_, &restored_response_info);
+ EXPECT_EQ(23, restored_response_info.ssl_info.key_exchange_group);
+}
+
+// Test that key_exchange_group is discarded for non-ECDHE ciphers prior to TLS
+// 1.3, to account for the historical key_exchange_info field. See
+// https://crbug.com/639421.
+TEST_F(HttpResponseInfoTest, LegacyKeyExchangeInfoDHE) {
+ response_info_.ssl_info.cert =
+ ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
+ SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_TLS1_2,
+ &response_info_.ssl_info.connection_status);
+ SSLConnectionStatusSetCipherSuite(
+ 0x0093 /* TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 */,
+ &response_info_.ssl_info.connection_status);
+ response_info_.ssl_info.key_exchange_group = 1024;
+ net::HttpResponseInfo restored_response_info;
+ PickleAndRestore(response_info_, &restored_response_info);
+ EXPECT_EQ(0, restored_response_info.ssl_info.key_exchange_group);
+}
+
+// Test that key_exchange_group is discarded for unknown ciphers prior to TLS
+// 1.3, to account for the historical key_exchange_info field. See
+// https://crbug.com/639421.
+TEST_F(HttpResponseInfoTest, LegacyKeyExchangeInfoUnknown) {
+ response_info_.ssl_info.cert =
+ ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
+ SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_TLS1_2,
+ &response_info_.ssl_info.connection_status);
+ SSLConnectionStatusSetCipherSuite(0xffff,
+ &response_info_.ssl_info.connection_status);
+ response_info_.ssl_info.key_exchange_group = 1024;
+ net::HttpResponseInfo restored_response_info;
+ PickleAndRestore(response_info_, &restored_response_info);
+ EXPECT_EQ(0, restored_response_info.ssl_info.key_exchange_group);
+}
+
} // namespace
} // namespace net
diff --git a/chromium/net/http/http_security_headers_unittest.cc b/chromium/net/http/http_security_headers_unittest.cc
index e4904dd1b5c..9203781e75b 100644
--- a/chromium/net/http/http_security_headers_unittest.cc
+++ b/chromium/net/http/http_security_headers_unittest.cc
@@ -13,7 +13,6 @@
#include "net/http/http_security_headers.h"
#include "net/http/http_util.h"
#include "net/http/transport_security_state.h"
-#include "net/log/net_log.h"
#include "net/ssl/ssl_info.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -790,9 +789,9 @@ TEST_F(HttpSecurityHeadersTest, UpdateDynamicPKPMaxAge0) {
std::string failure_log;
// Damage the hashes to cause a pin validation failure.
- new_static_pkp_state2.spki_hashes[0].data()[0] ^= 0x80;
- new_static_pkp_state2.spki_hashes[1].data()[0] ^= 0x80;
- new_static_pkp_state2.spki_hashes[2].data()[0] ^= 0x80;
+ for (size_t i = 0; i < new_static_pkp_state2.spki_hashes.size(); i++) {
+ new_static_pkp_state2.spki_hashes[i].data()[0] ^= 0x80;
+ }
const bool is_issued_by_known_root = true;
HostPortPair domain_port(domain, 443);
diff --git a/chromium/net/http/http_server_properties.cc b/chromium/net/http/http_server_properties.cc
index 98cf6c88eb3..15944114d21 100644
--- a/chromium/net/http/http_server_properties.cc
+++ b/chromium/net/http/http_server_properties.cc
@@ -12,11 +12,49 @@
namespace net {
+namespace {
+
+enum AlternativeProxyUsage {
+ // Alternative Proxy was used without racing a normal connection.
+ ALTERNATIVE_PROXY_USAGE_NO_RACE = 0,
+ // Alternative Proxy was used by winning a race with a normal connection.
+ ALTERNATIVE_PROXY_USAGE_WON_RACE = 1,
+ // Alternative Proxy was not used by losing a race with a normal connection.
+ ALTERNATIVE_PROXY_USAGE_LOST_RACE = 2,
+ // Maximum value for the enum.
+ ALTERNATIVE_PROXY_USAGE_MAX,
+};
+
+AlternativeProxyUsage ConvertProtocolUsageToProxyUsage(
+ AlternateProtocolUsage usage) {
+ switch (usage) {
+ case ALTERNATE_PROTOCOL_USAGE_NO_RACE:
+ return ALTERNATIVE_PROXY_USAGE_NO_RACE;
+ case ALTERNATE_PROTOCOL_USAGE_WON_RACE:
+ return ALTERNATIVE_PROXY_USAGE_WON_RACE;
+ case ALTERNATE_PROTOCOL_USAGE_LOST_RACE:
+ return ALTERNATIVE_PROXY_USAGE_LOST_RACE;
+ default:
+ NOTREACHED();
+ return ALTERNATIVE_PROXY_USAGE_MAX;
+ }
+}
+
+} // namespace anonymous
+
const char kAlternativeServiceHeader[] = "Alt-Svc";
-void HistogramAlternateProtocolUsage(AlternateProtocolUsage usage) {
- UMA_HISTOGRAM_ENUMERATION("Net.AlternateProtocolUsage", usage,
- ALTERNATE_PROTOCOL_USAGE_MAX);
+void HistogramAlternateProtocolUsage(AlternateProtocolUsage usage,
+ bool proxy_server_used) {
+ if (proxy_server_used) {
+ DCHECK_LE(usage, ALTERNATE_PROTOCOL_USAGE_LOST_RACE);
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicAlternativeProxy.Usage",
+ ConvertProtocolUsageToProxyUsage(usage),
+ ALTERNATIVE_PROXY_USAGE_MAX);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("Net.AlternateProtocolUsage", usage,
+ ALTERNATE_PROTOCOL_USAGE_MAX);
+ }
}
void HistogramBrokenAlternateProtocolLocation(
@@ -26,8 +64,16 @@ void HistogramBrokenAlternateProtocolLocation(
}
bool IsAlternateProtocolValid(AlternateProtocol protocol) {
- return protocol >= ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION &&
- protocol <= ALTERNATE_PROTOCOL_MAXIMUM_VALID_VERSION;
+ switch (protocol) {
+ case NPN_HTTP_2:
+ return true;
+ case QUIC:
+ return true;
+ case UNINITIALIZED_ALTERNATE_PROTOCOL:
+ return false;
+ }
+ NOTREACHED();
+ return false;
}
const char* AlternateProtocolToString(AlternateProtocol protocol) {
@@ -36,8 +82,6 @@ const char* AlternateProtocolToString(AlternateProtocol protocol) {
return "quic";
case NPN_HTTP_2:
return "h2";
- case NPN_SPDY_3_1:
- return "npn-spdy/3.1";
case UNINITIALIZED_ALTERNATE_PROTOCOL:
return "Uninitialized";
}
@@ -50,20 +94,19 @@ AlternateProtocol AlternateProtocolFromString(const std::string& str) {
return QUIC;
if (str == "h2")
return NPN_HTTP_2;
- // "npn-h2" is accepted here so that persisted settings with the old string
- // can be loaded from disk. TODO(bnc): Remove around 2016 December.
+ // "npn-h2" and "npn-spdy/3.1" are accepted here so that persisted settings
+ // with the old string can be loaded from disk. TODO(bnc): Remove around
+ // 2016 December.
if (str == "npn-h2")
return NPN_HTTP_2;
if (str == "npn-spdy/3.1")
- return NPN_SPDY_3_1;
+ return NPN_HTTP_2;
return UNINITIALIZED_ALTERNATE_PROTOCOL;
}
AlternateProtocol AlternateProtocolFromNextProto(NextProto next_proto) {
switch (next_proto) {
- case kProtoSPDY31:
- return NPN_SPDY_3_1;
case kProtoHTTP2:
return NPN_HTTP_2;
case kProtoQUIC1SPDY3:
@@ -96,8 +139,6 @@ std::string AlternativeServiceInfo::ToString() const {
void HttpServerProperties::ForceHTTP11(SSLConfig* ssl_config) {
ssl_config->alpn_protos.clear();
ssl_config->alpn_protos.push_back(kProtoHTTP11);
- ssl_config->npn_protos.clear();
- ssl_config->npn_protos.push_back(kProtoHTTP11);
}
} // namespace net
diff --git a/chromium/net/http/http_server_properties.h b/chromium/net/http/http_server_properties.h
index 5acc682e6f0..eaf0468701c 100644
--- a/chromium/net/http/http_server_properties.h
+++ b/chromium/net/http/http_server_properties.h
@@ -17,8 +17,8 @@
#include "base/time/time.h"
#include "net/base/host_port_pair.h"
#include "net/base/net_export.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_server_id.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_server_id.h"
#include "net/socket/next_proto.h"
#include "net/spdy/spdy_framer.h" // TODO(willchan): Reconsider this.
#include "net/spdy/spdy_protocol.h"
@@ -51,7 +51,8 @@ enum AlternateProtocolUsage {
};
// Log a histogram to reflect |usage|.
-NET_EXPORT void HistogramAlternateProtocolUsage(AlternateProtocolUsage usage);
+NET_EXPORT void HistogramAlternateProtocolUsage(AlternateProtocolUsage usage,
+ bool proxy_server_used);
enum BrokenAlternateProtocolLocation {
BROKEN_ALTERNATE_PROTOCOL_LOCATION_HTTP_STREAM_FACTORY_IMPL_JOB = 0,
@@ -66,27 +67,13 @@ NET_EXPORT void HistogramBrokenAlternateProtocolLocation(
BrokenAlternateProtocolLocation location);
enum AlternateProtocol {
- NPN_SPDY_3_1,
- ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION = NPN_SPDY_3_1,
- NPN_SPDY_MINIMUM_VERSION = NPN_SPDY_3_1,
NPN_HTTP_2,
- NPN_SPDY_MAXIMUM_VERSION = NPN_HTTP_2,
QUIC,
- ALTERNATE_PROTOCOL_MAXIMUM_VALID_VERSION = QUIC,
UNINITIALIZED_ALTERNATE_PROTOCOL,
};
-// Simply returns whether |protocol| is between
-// ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION and
-// ALTERNATE_PROTOCOL_MAXIMUM_VALID_VERSION (inclusive).
NET_EXPORT bool IsAlternateProtocolValid(AlternateProtocol protocol);
-enum AlternateProtocolSize {
- NUM_VALID_ALTERNATE_PROTOCOLS =
- ALTERNATE_PROTOCOL_MAXIMUM_VALID_VERSION -
- ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION + 1,
-};
-
NET_EXPORT const char* AlternateProtocolToString(AlternateProtocol protocol);
NET_EXPORT AlternateProtocol AlternateProtocolFromString(
const std::string& str);
@@ -234,6 +221,9 @@ class NET_EXPORT HttpServerProperties {
// Returns true if |server| supports a network protocol which honors
// request prioritization.
+ // Note that this also implies that the server supports request
+ // multiplexing, since priorities imply a relationship between
+ // multiple requests.
virtual bool SupportsRequestPriority(const url::SchemeHostPort& server) = 0;
// Returns the value set by SetSupportsSpdy(). If not set, returns false.
@@ -265,7 +255,8 @@ class NET_EXPORT HttpServerProperties {
// Set a single alternative service for |origin|. Previous alternative
// services for |origin| are discarded.
// |alternative_service.host| may be empty.
- // Return true if |alternative_service_map_| is changed.
+ // Return true if |alternative_service_map_| has changed significantly enough
+ // that it should be persisted to disk.
virtual bool SetAlternativeService(
const url::SchemeHostPort& origin,
const AlternativeService& alternative_service,
@@ -274,7 +265,9 @@ class NET_EXPORT HttpServerProperties {
// Set alternative services for |origin|. Previous alternative services for
// |origin| are discarded.
// Hostnames in |alternative_service_info_vector| may be empty.
- // Return true if |alternative_service_map_| is changed.
+ // |alternative_service_info_vector| may be empty.
+ // Return true if |alternative_service_map_| has changed significantly enough
+ // that it should be persisted to disk.
virtual bool SetAlternativeServices(
const url::SchemeHostPort& origin,
const AlternativeServiceInfoVector& alternative_service_info_vector) = 0;
diff --git a/chromium/net/http/http_server_properties_impl.cc b/chromium/net/http/http_server_properties_impl.cc
index 9e6e92e719d..f0489c86986 100644
--- a/chromium/net/http/http_server_properties_impl.cc
+++ b/chromium/net/http/http_server_properties_impl.cc
@@ -112,7 +112,7 @@ void HttpServerPropertiesImpl::InitializeAlternativeServiceServers(
url::SchemeHostPort canonical_server(kCanonicalScheme, canonical_suffix,
kCanonicalPort);
// If we already have a valid canonical server, we're done.
- if (ContainsKey(canonical_host_to_origin_map_, canonical_server) &&
+ if (base::ContainsKey(canonical_host_to_origin_map_, canonical_server) &&
(alternative_service_map_.Peek(
canonical_host_to_origin_map_[canonical_server]) !=
alternative_service_map_.end())) {
@@ -336,8 +336,7 @@ AlternativeServiceVector HttpServerPropertiesImpl::GetAlternativeServices(
// If the alternative service is equivalent to the origin (same host, same
// port, and both TCP), skip it.
if (host_port_pair.Equals(alternative_service.host_port_pair()) &&
- NPN_SPDY_MINIMUM_VERSION <= alternative_service.protocol &&
- alternative_service.protocol <= NPN_SPDY_MAXIMUM_VERSION) {
+ alternative_service.protocol == NPN_HTTP_2) {
++it;
continue;
}
@@ -413,8 +412,27 @@ bool HttpServerPropertiesImpl::SetAlternativeServices(
if (it != alternative_service_map_.end()) {
DCHECK(!it->second.empty());
if (it->second.size() == alternative_service_info_vector.size()) {
- changed = !std::equal(it->second.begin(), it->second.end(),
- alternative_service_info_vector.begin());
+ const base::Time now = base::Time::Now();
+ changed = false;
+ auto new_it = alternative_service_info_vector.begin();
+ for (const auto& old : it->second) {
+ // Persist to disk immediately if new entry has different scheme, host,
+ // or port.
+ if (old.alternative_service != new_it->alternative_service) {
+ changed = true;
+ break;
+ }
+ // Also persist to disk if new expiration it more that twice as far or
+ // less than half as far in the future.
+ base::Time old_time = old.expiration;
+ base::Time new_time = new_it->expiration;
+ if (new_time - now > 2 * (old_time - now) ||
+ 2 * (new_time - now) < (old_time - now)) {
+ changed = true;
+ break;
+ }
+ ++new_it;
+ }
}
}
@@ -428,7 +446,8 @@ bool HttpServerPropertiesImpl::SetAlternativeServices(
// TODO(rch): Consider the case where multiple requests are started
// before the first completes. In this case, only one of the jobs
// would reach this code, whereas all of them should should have.
- HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING);
+ HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING,
+ false);
}
// If this host ends with a canonical suffix, then set it as the
@@ -473,7 +492,8 @@ void HttpServerPropertiesImpl::MarkAlternativeServiceBroken(
void HttpServerPropertiesImpl::MarkAlternativeServiceRecentlyBroken(
const AlternativeService& alternative_service) {
- if (!ContainsKey(recently_broken_alternative_services_, alternative_service))
+ if (!base::ContainsKey(recently_broken_alternative_services_,
+ alternative_service))
recently_broken_alternative_services_[alternative_service] = 1;
}
@@ -481,15 +501,15 @@ bool HttpServerPropertiesImpl::IsAlternativeServiceBroken(
const AlternativeService& alternative_service) const {
// Empty host means use host of origin, callers are supposed to substitute.
DCHECK(!alternative_service.host.empty());
- return ContainsKey(broken_alternative_services_, alternative_service);
+ return base::ContainsKey(broken_alternative_services_, alternative_service);
}
bool HttpServerPropertiesImpl::WasAlternativeServiceRecentlyBroken(
const AlternativeService& alternative_service) {
if (alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
return false;
- return ContainsKey(recently_broken_alternative_services_,
- alternative_service);
+ return base::ContainsKey(recently_broken_alternative_services_,
+ alternative_service);
}
void HttpServerPropertiesImpl::ConfirmAlternativeService(
diff --git a/chromium/net/http/http_server_properties_impl_unittest.cc b/chromium/net/http/http_server_properties_impl_unittest.cc
index c566005d251..6031428ba7f 100644
--- a/chromium/net/http/http_server_properties_impl_unittest.cc
+++ b/chromium/net/http/http_server_properties_impl_unittest.cc
@@ -441,7 +441,7 @@ TEST_F(AlternateProtocolServerPropertiesTest, Initialize) {
// |alternative_service_map| has an entry for
// |test_server2|.
AlternativeServiceInfoVector alternative_service_info_vector;
- const AlternativeService alternative_service2(NPN_SPDY_3_1, "bar2", 443);
+ const AlternativeService alternative_service2(NPN_HTTP_2, "bar2", 443);
base::Time expiration2 = now + base::TimeDelta::FromDays(2);
alternative_service_info_vector.push_back(
AlternativeServiceInfo(alternative_service2, expiration2));
@@ -627,7 +627,7 @@ TEST_F(AlternateProtocolServerPropertiesTest, ClearServerWithCanonical) {
TEST_F(AlternateProtocolServerPropertiesTest, MRUOfGetAlternativeServices) {
url::SchemeHostPort test_server1("http", "foo1", 80);
- const AlternativeService alternative_service1(NPN_SPDY_3_1, "foo1", 443);
+ const AlternativeService alternative_service1(NPN_HTTP_2, "foo1", 443);
SetAlternativeService(test_server1, alternative_service1);
url::SchemeHostPort test_server2("http", "foo2", 80);
const AlternativeService alternative_service2(NPN_HTTP_2, "foo2", 1234);
@@ -699,7 +699,7 @@ TEST_F(AlternateProtocolServerPropertiesTest, MaxAge) {
// First alternative service expired one day ago, should not be returned by
// GetAlternativeServices().
- const AlternativeService alternative_service1(NPN_SPDY_3_1, "foo", 443);
+ const AlternativeService alternative_service1(NPN_HTTP_2, "foo", 443);
alternative_service_info_vector.push_back(
AlternativeServiceInfo(alternative_service1, now - one_day));
@@ -725,7 +725,7 @@ TEST_F(AlternateProtocolServerPropertiesTest, MaxAgeCanonical) {
// First alternative service expired one day ago, should not be returned by
// GetAlternativeServices().
- const AlternativeService alternative_service1(NPN_SPDY_3_1, "foo", 443);
+ const AlternativeService alternative_service1(NPN_HTTP_2, "foo", 443);
alternative_service_info_vector.push_back(
AlternativeServiceInfo(alternative_service1, now - one_day));
@@ -748,7 +748,7 @@ TEST_F(AlternateProtocolServerPropertiesTest, MaxAgeCanonical) {
TEST_F(AlternateProtocolServerPropertiesTest, AlternativeServiceWithScheme) {
AlternativeServiceInfoVector alternative_service_info_vector;
- const AlternativeService alternative_service1(NPN_SPDY_3_1, "foo", 443);
+ const AlternativeService alternative_service1(NPN_HTTP_2, "foo", 443);
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
alternative_service_info_vector.push_back(
AlternativeServiceInfo(alternative_service1, expiration));
@@ -784,7 +784,7 @@ TEST_F(AlternateProtocolServerPropertiesTest, AlternativeServiceWithScheme) {
TEST_F(AlternateProtocolServerPropertiesTest, ClearAlternativeServices) {
AlternativeServiceInfoVector alternative_service_info_vector;
- const AlternativeService alternative_service1(NPN_SPDY_3_1, "foo", 443);
+ const AlternativeService alternative_service1(NPN_HTTP_2, "foo", 443);
base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
alternative_service_info_vector.push_back(
AlternativeServiceInfo(alternative_service1, expiration));
diff --git a/chromium/net/http/http_server_properties_manager.cc b/chromium/net/http/http_server_properties_manager.cc
index 467c5b80454..1f91bb691d9 100644
--- a/chromium/net/http/http_server_properties_manager.cc
+++ b/chromium/net/http/http_server_properties_manager.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
@@ -1110,20 +1111,22 @@ void HttpServerPropertiesManager::UpdatePrefsOnPrefThread(
const url::SchemeHostPort server = map_it->first;
const ServerPref& server_pref = map_it->second;
- base::DictionaryValue* servers_dict = new base::DictionaryValue;
- base::DictionaryValue* server_pref_dict = new base::DictionaryValue;
+ auto servers_dict = base::MakeUnique<base::DictionaryValue>();
+ auto server_pref_dict = base::MakeUnique<base::DictionaryValue>();
// Save supports_spdy.
if (server_pref.supports_spdy)
server_pref_dict->SetBoolean(kSupportsSpdyKey, server_pref.supports_spdy);
- SaveSpdySettingsToServerPrefs(server_pref.settings_map, server_pref_dict);
+ SaveSpdySettingsToServerPrefs(server_pref.settings_map,
+ server_pref_dict.get());
SaveAlternativeServiceToServerPrefs(
- server_pref.alternative_service_info_vector, server_pref_dict);
+ server_pref.alternative_service_info_vector, server_pref_dict.get());
SaveNetworkStatsToServerPrefs(server_pref.server_network_stats,
- server_pref_dict);
+ server_pref_dict.get());
- servers_dict->SetWithoutPathExpansion(server.Serialize(), server_pref_dict);
- bool value = servers_list->AppendIfNotPresent(servers_dict);
+ servers_dict->SetWithoutPathExpansion(server.Serialize(),
+ std::move(server_pref_dict));
+ bool value = servers_list->AppendIfNotPresent(std::move(servers_dict));
DCHECK(value); // Should never happen.
}
diff --git a/chromium/net/http/http_server_properties_manager.h b/chromium/net/http/http_server_properties_manager.h
index 988ab4a8ece..28167c8e6c8 100644
--- a/chromium/net/http/http_server_properties_manager.h
+++ b/chromium/net/http/http_server_properties_manager.h
@@ -18,6 +18,7 @@
#include "base/timer/timer.h"
#include "base/values.h"
#include "net/base/host_port_pair.h"
+#include "net/base/net_export.h"
#include "net/http/http_server_properties.h"
#include "net/http/http_server_properties_impl.h"
diff --git a/chromium/net/http/http_server_properties_manager_unittest.cc b/chromium/net/http/http_server_properties_manager_unittest.cc
index 51f509496a9..1f999a92b13 100644
--- a/chromium/net/http/http_server_properties_manager_unittest.cc
+++ b/chromium/net/http/http_server_properties_manager_unittest.cc
@@ -10,6 +10,7 @@
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
@@ -263,16 +264,15 @@ TEST_P(HttpServerPropertiesManagerTest,
server_pref_dict->SetWithoutPathExpansion("network_stats", stats);
// Set the server preference for https://www.google.com.
- base::DictionaryValue* servers_dict = new base::DictionaryValue;
+ auto servers_dict = base::MakeUnique<base::DictionaryValue>();
servers_dict->SetWithoutPathExpansion(
GetParam() >= 5 ? "https://www.google.com" : "www.google.com:443",
server_pref_dict);
base::ListValue* servers_list = nullptr;
if (GetParam() >= 4) {
servers_list = new base::ListValue;
- // |servers_list| takes ownership of |servers_dict|.
- servers_list->AppendIfNotPresent(servers_dict);
- servers_dict = new base::DictionaryValue;
+ servers_list->AppendIfNotPresent(std::move(servers_dict));
+ servers_dict = base::MakeUnique<base::DictionaryValue>();
}
// Set the preference for mail.google.com server.
@@ -284,7 +284,7 @@ TEST_P(HttpServerPropertiesManagerTest,
// Set up alternative_services for https://mail.google.com.
std::unique_ptr<base::DictionaryValue> alternative_service_dict2(
new base::DictionaryValue);
- alternative_service_dict2->SetString("protocol_str", "npn-spdy/3.1");
+ alternative_service_dict2->SetString("protocol_str", "h2");
alternative_service_dict2->SetInteger("port", 444);
base::ListValue* alternative_service_list1 = new base::ListValue;
alternative_service_list1->Append(std::move(alternative_service_dict2));
@@ -302,8 +302,7 @@ TEST_P(HttpServerPropertiesManagerTest,
server_pref_dict1);
base::DictionaryValue http_server_properties_dict;
if (GetParam() >= 4) {
- // |servers_list| takes ownership of |servers_dict|.
- servers_list->AppendIfNotPresent(servers_dict);
+ servers_list->AppendIfNotPresent(std::move(servers_dict));
if (GetParam() == 5) {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, -1);
} else {
@@ -315,8 +314,8 @@ TEST_P(HttpServerPropertiesManagerTest,
} else {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict,
GetParam());
- http_server_properties_dict.SetWithoutPathExpansion("servers",
- servers_dict);
+ http_server_properties_dict.SetWithoutPathExpansion(
+ "servers", std::move(servers_dict));
}
base::DictionaryValue* supports_quic = new base::DictionaryValue;
supports_quic->SetBoolean("used_quic", true);
@@ -382,7 +381,7 @@ TEST_P(HttpServerPropertiesManagerTest,
AlternativeServiceMap::const_iterator map_it = map.begin();
EXPECT_EQ("mail.google.com", map_it->first.host());
ASSERT_EQ(1u, map_it->second.size());
- EXPECT_EQ(NPN_SPDY_3_1, map_it->second[0].alternative_service.protocol);
+ EXPECT_EQ(NPN_HTTP_2, map_it->second[0].alternative_service.protocol);
EXPECT_TRUE(map_it->second[0].alternative_service.host.empty());
EXPECT_EQ(444, map_it->second[0].alternative_service.port);
++map_it;
@@ -410,7 +409,7 @@ TEST_P(HttpServerPropertiesManagerTest,
++map_it;
EXPECT_EQ("mail.google.com", map_it->first.host());
ASSERT_EQ(1u, map_it->second.size());
- EXPECT_EQ(NPN_SPDY_3_1, map_it->second[0].alternative_service.protocol);
+ EXPECT_EQ(NPN_HTTP_2, map_it->second[0].alternative_service.protocol);
EXPECT_TRUE(map_it->second[0].alternative_service.host.empty());
EXPECT_EQ(444, map_it->second[0].alternative_service.port);
}
@@ -475,14 +474,13 @@ TEST_P(HttpServerPropertiesManagerTest, BadCachedHostPortPair) {
server_pref_dict->SetWithoutPathExpansion("network_stats", stats);
// Set the server preference for www.google.com:65536.
- base::DictionaryValue* servers_dict = new base::DictionaryValue;
+ auto servers_dict = base::MakeUnique<base::DictionaryValue>();
servers_dict->SetWithoutPathExpansion("www.google.com:65536",
server_pref_dict);
base::DictionaryValue http_server_properties_dict;
if (GetParam() >= 4) {
base::ListValue* servers_list = new base::ListValue;
- // |servers_list| takes ownership of |servers_dict|.
- servers_list->AppendIfNotPresent(servers_dict);
+ servers_list->AppendIfNotPresent(std::move(servers_dict));
if (GetParam() == 5) {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, -1);
} else {
@@ -494,8 +492,8 @@ TEST_P(HttpServerPropertiesManagerTest, BadCachedHostPortPair) {
} else {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict,
GetParam());
- http_server_properties_dict.SetWithoutPathExpansion("servers",
- servers_dict);
+ http_server_properties_dict.SetWithoutPathExpansion(
+ "servers", std::move(servers_dict));
}
// Set quic_server_info for www.google.com:65536.
@@ -552,13 +550,12 @@ TEST_P(HttpServerPropertiesManagerTest, BadCachedAltProtocolPort) {
alternative_service_list);
// Set the server preference for www.google.com:80.
- base::DictionaryValue* servers_dict = new base::DictionaryValue;
+ auto servers_dict = base::MakeUnique<base::DictionaryValue>();
servers_dict->SetWithoutPathExpansion("www.google.com:80", server_pref_dict);
base::DictionaryValue http_server_properties_dict;
if (GetParam() >= 4) {
base::ListValue* servers_list = new base::ListValue;
- // |servers_list| takes ownership of |servers_dict|.
- servers_list->AppendIfNotPresent(servers_dict);
+ servers_list->AppendIfNotPresent(std::move(servers_dict));
if (GetParam() == 5) {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, -1);
} else {
@@ -570,8 +567,8 @@ TEST_P(HttpServerPropertiesManagerTest, BadCachedAltProtocolPort) {
} else {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict,
GetParam());
- http_server_properties_dict.SetWithoutPathExpansion("servers",
- servers_dict);
+ http_server_properties_dict.SetWithoutPathExpansion(
+ "servers", std::move(servers_dict));
}
// Set up the pref.
@@ -972,7 +969,7 @@ TEST_P(HttpServerPropertiesManagerTest, Clear) {
TEST_P(HttpServerPropertiesManagerTest, BadSupportsQuic) {
ExpectCacheUpdate();
- base::DictionaryValue* servers_dict = new base::DictionaryValue;
+ auto servers_dict = base::MakeUnique<base::DictionaryValue>();
base::ListValue* servers_list = nullptr;
if (GetParam() >= 4)
servers_list = new base::ListValue;
@@ -996,9 +993,8 @@ TEST_P(HttpServerPropertiesManagerTest, BadSupportsQuic) {
StringPrintf("www.google.com:%d", i), server_pref_dict);
}
if (GetParam() >= 4) {
- // |servers_list| takes ownership of |servers_dict|.
- servers_list->AppendIfNotPresent(servers_dict);
- servers_dict = new base::DictionaryValue;
+ servers_list->AppendIfNotPresent(std::move(servers_dict));
+ servers_dict = base::MakeUnique<base::DictionaryValue>();
}
}
@@ -1013,8 +1009,7 @@ TEST_P(HttpServerPropertiesManagerTest, BadSupportsQuic) {
}
base::DictionaryValue http_server_properties_dict;
if (GetParam() >= 4) {
- // |servers_list| takes ownership of |servers_dict|.
- servers_list->AppendIfNotPresent(servers_dict);
+ servers_list->AppendIfNotPresent(std::move(servers_dict));
if (GetParam() == 5) {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, -1);
} else {
@@ -1026,8 +1021,8 @@ TEST_P(HttpServerPropertiesManagerTest, BadSupportsQuic) {
} else {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict,
GetParam());
- http_server_properties_dict.SetWithoutPathExpansion("servers",
- servers_dict);
+ http_server_properties_dict.SetWithoutPathExpansion(
+ "servers", std::move(servers_dict));
}
// Set up SupportsQuic for 127.0.0.1
@@ -1087,7 +1082,7 @@ TEST_P(HttpServerPropertiesManagerTest, UpdateCacheWithPrefs) {
http_server_props_manager_->SetAlternativeServices(
server_www, alternative_service_info_vector);
- AlternativeService mail_alternative_service(NPN_SPDY_3_1, "foo.google.com",
+ AlternativeService mail_alternative_service(NPN_HTTP_2, "foo.google.com",
444);
base::Time expiration3 = base::Time::Max();
http_server_props_manager_->SetAlternativeService(
@@ -1126,7 +1121,7 @@ TEST_P(HttpServerPropertiesManagerTest, UpdateCacheWithPrefs) {
"\"port\":1234,\"protocol_str\":\"h2\"}]}},"
"{\"http://mail.google.com\":{\"alternative_service\":[{"
"\"expiration\":\"9223372036854775807\",\"host\":\"foo.google.com\","
- "\"port\":444,\"protocol_str\":\"npn-spdy/3.1\"}],"
+ "\"port\":444,\"protocol_str\":\"h2\"}],"
"\"network_stats\":{\"srtt\":42}}}"
"],"
"\"supports_quic\":{\"address\":\"127.0.0.1\",\"used_quic\":true},"
diff --git a/chromium/net/http/http_stream.h b/chromium/net/http/http_stream.h
index 8aeec0650ab..b161a8702f2 100644
--- a/chromium/net/http/http_stream.h
+++ b/chromium/net/http/http_stream.h
@@ -22,7 +22,7 @@
#include "net/base/net_errors.h"
#include "net/base/net_export.h"
#include "net/base/request_priority.h"
-#include "net/base/upload_progress.h"
+#include "net/ssl/token_binding.h"
namespace crypto {
class ECPrivateKey;
@@ -30,7 +30,6 @@ class ECPrivateKey;
namespace net {
-class BoundNetLog;
class HttpNetworkSession;
class HttpRequestHeaders;
struct HttpRequestInfo;
@@ -38,6 +37,7 @@ class HttpResponseInfo;
class IOBuffer;
class IPEndPoint;
struct LoadTimingInfo;
+class NetLogWithSource;
class SSLCertRequestInfo;
class SSLInfo;
@@ -51,7 +51,7 @@ class NET_EXPORT_PRIVATE HttpStream {
// Returns a net error code, possibly ERR_IO_PENDING.
virtual int InitializeStream(const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback) = 0;
// Writes the headers and uploads body data to the underlying socket.
@@ -158,10 +158,12 @@ class NET_EXPORT_PRIVATE HttpStream {
// and does not modify |endpoint| if it is unavailable.
virtual bool GetRemoteEndpoint(IPEndPoint* endpoint) = 0;
- // Signs the EKM value for Token Binding from the TLS layer using |*key| and
- // puts the result in |*out|. Returns OK or ERR_FAILED.
- virtual Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) = 0;
+ // Generates the signature used in Token Binding using |*key| and for a Token
+ // Binding of type |tb_type|, putting the signature in |*out|. Returns OK or
+ // ERR_FAILED.
+ virtual Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) = 0;
// In the case of an HTTP error or redirect, flush the response body (usually
// a simple error or "this page has moved") so that we can re-use the
@@ -177,9 +179,6 @@ class NET_EXPORT_PRIVATE HttpStream {
// Called when the priority of the parent transaction changes.
virtual void SetPriority(RequestPriority priority) = 0;
- // Queries the UploadDataStream for its progress (bytes sent).
- virtual UploadProgress GetUploadProgress() const = 0;
-
// Returns a new (not initialized) stream using the same underlying
// connection and invalidates the old stream - no further methods should be
// called on the old stream. The caller should ensure that the response body
diff --git a/chromium/net/http/http_stream_factory.cc b/chromium/net/http/http_stream_factory.cc
index e97323ddb96..82c51e9fe0f 100644
--- a/chromium/net/http/http_stream_factory.cc
+++ b/chromium/net/http/http_stream_factory.cc
@@ -15,25 +15,14 @@
#include "net/base/port_util.h"
#include "net/http/http_network_session.h"
#include "net/http/http_response_headers.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/spdy/spdy_alt_svc_wire_format.h"
#include "url/gurl.h"
namespace net {
-// WARNING: If you modify or add any static flags, you must keep them in sync
-// with |ResetStaticSettingsToInit|. This is critical for unit test isolation.
-
-// static
-bool HttpStreamFactory::spdy_enabled_ = true;
-
HttpStreamFactory::~HttpStreamFactory() {}
-// static
-void HttpStreamFactory::ResetStaticSettingsToInit() {
- spdy_enabled_ = true;
-}
-
void HttpStreamFactory::ProcessAlternativeServices(
HttpNetworkSession* session,
const HttpResponseHeaders* headers,
diff --git a/chromium/net/http/http_stream_factory.h b/chromium/net/http/http_stream_factory.h
index b3afa2ac17f..7a094f6613b 100644
--- a/chromium/net/http/http_stream_factory.h
+++ b/chromium/net/http/http_stream_factory.h
@@ -31,7 +31,6 @@ class Value;
namespace net {
class AuthCredentials;
-class BoundNetLog;
class BidirectionalStreamImpl;
class HostMappingRules;
class HostPortPair;
@@ -41,6 +40,7 @@ class HttpResponseHeaders;
class HttpResponseInfo;
class HttpServerProperties;
class HttpStream;
+class NetLogWithSource;
class ProxyInfo;
class SSLCertRequestInfo;
class SSLInfo;
@@ -180,11 +180,11 @@ class NET_EXPORT_PRIVATE HttpStreamRequest {
// Returns the LoadState for the request.
virtual LoadState GetLoadState() const = 0;
- // Returns true if TLS/NPN was negotiated for this stream.
- virtual bool was_npn_negotiated() const = 0;
+ // Returns true if TLS/ALPN was negotiated for this stream.
+ virtual bool was_alpn_negotiated() const = 0;
// Protocol negotiated with the server.
- virtual NextProto protocol_negotiated() const = 0;
+ virtual NextProto negotiated_protocol() const = 0;
// Returns true if this stream is being fetched over SPDY.
virtual bool using_spdy() const = 0;
@@ -212,7 +212,7 @@ class NET_EXPORT HttpStreamFactory {
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::Delegate* delegate,
- const BoundNetLog& net_log) = 0;
+ const NetLogWithSource& net_log) = 0;
// Request a WebSocket handshake stream.
// Will call delegate->OnWebSocketHandshakeStreamReady on successful
@@ -224,7 +224,7 @@ class NET_EXPORT HttpStreamFactory {
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::Delegate* delegate,
WebSocketHandshakeStreamBase::CreateHelper* create_helper,
- const BoundNetLog& net_log) = 0;
+ const NetLogWithSource& net_log) = 0;
// Request a BidirectionalStreamImpl.
// Will call delegate->OnBidirectionalStreamImplReady on successful
@@ -235,7 +235,7 @@ class NET_EXPORT HttpStreamFactory {
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::Delegate* delegate,
- const BoundNetLog& net_log) = 0;
+ const NetLogWithSource& net_log) = 0;
// Requests that enough connections for |num_streams| be opened.
virtual void PreconnectStreams(int num_streams,
@@ -243,25 +243,10 @@ class NET_EXPORT HttpStreamFactory {
virtual const HostMappingRules* GetHostMappingRules() const = 0;
- // Static settings
-
- // Reset all static settings to initialized values. Used to init test suite.
- static void ResetStaticSettingsToInit();
-
- // Turns spdy on or off.
- // TODO(mmenke): Figure out if this can be made a property of the
- // HttpNetworkSession.
- static void set_spdy_enabled(bool value) {
- spdy_enabled_ = value;
- }
- static bool spdy_enabled() { return spdy_enabled_; }
-
protected:
HttpStreamFactory();
private:
- static bool spdy_enabled_;
-
url::SchemeHostPort RewriteHost(const url::SchemeHostPort& server);
DISALLOW_COPY_AND_ASSIGN(HttpStreamFactory);
diff --git a/chromium/net/http/http_stream_factory_impl.cc b/chromium/net/http/http_stream_factory_impl.cc
index ced9ce3d1db..5ba08cf0beb 100644
--- a/chromium/net/http/http_stream_factory_impl.cc
+++ b/chromium/net/http/http_stream_factory_impl.cc
@@ -16,11 +16,11 @@
#include "net/http/http_stream_factory_impl_job_controller.h"
#include "net/http/http_stream_factory_impl_request.h"
#include "net/http/transport_security_state.h"
-#include "net/log/net_log.h"
-#include "net/quic/quic_server_id.h"
+#include "net/quic/core/quic_server_id.h"
#include "net/spdy/bidirectional_stream_spdy_impl.h"
#include "net/spdy/spdy_http_stream.h"
#include "url/gurl.h"
+#include "url/url_constants.h"
namespace net {
@@ -63,7 +63,25 @@ class DefaultJobFactory : public HttpStreamFactoryImpl::JobFactory {
return new HttpStreamFactoryImpl::Job(
delegate, job_type, session, request_info, priority, server_ssl_config,
proxy_ssl_config, destination, origin_url, alternative_service,
- net_log);
+ ProxyServer(), net_log);
+ }
+
+ HttpStreamFactoryImpl::Job* CreateJob(
+ HttpStreamFactoryImpl::Job::Delegate* delegate,
+ HttpStreamFactoryImpl::JobType job_type,
+ HttpNetworkSession* session,
+ const HttpRequestInfo& request_info,
+ RequestPriority priority,
+ const SSLConfig& server_ssl_config,
+ const SSLConfig& proxy_ssl_config,
+ HostPortPair destination,
+ GURL origin_url,
+ const ProxyServer& alternative_proxy_server,
+ NetLog* net_log) override {
+ return new HttpStreamFactoryImpl::Job(
+ delegate, job_type, session, request_info, priority, server_ssl_config,
+ proxy_ssl_config, destination, origin_url, AlternativeService(),
+ alternative_proxy_server, net_log);
}
};
} // anonymous namespace
@@ -85,7 +103,7 @@ HttpStreamRequest* HttpStreamFactoryImpl::RequestStream(
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::Delegate* delegate,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
DCHECK(!for_websockets_);
return RequestStreamInternal(request_info, priority, server_ssl_config,
proxy_ssl_config, delegate, nullptr,
@@ -99,7 +117,7 @@ HttpStreamRequest* HttpStreamFactoryImpl::RequestWebSocketHandshakeStream(
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::Delegate* delegate,
WebSocketHandshakeStreamBase::CreateHelper* create_helper,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
DCHECK(for_websockets_);
DCHECK(create_helper);
return RequestStreamInternal(request_info, priority, server_ssl_config,
@@ -113,7 +131,7 @@ HttpStreamRequest* HttpStreamFactoryImpl::RequestBidirectionalStreamImpl(
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::Delegate* delegate,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
DCHECK(!for_websockets_);
DCHECK(request_info.url.SchemeIs(url::kHttpsScheme));
@@ -131,7 +149,7 @@ HttpStreamRequest* HttpStreamFactoryImpl::RequestStreamInternal(
WebSocketHandshakeStreamBase::CreateHelper*
websocket_handshake_stream_create_helper,
HttpStreamRequest::StreamType stream_type,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
JobController* job_controller =
new JobController(this, delegate, session_, job_factory_.get());
job_controller_set_.insert(base::WrapUnique(job_controller));
@@ -171,10 +189,10 @@ void HttpStreamFactoryImpl::OnNewSpdySessionReady(
bool direct,
const SSLConfig& used_ssl_config,
const ProxyInfo& used_proxy_info,
- bool was_npn_negotiated,
- NextProto protocol_negotiated,
+ bool was_alpn_negotiated,
+ NextProto negotiated_protocol,
bool using_spdy,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
while (true) {
if (!spdy_session)
break;
@@ -186,10 +204,10 @@ void HttpStreamFactoryImpl::OnNewSpdySessionReady(
// TODO(willchan): If it's important, switch RequestSet out for a FIFO
// queue (Order by priority first, then FIFO within same priority). Unclear
// that it matters here.
- if (!ContainsKey(spdy_session_request_map_, spdy_session_key))
+ if (!base::ContainsKey(spdy_session_request_map_, spdy_session_key))
break;
Request* request = *spdy_session_request_map_[spdy_session_key].begin();
- request->Complete(was_npn_negotiated, protocol_negotiated, using_spdy);
+ request->Complete(was_alpn_negotiated, negotiated_protocol, using_spdy);
if (for_websockets_) {
// TODO(ricea): Restore this code path when WebSocket over SPDY
// implementation is ready.
@@ -200,7 +218,8 @@ void HttpStreamFactoryImpl::OnNewSpdySessionReady(
used_ssl_config, used_proxy_info,
new BidirectionalStreamSpdyImpl(spdy_session));
} else {
- bool use_relative_url = direct || request->url().SchemeIs("https");
+ bool use_relative_url =
+ direct || request->url().SchemeIs(url::kHttpsScheme);
request->OnStreamReady(
used_ssl_config, used_proxy_info,
new SpdyHttpStream(spdy_session, use_relative_url));
diff --git a/chromium/net/http/http_stream_factory_impl.h b/chromium/net/http/http_stream_factory_impl.h
index ed5a9c4a740..e99bb721ccc 100644
--- a/chromium/net/http/http_stream_factory_impl.h
+++ b/chromium/net/http/http_stream_factory_impl.h
@@ -15,8 +15,8 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "net/base/host_port_pair.h"
+#include "net/base/net_export.h"
#include "net/http/http_stream_factory.h"
-#include "net/log/net_log.h"
#include "net/proxy/proxy_server.h"
#include "net/socket/ssl_client_socket.h"
#include "net/spdy/spdy_session_key.h"
@@ -25,6 +25,7 @@ namespace net {
class HttpNetworkSession;
class SpdySession;
+class NetLogWithSource;
class NET_EXPORT_PRIVATE HttpStreamFactoryImpl : public HttpStreamFactory {
public:
@@ -44,7 +45,7 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl : public HttpStreamFactory {
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::Delegate* delegate,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
HttpStreamRequest* RequestWebSocketHandshakeStream(
const HttpRequestInfo& info,
@@ -53,7 +54,7 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl : public HttpStreamFactory {
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::Delegate* delegate,
WebSocketHandshakeStreamBase::CreateHelper* create_helper,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
HttpStreamRequest* RequestBidirectionalStreamImpl(
const HttpRequestInfo& info,
@@ -61,7 +62,7 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl : public HttpStreamFactory {
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::Delegate* delegate,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void PreconnectStreams(int num_streams, const HttpRequestInfo& info) override;
const HostMappingRules* GetHostMappingRules() const override;
@@ -101,7 +102,7 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl : public HttpStreamFactory {
HttpStreamRequest::Delegate* delegate,
WebSocketHandshakeStreamBase::CreateHelper* create_helper,
HttpStreamRequest::StreamType stream_type,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Called when a SpdySession is ready. It will find appropriate Requests and
// fulfill them. |direct| indicates whether or not |spdy_session| uses a
@@ -110,10 +111,10 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl : public HttpStreamFactory {
bool direct,
const SSLConfig& used_ssl_config,
const ProxyInfo& used_proxy_info,
- bool was_npn_negotiated,
- NextProto protocol_negotiated,
+ bool was_alpn_negotiated,
+ NextProto negotiated_protocol,
bool using_spdy,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Called when the Job detects that the endpoint indicated by the
// Alternate-Protocol does not work. Lets the factory update
diff --git a/chromium/net/http/http_stream_factory_impl_job.cc b/chromium/net/http/http_stream_factory_impl_job.cc
index 1c8451b5555..06cf1bbbb3d 100644
--- a/chromium/net/http/http_stream_factory_impl_job.cc
+++ b/chromium/net/http/http_stream_factory_impl_job.cc
@@ -6,7 +6,6 @@
#include <algorithm>
#include <string>
-#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -25,6 +24,7 @@
#include "base/values.h"
#include "build/build_config.h"
#include "net/base/port_util.h"
+#include "net/base/proxy_delegate.h"
#include "net/cert/cert_verifier.h"
#include "net/http/bidirectional_stream_impl.h"
#include "net/http/http_basic_stream.h"
@@ -35,8 +35,11 @@
#include "net/http/http_server_properties.h"
#include "net/http/http_stream_factory.h"
#include "net/http/http_stream_factory_impl_request.h"
-#include "net/log/net_log.h"
-#include "net/quic/quic_http_stream.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
+#include "net/quic/chromium/quic_http_stream.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool.h"
#include "net/socket/client_socket_pool_manager.h"
@@ -51,12 +54,13 @@
#include "net/ssl/channel_id_service.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/ssl/ssl_connection_status_flags.h"
+#include "url/url_constants.h"
namespace net {
namespace {
-void DoNothingAsyncCallback(int result){};
+void DoNothingAsyncCallback(int result) {}
void RecordChannelIDKeyMatch(SSLClientSocket* ssl_socket,
ChannelIDService* channel_id_service,
std::string host) {
@@ -113,7 +117,7 @@ void RecordChannelIDKeyMatch(SSLClientSocket* ssl_socket,
// Returns parameters associated with the start of a HTTP stream job.
std::unique_ptr<base::Value> NetLogHttpStreamJobCallback(
- const NetLog::Source& source,
+ const NetLogSource& source,
const GURL* original_url,
const GURL* url,
const AlternativeService* alternative_service,
@@ -129,26 +133,15 @@ std::unique_ptr<base::Value> NetLogHttpStreamJobCallback(
return std::move(dict);
}
-// Returns parameters associated with the delay of the HTTP stream job.
-std::unique_ptr<base::Value> NetLogHttpStreamJobDelayCallback(
- base::TimeDelta delay,
- NetLogCaptureMode /* capture_mode */) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetInteger("resume_after_ms", static_cast<int>(delay.InMilliseconds()));
- return std::move(dict);
-}
-
// Returns parameters associated with the Proto (with NPN negotiation) of a HTTP
// stream.
std::unique_ptr<base::Value> NetLogHttpStreamProtoCallback(
- const SSLClientSocket::NextProtoStatus status,
- const std::string* proto,
+ NextProto negotiated_protocol,
NetLogCaptureMode /* capture_mode */) {
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetString("next_proto_status",
- SSLClientSocket::NextProtoStatusToString(status));
- dict->SetString("proto", *proto);
+ dict->SetString("proto",
+ SSLClientSocket::NextProtoToString(negotiated_protocol));
return std::move(dict);
}
@@ -172,6 +165,7 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate,
destination,
origin_url,
AlternativeService(),
+ ProxyServer(),
net_log) {}
HttpStreamFactoryImpl::Job::Job(Delegate* delegate,
@@ -184,12 +178,14 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate,
HostPortPair destination,
GURL origin_url,
AlternativeService alternative_service,
+ const ProxyServer& alternative_proxy_server,
NetLog* net_log)
: request_info_(request_info),
priority_(priority),
server_ssl_config_(server_ssl_config),
proxy_ssl_config_(proxy_ssl_config),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_HTTP_STREAM_JOB)),
+ net_log_(
+ NetLogWithSource::Make(net_log, NetLogSourceType::HTTP_STREAM_JOB)),
io_callback_(base::Bind(&Job::OnIOComplete, base::Unretained(this))),
connection_(new ClientSocketHandle),
session_(session),
@@ -198,28 +194,42 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate,
destination_(destination),
origin_url_(origin_url),
alternative_service_(alternative_service),
+ alternative_proxy_server_(alternative_proxy_server),
delegate_(delegate),
job_type_(job_type),
- blocking_job_(NULL),
- waiting_job_(NULL),
using_ssl_(false),
using_spdy_(false),
using_quic_(false),
quic_request_(session_->quic_stream_factory()),
using_existing_quic_session_(false),
- spdy_certificate_error_(OK),
establishing_tunnel_(false),
- was_npn_negotiated_(false),
- protocol_negotiated_(kProtoUnknown),
+ was_alpn_negotiated_(false),
+ negotiated_protocol_(kProtoUnknown),
num_streams_(0),
spdy_session_direct_(false),
- job_status_(STATUS_RUNNING),
- other_job_status_(STATUS_RUNNING),
stream_type_(HttpStreamRequest::BIDIRECTIONAL_STREAM),
ptr_factory_(this) {
DCHECK(session);
+ // The job can't have alternative service and alternative proxy server set at
+ // the same time since alternative services are used for requests that are
+ // fetched directly, while the alternative proxy server is used for requests
+ // that should be fetched using proxy.
+ DCHECK(alternative_service_.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL ||
+ !alternative_proxy_server_.is_valid());
+ DCHECK(!alternative_proxy_server_.is_valid() ||
+ !(IsSpdyAlternative() || IsQuicAlternative()));
+ // If either the alternative service protocol is specified or if the
+ // alternative proxy server is valid, then the job type must be set to
+ // either ALTERNATIVE or PRECONNECT.
+ DCHECK((alternative_service_.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL &&
+ !alternative_proxy_server_.is_valid()) ||
+ (job_type_ == ALTERNATIVE || job_type_ == PRECONNECT));
+ // If the alternative proxy server is valid, then the job type must be
+ // set to ALTERNATIVE.
+ DCHECK(!alternative_proxy_server_.is_valid() || job_type_ == ALTERNATIVE);
+
if (IsSpdyAlternative()) {
- DCHECK(origin_url_.SchemeIs("https"));
+ DCHECK(origin_url_.SchemeIs(url::kHttpsScheme));
}
if (IsQuicAlternative()) {
DCHECK(session_->params().enable_quic);
@@ -228,7 +238,7 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate,
}
HttpStreamFactoryImpl::Job::~Job() {
- net_log_.EndEvent(NetLog::TYPE_HTTP_STREAM_JOB);
+ net_log_.EndEvent(NetLogEventType::HTTP_STREAM_JOB);
// When we're in a partially constructed state, waiting for the user to
// provide certificate handling information or authentication, we can't reuse
@@ -286,60 +296,16 @@ LoadState HttpStreamFactoryImpl::Job::GetLoadState() const {
}
}
-void HttpStreamFactoryImpl::Job::WaitFor(Job* job) {
- DCHECK_EQ(STATE_NONE, next_state_);
- DCHECK_EQ(STATE_NONE, job->next_state_);
- DCHECK(!blocking_job_);
- DCHECK(!job->waiting_job_);
-
- // Never share connection with other jobs for FTP requests.
- DCHECK(!request_info_.url.SchemeIs("ftp"));
-
- blocking_job_ = job;
- job->waiting_job_ = this;
-}
-
-void HttpStreamFactoryImpl::Job::ResumeAfterDelay() {
- DCHECK(!blocking_job_);
- DCHECK_EQ(STATE_WAIT_FOR_JOB_COMPLETE, next_state_);
-
- net_log_.AddEvent(NetLog::TYPE_HTTP_STREAM_JOB_DELAYED,
- base::Bind(&NetLogHttpStreamJobDelayCallback, wait_time_));
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(&HttpStreamFactoryImpl::Job::OnIOComplete,
- ptr_factory_.GetWeakPtr(), OK),
- wait_time_);
-}
-
-void HttpStreamFactoryImpl::Job::Resume(Job* job,
- const base::TimeDelta& delay) {
- DCHECK_EQ(blocking_job_, job);
- blocking_job_ = NULL;
-
- // If |this| job is not past STATE_WAIT_FOR_JOB_COMPLETE state, then it will
- // be delayed by the |wait_time_| when it resumes.
- if (next_state_ == STATE_NONE || next_state_ <= STATE_WAIT_FOR_JOB_COMPLETE)
- wait_time_ = delay;
-
- // We know we're blocked if the next_state_ is STATE_WAIT_FOR_JOB_COMPLETE.
- // Unblock |this|.
- if (next_state_ == STATE_WAIT_FOR_JOB_COMPLETE)
- ResumeAfterDelay();
+void HttpStreamFactoryImpl::Job::Resume() {
+ DCHECK_EQ(job_type_, MAIN);
+ DCHECK_EQ(next_state_, STATE_WAIT_COMPLETE);
+ OnIOComplete(OK);
}
void HttpStreamFactoryImpl::Job::Orphan() {
- net_log_.AddEvent(NetLog::TYPE_HTTP_STREAM_JOB_ORPHANED);
- if (blocking_job_) {
- // We've been orphaned, but there's a job we're blocked on. Don't bother
- // racing, just cancel ourself.
- DCHECK(blocking_job_->waiting_job_);
- blocking_job_->waiting_job_ = NULL;
- blocking_job_ = NULL;
- if (delegate_->for_websockets() && connection_ && connection_->socket()) {
- connection_->socket()->Disconnect();
- }
- delegate_->OnOrphanedJobComplete(this);
- } else if (delegate_->for_websockets()) {
+ net_log_.AddEvent(NetLogEventType::HTTP_STREAM_JOB_ORPHANED);
+
+ if (delegate_->for_websockets()) {
// We cancel this job because a WebSocketHandshakeStream can't be created
// without a WebSocketHandshakeStreamBase::CreateHelper which is stored in
// the Request class and isn't retrievable by this job.
@@ -357,12 +323,12 @@ void HttpStreamFactoryImpl::Job::SetPriority(RequestPriority priority) {
// preconnect state.
}
-bool HttpStreamFactoryImpl::Job::was_npn_negotiated() const {
- return was_npn_negotiated_;
+bool HttpStreamFactoryImpl::Job::was_alpn_negotiated() const {
+ return was_alpn_negotiated_;
}
-NextProto HttpStreamFactoryImpl::Job::protocol_negotiated() const {
- return protocol_negotiated_;
+NextProto HttpStreamFactoryImpl::Job::negotiated_protocol() const {
+ return negotiated_protocol_;
}
bool HttpStreamFactoryImpl::Job::using_spdy() const {
@@ -410,8 +376,8 @@ bool HttpStreamFactoryImpl::Job::CanUseExistingSpdySession() const {
// https://crbug.com/133176
// TODO(ricea): Add "wss" back to this list when SPDY WebSocket support is
// working.
- return origin_url_.SchemeIs("https") ||
- proxy_info_.proxy_server().is_https() || IsSpdyAlternative();
+ return origin_url_.SchemeIs(url::kHttpsScheme) ||
+ proxy_info_.proxy_server().is_https();
}
void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() {
@@ -419,9 +385,6 @@ void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() {
DCHECK_NE(job_type_, PRECONNECT);
DCHECK(!delegate_->for_websockets());
- UMA_HISTOGRAM_TIMES("Net.HttpStreamFactoryJob.StreamReadyCallbackTime",
- base::TimeTicks::Now() - job_stream_ready_start_time_);
-
MaybeCopyConnectionAttemptsFromSocketOrHandle();
delegate_->OnStreamReady(this, server_ssl_config_, proxy_info_);
@@ -528,7 +491,7 @@ int HttpStreamFactoryImpl::Job::OnHostResolution(
const SpdySessionKey& spdy_session_key,
const GURL& origin_url,
const AddressList& addresses,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
// It is OK to dereference spdy_session_pool, because the
// ClientSocketPoolManager will be destroyed in the same callback that
// destroys the SpdySessionPool.
@@ -552,10 +515,6 @@ int HttpStreamFactoryImpl::Job::RunLoop(int result) {
if (result == ERR_IO_PENDING)
return result;
- // If there was an error, we should have already resumed the |waiting_job_|,
- // if there was one.
- DCHECK(result == OK || waiting_job_ == NULL);
-
if (job_type_ == PRECONNECT) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
@@ -621,8 +580,6 @@ int HttpStreamFactoryImpl::Job::RunLoop(int result) {
}
case OK:
- job_status_ = STATUS_SUCCEEDED;
- MaybeMarkAlternativeServiceBroken();
next_state_ = STATE_DONE;
if (new_spdy_session_.get()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -646,7 +603,6 @@ int HttpStreamFactoryImpl::Job::RunLoop(int result) {
}
} else {
DCHECK(stream_.get());
- job_stream_ready_start_time_ = base::TimeTicks::Now();
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&Job::OnStreamReadyCallback, ptr_factory_.GetWeakPtr()));
@@ -654,16 +610,6 @@ int HttpStreamFactoryImpl::Job::RunLoop(int result) {
return ERR_IO_PENDING;
default:
- DCHECK(result != ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN ||
- IsSpdyAlternative() || IsQuicAlternative());
- if (job_status_ != STATUS_BROKEN) {
- DCHECK_EQ(STATUS_RUNNING, job_status_);
- job_status_ = STATUS_FAILED;
- // TODO(bnc): If (result == ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN),
- // then instead of marking alternative service broken, mark (origin,
- // alternative service) couple as invalid.
- MaybeMarkAlternativeServiceBroken();
- }
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&Job::OnStreamFailedCallback,
ptr_factory_.GetWeakPtr(), result));
@@ -689,12 +635,12 @@ int HttpStreamFactoryImpl::Job::DoLoop(int result) {
case STATE_RESOLVE_PROXY_COMPLETE:
rv = DoResolveProxyComplete(rv);
break;
- case STATE_WAIT_FOR_JOB:
+ case STATE_WAIT:
DCHECK_EQ(OK, rv);
- rv = DoWaitForJob();
+ rv = DoWait();
break;
- case STATE_WAIT_FOR_JOB_COMPLETE:
- rv = DoWaitForJobComplete(rv);
+ case STATE_WAIT_COMPLETE:
+ rv = DoWaitComplete(rv);
break;
case STATE_INIT_CONNECTION:
DCHECK_EQ(OK, rv);
@@ -738,27 +684,21 @@ int HttpStreamFactoryImpl::Job::StartInternal() {
}
int HttpStreamFactoryImpl::Job::DoStart() {
- valid_spdy_session_pool_.reset(new ValidSpdySessionPool(
- session_->spdy_session_pool(), origin_url_, IsSpdyAlternative()));
- const BoundNetLog* net_log = delegate_->GetNetLog(this);
+ const NetLogWithSource* net_log = delegate_->GetNetLog(this);
if (net_log) {
net_log_.BeginEvent(
- NetLog::TYPE_HTTP_STREAM_JOB,
+ NetLogEventType::HTTP_STREAM_JOB,
base::Bind(&NetLogHttpStreamJobCallback, net_log->source(),
&request_info_.url, &origin_url_, &alternative_service_,
priority_));
- net_log->AddEvent(NetLog::TYPE_HTTP_STREAM_REQUEST_STARTED_JOB,
+ net_log->AddEvent(NetLogEventType::HTTP_STREAM_REQUEST_STARTED_JOB,
net_log_.source().ToEventParametersCallback());
}
// Don't connect to restricted ports.
if (!IsPortAllowedForScheme(destination_.port(),
request_info_.url.scheme())) {
- if (waiting_job_) {
- waiting_job_->Resume(this, base::TimeDelta());
- waiting_job_ = NULL;
- }
return ERR_UNSAFE_PORT;
}
@@ -777,30 +717,15 @@ int HttpStreamFactoryImpl::Job::DoResolveProxy() {
return OK;
}
- // TODO(rch): remove this code since Alt-Svc seems to prohibit it.
- GURL url_for_proxy = origin_url_;
- // For SPDY via Alt-Svc, set |alternative_service_url_| to
- // https://<alternative host>:<alternative port>/...
- // so the proxy resolution works with the actual destination, and so
- // that the correct socket pool is used.
- if (IsSpdyAlternative()) {
- // TODO(rch): Figure out how to make QUIC iteract with PAC
- // scripts. By not re-writing the URL, we will query the PAC script
- // for the proxy to use to reach the original URL via TCP. But
- // the alternate request will be going via UDP to a different port.
- GURL::Replacements replacements;
- // new_port needs to be in scope here because GURL::Replacements references
- // the memory contained by it directly.
- const std::string new_port = base::UintToString(alternative_service_.port);
- replacements.SetSchemeStr("https");
- replacements.SetPortStr(new_port);
- url_for_proxy = url_for_proxy.ReplaceComponents(replacements);
+ // If an alternative proxy server was provided, use that.
+ if (alternative_proxy_server_.is_valid()) {
+ proxy_info_.UseProxyServer(alternative_proxy_server_);
+ return OK;
}
return session_->proxy_service()->ResolveProxy(
- url_for_proxy, request_info_.method, request_info_.load_flags,
- &proxy_info_, io_callback_, &pac_request_,
- session_->params().proxy_delegate, net_log_);
+ origin_url_, request_info_.method, &proxy_info_, io_callback_,
+ &pac_request_, session_->params().proxy_delegate, net_log_);
}
int HttpStreamFactoryImpl::Job::DoResolveProxyComplete(int result) {
@@ -831,61 +756,60 @@ int HttpStreamFactoryImpl::Job::DoResolveProxyComplete(int result) {
}
if (result != OK) {
- if (waiting_job_) {
- waiting_job_->Resume(this, base::TimeDelta());
- waiting_job_ = NULL;
- }
return result;
}
- next_state_ = STATE_WAIT_FOR_JOB;
+ next_state_ = STATE_WAIT;
+
+ delegate_->OnResolveProxyComplete(this, request_info_, priority_,
+ server_ssl_config_, proxy_ssl_config_,
+ stream_type_);
+
return OK;
}
bool HttpStreamFactoryImpl::Job::ShouldForceQuic() const {
return session_->params().enable_quic &&
- ContainsKey(session_->params().origins_to_force_quic_on,
- destination_) &&
- proxy_info_.is_direct() && origin_url_.SchemeIs("https");
+ (base::ContainsKey(session_->params().origins_to_force_quic_on,
+ HostPortPair()) ||
+ base::ContainsKey(session_->params().origins_to_force_quic_on,
+ destination_)) &&
+ proxy_info_.is_direct() && origin_url_.SchemeIs(url::kHttpsScheme);
}
-int HttpStreamFactoryImpl::Job::DoWaitForJob() {
- if (!blocking_job_ && wait_time_.is_zero()) {
- // There is no |blocking_job_| and there is no |wait_time_|.
- next_state_ = STATE_INIT_CONNECTION;
- return OK;
- }
-
- next_state_ = STATE_WAIT_FOR_JOB_COMPLETE;
- if (!wait_time_.is_zero()) {
- // If there is a waiting_time, then resume the job after the wait_time_.
- DCHECK(!blocking_job_);
- ResumeAfterDelay();
- }
+int HttpStreamFactoryImpl::Job::DoWait() {
+ next_state_ = STATE_WAIT_COMPLETE;
+ if (delegate_->ShouldWait(this))
+ return ERR_IO_PENDING;
- return ERR_IO_PENDING;
+ return OK;
}
-int HttpStreamFactoryImpl::Job::DoWaitForJobComplete(int result) {
- DCHECK(!blocking_job_);
+int HttpStreamFactoryImpl::Job::DoWaitComplete(int result) {
DCHECK_EQ(OK, result);
- wait_time_ = base::TimeDelta();
next_state_ = STATE_INIT_CONNECTION;
return OK;
}
int HttpStreamFactoryImpl::Job::DoInitConnection() {
+ int result = DoInitConnectionImpl();
+ if (result != ERR_SPDY_SESSION_ALREADY_EXISTS)
+ delegate_->OnConnectionInitialized(this, result);
+
+ return result;
+}
+
+int HttpStreamFactoryImpl::Job::DoInitConnectionImpl() {
// TODO(pkasting): Remove ScopedTracker below once crbug.com/462812 is fixed.
tracked_objects::ScopedTracker tracking_profile(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"462812 HttpStreamFactoryImpl::Job::DoInitConnection"));
- DCHECK(!blocking_job_);
DCHECK(!connection_->is_initialized());
DCHECK(proxy_info_.proxy_server().is_valid());
next_state_ = STATE_INIT_CONNECTION_COMPLETE;
- using_ssl_ = origin_url_.SchemeIs("https") || origin_url_.SchemeIs("wss") ||
- IsSpdyAlternative();
+ using_ssl_ = origin_url_.SchemeIs(url::kHttpsScheme) ||
+ origin_url_.SchemeIs(url::kWssScheme);
using_spdy_ = false;
if (ShouldForceQuic())
@@ -909,7 +833,8 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
}
if (using_quic_) {
- if (proxy_info_.is_quic() && !request_info_.url.SchemeIs("http")) {
+ if (proxy_info_.is_quic() &&
+ !request_info_.url.SchemeIs(url::kHttpScheme)) {
NOTREACHED();
// TODO(rch): support QUIC proxies for HTTPS urls.
return ERR_NOT_IMPLEMENTED;
@@ -922,7 +847,7 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
destination = proxy_info_.proxy_server().host_port_pair();
ssl_config = &proxy_ssl_config_;
GURL::Replacements replacements;
- replacements.SetSchemeStr("https");
+ replacements.SetSchemeStr(url::kHttpsScheme);
replacements.SetHostStr(destination.host());
const std::string new_port = base::UintToString(destination.port());
replacements.SetPortStr(new_port);
@@ -933,8 +858,7 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
replacements.ClearRef();
url = url.ReplaceComponents(replacements);
- // If QUIC is disabled on the destination port, return error.
- if (session_->quic_stream_factory()->IsQuicDisabled(destination.port()))
+ if (session_->quic_stream_factory()->IsQuicDisabled())
return ERR_QUIC_PROTOCOL_ERROR;
} else {
DCHECK(using_ssl_);
@@ -951,21 +875,11 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
if (rv == OK) {
using_existing_quic_session_ = true;
} else {
- // OK, there's no available QUIC session. Let |waiting_job_| resume
- // if it's paused.
- if (waiting_job_) {
- if (rv == ERR_IO_PENDING) {
- // Start the |waiting_job_| after the delay returned by
- // GetTimeDelayForWaitingJob().
- //
- // If QUIC request fails during handshake, then
- // DoInitConnectionComplete() will start the |waiting_job_|.
- waiting_job_->Resume(this, quic_request_.GetTimeDelayForWaitingJob());
- } else {
- // QUIC request has failed, resume the |waiting_job_|.
- waiting_job_->Resume(this, base::TimeDelta());
- }
- waiting_job_ = NULL;
+ // 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());
}
}
return rv;
@@ -976,11 +890,9 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
// Check first if we have a spdy session for this group. If so, then go
// straight to using that.
if (CanUseExistingSpdySession()) {
- base::WeakPtr<SpdySession> spdy_session;
- int result = valid_spdy_session_pool_->FindAvailableSession(
- spdy_session_key, net_log_, &spdy_session);
- if (result != OK)
- return result;
+ base::WeakPtr<SpdySession> spdy_session =
+ session_->spdy_session_pool()->FindAvailableSession(
+ spdy_session_key, origin_url_, net_log_);
if (spdy_session) {
// If we're preconnecting, but we already have a SpdySession, we don't
// actually need to preconnect any sockets, so we're done.
@@ -998,13 +910,6 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
delegate_->SetSpdySessionKey(this, spdy_session_key);
}
- // OK, there's no available SPDY session. Let |waiting_job_| resume if it's
- // paused.
- if (waiting_job_) {
- waiting_job_->Resume(this, base::TimeDelta());
- waiting_job_ = NULL;
- }
-
if (proxy_info_.is_http() || proxy_info_.is_https())
establishing_tunnel_ = using_ssl_;
@@ -1040,7 +945,6 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
// TODO(ricea): Re-enable NPN when WebSockets over SPDY is supported.
SSLConfig websocket_server_ssl_config = server_ssl_config_;
websocket_server_ssl_config.alpn_protos.clear();
- websocket_server_ssl_config.npn_protos.clear();
return InitSocketHandleForWebSocketRequest(
GetSocketGroup(), destination_, request_info_.extra_headers,
request_info_.load_flags, priority_, session_, proxy_info_, expect_spdy,
@@ -1057,10 +961,6 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() {
}
int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) {
- if (using_quic_ && result < 0 && waiting_job_) {
- waiting_job_->Resume(this, base::TimeDelta());
- waiting_job_ = NULL;
- }
if (job_type_ == PRECONNECT) {
if (using_quic_)
return result;
@@ -1069,7 +969,7 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) {
}
if (result == ERR_SPDY_SESSION_ALREADY_EXISTS) {
- // We found a SPDY connection after resolving the host. This is
+ // We found a SPDY connection after resolving the host. This is
// probably an IP pooled connection.
SpdySessionKey spdy_session_key = GetSpdySessionKey();
existing_spdy_session_ =
@@ -1085,23 +985,16 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) {
return OK;
}
- if (proxy_info_.is_quic() && using_quic_) {
- // Mark QUIC proxy as bad if QUIC got disabled on the destination port.
+ if (proxy_info_.is_quic()) {
+ DCHECK(using_quic_);
+ // Mark QUIC proxy as bad if QUIC got disabled.
// Underlying QUIC layer would have closed the connection.
- HostPortPair destination = proxy_info_.proxy_server().host_port_pair();
- if (session_->quic_stream_factory()->IsQuicDisabled(destination.port())) {
+ if (session_->quic_stream_factory()->IsQuicDisabled()) {
using_quic_ = false;
return ReconsiderProxyAfterError(ERR_QUIC_PROTOCOL_ERROR);
}
}
- // TODO(willchan): Make this a bit more exact. Maybe there are recoverable
- // errors, such as ignoring certificate errors for Alternate-Protocol.
- if (result < 0 && waiting_job_) {
- waiting_job_->Resume(this, base::TimeDelta());
- waiting_job_ = NULL;
- }
-
// |result| may be the result of any of the stacked pools. The following
// logic is used when determining how to interpret an error.
// If |result| < 0:
@@ -1115,24 +1008,19 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) {
if (ssl_started && (result == OK || IsCertificateError(result))) {
if (using_quic_ && result == OK) {
- was_npn_negotiated_ = true;
- protocol_negotiated_ =
- SSLClientSocket::NextProtoFromString("quic/1+spdy/3");
+ was_alpn_negotiated_ = true;
+ negotiated_protocol_ = kProtoQUIC1SPDY3;
} else {
SSLClientSocket* ssl_socket =
static_cast<SSLClientSocket*>(connection_->socket());
if (ssl_socket->WasNpnNegotiated()) {
- was_npn_negotiated_ = true;
- std::string proto;
- SSLClientSocket::NextProtoStatus status =
- ssl_socket->GetNextProto(&proto);
- protocol_negotiated_ = SSLClientSocket::NextProtoFromString(proto);
+ was_alpn_negotiated_ = true;
+ negotiated_protocol_ = ssl_socket->GetNegotiatedProtocol();
net_log_.AddEvent(
- NetLog::TYPE_HTTP_STREAM_REQUEST_PROTO,
- base::Bind(&NetLogHttpStreamProtoCallback,
- status, &proto));
- if (NextProtoIsSPDY(protocol_negotiated_))
- SwitchToSpdyMode();
+ NetLogEventType::HTTP_STREAM_REQUEST_PROTO,
+ base::Bind(&NetLogHttpStreamProtoCallback, negotiated_protocol_));
+ if (negotiated_protocol_ == kProtoHTTP2)
+ using_spdy_ = true;
}
}
} else if (proxy_info_.is_https() && connection_->socket() &&
@@ -1143,9 +1031,9 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) {
if (!proxy_socket->IsConnected())
return ERR_CONNECTION_CLOSED;
if (proxy_socket->IsUsingSpdy()) {
- was_npn_negotiated_ = true;
- protocol_negotiated_ = proxy_socket->GetProtocolNegotiated();
- SwitchToSpdyMode();
+ was_alpn_negotiated_ = true;
+ negotiated_protocol_ = proxy_socket->GetProxyNegotiatedProtocol();
+ using_spdy_ = true;
}
}
@@ -1167,28 +1055,17 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) {
return ReconsiderProxyAfterError(result);
}
- if (IsSpdyAlternative() && !using_spdy_) {
- job_status_ = STATUS_BROKEN;
- MaybeMarkAlternativeServiceBroken();
- return ERR_NPN_NEGOTIATION_FAILED;
- }
+ if (IsSpdyAlternative() && !using_spdy_)
+ return ERR_ALPN_NEGOTIATION_FAILED;
if (!ssl_started && result < 0 &&
- (IsSpdyAlternative() || IsQuicAlternative())) {
- job_status_ = STATUS_BROKEN;
- // TODO(bnc): if (result == ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN), then
- // instead of marking alternative service broken, mark (origin, alternative
- // service) couple as invalid.
- MaybeMarkAlternativeServiceBroken();
+ (IsSpdyAlternative() || IsQuicAlternative()))
return result;
- }
if (using_quic_) {
- if (result < 0) {
- job_status_ = STATUS_BROKEN;
- MaybeMarkAlternativeServiceBroken();
+ if (result < 0)
return result;
- }
+
if (stream_type_ == HttpStreamRequest::BIDIRECTIONAL_STREAM) {
bidirectional_stream_impl_ =
quic_request_.CreateBidirectionalStreamImpl();
@@ -1215,16 +1092,10 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) {
if (using_ssl_) {
DCHECK(ssl_started);
if (IsCertificateError(result)) {
- if (IsSpdyAlternative() && origin_url_.SchemeIs("http")) {
- // We ignore certificate errors for http over spdy.
- spdy_certificate_error_ = result;
- result = OK;
- } else {
- result = HandleCertificateError(result);
- if (result == OK && !connection_->socket()->IsConnectedAndIdle()) {
- ReturnToStateInitConnection(true /* close connection */);
- return result;
- }
+ result = HandleCertificateError(result);
+ if (result == OK && !connection_->socket()->IsConnectedAndIdle()) {
+ ReturnToStateInitConnection(true /* close connection */);
+ return result;
}
}
if (result < 0)
@@ -1260,7 +1131,8 @@ int HttpStreamFactoryImpl::Job::SetSpdyHttpStreamOrBidirectionalStreamImpl(
// HttpStreamFactoryImpl will be creating all the SpdyHttpStreams, since it
// will know when SpdySessions become available.
- bool use_relative_url = direct || request_info_.url.SchemeIs("https");
+ bool use_relative_url =
+ direct || request_info_.url.SchemeIs(url::kHttpsScheme);
stream_.reset(new SpdyHttpStream(session, use_relative_url));
return OK;
}
@@ -1292,8 +1164,8 @@ int HttpStreamFactoryImpl::Job::DoCreateStream() {
DCHECK(!IsSpdyAlternative());
// We may get ftp scheme when fetching ftp resources through proxy.
bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) &&
- (request_info_.url.SchemeIs("http") ||
- request_info_.url.SchemeIs("ftp"));
+ (request_info_.url.SchemeIs(url::kHttpScheme) ||
+ request_info_.url.SchemeIs(url::kFtpScheme));
if (delegate_->for_websockets()) {
DCHECK_NE(job_type_, PRECONNECT);
DCHECK(delegate_->websocket_handshake_stream_create_helper());
@@ -1301,7 +1173,9 @@ int HttpStreamFactoryImpl::Job::DoCreateStream() {
delegate_->websocket_handshake_stream_create_helper()
->CreateBasicStream(std::move(connection_), using_proxy));
} else {
- stream_.reset(new HttpBasicStream(connection_.release(), using_proxy));
+ stream_.reset(new HttpBasicStream(
+ std::move(connection_), using_proxy,
+ session_->params().http_09_on_non_default_ports_enabled));
}
return OK;
}
@@ -1322,22 +1196,16 @@ int HttpStreamFactoryImpl::Job::DoCreateStream() {
}
SpdySessionKey spdy_session_key = GetSpdySessionKey();
- base::WeakPtr<SpdySession> spdy_session;
- int result = valid_spdy_session_pool_->FindAvailableSession(
- spdy_session_key, net_log_, &spdy_session);
- if (result != OK) {
- return result;
- }
+ base::WeakPtr<SpdySession> spdy_session =
+ session_->spdy_session_pool()->FindAvailableSession(
+ spdy_session_key, origin_url_, net_log_);
if (spdy_session) {
return SetSpdyHttpStreamOrBidirectionalStreamImpl(spdy_session, direct);
}
- result = valid_spdy_session_pool_->CreateAvailableSessionFromSocket(
- spdy_session_key, std::move(connection_), net_log_,
- spdy_certificate_error_, using_ssl_, &spdy_session);
- if (result != OK) {
- return result;
- }
+ spdy_session =
+ session_->spdy_session_pool()->CreateAvailableSessionFromSocket(
+ spdy_session_key, std::move(connection_), net_log_, using_ssl_);
if (!spdy_session->HasAcceptableTransportSecurity()) {
spdy_session->CloseSessionOnError(
@@ -1346,11 +1214,7 @@ int HttpStreamFactoryImpl::Job::DoCreateStream() {
}
SSLInfo ssl_info;
- bool was_npn_negotiated;
- NextProto protocol_negotiated;
- if (spdy_session->GetSSLInfo(&ssl_info, &was_npn_negotiated,
- &protocol_negotiated) &&
- spdy_session->GetProtocolVersion() >= HTTP2) {
+ if (spdy_session->GetSSLInfo(&ssl_info)) {
UMA_HISTOGRAM_SPARSE_SLOWLY(
"Net.Http2SSLCipherSuite",
SSLConnectionStatusToCipherSuite(ssl_info.connection_status));
@@ -1360,9 +1224,9 @@ int HttpStreamFactoryImpl::Job::DoCreateStream() {
spdy_session_direct_ = direct;
const HostPortPair host_port_pair = spdy_session_key.host_port_pair();
bool is_https = ssl_info.is_valid();
- url::SchemeHostPort scheme_host_port(is_https ? "https" : "http",
- host_port_pair.host(),
- host_port_pair.port());
+ url::SchemeHostPort scheme_host_port(
+ is_https ? url::kHttpsScheme : url::kHttpScheme, host_port_pair.host(),
+ host_port_pair.port());
HttpServerProperties* http_server_properties =
session_->http_server_properties();
@@ -1436,18 +1300,19 @@ void HttpStreamFactoryImpl::Job::SetSocketMotivation() {
bool HttpStreamFactoryImpl::Job::IsHttpsProxyAndHttpUrl() const {
if (!proxy_info_.is_https())
return false;
- if (IsSpdyAlternative() || IsQuicAlternative()) {
+ DCHECK(!IsSpdyAlternative());
+ if (IsQuicAlternative()) {
// We currently only support Alternate-Protocol where the original scheme
// is http.
- DCHECK(origin_url_.SchemeIs("http"));
- return origin_url_.SchemeIs("http");
+ // TODO(bnc): This comment is probably incorrect.
+ DCHECK(origin_url_.SchemeIs(url::kHttpScheme));
+ return origin_url_.SchemeIs(url::kHttpScheme);
}
- return request_info_.url.SchemeIs("http");
+ return request_info_.url.SchemeIs(url::kHttpScheme);
}
bool HttpStreamFactoryImpl::Job::IsSpdyAlternative() const {
- return alternative_service_.protocol >= NPN_SPDY_MINIMUM_VERSION &&
- alternative_service_.protocol <= NPN_SPDY_MAXIMUM_VERSION;
+ return alternative_service_.protocol == NPN_HTTP_2;
}
bool HttpStreamFactoryImpl::Job::IsQuicAlternative() const {
@@ -1516,14 +1381,15 @@ int HttpStreamFactoryImpl::Job::ReconsiderProxyAfterError(int error) {
case ERR_TIMED_OUT:
case ERR_TUNNEL_CONNECTION_FAILED:
case ERR_SOCKS_CONNECTION_FAILED:
- // This can happen in the case of trying to talk to a proxy using SSL, and
- // ending up talking to a captive portal that supports SSL instead.
+ // ERR_PROXY_CERTIFICATE_INVALID can happen in the case of trying to talk to
+ // a proxy using SSL, and ending up talking to a captive portal that
+ // supports SSL instead.
case ERR_PROXY_CERTIFICATE_INVALID:
- // This can happen when trying to talk SSL to a non-SSL server (Like a
- // captive portal).
case ERR_QUIC_PROTOCOL_ERROR:
case ERR_QUIC_HANDSHAKE_FAILED:
case ERR_MSG_TOO_BIG:
+ // ERR_SSL_PROTOCOL_ERROR can happen when trying to talk SSL to a non-SSL
+ // server (like a captive portal).
case ERR_SSL_PROTOCOL_ERROR:
break;
case ERR_SOCKS_CONNECTION_HOST_UNREACHABLE:
@@ -1547,15 +1413,22 @@ int HttpStreamFactoryImpl::Job::ReconsiderProxyAfterError(int error) {
if (request_info_.load_flags & LOAD_BYPASS_PROXY)
return error;
+ // Alternative proxy server job should not use fallback proxies, and instead
+ // return. This would resume the main job (if possible) which may try the
+ // fallback proxies.
+ if (alternative_proxy_server_.is_valid()) {
+ DCHECK_EQ(STATE_NONE, next_state_);
+ return error;
+ }
+
if (proxy_info_.is_https() && proxy_ssl_config_.send_client_cert) {
session_->ssl_client_auth_cache()->Remove(
proxy_info_.proxy_server().host_port_pair());
}
int rv = session_->proxy_service()->ReconsiderProxyAfterError(
- request_info_.url, request_info_.method, request_info_.load_flags, error,
- &proxy_info_, io_callback_, &pac_request_,
- session_->params().proxy_delegate, net_log_);
+ request_info_.url, request_info_.method, error, &proxy_info_,
+ io_callback_, &pac_request_, session_->params().proxy_delegate, net_log_);
if (rv == OK || rv == ERR_IO_PENDING) {
// If the error was during connection setup, there is no socket to
// disconnect.
@@ -1583,22 +1456,18 @@ int HttpStreamFactoryImpl::Job::HandleCertificateError(int error) {
static_cast<SSLClientSocket*>(connection_->socket());
ssl_socket->GetSSLInfo(&ssl_info_);
+ if (!ssl_info_.cert) {
+ // If the server's certificate could not be parsed, there is no way
+ // to gracefully recover this, so just pass the error up.
+ return error;
+ }
+
// Add the bad certificate to the set of allowed certificates in the
// SSL config object. This data structure will be consulted after calling
// RestartIgnoringLastError(). And the user will be asked interactively
// before RestartIgnoringLastError() is ever called.
- SSLConfig::CertAndStatus bad_cert;
-
- // |ssl_info_.cert| may be NULL if we failed to create
- // X509Certificate for whatever reason, but normally it shouldn't
- // happen, unless this code is used inside sandbox.
- if (ssl_info_.cert.get() == NULL ||
- !X509Certificate::GetDEREncoded(ssl_info_.cert->os_cert_handle(),
- &bad_cert.der_cert)) {
- return error;
- }
- bad_cert.cert_status = ssl_info_.cert_status;
- server_ssl_config_.allowed_bad_certs.push_back(bad_cert);
+ server_ssl_config_.allowed_bad_certs.emplace_back(ssl_info_.cert,
+ ssl_info_.cert_status);
int load_flags = request_info_.load_flags;
if (session_->params().ignore_certificate_errors)
@@ -1608,112 +1477,13 @@ int HttpStreamFactoryImpl::Job::HandleCertificateError(int error) {
return error;
}
-void HttpStreamFactoryImpl::Job::SwitchToSpdyMode() {
- if (protocol_negotiated_ == kProtoSPDY31 &&
- !HttpStreamFactory::spdy_enabled())
- return;
-
- using_spdy_ = true;
-}
-
-void HttpStreamFactoryImpl::Job::ReportJobSucceededForRequest() {
- if (using_existing_quic_session_) {
- // If an existing session was used, then no TCP connection was
- // started.
- HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_NO_RACE);
- } else if (IsSpdyAlternative() || IsQuicAlternative()) {
- // This Job was the alternative Job, and hence won the race.
- HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_WON_RACE);
- } else {
- // This Job was the normal Job, and hence the alternative Job lost the race.
- HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_LOST_RACE);
- }
-}
-
-void HttpStreamFactoryImpl::Job::MarkOtherJobComplete(const Job& job) {
- DCHECK_EQ(STATUS_RUNNING, other_job_status_);
- other_job_status_ = job.job_status_;
- other_job_alternative_service_ = job.alternative_service_;
- MaybeMarkAlternativeServiceBroken();
-}
-
-void HttpStreamFactoryImpl::Job::MaybeMarkAlternativeServiceBroken() {
- if (job_status_ == STATUS_RUNNING || other_job_status_ == STATUS_RUNNING)
- return;
-
- if (IsSpdyAlternative() || IsQuicAlternative()) {
- if (job_status_ == STATUS_BROKEN && other_job_status_ == STATUS_SUCCEEDED) {
- HistogramBrokenAlternateProtocolLocation(
- BROKEN_ALTERNATE_PROTOCOL_LOCATION_HTTP_STREAM_FACTORY_IMPL_JOB_ALT);
- session_->http_server_properties()->MarkAlternativeServiceBroken(
- alternative_service_);
- }
- return;
- }
-
- session_->quic_stream_factory()->OnTcpJobCompleted(job_status_ ==
- STATUS_SUCCEEDED);
- if (job_status_ == STATUS_SUCCEEDED && other_job_status_ == STATUS_BROKEN) {
- HistogramBrokenAlternateProtocolLocation(
- BROKEN_ALTERNATE_PROTOCOL_LOCATION_HTTP_STREAM_FACTORY_IMPL_JOB_MAIN);
- session_->http_server_properties()->MarkAlternativeServiceBroken(
- other_job_alternative_service_);
- }
-}
-
-HttpStreamFactoryImpl::Job::ValidSpdySessionPool::ValidSpdySessionPool(
- SpdySessionPool* spdy_session_pool,
- GURL& origin_url,
- bool is_spdy_alternative)
- : spdy_session_pool_(spdy_session_pool),
- origin_url_(origin_url),
- is_spdy_alternative_(is_spdy_alternative) {
-}
-
-int HttpStreamFactoryImpl::Job::ValidSpdySessionPool::FindAvailableSession(
- const SpdySessionKey& key,
- const BoundNetLog& net_log,
- base::WeakPtr<SpdySession>* spdy_session) {
- *spdy_session =
- spdy_session_pool_->FindAvailableSession(key, origin_url_, net_log);
- return CheckAlternativeServiceValidityForOrigin(*spdy_session);
-}
-
-int HttpStreamFactoryImpl::Job::ValidSpdySessionPool::
- CreateAvailableSessionFromSocket(
- const SpdySessionKey& key,
- std::unique_ptr<ClientSocketHandle> connection,
- const BoundNetLog& net_log,
- int certificate_error_code,
- bool is_secure,
- base::WeakPtr<SpdySession>* spdy_session) {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("net"),
- "HttpStreamFactoryImpl::Job::CreateAvailableSessionFromSocket");
- *spdy_session = spdy_session_pool_->CreateAvailableSessionFromSocket(
- key, std::move(connection), net_log, certificate_error_code, is_secure);
- return CheckAlternativeServiceValidityForOrigin(*spdy_session);
-}
-
-int HttpStreamFactoryImpl::Job::ValidSpdySessionPool::
- CheckAlternativeServiceValidityForOrigin(
- base::WeakPtr<SpdySession> spdy_session) {
- // For an alternative Job, destination_.host() might be different than
- // origin_url_.host(), therefore it needs to be verified that the former
- // provides a certificate that is valid for the latter.
- if (!is_spdy_alternative_ || !spdy_session ||
- spdy_session->VerifyDomainAuthentication(origin_url_.host())) {
- return OK;
- }
- return ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN;
-}
-
ClientSocketPoolManager::SocketGroupType
HttpStreamFactoryImpl::Job::GetSocketGroup() const {
std::string scheme = origin_url_.scheme();
- if (scheme == "https" || scheme == "wss" || IsSpdyAlternative())
+ if (scheme == url::kHttpsScheme || scheme == url::kWssScheme)
return ClientSocketPoolManager::SSL_GROUP;
- if (scheme == "ftp")
+ if (scheme == url::kFtpScheme)
return ClientSocketPoolManager::FTP_GROUP;
return ClientSocketPoolManager::NORMAL_GROUP;
diff --git a/chromium/net/http/http_stream_factory_impl_job.h b/chromium/net/http/http_stream_factory_impl_job.h
index 0f7b1777ae5..fa26fae1470 100644
--- a/chromium/net/http/http_stream_factory_impl_job.h
+++ b/chromium/net/http/http_stream_factory_impl_job.h
@@ -6,6 +6,7 @@
#define NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_H_
#include <memory>
+#include <utility>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
@@ -19,9 +20,10 @@
#include "net/http/http_auth_controller.h"
#include "net/http/http_request_info.h"
#include "net/http/http_stream_factory_impl.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
+#include "net/proxy/proxy_server.h"
#include "net/proxy/proxy_service.h"
-#include "net/quic/quic_stream_factory.h"
+#include "net/quic/chromium/quic_stream_factory.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool_manager.h"
#include "net/socket/ssl_client_socket.h"
@@ -35,6 +37,8 @@ class HttpAuthController;
class HttpNetworkSession;
class HttpStream;
class SpdySessionPool;
+class NetLog;
+struct SSLConfig;
class QuicHttpStream;
// An HttpStreamRequestImpl exists for each stream which is in progress of being
@@ -96,6 +100,16 @@ class HttpStreamFactoryImpl::Job {
const ProxyInfo& used_proxy_info,
HttpAuthController* auth_controller) = 0;
+ // Invoked when |job| has completed proxy resolution. The delegate may
+ // create an alternative proxy server job to fetch the request.
+ virtual void OnResolveProxyComplete(
+ Job* job,
+ const HttpRequestInfo& request_info,
+ RequestPriority priority,
+ const SSLConfig& server_ssl_config,
+ const SSLConfig& proxy_ssl_config,
+ HttpStreamRequest::StreamType stream_type) = 0;
+
// Invoked to notify the Request and Factory of the readiness of new
// SPDY session.
virtual void OnNewSpdySessionReady(
@@ -115,6 +129,13 @@ class HttpStreamFactoryImpl::Job {
Job* job,
const ConnectionAttempts& attempts) = 0;
+ // Invoked when |job| finishes initiating a connection.
+ virtual void OnConnectionInitialized(Job* job, int rv) = 0;
+
+ // Return false if |job| can advance to the next state. Otherwise, |job|
+ // will wait for Job::Resume() to be called before advancing.
+ virtual bool ShouldWait(Job* job) = 0;
+
// Called when |job| determines the appropriate |spdy_session_key| for the
// Request. Note that this does not mean that SPDY is necessarily supported
// for this SpdySessionKey, since we may need to wait for NPN to complete
@@ -125,11 +146,13 @@ class HttpStreamFactoryImpl::Job {
// Remove session from the SpdySessionRequestMap.
virtual void RemoveRequestFromSpdySessionRequestMapForJob(Job* job) = 0;
- virtual const BoundNetLog* GetNetLog(Job* job) const = 0;
+ virtual const NetLogWithSource* GetNetLog(Job* job) const = 0;
virtual WebSocketHandshakeStreamBase::CreateHelper*
websocket_handshake_stream_create_helper() = 0;
+ virtual void MaybeSetWaitTimeForMainJob(const base::TimeDelta& delay) = 0;
+
virtual bool for_websockets() = 0;
};
@@ -147,9 +170,14 @@ class HttpStreamFactoryImpl::Job {
GURL origin_url,
NetLog* net_log);
- // Constructor for alternative Job.
- // Job is owned by |delegate|, hence |delegate| is valid for the
- // lifetime of the Job.
+ // Constructor for the alternative Job. The Job is owned by |delegate|, hence
+ // |delegate| is valid for the lifetime of the Job. If |alternative_service|
+ // is initialized, then the Job will use the alternative service. On the
+ // other hand, if |alternative_proxy_server| is a valid proxy server, then the
+ // job will use that instead of using ProxyService for proxy resolution.
+ // Further, if |alternative_proxy_server| is a valid but bad proxy, then
+ // fallback proxies are not used. It is illegal to call this with an
+ // initialized |alternative_service|, and a valid |alternative_proxy_server|.
Job(Delegate* delegate,
JobType job_type,
HttpNetworkSession* session,
@@ -160,12 +188,13 @@ class HttpStreamFactoryImpl::Job {
HostPortPair destination,
GURL origin_url,
AlternativeService alternative_service,
+ const ProxyServer& alternative_proxy_server,
NetLog* net_log);
virtual ~Job();
// Start initiates the process of creating a new HttpStream.
// |delegate_| will be notified upon completion.
- virtual void Start(HttpStreamRequest::StreamType stream_type);
+ void Start(HttpStreamRequest::StreamType stream_type);
// Preconnect will attempt to request |num_streams| sockets from the
// appropriate ClientSocketPool.
@@ -174,14 +203,9 @@ class HttpStreamFactoryImpl::Job {
int RestartTunnelWithProxyAuth(const AuthCredentials& credentials);
LoadState GetLoadState() const;
- // Tells |this| to wait for |job| to resume it.
- void WaitFor(Job* job);
-
- // Tells |this| that |job| has determined it still needs to continue
- // connecting, so allow |this| to continue after the specified |delay|. If
- // this is not called, then |request_| is expected to cancel |this| by
- // deleting it.
- void Resume(Job* job, const base::TimeDelta& delay);
+ // Tells |this| that |delegate_| has determined it still needs to continue
+ // connecting.
+ virtual void Resume();
// Called to detach |this| Job. May resume the other Job, will disconnect
// the socket for |this| Job, and notify |delegate| upon completion.
@@ -190,10 +214,10 @@ class HttpStreamFactoryImpl::Job {
void SetPriority(RequestPriority priority);
RequestPriority priority() const { return priority_; }
- bool was_npn_negotiated() const;
- NextProto protocol_negotiated() const;
+ bool was_alpn_negotiated() const;
+ NextProto negotiated_protocol() const;
bool using_spdy() const;
- const BoundNetLog& net_log() const { return net_log_; }
+ const NetLogWithSource& net_log() const { return net_log_; }
HttpStreamRequest::StreamType stream_type() const { return stream_type_; }
std::unique_ptr<HttpStream> ReleaseStream() { return std::move(stream_); }
@@ -204,46 +228,48 @@ class HttpStreamFactoryImpl::Job {
return std::move(bidirectional_stream_impl_);
}
+ bool is_waiting() const { return next_state_ == STATE_WAIT_COMPLETE; }
const SSLConfig& server_ssl_config() const;
const SSLConfig& proxy_ssl_config() const;
const ProxyInfo& proxy_info() const;
- // Called to indicate that this job succeeded, and some other jobs
- // will be orphaned.
- void ReportJobSucceededForRequest();
+ JobType job_type() const { return job_type_; }
+
+ const AlternativeService alternative_service() const {
+ return alternative_service_;
+ }
- // Marks that the other |job| has completed.
- virtual void MarkOtherJobComplete(const Job& job);
+ const ProxyServer alternative_proxy_server() const {
+ return alternative_proxy_server_;
+ }
- JobType job_type() const { return job_type_; }
+ bool using_existing_quic_session() const {
+ return using_existing_quic_session_;
+ }
private:
- FRIEND_TEST_ALL_PREFIXES(HttpStreamFactoryImplRequestTest, DelayMainJob);
+ friend class HttpStreamFactoryImplJobPeer;
enum State {
STATE_START,
STATE_RESOLVE_PROXY,
STATE_RESOLVE_PROXY_COMPLETE,
- // Note that when Alternate-Protocol says we can connect to an alternate
- // port using a different protocol, we have the choice of communicating over
- // the original protocol, or speaking the alternate protocol (currently,
- // only npn-spdy) over an alternate port. For a cold page load, the http
- // connection that delivers the http response that has the
- // Alternate-Protocol header will already be warm. So, blocking the next
- // http request on establishing a new npn-spdy connection would incur extra
- // latency. Even if the http connection was not reused, establishing a new
- // http connection is typically faster than npn-spdy, since npn-spdy
- // requires a SSL handshake. Therefore, we start both the http and the
- // npn-spdy jobs in parallel. In order not to unnecessarily waste sockets,
- // we have the http job block on the npn-spdy job after proxy resolution.
- // The npn-spdy job will Resume() the http job if, in
- // STATE_INIT_CONNECTION_COMPLETE, it detects an error or does not find an
- // existing SpdySession. In that case, the http and npn-spdy jobs will race.
- // When QUIC protocol is used by the npn-spdy job, then http job will wait
- // for |wait_time_| when the http job was resumed.
- STATE_WAIT_FOR_JOB,
- STATE_WAIT_FOR_JOB_COMPLETE,
+ // The main and alternative jobs are started in parallel. The main job
+ // waits after it finishes proxy resolution. The alternative job never
+ // waits.
+ //
+ // An HTTP/2 alternative job notifies the JobController in DoInitConnection
+ // unless it can pool to an existing SpdySession. JobController, in turn,
+ // resumes the main job.
+ //
+ // A QUIC alternative job notifies the JobController in DoInitConnection
+ // regardless of whether it pools to an existing QUIC session, but the main
+ // job is only resumed after some delay.
+ //
+ // If the main job is resumed, then it races the alternative job.
+ STATE_WAIT,
+ STATE_WAIT_COMPLETE,
STATE_INIT_CONNECTION,
STATE_INIT_CONNECTION_COMPLETE,
@@ -258,61 +284,6 @@ class HttpStreamFactoryImpl::Job {
STATE_NONE
};
- enum JobStatus {
- STATUS_RUNNING,
- STATUS_FAILED,
- STATUS_BROKEN,
- STATUS_SUCCEEDED
- };
-
- // Wrapper class for SpdySessionPool methods to enforce certificate
- // requirements for SpdySessions.
- class ValidSpdySessionPool {
- public:
- ValidSpdySessionPool(SpdySessionPool* spdy_session_pool,
- GURL& origin_url,
- bool is_spdy_alternative);
-
- // Returns OK if a SpdySession was not found (in which case |spdy_session|
- // is set to nullptr), or if one was found (in which case |spdy_session| is
- // set to it) and it has an associated SSL certificate with is valid for
- // |origin_url_|, or if this requirement does not apply because the Job is
- // not a SPDY alternative job. Returns the appropriate error code
- // otherwise,
- // in which case |spdy_session| should not be used.
- int FindAvailableSession(const SpdySessionKey& key,
- const BoundNetLog& net_log,
- base::WeakPtr<SpdySession>* spdy_session);
-
- // Creates a SpdySession and sets |spdy_session| to point to it. Returns OK
- // if the associated SSL certificate is valid for |origin_url_|, or if this
- // requirement does not apply because the Job is not a SPDY alternative job.
- // Returns the appropriate error code otherwise, in which case
- // |spdy_session| should not be used.
- int CreateAvailableSessionFromSocket(
- const SpdySessionKey& key,
- std::unique_ptr<ClientSocketHandle> connection,
- const BoundNetLog& net_log,
- int certificate_error_code,
- bool is_secure,
- base::WeakPtr<SpdySession>* spdy_session);
-
- private:
- // Returns OK if |spdy_session| has an associated SSL certificate with is
- // valid for |origin_url_|, or if this requirement does not apply because
- // the Job is not a SPDY alternative job, or if |spdy_session| is null.
- // Returns appropriate error code otherwise.
- int CheckAlternativeServiceValidityForOrigin(
- base::WeakPtr<SpdySession> spdy_session);
-
- SpdySessionPool* const spdy_session_pool_;
- const GURL origin_url_;
- const bool is_spdy_alternative_;
- };
-
- // Resume the |this| job after the specified |wait_time_|.
- void ResumeAfterDelay();
-
void OnStreamReadyCallback();
void OnBidirectionalStreamImplReadyCallback();
void OnWebSocketHandshakeStreamReadyCallback();
@@ -331,6 +302,7 @@ class HttpStreamFactoryImpl::Job {
int RunLoop(int result);
int DoLoop(int result);
int StartInternal();
+ int DoInitConnectionImpl();
// 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
@@ -339,8 +311,8 @@ class HttpStreamFactoryImpl::Job {
int DoStart();
int DoResolveProxy();
int DoResolveProxyComplete(int result);
- int DoWaitForJob();
- int DoWaitForJobComplete(int result);
+ int DoWait();
+ int DoWaitComplete(int result);
int DoInitConnection();
int DoInitConnectionComplete(int result);
int DoWaitingUserAction(int result);
@@ -398,14 +370,9 @@ class HttpStreamFactoryImpl::Job {
// Called to handle a client certificate request.
int HandleCertificateRequest(int error);
- // Moves this stream request into SPDY mode.
- void SwitchToSpdyMode();
-
// Should we force QUIC for this stream request.
bool ShouldForceQuic() const;
- void MaybeMarkAlternativeServiceBroken();
-
ClientSocketPoolManager::SocketGroupType GetSocketGroup() const;
void MaybeCopyConnectionAttemptsFromSocketOrHandle();
@@ -421,14 +388,14 @@ class HttpStreamFactoryImpl::Job {
const SpdySessionKey& spdy_session_key,
const GURL& origin_url,
const AddressList& addresses,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
const HttpRequestInfo request_info_;
RequestPriority priority_;
ProxyInfo proxy_info_;
SSLConfig server_ssl_config_;
SSLConfig proxy_ssl_config_;
- const BoundNetLog net_log_;
+ const NetLogWithSource net_log_;
CompletionCallback io_callback_;
std::unique_ptr<ClientSocketHandle> connection_;
@@ -439,33 +406,23 @@ class HttpStreamFactoryImpl::Job {
// The server we are trying to reach, could be that of the origin or of the
// alternative service (after applying host mapping rules).
- HostPortPair destination_;
+ const HostPortPair destination_;
// The origin url we're trying to reach. This url may be different from the
// original request when host mapping rules are set-up.
- GURL origin_url_;
+ const GURL origin_url_;
// AlternativeService for this Job if this is an alternative Job.
const AlternativeService alternative_service_;
- // AlternativeService for the other Job if this is not an alternative Job.
- AlternativeService other_job_alternative_service_;
+ // Alternative proxy server that should be used by |this| to fetch the
+ // request.
+ const ProxyServer alternative_proxy_server_;
// Unowned. |this| job is owned by |delegate_|.
Delegate* delegate_;
- JobType job_type_;
-
- // This is the Job we're dependent on. It will notify us if/when it's OK to
- // proceed.
- Job* blocking_job_;
-
- // |waiting_job_| is a Job waiting to see if |this| can reuse a connection.
- // If |this| is unable to do so, we'll notify |waiting_job_| that it's ok to
- // proceed and then race the two Jobs.
- Job* waiting_job_;
-
- base::TimeDelta wait_time_;
+ const JobType job_type_;
// True if handling a HTTPS request, or using SPDY with SSL
bool using_ssl_;
@@ -483,9 +440,6 @@ class HttpStreamFactoryImpl::Job {
// Force quic for a specific port.
int force_quic_port_;
- // The certificate error while using SPDY over SSL for insecure URLs.
- int spdy_certificate_error_;
-
scoped_refptr<HttpAuthController>
auth_controllers_[HttpAuth::AUTH_NUM_TARGETS];
@@ -497,18 +451,16 @@ class HttpStreamFactoryImpl::Job {
std::unique_ptr<WebSocketHandshakeStreamBase> websocket_stream_;
std::unique_ptr<BidirectionalStreamImpl> bidirectional_stream_impl_;
- // True if we negotiated NPN.
- bool was_npn_negotiated_;
+ // True if we negotiated ALPN.
+ bool was_alpn_negotiated_;
// Protocol negotiated with the server.
- NextProto protocol_negotiated_;
+ NextProto negotiated_protocol_;
// 0 if we're not preconnecting. Otherwise, the number of streams to
// preconnect.
int num_streams_;
- std::unique_ptr<ValidSpdySessionPool> valid_spdy_session_pool_;
-
// Initialized when we create a new SpdySession.
base::WeakPtr<SpdySession> new_spdy_session_;
@@ -518,10 +470,6 @@ class HttpStreamFactoryImpl::Job {
// Only used if |new_spdy_session_| is non-NULL.
bool spdy_session_direct_;
- JobStatus job_status_;
- JobStatus other_job_status_;
- base::TimeTicks job_stream_ready_start_time_;
-
// Type of stream that is requested.
HttpStreamRequest::StreamType stream_type_;
@@ -535,7 +483,7 @@ class HttpStreamFactoryImpl::JobFactory {
public:
virtual ~JobFactory() {}
- // Creates an alternative Job.
+ // Creates an alternative service Job.
virtual HttpStreamFactoryImpl::Job* CreateJob(
HttpStreamFactoryImpl::Job::Delegate* delegate,
HttpStreamFactoryImpl::JobType job_type,
@@ -549,6 +497,20 @@ class HttpStreamFactoryImpl::JobFactory {
AlternativeService alternative_service,
NetLog* net_log) = 0;
+ // Creates an alternative proxy server Job.
+ virtual HttpStreamFactoryImpl::Job* CreateJob(
+ HttpStreamFactoryImpl::Job::Delegate* delegate,
+ HttpStreamFactoryImpl::JobType job_type,
+ HttpNetworkSession* session,
+ const HttpRequestInfo& request_info,
+ RequestPriority priority,
+ const SSLConfig& server_ssl_config,
+ const SSLConfig& proxy_ssl_config,
+ HostPortPair destination,
+ GURL origin_url,
+ const ProxyServer& alternative_proxy_server,
+ NetLog* net_log) = 0;
+
// Creates a non-alternative Job.
virtual HttpStreamFactoryImpl::Job* CreateJob(
HttpStreamFactoryImpl::Job::Delegate* delegate,
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 3a6a63674a6..57112766547 100644
--- a/chromium/net/http/http_stream_factory_impl_job_controller.cc
+++ b/chromium/net/http/http_stream_factory_impl_job_controller.cc
@@ -4,16 +4,37 @@
#include "net/http/http_stream_factory_impl_job_controller.h"
+#include <memory>
+#include <string>
+#include <utility>
+
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
+#include "base/values.h"
#include "net/base/host_mapping_rules.h"
+#include "net/base/proxy_delegate.h"
#include "net/http/bidirectional_stream_impl.h"
#include "net/http/transport_security_state.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.h"
+#include "net/proxy/proxy_server.h"
#include "net/spdy/spdy_session.h"
+#include "url/url_constants.h"
namespace net {
+// Returns parameters associated with the delay of the HTTP stream job.
+std::unique_ptr<base::Value> NetLogHttpStreamJobDelayCallback(
+ base::TimeDelta delay,
+ NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetInteger("resume_after_ms", static_cast<int>(delay.InMilliseconds()));
+ return std::move(dict);
+}
+
HttpStreamFactoryImpl::JobController::JobController(
HttpStreamFactoryImpl* factory,
HttpStreamRequest::Delegate* delegate,
@@ -25,8 +46,12 @@ HttpStreamFactoryImpl::JobController::JobController(
request_(nullptr),
delegate_(delegate),
is_preconnect_(false),
+ alternative_job_failed_(false),
job_bound_(false),
- bound_job_(nullptr) {
+ main_job_is_blocked_(false),
+ bound_job_(nullptr),
+ can_start_alternative_proxy_job_(false),
+ ptr_factory_(this) {
DCHECK(factory);
}
@@ -45,7 +70,7 @@ HttpStreamFactoryImpl::Request* HttpStreamFactoryImpl::JobController::Start(
HttpStreamRequest::Delegate* delegate,
WebSocketHandshakeStreamBase::CreateHelper*
websocket_handshake_stream_create_helper,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
HttpStreamRequest::StreamType stream_type,
RequestPriority priority,
const SSLConfig& server_ssl_config,
@@ -158,7 +183,7 @@ void HttpStreamFactoryImpl::JobController::OnStreamReady(
std::unique_ptr<HttpStream> stream = job->ReleaseStream();
DCHECK(stream);
- MarkRequestComplete(job->was_npn_negotiated(), job->protocol_negotiated(),
+ MarkRequestComplete(job->was_alpn_negotiated(), job->negotiated_protocol(),
job->using_spdy());
if (!request_)
@@ -181,7 +206,7 @@ void HttpStreamFactoryImpl::JobController::OnBidirectionalStreamImplReady(
return;
}
- MarkRequestComplete(job->was_npn_negotiated(), job->protocol_negotiated(),
+ MarkRequestComplete(job->was_alpn_negotiated(), job->negotiated_protocol(),
job->using_spdy());
if (!request_)
@@ -203,8 +228,7 @@ void HttpStreamFactoryImpl::JobController::OnWebSocketHandshakeStreamReady(
const ProxyInfo& used_proxy_info,
WebSocketHandshakeStreamBase* stream) {
DCHECK(job);
-
- MarkRequestComplete(job->was_npn_negotiated(), job->protocol_negotiated(),
+ MarkRequestComplete(job->was_alpn_negotiated(), job->negotiated_protocol(),
job->using_spdy());
if (!request_)
@@ -222,6 +246,11 @@ void HttpStreamFactoryImpl::JobController::OnStreamFailed(
Job* job,
int status,
const SSLConfig& used_ssl_config) {
+ if (job->job_type() == ALTERNATIVE)
+ OnAlternativeJobFailed(job);
+
+ MaybeResumeMainJob(job, base::TimeDelta());
+
if (job_bound_ && bound_job_ != job) {
// We have bound a job to the associated Request, |job| has been orphaned.
OnOrphanedJobComplete(job);
@@ -238,13 +267,10 @@ void HttpStreamFactoryImpl::JobController::OnStreamFailed(
// Hey, we've got other jobs! Maybe one of them will succeed, let's just
// ignore this failure.
factory_->request_map_.erase(job);
- // Notify all the other jobs that this one failed.
if (job->job_type() == MAIN) {
- alternative_job_->MarkOtherJobComplete(*job);
main_job_.reset();
} else {
DCHECK(job->job_type() == ALTERNATIVE);
- main_job_->MarkOtherJobComplete(*job);
alternative_job_.reset();
}
return;
@@ -261,6 +287,8 @@ void HttpStreamFactoryImpl::JobController::OnCertificateError(
int status,
const SSLConfig& used_ssl_config,
const SSLInfo& ssl_info) {
+ MaybeResumeMainJob(job, base::TimeDelta());
+
if (job_bound_ && bound_job_ != job) {
// We have bound a job to the associated Request, |job| has been orphaned.
OnOrphanedJobComplete(job);
@@ -282,6 +310,8 @@ void HttpStreamFactoryImpl::JobController::OnHttpsProxyTunnelResponse(
const SSLConfig& used_ssl_config,
const ProxyInfo& used_proxy_info,
HttpStream* stream) {
+ MaybeResumeMainJob(job, base::TimeDelta());
+
if (job_bound_ && bound_job_ != job) {
// We have bound a job to the associated Request, |job| has been orphaned.
OnOrphanedJobComplete(job);
@@ -300,6 +330,8 @@ void HttpStreamFactoryImpl::JobController::OnNeedsClientAuth(
Job* job,
const SSLConfig& used_ssl_config,
SSLCertRequestInfo* cert_info) {
+ MaybeResumeMainJob(job, base::TimeDelta());
+
if (job_bound_ && bound_job_ != job) {
// We have bound a job to the associated Request, |job| has been orphaned.
OnOrphanedJobComplete(job);
@@ -319,6 +351,8 @@ void HttpStreamFactoryImpl::JobController::OnNeedsProxyAuth(
const SSLConfig& used_ssl_config,
const ProxyInfo& used_proxy_info,
HttpAuthController* auth_controller) {
+ MaybeResumeMainJob(job, base::TimeDelta());
+
if (job_bound_ && bound_job_ != job) {
// We have bound a job to the associated Request, |job| has been orphaned.
OnOrphanedJobComplete(job);
@@ -333,6 +367,46 @@ void HttpStreamFactoryImpl::JobController::OnNeedsProxyAuth(
auth_controller);
}
+void HttpStreamFactoryImpl::JobController::OnResolveProxyComplete(
+ Job* job,
+ const HttpRequestInfo& request_info,
+ RequestPriority priority,
+ const SSLConfig& server_ssl_config,
+ const SSLConfig& proxy_ssl_config,
+ HttpStreamRequest::StreamType stream_type) {
+ DCHECK(job);
+
+ ProxyServer alternative_proxy_server;
+ if (!ShouldCreateAlternativeProxyServerJob(job, job->proxy_info(),
+ request_info.url,
+ &alternative_proxy_server)) {
+ return;
+ }
+
+ DCHECK(main_job_);
+ DCHECK_EQ(MAIN, job->job_type());
+ DCHECK(!alternative_job_);
+ DCHECK(!main_job_is_blocked_);
+
+ HostPortPair destination(HostPortPair::FromURL(request_info.url));
+ GURL origin_url = ApplyHostMappingRules(request_info.url, &destination);
+
+ alternative_job_.reset(job_factory_->CreateJob(
+ this, ALTERNATIVE, session_, request_info, priority, server_ssl_config,
+ proxy_ssl_config, destination, origin_url, alternative_proxy_server,
+ job->net_log().net_log()));
+ AttachJob(alternative_job_.get());
+
+ can_start_alternative_proxy_job_ = false;
+ main_job_is_blocked_ = true;
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &HttpStreamFactoryImpl::JobController::StartAlternativeProxyServerJob,
+ ptr_factory_.GetWeakPtr()));
+}
+
void HttpStreamFactoryImpl::JobController::OnNewSpdySessionReady(
Job* job,
const base::WeakPtr<SpdySession>& spdy_session,
@@ -345,16 +419,19 @@ void HttpStreamFactoryImpl::JobController::OnNewSpdySessionReady(
// Cache these values in case the job gets deleted.
const SSLConfig used_ssl_config = job->server_ssl_config();
const ProxyInfo used_proxy_info = job->proxy_info();
- const bool was_npn_negotiated = job->was_npn_negotiated();
- const NextProto protocol_negotiated = job->protocol_negotiated();
+ const bool was_alpn_negotiated = job->was_alpn_negotiated();
+ const NextProto negotiated_protocol = job->negotiated_protocol();
const bool using_spdy = job->using_spdy();
- const BoundNetLog net_log = job->net_log();
+ const NetLogWithSource net_log = job->net_log();
// Cache this so we can still use it if the JobController is deleted.
HttpStreamFactoryImpl* factory = factory_;
// Notify |request_|.
if (!is_preconnect_ && !is_job_orphaned) {
+ if (job->job_type() == MAIN && alternative_job_failed_)
+ ReportBrokenAlternativeService();
+
DCHECK(request_);
// The first case is the usual case.
@@ -362,7 +439,7 @@ void HttpStreamFactoryImpl::JobController::OnNewSpdySessionReady(
BindJob(job);
}
- MarkRequestComplete(was_npn_negotiated, protocol_negotiated, using_spdy);
+ MarkRequestComplete(was_alpn_negotiated, negotiated_protocol, using_spdy);
std::unique_ptr<HttpStream> stream;
std::unique_ptr<BidirectionalStreamImpl> bidirectional_stream_impl;
@@ -388,8 +465,8 @@ void HttpStreamFactoryImpl::JobController::OnNewSpdySessionReady(
// Notify |factory_|. |request_| and |bounded_job_| might be deleted already.
if (spdy_session && spdy_session->IsAvailable()) {
factory->OnNewSpdySessionReady(spdy_session, direct, used_ssl_config,
- used_proxy_info, was_npn_negotiated,
- protocol_negotiated, using_spdy, net_log);
+ used_proxy_info, was_alpn_negotiated,
+ negotiated_protocol, using_spdy, net_log);
}
if (is_job_orphaned) {
OnOrphanedJobComplete(job);
@@ -426,6 +503,64 @@ void HttpStreamFactoryImpl::JobController::AddConnectionAttemptsToRequest(
request_->AddConnectionAttempts(attempts);
}
+void HttpStreamFactoryImpl::JobController::ResumeMainJob() {
+ main_job_->net_log().AddEvent(
+ NetLogEventType::HTTP_STREAM_JOB_DELAYED,
+ base::Bind(&NetLogHttpStreamJobDelayCallback, main_job_wait_time_));
+
+ main_job_->Resume();
+ main_job_wait_time_ = base::TimeDelta();
+}
+
+void HttpStreamFactoryImpl::JobController::MaybeResumeMainJob(
+ Job* job,
+ const base::TimeDelta& delay) {
+ DCHECK(job == main_job_.get() || job == alternative_job_.get());
+
+ if (!main_job_is_blocked_ || job != alternative_job_.get() || !main_job_)
+ return;
+
+ main_job_is_blocked_ = false;
+
+ if (!main_job_->is_waiting())
+ return;
+
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&HttpStreamFactoryImpl::JobController::ResumeMainJob,
+ ptr_factory_.GetWeakPtr()),
+ main_job_wait_time_);
+}
+
+void HttpStreamFactoryImpl::JobController::OnConnectionInitialized(Job* job,
+ int rv) {
+ if (rv != OK) {
+ // Resume the main job as there's an error raised in connection
+ // initiation.
+ return MaybeResumeMainJob(job, main_job_wait_time_);
+ }
+}
+
+bool HttpStreamFactoryImpl::JobController::ShouldWait(Job* job) {
+ // The alternative job never waits.
+ if (job == alternative_job_.get())
+ return false;
+
+ if (main_job_is_blocked_)
+ return true;
+
+ if (main_job_wait_time_.is_zero())
+ return false;
+
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&HttpStreamFactoryImpl::JobController::ResumeMainJob,
+ ptr_factory_.GetWeakPtr()),
+ main_job_wait_time_);
+
+ return true;
+}
+
void HttpStreamFactoryImpl::JobController::SetSpdySessionKey(
Job* job,
const SpdySessionKey& spdy_session_key) {
@@ -436,7 +571,7 @@ void HttpStreamFactoryImpl::JobController::SetSpdySessionKey(
if (!request_->HasSpdySessionKey()) {
RequestSet& request_set =
factory_->spdy_session_request_map_[spdy_session_key];
- DCHECK(!ContainsKey(request_set, request_));
+ DCHECK(!base::ContainsKey(request_set, request_));
request_set.insert(request_);
request_->SetSpdySessionKey(spdy_session_key);
}
@@ -457,9 +592,9 @@ void HttpStreamFactoryImpl::JobController::
if (spdy_session_key) {
SpdySessionRequestMap& spdy_session_request_map =
factory_->spdy_session_request_map_;
- DCHECK(ContainsKey(spdy_session_request_map, *spdy_session_key));
+ DCHECK(base::ContainsKey(spdy_session_request_map, *spdy_session_key));
RequestSet& request_set = spdy_session_request_map[*spdy_session_key];
- DCHECK(ContainsKey(request_set, request_));
+ DCHECK(base::ContainsKey(request_set, request_));
request_set.erase(request_);
if (request_set.empty())
spdy_session_request_map.erase(*spdy_session_key);
@@ -467,7 +602,7 @@ void HttpStreamFactoryImpl::JobController::
}
}
-const BoundNetLog* HttpStreamFactoryImpl::JobController::GetNetLog(
+const NetLogWithSource* HttpStreamFactoryImpl::JobController::GetNetLog(
Job* job) const {
if (is_preconnect_ || (job_bound_ && bound_job_ != job))
return nullptr;
@@ -475,6 +610,12 @@ const BoundNetLog* HttpStreamFactoryImpl::JobController::GetNetLog(
return &request_->net_log();
}
+void HttpStreamFactoryImpl::JobController::MaybeSetWaitTimeForMainJob(
+ const base::TimeDelta& delay) {
+ if (main_job_is_blocked_)
+ main_job_wait_time_ = delay;
+}
+
WebSocketHandshakeStreamBase::CreateHelper* HttpStreamFactoryImpl::
JobController::websocket_handshake_stream_create_helper() {
DCHECK(request_);
@@ -488,7 +629,7 @@ void HttpStreamFactoryImpl::JobController::CreateJobs(
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::Delegate* delegate,
HttpStreamRequest::StreamType stream_type,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
DCHECK(!main_job_);
DCHECK(!alternative_job_);
HostPortPair destination(HostPortPair::FromURL(request_info.url));
@@ -509,7 +650,7 @@ void HttpStreamFactoryImpl::JobController::CreateJobs(
<< alternative_service.host_port_pair().host()
<< " port: " << alternative_service.host_port_pair().port() << ")";
- DCHECK(!request_info.url.SchemeIs("ftp"));
+ DCHECK(!request_info.url.SchemeIs(url::kFtpScheme));
HostPortPair alternative_destination(alternative_service.host_port_pair());
ignore_result(
ApplyHostMappingRules(request_info.url, &alternative_destination));
@@ -520,11 +661,10 @@ void HttpStreamFactoryImpl::JobController::CreateJobs(
alternative_service, net_log.net_log()));
AttachJob(alternative_job_.get());
- main_job_->WaitFor(alternative_job_.get());
- // Make sure to wait until we call WaitFor(), before starting
- // |alternative_job|, otherwise |alternative_job| will not notify |job|
- // appropriately.
+ main_job_is_blocked_ = true;
alternative_job_->Start(request_->stream_type());
+ } else {
+ can_start_alternative_proxy_job_ = true;
}
// Even if |alternative_job| has already finished, it will not have notified
// the request yet, since we defer that to the next iteration of the
@@ -549,10 +689,10 @@ void HttpStreamFactoryImpl::JobController::BindJob(Job* job) {
factory_->request_map_.erase(job);
request_->net_log().AddEvent(
- NetLog::TYPE_HTTP_STREAM_REQUEST_BOUND_TO_JOB,
+ NetLogEventType::HTTP_STREAM_REQUEST_BOUND_TO_JOB,
job->net_log().source().ToEventParametersCallback());
job->net_log().AddEvent(
- NetLog::TYPE_HTTP_STREAM_JOB_BOUND_TO_REQUEST,
+ NetLogEventType::HTTP_STREAM_JOB_BOUND_TO_REQUEST,
request_->net_log().source().ToEventParametersCallback());
OrphanUnboundJob();
@@ -604,17 +744,13 @@ void HttpStreamFactoryImpl::JobController::OnJobSucceeded(Job* job) {
CancelJobs();
return;
}
+
+ if (job->job_type() == MAIN && alternative_job_failed_)
+ ReportBrokenAlternativeService();
+
if (!bound_job_) {
- if (main_job_ && alternative_job_) {
- job->ReportJobSucceededForRequest();
- // Notify all the other jobs that this one succeeded.
- if (job->job_type() == MAIN) {
- alternative_job_->MarkOtherJobComplete(*job);
- } else {
- DCHECK(job->job_type() == ALTERNATIVE);
- main_job_->MarkOtherJobComplete(*job);
- }
- }
+ if (main_job_ && alternative_job_)
+ ReportAlternateProtocolUsage(job);
BindJob(job);
return;
}
@@ -622,11 +758,51 @@ void HttpStreamFactoryImpl::JobController::OnJobSucceeded(Job* job) {
}
void HttpStreamFactoryImpl::JobController::MarkRequestComplete(
- bool was_npn_negotiated,
- NextProto protocol_negotiated,
+ bool was_alpn_negotiated,
+ NextProto negotiated_protocol,
bool using_spdy) {
if (request_)
- request_->Complete(was_npn_negotiated, protocol_negotiated, using_spdy);
+ request_->Complete(was_alpn_negotiated, negotiated_protocol, using_spdy);
+}
+
+void HttpStreamFactoryImpl::JobController::OnAlternativeJobFailed(Job* job) {
+ DCHECK_EQ(job->job_type(), ALTERNATIVE);
+
+ alternative_job_failed_ = true;
+
+ if (job->alternative_proxy_server().is_valid()) {
+ failed_alternative_proxy_server_ = job->alternative_proxy_server();
+ } else {
+ DCHECK(!failed_alternative_proxy_server_.is_valid());
+ failed_alternative_service_ = job->alternative_service();
+ }
+
+ if (!request_ || (job_bound_ && bound_job_ != job)) {
+ // If |request_| is gone then it must have been successfully served by
+ // |main_job_|.
+ // If |request_| is bound to a different job, then it is being
+ // successfully serverd by the main job.
+ ReportBrokenAlternativeService();
+ }
+}
+
+void HttpStreamFactoryImpl::JobController::ReportBrokenAlternativeService() {
+ DCHECK(failed_alternative_service_.protocol !=
+ UNINITIALIZED_ALTERNATE_PROTOCOL ||
+ failed_alternative_proxy_server_.is_valid());
+
+ if (failed_alternative_proxy_server_.is_valid()) {
+ ProxyDelegate* proxy_delegate = session_->params().proxy_delegate;
+ if (proxy_delegate)
+ proxy_delegate->OnAlternativeProxyBroken(
+ failed_alternative_proxy_server_);
+ } else {
+ HistogramBrokenAlternateProtocolLocation(
+ BROKEN_ALTERNATE_PROTOCOL_LOCATION_HTTP_STREAM_FACTORY_IMPL_JOB_ALT);
+ session_->http_server_properties()->MarkAlternativeServiceBroken(
+ failed_alternative_service_);
+ }
+ session_->quic_stream_factory()->OnTcpJobCompleted(true);
}
void HttpStreamFactoryImpl::JobController::MaybeNotifyFactoryOfCompletion() {
@@ -668,8 +844,8 @@ bool HttpStreamFactoryImpl::JobController::IsQuicWhitelistedForHost(
if (session_->params().transport_security_state->IsGooglePinnedHost(host))
return true;
- return ContainsKey(session_->params().quic_host_whitelist,
- base::ToLowerASCII(host));
+ return base::ContainsKey(session_->params().quic_host_whitelist,
+ base::ToLowerASCII(host));
}
AlternativeService
@@ -707,7 +883,7 @@ HttpStreamFactoryImpl::JobController::GetAlternativeServiceForInternal(
HttpStreamRequest::StreamType stream_type) {
GURL original_url = request_info.url;
- if (!original_url.SchemeIs("https"))
+ if (!original_url.SchemeIs(url::kHttpsScheme))
return AlternativeService();
url::SchemeHostPort origin(original_url);
@@ -731,7 +907,7 @@ HttpStreamFactoryImpl::JobController::GetAlternativeServiceForInternal(
quic_advertised = true;
if (http_server_properties.IsAlternativeServiceBroken(
alternative_service)) {
- HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_BROKEN);
+ HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_BROKEN, false);
continue;
}
@@ -748,12 +924,7 @@ HttpStreamFactoryImpl::JobController::GetAlternativeServiceForInternal(
origin.port() < kUnrestrictedPort))
continue;
- if (alternative_service.protocol >= NPN_SPDY_MINIMUM_VERSION &&
- alternative_service.protocol <= NPN_SPDY_MAXIMUM_VERSION) {
- if (alternative_service.protocol == NPN_SPDY_3_1 &&
- !HttpStreamFactory::spdy_enabled())
- continue;
-
+ if (alternative_service.protocol == NPN_HTTP_2) {
if (origin.host() != alternative_service.host &&
!session_->params()
.enable_http2_alternative_service_with_different_host) {
@@ -786,11 +957,10 @@ HttpStreamFactoryImpl::JobController::GetAlternativeServiceForInternal(
continue;
}
- if (session_->quic_stream_factory()->IsQuicDisabled(
- alternative_service.port))
+ if (session_->quic_stream_factory()->IsQuicDisabled())
continue;
- if (!original_url.SchemeIs("https"))
+ if (!original_url.SchemeIs(url::kHttpsScheme))
continue;
// Check whether there is an existing QUIC session to use for this origin.
@@ -817,4 +987,103 @@ HttpStreamFactoryImpl::JobController::GetAlternativeServiceForInternal(
return first_alternative_service;
}
+
+bool HttpStreamFactoryImpl::JobController::
+ ShouldCreateAlternativeProxyServerJob(
+ Job* job,
+ const ProxyInfo& proxy_info,
+ const GURL& url,
+ ProxyServer* alternative_proxy_server) const {
+ DCHECK(!alternative_proxy_server->is_valid());
+ if (!can_start_alternative_proxy_job_) {
+ // Either an alternative service job or an alternative proxy server job has
+ // already been started.
+ return false;
+ }
+
+ if (job->job_type() == ALTERNATIVE) {
+ // If |job| is using alternative service, then alternative proxy server
+ // should not be used.
+ return false;
+ }
+
+ if (is_preconnect_ || job->job_type() == PRECONNECT) {
+ // Preconnects should be fetched using only the main job to keep the
+ // resource utilization down.
+ return false;
+ }
+
+ if (proxy_info.is_empty() || proxy_info.is_direct() || proxy_info.is_quic()) {
+ // Alternative proxy server job can be created only if |job| fetches the
+ // |request_| through a non-QUIC proxy.
+ return false;
+ }
+
+ if (!url.SchemeIs(url::kHttpScheme)) {
+ // Only HTTP URLs can be fetched through alternative proxy server, since the
+ // alternative proxy server may not support fetching of URLs with other
+ // schemes.
+ return false;
+ }
+
+ ProxyDelegate* proxy_delegate = session_->params().proxy_delegate;
+ if (!proxy_delegate)
+ return false;
+
+ proxy_delegate->GetAlternativeProxy(url, proxy_info.proxy_server(),
+ alternative_proxy_server);
+
+ if (!alternative_proxy_server->is_valid())
+ return false;
+
+ DCHECK(!(*alternative_proxy_server == proxy_info.proxy_server()));
+
+ if (!alternative_proxy_server->is_https() &&
+ !alternative_proxy_server->is_quic()) {
+ // Alternative proxy server should be a secure server.
+ return false;
+ }
+
+ if (alternative_proxy_server->is_quic()) {
+ // Check that QUIC is enabled globally, and it is not disabled.
+ if (!session_->params().enable_quic ||
+ session_->quic_stream_factory()->IsQuicDisabled()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void HttpStreamFactoryImpl::JobController::ReportAlternateProtocolUsage(
+ Job* job) const {
+ DCHECK(main_job_ && alternative_job_);
+
+ bool proxy_server_used =
+ alternative_job_->alternative_proxy_server().is_quic();
+
+ if (job == main_job_.get()) {
+ HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_LOST_RACE,
+ proxy_server_used);
+ return;
+ }
+
+ DCHECK_EQ(alternative_job_.get(), job);
+ if (job->using_existing_quic_session()) {
+ HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_NO_RACE,
+ proxy_server_used);
+ return;
+ }
+
+ HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_WON_RACE,
+ proxy_server_used);
}
+
+void HttpStreamFactoryImpl::JobController::StartAlternativeProxyServerJob() {
+ if (!alternative_job_ || !request_)
+ return;
+ DCHECK(alternative_job_->alternative_proxy_server().is_valid());
+ alternative_job_->Start(request_->stream_type());
+}
+
+} // namespace net
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 79a9298b682..770071f68b1 100644
--- a/chromium/net/http/http_stream_factory_impl_job_controller.h
+++ b/chromium/net/http/http_stream_factory_impl_job_controller.h
@@ -5,11 +5,14 @@
#ifndef NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_CONTROLLER_H_
#define NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_CONTROLLER_H_
+#include "net/base/host_port_pair.h"
#include "net/http/http_stream_factory_impl_job.h"
#include "net/http/http_stream_factory_impl_request.h"
namespace net {
+class NetLogWithSource;
+
// HttpStreamFactoryImpl::JobController manages Request and Job(s).
class HttpStreamFactoryImpl::JobController
: public HttpStreamFactoryImpl::Job::Delegate,
@@ -37,7 +40,7 @@ class HttpStreamFactoryImpl::JobController
HttpStreamRequest::Delegate* delegate,
WebSocketHandshakeStreamBase::CreateHelper*
websocket_handshake_stream_create_helper,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
HttpStreamRequest::StreamType stream_type,
RequestPriority priority,
const SSLConfig& server_ssl_config,
@@ -114,6 +117,14 @@ class HttpStreamFactoryImpl::JobController
const ProxyInfo& used_proxy_info,
HttpAuthController* auth_controller) override;
+ void OnResolveProxyComplete(
+ Job* job,
+ const HttpRequestInfo& request_info,
+ RequestPriority priority,
+ const SSLConfig& server_ssl_config,
+ const SSLConfig& proxy_ssl_config,
+ HttpStreamRequest::StreamType stream_type) override;
+
// Invoked to notify the Request and Factory of the readiness of new
// SPDY session.
void OnNewSpdySessionReady(Job* job,
@@ -132,6 +143,14 @@ class HttpStreamFactoryImpl::JobController
Job* job,
const ConnectionAttempts& attempts) override;
+ // Invoked when |job| finishes initiating a connection.
+ // Resume the other job if there's an error raised.
+ void OnConnectionInitialized(Job* job, int rv) override;
+
+ // Return false if |job| can advance to the next state. Otherwise, |job|
+ // will wait for Job::Resume() to be called before advancing.
+ bool ShouldWait(Job* job) override;
+
// Called when |job| determines the appropriate |spdy_session_key| for the
// Request. Note that this does not mean that SPDY is necessarily supported
// for this SpdySessionKey, since we may need to wait for NPN to complete
@@ -141,12 +160,15 @@ class HttpStreamFactoryImpl::JobController
// Remove session from the SpdySessionRequestMap.
void RemoveRequestFromSpdySessionRequestMapForJob(Job* job) override;
- const BoundNetLog* GetNetLog(Job* job) const override;
+ const NetLogWithSource* GetNetLog(Job* job) const override;
+
+ void MaybeSetWaitTimeForMainJob(const base::TimeDelta& delay) override;
+
WebSocketHandshakeStreamBase::CreateHelper*
websocket_handshake_stream_create_helper() override;
private:
- FRIEND_TEST_ALL_PREFIXES(HttpStreamFactoryImplRequestTest, DelayMainJob);
+ friend class JobControllerPeer;
// Creates Job(s) for |request_|. Job(s) will be owned by |this|.
void CreateJobs(const HttpRequestInfo& request_info,
@@ -155,7 +177,7 @@ class HttpStreamFactoryImpl::JobController
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::Delegate* delegate,
HttpStreamRequest::StreamType stream_type,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Attaches |job| to |request_|. Does not mean that |request_| will use |job|.
void AttachJob(Job* job);
@@ -177,12 +199,24 @@ class HttpStreamFactoryImpl::JobController
void OnJobSucceeded(Job* job);
// Marks completion of the |request_|.
- void MarkRequestComplete(bool was_npn_negotiated,
- NextProto protocol_negotiated,
+ void MarkRequestComplete(bool was_alpn_negotiated,
+ NextProto negotiated_protocol,
bool using_spdy);
+ // Must be called when |alternative_job_| fails.
+ void OnAlternativeJobFailed(Job* job);
+
+ // Called to report to http_server_properties to mark alternative service
+ // broken.
+ void ReportBrokenAlternativeService();
+
void MaybeNotifyFactoryOfCompletion();
+ // Called to resume the main job with delay.
+ void MaybeResumeMainJob(Job* job, const base::TimeDelta& delay);
+
+ void ResumeMainJob();
+
// Returns true if QUIC is whitelisted for |host|.
bool IsQuicWhitelistedForHost(const std::string& host);
@@ -199,6 +233,23 @@ class HttpStreamFactoryImpl::JobController
// Remove session from the SpdySessionRequestMap.
void RemoveRequestFromSpdySessionRequestMap();
+ // Returns true if the |request_| can be fetched via an alternative
+ // proxy server, and sets |alternative_proxy_server| to the available
+ // alternative proxy server. |alternative_proxy_server| should not be null,
+ // and is owned by the caller.
+ bool ShouldCreateAlternativeProxyServerJob(
+ Job* job,
+ const ProxyInfo& proxy_info_,
+ const GURL& url,
+ ProxyServer* alternative_proxy_server) const;
+
+ // Records histogram metrics for the usage of alternative protocol. Must be
+ // called when |job| has succeeded and the other job will be orphaned.
+ void ReportAlternateProtocolUsage(Job* job) const;
+
+ // Starts the |alternative_job_|.
+ void StartAlternativeProxyServerJob();
+
HttpStreamFactoryImpl* factory_;
HttpNetworkSession* session_;
JobFactory* job_factory_;
@@ -220,12 +271,32 @@ class HttpStreamFactoryImpl::JobController
std::unique_ptr<Job> main_job_;
std::unique_ptr<Job> alternative_job_;
+ // True if |alternative_job_| uses alternative service/proxy server and it
+ // fails.
+ bool alternative_job_failed_;
+
+ // Either and only one of these records failed alternative service/proxy
+ // server that |alternative_job_| uses.
+ AlternativeService failed_alternative_service_;
+ ProxyServer failed_alternative_proxy_server_;
+
// True if a Job has ever been bound to the |request_|.
bool job_bound_;
+ // True if the main job has to wait for the alternative job: i.e., the main
+ // job must not create a connection until it is resumed.
+ bool main_job_is_blocked_;
+ // Waiting time for the main job before it is resumed.
+ base::TimeDelta main_job_wait_time_;
+
// At the point where a Job is irrevocably tied to |request_|, we set this.
// It will be nulled when the |request_| is finished.
Job* bound_job_;
+
+ // True if an alternative proxy server job can be started to fetch |request_|.
+ bool can_start_alternative_proxy_job_;
+
+ base::WeakPtrFactory<JobController> ptr_factory_;
};
} // namespace net
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 fae31f1da25..6464e852d68 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
@@ -6,12 +6,24 @@
#include <memory>
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/test/histogram_tester.h"
+#include "base/threading/platform_thread.h"
+#include "net/base/test_proxy_delegate.h"
+#include "net/dns/mock_host_resolver.h"
#include "net/http/http_basic_stream.h"
#include "net/http/http_stream_factory_impl_request.h"
#include "net/http/http_stream_factory_test_util.h"
+#include "net/log/net_log_with_source.h"
+#include "net/proxy/mock_proxy_resolver.h"
+#include "net/proxy/proxy_config_service_fixed.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_service.h"
+#include "net/quic/test_tools/quic_stream_factory_peer.h"
#include "net/spdy/spdy_test_util_common.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gmock_mutant.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
@@ -27,15 +39,100 @@ void DeleteHttpStreamPointer(const SSLConfig& used_ssl_config,
delete stream;
}
+class FailingProxyResolverFactory : public ProxyResolverFactory {
+ public:
+ FailingProxyResolverFactory() : ProxyResolverFactory(false) {}
+
+ // ProxyResolverFactory override.
+ int CreateProxyResolver(
+ const scoped_refptr<ProxyResolverScriptData>& script_data,
+ std::unique_ptr<ProxyResolver>* result,
+ const CompletionCallback& callback,
+ std::unique_ptr<Request>* request) override {
+ return ERR_PAC_SCRIPT_FAILED;
+ }
+};
+
+class FailingHostResolver : public MockHostResolverBase {
+ public:
+ FailingHostResolver() : MockHostResolverBase(false /*use_caching*/) {}
+ ~FailingHostResolver() override {}
+
+ int Resolve(const RequestInfo& info,
+ RequestPriority priority,
+ AddressList* addresses,
+ const CompletionCallback& callback,
+ std::unique_ptr<Request>* out_req,
+ const NetLogWithSource& net_log) override {
+ return ERR_NAME_NOT_RESOLVED;
+ }
+};
+
+class HangingResolver : public MockHostResolverBase {
+ public:
+ HangingResolver() : MockHostResolverBase(false /*use_caching*/) {}
+ ~HangingResolver() override {}
+
+ int Resolve(const RequestInfo& info,
+ RequestPriority priority,
+ AddressList* addresses,
+ const CompletionCallback& callback,
+ std::unique_ptr<Request>* out_req,
+ const NetLogWithSource& net_log) override {
+ return ERR_IO_PENDING;
+ }
+};
} // anonymous namespace
+class HttpStreamFactoryImplJobPeer {
+ public:
+ static void Start(HttpStreamFactoryImpl::Job* job,
+ HttpStreamRequest::StreamType stream_type) {
+ // Start() is mocked for MockHttpStreamFactoryImplJob.
+ // This is the alternative method to invoke real Start() method on Job.
+ job->stream_type_ = stream_type;
+ job->StartInternal();
+ }
+};
+
+class JobControllerPeer {
+ public:
+ static void VerifyWaitingTimeForMainJob(
+ HttpStreamFactoryImpl::JobController* job_controller,
+ const base::TimeDelta& delay) {
+ EXPECT_EQ(delay, job_controller->main_job_wait_time_);
+ }
+
+ static bool main_job_is_blocked(
+ HttpStreamFactoryImpl::JobController* job_controller) {
+ return job_controller->main_job_is_blocked_;
+ }
+};
+
class HttpStreamFactoryImplJobControllerTest
: public ::testing::Test,
public ::testing::WithParamInterface<NextProto> {
public:
HttpStreamFactoryImplJobControllerTest()
- : session_deps_(GetParam(), ProxyService::CreateDirect()) {
+ : session_deps_(ProxyService::CreateDirect()) {
session_deps_.enable_quic = true;
+ }
+
+ void Initialize(bool use_alternative_proxy) {
+ std::unique_ptr<TestProxyDelegate> test_proxy_delegate(
+ new TestProxyDelegate());
+ test_proxy_delegate_ = test_proxy_delegate.get();
+
+ test_proxy_delegate->set_alternative_proxy_server(
+ ProxyServer::FromPacString("QUIC myproxy.org:443"));
+ EXPECT_TRUE(test_proxy_delegate->alternative_proxy_server().is_quic());
+ session_deps_.proxy_delegate.reset(test_proxy_delegate.release());
+
+ if (use_alternative_proxy) {
+ std::unique_ptr<ProxyService> proxy_service =
+ ProxyService::CreateFixedFromPacResult("HTTPS myproxy.org:443");
+ session_deps_.proxy_service.reset(proxy_service.release());
+ }
session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
factory_ =
static_cast<HttpStreamFactoryImpl*>(session_->http_stream_factory());
@@ -44,6 +141,10 @@ class HttpStreamFactoryImplJobControllerTest
HttpStreamFactoryImplPeer::AddJobController(factory_, job_controller_);
}
+ TestProxyDelegate* test_proxy_delegate() const {
+ return test_proxy_delegate_;
+ }
+
~HttpStreamFactoryImplJobControllerTest() {}
void SetAlternativeService(const HttpRequestInfo& request_info,
@@ -55,6 +156,19 @@ class HttpStreamFactoryImplJobControllerTest
server, alternative_service, expiration);
}
+ void VerifyBrokenAlternateProtocolMapping(const HttpRequestInfo& request_info,
+ bool should_mark_broken) {
+ const url::SchemeHostPort server(request_info.url);
+ const AlternativeServiceVector alternative_service_vector =
+ session_->http_server_properties()->GetAlternativeServices(server);
+ EXPECT_EQ(1u, alternative_service_vector.size());
+ EXPECT_EQ(should_mark_broken,
+ session_->http_server_properties()->IsAlternativeServiceBroken(
+ alternative_service_vector[0]));
+ }
+
+ // Not owned by |this|.
+ TestProxyDelegate* test_proxy_delegate_;
TestJobFactory job_factory_;
MockHttpStreamRequestDelegate request_delegate_;
SpdySessionDependencies session_deps_;
@@ -66,19 +180,25 @@ class HttpStreamFactoryImplJobControllerTest
DISALLOW_COPY_AND_ASSIGN(HttpStreamFactoryImplJobControllerTest);
};
-INSTANTIATE_TEST_CASE_P(NextProto,
- HttpStreamFactoryImplJobControllerTest,
- testing::Values(kProtoSPDY31, kProtoHTTP2));
-
-TEST_P(HttpStreamFactoryImplJobControllerTest,
+TEST_F(HttpStreamFactoryImplJobControllerTest,
OnStreamFailedWithNoAlternativeJob) {
+ ProxyConfig proxy_config;
+ proxy_config.set_auto_detect(true);
+ // Use asynchronous proxy resolver.
+ MockAsyncProxyResolverFactory* proxy_resolver_factory =
+ new MockAsyncProxyResolverFactory(false);
+ session_deps_.proxy_service.reset(
+ new ProxyService(base::MakeUnique<ProxyConfigServiceFixed>(proxy_config),
+ base::WrapUnique(proxy_resolver_factory), nullptr));
+ Initialize(false);
+
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("http://www.google.com");
request_.reset(
job_controller_->Start(request_info, &request_delegate_, nullptr,
- BoundNetLog(), HttpStreamRequest::HTTP_STREAM,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
EXPECT_TRUE(job_controller_->main_job());
@@ -90,22 +210,31 @@ TEST_P(HttpStreamFactoryImplJobControllerTest,
SSLConfig());
}
-TEST_P(HttpStreamFactoryImplJobControllerTest,
+TEST_F(HttpStreamFactoryImplJobControllerTest,
OnStreamReadyWithNoAlternativeJob) {
+ ProxyConfig proxy_config;
+ proxy_config.set_auto_detect(true);
+ // Use asynchronous proxy resolver.
+ MockAsyncProxyResolverFactory* proxy_resolver_factory =
+ new MockAsyncProxyResolverFactory(false);
+ session_deps_.proxy_service.reset(
+ new ProxyService(base::MakeUnique<ProxyConfigServiceFixed>(proxy_config),
+ base::WrapUnique(proxy_resolver_factory), nullptr));
+ Initialize(false);
+
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("http://www.google.com");
request_.reset(
job_controller_->Start(request_info, &request_delegate_, nullptr,
- BoundNetLog(), HttpStreamRequest::HTTP_STREAM,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
- EXPECT_TRUE(job_controller_->main_job());
- // There's no other alternative job. Thus when stream is ready, it should
+ // There's no other alternative job. Thus when a stream is ready, it should
// notify Request.
HttpStream* http_stream =
- new HttpBasicStream(new ClientSocketHandle(), false);
+ new HttpBasicStream(base::MakeUnique<ClientSocketHandle>(), false, false);
job_factory_.main_job()->SetStream(http_stream);
EXPECT_CALL(request_delegate_, OnStreamReady(_, _, http_stream))
@@ -116,7 +245,17 @@ TEST_P(HttpStreamFactoryImplJobControllerTest,
// Test we cancel Jobs correctly when the Request is explicitly canceled
// before any Job is bound to Request.
-TEST_P(HttpStreamFactoryImplJobControllerTest, CancelJobsBeforeBinding) {
+TEST_F(HttpStreamFactoryImplJobControllerTest, CancelJobsBeforeBinding) {
+ ProxyConfig proxy_config;
+ proxy_config.set_auto_detect(true);
+ // Use asynchronous proxy resolver.
+ MockAsyncProxyResolverFactory* proxy_resolver_factory =
+ new MockAsyncProxyResolverFactory(false);
+ session_deps_.proxy_service.reset(new ProxyService(
+ base::WrapUnique(new ProxyConfigServiceFixed(proxy_config)),
+ base::WrapUnique(proxy_resolver_factory), nullptr));
+ Initialize(false);
+
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("https://www.google.com");
@@ -127,7 +266,7 @@ TEST_P(HttpStreamFactoryImplJobControllerTest, CancelJobsBeforeBinding) {
request_.reset(
job_controller_->Start(request_info, &request_delegate_, nullptr,
- BoundNetLog(), HttpStreamRequest::HTTP_STREAM,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
EXPECT_TRUE(job_controller_->main_job());
EXPECT_TRUE(job_controller_->alternative_job());
@@ -136,10 +275,21 @@ TEST_P(HttpStreamFactoryImplJobControllerTest, CancelJobsBeforeBinding) {
// to serve Request yet and JobController will notify the factory to delete
// itself upon completion.
request_.reset();
+ VerifyBrokenAlternateProtocolMapping(request_info, false);
EXPECT_TRUE(HttpStreamFactoryImplPeer::IsJobControllerDeleted(factory_));
}
-TEST_P(HttpStreamFactoryImplJobControllerTest, OnStreamFailedForBothJobs) {
+TEST_F(HttpStreamFactoryImplJobControllerTest, OnStreamFailedForBothJobs) {
+ ProxyConfig proxy_config;
+ proxy_config.set_auto_detect(true);
+ // Use asynchronous proxy resolver.
+ MockAsyncProxyResolverFactory* proxy_resolver_factory =
+ new MockAsyncProxyResolverFactory(false);
+ session_deps_.proxy_service.reset(
+ new ProxyService(base::MakeUnique<ProxyConfigServiceFixed>(proxy_config),
+ base::WrapUnique(proxy_resolver_factory), nullptr));
+ Initialize(false);
+
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("https://www.google.com");
@@ -150,7 +300,7 @@ TEST_P(HttpStreamFactoryImplJobControllerTest, OnStreamFailedForBothJobs) {
request_.reset(
job_controller_->Start(request_info, &request_delegate_, nullptr,
- BoundNetLog(), HttpStreamRequest::HTTP_STREAM,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
EXPECT_TRUE(job_controller_->main_job());
EXPECT_TRUE(job_controller_->alternative_job());
@@ -159,7 +309,6 @@ TEST_P(HttpStreamFactoryImplJobControllerTest, OnStreamFailedForBothJobs) {
// thus should not notify Request of the alternative job's failure. But should
// notify the main job to mark the alternative job failed.
EXPECT_CALL(request_delegate_, OnStreamFailed(_, _)).Times(0);
- EXPECT_CALL(*job_factory_.main_job(), MarkOtherJobComplete(_)).Times(1);
job_controller_->OnStreamFailed(job_factory_.alternative_job(), ERR_FAILED,
SSLConfig());
EXPECT_TRUE(!job_controller_->alternative_job());
@@ -170,10 +319,21 @@ TEST_P(HttpStreamFactoryImplJobControllerTest, OnStreamFailedForBothJobs) {
EXPECT_CALL(request_delegate_, OnStreamFailed(_, _)).Times(1);
job_controller_->OnStreamFailed(job_factory_.main_job(), ERR_FAILED,
SSLConfig());
+ VerifyBrokenAlternateProtocolMapping(request_info, false);
}
-TEST_P(HttpStreamFactoryImplJobControllerTest,
- SecondJobFailsAfterFirstJobSucceeds) {
+TEST_F(HttpStreamFactoryImplJobControllerTest,
+ AltJobFailsAfterMainJobSucceeds) {
+ ProxyConfig proxy_config;
+ proxy_config.set_auto_detect(true);
+ // Use asynchronous proxy resolver.
+ MockAsyncProxyResolverFactory* proxy_resolver_factory =
+ new MockAsyncProxyResolverFactory(false);
+ session_deps_.proxy_service.reset(
+ new ProxyService(base::MakeUnique<ProxyConfigServiceFixed>(proxy_config),
+ base::WrapUnique(proxy_resolver_factory), nullptr));
+ Initialize(false);
+
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("https://www.google.com");
@@ -184,7 +344,7 @@ TEST_P(HttpStreamFactoryImplJobControllerTest,
request_.reset(
job_controller_->Start(request_info, &request_delegate_, nullptr,
- BoundNetLog(), HttpStreamRequest::HTTP_STREAM,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
EXPECT_TRUE(job_controller_->main_job());
EXPECT_TRUE(job_controller_->alternative_job());
@@ -193,13 +353,11 @@ TEST_P(HttpStreamFactoryImplJobControllerTest,
// to Request. The alternative job will mark the main job complete and gets
// orphaned.
HttpStream* http_stream =
- new HttpBasicStream(new ClientSocketHandle(), false);
+ new HttpBasicStream(base::MakeUnique<ClientSocketHandle>(), false, false);
job_factory_.main_job()->SetStream(http_stream);
EXPECT_CALL(request_delegate_, OnStreamReady(_, _, http_stream))
.WillOnce(Invoke(DeleteHttpStreamPointer));
- EXPECT_CALL(*job_factory_.alternative_job(), MarkOtherJobComplete(_))
- .Times(1);
job_controller_->OnStreamReady(job_factory_.main_job(), SSLConfig(),
ProxyInfo());
@@ -209,13 +367,24 @@ TEST_P(HttpStreamFactoryImplJobControllerTest,
job_controller_->OnStreamFailed(job_factory_.alternative_job(), ERR_FAILED,
SSLConfig());
+ VerifyBrokenAlternateProtocolMapping(request_info, true);
// Reset the request as it's been successfully served.
request_.reset();
EXPECT_TRUE(HttpStreamFactoryImplPeer::IsJobControllerDeleted(factory_));
}
-TEST_P(HttpStreamFactoryImplJobControllerTest,
- SecondJobSucceedsAfterFirstJobFailed) {
+TEST_F(HttpStreamFactoryImplJobControllerTest,
+ AltJobSucceedsAfterMainJobFailed) {
+ ProxyConfig proxy_config;
+ proxy_config.set_auto_detect(true);
+ // Use asynchronous proxy resolver.
+ MockAsyncProxyResolverFactory* proxy_resolver_factory =
+ new MockAsyncProxyResolverFactory(false);
+ session_deps_.proxy_service.reset(
+ new ProxyService(base::MakeUnique<ProxyConfigServiceFixed>(proxy_config),
+ base::WrapUnique(proxy_resolver_factory), nullptr));
+ Initialize(false);
+
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("https://www.google.com");
@@ -226,34 +395,88 @@ TEST_P(HttpStreamFactoryImplJobControllerTest,
request_.reset(
job_controller_->Start(request_info, &request_delegate_, nullptr,
- BoundNetLog(), HttpStreamRequest::HTTP_STREAM,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
EXPECT_TRUE(job_controller_->main_job());
EXPECT_TRUE(job_controller_->alternative_job());
// |main_job| fails but should not report status to Request.
- // The alternative job will mark the main job complete.
EXPECT_CALL(request_delegate_, OnStreamFailed(_, _)).Times(0);
- EXPECT_CALL(*job_factory_.alternative_job(), MarkOtherJobComplete(_))
- .Times(1);
job_controller_->OnStreamFailed(job_factory_.main_job(), ERR_FAILED,
SSLConfig());
// |alternative_job| succeeds and should report status to Request.
HttpStream* http_stream =
- new HttpBasicStream(new ClientSocketHandle(), false);
+ new HttpBasicStream(base::MakeUnique<ClientSocketHandle>(), false, false);
job_factory_.alternative_job()->SetStream(http_stream);
EXPECT_CALL(request_delegate_, OnStreamReady(_, _, http_stream))
.WillOnce(Invoke(DeleteHttpStreamPointer));
job_controller_->OnStreamReady(job_factory_.alternative_job(), SSLConfig(),
ProxyInfo());
+ VerifyBrokenAlternateProtocolMapping(request_info, false);
+}
+
+TEST_F(HttpStreamFactoryImplJobControllerTest,
+ MainJobSucceedsAfterAltJobFailed) {
+ ProxyConfig proxy_config;
+ proxy_config.set_auto_detect(true);
+ // Use asynchronous proxy resolver.
+ MockAsyncProxyResolverFactory* proxy_resolver_factory =
+ new MockAsyncProxyResolverFactory(false);
+ session_deps_.proxy_service.reset(
+ new ProxyService(base::MakeUnique<ProxyConfigServiceFixed>(proxy_config),
+ base::WrapUnique(proxy_resolver_factory), nullptr));
+ Initialize(false);
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.google.com");
+
+ url::SchemeHostPort server(request_info.url);
+ AlternativeService alternative_service(QUIC, server.host(), 443);
+ SetAlternativeService(request_info, alternative_service);
+
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+ EXPECT_TRUE(job_controller_->main_job());
+ EXPECT_TRUE(job_controller_->alternative_job());
+
+ // |alternative_job| fails but should not report status to Request.
+ EXPECT_CALL(request_delegate_, OnStreamFailed(_, _)).Times(0);
+
+ job_controller_->OnStreamFailed(job_factory_.alternative_job(), ERR_FAILED,
+ SSLConfig());
+
+ // |main_job| succeeds and should report status to Request.
+ HttpStream* http_stream =
+ new HttpBasicStream(base::MakeUnique<ClientSocketHandle>(), false, false);
+ job_factory_.main_job()->SetStream(http_stream);
+
+ EXPECT_CALL(request_delegate_, OnStreamReady(_, _, http_stream))
+ .WillOnce(Invoke(DeleteHttpStreamPointer));
+ job_controller_->OnStreamReady(job_factory_.main_job(), SSLConfig(),
+ ProxyInfo());
+
+ VerifyBrokenAlternateProtocolMapping(request_info, true);
}
// Regression test for crbug/621069.
// Get load state after main job fails and before alternative job succeeds.
-TEST_P(HttpStreamFactoryImplJobControllerTest, GetLoadStateAfterMainJobFailed) {
+TEST_F(HttpStreamFactoryImplJobControllerTest, GetLoadStateAfterMainJobFailed) {
+ ProxyConfig proxy_config;
+ proxy_config.set_auto_detect(true);
+ // Use asynchronous proxy resolver.
+ MockAsyncProxyResolverFactory* proxy_resolver_factory =
+ new MockAsyncProxyResolverFactory(false);
+ session_deps_.proxy_service.reset(new ProxyService(
+ base::WrapUnique(new ProxyConfigServiceFixed(proxy_config)),
+ base::WrapUnique(proxy_resolver_factory), nullptr));
+ Initialize(false);
+
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("https://www.google.com");
@@ -264,7 +487,7 @@ TEST_P(HttpStreamFactoryImplJobControllerTest, GetLoadStateAfterMainJobFailed) {
request_.reset(
job_controller_->Start(request_info, &request_delegate_, nullptr,
- BoundNetLog(), HttpStreamRequest::HTTP_STREAM,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
EXPECT_TRUE(job_controller_->main_job());
EXPECT_TRUE(job_controller_->alternative_job());
@@ -272,8 +495,6 @@ TEST_P(HttpStreamFactoryImplJobControllerTest, GetLoadStateAfterMainJobFailed) {
// |main_job| fails but should not report status to Request.
// The alternative job will mark the main job complete.
EXPECT_CALL(request_delegate_, OnStreamFailed(_, _)).Times(0);
- EXPECT_CALL(*job_factory_.alternative_job(), MarkOtherJobComplete(_))
- .Times(1);
job_controller_->OnStreamFailed(job_factory_.main_job(), ERR_FAILED,
SSLConfig());
@@ -283,7 +504,7 @@ TEST_P(HttpStreamFactoryImplJobControllerTest, GetLoadStateAfterMainJobFailed) {
// |alternative_job| succeeds and should report status to Request.
HttpStream* http_stream =
- new HttpBasicStream(new ClientSocketHandle(), false);
+ new HttpBasicStream(base::MakeUnique<ClientSocketHandle>(), false, false);
job_factory_.alternative_job()->SetStream(http_stream);
EXPECT_CALL(request_delegate_, OnStreamReady(_, _, http_stream))
@@ -292,4 +513,444 @@ TEST_P(HttpStreamFactoryImplJobControllerTest, GetLoadStateAfterMainJobFailed) {
ProxyInfo());
}
+TEST_F(HttpStreamFactoryImplJobControllerTest, DoNotResumeMainJobBeforeWait) {
+ // Use failing ProxyResolverFactory which is unable to create ProxyResolver
+ // to stall the alternative job and report to controller to maybe resume the
+ // main job.
+ ProxyConfig proxy_config;
+ proxy_config.set_auto_detect(true);
+ proxy_config.set_pac_mandatory(true);
+ session_deps_.proxy_service.reset(new ProxyService(
+ base::MakeUnique<ProxyConfigServiceFixed>(proxy_config),
+ base::WrapUnique(new FailingProxyResolverFactory), nullptr));
+
+ Initialize(false);
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.google.com");
+
+ url::SchemeHostPort server(request_info.url);
+ AlternativeService alternative_service(QUIC, server.host(), 443);
+ SetAlternativeService(request_info, alternative_service);
+
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+ EXPECT_TRUE(job_controller_->main_job());
+ EXPECT_TRUE(job_controller_->alternative_job());
+
+ // Wait until OnStreamFailedCallback is executed on the alternative job.
+ EXPECT_CALL(request_delegate_, OnStreamFailed(_, _)).Times(1);
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(HttpStreamFactoryImplJobControllerTest, InvalidPortForQuic) {
+ // Using a restricted port 101 for QUIC should fail and the alternative job
+ // should post OnStreamFailedCall on the controller to resume the main job.
+ Initialize(false);
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.google.com");
+
+ url::SchemeHostPort server(request_info.url);
+ AlternativeService alternative_service(QUIC, server.host(), 101);
+ SetAlternativeService(request_info, alternative_service);
+
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+
+ EXPECT_TRUE(job_factory_.main_job()->is_waiting());
+
+ // Wait until OnStreamFailedCallback is executed on the alternative job.
+ EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(1);
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(HttpStreamFactoryImplJobControllerTest,
+ NoAvailableSpdySessionToResumeMainJob) {
+ // Test the alternative job is not resumed when the alternative job is
+ // IO_PENDING for proxy resolution. Once all the proxy resolution succeeds,
+ // the latter part of this test tests controller resumes the main job
+ // when there's no SPDY session for the alternative job.
+ ProxyConfig proxy_config;
+ proxy_config.set_auto_detect(true);
+ // Use asynchronous proxy resolver.
+ MockAsyncProxyResolverFactory* proxy_resolver_factory =
+ new MockAsyncProxyResolverFactory(false);
+ session_deps_.proxy_service.reset(
+ new ProxyService(base::MakeUnique<ProxyConfigServiceFixed>(proxy_config),
+ base::WrapUnique(proxy_resolver_factory), nullptr));
+
+ HangingResolver* host_resolver = new HangingResolver();
+ session_deps_.host_resolver.reset(host_resolver);
+ session_deps_.host_resolver->set_synchronous_mode(false);
+
+ Initialize(false);
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.google.com");
+
+ // Set a SPDY alternative service for the server.
+ url::SchemeHostPort server(request_info.url);
+ AlternativeService alternative_service(QUIC, server.host(), 443);
+ SetAlternativeService(request_info, alternative_service);
+ // Hack to use different URL for the main job to help differentiate the proxy
+ // requests.
+ job_factory_.UseDifferentURLForMainJob(GURL("http://www.google.com"));
+
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+ // Both jobs should be created but stalled as proxy resolution not completed.
+ EXPECT_TRUE(job_controller_->main_job());
+ EXPECT_TRUE(job_controller_->alternative_job());
+
+ MockAsyncProxyResolver resolver;
+ proxy_resolver_factory->pending_requests()[0]->CompleteNowWithForwarder(
+ net::OK, &resolver);
+
+ // Resolve proxy for the main job which then proceed to wait for the
+ // alternative job which is IO_PENDING.
+ int main_job_request_id =
+ resolver.pending_requests()[0]->url().SchemeIs("http") ? 0 : 1;
+
+ resolver.pending_requests()[main_job_request_id]->results()->UseNamedProxy(
+ "result1:80");
+ resolver.pending_requests()[main_job_request_id]->CompleteNow(net::OK);
+ EXPECT_TRUE(job_controller_->main_job()->is_waiting());
+
+ // Resolve proxy for the alternative job to proceed to create a connection.
+ // Use hanging HostResolver to fail creation of a SPDY session for the
+ // alternative job. The alternative job will be IO_PENDING thus should resume
+ // the main job.
+ resolver.pending_requests()[0]->CompleteNow(net::OK);
+ EXPECT_CALL(request_delegate_, OnStreamFailed(_, _)).Times(0);
+ EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(1);
+
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(HttpStreamFactoryImplJobControllerTest,
+ NoAvailableQuicSessionToResumeMainJob) {
+ // Use failing HostResolver which is unable to resolve the host name for QUIC.
+ // No QUIC session is created and thus should resume the main job.
+ FailingHostResolver* host_resolver = new FailingHostResolver();
+ session_deps_.host_resolver.reset(host_resolver);
+
+ ProxyConfig proxy_config;
+ proxy_config.set_auto_detect(true);
+ // Use asynchronous proxy resolver.
+ MockAsyncProxyResolverFactory* proxy_resolver_factory =
+ new MockAsyncProxyResolverFactory(false);
+ session_deps_.proxy_service.reset(
+ new ProxyService(base::MakeUnique<ProxyConfigServiceFixed>(proxy_config),
+ base::WrapUnique(proxy_resolver_factory), nullptr));
+
+ Initialize(false);
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.google.com");
+
+ url::SchemeHostPort server(request_info.url);
+ AlternativeService alternative_service(QUIC, server.host(), 443);
+ SetAlternativeService(request_info, alternative_service);
+ // Hack to use different URL for the main job to help differentiate the proxy
+ // requests.
+ job_factory_.UseDifferentURLForMainJob(GURL("http://www.google.com"));
+
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+ EXPECT_TRUE(job_controller_->main_job());
+ EXPECT_TRUE(job_controller_->alternative_job());
+
+ MockAsyncProxyResolver resolver;
+ proxy_resolver_factory->pending_requests()[0]->CompleteNowWithForwarder(
+ net::OK, &resolver);
+
+ // Resolve proxy for the main job which then proceed to wait for the
+ // alternative job which is IO_PENDING.
+ int main_job_request_id =
+ resolver.pending_requests()[0]->url().SchemeIs("http") ? 0 : 1;
+
+ resolver.pending_requests()[main_job_request_id]->results()->UseNamedProxy(
+ "result1:80");
+ resolver.pending_requests()[main_job_request_id]->CompleteNow(net::OK);
+ EXPECT_TRUE(job_controller_->main_job()->is_waiting());
+
+ // Resolve proxy for the alternative job to proceed to create a connection.
+ // Use failing HostResolver to fail creation of a QUIC session for the
+ // alternative job. The alternative job will thus resume the main job.
+ resolver.pending_requests()[0]->results()->UseNamedProxy("result1:80");
+ resolver.pending_requests()[0]->CompleteNow(net::OK);
+
+ // Wait until OnStreamFailedCallback is executed on the alternative job.
+ // Request shouldn't be notified as the main job is still pending status.
+ EXPECT_CALL(request_delegate_, OnStreamFailed(_, _)).Times(0);
+ EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(1);
+
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(HttpStreamFactoryImplJobControllerTest, DelayedTCP) {
+ HangingResolver* resolver = new HangingResolver();
+ session_deps_.host_resolver.reset(resolver);
+
+ Initialize(false);
+
+ // Enable delayed TCP and set time delay for waiting job.
+ QuicStreamFactory* quic_stream_factory = session_->quic_stream_factory();
+ test::QuicStreamFactoryPeer::SetDelayTcpRace(quic_stream_factory, true);
+ 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);
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.google.com");
+
+ // Set a SPDY alternative service for the server.
+ url::SchemeHostPort server(request_info.url);
+ AlternativeService alternative_service(QUIC, server.host(), 443);
+ SetAlternativeService(request_info, alternative_service);
+
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+ EXPECT_TRUE(job_controller_->main_job());
+ EXPECT_TRUE(job_controller_->alternative_job());
+
+ // The alternative job stalls as host resolution hangs when creating the QUIC
+ // request and controller should resume the main job after delay.
+ // Verify the waiting time for delayed main job.
+ EXPECT_CALL(*job_factory_.main_job(), Resume())
+ .WillOnce(Invoke(testing::CreateFunctor(
+ &JobControllerPeer::VerifyWaitingTimeForMainJob, job_controller_,
+ base::TimeDelta::FromMicroseconds(15))));
+
+ base::RunLoop().RunUntilIdle();
+}
+
+// Verifies that the alternative proxy server job is not created if the URL
+// scheme is HTTPS.
+TEST_F(HttpStreamFactoryImplJobControllerTest, HttpsURL) {
+ // Using hanging resolver will cause the alternative job to hang indefinitely.
+ HangingResolver* resolver = new HangingResolver();
+ session_deps_.host_resolver.reset(resolver);
+
+ Initialize(true);
+ EXPECT_TRUE(test_proxy_delegate()->alternative_proxy_server().is_quic());
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://mail.example.org/");
+
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+ EXPECT_TRUE(job_controller_->main_job());
+ EXPECT_FALSE(job_controller_->main_job()->is_waiting());
+ EXPECT_FALSE(job_controller_->alternative_job());
+
+ 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
+// does not fetch the resource through a proxy.
+TEST_F(HttpStreamFactoryImplJobControllerTest, HttpURLWithNoProxy) {
+ // Using hanging resolver will cause the alternative job to hang indefinitely.
+ HangingResolver* resolver = new HangingResolver();
+ session_deps_.host_resolver.reset(resolver);
+
+ Initialize(false);
+ EXPECT_TRUE(test_proxy_delegate()->alternative_proxy_server().is_quic());
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("http://mail.example.org/");
+
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+ EXPECT_TRUE(job_controller_->main_job());
+ EXPECT_FALSE(job_controller_->main_job()->is_waiting());
+ EXPECT_FALSE(job_controller_->alternative_job());
+
+ 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) {
+ // Using hanging resolver will cause the alternative job to hang indefinitely.
+ HangingResolver* resolver = new HangingResolver();
+ session_deps_.host_resolver.reset(resolver);
+
+ Initialize(true);
+ EXPECT_TRUE(test_proxy_delegate()->alternative_proxy_server().is_quic());
+
+ // Enable delayed TCP and set time delay for waiting job.
+ QuicStreamFactory* quic_stream_factory = session_->quic_stream_factory();
+ test::QuicStreamFactoryPeer::SetDelayTcpRace(quic_stream_factory, true);
+ quic_stream_factory->set_require_confirmation(false);
+ ServerNetworkStats stats1;
+ stats1.srtt = base::TimeDelta::FromMicroseconds(10);
+ session_->http_server_properties()->SetServerNetworkStats(
+ url::SchemeHostPort(GURL("https://myproxy.org")), stats1);
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("http://mail.example.org/");
+
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+ EXPECT_TRUE(job_controller_->main_job());
+ EXPECT_TRUE(job_controller_->main_job()->is_waiting());
+ EXPECT_TRUE(job_controller_->alternative_job());
+ EXPECT_TRUE(JobControllerPeer::main_job_is_blocked(job_controller_));
+
+ // The alternative proxy server job stalls when connecting to the alternative
+ // proxy server, and controller should resume the main job after delay.
+ // Verify the waiting time for delayed main job.
+ EXPECT_CALL(*job_factory_.main_job(), Resume())
+ .WillOnce(Invoke(testing::CreateFunctor(
+ &JobControllerPeer::VerifyWaitingTimeForMainJob, job_controller_,
+ base::TimeDelta::FromMicroseconds(15))));
+
+ // This message loop should cause the alternative proxy server job to start,
+ // and schedule resumption of the main job.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(JobControllerPeer::main_job_is_blocked(job_controller_));
+
+ // Wait for the Resume to post.
+ base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
+
+ // This message loop should cause the main job to resume.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(JobControllerPeer::main_job_is_blocked(job_controller_));
+
+ JobControllerPeer::VerifyWaitingTimeForMainJob(
+ job_controller_, base::TimeDelta::FromMicroseconds(0));
+
+ // Since the main job did not complete successfully, 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());
+}
+
+// Verifies that the alternative proxy server job fails immediately, and the
+// main job is not blocked.
+TEST_F(HttpStreamFactoryImplJobControllerTest, FailAlternativeProxy) {
+ // Using failing resolver will cause the alternative job to fail.
+ FailingHostResolver* resolver = new FailingHostResolver();
+ session_deps_.host_resolver.reset(resolver);
+
+ Initialize(true);
+ EXPECT_TRUE(test_proxy_delegate()->alternative_proxy_server().is_quic());
+
+ // Enable delayed TCP and set time delay for waiting job.
+ QuicStreamFactory* quic_stream_factory = session_->quic_stream_factory();
+ test::QuicStreamFactoryPeer::SetDelayTcpRace(quic_stream_factory, true);
+ quic_stream_factory->set_require_confirmation(false);
+ ServerNetworkStats stats1;
+ stats1.srtt = base::TimeDelta::FromMicroseconds(300 * 1000);
+ session_->http_server_properties()->SetServerNetworkStats(
+ url::SchemeHostPort(GURL("https://myproxy.org")), stats1);
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("http://mail.example.org/");
+
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+ EXPECT_TRUE(job_controller_->main_job()->is_waiting());
+ EXPECT_TRUE(job_controller_->alternative_job());
+
+ EXPECT_CALL(request_delegate_, OnStreamReady(_, _, _)).Times(0);
+
+ // Since the alternative proxy server job is started in the next message loop,
+ // the main job would remain blocked until the alternative proxy starts, and
+ // fails.
+ EXPECT_CALL(*job_factory_.main_job(), Resume())
+ .WillOnce(Invoke(testing::CreateFunctor(
+ &JobControllerPeer::VerifyWaitingTimeForMainJob, job_controller_,
+ base::TimeDelta::FromMicroseconds(0))));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(job_controller_->alternative_job());
+ EXPECT_TRUE(job_controller_->main_job()->is_waiting());
+ // Since the main job did not complete successfully, 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());
+}
+
+TEST_F(HttpStreamFactoryImplJobControllerTest,
+ AlternativeProxyServerJobFailsAfterMainJobSucceeds) {
+ base::HistogramTester histogram_tester;
+ Initialize(true);
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("http://www.google.com");
+
+ url::SchemeHostPort server(request_info.url);
+
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+ EXPECT_TRUE(job_controller_->main_job());
+ EXPECT_TRUE(job_controller_->alternative_job());
+
+ // Main job succeeds, starts serving Request and it should report status
+ // to Request. The alternative job will mark the main job complete and gets
+ // orphaned.
+ HttpStream* http_stream =
+ new HttpBasicStream(base::MakeUnique<ClientSocketHandle>(), false, false);
+ job_factory_.main_job()->SetStream(http_stream);
+
+ EXPECT_CALL(request_delegate_, OnStreamReady(_, _, http_stream))
+ .WillOnce(Invoke(DeleteHttpStreamPointer));
+ job_controller_->OnStreamReady(job_factory_.main_job(), SSLConfig(),
+ ProxyInfo());
+
+ // JobController shouldn't report the status of alternative server job as
+ // request is already successfully served.
+ EXPECT_CALL(request_delegate_, OnStreamFailed(_, _)).Times(0);
+ job_controller_->OnStreamFailed(job_factory_.alternative_job(), ERR_FAILED,
+ SSLConfig());
+
+ // Reset the request as it's been successfully served.
+ request_.reset();
+ EXPECT_TRUE(HttpStreamFactoryImplPeer::IsJobControllerDeleted(factory_));
+
+ histogram_tester.ExpectUniqueSample("Net.QuicAlternativeProxy.Usage",
+ 2 /* ALTERNATIVE_PROXY_USAGE_LOST_RACE */,
+ 1);
+}
+
} // namespace net
diff --git a/chromium/net/http/http_stream_factory_impl_request.cc b/chromium/net/http/http_stream_factory_impl_request.cc
index 09962039c6d..e6bcbe42c68 100644
--- a/chromium/net/http/http_stream_factory_impl_request.cc
+++ b/chromium/net/http/http_stream_factory_impl_request.cc
@@ -9,6 +9,7 @@
#include "base/stl_util.h"
#include "net/http/bidirectional_stream_impl.h"
#include "net/http/http_stream_factory_impl_job.h"
+#include "net/log/net_log_event_type.h"
#include "net/spdy/spdy_http_stream.h"
#include "net/spdy/spdy_session.h"
@@ -20,7 +21,7 @@ HttpStreamFactoryImpl::Request::Request(
HttpStreamRequest::Delegate* delegate,
WebSocketHandshakeStreamBase::CreateHelper*
websocket_handshake_stream_create_helper,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
StreamType stream_type)
: url_(url),
helper_(helper),
@@ -29,17 +30,17 @@ HttpStreamFactoryImpl::Request::Request(
delegate_(delegate),
net_log_(net_log),
completed_(false),
- was_npn_negotiated_(false),
- protocol_negotiated_(kProtoUnknown),
+ was_alpn_negotiated_(false),
+ negotiated_protocol_(kProtoUnknown),
using_spdy_(false),
stream_type_(stream_type) {
DCHECK(delegate_);
- net_log_.BeginEvent(NetLog::TYPE_HTTP_STREAM_REQUEST);
+ net_log_.BeginEvent(NetLogEventType::HTTP_STREAM_REQUEST);
}
HttpStreamFactoryImpl::Request::~Request() {
- net_log_.EndEvent(NetLog::TYPE_HTTP_STREAM_REQUEST);
+ net_log_.EndEvent(NetLogEventType::HTTP_STREAM_REQUEST);
helper_->OnRequestComplete();
}
@@ -48,13 +49,13 @@ void HttpStreamFactoryImpl::Request::SetSpdySessionKey(
spdy_session_key_.reset(new SpdySessionKey(spdy_session_key));
}
-void HttpStreamFactoryImpl::Request::Complete(bool was_npn_negotiated,
- NextProto protocol_negotiated,
+void HttpStreamFactoryImpl::Request::Complete(bool was_alpn_negotiated,
+ NextProto negotiated_protocol,
bool using_spdy) {
DCHECK(!completed_);
completed_ = true;
- was_npn_negotiated_ = was_npn_negotiated;
- protocol_negotiated_ = protocol_negotiated;
+ was_alpn_negotiated_ = was_alpn_negotiated;
+ negotiated_protocol_ = negotiated_protocol;
using_spdy_ = using_spdy;
}
@@ -134,15 +135,14 @@ LoadState HttpStreamFactoryImpl::Request::GetLoadState() const {
return helper_->GetLoadState();
}
-bool HttpStreamFactoryImpl::Request::was_npn_negotiated() const {
+bool HttpStreamFactoryImpl::Request::was_alpn_negotiated() const {
DCHECK(completed_);
- return was_npn_negotiated_;
+ return was_alpn_negotiated_;
}
-NextProto HttpStreamFactoryImpl::Request::protocol_negotiated()
- const {
+NextProto HttpStreamFactoryImpl::Request::negotiated_protocol() const {
DCHECK(completed_);
- return protocol_negotiated_;
+ return negotiated_protocol_;
}
bool HttpStreamFactoryImpl::Request::using_spdy() const {
diff --git a/chromium/net/http/http_stream_factory_impl_request.h b/chromium/net/http/http_stream_factory_impl_request.h
index 5eab8d82bd2..16f1e719036 100644
--- a/chromium/net/http/http_stream_factory_impl_request.h
+++ b/chromium/net/http/http_stream_factory_impl_request.h
@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "net/base/net_export.h"
#include "net/http/http_stream_factory_impl.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/connection_attempts.h"
#include "net/socket/ssl_client_socket.h"
#include "net/spdy/spdy_session_key.h"
@@ -52,7 +52,7 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest {
HttpStreamRequest::Delegate* delegate,
WebSocketHandshakeStreamBase::CreateHelper*
websocket_handshake_stream_create_helper,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
StreamType stream_type);
~Request() override;
@@ -60,7 +60,7 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest {
// The GURL from the HttpRequestInfo the started the Request.
const GURL& url() const { return url_; }
- const BoundNetLog& net_log() const { return net_log_; }
+ const NetLogWithSource& net_log() const { return net_log_; }
// Called when the |helper_| determines the appropriate |spdy_session_key|
// for the Request. Note that this does not mean that SPDY is necessarily
@@ -70,8 +70,8 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest {
bool HasSpdySessionKey() const;
// Marks completion of the request. Must be called before OnStreamReady().
- void Complete(bool was_npn_negotiated,
- NextProto protocol_negotiated,
+ void Complete(bool was_alpn_negotiated,
+ NextProto negotiated_protocol,
bool using_spdy);
void ResetSpdySessionKey();
@@ -119,8 +119,8 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest {
int RestartTunnelWithProxyAuth(const AuthCredentials& credentials) override;
void SetPriority(RequestPriority priority) override;
LoadState GetLoadState() const override;
- bool was_npn_negotiated() const override;
- NextProto protocol_negotiated() const override;
+ bool was_alpn_negotiated() const override;
+ NextProto negotiated_protocol() const override;
bool using_spdy() const override;
const ConnectionAttempts& connection_attempts() const override;
HttpStreamRequest::StreamType stream_type() const { return stream_type_; }
@@ -137,14 +137,14 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest {
WebSocketHandshakeStreamBase::CreateHelper* const
websocket_handshake_stream_create_helper_;
HttpStreamRequest::Delegate* const delegate_;
- const BoundNetLog net_log_;
+ const NetLogWithSource net_log_;
std::unique_ptr<const SpdySessionKey> spdy_session_key_;
bool completed_;
- bool was_npn_negotiated_;
+ bool was_alpn_negotiated_;
// Protocol negotiated with the server.
- NextProto protocol_negotiated_;
+ NextProto negotiated_protocol_;
bool using_spdy_;
ConnectionAttempts connection_attempts_;
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 1954d3b7daf..6de0bab70b2 100644
--- a/chromium/net/http/http_stream_factory_impl_request_unittest.cc
+++ b/chromium/net/http/http_stream_factory_impl_request_unittest.cc
@@ -20,19 +20,11 @@ using testing::_;
namespace net {
-class HttpStreamFactoryImplRequestTest
- : public ::testing::Test,
- public ::testing::WithParamInterface<NextProto> {};
-
-INSTANTIATE_TEST_CASE_P(NextProto,
- HttpStreamFactoryImplRequestTest,
- testing::Values(kProtoSPDY31,
- kProtoHTTP2));
+class HttpStreamFactoryImplRequestTest : public ::testing::Test {};
// Make sure that Request passes on its priority updates to its jobs.
-TEST_P(HttpStreamFactoryImplRequestTest, SetPriority) {
- SpdySessionDependencies session_deps(GetParam(),
- ProxyService::CreateDirect());
+TEST_F(HttpStreamFactoryImplRequestTest, SetPriority) {
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
std::unique_ptr<HttpNetworkSession> session =
SpdySessionDependencies::SpdyCreateSession(&session_deps);
HttpStreamFactoryImpl* factory =
@@ -47,7 +39,7 @@ TEST_P(HttpStreamFactoryImplRequestTest, SetPriority) {
HttpRequestInfo request_info;
std::unique_ptr<HttpStreamFactoryImpl::Request> request(
job_controller->Start(request_info, &request_delegate, nullptr,
- BoundNetLog(), HttpStreamRequest::HTTP_STREAM,
+ NetLogWithSource(), HttpStreamRequest::HTTP_STREAM,
DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
EXPECT_TRUE(job_controller->main_job());
EXPECT_EQ(DEFAULT_PRIORITY, job_controller->main_job()->priority());
@@ -62,79 +54,4 @@ TEST_P(HttpStreamFactoryImplRequestTest, SetPriority) {
request->SetPriority(IDLE);
EXPECT_EQ(IDLE, job_controller->main_job()->priority());
}
-
-TEST_P(HttpStreamFactoryImplRequestTest, DelayMainJob) {
- SpdySessionDependencies session_deps(GetParam(),
- ProxyService::CreateDirect());
-
- std::unique_ptr<HttpNetworkSession> session =
- SpdySessionDependencies::SpdyCreateSession(&session_deps);
-
- StaticSocketDataProvider socket_data;
- socket_data.set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
- session_deps.socket_factory->AddSocketDataProvider(&socket_data);
-
- HttpStreamFactoryImpl* factory =
- static_cast<HttpStreamFactoryImpl*>(session->http_stream_factory());
- MockHttpStreamRequestDelegate request_delegate;
- HttpStreamFactoryImpl::JobFactory* job_factory =
- HttpStreamFactoryImplPeer::GetDefaultJobFactory(factory);
- HttpStreamFactoryImpl::JobController* job_controller =
- new HttpStreamFactoryImpl::JobController(factory, &request_delegate,
- session.get(), job_factory);
- factory->job_controller_set_.insert(base::WrapUnique(job_controller));
-
- HttpRequestInfo request_info;
- request_info.method = "GET";
- request_info.url = GURL("https://www.google.com");
-
- HttpStreamFactoryImpl::Request request(
- request_info.url, job_controller, &request_delegate, nullptr,
- BoundNetLog(), HttpStreamFactoryImpl::Request::HTTP_STREAM);
- job_controller->request_ = &request;
-
- HostPortPair server = HostPortPair::FromURL(request_info.url);
- GURL original_url =
- job_controller->ApplyHostMappingRules(request_info.url, &server);
-
- HttpStreamFactoryImpl::Job* job = new HttpStreamFactoryImpl::Job(
- job_controller, HttpStreamFactoryImpl::MAIN, session.get(), request_info,
- DEFAULT_PRIORITY, SSLConfig(), SSLConfig(), server, original_url,
- nullptr);
- job_controller->main_job_.reset(job);
- job_controller->AttachJob(job);
- EXPECT_EQ(DEFAULT_PRIORITY, job->priority());
-
- AlternativeService alternative_service(net::NPN_HTTP_2, server);
- HttpStreamFactoryImpl::Job* alternative_job = new HttpStreamFactoryImpl::Job(
- job_controller, HttpStreamFactoryImpl::ALTERNATIVE, session.get(),
- request_info, DEFAULT_PRIORITY, SSLConfig(), SSLConfig(), server,
- original_url, alternative_service, nullptr);
- job_controller->alternative_job_.reset(alternative_job);
- job_controller->AttachJob(alternative_job);
-
- job->WaitFor(alternative_job);
- EXPECT_EQ(HttpStreamFactoryImpl::Job::STATE_NONE, job->next_state_);
-
- // Test |alternative_job| resuming the |job| after delay.
- int wait_time = 1;
- base::TimeDelta delay = base::TimeDelta::FromMilliseconds(wait_time);
- job->Resume(alternative_job, delay);
-
- // Verify |job| has |wait_time_| and there is no |blocking_job_|
- EXPECT_EQ(delay, job->wait_time_);
- EXPECT_TRUE(!job->blocking_job_);
-
- // Start the |job| and verify |job|'s |wait_time_| is cleared.
- job->Start(request.stream_type());
-
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(wait_time + 1));
- base::RunLoop().RunUntilIdle();
-
- EXPECT_NE(delay, job->wait_time_);
- EXPECT_TRUE(job->wait_time_.is_zero());
- EXPECT_EQ(HttpStreamFactoryImpl::Job::STATE_INIT_CONNECTION_COMPLETE,
- job->next_state_);
-}
-
} // namespace net
diff --git a/chromium/net/http/http_stream_factory_impl_unittest.cc b/chromium/net/http/http_stream_factory_impl_unittest.cc
index c33c9747b90..b9d6edb027a 100644
--- a/chromium/net/http/http_stream_factory_impl_unittest.cc
+++ b/chromium/net/http/http_stream_factory_impl_unittest.cc
@@ -11,9 +11,11 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "net/base/port_util.h"
#include "net/base/test_completion_callback.h"
+#include "net/base/test_proxy_delegate.h"
#include "net/cert/ct_policy_enforcer.h"
#include "net/cert/mock_cert_verifier.h"
#include "net/cert/multi_log_ct_verifier.h"
@@ -29,11 +31,11 @@
#include "net/http/http_server_properties_impl.h"
#include "net/http/http_stream.h"
#include "net/http/transport_security_state.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_service.h"
-#include "net/quic/quic_http_utils.h"
-#include "net/quic/quic_server_id.h"
+#include "net/quic/core/quic_http_utils.h"
+#include "net/quic/core/quic_server_id.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
#include "net/quic/test_tools/mock_random.h"
@@ -50,14 +52,25 @@
#include "net/ssl/ssl_config_service.h"
#include "net/ssl/ssl_config_service_defaults.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
// This file can be included from net/http even though
// it is in net/websockets because it doesn't
// introduce any link dependency to net/websockets.
#include "net/websockets/websocket_handshake_stream_base.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
+namespace base {
+class Value;
+class DictionaryValue;
+} // namespace base
+
namespace net {
class BidirectionalStreamImpl;
@@ -82,7 +95,7 @@ class MockWebSocketHandshakeStream : public WebSocketHandshakeStreamBase {
// HttpStream methods
int InitializeStream(const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback) override {
return ERR_IO_PENDING;
}
@@ -112,15 +125,15 @@ class MockWebSocketHandshakeStream : public WebSocketHandshakeStreamBase {
void GetSSLInfo(SSLInfo* ssl_info) override {}
void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override {}
bool GetRemoteEndpoint(IPEndPoint* endpoint) override { return false; }
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) override {
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) override {
ADD_FAILURE();
return ERR_NOT_IMPLEMENTED;
}
void Drain(HttpNetworkSession* session) override {}
void PopulateNetErrorDetails(NetErrorDetails* details) override { return; }
void SetPriority(RequestPriority priority) override {}
- UploadProgress GetUploadProgress() const override { return UploadProgress(); }
HttpStream* RenewStreamForAuth() override { return nullptr; }
std::unique_ptr<WebSocketStream> Upgrade() override {
@@ -377,7 +390,7 @@ class CapturePreconnectsSocketPool : public ParentPool {
ClientSocketPool::RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
ADD_FAILURE();
return ERR_UNEXPECTED;
}
@@ -385,7 +398,7 @@ class CapturePreconnectsSocketPool : public ParentPool {
void RequestSockets(const std::string& group_name,
const void* socket_params,
int num_sockets,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
last_num_streams_ = num_sockets;
}
@@ -476,15 +489,9 @@ class HttpStreamFactoryTest : public ::testing::Test,
public ::testing::WithParamInterface<NextProto> {
};
-INSTANTIATE_TEST_CASE_P(NextProto,
- HttpStreamFactoryTest,
- testing::Values(kProtoSPDY31,
- kProtoHTTP2));
-
-TEST_P(HttpStreamFactoryTest, PreconnectDirect) {
+TEST_F(HttpStreamFactoryTest, PreconnectDirect) {
for (size_t i = 0; i < arraysize(kTests); ++i) {
- SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateDirect());
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
std::unique_ptr<HttpNetworkSession> session(
SpdySessionDependencies::SpdyCreateSession(&session_deps));
HttpNetworkSessionPeer peer(session.get());
@@ -513,10 +520,10 @@ TEST_P(HttpStreamFactoryTest, PreconnectDirect) {
}
}
-TEST_P(HttpStreamFactoryTest, PreconnectHttpProxy) {
+TEST_F(HttpStreamFactoryTest, PreconnectHttpProxy) {
for (size_t i = 0; i < arraysize(kTests); ++i) {
SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateFixed("http_proxy"));
+ ProxyService::CreateFixed("http_proxy"));
std::unique_ptr<HttpNetworkSession> session(
SpdySessionDependencies::SpdyCreateSession(&session_deps));
HttpNetworkSessionPeer peer(session.get());
@@ -535,8 +542,10 @@ TEST_P(HttpStreamFactoryTest, PreconnectHttpProxy) {
session_deps.ct_policy_enforcer.get());
std::unique_ptr<MockClientSocketPoolManager> mock_pool_manager(
new MockClientSocketPoolManager);
- mock_pool_manager->SetSocketPoolForHTTPProxy(proxy_host, http_proxy_pool);
- mock_pool_manager->SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool);
+ mock_pool_manager->SetSocketPoolForHTTPProxy(
+ proxy_host, base::WrapUnique(http_proxy_pool));
+ mock_pool_manager->SetSocketPoolForSSLWithProxy(
+ proxy_host, base::WrapUnique(ssl_conn_pool));
peer.SetClientSocketPoolManager(std::move(mock_pool_manager));
PreconnectHelper(kTests[i], session.get());
if (kTests[i].ssl)
@@ -546,10 +555,10 @@ TEST_P(HttpStreamFactoryTest, PreconnectHttpProxy) {
}
}
-TEST_P(HttpStreamFactoryTest, PreconnectSocksProxy) {
+TEST_F(HttpStreamFactoryTest, PreconnectSocksProxy) {
for (size_t i = 0; i < arraysize(kTests); ++i) {
SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateFixed("socks4://socks_proxy:1080"));
+ ProxyService::CreateFixed("socks4://socks_proxy:1080"));
std::unique_ptr<HttpNetworkSession> session(
SpdySessionDependencies::SpdyCreateSession(&session_deps));
HttpNetworkSessionPeer peer(session.get());
@@ -568,8 +577,10 @@ TEST_P(HttpStreamFactoryTest, PreconnectSocksProxy) {
session_deps.ct_policy_enforcer.get());
std::unique_ptr<MockClientSocketPoolManager> mock_pool_manager(
new MockClientSocketPoolManager);
- mock_pool_manager->SetSocketPoolForSOCKSProxy(proxy_host, socks_proxy_pool);
- mock_pool_manager->SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool);
+ mock_pool_manager->SetSocketPoolForSOCKSProxy(
+ proxy_host, base::WrapUnique(socks_proxy_pool));
+ mock_pool_manager->SetSocketPoolForSSLWithProxy(
+ proxy_host, base::WrapUnique(ssl_conn_pool));
peer.SetClientSocketPoolManager(std::move(mock_pool_manager));
PreconnectHelper(kTests[i], session.get());
if (kTests[i].ssl)
@@ -579,10 +590,9 @@ TEST_P(HttpStreamFactoryTest, PreconnectSocksProxy) {
}
}
-TEST_P(HttpStreamFactoryTest, PreconnectDirectWithExistingSpdySession) {
+TEST_F(HttpStreamFactoryTest, PreconnectDirectWithExistingSpdySession) {
for (size_t i = 0; i < arraysize(kTests); ++i) {
- SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateDirect());
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
std::unique_ptr<HttpNetworkSession> session(
SpdySessionDependencies::SpdyCreateSession(&session_deps));
HttpNetworkSessionPeer peer(session.get());
@@ -623,11 +633,10 @@ TEST_P(HttpStreamFactoryTest, PreconnectDirectWithExistingSpdySession) {
// Verify that preconnects to unsafe ports are cancelled before they reach
// the SocketPool.
-TEST_P(HttpStreamFactoryTest, PreconnectUnsafePort) {
+TEST_F(HttpStreamFactoryTest, PreconnectUnsafePort) {
ASSERT_FALSE(IsPortAllowedForScheme(7, "http"));
- SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateDirect());
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
std::unique_ptr<HttpNetworkSession> session(
SpdySessionDependencies::SpdyCreateSession(&session_deps));
HttpNetworkSessionPeer peer(session.get());
@@ -646,10 +655,10 @@ TEST_P(HttpStreamFactoryTest, PreconnectUnsafePort) {
EXPECT_EQ(-1, transport_conn_pool->last_num_streams());
}
-TEST_P(HttpStreamFactoryTest, JobNotifiesProxy) {
+TEST_F(HttpStreamFactoryTest, JobNotifiesProxy) {
const char* kProxyString = "PROXY bad:99; PROXY maybe:80; DIRECT";
SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateFixedFromPacResult(kProxyString));
+ ProxyService::CreateFixedFromPacResult(kProxyString));
// First connection attempt fails
StaticSocketDataProvider socket_data1;
@@ -675,7 +684,7 @@ TEST_P(HttpStreamFactoryTest, JobNotifiesProxy) {
std::unique_ptr<HttpStreamRequest> request(
session->http_stream_factory()->RequestStream(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
waiter.WaitForStream();
// The proxy that failed should now be known to the proxy_service as bad.
@@ -686,25 +695,30 @@ TEST_P(HttpStreamFactoryTest, JobNotifiesProxy) {
EXPECT_TRUE(iter != retry_info.end());
}
-TEST_P(HttpStreamFactoryTest, UnreachableQuicProxyMarkedAsBad) {
- const int mock_error[] = {ERR_PROXY_CONNECTION_FAILED,
- ERR_NAME_NOT_RESOLVED,
- ERR_INTERNET_DISCONNECTED,
- ERR_ADDRESS_UNREACHABLE,
- ERR_CONNECTION_CLOSED,
- ERR_CONNECTION_TIMED_OUT,
- ERR_CONNECTION_RESET,
- ERR_CONNECTION_REFUSED,
- ERR_CONNECTION_ABORTED,
- ERR_TIMED_OUT,
- ERR_TUNNEL_CONNECTION_FAILED,
- ERR_SOCKS_CONNECTION_FAILED,
- ERR_PROXY_CERTIFICATE_INVALID,
- ERR_QUIC_PROTOCOL_ERROR,
- ERR_QUIC_HANDSHAKE_FAILED,
- ERR_SSL_PROTOCOL_ERROR,
- ERR_MSG_TOO_BIG};
- for (size_t i = 0; i < arraysize(mock_error); ++i) {
+// List of errors that are used in the tests related to QUIC proxy.
+const int quic_proxy_test_mock_errors[] = {
+ ERR_PROXY_CONNECTION_FAILED,
+ ERR_NAME_NOT_RESOLVED,
+ ERR_INTERNET_DISCONNECTED,
+ ERR_ADDRESS_UNREACHABLE,
+ ERR_CONNECTION_CLOSED,
+ ERR_CONNECTION_TIMED_OUT,
+ ERR_CONNECTION_RESET,
+ ERR_CONNECTION_REFUSED,
+ ERR_CONNECTION_ABORTED,
+ ERR_TIMED_OUT,
+ ERR_TUNNEL_CONNECTION_FAILED,
+ ERR_SOCKS_CONNECTION_FAILED,
+ ERR_PROXY_CERTIFICATE_INVALID,
+ ERR_QUIC_PROTOCOL_ERROR,
+ ERR_QUIC_HANDSHAKE_FAILED,
+ ERR_SSL_PROTOCOL_ERROR,
+ ERR_MSG_TOO_BIG,
+};
+
+// Tests that a bad QUIC proxy is added to the list of bad proxies.
+TEST_F(HttpStreamFactoryTest, QuicProxyMarkedAsBad) {
+ for (size_t i = 0; i < arraysize(quic_proxy_test_mock_errors); ++i) {
std::unique_ptr<ProxyService> proxy_service;
proxy_service =
ProxyService::CreateFixedFromPacResult("QUIC bad:99; DIRECT");
@@ -735,7 +749,8 @@ TEST_P(HttpStreamFactoryTest, UnreachableQuicProxyMarkedAsBad) {
session->quic_stream_factory()->set_require_confirmation(false);
StaticSocketDataProvider socket_data1;
- socket_data1.set_connect_data(MockConnect(ASYNC, mock_error[i]));
+ socket_data1.set_connect_data(
+ MockConnect(ASYNC, quic_proxy_test_mock_errors[i]));
socket_factory.AddSocketDataProvider(&socket_data1);
// Second connection attempt succeeds.
@@ -754,17 +769,17 @@ TEST_P(HttpStreamFactoryTest, UnreachableQuicProxyMarkedAsBad) {
std::unique_ptr<HttpStreamRequest> request(
session->http_stream_factory()->RequestStream(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
waiter.WaitForStream();
// The proxy that failed should now be known to the proxy_service as bad.
const ProxyRetryInfoMap& retry_info =
session->proxy_service()->proxy_retry_info();
- EXPECT_EQ(1u, retry_info.size()) << mock_error[i];
+ EXPECT_EQ(1u, retry_info.size()) << quic_proxy_test_mock_errors[i];
EXPECT_TRUE(waiter.used_proxy_info().is_direct());
ProxyRetryInfoMap::const_iterator iter = retry_info.find("quic://bad:99");
- EXPECT_TRUE(iter != retry_info.end()) << mock_error[i];
+ EXPECT_TRUE(iter != retry_info.end()) << quic_proxy_test_mock_errors[i];
}
}
@@ -798,7 +813,7 @@ class MockQuicData {
public:
MockQuicData() : packet_number_(0) {}
- ~MockQuicData() { STLDeleteElements(&packets_); }
+ ~MockQuicData() { base::STLDeleteElements(&packets_); }
void AddRead(std::unique_ptr<QuicEncryptedPacket> packet) {
reads_.push_back(
@@ -832,73 +847,261 @@ class MockQuicData {
std::unique_ptr<SequencedSocketData> socket_data_;
};
+void SetupForQuicAlternativeProxyTest(
+ HttpNetworkSession::Params* params,
+ MockClientSocketFactory* socket_factory,
+ ProxyService* proxy_service,
+ TestProxyDelegate* test_proxy_delegate,
+ HttpServerPropertiesImpl* http_server_properties,
+ MockCertVerifier* cert_verifier,
+ CTPolicyEnforcer* ct_policy_enforcer,
+ MultiLogCTVerifier* ct_verifier,
+ SSLConfigServiceDefaults* ssl_config_service,
+ MockHostResolver* host_resolver,
+ TransportSecurityState* transport_security_state,
+ bool set_alternative_proxy_server) {
+ params->enable_quic = true;
+ params->quic_disable_preconnect_if_0rtt = false;
+ params->client_socket_factory = socket_factory;
+ params->host_resolver = host_resolver;
+ params->transport_security_state = transport_security_state;
+ params->proxy_service = proxy_service;
+ params->ssl_config_service = ssl_config_service;
+ params->http_server_properties = http_server_properties;
+ params->cert_verifier = cert_verifier;
+ params->ct_policy_enforcer = ct_policy_enforcer;
+ params->cert_transparency_verifier = ct_verifier;
+
+ if (set_alternative_proxy_server) {
+ test_proxy_delegate->set_alternative_proxy_server(
+ ProxyServer::FromPacString("QUIC badproxy:99"));
+ }
+ params->proxy_delegate = test_proxy_delegate;
+}
+
} // namespace
-TEST_P(HttpStreamFactoryTest, QuicLossyProxyMarkedAsBad) {
- // Checks if a
- std::unique_ptr<ProxyService> proxy_service;
- proxy_service = ProxyService::CreateFixedFromPacResult("QUIC bad:99; DIRECT");
-
- HttpNetworkSession::Params params;
- params.enable_quic = true;
- params.quic_disable_preconnect_if_0rtt = false;
- scoped_refptr<SSLConfigServiceDefaults> ssl_config_service(
- new SSLConfigServiceDefaults);
- HttpServerPropertiesImpl http_server_properties;
- MockClientSocketFactory socket_factory;
- params.client_socket_factory = &socket_factory;
- MockHostResolver host_resolver;
- params.host_resolver = &host_resolver;
- MockCertVerifier cert_verifier;
- params.cert_verifier = &cert_verifier;
- TransportSecurityState transport_security_state;
- params.transport_security_state = &transport_security_state;
- MultiLogCTVerifier ct_verifier;
- params.cert_transparency_verifier = &ct_verifier;
- CTPolicyEnforcer ct_policy_enforcer;
- params.ct_policy_enforcer = &ct_policy_enforcer;
- params.proxy_service = proxy_service.get();
- params.ssl_config_service = ssl_config_service.get();
- params.http_server_properties = &http_server_properties;
- params.quic_max_number_of_lossy_connections = 2;
-
- std::unique_ptr<HttpNetworkSession> session(new HttpNetworkSession(params));
- session->quic_stream_factory()->set_require_confirmation(false);
-
- session->quic_stream_factory()->number_of_lossy_connections_[99] =
- params.quic_max_number_of_lossy_connections;
- session->quic_stream_factory()->MaybeDisableQuic(99);
- ASSERT_TRUE(session->quic_stream_factory()->IsQuicDisabled(99));
+// Tests that a HTTPS proxy that supports QUIC alternative proxy server is
+// marked as bad if connecting to both the default proxy and the alternative
+// proxy is unsuccessful.
+TEST_F(HttpStreamFactoryTest, WithQUICAlternativeProxyMarkedAsBad) {
+ const bool set_alternative_proxy_server_values[] = {
+ false, true,
+ };
- StaticSocketDataProvider socket_data2;
- socket_data2.set_connect_data(MockConnect(ASYNC, OK));
- socket_factory.AddSocketDataProvider(&socket_data2);
+ for (auto mock_error : quic_proxy_test_mock_errors) {
+ for (auto set_alternative_proxy_server :
+ set_alternative_proxy_server_values) {
+ HttpNetworkSession::Params params;
+ MockClientSocketFactory socket_factory;
+ std::unique_ptr<ProxyService> proxy_service =
+ ProxyService::CreateFixedFromPacResult(
+ "HTTPS badproxy:99; HTTPS badfallbackproxy:98; DIRECT");
+ TestProxyDelegate test_proxy_delegate;
+ HttpServerPropertiesImpl http_server_properties;
+ MockCertVerifier cert_verifier;
+ CTPolicyEnforcer ct_policy_enforcer;
+ MultiLogCTVerifier ct_verifier;
+ scoped_refptr<SSLConfigServiceDefaults> ssl_config_service(
+ new SSLConfigServiceDefaults);
+ MockHostResolver host_resolver;
+ TransportSecurityState transport_security_state;
+ SetupForQuicAlternativeProxyTest(
+ &params, &socket_factory, proxy_service.get(), &test_proxy_delegate,
+ &http_server_properties, &cert_verifier, &ct_policy_enforcer,
+ &ct_verifier, ssl_config_service.get(), &host_resolver,
+ &transport_security_state, set_alternative_proxy_server);
+
+ std::unique_ptr<HttpNetworkSession> session(
+ new HttpNetworkSession(params));
+
+ // Before starting the test, verify that there are no proxies marked as
+ // bad.
+ ASSERT_TRUE(session->proxy_service()->proxy_retry_info().empty())
+ << mock_error;
+
+ StaticSocketDataProvider socket_data_proxy_main_job;
+ socket_data_proxy_main_job.set_connect_data(
+ MockConnect(ASYNC, mock_error));
+ socket_factory.AddSocketDataProvider(&socket_data_proxy_main_job);
+
+ StaticSocketDataProvider socket_data_proxy_alternate_job;
+ if (set_alternative_proxy_server) {
+ // Mock socket used by the QUIC job.
+ socket_data_proxy_alternate_job.set_connect_data(
+ MockConnect(ASYNC, mock_error));
+ socket_factory.AddSocketDataProvider(&socket_data_proxy_alternate_job);
+ }
+
+ // When retrying the job using the second proxy (badFallback:98),
+ // alternative job must not be created. So, socket data for only the
+ // main job is needed.
+ StaticSocketDataProvider socket_data_proxy_main_job_2;
+ socket_data_proxy_main_job_2.set_connect_data(
+ MockConnect(ASYNC, mock_error));
+ socket_factory.AddSocketDataProvider(&socket_data_proxy_main_job_2);
+
+ // First request would use DIRECT, and succeed.
+ StaticSocketDataProvider socket_data_direct_first_request;
+ socket_data_direct_first_request.set_connect_data(MockConnect(ASYNC, OK));
+ socket_factory.AddSocketDataProvider(&socket_data_direct_first_request);
+
+ // Second request would use DIRECT, and succeed.
+ StaticSocketDataProvider socket_data_direct_second_request;
+ socket_data_direct_second_request.set_connect_data(
+ MockConnect(ASYNC, OK));
+ socket_factory.AddSocketDataProvider(&socket_data_direct_second_request);
+
+ // Now request a stream. It should succeed using the DIRECT.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("http://www.google.com");
+
+ SSLConfig ssl_config;
+ StreamRequestWaiter waiter;
+
+ EXPECT_EQ(set_alternative_proxy_server,
+ test_proxy_delegate.alternative_proxy_server().is_quic());
+
+ // Start two requests. The first request should consume data from
+ // |socket_data_proxy_main_job|,
+ // |socket_data_proxy_alternate_job| and
+ // |socket_data_direct_first_request|. The second request should consume
+ // data from |socket_data_direct_second_request|.
+ for (size_t i = 0; i < 2; ++i) {
+ std::unique_ptr<HttpStreamRequest> request(
+ session->http_stream_factory()->RequestStream(
+ request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
+ NetLogWithSource()));
+ waiter.WaitForStream();
+
+ // The proxy that failed should now be known to the proxy_service as
+ // bad.
+ const ProxyRetryInfoMap retry_info =
+ session->proxy_service()->proxy_retry_info();
+ EXPECT_EQ(2u, retry_info.size()) << mock_error;
+
+ // Verify that request was fetched without proxy.
+ EXPECT_TRUE(waiter.used_proxy_info().is_direct());
+
+ EXPECT_NE(retry_info.end(), retry_info.find("https://badproxy:99"));
+ EXPECT_NE(retry_info.end(),
+ retry_info.find("https://badfallbackproxy:98"));
+
+ // 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());
+ }
+ }
+ }
+ }
+}
- // Now request a stream. It should succeed using the second proxy in the
- // list.
- HttpRequestInfo request_info;
- request_info.method = "GET";
- request_info.url = GURL("http://www.google.com");
+// Tests that a HTTPS proxy that supports QUIC alternative proxy server is
+// not marked as bad if only the alternative proxy server job fails.
+TEST_F(HttpStreamFactoryTest, WithQUICAlternativeProxyNotMarkedAsBad) {
+ for (auto mock_error : quic_proxy_test_mock_errors) {
+ HttpNetworkSession::Params params;
+ MockClientSocketFactory socket_factory;
+ std::unique_ptr<ProxyService> proxy_service =
+ ProxyService::CreateFixedFromPacResult("HTTPS badproxy:99; DIRECT");
+ TestProxyDelegate test_proxy_delegate;
+ HttpServerPropertiesImpl http_server_properties;
+ MockCertVerifier cert_verifier;
+ CTPolicyEnforcer ct_policy_enforcer;
+ MultiLogCTVerifier ct_verifier;
- SSLConfig ssl_config;
- StreamRequestWaiter waiter;
- std::unique_ptr<HttpStreamRequest> request(
- session->http_stream_factory()->RequestStream(
- request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
- waiter.WaitForStream();
+ scoped_refptr<SSLConfigServiceDefaults> ssl_config_service(
+ new SSLConfigServiceDefaults);
+ MockHostResolver host_resolver;
+ TransportSecurityState transport_security_state;
- // The proxy that failed should now be known to the proxy_service as bad.
- const ProxyRetryInfoMap& retry_info =
- session->proxy_service()->proxy_retry_info();
- EXPECT_EQ(1u, retry_info.size());
- EXPECT_TRUE(waiter.used_proxy_info().is_direct());
+ SetupForQuicAlternativeProxyTest(
+ &params, &socket_factory, proxy_service.get(), &test_proxy_delegate,
+ &http_server_properties, &cert_verifier, &ct_policy_enforcer,
+ &ct_verifier, ssl_config_service.get(), &host_resolver,
+ &transport_security_state, true);
- ProxyRetryInfoMap::const_iterator iter = retry_info.find("quic://bad:99");
- EXPECT_TRUE(iter != retry_info.end());
+ HostPortPair host_port_pair("badproxy", 99);
+ std::unique_ptr<HttpNetworkSession> session(new HttpNetworkSession(params));
+
+ // Before starting the test, verify that there are no proxies marked as
+ // bad.
+ ASSERT_TRUE(session->proxy_service()->proxy_retry_info().empty())
+ << mock_error;
+
+ StaticSocketDataProvider socket_data_proxy_main_job;
+ socket_data_proxy_main_job.set_connect_data(MockConnect(ASYNC, mock_error));
+ socket_factory.AddSocketDataProvider(&socket_data_proxy_main_job);
+
+ SSLSocketDataProvider ssl_data(ASYNC, OK);
+
+ // Next connection attempt would use HTTPS proxy, and succeed.
+ StaticSocketDataProvider socket_data_https_first;
+ socket_data_https_first.set_connect_data(MockConnect(ASYNC, OK));
+ socket_factory.AddSocketDataProvider(&socket_data_https_first);
+ socket_factory.AddSSLSocketDataProvider(&ssl_data);
+
+ // Next connection attempt would use HTTPS proxy, and succeed.
+ StaticSocketDataProvider socket_data_https_second;
+ socket_data_https_second.set_connect_data(MockConnect(ASYNC, OK));
+ socket_factory.AddSocketDataProvider(&socket_data_https_second);
+ socket_factory.AddSSLSocketDataProvider(&ssl_data);
+
+ // Now request a stream. It should succeed using the second proxy in the
+ // list.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("http://www.google.com");
+
+ SSLConfig ssl_config;
+ StreamRequestWaiter waiter;
+
+ EXPECT_TRUE(test_proxy_delegate.alternative_proxy_server().is_quic());
+
+ // Start two requests. The first request should consume data from
+ // |socket_data_proxy_main_job| and |socket_data_https_first|.
+ // The second request should consume data from |socket_data_https_second|.
+ for (size_t i = 0; i < 2; ++i) {
+ std::unique_ptr<HttpStreamRequest> request(
+ session->http_stream_factory()->RequestStream(
+ request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
+ NetLogWithSource()));
+ waiter.WaitForStream();
+
+ // The proxy that failed should now be known to the proxy_service as
+ // bad.
+ const ProxyRetryInfoMap retry_info =
+ session->proxy_service()->proxy_retry_info();
+ // Proxy should not be marked as bad.
+ EXPECT_EQ(0u, retry_info.size()) << mock_error;
+ // Verify that request was fetched using proxy.
+ EXPECT_TRUE(waiter.used_proxy_info().is_https());
+ EXPECT_TRUE(host_port_pair.Equals(
+ waiter.used_proxy_info().proxy_server().host_port_pair()));
+ net::ProxyServer proxy_server;
+
+ // 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());
+ }
+ }
}
-TEST_P(HttpStreamFactoryTest, UsePreConnectIfNoZeroRTT) {
+TEST_F(HttpStreamFactoryTest, UsePreConnectIfNoZeroRTT) {
for (int num_streams = 1; num_streams < 3; ++num_streams) {
GURL url = GURL("https://www.google.com");
@@ -917,7 +1120,7 @@ TEST_P(HttpStreamFactoryTest, UsePreConnectIfNoZeroRTT) {
server, alternative_service_info_vector);
SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateFixed("http_proxy"));
+ ProxyService::CreateFixed("http_proxy"));
// Setup params to disable preconnect, but QUIC doesn't 0RTT.
HttpNetworkSession::Params params =
@@ -943,15 +1146,17 @@ TEST_P(HttpStreamFactoryTest, UsePreConnectIfNoZeroRTT) {
session_deps.ct_policy_enforcer.get());
std::unique_ptr<MockClientSocketPoolManager> mock_pool_manager(
new MockClientSocketPoolManager);
- mock_pool_manager->SetSocketPoolForHTTPProxy(proxy_host, http_proxy_pool);
- mock_pool_manager->SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool);
+ mock_pool_manager->SetSocketPoolForHTTPProxy(
+ proxy_host, base::WrapUnique(http_proxy_pool));
+ mock_pool_manager->SetSocketPoolForSSLWithProxy(
+ proxy_host, base::WrapUnique(ssl_conn_pool));
peer.SetClientSocketPoolManager(std::move(mock_pool_manager));
PreconnectHelperForURL(num_streams, url, session.get());
EXPECT_EQ(num_streams, ssl_conn_pool->last_num_streams());
}
}
-TEST_P(HttpStreamFactoryTest, QuicDisablePreConnectIfZeroRtt) {
+TEST_F(HttpStreamFactoryTest, QuicDisablePreConnectIfZeroRtt) {
for (int num_streams = 1; num_streams < 3; ++num_streams) {
GURL url = GURL("https://www.google.com");
@@ -968,7 +1173,7 @@ TEST_P(HttpStreamFactoryTest, QuicDisablePreConnectIfZeroRtt) {
http_server_properties.SetAlternativeServices(
server, alternative_service_info_vector);
- SpdySessionDependencies session_deps(GetParam());
+ SpdySessionDependencies session_deps;
// Setup params to disable preconnect, but QUIC does 0RTT.
HttpNetworkSession::Params params =
@@ -1009,9 +1214,8 @@ TEST_P(HttpStreamFactoryTest, QuicDisablePreConnectIfZeroRtt) {
namespace {
-TEST_P(HttpStreamFactoryTest, PrivacyModeDisablesChannelId) {
- SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateDirect());
+TEST_F(HttpStreamFactoryTest, PrivacyModeDisablesChannelId) {
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
StaticSocketDataProvider socket_data;
socket_data.set_connect_data(MockConnect(ASYNC, OK));
@@ -1039,7 +1243,7 @@ TEST_P(HttpStreamFactoryTest, PrivacyModeDisablesChannelId) {
std::unique_ptr<HttpStreamRequest> request(
session->http_stream_factory()->RequestStream(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
waiter.WaitForStream();
// The stream shouldn't come from spdy as we are using different privacy mode
@@ -1076,9 +1280,8 @@ int GetSpdySessionCount(HttpNetworkSession* session) {
} // namespace
-TEST_P(HttpStreamFactoryTest, PrivacyModeUsesDifferentSocketPoolGroup) {
- SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateDirect());
+TEST_F(HttpStreamFactoryTest, PrivacyModeUsesDifferentSocketPoolGroup) {
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
StaticSocketDataProvider socket_data_1;
socket_data_1.set_connect_data(MockConnect(ASYNC, OK));
@@ -1116,7 +1319,7 @@ TEST_P(HttpStreamFactoryTest, PrivacyModeUsesDifferentSocketPoolGroup) {
std::unique_ptr<HttpStreamRequest> request1(
session->http_stream_factory()->RequestStream(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
waiter.WaitForStream();
EXPECT_EQ(GetSocketPoolGroupCount(ssl_pool), 1);
@@ -1124,7 +1327,7 @@ TEST_P(HttpStreamFactoryTest, PrivacyModeUsesDifferentSocketPoolGroup) {
std::unique_ptr<HttpStreamRequest> request2(
session->http_stream_factory()->RequestStream(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
waiter.WaitForStream();
EXPECT_EQ(GetSocketPoolGroupCount(ssl_pool), 1);
@@ -1133,15 +1336,14 @@ TEST_P(HttpStreamFactoryTest, PrivacyModeUsesDifferentSocketPoolGroup) {
std::unique_ptr<HttpStreamRequest> request3(
session->http_stream_factory()->RequestStream(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
waiter.WaitForStream();
EXPECT_EQ(GetSocketPoolGroupCount(ssl_pool), 2);
}
-TEST_P(HttpStreamFactoryTest, GetLoadState) {
- SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateDirect());
+TEST_F(HttpStreamFactoryTest, GetLoadState) {
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
// Force asynchronous host resolutions, so that the LoadState will be
// resolving the host.
@@ -1163,16 +1365,15 @@ TEST_P(HttpStreamFactoryTest, GetLoadState) {
std::unique_ptr<HttpStreamRequest> request(
session->http_stream_factory()->RequestStream(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(LOAD_STATE_RESOLVING_HOST, request->GetLoadState());
waiter.WaitForStream();
}
-TEST_P(HttpStreamFactoryTest, RequestHttpStream) {
- SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateDirect());
+TEST_F(HttpStreamFactoryTest, RequestHttpStream) {
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
StaticSocketDataProvider socket_data;
socket_data.set_connect_data(MockConnect(ASYNC, OK));
@@ -1193,7 +1394,7 @@ TEST_P(HttpStreamFactoryTest, RequestHttpStream) {
std::unique_ptr<HttpStreamRequest> request(
session->http_stream_factory()->RequestStream(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
waiter.WaitForStream();
EXPECT_TRUE(waiter.stream_done());
ASSERT_TRUE(nullptr != waiter.stream());
@@ -1212,9 +1413,8 @@ TEST_P(HttpStreamFactoryTest, RequestHttpStream) {
EXPECT_TRUE(waiter.used_proxy_info().is_direct());
}
-TEST_P(HttpStreamFactoryTest, RequestHttpStreamOverSSL) {
- SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateDirect());
+TEST_F(HttpStreamFactoryTest, RequestHttpStreamOverSSL) {
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
MockRead mock_read(ASYNC, OK);
StaticSocketDataProvider socket_data(&mock_read, 1, nullptr, 0);
@@ -1238,7 +1438,7 @@ TEST_P(HttpStreamFactoryTest, RequestHttpStreamOverSSL) {
std::unique_ptr<HttpStreamRequest> request(
session->http_stream_factory()->RequestStream(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
waiter.WaitForStream();
EXPECT_TRUE(waiter.stream_done());
ASSERT_TRUE(nullptr != waiter.stream());
@@ -1257,9 +1457,9 @@ TEST_P(HttpStreamFactoryTest, RequestHttpStreamOverSSL) {
EXPECT_TRUE(waiter.used_proxy_info().is_direct());
}
-TEST_P(HttpStreamFactoryTest, RequestHttpStreamOverProxy) {
+TEST_F(HttpStreamFactoryTest, RequestHttpStreamOverProxy) {
SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateFixed("myproxy:8888"));
+ ProxyService::CreateFixed("myproxy:8888"));
StaticSocketDataProvider socket_data;
socket_data.set_connect_data(MockConnect(ASYNC, OK));
@@ -1280,7 +1480,7 @@ TEST_P(HttpStreamFactoryTest, RequestHttpStreamOverProxy) {
std::unique_ptr<HttpStreamRequest> request(
session->http_stream_factory()->RequestStream(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
waiter.WaitForStream();
EXPECT_TRUE(waiter.stream_done());
ASSERT_TRUE(nullptr != waiter.stream());
@@ -1306,9 +1506,8 @@ TEST_P(HttpStreamFactoryTest, RequestHttpStreamOverProxy) {
EXPECT_FALSE(waiter.used_proxy_info().is_direct());
}
-TEST_P(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStream) {
- SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateDirect());
+TEST_F(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStream) {
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
StaticSocketDataProvider socket_data;
socket_data.set_connect_data(MockConnect(ASYNC, OK));
@@ -1328,9 +1527,9 @@ TEST_P(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStream) {
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, BoundNetLog()));
+ ->RequestWebSocketHandshakeStream(
+ request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
+ &create_helper, NetLogWithSource()));
waiter.WaitForStream();
EXPECT_TRUE(waiter.stream_done());
EXPECT_TRUE(nullptr == waiter.stream());
@@ -1346,9 +1545,8 @@ TEST_P(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStream) {
EXPECT_TRUE(waiter.used_proxy_info().is_direct());
}
-TEST_P(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStreamOverSSL) {
- SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateDirect());
+TEST_F(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStreamOverSSL) {
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
MockRead mock_read(ASYNC, OK);
StaticSocketDataProvider socket_data(&mock_read, 1, nullptr, 0);
@@ -1372,9 +1570,9 @@ TEST_P(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStreamOverSSL) {
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, BoundNetLog()));
+ ->RequestWebSocketHandshakeStream(
+ request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
+ &create_helper, NetLogWithSource()));
waiter.WaitForStream();
EXPECT_TRUE(waiter.stream_done());
EXPECT_TRUE(nullptr == waiter.stream());
@@ -1390,9 +1588,9 @@ TEST_P(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStreamOverSSL) {
EXPECT_TRUE(waiter.used_proxy_info().is_direct());
}
-TEST_P(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStreamOverProxy) {
+TEST_F(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStreamOverProxy) {
SpdySessionDependencies session_deps(
- GetParam(), ProxyService::CreateFixed("myproxy:8888"));
+ ProxyService::CreateFixed("myproxy:8888"));
MockRead read(SYNCHRONOUS, "HTTP/1.0 200 Connection established\r\n\r\n");
StaticSocketDataProvider socket_data(&read, 1, 0, 0);
@@ -1413,9 +1611,9 @@ TEST_P(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStreamOverProxy) {
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, BoundNetLog()));
+ ->RequestWebSocketHandshakeStream(
+ request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
+ &create_helper, NetLogWithSource()));
waiter.WaitForStream();
EXPECT_TRUE(waiter.stream_done());
EXPECT_TRUE(nullptr == waiter.stream());
@@ -1442,9 +1640,8 @@ TEST_P(HttpStreamFactoryTest, RequestWebSocketBasicHandshakeStreamOverProxy) {
EXPECT_FALSE(waiter.used_proxy_info().is_direct());
}
-TEST_P(HttpStreamFactoryTest, RequestSpdyHttpStream) {
- SpdySessionDependencies session_deps(GetParam(),
- ProxyService::CreateDirect());
+TEST_F(HttpStreamFactoryTest, RequestSpdyHttpStream) {
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
MockRead mock_read(SYNCHRONOUS, ERR_IO_PENDING);
SequencedSocketData socket_data(&mock_read, 1, nullptr, 0);
@@ -1452,7 +1649,7 @@ TEST_P(HttpStreamFactoryTest, RequestSpdyHttpStream) {
session_deps.socket_factory->AddSocketDataProvider(&socket_data);
SSLSocketDataProvider ssl_socket_data(ASYNC, OK);
- ssl_socket_data.SetNextProto(GetParam());
+ ssl_socket_data.next_proto = kProtoHTTP2;
session_deps.socket_factory->AddSSLSocketDataProvider(&ssl_socket_data);
HostPortPair host_port_pair("www.google.com", 443);
@@ -1470,7 +1667,7 @@ TEST_P(HttpStreamFactoryTest, RequestSpdyHttpStream) {
std::unique_ptr<HttpStreamRequest> request(
session->http_stream_factory()->RequestStream(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
waiter.WaitForStream();
EXPECT_TRUE(waiter.stream_done());
EXPECT_TRUE(nullptr == waiter.websocket_stream());
@@ -1489,9 +1686,8 @@ TEST_P(HttpStreamFactoryTest, RequestSpdyHttpStream) {
EXPECT_TRUE(waiter.used_proxy_info().is_direct());
}
-TEST_P(HttpStreamFactoryTest, RequestBidirectionalStreamImpl) {
- SpdySessionDependencies session_deps(GetParam(),
- ProxyService::CreateDirect());
+TEST_F(HttpStreamFactoryTest, RequestBidirectionalStreamImpl) {
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
MockRead mock_read(ASYNC, OK);
SequencedSocketData socket_data(&mock_read, 1, nullptr, 0);
@@ -1499,7 +1695,7 @@ TEST_P(HttpStreamFactoryTest, RequestBidirectionalStreamImpl) {
session_deps.socket_factory->AddSocketDataProvider(&socket_data);
SSLSocketDataProvider ssl_socket_data(ASYNC, OK);
- ssl_socket_data.SetNextProto(GetParam());
+ ssl_socket_data.next_proto = kProtoHTTP2;
session_deps.socket_factory->AddSSLSocketDataProvider(&ssl_socket_data);
HostPortPair host_port_pair("www.google.com", 443);
@@ -1517,7 +1713,7 @@ TEST_P(HttpStreamFactoryTest, RequestBidirectionalStreamImpl) {
std::unique_ptr<HttpStreamRequest> request(
session->http_stream_factory()->RequestBidirectionalStreamImpl(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
waiter.WaitForStream();
EXPECT_TRUE(waiter.stream_done());
EXPECT_FALSE(waiter.websocket_stream());
@@ -1640,7 +1836,7 @@ class HttpStreamFactoryBidirectionalQuicTest
INSTANTIATE_TEST_CASE_P(Version,
HttpStreamFactoryBidirectionalQuicTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(HttpStreamFactoryBidirectionalQuicTest,
RequestBidirectionalStreamImplQuicAlternative) {
@@ -1685,7 +1881,7 @@ TEST_P(HttpStreamFactoryBidirectionalQuicTest,
std::unique_ptr<HttpStreamRequest> request(
session()->http_stream_factory()->RequestBidirectionalStreamImpl(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
waiter.WaitForStream();
EXPECT_TRUE(waiter.stream_done());
@@ -1701,13 +1897,13 @@ TEST_P(HttpStreamFactoryBidirectionalQuicTest,
bidi_request_info.priority = LOWEST;
TestBidirectionalDelegate delegate;
- stream_impl->Start(&bidi_request_info, BoundNetLog(),
+ stream_impl->Start(&bidi_request_info, NetLogWithSource(),
/*send_request_headers_automatically=*/true, &delegate,
nullptr);
delegate.WaitUntilDone();
scoped_refptr<IOBuffer> buffer = new net::IOBuffer(1);
- EXPECT_EQ(OK, stream_impl->ReadData(buffer.get(), 1));
+ EXPECT_THAT(stream_impl->ReadData(buffer.get(), 1), IsOk());
EXPECT_EQ(kProtoQUIC1SPDY3, stream_impl->GetProtocol());
EXPECT_EQ("200", delegate.response_headers().find(":status")->second);
EXPECT_EQ(0, GetSocketPoolGroupCount(session()->GetTransportSocketPool(
@@ -1750,7 +1946,7 @@ TEST_P(HttpStreamFactoryBidirectionalQuicTest,
std::unique_ptr<HttpStreamRequest> request(
session()->http_stream_factory()->RequestBidirectionalStreamImpl(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
waiter.WaitForStream();
EXPECT_TRUE(waiter.stream_done());
@@ -1759,7 +1955,7 @@ TEST_P(HttpStreamFactoryBidirectionalQuicTest,
ASSERT_FALSE(waiter.bidirectional_stream_impl());
// Since the alternative service job is not started, we will get the error
// from the http job.
- ASSERT_EQ(ERR_CONNECTION_REFUSED, waiter.error_status());
+ ASSERT_THAT(waiter.error_status(), IsError(ERR_CONNECTION_REFUSED));
}
// Tests that if Http job fails, but Quic job succeeds, we return
@@ -1808,7 +2004,7 @@ TEST_P(HttpStreamFactoryBidirectionalQuicTest,
std::unique_ptr<HttpStreamRequest> request(
session()->http_stream_factory()->RequestBidirectionalStreamImpl(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
waiter.WaitForStream();
EXPECT_TRUE(waiter.stream_done());
@@ -1824,14 +2020,14 @@ TEST_P(HttpStreamFactoryBidirectionalQuicTest,
bidi_request_info.priority = LOWEST;
TestBidirectionalDelegate delegate;
- stream_impl->Start(&bidi_request_info, BoundNetLog(),
+ stream_impl->Start(&bidi_request_info, NetLogWithSource(),
/*send_request_headers_automatically=*/true, &delegate,
nullptr);
delegate.WaitUntilDone();
// Make sure the BidirectionalStream negotiated goes through QUIC.
scoped_refptr<IOBuffer> buffer = new net::IOBuffer(1);
- EXPECT_EQ(OK, stream_impl->ReadData(buffer.get(), 1));
+ EXPECT_THAT(stream_impl->ReadData(buffer.get(), 1), IsOk());
EXPECT_EQ(kProtoQUIC1SPDY3, stream_impl->GetProtocol());
EXPECT_EQ("200", delegate.response_headers().find(":status")->second);
// There is no Http2 socket pool.
@@ -1846,9 +2042,8 @@ TEST_P(HttpStreamFactoryBidirectionalQuicTest,
EXPECT_TRUE(waiter.used_proxy_info().is_direct());
}
-TEST_P(HttpStreamFactoryTest, RequestBidirectionalStreamImplFailure) {
- SpdySessionDependencies session_deps(GetParam(),
- ProxyService::CreateDirect());
+TEST_F(HttpStreamFactoryTest, RequestBidirectionalStreamImplFailure) {
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
MockRead mock_read(ASYNC, OK);
SequencedSocketData socket_data(&mock_read, 1, nullptr, 0);
@@ -1858,7 +2053,7 @@ TEST_P(HttpStreamFactoryTest, RequestBidirectionalStreamImplFailure) {
SSLSocketDataProvider ssl_socket_data(ASYNC, OK);
// If HTTP/1 is used, BidirectionalStreamImpl should not be obtained.
- ssl_socket_data.SetNextProto(kProtoHTTP11);
+ ssl_socket_data.next_proto = kProtoHTTP11;
session_deps.socket_factory->AddSSLSocketDataProvider(&ssl_socket_data);
HostPortPair host_port_pair("www.google.com", 443);
@@ -1876,10 +2071,10 @@ TEST_P(HttpStreamFactoryTest, RequestBidirectionalStreamImplFailure) {
std::unique_ptr<HttpStreamRequest> request(
session->http_stream_factory()->RequestBidirectionalStreamImpl(
request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
- BoundNetLog()));
+ NetLogWithSource()));
waiter.WaitForStream();
EXPECT_TRUE(waiter.stream_done());
- ASSERT_EQ(ERR_FAILED, waiter.error_status());
+ ASSERT_THAT(waiter.error_status(), IsError(ERR_FAILED));
EXPECT_FALSE(waiter.websocket_stream());
ASSERT_FALSE(waiter.stream());
ASSERT_FALSE(waiter.bidirectional_stream_impl());
@@ -1896,9 +2091,8 @@ TEST_P(HttpStreamFactoryTest, RequestBidirectionalStreamImplFailure) {
// TODO(ricea): This test can be removed once the new WebSocket stack supports
// SPDY. Currently, even if we connect to a SPDY-supporting server, we need to
// use plain SSL.
-TEST_P(HttpStreamFactoryTest, RequestWebSocketSpdyHandshakeStreamButGetSSL) {
- SpdySessionDependencies session_deps(GetParam(),
- ProxyService::CreateDirect());
+TEST_F(HttpStreamFactoryTest, RequestWebSocketSpdyHandshakeStreamButGetSSL) {
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
MockRead mock_read(SYNCHRONOUS, ERR_IO_PENDING);
StaticSocketDataProvider socket_data(&mock_read, 1, nullptr, 0);
@@ -1923,9 +2117,9 @@ TEST_P(HttpStreamFactoryTest, RequestWebSocketSpdyHandshakeStreamButGetSSL) {
WebSocketStreamCreateHelper create_helper;
std::unique_ptr<HttpStreamRequest> request1(
session->http_stream_factory_for_websocket()
- ->RequestWebSocketHandshakeStream(request_info, DEFAULT_PRIORITY,
- ssl_config, ssl_config, &waiter1,
- &create_helper, BoundNetLog()));
+ ->RequestWebSocketHandshakeStream(
+ request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter1,
+ &create_helper, NetLogWithSource()));
waiter1.WaitForStream();
EXPECT_TRUE(waiter1.stream_done());
ASSERT_TRUE(nullptr != waiter1.websocket_stream());
@@ -1943,9 +2137,8 @@ TEST_P(HttpStreamFactoryTest, RequestWebSocketSpdyHandshakeStreamButGetSSL) {
}
// TODO(ricea): Re-enable once WebSocket-over-SPDY is implemented.
-TEST_P(HttpStreamFactoryTest, DISABLED_RequestWebSocketSpdyHandshakeStream) {
- SpdySessionDependencies session_deps(GetParam(),
- ProxyService::CreateDirect());
+TEST_F(HttpStreamFactoryTest, DISABLED_RequestWebSocketSpdyHandshakeStream) {
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
MockRead mock_read(SYNCHRONOUS, ERR_IO_PENDING);
StaticSocketDataProvider socket_data(&mock_read, 1, nullptr, 0);
@@ -1953,7 +2146,7 @@ TEST_P(HttpStreamFactoryTest, DISABLED_RequestWebSocketSpdyHandshakeStream) {
session_deps.socket_factory->AddSocketDataProvider(&socket_data);
SSLSocketDataProvider ssl_socket_data(ASYNC, OK);
- ssl_socket_data.SetNextProto(GetParam());
+ ssl_socket_data.next_proto = kProtoHTTP2;
session_deps.socket_factory->AddSSLSocketDataProvider(&ssl_socket_data);
HostPortPair host_port_pair("www.google.com", 80);
@@ -1971,9 +2164,9 @@ TEST_P(HttpStreamFactoryTest, DISABLED_RequestWebSocketSpdyHandshakeStream) {
WebSocketStreamCreateHelper create_helper;
std::unique_ptr<HttpStreamRequest> request1(
session->http_stream_factory_for_websocket()
- ->RequestWebSocketHandshakeStream(request_info, DEFAULT_PRIORITY,
- ssl_config, ssl_config, &waiter1,
- &create_helper, BoundNetLog()));
+ ->RequestWebSocketHandshakeStream(
+ request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter1,
+ &create_helper, NetLogWithSource()));
waiter1.WaitForStream();
EXPECT_TRUE(waiter1.stream_done());
ASSERT_TRUE(nullptr != waiter1.websocket_stream());
@@ -1984,9 +2177,9 @@ TEST_P(HttpStreamFactoryTest, DISABLED_RequestWebSocketSpdyHandshakeStream) {
StreamRequestWaiter waiter2;
std::unique_ptr<HttpStreamRequest> request2(
session->http_stream_factory_for_websocket()
- ->RequestWebSocketHandshakeStream(request_info, DEFAULT_PRIORITY,
- ssl_config, ssl_config, &waiter2,
- &create_helper, BoundNetLog()));
+ ->RequestWebSocketHandshakeStream(
+ request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter2,
+ &create_helper, NetLogWithSource()));
waiter2.WaitForStream();
EXPECT_TRUE(waiter2.stream_done());
ASSERT_TRUE(nullptr != waiter2.websocket_stream());
@@ -2012,9 +2205,8 @@ TEST_P(HttpStreamFactoryTest, DISABLED_RequestWebSocketSpdyHandshakeStream) {
}
// TODO(ricea): Re-enable once WebSocket over SPDY is implemented.
-TEST_P(HttpStreamFactoryTest, DISABLED_OrphanedWebSocketStream) {
- SpdySessionDependencies session_deps(GetParam(),
- ProxyService::CreateDirect());
+TEST_F(HttpStreamFactoryTest, DISABLED_OrphanedWebSocketStream) {
+ SpdySessionDependencies session_deps(ProxyService::CreateDirect());
MockRead mock_read(ASYNC, OK);
SequencedSocketData socket_data(&mock_read, 1, nullptr, 0);
socket_data.set_connect_data(MockConnect(ASYNC, OK));
@@ -2026,7 +2218,7 @@ TEST_P(HttpStreamFactoryTest, DISABLED_OrphanedWebSocketStream) {
session_deps.socket_factory->AddSocketDataProvider(&socket_data2);
SSLSocketDataProvider ssl_socket_data(ASYNC, OK);
- ssl_socket_data.SetNextProto(GetParam());
+ ssl_socket_data.next_proto = kProtoHTTP2;
session_deps.socket_factory->AddSSLSocketDataProvider(&ssl_socket_data);
std::unique_ptr<HttpNetworkSession> session(
@@ -2051,9 +2243,9 @@ TEST_P(HttpStreamFactoryTest, DISABLED_OrphanedWebSocketStream) {
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, BoundNetLog()));
+ ->RequestWebSocketHandshakeStream(
+ request_info, DEFAULT_PRIORITY, ssl_config, ssl_config, &waiter,
+ &create_helper, NetLogWithSource()));
waiter.WaitForStream();
EXPECT_TRUE(waiter.stream_done());
EXPECT_TRUE(nullptr == waiter.stream());
diff --git a/chromium/net/http/http_stream_factory_test_util.cc b/chromium/net/http/http_stream_factory_test_util.cc
index 9b988b1594f..62d89c2c3f4 100644
--- a/chromium/net/http/http_stream_factory_test_util.cc
+++ b/chromium/net/http/http_stream_factory_test_util.cc
@@ -46,6 +46,7 @@ MockHttpStreamFactoryImplJob::MockHttpStreamFactoryImplJob(
HostPortPair destination,
GURL origin_url,
AlternativeService alternative_service,
+ const ProxyServer& alternative_proxy_server,
NetLog* net_log)
: HttpStreamFactoryImpl::Job(delegate,
job_type,
@@ -57,12 +58,15 @@ MockHttpStreamFactoryImplJob::MockHttpStreamFactoryImplJob(
destination,
origin_url,
alternative_service,
+ alternative_proxy_server,
net_log) {}
MockHttpStreamFactoryImplJob::~MockHttpStreamFactoryImplJob() {}
TestJobFactory::TestJobFactory()
- : main_job_(nullptr), alternative_job_(nullptr) {}
+ : main_job_(nullptr),
+ alternative_job_(nullptr),
+ override_main_job_url_(false) {}
TestJobFactory::~TestJobFactory() {}
@@ -78,12 +82,14 @@ HttpStreamFactoryImpl::Job* TestJobFactory::CreateJob(
GURL origin_url,
NetLog* net_log) {
DCHECK(!main_job_);
+
+ if (override_main_job_url_)
+ origin_url = main_job_alternative_url_;
+
main_job_ = new MockHttpStreamFactoryImplJob(
delegate, job_type, session, request_info, priority, SSLConfig(),
SSLConfig(), destination, origin_url, nullptr);
- EXPECT_CALL(*main_job_, Start(_)).Times(1);
-
return main_job_;
}
@@ -102,9 +108,29 @@ HttpStreamFactoryImpl::Job* TestJobFactory::CreateJob(
DCHECK(!alternative_job_);
alternative_job_ = new MockHttpStreamFactoryImplJob(
delegate, job_type, session, request_info, priority, SSLConfig(),
- SSLConfig(), destination, origin_url, alternative_service, nullptr);
+ SSLConfig(), destination, origin_url, alternative_service, ProxyServer(),
+ nullptr);
+
+ return alternative_job_;
+}
- EXPECT_CALL(*alternative_job_, Start(_)).Times(1);
+HttpStreamFactoryImpl::Job* TestJobFactory::CreateJob(
+ HttpStreamFactoryImpl::Job::Delegate* delegate,
+ HttpStreamFactoryImpl::JobType job_type,
+ HttpNetworkSession* session,
+ const HttpRequestInfo& request_info,
+ RequestPriority priority,
+ const SSLConfig& server_ssl_config,
+ const SSLConfig& proxy_ssl_config,
+ HostPortPair destination,
+ GURL origin_url,
+ const ProxyServer& alternative_proxy_server,
+ NetLog* net_log) {
+ DCHECK(!alternative_job_);
+ alternative_job_ = new MockHttpStreamFactoryImplJob(
+ delegate, job_type, session, request_info, priority, SSLConfig(),
+ SSLConfig(), destination, origin_url, AlternativeService(),
+ alternative_proxy_server, nullptr);
return alternative_job_;
}
diff --git a/chromium/net/http/http_stream_factory_test_util.h b/chromium/net/http/http_stream_factory_test_util.h
index a110508806b..39df572d677 100644
--- a/chromium/net/http/http_stream_factory_test_util.h
+++ b/chromium/net/http/http_stream_factory_test_util.h
@@ -12,8 +12,12 @@
#include "net/http/http_stream_factory_impl_job.h"
#include "net/http/http_stream_factory_impl_job_controller.h"
#include "net/proxy/proxy_info.h"
+#include "net/proxy/proxy_server.h"
#include "testing/gmock/include/gmock/gmock.h"
+using testing::_;
+using testing::Invoke;
+
namespace net {
class HttpStreamFactoryImplPeer {
@@ -109,13 +113,12 @@ class MockHttpStreamFactoryImplJob : public HttpStreamFactoryImpl::Job {
HostPortPair destination,
GURL origin_url,
AlternativeService alternative_service,
+ const ProxyServer& alternative_proxy_server,
NetLog* net_log);
~MockHttpStreamFactoryImplJob() override;
- MOCK_METHOD1(Start, void(HttpStreamRequest::StreamType stream_type));
-
- MOCK_METHOD1(MarkOtherJobComplete, void(const Job& job));
+ MOCK_METHOD0(Resume, void());
MOCK_METHOD0(Orphan, void());
};
@@ -151,14 +154,34 @@ class TestJobFactory : public HttpStreamFactoryImpl::JobFactory {
AlternativeService alternative_service,
NetLog* net_log) override;
+ HttpStreamFactoryImpl::Job* CreateJob(
+ HttpStreamFactoryImpl::Job::Delegate* delegate,
+ HttpStreamFactoryImpl::JobType job_type,
+ HttpNetworkSession* session,
+ const HttpRequestInfo& request_info,
+ RequestPriority priority,
+ const SSLConfig& server_ssl_config,
+ const SSLConfig& proxy_ssl_config,
+ HostPortPair destination,
+ GURL origin_url,
+ const ProxyServer& alternative_proxy_server,
+ NetLog* net_log) override;
+
MockHttpStreamFactoryImplJob* main_job() const { return main_job_; }
MockHttpStreamFactoryImplJob* alternative_job() const {
return alternative_job_;
}
+ void UseDifferentURLForMainJob(GURL url) {
+ override_main_job_url_ = true;
+ main_job_alternative_url_ = url;
+ }
+
private:
MockHttpStreamFactoryImplJob* main_job_;
MockHttpStreamFactoryImplJob* alternative_job_;
+ bool override_main_job_url_;
+ GURL main_job_alternative_url_;
};
} // namespace net
diff --git a/chromium/net/http/http_stream_parser.cc b/chromium/net/http/http_stream_parser.cc
index b673689ed29..0a65fda598a 100644
--- a/chromium/net/http/http_stream_parser.cc
+++ b/chromium/net/http/http_stream_parser.cc
@@ -22,9 +22,11 @@
#include "net/http/http_response_headers.h"
#include "net/http/http_status_line_validator.h"
#include "net/http/http_util.h"
+#include "net/log/net_log_event_type.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/ssl_client_socket.h"
#include "net/ssl/token_binding.h"
+#include "url/url_canon.h"
namespace net {
@@ -202,11 +204,12 @@ const size_t HttpStreamParser::kChunkHeaderFooterSize = 12;
HttpStreamParser::HttpStreamParser(ClientSocketHandle* connection,
const HttpRequestInfo* request,
GrowableIOBuffer* read_buffer,
- const BoundNetLog& net_log)
+ const NetLogWithSource& net_log)
: io_state_(STATE_NONE),
request_(request),
request_headers_(nullptr),
request_headers_length_(0),
+ http_09_on_non_default_ports_enabled_(false),
read_buf_(read_buffer),
read_buf_unused_offset_(0),
response_header_start_offset_(-1),
@@ -239,14 +242,11 @@ int HttpStreamParser::SendRequest(const std::string& request_line,
DCHECK(!callback.is_null());
DCHECK(response);
- net_log_.AddEvent(
- NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
- base::Bind(&HttpRequestHeaders::NetLogCallback,
- base::Unretained(&headers),
- &request_line));
+ net_log_.AddEvent(NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
+ base::Bind(&HttpRequestHeaders::NetLogCallback,
+ base::Unretained(&headers), &request_line));
- DVLOG(1) << __FUNCTION__ << "()"
- << " request_line = \"" << request_line << "\""
+ DVLOG(1) << __func__ << "() request_line = \"" << request_line << "\""
<< " headers = \"" << headers.ToString() << "\"";
response_ = response;
@@ -305,12 +305,11 @@ int HttpStreamParser::SendRequest(const std::string& request_line,
request_headers_->SetOffset(0);
did_merge = true;
- net_log_.AddEvent(
- NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_BODY,
- base::Bind(&NetLogSendRequestBodyCallback,
- request_->upload_data_stream->size(),
- false, /* not chunked */
- true /* merged */));
+ net_log_.AddEvent(NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST_BODY,
+ base::Bind(&NetLogSendRequestBodyCallback,
+ request_->upload_data_stream->size(),
+ false, /* not chunked */
+ true /* merged */));
}
if (!did_merge) {
@@ -333,6 +332,7 @@ int HttpStreamParser::ReadResponseHeaders(const CompletionCallback& callback) {
DCHECK(callback_.is_null());
DCHECK(!callback.is_null());
DCHECK_EQ(0, read_buf_unused_offset_);
+ DCHECK(SendRequestBuffersEmpty());
// This function can be called with io_state_ == STATE_DONE if the
// connection is closed after seeing just a 1xx response code.
@@ -369,6 +369,7 @@ int HttpStreamParser::ReadResponseBody(IOBuffer* buf, int buf_len,
DCHECK(callback_.is_null());
DCHECK(!callback.is_null());
DCHECK_LE(buf_len, kMaxBufSize);
+ DCHECK(SendRequestBuffersEmpty());
// Added to investigate crbug.com/499663.
CHECK(buf);
@@ -409,29 +410,37 @@ int HttpStreamParser::DoLoop(int result) {
case STATE_SEND_HEADERS:
DCHECK_EQ(OK, result);
result = DoSendHeaders();
+ DCHECK_NE(STATE_NONE, io_state_);
break;
case STATE_SEND_HEADERS_COMPLETE:
result = DoSendHeadersComplete(result);
+ DCHECK_NE(STATE_NONE, io_state_);
break;
case STATE_SEND_BODY:
DCHECK_EQ(OK, result);
result = DoSendBody();
+ DCHECK_NE(STATE_NONE, io_state_);
break;
case STATE_SEND_BODY_COMPLETE:
result = DoSendBodyComplete(result);
+ DCHECK_NE(STATE_NONE, io_state_);
break;
case STATE_SEND_REQUEST_READ_BODY_COMPLETE:
result = DoSendRequestReadBodyComplete(result);
+ DCHECK_NE(STATE_NONE, io_state_);
+ break;
+ case STATE_SEND_REQUEST_COMPLETE:
+ result = DoSendRequestComplete(result);
break;
case STATE_READ_HEADERS:
- net_log_.BeginEvent(NetLog::TYPE_HTTP_STREAM_PARSER_READ_HEADERS);
+ net_log_.BeginEvent(NetLogEventType::HTTP_STREAM_PARSER_READ_HEADERS);
DCHECK_GE(result, 0);
result = DoReadHeaders();
break;
case STATE_READ_HEADERS_COMPLETE:
result = DoReadHeadersComplete(result);
net_log_.EndEventWithNetErrorCode(
- NetLog::TYPE_HTTP_STREAM_PARSER_READ_HEADERS, result);
+ NetLogEventType::HTTP_STREAM_PARSER_READ_HEADERS, result);
break;
case STATE_READ_BODY:
DCHECK_GE(result, 0);
@@ -475,6 +484,7 @@ int HttpStreamParser::DoSendHeadersComplete(int result) {
// the headers were sent, but not all of the body way, and |result| is
// an error that this should try reading after, stash the error for now and
// act like the request was successfully sent.
+ io_state_ = STATE_SEND_REQUEST_COMPLETE;
if (request_headers_->BytesConsumed() >= request_headers_length_ &&
ShouldTryReadingOnUploadError(result)) {
upload_error_ = result;
@@ -495,17 +505,17 @@ int HttpStreamParser::DoSendHeadersComplete(int result) {
// !IsEOF() indicates that the body wasn't merged.
(request_->upload_data_stream->size() > 0 &&
!request_->upload_data_stream->IsEOF()))) {
- net_log_.AddEvent(
- NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_BODY,
- base::Bind(&NetLogSendRequestBodyCallback,
- request_->upload_data_stream->size(),
- request_->upload_data_stream->is_chunked(),
- false /* not merged */));
+ net_log_.AddEvent(NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST_BODY,
+ base::Bind(&NetLogSendRequestBodyCallback,
+ request_->upload_data_stream->size(),
+ request_->upload_data_stream->is_chunked(),
+ false /* not merged */));
io_state_ = STATE_SEND_BODY;
return OK;
}
// Finished sending the request.
+ io_state_ = STATE_SEND_REQUEST_COMPLETE;
return OK;
}
@@ -520,6 +530,7 @@ int HttpStreamParser::DoSendBody() {
if (request_->upload_data_stream->is_chunked() && sent_last_chunk_) {
// Finished sending the request.
+ io_state_ = STATE_SEND_REQUEST_COMPLETE;
return OK;
}
@@ -534,6 +545,7 @@ int HttpStreamParser::DoSendBodyComplete(int result) {
if (result < 0) {
// If |result| is an error that this should try reading after, stash the
// error for now and act like the request was successfully sent.
+ io_state_ = STATE_SEND_REQUEST_COMPLETE;
if (ShouldTryReadingOnUploadError(result)) {
upload_error_ = result;
return OK;
@@ -551,8 +563,10 @@ int HttpStreamParser::DoSendBodyComplete(int result) {
int HttpStreamParser::DoSendRequestReadBodyComplete(int result) {
// |result| is the result of read from the request body from the last call to
// DoSendBody().
- if (result < 0)
+ if (result < 0) {
+ io_state_ = STATE_SEND_REQUEST_COMPLETE;
return result;
+ }
// Chunked data needs to be encoded.
if (request_->upload_data_stream->is_chunked()) {
@@ -574,6 +588,7 @@ int HttpStreamParser::DoSendRequestReadBodyComplete(int result) {
DCHECK(request_->upload_data_stream->IsEOF());
DCHECK(!request_->upload_data_stream->is_chunked());
// Finished sending the request.
+ io_state_ = STATE_SEND_REQUEST_COMPLETE;
} else if (result > 0) {
request_body_send_buf_->DidAppend(result);
result = 0;
@@ -582,6 +597,15 @@ int HttpStreamParser::DoSendRequestReadBodyComplete(int result) {
return result;
}
+int HttpStreamParser::DoSendRequestComplete(int result) {
+ DCHECK_NE(result, ERR_IO_PENDING);
+ request_headers_ = nullptr;
+ request_body_send_buf_ = nullptr;
+ request_body_read_buf_ = nullptr;
+
+ return result;
+}
+
int HttpStreamParser::DoReadHeaders() {
io_state_ = STATE_READ_HEADERS_COMPLETE;
@@ -972,7 +996,20 @@ int HttpStreamParser::ParseResponseHeaders(int end_offset) {
std::string(read_buf_->StartOfBuffer(), raw_headers.find('\0')));
headers = new HttpResponseHeaders(raw_headers);
} else {
- // Enough data was read -- there is no status line.
+ // Enough data was read -- there is no status line, so this is HTTP/0.9, or
+ // the server is broken / doesn't speak HTTP.
+
+ // If the port is not the default for the scheme, assume it's not a real
+ // HTTP/0.9 response, and fail the request.
+ // TODO(crbug.com/624462): Further restrict the cases in which we allow
+ // HTTP/0.9.
+ std::string scheme(request_->url.scheme());
+ if (!http_09_on_non_default_ports_enabled_ &&
+ url::DefaultPortForScheme(scheme.c_str(), scheme.length()) !=
+ request_->url.EffectiveIntPort()) {
+ return ERR_INVALID_HTTP_RESPONSE;
+ }
+
headers = new HttpResponseHeaders(std::string("HTTP/0.9 200 OK"));
if (request_->url.SchemeIsCryptographic()) {
@@ -1008,9 +1045,8 @@ int HttpStreamParser::ParseResponseHeaders(int end_offset) {
response_->connection_info = HttpResponseInfo::CONNECTION_INFO_HTTP1_1;
}
response_->vary_data.Init(*request_, *response_->headers);
- DVLOG(1) << __FUNCTION__ << "()"
- << " content_length = \"" << response_->headers->GetContentLength()
- << "\n\""
+ DVLOG(1) << __func__ << "() content_length = \""
+ << response_->headers->GetContentLength() << "\n\""
<< " headers = \"" << GetResponseHeaderLines(*response_->headers)
<< "\"";
return OK;
@@ -1065,14 +1101,6 @@ void HttpStreamParser::CalculateResponseBodySize() {
}
}
-UploadProgress HttpStreamParser::GetUploadProgress() const {
- if (!request_->upload_data_stream)
- return UploadProgress();
-
- return UploadProgress(request_->upload_data_stream->position(),
- request_->upload_data_stream->size());
-}
-
bool HttpStreamParser::IsResponseBodyComplete() const {
if (chunked_decoder_.get())
return chunked_decoder_->reached_eof();
@@ -1137,15 +1165,16 @@ void HttpStreamParser::GetSSLCertRequestInfo(
}
}
-Error HttpStreamParser::GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) {
+Error HttpStreamParser::GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) {
if (!request_->url.SchemeIsCryptographic() || !connection_->socket()) {
NOTREACHED();
return ERR_FAILED;
}
SSLClientSocket* ssl_socket =
static_cast<SSLClientSocket*>(connection_->socket());
- return ssl_socket->GetSignedEKMForTokenBinding(key, out);
+ return ssl_socket->GetTokenBindingSignature(key, tb_type, out);
}
int HttpStreamParser::EncodeChunk(const base::StringPiece& payload,
@@ -1194,4 +1223,9 @@ void HttpStreamParser::ValidateStatusLine(const std::string& status_line) {
HttpStatusLineValidator::STATUS_LINE_MAX);
}
+bool HttpStreamParser::SendRequestBuffersEmpty() {
+ return request_headers_ == nullptr && request_body_send_buf_ == nullptr &&
+ request_body_send_buf_ == nullptr;
+}
+
} // namespace net
diff --git a/chromium/net/http/http_stream_parser.h b/chromium/net/http/http_stream_parser.h
index 3a4258ee9f3..4d30bc427f1 100644
--- a/chromium/net/http/http_stream_parser.h
+++ b/chromium/net/http/http_stream_parser.h
@@ -19,8 +19,8 @@
#include "net/base/completion_callback.h"
#include "net/base/net_errors.h"
#include "net/base/net_export.h"
-#include "net/base/upload_progress.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
+#include "net/ssl/token_binding.h"
namespace net {
@@ -47,9 +47,17 @@ class NET_EXPORT_PRIVATE HttpStreamParser {
HttpStreamParser(ClientSocketHandle* connection,
const HttpRequestInfo* request,
GrowableIOBuffer* read_buffer,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
virtual ~HttpStreamParser();
+ // Sets whether or not HTTP/0.9 is only allowed on default ports. It's not
+ // allowed, by default.
+ void set_http_09_on_non_default_ports_enabled(
+ bool http_09_on_non_default_ports_enabled) {
+ http_09_on_non_default_ports_enabled_ =
+ http_09_on_non_default_ports_enabled;
+ }
+
// These functions implement the interface described in HttpStream with
// some additional functionality
int SendRequest(const std::string& request_line,
@@ -64,10 +72,6 @@ class NET_EXPORT_PRIVATE HttpStreamParser {
void Close(bool not_reusable);
- // Returns the progress of uploading. When data is chunked, size is set to
- // zero, but position will not be.
- UploadProgress GetUploadProgress() const;
-
bool IsResponseBodyComplete() const;
bool CanFindEndOfResponse() const;
@@ -97,8 +101,9 @@ class NET_EXPORT_PRIVATE HttpStreamParser {
void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out);
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out);
// Encodes the given |payload| in the chunked format to |output|.
// Returns the number of bytes written to |output|. |output_size| should
@@ -135,6 +140,7 @@ class NET_EXPORT_PRIVATE HttpStreamParser {
STATE_SEND_BODY,
STATE_SEND_BODY_COMPLETE,
STATE_SEND_REQUEST_READ_BODY_COMPLETE,
+ STATE_SEND_REQUEST_COMPLETE,
STATE_READ_HEADERS,
STATE_READ_HEADERS_COMPLETE,
STATE_READ_BODY,
@@ -167,6 +173,7 @@ class NET_EXPORT_PRIVATE HttpStreamParser {
int DoSendBody();
int DoSendBodyComplete(int result);
int DoSendRequestReadBodyComplete(int result);
+ int DoSendRequestComplete(int result);
int DoReadHeaders();
int DoReadHeadersComplete(int result);
int DoReadBody();
@@ -191,6 +198,9 @@ class NET_EXPORT_PRIVATE HttpStreamParser {
// Uploads statistics about status line compliance with RFC 7230.
void ValidateStatusLine(const std::string& status_line);
+ // Check if buffers used to send the request are empty.
+ bool SendRequestBuffersEmpty();
+
// Next state of the request, when the current one completes.
State io_state_;
@@ -204,6 +214,9 @@ class NET_EXPORT_PRIVATE HttpStreamParser {
// |request_headers_| if the body was merged with the headers.
int request_headers_length_;
+ // True if HTTP/0.9 should be permitted on non-default ports.
+ bool http_09_on_non_default_ports_enabled_;
+
// Temporary buffer for reading.
scoped_refptr<GrowableIOBuffer> read_buf_;
@@ -260,7 +273,7 @@ class NET_EXPORT_PRIVATE HttpStreamParser {
// The underlying socket.
ClientSocketHandle* const connection_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
// Callback to be used when doing IO.
CompletionCallback io_callback_;
diff --git a/chromium/net/http/http_stream_parser_fuzzer.cc b/chromium/net/http/http_stream_parser_fuzzer.cc
index 421aaac4c47..f31d0edeacc 100644
--- a/chromium/net/http/http_stream_parser_fuzzer.cc
+++ b/chromium/net/http/http_stream_parser_fuzzer.cc
@@ -15,14 +15,13 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "net/base/fuzzed_data_provider.h"
+#include "base/test/fuzzed_data_provider.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_info.h"
-#include "net/log/net_log.h"
#include "net/log/test_net_log.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/fuzzed_socket.h"
@@ -34,7 +33,7 @@
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
net::TestCompletionCallback callback;
net::BoundTestNetLog bound_test_net_log;
- net::FuzzedDataProvider data_provider(data, size);
+ base::FuzzedDataProvider data_provider(data, size);
std::unique_ptr<net::FuzzedSocket> fuzzed_socket(new net::FuzzedSocket(
&data_provider, bound_test_net_log.bound().net_log()));
CHECK_EQ(net::OK, fuzzed_socket->Connect(callback.callback()));
diff --git a/chromium/net/http/http_stream_parser_unittest.cc b/chromium/net/http/http_stream_parser_unittest.cc
index 8a1fc9acf73..030adffdd5d 100644
--- a/chromium/net/http/http_stream_parser_unittest.cc
+++ b/chromium/net/http/http_stream_parser_unittest.cc
@@ -34,9 +34,14 @@
#include "net/http/http_response_info.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/socket_test_util.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -56,7 +61,7 @@ std::unique_ptr<ClientSocketHandle> CreateConnectedSocketHandle(
new MockTCPClientSocket(net::AddressList(), nullptr, data));
TestCompletionCallback callback;
- EXPECT_EQ(OK, socket->Connect(callback.callback()));
+ EXPECT_THAT(socket->Connect(callback.callback()), IsOk());
std::unique_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
socket_handle->SetSocket(std::move(socket));
@@ -74,7 +79,7 @@ class ReadErrorUploadDataStream : public UploadDataStream {
void CompleteRead() { UploadDataStream::OnReadCompleted(ERR_FAILED); }
// UploadDataStream implementation:
- int InitInternal() override { return OK; }
+ int InitInternal(const NetLogWithSource& net_log) override { return OK; }
int ReadInternal(IOBuffer* buf, int buf_len) override {
if (async_ == FailureMode::ASYNC) {
@@ -107,7 +112,20 @@ TEST(HttpStreamParser, DataReadErrorSynchronous) {
ReadErrorUploadDataStream upload_data_stream(
ReadErrorUploadDataStream::FailureMode::SYNC);
- ASSERT_EQ(OK, upload_data_stream.Init(TestCompletionCallback().callback()));
+
+ // Test upload progress before init.
+ UploadProgress progress = upload_data_stream.GetUploadProgress();
+ EXPECT_EQ(0u, progress.size());
+ EXPECT_EQ(0u, progress.position());
+
+ ASSERT_THAT(upload_data_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
+
+ // Test upload progress after init.
+ progress = upload_data_stream.GetUploadProgress();
+ EXPECT_EQ(0u, progress.size());
+ EXPECT_EQ(0u, progress.position());
HttpRequestInfo request;
request.method = "POST";
@@ -116,7 +134,7 @@ TEST(HttpStreamParser, DataReadErrorSynchronous) {
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
HttpStreamParser parser(socket_handle.get(), &request, read_buffer.get(),
- BoundNetLog());
+ NetLogWithSource());
HttpRequestHeaders headers;
headers.SetHeader("Content-Length", "12");
@@ -125,7 +143,11 @@ TEST(HttpStreamParser, DataReadErrorSynchronous) {
TestCompletionCallback callback;
int result = parser.SendRequest("POST / HTTP/1.1\r\n", headers, &response,
callback.callback());
- EXPECT_EQ(ERR_FAILED, callback.GetResult(result));
+ EXPECT_THAT(callback.GetResult(result), IsError(ERR_FAILED));
+
+ progress = upload_data_stream.GetUploadProgress();
+ EXPECT_EQ(0u, progress.size());
+ EXPECT_EQ(0u, progress.position());
EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
}
@@ -142,7 +164,9 @@ TEST(HttpStreamParser, DataReadErrorAsynchronous) {
ReadErrorUploadDataStream upload_data_stream(
ReadErrorUploadDataStream::FailureMode::ASYNC);
- ASSERT_EQ(OK, upload_data_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_data_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
HttpRequestInfo request;
request.method = "POST";
@@ -151,7 +175,7 @@ TEST(HttpStreamParser, DataReadErrorAsynchronous) {
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
HttpStreamParser parser(socket_handle.get(), &request, read_buffer.get(),
- BoundNetLog());
+ NetLogWithSource());
HttpRequestHeaders headers;
headers.SetHeader("Content-Length", "12");
@@ -160,12 +184,98 @@ TEST(HttpStreamParser, DataReadErrorAsynchronous) {
TestCompletionCallback callback;
int result = parser.SendRequest("POST / HTTP/1.1\r\n", headers, &response,
callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+
+ UploadProgress progress = upload_data_stream.GetUploadProgress();
+ EXPECT_EQ(0u, progress.size());
+ EXPECT_EQ(0u, progress.position());
+
+ EXPECT_THAT(callback.GetResult(result), IsError(ERR_FAILED));
- EXPECT_EQ(ERR_FAILED, callback.GetResult(result));
EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
}
+class InitAsyncUploadDataStream : public ChunkedUploadDataStream {
+ public:
+ explicit InitAsyncUploadDataStream(int64_t identifier)
+ : ChunkedUploadDataStream(identifier), weak_factory_(this) {}
+
+ private:
+ void CompleteInit() { UploadDataStream::OnInitCompleted(OK); }
+
+ int InitInternal(const NetLogWithSource& net_log) override {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&InitAsyncUploadDataStream::CompleteInit,
+ weak_factory_.GetWeakPtr()));
+ return ERR_IO_PENDING;
+ }
+
+ base::WeakPtrFactory<InitAsyncUploadDataStream> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(InitAsyncUploadDataStream);
+};
+
+TEST(HttpStreamParser, InitAsynchronousUploadDataStream) {
+ InitAsyncUploadDataStream upload_data_stream(0);
+
+ TestCompletionCallback callback;
+ int result = upload_data_stream.Init(callback.callback(), NetLogWithSource());
+ ASSERT_THAT(result, IsError(ERR_IO_PENDING));
+
+ // Should be empty progress while initialization is in progress.
+ UploadProgress progress = upload_data_stream.GetUploadProgress();
+ EXPECT_EQ(0u, progress.size());
+ EXPECT_EQ(0u, progress.position());
+ EXPECT_THAT(callback.GetResult(result), IsOk());
+
+ // Initialization complete.
+ progress = upload_data_stream.GetUploadProgress();
+ EXPECT_EQ(0u, progress.size());
+ EXPECT_EQ(0u, progress.position());
+
+ HttpRequestInfo request;
+ request.method = "POST";
+ request.url = GURL("http://localhost");
+ request.upload_data_stream = &upload_data_stream;
+
+ static const char kChunk[] = "Chunk 1";
+ MockWrite writes[] = {
+ MockWrite(ASYNC, 0, "POST / HTTP/1.1\r\n"),
+ MockWrite(ASYNC, 1, "Transfer-Encoding: chunked\r\n\r\n"),
+ MockWrite(ASYNC, 2, "7\r\nChunk 1\r\n"),
+ };
+
+ SequencedSocketData data(nullptr, 0, writes, arraysize(writes));
+ std::unique_ptr<ClientSocketHandle> socket_handle =
+ CreateConnectedSocketHandle(&data);
+
+ scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
+ HttpStreamParser parser(socket_handle.get(), &request, read_buffer.get(),
+ NetLogWithSource());
+
+ HttpRequestHeaders headers;
+ headers.SetHeader("Transfer-Encoding", "chunked");
+
+ HttpResponseInfo response;
+ TestCompletionCallback callback1;
+ int result1 = parser.SendRequest("POST / HTTP/1.1\r\n", headers, &response,
+ callback1.callback());
+ EXPECT_EQ(ERR_IO_PENDING, result1);
+ base::RunLoop().RunUntilIdle();
+ upload_data_stream.AppendData(kChunk, arraysize(kChunk) - 1, true);
+
+ // Check progress after read completes.
+ progress = upload_data_stream.GetUploadProgress();
+ EXPECT_EQ(0u, progress.size());
+ EXPECT_EQ(7u, progress.position());
+
+ // Check progress after reset.
+ upload_data_stream.Reset();
+ progress = upload_data_stream.GetUploadProgress();
+ EXPECT_EQ(0u, progress.size());
+ EXPECT_EQ(0u, progress.position());
+}
+
// The empty payload is how the last chunk is encoded.
TEST(HttpStreamParser, EncodeChunk_EmptyPayload) {
char output[kOutputSize];
@@ -221,7 +331,7 @@ TEST(HttpStreamParser, EncodeChunk_TooLargePayload) {
const std::string kPayload(kMaxPayloadSize + 1, '\xff');
const int num_bytes_written =
HttpStreamParser::EncodeChunk(kPayload, output, sizeof(output));
- ASSERT_EQ(ERR_INVALID_ARGUMENT, num_bytes_written);
+ ASSERT_THAT(num_bytes_written, IsError(ERR_INVALID_ARGUMENT));
}
TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_NoBody) {
@@ -232,9 +342,10 @@ TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_NoBody) {
TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_EmptyBody) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- std::unique_ptr<UploadDataStream> body(base::WrapUnique(
- new ElementsUploadDataStream(std::move(element_readers), 0)));
- ASSERT_EQ(OK, body->Init(CompletionCallback()));
+ std::unique_ptr<UploadDataStream> body(
+ base::MakeUnique<ElementsUploadDataStream>(std::move(element_readers),
+ 0));
+ ASSERT_THAT(body->Init(CompletionCallback(), NetLogWithSource()), IsOk());
// Shouldn't be merged if upload data is empty.
ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
"some header", body.get()));
@@ -244,7 +355,9 @@ TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_ChunkedBody) {
const std::string payload = "123";
std::unique_ptr<ChunkedUploadDataStream> body(new ChunkedUploadDataStream(0));
body->AppendData(payload.data(), payload.size(), true);
- ASSERT_EQ(OK, body->Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(
+ body->Init(TestCompletionCallback().callback(), NetLogWithSource()),
+ IsOk());
// Shouldn't be merged if upload data carries chunked data.
ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
"some header", body.get()));
@@ -255,20 +368,22 @@ TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_FileBody) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath temp_file_path;
- ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &temp_file_path));
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir.GetPath(), &temp_file_path));
{
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(base::WrapUnique(
- new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
- temp_file_path, 0, 0, base::Time())));
+ element_readers.push_back(base::MakeUnique<UploadFileElementReader>(
+ base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0, 0,
+ base::Time()));
std::unique_ptr<UploadDataStream> body(
new ElementsUploadDataStream(std::move(element_readers), 0));
TestCompletionCallback callback;
- ASSERT_EQ(ERR_IO_PENDING, body->Init(callback.callback()));
- ASSERT_EQ(OK, callback.WaitForResult());
+ ASSERT_THAT(body->Init(callback.callback(), NetLogWithSource()),
+ IsError(ERR_IO_PENDING));
+ ASSERT_THAT(callback.WaitForResult(), IsOk());
// Shouldn't be merged if upload data carries a file, as it's not in-memory.
ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
"some header", body.get()));
@@ -281,12 +396,12 @@ TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_FileBody) {
TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_SmallBodyInMemory) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
const std::string payload = "123";
- element_readers.push_back(base::WrapUnique(
- new UploadBytesElementReader(payload.data(), payload.size())));
+ element_readers.push_back(base::MakeUnique<UploadBytesElementReader>(
+ payload.data(), payload.size()));
std::unique_ptr<UploadDataStream> body(
new ElementsUploadDataStream(std::move(element_readers), 0));
- ASSERT_EQ(OK, body->Init(CompletionCallback()));
+ ASSERT_THAT(body->Init(CompletionCallback(), NetLogWithSource()), IsOk());
// Yes, should be merged if the in-memory body is small here.
ASSERT_TRUE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
"some header", body.get()));
@@ -295,12 +410,12 @@ TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_SmallBodyInMemory) {
TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_LargeBodyInMemory) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
const std::string payload(10000, 'a'); // 'a' x 10000.
- element_readers.push_back(base::WrapUnique(
- new UploadBytesElementReader(payload.data(), payload.size())));
+ element_readers.push_back(base::MakeUnique<UploadBytesElementReader>(
+ payload.data(), payload.size()));
std::unique_ptr<UploadDataStream> body(
new ElementsUploadDataStream(std::move(element_readers), 0));
- ASSERT_EQ(OK, body->Init(CompletionCallback()));
+ ASSERT_THAT(body->Init(CompletionCallback(), NetLogWithSource()), IsOk());
// Shouldn't be merged if the in-memory body is large here.
ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
"some header", body.get()));
@@ -321,7 +436,7 @@ TEST(HttpStreamParser, SentBytesNoHeaders) {
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
HttpStreamParser parser(socket_handle.get(), &request, read_buffer.get(),
- BoundNetLog());
+ NetLogWithSource());
HttpResponseInfo response;
TestCompletionCallback callback;
@@ -349,7 +464,7 @@ TEST(HttpStreamParser, SentBytesWithHeaders) {
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
HttpStreamParser parser(socket_handle.get(), &request, read_buffer.get(),
- BoundNetLog());
+ NetLogWithSource());
HttpRequestHeaders headers;
headers.SetHeader("Host", "localhost");
@@ -380,7 +495,7 @@ TEST(HttpStreamParser, SentBytesWithHeadersMultiWrite) {
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
HttpStreamParser parser(socket_handle.get(), &request, read_buffer.get(),
- BoundNetLog());
+ NetLogWithSource());
HttpRequestHeaders headers;
headers.SetHeader("Host", "localhost");
@@ -412,7 +527,7 @@ TEST(HttpStreamParser, SentBytesWithErrorWritingHeaders) {
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
HttpStreamParser parser(socket_handle.get(), &request, read_buffer.get(),
- BoundNetLog());
+ NetLogWithSource());
HttpRequestHeaders headers;
headers.SetHeader("Host", "localhost");
@@ -440,9 +555,11 @@ TEST(HttpStreamParser, SentBytesPost) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
element_readers.push_back(
- base::WrapUnique(new UploadBytesElementReader("hello world!", 12)));
+ base::MakeUnique<UploadBytesElementReader>("hello world!", 12));
ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- ASSERT_EQ(OK, upload_data_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_data_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
HttpRequestInfo request;
request.method = "POST";
@@ -451,7 +568,7 @@ TEST(HttpStreamParser, SentBytesPost) {
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
HttpStreamParser parser(socket_handle.get(), &request, read_buffer.get(),
- BoundNetLog());
+ NetLogWithSource());
HttpRequestHeaders headers;
headers.SetHeader("Content-Length", "12");
@@ -462,6 +579,10 @@ TEST(HttpStreamParser, SentBytesPost) {
callback.callback()));
EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
+
+ UploadProgress progress = upload_data_stream.GetUploadProgress();
+ EXPECT_EQ(12u, progress.size());
+ EXPECT_EQ(12u, progress.position());
}
TEST(HttpStreamParser, SentBytesChunkedPostError) {
@@ -479,7 +600,9 @@ TEST(HttpStreamParser, SentBytesChunkedPostError) {
CreateConnectedSocketHandle(&data);
ChunkedUploadDataStream upload_data_stream(0);
- ASSERT_EQ(OK, upload_data_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_data_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
HttpRequestInfo request;
request.method = "POST";
@@ -488,7 +611,7 @@ TEST(HttpStreamParser, SentBytesChunkedPostError) {
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
HttpStreamParser parser(socket_handle.get(), &request, read_buffer.get(),
- BoundNetLog());
+ NetLogWithSource());
HttpRequestHeaders headers;
headers.SetHeader("Transfer-Encoding", "chunked");
@@ -504,9 +627,13 @@ TEST(HttpStreamParser, SentBytesChunkedPostError) {
base::RunLoop().RunUntilIdle();
// This write should fail.
upload_data_stream.AppendData(kChunk, arraysize(kChunk) - 1, false);
- EXPECT_EQ(ERR_FAILED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_FAILED));
EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)), parser.sent_bytes());
+
+ UploadProgress progress = upload_data_stream.GetUploadProgress();
+ EXPECT_EQ(0u, progress.size());
+ EXPECT_EQ(14u, progress.position());
}
// Test to ensure the HttpStreamParser state machine does not get confused
@@ -535,7 +662,9 @@ TEST(HttpStreamParser, AsyncSingleChunkAndAsyncSocket) {
};
ChunkedUploadDataStream upload_stream(0);
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
std::unique_ptr<ClientSocketHandle> socket_handle =
@@ -548,7 +677,7 @@ TEST(HttpStreamParser, AsyncSingleChunkAndAsyncSocket) {
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(),
- BoundNetLog());
+ NetLogWithSource());
HttpRequestHeaders request_headers;
request_headers.SetHeader("Transfer-Encoding", "chunked");
@@ -567,11 +696,12 @@ TEST(HttpStreamParser, AsyncSingleChunkAndAsyncSocket) {
// Now append the only chunk and wait for the callback.
upload_stream.AppendData(kChunk, arraysize(kChunk) - 1, true);
- ASSERT_EQ(OK, callback.WaitForResult());
+ ASSERT_THAT(callback.WaitForResult(), IsOk());
// Attempt to read the response status and the response headers.
- ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
- ASSERT_EQ(OK, callback.WaitForResult());
+ ASSERT_THAT(parser.ReadResponseHeaders(callback.callback()),
+ IsError(ERR_IO_PENDING));
+ ASSERT_THAT(callback.WaitForResult(), IsOk());
// Finally, attempt to read the response body.
scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
@@ -610,7 +740,9 @@ TEST(HttpStreamParser, SyncSingleChunkAndAsyncSocket) {
};
ChunkedUploadDataStream upload_stream(0);
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
// Append the only chunk.
upload_stream.AppendData(kChunk, arraysize(kChunk) - 1, true);
@@ -625,7 +757,7 @@ TEST(HttpStreamParser, SyncSingleChunkAndAsyncSocket) {
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(),
- BoundNetLog());
+ NetLogWithSource());
HttpRequestHeaders request_headers;
request_headers.SetHeader("Transfer-Encoding", "chunked");
@@ -637,11 +769,12 @@ TEST(HttpStreamParser, SyncSingleChunkAndAsyncSocket) {
ASSERT_EQ(ERR_IO_PENDING,
parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
&response_info, callback.callback()));
- ASSERT_EQ(OK, callback.WaitForResult());
+ ASSERT_THAT(callback.WaitForResult(), IsOk());
// Attempt to read the response status and the response headers.
- ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
- ASSERT_EQ(OK, callback.WaitForResult());
+ ASSERT_THAT(parser.ReadResponseHeaders(callback.callback()),
+ IsError(ERR_IO_PENDING));
+ ASSERT_THAT(callback.WaitForResult(), IsOk());
// Finally, attempt to read the response body.
scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
@@ -689,7 +822,9 @@ TEST(HttpStreamParser, AsyncChunkAndAsyncSocketWithMultipleChunks) {
ChunkedUploadDataStream upload_stream(0);
upload_stream.AppendData(kChunk1, arraysize(kChunk1) - 1, false);
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
std::unique_ptr<ClientSocketHandle> socket_handle =
@@ -701,8 +836,8 @@ TEST(HttpStreamParser, AsyncChunkAndAsyncSocketWithMultipleChunks) {
request_info.upload_data_stream = &upload_stream;
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
- HttpStreamParser parser(
- socket_handle.get(), &request_info, read_buffer.get(), BoundNetLog());
+ HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(),
+ NetLogWithSource());
HttpRequestHeaders request_headers;
request_headers.SetHeader("Transfer-Encoding", "chunked");
@@ -730,11 +865,12 @@ TEST(HttpStreamParser, AsyncChunkAndAsyncSocketWithMultipleChunks) {
ASSERT_FALSE(callback.have_result());
// Wait for writes to complete.
- ASSERT_EQ(OK, callback.WaitForResult());
+ ASSERT_THAT(callback.WaitForResult(), IsOk());
// Attempt to read the response status and the response headers.
- ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
- ASSERT_EQ(OK, callback.WaitForResult());
+ ASSERT_THAT(parser.ReadResponseHeaders(callback.callback()),
+ IsError(ERR_IO_PENDING));
+ ASSERT_THAT(callback.WaitForResult(), IsOk());
// Finally, attempt to read the response body.
scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
@@ -770,7 +906,9 @@ TEST(HttpStreamParser, AsyncEmptyChunkedUpload) {
};
ChunkedUploadDataStream upload_stream(0);
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
std::unique_ptr<ClientSocketHandle> socket_handle =
@@ -783,7 +921,7 @@ TEST(HttpStreamParser, AsyncEmptyChunkedUpload) {
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(),
- BoundNetLog());
+ NetLogWithSource());
HttpRequestHeaders request_headers;
request_headers.SetHeader("Transfer-Encoding", "chunked");
@@ -800,11 +938,12 @@ TEST(HttpStreamParser, AsyncEmptyChunkedUpload) {
upload_stream.AppendData(nullptr, 0, true);
ASSERT_FALSE(callback.have_result());
- ASSERT_EQ(OK, callback.WaitForResult());
+ ASSERT_THAT(callback.WaitForResult(), IsOk());
// Attempt to read the response status and the response headers.
- ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
- ASSERT_EQ(OK, callback.WaitForResult());
+ ASSERT_THAT(parser.ReadResponseHeaders(callback.callback()),
+ IsError(ERR_IO_PENDING));
+ ASSERT_THAT(callback.WaitForResult(), IsOk());
// Finally, attempt to read the response body.
scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
@@ -840,7 +979,9 @@ TEST(HttpStreamParser, SyncEmptyChunkedUpload) {
};
ChunkedUploadDataStream upload_stream(0);
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
// Append final empty chunk.
upload_stream.AppendData(nullptr, 0, true);
@@ -855,7 +996,7 @@ TEST(HttpStreamParser, SyncEmptyChunkedUpload) {
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(),
- BoundNetLog());
+ NetLogWithSource());
HttpRequestHeaders request_headers;
request_headers.SetHeader("Transfer-Encoding", "chunked");
@@ -869,11 +1010,12 @@ TEST(HttpStreamParser, SyncEmptyChunkedUpload) {
&response_info, callback.callback()));
// Complete writing the request headers and body.
- ASSERT_EQ(OK, callback.WaitForResult());
+ ASSERT_THAT(callback.WaitForResult(), IsOk());
// Attempt to read the response status and the response headers.
- ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
- ASSERT_EQ(OK, callback.WaitForResult());
+ ASSERT_THAT(parser.ReadResponseHeaders(callback.callback()),
+ IsError(ERR_IO_PENDING));
+ ASSERT_THAT(callback.WaitForResult(), IsOk());
// Finally, attempt to read the response body.
scoped_refptr<IOBuffer> body_buffer(new IOBuffer(kBodySize));
@@ -955,8 +1097,8 @@ TEST(HttpStreamParser, TruncatedHeaders) {
request_info.load_flags = LOAD_NORMAL;
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
- HttpStreamParser parser(
- socket_handle.get(), &request_info, read_buffer.get(), BoundNetLog());
+ HttpStreamParser parser(socket_handle.get(), &request_info,
+ read_buffer.get(), NetLogWithSource());
HttpRequestHeaders request_headers;
HttpResponseInfo response_info;
@@ -968,16 +1110,16 @@ TEST(HttpStreamParser, TruncatedHeaders) {
EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
parser.sent_bytes());
if (i == arraysize(reads) - 1) {
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(response_info.headers.get());
EXPECT_EQ(CountReadBytes(reads[i], 2), parser.received_bytes());
} else {
if (protocol == HTTP) {
- EXPECT_EQ(ERR_CONNECTION_CLOSED, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_CLOSED));
EXPECT_TRUE(response_info.headers.get());
EXPECT_EQ(CountReadBytes(reads[i], 2), parser.received_bytes());
} else {
- EXPECT_EQ(ERR_RESPONSE_HEADERS_TRUNCATED, rv);
+ EXPECT_THAT(rv, IsError(ERR_RESPONSE_HEADERS_TRUNCATED));
EXPECT_FALSE(response_info.headers.get());
EXPECT_EQ(0, parser.received_bytes());
}
@@ -1012,8 +1154,8 @@ TEST(HttpStreamParser, Websocket101Response) {
request_info.load_flags = LOAD_NORMAL;
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
- HttpStreamParser parser(
- socket_handle.get(), &request_info, read_buffer.get(), BoundNetLog());
+ HttpStreamParser parser(socket_handle.get(), &request_info, read_buffer.get(),
+ NetLogWithSource());
HttpRequestHeaders request_headers;
HttpResponseInfo response_info;
@@ -1021,7 +1163,7 @@ TEST(HttpStreamParser, Websocket101Response) {
ASSERT_EQ(OK, parser.SendRequest("GET / HTTP/1.1\r\n", request_headers,
&response_info, callback.callback()));
- EXPECT_EQ(OK, parser.ReadResponseHeaders(callback.callback()));
+ EXPECT_THAT(parser.ReadResponseHeaders(callback.callback()), IsOk());
ASSERT_TRUE(response_info.headers.get());
EXPECT_EQ(101, response_info.headers->response_code());
EXPECT_TRUE(response_info.headers->HasHeaderValue("Connection", "Upgrade"));
@@ -1040,11 +1182,22 @@ TEST(HttpStreamParser, Websocket101Response) {
// Helper class for constructing HttpStreamParser and running GET requests.
class SimpleGetRunner {
public:
- SimpleGetRunner() : read_buffer_(new GrowableIOBuffer), sequence_number_(0) {
+ SimpleGetRunner()
+ : url_("http://localhost"),
+ http_09_on_non_default_ports_enabled_(false),
+ read_buffer_(new GrowableIOBuffer),
+ sequence_number_(0) {
writes_.push_back(MockWrite(
SYNCHRONOUS, sequence_number_++, "GET / HTTP/1.1\r\n\r\n"));
}
+ void set_url(const GURL& url) { url_ = url; }
+ void set_http_09_on_non_default_ports_enabled(
+ bool http_09_on_non_default_ports_enabled) {
+ http_09_on_non_default_ports_enabled_ =
+ http_09_on_non_default_ports_enabled;
+ }
+
HttpStreamParser* parser() { return parser_.get(); }
GrowableIOBuffer* read_buffer() { return read_buffer_.get(); }
HttpResponseInfo* response_info() { return &response_info_; }
@@ -1069,22 +1222,28 @@ class SimpleGetRunner {
socket_handle_ = CreateConnectedSocketHandle(data_.get());
request_info_.method = "GET";
- request_info_.url = GURL("http://localhost");
+ request_info_.url = url_;
request_info_.load_flags = LOAD_NORMAL;
- parser_.reset(new HttpStreamParser(
- socket_handle_.get(), &request_info_, read_buffer(), BoundNetLog()));
+ parser_.reset(new HttpStreamParser(socket_handle_.get(), &request_info_,
+ read_buffer(), NetLogWithSource()));
+
+ parser_->set_http_09_on_non_default_ports_enabled(
+ http_09_on_non_default_ports_enabled_);
TestCompletionCallback callback;
ASSERT_EQ(OK, parser_->SendRequest("GET / HTTP/1.1\r\n", request_headers_,
&response_info_, callback.callback()));
}
- void ReadHeaders() {
+ void ReadHeadersExpectingError(Error error) {
TestCompletionCallback callback;
- EXPECT_EQ(OK, parser_->ReadResponseHeaders(callback.callback()));
+ EXPECT_THAT(parser_->ReadResponseHeaders(callback.callback()),
+ IsError(error));
}
+ void ReadHeaders() { ReadHeadersExpectingError(OK); }
+
void ReadBody(int user_buf_len, int* read_lengths) {
TestCompletionCallback callback;
scoped_refptr<IOBuffer> buffer = new IOBuffer(user_buf_len);
@@ -1101,6 +1260,9 @@ class SimpleGetRunner {
}
private:
+ GURL url_;
+ bool http_09_on_non_default_ports_enabled_;
+
HttpRequestHeaders request_headers_;
HttpResponseInfo response_info_;
HttpRequestInfo request_info_;
@@ -1113,21 +1275,82 @@ class SimpleGetRunner {
int sequence_number_;
};
-// Test that HTTP/0.9 response size is correctly calculated.
-TEST(HttpStreamParser, ReceivedBytesNoHeaders) {
+// Test that HTTP/0.9 works as expected, only on ports where it should be
+// enabled.
+TEST(HttpStreamParser, Http09PortTests) {
+ struct TestCase {
+ const char* url;
+ bool http_09_on_non_default_ports_enabled;
+
+ // Expected result when trying to read headers.
+ Error expected_header_error;
+ };
+
+ const TestCase kTestCases[] = {
+ // Default ports should work for HTTP/0.9, regardless of whether the port
+ // is explicitly specified or not.
+ {"http://foo.com/", false, OK},
+ {"http://foo.com:80/", false, OK},
+ {"https://foo.com/", false, OK},
+ {"https://foo.com:443/", false, OK},
+
+ // Non-standard ports should not support HTTP/0.9, by default.
+ {"http://foo.com:8080/", false, ERR_INVALID_HTTP_RESPONSE},
+ {"https://foo.com:8080/", false, ERR_INVALID_HTTP_RESPONSE},
+ {"http://foo.com:443/", false, ERR_INVALID_HTTP_RESPONSE},
+ {"https://foo.com:80/", false, ERR_INVALID_HTTP_RESPONSE},
+
+ // Allowing non-default ports should not break the default ones.
+ {"http://foo.com/", true, OK},
+ {"http://foo.com:80/", true, OK},
+ {"https://foo.com/", true, OK},
+ {"https://foo.com:443/", true, OK},
+
+ // Check that non-default ports works.
+ {"http://foo.com:8080/", true, OK},
+ {"https://foo.com:8080/", true, OK},
+ {"http://foo.com:443/", true, OK},
+ {"https://foo.com:80/", true, OK},
+ };
+
std::string response = "hello\r\nworld\r\n";
+ int response_size = response.size();
+ for (const auto& test_case : kTestCases) {
+ SimpleGetRunner get_runner;
+ get_runner.set_url(GURL(test_case.url));
+ get_runner.set_http_09_on_non_default_ports_enabled(
+ test_case.http_09_on_non_default_ports_enabled);
+ get_runner.AddRead(response);
+ get_runner.SetupParserAndSendRequest();
+
+ get_runner.ReadHeadersExpectingError(test_case.expected_header_error);
+ if (test_case.expected_header_error != OK)
+ continue;
+
+ ASSERT_TRUE(get_runner.response_info()->headers);
+ EXPECT_EQ("HTTP/0.9 200 OK",
+ get_runner.response_info()->headers->GetStatusLine());
+
+ EXPECT_EQ(0, get_runner.parser()->received_bytes());
+ int read_lengths[] = {response_size, 0};
+ get_runner.ReadBody(response_size, read_lengths);
+ EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
+ EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP0_9,
+ get_runner.response_info()->connection_info);
+ }
+}
+
+// Make sure that HTTP/0.9 isn't allowed in the truncated header case on a weird
+// port.
+TEST(HttpStreamParser, Http09TruncatedHeaderPortTest) {
SimpleGetRunner get_runner;
+ get_runner.set_url(GURL("http://foo.com:8080/"));
+ std::string response = "HT";
get_runner.AddRead(response);
get_runner.SetupParserAndSendRequest();
- get_runner.ReadHeaders();
- EXPECT_EQ(0, get_runner.parser()->received_bytes());
- int response_size = response.size();
- int read_lengths[] = {response_size, 0};
- get_runner.ReadBody(response_size, read_lengths);
- EXPECT_EQ(response_size, get_runner.parser()->received_bytes());
- EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP0_9,
- get_runner.response_info()->connection_info);
+
+ get_runner.ReadHeadersExpectingError(ERR_INVALID_HTTP_RESPONSE);
}
// Test basic case where there is no keep-alive or extra data from the socket,
@@ -1375,14 +1598,14 @@ TEST(HttpStreamParser, ReadAfterUnownedObjectsDestroyed) {
scoped_refptr<GrowableIOBuffer> read_buffer(new GrowableIOBuffer);
HttpStreamParser parser(socket_handle.get(), request_info.get(),
- read_buffer.get(), BoundNetLog());
+ read_buffer.get(), NetLogWithSource());
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.ReadResponseHeaders(callback.callback()));
+ ASSERT_THAT(parser.ReadResponseHeaders(callback.callback()), IsOk());
// If the object that owns the HttpStreamParser is deleted, it takes the
// objects passed to the HttpStreamParser with it.
diff --git a/chromium/net/http/http_transaction.h b/chromium/net/http/http_transaction.h
index 76fd12b7d8b..b39e6514426 100644
--- a/chromium/net/http/http_transaction.h
+++ b/chromium/net/http/http_transaction.h
@@ -19,12 +19,12 @@
namespace net {
class AuthCredentials;
-class BoundNetLog;
class HttpRequestHeaders;
struct HttpRequestInfo;
class HttpResponseInfo;
class IOBuffer;
struct LoadTimingInfo;
+class NetLogWithSource;
class ProxyInfo;
class QuicServerInfo;
class SSLPrivateKey;
@@ -66,7 +66,7 @@ class NET_EXPORT_PRIVATE HttpTransaction {
// Profiling information for the request is saved to |net_log| if non-NULL.
virtual int Start(const HttpRequestInfo* request_info,
const CompletionCallback& callback,
- const BoundNetLog& net_log) = 0;
+ const NetLogWithSource& net_log) = 0;
// Restarts the HTTP transaction, ignoring the last error. This call can
// only be made after a call to Start (or RestartIgnoringLastError) failed.
@@ -148,10 +148,6 @@ class NET_EXPORT_PRIVATE HttpTransaction {
// Returns the load state for this transaction.
virtual LoadState GetLoadState() const = 0;
- // Returns the upload progress in bytes. If there is no upload data,
- // zero will be returned. This does not include the request headers.
- virtual UploadProgress GetUploadProgress() const = 0;
-
// SetQuicServerInfo sets a object which reads and writes public information
// about a QUIC server.
virtual void SetQuicServerInfo(QuicServerInfo* quic_server_info) = 0;
diff --git a/chromium/net/http/http_transaction_test_util.cc b/chromium/net/http/http_transaction_test_util.cc
index 046691fe9cb..556033a0580 100644
--- a/chromium/net/http/http_transaction_test_util.cc
+++ b/chromium/net/http/http_transaction_test_util.cc
@@ -25,6 +25,9 @@
#include "net/http/http_request_info.h"
#include "net/http/http_response_info.h"
#include "net/http/http_transaction.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -163,7 +166,7 @@ TestTransactionConsumer::~TestTransactionConsumer() {
}
void TestTransactionConsumer::Start(const HttpRequestInfo* request,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
state_ = STARTING;
int result = trans_->Start(
request, base::Bind(&TestTransactionConsumer::OnIOComplete,
@@ -231,7 +234,7 @@ MockNetworkTransaction::MockNetworkTransaction(RequestPriority priority,
transaction_factory_(factory->AsWeakPtr()),
received_bytes_(0),
sent_bytes_(0),
- socket_log_id_(NetLog::Source::kInvalidId),
+ socket_log_id_(NetLogSource::kInvalidId),
done_reading_called_(false),
weak_factory_(this) {}
@@ -239,7 +242,7 @@ MockNetworkTransaction::~MockNetworkTransaction() {}
int MockNetworkTransaction::Start(const HttpRequestInfo* request,
const CompletionCallback& callback,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
if (request_)
return ERR_FAILED;
@@ -266,12 +269,12 @@ int MockNetworkTransaction::RestartWithAuth(
return ERR_FAILED;
HttpRequestInfo auth_request_info = *request_;
- auth_request_info.extra_headers.AddHeaderFromString("Authorization: Bar");
+ auth_request_info.extra_headers.SetHeader("Authorization", "Bar");
// Let the MockTransactionHandler worry about this: the only way for this
// test to succeed is by using an explicit handler for the transaction so
// that server behavior can be simulated.
- return StartInternal(&auth_request_info, callback, BoundNetLog());
+ return StartInternal(&auth_request_info, callback, NetLogWithSource());
}
void MockNetworkTransaction::PopulateNetErrorDetails(
@@ -352,17 +355,13 @@ LoadState MockNetworkTransaction::GetLoadState() const {
return LOAD_STATE_IDLE;
}
-UploadProgress MockNetworkTransaction::GetUploadProgress() const {
- return UploadProgress();
-}
-
void MockNetworkTransaction::SetQuicServerInfo(
QuicServerInfo* quic_server_info) {
}
bool MockNetworkTransaction::GetLoadTimingInfo(
LoadTimingInfo* load_timing_info) const {
- if (socket_log_id_ != NetLog::Source::kInvalidId) {
+ if (socket_log_id_ != NetLogSource::kInvalidId) {
// The minimal set of times for a request that gets a response, assuming it
// gets a new socket.
load_timing_info->socket_reused = false;
@@ -404,7 +403,7 @@ const int64_t MockNetworkTransaction::kTotalSentBytes = 100;
int MockNetworkTransaction::StartInternal(const HttpRequestInfo* request,
const CompletionCallback& callback,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
const MockTransaction* t = FindMockTransaction(request->url);
if (!t)
return ERR_FAILED;
diff --git a/chromium/net/http/http_transaction_test_util.h b/chromium/net/http/http_transaction_test_util.h
index 21d2b623cbb..718fe2727bc 100644
--- a/chromium/net/http/http_transaction_test_util.h
+++ b/chromium/net/http/http_transaction_test_util.h
@@ -26,7 +26,6 @@
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
-#include "net/log/net_log.h"
#include "net/socket/connection_attempts.h"
namespace net {
@@ -35,6 +34,7 @@ class HttpRequestHeaders;
class IOBuffer;
class SSLPrivateKey;
class X509Certificate;
+class NetLogWithSource;
struct HttpRequestInfo;
//-----------------------------------------------------------------------------
@@ -130,7 +130,7 @@ class TestTransactionConsumer {
HttpTransactionFactory* factory);
virtual ~TestTransactionConsumer();
- void Start(const HttpRequestInfo* request, const BoundNetLog& net_log);
+ void Start(const HttpRequestInfo* request, const NetLogWithSource& net_log);
bool is_done() const { return state_ == DONE; }
int error() const { return error_; }
@@ -185,7 +185,7 @@ class MockNetworkTransaction
int Start(const HttpRequestInfo* request,
const CompletionCallback& callback,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
int RestartIgnoringLastError(const CompletionCallback& callback) override;
@@ -217,8 +217,6 @@ class MockNetworkTransaction
LoadState GetLoadState() const override;
- UploadProgress GetUploadProgress() const override;
-
void SetQuicServerInfo(QuicServerInfo* quic_server_info) override;
bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
@@ -256,7 +254,7 @@ class MockNetworkTransaction
private:
int StartInternal(const HttpRequestInfo* request,
const CompletionCallback& callback,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
void CallbackLater(const CompletionCallback& callback, int result);
void RunCallback(const CompletionCallback& callback, int result);
@@ -275,7 +273,8 @@ class MockNetworkTransaction
int64_t sent_bytes_;
// NetLog ID of the fake / non-existent underlying socket used by the
- // connection. Requires Start() be passed a BoundNetLog with a real NetLog to
+ // connection. Requires Start() be passed a NetLogWithSource with a real
+ // NetLog to
// be initialized.
unsigned int socket_log_id_;
diff --git a/chromium/net/http/http_util.cc b/chromium/net/http/http_util.cc
index 1f1ef91d01e..aa2fdb6d66e 100644
--- a/chromium/net/http/http_util.cc
+++ b/chromium/net/http/http_util.cc
@@ -20,6 +20,19 @@
namespace net {
+namespace {
+template <typename ConstIterator>
+void TrimLWSImplementation(ConstIterator* begin, ConstIterator* end) {
+ // leading whitespace
+ while (*begin < *end && HttpUtil::IsLWS((*begin)[0]))
+ ++(*begin);
+
+ // trailing whitespace
+ while (*begin < *end && HttpUtil::IsLWS((*end)[-1]))
+ --(*end);
+}
+} // namespace
+
// Helpers --------------------------------------------------------------------
// Returns the index of the closing quote of the string, if any. |start| points
@@ -340,16 +353,19 @@ bool HttpUtil::IsSafeHeader(const std::string& name) {
}
// static
-bool HttpUtil::IsValidHeaderName(const std::string& name) {
+bool HttpUtil::IsValidHeaderName(const base::StringPiece& name) {
// Check whether the header name is RFC 2616-compliant.
return HttpUtil::IsToken(name);
}
// static
-bool HttpUtil::IsValidHeaderValue(const std::string& value) {
- // Just a sanity check: disallow NUL and CRLF.
- return value.find('\0') == std::string::npos &&
- value.find("\r\n") == std::string::npos;
+bool HttpUtil::IsValidHeaderValue(const base::StringPiece& value) {
+ // Just a sanity check: disallow NUL, CR and LF.
+ for (char c : value) {
+ if (c == '\0' || c == '\r' || c == '\n')
+ return false;
+ }
+ return true;
}
// static
@@ -410,15 +426,18 @@ bool HttpUtil::IsLWS(char c) {
return strchr(HTTP_LWS, c) != NULL;
}
+// static
void HttpUtil::TrimLWS(std::string::const_iterator* begin,
std::string::const_iterator* end) {
- // leading whitespace
- while (*begin < *end && IsLWS((*begin)[0]))
- ++(*begin);
+ TrimLWSImplementation(begin, end);
+}
- // trailing whitespace
- while (*begin < *end && IsLWS((*end)[-1]))
- --(*end);
+// static
+base::StringPiece HttpUtil::TrimLWS(const base::StringPiece& string) {
+ const char* begin = string.data();
+ const char* end = string.data() + string.size();
+ TrimLWSImplementation(&begin, &end);
+ return base::StringPiece(begin, end - begin);
}
bool HttpUtil::IsQuote(char c) {
@@ -427,23 +446,19 @@ bool HttpUtil::IsQuote(char c) {
return c == '"' || c == '\'';
}
-namespace {
-bool IsTokenChar(unsigned char c) {
- return !(c >= 0x80 || c <= 0x1F || c == 0x7F || c == '(' || c == ')' ||
- c == '<' || c == '>' || c == '@' || c == ',' || c == ';' ||
- c == ':' || c == '\\' || c == '"' || c == '/' || c == '[' ||
- c == ']' || c == '?' || c == '=' || c == '{' || c == '}' ||
- c == ' ' || c == '\t');
+bool HttpUtil::IsTokenChar(char c) {
+ return !(c >= 0x7F || c <= 0x20 || c == '(' || c == ')' || c == '<' ||
+ c == '>' || c == '@' || c == ',' || c == ';' || c == ':' ||
+ c == '\\' || c == '"' || c == '/' || c == '[' || c == ']' ||
+ c == '?' || c == '=' || c == '{' || c == '}');
}
-} // anonymous namespace
-// See RFC 2616 Sec 2.2 for the definition of |token|.
-bool HttpUtil::IsToken(std::string::const_iterator begin,
- std::string::const_iterator end) {
- if (begin == end)
+// See RFC 7230 Sec 3.2.6 for the definition of |token|.
+bool HttpUtil::IsToken(const base::StringPiece& string) {
+ if (string.empty())
return false;
- for (std::string::const_iterator iter = begin; iter != end; ++iter) {
- if (!IsTokenChar(*iter))
+ for (char c : string) {
+ if (!IsTokenChar(c))
return false;
}
return true;
@@ -892,7 +907,8 @@ bool HttpUtil::HeadersIterator::GetNext() {
continue;
TrimLWS(&name_begin_, &name_end_);
- if (!IsToken(name_begin_, name_end_))
+ DCHECK(name_begin_ < name_end_);
+ if (!IsToken(base::StringPiece(name_begin_, name_end_)))
continue; // skip malformed header
values_begin_ = colon + 1;
diff --git a/chromium/net/http/http_util.h b/chromium/net/http/http_util.h
index 77706f1afea..8658b578837 100644
--- a/chromium/net/http/http_util.h
+++ b/chromium/net/http/http_util.h
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_tokenizer.h"
#include "base/time/time.h"
#include "net/base/net_export.h"
@@ -77,11 +78,11 @@ class NET_EXPORT HttpUtil {
static bool IsSafeHeader(const std::string& name);
// Returns true if |name| is a valid HTTP header name.
- static bool IsValidHeaderName(const std::string& name);
+ static bool IsValidHeaderName(const base::StringPiece& name);
// Returns false if |value| contains NUL or CRLF. This method does not perform
// a fully RFC-2616-compliant header value validation.
- static bool IsValidHeaderValue(const std::string& value);
+ static bool IsValidHeaderValue(const base::StringPiece& value);
// Strips all header lines from |headers| whose name matches
// |headers_to_remove|. |headers_to_remove| is a list of null-terminated
@@ -108,16 +109,15 @@ class NET_EXPORT HttpUtil {
// Trim HTTP_LWS chars from the beginning and end of the string.
static void TrimLWS(std::string::const_iterator* begin,
std::string::const_iterator* end);
+ static base::StringPiece TrimLWS(const base::StringPiece& string);
// Whether the character is the start of a quotation mark.
static bool IsQuote(char c);
- // Whether the string is a valid |token| as defined in RFC 2616 Sec 2.2.
- static bool IsToken(std::string::const_iterator begin,
- std::string::const_iterator end);
- static bool IsToken(const std::string& str) {
- return IsToken(str.begin(), str.end());
- }
+ // Whether the character is a valid |tchar| as defined in RFC 7230 Sec 3.2.6.
+ static bool IsTokenChar(char c);
+ // Whether the string is a valid |token| as defined in RFC 7230 Sec 3.2.6.
+ static bool IsToken(const base::StringPiece& str);
// Whether the string is a valid |parmname| as defined in RFC 5987 Sec 3.2.1.
static bool IsParmName(std::string::const_iterator begin,
diff --git a/chromium/net/http/http_util_unittest.cc b/chromium/net/http/http_util_unittest.cc
index 7162d7a0a3c..5d443340e49 100644
--- a/chromium/net/http/http_util_unittest.cc
+++ b/chromium/net/http/http_util_unittest.cc
@@ -1367,4 +1367,45 @@ TEST(HttpUtilTest, HasValidators) {
EXPECT_TRUE(HttpUtil::HasValidators(v1_1, kEtagEmpty, kLastModifiedInvalid));
}
+TEST(HttpUtilTest, IsValidHeaderValue) {
+ const char* const invalid_values[] = {
+ "X-Requested-With: chrome${NUL}Sec-Unsafe: injected",
+ "X-Requested-With: chrome\r\nSec-Unsafe: injected",
+ "X-Requested-With: chrome\nSec-Unsafe: injected",
+ "X-Requested-With: chrome\rSec-Unsafe: injected",
+ };
+ for (const std::string& value : invalid_values) {
+ std::string replaced = value;
+ base::ReplaceSubstringsAfterOffset(&replaced, 0, "${NUL}",
+ std::string(1, '\0'));
+ EXPECT_FALSE(HttpUtil::IsValidHeaderValue(replaced)) << replaced;
+ }
+
+ // Check that all characters permitted by RFC7230 3.2.6 are allowed.
+ std::string allowed = "\t";
+ for (char c = '\x20'; c < '\x7F'; ++c) {
+ allowed.append(1, c);
+ }
+ for (int c = 0x80; c <= 0xFF; ++c) {
+ allowed.append(1, static_cast<char>(c));
+ }
+ EXPECT_TRUE(HttpUtil::IsValidHeaderValue(allowed));
+}
+
+TEST(HttpUtilTest, IsToken) {
+ EXPECT_TRUE(HttpUtil::IsToken("valid"));
+ EXPECT_TRUE(HttpUtil::IsToken("!"));
+ EXPECT_TRUE(HttpUtil::IsToken("~"));
+
+ EXPECT_FALSE(HttpUtil::IsToken(""));
+ EXPECT_FALSE(HttpUtil::IsToken(base::StringPiece()));
+ EXPECT_FALSE(HttpUtil::IsToken("hello, world"));
+ EXPECT_FALSE(HttpUtil::IsToken(" "));
+ EXPECT_FALSE(HttpUtil::IsToken(base::StringPiece("\0", 1)));
+ EXPECT_FALSE(HttpUtil::IsToken("\x01"));
+ EXPECT_FALSE(HttpUtil::IsToken("\x7F"));
+ EXPECT_FALSE(HttpUtil::IsToken("\x80"));
+ EXPECT_FALSE(HttpUtil::IsToken("\xff"));
+}
+
} // namespace net
diff --git a/chromium/net/http/mock_http_cache.cc b/chromium/net/http/mock_http_cache.cc
index 560ae9c80da..9fc8ced93ce 100644
--- a/chromium/net/http/mock_http_cache.cc
+++ b/chromium/net/http/mock_http_cache.cc
@@ -541,11 +541,11 @@ int MockBackendFactory::CreateBackend(
//-----------------------------------------------------------------------------
MockHttpCache::MockHttpCache()
- : MockHttpCache(base::WrapUnique(new MockBackendFactory())) {}
+ : MockHttpCache(base::MakeUnique<MockBackendFactory>()) {}
MockHttpCache::MockHttpCache(
std::unique_ptr<HttpCache::BackendFactory> disk_cache_factory)
- : http_cache_(base::WrapUnique(new MockNetworkLayer()),
+ : http_cache_(base::MakeUnique<MockNetworkLayer>(),
std::move(disk_cache_factory),
true) {}
diff --git a/chromium/net/http/proxy_client_socket.cc b/chromium/net/http/proxy_client_socket.cc
index ffdbec86460..453b6d94d42 100644
--- a/chromium/net/http/proxy_client_socket.cc
+++ b/chromium/net/http/proxy_client_socket.cc
@@ -54,9 +54,10 @@ void ProxyClientSocket::BuildTunnelRequest(
}
// static
-int ProxyClientSocket::HandleProxyAuthChallenge(HttpAuthController* auth,
- HttpResponseInfo* response,
- const BoundNetLog& net_log) {
+int ProxyClientSocket::HandleProxyAuthChallenge(
+ HttpAuthController* auth,
+ HttpResponseInfo* response,
+ const NetLogWithSource& net_log) {
DCHECK(response->headers.get());
int rv = auth->HandleAuthChallenge(response->headers, response->ssl_info,
false, true, net_log);
diff --git a/chromium/net/http/proxy_client_socket.h b/chromium/net/http/proxy_client_socket.h
index b240689b726..bfe49d18789 100644
--- a/chromium/net/http/proxy_client_socket.h
+++ b/chromium/net/http/proxy_client_socket.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/macros.h"
+#include "net/base/net_export.h"
#include "net/socket/ssl_client_socket.h"
#include "net/socket/stream_socket.h"
@@ -22,6 +23,7 @@ class HttpResponseInfo;
class HttpRequestHeaders;
struct HttpRequestInfo;
class HttpAuthController;
+class NetLogWithSource;
class NET_EXPORT_PRIVATE ProxyClientSocket : public StreamSocket {
public:
@@ -52,7 +54,7 @@ class NET_EXPORT_PRIVATE ProxyClientSocket : public StreamSocket {
virtual bool IsUsingSpdy() const = 0;
// Returns the protocol negotiated with the proxy.
- virtual NextProto GetProtocolNegotiated() const = 0;
+ virtual NextProto GetProxyNegotiatedProtocol() const = 0;
protected:
// The HTTP CONNECT method for establishing a tunnel connection is documented
@@ -68,7 +70,7 @@ class NET_EXPORT_PRIVATE ProxyClientSocket : public StreamSocket {
// construction/ this method should be called.
static int HandleProxyAuthChallenge(HttpAuthController* auth,
HttpResponseInfo* response,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Logs (to the log and in a histogram) a blocked CONNECT response.
static void LogBlockedTunnelResponse(int http_response_code,
diff --git a/chromium/net/http/proxy_connect_redirect_http_stream.cc b/chromium/net/http/proxy_connect_redirect_http_stream.cc
index 45d742450e5..5b8a2bcc43a 100644
--- a/chromium/net/http/proxy_connect_redirect_http_stream.cc
+++ b/chromium/net/http/proxy_connect_redirect_http_stream.cc
@@ -23,7 +23,7 @@ ProxyConnectRedirectHttpStream::~ProxyConnectRedirectHttpStream() {}
int ProxyConnectRedirectHttpStream::InitializeStream(
const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback) {
NOTREACHED();
return OK;
@@ -102,8 +102,9 @@ bool ProxyConnectRedirectHttpStream::GetRemoteEndpoint(IPEndPoint* endpoint) {
return false;
}
-Error ProxyConnectRedirectHttpStream::GetSignedEKMForTokenBinding(
+Error ProxyConnectRedirectHttpStream::GetTokenBindingSignature(
crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
std::vector<uint8_t>* out) {
NOTREACHED();
return ERR_NOT_IMPLEMENTED;
@@ -122,10 +123,6 @@ void ProxyConnectRedirectHttpStream::SetPriority(RequestPriority priority) {
// Nothing to do.
}
-UploadProgress ProxyConnectRedirectHttpStream::GetUploadProgress() const {
- return UploadProgress();
-}
-
HttpStream* ProxyConnectRedirectHttpStream::RenewStreamForAuth() {
NOTREACHED();
return NULL;
diff --git a/chromium/net/http/proxy_connect_redirect_http_stream.h b/chromium/net/http/proxy_connect_redirect_http_stream.h
index 7368e1d7cb6..74d91362463 100644
--- a/chromium/net/http/proxy_connect_redirect_http_stream.h
+++ b/chromium/net/http/proxy_connect_redirect_http_stream.h
@@ -30,7 +30,7 @@ class ProxyConnectRedirectHttpStream : public HttpStream {
int InitializeStream(const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback) override;
int SendRequest(const HttpRequestHeaders& request_headers,
HttpResponseInfo* response,
@@ -58,15 +58,15 @@ class ProxyConnectRedirectHttpStream : public HttpStream {
void GetSSLInfo(SSLInfo* ssl_info) override;
void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
bool GetRemoteEndpoint(IPEndPoint* endpoint) override;
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) override;
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) override;
void Drain(HttpNetworkSession* session) override;
void PopulateNetErrorDetails(NetErrorDetails* details) override;
// This function may be called.
void SetPriority(RequestPriority priority) override;
- UploadProgress GetUploadProgress() const override;
HttpStream* RenewStreamForAuth() override;
private:
diff --git a/chromium/net/http/transport_security_persister_unittest.cc b/chromium/net/http/transport_security_persister_unittest.cc
index 5809c92719f..c48f3c0ef03 100644
--- a/chromium/net/http/transport_security_persister_unittest.cc
+++ b/chromium/net/http/transport_security_persister_unittest.cc
@@ -13,6 +13,8 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "net/http/transport_security_state.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -28,14 +30,16 @@ class TransportSecurityPersisterTest : public testing::Test {
}
~TransportSecurityPersisterTest() override {
- base::MessageLoopForIO::current()->RunUntilIdle();
+ EXPECT_TRUE(base::MessageLoopForIO::IsCurrent());
+ base::RunLoop().RunUntilIdle();
}
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ ASSERT_TRUE(base::MessageLoopForIO::IsCurrent());
persister_.reset(new TransportSecurityPersister(
- &state_, temp_dir_.path(),
- base::MessageLoopForIO::current()->task_runner(), false));
+ &state_, temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get(),
+ false));
}
protected:
@@ -139,7 +143,7 @@ TEST_F(TransportSecurityPersisterTest, SerializeData3) {
// ImportantFileWriter, which has an asynchronous commit interval rather
// than block.) Use a different basename just for cleanliness.
base::FilePath path =
- temp_dir_.path().AppendASCII("TransportSecurityPersisterTest");
+ temp_dir_.GetPath().AppendASCII("TransportSecurityPersisterTest");
EXPECT_TRUE(base::WriteFile(path, serialized.c_str(), serialized.size()));
// Read the data back.
diff --git a/chromium/net/http/transport_security_state.cc b/chromium/net/http/transport_security_state.cc
index 5e67d4c4c2e..a3f468d9a43 100644
--- a/chromium/net/http/transport_security_state.cc
+++ b/chromium/net/http/transport_security_state.cc
@@ -69,8 +69,8 @@ struct SHA256ToHashValueComparator {
};
void RecordUMAForHPKPReportFailure(const GURL& report_uri, int net_error) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.PublicKeyPinReportSendingFailure",
- net_error);
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Net.PublicKeyPinReportSendingFailure2",
+ -net_error);
}
std::string TimeToISO8601(const base::Time& t) {
@@ -85,13 +85,13 @@ std::string TimeToISO8601(const base::Time& t) {
std::unique_ptr<base::ListValue> GetPEMEncodedChainAsList(
const net::X509Certificate* cert_chain) {
if (!cert_chain)
- return base::WrapUnique(new base::ListValue());
+ return base::MakeUnique<base::ListValue>();
std::unique_ptr<base::ListValue> result(new base::ListValue());
std::vector<std::string> pem_encoded_chain;
cert_chain->GetPEMEncodedChain(&pem_encoded_chain);
for (const std::string& cert : pem_encoded_chain)
- result->Append(base::WrapUnique(new base::StringValue(cert)));
+ result->Append(base::MakeUnique<base::StringValue>(cert));
return result;
}
@@ -637,12 +637,87 @@ bool DecodeHSTSPreload(const std::string& hostname, PreloadResult* out) {
return found;
}
+// Serializes an OCSPVerifyResult::ResponseStatus to a string enum, suitable for
+// the |response-status| field in an Expect-Staple report.
+std::string SerializeExpectStapleResponseStatus(
+ OCSPVerifyResult::ResponseStatus status) {
+ switch (status) {
+ case OCSPVerifyResult::MISSING:
+ return "MISSING";
+ case OCSPVerifyResult::PROVIDED:
+ return "PROVIDED";
+ case OCSPVerifyResult::ERROR_RESPONSE:
+ return "ERROR_RESPONSE";
+ case OCSPVerifyResult::BAD_PRODUCED_AT:
+ return "BAD_PRODUCED_AT";
+ case OCSPVerifyResult::NO_MATCHING_RESPONSE:
+ return "NO_MATCHING_RESPONSE";
+ case OCSPVerifyResult::INVALID_DATE:
+ return "INVALID_DATE";
+ case OCSPVerifyResult::PARSE_RESPONSE_ERROR:
+ return "PARSE_RESPONSE_ERROR";
+ case OCSPVerifyResult::PARSE_RESPONSE_DATA_ERROR:
+ return "PARSE_RESPONSE_DATA_ERROR";
+ }
+ return std::string();
+}
+
+// Serializes an OCSPRevocationStatus to a string enum, suitable for the
+// |cert-status| field in an Expect-Staple report.
+std::string SerializeExpectStapleRevocationStatus(
+ const OCSPRevocationStatus& status) {
+ switch (status) {
+ case OCSPRevocationStatus::GOOD:
+ return "GOOD";
+ case OCSPRevocationStatus::REVOKED:
+ return "REVOKED";
+ case OCSPRevocationStatus::UNKNOWN:
+ return "UNKNOWN";
+ }
+ return std::string();
+}
+
+bool SerializeExpectStapleReport(const HostPortPair& host_port_pair,
+ const SSLInfo& ssl_info,
+ const std::string& ocsp_response,
+ std::string* out_serialized_report) {
+ base::DictionaryValue report;
+ report.SetString("date-time", TimeToISO8601(base::Time::Now()));
+ report.SetString("hostname", host_port_pair.host());
+ report.SetInteger("port", host_port_pair.port());
+ report.SetString("response-status",
+ SerializeExpectStapleResponseStatus(
+ ssl_info.ocsp_result.response_status));
+
+ if (!ocsp_response.empty()) {
+ std::string encoded_ocsp_response;
+ base::Base64Encode(ocsp_response, &encoded_ocsp_response);
+ report.SetString("ocsp-response", encoded_ocsp_response);
+ }
+ if (ssl_info.ocsp_result.response_status == OCSPVerifyResult::PROVIDED) {
+ report.SetString("cert-status",
+ SerializeExpectStapleRevocationStatus(
+ ssl_info.ocsp_result.revocation_status));
+ }
+ if (ssl_info.is_issued_by_known_root) {
+ report.Set("served-certificate-chain",
+ GetPEMEncodedChainAsList(ssl_info.unverified_cert.get()));
+ report.Set("validated-certificate-chain",
+ GetPEMEncodedChainAsList(ssl_info.cert.get()));
+ }
+
+ if (!base::JSONWriter::Write(report, out_serialized_report))
+ return false;
+ return true;
+}
+
} // namespace
TransportSecurityState::TransportSecurityState()
: enable_static_pins_(true),
enable_static_expect_ct_(true),
- enable_static_expect_staple_(false),
+ enable_static_expect_staple_(true),
+ enable_pkp_bypass_for_local_trust_anchors_(true),
sent_reports_cache_(kMaxHPKPReportCacheEntries) {
// Static pinning is only enabled for official builds to make sure that
// others don't end up with pins that cannot be easily updated.
@@ -712,6 +787,36 @@ TransportSecurityState::PKPStatus TransportSecurityState::CheckPublicKeyPins(
return pin_validity;
}
+void TransportSecurityState::CheckExpectStaple(
+ const HostPortPair& host_port_pair,
+ const SSLInfo& ssl_info,
+ const std::string& ocsp_response) {
+ DCHECK(CalledOnValidThread());
+ if (!enable_static_expect_staple_ || !report_sender_)
+ return;
+
+ // Determine if the host is on the Expect-Staple preload list. If the build is
+ // not timely (i.e. the preload list is not fresh), this will fail and return
+ // false.
+ ExpectStapleState expect_staple_state;
+ if (!GetStaticExpectStapleState(host_port_pair.host(), &expect_staple_state))
+ return;
+
+ // No report needed if a stapled OCSP response was provided.
+ if (ssl_info.ocsp_result.response_status == OCSPVerifyResult::PROVIDED &&
+ ssl_info.ocsp_result.revocation_status == OCSPRevocationStatus::GOOD) {
+ return;
+ }
+
+ std::string serialized_report;
+ if (!SerializeExpectStapleReport(host_port_pair, ssl_info, ocsp_response,
+ &serialized_report)) {
+ return;
+ }
+ report_sender_->Send(expect_staple_state.report_uri,
+ "application/json; charset=utf-8", serialized_report);
+}
+
bool TransportSecurityState::HasPublicKeyPins(const std::string& host) {
PKPState dynamic_state;
if (GetDynamicPKPState(host, &dynamic_state))
@@ -863,6 +968,11 @@ void TransportSecurityState::AddHPKPInternal(const std::string& host,
EnablePKPHost(host, pkp_state);
}
+void TransportSecurityState::
+ SetEnablePublicKeyPinningBypassForLocalTrustAnchors(bool value) {
+ enable_pkp_bypass_for_local_trust_anchors_ = value;
+}
+
void TransportSecurityState::EnableSTSHost(const std::string& host,
const STSState& state) {
DCHECK(CalledOnValidThread());
@@ -927,7 +1037,7 @@ TransportSecurityState::CheckPinsAndMaybeSendReport(
return PKPStatus::OK;
// Don't report violations for certificates that chain to local roots.
- if (!is_issued_by_known_root)
+ if (!is_issued_by_known_root && enable_pkp_bypass_for_local_trust_anchors_)
return PKPStatus::BYPASSED;
if (!report_sender_ ||
@@ -962,7 +1072,8 @@ TransportSecurityState::CheckPinsAndMaybeSendReport(
base::TimeTicks::Now() +
base::TimeDelta::FromMinutes(kTimeToRememberHPKPReportsMins));
- report_sender_->Send(pkp_state.report_uri, serialized_report);
+ report_sender_->Send(pkp_state.report_uri, "application/json; charset=utf-8",
+ serialized_report);
return PKPStatus::VIOLATED;
}
@@ -1185,24 +1296,55 @@ void TransportSecurityState::ProcessExpectCTHeader(
const SSLInfo& ssl_info) {
DCHECK(CalledOnValidThread());
- if (!expect_ct_reporter_)
- return;
-
- if (value != "preload")
- return;
+ // Records the result of processing an Expect-CT header. This enum is
+ // histogrammed, so do not reorder or remove values.
+ enum ExpectCTHeaderResult {
+ // An Expect-CT header was received, but it had the wrong value.
+ EXPECT_CT_HEADER_BAD_VALUE = 0,
+ // The Expect-CT header was ignored because the build was old.
+ EXPECT_CT_HEADER_BUILD_NOT_TIMELY = 1,
+ // The Expect-CT header was ignored because the certificate did not chain to
+ // a public root.
+ EXPECT_CT_HEADER_PRIVATE_ROOT = 2,
+ // The Expect-CT header was ignored because CT compliance details were
+ // unavailable.
+ EXPECT_CT_HEADER_COMPLIANCE_DETAILS_UNAVAILABLE = 3,
+ // The request satisified the Expect-CT compliance policy, so no action was
+ // taken.
+ EXPECT_CT_HEADER_COMPLIED = 4,
+ // The Expect-CT header was ignored because there was no corresponding
+ // preload list entry.
+ EXPECT_CT_HEADER_NOT_PRELOADED = 5,
+ // The Expect-CT header was processed successfully and passed on to the
+ // delegate to send a report.
+ EXPECT_CT_HEADER_PROCESSED = 6,
+ EXPECT_CT_HEADER_LAST = EXPECT_CT_HEADER_PROCESSED
+ };
+
+ ExpectCTHeaderResult result = EXPECT_CT_HEADER_PROCESSED;
- if (!IsBuildTimely())
+ if (!expect_ct_reporter_)
return;
- if (!ssl_info.is_issued_by_known_root ||
- !ssl_info.ct_compliance_details_available ||
- ssl_info.ct_cert_policy_compliance ==
- ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS) {
- return;
+ ExpectCTState state;
+ if (value != "preload") {
+ result = EXPECT_CT_HEADER_BAD_VALUE;
+ } else if (!IsBuildTimely()) {
+ result = EXPECT_CT_HEADER_BUILD_NOT_TIMELY;
+ } else if (!ssl_info.is_issued_by_known_root) {
+ result = EXPECT_CT_HEADER_PRIVATE_ROOT;
+ } else if (!ssl_info.ct_compliance_details_available) {
+ result = EXPECT_CT_HEADER_COMPLIANCE_DETAILS_UNAVAILABLE;
+ } else if (ssl_info.ct_cert_policy_compliance ==
+ ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS) {
+ result = EXPECT_CT_HEADER_COMPLIED;
+ } else if (!GetStaticExpectCTState(host_port_pair.host(), &state)) {
+ result = EXPECT_CT_HEADER_NOT_PRELOADED;
}
- ExpectCTState state;
- if (!GetStaticExpectCTState(host_port_pair.host(), &state))
+ UMA_HISTOGRAM_ENUMERATION("Net.ExpectCTHeaderResult", result,
+ EXPECT_CT_HEADER_LAST + 1);
+ if (result != EXPECT_CT_HEADER_PROCESSED)
return;
expect_ct_reporter_->OnExpectCTFailed(host_port_pair, state.report_uri,
diff --git a/chromium/net/http/transport_security_state.h b/chromium/net/http/transport_security_state.h
index c29f8590c0d..3326ca246c8 100644
--- a/chromium/net/http/transport_security_state.h
+++ b/chromium/net/http/transport_security_state.h
@@ -13,6 +13,7 @@
#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
+#include "base/strings/string_piece.h"
#include "base/threading/non_thread_safe.h"
#include "base/time/time.h"
#include "net/base/expiring_cache.h"
@@ -252,8 +253,12 @@ class NET_EXPORT TransportSecurityState
// An interface for asynchronously sending HPKP violation reports.
class NET_EXPORT ReportSenderInterface {
public:
- // Sends the given serialized |report| to |report_uri|.
- virtual void Send(const GURL& report_uri, const std::string& report) = 0;
+ // Sends the given serialized |report| to |report_uri| with
+ // Content-Type header as specified in
+ // |content_type|. |content_type| should be non-empty.
+ virtual void Send(const GURL& report_uri,
+ base::StringPiece content_type,
+ base::StringPiece report) = 0;
// Sets a callback to be called when report sending fails.
virtual void SetErrorCallback(
@@ -303,6 +308,19 @@ class NET_EXPORT TransportSecurityState
std::string* failure_log);
bool HasPublicKeyPins(const std::string& host);
+ // Sends an Expect-Staple report containing the raw |ocsp_response| for
+ // |host_port_pair| if the following conditions are true:
+ // 1. Sending Expect-Staple reports is enabled (via
+ // |enable_static_expect_staple_|)
+ // 2. A report sender was provided via SetReportSender().
+ // 3. The build is timele (i.e. the preload list is fresh).
+ // 4. The given host is present on the Expect-Staple preload list.
+ // 5. |ssl_info| indicates the connection did not provide an OCSP response
+ // indicating a revocation status of GOOD.
+ void CheckExpectStaple(const HostPortPair& host_port_pair,
+ const SSLInfo& ssl_info,
+ const std::string& ocsp_response);
+
// Returns true if connections to |host|, using the validated certificate
// |validated_certificate_chain|, are expected to be accompanied with
// valid Certificate Transparency information that complies with the
@@ -421,6 +439,14 @@ class NET_EXPORT TransportSecurityState
const HashValueVector& hashes,
const GURL& report_uri);
+ // Enables or disables public key pinning bypass for local trust anchors.
+ // Disabling the bypass for local trust anchors is highly discouraged.
+ // This method is used by Cronet only and *** MUST NOT *** be used by any
+ // other consumer. For more information see "How does key pinning interact
+ // with local proxies and filters?" at
+ // https://www.chromium.org/Home/chromium-security/security-faq
+ void SetEnablePublicKeyPinningBypassForLocalTrustAnchors(bool value);
+
// Parses |value| as a Public-Key-Pins-Report-Only header value and
// sends a HPKP report for |host_port_pair| if |ssl_info| violates the
// pin. Returns true if |value| parses and includes a valid
@@ -557,6 +583,9 @@ class NET_EXPORT TransportSecurityState
// True if static expect-staple state should be used.
bool enable_static_expect_staple_;
+ // True if public key pinning bypass is enabled for local trust anchors.
+ bool enable_pkp_bypass_for_local_trust_anchors_;
+
ExpectCTReporter* expect_ct_reporter_ = nullptr;
RequireCTDelegate* require_ct_delegate_ = nullptr;
diff --git a/chromium/net/http/transport_security_state_ct_policies.inc b/chromium/net/http/transport_security_state_ct_policies.inc
index 82998af6de1..60d8dfba996 100644
--- a/chromium/net/http/transport_security_state_ct_policies.inc
+++ b/chromium/net/http/transport_security_state_ct_policies.inc
@@ -212,9 +212,6 @@ const SHA256HashValue kSymantecRoots[] = {
};
const SHA256HashValue kSymantecExceptions[] = {
- {{0x0b, 0x2a, 0xc7, 0xee, 0x53, 0xe1, 0xb3, 0xb2, 0x12, 0xcf, 0xd1,
- 0x95, 0xfb, 0xe4, 0x29, 0xc3, 0x7b, 0x0a, 0xc4, 0xb1, 0x6e, 0xa0,
- 0xb8, 0xf6, 0xcf, 0xe4, 0xfe, 0xd9, 0x9b, 0x2e, 0x19, 0xb6}},
{{0x56, 0xe9, 0x8d, 0xea, 0xc0, 0x06, 0xa7, 0x29, 0xaf, 0xa2, 0xed,
0x79, 0xf9, 0xe4, 0x19, 0xdf, 0x69, 0xf4, 0x51, 0x24, 0x25, 0x96,
0xd2, 0xaa, 0xf2, 0x84, 0xc7, 0x4a, 0x85, 0x5e, 0x35, 0x2e}},
diff --git a/chromium/net/http/transport_security_state_static.h b/chromium/net/http/transport_security_state_static.h
index 78d617c6571..722f2e19a17 100644
--- a/chromium/net/http/transport_security_state_static.h
+++ b/chromium/net/http/transport_security_state_static.h
@@ -285,6 +285,8 @@ enum SecondLevelDomainName {
DOMAIN_GOOGLEWEBLIGHT_COM,
DOMAIN_GOOGLEADSSERVING_CN,
DOMAIN_SWEHACK_ORG,
+ DOMAIN_GOOGLESOURCE_COM,
+ DOMAIN_NIGHTX_UK,
// Boundary value for UMA_HISTOGRAM_ENUMERATION.
DOMAIN_NUM_EVENTS,
};
@@ -573,11 +575,12 @@ static const char kSPKIHash_COMODORSADomainValidationSecureServerCA[] =
"\x11\x12\x33\x3d\xda\xb2\x3d\x66\xb8\xef\xb8\x68\x87\x63\x8a\xe6";
static const char* const kExpectCTReportURIs[] = {
- "https://report.badssl.com/expect-ct",
"https://clients3.google.com/ct_upload",
};
static const char* const kExpectStapleReportURIs[] = {
"https://report.badssl.com/expect-staple",
+ "https://log.getdropbox.com/log/ocsp_expect_staple",
+ "https://reporting.caddyserver.com/expect-staple",
};
// The following is static data describing the hosts that are hardcoded with
// certificate pins or HSTS information.
@@ -598,6 +601,7 @@ static const char* const kGoogleAcceptableCerts[] = {
kSPKIHash_GoogleBackup2048,
kSPKIHash_GoogleG2,
kSPKIHash_GeoTrustGlobal,
+ kSPKIHash_GlobalSignRootCA_R2,
NULL,
};
static const char kGoogleReportURI[] = "http://clients3.google.com/cert_upload_json";
@@ -745,6 +749,20 @@ static const char* const kSwehackComAcceptableCerts[] = {
kSPKIHash_COMODORSADomainValidationSecureServerCA,
NULL,
};
+static const char* const kNightxAcceptableCerts[] = {
+ kSPKIHash_LetsEncryptAuthorityPrimary_X1_X3,
+ kSPKIHash_LetsEncryptAuthorityBackup_X2_X4,
+ kSPKIHash_VeriSignClass3_G4,
+ kSPKIHash_VeriSignClass3_G5,
+ kSPKIHash_VeriSignUniversal,
+ kSPKIHash_DigiCertGlobalRoot,
+ kSPKIHash_DigiCertEVRoot,
+ kSPKIHash_DigiCertAssuredIDRoot,
+ kSPKIHash_COMODOCertificationAuthority,
+ kSPKIHash_AddTrustExternalCARoot,
+ NULL,
+};
+static const char kNightxReportURI[] = "http://l.nightx.uk/report/hpkp";
struct Pinset {
const char* const* const accepted_pins;
@@ -763,6 +781,7 @@ static const struct Pinset kPinsets[] = {
{kSpideroakAcceptableCerts, kNoRejectedPublicKeys, kNoReportURI},
{kYahooAcceptableCerts, kNoRejectedPublicKeys, kNoReportURI},
{kSwehackComAcceptableCerts, kNoRejectedPublicKeys, kNoReportURI},
+ {kNightxAcceptableCerts, kNoRejectedPublicKeys, kNightxReportURI},
};
// kHSTSHuffmanTree describes a Huffman tree. The nodes of the tree are pairs
@@ -771,9991 +790,11249 @@ static const struct Pinset kPinsets[] = {
// uint8_t value has the MSB set then it represents a literal leaf value.
// Otherwise it's a pointer to the n'th element of the array.
static const uint8_t kHSTSHuffmanTree[] = {
- 0xb0, 0xb2, 0xc1, 0xb9, 0x01, 0xb7, 0xb8, 0x02, 0x03, 0xf1, 0x00, 0x04,
- 0xae, 0x05, 0x06, 0xf9, 0xf0, 0x07, 0xf5, 0xe4, 0x08, 0x09, 0xf7, 0xe6,
+ 0xb1, 0xb2, 0xc1, 0xb9, 0xb7, 0x01, 0xb8, 0x02, 0x03, 0xf1, 0x00, 0x04,
+ 0xfa, 0x05, 0x06, 0xf9, 0xf0, 0x07, 0xf5, 0xe4, 0x08, 0x09, 0xf7, 0xe6,
0x0b, 0xed, 0xf2, 0x0c, 0x0a, 0x0d, 0xe9, 0xef, 0x80, 0x0f, 0x0e, 0x10,
- 0xeb, 0xe2, 0xe3, 0x12, 0x13, 0xe1, 0x14, 0xff, 0xb6, 0xb5, 0xb3, 0x16,
- 0xb1, 0xb4, 0x17, 0x18, 0x19, 0xf8, 0x1a, 0xad, 0xea, 0xfa, 0x1c, 0xf6,
+ 0xeb, 0xe2, 0xe3, 0x12, 0xe1, 0x13, 0x14, 0xff, 0xb5, 0xb6, 0xb3, 0x16,
+ 0xb4, 0xb0, 0x17, 0x18, 0x19, 0xae, 0x1a, 0xad, 0xf8, 0xea, 0x1c, 0xf6,
0x1b, 0x1d, 0xec, 0x1e, 0xe5, 0x1f, 0xe7, 0xe8, 0xf3, 0x21, 0xf4, 0xee,
0x22, 0x23, 0x20, 0x24, 0x15, 0x25, 0x11, 0x26,
};
static const uint8_t kPreloadedHSTSData[] = {
0xfb, 0x5d, 0x3b, 0xf4, 0xa8, 0x89, 0x4b, 0xdf, 0x6d, 0x2c, 0x5f, 0xf3,
- 0xc3, 0x35, 0x9e, 0xee, 0x35, 0x8b, 0xfe, 0x61, 0xe1, 0x41, 0xbe, 0x25,
- 0x8b, 0x04, 0xc4, 0x63, 0xc4, 0x6e, 0x71, 0xdf, 0x1d, 0xdc, 0x14, 0x35,
- 0x62, 0xe0, 0x09, 0x62, 0xf4, 0x0b, 0x71, 0x62, 0xee, 0xfc, 0xb1, 0x7f,
- 0xfd, 0x3f, 0x98, 0x13, 0x9b, 0xdc, 0x27, 0x3c, 0xb1, 0x7f, 0xd8, 0x7e,
- 0xfc, 0xdf, 0xcd, 0xd5, 0x8b, 0x71, 0x62, 0x86, 0x79, 0xee, 0x7b, 0x7c,
- 0x2d, 0xd1, 0xca, 0xc5, 0x41, 0x1f, 0xe3, 0x19, 0x68, 0x4f, 0xfc, 0x86,
- 0xff, 0x61, 0x85, 0x3e, 0xfb, 0x2c, 0x5d, 0xe0, 0xd6, 0x2e, 0x76, 0x58,
- 0xac, 0x35, 0xff, 0x19, 0xbf, 0xfc, 0x20, 0xbf, 0x3a, 0xfb, 0x7e, 0x73,
- 0x50, 0x58, 0xbf, 0xfe, 0xfb, 0x09, 0xfb, 0x86, 0xb3, 0xb8, 0x31, 0xd6,
- 0x2f, 0xf7, 0xc3, 0x8b, 0x8d, 0xd9, 0x8b, 0x15, 0x28, 0x8b, 0xc5, 0x2a,
- 0x94, 0x7e, 0x14, 0x36, 0xec, 0x4b, 0x17, 0xfa, 0x05, 0x9b, 0xcb, 0x38,
- 0xb1, 0x58, 0x78, 0xae, 0x23, 0x7f, 0xf0, 0x8f, 0xf2, 0xce, 0xfc, 0x4f,
- 0xf5, 0x8b, 0xff, 0xf4, 0x09, 0xfc, 0xe7, 0xe4, 0x8e, 0x7f, 0x30, 0x58,
- 0xae, 0x22, 0x64, 0x34, 0x5b, 0xb3, 0x8b, 0x17, 0x9d, 0xfa, 0x54, 0x45,
- 0xa5, 0x40, 0xf9, 0x70, 0x93, 0xa1, 0x7b, 0xff, 0xfb, 0xef, 0x84, 0xfe,
- 0xe7, 0x3a, 0xfb, 0x6f, 0x9e, 0x2c, 0x5f, 0x78, 0x9c, 0xd5, 0x8b, 0xf4,
- 0xeb, 0x3b, 0xf2, 0xc5, 0x9b, 0x48, 0xa9, 0xfa, 0xe8, 0x08, 0xef, 0xcc,
- 0x6f, 0xb5, 0x2b, 0x17, 0x6b, 0x8b, 0x17, 0xe3, 0x27, 0x7b, 0xfd, 0x62,
- 0xff, 0x79, 0xce, 0xf0, 0x7d, 0x2c, 0x54, 0x9e, 0xf3, 0x15, 0xde, 0xe0,
- 0x7e, 0x58, 0xa1, 0xab, 0x09, 0xd4, 0x63, 0xdf, 0x86, 0xc1, 0x1a, 0xf0,
- 0xa7, 0x7b, 0xb0, 0x64, 0x17, 0x7b, 0xcb, 0x17, 0xff, 0xc2, 0xf7, 0x07,
- 0xf9, 0xe4, 0xfc, 0x53, 0xc5, 0x8b, 0xff, 0xe7, 0xfe, 0x16, 0xb5, 0x9d,
- 0xc3, 0xcc, 0x75, 0x8a, 0x82, 0x2e, 0x4d, 0x18, 0x12, 0x8d, 0xdd, 0x4a,
- 0xc5, 0xf1, 0xd8, 0xce, 0x2c, 0x5f, 0xfe, 0x35, 0xb5, 0xee, 0xfa, 0x6c,
- 0x32, 0x11, 0xac, 0x51, 0xcf, 0xd3, 0xc4, 0x97, 0xfc, 0xe1, 0x96, 0x45,
- 0xa9, 0x31, 0x62, 0x98, 0xf7, 0x44, 0x45, 0x71, 0x18, 0xb1, 0x58, 0x99,
- 0x17, 0xe1, 0xd2, 0x61, 0x0d, 0xfc, 0x76, 0xef, 0x93, 0xda, 0xc5, 0xff,
- 0xd3, 0x85, 0xe1, 0x38, 0xf9, 0x26, 0xac, 0x5f, 0xd2, 0x3e, 0xf9, 0x31,
- 0x2c, 0x54, 0xa2, 0x92, 0x06, 0x1c, 0x44, 0xb9, 0xf7, 0xac, 0x5f, 0x4f,
- 0x47, 0x12, 0xc5, 0x86, 0xc6, 0xf4, 0x86, 0x6f, 0xdd, 0x8f, 0x4f, 0x05,
- 0x8b, 0xfc, 0x20, 0x16, 0x46, 0x1c, 0x16, 0x2f, 0xf4, 0xfb, 0x87, 0x14,
- 0xc6, 0xb1, 0x52, 0x89, 0x5f, 0x95, 0x11, 0xb5, 0xff, 0x8b, 0xdf, 0xc8,
- 0x19, 0x3d, 0xf1, 0x62, 0xff, 0xd3, 0xdf, 0x3c, 0xd1, 0xc6, 0xde, 0x58,
- 0xb8, 0x72, 0xb1, 0x52, 0x89, 0xad, 0x20, 0x92, 0x15, 0xe6, 0x03, 0xac,
- 0x5f, 0xe6, 0xde, 0xdb, 0xce, 0xde, 0x58, 0xb0, 0xd6, 0x2f, 0xf7, 0x27,
- 0x51, 0x44, 0xdf, 0x58, 0xa1, 0x9e, 0x47, 0x04, 0xaf, 0xed, 0x49, 0xf0,
- 0x8e, 0xb1, 0x7f, 0x89, 0xb8, 0xc5, 0xdc, 0x16, 0x2b, 0x47, 0xc0, 0x61,
- 0x6d, 0xcd, 0x1a, 0xc5, 0xe3, 0x81, 0x96, 0x2f, 0xed, 0x3f, 0x1f, 0x3e,
- 0xb1, 0x6f, 0x39, 0xe5, 0x08, 0x76, 0xe9, 0xdc, 0x58, 0xbf, 0xe9, 0xce,
- 0x45, 0xf6, 0x33, 0xcb, 0x14, 0x34, 0x6f, 0x33, 0x11, 0xc9, 0xf8, 0x35,
- 0x52, 0xa8, 0xfb, 0x1f, 0xda, 0x10, 0x4f, 0x18, 0x0d, 0xff, 0x1f, 0x35,
- 0xa6, 0xde, 0xfd, 0x2c, 0x5f, 0xfd, 0xd6, 0xa4, 0xd9, 0x2f, 0x05, 0x81,
- 0x66, 0xc4, 0xb1, 0x78, 0x2a, 0x43, 0x58, 0xbf, 0xb5, 0x9f, 0x6e, 0xc9,
- 0x62, 0xf8, 0xd0, 0x4f, 0x96, 0x2d, 0xf9, 0x3d, 0x26, 0x2e, 0xbf, 0xbe,
- 0x42, 0x73, 0x7a, 0x58, 0xbf, 0xa7, 0x58, 0x37, 0x82, 0xc5, 0x0d, 0x10,
- 0x6c, 0x4c, 0x19, 0x85, 0xc5, 0xc5, 0x8a, 0x94, 0xe4, 0xc6, 0xad, 0x90,
- 0xf6, 0x23, 0x0b, 0xfe, 0xe8, 0x3f, 0x34, 0x0c, 0xcf, 0xac, 0x5f, 0xf1,
- 0x4e, 0x47, 0xee, 0x64, 0x6b, 0x17, 0xff, 0xbd, 0xcc, 0x88, 0xa4, 0xfa,
- 0xd4, 0xf6, 0xb1, 0x7f, 0xc2, 0x0b, 0x8f, 0x3d, 0xcc, 0xfa, 0xc5, 0xbd,
- 0x28, 0x8a, 0x74, 0xcb, 0xfe, 0xeb, 0x0b, 0x23, 0x8c, 0x44, 0xb1, 0x6d,
- 0xc5, 0x8b, 0xed, 0x73, 0x0c, 0x58, 0xbf, 0x11, 0x4f, 0x61, 0xc9, 0xb9,
- 0xc1, 0x5b, 0xf9, 0xb9, 0xad, 0x4c, 0x16, 0x2f, 0xff, 0x78, 0x5a, 0x7e,
- 0x79, 0xb6, 0x70, 0x12, 0xb1, 0x4b, 0x0c, 0x79, 0xb5, 0xd2, 0x25, 0xdd,
- 0xee, 0xff, 0xfd, 0x80, 0xe3, 0x76, 0x66, 0x75, 0x24, 0x27, 0x82, 0xc5,
- 0xff, 0x17, 0xb9, 0xec, 0xc3, 0x38, 0xb1, 0x73, 0xfd, 0x62, 0xb0, 0xf4,
- 0x7b, 0x3a, 0xbf, 0xff, 0x45, 0x09, 0x06, 0xb3, 0xa9, 0x83, 0x69, 0xb8,
- 0xb1, 0x52, 0x7f, 0x38, 0x45, 0x7e, 0xcf, 0x85, 0x36, 0x10, 0x5a, 0xac,
- 0x54, 0xae, 0x06, 0x8c, 0xf7, 0x21, 0x89, 0xd1, 0x3b, 0x3a, 0x7e, 0x1a,
- 0x64, 0x47, 0xe8, 0xc8, 0x4c, 0x20, 0xbf, 0xf6, 0x79, 0xc8, 0x0e, 0x73,
- 0xb2, 0xc5, 0xee, 0x9a, 0x35, 0x8b, 0xff, 0xff, 0x0b, 0xf8, 0x3f, 0x7f,
- 0x0f, 0x9f, 0xfb, 0xb7, 0xa7, 0xdc, 0x58, 0xbd, 0xcc, 0x25, 0x8b, 0xfd,
- 0xdf, 0xf0, 0x7a, 0x7e, 0x96, 0x29, 0x8f, 0x49, 0xc7, 0x2a, 0x09, 0x9d,
- 0x76, 0x7a, 0xc3, 0xfc, 0x85, 0xf5, 0xe3, 0x73, 0x75, 0x62, 0xed, 0xdd,
- 0xd5, 0x8b, 0xb3, 0xb4, 0x8b, 0x4a, 0x45, 0x81, 0xa3, 0x52, 0x01, 0x8b,
- 0xfd, 0xec, 0xd0, 0x0e, 0xdc, 0x48, 0x08, 0x69, 0xef, 0xe8, 0x7d, 0xb7,
- 0xe4, 0x4b, 0x15, 0x27, 0xee, 0xe8, 0xd7, 0xed, 0xe5, 0x3d, 0xf1, 0x62,
- 0xff, 0x87, 0xce, 0x66, 0x87, 0xfc, 0x58, 0xbf, 0xbe, 0xdd, 0x49, 0xd9,
- 0x62, 0xff, 0x48, 0x23, 0x78, 0x4e, 0xe2, 0xc5, 0xff, 0xfd, 0xc6, 0xf7,
- 0xf0, 0x79, 0xd4, 0xf9, 0x8b, 0x3b, 0x58, 0xa9, 0x46, 0x01, 0x17, 0x78,
- 0xde, 0xff, 0xfc, 0x58, 0x07, 0x20, 0x06, 0x7f, 0x09, 0xe3, 0x95, 0x8a,
- 0xc4, 0xea, 0x58, 0xac, 0xa1, 0xf5, 0xe2, 0xeb, 0x04, 0x0a, 0x37, 0x3a,
- 0x7b, 0x10, 0xe8, 0x5a, 0x8c, 0x4c, 0x63, 0xf1, 0xa0, 0xc1, 0x88, 0x71,
- 0x8e, 0x64, 0xb7, 0x43, 0x63, 0x2c, 0xea, 0x35, 0x3e, 0xe1, 0xb4, 0xcd,
- 0x91, 0x42, 0xeb, 0x50, 0xc8, 0x39, 0x77, 0xe5, 0x2d, 0x3a, 0x31, 0x47,
- 0x9f, 0xc9, 0xc4, 0xdf, 0x47, 0x92, 0x24, 0x33, 0x08, 0x76, 0x61, 0xca,
- 0x1c, 0x79, 0x37, 0xff, 0xff, 0x39, 0xc2, 0x36, 0xb4, 0x2d, 0x6a, 0x4b,
- 0x0d, 0x6f, 0xff, 0x03, 0x58, 0xbe, 0xd0, 0xbd, 0x8b, 0x17, 0xff, 0x1a,
- 0x66, 0xe4, 0x63, 0xd8, 0xf6, 0xed, 0xfe, 0xca, 0xc5, 0xfa, 0x63, 0x7d,
- 0x74, 0xb1, 0x73, 0x6f, 0x58, 0xbd, 0x3e, 0xe2, 0xc5, 0xee, 0x08, 0xfa,
- 0x3e, 0x00, 0x15, 0x10, 0xcd, 0x05, 0x88, 0xfa, 0x68, 0x5d, 0x5f, 0xec,
- 0x07, 0x33, 0xa7, 0x1a, 0xc5, 0xf8, 0x9c, 0xce, 0x71, 0x62, 0xb0, 0xf7,
- 0x74, 0x69, 0x7d, 0xd3, 0xbf, 0x4a, 0x8a, 0x88, 0xbc, 0x6c, 0xf1, 0x62,
- 0xfe, 0xfc, 0xfa, 0x7b, 0x31, 0x62, 0xf8, 0xa0, 0xc7, 0x58, 0xbf, 0x43,
- 0x09, 0x86, 0xb1, 0x58, 0x89, 0x76, 0x1e, 0x73, 0x0f, 0x11, 0x56, 0x93,
- 0x02, 0x3c, 0x32, 0x2f, 0xbf, 0x9a, 0xc5, 0x8b, 0xcd, 0x16, 0xea, 0xc5,
- 0x49, 0xe1, 0xfc, 0x8a, 0xfd, 0xd3, 0xfe, 0x7e, 0xb1, 0x7f, 0xff, 0x08,
- 0x9c, 0xdd, 0xbe, 0x36, 0x4a, 0x19, 0xf6, 0x3a, 0xc5, 0xc2, 0x0d, 0x62,
- 0xf0, 0xe4, 0xeb, 0x17, 0xc6, 0x86, 0x5d, 0x2c, 0x50, 0xcf, 0x0c, 0xd1,
- 0xdb, 0xff, 0xe8, 0x46, 0x16, 0x4e, 0xc1, 0x1f, 0x5a, 0xdb, 0xb7, 0xfb,
- 0x2b, 0x15, 0x28, 0xe6, 0x65, 0xc0, 0x11, 0xdf, 0xb4, 0xdd, 0x36, 0xf5,
- 0x8b, 0xe1, 0xce, 0x12, 0xc5, 0xf9, 0xcd, 0xcf, 0xba, 0xc5, 0x61, 0xe4,
- 0x88, 0x86, 0xff, 0xfe, 0x11, 0x39, 0xbb, 0x7c, 0x6c, 0x94, 0x33, 0xec,
- 0x75, 0x8b, 0xed, 0x6b, 0x36, 0x56, 0x28, 0xe8, 0x84, 0x75, 0xeb, 0xfd,
- 0x25, 0x01, 0xfd, 0x8e, 0xb1, 0x7f, 0xff, 0xec, 0xf6, 0x7b, 0x34, 0x03,
- 0xbc, 0x27, 0x8d, 0xc6, 0xef, 0xcb, 0x14, 0x6a, 0x27, 0xf8, 0x67, 0x7f,
- 0xfe, 0x78, 0x14, 0xf3, 0x3b, 0xe8, 0x9f, 0x3b, 0xe9, 0x62, 0xfd, 0x26,
- 0x67, 0xdd, 0x62, 0xf0, 0xdb, 0x7a, 0xc5, 0x82, 0x4a, 0xfc, 0x6c, 0x23,
- 0x1d, 0x1c, 0x22, 0x72, 0x32, 0x3e, 0x9b, 0x18, 0x84, 0xe5, 0x3f, 0x8d,
- 0x11, 0xcb, 0x89, 0xd3, 0x90, 0xa5, 0xf4, 0x30, 0x77, 0x92, 0x06, 0xaf,
- 0xba, 0x51, 0x7e, 0xe0, 0x9c, 0x80, 0xb1, 0x7d, 0x84, 0xde, 0x58, 0xbd,
- 0x87, 0x09, 0xe3, 0xc9, 0xd9, 0x28, 0xbf, 0xef, 0xb6, 0xbe, 0xfc, 0xc0,
- 0xd6, 0x2e, 0x19, 0x2c, 0x5f, 0xa2, 0x9f, 0x8a, 0x35, 0x8b, 0xf3, 0xc3,
- 0xcd, 0x1a, 0xc5, 0x61, 0xea, 0x31, 0x5d, 0xe7, 0xf3, 0x2c, 0x5d, 0x21,
- 0x31, 0x1c, 0x3d, 0x9d, 0x7d, 0xaf, 0x84, 0x14, 0x34, 0xd8, 0xf9, 0x18,
- 0xcd, 0xec, 0x33, 0x16, 0x2f, 0x0a, 0x63, 0x58, 0xb8, 0x5f, 0x58, 0xbf,
- 0x9e, 0x1d, 0xf2, 0x63, 0x58, 0xbf, 0xe7, 0xec, 0xb3, 0x7e, 0x9b, 0x8b,
- 0x17, 0xe6, 0x98, 0x3c, 0x16, 0x2a, 0x34, 0x55, 0x0c, 0x60, 0xe6, 0x1f,
- 0x3b, 0xbf, 0xb2, 0x31, 0xce, 0x0d, 0x62, 0xf8, 0x7f, 0x68, 0x96, 0x2b,
- 0x0f, 0x49, 0xcb, 0xaf, 0xc4, 0xfb, 0xb9, 0x1a, 0xc5, 0xe3, 0x1f, 0xeb,
- 0x17, 0x48, 0xd6, 0x2a, 0x4d, 0xaf, 0xc7, 0xaf, 0xf9, 0xcb, 0xdc, 0xd6,
- 0x49, 0xd6, 0x2f, 0xcc, 0x44, 0x2d, 0xc5, 0x8b, 0xfe, 0xe6, 0x0f, 0x35,
- 0x09, 0xd2, 0xc5, 0x49, 0xf1, 0xe8, 0xaa, 0xd1, 0xac, 0x54, 0x9b, 0x4c,
- 0x21, 0xbe, 0xea, 0x74, 0x6a, 0xc5, 0xfa, 0x0f, 0xe8, 0x3a, 0xc5, 0xf4,
- 0x80, 0x12, 0xb1, 0x52, 0x79, 0x44, 0x51, 0x7f, 0xc4, 0x3c, 0xd0, 0xdd,
- 0xc6, 0xb1, 0x61, 0x2c, 0x54, 0x9e, 0x53, 0x9c, 0x58, 0x96, 0x2f, 0xd1,
- 0xe9, 0xdf, 0xcb, 0x14, 0xc6, 0xe9, 0xc4, 0x6e, 0x38, 0xd6, 0x2f, 0xbe,
- 0xdf, 0x08, 0x15, 0x5c, 0x6d, 0x18, 0xee, 0x43, 0x20, 0xd8, 0x48, 0x74,
- 0x41, 0x13, 0x01, 0xc8, 0x3f, 0x0c, 0xfe, 0x0f, 0xf9, 0xbc, 0xc6, 0xad,
- 0x95, 0xad, 0xd1, 0xfb, 0xdc, 0xc2, 0x58, 0xbf, 0x6b, 0xa7, 0x7e, 0x95,
- 0x15, 0xe9, 0x7e, 0x6d, 0xde, 0x85, 0x1a, 0xc5, 0xa0, 0xb1, 0x63, 0xac,
- 0x54, 0x9a, 0x47, 0x12, 0xba, 0x40, 0xb1, 0x7b, 0xf3, 0xda, 0xc5, 0xf6,
- 0x79, 0xa3, 0x58, 0xbf, 0xa3, 0x0f, 0x65, 0xc8, 0x0b, 0x17, 0xfe, 0x72,
- 0x06, 0x7a, 0x49, 0x80, 0xb1, 0x52, 0x7d, 0xfb, 0x26, 0x76, 0x09, 0x04,
- 0xeb, 0xf0, 0x73, 0x46, 0xee, 0xa4, 0x01, 0xf1, 0x0b, 0xec, 0x8f, 0x07,
- 0x09, 0x2b, 0xff, 0x82, 0x3c, 0x02, 0x66, 0xba, 0x77, 0xe9, 0x51, 0x23,
- 0x17, 0xff, 0x82, 0x1d, 0xe0, 0x13, 0x35, 0xd3, 0xbf, 0x4a, 0x89, 0xe0,
- 0xbf, 0xfc, 0x10, 0xef, 0x00, 0x99, 0xae, 0x9d, 0xfa, 0x54, 0x4f, 0xe5,
- 0xff, 0xe0, 0x87, 0x78, 0x04, 0xcd, 0x74, 0xef, 0xd2, 0xa2, 0x86, 0x2f,
- 0xfc, 0xf0, 0x09, 0x9a, 0xe9, 0xdf, 0xa5, 0x45, 0x10, 0x5f, 0xcf, 0xd0,
- 0x40, 0x34, 0x6b, 0x14, 0x74, 0x40, 0xef, 0x4f, 0xbf, 0xf4, 0x02, 0x0b,
- 0x9b, 0x67, 0x93, 0x05, 0x8a, 0x08, 0x7d, 0x32, 0x4b, 0x7f, 0xe8, 0x9b,
- 0xfd, 0xe7, 0x87, 0x87, 0x58, 0xbf, 0xfc, 0xe1, 0x06, 0xe4, 0xfd, 0x6d,
- 0x0d, 0xce, 0xb1, 0x7f, 0x37, 0x9b, 0x4e, 0x05, 0x8b, 0xec, 0xf6, 0x01,
- 0x62, 0xfc, 0x42, 0x78, 0x71, 0x62, 0xc7, 0x58, 0xbf, 0xed, 0xf9, 0xdc,
- 0x34, 0xef, 0x05, 0x8b, 0xc4, 0xe1, 0x20, 0x8c, 0x52, 0x2d, 0xf1, 0x16,
- 0xc9, 0x40, 0x62, 0x57, 0xe1, 0xc9, 0x4f, 0xd6, 0x2f, 0xff, 0xdf, 0xc2,
- 0xc3, 0x7e, 0xf0, 0xf9, 0x8e, 0x19, 0xd6, 0x2f, 0xba, 0x77, 0xe9, 0x51,
- 0x48, 0x95, 0x04, 0x44, 0xe9, 0x62, 0xfc, 0x2f, 0x14, 0xfd, 0x62, 0xff,
- 0xef, 0xef, 0x7d, 0x71, 0xff, 0xc9, 0x8d, 0x62, 0xff, 0xe7, 0xef, 0x9f,
- 0x32, 0x41, 0xb4, 0x33, 0xac, 0x5f, 0xe8, 0x4e, 0xa3, 0x9d, 0x46, 0xb1,
- 0x61, 0x2c, 0x54, 0x9e, 0x40, 0x0d, 0xaf, 0xff, 0x16, 0x7f, 0xc5, 0x20,
- 0xc2, 0x78, 0x2c, 0x5f, 0xe2, 0x93, 0xf0, 0x1e, 0x75, 0x8b, 0xfc, 0xfe,
- 0x3b, 0x7b, 0xec, 0xb1, 0x79, 0xe0, 0x12, 0x55, 0x52, 0x64, 0x2c, 0x22,
- 0x23, 0x72, 0x80, 0x24, 0x14, 0x24, 0xf8, 0x43, 0xe4, 0x70, 0xcc, 0xef,
- 0x82, 0x4e, 0x1d, 0x62, 0xec, 0xde, 0xb1, 0x7f, 0xfb, 0xac, 0xf4, 0x97,
- 0xb8, 0xe4, 0x2c, 0x58, 0xb0, 0x4e, 0x1f, 0x10, 0x63, 0x34, 0xc8, 0xb1,
- 0xdf, 0x08, 0x6b, 0xff, 0xd0, 0x09, 0xa7, 0x03, 0xf9, 0xb5, 0x87, 0x58,
- 0xbf, 0xf7, 0x7c, 0x83, 0x73, 0x93, 0xa8, 0x2c, 0x5f, 0xf3, 0x75, 0x27,
- 0xe7, 0xa6, 0x0b, 0x17, 0x7f, 0x16, 0x2e, 0x93, 0x16, 0x2f, 0xe1, 0x68,
- 0x1b, 0x47, 0x12, 0xc5, 0x82, 0x41, 0x13, 0x83, 0x3a, 0xf8, 0xbf, 0x06,
- 0x29, 0xd3, 0x22, 0x04, 0x37, 0x6f, 0xe8, 0x67, 0xfe, 0xf0, 0x58, 0xbf,
- 0xfe, 0x68, 0x82, 0x7b, 0xec, 0xe0, 0x91, 0x05, 0xe5, 0x62, 0xff, 0xdd,
- 0x04, 0x1b, 0x6d, 0x72, 0xea, 0x56, 0x2b, 0x11, 0x34, 0xea, 0xd7, 0xff,
- 0xf6, 0x0f, 0xf2, 0x18, 0x4f, 0x13, 0x83, 0x9c, 0x90, 0x24, 0x58, 0x24,
- 0xb2, 0x2a, 0x86, 0x83, 0xd4, 0x62, 0x87, 0x96, 0x07, 0xf8, 0xd3, 0x1c,
- 0xa4, 0x11, 0xb7, 0x78, 0xa3, 0x7c, 0x32, 0x36, 0x48, 0x6f, 0x73, 0x38,
- 0xb1, 0x7c, 0x2d, 0xd1, 0xca, 0xc5, 0x76, 0x78, 0x7f, 0x1d, 0xbf, 0xfe,
- 0xfc, 0xfd, 0x8d, 0xe7, 0x30, 0x81, 0xb3, 0x8b, 0x17, 0xdd, 0x3b, 0xf4,
- 0xa8, 0x94, 0x0b, 0xff, 0x48, 0x0e, 0xf0, 0xfc, 0xbe, 0x96, 0x2a, 0x08,
- 0xc2, 0xd2, 0x99, 0x18, 0xdf, 0xfe, 0xfb, 0x46, 0x71, 0x68, 0x1c, 0xe3,
- 0x8d, 0x62, 0xff, 0xbf, 0x3a, 0x89, 0xbf, 0x31, 0x2c, 0x5f, 0xe7, 0x30,
- 0xb0, 0x12, 0x05, 0x8b, 0xfd, 0x83, 0xc1, 0xc9, 0x79, 0x62, 0x88, 0xf9,
- 0x78, 0x67, 0x7f, 0x3c, 0x09, 0xa4, 0xd5, 0x8b, 0xff, 0x9f, 0xbe, 0x47,
- 0x86, 0x08, 0xa7, 0x8b, 0x17, 0xfd, 0xc9, 0x3e, 0x79, 0xc4, 0x17, 0x58,
- 0xbf, 0xd3, 0xc1, 0xe9, 0x85, 0x1a, 0xc5, 0xb3, 0xc7, 0xe5, 0xbc, 0xf6,
- 0xed, 0x4a, 0xc5, 0xfe, 0x80, 0x70, 0xc0, 0x4c, 0x16, 0x28, 0x67, 0x99,
- 0xa1, 0x7b, 0xe8, 0x36, 0xa0, 0xb1, 0x79, 0xc7, 0x8b, 0x15, 0x87, 0xc3,
- 0x11, 0x17, 0x08, 0xef, 0xfa, 0x19, 0xf2, 0xcf, 0x7d, 0x96, 0x2f, 0xff,
- 0x3c, 0x6d, 0xad, 0x37, 0x70, 0xf3, 0xf6, 0xb1, 0x7f, 0xff, 0xfd, 0xe6,
- 0x21, 0x43, 0x38, 0x59, 0x18, 0x70, 0xf1, 0xad, 0xdf, 0x07, 0x84, 0xb1,
- 0x7b, 0xfe, 0x3a, 0xc5, 0xf0, 0x47, 0x80, 0x49, 0x5d, 0x30, 0xc8, 0x72,
- 0xf4, 0x5e, 0xc9, 0xb1, 0x42, 0x80, 0xe4, 0x20, 0x2d, 0x28, 0x5c, 0xf2,
- 0x1a, 0xde, 0x2f, 0xd9, 0x38, 0x0d, 0x37, 0x76, 0x10, 0x15, 0x1b, 0xe0,
- 0x33, 0xc2, 0xba, 0x18, 0x1c, 0x76, 0xfd, 0x52, 0x00, 0x9a, 0x55, 0x36,
- 0xe4, 0xe4, 0xbe, 0xa5, 0x4c, 0x9e, 0x10, 0x3f, 0x57, 0x02, 0xe8, 0x5d,
- 0x77, 0x91, 0xa3, 0x8a, 0x91, 0x9b, 0xbb, 0x3c, 0x59, 0x7f, 0xf8, 0x21,
- 0xde, 0x01, 0x33, 0x5d, 0x3b, 0xf4, 0xa8, 0x9c, 0xcb, 0xff, 0xc1, 0x0e,
- 0xf0, 0x09, 0x9a, 0xe9, 0xdf, 0xa5, 0x45, 0x12, 0x5d, 0xb0, 0xa3, 0x58,
- 0xbf, 0xe1, 0x3e, 0xa1, 0xb0, 0xb7, 0x81, 0x96, 0x2f, 0x37, 0x7c, 0x58,
- 0xbc, 0x52, 0x75, 0x8b, 0xfe, 0x27, 0xef, 0xcf, 0xe8, 0x3a, 0xc5, 0xfd,
- 0xfc, 0xcf, 0x7f, 0x16, 0x2a, 0x34, 0x50, 0x30, 0xf0, 0x07, 0x3c, 0x73,
- 0x76, 0xf9, 0x58, 0xbf, 0x87, 0xa9, 0xde, 0xdb, 0xd6, 0x2f, 0xb8, 0x79,
- 0xe2, 0xc5, 0xff, 0x37, 0x30, 0x70, 0x87, 0xc4, 0xb1, 0x7e, 0xe4, 0x50,
- 0x60, 0x2c, 0x56, 0x22, 0x1f, 0xa2, 0x36, 0x3a, 0xbf, 0xfa, 0x7b, 0xcf,
- 0x37, 0x66, 0x67, 0x7e, 0x58, 0xbf, 0xb0, 0x61, 0x8d, 0xce, 0xb1, 0x7f,
- 0xfe, 0xc2, 0x86, 0xdc, 0x1b, 0x73, 0xbf, 0x09, 0xf8, 0xb1, 0x7f, 0xa6,
- 0x30, 0xf6, 0x5c, 0x80, 0xb1, 0x74, 0x02, 0x6c, 0x6a, 0xd1, 0x86, 0x3f,
- 0x90, 0xe2, 0xe8, 0xf5, 0x86, 0x7f, 0x0b, 0x9f, 0x17, 0xef, 0x48, 0x30,
- 0xbc, 0x35, 0x8b, 0xfb, 0x85, 0xb4, 0x28, 0x36, 0x58, 0xbf, 0xf1, 0x60,
- 0x24, 0x1a, 0xd4, 0x98, 0xb1, 0x7c, 0x45, 0x9e, 0x58, 0xb0, 0x49, 0x44,
- 0xa7, 0x0d, 0x03, 0x3f, 0xad, 0x26, 0xf2, 0x08, 0xd0, 0x6b, 0x4b, 0xb4,
- 0x7c, 0x5d, 0x14, 0xe8, 0xe5, 0xff, 0xff, 0xfa, 0x30, 0xf7, 0x02, 0xd4,
- 0x2f, 0xb7, 0x6f, 0xf6, 0x42, 0x10, 0x59, 0xb1, 0xec, 0x5b, 0x81, 0x60,
- 0x7b, 0x76, 0xff, 0x65, 0x62, 0xfd, 0xae, 0x9d, 0xfa, 0x54, 0x43, 0x85,
- 0xfc, 0x2e, 0xb4, 0xd2, 0x4b, 0x17, 0xe6, 0x2f, 0x49, 0xd6, 0x2c, 0x13,
- 0x11, 0x19, 0xf3, 0x7d, 0x92, 0xeb, 0xff, 0x30, 0xf0, 0xe5, 0x9d, 0xf9,
- 0xd6, 0x2f, 0xf6, 0xb3, 0xaf, 0xcf, 0x70, 0x58, 0xb1, 0x8b, 0x15, 0x27,
- 0x93, 0x86, 0xd4, 0xb1, 0x7f, 0xf1, 0x39, 0xbd, 0x7d, 0xb5, 0xa9, 0x31,
- 0x62, 0xfa, 0x31, 0xcc, 0x6b, 0x17, 0xff, 0x75, 0xf9, 0x35, 0xb8, 0x16,
- 0xf6, 0x27, 0xfa, 0xc5, 0x84, 0xb1, 0x7f, 0x4f, 0xbf, 0x3d, 0x81, 0x62,
- 0xb7, 0x11, 0x26, 0x75, 0x2e, 0x09, 0x5c, 0x44, 0xb1, 0x7d, 0xd3, 0xbf,
- 0x4a, 0x88, 0xbc, 0xbf, 0xd9, 0xd8, 0x38, 0xed, 0x1a, 0xc5, 0xf8, 0x9c,
- 0x0f, 0xc5, 0x8b, 0xf6, 0x45, 0x07, 0xe2, 0xc5, 0x62, 0x76, 0xed, 0x0b,
- 0x88, 0x8c, 0xf4, 0x2c, 0x46, 0x3e, 0x35, 0x0c, 0x9e, 0xff, 0x47, 0xfc,
- 0xfe, 0x34, 0x6b, 0x17, 0xa4, 0xcf, 0x2c, 0x59, 0xf4, 0x7a, 0x64, 0x6b,
- 0x70, 0xb7, 0x16, 0x2e, 0x16, 0x96, 0x2a, 0x06, 0xcd, 0xc6, 0xef, 0x7d,
- 0xb4, 0xb1, 0x7c, 0x53, 0xb9, 0x12, 0xc5, 0x1c, 0xf0, 0xfe, 0x3b, 0x7d,
- 0xba, 0xc5, 0x12, 0xc5, 0xc6, 0x44, 0xb1, 0x7f, 0x60, 0xff, 0x80, 0x75,
- 0x8b, 0xe9, 0x10, 0x5f, 0x8b, 0x15, 0x88, 0x94, 0x72, 0x6e, 0x0d, 0x18,
- 0x5b, 0x7f, 0x98, 0x1c, 0x00, 0x1b, 0xcb, 0x17, 0xe9, 0x38, 0x3a, 0x02,
- 0xc5, 0x61, 0xef, 0x31, 0xa5, 0xc1, 0xf1, 0x62, 0xd0, 0x58, 0xa9, 0x35,
- 0x6e, 0x33, 0x7f, 0x81, 0xee, 0x7f, 0x18, 0x6b, 0x16, 0x8d, 0x62, 0xb4,
- 0x78, 0xe4, 0x69, 0x7f, 0xde, 0x29, 0x38, 0x63, 0xfc, 0xac, 0x5f, 0x9e,
- 0x07, 0x98, 0x2c, 0x58, 0xeb, 0x15, 0x28, 0x95, 0x62, 0x1f, 0x9d, 0x78,
- 0xa2, 0xfd, 0xd6, 0xdf, 0x66, 0x96, 0x2f, 0xf6, 0x1f, 0x3a, 0xe9, 0xbe,
- 0xb1, 0x7a, 0x0f, 0x05, 0x8a, 0x63, 0xd2, 0x88, 0xd6, 0xee, 0x76, 0xb1,
- 0x7d, 0xe8, 0x49, 0xa9, 0x17, 0xd8, 0x3f, 0x71, 0x62, 0xb1, 0x10, 0x47,
- 0x22, 0x71, 0x92, 0x24, 0xbf, 0xc5, 0x9d, 0xc3, 0x8c, 0x6a, 0xc5, 0xfb,
- 0xf9, 0xd3, 0xc1, 0x62, 0xfc, 0xfd, 0x89, 0xfc, 0xb1, 0x76, 0xc9, 0x2c,
- 0x5f, 0xc7, 0x62, 0xc3, 0xca, 0xc5, 0xf4, 0x7e, 0xcf, 0xac, 0x56, 0x1e,
- 0x83, 0x96, 0x5f, 0xe9, 0x06, 0x10, 0xb9, 0x2b, 0x16, 0x09, 0x2c, 0x97,
- 0x78, 0xe1, 0x0f, 0x02, 0x01, 0x86, 0x64, 0x7f, 0xdd, 0x42, 0xf3, 0xb5,
- 0x96, 0x63, 0x8a, 0x16, 0xda, 0x84, 0xd1, 0xd2, 0xff, 0x0f, 0xb7, 0x3b,
- 0x28, 0xc0, 0x38, 0x75, 0xe3, 0x51, 0x14, 0xef, 0x29, 0xd9, 0x6a, 0x0c,
- 0x82, 0xff, 0x9f, 0xa0, 0x90, 0xcd, 0x64, 0x16, 0x2f, 0xff, 0xff, 0x89,
- 0xc2, 0x60, 0x82, 0xec, 0x6b, 0x7b, 0xf8, 0xd0, 0xe6, 0xdc, 0x36, 0x60,
- 0xb1, 0x7e, 0xce, 0x1c, 0x72, 0xb1, 0x7f, 0xe7, 0x80, 0x4c, 0xd7, 0x4e,
- 0xfd, 0x2a, 0x26, 0x42, 0xc1, 0x23, 0x4c, 0xe3, 0xa3, 0xcd, 0x42, 0x14,
- 0xe5, 0x17, 0xe0, 0x9f, 0x77, 0x3a, 0xc5, 0xef, 0x61, 0xd6, 0x2e, 0xf9,
- 0xd6, 0x2f, 0xda, 0xe9, 0xdf, 0xa5, 0x45, 0xbc, 0x58, 0x24, 0x9f, 0x60,
- 0xc7, 0x70, 0x62, 0xf8, 0x26, 0xce, 0x12, 0xc5, 0xcf, 0xba, 0xb1, 0x7f,
- 0x81, 0x23, 0x13, 0xea, 0x0b, 0x17, 0xfe, 0x78, 0x04, 0xcd, 0x74, 0xef,
- 0xd2, 0xa2, 0x93, 0x2c, 0x13, 0x11, 0x3a, 0xc3, 0x47, 0x34, 0xb8, 0x29,
- 0xb0, 0x2c, 0x5f, 0xfb, 0x0b, 0x3d, 0xa6, 0x37, 0xe2, 0x58, 0xb1, 0xd6,
- 0x2f, 0xf8, 0x4f, 0xde, 0xb4, 0x28, 0xb8, 0xb1, 0x50, 0x3c, 0xfe, 0x09,
- 0x5c, 0x7e, 0xd6, 0x2f, 0xec, 0xf1, 0x4c, 0x9d, 0x62, 0xfe, 0xec, 0x01,
- 0xe9, 0xc0, 0xb1, 0x77, 0xc2, 0x05, 0x53, 0x47, 0x19, 0x0e, 0x42, 0x38,
- 0xe4, 0x5f, 0x19, 0x72, 0xca, 0xd8, 0xdb, 0x13, 0xf9, 0x8d, 0x36, 0x14,
- 0x9b, 0x1c, 0x94, 0xf7, 0xa4, 0xde, 0x42, 0x5b, 0xc6, 0xbb, 0xe1, 0x88,
- 0x1c, 0x6f, 0xb7, 0xf8, 0x26, 0x6b, 0xa7, 0x7e, 0x95, 0x10, 0xe9, 0x7e,
- 0xd7, 0x4e, 0xfd, 0x2a, 0x25, 0x82, 0xfb, 0x00, 0x76, 0x58, 0xbf, 0x04,
- 0x3b, 0xc0, 0x26, 0x1e, 0xce, 0xc9, 0xbd, 0xfe, 0x09, 0x9a, 0xe9, 0xdf,
- 0xa5, 0x44, 0x60, 0x5e, 0x32, 0x4e, 0xb1, 0x7a, 0x0c, 0x35, 0x8b, 0xda,
- 0x9e, 0xd6, 0x2f, 0xd0, 0xce, 0x3f, 0x16, 0x2f, 0x61, 0x0d, 0x62, 0xc1,
- 0x31, 0x13, 0xb1, 0x0f, 0x38, 0xe8, 0x87, 0x8c, 0x28, 0xbf, 0xff, 0x38,
- 0x36, 0x70, 0x21, 0x3f, 0xa1, 0x9e, 0xc1, 0xac, 0x5f, 0xff, 0x98, 0xed,
- 0xa0, 0x9e, 0xd9, 0xcf, 0xfa, 0x7b, 0x31, 0x62, 0x89, 0x30, 0x8e, 0x29,
- 0x79, 0x66, 0xf8, 0x24, 0x33, 0x8b, 0x17, 0xbc, 0xd1, 0x2c, 0x5f, 0xff,
- 0xff, 0xf4, 0x90, 0x8f, 0xa9, 0xf3, 0x74, 0xc3, 0xfc, 0xf5, 0xf9, 0x8c,
- 0xed, 0xe7, 0x89, 0xfc, 0xb1, 0x7c, 0xc4, 0xe0, 0x58, 0xbd, 0x86, 0x04,
- 0xed, 0x16, 0xfc, 0x84, 0xb5, 0xfd, 0xc8, 0xff, 0x80, 0x75, 0x8b, 0xff,
- 0xfe, 0x87, 0x02, 0x75, 0xf7, 0x8b, 0xaf, 0xe6, 0xb6, 0x2f, 0xc4, 0x7e,
- 0x2c, 0x5f, 0x4f, 0xc5, 0xe5, 0x8b, 0xf6, 0x78, 0x13, 0xd2, 0xc5, 0xff,
- 0xe9, 0xf3, 0x02, 0x60, 0x3f, 0xc9, 0x74, 0xb1, 0x7d, 0xdc, 0x1c, 0x96,
- 0x2f, 0x1d, 0xb8, 0xb1, 0x69, 0x39, 0xe0, 0x00, 0x8e, 0xf9, 0x88, 0x0c,
- 0xb1, 0x7d, 0xd3, 0xbf, 0x4a, 0x88, 0xf4, 0xa8, 0x1e, 0x96, 0x88, 0x6f,
- 0xff, 0x6e, 0x14, 0xb8, 0xdb, 0x87, 0x91, 0x81, 0x62, 0xfb, 0x8f, 0xde,
- 0xf5, 0x8b, 0x04, 0xc4, 0x4a, 0x39, 0x17, 0x93, 0x2f, 0xff, 0xfc, 0x12,
- 0x39, 0x89, 0x89, 0xba, 0x7f, 0xb9, 0x9b, 0x46, 0x40, 0x1a, 0xc5, 0x41,
- 0x15, 0x3d, 0x1b, 0x5f, 0xf7, 0x4f, 0xa7, 0xfc, 0x59, 0xe5, 0x8b, 0xff,
- 0xc2, 0xcf, 0xe1, 0x03, 0x0b, 0xdf, 0xc5, 0x8b, 0xd3, 0xa8, 0x96, 0x2e,
- 0x70, 0x8c, 0x8a, 0x12, 0x3b, 0xe2, 0x45, 0xff, 0xf4, 0xf7, 0x14, 0x27,
- 0x51, 0xeb, 0x4d, 0xee, 0x2c, 0x5f, 0xff, 0xe3, 0x84, 0x73, 0x1e, 0x36,
- 0x31, 0xc3, 0x62, 0xf4, 0xf1, 0x62, 0xc1, 0x25, 0x77, 0xee, 0x38, 0x6a,
- 0x8c, 0xf7, 0xb2, 0xf6, 0x75, 0x88, 0x8f, 0x45, 0x3f, 0x84, 0x53, 0xc7,
- 0x6c, 0x50, 0xc5, 0xf1, 0xd8, 0x6a, 0x97, 0xfe, 0xdd, 0x13, 0x8f, 0x65,
- 0xb9, 0x91, 0xac, 0x5f, 0xfb, 0xc5, 0x3b, 0x40, 0x70, 0xf4, 0xeb, 0x17,
- 0xc4, 0xe6, 0x04, 0xc4, 0x44, 0x71, 0x1a, 0xfd, 0xae, 0x9d, 0xfa, 0x54,
- 0x58, 0x65, 0xfe, 0x81, 0x4e, 0x73, 0x09, 0x62, 0xe6, 0x82, 0xc5, 0x82,
- 0x61, 0xff, 0xf6, 0x6e, 0x03, 0x1b, 0xe0, 0x80, 0x2c, 0x58, 0xbc, 0xff,
- 0xe2, 0xc5, 0xdd, 0xf9, 0x62, 0xfe, 0x14, 0x6c, 0x42, 0x3a, 0xc5, 0x49,
- 0xe4, 0x10, 0xcd, 0xf4, 0xee, 0x4c, 0x4b, 0x17, 0xa4, 0xa3, 0x58, 0xb4,
- 0xac, 0x5f, 0x48, 0x20, 0x75, 0x8a, 0xf9, 0xb4, 0x21, 0x1a, 0x1a, 0x63,
- 0x8c, 0xcb, 0x11, 0x07, 0xc9, 0xbc, 0xa3, 0x7f, 0xff, 0xd3, 0x3c, 0x09,
- 0xe1, 0xb1, 0xfb, 0x87, 0x3b, 0x86, 0x6a, 0x35, 0x8a, 0x08, 0x8b, 0x82,
- 0x4b, 0xb4, 0xc6, 0xa8, 0x73, 0x51, 0xfc, 0x5f, 0xe0, 0x99, 0xae, 0x9d,
- 0xfa, 0x54, 0x5c, 0xe5, 0xdf, 0xde, 0xb1, 0x73, 0x9d, 0x62, 0xf9, 0xb5,
- 0xa7, 0x58, 0xbe, 0xe4, 0x91, 0xab, 0x15, 0x87, 0x8a, 0x19, 0x15, 0xe2,
- 0x9e, 0xd6, 0x2f, 0x9f, 0x50, 0x08, 0x34, 0x5a, 0x90, 0xd7, 0x17, 0x37,
- 0x48, 0xaf, 0xff, 0xff, 0xfe, 0x9d, 0x87, 0x08, 0xfa, 0xfe, 0xdd, 0xbf,
- 0xd9, 0x09, 0x18, 0x8d, 0x0b, 0x59, 0x0a, 0xf7, 0x1c, 0x7d, 0x1f, 0x6e,
- 0xdf, 0xec, 0xac, 0x54, 0xb3, 0xf1, 0xa3, 0x84, 0xec, 0x11, 0x72, 0x3e,
- 0x9e, 0x8c, 0x1a, 0x78, 0x83, 0x51, 0xa6, 0x9e, 0x17, 0x5f, 0x94, 0xa7,
- 0xe3, 0x11, 0x43, 0xe7, 0x75, 0x62, 0xff, 0xb8, 0x7c, 0xdb, 0x0c, 0x1c,
- 0xac, 0x5f, 0xb5, 0xd3, 0xbf, 0x4a, 0x88, 0x78, 0xbf, 0xfd, 0xf6, 0x93,
- 0xb8, 0xc3, 0xdd, 0x92, 0x82, 0xc5, 0x82, 0x4a, 0x2f, 0xf0, 0xef, 0x86,
- 0xf7, 0xfd, 0x3f, 0x98, 0xf5, 0x38, 0x35, 0x8b, 0xff, 0x69, 0xb9, 0x23,
- 0x72, 0x63, 0xac, 0x57, 0xcf, 0xdb, 0x79, 0xcd, 0xef, 0x74, 0x05, 0x8b,
- 0xfd, 0xa9, 0x6f, 0x14, 0x9d, 0x62, 0xff, 0x0b, 0x9b, 0x46, 0x4f, 0xf5,
- 0x8b, 0xff, 0xfb, 0x06, 0xdc, 0xc2, 0xe7, 0x5f, 0x62, 0x2c, 0xed, 0x62,
- 0xff, 0xff, 0x39, 0xb1, 0x72, 0x7d, 0xb4, 0x3f, 0x31, 0x0a, 0x19, 0xc5,
- 0x8a, 0xfa, 0x30, 0x09, 0x6a, 0xff, 0xff, 0xfb, 0xf9, 0xad, 0x4f, 0x70,
- 0x0f, 0xcc, 0x42, 0x86, 0x70, 0xb2, 0x30, 0xe0, 0xb1, 0x7f, 0xfe, 0x2c,
- 0xe3, 0x3c, 0x78, 0x33, 0xb6, 0xcc, 0x9d, 0x62, 0xfb, 0xa7, 0x7e, 0x95,
- 0x11, 0x31, 0x7e, 0xc6, 0xf6, 0x84, 0xb1, 0x7d, 0xb9, 0xf9, 0x35, 0x62,
- 0xff, 0xff, 0x68, 0xb2, 0x3c, 0x1e, 0x18, 0x2d, 0x67, 0x5f, 0x9d, 0xeb,
- 0x17, 0x64, 0x6b, 0x17, 0xc2, 0x3e, 0x0d, 0x62, 0xa5, 0x14, 0x1d, 0xb2,
- 0xee, 0x8c, 0x5f, 0xbd, 0xc8, 0xf0, 0xc5, 0x8b, 0xfe, 0xf0, 0x8d, 0xdb,
- 0xfc, 0x03, 0xac, 0x56, 0x22, 0x6d, 0xcc, 0xc4, 0x57, 0x61, 0x2c, 0x5f,
- 0xef, 0x09, 0xfb, 0xfc, 0xef, 0x58, 0xa8, 0x2b, 0x2c, 0xe8, 0x89, 0xa1,
- 0x03, 0xa5, 0x73, 0x98, 0xb9, 0x41, 0x46, 0xc5, 0xc2, 0xef, 0x09, 0x5f,
- 0xf3, 0xb9, 0x03, 0x4d, 0x26, 0xac, 0x5c, 0x28, 0xd6, 0x2d, 0x8b, 0x17,
- 0x30, 0x5d, 0x62, 0x88, 0xf1, 0x77, 0x8c, 0x98, 0x23, 0x7f, 0xfb, 0xe1,
- 0x94, 0xf7, 0xfc, 0x18, 0x9f, 0xa5, 0x8b, 0xf8, 0xe1, 0x91, 0x64, 0x6b,
- 0x17, 0xe3, 0x35, 0x9f, 0xe2, 0xc5, 0x49, 0xec, 0xe1, 0x7d, 0x41, 0x18,
- 0xc5, 0x0a, 0x6b, 0xfb, 0xc5, 0x3d, 0x31, 0x2c, 0x5f, 0x8a, 0x7a, 0x62,
- 0x58, 0xbf, 0x4f, 0x70, 0x63, 0xed, 0x3d, 0x4f, 0x16, 0xdf, 0x81, 0xcd,
- 0xb8, 0x35, 0x8b, 0xfc, 0xc6, 0x61, 0x67, 0x7e, 0x58, 0xac, 0x45, 0x03,
- 0x20, 0xe8, 0xae, 0xec, 0xdd, 0x58, 0xbd, 0xd3, 0x0d, 0x62, 0xf3, 0x90,
- 0xf0, 0xdc, 0x30, 0xd5, 0xf9, 0xb6, 0x9f, 0xa8, 0x96, 0x29, 0xcf, 0x70,
- 0x8b, 0xef, 0xfc, 0x7f, 0x8b, 0xad, 0xb9, 0xf7, 0xd2, 0xc5, 0xff, 0xde,
- 0xe7, 0x25, 0xbb, 0xf7, 0xa4, 0xeb, 0x17, 0xfd, 0x3f, 0x9d, 0xe7, 0x92,
- 0x8d, 0x62, 0xff, 0xe1, 0x7b, 0x84, 0x21, 0x7a, 0x12, 0x6a, 0xc5, 0xee,
- 0x39, 0x2c, 0x5f, 0xff, 0xa7, 0x40, 0xfc, 0xef, 0x8a, 0x64, 0xfc, 0xc1,
- 0xac, 0x5f, 0xf7, 0xff, 0x3b, 0xe1, 0x9a, 0x95, 0x8b, 0xfd, 0x33, 0x16,
- 0x6f, 0x6d, 0x2c, 0x57, 0xd1, 0x90, 0xeb, 0x04, 0x77, 0x58, 0x9e, 0xd4,
- 0x48, 0xc4, 0x77, 0xc4, 0x7f, 0x43, 0x92, 0xff, 0x13, 0x80, 0x9e, 0x04,
- 0xb1, 0x7e, 0xf6, 0x02, 0x74, 0xb1, 0x73, 0x7a, 0x4f, 0x65, 0x8c, 0x6f,
- 0xa3, 0xf8, 0xa3, 0x58, 0xa9, 0x56, 0x2d, 0x92, 0x87, 0x5e, 0x15, 0x02,
- 0x2b, 0xbe, 0x8c, 0xf3, 0xa5, 0x8b, 0xee, 0x84, 0x46, 0xac, 0x5c, 0xee,
- 0xb1, 0x4e, 0x7b, 0xe4, 0x48, 0x19, 0x2d, 0xff, 0x9f, 0xbe, 0x45, 0xb8,
- 0xc5, 0xee, 0x2c, 0x5c, 0x3f, 0xac, 0x5f, 0xfe, 0xf4, 0x33, 0x5a, 0x78,
- 0x61, 0xe7, 0xa5, 0x8a, 0xc3, 0xe3, 0x71, 0x8b, 0xfd, 0xa9, 0xfb, 0x8e,
- 0x07, 0x58, 0xbf, 0xef, 0x0b, 0xf2, 0x3f, 0xb0, 0x16, 0x2f, 0xfa, 0x61,
- 0x8c, 0x59, 0x26, 0xac, 0x5f, 0xff, 0xbf, 0x3a, 0x07, 0x30, 0x7e, 0x13,
- 0xf5, 0x9a, 0x58, 0xad, 0xc4, 0x64, 0x44, 0x75, 0xe3, 0x7b, 0xbc, 0x75,
- 0x8b, 0xf6, 0x1c, 0xf2, 0x35, 0x8b, 0xff, 0x07, 0x1f, 0x25, 0xbb, 0xf4,
- 0x9d, 0x62, 0xff, 0xee, 0x3b, 0xf5, 0x9d, 0x49, 0x4f, 0x4b, 0x16, 0xc8,
- 0x91, 0x5f, 0xf2, 0x8e, 0x21, 0x5e, 0x9d, 0x71, 0x62, 0xff, 0xf6, 0x6f,
- 0x2c, 0xe7, 0x5f, 0x6d, 0xd6, 0xe2, 0xc5, 0xff, 0x4c, 0x03, 0xcd, 0x73,
- 0x0c, 0x58, 0xbf, 0xd0, 0x93, 0x5b, 0xef, 0x1a, 0xc5, 0xff, 0x00, 0x65,
- 0x30, 0xff, 0x00, 0xb1, 0x51, 0xa2, 0xa9, 0x8e, 0xf4, 0x6b, 0x78, 0x84,
- 0x35, 0x8a, 0x1a, 0xb9, 0x0c, 0x87, 0xe7, 0x66, 0x9f, 0x86, 0x38, 0x0d,
- 0x88, 0x74, 0x50, 0xf9, 0x0c, 0xc2, 0xfc, 0x4e, 0xc4, 0x05, 0x8b, 0xf1,
- 0x82, 0x9d, 0x46, 0xb1, 0x5b, 0x4f, 0x44, 0xc2, 0x6b, 0xff, 0x99, 0xc1,
- 0xa9, 0x2f, 0x7f, 0x20, 0xb1, 0x7f, 0xb5, 0x93, 0xdc, 0x18, 0xeb, 0x17,
- 0xf6, 0x4f, 0x70, 0x63, 0xac, 0x5f, 0x4f, 0x4c, 0x5b, 0x4f, 0x8b, 0x46,
- 0x94, 0xc9, 0x82, 0x7c, 0x94, 0xa1, 0x4b, 0x73, 0x1d, 0x62, 0xfa, 0x1f,
- 0x0f, 0x8b, 0x17, 0x38, 0x6a, 0x88, 0x5c, 0xae, 0xcf, 0x28, 0x44, 0xb5,
- 0x12, 0x21, 0x3c, 0xc3, 0x7e, 0xfe, 0x46, 0x22, 0x58, 0xbe, 0x7d, 0x4e,
- 0xf5, 0x8a, 0x19, 0xe6, 0x80, 0xa6, 0xfe, 0xfb, 0x97, 0xb3, 0xeb, 0x17,
- 0xd0, 0xc7, 0x25, 0x8b, 0xfd, 0x1e, 0x40, 0x84, 0xfc, 0x58, 0xa6, 0x44,
- 0x14, 0x45, 0xae, 0x43, 0x7a, 0x4f, 0x05, 0x8b, 0xc4, 0x23, 0x56, 0x2b,
- 0xb3, 0x76, 0x43, 0xb7, 0xdf, 0x69, 0x89, 0x62, 0xc1, 0x25, 0xb5, 0x25,
- 0x8c, 0x92, 0x03, 0xe3, 0x32, 0xc9, 0xc2, 0x23, 0x61, 0x12, 0xcf, 0xb1,
- 0x43, 0xdf, 0x51, 0x8d, 0x9e, 0x18, 0x5f, 0x96, 0x6c, 0xf0, 0xa7, 0x01,
- 0x71, 0x42, 0x9f, 0x92, 0xec, 0x3d, 0x1e, 0xb8, 0xa1, 0x71, 0xbd, 0xc7,
- 0x66, 0x14, 0x81, 0xb5, 0x6e, 0x90, 0xdf, 0xb3, 0x5c, 0x69, 0x58, 0xbc,
- 0x16, 0xf6, 0x16, 0xc6, 0xb1, 0x7f, 0xed, 0x0a, 0x3c, 0xfc, 0x45, 0x23,
- 0x58, 0xbe, 0x29, 0xc3, 0x56, 0x2f, 0xf7, 0xbf, 0x99, 0xef, 0xe2, 0xc5,
- 0xfd, 0xf9, 0x7e, 0xc7, 0xda, 0xc5, 0xe3, 0x75, 0xda, 0xc5, 0xf6, 0x1c,
- 0x47, 0x58, 0xbf, 0xda, 0x92, 0xc1, 0x8e, 0x56, 0x2f, 0xfc, 0xe4, 0x6b,
- 0xfa, 0x7c, 0xe0, 0x58, 0xbe, 0x18, 0x72, 0x4b, 0x17, 0xff, 0xf3, 0x78,
- 0x5a, 0x7e, 0x61, 0x7f, 0x30, 0xa1, 0xc5, 0x8a, 0x93, 0xfc, 0x72, 0x3a,
- 0x58, 0xbf, 0x3e, 0x7b, 0x0e, 0xb1, 0x70, 0x26, 0x4d, 0x99, 0x06, 0x5f,
- 0x85, 0xa0, 0x6d, 0x95, 0x8b, 0xbe, 0xeb, 0x17, 0x31, 0xab, 0x16, 0x12,
- 0xc5, 0x61, 0xe0, 0xc4, 0x2f, 0xc1, 0x8b, 0xee, 0x7e, 0x40, 0xb1, 0x7d,
- 0xe9, 0x2d, 0xeb, 0x16, 0xf2, 0xc5, 0xff, 0xd3, 0xa9, 0xea, 0x58, 0x0f,
- 0xe1, 0x2c, 0x57, 0xcf, 0xeb, 0xc4, 0x9b, 0x22, 0x57, 0x81, 0xc0, 0x9b,
- 0x02, 0xe1, 0x90, 0x5a, 0x93, 0xc9, 0x78, 0xd0, 0x70, 0x8b, 0xa3, 0x3e,
- 0xcc, 0x18, 0x83, 0x44, 0x67, 0x32, 0xfc, 0x2e, 0x80, 0xa7, 0xc2, 0xaf,
- 0x36, 0x08, 0xbc, 0x38, 0x4e, 0xdf, 0x86, 0x13, 0x1b, 0x71, 0x62, 0xff,
- 0xf3, 0x43, 0x81, 0x33, 0xb8, 0x3c, 0x61, 0xf4, 0xb1, 0x52, 0x7f, 0xd8,
- 0x5b, 0x52, 0x9d, 0x27, 0xe3, 0x84, 0xbf, 0xe0, 0xa0, 0x57, 0x59, 0xe6,
- 0xf8, 0x96, 0x2f, 0xb8, 0xd1, 0x85, 0x56, 0x2f, 0xc2, 0x22, 0x68, 0x2c,
- 0x50, 0x51, 0x12, 0x3b, 0x12, 0x17, 0x0a, 0x2f, 0xfc, 0x14, 0x0a, 0xb4,
- 0x73, 0xb7, 0xae, 0x62, 0xc5, 0xc1, 0x61, 0x2c, 0x5e, 0xfe, 0x69, 0x62,
- 0x82, 0x88, 0x84, 0xd8, 0x92, 0xfe, 0x39, 0x7f, 0xec, 0x81, 0x39, 0xb1,
- 0x72, 0x7c, 0xb1, 0x7d, 0xe6, 0xd6, 0x2c, 0x56, 0xc3, 0x3e, 0x2c, 0x40,
- 0xbf, 0xec, 0xf0, 0x71, 0xbe, 0x9a, 0x25, 0x8b, 0xfa, 0x01, 0x64, 0x61,
- 0x50, 0xb5, 0xd8, 0x4b, 0x17, 0x8b, 0x3e, 0xb1, 0x7f, 0x31, 0xf2, 0x74,
- 0x6a, 0xc5, 0x0c, 0xf2, 0xba, 0x1c, 0xbc, 0x16, 0xf6, 0x1e, 0xc0, 0xb1,
- 0x7f, 0xb3, 0x9c, 0xc6, 0x2e, 0x96, 0x2b, 0x62, 0x4d, 0xe4, 0x2a, 0x4f,
- 0xb0, 0x1e, 0x6c, 0x70, 0x91, 0x0b, 0x52, 0x32, 0x2f, 0xbd, 0xa7, 0xe2,
- 0xc5, 0xfc, 0x14, 0x0f, 0xff, 0xc8, 0xd6, 0x2e, 0xd9, 0xed, 0x62, 0xdf,
- 0x58, 0xad, 0xa8, 0x80, 0x0a, 0x0e, 0xec, 0x33, 0x51, 0x0e, 0x5f, 0xf0,
- 0x57, 0x98, 0x45, 0x8f, 0xd2, 0xc5, 0x9d, 0x62, 0x82, 0x87, 0x9b, 0xd9,
- 0xe5, 0xc6, 0xca, 0xc5, 0xe8, 0xb9, 0x2b, 0x17, 0xc3, 0xc2, 0x89, 0x62,
- 0xe6, 0xf2, 0xc5, 0x31, 0xba, 0xf9, 0x1d, 0x1c, 0xfe, 0x3c, 0xb1, 0x7f,
- 0xbb, 0xf7, 0x70, 0x11, 0x1a, 0xb1, 0x7f, 0xe9, 0x88, 0xb3, 0x7b, 0x9c,
- 0xec, 0xb1, 0x4e, 0x7f, 0x02, 0x38, 0xbf, 0x00, 0x0f, 0xdf, 0x16, 0x2f,
- 0xff, 0xf8, 0x6d, 0x9a, 0x88, 0xb3, 0x7f, 0xf0, 0x73, 0xce, 0x49, 0xab,
- 0x16, 0xfb, 0x22, 0x4c, 0x45, 0x57, 0xff, 0x9a, 0x28, 0x67, 0x70, 0xda,
- 0x77, 0x72, 0x58, 0xb9, 0xf7, 0x56, 0x2f, 0xff, 0xf7, 0x33, 0xdb, 0x7f,
- 0x9d, 0x49, 0x85, 0x83, 0xfb, 0x44, 0xb1, 0x51, 0xaa, 0xd2, 0xc8, 0x48,
- 0x1b, 0x09, 0xae, 0xa1, 0x69, 0xf2, 0x87, 0x4d, 0xf0, 0xd5, 0x6c, 0x4a,
- 0xdb, 0xc2, 0xb2, 0xbe, 0x6f, 0x6c, 0x44, 0x4b, 0x17, 0xfb, 0xb9, 0xf6,
- 0x67, 0x70, 0x58, 0xbf, 0xb1, 0xbc, 0x53, 0xda, 0xc5, 0x8d, 0x58, 0xa0,
- 0xa2, 0x25, 0x82, 0xc2, 0x10, 0xb5, 0x35, 0xd9, 0x2d, 0xba, 0x3f, 0xac,
- 0x5e, 0xd7, 0x38, 0xb1, 0x71, 0x71, 0x62, 0x82, 0xa6, 0xd7, 0x78, 0xf5,
- 0xe3, 0xcf, 0x4b, 0x15, 0xb1, 0x9e, 0x2e, 0x13, 0xdf, 0xdb, 0x04, 0x98,
- 0xfd, 0x4a, 0xc5, 0xfc, 0x16, 0xbb, 0x11, 0x6c, 0xc9, 0xd6, 0x2b, 0x60,
- 0x3f, 0x10, 0xb5, 0x34, 0xbf, 0xff, 0x0f, 0x6e, 0x70, 0xa3, 0x8d, 0xf7,
- 0x36, 0xed, 0xfe, 0xca, 0xc5, 0xfc, 0xe5, 0x1f, 0xe7, 0x71, 0x62, 0xf1,
- 0xc3, 0xe2, 0xc5, 0xe8, 0x48, 0x16, 0x28, 0x67, 0xdb, 0x86, 0x2e, 0x3f,
- 0x7e, 0xfb, 0xf9, 0xe0, 0xb1, 0x7f, 0x82, 0xbb, 0x78, 0x03, 0xe7, 0x16,
- 0x2f, 0x8b, 0x33, 0x4b, 0x17, 0x7d, 0xd6, 0x2c, 0xda, 0x37, 0x1b, 0xc8,
- 0x6f, 0x75, 0x1f, 0xd6, 0x2f, 0xf8, 0x1b, 0x79, 0x2d, 0x1b, 0xf9, 0x62,
- 0xfd, 0x3c, 0x0b, 0x61, 0x40, 0xa2, 0xc5, 0xc7, 0x3a, 0xc5, 0x32, 0x22,
- 0xf8, 0x78, 0x23, 0x7b, 0xf4, 0xf0, 0x5f, 0x65, 0x8a, 0xda, 0x98, 0x14,
- 0x21, 0x57, 0xc2, 0xfa, 0x58, 0xbf, 0x41, 0xf4, 0xfd, 0x2c, 0x5c, 0xd1,
- 0x2c, 0x54, 0x9e, 0x0e, 0x14, 0xdf, 0xe2, 0xce, 0xe0, 0x4f, 0x1a, 0xc5,
- 0x68, 0xf5, 0x38, 0x41, 0x7e, 0xe0, 0x9c, 0x80, 0xb1, 0x5b, 0x4f, 0x2b,
- 0xc4, 0x57, 0xf1, 0x66, 0xf2, 0xce, 0x2c, 0x51, 0xcf, 0x48, 0x04, 0x97,
- 0xb8, 0xc0, 0x58, 0xbe, 0x62, 0x9e, 0x2c, 0x56, 0x1f, 0x03, 0x11, 0x7c,
- 0x76, 0xf1, 0x86, 0x18, 0x91, 0x7b, 0xdf, 0xc4, 0x80, 0x86, 0x86, 0xfc,
- 0xc6, 0xb9, 0x01, 0x62, 0xce, 0x47, 0xaf, 0xe2, 0xfb, 0xff, 0xff, 0xa6,
- 0x3d, 0xbc, 0x14, 0xf7, 0xef, 0xe1, 0xf3, 0xc5, 0x20, 0x04, 0xac, 0x5d,
- 0xb3, 0x8b, 0x17, 0xde, 0x8b, 0x3c, 0xb1, 0x61, 0xac, 0x5b, 0x75, 0x62,
- 0x86, 0x8d, 0xac, 0x75, 0x71, 0xa1, 0x12, 0x06, 0x25, 0x52, 0xae, 0x2c,
- 0x71, 0xce, 0x82, 0x14, 0xa5, 0x18, 0x05, 0xfb, 0xe5, 0xb0, 0xb6, 0x77,
- 0x56, 0x2e, 0x77, 0x58, 0xb7, 0xd8, 0xf2, 0xdc, 0xd6, 0xff, 0xfe, 0x06,
- 0xa7, 0x6e, 0xa7, 0xdd, 0xc2, 0x4d, 0xd3, 0x98, 0xb1, 0x7c, 0x1f, 0x1c,
- 0x0b, 0x17, 0x45, 0xf5, 0x8b, 0xff, 0x1f, 0x6e, 0x36, 0x98, 0xf2, 0x6a,
- 0xc5, 0x31, 0xed, 0x38, 0xcd, 0xff, 0x9a, 0x2d, 0xbf, 0x96, 0xd0, 0xb7,
- 0x16, 0x2a, 0x53, 0x44, 0xd3, 0x0f, 0xdf, 0x80, 0x41, 0x7f, 0xfe, 0xeb,
- 0xe4, 0x2f, 0x6d, 0x2c, 0xdd, 0xf3, 0x66, 0xea, 0xc5, 0xc2, 0xfa, 0xc5,
- 0xef, 0x0b, 0x71, 0x62, 0xfb, 0x77, 0x5c, 0xe2, 0xc5, 0x61, 0xe4, 0x31,
- 0x0d, 0x4a, 0x37, 0x8d, 0x5e, 0xd3, 0x05, 0xff, 0xd8, 0x5d, 0xfb, 0x6f,
- 0x00, 0x7c, 0xe2, 0xc5, 0xf8, 0x5e, 0x68, 0xe5, 0x62, 0xb0, 0xfc, 0x49,
- 0x22, 0xff, 0x7e, 0x63, 0xd4, 0xe0, 0xd6, 0x2f, 0xcd, 0xcf, 0x67, 0xd6,
- 0x2f, 0xf4, 0x94, 0xf2, 0x58, 0xeb, 0x17, 0x9f, 0xdc, 0x58, 0xa3, 0x4f,
- 0x3b, 0x46, 0x37, 0xb7, 0x47, 0x2b, 0x15, 0x28, 0xed, 0xe8, 0xd1, 0x9d,
- 0x84, 0x47, 0x7b, 0xee, 0x17, 0x58, 0xbf, 0x6f, 0x14, 0x33, 0x8b, 0x17,
- 0xc0, 0x62, 0x12, 0xc5, 0x61, 0xe6, 0x88, 0xae, 0xfb, 0x07, 0x91, 0xac,
- 0x5f, 0x6e, 0x6d, 0x9d, 0x89, 0x62, 0xff, 0x14, 0xec, 0xe1, 0x31, 0xab,
- 0x17, 0xfb, 0xcf, 0xdf, 0x1f, 0xb3, 0x16, 0x2d, 0x2b, 0x17, 0x9a, 0x49,
- 0x62, 0xb4, 0x6b, 0x3c, 0x23, 0x5b, 0x13, 0x34, 0x9c, 0x70, 0xd2, 0xc2,
- 0xd3, 0x4a, 0x3a, 0x73, 0xee, 0x32, 0xa6, 0x97, 0x87, 0xb9, 0x09, 0x98,
- 0xa3, 0x6a, 0xd4, 0x63, 0x67, 0x85, 0x0f, 0xe3, 0x0d, 0x0b, 0x9e, 0x13,
- 0x77, 0x88, 0x77, 0x91, 0xec, 0x96, 0x86, 0x6b, 0xba, 0xc7, 0x7e, 0xd6,
- 0x6f, 0x9e, 0xd6, 0x2f, 0x16, 0x79, 0x62, 0xff, 0xf7, 0x70, 0xe7, 0x25,
- 0xbb, 0xf7, 0xa4, 0xeb, 0x15, 0xa4, 0x4a, 0x11, 0x59, 0x83, 0x97, 0xfe,
- 0x8f, 0x0a, 0x4c, 0xf1, 0xaf, 0xc5, 0x8b, 0xfd, 0x9b, 0xdd, 0xba, 0xc2,
- 0x58, 0xb8, 0xbd, 0x87, 0xea, 0x48, 0x37, 0xbc, 0xd8, 0xb1, 0x7b, 0x06,
- 0xcb, 0x15, 0xb4, 0xdc, 0x48, 0xe5, 0x32, 0x21, 0x4c, 0x63, 0xbc, 0x2f,
- 0x71, 0x62, 0xff, 0xb7, 0x1f, 0xd1, 0x41, 0xb5, 0x12, 0xc5, 0xfb, 0x6f,
- 0x52, 0x67, 0x6b, 0x17, 0xfd, 0x30, 0x31, 0xf5, 0xe9, 0xc5, 0x8b, 0xff,
- 0xff, 0xfe, 0xe6, 0xdf, 0xe4, 0x72, 0x67, 0x70, 0xe6, 0xd1, 0x75, 0xad,
- 0x4e, 0xd8, 0x8d, 0xef, 0x6e, 0xdf, 0xec, 0xac, 0x5f, 0xdd, 0xed, 0x8b,
- 0x33, 0xa5, 0x8a, 0x95, 0x5e, 0x39, 0x19, 0x57, 0x44, 0x6e, 0x3c, 0x03,
- 0xf2, 0x2e, 0xf1, 0xc8, 0xa1, 0x5b, 0x7e, 0xfc, 0x82, 0x77, 0x16, 0x2c,
- 0x62, 0xc5, 0xfd, 0x08, 0x1e, 0x29, 0xdd, 0x58, 0xb0, 0x16, 0x29, 0x91,
- 0x06, 0x02, 0xb2, 0x13, 0x11, 0x9d, 0xdb, 0x32, 0xb1, 0x7a, 0x4d, 0x65,
- 0x8b, 0xa4, 0xeb, 0x17, 0x4f, 0x6b, 0x17, 0xf7, 0x30, 0xfb, 0xc7, 0x8b,
- 0x14, 0x33, 0xdf, 0x88, 0x5f, 0x83, 0x14, 0x48, 0xc6, 0xe0, 0xd7, 0x9f,
- 0x2e, 0xd9, 0x0a, 0x2c, 0x5f, 0xfe, 0x04, 0x97, 0x5b, 0x70, 0x85, 0x0c,
- 0xe2, 0xc5, 0xf8, 0x1a, 0x6e, 0xc0, 0xb1, 0x7f, 0x6d, 0xef, 0xc5, 0x23,
- 0x58, 0xb3, 0xf6, 0x7b, 0x7c, 0x2a, 0xbf, 0xf0, 0x8f, 0x39, 0xc2, 0xcd,
- 0xee, 0xb1, 0x7f, 0x39, 0x64, 0x61, 0xc1, 0x62, 0xfd, 0x31, 0x3b, 0xe9,
- 0x62, 0x80, 0x7a, 0xfc, 0x2f, 0xae, 0xd3, 0x87, 0xfc, 0x29, 0xf8, 0x51,
- 0xe8, 0x4b, 0x5e, 0xdb, 0x0e, 0x96, 0x2f, 0xf3, 0x6d, 0xe3, 0xcf, 0x70,
- 0x58, 0xbf, 0xee, 0x6d, 0xc2, 0x91, 0x05, 0xf8, 0xb1, 0x7b, 0x6f, 0x70,
- 0x58, 0xa9, 0x57, 0xad, 0x91, 0x80, 0x9a, 0x5e, 0xd1, 0xd3, 0x1d, 0x27,
- 0xe4, 0x24, 0x6d, 0xc3, 0xfb, 0xff, 0xfb, 0x5b, 0x4b, 0x37, 0xe6, 0xa1,
- 0xb6, 0x46, 0xf1, 0x71, 0x62, 0xff, 0xf6, 0xbe, 0x63, 0x8f, 0x68, 0x60,
- 0x03, 0x6e, 0xac, 0x5f, 0xfd, 0x86, 0x6e, 0x9c, 0x4c, 0x7c, 0x20, 0x2c,
- 0x5f, 0xff, 0xfb, 0xb9, 0x34, 0xb0, 0x7f, 0x68, 0xb6, 0xf3, 0x3b, 0x86,
- 0xb0, 0xc5, 0x8a, 0x64, 0x5d, 0x92, 0x45, 0x62, 0x72, 0x2e, 0xc4, 0x51,
- 0x87, 0x5f, 0x78, 0x53, 0x1a, 0xc5, 0xfd, 0x07, 0xd7, 0x18, 0x6b, 0x17,
- 0xf6, 0x7f, 0x0f, 0x3d, 0x2c, 0x5c, 0x3c, 0x58, 0xa9, 0x3f, 0x38, 0x17,
- 0x31, 0x75, 0xf9, 0xb4, 0xdb, 0xf1, 0x62, 0x99, 0x1d, 0xbe, 0x84, 0xbe,
- 0xe9, 0x6d, 0xf6, 0xce, 0x6a, 0x56, 0x2f, 0xe9, 0xe7, 0xe4, 0xbc, 0xb1,
- 0x7f, 0xff, 0x77, 0x0e, 0x1f, 0x0b, 0x6e, 0xeb, 0x7e, 0x36, 0xcd, 0x2c,
- 0x5b, 0x71, 0x62, 0xf7, 0xb3, 0x8b, 0x15, 0x04, 0x60, 0xe1, 0x6f, 0x4c,
- 0x42, 0x15, 0xbf, 0xff, 0xc5, 0x9d, 0x7d, 0x8b, 0x05, 0xdf, 0xb6, 0xb9,
- 0x98, 0x6a, 0xc5, 0xe6, 0x8f, 0x8b, 0x17, 0xfe, 0xce, 0x9e, 0x3f, 0xe7,
- 0x58, 0x4b, 0x16, 0x33, 0x6a, 0x30, 0xf1, 0x97, 0xe3, 0xd7, 0xf8, 0xd1,
- 0x8a, 0x7e, 0x52, 0xb1, 0x7f, 0x43, 0x86, 0x8a, 0x7b, 0x58, 0xbe, 0xc1,
- 0xbc, 0x16, 0x2b, 0xb3, 0xd3, 0x30, 0xc6, 0xfb, 0x53, 0x31, 0xac, 0x5f,
- 0x45, 0x3e, 0x75, 0x8b, 0xfe, 0x8e, 0x63, 0xe4, 0xc4, 0xdb, 0xd6, 0x2e,
- 0x73, 0x38, 0x88, 0x41, 0x11, 0x86, 0x47, 0x7b, 0x7f, 0x83, 0x58, 0xa9,
- 0x4f, 0x17, 0x0e, 0x1a, 0x10, 0xe5, 0x0a, 0x83, 0x0f, 0x6f, 0x07, 0x24,
- 0xb1, 0x7f, 0xcd, 0xa8, 0xc4, 0x0c, 0x2c, 0x58, 0xba, 0x23, 0xac, 0x5f,
- 0xe8, 0x73, 0xc2, 0xc1, 0xed, 0x88, 0xf4, 0x80, 0x73, 0x7f, 0xfd, 0x83,
- 0xf8, 0x8c, 0xe3, 0x7b, 0xec, 0xe0, 0x58, 0xae, 0xd1, 0x3e, 0x49, 0xd7,
- 0x1e, 0x0b, 0x17, 0xff, 0xa7, 0x5d, 0x1a, 0x0c, 0x72, 0xee, 0x1c, 0x58,
- 0xa8, 0x1f, 0x2f, 0x06, 0x2f, 0xb3, 0x52, 0x75, 0x8b, 0xc5, 0x9b, 0xf6,
- 0x9e, 0x21, 0x11, 0x5f, 0xff, 0xf7, 0x0b, 0x06, 0xc6, 0x6d, 0x2c, 0xdd,
- 0xf3, 0x70, 0x53, 0xa5, 0x8a, 0xd2, 0x6d, 0x9c, 0x86, 0x67, 0x8d, 0x6f,
- 0xf1, 0x1a, 0x58, 0xdd, 0xf9, 0x62, 0xdb, 0xd6, 0x2b, 0x0f, 0x23, 0x86,
- 0x95, 0x28, 0x9f, 0x13, 0xf5, 0xf4, 0xe7, 0xf8, 0xb1, 0x73, 0x46, 0xb1,
- 0x60, 0x44, 0x6e, 0xbc, 0x45, 0x7f, 0xba, 0x2c, 0x1f, 0xdf, 0x8b, 0x17,
- 0xf0, 0x30, 0x87, 0xf9, 0x58, 0xbf, 0xbe, 0xc4, 0x00, 0xce, 0xb1, 0x4c,
- 0x7b, 0x9e, 0x2d, 0xb8, 0x6c, 0xb1, 0x7f, 0xff, 0x7d, 0xb0, 0xb1, 0x87,
- 0x92, 0x07, 0xe9, 0xf4, 0xb1, 0x7f, 0xa3, 0x93, 0x94, 0xf6, 0x05, 0x8a,
- 0x94, 0xd5, 0x61, 0x09, 0x0e, 0x88, 0x7b, 0x17, 0x75, 0x8b, 0xf7, 0xf6,
- 0xbe, 0x71, 0x62, 0xa4, 0xfe, 0xb1, 0x42, 0xc2, 0x58, 0xbf, 0xbc, 0x53,
- 0x0c, 0xf2, 0xc5, 0xf1, 0x16, 0x79, 0x62, 0xe8, 0xc4, 0xb1, 0x78, 0xc7,
- 0xe2, 0xc5, 0xe7, 0xd4, 0x36, 0xa2, 0x16, 0x4b, 0x58, 0x87, 0xe3, 0x35,
- 0x2c, 0xbc, 0x6c, 0x8c, 0x87, 0xb3, 0x76, 0x87, 0x36, 0xa5, 0x62, 0x9d,
- 0x4b, 0xf2, 0xc6, 0x5d, 0x70, 0xa3, 0xf7, 0xe1, 0x00, 0xa1, 0x2f, 0x7f,
- 0xed, 0x34, 0x6e, 0x72, 0xec, 0x44, 0xb1, 0x6d, 0xc5, 0x8b, 0x79, 0x62,
- 0xe9, 0x02, 0xc5, 0xff, 0xe6, 0x10, 0x5e, 0x76, 0xf0, 0x40, 0x3e, 0x79,
- 0x62, 0xbb, 0x3e, 0x8d, 0x0b, 0xdf, 0xfd, 0xd7, 0xe7, 0x9e, 0xd4, 0xf7,
- 0xf6, 0x58, 0xbf, 0xf4, 0xf5, 0xc9, 0x6e, 0xfd, 0x27, 0x58, 0xa5, 0x8b,
- 0xda, 0x16, 0xe2, 0xc5, 0x40, 0xd6, 0xf8, 0x32, 0xa5, 0x1a, 0xa4, 0x8e,
- 0x26, 0xdb, 0xe0, 0x72, 0x3f, 0x2c, 0x5f, 0xcf, 0xf9, 0x29, 0x82, 0xc5,
- 0xff, 0xff, 0xbd, 0x92, 0x59, 0xd1, 0x3c, 0x73, 0xad, 0x4f, 0xbf, 0x83,
- 0x58, 0xbe, 0xde, 0x59, 0xcd, 0xa8, 0x97, 0xc2, 0xcb, 0xff, 0xec, 0x2c,
- 0x37, 0xef, 0x0f, 0x98, 0xe1, 0x9d, 0x62, 0xff, 0xce, 0x6e, 0xdf, 0x3b,
- 0x96, 0xd8, 0xd6, 0x2a, 0x53, 0x8e, 0x68, 0x5e, 0x7c, 0xf0, 0x94, 0xaf,
- 0xc0, 0xc3, 0xcf, 0x4b, 0x17, 0x9f, 0xdc, 0x58, 0xb8, 0x51, 0xac, 0x54,
- 0x0d, 0xb6, 0x87, 0x6f, 0xd9, 0x0f, 0xbc, 0x16, 0x2a, 0x23, 0xc9, 0xf9,
- 0x0d, 0x8a, 0x51, 0x97, 0xe8, 0x54, 0x5f, 0xe7, 0x20, 0xff, 0xf9, 0x1a,
- 0xc5, 0xff, 0xf7, 0xb9, 0x39, 0xb7, 0x53, 0xe6, 0xe9, 0x86, 0xb1, 0x7e,
- 0xeb, 0x68, 0xfb, 0x31, 0x62, 0xb8, 0x88, 0x11, 0x29, 0x5e, 0xee, 0x4d,
- 0x58, 0xbf, 0xff, 0xfb, 0x53, 0xb7, 0xf9, 0xbb, 0xe9, 0xd7, 0x45, 0x9e,
- 0xd0, 0xbb, 0x87, 0x16, 0x2f, 0x19, 0xfc, 0x24, 0x4c, 0xf8, 0x7e, 0xf8,
- 0x51, 0x38, 0xd6, 0x2f, 0xd9, 0xed, 0x61, 0x8b, 0x16, 0xeb, 0x69, 0xe6,
- 0xfc, 0x92, 0xa5, 0x15, 0x8d, 0x08, 0x1b, 0xb5, 0x05, 0x8b, 0xfc, 0x6b,
- 0xf3, 0x3c, 0x1c, 0x6b, 0x17, 0xdb, 0x7a, 0x32, 0x56, 0x2a, 0x07, 0xbc,
- 0x73, 0x7a, 0x95, 0x60, 0xfd, 0x96, 0x34, 0x2d, 0x75, 0x1b, 0x41, 0xc9,
- 0x9d, 0xda, 0xfd, 0xb1, 0xe9, 0xa4, 0xd5, 0x8b, 0xf7, 0xbf, 0x2d, 0xd2,
- 0xc5, 0x1a, 0x7a, 0xfe, 0x2e, 0xbf, 0x0c, 0x9d, 0xfe, 0xb1, 0x44, 0x79,
- 0x5c, 0x23, 0xbf, 0x67, 0x3c, 0xfa, 0x58, 0xbf, 0xfd, 0xcc, 0x72, 0xdb,
- 0xce, 0xe4, 0xa7, 0x8b, 0x16, 0x87, 0xcf, 0xcf, 0xc5, 0x17, 0xf4, 0x8e,
- 0x7f, 0x30, 0x58, 0xbf, 0xd3, 0xed, 0xaf, 0xd3, 0x6f, 0x58, 0xad, 0x1f,
- 0x29, 0x16, 0xdf, 0xff, 0xf9, 0xbb, 0xf3, 0xfc, 0xb0, 0x7f, 0x68, 0xb9,
- 0xd6, 0x31, 0x44, 0xb1, 0x7f, 0xfd, 0x3e, 0xda, 0x42, 0xdd, 0xdb, 0x9e,
- 0xd9, 0xcf, 0x2c, 0x54, 0xa6, 0xec, 0xd0, 0x8d, 0xd1, 0x08, 0x9b, 0xae,
- 0x7f, 0x2c, 0x5f, 0xfd, 0xf9, 0x37, 0x6f, 0x89, 0xfd, 0x3e, 0x58, 0xbf,
- 0xbb, 0x83, 0x7c, 0x47, 0x58, 0xb9, 0xa3, 0x58, 0xad, 0xa7, 0x91, 0xe3,
- 0x0a, 0xfa, 0x32, 0x80, 0x2e, 0x50, 0x8f, 0xbf, 0x18, 0xff, 0x88, 0x28,
- 0xb1, 0x7f, 0xd8, 0x3d, 0xbe, 0x35, 0x8c, 0xe2, 0xc5, 0xb3, 0x47, 0xdb,
- 0xbc, 0xbe, 0xff, 0xf4, 0x93, 0xed, 0xfb, 0xb7, 0x38, 0xc7, 0x58, 0xbf,
- 0x9f, 0xe6, 0xce, 0x9d, 0x62, 0xff, 0xda, 0x8b, 0x6f, 0x25, 0xa3, 0x7f,
- 0x2c, 0x54, 0xa7, 0x0a, 0x38, 0x50, 0xfc, 0xa4, 0x92, 0x84, 0x5d, 0x73,
- 0x81, 0x62, 0xff, 0xfb, 0x69, 0x4f, 0x26, 0x32, 0xc1, 0xfd, 0xa2, 0x58,
- 0xbf, 0xff, 0xfb, 0x9a, 0x29, 0x8b, 0x68, 0x7e, 0x68, 0x67, 0x7e, 0xcd,
- 0xe5, 0x9c, 0x58, 0xad, 0x23, 0x28, 0x94, 0xab, 0xc9, 0x81, 0x8a, 0x1c,
- 0x34, 0xb1, 0x4b, 0x17, 0xf4, 0xb1, 0x3e, 0x8d, 0x58, 0xbb, 0xdb, 0x4d,
- 0x37, 0x3f, 0x0c, 0xbc, 0x69, 0xb2, 0xb1, 0x68, 0x2c, 0x53, 0x1b, 0x18,
- 0x87, 0xef, 0xfe, 0xce, 0xe1, 0xb7, 0x22, 0xfc, 0x91, 0xab, 0x15, 0x29,
- 0x88, 0x76, 0x8b, 0xa6, 0x13, 0x90, 0xdf, 0xed, 0x16, 0x75, 0x93, 0xb8,
- 0xb1, 0x7f, 0xf1, 0x7b, 0x9b, 0xdb, 0xd3, 0x85, 0x12, 0xc5, 0xff, 0xb5,
- 0x1e, 0x67, 0x06, 0x4f, 0xf5, 0x8b, 0xf6, 0x9b, 0x93, 0xda, 0xc5, 0x4a,
- 0x39, 0x30, 0xd9, 0x91, 0x9c, 0xfe, 0xff, 0xfd, 0x0e, 0x00, 0x51, 0x6d,
- 0xc6, 0xd3, 0x1e, 0x4d, 0x58, 0xbf, 0x82, 0xb1, 0x41, 0xbd, 0xc5, 0x8b,
- 0xdc, 0x0f, 0x8b, 0x15, 0x19, 0xe9, 0x9c, 0xd2, 0xe9, 0x02, 0xc5, 0xf8,
- 0xbd, 0xfc, 0xdd, 0x58, 0xbf, 0x45, 0xc7, 0xd1, 0xab, 0x17, 0x9c, 0xcd,
- 0x49, 0xeb, 0x61, 0x5d, 0xff, 0x11, 0xb3, 0x13, 0x14, 0x9d, 0x62, 0xfe,
- 0x35, 0xe0, 0x52, 0x75, 0x8a, 0x93, 0xe7, 0x63, 0x9a, 0x82, 0xa2, 0xfe,
- 0xce, 0x5a, 0x15, 0xb1, 0x11, 0xe9, 0xb7, 0xf0, 0x99, 0xbe, 0x6e, 0x9f,
- 0x4b, 0x17, 0x8e, 0xe6, 0x2c, 0x5b, 0x90, 0x3c, 0x17, 0x23, 0xbe, 0xcd,
- 0xef, 0xa5, 0x8b, 0xf8, 0x78, 0x50, 0xfe, 0x2c, 0x54, 0x9e, 0x8b, 0x12,
- 0x5f, 0xff, 0xb9, 0xb7, 0x18, 0xcd, 0xa5, 0x80, 0x2c, 0x78, 0x96, 0x2f,
- 0xfb, 0xed, 0xa8, 0xbe, 0xf9, 0xa5, 0x8b, 0xff, 0xff, 0xf8, 0x1c, 0x2c,
- 0x7e, 0xf6, 0x8f, 0xe2, 0xda, 0x59, 0xdc, 0x30, 0x51, 0x96, 0x3f, 0x6b,
- 0x15, 0x89, 0x91, 0x74, 0xb2, 0xc7, 0x57, 0xb3, 0x90, 0x58, 0xb9, 0xfa,
- 0x54, 0x53, 0x05, 0x8d, 0x58, 0xaf, 0x9e, 0xab, 0x8e, 0x88, 0x96, 0xfd,
- 0x1b, 0x9f, 0x9b, 0x2b, 0x15, 0x2a, 0xa6, 0xa3, 0x78, 0xc8, 0xd0, 0xba,
- 0x84, 0x2b, 0x17, 0x5f, 0xff, 0xef, 0x70, 0x3e, 0x6d, 0xc8, 0x7e, 0x5b,
- 0x40, 0x3b, 0xc1, 0x62, 0xff, 0x8b, 0xb8, 0x73, 0xd3, 0xa8, 0x96, 0x2f,
- 0x16, 0x7d, 0x62, 0xff, 0xba, 0x13, 0xff, 0x3c, 0xff, 0x58, 0xa1, 0x9e,
- 0xb7, 0x63, 0x95, 0x88, 0xb5, 0xf4, 0x24, 0xaf, 0xfc, 0xfd, 0xe3, 0x69,
- 0x8f, 0x26, 0xac, 0x5e, 0x0e, 0x49, 0x62, 0xf6, 0x30, 0x16, 0x2d, 0x8b,
- 0x16, 0xc0, 0x1a, 0xdd, 0xe3, 0x97, 0x34, 0x6b, 0x14, 0xb0, 0xe5, 0xc5,
- 0xda, 0xc5, 0x8b, 0x77, 0xb5, 0x17, 0x64, 0x95, 0xc4, 0x01, 0x0d, 0x56,
- 0x2a, 0x80, 0x68, 0xc6, 0xb4, 0x4e, 0xf0, 0xfa, 0xbd, 0x82, 0xd2, 0xc5,
- 0xa2, 0x58, 0xbe, 0x16, 0x76, 0x4b, 0x15, 0x19, 0xb6, 0x38, 0x9d, 0x8c,
- 0x58, 0xb9, 0x86, 0xb1, 0x5b, 0x86, 0xab, 0x82, 0x77, 0x0e, 0x25, 0x8b,
- 0xfe, 0xd6, 0x0f, 0xf2, 0x61, 0xc4, 0xb1, 0x7f, 0x7f, 0x06, 0xc5, 0xe5,
- 0x8b, 0x46, 0xb1, 0x77, 0xf8, 0xb1, 0x46, 0x9a, 0xb7, 0x13, 0xbf, 0x89,
- 0xcc, 0xf6, 0x7d, 0x62, 0xa5, 0x36, 0xbc, 0x4c, 0x39, 0x27, 0xc6, 0x7c,
- 0x76, 0x62, 0xc6, 0xc9, 0x0d, 0xfb, 0xe2, 0x37, 0x23, 0x58, 0xbf, 0x61,
- 0xce, 0xe7, 0x58, 0xb8, 0xe0, 0x58, 0xbb, 0xef, 0xb5, 0x1a, 0x43, 0x67,
- 0xd1, 0x58, 0x0a, 0x2f, 0xed, 0x4f, 0x89, 0xc0, 0xb1, 0x5a, 0x3f, 0x7d,
- 0xd4, 0xab, 0xfd, 0xb7, 0xb8, 0x14, 0xe7, 0x16, 0x2b, 0xb5, 0x6c, 0x4d,
- 0x2c, 0x1d, 0xc9, 0x6f, 0xff, 0xc0, 0x6e, 0x6d, 0xfb, 0xf3, 0xd3, 0x17,
- 0x3f, 0x8b, 0x14, 0xb1, 0x7f, 0x09, 0x86, 0xc4, 0xcb, 0x16, 0x35, 0x8d,
- 0xc1, 0xc3, 0x2f, 0xcf, 0xcf, 0xbc, 0x16, 0x2f, 0x9e, 0x0c, 0x75, 0x8b,
- 0xf7, 0x4f, 0xac, 0xe9, 0x62, 0xff, 0x85, 0xdc, 0x39, 0xb7, 0x9e, 0xe9,
- 0x62, 0xfe, 0x2f, 0x43, 0x01, 0xc5, 0x8b, 0xc6, 0xbf, 0x36, 0xa2, 0x63,
- 0x45, 0x4e, 0x81, 0x5f, 0x47, 0xef, 0xa1, 0x75, 0x5a, 0x4d, 0xd3, 0xe4,
- 0xe6, 0x46, 0x4b, 0x7f, 0x37, 0xdd, 0xa3, 0x95, 0x8b, 0xd0, 0x9e, 0xd6,
- 0x2f, 0xe3, 0x75, 0xac, 0xef, 0x8b, 0x17, 0xff, 0xe2, 0xce, 0xfd, 0xb7,
- 0xef, 0xbf, 0x68, 0xfe, 0x28, 0xd6, 0x2f, 0xdf, 0x98, 0xf0, 0xc5, 0x8b,
- 0x1e, 0x51, 0x12, 0x35, 0xfb, 0xfb, 0x39, 0x06, 0x06, 0x2c, 0x5e, 0x86,
- 0x79, 0x62, 0xa0, 0x79, 0x5e, 0x2d, 0xa9, 0x4f, 0x47, 0x0e, 0x3b, 0x2d,
- 0x61, 0xe7, 0x85, 0xd0, 0x9c, 0xaf, 0xff, 0x0d, 0xb0, 0xcd, 0xbc, 0x96,
- 0x8d, 0xfc, 0xb1, 0x7c, 0xdc, 0x9e, 0xd6, 0x2b, 0xb3, 0xf0, 0xfa, 0x6d,
- 0xfb, 0xbe, 0x8a, 0x77, 0xac, 0x5f, 0xfe, 0x20, 0x10, 0xb8, 0x59, 0xee,
- 0x37, 0x16, 0x2f, 0xe7, 0xd4, 0x50, 0x6f, 0xac, 0x5f, 0xe1, 0x47, 0xf6,
- 0xdf, 0x91, 0x2c, 0x5f, 0xc1, 0xff, 0xf2, 0x5d, 0x2c, 0x5f, 0x14, 0x9f,
- 0x8b, 0x17, 0x3f, 0x7c, 0x3d, 0x2f, 0x18, 0x54, 0xa6, 0xff, 0x84, 0x6c,
- 0x58, 0xe9, 0x3c, 0x2f, 0x14, 0x22, 0xae, 0xe7, 0x16, 0x2d, 0x8b, 0x17,
- 0xfc, 0xc6, 0xb7, 0x8b, 0x37, 0x76, 0xe8, 0xd4, 0xef, 0x18, 0xbf, 0xcc,
- 0x40, 0xc3, 0xbf, 0x6b, 0x15, 0x12, 0x22, 0x37, 0xaa, 0xdf, 0xff, 0xe2,
- 0xce, 0xbd, 0xe9, 0xf7, 0x22, 0x2c, 0x33, 0x6c, 0xec, 0x4b, 0x17, 0xfe,
- 0xea, 0x4f, 0xfc, 0xe6, 0x31, 0x2c, 0x54, 0xa2, 0xa3, 0xed, 0x57, 0xff,
- 0xfe, 0x84, 0xeb, 0xb8, 0x73, 0x6f, 0x05, 0x3d, 0x93, 0xfb, 0xef, 0x12,
- 0xc5, 0xfb, 0x53, 0xbe, 0x74, 0xb1, 0x7d, 0x3d, 0x61, 0xd6, 0x2f, 0xf6,
- 0xdc, 0xe7, 0x1b, 0x0c, 0x58, 0xa8, 0x8f, 0x67, 0x44, 0x77, 0xff, 0xff,
- 0xd8, 0xc3, 0xdb, 0x9f, 0x6d, 0x7d, 0xf6, 0xff, 0x06, 0x58, 0xfd, 0xe4,
- 0x6b, 0x14, 0xc8, 0xa3, 0xf9, 0x1d, 0xfc, 0xe5, 0xb4, 0x72, 0x4b, 0x15,
- 0x2a, 0xb6, 0x32, 0x19, 0xdd, 0x91, 0x33, 0x97, 0x23, 0x26, 0x11, 0x15,
- 0xf1, 0x78, 0xd6, 0x58, 0xbe, 0xc3, 0xcf, 0x4b, 0x17, 0xf7, 0x4d, 0x1e,
- 0x77, 0xe5, 0x8a, 0x81, 0xea, 0x18, 0x47, 0x6d, 0x95, 0x8b, 0xf8, 0x1b,
- 0x67, 0xa7, 0x0d, 0x62, 0xff, 0xa7, 0x0a, 0x1b, 0x67, 0x7c, 0xac, 0x51,
- 0xa8, 0x82, 0x21, 0x5f, 0x19, 0x54, 0xa3, 0x55, 0xa1, 0x4b, 0x7a, 0x75,
- 0x05, 0x8b, 0xff, 0xfd, 0xa1, 0x77, 0x0e, 0x6d, 0x92, 0x1f, 0xe7, 0x67,
- 0x35, 0x2b, 0x15, 0xb5, 0xd4, 0xae, 0x6c, 0x08, 0x01, 0x6c, 0x56, 0x5e,
- 0xa3, 0x87, 0xc4, 0x23, 0xbc, 0x1c, 0xe0, 0x96, 0x46, 0x06, 0x6c, 0xa0,
- 0xae, 0xa5, 0x48, 0x77, 0x1a, 0x8b, 0x46, 0x73, 0x14, 0xb5, 0x1d, 0x4b,
- 0x3f, 0x3c, 0xad, 0x6f, 0xcb, 0xa9, 0x01, 0xc1, 0x4b, 0xd6, 0xe4, 0xa4,
- 0x9f, 0x4b, 0xe2, 0x13, 0x16, 0xf8, 0xd3, 0x0c, 0x26, 0xdd, 0x1d, 0xbd,
- 0x1e, 0x46, 0xb1, 0x7f, 0x9c, 0xcd, 0xae, 0x37, 0x8d, 0x62, 0xff, 0xef,
- 0x70, 0x7f, 0x9d, 0x91, 0x7d, 0xb4, 0xb1, 0x5a, 0x44, 0x00, 0x8d, 0xef,
- 0x43, 0xbe, 0x96, 0x2f, 0xe7, 0x32, 0x22, 0x61, 0xac, 0x5d, 0x00, 0x2c,
- 0x5d, 0x19, 0xd6, 0x2b, 0x69, 0xb1, 0x61, 0x8b, 0xff, 0xf1, 0x34, 0x7b,
- 0x5b, 0x0b, 0x3a, 0xdd, 0xf6, 0x1d, 0x62, 0xf1, 0xe7, 0xa5, 0x8b, 0xdd,
- 0xff, 0x22, 0x3f, 0x80, 0x2d, 0x5f, 0xff, 0xd9, 0x1b, 0x97, 0xb9, 0x3d,
- 0x6d, 0x39, 0xd8, 0xba, 0x58, 0xbf, 0xa1, 0xc8, 0xa1, 0x31, 0x2c, 0x50,
- 0xd1, 0x21, 0xda, 0xfd, 0xfc, 0x3e, 0x3c, 0xf7, 0x05, 0x8a, 0x93, 0xd3,
- 0x72, 0x4b, 0xfe, 0x2d, 0xba, 0xc6, 0xfc, 0x8d, 0x62, 0xb1, 0x5a, 0x71,
- 0xb0, 0x9f, 0x62, 0x3d, 0x10, 0x7d, 0x81, 0xe1, 0x34, 0x51, 0x8c, 0x08,
- 0x82, 0xfb, 0x08, 0xdd, 0xc5, 0x8b, 0xff, 0xff, 0xf7, 0xdb, 0xdf, 0xcd,
- 0x4e, 0xfd, 0xa7, 0x16, 0xee, 0xdc, 0xee, 0x18, 0x22, 0x07, 0x16, 0x2d,
- 0xe6, 0x45, 0xa7, 0x09, 0xaf, 0xff, 0x8a, 0x2f, 0xcb, 0x69, 0x8e, 0xdb,
- 0x32, 0x75, 0x8b, 0x98, 0xeb, 0x17, 0xff, 0xdd, 0xc0, 0x9a, 0x2d, 0xa5,
- 0x9e, 0xe3, 0x69, 0x62, 0x99, 0x17, 0x91, 0x29, 0x18, 0x2f, 0x7f, 0xc7,
- 0x68, 0xbe, 0xe5, 0x32, 0xb1, 0x7f, 0xe0, 0x36, 0x6b, 0x6e, 0xf9, 0x1e,
- 0xe2, 0xc5, 0x1c, 0xff, 0xb7, 0x4e, 0x2f, 0xf3, 0xc2, 0x2f, 0xb7, 0x7e,
- 0x58, 0xbf, 0xd0, 0xe4, 0x9b, 0xe6, 0x8d, 0x62, 0xff, 0x08, 0xbd, 0x3b,
- 0xdf, 0xeb, 0x17, 0xfe, 0x73, 0x3d, 0x9f, 0xc2, 0x78, 0x2c, 0x54, 0x0f,
- 0xcc, 0x8d, 0x6f, 0xff, 0xbb, 0xc1, 0x11, 0xbe, 0xd4, 0xf6, 0x0e, 0x4a,
- 0xc5, 0xff, 0xa7, 0xad, 0xa4, 0xfc, 0x3c, 0x92, 0xc5, 0xfa, 0x4b, 0xdb,
- 0x46, 0xb1, 0x7f, 0x49, 0xf3, 0x08, 0xd5, 0x8b, 0xf7, 0xb6, 0x83, 0xb0,
- 0x2c, 0x53, 0x22, 0x13, 0xe5, 0x42, 0x2d, 0xbf, 0xfd, 0xf6, 0xeb, 0xf9,
- 0xb7, 0x82, 0xfc, 0xee, 0x2c, 0x5f, 0xc5, 0x3d, 0xc1, 0x89, 0x62, 0x96,
- 0x2f, 0xf6, 0x7c, 0xb3, 0xdf, 0x65, 0x8a, 0x19, 0xf5, 0x91, 0x6f, 0x83,
- 0x2f, 0xfb, 0xd3, 0x0e, 0x45, 0x09, 0x8d, 0x62, 0xd9, 0x89, 0x93, 0x77,
- 0x0b, 0xcf, 0x17, 0x5f, 0xff, 0x7b, 0xf8, 0x0d, 0xa7, 0x9c, 0xf0, 0xf0,
- 0x96, 0x2d, 0xa5, 0x8b, 0x18, 0xb1, 0x7f, 0x38, 0xf5, 0xa1, 0x46, 0xb1,
- 0x7e, 0x9c, 0x2f, 0x6c, 0xac, 0x5b, 0x60, 0x58, 0xac, 0x44, 0xb1, 0xa2,
- 0x5d, 0x09, 0x9c, 0xc3, 0x85, 0x57, 0xde, 0x6d, 0x62, 0xc5, 0xbb, 0xda,
- 0x7d, 0xb8, 0x97, 0x6e, 0x62, 0x6f, 0xcf, 0x1a, 0xa5, 0x0d, 0x75, 0x4f,
- 0xb3, 0x68, 0xa1, 0x53, 0xa2, 0x13, 0xa9, 0xfe, 0x18, 0x85, 0x1a, 0xaf,
- 0xa3, 0xb9, 0xbf, 0xff, 0x8b, 0x0c, 0xc8, 0xf6, 0xee, 0x63, 0x9b, 0xb7,
- 0x46, 0x69, 0x62, 0xff, 0xff, 0xf3, 0x61, 0xf3, 0xed, 0x87, 0xda, 0x59,
- 0xef, 0xe4, 0x3e, 0xd8, 0x75, 0x8b, 0xff, 0xff, 0xa0, 0xdc, 0x2c, 0xdf,
- 0xfc, 0x8b, 0xf2, 0x51, 0x6d, 0x7e, 0x9b, 0x7a, 0xc5, 0xff, 0xe6, 0xc3,
- 0x0b, 0x39, 0x9f, 0xfb, 0x71, 0x62, 0xd9, 0xda, 0x30, 0xbc, 0xf3, 0x7f,
- 0xff, 0x36, 0x18, 0x59, 0x1e, 0x0b, 0xc4, 0xe6, 0xbf, 0x16, 0x2f, 0xfd,
- 0x9a, 0xfc, 0xed, 0x7f, 0x0a, 0x56, 0x2f, 0xfe, 0xe6, 0x75, 0xb7, 0xb8,
- 0x70, 0x9a, 0x25, 0x8b, 0xff, 0xff, 0x16, 0x6f, 0xfe, 0x6b, 0x59, 0xee,
- 0x6e, 0xfa, 0x79, 0xf6, 0xc5, 0x8b, 0x4f, 0x91, 0x74, 0x62, 0x55, 0x32,
- 0x64, 0x7a, 0x87, 0xd5, 0xff, 0xff, 0x61, 0x1b, 0xb7, 0x53, 0xbd, 0xbd,
- 0xcc, 0x35, 0xb4, 0xfd, 0xac, 0x54, 0x6a, 0xf6, 0x7e, 0xcc, 0x51, 0x9c,
- 0x70, 0xa7, 0xd1, 0xbf, 0x06, 0x51, 0x4c, 0xb9, 0x94, 0x29, 0xc6, 0x4b,
- 0xff, 0xcc, 0x3d, 0xa7, 0x6d, 0xb2, 0x37, 0x8b, 0x8b, 0x17, 0xef, 0xb7,
- 0xb0, 0xeb, 0x16, 0x82, 0xc5, 0xfd, 0xee, 0xfa, 0x6f, 0xc4, 0xb1, 0x41,
- 0x53, 0xec, 0x81, 0x47, 0x04, 0xad, 0xa9, 0x47, 0x74, 0x70, 0xbb, 0xbf,
- 0x73, 0x92, 0x5d, 0x2c, 0x5f, 0xff, 0x14, 0x5b, 0x7f, 0xd3, 0x73, 0x07,
- 0x1e, 0x18, 0xb1, 0x74, 0x7f, 0xc3, 0xff, 0x72, 0x9b, 0xf4, 0x27, 0xb8,
- 0x71, 0x62, 0xff, 0xff, 0xff, 0xd8, 0x46, 0xed, 0x6f, 0x88, 0x24, 0x4d,
- 0xe9, 0x39, 0x39, 0xbf, 0x60, 0x99, 0xfe, 0xc1, 0x23, 0x48, 0xbf, 0xff,
- 0xcd, 0xaf, 0xe7, 0x6f, 0xde, 0xd3, 0x90, 0xbd, 0xb7, 0x7f, 0x16, 0x2f,
- 0xff, 0xfc, 0xc6, 0x0c, 0x5a, 0xda, 0x29, 0x8f, 0x9d, 0x7c, 0x5f, 0xed,
- 0xcc, 0x58, 0xbf, 0xff, 0xb3, 0x7c, 0x96, 0xde, 0x36, 0x9c, 0x0e, 0x51,
- 0x4a, 0xc5, 0x74, 0x8d, 0x3f, 0xbb, 0x5a, 0x3e, 0xd5, 0x16, 0xb1, 0x51,
- 0xe1, 0x45, 0xc8, 0xcf, 0x6b, 0x15, 0x55, 0x8a, 0x52, 0xd5, 0xf8, 0xb3,
- 0xdf, 0x65, 0x8b, 0xff, 0x7d, 0xb3, 0xa9, 0xf7, 0xdb, 0x16, 0x28, 0xd3,
- 0xe5, 0xdd, 0x27, 0xb8, 0x78, 0xb1, 0x52, 0xd8, 0x8a, 0xe4, 0x39, 0x1a,
- 0x15, 0xff, 0xa5, 0x21, 0x3c, 0x63, 0x65, 0x2d, 0x60, 0x50, 0x90, 0xd9,
- 0x26, 0xbb, 0x34, 0xb1, 0x6d, 0xd5, 0x8b, 0x1d, 0x62, 0xff, 0x3c, 0x30,
- 0xee, 0x40, 0x58, 0xbe, 0xcf, 0xcc, 0x4b, 0x15, 0xb0, 0x1f, 0x3f, 0xc4,
- 0x9c, 0xca, 0xee, 0x62, 0xc5, 0xc7, 0xeb, 0x69, 0xe5, 0x31, 0x9d, 0xb7,
- 0x16, 0x2f, 0xde, 0x11, 0x03, 0x8b, 0x17, 0xff, 0xff, 0x74, 0x59, 0xbf,
- 0x6f, 0x1b, 0x08, 0x1b, 0x4b, 0x37, 0x96, 0x73, 0x7a, 0xc5, 0xff, 0x1a,
- 0xfe, 0xe4, 0x44, 0xc6, 0x2c, 0x5f, 0x39, 0xdb, 0x8b, 0x17, 0xef, 0xb9,
- 0xdb, 0x8b, 0x14, 0x6a, 0x21, 0xbe, 0x79, 0xc2, 0x2a, 0xd2, 0x66, 0x25,
- 0x18, 0x05, 0xff, 0xef, 0x8b, 0x08, 0xdd, 0xbe, 0xee, 0x18, 0x4b, 0x17,
- 0xfb, 0x1c, 0xfb, 0x76, 0x64, 0xeb, 0x17, 0xff, 0xa1, 0x3c, 0xf8, 0xb5,
- 0x9e, 0xf3, 0x1d, 0x62, 0x86, 0x8d, 0x1e, 0x93, 0xbb, 0x38, 0xbf, 0xf1,
- 0x60, 0x8d, 0xd3, 0x49, 0xf1, 0x62, 0xff, 0xfc, 0x29, 0xda, 0x58, 0x3f,
- 0xb1, 0xa3, 0x93, 0x40, 0xb1, 0x58, 0x9e, 0x1e, 0xa1, 0xf4, 0x73, 0x22,
- 0x3e, 0xbf, 0xfd, 0xef, 0xe6, 0xef, 0xa2, 0xcd, 0xc7, 0x20, 0x2c, 0x5f,
- 0xe9, 0x3b, 0x97, 0x70, 0x95, 0x8a, 0x24, 0x42, 0x79, 0x46, 0xff, 0xec,
- 0x60, 0x6d, 0x2c, 0xde, 0xda, 0x75, 0x8a, 0x63, 0xe8, 0xf1, 0x15, 0xf1,
- 0x9b, 0x79, 0x12, 0xc5, 0xbc, 0xb1, 0x52, 0x6e, 0x9c, 0xa2, 0xff, 0xc5,
- 0x19, 0x66, 0xfe, 0x0a, 0x7b, 0x58, 0xbf, 0xef, 0xcf, 0x7b, 0x76, 0x16,
- 0xf0, 0x32, 0xc5, 0xfb, 0xdd, 0xc1, 0xb6, 0x56, 0x28, 0x67, 0xe5, 0xc4,
- 0x5a, 0x94, 0x6b, 0x47, 0x0b, 0x4a, 0x82, 0xee, 0xbe, 0x0a, 0xb4, 0xb1,
- 0xde, 0x46, 0x5b, 0xe5, 0xb1, 0x43, 0xd6, 0xfd, 0xbf, 0x77, 0xd9, 0xf5,
- 0x8b, 0xff, 0x67, 0x05, 0x26, 0xf2, 0x75, 0x12, 0xc5, 0x31, 0xf7, 0x98,
- 0x5d, 0x7d, 0xa8, 0x38, 0xd6, 0x2e, 0x7e, 0x96, 0x2f, 0xda, 0xcd, 0x96,
- 0x02, 0xc5, 0xfe, 0xeb, 0xed, 0xf2, 0x14, 0x6b, 0x17, 0xe9, 0xec, 0x1a,
- 0x95, 0x8a, 0x81, 0xef, 0xf8, 0xda, 0xa3, 0x45, 0x61, 0x42, 0x2a, 0xf7,
- 0xb0, 0x2e, 0xb1, 0x41, 0x54, 0xc3, 0x66, 0x18, 0x98, 0x51, 0x7f, 0xa7,
- 0x3c, 0x00, 0xca, 0x0b, 0x17, 0x67, 0xd6, 0x28, 0x8f, 0x2f, 0x64, 0xd2,
- 0xe3, 0x65, 0x62, 0xec, 0x1a, 0xc5, 0x6d, 0x64, 0xf2, 0xec, 0x42, 0xf1,
- 0xc3, 0x1a, 0x13, 0xc0, 0xf9, 0x0d, 0x97, 0x22, 0xe4, 0x66, 0x1e, 0x84,
- 0x18, 0x89, 0x37, 0x8c, 0x5f, 0x9b, 0xdc, 0xc0, 0x2c, 0x5f, 0xbf, 0x9b,
- 0xdb, 0x7a, 0xc5, 0xff, 0xf6, 0x6b, 0xb7, 0x8b, 0x6f, 0xdb, 0x45, 0x91,
- 0xac, 0x5f, 0xff, 0xef, 0x7e, 0x62, 0xda, 0x59, 0xf6, 0xf7, 0x05, 0xd0,
- 0xa5, 0x62, 0xc4, 0x6a, 0x2e, 0x5d, 0x52, 0xec, 0x02, 0xc5, 0xff, 0xc4,
- 0x02, 0xc6, 0x8b, 0xf2, 0x46, 0xac, 0x53, 0x1e, 0xdb, 0x8b, 0xdf, 0xd0,
- 0xe7, 0x9a, 0x7b, 0x58, 0xbf, 0xff, 0xe7, 0x8b, 0x6f, 0x39, 0x9f, 0xd6,
- 0xb0, 0xc2, 0xc3, 0x1c, 0x0b, 0x17, 0xe9, 0x2f, 0xbc, 0x16, 0x2f, 0xfb,
- 0xd9, 0x1c, 0xf1, 0xb5, 0x8b, 0x17, 0xa4, 0x72, 0xb1, 0x43, 0x3f, 0xce,
- 0xc9, 0xce, 0x73, 0x4b, 0x14, 0xb1, 0x7f, 0xde, 0xc8, 0xe7, 0x8d, 0xac,
- 0x58, 0xbd, 0x23, 0x95, 0x8b, 0xdc, 0x78, 0xb6, 0xa2, 0x76, 0x4c, 0x30,
- 0x33, 0xb0, 0xc3, 0x9c, 0xdb, 0x09, 0x3e, 0x1f, 0x47, 0x09, 0x7d, 0xb0,
- 0x05, 0xbd, 0x8f, 0x60, 0x58, 0xbe, 0x67, 0x21, 0xac, 0x58, 0xcd, 0xa7,
- 0xb4, 0x33, 0x9b, 0xf6, 0x3f, 0x70, 0xe2, 0xc5, 0xfc, 0xf1, 0x7b, 0x0b,
- 0xcb, 0x14, 0x03, 0xd7, 0x30, 0xa6, 0xa0, 0x99, 0x6b, 0x42, 0x23, 0x90,
- 0x82, 0xbe, 0xeb, 0xed, 0xd2, 0xc5, 0xf0, 0xbf, 0x27, 0x58, 0xbf, 0xfe,
- 0x16, 0xb5, 0x25, 0x86, 0xb7, 0xff, 0x81, 0xac, 0x54, 0xa2, 0x67, 0x09,
- 0x74, 0x47, 0x7d, 0xf9, 0x11, 0x2c, 0x5f, 0x09, 0xfb, 0xf2, 0xc5, 0xc5,
- 0xe5, 0x8b, 0xff, 0xff, 0x8d, 0xcd, 0x69, 0x8f, 0xb6, 0x28, 0x08, 0xfd,
- 0xc3, 0x9c, 0x9d, 0x74, 0xb1, 0x77, 0xdd, 0x62, 0xce, 0xc8, 0x92, 0xde,
- 0xf7, 0x7c, 0xc6, 0xc9, 0xd6, 0x2f, 0xe9, 0x2f, 0x7f, 0x06, 0xb1, 0x52,
- 0x7a, 0x1c, 0x23, 0xbc, 0x21, 0xca, 0xc5, 0xff, 0xf3, 0x0d, 0x9f, 0xcc,
- 0xfe, 0xdb, 0xc6, 0x89, 0x62, 0xa0, 0xbf, 0xca, 0x32, 0x8c, 0x87, 0x29,
- 0xb0, 0x83, 0xec, 0x82, 0x29, 0x67, 0xba, 0x86, 0x99, 0xcb, 0xbe, 0x44,
- 0xe4, 0x85, 0x0a, 0x9e, 0x3c, 0xef, 0x21, 0xd9, 0x1d, 0xb6, 0xea, 0xc5,
- 0xe8, 0xe6, 0x35, 0x8a, 0x58, 0xbf, 0xb0, 0xe3, 0xfe, 0x71, 0x62, 0xfd,
- 0x1e, 0xde, 0x9a, 0x35, 0x8b, 0xfb, 0x9d, 0x74, 0xe4, 0x6a, 0xc5, 0x05,
- 0x88, 0x99, 0x8c, 0x33, 0x45, 0xde, 0x2e, 0xbf, 0xc5, 0xb7, 0x7f, 0x70,
- 0xe4, 0x4b, 0x17, 0xfd, 0x0e, 0x7d, 0xb0, 0xb3, 0x7a, 0xc5, 0xff, 0xfe,
- 0x1f, 0xf3, 0xde, 0x72, 0xeb, 0x1b, 0x4c, 0x79, 0x35, 0x62, 0xe8, 0xfb,
- 0x58, 0xbf, 0x7d, 0xf7, 0x24, 0x0b, 0x14, 0x34, 0xc6, 0xfb, 0x3b, 0x63,
- 0xa7, 0x61, 0xdd, 0x1a, 0xbf, 0x6d, 0x0e, 0x39, 0x8d, 0x62, 0xfc, 0x59,
- 0xf7, 0xf2, 0xc5, 0x40, 0xf5, 0x62, 0x2e, 0xbf, 0x8d, 0x6e, 0xf8, 0x2e,
- 0x2c, 0x56, 0x8f, 0x50, 0x88, 0xef, 0x87, 0xb6, 0x77, 0x16, 0x2a, 0x55,
- 0x4e, 0xe4, 0x6b, 0xcd, 0x0f, 0x60, 0xc8, 0x6f, 0xf4, 0xed, 0x2c, 0xdf,
- 0x9f, 0x58, 0xb3, 0x2c, 0x5f, 0xf0, 0x8b, 0x6c, 0x4d, 0x18, 0xa2, 0x58,
- 0xbf, 0xb0, 0x71, 0x42, 0x77, 0x16, 0x2f, 0xfe, 0xf1, 0xb3, 0xdc, 0x39,
- 0xdc, 0x24, 0xd5, 0x8b, 0x1d, 0x62, 0xfe, 0x39, 0x39, 0xbf, 0x6d, 0xa7,
- 0xb9, 0x1a, 0x55, 0xff, 0x1f, 0x8f, 0x16, 0xef, 0xf2, 0x35, 0x8a, 0x94,
- 0x43, 0x62, 0x3d, 0x46, 0x9b, 0xa6, 0x8f, 0xfd, 0x18, 0xa5, 0xff, 0xa3,
- 0xda, 0x59, 0xee, 0x7f, 0x0d, 0x58, 0xbb, 0x09, 0x62, 0xf4, 0x24, 0x0b,
- 0x16, 0xd0, 0xcd, 0x9e, 0x0b, 0x5f, 0x03, 0x9b, 0x9d, 0x2c, 0x54, 0xa3,
- 0x11, 0x9d, 0x84, 0x4d, 0x7f, 0x7f, 0xaf, 0xce, 0xa2, 0x58, 0xbf, 0x03,
- 0x3c, 0x1c, 0x6b, 0x17, 0xf8, 0xb0, 0xcd, 0xdf, 0x67, 0xd6, 0x2f, 0xee,
- 0x67, 0xfc, 0xc6, 0xac, 0x5f, 0xf7, 0x3e, 0x28, 0xb6, 0x99, 0xb9, 0xda,
- 0xc5, 0x8c, 0x89, 0x15, 0x5c, 0x37, 0xf1, 0x7d, 0xbc, 0xb1, 0x6e, 0x2c,
- 0x5f, 0x8c, 0xf6, 0x7f, 0x69, 0xa6, 0x93, 0xb1, 0x2b, 0xd1, 0xc0, 0xd5,
- 0x8a, 0x94, 0xe5, 0x32, 0x1a, 0xae, 0xb8, 0x24, 0x3a, 0xd8, 0xd9, 0x13,
- 0x92, 0x2b, 0x09, 0x6a, 0xa6, 0xa4, 0x74, 0x6c, 0xd1, 0xc2, 0xfe, 0x1f,
- 0x8e, 0x5c, 0x51, 0xe2, 0xdf, 0xfd, 0x07, 0xe6, 0x46, 0xfe, 0x8f, 0x0c,
- 0x58, 0xbf, 0xec, 0xfe, 0xd0, 0xdf, 0x73, 0xf8, 0xb1, 0x7f, 0x7f, 0x3a,
- 0x84, 0x9d, 0x62, 0xff, 0x7f, 0x20, 0xe5, 0x9d, 0xac, 0x56, 0x1f, 0x17,
- 0x8b, 0xef, 0xff, 0xfd, 0x09, 0x8f, 0xb8, 0x71, 0x8d, 0xdb, 0xcc, 0xe9,
- 0x8e, 0x2d, 0x46, 0xb1, 0x7b, 0xdd, 0x0d, 0x62, 0xff, 0x61, 0x9b, 0x7e,
- 0xd8, 0x75, 0x8b, 0xff, 0xe8, 0xf1, 0x8b, 0xc5, 0x9b, 0xf6, 0xf0, 0xc2,
- 0x58, 0xb9, 0xc1, 0xb5, 0x15, 0x31, 0x8f, 0xf0, 0xda, 0xbb, 0x4d, 0x70,
- 0xa3, 0x1e, 0xbf, 0xff, 0x9b, 0xdc, 0xc3, 0x58, 0x88, 0x4e, 0x0f, 0x38,
- 0x16, 0x2f, 0xef, 0xe1, 0x77, 0x26, 0xac, 0x5f, 0xce, 0x5e, 0x16, 0xa3,
- 0x58, 0xa6, 0x56, 0x8e, 0x04, 0x72, 0x85, 0x0f, 0xa3, 0x7d, 0xde, 0x54,
- 0x62, 0xd0, 0x65, 0xf7, 0x77, 0xe5, 0x8b, 0x6e, 0xac, 0x56, 0xd3, 0x5c,
- 0x31, 0x9b, 0xd8, 0xd1, 0x2c, 0x5f, 0xf9, 0xb2, 0x2d, 0xbc, 0x9f, 0xbe,
- 0xe2, 0xc5, 0xfe, 0x7e, 0xff, 0x9e, 0x03, 0xac, 0x5d, 0x91, 0x2c, 0x56,
- 0x1e, 0x63, 0x1a, 0x5f, 0xfa, 0x7f, 0xb7, 0x59, 0x1e, 0x39, 0xd6, 0x2f,
- 0xff, 0x70, 0x58, 0x5b, 0x4b, 0x3f, 0xf7, 0x1a, 0xc5, 0xfe, 0xc8, 0xf6,
- 0xc5, 0x18, 0x34, 0xb1, 0x50, 0x44, 0x2f, 0x92, 0xef, 0x8a, 0x75, 0x2b,
- 0x17, 0xff, 0xf0, 0xf6, 0xf1, 0xb6, 0x64, 0x81, 0xfc, 0x2c, 0x6f, 0xac,
- 0x5f, 0xfe, 0x6d, 0x99, 0x20, 0x7f, 0x0b, 0x1b, 0xeb, 0x17, 0xc5, 0x87,
- 0xda, 0x48, 0xa8, 0xe2, 0xf5, 0xff, 0x77, 0x93, 0xdc, 0x45, 0x27, 0x58,
- 0xbf, 0xbb, 0xe7, 0xf1, 0xf4, 0xb1, 0x7f, 0xff, 0xe6, 0x3e, 0x9b, 0x3b,
- 0x21, 0x7a, 0x7f, 0xb7, 0x7b, 0x7a, 0x29, 0x58, 0xa7, 0x45, 0x07, 0x8b,
- 0xef, 0xfd, 0x25, 0xe9, 0x83, 0x11, 0xb2, 0xb1, 0x51, 0xab, 0xf3, 0x18,
- 0xe9, 0xb0, 0x90, 0xe8, 0x83, 0xb8, 0x63, 0x31, 0x1c, 0x50, 0xc9, 0xf9,
- 0xd7, 0xa1, 0xb7, 0xbc, 0x8a, 0xff, 0xfb, 0x1e, 0x3f, 0xcb, 0x7b, 0x93,
- 0x1e, 0x71, 0x62, 0xff, 0x6a, 0x39, 0x6d, 0x61, 0x2c, 0x5e, 0x37, 0x91,
- 0x2c, 0x56, 0x1e, 0x9f, 0x66, 0x76, 0x3a, 0xc6, 0xd3, 0x45, 0x7d, 0x13,
- 0x64, 0x6b, 0x17, 0x8b, 0x06, 0xb1, 0x7e, 0x06, 0x0b, 0x51, 0xac, 0x5c,
- 0x1f, 0x16, 0x2f, 0x0f, 0xf2, 0xb1, 0xb4, 0xb9, 0xac, 0x3f, 0x11, 0x21,
- 0xdf, 0x6d, 0xfb, 0xc4, 0xb1, 0x52, 0x98, 0xe6, 0x12, 0x76, 0x48, 0x50,
- 0x8d, 0xe1, 0x0d, 0xf8, 0xa7, 0x0c, 0x8d, 0x62, 0xf6, 0xc8, 0xbc, 0xb1,
- 0x7e, 0xf7, 0x09, 0x8d, 0x58, 0xad, 0x8c, 0xfc, 0xe0, 0x52, 0x72, 0x1b,
- 0xfb, 0xbe, 0x66, 0x11, 0xab, 0x17, 0xc7, 0x0e, 0x40, 0xb1, 0x7f, 0xfa,
- 0x31, 0xe9, 0xfa, 0x2c, 0xdf, 0xa6, 0xe2, 0xc5, 0x4a, 0x35, 0x70, 0xd1,
- 0x8b, 0xc4, 0x49, 0x77, 0xb8, 0xb1, 0x7f, 0x7b, 0xef, 0x10, 0x67, 0x58,
- 0xa5, 0x8b, 0x7d, 0x62, 0xbe, 0x5f, 0x38, 0x65, 0xd9, 0xc5, 0x8b, 0x9f,
- 0x4b, 0x16, 0x04, 0x0d, 0x76, 0x85, 0xef, 0x9e, 0x01, 0x8d, 0x62, 0xde,
- 0x93, 0xcb, 0xf9, 0x3d, 0x3a, 0x61, 0xc0, 0x4f, 0x28, 0x4c, 0x5c, 0x70,
- 0xd6, 0x2e, 0x91, 0xac, 0x5d, 0xc6, 0x58, 0xbb, 0xb0, 0x2c, 0x57, 0xcf,
- 0x1c, 0x2e, 0x2e, 0x21, 0x7b, 0xff, 0x44, 0xdc, 0x0f, 0xb0, 0x3b, 0x46,
- 0xb1, 0x7d, 0xd8, 0x35, 0x2b, 0x16, 0xe6, 0xd3, 0xe7, 0x94, 0x3b, 0x86,
- 0xcb, 0x15, 0x2c, 0xba, 0x38, 0xe1, 0x43, 0x93, 0x82, 0xdd, 0x42, 0x9d,
- 0xa3, 0xe1, 0xd4, 0x72, 0xdf, 0x3a, 0x78, 0xc9, 0x80, 0x68, 0x4c, 0x1c,
- 0x84, 0xd6, 0xf2, 0x9b, 0xdb, 0xff, 0x8b, 0x17, 0xcc, 0x79, 0xfa, 0xc5,
- 0xf9, 0xff, 0xb4, 0x72, 0xb1, 0x4c, 0x7d, 0x7f, 0x1f, 0xf1, 0x15, 0xfd,
- 0xe2, 0x98, 0x67, 0x96, 0x2f, 0xb0, 0x9e, 0x0b, 0x17, 0xde, 0xe0, 0x7c,
- 0xda, 0x79, 0xdb, 0x19, 0x6d, 0xfe, 0xf3, 0x47, 0x9f, 0x17, 0x96, 0x2d,
- 0x8b, 0x17, 0xb9, 0x26, 0xac, 0x57, 0xcd, 0x7f, 0x84, 0x6d, 0x12, 0xc5,
- 0xfd, 0x82, 0xcf, 0xf5, 0x1a, 0xc5, 0x49, 0xe1, 0xf0, 0x4e, 0xfd, 0xb7,
- 0x07, 0x84, 0xb1, 0x5d, 0x9e, 0x51, 0x10, 0xde, 0xfc, 0x8d, 0x62, 0xa5,
- 0x1d, 0xb9, 0x0a, 0xe8, 0x88, 0xaf, 0xff, 0xe1, 0x6d, 0xeb, 0xec, 0x32,
- 0x97, 0x8f, 0xaf, 0xbe, 0x96, 0x2f, 0xec, 0xd0, 0x18, 0xbc, 0xb1, 0x77,
- 0x7d, 0xac, 0x58, 0xfb, 0x4f, 0x1c, 0xe5, 0xb7, 0xef, 0x34, 0x64, 0xeb,
- 0x17, 0xff, 0x7b, 0x9b, 0x77, 0x7d, 0x9f, 0xf3, 0x1d, 0x62, 0xe8, 0xe5,
- 0x62, 0xa0, 0x88, 0xb2, 0x28, 0xf2, 0x5d, 0xfd, 0xf7, 0x81, 0xf4, 0xcb,
- 0x17, 0xff, 0x1a, 0x6b, 0xfb, 0x9e, 0x29, 0xee, 0x0b, 0x17, 0xf6, 0x63,
- 0x97, 0xb8, 0xb1, 0x7e, 0x29, 0x86, 0x79, 0x62, 0x88, 0xf4, 0xfc, 0x59,
- 0x52, 0x8b, 0xc8, 0x42, 0x6e, 0xe6, 0xe2, 0xc5, 0x8e, 0xb1, 0x7b, 0x59,
- 0xda, 0xc5, 0xec, 0x68, 0xd6, 0x2f, 0xa4, 0xe7, 0x65, 0x8b, 0x64, 0x66,
- 0xff, 0xc3, 0xb4, 0x34, 0x56, 0xfc, 0x5c, 0x02, 0x44, 0xbb, 0x7d, 0x87,
- 0x17, 0x96, 0x2f, 0xfd, 0x3d, 0x16, 0x6f, 0xdd, 0xd3, 0xf6, 0xb1, 0x7f,
- 0x9b, 0x3b, 0xdd, 0xd3, 0xf6, 0xb1, 0x71, 0x67, 0x0f, 0xf7, 0x75, 0x16,
- 0xfa, 0x31, 0x6b, 0xa5, 0x8b, 0xff, 0x66, 0xeb, 0x67, 0x7b, 0xba, 0x7e,
- 0xd6, 0x2f, 0xf8, 0xd9, 0x28, 0x67, 0xd8, 0xeb, 0x17, 0x39, 0xbb, 0x51,
- 0xa9, 0x19, 0x79, 0x13, 0x79, 0x1a, 0xfc, 0xdc, 0xe4, 0x9d, 0x62, 0x99,
- 0x51, 0x1e, 0x8f, 0x0a, 0x37, 0x4d, 0xe9, 0x75, 0x2b, 0xfe, 0x98, 0xf8,
- 0x6a, 0x13, 0x46, 0xa3, 0xa3, 0x43, 0xc2, 0x9d, 0xe1, 0x6a, 0x02, 0xf2,
- 0x87, 0x50, 0xa5, 0x7b, 0xdf, 0x86, 0xc4, 0xe3, 0x58, 0xbd, 0xc1, 0xf6,
- 0xb1, 0x7b, 0xfb, 0x1e, 0x96, 0x2e, 0x07, 0x4b, 0x17, 0xff, 0xb2, 0x2f,
- 0xc9, 0x1a, 0x59, 0xef, 0x89, 0x62, 0xb6, 0xa2, 0x1c, 0xd2, 0x3f, 0x8c,
- 0xdf, 0x74, 0x27, 0x82, 0xc5, 0x6d, 0x47, 0xec, 0x21, 0x4d, 0xd9, 0x9d,
- 0x32, 0x6b, 0x9a, 0x8c, 0x92, 0xfe, 0xd7, 0xf3, 0x42, 0xc5, 0x8b, 0xff,
- 0xfb, 0x3b, 0x87, 0x3d, 0xf9, 0x3c, 0xb0, 0xf6, 0xce, 0xc4, 0xb1, 0x7f,
- 0xf8, 0xa2, 0x63, 0xeb, 0x3b, 0x87, 0x05, 0x12, 0xc5, 0xff, 0xe2, 0xeb,
- 0xef, 0xed, 0xba, 0xcf, 0x3f, 0x6b, 0x15, 0x89, 0x96, 0xb1, 0x73, 0xb1,
- 0x89, 0x3a, 0xff, 0xb4, 0x59, 0x1c, 0x62, 0xd4, 0x6b, 0x17, 0xed, 0x11,
- 0x3f, 0xd6, 0x2f, 0xe2, 0xdb, 0xd7, 0x00, 0x35, 0x8a, 0x94, 0x4b, 0x31,
- 0xeb, 0x93, 0xdf, 0xff, 0xcd, 0xcf, 0xe6, 0xb5, 0x31, 0xed, 0xc2, 0x1f,
- 0xe5, 0x62, 0xff, 0xc2, 0xe6, 0xd3, 0x87, 0xf7, 0xfc, 0xac, 0x5f, 0xb3,
- 0xc2, 0xce, 0xd6, 0x2f, 0x1b, 0x9d, 0xac, 0x5d, 0x31, 0x6d, 0x3c, 0x8f,
- 0x14, 0xd6, 0x26, 0x30, 0x4b, 0xa2, 0x84, 0x5d, 0xff, 0xfc, 0x67, 0xb1,
- 0x8f, 0xb4, 0xb3, 0xa6, 0xd6, 0x9a, 0x35, 0x8b, 0xff, 0xff, 0xf0, 0x8b,
- 0x69, 0x8f, 0xdc, 0x34, 0xe0, 0xdb, 0xc1, 0x4f, 0x7f, 0xc6, 0x2c, 0x35,
- 0x62, 0xff, 0xff, 0xff, 0x75, 0x9d, 0x16, 0x7b, 0xe2, 0xfb, 0xf7, 0x0e,
- 0x7b, 0x58, 0x66, 0x30, 0xfd, 0xc6, 0x58, 0xbf, 0xff, 0xde, 0x16, 0x16,
- 0xd6, 0xcf, 0x14, 0x83, 0x6e, 0x30, 0xd6, 0x2f, 0xf8, 0xf8, 0x7d, 0xa7,
- 0xdc, 0xdf, 0x05, 0x8b, 0xff, 0xff, 0xd9, 0xb7, 0x41, 0xf2, 0x76, 0xf1,
- 0xb0, 0xa2, 0xe7, 0x9b, 0x23, 0x29, 0x58, 0xad, 0x26, 0x40, 0x76, 0x2f,
- 0xa1, 0x5f, 0xff, 0x6b, 0x59, 0xee, 0x7d, 0xb3, 0x6f, 0xc1, 0x2b, 0x15,
- 0x2a, 0x8d, 0x5a, 0x3b, 0x21, 0x18, 0xdf, 0xff, 0xd3, 0xfc, 0x19, 0xa2,
- 0x9f, 0xe7, 0xa4, 0xef, 0xe5, 0x8a, 0x95, 0x75, 0xf8, 0xbf, 0xf9, 0x57,
- 0xe2, 0x36, 0xbf, 0xec, 0x92, 0xeb, 0x3d, 0xf6, 0x58, 0xbf, 0xff, 0xfe,
- 0x68, 0xbf, 0x9c, 0xd6, 0x75, 0xb7, 0xed, 0x85, 0x9b, 0xcb, 0x06, 0x22,
- 0x58, 0xbf, 0x61, 0x74, 0x19, 0xd6, 0x2f, 0xfe, 0xfe, 0x49, 0x44, 0x59,
- 0xee, 0x3a, 0xc5, 0xa1, 0xa4, 0xc9, 0x48, 0xe3, 0xd0, 0x80, 0xdd, 0x2a,
- 0xbf, 0xf6, 0xef, 0xa7, 0x91, 0x41, 0xf5, 0x1a, 0xc5, 0xef, 0x31, 0xab,
- 0x17, 0x61, 0xf6, 0x9f, 0x1e, 0xc6, 0x8b, 0x7f, 0xf3, 0x46, 0xe7, 0x3b,
- 0x6d, 0x1b, 0x6f, 0x58, 0xa1, 0x9f, 0xee, 0x8d, 0x2f, 0x44, 0xdb, 0x8b,
- 0x17, 0xff, 0xf7, 0x9a, 0x3c, 0x1e, 0xd3, 0xbc, 0x34, 0xd1, 0xb9, 0xd6,
- 0x2f, 0xf4, 0x6e, 0x72, 0x9d, 0x44, 0xb1, 0x7f, 0xdd, 0xe1, 0xa0, 0x3e,
- 0x6d, 0xd6, 0x22, 0x51, 0x97, 0xef, 0x80, 0xef, 0x12, 0xc5, 0xa5, 0x62,
- 0xf6, 0x14, 0x7b, 0x4d, 0xa7, 0x44, 0x77, 0xff, 0xd8, 0x2d, 0x6d, 0x8b,
- 0xe2, 0x35, 0xb0, 0x8d, 0x58, 0xbf, 0x8e, 0x20, 0x6d, 0x3e, 0x96, 0x2f,
- 0xff, 0x9f, 0xd3, 0xa1, 0x1d, 0xb9, 0xb7, 0x90, 0xe2, 0xc5, 0xff, 0x6a,
- 0x39, 0x8e, 0x31, 0x6a, 0x35, 0x8b, 0xff, 0x6d, 0x8b, 0xe2, 0x35, 0xb0,
- 0x8d, 0x58, 0xbf, 0xff, 0x4e, 0xe6, 0xde, 0xe1, 0x31, 0xf7, 0x0e, 0x13,
- 0x9a, 0xb1, 0x7f, 0x8b, 0x6f, 0x05, 0xb2, 0x2d, 0x2c, 0x56, 0x23, 0x77,
- 0xe8, 0x82, 0x5f, 0xbf, 0xff, 0xfd, 0x9d, 0x3c, 0x7b, 0x78, 0xdb, 0x32,
- 0x40, 0xf6, 0xe9, 0x49, 0x63, 0x79, 0x62, 0xff, 0xfe, 0xf4, 0x96, 0x47,
- 0xb6, 0x31, 0x6a, 0x1e, 0x98, 0xb8, 0xb1, 0x74, 0xf7, 0xf4, 0x6f, 0xee,
- 0xbf, 0x54, 0xaa, 0x5c, 0xe4, 0x63, 0x82, 0x8c, 0x3a, 0xfe, 0x2c, 0xde,
- 0x59, 0xc5, 0x8b, 0xdd, 0xb9, 0x2c, 0x58, 0x7b, 0x4f, 0x2f, 0x0b, 0xaf,
- 0xfe, 0xdb, 0xcf, 0x8b, 0x6f, 0xb9, 0xc9, 0xd2, 0xc5, 0xff, 0xfd, 0x3a,
- 0x06, 0xd9, 0xde, 0xff, 0x9d, 0x6b, 0x3d, 0xc5, 0x8a, 0x8d, 0x15, 0x5f,
- 0x4b, 0xbf, 0xf4, 0x27, 0xc2, 0xeb, 0x6f, 0x3c, 0xcb, 0x17, 0xff, 0xdf,
- 0x98, 0xf6, 0x96, 0x6f, 0x7f, 0xfe, 0x7b, 0x58, 0xbf, 0xff, 0xee, 0xf8,
- 0xd8, 0x66, 0xdf, 0xe7, 0xb9, 0x91, 0xed, 0xc6, 0x1a, 0xc5, 0x0d, 0x18,
- 0x58, 0xab, 0x7f, 0xf6, 0x79, 0xbb, 0x81, 0x4e, 0xdd, 0xde, 0x96, 0x2f,
- 0xff, 0xa7, 0xb8, 0x73, 0xed, 0x9e, 0xee, 0x0d, 0xf5, 0x8b, 0xfe, 0x2c,
- 0xd6, 0x75, 0x8c, 0x35, 0x8b, 0xfa, 0x3f, 0x44, 0x52, 0x75, 0x8b, 0xf3,
- 0xcc, 0x53, 0x12, 0xc5, 0xfb, 0x07, 0xf1, 0x18, 0xb1, 0x74, 0xc5, 0xb4,
- 0xf4, 0xc8, 0xa6, 0xff, 0xfe, 0xc8, 0xf1, 0x86, 0x42, 0xfe, 0xd9, 0x1b,
- 0xc5, 0xc5, 0x8b, 0xfb, 0x3e, 0xda, 0xfb, 0xac, 0x5f, 0xbe, 0xda, 0xfb,
- 0xac, 0x5d, 0x86, 0x6d, 0x3d, 0x5c, 0x2d, 0xa9, 0x5c, 0x87, 0xc8, 0x69,
- 0xf6, 0x48, 0xd1, 0x82, 0xc4, 0x45, 0xa4, 0xbf, 0xa9, 0x39, 0xc1, 0x42,
- 0x0f, 0x85, 0xfe, 0x85, 0x9d, 0xf7, 0xb3, 0x06, 0xb1, 0x51, 0xb6, 0x66,
- 0x83, 0x86, 0x89, 0xb1, 0xa2, 0xf5, 0x2f, 0x8f, 0xb8, 0xda, 0x5a, 0x32,
- 0xb8, 0x88, 0xb5, 0x0b, 0x53, 0xc2, 0x1f, 0xe6, 0xa0, 0x55, 0x23, 0x2e,
- 0x4a, 0xaf, 0xf4, 0xe8, 0x7e, 0xec, 0x2b, 0x6f, 0xff, 0x9b, 0x98, 0x38,
- 0xf0, 0xcd, 0xa4, 0x59, 0xda, 0xc5, 0xfe, 0xf1, 0x67, 0xbf, 0x91, 0xac,
- 0x5f, 0xdb, 0xbe, 0x62, 0x73, 0xac, 0x52, 0xc5, 0xfb, 0xdc, 0xc9, 0x8f,
- 0x69, 0xbc, 0x39, 0x85, 0xef, 0xb9, 0xab, 0x17, 0xfb, 0x6e, 0xb3, 0xb8,
- 0x31, 0xd6, 0x2b, 0x48, 0x95, 0xf2, 0x01, 0x83, 0xd7, 0xfe, 0x7d, 0x7f,
- 0x3d, 0x24, 0xc0, 0x58, 0xb6, 0xea, 0xc5, 0xd3, 0xa5, 0x8b, 0xfc, 0x2f,
- 0x66, 0x1c, 0x06, 0x2c, 0x5f, 0x16, 0x47, 0xb6, 0x23, 0xcc, 0x00, 0xbd,
- 0xf4, 0x3c, 0xd1, 0xac, 0x5f, 0xee, 0x9b, 0x98, 0x3d, 0xa3, 0x58, 0xbf,
- 0xbb, 0x87, 0x36, 0xf9, 0x96, 0x2d, 0x9f, 0x3e, 0x93, 0x0d, 0xef, 0xfd,
- 0x09, 0xc0, 0x7f, 0x30, 0xba, 0x58, 0xbf, 0xfd, 0xf6, 0x21, 0xed, 0x0f,
- 0xa2, 0xcf, 0xe2, 0xc5, 0xff, 0x3f, 0xb9, 0x14, 0x04, 0x5e, 0x58, 0xac,
- 0x46, 0x34, 0x47, 0xc0, 0x4d, 0xbf, 0xef, 0xb1, 0xe7, 0x0b, 0xdc, 0x58,
- 0xbf, 0xff, 0xc2, 0xf6, 0x85, 0x16, 0xdf, 0x45, 0xf1, 0x03, 0xcd, 0x9b,
- 0xab, 0x17, 0xd3, 0xd4, 0x9f, 0x6a, 0x34, 0xfa, 0x30, 0x23, 0x8a, 0x95,
- 0xca, 0x7c, 0x8c, 0x17, 0xa3, 0x16, 0x3d, 0xd3, 0x0b, 0x9e, 0x14, 0x23,
- 0x77, 0x63, 0xc1, 0xbf, 0xff, 0xb5, 0x8e, 0x7d, 0xa6, 0xbf, 0x7f, 0xcf,
- 0xfe, 0x7c, 0xb1, 0x7d, 0x98, 0x0e, 0x2c, 0x5c, 0xc6, 0x2c, 0x5e, 0xd4,
- 0x50, 0x58, 0xa1, 0x9b, 0x7c, 0x18, 0xbf, 0xf9, 0xbb, 0x87, 0x36, 0x8d,
- 0xb7, 0xc8, 0xd6, 0x2f, 0x77, 0x3b, 0x8b, 0x17, 0xa6, 0x28, 0x96, 0x28,
- 0xd4, 0x45, 0x3a, 0x50, 0x88, 0x6f, 0xb3, 0xef, 0xbd, 0x62, 0xfe, 0x86,
- 0x7f, 0x37, 0xf1, 0x62, 0xd8, 0x33, 0xd4, 0x88, 0x92, 0xff, 0xfb, 0xe2,
- 0xe6, 0xdf, 0xb7, 0xbf, 0x9a, 0x9d, 0xeb, 0x17, 0xee, 0x36, 0x76, 0x75,
- 0x8a, 0x19, 0xff, 0x79, 0x56, 0xfe, 0xce, 0xcb, 0x30, 0x0b, 0x15, 0x87,
- 0x9e, 0x44, 0x57, 0xf1, 0x4f, 0x7f, 0xc8, 0xd6, 0x2e, 0x93, 0x8d, 0x56,
- 0x5e, 0x2c, 0x9b, 0x0a, 0xad, 0x42, 0x10, 0xa1, 0xeb, 0xe2, 0x0b, 0xff,
- 0xb5, 0x26, 0x6e, 0x94, 0x99, 0xdc, 0x38, 0xb1, 0x69, 0x58, 0xbe, 0x6d,
- 0x3f, 0x6b, 0x16, 0xf3, 0x1b, 0x4e, 0x08, 0xd0, 0xd1, 0x4a, 0xcf, 0xf7,
- 0xfc, 0xe5, 0xd7, 0xd8, 0xe5, 0x2b, 0x17, 0xff, 0x0c, 0x9e, 0x28, 0xa7,
- 0xc0, 0xce, 0x2c, 0x5f, 0xff, 0x14, 0xc7, 0xf9, 0x6f, 0x71, 0x8b, 0xb8,
- 0x2c, 0x5c, 0x70, 0xd6, 0x2e, 0x98, 0x96, 0x2a, 0x4d, 0x8b, 0x0c, 0xdf,
- 0xfc, 0xdb, 0xd8, 0x7b, 0x66, 0x21, 0xb9, 0x8b, 0x17, 0xff, 0xff, 0x89,
- 0x8d, 0xfb, 0xc5, 0xb4, 0x85, 0xbb, 0xb7, 0x3b, 0x86, 0x08, 0x81, 0xc5,
- 0x8b, 0xff, 0xe6, 0x87, 0xb9, 0x9b, 0xf5, 0x80, 0xe3, 0xf4, 0xb1, 0x7f,
- 0xec, 0x1e, 0x39, 0xbb, 0x4c, 0x73, 0x16, 0x2f, 0xdf, 0x69, 0x28, 0xd6,
- 0x28, 0xe9, 0x9f, 0xfe, 0x10, 0x24, 0xa7, 0xbd, 0x0e, 0xff, 0xfe, 0x10,
- 0xdc, 0x81, 0xb7, 0xd9, 0xf9, 0xf6, 0xb0, 0x6b, 0x17, 0xc7, 0x66, 0x31,
- 0x62, 0xa5, 0x18, 0x90, 0x44, 0x75, 0xda, 0x25, 0x53, 0x5c, 0x1f, 0xf4,
- 0xa4, 0xdb, 0xfd, 0xa9, 0x8f, 0xed, 0x83, 0x58, 0xbe, 0x98, 0xb8, 0xcb,
- 0x15, 0x05, 0xc4, 0xa1, 0x91, 0x61, 0xc7, 0x48, 0xcd, 0x2c, 0x6f, 0x47,
- 0x04, 0x69, 0x7f, 0xff, 0x42, 0x74, 0x69, 0xc9, 0xbb, 0x87, 0x07, 0xa6,
- 0x8d, 0x62, 0xff, 0xff, 0x71, 0x84, 0x3d, 0xa6, 0x93, 0x8c, 0x59, 0xfd,
- 0xb1, 0x44, 0xb1, 0x6c, 0x89, 0x19, 0x1c, 0x5f, 0xbd, 0x31, 0x71, 0x62,
- 0xe1, 0x0d, 0x62, 0xfe, 0xe1, 0x16, 0x03, 0x8b, 0x15, 0x11, 0xe2, 0xf8,
- 0x62, 0xff, 0xff, 0xce, 0x3c, 0x27, 0xf7, 0x33, 0x40, 0x04, 0xe7, 0x7e,
- 0xe3, 0x2c, 0x58, 0x28, 0xb1, 0x52, 0xe9, 0x82, 0xb2, 0xb4, 0x8a, 0xea,
- 0x31, 0x36, 0x9c, 0xfa, 0xd4, 0x21, 0x3f, 0x2c, 0xa9, 0xe7, 0x58, 0x4a,
- 0x33, 0x4f, 0x14, 0x89, 0x8c, 0xc2, 0x3d, 0x96, 0xbb, 0xfa, 0x60, 0xc3,
- 0xc2, 0x58, 0xbe, 0x9e, 0x36, 0x96, 0x2f, 0x8b, 0xcd, 0xbd, 0x62, 0xfa,
- 0x02, 0x7f, 0x2c, 0x5d, 0x3b, 0x8b, 0x17, 0x0b, 0x71, 0x62, 0xf4, 0x94,
- 0xac, 0x57, 0x47, 0xa1, 0xa1, 0xa3, 0x8d, 0xd4, 0xa3, 0x1f, 0x09, 0x19,
- 0xce, 0xfb, 0xdc, 0x70, 0x2c, 0x5f, 0xff, 0x0a, 0x3d, 0xb2, 0xdf, 0xea,
- 0x40, 0x77, 0x82, 0xc5, 0xff, 0x9b, 0x6b, 0x68, 0x51, 0xbe, 0xba, 0x58,
- 0xa3, 0x51, 0x2f, 0xf5, 0x4b, 0xe6, 0xfb, 0xc6, 0xb1, 0x7e, 0x92, 0x39,
- 0xa6, 0xac, 0x5f, 0xe6, 0xe3, 0x08, 0x2e, 0x39, 0x58, 0xbd, 0x3e, 0x95,
- 0x8a, 0x19, 0xfe, 0xf8, 0xab, 0x79, 0xbd, 0xfb, 0xe7, 0x62, 0xe9, 0x62,
- 0xfb, 0x3c, 0xdc, 0x58, 0xac, 0x3c, 0xbe, 0x14, 0xde, 0x84, 0x9d, 0x62,
- 0xe7, 0x0d, 0x62, 0xbe, 0x6d, 0x78, 0x3b, 0x7f, 0xef, 0x7d, 0xb3, 0x06,
- 0x58, 0x62, 0xc5, 0x61, 0xef, 0xb1, 0x0d, 0xff, 0xb9, 0x31, 0x67, 0xdb,
- 0x5f, 0x75, 0x8b, 0xfb, 0x59, 0xfe, 0xe1, 0xc5, 0x8b, 0xb3, 0xeb, 0x14,
- 0xc8, 0x86, 0xd1, 0xf9, 0xcc, 0x2f, 0x69, 0x8d, 0x58, 0xbf, 0xf1, 0xf1,
- 0xbc, 0xfe, 0xfc, 0xf9, 0x62, 0xd8, 0xb1, 0x7f, 0xfc, 0x2c, 0x6f, 0xe7,
- 0x5f, 0x6d, 0xa6, 0x1f, 0xa5, 0x8b, 0xde, 0xc3, 0x16, 0x2d, 0x19, 0x1f,
- 0x9f, 0x95, 0x68, 0xe8, 0xac, 0x14, 0x21, 0x2f, 0x46, 0x2f, 0x2c, 0x5f,
- 0x7d, 0x9c, 0x0b, 0x15, 0x87, 0x83, 0xe1, 0xfa, 0xc4, 0x45, 0x01, 0xa6,
- 0xff, 0xf0, 0x8b, 0x6e, 0x6a, 0x33, 0xe7, 0x3f, 0x8b, 0x17, 0xc1, 0x72,
- 0x7f, 0x2c, 0x54, 0x67, 0xe6, 0x24, 0xdb, 0xfe, 0xda, 0x76, 0x2c, 0xf7,
- 0xd9, 0x62, 0xfd, 0x1b, 0x97, 0xb8, 0xb1, 0x7f, 0x7d, 0xe3, 0xdb, 0x0f,
- 0x2c, 0x5f, 0x88, 0x12, 0xdb, 0xd6, 0x2f, 0xd1, 0x07, 0xc9, 0xc5, 0x8a,
- 0x63, 0xd3, 0x72, 0x9b, 0xf3, 0xe8, 0xbb, 0x65, 0x8b, 0xd1, 0x4f, 0x96,
- 0x2a, 0x53, 0x71, 0x81, 0x1e, 0x1d, 0x31, 0x4f, 0xe1, 0x0b, 0xe2, 0x01,
- 0x14, 0x5e, 0x96, 0x1a, 0xc5, 0xef, 0xb9, 0x2c, 0x54, 0x6c, 0x8f, 0xd8,
- 0x16, 0x0e, 0x1d, 0x38, 0x5a, 0x6c, 0x2e, 0xba, 0x24, 0x68, 0x50, 0x44,
- 0xf8, 0x78, 0x5a, 0xfe, 0x14, 0xce, 0x5e, 0x01, 0xe2, 0x8d, 0xd3, 0xd2,
- 0x81, 0xb7, 0xb3, 0x98, 0x39, 0x73, 0x76, 0xb1, 0x60, 0xaa, 0xc5, 0xfd,
- 0xb7, 0x8d, 0xf6, 0x3a, 0xc5, 0xef, 0x49, 0xd6, 0x2b, 0x63, 0x3e, 0x3e,
- 0xc5, 0x88, 0xc2, 0xe8, 0x46, 0xb1, 0x77, 0x66, 0xac, 0x5f, 0xc7, 0x78,
- 0x6b, 0x0c, 0x58, 0xbb, 0x3b, 0x19, 0xe4, 0xe0, 0xd5, 0xf0, 0x57, 0x9e,
- 0xc5, 0x8b, 0xfd, 0xf6, 0x3f, 0xf0, 0x0e, 0xb1, 0x7d, 0xd6, 0x10, 0x16,
- 0x2f, 0xfd, 0xf9, 0x29, 0xeb, 0x53, 0x84, 0xb1, 0x43, 0x44, 0x9b, 0x99,
- 0xf8, 0x8e, 0xfe, 0xc8, 0xe4, 0xd7, 0xe2, 0xc5, 0xff, 0xf7, 0xdb, 0x5f,
- 0x7d, 0xb9, 0xdc, 0x33, 0x51, 0xac, 0x5f, 0xdf, 0x61, 0xb6, 0xba, 0x58,
- 0xbf, 0xff, 0x3f, 0x63, 0xd1, 0x39, 0x85, 0x80, 0x06, 0x01, 0x62, 0xee,
- 0xf9, 0xb5, 0x33, 0x71, 0x97, 0xe1, 0x7f, 0x4a, 0x9e, 0x2f, 0xbf, 0xdf,
- 0x96, 0x27, 0xd1, 0xab, 0x17, 0xf4, 0xb1, 0x3e, 0x8d, 0x58, 0xbe, 0xd6,
- 0x9b, 0x5b, 0x4f, 0x83, 0xe6, 0x77, 0xf1, 0x64, 0x5a, 0x7d, 0xeb, 0x17,
- 0xec, 0x8b, 0x4f, 0xbd, 0x62, 0x96, 0x2d, 0xd6, 0xd3, 0xe7, 0x23, 0x0d,
- 0xe5, 0x76, 0x70, 0x23, 0x6c, 0xa1, 0x45, 0x78, 0xb0, 0xeb, 0x16, 0xed,
- 0x62, 0xe7, 0x84, 0x0d, 0x7f, 0x07, 0x2f, 0xff, 0xff, 0x6d, 0x3c, 0xe7,
- 0xb6, 0xe4, 0x1b, 0x79, 0x67, 0x36, 0xc8, 0xde, 0x2e, 0x2c, 0x5e, 0x33,
- 0x80, 0x58, 0xbf, 0xb0, 0xe3, 0x77, 0xe9, 0x62, 0xe2, 0xeb, 0x69, 0xe6,
- 0xfc, 0x7e, 0xa0, 0x8f, 0xc7, 0x86, 0x65, 0x74, 0xbc, 0xdc, 0xcf, 0x71,
- 0x1a, 0x69, 0x88, 0xe5, 0xaf, 0x1f, 0x88, 0x23, 0x95, 0x25, 0xb1, 0x46,
- 0x51, 0x7b, 0x9e, 0x65, 0x8b, 0xd1, 0x03, 0xb5, 0x8b, 0x8d, 0xdb, 0xd1,
- 0xbd, 0x00, 0xed, 0xee, 0x05, 0xf8, 0xb1, 0x52, 0x7a, 0x7d, 0x98, 0xdf,
- 0x00, 0x02, 0xdc, 0x58, 0xb0, 0x16, 0x2f, 0xda, 0x8e, 0x75, 0x1a, 0xc5,
- 0xf9, 0x8b, 0xc1, 0x9d, 0x62, 0xa4, 0xf5, 0x00, 0x57, 0x7a, 0x1c, 0xc5,
- 0x8b, 0xf0, 0x54, 0xa7, 0x00, 0xb1, 0x5a, 0x3c, 0x80, 0x0e, 0xdf, 0xf9,
- 0xb0, 0xce, 0x0a, 0x22, 0x93, 0xac, 0x5e, 0x13, 0xf1, 0x62, 0xa0, 0x8e,
- 0x8c, 0x69, 0x39, 0x10, 0x68, 0x17, 0xf8, 0xc3, 0xcb, 0x68, 0x5b, 0x8b,
- 0x17, 0x10, 0x96, 0x29, 0x62, 0xda, 0xda, 0x68, 0xf8, 0x2f, 0x7e, 0xdb,
- 0xdc, 0x05, 0x1a, 0xc5, 0x49, 0xeb, 0xc0, 0xa6, 0xb1, 0x1a, 0x62, 0x85,
- 0x95, 0xff, 0xfc, 0xda, 0xdb, 0x8d, 0x84, 0x6f, 0xdb, 0x0f, 0x9d, 0x2c,
- 0x5f, 0xf6, 0x77, 0x0e, 0x77, 0x01, 0x69, 0x62, 0xff, 0xff, 0xc7, 0xe7,
- 0x5f, 0x9e, 0xbb, 0x81, 0x08, 0x7b, 0x58, 0xd7, 0x20, 0x2c, 0x5f, 0xff,
- 0xe8, 0xf5, 0x27, 0xe0, 0xa7, 0x6c, 0xea, 0x47, 0xf9, 0x3a, 0xc5, 0x62,
- 0x35, 0xd9, 0xce, 0xff, 0xa1, 0xb6, 0x76, 0xfb, 0xf8, 0x4b, 0x15, 0x89,
- 0xe7, 0x32, 0xe6, 0xa3, 0x14, 0x72, 0x1b, 0xf0, 0x38, 0xdd, 0x98, 0xb1,
- 0x7e, 0xee, 0x4f, 0x1c, 0xac, 0x5f, 0x77, 0x06, 0xfa, 0xc5, 0xd9, 0xdf,
- 0xcf, 0x3b, 0xc5, 0x57, 0xe8, 0xa1, 0x25, 0x05, 0x8a, 0xd1, 0xeb, 0x80,
- 0xba, 0xfe, 0xed, 0xe0, 0x52, 0x75, 0x8b, 0xff, 0xfe, 0x28, 0xbf, 0x9d,
- 0xc2, 0x48, 0x7b, 0x4b, 0x37, 0xe9, 0xb8, 0xb1, 0x7f, 0xc5, 0x17, 0x8b,
- 0x23, 0x72, 0x58, 0xa6, 0x45, 0x20, 0x9a, 0xef, 0xff, 0xff, 0x6b, 0x4d,
- 0x1e, 0xdf, 0xe7, 0x8a, 0x62, 0xfe, 0x47, 0x3d, 0xf8, 0x5d, 0x2c, 0x5f,
- 0xff, 0xfd, 0x26, 0xfe, 0x76, 0x96, 0x08, 0xdd, 0xbd, 0xc3, 0x8c, 0x41,
- 0xcc, 0x6b, 0x17, 0xe2, 0x07, 0x08, 0x4b, 0x17, 0xec, 0x14, 0xea, 0x35,
- 0x8b, 0xcd, 0x84, 0xb1, 0x6e, 0xc8, 0xf1, 0x38, 0x53, 0x58, 0x98, 0x73,
- 0x3d, 0x09, 0xb2, 0xff, 0xfb, 0x37, 0x4b, 0x0e, 0xe5, 0xee, 0x6d, 0x93,
- 0x16, 0x2a, 0x55, 0x82, 0x64, 0x34, 0x98, 0x8b, 0xf1, 0xc6, 0x88, 0xbe,
- 0xff, 0xde, 0x39, 0xde, 0x2d, 0xa5, 0x86, 0x2c, 0x5f, 0xfd, 0xa2, 0xef,
- 0x38, 0x28, 0x8a, 0x4e, 0xb1, 0x7f, 0xcc, 0x6f, 0xe5, 0xa3, 0x93, 0x56,
- 0x29, 0x91, 0x03, 0xc4, 0x6a, 0xda, 0x8e, 0x68, 0x43, 0x12, 0xff, 0xdc,
- 0xce, 0xe0, 0xda, 0x2e, 0xf1, 0x62, 0xff, 0x0a, 0x22, 0xcf, 0xbf, 0x96,
- 0x2a, 0x33, 0xf4, 0x24, 0x0b, 0xff, 0xa0, 0x20, 0x70, 0xb3, 0x9c, 0x93,
- 0x16, 0x2f, 0x8c, 0xdb, 0x1b, 0x2c, 0x5f, 0x8c, 0x1f, 0xdc, 0xeb, 0x17,
- 0xfb, 0xb8, 0x73, 0x6f, 0x3c, 0xcb, 0x15, 0x27, 0xc4, 0xc5, 0x55, 0x88,
- 0xa9, 0xfc, 0x22, 0x6f, 0xfd, 0x86, 0x78, 0x6d, 0x9d, 0xc3, 0x8b, 0x17,
- 0xfb, 0xf2, 0xc4, 0xfa, 0x35, 0x62, 0xff, 0xf1, 0xf6, 0xe0, 0x82, 0xed,
- 0xf6, 0x3b, 0x8d, 0x62, 0xd9, 0x12, 0x20, 0xc4, 0x67, 0x7f, 0xc7, 0xce,
- 0x6d, 0x88, 0xa4, 0xeb, 0x17, 0xff, 0xee, 0x46, 0xfb, 0x47, 0xf9, 0xd6,
- 0xb3, 0x7c, 0xf6, 0xb1, 0x43, 0x4e, 0xb1, 0x89, 0xf5, 0x0c, 0x43, 0x94,
- 0xf8, 0xf2, 0xff, 0xfd, 0x39, 0x1e, 0xd1, 0xe9, 0xa3, 0xf3, 0x61, 0x46,
- 0xb1, 0x7f, 0xed, 0x03, 0x6f, 0x81, 0x9b, 0xb8, 0x4b, 0x17, 0xdb, 0xf0,
- 0x5d, 0x2c, 0x5f, 0xff, 0xf3, 0xeb, 0xf9, 0xe6, 0xc2, 0x8f, 0x93, 0x84,
- 0x3f, 0xca, 0xc5, 0xb4, 0xb1, 0x7f, 0x66, 0xef, 0x98, 0xa3, 0x58, 0xbb,
- 0xdb, 0x63, 0x3c, 0x32, 0x12, 0xa9, 0x4d, 0x07, 0x11, 0x3b, 0x26, 0x78,
- 0x53, 0xdf, 0xff, 0xfb, 0xbc, 0x8c, 0x5b, 0xbb, 0x7b, 0x87, 0xa4, 0xcd,
- 0xb9, 0xa0, 0x02, 0x56, 0x2f, 0xfb, 0x22, 0xd9, 0x17, 0xb3, 0xbf, 0x2c,
- 0x5e, 0xcd, 0x0d, 0x62, 0xe9, 0x82, 0xc5, 0xff, 0xf7, 0x36, 0xea, 0x7a,
- 0xc2, 0x8a, 0x19, 0xee, 0x2c, 0x56, 0x23, 0x1c, 0xe7, 0xe0, 0x1d, 0x10,
- 0xbd, 0xff, 0xd1, 0xb9, 0x67, 0xf3, 0xda, 0xc3, 0x16, 0x2f, 0xff, 0xff,
- 0xd8, 0x23, 0x48, 0x5e, 0x8b, 0x3c, 0xdd, 0xc0, 0xa4, 0xb3, 0xed, 0x9a,
- 0x89, 0x62, 0xb1, 0x19, 0x3d, 0xa2, 0xdf, 0xf6, 0x19, 0xf9, 0x37, 0x3d,
- 0xc5, 0x8b, 0xff, 0x9c, 0xa3, 0x38, 0x98, 0x6c, 0x4c, 0xb1, 0x4c, 0x7f,
- 0xc6, 0x1d, 0xdf, 0xd1, 0x77, 0x01, 0x4f, 0x96, 0x2f, 0xf8, 0x5d, 0xff,
- 0x3d, 0xac, 0x31, 0x62, 0xff, 0xfe, 0x84, 0xeb, 0xb8, 0x73, 0x6f, 0xe5,
- 0x89, 0xf4, 0x6a, 0xc5, 0xff, 0xfb, 0x20, 0xdb, 0xcb, 0x39, 0xb7, 0x3e,
- 0xfd, 0x81, 0x62, 0xf1, 0x64, 0x16, 0x2d, 0x0d, 0xa7, 0xeb, 0xe5, 0x9b,
- 0xff, 0x76, 0x3f, 0x89, 0xf8, 0x58, 0x35, 0x8a, 0xc3, 0xea, 0x11, 0x55,
- 0xff, 0xd1, 0xb9, 0x6d, 0xd6, 0x98, 0xdc, 0x25, 0x8b, 0xfe, 0x7f, 0x7b,
- 0x22, 0x83, 0x79, 0x62, 0xfe, 0xc3, 0x4d, 0x7f, 0x71, 0x62, 0xfb, 0x3e,
- 0xfe, 0x58, 0xb9, 0xcf, 0xb4, 0xf4, 0x88, 0xc2, 0xa5, 0x17, 0x5f, 0x84,
- 0x65, 0xc0, 0x31, 0x62, 0xfb, 0x67, 0x35, 0x2b, 0x16, 0xcd, 0x1b, 0xed,
- 0xe3, 0x37, 0x61, 0x2c, 0x54, 0xab, 0x70, 0xc3, 0x1e, 0xcf, 0x3f, 0x19,
- 0xf3, 0x90, 0xf2, 0x30, 0x1f, 0x32, 0x88, 0xa2, 0xff, 0xec, 0xf7, 0x36,
- 0xeb, 0x1b, 0xf2, 0x35, 0x8b, 0xfe, 0xff, 0xe7, 0xbd, 0xa6, 0x1f, 0xa5,
- 0x8b, 0xdd, 0x3e, 0xe2, 0xc5, 0xfd, 0x9e, 0xd6, 0xb2, 0x0b, 0x14, 0xb1,
- 0x7e, 0xcf, 0x96, 0x74, 0xb1, 0x40, 0x36, 0x84, 0x19, 0x4c, 0x8a, 0x38,
- 0x88, 0x7c, 0xc5, 0x7b, 0x3b, 0xf2, 0xc5, 0xfe, 0xc1, 0xb6, 0xff, 0x36,
- 0x96, 0x2e, 0xce, 0x6d, 0x44, 0x1e, 0xe1, 0x83, 0x8f, 0x53, 0xa7, 0x4a,
- 0x51, 0xb3, 0x5f, 0xf6, 0x1f, 0xf2, 0xda, 0x16, 0xe2, 0xc5, 0xfd, 0xe6,
- 0x8c, 0x9c, 0xeb, 0x15, 0x1b, 0x6c, 0xba, 0x38, 0xfd, 0x71, 0x04, 0xd8,
- 0x68, 0x75, 0x2c, 0x9b, 0xb8, 0xce, 0x9a, 0x13, 0xd1, 0x11, 0x6a, 0x54,
- 0xd9, 0xd3, 0xff, 0x1c, 0xd3, 0xa0, 0x82, 0x34, 0x02, 0x8c, 0x17, 0x90,
- 0xa1, 0xf4, 0xb9, 0x21, 0x3e, 0xef, 0x8f, 0xac, 0x32, 0x8d, 0xd3, 0xcb,
- 0xfe, 0x93, 0x96, 0x0f, 0x4d, 0x1a, 0xc5, 0xff, 0xfe, 0x33, 0xe2, 0x9e,
- 0xf6, 0xeb, 0x53, 0x19, 0x3b, 0xe8, 0xd5, 0x8b, 0xfc, 0x58, 0x2c, 0x36,
- 0x00, 0x58, 0xa7, 0x44, 0xd9, 0x8c, 0xf5, 0x04, 0x7b, 0xe4, 0x35, 0x2f,
- 0x1b, 0x3a, 0x58, 0xbf, 0xfe, 0x9d, 0xbf, 0x7d, 0xfb, 0x70, 0xe7, 0x9d,
- 0x1a, 0xb1, 0x7e, 0x01, 0xf3, 0x3c, 0xb1, 0x7f, 0xd9, 0xb7, 0x59, 0xf2,
- 0xc8, 0x96, 0x2b, 0x0f, 0x8c, 0x8a, 0x2f, 0xff, 0xf7, 0xdc, 0x1c, 0xda,
- 0x59, 0xbc, 0xb3, 0x98, 0x79, 0xe9, 0x62, 0xff, 0xff, 0xfb, 0x42, 0x3b,
- 0x73, 0x6c, 0x50, 0x11, 0x7b, 0x6f, 0xe6, 0x0c, 0x58, 0x79, 0x58, 0xb7,
- 0x16, 0x2f, 0xde, 0xdb, 0xd7, 0x8e, 0xb1, 0x52, 0x8c, 0x17, 0x84, 0x10,
- 0x84, 0xaa, 0x25, 0x4a, 0x1f, 0x1e, 0x28, 0x5d, 0x70, 0x83, 0xd1, 0x92,
- 0xdf, 0xc2, 0x39, 0xb2, 0x5d, 0x2c, 0x5f, 0xff, 0xfb, 0x9b, 0x4b, 0x07,
- 0x3e, 0xe6, 0xdf, 0x6e, 0x94, 0xf0, 0x53, 0xda, 0xc5, 0xff, 0xc0, 0xdb,
- 0x82, 0x1e, 0xd9, 0xe4, 0xc1, 0x62, 0x82, 0x8d, 0xf7, 0xa8, 0x58, 0x4f,
- 0x31, 0xa7, 0x65, 0x6e, 0xdb, 0xdc, 0xa5, 0x87, 0x94, 0xee, 0x4a, 0xfe,
- 0x30, 0x13, 0xa5, 0xfb, 0xe1, 0x97, 0x60, 0x58, 0xbf, 0xed, 0xbb, 0xbe,
- 0xcf, 0xf9, 0x8e, 0xb1, 0x7f, 0xf4, 0x6f, 0xed, 0x64, 0x6e, 0x5e, 0xe2,
- 0xc5, 0x62, 0x2c, 0x3a, 0x2b, 0x63, 0xfb, 0xff, 0xfa, 0x1f, 0xc6, 0x87,
- 0x30, 0x85, 0xe2, 0xc0, 0x4a, 0xc5, 0x99, 0x62, 0xda, 0xc3, 0xea, 0x02,
- 0xcd, 0xff, 0xf6, 0x7b, 0xf8, 0x31, 0x7b, 0x93, 0xc1, 0x71, 0x62, 0xfe,
- 0x9c, 0x2e, 0x83, 0x3a, 0xc5, 0xfe, 0xf0, 0xa7, 0x23, 0x0c, 0xeb, 0x17,
- 0xfe, 0xfc, 0x90, 0xa2, 0xce, 0x72, 0x56, 0x2d, 0xb9, 0xf4, 0x7a, 0xf9,
- 0x44, 0x32, 0xfd, 0xd3, 0x6a, 0x94, 0xd9, 0x9e, 0x31, 0xcb, 0xf6, 0x17,
- 0x80, 0x25, 0x8b, 0xff, 0xfa, 0x61, 0x87, 0x9e, 0xbd, 0xcc, 0x04, 0xe7,
- 0x70, 0x58, 0xaf, 0xa2, 0x10, 0x8a, 0x2f, 0xa3, 0xc7, 0x89, 0x62, 0xff,
- 0xff, 0xcd, 0xbc, 0xb3, 0x9b, 0x7c, 0xdb, 0x73, 0xd3, 0xd3, 0x6f, 0x9f,
- 0xac, 0x5f, 0xe1, 0xc8, 0x36, 0xe7, 0x7e, 0x58, 0xbf, 0xfe, 0x7d, 0x3f,
- 0xfb, 0x86, 0x7b, 0x6f, 0x5c, 0xdc, 0x58, 0xbf, 0x9a, 0x0f, 0xef, 0xb2,
- 0xc5, 0xff, 0xf3, 0x9c, 0x7f, 0x9d, 0x16, 0x0f, 0xee, 0x62, 0xc5, 0x0d,
- 0x30, 0xce, 0x8d, 0xfc, 0xb1, 0xbc, 0xb6, 0xfe, 0x7d, 0xc1, 0x96, 0x7d,
- 0x62, 0xe3, 0xf1, 0x62, 0xf3, 0xf1, 0x96, 0x2a, 0x4d, 0xa0, 0x06, 0x2f,
- 0xf8, 0x38, 0xf0, 0x9c, 0xef, 0xf5, 0x8b, 0xe6, 0xd1, 0x3a, 0xc5, 0x46,
- 0xab, 0x0e, 0x04, 0x8d, 0x1b, 0xfc, 0x48, 0x24, 0xc9, 0xe2, 0x0d, 0xe7,
- 0x57, 0xfb, 0x9c, 0x96, 0x8d, 0xfc, 0xb1, 0x7f, 0xdc, 0x73, 0x37, 0x5b,
- 0x08, 0x6b, 0x17, 0xf6, 0x7b, 0x1c, 0xa2, 0x58, 0xbe, 0xce, 0x4e, 0x96,
- 0x2c, 0x6f, 0xcf, 0x3c, 0x8b, 0x6d, 0x09, 0x47, 0x3e, 0x1a, 0x0a, 0x11,
- 0x76, 0x82, 0xc5, 0xe1, 0x88, 0x0b, 0x17, 0xff, 0xf4, 0xee, 0x6d, 0x6c,
- 0x2c, 0xfb, 0x61, 0x77, 0x0e, 0x2c, 0x5f, 0xed, 0xd6, 0xce, 0xfe, 0xd8,
- 0xb1, 0x62, 0xed, 0x12, 0x80, 0x5e, 0xbf, 0xb3, 0xdc, 0xfb, 0x1a, 0xb1,
- 0x7d, 0xcf, 0xb1, 0xab, 0x17, 0xe8, 0xf3, 0x45, 0x84, 0x7a, 0x7e, 0x2f,
- 0xbe, 0x93, 0xb8, 0xd6, 0x2a, 0x53, 0x9f, 0x18, 0x96, 0x42, 0xcb, 0xef,
- 0x84, 0x7b, 0x7f, 0x45, 0xfc, 0xf4, 0x8d, 0x62, 0xf0, 0x72, 0x4b, 0x17,
- 0x49, 0x2c, 0x5c, 0xe6, 0x6d, 0x36, 0x61, 0x8e, 0xd6, 0x22, 0x48, 0x98,
- 0xaf, 0xff, 0x60, 0xf6, 0x89, 0xc3, 0xf0, 0x9e, 0x39, 0x58, 0xbe, 0x93,
- 0xf0, 0xeb, 0x17, 0xe7, 0xf6, 0xde, 0x8c, 0x58, 0xbf, 0xf6, 0x1b, 0xfc,
- 0xf7, 0x0a, 0x60, 0xb1, 0x52, 0x8d, 0xd6, 0x4e, 0x72, 0x31, 0x16, 0xdf,
- 0x47, 0xe6, 0x8d, 0x62, 0xfd, 0xe7, 0x3b, 0x79, 0x62, 0xb0, 0xf3, 0x48,
- 0x96, 0xf0, 0xd8, 0x6b, 0x17, 0xff, 0xfe, 0x14, 0xeb, 0x6c, 0xfe, 0x47,
- 0xb7, 0xcd, 0x9b, 0xbd, 0xc1, 0xfb, 0x58, 0xbc, 0x07, 0xdc, 0x58, 0xbf,
- 0x70, 0xa6, 0x2f, 0x2c, 0x50, 0xd1, 0xb6, 0x43, 0xbc, 0x75, 0xf1, 0x05,
- 0xdc, 0x0b, 0x6b, 0x16, 0x82, 0xc5, 0x4a, 0x6c, 0xf9, 0x0f, 0xb7, 0x3c,
- 0xf0, 0xf5, 0xe2, 0xea, 0x56, 0x2f, 0xff, 0xff, 0xbf, 0x9e, 0xe3, 0xc5,
- 0xb4, 0xb3, 0xb8, 0x60, 0xa3, 0x2c, 0x1f, 0xda, 0x25, 0x8b, 0x8b, 0xcb,
- 0x17, 0xff, 0xb9, 0x30, 0xf6, 0x7c, 0xb3, 0xdf, 0x65, 0x8a, 0x93, 0xe0,
- 0x61, 0x7b, 0x84, 0x6a, 0xc5, 0x32, 0x67, 0x1a, 0x1d, 0xfc, 0x38, 0xbc,
- 0x41, 0x78, 0xff, 0x75, 0x8b, 0xff, 0x02, 0x2f, 0xb0, 0x09, 0xfb, 0x82,
- 0xc5, 0x2c, 0x5b, 0x1c, 0xf3, 0x78, 0x83, 0x7b, 0xe6, 0xf9, 0x62, 0xfd,
- 0xef, 0x7b, 0x0c, 0x58, 0xa9, 0x3c, 0x96, 0x1f, 0xa9, 0x47, 0xc9, 0xda,
- 0x80, 0xdf, 0x78, 0xf3, 0xd2, 0xc5, 0xda, 0xc5, 0x8b, 0xd8, 0xc3, 0x58,
- 0xb7, 0x16, 0x2e, 0x2c, 0xe8, 0xd7, 0x76, 0x39, 0x79, 0xb0, 0x96, 0x2f,
- 0x34, 0xc4, 0xb1, 0x7f, 0xf6, 0x03, 0x6f, 0xdb, 0xdc, 0x26, 0x89, 0x62,
- 0xff, 0xc5, 0x9c, 0xdb, 0xc0, 0x1f, 0x38, 0xb1, 0x51, 0xa3, 0xb4, 0xe5,
- 0xbc, 0x1b, 0xf0, 0xee, 0xf4, 0x7a, 0xd8, 0x13, 0x9d, 0x91, 0xec, 0x8c,
- 0xca, 0xff, 0xe2, 0x06, 0xce, 0x7d, 0xa4, 0xee, 0x35, 0x8b, 0xfb, 0x59,
- 0x02, 0x93, 0xac, 0x5f, 0xb2, 0x05, 0x27, 0x58, 0xb8, 0x81, 0xb4, 0xf5,
- 0x34, 0x5b, 0x7f, 0xff, 0xfe, 0x87, 0x38, 0x29, 0xf3, 0x0f, 0x0a, 0x2d,
- 0xa5, 0x9a, 0x92, 0xf7, 0xf3, 0x75, 0x62, 0xff, 0xd3, 0x8d, 0xef, 0xc9,
- 0x4f, 0x4b, 0x17, 0xf1, 0xfb, 0x9f, 0xfe, 0x56, 0x2f, 0x77, 0x0e, 0x46,
- 0x7d, 0x98, 0x7b, 0x58, 0x9a, 0xbf, 0x65, 0xfa, 0x87, 0x9d, 0xb8, 0xb1,
- 0x58, 0xa8, 0xe4, 0x51, 0xf8, 0x86, 0x6d, 0x68, 0xd6, 0x2f, 0xd1, 0xcf,
- 0xb0, 0x0b, 0x17, 0xf0, 0xdc, 0xa0, 0xc7, 0x58, 0xbf, 0xfb, 0x21, 0xf7,
- 0x84, 0xfb, 0x58, 0x35, 0x8b, 0xf6, 0xb3, 0xb8, 0x71, 0x62, 0xf7, 0x5f,
- 0xc5, 0x8a, 0x8c, 0xf2, 0x34, 0x55, 0x7f, 0x03, 0x9b, 0x41, 0xcd, 0x2c,
- 0x56, 0x1e, 0xab, 0x91, 0xdf, 0xf7, 0x73, 0xa8, 0xf6, 0xe3, 0x0d, 0x62,
- 0xe8, 0x99, 0x62, 0xff, 0xec, 0xf6, 0xdc, 0x87, 0xf1, 0xa1, 0xc5, 0x8a,
- 0xc5, 0x40, 0xac, 0x26, 0xe5, 0x20, 0x2d, 0x28, 0x70, 0x88, 0x83, 0x79,
- 0xee, 0xc8, 0xc5, 0xf7, 0xf6, 0x0e, 0xb6, 0x56, 0x2f, 0xec, 0xee, 0x12,
- 0x09, 0x58, 0xbf, 0x16, 0x7d, 0xfc, 0xb1, 0x5d, 0x9e, 0xa9, 0xcb, 0xaf,
- 0xb5, 0x91, 0x4a, 0xc5, 0xf3, 0x6f, 0xcd, 0x2c, 0x56, 0xc4, 0x8e, 0xc9,
- 0x84, 0x13, 0x11, 0xfc, 0x8e, 0xfb, 0x6f, 0x51, 0x98, 0xb1, 0x7f, 0x16,
- 0x00, 0xf3, 0x05, 0x8b, 0xf1, 0x67, 0xbe, 0xcb, 0x14, 0x33, 0xd4, 0x30,
- 0xb6, 0xfd, 0x1e, 0xd1, 0x4c, 0x4b, 0x17, 0xff, 0xfc, 0x52, 0x0e, 0xe1,
- 0xc1, 0x4f, 0x8b, 0x06, 0xd9, 0xa8, 0x96, 0x2a, 0x51, 0x6e, 0xe4, 0x7e,
- 0x2d, 0xa9, 0x6e, 0x30, 0xe3, 0x8f, 0xfc, 0x70, 0xac, 0xc9, 0x5c, 0xbd,
- 0xc6, 0xaa, 0xd1, 0xec, 0x45, 0x0d, 0xfd, 0x43, 0xfb, 0xf1, 0xf7, 0x3c,
- 0x6f, 0x00, 0x8c, 0xec, 0xa3, 0xcc, 0xe4, 0xa7, 0x3f, 0x4a, 0x3d, 0x14,
- 0x6c, 0xbb, 0xd1, 0x43, 0x8c, 0xd2, 0xfd, 0x06, 0xd6, 0x76, 0xb1, 0x7b,
- 0x9f, 0xc5, 0x8b, 0xf6, 0x72, 0x3c, 0x31, 0x62, 0xff, 0xef, 0x88, 0x7f,
- 0x17, 0xb9, 0xf1, 0x44, 0xb1, 0x5d, 0xa2, 0xe6, 0x22, 0x9f, 0x8e, 0x91,
- 0x55, 0xe2, 0xf7, 0x16, 0x2f, 0xff, 0x36, 0x9b, 0x3b, 0xdb, 0xe8, 0x8a,
- 0x4e, 0xb1, 0x7f, 0xf6, 0x3f, 0x7b, 0x47, 0x31, 0xed, 0x34, 0xd5, 0x8a,
- 0xe9, 0x13, 0x5d, 0xa6, 0xdf, 0xd2, 0x72, 0xc8, 0xf1, 0x62, 0xf7, 0xb9,
- 0xfc, 0x3d, 0x2f, 0x92, 0xdf, 0xff, 0x8f, 0xdc, 0x39, 0xae, 0xe7, 0xdc,
- 0x9f, 0xb7, 0x96, 0x2f, 0xfb, 0x0d, 0x2c, 0xf7, 0xd8, 0xc5, 0x8b, 0xf6,
- 0x19, 0x83, 0x3a, 0xc5, 0xff, 0xe9, 0xef, 0xed, 0x84, 0x36, 0xdf, 0x23,
- 0x58, 0xa9, 0x4c, 0xe9, 0x8c, 0xf4, 0xb3, 0xf3, 0xa2, 0x29, 0xbb, 0x70,
- 0x6b, 0x17, 0xff, 0xd1, 0xe7, 0x43, 0xfb, 0x61, 0xbb, 0x4d, 0x14, 0xac,
- 0x5f, 0xd9, 0xad, 0x67, 0xb8, 0xb1, 0x7f, 0x13, 0x9a, 0x77, 0x82, 0xc5,
- 0xe8, 0x37, 0xbe, 0x7b, 0x9e, 0x2e, 0xbf, 0x61, 0xcb, 0x3b, 0x58, 0xbf,
- 0xbc, 0xdb, 0xe4, 0xba, 0x58, 0xae, 0x1e, 0xc0, 0x65, 0x17, 0x7f, 0x16,
- 0x2f, 0xd2, 0x76, 0xfc, 0xac, 0x5e, 0x20, 0xfe, 0xb1, 0x7f, 0xb3, 0xdf,
- 0x6f, 0x67, 0x4b, 0x17, 0xd3, 0x85, 0xd2, 0xc5, 0x6d, 0x46, 0xac, 0x08,
- 0xf4, 0x2e, 0xe4, 0xe4, 0x3d, 0xe3, 0x4b, 0xff, 0xd3, 0x27, 0xda, 0x3f,
- 0xce, 0xdf, 0xce, 0xe2, 0xc5, 0x6c, 0x6a, 0xb5, 0x58, 0x6e, 0x28, 0x59,
- 0x7e, 0x36, 0x02, 0x57, 0xbf, 0xf4, 0x39, 0xe7, 0x8f, 0x74, 0xb3, 0xb5,
- 0x8b, 0xfb, 0xf3, 0x01, 0x38, 0x6b, 0x17, 0xe1, 0xff, 0x0b, 0xcb, 0x15,
- 0x03, 0xd7, 0x88, 0xbe, 0xbb, 0x45, 0xf1, 0x42, 0x6e, 0xff, 0xb4, 0xd8,
- 0x67, 0xbc, 0xe4, 0xb1, 0x77, 0x66, 0xac, 0x5c, 0xdd, 0xed, 0x3d, 0x31,
- 0x9c, 0xde, 0x60, 0x62, 0xc5, 0xf9, 0xa2, 0x77, 0x82, 0xc5, 0xb9, 0x03,
- 0xc4, 0xc1, 0xcb, 0xff, 0xd8, 0x66, 0xef, 0xf3, 0xd8, 0x03, 0xbc, 0x4b,
- 0x15, 0x29, 0xb2, 0xe9, 0xed, 0xdd, 0x08, 0x9e, 0xff, 0xcf, 0xbc, 0xb3,
- 0xd8, 0x02, 0x1a, 0xc5, 0x80, 0xb1, 0x4c, 0x7a, 0x31, 0x1f, 0xdf, 0xf7,
- 0xe3, 0x6c, 0x2e, 0xe1, 0xc5, 0x8b, 0xfe, 0xef, 0xf9, 0xd1, 0x60, 0xb7,
- 0x16, 0x2f, 0xf6, 0xde, 0x61, 0x4e, 0xa2, 0x58, 0xbf, 0xfd, 0x9d, 0x73,
- 0x3d, 0x16, 0x1a, 0x58, 0x05, 0x8a, 0xd2, 0x20, 0x8c, 0x36, 0xb4, 0x25,
- 0x31, 0xfc, 0x3b, 0x68, 0x60, 0x5f, 0xd3, 0xaf, 0x36, 0x76, 0xb1, 0x7f,
- 0xd2, 0x2e, 0xbb, 0xf3, 0x61, 0x2c, 0x57, 0xcf, 0xa0, 0x8b, 0xaf, 0xe6,
- 0xec, 0x1a, 0x71, 0xac, 0x5e, 0xcd, 0x01, 0x62, 0xfd, 0xc6, 0xc2, 0x02,
- 0xc5, 0xb1, 0x8f, 0x13, 0x83, 0xb7, 0xe6, 0x00, 0x33, 0x4b, 0x17, 0xc3,
- 0xfc, 0xc1, 0x62, 0x86, 0x98, 0x2f, 0xc8, 0x49, 0xcf, 0x84, 0xc1, 0x94,
- 0x5b, 0x62, 0x58, 0xbf, 0x3e, 0x13, 0x1a, 0xb1, 0x7b, 0xd9, 0xf5, 0x8a,
- 0x23, 0xc4, 0xdd, 0x27, 0xb9, 0x8e, 0xb1, 0x7d, 0xb7, 0xb1, 0x12, 0xc5,
- 0xfe, 0xc3, 0x36, 0xc8, 0x24, 0x0b, 0x17, 0xff, 0xfd, 0x07, 0xef, 0x69,
- 0x0b, 0x77, 0x6e, 0x77, 0x0c, 0x11, 0x03, 0x8b, 0x15, 0x1a, 0x29, 0xbb,
- 0x36, 0xa3, 0xa6, 0x11, 0xbc, 0x5f, 0x76, 0x19, 0x97, 0xfd, 0xb1, 0xfb,
- 0xcc, 0x5d, 0xc3, 0x8b, 0x17, 0xdb, 0x9f, 0xcd, 0xc5, 0x8b, 0xdb, 0x2c,
- 0x17, 0x58, 0xad, 0xaa, 0xa6, 0xb6, 0x34, 0xb8, 0xd6, 0xf2, 0x32, 0xc3,
- 0x4e, 0xdd, 0x03, 0x64, 0xa6, 0xff, 0xff, 0xfb, 0xbe, 0x0a, 0x7b, 0xdb,
- 0xfc, 0x1e, 0xd2, 0xc1, 0x1b, 0xb7, 0x80, 0x03, 0x79, 0x62, 0xff, 0xff,
- 0xd8, 0x33, 0x9e, 0x7d, 0xcc, 0xf7, 0x34, 0xd9, 0xd1, 0x60, 0xd6, 0x2f,
- 0xff, 0x78, 0x53, 0x91, 0xed, 0xe3, 0x13, 0x69, 0x62, 0xc6, 0x12, 0x2e,
- 0x03, 0x6c, 0xa9, 0x4d, 0xab, 0x23, 0x40, 0xbf, 0x49, 0x76, 0xf1, 0xac,
- 0x5f, 0xd1, 0x30, 0xf0, 0xec, 0xb1, 0x7f, 0xff, 0xff, 0xdd, 0x4f, 0xe4,
- 0xfe, 0xce, 0x72, 0x75, 0xa9, 0x2c, 0x8f, 0x05, 0xc1, 0x44, 0x52, 0x75,
- 0x8a, 0x94, 0x61, 0xe1, 0x75, 0xe1, 0x68, 0xd5, 0x8a, 0x39, 0xe0, 0x6c,
- 0x90, 0xdf, 0x9c, 0x01, 0xbc, 0x6b, 0x17, 0xff, 0xff, 0x47, 0xb7, 0xd1,
- 0xb6, 0x6a, 0x3d, 0xb1, 0x41, 0xbf, 0x83, 0xef, 0x37, 0x56, 0x2b, 0x11,
- 0x9c, 0xc4, 0xa2, 0x2a, 0xbc, 0xc0, 0x95, 0x8b, 0xfd, 0xb4, 0xb3, 0x4d,
- 0x27, 0x58, 0xbf, 0xf6, 0x9f, 0xda, 0xc6, 0xfc, 0x8d, 0x62, 0xfe, 0x19,
- 0x67, 0xdf, 0xcb, 0x17, 0xef, 0x77, 0x06, 0xd2, 0xc5, 0x61, 0xeb, 0xf0,
- 0xb6, 0xa3, 0x4c, 0x18, 0x63, 0x9a, 0x34, 0x04, 0x25, 0x6f, 0x69, 0xc3,
- 0x58, 0xbf, 0x4f, 0x8e, 0xde, 0x58, 0xa7, 0x3c, 0x61, 0x0f, 0x5f, 0x17,
- 0x78, 0x75, 0x8a, 0x8c, 0xf1, 0x0c, 0x21, 0xbf, 0xf4, 0x9b, 0xba, 0x2c,
- 0x28, 0x83, 0x3a, 0xc5, 0xff, 0x19, 0x9a, 0x1b, 0x67, 0xb8, 0xb1, 0x7f,
- 0x81, 0xcc, 0xdb, 0xd7, 0x8e, 0xb1, 0x7f, 0xff, 0xff, 0x8d, 0x2c, 0xda,
- 0xd8, 0x4f, 0xef, 0xcc, 0x5b, 0x4b, 0x3e, 0xde, 0xe0, 0xba, 0x14, 0xac,
- 0x56, 0x26, 0xdb, 0xd9, 0x23, 0x22, 0xb9, 0xd0, 0x8e, 0x2f, 0xff, 0x84,
- 0x17, 0xdb, 0x3f, 0x6f, 0x71, 0x8b, 0xb8, 0x2c, 0x5f, 0xfe, 0x73, 0x70,
- 0x85, 0xef, 0xe6, 0xf1, 0xca, 0xc5, 0xff, 0xd9, 0xec, 0x68, 0xf3, 0xa6,
- 0x8b, 0x8b, 0x17, 0xfe, 0xcc, 0x07, 0x36, 0xeb, 0x83, 0xe2, 0xc5, 0xfe,
- 0xd6, 0x75, 0xf6, 0xd4, 0x4b, 0x15, 0xb5, 0x17, 0xc3, 0x46, 0xc4, 0x2b,
- 0xff, 0xef, 0xb6, 0xdc, 0x8b, 0xb8, 0x73, 0xdf, 0xce, 0xd6, 0x28, 0x93,
- 0x91, 0xf4, 0x61, 0x5b, 0xcc, 0x6f, 0xbd, 0xa1, 0x1d, 0x62, 0xff, 0xff,
- 0x61, 0xce, 0xdd, 0xed, 0x34, 0xdc, 0x2f, 0x1a, 0x29, 0xd2, 0xc5, 0xd9,
- 0xd3, 0x22, 0x2f, 0x44, 0x97, 0xfe, 0x14, 0x5b, 0x7d, 0xc6, 0xdb, 0x23,
- 0x58, 0xbe, 0xec, 0xb3, 0x65, 0x62, 0xa5, 0x5a, 0x26, 0x47, 0xd0, 0xd0,
- 0xc3, 0xf9, 0x73, 0xa2, 0xdf, 0xcd, 0xf6, 0x3b, 0x8d, 0x62, 0x96, 0x2e,
- 0x20, 0x40, 0xdc, 0x8c, 0xb6, 0xf8, 0xf0, 0x26, 0x58, 0xa9, 0x3c, 0xec,
- 0x2c, 0xbc, 0xc5, 0xe5, 0x8b, 0xfa, 0x1c, 0x73, 0x8b, 0x8b, 0x15, 0x19,
- 0xe5, 0xb8, 0xe5, 0xfb, 0x3f, 0xf7, 0x82, 0xc5, 0xe9, 0x23, 0x56, 0x2f,
- 0xf6, 0xe6, 0xdc, 0xdd, 0xfc, 0xf9, 0x62, 0xfb, 0x51, 0xe7, 0x4b, 0x15,
- 0x87, 0xc2, 0xc7, 0x95, 0xf4, 0x4f, 0x79, 0xfa, 0xa5, 0xbb, 0x77, 0x8c,
- 0xf8, 0x72, 0x90, 0xf2, 0x58, 0xe9, 0xb2, 0x9f, 0xba, 0x84, 0x67, 0x71,
- 0xa0, 0xb4, 0xe2, 0x06, 0xa3, 0xe0, 0x39, 0x47, 0xe3, 0xfa, 0x78, 0xcd,
- 0x0a, 0x51, 0xdf, 0x25, 0xc6, 0xfa, 0x1b, 0x42, 0x6b, 0xd9, 0x22, 0xdd,
- 0x86, 0x35, 0xff, 0x16, 0x19, 0xbb, 0xbb, 0xec, 0xfa, 0xc5, 0xfe, 0x27,
- 0x37, 0x30, 0x8d, 0x58, 0xbb, 0xac, 0x58, 0xae, 0x91, 0x16, 0x74, 0x07,
- 0x33, 0xa5, 0x8b, 0xff, 0xb6, 0xe4, 0x5d, 0xc3, 0x9e, 0xfe, 0x76, 0xb1,
- 0x7f, 0xcd, 0x9d, 0x96, 0xde, 0x61, 0x2c, 0x5e, 0xfb, 0x69, 0x62, 0xbe,
- 0x7a, 0xfb, 0xa7, 0x57, 0xfa, 0x12, 0x3d, 0xa3, 0x68, 0x96, 0x2f, 0xfb,
- 0x6f, 0x8b, 0x0c, 0xc6, 0xe2, 0xc5, 0xff, 0xb0, 0xd9, 0x2e, 0xb6, 0xef,
- 0xe1, 0x8b, 0x17, 0xff, 0xfe, 0xf3, 0xc4, 0x59, 0x1b, 0xed, 0x2e, 0xf0,
- 0xc2, 0xc1, 0x61, 0xab, 0x14, 0x14, 0x4f, 0xee, 0x30, 0xce, 0xa1, 0x45,
- 0xd9, 0x2c, 0x46, 0xff, 0x3b, 0xdd, 0x46, 0xbd, 0xf9, 0x02, 0xc5, 0xfe,
- 0xfb, 0x02, 0x7c, 0xdb, 0xd6, 0x2f, 0xe6, 0x69, 0x32, 0x62, 0x58, 0xbe,
- 0xf3, 0x90, 0x16, 0x2f, 0xff, 0xce, 0x69, 0xa0, 0x78, 0xb7, 0x4a, 0x4c,
- 0xee, 0x1c, 0x58, 0xb0, 0x6e, 0x88, 0x02, 0x22, 0xbc, 0x6e, 0x71, 0x62,
- 0xf9, 0xf7, 0x24, 0x0b, 0x15, 0xb1, 0xae, 0x05, 0xcc, 0xa2, 0xbc, 0x75,
- 0xe8, 0x76, 0x23, 0x57, 0x85, 0x71, 0x14, 0x18, 0x3d, 0x7b, 0x9e, 0x65,
- 0x8a, 0x58, 0xbf, 0xb0, 0xf3, 0xf7, 0xfa, 0xc5, 0xb4, 0xb1, 0x4b, 0x15,
- 0x85, 0xf4, 0x42, 0x57, 0xa7, 0x34, 0xb1, 0x5b, 0x4d, 0xe1, 0x10, 0x5e,
- 0xfb, 0x1a, 0xb1, 0x5b, 0x51, 0x8e, 0x38, 0x43, 0x9a, 0x45, 0x7f, 0xfd,
- 0xdc, 0x0a, 0x76, 0x9c, 0xa4, 0xdf, 0x34, 0x6b, 0x17, 0xb9, 0xa3, 0xac,
- 0x5f, 0xfd, 0xb7, 0xda, 0xc3, 0x32, 0x32, 0xc3, 0x16, 0x2b, 0x6a, 0x7c,
- 0x72, 0x3b, 0x90, 0xd3, 0x63, 0x82, 0x54, 0xf0, 0xf5, 0xfb, 0x5b, 0x4b,
- 0x79, 0x8b, 0x17, 0xff, 0xe3, 0x41, 0x17, 0x36, 0xf8, 0xf3, 0xfc, 0x2e,
- 0xf1, 0x62, 0xf8, 0xdd, 0x91, 0x79, 0x62, 0xdc, 0x58, 0xbc, 0xe0, 0x95,
- 0x8a, 0xd1, 0xeb, 0x1c, 0xa3, 0xe2, 0x57, 0x9e, 0x29, 0x58, 0xbd, 0xfc,
- 0xd2, 0xc5, 0x4a, 0x69, 0x10, 0x2e, 0x78, 0x58, 0x98, 0x5f, 0xba, 0x3b,
- 0x7f, 0x47, 0x14, 0x36, 0x3d, 0x46, 0xb1, 0x7c, 0x19, 0x66, 0xf5, 0x8b,
- 0xe6, 0x1e, 0x0d, 0x62, 0xbb, 0x3c, 0x73, 0x92, 0xda, 0x25, 0x8b, 0xa4,
- 0xeb, 0x16, 0xf2, 0xc5, 0x68, 0xd4, 0xb8, 0xbd, 0x0c, 0xf7, 0x3e, 0x79,
- 0x7d, 0x23, 0x78, 0x2c, 0x5e, 0xf6, 0x71, 0x62, 0xff, 0xd8, 0xfd, 0x82,
- 0x28, 0x4e, 0xa3, 0x58, 0xbd, 0xa9, 0x89, 0x62, 0xe1, 0x18, 0xb1, 0x73,
- 0xf6, 0xb1, 0x58, 0x6c, 0x78, 0x33, 0x51, 0xa3, 0xc0, 0xd2, 0x2f, 0x8e,
- 0xba, 0x17, 0x93, 0xef, 0xa0, 0xe5, 0xb2, 0xb1, 0x74, 0x4e, 0xb1, 0x74,
- 0x23, 0x58, 0xbd, 0xe9, 0x82, 0xc5, 0xfd, 0xf7, 0xec, 0x01, 0x9d, 0x62,
- 0xfb, 0x3d, 0x87, 0x58, 0xad, 0xa7, 0xe1, 0x83, 0xae, 0x63, 0x7f, 0xfd,
- 0x92, 0x40, 0x96, 0xf7, 0xf0, 0xf8, 0x35, 0x8b, 0xc1, 0x8a, 0x35, 0x8b,
- 0xa4, 0xd5, 0x8a, 0x8d, 0x16, 0x90, 0x2f, 0x35, 0x37, 0xc4, 0x17, 0xf3,
- 0x99, 0x3e, 0xc8, 0xd6, 0x2f, 0xe6, 0xd7, 0x70, 0x29, 0x58, 0xbf, 0x4f,
- 0xa0, 0xde, 0x58, 0xbf, 0xbf, 0x3d, 0xc3, 0x3c, 0xb1, 0x50, 0x3d, 0x71,
- 0x94, 0x57, 0xd1, 0x4f, 0xe8, 0x42, 0xdf, 0xf4, 0x7a, 0xc8, 0xa0, 0xc4,
- 0x6a, 0xc5, 0xff, 0x49, 0x7b, 0x4d, 0xbf, 0x06, 0xb1, 0x4e, 0x7e, 0xdb,
- 0x27, 0x97, 0x67, 0x96, 0x2d, 0x12, 0xc5, 0x7c, 0xd5, 0x10, 0xbd, 0x05,
- 0x17, 0x7d, 0xa5, 0xff, 0x1f, 0xda, 0x31, 0x28, 0x92, 0xce, 0x4b, 0xf1,
- 0x87, 0x8c, 0xf4, 0x8f, 0xc5, 0x0d, 0x6d, 0x98, 0x4f, 0x06, 0x9d, 0x7f,
- 0xff, 0xed, 0xbd, 0x7d, 0xbe, 0x2f, 0x6d, 0xc1, 0xb7, 0x3b, 0xf0, 0x9f,
- 0x8b, 0x17, 0xf6, 0x40, 0x84, 0xfc, 0x58, 0xa1, 0xa2, 0x84, 0xc7, 0x4b,
- 0x71, 0x62, 0xf7, 0xdb, 0x4b, 0x17, 0xf1, 0x0b, 0x9a, 0xe7, 0x16, 0x2b,
- 0x47, 0x99, 0xbc, 0x76, 0xfd, 0xd9, 0x8e, 0x40, 0x58, 0xb8, 0x8d, 0x58,
- 0xb7, 0x18, 0xf0, 0x84, 0x55, 0x73, 0xfd, 0x62, 0xff, 0xc7, 0x93, 0x7d,
- 0xfc, 0xf4, 0x81, 0x62, 0xfc, 0xe3, 0x9c, 0x25, 0x8b, 0x1a, 0xb1, 0x51,
- 0xa2, 0x41, 0x85, 0xfe, 0x80, 0x44, 0xd7, 0xcd, 0xec, 0xe2, 0xc5, 0xff,
- 0x78, 0x9f, 0xe7, 0x9c, 0xf2, 0xc5, 0xf1, 0xcb, 0x3a, 0xda, 0x7b, 0x5d,
- 0x91, 0x5f, 0xff, 0x64, 0x6e, 0x5d, 0x6d, 0xe4, 0x9d, 0xfb, 0xf2, 0xc5,
- 0x4a, 0x24, 0x34, 0x79, 0x7f, 0xb7, 0x3f, 0x91, 0xeb, 0x52, 0xb1, 0x4b,
- 0x17, 0xf7, 0x03, 0x3e, 0xb5, 0x2b, 0x17, 0xff, 0x3c, 0x30, 0x86, 0x53,
- 0x01, 0xf1, 0x62, 0xd9, 0x87, 0xff, 0xe0, 0xcd, 0xe6, 0x17, 0xfd, 0xb7,
- 0x82, 0x9e, 0xc5, 0x9f, 0x58, 0xbb, 0x9b, 0x12, 0xc5, 0xff, 0xe2, 0xc3,
- 0xcf, 0x5b, 0x43, 0x8e, 0x37, 0xed, 0x62, 0xfe, 0x11, 0xce, 0xf0, 0xdb,
- 0xe3, 0xee, 0xdd, 0x1d, 0xbf, 0x0a, 0x01, 0xeb, 0x8b, 0x16, 0x68, 0x26,
- 0x41, 0xf8, 0x55, 0x92, 0x55, 0xf8, 0x79, 0x17, 0xd9, 0x62, 0xfb, 0x22,
- 0xfb, 0x2c, 0x5b, 0xad, 0xa7, 0x98, 0x32, 0x9b, 0xff, 0xf4, 0xea, 0x7a,
- 0xc3, 0xcf, 0x50, 0x6e, 0x08, 0xeb, 0x15, 0x2b, 0xbf, 0x71, 0x92, 0x62,
- 0xf4, 0x4c, 0xda, 0x85, 0xbf, 0xe3, 0x26, 0x72, 0x22, 0x85, 0xbf, 0xa3,
- 0x55, 0x14, 0x21, 0xb6, 0x4a, 0xef, 0xed, 0x64, 0x9b, 0x24, 0xb1, 0x73,
- 0xfd, 0x62, 0xe0, 0xa6, 0xc4, 0xb1, 0x78, 0x9c, 0xeb, 0x17, 0xfe, 0x7e,
- 0xfb, 0x80, 0xa3, 0xdb, 0xec, 0x58, 0xbf, 0xff, 0xfb, 0x37, 0x62, 0x9f,
- 0xe7, 0x8a, 0x62, 0xdb, 0x85, 0x9d, 0xc1, 0xb8, 0xb1, 0x7f, 0xff, 0x7d,
- 0xe2, 0x38, 0x89, 0xcd, 0xe6, 0x75, 0xf1, 0x6e, 0x2c, 0x5d, 0x3e, 0x02,
- 0x36, 0x78, 0xef, 0x7d, 0xee, 0x77, 0x05, 0x8b, 0x4a, 0xc5, 0x61, 0xb6,
- 0x01, 0x2d, 0xd9, 0xc5, 0x8b, 0xff, 0xf7, 0x70, 0xe6, 0xdc, 0x10, 0x5d,
- 0xbe, 0xe5, 0x9b, 0xd6, 0x2f, 0xfc, 0x7c, 0xee, 0x1c, 0x79, 0xee, 0x0b,
- 0x15, 0xd2, 0x2d, 0x8e, 0x2f, 0xf5, 0xeb, 0xff, 0x6a, 0x2e, 0x4e, 0x9e,
- 0x0d, 0xf5, 0x8b, 0x83, 0x8d, 0x62, 0x99, 0x11, 0x6e, 0x62, 0x48, 0x15,
- 0x05, 0x72, 0x38, 0x5b, 0xd8, 0xbb, 0x10, 0xe8, 0x73, 0xf1, 0x8f, 0x13,
- 0x27, 0xa3, 0x61, 0xa0, 0xa4, 0x6a, 0x62, 0xfb, 0x14, 0x2f, 0x42, 0xb2,
- 0x85, 0x36, 0x08, 0x7b, 0x6c, 0x73, 0x80, 0xbb, 0x0e, 0x19, 0x7b, 0x09,
- 0x40, 0x2d, 0xc2, 0x4c, 0x2c, 0x84, 0xbc, 0xd3, 0x55, 0x63, 0x9c, 0xcd,
- 0x84, 0xe6, 0xa0, 0xe9, 0xba, 0x79, 0x6a, 0x86, 0x0d, 0x9d, 0x13, 0xea,
- 0xb2, 0x49, 0xee, 0x94, 0xfc, 0xd4, 0x89, 0x98, 0xa9, 0x2f, 0xda, 0xa7,
- 0xc3, 0x9e, 0x92, 0x61, 0xfb, 0x50, 0x18, 0xf4, 0x9d, 0xa0, 0x4f, 0xba,
- 0x05, 0xe3, 0x22, 0x2a, 0xfc, 0x5f, 0x95, 0xd0, 0xd7, 0xab, 0xd7, 0x61,
- 0x4e, 0xf2, 0xef, 0x94, 0xce, 0x64, 0x74, 0x7b, 0x33, 0xc9, 0x01, 0xcf,
- 0xaf, 0x6e, 0xce, 0x24, 0x5f, 0xff, 0xc2, 0xe8, 0x27, 0x7e, 0xd4, 0xe7,
- 0x7b, 0x18, 0xdd, 0xcd, 0x58, 0xa0, 0x8a, 0xdc, 0x1a, 0x58, 0x4d, 0xfc,
- 0xed, 0xee, 0x31, 0x2c, 0x5e, 0x6d, 0x62, 0xc5, 0x6e, 0x1e, 0x47, 0x0b,
- 0x2f, 0xda, 0xe9, 0xdf, 0xa5, 0x45, 0x3a, 0x5d, 0x9d, 0xac, 0x5f, 0xfe,
- 0x10, 0x89, 0x8a, 0x7e, 0xc7, 0xce, 0x2c, 0x5d, 0xa3, 0xac, 0x54, 0xa3,
- 0x53, 0x09, 0x7b, 0x37, 0x38, 0xc0, 0x12, 0x2e, 0x89, 0xd6, 0x2f, 0xbc,
- 0xe4, 0x6a, 0xc5, 0xf8, 0xd7, 0x80, 0x40, 0xe4, 0xdd, 0xf6, 0x31, 0x41,
- 0x11, 0x8c, 0x6c, 0x21, 0x2f, 0xff, 0xd0, 0x09, 0x90, 0xfe, 0x34, 0x39,
- 0x3e, 0x91, 0xac, 0x5e, 0xed, 0xe3, 0x58, 0xbb, 0x38, 0xb1, 0x52, 0x6d,
- 0xb0, 0x7e, 0xfa, 0x38, 0xe7, 0xb5, 0x8b, 0xf9, 0xe3, 0xf7, 0x1c, 0x0b,
- 0x17, 0x68, 0x27, 0xcf, 0xd1, 0xc7, 0xf6, 0x49, 0xaa, 0x53, 0x40, 0x68,
- 0xc0, 0x6f, 0xda, 0xe9, 0xdf, 0xa5, 0x45, 0x46, 0x5f, 0xf9, 0xe0, 0x13,
- 0x35, 0xd3, 0xbf, 0x4a, 0x89, 0xa0, 0xbf, 0xfc, 0x59, 0x14, 0x1f, 0x50,
- 0x2c, 0xde, 0xeb, 0x17, 0xa7, 0x3b, 0x58, 0xbc, 0xf1, 0xca, 0xc5, 0x11,
- 0xba, 0x10, 0xed, 0x62, 0x65, 0x67, 0x37, 0xe2, 0x7f, 0xa1, 0x0b, 0x7f,
- 0x83, 0x7d, 0xe1, 0x3c, 0xd1, 0xac, 0x50, 0x43, 0xfc, 0x94, 0x2b, 0xff,
- 0xec, 0xf3, 0x7c, 0x5f, 0x76, 0xef, 0x92, 0x6a, 0xc5, 0xfa, 0x30, 0xe3,
- 0x98, 0xd6, 0x2f, 0xba, 0x77, 0xe9, 0x51, 0x57, 0x95, 0x87, 0xbd, 0xa2,
- 0xdb, 0xff, 0xdf, 0x6f, 0x72, 0x61, 0xf9, 0x31, 0xc9, 0x62, 0xff, 0xef,
- 0x03, 0x07, 0xfc, 0x18, 0xdb, 0xb5, 0x8b, 0xf6, 0xf9, 0x2f, 0x89, 0x62,
- 0xff, 0xcf, 0xdc, 0x39, 0x9d, 0x0f, 0x3b, 0x58, 0xac, 0x3e, 0xc7, 0x2a,
- 0xbf, 0x98, 0x63, 0x9d, 0x4a, 0xc5, 0xfb, 0x84, 0xf3, 0xc5, 0x8b, 0xff,
- 0xff, 0x61, 0x30, 0xce, 0xee, 0x5d, 0x0f, 0xf3, 0x83, 0x62, 0x8d, 0x62,
- 0xa5, 0x12, 0x30, 0x27, 0xbf, 0xf9, 0xff, 0x13, 0xfb, 0xdd, 0xf4, 0xc4,
- 0xb1, 0x7f, 0xfe, 0x01, 0x08, 0xe1, 0x8c, 0x72, 0x03, 0xce, 0x79, 0x62,
- 0xfe, 0x7f, 0x73, 0x3b, 0xf2, 0xc5, 0x76, 0x88, 0x62, 0x57, 0xb0, 0x41,
- 0xab, 0xbc, 0xc8, 0x57, 0xf4, 0x43, 0xda, 0x56, 0xa1, 0x65, 0xf2, 0x0f,
- 0x42, 0xf8, 0xc2, 0x20, 0xe1, 0x9b, 0x7e, 0xd7, 0x4e, 0xfd, 0x2a, 0x2b,
- 0x62, 0xff, 0xa0, 0x13, 0x35, 0xd3, 0xbf, 0x4a, 0x89, 0x04, 0xbe, 0xc3,
- 0xce, 0xe2, 0xc5, 0x82, 0x62, 0x29, 0x9c, 0xdf, 0x89, 0x57, 0xc7, 0x62,
- 0x95, 0x8b, 0xf6, 0xba, 0x77, 0xe9, 0x51, 0x21, 0x97, 0xf6, 0x85, 0xbe,
- 0x4c, 0x3a, 0xc5, 0xfc, 0x59, 0xcf, 0x42, 0x56, 0x2f, 0x3c, 0x02, 0x4a,
- 0x2d, 0xf0, 0x85, 0x8d, 0xf7, 0x99, 0x5f, 0xfd, 0x18, 0x40, 0xcf, 0xb7,
- 0x34, 0xfe, 0xe2, 0xc5, 0x04, 0x44, 0xdb, 0x27, 0xdf, 0xec, 0xf3, 0x0f,
- 0x0a, 0x25, 0x8b, 0xfc, 0xe6, 0x84, 0x34, 0xdc, 0xdc, 0x58, 0xb7, 0x02,
- 0x1f, 0x79, 0x19, 0xde, 0x77, 0xe9, 0x71, 0x81, 0x95, 0x27, 0xa7, 0xd1,
- 0x4d, 0xba, 0x58, 0xb6, 0xe2, 0xc5, 0x61, 0xa8, 0xf8, 0x9d, 0xc6, 0x79,
- 0x62, 0xf7, 0x18, 0xd5, 0x8a, 0x19, 0xb7, 0xec, 0x66, 0xed, 0x82, 0x35,
- 0x8b, 0xfe, 0xfc, 0xfb, 0x9b, 0x17, 0x36, 0x02, 0x58, 0xa0, 0xa1, 0xf1,
- 0x40, 0x7a, 0xfb, 0xde, 0xcd, 0xd5, 0x8b, 0x12, 0xc5, 0xe0, 0xb4, 0xd9,
- 0x0a, 0x2c, 0x5e, 0x9d, 0x90, 0xa2, 0xc5, 0x05, 0xa1, 0xe8, 0x49, 0x65,
- 0x99, 0x62, 0xb6, 0x24, 0x4d, 0x6c, 0x36, 0x10, 0xb5, 0x28, 0xbf, 0xfc,
- 0x16, 0xa1, 0x6b, 0xb1, 0x7e, 0x4e, 0x4f, 0xf6, 0xd2, 0xc5, 0xbb, 0x58,
- 0xb8, 0xa0, 0xb1, 0x7b, 0xd8, 0x05, 0x8b, 0x12, 0xc5, 0xf0, 0x86, 0xfb,
- 0x8b, 0x14, 0xc6, 0xdf, 0x82, 0x37, 0x85, 0xec, 0x58, 0xba, 0x62, 0x58,
- 0xbf, 0x8f, 0x9d, 0x13, 0xee, 0x2c, 0x5e, 0xc6, 0x8d, 0x62, 0xc1, 0xac,
- 0x56, 0x1f, 0x0e, 0x8c, 0x44, 0x3b, 0x7e, 0x1c, 0xf9, 0xc6, 0xb1, 0x63,
- 0xac, 0x5c, 0xdb, 0xd6, 0x2a, 0x4f, 0x4d, 0x8a, 0x3c, 0x25, 0x7b, 0xf9,
- 0xc5, 0x8b, 0x3a, 0xc5, 0x0c, 0xd7, 0x78, 0x76, 0x86, 0xa8, 0xc7, 0x04,
- 0xf7, 0x05, 0xe2, 0x54, 0xd1, 0x07, 0xc7, 0x78, 0xf3, 0xe8, 0x40, 0x86,
- 0xb7, 0x7f, 0x14, 0xf7, 0x06, 0x25, 0x8b, 0xdc, 0x6d, 0xeb, 0x14, 0x33,
- 0xcc, 0xf1, 0x6d, 0x89, 0x62, 0xfc, 0x39, 0x28, 0xf7, 0x16, 0x2f, 0xf4,
- 0x9a, 0x18, 0x01, 0x3d, 0xac, 0x54, 0x9f, 0x1c, 0x65, 0x97, 0xe7, 0xfb,
- 0x1f, 0x16, 0x2b, 0x11, 0x7a, 0x4e, 0x9b, 0xc8, 0xaf, 0xec, 0xeb, 0xf3,
- 0x31, 0x2c, 0x5b, 0x65, 0x62, 0x98, 0xfd, 0x3e, 0x60, 0x22, 0xfb, 0xc4,
- 0x0e, 0x2c, 0x5f, 0x9e, 0x30, 0xf2, 0x25, 0x8a, 0xc3, 0xc8, 0x21, 0xdb,
- 0xdb, 0x39, 0xda, 0xc5, 0xee, 0x8b, 0x71, 0x62, 0xff, 0xce, 0x67, 0xd9,
- 0xe1, 0xe6, 0x8d, 0x62, 0x9c, 0xf8, 0x48, 0x86, 0xff, 0xc0, 0xce, 0xf8,
- 0x1e, 0x98, 0xf8, 0xb1, 0x73, 0x44, 0xb1, 0x6c, 0xec, 0xf6, 0x74, 0x83,
- 0x7d, 0x1f, 0x3b, 0x65, 0x8b, 0xff, 0xd3, 0xdc, 0x18, 0xe6, 0x61, 0x0f,
- 0xf2, 0xb1, 0x58, 0x9d, 0x9b, 0x10, 0x6a, 0x10, 0x44, 0xf3, 0xc2, 0x81,
- 0x12, 0xdf, 0x9c, 0x61, 0xc9, 0x2c, 0x5f, 0xe6, 0x16, 0xe7, 0xe7, 0x23,
- 0x58, 0xbf, 0xf6, 0xbc, 0x19, 0x3f, 0x58, 0x5d, 0x2c, 0x5e, 0x3b, 0x6c,
- 0xac, 0x5f, 0xec, 0xdf, 0x85, 0x9d, 0xf9, 0x62, 0xa4, 0xf5, 0x7e, 0x41,
- 0x74, 0xee, 0xac, 0x5f, 0xf8, 0xc7, 0x86, 0xb1, 0xbf, 0x23, 0x58, 0xbe,
- 0xe9, 0xdf, 0xa5, 0x45, 0x88, 0x5f, 0x69, 0xcb, 0xcb, 0x16, 0x02, 0xc5,
- 0x68, 0xda, 0x6e, 0x91, 0x5f, 0xda, 0xfb, 0xf3, 0x03, 0x58, 0xbb, 0xe2,
- 0x58, 0xbe, 0xe0, 0x65, 0x05, 0x8a, 0x19, 0xbc, 0xf0, 0xc5, 0x32, 0x23,
- 0x1d, 0xae, 0xfe, 0x2f, 0xbf, 0x27, 0x71, 0x62, 0xc6, 0x2c, 0x5d, 0xc6,
- 0x58, 0xa6, 0x35, 0x40, 0x13, 0xbf, 0xf4, 0x33, 0x9e, 0xfe, 0x36, 0xa0,
- 0xb1, 0x4c, 0x7b, 0xe2, 0x20, 0xbf, 0xa6, 0x7b, 0x3b, 0x8d, 0x62, 0xff,
- 0x0c, 0x02, 0xf7, 0x05, 0xb8, 0xb1, 0x71, 0x41, 0x62, 0xa4, 0xf4, 0x04,
- 0x73, 0x7f, 0xba, 0x9c, 0xd0, 0x01, 0xe5, 0x8a, 0x8d, 0x71, 0x4e, 0x05,
- 0x18, 0x6f, 0xd4, 0x25, 0xbb, 0x21, 0x61, 0xad, 0x1f, 0x9d, 0x97, 0xf0,
- 0xb0, 0x72, 0x12, 0x85, 0xcf, 0x08, 0x7c, 0xfc, 0x22, 0x1b, 0xed, 0x49,
- 0x1a, 0xb1, 0x7a, 0x13, 0xb8, 0xb1, 0x58, 0x78, 0x71, 0x11, 0xdf, 0xfe,
- 0xf7, 0xb2, 0x3e, 0x4e, 0x9e, 0x0d, 0xf5, 0x8b, 0x32, 0xc5, 0x99, 0x62,
- 0xd0, 0x34, 0xd1, 0x00, 0x46, 0xfc, 0x1e, 0xce, 0x6a, 0x56, 0x2e, 0x16,
- 0x96, 0x2f, 0xbd, 0x25, 0x1a, 0xc5, 0x44, 0x6e, 0xfc, 0x31, 0x62, 0x58,
- 0xba, 0x49, 0x62, 0xfe, 0x9e, 0x07, 0x1c, 0xc6, 0xb1, 0x44, 0x7b, 0x1c,
- 0x11, 0x0c, 0x5a, 0xfb, 0x73, 0xe2, 0xdc, 0x58, 0xa9, 0x4c, 0xeb, 0x19,
- 0xd9, 0xe8, 0x45, 0xf7, 0xfc, 0x28, 0xcb, 0x07, 0xf1, 0x1a, 0xb1, 0x52,
- 0xa9, 0x18, 0xd6, 0xdf, 0xc6, 0xc4, 0x47, 0x77, 0xdf, 0xe0, 0xa5, 0x62,
- 0xff, 0xf6, 0x77, 0xd8, 0x1f, 0xdc, 0x62, 0xee, 0x0b, 0x17, 0xff, 0x4e,
- 0x73, 0x08, 0x6c, 0x09, 0x25, 0x8b, 0xc5, 0x31, 0xac, 0x53, 0x22, 0xac,
- 0x93, 0x44, 0x83, 0x70, 0xb4, 0xb1, 0x7d, 0x3a, 0x93, 0xac, 0x54, 0xa6,
- 0x6d, 0x08, 0x67, 0x39, 0x77, 0x06, 0x2f, 0x86, 0x1e, 0xc5, 0x05, 0x8b,
- 0xf0, 0x3a, 0xfb, 0x05, 0xd6, 0x2f, 0x7f, 0x00, 0xb1, 0x7f, 0x77, 0xcf,
- 0xcb, 0x79, 0x62, 0xe7, 0xf2, 0xc5, 0x31, 0xe3, 0x1c, 0xbe, 0xf3, 0xe7,
- 0xd6, 0x2e, 0x90, 0x2c, 0x54, 0x9b, 0x3f, 0x8e, 0x5c, 0x2d, 0x95, 0x8b,
- 0xe6, 0x29, 0x8d, 0x62, 0xff, 0xfb, 0xd9, 0xdc, 0x08, 0x5e, 0x76, 0x29,
- 0x1a, 0xc5, 0xfc, 0x72, 0xc9, 0xdc, 0x89, 0x62, 0xc0, 0x58, 0xa9, 0x3c,
- 0x36, 0x31, 0xbb, 0xd0, 0x58, 0xbc, 0xf3, 0xda, 0xc5, 0x6c, 0x0a, 0x94,
- 0xf0, 0xab, 0xa2, 0xed, 0x31, 0xfd, 0x50, 0x88, 0x38, 0x37, 0xe2, 0x2d,
- 0x98, 0x49, 0x06, 0x41, 0xba, 0x31, 0x79, 0xfd, 0xc5, 0x8b, 0xff, 0xed,
- 0x40, 0xe5, 0x3a, 0x91, 0xe4, 0x53, 0xf5, 0x8a, 0x63, 0xed, 0x71, 0xdb,
- 0xec, 0xe9, 0xf8, 0xb1, 0x7d, 0xbc, 0x4f, 0xc5, 0x8b, 0x32, 0xc5, 0xff,
- 0x4f, 0xb9, 0xcf, 0x4f, 0x66, 0x2c, 0x5f, 0x9b, 0x4c, 0x60, 0x5d, 0x62,
- 0xdd, 0xac, 0x54, 0x11, 0xeb, 0x84, 0x0c, 0x47, 0x11, 0x2e, 0x84, 0x7e,
- 0x78, 0x19, 0x6d, 0xff, 0x9b, 0xfd, 0xc3, 0x3d, 0x9d, 0xf9, 0x62, 0xff,
- 0x7f, 0x0f, 0x8f, 0xa8, 0xd6, 0x2a, 0x07, 0xea, 0x34, 0x1b, 0xf7, 0xbc,
- 0xf0, 0xe2, 0xc5, 0xec, 0xd4, 0xac, 0x5e, 0x2c, 0x3a, 0xc6, 0xc9, 0x79,
- 0x7f, 0xe1, 0x67, 0x63, 0xdf, 0xfc, 0x78, 0x96, 0x2b, 0xb4, 0x5b, 0x44,
- 0x8b, 0xbc, 0xba, 0xd0, 0x58, 0xbd, 0xdf, 0x1d, 0x62, 0xfb, 0x30, 0xce,
- 0x2c, 0x54, 0x9e, 0x9e, 0x09, 0x78, 0x7a, 0xdb, 0xd6, 0x2e, 0x11, 0x2c,
- 0x58, 0x2e, 0xb1, 0x6d, 0xeb, 0x15, 0x29, 0xf0, 0xe4, 0x36, 0x35, 0x08,
- 0x70, 0x16, 0xf0, 0x53, 0xc2, 0xfb, 0xc5, 0xaf, 0xee, 0xa7, 0xdf, 0xc0,
- 0x2c, 0x5f, 0xc1, 0xe6, 0xb3, 0x22, 0x58, 0xa2, 0x3d, 0xee, 0x17, 0xdf,
- 0xbb, 0xe4, 0xeb, 0x8b, 0x17, 0xfc, 0xfe, 0xe0, 0xc4, 0xfa, 0x82, 0xc5,
- 0xfe, 0x8f, 0xb8, 0x70, 0x9a, 0x25, 0x8b, 0xef, 0x10, 0xa3, 0x58, 0xa9,
- 0x3d, 0xb2, 0x37, 0xa9, 0x4c, 0x03, 0x08, 0x48, 0xa8, 0x50, 0x95, 0xbf,
- 0xb5, 0x00, 0x66, 0x44, 0xb1, 0x70, 0x83, 0x58, 0xbe, 0x79, 0x6d, 0x95,
- 0x8b, 0xf7, 0xdb, 0x7c, 0x92, 0xc5, 0xce, 0x1a, 0xc5, 0x0c, 0xf0, 0x44,
- 0x53, 0x77, 0x22, 0x58, 0xbd, 0xa0, 0xf8, 0xb1, 0x58, 0x98, 0x39, 0xa5,
- 0xfa, 0x19, 0x26, 0x5f, 0x11, 0x6f, 0x19, 0xbf, 0xee, 0x1b, 0xa9, 0x1f,
- 0xe7, 0x7a, 0xc5, 0xf4, 0x03, 0xfc, 0xac, 0x5e, 0xd4, 0xc1, 0x62, 0x9c,
- 0xf0, 0x77, 0x92, 0x5f, 0x8f, 0x8d, 0xa8, 0x96, 0x2d, 0xb8, 0xb1, 0x52,
- 0x6f, 0x9c, 0xa6, 0xf8, 0x39, 0xdd, 0xe2, 0xc5, 0xb8, 0xb1, 0x7f, 0xc4,
- 0xe7, 0xe6, 0x1e, 0x77, 0x16, 0x2f, 0xd2, 0x3c, 0x7d, 0xc5, 0x8a, 0x23,
- 0xe5, 0xde, 0x77, 0x7f, 0xe6, 0x8d, 0xcb, 0xef, 0xc9, 0xdc, 0x58, 0xbd,
- 0xf9, 0xfa, 0xc5, 0x2c, 0x5b, 0x06, 0x6a, 0x4e, 0x3b, 0x7d, 0xa6, 0x33,
- 0x71, 0x62, 0x99, 0x1b, 0x5f, 0x23, 0x26, 0xae, 0x13, 0x5f, 0xfe, 0xd3,
- 0x1e, 0x7b, 0xfc, 0x8c, 0x9f, 0x71, 0x62, 0x86, 0xa8, 0x03, 0x09, 0xf9,
- 0x1a, 0x8f, 0x8e, 0xef, 0xba, 0xfc, 0xe9, 0x62, 0xf3, 0x66, 0x96, 0x2b,
- 0xb3, 0xc0, 0x0c, 0x92, 0xff, 0x00, 0x4e, 0x1f, 0xe6, 0x0b, 0x15, 0x2b,
- 0x86, 0x98, 0xb2, 0xcf, 0xdf, 0x61, 0x79, 0x43, 0xe2, 0x84, 0x21, 0x84,
- 0x97, 0x4c, 0x16, 0x2f, 0xdd, 0x7e, 0x7b, 0xdd, 0x58, 0xa1, 0x9e, 0x2f,
- 0x62, 0xf6, 0x1a, 0xc5, 0xf8, 0x9c, 0xf3, 0xf5, 0x8a, 0xc3, 0x72, 0xc2,
- 0x57, 0xff, 0xa4, 0xf3, 0x01, 0x94, 0xfd, 0xf3, 0x4b, 0x14, 0xb1, 0x50,
- 0x3d, 0x4d, 0x94, 0x8b, 0xf1, 0x4f, 0xe7, 0x71, 0x62, 0xf7, 0xb0, 0x0b,
- 0x17, 0xf1, 0xdb, 0x9c, 0x61, 0xac, 0x5e, 0x7d, 0x1a, 0xb1, 0x42, 0x3c,
- 0xc3, 0x0b, 0xaf, 0xe2, 0xcd, 0xe5, 0x9c, 0x58, 0xb9, 0xb4, 0xb1, 0x5d,
- 0x1e, 0x2f, 0xcb, 0xad, 0xc5, 0x8b, 0xfd, 0xb9, 0xb4, 0x39, 0x27, 0x35,
- 0x62, 0xff, 0x41, 0xf0, 0xb3, 0xdc, 0x58, 0xbf, 0x66, 0x17, 0x7e, 0x58,
- 0xbf, 0xd9, 0xf2, 0xcf, 0x7d, 0x96, 0x28, 0x67, 0xb5, 0xe2, 0x8a, 0x94,
- 0x7d, 0x60, 0x97, 0x67, 0x40, 0x84, 0x65, 0xf0, 0xe5, 0xf4, 0xb1, 0x78,
- 0xfc, 0xe2, 0xc5, 0xf8, 0xef, 0xf6, 0x89, 0x62, 0xa4, 0xf1, 0xdc, 0x7a,
- 0xff, 0xd9, 0xdc, 0x3f, 0x3c, 0x37, 0xf2, 0xb1, 0x52, 0xb8, 0x2f, 0x05,
- 0xce, 0xdc, 0xd8, 0x96, 0x22, 0xad, 0x34, 0xfd, 0xa0, 0xa3, 0x1d, 0xe2,
- 0x0f, 0x9a, 0x77, 0x48, 0x2f, 0xbc, 0xef, 0x1a, 0xc5, 0xb6, 0x56, 0x2e,
- 0x87, 0x16, 0x2c, 0xf0, 0x35, 0xbd, 0x8a, 0xdf, 0x79, 0x88, 0xc4, 0x8b,
- 0x09, 0x62, 0xd3, 0x86, 0xd7, 0xe4, 0x77, 0x66, 0x96, 0x2f, 0xf1, 0x7b,
- 0x9d, 0xf1, 0xf7, 0x16, 0x2f, 0xec, 0x1e, 0xe6, 0x77, 0xb8, 0xb1, 0x4e,
- 0x7d, 0xa4, 0x71, 0x5b, 0x89, 0xba, 0xba, 0x80, 0x17, 0x08, 0x94, 0x50,
- 0x84, 0xbc, 0x1f, 0xc4, 0xb1, 0x7f, 0xe3, 0x8a, 0x2e, 0xf9, 0x31, 0x36,
- 0xf5, 0x8b, 0xfc, 0xdc, 0xfb, 0x94, 0xca, 0xc5, 0xc2, 0xfa, 0xc5, 0xfe,
- 0x2e, 0xbd, 0xe7, 0x87, 0x16, 0x2b, 0x47, 0xfc, 0x73, 0x11, 0x0c, 0x5f,
- 0xff, 0x67, 0xfb, 0x87, 0x22, 0x83, 0x17, 0xa4, 0x0b, 0x17, 0xf4, 0x9c,
- 0xa7, 0xb8, 0x2c, 0x53, 0x22, 0x03, 0xea, 0x57, 0xb5, 0xac, 0x58, 0xbd,
- 0xdc, 0x38, 0xb1, 0x77, 0xdb, 0x86, 0xf0, 0xc1, 0xdb, 0xe8, 0xce, 0xfe,
- 0x58, 0xbf, 0xf4, 0x99, 0xf7, 0x1f, 0xe4, 0xa3, 0x58, 0xa9, 0x3e, 0x4d,
- 0x12, 0x5f, 0x6b, 0x1f, 0x75, 0x62, 0xf4, 0x99, 0x05, 0x8b, 0xfe, 0xcf,
- 0x73, 0x59, 0xc9, 0xed, 0x62, 0xf6, 0x3f, 0x4b, 0x15, 0xd1, 0xfa, 0xb0,
- 0xf1, 0x1d, 0x5f, 0xfa, 0x4c, 0x0e, 0x3e, 0x61, 0xe7, 0x71, 0x62, 0xa3,
- 0x55, 0x98, 0x38, 0x57, 0xf4, 0xbd, 0x14, 0x24, 0x74, 0x43, 0xf8, 0x4d,
- 0x78, 0xba, 0xee, 0x76, 0xb1, 0x74, 0x37, 0x16, 0x2e, 0xce, 0x2c, 0x5d,
- 0xbb, 0xa5, 0x8a, 0x95, 0xc6, 0xdc, 0x97, 0x1e, 0xcf, 0x0e, 0x32, 0x18,
- 0xde, 0xe8, 0xbd, 0xff, 0xda, 0xe8, 0x4e, 0x3c, 0x21, 0xfd, 0x96, 0x2f,
- 0xd9, 0xfe, 0xe1, 0xc5, 0x8b, 0xf1, 0xc2, 0x75, 0xbc, 0xc5, 0x8a, 0x63,
- 0xda, 0x0c, 0xaa, 0xe3, 0xca, 0xc5, 0xe6, 0xdf, 0x8b, 0x17, 0xfd, 0xd1,
- 0x3f, 0x38, 0x29, 0xe9, 0x62, 0xb0, 0xfc, 0x3c, 0x2e, 0x21, 0xeb, 0x83,
- 0xe9, 0x62, 0xff, 0xce, 0xde, 0x86, 0x1a, 0x58, 0x05, 0x8b, 0xf7, 0x70,
- 0x2c, 0x1a, 0xc5, 0x41, 0x10, 0x3f, 0x1a, 0x23, 0xeb, 0xb0, 0xc5, 0x8a,
- 0x58, 0xaf, 0x9a, 0x4f, 0x0c, 0x5f, 0xcd, 0xcf, 0xb4, 0xb2, 0xc5, 0xff,
- 0xf8, 0xb3, 0x3a, 0xfc, 0xee, 0x16, 0x7b, 0x18, 0x0b, 0x14, 0x74, 0x41,
- 0x39, 0x65, 0xfe, 0xc2, 0xee, 0x78, 0xfb, 0x8b, 0x17, 0xe2, 0x8a, 0x7f,
- 0x2b, 0x14, 0xb1, 0x76, 0x0d, 0x62, 0xe0, 0x3f, 0x66, 0x8f, 0x78, 0x65,
- 0xfd, 0xee, 0x7c, 0x9c, 0x0b, 0x17, 0xdf, 0xed, 0xf7, 0x16, 0x2a, 0x4f,
- 0x57, 0x0b, 0xaf, 0x81, 0xc9, 0x25, 0x8b, 0xfd, 0xaf, 0xbb, 0x71, 0xb7,
- 0xac, 0x5c, 0x6b, 0x2c, 0x54, 0x9f, 0x7e, 0x11, 0x39, 0xad, 0xff, 0xb0,
- 0x89, 0xfd, 0xb6, 0x12, 0x75, 0x8b, 0x74, 0xb1, 0x5f, 0x3d, 0x21, 0x1f,
- 0xdf, 0x9f, 0xc2, 0x70, 0xd6, 0x2a, 0x57, 0x55, 0x47, 0x09, 0xfc, 0x84,
- 0x93, 0x42, 0xbf, 0x71, 0x4c, 0xf0, 0xa3, 0xf9, 0x13, 0x9b, 0x01, 0x2c,
- 0xa1, 0x09, 0xc8, 0x47, 0xf9, 0xf8, 0x44, 0x57, 0xf1, 0x93, 0xad, 0x3c,
- 0x4b, 0x17, 0xfc, 0x39, 0xe8, 0x30, 0x02, 0x7b, 0x58, 0xbd, 0xc7, 0xed,
- 0x62, 0xff, 0x9f, 0x58, 0x76, 0xd9, 0x93, 0xac, 0x57, 0x48, 0x96, 0x63,
- 0xd1, 0x0f, 0x5f, 0x3f, 0x37, 0x03, 0x58, 0xbf, 0x76, 0x31, 0xb7, 0x16,
- 0x2f, 0x6b, 0x38, 0xb1, 0x52, 0x78, 0xf8, 0x55, 0x7d, 0xe9, 0xee, 0x0b,
- 0x17, 0xf3, 0x03, 0x64, 0x98, 0x0b, 0x17, 0x60, 0x16, 0x2a, 0x33, 0xeb,
- 0xd1, 0x21, 0x18, 0x5f, 0xe9, 0xf7, 0x36, 0x73, 0x46, 0xac, 0x5f, 0xf9,
- 0xdb, 0xd9, 0xa0, 0x1d, 0xe0, 0xb1, 0x7f, 0x67, 0xbe, 0xe3, 0x65, 0x8a,
- 0xf9, 0xf5, 0xec, 0x9f, 0x5e, 0x23, 0x7e, 0xb1, 0x78, 0x7f, 0x65, 0x8a,
- 0x63, 0xe0, 0x72, 0x51, 0x0f, 0x5f, 0xe8, 0x89, 0xcc, 0xc2, 0x02, 0xc5,
- 0xe2, 0x98, 0xd6, 0x29, 0xcf, 0x44, 0x8d, 0x2f, 0x7b, 0x03, 0x58, 0xa9,
- 0x57, 0xbb, 0x90, 0xc6, 0x34, 0xc3, 0xed, 0xcf, 0x08, 0xb2, 0x2f, 0xe4,
- 0x60, 0x62, 0x7e, 0xdd, 0x20, 0xb0, 0x96, 0x2f, 0xb7, 0x5e, 0x74, 0xb1,
- 0x7f, 0x14, 0xc2, 0x77, 0xca, 0xc5, 0x80, 0xb1, 0x7e, 0x35, 0xc8, 0x51,
- 0x2c, 0x54, 0x9b, 0xc1, 0x09, 0x5f, 0x09, 0xb7, 0x4e, 0xb1, 0x7f, 0x6f,
- 0xd3, 0xcb, 0x6c, 0xac, 0x5c, 0xd1, 0xac, 0x5b, 0x16, 0x2b, 0x13, 0x42,
- 0xec, 0x49, 0x89, 0x62, 0x6a, 0xd1, 0x01, 0xc9, 0x9c, 0xc8, 0x86, 0x2f,
- 0xd9, 0xfd, 0xed, 0xa5, 0x8b, 0xfc, 0x50, 0xfb, 0x6f, 0xc1, 0xac, 0x5a,
- 0x56, 0x29, 0xcf, 0x18, 0x8d, 0x6f, 0x66, 0xa5, 0x62, 0xfa, 0x23, 0x24,
- 0xd5, 0x8b, 0xe3, 0x43, 0x8b, 0x8b, 0x17, 0xbd, 0xbb, 0x2b, 0x15, 0xa3,
- 0xc7, 0x22, 0x7b, 0xe8, 0xfd, 0x9d, 0x2c, 0x5f, 0xe7, 0x34, 0x3f, 0xfe,
- 0x60, 0xb1, 0x52, 0x98, 0x2e, 0x0e, 0x33, 0x6b, 0x90, 0xec, 0x92, 0xdf,
- 0xfb, 0xf8, 0x31, 0xb7, 0x79, 0xdf, 0x96, 0x2f, 0xed, 0xa3, 0x0d, 0xf5,
- 0xa5, 0x8a, 0x8c, 0xfc, 0xc6, 0x83, 0x7f, 0x87, 0x9e, 0xfc, 0x97, 0x4b,
- 0x17, 0xa5, 0xb6, 0x56, 0x2f, 0xbd, 0xc0, 0xce, 0xb1, 0x4e, 0x78, 0x82,
- 0x1f, 0xbb, 0x72, 0x0b, 0x17, 0xff, 0xfc, 0x09, 0x2e, 0x9f, 0xe4, 0xe0,
- 0xd4, 0xf5, 0x9a, 0xd3, 0x2c, 0x5f, 0xf0, 0xf6, 0xe7, 0x27, 0x34, 0x05,
- 0x8b, 0xdf, 0x0f, 0x8b, 0x15, 0x87, 0xb4, 0xe7, 0x77, 0xb9, 0xf6, 0x58,
- 0xbf, 0xcc, 0x3f, 0x13, 0xf7, 0xc5, 0x8a, 0x58, 0xbf, 0xb8, 0xdd, 0xe7,
- 0x7e, 0x58, 0xae, 0xcd, 0xe7, 0x83, 0x2e, 0x8e, 0x56, 0x2a, 0x51, 0x54,
- 0xee, 0x02, 0x22, 0xb9, 0xa0, 0xb1, 0x7d, 0x9c, 0x60, 0x2c, 0x54, 0xaa,
- 0xe5, 0x8c, 0x8c, 0x6f, 0x18, 0x43, 0xd8, 0xdf, 0xe1, 0x80, 0x02, 0x02,
- 0x86, 0x3f, 0x0b, 0xb6, 0x45, 0xef, 0xfa, 0x0d, 0xe0, 0x4f, 0xc3, 0xe2,
- 0xc5, 0xc2, 0x02, 0xc5, 0x44, 0x7a, 0x7b, 0xa7, 0x75, 0xb1, 0x3b, 0xfd,
- 0x60, 0xaa, 0xbe, 0xc1, 0x08, 0x4d, 0x8c, 0x9b, 0x61, 0xc3, 0x00, 0x2d,
- 0xa1, 0x4c, 0xa8, 0xe8, 0xe1, 0xab, 0x08, 0xd4, 0xc7, 0x28, 0xa7, 0x27,
- 0x2b, 0x4d, 0x8c, 0x4f, 0xa9, 0x4d, 0x1d, 0xc6, 0xf4, 0xd2, 0xa5, 0x22,
- 0x94, 0x19, 0xa9, 0x57, 0x47, 0x8f, 0x37, 0xf3, 0xaf, 0x6f, 0x39, 0x98,
- 0x09, 0x43, 0x01, 0x75, 0x12, 0x9c, 0x8c, 0xe4, 0xed, 0xb7, 0xa7, 0x2b,
- 0x85, 0x1e, 0x96, 0xf7, 0x03, 0x1c, 0x36, 0x63, 0x25, 0x0e, 0x5d, 0x16,
- 0xec, 0x3b, 0x2e, 0xea, 0x56, 0x2f, 0x9f, 0xa9, 0xd2, 0xc5, 0x18, 0x6e,
- 0xf7, 0x46, 0x2e, 0x33, 0x16, 0x2f, 0xf3, 0x76, 0x07, 0xfe, 0x6c, 0xac,
- 0x5f, 0xf9, 0xa7, 0xdf, 0x73, 0x70, 0x80, 0xb1, 0x7f, 0xf9, 0xf5, 0xb5,
- 0xfd, 0xb7, 0xdd, 0xf4, 0xc4, 0xb1, 0x4c, 0x8d, 0xdd, 0x0c, 0x7c, 0xdf,
- 0x79, 0xf5, 0xfb, 0x91, 0x66, 0x9d, 0x62, 0xfa, 0x7a, 0x77, 0x58, 0xbd,
- 0xac, 0x82, 0xc5, 0xcc, 0x75, 0x8a, 0x63, 0xff, 0x39, 0x4f, 0x88, 0xb7,
- 0x47, 0x6f, 0xec, 0xf4, 0xb1, 0xf8, 0xb1, 0x7a, 0x40, 0xcb, 0x17, 0xf4,
- 0xc3, 0x35, 0x9c, 0x58, 0xbf, 0x7f, 0x3d, 0x3f, 0x58, 0xa1, 0x9e, 0xab,
- 0x96, 0xdf, 0xfe, 0xd6, 0x85, 0x0d, 0x64, 0xf7, 0x06, 0x3a, 0xc5, 0xd1,
- 0x32, 0xc5, 0x61, 0xf2, 0x3a, 0x65, 0xee, 0x07, 0xc5, 0x8b, 0xff, 0xa1,
- 0xe1, 0x46, 0x13, 0xee, 0x76, 0xe2, 0xc5, 0xee, 0x9f, 0x7a, 0xc5, 0xff,
- 0xbe, 0x2e, 0xf9, 0x27, 0x7e, 0xfc, 0xb1, 0x6c, 0xed, 0x15, 0x7a, 0x49,
- 0xf1, 0x05, 0xff, 0xbd, 0x27, 0xe4, 0xb4, 0x6f, 0xe5, 0x8b, 0xf9, 0xf7,
- 0x1f, 0x3b, 0xf2, 0xc5, 0x76, 0x7e, 0x1f, 0x3f, 0xbf, 0xcf, 0x83, 0x6e,
- 0xc9, 0xd6, 0x2b, 0x0f, 0x54, 0x44, 0x77, 0x0c, 0xd5, 0x8b, 0xe9, 0xf4,
- 0x1d, 0x62, 0xfb, 0x5b, 0xb2, 0x4b, 0x16, 0x25, 0x8a, 0x93, 0x6c, 0x61,
- 0x2d, 0xef, 0x14, 0xac, 0x5d, 0xf0, 0x92, 0xbb, 0xa9, 0x91, 0x81, 0x34,
- 0x2f, 0x62, 0x3e, 0xd1, 0x69, 0xdc, 0x7f, 0x08, 0x57, 0x20, 0x28, 0x65,
- 0x72, 0x1f, 0x7e, 0x21, 0xde, 0x32, 0x62, 0xc0, 0x64, 0x34, 0x11, 0x92,
- 0xd1, 0x34, 0x87, 0xeb, 0xfb, 0x35, 0xd3, 0xbf, 0x4a, 0x8b, 0x34, 0xbf,
- 0xff, 0x3e, 0x9e, 0x01, 0x3a, 0x2c, 0x8f, 0x5d, 0xc8, 0xd6, 0x2f, 0x75,
- 0x87, 0x58, 0xbf, 0x36, 0x8c, 0xcf, 0xac, 0x5f, 0x7d, 0x9c, 0x96, 0x2b,
- 0xe7, 0x95, 0xe2, 0x9b, 0xfc, 0x09, 0xe3, 0x3f, 0x66, 0x2c, 0x5f, 0x85,
- 0x17, 0xd8, 0x6b, 0x17, 0xff, 0x6b, 0x1e, 0x2e, 0xfd, 0xb4, 0xc6, 0x95,
- 0x8b, 0xfe, 0x1e, 0x61, 0xa3, 0x26, 0x8d, 0x62, 0xff, 0xf4, 0x73, 0xd7,
- 0x32, 0x62, 0xc8, 0xf0, 0x96, 0x2b, 0x11, 0x0c, 0xe7, 0x57, 0x9f, 0x3c,
- 0xb1, 0x7f, 0xef, 0x34, 0x1b, 0xe2, 0x39, 0xd9, 0x62, 0xfb, 0x5f, 0x70,
- 0x92, 0xa8, 0xd3, 0x1a, 0x18, 0x88, 0xe6, 0xbf, 0x2a, 0x28, 0x67, 0xf0,
- 0x84, 0x31, 0xcb, 0xfe, 0xc8, 0xa0, 0xfa, 0x8f, 0xe2, 0x58, 0xbf, 0xde,
- 0xfe, 0x34, 0x67, 0x95, 0x8b, 0xfb, 0xc5, 0x39, 0xf7, 0x58, 0xbf, 0xf4,
- 0xe8, 0x1e, 0xe7, 0xf1, 0x86, 0xb1, 0x70, 0x51, 0xd6, 0x2d, 0x1a, 0xc5,
- 0xe8, 0x4f, 0x6b, 0x16, 0xc9, 0x36, 0x31, 0x09, 0xdf, 0x31, 0x3c, 0x6b,
- 0x17, 0xff, 0x6c, 0xb9, 0x03, 0x3d, 0x24, 0xc0, 0x58, 0xa1, 0xa7, 0x69,
- 0x87, 0x9d, 0x9a, 0x7c, 0xb1, 0xcf, 0xc9, 0x33, 0x84, 0xc1, 0x91, 0x5b,
- 0xeb, 0x17, 0xef, 0xcf, 0x3e, 0xcb, 0x17, 0xfe, 0x6f, 0x49, 0xc9, 0xcd,
- 0xfb, 0x2c, 0x5d, 0x3f, 0x58, 0xbf, 0x8b, 0x37, 0xfd, 0xe0, 0xb1, 0x79,
- 0xf5, 0xc5, 0x8b, 0x04, 0x8d, 0x1b, 0x78, 0x25, 0x11, 0x47, 0xcf, 0xbc,
- 0x2e, 0x61, 0x7d, 0x04, 0x4e, 0xb7, 0x76, 0x34, 0xcb, 0xff, 0xe1, 0x3c,
- 0x7a, 0xc3, 0x84, 0xfc, 0xc6, 0x42, 0x58, 0xa0, 0x8b, 0xe7, 0x9d, 0x1e,
- 0x34, 0xa8, 0xe7, 0x97, 0xde, 0x45, 0xf7, 0x8e, 0x1e, 0x96, 0x2f, 0xe1,
- 0x1b, 0x26, 0x08, 0xd5, 0x8a, 0x63, 0xd1, 0x30, 0x7e, 0xf7, 0xd8, 0xc5,
- 0x8b, 0x8e, 0xcb, 0x17, 0xdc, 0x29, 0x31, 0x62, 0xf7, 0x59, 0xf5, 0x8b,
- 0xb9, 0x2b, 0x17, 0xe1, 0x73, 0xd3, 0xc5, 0x8a, 0x81, 0xe0, 0x44, 0x2f,
- 0x52, 0x88, 0x16, 0x5e, 0xbf, 0x8a, 0x4f, 0xc6, 0x8d, 0x62, 0xf1, 0x68,
- 0x4b, 0x15, 0x03, 0xcb, 0x62, 0xeb, 0x8c, 0xd2, 0xc5, 0xf8, 0x4d, 0xb0,
- 0x82, 0xbb, 0x12, 0xc5, 0xe1, 0x77, 0xc5, 0x8b, 0xf0, 0x7e, 0x29, 0x02,
- 0xc5, 0x68, 0xf2, 0x37, 0x8f, 0xdf, 0xa3, 0x14, 0x05, 0x2b, 0x15, 0x27,
- 0x9c, 0xc4, 0x97, 0xcc, 0x76, 0xdd, 0x58, 0xb8, 0x41, 0xac, 0x5e, 0x2c,
- 0xe2, 0xc5, 0x49, 0xed, 0x44, 0x4a, 0x18, 0xcd, 0xf7, 0xdb, 0xbe, 0x2c,
- 0x5d, 0x3d, 0xac, 0x5c, 0xdb, 0x2b, 0x15, 0xb8, 0x7a, 0xd1, 0x12, 0x06,
- 0x31, 0x71, 0x92, 0xb1, 0x76, 0x8d, 0x58, 0xb8, 0xe1, 0x25, 0x5e, 0xa0,
- 0xc8, 0xb0, 0x7b, 0xb1, 0x76, 0x85, 0x24, 0x4d, 0x9a, 0x21, 0x38, 0xcf,
- 0xe1, 0x9c, 0xef, 0x42, 0x84, 0x31, 0x86, 0x81, 0x8c, 0x5d, 0x8c, 0xb1,
- 0x76, 0x0d, 0x62, 0xc4, 0xb1, 0x7f, 0xd0, 0x09, 0x9a, 0xe9, 0xdf, 0xa5,
- 0x45, 0x00, 0x56, 0x1e, 0xdb, 0x88, 0xdf, 0xe6, 0x3c, 0xee, 0x7f, 0x23,
- 0x58, 0xbc, 0xfa, 0x35, 0x62, 0xff, 0xed, 0x97, 0x20, 0x67, 0xa4, 0x98,
- 0x0b, 0x16, 0x09, 0x04, 0xd0, 0xb0, 0x58, 0xee, 0x5f, 0x20, 0x30, 0xdc,
- 0x31, 0xeb, 0xf8, 0xbd, 0xc9, 0x1c, 0xac, 0x5d, 0x03, 0xac, 0x5f, 0xcd,
- 0xc8, 0x8a, 0x46, 0xb1, 0x7b, 0x5d, 0xc1, 0x62, 0x86, 0x79, 0xae, 0x5d,
- 0x7e, 0x9e, 0xfc, 0xfa, 0x58, 0xbf, 0x49, 0x67, 0x7e, 0x58, 0xbe, 0xe4,
- 0x18, 0x0b, 0x14, 0x73, 0xcb, 0xf1, 0x45, 0xb7, 0xac, 0x5b, 0xcb, 0x15,
- 0x03, 0x4d, 0xd0, 0xa5, 0xfc, 0xdf, 0x92, 0x9f, 0x2c, 0x5e, 0x1b, 0xb2,
- 0xc5, 0x4a, 0x7b, 0x30, 0x2d, 0xc6, 0x56, 0x21, 0x77, 0x42, 0x48, 0xe1,
- 0x10, 0x8b, 0x2f, 0x45, 0x30, 0x58, 0xbb, 0x5e, 0x58, 0xb0, 0x4c, 0x36,
- 0xdc, 0x1e, 0xbf, 0xe9, 0xf7, 0xf0, 0xf9, 0xac, 0x58, 0xbe, 0x8b, 0x33,
- 0xa5, 0x8b, 0xf7, 0x8d, 0x7e, 0x04, 0xd1, 0xee, 0x06, 0x71, 0x50, 0x46,
- 0x39, 0x90, 0x84, 0xbf, 0xfb, 0xdc, 0x09, 0xb0, 0xc2, 0xc0, 0xa8, 0x58,
- 0x0e, 0x62, 0xc5, 0x04, 0x4f, 0xc2, 0x63, 0x6a, 0x72, 0x9b, 0xb9, 0xe5,
- 0x8b, 0x4a, 0xc5, 0xbe, 0xb1, 0x47, 0x34, 0x62, 0x11, 0xbe, 0x0a, 0xef,
- 0xef, 0x8b, 0x17, 0x87, 0x87, 0x58, 0xbf, 0xfb, 0xcc, 0x2e, 0x06, 0x7d,
- 0x69, 0x8d, 0x58, 0xbf, 0xff, 0x6f, 0x9f, 0xb0, 0xff, 0x30, 0xe3, 0xfd,
- 0xb8, 0xb1, 0x7f, 0xd3, 0xf9, 0x8f, 0x53, 0x83, 0x58, 0xbf, 0xb9, 0x27,
- 0x29, 0x89, 0x62, 0xdf, 0x58, 0xbc, 0x19, 0x44, 0xb1, 0x6f, 0x61, 0xb1,
- 0x00, 0x95, 0xd9, 0x1a, 0xc5, 0x61, 0xbe, 0x22, 0x6b, 0xe6, 0x3c, 0xc4,
- 0xb1, 0x51, 0xa7, 0xa9, 0x01, 0xd6, 0x48, 0xfa, 0xb8, 0x0e, 0x4a, 0x13,
- 0xbb, 0x23, 0xf7, 0xff, 0x85, 0xa8, 0x67, 0x18, 0x41, 0x72, 0x93, 0xac,
- 0x5b, 0x8b, 0x17, 0xee, 0x4f, 0xdb, 0x7a, 0xc5, 0xfd, 0xf7, 0x7f, 0xcc,
- 0x16, 0x2f, 0x86, 0xc4, 0x05, 0x8a, 0xda, 0x88, 0xbc, 0x12, 0x62, 0xa7,
- 0x2d, 0xbf, 0xfe, 0xd4, 0x63, 0xfb, 0x6b, 0x93, 0xa8, 0x9b, 0xeb, 0x17,
- 0xfe, 0x07, 0x09, 0xcd, 0xcd, 0xed, 0xa5, 0x8b, 0xff, 0x9b, 0xe2, 0xfb,
- 0xb7, 0x7c, 0x93, 0x56, 0x2b, 0x11, 0x0f, 0xe4, 0x1b, 0xc2, 0x1e, 0x2c,
- 0x5f, 0xda, 0xf1, 0x49, 0xf8, 0xb1, 0x7f, 0xfe, 0xd0, 0xdc, 0x8d, 0xfe,
- 0x6e, 0x69, 0x8f, 0x26, 0xac, 0x56, 0x22, 0x20, 0x45, 0xd6, 0xd9, 0x58,
- 0xa9, 0x4f, 0x63, 0x21, 0xb4, 0xc4, 0x5f, 0x85, 0x28, 0x08, 0xaf, 0x3e,
- 0xb1, 0x62, 0xf7, 0x24, 0x0b, 0x17, 0xd0, 0x62, 0xc5, 0x8a, 0xf1, 0xbe,
- 0x30, 0x76, 0xfb, 0xa7, 0x7e, 0x95, 0x16, 0xf9, 0x7b, 0x65, 0xfc, 0xb1,
- 0x7f, 0x98, 0xa4, 0xe0, 0x7f, 0x2c, 0x5e, 0x8b, 0x00, 0xb1, 0x7e, 0x0e,
- 0x3f, 0xce, 0x96, 0x2b, 0xa4, 0xd2, 0x19, 0x6b, 0x44, 0x47, 0x31, 0xf9,
- 0x03, 0x99, 0x78, 0x7a, 0xff, 0x9b, 0xf3, 0xdc, 0xee, 0x67, 0x6b, 0x17,
- 0xf8, 0x38, 0xdc, 0x7f, 0x9e, 0x2c, 0x5f, 0xff, 0xf3, 0xc4, 0x36, 0xd7,
- 0xf0, 0x65, 0x3d, 0x3c, 0x65, 0x27, 0x58, 0xbf, 0xed, 0x0b, 0x9f, 0x78,
- 0x01, 0x96, 0x2c, 0xc0, 0x45, 0x0f, 0x99, 0xef, 0xbd, 0xc7, 0xf2, 0xc5,
- 0xff, 0xb5, 0x9b, 0x91, 0x7d, 0xce, 0xdc, 0x58, 0xbb, 0x23, 0xc3, 0xe6,
- 0xd1, 0x1d, 0x74, 0x9c, 0x97, 0xe1, 0xae, 0x50, 0x8e, 0xb1, 0x8b, 0x17,
- 0xfc, 0xe5, 0xd7, 0x27, 0xef, 0xb8, 0xb1, 0x46, 0x9e, 0x7f, 0x84, 0xef,
- 0xb0, 0x9a, 0x25, 0x8b, 0xe6, 0xcd, 0x6f, 0x58, 0xbe, 0xee, 0x11, 0xca,
- 0xc5, 0xe9, 0x33, 0x65, 0x62, 0xb0, 0xf1, 0xb4, 0x4b, 0x7d, 0xd7, 0xb3,
- 0xa5, 0x8b, 0x12, 0xc5, 0x61, 0xb6, 0xf1, 0x2d, 0xef, 0xce, 0x96, 0x2f,
- 0xdf, 0x6d, 0x7d, 0xd6, 0x2f, 0xff, 0x7e, 0x63, 0xf6, 0x7c, 0xb3, 0xdf,
- 0x65, 0x8b, 0xc7, 0xc1, 0xac, 0x58, 0xeb, 0x17, 0xfa, 0x63, 0x1e, 0x19,
- 0xc0, 0x92, 0x8b, 0xec, 0x1d, 0x88, 0xa1, 0xd2, 0x83, 0x1d, 0xa8, 0x27,
- 0x55, 0x8a, 0xff, 0x86, 0xf5, 0xf0, 0xcf, 0x9d, 0xac, 0x5f, 0x43, 0x81,
- 0xf1, 0x62, 0xa4, 0xf2, 0x7c, 0x49, 0x7d, 0x9e, 0xe6, 0x2c, 0x5f, 0xcf,
- 0xd8, 0xd8, 0xa3, 0x58, 0xbf, 0xd9, 0xb9, 0xa6, 0x3c, 0x9a, 0xb1, 0x52,
- 0x88, 0x8d, 0x11, 0x7c, 0xbe, 0xf7, 0x3e, 0x35, 0x8b, 0xf0, 0x7e, 0x29,
- 0x02, 0xc5, 0x1c, 0xf1, 0xf7, 0x8f, 0x5c, 0x52, 0xb1, 0x7f, 0xf7, 0xb8,
- 0xdc, 0x92, 0xcf, 0x7d, 0x96, 0x2f, 0xfc, 0xfb, 0xba, 0x63, 0x73, 0xed,
- 0x05, 0x8b, 0xff, 0x00, 0x45, 0xd3, 0x8f, 0xf3, 0xc5, 0x8b, 0xfe, 0x03,
- 0x78, 0x9f, 0xd2, 0x35, 0x8b, 0xc5, 0x9f, 0x58, 0xad, 0x26, 0x5e, 0x71,
- 0x6f, 0xa1, 0x81, 0x0b, 0x88, 0x1b, 0xce, 0x2f, 0xf9, 0xb9, 0x83, 0x98,
- 0x98, 0xeb, 0x17, 0xe1, 0xce, 0xe0, 0x8e, 0xb1, 0x7f, 0xec, 0x8e, 0x31,
- 0x0e, 0x75, 0x23, 0x58, 0xbf, 0x79, 0xb5, 0x3b, 0xd6, 0x2f, 0xf9, 0xf9,
- 0x38, 0x43, 0xfc, 0xac, 0x5f, 0xef, 0xc8, 0xdb, 0x7c, 0x8d, 0x62, 0xff,
- 0xb5, 0x9d, 0xfc, 0x9f, 0x72, 0x35, 0x8b, 0x60, 0xcf, 0xcc, 0xe6, 0xb6,
- 0xe6, 0x91, 0xa2, 0x50, 0xaa, 0xa2, 0x4c, 0xa3, 0x90, 0xfb, 0xa9, 0x57,
- 0x47, 0x91, 0xa9, 0xf4, 0xb4, 0xc7, 0x3a, 0x2c, 0x78, 0xda, 0x6f, 0xc1,
- 0xe7, 0xdc, 0xeb, 0x17, 0x08, 0xd5, 0x8b, 0xe3, 0xc5, 0x21, 0xac, 0x5d,
- 0x3f, 0x58, 0xbf, 0xf6, 0xeb, 0x9c, 0x3d, 0x00, 0xed, 0xc5, 0x8a, 0xe9,
- 0x18, 0x47, 0x29, 0x71, 0x92, 0x25, 0xdd, 0x17, 0xbf, 0x84, 0x06, 0x21,
- 0x69, 0x62, 0xf3, 0x17, 0x96, 0x2e, 0x17, 0x6b, 0x17, 0xfc, 0xf0, 0xf7,
- 0x30, 0xcf, 0xb2, 0xc5, 0xee, 0xdf, 0xeb, 0x14, 0x74, 0x5d, 0xb9, 0x70,
- 0x07, 0x08, 0x64, 0x47, 0x57, 0xfd, 0xa9, 0xe6, 0x77, 0xe6, 0xd2, 0xc5,
- 0xfe, 0xf8, 0x88, 0x7f, 0x63, 0x16, 0x2f, 0xfe, 0x88, 0x43, 0x72, 0x06,
- 0xd6, 0x3f, 0x96, 0x2b, 0xe7, 0xfb, 0xe3, 0x5b, 0xda, 0x9f, 0x2c, 0x5f,
- 0xfa, 0x7c, 0x27, 0x8e, 0x7f, 0x27, 0x58, 0xbf, 0xa2, 0x71, 0xfd, 0x8e,
- 0xb1, 0x7f, 0x79, 0xb0, 0x72, 0x75, 0x8a, 0xed, 0x13, 0x7e, 0x3f, 0x30,
- 0xbe, 0xf9, 0xe3, 0x11, 0x2c, 0x5d, 0xc2, 0x58, 0xbf, 0xbb, 0xe4, 0xf5,
- 0x87, 0x58, 0xbe, 0x3f, 0x58, 0x4b, 0x15, 0x2a, 0x94, 0x32, 0x16, 0xfa,
- 0x22, 0x78, 0x5c, 0x11, 0x97, 0x08, 0xc4, 0x2e, 0x19, 0x85, 0x2c, 0x5f,
- 0xff, 0xe2, 0x98, 0x61, 0xe7, 0xaf, 0x73, 0x01, 0x39, 0xdc, 0x16, 0x2f,
- 0xd1, 0x49, 0x14, 0xac, 0x5f, 0xff, 0xce, 0xde, 0x98, 0x36, 0x80, 0x09,
- 0xd9, 0xcd, 0x1a, 0xb1, 0x77, 0x5a, 0x58, 0xbf, 0xe0, 0x0c, 0xa6, 0x1f,
- 0xe0, 0x16, 0x2c, 0x4b, 0x15, 0xa3, 0xcb, 0x73, 0xaa, 0x94, 0xdd, 0xc6,
- 0x18, 0xcc, 0x3f, 0x27, 0xf2, 0xf0, 0x99, 0x2f, 0xcf, 0x1c, 0xfd, 0xd6,
- 0x2f, 0xed, 0x3c, 0x7e, 0x7f, 0xac, 0x5e, 0x29, 0x35, 0x62, 0xfb, 0x37,
- 0x1f, 0xeb, 0x17, 0x3f, 0xba, 0x3c, 0x2e, 0x0e, 0xd4, 0xa2, 0x7c, 0x9c,
- 0x6f, 0xf8, 0xb3, 0xde, 0xc8, 0x9e, 0x25, 0x8b, 0xd1, 0x0b, 0xeb, 0x17,
- 0x0c, 0xeb, 0x17, 0xec, 0x8a, 0x13, 0xda, 0xc5, 0x61, 0xf0, 0x9a, 0x3e,
- 0x43, 0x17, 0x49, 0x2c, 0x57, 0x49, 0x80, 0x31, 0x0f, 0xe1, 0x36, 0x61,
- 0x75, 0xef, 0x98, 0xeb, 0x17, 0xff, 0x0b, 0x9f, 0x78, 0x8b, 0x00, 0x2e,
- 0x2c, 0x5f, 0xb0, 0xbd, 0x3c, 0x58, 0xbc, 0xe4, 0x6a, 0xc5, 0xa0, 0xb1,
- 0x7d, 0x9b, 0xdb, 0x4b, 0x17, 0xf0, 0x05, 0xcd, 0xcc, 0xed, 0x62, 0xa2,
- 0x3d, 0x70, 0x12, 0x56, 0x22, 0x31, 0xda, 0x6f, 0xfc, 0xfd, 0xf7, 0xc6,
- 0x1e, 0x19, 0xc5, 0x8a, 0x95, 0x74, 0x59, 0x1e, 0x3b, 0x22, 0x68, 0x7b,
- 0xe8, 0xce, 0x4e, 0x50, 0xa9, 0xe1, 0x0d, 0xff, 0xf3, 0xf7, 0xac, 0xce,
- 0xcc, 0xf8, 0xa7, 0xbe, 0x2c, 0x5f, 0x9e, 0x3e, 0x9c, 0x6b, 0x17, 0xff,
- 0x4f, 0x98, 0x1c, 0x7e, 0xc0, 0xdb, 0xd6, 0x2f, 0x9f, 0xa7, 0x8d, 0x62,
- 0xef, 0x36, 0x8f, 0xaf, 0x88, 0xf7, 0xe7, 0x21, 0xfe, 0x56, 0x2f, 0x80,
- 0xc4, 0x6a, 0xc5, 0x39, 0xe5, 0x00, 0x9e, 0x82, 0xad, 0xf2, 0x56, 0xc0,
- 0x77, 0xb0, 0xc8, 0x66, 0x3f, 0xf8, 0xdb, 0x21, 0x0d, 0x91, 0xca, 0x14,
- 0xc8, 0xe6, 0x8d, 0x64, 0xea, 0x3c, 0xfe, 0xe1, 0x14, 0xc4, 0x7b, 0x84,
- 0x51, 0x4a, 0x14, 0xd3, 0xf1, 0xe1, 0x53, 0xf9, 0xc1, 0x97, 0x8c, 0x90,
- 0x11, 0x83, 0x94, 0xa9, 0x8e, 0x47, 0xe3, 0xe9, 0x7f, 0x02, 0x79, 0xd9,
- 0x54, 0x0e, 0x12, 0xbb, 0xae, 0xf7, 0x4c, 0x6b, 0x17, 0x3f, 0x96, 0x2f,
- 0x3f, 0x61, 0x06, 0x6b, 0xce, 0x31, 0x7f, 0x9f, 0xb0, 0x81, 0xe1, 0x74,
- 0xb1, 0x41, 0x15, 0x38, 0x94, 0xa0, 0x41, 0x1a, 0xdf, 0xf6, 0x45, 0x07,
- 0xd4, 0x7f, 0x12, 0xc5, 0xf3, 0x6c, 0x90, 0x16, 0x2f, 0x7b, 0x9d, 0xac,
- 0x5f, 0xfb, 0xcd, 0x06, 0xf8, 0x8e, 0x76, 0x58, 0xb8, 0x61, 0x06, 0x8b,
- 0xf7, 0x3c, 0xe1, 0x28, 0x63, 0xf7, 0x3f, 0x4b, 0x17, 0xfd, 0xe8, 0xa0,
- 0xfa, 0x8f, 0xe2, 0x58, 0xae, 0x8f, 0x57, 0xb1, 0x8b, 0xff, 0x83, 0xeb,
- 0x6c, 0xeb, 0x4c, 0x4f, 0xd2, 0xc5, 0xe6, 0xf8, 0x96, 0x2f, 0xf6, 0xcb,
- 0x90, 0x3d, 0x31, 0x2c, 0x56, 0x23, 0x04, 0xe4, 0x81, 0x74, 0x90, 0xc7,
- 0x6e, 0x0a, 0x6c, 0x0b, 0x17, 0x8e, 0xfd, 0xac, 0x5e, 0x03, 0xfd, 0x62,
- 0xff, 0xbc, 0xc7, 0xe7, 0xf0, 0xc7, 0x58, 0xbb, 0x7b, 0x2c, 0x5f, 0x6b,
- 0x58, 0x1a, 0xc5, 0xff, 0x4c, 0x0c, 0x7d, 0x6b, 0x03, 0x58, 0xbd, 0x86,
- 0x04, 0xd8, 0x93, 0x0e, 0x92, 0x1c, 0x1e, 0xec, 0x76, 0x23, 0xa7, 0x19,
- 0x22, 0x4b, 0x70, 0x22, 0x79, 0x71, 0xc6, 0x9f, 0x78, 0xf8, 0x75, 0x8b,
- 0xfe, 0xfb, 0x38, 0x30, 0x5a, 0x8d, 0x62, 0xff, 0x79, 0xbd, 0xcf, 0xb0,
- 0x4c, 0x3d, 0x7f, 0x0e, 0xd4, 0xae, 0x00, 0xb4, 0xb2, 0xc1, 0x42, 0x2a,
- 0xfd, 0x18, 0x40, 0x0b, 0xb5, 0x8b, 0xff, 0xfc, 0xde, 0x13, 0xc6, 0x13,
- 0x21, 0xf9, 0xd6, 0x61, 0x1a, 0xb1, 0x5a, 0x44, 0x88, 0x5c, 0xba, 0xff,
- 0xff, 0xee, 0x9f, 0x4f, 0xf8, 0x67, 0xb0, 0x7c, 0x73, 0xe6, 0xa3, 0x9e,
- 0xd6, 0x2f, 0xec, 0x1b, 0x9f, 0x09, 0x62, 0xff, 0xfb, 0x04, 0x17, 0xc2,
- 0x76, 0xfb, 0xfb, 0xf2, 0xb1, 0x4c, 0x8f, 0x1d, 0x3a, 0x7c, 0xb2, 0xfd,
- 0xae, 0x9d, 0xfa, 0x54, 0x52, 0x85, 0xff, 0xf3, 0xf8, 0xb2, 0x3d, 0x4f,
- 0xdb, 0xf9, 0xa5, 0x8b, 0xff, 0xe7, 0x1e, 0x0f, 0xf8, 0x40, 0x3e, 0x6b,
- 0x16, 0x2e, 0xe1, 0x8b, 0x17, 0xfe, 0xfc, 0x80, 0xef, 0x0e, 0x70, 0xc5,
- 0x8b, 0xcf, 0x00, 0x92, 0x9a, 0xee, 0x17, 0x80, 0xdc, 0x93, 0xf8, 0x9c,
- 0x18, 0xcd, 0xff, 0x9b, 0xa7, 0xd3, 0xc1, 0xb8, 0x05, 0x8b, 0xf6, 0xba,
- 0x77, 0xe9, 0x51, 0x27, 0x17, 0x40, 0x24, 0x9f, 0xb6, 0x1f, 0xd1, 0xd3,
- 0x0d, 0x78, 0x6f, 0xdf, 0xf6, 0x82, 0x7b, 0xf9, 0xa6, 0xe2, 0xc5, 0xf7,
- 0xe6, 0x27, 0x58, 0xbe, 0xe8, 0x84, 0x6a, 0xc5, 0xda, 0x09, 0x87, 0x90,
- 0xe4, 0x74, 0x11, 0x1b, 0x4c, 0x50, 0xf0, 0x84, 0xa9, 0x94, 0x10, 0x67,
- 0x1d, 0x6b, 0xa3, 0x09, 0xf4, 0x91, 0xe6, 0xae, 0x83, 0x92, 0x83, 0xcd,
- 0x8d, 0xaf, 0xa8, 0xf3, 0xda, 0x5e, 0xfe, 0xe4, 0x68, 0xb1, 0x47, 0x11,
- 0xa8, 0x73, 0x1e, 0xf2, 0x62, 0x3f, 0x3e, 0xda, 0xf3, 0x90, 0x00, 0x94,
- 0x26, 0x53, 0x85, 0x5c, 0xb4, 0x1e, 0x5e, 0x9c, 0xfa, 0x14, 0x33, 0xb7,
- 0xce, 0x2e, 0x5f, 0xb5, 0xd3, 0xbf, 0x4a, 0x88, 0x7c, 0xbf, 0xf3, 0xc0,
- 0x26, 0x6b, 0xa7, 0x7e, 0x95, 0x12, 0x99, 0x60, 0x98, 0x88, 0x63, 0x9b,
- 0xdf, 0xe0, 0x99, 0xae, 0x9d, 0xfa, 0x54, 0x44, 0xe5, 0xf9, 0xbd, 0xc1,
- 0x1d, 0x62, 0xfc, 0x23, 0x93, 0x9a, 0xb1, 0x7b, 0xf3, 0x12, 0xc5, 0xdd,
- 0xc1, 0x62, 0xa2, 0x44, 0x4e, 0x8a, 0x7e, 0x52, 0x21, 0xeb, 0xfc, 0x2e,
- 0xc3, 0x18, 0xbd, 0xc5, 0x8b, 0xff, 0xc1, 0x61, 0xa6, 0x6e, 0x46, 0x3d,
- 0x8f, 0x6e, 0xdf, 0xec, 0xac, 0x5f, 0xb5, 0xd3, 0xbf, 0x4a, 0x88, 0xc4,
- 0xbf, 0x71, 0xb7, 0xc9, 0xd6, 0x2f, 0x77, 0x08, 0xd6, 0x2d, 0xf9, 0x3c,
- 0xac, 0x2a, 0xbf, 0x6f, 0x7e, 0x4c, 0x16, 0x2f, 0xe8, 0x48, 0x3e, 0xc6,
- 0x2c, 0x5f, 0xff, 0xc2, 0x27, 0x37, 0x6f, 0x8d, 0x92, 0x86, 0x7d, 0x8e,
- 0xb1, 0x7e, 0x8a, 0x7b, 0x83, 0xac, 0x5f, 0x49, 0xfa, 0x02, 0xc5, 0xe0,
- 0xe6, 0x25, 0x8b, 0xff, 0xe8, 0x46, 0x16, 0x4e, 0xc1, 0x1f, 0x5a, 0xdb,
- 0xb7, 0xfb, 0x2b, 0x15, 0x88, 0xd4, 0xf9, 0x53, 0x92, 0x00, 0x7e, 0xfd,
- 0xa6, 0xe9, 0xb7, 0xac, 0x5f, 0x85, 0xe9, 0xee, 0x0b, 0x17, 0xb3, 0xbf,
- 0x2c, 0x5f, 0xec, 0x2f, 0xe7, 0xa4, 0x6b, 0x17, 0x67, 0xa4, 0xf4, 0x18,
- 0x7a, 0xff, 0xde, 0x36, 0x4a, 0x19, 0xf6, 0x3a, 0xc5, 0xff, 0x1b, 0x25,
- 0x0c, 0xfb, 0x1d, 0x62, 0xf8, 0x44, 0xe6, 0xed, 0x3f, 0x8f, 0x1f, 0xdf,
- 0xb4, 0x06, 0xfc, 0xac, 0x51, 0xcf, 0x8c, 0x47, 0x77, 0xbb, 0x86, 0xc0,
- 0xb1, 0x7f, 0x7f, 0xdc, 0xce, 0xe0, 0xb1, 0x4c, 0x7a, 0x82, 0x24, 0xbf,
- 0x6d, 0x88, 0xa4, 0x6b, 0x17, 0x83, 0x86, 0xe2, 0xc5, 0x82, 0x4a, 0xee,
- 0xbc, 0x67, 0xd0, 0x38, 0xc6, 0x5e, 0xa1, 0x02, 0xc4, 0xd1, 0x15, 0x1c,
- 0xbf, 0xf1, 0x99, 0x39, 0xd8, 0x0a, 0xc9, 0xeb, 0x91, 0x83, 0x79, 0xdb,
- 0x64, 0x87, 0x74, 0xae, 0xff, 0xf0, 0x43, 0xbc, 0x02, 0x66, 0xba, 0x77,
- 0xe9, 0x51, 0x3c, 0x97, 0xb7, 0xcf, 0xd6, 0x2d, 0x2b, 0x15, 0x26, 0xc3,
- 0x43, 0xf7, 0xd2, 0x50, 0xe2, 0xc5, 0xd9, 0xc5, 0x8b, 0xde, 0x93, 0xac,
- 0x5f, 0xbe, 0xc5, 0x9b, 0xd6, 0x2b, 0x48, 0x9f, 0x01, 0x00, 0x5c, 0x8b,
- 0xc2, 0xe1, 0x8e, 0xdf, 0xe0, 0xa7, 0xe2, 0x06, 0xc5, 0xae, 0x2c, 0x5f,
- 0xb8, 0x21, 0xe1, 0xd6, 0x2e, 0x80, 0x6b, 0x17, 0xc2, 0x7d, 0x41, 0x62,
- 0xf7, 0x83, 0x8d, 0x62, 0xf1, 0xc5, 0xb8, 0xb1, 0x7e, 0x71, 0xfe, 0x78,
- 0xb1, 0x7f, 0xb3, 0xff, 0x9e, 0xdf, 0x71, 0x62, 0xc1, 0x02, 0xda, 0x68,
- 0xb2, 0x81, 0x02, 0x91, 0x8c, 0xe1, 0x18, 0x08, 0x08, 0x87, 0x85, 0x14,
- 0x11, 0x50, 0x89, 0x91, 0xca, 0x54, 0xb2, 0xcc, 0xa3, 0x2a, 0x84, 0xf5,
- 0x27, 0xe1, 0xf3, 0xe9, 0x67, 0xb7, 0xed, 0x74, 0xef, 0xd2, 0xa2, 0x20,
- 0x2f, 0xfc, 0xf0, 0x09, 0x9a, 0xe9, 0xdf, 0xa5, 0x44, 0xa8, 0x5f, 0xda,
- 0x17, 0xe4, 0xba, 0x58, 0xbf, 0xba, 0x6c, 0xdd, 0xfc, 0xac, 0x54, 0x9f,
- 0x06, 0x17, 0xdf, 0xde, 0xc2, 0x29, 0x8d, 0x62, 0xc1, 0x31, 0x33, 0x33,
- 0x9b, 0x94, 0x2b, 0xfc, 0x41, 0x7e, 0xd7, 0x4e, 0xfd, 0x2a, 0x22, 0x82,
- 0xfd, 0xa9, 0x3c, 0xf6, 0xb1, 0x78, 0xe2, 0x1a, 0xc5, 0xff, 0x9b, 0xd1,
- 0x4b, 0x66, 0xf6, 0xdc, 0x58, 0xb7, 0xd8, 0xf8, 0x77, 0x8f, 0x5e, 0x38,
- 0xb7, 0x16, 0x2f, 0xde, 0xe7, 0xc5, 0xc5, 0x8b, 0xfd, 0x0c, 0x19, 0x3b,
- 0x8d, 0x62, 0xa4, 0xf7, 0x1c, 0xaa, 0xff, 0xc2, 0x7d, 0x3c, 0x3c, 0xdc,
- 0x12, 0xc5, 0xff, 0x4f, 0x65, 0x9e, 0xe4, 0x9d, 0x62, 0x88, 0xfe, 0x04,
- 0x7f, 0x7a, 0x41, 0x8b, 0x16, 0x09, 0x8a, 0x8f, 0x18, 0xdd, 0xe1, 0x14,
- 0x02, 0x92, 0x7d, 0xe4, 0x26, 0x03, 0x21, 0xbf, 0xc1, 0x33, 0x5d, 0x3b,
- 0xf4, 0xa8, 0x8c, 0x8b, 0xf6, 0xba, 0x77, 0xe9, 0x51, 0x32, 0x97, 0xe8,
- 0x67, 0x9f, 0xa5, 0x8b, 0xf0, 0x43, 0xbc, 0x02, 0x61, 0xf0, 0x76, 0x6f,
- 0x77, 0x62, 0x58, 0xbf, 0x6b, 0xa7, 0x7e, 0x95, 0x15, 0x21, 0x62, 0x58,
- 0xba, 0x07, 0x58, 0xbe, 0x3e, 0x67, 0x96, 0x2c, 0x1a, 0xc5, 0xed, 0xd1,
- 0x01, 0x62, 0xc1, 0x20, 0x8c, 0xfc, 0x19, 0xdc, 0x37, 0xd0, 0x8b, 0x8c,
- 0x08, 0x8b, 0x74, 0x4e, 0xfd, 0xae, 0x9d, 0xfa, 0x54, 0x57, 0x45, 0xfd,
- 0xf6, 0xd6, 0x9e, 0x0b, 0x16, 0x09, 0x87, 0xcb, 0xc3, 0x7b, 0xc1, 0xc9,
- 0xd6, 0x2f, 0xda, 0xe9, 0xdf, 0xa5, 0x45, 0x8a, 0x58, 0x24, 0x9e, 0xae,
- 0x0f, 0x5f, 0xf4, 0xf3, 0x92, 0x7f, 0x67, 0x4b, 0x17, 0xdd, 0x3b, 0xf4,
- 0xa8, 0x9e, 0x8b, 0xf1, 0xde, 0x01, 0x33, 0xa3, 0xeb, 0xd1, 0xd5, 0xe3,
- 0x1f, 0xa5, 0x8b, 0xfb, 0xf2, 0xda, 0x60, 0xba, 0xc5, 0xfc, 0xd1, 0xbc,
- 0xf7, 0xc5, 0x8b, 0xf4, 0xb6, 0xcb, 0x6e, 0xac, 0x5f, 0x4f, 0x6f, 0xba,
- 0xb1, 0x71, 0x81, 0x31, 0x1a, 0x5d, 0x0f, 0xfc, 0xc5, 0xcb, 0xc8, 0xb6,
- 0xff, 0xf4, 0x90, 0x4c, 0xfb, 0xed, 0x3c, 0xe7, 0x96, 0x2f, 0xff, 0xff,
- 0x0f, 0x0c, 0x08, 0x58, 0x69, 0xaf, 0xee, 0x31, 0x45, 0x3d, 0x6b, 0x3b,
- 0x58, 0xbf, 0xff, 0xff, 0x79, 0xf5, 0x00, 0x99, 0xc1, 0x3f, 0x78, 0x52,
- 0x60, 0x7e, 0x68, 0x67, 0x7e, 0x58, 0xbf, 0x67, 0xbe, 0xc6, 0x2c, 0x5f,
- 0xfb, 0x98, 0x4e, 0x6f, 0xda, 0x49, 0x62, 0xff, 0xb3, 0x3e, 0xdd, 0x7f,
- 0x02, 0x11, 0xf3, 0x78, 0xa6, 0xf9, 0xb5, 0xf7, 0x58, 0xbf, 0x98, 0xc1,
- 0xbb, 0x9a, 0xb1, 0x7f, 0x44, 0x52, 0x70, 0x99, 0xf3, 0xd1, 0xe1, 0x15,
- 0xdc, 0xf2, 0xc5, 0xd9, 0xc5, 0x8b, 0xff, 0x66, 0xbb, 0x93, 0xfd, 0xf3,
- 0x4b, 0x17, 0x70, 0x0b, 0x17, 0xe2, 0x73, 0x94, 0xac, 0x5f, 0xc2, 0xe7,
- 0xde, 0x01, 0x36, 0x04, 0x56, 0x38, 0xc1, 0x0b, 0x98, 0x7e, 0x18, 0xc5,
- 0xe8, 0xe7, 0x71, 0x62, 0xed, 0x79, 0x62, 0xfd, 0x9e, 0xe3, 0x1d, 0x62,
- 0xff, 0xf4, 0xf7, 0xec, 0x89, 0xb5, 0xee, 0x0b, 0x71, 0x62, 0xf3, 0xf6,
- 0x12, 0x51, 0x62, 0xe4, 0x24, 0x31, 0xe2, 0x8a, 0xc5, 0x4c, 0xba, 0x87,
- 0x97, 0x23, 0x25, 0xa8, 0x2e, 0x7d, 0x0d, 0x33, 0xb7, 0xe2, 0x87, 0x77,
- 0xa5, 0x83, 0x50, 0x45, 0xeb, 0xd9, 0x8c, 0x4d, 0xa7, 0x54, 0x6f, 0xff,
- 0x0c, 0x27, 0xbc, 0x28, 0xc3, 0x8b, 0x82, 0xed, 0x62, 0xf4, 0x88, 0x2e,
- 0xb1, 0x7e, 0xd7, 0x5f, 0x6e, 0x2c, 0x53, 0x1e, 0x58, 0x88, 0x6e, 0xf4,
- 0xac, 0x56, 0xc4, 0x6e, 0x3b, 0x21, 0xbd, 0x1e, 0xc8, 0x51, 0x62, 0xff,
- 0x66, 0xf2, 0xce, 0x00, 0xeb, 0x15, 0xb0, 0x8f, 0x6c, 0x89, 0xaf, 0xcd,
- 0xf2, 0x78, 0x96, 0x2e, 0xd9, 0x0a, 0x2c, 0x5e, 0xd8, 0x70, 0x1a, 0xc5,
- 0xfa, 0x18, 0x3d, 0xb8, 0xb1, 0x7e, 0x76, 0x8f, 0x52, 0xb1, 0x7d, 0xdf,
- 0x4c, 0x4b, 0x17, 0xef, 0x10, 0x9f, 0x63, 0x58, 0xad, 0x89, 0x33, 0x50,
- 0xa9, 0x3e, 0xc3, 0x28, 0xd8, 0x43, 0xf2, 0x49, 0xf2, 0xaf, 0x14, 0x06,
- 0x49, 0x71, 0xc0, 0xb1, 0x7e, 0xcf, 0x30, 0xb8, 0xb1, 0x76, 0xc4, 0x16,
- 0xd6, 0x2b, 0x62, 0x3e, 0x30, 0xb6, 0x30, 0x16, 0x14, 0x5f, 0x82, 0xd7,
- 0x62, 0xe6, 0xbc, 0xb1, 0x7f, 0x83, 0x2c, 0xd6, 0xa7, 0xa5, 0x8a, 0xd8,
- 0x8f, 0xaf, 0x63, 0x36, 0xbe, 0xd1, 0xfd, 0xda, 0xc5, 0xf8, 0x28, 0x15,
- 0x3f, 0x0d, 0x58, 0xb9, 0xb8, 0xb1, 0x63, 0x16, 0x2b, 0x62, 0x3d, 0xde,
- 0x8c, 0xc3, 0x17, 0xbf, 0x05, 0x02, 0xb3, 0x03, 0xac, 0x5e, 0xfc, 0xee,
- 0x2c, 0x5f, 0xf8, 0x2c, 0xd8, 0x36, 0x30, 0xae, 0xc7, 0xb1, 0xec, 0x2d,
- 0x8f, 0x62, 0x58, 0xbf, 0xf0, 0x5a, 0xec, 0x7b, 0x08, 0x2d, 0x42, 0xd4,
- 0x2a, 0x15, 0x0a, 0x6c, 0x4b, 0x17, 0xfe, 0xd8, 0x41, 0x60, 0x5a, 0xec,
- 0x20, 0xb5, 0x0a, 0x85, 0xb0, 0xb5, 0xd8, 0x96, 0x2f, 0xfb, 0xe3, 0x80,
- 0x48, 0x70, 0x82, 0x05, 0x53, 0x59, 0xd8, 0x1b, 0xc2, 0xdb, 0x9d, 0x6c,
- 0x4a, 0x87, 0x42, 0xa6, 0x21, 0x6e, 0x37, 0x9b, 0xf0, 0x54, 0xee, 0xe4,
- 0xb1, 0x7f, 0x4b, 0x7b, 0xd2, 0x75, 0x8b, 0x87, 0xb8, 0xb1, 0x41, 0x43,
- 0xf3, 0x0b, 0x52, 0xbe, 0xcb, 0x6f, 0x75, 0x9f, 0x48, 0xbb, 0x9a, 0x58,
- 0xbc, 0x79, 0xe2, 0xc5, 0xff, 0xfe, 0xf0, 0x7a, 0x9f, 0xce, 0x74, 0x36,
- 0x28, 0xcf, 0x30, 0x58, 0xbb, 0x52, 0xb1, 0x4c, 0x7f, 0x40, 0x63, 0xbf,
- 0x4e, 0xb4, 0xf0, 0x58, 0xbf, 0xf8, 0x85, 0x3b, 0x5d, 0xbd, 0x0c, 0xe2,
- 0xc5, 0xff, 0xdf, 0x9e, 0x38, 0x7f, 0xfb, 0x77, 0xc5, 0x8b, 0xfe, 0x69,
- 0x2c, 0xdf, 0xa9, 0xe2, 0xc5, 0x74, 0x88, 0x0f, 0xa3, 0xdf, 0x34, 0x4c,
- 0x62, 0xc5, 0xe8, 0x98, 0xc5, 0x8b, 0xb2, 0x0b, 0x14, 0xc6, 0xd9, 0xc7,
- 0xe8, 0xe7, 0xf2, 0x05, 0xab, 0xff, 0x36, 0xdf, 0xb3, 0xc3, 0xcd, 0x1a,
- 0xc5, 0x61, 0xf1, 0xfc, 0x8a, 0xfd, 0xe0, 0x06, 0x51, 0x2c, 0x5f, 0xf9,
- 0xf9, 0xb7, 0x9c, 0xc8, 0x42, 0x56, 0x2d, 0xc5, 0x8b, 0xfa, 0x7a, 0x68,
- 0xdc, 0x96, 0x2f, 0xff, 0xc4, 0xe6, 0xb6, 0xa6, 0x10, 0xce, 0x00, 0x12,
- 0xb1, 0x7f, 0x9f, 0xc2, 0xcc, 0x23, 0x56, 0x28, 0x69, 0xaa, 0xe1, 0x09,
- 0xa5, 0x71, 0x20, 0xe8, 0x4b, 0xe5, 0xc0, 0x55, 0xbf, 0x7a, 0x4a, 0x62,
- 0x58, 0xba, 0x74, 0xb1, 0x60, 0xba, 0xc5, 0xe9, 0xfc, 0xac, 0x56, 0x1f,
- 0x89, 0xa5, 0x11, 0x0b, 0x90, 0xb5, 0xff, 0x8b, 0x05, 0xd1, 0x64, 0x61,
- 0xc1, 0x62, 0xff, 0xf3, 0x9c, 0x24, 0xeb, 0x4d, 0xbb, 0xd0, 0xa3, 0x58,
- 0xbb, 0x4c, 0x48, 0x93, 0xdd, 0x41, 0xbe, 0x6f, 0x86, 0x75, 0x8b, 0xff,
- 0xcc, 0x6e, 0xdc, 0x27, 0xef, 0x86, 0x9a, 0xeb, 0x15, 0xd1, 0xf9, 0x91,
- 0x25, 0xf7, 0x6f, 0xf9, 0x58, 0xbf, 0xfb, 0x85, 0x80, 0x09, 0xf6, 0xe9,
- 0xf4, 0xb1, 0x52, 0x7d, 0x4e, 0x47, 0x71, 0x18, 0xb1, 0x7e, 0xe1, 0x09,
- 0xe0, 0xb1, 0x7f, 0xfb, 0x8c, 0x7e, 0xf8, 0xfe, 0x17, 0x7c, 0x95, 0x8b,
- 0xfb, 0xd1, 0x41, 0xf4, 0x6a, 0xc5, 0xd9, 0xd2, 0xc5, 0xe1, 0xe1, 0xae,
- 0x79, 0x3e, 0x31, 0xbe, 0xfc, 0x9f, 0xa5, 0x8a, 0x94, 0xcb, 0x70, 0x63,
- 0xb2, 0x87, 0x84, 0xb7, 0x8c, 0xee, 0x10, 0x16, 0x2f, 0xde, 0xfb, 0x08,
- 0x2e, 0xb1, 0x50, 0x3c, 0x5c, 0x18, 0xbe, 0xcc, 0x23, 0x56, 0x2f, 0xff,
- 0x70, 0xa7, 0xdc, 0xc2, 0x17, 0x84, 0x6a, 0xc5, 0x71, 0x11, 0xde, 0x21,
- 0x11, 0x15, 0xe1, 0xe7, 0xd6, 0x2f, 0x44, 0xc6, 0x2c, 0x58, 0x70, 0x37,
- 0x8c, 0x3b, 0x7f, 0xfb, 0x3a, 0x1b, 0x10, 0x79, 0xad, 0x4e, 0xf5, 0x8b,
- 0xff, 0xb6, 0xcc, 0x94, 0x9f, 0x6e, 0xdf, 0xec, 0xac, 0x54, 0xa3, 0x00,
- 0x04, 0xc4, 0x9b, 0x7f, 0xc1, 0x78, 0x4e, 0x10, 0xe4, 0xeb, 0x17, 0xfe,
- 0xfe, 0x45, 0xf6, 0xfc, 0xea, 0x56, 0x2e, 0x7e, 0xd6, 0x2f, 0x14, 0xee,
- 0x2c, 0x5f, 0xe7, 0xe3, 0xfc, 0x45, 0x1a, 0xc5, 0x11, 0xf5, 0xf8, 0x60,
- 0x43, 0xf5, 0xb5, 0x97, 0x87, 0x18, 0xc4, 0x21, 0x2e, 0x32, 0x1c, 0x28,
- 0xee, 0x18, 0xad, 0x29, 0x56, 0x28, 0x6b, 0xea, 0x19, 0xe7, 0x85, 0x1f,
- 0xe1, 0x18, 0x51, 0xa6, 0xf2, 0x32, 0x1f, 0x46, 0x58, 0x22, 0xe0, 0xcf,
- 0x37, 0x61, 0x55, 0x77, 0x04, 0xb1, 0x6d, 0x2c, 0x5d, 0x3a, 0x58, 0xbc,
- 0x59, 0xba, 0xb1, 0x76, 0x7d, 0x62, 0xfd, 0xae, 0xe1, 0xe9, 0x58, 0xbd,
- 0x9b, 0xf1, 0x62, 0xb0, 0xf2, 0x08, 0xaa, 0xb6, 0xa3, 0x1f, 0xa1, 0x27,
- 0x17, 0xd9, 0x1f, 0x0d, 0x7e, 0xfb, 0x0e, 0xde, 0x58, 0xa9, 0x4d, 0x47,
- 0x50, 0xdf, 0xf2, 0x85, 0xee, 0x85, 0xa5, 0x8b, 0xb4, 0x05, 0x8b, 0x9f,
- 0x16, 0x2b, 0xb3, 0x5d, 0xa1, 0x8b, 0xc4, 0xfe, 0x58, 0xbc, 0x4d, 0xc5,
- 0x8b, 0x18, 0x15, 0x37, 0x12, 0x39, 0x74, 0xfd, 0x62, 0xfb, 0x5b, 0xdc,
- 0xeb, 0x17, 0xf7, 0x47, 0x29, 0xec, 0x0b, 0x17, 0xb9, 0x09, 0x58, 0xbf,
- 0x73, 0x33, 0x19, 0x62, 0xb0, 0xf0, 0xc0, 0x3b, 0x7f, 0xf9, 0xb6, 0xcc,
- 0x4d, 0xed, 0x4f, 0x42, 0xe9, 0x62, 0xf0, 0x1f, 0xb5, 0x8b, 0xec, 0xf4,
- 0x98, 0xb1, 0x58, 0x78, 0x24, 0x3d, 0x7f, 0xf9, 0xb6, 0xff, 0x22, 0x6e,
- 0xf9, 0xfc, 0xe9, 0x62, 0xe2, 0xe2, 0xc5, 0xf1, 0x3f, 0xb8, 0xb1, 0x50,
- 0x37, 0x27, 0x17, 0xbd, 0x39, 0xa5, 0x8b, 0xff, 0xdd, 0x3e, 0x9f, 0xcd,
- 0xc9, 0x29, 0x02, 0xc5, 0xa1, 0xf3, 0xe5, 0x0c, 0x72, 0xbb, 0x45, 0x7e,
- 0xa1, 0x0d, 0x52, 0xaf, 0x9e, 0x33, 0x51, 0xa6, 0xe2, 0xd7, 0x45, 0x6c,
- 0x2f, 0x11, 0x29, 0xdc, 0xc0, 0x43, 0xc8, 0x48, 0x78, 0x80, 0x51, 0x9b,
- 0xdf, 0x0c, 0xe6, 0x71, 0x62, 0xff, 0x81, 0xd7, 0xdb, 0x4d, 0x90, 0x58,
- 0xbc, 0xc1, 0x9d, 0x62, 0xe6, 0x1a, 0xc5, 0x39, 0xb5, 0x0c, 0x7a, 0xf7,
- 0xe4, 0x96, 0x2f, 0x73, 0x77, 0x75, 0x62, 0xfb, 0x6c, 0x00, 0x75, 0x8b,
- 0xda, 0xc1, 0xac, 0x5f, 0xe7, 0xf4, 0xc5, 0xc6, 0x3a, 0xc5, 0x1a, 0x7a,
- 0x3f, 0x1d, 0xbf, 0xd3, 0x02, 0xce, 0xfd, 0x8b, 0x17, 0xee, 0x9b, 0xb8,
- 0xc9, 0x62, 0xff, 0xe7, 0xea, 0x48, 0x71, 0x42, 0x75, 0x1a, 0xc5, 0x76,
- 0x7e, 0x5f, 0x2b, 0xb7, 0x16, 0x29, 0x8d, 0xaf, 0x08, 0xef, 0xe2, 0xd3,
- 0xbb, 0xf9, 0x62, 0xff, 0xfb, 0xdc, 0x1e, 0xb1, 0x8d, 0xf9, 0x8e, 0x51,
- 0xac, 0x5f, 0x10, 0xf0, 0xd5, 0x8b, 0xdf, 0x11, 0xd6, 0x2e, 0xde, 0x35,
- 0x8a, 0xd8, 0x6a, 0xd8, 0xe4, 0x96, 0x0d, 0xe3, 0x21, 0xc1, 0xce, 0xc9,
- 0x19, 0xdf, 0x44, 0x7f, 0x86, 0xd3, 0x90, 0x70, 0xb3, 0xca, 0x62, 0x23,
- 0x30, 0x7a, 0xfd, 0x84, 0x53, 0x1a, 0xc5, 0xbb, 0x58, 0xd1, 0xa7, 0xbc,
- 0x22, 0x82, 0xc5, 0xfb, 0x91, 0x49, 0x46, 0xb1, 0x58, 0x7d, 0x46, 0x91,
- 0xf8, 0x76, 0xf6, 0xd8, 0x46, 0xb1, 0x78, 0xed, 0xc5, 0x8b, 0xf1, 0x1a,
- 0xd9, 0xc5, 0x8b, 0xf7, 0xdb, 0x8c, 0x35, 0x8b, 0xcd, 0x27, 0x58, 0xb6,
- 0xa0, 0x78, 0x9f, 0x28, 0xbe, 0x7f, 0x3f, 0x4b, 0x14, 0xc7, 0x96, 0x61,
- 0x45, 0xf0, 0x82, 0xfc, 0x8d, 0x62, 0xff, 0xc6, 0x38, 0x33, 0xaf, 0xb8,
- 0x38, 0xb1, 0x52, 0x7d, 0x58, 0x53, 0x7f, 0xee, 0x3f, 0x72, 0x4e, 0x3c,
- 0x35, 0x62, 0x8d, 0x4e, 0xfd, 0x87, 0x7f, 0x0b, 0x72, 0x84, 0x67, 0x88,
- 0x2e, 0x30, 0x6b, 0x17, 0xff, 0xbd, 0xfc, 0x38, 0x1f, 0x59, 0xbf, 0x06,
- 0xb1, 0x74, 0xfd, 0x62, 0xc3, 0x58, 0xa3, 0x9a, 0x92, 0x17, 0xb1, 0xab,
- 0x17, 0x88, 0x12, 0xb1, 0x71, 0x0f, 0x69, 0xaf, 0xe0, 0x9d, 0xd9, 0xe5,
- 0x8b, 0xfb, 0x38, 0x63, 0x94, 0x6b, 0x15, 0x29, 0x9c, 0x63, 0xab, 0xa7,
- 0x80, 0xb8, 0x85, 0xef, 0xf1, 0x39, 0x9b, 0x5f, 0xac, 0x58, 0xbe, 0x17,
- 0x1f, 0xa5, 0x8b, 0xff, 0x08, 0x7f, 0x69, 0xdf, 0xa0, 0xf8, 0xb1, 0x5a,
- 0x3e, 0x72, 0x24, 0xbe, 0xf6, 0xce, 0x7d, 0x62, 0xf7, 0x07, 0x2b, 0x17,
- 0xff, 0xf7, 0x59, 0xdf, 0xbe, 0xda, 0x97, 0x80, 0x33, 0x22, 0x58, 0xbf,
- 0xde, 0xce, 0x84, 0x07, 0xc5, 0x8a, 0x24, 0x48, 0xf1, 0x76, 0x8d, 0x46,
- 0x83, 0xc2, 0xba, 0xa5, 0x33, 0xfc, 0x21, 0x14, 0x3d, 0xad, 0xc5, 0x8b,
- 0x62, 0xc5, 0x31, 0xa3, 0xdd, 0x12, 0xbe, 0xec, 0xa4, 0xd5, 0x8b, 0xfc,
- 0xc1, 0x9f, 0x30, 0x8d, 0x58, 0xa3, 0x9f, 0xdb, 0x91, 0x80, 0x92, 0xff,
- 0xb0, 0x9e, 0x1c, 0x81, 0x91, 0xac, 0x5f, 0x43, 0x8c, 0x4b, 0x17, 0xdf,
- 0xea, 0x7a, 0x58, 0xbf, 0xf7, 0x44, 0xff, 0x7e, 0xf3, 0xbf, 0x2c, 0x54,
- 0x11, 0x87, 0xd9, 0xdb, 0x11, 0x08, 0x96, 0xff, 0xe9, 0xd0, 0x8e, 0x4e,
- 0x68, 0xf4, 0x17, 0x58, 0xbd, 0x8e, 0x75, 0x8a, 0x34, 0xf9, 0xb4, 0x95,
- 0x52, 0x8c, 0x67, 0x85, 0x1d, 0xf1, 0x79, 0x8e, 0xb1, 0x7a, 0x66, 0x0b,
- 0x18, 0x68, 0xaf, 0xe9, 0xe4, 0xfe, 0x78, 0xb1, 0x7b, 0xa6, 0xe9, 0x62,
- 0xf6, 0xce, 0x7d, 0x62, 0xed, 0x42, 0x4d, 0xff, 0x87, 0xeb, 0x48, 0x98,
- 0x76, 0xcb, 0xbd, 0x8b, 0x15, 0x2c, 0x9a, 0x48, 0xcb, 0xf2, 0x3e, 0x0e,
- 0xd5, 0x1a, 0x35, 0x1d, 0x23, 0xfe, 0x3d, 0xc7, 0x86, 0x91, 0x47, 0x6f,
- 0xc4, 0x81, 0x43, 0x0c, 0x32, 0x2b, 0xff, 0xc6, 0xbe, 0x77, 0xef, 0x4e,
- 0x6f, 0x6e, 0x96, 0x2f, 0xfe, 0xee, 0x1c, 0x92, 0x9e, 0xa5, 0xbe, 0xb1,
- 0x7f, 0x8b, 0x39, 0xe7, 0x72, 0x58, 0xa3, 0x51, 0x88, 0xe9, 0xdb, 0xd1,
- 0x6f, 0xb7, 0x77, 0x67, 0x71, 0x62, 0xff, 0xfb, 0xcc, 0x42, 0x86, 0x70,
- 0x62, 0x7d, 0x41, 0x62, 0xd3, 0xb4, 0xff, 0x03, 0x2c, 0xbf, 0xf1, 0xde,
- 0x19, 0xf6, 0xd7, 0xdd, 0x62, 0xe6, 0xd6, 0x8f, 0xa0, 0x05, 0x57, 0xff,
- 0xf1, 0x61, 0xb8, 0x5b, 0x79, 0xef, 0xe1, 0xc3, 0x90, 0x2c, 0x54, 0xa2,
- 0x2f, 0x0b, 0x6f, 0xf0, 0x9f, 0x8d, 0x13, 0x18, 0xb1, 0x4c, 0x9f, 0xbf,
- 0xe3, 0xa1, 0x22, 0x1b, 0xdf, 0x92, 0x58, 0xbb, 0xc7, 0x58, 0xb6, 0xca,
- 0xc5, 0x76, 0x6b, 0x7e, 0x31, 0x5d, 0x1f, 0x5b, 0xa4, 0xdf, 0x0f, 0x4c,
- 0x62, 0xc5, 0xfd, 0x99, 0x1e, 0x67, 0x96, 0x2e, 0x37, 0x7a, 0xc5, 0xec,
- 0x10, 0xd6, 0x2a, 0x34, 0x44, 0x8c, 0x90, 0x8b, 0x78, 0x37, 0x7f, 0xff,
- 0xd3, 0xef, 0xcf, 0x32, 0x1f, 0x93, 0x93, 0x9a, 0x58, 0x05, 0x8b, 0xcc,
- 0x5e, 0x58, 0xbe, 0x9e, 0xb3, 0x4b, 0x17, 0xdf, 0x9d, 0xf8, 0xb1, 0x7f,
- 0x3e, 0xf6, 0x89, 0x8c, 0x58, 0xa3, 0xa2, 0x50, 0x87, 0x3c, 0x46, 0x19,
- 0x25, 0xfe, 0x16, 0xa3, 0x3c, 0xe7, 0x96, 0x2f, 0xfb, 0x92, 0x71, 0xfe,
- 0x4b, 0xa5, 0x8b, 0x98, 0xb0, 0xfb, 0xcd, 0x35, 0xa9, 0x46, 0xc0, 0xe1,
- 0x59, 0x7a, 0x02, 0xe2, 0xc5, 0xfc, 0x37, 0xd0, 0x36, 0x71, 0x62, 0xf7,
- 0xc3, 0xde, 0xb1, 0x7f, 0xd2, 0x72, 0xce, 0xb4, 0xc0, 0x58, 0xb0, 0xd6,
- 0x2f, 0x73, 0x98, 0xb1, 0x61, 0xc9, 0xaf, 0x71, 0x2a, 0x82, 0x2b, 0xb8,
- 0x42, 0x26, 0x8b, 0xfb, 0xee, 0xdd, 0x61, 0x2c, 0x5f, 0xe8, 0x63, 0x73,
- 0x82, 0x95, 0x8b, 0xf8, 0x78, 0x50, 0xfe, 0x2c, 0x5f, 0xff, 0xfe, 0xce,
- 0x7f, 0x35, 0x24, 0xfd, 0xc3, 0xf3, 0xef, 0x4f, 0x7f, 0x93, 0xac, 0x54,
- 0xa3, 0x61, 0x8c, 0xce, 0x5b, 0x7f, 0xef, 0x49, 0xfb, 0xe9, 0xbb, 0xcd,
- 0x2c, 0x5f, 0xbf, 0x9a, 0x6e, 0x2c, 0x5e, 0x26, 0x87, 0x67, 0xd5, 0xe4,
- 0x2b, 0xbb, 0xf2, 0xc5, 0xff, 0x60, 0x24, 0x9c, 0x78, 0x6a, 0xc5, 0xfd,
- 0x3e, 0xc6, 0x10, 0x5d, 0x62, 0x9c, 0xfa, 0x40, 0x71, 0x7f, 0xd9, 0x1e,
- 0x0f, 0x0a, 0x77, 0x16, 0x2f, 0xff, 0xfd, 0xc9, 0x81, 0x99, 0xf0, 0xfc,
- 0x52, 0x07, 0xf0, 0x03, 0x28, 0x2c, 0x54, 0xab, 0x1d, 0x8e, 0x30, 0x58,
- 0x42, 0x61, 0xcc, 0xc1, 0x08, 0x22, 0x21, 0xf1, 0xdd, 0xff, 0xe2, 0xf6,
- 0xce, 0x45, 0x07, 0xd4, 0x63, 0x95, 0x8b, 0xff, 0xf8, 0xa1, 0x3e, 0x7f,
- 0xf1, 0x9f, 0xc0, 0x0c, 0xa0, 0xb1, 0x7d, 0xef, 0x66, 0xe2, 0xc5, 0xff,
- 0x4e, 0x43, 0xf8, 0xd0, 0xe2, 0xc5, 0x70, 0xf7, 0xbc, 0x4d, 0x7e, 0x1c,
- 0x5f, 0x16, 0xe2, 0xc5, 0x76, 0x7a, 0x04, 0x45, 0x58, 0x9b, 0xd3, 0x27,
- 0xbc, 0x61, 0x37, 0xed, 0x13, 0x61, 0xab, 0x17, 0xe9, 0xfb, 0x77, 0x05,
- 0x8b, 0x8f, 0x05, 0x8b, 0xfe, 0x7c, 0xe8, 0x79, 0xa0, 0x32, 0xc5, 0x6d,
- 0x3f, 0xa1, 0x94, 0xfc, 0x62, 0xff, 0x77, 0xc0, 0xc9, 0xa4, 0x6b, 0x15,
- 0xa3, 0xe6, 0x23, 0x1a, 0x94, 0xca, 0x5a, 0x30, 0x8b, 0xfd, 0x0e, 0x14,
- 0x81, 0xce, 0xb1, 0x7e, 0x7e, 0xfd, 0x1c, 0xac, 0x54, 0x9e, 0xe9, 0x19,
- 0xdf, 0x8d, 0xc1, 0x6a, 0x35, 0x8b, 0xe9, 0xe8, 0x52, 0xb1, 0x5a, 0x3c,
- 0xe3, 0x0a, 0xef, 0xe6, 0xd4, 0x62, 0x06, 0x2c, 0x5f, 0xbd, 0x38, 0x5d,
- 0x2c, 0x5f, 0x77, 0xe9, 0x3a, 0xc5, 0x1a, 0x79, 0x9d, 0x94, 0x58, 0x96,
- 0x2f, 0xe6, 0x78, 0x79, 0xa3, 0x58, 0xbf, 0xbc, 0xdf, 0x62, 0xf2, 0xc5,
- 0xa1, 0xb4, 0xfb, 0x3e, 0x22, 0x19, 0x75, 0xff, 0xb3, 0x70, 0x7f, 0x9f,
- 0xcf, 0xb8, 0xb1, 0x7f, 0xfa, 0x73, 0xbf, 0x7e, 0x7c, 0x52, 0x0e, 0x2c,
- 0x5d, 0x20, 0x58, 0xbb, 0xe7, 0x58, 0xbf, 0xff, 0xda, 0x14, 0x18, 0xb0,
- 0x40, 0xdb, 0x9c, 0x21, 0x3c, 0x6b, 0x15, 0xd2, 0x24, 0xb8, 0x2f, 0xe1,
- 0x8a, 0x95, 0x56, 0xb1, 0x91, 0xb3, 0xdb, 0xc2, 0x40, 0x8e, 0x3c, 0x84,
- 0x28, 0x6e, 0x5f, 0x86, 0xe4, 0x23, 0xac, 0x5f, 0xf8, 0x40, 0xce, 0xb3,
- 0x5a, 0x78, 0x2c, 0x5f, 0xfc, 0x27, 0x81, 0xc5, 0xef, 0xc8, 0x82, 0xeb,
- 0x17, 0x49, 0xd6, 0x2b, 0x11, 0x93, 0xa2, 0x82, 0x40, 0xe2, 0x55, 0xff,
- 0xf0, 0xde, 0x29, 0xec, 0x9c, 0xdc, 0x1b, 0xc1, 0x62, 0xf4, 0x6d, 0xa5,
- 0x8b, 0xfe, 0x33, 0x59, 0x3d, 0xc1, 0x8e, 0xb1, 0x7f, 0xdc, 0x6e, 0xfd,
- 0x14, 0x27, 0xb5, 0x8b, 0xf7, 0x3d, 0xcc, 0xf2, 0xc5, 0x4a, 0x28, 0x78,
- 0x76, 0x23, 0xdb, 0xf0, 0x5d, 0xa2, 0x63, 0x16, 0x2f, 0xe2, 0x98, 0x84,
- 0xe1, 0xac, 0x50, 0x8f, 0x74, 0x32, 0xeb, 0xb3, 0xeb, 0x17, 0x8c, 0x30,
- 0xc4, 0x8b, 0xff, 0xde, 0x6f, 0x73, 0xed, 0xb2, 0x1e, 0xa6, 0x09, 0x01,
- 0x0d, 0x0d, 0x4a, 0xa5, 0x83, 0x54, 0x5a, 0x17, 0xef, 0x08, 0xcf, 0x11,
- 0x88, 0xe2, 0xef, 0x76, 0xb1, 0x7f, 0x9b, 0x51, 0x88, 0x18, 0x4b, 0x14,
- 0x73, 0xcd, 0x0b, 0x8c, 0xdd, 0x13, 0x2c, 0x5f, 0xff, 0xd0, 0x92, 0xcf,
- 0x7d, 0xb3, 0xd2, 0x76, 0xd4, 0x16, 0x2b, 0x47, 0xe3, 0xe1, 0x8b, 0xf8,
- 0xe1, 0x96, 0x6f, 0xc5, 0x8b, 0xf6, 0x70, 0x45, 0xe5, 0x8a, 0x63, 0xfa,
- 0x72, 0x22, 0x30, 0xbf, 0xff, 0x4e, 0xa3, 0x9f, 0xbb, 0x6b, 0x4c, 0x70,
- 0xa6, 0xc3, 0x58, 0xa8, 0x36, 0x9a, 0x23, 0x85, 0x06, 0x42, 0xac, 0xd3,
- 0xde, 0xa3, 0xd1, 0xec, 0x9d, 0x87, 0xa2, 0x86, 0xfe, 0xa5, 0xa6, 0x9e,
- 0x3e, 0xef, 0xc6, 0xba, 0x08, 0x42, 0x94, 0xb2, 0x3e, 0x46, 0x6d, 0xe9,
- 0x52, 0x62, 0x85, 0x76, 0xf8, 0xc4, 0x77, 0x4b, 0x2f, 0xfb, 0xb8, 0x73,
- 0x98, 0x37, 0xf2, 0xc5, 0xfd, 0xaf, 0x48, 0x82, 0xfc, 0x58, 0xb9, 0xb6,
- 0x56, 0x2e, 0x88, 0xeb, 0x17, 0xec, 0xd7, 0x85, 0xf5, 0x8a, 0xd1, 0xee,
- 0x00, 0x68, 0x31, 0x9b, 0x62, 0xc5, 0xb1, 0x63, 0x70, 0xb1, 0xbe, 0xd1,
- 0x3e, 0xf5, 0x8b, 0xd8, 0xe4, 0xb1, 0x63, 0x16, 0x2e, 0xdb, 0x8b, 0x14,
- 0xe6, 0xb3, 0xc2, 0x75, 0x29, 0xdc, 0x8c, 0xef, 0x21, 0x1e, 0x6a, 0x0b,
- 0x11, 0xe8, 0x90, 0xe8, 0xf7, 0xff, 0xf1, 0x67, 0xbf, 0x90, 0xd4, 0xfd,
- 0xdb, 0xd3, 0xf5, 0x8b, 0xc0, 0xe6, 0x2c, 0x5f, 0xbb, 0xdd, 0x79, 0xed,
- 0x62, 0xfb, 0xf8, 0x07, 0x58, 0xbe, 0xfb, 0x77, 0xe5, 0x8b, 0x9e, 0x1b,
- 0x4f, 0x1a, 0x22, 0x2b, 0x18, 0xb1, 0x7d, 0x09, 0x28, 0x2c, 0x59, 0xd6,
- 0x2f, 0x4f, 0xf8, 0xb1, 0x5d, 0x9a, 0xe6, 0x11, 0xbf, 0xf4, 0xf5, 0xb7,
- 0x0a, 0x44, 0x17, 0xe2, 0xc5, 0xff, 0xfc, 0xfe, 0x6f, 0xb9, 0xf6, 0xe7,
- 0x27, 0x35, 0x84, 0xb1, 0x7f, 0xee, 0x61, 0x0f, 0x6e, 0x0d, 0xb7, 0xac,
- 0x5f, 0xfd, 0xc7, 0xef, 0x9c, 0xc2, 0x06, 0xce, 0x2c, 0x5f, 0xfe, 0x6e,
- 0xb9, 0x3b, 0x39, 0xe8, 0x43, 0x38, 0xb1, 0x43, 0x54, 0x57, 0xd9, 0x84,
- 0x42, 0x7a, 0x50, 0x39, 0x09, 0x22, 0xf1, 0x6b, 0xc8, 0x5b, 0xd2, 0x2f,
- 0xb5, 0xfc, 0x25, 0x8b, 0xff, 0xf1, 0x63, 0x71, 0xb5, 0x22, 0xf4, 0x53,
- 0x83, 0x58, 0xa9, 0x57, 0x2e, 0xd2, 0xa7, 0x9e, 0x10, 0x62, 0x22, 0xbf,
- 0x07, 0x06, 0x07, 0x16, 0x2f, 0x64, 0xca, 0xc5, 0xf8, 0x3e, 0x19, 0x9f,
- 0x58, 0xa8, 0xcf, 0x1b, 0x83, 0x74, 0x34, 0x49, 0xe9, 0xc2, 0xfe, 0x2d,
- 0xa1, 0xf2, 0x71, 0x62, 0xfb, 0x4e, 0x76, 0x58, 0xbe, 0xf4, 0xf6, 0x62,
- 0xc5, 0x62, 0xec, 0x17, 0x4b, 0x3f, 0x97, 0x68, 0xf0, 0xdb, 0x01, 0x18,
- 0x8c, 0x0c, 0x22, 0xbf, 0xf0, 0xe6, 0x4f, 0x9c, 0x13, 0xf6, 0xb1, 0x7f,
- 0xfc, 0x20, 0xfc, 0x52, 0x07, 0xf0, 0x03, 0x28, 0x2c, 0x53, 0x22, 0x47,
- 0xc7, 0xf7, 0xe8, 0xf6, 0x83, 0xb0, 0x2c, 0x5f, 0xbd, 0xec, 0x23, 0xac,
- 0x5f, 0xff, 0xe9, 0xce, 0x61, 0x6a, 0x60, 0xc7, 0xce, 0xe1, 0x10, 0x96,
- 0x2a, 0x51, 0x6e, 0xc5, 0xc4, 0x51, 0x71, 0x9f, 0x58, 0xbf, 0xfd, 0x25,
- 0xd0, 0x7a, 0x70, 0x37, 0xbf, 0x2b, 0x17, 0xcf, 0x1b, 0x92, 0xc5, 0xfb,
- 0xdf, 0xc0, 0x3a, 0xc5, 0x76, 0x79, 0x44, 0x45, 0x7f, 0x1f, 0x6f, 0xf0,
- 0x0e, 0xb1, 0x7f, 0x19, 0xcc, 0xc2, 0x8d, 0x62, 0xa5, 0x10, 0x38, 0x44,
- 0xc6, 0x17, 0xf6, 0xb0, 0x85, 0x3a, 0x58, 0xbe, 0x9e, 0x4e, 0xf5, 0x8b,
- 0xff, 0xa4, 0x9f, 0xd0, 0x93, 0x5c, 0xcf, 0x2c, 0x56, 0xc6, 0x89, 0x6f,
- 0x96, 0x88, 0x92, 0xf6, 0xd7, 0xe9, 0x62, 0xa5, 0x5a, 0x6c, 0x21, 0xb3,
- 0xd1, 0x68, 0x06, 0x79, 0x18, 0xb7, 0xa1, 0x87, 0xba, 0x6b, 0x7e, 0x0c,
- 0xe7, 0x6d, 0xc5, 0x8b, 0xf6, 0x17, 0x98, 0xeb, 0x15, 0x03, 0xd4, 0x39,
- 0x6d, 0xf6, 0x72, 0x60, 0xb1, 0x7d, 0xaf, 0xb0, 0x6b, 0x17, 0xf4, 0x39,
- 0xe6, 0x9e, 0xd6, 0x2f, 0x8e, 0x1c, 0x92, 0xc5, 0xf3, 0x0f, 0x0e, 0xb1,
- 0x7c, 0xee, 0x40, 0x58, 0xb1, 0x92, 0x78, 0x66, 0x91, 0x5c, 0x23, 0xac,
- 0x5f, 0xe3, 0x1e, 0x2c, 0x84, 0xee, 0x2c, 0x5f, 0xb7, 0x45, 0x13, 0x44,
- 0xb1, 0x4c, 0x8a, 0x7f, 0x94, 0xf0, 0x60, 0x47, 0x17, 0xfc, 0xc7, 0xff,
- 0x6f, 0xb9, 0xee, 0x2c, 0x5f, 0xdd, 0x3f, 0xff, 0x83, 0x58, 0xa9, 0x3e,
- 0xd1, 0x1f, 0x5f, 0x49, 0x8e, 0x62, 0xc5, 0xf7, 0xb8, 0x21, 0xac, 0x5f,
- 0x9b, 0xb8, 0x7b, 0xa5, 0x8b, 0xfd, 0x2f, 0xaf, 0x98, 0xe3, 0x48, 0xb8,
- 0xc3, 0x12, 0x28, 0x67, 0x9c, 0x61, 0xa5, 0xcd, 0xb8, 0x90, 0x10, 0xd1,
- 0xd0, 0x11, 0x91, 0xe8, 0x4e, 0x5f, 0xba, 0x6e, 0x7d, 0x96, 0x2f, 0xfa,
- 0x41, 0xf9, 0xe1, 0x3c, 0x4b, 0x15, 0xd9, 0xf1, 0x11, 0x4d, 0xe3, 0xc9,
- 0xd6, 0x2f, 0x40, 0x5e, 0x58, 0xa9, 0x37, 0x62, 0x1d, 0xa9, 0x5c, 0x85,
- 0x19, 0x16, 0x11, 0x76, 0x48, 0xc5, 0xf1, 0x46, 0x1a, 0x78, 0x54, 0x80,
- 0x84, 0x89, 0x39, 0x0e, 0xcf, 0x42, 0x2b, 0x65, 0x76, 0xf8, 0x87, 0xf7,
- 0x58, 0xbd, 0x8f, 0xb8, 0xb1, 0x7b, 0x58, 0x35, 0x8a, 0xc3, 0xde, 0xd1,
- 0x16, 0xf1, 0xfb, 0xdf, 0x9d, 0x2c, 0x5d, 0xee, 0x2c, 0x5f, 0x8f, 0xad,
- 0x4c, 0x6b, 0x17, 0xb0, 0x05, 0x27, 0x85, 0x83, 0x17, 0x19, 0xc5, 0xe6,
- 0x20, 0x5b, 0x16, 0x2d, 0xde, 0x1b, 0x7f, 0x13, 0x5f, 0x77, 0x00, 0xaf,
- 0x6b, 0x16, 0xfa, 0xc5, 0xff, 0xb8, 0x32, 0x91, 0xfe, 0x7d, 0xc5, 0x8a,
- 0x93, 0xd1, 0xe0, 0x95, 0x4a, 0x30, 0xf0, 0x9c, 0x4f, 0x77, 0xff, 0xfd,
- 0x86, 0x64, 0x3f, 0x8d, 0x0e, 0x77, 0xc6, 0xf3, 0x14, 0x6b, 0x17, 0x7e,
- 0x25, 0x8b, 0xfd, 0xf6, 0x78, 0x79, 0xa3, 0x58, 0xbe, 0x62, 0xf4, 0xac,
- 0x5f, 0xf3, 0x69, 0xc1, 0xbb, 0xec, 0xfa, 0xc5, 0x7c, 0xf7, 0x7c, 0x43,
- 0x7f, 0xcc, 0x61, 0x67, 0x98, 0x40, 0x58, 0xbf, 0xbd, 0x2c, 0x41, 0xf1,
- 0x62, 0xfc, 0x76, 0x89, 0x8c, 0x58, 0xa9, 0x3d, 0x86, 0x2e, 0xbf, 0x36,
- 0x87, 0x31, 0xac, 0x5f, 0xe7, 0xd7, 0xb8, 0x4c, 0x6a, 0xc5, 0xfd, 0xdf,
- 0x33, 0xc1, 0xc6, 0xb1, 0x74, 0x9d, 0x62, 0xff, 0xff, 0xf9, 0xb8, 0x1e,
- 0xa7, 0xf3, 0x87, 0x62, 0x84, 0xb7, 0xdb, 0xa2, 0x6d, 0xeb, 0x17, 0xc6,
- 0x7b, 0x3e, 0x34, 0x4a, 0x70, 0x5e, 0xa5, 0x30, 0x17, 0x86, 0x35, 0xf8,
- 0xdc, 0xd6, 0x79, 0x62, 0xff, 0xec, 0x37, 0x05, 0xa7, 0x1c, 0xfe, 0x56,
- 0x29, 0x8f, 0xb7, 0x85, 0x37, 0xfe, 0x27, 0x33, 0xaf, 0xb6, 0xf6, 0xd2,
- 0xc5, 0xe1, 0xfe, 0x56, 0x28, 0x67, 0xbe, 0x1a, 0x15, 0x05, 0x57, 0x8c,
- 0x65, 0x7e, 0x11, 0x95, 0x61, 0x77, 0x4d, 0x1d, 0x8c, 0xb4, 0x24, 0x77,
- 0x08, 0xb5, 0x09, 0x1f, 0x90, 0x39, 0x49, 0x46, 0x6b, 0xc8, 0x4a, 0x0a,
- 0x10, 0x17, 0xa2, 0x7d, 0x2c, 0x5f, 0xf7, 0xbf, 0x80, 0x14, 0xf6, 0x1a,
- 0xc5, 0xff, 0xff, 0x9d, 0xbd, 0x3f, 0x2c, 0xf7, 0xd8, 0x38, 0x4e, 0xf6,
- 0x20, 0x2c, 0x5f, 0xba, 0xc3, 0xcf, 0x16, 0x2f, 0x08, 0x86, 0xb1, 0x7f,
- 0xf6, 0x34, 0x67, 0x97, 0x68, 0x3f, 0x16, 0x2f, 0xf3, 0x80, 0x3d, 0x97,
- 0x20, 0x2c, 0x57, 0xcf, 0xe8, 0x90, 0xef, 0xff, 0xcd, 0xee, 0x61, 0xb1,
- 0x41, 0xbd, 0xc1, 0xe1, 0x2c, 0x5f, 0xfe, 0xcf, 0xe1, 0x7b, 0x99, 0xbc,
- 0xa7, 0xb5, 0x8a, 0x95, 0x49, 0x3d, 0x8f, 0x7c, 0xf1, 0xdb, 0x00, 0x53,
- 0xe8, 0x4b, 0xef, 0x21, 0x31, 0x5e, 0xe6, 0xed, 0x62, 0xf4, 0x97, 0x96,
- 0x2e, 0x6d, 0x2c, 0x54, 0x66, 0xcf, 0x07, 0x2f, 0xf4, 0x18, 0xff, 0xed,
- 0xf7, 0x16, 0x2f, 0x9f, 0x53, 0x05, 0x8b, 0xee, 0xf0, 0x51, 0x2c, 0x5f,
- 0xf8, 0x53, 0xa3, 0x5c, 0x3f, 0x34, 0x16, 0x2f, 0xf9, 0xfb, 0xdb, 0xdf,
- 0x30, 0x8d, 0x58, 0xa8, 0xd3, 0x1f, 0xec, 0x84, 0xe7, 0x1f, 0x22, 0x22,
- 0x5f, 0x20, 0xdf, 0x7f, 0x71, 0x8e, 0xb1, 0x78, 0xa4, 0x0b, 0x15, 0xb4,
- 0xf0, 0xb8, 0x4d, 0x7f, 0x79, 0xce, 0x79, 0x3a, 0xc5, 0x8f, 0x87, 0xa5,
- 0xd9, 0x25, 0xfe, 0xef, 0xf9, 0x17, 0xdb, 0x4b, 0x15, 0x27, 0xbd, 0x85,
- 0x17, 0xe7, 0x2c, 0xee, 0x56, 0x2f, 0xf7, 0xe4, 0xfd, 0x7d, 0xa2, 0x58,
- 0xb4, 0xec, 0x67, 0xbb, 0xd9, 0x3d, 0xf3, 0xf3, 0xb7, 0x58, 0xbf, 0xe8,
- 0x73, 0xef, 0xd4, 0x90, 0xd6, 0x2f, 0x03, 0xdf, 0x58, 0xa8, 0x1f, 0xdf,
- 0x64, 0x60, 0x3a, 0xbf, 0xff, 0xf6, 0xb0, 0x7c, 0x7d, 0xc6, 0xef, 0xee,
- 0xd0, 0x91, 0xfc, 0x46, 0xac, 0x58, 0x0b, 0x14, 0xe8, 0xb3, 0xe1, 0x80,
- 0x6e, 0x37, 0xe6, 0xeb, 0x1c, 0xeb, 0x15, 0x2b, 0xab, 0xf0, 0x7a, 0xc8,
- 0xda, 0x9a, 0x34, 0xbd, 0x3e, 0xbc, 0x6b, 0x64, 0x61, 0x7f, 0x10, 0xf9,
- 0xc6, 0x3a, 0xc5, 0xfb, 0xa7, 0x8f, 0x0c, 0x58, 0xbf, 0x4e, 0x87, 0x84,
- 0xb1, 0x58, 0x88, 0x02, 0x2e, 0xf1, 0x5d, 0xfa, 0x76, 0x5b, 0xe2, 0x58,
- 0xbf, 0x08, 0x8b, 0x0d, 0x58, 0xbd, 0xa6, 0xfa, 0xc5, 0x74, 0x78, 0xa4,
- 0x51, 0x7d, 0xbb, 0xe6, 0x35, 0x62, 0xe9, 0x0d, 0x62, 0xb8, 0x6f, 0xf6,
- 0x49, 0xef, 0xfe, 0x90, 0x4f, 0xce, 0x4e, 0x6f, 0xd9, 0x62, 0xdb, 0x1a,
- 0xc5, 0xfd, 0xf9, 0x23, 0x1f, 0xb5, 0x8b, 0xff, 0x14, 0x53, 0x85, 0x1e,
- 0x77, 0xe5, 0x8a, 0x19, 0xf7, 0xb9, 0x7d, 0xff, 0x7e, 0x7a, 0x90, 0x39,
- 0x01, 0x62, 0xfe, 0x06, 0xdc, 0xe3, 0x92, 0xc5, 0xff, 0xc2, 0x92, 0x73,
- 0x62, 0x29, 0x07, 0x16, 0x28, 0x68, 0xad, 0x23, 0x9f, 0x17, 0xdf, 0x82,
- 0xa3, 0x62, 0xe9, 0x62, 0x98, 0xf7, 0x1c, 0xbe, 0xf8, 0xc7, 0x93, 0xac,
- 0x5f, 0x9f, 0x91, 0xb6, 0x96, 0x2f, 0xb4, 0xc2, 0x8d, 0x71, 0x7a, 0x97,
- 0xba, 0x14, 0x6b, 0x8b, 0xd4, 0xbf, 0xf6, 0x36, 0xfc, 0x2c, 0x1b, 0xc1,
- 0x71, 0x7a, 0x97, 0xe7, 0x2e, 0xe0, 0x10, 0x68, 0xa9, 0xe1, 0x89, 0x85,
- 0xb7, 0x3e, 0xea, 0xc5, 0x0d, 0x33, 0xc3, 0xc3, 0x48, 0x94, 0x2f, 0xc6,
- 0xf9, 0xdc, 0x96, 0x2f, 0x10, 0xa3, 0x58, 0xa7, 0x3c, 0x6f, 0x14, 0x53,
- 0x22, 0x70, 0x9e, 0xea, 0x57, 0x54, 0xc6, 0x5d, 0x8e, 0x0c, 0xc3, 0xa2,
- 0x43, 0xa2, 0x3c, 0x21, 0xb9, 0x19, 0x57, 0x88, 0x05, 0x1f, 0xdd, 0xfe,
- 0x27, 0x3f, 0xe7, 0x06, 0xb1, 0x76, 0xc5, 0xb0, 0x2c, 0x5e, 0x69, 0xd2,
- 0xc5, 0x6c, 0x66, 0xfb, 0xe4, 0x57, 0xff, 0x69, 0x8f, 0x3b, 0x85, 0x87,
- 0xee, 0x56, 0x2a, 0x07, 0xdb, 0x11, 0x35, 0xe2, 0x71, 0xac, 0x5e, 0xe4,
- 0x6e, 0xb1, 0x4c, 0x6e, 0x83, 0x1c, 0xbf, 0xde, 0x6d, 0x4f, 0x59, 0xbd,
- 0x62, 0xe3, 0xb2, 0xc5, 0xfd, 0x23, 0x6d, 0xf2, 0x35, 0x8b, 0xf7, 0xa4,
- 0xa6, 0x25, 0x8a, 0x94, 0x52, 0x46, 0x6c, 0x31, 0x77, 0x2f, 0xbf, 0x61,
- 0xf4, 0xfd, 0xac, 0x50, 0xd3, 0x2a, 0x28, 0x62, 0xf0, 0xf2, 0xfd, 0x0c,
- 0xdf, 0x30, 0x58, 0xbd, 0x9a, 0x95, 0x8b, 0xdb, 0xf0, 0x6b, 0x15, 0xd2,
- 0xaf, 0xee, 0xe1, 0xba, 0xd1, 0xc3, 0xe8, 0xd7, 0xe5, 0x42, 0x1c, 0xb1,
- 0x8b, 0x17, 0xf9, 0x8c, 0x96, 0x1e, 0x1d, 0x62, 0xcd, 0x87, 0x8d, 0x10,
- 0x9d, 0xe7, 0xd4, 0x6b, 0x14, 0xb1, 0x62, 0xe8, 0xd5, 0x44, 0x3d, 0x7f,
- 0x7d, 0xe2, 0xd4, 0xc6, 0xb1, 0x7f, 0x37, 0x7c, 0xfe, 0x74, 0xb1, 0x7d,
- 0xfc, 0x68, 0x96, 0x2f, 0xe9, 0xdf, 0x9f, 0xfc, 0xac, 0x5f, 0xb3, 0xdc,
- 0xc8, 0x96, 0x3e, 0x6b, 0xef, 0xff, 0xff, 0xb3, 0xbe, 0x36, 0x19, 0xb7,
- 0x3b, 0x87, 0x1b, 0xdc, 0x6e, 0xc6, 0x31, 0x46, 0xb1, 0x7f, 0xe9, 0xe8,
- 0xb2, 0x2f, 0x8b, 0x51, 0x2c, 0x53, 0x23, 0x1c, 0xa1, 0x0b, 0x7f, 0xfe,
- 0x62, 0x1e, 0xd0, 0xfc, 0xdc, 0x76, 0x21, 0x41, 0x62, 0xf9, 0xe3, 0xfb,
- 0x2c, 0x56, 0x2a, 0x7a, 0x62, 0x88, 0x8c, 0x34, 0x60, 0x4a, 0x5e, 0x8c,
- 0x03, 0x79, 0x36, 0xca, 0xbd, 0xe1, 0x6a, 0x0b, 0x17, 0xfe, 0x3b, 0x8f,
- 0x53, 0xef, 0xe0, 0xd6, 0x2f, 0xe7, 0xf0, 0x03, 0x28, 0x2c, 0x5f, 0xa3,
- 0xeb, 0xf3, 0xa5, 0x8b, 0xfc, 0xee, 0x60, 0x1f, 0xdc, 0x58, 0xb8, 0x3e,
- 0x2c, 0x50, 0xcf, 0x37, 0xe6, 0x97, 0xc2, 0x8a, 0x7b, 0x58, 0xbf, 0xf0,
- 0xe7, 0xcf, 0x0c, 0xde, 0xe3, 0x58, 0xbf, 0x34, 0x71, 0xb6, 0x96, 0x2f,
- 0xd2, 0x44, 0x23, 0xac, 0x5a, 0x1e, 0x3d, 0x10, 0xca, 0xab, 0x6a, 0xa0,
- 0x59, 0x1e, 0x8c, 0xff, 0x0b, 0xcd, 0x78, 0xe8, 0x88, 0xe4, 0xaf, 0x09,
- 0x1b, 0xf3, 0x04, 0x30, 0xc3, 0x12, 0x2f, 0xfc, 0x6b, 0xf7, 0xb7, 0xee,
- 0x76, 0xe2, 0xc5, 0xa6, 0x07, 0xe2, 0x72, 0xeb, 0xb3, 0xeb, 0x17, 0x60,
- 0x5d, 0x62, 0xec, 0x1a, 0xc5, 0xfb, 0xc0, 0x0c, 0xa0, 0xb1, 0x43, 0x3d,
- 0xc3, 0x46, 0xdc, 0x5e, 0xfc, 0xfa, 0xea, 0x7c, 0xb1, 0x73, 0x69, 0x62,
- 0xbe, 0x78, 0x02, 0x29, 0xb7, 0x4b, 0x17, 0x38, 0xd6, 0x2f, 0xed, 0x3f,
- 0x3e, 0xf0, 0x58, 0xb7, 0x6b, 0x17, 0x31, 0x8b, 0x17, 0x06, 0x05, 0x8a,
- 0x88, 0xd8, 0x80, 0x62, 0xf4, 0x1c, 0x6b, 0x17, 0x18, 0x62, 0xc5, 0x41,
- 0x1c, 0x58, 0x2f, 0xd1, 0x73, 0x22, 0x70, 0x88, 0xc1, 0xdb, 0x83, 0x02,
- 0x40, 0x43, 0xd7, 0xa7, 0x4d, 0xe3, 0xd1, 0xa6, 0x5f, 0xec, 0x3b, 0x0e,
- 0x31, 0x71, 0x62, 0xff, 0xfe, 0x06, 0xce, 0x6a, 0x7c, 0xdd, 0x30, 0xe3,
- 0x92, 0x95, 0x8b, 0xd9, 0xdf, 0x96, 0x2d, 0x84, 0x7f, 0x9c, 0x5e, 0xaf,
- 0xa3, 0x5f, 0x90, 0xb1, 0xbf, 0xe6, 0x1e, 0x1d, 0xa2, 0x63, 0x16, 0x2f,
- 0xff, 0xfa, 0x1f, 0x91, 0xcb, 0x76, 0x0d, 0x60, 0xe7, 0x4d, 0xd8, 0x16,
- 0x2f, 0xff, 0xfa, 0x7e, 0xed, 0xe9, 0x80, 0x87, 0x81, 0xe6, 0xbc, 0x2f,
- 0xac, 0x5f, 0xfe, 0x71, 0xe6, 0x11, 0xbc, 0xe6, 0x10, 0x16, 0x2f, 0xbe,
- 0x27, 0x36, 0x53, 0x52, 0xc3, 0xad, 0x34, 0x1d, 0x9e, 0xf1, 0x4f, 0xd6,
- 0x2f, 0xff, 0xe8, 0x3f, 0x39, 0x39, 0x18, 0xa0, 0x3d, 0x13, 0x98, 0xb1,
- 0x43, 0x46, 0x69, 0xaa, 0x8c, 0x39, 0x7f, 0x69, 0xe1, 0x3a, 0x02, 0xc5,
- 0xff, 0xfe, 0xfb, 0xc3, 0xf2, 0xfa, 0xe7, 0x33, 0xed, 0xc1, 0x46, 0xb1,
- 0x6c, 0xd2, 0x24, 0x3e, 0x5d, 0x7f, 0xfd, 0xa9, 0x78, 0x6a, 0x7e, 0xed,
- 0xd6, 0x12, 0xc5, 0x4a, 0x66, 0xd0, 0x86, 0x03, 0x14, 0x57, 0x15, 0xd8,
- 0xfa, 0x5b, 0xed, 0xe8, 0x6e, 0x41, 0x62, 0xf7, 0xdb, 0x8b, 0x15, 0x26,
- 0xfa, 0x04, 0x37, 0xfb, 0x39, 0x17, 0xd8, 0xcf, 0x2c, 0x5f, 0xa3, 0xcc,
- 0x23, 0x56, 0x2a, 0x4f, 0x7d, 0xcd, 0xaf, 0xe6, 0x3f, 0x58, 0x5d, 0x2c,
- 0x5f, 0x3c, 0x7c, 0xfa, 0xc5, 0x68, 0xf4, 0xf8, 0x5f, 0x5b, 0x59, 0x15,
- 0x70, 0x73, 0x1b, 0x7f, 0x71, 0xcd, 0x34, 0xe5, 0x89, 0x35, 0x71, 0xff,
- 0xce, 0x76, 0xd8, 0x96, 0x2f, 0x3b, 0x9d, 0x62, 0xf7, 0xdb, 0xcb, 0x16,
- 0xde, 0x15, 0x3d, 0x0f, 0x8b, 0x86, 0x39, 0x7f, 0x9c, 0xed, 0x27, 0xc2,
- 0x58, 0xbf, 0xbf, 0x3a, 0xf6, 0x74, 0xb1, 0x6c, 0x19, 0xf0, 0x78, 0xc6,
- 0xe3, 0x5d, 0x62, 0xfb, 0x08, 0x51, 0x2c, 0x5f, 0x36, 0xf9, 0x1a, 0xc5,
- 0xff, 0xfb, 0x8f, 0xee, 0x16, 0x72, 0x7b, 0x07, 0xb3, 0x8b, 0x15, 0xda,
- 0x27, 0x4e, 0x47, 0xe2, 0x4b, 0xb5, 0x12, 0xc5, 0xda, 0x95, 0x8a, 0x93,
- 0x61, 0x83, 0x35, 0x2d, 0x94, 0x04, 0x21, 0x57, 0x92, 0xb2, 0xda, 0x54,
- 0x0f, 0xe1, 0xd6, 0xf4, 0x8d, 0x20, 0x43, 0x50, 0xa1, 0x39, 0xe2, 0x71,
- 0x42, 0xd7, 0x65, 0x86, 0xff, 0xff, 0xff, 0xff, 0x6c, 0xe1, 0xde, 0x0d,
- 0xc0, 0x60, 0x3e, 0xed, 0x09, 0x1f, 0xc4, 0x6c, 0xb1, 0x3f, 0xa6, 0x0f,
- 0xbf, 0xef, 0x05, 0x8b, 0xf7, 0xdb, 0x7e, 0x46, 0xb1, 0x4c, 0x8e, 0x9e,
- 0x42, 0xfa, 0xff, 0xbe, 0x2f, 0x7f, 0x34, 0xdc, 0x58, 0xbd, 0xc7, 0x89,
- 0x62, 0xff, 0xc3, 0x92, 0x88, 0x5f, 0x7f, 0xca, 0xc5, 0xf1, 0xe7, 0xb8,
- 0x2c, 0x5f, 0xfb, 0x37, 0xc8, 0xcb, 0x3d, 0x80, 0x58, 0xbb, 0x09, 0x62,
- 0xd9, 0xd9, 0xea, 0xef, 0x3f, 0xbf, 0x7f, 0xd3, 0x03, 0xac, 0x5c, 0x18,
- 0x16, 0x29, 0x91, 0xcb, 0xa7, 0x9f, 0x95, 0x00, 0xa6, 0xf3, 0x10, 0xd6,
- 0x2f, 0xfe, 0x61, 0xbf, 0x9b, 0x99, 0x0c, 0xfa, 0xc5, 0xcf, 0xba, 0xb1,
- 0x7b, 0x3b, 0xf2, 0xc5, 0x7c, 0xfe, 0xfc, 0x87, 0xba, 0x35, 0x7f, 0x66,
- 0xa7, 0xdc, 0xc5, 0x8b, 0xff, 0xe7, 0xee, 0x13, 0x0c, 0x1f, 0x26, 0x12,
- 0x4b, 0x15, 0x88, 0xae, 0x63, 0x22, 0x2d, 0xbf, 0xb8, 0xff, 0x69, 0x02,
- 0xc5, 0xf8, 0xbd, 0xcc, 0x25, 0x8b, 0xff, 0x06, 0x50, 0x2c, 0xf7, 0xb2,
- 0x35, 0x8a, 0x63, 0xe7, 0x01, 0x3d, 0xfb, 0x4f, 0xbf, 0x75, 0xd6, 0x2a,
- 0x0b, 0x86, 0x63, 0x27, 0xec, 0xe9, 0x87, 0xb5, 0x19, 0x27, 0xcf, 0x0a,
- 0x34, 0x5e, 0x16, 0xfa, 0x12, 0x9b, 0xc8, 0x6f, 0xdb, 0x16, 0xc6, 0x14,
- 0xd9, 0xf2, 0xc5, 0xfe, 0x8f, 0xc7, 0xfe, 0x01, 0xd6, 0x2f, 0xb0, 0x98,
- 0xd5, 0x8a, 0x82, 0x24, 0x8e, 0x77, 0xbc, 0xd6, 0xee, 0xb7, 0x56, 0x2f,
- 0x72, 0x1f, 0x58, 0xa2, 0x37, 0x5e, 0x1c, 0xbf, 0xff, 0x70, 0x9f, 0x9f,
- 0xc8, 0x67, 0xdb, 0x5f, 0x75, 0x8b, 0xfe, 0x63, 0x4b, 0x3f, 0xf9, 0xf2,
- 0xc5, 0x76, 0x88, 0xdd, 0x2a, 0x5f, 0x67, 0x71, 0xef, 0x58, 0xbe, 0xcf,
- 0x44, 0x75, 0x8b, 0xfd, 0xc1, 0xb9, 0xe7, 0xdd, 0x2c, 0x5f, 0xe1, 0xe1,
- 0x0a, 0x19, 0xc5, 0x8a, 0xec, 0xfa, 0x08, 0xd6, 0xfb, 0xbe, 0x08, 0x0b,
- 0x17, 0x17, 0x4b, 0x15, 0x26, 0xf5, 0xc9, 0x6f, 0xf0, 0x7e, 0x2c, 0x8d,
- 0xb4, 0xb1, 0x7a, 0x58, 0x6b, 0x17, 0xe2, 0xe8, 0xd1, 0xf6, 0xb1, 0x7c,
- 0xfb, 0xb8, 0x4b, 0x17, 0x9b, 0x8c, 0xb1, 0x4e, 0x7d, 0x9c, 0x2c, 0xf1,
- 0x25, 0xfd, 0x9d, 0x4f, 0xe4, 0xeb, 0x15, 0x2a, 0xe1, 0xf1, 0xb1, 0xa1,
- 0x5b, 0xa2, 0x43, 0x93, 0xbc, 0x23, 0x00, 0xbe, 0x43, 0xfc, 0x35, 0x14,
- 0x22, 0x0c, 0x2e, 0xbf, 0xf4, 0x86, 0x01, 0x42, 0x0f, 0xf1, 0x2c, 0x5e,
- 0xcc, 0x35, 0x62, 0xfa, 0x12, 0x0e, 0x2c, 0x50, 0xcf, 0x03, 0x07, 0x6a,
- 0x34, 0x51, 0x77, 0x08, 0x1b, 0xef, 0x09, 0xc9, 0x62, 0xfb, 0x5a, 0x98,
- 0x2c, 0x5f, 0xe6, 0x1b, 0x05, 0xe4, 0x99, 0x62, 0xb0, 0xf6, 0x3e, 0x47,
- 0x7f, 0xfc, 0xc6, 0xe3, 0x1f, 0x52, 0x20, 0xbb, 0xff, 0x8b, 0x17, 0xf9,
- 0xe1, 0x83, 0xd7, 0x38, 0xb1, 0x7d, 0x38, 0x18, 0xd6, 0x2f, 0xff, 0xe8,
- 0x14, 0xe7, 0x30, 0xbd, 0xfc, 0x18, 0xbd, 0xc5, 0x8b, 0xf7, 0x3f, 0xf9,
- 0x25, 0x8b, 0xf9, 0xbc, 0xff, 0x33, 0x71, 0x62, 0xb0, 0xf6, 0x8d, 0x28,
- 0xbf, 0xa6, 0x3d, 0x9c, 0xd4, 0xac, 0x5f, 0xec, 0x8b, 0xf9, 0xc7, 0x25,
- 0x8b, 0xc0, 0x6f, 0xac, 0x5f, 0xf8, 0x79, 0xdc, 0x39, 0xee, 0x38, 0x16,
- 0x2b, 0x48, 0x91, 0x01, 0x98, 0x87, 0x6f, 0xf0, 0xb9, 0xf7, 0x84, 0x3e,
- 0xb1, 0x7d, 0xce, 0x61, 0x8b, 0x17, 0xf8, 0xc1, 0xff, 0x37, 0xe6, 0x96,
- 0x2f, 0xfe, 0x63, 0xed, 0xeb, 0xed, 0xfe, 0x9b, 0x8b, 0x17, 0xfb, 0x21,
- 0x82, 0x0b, 0xb9, 0x2c, 0x5f, 0xfd, 0x30, 0xfc, 0xf7, 0xe9, 0xfb, 0xee,
- 0x2c, 0x54, 0xa3, 0xfb, 0x46, 0xff, 0x49, 0x23, 0x6b, 0xff, 0xfc, 0xc5,
- 0x9d, 0xf8, 0xd7, 0xf7, 0xe7, 0xf9, 0xbd, 0xe0, 0xb1, 0x7b, 0x30, 0x96,
- 0x2a, 0x35, 0xc8, 0x31, 0xaa, 0x74, 0x69, 0xd9, 0x1b, 0x42, 0xd2, 0x22,
- 0x2d, 0x43, 0x08, 0xe6, 0x1f, 0x35, 0xf4, 0x64, 0x5b, 0xce, 0xf7, 0x58,
- 0xef, 0xc7, 0xf1, 0x64, 0x16, 0x2f, 0xfa, 0x75, 0xc2, 0xc3, 0xcf, 0x4b,
- 0x17, 0x14, 0xac, 0x5f, 0xb9, 0xf9, 0x33, 0x8b, 0x17, 0xf1, 0xbd, 0xfb,
- 0xed, 0xf5, 0x8a, 0x19, 0xed, 0xe8, 0xaa, 0xff, 0x86, 0xda, 0x9d, 0xe0,
- 0xe4, 0x16, 0x2e, 0x93, 0xac, 0x54, 0x9e, 0x9f, 0xcf, 0x2b, 0xe9, 0x83,
- 0xbb, 0x8f, 0x9d, 0x6f, 0xfb, 0x8f, 0xf6, 0x1f, 0x4d, 0x1a, 0xc5, 0xfe,
- 0x78, 0x60, 0xf9, 0xc9, 0x58, 0xbf, 0xbd, 0xf9, 0x3c, 0x44, 0xb1, 0x52,
- 0x89, 0xdc, 0x3b, 0x01, 0x9d, 0x05, 0x19, 0x08, 0x32, 0xf5, 0x93, 0x94,
- 0x9d, 0x43, 0x01, 0x8a, 0x1e, 0x34, 0x01, 0x43, 0x36, 0xe2, 0xf2, 0xc5,
- 0xe1, 0x6a, 0x35, 0x8b, 0xdd, 0x0a, 0x56, 0x2f, 0x18, 0xff, 0x58, 0xa9,
- 0x3f, 0x28, 0x0b, 0xb0, 0xfe, 0x87, 0xaf, 0xb0, 0x5a, 0x8d, 0x62, 0xff,
- 0xdb, 0xdb, 0xc0, 0x11, 0x71, 0x86, 0xb1, 0x7e, 0xce, 0x7c, 0x51, 0xac,
- 0x5b, 0x5b, 0x51, 0x1f, 0x84, 0x9f, 0x41, 0xbf, 0xff, 0xcf, 0x00, 0xe1,
- 0xfc, 0x10, 0x5f, 0x08, 0xd2, 0x2c, 0x89, 0x62, 0xa5, 0x13, 0xa7, 0x37,
- 0xbf, 0xed, 0xa3, 0x27, 0x34, 0xd7, 0x31, 0x62, 0xfc, 0xda, 0x84, 0x52,
- 0xb1, 0x7f, 0xf7, 0xf0, 0x9c, 0xdf, 0xb7, 0xa0, 0xcb, 0x15, 0xf3, 0xed,
- 0xe1, 0x4d, 0x62, 0x33, 0x5a, 0x15, 0x77, 0x6c, 0xb2, 0xc5, 0xff, 0xf0,
- 0xba, 0x0f, 0xb0, 0x3f, 0x1f, 0x4d, 0xd8, 0x16, 0x2f, 0xd3, 0xf2, 0xc3,
- 0x56, 0x29, 0x8f, 0xf7, 0xea, 0xb7, 0xe9, 0x8b, 0xed, 0xa5, 0x8b, 0xf8,
- 0x5e, 0xe4, 0x82, 0x35, 0x8b, 0xff, 0xd8, 0x39, 0x84, 0xf3, 0x99, 0x08,
- 0x4a, 0xc5, 0xf3, 0xea, 0x60, 0xb1, 0x7f, 0xff, 0x31, 0x3b, 0x10, 0x35,
- 0x3f, 0x76, 0xf4, 0xfd, 0x62, 0x86, 0x8f, 0x23, 0x98, 0x12, 0x4f, 0x88,
- 0xaf, 0xbd, 0xc1, 0x46, 0xb1, 0x7f, 0xff, 0xdd, 0xea, 0x45, 0xe1, 0x1f,
- 0x4e, 0xe0, 0x2c, 0xde, 0xda, 0x58, 0xa6, 0x44, 0x73, 0x92, 0xdf, 0xfa,
- 0x01, 0x8d, 0xe3, 0xc3, 0xbf, 0x16, 0x2f, 0xfa, 0x13, 0xf9, 0xf7, 0xdc,
- 0xeb, 0x15, 0x27, 0xf4, 0x24, 0x1b, 0xff, 0xc4, 0xc0, 0xf7, 0x7d, 0x36,
- 0x83, 0x91, 0xac, 0x5f, 0xf7, 0xc3, 0x18, 0xbd, 0xc0, 0x4a, 0xc5, 0x4a,
- 0x22, 0x5d, 0x36, 0x86, 0xad, 0xb3, 0xa2, 0x16, 0x8c, 0x6c, 0xf0, 0xca,
- 0x28, 0x4d, 0xfa, 0x15, 0x57, 0xbe, 0xdf, 0x58, 0xbf, 0xfe, 0x01, 0xf0,
- 0xf8, 0x4e, 0x79, 0x80, 0x7c, 0x58, 0xb8, 0x72, 0xb1, 0x7e, 0x03, 0xb0,
- 0xd9, 0x62, 0xa4, 0xdf, 0x38, 0xbd, 0xf3, 0x9f, 0x8e, 0xb1, 0x7a, 0x4f,
- 0x2b, 0x17, 0xf9, 0xdb, 0xa2, 0x7c, 0xe9, 0x62, 0xfd, 0x3e, 0xfb, 0xc4,
- 0xb1, 0xc3, 0x67, 0x5d, 0xa6, 0xaf, 0xa8, 0x47, 0x70, 0x7f, 0x79, 0x16,
- 0xca, 0x7d, 0xfb, 0x42, 0xeb, 0xf2, 0xb1, 0x7f, 0x6a, 0x28, 0x37, 0xb8,
- 0xb1, 0x62, 0x93, 0xda, 0xc2, 0xab, 0xec, 0xd4, 0xf1, 0x62, 0xff, 0x44,
- 0xf1, 0x3f, 0x70, 0xe2, 0xc5, 0xfc, 0xf1, 0xb4, 0x4c, 0x62, 0xc5, 0xff,
- 0xfe, 0x73, 0x3d, 0x9f, 0xda, 0x3c, 0x8a, 0x0f, 0xa8, 0xfe, 0x25, 0x8a,
- 0x94, 0x78, 0x61, 0x13, 0x9b, 0x91, 0x85, 0xfb, 0x0a, 0x3c, 0x31, 0x62,
- 0xfc, 0xe7, 0xfb, 0x18, 0xb1, 0x51, 0x9e, 0x90, 0xca, 0x6f, 0xfe, 0x9f,
- 0x61, 0x31, 0xa0, 0x3c, 0xc1, 0x62, 0xff, 0xa6, 0x30, 0xe1, 0xf1, 0x3c,
- 0x6b, 0x17, 0xf9, 0xfd, 0xce, 0xba, 0x6e, 0xd6, 0x2f, 0xf9, 0xba, 0xc8,
- 0x9c, 0xa3, 0x0a, 0xac, 0x56, 0x26, 0x34, 0xc4, 0x7a, 0x44, 0x73, 0xd2,
- 0x37, 0xb6, 0xc6, 0xb1, 0x7e, 0x9d, 0x6b, 0x3e, 0xb1, 0x7f, 0xf4, 0xe1,
- 0x7e, 0x58, 0x0f, 0xe1, 0x2c, 0x5e, 0x78, 0x79, 0x62, 0xff, 0xfa, 0x4d,
- 0x33, 0x1b, 0x79, 0x8e, 0x39, 0xc3, 0xac, 0x5f, 0xc4, 0xe6, 0xc9, 0xe5,
- 0x62, 0x82, 0xa9, 0x8f, 0x40, 0x5f, 0x45, 0x07, 0x42, 0x21, 0xd1, 0x29,
- 0xdc, 0x69, 0xab, 0x17, 0xf1, 0x3f, 0x58, 0x5d, 0x2c, 0x54, 0x67, 0x90,
- 0xc3, 0x57, 0x82, 0xcd, 0xc0, 0x2c, 0x5b, 0x71, 0x62, 0xfe, 0xe3, 0xb8,
- 0x6e, 0x1a, 0xc5, 0xf4, 0x04, 0x30, 0x9b, 0x01, 0xf5, 0x1a, 0x4d, 0xe1,
- 0x5b, 0xf8, 0xef, 0xde, 0xc5, 0x9f, 0x58, 0xbc, 0x63, 0xf1, 0x62, 0xfe,
- 0x3c, 0xe1, 0x7b, 0x8b, 0x17, 0xe9, 0x8f, 0x20, 0xcb, 0x17, 0x83, 0x18,
- 0x4c, 0x45, 0x3f, 0xcd, 0x38, 0x3d, 0xe2, 0xda, 0x89, 0x34, 0x7f, 0xc3,
- 0xda, 0xfb, 0xff, 0xce, 0xd6, 0x2f, 0xe7, 0x1c, 0x94, 0x81, 0x62, 0xf9,
- 0xb9, 0x83, 0x93, 0xd0, 0xd9, 0x24, 0xbf, 0x3f, 0x3d, 0x9f, 0x58, 0xbf,
- 0xf0, 0x86, 0xe4, 0x0f, 0x37, 0x7c, 0x58, 0xbf, 0xff, 0xda, 0x7e, 0x07,
- 0xe2, 0xcd, 0xee, 0x01, 0xe8, 0x9c, 0xc5, 0x8b, 0x7a, 0x08, 0xa4, 0x12,
- 0x05, 0xef, 0xb8, 0xd6, 0x2f, 0xf9, 0xa4, 0xfb, 0x70, 0x6d, 0xbd, 0x62,
- 0x99, 0x10, 0x5f, 0x29, 0xe0, 0xed, 0xf6, 0xdf, 0x31, 0xd6, 0x2a, 0x57,
- 0x0a, 0x47, 0x1e, 0x9f, 0x4f, 0x4c, 0x74, 0xf1, 0xa7, 0x08, 0xbe, 0xff,
- 0xfc, 0xdd, 0x49, 0xf8, 0xfa, 0xc3, 0x8b, 0xa7, 0x82, 0xc5, 0xff, 0x3e,
- 0x9f, 0xcd, 0xa7, 0x02, 0xc5, 0xcd, 0xbd, 0x62, 0xff, 0x49, 0x3f, 0xc4,
- 0x51, 0xac, 0x5f, 0xf9, 0x8d, 0x91, 0xb1, 0x3e, 0x8d, 0x58, 0xbf, 0xfd,
- 0x9d, 0xfb, 0xbf, 0x31, 0x98, 0x37, 0x82, 0xc5, 0x62, 0x23, 0x00, 0x7f,
- 0x6f, 0xac, 0x5f, 0xcd, 0xa0, 0x1d, 0xb8, 0xb1, 0x50, 0x4f, 0x27, 0xa5,
- 0x7d, 0xc3, 0x83, 0x8c, 0x94, 0x2f, 0xc4, 0x45, 0xb2, 0x25, 0x78, 0xfc,
- 0x25, 0x8b, 0xff, 0xff, 0xbb, 0xe6, 0x41, 0xbd, 0xfc, 0x20, 0x02, 0x7e,
- 0x58, 0x37, 0x3a, 0xc5, 0x4a, 0x23, 0x98, 0x76, 0xf0, 0xe4, 0xeb, 0x17,
- 0xf0, 0x32, 0x29, 0xef, 0x8b, 0x17, 0xfe, 0xfe, 0x17, 0x5b, 0x70, 0x6d,
- 0xbd, 0x62, 0xff, 0xff, 0x13, 0x99, 0xfc, 0x3b, 0x99, 0xee, 0x61, 0x83,
- 0x63, 0xac, 0x5e, 0xfe, 0x44, 0xb1, 0x7f, 0xc2, 0xd3, 0xbc, 0x3d, 0x9f,
- 0x58, 0xbf, 0x03, 0xb8, 0x4e, 0xea, 0xc5, 0xfd, 0x9a, 0xc8, 0xa4, 0xd5,
- 0x8a, 0xc3, 0xdc, 0xf1, 0x6d, 0xff, 0xff, 0xdc, 0xfc, 0xfe, 0x5b, 0xb0,
- 0x6b, 0x07, 0x3e, 0xe3, 0x17, 0x70, 0x58, 0xac, 0x54, 0x3a, 0xc6, 0x11,
- 0x21, 0xfd, 0x8f, 0x83, 0xde, 0x84, 0xa9, 0x84, 0x37, 0x86, 0xc7, 0x58,
- 0xbf, 0xf1, 0x13, 0x1f, 0x6b, 0x00, 0x30, 0x2c, 0x5f, 0xe3, 0x4b, 0x23,
- 0x8c, 0x44, 0xb1, 0x52, 0xac, 0xe7, 0x25, 0x1d, 0x33, 0x5b, 0x8e, 0x89,
- 0x06, 0xfe, 0xfb, 0xc2, 0x79, 0x05, 0x8b, 0xfe, 0xcf, 0xb7, 0x7c, 0xf8,
- 0xb8, 0xb1, 0x76, 0x17, 0x47, 0xd2, 0x02, 0xeb, 0xff, 0xf8, 0x4f, 0xb9,
- 0xb7, 0x64, 0x53, 0xb7, 0x38, 0x42, 0x78, 0xd6, 0x2f, 0xb8, 0xed, 0x1a,
- 0xc5, 0xee, 0x47, 0x2b, 0x15, 0x19, 0xe0, 0xe1, 0x1d, 0xff, 0xfd, 0xec,
- 0xdf, 0xb7, 0x64, 0x53, 0xb7, 0x38, 0x42, 0x78, 0xd6, 0x2f, 0xfa, 0x13,
- 0xef, 0x4b, 0x9e, 0x35, 0x8a, 0xc4, 0x4f, 0xf6, 0xcb, 0x7f, 0xfb, 0x3e,
- 0xee, 0x72, 0x7d, 0x34, 0xf1, 0x62, 0xd8, 0x73, 0xea, 0xde, 0x47, 0x7e,
- 0x8f, 0x76, 0x7b, 0xe2, 0xc5, 0xf9, 0xc0, 0x3c, 0x25, 0x8a, 0xc5, 0x4a,
- 0x0d, 0x0a, 0x7f, 0xc6, 0x56, 0xe5, 0x24, 0x5d, 0x68, 0x96, 0x2f, 0x61,
- 0x1a, 0xb1, 0x52, 0x6c, 0x30, 0x4e, 0xff, 0x75, 0x30, 0xf7, 0xdc, 0x6b,
- 0x17, 0xe6, 0xd9, 0xcd, 0x1a, 0xb1, 0x7d, 0xbc, 0xb3, 0x8b, 0x17, 0xf1,
- 0x39, 0xa5, 0x80, 0x58, 0xa6, 0x3d, 0x13, 0x92, 0x5f, 0xfd, 0x90, 0xf6,
- 0x7c, 0xb3, 0xdf, 0x65, 0x8b, 0x4a, 0xc5, 0x7c, 0xf5, 0x1d, 0x0e, 0xf0,
- 0x03, 0x02, 0xc5, 0xa0, 0xb1, 0x7d, 0x3e, 0xe6, 0xd6, 0x36, 0x3e, 0x1f,
- 0xb8, 0xd8, 0x2c, 0x5f, 0xbe, 0xdb, 0xdb, 0xa5, 0x8b, 0xb3, 0xf0, 0x3c,
- 0x4e, 0x86, 0x6a, 0x35, 0x48, 0x78, 0x3e, 0x73, 0x57, 0x7d, 0xe3, 0xaf,
- 0x94, 0xb6, 0x5f, 0x6f, 0x18, 0x61, 0x89, 0x17, 0xfe, 0xd1, 0x09, 0xc3,
- 0xc8, 0xa4, 0xeb, 0x01, 0x0d, 0x0d, 0xe8, 0x98, 0xc5, 0x8b, 0xdf, 0x10,
- 0x16, 0x2d, 0xf6, 0x37, 0xb1, 0x0f, 0xdb, 0xa5, 0x8a, 0x94, 0x64, 0xe4,
- 0x23, 0xf4, 0x4f, 0x7f, 0xa4, 0x79, 0x09, 0x2e, 0x96, 0x2a, 0x5d, 0x01,
- 0x94, 0x71, 0xb3, 0x42, 0x1d, 0xe3, 0x26, 0xc9, 0xc0, 0x3e, 0xdb, 0x5a,
- 0x37, 0x4d, 0xc8, 0x58, 0x45, 0x18, 0xae, 0xa3, 0xa5, 0x3c, 0x6c, 0xbf,
- 0x9c, 0xcc, 0x79, 0x45, 0xa0, 0x87, 0xf1, 0x4b, 0x5a, 0xe4, 0x2e, 0x3d,
- 0x29, 0xf4, 0x52, 0xb1, 0x8c, 0x8d, 0x48, 0x33, 0x3b, 0xe6, 0xd3, 0x81,
- 0x62, 0xff, 0x0f, 0xf3, 0x19, 0x67, 0x6b, 0x17, 0x87, 0xf9, 0x58, 0xa3,
- 0x9f, 0xa0, 0x08, 0xb8, 0x6b, 0x7d, 0xad, 0x67, 0xd6, 0x2f, 0xef, 0xb6,
- 0xee, 0xe8, 0x8d, 0x58, 0xa9, 0x3d, 0x9e, 0x88, 0xec, 0x17, 0x58, 0xb8,
- 0xb8, 0xb1, 0x66, 0x58, 0xbf, 0xb5, 0xcf, 0xc9, 0x79, 0x62, 0xe9, 0x02,
- 0xc5, 0xbd, 0x27, 0x8b, 0xc2, 0xeb, 0xff, 0xda, 0x8c, 0x3f, 0x37, 0xc4,
- 0x73, 0xbc, 0x16, 0x2c, 0x17, 0x58, 0xbf, 0xef, 0x4e, 0xb9, 0xf9, 0x2f,
- 0x2c, 0x5d, 0xc9, 0x58, 0xbc, 0x71, 0xca, 0xc5, 0xfe, 0x2f, 0x3c, 0x5c,
- 0x9f, 0x2c, 0x53, 0x1e, 0x8b, 0x8e, 0xdf, 0x33, 0xe7, 0x4b, 0x17, 0xfe,
- 0xcd, 0xe5, 0x9c, 0x88, 0xa4, 0x6b, 0x17, 0xdd, 0x0e, 0x63, 0x58, 0xb8,
- 0x12, 0xb1, 0x7b, 0x8d, 0xa5, 0x8a, 0xc3, 0xd9, 0x01, 0x2f, 0x85, 0xef,
- 0xf4, 0x30, 0x98, 0x78, 0x4b, 0x17, 0x70, 0x24, 0xa7, 0xe3, 0x82, 0xd1,
- 0x1c, 0xfd, 0xa0, 0x04, 0x04, 0x45, 0xc8, 0x4c, 0xf8, 0xba, 0x9d, 0x56,
- 0x17, 0xa5, 0x1f, 0xdf, 0x76, 0x37, 0x8d, 0x62, 0xee, 0x4a, 0xc5, 0xe3,
- 0x8e, 0x56, 0x2f, 0xf1, 0x79, 0xe2, 0xe4, 0xf9, 0x62, 0x98, 0xf4, 0x5c,
- 0x76, 0xf9, 0x9f, 0x3a, 0x58, 0xbf, 0xf6, 0x6f, 0x2c, 0xe4, 0x45, 0x23,
- 0x58, 0xbe, 0xe8, 0x73, 0x1a, 0xc5, 0xfd, 0x10, 0x1b, 0x71, 0xe2, 0x58,
- 0xbc, 0xc0, 0xe2, 0xc5, 0xc0, 0x95, 0x8b, 0xdc, 0x6d, 0x2c, 0x5d, 0x91,
- 0x2c, 0x56, 0x23, 0x07, 0xa2, 0x5f, 0x99, 0x80, 0x77, 0xc2, 0xe1, 0x8e,
- 0xdf, 0xd8, 0x4c, 0x3c, 0x25, 0x8b, 0xf6, 0x11, 0x3f, 0x96, 0x2f, 0xd1,
- 0xfb, 0x30, 0xeb, 0x15, 0x03, 0xfa, 0xf9, 0x5b, 0x93, 0x5f, 0xc4, 0xe3,
- 0xc3, 0x42, 0x4a, 0xf3, 0x3c, 0x05, 0x86, 0x2f, 0x8a, 0xdd, 0x4a, 0xe9,
- 0x62, 0xb8, 0x89, 0x7e, 0xd0, 0x02, 0x02, 0x22, 0xe4, 0x60, 0x3e, 0x86,
- 0x95, 0xff, 0xda, 0x9e, 0xf8, 0x52, 0x7c, 0xef, 0xcb, 0x17, 0xff, 0xe7,
- 0x1e, 0x61, 0x1a, 0x19, 0x49, 0x46, 0xda, 0x58, 0xbc, 0xfa, 0x8d, 0x72,
- 0x09, 0x17, 0xd0, 0xce, 0xe0, 0xb9, 0x04, 0x8b, 0xdc, 0x61, 0xae, 0x41,
- 0x22, 0xe3, 0x0c, 0x5c, 0x82, 0x45, 0x74, 0x8a, 0xd8, 0x8a, 0xfc, 0x62,
- 0x61, 0x55, 0xcf, 0xe4, 0xc8, 0x24, 0x02, 0x1e, 0x05, 0xff, 0xff, 0xc3,
- 0x29, 0x1f, 0xe7, 0xdc, 0x9f, 0x48, 0xe7, 0xd8, 0x70, 0x18, 0xb1, 0x7f,
- 0x67, 0xf3, 0x08, 0xd5, 0x8b, 0xce, 0x40, 0xda, 0xc9, 0xc4, 0x99, 0xe8,
- 0x9d, 0x43, 0x70, 0xe8, 0xc5, 0x1a, 0x17, 0x0e, 0x3c, 0xe5, 0x7e, 0xfb,
- 0xc2, 0x60, 0xb1, 0x7d, 0xb3, 0x8f, 0xf5, 0x8a, 0xdc, 0x46, 0xc7, 0xe1,
- 0x16, 0x02, 0x8b, 0xfd, 0x11, 0x93, 0xd8, 0xe7, 0x8b, 0x15, 0x87, 0xde,
- 0xc7, 0x16, 0x82, 0xc5, 0xfd, 0x01, 0x47, 0xe6, 0x8d, 0x22, 0xfb, 0x40,
- 0x6f, 0x2c, 0x5e, 0xdf, 0x3c, 0x58, 0xbe, 0x71, 0xff, 0x16, 0x2f, 0x0d,
- 0x8e, 0xb1, 0x7f, 0xef, 0xcf, 0x98, 0xa4, 0xf3, 0xc5, 0x8b, 0x6e, 0x2c,
- 0x54, 0xa3, 0x4f, 0x08, 0xcd, 0x1f, 0x72, 0x2e, 0x0e, 0xee, 0x9e, 0xd4,
- 0x49, 0xae, 0x7e, 0x30, 0x4b, 0xfe, 0x92, 0x81, 0x48, 0x1c, 0xeb, 0x17,
- 0xf7, 0x4d, 0xcf, 0x67, 0xd6, 0x2f, 0xcd, 0xed, 0x08, 0xeb, 0x17, 0xd3,
- 0xf1, 0x69, 0x62, 0xf7, 0xdf, 0xcb, 0x15, 0x19, 0xf4, 0xc4, 0x53, 0xc2,
- 0x3b, 0xa7, 0xeb, 0x16, 0x95, 0x8f, 0x16, 0xf7, 0xf9, 0xa0, 0x27, 0xe7,
- 0xd9, 0x62, 0xfe, 0xcd, 0xee, 0x7c, 0xfa, 0xc5, 0xa0, 0x91, 0x79, 0xf5,
- 0x1a, 0x45, 0x24, 0x54, 0x9b, 0xce, 0x84, 0x8e, 0x3d, 0x7a, 0x41, 0xd2,
- 0x40, 0x43, 0x5d, 0x7f, 0xf7, 0xde, 0x05, 0x9c, 0x11, 0xa7, 0x31, 0x62,
- 0x8e, 0x98, 0x81, 0x42, 0x67, 0xc6, 0x17, 0x8a, 0x1f, 0x58, 0xbd, 0xdc,
- 0x38, 0xb1, 0x52, 0x9d, 0xa6, 0x46, 0x86, 0x73, 0x57, 0x1d, 0xbf, 0x61,
- 0x46, 0xda, 0x58, 0xb6, 0xca, 0xc5, 0x9e, 0x33, 0x7a, 0x45, 0x17, 0xed,
- 0x00, 0xed, 0xc5, 0x8b, 0xf8, 0x32, 0x87, 0x3e, 0x35, 0x8c, 0x35, 0x37,
- 0xf7, 0xb8, 0x07, 0x7d, 0x2c, 0x5f, 0x4f, 0x4d, 0xc5, 0x8b, 0xe1, 0x3e,
- 0xa0, 0xb1, 0x63, 0xac, 0x5a, 0x03, 0x36, 0xb1, 0x11, 0xdf, 0xff, 0xff,
- 0xe0, 0x00, 0x5c, 0x7f, 0x7a, 0x19, 0xff, 0xbc, 0x36, 0x73, 0x9c, 0x17,
- 0x3d, 0xcc, 0x31, 0x62, 0xa5, 0x34, 0x38, 0xcb, 0xb1, 0x61, 0xca, 0x2f,
- 0xfe, 0xce, 0xfd, 0xc6, 0x29, 0x03, 0x9d, 0x62, 0xf4, 0x27, 0xb5, 0x8b,
- 0xb0, 0x6b, 0x17, 0xd9, 0x13, 0x1d, 0x62, 0xa3, 0x44, 0xe4, 0x48, 0x9e,
- 0x1e, 0x30, 0x5e, 0xfd, 0x31, 0x42, 0x40, 0x91, 0x71, 0x01, 0x62, 0xf7,
- 0xc5, 0xb8, 0xb1, 0x7f, 0x79, 0xb4, 0xd1, 0xca, 0xc5, 0x61, 0xf3, 0x74,
- 0x2e, 0x19, 0x0d, 0xff, 0xfb, 0xf8, 0xd0, 0xe6, 0xdf, 0x7f, 0x06, 0x2f,
- 0x71, 0x62, 0xba, 0x4c, 0x63, 0x50, 0x8f, 0xf1, 0x85, 0xff, 0x01, 0xcb,
- 0xd1, 0x66, 0xb1, 0x62, 0xff, 0xde, 0xfe, 0x0c, 0x5e, 0xe4, 0x52, 0xb1,
- 0x66, 0x58, 0xbf, 0xe8, 0xc5, 0x01, 0xfc, 0x4e, 0x4b, 0x17, 0xf3, 0x49,
- 0xe3, 0xc3, 0x16, 0x2f, 0xd9, 0x19, 0xf0, 0xeb, 0x17, 0xb8, 0xda, 0x58,
- 0xa2, 0x3c, 0x6f, 0x14, 0xdf, 0xc4, 0xe0, 0x00, 0xb8, 0xb1, 0x7a, 0x4e,
- 0x10, 0x69, 0x88, 0x60, 0x8e, 0x8e, 0xf8, 0xeb, 0xe2, 0x1b, 0x98, 0xde,
- 0x27, 0x5c, 0x1c, 0x6a, 0x35, 0x8a, 0xeb, 0x5a, 0x35, 0x87, 0x37, 0x28,
- 0xf9, 0xef, 0xf8, 0x0c, 0x5e, 0xef, 0x8f, 0xb8, 0xb1, 0x7e, 0xfe, 0x47,
- 0xee, 0x2c, 0x56, 0x8f, 0x9f, 0xe7, 0xb7, 0xda, 0x9e, 0xf8, 0xb1, 0x7b,
- 0x23, 0x12, 0xc5, 0x61, 0xf2, 0x39, 0x11, 0x12, 0x5f, 0xef, 0x6d, 0x2c,
- 0x00, 0x7d, 0xac, 0x5f, 0xee, 0x16, 0x45, 0x09, 0xed, 0x62, 0xb0, 0xfb,
- 0x7c, 0x71, 0x52, 0xdc, 0x6b, 0xc2, 0x97, 0x26, 0x32, 0x0c, 0x8d, 0xb8,
- 0xd2, 0xbe, 0xcd, 0xda, 0x13, 0x1a, 0x48, 0xfc, 0x7a, 0x8e, 0xfc, 0x04,
- 0xf2, 0x8e, 0x0b, 0x93, 0x90, 0xbe, 0x8c, 0x4b, 0x66, 0x13, 0x37, 0xff,
- 0xe8, 0xf5, 0xac, 0x1b, 0x9f, 0xef, 0xe2, 0x98, 0x96, 0x2f, 0xff, 0xff,
- 0x0b, 0x42, 0x88, 0x9c, 0x1c, 0xe6, 0x1b, 0x82, 0xd3, 0x8e, 0x7f, 0x2b,
- 0x17, 0xff, 0xd9, 0xe9, 0xf7, 0x35, 0x25, 0xef, 0xe4, 0x16, 0x2f, 0xe6,
- 0x0e, 0x7b, 0x9e, 0xd6, 0x2f, 0xe1, 0x4e, 0xb4, 0xd1, 0xac, 0x5f, 0xfc,
- 0x23, 0x70, 0xbf, 0x83, 0x1b, 0x76, 0xb1, 0x7f, 0x04, 0x6f, 0x6b, 0x20,
- 0xb1, 0x5d, 0x1f, 0xb3, 0x23, 0x5f, 0xdf, 0x6d, 0xe2, 0x04, 0x16, 0x2f,
- 0xf7, 0x25, 0xb5, 0xac, 0x8d, 0x62, 0xfe, 0x84, 0x83, 0xec, 0x62, 0xc5,
- 0xf7, 0x38, 0x2e, 0xd6, 0x2f, 0xc3, 0xfc, 0x90, 0x96, 0x2a, 0x4f, 0x35,
- 0xc9, 0x6f, 0xfa, 0x4e, 0x58, 0x36, 0xff, 0x16, 0x2f, 0x63, 0x01, 0x62,
- 0xfb, 0xa3, 0x74, 0x05, 0x8b, 0xce, 0xe4, 0xb1, 0x7f, 0x42, 0x62, 0xc6,
- 0x02, 0xc5, 0x82, 0x0d, 0x54, 0x5e, 0x42, 0x94, 0xd2, 0x2e, 0xcc, 0x62,
- 0x34, 0x3b, 0xe7, 0xc8, 0x02, 0xe7, 0x04, 0x39, 0xe2, 0x6d, 0xd1, 0xbb,
- 0x84, 0x62, 0xc5, 0xf4, 0xee, 0x0e, 0x56, 0x2f, 0xb7, 0x7e, 0x20, 0xd6,
- 0x2f, 0xe1, 0x07, 0xc6, 0xc2, 0x58, 0xbb, 0x22, 0x58, 0xb8, 0x38, 0x96,
- 0x29, 0x8d, 0x93, 0x8c, 0x5a, 0x62, 0x3f, 0xfe, 0x30, 0x5e, 0x30, 0xc3,
- 0x12, 0x2d, 0x29, 0x01, 0x0d, 0x0d, 0xd0, 0x8d, 0x62, 0xa0, 0x6f, 0x0e,
- 0x47, 0x7b, 0xf2, 0x05, 0x8b, 0xfb, 0x63, 0xfc, 0x82, 0x77, 0x16, 0x2b,
- 0xc7, 0xa6, 0x18, 0xed, 0xdf, 0xd2, 0xc5, 0xef, 0xec, 0x66, 0x2c, 0x5f,
- 0x45, 0x99, 0xd2, 0xc5, 0x4a, 0xf7, 0x54, 0x6a, 0xf0, 0x79, 0x1a, 0x7e,
- 0x4a, 0xbb, 0x36, 0x15, 0xfd, 0x0c, 0xf6, 0x4b, 0x14, 0x29, 0xf5, 0x08,
- 0x57, 0x74, 0xf1, 0x1e, 0xf1, 0x83, 0x09, 0x2f, 0x87, 0x99, 0xa5, 0x8b,
- 0xff, 0xde, 0x8b, 0x35, 0xa7, 0x8b, 0x35, 0x9e, 0x58, 0xac, 0x3e, 0xe6,
- 0x22, 0xbf, 0xfc, 0x50, 0xdb, 0x06, 0xf4, 0x27, 0x53, 0xd2, 0xc5, 0xfa,
- 0x75, 0xac, 0xfa, 0xc5, 0x61, 0xfa, 0x9a, 0x9b, 0x7f, 0x47, 0x14, 0x36,
- 0x3d, 0x46, 0xb1, 0x7f, 0xf8, 0x07, 0x78, 0x6d, 0x91, 0xc6, 0x79, 0xd2,
- 0xc5, 0xf3, 0x49, 0x79, 0x62, 0xf4, 0x6e, 0x4b, 0x15, 0xa4, 0x46, 0x7d,
- 0x3b, 0xc4, 0x37, 0xfe, 0x34, 0x5c, 0x83, 0x6a, 0x31, 0x01, 0x62, 0xe2,
- 0xc5, 0x8b, 0xc1, 0xf6, 0x4b, 0x17, 0xe2, 0xce, 0xc1, 0xc5, 0x8b, 0xbb,
- 0x31, 0x62, 0xfb, 0x37, 0x24, 0xeb, 0x15, 0x87, 0xd0, 0xe5, 0x3c, 0x1a,
- 0xa3, 0x53, 0x0d, 0x64, 0x33, 0x8b, 0x7e, 0x10, 0xf7, 0x98, 0xf2, 0xb1,
- 0x79, 0xa4, 0xeb, 0x17, 0x38, 0xd6, 0x2b, 0x46, 0xcf, 0xc3, 0x97, 0xe8,
- 0xff, 0x80, 0x75, 0x8a, 0x8c, 0xf2, 0xb4, 0x43, 0x7d, 0xf1, 0xe1, 0x2c,
- 0x5f, 0xfe, 0x0f, 0xc5, 0x20, 0x7f, 0x00, 0x32, 0x82, 0xc5, 0xdb, 0xc6,
- 0xb1, 0x52, 0x7c, 0xce, 0x99, 0x7f, 0xfd, 0xf6, 0xd6, 0xde, 0x73, 0x0b,
- 0xa7, 0x20, 0x2c, 0x58, 0x2d, 0x56, 0x28, 0x28, 0xb8, 0x27, 0x90, 0xc4,
- 0x68, 0xcf, 0x74, 0x86, 0xf0, 0x99, 0xe1, 0x1f, 0xa1, 0x10, 0x22, 0x0d,
- 0xea, 0x57, 0xc1, 0x8f, 0xec, 0xb1, 0x7f, 0xe7, 0xf7, 0x0c, 0xcf, 0x81,
- 0xfc, 0xb1, 0x7e, 0x06, 0x0d, 0xe0, 0xb1, 0x7d, 0xbc, 0x4e, 0x4b, 0x17,
- 0xda, 0x3c, 0xf1, 0x62, 0xff, 0xfb, 0x30, 0xa6, 0x1e, 0xfb, 0x9c, 0xb3,
- 0x7a, 0xc5, 0xf6, 0x7a, 0x7a, 0xda, 0x7e, 0x44, 0x47, 0x51, 0xa6, 0xb8,
- 0x32, 0x4d, 0x20, 0x11, 0x41, 0x90, 0x96, 0xbc, 0x18, 0xe2, 0x58, 0xbd,
- 0x06, 0x25, 0x8b, 0xff, 0x98, 0xe4, 0xe6, 0xf3, 0xf2, 0x5e, 0x58, 0xbf,
- 0x71, 0xfe, 0xdc, 0x58, 0xb8, 0x38, 0x2c, 0x5f, 0xe9, 0x30, 0xb0, 0x02,
- 0xe2, 0xc5, 0x1a, 0x79, 0xba, 0x19, 0xbf, 0xff, 0xfd, 0x0e, 0x7d, 0xdb,
- 0xc2, 0xd3, 0xf3, 0x0a, 0x60, 0x3d, 0x37, 0x70, 0x58, 0xbc, 0x1e, 0xe9,
- 0x8b, 0x17, 0xff, 0xc0, 0xc1, 0xfb, 0x8d, 0xef, 0xe6, 0xf1, 0xca, 0xc5,
- 0xcd, 0xda, 0xc5, 0x46, 0x88, 0xdd, 0x11, 0xf9, 0x4a, 0xfe, 0x76, 0xf4,
- 0x4c, 0x62, 0xc5, 0xfc, 0x3f, 0xc9, 0x8f, 0xe5, 0x8b, 0xff, 0x61, 0x1b,
- 0x9a, 0xf7, 0x9b, 0x4b, 0x17, 0xa3, 0x6d, 0x49, 0xf7, 0x61, 0x7d, 0x7d,
- 0x19, 0xe5, 0x09, 0xdb, 0xfe, 0xf7, 0x03, 0x3e, 0xdc, 0xef, 0xcb, 0x15,
- 0x27, 0xcd, 0x84, 0xf7, 0xfe, 0x06, 0x69, 0x81, 0x80, 0xd1, 0xd6, 0x2f,
- 0xff, 0x1b, 0x3c, 0xd4, 0xfc, 0xb3, 0xd2, 0x75, 0x8b, 0x84, 0x1a, 0xc5,
- 0xff, 0x0a, 0x19, 0xc0, 0xe3, 0x11, 0x2c, 0x5f, 0xe2, 0xcd, 0xed, 0x13,
- 0x18, 0xb1, 0x5f, 0x44, 0x59, 0x0c, 0xf0, 0xf2, 0xff, 0xfe, 0x13, 0xc7,
- 0xd0, 0xa3, 0xf6, 0x7c, 0xb3, 0xdf, 0x65, 0x8b, 0xf4, 0xc4, 0x42, 0xe2,
- 0xc5, 0x62, 0x71, 0x6d, 0x0d, 0x5f, 0x97, 0xf9, 0x7a, 0xe6, 0x25, 0x8b,
- 0xf9, 0xc8, 0x19, 0xe3, 0x56, 0x2a, 0x57, 0x90, 0xe3, 0x51, 0x81, 0x01,
- 0xa3, 0x91, 0x22, 0x69, 0xd7, 0xe4, 0x6f, 0x18, 0x29, 0x46, 0xcd, 0xc2,
- 0x0f, 0x47, 0x95, 0xbd, 0x07, 0x64, 0x5a, 0xf8, 0xbd, 0x3b, 0x2b, 0x17,
- 0xa4, 0xbc, 0xb1, 0x7d, 0x3a, 0x7f, 0xac, 0x50, 0xcd, 0xf6, 0xf1, 0xcb,
- 0xb2, 0x25, 0x8b, 0xef, 0x88, 0xf2, 0xb1, 0x4b, 0x14, 0xb1, 0x67, 0x39,
- 0x71, 0xc0, 0xcb, 0x84, 0x17, 0x58, 0xbe, 0xfe, 0x01, 0xd6, 0x2f, 0xbc,
- 0xdf, 0x12, 0xc5, 0xfd, 0x9a, 0xee, 0x1e, 0x95, 0x8b, 0xa7, 0x70, 0x2d,
- 0x9e, 0x90, 0x64, 0x74, 0x14, 0x4f, 0x15, 0x98, 0xe2, 0x23, 0x71, 0x82,
- 0x3b, 0x11, 0x2e, 0xf1, 0xcd, 0xd7, 0x4b, 0x04, 0x0a, 0x43, 0xa5, 0xac,
- 0x2b, 0x1d, 0xbe, 0xc1, 0x0e, 0xad, 0x8e, 0x15, 0x5b, 0x0c, 0xb3, 0x61,
- 0x42, 0x08, 0x2d, 0xca, 0x53, 0x0b, 0x21, 0x74, 0x16, 0xa7, 0x73, 0x4b,
- 0xe1, 0x8e, 0x79, 0x92, 0x13, 0x82, 0xa3, 0xa5, 0x7f, 0xe5, 0x70, 0xaa,
- 0x6c, 0xb0, 0x3e, 0xa7, 0x7a, 0xbb, 0x9c, 0x51, 0x69, 0xd5, 0x2d, 0xc8,
- 0xc7, 0x22, 0x9e, 0x61, 0xd5, 0x22, 0x38, 0xf3, 0xc8, 0xff, 0xad, 0x86,
- 0x5e, 0x77, 0x9c, 0x13, 0x97, 0x21, 0x78, 0xd1, 0xca, 0x90, 0xd7, 0xcb,
- 0x42, 0x4b, 0xea, 0xeb, 0x14, 0x53, 0xfd, 0xdb, 0xe3, 0x4b, 0x32, 0x12,
- 0xbb, 0x33, 0x86, 0xa1, 0xd2, 0x0e, 0x37, 0x65, 0x48, 0xdf, 0x82, 0xcf,
- 0x13, 0x81, 0x62, 0xfe, 0xd8, 0xf6, 0x3f, 0x13, 0x81, 0x62, 0xfd, 0x19,
- 0xe7, 0xb0, 0x81, 0x43, 0xe5, 0xd8, 0x0b, 0x69, 0xd5, 0xe3, 0x0a, 0x5b,
- 0xd5, 0xf3, 0x10, 0x19, 0x62, 0xf3, 0x9f, 0x8b, 0x15, 0x03, 0x7d, 0xbc,
- 0x86, 0xfc, 0x7c, 0x67, 0x02, 0xc5, 0xf7, 0x4e, 0xfd, 0x2a, 0x28, 0xa2,
- 0xff, 0xfc, 0xe0, 0x9e, 0xbe, 0xdc, 0xfb, 0x7b, 0xf8, 0x4b, 0x15, 0xa4,
- 0x43, 0x11, 0x8d, 0xff, 0xa7, 0xcc, 0x09, 0x87, 0xb9, 0xb1, 0x2c, 0x5f,
- 0xba, 0x92, 0x90, 0x2c, 0x5f, 0x78, 0xd6, 0xe9, 0x62, 0x9c, 0xf3, 0x78,
- 0x51, 0x7f, 0x60, 0x03, 0xd3, 0x81, 0x62, 0xf3, 0xc0, 0x24, 0xa7, 0x61,
- 0x90, 0xad, 0xd1, 0x17, 0xe1, 0x23, 0xe2, 0x1b, 0xff, 0xa5, 0xf4, 0x42,
- 0x7e, 0xf3, 0xee, 0xb1, 0x7f, 0xfc, 0xd1, 0x14, 0xfb, 0x9e, 0xef, 0xa6,
- 0x28, 0xd6, 0x2f, 0xff, 0xb3, 0xfe, 0x63, 0x1b, 0x20, 0xda, 0x70, 0x2c,
- 0x50, 0xd1, 0x45, 0xc5, 0x3b, 0x04, 0xc5, 0x68, 0x27, 0x8f, 0x4f, 0xec,
- 0xdc, 0x87, 0x2d, 0xfe, 0x09, 0x9a, 0xe9, 0xdf, 0xa5, 0x45, 0xd0, 0x5f,
- 0xfc, 0x11, 0xe0, 0x13, 0x35, 0xd3, 0xbf, 0x4a, 0x89, 0x2c, 0xbf, 0xa4,
- 0x18, 0x79, 0xe9, 0x62, 0xfd, 0xae, 0x9d, 0xfa, 0x54, 0x5e, 0x45, 0xcf,
- 0xbd, 0x62, 0xc1, 0x06, 0x7f, 0xd8, 0x5d, 0xb2, 0x6f, 0x53, 0x18, 0x07,
- 0x4c, 0x72, 0xa1, 0x60, 0xeb, 0x90, 0xa4, 0xea, 0x31, 0x28, 0xa1, 0xaa,
- 0x77, 0xef, 0xcf, 0xa8, 0x3a, 0x09, 0x63, 0xb8, 0x23, 0x92, 0xea, 0xbc,
- 0xa2, 0x24, 0x4d, 0xf0, 0xd5, 0xbf, 0xfc, 0x10, 0xef, 0x00, 0x99, 0xae,
- 0x9d, 0xfa, 0x54, 0x4b, 0x25, 0xf0, 0x50, 0xdd, 0x90, 0xa2, 0xc5, 0xb6,
- 0x35, 0x8b, 0x6e, 0xac, 0x5b, 0xeb, 0x14, 0x14, 0x37, 0xdb, 0x00, 0xb8,
- 0x85, 0x6f, 0xf3, 0x0f, 0xf8, 0xc4, 0x6a, 0xc5, 0xef, 0xb9, 0xab, 0x17,
- 0xdf, 0x7f, 0x09, 0x62, 0xfb, 0xf3, 0xb8, 0x75, 0x8b, 0xff, 0x67, 0xda,
- 0x05, 0x98, 0x20, 0xba, 0xc5, 0xff, 0xb1, 0xb7, 0xb1, 0x0a, 0x19, 0xc5,
- 0x8b, 0xfe, 0x91, 0xed, 0x9f, 0x6b, 0x06, 0xb1, 0x78, 0x5d, 0x3a, 0xc5,
- 0x41, 0x37, 0x3e, 0x8c, 0xd8, 0x7b, 0x70, 0x8c, 0xe4, 0xc4, 0x83, 0xe3,
- 0xf0, 0xce, 0xef, 0xde, 0x13, 0xc3, 0x8b, 0x17, 0xd8, 0x63, 0x81, 0x62,
- 0x86, 0x79, 0x84, 0x53, 0x7f, 0xc0, 0xda, 0xde, 0xe4, 0xe8, 0x0b, 0x17,
- 0xee, 0x39, 0xbf, 0x65, 0x8b, 0xa6, 0x35, 0x8b, 0xff, 0x61, 0xf8, 0xf0,
- 0x0f, 0x93, 0x8b, 0x15, 0xb8, 0x7a, 0xfe, 0x18, 0xbc, 0xd1, 0xf9, 0x62,
- 0xa5, 0x1f, 0xf8, 0x78, 0xd0, 0x80, 0xf1, 0x2d, 0xef, 0x98, 0xeb, 0x17,
- 0xf1, 0xe4, 0x8d, 0xc8, 0xd6, 0x2e, 0x73, 0xac, 0x5f, 0xf9, 0xf5, 0x09,
- 0xf7, 0xe4, 0x41, 0x75, 0x8a, 0xd8, 0x11, 0x4f, 0x83, 0xde, 0x2f, 0x10,
- 0xbd, 0xf8, 0x5e, 0x6f, 0xca, 0xc5, 0xff, 0xbf, 0x3f, 0x63, 0x7d, 0xc7,
- 0x02, 0xc5, 0xff, 0x3c, 0x38, 0x2f, 0x4f, 0xb8, 0xb1, 0x7f, 0x17, 0xb5,
- 0x2f, 0xd2, 0xc5, 0xcf, 0xc5, 0x8b, 0xff, 0xf3, 0xbc, 0x1f, 0xfb, 0x72,
- 0x31, 0x79, 0xbf, 0x2b, 0x15, 0x19, 0xf7, 0x44, 0x2f, 0x70, 0xb4, 0xb1,
- 0x7e, 0x87, 0x1f, 0x67, 0x16, 0x2f, 0x3b, 0xf4, 0xa8, 0x8c, 0xcb, 0xfd,
- 0x3d, 0xc2, 0x74, 0x78, 0x2c, 0x5f, 0xff, 0xf7, 0x3d, 0xe6, 0xff, 0x70,
- 0xe1, 0x0b, 0x0d, 0x35, 0x9e, 0x0b, 0x16, 0xc0, 0x22, 0x7f, 0xc6, 0xb7,
- 0xff, 0xfd, 0x0c, 0xda, 0xfe, 0x14, 0xed, 0x19, 0x4e, 0xb4, 0xd8, 0x75,
- 0x8a, 0x94, 0xe1, 0x7a, 0x2b, 0xd4, 0x32, 0x5c, 0xa2, 0xfe, 0x69, 0x3c,
- 0x78, 0x62, 0xc5, 0xc5, 0x05, 0x8b, 0x1d, 0x62, 0xfc, 0xda, 0xfb, 0x84,
- 0xd1, 0xec, 0x1c, 0xbc, 0x31, 0x7b, 0x7d, 0x62, 0xe9, 0xd2, 0xc5, 0x9b,
- 0xa3, 0x53, 0xbc, 0x4a, 0xf9, 0xb4, 0xfa, 0x58, 0xbb, 0x9b, 0x8b, 0x16,
- 0x78, 0x1b, 0xdf, 0x11, 0x5f, 0xfd, 0xc6, 0x17, 0x30, 0x85, 0x0c, 0xe2,
- 0xc5, 0xd3, 0xda, 0xc5, 0xe6, 0x2e, 0x96, 0x2b, 0x86, 0xd7, 0xc3, 0x17,
- 0xff, 0x7b, 0x8d, 0xe2, 0x91, 0x3e, 0x8d, 0x58, 0xb9, 0x8e, 0xb1, 0x60,
- 0xbb, 0x1e, 0xe6, 0xea, 0x2d, 0x46, 0xbb, 0x81, 0x02, 0x81, 0xa0, 0x61,
- 0xd3, 0x42, 0x72, 0x22, 0x4d, 0x47, 0x3a, 0x78, 0x4d, 0x7d, 0xdc, 0x99,
- 0xb8, 0x4d, 0xe7, 0x91, 0x3e, 0xdf, 0xe7, 0x33, 0xed, 0x3a, 0x95, 0x8b,
- 0xff, 0xff, 0xf3, 0x8f, 0x9f, 0xc3, 0x93, 0x47, 0xb4, 0xe2, 0x27, 0x37,
- 0xe5, 0x9e, 0xd6, 0x2c, 0x56, 0x91, 0x70, 0x46, 0x77, 0xff, 0xfb, 0xed,
- 0xef, 0x37, 0x03, 0x8e, 0x63, 0x2c, 0x00, 0xb8, 0xb1, 0x7e, 0xf3, 0x1e,
- 0x62, 0x58, 0xbf, 0xb2, 0x76, 0xcf, 0x0e, 0xb1, 0x58, 0x7b, 0x1c, 0x29,
- 0xbf, 0xc4, 0xe6, 0x78, 0x9c, 0xd5, 0x8a, 0x81, 0xea, 0xf8, 0x86, 0xfb,
- 0x5a, 0x7e, 0x2c, 0x5f, 0xbf, 0x84, 0xe7, 0x58, 0xbe, 0xef, 0xf3, 0xc5,
- 0x8b, 0xd1, 0x39, 0x2c, 0x5e, 0x9f, 0x71, 0x62, 0xff, 0xd8, 0x6f, 0x27,
- 0x08, 0x7f, 0x95, 0x8a, 0xe1, 0xed, 0x88, 0x76, 0xb6, 0xa6, 0x11, 0x02,
- 0x3c, 0x27, 0x88, 0x93, 0x8f, 0x17, 0xed, 0xd2, 0x73, 0x06, 0xb1, 0x7f,
- 0xa7, 0x51, 0xeb, 0x07, 0x8b, 0x17, 0xff, 0x79, 0xb4, 0xe0, 0xdb, 0xdc,
- 0x24, 0xeb, 0x17, 0xe2, 0x98, 0x71, 0xd6, 0x2a, 0x51, 0x9f, 0x02, 0xc6,
- 0x34, 0xde, 0x91, 0x7e, 0xfb, 0x14, 0xfd, 0x62, 0xff, 0x7e, 0x4f, 0xbb,
- 0x8f, 0x12, 0xc5, 0x0c, 0xf7, 0xba, 0x27, 0xb7, 0xd6, 0x2f, 0xff, 0xfe,
- 0xf3, 0x1f, 0x4d, 0x9d, 0x90, 0xbd, 0x3f, 0xdb, 0xbd, 0xbd, 0x14, 0xac,
- 0x56, 0x22, 0x27, 0xc2, 0x57, 0xfd, 0x27, 0xfb, 0xf9, 0xc8, 0x0b, 0x17,
- 0xe7, 0x20, 0xe4, 0x0b, 0x17, 0x64, 0x16, 0x2a, 0x53, 0x45, 0xc8, 0x56,
- 0x31, 0x16, 0x8e, 0x0e, 0x51, 0x7b, 0xcc, 0x4b, 0x17, 0xee, 0x37, 0xb4,
- 0xcb, 0x17, 0xf4, 0x39, 0xc7, 0x28, 0x2c, 0x5e, 0x8f, 0x9c, 0x58, 0xbf,
- 0x17, 0xb8, 0x2d, 0x2c, 0x57, 0x68, 0xba, 0x61, 0xc7, 0x28, 0x22, 0xe1,
- 0x0f, 0xdc, 0xe3, 0x58, 0xbf, 0x41, 0xc8, 0x5d, 0x2c, 0x57, 0x47, 0x81,
- 0xd8, 0xbd, 0xcf, 0xd2, 0xc5, 0xd3, 0xb8, 0xb1, 0x51, 0x9b, 0x20, 0xb8,
- 0xc5, 0xff, 0xbc, 0xe4, 0x0d, 0xa1, 0xe7, 0x66, 0x2c, 0x5f, 0x7b, 0xd2,
- 0x75, 0x8b, 0xe8, 0x79, 0xa3, 0x58, 0xac, 0x44, 0x59, 0xa8, 0x8e, 0x47,
- 0x7f, 0xfd, 0x27, 0x14, 0xc7, 0xb7, 0x58, 0xdf, 0x91, 0xac, 0x5f, 0x39,
- 0x07, 0xc5, 0x8b, 0xc5, 0x9d, 0x2c, 0x5f, 0xf3, 0x79, 0x8f, 0x17, 0x18,
- 0x96, 0x2f, 0xff, 0xed, 0x67, 0xb9, 0xf7, 0x80, 0xa7, 0x3d, 0x3d, 0xc1,
- 0x62, 0xba, 0x44, 0xae, 0x8e, 0x6f, 0xfd, 0x2d, 0xaf, 0x7b, 0x27, 0x40,
- 0x58, 0xb7, 0xa4, 0xf8, 0xa2, 0x24, 0xbf, 0x74, 0xda, 0x3c, 0x16, 0x2f,
- 0xf1, 0xf3, 0x40, 0x21, 0x01, 0x62, 0xd0, 0x58, 0xa8, 0x27, 0x9f, 0x84,
- 0x6d, 0x18, 0xa7, 0xca, 0x1c, 0xa8, 0x33, 0x4b, 0xf0, 0x27, 0xd2, 0x35,
- 0x8a, 0x95, 0x7b, 0x78, 0xac, 0xd0, 0xb1, 0xf9, 0x7b, 0xca, 0x21, 0x12,
- 0xe5, 0xfe, 0xf1, 0x3e, 0xde, 0xba, 0xc5, 0x8b, 0xff, 0xe1, 0x7b, 0x9d,
- 0xc2, 0x48, 0x1c, 0xda, 0x22, 0x58, 0xbd, 0x3e, 0x95, 0x8a, 0x19, 0xf8,
- 0x6f, 0x54, 0xbf, 0xef, 0x4e, 0x9c, 0x8b, 0x0d, 0x58, 0xbc, 0x2f, 0x09,
- 0x62, 0x98, 0xf5, 0x8e, 0x71, 0x7b, 0xf8, 0x4b, 0x15, 0xda, 0x6b, 0xcd,
- 0x0a, 0x7f, 0xbd, 0x08, 0x86, 0xef, 0xc4, 0xb1, 0x7d, 0x91, 0x64, 0x4b,
- 0x17, 0xed, 0x0b, 0xd9, 0x1a, 0xc5, 0xf6, 0x68, 0x72, 0xb1, 0x6e, 0x6d,
- 0x3f, 0x09, 0x24, 0x22, 0xab, 0x7d, 0x62, 0xbb, 0x3c, 0x77, 0x35, 0xbe,
- 0x98, 0x61, 0x2c, 0x53, 0x26, 0x26, 0xf0, 0xd0, 0x01, 0x15, 0xec, 0xce,
- 0x96, 0x2f, 0xfb, 0xdc, 0xcd, 0x00, 0x84, 0x05, 0x8b, 0xff, 0xa7, 0xdc,
- 0xfc, 0xb7, 0xb9, 0x31, 0xac, 0x5f, 0xb3, 0x53, 0x17, 0x16, 0x2b, 0x47,
- 0xdd, 0xf4, 0x5b, 0xef, 0x3f, 0xe5, 0x62, 0xfb, 0xdf, 0x16, 0xca, 0xc5,
- 0xfe, 0xc9, 0xd3, 0xc1, 0xbe, 0xb1, 0x7f, 0x98, 0xce, 0x4f, 0xdf, 0x71,
- 0x62, 0xb4, 0x7d, 0x3e, 0x32, 0xbf, 0x7b, 0xfd, 0xe6, 0xea, 0xc5, 0x0d,
- 0x32, 0x3e, 0xc8, 0x98, 0x88, 0xf0, 0x90, 0xf9, 0x15, 0xfb, 0x8e, 0x6f,
- 0xd9, 0x62, 0xff, 0xb7, 0x07, 0xf1, 0x73, 0xb8, 0x3a, 0xc5, 0xcd, 0xfc,
- 0x3e, 0x81, 0x14, 0xd4, 0xaa, 0xaf, 0xc8, 0xf2, 0xde, 0x17, 0x17, 0xf9,
- 0xa1, 0x30, 0x93, 0xc1, 0x62, 0xf0, 0x79, 0xb1, 0xac, 0x5f, 0xfd, 0xa9,
- 0x07, 0xda, 0x74, 0x03, 0xc1, 0x62, 0xfa, 0x2f, 0xb0, 0x16, 0x2f, 0xa7,
- 0xf2, 0x05, 0x8a, 0x94, 0x45, 0x9a, 0x8b, 0xb2, 0x49, 0x7f, 0xfe, 0x27,
- 0x33, 0xd9, 0xfd, 0xbb, 0x16, 0xc4, 0x14, 0x0b, 0x61, 0x5d, 0x89, 0x62,
- 0xff, 0xf0, 0x80, 0x76, 0x2c, 0x01, 0x63, 0xc4, 0xb1, 0x7f, 0x9b, 0xed,
- 0x25, 0x10, 0x96, 0x2f, 0x4f, 0xc2, 0xab, 0x17, 0xec, 0xc2, 0xef, 0xcb,
- 0x17, 0xfc, 0x2d, 0x3f, 0x36, 0xfa, 0x33, 0x16, 0x2c, 0xda, 0x3e, 0x7f,
- 0x14, 0x54, 0xa3, 0x89, 0x8c, 0xde, 0x11, 0x17, 0xd1, 0xff, 0x3c, 0xb1,
- 0x7f, 0xd0, 0x72, 0x06, 0xd3, 0x33, 0xeb, 0x17, 0xfc, 0x3d, 0x60, 0xbf,
- 0x27, 0xc5, 0x8a, 0xc3, 0xf5, 0x11, 0xe5, 0xff, 0xf6, 0x6f, 0xcd, 0xa1,
- 0xf9, 0xb4, 0xd1, 0xb9, 0xd6, 0x2f, 0xff, 0xfb, 0x01, 0xb3, 0x9b, 0x4b,
- 0x23, 0x0e, 0x1b, 0x79, 0xc6, 0x33, 0x8b, 0x15, 0xf4, 0x63, 0x12, 0xad,
- 0x4a, 0xe4, 0x56, 0x19, 0xb4, 0x2b, 0xa2, 0x33, 0xd3, 0xbf, 0xe3, 0x2b,
- 0x73, 0x2e, 0x42, 0x67, 0xd0, 0xe7, 0xbf, 0xfe, 0x2d, 0x4f, 0xdd, 0xbd,
- 0x3f, 0x2e, 0xd9, 0x62, 0xff, 0xdf, 0x9d, 0x03, 0x5a, 0x93, 0xf1, 0x62,
- 0xfc, 0xfc, 0x26, 0x95, 0x8b, 0xff, 0x9b, 0x43, 0xf8, 0xb5, 0x9d, 0x7f,
- 0x16, 0x2f, 0xcd, 0xa7, 0xdd, 0x65, 0x8a, 0x81, 0xf8, 0x74, 0x8d, 0x7f,
- 0x46, 0xf1, 0x90, 0xbc, 0xb1, 0x7d, 0xe1, 0x3f, 0x96, 0x2f, 0x09, 0xfc,
- 0xb1, 0x5b, 0x4f, 0x03, 0xc4, 0x77, 0xb7, 0xe6, 0x96, 0x2a, 0x4f, 0x0f,
- 0x09, 0x2f, 0xe7, 0x04, 0xef, 0xc2, 0x58, 0xa9, 0x54, 0x91, 0x89, 0xc6,
- 0xa0, 0x77, 0x09, 0x66, 0x23, 0x28, 0x59, 0xf0, 0x82, 0xfb, 0x8d, 0xe6,
- 0x58, 0xb8, 0x43, 0x58, 0xad, 0x8c, 0xdd, 0x08, 0x8a, 0xfe, 0x89, 0xbf,
- 0xac, 0x3a, 0xc5, 0xf0, 0x7c, 0x9c, 0x58, 0xb9, 0x8c, 0x58, 0xbb, 0x77,
- 0x16, 0x29, 0xd1, 0x08, 0x02, 0xfe, 0x11, 0xf8, 0x62, 0xfe, 0xe4, 0xfb,
- 0x9f, 0x65, 0x8b, 0xf1, 0x61, 0xf5, 0x8b, 0x17, 0xd1, 0xc1, 0xc6, 0xb1,
- 0x7d, 0xad, 0xf8, 0x35, 0x8a, 0xc4, 0x4f, 0x1c, 0xb9, 0xc9, 0xc4, 0x49,
- 0x7e, 0xfc, 0xe8, 0xf0, 0x58, 0xbc, 0x3c, 0xf2, 0xc5, 0xfe, 0xc2, 0xdb,
- 0xf9, 0xcd, 0xc5, 0x8b, 0xff, 0x37, 0xb9, 0x83, 0x88, 0xa4, 0x6b, 0x17,
- 0xc0, 0x6e, 0xe0, 0xb1, 0x7f, 0xa4, 0xbc, 0xd1, 0x94, 0xac, 0x5f, 0xfe,
- 0x6d, 0x34, 0x72, 0x59, 0xfd, 0x0b, 0x7a, 0xc5, 0x41, 0x35, 0xe1, 0x94,
- 0x9c, 0x77, 0xe6, 0xe0, 0x3f, 0x22, 0x4f, 0x19, 0x5f, 0xfe, 0x92, 0xe9,
- 0xfc, 0xe6, 0x87, 0x1c, 0xc6, 0xb1, 0x7f, 0xe6, 0x18, 0xbd, 0xc7, 0xf3,
- 0x9a, 0xb1, 0x7f, 0x61, 0x9d, 0xc3, 0x9b, 0x4d, 0x44, 0x73, 0xa7, 0x5f,
- 0xff, 0xd8, 0x58, 0x6f, 0xde, 0x2f, 0xb9, 0xb9, 0xac, 0xf2, 0xc5, 0xff,
- 0xc1, 0xcf, 0x61, 0x91, 0x63, 0x77, 0xe5, 0x8a, 0x64, 0x76, 0xfd, 0x29,
- 0xd7, 0x28, 0x28, 0xea, 0xa9, 0x76, 0x06, 0xe9, 0x8e, 0xaa, 0x38, 0x60,
- 0xc2, 0x32, 0x01, 0xc3, 0x9b, 0x27, 0x80, 0x4d, 0x8d, 0xf3, 0xa2, 0x2e,
- 0xe3, 0x11, 0x68, 0xca, 0xa2, 0x8c, 0x73, 0x51, 0xf0, 0x1e, 0x30, 0x7f,
- 0xce, 0x31, 0xbc, 0x77, 0xe0, 0x8d, 0x58, 0x2e, 0x68, 0x52, 0xb3, 0x39,
- 0x39, 0x89, 0xe9, 0x5b, 0x62, 0x85, 0x46, 0xf8, 0x55, 0x6c, 0xc3, 0x68,
- 0x38, 0xe6, 0x77, 0x63, 0xdf, 0xbf, 0xef, 0x48, 0xf5, 0xa9, 0x3f, 0x16,
- 0x2f, 0xfa, 0x10, 0xc2, 0x06, 0x60, 0xd6, 0x2e, 0x37, 0xa5, 0x8b, 0xf8,
- 0xf0, 0x99, 0xe3, 0x2c, 0x5c, 0xe0, 0x58, 0xa9, 0x3c, 0x47, 0x2d, 0xbe,
- 0x1b, 0xbf, 0x6b, 0x17, 0xf3, 0x76, 0xdd, 0x48, 0x6b, 0x14, 0xe7, 0xa6,
- 0x44, 0x77, 0x98, 0x33, 0xac, 0x5f, 0xfa, 0x0c, 0x30, 0xfd, 0xdf, 0x4c,
- 0x75, 0x8b, 0xf6, 0x7f, 0xb7, 0xdc, 0x58, 0xa8, 0x8f, 0xbc, 0x90, 0xef,
- 0x74, 0xfb, 0xd6, 0x2f, 0xf8, 0xf1, 0x41, 0xf5, 0x1f, 0xc4, 0xb1, 0x77,
- 0x82, 0x4a, 0xa6, 0xfc, 0x3a, 0x39, 0xc7, 0xd7, 0x9d, 0xcc, 0x04, 0x1c,
- 0x84, 0x6f, 0x88, 0x83, 0x20, 0xbf, 0xff, 0xf8, 0x5d, 0xc0, 0x23, 0x97,
- 0xb0, 0xfc, 0x1f, 0xe7, 0x43, 0x77, 0x31, 0x62, 0xff, 0xe9, 0x30, 0x26,
- 0x14, 0x99, 0xa9, 0x3a, 0xc5, 0x04, 0x5d, 0xbb, 0xc9, 0xc6, 0xd2, 0x84,
- 0x8f, 0x9d, 0xaf, 0xff, 0x04, 0x3b, 0xc0, 0x26, 0x6b, 0xa7, 0x7e, 0x95,
- 0x13, 0x49, 0x7f, 0xf8, 0x21, 0xde, 0x01, 0x33, 0x5d, 0x3b, 0xf4, 0xa8,
- 0x9c, 0x4b, 0xc0, 0x29, 0x58, 0xbf, 0x41, 0x88, 0x0c, 0xb1, 0x7e, 0x86,
- 0x7a, 0x10, 0x58, 0xbf, 0xdb, 0xe7, 0xfb, 0x4a, 0x60, 0xb1, 0x7f, 0xe7,
- 0x80, 0x4c, 0xd7, 0x4e, 0xfd, 0x2a, 0x28, 0x12, 0xff, 0xf3, 0x49, 0xdc,
- 0x7a, 0x9f, 0x7f, 0x06, 0xb1, 0x7d, 0xc2, 0xee, 0x0b, 0x16, 0x09, 0x29,
- 0xaf, 0xe0, 0xe7, 0x64, 0xec, 0x52, 0x73, 0x7f, 0xa7, 0xf9, 0x26, 0xe0,
- 0xa6, 0xc6, 0xb1, 0x7d, 0xd3, 0xbf, 0x4a, 0x8b, 0x80, 0xbf, 0xc3, 0xfc,
- 0xec, 0xe6, 0xa5, 0x62, 0xb4, 0x7c, 0xe4, 0x63, 0x77, 0x7c, 0x58, 0xbe,
- 0x37, 0xa7, 0x1a, 0xc5, 0xd2, 0x1a, 0xc5, 0xfc, 0x59, 0xee, 0x9b, 0x8b,
- 0x17, 0x4b, 0x2c, 0x5f, 0x7c, 0x4f, 0x05, 0x8b, 0xfc, 0x50, 0x96, 0x1e,
- 0x1d, 0x62, 0xb6, 0x34, 0xe6, 0x32, 0x11, 0x1d, 0x90, 0xb0, 0xce, 0x89,
- 0x4e, 0x31, 0xf2, 0xef, 0x0b, 0x08, 0x8e, 0xfd, 0x00, 0x86, 0x85, 0x4d,
- 0x58, 0xa0, 0x88, 0xba, 0x98, 0x44, 0x5f, 0xed, 0x88, 0x28, 0x15, 0x80,
- 0x20, 0xcb, 0x17, 0xf1, 0xe7, 0xc2, 0x89, 0xd6, 0x2f, 0x77, 0x0e, 0x2c,
- 0x52, 0xc5, 0x9d, 0xcd, 0x58, 0x07, 0xef, 0xd1, 0x42, 0x4a, 0x0b, 0x14,
- 0xb1, 0x58, 0x6d, 0x48, 0xa6, 0xfe, 0x86, 0x1a, 0x58, 0x05, 0x8b, 0xc0,
- 0xc3, 0x16, 0x2f, 0x8a, 0x73, 0xeb, 0x15, 0x26, 0xfe, 0x31, 0xeb, 0x98,
- 0x26, 0xc2, 0x4e, 0x8e, 0x50, 0xb4, 0xb4, 0x4b, 0x5e, 0x1f, 0x0d, 0xb6,
- 0xf7, 0xdb, 0xa5, 0x8b, 0xfe, 0xcf, 0x77, 0xd3, 0x73, 0xec, 0xb1, 0x5b,
- 0x87, 0xb2, 0x43, 0xd7, 0xed, 0x74, 0xef, 0xd2, 0xa2, 0x49, 0x2e, 0x80,
- 0x49, 0x3d, 0xbc, 0x24, 0xb0, 0x4f, 0xa6, 0x98, 0xf1, 0x8f, 0x5f, 0xb0,
- 0xc0, 0x0b, 0x8b, 0x17, 0x18, 0x05, 0x8b, 0xff, 0x75, 0xf9, 0xd6, 0x78,
- 0xa4, 0xeb, 0x17, 0xf9, 0xfc, 0x59, 0x1b, 0x92, 0xc5, 0xfa, 0x62, 0x29,
- 0x1a, 0xc5, 0xc6, 0x98, 0xb1, 0x78, 0xbb, 0x95, 0x8b, 0xfa, 0x0f, 0xa8,
- 0xc7, 0x2b, 0x17, 0xf6, 0x13, 0xf7, 0x0e, 0x2c, 0x5f, 0xff, 0x84, 0x4e,
- 0x6f, 0x8d, 0x92, 0x86, 0x7d, 0x8e, 0xb1, 0x73, 0xf6, 0xb1, 0x7f, 0x39,
- 0xdf, 0xed, 0x12, 0xc5, 0x68, 0xf1, 0xbc, 0x31, 0x79, 0xb5, 0x05, 0x8b,
- 0xff, 0xf6, 0x75, 0x3f, 0x93, 0xf5, 0xf6, 0xf6, 0x61, 0xd6, 0x2f, 0xc7,
- 0xd6, 0x0f, 0xcb, 0x17, 0xc0, 0x96, 0x89, 0x62, 0xff, 0x4f, 0x61, 0xf8,
- 0xa4, 0x0b, 0x15, 0x28, 0x81, 0x01, 0x48, 0x88, 0xef, 0xdb, 0xbf, 0x92,
- 0x35, 0x62, 0xc3, 0x58, 0xbf, 0xa3, 0x2c, 0xde, 0x29, 0x58, 0xa8, 0xcf,
- 0x09, 0xc4, 0xae, 0x70, 0x91, 0xab, 0xe1, 0x19, 0x56, 0x0c, 0x9a, 0x7f,
- 0xd1, 0x97, 0x65, 0x0c, 0x35, 0x10, 0xee, 0x8b, 0xce, 0x5c, 0xf0, 0x9c,
- 0x01, 0x11, 0x0e, 0xf2, 0x1a, 0xfe, 0x2f, 0xd9, 0x6e, 0xa8, 0xdd, 0xf0,
- 0x04, 0x2d, 0x85, 0xef, 0x49, 0xb1, 0x2e, 0x82, 0x3b, 0xce, 0x4a, 0xbd,
- 0xf4, 0xb1, 0x8d, 0xf3, 0x82, 0x57, 0xed, 0x78, 0x85, 0xe5, 0x8b, 0xff,
- 0x1a, 0xe1, 0x33, 0x5d, 0x3b, 0xf4, 0xa8, 0xb5, 0x0b, 0xee, 0x4f, 0xb8,
- 0xb1, 0x7f, 0xe7, 0x80, 0x4c, 0xd7, 0x4e, 0xfd, 0x2a, 0x25, 0x52, 0xe6,
- 0x31, 0x62, 0x96, 0x2b, 0x13, 0x0f, 0x34, 0xa7, 0xb5, 0x03, 0x91, 0xf9,
- 0x3f, 0x74, 0x62, 0xff, 0xff, 0xff, 0xfc, 0x0d, 0xbb, 0x7f, 0xb2, 0x13,
- 0x7e, 0xc2, 0x14, 0x71, 0xbe, 0xe6, 0xe6, 0x4c, 0x3e, 0x17, 0xed, 0xa6,
- 0x42, 0x81, 0x66, 0xdd, 0xbf, 0xd9, 0x58, 0xa0, 0x89, 0x9f, 0x6c, 0x4b,
- 0x97, 0xf6, 0x6b, 0xa7, 0x7e, 0x95, 0x11, 0x49, 0x7f, 0xe7, 0x73, 0xe6,
- 0x80, 0x42, 0x02, 0xc5, 0xff, 0xa7, 0xdc, 0xcd, 0x00, 0x84, 0x05, 0x8b,
- 0xb8, 0xeb, 0x17, 0xb9, 0x2e, 0xb1, 0x58, 0x6c, 0xd8, 0x5e, 0xff, 0x13,
- 0x83, 0x9e, 0xce, 0x96, 0x2f, 0xd8, 0x38, 0xf0, 0xc5, 0x8b, 0x8e, 0x13,
- 0xe9, 0x96, 0x91, 0xf7, 0x1c, 0xbc, 0x3f, 0xbc, 0xd2, 0x82, 0x27, 0x86,
- 0xf1, 0xb4, 0xdf, 0xb5, 0xd3, 0xbf, 0x4a, 0x88, 0xd0, 0xbf, 0x89, 0x87,
- 0xa6, 0x8d, 0x62, 0xc1, 0x30, 0xf9, 0x58, 0xde, 0xf0, 0x5a, 0xec, 0x85,
- 0x16, 0x2f, 0xb6, 0x2d, 0x86, 0x16, 0xa1, 0x6a, 0xb1, 0x7c, 0xdf, 0x63,
- 0xac, 0x5c, 0x2f, 0xac, 0x5f, 0x36, 0xa6, 0x25, 0x8b, 0xff, 0x0f, 0x0e,
- 0xda, 0xce, 0x45, 0x2b, 0x17, 0xfb, 0xde, 0x67, 0xdf, 0x3e, 0x58, 0xbf,
- 0xff, 0xc2, 0xe7, 0xf0, 0x61, 0x87, 0xc6, 0x0f, 0xcd, 0xc8, 0x83, 0x58,
- 0xa9, 0x44, 0xeb, 0x9a, 0xdf, 0xfe, 0x89, 0x9b, 0xf1, 0x67, 0xa7, 0xd2,
- 0x35, 0x8b, 0xcc, 0xe6, 0x24, 0x5f, 0xf4, 0xfe, 0x63, 0xd4, 0xe0, 0xd6,
- 0x2f, 0xfd, 0x33, 0xbe, 0x4a, 0x62, 0x98, 0x96, 0x2f, 0xd1, 0x71, 0xf3,
- 0xcb, 0x17, 0xfb, 0x5a, 0x9e, 0xf9, 0xf1, 0xac, 0x5b, 0xf2, 0x7b, 0xec,
- 0x53, 0x7f, 0xfd, 0x3f, 0x98, 0xb8, 0x2f, 0x08, 0x51, 0x4e, 0xf5, 0x8a,
- 0x95, 0x5b, 0x6c, 0x47, 0xb9, 0x0d, 0xc8, 0x88, 0x4e, 0x97, 0xf1, 0xd2,
- 0x39, 0xf4, 0x27, 0xf7, 0x93, 0x5f, 0xcd, 0xc8, 0xb3, 0x52, 0xb1, 0x7d,
- 0xd3, 0xbf, 0x4a, 0x8a, 0x7c, 0xbf, 0xfc, 0xda, 0xfb, 0xfb, 0x8f, 0xdb,
- 0x90, 0x16, 0x2e, 0xf4, 0xac, 0x56, 0x91, 0x25, 0xf3, 0x1f, 0x25, 0x5f,
- 0x19, 0xd4, 0x41, 0x55, 0x8b, 0xff, 0xef, 0xb7, 0xb9, 0x9b, 0xfe, 0xdb,
- 0x39, 0xa3, 0x56, 0x2f, 0xf3, 0x79, 0xbd, 0xf1, 0x79, 0x62, 0xfa, 0x4f,
- 0xa7, 0x58, 0xbf, 0xd3, 0xef, 0xbc, 0x5b, 0x71, 0x62, 0xff, 0xe9, 0x9d,
- 0x4f, 0x1b, 0x5a, 0x6e, 0x2c, 0x54, 0x47, 0xf3, 0xe3, 0x6a, 0xd2, 0x3c,
- 0x88, 0xd3, 0xd0, 0x9b, 0xbf, 0xe7, 0x83, 0x0f, 0xf3, 0x0e, 0x2c, 0x5f,
- 0x85, 0xef, 0x4e, 0xf5, 0x8b, 0xff, 0xa6, 0x28, 0x98, 0x13, 0x14, 0x58,
- 0x05, 0x8b, 0xdf, 0x69, 0xd1, 0xf9, 0x91, 0x5d, 0xdf, 0x12, 0xc5, 0x61,
- 0xe4, 0x88, 0xc6, 0xfd, 0x9f, 0x62, 0xf2, 0xc5, 0xff, 0xc7, 0x21, 0x7d,
- 0xb5, 0x9c, 0x8a, 0x56, 0x2f, 0xff, 0xff, 0xd3, 0xe6, 0x27, 0xe7, 0x33,
- 0xdf, 0x73, 0xff, 0x0a, 0x67, 0x8e, 0x2d, 0xeb, 0x17, 0xcf, 0x13, 0x7d,
- 0x62, 0xff, 0xf6, 0xb1, 0xa2, 0xe0, 0xa7, 0xb2, 0x9f, 0x2c, 0x5f, 0xb7,
- 0x8b, 0x72, 0x40, 0xb1, 0x50, 0x4e, 0x25, 0x89, 0xf4, 0x8a, 0x78, 0x40,
- 0xf8, 0x8c, 0x49, 0x77, 0xdd, 0xf8, 0x5a, 0x58, 0xbf, 0xf7, 0xb4, 0x28,
- 0xb9, 0xd3, 0xc5, 0xc5, 0x8a, 0xc3, 0xe9, 0x11, 0x2d, 0xc0, 0x0d, 0x62,
- 0xfe, 0x29, 0xf1, 0x4f, 0x96, 0x2a, 0x07, 0x8a, 0xe3, 0x37, 0xa2, 0x6e,
- 0x2c, 0x5f, 0x34, 0xeb, 0x16, 0x2f, 0xd3, 0xee, 0xf3, 0xd2, 0x6f, 0xfe,
- 0x3d, 0x7f, 0xe8, 0x84, 0x51, 0xf3, 0xa7, 0x8b, 0x8b, 0x15, 0x28, 0x81,
- 0xc3, 0xdb, 0x9f, 0x8b, 0x17, 0xe1, 0x45, 0x13, 0x9a, 0xb1, 0x7f, 0xde,
- 0x9e, 0xde, 0x2d, 0x4e, 0xf5, 0x8a, 0xdc, 0x44, 0x07, 0x05, 0xfc, 0x59,
- 0x4b, 0x17, 0xbe, 0xda, 0x58, 0xad, 0x8c, 0xd4, 0x88, 0x32, 0xd8, 0xb1,
- 0x60, 0x81, 0x46, 0x64, 0x0e, 0xc4, 0x58, 0x15, 0x3d, 0xd8, 0x08, 0xa6,
- 0x57, 0x9c, 0x70, 0x8d, 0xc8, 0x60, 0x1a, 0x61, 0xd1, 0x5b, 0x46, 0x90,
- 0x73, 0x4f, 0xc3, 0xd5, 0xe3, 0xaa, 0x28, 0x62, 0xf1, 0x9b, 0xd0, 0xe1,
- 0x14, 0x28, 0x76, 0x57, 0x37, 0x49, 0xaf, 0xff, 0x04, 0x3b, 0xc0, 0x26,
- 0x6b, 0xa7, 0x7e, 0x95, 0x13, 0x51, 0x7f, 0x66, 0xba, 0x77, 0xe9, 0x51,
- 0x5d, 0x97, 0xff, 0xb3, 0x75, 0xbc, 0xd0, 0xda, 0x53, 0xee, 0x2c, 0x5f,
- 0xfd, 0x27, 0x0f, 0xcc, 0x42, 0x86, 0x71, 0x62, 0xf1, 0x10, 0xd6, 0x2f,
- 0x1e, 0x7e, 0xb1, 0x4b, 0x17, 0x18, 0x13, 0xe8, 0xd8, 0x02, 0x71, 0x22,
- 0x88, 0x70, 0xc1, 0xda, 0x08, 0x9b, 0x6b, 0x46, 0x29, 0x70, 0x19, 0x62,
- 0xc3, 0x58, 0xba, 0x4e, 0xb1, 0x5f, 0x35, 0x3c, 0x12, 0xb6, 0xca, 0xc5,
- 0x89, 0x62, 0xa3, 0x34, 0xc7, 0x15, 0xba, 0x39, 0x58, 0xbe, 0xe9, 0xdf,
- 0xa5, 0x45, 0x7c, 0x5e, 0x30, 0xc3, 0x12, 0x2c, 0x49, 0x01, 0x0d, 0x0d,
- 0x68, 0xfd, 0x4e, 0xa5, 0x7f, 0xbf, 0x86, 0xbc, 0xf7, 0xba, 0xb1, 0x7a,
- 0x13, 0xda, 0xc5, 0xf7, 0x60, 0x92, 0x58, 0xbb, 0xec, 0xb1, 0x6c, 0x93,
- 0x75, 0xe2, 0x3b, 0x85, 0xc5, 0x8b, 0xb3, 0xeb, 0x14, 0x33, 0x5f, 0x10,
- 0xc5, 0xcf, 0xbd, 0x62, 0xff, 0x18, 0xfe, 0xe4, 0xe4, 0x6b, 0x17, 0xb9,
- 0x20, 0x58, 0xaf, 0x9e, 0x97, 0x8d, 0x6d, 0x2b, 0x17, 0xc4, 0xfd, 0xf1,
- 0x62, 0xb0, 0xf5, 0xb8, 0x45, 0xe1, 0x1b, 0xc6, 0x66, 0x96, 0x2d, 0xe5,
- 0x8b, 0xfe, 0x6d, 0x64, 0x6d, 0x0c, 0x1a, 0xc5, 0xfe, 0xd0, 0x3d, 0xc7,
- 0x06, 0x2c, 0x53, 0x22, 0x77, 0x43, 0xce, 0x24, 0x23, 0x9b, 0xdf, 0x20,
- 0x2c, 0x5f, 0x6e, 0xfc, 0x41, 0xac, 0x5e, 0x8b, 0x22, 0x58, 0xb3, 0x2c,
- 0x57, 0x67, 0xb1, 0x11, 0x41, 0xc7, 0xed, 0xa5, 0x8a, 0x58, 0xa6, 0x2f,
- 0xb4, 0x25, 0x4b, 0x16, 0x65, 0x8b, 0x46, 0x69, 0x7b, 0xf0, 0xcb, 0x6f,
- 0x58, 0xaf, 0x9f, 0xc3, 0x9e, 0x08, 0xa2, 0xfb, 0x0a, 0x60, 0xb1, 0x60,
- 0x9b, 0x09, 0x76, 0xc2, 0x50, 0x23, 0x47, 0x81, 0x16, 0x42, 0x37, 0xa2,
- 0x28, 0x8e, 0x34, 0xb0, 0xea, 0x80, 0x22, 0x28, 0x60, 0xf2, 0x19, 0x7e,
- 0x3b, 0x13, 0xae, 0xcc, 0x31, 0xc3, 0x2e, 0xbf, 0xfc, 0x10, 0xef, 0x00,
- 0x99, 0xae, 0x9d, 0xfa, 0x54, 0x4f, 0x65, 0x82, 0xeb, 0x17, 0xfc, 0x37,
- 0xea, 0x7a, 0x11, 0x0d, 0x62, 0xff, 0xf9, 0xa1, 0xcd, 0xcf, 0x8b, 0xac,
- 0x8f, 0x68, 0xf4, 0xb1, 0x7d, 0x3b, 0xaf, 0xda, 0xc5, 0xe6, 0x20, 0x2c,
- 0x54, 0x68, 0xd6, 0x81, 0xdf, 0xd6, 0x77, 0x93, 0x5f, 0xfc, 0x2d, 0x45,
- 0xa6, 0x8d, 0xce, 0xdc, 0x58, 0xbf, 0x30, 0xe7, 0x5c, 0x58, 0xbf, 0x6b,
- 0xa7, 0x7e, 0x95, 0x17, 0x09, 0x7c, 0x71, 0x7b, 0x8b, 0x17, 0xfb, 0xed,
- 0x01, 0x02, 0x62, 0x58, 0xbf, 0xf3, 0x6f, 0x78, 0xb8, 0xda, 0x93, 0xac,
- 0x5f, 0xd2, 0xda, 0xd3, 0x18, 0xb1, 0x7c, 0x3f, 0xe4, 0x4b, 0x16, 0x08,
- 0x15, 0x55, 0x7d, 0x30, 0xec, 0x8d, 0x02, 0x08, 0xf8, 0x50, 0x69, 0xbb,
- 0x12, 0x44, 0x6a, 0x74, 0x11, 0x17, 0x5f, 0xfc, 0x11, 0xe0, 0x13, 0x35,
- 0xd3, 0xbf, 0x4a, 0x89, 0x3c, 0xbf, 0xf3, 0x44, 0x12, 0x45, 0x3e, 0x90,
- 0x2c, 0x5f, 0xe3, 0x42, 0x45, 0xf9, 0x23, 0x56, 0x2a, 0x5b, 0xda, 0xa8,
- 0xe3, 0xee, 0x84, 0x24, 0x0d, 0xa6, 0x54, 0xf5, 0x1a, 0x9c, 0x51, 0xe5,
- 0x6a, 0x77, 0x6f, 0xf1, 0x80, 0xf2, 0x58, 0xde, 0xf8, 0x4f, 0x18, 0xae,
- 0x1a, 0x0d, 0xfe, 0x09, 0x9a, 0xe9, 0xdf, 0xa5, 0x44, 0x54, 0x5f, 0xb5,
- 0xd3, 0xbf, 0x4a, 0x8a, 0x64, 0xbf, 0x9b, 0xf8, 0xfd, 0x81, 0x62, 0xc1,
- 0x30, 0xf9, 0x76, 0x4d, 0xef, 0xff, 0x04, 0x3b, 0xc0, 0x26, 0x6b, 0xa7,
- 0x7e, 0x95, 0x13, 0x39, 0x7f, 0xf8, 0x21, 0xde, 0x01, 0x33, 0x5d, 0x3b,
- 0xf4, 0xa8, 0xa3, 0x4a, 0x8d, 0x38, 0xf1, 0xc2, 0xa4, 0xd2, 0xcf, 0x2e,
- 0xdf, 0xf9, 0xe0, 0x13, 0x35, 0xd3, 0xbf, 0x4a, 0x88, 0xe8, 0xbf, 0x8b,
- 0x3d, 0xc9, 0x3a, 0xc5, 0xe9, 0xf7, 0x16, 0x2f, 0x6a, 0x30, 0x9c, 0x3c,
- 0xa0, 0xcb, 0x6f, 0xff, 0x10, 0xbc, 0x23, 0x7d, 0xdf, 0x4d, 0xae, 0x2c,
- 0x5f, 0xfe, 0x13, 0xb4, 0x18, 0x1c, 0x17, 0x3e, 0x25, 0x8b, 0xda, 0x80,
- 0x4c, 0x44, 0xd7, 0x13, 0xe8, 0x22, 0x74, 0x33, 0x09, 0x96, 0x86, 0x95,
- 0xc2, 0xfa, 0xc5, 0xfb, 0x63, 0x0a, 0xeb, 0x9c, 0x58, 0xbe, 0xeb, 0xa1,
- 0x74, 0xb1, 0x7d, 0xc1, 0x1d, 0x96, 0x2e, 0x33, 0xeb, 0x14, 0xc6, 0xf0,
- 0xc2, 0x3b, 0xf6, 0x10, 0xf2, 0x35, 0x8b, 0xfe, 0x6d, 0x70, 0xb0, 0x7f,
- 0x95, 0x8b, 0xfd, 0x33, 0xd6, 0x6b, 0x58, 0xb1, 0x4c, 0x89, 0x3f, 0x94,
- 0x11, 0xc5, 0xfb, 0x35, 0xd0, 0x8d, 0x58, 0xbf, 0xee, 0xa4, 0xf8, 0xc7,
- 0x9d, 0xc5, 0x8b, 0xe6, 0xd3, 0xb2, 0xc5, 0xff, 0x8b, 0x0d, 0x78, 0xb9,
- 0xf9, 0x1a, 0xc5, 0xe8, 0x9f, 0xcb, 0x17, 0xdd, 0x3b, 0xf4, 0xa8, 0xa6,
- 0x8b, 0xc6, 0x3f, 0xd6, 0x2f, 0xe9, 0xeb, 0x3a, 0xf8, 0x96, 0x2d, 0x9d,
- 0x9e, 0x71, 0xc7, 0xaf, 0xfe, 0xe6, 0x10, 0xe7, 0x6e, 0xc2, 0xde, 0x06,
- 0x58, 0xbf, 0x37, 0x3d, 0x9f, 0x58, 0xbf, 0xcd, 0xac, 0x8a, 0x44, 0x17,
- 0x58, 0xa1, 0xaa, 0x3b, 0xc2, 0xb3, 0x4f, 0x18, 0x86, 0x24, 0x0d, 0x0f,
- 0x13, 0xff, 0x0a, 0x3c, 0x9d, 0xbc, 0xa2, 0xfb, 0x4e, 0x36, 0x58, 0xbf,
- 0xfd, 0xd3, 0xeb, 0x9f, 0x76, 0xe7, 0x33, 0x8b, 0x17, 0xff, 0xfd, 0x85,
- 0xee, 0x37, 0x58, 0x5c, 0xeb, 0xed, 0xfe, 0x83, 0x8d, 0x62, 0xff, 0xb8,
- 0xfd, 0xe4, 0x53, 0xfe, 0x2c, 0x59, 0xbe, 0x8f, 0x12, 0x4b, 0xf3, 0x5d,
- 0xfe, 0xd4, 0x7c, 0xd6, 0xa4, 0xc5, 0x8b, 0xfb, 0x23, 0xce, 0xb0, 0x6b,
- 0x15, 0xf4, 0x4d, 0x39, 0xa1, 0x1b, 0xdf, 0xfb, 0xec, 0x51, 0xf0, 0x53,
- 0xa8, 0x96, 0x2f, 0xff, 0xd9, 0x1c, 0xf1, 0xb5, 0x9b, 0x71, 0x8a, 0x4e,
- 0xb1, 0x50, 0x44, 0xb7, 0x90, 0x6f, 0x40, 0xf0, 0x58, 0xbe, 0xf7, 0x1c,
- 0x0b, 0x17, 0xfa, 0x7d, 0xcd, 0x31, 0xf1, 0x62, 0xf0, 0x3c, 0xcb, 0x17,
- 0xfb, 0x9d, 0x36, 0xb4, 0xd1, 0xac, 0x54, 0xa2, 0xa7, 0xb2, 0x37, 0x33,
- 0xe0, 0xed, 0xff, 0xfd, 0x18, 0xb5, 0x17, 0x23, 0x98, 0xb9, 0xfc, 0x1b,
- 0x6f, 0x58, 0xbf, 0xff, 0xdf, 0x73, 0x4b, 0x21, 0xf9, 0x86, 0x7c, 0xb1,
- 0xe3, 0x58, 0xbf, 0xec, 0xd3, 0xcb, 0x14, 0x9d, 0x62, 0xff, 0xff, 0xfa,
- 0x7b, 0xeb, 0xf9, 0xb7, 0xf9, 0xd7, 0xdb, 0xf8, 0x4e, 0x6e, 0x6f, 0x9e,
- 0xd6, 0x2f, 0xd1, 0xed, 0xf8, 0x37, 0xac, 0x54, 0x69, 0xd6, 0x0d, 0x8f,
- 0x8c, 0x1b, 0xcd, 0x83, 0x84, 0x25, 0xff, 0x6f, 0xeb, 0xec, 0x0f, 0xb1,
- 0xd6, 0x2f, 0xed, 0xb2, 0x46, 0xfd, 0x96, 0x2f, 0xb0, 0xa4, 0xc5, 0x8a,
- 0x81, 0xe9, 0x44, 0x61, 0x58, 0x98, 0x33, 0x2a, 0x3c, 0x23, 0xee, 0xd0,
- 0x96, 0x2f, 0xb3, 0xe1, 0xe9, 0x62, 0x8e, 0x6f, 0x08, 0x62, 0xe3, 0xec,
- 0xac, 0x5f, 0xce, 0x5d, 0x6d, 0x8f, 0x8b, 0x14, 0x03, 0xcd, 0x10, 0xdd,
- 0xfe, 0xeb, 0xa1, 0x68, 0x1f, 0x12, 0xc5, 0xfd, 0x25, 0xed, 0x9c, 0xf2,
- 0xc5, 0xfe, 0x70, 0x3f, 0xbd, 0x9f, 0x58, 0xa8, 0x1f, 0x19, 0x86, 0x17,
- 0xdf, 0x6c, 0xd2, 0xc5, 0xdf, 0x12, 0xc5, 0xa0, 0xb1, 0x7f, 0xa3, 0xce,
- 0xbc, 0x4f, 0x12, 0xc5, 0x6c, 0x09, 0xa0, 0x64, 0x26, 0xd8, 0x8c, 0x04,
- 0x5b, 0xc6, 0x03, 0x12, 0xbd, 0xf3, 0x00, 0xb1, 0x6f, 0x2c, 0x53, 0x1b,
- 0x1f, 0x8f, 0xdc, 0x39, 0x58, 0xbf, 0xff, 0x7b, 0x81, 0xf3, 0x52, 0x3c,
- 0xff, 0x58, 0x51, 0xac, 0x54, 0x9f, 0x86, 0x0b, 0xdf, 0xd2, 0xc0, 0x7f,
- 0x09, 0x62, 0xff, 0xd8, 0x0c, 0xc8, 0xa2, 0x29, 0x1a, 0xc5, 0xff, 0xb4,
- 0x01, 0x94, 0xc3, 0xfc, 0x02, 0xc5, 0x62, 0x6b, 0x87, 0x84, 0x87, 0xc8,
- 0x08, 0xb4, 0x47, 0xf7, 0xbd, 0x30, 0x58, 0xbf, 0xe1, 0x7b, 0xf9, 0x14,
- 0x27, 0xb5, 0x8b, 0xff, 0xc4, 0xfe, 0xcf, 0x73, 0x3f, 0x9b, 0x9e, 0x58,
- 0xaf, 0xa2, 0x94, 0x87, 0x77, 0x9e, 0x5f, 0xf9, 0xb5, 0xa6, 0x8f, 0x8c,
- 0x0e, 0x2c, 0x5a, 0x25, 0x8b, 0x9f, 0xeb, 0x17, 0xec, 0xfb, 0x90, 0xd6,
- 0x2a, 0x33, 0xd1, 0x80, 0x98, 0x05, 0xee, 0x93, 0x56, 0x2f, 0x6f, 0x6d,
- 0x2c, 0x58, 0x96, 0x2b, 0x0d, 0x83, 0x8f, 0xdf, 0x70, 0x2c, 0x0b, 0x02,
- 0xc5, 0x8b, 0x3c, 0x47, 0xa4, 0x01, 0xfb, 0xf9, 0xa4, 0xf1, 0xe1, 0x8b,
- 0x17, 0xff, 0xd9, 0xef, 0xe4, 0x34, 0xe5, 0xef, 0xbc, 0x16, 0x2e, 0x90,
- 0x2c, 0x5f, 0xe7, 0xee, 0x7a, 0x6e, 0x82, 0x69, 0x12, 0xa4, 0x5e, 0x1a,
- 0x7d, 0x62, 0xaa, 0x5e, 0x8c, 0x5a, 0x12, 0x3f, 0x30, 0x28, 0x4d, 0x72,
- 0x17, 0xb7, 0x9e, 0x2e, 0x2c, 0x5f, 0x8b, 0x9f, 0xcd, 0xc5, 0x8b, 0x69,
- 0x62, 0xb0, 0xde, 0x86, 0x57, 0x7e, 0x07, 0xe6, 0x1c, 0x58, 0xbc, 0x42,
- 0x35, 0x62, 0xf1, 0x8f, 0x1a, 0xc5, 0xff, 0x48, 0x1f, 0xc0, 0x0c, 0xa0,
- 0xb1, 0x5f, 0x3d, 0x92, 0x1f, 0xa9, 0x46, 0x09, 0x14, 0xf9, 0xde, 0xc1,
- 0x36, 0x06, 0xd0, 0xe4, 0x2d, 0x8c, 0x49, 0x9c, 0x18, 0xc7, 0x0b, 0x4c,
- 0x94, 0xd2, 0x6c, 0x23, 0xba, 0x8e, 0xb7, 0xb8, 0x62, 0x31, 0x1e, 0xa1,
- 0x8f, 0xf9, 0x5d, 0xce, 0xde, 0x06, 0xd2, 0x8d, 0x8b, 0x91, 0xf8, 0x7a,
- 0x5c, 0xc0, 0x99, 0xb6, 0x56, 0xc3, 0x87, 0x15, 0xd1, 0xec, 0xac, 0x5f,
- 0xff, 0x67, 0x9b, 0xe2, 0xfb, 0xb7, 0x7c, 0x93, 0x56, 0x2f, 0x98, 0x80,
- 0xcb, 0x17, 0xdd, 0x3b, 0xf4, 0xa8, 0xaa, 0x8a, 0x81, 0xe9, 0x68, 0x86,
- 0xff, 0xcf, 0x00, 0x99, 0xae, 0x9d, 0xfa, 0x54, 0x4d, 0xa5, 0x82, 0x46,
- 0x99, 0x80, 0xc7, 0x32, 0x14, 0x67, 0x22, 0xbf, 0xc1, 0x33, 0x5d, 0x3b,
- 0xf4, 0xa8, 0xaf, 0xcb, 0xf6, 0xba, 0x77, 0xe9, 0x51, 0x63, 0x17, 0x6e,
- 0xc1, 0x62, 0xc1, 0x30, 0xf4, 0xa2, 0x37, 0xbe, 0xeb, 0xf2, 0x6a, 0xc5,
- 0xe9, 0xf7, 0x16, 0x2b, 0x87, 0x85, 0xe2, 0x5b, 0xfe, 0x8e, 0x78, 0xe0,
- 0xe3, 0x0d, 0x62, 0xfe, 0x14, 0x33, 0x8f, 0xe5, 0x8b, 0xfc, 0x2c, 0xd7,
- 0x5f, 0x6e, 0x2c, 0x56, 0x91, 0x3a, 0x47, 0x5c, 0x2e, 0xbf, 0xda, 0x93,
- 0x36, 0x43, 0xfb, 0xac, 0x5f, 0x87, 0xb0, 0x6c, 0x04, 0x6a, 0xc5, 0xf7,
- 0xb8, 0xfd, 0xac, 0x50, 0x50, 0xf6, 0x24, 0xd2, 0xff, 0x88, 0x51, 0xc5,
- 0x09, 0xd4, 0x6b, 0x17, 0x6b, 0xcb, 0x17, 0xcf, 0x0c, 0x1a, 0xc5, 0xfd,
- 0xec, 0xd0, 0xf0, 0x96, 0x2d, 0x83, 0x3c, 0xff, 0x11, 0x5d, 0x0c, 0x58,
- 0xbf, 0x9d, 0xfd, 0xec, 0xfa, 0xc5, 0xff, 0xec, 0x39, 0x39, 0xa5, 0x80,
- 0xda, 0x66, 0xc6, 0xb1, 0x46, 0xa2, 0x5b, 0x42, 0xe4, 0x5b, 0x7f, 0x8c,
- 0x93, 0x1c, 0xbb, 0xf2, 0xc5, 0xfb, 0x5e, 0xfe, 0x46, 0xb1, 0x52, 0x7c,
- 0x18, 0x6d, 0x7f, 0x79, 0x8f, 0xdc, 0x38, 0xb1, 0x60, 0x98, 0xac, 0x9b,
- 0x45, 0xe7, 0x84, 0x8f, 0xc9, 0x5c, 0xf4, 0x99, 0xf9, 0x0b, 0xd0, 0xe1,
- 0x21, 0xba, 0x41, 0x66, 0x08, 0xb8, 0xfb, 0xa9, 0x7c, 0xb7, 0xed, 0x74,
- 0xef, 0xd2, 0xa2, 0xd5, 0x2f, 0xda, 0xe9, 0xdf, 0xa5, 0x45, 0x04, 0x5d,
- 0x1f, 0xd6, 0x2f, 0x3c, 0x02, 0x61, 0xe8, 0x00, 0xde, 0xfd, 0x26, 0x6c,
- 0xe6, 0x96, 0x2c, 0x13, 0x11, 0xce, 0x78, 0x43, 0x86, 0x69, 0x7d, 0xed,
- 0x3f, 0xd6, 0x2f, 0xef, 0xb4, 0x71, 0x8b, 0x8b, 0x17, 0xda, 0x9f, 0x71,
- 0x62, 0xf1, 0x64, 0x6b, 0x16, 0xc1, 0x9e, 0x07, 0x44, 0x77, 0xf4, 0x9d,
- 0xfb, 0xf4, 0x16, 0x2f, 0xf6, 0x7f, 0x9a, 0x26, 0xe9, 0x62, 0xb1, 0x31,
- 0xfe, 0x88, 0xc9, 0xc7, 0x85, 0x1e, 0x2f, 0xbb, 0x5e, 0x58, 0xbf, 0xcd,
- 0xb3, 0x3e, 0xfb, 0xc4, 0xb1, 0x7b, 0x3e, 0x11, 0xcf, 0x3f, 0x83, 0x17,
- 0x39, 0x81, 0x11, 0x9b, 0xe8, 0x4c, 0xdf, 0xc1, 0x6f, 0x62, 0xf6, 0xce,
- 0x7d, 0x62, 0xfe, 0x20, 0x4e, 0xe3, 0x9d, 0x62, 0xff, 0x1b, 0x0c, 0x6f,
- 0xbc, 0x4b, 0x15, 0x27, 0xca, 0xc6, 0x17, 0xef, 0xe7, 0x52, 0x75, 0x8b,
- 0xd2, 0x51, 0x2c, 0x5f, 0xfe, 0x8a, 0x77, 0xbe, 0xb9, 0xc6, 0xd6, 0x1a,
- 0xb1, 0x7f, 0x9a, 0x29, 0xde, 0xfa, 0xe2, 0xc5, 0xb8, 0xb1, 0x52, 0x79,
- 0x04, 0x6d, 0x7f, 0xf4, 0x80, 0x5e, 0xe1, 0x4e, 0xec, 0xc6, 0xb1, 0x76,
- 0xa5, 0x62, 0xa0, 0x9b, 0xd8, 0xc8, 0x3a, 0x29, 0x61, 0xdf, 0xc2, 0x5b,
- 0x79, 0x06, 0xea, 0x45, 0xf3, 0x7d, 0xf8, 0xb1, 0x7d, 0xd3, 0xbf, 0x4a,
- 0x8b, 0x88, 0xbf, 0x84, 0xfd, 0x8f, 0x34, 0xb1, 0x5a, 0x3e, 0x0e, 0x18,
- 0xdf, 0xff, 0xa0, 0x1f, 0xe0, 0xfe, 0x70, 0x08, 0x9f, 0x78, 0xd6, 0x2e,
- 0x0e, 0x25, 0x8b, 0xfe, 0xe6, 0x30, 0x03, 0xf3, 0xfd, 0x62, 0xfe, 0xef,
- 0xa6, 0xe7, 0xd9, 0x62, 0xa3, 0x44, 0x27, 0xc6, 0xbc, 0x75, 0x7f, 0xfd,
- 0x09, 0xf0, 0x36, 0xe7, 0xf5, 0x80, 0x14, 0x4b, 0x16, 0x35, 0x62, 0xe8,
- 0x99, 0x62, 0xb0, 0xd5, 0xb8, 0x9d, 0xfe, 0xdf, 0x9e, 0xe6, 0xf9, 0xfa,
- 0xc5, 0x40, 0xf5, 0xfe, 0x3f, 0x58, 0x8f, 0x86, 0x86, 0xb5, 0xfe, 0x2f,
- 0x43, 0x09, 0x86, 0xb1, 0x7f, 0xc4, 0xe0, 0xe7, 0xe4, 0xbc, 0xb1, 0x58,
- 0x7d, 0x5e, 0x32, 0xbf, 0x61, 0xdb, 0x74, 0x6b, 0x17, 0x49, 0xd6, 0x2a,
- 0x4f, 0x8f, 0x70, 0x87, 0x45, 0x77, 0xf0, 0x89, 0xcd, 0x80, 0x16, 0x2f,
- 0x9f, 0x75, 0xa3, 0x58, 0xbf, 0x7c, 0x46, 0xe1, 0x2c, 0x5e, 0x87, 0x99,
- 0x62, 0xfc, 0x3c, 0xdc, 0x9f, 0xac, 0x5e, 0xdd, 0x6e, 0x96, 0x28, 0x68,
- 0x92, 0x88, 0xa7, 0x43, 0xbb, 0xa5, 0x77, 0xf8, 0xef, 0x0e, 0x30, 0xf1,
- 0x62, 0xf1, 0xb3, 0xc5, 0x8b, 0xfd, 0x09, 0x89, 0xff, 0x3b, 0x8b, 0x17,
- 0xfe, 0x88, 0x50, 0x0f, 0x7c, 0xfd, 0xf7, 0xac, 0x54, 0xa2, 0x6f, 0x07,
- 0x9c, 0xde, 0xfe, 0x16, 0xe3, 0xf8, 0x52, 0xb1, 0x4b, 0x17, 0x4c, 0x6b,
- 0x15, 0xd9, 0xea, 0xf0, 0xc7, 0x74, 0x32, 0xff, 0xb3, 0xfe, 0x29, 0x06,
- 0xd6, 0x58, 0xbf, 0x17, 0x89, 0xcd, 0x58, 0xa5, 0x8a, 0xc3, 0x69, 0xb2,
- 0x51, 0x4e, 0x8c, 0x42, 0x33, 0xe3, 0x75, 0xfc, 0x77, 0xdf, 0x3a, 0xdd,
- 0x58, 0xbf, 0xf3, 0x0f, 0x37, 0x9f, 0x21, 0xdc, 0x16, 0x2f, 0xcf, 0xc7,
- 0x20, 0x2c, 0x5f, 0xcd, 0xbe, 0x07, 0x98, 0x96, 0x2f, 0xfd, 0x38, 0x47,
- 0x9f, 0xee, 0xbe, 0xea, 0xc5, 0x40, 0xfd, 0x34, 0x63, 0x7f, 0xd8, 0x7c,
- 0xd6, 0x47, 0x86, 0x2c, 0x5f, 0xfe, 0xfc, 0xef, 0xf7, 0x1b, 0xdf, 0xcd,
- 0xde, 0x2c, 0x54, 0xa7, 0x79, 0x86, 0x66, 0xa1, 0x34, 0x26, 0xfe, 0x44,
- 0x03, 0xaa, 0x58, 0xbf, 0xa3, 0x7c, 0xf6, 0x1d, 0x62, 0x82, 0x86, 0xe9,
- 0xc3, 0x2f, 0xc3, 0x72, 0xcd, 0xd5, 0x8b, 0xfb, 0x34, 0xfe, 0x14, 0xac,
- 0x5f, 0xff, 0x39, 0x4b, 0x6e, 0xf1, 0xb9, 0x9f, 0xcd, 0x95, 0x8a, 0x1a,
- 0x20, 0x37, 0x96, 0xdf, 0xfc, 0xc4, 0x28, 0x67, 0x38, 0xc3, 0xc5, 0x8a,
- 0x94, 0xc4, 0xa2, 0x85, 0x57, 0x89, 0x6c, 0x13, 0x61, 0x33, 0x60, 0x66,
- 0x50, 0xec, 0x1b, 0xf2, 0x10, 0x5d, 0x91, 0x34, 0x37, 0x62, 0x8c, 0xa7,
- 0x50, 0xf3, 0x39, 0x8f, 0xcb, 0xde, 0x17, 0x00, 0x41, 0x28, 0x67, 0x72,
- 0x34, 0x6f, 0x47, 0xd5, 0xb3, 0x09, 0x50, 0xe3, 0x36, 0xbf, 0xb6, 0x2d,
- 0x8b, 0x4e, 0xf0, 0x58, 0xbf, 0xc1, 0x42, 0xd8, 0x3d, 0xb3, 0xb0, 0x0d,
- 0x62, 0xff, 0x6c, 0x58, 0x20, 0xff, 0x26, 0xac, 0x5c, 0xe1, 0x55, 0x8a,
- 0x0a, 0x9e, 0xb1, 0x1d, 0xdf, 0xb6, 0x18, 0x54, 0x72, 0x35, 0x8b, 0xf6,
- 0xc7, 0xb0, 0xc0, 0x6c, 0xac, 0x5f, 0xf9, 0xbb, 0x0b, 0x39, 0xad, 0xbb,
- 0x7f, 0xb2, 0xb1, 0x7d, 0xb7, 0x6f, 0xf6, 0x56, 0x2f, 0xb6, 0xed, 0xfe,
- 0xca, 0xc5, 0xe9, 0xf7, 0x4b, 0x15, 0xb8, 0x7e, 0x91, 0x15, 0xfc, 0xae,
- 0x82, 0xda, 0x3d, 0x47, 0x0c, 0x2b, 0xfe, 0x9d, 0x3f, 0x80, 0x19, 0x41,
- 0x62, 0xff, 0xe3, 0x4c, 0xdc, 0x8c, 0x7b, 0x1e, 0xdd, 0xbf, 0xd9, 0x58,
- 0xbe, 0x9c, 0xd4, 0x16, 0x28, 0x2c, 0x3f, 0xc2, 0x5a, 0xbf, 0x73, 0x8f,
- 0xbf, 0x16, 0x2f, 0xba, 0x77, 0xe9, 0x51, 0x74, 0x97, 0xe2, 0x17, 0xa7,
- 0x8b, 0x15, 0xa3, 0xd9, 0xf9, 0x8d, 0xf3, 0x8a, 0x07, 0x58, 0xbf, 0x86,
- 0x1c, 0x18, 0x1c, 0x58, 0xaf, 0x9e, 0x9b, 0x91, 0xdf, 0x13, 0x8e, 0x56,
- 0x2f, 0xf4, 0xef, 0x72, 0x9d, 0xfc, 0x58, 0xa9, 0x3d, 0x7f, 0x90, 0xdf,
- 0xfc, 0x14, 0xe7, 0x22, 0x80, 0x5f, 0x6e, 0xdf, 0xec, 0xac, 0x5f, 0xd0,
- 0x9e, 0xdf, 0x90, 0x58, 0xbf, 0xe2, 0x8b, 0x53, 0xdc, 0x18, 0xeb, 0x17,
- 0xfe, 0xdf, 0x25, 0xee, 0x0b, 0xd9, 0xa5, 0x8b, 0xff, 0xff, 0xcd, 0xb4,
- 0x2d, 0x85, 0x36, 0x1f, 0xe5, 0x86, 0x52, 0x2e, 0x8c, 0x71, 0xcf, 0x7c,
- 0x58, 0xa9, 0x4c, 0x23, 0x0e, 0xc9, 0x06, 0xfa, 0x1b, 0xb9, 0xe5, 0x8b,
- 0xee, 0x4e, 0xef, 0x16, 0x2a, 0x4f, 0x33, 0x74, 0x9a, 0xef, 0x6e, 0xac,
- 0x5f, 0x8d, 0x34, 0x32, 0xe9, 0x62, 0xa4, 0xf2, 0x18, 0x6e, 0xfb, 0xa3,
- 0xb6, 0xe2, 0xc5, 0xce, 0x35, 0x8b, 0xf4, 0x1a, 0x61, 0xb8, 0xb1, 0x5b,
- 0x4f, 0x0b, 0x05, 0xef, 0x0f, 0x06, 0xb1, 0x76, 0xa3, 0x58, 0xa9, 0x46,
- 0x10, 0xda, 0x70, 0x8d, 0x87, 0x6f, 0xff, 0xfe, 0xfe, 0x6f, 0xd6, 0x73,
- 0x35, 0xd4, 0xe7, 0x8b, 0x39, 0xcc, 0x1a, 0xc5, 0xfe, 0x8e, 0x4b, 0xa1,
- 0x87, 0xc5, 0x8b, 0xff, 0x80, 0xc4, 0x19, 0xad, 0xe7, 0x07, 0x16, 0x2f,
- 0xf9, 0xb0, 0xbf, 0x9e, 0x91, 0xac, 0x5f, 0xf9, 0x8b, 0x53, 0xe6, 0xe9,
- 0x86, 0xb1, 0x51, 0xa3, 0xc8, 0x06, 0xfe, 0x46, 0xde, 0x6f, 0x7f, 0xb7,
- 0xcf, 0xb8, 0x2e, 0x82, 0xeb, 0x15, 0x29, 0xf0, 0xe4, 0x6c, 0xae, 0x81,
- 0x7f, 0xdf, 0x63, 0x3d, 0xdf, 0x4d, 0xf5, 0x8b, 0xf0, 0x81, 0x11, 0x79,
- 0x62, 0x86, 0x7c, 0xfa, 0x3d, 0xb9, 0xc3, 0x58, 0xbf, 0xf7, 0xb6, 0xf1,
- 0xcb, 0xaf, 0xb6, 0x96, 0x2d, 0xc8, 0xcf, 0x6b, 0x06, 0x2f, 0xf4, 0xf9,
- 0xe3, 0x13, 0x41, 0x62, 0xe0, 0xfe, 0xb1, 0x44, 0x79, 0xa1, 0x9a, 0x5f,
- 0xff, 0x9e, 0x05, 0x3c, 0xce, 0xfa, 0x27, 0xce, 0xfa, 0x58, 0xbf, 0xe6,
- 0xfe, 0x76, 0x08, 0x0f, 0x16, 0x2c, 0x10, 0x28, 0xcc, 0xa2, 0xd8, 0x8e,
- 0x36, 0x08, 0x4e, 0x6c, 0x22, 0x50, 0xb0, 0xce, 0x63, 0x2a, 0x8c, 0xba,
- 0x10, 0xb6, 0x19, 0x36, 0x42, 0x0f, 0xa7, 0x56, 0x78, 0xdc, 0x21, 0x89,
- 0x63, 0x51, 0x9b, 0x9d, 0xeb, 0xed, 0x8f, 0x0e, 0x22, 0x94, 0x37, 0xc8,
- 0x4d, 0xf9, 0xf0, 0x4e, 0xbb, 0xc8, 0xb6, 0x55, 0xee, 0x9d, 0x95, 0x8b,
- 0xff, 0xc5, 0xe6, 0x3f, 0xe5, 0x89, 0xf4, 0x6a, 0xc5, 0xfc, 0xfe, 0x93,
- 0xc9, 0x2c, 0x56, 0x1f, 0xae, 0x92, 0x6f, 0xfc, 0x7e, 0x0b, 0xd0, 0x6d,
- 0xff, 0x65, 0x8b, 0xfb, 0x33, 0x9d, 0x7a, 0x56, 0x2f, 0xe8, 0xe7, 0xce,
- 0x68, 0x96, 0x29, 0x62, 0xff, 0xe9, 0xd0, 0x36, 0xf3, 0xf2, 0x77, 0x25,
- 0x8b, 0xfe, 0x17, 0x9b, 0xec, 0x6f, 0xd9, 0x62, 0xff, 0x4e, 0x83, 0xff,
- 0xf0, 0x0b, 0x15, 0x04, 0x5a, 0x8d, 0x1b, 0xe7, 0x57, 0xf4, 0x1e, 0x0e,
- 0x5d, 0x2c, 0x52, 0xc5, 0xa5, 0x62, 0x86, 0x5e, 0x90, 0x65, 0xb8, 0xb1,
- 0x52, 0x6c, 0x7c, 0x3f, 0x7f, 0xfb, 0x3d, 0x26, 0x07, 0x1f, 0x30, 0xf3,
- 0xb8, 0xb1, 0x63, 0xac, 0x5f, 0xcf, 0x0d, 0x31, 0x8c, 0xb1, 0x7c, 0x52,
- 0x3d, 0x2c, 0x5f, 0xf9, 0xa0, 0xda, 0xee, 0x4a, 0x78, 0xb1, 0x51, 0x9f,
- 0x07, 0x88, 0xac, 0x10, 0x28, 0xaa, 0x83, 0x21, 0x83, 0x11, 0x87, 0xdf,
- 0x08, 0x83, 0xca, 0x1b, 0x22, 0x41, 0xc2, 0x3a, 0xb4, 0xad, 0x70, 0xf2,
- 0xb4, 0x2f, 0xb0, 0xc0, 0xa1, 0xd6, 0x2f, 0xe2, 0x9e, 0xce, 0xfe, 0x58,
- 0xbf, 0xfc, 0x63, 0x8f, 0xf3, 0xdf, 0xa7, 0xef, 0xb8, 0xb1, 0x66, 0xd1,
- 0xfe, 0xfc, 0xba, 0xff, 0xff, 0x85, 0xa8, 0x73, 0xee, 0xda, 0xd6, 0x85,
- 0xdb, 0x69, 0xf8, 0xb1, 0x7e, 0xc3, 0x39, 0x9f, 0x58, 0xbf, 0xf7, 0x53,
- 0x9f, 0x9f, 0x14, 0xf9, 0x62, 0xfe, 0x72, 0xfc, 0xea, 0x0b, 0x15, 0xa3,
- 0xeb, 0xe1, 0xf5, 0xe1, 0x7f, 0x8b, 0x17, 0xfe, 0x73, 0x7a, 0xfb, 0x45,
- 0xa9, 0x31, 0x62, 0xf4, 0xe7, 0x7d, 0x1f, 0x09, 0x0f, 0x5f, 0xfc, 0xe7,
- 0xe7, 0x89, 0xc1, 0xdf, 0x82, 0xc5, 0x8b, 0x7b, 0x47, 0xfc, 0x23, 0x3b,
- 0xff, 0x13, 0x99, 0xec, 0xfb, 0xc4, 0xeb, 0x17, 0xff, 0xe0, 0x02, 0x76,
- 0xfe, 0x7c, 0x2e, 0xbf, 0x24, 0xeb, 0x17, 0xff, 0xe2, 0x13, 0xee, 0x64,
- 0x3f, 0x86, 0xe0, 0xe2, 0x12, 0xc5, 0x62, 0x2c, 0xbe, 0xb1, 0x77, 0x58,
- 0xb1, 0x7f, 0x4c, 0x1b, 0xbf, 0x62, 0xc5, 0xff, 0xf3, 0xf7, 0x0e, 0x77,
- 0xe2, 0x7f, 0xe7, 0x7e, 0x58, 0xa9, 0x45, 0xd9, 0xa4, 0x5a, 0x18, 0x72,
- 0xeb, 0xed, 0x71, 0xb4, 0xb1, 0x7f, 0xb0, 0x41, 0x7e, 0xbe, 0xd1, 0x2c,
- 0x5f, 0xff, 0xff, 0x7a, 0x5a, 0x0f, 0xce, 0x4f, 0x33, 0xec, 0x52, 0x7d,
- 0x48, 0x6e, 0x4b, 0x17, 0xee, 0x4f, 0xc3, 0x89, 0x62, 0x99, 0x14, 0xbe,
- 0x7a, 0xa9, 0x4c, 0x93, 0x08, 0xde, 0x1b, 0xf7, 0xa1, 0x27, 0x58, 0xa5,
- 0x8b, 0xfb, 0x07, 0xac, 0x68, 0x96, 0x2f, 0xf4, 0x65, 0x9d, 0xfb, 0x0c,
- 0x58, 0xbf, 0x77, 0xe9, 0xc3, 0x08, 0xf9, 0x03, 0x2e, 0xad, 0x81, 0x16,
- 0x18, 0xe1, 0x77, 0x20, 0xb1, 0x7f, 0xfd, 0x83, 0x17, 0xb9, 0xd7, 0xdb,
- 0x82, 0x7e, 0xd6, 0x2f, 0xff, 0x9e, 0x1c, 0x0c, 0x85, 0x1f, 0xb9, 0x84,
- 0x05, 0x8a, 0xfa, 0x29, 0x44, 0xa7, 0x46, 0xa3, 0x83, 0xd0, 0xbd, 0xbf,
- 0xda, 0xd3, 0xc2, 0x3c, 0x31, 0x62, 0x96, 0x2e, 0x88, 0x4b, 0x15, 0x87,
- 0xb7, 0xf3, 0x63, 0x03, 0x2f, 0xfb, 0xe1, 0xf9, 0xb4, 0xd1, 0xca, 0xc5,
- 0xff, 0xfc, 0x28, 0x13, 0x40, 0xb3, 0xdc, 0x98, 0x0e, 0x7c, 0xb1, 0x7f,
- 0xe9, 0xef, 0xaf, 0xb6, 0xb4, 0xf0, 0x58, 0xbf, 0xd1, 0x96, 0x77, 0xec,
- 0x31, 0x62, 0xfe, 0x1b, 0xf7, 0xec, 0x39, 0xcf, 0xdc, 0x34, 0x1b, 0xed,
- 0x49, 0x9c, 0x58, 0xbd, 0xfc, 0x89, 0x62, 0xff, 0xf1, 0x7b, 0x98, 0xc7,
- 0xc1, 0xcc, 0x27, 0x0f, 0x0b, 0xc4, 0x94, 0xc8, 0xe5, 0x14, 0x22, 0x2a,
- 0x0a, 0x91, 0xf0, 0xbd, 0x8e, 0xf9, 0x1d, 0xb5, 0xff, 0xd8, 0x39, 0x84,
- 0xea, 0x43, 0x72, 0x58, 0xbf, 0xf6, 0xfc, 0x81, 0xc6, 0xdb, 0xe4, 0x6b,
- 0x17, 0xff, 0xcd, 0xf1, 0x1c, 0xef, 0x0f, 0xb9, 0xdb, 0x8b, 0x14, 0x74,
- 0x6b, 0x3a, 0x1f, 0x90, 0xee, 0x70, 0x91, 0xb2, 0xd3, 0x20, 0xd3, 0x90,
- 0x94, 0xee, 0x30, 0x18, 0x8a, 0x35, 0x1d, 0x67, 0xe3, 0x60, 0x73, 0x32,
- 0x86, 0x6f, 0x23, 0x07, 0xf4, 0xac, 0xb0, 0xe3, 0x19, 0xaf, 0xb3, 0x16,
- 0x4a, 0x96, 0xe7, 0x7e, 0xe1, 0xe4, 0xa2, 0x58, 0xbf, 0xd0, 0xcf, 0x7e,
- 0x43, 0x25, 0x8b, 0xff, 0x79, 0xba, 0x61, 0xb9, 0x1b, 0x2b, 0x17, 0x86,
- 0xc6, 0xac, 0x5f, 0xf4, 0xf7, 0xf7, 0xe7, 0xa4, 0xc5, 0x8a, 0x94, 0x4c,
- 0x61, 0xfe, 0x87, 0xaf, 0xf3, 0xf8, 0x85, 0x1f, 0x7b, 0x8b, 0x16, 0x0a,
- 0xac, 0x5c, 0x2f, 0xac, 0x5f, 0x8b, 0x3e, 0xfe, 0x58, 0xbf, 0xa0, 0xf9,
- 0xbe, 0x46, 0xb1, 0x41, 0x53, 0xd6, 0xd8, 0x44, 0xf7, 0xed, 0x8c, 0x2b,
- 0xae, 0x71, 0x62, 0xf9, 0x85, 0x09, 0x58, 0xbe, 0xce, 0xe4, 0xeb, 0x17,
- 0xcc, 0x52, 0x05, 0x8b, 0xff, 0xff, 0x69, 0xb7, 0xc8, 0xd8, 0x9f, 0x46,
- 0xed, 0xfb, 0xf0, 0xc9, 0x1a, 0xc5, 0xfe, 0xfc, 0xc7, 0xa9, 0xc1, 0xac,
- 0x5f, 0xa7, 0x7b, 0xe6, 0x96, 0x2e, 0xc8, 0xd6, 0x2e, 0x1c, 0xac, 0x50,
- 0x66, 0xbf, 0x74, 0x62, 0xa5, 0x16, 0x3f, 0x34, 0x12, 0xc5, 0xf9, 0xe2,
- 0x83, 0x79, 0x62, 0xff, 0x0b, 0x75, 0xb7, 0xfb, 0x3e, 0xb1, 0x7f, 0xe9,
- 0x1e, 0xa6, 0x0d, 0xdf, 0xb1, 0x62, 0xff, 0xf9, 0xff, 0x30, 0x1f, 0xe7,
- 0xbf, 0x31, 0xf8, 0xb1, 0x50, 0x55, 0x52, 0x69, 0x17, 0x44, 0x7a, 0x21,
- 0xfc, 0x64, 0x40, 0x2f, 0x22, 0x9f, 0x1c, 0xef, 0x3f, 0xbf, 0xed, 0x73,
- 0xed, 0xd7, 0x42, 0x8d, 0x62, 0xfe, 0x33, 0x37, 0x90, 0xa0, 0xb1, 0x7f,
- 0x08, 0xdc, 0x2d, 0xdc, 0x58, 0xbf, 0xff, 0xdf, 0x63, 0x9d, 0x8c, 0xe7,
- 0x7d, 0x36, 0x68, 0x73, 0xda, 0xc5, 0xff, 0xf4, 0xc3, 0x38, 0xc4, 0x02,
- 0xcf, 0x7f, 0x16, 0x2e, 0xd4, 0x3a, 0x45, 0x91, 0x32, 0xd4, 0xa7, 0x03,
- 0x87, 0xc4, 0x62, 0x28, 0x71, 0xdf, 0xff, 0xf4, 0x8f, 0xf9, 0xdf, 0x89,
- 0xfe, 0x07, 0xe7, 0x1f, 0x5d, 0x2c, 0x5f, 0xef, 0x72, 0x62, 0x77, 0xd2,
- 0xc5, 0xf4, 0x7b, 0x2e, 0x6a, 0xc5, 0xfe, 0xcc, 0xc3, 0x4d, 0x78, 0x2c,
- 0x51, 0xa8, 0xf8, 0x66, 0x8f, 0x9a, 0x78, 0xa2, 0xfb, 0x9d, 0x7a, 0x56,
- 0x2f, 0xf3, 0x1d, 0xb5, 0xc8, 0x4a, 0xc5, 0x61, 0xeb, 0xf8, 0x92, 0xff,
- 0xf3, 0x19, 0xce, 0xbe, 0xdd, 0xfb, 0x5a, 0x95, 0x8b, 0xff, 0x6b, 0xcf,
- 0x0e, 0x6f, 0x16, 0x99, 0x62, 0xff, 0xe7, 0xe1, 0x39, 0xa3, 0xf8, 0x9f,
- 0x8b, 0x15, 0x28, 0x87, 0x12, 0x15, 0xff, 0xff, 0x39, 0x81, 0xe6, 0x89,
- 0xfb, 0x87, 0x53, 0xee, 0x67, 0x7e, 0x58, 0xbf, 0x16, 0x02, 0x40, 0xb1,
- 0x7f, 0x46, 0x1e, 0x7d, 0xfb, 0x58, 0xbf, 0xd0, 0x62, 0x8a, 0x0d, 0xf5,
- 0x8b, 0x4c, 0x11, 0x19, 0x84, 0xf1, 0x18, 0xd6, 0x2a, 0x44, 0xd1, 0x0f,
- 0xe1, 0xaa, 0xe4, 0x45, 0x0f, 0x7b, 0xf6, 0xf6, 0xd6, 0x0d, 0x62, 0xff,
- 0xfb, 0x9f, 0x6e, 0x7b, 0xf8, 0x36, 0xe6, 0x12, 0xc5, 0x8b, 0x0f, 0xe4,
- 0x45, 0x57, 0xf8, 0x9f, 0x46, 0xfb, 0x3a, 0x58, 0xb7, 0xe4, 0xf6, 0xf0,
- 0x9a, 0xfc, 0xff, 0x81, 0x74, 0xb1, 0x7f, 0xa4, 0xf8, 0xc7, 0x9d, 0xc5,
- 0x8b, 0xfd, 0x03, 0xf1, 0x8b, 0xb8, 0x2c, 0x57, 0x47, 0xd5, 0x11, 0xad,
- 0xfe, 0x6d, 0x39, 0x03, 0x09, 0x62, 0xff, 0x79, 0x8b, 0x3b, 0x84, 0xac,
- 0x5f, 0xfd, 0xad, 0x3c, 0x38, 0x58, 0x70, 0xfb, 0x58, 0xa9, 0x3f, 0xac,
- 0x33, 0xbf, 0xe6, 0x81, 0x67, 0xc9, 0xe0, 0xb1, 0x7f, 0xfe, 0x86, 0x10,
- 0xff, 0x38, 0x52, 0x03, 0xbc, 0x16, 0x28, 0x91, 0x14, 0x19, 0xbd, 0xe7,
- 0x7e, 0x95, 0x12, 0x61, 0x7b, 0x75, 0xb8, 0xb1, 0x50, 0x3e, 0xde, 0x88,
- 0xf7, 0x4a, 0xaf, 0x82, 0xcd, 0x8c, 0x28, 0x15, 0x58, 0xbf, 0xfd, 0xc1,
- 0xfe, 0x7f, 0x27, 0xd6, 0x9b, 0xa5, 0x8a, 0xe9, 0x10, 0x4e, 0x6d, 0x7f,
- 0xff, 0xfb, 0x3a, 0x91, 0x75, 0xf9, 0xd6, 0xdc, 0x26, 0xef, 0x81, 0xc6,
- 0x58, 0x35, 0x8b, 0xfd, 0xbd, 0xcf, 0x86, 0xcf, 0x16, 0x2f, 0x77, 0x0e,
- 0x6d, 0x45, 0x9e, 0x3e, 0xdf, 0xec, 0xef, 0xde, 0x78, 0x71, 0x62, 0xa5,
- 0x34, 0x2c, 0x86, 0xb6, 0x8d, 0xef, 0xf1, 0x3f, 0xb9, 0xd0, 0x89, 0x62,
- 0xff, 0xf8, 0x0c, 0x03, 0x31, 0xb7, 0x96, 0x7b, 0xec, 0xb1, 0x7a, 0x3f,
- 0x32, 0xc5, 0xff, 0xc4, 0xe6, 0x70, 0xc7, 0x1c, 0xf7, 0xc5, 0x8b, 0x62,
- 0xc5, 0x68, 0xf6, 0x3c, 0x8f, 0x7e, 0xe3, 0xbc, 0x38, 0xb1, 0x7f, 0x3c,
- 0x39, 0x84, 0x05, 0x8b, 0x3e, 0xd4, 0x76, 0x8d, 0xdb, 0xb2, 0x2f, 0x14,
- 0x5b, 0x58, 0x9c, 0x1f, 0xe3, 0x3e, 0xbf, 0xff, 0x9e, 0x32, 0x9e, 0xfb,
- 0xe8, 0x4f, 0xa0, 0x67, 0x7e, 0x58, 0xac, 0x54, 0x8c, 0xd1, 0xdb, 0x91,
- 0x7d, 0xff, 0x3c, 0x39, 0x85, 0x3d, 0xf1, 0x62, 0xfb, 0x90, 0x60, 0x2c,
- 0x5f, 0xff, 0x78, 0xd7, 0xe6, 0xb5, 0x91, 0x80, 0xf3, 0x05, 0x8a, 0x81,
- 0xfb, 0x18, 0x47, 0x7f, 0xff, 0xef, 0xe4, 0x3f, 0x83, 0x29, 0xe8, 0x39,
- 0x33, 0x39, 0xc7, 0x35, 0x62, 0xa5, 0x12, 0x5e, 0x23, 0xbf, 0xf1, 0x98,
- 0x37, 0x87, 0xb8, 0xe0, 0x58, 0xbf, 0xfc, 0x52, 0x60, 0x7e, 0x29, 0x06,
- 0x77, 0xe5, 0x8b, 0xfd, 0x9a, 0xf9, 0x4f, 0x70, 0x58, 0xb9, 0xfb, 0xc4,
- 0x40, 0x06, 0x99, 0x4c, 0x8e, 0xf1, 0x43, 0x02, 0xff, 0xe6, 0xec, 0xcf,
- 0x7d, 0xa4, 0xb3, 0xa5, 0x8b, 0xff, 0x13, 0x9c, 0x0d, 0xa6, 0xec, 0x0b,
- 0x17, 0xd8, 0xda, 0x8d, 0x62, 0x86, 0x7c, 0x41, 0x73, 0xfb, 0xfe, 0x63,
- 0x64, 0x71, 0x9e, 0x74, 0xb1, 0x50, 0x65, 0x63, 0x8c, 0x9b, 0x21, 0x26,
- 0x69, 0x27, 0x50, 0xab, 0xd4, 0x62, 0xe7, 0x8f, 0xdf, 0xf2, 0x9e, 0x80,
- 0x6a, 0x51, 0xa0, 0xf2, 0x31, 0x1f, 0x13, 0x8a, 0x15, 0x1b, 0xc9, 0xaf,
- 0xe1, 0x80, 0x2b, 0xc0, 0x6c, 0xac, 0x5e, 0xdd, 0xdd, 0x95, 0x8b, 0xff,
- 0xb0, 0xcf, 0xbf, 0xb9, 0x3f, 0x0e, 0x25, 0x8b, 0xff, 0xd9, 0xaf, 0xbb,
- 0x78, 0x5a, 0x7d, 0xf8, 0xb1, 0x43, 0x44, 0x9f, 0xd2, 0x2f, 0x71, 0x86,
- 0xb1, 0x7f, 0x14, 0xf6, 0x77, 0xf2, 0xc5, 0xfe, 0xeb, 0xc2, 0xfe, 0xa4,
- 0xc5, 0x8b, 0xff, 0xb3, 0xbf, 0xe0, 0xff, 0x91, 0x41, 0xd6, 0x2a, 0x4f,
- 0xf4, 0xe6, 0xf7, 0xff, 0xff, 0x9a, 0x4b, 0xdd, 0x7d, 0xbd, 0x91, 0x14,
- 0x9f, 0x3e, 0xda, 0xfb, 0xac, 0x5f, 0xf3, 0x61, 0x9d, 0x7e, 0x5b, 0x65,
- 0x62, 0xff, 0xf4, 0x94, 0x30, 0x5a, 0x8c, 0x19, 0x83, 0x58, 0xbf, 0xdd,
- 0x36, 0xb9, 0x14, 0xba, 0xc5, 0xfe, 0x6f, 0x02, 0x7e, 0x1f, 0x16, 0x2f,
- 0x9e, 0x12, 0x4b, 0x17, 0xe1, 0x73, 0xef, 0x08, 0x1e, 0xb7, 0xcd, 0x6f,
- 0xe7, 0x06, 0x10, 0xe0, 0xb1, 0x7f, 0xf3, 0xf7, 0xef, 0xe3, 0x0e, 0x4b,
- 0xa5, 0x8a, 0x35, 0x38, 0x6e, 0xd2, 0xb5, 0x08, 0xb2, 0x3f, 0xe1, 0x6d,
- 0x98, 0x6a, 0xe5, 0xa2, 0x23, 0xd0, 0xe9, 0xe1, 0x57, 0xf2, 0x10, 0xbb,
- 0xb7, 0xa3, 0xc3, 0xbf, 0x0e, 0x79, 0xe6, 0x58, 0xbf, 0x64, 0x67, 0x68,
- 0x96, 0x2a, 0x57, 0x46, 0x7f, 0x38, 0x98, 0xef, 0x64, 0x51, 0x7f, 0xf9,
- 0xc8, 0x00, 0x9c, 0xde, 0xc5, 0xdf, 0x96, 0x2f, 0xbc, 0xc7, 0x75, 0x8b,
- 0xe3, 0x3e, 0x2e, 0x96, 0x2c, 0x6a, 0xc5, 0xfd, 0xfe, 0x4f, 0xa4, 0x6b,
- 0x15, 0x27, 0xcf, 0x84, 0xcc, 0x27, 0x52, 0x98, 0x06, 0x25, 0xfa, 0x11,
- 0x37, 0xff, 0x84, 0xff, 0x71, 0xc0, 0xff, 0x90, 0xc9, 0x62, 0xf1, 0x49,
- 0xd6, 0x2f, 0xcd, 0xcf, 0xce, 0x96, 0x2a, 0x23, 0xc4, 0xf8, 0xe5, 0xfe,
- 0xff, 0x9a, 0x33, 0xcf, 0x4b, 0x17, 0xff, 0xfd, 0xa8, 0xc4, 0x0d, 0xbe,
- 0xe6, 0x7b, 0x6e, 0x7a, 0x70, 0xa0, 0xb1, 0x52, 0x8a, 0x26, 0x36, 0xbf,
- 0xff, 0x3f, 0x5a, 0x9f, 0x96, 0x7b, 0x02, 0x18, 0x61, 0x89, 0x15, 0x05,
- 0x40, 0x9d, 0x1a, 0x3c, 0x23, 0xf9, 0x0c, 0x5f, 0x10, 0xdf, 0xba, 0x17,
- 0x45, 0x2b, 0x17, 0xee, 0x45, 0xf9, 0xf2, 0xc5, 0x74, 0x7a, 0x91, 0x15,
- 0x5f, 0xc1, 0x60, 0x5a, 0xfb, 0x61, 0xec, 0x5b, 0x8b, 0x17, 0xe2, 0xf7,
- 0x42, 0x8d, 0x62, 0xff, 0xee, 0xe0, 0x53, 0x0d, 0x4f, 0x9f, 0xcb, 0x17,
- 0xfc, 0x30, 0xe7, 0xbd, 0x9c, 0xd4, 0xac, 0x5d, 0x30, 0x58, 0xa9, 0x46,
- 0x2e, 0x15, 0xba, 0x29, 0x1f, 0x5f, 0x1f, 0x4f, 0xc5, 0x8b, 0xff, 0x4c,
- 0x79, 0xd4, 0x9d, 0xb9, 0xd2, 0xc5, 0xf0, 0xb7, 0x26, 0x0b, 0x17, 0xfe,
- 0x7f, 0x4e, 0xb9, 0xf9, 0x2f, 0x2c, 0x5f, 0xb2, 0x0c, 0xfb, 0xd6, 0x2b,
- 0xe8, 0x8d, 0x22, 0x6e, 0x1f, 0x54, 0x13, 0x59, 0xc3, 0x9f, 0x91, 0x8a,
- 0x19, 0xd7, 0x8e, 0xff, 0x58, 0xbf, 0xfc, 0x53, 0x0d, 0x68, 0x5d, 0xb6,
- 0x9f, 0x8b, 0x17, 0xff, 0xdc, 0xc3, 0x4b, 0x3d, 0xcc, 0x81, 0x39, 0x8b,
- 0x16, 0x6f, 0xa2, 0x6f, 0xc9, 0x74, 0xc8, 0xe0, 0xdf, 0x0b, 0x8b, 0xfd,
- 0x25, 0xec, 0x29, 0x35, 0x62, 0xf4, 0xff, 0x8b, 0x15, 0xbc, 0xf3, 0xf7,
- 0x4c, 0xaf, 0xfa, 0x4f, 0xef, 0xe1, 0x48, 0x16, 0x2f, 0xc7, 0x98, 0x6e,
- 0x74, 0xb1, 0x7e, 0x29, 0x17, 0xb8, 0xb1, 0x40, 0x3d, 0x5f, 0x16, 0xdf,
- 0xf7, 0x20, 0xde, 0x00, 0x65, 0x05, 0x8a, 0x8c, 0xf7, 0x7b, 0x22, 0xbf,
- 0x8b, 0x3d, 0xf0, 0xcc, 0x58, 0xbf, 0xbd, 0x91, 0x41, 0xc9, 0x62, 0xbb,
- 0x3d, 0xe3, 0x98, 0x56, 0x22, 0x95, 0xa1, 0x05, 0x52, 0xa9, 0x53, 0x1e,
- 0x18, 0x9f, 0x51, 0xc7, 0xdf, 0xff, 0xf7, 0x7d, 0x7d, 0x8e, 0x4d, 0x1c,
- 0xfb, 0x81, 0xfb, 0xf8, 0x35, 0x8b, 0xfe, 0x37, 0x68, 0x79, 0xad, 0x97,
- 0x35, 0x62, 0xc1, 0x75, 0x8a, 0x93, 0xd8, 0x74, 0x2b, 0xff, 0xf8, 0x9c,
- 0xdf, 0xcb, 0x41, 0x8b, 0xd0, 0xcd, 0x62, 0xc5, 0x4a, 0x67, 0x85, 0x0c,
- 0x31, 0x10, 0x5f, 0xfe, 0x06, 0x77, 0xec, 0x21, 0x78, 0x13, 0x05, 0x8b,
- 0xff, 0x9b, 0x98, 0x3e, 0xa6, 0x39, 0xcf, 0x2c, 0x5f, 0x85, 0xff, 0x4c,
- 0x4b, 0x17, 0xff, 0xf7, 0xdf, 0x5f, 0x62, 0xc1, 0xe9, 0x85, 0x18, 0x67,
- 0x58, 0xbf, 0xfe, 0xf4, 0xf4, 0xde, 0x63, 0xed, 0xe3, 0x8c, 0x6b, 0x17,
- 0xfb, 0x39, 0x17, 0xd8, 0xcf, 0x2c, 0x5f, 0xef, 0xb9, 0xc7, 0x9b, 0x4e,
- 0xb1, 0x7f, 0xda, 0xd4, 0xe3, 0xeb, 0xb8, 0x2c, 0x5c, 0x09, 0x58, 0xa9,
- 0x45, 0xe8, 0xcd, 0x98, 0xd8, 0x07, 0x57, 0xfe, 0xfb, 0x6f, 0xcd, 0xc1,
- 0x93, 0xe9, 0x62, 0xf8, 0x51, 0xf7, 0xb8, 0xb1, 0x5d, 0x1f, 0x61, 0x21,
- 0xd0, 0xd5, 0x1b, 0x32, 0xef, 0x23, 0x10, 0xf4, 0x29, 0xef, 0xff, 0x4c,
- 0x65, 0x99, 0x1f, 0x8d, 0x92, 0x82, 0xc5, 0xfe, 0x8f, 0xee, 0x76, 0xe3,
- 0x2c, 0x5f, 0xe1, 0xbb, 0x98, 0x1e, 0x76, 0xb1, 0x67, 0x23, 0xea, 0xf1,
- 0xa5, 0x62, 0xe0, 0xa7, 0x49, 0x7f, 0x45, 0x79, 0x4c, 0x04, 0x92, 0x64,
- 0x2d, 0x6f, 0xfe, 0x16, 0xe7, 0xf3, 0x06, 0x59, 0x1c, 0xac, 0x5f, 0xf7,
- 0x9b, 0x8c, 0x20, 0xb8, 0xe5, 0x62, 0xf1, 0x86, 0x18, 0x91, 0x7d, 0x19,
- 0xdb, 0x89, 0x01, 0x0d, 0x0d, 0xd2, 0x35, 0x8a, 0x73, 0xcd, 0x23, 0x6b,
- 0xf0, 0x7f, 0x7f, 0xca, 0xc5, 0xff, 0x37, 0x26, 0x11, 0x7d, 0x80, 0xb1,
- 0x7f, 0xb3, 0xbd, 0x66, 0xcb, 0x01, 0x62, 0x86, 0x9d, 0x63, 0x23, 0xea,
- 0x15, 0x67, 0x20, 0xf9, 0x49, 0x1d, 0x5f, 0xff, 0xb8, 0x59, 0xff, 0x14,
- 0x82, 0x13, 0x3c, 0x65, 0x8b, 0x7d, 0x62, 0xbb, 0x3e, 0x50, 0xd4, 0xef,
- 0xd3, 0x84, 0xe7, 0x58, 0xbf, 0xf3, 0xc3, 0xed, 0xd8, 0x34, 0xe3, 0x58,
- 0xbd, 0xed, 0x62, 0xc5, 0xc3, 0x31, 0x62, 0xff, 0xfd, 0x9b, 0xe4, 0xbc,
- 0x79, 0xc2, 0x1e, 0x77, 0xe5, 0x8b, 0xce, 0x5d, 0x4a, 0x23, 0x23, 0x1d,
- 0xd0, 0xcd, 0x32, 0x6a, 0xe0, 0x24, 0x22, 0x61, 0x43, 0x32, 0xfd, 0xa8,
- 0xe7, 0x51, 0xac, 0x5f, 0x98, 0xbc, 0x19, 0xd6, 0x2d, 0x09, 0x3d, 0x40,
- 0x15, 0xdf, 0xff, 0xbe, 0xdd, 0x7f, 0x3d, 0xf6, 0x70, 0x7d, 0x80, 0xb1,
- 0x7f, 0xfb, 0xf9, 0xce, 0x61, 0xc6, 0xdb, 0xe4, 0x6b, 0x17, 0xf4, 0x9e,
- 0x2f, 0xb6, 0x96, 0x2f, 0xdc, 0xc3, 0xbf, 0x6b, 0x17, 0xe3, 0x76, 0xe6,
- 0x69, 0x62, 0xb0, 0xf5, 0x04, 0x53, 0x7e, 0xe3, 0x61, 0x01, 0x62, 0xb4,
- 0x79, 0x1c, 0x21, 0xbd, 0xac, 0xdc, 0x58, 0xbf, 0xfc, 0x2e, 0x7d, 0xb2,
- 0x26, 0x8f, 0x3b, 0xf2, 0xc5, 0xff, 0x18, 0x1c, 0x7c, 0xc3, 0xce, 0xe2,
- 0xc5, 0xff, 0xe1, 0x77, 0x9a, 0x0f, 0xdc, 0xc3, 0x5b, 0x4b, 0x17, 0xff,
- 0x9b, 0xac, 0x21, 0xe9, 0xfa, 0xce, 0xfc, 0xb1, 0x52, 0x8d, 0xaf, 0xa0,
- 0x71, 0x3a, 0xff, 0xcc, 0x41, 0xe4, 0x5c, 0x6e, 0xcc, 0x58, 0xbe, 0x70,
- 0x78, 0x2e, 0xb1, 0x58, 0xad, 0xbb, 0xa5, 0x68, 0x93, 0x35, 0x0c, 0xb3,
- 0x91, 0x11, 0x07, 0xa3, 0x27, 0xde, 0x5e, 0x62, 0x15, 0xfb, 0x3b, 0xf7,
- 0xe5, 0x62, 0xfc, 0xdb, 0xfd, 0x38, 0xb1, 0x7f, 0x81, 0x25, 0xf7, 0x73,
- 0xac, 0x57, 0xd1, 0x09, 0xc2, 0x9f, 0x14, 0xd4, 0xae, 0x6b, 0xe4, 0xb9,
- 0x57, 0x8c, 0x4a, 0xff, 0xfc, 0xdc, 0xe4, 0xea, 0x1a, 0x9f, 0x70, 0x32,
- 0x82, 0xc5, 0xfc, 0x1e, 0x6b, 0x65, 0xcd, 0x58, 0xbf, 0x66, 0xb6, 0x5c,
- 0xd5, 0x8b, 0xb3, 0x9b, 0x4f, 0x7c, 0x33, 0x3b, 0xff, 0xd1, 0x14, 0xfb,
- 0x9e, 0xef, 0xa6, 0x28, 0xd6, 0x2f, 0xfd, 0x85, 0xed, 0x3b, 0xf7, 0x0e,
- 0x2c, 0x5f, 0xf3, 0x9b, 0xb7, 0xf2, 0x09, 0xdc, 0x58, 0xbf, 0xa6, 0x19,
- 0xbd, 0xb4, 0xb1, 0x58, 0x99, 0x5b, 0x18, 0x7d, 0x39, 0xcf, 0xc8, 0xfe,
- 0xff, 0xff, 0xc0, 0x0c, 0xb3, 0x5a, 0xc3, 0x33, 0x73, 0x0a, 0x40, 0x77,
- 0x82, 0xc5, 0xff, 0xff, 0xff, 0x16, 0x70, 0x1d, 0x61, 0x37, 0x7c, 0x2c,
- 0xf7, 0x32, 0x04, 0xe6, 0x77, 0xe1, 0x3f, 0x16, 0x2c, 0xc4, 0x98, 0x26,
- 0xf6, 0xfb, 0xff, 0xfb, 0xdc, 0x10, 0xfe, 0xd9, 0x13, 0xb6, 0xe3, 0x77,
- 0x05, 0x8b, 0xff, 0xf8, 0xb0, 0x0e, 0x40, 0xd6, 0xb0, 0xcc, 0x03, 0xf6,
- 0xb1, 0x44, 0x8b, 0xbf, 0x30, 0x5f, 0x9b, 0xd1, 0xe1, 0x8b, 0x17, 0xfd,
- 0x3d, 0x7c, 0x85, 0xe9, 0xe2, 0xc5, 0xfa, 0x28, 0x36, 0xb8, 0xb1, 0x7f,
- 0xd3, 0xd4, 0x9f, 0x06, 0xe7, 0x58, 0xad, 0x1f, 0x1e, 0xe9, 0x55, 0xfb,
- 0x70, 0x32, 0x9e, 0x96, 0x29, 0x8f, 0x49, 0xc9, 0x6f, 0xfe, 0x87, 0x32,
- 0x46, 0xc4, 0xfa, 0x35, 0x62, 0xfd, 0xa9, 0xc1, 0xb2, 0xc5, 0xfd, 0xf6,
- 0x18, 0xf0, 0xc5, 0x8b, 0xf6, 0xb3, 0x7f, 0xf3, 0x69, 0xeb, 0x74, 0x4f,
- 0x52, 0x8d, 0xd7, 0x84, 0xd5, 0xff, 0xff, 0xf0, 0x39, 0x90, 0xfc, 0xb6,
- 0x80, 0x09, 0xd6, 0x08, 0xd1, 0xb6, 0x9f, 0x8b, 0x17, 0xff, 0xdf, 0xc8,
- 0x6d, 0xeb, 0xed, 0xee, 0xfa, 0x6d, 0x2c, 0x54, 0xa3, 0x53, 0xcf, 0xd7,
- 0xff, 0xf0, 0x5d, 0xbd, 0xf9, 0xd6, 0x9b, 0xbf, 0xe6, 0x17, 0x4b, 0x15,
- 0x05, 0xc9, 0x96, 0x87, 0x2e, 0x88, 0x8e, 0x55, 0xf8, 0x77, 0x82, 0x1f,
- 0xa5, 0x0f, 0xa1, 0x11, 0x5f, 0xfe, 0xf4, 0x9f, 0xa7, 0x1e, 0x18, 0x1e,
- 0xa0, 0xb1, 0x7f, 0xef, 0xc9, 0x1b, 0xd3, 0x49, 0x41, 0x62, 0xf4, 0x7b,
- 0xc6, 0xb1, 0x50, 0x3e, 0x02, 0x3f, 0xbf, 0xf3, 0xeb, 0x69, 0x3f, 0xa0,
- 0xe3, 0x58, 0xbf, 0xff, 0x98, 0x87, 0xac, 0xeb, 0xf3, 0xfc, 0xd6, 0xa4,
- 0xd5, 0x8a, 0x82, 0x27, 0x3e, 0x81, 0x7f, 0x3b, 0xfb, 0x65, 0xba, 0x58,
- 0xbf, 0xfc, 0x6e, 0x7d, 0xfd, 0xce, 0xe0, 0x27, 0xf2, 0xc5, 0xff, 0xff,
- 0xfe, 0xd7, 0x39, 0x3a, 0xeb, 0xaf, 0xb4, 0x4e, 0xfa, 0xce, 0xfd, 0xdf,
- 0x42, 0x72, 0xef, 0xcb, 0x17, 0xfc, 0x77, 0x18, 0x7b, 0xb2, 0x50, 0x58,
- 0xbf, 0xee, 0x85, 0xb9, 0xc6, 0x33, 0x34, 0xb1, 0x52, 0x7f, 0x9d, 0x1e,
- 0xdf, 0xfd, 0xf6, 0x88, 0x9c, 0xcf, 0x67, 0xce, 0xb1, 0x7e, 0x6c, 0xe3,
- 0x92, 0xc5, 0xfb, 0xc2, 0xd3, 0xf3, 0xa3, 0xec, 0xf2, 0x35, 0xff, 0xee,
- 0x66, 0xb6, 0xf5, 0xf6, 0xde, 0xc4, 0x35, 0x8a, 0x64, 0x47, 0xf1, 0x02,
- 0xff, 0xfc, 0xe5, 0x18, 0xff, 0x3a, 0xd6, 0x73, 0x82, 0x25, 0x8a, 0xc5,
- 0x54, 0xed, 0x18, 0x93, 0xc6, 0x3a, 0x61, 0x15, 0xff, 0x98, 0x62, 0xf7,
- 0x24, 0x9b, 0x16, 0x2f, 0xf8, 0xf3, 0xad, 0xf9, 0xa9, 0x89, 0x62, 0xff,
- 0xfd, 0xa6, 0x14, 0x7e, 0xfc, 0xb6, 0xb4, 0xc5, 0x1a, 0xc5, 0xff, 0xd3,
- 0x9a, 0x83, 0xfb, 0xee, 0x40, 0x58, 0xbf, 0xff, 0x7c, 0x5d, 0xfb, 0x8f,
- 0xdf, 0x5b, 0x39, 0xce, 0x62, 0xc5, 0xff, 0x39, 0xdf, 0xdf, 0x72, 0x02,
- 0xc5, 0xb0, 0x69, 0x97, 0xfd, 0x5f, 0xc8, 0x7b, 0xd7, 0x6f, 0xfd, 0xae,
- 0x8f, 0x3d, 0xf3, 0x37, 0xe2, 0xc5, 0xcf, 0xb8, 0xb1, 0x79, 0xf4, 0x6a,
- 0xc5, 0xff, 0xfd, 0x11, 0x48, 0xf3, 0xbf, 0x64, 0x24, 0xa3, 0x3e, 0x2c,
- 0x5d, 0x87, 0x58, 0xbf, 0xf1, 0x60, 0xd9, 0xca, 0x33, 0xe2, 0xc5, 0xe0,
- 0x6c, 0xe0, 0xcf, 0x50, 0x31, 0x7a, 0xd2, 0x60, 0xbf, 0x1e, 0x28, 0x58,
- 0x5f, 0x79, 0xf5, 0xc5, 0x8b, 0xf6, 0xdd, 0x9c, 0xd4, 0xac, 0x54, 0x67,
- 0xa0, 0x44, 0x75, 0x2a, 0x82, 0x63, 0x43, 0xc8, 0xc7, 0xde, 0x10, 0xb7,
- 0xfd, 0x06, 0xf7, 0x3a, 0x9f, 0x71, 0x62, 0xfe, 0x06, 0xdc, 0x1b, 0xc1,
- 0x62, 0xa2, 0x3e, 0xb7, 0x3b, 0xb1, 0xab, 0x17, 0xff, 0x67, 0x5f, 0x9f,
- 0xe6, 0xb5, 0x26, 0xac, 0x5f, 0xb3, 0x5a, 0x93, 0x56, 0x2f, 0x89, 0x81,
- 0xc9, 0x44, 0x16, 0x84, 0xfe, 0x8d, 0x7f, 0xdf, 0x70, 0x1d, 0xe0, 0xfc,
- 0x58, 0xbf, 0xcf, 0x08, 0x4c, 0x3a, 0xe2, 0xc5, 0x61, 0xf7, 0x08, 0xe6,
- 0xff, 0xff, 0xe6, 0xf7, 0xf0, 0x70, 0x6f, 0x61, 0xf8, 0xf0, 0xd9, 0xce,
- 0x73, 0x16, 0x2b, 0x13, 0xec, 0x68, 0x52, 0x7e, 0x16, 0x7c, 0x21, 0xbf,
- 0xfc, 0xf1, 0xfd, 0xa4, 0xb2, 0x26, 0xd3, 0x2c, 0x54, 0x1b, 0x46, 0xb1,
- 0xc7, 0xc3, 0x93, 0xbc, 0x9d, 0xc2, 0x19, 0xa1, 0x5d, 0x14, 0x2f, 0x74,
- 0x46, 0x73, 0x1f, 0xca, 0xf4, 0x74, 0x90, 0x1e, 0x94, 0x6d, 0x7c, 0x94,
- 0x9d, 0xe9, 0x53, 0xe6, 0x23, 0x5f, 0xf7, 0xdf, 0x8c, 0x45, 0x3d, 0xac,
- 0x5f, 0xe6, 0xfc, 0xf7, 0x0c, 0x3a, 0xc5, 0xf6, 0x13, 0x0f, 0x87, 0xd9,
- 0xb2, 0x71, 0x7f, 0xf1, 0x7b, 0x81, 0xf9, 0x8a, 0x7b, 0x82, 0xc5, 0xf8,
- 0xb3, 0xef, 0xe5, 0x8b, 0xff, 0x42, 0x4a, 0x30, 0xf4, 0x42, 0x82, 0xc5,
- 0xee, 0x66, 0x96, 0x2f, 0xe2, 0x71, 0x83, 0xb0, 0x2c, 0x56, 0x23, 0xeb,
- 0x71, 0x1a, 0x22, 0x7f, 0xa0, 0xf0, 0x76, 0xff, 0xe7, 0x28, 0x69, 0xfb,
- 0xfc, 0xe7, 0x16, 0x2f, 0xfe, 0xe9, 0xb5, 0xfc, 0x8b, 0xed, 0xa8, 0xd6,
- 0x2f, 0xff, 0x16, 0x18, 0xe0, 0xdb, 0xef, 0xcb, 0x74, 0xb1, 0x7d, 0xe8,
- 0xf0, 0x6b, 0x17, 0xfc, 0xc6, 0x87, 0xa0, 0x1d, 0xb8, 0xb1, 0x46, 0xa2,
- 0xb6, 0x24, 0xdd, 0x92, 0x4b, 0xff, 0x8b, 0x01, 0x9b, 0xd8, 0xd0, 0x3f,
- 0x96, 0x2f, 0xfc, 0xdd, 0xf0, 0x0e, 0x43, 0x88, 0x4b, 0x17, 0x8c, 0x30,
- 0xc5, 0x8b, 0xff, 0x8a, 0x41, 0x83, 0xe6, 0x1e, 0x7a, 0x48, 0x08, 0x68,
- 0x68, 0x08, 0xb8, 0xf3, 0x15, 0xfe, 0xfb, 0x60, 0xe4, 0xbc, 0xb1, 0x50,
- 0x4d, 0x4c, 0xf0, 0xfe, 0xde, 0x47, 0x7f, 0xe7, 0x07, 0x5f, 0x68, 0x8a,
- 0x40, 0xb1, 0x58, 0x7f, 0x0c, 0x71, 0x7f, 0x6b, 0x37, 0x7e, 0xe3, 0x58,
- 0xbf, 0xf6, 0x77, 0xb4, 0xb3, 0x7e, 0x9b, 0x8b, 0x17, 0xf7, 0x5f, 0x69,
- 0x2e, 0x96, 0x2a, 0x4f, 0xcb, 0x10, 0xef, 0xf6, 0xa7, 0xcd, 0xd3, 0x0d,
- 0x62, 0xfd, 0x08, 0xb3, 0x3a, 0x58, 0xbf, 0xc2, 0x8e, 0x58, 0x78, 0x75,
- 0x8b, 0x69, 0x62, 0xb6, 0x24, 0x52, 0x49, 0xa1, 0x15, 0x06, 0x69, 0x7e,
- 0x33, 0x0e, 0xfd, 0xac, 0x5f, 0x03, 0x1f, 0x71, 0x62, 0xa4, 0xf3, 0xd8,
- 0xaa, 0xa0, 0xbd, 0xe3, 0x91, 0x9a, 0x1a, 0x9b, 0xda, 0x23, 0x43, 0xd7,
- 0xf2, 0x80, 0x1c, 0x80, 0xa1, 0x47, 0xc8, 0x62, 0x7a, 0x12, 0x17, 0xb9,
- 0xb4, 0xd5, 0x8b, 0xd1, 0xcf, 0xd6, 0x2b, 0x69, 0xbf, 0x22, 0x1b, 0xf7,
- 0xfd, 0xc1, 0x6e, 0x2c, 0x5c, 0x66, 0xc4, 0xb1, 0x52, 0x79, 0x7d, 0x96,
- 0xdf, 0xf1, 0x39, 0xbe, 0xe1, 0x31, 0xab, 0x17, 0xef, 0x79, 0x8f, 0xc5,
- 0x8b, 0x9d, 0x96, 0x2f, 0xdd, 0xfb, 0x7e, 0x12, 0xc5, 0xf9, 0xfd, 0x07,
- 0x1a, 0xc5, 0x8d, 0xc3, 0xd3, 0x22, 0xbb, 0xa1, 0xf5, 0x8a, 0xc4, 0xc2,
- 0xd8, 0xeb, 0xe5, 0x2e, 0xd3, 0xe2, 0x7b, 0x32, 0xc5, 0xff, 0xfe, 0x32,
- 0x4a, 0x4d, 0x29, 0x34, 0x3d, 0x99, 0xd4, 0xf5, 0x2b, 0x17, 0xfd, 0x31,
- 0xb1, 0xfd, 0x98, 0x75, 0x8b, 0xff, 0xe9, 0x39, 0x4f, 0x60, 0x1e, 0x1e,
- 0x3c, 0x31, 0x62, 0xfe, 0xfc, 0xed, 0xe9, 0xa3, 0x58, 0xbf, 0xf3, 0x9f,
- 0x34, 0x69, 0xa2, 0x2f, 0x2c, 0x5f, 0xe9, 0xf7, 0x38, 0xc5, 0x12, 0xc5,
- 0x7c, 0xfd, 0x49, 0x06, 0xff, 0xc6, 0x39, 0x43, 0xe2, 0x9e, 0xf8, 0xb1,
- 0x7f, 0xff, 0x39, 0xf5, 0x9b, 0xe4, 0xbd, 0x9f, 0x6d, 0x7d, 0xd6, 0x2f,
- 0xf9, 0xfd, 0xcf, 0x79, 0xe1, 0xc5, 0x8a, 0x89, 0x1e, 0xfa, 0x21, 0xfa,
- 0x09, 0x2d, 0xdf, 0xfc, 0xfa, 0x78, 0x67, 0x1f, 0xd9, 0x12, 0xc5, 0xff,
- 0x7b, 0x53, 0x9d, 0xed, 0x7e, 0x2c, 0x5f, 0xda, 0x7d, 0x14, 0xc1, 0x62,
- 0xfe, 0x28, 0xdb, 0x5b, 0xe0, 0xb1, 0x7f, 0xff, 0xbd, 0xe9, 0x81, 0x3f,
- 0xe4, 0xff, 0xc1, 0xbf, 0x64, 0xb1, 0x7f, 0xfb, 0xdf, 0xcd, 0xff, 0x6d,
- 0xbc, 0xe3, 0x1d, 0x62, 0xa5, 0x1c, 0x18, 0x62, 0xec, 0x17, 0xfd, 0x06,
- 0xd7, 0x72, 0x53, 0xc5, 0x8b, 0xfe, 0x9c, 0x8f, 0x53, 0xe7, 0xf2, 0xc5,
- 0x31, 0xf9, 0x08, 0xe6, 0xb6, 0x1a, 0xe9, 0x54, 0x88, 0xc6, 0xcd, 0x03,
- 0x91, 0xa9, 0x64, 0x73, 0xdd, 0x1e, 0xf6, 0x89, 0xa3, 0xc2, 0x8c, 0x37,
- 0xd0, 0x9f, 0xbf, 0xa1, 0x31, 0x63, 0x01, 0x62, 0xc1, 0x36, 0x27, 0xdb,
- 0x0b, 0xd8, 0x05, 0xb6, 0x36, 0xe0, 0xb6, 0x59, 0x32, 0xb7, 0x23, 0x94,
- 0x15, 0x08, 0xce, 0x07, 0x2b, 0x63, 0x29, 0x7d, 0xc6, 0xc3, 0xcf, 0xa9,
- 0xd5, 0x0e, 0xe5, 0xa4, 0xb4, 0x2a, 0xb7, 0x09, 0x22, 0x94, 0xd1, 0xa9,
- 0x6e, 0xc7, 0x8d, 0xfb, 0xf3, 0x89, 0x0f, 0x28, 0x44, 0x12, 0x85, 0xca,
- 0x75, 0xb3, 0x95, 0xa5, 0x47, 0xa9, 0x0c, 0xa2, 0x87, 0x61, 0x8d, 0xbb,
- 0x31, 0x96, 0x87, 0x3a, 0xe5, 0xbb, 0x0b, 0x2b, 0xf0, 0x7f, 0x7f, 0xca,
- 0xc5, 0xfa, 0x1d, 0xc9, 0x0d, 0x62, 0xa0, 0xaa, 0x40, 0xf2, 0x8f, 0x88,
- 0xa6, 0xff, 0xf6, 0xb0, 0xc1, 0xff, 0x22, 0x2c, 0xd4, 0x16, 0x2f, 0x6b,
- 0x37, 0x16, 0x2f, 0xfd, 0x26, 0x07, 0x1f, 0x30, 0xf3, 0xb8, 0xb1, 0x5a,
- 0x45, 0x89, 0xd3, 0x3c, 0x41, 0x7f, 0xfc, 0xe7, 0x9d, 0x75, 0xa1, 0x1b,
- 0xa1, 0x3f, 0x16, 0x2b, 0x11, 0x06, 0x23, 0x0b, 0xfd, 0xae, 0x84, 0xe3,
- 0x3c, 0xac, 0x5f, 0xfd, 0x3a, 0x0f, 0xcd, 0xef, 0xe0, 0xd9, 0x62, 0xff,
- 0x17, 0x60, 0xce, 0x3e, 0xe2, 0xc5, 0xff, 0x14, 0xc6, 0x1f, 0xfe, 0xfb,
- 0x8b, 0x17, 0xd3, 0x83, 0xed, 0x62, 0xb1, 0x13, 0x1f, 0x37, 0xde, 0x7d,
- 0x7f, 0x3b, 0xfb, 0x65, 0xba, 0x58, 0xbb, 0x7e, 0xea, 0xc5, 0xff, 0xff,
- 0x31, 0x30, 0x39, 0xac, 0xeb, 0xf3, 0xfc, 0xd6, 0xa4, 0xd5, 0x8a, 0x94,
- 0xfe, 0x23, 0x35, 0xc8, 0x6e, 0xe8, 0xc4, 0x06, 0x3e, 0x1d, 0xbd, 0xb0,
- 0xb6, 0x28, 0x2c, 0x5e, 0x7d, 0x46, 0xb1, 0x7f, 0xb3, 0xdc, 0x6e, 0xb0,
- 0x96, 0x2e, 0x30, 0xc5, 0x8b, 0xff, 0x0a, 0x37, 0xf7, 0xbb, 0xe9, 0x89,
- 0x62, 0xf3, 0xf4, 0x13, 0xa4, 0x56, 0x90, 0xf1, 0x86, 0x61, 0x8d, 0x5f,
- 0xb4, 0xf0, 0x6f, 0xac, 0x5f, 0xfd, 0xae, 0x7d, 0x8c, 0xfb, 0x46, 0xe4,
- 0xb1, 0x52, 0x7d, 0xce, 0x51, 0x7f, 0xfc, 0x5d, 0x80, 0xe2, 0xef, 0xf9,
- 0xbf, 0x3d, 0xc5, 0x8b, 0xf4, 0x50, 0x9d, 0x46, 0xb1, 0x7f, 0xe3, 0x88,
- 0x3c, 0xd4, 0x62, 0x71, 0xac, 0x56, 0x23, 0x0b, 0x4a, 0xa7, 0x2b, 0xbf,
- 0x61, 0xfe, 0xe3, 0x58, 0xb0, 0x4d, 0x89, 0xfd, 0xdf, 0xa6, 0x11, 0xf0,
- 0x21, 0x1a, 0x16, 0x4b, 0x8a, 0x34, 0xb3, 0xaa, 0x67, 0xf6, 0xe1, 0x7c,
- 0x45, 0x3a, 0x86, 0x67, 0xcb, 0x9e, 0xf7, 0x75, 0x0a, 0x36, 0xce, 0x4a,
- 0x1a, 0xf2, 0xe6, 0xf8, 0x6b, 0x19, 0x0c, 0x10, 0xe1, 0xc5, 0xba, 0x5f,
- 0x50, 0x85, 0xb0, 0xe8, 0xeb, 0x47, 0x4e, 0xe5, 0x4b, 0xe9, 0x2c, 0xf0,
- 0x96, 0xfc, 0xe7, 0x48, 0x23, 0x1b, 0x29, 0x45, 0x3c, 0xa6, 0xdb, 0xfa,
- 0x9b, 0xb0, 0x2b, 0xf9, 0x16, 0xb8, 0x50, 0x58, 0xbf, 0x60, 0xff, 0x26,
- 0x2c, 0x5f, 0xdc, 0x98, 0xa0, 0xd1, 0x2c, 0x5f, 0xf7, 0xa4, 0x98, 0x19,
- 0xdf, 0x96, 0x2f, 0xb6, 0x5c, 0x80, 0xb1, 0x74, 0xc7, 0x87, 0xbc, 0x19,
- 0xcd, 0x01, 0x1f, 0xa4, 0x31, 0xc2, 0x90, 0xe1, 0x1d, 0x76, 0x76, 0xb1,
- 0x78, 0xec, 0x05, 0x8b, 0xe7, 0xd7, 0x41, 0x20, 0x6d, 0x78, 0x31, 0x7f,
- 0xfa, 0x0f, 0xc0, 0x85, 0x39, 0xe9, 0xee, 0x0b, 0x17, 0x8d, 0x6d, 0x2c,
- 0x5d, 0x20, 0x58, 0xbe, 0xf7, 0xa4, 0xeb, 0x17, 0x98, 0x61, 0x18, 0xf6,
- 0x3e, 0x3c, 0x18, 0xbd, 0xff, 0xa6, 0x01, 0x03, 0x93, 0x03, 0x8b, 0x8b,
- 0x16, 0x6e, 0x91, 0x10, 0x04, 0x2a, 0x08, 0xa8, 0x1e, 0x37, 0x76, 0x3b,
- 0xf4, 0x65, 0x97, 0xfe, 0x7e, 0x82, 0x08, 0x0d, 0x0c, 0x82, 0xc5, 0xff,
- 0xf6, 0x79, 0xbe, 0x2f, 0xbb, 0x77, 0xc9, 0x35, 0x62, 0xfd, 0xae, 0x9d,
- 0xfa, 0x54, 0x46, 0xa5, 0xff, 0xf7, 0xd8, 0xc7, 0x2e, 0xb5, 0x2d, 0x07,
- 0xe2, 0xc5, 0xf8, 0x5e, 0x14, 0x52, 0xb1, 0x7e, 0x61, 0xbe, 0x79, 0x62,
- 0xf1, 0xbd, 0xf1, 0x62, 0xc1, 0x23, 0x4e, 0x2c, 0x68, 0x58, 0xa3, 0xd1,
- 0xbf, 0xd4, 0x1c, 0xab, 0xc4, 0xf7, 0xff, 0xfb, 0x7c, 0x97, 0x82, 0x3e,
- 0xf7, 0x1e, 0x0d, 0xce, 0xe3, 0x58, 0xbf, 0x6b, 0xa7, 0x7e, 0x95, 0x15,
- 0x29, 0x7b, 0x00, 0xeb, 0x16, 0xe9, 0x51, 0x0d, 0x14, 0xb1, 0x4e, 0x6b,
- 0x00, 0x41, 0x60, 0x98, 0x89, 0xff, 0x9b, 0xba, 0x45, 0xf7, 0x9f, 0xb0,
- 0x2c, 0x5f, 0xfe, 0xcf, 0xb0, 0x7e, 0x62, 0x14, 0x33, 0x8b, 0x17, 0xfb,
- 0x3e, 0x4f, 0xef, 0x4a, 0xc5, 0xe2, 0x70, 0x8e, 0x8a, 0x0f, 0x12, 0x06,
- 0x95, 0x78, 0x29, 0xb0, 0xf6, 0x35, 0x8b, 0xf3, 0x9e, 0x37, 0xdc, 0x58,
- 0xbe, 0xe9, 0xdf, 0xa5, 0x44, 0x7c, 0x5c, 0x39, 0x58, 0xad, 0x1e, 0x41,
- 0xcc, 0x6f, 0xf7, 0x1b, 0xe6, 0x3e, 0xa0, 0xb1, 0x7f, 0x9b, 0x5b, 0x58,
- 0x78, 0x75, 0x8b, 0x9f, 0x4b, 0x15, 0xf3, 0xcc, 0x73, 0x5b, 0xbe, 0x25,
- 0x8b, 0xfe, 0x18, 0xbd, 0xcc, 0x83, 0x7d, 0x62, 0x86, 0x7a, 0x4c, 0x31,
- 0x77, 0x7c, 0x58, 0xb1, 0xab, 0x15, 0x86, 0xb3, 0x64, 0x66, 0xff, 0xb3,
- 0x79, 0x67, 0x03, 0xd1, 0xab, 0x17, 0xff, 0x0b, 0x40, 0xeb, 0xed, 0x11,
- 0x48, 0x16, 0x2f, 0xf4, 0x33, 0x71, 0xc8, 0x1b, 0x1a, 0xc5, 0xfe, 0x21,
- 0x74, 0x79, 0xd7, 0x4b, 0x17, 0xbd, 0x38, 0xb1, 0x7f, 0xf7, 0xa1, 0x26,
- 0xed, 0x9f, 0x72, 0x40, 0xb1, 0x62, 0xc3, 0xe4, 0x71, 0xcb, 0xa0, 0x10,
- 0x28, 0xae, 0x96, 0x32, 0xdc, 0x74, 0xec, 0x8a, 0x28, 0x40, 0xbb, 0x98,
- 0x13, 0x48, 0x8f, 0x87, 0xbe, 0x47, 0x11, 0xd8, 0x70, 0x9a, 0xae, 0x97,
- 0x2a, 0xde, 0x5f, 0x3d, 0xfc, 0x13, 0x8f, 0x3d, 0xc1, 0x62, 0xfd, 0xef,
- 0xc9, 0x1a, 0xb1, 0x7f, 0x69, 0xc0, 0xf9, 0xa5, 0x8b, 0xc2, 0x28, 0xd6,
- 0x2f, 0x39, 0x44, 0xb1, 0x5f, 0x37, 0x6e, 0x3d, 0x7f, 0x66, 0xbc, 0x53,
- 0xda, 0xc5, 0xfd, 0xf9, 0x6d, 0xf8, 0x35, 0x8b, 0xff, 0x3c, 0x73, 0xf6,
- 0xd3, 0x49, 0xd6, 0x2f, 0xf4, 0xeb, 0x0b, 0xd9, 0xf5, 0x8b, 0xb0, 0x24,
- 0xa6, 0xfc, 0x32, 0x9f, 0xb4, 0x00, 0x83, 0xc5, 0xdb, 0x25, 0xe1, 0x9f,
- 0x51, 0xaa, 0x89, 0x0f, 0x1d, 0x7d, 0x04, 0x54, 0xfb, 0x32, 0x94, 0x6f,
- 0xff, 0xf0, 0xb4, 0x6b, 0xf3, 0x07, 0x3d, 0xf0, 0x3f, 0x1a, 0xc6, 0xac,
- 0x5e, 0xe3, 0xf1, 0x62, 0xfb, 0x34, 0x4e, 0xb1, 0x52, 0x6f, 0x98, 0x76,
- 0xa0, 0x8c, 0x48, 0xa1, 0x4b, 0x78, 0xc3, 0x7a, 0x58, 0xbf, 0x77, 0xdc,
- 0x33, 0xcb, 0x15, 0xc3, 0xcc, 0x11, 0x0d, 0xff, 0xe0, 0xb0, 0xd3, 0x37,
- 0x23, 0x1e, 0xc7, 0xb7, 0x6f, 0xf6, 0x56, 0x2f, 0xfc, 0x27, 0xd4, 0x0b,
- 0x39, 0x3a, 0x58, 0xbe, 0xe9, 0xdf, 0xa5, 0x45, 0x8e, 0x5f, 0xa7, 0xe4,
- 0xe1, 0xac, 0x5c, 0x2d, 0x2c, 0x56, 0x8f, 0xc4, 0xe6, 0x2e, 0x51, 0x7f,
- 0xb1, 0x8a, 0x3f, 0x67, 0xd6, 0x2e, 0x7e, 0x2c, 0x5f, 0xd1, 0x87, 0xad,
- 0x66, 0x96, 0x2f, 0x1f, 0x92, 0xb1, 0x50, 0x3e, 0x57, 0x17, 0x11, 0x8d,
- 0xff, 0x13, 0x9b, 0xf6, 0x92, 0x8d, 0x62, 0xff, 0xff, 0x61, 0x7b, 0x9b,
- 0x78, 0x1c, 0xe8, 0x1b, 0x2d, 0xfc, 0xde, 0xb1, 0x7f, 0x17, 0xb4, 0x29,
- 0x3a, 0xc5, 0xff, 0xf8, 0x9c, 0xdd, 0xbe, 0x36, 0x4a, 0x19, 0xf6, 0x3a,
- 0xc5, 0x4a, 0x3b, 0xdd, 0xa4, 0x45, 0xd7, 0xf0, 0x1f, 0xdc, 0x93, 0x56,
- 0x2f, 0x8d, 0x0c, 0xba, 0x58, 0xb6, 0x2c, 0x51, 0xa6, 0xdf, 0x79, 0x35,
- 0xfe, 0x6f, 0x4e, 0x8d, 0xfb, 0x2c, 0x5f, 0xff, 0x42, 0x30, 0xb2, 0x76,
- 0x08, 0xfa, 0xd6, 0xdd, 0xbf, 0xd9, 0x58, 0xbf, 0xec, 0xdf, 0x30, 0xee,
- 0x19, 0xe5, 0x8a, 0xc4, 0xd8, 0x59, 0x99, 0xc9, 0x00, 0x68, 0x4c, 0xf7,
- 0xec, 0xde, 0x1c, 0x5c, 0x58, 0xb9, 0xa0, 0xb1, 0x7f, 0xb0, 0xbf, 0x9e,
- 0x91, 0xac, 0x5f, 0xb3, 0x7f, 0xde, 0x0b, 0x16, 0xf3, 0x1e, 0xe1, 0x19,
- 0x50, 0xd1, 0x33, 0x8e, 0x77, 0xfd, 0x06, 0xf0, 0x7a, 0x9f, 0xca, 0xc5,
- 0xff, 0xf9, 0xb8, 0x1f, 0x60, 0xcd, 0xed, 0xe9, 0xc2, 0x82, 0xc5, 0xf9,
- 0xbd, 0xe6, 0xf2, 0xc5, 0xff, 0xf8, 0x44, 0xe6, 0xf8, 0xd9, 0x28, 0x67,
- 0xd8, 0xeb, 0x17, 0xda, 0xd6, 0x6c, 0xac, 0x5f, 0xb4, 0x06, 0xfc, 0xac,
- 0x56, 0xd4, 0xd7, 0xa0, 0x75, 0x8b, 0x07, 0x28, 0x75, 0x61, 0x13, 0x5f,
- 0xc3, 0xc3, 0xb7, 0xe5, 0x62, 0xfb, 0x59, 0x91, 0x2c, 0x54, 0x9e, 0x86,
- 0x16, 0xd8, 0x24, 0xb2, 0x2a, 0xe3, 0x75, 0x81, 0x10, 0xd9, 0x72, 0x15,
- 0xe6, 0x97, 0x34, 0x26, 0x22, 0x2e, 0x3c, 0x65, 0x1f, 0x8e, 0x3d, 0xd1,
- 0xca, 0x18, 0xdc, 0x8e, 0x00, 0x38, 0x54, 0x5d, 0xec, 0x58, 0xb0, 0x51,
- 0x62, 0xbb, 0x35, 0xac, 0x2f, 0x79, 0xb5, 0x12, 0xc5, 0xf4, 0x3c, 0x21,
- 0xac, 0x51, 0xa7, 0x85, 0xd8, 0xf5, 0xff, 0xff, 0xfb, 0xf8, 0xed, 0xcf,
- 0xe0, 0x36, 0xf3, 0x07, 0x87, 0x6e, 0xe0, 0x52, 0x68, 0x16, 0x2f, 0xe2,
- 0x73, 0x3d, 0x9f, 0x58, 0xad, 0x89, 0x16, 0x71, 0x42, 0x16, 0xe3, 0x9a,
- 0xb1, 0x41, 0x53, 0xc7, 0x0b, 0x0b, 0xaf, 0xc5, 0x9f, 0x7f, 0x2c, 0x5e,
- 0x0b, 0x5d, 0x88, 0x0b, 0x14, 0x15, 0x3d, 0x10, 0xb0, 0x9e, 0xff, 0xdb,
- 0x10, 0x50, 0x2a, 0x2c, 0xd1, 0x48, 0x16, 0x2f, 0xfc, 0x15, 0xd8, 0x60,
- 0x04, 0x8f, 0xe2, 0xdd, 0x58, 0xbf, 0xb3, 0xa9, 0xf3, 0x6f, 0x58, 0xbf,
- 0xf6, 0x19, 0xcc, 0x6e, 0x7b, 0x37, 0x16, 0x2b, 0xe7, 0xe4, 0x46, 0x17,
- 0xbe, 0x21, 0xac, 0x5d, 0xb0, 0xc2, 0x8b, 0x17, 0xfc, 0x53, 0xf7, 0x6e,
- 0x36, 0xf5, 0x8b, 0xb0, 0xe1, 0x43, 0xdb, 0x0c, 0x8a, 0xfe, 0xc8, 0x43,
- 0x42, 0x0a, 0xac, 0x50, 0xcf, 0x94, 0x8c, 0xaf, 0xfa, 0x62, 0x6f, 0x71,
- 0x8a, 0x25, 0x8b, 0xff, 0xa4, 0x1f, 0xdc, 0x63, 0xfb, 0x8f, 0xda, 0xc5,
- 0xff, 0x4e, 0x9c, 0xe5, 0x9d, 0xf9, 0x62, 0xba, 0x44, 0x11, 0xd2, 0x6e,
- 0xc8, 0xd6, 0x2e, 0x1c, 0xac, 0x50, 0x66, 0xbf, 0x74, 0x62, 0x98, 0xfe,
- 0x04, 0xa7, 0x7f, 0xef, 0xb6, 0xd0, 0xfa, 0x2c, 0xfe, 0x2c, 0x5f, 0xc0,
- 0xe3, 0xfb, 0xce, 0xb1, 0x46, 0x9f, 0x83, 0xa1, 0x5f, 0xee, 0x4c, 0x47,
- 0x9f, 0x71, 0x62, 0xe3, 0xf4, 0xb1, 0x7f, 0xce, 0x36, 0xee, 0x1e, 0x6d,
- 0x2c, 0x5f, 0xfa, 0x74, 0x02, 0xc8, 0xa0, 0xd1, 0x2c, 0x50, 0xd5, 0xe7,
- 0xe1, 0x0b, 0x43, 0x7b, 0x44, 0x3f, 0x8c, 0xd0, 0xa1, 0x23, 0xc2, 0x2f,
- 0x1a, 0xef, 0x19, 0xdd, 0x3a, 0xbf, 0xe3, 0x35, 0x84, 0xfd, 0xc3, 0x8b,
- 0x17, 0x11, 0xab, 0x17, 0xf7, 0x7f, 0x69, 0x28, 0xd6, 0x2e, 0xc1, 0xac,
- 0x56, 0x22, 0x65, 0xce, 0xc4, 0x31, 0xbc, 0xbe, 0xfd, 0xf7, 0x3c, 0x92,
- 0xc5, 0xf7, 0x3e, 0xc6, 0x2c, 0x5f, 0xfd, 0x16, 0xe3, 0x47, 0xfc, 0x88,
- 0xb0, 0xc5, 0x8b, 0xfb, 0xa7, 0xd6, 0xcb, 0xfd, 0x62, 0xef, 0xfd, 0x62,
- 0xfd, 0x26, 0x7b, 0x3e, 0xb1, 0x70, 0x78, 0xb1, 0x7c, 0x3c, 0xef, 0xcb,
- 0x15, 0x26, 0xf1, 0x86, 0x2b, 0x6a, 0x6c, 0x98, 0x4e, 0x69, 0x23, 0x25,
- 0x85, 0xcc, 0x88, 0x63, 0x8c, 0xb7, 0xf1, 0x48, 0x21, 0xd4, 0x6b, 0x17,
- 0xff, 0x4c, 0xee, 0xff, 0x1c, 0x79, 0x87, 0x58, 0xbb, 0xdc, 0x88, 0xfd,
- 0x7e, 0x61, 0x6e, 0x96, 0x2f, 0x00, 0x29, 0xf5, 0x8a, 0xd8, 0x66, 0xd7,
- 0x82, 0x77, 0xc2, 0xe7, 0xf1, 0x62, 0xff, 0xf3, 0x7c, 0x43, 0xfc, 0xf5,
- 0xf1, 0x38, 0x6b, 0x15, 0xa4, 0x4b, 0x91, 0x3f, 0x88, 0xef, 0xff, 0x66,
- 0xee, 0x75, 0xee, 0xe1, 0x84, 0x07, 0x58, 0xbf, 0xff, 0xf9, 0x8b, 0x7e,
- 0x0c, 0x9d, 0xf7, 0xe6, 0xe7, 0xb7, 0x1b, 0xc5, 0x20, 0x58, 0xbc, 0xc2,
- 0x02, 0xc5, 0xbb, 0xdc, 0x44, 0xac, 0x4f, 0x17, 0x8e, 0xda, 0x58, 0xac,
- 0x3c, 0xb0, 0x17, 0x5e, 0xc7, 0x25, 0x8b, 0xdf, 0x98, 0x96, 0x2e, 0x6f,
- 0x31, 0xb9, 0x71, 0xbb, 0xa0, 0x35, 0x8b, 0xff, 0xb0, 0xce, 0x16, 0x45,
- 0x01, 0x17, 0x96, 0x2f, 0xa1, 0xb8, 0xc7, 0x58, 0xbe, 0xe3, 0xbe, 0xe2,
- 0xc5, 0xf7, 0xff, 0x3b, 0x8b, 0x17, 0xec, 0xfe, 0xe3, 0x13, 0x9f, 0x8f,
- 0x89, 0x83, 0x25, 0xa2, 0x4c, 0x13, 0x7c, 0x2d, 0xef, 0xff, 0xdd, 0x66,
- 0xf6, 0xd6, 0xcb, 0xc7, 0xb3, 0xac, 0xff, 0x16, 0x2b, 0x11, 0x14, 0xe5,
- 0x57, 0xff, 0xbf, 0x3d, 0xe4, 0x64, 0x21, 0x7a, 0x7e, 0xb1, 0x7f, 0xcd,
- 0xd7, 0xdb, 0xdc, 0x7e, 0xd6, 0x2f, 0xc5, 0x83, 0xcf, 0xf4, 0x88, 0x7f,
- 0xa6, 0x5f, 0xee, 0x98, 0xcc, 0x89, 0xf7, 0x16, 0x2b, 0x47, 0xf1, 0xf3,
- 0xfb, 0xff, 0xff, 0x16, 0x1c, 0x84, 0x03, 0x77, 0x18, 0x87, 0x91, 0x98,
- 0x27, 0x8d, 0x62, 0xa5, 0x12, 0x98, 0x45, 0x7f, 0xff, 0xa4, 0xcf, 0xe6,
- 0x9c, 0xf9, 0xef, 0xe6, 0x1f, 0x3a, 0x58, 0xbf, 0xfd, 0xce, 0x9d, 0xf7,
- 0xeb, 0x1b, 0xf2, 0x35, 0x8b, 0xff, 0xd9, 0xba, 0x59, 0xbc, 0xb0, 0x07,
- 0x98, 0x2c, 0x57, 0x48, 0x99, 0x89, 0x32, 0xa5, 0x31, 0xfc, 0x87, 0xd5,
- 0xff, 0x3f, 0x65, 0x9e, 0xe6, 0x18, 0xb1, 0x52, 0xbf, 0xaf, 0x90, 0xfb,
- 0xe8, 0xbd, 0xa3, 0x2e, 0xdc, 0x5a, 0x88, 0xab, 0x51, 0xd3, 0x7e, 0x3b,
- 0x42, 0x8d, 0x00, 0x44, 0xf7, 0x77, 0xc5, 0x8b, 0xda, 0x14, 0x16, 0x2d,
- 0xf9, 0x36, 0xec, 0x33, 0x7f, 0xd1, 0xb7, 0xe2, 0x78, 0x37, 0xd6, 0x2f,
- 0xda, 0x06, 0xc8, 0xbc, 0xb1, 0x7f, 0xb7, 0xfd, 0x87, 0xfc, 0xe2, 0xc5,
- 0xff, 0xff, 0x08, 0x5d, 0x96, 0x6f, 0xda, 0x3c, 0xf4, 0x33, 0xff, 0x78,
- 0x2c, 0x5f, 0xf1, 0xf9, 0xfc, 0xf1, 0x49, 0xd6, 0x2f, 0x16, 0x70, 0x91,
- 0x4b, 0xb2, 0xd9, 0x4e, 0x98, 0x86, 0xf8, 0x6d, 0xdf, 0xfe, 0xd6, 0xa6,
- 0x3c, 0x33, 0xb8, 0x78, 0x43, 0x58, 0xbe, 0xcc, 0x23, 0x56, 0x2f, 0xfc,
- 0xc6, 0xe4, 0x19, 0xf7, 0xfd, 0x96, 0x2d, 0x2c, 0x8b, 0x1d, 0x27, 0xfc,
- 0x8a, 0xa5, 0x52, 0x63, 0x46, 0x7b, 0xf8, 0x6d, 0xdf, 0xe2, 0xf6, 0xc6,
- 0xfe, 0x14, 0xac, 0x5f, 0xd0, 0x2c, 0xef, 0xce, 0xb1, 0x7f, 0x0f, 0xc6,
- 0xb1, 0x0d, 0x62, 0xa5, 0x12, 0xae, 0x70, 0x22, 0xeb, 0xe3, 0xb1, 0x9c,
- 0x58, 0xbf, 0xcf, 0x1f, 0xb8, 0xef, 0xb8, 0xb1, 0x51, 0x9e, 0xde, 0xf2,
- 0x4b, 0xfb, 0xed, 0x13, 0xbc, 0x16, 0x2e, 0x3c, 0x16, 0x2e, 0x6d, 0x74,
- 0x78, 0xc1, 0x97, 0x5f, 0xfd, 0xf9, 0x3f, 0x5f, 0x6f, 0x66, 0x1d, 0x62,
- 0xfb, 0x51, 0xc9, 0xab, 0x16, 0x65, 0x8b, 0x9c, 0xdc, 0x36, 0xde, 0x25,
- 0xa9, 0x45, 0x39, 0x3d, 0xdf, 0xfe, 0x2c, 0xf8, 0x7c, 0xe0, 0x8f, 0xc7,
- 0xed, 0x62, 0xf8, 0x18, 0xce, 0xb1, 0x78, 0x0c, 0x1a, 0xc5, 0xff, 0xff,
- 0xe9, 0x2f, 0x71, 0xbe, 0xc7, 0x1c, 0xff, 0x37, 0xee, 0x31, 0x0f, 0x23,
- 0x58, 0xbe, 0xdd, 0x9f, 0xf1, 0x62, 0xba, 0x4c, 0xb5, 0xd3, 0x40, 0x43,
- 0xe1, 0xed, 0xd7, 0xbb, 0xfe, 0x7d, 0x47, 0xf6, 0xcd, 0x44, 0xb1, 0x7f,
- 0xf3, 0xb9, 0x03, 0x99, 0xb9, 0x13, 0xba, 0xc5, 0xff, 0xff, 0xfc, 0xdf,
- 0xdc, 0x62, 0xcf, 0x7a, 0x63, 0x19, 0x4c, 0x83, 0xd0, 0xc2, 0x27, 0x82,
- 0xc5, 0xff, 0x67, 0xb0, 0xef, 0xa6, 0x89, 0x62, 0xb1, 0x18, 0x25, 0x08,
- 0x8a, 0xe9, 0x36, 0x88, 0x8e, 0xfd, 0x18, 0x3d, 0xfa, 0x1c, 0x8f, 0x0c,
- 0x58, 0xbd, 0x9a, 0x8d, 0x62, 0xf3, 0x94, 0x4b, 0x15, 0xf3, 0x76, 0xe3,
- 0xd7, 0x9d, 0xfa, 0x54, 0x5a, 0x05, 0xff, 0xfe, 0xc1, 0xcf, 0x4c, 0x51,
- 0xf3, 0xaf, 0xb0, 0xc7, 0x84, 0xb1, 0x7e, 0x7d, 0x47, 0x86, 0x2c, 0x5e,
- 0x73, 0x37, 0x76, 0xa2, 0x33, 0xa6, 0x2b, 0xf8, 0x12, 0x53, 0xee, 0x2c,
- 0x5e, 0xd4, 0xf9, 0x62, 0xfe, 0x91, 0x78, 0x9b, 0x7a, 0xc5, 0xfd, 0xee,
- 0x61, 0xad, 0xa8, 0x8f, 0x33, 0x43, 0xb5, 0x2a, 0x8d, 0x86, 0xcd, 0xd1,
- 0x06, 0xa1, 0x6c, 0x03, 0xb0, 0xde, 0x6f, 0xef, 0x6d, 0xc3, 0x5b, 0x4b,
- 0x17, 0xa0, 0xc0, 0x58, 0xbf, 0xee, 0xfd, 0x26, 0xee, 0x30, 0x86, 0xb1,
- 0x7f, 0x37, 0xbe, 0xe4, 0x6a, 0xc5, 0x32, 0x2e, 0xe2, 0x31, 0x71, 0xde,
- 0x1f, 0xde, 0x10, 0xb4, 0xb1, 0x78, 0xa7, 0x4b, 0x17, 0x6a, 0x28, 0x8d,
- 0xd7, 0x07, 0xaf, 0xff, 0xf7, 0x1c, 0xbf, 0x3b, 0xff, 0x9e, 0xc7, 0x2e,
- 0xb0, 0x6b, 0x17, 0xff, 0xf9, 0xa7, 0xcd, 0xf9, 0xe7, 0xf3, 0x9a, 0xce,
- 0xb3, 0xcb, 0x17, 0xff, 0x48, 0x38, 0x59, 0xb8, 0x39, 0xf7, 0x16, 0x2c,
- 0xe4, 0x8a, 0x7e, 0x30, 0x5b, 0x52, 0x99, 0x7f, 0xe3, 0x08, 0xbf, 0xa3,
- 0xdb, 0x14, 0x26, 0x35, 0x8a, 0xc4, 0xf0, 0x5a, 0x35, 0xe7, 0x2f, 0xbf,
- 0x0e, 0x62, 0x63, 0xac, 0x5f, 0xc6, 0x16, 0x46, 0x1c, 0x16, 0x2f, 0xc3,
- 0xc0, 0x3c, 0xac, 0x5f, 0xff, 0xf9, 0xf5, 0x0e, 0x30, 0xf3, 0x51, 0xb7,
- 0x3e, 0xe0, 0xe6, 0x12, 0xc5, 0x62, 0x24, 0xf8, 0x4f, 0x4c, 0x8e, 0x61,
- 0x43, 0x12, 0xfd, 0x19, 0xdd, 0xc9, 0x62, 0xff, 0x6f, 0xfe, 0x14, 0x6d,
- 0xc5, 0x8b, 0xfc, 0x0c, 0x6e, 0x72, 0x40, 0xb1, 0x52, 0x7d, 0x2e, 0x6d,
- 0x52, 0x8b, 0x1e, 0x42, 0x46, 0xff, 0xc3, 0xd9, 0xce, 0x0f, 0xed, 0xa8,
- 0xd6, 0x2f, 0xff, 0xb0, 0xcf, 0x1e, 0x73, 0xdf, 0xcc, 0x2e, 0x96, 0x2a,
- 0x51, 0x29, 0xf4, 0x4b, 0xdb, 0x10, 0x57, 0x60, 0x58, 0xbe, 0xc2, 0x83,
- 0x2c, 0x5f, 0xfd, 0x9a, 0xd3, 0xc0, 0x32, 0x7f, 0x71, 0x62, 0xa4, 0xf9,
- 0xa0, 0x43, 0x66, 0xd2, 0x2c, 0xfd, 0x09, 0x2b, 0xfd, 0x17, 0xe7, 0xdf,
- 0x98, 0x96, 0x2a, 0x5b, 0x21, 0x88, 0xc9, 0x61, 0x2a, 0x1c, 0x70, 0xd0,
- 0xc8, 0x44, 0x9a, 0xd7, 0xd4, 0x35, 0x9a, 0x34, 0xed, 0xc8, 0xed, 0xb5,
- 0x29, 0xbc, 0xf1, 0x8d, 0x7e, 0x51, 0xbb, 0x9a, 0x14, 0x61, 0xfc, 0x86,
- 0xc7, 0xa1, 0x77, 0xbe, 0x1a, 0xa1, 0x96, 0xdf, 0xff, 0xfe, 0x6f, 0x88,
- 0x9d, 0xf7, 0xf5, 0xf6, 0xf6, 0x1f, 0x8d, 0x84, 0x07, 0x58, 0xbf, 0xfe,
- 0xee, 0x05, 0x2e, 0x36, 0xeb, 0x3e, 0xfe, 0x58, 0xa8, 0x23, 0x1d, 0x9d,
- 0xec, 0x05, 0x8b, 0xc3, 0xfc, 0xac, 0x5f, 0x67, 0x7e, 0x75, 0x8b, 0x73,
- 0x69, 0xe0, 0x10, 0xed, 0x85, 0xa3, 0xfb, 0xf2, 0x95, 0xb1, 0x62, 0xff,
- 0xf0, 0xff, 0x32, 0xde, 0xe3, 0x17, 0x70, 0x58, 0xb0, 0x86, 0x7b, 0x64,
- 0x23, 0x76, 0x1d, 0x62, 0xff, 0xf8, 0xd6, 0xd6, 0x77, 0xef, 0xb0, 0x72,
- 0x39, 0x58, 0xb9, 0xc9, 0x62, 0xf3, 0x16, 0x2c, 0x5f, 0xfb, 0x9f, 0x93,
- 0xfb, 0x84, 0xfd, 0xc6, 0x6c, 0x60, 0x2d, 0x7f, 0xee, 0xf7, 0xff, 0x71,
- 0xbc, 0x52, 0x75, 0x8a, 0xc4, 0xc7, 0xbb, 0x84, 0x1b, 0xab, 0x5e, 0x98,
- 0xd9, 0x62, 0xb1, 0x56, 0x71, 0xb0, 0x9d, 0x68, 0x41, 0xe8, 0x9d, 0xe3,
- 0x35, 0x23, 0x5b, 0xff, 0xfe, 0xd6, 0x0c, 0x9d, 0xf7, 0xf3, 0x37, 0x3c,
- 0x59, 0x9a, 0x89, 0x62, 0xfc, 0x5e, 0xda, 0x78, 0xd6, 0x2f, 0x84, 0x77,
- 0xf2, 0xc5, 0xff, 0xf9, 0xa3, 0x2c, 0xdf, 0xf6, 0xf7, 0x70, 0x92, 0x89,
- 0x62, 0xa5, 0x15, 0x03, 0x2c, 0xf9, 0x1d, 0xff, 0xff, 0x9b, 0x4d, 0x9b,
- 0xf2, 0x3c, 0x6f, 0x49, 0xc9, 0xcd, 0xfb, 0x2c, 0x5f, 0xfd, 0x09, 0x78,
- 0x6d, 0x68, 0x9b, 0x09, 0x62, 0xff, 0xec, 0xe3, 0x7a, 0x4e, 0xde, 0x14,
- 0xac, 0x5f, 0xf8, 0x4f, 0xdf, 0x0b, 0x37, 0xbc, 0x16, 0x2f, 0xfa, 0x22,
- 0x93, 0xfe, 0x77, 0x9d, 0x62, 0xff, 0xf4, 0x1b, 0x40, 0x7f, 0x64, 0x50,
- 0x6f, 0x2c, 0x5f, 0xbc, 0xdb, 0x39, 0x1a, 0xc5, 0xed, 0x88, 0x29, 0xb1,
- 0x2c, 0x5f, 0xee, 0x67, 0xdb, 0x82, 0x8d, 0x62, 0xf9, 0xb6, 0x72, 0x35,
- 0x8b, 0x9f, 0xbd, 0xa8, 0xb3, 0x0b, 0x0b, 0x38, 0x59, 0xe3, 0x5b, 0x9f,
- 0xb5, 0x8a, 0xc4, 0xe8, 0xbb, 0x3c, 0xe4, 0x3f, 0xbc, 0xa1, 0x66, 0x1a,
- 0xb4, 0x9e, 0x8b, 0xfb, 0x6c, 0x24, 0x5e, 0x21, 0xfa, 0x3e, 0x3b, 0xfe,
- 0xfb, 0x7b, 0x8f, 0xd8, 0x0c, 0x58, 0xbc, 0x37, 0x8d, 0x62, 0xed, 0x47,
- 0xd1, 0xed, 0x06, 0x79, 0x7f, 0xfc, 0x28, 0xf4, 0xde, 0x8c, 0x5a, 0x87,
- 0x37, 0x19, 0x62, 0x99, 0x76, 0x8b, 0xf3, 0x8b, 0x6f, 0x0b, 0xf2, 0x31,
- 0xbf, 0xb3, 0xd8, 0x4f, 0x12, 0xc5, 0xfd, 0xa6, 0xe8, 0xa7, 0xeb, 0x17,
- 0xfc, 0x27, 0xf3, 0xc1, 0xfb, 0x82, 0xc5, 0xf9, 0xc3, 0xce, 0xfc, 0xb1,
- 0x76, 0xb8, 0xb1, 0x50, 0x46, 0xbe, 0x16, 0xf4, 0x5d, 0xc3, 0xad, 0x92,
- 0xab, 0xfc, 0xc3, 0xc3, 0xed, 0xc1, 0xac, 0x5c, 0xfc, 0x58, 0xbf, 0x31,
- 0x81, 0x40, 0xa8, 0x51, 0x62, 0xff, 0xf8, 0x5a, 0xd4, 0x96, 0x1a, 0xdf,
- 0xfe, 0x06, 0xb1, 0x60, 0xba, 0xc5, 0x68, 0xf9, 0xc4, 0xa3, 0x7d, 0x3a,
- 0x98, 0x96, 0x2f, 0x14, 0x9d, 0x62, 0xd2, 0xb1, 0x51, 0x1a, 0xd3, 0x8e,
- 0x5f, 0xe3, 0x88, 0xbd, 0xc1, 0x69, 0x62, 0xa0, 0x9d, 0x90, 0xcd, 0x4d,
- 0x17, 0xd4, 0x27, 0x4e, 0x44, 0x4a, 0x1b, 0x24, 0x57, 0xef, 0xb9, 0xe4,
- 0x96, 0x2d, 0xa5, 0x8b, 0xda, 0xcc, 0x58, 0xa0, 0x1a, 0xed, 0xd1, 0x2b,
- 0xff, 0xfb, 0xbe, 0x4c, 0x35, 0x91, 0xce, 0xb3, 0xcd, 0xd9, 0x8b, 0x16,
- 0x35, 0x62, 0xa3, 0x3f, 0x22, 0x5f, 0xbf, 0x77, 0x0d, 0x73, 0x8b, 0x15,
- 0x27, 0x9b, 0x84, 0x57, 0xff, 0x6e, 0x88, 0xff, 0x93, 0xc5, 0xb8, 0xc3,
- 0x58, 0xbf, 0xdd, 0xff, 0x22, 0x89, 0xf8, 0xb1, 0x4c, 0x88, 0x47, 0x4d,
- 0xbf, 0xf4, 0xc6, 0xe3, 0x29, 0x83, 0x12, 0xc5, 0xfc, 0x5d, 0xc3, 0xc2,
- 0x1a, 0xc5, 0xfb, 0x73, 0x08, 0xec, 0xb1, 0x52, 0x7b, 0x4e, 0x61, 0x7c,
- 0x53, 0x86, 0x2c, 0x5e, 0x2c, 0x02, 0xc5, 0xff, 0xf3, 0x6d, 0xdc, 0x68,
- 0xf6, 0xff, 0x22, 0x2c, 0x31, 0x62, 0xfa, 0x2c, 0xc8, 0xd6, 0x2f, 0xdc,
- 0x6f, 0x14, 0xac, 0x5d, 0x9f, 0xe1, 0xe5, 0xf8, 0x92, 0xc6, 0x05, 0x53,
- 0x0f, 0xd1, 0x17, 0xc7, 0x3d, 0x0a, 0x4b, 0xf8, 0xcf, 0x14, 0x9f, 0x8b,
- 0x14, 0xe7, 0xfa, 0x24, 0xeb, 0xf4, 0x5f, 0xc0, 0x3a, 0xc5, 0x4a, 0xe1,
- 0xac, 0x21, 0xc7, 0x90, 0xa4, 0xd1, 0x0f, 0xe1, 0x2e, 0x51, 0xd6, 0x6f,
- 0x21, 0xbf, 0xff, 0xef, 0xe7, 0xbc, 0xf1, 0xe7, 0x8e, 0xc2, 0x28, 0x8b,
- 0x0c, 0x58, 0xbf, 0xf3, 0xeb, 0xd9, 0xd8, 0x1d, 0xe2, 0x58, 0xbf, 0xe2,
- 0xc3, 0x3f, 0x87, 0x9e, 0x2c, 0x5f, 0xf6, 0x34, 0x3f, 0x3f, 0x63, 0x56,
- 0x2f, 0xf1, 0x38, 0x39, 0xd7, 0xda, 0x23, 0xf2, 0x23, 0x9a, 0x1a, 0x6c,
- 0x91, 0x34, 0x7a, 0x16, 0x57, 0xf7, 0xbf, 0x90, 0x80, 0x16, 0x2a, 0x4f,
- 0x98, 0x8d, 0xef, 0xf1, 0x3b, 0xef, 0x86, 0xf0, 0x2c, 0x5f, 0xff, 0x72,
- 0x62, 0xfc, 0xef, 0x2c, 0x1f, 0xe7, 0x8b, 0x14, 0x34, 0x44, 0xf8, 0xde,
- 0xfb, 0xa9, 0x07, 0x16, 0x2f, 0xef, 0xb1, 0x9b, 0x32, 0x05, 0x8b, 0xff,
- 0xc7, 0x6e, 0xe1, 0xc2, 0xce, 0xbc, 0x22, 0x58, 0xbf, 0xdc, 0xcd, 0xc0,
- 0x3b, 0xc4, 0xb1, 0x7f, 0xfb, 0x3d, 0xc6, 0xcd, 0x48, 0x38, 0xdb, 0xd6,
- 0x2b, 0x13, 0x47, 0xe8, 0x8e, 0x22, 0x43, 0x99, 0x7d, 0x33, 0x64, 0xde,
- 0xff, 0xef, 0x7f, 0x37, 0xee, 0x30, 0x87, 0x83, 0x58, 0xbd, 0xfc, 0xf2,
- 0xc5, 0xff, 0x70, 0x5a, 0x87, 0x44, 0xfb, 0xab, 0x17, 0xcf, 0xe2, 0xc1,
- 0x9e, 0xdf, 0x87, 0x6f, 0xa1, 0xc6, 0x1a, 0xc5, 0xcd, 0xc5, 0x8b, 0x01,
- 0x8d, 0xd1, 0xc8, 0xea, 0x55, 0xc4, 0x64, 0x7e, 0x0c, 0xb8, 0xf0, 0xa5,
- 0x13, 0x8d, 0xf8, 0xba, 0x7e, 0x32, 0xc5, 0xff, 0xfd, 0xa2, 0x99, 0xef,
- 0x6f, 0x3c, 0x52, 0x3f, 0xcf, 0x96, 0x2e, 0x6f, 0xac, 0x5f, 0x40, 0x9c,
- 0x35, 0x8b, 0xfc, 0x37, 0x06, 0xb4, 0xe0, 0x58, 0xbe, 0xd7, 0x5b, 0x86,
- 0x2c, 0x5f, 0x1a, 0x15, 0x73, 0x16, 0x2b, 0x0f, 0x49, 0xca, 0x69, 0x91,
- 0x4c, 0x50, 0x86, 0xa9, 0x4e, 0x2f, 0x0a, 0x37, 0x17, 0x5c, 0x5c, 0x50,
- 0xc9, 0xbf, 0xfb, 0x45, 0x9b, 0xf5, 0x8d, 0xf9, 0x1a, 0xc5, 0xe7, 0xdc,
- 0x65, 0x8b, 0xff, 0x07, 0xe3, 0x58, 0xd9, 0xc2, 0x95, 0x8b, 0x76, 0xb1,
- 0x7f, 0xf9, 0x9d, 0xe2, 0xf7, 0xf2, 0x1f, 0x6d, 0xeb, 0x17, 0xff, 0xd9,
- 0xee, 0x61, 0x99, 0xf6, 0xd0, 0xa4, 0x0b, 0x15, 0x28, 0xaf, 0xdc, 0x13,
- 0x24, 0xcb, 0xf0, 0x7e, 0x29, 0x02, 0xc5, 0x4a, 0x75, 0xbd, 0xa2, 0xe8,
- 0x7c, 0xf0, 0xef, 0xde, 0x63, 0x7e, 0x9f, 0x67, 0xe5, 0x62, 0xff, 0x3e,
- 0x80, 0x2e, 0x8e, 0xcb, 0x17, 0xfe, 0x11, 0x45, 0xfc, 0x2c, 0x61, 0xac,
- 0x5e, 0x8e, 0x2c, 0x58, 0xbf, 0xfe, 0xdf, 0x9d, 0x69, 0xdf, 0xb8, 0x73,
- 0x71, 0x89, 0x62, 0xa4, 0xfd, 0x5c, 0x7e, 0xff, 0xed, 0xc6, 0xcf, 0xce,
- 0xfe, 0x7e, 0x7b, 0x58, 0xa9, 0x4d, 0x49, 0x8d, 0x7f, 0x0b, 0x3e, 0x10,
- 0x5f, 0x4f, 0xb0, 0xeb, 0x17, 0xfe, 0xe7, 0xf0, 0xcf, 0xb1, 0x85, 0x8b,
- 0x14, 0x03, 0xe2, 0xde, 0x45, 0x7e, 0xee, 0x05, 0x27, 0x58, 0xbf, 0xff,
- 0xff, 0xc7, 0xdc, 0x6f, 0x83, 0x1c, 0xba, 0xce, 0xe1, 0xc6, 0xf7, 0x1b,
- 0xb8, 0x14, 0xfe, 0x56, 0x2f, 0xec, 0xfb, 0x66, 0xa2, 0x58, 0xbf, 0xf6,
- 0x77, 0x0e, 0x37, 0x9c, 0xb1, 0x62, 0xff, 0x61, 0xff, 0x91, 0x3c, 0x4b,
- 0x17, 0xe6, 0x8f, 0xf3, 0x3b, 0x4f, 0xcf, 0xc7, 0xd5, 0xb5, 0x1c, 0x39,
- 0x0a, 0x1b, 0xff, 0xdf, 0x9e, 0xf3, 0x53, 0xe6, 0xe9, 0x86, 0xb1, 0x78,
- 0x5a, 0x89, 0x62, 0xfb, 0x22, 0xcf, 0x0c, 0xfa, 0xb8, 0x97, 0x66, 0x1a,
- 0x33, 0x3f, 0x09, 0x3a, 0x95, 0x52, 0xb8, 0x53, 0xf9, 0x47, 0xf7, 0xff,
- 0xec, 0x6f, 0x71, 0xbd, 0x3e, 0xe1, 0x66, 0x18, 0xb1, 0x7f, 0xff, 0xe6,
- 0x2c, 0xf4, 0x9c, 0xc1, 0x3c, 0x7b, 0x73, 0xed, 0xaf, 0xba, 0xc5, 0xf8,
- 0xd3, 0x5f, 0xdc, 0x58, 0xbf, 0xfe, 0xc8, 0xdc, 0x6c, 0x2e, 0xb4, 0xc6,
- 0x44, 0xcb, 0x15, 0x28, 0xec, 0xc6, 0xed, 0x15, 0xdc, 0xfb, 0xab, 0x17,
- 0xbe, 0xc6, 0x2c, 0x5f, 0xbb, 0x87, 0x0b, 0x0e, 0x6e, 0x3c, 0x35, 0x7f,
- 0xdd, 0xc3, 0x91, 0x69, 0xfd, 0xc5, 0x8b, 0xff, 0xff, 0xf7, 0xe7, 0x5c,
- 0xc6, 0x23, 0x76, 0xfd, 0xb6, 0xf1, 0x85, 0xd9, 0xdd, 0xc8, 0x6b, 0x17,
- 0xff, 0xff, 0xff, 0xff, 0xb5, 0xac, 0x62, 0x8f, 0x6f, 0xdb, 0x6f, 0x5f,
- 0x6f, 0xb9, 0x9b, 0x41, 0x31, 0x6d, 0xfe, 0x66, 0xd2, 0xc1, 0xfd, 0xf6,
- 0xe6, 0x19, 0xe5, 0x8b, 0xa2, 0xda, 0x34, 0xda, 0x32, 0x10, 0xf5, 0x89,
- 0xee, 0x3c, 0x74, 0xb7, 0xe2, 0x9e, 0xa0, 0x75, 0x8b, 0xff, 0xd9, 0xb9,
- 0xf1, 0x45, 0xfc, 0x8a, 0x13, 0xda, 0xc5, 0xff, 0xdc, 0xc8, 0xbf, 0x3b,
- 0xf3, 0xff, 0x95, 0x8a, 0x1a, 0x30, 0x74, 0x53, 0xe5, 0x1b, 0xfc, 0xe0,
- 0xe1, 0xdf, 0xbf, 0x2c, 0x52, 0xc5, 0xff, 0x70, 0x84, 0x2f, 0x42, 0x4d,
- 0x58, 0xae, 0xcf, 0x1f, 0xc1, 0x95, 0x88, 0xcf, 0x73, 0x01, 0x3e, 0x5f,
- 0xfb, 0x23, 0xd4, 0xcf, 0x9b, 0xf2, 0xb1, 0x7f, 0xe6, 0x8b, 0x84, 0xee,
- 0x3f, 0xb2, 0xc5, 0xfc, 0x59, 0xcf, 0xc8, 0xd6, 0x2a, 0x4f, 0xaf, 0x0f,
- 0xaf, 0xff, 0xff, 0x8a, 0x7f, 0x85, 0x8c, 0x30, 0x4f, 0x70, 0xe1, 0xb3,
- 0x25, 0xd6, 0x0d, 0x62, 0x89, 0x34, 0x5e, 0x42, 0xa7, 0xc4, 0x17, 0xff,
- 0xa0, 0xc6, 0xb7, 0x8b, 0x21, 0xae, 0x71, 0x62, 0xff, 0xec, 0x38, 0xa0,
- 0xe3, 0xdb, 0xe3, 0x81, 0x62, 0xfe, 0x98, 0xb3, 0x7b, 0x69, 0x62, 0xff,
- 0xf4, 0x3e, 0xf0, 0xe8, 0x9f, 0x77, 0x77, 0x75, 0x96, 0x2a, 0x51, 0x09,
- 0x86, 0x17, 0xcd, 0xac, 0x25, 0x8a, 0x94, 0xd6, 0x7e, 0x96, 0x50, 0xcc,
- 0xe1, 0x0d, 0xfb, 0xb1, 0xfd, 0x8c, 0x58, 0xbf, 0xf8, 0x43, 0xc2, 0x14,
- 0x18, 0x78, 0x05, 0x8a, 0x93, 0xef, 0x62, 0xbb, 0xff, 0x84, 0xe7, 0xf1,
- 0x64, 0x65, 0x9d, 0xac, 0x5f, 0xf6, 0x75, 0x3f, 0x69, 0x21, 0xac, 0x5f,
- 0xfd, 0xfc, 0x30, 0x58, 0xdf, 0xe4, 0xc6, 0xb1, 0x73, 0x0a, 0x33, 0xfe,
- 0xec, 0xe2, 0xa3, 0x67, 0xa3, 0x8e, 0x37, 0x9c, 0x85, 0x1f, 0x52, 0xae,
- 0x62, 0x37, 0xd4, 0x68, 0x0e, 0xcc, 0x09, 0x43, 0x45, 0x1d, 0xc7, 0x23,
- 0x73, 0xf4, 0x71, 0xdb, 0xe1, 0x60, 0x61, 0x06, 0xec, 0x30, 0xef, 0xa2,
- 0x83, 0x44, 0xb1, 0x71, 0x46, 0xb1, 0x7c, 0x0d, 0x3e, 0xca, 0xc5, 0x6d,
- 0x3e, 0x3d, 0x80, 0x97, 0xb1, 0x8b, 0xff, 0x31, 0x9b, 0x8d, 0x1f, 0x26,
- 0x62, 0x58, 0xb6, 0xea, 0xc5, 0xdf, 0xdd, 0x58, 0xbf, 0xfd, 0x9b, 0xfe,
- 0xf0, 0x03, 0xf6, 0x06, 0xed, 0x62, 0xde, 0x93, 0xe9, 0xf8, 0xdd, 0xff,
- 0xf6, 0xa3, 0x9d, 0xce, 0x16, 0x7b, 0xcd, 0xae, 0x96, 0x2f, 0xec, 0x8f,
- 0x85, 0x9b, 0xd6, 0x2a, 0x09, 0x95, 0x33, 0xf3, 0x93, 0xf9, 0x56, 0xef,
- 0x86, 0xb1, 0x63, 0x56, 0x2a, 0x5b, 0x30, 0xdc, 0xa7, 0xcc, 0xb4, 0x6c,
- 0xfb, 0x86, 0xef, 0x1b, 0x77, 0x0f, 0x03, 0x19, 0xbf, 0xff, 0x43, 0x38,
- 0xe4, 0x0f, 0xe4, 0xfb, 0x92, 0x05, 0x8b, 0xe7, 0x3b, 0xc1, 0x62, 0xff,
- 0xef, 0xb6, 0xdc, 0x2c, 0x6d, 0x3e, 0xf5, 0x8b, 0xff, 0x98, 0x9c, 0x65,
- 0x83, 0xfc, 0xf1, 0x62, 0xf0, 0x73, 0xa5, 0x8b, 0xfe, 0x8c, 0xf3, 0xaf,
- 0x14, 0xc6, 0xb1, 0x7d, 0xd7, 0x66, 0xf4, 0xb1, 0x78, 0x39, 0x02, 0xc5,
- 0x31, 0xe3, 0x00, 0xa2, 0xfb, 0x7c, 0x97, 0x4b, 0x17, 0xff, 0xf4, 0x96,
- 0x03, 0x98, 0x3f, 0xcc, 0x67, 0x11, 0x0d, 0x62, 0x99, 0x10, 0x1f, 0x25,
- 0xbf, 0x37, 0xbd, 0x30, 0x58, 0xba, 0x7b, 0x58, 0xa8, 0x2a, 0xa0, 0x1a,
- 0xa1, 0xa4, 0x5d, 0x23, 0x69, 0x09, 0xc7, 0x8a, 0x10, 0x3e, 0x85, 0x0e,
- 0xf2, 0x2d, 0x92, 0x8b, 0xf8, 0xbd, 0x3c, 0xf3, 0x2c, 0x5f, 0xff, 0xd3,
- 0x16, 0x0f, 0xf3, 0xbf, 0xf9, 0xe2, 0x99, 0x3a, 0xc5, 0xff, 0x0c, 0xa6,
- 0x18, 0x79, 0xe9, 0x62, 0xfe, 0xec, 0x63, 0xc7, 0x8d, 0x62, 0xfe, 0xc3,
- 0x35, 0x9f, 0xe2, 0xc5, 0xff, 0xed, 0x3f, 0x59, 0xbd, 0xb5, 0xb2, 0xf1,
- 0xec, 0xac, 0x5f, 0xff, 0xbe, 0xdb, 0xcb, 0x0c, 0xc6, 0xf3, 0x69, 0xc0,
- 0xb1, 0x78, 0xa4, 0x6b, 0x17, 0xd0, 0xcf, 0xe2, 0xc5, 0xe8, 0xc4, 0x4b,
- 0x17, 0x77, 0xcd, 0xa9, 0xcf, 0x49, 0xcc, 0x66, 0x03, 0x2f, 0xe9, 0x52,
- 0x25, 0x67, 0x1c, 0x0c, 0x8a, 0xf9, 0x9c, 0x86, 0xb1, 0x7f, 0x7d, 0xa2,
- 0x77, 0x8d, 0x62, 0xf4, 0xe0, 0x16, 0x2d, 0x23, 0x3e, 0xce, 0x88, 0x62,
- 0x2f, 0xa9, 0x56, 0x98, 0x72, 0xd7, 0x8f, 0xe8, 0x10, 0xef, 0xbe, 0x68,
- 0xcf, 0x2b, 0x17, 0xf4, 0xea, 0x39, 0xd4, 0x6b, 0x17, 0xff, 0x89, 0xcc,
- 0xfc, 0xc1, 0x8b, 0x0f, 0x2b, 0x17, 0xff, 0x67, 0x7e, 0x9c, 0xd6, 0xa6,
- 0x77, 0x56, 0x2c, 0x64, 0x48, 0x8f, 0x24, 0x8b, 0xfe, 0x68, 0xf0, 0xc9,
- 0xf8, 0x89, 0x62, 0xa0, 0x99, 0x1e, 0x42, 0xff, 0xe5, 0x57, 0xfd, 0xbd,
- 0xc8, 0x1f, 0xc0, 0x3a, 0xc5, 0xf9, 0x8d, 0xf3, 0x46, 0xb1, 0x7f, 0xfb,
- 0x30, 0x07, 0x98, 0xb8, 0x3f, 0xbc, 0x6b, 0x14, 0xc8, 0xb0, 0xf9, 0xd1,
- 0x15, 0x5f, 0xfe, 0x9f, 0xc9, 0xe2, 0x2c, 0x33, 0xd9, 0xf5, 0x8b, 0xf8,
- 0xbf, 0x80, 0x92, 0x58, 0xa5, 0x8b, 0xf4, 0x35, 0x38, 0x35, 0x8b, 0x98,
- 0x5d, 0x9b, 0x42, 0x0c, 0xbf, 0xff, 0xd9, 0x0e, 0xbe, 0xdf, 0x9c, 0xd4,
- 0x3c, 0x52, 0x7e, 0x2c, 0x5f, 0xf6, 0x1f, 0x92, 0x77, 0xef, 0xcb, 0x17,
- 0xfc, 0xf1, 0x8a, 0x70, 0x85, 0x1a, 0xc5, 0x61, 0xfa, 0x68, 0xea, 0xbe,
- 0x8f, 0x6e, 0x43, 0x56, 0xff, 0xe9, 0xe1, 0x61, 0xad, 0xff, 0xe6, 0xe2,
- 0xc5, 0xff, 0x0b, 0xdb, 0x9c, 0xc6, 0x21, 0xac, 0x5f, 0x0a, 0x7b, 0x1a,
- 0xc5, 0xfe, 0xc3, 0xe4, 0x50, 0x6c, 0x58, 0xa1, 0xaa, 0xfd, 0xe8, 0xb9,
- 0xd2, 0xf8, 0xc1, 0xe8, 0xc8, 0x84, 0x51, 0xbd, 0x1c, 0xc3, 0xc0, 0xc9,
- 0x2e, 0x19, 0xd6, 0x2f, 0xb7, 0x67, 0x51, 0xac, 0x5e, 0x17, 0xb8, 0xb1,
- 0x7b, 0x75, 0x8c, 0x58, 0xa9, 0x5c, 0xea, 0xc9, 0x7c, 0x51, 0x42, 0x29,
- 0xc6, 0x04, 0x4f, 0xba, 0x3d, 0x60, 0xaa, 0xc5, 0xf6, 0x37, 0xc4, 0xb1,
- 0x7e, 0x92, 0xcd, 0xee, 0xb1, 0x6e, 0xa2, 0x3c, 0xad, 0x11, 0x54, 0x68,
- 0x8a, 0xd3, 0x05, 0xff, 0xf9, 0xbd, 0xc6, 0xe9, 0xf5, 0xd7, 0xdb, 0x7b,
- 0x9d, 0x62, 0xff, 0xff, 0x9c, 0xde, 0x0d, 0xb3, 0xbe, 0x98, 0x9f, 0xb3,
- 0xcc, 0xf1, 0x62, 0xff, 0xf1, 0xe7, 0xaf, 0x73, 0x01, 0x39, 0xdc, 0x16,
- 0x2f, 0x8d, 0x6e, 0x99, 0x62, 0xe9, 0x86, 0x1f, 0x87, 0x93, 0x2b, 0xe9,
- 0x82, 0x14, 0x36, 0x2f, 0x0f, 0x20, 0xb1, 0x7b, 0x71, 0x8c, 0x58, 0xbc,
- 0x6b, 0x74, 0xb1, 0x7e, 0x6d, 0xe5, 0x9c, 0xda, 0x7b, 0xbf, 0x1d, 0xf1,
- 0x0d, 0xff, 0x6f, 0xc1, 0xc5, 0x98, 0x46, 0xac, 0x5f, 0xfe, 0x84, 0xf3,
- 0xf2, 0x5e, 0xfe, 0xe3, 0x1d, 0x62, 0x89, 0x11, 0x3e, 0x3c, 0xbf, 0xf4,
- 0x9f, 0x8d, 0xa9, 0xf3, 0x6f, 0x58, 0xbf, 0x6e, 0x37, 0xde, 0x25, 0x8b,
- 0x7a, 0x4f, 0xb3, 0xe8, 0x17, 0xf4, 0xf4, 0x4f, 0xdf, 0x96, 0x2f, 0xf7,
- 0x35, 0x31, 0xbe, 0xba, 0x58, 0xbe, 0x8f, 0x66, 0x4e, 0xb1, 0x4c, 0x7b,
- 0xa1, 0x9b, 0x54, 0x15, 0x1d, 0x34, 0x35, 0xf7, 0x21, 0x1c, 0x72, 0x7f,
- 0x42, 0x32, 0xfd, 0x3e, 0x8f, 0x0c, 0x58, 0xbf, 0xf7, 0x7d, 0x13, 0xc6,
- 0xf0, 0x6f, 0xac, 0x56, 0x8f, 0xac, 0x45, 0x57, 0x98, 0x1c, 0x58, 0xbe,
- 0xc8, 0xf7, 0xf9, 0x62, 0xb0, 0xf0, 0xc4, 0x3b, 0x7f, 0xf7, 0x1f, 0xbf,
- 0x7b, 0x3a, 0x18, 0xa3, 0x58, 0xb6, 0x74, 0x7d, 0x5e, 0x21, 0xbf, 0x0f,
- 0xa1, 0x66, 0xe2, 0xc5, 0xff, 0x8a, 0x7b, 0xfc, 0xb1, 0x38, 0xd6, 0x2a,
- 0x23, 0xea, 0x39, 0x6d, 0xf7, 0x30, 0x8d, 0x58, 0xbe, 0x9c, 0x83, 0xac,
- 0x57, 0x67, 0x89, 0xf2, 0x3b, 0xff, 0xfe, 0xe7, 0xf3, 0xdb, 0x38, 0x4d,
- 0x3d, 0x96, 0x6f, 0x9c, 0x31, 0x62, 0xf8, 0x1b, 0x00, 0x57, 0x62, 0x58,
- 0xa6, 0x44, 0xe6, 0x9a, 0xaa, 0x53, 0x48, 0x1b, 0x3b, 0xc2, 0xfe, 0xff,
- 0x0f, 0x7c, 0x97, 0xb0, 0x0b, 0x17, 0xe9, 0xf7, 0xe7, 0xcb, 0x17, 0x10,
- 0x16, 0x2a, 0x33, 0xf4, 0xd1, 0xab, 0x94, 0x5f, 0xe7, 0xef, 0x9a, 0xcf,
- 0xf1, 0x62, 0xff, 0xff, 0xf0, 0xb5, 0xfc, 0x8a, 0x27, 0xd4, 0x5e, 0xf8,
- 0x81, 0xcc, 0x6d, 0xe3, 0x95, 0x8b, 0xfe, 0x6f, 0xf3, 0x4c, 0x52, 0x75,
- 0x8b, 0xfa, 0x79, 0xb8, 0xdd, 0xf9, 0x62, 0xfe, 0x9e, 0x44, 0x59, 0x12,
- 0xc5, 0x32, 0x62, 0xfb, 0x8f, 0xda, 0x38, 0xf9, 0x95, 0xfb, 0xdf, 0x72,
- 0x35, 0x62, 0xff, 0x6e, 0x90, 0x85, 0xd3, 0x1a, 0xb1, 0x6f, 0x2c, 0x52,
- 0xc5, 0xf3, 0x18, 0x77, 0xec, 0xbe, 0xf0, 0x95, 0xfe, 0x14, 0x63, 0xfe,
- 0x14, 0xac, 0x54, 0xa3, 0x0f, 0xa5, 0x72, 0x38, 0xbf, 0xcd, 0x86, 0x45,
- 0x06, 0x25, 0x8b, 0xff, 0xe9, 0x3e, 0xe3, 0x4c, 0x96, 0xb1, 0x8f, 0x8b,
- 0x17, 0xff, 0x60, 0xff, 0x26, 0x77, 0x0f, 0x08, 0x6b, 0x17, 0xf0, 0x31,
- 0x8f, 0x3b, 0x8b, 0x17, 0xff, 0x03, 0xec, 0x2f, 0x73, 0xe2, 0xcf, 0x2c,
- 0x5d, 0x9c, 0x58, 0xb9, 0xfc, 0xb1, 0x68, 0x68, 0xd7, 0x7c, 0x5e, 0x9d,
- 0x13, 0x62, 0x74, 0xac, 0x47, 0x6f, 0x21, 0x97, 0x6c, 0x1a, 0xb3, 0xac,
- 0x40, 0xea, 0x1d, 0x9b, 0x85, 0xf1, 0x1a, 0x12, 0x7f, 0xa3, 0x35, 0xbf,
- 0xfd, 0x9a, 0xd8, 0xf9, 0xe2, 0x6e, 0xf9, 0xb7, 0xcb, 0x17, 0xff, 0xb2,
- 0x4b, 0x3a, 0x2c, 0xf0, 0x9c, 0xc5, 0x8b, 0xff, 0x8b, 0xf9, 0x3d, 0xbb,
- 0x70, 0x33, 0x56, 0x2f, 0xff, 0xd0, 0x6f, 0x6d, 0x1f, 0xe7, 0x45, 0x9b,
- 0xdf, 0xcb, 0x15, 0x28, 0x9f, 0x89, 0x1a, 0xff, 0xfa, 0x37, 0x2f, 0x70,
- 0x45, 0xef, 0x7d, 0xc6, 0xb1, 0x7f, 0xd8, 0x0d, 0x9c, 0x71, 0xe7, 0x16,
- 0x2f, 0xfe, 0x6f, 0x7f, 0x1a, 0x1c, 0xce, 0xfc, 0xb1, 0x43, 0x4f, 0x73,
- 0x21, 0xd0, 0xe4, 0x64, 0xa3, 0xc3, 0xbb, 0xf8, 0xa6, 0x1f, 0xe0, 0x16,
- 0x2f, 0xf8, 0x05, 0x9e, 0xe3, 0xb9, 0x2c, 0x5f, 0xfc, 0x2c, 0x8b, 0x1b,
- 0xa2, 0xcf, 0xe2, 0xc5, 0x80, 0x34, 0x54, 0xf4, 0x5c, 0x46, 0xf7, 0x8e,
- 0xfd, 0xac, 0x5f, 0xff, 0xd0, 0x61, 0xe7, 0xf2, 0x39, 0x83, 0x73, 0x99,
- 0xb8, 0xb1, 0x5a, 0x45, 0x90, 0x0d, 0xbc, 0x3d, 0x70, 0x8d, 0x58, 0xbf,
- 0xd9, 0xf1, 0xfe, 0x4a, 0x35, 0x8b, 0x0f, 0xe7, 0x9a, 0x60, 0xcd, 0xf7,
- 0xf0, 0x6c, 0xb1, 0x52, 0x79, 0x7c, 0x29, 0xa9, 0x6c, 0x91, 0xe0, 0x48,
- 0x38, 0xd7, 0x72, 0x55, 0xfb, 0x43, 0x23, 0x50, 0xcf, 0xfc, 0x7b, 0x4f,
- 0x0a, 0x80, 0x17, 0x94, 0xe4, 0x37, 0x1e, 0x7d, 0x28, 0xbc, 0x51, 0xd4,
- 0x07, 0x0c, 0x8b, 0xfd, 0x83, 0x8f, 0x42, 0x90, 0x2c, 0x5f, 0xff, 0x01,
- 0xff, 0x80, 0x03, 0xeb, 0x37, 0xff, 0x16, 0x2f, 0xff, 0xde, 0xe1, 0x08,
- 0x5d, 0xc3, 0x83, 0xfe, 0x37, 0x96, 0x2b, 0x48, 0xde, 0x39, 0xa9, 0x28,
- 0xdf, 0xd0, 0xd6, 0xa4, 0xfc, 0x58, 0xa9, 0x3d, 0xee, 0xcb, 0xef, 0xff,
- 0x13, 0x0c, 0x73, 0xee, 0x0f, 0xf2, 0x4b, 0x16, 0x3a, 0xc5, 0xf8, 0x0c,
- 0x50, 0xe2, 0xc5, 0x76, 0x6e, 0xbc, 0x25, 0x58, 0x8a, 0x56, 0x84, 0x1d,
- 0xfd, 0xf8, 0x9b, 0xec, 0x75, 0x8b, 0x81, 0xc5, 0x8b, 0xee, 0x88, 0x5c,
- 0x58, 0xbf, 0xe1, 0xe1, 0xcb, 0x3d, 0xf6, 0x58, 0xbf, 0x0b, 0x40, 0x0a,
- 0x6c, 0x35, 0x8a, 0xc4, 0x48, 0x31, 0x27, 0x0e, 0x2b, 0x13, 0x05, 0x62,
- 0xff, 0xc2, 0xa2, 0xfb, 0x85, 0x31, 0xac, 0x5f, 0xf7, 0x85, 0xb7, 0x33,
- 0xac, 0x95, 0x8a, 0xd1, 0xef, 0x11, 0x1d, 0xff, 0xfb, 0x74, 0xb3, 0x7b,
- 0xf1, 0xb0, 0xbf, 0xb8, 0xc7, 0x58, 0xb4, 0x30, 0xff, 0x18, 0x86, 0xf4,
- 0xe1, 0x2c, 0x5d, 0x24, 0xb1, 0x5a, 0x36, 0x27, 0x1b, 0xbe, 0x37, 0x52,
- 0x75, 0x8b, 0xd1, 0xe1, 0x8b, 0x17, 0x64, 0x6b, 0x15, 0xb4, 0xff, 0x24,
- 0x84, 0xc2, 0x4d, 0x91, 0xfb, 0xff, 0xff, 0xf4, 0x94, 0x7e, 0xe6, 0x19,
- 0xf9, 0xdf, 0xe2, 0x9e, 0xff, 0x8e, 0x3c, 0xc3, 0xac, 0x5f, 0xe6, 0x2f,
- 0x43, 0x35, 0x8b, 0x17, 0xf8, 0x6f, 0x0f, 0x71, 0xc0, 0xb1, 0x79, 0xa4,
- 0xeb, 0x17, 0x4f, 0x58, 0x7a, 0x1a, 0x34, 0xa8, 0xd3, 0x34, 0x84, 0x21,
- 0x4a, 0x10, 0x57, 0xff, 0x8f, 0x83, 0xf7, 0xc4, 0x03, 0x70, 0xbc, 0xb1,
- 0x7f, 0xf0, 0x1f, 0x59, 0xbf, 0x18, 0x7f, 0x65, 0x8a, 0xc4, 0x48, 0x9d,
- 0x32, 0xff, 0xce, 0x0d, 0x49, 0x7b, 0xf9, 0x05, 0x8b, 0xff, 0xc0, 0xc6,
- 0x2f, 0x61, 0xdf, 0xc0, 0x75, 0x8a, 0x94, 0xdd, 0x32, 0x19, 0x8c, 0x44,
- 0x23, 0xeb, 0xd9, 0xf7, 0x58, 0xbf, 0xf7, 0x07, 0xf9, 0x8a, 0x0d, 0xa8,
- 0x2c, 0x5e, 0x10, 0x89, 0x62, 0xfc, 0xdf, 0xfe, 0x0d, 0x62, 0x96, 0x06,
- 0x78, 0xbc, 0x1d, 0xae, 0xd1, 0x61, 0x14, 0x21, 0xa8, 0x68, 0xf6, 0x78,
- 0x66, 0x5f, 0xfb, 0x21, 0xf7, 0x86, 0xdf, 0x41, 0x96, 0x2f, 0xc5, 0x80,
- 0x17, 0x16, 0x2f, 0xf4, 0xfb, 0xf8, 0xc4, 0xeb, 0x15, 0x19, 0xec, 0xe8,
- 0xa2, 0xff, 0x03, 0x67, 0x1c, 0x79, 0xc5, 0x8b, 0xdb, 0x8c, 0x75, 0x8b,
- 0xff, 0xe7, 0x07, 0x24, 0x1e, 0xc6, 0x1e, 0x14, 0x4b, 0x1f, 0x34, 0x15,
- 0x28, 0xd8, 0xc2, 0x37, 0x56, 0xbf, 0xd0, 0xf7, 0xf3, 0x53, 0xe5, 0x8b,
- 0xf8, 0xcc, 0xeb, 0xac, 0x31, 0x62, 0xee, 0xb7, 0xac, 0x58, 0x0b, 0x17,
- 0xff, 0xa1, 0xcc, 0xd4, 0xf0, 0xb0, 0x02, 0xe2, 0xc5, 0x61, 0xee, 0x38,
- 0x95, 0x4a, 0x25, 0xfe, 0xef, 0x58, 0x8e, 0xbf, 0x43, 0x26, 0xff, 0xf6,
- 0x6e, 0x80, 0xf3, 0x17, 0x98, 0x5a, 0xe2, 0xc5, 0xfe, 0x3e, 0x61, 0x7b,
- 0x67, 0x16, 0x2f, 0xfe, 0xe7, 0xa6, 0x74, 0x08, 0x8b, 0x0c, 0x58, 0xbe,
- 0x00, 0x1c, 0x6b, 0x17, 0x67, 0x6b, 0x16, 0xfe, 0x1b, 0xb6, 0x23, 0xae,
- 0xd1, 0xb6, 0xe6, 0xa0, 0x84, 0x0d, 0xe3, 0x60, 0x25, 0x8b, 0xf7, 0xe7,
- 0x51, 0x9d, 0x62, 0xff, 0x09, 0xcb, 0xf8, 0xf1, 0x2c, 0x5b, 0xb8, 0x8f,
- 0x74, 0xc2, 0xaa, 0x64, 0x53, 0xbb, 0xe5, 0x4a, 0xb6, 0xdc, 0x8c, 0x7d,
- 0x89, 0xde, 0x32, 0xa2, 0x86, 0xe5, 0xff, 0x3e, 0xee, 0xb0, 0x89, 0xe2,
- 0x58, 0xbb, 0xe7, 0x58, 0xa9, 0x66, 0xe8, 0x42, 0x18, 0xf9, 0x19, 0x5f,
- 0x71, 0x87, 0x34, 0x34, 0xff, 0x2b, 0xa5, 0xe3, 0x36, 0x01, 0x39, 0x46,
- 0xe5, 0xc9, 0x73, 0x42, 0x58, 0x30, 0xee, 0xfb, 0x59, 0xfe, 0x2c, 0x5c,
- 0x22, 0x58, 0xbe, 0xef, 0x93, 0xda, 0xc5, 0x6c, 0x67, 0xbe, 0x17, 0x23,
- 0x21, 0x7b, 0xff, 0xdf, 0x61, 0x14, 0x78, 0x38, 0x84, 0x2d, 0x2c, 0x5f,
- 0xa2, 0x68, 0xf3, 0xb5, 0x8b, 0xda, 0x14, 0x16, 0x2b, 0xb3, 0xc9, 0xf1,
- 0x5d, 0xfd, 0xb7, 0xc5, 0x27, 0xe2, 0xc5, 0xf6, 0x73, 0x0c, 0x58, 0xa8,
- 0x26, 0x18, 0xd0, 0x96, 0x72, 0x32, 0x30, 0xbf, 0xf3, 0xeb, 0x58, 0x1e,
- 0x0d, 0xe0, 0xb1, 0x78, 0xb0, 0x0b, 0x16, 0x95, 0x8a, 0x01, 0xad, 0xf0,
- 0xe5, 0xcf, 0xe5, 0x8a, 0xd1, 0xb8, 0xf9, 0x0d, 0xf1, 0xe7, 0x5c, 0x58,
- 0xbf, 0xd2, 0x72, 0xc0, 0x0b, 0x8b, 0x17, 0xfd, 0xac, 0xfe, 0x47, 0xb5,
- 0xb8, 0xb1, 0x58, 0x8b, 0x36, 0x21, 0x22, 0x31, 0x19, 0xdf, 0xe8, 0x37,
- 0x39, 0x3a, 0x82, 0xc5, 0xf3, 0x9e, 0x59, 0x62, 0xf7, 0x98, 0xc5, 0x8a,
- 0x19, 0xf9, 0xc4, 0x68, 0x61, 0x0d, 0xfc, 0xc4, 0x28, 0x67, 0x16, 0x2f,
- 0xff, 0xd0, 0x6f, 0x73, 0xaf, 0xb7, 0xbb, 0x83, 0x7b, 0x8b, 0x17, 0xfd,
- 0x20, 0x3b, 0xc3, 0x59, 0x1a, 0xc5, 0xe8, 0xf3, 0x75, 0x62, 0xfe, 0x9c,
- 0xf7, 0x1f, 0xb5, 0x8b, 0xfe, 0xf4, 0xf6, 0x07, 0xff, 0xd9, 0x62, 0xf9,
- 0xb6, 0x72, 0x35, 0x8a, 0xc3, 0xe0, 0xf1, 0xd5, 0x8e, 0xb1, 0x7f, 0x31,
- 0x0a, 0x19, 0xcd, 0xa6, 0xcf, 0x79, 0x0d, 0x4a, 0xa1, 0x93, 0x4c, 0x62,
- 0x2d, 0xfa, 0xc9, 0x1d, 0x70, 0x87, 0xd0, 0xc1, 0xbe, 0xf8, 0xb3, 0xcb,
- 0x17, 0xfe, 0x17, 0x70, 0xe7, 0xf2, 0x31, 0x12, 0xc5, 0xfe, 0xdb, 0xad,
- 0xc6, 0x06, 0x0d, 0x62, 0xfc, 0x4f, 0xe7, 0x3a, 0xc5, 0x32, 0x31, 0x74,
- 0x46, 0x74, 0x20, 0xce, 0x6c, 0x10, 0x29, 0x08, 0xe3, 0xcd, 0x89, 0x8f,
- 0x60, 0x8c, 0x7b, 0x63, 0x7c, 0xd8, 0x45, 0x61, 0x6a, 0x99, 0x33, 0x91,
- 0xf1, 0xc6, 0x71, 0x08, 0xe8, 0x47, 0x48, 0xb5, 0xca, 0xcb, 0xec, 0xd9,
- 0xcd, 0xce, 0xa7, 0x82, 0x3b, 0x8c, 0x85, 0xa3, 0xff, 0xdc, 0x6d, 0x8a,
- 0x72, 0x2b, 0x53, 0xb9, 0xa7, 0x8f, 0x7b, 0xf5, 0xa8, 0x53, 0xcb, 0x1e,
- 0x04, 0xbe, 0x80, 0xba, 0x41, 0x4f, 0x18, 0x72, 0xb3, 0x38, 0xf5, 0x60,
- 0x10, 0x28, 0xcd, 0x77, 0xc6, 0x86, 0x62, 0x06, 0xcc, 0x6a, 0xe1, 0xca,
- 0xc6, 0xdd, 0x8c, 0xc2, 0xfe, 0xd0, 0x41, 0xef, 0x69, 0x58, 0xbf, 0xb7,
- 0x58, 0x65, 0x31, 0x2c, 0x5e, 0x97, 0x25, 0x8b, 0xec, 0xfb, 0xf9, 0x62,
- 0xc1, 0x5c, 0x3e, 0xef, 0x98, 0x90, 0xdd, 0xfd, 0xb0, 0xb6, 0x07, 0xf6,
- 0x6e, 0xac, 0x5f, 0xfd, 0x27, 0x29, 0xdb, 0x14, 0x27, 0x51, 0xac, 0x5f,
- 0xfe, 0x9d, 0x0a, 0x28, 0x9b, 0xec, 0x77, 0x1a, 0xc5, 0xfd, 0x87, 0xdb,
- 0x11, 0x44, 0xb1, 0x7e, 0x7f, 0x72, 0x77, 0x16, 0x28, 0x67, 0xba, 0x46,
- 0x57, 0xf7, 0xc3, 0xdd, 0x92, 0x02, 0xc5, 0xff, 0xff, 0x8b, 0xdc, 0x96,
- 0x86, 0x6e, 0x97, 0xa7, 0xf2, 0x68, 0xa7, 0x75, 0x62, 0xf6, 0xe8, 0xe5,
- 0x62, 0x9d, 0x12, 0x22, 0x71, 0xbf, 0x0b, 0xd1, 0x49, 0xab, 0x17, 0xfd,
- 0x31, 0xf2, 0x26, 0x3b, 0xc4, 0xb1, 0x43, 0x54, 0xbd, 0xd2, 0x43, 0x42,
- 0xa6, 0x22, 0x1f, 0xc3, 0x0c, 0x88, 0xb7, 0x4a, 0xef, 0xff, 0xfe, 0xcd,
- 0xd2, 0x7e, 0xb7, 0x42, 0x71, 0x8c, 0x2c, 0xe6, 0xd7, 0xf0, 0xa5, 0x62,
- 0xe0, 0x32, 0xc5, 0x69, 0x12, 0x7c, 0x7c, 0xbf, 0xba, 0x7d, 0x47, 0x86,
- 0x2c, 0x56, 0x1e, 0xa3, 0x11, 0xdf, 0xff, 0xbf, 0x85, 0x86, 0xfd, 0xe1,
- 0xf3, 0x1c, 0x33, 0xac, 0x5b, 0xb5, 0x8b, 0xfe, 0x96, 0xe6, 0x37, 0xe7,
- 0xcb, 0x15, 0x03, 0xca, 0xf8, 0x9d, 0xf7, 0x4e, 0xfd, 0x2a, 0x2d, 0x62,
- 0xff, 0xe6, 0xd7, 0xdf, 0x8f, 0xe2, 0x70, 0x2c, 0x5f, 0x36, 0xb7, 0x06,
- 0xb1, 0x50, 0x4d, 0x79, 0xa1, 0x45, 0xa2, 0x2f, 0x98, 0xef, 0x43, 0xbf,
- 0x64, 0x1b, 0xe2, 0x58, 0xbf, 0xe8, 0x09, 0xbf, 0x1b, 0x90, 0xd6, 0x2f,
- 0xfc, 0x4f, 0xa9, 0x8b, 0x6e, 0x69, 0x96, 0x2f, 0xff, 0xdc, 0x29, 0x8b,
- 0x4c, 0x09, 0x6d, 0xd1, 0xe7, 0x16, 0x2f, 0xe6, 0x3b, 0xc5, 0x9f, 0x58,
- 0xa6, 0x46, 0x34, 0x48, 0x07, 0x58, 0xbf, 0x03, 0x37, 0x4b, 0xcb, 0x17,
- 0xf8, 0x45, 0x9b, 0xac, 0x63, 0x2c, 0x5f, 0x71, 0xcb, 0xa5, 0x8a, 0xf9,
- 0xec, 0xee, 0x9b, 0x5d, 0x3e, 0x58, 0xa9, 0x46, 0x06, 0x42, 0x12, 0x22,
- 0x5b, 0xda, 0x93, 0xac, 0x5f, 0xdf, 0xce, 0x4c, 0x7b, 0xab, 0x17, 0xff,
- 0x87, 0x27, 0x29, 0xdb, 0x14, 0x27, 0x51, 0xac, 0x5c, 0x01, 0xac, 0x5f,
- 0xb5, 0xd3, 0xbf, 0x4a, 0x8a, 0x0c, 0xbe, 0xce, 0xb3, 0xb5, 0x8b, 0xa0,
- 0x12, 0x51, 0x82, 0x34, 0xec, 0x18, 0xf9, 0xbd, 0x62, 0x67, 0x8f, 0x0f,
- 0x3b, 0xfe, 0xfe, 0xeb, 0x80, 0x24, 0xf0, 0xc5, 0x8b, 0xd1, 0x4f, 0x96,
- 0x2a, 0x4f, 0x7b, 0x10, 0x2d, 0xd2, 0xc5, 0xfd, 0xfc, 0xf7, 0xdc, 0xeb,
- 0x17, 0xfb, 0x6f, 0xa4, 0xed, 0xa8, 0x96, 0x2b, 0x0f, 0x94, 0x05, 0xd7,
- 0xf6, 0x17, 0x4e, 0x40, 0x58, 0xad, 0xa8, 0xc6, 0x27, 0x8e, 0x10, 0xdf,
- 0xe8, 0x4e, 0xa3, 0x9d, 0x46, 0xb1, 0x7f, 0xbb, 0x84, 0xe7, 0xb6, 0xe2,
- 0xc5, 0xee, 0xa7, 0xa5, 0x8a, 0x94, 0x45, 0xe1, 0xb3, 0x9b, 0x5f, 0x8f,
- 0x9b, 0xa4, 0x05, 0x8b, 0xd8, 0x76, 0x58, 0xbe, 0xd3, 0x1a, 0x75, 0x8b,
- 0xde, 0xcf, 0xac, 0x5f, 0xe9, 0x2f, 0x4e, 0x98, 0xeb, 0x17, 0x79, 0x96,
- 0x2f, 0xff, 0xb0, 0x0f, 0xac, 0xdf, 0x83, 0xc3, 0xcf, 0x4b, 0x15, 0x29,
- 0x91, 0x0c, 0xaf, 0x07, 0x0d, 0x24, 0xf8, 0xeb, 0x99, 0x10, 0xbd, 0xc7,
- 0x89, 0x62, 0xf8, 0x02, 0x28, 0x96, 0x2e, 0x6e, 0x96, 0x2a, 0x4d, 0xe6,
- 0xc9, 0x25, 0xbf, 0xb4, 0xfe, 0x02, 0x2a, 0xdf, 0xda, 0xe6, 0x6a, 0x78,
- 0xb1, 0x7d, 0xc3, 0xc8, 0x16, 0x29, 0x8f, 0x45, 0xcb, 0xaf, 0xd1, 0x01,
- 0xca, 0x25, 0x8b, 0x89, 0x96, 0x2a, 0x4f, 0x03, 0xa2, 0xab, 0xe7, 0x06,
- 0x69, 0x62, 0xfa, 0x42, 0x0c, 0x6b, 0x17, 0xfb, 0x05, 0xd7, 0xe7, 0x58,
- 0xb1, 0x7f, 0xda, 0x93, 0x0b, 0x06, 0xda, 0x58, 0xbf, 0xfe, 0xcf, 0xfd,
- 0xdb, 0xd2, 0x59, 0xfc, 0xe9, 0x62, 0xb1, 0x50, 0x09, 0xaf, 0xac, 0xc1,
- 0xf2, 0x22, 0x22, 0xe1, 0x28, 0x8d, 0x36, 0x4e, 0x6f, 0xff, 0xd8, 0x10,
- 0xb1, 0x8a, 0x62, 0x72, 0x13, 0x46, 0xb1, 0x7f, 0x37, 0x85, 0x13, 0x79,
- 0x62, 0x86, 0x88, 0x48, 0x95, 0x6f, 0xfe, 0x7d, 0xde, 0x66, 0xe9, 0x3f,
- 0xb3, 0x75, 0x62, 0xff, 0x3c, 0x6f, 0x9e, 0xc3, 0xac, 0x5f, 0xff, 0xfd,
- 0xa0, 0x38, 0xe7, 0x5b, 0xbc, 0xcd, 0xd2, 0x04, 0xc4, 0x1e, 0xe8, 0x8e,
- 0xb1, 0x7f, 0xff, 0x3f, 0xb0, 0xf8, 0xd1, 0x43, 0xf8, 0x31, 0x7b, 0x8b,
- 0x17, 0xff, 0xdc, 0x68, 0xdf, 0x8e, 0x4f, 0xef, 0xcc, 0x4b, 0x17, 0xfe,
- 0x72, 0x06, 0x7a, 0x49, 0x80, 0xb1, 0x52, 0x9b, 0x30, 0xdf, 0xbc, 0xb9,
- 0xb2, 0xa1, 0x7f, 0xff, 0xd0, 0x63, 0x1f, 0xf2, 0x3e, 0x9e, 0x3f, 0x16,
- 0x47, 0xa9, 0x58, 0xb0, 0x4d, 0x8d, 0xb3, 0x9a, 0xd8, 0x66, 0xf3, 0x2a,
- 0x6a, 0x11, 0xad, 0x64, 0x6f, 0xc6, 0xa8, 0xf6, 0x50, 0xd1, 0x80, 0x45,
- 0x0f, 0x0d, 0x1a, 0x1e, 0x35, 0x9f, 0xc2, 0x15, 0xe1, 0xcc, 0x50, 0xbc,
- 0xe4, 0x69, 0xfe, 0x95, 0xb6, 0x28, 0x7c, 0x18, 0x49, 0xb2, 0x98, 0x1c,
- 0x73, 0x3b, 0xa8, 0x17, 0xf8, 0xd0, 0x8f, 0xff, 0xe4, 0x6b, 0x17, 0xff,
- 0x82, 0x1d, 0xe0, 0x13, 0x35, 0xd3, 0xbf, 0x4a, 0x8a, 0x2c, 0xbf, 0xc1,
- 0x33, 0x5d, 0x3b, 0xf4, 0xa8, 0xba, 0x8a, 0x98, 0x5e, 0xb4, 0x42, 0x3d,
- 0x2c, 0x6d, 0xea, 0x30, 0x46, 0x9f, 0xfe, 0x3d, 0x26, 0x73, 0xf8, 0x8f,
- 0x59, 0x79, 0x53, 0x80, 0xad, 0x0e, 0x8a, 0x38, 0x3e, 0x1c, 0x79, 0x76,
- 0xfd, 0xae, 0x9d, 0xfa, 0x54, 0x44, 0x25, 0xa3, 0x58, 0xbd, 0xf6, 0x25,
- 0x8b, 0xb0, 0x6b, 0x16, 0xe9, 0x62, 0xba, 0x3c, 0x6f, 0x8e, 0x10, 0xbd,
- 0xf6, 0x6f, 0x6d, 0x2c, 0x5f, 0x36, 0xb3, 0xb5, 0x8a, 0xc4, 0xc1, 0x8d,
- 0x37, 0xed, 0x67, 0x70, 0xbf, 0x64, 0x92, 0xff, 0xe8, 0xf0, 0xc0, 0x9c,
- 0x18, 0x9f, 0x50, 0x58, 0xbe, 0x29, 0x07, 0x16, 0x2f, 0xed, 0x0b, 0xfb,
- 0xf0, 0x6b, 0x17, 0xb3, 0x06, 0xb1, 0x7f, 0xff, 0xfb, 0xcc, 0x42, 0x86,
- 0x70, 0xb2, 0x30, 0xe1, 0xb7, 0x82, 0x01, 0xe6, 0x0b, 0x17, 0x78, 0x24,
- 0x48, 0xeb, 0xd1, 0x11, 0x18, 0x86, 0x39, 0x41, 0x13, 0xd3, 0x82, 0x96,
- 0x46, 0x6b, 0x7f, 0xf0, 0x40, 0xbc, 0x97, 0x83, 0x39, 0x64, 0x6b, 0x16,
- 0xd9, 0x58, 0xbe, 0x9f, 0xc9, 0xd6, 0x2f, 0xba, 0x77, 0xe9, 0x51, 0x1b,
- 0x15, 0xd1, 0xe9, 0xe8, 0x8a, 0xc1, 0x06, 0x88, 0xbc, 0x68, 0xbf, 0xc1,
- 0x33, 0x5d, 0x3b, 0xf4, 0xa8, 0xa6, 0xcb, 0x9e, 0x0b, 0x17, 0xdd, 0x3b,
- 0xf4, 0xa8, 0xa8, 0x0a, 0x19, 0xe4, 0x68, 0x5e, 0xc6, 0x2c, 0x52, 0xc5,
- 0xb3, 0xb2, 0xfe, 0x21, 0x3b, 0xef, 0xfe, 0x46, 0xb1, 0x60, 0x98, 0x88,
- 0xbf, 0xa0, 0x86, 0x4f, 0x7f, 0x82, 0x66, 0xba, 0x77, 0xe9, 0x51, 0x53,
- 0x17, 0x01, 0x96, 0x2f, 0xc2, 0xed, 0xc5, 0xa5, 0x8b, 0xc2, 0x6d, 0x2c,
- 0x5f, 0x74, 0xef, 0xd2, 0xa2, 0xb0, 0x2f, 0xbd, 0x3d, 0xc1, 0x62, 0xb4,
- 0x7a, 0xa7, 0x31, 0xbf, 0x31, 0x83, 0x16, 0x96, 0x2d, 0x1a, 0xc5, 0xc1,
- 0xc1, 0x62, 0xf3, 0x97, 0x4b, 0x15, 0x27, 0x92, 0x01, 0x3f, 0x0c, 0xdd,
- 0xc2, 0x58, 0xb8, 0x66, 0xac, 0x5e, 0x90, 0x32, 0xc5, 0xc7, 0xe2, 0xc5,
- 0xf9, 0xe1, 0xe6, 0x8d, 0x62, 0xfd, 0xce, 0x16, 0x01, 0x62, 0x98, 0xf4,
- 0x5c, 0xa6, 0xe6, 0xd9, 0x58, 0xb6, 0x96, 0x2f, 0x36, 0xcb, 0xc9, 0xac,
- 0x10, 0xd5, 0xfe, 0x09, 0x9a, 0xe9, 0xdf, 0xa5, 0x44, 0x7e, 0x5c, 0x2e,
- 0x2c, 0x5e, 0x29, 0x1a, 0xc5, 0xf4, 0xc1, 0xfc, 0xb1, 0x52, 0x8c, 0xd8,
- 0x19, 0x8d, 0x11, 0x86, 0x08, 0x72, 0xfb, 0x30, 0xa0, 0xb1, 0x69, 0x58,
- 0xb4, 0x6b, 0x17, 0xe6, 0xe7, 0x84, 0xeb, 0x15, 0x26, 0xec, 0x62, 0x75,
- 0x03, 0xec, 0xc4, 0xcb, 0xd1, 0x0b, 0x4b, 0x17, 0x0c, 0x96, 0x2a, 0x4d,
- 0xb7, 0xc7, 0xef, 0xee, 0xe0, 0xf0, 0x62, 0x58, 0xbd, 0x25, 0x12, 0xc5,
- 0xf4, 0x50, 0x9e, 0xd6, 0x2f, 0xa7, 0x8d, 0x12, 0xc5, 0x62, 0x24, 0xcd,
- 0x2e, 0x61, 0xdd, 0x12, 0xde, 0x35, 0xfc, 0xb1, 0x73, 0xf9, 0x62, 0xe3,
- 0xee, 0xac, 0x5d, 0xef, 0x2c, 0x58, 0x26, 0xc2, 0x5d, 0xc6, 0x91, 0x71,
- 0x95, 0x63, 0x97, 0x44, 0x5d, 0xb9, 0xb1, 0x76, 0xe0, 0xbe, 0x86, 0x4e,
- 0x39, 0xf6, 0x97, 0x8c, 0x64, 0x08, 0xe5, 0x08, 0xde, 0x2b, 0xfa, 0x16,
- 0x62, 0x3c, 0xd9, 0x1e, 0x0c, 0x5f, 0x74, 0x6e, 0xff, 0xf0, 0x43, 0xbc,
- 0x02, 0x66, 0xba, 0x77, 0xe9, 0x51, 0x37, 0x97, 0xff, 0x1d, 0xe0, 0x13,
- 0x35, 0xd3, 0xbf, 0x4a, 0x89, 0xf8, 0xbd, 0xb1, 0x05, 0x36, 0x25, 0x8b,
- 0xff, 0xfe, 0xf8, 0xbc, 0x4e, 0x6f, 0x7e, 0xd4, 0xe7, 0x6e, 0xdd, 0xba,
- 0xc5, 0xb6, 0x2d, 0x89, 0x12, 0xb8, 0x59, 0x7e, 0x3c, 0x9e, 0x43, 0x58,
- 0xbe, 0xcc, 0xd7, 0x16, 0x29, 0xcf, 0x2c, 0x05, 0x37, 0xfe, 0x0a, 0x05,
- 0x5e, 0x1f, 0x6d, 0xf9, 0x1a, 0xc5, 0xcf, 0x05, 0x8b, 0x98, 0xeb, 0x14,
- 0x14, 0x4c, 0x5b, 0x62, 0x7d, 0x0a, 0x90, 0xec, 0x34, 0xad, 0x0b, 0xdf,
- 0xfb, 0x62, 0x91, 0xe6, 0xf2, 0x10, 0x72, 0xb1, 0x7d, 0xb1, 0x47, 0xc0,
- 0x2c, 0x5f, 0x9e, 0x3f, 0x08, 0xd5, 0x8b, 0xf7, 0x5a, 0x29, 0x82, 0xc5,
- 0x05, 0xa9, 0xff, 0x68, 0xa9, 0xca, 0xee, 0x0c, 0xeb, 0x17, 0xf6, 0x1a,
- 0xde, 0x29, 0x58, 0xae, 0x8f, 0x1b, 0x64, 0x66, 0xe8, 0x1d, 0x62, 0xfe,
- 0xe3, 0x9f, 0x53, 0xc5, 0x8b, 0xfe, 0xde, 0xdd, 0x6c, 0x59, 0x14, 0xf9,
- 0x62, 0xfd, 0xa9, 0xf8, 0xa5, 0x62, 0xfd, 0xfc, 0xf4, 0x8d, 0x62, 0x82,
- 0x8a, 0x8f, 0x76, 0x28, 0x62, 0x05, 0x5e, 0xc2, 0xc2, 0x60, 0xb5, 0x18,
- 0xc2, 0xe6, 0x42, 0x72, 0x8b, 0xdc, 0xc2, 0x58, 0xbf, 0xb6, 0x3d, 0x80,
- 0xf3, 0x9e, 0x58, 0xbf, 0xc1, 0x6b, 0xb1, 0x36, 0xcf, 0xd8, 0x2e, 0xb1,
- 0x71, 0x74, 0xb1, 0x7d, 0xc8, 0x8f, 0xc5, 0x8b, 0xf1, 0x7b, 0xec, 0x75,
- 0x8b, 0xe8, 0x84, 0xe1, 0xac, 0x54, 0x9e, 0x6b, 0x94, 0x5e, 0x3c, 0xf1,
- 0x62, 0xee, 0xba, 0x58, 0xbf, 0xdd, 0x7d, 0xbd, 0x98, 0x75, 0x8b, 0xb7,
- 0xf4, 0xb8, 0xc0, 0x8a, 0xd8, 0xd3, 0xd8, 0x0b, 0x07, 0x02, 0xd4, 0xe2,
- 0x51, 0xd8, 0x62, 0x27, 0x2d, 0x10, 0x00, 0x77, 0x83, 0x5e, 0x34, 0xbe,
- 0x0a, 0xec, 0xe7, 0x6b, 0x17, 0xf7, 0xe5, 0xb4, 0xda, 0x58, 0xa0, 0xa1,
- 0xec, 0x74, 0x57, 0x7f, 0x6c, 0x4f, 0x1f, 0xdb, 0x71, 0x62, 0xff, 0xb6,
- 0xfb, 0xf8, 0x7c, 0xd6, 0x2c, 0x5f, 0xc1, 0x6c, 0x28, 0x14, 0x0a, 0xf2,
- 0x56, 0x2f, 0xdb, 0x01, 0xa6, 0xe6, 0xe2, 0xc5, 0xfd, 0xe6, 0x23, 0x30,
- 0x96, 0x2e, 0xe0, 0x96, 0x2f, 0x00, 0x3f, 0x2c, 0x61, 0x71, 0x76, 0xfe,
- 0x97, 0x18, 0x09, 0x6f, 0xac, 0x5c, 0x00, 0x2c, 0x56, 0xc4, 0x9e, 0x88,
- 0x54, 0x9f, 0x63, 0x37, 0xd8, 0x67, 0x61, 0x6a, 0x83, 0x86, 0x6e, 0x8b,
- 0xe2, 0xd1, 0x14, 0x06, 0x25, 0x7b, 0x63, 0x39, 0xd6, 0x2f, 0x38, 0xd9,
- 0x62, 0xff, 0xe2, 0x7f, 0x70, 0xa7, 0x5a, 0x71, 0xac, 0x54, 0x0f, 0x7f,
- 0x07, 0x2f, 0xef, 0xb7, 0x8a, 0x62, 0x58, 0xb9, 0xf1, 0x62, 0xba, 0x3c,
- 0x4d, 0x17, 0x5f, 0x38, 0xf0, 0xeb, 0x17, 0xba, 0x92, 0x58, 0xbf, 0xf6,
- 0xf9, 0xfb, 0x4c, 0x51, 0x4f, 0x4b, 0x14, 0x14, 0x4e, 0x30, 0x2b, 0x08,
- 0x2d, 0x81, 0x97, 0x61, 0x11, 0xe1, 0x13, 0x0e, 0xdf, 0x6c, 0x71, 0x9f,
- 0x8b, 0x17, 0xfb, 0x5f, 0x7e, 0x30, 0xf1, 0x62, 0xfa, 0x49, 0xbb, 0x58,
- 0xb6, 0x61, 0xea, 0xc4, 0x67, 0x7f, 0x13, 0x1b, 0xf7, 0x82, 0xc5, 0xff,
- 0xf3, 0xfa, 0x4b, 0xa6, 0x38, 0xc4, 0xfa, 0x82, 0xc5, 0x1c, 0xff, 0x88,
- 0xba, 0xfc, 0x67, 0xbd, 0x27, 0x58, 0xad, 0x80, 0xf2, 0xe3, 0x21, 0xbf,
- 0xe7, 0xfb, 0x6f, 0x08, 0x61, 0x86, 0x24, 0x5f, 0xef, 0xbf, 0xbc, 0xee,
- 0x62, 0xc5, 0xd2, 0x35, 0x8b, 0xf6, 0x74, 0xfc, 0x65, 0x8a, 0xd8, 0xd5,
- 0x25, 0xec, 0x37, 0xfd, 0x85, 0x0f, 0x00, 0xb6, 0x50, 0x16, 0xa8, 0x3d,
- 0x9a, 0x7c, 0x5e, 0xff, 0xff, 0x7d, 0xb9, 0x30, 0xcf, 0xb6, 0xbe, 0xf8,
- 0x2c, 0xfa, 0xc5, 0xff, 0xf6, 0xa5, 0xbd, 0xfc, 0x1b, 0x73, 0x08, 0x0b,
- 0x16, 0x0a, 0xba, 0x2b, 0x78, 0xbf, 0x77, 0x25, 0x62, 0x82, 0x87, 0x87,
- 0x02, 0xcb, 0xfb, 0x72, 0x74, 0xef, 0x05, 0x8b, 0xf7, 0xd9, 0xc0, 0x16,
- 0xab, 0x17, 0xa7, 0xb8, 0x2c, 0x56, 0xc4, 0x8a, 0x30, 0xb0, 0x9b, 0xc6,
- 0x1b, 0xa5, 0xf7, 0xf8, 0x28, 0x52, 0x30, 0xc1, 0xc5, 0x8b, 0xff, 0x6c,
- 0x1b, 0x14, 0x45, 0x23, 0xce, 0xfc, 0xb1, 0x7f, 0x45, 0x3b, 0x3b, 0xb1,
- 0x44, 0xb1, 0x7d, 0x83, 0x78, 0x2c, 0x5f, 0xec, 0x0c, 0xf8, 0x59, 0xb8,
- 0xb1, 0x7b, 0x42, 0xdd, 0x58, 0xa0, 0xa2, 0x66, 0xbb, 0x01, 0xce, 0xc6,
- 0x97, 0xb0, 0x8e, 0x02, 0xd9, 0x10, 0x8d, 0xaf, 0xff, 0xdb, 0x11, 0x3f,
- 0xa7, 0x0a, 0x07, 0x9c, 0x21, 0xac, 0x5f, 0x16, 0x30, 0x16, 0x2f, 0xfb,
- 0x62, 0x83, 0x7b, 0xf2, 0x46, 0xac, 0x5e, 0x01, 0xb2, 0xb1, 0x41, 0x43,
- 0xdd, 0xd8, 0x67, 0xf7, 0xe6, 0xd0, 0x01, 0x2b, 0x17, 0x34, 0x6b, 0x14,
- 0x14, 0x4d, 0x04, 0x2a, 0xaf, 0xb1, 0xbf, 0x40, 0xb3, 0xc5, 0x17, 0x9f,
- 0x3e, 0xb1, 0x7f, 0xcf, 0xee, 0xe1, 0xec, 0xd1, 0xab, 0x17, 0xfe, 0x6e,
- 0xf8, 0x58, 0x39, 0xcd, 0x2c, 0x5c, 0xc0, 0x58, 0xad, 0x89, 0x15, 0xa1,
- 0x6a, 0x38, 0x03, 0xc2, 0x3e, 0xbd, 0xb0, 0x05, 0xf6, 0x25, 0x8b, 0xff,
- 0xc1, 0x48, 0x82, 0xbb, 0x0c, 0x80, 0x16, 0xbb, 0x76, 0xff, 0x65, 0x62,
- 0xb6, 0x12, 0x25, 0x80, 0x59, 0x7f, 0xe9, 0x99, 0x99, 0x99, 0xef, 0x8b,
- 0x17, 0xa2, 0x9f, 0x2c, 0x5d, 0x33, 0x27, 0xb5, 0x11, 0xe5, 0xff, 0xef,
- 0xcc, 0x5d, 0xf3, 0x3b, 0xdc, 0x99, 0x25, 0x8b, 0xcd, 0xde, 0x2c, 0x5f,
- 0xb4, 0xd1, 0xb9, 0xd2, 0x2e, 0x30, 0xc4, 0x8a, 0xc3, 0xc3, 0x30, 0xa6,
- 0xc2, 0x48, 0x08, 0x68, 0xaf, 0x7f, 0x3a, 0x58, 0xa9, 0x4c, 0xff, 0xe5,
- 0x80, 0x4f, 0xe4, 0x20, 0x83, 0x24, 0xbf, 0x0b, 0x66, 0x45, 0xda, 0xc5,
- 0xc2, 0x82, 0xc5, 0xff, 0xa7, 0xf8, 0x0c, 0x1f, 0xde, 0x0b, 0x17, 0xce,
- 0x53, 0xba, 0xb1, 0x7f, 0x42, 0x4f, 0x3a, 0xd2, 0xc5, 0x62, 0x35, 0x77,
- 0x0b, 0x74, 0x30, 0xe7, 0xc2, 0x24, 0xbf, 0xff, 0xbc, 0xc7, 0xc2, 0xf7,
- 0x24, 0xde, 0x08, 0x7f, 0x65, 0x8b, 0xfa, 0x1b, 0x78, 0xc2, 0xd2, 0xc5,
- 0xff, 0x4f, 0x1f, 0x4d, 0xee, 0x62, 0xc5, 0x76, 0x7d, 0x20, 0x31, 0xbf,
- 0xfc, 0xec, 0x58, 0x0d, 0xb3, 0xa8, 0xe7, 0xcb, 0x17, 0xfe, 0xdd, 0x6d,
- 0xcf, 0xc5, 0x3b, 0x8e, 0x75, 0x8b, 0xfd, 0xef, 0xc9, 0x46, 0xdb, 0xd6,
- 0x2f, 0xdc, 0xc8, 0x6c, 0xe2, 0xc5, 0xec, 0x3c, 0xed, 0x3e, 0x1e, 0x1b,
- 0x5f, 0xff, 0xe9, 0x68, 0x70, 0x33, 0xe1, 0x0a, 0x0f, 0xe3, 0x1f, 0xb5,
- 0x8a, 0x1a, 0x71, 0x9f, 0x4b, 0x28, 0x55, 0x78, 0xd2, 0xfc, 0x77, 0x3e,
- 0x0d, 0x62, 0xff, 0xbd, 0xd7, 0xd8, 0x8a, 0x7b, 0x58, 0xa9, 0x3e, 0x27,
- 0x28, 0xbf, 0xf4, 0xc7, 0x3c, 0x6d, 0x9c, 0xd4, 0xac, 0x56, 0xd5, 0x6f,
- 0x39, 0x0c, 0x56, 0x8e, 0xbf, 0xf0, 0xa4, 0x22, 0x0b, 0xfe, 0x29, 0xdb,
- 0x14, 0x27, 0x51, 0xac, 0x5f, 0xec, 0x1b, 0x6f, 0xe0, 0x3a, 0x58, 0xbf,
- 0xff, 0xf6, 0x6f, 0x6f, 0x43, 0x01, 0xc2, 0xc0, 0x6a, 0x63, 0x7d, 0x74,
- 0xb1, 0x74, 0xc1, 0xd1, 0x4d, 0xc3, 0x7b, 0xd9, 0x1c, 0xac, 0x5f, 0xff,
- 0x60, 0x33, 0xdc, 0x6d, 0xe5, 0x9e, 0xfb, 0x2c, 0x5d, 0xee, 0x61, 0xf6,
- 0x90, 0xed, 0xff, 0xfc, 0xc7, 0x6d, 0x0e, 0x47, 0x8d, 0x07, 0xe6, 0x09,
- 0x62, 0x8e, 0xa8, 0x0b, 0xf0, 0xe3, 0x28, 0x4d, 0x78, 0xb2, 0xfb, 0x83,
- 0xf0, 0x96, 0x2f, 0xff, 0xfe, 0xdf, 0x3a, 0xc1, 0x93, 0xe8, 0xd7, 0xf0,
- 0xbc, 0xde, 0xe7, 0xd9, 0x62, 0xff, 0x68, 0x44, 0x2f, 0x0b, 0xcb, 0x17,
- 0xbf, 0x24, 0xb1, 0x4c, 0x7a, 0x3e, 0x35, 0xbe, 0xd0, 0x7e, 0xe2, 0xc5,
- 0x49, 0xe3, 0x61, 0x0d, 0xfe, 0x98, 0x8a, 0x4e, 0x28, 0xd6, 0x2f, 0xcf,
- 0xc6, 0x38, 0x96, 0x28, 0xe7, 0xbb, 0xf3, 0x5b, 0x8d, 0x31, 0x62, 0xff,
- 0xfa, 0x48, 0xa6, 0x33, 0x1e, 0x3f, 0xb4, 0x92, 0xc5, 0xe2, 0xc0, 0x2c,
- 0x54, 0x0f, 0xaf, 0x13, 0xea, 0x55, 0x5e, 0x74, 0x90, 0xc4, 0x9f, 0x8c,
- 0x2d, 0xdf, 0x7c, 0x44, 0x28, 0x42, 0xdf, 0x34, 0x6e, 0x75, 0x8b, 0xc4,
- 0xd2, 0xb1, 0x7e, 0xce, 0x7e, 0x78, 0xb1, 0x7e, 0x90, 0xcf, 0xf6, 0x58,
- 0xbf, 0xf6, 0x77, 0xe0, 0xe3, 0xf6, 0xa7, 0x8b, 0x14, 0x34, 0x69, 0x68,
- 0x8c, 0xe3, 0x64, 0x51, 0xc2, 0x9b, 0xff, 0x7e, 0x7b, 0x86, 0x1d, 0xa7,
- 0x71, 0x62, 0xfb, 0x7c, 0x0f, 0x2b, 0x17, 0xe7, 0x8e, 0x5f, 0xa5, 0x8b,
- 0xe9, 0xe4, 0x9d, 0x62, 0xff, 0x4c, 0x64, 0x2c, 0xef, 0xcb, 0x16, 0x0f,
- 0x69, 0xeb, 0xfc, 0x8a, 0xa5, 0x31, 0x2c, 0x42, 0xf9, 0x2b, 0xc2, 0x02,
- 0xfd, 0xcf, 0x61, 0x1a, 0xb1, 0x7f, 0x9f, 0xbe, 0x3b, 0xf7, 0xc5, 0x8a,
- 0x81, 0xef, 0x70, 0xa6, 0xfb, 0x8f, 0x0d, 0xc5, 0x8b, 0xff, 0x43, 0x93,
- 0x09, 0x07, 0x33, 0x7a, 0xc5, 0xe9, 0x1b, 0x2c, 0x5f, 0xed, 0x07, 0xee,
- 0x47, 0x86, 0x2c, 0x5f, 0xe7, 0xd7, 0x58, 0x2d, 0x46, 0xb1, 0x7f, 0xd9,
- 0xac, 0xfb, 0x6b, 0xee, 0xb1, 0x69, 0x8c, 0xfb, 0xba, 0x36, 0xbf, 0xfc,
- 0xdc, 0xc1, 0xea, 0x45, 0xe2, 0x6d, 0xeb, 0x17, 0x39, 0x8b, 0x15, 0xd1,
- 0xf1, 0x98, 0x97, 0x7f, 0xf4, 0xea, 0x1d, 0x7d, 0xa2, 0x27, 0x31, 0x62,
- 0xff, 0xed, 0x3c, 0x63, 0xfc, 0xf3, 0xc2, 0xfa, 0xc5, 0x71, 0x11, 0xde,
- 0x47, 0xbd, 0xe6, 0x89, 0x62, 0xc7, 0x82, 0xa4, 0x1c, 0x1c, 0xd4, 0x29,
- 0xbf, 0x08, 0xce, 0x42, 0xcb, 0xc4, 0x77, 0xc5, 0x80, 0xd9, 0x58, 0xbe,
- 0x93, 0xcf, 0xd6, 0x2f, 0xd2, 0x60, 0xf0, 0xeb, 0x16, 0x68, 0x1e, 0x58,
- 0x64, 0x55, 0x2a, 0xe1, 0xf2, 0x54, 0x13, 0x36, 0xfd, 0xc2, 0xfe, 0x70,
- 0x3f, 0x4f, 0xa5, 0x8b, 0xfa, 0x4e, 0x0c, 0xcd, 0xc5, 0x8b, 0xff, 0xe1,
- 0x11, 0x49, 0xa7, 0xfc, 0xf7, 0xe9, 0xfa, 0xc5, 0xff, 0xfc, 0x5e, 0xe0,
- 0xa7, 0xf2, 0x72, 0xc0, 0x1e, 0x60, 0xb1, 0x78, 0x6f, 0xf5, 0x8b, 0xfe,
- 0x9f, 0xcf, 0x70, 0x84, 0xc6, 0xb1, 0x7d, 0xd7, 0xdb, 0x4b, 0x17, 0xf6,
- 0xe1, 0x64, 0x78, 0x62, 0xc5, 0x4a, 0x61, 0x18, 0xb5, 0xa1, 0xd7, 0x3b,
- 0x11, 0x25, 0xff, 0xef, 0xb1, 0xc7, 0x3b, 0x76, 0x45, 0xf6, 0xd2, 0xc5,
- 0xfd, 0xe9, 0xf9, 0x4c, 0x16, 0x2b, 0x69, 0xfe, 0xb2, 0x85, 0x2c, 0x5f,
- 0xc4, 0xe6, 0xb6, 0xa6, 0x06, 0xbf, 0xe4, 0x77, 0xcf, 0xed, 0x4a, 0xc5,
- 0xfa, 0x75, 0xa7, 0x89, 0x62, 0xe6, 0xed, 0x62, 0xff, 0x00, 0x58, 0x03,
- 0xbc, 0x16, 0x2e, 0xc9, 0x58, 0xa8, 0x1f, 0x17, 0x63, 0x07, 0x34, 0xa8,
- 0xd1, 0x76, 0xf0, 0x8b, 0xbf, 0xff, 0xdf, 0x6e, 0xe4, 0xa7, 0x83, 0xfc,
- 0xf1, 0x8b, 0xb8, 0x2c, 0x5f, 0xff, 0xf7, 0xdc, 0x7f, 0x62, 0x7f, 0x4c,
- 0x4c, 0x6b, 0x16, 0x6f, 0x58, 0xbf, 0xe6, 0xf6, 0x6b, 0x42, 0x8f, 0x7a,
- 0xc5, 0xff, 0x73, 0x3c, 0x3c, 0xc0, 0x71, 0x62, 0xbe, 0x7e, 0xde, 0x3d,
- 0xbf, 0xe6, 0xf6, 0x6b, 0x42, 0x8f, 0x7a, 0xc5, 0xc2, 0x2d, 0xa7, 0xbf,
- 0xf2, 0x2a, 0x94, 0xf3, 0x31, 0x87, 0x91, 0x9e, 0x54, 0x19, 0x3c, 0x63,
- 0x97, 0x5b, 0x88, 0x66, 0x97, 0x74, 0x61, 0xa8, 0xd6, 0x7f, 0x0f, 0x40,
- 0x21, 0x14, 0x37, 0x79, 0x1f, 0xa5, 0xf1, 0xd8, 0x72, 0xb1, 0x7f, 0x37,
- 0xf5, 0xa6, 0x8d, 0x62, 0xa4, 0xf4, 0x7e, 0x45, 0x71, 0x9e, 0x58, 0xbf,
- 0xf9, 0x9b, 0xf1, 0x67, 0xa7, 0xd2, 0x35, 0x8b, 0xf4, 0xf8, 0xd7, 0xe2,
- 0xc5, 0xf0, 0x66, 0x86, 0x6a, 0xc5, 0xa5, 0x62, 0xff, 0xfa, 0x7b, 0x83,
- 0x90, 0x36, 0x81, 0xb4, 0xc6, 0xac, 0x54, 0xa6, 0x25, 0x10, 0xcf, 0xd1,
- 0x0c, 0x29, 0xd9, 0x28, 0xdd, 0x11, 0xbf, 0xd3, 0xdc, 0x5f, 0x92, 0x35,
- 0x62, 0xe2, 0x89, 0x62, 0xf7, 0x3e, 0xcb, 0x14, 0x73, 0x6b, 0xe1, 0x8b,
- 0xe8, 0xce, 0xd0, 0x58, 0xbe, 0x90, 0x06, 0x75, 0x8b, 0xe2, 0x13, 0xc1,
- 0x62, 0xba, 0x3c, 0x6e, 0x12, 0x5f, 0xd2, 0x70, 0x80, 0x04, 0xac, 0x5e,
- 0x0b, 0xcf, 0x96, 0x2f, 0xe7, 0xeb, 0x6c, 0xe7, 0x16, 0x2f, 0xd3, 0x85,
- 0xee, 0x2c, 0x50, 0xcf, 0x5c, 0xe6, 0x15, 0xf4, 0x65, 0x08, 0xc3, 0x75,
- 0xe2, 0xa5, 0x38, 0xac, 0x6a, 0x68, 0x76, 0xdf, 0x9b, 0xfe, 0xce, 0x96,
- 0x2f, 0x61, 0x01, 0x62, 0xa2, 0x3c, 0x5d, 0xd2, 0x9a, 0x95, 0x56, 0x98,
- 0xd7, 0xa8, 0xea, 0xdd, 0xe2, 0xff, 0x0c, 0x39, 0xdc, 0xf8, 0xb8, 0xb1,
- 0x7e, 0xdd, 0x63, 0xe7, 0x96, 0x2f, 0xde, 0xcf, 0x14, 0xac, 0x57, 0x68,
- 0x8b, 0x39, 0xc9, 0x15, 0xde, 0x13, 0xf1, 0x62, 0xe9, 0x31, 0x62, 0xb4,
- 0x6d, 0x78, 0x3b, 0x73, 0xfd, 0x62, 0xe8, 0xa5, 0x62, 0xe9, 0xf2, 0xc5,
- 0x49, 0xaf, 0x34, 0x62, 0xf8, 0x78, 0x50, 0x58, 0xbf, 0x63, 0x43, 0xf2,
- 0xb1, 0x74, 0x5e, 0x63, 0xc9, 0xf9, 0x15, 0xff, 0xf8, 0x7f, 0x9d, 0x30,
- 0x24, 0x39, 0x88, 0xa4, 0xeb, 0x17, 0xf8, 0xd9, 0x2f, 0x71, 0xfe, 0xb1,
- 0x52, 0x8b, 0x86, 0x2e, 0x75, 0x6b, 0xf1, 0x63, 0x94, 0x6b, 0x15, 0x2a,
- 0x90, 0xb1, 0x95, 0x88, 0x5d, 0x18, 0xa3, 0x22, 0xe1, 0x6d, 0xe7, 0xcd,
- 0x2c, 0x5f, 0xf6, 0x72, 0x47, 0xc9, 0x61, 0xac, 0x5f, 0xd3, 0x1e, 0xa7,
- 0x06, 0xb1, 0x7f, 0xec, 0x3f, 0x3f, 0x3d, 0xfa, 0x7e, 0xb1, 0x79, 0xe2,
- 0x95, 0x8b, 0xfb, 0xf3, 0xef, 0x49, 0xd6, 0x2f, 0xff, 0xed, 0x60, 0xf8,
- 0x42, 0xc8, 0x09, 0xc7, 0xcc, 0xd2, 0xc5, 0x0d, 0x11, 0x2c, 0x5d, 0x5a,
- 0x4e, 0x28, 0xe3, 0x9f, 0x38, 0xf1, 0x76, 0xf4, 0x00, 0xe1, 0x4d, 0x7c,
- 0x52, 0x7e, 0x2c, 0x5e, 0x3b, 0xf6, 0xb1, 0xe3, 0x45, 0x77, 0xba, 0x58,
- 0xbe, 0x6d, 0x03, 0x8b, 0x15, 0x87, 0xd5, 0xa2, 0xef, 0x0c, 0xdf, 0xc5,
- 0x3b, 0x40, 0x09, 0x58, 0xbe, 0x70, 0x4c, 0x16, 0x2f, 0xe8, 0x7c, 0x1b,
- 0xc2, 0xbb, 0x12, 0xc5, 0xfc, 0xe5, 0x3f, 0xfc, 0xac, 0x5f, 0xe9, 0xd3,
- 0xcc, 0x26, 0x0b, 0x17, 0x08, 0x96, 0x2e, 0xce, 0x96, 0x2e, 0x98, 0x7c,
- 0xd7, 0xf8, 0x5e, 0xbb, 0x47, 0xa4, 0x47, 0x7a, 0x2c, 0x26, 0x1b, 0xff,
- 0xe2, 0xcd, 0xfd, 0x3e, 0xa3, 0x7f, 0x3f, 0x60, 0x58, 0xbf, 0xd8, 0x36,
- 0xe1, 0x8f, 0xa5, 0x8a, 0x95, 0x64, 0xa3, 0x87, 0x66, 0x17, 0x74, 0x5e,
- 0xd1, 0x8b, 0x39, 0xf7, 0x95, 0x2f, 0xf1, 0x3c, 0x7d, 0xc2, 0x77, 0x56,
- 0x2f, 0xc0, 0x9c, 0xee, 0x0b, 0x17, 0xfb, 0x9f, 0x70, 0xff, 0x30, 0x58,
- 0xa8, 0xd1, 0x2d, 0xd1, 0xc7, 0x65, 0x37, 0x64, 0x4b, 0x17, 0xfe, 0x21,
- 0x60, 0xc9, 0xe1, 0x84, 0xb1, 0x7f, 0xe7, 0xef, 0xf2, 0xc0, 0x7f, 0x09,
- 0x62, 0xff, 0xff, 0x4b, 0x41, 0xf9, 0xc9, 0xc2, 0x98, 0x61, 0xdf, 0xb5,
- 0x8b, 0x61, 0xd1, 0x3b, 0xe3, 0xfa, 0xc4, 0xc6, 0x5c, 0x63, 0x90, 0xd9,
- 0xbf, 0x64, 0x79, 0xdc, 0x16, 0x2f, 0xff, 0xbf, 0x27, 0x6d, 0x36, 0xec,
- 0x87, 0x1e, 0x18, 0xb1, 0x7e, 0x98, 0x1d, 0xbc, 0xb1, 0x7f, 0xec, 0x1c,
- 0x86, 0x72, 0x9e, 0xe0, 0xb1, 0x7f, 0x60, 0xba, 0x0f, 0x3b, 0x58, 0xa1,
- 0xa6, 0x31, 0x11, 0x51, 0xd5, 0x78, 0x51, 0xbd, 0x02, 0xff, 0xcd, 0xa9,
- 0xe0, 0x64, 0x53, 0xa5, 0x8b, 0xfb, 0xf3, 0xef, 0xe0, 0x16, 0x2f, 0xf4,
- 0xc4, 0x2e, 0xca, 0x62, 0x58, 0xbf, 0xe9, 0x81, 0x3f, 0xa0, 0xdb, 0xd6,
- 0x2f, 0x07, 0x20, 0x58, 0xbd, 0xba, 0xd1, 0xac, 0x51, 0xd1, 0x5f, 0xf3,
- 0x6e, 0x1d, 0x78, 0x7a, 0xdb, 0x8b, 0x17, 0xfd, 0x91, 0x14, 0xc7, 0xc9,
- 0xe9, 0x62, 0xe8, 0x62, 0xc5, 0x7c, 0xf4, 0xbc, 0x77, 0x77, 0x31, 0x62,
- 0xfd, 0x31, 0x34, 0xf1, 0x62, 0xff, 0xee, 0x4e, 0xba, 0xf1, 0x64, 0x6e,
- 0x4b, 0x17, 0xfe, 0xf7, 0xf3, 0x7b, 0x90, 0xf0, 0x0b, 0x16, 0xfa, 0xc5,
- 0x4a, 0xb0, 0x58, 0xd3, 0x86, 0x7d, 0x90, 0xdd, 0x63, 0xd7, 0x67, 0x01,
- 0x11, 0x0b, 0xf8, 0xa0, 0x48, 0xa6, 0x20, 0x5d, 0xe3, 0xac, 0x5f, 0xcf,
- 0x9a, 0x00, 0x25, 0x62, 0xfd, 0x9f, 0x67, 0x82, 0xc5, 0xf7, 0x3b, 0x2d,
- 0x2c, 0x5f, 0xed, 0x67, 0xd8, 0xa4, 0xeb, 0x17, 0xff, 0x4e, 0xe7, 0xcb,
- 0x3b, 0xf0, 0x9f, 0x8b, 0x17, 0xf4, 0xbe, 0xbd, 0x9f, 0x58, 0xbf, 0xfe,
- 0xc6, 0x2c, 0x8a, 0x63, 0x78, 0xce, 0xd1, 0xac, 0x5f, 0xfe, 0x3e, 0x0e,
- 0x61, 0x3c, 0x03, 0xbf, 0x6b, 0x15, 0x29, 0xa1, 0x1c, 0xcb, 0xe9, 0x1c,
- 0x2d, 0x0d, 0x46, 0xa5, 0x50, 0xeb, 0x8c, 0x70, 0xb7, 0xc4, 0xe2, 0x8d,
- 0x9a, 0xff, 0xbc, 0xfc, 0xcf, 0xfd, 0x8e, 0xb1, 0x77, 0xf8, 0xb1, 0x7f,
- 0xd9, 0xcc, 0x61, 0xbb, 0x46, 0xb1, 0x7f, 0xe2, 0x70, 0x61, 0x7b, 0x8f,
- 0x05, 0x8a, 0x94, 0x63, 0x1a, 0x73, 0xa1, 0x8f, 0x1c, 0x5f, 0x8a, 0x63,
- 0x98, 0xd6, 0x28, 0x67, 0xcd, 0x11, 0xed, 0xfc, 0x39, 0x7d, 0x00, 0x4b,
- 0x17, 0x67, 0xd6, 0x2a, 0x33, 0xc5, 0xde, 0x5d, 0x7e, 0xd3, 0xb6, 0xb1,
- 0x62, 0xfe, 0xc1, 0x81, 0x8b, 0xcb, 0x17, 0xff, 0x1d, 0x80, 0xfe, 0x2c,
- 0x8f, 0x52, 0xb1, 0x4b, 0x16, 0xc6, 0x3d, 0x0f, 0x22, 0x5e, 0xff, 0x99,
- 0x62, 0xfe, 0xdc, 0xcd, 0xe5, 0x90, 0x58, 0xb9, 0xa2, 0x58, 0xa6, 0x3c,
- 0xaf, 0x19, 0x5e, 0xff, 0xe5, 0x62, 0xfe, 0x35, 0xe1, 0xc6, 0x1a, 0xc5,
- 0x61, 0xe6, 0x30, 0xed, 0x4a, 0xa4, 0xbc, 0x68, 0x62, 0x5d, 0x13, 0xfd,
- 0xf5, 0xc9, 0xb8, 0xcf, 0xe6, 0xdb, 0x85, 0x05, 0x8b, 0xfb, 0xed, 0xad,
- 0x67, 0x96, 0x2a, 0x33, 0xc6, 0xe8, 0x62, 0xf9, 0xcf, 0x3b, 0x8b, 0x17,
- 0x87, 0x30, 0x58, 0xb9, 0xb9, 0xf3, 0xc2, 0x11, 0x2d, 0xff, 0xe8, 0xa0,
- 0xdb, 0xe7, 0x58, 0xd0, 0x16, 0x96, 0x2b, 0x47, 0xf4, 0xe5, 0xb7, 0x3c,
- 0x16, 0x2f, 0xc5, 0xed, 0x99, 0x3a, 0xc5, 0x39, 0xe1, 0x08, 0x5e, 0xfb,
- 0x71, 0x8c, 0xe9, 0x62, 0xd0, 0x58, 0xbf, 0xf4, 0xfc, 0x4e, 0x1e, 0x6f,
- 0x7d, 0x2c, 0x53, 0x1e, 0x9f, 0x04, 0xaa, 0x51, 0x39, 0xe7, 0xbb, 0xe3,
- 0x24, 0xa5, 0x62, 0xff, 0x1f, 0x8d, 0xb3, 0x9a, 0x95, 0x8b, 0xd8, 0x7d,
- 0x2c, 0x5e, 0x63, 0xb2, 0xc5, 0x4a, 0x24, 0x70, 0x88, 0x8d, 0xbc, 0x3b,
- 0x5b, 0x0d, 0xdb, 0x90, 0xcc, 0x78, 0x51, 0xc6, 0x4b, 0x09, 0x78, 0x83,
- 0x9d, 0x19, 0xc8, 0xd0, 0x7a, 0x8d, 0x6f, 0xb8, 0x4f, 0x35, 0x28, 0x17,
- 0x72, 0x1f, 0xb1, 0x46, 0x67, 0xa9, 0x62, 0x67, 0x96, 0x1f, 0xf9, 0xd0,
- 0x97, 0x8c, 0x10, 0x11, 0xa6, 0x14, 0xe2, 0x8f, 0x25, 0x5c, 0xfa, 0x5e,
- 0x38, 0xa1, 0x6b, 0xbe, 0x1c, 0x1b, 0x2c, 0x61, 0xc2, 0xf7, 0x76, 0x16,
- 0x76, 0x65, 0x8b, 0xb6, 0x81, 0x62, 0xb6, 0x9a, 0xbe, 0x08, 0xdc, 0x6f,
- 0x96, 0x2f, 0xff, 0xfb, 0x61, 0x6c, 0x73, 0x81, 0x6f, 0x5b, 0x18, 0x59,
- 0xbf, 0x70, 0x2d, 0x45, 0xb7, 0x6f, 0xf6, 0x56, 0x2f, 0xe0, 0x72, 0x22,
- 0x91, 0xac, 0x5f, 0xf6, 0xfc, 0x1f, 0x7e, 0x2c, 0x02, 0xc5, 0xa1, 0x27,
- 0xd6, 0xc5, 0xf7, 0xa2, 0x0c, 0xeb, 0x17, 0xfd, 0x9e, 0xe6, 0x7b, 0xf8,
- 0x05, 0x8b, 0xfd, 0xb6, 0x76, 0x9d, 0x8b, 0xcb, 0x17, 0xf9, 0x8d, 0x72,
- 0xf6, 0x12, 0xc5, 0xfe, 0x73, 0x5b, 0x9c, 0x76, 0x58, 0xac, 0x4c, 0x6d,
- 0xc9, 0x88, 0x83, 0x87, 0x3e, 0x37, 0xde, 0x65, 0x73, 0x92, 0xc5, 0x68,
- 0xfb, 0x4e, 0xaf, 0x7d, 0x3e, 0xc3, 0xac, 0x5f, 0xbd, 0x24, 0xc0, 0x58,
- 0xbb, 0xbe, 0xd6, 0x2e, 0xdb, 0xc5, 0x8b, 0xf6, 0x85, 0xbc, 0x06, 0x2c,
- 0x5c, 0x5c, 0x58, 0xbf, 0xb0, 0xc7, 0x01, 0xf1, 0x62, 0xfe, 0x2c, 0xf0,
- 0x9c, 0xc5, 0x8a, 0xda, 0x98, 0xee, 0x11, 0x76, 0x4e, 0x71, 0xaf, 0x8d,
- 0x00, 0xb4, 0x85, 0xf7, 0x97, 0x5f, 0xbd, 0xc6, 0xec, 0xc5, 0x8b, 0xff,
- 0x49, 0xdb, 0xbe, 0x0a, 0x21, 0x1a, 0xb1, 0x7e, 0x2f, 0x7f, 0x20, 0xb1,
- 0x77, 0x31, 0x62, 0x98, 0xdf, 0xb9, 0x45, 0xfe, 0x29, 0x33, 0x67, 0x35,
- 0x2b, 0x17, 0xe7, 0xc0, 0x07, 0xe5, 0x8b, 0xff, 0x09, 0xbf, 0xfc, 0xd6,
- 0x98, 0xeb, 0x17, 0x87, 0x3b, 0xab, 0x17, 0xdf, 0x67, 0xdc, 0x58, 0xa2,
- 0x3c, 0x5f, 0x10, 0x56, 0xd4, 0xe9, 0x61, 0x08, 0x21, 0x8f, 0x9a, 0x6c,
- 0x72, 0x97, 0x84, 0x25, 0x69, 0x51, 0xa1, 0x91, 0xe8, 0x5f, 0x47, 0x3e,
- 0xe2, 0xc5, 0xe9, 0x07, 0x16, 0x2b, 0x47, 0x82, 0x44, 0x97, 0xcf, 0xa7,
- 0x82, 0xc5, 0x61, 0xe1, 0x91, 0x0d, 0xfb, 0x3d, 0xc9, 0x02, 0xc5, 0x68,
- 0xf2, 0x3e, 0x41, 0x78, 0xc3, 0x0c, 0x58, 0xbe, 0x8c, 0x9a, 0x52, 0x02,
- 0x1a, 0x1b, 0xfb, 0xf3, 0xf2, 0xc3, 0x56, 0x2f, 0x08, 0xbc, 0xb1, 0x7f,
- 0x39, 0x40, 0x73, 0x1a, 0xc5, 0x61, 0xe5, 0xfc, 0x76, 0x86, 0x89, 0xad,
- 0xc7, 0x9b, 0xff, 0xf1, 0x90, 0x6f, 0x42, 0x48, 0x0e, 0x4d, 0xdc, 0x16,
- 0x2f, 0x9f, 0xd2, 0x35, 0x8b, 0xd8, 0x5d, 0x2c, 0x5d, 0xdc, 0x16, 0x2f,
- 0xf1, 0xb3, 0xee, 0x7d, 0xc4, 0xb1, 0x71, 0xe5, 0x62, 0xfc, 0xd1, 0xe7,
- 0x7e, 0x58, 0xbf, 0xcf, 0xf2, 0xcd, 0xef, 0xd2, 0xc5, 0x80, 0xb1, 0x6e,
- 0x96, 0x2f, 0xc1, 0xeb, 0x04, 0x35, 0x8a, 0xc3, 0xcf, 0x61, 0x2e, 0x09,
- 0xd4, 0xa6, 0x80, 0x68, 0xcb, 0x1a, 0x9c, 0x5c, 0x8a, 0xbd, 0x08, 0x4b,
- 0xfe, 0x87, 0x7c, 0x6d, 0x75, 0xfc, 0x58, 0xbe, 0x7e, 0x6f, 0x82, 0xc5,
- 0xd8, 0x35, 0x8a, 0x34, 0xde, 0x6f, 0x25, 0xae, 0xd1, 0xef, 0xa5, 0xbf,
- 0x3c, 0x5f, 0x9c, 0xa0, 0xc7, 0x58, 0xbd, 0x82, 0xd9, 0x58, 0xad, 0xac,
- 0xc2, 0x20, 0xa9, 0x18, 0x58, 0x33, 0x32, 0xa2, 0xc7, 0x19, 0xfe, 0x4a,
- 0xa9, 0x68, 0x7c, 0x7d, 0x0d, 0xe1, 0x9c, 0x02, 0x62, 0x56, 0xe1, 0x10,
- 0xa5, 0x2a, 0x6f, 0x31, 0xd9, 0x27, 0xbd, 0xb1, 0x6c, 0x30, 0xa2, 0xc5,
- 0xff, 0x7d, 0xe2, 0x29, 0xcd, 0x41, 0x62, 0xff, 0xce, 0x41, 0xc5, 0xc6,
- 0x2e, 0xe0, 0xb1, 0x7f, 0xe3, 0x33, 0x84, 0xd3, 0xac, 0x8d, 0x62, 0xb7,
- 0x11, 0x72, 0x23, 0x9d, 0xe8, 0x37, 0xc2, 0x8e, 0x62, 0x58, 0xbf, 0xff,
- 0xff, 0xed, 0xbf, 0xce, 0xe1, 0xf3, 0xed, 0xeb, 0xe2, 0xf7, 0xb0, 0xbf,
- 0x9e, 0x91, 0xed, 0xdb, 0xfd, 0x95, 0x8a, 0x94, 0x64, 0xee, 0x12, 0xdf,
- 0x8a, 0x74, 0xfc, 0x58, 0xbf, 0xe1, 0xe0, 0x82, 0xed, 0xf7, 0x3a, 0xc5,
- 0xfa, 0x4e, 0x59, 0x12, 0xc6, 0x1b, 0xdb, 0xf7, 0x33, 0xed, 0xf5, 0x8b,
- 0xda, 0x9d, 0xeb, 0x17, 0xb7, 0xe0, 0xd6, 0x2f, 0xef, 0xb4, 0x90, 0xa5,
- 0x62, 0xff, 0x4e, 0xe1, 0xb9, 0xc7, 0xdc, 0x58, 0xbe, 0x03, 0x14, 0x4b,
- 0x14, 0x6a, 0x22, 0x7e, 0x59, 0xe3, 0xab, 0xf6, 0x0c, 0x30, 0x71, 0x62,
- 0xfb, 0x8e, 0x50, 0x58, 0xbf, 0xff, 0xff, 0xed, 0x0b, 0x59, 0xd6, 0x6b,
- 0x4f, 0x0c, 0xf4, 0xfb, 0x9c, 0x13, 0x9c, 0x3f, 0xbf, 0xe5, 0x62, 0xb6,
- 0xa7, 0xb5, 0xf1, 0xf7, 0x85, 0x41, 0x18, 0xf0, 0xab, 0x74, 0x8a, 0xfb,
- 0x7b, 0xfd, 0x96, 0x2f, 0xf6, 0x71, 0xdf, 0xb8, 0x32, 0xc5, 0xc1, 0xfd,
- 0x62, 0xf4, 0x42, 0x0d, 0x62, 0xa4, 0xdc, 0xb8, 0xcd, 0x4a, 0x2b, 0xe3,
- 0x24, 0xfb, 0x65, 0xf9, 0xe2, 0xe4, 0xf6, 0xb1, 0x5b, 0x57, 0x01, 0x86,
- 0xc8, 0x03, 0x7e, 0x4a, 0x02, 0xf4, 0x61, 0xfb, 0xcc, 0x2f, 0xe9, 0x87,
- 0xe7, 0x7b, 0x2c, 0x5f, 0x1e, 0x37, 0xdc, 0x58, 0xbd, 0x27, 0x95, 0x8a,
- 0xc3, 0xc3, 0xe8, 0x9e, 0xf7, 0xc3, 0xe2, 0xc5, 0xf3, 0x10, 0x8d, 0x58,
- 0xbf, 0xa1, 0x20, 0xfc, 0x25, 0x62, 0x8d, 0x3d, 0x16, 0x23, 0xbe, 0x11,
- 0x49, 0xd6, 0x2f, 0x3b, 0x9d, 0x62, 0x8e, 0x6f, 0xbe, 0x45, 0x61, 0xac,
- 0x5c, 0xfc, 0x58, 0xb6, 0x8e, 0x6a, 0x44, 0x25, 0x52, 0x7e, 0x2e, 0x95,
- 0x74, 0x3c, 0xb1, 0x7d, 0x14, 0xf9, 0xd6, 0x2f, 0x84, 0x0c, 0x2e, 0x8d,
- 0xd8, 0x86, 0x2d, 0x05, 0x8a, 0x8c, 0xf2, 0xbe, 0x71, 0x7f, 0xf4, 0xfc,
- 0x31, 0xf9, 0xb2, 0x29, 0x3a, 0xc5, 0xff, 0xdd, 0x13, 0xfa, 0x70, 0xc7,
- 0x27, 0x58, 0xbd, 0x24, 0x6a, 0xc5, 0xff, 0xbc, 0xc6, 0x75, 0xf6, 0xde,
- 0xc3, 0x58, 0xbf, 0xda, 0x87, 0xf3, 0x7c, 0x9d, 0x62, 0x96, 0x2e, 0xe6,
- 0x2c, 0x58, 0x50, 0x34, 0x61, 0x70, 0xca, 0x94, 0xc9, 0xfa, 0x43, 0xec,
- 0x75, 0x90, 0xdd, 0x66, 0xfc, 0xf0, 0xe3, 0x6f, 0x58, 0xbe, 0xcd, 0x48,
- 0xd6, 0x2f, 0xa2, 0xfe, 0x44, 0xb1, 0x7b, 0x35, 0x9b, 0x4f, 0x1d, 0xc8,
- 0xaf, 0x1c, 0x5b, 0xd6, 0x2f, 0xec, 0x87, 0x70, 0xcf, 0x2c, 0x5b, 0xd0,
- 0x44, 0x16, 0x19, 0xfc, 0x82, 0xe6, 0xe9, 0x62, 0xfc, 0x7d, 0x8f, 0x77,
- 0x70, 0x6b, 0x14, 0x03, 0xcd, 0x10, 0xc5, 0x2c, 0x5e, 0xf0, 0x8e, 0xb1,
- 0x7d, 0xdc, 0x3e, 0xcb, 0x15, 0x27, 0x84, 0xe3, 0xd7, 0xf7, 0xa7, 0x7b,
- 0x10, 0x16, 0x29, 0x51, 0x07, 0x17, 0xf3, 0xc6, 0x07, 0x21, 0xa2, 0xb0,
- 0x69, 0x6e, 0x62, 0x21, 0x3a, 0x2f, 0xd9, 0x19, 0xad, 0x89, 0x32, 0xb3,
- 0xa7, 0x7a, 0x14, 0x97, 0xfc, 0xd9, 0xee, 0x6b, 0x07, 0x8b, 0x17, 0xf7,
- 0xdc, 0xe5, 0x3d, 0xac, 0x5f, 0x1f, 0x8f, 0x0f, 0x9f, 0x30, 0x67, 0x17,
- 0x9d, 0xf4, 0xb1, 0x7f, 0x03, 0xe5, 0x9e, 0xe2, 0xc5, 0xfc, 0x59, 0xbc,
- 0xb3, 0x8b, 0x16, 0x98, 0x8f, 0xe3, 0x43, 0x9e, 0x2e, 0xa9, 0x4e, 0x23,
- 0x21, 0x43, 0xc8, 0x59, 0x5b, 0x8b, 0x17, 0xef, 0xce, 0xe0, 0xa0, 0xb1,
- 0x52, 0x6f, 0x9c, 0x4a, 0xf9, 0xfd, 0x86, 0x2c, 0x54, 0x19, 0x2a, 0xe3,
- 0x72, 0xc2, 0x23, 0x5c, 0x3a, 0x86, 0x8e, 0xa1, 0x4a, 0x72, 0x3f, 0xc6,
- 0xda, 0x04, 0xa2, 0x87, 0x9f, 0x21, 0x05, 0xe9, 0x5a, 0xbb, 0xdd, 0xf6,
- 0x47, 0xef, 0xe8, 0x16, 0x77, 0xec, 0x58, 0xbd, 0x0f, 0x46, 0xb1, 0x7f,
- 0xf8, 0xb3, 0xf8, 0xfd, 0x7e, 0x48, 0x43, 0x58, 0xbf, 0xfc, 0x09, 0xef,
- 0x23, 0x1b, 0xbf, 0x4e, 0x35, 0x8b, 0x07, 0xd2, 0x25, 0x40, 0x93, 0x52,
- 0x98, 0x68, 0xcb, 0xb5, 0x0b, 0x4b, 0xf8, 0xbd, 0x0c, 0xd6, 0x2c, 0x5f,
- 0x9d, 0xe3, 0xc2, 0x58, 0xbb, 0x65, 0xd6, 0x29, 0xcf, 0xbb, 0xc5, 0xa1,
- 0x93, 0xdf, 0xed, 0x47, 0xc7, 0xeb, 0x58, 0xb1, 0x7f, 0xbf, 0x3f, 0x63,
- 0x70, 0xc5, 0x8b, 0xfb, 0x3a, 0x7f, 0xcf, 0xd6, 0x2a, 0x07, 0xc7, 0xf3,
- 0x5b, 0xff, 0x9d, 0xbd, 0x25, 0xd6, 0x7b, 0xec, 0xb1, 0x6e, 0x2c, 0x5f,
- 0x98, 0x1c, 0xfb, 0x2c, 0x56, 0x1b, 0xa2, 0x12, 0xbb, 0x43, 0x58, 0xb8,
- 0xc3, 0x16, 0x2a, 0x06, 0xc8, 0xc1, 0x8b, 0xd2, 0xdb, 0xd2, 0x02, 0x1a,
- 0x2b, 0xfe, 0x62, 0x60, 0x73, 0x3e, 0xeb, 0x17, 0xf1, 0x61, 0x98, 0x43,
- 0x58, 0xac, 0x4e, 0x9b, 0xe4, 0x4e, 0xfb, 0xc7, 0x3f, 0x18, 0x06, 0x6f,
- 0x7f, 0x49, 0x7b, 0xf9, 0x05, 0x8b, 0x81, 0xc5, 0x8b, 0xf9, 0xbe, 0xc6,
- 0x9b, 0x2b, 0x16, 0x0c, 0x67, 0x8f, 0xe1, 0x8a, 0xd2, 0x27, 0x78, 0xe9,
- 0x7c, 0x42, 0x70, 0xd6, 0x2a, 0x55, 0xbc, 0xb4, 0xa3, 0xf0, 0xe1, 0xe9,
- 0xba, 0x47, 0x77, 0x3c, 0xb1, 0x79, 0x89, 0xd6, 0x2d, 0x1a, 0xc5, 0xb2,
- 0x06, 0xb8, 0x86, 0xef, 0xfa, 0x4f, 0xb7, 0x35, 0x1b, 0x46, 0xb1, 0x5d,
- 0x22, 0xa3, 0x71, 0x18, 0x89, 0x6f, 0x7e, 0x65, 0x62, 0xfe, 0x3e, 0x0e,
- 0x4b, 0xa5, 0x8a, 0x39, 0xe5, 0x06, 0x39, 0x78, 0xc3, 0x0c, 0x48, 0xa4,
- 0x80, 0x86, 0x86, 0xf9, 0x8c, 0x68, 0x92, 0x2b, 0xa3, 0xc2, 0x61, 0xeb,
- 0xed, 0x4e, 0xfc, 0x58, 0xbd, 0x16, 0x7d, 0x62, 0xb0, 0xf0, 0x9c, 0x92,
- 0xfb, 0x3c, 0x27, 0x58, 0xbb, 0x02, 0xeb, 0x15, 0xb0, 0x37, 0x19, 0x73,
- 0x0e, 0x68, 0xe1, 0xfd, 0x93, 0x85, 0x6d, 0x49, 0xc2, 0xd4, 0x7e, 0xc7,
- 0x85, 0x1f, 0xe5, 0xd4, 0x3c, 0x3d, 0x40, 0xfa, 0x50, 0x86, 0xe3, 0x27,
- 0x88, 0x0c, 0x22, 0xbf, 0x13, 0xc3, 0x06, 0xb1, 0x7a, 0x02, 0xc5, 0x8b,
- 0xf6, 0x77, 0xc9, 0x82, 0xc5, 0x68, 0xf1, 0x8c, 0x1d, 0xbf, 0xef, 0xf4,
- 0xd2, 0x03, 0xcc, 0x16, 0x2f, 0xfe, 0xf0, 0x18, 0xa1, 0xc8, 0xf7, 0xf1,
- 0x96, 0x2f, 0xe2, 0xc0, 0x03, 0x00, 0xb1, 0x7f, 0x66, 0xa4, 0xa7, 0x8b,
- 0x17, 0xff, 0xfb, 0x99, 0xbc, 0xa7, 0xbc, 0x3b, 0xf3, 0x34, 0xfd, 0x98,
- 0xb1, 0x58, 0x89, 0x0f, 0x16, 0x5f, 0xbc, 0x1f, 0xdc, 0x0b, 0x15, 0x19,
- 0xe6, 0x76, 0x45, 0x43, 0x4d, 0xd7, 0xb4, 0x82, 0x8c, 0x26, 0xf1, 0x37,
- 0x16, 0x2f, 0x3e, 0x74, 0xb1, 0x79, 0xb2, 0x35, 0x8b, 0xff, 0x18, 0xe3,
- 0xda, 0x18, 0x00, 0xdb, 0xab, 0x17, 0xe1, 0x79, 0xc1, 0xc5, 0x8a, 0xf9,
- 0xf8, 0x01, 0x1e, 0xff, 0xa3, 0x97, 0xe8, 0x1a, 0xce, 0xd6, 0x2b, 0x47,
- 0xbc, 0x44, 0x57, 0xc3, 0x72, 0x02, 0xc5, 0xff, 0x39, 0xdb, 0xfd, 0xf2,
- 0x46, 0xb1, 0x7f, 0xf4, 0x90, 0x0a, 0x7b, 0x8a, 0x48, 0x0b, 0x15, 0xb5,
- 0x5e, 0x5e, 0x47, 0x5e, 0xc6, 0xfa, 0x1c, 0xf8, 0xeb, 0xc3, 0xac, 0x04,
- 0x24, 0x45, 0xc3, 0xab, 0xf6, 0xd3, 0xce, 0x79, 0x62, 0xf0, 0x20, 0x4b,
- 0x15, 0x19, 0xe3, 0xc0, 0xaa, 0xfd, 0x16, 0xc8, 0x36, 0x71, 0x62, 0xf7,
- 0x9f, 0xeb, 0x17, 0xef, 0x14, 0x9f, 0x8b, 0x15, 0x27, 0x8b, 0xd8, 0xed,
- 0xff, 0x9f, 0x5c, 0xfb, 0x74, 0x2d, 0x01, 0x62, 0xff, 0xb2, 0x33, 0xe7,
- 0x7e, 0x93, 0xac, 0x54, 0x9f, 0xe0, 0xd0, 0x6f, 0xda, 0xcd, 0xef, 0xf5,
- 0x8b, 0x32, 0xc5, 0xff, 0x39, 0xbd, 0x7d, 0x86, 0xf0, 0x58, 0xbe, 0x8e,
- 0x37, 0xed, 0x62, 0xdc, 0x63, 0xf2, 0x21, 0x10, 0xce, 0xef, 0xff, 0xf7,
- 0xe4, 0xa4, 0x5d, 0x79, 0xff, 0x87, 0x6f, 0x00, 0x4b, 0x14, 0x6a, 0x66,
- 0x20, 0x84, 0xe7, 0x8d, 0x2f, 0xff, 0x1a, 0xde, 0x2c, 0x86, 0xde, 0x8e,
- 0x09, 0x58, 0xbe, 0xcd, 0x7d, 0x96, 0x2f, 0xff, 0x3c, 0x0b, 0x37, 0xbc,
- 0x53, 0x9e, 0xe2, 0xc5, 0x49, 0xf6, 0xb9, 0x15, 0xb6, 0x56, 0x2f, 0x86,
- 0xec, 0x35, 0x8a, 0xd8, 0x0d, 0xbe, 0x0a, 0xde, 0xdf, 0x84, 0xb1, 0x77,
- 0xd9, 0x62, 0xf7, 0x80, 0x25, 0x8b, 0xfe, 0x63, 0x22, 0xdb, 0x3a, 0xd6,
- 0x2c, 0x54, 0xa2, 0x40, 0xd1, 0xe6, 0x17, 0x88, 0x7a, 0xff, 0x64, 0x61,
- 0xff, 0xf9, 0xb8, 0xb1, 0x7f, 0xf0, 0x3f, 0x99, 0x1b, 0x66, 0xf9, 0xed,
- 0x62, 0xa5, 0x10, 0x06, 0x1c, 0xdf, 0xfd, 0x27, 0xd6, 0xa6, 0x3f, 0x3b,
- 0x9a, 0xb1, 0x74, 0x98, 0xb1, 0x40, 0x3d, 0xe2, 0x46, 0xbf, 0xfe, 0x10,
- 0x5f, 0x9c, 0xeb, 0xed, 0xdf, 0xb5, 0xa9, 0x58, 0xbf, 0xec, 0xe6, 0x34,
- 0x67, 0x7d, 0xd5, 0x8b, 0xbf, 0x8b, 0x15, 0x03, 0xd3, 0xe1, 0xe5, 0x4a,
- 0x33, 0x45, 0x0a, 0xbb, 0xc7, 0x9e, 0x96, 0x2f, 0xf9, 0xe1, 0xc0, 0x3e,
- 0xfc, 0x1a, 0xc5, 0xd9, 0xfc, 0x3d, 0x9f, 0x8f, 0x5f, 0xff, 0x9b, 0x5f,
- 0x17, 0xdd, 0xbd, 0x30, 0x10, 0xf1, 0x62, 0xfd, 0xa6, 0x8d, 0xce, 0xb1,
- 0x71, 0x86, 0x2c, 0x56, 0x1e, 0x19, 0x85, 0x36, 0x12, 0x40, 0x43, 0x45,
- 0x47, 0x46, 0xf7, 0xe1, 0x75, 0x7f, 0xfb, 0x7f, 0xdb, 0x0b, 0xaf, 0xb1,
- 0xe7, 0xa5, 0x8b, 0xf9, 0xc1, 0xdc, 0x33, 0xcb, 0x15, 0x87, 0xf8, 0xc9,
- 0xb7, 0xa0, 0x19, 0xd6, 0x2f, 0x9f, 0xb1, 0x8d, 0x62, 0xf4, 0x83, 0x8b,
- 0x15, 0x05, 0x45, 0xcd, 0x18, 0x57, 0xe1, 0x48, 0xe4, 0x1c, 0x1f, 0x11,
- 0x25, 0xec, 0x3e, 0xe2, 0xc5, 0xff, 0x9f, 0x7e, 0x06, 0x53, 0xf6, 0x8d,
- 0x62, 0xff, 0x67, 0x0b, 0x3d, 0xf6, 0x58, 0xa1, 0xa2, 0x4f, 0x44, 0x04,
- 0x83, 0x7f, 0x37, 0xdc, 0x98, 0xeb, 0x14, 0x36, 0x4b, 0xd6, 0x46, 0xa4,
- 0xc6, 0xf1, 0x42, 0xef, 0x4a, 0xe7, 0x85, 0xaf, 0xe1, 0x7a, 0x08, 0x40,
- 0x94, 0x3b, 0xbd, 0x2a, 0xbb, 0x7c, 0x3d, 0x77, 0x4b, 0xe9, 0x62, 0xfe,
- 0x9e, 0x37, 0x8a, 0x56, 0x2a, 0x4d, 0xc7, 0xc3, 0x2f, 0xe8, 0x31, 0x7b,
- 0x0e, 0xb1, 0x7d, 0x9f, 0x63, 0x16, 0x2f, 0xa0, 0x0c, 0x02, 0xc5, 0xf3,
- 0xe0, 0x78, 0xb1, 0x7f, 0x7b, 0x22, 0x29, 0x3a, 0xe2, 0x02, 0x2f, 0x88,
- 0x7f, 0x95, 0x44, 0x04, 0x04, 0x37, 0x77, 0x14, 0xac, 0x54, 0xa6, 0x4f,
- 0x19, 0x6f, 0x64, 0x7f, 0x23, 0x75, 0xdd, 0xd4, 0x1b, 0xfc, 0x66, 0x6d,
- 0xe1, 0x4e, 0x96, 0x2f, 0xfd, 0xdc, 0x09, 0xa3, 0xf3, 0xc3, 0x8b, 0x17,
- 0xfd, 0xc1, 0xe1, 0x49, 0x0a, 0x56, 0x2c, 0xc6, 0x9f, 0xc7, 0x68, 0x37,
- 0xff, 0xf7, 0xe7, 0xfd, 0x37, 0x30, 0x65, 0x91, 0x45, 0x31, 0xac, 0x5f,
- 0x8e, 0x0d, 0x67, 0x6b, 0x14, 0x34, 0x44, 0x62, 0xf5, 0xfb, 0x4c, 0x20,
- 0xbc, 0xac, 0x5f, 0xed, 0x67, 0x7c, 0x03, 0xf9, 0x62, 0xff, 0x31, 0x7a,
- 0x41, 0xee, 0x2c, 0x5d, 0x3d, 0xac, 0x5a, 0x28, 0x1e, 0x59, 0x86, 0x75,
- 0x28, 0xd6, 0x34, 0xb3, 0x90, 0x80, 0xb0, 0xa3, 0x4c, 0xb7, 0xa8, 0x7c,
- 0x5f, 0xa6, 0x0f, 0xd9, 0x8b, 0x17, 0xfd, 0xb7, 0x5a, 0xcf, 0xf7, 0x0e,
- 0x2c, 0x5f, 0xff, 0xec, 0xe0, 0x9f, 0xbc, 0xc2, 0x37, 0x9c, 0xc2, 0xf7,
- 0x16, 0x2f, 0xfa, 0x0c, 0x5e, 0xfe, 0x43, 0x65, 0x62, 0xba, 0x46, 0xdf,
- 0x67, 0xc7, 0x61, 0xb8, 0xdd, 0xeb, 0x17, 0xfd, 0xed, 0x4e, 0x77, 0xb0,
- 0xf6, 0x16, 0xc0, 0xb1, 0x7f, 0xde, 0x14, 0xe4, 0x7b, 0x0f, 0x61, 0x6c,
- 0x0b, 0x17, 0x39, 0x83, 0x45, 0x9f, 0x63, 0x61, 0xa6, 0x54, 0xae, 0x72,
- 0xe4, 0x2b, 0x9a, 0x3d, 0xed, 0x18, 0xbc, 0x60, 0xa5, 0x0e, 0x5b, 0xef,
- 0x70, 0x50, 0x58, 0xbf, 0xf4, 0xf6, 0x0c, 0x67, 0xdf, 0x3a, 0x58, 0xbf,
- 0x0b, 0x67, 0x34, 0x05, 0x8b, 0xf6, 0x80, 0x77, 0x82, 0xc5, 0x3a, 0x2e,
- 0x48, 0x93, 0x88, 0x01, 0x96, 0x5a, 0x35, 0x8b, 0xf6, 0xdc, 0x89, 0x8e,
- 0xb1, 0x7f, 0x01, 0xe1, 0x1b, 0xc6, 0xb1, 0x7f, 0xdd, 0xfb, 0x20, 0xc4,
- 0x06, 0x58, 0xbf, 0x85, 0x1b, 0x10, 0x8e, 0xb1, 0x52, 0x7d, 0x04, 0x73,
- 0x7e, 0x93, 0xfe, 0x77, 0xac, 0x5f, 0xfe, 0x14, 0xed, 0xdd, 0xf3, 0x73,
- 0xfd, 0xb9, 0x8b, 0x15, 0x1a, 0x6b, 0xf8, 0x56, 0xd0, 0x98, 0xd1, 0x07,
- 0x0a, 0xaf, 0xfd, 0x83, 0xfb, 0x84, 0x9f, 0xcf, 0x6b, 0x17, 0xfd, 0xf7,
- 0xe3, 0x11, 0x4f, 0x6b, 0x14, 0xb0, 0x15, 0x54, 0x75, 0xa8, 0xdc, 0x8e,
- 0x9f, 0xc4, 0x1b, 0xfe, 0x23, 0x74, 0x4d, 0xd0, 0x89, 0x62, 0xfd, 0xe9,
- 0xc2, 0x95, 0x8a, 0x63, 0xe0, 0x23, 0xab, 0xc1, 0x97, 0x96, 0x2f, 0x31,
- 0xdd, 0x62, 0xff, 0x63, 0x1a, 0xc3, 0x73, 0xac, 0x5f, 0xda, 0xef, 0x98,
- 0x46, 0xac, 0x50, 0xcf, 0x8c, 0x33, 0x3a, 0x8d, 0x18, 0x06, 0x8f, 0x1d,
- 0xfe, 0xff, 0xd2, 0xdc, 0x9f, 0x72, 0x7f, 0x2b, 0x17, 0xff, 0x30, 0xba,
- 0x16, 0x37, 0x7e, 0x93, 0xac, 0x5f, 0xf6, 0x46, 0x52, 0x6e, 0x77, 0xe5,
- 0x8a, 0x35, 0x17, 0xc7, 0x3d, 0x0d, 0x1a, 0xfd, 0xd6, 0x37, 0x0e, 0xb1,
- 0x7f, 0xf7, 0x24, 0xbc, 0x1c, 0x5f, 0x6f, 0x71, 0x62, 0xfb, 0x35, 0x3b,
- 0xd6, 0x2b, 0xb3, 0xeb, 0xf2, 0x3d, 0xfd, 0x09, 0x8e, 0x78, 0x25, 0x8b,
- 0xff, 0xf1, 0xe6, 0x19, 0xd0, 0xd8, 0xb3, 0x5d, 0x4e, 0x2c, 0x5b, 0xa8,
- 0x91, 0x08, 0x02, 0xfa, 0xed, 0x1a, 0x45, 0x0a, 0x7a, 0x3a, 0x71, 0xcf,
- 0x1b, 0x35, 0x4a, 0xe3, 0x56, 0x42, 0xc5, 0xa1, 0xc0, 0xf0, 0xf0, 0x14,
- 0x78, 0x17, 0xb7, 0x67, 0xb5, 0x8b, 0xfc, 0x58, 0x0e, 0x06, 0xfe, 0x58,
- 0xbb, 0x0e, 0xb1, 0x7d, 0xa8, 0xe6, 0x0b, 0x15, 0x26, 0xef, 0x05, 0xee,
- 0x6c, 0x58, 0xbf, 0x66, 0xb4, 0xf0, 0x58, 0xbf, 0x6b, 0x4d, 0x17, 0x16,
- 0x2a, 0x07, 0xa5, 0x85, 0x15, 0x04, 0x44, 0xf9, 0xa2, 0xf1, 0xe3, 0x95,
- 0x8b, 0xfd, 0x85, 0x3d, 0xf1, 0xfa, 0x58, 0xa3, 0x4f, 0xd7, 0xa2, 0x33,
- 0x07, 0xaf, 0x72, 0x1d, 0x2c, 0x5f, 0x4e, 0xe6, 0xa5, 0x62, 0xb0, 0xf1,
- 0x38, 0x3f, 0x78, 0x07, 0xf2, 0xc5, 0x41, 0x53, 0x13, 0x10, 0x9d, 0xbd,
- 0xe3, 0x1d, 0x03, 0xb1, 0x10, 0xdf, 0xfb, 0x0f, 0x3d, 0x37, 0xb4, 0x23,
- 0xac, 0x5f, 0xbe, 0xf1, 0x8f, 0x7a, 0xc5, 0xff, 0xb4, 0xd1, 0xea, 0x5a,
- 0x0f, 0xc5, 0x8b, 0xff, 0x3e, 0x61, 0x1a, 0x1f, 0x84, 0x35, 0x8b, 0xd1,
- 0x38, 0xd6, 0x2f, 0x6e, 0xb6, 0xf5, 0x8b, 0x47, 0xa4, 0x5f, 0xfc, 0xfc,
- 0x48, 0x1b, 0xa3, 0xd7, 0x9b, 0xbe, 0x2c, 0x5f, 0xfd, 0xc9, 0x8f, 0x35,
- 0x11, 0x48, 0x38, 0xb1, 0x7f, 0x9b, 0xf9, 0xad, 0x67, 0x6b, 0x17, 0xe8,
- 0x8a, 0x75, 0x05, 0x8b, 0x4c, 0x0f, 0x77, 0x0d, 0x2f, 0xff, 0xcc, 0x66,
- 0x10, 0xba, 0x63, 0x79, 0xf9, 0x2f, 0x2c, 0x54, 0x15, 0x58, 0x74, 0x80,
- 0xf0, 0xeb, 0x02, 0x3f, 0x87, 0x8c, 0x85, 0x1e, 0xe9, 0x35, 0xf6, 0x9e,
- 0x11, 0x2c, 0x5f, 0xfb, 0xbf, 0x61, 0x48, 0x30, 0x80, 0xb1, 0x7d, 0xc9,
- 0x06, 0xc4, 0xb1, 0x58, 0x7c, 0xdc, 0x3e, 0xa3, 0x51, 0x56, 0x64, 0x22,
- 0xaf, 0xbf, 0x80, 0x75, 0x8a, 0x94, 0xda, 0xde, 0x31, 0xfe, 0x15, 0x5f,
- 0xb8, 0xc5, 0xe6, 0x58, 0xbf, 0x79, 0xba, 0x78, 0x2c, 0x5b, 0x51, 0x1e,
- 0x83, 0x93, 0xdf, 0xfa, 0x0c, 0x73, 0x30, 0x87, 0xf9, 0x58, 0xbf, 0xf8,
- 0xa7, 0xd9, 0x9a, 0xd6, 0x4f, 0x4b, 0x17, 0xf8, 0xdc, 0xd0, 0x0e, 0xdc,
- 0x58, 0xae, 0xd1, 0x6f, 0xf3, 0xf2, 0x43, 0xbf, 0xdf, 0x6e, 0xc1, 0xa7,
- 0x1a, 0xc5, 0xa2, 0x58, 0xbe, 0xec, 0x1a, 0x94, 0x8b, 0x8c, 0x31, 0x22,
- 0xa4, 0xdf, 0x18, 0x49, 0x66, 0x48, 0x08, 0x68, 0x6b, 0xe8, 0x95, 0x27,
- 0x2b, 0xff, 0x0c, 0x5e, 0x6f, 0xb1, 0xbf, 0x65, 0x8b, 0xff, 0xfe, 0x6d,
- 0xc9, 0x1e, 0xd7, 0x9e, 0xfa, 0xfc, 0xf7, 0xc7, 0x9d, 0xd5, 0x8b, 0xff,
- 0xfd, 0x9b, 0xb3, 0x13, 0x1e, 0x62, 0xda, 0x5d, 0xc3, 0xe2, 0x02, 0xc5,
- 0xc4, 0x12, 0x51, 0xb3, 0x8e, 0x17, 0xdd, 0x13, 0xc1, 0x62, 0xe6, 0xe9,
- 0x62, 0xff, 0x00, 0x5e, 0x29, 0xf7, 0x16, 0x2d, 0xba, 0xb1, 0x7c, 0xfb,
- 0x43, 0x3a, 0xc5, 0x39, 0xf7, 0xef, 0x34, 0x30, 0x56, 0xfe, 0x1b, 0x6f,
- 0xfe, 0x6e, 0xac, 0x5a, 0x25, 0x8a, 0xc3, 0xc6, 0x63, 0x3a, 0x58, 0xbd,
- 0xb3, 0x9f, 0x58, 0xbb, 0x50, 0xda, 0xae, 0x82, 0x10, 0xca, 0xc2, 0x2e,
- 0xe3, 0x19, 0x62, 0xed, 0x11, 0xfe, 0x10, 0xee, 0xee, 0x02, 0x0f, 0x06,
- 0x54, 0xae, 0x3c, 0xbc, 0xbd, 0x0b, 0xef, 0x79, 0xce, 0xb1, 0x7e, 0x28,
- 0x74, 0x28, 0xd6, 0x2f, 0x4e, 0xa2, 0x58, 0xa7, 0x3c, 0x91, 0x15, 0xdf,
- 0xc1, 0x9c, 0x9f, 0xdc, 0x58, 0xad, 0xae, 0xb5, 0xc3, 0x60, 0x6d, 0x99,
- 0x7d, 0xd1, 0xc3, 0x42, 0x04, 0x63, 0x75, 0xca, 0x50, 0xc7, 0x71, 0x87,
- 0xb4, 0x68, 0xfa, 0x9d, 0x40, 0x3c, 0x64, 0x9f, 0x9e, 0xe0, 0x79, 0x58,
- 0x05, 0x38, 0xef, 0xe8, 0x42, 0x8a, 0x75, 0x63, 0x79, 0x59, 0x8d, 0x81,
- 0x90, 0xde, 0xf3, 0x18, 0xb1, 0x63, 0x56, 0x2f, 0xe8, 0xf6, 0x45, 0xf6,
- 0xd2, 0xc5, 0xfe, 0x28, 0x70, 0x7f, 0x63, 0x16, 0x2f, 0x46, 0xe7, 0x58,
- 0xbb, 0xb2, 0x58, 0xbf, 0x77, 0x0f, 0x87, 0xc5, 0x8b, 0x3e, 0x1e, 0x21,
- 0x0c, 0x5c, 0xc3, 0x58, 0xb4, 0x4b, 0x17, 0x1e, 0x56, 0x2f, 0x79, 0x8c,
- 0x5c, 0x61, 0x05, 0xce, 0x1a, 0xa2, 0x07, 0x3b, 0x35, 0x75, 0xb5, 0x11,
- 0x6c, 0x26, 0x24, 0x2a, 0x82, 0x3e, 0x3e, 0x4b, 0xe8, 0x51, 0x56, 0xd5,
- 0x41, 0x52, 0x26, 0xc6, 0x6e, 0x6a, 0x28, 0xd6, 0xaf, 0x4c, 0x72, 0xb1,
- 0x7f, 0xf4, 0xc3, 0x3e, 0xfd, 0x83, 0x3b, 0xf2, 0xc5, 0xc0, 0xc2, 0x3e,
- 0x3e, 0x0e, 0xdf, 0xe1, 0x7d, 0xb5, 0x9d, 0xf9, 0x62, 0xfe, 0xf6, 0x36,
- 0xcf, 0xe5, 0x62, 0xdc, 0xd9, 0x3e, 0x50, 0xcd, 0x6e, 0xd0, 0x5d, 0x62,
- 0xb4, 0x8d, 0x90, 0x42, 0x44, 0x8b, 0x2f, 0xec, 0x20, 0x66, 0x0d, 0x62,
- 0xe7, 0x31, 0x62, 0xfe, 0x76, 0xef, 0x8c, 0xeb, 0x17, 0xff, 0xbc, 0x53,
- 0x9b, 0xdb, 0xd3, 0x85, 0x05, 0x8a, 0x34, 0xfd, 0x98, 0xb6, 0xff, 0xff,
- 0xd0, 0xeb, 0xed, 0xa8, 0xcf, 0x3d, 0x7e, 0x58, 0x73, 0xf9, 0x82, 0xc5,
- 0xef, 0xc9, 0xab, 0x15, 0xda, 0x23, 0x77, 0xb7, 0xdf, 0xc0, 0xd6, 0x9b,
- 0xb0, 0x2c, 0x5f, 0xfd, 0x09, 0x20, 0x66, 0x80, 0x76, 0xe2, 0xc5, 0xfe,
- 0xce, 0xa6, 0x32, 0x9e, 0x96, 0x2f, 0xdd, 0x14, 0xf7, 0x05, 0x8b, 0x01,
- 0x62, 0xdb, 0x9b, 0x4f, 0xc7, 0x0d, 0x58, 0xaa, 0xfd, 0x9e, 0xe3, 0xf6,
- 0xb1, 0x7f, 0xfb, 0x99, 0xf6, 0xe0, 0xa3, 0xdb, 0x14, 0x92, 0xc5, 0xd2,
- 0x25, 0x8b, 0xf0, 0x88, 0x01, 0xc1, 0x62, 0xff, 0x7e, 0x40, 0x77, 0x86,
- 0xdc, 0x3c, 0x1e, 0x0b, 0xd0, 0xd3, 0x03, 0xe1, 0x48, 0x70, 0x8f, 0xbf,
- 0xd2, 0x08, 0xa0, 0xc2, 0x0b, 0xac, 0x5e, 0x2c, 0xe6, 0xd3, 0xf0, 0x0c,
- 0xde, 0x86, 0xb8, 0x50, 0x6c, 0x23, 0x9e, 0x15, 0xe4, 0x4d, 0xe3, 0x01,
- 0x42, 0xd7, 0x7c, 0x75, 0x77, 0xff, 0x69, 0xbb, 0x0f, 0xd8, 0xd0, 0x7e,
- 0x2c, 0x5f, 0xf0, 0xa3, 0x9d, 0xb3, 0xe9, 0x1a, 0xc5, 0x69, 0x10, 0x5f,
- 0x46, 0xbe, 0xdd, 0xdd, 0x9d, 0xc5, 0x8b, 0xff, 0xf4, 0xfb, 0xf8, 0x3f,
- 0x67, 0xcb, 0x3d, 0xf6, 0x58, 0xb4, 0xed, 0x44, 0x06, 0x8b, 0x2f, 0x9e,
- 0x00, 0x3a, 0xc5, 0xff, 0xfd, 0x21, 0xe9, 0x8f, 0x26, 0xf3, 0xed, 0xe2,
- 0x93, 0xac, 0x51, 0xcf, 0xfc, 0x04, 0x76, 0xd6, 0x91, 0x96, 0x08, 0x54,
- 0xdf, 0xf0, 0x7e, 0x62, 0x14, 0x33, 0x8b, 0x17, 0x9f, 0x51, 0xac, 0x5c,
- 0x61, 0x8b, 0x17, 0xf3, 0x66, 0xf0, 0xe0, 0x13, 0xa3, 0x70, 0x60, 0xf5,
- 0x74, 0x8b, 0xcd, 0x39, 0x5f, 0x13, 0xf6, 0x05, 0x8b, 0xfb, 0x82, 0x01,
- 0xe6, 0x0b, 0x17, 0xf4, 0x19, 0xf7, 0xfd, 0x96, 0x2e, 0x63, 0x76, 0x9e,
- 0xf6, 0x17, 0xdf, 0xee, 0x67, 0x9c, 0xf8, 0x4b, 0x14, 0x35, 0x6b, 0xcd,
- 0x1b, 0x76, 0xa1, 0xd4, 0x72, 0x4f, 0xc2, 0x07, 0xc5, 0xf7, 0xfe, 0xe6,
- 0x16, 0x7f, 0x3a, 0xc2, 0x58, 0xbf, 0xfc, 0xdc, 0xc2, 0xda, 0x1e, 0xa2,
- 0xcc, 0x31, 0x62, 0xfb, 0x4d, 0x27, 0x58, 0xbf, 0xdc, 0xf7, 0xf0, 0xf9,
- 0x05, 0x8b, 0xff, 0xc2, 0x91, 0xe7, 0x80, 0x19, 0x43, 0xf8, 0xb1, 0x74,
- 0xf1, 0x62, 0xff, 0xfe, 0xc0, 0x6c, 0xe0, 0x57, 0x60, 0x9e, 0x73, 0x3d,
- 0xf7, 0x82, 0xc5, 0x41, 0x1f, 0xa3, 0x34, 0x02, 0x59, 0x0b, 0xdf, 0x18,
- 0xe1, 0x9d, 0x62, 0xf3, 0xf7, 0x2b, 0x17, 0xec, 0x37, 0xef, 0x0f, 0x9e,
- 0x10, 0x64, 0xb5, 0x05, 0x4d, 0x03, 0x3d, 0x35, 0x39, 0xa3, 0x1f, 0x27,
- 0xea, 0x95, 0x64, 0x39, 0x2b, 0x42, 0xff, 0x6f, 0x33, 0x08, 0x7f, 0x95,
- 0x8b, 0xf9, 0x87, 0xac, 0x3e, 0x2c, 0x5f, 0xf7, 0xb8, 0x1e, 0xa7, 0xd3,
- 0x05, 0x8b, 0xee, 0x9d, 0xfa, 0x54, 0x43, 0x05, 0xfe, 0x69, 0xd4, 0x05,
- 0x38, 0xb1, 0x5b, 0x51, 0x3d, 0xa3, 0xb2, 0x31, 0xbe, 0x39, 0xde, 0x1b,
- 0x51, 0xf9, 0x90, 0xcb, 0xbf, 0xf1, 0x64, 0x7a, 0x63, 0x0f, 0x3c, 0x58,
- 0xbf, 0xff, 0x98, 0x7b, 0xb3, 0x9a, 0x8e, 0x46, 0x4e, 0x69, 0xb2, 0xb1,
- 0x46, 0xa2, 0x7f, 0x7a, 0x05, 0xf7, 0x4e, 0xfd, 0x2c, 0x5f, 0xff, 0xec,
- 0xeb, 0xf3, 0xdc, 0x36, 0x73, 0xfd, 0x36, 0x13, 0x9a, 0xb1, 0x5a, 0x44,
- 0x51, 0x12, 0x5d, 0xd0, 0x16, 0x2e, 0x7e, 0x61, 0xbb, 0x39, 0x15, 0x62,
- 0x7e, 0xaf, 0x0d, 0xf1, 0x43, 0xae, 0xe8, 0xc4, 0xb1, 0x7f, 0xb9, 0xe7,
- 0xef, 0x65, 0x8d, 0x58, 0xbf, 0x64, 0x52, 0x43, 0x58, 0xa9, 0x3e, 0x1d,
- 0x1c, 0xd4, 0xb6, 0x05, 0x70, 0x34, 0x69, 0xc5, 0x4f, 0xcf, 0xbf, 0x39,
- 0x51, 0x4b, 0x27, 0xf1, 0xc8, 0x9e, 0xaf, 0xc5, 0x20, 0xec, 0x0b, 0x17,
- 0xec, 0x84, 0xe8, 0x0b, 0x17, 0x48, 0x6b, 0x17, 0xe7, 0x8c, 0xa6, 0x09,
- 0x15, 0x11, 0xe0, 0x7c, 0x62, 0xff, 0x3b, 0x7a, 0x75, 0x20, 0x58, 0xbf,
- 0xf7, 0x8a, 0x40, 0x32, 0x6e, 0xfc, 0xb1, 0x6f, 0x7c, 0xfc, 0x43, 0x32,
- 0xbf, 0x7d, 0xc8, 0x38, 0xd6, 0x2a, 0x09, 0xbc, 0x1a, 0x52, 0x76, 0x82,
- 0x84, 0xa1, 0x85, 0x37, 0xfe, 0x6e, 0xa7, 0x8f, 0xad, 0x31, 0x8b, 0x17,
- 0xfd, 0x1c, 0x0f, 0x3f, 0x76, 0x35, 0x62, 0xff, 0xde, 0x62, 0x8f, 0x3b,
- 0xf7, 0xdd, 0x62, 0xff, 0xe6, 0xd1, 0xbd, 0x7d, 0xbe, 0x42, 0x8d, 0x62,
- 0xb1, 0x11, 0x00, 0x40, 0xbf, 0xfb, 0xad, 0x6b, 0x39, 0xce, 0x39, 0x41,
- 0x62, 0xff, 0xfe, 0x1e, 0x89, 0xcc, 0xda, 0xda, 0x92, 0xcf, 0xe7, 0x4b,
- 0x14, 0x49, 0xc4, 0x72, 0x18, 0x62, 0x22, 0x31, 0x1a, 0xf8, 0x59, 0xc6,
- 0x58, 0xbb, 0x82, 0x58, 0xbf, 0xa1, 0xf7, 0x72, 0x95, 0x8b, 0x4f, 0x47,
- 0x89, 0xd8, 0xc5, 0xff, 0xd9, 0xe9, 0xfb, 0x61, 0xa6, 0xcc, 0x16, 0x2f,
- 0xda, 0xe9, 0xdf, 0xa5, 0x44, 0x14, 0x5e, 0xfc, 0x9d, 0x62, 0xff, 0xd3,
- 0x1b, 0xfb, 0x59, 0x0d, 0x9c, 0x58, 0xbd, 0x1b, 0x69, 0x62, 0x86, 0x8f,
- 0x9c, 0x45, 0x63, 0x72, 0x1d, 0xe2, 0x15, 0xfb, 0xf2, 0x71, 0x76, 0xb1,
- 0x7b, 0x93, 0xda, 0xc5, 0xf7, 0xb9, 0x20, 0x48, 0xbc, 0xfa, 0x8d, 0x22,
- 0xf8, 0x44, 0xe6, 0xa4, 0x5f, 0xe6, 0x8f, 0x3d, 0xc9, 0x02, 0x45, 0x24,
- 0x5f, 0xd9, 0xd4, 0xfe, 0x4e, 0x91, 0x71, 0x86, 0x24, 0x5f, 0xc5, 0x25,
- 0x1b, 0x69, 0x22, 0xb1, 0x31, 0x9e, 0x88, 0xce, 0x3d, 0xf2, 0x30, 0x1a,
- 0x10, 0x61, 0x85, 0xc1, 0x8d, 0x5b, 0x49, 0x01, 0x0f, 0xce, 0xf4, 0x1b,
- 0xeb, 0x14, 0xb1, 0x5d, 0xa7, 0xf0, 0xd1, 0xd5, 0x39, 0x28, 0x63, 0xb5,
- 0x05, 0x55, 0xb1, 0x23, 0xfe, 0x51, 0x15, 0xff, 0xf1, 0x9c, 0x2c, 0xef,
- 0xce, 0x51, 0xe7, 0x7e, 0x58, 0xbf, 0xb7, 0xed, 0x78, 0x43, 0x16, 0x2a,
- 0x51, 0x0b, 0x8a, 0x77, 0xff, 0xe2, 0xcf, 0x08, 0x07, 0x78, 0x06, 0x7d,
- 0x96, 0x35, 0x62, 0xe7, 0xd2, 0xc5, 0xfa, 0x3c, 0x1c, 0x9d, 0x62, 0xfc,
- 0xdf, 0xea, 0x4e, 0x61, 0xe0, 0x06, 0x2f, 0x43, 0x46, 0xe7, 0xa1, 0x37,
- 0x52, 0xc8, 0x75, 0xc5, 0x16, 0x8f, 0x23, 0x48, 0x7f, 0x66, 0x79, 0x79,
- 0xe5, 0x0b, 0xf1, 0x43, 0xf6, 0xff, 0xfe, 0x78, 0x78, 0xa7, 0x3b, 0xce,
- 0xa7, 0xdf, 0x6d, 0xeb, 0x17, 0x38, 0xd6, 0x28, 0xd3, 0xf4, 0x3a, 0xed,
- 0xff, 0xff, 0x16, 0x7b, 0xd3, 0xdc, 0x36, 0xfe, 0x4e, 0x2e, 0xf9, 0xf9,
- 0x58, 0xbf, 0xbe, 0xc6, 0x9b, 0x31, 0xac, 0x5f, 0xd8, 0x5c, 0x62, 0xc5,
- 0x8b, 0xf8, 0xf8, 0x3f, 0xe4, 0x6b, 0x17, 0xff, 0x89, 0xcd, 0xe0, 0x3d,
- 0xee, 0xfd, 0x9d, 0x2c, 0x5f, 0xbd, 0xb7, 0xda, 0x95, 0x8a, 0x94, 0x54,
- 0x1a, 0x5f, 0xda, 0x75, 0xef, 0x88, 0xeb, 0x14, 0x6a, 0x7c, 0x3b, 0x84,
- 0x7a, 0x6b, 0xf9, 0x89, 0x43, 0x4f, 0x74, 0xc6, 0xfe, 0x2c, 0xe6, 0xa7,
- 0x8b, 0x17, 0x85, 0x0c, 0x58, 0xa7, 0x3c, 0xa0, 0x16, 0xdf, 0xb0, 0x9f,
- 0xdc, 0x58, 0xbe, 0xfc, 0x94, 0x16, 0x2f, 0xd9, 0xf2, 0x78, 0x96, 0x28,
- 0x67, 0xe3, 0x84, 0xe4, 0x45, 0x50, 0x45, 0xff, 0x21, 0x25, 0x7c, 0xf1,
- 0x67, 0xd6, 0x2f, 0x87, 0xf9, 0x89, 0x62, 0xfe, 0x69, 0xd6, 0x77, 0xe5,
- 0x8b, 0xfe, 0x96, 0x27, 0xf4, 0x4c, 0x62, 0xc5, 0xff, 0xb3, 0x0c, 0xe7,
- 0x72, 0x53, 0xc5, 0x8b, 0x6b, 0x6a, 0x3b, 0x64, 0x8c, 0xe4, 0x9c, 0x2e,
- 0xf1, 0xcd, 0x4a, 0x6c, 0xcd, 0x18, 0xad, 0xfc, 0x77, 0x1f, 0xe4, 0x96,
- 0x2f, 0x6b, 0x3e, 0xb1, 0x7d, 0xe1, 0x7b, 0x8b, 0x17, 0xdd, 0xc3, 0x3c,
- 0xb1, 0x58, 0x79, 0x1a, 0x24, 0xbf, 0xcc, 0xfe, 0xce, 0xa4, 0x0b, 0x17,
- 0xff, 0xce, 0xc0, 0xe6, 0x1a, 0xe7, 0xd4, 0xe1, 0x2c, 0x5e, 0xe8, 0x30,
- 0x2c, 0x5f, 0xff, 0xde, 0xe7, 0xf3, 0x75, 0xc8, 0xd1, 0xe3, 0x6b, 0x52,
- 0xb1, 0x52, 0x7f, 0xce, 0x41, 0x7d, 0xf9, 0xef, 0x8b, 0x17, 0xcd, 0x9d,
- 0xf9, 0x62, 0xb0, 0xf1, 0xfc, 0x49, 0x7f, 0xff, 0xdf, 0x6d, 0x60, 0xdc,
- 0xf8, 0x5e, 0x29, 0x33, 0x3d, 0xc5, 0x8b, 0x4a, 0xc5, 0xf4, 0xef, 0x1c,
- 0xf4, 0x7e, 0xc0, 0x65, 0xbf, 0xf3, 0xc3, 0xef, 0xee, 0x61, 0x41, 0x62,
- 0xbe, 0x7f, 0x3e, 0x3b, 0xa8, 0x2b, 0x4b, 0xec, 0xb7, 0x4c, 0xa7, 0x21,
- 0xf9, 0x99, 0x43, 0x33, 0x8c, 0xfe, 0x8c, 0x42, 0xff, 0xf6, 0x68, 0x1e,
- 0xd6, 0x47, 0xe9, 0xce, 0x2c, 0x5f, 0xff, 0x48, 0x03, 0xcf, 0xf9, 0xbb,
- 0x33, 0x3b, 0xf2, 0xc5, 0xee, 0xb0, 0xeb, 0x17, 0xff, 0xf6, 0x75, 0x22,
- 0xeb, 0xf3, 0xaf, 0xb8, 0xfe, 0xfa, 0x58, 0xbf, 0x86, 0xfe, 0xe0, 0xa0,
- 0xb1, 0x74, 0x36, 0x65, 0x15, 0x58, 0x3c, 0x1a, 0xed, 0xfc, 0xfa, 0x9f,
- 0x36, 0xf5, 0x8a, 0xec, 0xfb, 0x48, 0xfa, 0xff, 0xff, 0xda, 0xd4, 0xf7,
- 0x0e, 0xf8, 0xda, 0xeb, 0xf8, 0x1e, 0x9a, 0x46, 0xb1, 0x7e, 0x23, 0x43,
- 0xce, 0xd6, 0x2f, 0xf9, 0xf5, 0x9d, 0xc2, 0x41, 0x2b, 0x15, 0x28, 0xf7,
- 0xc2, 0x26, 0x71, 0x11, 0x5d, 0xff, 0x77, 0x0f, 0x67, 0x3d, 0x9b, 0x8b,
- 0x17, 0xff, 0xee, 0x8d, 0x7e, 0x66, 0xa0, 0xdf, 0x72, 0xee, 0x0b, 0x17,
- 0xfe, 0xea, 0x7d, 0xcc, 0xf3, 0x76, 0x62, 0xc5, 0x62, 0x26, 0x8d, 0x58,
- 0xa9, 0x47, 0xdb, 0xc3, 0x62, 0xa5, 0x72, 0x18, 0x6f, 0xcc, 0x97, 0xf9,
- 0x4c, 0x45, 0x19, 0xad, 0xfb, 0x84, 0x2d, 0xf0, 0x58, 0xbf, 0x61, 0x7f,
- 0x09, 0x62, 0xf4, 0x61, 0xf4, 0xb1, 0x7c, 0x4d, 0x16, 0xe2, 0xc5, 0x4a,
- 0x26, 0x3e, 0x56, 0xe4, 0xdc, 0x21, 0xb9, 0xc0, 0xb1, 0x50, 0x3d, 0x2f,
- 0x1d, 0xdf, 0xff, 0xfc, 0x2f, 0x73, 0x9e, 0x6c, 0x88, 0xf3, 0xc8, 0x8b,
- 0x0e, 0x68, 0xa5, 0x62, 0xff, 0xa1, 0x9e, 0x3c, 0xe1, 0x0d, 0x62, 0xfd,
- 0xd7, 0xf3, 0xbd, 0xd5, 0x8b, 0xff, 0xf3, 0xbc, 0x1f, 0xfb, 0x72, 0x31,
- 0x78, 0x4e, 0x1a, 0xa2, 0xfb, 0x2f, 0x6f, 0x17, 0x96, 0x2e, 0x91, 0xac,
- 0x54, 0x9b, 0x70, 0x10, 0x5f, 0xcf, 0xd4, 0x94, 0x81, 0x62, 0xff, 0xa6,
- 0x46, 0xdd, 0x31, 0x46, 0xb1, 0x7f, 0xcc, 0x5d, 0xc3, 0x42, 0x9e, 0x2c,
- 0x5d, 0x9b, 0xab, 0x15, 0xc3, 0xd4, 0x30, 0xea, 0xfd, 0x9a, 0xc1, 0xca,
- 0xc5, 0x0d, 0x54, 0xe7, 0x6e, 0xbb, 0x87, 0x11, 0x17, 0x6a, 0x13, 0xbf,
- 0x20, 0x22, 0xdf, 0x42, 0x37, 0x79, 0x1d, 0xfb, 0xf9, 0x14, 0xee, 0x2c,
- 0x5f, 0x87, 0xad, 0x61, 0x8b, 0x17, 0xfe, 0xf6, 0x7e, 0x74, 0x02, 0x73,
- 0x56, 0x2a, 0x34, 0x4a, 0x91, 0x67, 0x0a, 0xaf, 0xe6, 0x2c, 0xf4, 0xc4,
- 0xb1, 0x7f, 0xbf, 0x22, 0xee, 0x0d, 0xb2, 0xb1, 0x7f, 0xf4, 0x39, 0x27,
- 0xce, 0x89, 0xf3, 0xa5, 0x8b, 0xe9, 0x23, 0x46, 0xb1, 0x7f, 0xfc, 0xe5,
- 0x19, 0x67, 0x7c, 0x7c, 0xf6, 0x1d, 0x62, 0xf3, 0x82, 0x56, 0x2f, 0xff,
- 0x0d, 0x8f, 0xdc, 0x38, 0x59, 0xa0, 0xfc, 0xb1, 0x7b, 0x4f, 0x12, 0xc5,
- 0x4a, 0x7a, 0x70, 0x30, 0xe8, 0xb7, 0xb3, 0x8f, 0xa2, 0xb9, 0x1f, 0x13,
- 0xfc, 0x38, 0x24, 0xdb, 0xa1, 0xc5, 0x8b, 0xf4, 0x1b, 0xa7, 0xd2, 0xc5,
- 0xff, 0xe7, 0x2c, 0xf4, 0xb6, 0x98, 0xd3, 0x65, 0x62, 0xb8, 0x7e, 0x41,
- 0x94, 0xdb, 0xa5, 0x8b, 0xff, 0xf9, 0xb4, 0x6f, 0xe4, 0xf1, 0x41, 0x8b,
- 0xf3, 0xa9, 0x58, 0xb1, 0x2c, 0x50, 0x0f, 0xb4, 0x4b, 0x96, 0xf6, 0x22,
- 0x8b, 0x90, 0x80, 0xbc, 0xda, 0xc5, 0x8b, 0xc5, 0x90, 0x58, 0xae, 0x8d,
- 0xc7, 0x87, 0x2f, 0x14, 0x9d, 0x62, 0xa5, 0x14, 0x6c, 0xcb, 0xc2, 0x2b,
- 0xfe, 0x68, 0x7b, 0xf9, 0xa6, 0xe2, 0xc5, 0xff, 0xfa, 0x18, 0x43, 0xfc,
- 0xe1, 0x48, 0x0e, 0xf0, 0x58, 0xa2, 0x44, 0x60, 0x67, 0x37, 0xfb, 0x3f,
- 0xdc, 0x3d, 0x27, 0x58, 0xbf, 0x40, 0xb3, 0x23, 0x58, 0xbb, 0x51, 0xac,
- 0x5f, 0xf4, 0x41, 0x5f, 0x30, 0xc7, 0x84, 0xb1, 0x52, 0x7f, 0xf8, 0x50,
- 0xc3, 0x37, 0xf9, 0xc7, 0x20, 0x93, 0x38, 0xb1, 0x58, 0x98, 0xa7, 0xe1,
- 0x68, 0xe5, 0x97, 0xf6, 0xc8, 0x5b, 0xdb, 0xb7, 0xfb, 0x2b, 0x88, 0x04,
- 0xbf, 0xde, 0x00, 0x65, 0x0f, 0xe2, 0xe2, 0x01, 0x2f, 0x3e, 0xa0, 0xb8,
- 0x80, 0x4a, 0xc3, 0xec, 0x12, 0x15, 0xcf, 0x05, 0xc4, 0x02, 0x5f, 0x39,
- 0x77, 0x05, 0xc4, 0x02, 0x5f, 0xe6, 0xeb, 0xf8, 0x00, 0x4a, 0xe2, 0x01,
- 0x2f, 0x31, 0x0d, 0x71, 0x00, 0x94, 0x34, 0x5f, 0x1c, 0x93, 0xe6, 0x1b,
- 0xd0, 0x6c, 0x6a, 0xe2, 0x01, 0x2f, 0x6a, 0x7c, 0xb8, 0x80, 0x4a, 0x5c,
- 0x40, 0x25, 0xed, 0x96, 0x02, 0xe2, 0x01, 0x2e, 0x93, 0xae, 0x20, 0x12,
- 0x86, 0x7d, 0x58, 0x32, 0xc5, 0xb7, 0xcc, 0x71, 0xca, 0xe2, 0x01, 0x2f,
- 0x79, 0xfa, 0x5c, 0x40, 0x25, 0xff, 0x89, 0xe0, 0x13, 0xed, 0xd3, 0xe9,
- 0x71, 0x00, 0x97, 0xff, 0x3f, 0x85, 0x1b, 0x17, 0xbe, 0xf0, 0x5c, 0x40,
- 0x25, 0xce, 0x35, 0xc4, 0x02, 0x5f, 0xe2, 0x73, 0x39, 0xc9, 0x02, 0xe2,
- 0x01, 0x2f, 0xcc, 0x6b, 0x90, 0x17, 0x10, 0x09, 0x73, 0x71, 0x71, 0x00,
- 0x95, 0xa3, 0xd9, 0xf1, 0xad, 0xff, 0xef, 0xb7, 0xbd, 0x9c, 0xdb, 0xa6,
- 0x93, 0xae, 0x20, 0x12, 0xfd, 0xe2, 0x9e, 0xe0, 0xa8, 0x80, 0x4b, 0x81,
- 0x2b, 0x88, 0x04, 0x08, 0x6d, 0xa9, 0x71, 0x00, 0x97, 0xd2, 0x77, 0x1a,
- 0xe2, 0x01, 0x28, 0x67, 0x90, 0xc3, 0x37, 0xc2, 0x72, 0xe9, 0x71, 0x00,
- 0x97, 0xa7, 0x5d, 0x2e, 0x20, 0x12, 0xff, 0xd9, 0xdf, 0x07, 0x38, 0x40,
- 0xe2, 0xe2, 0x01, 0x2f, 0x8e, 0x1c, 0x81, 0x71, 0x00, 0x97, 0xcf, 0x08,
- 0x4a, 0xe2, 0x01, 0x2b, 0x0f, 0x80, 0x46, 0x37, 0xe7, 0xeb, 0xf3, 0xda,
- 0xe2, 0x01, 0x2b, 0x13, 0x04, 0xfc, 0x2b, 0x04, 0x43, 0x76, 0x80, 0xb8,
- 0x80, 0x4a, 0x82, 0xbc, 0x71, 0x92, 0x64, 0x26, 0xba, 0x22, 0x68, 0x47,
- 0xfd, 0xf8, 0x04, 0x3c, 0x30, 0xf4, 0x65, 0xe2, 0x35, 0xbf, 0x67, 0xb8,
- 0xfd, 0xae, 0x20, 0x12, 0xff, 0x0e, 0x7a, 0x8b, 0x53, 0xe5, 0xc4, 0x02,
- 0x0c, 0xdb, 0x5e, 0xd4, 0x98, 0xb8, 0x80, 0x4a, 0xe8, 0xff, 0xb4, 0xa7,
- 0x7f, 0x84, 0xf0, 0x84, 0x86, 0x75, 0xc4, 0x02, 0x5f, 0x31, 0x43, 0x8b,
- 0x88, 0x04, 0xbf, 0x9e, 0x28, 0x67, 0x70, 0x5c, 0x40, 0x25, 0x62, 0x34,
- 0x7e, 0x46, 0x04, 0x21, 0x17, 0xdf, 0xf7, 0xe7, 0x81, 0x38, 0x2d, 0x01,
- 0x71, 0x00, 0xc5, 0x66, 0x5c, 0x40, 0x25, 0xcf, 0x18, 0xcf, 0xb3, 0xe9,
- 0xd7, 0x68, 0x0b, 0x88, 0x04, 0xbf, 0x3f, 0xb8, 0xdd, 0xae, 0x20, 0x12,
- 0xfe, 0x62, 0x14, 0x33, 0x8b, 0x88, 0x04, 0xa9, 0x44, 0xa9, 0x12, 0xf8,
- 0xda, 0xa5, 0x96, 0x66, 0x38, 0x5c, 0xe4, 0x37, 0xd8, 0xfe, 0x22, 0x0d,
- 0x42, 0x53, 0xe5, 0xae, 0x5e, 0x02, 0xb2, 0x4e, 0xe4, 0xe0, 0xcf, 0xa5,
- 0x10, 0xec, 0xc2, 0xa0, 0x38, 0x61, 0xde, 0xf3, 0x18, 0xb8, 0xc2, 0x4b,
- 0xce, 0xfd, 0x2a, 0x20, 0x10, 0x22, 0x62, 0xdd, 0xc3, 0xae, 0xf4, 0x99,
- 0xc5, 0x8b, 0x79, 0x62, 0xf1, 0x67, 0x5d, 0x1b, 0x06, 0x1e, 0xb8, 0x67,
- 0x58, 0xbf, 0xfe, 0x20, 0x7b, 0xf9, 0xd4, 0x9f, 0x91, 0xc2, 0x35, 0x8b,
- 0xfc, 0x2f, 0x67, 0x3d, 0x9d, 0x2c, 0x56, 0xc3, 0x45, 0x0b, 0x8c, 0x01,
- 0x52, 0xfe, 0xf1, 0x60, 0x36, 0x71, 0x62, 0x86, 0x99, 0xc1, 0xb0, 0xd3,
- 0x39, 0xad, 0xfe, 0x83, 0x78, 0xd3, 0x73, 0x71, 0x62, 0xfa, 0x7d, 0x23,
- 0x58, 0xb4, 0x6b, 0x15, 0x03, 0x6b, 0xbc, 0x8a, 0xfe, 0x8e, 0x75, 0xf7,
- 0xdc, 0x58, 0xbf, 0xee, 0x14, 0x9f, 0x9d, 0x4f, 0x16, 0x2d, 0xc5, 0x8b,
- 0xfd, 0x9c, 0x27, 0xe6, 0x6e, 0x2c, 0x5e, 0x91, 0xfd, 0x62, 0xbe, 0x7a,
- 0x44, 0x6b, 0x58, 0x8b, 0xff, 0x9d, 0x6f, 0x64, 0xa9, 0x4d, 0x17, 0x08,
- 0xda, 0x1e, 0x37, 0xfe, 0x2c, 0xeb, 0xec, 0x00, 0x0a, 0x25, 0x8b, 0xef,
- 0x3b, 0xe9, 0x62, 0xff, 0x87, 0x86, 0x96, 0x7a, 0x4c, 0x58, 0xbf, 0xb3,
- 0x59, 0x08, 0x4a, 0xc5, 0x41, 0x19, 0x5d, 0xa0, 0x80, 0x88, 0x8e, 0xaf,
- 0x0d, 0xfe, 0xb1, 0x7e, 0xc8, 0xb9, 0x31, 0xac, 0x5b, 0xd8, 0x78, 0xfe,
- 0x1d, 0xb8, 0x12, 0x91, 0x63, 0x52, 0x2f, 0x7e, 0x63, 0x58, 0xb8, 0xc3,
- 0x12, 0x29, 0x8f, 0x8b, 0x70, 0x5e, 0x21, 0x33, 0x07, 0xad, 0xc4, 0x80,
- 0x87, 0x81, 0x58, 0x8e, 0xe6, 0x86, 0x4d, 0xff, 0xd8, 0x08, 0x37, 0xa4,
- 0xf2, 0x43, 0x58, 0xa3, 0x9f, 0x4b, 0x93, 0x5f, 0xd8, 0x3f, 0xc9, 0x0d,
- 0x62, 0xfe, 0xf7, 0x30, 0xcf, 0xb2, 0xc5, 0xbc, 0xb1, 0x5e, 0x3c, 0x11,
- 0x17, 0xdf, 0xa6, 0x3e, 0x1e, 0x0b, 0x14, 0xc7, 0x99, 0xe2, 0x2b, 0xff,
- 0xf7, 0x70, 0xe1, 0x77, 0x26, 0xf2, 0x7b, 0x83, 0x1d, 0x62, 0xff, 0x8d,
- 0x6d, 0x06, 0x00, 0x4f, 0x6b, 0x17, 0xd0, 0xf4, 0x98, 0xb1, 0x77, 0xb9,
- 0x87, 0xc3, 0xd9, 0xed, 0x6c, 0x6d, 0xc6, 0x0c, 0xc2, 0x2a, 0x38, 0xda,
- 0x21, 0x0b, 0xa1, 0xc6, 0x6f, 0xd5, 0x31, 0xf5, 0xa3, 0xba, 0x88, 0xdf,
- 0x51, 0xd9, 0xbc, 0x3f, 0x41, 0x1e, 0xd9, 0x10, 0xfa, 0x17, 0x42, 0x21,
- 0x0e, 0x17, 0x77, 0xfd, 0x90, 0x61, 0xbf, 0x5c, 0x82, 0xc5, 0xfe, 0x62,
- 0xe9, 0xb4, 0xc0, 0x58, 0xbd, 0x98, 0x05, 0x8a, 0x39, 0xe7, 0x91, 0x9d,
- 0x74, 0x8a, 0xaf, 0xc2, 0x26, 0xfe, 0xf0, 0xfe, 0x27, 0x25, 0x8b, 0xdd,
- 0x7c, 0x96, 0x2f, 0xfe, 0xf6, 0xce, 0x45, 0x07, 0xd4, 0x63, 0x95, 0x8a,
- 0xed, 0x12, 0xc7, 0x2e, 0x21, 0xeb, 0xf6, 0x0d, 0xc1, 0xc5, 0x8b, 0xff,
- 0xe0, 0x1d, 0xe1, 0xb4, 0x9a, 0x76, 0xb1, 0xf1, 0x62, 0xf4, 0x52, 0x62,
- 0xc5, 0xff, 0xef, 0xb6, 0xf6, 0xeb, 0x53, 0x1b, 0xeb, 0xa5, 0x8b, 0xfa,
- 0x7b, 0x92, 0x7f, 0x2c, 0x5c, 0x40, 0x58, 0xba, 0x78, 0xb1, 0x4c, 0x6b,
- 0xb7, 0x8b, 0xd7, 0xcf, 0xf7, 0x7a, 0xdd, 0x4a, 0x61, 0xfd, 0x0f, 0x87,
- 0x0c, 0xca, 0xd2, 0x78, 0x04, 0x51, 0xe8, 0xd8, 0x6f, 0xff, 0xf7, 0xd8,
- 0x87, 0x87, 0xf4, 0xe6, 0x1c, 0x73, 0x84, 0xb1, 0x7f, 0xb3, 0xbf, 0x79,
- 0xe1, 0xc5, 0x8b, 0xfc, 0x1c, 0x99, 0xa9, 0xc2, 0x58, 0xbd, 0x00, 0xbc,
- 0x16, 0x2e, 0xee, 0x0b, 0x8c, 0x00, 0xbf, 0xfd, 0x86, 0x4f, 0xb2, 0x28,
- 0x37, 0xb8, 0xeb, 0x15, 0x04, 0x63, 0xf6, 0x68, 0x44, 0x5c, 0x26, 0xbf,
- 0xff, 0x4e, 0x7f, 0x84, 0xfe, 0x17, 0x87, 0xf6, 0x35, 0x62, 0xff, 0x9b,
- 0xbe, 0x78, 0xa4, 0xfc, 0x58, 0xbf, 0xff, 0xff, 0xff, 0x85, 0xb8, 0x4f,
- 0x9f, 0x70, 0xcb, 0x37, 0xe1, 0x39, 0xb1, 0x40, 0x5c, 0xe1, 0x8e, 0x3f,
- 0xb1, 0x9c, 0xc7, 0x1a, 0xc5, 0x1a, 0x8f, 0x7e, 0x1d, 0x54, 0xae, 0xf6,
- 0x64, 0x2f, 0xda, 0x3f, 0x08, 0x8d, 0xb4, 0xba, 0xf0, 0xfc, 0x23, 0xdf,
- 0x46, 0x9b, 0x7f, 0xfe, 0x22, 0x17, 0x79, 0xdf, 0x87, 0xa7, 0xef, 0x23,
- 0x58, 0xbf, 0x67, 0xb5, 0x3c, 0x58, 0xa6, 0x44, 0x09, 0x2c, 0xde, 0x04,
- 0xc1, 0x62, 0xfe, 0x27, 0xee, 0x5a, 0x25, 0x8b, 0x46, 0xb1, 0x4b, 0x17,
- 0xa2, 0x84, 0xe8, 0xbf, 0x00, 0x9d, 0xf4, 0x9b, 0x27, 0x58, 0xa8, 0x23,
- 0x83, 0xb2, 0x16, 0x1d, 0xd2, 0x69, 0xcc, 0xaf, 0xfd, 0x0e, 0x6d, 0x2c,
- 0x3c, 0xe8, 0xd5, 0x8b, 0xff, 0xfd, 0x27, 0x0f, 0x3e, 0xe7, 0xc3, 0xb7,
- 0xb0, 0xd6, 0xd2, 0xc5, 0xff, 0xf6, 0x6a, 0x22, 0x90, 0x73, 0xaf, 0xb6,
- 0xa3, 0x58, 0xa8, 0x22, 0xd3, 0x8c, 0x37, 0xed, 0xbb, 0x73, 0xee, 0xb1,
- 0x7f, 0xdf, 0x76, 0xf4, 0x3e, 0x23, 0x56, 0x2f, 0x3f, 0xf8, 0xb1, 0x5c,
- 0x3d, 0x83, 0x0e, 0xef, 0xe8, 0x4e, 0x80, 0x19, 0xd6, 0x2f, 0xa2, 0xfb,
- 0x44, 0xb1, 0x7f, 0xe3, 0x4d, 0x62, 0xeb, 0x6c, 0x7f, 0x35, 0x62, 0xb0,
- 0xfb, 0x18, 0x96, 0xff, 0xed, 0xe5, 0x9c, 0xf6, 0x14, 0x33, 0x8b, 0x17,
- 0xc7, 0x91, 0x79, 0x62, 0xb0, 0xfa, 0x1d, 0x16, 0xfc, 0x42, 0xf0, 0x8d,
- 0x58, 0xbe, 0xf7, 0x9f, 0x4b, 0x17, 0xec, 0x8b, 0xf3, 0x1a, 0xc5, 0x61,
- 0xfb, 0xb9, 0x51, 0x11, 0xdf, 0xf8, 0x9f, 0xdc, 0x6e, 0xca, 0x4c, 0x58,
- 0xbd, 0xe7, 0x25, 0x8b, 0x3e, 0xd5, 0x4c, 0xb8, 0x47, 0xf8, 0x4e, 0x14,
- 0x22, 0x39, 0x09, 0x70, 0xcb, 0x37, 0x4f, 0xeb, 0x6a, 0xb6, 0x7f, 0xca,
- 0xe9, 0xbf, 0xe9, 0xdc, 0x1f, 0xe6, 0x37, 0x25, 0x8b, 0xff, 0xe9, 0x38,
- 0x65, 0xef, 0x89, 0xe1, 0xf1, 0x71, 0x62, 0xff, 0x74, 0x59, 0xbf, 0xef,
- 0x05, 0x8b, 0xc7, 0x03, 0x2c, 0x5f, 0x4f, 0x52, 0x7c, 0x3d, 0x36, 0x36,
- 0xae, 0xd7, 0x34, 0x35, 0x2e, 0x2b, 0xe5, 0xc4, 0x79, 0xbb, 0x0a, 0x5b,
- 0xf8, 0x33, 0x34, 0xd9, 0xf4, 0x8b, 0xfc, 0xfe, 0x98, 0x08, 0x78, 0xb1,
- 0x7d, 0xf9, 0xc8, 0xd6, 0x28, 0x8f, 0x5b, 0x86, 0x77, 0xdc, 0x69, 0x02,
- 0xc5, 0xff, 0x7a, 0x7b, 0xf6, 0x1e, 0x7e, 0xb1, 0x7d, 0x16, 0x61, 0x8b,
- 0x17, 0xd0, 0x6d, 0x71, 0x62, 0xff, 0xe0, 0xcf, 0x9e, 0x9d, 0xed, 0xe8,
- 0x4a, 0xc5, 0xf3, 0x7a, 0x74, 0xb1, 0x7f, 0xcd, 0x9d, 0xfa, 0x28, 0x3e,
- 0x96, 0x2c, 0x06, 0x45, 0x27, 0xd1, 0xc8, 0x8a, 0xf0, 0x1b, 0x16, 0x2f,
- 0xa2, 0xfb, 0xc4, 0xb1, 0x7d, 0xd3, 0xea, 0x35, 0x8b, 0xd1, 0x3f, 0x96,
- 0x2f, 0xd9, 0x14, 0x27, 0xb5, 0x8b, 0xfe, 0xfc, 0xf3, 0xef, 0xc9, 0xdc,
- 0x58, 0xb9, 0xa2, 0x58, 0xbc, 0xd2, 0x4b, 0x17, 0xec, 0xd0, 0xff, 0x8b,
- 0x14, 0x33, 0xc3, 0xe0, 0xdd, 0x7c, 0xff, 0x78, 0xb7, 0x79, 0xc8, 0x0b,
- 0x17, 0x8a, 0x60, 0x91, 0x7f, 0xe2, 0x03, 0x6e, 0xee, 0x8a, 0x13, 0xb8,
- 0xb1, 0x63, 0xac, 0x56, 0xd4, 0x49, 0x60, 0xe3, 0x8e, 0x06, 0x91, 0x5b,
- 0x55, 0xfa, 0xc9, 0x0c, 0x64, 0x43, 0x3a, 0xc2, 0x4e, 0xe1, 0x8e, 0xc6,
- 0x9a, 0x1c, 0xf9, 0x2b, 0x92, 0x90, 0xf7, 0x0a, 0xbd, 0x0b, 0x9d, 0xd8,
- 0x5a, 0x54, 0xb2, 0xee, 0x71, 0x29, 0xa7, 0x71, 0xbe, 0xb8, 0xf3, 0x8f,
- 0x77, 0xee, 0x6b, 0x53, 0xe5, 0x8b, 0xfd, 0x9f, 0x7c, 0x00, 0x7e, 0x58,
- 0xbd, 0xe6, 0x8d, 0x62, 0xbb, 0x3f, 0xbd, 0xc2, 0x93, 0x9a, 0x5f, 0xb8,
- 0x6e, 0x9f, 0xa5, 0x8b, 0xfd, 0x11, 0x60, 0xff, 0x3c, 0x58, 0xbf, 0xfb,
- 0x00, 0x07, 0xef, 0x9c, 0x92, 0xe9, 0x62, 0xd0, 0x58, 0xa2, 0x3d, 0x8e,
- 0x23, 0x54, 0x11, 0xb1, 0xf2, 0xbd, 0xf0, 0x8c, 0xbc, 0x5e, 0xe2, 0xc5,
- 0xff, 0xd9, 0xed, 0x88, 0x29, 0xb1, 0x37, 0x7c, 0x17, 0x16, 0x2f, 0xf7,
- 0x5f, 0x61, 0xc9, 0x79, 0x62, 0xe6, 0x82, 0xc5, 0x76, 0x79, 0x64, 0x69,
- 0x71, 0x01, 0x62, 0xfd, 0xaf, 0xbb, 0x9d, 0x62, 0xf8, 0x44, 0x2e, 0x96,
- 0x29, 0xcf, 0x33, 0x85, 0x17, 0xf7, 0xa2, 0x86, 0x77, 0x05, 0x8a, 0x94,
- 0xf2, 0xd8, 0xdc, 0xe3, 0xaf, 0x0a, 0x0f, 0x11, 0x09, 0x8c, 0x32, 0x1b,
- 0xfe, 0x0f, 0x30, 0x5f, 0xcd, 0xf2, 0xb1, 0x7f, 0xe3, 0x27, 0x5c, 0xc3,
- 0x1f, 0x46, 0xac, 0x5d, 0xd3, 0xac, 0x5e, 0xce, 0x09, 0x62, 0xff, 0xfd,
- 0xfc, 0xe8, 0x84, 0x32, 0x90, 0xf4, 0xd2, 0x4b, 0x15, 0x89, 0x83, 0xfc,
- 0xed, 0xd0, 0x88, 0x63, 0xc3, 0xb7, 0xf8, 0xcc, 0xef, 0xde, 0x93, 0xac,
- 0x5f, 0x8b, 0x00, 0x2e, 0x2c, 0x5f, 0xf7, 0x4d, 0x85, 0x9b, 0xdf, 0x8b,
- 0x15, 0x19, 0xf1, 0x7c, 0xa2, 0x9d, 0x17, 0x7c, 0x84, 0xc5, 0xf0, 0xc7,
- 0x87, 0x58, 0xb8, 0x12, 0x91, 0x71, 0x86, 0x24, 0x53, 0x1b, 0x13, 0x05,
- 0xef, 0xc3, 0x13, 0xea, 0x09, 0x01, 0x0d, 0x0d, 0x62, 0x2c, 0x0d, 0x75,
- 0xbf, 0xfd, 0xee, 0xfa, 0x6f, 0xec, 0xcf, 0xbe, 0x1f, 0x16, 0x2d, 0xb0,
- 0x96, 0x2f, 0xf4, 0xc1, 0xbd, 0x09, 0xf2, 0xc5, 0xc1, 0x7e, 0x2c, 0x05,
- 0xa9, 0xe5, 0xe8, 0x62, 0xff, 0xbe, 0xfe, 0xe7, 0x45, 0x91, 0xac, 0x5e,
- 0x38, 0x8d, 0x58, 0xbd, 0xb0, 0xf6, 0x3d, 0x8d, 0x62, 0xee, 0x99, 0x62,
- 0xff, 0xd3, 0xb8, 0x2d, 0x66, 0xb5, 0x3d, 0xac, 0x5f, 0x13, 0x77, 0x05,
- 0x8b, 0xfe, 0x6e, 0xff, 0x83, 0xd3, 0xf4, 0xb1, 0x52, 0x7b, 0xda, 0x23,
- 0xbe, 0xcd, 0xf8, 0x4b, 0x17, 0xfb, 0x98, 0xde, 0x35, 0xbe, 0xb1, 0x7f,
- 0xdf, 0x9d, 0x4f, 0x4c, 0x5d, 0x2c, 0x5e, 0x35, 0xf9, 0xb0, 0xd3, 0x99,
- 0xe8, 0xbb, 0xb1, 0x8d, 0x42, 0x87, 0xe4, 0x3e, 0x23, 0xdd, 0x34, 0xac,
- 0x54, 0xf4, 0xc7, 0x7e, 0x8e, 0xe2, 0xa0, 0xbb, 0x17, 0xdc, 0x60, 0x7a,
- 0x86, 0xb9, 0xc8, 0xc5, 0x09, 0xd3, 0x25, 0x5d, 0xdf, 0xbe, 0xdc, 0x14,
- 0x6b, 0x17, 0xf1, 0x86, 0xbf, 0x8a, 0x56, 0x2f, 0x1c, 0x5a, 0x58, 0xbd,
- 0xd3, 0x71, 0x62, 0xf8, 0x47, 0xc1, 0xac, 0x57, 0x68, 0x8e, 0x62, 0xff,
- 0x8f, 0x6e, 0x8f, 0x5f, 0xff, 0xda, 0x80, 0xa7, 0x3f, 0xd3, 0x73, 0x07,
- 0x1e, 0x18, 0xb1, 0x7f, 0xd9, 0xba, 0xe4, 0x6e, 0x77, 0xe5, 0x8b, 0xf6,
- 0x87, 0xf6, 0x89, 0x62, 0xbe, 0x7c, 0xe1, 0x9e, 0xdf, 0x0a, 0x48, 0xd5,
- 0x8b, 0xfb, 0xec, 0x3f, 0x88, 0xd5, 0x8b, 0xf1, 0x4c, 0x4d, 0xda, 0xc5,
- 0xb0, 0x67, 0xf9, 0xd1, 0x1b, 0x18, 0x5e, 0xf6, 0x74, 0xb1, 0x47, 0x3d,
- 0x2e, 0x1a, 0x5e, 0x81, 0xc0, 0xb1, 0x7e, 0xf1, 0x66, 0xa5, 0x62, 0xa5,
- 0x50, 0xe9, 0xb0, 0xc5, 0x04, 0x3c, 0x7c, 0x44, 0x60, 0xf5, 0xe2, 0x63,
- 0x56, 0x2f, 0xfc, 0x1f, 0x27, 0x39, 0xad, 0x37, 0x96, 0x2b, 0x0f, 0x77,
- 0x83, 0xb7, 0xfc, 0x6b, 0xed, 0x93, 0x93, 0x1a, 0xb1, 0x7f, 0xe7, 0xe1,
- 0xe5, 0xb5, 0xa6, 0x31, 0x62, 0xfd, 0x1e, 0x0e, 0x4e, 0xb1, 0x6e, 0x1a,
- 0x8a, 0x4f, 0x9e, 0x06, 0x7f, 0x7f, 0xff, 0xf7, 0xe7, 0x98, 0x09, 0xf7,
- 0x35, 0x91, 0xce, 0xb9, 0xfe, 0x9b, 0x8b, 0x17, 0xda, 0xd3, 0x8d, 0x62,
- 0xf4, 0x1f, 0x4b, 0x14, 0x34, 0x5a, 0x63, 0xa3, 0x91, 0xdf, 0xc7, 0xd6,
- 0x9b, 0xb0, 0x2c, 0x5f, 0x79, 0xff, 0x12, 0xc5, 0xfc, 0x53, 0xd7, 0xdb,
- 0x75, 0x62, 0xf1, 0xb3, 0xc5, 0x8b, 0xfe, 0xcf, 0x79, 0x8d, 0xf6, 0x74,
- 0xb1, 0x7f, 0x4f, 0x7c, 0xce, 0xfc, 0xb1, 0x76, 0xa5, 0x62, 0x86, 0x78,
- 0xfe, 0x30, 0xbf, 0x08, 0x87, 0xb0, 0x6c, 0x0b, 0x17, 0xff, 0xde, 0xd4,
- 0xe7, 0x7b, 0x24, 0x71, 0x78, 0x0e, 0xb1, 0x7f, 0xbc, 0xdd, 0x30, 0xe7,
- 0xcb, 0x17, 0xee, 0x4f, 0x58, 0x75, 0x8a, 0x93, 0xdd, 0xe1, 0xa5, 0xf3,
- 0x77, 0x0c, 0x58, 0xb7, 0x36, 0xaa, 0x3f, 0x92, 0x48, 0x18, 0x8c, 0x7b,
- 0x21, 0x05, 0xd1, 0x17, 0x66, 0x7a, 0x85, 0x88, 0x08, 0x6a, 0x0b, 0x9c,
- 0x1d, 0xc3, 0x14, 0xf0, 0xec, 0x72, 0xef, 0x4a, 0x6f, 0xbe, 0x7e, 0xf0,
- 0x6b, 0x17, 0xfb, 0xf9, 0x0f, 0x33, 0x76, 0xb1, 0x7f, 0xde, 0x68, 0xe7,
- 0xb0, 0x6a, 0x56, 0x2e, 0xfc, 0x6b, 0x17, 0xb9, 0xec, 0x58, 0xb7, 0x36,
- 0x9f, 0x8f, 0x47, 0x61, 0x8c, 0xdf, 0xf4, 0x6f, 0x84, 0x28, 0x67, 0x16,
- 0x2b, 0x0f, 0xcb, 0x87, 0x37, 0xe7, 0x06, 0xcb, 0x1d, 0x62, 0xfe, 0xe9,
- 0xb8, 0x28, 0x32, 0xc5, 0xe2, 0x17, 0x16, 0x2b, 0xe7, 0x99, 0xbc, 0xbe,
- 0xff, 0xec, 0xf3, 0x77, 0x02, 0x9d, 0x8f, 0x61, 0x6c, 0xac, 0x5f, 0xf3,
- 0xb7, 0x98, 0xbc, 0x2f, 0xac, 0x5e, 0xfb, 0x6f, 0x58, 0xb8, 0x50, 0xf9,
- 0xeb, 0x86, 0x71, 0x7f, 0xf3, 0x8f, 0xed, 0xac, 0xdf, 0x25, 0x12, 0xc5,
- 0xff, 0xdc, 0x16, 0x8b, 0x07, 0xf9, 0x32, 0x56, 0x2d, 0x3b, 0x51, 0x17,
- 0xe4, 0x6b, 0x87, 0xd2, 0xc5, 0xd9, 0xbc, 0x67, 0x86, 0x02, 0xab, 0xfc,
- 0x6f, 0xbb, 0xe9, 0xb5, 0xc5, 0x8b, 0xf6, 0x78, 0x0f, 0xe5, 0x8a, 0x95,
- 0x4b, 0x50, 0x24, 0xd4, 0x2a, 0xbf, 0x0f, 0xd1, 0x17, 0xec, 0x9c, 0x5f,
- 0xff, 0xa7, 0xef, 0x85, 0x3a, 0x34, 0x62, 0x7d, 0x41, 0x62, 0xa0, 0xae,
- 0xb3, 0x84, 0x3e, 0x95, 0xa3, 0xba, 0xcb, 0x52, 0xce, 0xa9, 0x1b, 0x9e,
- 0x42, 0xe1, 0xa5, 0x2e, 0xbc, 0xec, 0xa0, 0x17, 0xbc, 0x46, 0x29, 0xcc,
- 0x3b, 0xff, 0xf7, 0xa4, 0x60, 0x7e, 0xc0, 0xdd, 0x87, 0xa7, 0xed, 0x62,
- 0xe7, 0x82, 0xc5, 0xda, 0xc5, 0x8a, 0x63, 0x5c, 0xe2, 0xf6, 0xd9, 0x58,
- 0xa9, 0x45, 0xe7, 0xe1, 0x11, 0xb2, 0x3f, 0x7f, 0xb0, 0xa1, 0x9c, 0x0c,
- 0xeb, 0x17, 0xe3, 0xf0, 0x0e, 0xeb, 0x15, 0xe3, 0xdc, 0x0c, 0xd2, 0xff,
- 0x61, 0x6d, 0xfe, 0x76, 0x62, 0xc5, 0xfd, 0x3f, 0x6d, 0xf9, 0x12, 0xc5,
- 0x68, 0xf9, 0xc0, 0x6f, 0x7e, 0x89, 0xdc, 0xa3, 0x58, 0xbf, 0x84, 0x0d,
- 0xbd, 0x1c, 0x0b, 0x16, 0x86, 0x1e, 0xe1, 0x14, 0xd4, 0x69, 0xe0, 0xc2,
- 0x12, 0x79, 0x08, 0xae, 0xdf, 0xaf, 0xfb, 0x3b, 0x87, 0xf7, 0x77, 0x67,
- 0x71, 0x62, 0xff, 0xdf, 0xe3, 0x41, 0xbd, 0x3e, 0xe2, 0xc5, 0xff, 0xe0,
- 0x10, 0xb9, 0xee, 0x4e, 0xb3, 0xbf, 0x2c, 0x53, 0xa2, 0x2c, 0x8f, 0xef,
- 0xfe, 0x6d, 0x6d, 0x79, 0x84, 0x90, 0xa0, 0xb1, 0x7d, 0x3a, 0xcd, 0xeb,
- 0x17, 0xef, 0xb6, 0xcb, 0xc6, 0xb1, 0x50, 0x44, 0xaf, 0x11, 0x7c, 0x49,
- 0x7f, 0x81, 0xcc, 0x2c, 0xe0, 0x96, 0x2b, 0x0f, 0x8d, 0xcc, 0x2d, 0x05,
- 0x8b, 0xfd, 0x39, 0xdf, 0xb3, 0x52, 0xb1, 0x5a, 0x3c, 0x52, 0x12, 0xbf,
- 0xf4, 0xfc, 0x3e, 0x16, 0x7b, 0xf8, 0xb1, 0x7f, 0xf7, 0xc5, 0xce, 0x4e,
+ 0xcb, 0x35, 0x9e, 0xee, 0x75, 0x8b, 0xf8, 0x85, 0x37, 0xde, 0x65, 0x8b,
+ 0xfe, 0x61, 0xe1, 0x49, 0xbe, 0x25, 0x8b, 0x6c, 0xe2, 0x3d, 0xe6, 0x37,
+ 0x38, 0xef, 0x0e, 0xfc, 0x61, 0x76, 0xc6, 0x6a, 0xc5, 0xc0, 0x12, 0xc5,
+ 0xe9, 0x16, 0xea, 0xc5, 0xdd, 0xf9, 0x62, 0xff, 0xfa, 0x3f, 0x12, 0x27,
+ 0x37, 0xb9, 0x46, 0x79, 0x62, 0xff, 0xb0, 0xfd, 0xf9, 0xbf, 0x81, 0x16,
+ 0x2d, 0xc5, 0x8a, 0x19, 0xe7, 0x39, 0xe5, 0xf0, 0x82, 0x0e, 0x16, 0x2f,
+ 0xfe, 0x2c, 0x9f, 0x50, 0x4c, 0xfd, 0xc9, 0x62, 0xa4, 0x9a, 0x08, 0xc6,
+ 0x5a, 0x13, 0xdf, 0x21, 0xf1, 0x2d, 0xfc, 0x61, 0x47, 0xbe, 0xcb, 0x17,
+ 0x8b, 0xbe, 0x2c, 0x56, 0x1e, 0x60, 0x8b, 0xae, 0xf0, 0x6b, 0x17, 0x3b,
+ 0x2c, 0x56, 0x1a, 0xff, 0x8c, 0xdf, 0xfe, 0x10, 0x5f, 0x9d, 0x7d, 0xbf,
+ 0x19, 0xa9, 0x2c, 0x5f, 0xfd, 0xc6, 0xde, 0x58, 0x01, 0x73, 0xe2, 0x58,
+ 0xbf, 0xfe, 0xfb, 0x09, 0xfb, 0x96, 0xb3, 0xb9, 0x31, 0xd6, 0x2f, 0xf7,
+ 0xc3, 0x9b, 0x8d, 0xd9, 0x8b, 0x16, 0xed, 0x62, 0xa1, 0x13, 0xd8, 0xa4,
+ 0xe7, 0x35, 0x09, 0xb1, 0x62, 0x81, 0x43, 0x96, 0xff, 0xf3, 0x3e, 0xf2,
+ 0x13, 0x86, 0x3f, 0xb1, 0xab, 0x16, 0x25, 0x8b, 0xfd, 0x22, 0xcd, 0xe5,
+ 0x9c, 0x58, 0xac, 0x3c, 0x57, 0x11, 0xbf, 0xf8, 0x47, 0xf9, 0x67, 0x7e,
+ 0x27, 0xfa, 0xc5, 0xff, 0xfa, 0x44, 0xfe, 0x73, 0xf2, 0x07, 0x1f, 0x89,
+ 0x2c, 0x57, 0x11, 0x32, 0x1a, 0x2d, 0xd9, 0xc5, 0x8b, 0xce, 0xfd, 0x2a,
+ 0x22, 0xd2, 0xa4, 0x7c, 0xb8, 0x49, 0xd0, 0xbd, 0xff, 0xfd, 0xf7, 0xc2,
+ 0x7f, 0x73, 0x9d, 0x7d, 0xb7, 0xc7, 0x16, 0x2f, 0xbc, 0x4e, 0x6a, 0xc5,
+ 0xfa, 0x35, 0x9d, 0xf9, 0x62, 0xcd, 0xa4, 0x54, 0xfd, 0x74, 0x04, 0x77,
+ 0xe6, 0x37, 0xda, 0x85, 0x8b, 0xb5, 0xc5, 0x8b, 0xf1, 0x91, 0xbd, 0xfe,
+ 0xb1, 0x7f, 0xbc, 0xe7, 0x79, 0x3e, 0x96, 0x2a, 0x0f, 0x79, 0x8a, 0xef,
+ 0x70, 0x3f, 0x2c, 0x54, 0x95, 0xcd, 0x8e, 0x12, 0x5a, 0x8c, 0x7b, 0xf0,
+ 0xd8, 0x23, 0x5e, 0x14, 0xef, 0x76, 0x0c, 0x82, 0xef, 0x79, 0x62, 0xff,
+ 0xf8, 0x5e, 0xe0, 0xff, 0x1c, 0x8f, 0x8a, 0x38, 0xb1, 0x7f, 0xfc, 0xff,
+ 0xc2, 0xd6, 0xb3, 0xb9, 0x79, 0x8e, 0xb1, 0x52, 0x45, 0xc9, 0xa3, 0x02,
+ 0x51, 0xbb, 0xa8, 0x58, 0xbe, 0x3b, 0x19, 0xc5, 0x8b, 0xff, 0xc6, 0xb6,
+ 0xbd, 0xdf, 0x4d, 0x86, 0x4a, 0x75, 0x8a, 0x39, 0xfa, 0x78, 0x92, 0xff,
+ 0x9c, 0x32, 0xc9, 0xb5, 0x06, 0x2c, 0x53, 0x1e, 0xe8, 0x88, 0xae, 0x23,
+ 0x16, 0x2b, 0x13, 0x22, 0xfc, 0x3a, 0x4c, 0x21, 0xbf, 0x8e, 0xdd, 0xf2,
+ 0x3b, 0x58, 0xbf, 0xfa, 0x30, 0xbc, 0x27, 0x1f, 0x20, 0xd5, 0x8b, 0xfa,
+ 0x07, 0xdf, 0x22, 0x65, 0x8a, 0x84, 0x52, 0x48, 0xc3, 0x88, 0x97, 0x3e,
+ 0xf5, 0x8b, 0xe8, 0xe8, 0xe2, 0x58, 0xb0, 0xd8, 0xde, 0x90, 0xcd, 0xfb,
+ 0xb1, 0xe9, 0xe4, 0xb1, 0x7f, 0x84, 0x02, 0xc9, 0xc3, 0x92, 0xc5, 0xe1,
+ 0x44, 0xeb, 0x17, 0xcd, 0xa7, 0x92, 0xc5, 0xe8, 0xf7, 0x0e, 0x78, 0x1f,
+ 0x1e, 0xa8, 0x46, 0x9f, 0xca, 0x89, 0xda, 0xff, 0xc5, 0xef, 0xe4, 0x8c,
+ 0x8e, 0xf8, 0xb1, 0x7f, 0xdd, 0xf3, 0xcd, 0x3c, 0xed, 0xe5, 0x8b, 0xff,
+ 0xd3, 0x8f, 0x4f, 0xd1, 0x66, 0xfd, 0x37, 0x16, 0x2a, 0x11, 0x16, 0x23,
+ 0xdb, 0x87, 0x0b, 0x15, 0x09, 0x82, 0xea, 0x19, 0x84, 0x45, 0x70, 0x1d,
+ 0x62, 0xfe, 0xeb, 0x59, 0x2d, 0xcc, 0x58, 0xa6, 0x3c, 0x91, 0x0b, 0xdf,
+ 0xe6, 0xde, 0xdb, 0xce, 0xde, 0x58, 0xb0, 0xd6, 0x2f, 0xf7, 0x23, 0x53,
+ 0x4c, 0xdf, 0x58, 0xa1, 0x9e, 0x47, 0x04, 0xaf, 0xed, 0x41, 0xf0, 0x8e,
+ 0xb1, 0x7f, 0x89, 0xb8, 0xc5, 0xdc, 0x96, 0x2b, 0x47, 0xc0, 0x61, 0x6d,
+ 0xcd, 0x3a, 0xc5, 0xe3, 0x81, 0x96, 0x2f, 0xed, 0x3f, 0x1f, 0x3e, 0xb1,
+ 0x6f, 0x39, 0xe5, 0x08, 0x76, 0xe8, 0xdd, 0x58, 0xbf, 0xe8, 0xce, 0x4d,
+ 0xf6, 0x33, 0xcb, 0x14, 0x34, 0x6f, 0x33, 0x11, 0xc9, 0xf8, 0x35, 0x50,
+ 0xa8, 0xfb, 0x1f, 0xda, 0x10, 0x4f, 0x18, 0x0d, 0xff, 0x1f, 0x35, 0xa6,
+ 0xde, 0xfd, 0x2c, 0x5f, 0xd9, 0x83, 0xdf, 0x1f, 0x58, 0xbf, 0xfb, 0xad,
+ 0x41, 0xb0, 0x5e, 0x0b, 0x02, 0xc0, 0xa2, 0xc5, 0xe0, 0xa9, 0x0d, 0x62,
+ 0xfe, 0xd6, 0x7d, 0xbb, 0x25, 0x8b, 0xe3, 0x41, 0x1e, 0x58, 0xb7, 0xe0,
+ 0xf4, 0x98, 0xba, 0xfe, 0xf9, 0x09, 0xcd, 0xe9, 0x62, 0xfe, 0x8d, 0x60,
+ 0xde, 0x4b, 0x14, 0x34, 0x41, 0xb1, 0x30, 0x66, 0x17, 0x17, 0x16, 0x2a,
+ 0x13, 0x92, 0x1a, 0xae, 0x43, 0xd8, 0x8c, 0x2f, 0xfb, 0xa0, 0xfc, 0xd2,
+ 0x33, 0x3e, 0xb1, 0x7f, 0xc5, 0x19, 0x3f, 0xb9, 0x93, 0xac, 0x5f, 0xfe,
+ 0x60, 0x6a, 0x24, 0xdc, 0xe4, 0x6a, 0x4b, 0x17, 0xff, 0x73, 0x26, 0x28,
+ 0x3e, 0xb5, 0x1d, 0xac, 0x56, 0x91, 0x21, 0xe4, 0xab, 0xfe, 0x10, 0x5c,
+ 0x79, 0xee, 0x67, 0xd6, 0x2d, 0xe8, 0x3e, 0x17, 0x23, 0xbf, 0xee, 0xb0,
+ 0xb2, 0x79, 0xc4, 0x4b, 0x16, 0xdd, 0x58, 0xbe, 0xd7, 0x30, 0xc5, 0x8b,
+ 0xf1, 0x14, 0x76, 0x1c, 0x1b, 0x9c, 0x15, 0xbf, 0xfb, 0x50, 0x6c, 0x14,
+ 0x75, 0x0d, 0xf5, 0x8b, 0xf9, 0xb9, 0xad, 0x44, 0x96, 0x2f, 0xff, 0x78,
+ 0x5a, 0x7e, 0x79, 0xb7, 0x30, 0x10, 0xb1, 0x4b, 0x0c, 0x79, 0xb5, 0xd2,
+ 0x25, 0xdd, 0xee, 0xff, 0xa7, 0xfe, 0x7b, 0x84, 0xd3, 0x2c, 0x5f, 0xcd,
+ 0x85, 0xdc, 0xb8, 0xb1, 0x7d, 0x39, 0xc4, 0x6a, 0xc5, 0xff, 0xee, 0x37,
+ 0x66, 0x67, 0x50, 0x42, 0x79, 0x2c, 0x5b, 0x27, 0x45, 0x06, 0x8b, 0x80,
+ 0x4d, 0x7f, 0xff, 0xb0, 0x86, 0x38, 0x03, 0x06, 0x7e, 0x37, 0xa3, 0xb3,
+ 0x16, 0x2f, 0xf8, 0xbd, 0xcf, 0x66, 0x19, 0xc5, 0x8b, 0x9f, 0xeb, 0x15,
+ 0x87, 0xa3, 0xd9, 0xd5, 0xff, 0xdf, 0x6f, 0x73, 0xed, 0x82, 0x2f, 0x2c,
+ 0x5f, 0xff, 0xa6, 0x94, 0x03, 0x59, 0xd4, 0x49, 0xb4, 0xdc, 0x58, 0xbf,
+ 0x38, 0x39, 0x28, 0x58, 0xa8, 0x47, 0x2c, 0x88, 0xb1, 0x10, 0x95, 0xef,
+ 0xd9, 0xfd, 0x8f, 0x61, 0x85, 0xba, 0xc5, 0x42, 0xf2, 0xd8, 0xcf, 0x72,
+ 0x32, 0xbe, 0x89, 0x99, 0xd3, 0x47, 0x9f, 0x86, 0xdb, 0x91, 0x94, 0x36,
+ 0xf8, 0x6d, 0xe8, 0xe6, 0x4c, 0x3a, 0xbf, 0xf6, 0x79, 0xc8, 0x0e, 0x73,
+ 0xb2, 0xc5, 0xee, 0x9a, 0x75, 0x8b, 0xff, 0xff, 0x0b, 0xf8, 0x3f, 0x7f,
+ 0x0f, 0x9f, 0xfb, 0xb7, 0xa3, 0xdc, 0x58, 0xbf, 0xf1, 0x13, 0x9a, 0x1e,
+ 0xb4, 0xfd, 0xac, 0x5e, 0xe6, 0x12, 0xc5, 0xfe, 0xef, 0xf8, 0x3d, 0x3f,
+ 0x4b, 0x15, 0x88, 0x93, 0x64, 0x17, 0x1c, 0xa9, 0x27, 0x11, 0xd9, 0xeb,
+ 0x0f, 0xf2, 0x1f, 0xf7, 0x8d, 0xc0, 0x8b, 0x17, 0xfb, 0x44, 0x2e, 0xfc,
+ 0x50, 0xb1, 0x60, 0x8b, 0x15, 0x07, 0x90, 0x10, 0xd2, 0xec, 0xed, 0x22,
+ 0xd0, 0x91, 0x60, 0x68, 0xd4, 0x80, 0x62, 0xff, 0x7b, 0x34, 0x03, 0xb7,
+ 0x12, 0x36, 0x4d, 0x3d, 0xfd, 0x2f, 0xb6, 0xfc, 0x99, 0x62, 0xa0, 0xfe,
+ 0x1d, 0x1e, 0xfd, 0xbc, 0xa3, 0xbe, 0x2c, 0x5f, 0xff, 0xff, 0x41, 0x74,
+ 0xfe, 0x7e, 0xc1, 0xee, 0x61, 0x13, 0x9a, 0x1e, 0xb4, 0xfd, 0xac, 0x5f,
+ 0x40, 0x0f, 0x8b, 0x14, 0x04, 0x51, 0x7a, 0x10, 0x17, 0xfc, 0x3e, 0x73,
+ 0x34, 0x3f, 0xe2, 0xc5, 0xff, 0xe0, 0x9e, 0x83, 0x23, 0x9f, 0x7d, 0xf8,
+ 0x35, 0x8b, 0xfb, 0xed, 0xd4, 0x1d, 0x96, 0x2f, 0xff, 0xbd, 0xe7, 0x06,
+ 0x0d, 0xb8, 0x37, 0x73, 0x16, 0x2f, 0xf4, 0x02, 0x77, 0x94, 0x6e, 0xac,
+ 0x5f, 0xff, 0xdc, 0x6f, 0x7f, 0x07, 0x9d, 0x47, 0x98, 0xb3, 0xb5, 0x8a,
+ 0x84, 0xc4, 0x30, 0xb8, 0x94, 0x3c, 0x6f, 0x7f, 0xfe, 0x2c, 0x03, 0x90,
+ 0x03, 0x3f, 0x84, 0xf3, 0xc2, 0xc5, 0x62, 0xb1, 0xfe, 0xe1, 0x9a, 0xc5,
+ 0x13, 0x1d, 0x14, 0x6b, 0xfe, 0x3b, 0xb6, 0xce, 0xc6, 0xe8, 0x42, 0x42,
+ 0x83, 0xc1, 0x6e, 0x31, 0x11, 0xb0, 0xcf, 0x09, 0xb9, 0x28, 0x0e, 0x38,
+ 0x2c, 0x97, 0x9c, 0x6c, 0x67, 0xdd, 0x46, 0xa7, 0xdc, 0x36, 0x99, 0xb2,
+ 0x68, 0x7c, 0x6a, 0x33, 0x33, 0xbe, 0xfe, 0x52, 0xfb, 0xa3, 0x00, 0xf0,
+ 0xa3, 0xc1, 0xe4, 0xf4, 0xdf, 0xa5, 0x21, 0x89, 0x0c, 0xc6, 0x8d, 0xc8,
+ 0x75, 0x87, 0x2c, 0xfe, 0xff, 0xff, 0xe7, 0x3e, 0xcb, 0x6b, 0x42, 0xd6,
+ 0xa0, 0xb0, 0xd6, 0xff, 0xf0, 0x35, 0x8b, 0xed, 0x0b, 0xd8, 0xb1, 0x7f,
+ 0xf1, 0xa6, 0x6e, 0xce, 0x3d, 0x8b, 0x6e, 0xdf, 0xee, 0x2c, 0x5f, 0xa2,
+ 0x77, 0xd7, 0x4b, 0x17, 0x36, 0xf5, 0x8b, 0xd1, 0xee, 0x2c, 0x5e, 0xe0,
+ 0x8f, 0xa3, 0xe0, 0x01, 0x51, 0x0c, 0xd0, 0x58, 0x8f, 0xa6, 0x85, 0xd5,
+ 0xfe, 0xc0, 0x73, 0x3a, 0x71, 0xac, 0x5f, 0x89, 0xcc, 0xe7, 0x16, 0x2b,
+ 0x0f, 0x77, 0x46, 0x97, 0xdd, 0x3b, 0xf4, 0xa8, 0xa8, 0x8b, 0xc6, 0xc7,
+ 0x16, 0x2f, 0xef, 0xc7, 0xa3, 0xb3, 0x16, 0x2f, 0x8a, 0x4c, 0x75, 0x8b,
+ 0xf4, 0xb0, 0x98, 0x6b, 0x15, 0x88, 0x97, 0x61, 0xe7, 0x30, 0xf1, 0x15,
+ 0x69, 0x30, 0x23, 0xc3, 0x22, 0xfb, 0xf9, 0xac, 0x58, 0xbc, 0xd3, 0x04,
+ 0x58, 0xa8, 0x3c, 0x2f, 0x91, 0x5f, 0xba, 0x7f, 0xc7, 0xd6, 0x2f, 0xff,
+ 0xe1, 0x13, 0x9b, 0xb7, 0xc6, 0xc1, 0x4b, 0x3e, 0xc7, 0x58, 0xb8, 0x41,
+ 0xac, 0x5e, 0x1c, 0x1d, 0x62, 0xf8, 0xd0, 0xcb, 0xa5, 0x8a, 0x19, 0xe1,
+ 0x9a, 0x3b, 0x7f, 0xfd, 0x29, 0xc2, 0xc8, 0xd8, 0x27, 0xeb, 0x5b, 0x76,
+ 0xff, 0x71, 0x62, 0xa1, 0x1c, 0xcc, 0xb8, 0x02, 0x3b, 0xf6, 0x9b, 0xa6,
+ 0xde, 0xb1, 0x7c, 0x38, 0xc2, 0x58, 0xbf, 0x39, 0xb9, 0xf7, 0x58, 0xac,
+ 0x3c, 0x91, 0x10, 0xdf, 0xff, 0xc2, 0x27, 0x37, 0x6f, 0x8d, 0x82, 0x96,
+ 0x7d, 0x8e, 0xb1, 0x7d, 0xad, 0x66, 0xe2, 0xc5, 0x1d, 0x10, 0x8e, 0xbd,
+ 0x7f, 0xa0, 0xa4, 0x3f, 0xb1, 0xd6, 0x2f, 0xff, 0xfd, 0x9e, 0xcf, 0x66,
+ 0x80, 0x77, 0x94, 0x71, 0xb8, 0xdd, 0xf9, 0x62, 0x8d, 0x44, 0xff, 0x0c,
+ 0xef, 0xff, 0xcf, 0x22, 0x8e, 0x67, 0x7d, 0x13, 0xe7, 0x7d, 0x2c, 0x5f,
+ 0xa0, 0xcc, 0xfb, 0xac, 0x5e, 0x1b, 0x6f, 0x58, 0xb6, 0xcc, 0x2f, 0xc6,
+ 0x4a, 0x31, 0xd1, 0xc2, 0x27, 0x23, 0x23, 0xe9, 0xad, 0x88, 0x4e, 0x53,
+ 0xf8, 0xd1, 0x1c, 0xb8, 0x9d, 0x39, 0x0a, 0x5f, 0x43, 0x07, 0x79, 0x20,
+ 0x6a, 0xe1, 0x0a, 0x2f, 0xdc, 0x13, 0x90, 0x16, 0x2f, 0xb0, 0x9b, 0xcb,
+ 0x17, 0xb0, 0xfb, 0x3e, 0x3c, 0x9d, 0xc2, 0x8b, 0xfe, 0xfb, 0x6b, 0xef,
+ 0xcc, 0x0d, 0x62, 0xe1, 0x92, 0xc5, 0xfa, 0x68, 0xf8, 0xa7, 0x58, 0xbf,
+ 0x3c, 0xbc, 0xd3, 0xac, 0x56, 0x1e, 0xa3, 0x15, 0xde, 0x7f, 0x32, 0xc5,
+ 0xd1, 0xb3, 0x88, 0xe1, 0xec, 0xeb, 0xed, 0x7c, 0x20, 0xa1, 0xa6, 0xcb,
+ 0xc8, 0xc6, 0xaf, 0x61, 0x98, 0xb1, 0x7c, 0xe7, 0x28, 0x58, 0xbf, 0xf9,
+ 0x8a, 0x3c, 0xda, 0x63, 0xe0, 0xd6, 0x28, 0x8f, 0x8c, 0x21, 0x0d, 0xd1,
+ 0x3a, 0xc5, 0x61, 0xbb, 0x11, 0x1d, 0xc2, 0xfa, 0xc5, 0xfc, 0xf2, 0xef,
+ 0x91, 0x3a, 0xc5, 0xff, 0x3f, 0x65, 0x9b, 0xf4, 0xdc, 0x58, 0xbf, 0x34,
+ 0x49, 0xe4, 0xb1, 0x53, 0xa2, 0xa8, 0x63, 0x07, 0x30, 0xf9, 0xdd, 0xfd,
+ 0x93, 0x8e, 0x30, 0x6b, 0x17, 0xc3, 0xfb, 0x4c, 0xb1, 0x58, 0x7a, 0x4e,
+ 0x5d, 0x7e, 0x27, 0x09, 0x93, 0xac, 0x5e, 0x31, 0xfe, 0xb1, 0x74, 0x0d,
+ 0x62, 0xa0, 0xda, 0xfc, 0x7a, 0xff, 0xb3, 0xdf, 0x7e, 0xa0, 0x86, 0xb1,
+ 0x7f, 0x8b, 0xdc, 0xd6, 0x41, 0xd6, 0x2a, 0x0f, 0xb1, 0xce, 0x6f, 0xcc,
+ 0x44, 0x2d, 0xd5, 0x8b, 0xfe, 0xe6, 0x0f, 0x35, 0x28, 0xd2, 0xc5, 0x41,
+ 0xf1, 0xe8, 0xaa, 0xd3, 0xac, 0x54, 0x1b, 0x4c, 0x21, 0xbe, 0xea, 0x34,
+ 0x6a, 0xc5, 0xfa, 0x4f, 0xe9, 0x3a, 0xc5, 0xf4, 0x00, 0x10, 0xb1, 0x7f,
+ 0xa3, 0x53, 0xe1, 0xf0, 0xeb, 0x15, 0x07, 0xfc, 0x45, 0x1c, 0x22, 0xbf,
+ 0xe2, 0x1e, 0x68, 0x6e, 0xe3, 0x58, 0xb0, 0x96, 0x2a, 0x0f, 0x29, 0xce,
+ 0x29, 0x62, 0xc4, 0xb1, 0x39, 0x32, 0xfd, 0x3e, 0x9d, 0xfc, 0xb1, 0x4c,
+ 0x79, 0x2e, 0x41, 0x71, 0xc6, 0xb1, 0x7d, 0xf6, 0xfe, 0xc8, 0x55, 0x76,
+ 0xf4, 0x70, 0xbb, 0xc8, 0x65, 0x1b, 0x09, 0x0e, 0x88, 0x26, 0x5f, 0x3c,
+ 0x23, 0x3f, 0x0b, 0x7e, 0x0f, 0xfa, 0x14, 0x66, 0x3b, 0xee, 0x3a, 0x84,
+ 0x20, 0xbd, 0xcc, 0x25, 0x8b, 0xf6, 0xba, 0x77, 0xe9, 0x51, 0x5e, 0x97,
+ 0xe6, 0x09, 0xd0, 0xa7, 0x58, 0xb4, 0x96, 0x2c, 0x75, 0x8a, 0x83, 0x48,
+ 0xe2, 0x57, 0x40, 0x16, 0x2f, 0x7e, 0x3b, 0x58, 0xbe, 0xcf, 0x34, 0xeb,
+ 0x17, 0xf4, 0xe1, 0xee, 0x39, 0x01, 0x62, 0xff, 0xce, 0x40, 0xcf, 0x41,
+ 0x30, 0x16, 0x2a, 0x0f, 0xbf, 0x70, 0xce, 0xdb, 0x32, 0x4e, 0xbb, 0x07,
+ 0x34, 0x6e, 0xea, 0x20, 0x1f, 0x10, 0xbe, 0xe0, 0xf0, 0x70, 0x92, 0xbf,
+ 0xfb, 0x65, 0xe5, 0xb3, 0x9a, 0xe9, 0xdf, 0xa5, 0x44, 0x8c, 0x5f, 0xfe,
+ 0xd9, 0x3b, 0xcb, 0x67, 0x35, 0xd3, 0xbf, 0x4a, 0x89, 0xe0, 0xbf, 0x6b,
+ 0xa7, 0x7e, 0x95, 0x13, 0xf9, 0x76, 0xf6, 0x58, 0xbf, 0x6c, 0x9d, 0xe5,
+ 0xb3, 0x87, 0xa0, 0xc6, 0xf7, 0xff, 0xb6, 0x4e, 0xf2, 0xd9, 0xcd, 0x74,
+ 0xef, 0xd2, 0xa2, 0x86, 0x2f, 0xfc, 0xf2, 0xd9, 0xcd, 0x74, 0xef, 0xd2,
+ 0xa2, 0x88, 0x2f, 0xe7, 0xeb, 0x64, 0x0d, 0x3a, 0xc5, 0x1d, 0x10, 0x7b,
+ 0xd4, 0x2f, 0xfd, 0x2d, 0x91, 0x73, 0x6c, 0x72, 0x24, 0xb1, 0x5b, 0x27,
+ 0xd5, 0x04, 0xb7, 0xfe, 0x99, 0xbf, 0xde, 0x78, 0x78, 0x75, 0x8b, 0xff,
+ 0xcf, 0xb2, 0x37, 0x27, 0xeb, 0x68, 0x6e, 0x75, 0x8b, 0xf9, 0xbc, 0xda,
+ 0x70, 0x2c, 0x5f, 0x67, 0xb0, 0x0b, 0x17, 0xe2, 0x13, 0xcb, 0x8b, 0x16,
+ 0x3a, 0xc5, 0xff, 0x6f, 0xce, 0xe5, 0xa7, 0x79, 0x2c, 0x5e, 0x27, 0xd9,
+ 0x92, 0x31, 0x48, 0xb7, 0xc4, 0x5b, 0x85, 0x01, 0x89, 0x5f, 0x87, 0x05,
+ 0x1f, 0x58, 0xbf, 0xff, 0x7f, 0x0b, 0x0d, 0xfb, 0xcb, 0xe6, 0x38, 0x67,
+ 0x58, 0xbe, 0xe9, 0xdf, 0xa5, 0x45, 0x22, 0x54, 0x91, 0x13, 0xa5, 0x8b,
+ 0xf0, 0xbc, 0x51, 0xf5, 0x8b, 0xff, 0x6f, 0x7d, 0x71, 0xff, 0xc8, 0x9d,
+ 0x62, 0xfd, 0x13, 0x6a, 0x0e, 0xb1, 0x5f, 0x3e, 0xbe, 0x21, 0x5f, 0xfc,
+ 0xfd, 0xf3, 0xe6, 0x40, 0x36, 0x86, 0x75, 0x8b, 0xfd, 0x28, 0xd4, 0xf1,
+ 0xa9, 0xd6, 0x2f, 0xfe, 0xf7, 0x20, 0xe5, 0x83, 0xfe, 0x79, 0x62, 0xc2,
+ 0x58, 0xa8, 0x44, 0x66, 0x1b, 0x01, 0x12, 0xff, 0xf1, 0x67, 0xfc, 0x50,
+ 0x0c, 0x27, 0x92, 0xc5, 0xfe, 0x28, 0x3f, 0x01, 0xe7, 0x58, 0xbf, 0xcf,
+ 0xe3, 0xb7, 0xbe, 0xcb, 0x17, 0x9e, 0x5b, 0x30, 0xac, 0xeb, 0x21, 0x61,
+ 0x31, 0x1b, 0xc2, 0x4c, 0x04, 0x45, 0x0d, 0x7e, 0x17, 0x79, 0x1c, 0x33,
+ 0x3b, 0xed, 0x98, 0xc3, 0xac, 0x5d, 0x9b, 0xd6, 0x2f, 0xff, 0x75, 0x9e,
+ 0x82, 0xf7, 0x1c, 0x85, 0x8b, 0x16, 0xd9, 0xe1, 0xf1, 0x06, 0x33, 0x4c,
+ 0x8b, 0x3d, 0xf0, 0x87, 0xbf, 0xfd, 0x2d, 0x9d, 0x38, 0x1f, 0xcd, 0xac,
+ 0x3a, 0xc5, 0xff, 0xbb, 0xe4, 0x9b, 0x9c, 0x8d, 0x49, 0x62, 0xff, 0x9b,
+ 0xa8, 0x3f, 0x3d, 0x12, 0x58, 0xbb, 0xf8, 0xb1, 0x74, 0x18, 0xb1, 0x7f,
+ 0x0b, 0x40, 0xda, 0x39, 0x96, 0x2d, 0xb3, 0x24, 0x4e, 0x0c, 0xeb, 0xe2,
+ 0xfc, 0x18, 0xa7, 0x4c, 0x8c, 0x10, 0xdd, 0xbf, 0xa5, 0x9f, 0xfb, 0xc9,
+ 0x62, 0xff, 0xf9, 0xa6, 0xd9, 0xf7, 0xd9, 0xc1, 0x02, 0x0b, 0xc2, 0xc5,
+ 0xff, 0xba, 0xd9, 0x1b, 0x6d, 0x72, 0xea, 0x16, 0x2b, 0x11, 0x38, 0xea,
+ 0xf7, 0xff, 0xf6, 0x0f, 0xf0, 0x1e, 0xcf, 0x89, 0xc1, 0xce, 0x40, 0x12,
+ 0x2d, 0xb3, 0x0c, 0x94, 0xf1, 0xa0, 0xf5, 0x18, 0xa9, 0xe5, 0xcd, 0x7e,
+ 0x35, 0x47, 0x29, 0x04, 0x6e, 0x1e, 0x28, 0xdf, 0x0c, 0xad, 0xc2, 0x1b,
+ 0xfe, 0x8d, 0x9c, 0x26, 0x36, 0x38, 0xb1, 0x7b, 0x99, 0xc5, 0x8b, 0xe1,
+ 0x04, 0x1c, 0x2c, 0x57, 0x67, 0x85, 0xf1, 0xdb, 0xff, 0xef, 0xc7, 0xd8,
+ 0xde, 0x73, 0x08, 0x1b, 0x98, 0xb1, 0x7d, 0x1c, 0x1b, 0x2c, 0x5f, 0x74,
+ 0xef, 0xd2, 0xa2, 0x50, 0x2f, 0xfd, 0x00, 0x3b, 0xcb, 0xf0, 0xfa, 0x58,
+ 0xa9, 0x23, 0x90, 0xd5, 0x3d, 0x11, 0x11, 0x8d, 0xff, 0xef, 0xb4, 0xe7,
+ 0x16, 0x81, 0xce, 0x38, 0xd6, 0x2f, 0xfb, 0xf1, 0xa9, 0x9b, 0xf1, 0x32,
+ 0xc5, 0xfe, 0x73, 0x0b, 0x01, 0x00, 0x58, 0xbf, 0xd8, 0x3c, 0x1c, 0x17,
+ 0x96, 0x28, 0x8f, 0x97, 0x86, 0x77, 0xf3, 0xc8, 0x9a, 0x0d, 0x58, 0xbf,
+ 0xf9, 0xfb, 0xe4, 0xf8, 0x60, 0x8a, 0x38, 0xb1, 0x7f, 0xdc, 0x83, 0xe7,
+ 0x9c, 0x41, 0x75, 0x8b, 0xfd, 0x1c, 0x1e, 0x98, 0x53, 0xac, 0x5b, 0x3c,
+ 0x7e, 0x5b, 0xcf, 0x6e, 0xd4, 0x2c, 0x5f, 0xe9, 0x07, 0x2c, 0x04, 0x49,
+ 0x62, 0x86, 0x79, 0x9a, 0x17, 0xbe, 0x93, 0x6a, 0x4b, 0x17, 0x9c, 0x78,
+ 0xb1, 0x58, 0x7c, 0x33, 0x11, 0x70, 0x8e, 0xff, 0xa5, 0x9f, 0x2c, 0xf7,
+ 0xd9, 0x62, 0xff, 0xf3, 0xce, 0xda, 0xd3, 0x77, 0x2f, 0x3f, 0x6b, 0x17,
+ 0xff, 0xff, 0xde, 0x62, 0x14, 0xb3, 0x85, 0x93, 0x87, 0x2f, 0x1a, 0xdd,
+ 0xf0, 0x78, 0x4b, 0x17, 0xbf, 0xe3, 0xac, 0x5d, 0x2d, 0x98, 0x5d, 0x60,
+ 0xc8, 0xc1, 0xfa, 0x3d, 0x64, 0xd9, 0xa1, 0x40, 0x72, 0x10, 0x16, 0x94,
+ 0x2e, 0x79, 0x0d, 0x6f, 0x17, 0xee, 0x1c, 0x06, 0x9a, 0x12, 0x10, 0x16,
+ 0xd9, 0x92, 0xf5, 0xfb, 0xce, 0xee, 0xd4, 0xef, 0x95, 0x3b, 0x2b, 0x42,
+ 0xb8, 0x38, 0xf3, 0xba, 0xa4, 0x01, 0x34, 0xaa, 0x8d, 0xd9, 0xde, 0x7d,
+ 0x4a, 0xa7, 0x3c, 0x20, 0xbe, 0xb2, 0x08, 0x57, 0x85, 0xd0, 0xf9, 0x1a,
+ 0x60, 0xa9, 0x2e, 0x61, 0x27, 0xde, 0x6f, 0xfc, 0xf2, 0xd9, 0xcd, 0x74,
+ 0xef, 0xd2, 0xa2, 0x73, 0x2e, 0xcd, 0x2c, 0x5f, 0xee, 0x67, 0xe2, 0x7c,
+ 0xd2, 0xc5, 0xfe, 0x7e, 0xb6, 0x43, 0x39, 0x44, 0xe7, 0x97, 0x82, 0xf6,
+ 0xd9, 0x3a, 0x3a, 0x77, 0xc2, 0x6e, 0xe9, 0x42, 0xc5, 0xff, 0x9e, 0x5b,
+ 0x39, 0xae, 0x9d, 0xfa, 0x54, 0x51, 0x25, 0xb6, 0x7a, 0x3e, 0x73, 0x8b,
+ 0xdd, 0xb0, 0xe7, 0x58, 0xbf, 0xb9, 0xc8, 0x00, 0x73, 0xac, 0x5f, 0xe7,
+ 0xd4, 0xb6, 0x1e, 0xf0, 0x32, 0xc5, 0x61, 0xf6, 0x88, 0xc6, 0xf3, 0x77,
+ 0xc5, 0x8b, 0xc5, 0x07, 0x58, 0xbf, 0xe2, 0x7e, 0xfc, 0xfe, 0x93, 0xac,
+ 0x5f, 0xdf, 0xcc, 0xf7, 0xf1, 0x62, 0xa7, 0x45, 0x03, 0x0f, 0x00, 0x73,
+ 0xc7, 0x37, 0x6f, 0x85, 0x8b, 0xf6, 0xa3, 0x7b, 0x6f, 0x58, 0xbd, 0x33,
+ 0x1d, 0x62, 0x86, 0x79, 0x4c, 0x59, 0x7d, 0xc3, 0xc7, 0x16, 0x2f, 0xf9,
+ 0xb9, 0x83, 0x94, 0xbe, 0x25, 0x8b, 0xf7, 0x26, 0x93, 0x01, 0x62, 0xb1,
+ 0x10, 0xfd, 0x11, 0xb1, 0xd5, 0xe3, 0xb8, 0x16, 0x2f, 0xef, 0xfb, 0xd1,
+ 0xa0, 0x2c, 0x54, 0x1e, 0x66, 0x0e, 0xdf, 0xfd, 0x1d, 0xe7, 0x9b, 0xb3,
+ 0x33, 0xbf, 0x2c, 0x5f, 0xd8, 0x30, 0xc6, 0xe7, 0x58, 0xbf, 0xff, 0x61,
+ 0x4b, 0x6e, 0x0d, 0xb9, 0xdf, 0x84, 0xfc, 0x58, 0xbf, 0xd1, 0x38, 0x7b,
+ 0x8e, 0x40, 0x58, 0xba, 0x5b, 0x3b, 0x12, 0xe1, 0xb8, 0xe1, 0x19, 0x90,
+ 0xc1, 0xe8, 0xf5, 0x98, 0xff, 0x0a, 0x82, 0x7b, 0xf1, 0x06, 0xf4, 0x83,
+ 0x0b, 0xc3, 0x58, 0xbf, 0xb8, 0x5b, 0x76, 0x31, 0xb2, 0xc5, 0xff, 0x8b,
+ 0x01, 0x00, 0xd6, 0xa0, 0xc5, 0x8b, 0xe2, 0x2c, 0xf2, 0xc5, 0xb6, 0x61,
+ 0x12, 0xbc, 0x35, 0x0c, 0xfe, 0xb4, 0x9c, 0x70, 0x23, 0x55, 0xad, 0x2f,
+ 0x5a, 0xf2, 0x13, 0x42, 0x9d, 0xf1, 0xbf, 0xff, 0xff, 0x4e, 0x1e, 0xe8,
+ 0x5b, 0x85, 0xf6, 0xed, 0xfe, 0xe6, 0xc9, 0x05, 0x9b, 0x10, 0x53, 0x74,
+ 0x2c, 0x0f, 0x6e, 0xdf, 0xee, 0x2c, 0x5f, 0xb5, 0xd3, 0xbf, 0x4a, 0x88,
+ 0x70, 0xbf, 0x85, 0xd6, 0x9a, 0x09, 0x62, 0xfc, 0xc5, 0xe8, 0x3a, 0xc5,
+ 0xb6, 0x71, 0x11, 0x9f, 0x37, 0xdc, 0x2e, 0xbf, 0xfb, 0x61, 0x85, 0x3f,
+ 0x02, 0x09, 0xd7, 0xe0, 0xc5, 0x8b, 0xff, 0x30, 0xf0, 0xe5, 0x9d, 0xf9,
+ 0xd6, 0x2f, 0xf6, 0xb3, 0xaf, 0xc7, 0x72, 0x58, 0xb1, 0x8b, 0x15, 0x07,
+ 0x93, 0x86, 0xd4, 0xb1, 0x7f, 0xf1, 0x39, 0xbd, 0x7d, 0xb5, 0xa8, 0x31,
+ 0x62, 0xfa, 0x71, 0xc4, 0xeb, 0x17, 0xff, 0x75, 0xf8, 0x35, 0xb8, 0x16,
+ 0x82, 0x8f, 0xf5, 0x8b, 0x09, 0x62, 0xfe, 0x8f, 0x7e, 0x3b, 0x02, 0xc5,
+ 0x6e, 0xa2, 0x48, 0xea, 0x3c, 0x12, 0xb8, 0x89, 0x62, 0xfb, 0xa7, 0x7e,
+ 0x95, 0x11, 0x79, 0x7f, 0xb3, 0xb0, 0x71, 0xda, 0x75, 0x8b, 0xf1, 0x38,
+ 0x1f, 0x8b, 0x17, 0xec, 0x9a, 0x4f, 0xc5, 0x8a, 0xc4, 0xed, 0x9a, 0x16,
+ 0xf3, 0x19, 0xe8, 0x58, 0x8c, 0x7c, 0x6a, 0x19, 0x3d, 0xfe, 0x9f, 0xf9,
+ 0xfc, 0x69, 0xd6, 0x2f, 0x41, 0x9e, 0x58, 0xb3, 0xe8, 0xf4, 0xc8, 0xd6,
+ 0xe1, 0x6e, 0xac, 0x5c, 0x2d, 0x2c, 0x54, 0x8d, 0x9b, 0x8d, 0xde, 0xfb,
+ 0x69, 0x62, 0xf8, 0xa3, 0x76, 0x65, 0x8a, 0x39, 0xe1, 0xfc, 0x76, 0xf8,
+ 0x23, 0x14, 0xcb, 0x17, 0x19, 0x32, 0xc5, 0xfd, 0x83, 0xfe, 0x01, 0xd6,
+ 0x2f, 0xa0, 0x41, 0x7e, 0x2c, 0x56, 0x22, 0x4d, 0xc9, 0x78, 0x34, 0x61,
+ 0x6d, 0xfe, 0x60, 0x70, 0x00, 0x6f, 0x2c, 0x5f, 0xa0, 0xe0, 0xe8, 0x0b,
+ 0x15, 0x87, 0xbc, 0xc6, 0x97, 0x07, 0xc5, 0x8b, 0x49, 0x62, 0xa0, 0xd5,
+ 0xb8, 0xcd, 0xfe, 0x07, 0xb9, 0xfc, 0x61, 0xac, 0x5a, 0x75, 0x8a, 0xd1,
+ 0xe3, 0x91, 0xa5, 0xff, 0x78, 0xa0, 0xe1, 0x8f, 0xf0, 0xb1, 0x7e, 0x79,
+ 0x1e, 0x24, 0xb1, 0x63, 0xac, 0x54, 0x22, 0x55, 0x88, 0x7e, 0x75, 0xe2,
+ 0x8b, 0xf7, 0x5b, 0x7d, 0x9a, 0x58, 0xbf, 0xc2, 0x72, 0xeb, 0x52, 0xe2,
+ 0xc5, 0xfe, 0xc3, 0xe7, 0x5d, 0x37, 0xd6, 0x2f, 0x49, 0xe4, 0xb1, 0x4c,
+ 0x7a, 0x53, 0x1a, 0xdd, 0xce, 0xd6, 0x2f, 0xbd, 0x28, 0x35, 0x22, 0xfb,
+ 0x07, 0xee, 0x2c, 0x56, 0x22, 0x08, 0xe4, 0x4e, 0x32, 0x44, 0x97, 0xf8,
+ 0xb3, 0xb9, 0x71, 0x8d, 0x58, 0xbf, 0x00, 0x10, 0x46, 0xac, 0x5e, 0xe9,
+ 0xe4, 0xb1, 0x6f, 0xc1, 0xe3, 0xe1, 0x4d, 0xf9, 0xfb, 0x13, 0xf9, 0x62,
+ 0xed, 0xc2, 0x58, 0xbf, 0x8e, 0xc5, 0x87, 0x85, 0x8b, 0xe9, 0xfd, 0x9f,
+ 0x58, 0xac, 0x3d, 0x07, 0x2c, 0xbf, 0xd0, 0x0c, 0x21, 0x72, 0x16, 0x2d,
+ 0xb2, 0x16, 0x32, 0x90, 0xa1, 0x52, 0x78, 0x43, 0xc8, 0x80, 0x61, 0x99,
+ 0x1f, 0xef, 0x50, 0xbc, 0xed, 0x65, 0x98, 0xe6, 0x85, 0xae, 0xa1, 0x34,
+ 0x74, 0xbf, 0xc3, 0xed, 0xce, 0xc0, 0x58, 0x51, 0x84, 0xf0, 0xeb, 0xcf,
+ 0x82, 0x26, 0xde, 0x53, 0xb8, 0xd4, 0x19, 0x05, 0xff, 0x3f, 0x5b, 0x32,
+ 0xcd, 0x64, 0x96, 0x2f, 0xff, 0xff, 0x89, 0xf6, 0x70, 0x41, 0x76, 0x35,
+ 0xbd, 0xfc, 0x69, 0x73, 0x6e, 0x1b, 0x12, 0x58, 0xbf, 0x67, 0x0e, 0x38,
+ 0x58, 0xbf, 0xfe, 0x79, 0xf5, 0x13, 0xf1, 0xc8, 0x5d, 0x67, 0x16, 0x2f,
+ 0xda, 0xe9, 0xdf, 0xa5, 0x44, 0xc8, 0x5e, 0x79, 0x6c, 0xc2, 0x22, 0x71,
+ 0x4a, 0xdb, 0x33, 0xa7, 0x53, 0xd1, 0xee, 0xa1, 0x0c, 0x78, 0x58, 0xdf,
+ 0xfd, 0xf6, 0xd4, 0xb6, 0x47, 0x87, 0x19, 0xd6, 0x2f, 0xdb, 0x3f, 0x77,
+ 0x3a, 0xc5, 0xef, 0x61, 0xd6, 0x2e, 0xf9, 0xd6, 0x2f, 0xda, 0xe9, 0xdf,
+ 0xa5, 0x45, 0xbc, 0x5b, 0x66, 0x0f, 0xb0, 0x63, 0xb8, 0x31, 0x7d, 0xb3,
+ 0xb9, 0x84, 0xb1, 0x73, 0x84, 0x58, 0xbf, 0xc0, 0x81, 0x89, 0xf5, 0x25,
+ 0x8b, 0xff, 0x3c, 0xb6, 0x73, 0x5d, 0x3b, 0xf4, 0xa8, 0xa4, 0xcb, 0x6c,
+ 0xe2, 0x27, 0x58, 0x64, 0xe6, 0x97, 0x6c, 0x7b, 0x02, 0xc5, 0xff, 0xb0,
+ 0xb3, 0xda, 0x63, 0x7e, 0x25, 0x8b, 0x1d, 0x62, 0xff, 0x84, 0xfd, 0xeb,
+ 0x42, 0x9b, 0x8b, 0x15, 0x23, 0xcf, 0xe0, 0x95, 0xc7, 0xed, 0x62, 0xfe,
+ 0xcf, 0x14, 0x41, 0xd6, 0x2f, 0xee, 0xc0, 0x1e, 0x9c, 0x0b, 0x17, 0x7f,
+ 0x64, 0x2a, 0x9a, 0x40, 0xc8, 0xb2, 0x11, 0xc7, 0x22, 0xf8, 0xcb, 0x96,
+ 0x56, 0xc4, 0xd9, 0x78, 0xc4, 0x69, 0xb2, 0xa5, 0x3e, 0xe4, 0xb0, 0xc6,
+ 0x53, 0xd2, 0x4f, 0x21, 0x2f, 0xe3, 0x6d, 0xf0, 0xc5, 0x0e, 0x37, 0xfb,
+ 0xfb, 0x35, 0xd3, 0xbf, 0x4a, 0x88, 0x74, 0xbf, 0xd9, 0xce, 0x40, 0x03,
+ 0x9d, 0x62, 0xff, 0xdf, 0xc2, 0x27, 0xf7, 0xe4, 0xcb, 0x17, 0xf6, 0xbe,
+ 0x63, 0x8f, 0x64, 0x67, 0xe7, 0xe3, 0x6a, 0xd9, 0x47, 0xc3, 0xc2, 0xbe,
+ 0xfd, 0xae, 0x9d, 0xfa, 0x54, 0x4b, 0x05, 0xf6, 0x00, 0xec, 0xb1, 0x7e,
+ 0xd9, 0x3b, 0xcb, 0x67, 0x0f, 0x67, 0x70, 0xde, 0xff, 0x6c, 0xe6, 0xba,
+ 0x77, 0xe9, 0x51, 0x18, 0x17, 0x8c, 0x83, 0xac, 0x5e, 0xc2, 0xe9, 0x62,
+ 0xf4, 0x98, 0x6b, 0x17, 0xb5, 0x1d, 0xac, 0x5f, 0xa5, 0x9c, 0x7e, 0x2c,
+ 0x5e, 0xc2, 0x1a, 0xc5, 0xff, 0xdb, 0x8e, 0x40, 0xcf, 0x41, 0x30, 0x16,
+ 0x2d, 0xb3, 0x88, 0xff, 0xe8, 0x7a, 0x61, 0xd7, 0x1d, 0x10, 0xf1, 0x85,
+ 0x01, 0x8e, 0x5f, 0xff, 0x9c, 0x1b, 0x99, 0xb2, 0x4f, 0xe9, 0x67, 0xb0,
+ 0x6b, 0x17, 0xff, 0xe6, 0x3b, 0x6b, 0x67, 0xdb, 0x99, 0xff, 0x47, 0x66,
+ 0x2c, 0x51, 0x26, 0x4f, 0xc6, 0xff, 0x2d, 0x5d, 0x9c, 0x58, 0xb0, 0x45,
+ 0x8b, 0x6c, 0xc8, 0xd5, 0xcc, 0x2f, 0x7b, 0xcd, 0x32, 0xc5, 0xff, 0xff,
+ 0xff, 0x41, 0x08, 0xfa, 0x8f, 0x37, 0x4c, 0x3f, 0xc7, 0x5f, 0x89, 0xce,
+ 0xde, 0x79, 0x9f, 0xcb, 0x17, 0xcc, 0x4e, 0x05, 0x8b, 0xd8, 0x66, 0xcf,
+ 0x68, 0xb7, 0xe4, 0x25, 0xaf, 0xee, 0x4f, 0xfc, 0x03, 0xac, 0x5f, 0xff,
+ 0xf4, 0xb9, 0xb3, 0xd7, 0xde, 0x6e, 0xbf, 0x9a, 0x0a, 0x7e, 0x63, 0xf1,
+ 0x62, 0xfa, 0x3e, 0x2f, 0x2c, 0x5f, 0xb3, 0xc0, 0x8e, 0x96, 0x2f, 0xff,
+ 0x47, 0x98, 0x11, 0x21, 0xfe, 0x0b, 0xa5, 0x8b, 0xee, 0xe4, 0xe4, 0xb1,
+ 0x78, 0xed, 0xc5, 0x8b, 0x41, 0xcf, 0x00, 0x04, 0x77, 0xfe, 0x6d, 0x4e,
+ 0x20, 0x61, 0x06, 0x75, 0x8b, 0xe6, 0x20, 0x32, 0xc5, 0xf7, 0x4e, 0xfd,
+ 0x2a, 0x23, 0xd2, 0xa4, 0x7a, 0x5a, 0x21, 0xbf, 0xfd, 0xba, 0x50, 0xe3,
+ 0x6e, 0x1e, 0x06, 0x05, 0x8b, 0xee, 0x3f, 0x7b, 0xd6, 0x2d, 0xb3, 0x24,
+ 0xc9, 0xf2, 0x12, 0x6e, 0x45, 0xe4, 0xcb, 0xff, 0xff, 0x6c, 0xcf, 0x13,
+ 0x31, 0x37, 0x4f, 0xf7, 0x33, 0x68, 0xc8, 0x03, 0x58, 0xa9, 0x22, 0xfb,
+ 0xa4, 0xab, 0xfe, 0xe9, 0xf4, 0xff, 0x9b, 0x3c, 0xb1, 0x7f, 0xf8, 0x59,
+ 0xfc, 0x20, 0x61, 0x7b, 0xf8, 0xb1, 0x7a, 0x35, 0x32, 0xc5, 0xcf, 0xb2,
+ 0xc8, 0xa1, 0x23, 0xbe, 0x24, 0x5f, 0xff, 0x47, 0x73, 0x4a, 0x35, 0x3e,
+ 0xb4, 0xde, 0xe2, 0xc5, 0xff, 0xfe, 0x3e, 0xcb, 0x98, 0xf3, 0xb1, 0x8e,
+ 0x1b, 0x17, 0xa3, 0x8b, 0x15, 0x0b, 0xca, 0x93, 0xc3, 0x54, 0x67, 0xdd,
+ 0x97, 0xb3, 0xac, 0xc4, 0x7a, 0x29, 0xfc, 0x22, 0x9e, 0x50, 0x61, 0x43,
+ 0x17, 0xc7, 0x81, 0xaa, 0x5f, 0xec, 0xe7, 0x20, 0x01, 0xce, 0xb1, 0x7f,
+ 0xff, 0x87, 0x0f, 0xaf, 0x98, 0xe3, 0xf7, 0xf0, 0x89, 0xfc, 0xb1, 0x6d,
+ 0x91, 0xa2, 0x5b, 0x86, 0xd5, 0xb2, 0x9c, 0x04, 0xf1, 0xaa, 0x5f, 0xf8,
+ 0x20, 0x9c, 0x7b, 0x8d, 0xcc, 0x9d, 0x62, 0xf7, 0x04, 0x05, 0x8b, 0xde,
+ 0x7e, 0x96, 0x2e, 0x04, 0x2c, 0x5f, 0xf1, 0x46, 0xd0, 0x1c, 0x3d, 0x3a,
+ 0xc5, 0x31, 0xe9, 0xf8, 0x5e, 0xf8, 0x9c, 0xcd, 0x9c, 0x47, 0xaf, 0x68,
+ 0xae, 0x3d, 0xc7, 0x1b, 0xf6, 0xba, 0x77, 0xe9, 0x51, 0x61, 0x97, 0xfa,
+ 0x45, 0x19, 0xcc, 0x25, 0x8b, 0x9a, 0x4b, 0x16, 0xd9, 0xc3, 0xff, 0xec,
+ 0xdc, 0x06, 0x37, 0xdb, 0x20, 0x2c, 0x58, 0xbc, 0xff, 0xe2, 0xc5, 0xdd,
+ 0xf9, 0x62, 0xfe, 0x14, 0xec, 0x42, 0x3a, 0xc5, 0x41, 0xe4, 0x10, 0xcd,
+ 0xf4, 0x6e, 0xc4, 0xcb, 0x17, 0xa0, 0xa7, 0x58, 0xb4, 0x2c, 0x5f, 0x40,
+ 0x24, 0x75, 0x8a, 0xf9, 0xb4, 0x21, 0x1a, 0x1a, 0x63, 0x8c, 0xcb, 0x31,
+ 0x07, 0xc9, 0xbc, 0xa3, 0x7f, 0xff, 0xd1, 0x1c, 0xd9, 0xf0, 0xd8, 0xfd,
+ 0xcb, 0x9d, 0xcb, 0x35, 0x3a, 0xc5, 0x6c, 0xa2, 0xe4, 0x92, 0xed, 0x13,
+ 0xaa, 0x1f, 0xd4, 0x7f, 0x57, 0xfb, 0x67, 0x35, 0xd3, 0xbf, 0x4a, 0x8b,
+ 0x9c, 0xbb, 0xfb, 0xd6, 0x2f, 0xf7, 0x04, 0xfd, 0xfb, 0xec, 0xb1, 0x7a,
+ 0x42, 0x1a, 0xc5, 0xce, 0x75, 0x8b, 0xe6, 0xd6, 0x9d, 0x62, 0xfb, 0x90,
+ 0x46, 0xac, 0x56, 0x1e, 0x28, 0x64, 0x57, 0xff, 0xed, 0x31, 0xe0, 0xdf,
+ 0xbf, 0x00, 0x77, 0xef, 0xcb, 0x17, 0x8a, 0x3b, 0x58, 0xbe, 0x7d, 0x4b,
+ 0x64, 0x69, 0xb0, 0x60, 0xd7, 0x66, 0xa4, 0x3d, 0xc5, 0xc0, 0xc8, 0x82,
+ 0x2c, 0x5f, 0xff, 0xff, 0xfd, 0x1b, 0x0a, 0x53, 0xf5, 0xfd, 0xbb, 0x7f,
+ 0xb9, 0xb3, 0x38, 0x8d, 0x0b, 0x78, 0x0a, 0xf7, 0x3c, 0xfd, 0x1f, 0x6e,
+ 0xdf, 0xee, 0x2c, 0x54, 0x36, 0x60, 0xb3, 0xc2, 0x0e, 0x48, 0xf9, 0x29,
+ 0xaf, 0xa5, 0xb6, 0x9f, 0xff, 0xd4, 0x64, 0x67, 0x86, 0xaf, 0xe5, 0x2b,
+ 0xf8, 0xc4, 0x51, 0xd2, 0x84, 0x84, 0x0d, 0xff, 0x70, 0xf9, 0xb6, 0x58,
+ 0x38, 0x58, 0xbf, 0x6b, 0xa7, 0x7e, 0x95, 0x10, 0xf1, 0x7f, 0xfb, 0xed,
+ 0x07, 0x71, 0x86, 0x12, 0x0a, 0x4b, 0x16, 0xd9, 0x84, 0x5f, 0x61, 0xdf,
+ 0x0d, 0xee, 0x0a, 0x85, 0xba, 0xc5, 0xff, 0x47, 0xe2, 0x7d, 0x46, 0x0d,
+ 0x62, 0xff, 0xf7, 0x30, 0xa2, 0x5f, 0xcf, 0xb6, 0x12, 0xc5, 0xff, 0xb4,
+ 0xdc, 0x81, 0xb9, 0x31, 0xd6, 0x2b, 0xe8, 0xbd, 0xe1, 0xce, 0xf4, 0x7b,
+ 0xde, 0xe8, 0x0b, 0x17, 0xfb, 0x50, 0xde, 0x28, 0x3a, 0xc5, 0xfe, 0x17,
+ 0x36, 0x8c, 0x9f, 0xeb, 0x17, 0xff, 0xf6, 0x0d, 0xb9, 0x85, 0xce, 0xbe,
+ 0xc4, 0x59, 0xda, 0xc5, 0xff, 0xfe, 0x73, 0x66, 0xe4, 0x7b, 0x68, 0x7e,
+ 0x62, 0x14, 0xb3, 0x8b, 0x15, 0xf4, 0x60, 0x12, 0xd5, 0xf9, 0xb4, 0xfe,
+ 0x0b, 0x75, 0x8b, 0xff, 0xff, 0xef, 0xe6, 0xb5, 0x1d, 0xc8, 0x3f, 0x31,
+ 0x0a, 0x59, 0xc2, 0xc9, 0xc3, 0x92, 0xc5, 0xff, 0xf8, 0xb3, 0x8c, 0xf3,
+ 0xe0, 0xce, 0xdb, 0x90, 0x75, 0x8b, 0xee, 0x9d, 0xfa, 0x54, 0x44, 0xc5,
+ 0xfb, 0x1b, 0xda, 0x12, 0xc5, 0xf6, 0xef, 0xe0, 0xd5, 0x8b, 0xff, 0xfd,
+ 0xa2, 0xc9, 0xf0, 0x78, 0x60, 0xb5, 0x9d, 0x7e, 0x37, 0xac, 0x5d, 0x93,
+ 0xac, 0x5f, 0x08, 0xf8, 0x35, 0x8a, 0x84, 0x50, 0x76, 0xca, 0x10, 0x62,
+ 0xfd, 0xee, 0x4f, 0x86, 0x2c, 0x5f, 0xf7, 0x84, 0x6e, 0xdf, 0xe0, 0x1d,
+ 0x62, 0xb1, 0x13, 0x4e, 0x64, 0x22, 0xbb, 0x09, 0x62, 0xff, 0x78, 0x4f,
+ 0xdf, 0xe3, 0x7a, 0xc5, 0x49, 0x5a, 0xd1, 0xa4, 0x5d, 0x17, 0xb4, 0x20,
+ 0x74, 0xae, 0x73, 0x17, 0x28, 0x28, 0xd8, 0x78, 0x5d, 0xe1, 0x2b, 0xfe,
+ 0x77, 0x20, 0x69, 0xa0, 0xd5, 0x8b, 0xff, 0xff, 0xff, 0xe0, 0x67, 0x1f,
+ 0x77, 0x6f, 0xbe, 0xd1, 0xcd, 0xb9, 0xad, 0x67, 0xcb, 0x3d, 0x07, 0xdb,
+ 0x9a, 0x79, 0x62, 0xc5, 0xc2, 0x9d, 0x62, 0xd8, 0xb1, 0x73, 0x05, 0xd6,
+ 0x28, 0x8f, 0x17, 0x78, 0xc9, 0x82, 0x37, 0xff, 0xbe, 0x19, 0x47, 0x7f,
+ 0xc1, 0x89, 0xfa, 0x58, 0xbf, 0x8e, 0x19, 0x16, 0x4e, 0xb1, 0x7e, 0x33,
+ 0x59, 0xfe, 0x2c, 0x54, 0x1e, 0xce, 0x17, 0xd4, 0x91, 0x8c, 0x50, 0xa6,
+ 0xbf, 0xbc, 0x51, 0xd3, 0x12, 0xc5, 0xf8, 0xa3, 0xa6, 0x25, 0x8b, 0xf4,
+ 0x77, 0x26, 0x3e, 0xd3, 0xd4, 0xf1, 0x6d, 0xf8, 0x1c, 0xdb, 0x83, 0x58,
+ 0xbf, 0xcc, 0x66, 0x16, 0x77, 0xe5, 0x8a, 0xc4, 0x50, 0x32, 0x0e, 0x8a,
+ 0xee, 0xc0, 0x8b, 0x17, 0xba, 0x61, 0xac, 0x5c, 0x43, 0xc3, 0x6e, 0xc3,
+ 0x37, 0xb9, 0x83, 0x58, 0xa7, 0x3c, 0x7f, 0x15, 0x5f, 0x9b, 0x69, 0xfa,
+ 0x99, 0x62, 0x9c, 0xf3, 0x88, 0x86, 0xff, 0xc7, 0xf8, 0xba, 0xdb, 0x9f,
+ 0x7d, 0x2c, 0x5f, 0xfd, 0xee, 0x72, 0x1b, 0xbf, 0x7a, 0x0e, 0xb1, 0x7f,
+ 0xd1, 0xf8, 0xde, 0x78, 0x29, 0xd6, 0x2f, 0xfe, 0x17, 0xb8, 0x42, 0x17,
+ 0xa5, 0x06, 0xac, 0x5e, 0xe3, 0x92, 0xc5, 0xff, 0xfa, 0x34, 0x0f, 0xc6,
+ 0xf9, 0xa2, 0x0f, 0xcc, 0x1a, 0xc5, 0xff, 0x7f, 0xf1, 0xbe, 0x59, 0xa8,
+ 0x58, 0xbf, 0xd1, 0x13, 0x66, 0xf6, 0xd2, 0xc5, 0x7d, 0x19, 0x0e, 0xb0,
+ 0x47, 0x77, 0xff, 0x09, 0xe7, 0x2c, 0x39, 0xdb, 0x5c, 0x58, 0xac, 0x54,
+ 0x3f, 0x32, 0x31, 0x1d, 0xf1, 0x1f, 0xd0, 0xe4, 0x30, 0xba, 0xff, 0x13,
+ 0x80, 0x9e, 0x44, 0xb1, 0x7e, 0xf6, 0x02, 0x34, 0xb1, 0x73, 0x7a, 0x0f,
+ 0x65, 0x8c, 0x6f, 0xa7, 0xf8, 0xa7, 0x58, 0xa8, 0x56, 0xd5, 0x92, 0x98,
+ 0x9e, 0x16, 0xe2, 0x2b, 0xbe, 0x9c, 0xf1, 0xa5, 0x8b, 0xee, 0x84, 0x46,
+ 0xac, 0x5c, 0xee, 0xb1, 0x4e, 0x7b, 0xe4, 0x48, 0x19, 0x2d, 0xff, 0x9f,
+ 0xbe, 0x4d, 0xba, 0xc5, 0xee, 0x2c, 0x5c, 0x3f, 0xac, 0x5f, 0xfe, 0xf4,
+ 0xb3, 0x5a, 0x79, 0x61, 0xe3, 0xa5, 0x8b, 0xff, 0xd8, 0xf2, 0x10, 0xf1,
+ 0x9f, 0x7c, 0x69, 0x62, 0xb1, 0x15, 0xae, 0x30, 0x24, 0xbb, 0xfd, 0xa8,
+ 0xfb, 0x8e, 0x47, 0x58, 0xbf, 0xef, 0x0b, 0xf0, 0x3f, 0xb0, 0x16, 0x2f,
+ 0xfa, 0x25, 0x8c, 0x59, 0x06, 0xac, 0x5f, 0xff, 0xbf, 0x1a, 0x07, 0x30,
+ 0x7e, 0x13, 0xf5, 0x9a, 0x58, 0xad, 0xd4, 0x64, 0x4c, 0x75, 0xe3, 0x7b,
+ 0xbc, 0x75, 0x8b, 0xdb, 0x8f, 0xa5, 0x8b, 0xfe, 0xd4, 0x78, 0x7f, 0x13,
+ 0xf1, 0x62, 0xff, 0xb3, 0x9c, 0x11, 0x4e, 0x6c, 0xcb, 0x17, 0xec, 0x39,
+ 0xe0, 0x6b, 0x17, 0xfe, 0x0e, 0x7e, 0x43, 0x77, 0xe8, 0x3a, 0xc5, 0xff,
+ 0xdc, 0x77, 0xeb, 0x3a, 0x82, 0x8e, 0x96, 0x2d, 0x93, 0x22, 0xbf, 0xe5,
+ 0x1c, 0x42, 0xbd, 0x1a, 0xe2, 0xc5, 0xfe, 0x94, 0x7f, 0x33, 0xdc, 0x58,
+ 0xbf, 0xf1, 0x67, 0x3a, 0xfb, 0x04, 0x6e, 0x2c, 0x5b, 0x26, 0x3f, 0x4d,
+ 0xe6, 0x77, 0xfd, 0x12, 0x0f, 0x35, 0xcc, 0x31, 0x62, 0xff, 0x4a, 0x0d,
+ 0x6f, 0xbc, 0xeb, 0x17, 0xfc, 0x01, 0x94, 0x4b, 0xfc, 0x02, 0xc5, 0x4e,
+ 0x8a, 0xa6, 0x3b, 0xd1, 0xad, 0xe2, 0x10, 0xd6, 0x28, 0x6b, 0x8e, 0xd9,
+ 0x0f, 0xce, 0xcd, 0x18, 0x62, 0x62, 0x0d, 0x1d, 0x7e, 0x1d, 0x80, 0x36,
+ 0x28, 0x48, 0x8a, 0x1a, 0x81, 0x98, 0x5f, 0x89, 0xd8, 0x80, 0xb1, 0x7e,
+ 0x30, 0x51, 0xa9, 0xd6, 0x2b, 0x69, 0xe8, 0x98, 0x4d, 0x7f, 0xf3, 0x38,
+ 0x35, 0x05, 0xef, 0xe4, 0x96, 0x2f, 0xf6, 0xb2, 0x3b, 0x93, 0x1d, 0x62,
+ 0xfe, 0xc8, 0xee, 0x4c, 0x75, 0x8b, 0xe8, 0xe9, 0x8b, 0x69, 0xf1, 0x68,
+ 0xd2, 0xf9, 0xdb, 0x58, 0xb1, 0x7f, 0xbe, 0xc7, 0xf7, 0x1b, 0x4b, 0x14,
+ 0xc9, 0xac, 0xfc, 0x94, 0xa1, 0x4b, 0xe3, 0xa1, 0x10, 0xdc, 0xc7, 0x58,
+ 0xbe, 0x97, 0xc3, 0xe2, 0xc5, 0xce, 0x1a, 0xa2, 0x17, 0x2b, 0xb3, 0xca,
+ 0x11, 0x2d, 0x4c, 0x88, 0x4f, 0x30, 0xdf, 0xbf, 0x93, 0x88, 0x96, 0x2f,
+ 0x9f, 0x51, 0xbd, 0x62, 0x86, 0x79, 0xa0, 0x29, 0xbf, 0xbe, 0xe5, 0xec,
+ 0xfa, 0xc5, 0xf4, 0xb1, 0xc9, 0x62, 0xff, 0x4f, 0x92, 0x21, 0x3f, 0x16,
+ 0x29, 0x91, 0x05, 0x31, 0x6b, 0x90, 0xde, 0x83, 0xc9, 0x62, 0xf1, 0x08,
+ 0xd5, 0x8b, 0xef, 0x98, 0xf3, 0xac, 0x57, 0x67, 0xc0, 0x43, 0xbe, 0x1e,
+ 0xbe, 0xfb, 0x44, 0xcb, 0x16, 0xd9, 0x0a, 0xb7, 0x33, 0x31, 0x0e, 0x09,
+ 0xcc, 0xa4, 0x3e, 0x33, 0x2c, 0x9c, 0x50, 0x36, 0x12, 0xfd, 0x9c, 0x34,
+ 0x3d, 0xa6, 0x87, 0xbe, 0xa3, 0x1b, 0x3c, 0x3e, 0xbf, 0x2e, 0x29, 0xe1,
+ 0x4e, 0x02, 0xe2, 0x87, 0x8f, 0x27, 0x29, 0x3d, 0x29, 0x64, 0x50, 0xd2,
+ 0xde, 0xe3, 0xb9, 0x0a, 0x40, 0xe1, 0x1e, 0x10, 0xbe, 0xfd, 0x9a, 0xe3,
+ 0x42, 0xc5, 0xe0, 0xb5, 0xb0, 0xf6, 0x25, 0x8b, 0xff, 0x68, 0x53, 0xe7,
+ 0xe6, 0x28, 0x1a, 0xc5, 0xfe, 0xea, 0x3f, 0x07, 0xf8, 0x96, 0x2f, 0x46,
+ 0x1a, 0xb1, 0x58, 0x7a, 0x44, 0x6b, 0x7c, 0xf2, 0xfe, 0x2c, 0x5f, 0xdf,
+ 0xcc, 0xf7, 0xf1, 0x62, 0x86, 0x79, 0xfe, 0x22, 0xbe, 0x7e, 0xc7, 0xda,
+ 0xc5, 0xfb, 0x9f, 0x8e, 0xf8, 0xb1, 0x6f, 0xc1, 0xe7, 0xb1, 0x2d, 0xe3,
+ 0x75, 0xda, 0xc5, 0xf6, 0x1c, 0x47, 0x58, 0xbf, 0xda, 0x82, 0xc1, 0x8e,
+ 0x16, 0x2f, 0xfc, 0xe4, 0x6b, 0xfa, 0x3c, 0xe0, 0x58, 0xbe, 0x18, 0x70,
+ 0x4b, 0x17, 0x85, 0xa9, 0x2c, 0x5f, 0xff, 0xbc, 0x2d, 0x3f, 0x30, 0xbf,
+ 0x98, 0x52, 0xe2, 0xc5, 0x4e, 0x7e, 0x4c, 0x3d, 0x50, 0x8b, 0x77, 0x84,
+ 0xad, 0x2c, 0x5f, 0x9f, 0x3d, 0x87, 0x58, 0xb8, 0x11, 0x06, 0xcc, 0x83,
+ 0x2f, 0xc2, 0xd0, 0x36, 0xc2, 0xc5, 0xdf, 0x75, 0x8b, 0xff, 0xe9, 0xe7,
+ 0x82, 0xcf, 0x37, 0x66, 0x67, 0x7e, 0x58, 0xb9, 0x8d, 0x58, 0xb0, 0x96,
+ 0x2b, 0x11, 0x2a, 0xc2, 0xf3, 0x2a, 0x70, 0x62, 0xfb, 0x9f, 0x80, 0x2c,
+ 0x5f, 0xed, 0x00, 0xef, 0x2d, 0xbe, 0x58, 0xb6, 0xea, 0xc5, 0x61, 0xe6,
+ 0x1a, 0x6f, 0x7d, 0xe8, 0x2d, 0xeb, 0x17, 0xa3, 0x3b, 0x58, 0xa5, 0x8a,
+ 0x23, 0x53, 0xe1, 0xdb, 0xff, 0xa3, 0x51, 0xd4, 0x30, 0x1f, 0xc2, 0x58,
+ 0xaf, 0xa2, 0xc7, 0xc9, 0xbb, 0x84, 0x17, 0x81, 0xcd, 0x9d, 0x81, 0x79,
+ 0x34, 0x2d, 0xc9, 0xe0, 0xbc, 0x70, 0x93, 0xc6, 0xfe, 0x9c, 0x7b, 0x26,
+ 0x62, 0x0d, 0x11, 0x9c, 0xcb, 0xf0, 0xf5, 0x02, 0xcf, 0x0a, 0xbd, 0x0c,
+ 0x01, 0x1e, 0x6e, 0x37, 0x87, 0x0d, 0x3b, 0x9b, 0x75, 0x62, 0xf3, 0x3c,
+ 0x96, 0x2e, 0x1e, 0xce, 0x1b, 0x6f, 0x8d, 0x5f, 0xfe, 0x69, 0x73, 0x67,
+ 0x3b, 0x93, 0xce, 0x1f, 0x4b, 0x15, 0x08, 0x81, 0xc2, 0xfa, 0x84, 0xfe,
+ 0x7f, 0x1e, 0xc5, 0xff, 0x6c, 0x61, 0x5d, 0x67, 0x9b, 0xe2, 0x58, 0xbe,
+ 0xe3, 0x4e, 0x15, 0x58, 0xbf, 0x08, 0x89, 0xa4, 0xb1, 0x5b, 0x1a, 0x24,
+ 0x82, 0x88, 0x7c, 0x28, 0xbf, 0xf6, 0xc6, 0x15, 0x69, 0xe3, 0x6f, 0x5c,
+ 0xc5, 0x8b, 0x82, 0xc2, 0x58, 0xbd, 0xfc, 0xd2, 0xc5, 0x6c, 0x68, 0x85,
+ 0x0a, 0x26, 0x7c, 0x72, 0xff, 0xd9, 0x22, 0x73, 0x66, 0xe4, 0x79, 0x62,
+ 0xfb, 0xcd, 0xac, 0x58, 0xad, 0x84, 0x7c, 0x58, 0x81, 0x7f, 0xd9, 0xe0,
+ 0xe7, 0x7d, 0x34, 0xcb, 0x17, 0xf4, 0x82, 0xc9, 0xc2, 0xa1, 0x6f, 0xb0,
+ 0xd6, 0x2f, 0x16, 0x7d, 0x62, 0xfe, 0x63, 0xe4, 0x68, 0xd5, 0x8a, 0x19,
+ 0xe5, 0x74, 0x39, 0x78, 0x2d, 0x6c, 0x2d, 0x81, 0x62, 0xff, 0x67, 0x39,
+ 0x8c, 0x5d, 0x2c, 0x50, 0x51, 0x37, 0x90, 0xa9, 0x3e, 0xc0, 0x79, 0xb1,
+ 0x42, 0x44, 0x2d, 0xc8, 0xc8, 0xbe, 0xf6, 0x9f, 0x8b, 0x17, 0xf6, 0xc6,
+ 0x1f, 0xff, 0x93, 0xac, 0x5d, 0xb9, 0xda, 0xc5, 0xbe, 0xb1, 0x5b, 0x51,
+ 0x03, 0xb1, 0x8e, 0xec, 0x23, 0x61, 0x0e, 0x5f, 0xf0, 0x57, 0x98, 0x45,
+ 0x8f, 0xd2, 0xc5, 0x9d, 0x62, 0xb6, 0x33, 0xcd, 0xec, 0xf2, 0xe3, 0x61,
+ 0x62, 0xf4, 0xdc, 0x85, 0x8b, 0xe1, 0xe1, 0x4c, 0xb1, 0x73, 0x79, 0x62,
+ 0x98, 0xdd, 0x7c, 0x8e, 0x8e, 0x7f, 0x1e, 0x58, 0xbf, 0xdd, 0xfb, 0xb9,
+ 0x08, 0x8d, 0x58, 0xbf, 0xf4, 0x4c, 0x59, 0xbd, 0xce, 0x76, 0x58, 0xa7,
+ 0x3f, 0x81, 0x1c, 0x5f, 0x80, 0x07, 0xef, 0x8b, 0x17, 0xff, 0xfc, 0x36,
+ 0xcd, 0x4c, 0x59, 0xbf, 0xf8, 0x38, 0xe7, 0x20, 0xd5, 0x8b, 0x7d, 0x91,
+ 0x26, 0x22, 0xab, 0xff, 0xcd, 0x34, 0xb3, 0xb9, 0x6d, 0x3b, 0xb9, 0x2c,
+ 0x5c, 0xe1, 0x16, 0x2f, 0xff, 0xf7, 0x33, 0xdb, 0x7f, 0x9d, 0x41, 0x85,
+ 0x83, 0xfb, 0x4c, 0xb1, 0x53, 0xaa, 0xd1, 0xc8, 0x48, 0x1b, 0x09, 0xae,
+ 0xa1, 0x69, 0xf2, 0x87, 0x4d, 0xf0, 0xcd, 0x05, 0x15, 0xb7, 0x85, 0x65,
+ 0x7c, 0xde, 0x0a, 0x11, 0x2c, 0x5f, 0xb6, 0x30, 0xa8, 0xbc, 0xcb, 0x17,
+ 0xfb, 0xb8, 0xf6, 0x67, 0x72, 0x58, 0xbf, 0xb1, 0xbc, 0x51, 0xda, 0xc5,
+ 0x8d, 0x58, 0xad, 0x8d, 0x18, 0xe1, 0x42, 0x00, 0xb0, 0xc8, 0x2d, 0xcd,
+ 0x77, 0x0b, 0x6e, 0x9f, 0xeb, 0x17, 0x6e, 0x6c, 0x6b, 0x17, 0xb5, 0xce,
+ 0x2c, 0x5c, 0x5c, 0x58, 0xa0, 0xa9, 0xb5, 0xde, 0x3d, 0x78, 0xf1, 0xd2,
+ 0xc5, 0x05, 0x11, 0x35, 0xb1, 0x2a, 0xe1, 0x3d, 0xfd, 0xb0, 0x41, 0x8f,
+ 0xd4, 0x2c, 0x5f, 0xc1, 0x6e, 0x14, 0x2d, 0xc8, 0x3a, 0xc5, 0x6c, 0x07,
+ 0xe0, 0x16, 0xe6, 0x97, 0xff, 0xe1, 0xed, 0xce, 0x14, 0xf3, 0xbe, 0xee,
+ 0xdd, 0xbf, 0xdc, 0x58, 0xbf, 0x9c, 0xa7, 0xfc, 0x6e, 0xac, 0x5e, 0x38,
+ 0x7c, 0x58, 0xbd, 0x28, 0x02, 0xc5, 0x0c, 0xfb, 0x70, 0xc5, 0xc7, 0xef,
+ 0xdf, 0x7f, 0x3c, 0x96, 0x2f, 0xf0, 0x57, 0x6f, 0x00, 0x7c, 0xe2, 0xc5,
+ 0xf1, 0x66, 0x69, 0x62, 0xef, 0xba, 0xc5, 0x9b, 0x46, 0xe3, 0x79, 0x0d,
+ 0xee, 0xa7, 0xfa, 0xc5, 0xff, 0x03, 0x6f, 0x21, 0xa7, 0x7f, 0x2c, 0x5f,
+ 0xa3, 0x81, 0x6b, 0x63, 0xd8, 0xd6, 0x2e, 0x39, 0xd6, 0x29, 0x91, 0x1b,
+ 0xc3, 0xc1, 0x1c, 0xdf, 0xa3, 0x82, 0xfb, 0x2c, 0x56, 0xd4, 0xc1, 0x25,
+ 0x0a, 0xde, 0x17, 0xd2, 0xc5, 0xfa, 0x4f, 0xa7, 0xe9, 0x62, 0xe6, 0x99,
+ 0x62, 0xa0, 0xf0, 0x70, 0xa6, 0xff, 0x16, 0x77, 0x22, 0x79, 0xd6, 0x2b,
+ 0x47, 0xa9, 0xc2, 0x0b, 0xf7, 0x04, 0xe4, 0x05, 0x8a, 0xda, 0x79, 0x5e,
+ 0x22, 0xbf, 0x8b, 0x37, 0x96, 0x71, 0x62, 0x8e, 0x7a, 0x40, 0x24, 0xbd,
+ 0xc6, 0x02, 0xc5, 0xf3, 0x14, 0x71, 0x62, 0xb0, 0xf8, 0x18, 0x8b, 0xe3,
+ 0xb7, 0x8c, 0x30, 0xc4, 0x8b, 0xde, 0xfe, 0x24, 0x6c, 0x9a, 0x1b, 0xf3,
+ 0x1a, 0xe4, 0x05, 0x8b, 0x39, 0x1e, 0xc7, 0x8c, 0x2f, 0xff, 0xfe, 0x89,
+ 0xf6, 0xf0, 0x51, 0xdf, 0xbf, 0x87, 0xcf, 0x14, 0x00, 0x10, 0xb1, 0x76,
+ 0xe6, 0x2c, 0x5f, 0x7a, 0x6c, 0xf2, 0xc5, 0x86, 0xb1, 0x60, 0x8b, 0x14,
+ 0x34, 0x6c, 0xe3, 0xab, 0x8d, 0x08, 0x90, 0x31, 0x2a, 0x85, 0x71, 0x63,
+ 0x8e, 0x74, 0x10, 0xa6, 0x28, 0x7f, 0xdf, 0xbe, 0x5b, 0x0f, 0x70, 0x22,
+ 0xc5, 0xce, 0xeb, 0x16, 0xfb, 0x1e, 0x53, 0x9a, 0x5f, 0xff, 0xc0, 0xd4,
+ 0x6d, 0xd4, 0x7b, 0xb9, 0x41, 0xba, 0x73, 0x16, 0x2f, 0x83, 0xe3, 0x81,
+ 0x62, 0xe9, 0xbe, 0xb1, 0x7f, 0xe3, 0xed, 0xc6, 0xd3, 0x1e, 0x0d, 0x58,
+ 0xa6, 0x3d, 0xa7, 0x19, 0xbf, 0xf3, 0x4d, 0xb7, 0xf0, 0xda, 0x16, 0xea,
+ 0xc5, 0x42, 0x68, 0x9a, 0x61, 0xfb, 0xf0, 0x08, 0x2f, 0xff, 0xdd, 0x7c,
+ 0x85, 0xed, 0xa5, 0x81, 0x3c, 0xd8, 0x11, 0x62, 0xe1, 0x7d, 0x62, 0xf7,
+ 0x85, 0xba, 0xb1, 0x7c, 0x13, 0x5c, 0xe2, 0xc5, 0x61, 0xe3, 0xb1, 0x0d,
+ 0xee, 0x64, 0xeb, 0x15, 0x08, 0xf9, 0x35, 0x73, 0x4b, 0xee, 0x41, 0x7f,
+ 0xf6, 0x17, 0x7e, 0xdb, 0xc0, 0x1f, 0x38, 0xb1, 0x7e, 0x17, 0x9a, 0x78,
+ 0x58, 0xac, 0x3f, 0x12, 0x48, 0xbf, 0xdf, 0x89, 0xf5, 0x18, 0x35, 0x8b,
+ 0xf3, 0x73, 0xd9, 0xf5, 0x8b, 0xfd, 0x05, 0x1c, 0x86, 0x3a, 0xc5, 0xe7,
+ 0xf7, 0x16, 0x28, 0xd3, 0xce, 0xd1, 0x8d, 0xe0, 0x83, 0x85, 0x8a, 0x84,
+ 0x76, 0x74, 0x68, 0xce, 0xc2, 0x23, 0xbd, 0xf7, 0x0b, 0xac, 0x5f, 0xb7,
+ 0x8a, 0x59, 0xc5, 0x8b, 0xe0, 0x31, 0x09, 0x62, 0xb0, 0xf3, 0x44, 0x57,
+ 0x78, 0x79, 0x3a, 0xc5, 0xed, 0xf1, 0xa5, 0x8a, 0xc3, 0x7a, 0xc3, 0xd7,
+ 0xdb, 0xbb, 0x60, 0x28, 0xb1, 0x7f, 0x8a, 0x37, 0x30, 0x98, 0xd5, 0x8b,
+ 0xfd, 0xe7, 0xef, 0x8f, 0xd9, 0x8b, 0x16, 0x85, 0x8b, 0xcd, 0x04, 0xb1,
+ 0x5a, 0x35, 0x9e, 0x11, 0xa0, 0xa3, 0x36, 0x14, 0x70, 0xd2, 0xc2, 0xd3,
+ 0x4a, 0x3a, 0x73, 0xee, 0x32, 0xc6, 0x97, 0x87, 0xbb, 0x09, 0x79, 0xa3,
+ 0x6a, 0xd4, 0x66, 0xc7, 0x85, 0x6f, 0xe3, 0x0c, 0x0b, 0x9e, 0x13, 0x77,
+ 0x97, 0xb7, 0x8f, 0xee, 0x16, 0x06, 0x6a, 0x11, 0x8e, 0xf1, 0xda, 0x4b,
+ 0x17, 0xed, 0x66, 0xf8, 0xed, 0x62, 0xf1, 0x67, 0x96, 0x2f, 0xff, 0x77,
+ 0x2e, 0x72, 0x1b, 0xbf, 0x7a, 0x0e, 0xb1, 0x5a, 0x44, 0xa1, 0x15, 0x98,
+ 0x39, 0x7f, 0xe9, 0xf0, 0xa0, 0xcf, 0x1a, 0xfc, 0x58, 0xbf, 0xd9, 0xbd,
+ 0xdb, 0xac, 0x25, 0x8b, 0x8b, 0xd8, 0x7e, 0xa4, 0x83, 0x7b, 0xcd, 0x8b,
+ 0x17, 0xb0, 0x6c, 0xb1, 0x5b, 0x4d, 0xc4, 0x0e, 0x53, 0x22, 0x14, 0xc6,
+ 0x3b, 0xc2, 0xf7, 0x16, 0x2f, 0xfb, 0x75, 0xfd, 0x34, 0x9b, 0x53, 0x2c,
+ 0x5f, 0xb6, 0xf5, 0x06, 0x76, 0xb1, 0x7f, 0xd1, 0x23, 0x1f, 0x5e, 0x8c,
+ 0x58, 0xbf, 0xff, 0xff, 0xee, 0x6d, 0xfe, 0x4f, 0x06, 0x77, 0x2e, 0x6d,
+ 0x17, 0x5a, 0xd4, 0x6d, 0x98, 0xde, 0xf6, 0xed, 0xfe, 0xe2, 0xc5, 0xfd,
+ 0xde, 0xd9, 0xb3, 0x3a, 0x58, 0xa0, 0xaa, 0xba, 0x28, 0x85, 0x8e, 0x46,
+ 0x55, 0xd1, 0x1b, 0x8f, 0x00, 0xfc, 0x8b, 0xbc, 0x72, 0x28, 0x56, 0xdf,
+ 0xbf, 0x00, 0x8d, 0xd5, 0x8b, 0x8e, 0xcb, 0x14, 0xb1, 0x40, 0x34, 0x66,
+ 0x0b, 0xdf, 0xd2, 0x91, 0xe6, 0x80, 0x8b, 0x16, 0x02, 0xc5, 0x32, 0x2d,
+ 0x00, 0x9c, 0x44, 0x42, 0x32, 0xbb, 0x72, 0x16, 0x2f, 0x41, 0xac, 0xb1,
+ 0x7c, 0x38, 0xe4, 0x2c, 0x5d, 0x07, 0x58, 0xba, 0x3b, 0x58, 0xbf, 0xb9,
+ 0x87, 0xde, 0x3c, 0x58, 0xa8, 0x44, 0x08, 0xc8, 0xa6, 0x17, 0xe0, 0xc5,
+ 0x12, 0x3d, 0x78, 0x35, 0xe8, 0x4f, 0x5d, 0xb9, 0xb1, 0xac, 0x5f, 0xfe,
+ 0x04, 0x17, 0x5b, 0x70, 0x85, 0x2c, 0xe2, 0xc5, 0xf8, 0x1a, 0x6e, 0xc0,
+ 0xb1, 0x7e, 0xf3, 0xc9, 0x80, 0xb1, 0x7f, 0x6d, 0xef, 0xc5, 0x03, 0x58,
+ 0xb3, 0xf6, 0x88, 0x32, 0x2a, 0xe1, 0x45, 0xff, 0x84, 0x78, 0xce, 0x16,
+ 0x6f, 0x75, 0x8b, 0xf9, 0xcb, 0x27, 0x0e, 0x4b, 0x17, 0xe8, 0x99, 0xdf,
+ 0x4b, 0x14, 0x03, 0xd7, 0xe1, 0x7d, 0x76, 0x9d, 0xe7, 0xe1, 0x9f, 0xc3,
+ 0x5f, 0x42, 0x5a, 0xf6, 0xd9, 0x74, 0xb1, 0x7f, 0x6d, 0xe3, 0xc7, 0x72,
+ 0x58, 0xb8, 0x1c, 0x58, 0xa6, 0x3c, 0x97, 0x31, 0xbf, 0xee, 0x6d, 0xc2,
+ 0x81, 0x05, 0xf8, 0xb1, 0x7b, 0x6f, 0x72, 0x58, 0xbf, 0xc7, 0xfb, 0x78,
+ 0xa0, 0xeb, 0x15, 0x0b, 0x94, 0xd9, 0x19, 0x81, 0xa6, 0x8d, 0x1e, 0xe1,
+ 0xd2, 0x7e, 0xd4, 0x44, 0x1c, 0x3f, 0x11, 0x0d, 0xff, 0xfd, 0xad, 0xa5,
+ 0x9b, 0xf3, 0x52, 0xdb, 0x03, 0x79, 0xb8, 0xb1, 0x7f, 0xfb, 0x5f, 0x31,
+ 0xc7, 0xb4, 0x30, 0x01, 0x82, 0x2c, 0x5f, 0xfd, 0x86, 0x04, 0x38, 0x98,
+ 0xf8, 0x40, 0x58, 0xbf, 0xff, 0xf7, 0x70, 0x69, 0x60, 0xfe, 0xd3, 0x6d,
+ 0xe6, 0x77, 0x2d, 0x61, 0x8b, 0x14, 0xc8, 0xba, 0x24, 0x7a, 0xc4, 0xe3,
+ 0xdd, 0x88, 0xa3, 0x0c, 0xbf, 0xa0, 0xdc, 0x1e, 0xe6, 0xc6, 0xb1, 0x7d,
+ 0xe1, 0x44, 0xeb, 0x17, 0xf4, 0x9f, 0x5c, 0x61, 0xac, 0x5f, 0xd9, 0xfc,
+ 0x3c, 0x74, 0xb1, 0x70, 0xf1, 0x62, 0xa0, 0xfc, 0xe4, 0x5c, 0xc5, 0xd7,
+ 0xe6, 0xd3, 0x6f, 0xc5, 0x8a, 0x92, 0x64, 0x8c, 0x6f, 0xe8, 0x4b, 0x84,
+ 0x2d, 0xbe, 0xdc, 0xcd, 0x42, 0xc5, 0xfd, 0x1c, 0xfc, 0x17, 0x96, 0x2f,
+ 0xff, 0xee, 0xe5, 0xc3, 0xe1, 0x6d, 0x08, 0xdf, 0x9d, 0xb3, 0x4b, 0x16,
+ 0xdd, 0x58, 0xbd, 0xec, 0xe2, 0xc5, 0x49, 0x18, 0x18, 0x5b, 0xd3, 0x08,
+ 0x85, 0x6f, 0xff, 0xf1, 0x67, 0x5f, 0x62, 0xc1, 0x77, 0xed, 0xae, 0x66,
+ 0x1a, 0xb1, 0x79, 0xa7, 0xe2, 0xc5, 0xff, 0xb3, 0xa7, 0x9f, 0xf9, 0xd6,
+ 0x12, 0xc5, 0x8c, 0xda, 0x8c, 0x3c, 0x65, 0xf8, 0xf5, 0xfe, 0x34, 0x62,
+ 0x8f, 0x94, 0x2c, 0x5f, 0xd2, 0xe1, 0xa2, 0x8e, 0xd6, 0x2f, 0xb0, 0x6f,
+ 0x25, 0x8a, 0xec, 0xf4, 0xcc, 0x31, 0xbe, 0xd4, 0x44, 0xeb, 0x17, 0xd3,
+ 0x47, 0x9d, 0x62, 0xff, 0x44, 0xfc, 0x89, 0x9b, 0x7a, 0xc5, 0xe9, 0x87,
+ 0x25, 0x8a, 0x9c, 0xf5, 0xb0, 0xde, 0xe7, 0x33, 0x88, 0xbe, 0x11, 0x18,
+ 0x6f, 0x37, 0xb7, 0xf8, 0x35, 0x8a, 0x84, 0xff, 0xf0, 0xe1, 0xa1, 0x0e,
+ 0x50, 0xe2, 0x30, 0xf6, 0xf0, 0x70, 0x4b, 0x17, 0xfc, 0xda, 0x9c, 0x40,
+ 0xc2, 0xc5, 0x8b, 0xa6, 0x3a, 0xc5, 0xfe, 0x97, 0x3c, 0x2c, 0x1e, 0xd9,
+ 0x8f, 0x48, 0x07, 0x37, 0xff, 0xd8, 0x3f, 0x88, 0xce, 0x37, 0xbe, 0xce,
+ 0x05, 0x8a, 0xed, 0x13, 0xe4, 0x9d, 0x71, 0xe4, 0xb1, 0x7f, 0xfa, 0x35,
+ 0xd1, 0xa0, 0xc7, 0x2e, 0xe5, 0xc5, 0x8a, 0x91, 0xf2, 0xf0, 0x62, 0xfb,
+ 0x35, 0x07, 0x58, 0xbc, 0x59, 0xbf, 0x69, 0xe2, 0x11, 0x15, 0xff, 0xff,
+ 0x70, 0xb0, 0x6c, 0x66, 0xd2, 0xc0, 0x9e, 0x6e, 0x0a, 0x34, 0xb1, 0x5a,
+ 0x4d, 0xaf, 0x90, 0xcc, 0xf1, 0xad, 0xfe, 0x23, 0x4b, 0x1b, 0xbf, 0x2c,
+ 0x5b, 0x7a, 0xc5, 0x61, 0xe4, 0x70, 0xd2, 0xa1, 0x13, 0xe2, 0x7e, 0xbe,
+ 0x8c, 0xff, 0x16, 0x2e, 0x69, 0xd6, 0x2c, 0x09, 0x8d, 0xd7, 0x88, 0xaf,
+ 0xf7, 0x45, 0x83, 0xfb, 0xf1, 0x62, 0xfe, 0x06, 0x10, 0xff, 0x0b, 0x17,
+ 0xf7, 0xd8, 0x80, 0x19, 0xd6, 0x29, 0x8f, 0x73, 0xc5, 0xb7, 0x0d, 0x96,
+ 0x2f, 0xff, 0xef, 0xb6, 0x16, 0x30, 0xf2, 0x00, 0xfd, 0x3e, 0x96, 0x2f,
+ 0xf4, 0xf0, 0x72, 0x8e, 0xc0, 0xb1, 0x50, 0x9a, 0xac, 0xa1, 0x21, 0xd1,
+ 0x0f, 0x62, 0xee, 0xb1, 0x7e, 0xfe, 0xd7, 0xce, 0x2c, 0x54, 0x1f, 0xd6,
+ 0x28, 0x58, 0x4b, 0x17, 0xf7, 0x8a, 0x25, 0x9e, 0x58, 0xbe, 0x22, 0xcf,
+ 0x2c, 0x5d, 0x38, 0x96, 0x2f, 0x18, 0xfc, 0x58, 0xbc, 0xfa, 0x96, 0xd4,
+ 0x42, 0xc1, 0x6b, 0x10, 0xfc, 0x66, 0xa1, 0x98, 0x85, 0x91, 0xac, 0x76,
+ 0x88, 0xd0, 0xe5, 0xd4, 0xaf, 0xf3, 0xa9, 0x7e, 0x58, 0xc3, 0xae, 0x14,
+ 0x7e, 0xfc, 0x20, 0x14, 0x25, 0xef, 0xfd, 0xa6, 0x9d, 0xce, 0x5d, 0x88,
+ 0x96, 0x2d, 0xba, 0xb1, 0x6f, 0x2c, 0x5d, 0x00, 0x58, 0xbf, 0xfc, 0xc2,
+ 0x0b, 0xc6, 0xde, 0x08, 0x07, 0xcf, 0x2c, 0x57, 0x67, 0xd1, 0xa1, 0x7b,
+ 0xff, 0xba, 0xfc, 0x73, 0xda, 0x8e, 0xfe, 0xcb, 0x17, 0xfe, 0x8e, 0xb9,
+ 0x0d, 0xdf, 0xa0, 0xeb, 0x14, 0xb1, 0x7b, 0x42, 0xdd, 0x58, 0xa9, 0x1a,
+ 0xdf, 0x06, 0x54, 0x23, 0x54, 0x91, 0xc4, 0xdb, 0x7c, 0x0e, 0x4f, 0xe5,
+ 0x8b, 0xf9, 0xff, 0x05, 0x12, 0x58, 0xbf, 0xff, 0xf7, 0xb2, 0x0b, 0x3a,
+ 0x27, 0x9e, 0x35, 0xa8, 0xf7, 0xf0, 0x6b, 0x17, 0xdb, 0xcb, 0x39, 0xb5,
+ 0x12, 0xf8, 0x59, 0x7f, 0xfd, 0x85, 0x86, 0xfd, 0xe5, 0xf3, 0x1c, 0x33,
+ 0xac, 0x5f, 0xf9, 0xcd, 0xdb, 0xe7, 0x72, 0xdb, 0x3a, 0xc5, 0x42, 0x71,
+ 0xcd, 0x0b, 0xcf, 0x9e, 0x12, 0x95, 0xf8, 0x18, 0x78, 0xe9, 0x62, 0xf3,
+ 0xfb, 0x8b, 0x17, 0x0a, 0x75, 0x8a, 0x91, 0xb6, 0xd0, 0xed, 0xfb, 0x25,
+ 0xf7, 0x92, 0xc5, 0x4c, 0x79, 0x3f, 0x21, 0xb1, 0x42, 0x32, 0xfd, 0x0a,
+ 0x8b, 0xbf, 0xba, 0xb1, 0x7f, 0x9c, 0x83, 0xff, 0xe0, 0x6b, 0x17, 0xff,
+ 0xde, 0xe4, 0x66, 0xdd, 0x47, 0x9b, 0xa6, 0x1a, 0xc5, 0xdd, 0x98, 0xb1,
+ 0x63, 0x16, 0x2e, 0xeb, 0x68, 0xcd, 0x6f, 0x63, 0x55, 0xc4, 0x58, 0x09,
+ 0xfe, 0xf7, 0x70, 0x6a, 0xc5, 0xff, 0xff, 0xda, 0x8d, 0xbf, 0xc0, 0x9e,
+ 0x8d, 0x74, 0x59, 0xed, 0x0b, 0xb9, 0x71, 0x62, 0xf1, 0x9f, 0xc2, 0x44,
+ 0xc7, 0x87, 0xef, 0x85, 0x33, 0x8d, 0x62, 0xfd, 0x9e, 0xd6, 0x18, 0xb1,
+ 0x6e, 0xb6, 0x9e, 0x6f, 0xc9, 0x2a, 0x11, 0x58, 0xd0, 0x81, 0xbb, 0x52,
+ 0x58, 0xbf, 0xc6, 0xbf, 0x33, 0xc1, 0xce, 0xb1, 0x7d, 0xb7, 0xa3, 0x21,
+ 0x62, 0xa4, 0x7b, 0xc7, 0x37, 0xa8, 0x56, 0xa1, 0x22, 0xce, 0xc6, 0xda,
+ 0x1c, 0x9a, 0x8d, 0x9c, 0xe4, 0xce, 0xed, 0x7e, 0xd8, 0xb4, 0xd0, 0x6a,
+ 0xc5, 0xfb, 0xdf, 0x86, 0xe9, 0x62, 0x8d, 0x3d, 0x7f, 0x17, 0x5f, 0x86,
+ 0x4e, 0xff, 0x58, 0xa2, 0x3c, 0xae, 0x11, 0xdf, 0xb3, 0x9e, 0x7d, 0x2c,
+ 0x5f, 0xfe, 0xe6, 0x39, 0x6d, 0xe7, 0x70, 0x51, 0xc5, 0x8b, 0x4b, 0xe7,
+ 0xe7, 0xe2, 0x8b, 0xfa, 0x07, 0x1f, 0x89, 0x2c, 0x5f, 0xe8, 0xf6, 0xd7,
+ 0xe9, 0xb7, 0xac, 0x56, 0x8f, 0x94, 0x8b, 0x6f, 0xff, 0xfc, 0xdd, 0xf9,
+ 0xfe, 0x58, 0x3f, 0xb4, 0xdc, 0xeb, 0x18, 0xa6, 0x58, 0xbf, 0xfe, 0x8f,
+ 0x6d, 0x21, 0x04, 0xdb, 0x9e, 0xdc, 0xcf, 0x2c, 0x54, 0x26, 0xea, 0xd0,
+ 0x8d, 0xd1, 0x08, 0x9b, 0xae, 0x7f, 0x2c, 0x5f, 0xfd, 0xf8, 0x37, 0x6f,
+ 0x89, 0xfd, 0x1e, 0x58, 0xbf, 0xbb, 0x93, 0x7c, 0x47, 0x58, 0xb9, 0xa7,
+ 0x58, 0xad, 0xa7, 0x91, 0xe3, 0x0a, 0xfa, 0x32, 0x80, 0x2e, 0x50, 0x8f,
+ 0xbf, 0x18, 0xff, 0x9b, 0x63, 0x58, 0xbf, 0xec, 0x1e, 0xdf, 0x1a, 0xc6,
+ 0x71, 0x62, 0xd9, 0xa3, 0xee, 0xde, 0x61, 0x7f, 0xfa, 0x09, 0xf6, 0xfd,
+ 0xdb, 0x9c, 0x63, 0xac, 0x5f, 0xcf, 0xf3, 0x63, 0x4e, 0xb1, 0x7f, 0xed,
+ 0x4d, 0xb7, 0x90, 0xd3, 0xbf, 0x96, 0x2a, 0x13, 0x86, 0x1c, 0x28, 0xbe,
+ 0x52, 0x49, 0x42, 0x2e, 0xbf, 0xf0, 0xb9, 0xad, 0x67, 0xfb, 0x97, 0x16,
+ 0x2e, 0x70, 0x2c, 0x5f, 0xff, 0x6d, 0x28, 0xe4, 0x4e, 0x58, 0x3f, 0xb4,
+ 0xcb, 0x17, 0xff, 0xff, 0x73, 0x45, 0x13, 0x6d, 0x0f, 0xcd, 0x2c, 0xef,
+ 0xd9, 0xbc, 0xb3, 0x8b, 0x15, 0xa4, 0x65, 0x12, 0x95, 0x49, 0x34, 0x5f,
+ 0x21, 0x0a, 0x1c, 0x34, 0xb1, 0x7f, 0xff, 0xe8, 0x2e, 0x9f, 0xe4, 0xe0,
+ 0xdb, 0xec, 0xf9, 0x67, 0xbe, 0xcb, 0x14, 0xb1, 0x7f, 0x43, 0x13, 0xe8,
+ 0xd5, 0x8b, 0xbd, 0xb4, 0xd3, 0x73, 0xf0, 0xcb, 0xc6, 0x9b, 0x0b, 0x16,
+ 0x92, 0xc5, 0x31, 0xb1, 0x98, 0x7e, 0xff, 0xec, 0xee, 0x5b, 0x72, 0x6f,
+ 0xc1, 0x1a, 0xb1, 0x50, 0x9b, 0xe1, 0xa1, 0x9d, 0xc2, 0x97, 0x4c, 0x27,
+ 0x21, 0xbf, 0xda, 0x2c, 0xeb, 0x23, 0x75, 0x62, 0xff, 0xe2, 0xf7, 0x37,
+ 0xb7, 0xa3, 0x0a, 0x65, 0x8b, 0xff, 0x6a, 0x7c, 0xce, 0x0c, 0x9f, 0xeb,
+ 0x17, 0xed, 0x37, 0x23, 0xb5, 0x8a, 0x84, 0x72, 0x61, 0xb3, 0x23, 0x39,
+ 0xfd, 0xff, 0xfa, 0x5c, 0x00, 0xa6, 0xdb, 0x8d, 0xa6, 0x3c, 0x1a, 0xb1,
+ 0x7f, 0x05, 0x66, 0x93, 0x7b, 0x8b, 0x17, 0xb8, 0x1f, 0x16, 0x2a, 0x73,
+ 0xd3, 0x39, 0xa5, 0xd0, 0x05, 0x8b, 0xf1, 0x7b, 0xf8, 0x11, 0x62, 0xfd,
+ 0x37, 0x1f, 0x46, 0xac, 0x5e, 0x73, 0x35, 0x07, 0xab, 0x85, 0x57, 0xf8,
+ 0xd8, 0x99, 0x8a, 0x0e, 0xb1, 0x7d, 0xb7, 0xb9, 0x32, 0xc5, 0x11, 0xed,
+ 0x78, 0xd2, 0xfe, 0x35, 0xe4, 0x50, 0x75, 0x8a, 0x83, 0xcf, 0x62, 0x1a,
+ 0x92, 0xa7, 0x0e, 0xce, 0x5a, 0x15, 0xb3, 0x11, 0xe9, 0xb3, 0xf0, 0xdb,
+ 0xbe, 0x6e, 0x9f, 0x4b, 0x17, 0x8e, 0xe6, 0x2c, 0x5b, 0x92, 0x3c, 0x17,
+ 0x23, 0xbe, 0xcd, 0xef, 0xa5, 0x8b, 0xf8, 0x78, 0x52, 0xfe, 0x2c, 0x54,
+ 0x1e, 0x8b, 0x12, 0x5f, 0xff, 0xb9, 0xb7, 0x18, 0xcd, 0xa5, 0x80, 0x2c,
+ 0x79, 0x96, 0x2f, 0xfb, 0xed, 0xa9, 0xbe, 0xf9, 0xa5, 0x8b, 0xff, 0xff,
+ 0xf8, 0x1c, 0x2c, 0x7e, 0xf6, 0x8f, 0xe2, 0xda, 0x59, 0xdc, 0xb0, 0x53,
+ 0x96, 0x3f, 0x6b, 0x15, 0x89, 0x91, 0x74, 0xb2, 0xc7, 0x57, 0xb3, 0x92,
+ 0x58, 0xb9, 0xfa, 0x54, 0x53, 0x05, 0x8d, 0x58, 0xaf, 0x9e, 0xab, 0x8e,
+ 0x88, 0x96, 0xfd, 0x3b, 0x9f, 0x9b, 0x8b, 0x15, 0x0a, 0xa6, 0xa7, 0x78,
+ 0xc8, 0xd0, 0xba, 0x84, 0x2b, 0x17, 0x5f, 0xff, 0xef, 0x70, 0x3e, 0x6d,
+ 0xc9, 0x7e, 0x1b, 0x40, 0x3b, 0xc9, 0x62, 0xff, 0x8b, 0xb9, 0x73, 0xd1,
+ 0xa9, 0x96, 0x2f, 0x16, 0x7d, 0x62, 0xff, 0xba, 0x13, 0xff, 0x3c, 0xff,
+ 0x58, 0xa1, 0x9e, 0xb7, 0x63, 0x95, 0x88, 0xb5, 0xf4, 0x24, 0xaf, 0xfc,
+ 0xfd, 0xe3, 0x69, 0x8f, 0x06, 0xac, 0x5e, 0x0e, 0x09, 0x62, 0xf6, 0x30,
+ 0x16, 0x2d, 0x8b, 0x16, 0xc0, 0x1a, 0xdd, 0xe3, 0x97, 0x34, 0xeb, 0x14,
+ 0xb0, 0xe5, 0xc5, 0xda, 0xc5, 0x8b, 0x77, 0xb5, 0x17, 0x64, 0x95, 0xc4,
+ 0x01, 0x0d, 0x56, 0x2a, 0x80, 0x68, 0xc6, 0xb4, 0x4e, 0xf0, 0xfa, 0xbd,
+ 0x82, 0xd2, 0xc5, 0xa6, 0x58, 0xbe, 0x16, 0x76, 0x4b, 0x15, 0x39, 0xb6,
+ 0x38, 0x9d, 0x8c, 0x58, 0xb9, 0x86, 0xb1, 0x5b, 0xa6, 0xab, 0x82, 0x77,
+ 0x0e, 0x65, 0x8b, 0xfe, 0xd6, 0x0f, 0xf0, 0x61, 0xc4, 0xb1, 0x7f, 0x7f,
+ 0x06, 0xc5, 0xe5, 0x8b, 0x4e, 0xb1, 0x77, 0xf8, 0xb1, 0x46, 0x9a, 0xb7,
+ 0x13, 0xbf, 0x89, 0xcc, 0xf6, 0x7d, 0x62, 0xfb, 0x72, 0x35, 0x8b, 0x15,
+ 0x09, 0xc8, 0x62, 0x61, 0xc9, 0x3e, 0x33, 0xe3, 0xb3, 0x16, 0x37, 0x08,
+ 0x43, 0x2e, 0xbf, 0x7c, 0x46, 0xe4, 0xeb, 0x17, 0xec, 0x39, 0xdc, 0xeb,
+ 0x17, 0x1c, 0x0b, 0x17, 0x7d, 0xf6, 0xa3, 0x80, 0x6e, 0xba, 0x2b, 0x01,
+ 0x45, 0xfd, 0xa8, 0xf1, 0x38, 0x16, 0x2b, 0x47, 0xee, 0x11, 0x2a, 0xfe,
+ 0xee, 0x45, 0x19, 0xc5, 0x8b, 0xff, 0x9b, 0x82, 0x09, 0xb7, 0x86, 0xea,
+ 0x09, 0x62, 0xb6, 0x9f, 0xc0, 0x42, 0xea, 0xed, 0x5f, 0xe3, 0x4b, 0x3a,
+ 0x78, 0x4e, 0x5f, 0xff, 0x80, 0xdc, 0xdb, 0xf7, 0xe7, 0xa2, 0x6e, 0x7f,
+ 0x16, 0x29, 0x62, 0xfe, 0x13, 0x0d, 0x89, 0x96, 0x2c, 0x6b, 0x1b, 0x83,
+ 0x86, 0x5f, 0x9f, 0x9f, 0x79, 0x2c, 0x5f, 0x3c, 0x98, 0xeb, 0x17, 0xee,
+ 0x9f, 0x59, 0xd2, 0xc5, 0xff, 0x0b, 0xb9, 0x73, 0x6f, 0x3d, 0xd2, 0xc5,
+ 0xfc, 0x5e, 0x96, 0x03, 0x8b, 0x17, 0x8d, 0x7e, 0x6d, 0x44, 0xc6, 0x8a,
+ 0x9d, 0x02, 0xbe, 0x8f, 0xdf, 0x42, 0xea, 0xb4, 0x9b, 0xa7, 0xc9, 0xcc,
+ 0x8c, 0x96, 0xfe, 0x6f, 0xbb, 0x4f, 0x0b, 0x17, 0xa5, 0x1d, 0xac, 0x5f,
+ 0xc6, 0xeb, 0x59, 0xdf, 0x16, 0x2f, 0xff, 0xc5, 0x9d, 0xfb, 0x6f, 0xdf,
+ 0x7e, 0xd1, 0xfc, 0x53, 0xac, 0x5f, 0xbf, 0x13, 0xe1, 0x8b, 0x17, 0xe6,
+ 0xcd, 0xef, 0xa5, 0x8b, 0x1e, 0x11, 0x64, 0x35, 0xfe, 0x15, 0x5f, 0xd9,
+ 0xc9, 0x30, 0x31, 0x62, 0xf4, 0xb3, 0xcb, 0x15, 0x23, 0xca, 0xf1, 0x6d,
+ 0x42, 0xa0, 0x7c, 0x38, 0xec, 0xb5, 0x87, 0x9e, 0x1c, 0x62, 0x7f, 0xbf,
+ 0xfc, 0x36, 0xc3, 0x36, 0xf2, 0x1a, 0x77, 0xf2, 0xc5, 0xf3, 0x72, 0x3b,
+ 0x58, 0xae, 0xcf, 0xc3, 0xe9, 0xb7, 0xee, 0xfa, 0x28, 0xde, 0xb1, 0x7f,
+ 0xf8, 0x80, 0x42, 0xe1, 0x67, 0xb8, 0xdc, 0x58, 0xbf, 0x9f, 0x53, 0x49,
+ 0xbe, 0xb1, 0x7f, 0x85, 0x3f, 0xdb, 0x7e, 0x4c, 0xb1, 0x7f, 0x07, 0xff,
+ 0xc1, 0x74, 0xb1, 0x7c, 0x50, 0x7e, 0x2c, 0x5c, 0xfd, 0xf0, 0xf4, 0xbc,
+ 0x61, 0x50, 0x9b, 0xfe, 0x11, 0xb1, 0x63, 0xa4, 0xf0, 0xbc, 0x50, 0x8a,
+ 0xbb, 0x9c, 0x58, 0xb6, 0x2c, 0x5f, 0xf3, 0x1a, 0xde, 0x2c, 0x09, 0xb7,
+ 0x46, 0xa7, 0x78, 0xc5, 0xfe, 0x62, 0x06, 0x1d, 0xfb, 0x58, 0xa9, 0x91,
+ 0x0f, 0xbd, 0x52, 0xff, 0xff, 0x16, 0x75, 0xef, 0x47, 0xb9, 0x31, 0x61,
+ 0x9b, 0x60, 0x28, 0xb1, 0x7f, 0xee, 0xa0, 0xff, 0xce, 0x63, 0x12, 0xc5,
+ 0x42, 0x29, 0xfe, 0xd3, 0x7f, 0xff, 0xe9, 0x46, 0xbb, 0x97, 0x36, 0xf0,
+ 0x51, 0xd9, 0x3f, 0xbe, 0xf3, 0x2c, 0x5f, 0xb5, 0x1b, 0xe3, 0x4b, 0x17,
+ 0xd1, 0xd6, 0x1d, 0x62, 0xff, 0x6d, 0xce, 0x71, 0xb0, 0xc5, 0x8a, 0x98,
+ 0xf6, 0x74, 0x47, 0x7f, 0xff, 0xfd, 0x8c, 0x3d, 0xb9, 0xf6, 0xd7, 0xdf,
+ 0x6f, 0xf0, 0x65, 0x8f, 0xde, 0x4e, 0xb1, 0x4c, 0x8a, 0x3f, 0x91, 0xdf,
+ 0xce, 0x5b, 0x47, 0x04, 0xb1, 0x7a, 0x7e, 0xbc, 0xb1, 0x50, 0xab, 0xdf,
+ 0x21, 0x9b, 0xd9, 0x13, 0x39, 0x72, 0x32, 0x61, 0x11, 0x06, 0x5d, 0x7c,
+ 0x5e, 0x35, 0x96, 0x2f, 0xb0, 0xf1, 0xd2, 0xc5, 0xfd, 0xd3, 0x4f, 0x9d,
+ 0xf9, 0x62, 0xa4, 0x7a, 0x86, 0x11, 0xdb, 0x71, 0x62, 0xfe, 0x06, 0xd8,
+ 0xe9, 0xc3, 0x58, 0xbf, 0xe8, 0xc2, 0x96, 0xd8, 0xdf, 0x0b, 0x14, 0x6a,
+ 0x20, 0x88, 0x57, 0xc6, 0x55, 0x08, 0xd5, 0x68, 0x52, 0xde, 0x8d, 0x49,
+ 0x62, 0xff, 0xff, 0x68, 0x5d, 0xcb, 0x9b, 0x60, 0x87, 0xf8, 0xdc, 0xcd,
+ 0x42, 0xc5, 0x6d, 0x75, 0x78, 0x7b, 0x02, 0x00, 0x5a, 0x15, 0x87, 0xa9,
+ 0xe1, 0xf1, 0x28, 0xef, 0x07, 0x38, 0xb7, 0x91, 0x88, 0x1b, 0x28, 0x27,
+ 0xa9, 0x52, 0x3d, 0xc7, 0x26, 0xd1, 0xd9, 0x4d, 0x2e, 0x97, 0x52, 0xcf,
+ 0xcf, 0x2b, 0x5b, 0xf3, 0x88, 0x60, 0x3d, 0x29, 0xc0, 0xce, 0x4a, 0x4a,
+ 0xf4, 0xe0, 0x00, 0x9c, 0x37, 0xc6, 0x98, 0x61, 0x30, 0x41, 0xdb, 0xdc,
+ 0x8e, 0xd6, 0x2f, 0x4f, 0x93, 0xac, 0x5f, 0xe7, 0x33, 0x6b, 0x8d, 0xe7,
+ 0x58, 0xbf, 0xfb, 0xdc, 0x1f, 0xe3, 0x70, 0x5f, 0x6d, 0x2c, 0x56, 0x91,
+ 0x00, 0x23, 0x7b, 0xd2, 0xef, 0xa5, 0x8b, 0xf9, 0xcc, 0x98, 0x98, 0x6b,
+ 0x17, 0x48, 0x0b, 0x17, 0x4e, 0x75, 0x8a, 0xda, 0x6c, 0x58, 0x62, 0xff,
+ 0xfc, 0x4d, 0x3e, 0xd6, 0xc2, 0xce, 0x82, 0x7b, 0x0e, 0xb1, 0x78, 0xf1,
+ 0xd2, 0xc5, 0xee, 0xff, 0x93, 0x1f, 0xb8, 0x16, 0x6f, 0xff, 0xec, 0x9d,
+ 0xcb, 0xdc, 0x8e, 0xb6, 0x9c, 0xec, 0x5d, 0x2c, 0x5f, 0xd2, 0xe4, 0xd2,
+ 0x89, 0x96, 0x28, 0x68, 0x90, 0xed, 0x7e, 0xfe, 0x1f, 0x1e, 0x3b, 0x92,
+ 0xc5, 0x41, 0xe9, 0xb9, 0x25, 0xff, 0x16, 0xdd, 0x63, 0x7e, 0x06, 0xb1,
+ 0x6d, 0x89, 0x62, 0x86, 0xae, 0x0b, 0x07, 0x8d, 0x84, 0xfb, 0x11, 0xe8,
+ 0x83, 0xec, 0x0f, 0x09, 0x92, 0x8c, 0x60, 0x44, 0x1b, 0xce, 0xaf, 0xb0,
+ 0x8d, 0xdd, 0x58, 0xbf, 0xff, 0xff, 0x7d, 0xbd, 0xfc, 0xd4, 0x6f, 0xda,
+ 0x71, 0x04, 0xdb, 0x9d, 0xcb, 0x04, 0x40, 0xe2, 0xc5, 0xbc, 0xc8, 0xb3,
+ 0xe1, 0x35, 0xff, 0xf1, 0x4d, 0xf8, 0x6d, 0x31, 0xdb, 0x72, 0x0e, 0xb1,
+ 0x73, 0x1d, 0x62, 0xff, 0xfb, 0xb9, 0x13, 0x4d, 0xb4, 0xb3, 0xdc, 0x6d,
+ 0x2c, 0x53, 0x22, 0xf2, 0x65, 0x23, 0x05, 0xef, 0xf8, 0xed, 0x37, 0xdc,
+ 0xa2, 0x16, 0x2f, 0xfc, 0x06, 0xcd, 0x6d, 0xdf, 0x03, 0xdd, 0x58, 0xa3,
+ 0x9f, 0xf0, 0x43, 0x8b, 0xfc, 0xf2, 0x9b, 0xed, 0xdf, 0x96, 0x2f, 0xf4,
+ 0xb9, 0x06, 0xf9, 0xa7, 0x58, 0xbf, 0xc2, 0x2f, 0x46, 0xf7, 0xfa, 0xc5,
+ 0xff, 0x9c, 0xcf, 0x67, 0xf0, 0x9e, 0x4b, 0x15, 0x23, 0xf3, 0x23, 0x5b,
+ 0xff, 0xee, 0xf0, 0x44, 0x6f, 0xb5, 0x1d, 0x83, 0x90, 0xb1, 0x7f, 0x1f,
+ 0x0b, 0xdb, 0x98, 0xb1, 0x7e, 0x7e, 0x1e, 0x09, 0x62, 0xf4, 0x75, 0xb7,
+ 0x0f, 0x5c, 0x8c, 0x2f, 0xd0, 0x5e, 0xda, 0x35, 0x8b, 0xfa, 0x0f, 0x98,
+ 0x46, 0xac, 0x5f, 0xbd, 0xb4, 0x1d, 0x81, 0x62, 0x99, 0x10, 0x9f, 0x2a,
+ 0x11, 0x6d, 0xff, 0xef, 0xb7, 0x5f, 0xcd, 0xbc, 0x17, 0xe3, 0x75, 0x62,
+ 0xfe, 0x28, 0xee, 0x4c, 0x4b, 0x14, 0xb1, 0x7f, 0xb3, 0xe5, 0x9e, 0xfb,
+ 0x2c, 0x50, 0xcf, 0xac, 0x8b, 0x7c, 0x19, 0x7f, 0xde, 0x89, 0x72, 0x69,
+ 0x44, 0xeb, 0x16, 0xcc, 0x4c, 0x9b, 0xb8, 0x5e, 0x78, 0xba, 0xff, 0xfb,
+ 0xdf, 0xc0, 0x6d, 0x3c, 0x67, 0x87, 0x84, 0xb1, 0x6d, 0x2c, 0x58, 0xc5,
+ 0x8b, 0xf9, 0xc7, 0xad, 0x0a, 0x75, 0x8b, 0xf4, 0x61, 0x7b, 0x71, 0x62,
+ 0xdb, 0x02, 0xc5, 0x62, 0x25, 0x8d, 0x12, 0xe8, 0x4c, 0xe6, 0x1c, 0x2a,
+ 0xbe, 0xf3, 0x6b, 0x16, 0x2d, 0xde, 0xd3, 0xed, 0xc4, 0xbb, 0x73, 0x13,
+ 0x7e, 0x78, 0xd5, 0x28, 0x6b, 0xb3, 0xdd, 0x9b, 0x4d, 0x0a, 0x9d, 0x10,
+ 0x9e, 0x15, 0x5f, 0x85, 0xc1, 0x46, 0xab, 0xe8, 0xee, 0x6f, 0xff, 0xe2,
+ 0xc3, 0x32, 0x7d, 0xbb, 0xb8, 0xe6, 0xed, 0xd1, 0x9a, 0x58, 0xbf, 0xff,
+ 0xfc, 0xd8, 0x7c, 0xfb, 0x61, 0xf6, 0x96, 0x7b, 0xf9, 0x2f, 0xb6, 0x1d,
+ 0x62, 0xff, 0xff, 0xe9, 0x37, 0x0b, 0x37, 0xff, 0x26, 0xfc, 0x14, 0xdb,
+ 0x5f, 0xa6, 0xde, 0xb1, 0x7f, 0xf9, 0xb0, 0xc2, 0xce, 0x67, 0xfe, 0xdc,
+ 0x58, 0xb6, 0x76, 0x8c, 0x2f, 0x3c, 0xdf, 0xff, 0xcd, 0x86, 0x16, 0x4f,
+ 0x82, 0xf1, 0x39, 0xaf, 0xc5, 0x8b, 0xff, 0x66, 0xbf, 0x1b, 0x5f, 0xc2,
+ 0x85, 0x8b, 0xff, 0xb9, 0x9d, 0x6d, 0xee, 0x5c, 0x26, 0x99, 0x62, 0xff,
+ 0xff, 0xc5, 0x9b, 0xff, 0x9a, 0xd6, 0x7b, 0x81, 0x3d, 0x1c, 0xfb, 0x62,
+ 0xc5, 0xa3, 0xc8, 0xb9, 0x31, 0x2a, 0x99, 0x32, 0x2d, 0x43, 0xe6, 0xff,
+ 0xff, 0xb0, 0x8d, 0xdb, 0xa8, 0xde, 0xde, 0xe6, 0x1a, 0xda, 0x7e, 0xd6,
+ 0x2a, 0x75, 0x7b, 0x1f, 0x66, 0x28, 0xce, 0x38, 0x53, 0xe8, 0xdf, 0x43,
+ 0x28, 0xa6, 0x5c, 0xce, 0x14, 0xe3, 0x45, 0xff, 0xe6, 0x1e, 0xd3, 0xb6,
+ 0xd8, 0x1b, 0xcd, 0xc5, 0x8b, 0xf7, 0xdb, 0xd8, 0x75, 0x8b, 0x49, 0x62,
+ 0xff, 0xd8, 0xd3, 0xf1, 0xbf, 0xf8, 0x9d, 0x62, 0xfe, 0xf7, 0x7d, 0x37,
+ 0xe6, 0x58, 0xa0, 0xaa, 0x2b, 0x24, 0x50, 0x42, 0x5c, 0x40, 0xa8, 0x4c,
+ 0xee, 0x78, 0x7d, 0xdf, 0xe3, 0x4b, 0x37, 0x96, 0x71, 0x62, 0xb4, 0x7b,
+ 0xc4, 0x53, 0x7e, 0xe7, 0x20, 0xba, 0x58, 0xbf, 0xfe, 0x29, 0xb6, 0xff,
+ 0xa6, 0xe6, 0x0e, 0x7c, 0x31, 0x62, 0xb0, 0xff, 0xdc, 0xa6, 0xf7, 0xb3,
+ 0x8b, 0x16, 0x9f, 0xe6, 0xf7, 0xc4, 0x17, 0xe9, 0x47, 0x72, 0xe2, 0xc5,
+ 0xff, 0xff, 0xff, 0xb0, 0x8d, 0xda, 0xdf, 0x16, 0xcc, 0xcd, 0xe8, 0x39,
+ 0x39, 0xbf, 0x6d, 0x9c, 0xff, 0x60, 0x81, 0xa4, 0x5f, 0xff, 0xe6, 0xd7,
+ 0xf3, 0xb7, 0xef, 0x69, 0xc8, 0x5e, 0xdb, 0xbf, 0x8b, 0x17, 0xff, 0xfe,
+ 0x63, 0x06, 0x2d, 0x6d, 0x14, 0x4f, 0xce, 0xbe, 0x2f, 0xf6, 0xe6, 0x2c,
+ 0x5f, 0xff, 0xd9, 0xbe, 0x0b, 0x6f, 0x1b, 0x4e, 0x07, 0x29, 0xa1, 0x62,
+ 0xba, 0x46, 0x9f, 0xdd, 0xad, 0x3f, 0x6a, 0x8b, 0xd8, 0xa8, 0xf0, 0xa4,
+ 0xe4, 0x67, 0xb5, 0x8a, 0xaa, 0x05, 0x29, 0x5e, 0xfc, 0x59, 0xef, 0xb2,
+ 0xc5, 0xff, 0xbe, 0xd9, 0xd4, 0x7b, 0xed, 0x8b, 0x14, 0x69, 0xf2, 0x84,
+ 0x27, 0xb8, 0x78, 0xb1, 0x50, 0xd9, 0x1d, 0x64, 0x39, 0x1a, 0x15, 0xff,
+ 0xa5, 0x48, 0x3c, 0x78, 0xc5, 0x2e, 0x14, 0x50, 0x90, 0xdc, 0x25, 0xbb,
+ 0x34, 0xb1, 0x60, 0x8b, 0x16, 0x3a, 0xc5, 0xfe, 0x79, 0x61, 0xdc, 0x80,
+ 0xb1, 0x7d, 0x9f, 0x89, 0x96, 0x2b, 0x60, 0x3e, 0x7f, 0x89, 0x39, 0x95,
+ 0xdc, 0xc5, 0x8b, 0x8f, 0xd6, 0xd3, 0xca, 0x63, 0x3b, 0x6e, 0xac, 0x5f,
+ 0xbc, 0x22, 0x07, 0x16, 0x2f, 0xff, 0xfe, 0xe8, 0xb3, 0x7e, 0xde, 0x36,
+ 0x10, 0x36, 0x96, 0x6f, 0x2c, 0xe6, 0xf5, 0x8b, 0xfe, 0x35, 0xfd, 0xc9,
+ 0x89, 0x8c, 0x58, 0xbe, 0x73, 0xb7, 0x16, 0x2f, 0xdf, 0x73, 0xb7, 0x16,
+ 0x28, 0xd4, 0x43, 0x7c, 0xf3, 0x84, 0x55, 0xa4, 0xcc, 0x4a, 0x30, 0x0b,
+ 0xff, 0xdf, 0x16, 0x11, 0xbb, 0x7d, 0xdc, 0xb0, 0x96, 0x2f, 0xf6, 0x39,
+ 0xf6, 0xee, 0x41, 0xd6, 0x2f, 0xff, 0x4a, 0x39, 0xf1, 0x6b, 0x3d, 0xe6,
+ 0x3a, 0xc5, 0x0d, 0x1a, 0x3d, 0x27, 0x76, 0x71, 0x7f, 0xe2, 0xc1, 0x1b,
+ 0xa6, 0x83, 0xe2, 0xc5, 0xff, 0xf8, 0x51, 0xb4, 0xb0, 0x7f, 0x63, 0x47,
+ 0x06, 0x81, 0x62, 0xb1, 0x3c, 0x3d, 0x43, 0xe8, 0xe6, 0x44, 0x7d, 0x7f,
+ 0xfb, 0xdf, 0xc0, 0x9e, 0x9b, 0x37, 0x5c, 0x80, 0xb1, 0x7f, 0xa0, 0xee,
+ 0x5d, 0xca, 0x16, 0x28, 0x91, 0x07, 0xe5, 0x0b, 0xff, 0xb1, 0x81, 0xb4,
+ 0xb3, 0x7b, 0x69, 0xd6, 0x29, 0x8f, 0xa3, 0xc4, 0x57, 0xc6, 0x6d, 0xe4,
+ 0xcb, 0x16, 0xf2, 0xc5, 0x41, 0xba, 0x72, 0x8b, 0xff, 0x14, 0xe5, 0x9b,
+ 0xf8, 0x28, 0xed, 0x62, 0xff, 0xbf, 0x1d, 0xed, 0xd8, 0x7b, 0xc0, 0xcb,
+ 0x17, 0xef, 0x77, 0x26, 0xdc, 0x58, 0xa1, 0x9f, 0x97, 0x11, 0x6a, 0x11,
+ 0xad, 0x3c, 0x2d, 0x2a, 0x4b, 0xba, 0xd8, 0x2a, 0xd2, 0xc7, 0x79, 0x19,
+ 0x67, 0x96, 0xc5, 0x0f, 0x5b, 0xf6, 0xf0, 0x9e, 0xcf, 0xac, 0x5f, 0xfb,
+ 0x38, 0x28, 0x37, 0x91, 0xa9, 0x96, 0x29, 0x8f, 0xb8, 0xc2, 0xdb, 0xff,
+ 0xe1, 0x39, 0x6d, 0xf7, 0xe3, 0xdc, 0xfb, 0xc9, 0x62, 0xfb, 0x52, 0x71,
+ 0xac, 0x5c, 0xfd, 0x2c, 0x5f, 0xb5, 0x9b, 0x8c, 0x05, 0x8b, 0xfd, 0xd7,
+ 0xdb, 0xe4, 0x29, 0xd6, 0x2f, 0xd1, 0xd8, 0x35, 0x0b, 0x15, 0x23, 0xdf,
+ 0xf1, 0xb5, 0x4e, 0x8a, 0xc2, 0x84, 0x55, 0xef, 0x60, 0x5d, 0x62, 0x82,
+ 0xa9, 0x86, 0xc4, 0x31, 0x30, 0xa2, 0xff, 0x46, 0x78, 0x01, 0x94, 0x96,
+ 0x2e, 0xcf, 0xac, 0x51, 0x1e, 0x5e, 0xe1, 0xa5, 0xc6, 0xc2, 0xc5, 0xd8,
+ 0x35, 0x8a, 0xda, 0xca, 0x34, 0x0a, 0x0b, 0xcf, 0x0c, 0x59, 0x4f, 0x03,
+ 0x64, 0x36, 0x3a, 0x22, 0x75, 0x2e, 0x46, 0x61, 0xe8, 0x41, 0x88, 0x93,
+ 0x78, 0xc5, 0xf9, 0xbd, 0xcc, 0x02, 0xc5, 0xfb, 0xf9, 0xbd, 0xb7, 0xac,
+ 0x5f, 0xff, 0x66, 0xbb, 0x79, 0xb6, 0xfd, 0xb4, 0x59, 0x3a, 0xc5, 0xff,
+ 0xfe, 0xf7, 0xe2, 0x6d, 0xa5, 0x9f, 0x6f, 0x70, 0x5d, 0x0a, 0x16, 0x2c,
+ 0x46, 0xa2, 0xe5, 0xd5, 0x2e, 0xc0, 0x2c, 0x5f, 0xfc, 0x40, 0x2c, 0x69,
+ 0xbf, 0x04, 0x6a, 0xc5, 0x31, 0xed, 0xb8, 0xbd, 0xfd, 0x2e, 0x79, 0xa3,
+ 0xb5, 0x8b, 0xb3, 0x7a, 0xc5, 0xff, 0xff, 0x3c, 0xdb, 0x79, 0xcc, 0xfe,
+ 0xb5, 0x86, 0x16, 0x18, 0xe0, 0x58, 0xbf, 0x41, 0x7d, 0xe4, 0xb1, 0x7f,
+ 0xde, 0xc9, 0xe3, 0x8d, 0xac, 0x58, 0xbd, 0x03, 0x85, 0x8a, 0x19, 0xfe,
+ 0x76, 0x4e, 0x73, 0x9a, 0x58, 0xa5, 0x8b, 0xfe, 0xf6, 0x4f, 0x1c, 0x6d,
+ 0x62, 0xc5, 0xe8, 0x1c, 0x2c, 0x5e, 0xe3, 0xcd, 0xb5, 0x13, 0xb0, 0x61,
+ 0x81, 0x9d, 0x86, 0x1c, 0xe6, 0xd8, 0x49, 0xf0, 0xfa, 0x38, 0x4b, 0xed,
+ 0x80, 0x2d, 0x6c, 0x5b, 0x02, 0xc5, 0xf3, 0x39, 0x0d, 0x62, 0xc6, 0x6d,
+ 0x3d, 0xa1, 0x9c, 0xdf, 0xb1, 0xfb, 0x97, 0x16, 0x2f, 0xe7, 0x9b, 0xd8,
+ 0x5e, 0x58, 0xa0, 0x1e, 0xb9, 0x85, 0x35, 0x24, 0xcb, 0x5a, 0x11, 0x1c,
+ 0x84, 0x15, 0xf7, 0x5f, 0x6e, 0x96, 0x2f, 0x85, 0xf8, 0x3a, 0xc5, 0xff,
+ 0xf0, 0xb5, 0xa8, 0x2c, 0x35, 0xbf, 0xfc, 0x0d, 0x62, 0xa1, 0x13, 0x38,
+ 0x4b, 0xa2, 0x3b, 0xef, 0xc0, 0x89, 0x62, 0xf8, 0x4f, 0xdf, 0x96, 0x2e,
+ 0x2f, 0x2c, 0x5f, 0xff, 0xfc, 0x6e, 0x6b, 0x4c, 0x7d, 0xb3, 0x48, 0x47,
+ 0xee, 0x5c, 0xe4, 0x6b, 0xa5, 0x8b, 0xbe, 0xeb, 0x16, 0x76, 0x44, 0x96,
+ 0xf7, 0xbb, 0xe6, 0x36, 0x0e, 0xb1, 0x7f, 0x41, 0x7b, 0xf8, 0x35, 0x8a,
+ 0x83, 0xd0, 0xe1, 0x1d, 0xe1, 0x0e, 0x16, 0x2f, 0xff, 0x98, 0x6c, 0xfe,
+ 0x67, 0xf6, 0xde, 0x34, 0xcb, 0x15, 0x25, 0xff, 0xe1, 0x94, 0x64, 0x39,
+ 0x4d, 0x84, 0x1f, 0x64, 0x0c, 0x5f, 0x34, 0xb2, 0x7d, 0x43, 0x4c, 0xe5,
+ 0xdf, 0x22, 0x72, 0x42, 0x85, 0x4f, 0x1e, 0x77, 0x90, 0xee, 0x0e, 0xd8,
+ 0x22, 0xc5, 0xe9, 0xe2, 0x75, 0x8a, 0x58, 0xbf, 0xb0, 0xe3, 0xfe, 0x71,
+ 0x62, 0xfd, 0x3e, 0xde, 0x9a, 0x75, 0x8b, 0xfb, 0x9d, 0x74, 0xe4, 0x6a,
+ 0xc5, 0x05, 0x88, 0x99, 0x9c, 0x33, 0x45, 0xde, 0x2e, 0xbf, 0xc5, 0xb7,
+ 0x7f, 0x72, 0xe4, 0xcb, 0x17, 0xfd, 0x2e, 0x7d, 0xb0, 0xb3, 0x7a, 0xc5,
+ 0xff, 0xfe, 0x1f, 0xf3, 0xde, 0x72, 0xeb, 0x1b, 0x4c, 0x78, 0x35, 0x62,
+ 0xe9, 0xfb, 0x58, 0xbf, 0x7d, 0xf7, 0x60, 0x0b, 0x14, 0x34, 0xc6, 0xfb,
+ 0x3b, 0x63, 0xa7, 0x61, 0x08, 0x35, 0x7e, 0xda, 0x1c, 0xf1, 0x3a, 0xc5,
+ 0xf8, 0xb3, 0xef, 0xe5, 0x8a, 0x91, 0xea, 0xcc, 0x5d, 0x7f, 0x1a, 0xdd,
+ 0xf0, 0x5c, 0x58, 0xad, 0x1e, 0xa1, 0x11, 0xdf, 0x0f, 0x6c, 0x6e, 0xac,
+ 0x54, 0x2a, 0x9c, 0xc8, 0xd7, 0x9a, 0x1e, 0xa1, 0x90, 0xdf, 0xbd, 0xb7,
+ 0x7e, 0x0d, 0x62, 0xff, 0x46, 0xd2, 0xcd, 0xf9, 0xf5, 0x8b, 0x32, 0xc5,
+ 0xff, 0x08, 0xb6, 0xcc, 0xd3, 0x8a, 0x65, 0x8b, 0xfb, 0x07, 0x34, 0xa3,
+ 0x75, 0x62, 0xff, 0xef, 0x1b, 0x1d, 0xcb, 0x9d, 0xca, 0x0d, 0x58, 0xb1,
+ 0xd6, 0x2f, 0xe3, 0x93, 0x9b, 0xf6, 0xda, 0x7b, 0x93, 0xa5, 0x5f, 0xf1,
+ 0xf8, 0xf3, 0x04, 0xfe, 0x4e, 0xb1, 0x50, 0x88, 0x5c, 0x47, 0xa9, 0xd3,
+ 0x73, 0xd1, 0xff, 0xa3, 0x13, 0xbf, 0xf4, 0xfb, 0x4b, 0x3d, 0xcf, 0xe1,
+ 0xab, 0x17, 0x61, 0x2c, 0x5e, 0x94, 0x01, 0x62, 0x86, 0x6c, 0xf0, 0x5a,
+ 0xfe, 0x6d, 0x31, 0xe0, 0xd5, 0x8b, 0xfd, 0x9f, 0xfc, 0x76, 0xfb, 0xab,
+ 0x17, 0x81, 0xcd, 0xb8, 0x7c, 0xbc, 0x2e, 0xad, 0x22, 0xe8, 0xa1, 0x0b,
+ 0x7c, 0x0e, 0x6e, 0xf4, 0xb1, 0x50, 0x9b, 0xfb, 0x46, 0x60, 0x22, 0x7b,
+ 0xf7, 0x5f, 0x8d, 0x4c, 0xb1, 0x77, 0x99, 0x62, 0xbe, 0x78, 0x5c, 0x2b,
+ 0xbf, 0x03, 0x3c, 0x1c, 0xeb, 0x17, 0xf8, 0xb0, 0xc0, 0x9e, 0xcf, 0xac,
+ 0x5f, 0xdc, 0xcf, 0xf9, 0x8d, 0x58, 0xbf, 0xee, 0x7c, 0x53, 0x6d, 0x33,
+ 0x77, 0xb5, 0x8b, 0x19, 0x32, 0x2a, 0x78, 0x6d, 0xe2, 0xfb, 0xf7, 0x33,
+ 0xc1, 0xce, 0xb1, 0x6f, 0x2c, 0x5b, 0x8b, 0x17, 0x7f, 0x69, 0xa6, 0x93,
+ 0xb1, 0x2b, 0x8c, 0xf4, 0x22, 0x03, 0x13, 0xef, 0x4f, 0x23, 0x56, 0x2a,
+ 0x13, 0xda, 0xc8, 0x6a, 0x3c, 0x2e, 0x04, 0x5d, 0x5b, 0x13, 0x28, 0x1a,
+ 0x05, 0x25, 0x2d, 0x53, 0x12, 0x0d, 0x2d, 0xe8, 0xd9, 0xa3, 0x84, 0xfc,
+ 0x76, 0xee, 0xee, 0x51, 0xfe, 0x5f, 0xdd, 0xcb, 0x9b, 0x60, 0x96, 0x2f,
+ 0xfe, 0x93, 0xf3, 0x27, 0x7f, 0x4f, 0x86, 0x2c, 0x5f, 0xf6, 0x7f, 0x68,
+ 0x6f, 0xbb, 0xfc, 0x58, 0xbf, 0xbf, 0x9d, 0x4a, 0x0e, 0xb1, 0x7f, 0xbf,
+ 0x92, 0x72, 0xce, 0xd6, 0x2b, 0x0f, 0x8b, 0xc5, 0xf7, 0xff, 0xfe, 0x94,
+ 0x4f, 0xdc, 0xb8, 0xc6, 0xed, 0xe6, 0x74, 0xc7, 0x16, 0xa7, 0x58, 0xbd,
+ 0xee, 0x86, 0xb1, 0x7f, 0xb0, 0xcd, 0xbf, 0x6c, 0x3a, 0xc5, 0xff, 0xf4,
+ 0xf8, 0xc5, 0xe2, 0xcd, 0xfb, 0x78, 0x61, 0x2c, 0x5c, 0xe0, 0xda, 0x8a,
+ 0x99, 0xc7, 0xf8, 0x6d, 0x5d, 0xa6, 0xb8, 0x51, 0x8f, 0x5f, 0xff, 0xcd,
+ 0xee, 0x61, 0xac, 0x44, 0x27, 0x07, 0x9c, 0x0b, 0x17, 0xf7, 0xf0, 0xbb,
+ 0x83, 0x56, 0x2f, 0xe7, 0x2f, 0x0b, 0x53, 0xac, 0x54, 0x2b, 0x78, 0x63,
+ 0x10, 0x23, 0x94, 0x28, 0x7d, 0x1b, 0xee, 0xf2, 0xa3, 0x16, 0x83, 0x2f,
+ 0xbb, 0xbf, 0x2c, 0x58, 0x22, 0xc5, 0x6d, 0x35, 0xa3, 0x19, 0xbd, 0x8d,
+ 0x32, 0xc5, 0xff, 0x9b, 0x26, 0xdb, 0xc8, 0xfb, 0xee, 0xac, 0x5f, 0xe7,
+ 0xef, 0xf9, 0xe0, 0x3a, 0xc5, 0xd9, 0x32, 0xc5, 0x61, 0xe6, 0x31, 0xa5,
+ 0xff, 0xa3, 0xfb, 0x75, 0x93, 0xe3, 0x9d, 0x62, 0xff, 0xf7, 0x05, 0x85,
+ 0xb4, 0xb3, 0xff, 0x71, 0xac, 0x5f, 0xec, 0x9f, 0x6c, 0xd3, 0x83, 0x4b,
+ 0x15, 0x24, 0x42, 0xf9, 0x2e, 0xf8, 0xa3, 0x50, 0xb1, 0x7f, 0xff, 0x0f,
+ 0x6f, 0x1b, 0x72, 0x08, 0x1f, 0xc2, 0xc6, 0xfa, 0xc5, 0xff, 0xe6, 0xdc,
+ 0x82, 0x07, 0xf0, 0xb1, 0xbe, 0xb1, 0x7c, 0x58, 0x7d, 0xa4, 0x8a, 0x8e,
+ 0x2f, 0x5d, 0x1c, 0x58, 0xbf, 0xee, 0xf2, 0x3b, 0x98, 0xa0, 0xeb, 0x17,
+ 0xff, 0xd3, 0xe0, 0xf6, 0x9d, 0xe5, 0xa6, 0x9d, 0xce, 0xb1, 0x7f, 0x77,
+ 0xcf, 0xe3, 0xe9, 0x62, 0xff, 0xff, 0xcc, 0x7d, 0x36, 0x76, 0x42, 0xf4,
+ 0x7f, 0x6e, 0xf6, 0xf4, 0xd0, 0xb1, 0x4c, 0x8f, 0x47, 0x54, 0xf1, 0x7d,
+ 0xff, 0xa0, 0xbd, 0x12, 0x62, 0x36, 0x16, 0x2a, 0x75, 0xc6, 0xa1, 0x8e,
+ 0x9b, 0x09, 0x0e, 0x88, 0x3b, 0x86, 0x33, 0x11, 0xcd, 0x0c, 0x93, 0x9d,
+ 0x7c, 0x5f, 0xd1, 0x97, 0xef, 0x2e, 0xbf, 0xfe, 0xc7, 0x9f, 0xf0, 0xde,
+ 0xe4, 0x4f, 0x9c, 0x58, 0xbf, 0xda, 0x9e, 0x1b, 0x58, 0x4b, 0x17, 0x8d,
+ 0xe4, 0xcb, 0x15, 0x87, 0xa7, 0xd9, 0x9d, 0x8e, 0xb1, 0xb4, 0xd1, 0x5f,
+ 0x4c, 0xd9, 0x3a, 0xc5, 0xe2, 0xc1, 0xac, 0x5f, 0x81, 0x82, 0xd4, 0xeb,
+ 0x17, 0x07, 0xc5, 0x8b, 0xc3, 0xfc, 0x2c, 0x6d, 0x2e, 0x6b, 0x0f, 0xc4,
+ 0x48, 0x77, 0xdb, 0x7e, 0xf3, 0x2c, 0x54, 0x26, 0x39, 0x84, 0x9d, 0x92,
+ 0x14, 0x23, 0x78, 0x43, 0x7e, 0x28, 0xc3, 0x27, 0x58, 0xbd, 0xb8, 0x2f,
+ 0x2c, 0x5f, 0xba, 0x8f, 0xc1, 0xd6, 0x2f, 0xde, 0xe1, 0x31, 0xab, 0x17,
+ 0xfc, 0xe6, 0xe7, 0x51, 0xf8, 0x3a, 0xc5, 0xfb, 0x07, 0xad, 0x42, 0xc5,
+ 0x6c, 0x48, 0xfe, 0x91, 0x4e, 0x10, 0x9c, 0xa4, 0x8a, 0x4c, 0x3a, 0xbf,
+ 0xbb, 0xe6, 0x61, 0x1a, 0xb1, 0x7c, 0x70, 0xe0, 0x0b, 0x17, 0xe0, 0x41,
+ 0xe3, 0x4b, 0x17, 0xff, 0xa7, 0x1e, 0x9f, 0xa2, 0xcd, 0xfa, 0x6e, 0x2c,
+ 0x54, 0x26, 0x49, 0x8b, 0x6c, 0x5e, 0xe4, 0x82, 0x28, 0xbb, 0xdc, 0x58,
+ 0xbf, 0xf3, 0xf3, 0x6c, 0x4c, 0xdf, 0x73, 0xac, 0x5f, 0xde, 0xfb, 0xcc,
+ 0x19, 0xd6, 0x29, 0x62, 0xdf, 0x58, 0xaf, 0x97, 0xce, 0x19, 0x76, 0x71,
+ 0x62, 0xe7, 0xd2, 0xc5, 0x81, 0x23, 0x5d, 0xa1, 0x7b, 0xe7, 0x90, 0x63,
+ 0x58, 0xb7, 0xa0, 0xf2, 0xfe, 0x4f, 0x53, 0x26, 0x9e, 0xe8, 0x20, 0x4f,
+ 0x28, 0x4c, 0x5c, 0x70, 0xd6, 0x2e, 0x81, 0xac, 0x5d, 0xc6, 0x58, 0xbb,
+ 0xb0, 0x2c, 0x57, 0xcf, 0x1c, 0x2e, 0x2e, 0x21, 0x7b, 0xff, 0x4c, 0xdc,
+ 0x0f, 0xb0, 0x3b, 0x4e, 0xb1, 0x7d, 0xd8, 0x35, 0x0b, 0x16, 0xe6, 0xd3,
+ 0xe7, 0x84, 0x3b, 0x86, 0xcb, 0x15, 0x0c, 0xd6, 0xa9, 0xe1, 0x59, 0x93,
+ 0x91, 0xbd, 0x42, 0xd9, 0xa3, 0xe1, 0xd4, 0xa7, 0x0f, 0xa3, 0xbc, 0x6c,
+ 0xe0, 0x42, 0x26, 0x0e, 0x42, 0x6b, 0x79, 0x4d, 0xed, 0xff, 0xc5, 0x8b,
+ 0xe6, 0x3c, 0x7d, 0x62, 0xfc, 0xff, 0xda, 0x38, 0x58, 0xa6, 0x3e, 0xbf,
+ 0x8f, 0xf8, 0x8a, 0xfe, 0xf1, 0x44, 0xb3, 0xcb, 0x17, 0xd8, 0x4f, 0x25,
+ 0x8b, 0xef, 0x70, 0x3e, 0x6d, 0x3c, 0xed, 0x88, 0xb6, 0xf4, 0x7b, 0x8b,
+ 0x17, 0xf3, 0x4f, 0x9f, 0x17, 0x96, 0x28, 0x8f, 0x33, 0xc3, 0xb6, 0xc5,
+ 0x8b, 0xdc, 0x83, 0x56, 0x2b, 0xe6, 0xbf, 0xc2, 0x36, 0x99, 0x62, 0xfe,
+ 0xc1, 0x67, 0xfa, 0x9d, 0x62, 0xa0, 0xf0, 0xf8, 0x27, 0x7e, 0xdb, 0x83,
+ 0xc2, 0x58, 0xae, 0xcf, 0x28, 0x88, 0x6f, 0x7e, 0x06, 0xb1, 0x50, 0x8e,
+ 0xdc, 0x85, 0x74, 0xc4, 0x57, 0xff, 0xf0, 0xb6, 0xf5, 0xf6, 0x19, 0x43,
+ 0xcf, 0xd7, 0xdf, 0x4b, 0x17, 0xf6, 0x68, 0x0c, 0x5e, 0x58, 0xbb, 0xbe,
+ 0xd6, 0x2c, 0x7d, 0xa7, 0x8e, 0x72, 0xdb, 0xf7, 0x9a, 0x72, 0x75, 0x8b,
+ 0xff, 0xbd, 0xcd, 0xa1, 0x3d, 0x9f, 0xf3, 0x1d, 0x62, 0xe9, 0xe1, 0x62,
+ 0xa4, 0x88, 0xa2, 0x28, 0xf2, 0x55, 0xfd, 0xf7, 0x91, 0xf4, 0xcb, 0x17,
+ 0xff, 0x1a, 0x6b, 0xfb, 0x9e, 0x28, 0xee, 0x4b, 0x17, 0xf6, 0x63, 0x97,
+ 0xb8, 0xb1, 0x7e, 0x28, 0x96, 0x79, 0x62, 0x88, 0xf4, 0xfc, 0x59, 0x50,
+ 0x8b, 0xc9, 0x42, 0x6e, 0xfc, 0x42, 0x99, 0xc6, 0xb1, 0x73, 0x71, 0x62,
+ 0xc7, 0x58, 0xbd, 0xac, 0xed, 0x62, 0xf6, 0x34, 0xeb, 0x17, 0xd0, 0x73,
+ 0xb2, 0xc5, 0xb2, 0x73, 0x7f, 0xe1, 0xda, 0x1a, 0x2b, 0x7e, 0x2e, 0x01,
+ 0x22, 0x5d, 0xbe, 0xc3, 0x8b, 0xcb, 0x17, 0xfe, 0x8e, 0x8b, 0x37, 0x84,
+ 0xd3, 0xf6, 0xb1, 0x7f, 0x9b, 0x3b, 0x09, 0xa7, 0xed, 0x62, 0xe2, 0xce,
+ 0x1f, 0xd8, 0x44, 0x4b, 0xe9, 0xc5, 0xae, 0x96, 0x2f, 0xff, 0x67, 0x8a,
+ 0x3a, 0xda, 0x59, 0xcf, 0x89, 0x62, 0xff, 0x31, 0x67, 0x9f, 0x98, 0xb1,
+ 0x7f, 0x9b, 0x3b, 0x09, 0xa7, 0xed, 0x62, 0xd9, 0x31, 0xf4, 0x04, 0x31,
+ 0xbf, 0xe3, 0x60, 0xa5, 0x9f, 0x63, 0xac, 0x5c, 0xe6, 0xed, 0x4d, 0xae,
+ 0x72, 0xef, 0x93, 0x14, 0x2d, 0x3c, 0x55, 0x7e, 0x6e, 0x72, 0x0e, 0xb1,
+ 0x50, 0xae, 0x85, 0xa1, 0xad, 0xa3, 0xc2, 0x94, 0x13, 0xbd, 0x7a, 0xa1,
+ 0x92, 0x1d, 0x8f, 0x86, 0xc2, 0x39, 0xa3, 0x3d, 0xd1, 0xa1, 0xe1, 0x4e,
+ 0xf0, 0xb4, 0x01, 0x79, 0x43, 0xa8, 0x52, 0xf2, 0x2f, 0xc3, 0x62, 0x71,
+ 0xac, 0x5e, 0xe0, 0xfb, 0x58, 0xbd, 0xfd, 0x8b, 0x4b, 0x17, 0x03, 0xa5,
+ 0x8b, 0xff, 0xd9, 0x37, 0xe0, 0x8d, 0x2c, 0xf7, 0xc4, 0xb1, 0x5b, 0x51,
+ 0x0e, 0x69, 0x1f, 0xc6, 0x6f, 0xba, 0x13, 0xc9, 0x62, 0xb6, 0xa3, 0xf6,
+ 0x50, 0xa6, 0xec, 0xce, 0x99, 0x35, 0xcd, 0x46, 0x49, 0x7f, 0x6b, 0xf9,
+ 0xa1, 0x62, 0xc5, 0xff, 0xfd, 0x9d, 0xcb, 0x9e, 0xfc, 0x1e, 0x18, 0x7b,
+ 0x60, 0x28, 0xb1, 0x7f, 0xf8, 0xa6, 0x63, 0xeb, 0x3b, 0x97, 0x05, 0x32,
+ 0xc5, 0xff, 0xe2, 0xeb, 0xef, 0xed, 0xba, 0xcf, 0x3f, 0x6b, 0x15, 0x89,
+ 0x96, 0x31, 0x73, 0xb1, 0x09, 0x3a, 0xf7, 0x78, 0x6a, 0xc5, 0xfd, 0x93,
+ 0xce, 0x2d, 0x4e, 0xb1, 0x6d, 0x7c, 0xf4, 0x48, 0x7e, 0xfd, 0xa2, 0x27,
+ 0xfa, 0xc5, 0xfc, 0x5b, 0x7a, 0xe0, 0x06, 0xb1, 0x50, 0x88, 0x06, 0x27,
+ 0x72, 0x7b, 0xff, 0xf9, 0xb9, 0xfc, 0xd6, 0xa2, 0x7d, 0xb8, 0x43, 0xfc,
+ 0x2c, 0x5f, 0xf8, 0x5c, 0xda, 0x70, 0xfe, 0xff, 0x85, 0x8b, 0xf6, 0x78,
+ 0x59, 0xda, 0xc5, 0xe3, 0x73, 0xb5, 0x8b, 0xa2, 0x6d, 0xa7, 0x91, 0xe2,
+ 0x9a, 0xc4, 0xc6, 0x09, 0x74, 0x50, 0x8b, 0xbf, 0xff, 0x8c, 0xf6, 0x31,
+ 0xf6, 0x96, 0x74, 0xda, 0xd3, 0x4e, 0xb1, 0x7f, 0xff, 0xfe, 0x11, 0x6d,
+ 0x31, 0xfb, 0x96, 0x9c, 0x1b, 0x78, 0x28, 0xef, 0xf8, 0xc5, 0x86, 0xac,
+ 0x5f, 0xff, 0xff, 0xee, 0xb3, 0xa2, 0xcf, 0x7c, 0x5f, 0x7e, 0xe5, 0xcf,
+ 0x6b, 0x0c, 0xc6, 0x1f, 0xb8, 0xcb, 0x17, 0xff, 0xfb, 0xc2, 0xc2, 0xda,
+ 0xd9, 0xe2, 0x80, 0x6d, 0xc6, 0x1a, 0xc5, 0xff, 0x1f, 0x0f, 0xb4, 0xfb,
+ 0xbb, 0xe4, 0xb1, 0x7f, 0xff, 0xfb, 0x36, 0xe8, 0x3e, 0x46, 0xde, 0x36,
+ 0x14, 0xdc, 0xf3, 0x64, 0xe5, 0x0b, 0x15, 0xa4, 0xc8, 0x0e, 0xc5, 0xf4,
+ 0x2b, 0xff, 0xed, 0x6b, 0x3d, 0xcf, 0xb6, 0x6d, 0xf8, 0x21, 0x62, 0xa1,
+ 0x51, 0xab, 0x47, 0x64, 0x23, 0x1b, 0xff, 0xfa, 0x3f, 0x83, 0x34, 0x51,
+ 0xfc, 0xf4, 0x1d, 0xfc, 0xb1, 0x50, 0xae, 0xbf, 0x17, 0xff, 0x2a, 0xfc,
+ 0x46, 0xd7, 0xff, 0x61, 0x16, 0x7f, 0x07, 0xf1, 0x4c, 0xb1, 0x7f, 0xd9,
+ 0x05, 0xd6, 0x7b, 0xec, 0xb1, 0x7f, 0xff, 0xfc, 0xd3, 0x7f, 0x39, 0xac,
+ 0xeb, 0x6f, 0xdb, 0x0b, 0x37, 0x96, 0x0c, 0x44, 0xb1, 0x7e, 0xc2, 0xe8,
+ 0x33, 0xac, 0x5f, 0xfd, 0xfc, 0x82, 0x98, 0xb3, 0xdc, 0x75, 0x8b, 0x49,
+ 0x93, 0x69, 0xd2, 0x21, 0x1c, 0x7a, 0x10, 0x01, 0x0a, 0xaf, 0xa3, 0xad,
+ 0x62, 0xc5, 0xff, 0x82, 0x7a, 0x39, 0x34, 0x9f, 0x53, 0xac, 0x5e, 0xf3,
+ 0x1a, 0xb1, 0x76, 0x1f, 0x69, 0xf1, 0x6c, 0x48, 0x97, 0xff, 0x34, 0xee,
+ 0x73, 0xb6, 0xd1, 0xb6, 0xf5, 0x8a, 0x92, 0x60, 0x43, 0x84, 0x2e, 0x8d,
+ 0x2f, 0x4c, 0xdb, 0xab, 0x17, 0xff, 0xf7, 0x9a, 0x7c, 0x1e, 0xd3, 0xbc,
+ 0xb4, 0xd3, 0xb9, 0xd6, 0x2f, 0xf4, 0xee, 0x72, 0x8d, 0x4c, 0xb1, 0x7f,
+ 0xdd, 0xe1, 0xa0, 0x3e, 0x6d, 0xd6, 0x22, 0x51, 0x97, 0xef, 0x80, 0xef,
+ 0x32, 0xc5, 0xa1, 0x62, 0xf6, 0x14, 0xfb, 0x4d, 0xa7, 0x44, 0x77, 0xff,
+ 0xd8, 0x2d, 0x6d, 0x9b, 0xe2, 0x35, 0xb0, 0x8d, 0x58, 0xbf, 0x8e, 0x20,
+ 0x6d, 0x3e, 0x96, 0x2f, 0xff, 0x9f, 0xd1, 0xa1, 0x1d, 0xb9, 0xb7, 0x92,
+ 0xe2, 0xc5, 0xff, 0x6a, 0x78, 0x9e, 0x71, 0x6a, 0x75, 0x8b, 0xff, 0xf1,
+ 0x41, 0xbb, 0x4e, 0x26, 0xe4, 0x7c, 0xe1, 0xf4, 0xb1, 0x7f, 0xed, 0xb3,
+ 0x7c, 0x46, 0xb6, 0x11, 0xab, 0x17, 0xff, 0xe8, 0xdd, 0xdb, 0xdc, 0xa2,
+ 0x7e, 0xe5, 0xc2, 0x73, 0x56, 0x2f, 0xf1, 0x6d, 0xe0, 0xb7, 0x05, 0xa5,
+ 0x8a, 0xc4, 0x6e, 0xfd, 0x10, 0x4b, 0xf7, 0xff, 0xff, 0xb3, 0xa7, 0x9f,
+ 0x6f, 0x1b, 0x72, 0x08, 0x1e, 0x08, 0x50, 0x58, 0xde, 0x58, 0xbf, 0xff,
+ 0xbd, 0x05, 0x93, 0xed, 0x9c, 0x5a, 0x97, 0xa2, 0x6e, 0x2c, 0x5d, 0x1d,
+ 0xfd, 0x1b, 0xc1, 0x1f, 0x6a, 0x15, 0x5a, 0x9c, 0xff, 0x91, 0x9c, 0x0a,
+ 0x30, 0xdb, 0xf8, 0xb3, 0x79, 0x67, 0x16, 0x2f, 0x76, 0xe4, 0xb1, 0x61,
+ 0xed, 0x3c, 0xbc, 0x2e, 0xbf, 0xfb, 0x6f, 0x3e, 0x2d, 0xbe, 0xe7, 0x23,
+ 0x4b, 0x17, 0xff, 0xf4, 0x68, 0x1b, 0x63, 0x7b, 0xfe, 0x35, 0xac, 0xf7,
+ 0x16, 0x2a, 0x74, 0x55, 0x7d, 0x2e, 0xff, 0xd2, 0x8f, 0x0b, 0xad, 0xbc,
+ 0xf3, 0x2c, 0x5f, 0xff, 0x7e, 0x27, 0xda, 0x59, 0xbd, 0xff, 0xf8, 0xed,
+ 0x62, 0xff, 0xff, 0xbb, 0xe3, 0x61, 0x9b, 0x7f, 0x9e, 0xe6, 0x4f, 0xb7,
+ 0x18, 0x6b, 0x14, 0x34, 0x61, 0x62, 0xad, 0xff, 0xbc, 0xdd, 0xc8, 0xa3,
+ 0x68, 0x4e, 0x96, 0x2f, 0xff, 0x41, 0xcb, 0x37, 0x96, 0x6f, 0xcd, 0x49,
+ 0x62, 0xb1, 0x12, 0x24, 0x8b, 0x7f, 0xfd, 0x1d, 0xcb, 0x9f, 0x6c, 0xf7,
+ 0x72, 0x6f, 0xac, 0x5f, 0xf1, 0x66, 0xb3, 0xac, 0x61, 0xac, 0x5f, 0xd3,
+ 0xfa, 0x62, 0x83, 0xac, 0x5f, 0x9e, 0x26, 0x89, 0x96, 0x2f, 0xd8, 0x3f,
+ 0x88, 0xc5, 0x8b, 0xa2, 0x6d, 0xa7, 0xa6, 0x45, 0x37, 0xff, 0xf6, 0x4f,
+ 0x8c, 0x32, 0x17, 0xf6, 0xc0, 0xde, 0x6e, 0x2c, 0x5f, 0xd9, 0xf6, 0xd7,
+ 0xdd, 0x62, 0xfd, 0xf6, 0xd7, 0xdd, 0x62, 0xec, 0x33, 0x69, 0xea, 0xe1,
+ 0x6d, 0x42, 0xe7, 0x76, 0x43, 0x4f, 0xb2, 0x46, 0x8c, 0x16, 0x68, 0x59,
+ 0xe8, 0x87, 0xea, 0x4e, 0x70, 0x50, 0x83, 0xe1, 0x7f, 0xa1, 0x67, 0x7d,
+ 0xec, 0xc1, 0xac, 0x54, 0xed, 0xa6, 0x30, 0xe3, 0x0c, 0x36, 0x34, 0x5e,
+ 0xa5, 0xf1, 0xf7, 0x1d, 0x6b, 0x46, 0xb1, 0x31, 0xb6, 0xa1, 0x6a, 0x78,
+ 0x43, 0xfc, 0xd4, 0x0a, 0xa4, 0x65, 0xc9, 0x61, 0x1e, 0x9d, 0x83, 0x09,
+ 0x0b, 0x2b, 0xff, 0xe6, 0xe6, 0x0e, 0x7c, 0x33, 0x69, 0x16, 0x76, 0xb1,
+ 0x7d, 0x2c, 0x2f, 0xac, 0x5f, 0xef, 0x16, 0x7b, 0xf9, 0x3a, 0xc5, 0xda,
+ 0xc5, 0x8b, 0xf8, 0x27, 0x98, 0x9c, 0xeb, 0x14, 0xb1, 0x7d, 0xcc, 0x89,
+ 0xf6, 0x9b, 0xb3, 0x97, 0xd4, 0xe8, 0x8c, 0xf2, 0x95, 0xef, 0xb9, 0xab,
+ 0x17, 0xfb, 0x6e, 0xb3, 0xb9, 0x31, 0xd6, 0x2b, 0x47, 0xf3, 0xe2, 0x43,
+ 0x07, 0xaf, 0xfc, 0xfa, 0xfe, 0x7a, 0x09, 0x80, 0xb1, 0x60, 0x8b, 0x17,
+ 0xa7, 0x3f, 0x4b, 0x17, 0xe6, 0xc2, 0xcd, 0xeb, 0x17, 0xd8, 0xd3, 0x6d,
+ 0xec, 0xf2, 0x3e, 0x41, 0x74, 0x69, 0x62, 0xff, 0x0b, 0xd9, 0x87, 0x01,
+ 0x8b, 0x17, 0xc5, 0x93, 0xed, 0x98, 0xf3, 0x00, 0x2f, 0x7b, 0xcd, 0x3a,
+ 0xc5, 0xb7, 0x16, 0x2a, 0x46, 0xcf, 0x74, 0x7a, 0xff, 0x74, 0xdc, 0xc1,
+ 0xed, 0x1a, 0xc5, 0xfd, 0xdc, 0xb9, 0xb7, 0xcc, 0xb1, 0x6c, 0xf9, 0xf4,
+ 0x98, 0x6f, 0x7f, 0xe9, 0x46, 0x03, 0xf9, 0x85, 0xd2, 0xc5, 0xff, 0xef,
+ 0xb1, 0x0f, 0x68, 0x7d, 0x16, 0x7f, 0x16, 0x2f, 0xf9, 0xfd, 0xc9, 0xa4,
+ 0x22, 0xf2, 0xc5, 0x62, 0x31, 0xa6, 0x3e, 0x02, 0x6d, 0xff, 0x7d, 0x8f,
+ 0x18, 0x5e, 0xe2, 0xc5, 0xff, 0xfe, 0x17, 0xb4, 0x29, 0xb6, 0xfa, 0x6f,
+ 0x88, 0x1e, 0x6c, 0x08, 0xb1, 0x7d, 0x1d, 0x41, 0xf6, 0xa3, 0x4b, 0xa3,
+ 0x02, 0x38, 0xa8, 0x5d, 0x8f, 0xc8, 0xce, 0x7a, 0x30, 0x63, 0xd9, 0x97,
+ 0x35, 0x08, 0x87, 0x6f, 0x28, 0x46, 0x84, 0x8f, 0x02, 0xff, 0xfe, 0xd6,
+ 0x39, 0xf6, 0x9a, 0xfd, 0xff, 0x3f, 0xf8, 0xf2, 0xc5, 0xf6, 0x60, 0x38,
+ 0xb1, 0x73, 0x18, 0xb1, 0x7b, 0x53, 0x49, 0x62, 0x86, 0x6d, 0xf0, 0x62,
+ 0xff, 0xe6, 0xee, 0x5c, 0xda, 0x36, 0xdf, 0x03, 0x58, 0xbd, 0xdc, 0x6e,
+ 0xac, 0x52, 0xc5, 0xff, 0x7b, 0xb9, 0x37, 0xfb, 0x93, 0x2c, 0x5d, 0x13,
+ 0x4c, 0x79, 0x1c, 0x0c, 0xa3, 0x51, 0xc4, 0xe9, 0x42, 0x69, 0xbe, 0xcf,
+ 0xbe, 0xf5, 0x8b, 0xfa, 0x59, 0xfc, 0xdf, 0xc5, 0x8b, 0x60, 0xcf, 0x52,
+ 0x62, 0x4b, 0xff, 0xef, 0x8b, 0x9b, 0x7e, 0xde, 0xfe, 0x6a, 0x37, 0xac,
+ 0x5f, 0xb8, 0xd9, 0xd9, 0xd6, 0x28, 0x67, 0xfd, 0xe5, 0x5b, 0xfb, 0x3b,
+ 0x2c, 0xc0, 0x2c, 0x56, 0x1e, 0x79, 0x11, 0x5f, 0xc5, 0x1d, 0xff, 0x27,
+ 0x58, 0xba, 0x0e, 0x35, 0x64, 0x78, 0xb2, 0x6c, 0x60, 0x5a, 0x84, 0x21,
+ 0x43, 0xd7, 0xc4, 0x17, 0xff, 0x6a, 0x0c, 0x08, 0x50, 0x67, 0x72, 0xe2,
+ 0xc5, 0xa1, 0x62, 0xf9, 0xb4, 0xfd, 0xac, 0x5b, 0xcc, 0x6d, 0x38, 0x23,
+ 0x43, 0x45, 0x23, 0x3f, 0x5f, 0xf3, 0x97, 0x5f, 0x63, 0x94, 0x2c, 0x5f,
+ 0xfc, 0x32, 0x79, 0xa6, 0x8f, 0x03, 0x38, 0xb1, 0x7f, 0xfc, 0x51, 0x3f,
+ 0xe1, 0xbd, 0xc6, 0x2e, 0xe4, 0xb1, 0x71, 0xc3, 0x58, 0xba, 0x26, 0x58,
+ 0xa8, 0x36, 0x2c, 0x33, 0x7f, 0xf3, 0x6f, 0x61, 0xed, 0x89, 0x86, 0xe6,
+ 0x2c, 0x5f, 0xff, 0xfe, 0x26, 0x37, 0xef, 0x36, 0xd2, 0x10, 0x4d, 0xb9,
+ 0xdc, 0xb0, 0x44, 0x0e, 0x2c, 0x5f, 0xff, 0x34, 0xbd, 0xcc, 0xdf, 0xac,
+ 0x07, 0x1f, 0xa5, 0x8b, 0xfd, 0x8e, 0x6e, 0xd3, 0x1c, 0xc5, 0x8b, 0xff,
+ 0xfd, 0x9d, 0x6d, 0x2c, 0xfb, 0x67, 0x36, 0xe3, 0x7f, 0x3a, 0x58, 0xb6,
+ 0x0d, 0x13, 0x9f, 0x38, 0xbf, 0xef, 0x68, 0x52, 0xee, 0x59, 0xe5, 0x8b,
+ 0xe6, 0x82, 0x9d, 0x62, 0x98, 0xf7, 0xbe, 0x79, 0x47, 0x54, 0x2d, 0xf8,
+ 0x40, 0x14, 0x3b, 0xf7, 0xc2, 0x1a, 0xff, 0xfe, 0x10, 0xdc, 0x81, 0xb7,
+ 0xd9, 0xf8, 0xf6, 0xb0, 0x6b, 0x17, 0xc7, 0x66, 0x31, 0x62, 0xa1, 0x19,
+ 0xf2, 0x4f, 0x75, 0xda, 0x25, 0x6f, 0x9c, 0x1f, 0xf4, 0xb2, 0xfb, 0xfd,
+ 0xa8, 0x9f, 0xed, 0x83, 0x58, 0xbe, 0x89, 0xb8, 0xcb, 0x15, 0x25, 0xd2,
+ 0xc1, 0x91, 0x61, 0xc7, 0x48, 0xcd, 0x2f, 0xf7, 0x47, 0x04, 0x69, 0x7f,
+ 0xff, 0x4a, 0x34, 0x69, 0xc9, 0xbb, 0x97, 0x07, 0xa6, 0x9d, 0x62, 0xff,
+ 0xff, 0x71, 0x84, 0x3d, 0xa6, 0x93, 0x8c, 0x59, 0xfd, 0xb3, 0x4c, 0xb1,
+ 0x6c, 0x99, 0x19, 0x1c, 0x5f, 0xbd, 0x13, 0x71, 0x62, 0xe1, 0x0d, 0x62,
+ 0xfe, 0xe1, 0x16, 0x03, 0x8b, 0x15, 0x31, 0xe2, 0xf8, 0x62, 0xff, 0xff,
+ 0xce, 0x3c, 0x27, 0xf7, 0x33, 0x40, 0x04, 0x67, 0x7e, 0xe3, 0x2c, 0x5b,
+ 0x63, 0x58, 0xa8, 0x75, 0x3e, 0x59, 0x5b, 0x0d, 0xf5, 0x18, 0x9f, 0x6a,
+ 0x6d, 0x3b, 0x63, 0xa8, 0x4b, 0x7e, 0x5c, 0x13, 0xcf, 0x21, 0x94, 0x66,
+ 0x9e, 0x29, 0x13, 0x19, 0x84, 0x7b, 0x8d, 0x77, 0xb9, 0x9d, 0x2c, 0x5f,
+ 0xa4, 0xc3, 0xc2, 0x58, 0xad, 0xa7, 0x8b, 0x03, 0xd7, 0xb8, 0xda, 0x58,
+ 0xbf, 0xf9, 0xdb, 0xd2, 0x82, 0xf7, 0x18, 0x6b, 0x15, 0x07, 0xc1, 0xf1,
+ 0xdb, 0xe2, 0xf3, 0x6f, 0x58, 0xbe, 0x90, 0x9f, 0xcb, 0x17, 0x46, 0xea,
+ 0xc5, 0xc2, 0xdd, 0x58, 0xbd, 0x05, 0x0b, 0x15, 0xd1, 0xe8, 0x68, 0x68,
+ 0xe3, 0x75, 0x08, 0xc7, 0xc2, 0x46, 0x73, 0xbe, 0xf7, 0x1c, 0x0b, 0x17,
+ 0xff, 0xc2, 0x9f, 0x6c, 0x37, 0xfa, 0x80, 0x1d, 0xe4, 0xb1, 0x7f, 0xe6,
+ 0xda, 0xda, 0x14, 0xef, 0xae, 0x96, 0x28, 0xd4, 0x4b, 0xfd, 0x52, 0xf9,
+ 0xbe, 0xf3, 0xac, 0x5f, 0xa0, 0x8e, 0x69, 0xab, 0x17, 0xf9, 0xb8, 0xc2,
+ 0x0b, 0x8e, 0x16, 0x2f, 0x47, 0xa1, 0x62, 0x86, 0x7f, 0xbe, 0x2a, 0xde,
+ 0x6f, 0x7e, 0xf9, 0xd8, 0xba, 0x58, 0xbe, 0xcf, 0x37, 0x16, 0x2b, 0x0f,
+ 0x2f, 0x85, 0x37, 0xa5, 0x07, 0x58, 0xb9, 0xc3, 0x58, 0xaf, 0x9b, 0x5e,
+ 0x0e, 0xdf, 0xfb, 0xdf, 0x6c, 0xc1, 0x96, 0x18, 0xb1, 0x58, 0x7b, 0xec,
+ 0x43, 0x7f, 0xee, 0x44, 0xd9, 0xf6, 0xd7, 0xdd, 0x62, 0xfe, 0xd6, 0x7f,
+ 0xb9, 0x71, 0x62, 0xec, 0xfa, 0xc5, 0x32, 0x21, 0xb4, 0x7e, 0x73, 0x0b,
+ 0xda, 0x63, 0x56, 0x2f, 0xfc, 0x7c, 0x6f, 0x3f, 0xbf, 0x1e, 0x58, 0xb9,
+ 0xbe, 0xb1, 0x6c, 0x58, 0xbf, 0xfe, 0x16, 0x37, 0xf3, 0xaf, 0xb6, 0xd3,
+ 0x0f, 0xd2, 0xc5, 0xef, 0x61, 0x8b, 0x16, 0x9c, 0x8f, 0xcf, 0xca, 0xb4,
+ 0x74, 0x56, 0x0a, 0x10, 0x97, 0xa7, 0x17, 0x96, 0x2f, 0xbe, 0xce, 0x05,
+ 0x8a, 0xc3, 0xc1, 0xf0, 0xfd, 0x0d, 0x34, 0xdc, 0x86, 0x18, 0x1a, 0x6f,
+ 0xff, 0x08, 0xb6, 0xe6, 0xa7, 0x3e, 0x73, 0xf8, 0xb1, 0x7c, 0x17, 0x27,
+ 0xf2, 0xc5, 0x4e, 0x7e, 0x62, 0x4d, 0xbf, 0xed, 0xa7, 0x62, 0xcf, 0x7d,
+ 0x96, 0x2f, 0xd3, 0xb9, 0x7b, 0x8b, 0x17, 0xf7, 0xde, 0x7d, 0xb2, 0xf2,
+ 0xc5, 0xf8, 0x81, 0x0d, 0xbd, 0x62, 0xfd, 0x30, 0x7c, 0x8c, 0x58, 0xa6,
+ 0x3d, 0x37, 0x29, 0xbf, 0x3e, 0x8b, 0xb6, 0x58, 0xbd, 0x34, 0x79, 0x62,
+ 0xa1, 0x37, 0x19, 0x11, 0xe1, 0xd3, 0x14, 0xfe, 0x10, 0xbe, 0x20, 0x11,
+ 0x45, 0xe8, 0x61, 0xac, 0x5e, 0xfb, 0x92, 0xc5, 0x4e, 0xc9, 0x7d, 0x94,
+ 0x20, 0xc7, 0x0e, 0x8c, 0x2d, 0x36, 0x17, 0x5d, 0x12, 0x34, 0x28, 0x26,
+ 0x7c, 0x3c, 0x2d, 0x7f, 0x0a, 0x67, 0x2f, 0x00, 0xf1, 0x47, 0x17, 0xe9,
+ 0x43, 0x3b, 0xd9, 0xcc, 0x1c, 0xb9, 0xbb, 0x58, 0xb0, 0x55, 0x62, 0xef,
+ 0xee, 0xac, 0x5f, 0xdb, 0x78, 0xdf, 0x63, 0xac, 0x5e, 0xf4, 0x1d, 0x62,
+ 0xb6, 0x23, 0xfe, 0x90, 0xb7, 0x63, 0x64, 0x61, 0x74, 0xa7, 0x58, 0xbb,
+ 0xb3, 0x56, 0x2f, 0xe3, 0xbc, 0xb5, 0x86, 0x2c, 0x5d, 0x9d, 0x8c, 0xf2,
+ 0x70, 0x6a, 0xf8, 0x2b, 0xcf, 0x62, 0xc5, 0xfe, 0xfb, 0x1f, 0xf8, 0x07,
+ 0x58, 0xbf, 0xf6, 0x16, 0x6b, 0xaf, 0xe0, 0x38, 0xb1, 0x7d, 0xd6, 0x10,
+ 0x16, 0x2f, 0xfd, 0xf8, 0x28, 0xeb, 0x51, 0x84, 0xb1, 0x43, 0x46, 0x93,
+ 0x19, 0xb9, 0xff, 0x88, 0xef, 0xec, 0x9e, 0x0d, 0x7e, 0x2c, 0x5f, 0xff,
+ 0x7d, 0xb5, 0xf7, 0xdb, 0x9d, 0xcb, 0x35, 0x3a, 0xc5, 0xfd, 0xf6, 0x1b,
+ 0x6b, 0xa5, 0x8b, 0xec, 0xeb, 0x3b, 0x58, 0xbf, 0xff, 0x3f, 0x63, 0xd1,
+ 0x39, 0x85, 0x80, 0x06, 0x01, 0x62, 0xee, 0xf9, 0xb5, 0x36, 0x71, 0x9d,
+ 0xe1, 0x7f, 0x4a, 0x9f, 0x2f, 0xf1, 0x25, 0xe9, 0xa0, 0xc5, 0x8b, 0xf7,
+ 0x8b, 0x33, 0x4b, 0x17, 0xfb, 0xf0, 0xc4, 0xfa, 0x35, 0x62, 0xfe, 0x86,
+ 0x27, 0xd1, 0xab, 0x17, 0xda, 0xd3, 0x6b, 0x69, 0xf0, 0x7c, 0xce, 0xfe,
+ 0x2c, 0x9b, 0x4f, 0xbd, 0x62, 0xfd, 0x93, 0x69, 0xf7, 0xac, 0x52, 0xc5,
+ 0xba, 0xda, 0x7c, 0xe4, 0x61, 0xbc, 0xae, 0x80, 0x8d, 0xb2, 0x85, 0x15,
+ 0x42, 0x75, 0x0c, 0x3e, 0xf1, 0xb1, 0x5e, 0x2c, 0x3a, 0xc5, 0xbb, 0x58,
+ 0xb9, 0xe5, 0x23, 0x5f, 0xc1, 0xcb, 0xff, 0xff, 0xdb, 0x4f, 0x19, 0xed,
+ 0xb9, 0x26, 0xde, 0x59, 0xcd, 0xb0, 0x37, 0x9b, 0x8b, 0x17, 0x8c, 0xe0,
+ 0x16, 0x2f, 0xec, 0x38, 0xdd, 0xfa, 0x58, 0xb8, 0xba, 0xda, 0x79, 0xbf,
+ 0x1f, 0xa9, 0x23, 0xf1, 0xe1, 0x99, 0x5d, 0x2f, 0xc3, 0xb4, 0x25, 0xa6,
+ 0x41, 0xd3, 0x11, 0xcb, 0x5e, 0x53, 0x00, 0x25, 0x07, 0x93, 0x18, 0xa3,
+ 0x28, 0xbd, 0xcf, 0x32, 0xc5, 0xe9, 0x81, 0xda, 0xc5, 0xff, 0x64, 0xbf,
+ 0x0d, 0xad, 0x42, 0xc5, 0xc6, 0xed, 0xe8, 0xfd, 0x40, 0x3b, 0xc2, 0x0b,
+ 0xdc, 0x0b, 0xf1, 0x62, 0xa0, 0xf8, 0x7b, 0x3f, 0xbe, 0x00, 0x05, 0xba,
+ 0xb1, 0x60, 0x2c, 0x5f, 0xb5, 0x3c, 0x6a, 0x75, 0x8b, 0xf3, 0x17, 0x83,
+ 0x3a, 0xc5, 0x41, 0xea, 0x00, 0xae, 0xf4, 0xb9, 0x8b, 0x17, 0xe0, 0xa9,
+ 0x46, 0x01, 0x62, 0xb4, 0x79, 0x00, 0x1d, 0xbf, 0xf3, 0x61, 0x9c, 0x14,
+ 0xc5, 0x07, 0x58, 0xbc, 0x27, 0xe2, 0xc5, 0x49, 0x1d, 0x18, 0xd2, 0x72,
+ 0x20, 0xd0, 0x2f, 0xf1, 0x87, 0x86, 0xd0, 0xb7, 0x56, 0x2e, 0x21, 0x2c,
+ 0x52, 0xc5, 0xb5, 0xb4, 0xd1, 0xf0, 0x5e, 0xfd, 0xb7, 0xb9, 0x0a, 0x75,
+ 0x8a, 0x83, 0xd7, 0x91, 0x4d, 0x62, 0x34, 0xc5, 0x0b, 0x2b, 0xff, 0xf9,
+ 0xb5, 0xb7, 0x1b, 0x08, 0xdf, 0xb6, 0x1f, 0x3a, 0x58, 0xbf, 0xec, 0xee,
+ 0x5c, 0xee, 0x42, 0xd2, 0xc5, 0xff, 0xff, 0x8f, 0xce, 0xbf, 0x1d, 0x77,
+ 0x22, 0x10, 0xf6, 0xb1, 0xae, 0x40, 0x58, 0xbf, 0xff, 0xd3, 0xea, 0x0f,
+ 0xc1, 0x46, 0xd8, 0xd4, 0x0f, 0xf0, 0x75, 0x8a, 0xc4, 0x6b, 0xb3, 0x9d,
+ 0xff, 0x4b, 0x6c, 0x6d, 0xf7, 0xf0, 0x96, 0x2b, 0x13, 0xce, 0x65, 0xcd,
+ 0x46, 0x28, 0xe4, 0x37, 0xe0, 0x71, 0xbb, 0x31, 0x62, 0xfd, 0xdc, 0x1e,
+ 0x78, 0x58, 0xbe, 0xee, 0x4d, 0xf5, 0x8b, 0xb3, 0xbf, 0x9e, 0x77, 0x8a,
+ 0xaf, 0xd3, 0x4a, 0x0a, 0x4b, 0x15, 0xa3, 0xd7, 0x01, 0x75, 0xfd, 0xdb,
+ 0xc8, 0xa0, 0xeb, 0x17, 0xff, 0xfc, 0x53, 0x7f, 0x3b, 0x94, 0x10, 0xf6,
+ 0x96, 0x6f, 0xd3, 0x71, 0x62, 0xff, 0x8a, 0x6f, 0x16, 0x4e, 0xe4, 0xb1,
+ 0x4c, 0x8a, 0x41, 0x35, 0xdf, 0xff, 0xfe, 0xd6, 0x9a, 0x7d, 0xbf, 0xcf,
+ 0x14, 0x4d, 0xfc, 0x9e, 0x3b, 0xf0, 0xba, 0x58, 0xbf, 0xff, 0xfa, 0x0d,
+ 0xfc, 0x6d, 0x2c, 0x11, 0xbb, 0x7b, 0x97, 0x18, 0x83, 0x89, 0xd6, 0x2f,
+ 0xc4, 0x0e, 0x10, 0x96, 0x2f, 0xd8, 0x28, 0xd4, 0xeb, 0x17, 0x9b, 0x09,
+ 0x62, 0xdd, 0x91, 0xe2, 0x70, 0xa6, 0xb1, 0x30, 0xe6, 0x7a, 0x13, 0x65,
+ 0xff, 0xf6, 0x04, 0x2c, 0x3b, 0x97, 0xb9, 0xb6, 0x0c, 0x58, 0xa8, 0x56,
+ 0x07, 0x90, 0xd2, 0x62, 0x2f, 0xc7, 0x1a, 0x22, 0xfb, 0xff, 0x78, 0xe7,
+ 0x79, 0xb6, 0x96, 0x18, 0xb1, 0x7f, 0xf6, 0x8b, 0xbc, 0xe0, 0xa6, 0x28,
+ 0x3a, 0xc5, 0xff, 0x31, 0xbf, 0x86, 0x9e, 0x0d, 0x58, 0xa6, 0x44, 0x0f,
+ 0x11, 0xab, 0x6a, 0x39, 0xa5, 0x0c, 0x4b, 0xff, 0x73, 0x3b, 0x93, 0x68,
+ 0xbb, 0xc5, 0x8b, 0xfc, 0x7e, 0x1c, 0xb3, 0xbd, 0xd5, 0x8b, 0xfc, 0x29,
+ 0x8b, 0x3e, 0xfe, 0x58, 0xa9, 0xd1, 0x59, 0x88, 0x04, 0x71, 0x7f, 0xe1,
+ 0x03, 0x85, 0x9c, 0xe4, 0x18, 0xb1, 0x7f, 0x14, 0xfb, 0x9f, 0x0f, 0x4b,
+ 0x15, 0x23, 0xf4, 0x74, 0x0b, 0xe3, 0x36, 0xce, 0xcb, 0x17, 0xe3, 0x07,
+ 0xf7, 0x3a, 0xc5, 0xfe, 0xee, 0x5c, 0xdb, 0xcf, 0x32, 0xc5, 0x41, 0xf1,
+ 0x31, 0x55, 0x62, 0x2a, 0x7f, 0x08, 0x9b, 0xff, 0x61, 0x9e, 0x1b, 0x67,
+ 0x72, 0xe2, 0xc5, 0xfe, 0xfc, 0x31, 0x3e, 0x8d, 0x58, 0xbf, 0xfc, 0x7d,
+ 0xb8, 0x20, 0xbb, 0x7d, 0x8e, 0xe3, 0x58, 0xb6, 0x4c, 0x88, 0x31, 0x19,
+ 0xdf, 0xf1, 0xf3, 0x9b, 0x66, 0x28, 0x3a, 0xc5, 0xff, 0xfb, 0x93, 0xbe,
+ 0xd1, 0xfe, 0x35, 0xac, 0xdf, 0x1d, 0xac, 0x5f, 0xfa, 0x0a, 0x5b, 0x43,
+ 0x09, 0x05, 0x25, 0x8a, 0x1a, 0x7d, 0xec, 0x4f, 0xa8, 0x62, 0x1c, 0xa7,
+ 0xc7, 0x86, 0x2e, 0x5f, 0xff, 0xa3, 0x27, 0xda, 0x3d, 0x34, 0xfe, 0x6c,
+ 0x29, 0xd6, 0x2f, 0xef, 0x03, 0x02, 0x61, 0x2c, 0x5f, 0xf0, 0xa0, 0xb6,
+ 0xb7, 0xa2, 0x65, 0x8b, 0xb4, 0x0d, 0xa7, 0xd4, 0x72, 0xfb, 0xed, 0xf8,
+ 0x2e, 0x96, 0x2f, 0xff, 0xf9, 0xf5, 0xfc, 0xf3, 0x61, 0x4f, 0xc8, 0xc2,
+ 0x1f, 0xe1, 0x62, 0xda, 0x58, 0xbf, 0xb0, 0x27, 0x98, 0xa7, 0x58, 0xbb,
+ 0xdb, 0x67, 0x3c, 0x22, 0x12, 0xa8, 0x4c, 0xb3, 0x0c, 0x3b, 0x26, 0x78,
+ 0x53, 0x5f, 0xff, 0xfb, 0xbc, 0x9c, 0x41, 0x36, 0xf7, 0x2f, 0x41, 0x9b,
+ 0x73, 0x40, 0x04, 0x2c, 0x5f, 0xf6, 0x4d, 0xb8, 0x2f, 0x67, 0x7e, 0x58,
+ 0xbd, 0x9a, 0x1a, 0xc5, 0xd1, 0x25, 0x8b, 0xff, 0xee, 0x6d, 0xd4, 0x75,
+ 0x85, 0x34, 0xb3, 0xdc, 0x58, 0xac, 0x46, 0x39, 0xcf, 0xc0, 0x3a, 0x21,
+ 0x7b, 0xff, 0xa7, 0x72, 0xcf, 0xe7, 0xb5, 0x86, 0x2c, 0x5f, 0xff, 0xff,
+ 0xb0, 0x46, 0x90, 0xbd, 0x36, 0x79, 0xbb, 0x91, 0x41, 0x67, 0xdb, 0x35,
+ 0x32, 0xc5, 0x62, 0x32, 0x7b, 0x45, 0xbf, 0xec, 0x33, 0xf0, 0x6e, 0x7b,
+ 0x8b, 0x17, 0xff, 0x39, 0x4e, 0x71, 0x30, 0xd8, 0x99, 0x62, 0x98, 0xff,
+ 0x8c, 0x3b, 0xbf, 0xa6, 0xee, 0x42, 0x8f, 0x2c, 0x5f, 0xf4, 0xff, 0x8d,
+ 0xbc, 0xf8, 0xc6, 0xb1, 0x7f, 0xbb, 0xfe, 0x7b, 0x58, 0x62, 0xc5, 0x31,
+ 0xfa, 0x08, 0xfa, 0xff, 0xfe, 0x94, 0x6b, 0xb9, 0x73, 0x6f, 0xe1, 0x89,
+ 0xf4, 0x6a, 0xc5, 0xff, 0xfb, 0x24, 0xdb, 0xcb, 0x39, 0xb7, 0x3e, 0xfd,
+ 0x81, 0x62, 0xf1, 0x64, 0x96, 0x2d, 0x2d, 0xa7, 0xeb, 0xe5, 0x9b, 0xff,
+ 0x76, 0x3f, 0x89, 0xf8, 0x58, 0x35, 0x8a, 0xc3, 0xea, 0x11, 0x55, 0xff,
+ 0xd3, 0xb9, 0x6d, 0xd6, 0x98, 0xdc, 0x25, 0x8b, 0xfe, 0x7f, 0x7b, 0x26,
+ 0x93, 0x79, 0x62, 0xfe, 0xc3, 0x4d, 0x7f, 0x71, 0x62, 0xfb, 0x3e, 0xfe,
+ 0x58, 0xb9, 0xcf, 0xb4, 0xf4, 0x88, 0xc2, 0xa1, 0x17, 0x5f, 0x84, 0x65,
+ 0xc0, 0x31, 0x62, 0xfb, 0x73, 0x35, 0x0b, 0x15, 0xa3, 0x7d, 0xbc, 0x66,
+ 0xff, 0xf8, 0xfc, 0xfc, 0x17, 0xb5, 0x1f, 0xe9, 0xb8, 0xb1, 0x7c, 0x5b,
+ 0x7c, 0xcb, 0x15, 0x88, 0x98, 0x62, 0x37, 0x51, 0xbb, 0x09, 0x62, 0xa1,
+ 0x71, 0x9b, 0x21, 0x4b, 0xd9, 0x0f, 0xe3, 0x3e, 0x72, 0x1e, 0x46, 0x03,
+ 0xe8, 0x7e, 0x88, 0xb6, 0xff, 0xec, 0xf7, 0x36, 0xeb, 0x1b, 0xf0, 0x35,
+ 0x8b, 0xfe, 0xff, 0xe3, 0xbd, 0xa6, 0x1f, 0xa5, 0x8b, 0xdd, 0x3e, 0xea,
+ 0xc5, 0xfd, 0x9e, 0xd6, 0xb2, 0x4b, 0x14, 0xb1, 0x7e, 0xcf, 0x96, 0x74,
+ 0xb1, 0x40, 0x36, 0x84, 0x19, 0x4c, 0x8a, 0x39, 0x88, 0x7c, 0xc5, 0x7b,
+ 0x3b, 0xf2, 0xc5, 0xfe, 0xc1, 0xb6, 0xff, 0x36, 0x96, 0x2e, 0xce, 0x6d,
+ 0x44, 0x1e, 0xe9, 0x83, 0x8f, 0x53, 0xa7, 0x4a, 0x51, 0xb3, 0x5f, 0xf6,
+ 0x1f, 0xf0, 0xda, 0x16, 0xea, 0xc5, 0xfd, 0xe6, 0x9c, 0x9c, 0xeb, 0x15,
+ 0x3b, 0x71, 0x2c, 0x38, 0xfd, 0x71, 0x04, 0xd8, 0x68, 0x75, 0x2c, 0x97,
+ 0xb8, 0xce, 0x9a, 0x1a, 0xd3, 0x42, 0x8f, 0x52, 0xae, 0x4e, 0xbb, 0xf8,
+ 0xfb, 0xdd, 0x04, 0x11, 0x9f, 0x94, 0x60, 0xbc, 0x85, 0x0f, 0xa7, 0x22,
+ 0x05, 0x08, 0x8d, 0xf1, 0xf5, 0x86, 0x50, 0x10, 0xf2, 0xf8, 0x50, 0x43,
+ 0x58, 0xbf, 0xe8, 0x39, 0x60, 0xf4, 0xd3, 0xac, 0x5f, 0xff, 0xe3, 0x3e,
+ 0x28, 0xef, 0x6e, 0xb5, 0x13, 0x93, 0xbe, 0x8d, 0x58, 0xbf, 0xc5, 0x82,
+ 0xc3, 0x64, 0x05, 0x8a, 0x74, 0x4d, 0x98, 0xcf, 0x52, 0x47, 0xbe, 0x43,
+ 0x52, 0xff, 0xfa, 0x27, 0xdb, 0xf8, 0x6f, 0x72, 0x27, 0xce, 0x2c, 0x5e,
+ 0x36, 0x34, 0xb1, 0x7f, 0xfd, 0x1b, 0x7e, 0xfb, 0xf6, 0xe1, 0xcf, 0x1a,
+ 0x35, 0x62, 0xfc, 0x03, 0xe6, 0x79, 0x62, 0xff, 0xb3, 0x6e, 0xb3, 0xe5,
+ 0x93, 0x2c, 0x56, 0x1f, 0x19, 0x14, 0x5f, 0xff, 0xef, 0xb8, 0x39, 0xb4,
+ 0xb3, 0x79, 0x67, 0x30, 0xf1, 0xd2, 0xc5, 0xff, 0xff, 0xf6, 0x84, 0x76,
+ 0xe6, 0xd9, 0xa4, 0x22, 0xf6, 0xdf, 0xc4, 0x98, 0xb0, 0xf0, 0xb1, 0x6e,
+ 0x2c, 0x5f, 0xbd, 0xb7, 0xaf, 0x1d, 0x62, 0xa1, 0x18, 0x2f, 0x08, 0x21,
+ 0x09, 0x54, 0xca, 0x94, 0x3e, 0x3c, 0x50, 0xba, 0xe1, 0x07, 0xa3, 0x25,
+ 0xbf, 0x84, 0x73, 0x60, 0xba, 0x58, 0xbf, 0xff, 0xf7, 0x36, 0x96, 0x0e,
+ 0x3d, 0xcd, 0xbe, 0x08, 0x51, 0xc1, 0x47, 0x6b, 0x17, 0xff, 0x03, 0x6e,
+ 0x08, 0x7b, 0x63, 0x91, 0x25, 0x8a, 0xd8, 0xdd, 0x0d, 0x60, 0x58, 0x4f,
+ 0x11, 0xa7, 0x65, 0x73, 0x4d, 0xd4, 0x6d, 0x7d, 0xc6, 0x32, 0xc4, 0xef,
+ 0x2a, 0x8c, 0x95, 0xfc, 0x60, 0x27, 0x3b, 0xf7, 0xc3, 0x2e, 0xc0, 0xb1,
+ 0x7f, 0xdb, 0x42, 0x7b, 0x3f, 0xe6, 0x3a, 0xc5, 0xff, 0xd3, 0xbf, 0xb5,
+ 0x93, 0xb9, 0x7b, 0x8b, 0x15, 0x88, 0xaf, 0xe8, 0xad, 0x8f, 0xaf, 0xff,
+ 0xe9, 0x7f, 0x1a, 0x5c, 0xc2, 0x17, 0x8b, 0x01, 0x0b, 0x16, 0x65, 0x8b,
+ 0x6b, 0x0f, 0xa8, 0x0b, 0x37, 0xff, 0xd9, 0xef, 0xe0, 0xc5, 0xee, 0x47,
+ 0x05, 0xc5, 0x8b, 0xfa, 0x30, 0xba, 0x0c, 0xeb, 0x17, 0xfb, 0xc2, 0x8c,
+ 0x9c, 0x33, 0xac, 0x5f, 0xfb, 0xf0, 0x42, 0x9b, 0x39, 0xc8, 0x58, 0xb6,
+ 0xef, 0xd1, 0xeb, 0xe5, 0x10, 0xcb, 0xc2, 0x1b, 0x54, 0x26, 0xca, 0xf1,
+ 0x8e, 0x5f, 0xb0, 0xbc, 0x01, 0x2c, 0x5f, 0xff, 0xd1, 0x2c, 0x3c, 0x75,
+ 0xee, 0x60, 0x23, 0x3b, 0x92, 0xc5, 0x7d, 0x10, 0x84, 0x51, 0x7d, 0x3e,
+ 0x3c, 0xcb, 0x17, 0xff, 0xfe, 0x6d, 0xe5, 0x9c, 0xdb, 0xe6, 0xdb, 0x9e,
+ 0x8e, 0x9b, 0x7c, 0x7d, 0x62, 0xff, 0xff, 0xef, 0xe1, 0x4f, 0xb7, 0xaf,
+ 0x8b, 0xf1, 0xa0, 0x7f, 0x3c, 0x51, 0xd2, 0xc5, 0xfe, 0x1c, 0x03, 0x6e,
+ 0x77, 0xe5, 0x8b, 0xff, 0xe7, 0xd3, 0xff, 0xb9, 0x67, 0xb6, 0xf5, 0xcd,
+ 0xd5, 0x8b, 0xf9, 0xa4, 0xfe, 0xfb, 0x2c, 0x5f, 0xff, 0x39, 0xc7, 0xf8,
+ 0xd1, 0x60, 0xfe, 0xe6, 0x2c, 0x50, 0xd3, 0x0c, 0xe8, 0xdf, 0xcb, 0x1b,
+ 0xcb, 0x6f, 0xe7, 0xdd, 0x19, 0x67, 0xd6, 0x2e, 0x3f, 0x16, 0x2f, 0x3f,
+ 0x19, 0x62, 0xa0, 0xda, 0x00, 0x62, 0xff, 0x83, 0x9f, 0x09, 0xce, 0xff,
+ 0x58, 0xbe, 0x6d, 0x13, 0xac, 0x54, 0xea, 0xce, 0xa4, 0x48, 0x37, 0x36,
+ 0x8e, 0x0e, 0x64, 0x12, 0x64, 0xf1, 0x06, 0xf3, 0xab, 0xfd, 0xce, 0x43,
+ 0x4e, 0xfe, 0x58, 0xbf, 0xee, 0x39, 0x81, 0x1b, 0x08, 0x6b, 0x17, 0xf6,
+ 0x7b, 0x1c, 0xa6, 0x58, 0xbe, 0xce, 0x46, 0x96, 0x2c, 0x6f, 0xcf, 0x3c,
+ 0x8b, 0x6d, 0x28, 0x47, 0x36, 0x1a, 0x0a, 0x11, 0x56, 0x92, 0xc5, 0xe1,
+ 0x88, 0x0b, 0x17, 0xff, 0xf4, 0x6e, 0xed, 0x6c, 0x2c, 0xfb, 0x61, 0x77,
+ 0x2e, 0x2c, 0x5f, 0xe0, 0x8d, 0x9d, 0xfd, 0xb1, 0x62, 0xc5, 0xda, 0x24,
+ 0xc0, 0xbd, 0x7f, 0x67, 0xb9, 0xf6, 0x35, 0x62, 0xfb, 0x9f, 0x63, 0x56,
+ 0x2f, 0xd3, 0xe6, 0x8b, 0x08, 0xf4, 0xfc, 0x5f, 0x7d, 0x07, 0x71, 0xac,
+ 0x54, 0x27, 0x3c, 0x31, 0x2c, 0x85, 0x8f, 0xdf, 0x08, 0xf6, 0xfe, 0x9b,
+ 0xf9, 0xe8, 0x1a, 0xc5, 0xe0, 0xe0, 0x96, 0x2f, 0xf6, 0x7f, 0x6e, 0x13,
+ 0xc9, 0x62, 0xe8, 0x25, 0x8b, 0x9c, 0xcd, 0xa7, 0xcf, 0xe1, 0xd0, 0xcd,
+ 0x2b, 0x11, 0xa8, 0x50, 0x96, 0xbf, 0xfd, 0x83, 0xda, 0x27, 0x0f, 0xc2,
+ 0x79, 0xe1, 0x62, 0xfa, 0x0f, 0xc3, 0xac, 0x5f, 0x9f, 0xdb, 0x7a, 0x31,
+ 0x62, 0xff, 0xd8, 0x6f, 0xf3, 0xdc, 0x28, 0x92, 0xc5, 0x42, 0x37, 0x59,
+ 0x39, 0xc8, 0xc4, 0x5b, 0x7d, 0x3f, 0x9a, 0x75, 0x8b, 0xf7, 0x9c, 0xed,
+ 0xe5, 0x8a, 0xc3, 0xcd, 0x22, 0x5b, 0xc3, 0x61, 0xac, 0x5f, 0xff, 0xf8,
+ 0x51, 0xad, 0xb1, 0xf8, 0x1e, 0xdf, 0x36, 0x04, 0xee, 0x4f, 0xda, 0xc5,
+ 0xe0, 0x3e, 0xea, 0xc5, 0xfb, 0x85, 0x13, 0x79, 0x62, 0x86, 0x8d, 0xa2,
+ 0x1d, 0xe3, 0xa7, 0x88, 0x2e, 0xe0, 0x5a, 0x58, 0xb4, 0x96, 0x2a, 0x13,
+ 0x66, 0xc8, 0x7d, 0x39, 0xe7, 0x87, 0xaf, 0x17, 0x50, 0xb1, 0x7f, 0xff,
+ 0xfd, 0xfc, 0xf7, 0x1e, 0x6d, 0xa5, 0x9d, 0xcb, 0x05, 0x39, 0x60, 0xfe,
+ 0xd3, 0x2c, 0x5c, 0x5e, 0x58, 0xbf, 0xfd, 0xc8, 0x97, 0xb3, 0xe5, 0x9e,
+ 0xfb, 0x2c, 0x54, 0x1f, 0x03, 0x0b, 0xdc, 0x23, 0x56, 0x29, 0x93, 0x38,
+ 0xd0, 0xef, 0xe1, 0xc5, 0xe2, 0x0b, 0xc7, 0xfb, 0xac, 0x5e, 0xda, 0x19,
+ 0xd6, 0x2f, 0xfc, 0x09, 0xbe, 0xc0, 0x27, 0xee, 0x4b, 0x14, 0xb1, 0x6c,
+ 0x73, 0xcd, 0xe2, 0x0d, 0xef, 0x9b, 0xe5, 0x8b, 0xf7, 0xbd, 0xec, 0x31,
+ 0x62, 0xa0, 0xf2, 0x58, 0x7e, 0xa1, 0x31, 0xae, 0xc7, 0x4e, 0xdc, 0x06,
+ 0xfb, 0xc7, 0x8e, 0x96, 0x2e, 0xd6, 0x2c, 0x5e, 0xc6, 0x1a, 0xc5, 0xb8,
+ 0xb1, 0x71, 0x67, 0x46, 0xbb, 0xb1, 0xcb, 0xcd, 0x84, 0xb1, 0x79, 0xa2,
+ 0x65, 0x8b, 0xff, 0xb0, 0x1b, 0x7e, 0xde, 0xe1, 0x34, 0xcb, 0x17, 0xfe,
+ 0x2c, 0xe6, 0xde, 0x00, 0xf9, 0xc5, 0x8a, 0x9d, 0x1d, 0xa7, 0x2d, 0xe0,
+ 0xdf, 0x87, 0x77, 0xa3, 0xd6, 0xc0, 0x9c, 0xec, 0x0f, 0x64, 0x66, 0x57,
+ 0xff, 0x03, 0x9f, 0xc9, 0xe3, 0xb2, 0x63, 0x16, 0x2f, 0xfe, 0x20, 0x6e,
+ 0x67, 0xda, 0x0e, 0xe3, 0x58, 0xbf, 0xb5, 0x92, 0x28, 0x3a, 0xc5, 0xfb,
+ 0x24, 0x50, 0x75, 0x8b, 0x88, 0x1b, 0x4f, 0x53, 0x45, 0xb7, 0xff, 0xff,
+ 0xe9, 0x73, 0x82, 0x8f, 0x30, 0xf0, 0xa6, 0xda, 0x59, 0xa8, 0x2f, 0x7f,
+ 0x02, 0x2c, 0x5f, 0xfa, 0x31, 0xbd, 0xf8, 0x28, 0xe9, 0x62, 0xfe, 0x3f,
+ 0x71, 0xff, 0xc2, 0xc5, 0xee, 0xe5, 0xc9, 0xcf, 0xb3, 0x0f, 0x6b, 0x13,
+ 0x56, 0xec, 0xbf, 0x50, 0xf2, 0xb7, 0x16, 0x2a, 0x15, 0x3f, 0xe2, 0x38,
+ 0xa3, 0xf0, 0x0c, 0xda, 0xfd, 0x9c, 0xfb, 0x49, 0x62, 0xd3, 0xac, 0x5f,
+ 0xa7, 0x8f, 0x60, 0x16, 0x2f, 0xe1, 0xb9, 0x49, 0x8e, 0xb1, 0x7f, 0xf6,
+ 0x4b, 0xef, 0x28, 0xf6, 0xb0, 0x6b, 0x17, 0xed, 0x67, 0x72, 0xe2, 0xc5,
+ 0xee, 0xbf, 0x8b, 0x15, 0x39, 0xe4, 0x68, 0xaa, 0xfe, 0x07, 0x36, 0x83,
+ 0x9a, 0x58, 0xac, 0x3d, 0x57, 0x23, 0xbf, 0xee, 0xe3, 0x53, 0xed, 0xc6,
+ 0x1a, 0xc5, 0xd3, 0x32, 0xc5, 0xff, 0xd9, 0xed, 0xb9, 0x2f, 0xe3, 0x4b,
+ 0x8b, 0x15, 0x25, 0x45, 0xb8, 0x50, 0xc2, 0x6e, 0x52, 0x02, 0xd2, 0x87,
+ 0x08, 0x88, 0x37, 0x9e, 0xee, 0x0c, 0x5f, 0x7f, 0x60, 0xeb, 0x71, 0x62,
+ 0xfe, 0xce, 0xe5, 0x00, 0x85, 0x8b, 0xf1, 0x67, 0xdf, 0xcb, 0x15, 0xd9,
+ 0xea, 0x9c, 0xba, 0xfb, 0x59, 0x34, 0x2c, 0x5f, 0xf3, 0x6e, 0x41, 0xf9,
+ 0xfc, 0x3a, 0xc5, 0xf3, 0x6f, 0xcd, 0x2c, 0x50, 0x51, 0x32, 0x88, 0x84,
+ 0x13, 0x11, 0x9c, 0x8f, 0xe7, 0x97, 0xdb, 0x7a, 0x9c, 0xc5, 0x8b, 0xf8,
+ 0xb0, 0x07, 0x89, 0x2c, 0x5f, 0x8b, 0x3d, 0xf6, 0x58, 0xa1, 0x9e, 0xa1,
+ 0x85, 0xb7, 0xe9, 0xf6, 0x8a, 0x26, 0x58, 0xbf, 0xff, 0xe2, 0x80, 0x77,
+ 0x2e, 0x0a, 0x3c, 0x58, 0x36, 0xcd, 0x4c, 0xb1, 0x50, 0x8b, 0x77, 0x23,
+ 0xf1, 0x6d, 0x43, 0x75, 0x15, 0x3c, 0x7f, 0xc3, 0x85, 0x66, 0x4b, 0x5c,
+ 0xee, 0x36, 0x16, 0x8f, 0x5e, 0x68, 0xc8, 0x75, 0x18, 0x1f, 0xe3, 0xed,
+ 0x78, 0xde, 0x01, 0x1a, 0xe1, 0x47, 0xb7, 0xc9, 0x57, 0x3e, 0x94, 0xe2,
+ 0x28, 0xeb, 0xb7, 0xa9, 0x07, 0x19, 0xa5, 0xfa, 0x4d, 0xac, 0xed, 0x62,
+ 0xf7, 0x3f, 0x8b, 0x17, 0xec, 0xe4, 0xf8, 0x62, 0xc5, 0xff, 0xdf, 0x10,
+ 0xfe, 0x2f, 0x73, 0xe2, 0x99, 0x62, 0xbb, 0x45, 0xcc, 0xc5, 0x3f, 0x1d,
+ 0x22, 0xab, 0xc5, 0xee, 0x2c, 0x5f, 0xfe, 0x6d, 0x36, 0x77, 0xb7, 0xd3,
+ 0x14, 0x1d, 0x62, 0xff, 0xec, 0x7e, 0xf6, 0x8e, 0x27, 0xda, 0x69, 0xab,
+ 0x15, 0xd2, 0x26, 0xbb, 0x4d, 0xbf, 0xa0, 0xe5, 0x93, 0xe2, 0xc5, 0xef,
+ 0x73, 0xf8, 0x7a, 0x5f, 0x25, 0xbf, 0xff, 0x1f, 0xb9, 0x73, 0x5d, 0xc7,
+ 0xb9, 0x1f, 0x6f, 0x2c, 0x5f, 0xf6, 0x1a, 0x59, 0xef, 0xb1, 0x8b, 0x17,
+ 0xec, 0x33, 0x06, 0x75, 0x8b, 0xff, 0xd1, 0xdf, 0xdb, 0x08, 0x6d, 0xbe,
+ 0x06, 0xb1, 0x50, 0x99, 0xd3, 0x19, 0xe9, 0x67, 0xe7, 0x44, 0x53, 0x76,
+ 0xe8, 0xd6, 0x2f, 0xff, 0xa7, 0xce, 0x87, 0xf6, 0xc3, 0x76, 0x9a, 0x28,
+ 0x58, 0xbf, 0xb3, 0x5a, 0xcf, 0x71, 0x62, 0xfe, 0x27, 0x34, 0xef, 0x25,
+ 0x8b, 0xd2, 0x6f, 0x7c, 0xf7, 0x3c, 0x5d, 0x7e, 0xc3, 0x96, 0x76, 0xb1,
+ 0x7f, 0x79, 0xb7, 0xc1, 0x74, 0xb1, 0x5c, 0x3d, 0x80, 0xca, 0x2e, 0xfe,
+ 0x2c, 0x5f, 0xa4, 0xc4, 0x0e, 0x2c, 0x5f, 0xa0, 0xed, 0xf8, 0x58, 0xbc,
+ 0x41, 0xfd, 0x62, 0xff, 0x67, 0xbe, 0xde, 0xce, 0x96, 0x2f, 0xa3, 0x0b,
+ 0xa5, 0x8a, 0xda, 0x8f, 0xd9, 0x11, 0xcc, 0x2f, 0xa2, 0x87, 0x27, 0x21,
+ 0xef, 0x1a, 0x5f, 0xfe, 0x88, 0x3e, 0xd1, 0xfe, 0x36, 0xfe, 0x37, 0x56,
+ 0x2b, 0x62, 0x56, 0x16, 0xc3, 0x73, 0x42, 0xcb, 0xf1, 0xc4, 0x13, 0x2d,
+ 0xff, 0xa5, 0xcf, 0x3c, 0xe1, 0x0b, 0x3b, 0x58, 0xbf, 0xbf, 0x12, 0x13,
+ 0x86, 0xb1, 0x7e, 0x1f, 0xf0, 0xbc, 0xb1, 0x52, 0x3d, 0x79, 0x8b, 0xeb,
+ 0xb4, 0x5e, 0x94, 0x26, 0xaf, 0xfb, 0x4d, 0x86, 0x7b, 0xce, 0x4b, 0x17,
+ 0x76, 0x6a, 0xc5, 0xcd, 0xde, 0xd3, 0xd3, 0x19, 0xcd, 0xe6, 0x06, 0x2c,
+ 0x5f, 0x9a, 0x67, 0x79, 0x2c, 0x5b, 0x92, 0x3c, 0x4c, 0x1c, 0xbf, 0xfd,
+ 0x86, 0x04, 0xfe, 0x7b, 0x00, 0x77, 0x99, 0x62, 0xa1, 0x36, 0x4d, 0x3d,
+ 0xbb, 0xa1, 0x13, 0xdf, 0xf9, 0xf7, 0x96, 0x7b, 0x00, 0x43, 0x58, 0xb0,
+ 0x16, 0x29, 0x8f, 0x46, 0x63, 0xfb, 0xfe, 0xfc, 0xed, 0x85, 0xdc, 0xb8,
+ 0xb1, 0x7f, 0xdd, 0xff, 0x3a, 0x2c, 0x16, 0xea, 0xc5, 0xfe, 0xdb, 0xcc,
+ 0x28, 0xd4, 0xcb, 0x17, 0xff, 0xb3, 0xae, 0x67, 0xa6, 0xc3, 0x4b, 0x00,
+ 0xb1, 0x5a, 0x44, 0x11, 0x86, 0xd7, 0xff, 0xfd, 0x86, 0xed, 0xc3, 0x74,
+ 0xdd, 0x96, 0x78, 0x40, 0x3b, 0xc9, 0x62, 0xd2, 0x84, 0xe2, 0xb0, 0xed,
+ 0xa1, 0x80, 0x22, 0x4b, 0xfa, 0x35, 0xe6, 0xce, 0xd6, 0x2f, 0xfa, 0x05,
+ 0xd7, 0x7e, 0x6c, 0x25, 0x8a, 0xf9, 0xf4, 0x11, 0x75, 0xf4, 0xa0, 0x1c,
+ 0x58, 0xbf, 0x9b, 0xb0, 0x69, 0xc6, 0xb1, 0x7b, 0x34, 0x05, 0x8b, 0xf7,
+ 0x1b, 0x08, 0x0b, 0x16, 0xc6, 0x3c, 0x4e, 0x0e, 0xdf, 0x98, 0x00, 0xcd,
+ 0x2c, 0x5f, 0x0f, 0xf1, 0x25, 0x8a, 0x1a, 0x65, 0x18, 0x43, 0xf2, 0x32,
+ 0x73, 0xe1, 0x30, 0x65, 0x16, 0x0a, 0x2c, 0x5f, 0x9f, 0x09, 0x8d, 0x58,
+ 0xbd, 0xec, 0xfa, 0xc5, 0x11, 0xe2, 0x04, 0x27, 0xbf, 0xff, 0xff, 0xe6,
+ 0xeb, 0xf9, 0x1d, 0xcf, 0x18, 0xdd, 0x82, 0x0b, 0xa7, 0xf9, 0x38, 0x36,
+ 0xf5, 0xdf, 0x16, 0x2f, 0xff, 0xa2, 0x7f, 0x77, 0x21, 0x11, 0xbb, 0x5b,
+ 0x7b, 0x2c, 0x57, 0x48, 0xf1, 0x28, 0x4d, 0x5c, 0xc7, 0x58, 0xbe, 0xdb,
+ 0xd8, 0x89, 0x62, 0xff, 0x61, 0x9b, 0x60, 0x10, 0x05, 0x8b, 0xff, 0xfe,
+ 0x93, 0xf7, 0xb4, 0x84, 0x13, 0x6e, 0x77, 0x2c, 0x11, 0x03, 0x8b, 0x15,
+ 0x3a, 0x29, 0x7b, 0x36, 0xa9, 0x93, 0x2f, 0x39, 0x46, 0xf1, 0x70, 0x90,
+ 0xcb, 0xbf, 0xed, 0x8b, 0xde, 0x62, 0xee, 0x5c, 0x58, 0xbe, 0xdd, 0xfe,
+ 0x6e, 0xac, 0x5e, 0xdc, 0x60, 0xba, 0xc5, 0x6d, 0x57, 0x93, 0xb1, 0x2b,
+ 0xce, 0xb5, 0x92, 0x90, 0xcd, 0x48, 0x74, 0x0d, 0xc2, 0x9b, 0xff, 0xc5,
+ 0x07, 0xdb, 0xfc, 0xef, 0xd8, 0xf3, 0x2c, 0x5f, 0xff, 0xff, 0x77, 0xc1,
+ 0x47, 0x7b, 0x7f, 0x83, 0xda, 0x58, 0x23, 0x76, 0xf0, 0x00, 0x6f, 0x2c,
+ 0x5f, 0xff, 0xfb, 0x06, 0x73, 0xc7, 0xb9, 0x9e, 0xe6, 0x9b, 0x3a, 0x2c,
+ 0x1a, 0xc5, 0xff, 0xef, 0x0a, 0x32, 0x7d, 0xbc, 0x62, 0x6d, 0x2c, 0x58,
+ 0xc2, 0x45, 0xc0, 0x6d, 0x95, 0x09, 0xb5, 0x64, 0x68, 0x17, 0xe8, 0x2e,
+ 0xde, 0x75, 0x8b, 0xfa, 0x66, 0x1e, 0x1d, 0x96, 0x2f, 0xff, 0xff, 0xfb,
+ 0xa8, 0xfc, 0x1f, 0xd9, 0xce, 0x46, 0xb5, 0x05, 0x93, 0xe0, 0xb8, 0x29,
+ 0x8a, 0x0e, 0xb1, 0x50, 0x8c, 0x3c, 0x2e, 0xbc, 0x2d, 0x1a, 0xb1, 0x47,
+ 0x3c, 0x0d, 0xc2, 0x1b, 0xf3, 0x80, 0x37, 0x9d, 0x62, 0xff, 0xff, 0xe9,
+ 0xf6, 0xfa, 0x76, 0xcd, 0x4f, 0xb6, 0x69, 0x37, 0xf0, 0x7d, 0xe0, 0x45,
+ 0x8a, 0xc4, 0x66, 0xb1, 0x28, 0x8a, 0xaf, 0x30, 0x21, 0x62, 0xff, 0x6d,
+ 0x2c, 0xd3, 0x41, 0xd6, 0x2f, 0xfd, 0xa7, 0xf6, 0xb1, 0xbf, 0x03, 0x58,
+ 0xbf, 0x86, 0x59, 0xf7, 0xf2, 0xc5, 0xfb, 0xdd, 0xc9, 0xb4, 0xb1, 0x58,
+ 0x7a, 0xfc, 0x2d, 0xa9, 0xd3, 0x06, 0x18, 0xe6, 0x8d, 0x01, 0x09, 0x5b,
+ 0xda, 0x70, 0xd6, 0x2f, 0xd1, 0xe3, 0xb7, 0x96, 0x29, 0xcf, 0x18, 0x43,
+ 0xd7, 0xc5, 0xde, 0x1d, 0x62, 0xa7, 0x3c, 0x43, 0x08, 0x6f, 0xfd, 0x06,
+ 0x84, 0x16, 0x14, 0xc1, 0x9d, 0x62, 0xff, 0x8c, 0xcd, 0x0d, 0xb3, 0xdc,
+ 0x58, 0xbf, 0xc0, 0xe6, 0x6d, 0xeb, 0xc7, 0x58, 0xbf, 0xff, 0xff, 0xc6,
+ 0x96, 0x6d, 0x6c, 0x27, 0xf7, 0xe2, 0x6d, 0xa5, 0x9f, 0x6f, 0x70, 0x5d,
+ 0x0a, 0x16, 0x2b, 0x13, 0x6c, 0xec, 0x91, 0x91, 0x1c, 0xe8, 0x47, 0x17,
+ 0xff, 0xc2, 0x0b, 0xed, 0x8f, 0xb7, 0xb8, 0xc5, 0xdc, 0x96, 0x2f, 0xff,
+ 0x39, 0xb8, 0x42, 0xf7, 0xf3, 0x78, 0xe1, 0x62, 0xff, 0xec, 0xf6, 0x34,
+ 0xf9, 0xd3, 0x4d, 0xc5, 0x8b, 0xff, 0x66, 0x03, 0x9b, 0x75, 0xc1, 0xf1,
+ 0x62, 0xff, 0x6b, 0x3a, 0xfb, 0x6a, 0x65, 0x8a, 0xda, 0x8b, 0xe1, 0xa3,
+ 0x62, 0x15, 0xff, 0xf7, 0xdb, 0x6e, 0x4d, 0xdc, 0xb9, 0xef, 0xe7, 0x6b,
+ 0x17, 0xff, 0xf0, 0xc9, 0xff, 0xfe, 0xe0, 0x21, 0x41, 0xf6, 0x9c, 0x2e,
+ 0xb1, 0x44, 0x9f, 0xaf, 0xa3, 0x0a, 0xde, 0x62, 0x62, 0xb5, 0xf7, 0xb4,
+ 0x23, 0xac, 0x5f, 0xff, 0xec, 0x39, 0xdb, 0xbd, 0xa6, 0x9b, 0x85, 0xe3,
+ 0x45, 0x1a, 0x58, 0xbb, 0x3a, 0x64, 0x45, 0xe8, 0x92, 0xff, 0xc2, 0x9b,
+ 0x6f, 0xb8, 0xdb, 0x60, 0x6b, 0x17, 0xd2, 0x80, 0x71, 0x62, 0xec, 0xdc,
+ 0x58, 0xbf, 0xdb, 0x7f, 0x0d, 0x3e, 0x0d, 0x62, 0xdd, 0xe1, 0xf9, 0x91,
+ 0x1e, 0xf1, 0xaa, 0x85, 0xc3, 0x9c, 0x94, 0x98, 0xd0, 0xd1, 0xf9, 0x73,
+ 0xc2, 0xe2, 0xfe, 0x6f, 0xb1, 0xdc, 0x6b, 0x14, 0xb1, 0x71, 0x02, 0x46,
+ 0xe4, 0x65, 0xb7, 0xc7, 0x91, 0x32, 0xc5, 0x41, 0xe7, 0x61, 0x65, 0xfd,
+ 0xf7, 0x2f, 0x61, 0xd6, 0x2f, 0x31, 0x79, 0x62, 0xfe, 0x97, 0x1c, 0xe2,
+ 0xe2, 0xc5, 0xff, 0xff, 0xcd, 0xee, 0x7d, 0xb6, 0x96, 0x0a, 0x3b, 0xfe,
+ 0x01, 0xfb, 0x97, 0x16, 0x2a, 0x11, 0xdb, 0x39, 0x6b, 0x8e, 0x78, 0xbe,
+ 0xfd, 0x9f, 0xfb, 0xc9, 0x62, 0xf4, 0x11, 0xab, 0x17, 0xfb, 0x77, 0x6e,
+ 0x04, 0xfc, 0x79, 0x62, 0xfb, 0x53, 0xe7, 0x4b, 0x15, 0x87, 0xc0, 0xc7,
+ 0x75, 0xf4, 0x4e, 0xf9, 0xf6, 0xa1, 0xbf, 0x78, 0x9c, 0xf8, 0x72, 0x90,
+ 0xf2, 0x5a, 0x99, 0xb2, 0x9f, 0x3a, 0x84, 0x67, 0x71, 0xd6, 0x34, 0xec,
+ 0xfc, 0xce, 0xfa, 0x8e, 0xdc, 0xe5, 0x1f, 0x8f, 0xe5, 0xe3, 0x34, 0x29,
+ 0x47, 0x5c, 0x9c, 0x82, 0xf4, 0x38, 0x45, 0x18, 0x6e, 0xe1, 0xe0, 0x48,
+ 0x62, 0xdf, 0xf1, 0x61, 0x81, 0x02, 0x7b, 0x3e, 0xb1, 0x7f, 0x89, 0xcd,
+ 0xcc, 0x23, 0x56, 0x2e, 0xeb, 0x16, 0x2b, 0xa4, 0x44, 0x9c, 0xf9, 0xcc,
+ 0xe9, 0x62, 0xff, 0xed, 0xb9, 0x37, 0x72, 0xe7, 0xbf, 0x9d, 0xac, 0x5f,
+ 0xf3, 0x67, 0x65, 0xb7, 0x98, 0x4b, 0x17, 0xbe, 0xda, 0x58, 0xaf, 0x9e,
+ 0xb8, 0x43, 0xab, 0xfd, 0x28, 0x1e, 0xd1, 0xb4, 0xcb, 0x17, 0xfd, 0xb7,
+ 0xc5, 0x86, 0x63, 0x71, 0x62, 0xff, 0xd8, 0x6c, 0x17, 0x5b, 0x77, 0xf0,
+ 0xc5, 0x8b, 0xff, 0xff, 0x79, 0xe6, 0x2c, 0x9d, 0xf6, 0x97, 0x78, 0x61,
+ 0x60, 0xb0, 0xd5, 0x8a, 0xd8, 0xd3, 0xfa, 0x9c, 0x33, 0xa8, 0x51, 0x76,
+ 0x49, 0x31, 0xbf, 0xce, 0xc2, 0x23, 0x5e, 0xfc, 0x01, 0x62, 0xff, 0x7d,
+ 0x81, 0x1e, 0x6d, 0xeb, 0x17, 0xd2, 0xe0, 0xa6, 0x58, 0xbf, 0x34, 0x19,
+ 0x13, 0x2c, 0x57, 0x67, 0x9c, 0xc4, 0xb7, 0xde, 0x72, 0x02, 0xc5, 0xff,
+ 0xf9, 0xcd, 0x34, 0x0f, 0x30, 0x42, 0x83, 0x3b, 0x97, 0x16, 0x2c, 0x1b,
+ 0x9f, 0xf9, 0x11, 0x5e, 0x96, 0xd0, 0xaa, 0xc5, 0xe3, 0x73, 0x8b, 0x17,
+ 0xcf, 0xbb, 0x00, 0x58, 0xad, 0x89, 0x71, 0xba, 0x25, 0x15, 0x63, 0xaf,
+ 0x43, 0xb3, 0x42, 0x0d, 0xe1, 0x42, 0x02, 0x72, 0x24, 0x30, 0x7a, 0xf7,
+ 0x3c, 0xcb, 0x14, 0xb1, 0x7f, 0x61, 0xe3, 0xef, 0xf5, 0x8b, 0x69, 0x62,
+ 0x96, 0x2b, 0x0b, 0xe9, 0x84, 0xaf, 0x46, 0x69, 0x62, 0xb6, 0x9b, 0xc2,
+ 0x20, 0xbd, 0xf6, 0x35, 0x62, 0xb6, 0xa3, 0x1c, 0x70, 0x87, 0x34, 0x8a,
+ 0xff, 0xfb, 0xb9, 0x14, 0x6d, 0x39, 0x41, 0xbe, 0x69, 0xd6, 0x2f, 0x73,
+ 0x47, 0x58, 0xbf, 0xfb, 0x6f, 0xb5, 0x86, 0x64, 0xe5, 0x86, 0x2c, 0x56,
+ 0xd4, 0xf8, 0xe0, 0x77, 0x21, 0xa6, 0xc7, 0x04, 0xa9, 0xe1, 0xeb, 0xf6,
+ 0xb6, 0x96, 0xf3, 0x16, 0x2f, 0xff, 0xc6, 0x82, 0x6e, 0x6d, 0xf1, 0xe3,
+ 0xf8, 0x5d, 0xe2, 0xc5, 0xf1, 0xbb, 0x82, 0xf2, 0xc5, 0xb8, 0xb1, 0x79,
+ 0xc1, 0x0b, 0x15, 0xa3, 0xd6, 0x39, 0x47, 0xc4, 0xaf, 0x3c, 0xd0, 0xb1,
+ 0x7b, 0xf9, 0xa5, 0x8a, 0x84, 0xd2, 0x24, 0x5c, 0xf0, 0xb1, 0x30, 0xbc,
+ 0x20, 0xed, 0xfd, 0x3c, 0xd2, 0xd8, 0xb5, 0x3a, 0xc5, 0xf0, 0x65, 0x9b,
+ 0xd6, 0x2f, 0x98, 0x78, 0x35, 0x8a, 0xec, 0xf1, 0xce, 0x4b, 0x69, 0x96,
+ 0x2e, 0x83, 0xac, 0x5b, 0xcb, 0x15, 0xa3, 0x52, 0xe2, 0xf4, 0x33, 0xdc,
+ 0xf9, 0xe5, 0xf4, 0x0d, 0xe4, 0xb1, 0x7b, 0xd9, 0xc5, 0x8b, 0xff, 0x63,
+ 0xf6, 0x09, 0xa5, 0x1a, 0x9d, 0x62, 0xf6, 0xa2, 0x65, 0x8b, 0x84, 0x62,
+ 0xc5, 0xcf, 0xda, 0xc5, 0x61, 0xb1, 0xe0, 0xcd, 0x4e, 0x8f, 0x03, 0x48,
+ 0xbe, 0x3a, 0xe8, 0x5e, 0x4f, 0xbe, 0x93, 0x96, 0xe2, 0xc5, 0xd3, 0x3a,
+ 0xc5, 0xd2, 0x9d, 0x62, 0xf7, 0xa2, 0x4b, 0x17, 0xd9, 0x33, 0x69, 0x62,
+ 0xfe, 0xfb, 0xf6, 0x00, 0xce, 0xb1, 0x7d, 0x9e, 0xc3, 0xac, 0x56, 0xd4,
+ 0x49, 0xc0, 0xee, 0x11, 0xb9, 0x8d, 0xff, 0xf6, 0x41, 0x02, 0x1b, 0xdf,
+ 0xc3, 0xe0, 0xd6, 0x2f, 0x06, 0x29, 0xd6, 0x2e, 0x83, 0x56, 0x2a, 0x74,
+ 0x60, 0xc8, 0xf0, 0xd4, 0xdf, 0x10, 0x5f, 0xce, 0x64, 0x7b, 0x27, 0x58,
+ 0xbf, 0x7f, 0x0b, 0xb1, 0x2c, 0x5f, 0xcd, 0xae, 0xe4, 0x50, 0xb1, 0x7e,
+ 0x8f, 0x49, 0xbc, 0xb1, 0x7f, 0x7e, 0x3b, 0x96, 0x79, 0x62, 0xa4, 0x7a,
+ 0xe3, 0x28, 0xad, 0x23, 0x43, 0xe5, 0x3e, 0x84, 0x2d, 0xff, 0x4f, 0xac,
+ 0x9a, 0x4c, 0x46, 0xac, 0x5f, 0xf4, 0x17, 0xb4, 0xdb, 0xf0, 0x6b, 0x14,
+ 0xe7, 0xed, 0xb8, 0x79, 0x76, 0x79, 0x62, 0xd3, 0x2c, 0x57, 0xcd, 0x51,
+ 0x0b, 0xd6, 0xc6, 0xbc, 0xb9, 0x0f, 0xf8, 0xfe, 0xd1, 0x89, 0x4c, 0x96,
+ 0x72, 0x5f, 0x8c, 0x3c, 0x6d, 0xa4, 0x7e, 0x28, 0x7f, 0xee, 0x42, 0xac,
+ 0x34, 0xeb, 0xff, 0xff, 0x6d, 0xeb, 0xed, 0xf1, 0x7b, 0x6e, 0x0d, 0xb9,
+ 0xdf, 0x84, 0xfc, 0x58, 0xbf, 0xb2, 0x44, 0x27, 0xe2, 0xc5, 0x0d, 0x14,
+ 0x26, 0x3a, 0x5b, 0x8b, 0x17, 0xbe, 0xda, 0x58, 0xbf, 0x88, 0x5c, 0xd7,
+ 0x38, 0xb1, 0x5a, 0x3c, 0xcd, 0xe3, 0xb7, 0xee, 0xcc, 0x72, 0x02, 0xc5,
+ 0xc4, 0x6a, 0xc5, 0xb8, 0xc7, 0x84, 0x22, 0xab, 0x9f, 0xeb, 0x17, 0xfe,
+ 0x3c, 0x1b, 0xef, 0xe7, 0xa0, 0x0b, 0x17, 0xe7, 0x1c, 0x61, 0x2c, 0x58,
+ 0xd5, 0x8a, 0x9d, 0x12, 0x0c, 0x2f, 0xf4, 0x02, 0x26, 0xbe, 0x6f, 0x67,
+ 0x16, 0x2f, 0xfb, 0xc4, 0xff, 0x3c, 0x67, 0x96, 0x2f, 0x8e, 0x59, 0xd6,
+ 0xd3, 0xda, 0xec, 0x8a, 0xff, 0xfb, 0x27, 0x72, 0xeb, 0x6f, 0x20, 0xef,
+ 0xdf, 0x96, 0x2a, 0x11, 0x21, 0xa3, 0xcb, 0xfd, 0xbb, 0xfc, 0x9f, 0x5a,
+ 0x85, 0x8a, 0x58, 0xbf, 0xb8, 0x19, 0xf5, 0xa8, 0x58, 0xbf, 0xf9, 0xe5,
+ 0x84, 0x32, 0x89, 0x0f, 0x8b, 0x16, 0xcc, 0x3f, 0xff, 0x06, 0x6f, 0x30,
+ 0xbf, 0xed, 0xbc, 0x14, 0x76, 0x2c, 0xfa, 0xc5, 0xdc, 0x0a, 0x2c, 0x5f,
+ 0xfe, 0x2c, 0x3c, 0x75, 0xb4, 0x39, 0xe7, 0x7e, 0xd6, 0x2f, 0xe1, 0x1c,
+ 0xef, 0x2d, 0xbe, 0x3e, 0xd0, 0x83, 0x97, 0xe1, 0x48, 0x3d, 0x71, 0x62,
+ 0xa4, 0x98, 0xf7, 0xe1, 0x54, 0x49, 0x37, 0x8c, 0x79, 0xd6, 0x29, 0x8f,
+ 0x53, 0xe6, 0xb7, 0xe1, 0xe4, 0xdf, 0x65, 0x8b, 0xec, 0x9b, 0xec, 0xb1,
+ 0x6e, 0xb6, 0x9e, 0x60, 0xca, 0x6f, 0xff, 0xd1, 0xa8, 0xeb, 0x0f, 0x1d,
+ 0x49, 0xb8, 0x23, 0xac, 0x54, 0x2f, 0x1a, 0x4e, 0x49, 0x8b, 0xd3, 0x33,
+ 0x6a, 0x16, 0xff, 0x8c, 0x99, 0xc8, 0x8a, 0x16, 0xfe, 0x8e, 0x9c, 0x4d,
+ 0xbb, 0x85, 0x77, 0xf6, 0xb2, 0x0d, 0x82, 0x58, 0xb9, 0xfe, 0xb1, 0x76,
+ 0xc6, 0x14, 0x58, 0xbc, 0x4e, 0x75, 0x8b, 0xff, 0x3f, 0x7d, 0xc8, 0x53,
+ 0xed, 0xf6, 0x2c, 0x5f, 0xff, 0xfd, 0x81, 0x26, 0x8f, 0xe7, 0x8a, 0x26,
+ 0xdb, 0x85, 0x9d, 0xc9, 0xb8, 0xb1, 0x7f, 0xff, 0x7d, 0xe6, 0x38, 0x89,
+ 0xcd, 0xe6, 0x75, 0xf1, 0x6e, 0xac, 0x5d, 0x1e, 0x02, 0x36, 0x38, 0xed,
+ 0x7d, 0xee, 0x77, 0x25, 0x8b, 0x42, 0xc5, 0x61, 0xb6, 0x01, 0x2d, 0xd9,
+ 0xc5, 0x8b, 0xff, 0xf7, 0x72, 0xe6, 0xdc, 0x10, 0x5d, 0xbe, 0xe5, 0x9b,
+ 0xd6, 0x2f, 0xfc, 0x7c, 0xee, 0x5c, 0x78, 0xee, 0x4b, 0x15, 0xd2, 0x2d,
+ 0x8e, 0x2f, 0xf5, 0xeb, 0xff, 0x6a, 0x6e, 0x46, 0x9e, 0x4d, 0xf5, 0x8b,
+ 0x83, 0x9d, 0x62, 0x99, 0x11, 0x6e, 0x62, 0x48, 0x15, 0x25, 0x72, 0x18,
+ 0x5b, 0xd8, 0xbb, 0x10, 0xe8, 0x73, 0xf1, 0x8e, 0x93, 0x27, 0xa3, 0x61,
+ 0xad, 0x8e, 0x36, 0xe7, 0x90, 0xa4, 0x2f, 0x82, 0xb2, 0x85, 0x36, 0x08,
+ 0x7b, 0x6c, 0x53, 0x80, 0xdb, 0x0a, 0x1f, 0x7b, 0x0d, 0x88, 0x2d, 0x42,
+ 0xcc, 0x2c, 0x85, 0x44, 0x53, 0x6c, 0xe7, 0x9c, 0xe8, 0x94, 0xef, 0x58,
+ 0xe9, 0xcb, 0x79, 0x6b, 0x1f, 0xcd, 0x9d, 0x49, 0xea, 0xb3, 0x89, 0xee,
+ 0x95, 0x9a, 0xd4, 0x8b, 0xf9, 0xa9, 0x5e, 0x9a, 0xac, 0x63, 0x0f, 0x4a,
+ 0x4b, 0xfd, 0xab, 0xfa, 0x7a, 0x55, 0x68, 0x29, 0x12, 0x41, 0x78, 0xdb,
+ 0xca, 0xd0, 0xe7, 0x72, 0xbc, 0x01, 0xf5, 0xa1, 0x79, 0x14, 0xf2, 0xd6,
+ 0xf9, 0x4f, 0x26, 0x47, 0x47, 0xb9, 0x3d, 0x5a, 0x1c, 0xfc, 0xc0, 0x49,
+ 0xc4, 0x2b, 0xff, 0x17, 0xb6, 0x73, 0xd0, 0x4c, 0x05, 0x8b, 0xff, 0xf8,
+ 0x5d, 0x6c, 0xf7, 0xed, 0x46, 0x77, 0xb1, 0x0d, 0xdc, 0xd5, 0x8a, 0xd9,
+ 0x57, 0x69, 0x12, 0xc3, 0x19, 0x02, 0xff, 0x6e, 0xbb, 0x7b, 0x8c, 0x4b,
+ 0x17, 0xed, 0x74, 0xef, 0xd2, 0xa2, 0x9d, 0x2e, 0xce, 0xd6, 0x2f, 0xff,
+ 0x08, 0x44, 0xc5, 0x1f, 0x63, 0xe7, 0x16, 0x2e, 0xd1, 0xd6, 0x2f, 0xb0,
+ 0x9c, 0xd5, 0x8a, 0x84, 0xc1, 0xb0, 0xd7, 0xb3, 0x73, 0x8c, 0x01, 0x23,
+ 0x70, 0x62, 0xfb, 0x33, 0xec, 0xb1, 0x74, 0xce, 0xb1, 0x7d, 0xe7, 0x23,
+ 0x56, 0x2a, 0x0d, 0xdf, 0x63, 0x17, 0xc6, 0xbc, 0xb6, 0x46, 0x7f, 0xa1,
+ 0xae, 0x56, 0xca, 0x62, 0xa6, 0xc3, 0x5e, 0xff, 0xfd, 0x2d, 0x9c, 0x97,
+ 0xf1, 0xa5, 0xc8, 0xf4, 0x0d, 0x62, 0xfe, 0x8c, 0x2d, 0xb9, 0x3a, 0xc5,
+ 0xee, 0xde, 0x75, 0x8b, 0xb3, 0x8b, 0x15, 0x06, 0xdb, 0x07, 0xef, 0xa7,
+ 0x9e, 0x3b, 0x58, 0xbf, 0x9e, 0x7f, 0x71, 0xc0, 0xb1, 0x76, 0xb6, 0x74,
+ 0x8d, 0x9f, 0xb2, 0xb8, 0xfe, 0xe1, 0x35, 0x42, 0x6f, 0xed, 0x19, 0x8d,
+ 0xfb, 0x5d, 0x3b, 0xf4, 0xa8, 0xa8, 0xcb, 0xff, 0x3c, 0xb6, 0x73, 0x5d,
+ 0x3b, 0xf4, 0xa8, 0x9a, 0x0b, 0xff, 0xc5, 0x93, 0x49, 0xf5, 0x22, 0xcd,
+ 0xee, 0xb1, 0x7a, 0x33, 0xb5, 0x8b, 0xcf, 0x3c, 0x2c, 0x51, 0x1b, 0xa1,
+ 0x0e, 0xd6, 0x26, 0x58, 0x73, 0x7e, 0x28, 0x7a, 0x10, 0xb7, 0xf8, 0x37,
+ 0xdf, 0xb3, 0xe6, 0x9d, 0x62, 0xb6, 0x4f, 0xf6, 0x10, 0xaf, 0xff, 0xb3,
+ 0xcd, 0xf1, 0x7d, 0xdb, 0xbe, 0x41, 0xab, 0x17, 0xe9, 0xc3, 0x9e, 0x27,
+ 0x58, 0xbe, 0xe9, 0xdf, 0xa5, 0x45, 0x5e, 0x56, 0x1e, 0xf6, 0x8b, 0x6f,
+ 0xff, 0x7d, 0xbd, 0xc8, 0x97, 0xe0, 0xc7, 0x25, 0x8b, 0xff, 0xbc, 0x0c,
+ 0x1f, 0xf0, 0x63, 0x6e, 0xd6, 0x2f, 0xdb, 0xe0, 0xbe, 0x25, 0x8b, 0xff,
+ 0x3f, 0x72, 0xe6, 0x74, 0x3c, 0xed, 0x62, 0xb0, 0xfb, 0x1c, 0xaa, 0xfe,
+ 0x61, 0x8e, 0x35, 0x0b, 0x17, 0xee, 0x13, 0xc7, 0x16, 0x2f, 0xff, 0xfd,
+ 0x84, 0xc3, 0x3b, 0xb9, 0x74, 0x3f, 0xc6, 0x0d, 0x8a, 0x75, 0x8a, 0x84,
+ 0x48, 0xc8, 0x9e, 0xff, 0xf3, 0x6f, 0x1c, 0x67, 0x7f, 0x6d, 0x41, 0xd6,
+ 0x2f, 0xfd, 0xf9, 0x9f, 0xde, 0xef, 0xa6, 0x25, 0x8a, 0xc4, 0x47, 0x3a,
+ 0x65, 0xfb, 0x3f, 0xfc, 0x99, 0x62, 0xff, 0xfc, 0x02, 0x11, 0xc3, 0x18,
+ 0xe0, 0x07, 0x8c, 0xf2, 0xc5, 0xfc, 0xfe, 0xe6, 0x77, 0xe5, 0x8a, 0x1a,
+ 0x2b, 0xfb, 0x29, 0x25, 0x7b, 0x6c, 0x8d, 0x71, 0x6b, 0x21, 0x5f, 0xd1,
+ 0x0f, 0x69, 0x5a, 0x85, 0x97, 0xc8, 0x3d, 0x0b, 0xe3, 0x21, 0x60, 0x1c,
+ 0x34, 0x2f, 0xda, 0xe9, 0xdf, 0xa5, 0x45, 0x6c, 0x5f, 0xf4, 0xb6, 0x73,
+ 0x5d, 0x3b, 0xf4, 0xa8, 0x90, 0x4b, 0xec, 0x3c, 0x6e, 0xac, 0x5b, 0x67,
+ 0x11, 0x4e, 0xe6, 0xfc, 0x4b, 0xbe, 0x3b, 0x14, 0x2c, 0x5f, 0xb5, 0xd3,
+ 0xbf, 0x4a, 0x89, 0x0c, 0xbf, 0xb4, 0x2d, 0xf0, 0x61, 0xd6, 0x2f, 0xe2,
+ 0xce, 0x7a, 0x50, 0xb1, 0x79, 0xe5, 0xb3, 0x08, 0xb7, 0xc2, 0x16, 0x37,
+ 0xde, 0x65, 0x7f, 0xf4, 0xfb, 0x21, 0x9f, 0x6e, 0x69, 0xfd, 0xc5, 0x8a,
+ 0xd9, 0x44, 0xeb, 0x28, 0x5f, 0xec, 0xf3, 0x0f, 0x0a, 0x65, 0x8b, 0xfc,
+ 0xe6, 0xec, 0x9a, 0x6e, 0x6e, 0xac, 0x5b, 0x9b, 0x27, 0xe0, 0x46, 0x77,
+ 0x9d, 0xfa, 0x5c, 0x60, 0x65, 0x41, 0xea, 0x74, 0x55, 0x6e, 0x96, 0x2d,
+ 0xba, 0xb1, 0x58, 0x6a, 0x3e, 0x27, 0x71, 0x9e, 0x58, 0xbd, 0xc6, 0x35,
+ 0x62, 0x86, 0x6d, 0xfb, 0x19, 0xbb, 0x60, 0x9d, 0x62, 0xff, 0xbf, 0x1e,
+ 0xe0, 0x53, 0x9b, 0x01, 0x2c, 0x56, 0xc6, 0x7c, 0x32, 0x1e, 0xbe, 0xf7,
+ 0xb0, 0x22, 0xc5, 0x89, 0x62, 0xf0, 0x5b, 0x6e, 0x6c, 0x6b, 0x17, 0xa3,
+ 0x73, 0x63, 0x58, 0xa0, 0xb6, 0x3d, 0x28, 0x2d, 0xb3, 0x2c, 0x50, 0x51,
+ 0x13, 0x9b, 0x09, 0x8c, 0x2d, 0xca, 0x2f, 0xff, 0x05, 0xb8, 0x5b, 0x85,
+ 0x3f, 0x07, 0x27, 0xfb, 0x69, 0x62, 0xdd, 0xac, 0x5c, 0x52, 0x58, 0xbd,
+ 0xec, 0x02, 0xc5, 0x89, 0x62, 0xf8, 0x43, 0x7d, 0xd5, 0x8a, 0x63, 0x6f,
+ 0xc1, 0x1b, 0xc2, 0xf6, 0x2c, 0x5d, 0x13, 0x2c, 0x5f, 0xc7, 0xce, 0x89,
+ 0xf7, 0x56, 0x2f, 0x63, 0x4e, 0xb1, 0x60, 0xd6, 0x2b, 0x0f, 0x87, 0x46,
+ 0x22, 0x1d, 0xbf, 0x0e, 0x3c, 0xe3, 0x58, 0xb1, 0xd6, 0x2e, 0x6d, 0xeb,
+ 0x15, 0x07, 0xa6, 0xc5, 0x1e, 0x12, 0xbd, 0xfc, 0xe2, 0xc5, 0x9d, 0x62,
+ 0x86, 0x6b, 0xbc, 0x3b, 0x43, 0x54, 0x63, 0x82, 0x7b, 0xa2, 0xf3, 0x2a,
+ 0x68, 0x83, 0xe3, 0xbc, 0x79, 0xf4, 0x20, 0x43, 0x5b, 0xbf, 0x8a, 0x3b,
+ 0x93, 0x12, 0xc5, 0xee, 0x36, 0xf5, 0x8a, 0x19, 0xe6, 0x78, 0xb6, 0xc4,
+ 0xb1, 0x7e, 0x1c, 0x14, 0xfb, 0xab, 0x17, 0xfa, 0x0d, 0x0c, 0x00, 0x8e,
+ 0xd6, 0x2a, 0x0f, 0x8e, 0x72, 0xcb, 0xf3, 0xfd, 0x8f, 0x8b, 0x15, 0x88,
+ 0xbd, 0x27, 0x4d, 0xe4, 0x57, 0xf6, 0x75, 0xf8, 0x89, 0x96, 0x2f, 0xda,
+ 0xd4, 0x61, 0x2c, 0x5b, 0x71, 0x62, 0x99, 0x13, 0x7f, 0x30, 0x72, 0xf1,
+ 0x13, 0xde, 0x20, 0x71, 0x62, 0xfc, 0xf3, 0x87, 0x93, 0x2c, 0x5e, 0x00,
+ 0x73, 0xac, 0x5f, 0x1f, 0x3b, 0xe2, 0xc5, 0xb9, 0x07, 0x88, 0xc4, 0x17,
+ 0xb5, 0x87, 0x58, 0xac, 0x46, 0x79, 0x0e, 0xf1, 0xbf, 0xc4, 0xd7, 0xb7,
+ 0x33, 0xb5, 0x8b, 0x8c, 0x1a, 0xc5, 0xee, 0x8b, 0x75, 0x62, 0xff, 0x8c,
+ 0xfb, 0x3c, 0xbc, 0xd3, 0xac, 0x5a, 0x4b, 0x14, 0xe7, 0x9b, 0xe3, 0xba,
+ 0xfa, 0x2a, 0x1c, 0x64, 0x9b, 0xaf, 0xb7, 0xc4, 0x76, 0xb1, 0x7f, 0xe0,
+ 0x67, 0x7c, 0x0f, 0x4c, 0x7c, 0x58, 0xb9, 0xa6, 0x58, 0xae, 0xcf, 0x67,
+ 0x48, 0x37, 0xe9, 0xfa, 0xfb, 0x4c, 0xb1, 0x50, 0x8c, 0xdc, 0x7e, 0x62,
+ 0x3b, 0xe9, 0xf9, 0xdb, 0x2c, 0x5f, 0xfe, 0x8e, 0xe4, 0xc7, 0x33, 0x08,
+ 0x7f, 0x85, 0x8a, 0xc5, 0x53, 0x8c, 0x77, 0xa8, 0x64, 0x94, 0x3e, 0xf8,
+ 0x5a, 0x22, 0x5b, 0xf3, 0x8c, 0x38, 0x25, 0x8b, 0xfc, 0xc2, 0xdd, 0xfc,
+ 0x64, 0xeb, 0x17, 0xfe, 0xd7, 0x83, 0x27, 0xeb, 0x0b, 0xa5, 0x8b, 0xc7,
+ 0x6d, 0xc5, 0x8b, 0xfd, 0x9b, 0xf0, 0xb3, 0xbf, 0x2c, 0x54, 0x1e, 0xaf,
+ 0xc8, 0x2e, 0x80, 0x8b, 0x17, 0xfe, 0x31, 0xe5, 0xac, 0x6f, 0xc0, 0xd6,
+ 0x2f, 0xdc, 0x61, 0xe1, 0x2c, 0x5f, 0x74, 0xef, 0xd2, 0xa2, 0xc4, 0x2f,
+ 0xb4, 0xe5, 0xe5, 0x8b, 0x01, 0x62, 0xb4, 0x6d, 0x02, 0x11, 0x5f, 0x7c,
+ 0x9f, 0x75, 0x62, 0xfe, 0xd7, 0xdf, 0x98, 0x1a, 0xc5, 0xdf, 0x12, 0xc5,
+ 0xf7, 0x03, 0x29, 0x2c, 0x50, 0xcd, 0xe7, 0x86, 0x2f, 0x46, 0xa7, 0x58,
+ 0xa8, 0x46, 0x7b, 0x12, 0xbb, 0x58, 0x64, 0x37, 0xf1, 0x7d, 0xf9, 0x1b,
+ 0xab, 0x16, 0x31, 0x62, 0xee, 0x32, 0xc5, 0x31, 0xaa, 0x00, 0x9d, 0xff,
+ 0xa5, 0x9c, 0xf7, 0xf1, 0xb5, 0x25, 0x8a, 0x63, 0xdf, 0x11, 0x05, 0xfd,
+ 0x11, 0xd9, 0xdc, 0x6b, 0x17, 0xf8, 0x60, 0x17, 0xb8, 0x2d, 0xd5, 0x8b,
+ 0x8a, 0x4b, 0x15, 0x07, 0xa0, 0x23, 0x9b, 0xfd, 0xd4, 0x66, 0x80, 0x0f,
+ 0x2c, 0x5f, 0x47, 0x72, 0xe2, 0xc5, 0x4e, 0xb9, 0xf3, 0x22, 0x8c, 0x37,
+ 0xea, 0x12, 0xdd, 0x90, 0xb0, 0xcc, 0xc7, 0xfa, 0x27, 0x3b, 0x2f, 0xe1,
+ 0xe4, 0xe7, 0x65, 0x0b, 0x9e, 0x10, 0xf9, 0xf8, 0x44, 0x26, 0x1a, 0xdd,
+ 0xc6, 0x58, 0xbe, 0xd4, 0x11, 0xab, 0x17, 0xde, 0x62, 0x31, 0x62, 0xfa,
+ 0x62, 0x69, 0xd6, 0x2c, 0xf8, 0x78, 0xfd, 0x91, 0xde, 0x94, 0x6e, 0xac,
+ 0x50, 0xd1, 0x91, 0x82, 0xe6, 0xb5, 0x4c, 0x4f, 0x7c, 0xdc, 0x89, 0x96,
+ 0x2f, 0xfe, 0xf6, 0x4f, 0xc8, 0xd3, 0xc9, 0xbe, 0xb1, 0x5a, 0x3e, 0x8f,
+ 0x11, 0xd9, 0x96, 0x2c, 0xcb, 0x16, 0x91, 0xa6, 0x88, 0x02, 0x37, 0xe0,
+ 0xf7, 0x33, 0x50, 0xb1, 0x7a, 0x61, 0x69, 0x62, 0xe8, 0xe2, 0xc5, 0x89,
+ 0x62, 0xe8, 0x25, 0x8b, 0xfa, 0x38, 0x1c, 0xf1, 0x3a, 0xc5, 0x1a, 0x7d,
+ 0xe4, 0x2f, 0xc1, 0x10, 0xc5, 0xaf, 0xb7, 0x7e, 0x2d, 0xd5, 0x8a, 0x84,
+ 0xc8, 0x70, 0xb1, 0xa1, 0x1c, 0x23, 0xdb, 0xfe, 0x14, 0xe5, 0x83, 0xf8,
+ 0x8d, 0x58, 0xa8, 0x54, 0x12, 0x6a, 0x27, 0xe3, 0x49, 0x24, 0x0b, 0xef,
+ 0xf0, 0x50, 0xb1, 0x7f, 0xfb, 0x3b, 0xec, 0x0f, 0xee, 0x31, 0x77, 0x25,
+ 0x8b, 0xfc, 0x29, 0xfb, 0x97, 0xc5, 0xa5, 0x8b, 0xff, 0xa3, 0x39, 0x84,
+ 0x36, 0x04, 0x12, 0xc5, 0xe2, 0x89, 0xd6, 0x29, 0x91, 0xc7, 0xf4, 0xd2,
+ 0x38, 0x12, 0x0d, 0xf7, 0xfb, 0x7d, 0xd5, 0x8b, 0x85, 0xa5, 0x8b, 0xda,
+ 0x83, 0xac, 0x5c, 0x1c, 0x2c, 0x54, 0x1b, 0x5c, 0x1d, 0xa8, 0x4f, 0x52,
+ 0x51, 0x83, 0x1c, 0xed, 0xc9, 0xf8, 0x9b, 0x7c, 0x30, 0xc2, 0x92, 0x58,
+ 0xbf, 0x03, 0xaf, 0xb0, 0x5d, 0x62, 0xf7, 0xf0, 0x0b, 0x17, 0xf7, 0x7c,
+ 0xfc, 0x37, 0x96, 0x2e, 0x7f, 0x2c, 0x53, 0x1e, 0x31, 0xcb, 0xef, 0x3e,
+ 0x7d, 0x62, 0xe8, 0x02, 0xc5, 0x41, 0xb3, 0xf8, 0xe5, 0xc2, 0xdc, 0x58,
+ 0xbe, 0x62, 0x89, 0xd6, 0x2f, 0xff, 0xbd, 0x9d, 0xc8, 0x85, 0xe7, 0x62,
+ 0x81, 0xac, 0x5f, 0xc7, 0x2c, 0x8d, 0xd9, 0x96, 0x2c, 0x05, 0x8a, 0x83,
+ 0xc3, 0x63, 0x1b, 0xbd, 0x25, 0x8b, 0xcf, 0x1d, 0xac, 0x56, 0xc0, 0xa9,
+ 0x4b, 0x0a, 0x7a, 0x2e, 0xd3, 0x1f, 0xd5, 0x08, 0x83, 0x83, 0x7e, 0x22,
+ 0xdc, 0x84, 0x90, 0x64, 0x01, 0x06, 0x2f, 0xda, 0xd6, 0x77, 0xc5, 0x8b,
+ 0xcf, 0xee, 0x2c, 0x5f, 0xff, 0x6a, 0x47, 0x28, 0xd4, 0x0f, 0x26, 0x8f,
+ 0xac, 0x53, 0x1f, 0x6b, 0x8e, 0xdf, 0x67, 0x4f, 0xc5, 0x8b, 0xed, 0xe2,
+ 0x7e, 0x2c, 0x59, 0x96, 0x2f, 0xfa, 0x3d, 0xce, 0x7a, 0x3b, 0x31, 0x62,
+ 0xfc, 0xda, 0x63, 0x02, 0xeb, 0x16, 0xed, 0x62, 0xa4, 0x8f, 0x5c, 0x20,
+ 0x62, 0x39, 0x89, 0x74, 0x23, 0xf3, 0xc0, 0xcb, 0x6f, 0xfc, 0xdf, 0xee,
+ 0x59, 0xec, 0xef, 0xcb, 0x17, 0xfb, 0xf8, 0x7c, 0x7d, 0x4e, 0xb1, 0x52,
+ 0x3f, 0x51, 0xa0, 0xdf, 0xbd, 0xe7, 0x97, 0x16, 0x2f, 0x66, 0xa1, 0x62,
+ 0xf1, 0x61, 0xd6, 0x37, 0x0b, 0xcb, 0xff, 0x0b, 0x3b, 0x1e, 0xff, 0xe3,
+ 0xcc, 0xb1, 0x5d, 0xa2, 0xda, 0x64, 0x5d, 0xe5, 0xd6, 0x92, 0xc5, 0xee,
+ 0xf8, 0xeb, 0x17, 0xd9, 0x86, 0x71, 0x62, 0xa0, 0xf4, 0xf0, 0x4b, 0xc3,
+ 0xd6, 0xde, 0xb1, 0x70, 0x89, 0x62, 0xc1, 0x75, 0x8b, 0x6f, 0x58, 0xa8,
+ 0x4f, 0x87, 0x21, 0xb1, 0xa8, 0x43, 0x80, 0xb7, 0x82, 0x9e, 0x17, 0xde,
+ 0x2d, 0x7f, 0x75, 0x1e, 0xfe, 0x01, 0x62, 0xfe, 0x0f, 0x35, 0x99, 0x32,
+ 0xc5, 0x11, 0xef, 0x70, 0xbe, 0xfd, 0xdf, 0x23, 0x5c, 0x58, 0xbe, 0x07,
+ 0x03, 0xdd, 0x58, 0xbf, 0xde, 0xe0, 0xc4, 0xfa, 0x92, 0xc5, 0x61, 0xee,
+ 0xb9, 0x45, 0xfe, 0x9f, 0xb9, 0x70, 0x9a, 0x65, 0x8b, 0xef, 0x10, 0xa7,
+ 0x58, 0xa8, 0x3d, 0xb2, 0x37, 0xa8, 0x4d, 0x0f, 0x08, 0x4a, 0x10, 0xe2,
+ 0x7b, 0xbf, 0xb5, 0x20, 0x66, 0x4c, 0xb1, 0x70, 0x83, 0x58, 0xbf, 0xec,
+ 0x23, 0x30, 0x87, 0xf8, 0x58, 0xbd, 0x0d, 0xb8, 0xb1, 0x7e, 0x89, 0x70,
+ 0x5d, 0x2c, 0x53, 0x9e, 0x48, 0x07, 0xef, 0xdf, 0x6d, 0xf0, 0x4b, 0x17,
+ 0x38, 0x6b, 0x14, 0x33, 0xc1, 0x11, 0x4d, 0xdc, 0x99, 0x62, 0xf6, 0x83,
+ 0xe2, 0xc5, 0x62, 0x70, 0xa6, 0x97, 0xf4, 0x33, 0xa8, 0x40, 0x93, 0x17,
+ 0x88, 0xb7, 0x8c, 0xdf, 0xf7, 0x0d, 0xd4, 0x0f, 0xf1, 0xbd, 0x62, 0xff,
+ 0xfc, 0x5e, 0x2c, 0xe1, 0x8e, 0x53, 0xfb, 0xf8, 0x4b, 0x17, 0xd2, 0x0f,
+ 0xf0, 0xb1, 0x7b, 0x51, 0x25, 0x8a, 0x84, 0x4b, 0x3a, 0xae, 0xf2, 0x4b,
+ 0xf1, 0xf1, 0xb5, 0x32, 0xc5, 0xb7, 0x56, 0x2a, 0x0d, 0xf3, 0x94, 0xdf,
+ 0x07, 0x01, 0x38, 0xb1, 0x6e, 0x2c, 0x5f, 0xf1, 0x39, 0xf9, 0x87, 0x8d,
+ 0xd5, 0x8b, 0xf4, 0x0f, 0x1f, 0x75, 0x62, 0x88, 0xf9, 0x77, 0x9d, 0xdf,
+ 0xf9, 0xa7, 0x72, 0xfb, 0xf2, 0x37, 0x56, 0x2f, 0x1b, 0x9b, 0xab, 0x14,
+ 0xb1, 0x77, 0xe0, 0xd3, 0x5b, 0xf2, 0x1a, 0x58, 0xb6, 0x0c, 0xdc, 0x9c,
+ 0xb6, 0xfb, 0x4c, 0x66, 0xea, 0xc5, 0x32, 0x62, 0xff, 0x23, 0x28, 0x53,
+ 0xf0, 0x9a, 0xff, 0xf6, 0x98, 0xf1, 0xdf, 0xe0, 0x64, 0xfb, 0xab, 0x14,
+ 0x35, 0x48, 0x58, 0x4d, 0xc8, 0xe3, 0xbc, 0x83, 0x7d, 0xd7, 0xe3, 0x4b,
+ 0x17, 0x9b, 0x34, 0xb1, 0x5d, 0x9e, 0x00, 0x64, 0x97, 0xf8, 0x02, 0x70,
+ 0xff, 0x12, 0x58, 0xa8, 0x5c, 0xeb, 0xc6, 0xc6, 0x86, 0x9f, 0xdb, 0x9e,
+ 0x53, 0x08, 0xa1, 0x08, 0x61, 0x25, 0xd1, 0x25, 0x8b, 0xef, 0xc7, 0x61,
+ 0x16, 0x2c, 0x11, 0x62, 0xba, 0x37, 0x4c, 0x4d, 0x43, 0x3f, 0x2e, 0xd4,
+ 0x6c, 0x35, 0x8b, 0xf1, 0x39, 0xe3, 0xeb, 0x15, 0x86, 0xe5, 0x84, 0xaf,
+ 0xff, 0x41, 0xe2, 0x43, 0x28, 0xfb, 0xe6, 0x96, 0x29, 0x62, 0xa4, 0x7a,
+ 0x9b, 0x89, 0x17, 0xe2, 0x8f, 0xc6, 0xea, 0xc5, 0xef, 0x60, 0x16, 0x2f,
+ 0xe3, 0xb7, 0x38, 0xc3, 0x58, 0xbc, 0xfa, 0x35, 0x62, 0x84, 0x79, 0x86,
+ 0x17, 0x5f, 0xc5, 0x9b, 0xcb, 0x38, 0xb1, 0x73, 0x69, 0x62, 0xba, 0x3c,
+ 0x5f, 0x97, 0x5b, 0x8b, 0x17, 0xfb, 0x77, 0x68, 0x70, 0x4e, 0x6a, 0xc5,
+ 0xfe, 0x93, 0xe1, 0x67, 0xb8, 0xb1, 0x7e, 0xcc, 0x2e, 0xfc, 0xb1, 0x7f,
+ 0xb3, 0xe5, 0x9e, 0xfb, 0x2c, 0x50, 0xcf, 0x6b, 0xc5, 0x15, 0x08, 0xfa,
+ 0xc1, 0x2e, 0xce, 0x81, 0x08, 0xcb, 0xe1, 0xc3, 0xe9, 0x62, 0xf1, 0xf9,
+ 0xc5, 0x8b, 0xf1, 0xdf, 0xed, 0x32, 0xc5, 0x41, 0xe3, 0xb8, 0xf5, 0xff,
+ 0xb3, 0xb9, 0x7e, 0x38, 0x6f, 0xe1, 0x62, 0xa1, 0x70, 0x5e, 0x4b, 0x9d,
+ 0xb9, 0xb1, 0x2c, 0xc5, 0x5a, 0x69, 0xfb, 0x41, 0x46, 0x3b, 0xc4, 0x1f,
+ 0x34, 0x84, 0x20, 0xbf, 0xf7, 0x72, 0xfb, 0xc9, 0xb4, 0xdc, 0x58, 0xbe,
+ 0xf3, 0xbc, 0xeb, 0x16, 0xdc, 0x58, 0xba, 0x5c, 0x58, 0xb3, 0xc8, 0xd6,
+ 0xf6, 0x2b, 0x7d, 0xe6, 0x23, 0x12, 0x2c, 0x25, 0x8b, 0x46, 0x1b, 0x5f,
+ 0x91, 0xdd, 0x9a, 0x58, 0xbf, 0xc5, 0xee, 0x77, 0xc7, 0xdd, 0x58, 0xbf,
+ 0xb0, 0x7b, 0xb9, 0xde, 0xea, 0xc5, 0x2c, 0x53, 0x9f, 0xc9, 0x1c, 0x04,
+ 0x35, 0xa6, 0x4f, 0x43, 0x75, 0x01, 0xd4, 0x00, 0xb8, 0x44, 0xa2, 0x84,
+ 0x85, 0xe0, 0xfe, 0x25, 0x8b, 0xf7, 0x7c, 0x82, 0x9d, 0x62, 0xff, 0x85,
+ 0x37, 0x7c, 0x89, 0x9b, 0x7a, 0xc5, 0x61, 0xf4, 0x9c, 0xaa, 0xff, 0x37,
+ 0x3e, 0xe5, 0x10, 0xb1, 0x70, 0xbe, 0xb1, 0x7f, 0x8b, 0xaf, 0x79, 0xe5,
+ 0xc5, 0x8a, 0xd1, 0xff, 0x1c, 0xc4, 0x43, 0x17, 0xff, 0xd9, 0xfe, 0xe5,
+ 0xc9, 0xa4, 0xc5, 0xe8, 0x02, 0xc5, 0xfd, 0x07, 0x28, 0xee, 0x4b, 0x14,
+ 0xc8, 0x80, 0xfa, 0x95, 0xed, 0x6b, 0x16, 0x2f, 0x77, 0x2e, 0x2c, 0x5d,
+ 0xf6, 0xe1, 0xbc, 0x30, 0x76, 0xfa, 0x73, 0xbf, 0x96, 0x2f, 0xfd, 0x06,
+ 0x7d, 0xc7, 0xf8, 0x29, 0xd6, 0x2a, 0x0f, 0x93, 0x44, 0x97, 0xda, 0xc7,
+ 0x08, 0xb1, 0x7a, 0x0c, 0x92, 0xc5, 0xfe, 0xf7, 0x35, 0x9c, 0x8e, 0xd6,
+ 0x2d, 0x8b, 0x15, 0x87, 0x8c, 0x46, 0xb7, 0xb1, 0xfa, 0x58, 0xae, 0x91,
+ 0x42, 0xcc, 0x84, 0x41, 0x7f, 0xe8, 0x30, 0x39, 0xf9, 0x87, 0x8d, 0xd5,
+ 0x8a, 0x9d, 0x57, 0xc0, 0xe1, 0x5f, 0xd2, 0xf4, 0xd0, 0x91, 0xd1, 0x0f,
+ 0xe1, 0x8b, 0xe2, 0xfb, 0xb9, 0xda, 0xc5, 0xd2, 0xdd, 0x58, 0xbb, 0x38,
+ 0xb1, 0x70, 0x4d, 0x2c, 0x54, 0x2e, 0x3a, 0x64, 0xb9, 0x76, 0x78, 0x71,
+ 0x90, 0xc6, 0xc2, 0x0b, 0xdd, 0xf1, 0xac, 0x5f, 0xfd, 0xae, 0x84, 0xe3,
+ 0xc2, 0x1f, 0xd9, 0x62, 0xfd, 0x9f, 0xee, 0x5c, 0x58, 0xbf, 0x1f, 0x67,
+ 0xad, 0xe6, 0x2c, 0x53, 0x1e, 0xd8, 0x65, 0x57, 0x1e, 0x16, 0x2f, 0x86,
+ 0x28, 0xfa, 0xc5, 0xe6, 0xdf, 0x8b, 0x17, 0xfd, 0xd1, 0x3f, 0x38, 0x28,
+ 0xe9, 0x62, 0xb1, 0x12, 0x7a, 0x17, 0xf1, 0x18, 0x87, 0xae, 0x0f, 0xa5,
+ 0x8b, 0xff, 0x3b, 0x7a, 0x58, 0x69, 0x60, 0x16, 0x2f, 0xdd, 0xc8, 0xb0,
+ 0x6b, 0x15, 0x24, 0x40, 0xfc, 0x68, 0x8f, 0xae, 0xc3, 0x16, 0x29, 0x62,
+ 0xbe, 0x69, 0x3c, 0x31, 0x7f, 0x37, 0x3e, 0xd0, 0xcb, 0x17, 0xff, 0xe2,
+ 0xcc, 0xeb, 0xf1, 0xba, 0x59, 0xec, 0x60, 0x2c, 0x51, 0xd1, 0x04, 0xe5,
+ 0x97, 0xfb, 0x0b, 0xb8, 0xe3, 0xee, 0xac, 0x5f, 0x8a, 0x68, 0xfc, 0x2c,
+ 0x52, 0xc5, 0xd8, 0x35, 0x8b, 0x80, 0xfd, 0x9a, 0x3d, 0xe1, 0x97, 0xf7,
+ 0xb9, 0xf2, 0x70, 0x2c, 0x5f, 0x7f, 0xb7, 0xdd, 0x58, 0xa8, 0x3d, 0x5c,
+ 0x2e, 0xbe, 0x07, 0x20, 0x96, 0x2f, 0xf6, 0xbe, 0xed, 0xc6, 0xde, 0xb1,
+ 0x71, 0xac, 0xb1, 0x50, 0x7d, 0xf8, 0x44, 0xe6, 0xb7, 0xfe, 0xc2, 0x27,
+ 0xf6, 0xd9, 0x41, 0xd6, 0x2d, 0xd2, 0xc5, 0x7c, 0xf4, 0x84, 0x7f, 0x7e,
+ 0x7f, 0x09, 0xc3, 0x58, 0xad, 0x81, 0x76, 0x7e, 0x06, 0x07, 0x0a, 0x0c,
+ 0x85, 0xab, 0x42, 0xf7, 0x75, 0x4c, 0xf0, 0xa3, 0xf9, 0x13, 0x9b, 0x01,
+ 0x2c, 0xa1, 0x09, 0xc8, 0x47, 0xf9, 0xf8, 0x44, 0x57, 0xf1, 0x91, 0xad,
+ 0x3c, 0xcb, 0x17, 0xfc, 0x38, 0xe8, 0x30, 0x02, 0x3b, 0x58, 0xbd, 0xc7,
+ 0xed, 0x62, 0xff, 0x9f, 0x58, 0x76, 0xdc, 0x83, 0xac, 0x57, 0x48, 0x96,
+ 0x63, 0xd1, 0x0f, 0x5f, 0x3f, 0x37, 0x43, 0x58, 0xbf, 0x76, 0x31, 0xb7,
+ 0x16, 0x2f, 0x6b, 0x38, 0xb1, 0x7c, 0x70, 0xe4, 0xcb, 0x15, 0x07, 0xd7,
+ 0x85, 0x4c, 0x3b, 0x7d, 0xe8, 0xee, 0x4b, 0x17, 0xf3, 0x03, 0x70, 0x98,
+ 0x0b, 0x17, 0x60, 0x16, 0x2a, 0x73, 0xeb, 0xd1, 0x21, 0x18, 0x5f, 0xe8,
+ 0xf7, 0x37, 0x33, 0x46, 0xac, 0x5f, 0xf9, 0xdb, 0xd9, 0xa0, 0x1d, 0xe4,
+ 0xb1, 0x7f, 0x67, 0xbe, 0xe3, 0x65, 0x8a, 0xf9, 0xf5, 0xee, 0x1f, 0x5e,
+ 0x23, 0x7e, 0xb1, 0x78, 0x7f, 0x65, 0x8a, 0x63, 0xe0, 0x72, 0x51, 0x0f,
+ 0x5f, 0xe9, 0x89, 0xcc, 0xc2, 0x02, 0xc5, 0xe2, 0x89, 0xd6, 0x29, 0xcf,
+ 0x44, 0x8d, 0x2f, 0x7b, 0x03, 0x58, 0xa8, 0x5c, 0x0d, 0xc8, 0x63, 0x1a,
+ 0x61, 0xf8, 0x49, 0x3c, 0x25, 0xc8, 0xbf, 0x91, 0x81, 0x89, 0xf8, 0x21,
+ 0x05, 0x84, 0xb1, 0x7c, 0x11, 0xe3, 0x4b, 0x17, 0xf1, 0x44, 0xa3, 0x7c,
+ 0x2c, 0x58, 0x0b, 0x17, 0xe3, 0x5c, 0x85, 0x32, 0xc5, 0x41, 0xbc, 0x10,
+ 0x95, 0xf0, 0x98, 0x21, 0xd6, 0x2f, 0xed, 0xfa, 0x78, 0x6d, 0xc5, 0x8b,
+ 0x9a, 0x75, 0x8b, 0x62, 0xc5, 0x62, 0x68, 0x1d, 0x89, 0x31, 0x24, 0xcd,
+ 0x5a, 0x20, 0x39, 0x2b, 0x99, 0x10, 0xc5, 0xfb, 0x3f, 0xbd, 0xb4, 0xb1,
+ 0x7c, 0x38, 0x7d, 0x2c, 0x5f, 0xd2, 0xfb, 0x6f, 0xc1, 0xac, 0x56, 0x8f,
+ 0x48, 0x88, 0xad, 0x0b, 0x14, 0xe6, 0xc8, 0x88, 0x6f, 0x66, 0xa1, 0x62,
+ 0xfa, 0x63, 0x20, 0xd5, 0x8b, 0xe3, 0x43, 0x9b, 0x8b, 0x16, 0xfa, 0xc5,
+ 0xa1, 0x62, 0xde, 0x63, 0x46, 0x10, 0x4a, 0xb4, 0x7e, 0x44, 0x95, 0x7d,
+ 0x3f, 0xb3, 0xa5, 0x8b, 0xfc, 0xe6, 0x87, 0xff, 0xc4, 0x96, 0x2a, 0x13,
+ 0x30, 0xc1, 0xc6, 0x84, 0xc3, 0x90, 0xee, 0x12, 0xdf, 0xfb, 0xf8, 0x31,
+ 0xb7, 0x79, 0xdf, 0x96, 0x2f, 0xed, 0xa3, 0x0d, 0xf5, 0xa5, 0x8a, 0x9c,
+ 0xfc, 0xc6, 0x83, 0x7f, 0x87, 0x9e, 0xfc, 0x17, 0x4b, 0x17, 0xa1, 0xb7,
+ 0x16, 0x2f, 0xbd, 0xc0, 0xce, 0xb1, 0x4e, 0x78, 0x82, 0x1f, 0xbb, 0x76,
+ 0x4b, 0x17, 0xff, 0xfc, 0x08, 0x2e, 0x9f, 0xe4, 0xe0, 0xd4, 0x75, 0x9a,
+ 0xd3, 0x2c, 0x5f, 0xf0, 0xf6, 0xe7, 0x23, 0x34, 0x05, 0x8b, 0xdf, 0x0f,
+ 0x8b, 0x15, 0x87, 0xb4, 0xe7, 0x77, 0xdc, 0xe3, 0x1d, 0x62, 0xf7, 0x3e,
+ 0xcb, 0x17, 0xf9, 0x87, 0xe2, 0x7e, 0xf8, 0xb1, 0x4b, 0x17, 0xf7, 0x1b,
+ 0xbc, 0xef, 0xcb, 0x15, 0xd9, 0xbc, 0xf0, 0x65, 0xd3, 0xc2, 0xc5, 0x42,
+ 0x2a, 0x9d, 0xc0, 0x44, 0x57, 0x34, 0x96, 0x2f, 0x8a, 0x33, 0xb5, 0x8b,
+ 0x04, 0x58, 0xbe, 0xce, 0x30, 0x16, 0x29, 0x62, 0xd3, 0x2c, 0x4c, 0x4c,
+ 0xa8, 0x56, 0xd9, 0x39, 0x18, 0xde, 0x30, 0x87, 0xb1, 0xbf, 0xc3, 0x01,
+ 0xc8, 0x00, 0x46, 0x50, 0xc7, 0xe1, 0x77, 0x85, 0xcc, 0x22, 0xdc, 0x14,
+ 0x0c, 0xba, 0xff, 0xa4, 0xde, 0x04, 0x7c, 0x3e, 0x2c, 0x5f, 0xa5, 0xf8,
+ 0x23, 0x56, 0x2e, 0x10, 0x16, 0x2a, 0x63, 0xfc, 0x73, 0xb0, 0x85, 0x34,
+ 0x14, 0x7c, 0x84, 0xc0, 0xaa, 0xbe, 0xc1, 0x08, 0x3d, 0x88, 0x9f, 0x61,
+ 0x43, 0x04, 0x2d, 0x20, 0xc4, 0xa8, 0xd9, 0xe1, 0xab, 0x28, 0xde, 0x87,
+ 0x2e, 0x9b, 0x27, 0x56, 0x4d, 0x8e, 0xd3, 0xa9, 0x55, 0xfd, 0xca, 0x18,
+ 0x69, 0x54, 0x3b, 0xb0, 0xa9, 0x9a, 0x38, 0xcd, 0x4a, 0xba, 0x3c, 0xa1,
+ 0x0f, 0xcf, 0x58, 0x3c, 0xe7, 0xf0, 0x25, 0x39, 0x05, 0xd7, 0x4a, 0x73,
+ 0xf3, 0x93, 0xbf, 0xfe, 0x9c, 0xf0, 0x14, 0x7a, 0xbb, 0xdc, 0x0c, 0x85,
+ 0x76, 0xe4, 0x69, 0xe1, 0xce, 0x17, 0x04, 0x8d, 0x2a, 0xee, 0xa1, 0x62,
+ 0xf9, 0xfa, 0x8d, 0x2c, 0x51, 0x86, 0xec, 0x20, 0xc5, 0xc6, 0x62, 0xc5,
+ 0xfe, 0x6e, 0xc0, 0xff, 0xcd, 0xc5, 0x8b, 0xff, 0x34, 0x7b, 0xee, 0x6e,
+ 0x10, 0x16, 0x2f, 0xff, 0x3e, 0xb6, 0xbf, 0xb6, 0xfb, 0xbe, 0x98, 0x96,
+ 0x29, 0x91, 0xbb, 0xa1, 0x8f, 0x9b, 0xef, 0x3e, 0xbf, 0x72, 0x6c, 0xd3,
+ 0xac, 0x5f, 0x47, 0x4e, 0xeb, 0x17, 0xb5, 0x92, 0x58, 0xb9, 0x8e, 0xb1,
+ 0x4c, 0x7f, 0xe7, 0x29, 0xf1, 0x10, 0x41, 0xdb, 0xfb, 0x3d, 0x0c, 0x7e,
+ 0x2c, 0x5e, 0x80, 0x32, 0xc5, 0xfd, 0x12, 0xcd, 0x67, 0x16, 0x2f, 0xdf,
+ 0xcf, 0x47, 0xd6, 0x28, 0x67, 0xaa, 0xe5, 0xb7, 0xff, 0xb5, 0xa1, 0x4b,
+ 0x59, 0x1d, 0xc9, 0x8e, 0xb1, 0x74, 0xcc, 0xb1, 0x58, 0x7c, 0x8e, 0x99,
+ 0x7b, 0x81, 0xf1, 0x62, 0xff, 0xe9, 0x78, 0x53, 0xec, 0xfd, 0xce, 0xdc,
+ 0x58, 0xbd, 0xd3, 0xef, 0x58, 0xbf, 0xf7, 0xc5, 0xdf, 0x20, 0xef, 0xdf,
+ 0x96, 0x2d, 0x9d, 0xa2, 0xb3, 0x49, 0x5e, 0x20, 0xbf, 0xf7, 0xa0, 0xfc,
+ 0x86, 0x9d, 0xfc, 0xb1, 0x7f, 0x3e, 0xeb, 0xe7, 0x7e, 0x58, 0xae, 0xcf,
+ 0xc3, 0xe7, 0xf7, 0xf9, 0xf0, 0x6d, 0xd9, 0x3a, 0xc5, 0x61, 0xea, 0x88,
+ 0x8e, 0xe1, 0x9a, 0xb1, 0x7d, 0x1e, 0x93, 0xac, 0x5f, 0x68, 0x24, 0x12,
+ 0xc5, 0x89, 0x62, 0xa0, 0xda, 0x98, 0x49, 0x7b, 0xc5, 0x0b, 0x17, 0x7f,
+ 0x66, 0x17, 0x74, 0xb2, 0x30, 0x16, 0x85, 0xec, 0xc7, 0xba, 0x2d, 0x3b,
+ 0x8f, 0xe1, 0x0a, 0xe4, 0x05, 0x0c, 0xbe, 0x43, 0xef, 0xc4, 0x3b, 0xc6,
+ 0x4c, 0x57, 0x0c, 0x86, 0xb6, 0x59, 0x30, 0x71, 0x48, 0x98, 0xbf, 0xb3,
+ 0x5d, 0x3b, 0xf4, 0xa8, 0xb3, 0x4b, 0xff, 0xf3, 0xe9, 0xe5, 0xb3, 0xd1,
+ 0x64, 0xfa, 0xee, 0x06, 0xb1, 0x7b, 0xac, 0x3a, 0xc5, 0xfe, 0xce, 0x72,
+ 0x00, 0x1c, 0xeb, 0x17, 0xe6, 0xd1, 0x99, 0xf5, 0x8b, 0xef, 0xb3, 0x92,
+ 0xc5, 0x7c, 0xf2, 0xbc, 0x53, 0x7f, 0xfd, 0xf6, 0xe3, 0x78, 0xb3, 0x78,
+ 0xe2, 0x6f, 0xac, 0x5f, 0xe0, 0x47, 0x19, 0xfb, 0x31, 0x62, 0xfd, 0xa6,
+ 0x9c, 0x5b, 0xab, 0x17, 0xbe, 0xc3, 0x58, 0xb0, 0xb0, 0xf2, 0xa6, 0x2d,
+ 0xbd, 0x33, 0x8d, 0x62, 0xff, 0xd8, 0xf3, 0x77, 0xed, 0xa6, 0x34, 0x2c,
+ 0x54, 0x1f, 0x0e, 0x87, 0xaf, 0xf6, 0x61, 0xa3, 0x26, 0x9d, 0x62, 0xff,
+ 0xe3, 0x8b, 0xff, 0x73, 0x73, 0x59, 0xe5, 0x8a, 0x19, 0xfd, 0x1c, 0xd2,
+ 0xff, 0xf4, 0xf1, 0xd7, 0x32, 0x26, 0xc9, 0xf0, 0x96, 0x2b, 0x0f, 0xb9,
+ 0xc8, 0xaf, 0x3e, 0x79, 0x62, 0xff, 0x9a, 0x4d, 0xf1, 0x1c, 0xec, 0xb1,
+ 0x7f, 0x39, 0x03, 0xd1, 0x32, 0xc5, 0x78, 0xf9, 0xf7, 0x0e, 0x6f, 0xb5,
+ 0xf7, 0xd9, 0x85, 0x7d, 0x63, 0x1e, 0xc8, 0x40, 0x74, 0x44, 0xca, 0x47,
+ 0x7f, 0xfc, 0x22, 0x4a, 0x30, 0x9e, 0x10, 0x07, 0x08, 0x3b, 0xfe, 0xc9,
+ 0xa4, 0xfa, 0x9f, 0xe2, 0x58, 0xbf, 0xde, 0xfe, 0x34, 0xe7, 0x85, 0x8b,
+ 0xfb, 0xc5, 0x19, 0xf7, 0x58, 0xbf, 0xf4, 0x68, 0x1e, 0xe7, 0xf1, 0x86,
+ 0xb1, 0x76, 0xc6, 0xeb, 0x16, 0x9d, 0x62, 0xf4, 0xa3, 0xb5, 0x8b, 0x64,
+ 0x1b, 0x19, 0x84, 0xef, 0x98, 0x9e, 0x75, 0x8b, 0xfa, 0x70, 0xf7, 0x1c,
+ 0x80, 0xb1, 0x7f, 0xe7, 0x20, 0x67, 0xa0, 0x98, 0x0b, 0x15, 0x07, 0xdf,
+ 0xb8, 0x67, 0x43, 0x54, 0x07, 0x87, 0x9d, 0x9a, 0x7c, 0xb1, 0xcf, 0xc9,
+ 0x37, 0x84, 0xc1, 0xc2, 0x46, 0xdf, 0x58, 0xbf, 0x7e, 0x39, 0xf6, 0x58,
+ 0xbf, 0xf3, 0x7a, 0x0e, 0x4e, 0x6f, 0xd9, 0x62, 0xe8, 0xfa, 0xc5, 0xfc,
+ 0x59, 0xbf, 0xef, 0x25, 0x8b, 0xcf, 0xae, 0x2c, 0x5b, 0x66, 0x74, 0x6d,
+ 0xe0, 0x94, 0xc5, 0x1f, 0x3e, 0xf0, 0xb9, 0x85, 0xf5, 0xb2, 0x9d, 0xa0,
+ 0x48, 0xd4, 0xaf, 0xa2, 0x72, 0x12, 0xc5, 0xff, 0xfe, 0xcf, 0x37, 0x3d,
+ 0xfc, 0x38, 0x1f, 0x59, 0xbf, 0x06, 0xb1, 0x7f, 0x84, 0xf3, 0xeb, 0x0f,
+ 0xb3, 0xf4, 0x42, 0xf0, 0x8e, 0xb6, 0x59, 0x3e, 0xdd, 0x1e, 0x34, 0xe2,
+ 0x33, 0xce, 0x38, 0x94, 0x2d, 0x2e, 0x0a, 0x76, 0xb1, 0x78, 0xe1, 0xe9,
+ 0x62, 0xfe, 0x11, 0xb0, 0x60, 0x8d, 0x58, 0xa6, 0x3d, 0x13, 0x07, 0xef,
+ 0x7d, 0x8c, 0x58, 0xb3, 0x2c, 0x5f, 0xa3, 0xdb, 0x8c, 0x75, 0x8a, 0x39,
+ 0xbc, 0x00, 0x8d, 0xf7, 0x0a, 0x0c, 0x58, 0xbd, 0xd6, 0x7d, 0x62, 0xee,
+ 0x42, 0xc5, 0xf8, 0x5c, 0xf4, 0x71, 0x62, 0xa4, 0x78, 0x13, 0x0b, 0xdf,
+ 0x76, 0xc2, 0xed, 0x62, 0xa1, 0x14, 0xcc, 0xbc, 0x22, 0x3b, 0xf8, 0xa0,
+ 0xfc, 0x69, 0xd6, 0x2f, 0x16, 0x84, 0xb1, 0x52, 0x3c, 0xb6, 0x2e, 0xb8,
+ 0xcd, 0x2c, 0x5f, 0x84, 0xdb, 0x0c, 0x2a, 0x14, 0x58, 0xbc, 0xd8, 0x75,
+ 0x8b, 0xc2, 0xef, 0x8b, 0x17, 0xe0, 0xfc, 0x50, 0x05, 0x8a, 0x98, 0xf9,
+ 0x34, 0x39, 0xbc, 0x7e, 0xfd, 0x38, 0xa4, 0x28, 0x58, 0xa8, 0x3d, 0xc6,
+ 0x32, 0xbe, 0x63, 0xb0, 0x45, 0x8b, 0x84, 0x1a, 0xc5, 0xe2, 0xce, 0x2c,
+ 0x54, 0x1e, 0xcc, 0xc4, 0x81, 0x8c, 0xdf, 0x7d, 0xbb, 0xe2, 0xc5, 0xd1,
+ 0xda, 0xc5, 0xd1, 0xf5, 0x8b, 0xef, 0x33, 0x86, 0xb1, 0x6d, 0xc5, 0x8b,
+ 0x1a, 0xb1, 0x4c, 0x6a, 0x04, 0x2b, 0x5b, 0xa8, 0xbe, 0x98, 0x90, 0xe3,
+ 0x1c, 0x17, 0x0d, 0x2e, 0xe3, 0x21, 0x62, 0xed, 0x1a, 0xb1, 0x71, 0xf6,
+ 0x42, 0x8b, 0xac, 0xb0, 0xdc, 0x32, 0x2c, 0x5a, 0xec, 0x85, 0xa1, 0x93,
+ 0x33, 0xce, 0x88, 0x4e, 0x33, 0xf8, 0x7b, 0xbb, 0xc8, 0xa1, 0xdc, 0x62,
+ 0x78, 0x63, 0x17, 0x63, 0x2c, 0x58, 0x6b, 0x16, 0x3a, 0xc5, 0x61, 0xa4,
+ 0x71, 0x2b, 0x12, 0xc5, 0xff, 0x4b, 0x67, 0x35, 0xd3, 0xbf, 0x4a, 0x8a,
+ 0x00, 0xac, 0x3d, 0xc7, 0x11, 0xbf, 0xcc, 0x78, 0xdd, 0xfe, 0x4e, 0xb1,
+ 0x79, 0xf4, 0x6a, 0xc5, 0xff, 0xdb, 0x8e, 0x40, 0xcf, 0x41, 0x30, 0x16,
+ 0x2d, 0xb3, 0x24, 0xdb, 0xf0, 0xe8, 0xef, 0x7f, 0x20, 0x30, 0xdc, 0x31,
+ 0xeb, 0xf8, 0xbd, 0xc8, 0x1c, 0x2c, 0x5d, 0x23, 0xac, 0x5f, 0xcd, 0xc9,
+ 0x8a, 0x06, 0xb1, 0x4b, 0x17, 0x77, 0x25, 0x8a, 0xec, 0xd2, 0xe8, 0x32,
+ 0x86, 0x7e, 0xae, 0xa7, 0x7e, 0x8e, 0xfc, 0xfa, 0x58, 0xbf, 0x41, 0x67,
+ 0x7e, 0x58, 0xbe, 0xe4, 0x98, 0x0b, 0x14, 0x73, 0xcb, 0xf1, 0x45, 0xb7,
+ 0xac, 0x5b, 0xcb, 0x15, 0x23, 0x4d, 0xd0, 0xa5, 0xfc, 0xdf, 0x82, 0x8f,
+ 0x2c, 0x5e, 0x1b, 0xb2, 0xc5, 0x42, 0xa0, 0x19, 0x16, 0xe4, 0x23, 0x58,
+ 0x85, 0xdd, 0x09, 0x23, 0x84, 0x42, 0x2c, 0xbd, 0x34, 0x49, 0x62, 0xed,
+ 0x79, 0x62, 0xdb, 0x38, 0x6d, 0xb8, 0x3d, 0x7f, 0xd1, 0xef, 0xe1, 0xf3,
+ 0x58, 0xb1, 0x7d, 0x36, 0x67, 0x4b, 0x17, 0xef, 0x1a, 0xfc, 0xd9, 0xd1,
+ 0xee, 0x06, 0x71, 0x52, 0x46, 0x49, 0x90, 0x85, 0xbf, 0xfb, 0xdc, 0xd9,
+ 0xd8, 0x41, 0x60, 0x54, 0x2c, 0x07, 0x31, 0x62, 0xb6, 0x53, 0xf9, 0x88,
+ 0xdc, 0x9c, 0xa6, 0xee, 0x79, 0x62, 0xd0, 0xb1, 0x6f, 0xac, 0x51, 0xcd,
+ 0x18, 0x84, 0x6f, 0x82, 0xbb, 0xfb, 0xe2, 0xc5, 0xe1, 0xe1, 0xd6, 0x2f,
+ 0xfe, 0xf3, 0x0b, 0x81, 0x9f, 0x5a, 0x63, 0x56, 0x2f, 0xff, 0xdb, 0xe3,
+ 0xec, 0x3f, 0xc4, 0xb8, 0xff, 0x6e, 0x2c, 0x5f, 0xf4, 0x7e, 0x27, 0xd4,
+ 0x60, 0xd6, 0x2f, 0xee, 0x41, 0xca, 0x26, 0x58, 0xb7, 0xd6, 0x2f, 0x06,
+ 0x53, 0x2c, 0x5b, 0xd8, 0x6c, 0x40, 0x25, 0x76, 0x4e, 0xb1, 0x58, 0x6f,
+ 0x88, 0x9a, 0xf9, 0x8f, 0x13, 0x2c, 0x54, 0xe9, 0xea, 0x48, 0x75, 0x92,
+ 0x3e, 0xae, 0x03, 0x92, 0x84, 0xee, 0xe0, 0xfd, 0xff, 0xe1, 0x6a, 0x59,
+ 0xc6, 0x10, 0x5c, 0xa0, 0xeb, 0x16, 0xe2, 0xc5, 0xfb, 0x91, 0xf6, 0xde,
+ 0xb1, 0x7f, 0x7d, 0xdf, 0xf1, 0x25, 0x8b, 0xe1, 0xb1, 0x01, 0x62, 0xb6,
+ 0xa2, 0x2f, 0x04, 0x98, 0xa9, 0xcb, 0x6f, 0xff, 0xb5, 0x38, 0xfe, 0xda,
+ 0xe4, 0x6a, 0x66, 0xfa, 0xc5, 0xff, 0x81, 0xc2, 0x73, 0x73, 0x7b, 0x69,
+ 0x62, 0xff, 0xe6, 0xf8, 0xbe, 0xed, 0xdf, 0x20, 0xd5, 0x8a, 0xc4, 0x43,
+ 0xf9, 0x06, 0xf0, 0x87, 0x8b, 0x17, 0xf6, 0xbc, 0x50, 0x7e, 0x2c, 0x5f,
+ 0xff, 0xb4, 0x37, 0x23, 0x7f, 0x9b, 0xba, 0x63, 0xc1, 0xab, 0x15, 0x88,
+ 0x88, 0x11, 0x75, 0xb7, 0x16, 0x2a, 0x13, 0xd8, 0xc8, 0x6d, 0x31, 0x17,
+ 0xe1, 0x4a, 0x02, 0x2b, 0xcf, 0xac, 0x58, 0xb8, 0x40, 0x58, 0xbd, 0xc8,
+ 0x02, 0xc5, 0xf4, 0x98, 0xb1, 0x62, 0xbc, 0x6f, 0x8c, 0x1d, 0xbe, 0xe9,
+ 0xdf, 0xa5, 0x45, 0xbe, 0x5e, 0xdc, 0x7f, 0x2c, 0x5f, 0xe6, 0x28, 0x38,
+ 0x1f, 0xcb, 0x17, 0xa6, 0xc0, 0x2c, 0x5f, 0x83, 0x9f, 0xf1, 0xa5, 0x8a,
+ 0xe9, 0x36, 0x0e, 0xc7, 0x19, 0x5b, 0x44, 0x47, 0x31, 0xf9, 0x03, 0x99,
+ 0x78, 0x7a, 0xff, 0x9b, 0xf1, 0xdc, 0x6e, 0xe7, 0x6b, 0x17, 0xf8, 0x39,
+ 0xdc, 0x7f, 0x8e, 0x2c, 0x5f, 0xff, 0xf3, 0xcc, 0x36, 0xd7, 0xf0, 0x65,
+ 0x1d, 0x3c, 0xe5, 0x07, 0x58, 0xbf, 0xed, 0x0b, 0x9f, 0x79, 0x01, 0x96,
+ 0x2c, 0xc0, 0x45, 0x0f, 0x99, 0xef, 0xbd, 0xc7, 0xf2, 0xc5, 0xff, 0xb5,
+ 0x9b, 0xb3, 0x7d, 0xce, 0xdc, 0x58, 0xbb, 0x27, 0xc3, 0xe6, 0xd1, 0x1d,
+ 0x74, 0x9c, 0x97, 0xe1, 0xae, 0x50, 0x8e, 0xb1, 0x8b, 0x17, 0xfc, 0xe5,
+ 0xd7, 0x23, 0xef, 0xba, 0xb1, 0x46, 0x9e, 0x7f, 0x84, 0xef, 0xb0, 0x9a,
+ 0x65, 0x8b, 0xe6, 0xcd, 0x6f, 0x58, 0xbe, 0xee, 0x53, 0xc2, 0xc5, 0xe8,
+ 0x33, 0x71, 0x62, 0xb0, 0xf1, 0xb4, 0x4b, 0x7d, 0xd7, 0xb3, 0xa5, 0x8b,
+ 0x12, 0xc5, 0x61, 0xb6, 0xf1, 0x2d, 0xef, 0xc6, 0x96, 0x2f, 0xdf, 0x6d,
+ 0x7d, 0xd6, 0x2f, 0xff, 0x7e, 0x27, 0xf6, 0x7c, 0xb3, 0xdf, 0x65, 0x8b,
+ 0xc7, 0xc1, 0xac, 0x58, 0xeb, 0x17, 0xfa, 0x27, 0x1e, 0x19, 0xcd, 0x98,
+ 0x45, 0xf6, 0x0e, 0xcc, 0x50, 0xe9, 0x41, 0x8e, 0xd4, 0x93, 0xab, 0xc5,
+ 0x7f, 0xc3, 0x7a, 0xf1, 0xf3, 0xb5, 0x8b, 0xff, 0x89, 0xc1, 0xc1, 0xc7,
+ 0xb8, 0xf3, 0xac, 0x50, 0xcf, 0x8f, 0xc3, 0xd7, 0xd2, 0xe0, 0x7c, 0x58,
+ 0xa8, 0x3c, 0x7f, 0x11, 0x5f, 0x67, 0xb9, 0x8b, 0x17, 0xf3, 0xf6, 0x36,
+ 0x29, 0xd6, 0x2f, 0xf6, 0x6e, 0xe9, 0x8f, 0x06, 0xac, 0x54, 0x22, 0x23,
+ 0x44, 0x5f, 0x2f, 0xbd, 0xcf, 0x8d, 0x62, 0xfc, 0x1f, 0x8a, 0x00, 0xb1,
+ 0x47, 0x3c, 0x7d, 0xe3, 0xd7, 0xfb, 0xa7, 0xd4, 0xfb, 0xfc, 0x25, 0x8b,
+ 0x8a, 0x16, 0x2f, 0xfe, 0xf7, 0x1b, 0x90, 0x59, 0xef, 0xb2, 0xc5, 0xff,
+ 0x9c, 0x26, 0x98, 0xdc, 0xfb, 0x49, 0x62, 0xff, 0xc0, 0x11, 0x74, 0xe3,
+ 0xfc, 0x71, 0x62, 0xe1, 0x62, 0xc5, 0xff, 0x01, 0xbc, 0x4f, 0xe8, 0x1a,
+ 0xc5, 0xe2, 0xcf, 0xac, 0x57, 0x49, 0xbf, 0x68, 0xe4, 0xe2, 0xdf, 0x43,
+ 0x02, 0x09, 0x20, 0x70, 0x5f, 0x79, 0xc5, 0xff, 0x37, 0x30, 0x71, 0x33,
+ 0x1d, 0x62, 0xfc, 0x38, 0xdd, 0x11, 0xd6, 0x2f, 0xfd, 0x93, 0xce, 0x21,
+ 0xc6, 0xa0, 0x6b, 0x17, 0xef, 0x36, 0xa3, 0x7a, 0xc5, 0xff, 0x3f, 0x23,
+ 0x08, 0x7f, 0x85, 0x8b, 0xfd, 0xf8, 0x1b, 0x6f, 0x81, 0xac, 0x5f, 0xf6,
+ 0xb3, 0xbf, 0x93, 0xee, 0xce, 0xb1, 0x6c, 0x19, 0xf9, 0x9c, 0xd6, 0xdc,
+ 0xd2, 0x34, 0x4a, 0x15, 0x54, 0x49, 0x94, 0x72, 0x1f, 0x75, 0x0b, 0x81,
+ 0x99, 0x1d, 0x17, 0x4e, 0x8c, 0x73, 0xa2, 0xc7, 0x8d, 0xa6, 0xfc, 0x1e,
+ 0x7d, 0xce, 0xb1, 0x70, 0x8d, 0x58, 0xbe, 0x3c, 0xd0, 0x1a, 0xc5, 0xd1,
+ 0xf5, 0x8b, 0xff, 0x04, 0x73, 0x87, 0xa0, 0x1d, 0xb8, 0xb1, 0x5d, 0x23,
+ 0x04, 0xe5, 0x2e, 0x32, 0x44, 0xa1, 0x05, 0xef, 0xe1, 0x01, 0x88, 0x5a,
+ 0x58, 0xbc, 0xc5, 0xe5, 0x8b, 0x85, 0xda, 0xc5, 0xff, 0x3c, 0xbd, 0xcc,
+ 0x33, 0xec, 0xb1, 0x7b, 0xb7, 0xfa, 0xc5, 0x1d, 0x17, 0x6e, 0x5c, 0x01,
+ 0xc2, 0x19, 0x11, 0xd5, 0xfe, 0x8e, 0x67, 0x7e, 0x6d, 0x2c, 0x5f, 0xcf,
+ 0x3e, 0xfc, 0x29, 0xd6, 0x2b, 0x47, 0xcb, 0xb8, 0x69, 0x7f, 0xbe, 0x22,
+ 0x1f, 0xd8, 0xc5, 0x8b, 0xff, 0xa6, 0x10, 0xdc, 0x81, 0xb5, 0x8f, 0xe5,
+ 0x8a, 0xf9, 0xfe, 0xf8, 0xd6, 0xf6, 0xa3, 0xcb, 0x17, 0xfe, 0x8f, 0x09,
+ 0xe7, 0x8f, 0xc1, 0xd6, 0x2f, 0xe9, 0x9c, 0x7f, 0x63, 0xac, 0x5f, 0xde,
+ 0x6c, 0x1c, 0x1d, 0x62, 0xbb, 0x44, 0xdf, 0x8f, 0xcc, 0x2f, 0xbe, 0x79,
+ 0xc4, 0x4b, 0x17, 0x70, 0x96, 0x2f, 0xee, 0xf9, 0x1d, 0x61, 0xd6, 0x2f,
+ 0x8f, 0xd6, 0x12, 0xc5, 0x42, 0xa3, 0xbc, 0x85, 0x16, 0x88, 0x9e, 0x17,
+ 0x04, 0x65, 0xc2, 0x31, 0x0b, 0x86, 0x61, 0x4b, 0x17, 0xff, 0xb1, 0x8d,
+ 0xfe, 0x61, 0x75, 0x9d, 0xf9, 0x62, 0xff, 0xfe, 0x89, 0x61, 0xe3, 0xaf,
+ 0x73, 0x01, 0x19, 0xdc, 0x96, 0x2b, 0x48, 0xa7, 0x24, 0xbb, 0xf4, 0xd0,
+ 0x45, 0x0b, 0x17, 0xff, 0xf3, 0xb7, 0xa2, 0x4d, 0xa0, 0x02, 0x37, 0x33,
+ 0x46, 0xac, 0x5d, 0xd6, 0x96, 0x2f, 0xf8, 0x03, 0x28, 0x97, 0xf8, 0x05,
+ 0x8b, 0x12, 0xc5, 0x68, 0xf2, 0xdc, 0xea, 0xa1, 0x3d, 0xf1, 0xc2, 0xcd,
+ 0x88, 0xbe, 0x4f, 0xe5, 0xe1, 0x32, 0x5f, 0x9e, 0x78, 0xfb, 0xac, 0x5f,
+ 0xda, 0x79, 0xfc, 0xff, 0x58, 0xbc, 0x50, 0x6a, 0xc5, 0xf6, 0x6e, 0xbf,
+ 0xd6, 0x2e, 0x7f, 0x74, 0x78, 0x5c, 0x1d, 0xa8, 0x44, 0xf9, 0x38, 0xdf,
+ 0xf1, 0x67, 0xbd, 0x93, 0x3c, 0xcb, 0x17, 0xf6, 0x79, 0xfa, 0x69, 0x2c,
+ 0x5e, 0x98, 0x5f, 0x58, 0xb8, 0x67, 0x58, 0xbf, 0x64, 0xd2, 0x8e, 0xd6,
+ 0x2b, 0x0f, 0x84, 0xd1, 0xf2, 0x18, 0xba, 0x09, 0x62, 0xba, 0x4c, 0xb9,
+ 0x88, 0x66, 0x3a, 0xfc, 0x23, 0xcc, 0x2e, 0xbd, 0xf3, 0x1d, 0x62, 0xff,
+ 0xe1, 0x73, 0xef, 0x31, 0x60, 0x05, 0xc5, 0x8b, 0xf6, 0x17, 0xa3, 0x8b,
+ 0x17, 0x9c, 0x8d, 0x58, 0xb4, 0x96, 0x2f, 0xb3, 0x7b, 0x69, 0x62, 0xfe,
+ 0x00, 0xb9, 0xbb, 0x9d, 0xac, 0x54, 0xc7, 0xae, 0x02, 0x4a, 0xc4, 0x46,
+ 0x3b, 0x4d, 0xff, 0x9f, 0xbe, 0xf8, 0xc3, 0xc3, 0x38, 0xb1, 0x50, 0xaf,
+ 0x7b, 0x23, 0xf5, 0x65, 0x2d, 0x0f, 0x7d, 0x19, 0xc9, 0xca, 0x15, 0x3c,
+ 0x21, 0xbf, 0xfe, 0x7e, 0xf5, 0x99, 0xd9, 0x9f, 0x14, 0x77, 0xc5, 0x8b,
+ 0xf3, 0xcf, 0xd3, 0x8d, 0x62, 0xff, 0xe8, 0xf3, 0x03, 0x8f, 0xd8, 0x1b,
+ 0x7a, 0xc5, 0xf3, 0xf4, 0xf3, 0xac, 0x5d, 0xe6, 0xd1, 0xf5, 0xf1, 0x1e,
+ 0xfc, 0xe4, 0x3f, 0xc2, 0xc5, 0xf0, 0x18, 0x8d, 0x58, 0xa7, 0x3c, 0xa0,
+ 0x13, 0xd0, 0x55, 0xd0, 0x19, 0xec, 0x07, 0x7b, 0x08, 0x86, 0x23, 0xff,
+ 0x9d, 0xb2, 0x50, 0xd9, 0x1c, 0xa1, 0x4c, 0x8e, 0xc8, 0xd7, 0x2e, 0xa3,
+ 0xcf, 0xee, 0x11, 0x4c, 0x47, 0xba, 0x45, 0x34, 0xa1, 0x5d, 0x43, 0x7c,
+ 0xf0, 0xa9, 0xfc, 0xe4, 0x13, 0xc6, 0x48, 0x08, 0xc1, 0x8a, 0x57, 0x47,
+ 0x25, 0x2c, 0xfa, 0x70, 0xe4, 0x4f, 0x3b, 0x8a, 0x81, 0xc2, 0x54, 0x23,
+ 0xbd, 0xd1, 0x3a, 0xc5, 0xcf, 0xe5, 0x8b, 0xcf, 0xde, 0xc8, 0xcd, 0x79,
+ 0xc6, 0x2f, 0xf3, 0xf7, 0xb2, 0x1e, 0x17, 0x4b, 0x15, 0xb2, 0xa9, 0xe8,
+ 0xa5, 0x05, 0x88, 0xda, 0xf4, 0x85, 0x25, 0x8b, 0xfa, 0x4f, 0xa9, 0xfe,
+ 0x25, 0x8b, 0xf7, 0x20, 0x01, 0xce, 0xb1, 0x6c, 0x98, 0xf6, 0xf8, 0x61,
+ 0x7c, 0xdb, 0x84, 0x05, 0x8b, 0xde, 0xe7, 0x6b, 0x17, 0xfe, 0xf3, 0x49,
+ 0xbe, 0x23, 0x9d, 0x96, 0x2e, 0x1e, 0xcc, 0x93, 0x24, 0x1b, 0xcb, 0x94,
+ 0x70, 0x94, 0x31, 0xfb, 0xc7, 0xc2, 0x58, 0xbf, 0xd9, 0xce, 0x40, 0x03,
+ 0x9d, 0x62, 0xe7, 0xe9, 0x62, 0xff, 0xbd, 0x34, 0x9f, 0x53, 0xfc, 0x4b,
+ 0x15, 0xd1, 0xea, 0xf6, 0x31, 0x7b, 0xa6, 0x92, 0xc5, 0xff, 0xed, 0x40,
+ 0xf2, 0x69, 0x3e, 0xa7, 0xf8, 0x96, 0x2f, 0xfe, 0x0f, 0xad, 0xb1, 0xad,
+ 0x31, 0x3f, 0x4b, 0x17, 0xb7, 0x08, 0x0b, 0x17, 0xfa, 0x6d, 0x8b, 0x1b,
+ 0x7b, 0x9d, 0x62, 0x98, 0xf6, 0xfc, 0x41, 0x79, 0xbe, 0x25, 0x8b, 0xfe,
+ 0xc9, 0xa4, 0xfa, 0x9f, 0xe2, 0x58, 0xba, 0x26, 0x58, 0xbf, 0xe3, 0xcd,
+ 0x27, 0xd4, 0xff, 0x12, 0xc5, 0xf6, 0xe3, 0x90, 0x09, 0x12, 0x3e, 0x3c,
+ 0x0c, 0x62, 0xa1, 0x57, 0x90, 0xc7, 0x32, 0x11, 0x6c, 0x49, 0xa1, 0xe3,
+ 0xa6, 0xbc, 0x29, 0x02, 0xe4, 0x21, 0xc2, 0xba, 0xed, 0x8f, 0x60, 0x58,
+ 0xbc, 0x77, 0xed, 0x62, 0xf0, 0x1f, 0xeb, 0x17, 0xff, 0xfd, 0xf6, 0x9a,
+ 0x42, 0x34, 0xb3, 0xbf, 0x39, 0xfd, 0xcc, 0x9d, 0x62, 0xff, 0xbc, 0xc7,
+ 0xe7, 0xf0, 0xc7, 0x58, 0xbb, 0x7b, 0x2c, 0x5f, 0x6b, 0x58, 0x1a, 0xc5,
+ 0xff, 0x44, 0x8c, 0x7d, 0x6b, 0x03, 0x58, 0xbf, 0xde, 0xfe, 0x11, 0x3f,
+ 0x96, 0x2f, 0x61, 0x9b, 0x21, 0x44, 0xeb, 0x20, 0x8b, 0x07, 0xba, 0x1d,
+ 0xed, 0xae, 0x63, 0xa7, 0x19, 0x22, 0x40, 0x87, 0x76, 0xe6, 0xca, 0xad,
+ 0x59, 0xe5, 0x1e, 0x5e, 0x3e, 0x1d, 0x62, 0xff, 0xbe, 0xce, 0x0c, 0x16,
+ 0xa7, 0x58, 0xbf, 0xde, 0x6f, 0x73, 0xed, 0xb3, 0x87, 0xaf, 0xe1, 0xda,
+ 0x85, 0xef, 0xa6, 0x9e, 0x21, 0x14, 0x23, 0x6f, 0xd0, 0x0f, 0x88, 0x35,
+ 0x8b, 0x85, 0xda, 0xc5, 0xd3, 0xec, 0xfc, 0xf0, 0xc0, 0x55, 0x7f, 0xff,
+ 0x9b, 0xc2, 0x79, 0xf6, 0x72, 0x5f, 0x8d, 0x66, 0x11, 0xab, 0x15, 0xa4,
+ 0x4b, 0x05, 0xcc, 0xaf, 0xff, 0xfe, 0xe9, 0xf4, 0xff, 0x96, 0x7b, 0x07,
+ 0xc7, 0x3e, 0x6a, 0x78, 0xed, 0x62, 0xfe, 0xc1, 0xb9, 0xf0, 0x96, 0x2f,
+ 0xff, 0xb0, 0x41, 0x7c, 0x27, 0x6f, 0xbf, 0xbf, 0x0b, 0x14, 0xc8, 0xf1,
+ 0xd3, 0xa7, 0xcb, 0x2f, 0xda, 0xe9, 0xdf, 0xa5, 0x45, 0x28, 0x5f, 0xff,
+ 0x3f, 0x8b, 0x27, 0xd4, 0x7d, 0xbf, 0x9a, 0x58, 0xbf, 0xfe, 0x71, 0xe0,
+ 0xff, 0x84, 0x03, 0xe6, 0xb1, 0x62, 0xee, 0x18, 0xb1, 0x7f, 0xef, 0xc0,
+ 0x0e, 0xf2, 0xe7, 0x0c, 0x58, 0xbc, 0xf2, 0xd9, 0x84, 0xd7, 0x70, 0xbc,
+ 0x06, 0xe4, 0x9f, 0xc4, 0xe0, 0xc6, 0x6f, 0xfc, 0xdd, 0x3e, 0x9e, 0x4d,
+ 0xc0, 0x2c, 0x5f, 0xb5, 0xd3, 0xbf, 0x4a, 0x89, 0x38, 0xba, 0x5b, 0x30,
+ 0x7e, 0xd8, 0x7f, 0x47, 0x4c, 0x3d, 0xe1, 0xc1, 0x7f, 0xd9, 0x34, 0x9f,
+ 0x53, 0xfc, 0x4b, 0x17, 0xef, 0xe6, 0x9b, 0x8b, 0x17, 0x6b, 0x64, 0x67,
+ 0xc9, 0xe3, 0xcb, 0xd1, 0x33, 0xac, 0x5f, 0x31, 0x64, 0x96, 0x2b, 0xe6,
+ 0xf8, 0x20, 0xed, 0xf7, 0x44, 0x23, 0x56, 0x2e, 0xd6, 0xce, 0x1e, 0x43,
+ 0x91, 0xd6, 0xca, 0x6e, 0x4d, 0x08, 0xc7, 0x85, 0xbd, 0x44, 0xa3, 0xef,
+ 0x29, 0xeb, 0x9d, 0x09, 0x52, 0x7a, 0x47, 0x9b, 0x97, 0x46, 0x4a, 0x55,
+ 0x36, 0x3a, 0xce, 0xa3, 0xd1, 0x69, 0xc7, 0xed, 0xd8, 0xd3, 0x66, 0x8e,
+ 0x2f, 0x50, 0xe9, 0x3d, 0xe9, 0x0c, 0xfe, 0x94, 0x50, 0xf3, 0xb9, 0x20,
+ 0x94, 0xa6, 0x53, 0x8b, 0x9c, 0xb4, 0x5c, 0xbe, 0xa4, 0x2c, 0x8a, 0x31,
+ 0x7d, 0xf3, 0x9e, 0xd7, 0xed, 0x74, 0xef, 0xd2, 0xa2, 0x1f, 0x2f, 0xfc,
+ 0xf2, 0xd9, 0xcd, 0x74, 0xef, 0xd2, 0xa2, 0x53, 0x2d, 0xb3, 0x88, 0x87,
+ 0x39, 0xbd, 0xfe, 0xd9, 0xcd, 0x74, 0xef, 0xd2, 0xa2, 0x27, 0x2f, 0x6c,
+ 0x1b, 0x08, 0x28, 0xb1, 0x7e, 0x6f, 0x70, 0x47, 0x58, 0xbf, 0x08, 0xe4,
+ 0xe6, 0xac, 0x5e, 0xfc, 0x4c, 0xb1, 0x77, 0x72, 0x58, 0xa9, 0x91, 0x13,
+ 0xa2, 0x9f, 0x94, 0x88, 0x7a, 0xff, 0x0b, 0xb0, 0xc6, 0x2f, 0x71, 0x62,
+ 0xff, 0xf0, 0x58, 0x69, 0x9b, 0xb3, 0x8f, 0x62, 0xdb, 0xb7, 0xfb, 0x8b,
+ 0x17, 0xdd, 0x3b, 0xf4, 0xa8, 0x8c, 0x4b, 0xfe, 0x13, 0x9d, 0xf5, 0xac,
+ 0xed, 0x62, 0xb4, 0x7d, 0x7c, 0x31, 0xbf, 0x71, 0xb7, 0xc1, 0xd6, 0x2f,
+ 0x77, 0x29, 0xd6, 0x2d, 0xf8, 0x3c, 0xac, 0x2a, 0xbf, 0xc1, 0x66, 0xf0,
+ 0xb5, 0xb7, 0x6f, 0xf7, 0x16, 0x2f, 0xdb, 0xdf, 0x91, 0x25, 0x8b, 0xfb,
+ 0x9e, 0xef, 0xa6, 0xfa, 0xc5, 0xef, 0xb1, 0x8b, 0x17, 0x4a, 0x3e, 0x79,
+ 0xe0, 0x31, 0xbf, 0xff, 0x84, 0x4e, 0x6e, 0xdf, 0x1b, 0x05, 0x2c, 0xfb,
+ 0x1d, 0x62, 0xfd, 0x34, 0x77, 0x27, 0x58, 0xbe, 0x83, 0xf4, 0x05, 0x8b,
+ 0xc1, 0xc4, 0xcb, 0x17, 0xff, 0xd2, 0x9c, 0x2c, 0x8d, 0x82, 0x7e, 0xb5,
+ 0xb7, 0x6f, 0xf7, 0x16, 0x2b, 0x11, 0xa9, 0xf2, 0xa7, 0x24, 0x00, 0xfd,
+ 0xfb, 0x4d, 0xd3, 0x6f, 0x58, 0xbf, 0x0b, 0xd1, 0xdc, 0x96, 0x2f, 0x67,
+ 0x7e, 0x58, 0xbf, 0xd8, 0x5f, 0xcf, 0x40, 0xd6, 0x2e, 0xcf, 0x41, 0xe8,
+ 0x30, 0xf5, 0xff, 0xbc, 0x6c, 0x14, 0xb3, 0xec, 0x75, 0x8b, 0xfe, 0x36,
+ 0x0a, 0x59, 0xf6, 0x3a, 0xc5, 0xf0, 0x89, 0xcd, 0xda, 0x7f, 0x1e, 0x3f,
+ 0xbb, 0xae, 0x96, 0x2f, 0xda, 0x03, 0x7e, 0x16, 0x28, 0xe7, 0xfb, 0xc3,
+ 0xb1, 0x0d, 0x5e, 0xee, 0x5b, 0x02, 0xc5, 0xfd, 0xff, 0x73, 0x3b, 0x92,
+ 0xc5, 0x31, 0xea, 0x08, 0x92, 0xf3, 0x6b, 0x71, 0x62, 0xfd, 0xb6, 0x62,
+ 0x81, 0xac, 0x5e, 0x0e, 0x5b, 0xab, 0x16, 0xd9, 0xd8, 0x6b, 0xf8, 0x31,
+ 0x0b, 0x69, 0xcf, 0xa4, 0x71, 0x90, 0xd0, 0xe9, 0xb3, 0xb2, 0x66, 0x4a,
+ 0x99, 0xe4, 0xe5, 0xbf, 0x8c, 0xc9, 0xce, 0xc0, 0x56, 0x4f, 0x5c, 0x8c,
+ 0x83, 0xd0, 0x83, 0x11, 0x0e, 0xe1, 0x00, 0x42, 0xbb, 0xff, 0xdb, 0x27,
+ 0x79, 0x6c, 0xe6, 0xba, 0x77, 0xe9, 0x51, 0x3c, 0x97, 0xb7, 0xc7, 0xd6,
+ 0x2d, 0x0b, 0x15, 0x06, 0xc3, 0x43, 0xf7, 0xd0, 0x52, 0xe2, 0xc5, 0xd9,
+ 0xc5, 0x8b, 0xff, 0x3f, 0xa3, 0x42, 0x96, 0xa2, 0x4b, 0x17, 0x07, 0xc5,
+ 0x8b, 0xde, 0x83, 0xac, 0x5f, 0x31, 0x66, 0xf5, 0x8b, 0xf7, 0xa0, 0x98,
+ 0x0b, 0x17, 0xfd, 0x13, 0xe7, 0xa0, 0x98, 0x0b, 0x17, 0x9c, 0x81, 0x87,
+ 0xbe, 0x19, 0x3d, 0x7d, 0x16, 0x9b, 0x90, 0x82, 0xad, 0x27, 0x5a, 0x02,
+ 0x00, 0xb9, 0x11, 0x0b, 0xf0, 0xff, 0xc3, 0x21, 0xc3, 0x46, 0xff, 0x6c,
+ 0x7f, 0x98, 0x01, 0x4d, 0x71, 0x62, 0xfd, 0xc1, 0x0f, 0x0e, 0xb1, 0x74,
+ 0x83, 0x58, 0xbe, 0x13, 0xea, 0x4b, 0x17, 0xbc, 0x1c, 0xeb, 0x17, 0x8e,
+ 0x2d, 0xd5, 0x8b, 0xf3, 0x8f, 0xf1, 0xc5, 0x8b, 0xfd, 0x9f, 0xfc, 0x76,
+ 0xfb, 0xab, 0x16, 0xd9, 0x0b, 0x49, 0xa2, 0xc2, 0x04, 0x8a, 0x46, 0x33,
+ 0x84, 0x60, 0x20, 0x22, 0x1e, 0x14, 0x56, 0xca, 0xa3, 0x13, 0x23, 0xb3,
+ 0xa8, 0x66, 0xff, 0x4e, 0x57, 0x2a, 0x40, 0x37, 0xe3, 0x31, 0xf4, 0xe3,
+ 0x6d, 0xfb, 0x5d, 0x3b, 0xf4, 0xa8, 0x88, 0x0b, 0xff, 0x3c, 0xb6, 0x73,
+ 0x5d, 0x3b, 0xf4, 0xa8, 0x95, 0x0b, 0xfb, 0x42, 0xfc, 0x17, 0x4b, 0x17,
+ 0xf7, 0x4d, 0x81, 0x3f, 0x0b, 0x15, 0x07, 0xbf, 0x85, 0xf7, 0xf7, 0xb0,
+ 0x8a, 0x27, 0x58, 0xb6, 0xce, 0x26, 0x66, 0x73, 0x72, 0x85, 0x7f, 0x88,
+ 0x2f, 0xb7, 0xc1, 0x4e, 0xb1, 0x7e, 0xd7, 0x4e, 0xfd, 0x2a, 0x22, 0x82,
+ 0xfd, 0xa8, 0x3c, 0x76, 0xb1, 0x78, 0xe2, 0x1a, 0xc5, 0xff, 0x9b, 0xd3,
+ 0x43, 0x66, 0xf6, 0xdd, 0x58, 0xb7, 0xd8, 0xf8, 0x77, 0x8f, 0x5e, 0x38,
+ 0xb7, 0x56, 0x2f, 0xde, 0xe7, 0xc5, 0xc5, 0x8b, 0xfd, 0x2c, 0x19, 0x3b,
+ 0x8d, 0x62, 0xa0, 0xf7, 0x1c, 0xaa, 0xff, 0xc2, 0x7d, 0x3c, 0xbc, 0xdc,
+ 0x12, 0xc5, 0xff, 0x47, 0x65, 0x9e, 0xe4, 0x1d, 0x62, 0x88, 0xfe, 0x04,
+ 0x7f, 0x7a, 0x01, 0x8b, 0x16, 0xd9, 0x85, 0x4c, 0x38, 0x4a, 0xc6, 0xef,
+ 0x08, 0xa0, 0x14, 0x93, 0xef, 0x21, 0x30, 0x19, 0x0d, 0xfe, 0xd9, 0xcd,
+ 0x74, 0xef, 0xd2, 0xa2, 0x32, 0x2f, 0xda, 0xe9, 0xdf, 0xa5, 0x44, 0xca,
+ 0x5f, 0xa5, 0x9e, 0x7e, 0x96, 0x2f, 0xdb, 0x27, 0x79, 0x6c, 0xe1, 0xf0,
+ 0x76, 0x6f, 0x70, 0x54, 0x28, 0xb1, 0x77, 0x62, 0x58, 0xbf, 0x6b, 0xa7,
+ 0x7e, 0x95, 0x15, 0x21, 0x62, 0x58, 0xba, 0x47, 0x58, 0xbe, 0x3e, 0x67,
+ 0x96, 0x2e, 0x0b, 0x85, 0xd6, 0x2f, 0xe9, 0x30, 0xcb, 0x37, 0xac, 0x58,
+ 0x35, 0x8b, 0xc1, 0x04, 0x05, 0x8b, 0x6c, 0xec, 0x09, 0x9e, 0xc8, 0x83,
+ 0x06, 0x77, 0x4d, 0xf4, 0x22, 0xe3, 0x01, 0x72, 0x2f, 0x10, 0x08, 0xbc,
+ 0x20, 0x9d, 0xfb, 0x5d, 0x3b, 0xf4, 0xa8, 0xae, 0x8b, 0xfb, 0xed, 0xad,
+ 0x3c, 0x96, 0x2d, 0xb3, 0x87, 0xcb, 0xc3, 0x7b, 0xc1, 0xc1, 0xd6, 0x2f,
+ 0xda, 0xe9, 0xdf, 0xa5, 0x45, 0x8a, 0x5b, 0x66, 0x0f, 0x57, 0x07, 0xaf,
+ 0xfa, 0x39, 0xc8, 0x3f, 0xb3, 0xa5, 0x8b, 0xee, 0x9d, 0xfa, 0x54, 0x4f,
+ 0x45, 0xf8, 0xef, 0x2d, 0x9c, 0xe8, 0xfa, 0xf4, 0x75, 0x78, 0xc7, 0xe9,
+ 0x62, 0xfe, 0xfc, 0x36, 0x98, 0x2e, 0xb1, 0x7f, 0x34, 0xef, 0x1d, 0xf1,
+ 0x62, 0xfd, 0x0d, 0xb8, 0xc1, 0x16, 0x2f, 0xa3, 0xb7, 0x08, 0xb1, 0x71,
+ 0x9b, 0x38, 0x8d, 0x0e, 0x87, 0xfe, 0x62, 0xe5, 0xe4, 0x59, 0x7f, 0xfa,
+ 0x0b, 0x67, 0x3e, 0xfb, 0x4f, 0x19, 0xe5, 0x8b, 0xff, 0xff, 0xc3, 0xc3,
+ 0x36, 0x4b, 0x0d, 0x35, 0xfd, 0xc6, 0x29, 0xa3, 0xad, 0x67, 0x6b, 0x17,
+ 0xff, 0xff, 0xef, 0x3e, 0xa5, 0xb3, 0x9c, 0x13, 0xf7, 0x85, 0x06, 0x07,
+ 0xe6, 0x96, 0x77, 0xe5, 0x8b, 0xf6, 0x7b, 0xec, 0x62, 0xc5, 0xff, 0xb9,
+ 0x84, 0xe6, 0xfd, 0xa0, 0x96, 0x2f, 0xfb, 0x33, 0xed, 0xd7, 0xf3, 0x64,
+ 0x8f, 0x9b, 0xc5, 0x37, 0xcd, 0xaf, 0xba, 0xc5, 0xfc, 0xc6, 0x0d, 0xdc,
+ 0xd5, 0x8b, 0xfa, 0x62, 0x83, 0xec, 0xe7, 0xcf, 0x47, 0x84, 0x57, 0x73,
+ 0xcb, 0x17, 0x67, 0x16, 0x2f, 0xfd, 0x9a, 0xee, 0x0f, 0xf7, 0xcd, 0x2c,
+ 0x5d, 0xc0, 0x2c, 0x5f, 0x89, 0xce, 0x50, 0xb1, 0x7f, 0x0b, 0x9f, 0x79,
+ 0x6c, 0xec, 0x08, 0xac, 0x71, 0x82, 0x17, 0x30, 0xfc, 0x31, 0x8b, 0xd3,
+ 0xc6, 0xea, 0xc5, 0xda, 0xf2, 0xc5, 0xfb, 0x3d, 0xc6, 0x3a, 0xc5, 0xff,
+ 0xe8, 0xef, 0xd9, 0x33, 0x6b, 0xdc, 0x16, 0xea, 0xc5, 0xe7, 0xef, 0x66,
+ 0x11, 0x62, 0xe4, 0x24, 0x31, 0xe2, 0x8a, 0xc5, 0x4d, 0x1a, 0x87, 0x9f,
+ 0x23, 0x26, 0xa9, 0x2e, 0x80, 0x8d, 0x37, 0xb7, 0xf2, 0x87, 0x7f, 0xa5,
+ 0x85, 0x56, 0xca, 0xf6, 0x24, 0x46, 0x24, 0xd3, 0xab, 0x37, 0xfd, 0xe1,
+ 0x4e, 0x1c, 0xdc, 0x17, 0x6b, 0x17, 0x9f, 0xfc, 0x58, 0xb8, 0x7b, 0x3e,
+ 0x3d, 0xd3, 0x10, 0x2f, 0x40, 0x82, 0xeb, 0x17, 0xed, 0x75, 0xf6, 0xe2,
+ 0xc5, 0x31, 0xe5, 0x88, 0x86, 0xef, 0x42, 0xc5, 0x05, 0x0d, 0xc7, 0x64,
+ 0x37, 0xa7, 0xdc, 0xd8, 0xd6, 0x2f, 0xf6, 0x6f, 0x2c, 0xe0, 0x0e, 0xb1,
+ 0x5b, 0x0c, 0xf7, 0x08, 0x9e, 0xfc, 0xdf, 0x27, 0x99, 0x62, 0xff, 0x67,
+ 0xc4, 0x73, 0xbc, 0xcb, 0x17, 0x6e, 0x6c, 0x6b, 0x17, 0xb6, 0x14, 0x86,
+ 0xb1, 0x7e, 0x96, 0x0f, 0x6e, 0x2c, 0x5f, 0x9d, 0xa7, 0xd4, 0x2c, 0x5f,
+ 0x77, 0xd3, 0x12, 0xc5, 0xfb, 0xc4, 0x27, 0xd8, 0x96, 0x28, 0x28, 0x9b,
+ 0x58, 0x54, 0x9f, 0x62, 0x28, 0xd8, 0x46, 0xbb, 0x0c, 0x82, 0x09, 0x3e,
+ 0x55, 0xe2, 0x80, 0xc9, 0x2e, 0x38, 0x16, 0x2f, 0xf8, 0x2a, 0x61, 0xbd,
+ 0x4d, 0x21, 0x1a, 0xb1, 0x7e, 0xcf, 0x30, 0xb8, 0xb1, 0x70, 0x50, 0x2d,
+ 0x2c, 0x50, 0x51, 0x14, 0xfb, 0x00, 0xc0, 0x5a, 0x45, 0x0b, 0x0a, 0x2f,
+ 0xc1, 0x6e, 0x14, 0xe6, 0xbc, 0xb1, 0x7f, 0x83, 0x2c, 0xd6, 0xa3, 0xa5,
+ 0x8a, 0x0a, 0x1f, 0x56, 0xc4, 0x6b, 0x7d, 0xa3, 0xfb, 0xb5, 0x8b, 0xf6,
+ 0xc6, 0x15, 0x3f, 0x0d, 0x58, 0xb9, 0xb8, 0xb1, 0x63, 0x16, 0x28, 0x28,
+ 0x7b, 0xdd, 0x1a, 0x06, 0x2f, 0x7e, 0xd8, 0xc2, 0xb1, 0x23, 0xac, 0x5e,
+ 0xfc, 0x6e, 0xac, 0x5f, 0xf8, 0x2c, 0xd8, 0x36, 0x20, 0xae, 0xc5, 0xb1,
+ 0x6c, 0x3d, 0x88, 0x28, 0xb1, 0x7f, 0xe0, 0xb7, 0xd8, 0xb6, 0x18, 0x5b,
+ 0x85, 0xb8, 0x54, 0x2b, 0xb1, 0x85, 0x16, 0x2f, 0xfd, 0xb0, 0xc2, 0xc0,
+ 0xb7, 0xd8, 0x61, 0x6e, 0x15, 0x0b, 0x41, 0x6e, 0x14, 0x58, 0xbf, 0xef,
+ 0x8e, 0x5b, 0x32, 0xe1, 0x6c, 0x85, 0x53, 0x57, 0xd8, 0x1b, 0x82, 0xd3,
+ 0x9d, 0x05, 0x15, 0x0f, 0x05, 0x4c, 0x82, 0xd4, 0x6e, 0xf7, 0xe0, 0xa9,
+ 0xdd, 0xc9, 0x62, 0xfe, 0x86, 0xf7, 0xa0, 0xeb, 0x17, 0x0f, 0x75, 0x62,
+ 0xb6, 0x33, 0xf3, 0x0b, 0x72, 0xbe, 0xcb, 0x6f, 0x75, 0x9f, 0x48, 0xbb,
+ 0x9a, 0x58, 0xba, 0x38, 0xb1, 0x6d, 0x2c, 0x58, 0xeb, 0x14, 0x73, 0x77,
+ 0xe1, 0x73, 0x04, 0xaf, 0xff, 0xf7, 0x83, 0xd4, 0x7e, 0x33, 0xa1, 0xb1,
+ 0x4e, 0x78, 0x92, 0xc5, 0xda, 0x85, 0x8a, 0x63, 0xfa, 0x03, 0x1d, 0xf6,
+ 0xb4, 0xf2, 0x58, 0xbf, 0xd9, 0xd4, 0x6d, 0xfb, 0x9d, 0x62, 0xa0, 0xf6,
+ 0x7e, 0x47, 0x7f, 0xf1, 0x0a, 0x36, 0xbb, 0x7a, 0x59, 0xc5, 0x8b, 0xff,
+ 0xbf, 0x1c, 0x70, 0xff, 0xf6, 0xef, 0x8b, 0x17, 0xfc, 0xd0, 0x59, 0xbf,
+ 0x51, 0xc5, 0x8a, 0xe9, 0x10, 0x1f, 0x47, 0xbe, 0x69, 0x98, 0xc5, 0x8b,
+ 0xd3, 0x31, 0x8b, 0x17, 0x64, 0x96, 0x29, 0x8d, 0xb3, 0x8f, 0xd1, 0xcf,
+ 0xe4, 0x0b, 0x57, 0xfe, 0x6d, 0xbf, 0x67, 0x97, 0x9a, 0x75, 0x8a, 0xc3,
+ 0xe3, 0xf9, 0x15, 0xfb, 0xc0, 0x0c, 0xa6, 0x58, 0xbf, 0xf3, 0xf3, 0x6f,
+ 0x39, 0x92, 0x94, 0x2c, 0x5b, 0x8b, 0x17, 0xf4, 0x74, 0xd3, 0xb9, 0x2c,
+ 0x5f, 0xff, 0x89, 0xcd, 0x6d, 0x44, 0xa5, 0x9c, 0x00, 0x21, 0x62, 0xff,
+ 0x3f, 0x85, 0x98, 0x46, 0xac, 0x50, 0xd3, 0x55, 0xc2, 0x13, 0x4a, 0xe6,
+ 0x41, 0xd0, 0x97, 0xcb, 0x80, 0xab, 0x7e, 0xf4, 0x14, 0x4c, 0xb1, 0x74,
+ 0x69, 0x62, 0xc1, 0x75, 0x8b, 0xd1, 0xf8, 0x58, 0xac, 0x3f, 0x13, 0x4a,
+ 0x26, 0x17, 0x21, 0x6b, 0xff, 0x16, 0x0b, 0xa2, 0xc9, 0xc3, 0x92, 0xc5,
+ 0xff, 0xe7, 0x3e, 0xcc, 0x6b, 0x4c, 0x13, 0xa1, 0x4e, 0xb1, 0x76, 0x98,
+ 0x91, 0x26, 0x11, 0x06, 0xf9, 0xbe, 0x19, 0xd6, 0x2f, 0xff, 0x31, 0xbb,
+ 0x70, 0x9f, 0xbe, 0x1a, 0x6b, 0xac, 0x57, 0x47, 0xe6, 0x44, 0x97, 0xdd,
+ 0xbf, 0xe1, 0x62, 0xff, 0xd2, 0x16, 0x68, 0xb3, 0xdf, 0x65, 0x8b, 0xff,
+ 0xb8, 0x58, 0x0d, 0x9f, 0xb7, 0x4f, 0xa5, 0x8b, 0xb3, 0x16, 0x2a, 0x11,
+ 0x7e, 0xc4, 0x6e, 0x7c, 0x62, 0x45, 0xc4, 0x62, 0xc5, 0xfb, 0x84, 0x27,
+ 0x92, 0xc5, 0xff, 0xee, 0x31, 0xfb, 0xe3, 0xf8, 0x5d, 0xf2, 0x16, 0x2f,
+ 0xef, 0x4d, 0x27, 0xd1, 0xab, 0x17, 0x67, 0x4b, 0x17, 0x87, 0x86, 0xb9,
+ 0xe4, 0xf8, 0xc6, 0xfb, 0xf0, 0x7e, 0x96, 0x2a, 0x13, 0x2d, 0xc1, 0x8e,
+ 0xca, 0x1e, 0x12, 0xde, 0x33, 0xb8, 0x40, 0x58, 0xbf, 0x7b, 0xec, 0x20,
+ 0xba, 0xc5, 0x48, 0xf1, 0x70, 0x62, 0xfb, 0x30, 0x8d, 0x58, 0xbf, 0xfd,
+ 0xc2, 0x8f, 0x73, 0x08, 0x5e, 0x11, 0xab, 0x15, 0xc4, 0x47, 0x78, 0x84,
+ 0x44, 0x57, 0x87, 0x9f, 0x58, 0xbd, 0x33, 0x18, 0xb1, 0x61, 0xc8, 0xde,
+ 0x30, 0xed, 0xff, 0xec, 0xe8, 0x6c, 0x41, 0xe6, 0xb5, 0x1b, 0xd6, 0x2f,
+ 0xfe, 0xdb, 0x10, 0x50, 0x7d, 0xbb, 0x7f, 0xb8, 0xb1, 0x50, 0x8c, 0x00,
+ 0x13, 0x12, 0x6d, 0xff, 0x05, 0xe5, 0x18, 0x43, 0x83, 0xac, 0x5f, 0xfb,
+ 0xf9, 0x37, 0xdb, 0xf1, 0xa8, 0x58, 0xb9, 0xfb, 0x58, 0xbc, 0x51, 0xba,
+ 0xb1, 0x7f, 0x9f, 0x8f, 0xf1, 0x14, 0xeb, 0x14, 0x47, 0xd7, 0xe1, 0x81,
+ 0x0f, 0xd6, 0xd6, 0x66, 0x8c, 0xea, 0x72, 0x85, 0x48, 0xde, 0xb0, 0x87,
+ 0xb8, 0x62, 0xb4, 0xa5, 0x59, 0xa1, 0xaf, 0xa8, 0x67, 0x9e, 0x14, 0x5f,
+ 0x87, 0x09, 0x46, 0xd1, 0xc8, 0xc8, 0x7d, 0x19, 0x60, 0x8b, 0x83, 0x3c,
+ 0x09, 0x0a, 0xab, 0xb8, 0x25, 0x8b, 0x69, 0x62, 0xe8, 0xd2, 0xc5, 0xe2,
+ 0xc0, 0x8b, 0x17, 0x67, 0xd6, 0x2f, 0xda, 0xee, 0x5e, 0x85, 0x8b, 0xd9,
+ 0xbf, 0x16, 0x2b, 0x0f, 0x20, 0x8a, 0xab, 0x6a, 0x31, 0xba, 0x12, 0x71,
+ 0x7d, 0xc1, 0xe0, 0xd7, 0xef, 0xb0, 0xed, 0xe5, 0x8a, 0x84, 0xd4, 0x35,
+ 0x0d, 0xef, 0x28, 0x5e, 0xe8, 0x5a, 0x58, 0xbb, 0x40, 0x58, 0xb9, 0xf1,
+ 0x62, 0xbb, 0x35, 0xda, 0x18, 0xbc, 0x4f, 0xe5, 0x8b, 0xc4, 0xdc, 0x58,
+ 0xb1, 0x81, 0x53, 0x71, 0x03, 0x97, 0x47, 0xd6, 0x2f, 0xb5, 0xbd, 0xce,
+ 0xb1, 0x7f, 0x74, 0x72, 0x8e, 0xc0, 0xb1, 0x7b, 0x92, 0x85, 0x8b, 0xf7,
+ 0x33, 0x31, 0x96, 0x2b, 0x0f, 0x0c, 0x03, 0xb7, 0xff, 0x9b, 0x6c, 0x4c,
+ 0xde, 0xd4, 0x74, 0x2e, 0x96, 0x2f, 0x01, 0xfb, 0x58, 0xbe, 0xcf, 0x41,
+ 0x8b, 0x15, 0x87, 0x82, 0x43, 0xd7, 0xff, 0x9b, 0x6f, 0xf2, 0x66, 0xef,
+ 0x9f, 0xce, 0x96, 0x2e, 0x2e, 0x2c, 0x5f, 0x13, 0xfb, 0x8b, 0x15, 0x23,
+ 0x72, 0x71, 0x7b, 0xd1, 0x9a, 0x58, 0xbf, 0xfd, 0xd3, 0xe9, 0xfc, 0xdc,
+ 0x82, 0x80, 0x2c, 0x5a, 0x5f, 0x3e, 0x50, 0xc7, 0x2f, 0xd8, 0x15, 0x26,
+ 0x1a, 0xc5, 0x76, 0x8d, 0xad, 0x42, 0x18, 0x05, 0x35, 0x0b, 0x83, 0xf3,
+ 0x9a, 0x8d, 0x37, 0x16, 0xba, 0x2b, 0x61, 0x79, 0x89, 0x4e, 0xe6, 0x02,
+ 0x1e, 0x42, 0x43, 0xc4, 0x02, 0x8d, 0x8a, 0xf8, 0x67, 0x33, 0x8b, 0x17,
+ 0xfb, 0xaf, 0xb6, 0x9b, 0x24, 0xb1, 0x71, 0xac, 0xb1, 0x40, 0x3c, 0xce,
+ 0x1a, 0x5e, 0x60, 0xce, 0xb1, 0x73, 0x0d, 0x62, 0x9c, 0xda, 0x86, 0x3d,
+ 0x7b, 0xf0, 0x4b, 0x17, 0xb8, 0x10, 0x22, 0xc5, 0xf6, 0xd9, 0x00, 0xeb,
+ 0x17, 0xb5, 0x83, 0x58, 0xbf, 0xe9, 0xc4, 0x0c, 0xde, 0x59, 0xc5, 0x8b,
+ 0xfc, 0xfe, 0x89, 0xb8, 0xc7, 0x58, 0xa3, 0x51, 0x1b, 0xa1, 0xdf, 0x9e,
+ 0x5f, 0xe8, 0x91, 0x67, 0x7e, 0xc5, 0x8b, 0xf7, 0x4d, 0xdc, 0xe4, 0xb1,
+ 0x7f, 0xf3, 0xf5, 0x04, 0x39, 0xa5, 0x1a, 0x9d, 0x62, 0xbb, 0x3f, 0x2f,
+ 0x95, 0xdb, 0x8b, 0x14, 0xc6, 0xd7, 0x84, 0x77, 0xf1, 0x69, 0xdd, 0xfc,
+ 0xb1, 0x7f, 0xfd, 0xee, 0x0f, 0x58, 0xc6, 0xfc, 0xc7, 0x29, 0xd6, 0x2f,
+ 0x88, 0x78, 0x6a, 0xc5, 0xef, 0x88, 0xeb, 0x17, 0x6f, 0x1a, 0xc5, 0x6c,
+ 0x25, 0x7b, 0xf0, 0xe3, 0x25, 0x71, 0x90, 0xe0, 0xe7, 0x64, 0x4d, 0x0b,
+ 0x3d, 0x18, 0xfe, 0x1b, 0x4e, 0x41, 0xc2, 0xcf, 0x29, 0x88, 0x8c, 0xc1,
+ 0xeb, 0xf6, 0x11, 0x44, 0xeb, 0x16, 0xed, 0x63, 0x46, 0x9e, 0x96, 0x2e,
+ 0x29, 0x2c, 0x53, 0x1a, 0x31, 0x06, 0x5f, 0xb9, 0x34, 0x14, 0xeb, 0x15,
+ 0x88, 0x90, 0x35, 0x1b, 0xc4, 0x17, 0xb6, 0xca, 0x75, 0x8b, 0xc7, 0x6e,
+ 0x2c, 0x5f, 0x88, 0xd6, 0xce, 0x2c, 0x5f, 0xfa, 0x4f, 0xa9, 0xfe, 0x29,
+ 0xc1, 0xe5, 0x8b, 0xf7, 0xdb, 0x8c, 0x35, 0x8b, 0xcd, 0x07, 0x58, 0xb6,
+ 0xa4, 0x78, 0x9f, 0x28, 0xbe, 0x7f, 0x3f, 0x4b, 0x14, 0xc7, 0x96, 0x61,
+ 0x45, 0xf0, 0x82, 0xfc, 0x9d, 0x62, 0xff, 0xc6, 0x38, 0x33, 0xaf, 0xb8,
+ 0x38, 0xb1, 0x50, 0x7d, 0x58, 0x53, 0x7e, 0xe4, 0x00, 0x39, 0xd6, 0x2f,
+ 0xfd, 0xc7, 0xee, 0x09, 0xc7, 0x86, 0xac, 0x51, 0xaa, 0x8b, 0x58, 0x76,
+ 0x62, 0x8f, 0xc3, 0x48, 0xa1, 0x19, 0xc2, 0x0f, 0x15, 0xdf, 0xff, 0xdb,
+ 0xf6, 0xff, 0x06, 0xc5, 0x87, 0xef, 0xc2, 0x7e, 0x2c, 0x5c, 0x60, 0xd6,
+ 0x2f, 0xff, 0x7b, 0xf8, 0x70, 0x3e, 0xb3, 0x7e, 0x0d, 0x62, 0xe8, 0xfa,
+ 0xc5, 0x86, 0xb1, 0x47, 0x35, 0x24, 0x2f, 0x63, 0x56, 0x2f, 0x10, 0x21,
+ 0x62, 0xe2, 0x1e, 0xd3, 0x5f, 0xc1, 0x3b, 0xb3, 0xcb, 0x17, 0xf6, 0x70,
+ 0xc7, 0x29, 0xd6, 0x2a, 0x13, 0x38, 0xc7, 0x57, 0x4f, 0x01, 0x71, 0x0b,
+ 0xdf, 0xe2, 0x73, 0x36, 0xbf, 0x58, 0xb1, 0x7c, 0x2e, 0x3f, 0x4b, 0x17,
+ 0xfe, 0x10, 0xfe, 0xd1, 0xbf, 0x41, 0xf1, 0x62, 0xb4, 0x7c, 0xe4, 0x49,
+ 0x7d, 0xed, 0xcc, 0xfa, 0xc5, 0xee, 0x0e, 0x16, 0x2f, 0xf6, 0x75, 0x04,
+ 0x27, 0x92, 0xc5, 0xff, 0xfd, 0xd6, 0x77, 0xef, 0xb6, 0xa1, 0xe4, 0x0c,
+ 0xc9, 0x96, 0x2f, 0xf7, 0xb3, 0xa1, 0x01, 0xf1, 0x62, 0x8d, 0x46, 0x21,
+ 0x19, 0xf1, 0x76, 0x8d, 0x4c, 0x45, 0xe1, 0xc3, 0x50, 0x9c, 0x0e, 0x10,
+ 0x8a, 0x33, 0x7b, 0x71, 0x62, 0xd8, 0xb1, 0x4c, 0x68, 0xc2, 0x09, 0x5f,
+ 0x76, 0x50, 0x6a, 0xc5, 0xfe, 0x60, 0xcf, 0x98, 0x46, 0xac, 0x51, 0xcf,
+ 0xe9, 0xc8, 0x80, 0x49, 0x7f, 0xd8, 0x4f, 0x2e, 0x48, 0xc9, 0xd6, 0x2f,
+ 0xa5, 0xc6, 0x25, 0x8b, 0xef, 0xf5, 0x1d, 0x2c, 0x5f, 0xfb, 0xa2, 0x7f,
+ 0xbf, 0x79, 0xdf, 0x96, 0x2f, 0xf1, 0x39, 0xba, 0x68, 0x35, 0x62, 0xa4,
+ 0x8f, 0x7e, 0xce, 0xd8, 0x88, 0x44, 0xa6, 0x20, 0xdf, 0xfd, 0x1a, 0x11,
+ 0xc9, 0xcd, 0x1e, 0x82, 0xeb, 0x17, 0xb1, 0xce, 0xb1, 0x46, 0x9f, 0x36,
+ 0x92, 0xaa, 0x11, 0xa8, 0xf0, 0xb1, 0xbe, 0x2f, 0x31, 0xd6, 0x2f, 0x44,
+ 0x49, 0x63, 0x0d, 0x15, 0xfd, 0x1c, 0x8f, 0xc7, 0x16, 0x2f, 0x74, 0xdd,
+ 0x2c, 0x5e, 0xdc, 0xcf, 0xac, 0x5d, 0xa9, 0x41, 0xbf, 0xf0, 0xfd, 0x69,
+ 0x13, 0x0e, 0xd9, 0x77, 0xb1, 0x62, 0xa1, 0x96, 0x27, 0x39, 0x86, 0x4a,
+ 0x4e, 0x35, 0xc3, 0xb6, 0x06, 0x8d, 0x47, 0x48, 0xff, 0x94, 0x3c, 0xf0,
+ 0xd2, 0x28, 0xfe, 0x78, 0x90, 0x28, 0x61, 0x86, 0x45, 0x7f, 0xf8, 0xd7,
+ 0xce, 0xfd, 0xe8, 0xcd, 0xed, 0xd2, 0xc5, 0xe6, 0x20, 0x2c, 0x5f, 0xfd,
+ 0xdc, 0xb9, 0x05, 0x1d, 0x43, 0x7d, 0x62, 0xff, 0x16, 0x73, 0xce, 0xe4,
+ 0xb1, 0x46, 0xa3, 0x83, 0xe9, 0xce, 0x39, 0xbd, 0x16, 0xf8, 0x20, 0x48,
+ 0xdd, 0x58, 0xbf, 0xfe, 0xf3, 0x10, 0xa5, 0x9c, 0x18, 0x9f, 0x52, 0x58,
+ 0xb4, 0x6d, 0x3f, 0xa0, 0xca, 0xaf, 0xfc, 0x77, 0x96, 0x7d, 0xb5, 0xf7,
+ 0x58, 0xb9, 0xb5, 0xa3, 0xe8, 0x01, 0x55, 0xff, 0xfc, 0x58, 0x6e, 0x16,
+ 0xde, 0x7b, 0xf8, 0x70, 0xe0, 0x0b, 0x15, 0x08, 0x8b, 0xc2, 0xdb, 0xfc,
+ 0x27, 0xe3, 0x4c, 0xc6, 0x2c, 0x53, 0x2a, 0x02, 0xfc, 0x75, 0x84, 0x43,
+ 0x7f, 0xc6, 0x13, 0x9b, 0x83, 0x62, 0x58, 0xbd, 0xf8, 0x25, 0x8b, 0xef,
+ 0x79, 0xfa, 0x58, 0xbb, 0xc7, 0x58, 0xb6, 0xe2, 0xc5, 0x48, 0xf4, 0x7b,
+ 0x24, 0xf8, 0xc5, 0x42, 0x35, 0xba, 0x39, 0x76, 0xdb, 0xe1, 0xe9, 0x8c,
+ 0x58, 0xbf, 0xb3, 0x27, 0xcc, 0xf2, 0xc5, 0xc6, 0xef, 0x58, 0xbd, 0x82,
+ 0x1a, 0xc5, 0x4e, 0x88, 0x91, 0x92, 0x11, 0x6f, 0x06, 0xef, 0xff, 0xfa,
+ 0x3d, 0xf8, 0xe6, 0x4b, 0xf0, 0x72, 0x73, 0x4b, 0x00, 0xb1, 0x79, 0x8b,
+ 0xcb, 0x17, 0xd1, 0xd6, 0x69, 0x62, 0xfb, 0xf1, 0xbf, 0x16, 0x2f, 0xe7,
+ 0xde, 0xd3, 0x31, 0x8b, 0x14, 0x74, 0x4a, 0x10, 0xe7, 0x88, 0xc3, 0x24,
+ 0xbf, 0xc2, 0xd4, 0xe7, 0x8c, 0xf2, 0xc5, 0xff, 0x72, 0x0e, 0x3f, 0xc1,
+ 0x74, 0xb1, 0x73, 0x16, 0x1f, 0x79, 0xa6, 0xb5, 0x08, 0xd8, 0x1c, 0x2b,
+ 0x2f, 0x48, 0x5c, 0x58, 0xbf, 0x3e, 0x81, 0xb9, 0x8b, 0x17, 0x82, 0xbb,
+ 0xfc, 0xb1, 0x43, 0x3c, 0xfd, 0xe5, 0x77, 0xbe, 0x1e, 0xf5, 0x8b, 0xfe,
+ 0x83, 0x96, 0x75, 0xa6, 0x02, 0xc5, 0x86, 0xb1, 0x7b, 0x9c, 0xc5, 0x8b,
+ 0x0e, 0x0d, 0x7b, 0x89, 0x54, 0x91, 0x5d, 0xc2, 0x11, 0x34, 0x5f, 0x9d,
+ 0xba, 0xc2, 0x58, 0xbf, 0xfb, 0x30, 0x8d, 0xd3, 0x73, 0x8e, 0x6a, 0xc5,
+ 0x7c, 0xfb, 0x03, 0x27, 0xbf, 0xd2, 0xc6, 0xe7, 0x05, 0x0b, 0x17, 0xf0,
+ 0xf0, 0xa5, 0xfc, 0x58, 0xbf, 0xff, 0xfd, 0x9c, 0xfe, 0x6a, 0x09, 0xfb,
+ 0x97, 0xe3, 0xde, 0x8e, 0xff, 0x07, 0x58, 0xa8, 0x46, 0xc3, 0x19, 0x9c,
+ 0xb6, 0xff, 0xde, 0x83, 0xf7, 0xd3, 0x77, 0x9a, 0x58, 0xbf, 0x7f, 0x34,
+ 0xdc, 0x58, 0xbc, 0x4d, 0x2e, 0xcf, 0xab, 0xc8, 0x57, 0x77, 0xe5, 0x8b,
+ 0xf1, 0x38, 0xf0, 0xd5, 0x8b, 0xe9, 0x46, 0x79, 0x62, 0xec, 0x04, 0x1e,
+ 0x57, 0x65, 0x17, 0xf4, 0x7b, 0x18, 0x41, 0x75, 0x8a, 0x73, 0xde, 0x01,
+ 0x6d, 0xff, 0x64, 0xf8, 0x3c, 0x28, 0xdd, 0x58, 0xbf, 0xff, 0xf7, 0x22,
+ 0x46, 0x67, 0xc3, 0xf1, 0x40, 0x1f, 0xc0, 0x0c, 0xa4, 0xb1, 0x50, 0xad,
+ 0x4a, 0x78, 0x7d, 0xca, 0x13, 0x0e, 0x66, 0x08, 0x60, 0x91, 0x0f, 0x8e,
+ 0xef, 0xff, 0x17, 0xb7, 0x32, 0x69, 0x3e, 0xa7, 0x1c, 0x2c, 0x5f, 0xff,
+ 0xc5, 0x28, 0xf3, 0xff, 0x8c, 0xfe, 0x00, 0x65, 0x25, 0x8b, 0xef, 0x7b,
+ 0x37, 0x56, 0x2f, 0xfa, 0x32, 0x5f, 0xc6, 0x97, 0x16, 0x2b, 0x87, 0xbd,
+ 0xe2, 0x6b, 0xf0, 0xe6, 0xf8, 0xb7, 0x56, 0x2b, 0xb3, 0xd0, 0x22, 0x2a,
+ 0xc4, 0xde, 0x99, 0x3d, 0xe3, 0x09, 0xbf, 0x68, 0x9b, 0x0d, 0x58, 0xbf,
+ 0x47, 0xdb, 0xb9, 0x2c, 0x5c, 0x79, 0x2c, 0x5f, 0xf3, 0xe7, 0x43, 0xcd,
+ 0x01, 0x96, 0x2b, 0x69, 0xfd, 0x0c, 0xa7, 0xe3, 0x17, 0xfb, 0xbe, 0x06,
+ 0x4d, 0x03, 0x58, 0xbf, 0xfa, 0x3a, 0x83, 0xc1, 0x38, 0xf0, 0xd5, 0x8a,
+ 0xd2, 0x2a, 0x88, 0xc4, 0x21, 0xad, 0x42, 0x6f, 0xad, 0x1a, 0x65, 0xfe,
+ 0x97, 0x0a, 0x00, 0xe7, 0x58, 0xbf, 0x3f, 0x7e, 0x9e, 0x16, 0x2a, 0x0f,
+ 0x74, 0x8c, 0xef, 0xc6, 0xe0, 0xb5, 0x3a, 0xc5, 0xf4, 0x74, 0x28, 0x58,
+ 0xad, 0x1e, 0x71, 0x85, 0x77, 0xf3, 0x6a, 0x71, 0x03, 0x16, 0x2f, 0xde,
+ 0x8c, 0x2e, 0x96, 0x2f, 0xbb, 0xf4, 0x1d, 0x62, 0x8d, 0x3c, 0xce, 0xca,
+ 0x2c, 0x4b, 0x17, 0xf3, 0x3c, 0xbc, 0xd3, 0xac, 0x5f, 0xde, 0x6f, 0xb1,
+ 0x79, 0x62, 0xb6, 0x9f, 0x67, 0xc4, 0x43, 0x2e, 0xbf, 0xb8, 0xd9, 0xbd,
+ 0xf4, 0xb1, 0x52, 0x3e, 0x13, 0x99, 0x5f, 0xfb, 0x37, 0x47, 0xf8, 0xfc,
+ 0x7b, 0x8b, 0x17, 0xff, 0xa3, 0x3b, 0xf7, 0xe3, 0xc5, 0x00, 0xe2, 0xc5,
+ 0xd0, 0x05, 0x8b, 0xbe, 0x75, 0x8b, 0xff, 0xfd, 0xa1, 0x49, 0x8b, 0x04,
+ 0x0d, 0xb9, 0xc2, 0x13, 0xce, 0xb1, 0x5d, 0x22, 0x4b, 0x82, 0xfe, 0x18,
+ 0xa8, 0x56, 0x01, 0x39, 0x1b, 0x3d, 0xbc, 0x3c, 0x48, 0x8b, 0xc8, 0x42,
+ 0x86, 0xe5, 0xf8, 0x6e, 0x42, 0x3a, 0xc5, 0xff, 0x84, 0x0c, 0xeb, 0x35,
+ 0xa7, 0x92, 0xc5, 0xff, 0xc2, 0x79, 0x1c, 0x5e, 0xfc, 0x08, 0x2e, 0xb1,
+ 0x74, 0x1d, 0x62, 0xb1, 0x19, 0x3a, 0x28, 0x24, 0x0e, 0x25, 0x5f, 0xfe,
+ 0x79, 0xa3, 0xb2, 0x73, 0x70, 0x6f, 0x25, 0x8b, 0xd3, 0xe1, 0x8b, 0x17,
+ 0xcc, 0x09, 0x84, 0xb1, 0x43, 0x44, 0x76, 0x92, 0xc8, 0x7e, 0xf4, 0xed,
+ 0xa5, 0x8b, 0xfe, 0x33, 0x59, 0x1d, 0xc9, 0x8e, 0xb1, 0x7f, 0xdc, 0x6e,
+ 0xfd, 0x34, 0xa3, 0xb5, 0x8b, 0xf7, 0x3d, 0xcc, 0xf2, 0xc5, 0x42, 0x28,
+ 0x78, 0x76, 0x23, 0xdb, 0xf0, 0x5d, 0xa6, 0x63, 0x16, 0x2f, 0xe2, 0x89,
+ 0x84, 0xe1, 0xac, 0x50, 0x8f, 0x74, 0x32, 0xeb, 0xb3, 0xeb, 0x17, 0x8c,
+ 0x30, 0xc4, 0x8b, 0xff, 0xde, 0x6f, 0x73, 0xed, 0xb8, 0x1e, 0xa2, 0x49,
+ 0x1b, 0x26, 0x86, 0xa1, 0x51, 0xb9, 0xa5, 0xed, 0x0b, 0xf7, 0x84, 0x67,
+ 0x88, 0xc4, 0x71, 0x77, 0xbb, 0x58, 0xbf, 0xcd, 0xa9, 0xc4, 0x0c, 0x25,
+ 0x8a, 0x39, 0xe6, 0x85, 0xc6, 0x6e, 0x99, 0x96, 0x2f, 0xff, 0xe9, 0x41,
+ 0x67, 0xbe, 0xd9, 0xe8, 0x3b, 0x6a, 0x4b, 0x15, 0xa3, 0xf1, 0xf0, 0xc5,
+ 0xfc, 0x70, 0xcb, 0x37, 0xe2, 0xc5, 0xfb, 0x38, 0x22, 0xf2, 0xc5, 0x31,
+ 0xfd, 0x39, 0x11, 0x18, 0x5f, 0xff, 0xa3, 0x53, 0xc7, 0xdd, 0xb5, 0xa6,
+ 0x3e, 0xc7, 0xb0, 0x96, 0x2a, 0x4d, 0xb9, 0xc8, 0xe3, 0x0c, 0xc8, 0x5c,
+ 0x1a, 0x7b, 0xd4, 0x7a, 0x3d, 0x93, 0xb3, 0x6c, 0xd0, 0xd2, 0xd4, 0xbe,
+ 0xe3, 0xc7, 0xdb, 0xf8, 0xec, 0x41, 0x08, 0x52, 0x96, 0xdd, 0xc8, 0xcd,
+ 0xbd, 0x2c, 0x00, 0x50, 0xae, 0xdf, 0x18, 0x88, 0x42, 0xcb, 0xfe, 0xee,
+ 0x5c, 0xe6, 0x0d, 0xfc, 0xb1, 0x7f, 0x6b, 0xd0, 0x20, 0xbf, 0x16, 0x2e,
+ 0x6d, 0xc5, 0x8b, 0xa6, 0x3a, 0xc5, 0xfb, 0x35, 0xe1, 0x7d, 0x62, 0xb4,
+ 0x7b, 0x80, 0x1a, 0x0c, 0x66, 0xd8, 0xb1, 0x6c, 0x58, 0xdd, 0x2c, 0x6f,
+ 0xb4, 0x4f, 0xbd, 0x62, 0xf6, 0x39, 0x2c, 0x58, 0xc5, 0x8b, 0xb6, 0xe2,
+ 0xc5, 0x39, 0xac, 0xf0, 0x9d, 0x42, 0x77, 0x23, 0x3b, 0xc8, 0x47, 0x9a,
+ 0x82, 0xc4, 0x7a, 0x24, 0x3a, 0x3d, 0xff, 0xfc, 0x59, 0xef, 0xe4, 0xb5,
+ 0x1f, 0x76, 0xf4, 0x7d, 0x62, 0xf0, 0x39, 0x8b, 0x17, 0xc1, 0x1e, 0x3b,
+ 0x58, 0xbf, 0xda, 0x60, 0xbf, 0x5f, 0x83, 0x16, 0x2b, 0xb3, 0xdf, 0x62,
+ 0x5b, 0xef, 0xe0, 0x1d, 0x62, 0xfb, 0xed, 0xdf, 0x96, 0x2e, 0x79, 0x6d,
+ 0x3c, 0x69, 0x88, 0xac, 0x62, 0xc5, 0xf4, 0xa0, 0xa4, 0xb1, 0x67, 0x58,
+ 0xbd, 0x1f, 0xe2, 0xc5, 0x76, 0x6b, 0x98, 0x46, 0xff, 0xd1, 0xd6, 0xdc,
+ 0x28, 0x10, 0x5f, 0x8b, 0x17, 0xf7, 0x23, 0x35, 0x84, 0xb1, 0x7c, 0xf2,
+ 0x89, 0xd6, 0x2f, 0xf3, 0xf9, 0xbe, 0xe7, 0xdb, 0x87, 0x9f, 0xf2, 0xcb,
+ 0xff, 0x73, 0x08, 0x7b, 0x70, 0x6d, 0xbd, 0x62, 0xff, 0xee, 0x3f, 0x7c,
+ 0xe6, 0x10, 0x37, 0x31, 0x62, 0xff, 0xf3, 0x75, 0xc8, 0xdc, 0xcf, 0x4a,
+ 0x59, 0xc5, 0x8a, 0x1a, 0xa6, 0xae, 0xcc, 0x26, 0x13, 0xd2, 0x81, 0xc8,
+ 0x4a, 0x12, 0x9c, 0x4a, 0xf2, 0x16, 0xf4, 0x8b, 0xed, 0x7f, 0x09, 0x62,
+ 0xff, 0xfc, 0x58, 0xdc, 0x6d, 0x40, 0xbd, 0x34, 0x60, 0xd6, 0x2a, 0x15,
+ 0xe8, 0x34, 0xad, 0x27, 0x84, 0x40, 0x88, 0xaf, 0xc1, 0xc9, 0x81, 0xc5,
+ 0x8b, 0xd9, 0x10, 0xb1, 0x7e, 0x0f, 0x86, 0x67, 0xd6, 0x2a, 0x73, 0xc6,
+ 0xe0, 0xdd, 0x0d, 0x12, 0x7a, 0x70, 0xbf, 0x8b, 0x68, 0x7c, 0x8c, 0x58,
+ 0xbe, 0xd3, 0x9d, 0x96, 0x2f, 0xbd, 0x1d, 0x98, 0xb1, 0x58, 0xbc, 0x35,
+ 0xd2, 0xcf, 0xe7, 0x13, 0x1e, 0x1b, 0x60, 0x23, 0x11, 0x81, 0x84, 0x57,
+ 0xfe, 0x1c, 0x41, 0xf3, 0x82, 0x7e, 0xd6, 0x2f, 0xff, 0x84, 0x1f, 0x8a,
+ 0x00, 0xfe, 0x00, 0x65, 0x25, 0x8a, 0x64, 0x48, 0xf8, 0xfe, 0xfd, 0x3e,
+ 0xd0, 0x76, 0x05, 0x8b, 0xf7, 0xbd, 0x84, 0x75, 0x8b, 0xff, 0x9c, 0x11,
+ 0xfc, 0x1c, 0x72, 0x00, 0xb1, 0x7f, 0xff, 0xa3, 0x39, 0x85, 0xa8, 0x93,
+ 0x1f, 0x3b, 0x94, 0xc2, 0x58, 0xa8, 0x47, 0xd3, 0x17, 0x39, 0x41, 0x21,
+ 0xdc, 0x67, 0xd6, 0x2f, 0xff, 0x41, 0x74, 0x1e, 0x9c, 0x0d, 0xef, 0xc2,
+ 0xc5, 0xf3, 0xce, 0xe4, 0xb1, 0x7e, 0xf7, 0xf0, 0x0e, 0xb1, 0x5d, 0x9e,
+ 0x51, 0x11, 0x5f, 0xc7, 0xdb, 0xfc, 0x03, 0xac, 0x5f, 0xc6, 0x73, 0x30,
+ 0xa7, 0x58, 0xa8, 0x44, 0x0e, 0x11, 0x31, 0x85, 0xfd, 0xac, 0x21, 0x46,
+ 0x96, 0x2f, 0xff, 0xa3, 0x3b, 0x35, 0xf9, 0x8c, 0x4f, 0xee, 0x2c, 0x5f,
+ 0x47, 0x23, 0x7a, 0xc5, 0xff, 0xd0, 0x4f, 0xe9, 0x41, 0xae, 0x67, 0x96,
+ 0x2b, 0x62, 0x47, 0x2e, 0x8b, 0x7e, 0x9e, 0x22, 0x4b, 0xdb, 0x5f, 0xa5,
+ 0x8a, 0x85, 0x7f, 0x12, 0x8c, 0x73, 0xa3, 0x90, 0x0c, 0xf2, 0x31, 0x6f,
+ 0x46, 0x24, 0x11, 0x0a, 0xfc, 0x19, 0xce, 0xdb, 0xab, 0x17, 0xec, 0x2f,
+ 0x31, 0xd6, 0x2a, 0x47, 0xa8, 0x72, 0xdb, 0xec, 0xe4, 0x49, 0x62, 0xfb,
+ 0x5f, 0x60, 0xd6, 0x2f, 0xe9, 0x73, 0xcd, 0x1d, 0xac, 0x5f, 0x1c, 0x38,
+ 0x25, 0x8b, 0xe6, 0x1e, 0x1d, 0x62, 0xf9, 0xdc, 0x80, 0xb1, 0x63, 0x20,
+ 0xf0, 0xcd, 0x22, 0xb8, 0x47, 0x58, 0xbf, 0xc6, 0x3c, 0xd9, 0x28, 0xdd,
+ 0x58, 0xbf, 0x04, 0x14, 0xcd, 0x32, 0xc5, 0x32, 0x29, 0xbe, 0x53, 0xc1,
+ 0x81, 0x1c, 0x5f, 0xf3, 0x1f, 0xfd, 0xbe, 0xef, 0xb8, 0xb1, 0x7f, 0x74,
+ 0xff, 0xfe, 0x0d, 0x62, 0xa0, 0xfb, 0x44, 0x7d, 0x78, 0x46, 0x79, 0x62,
+ 0xf1, 0x8e, 0x62, 0xc5, 0x80, 0xb1, 0x50, 0x6c, 0x43, 0x1f, 0xbe, 0xf7,
+ 0x04, 0x35, 0x8b, 0xf3, 0x77, 0x2f, 0x74, 0xb1, 0x7f, 0xa1, 0xf5, 0xf3,
+ 0x1c, 0x69, 0x17, 0x18, 0x62, 0x45, 0x0c, 0xf3, 0x8c, 0x34, 0xb9, 0xb7,
+ 0x52, 0x36, 0x4d, 0x1d, 0x01, 0x19, 0x3e, 0x84, 0xe5, 0xfb, 0xa6, 0xe7,
+ 0xd9, 0x62, 0xff, 0xa0, 0x1f, 0x8e, 0x13, 0xcc, 0xb1, 0x5d, 0x9f, 0x11,
+ 0x14, 0xde, 0x3c, 0x1d, 0x62, 0xf4, 0x85, 0xe5, 0x8a, 0x83, 0x76, 0x21,
+ 0xda, 0x85, 0xcd, 0x21, 0x91, 0x61, 0x17, 0x64, 0x8c, 0x5f, 0x34, 0x61,
+ 0x87, 0x85, 0x4f, 0xc8, 0x40, 0xa0, 0x44, 0x3c, 0x87, 0x6f, 0xa1, 0x15,
+ 0xb8, 0xbb, 0x7c, 0x43, 0xfb, 0xac, 0x5d, 0x26, 0x58, 0xbd, 0x8f, 0xba,
+ 0xb1, 0x7b, 0x58, 0x35, 0x8a, 0xc3, 0xf5, 0x62, 0x2d, 0x0b, 0xef, 0x1f,
+ 0xbd, 0xf8, 0xd2, 0xc5, 0xde, 0xe2, 0xc5, 0xf8, 0xfa, 0xd4, 0x4e, 0xb1,
+ 0x70, 0x0a, 0x0f, 0x0b, 0x06, 0x2f, 0xf1, 0x67, 0x8a, 0x3b, 0x92, 0xc5,
+ 0x61, 0xef, 0x39, 0x5d, 0xfb, 0xbe, 0x46, 0x8d, 0x58, 0xb8, 0xce, 0x2f,
+ 0x31, 0x02, 0xd8, 0xb1, 0x58, 0x6d, 0xfc, 0x4d, 0x53, 0xa2, 0x0b, 0xb6,
+ 0x2b, 0xee, 0xe4, 0x15, 0xed, 0x62, 0xfb, 0xbe, 0x6d, 0x92, 0xc5, 0xbe,
+ 0xb1, 0x7f, 0xee, 0x0c, 0xa0, 0x7f, 0x8f, 0x71, 0x62, 0xa0, 0xf4, 0x78,
+ 0x25, 0x50, 0x8e, 0x8c, 0x25, 0x72, 0xa1, 0x3c, 0x5f, 0xff, 0xf6, 0x19,
+ 0x92, 0xfe, 0x34, 0xb9, 0xdf, 0x1b, 0xcc, 0x53, 0xac, 0x5d, 0xf9, 0x96,
+ 0x2f, 0xf7, 0xd9, 0xe5, 0xe6, 0x9d, 0x62, 0xf9, 0x8b, 0xd0, 0xb1, 0x7f,
+ 0xcd, 0xa7, 0x00, 0x4f, 0x67, 0xd6, 0x2b, 0xe7, 0xb9, 0xe2, 0x1b, 0xfe,
+ 0x63, 0x0b, 0x3c, 0xc2, 0x02, 0xc5, 0xfd, 0xe8, 0x62, 0x0f, 0x8b, 0x17,
+ 0xe3, 0xb4, 0xcc, 0x62, 0xc5, 0x41, 0xec, 0x31, 0x75, 0xf9, 0xb4, 0x38,
+ 0x9d, 0x62, 0xff, 0x3e, 0xbd, 0xc2, 0x63, 0x56, 0x2e, 0x63, 0x16, 0x2e,
+ 0x0e, 0x75, 0x8b, 0xdd, 0xf3, 0x08, 0xd9, 0x78, 0x62, 0xe8, 0x3a, 0xc5,
+ 0xff, 0xff, 0xf3, 0x70, 0x3d, 0x47, 0xe3, 0x0e, 0xc5, 0x28, 0x6f, 0xb7,
+ 0x44, 0xdb, 0xd6, 0x2f, 0x8c, 0xf6, 0x7c, 0x68, 0x94, 0xe0, 0xbd, 0x42,
+ 0x60, 0x2f, 0x0c, 0x6b, 0xf1, 0xb9, 0xac, 0xf2, 0xc5, 0xff, 0xd8, 0x6e,
+ 0x0b, 0x4e, 0x38, 0xfc, 0x2c, 0x53, 0x1f, 0x6f, 0x0a, 0x6e, 0x07, 0x16,
+ 0x2f, 0xfc, 0x4e, 0x67, 0x5f, 0x6d, 0xed, 0xa5, 0x8b, 0xc3, 0xfc, 0x2c,
+ 0x50, 0xcf, 0x7c, 0x34, 0x2a, 0x0a, 0xaf, 0xa2, 0x44, 0x2f, 0x65, 0x1c,
+ 0x56, 0x1d, 0x74, 0xd1, 0xd8, 0xcb, 0x42, 0x43, 0x74, 0x8b, 0x50, 0x91,
+ 0xf9, 0x03, 0x94, 0x94, 0x6c, 0xfc, 0x84, 0xa7, 0x88, 0x44, 0xef, 0x7a,
+ 0x67, 0xd2, 0xc5, 0xff, 0x7b, 0xf8, 0x01, 0x47, 0x61, 0xac, 0x5f, 0xff,
+ 0xf9, 0xdb, 0xd1, 0xf2, 0xcf, 0x7d, 0x83, 0x94, 0x6f, 0x62, 0x02, 0xc5,
+ 0xfb, 0xac, 0x3c, 0x71, 0x62, 0xf0, 0x88, 0x6b, 0x17, 0xff, 0x63, 0x4e,
+ 0x78, 0x76, 0x93, 0xf1, 0x62, 0xff, 0x38, 0x03, 0xdc, 0x72, 0x02, 0xc5,
+ 0x7c, 0xfe, 0x89, 0x0e, 0xff, 0xfc, 0xde, 0xe6, 0x1b, 0x34, 0x9b, 0xdc,
+ 0x1e, 0x12, 0xc5, 0xff, 0xec, 0xfe, 0x17, 0xb9, 0x9b, 0xca, 0x3b, 0x58,
+ 0xa8, 0x54, 0x93, 0xd8, 0xf7, 0xcf, 0x1d, 0xb0, 0x05, 0x3e, 0x84, 0xbe,
+ 0xf2, 0x13, 0x15, 0xee, 0x6e, 0xd6, 0x2f, 0x41, 0x79, 0x62, 0xe6, 0xd2,
+ 0xc5, 0x4e, 0x6c, 0xf0, 0x72, 0xff, 0x49, 0x8f, 0xfe, 0xdf, 0x75, 0x62,
+ 0xf9, 0xf5, 0x12, 0x58, 0xbe, 0xef, 0x05, 0x32, 0xc5, 0xff, 0x85, 0x1a,
+ 0x35, 0xc3, 0xf3, 0x49, 0x62, 0xff, 0x9f, 0xbd, 0xbd, 0xf3, 0x08, 0xd5,
+ 0x8a, 0x9d, 0x31, 0xfe, 0xc8, 0x4e, 0x71, 0xf2, 0x22, 0x25, 0xf2, 0x0d,
+ 0xf7, 0xf7, 0x58, 0xeb, 0x17, 0x8a, 0x00, 0xb1, 0x5b, 0x4f, 0x0b, 0x84,
+ 0xd7, 0xf7, 0x9c, 0xe7, 0x83, 0xac, 0x58, 0xf8, 0x7a, 0x5d, 0x92, 0x5f,
+ 0xee, 0xff, 0x93, 0x7d, 0xb4, 0xb1, 0x50, 0x7b, 0xd8, 0x51, 0x7e, 0x72,
+ 0xce, 0xe1, 0x62, 0xff, 0x7e, 0x0f, 0xd7, 0xda, 0x65, 0x8b, 0x46, 0xc4,
+ 0x7b, 0xbd, 0x93, 0xdf, 0x3f, 0x3b, 0x75, 0x8b, 0xfe, 0x97, 0x3e, 0xfd,
+ 0x41, 0x0d, 0x62, 0xf0, 0x3d, 0xf5, 0x8a, 0x91, 0xfd, 0xf6, 0x46, 0x03,
+ 0xab, 0xff, 0xff, 0x6b, 0x07, 0xc7, 0xdd, 0x6e, 0xfe, 0xed, 0x28, 0x1f,
+ 0xc4, 0x6a, 0xc5, 0x80, 0xb1, 0x4e, 0x8b, 0x3e, 0x18, 0x06, 0xe3, 0x70,
+ 0x1d, 0x62, 0xfb, 0xac, 0x73, 0xac, 0x54, 0x1b, 0xa6, 0x17, 0xbf, 0x73,
+ 0xf8, 0x07, 0x58, 0xa8, 0x5d, 0xb8, 0x93, 0xd6, 0x46, 0xd4, 0xd1, 0xa5,
+ 0xe9, 0xf5, 0xe3, 0x5b, 0x26, 0xae, 0x0f, 0xde, 0xe3, 0x74, 0xb1, 0x7f,
+ 0x10, 0xf9, 0xc6, 0x3a, 0xc5, 0xfb, 0xa7, 0x9f, 0x0c, 0x58, 0xbf, 0x46,
+ 0x87, 0x84, 0xb1, 0x58, 0x88, 0x02, 0x2e, 0xf1, 0x5d, 0xfa, 0x37, 0x1b,
+ 0xe2, 0x58, 0xbb, 0x3a, 0x58, 0xb8, 0x7d, 0x2c, 0x5f, 0x11, 0x61, 0xab,
+ 0x15, 0x86, 0xec, 0x43, 0x37, 0xb4, 0xdf, 0x58, 0xa9, 0x22, 0x43, 0xa5,
+ 0x32, 0x20, 0xbe, 0x09, 0xe6, 0x35, 0x62, 0xe8, 0x0d, 0x62, 0xb8, 0x6f,
+ 0xb7, 0x09, 0xaf, 0xfe, 0x80, 0x47, 0xce, 0x4e, 0x6f, 0xd9, 0x62, 0xdb,
+ 0x12, 0xc5, 0xff, 0xf6, 0x11, 0xb9, 0xa9, 0xe0, 0xcc, 0xfe, 0x12, 0xc5,
+ 0xfa, 0x08, 0xc7, 0xed, 0x62, 0xb0, 0xfe, 0x7e, 0xa1, 0x7f, 0xe2, 0x9a,
+ 0x30, 0xa7, 0xce, 0xfc, 0xb1, 0x7e, 0xf7, 0x0f, 0xa8, 0x58, 0xa1, 0xa2,
+ 0x29, 0xc8, 0x49, 0x02, 0xff, 0xbf, 0x1d, 0x40, 0x1c, 0x80, 0xb1, 0x7f,
+ 0x03, 0x6e, 0x71, 0xc9, 0x62, 0xff, 0xe1, 0x41, 0x39, 0xb3, 0x14, 0x03,
+ 0x8b, 0x14, 0x34, 0x56, 0x91, 0xcf, 0x8b, 0xef, 0xc1, 0x51, 0xb1, 0x74,
+ 0xb1, 0x4c, 0x7b, 0x8e, 0x5f, 0x7c, 0x63, 0xc1, 0xd6, 0x2f, 0xcf, 0xc9,
+ 0xdb, 0x4b, 0x17, 0xda, 0x61, 0x4e, 0xb8, 0xbd, 0x4b, 0xdd, 0x0a, 0x75,
+ 0xc5, 0xea, 0x5f, 0xfb, 0x1b, 0x7e, 0x16, 0x0d, 0xe4, 0xb8, 0xbd, 0x4b,
+ 0xf3, 0x97, 0x72, 0xd9, 0x1a, 0x2a, 0x78, 0x62, 0x61, 0x6d, 0xce, 0x11,
+ 0x62, 0x86, 0x99, 0xe1, 0xe1, 0xa4, 0x4a, 0x37, 0x98, 0xf0, 0xb1, 0x7e,
+ 0x37, 0xce, 0xe4, 0xb1, 0x78, 0x85, 0x3a, 0xc5, 0x39, 0xe3, 0x78, 0xa2,
+ 0x99, 0x17, 0x1a, 0x35, 0x26, 0x2a, 0xd8, 0x17, 0xc4, 0xe2, 0x13, 0xc3,
+ 0x2e, 0xc8, 0x5d, 0xb3, 0x76, 0x89, 0x0e, 0x88, 0xf1, 0x8d, 0x72, 0x33,
+ 0x7f, 0x10, 0x0a, 0x50, 0xbd, 0xff, 0xc5, 0xf7, 0xe1, 0x61, 0xa6, 0xe6,
+ 0xea, 0xc5, 0xfc, 0xe7, 0xfc, 0x60, 0xd6, 0x2b, 0x0f, 0xd4, 0x92, 0x2e,
+ 0x0a, 0x6c, 0x0b, 0x17, 0x9a, 0x34, 0xb1, 0x5b, 0x11, 0xbd, 0xf9, 0x0d,
+ 0xff, 0xda, 0x63, 0xc6, 0xe9, 0x61, 0xfb, 0x85, 0x8a, 0x91, 0xf6, 0xcc,
+ 0x4d, 0x7c, 0xf2, 0x8d, 0xd5, 0x8b, 0xc4, 0xe3, 0x58, 0xbd, 0xc9, 0xdd,
+ 0x62, 0x98, 0xdd, 0x06, 0x39, 0x7f, 0xbc, 0xda, 0x8e, 0xb3, 0x7a, 0xc5,
+ 0xc7, 0x65, 0x8b, 0xfa, 0x06, 0xdb, 0xe0, 0x6b, 0x17, 0xef, 0x41, 0x44,
+ 0xcb, 0x15, 0x08, 0xa4, 0x9c, 0xd8, 0x62, 0xee, 0x5f, 0x7e, 0xc3, 0xe9,
+ 0xfb, 0x58, 0xa9, 0xd3, 0x89, 0x1a, 0xf9, 0x43, 0x17, 0x87, 0x97, 0xe9,
+ 0x66, 0xf8, 0x92, 0xc5, 0xec, 0xd4, 0x2c, 0x5f, 0xda, 0x1e, 0x1a, 0x19,
+ 0xd6, 0x2e, 0x7d, 0xd5, 0x8b, 0xdb, 0xf0, 0x6b, 0x15, 0xd2, 0xb6, 0x9e,
+ 0xe1, 0x94, 0xd1, 0xd6, 0x69, 0x0f, 0xe5, 0x4e, 0x38, 0x46, 0x22, 0x1a,
+ 0xb1, 0x8b, 0x17, 0xf9, 0x8c, 0x86, 0x1e, 0x1d, 0x62, 0xcd, 0x87, 0x8d,
+ 0x30, 0x9d, 0xe7, 0xd4, 0xeb, 0x14, 0xb1, 0x62, 0xe8, 0xd5, 0x4c, 0x3d,
+ 0x7d, 0x36, 0xa2, 0x75, 0x8b, 0x7d, 0x61, 0xcd, 0x2d, 0xfc, 0xdd, 0xf3,
+ 0xf9, 0xd2, 0xc5, 0xf7, 0xf1, 0xa6, 0x58, 0xbd, 0x90, 0x35, 0x8b, 0xfa,
+ 0x37, 0xe7, 0xff, 0x0b, 0x17, 0xec, 0xf7, 0x32, 0x65, 0x8f, 0x9a, 0xfb,
+ 0xff, 0xff, 0xec, 0xef, 0x8d, 0x86, 0x6d, 0xce, 0xe5, 0xc6, 0xf7, 0x1b,
+ 0xb1, 0x8c, 0x53, 0xac, 0x5f, 0xfa, 0x3a, 0x2c, 0x9b, 0xe2, 0xd4, 0xcb,
+ 0x14, 0xc8, 0xc7, 0x28, 0x42, 0xdf, 0xe8, 0x23, 0x42, 0x7b, 0x3e, 0xb1,
+ 0x7f, 0xfe, 0x62, 0x1e, 0xd0, 0xfc, 0xdc, 0x76, 0x21, 0x49, 0x62, 0xf9,
+ 0xe7, 0xfb, 0x2c, 0x56, 0x2a, 0xe2, 0x64, 0xd9, 0x88, 0x74, 0x60, 0x72,
+ 0x32, 0x4b, 0xf4, 0x60, 0x02, 0x26, 0xde, 0x6d, 0xb8, 0xaf, 0x78, 0x5a,
+ 0x92, 0xc5, 0xff, 0x8e, 0xe3, 0xd4, 0x7b, 0xf8, 0x35, 0x8b, 0xf9, 0xfc,
+ 0x00, 0xca, 0x4b, 0x17, 0xe9, 0xfa, 0xfc, 0x69, 0x62, 0xff, 0x3b, 0x98,
+ 0x07, 0xf7, 0x16, 0x2e, 0x0f, 0x8b, 0x14, 0x33, 0xcd, 0xf9, 0xa5, 0xf0,
+ 0xa6, 0x8e, 0xd6, 0x2f, 0x63, 0x4c, 0xb1, 0x7f, 0xe1, 0xc7, 0x9e, 0x59,
+ 0xbd, 0xc6, 0xb1, 0x7e, 0x69, 0xe7, 0x6d, 0x2c, 0x5f, 0xa0, 0x88, 0x47,
+ 0x58, 0xb4, 0xbc, 0x7a, 0x21, 0x95, 0x56, 0xd5, 0x44, 0x50, 0x3d, 0x39,
+ 0xfe, 0x17, 0x9a, 0xf1, 0xd1, 0x14, 0xc4, 0xa7, 0x1d, 0x78, 0x48, 0xdf,
+ 0xf6, 0x6a, 0x76, 0xe7, 0xf3, 0x8b, 0x17, 0xe6, 0xd9, 0x30, 0xc3, 0x12,
+ 0x2f, 0xfc, 0x6b, 0xf7, 0xb7, 0xee, 0x76, 0xe2, 0xc5, 0xa2, 0x47, 0xe4,
+ 0x72, 0xfb, 0xb3, 0xeb, 0x17, 0x60, 0x5d, 0x62, 0xec, 0x1a, 0xc5, 0xfb,
+ 0xc0, 0x0c, 0xa4, 0xb1, 0x43, 0x3d, 0xc3, 0x46, 0xdc, 0x5e, 0xfc, 0xfa,
+ 0xea, 0x3c, 0xb1, 0x73, 0x69, 0x62, 0xbe, 0x78, 0x02, 0x29, 0xb7, 0x4b,
+ 0x17, 0x38, 0xd6, 0x2f, 0xed, 0x3f, 0x3e, 0xf2, 0x58, 0xb7, 0x6b, 0x17,
+ 0x31, 0x8b, 0x17, 0x06, 0x05, 0x8a, 0x98, 0xd8, 0x80, 0x62, 0xf4, 0x9c,
+ 0x6b, 0x17, 0x18, 0x62, 0xc5, 0x49, 0x1c, 0x58, 0x2f, 0xd1, 0x73, 0x22,
+ 0x70, 0x88, 0xc1, 0xdb, 0x83, 0x02, 0x46, 0xc9, 0xeb, 0xd3, 0xa6, 0xf3,
+ 0xe8, 0xd3, 0x2f, 0xf6, 0x1d, 0x87, 0x38, 0xb8, 0xb1, 0x7f, 0xff, 0x03,
+ 0x73, 0x35, 0x1e, 0x6e, 0x98, 0x73, 0xc1, 0x42, 0xc5, 0xec, 0xef, 0xcb,
+ 0x16, 0xc2, 0x3f, 0xce, 0x2f, 0x57, 0xd1, 0xaf, 0xc8, 0x58, 0xdf, 0xf3,
+ 0x0f, 0x0e, 0xd3, 0x31, 0x8b, 0x17, 0xff, 0xfd, 0x2f, 0xc0, 0xe1, 0xbb,
+ 0x06, 0xb0, 0x71, 0xa6, 0xec, 0x0b, 0x17, 0xff, 0xfd, 0x1f, 0x76, 0xf4,
+ 0x48, 0x43, 0xc0, 0xf3, 0x5e, 0x17, 0xd6, 0x2f, 0xff, 0x38, 0xf3, 0x08,
+ 0xde, 0x73, 0x08, 0x0b, 0x17, 0xdf, 0x13, 0x9b, 0x09, 0xa9, 0x61, 0xd6,
+ 0x9a, 0x0e, 0xcf, 0x78, 0xa3, 0xeb, 0x17, 0xff, 0xf4, 0x9f, 0x9c, 0x8c,
+ 0x9c, 0x52, 0x1e, 0x89, 0xcc, 0x58, 0xbf, 0xef, 0x68, 0x52, 0xee, 0x59,
+ 0xe5, 0x8b, 0xfe, 0xce, 0x7d, 0xe4, 0x3d, 0x05, 0xd6, 0x29, 0x8f, 0xe8,
+ 0x8f, 0x28, 0x69, 0xb3, 0x9a, 0xa8, 0xc3, 0x9b, 0xe1, 0xaf, 0x7f, 0x69,
+ 0xe5, 0x1a, 0x02, 0xc5, 0xff, 0xfe, 0xfb, 0xcb, 0xf0, 0xfa, 0xe7, 0x33,
+ 0xed, 0xc1, 0x4e, 0xb1, 0x6c, 0xd2, 0x24, 0x3e, 0x5d, 0x7f, 0xfd, 0xa8,
+ 0x79, 0x6a, 0x3e, 0xed, 0xd6, 0x12, 0xc5, 0x42, 0x69, 0x72, 0x86, 0xab,
+ 0x14, 0x57, 0x17, 0x18, 0x3d, 0x38, 0x59, 0x7c, 0x7e, 0xa5, 0x0b, 0x17,
+ 0xa5, 0xbb, 0x25, 0x8b, 0xdf, 0x6e, 0x2c, 0x54, 0x1b, 0xe9, 0x10, 0xdf,
+ 0xec, 0xe4, 0xdf, 0x63, 0x3c, 0xb1, 0x7e, 0x9f, 0x30, 0x8d, 0x58, 0xa8,
+ 0x3d, 0xf7, 0x36, 0xbf, 0x98, 0xfd, 0x61, 0x74, 0xb1, 0x7c, 0xf3, 0xf3,
+ 0xeb, 0x15, 0xa3, 0xd3, 0xe1, 0x7d, 0x6d, 0x64, 0xc0, 0xc9, 0xcc, 0x6d,
+ 0xfd, 0xc7, 0x36, 0xd3, 0xac, 0x0e, 0x5c, 0x4c, 0x5c, 0x7f, 0xf3, 0x9d,
+ 0x82, 0x8b, 0x17, 0x9d, 0xce, 0xb1, 0x7b, 0xed, 0xe5, 0x8b, 0x6f, 0x0a,
+ 0x9e, 0x7f, 0xc5, 0x83, 0x1c, 0xbf, 0xce, 0x76, 0x83, 0xe1, 0x2c, 0x5f,
+ 0xdf, 0x8d, 0x7b, 0x3a, 0x58, 0xb6, 0x0c, 0xf8, 0x3c, 0x63, 0x71, 0xae,
+ 0xb1, 0x7d, 0x84, 0x29, 0x96, 0x2f, 0x9b, 0x7c, 0x0d, 0x62, 0xff, 0xfd,
+ 0xc7, 0xf7, 0x0b, 0x39, 0x1d, 0x83, 0xd9, 0xc5, 0x8a, 0xed, 0x13, 0xa7,
+ 0x23, 0xf1, 0x25, 0xda, 0x99, 0x62, 0xed, 0x42, 0xc5, 0x41, 0xb0, 0xc1,
+ 0x9a, 0x86, 0xd1, 0x86, 0x50, 0xc3, 0xc9, 0x66, 0x6d, 0x2a, 0xe0, 0xf0,
+ 0x88, 0xfc, 0x2b, 0x1e, 0x93, 0x50, 0x08, 0x6f, 0x94, 0x27, 0x3c, 0x4e,
+ 0x28, 0x5a, 0xee, 0x30, 0xdf, 0x36, 0xeb, 0xc2, 0xc5, 0xff, 0xff, 0xff,
+ 0xfe, 0xdc, 0xc3, 0xbc, 0x9b, 0x80, 0xc0, 0x7d, 0xda, 0x50, 0x3f, 0x88,
+ 0xd8, 0x62, 0x7f, 0x44, 0x9f, 0x7f, 0xde, 0x4b, 0x17, 0xef, 0xb6, 0xfc,
+ 0x9d, 0x62, 0x99, 0x1d, 0x3c, 0x85, 0xf5, 0xff, 0x7c, 0x5e, 0xfe, 0x69,
+ 0xb8, 0xb1, 0x7b, 0x8f, 0x32, 0xc5, 0xff, 0x87, 0x05, 0x30, 0xbe, 0xff,
+ 0x85, 0x8b, 0xe3, 0xc7, 0x72, 0x58, 0xbf, 0xf6, 0x6f, 0x81, 0x96, 0x7b,
+ 0x00, 0xb1, 0x76, 0x12, 0xc5, 0xb3, 0xb3, 0xd5, 0xde, 0x7f, 0x7e, 0xff,
+ 0xa2, 0x47, 0x58, 0xb8, 0x30, 0x2c, 0x53, 0x23, 0x97, 0x4f, 0x3f, 0x2a,
+ 0x01, 0x4d, 0xe6, 0x21, 0xac, 0x5e, 0x2c, 0x1a, 0xc5, 0xff, 0x1f, 0x3d,
+ 0x00, 0x13, 0x81, 0x62, 0xff, 0xe6, 0x1b, 0xf9, 0xb9, 0x92, 0xcf, 0xac,
+ 0x5c, 0xe1, 0x16, 0x2f, 0x67, 0x7e, 0x58, 0xaf, 0x9f, 0xd7, 0x90, 0xc2,
+ 0x0c, 0xdf, 0xd9, 0xa8, 0xf7, 0x31, 0x62, 0xff, 0xf9, 0xfb, 0x94, 0x4b,
+ 0x07, 0xc8, 0x94, 0x12, 0xc5, 0x62, 0x2b, 0x58, 0xc4, 0x8b, 0x6f, 0xee,
+ 0x3f, 0xda, 0x00, 0xb1, 0x7e, 0x2f, 0x73, 0x09, 0x62, 0xff, 0xee, 0xc1,
+ 0xa7, 0x7e, 0xe5, 0xc0, 0xce, 0xb1, 0x7f, 0xe0, 0xca, 0x45, 0x9e, 0xf6,
+ 0x4e, 0xb1, 0x4c, 0x8b, 0x07, 0x27, 0x02, 0x4d, 0xfb, 0x4f, 0xbc, 0x23,
+ 0xac, 0x54, 0x2e, 0xf4, 0x4a, 0x30, 0xd1, 0x93, 0xf6, 0x74, 0xc3, 0xda,
+ 0x8c, 0x93, 0xe7, 0x8e, 0x38, 0x01, 0xc2, 0x8d, 0x83, 0x85, 0xbe, 0x86,
+ 0xee, 0xf2, 0xeb, 0xf0, 0x53, 0x62, 0xd8, 0xf7, 0x3c, 0xb1, 0x7f, 0xa7,
+ 0xf1, 0xff, 0x80, 0x75, 0x8b, 0xec, 0x26, 0x35, 0x62, 0xa4, 0x89, 0x23,
+ 0x9d, 0xef, 0x35, 0xbb, 0xa0, 0x8b, 0x17, 0xb9, 0x2f, 0xac, 0x51, 0x1b,
+ 0x9f, 0x0d, 0xdf, 0xff, 0xb8, 0x4f, 0xcf, 0xe4, 0xb3, 0xed, 0xaf, 0xba,
+ 0xc5, 0xff, 0x31, 0xa5, 0x9f, 0xfc, 0x79, 0x62, 0xbb, 0x44, 0x6e, 0x95,
+ 0x2f, 0xb3, 0xb9, 0xf7, 0xac, 0x5f, 0xc6, 0x72, 0x3d, 0x03, 0x58, 0xbd,
+ 0xe9, 0x8e, 0xb1, 0x50, 0x79, 0xd8, 0x5f, 0x7f, 0xb8, 0x37, 0x3c, 0x7b,
+ 0xa5, 0x8b, 0xfc, 0x3c, 0x21, 0x4b, 0x38, 0xb1, 0x5d, 0x9f, 0x41, 0x1a,
+ 0xdf, 0x77, 0xc1, 0x01, 0x62, 0xe2, 0xe9, 0x62, 0xa0, 0xde, 0xb9, 0x2d,
+ 0xfe, 0x0f, 0xc5, 0x93, 0xb6, 0x96, 0x2f, 0x43, 0x0d, 0x62, 0xfc, 0x5d,
+ 0x1a, 0x3e, 0xd6, 0x2f, 0x9c, 0x26, 0x12, 0xc5, 0xe6, 0xe3, 0x2c, 0x53,
+ 0x9f, 0x5f, 0x0b, 0x3c, 0x47, 0x7f, 0x67, 0x51, 0xf8, 0x3a, 0xc5, 0x42,
+ 0xbc, 0xfc, 0x6b, 0x68, 0x56, 0xe8, 0x90, 0xee, 0xaf, 0x08, 0x80, 0x2f,
+ 0x90, 0xff, 0x0d, 0x45, 0x08, 0x73, 0x0b, 0xaf, 0xfd, 0x01, 0x80, 0x52,
+ 0x93, 0xfc, 0x4b, 0x17, 0xb3, 0x0d, 0x58, 0xbe, 0x94, 0x03, 0x8b, 0x14,
+ 0x33, 0xc0, 0xc1, 0xda, 0x9d, 0x14, 0x5d, 0xc2, 0x06, 0xfb, 0xc2, 0x72,
+ 0x58, 0xbf, 0xff, 0x1e, 0x6d, 0x47, 0xf3, 0xd1, 0x27, 0xde, 0x38, 0x58,
+ 0xbe, 0xd6, 0xa2, 0x4b, 0x17, 0xff, 0xe7, 0xe7, 0x31, 0xfa, 0xf7, 0xdc,
+ 0xfa, 0xc9, 0xd6, 0x2f, 0xf3, 0x0d, 0x82, 0xf0, 0x4c, 0xb1, 0x50, 0x98,
+ 0x3e, 0x2c, 0x68, 0x8f, 0xea, 0xf7, 0xff, 0xcc, 0x6e, 0x31, 0xf5, 0x02,
+ 0x0b, 0xbf, 0xf8, 0xb1, 0x7f, 0x9e, 0x58, 0x3d, 0x73, 0x8b, 0x17, 0xb0,
+ 0x31, 0xac, 0x5f, 0xd9, 0xd8, 0x33, 0xdc, 0x58, 0xbf, 0x41, 0x77, 0x2e,
+ 0x2c, 0x7c, 0xd7, 0xd4, 0x22, 0x18, 0x49, 0xb7, 0xff, 0xe2, 0x8c, 0xe6,
+ 0x17, 0xbf, 0x83, 0x17, 0xb8, 0xb1, 0x7f, 0xfe, 0xce, 0x9f, 0xdb, 0x73,
+ 0x53, 0x9f, 0x39, 0xc8, 0x58, 0xa9, 0x22, 0xb7, 0xca, 0x97, 0x8f, 0x12,
+ 0x58, 0xbf, 0x73, 0xff, 0x82, 0x58, 0xbf, 0x9b, 0xcf, 0xf3, 0x37, 0x56,
+ 0x2a, 0x73, 0xf7, 0xc1, 0xd3, 0x4a, 0x2f, 0xe8, 0x9f, 0x73, 0x35, 0x0b,
+ 0x17, 0xf4, 0xdf, 0xce, 0x39, 0x2c, 0x5f, 0xdd, 0xc8, 0x3e, 0x46, 0x2c,
+ 0x56, 0x1e, 0xf3, 0x17, 0x5e, 0x03, 0x7d, 0x62, 0xff, 0xc3, 0xce, 0xe5,
+ 0xcf, 0x71, 0xc0, 0xb1, 0x5a, 0x3f, 0xe0, 0x10, 0x08, 0x76, 0xff, 0x0b,
+ 0x9f, 0x79, 0x4b, 0xeb, 0x17, 0xdc, 0xe6, 0x18, 0xb1, 0x7f, 0x8c, 0x1f,
+ 0xf3, 0x7e, 0x69, 0x62, 0xff, 0xe6, 0x3e, 0xde, 0xbe, 0xdf, 0xe9, 0xb8,
+ 0xb1, 0x7f, 0xb2, 0x58, 0x20, 0xbb, 0x92, 0xc5, 0xff, 0xd1, 0x2f, 0xc7,
+ 0x7e, 0x8f, 0xbe, 0xea, 0xc5, 0xfe, 0x70, 0x73, 0xc5, 0x92, 0x58, 0xa8,
+ 0x4c, 0xc7, 0x46, 0xff, 0x49, 0x23, 0x6f, 0x24, 0x5f, 0xff, 0xe6, 0x2c,
+ 0xef, 0xc6, 0xbf, 0xbf, 0x1f, 0xcd, 0xef, 0x25, 0x8b, 0xe7, 0x07, 0x82,
+ 0xeb, 0x17, 0xfb, 0x0f, 0x34, 0x9c, 0xa7, 0x58, 0xbd, 0x98, 0x4b, 0x15,
+ 0x3a, 0xf4, 0x80, 0xd5, 0x3a, 0x85, 0xd7, 0x70, 0xcf, 0x68, 0x4d, 0x4c,
+ 0x61, 0xa8, 0xc3, 0x4e, 0x5f, 0xf3, 0x5f, 0x46, 0xab, 0xbd, 0x24, 0xc6,
+ 0x30, 0xc9, 0xc2, 0x1a, 0xdf, 0x8f, 0xe2, 0xc9, 0x2c, 0x5f, 0xf4, 0x6b,
+ 0x85, 0x87, 0x8e, 0x96, 0x2e, 0xeb, 0xeb, 0x17, 0x14, 0x2c, 0x5f, 0xb9,
+ 0xf8, 0x33, 0x8b, 0x17, 0xf1, 0xbd, 0xfb, 0xed, 0xf5, 0x8a, 0x19, 0xed,
+ 0xe8, 0xaa, 0xff, 0x86, 0xda, 0x8d, 0xe0, 0xe4, 0x96, 0x2e, 0x83, 0xac,
+ 0x54, 0x1e, 0x9f, 0xcf, 0x2b, 0xe9, 0x83, 0xbb, 0x8f, 0x9d, 0x6f, 0xfb,
+ 0x8f, 0xf6, 0x1f, 0x4d, 0x3a, 0xc5, 0xfe, 0x79, 0x60, 0xf9, 0xc8, 0x58,
+ 0xbf, 0xbd, 0xf8, 0x3c, 0xc4, 0xb1, 0x50, 0x89, 0xdc, 0x3b, 0x01, 0x9d,
+ 0x6c, 0x6c, 0xb5, 0x78, 0x8c, 0xa7, 0x27, 0xb3, 0x3a, 0x87, 0x33, 0x14,
+ 0x68, 0xe5, 0xe3, 0x20, 0x14, 0x33, 0x6e, 0x2f, 0x2c, 0x5e, 0x16, 0xa7,
+ 0x58, 0xbd, 0xd0, 0xa1, 0x62, 0xf1, 0x8f, 0xf5, 0x8a, 0x83, 0xf2, 0x90,
+ 0xbb, 0x0f, 0xe8, 0x7a, 0xfb, 0x05, 0xa9, 0xd6, 0x2f, 0xfd, 0xbd, 0xbc,
+ 0x01, 0x17, 0x18, 0x6b, 0x17, 0xec, 0xe7, 0xc5, 0x3a, 0xc5, 0xb5, 0xb5,
+ 0x11, 0xf8, 0x49, 0xf4, 0x1b, 0xff, 0xfc, 0xf2, 0x0e, 0x5f, 0xc1, 0x05,
+ 0xf0, 0x8d, 0x22, 0xc9, 0x96, 0x2a, 0x11, 0x3a, 0x73, 0x7b, 0xfe, 0xda,
+ 0x32, 0x73, 0x4d, 0x73, 0x16, 0x2f, 0xcd, 0xa9, 0x4d, 0x0b, 0x17, 0xff,
+ 0x7f, 0x09, 0xcd, 0xfb, 0x7a, 0x4c, 0xb1, 0x5f, 0x3e, 0xde, 0x14, 0xd6,
+ 0x23, 0x35, 0xa1, 0x57, 0x76, 0xe3, 0x2c, 0x5f, 0xff, 0x0b, 0xa0, 0xfb,
+ 0x03, 0xf1, 0xf4, 0xdd, 0x81, 0x62, 0xfd, 0x1f, 0x2c, 0x35, 0x62, 0x98,
+ 0xff, 0x7e, 0xab, 0x7e, 0x89, 0xbe, 0xda, 0x58, 0xbf, 0x85, 0xee, 0x40,
+ 0x27, 0x58, 0xbf, 0xfd, 0x83, 0x89, 0x47, 0x39, 0x92, 0x94, 0x2c, 0x5f,
+ 0x3e, 0xa2, 0x4b, 0x17, 0xff, 0xf3, 0x13, 0xb1, 0x03, 0x51, 0xf7, 0x6f,
+ 0x47, 0xd6, 0x2f, 0xff, 0x39, 0x03, 0x6f, 0x39, 0x13, 0x49, 0xa6, 0x58,
+ 0xa1, 0xa6, 0x80, 0x73, 0x02, 0x49, 0xf1, 0x16, 0xe2, 0xbd, 0xf7, 0xb8,
+ 0x29, 0xd6, 0x2f, 0xff, 0xfb, 0xbd, 0x40, 0xbc, 0x23, 0xe9, 0xdc, 0x05,
+ 0x9b, 0xdb, 0x4b, 0x14, 0xc8, 0x8e, 0x72, 0x5b, 0xff, 0x48, 0x31, 0xbc,
+ 0xf8, 0x77, 0xe2, 0xc5, 0xff, 0x4a, 0x3f, 0x1e, 0xfb, 0x9d, 0x62, 0xa0,
+ 0xfe, 0x84, 0x83, 0x7f, 0xf8, 0x98, 0x1e, 0xef, 0xa6, 0xd0, 0x70, 0x35,
+ 0x8b, 0xfe, 0xf8, 0x63, 0x17, 0xb8, 0x08, 0x58, 0xa8, 0x44, 0x4b, 0xa6,
+ 0xd0, 0xd5, 0xe5, 0xf4, 0x42, 0xd1, 0xb4, 0x9e, 0x1b, 0x65, 0x09, 0xbf,
+ 0x42, 0xaa, 0xf7, 0xdb, 0xeb, 0x17, 0xff, 0xc0, 0x3e, 0x1f, 0x09, 0xcf,
+ 0x12, 0x0f, 0x8b, 0x17, 0x0e, 0x16, 0x2f, 0xc0, 0x76, 0x1b, 0x2c, 0x54,
+ 0x1b, 0xe7, 0x17, 0xbe, 0x73, 0xf1, 0xd6, 0x2f, 0x41, 0xe1, 0x62, 0xff,
+ 0x3b, 0x74, 0x4f, 0x9d, 0x2c, 0x5f, 0xa3, 0xdf, 0x79, 0x96, 0x38, 0x6c,
+ 0xeb, 0xb4, 0xd5, 0xf5, 0x08, 0xee, 0x0f, 0xef, 0x22, 0xdc, 0x4f, 0xbf,
+ 0x68, 0x5d, 0x7e, 0x16, 0x2f, 0xed, 0x4d, 0x26, 0xf7, 0x16, 0x2c, 0x50,
+ 0x7b, 0x58, 0x55, 0x6e, 0x2c, 0x5e, 0x99, 0x8c, 0x58, 0xbb, 0x35, 0x06,
+ 0xc5, 0x84, 0xaf, 0xf4, 0xcf, 0x33, 0xf7, 0x2e, 0x2c, 0x5f, 0xcf, 0x3b,
+ 0x4c, 0xc6, 0x2c, 0x5f, 0xff, 0xe7, 0x33, 0xd9, 0xfd, 0xa3, 0xc9, 0xa4,
+ 0xfa, 0x9f, 0xe2, 0x58, 0xa8, 0x47, 0xc6, 0x15, 0x39, 0xb9, 0x18, 0x5f,
+ 0xb0, 0xa7, 0xc3, 0x16, 0x2f, 0xce, 0x7f, 0xb1, 0x8b, 0x15, 0x39, 0xe9,
+ 0x0c, 0xa6, 0xff, 0xe8, 0xf6, 0x13, 0x1a, 0x03, 0xc4, 0x96, 0x2f, 0xfa,
+ 0x27, 0x0e, 0x5f, 0x13, 0xce, 0xb1, 0x7f, 0x9f, 0xdc, 0xeb, 0xa6, 0xed,
+ 0x62, 0xff, 0x9b, 0xac, 0x99, 0xca, 0x70, 0xaa, 0xc5, 0x62, 0x63, 0x4c,
+ 0x47, 0xa4, 0x47, 0x3d, 0x23, 0x7b, 0x6c, 0x4b, 0x17, 0xe8, 0xd6, 0xb3,
+ 0xeb, 0x17, 0xff, 0x46, 0x17, 0xe1, 0x80, 0xfe, 0x12, 0xc5, 0xe7, 0x97,
+ 0x96, 0x2f, 0xff, 0xa0, 0xd3, 0x31, 0xb7, 0x98, 0xe3, 0x8c, 0x3a, 0xc5,
+ 0xfc, 0x4e, 0x6c, 0x1e, 0x16, 0x28, 0x2a, 0x98, 0xf4, 0x85, 0xf4, 0x50,
+ 0x74, 0x22, 0x1d, 0x12, 0x9d, 0xc6, 0x9a, 0xb1, 0x7f, 0x13, 0xf5, 0x85,
+ 0xd2, 0xc5, 0x4e, 0x79, 0x0c, 0x35, 0x78, 0x2c, 0xdd, 0x02, 0xc5, 0xff,
+ 0xfc, 0x27, 0xd4, 0xb6, 0xff, 0x26, 0x8f, 0x61, 0xe3, 0xeb, 0x16, 0xdd,
+ 0x58, 0xbf, 0xb8, 0xee, 0x1b, 0x86, 0xb1, 0x7d, 0x21, 0x0f, 0x67, 0x60,
+ 0x46, 0x40, 0xc9, 0x8d, 0x5e, 0xf0, 0xad, 0xfc, 0x77, 0xec, 0x29, 0x9f,
+ 0x58, 0xbc, 0x63, 0xf1, 0x62, 0xfe, 0x3c, 0x61, 0x7b, 0x8b, 0x17, 0xe8,
+ 0x9f, 0x24, 0xcb, 0x17, 0x83, 0x1e, 0xce, 0x22, 0x9b, 0xe6, 0x7c, 0x1e,
+ 0xf1, 0x6d, 0x4c, 0x9a, 0xb7, 0xe3, 0x04, 0xbf, 0xe9, 0xe7, 0x6e, 0xbb,
+ 0x94, 0x04, 0x58, 0xbe, 0xff, 0xf3, 0xb5, 0x8b, 0xf9, 0xc7, 0x05, 0x00,
+ 0x58, 0xbe, 0x6e, 0x60, 0xe0, 0xf4, 0x37, 0x09, 0x2f, 0xcf, 0xcf, 0x67,
+ 0xd6, 0x2d, 0xf5, 0x8b, 0xff, 0x08, 0x6e, 0x40, 0xf3, 0x77, 0xc5, 0x8b,
+ 0xff, 0xfd, 0xa7, 0xe0, 0x7e, 0x2c, 0xde, 0xe0, 0x1e, 0x89, 0xcc, 0x58,
+ 0xb7, 0xa4, 0x8a, 0x41, 0x20, 0x5e, 0xfb, 0x8d, 0x62, 0xff, 0x9a, 0x0f,
+ 0xb7, 0x06, 0xdb, 0xd6, 0x2b, 0x13, 0x38, 0x68, 0x5b, 0x7c, 0xa7, 0x83,
+ 0xb7, 0xdb, 0x7c, 0xc7, 0x58, 0xa8, 0x5c, 0xfb, 0x1c, 0xa4, 0x0c, 0x2b,
+ 0xea, 0x12, 0x0c, 0x74, 0xf1, 0xb0, 0x09, 0x06, 0xf8, 0x52, 0xfb, 0x2c,
+ 0x5f, 0xff, 0x9b, 0xa8, 0x3f, 0x1f, 0x58, 0x71, 0x74, 0xf2, 0x58, 0xbf,
+ 0xe7, 0xd3, 0xf9, 0xb4, 0xe0, 0x58, 0xb9, 0xb7, 0xac, 0x5f, 0xe8, 0x27,
+ 0xf8, 0x8a, 0x75, 0x8b, 0xff, 0x31, 0xb0, 0x36, 0x27, 0xd1, 0xab, 0x17,
+ 0xff, 0xb3, 0xbf, 0x77, 0xe6, 0x33, 0x06, 0xf2, 0x58, 0xac, 0x44, 0x60,
+ 0x0f, 0xed, 0xf5, 0x8b, 0xf9, 0xb4, 0x03, 0xb7, 0x16, 0x2a, 0x74, 0xfb,
+ 0x24, 0x47, 0xd2, 0xbe, 0xe9, 0xc1, 0xc6, 0x4a, 0x17, 0xe2, 0x22, 0xdc,
+ 0x12, 0xbc, 0x7e, 0x12, 0xc5, 0xff, 0xff, 0xdd, 0xf3, 0x24, 0xde, 0xfe,
+ 0x10, 0x01, 0x1f, 0x2c, 0x1b, 0x9d, 0x62, 0xa1, 0x11, 0xcc, 0x3b, 0x78,
+ 0x70, 0x75, 0x8b, 0xf8, 0x19, 0x34, 0x77, 0xc5, 0x8b, 0xff, 0x7f, 0x0b,
+ 0xad, 0xb8, 0x36, 0xde, 0xb1, 0x7f, 0xff, 0x89, 0xcc, 0xfe, 0x1d, 0xcc,
+ 0xf7, 0x30, 0xc1, 0xb1, 0xd6, 0x2f, 0x7f, 0x26, 0x58, 0xbf, 0xe1, 0x69,
+ 0xde, 0x5e, 0xcf, 0xac, 0x5f, 0x81, 0xdc, 0xa0, 0x22, 0xc5, 0xfd, 0x9a,
+ 0xc9, 0xa0, 0xd5, 0x8a, 0xc3, 0xdb, 0xf1, 0x65, 0xff, 0xff, 0xdc, 0xfc,
+ 0x7e, 0x1b, 0xb0, 0x6b, 0x07, 0x1e, 0xe3, 0x17, 0x72, 0x58, 0xac, 0x54,
+ 0x38, 0xc6, 0x13, 0x21, 0xfd, 0x8f, 0x83, 0xde, 0x84, 0xa1, 0x84, 0x37,
+ 0x86, 0xc7, 0x58, 0xbf, 0xf1, 0x13, 0x1f, 0x6b, 0x00, 0x30, 0x2c, 0x5f,
+ 0xe3, 0x4b, 0x27, 0x9c, 0x44, 0xb1, 0x50, 0xac, 0xe3, 0x25, 0x1c, 0xb3,
+ 0x5b, 0x8e, 0x89, 0x06, 0xf0, 0x3c, 0x17, 0x58, 0xbd, 0x26, 0xd2, 0xc5,
+ 0xfd, 0xf7, 0x94, 0x72, 0x4b, 0x17, 0xfd, 0x9f, 0x6e, 0xf9, 0xf1, 0x71,
+ 0x62, 0xba, 0x3e, 0x90, 0x17, 0x57, 0x68, 0xa9, 0x28, 0x43, 0x54, 0x23,
+ 0xcf, 0x21, 0x97, 0x7f, 0xf0, 0x1b, 0xfc, 0x7e, 0xbf, 0x1b, 0xa3, 0x58,
+ 0xbf, 0xff, 0x3e, 0xee, 0xdd, 0xc1, 0x46, 0xdc, 0xe1, 0x09, 0xe7, 0x58,
+ 0xa0, 0x22, 0xa4, 0x49, 0x37, 0xdc, 0x76, 0x9d, 0x62, 0xf7, 0x27, 0x85,
+ 0x8a, 0x9c, 0xf0, 0x70, 0x8e, 0xe0, 0xac, 0xcb, 0x17, 0xff, 0xf7, 0xb3,
+ 0x7e, 0xdd, 0xc1, 0x46, 0xdc, 0xe1, 0x09, 0xe7, 0x58, 0xbf, 0xe9, 0x47,
+ 0xbd, 0x0e, 0x79, 0xd6, 0x2b, 0x11, 0x3f, 0xdb, 0x2d, 0xff, 0xec, 0xfb,
+ 0xb9, 0xc9, 0xf4, 0xd1, 0xc5, 0x8b, 0x61, 0xcf, 0xab, 0x79, 0x1d, 0xfa,
+ 0x70, 0x91, 0xdf, 0x16, 0x2f, 0xce, 0x01, 0xe1, 0x2c, 0x56, 0x2a, 0x29,
+ 0x66, 0x43, 0x91, 0x7e, 0x32, 0x67, 0x29, 0x22, 0xdb, 0x4c, 0xb1, 0x7b,
+ 0x08, 0xd5, 0x8a, 0x83, 0x61, 0x82, 0x77, 0xfb, 0xa8, 0x97, 0xbe, 0xe3,
+ 0x58, 0xbf, 0x36, 0xe6, 0x68, 0xd5, 0x8b, 0xed, 0xe5, 0x9c, 0x58, 0xbf,
+ 0x89, 0xcd, 0x2c, 0x02, 0xc5, 0x31, 0xe8, 0x9c, 0x92, 0xff, 0xec, 0x97,
+ 0xb3, 0xe5, 0x9e, 0xfb, 0x2c, 0x5a, 0x16, 0x2b, 0xe7, 0xa8, 0xe8, 0x77,
+ 0x80, 0x18, 0x16, 0x2d, 0x25, 0x8b, 0xe8, 0xf7, 0x36, 0xb1, 0xb1, 0xf0,
+ 0xfd, 0xc6, 0xc9, 0x62, 0xfd, 0xf6, 0xde, 0xdd, 0x2c, 0x5d, 0x9f, 0x91,
+ 0xe2, 0x74, 0x33, 0x53, 0xaa, 0x43, 0xc1, 0xf3, 0x9a, 0xbb, 0xef, 0x1d,
+ 0x7c, 0xa5, 0xb8, 0xfb, 0x78, 0xc3, 0x0c, 0x48, 0xbf, 0xf6, 0x88, 0x4e,
+ 0x1e, 0x4d, 0x07, 0x58, 0xd9, 0x34, 0x37, 0xa6, 0x63, 0x16, 0x2f, 0x7c,
+ 0x40, 0x58, 0xb7, 0xd8, 0xde, 0xcc, 0x3f, 0x6e, 0x96, 0x2a, 0x11, 0x95,
+ 0x90, 0x90, 0xd1, 0x3d, 0xfe, 0x81, 0xe4, 0xa0, 0xba, 0x58, 0xa8, 0x74,
+ 0x5d, 0x93, 0xc6, 0xcd, 0x28, 0x77, 0x8c, 0x9b, 0x27, 0x18, 0xbb, 0x6d,
+ 0x68, 0xdd, 0x37, 0x61, 0x61, 0x34, 0x69, 0xda, 0x8e, 0x94, 0xf1, 0xb2,
+ 0xfe, 0x76, 0x79, 0xe5, 0x31, 0x02, 0x30, 0xc2, 0x96, 0xb3, 0xc8, 0xd0,
+ 0xbd, 0x2b, 0xe0, 0x52, 0xb3, 0x8c, 0x8d, 0x4c, 0x33, 0x3b, 0xe6, 0xd3,
+ 0x81, 0x62, 0xff, 0x0f, 0xf1, 0x39, 0x67, 0x6b, 0x17, 0x87, 0xf8, 0x58,
+ 0xa3, 0x9f, 0xa0, 0x08, 0xb8, 0x6b, 0x7d, 0xad, 0x67, 0xd6, 0x2f, 0xef,
+ 0xb0, 0x40, 0x82, 0x35, 0x62, 0xa0, 0xf5, 0xfa, 0x23, 0xb0, 0x5d, 0x62,
+ 0xe2, 0xe2, 0xc5, 0x99, 0x62, 0xfe, 0xd7, 0x3f, 0x05, 0xe5, 0x8b, 0xa0,
+ 0x0b, 0x16, 0xf4, 0x1e, 0x2f, 0x0b, 0xaf, 0xff, 0x6a, 0x70, 0xfc, 0xdf,
+ 0x11, 0xce, 0xf2, 0x58, 0xb0, 0x5d, 0x62, 0xff, 0xbd, 0x1a, 0xe7, 0xe0,
+ 0xbc, 0xb1, 0x77, 0x21, 0x62, 0xf1, 0xc7, 0x0b, 0x17, 0xf8, 0xbc, 0xf3,
+ 0x72, 0x3c, 0xb1, 0x4c, 0x7a, 0x2e, 0x3b, 0x7c, 0xcf, 0x9d, 0x2c, 0x5f,
+ 0xfb, 0x37, 0x96, 0x72, 0x62, 0x81, 0xac, 0x5f, 0x74, 0x38, 0x9d, 0x62,
+ 0xe0, 0x42, 0xc5, 0xee, 0x36, 0x96, 0x2b, 0x0f, 0x64, 0x04, 0xbe, 0x17,
+ 0xbf, 0xd2, 0xc2, 0x61, 0xe1, 0x2c, 0x5d, 0xcd, 0x98, 0x4f, 0xc7, 0x05,
+ 0xa6, 0x39, 0xfb, 0x40, 0x08, 0x08, 0x8b, 0x90, 0x99, 0xf1, 0x75, 0x3a,
+ 0xac, 0x3f, 0x4a, 0x3f, 0xbe, 0xec, 0x6f, 0x3a, 0xc5, 0xdc, 0x85, 0x8b,
+ 0xc7, 0x1c, 0x2c, 0x5f, 0xe2, 0xf3, 0xcd, 0xc8, 0xf2, 0xc5, 0x31, 0xe8,
+ 0xb8, 0xed, 0xf3, 0x3e, 0x74, 0xb1, 0x7f, 0xec, 0xde, 0x59, 0xc9, 0x8a,
+ 0x06, 0xb1, 0x7d, 0xd0, 0xe2, 0x75, 0x8b, 0xfa, 0x60, 0x36, 0xeb, 0xcc,
+ 0xb1, 0x79, 0x81, 0xc5, 0x8b, 0x81, 0x0b, 0x17, 0xb8, 0xda, 0x58, 0xbb,
+ 0x26, 0x58, 0xac, 0x46, 0x0f, 0x44, 0xbf, 0x33, 0x00, 0xef, 0x85, 0xc3,
+ 0x1d, 0xbf, 0xb0, 0x98, 0x78, 0x4b, 0x17, 0xec, 0x22, 0x7f, 0x2c, 0x5f,
+ 0xa7, 0xf6, 0x61, 0xd6, 0x2a, 0x47, 0xf5, 0xf2, 0xb7, 0x26, 0xbf, 0x89,
+ 0xc7, 0x86, 0xec, 0xc2, 0xf3, 0x44, 0x85, 0x86, 0x2f, 0x8a, 0xdd, 0x4a,
+ 0xea, 0x62, 0xb9, 0x89, 0x7e, 0xd0, 0x02, 0x02, 0x22, 0xe4, 0x60, 0x3e,
+ 0x86, 0x95, 0xff, 0xda, 0x8e, 0xf8, 0x50, 0x7c, 0xef, 0xcb, 0x17, 0xff,
+ 0xe7, 0x1e, 0x61, 0x1a, 0x19, 0x41, 0x4e, 0xda, 0x58, 0xbc, 0xfa, 0x9d,
+ 0x72, 0x09, 0x17, 0xd2, 0xce, 0xe4, 0xb9, 0x04, 0x8b, 0xdc, 0x61, 0xae,
+ 0x41, 0x22, 0xe3, 0x0c, 0x5c, 0x82, 0x45, 0x74, 0x8a, 0xd9, 0x8a, 0xfc,
+ 0x62, 0x61, 0x55, 0xcf, 0xe4, 0xc8, 0x24, 0x36, 0x4f, 0x02, 0xff, 0xff,
+ 0xe1, 0x94, 0x0f, 0xf1, 0xee, 0x47, 0xa0, 0x71, 0xec, 0x38, 0x0c, 0x58,
+ 0xbf, 0xb3, 0xf9, 0x84, 0x6a, 0xc5, 0xe7, 0x20, 0x6d, 0x64, 0xe3, 0xc4,
+ 0xf4, 0x56, 0xa1, 0xba, 0x74, 0x62, 0x8d, 0x0b, 0x87, 0x3e, 0x72, 0xbf,
+ 0x7d, 0xe5, 0x12, 0x58, 0xbe, 0xdc, 0xc7, 0xfa, 0xc5, 0x6e, 0xa3, 0x63,
+ 0xf0, 0x8b, 0x01, 0x45, 0xfe, 0x98, 0xc8, 0xec, 0x71, 0xc5, 0x8a, 0xc3,
+ 0xef, 0x63, 0x8b, 0x49, 0x62, 0xfe, 0x90, 0xa7, 0xf3, 0x4e, 0x91, 0x7f,
+ 0x16, 0x7b, 0x90, 0x75, 0x8b, 0xed, 0x01, 0xbc, 0xb1, 0x7b, 0x7c, 0x71,
+ 0x62, 0xf9, 0xc7, 0xfc, 0x58, 0xbc, 0x36, 0x3a, 0xc5, 0xff, 0xbf, 0x1e,
+ 0x62, 0x83, 0xc7, 0x16, 0x2e, 0xff, 0x4b, 0x16, 0xdd, 0x58, 0xad, 0xa9,
+ 0x8c, 0xc1, 0x6e, 0x11, 0x9a, 0x3e, 0xe4, 0x5c, 0x1d, 0x11, 0xe8, 0x41,
+ 0x9a, 0x99, 0x3b, 0xef, 0xc6, 0x95, 0x7f, 0xd0, 0x52, 0x28, 0x03, 0x9d,
+ 0x62, 0xfe, 0xe9, 0xb9, 0xec, 0xfa, 0xc5, 0xf7, 0xb4, 0x23, 0xac, 0x5c,
+ 0xd3, 0xac, 0x53, 0x1b, 0xcf, 0x12, 0x5f, 0x47, 0xc5, 0xa5, 0x8b, 0xdf,
+ 0x7f, 0x2c, 0x54, 0xe7, 0xc1, 0x31, 0x07, 0x08, 0xee, 0x8f, 0xac, 0x5a,
+ 0x16, 0x3c, 0x5b, 0xdf, 0xe6, 0x90, 0x9f, 0x9f, 0x65, 0x8b, 0xfb, 0x37,
+ 0xb9, 0xf3, 0xeb, 0x16, 0x92, 0x45, 0xe7, 0xd4, 0xe9, 0x14, 0x91, 0x50,
+ 0x6f, 0x3a, 0x12, 0x38, 0xf5, 0xe8, 0x07, 0x49, 0x1b, 0x26, 0xba, 0xff,
+ 0xef, 0xbc, 0x8b, 0x38, 0x23, 0x4e, 0x62, 0xc5, 0x1d, 0x31, 0x12, 0x84,
+ 0xcf, 0x8c, 0x6f, 0x14, 0xbe, 0xb1, 0x7b, 0xb9, 0x71, 0x62, 0xa1, 0x3b,
+ 0x5c, 0x8d, 0x10, 0xe6, 0xae, 0x3b, 0x7e, 0xc2, 0x9d, 0xb4, 0xb1, 0x6d,
+ 0xc5, 0x8b, 0x3c, 0xe6, 0xf4, 0x8a, 0x2f, 0xda, 0x01, 0xdb, 0x8b, 0x17,
+ 0xf0, 0x65, 0x2e, 0x7c, 0x6b, 0x18, 0x6a, 0x6f, 0xef, 0x70, 0x0e, 0xfa,
+ 0x58, 0xbe, 0x8e, 0x9b, 0x8b, 0x17, 0xc2, 0x7d, 0x49, 0x62, 0xc7, 0x58,
+ 0xb4, 0x86, 0x6d, 0x66, 0x23, 0xbf, 0xff, 0xff, 0xc0, 0x00, 0xb8, 0xfe,
+ 0xf4, 0xb3, 0xff, 0x79, 0x6e, 0x67, 0x38, 0x2e, 0x7b, 0x98, 0x62, 0xc5,
+ 0x42, 0x68, 0x73, 0x97, 0x62, 0xc3, 0x94, 0x5f, 0xfd, 0x9d, 0xfb, 0x8c,
+ 0x50, 0x07, 0x3a, 0xc5, 0xe9, 0x47, 0x6b, 0x17, 0x60, 0xd6, 0x2f, 0xb2,
+ 0x66, 0x3a, 0xc5, 0x4e, 0x89, 0xc9, 0x91, 0x3c, 0x3c, 0x60, 0xbd, 0xfa,
+ 0x26, 0x94, 0x01, 0x22, 0xe2, 0x02, 0xc5, 0xef, 0x8b, 0x75, 0x62, 0xfe,
+ 0xf3, 0x69, 0xa7, 0x85, 0x8a, 0xc3, 0xe6, 0xe8, 0x5c, 0x32, 0x1b, 0xff,
+ 0xf7, 0xf1, 0xa5, 0xcd, 0xbe, 0xfe, 0x0c, 0x5e, 0xe2, 0xc5, 0x74, 0x98,
+ 0xc6, 0xa1, 0x1f, 0xe3, 0x0b, 0x9a, 0x65, 0x8b, 0xf8, 0xbd, 0x36, 0x6b,
+ 0x16, 0x2c, 0x03, 0x9e, 0x33, 0x8c, 0x58, 0x2d, 0xd6, 0x2f, 0xfd, 0xef,
+ 0xe0, 0xc5, 0xee, 0x4d, 0x0b, 0x16, 0x65, 0x8b, 0xfe, 0x9c, 0x52, 0x1f,
+ 0xc4, 0xe4, 0xb1, 0x7f, 0x34, 0x1e, 0x7c, 0x31, 0x62, 0xfd, 0x93, 0x9f,
+ 0x0e, 0xb1, 0x7b, 0x8d, 0xa5, 0x8a, 0x23, 0xc6, 0xf1, 0x4d, 0xfc, 0x4e,
+ 0x00, 0x0b, 0x8b, 0x17, 0xa0, 0xfb, 0x23, 0x4c, 0x43, 0x04, 0x74, 0x77,
+ 0xc7, 0x5f, 0x10, 0xd8, 0xde, 0x27, 0x5e, 0x1c, 0x6a, 0x34, 0x16, 0xe9,
+ 0xfd, 0x34, 0x79, 0x15, 0x8b, 0x84, 0xcd, 0x1a, 0xc3, 0xbe, 0x94, 0xa2,
+ 0x1b, 0xfe, 0x03, 0x17, 0xbb, 0xe3, 0xee, 0xac, 0x5f, 0xbf, 0x93, 0xfb,
+ 0x8b, 0x15, 0xa3, 0xe7, 0xf9, 0xed, 0xf6, 0xa3, 0xbe, 0x2c, 0x5e, 0xc9,
+ 0xc4, 0xb1, 0x58, 0x7c, 0x8e, 0x44, 0x44, 0x97, 0xfb, 0xdb, 0x4b, 0x00,
+ 0x1f, 0x6b, 0x17, 0xfb, 0x85, 0x93, 0x4a, 0x3b, 0x58, 0xac, 0x3e, 0xdf,
+ 0x1c, 0x54, 0x37, 0x3d, 0x32, 0xa5, 0xca, 0x0c, 0x83, 0x23, 0xd0, 0x34,
+ 0xaf, 0xb3, 0x76, 0x86, 0x5e, 0x92, 0x3f, 0x1e, 0xab, 0xbf, 0x01, 0x3c,
+ 0xa3, 0x82, 0xe4, 0xe7, 0xf7, 0xa3, 0x14, 0xdc, 0x84, 0xcd, 0xff, 0xfa,
+ 0x7d, 0x6b, 0x06, 0xe7, 0xfb, 0xf8, 0xa2, 0x65, 0x8b, 0xff, 0xff, 0xc2,
+ 0xd0, 0xa6, 0x27, 0x07, 0x39, 0x86, 0xe0, 0xb4, 0xe3, 0x8f, 0xc2, 0xc5,
+ 0xff, 0xef, 0x47, 0xb9, 0xa8, 0x2f, 0x7f, 0x24, 0xb1, 0x7f, 0xdc, 0x2c,
+ 0xff, 0x8a, 0x00, 0xb1, 0x6e, 0x2c, 0x56, 0x22, 0x50, 0xd4, 0xaf, 0x1c,
+ 0x5f, 0xcc, 0x1c, 0x77, 0x1d, 0xac, 0x5f, 0xc2, 0x8d, 0x69, 0xa7, 0x58,
+ 0xbf, 0xf8, 0x46, 0xe1, 0x7f, 0x06, 0x36, 0xed, 0x62, 0xfe, 0xd9, 0x6f,
+ 0x6b, 0x24, 0xb1, 0x5d, 0x1f, 0xbb, 0x23, 0x5f, 0xdf, 0x6d, 0xe2, 0x04,
+ 0x96, 0x2f, 0xf7, 0x21, 0xb5, 0xac, 0x9d, 0x62, 0xfe, 0x94, 0x03, 0xec,
+ 0x62, 0xc5, 0xf7, 0x38, 0x2e, 0xd6, 0x2f, 0xc3, 0xfc, 0x10, 0x96, 0x2a,
+ 0x0f, 0x35, 0xc9, 0x6f, 0xfa, 0x0e, 0x58, 0x36, 0xff, 0x16, 0x2f, 0x63,
+ 0x01, 0x62, 0xfb, 0xa3, 0x74, 0x05, 0x8b, 0xce, 0xe4, 0xb1, 0x7f, 0x4a,
+ 0x26, 0xc6, 0x02, 0xc5, 0xb6, 0x46, 0xaa, 0x33, 0x21, 0x4c, 0x69, 0x17,
+ 0x66, 0x33, 0x1a, 0x1d, 0xf3, 0xe4, 0x01, 0x73, 0x82, 0x1c, 0xf1, 0x30,
+ 0x41, 0xbb, 0x84, 0x62, 0xc5, 0xf4, 0x6e, 0x8e, 0x16, 0x2f, 0x82, 0x7c,
+ 0x41, 0xac, 0x5f, 0xc2, 0x0f, 0x8d, 0x84, 0xb1, 0x76, 0x4c, 0xb1, 0x70,
+ 0x73, 0x2c, 0x53, 0x1b, 0x27, 0x18, 0xb4, 0x4c, 0x7f, 0xfc, 0x60, 0xbc,
+ 0x61, 0x86, 0x24, 0x5a, 0x12, 0x36, 0x4d, 0x0d, 0xd2, 0x9d, 0x62, 0xa4,
+ 0x6f, 0x4e, 0x49, 0x7b, 0xf0, 0x05, 0x8b, 0xfb, 0x62, 0xfc, 0x02, 0x37,
+ 0x56, 0x2b, 0xc7, 0xa6, 0x18, 0xed, 0xdf, 0xd2, 0xc5, 0xc0, 0x02, 0xc5,
+ 0xef, 0xec, 0x46, 0x2c, 0x5f, 0x4d, 0x99, 0xd2, 0xc5, 0x42, 0xfb, 0xc4,
+ 0xea, 0xf2, 0x8c, 0x34, 0x66, 0x19, 0x2a, 0xf0, 0xd8, 0x57, 0xf4, 0x33,
+ 0xd9, 0x2c, 0xd0, 0xa6, 0xd4, 0x21, 0x9d, 0xd3, 0xc4, 0x62, 0x18, 0xde,
+ 0x30, 0x61, 0x25, 0xf0, 0xf3, 0x34, 0xb1, 0x7f, 0xfb, 0xd3, 0x66, 0xb4,
+ 0xf3, 0x66, 0xb3, 0xcb, 0x15, 0x87, 0xdc, 0xc4, 0x57, 0xfd, 0x26, 0xf4,
+ 0xa3, 0x51, 0xd2, 0xc5, 0xb7, 0x56, 0x2e, 0x29, 0x6d, 0x3c, 0xf9, 0x1d,
+ 0x5f, 0xa3, 0x5a, 0xcf, 0xac, 0x56, 0x1e, 0xb9, 0xa5, 0xf7, 0xf4, 0xf3,
+ 0x4b, 0x62, 0xd4, 0xeb, 0x17, 0xff, 0x80, 0x77, 0x96, 0xd8, 0x1c, 0xe7,
+ 0x8d, 0x2c, 0x5f, 0x34, 0x17, 0x96, 0x2f, 0x4e, 0xe4, 0xb1, 0x6c, 0x58,
+ 0xad, 0x22, 0x77, 0xe9, 0xde, 0x21, 0x30, 0x76, 0xff, 0xc6, 0x8b, 0x92,
+ 0x6d, 0x4e, 0x20, 0x2c, 0x5c, 0x58, 0xb1, 0x78, 0x3e, 0xc9, 0x62, 0xfc,
+ 0x59, 0xd8, 0x38, 0xb1, 0x77, 0x66, 0x2c, 0x5f, 0x66, 0xec, 0x1d, 0x62,
+ 0xb0, 0xfa, 0x1c, 0xa7, 0x83, 0x57, 0xfe, 0xf4, 0x1f, 0x69, 0x60, 0x03,
+ 0xed, 0x62, 0xff, 0x71, 0xff, 0xd4, 0x30, 0xd6, 0x28, 0xd4, 0xe1, 0x19,
+ 0x0c, 0xe2, 0xdf, 0x84, 0x39, 0x16, 0xf9, 0x0e, 0xf3, 0x1e, 0x16, 0x2f,
+ 0x34, 0x1d, 0x62, 0xe7, 0x1a, 0xc5, 0x68, 0xd9, 0xf8, 0x72, 0xfd, 0x3f,
+ 0xf0, 0x0e, 0xb1, 0x53, 0x9e, 0x56, 0x88, 0x6f, 0xbe, 0x3c, 0x25, 0x8b,
+ 0xff, 0xc1, 0xf8, 0xa0, 0x0f, 0xe0, 0x06, 0x52, 0x58, 0xbb, 0x78, 0xd6,
+ 0x2a, 0x0f, 0x99, 0xd3, 0x2f, 0xfd, 0xbe, 0x0b, 0xdc, 0x6d, 0xf8, 0x35,
+ 0x8b, 0xff, 0xcd, 0xad, 0xbc, 0xe6, 0x17, 0x4e, 0x40, 0x58, 0xa8, 0x44,
+ 0x77, 0xd0, 0xac, 0x16, 0xeb, 0x15, 0xb1, 0xae, 0x90, 0x64, 0x35, 0x5a,
+ 0x3c, 0x2d, 0x2e, 0x3c, 0x26, 0x78, 0x47, 0xe8, 0x44, 0x0a, 0x15, 0xdb,
+ 0xc8, 0xaf, 0xff, 0xde, 0x82, 0x60, 0x67, 0x7e, 0xd3, 0x19, 0x33, 0x2c,
+ 0x5f, 0x9f, 0x0f, 0x1d, 0x2c, 0x5e, 0x27, 0x02, 0xc5, 0xe1, 0xfd, 0x96,
+ 0x2b, 0x11, 0x70, 0x6a, 0xbf, 0xca, 0x03, 0x1c, 0xbf, 0xf3, 0xfb, 0x86,
+ 0x67, 0xc0, 0xfe, 0x58, 0xbf, 0x03, 0x06, 0xf2, 0x58, 0xbe, 0xde, 0x27,
+ 0x25, 0x8b, 0xed, 0x1e, 0x38, 0xb1, 0x7f, 0xfd, 0x98, 0x51, 0x2f, 0x7d,
+ 0xce, 0x59, 0xbd, 0x62, 0xfb, 0x3d, 0x1d, 0x6d, 0x3f, 0x22, 0x23, 0xa9,
+ 0xd3, 0x76, 0x19, 0xf6, 0x90, 0x08, 0xa0, 0xc8, 0x4b, 0x5e, 0x0c, 0x73,
+ 0x2c, 0x5c, 0xc4, 0xb1, 0x7f, 0xfd, 0x9d, 0x46, 0xdf, 0xc6, 0x01, 0xc8,
+ 0x58, 0xb1, 0x52, 0x3e, 0x6f, 0x8b, 0x5f, 0xfc, 0xc7, 0x27, 0x37, 0x9f,
+ 0x82, 0xf2, 0xc5, 0xfb, 0x8f, 0xf6, 0xe2, 0xc5, 0xc1, 0xc9, 0x62, 0xff,
+ 0x41, 0x85, 0x80, 0x17, 0x16, 0x28, 0xd3, 0xcd, 0xd0, 0xcd, 0xff, 0xff,
+ 0xe9, 0x73, 0xee, 0xde, 0x16, 0x9f, 0x98, 0x51, 0x21, 0xe9, 0xbb, 0x92,
+ 0xc5, 0xe0, 0xc2, 0x18, 0xb1, 0x7f, 0xfc, 0x0c, 0x1f, 0xb8, 0xde, 0xfe,
+ 0x6f, 0x1c, 0x2c, 0x5c, 0xdd, 0xac, 0x54, 0xe8, 0x8c, 0xd1, 0x17, 0x94,
+ 0xaf, 0xe7, 0x6f, 0x4c, 0xc6, 0x2c, 0x5f, 0xc3, 0xfc, 0x18, 0xfe, 0x58,
+ 0xbf, 0xf6, 0x11, 0xb9, 0xaf, 0x79, 0xb4, 0xb1, 0x7b, 0xee, 0x6a, 0xc5,
+ 0xe9, 0xdb, 0x50, 0x88, 0xcc, 0x2f, 0xf1, 0xfd, 0x7d, 0x1f, 0x65, 0x0b,
+ 0xbb, 0xfe, 0xf7, 0x03, 0x3e, 0xdc, 0xef, 0xcb, 0x15, 0x07, 0xcd, 0x84,
+ 0xf7, 0xfe, 0x06, 0x69, 0x81, 0x80, 0xd1, 0xd6, 0x2f, 0xff, 0x1b, 0x1c,
+ 0xd4, 0x7c, 0xb3, 0xd0, 0x75, 0x8b, 0xdb, 0x48, 0x2e, 0xb1, 0x70, 0x83,
+ 0x58, 0xbf, 0xfb, 0x3d, 0xf6, 0x93, 0x6a, 0x71, 0x01, 0x62, 0xff, 0x4b,
+ 0x38, 0x1c, 0xe2, 0x25, 0x8a, 0xe8, 0xff, 0x04, 0x8d, 0x7f, 0x8b, 0x37,
+ 0xb4, 0xcc, 0x62, 0xc5, 0x49, 0x31, 0x1f, 0x91, 0x94, 0x25, 0x78, 0x47,
+ 0x7f, 0xff, 0x09, 0xe7, 0xe8, 0x53, 0xfb, 0x3e, 0x59, 0xef, 0xb2, 0xc5,
+ 0xfa, 0x26, 0x21, 0x71, 0x62, 0xb1, 0x51, 0x23, 0x46, 0xb7, 0xf4, 0x2f,
+ 0x2f, 0x5c, 0xc4, 0xb1, 0x77, 0x8d, 0x58, 0xbe, 0xd3, 0x4d, 0xc5, 0x8b,
+ 0xce, 0x40, 0xc3, 0x7b, 0xa1, 0x9a, 0x85, 0xfb, 0x49, 0xd4, 0x65, 0x08,
+ 0x63, 0x48, 0xa6, 0x44, 0xd3, 0xaf, 0xc8, 0xde, 0x30, 0x42, 0x8e, 0x4b,
+ 0x84, 0x1e, 0x94, 0xc7, 0xbd, 0x0f, 0x71, 0x4e, 0xf8, 0xbd, 0x1b, 0x8b,
+ 0x17, 0xa3, 0x7c, 0x2c, 0x5e, 0x82, 0xf2, 0xc5, 0xf4, 0x69, 0xfe, 0xb1,
+ 0x43, 0x37, 0xdb, 0xc7, 0x2e, 0xc9, 0x96, 0x2f, 0xbe, 0x23, 0xc2, 0xc5,
+ 0x2c, 0x52, 0xc5, 0x9c, 0xe5, 0xc7, 0x03, 0x2e, 0x10, 0x5d, 0x62, 0xfb,
+ 0xf8, 0x07, 0x58, 0xbe, 0xf3, 0x7c, 0x4b, 0x17, 0xf6, 0x6b, 0xb9, 0x7a,
+ 0x16, 0x2e, 0x8d, 0xd0, 0xb4, 0x7a, 0x41, 0x91, 0xd6, 0xc6, 0x9f, 0x1c,
+ 0x12, 0xb2, 0xe4, 0xc4, 0x6e, 0x30, 0x47, 0x62, 0x25, 0xde, 0x38, 0x11,
+ 0xd2, 0xdb, 0x3b, 0x1c, 0x60, 0x81, 0x21, 0x58, 0xfb, 0x76, 0x08, 0xcf,
+ 0xf6, 0x28, 0x5d, 0xec, 0x22, 0xbd, 0x87, 0x08, 0x30, 0xb5, 0x29, 0x4c,
+ 0x2c, 0x85, 0xc8, 0x5b, 0x9e, 0x45, 0x33, 0xbe, 0x79, 0xe9, 0xa9, 0x4e,
+ 0x49, 0x0e, 0x99, 0x33, 0x95, 0xd7, 0xa1, 0xb2, 0xc0, 0xfa, 0x9e, 0x82,
+ 0xee, 0x73, 0xf5, 0xa7, 0x68, 0x37, 0x63, 0x40, 0x9a, 0x7e, 0x03, 0x54,
+ 0x8f, 0x43, 0xcf, 0xca, 0x7e, 0xb8, 0xf8, 0x79, 0xec, 0x50, 0x4e, 0x96,
+ 0x05, 0xe3, 0x47, 0x2a, 0x5c, 0x0f, 0x2d, 0x1f, 0x9f, 0xab, 0xbd, 0x91,
+ 0x52, 0x1f, 0x37, 0xc6, 0xbc, 0x64, 0x31, 0xb7, 0x27, 0x50, 0x83, 0xa5,
+ 0x40, 0x84, 0x95, 0x6b, 0x7e, 0x0b, 0x3c, 0x4e, 0x05, 0x8b, 0xfb, 0x62,
+ 0xd8, 0xbc, 0x4e, 0x05, 0x8b, 0xf4, 0xe7, 0x8e, 0xf6, 0x76, 0x33, 0xe5,
+ 0xd8, 0x0b, 0x69, 0xd5, 0xe6, 0x0a, 0x5b, 0xf5, 0xf3, 0x10, 0x19, 0x62,
+ 0xf3, 0x9f, 0x8b, 0x15, 0x23, 0x7d, 0xbc, 0x86, 0xfc, 0x7c, 0x67, 0x02,
+ 0xc5, 0xf7, 0x4e, 0xfd, 0x2a, 0x28, 0xa2, 0xff, 0xfc, 0xe0, 0x8e, 0xbe,
+ 0xdc, 0xfb, 0x7b, 0xf8, 0x4b, 0x15, 0xa4, 0x43, 0x11, 0x8d, 0xff, 0xa3,
+ 0xcc, 0x08, 0x97, 0xb8, 0x14, 0x58, 0xbf, 0x75, 0x05, 0x00, 0x58, 0xbe,
+ 0xf1, 0xad, 0xd2, 0xc5, 0x39, 0xe6, 0xf0, 0xa2, 0xfe, 0xc0, 0x07, 0xa7,
+ 0x02, 0xc5, 0xe7, 0x96, 0xcc, 0x27, 0x5f, 0x90, 0xad, 0xd1, 0x17, 0xe1,
+ 0x21, 0xe2, 0x1b, 0xff, 0xa1, 0xf4, 0x42, 0x7e, 0xf3, 0xee, 0xb1, 0x7f,
+ 0xfc, 0xd3, 0x14, 0x7b, 0x9e, 0xef, 0xa6, 0x29, 0xd6, 0x2f, 0xff, 0xb3,
+ 0xfe, 0x63, 0x1b, 0x24, 0xda, 0x70, 0x2c, 0x50, 0xd1, 0x45, 0xc5, 0x3b,
+ 0x6c, 0xe2, 0xb4, 0x13, 0xc7, 0xa5, 0xf6, 0x7e, 0x43, 0x96, 0xff, 0x6c,
+ 0xe6, 0xba, 0x77, 0xe9, 0x51, 0x74, 0x17, 0xff, 0x6c, 0xbc, 0xb6, 0x73,
+ 0x5d, 0x3b, 0xf4, 0xa8, 0x92, 0xcb, 0xfa, 0x01, 0x87, 0x8e, 0x96, 0x2f,
+ 0xda, 0xe9, 0xdf, 0xa5, 0x45, 0xe4, 0x5c, 0xfb, 0xd6, 0x2d, 0xb2, 0x33,
+ 0xfe, 0xc2, 0xed, 0xc3, 0x7a, 0x88, 0xc7, 0x2b, 0x27, 0x95, 0x57, 0x28,
+ 0x41, 0x64, 0x29, 0x7a, 0x8e, 0x0a, 0x68, 0xc1, 0x8e, 0xff, 0xf9, 0xf5,
+ 0x87, 0x84, 0xf9, 0x66, 0x11, 0x15, 0xc9, 0x75, 0x5e, 0x52, 0x12, 0x2e,
+ 0xf8, 0x6b, 0xdf, 0xfe, 0xd9, 0x3b, 0xcb, 0x67, 0x35, 0xd3, 0xbf, 0x4a,
+ 0x89, 0x64, 0xbe, 0xd8, 0xcd, 0xdc, 0xd8, 0xd6, 0x2d, 0xb1, 0x2c, 0x58,
+ 0x22, 0xc5, 0xbe, 0xb1, 0x5b, 0x19, 0xbd, 0xd8, 0x05, 0xc4, 0x29, 0x7f,
+ 0x98, 0x7f, 0xc6, 0x23, 0x56, 0x2f, 0x7d, 0xcd, 0x58, 0xbe, 0xfb, 0xf8,
+ 0x4b, 0x17, 0xdf, 0x8d, 0xd3, 0xac, 0x5e, 0x03, 0x1d, 0x62, 0xff, 0xd9,
+ 0xf6, 0x91, 0x66, 0x08, 0x2e, 0xb1, 0x7f, 0xec, 0x6d, 0xec, 0x42, 0x96,
+ 0x71, 0x62, 0xff, 0xa0, 0x7b, 0x63, 0xda, 0xc1, 0xac, 0x5e, 0x17, 0x4e,
+ 0xb1, 0x52, 0x4e, 0x43, 0xa3, 0x36, 0x1e, 0xdd, 0x23, 0xd1, 0x31, 0xc7,
+ 0x49, 0x07, 0xc7, 0xe1, 0x9d, 0xdf, 0xbc, 0x27, 0x97, 0x16, 0x2f, 0xb0,
+ 0xc7, 0x02, 0xc5, 0x0c, 0xf3, 0x08, 0xa6, 0xff, 0x81, 0xb5, 0xbd, 0xc8,
+ 0xd0, 0x16, 0x2f, 0xdc, 0x73, 0x7e, 0xcb, 0x17, 0x44, 0xeb, 0x17, 0xfe,
+ 0xc3, 0xf1, 0xe4, 0x1f, 0x23, 0x16, 0x2b, 0x74, 0xf5, 0xfc, 0x31, 0x79,
+ 0xa7, 0xf2, 0xc5, 0x42, 0x3f, 0xf0, 0xf1, 0xa1, 0x01, 0xe2, 0x5b, 0xdf,
+ 0x31, 0xd6, 0x2f, 0xe3, 0xc1, 0x1b, 0x93, 0xac, 0x5c, 0xe7, 0x58, 0xbf,
+ 0xf3, 0xea, 0x51, 0xef, 0xc0, 0x82, 0xeb, 0x15, 0xb0, 0x22, 0x9f, 0x07,
+ 0xbc, 0x5e, 0x21, 0x7b, 0xf0, 0xbc, 0xdf, 0x85, 0x8b, 0xff, 0x7e, 0x3e,
+ 0xc6, 0xfb, 0x8e, 0x05, 0x8b, 0xfe, 0x79, 0x70, 0x5e, 0x8f, 0x71, 0x62,
+ 0xfe, 0x2f, 0x6a, 0x1f, 0xa5, 0x8b, 0x9f, 0x8b, 0x17, 0xff, 0xe7, 0x79,
+ 0x3f, 0xf6, 0xe4, 0xe2, 0xf3, 0x7e, 0x16, 0x2a, 0x73, 0xee, 0x98, 0x5e,
+ 0xe1, 0x69, 0x62, 0xfd, 0x2e, 0x3e, 0xe6, 0x2c, 0x5e, 0x77, 0xe9, 0x51,
+ 0x19, 0x97, 0xfa, 0x3b, 0x94, 0x68, 0xf2, 0x58, 0xbf, 0xff, 0xee, 0x7b,
+ 0xcd, 0xfe, 0xe5, 0xc2, 0x16, 0x1a, 0x6b, 0x3c, 0x96, 0x2d, 0x80, 0x44,
+ 0xff, 0x8d, 0x6f, 0xff, 0xfa, 0x59, 0xb5, 0xfc, 0x28, 0xda, 0x32, 0x8d,
+ 0x69, 0xb0, 0xeb, 0x15, 0x09, 0xc2, 0xf4, 0x57, 0xa8, 0x64, 0xb9, 0x45,
+ 0xfc, 0xd0, 0x79, 0xf0, 0xc5, 0x8b, 0x8a, 0x4b, 0x16, 0x3a, 0xc5, 0xf9,
+ 0xb5, 0xf7, 0xd9, 0xd1, 0xec, 0x1c, 0xbc, 0x31, 0x7b, 0x7d, 0x62, 0xe8,
+ 0xd2, 0xc5, 0x9b, 0xa3, 0x53, 0xbc, 0x4a, 0xff, 0x76, 0x0e, 0x37, 0x8a,
+ 0x16, 0x2f, 0x9b, 0x4f, 0xa5, 0x8b, 0xb9, 0xba, 0xb1, 0x52, 0x37, 0xbe,
+ 0x22, 0xbf, 0xff, 0xa5, 0x9c, 0xf0, 0xa7, 0xeb, 0xed, 0x37, 0xe2, 0x7c,
+ 0x58, 0xac, 0x47, 0x93, 0xb8, 0x88, 0x86, 0xff, 0xee, 0x30, 0xb9, 0x84,
+ 0x29, 0x67, 0x16, 0x2f, 0xff, 0xff, 0x88, 0x52, 0xce, 0x67, 0x84, 0xfe,
+ 0xfe, 0x75, 0xf6, 0x9b, 0xf1, 0x3e, 0x2c, 0x5d, 0x1d, 0xac, 0x5e, 0x62,
+ 0xe9, 0x62, 0x99, 0x16, 0x9c, 0x7f, 0xf0, 0xc5, 0xff, 0xde, 0xe3, 0x78,
+ 0xa0, 0x4f, 0xa3, 0x56, 0x2e, 0x63, 0xac, 0x58, 0x2e, 0xc7, 0xb8, 0x11,
+ 0x16, 0xa7, 0x5f, 0x0a, 0x91, 0x40, 0xd0, 0x30, 0xe9, 0xa1, 0x39, 0x31,
+ 0x26, 0xa3, 0x9d, 0x3c, 0x26, 0xbe, 0xf0, 0x51, 0x8d, 0xf0, 0xbb, 0xd0,
+ 0xf8, 0x14, 0x22, 0xef, 0xf3, 0x99, 0xf6, 0x8d, 0x42, 0xc5, 0xff, 0xff,
+ 0xf9, 0xc7, 0xcf, 0xe1, 0xc9, 0xa7, 0xda, 0x71, 0x13, 0x9b, 0xf2, 0xcf,
+ 0x6b, 0x16, 0x2b, 0x48, 0xb8, 0x23, 0x3b, 0xff, 0xfd, 0xf6, 0xf7, 0x9b,
+ 0x81, 0xcf, 0x13, 0x96, 0x00, 0x5c, 0x58, 0xbf, 0x79, 0x8f, 0x13, 0x2c,
+ 0x5f, 0xd9, 0x1b, 0x63, 0x87, 0x58, 0xac, 0x3d, 0x8e, 0x14, 0xdf, 0xe2,
+ 0x73, 0x3c, 0x4e, 0x6a, 0xc5, 0x48, 0xf5, 0x7c, 0x43, 0x7d, 0xad, 0x3f,
+ 0x16, 0x2f, 0xdf, 0xc2, 0x73, 0xac, 0x5f, 0x77, 0xf8, 0xe2, 0xc5, 0xe9,
+ 0x9c, 0x96, 0x2f, 0xa7, 0xfc, 0x1a, 0xb1, 0x7a, 0x3d, 0xc5, 0x8b, 0xff,
+ 0x61, 0xbc, 0x8c, 0x21, 0xfe, 0x16, 0x2b, 0x87, 0xb6, 0x21, 0xda, 0xda,
+ 0x99, 0x6c, 0x88, 0xf0, 0x9e, 0x62, 0x47, 0x1d, 0xe4, 0x20, 0x2f, 0xc1,
+ 0x09, 0xcc, 0x1a, 0xc5, 0xfe, 0x8d, 0x4f, 0xac, 0x1e, 0x2c, 0x5f, 0xfd,
+ 0xe6, 0xd3, 0x83, 0x6f, 0x72, 0x83, 0xac, 0x5f, 0xfd, 0x07, 0x35, 0xf5,
+ 0x80, 0xe3, 0xf4, 0xb1, 0x7e, 0x28, 0x97, 0x1d, 0x62, 0xa1, 0x31, 0x49,
+ 0x15, 0xb1, 0xa1, 0x24, 0x6f, 0x46, 0xbf, 0x7d, 0x8a, 0x3e, 0xb1, 0x7f,
+ 0xbf, 0x07, 0x09, 0x8f, 0x32, 0xc5, 0x0c, 0xf7, 0x7a, 0x27, 0xb7, 0xd6,
+ 0x2f, 0xff, 0xfe, 0xf3, 0x1f, 0x4d, 0x9d, 0x90, 0xbd, 0x1f, 0xdb, 0xbd,
+ 0xbd, 0x34, 0x2c, 0x56, 0x22, 0x27, 0xc2, 0x57, 0xfd, 0x07, 0xfb, 0xf9,
+ 0xc8, 0x0b, 0x17, 0x83, 0x80, 0x2c, 0x5f, 0xc5, 0x83, 0xfc, 0x18, 0xb1,
+ 0x67, 0x23, 0xcc, 0xde, 0x3d, 0x76, 0x49, 0x62, 0xa1, 0x39, 0x1c, 0x85,
+ 0x63, 0x11, 0x6a, 0x10, 0x87, 0x28, 0xbd, 0xe6, 0x25, 0x8b, 0xf7, 0x1b,
+ 0xda, 0x65, 0x8b, 0xfa, 0x5c, 0xe3, 0x94, 0x96, 0x2f, 0x4f, 0xce, 0x2c,
+ 0x5f, 0x8b, 0xdc, 0x16, 0x96, 0x2b, 0xb4, 0x5d, 0x30, 0xe3, 0x94, 0x11,
+ 0x70, 0x87, 0xee, 0x71, 0xac, 0x5f, 0xa4, 0xe4, 0x2e, 0x96, 0x2b, 0xa3,
+ 0xc0, 0xec, 0x5e, 0xe7, 0xe9, 0x62, 0xe8, 0xdd, 0x58, 0xa9, 0xcd, 0x90,
+ 0x5c, 0x62, 0xff, 0xde, 0x72, 0x06, 0xd0, 0xf3, 0xb3, 0x16, 0x2f, 0xbd,
+ 0xe8, 0x3a, 0xc5, 0xf4, 0xbc, 0xd3, 0xac, 0x56, 0x22, 0x2c, 0xd4, 0x47,
+ 0x23, 0xbf, 0xfe, 0x83, 0x8a, 0x27, 0xdb, 0xac, 0x6f, 0xc0, 0xd6, 0x2f,
+ 0x9c, 0x83, 0xe2, 0xc5, 0xe2, 0xce, 0x96, 0x2f, 0xf9, 0xbc, 0xc7, 0x9b,
+ 0x8c, 0x4b, 0x17, 0xff, 0xf6, 0xb3, 0xdc, 0xfb, 0xc8, 0x51, 0x9e, 0x8e,
+ 0xe4, 0xb1, 0x5d, 0x22, 0x57, 0x47, 0x37, 0xfe, 0x86, 0xd7, 0xbd, 0x91,
+ 0xa0, 0x2c, 0x5b, 0xd0, 0x7c, 0x53, 0x12, 0x5f, 0xba, 0x6d, 0x1e, 0x4b,
+ 0x17, 0xf8, 0xf9, 0xa0, 0x10, 0x80, 0xb1, 0x69, 0x2c, 0x54, 0x93, 0xcf,
+ 0xc2, 0x36, 0x8c, 0x53, 0xe5, 0x0e, 0x54, 0x19, 0xa5, 0xf8, 0x11, 0xe8,
+ 0x1a, 0xc5, 0x42, 0xbd, 0xbc, 0x56, 0x68, 0x58, 0xfc, 0xbd, 0xe5, 0x10,
+ 0x89, 0x72, 0xff, 0x78, 0x9f, 0x6f, 0x5d, 0x62, 0xc5, 0xff, 0xf0, 0xbd,
+ 0xce, 0xe5, 0x04, 0x0e, 0x6d, 0x11, 0x2c, 0x5e, 0x8f, 0x42, 0xc5, 0x0c,
+ 0xfc, 0x37, 0xaa, 0x5f, 0xf7, 0xa3, 0x4e, 0x45, 0x86, 0xac, 0x5e, 0x17,
+ 0x84, 0xb1, 0x4c, 0x7a, 0xc7, 0x38, 0xbf, 0xff, 0x85, 0x26, 0xe4, 0x1f,
+ 0xaf, 0xb4, 0xdf, 0x89, 0xf1, 0x62, 0xf7, 0xf0, 0x96, 0x2b, 0xb4, 0xef,
+ 0x1a, 0x14, 0xff, 0x7a, 0x22, 0x11, 0x2f, 0x5d, 0xf9, 0x96, 0x2f, 0xb2,
+ 0x6c, 0x99, 0x62, 0xfd, 0xa1, 0x7b, 0x27, 0x58, 0xbe, 0xcd, 0x0e, 0x16,
+ 0x2d, 0xcd, 0xa7, 0xe1, 0x04, 0x84, 0x55, 0x6f, 0xac, 0x57, 0x67, 0x8e,
+ 0xe6, 0xb7, 0xc4, 0x27, 0x0d, 0x62, 0xec, 0x25, 0x8b, 0x44, 0xe6, 0xe6,
+ 0x44, 0x74, 0xc9, 0xa9, 0x3c, 0x34, 0x00, 0xb7, 0x7b, 0x33, 0xa5, 0x8b,
+ 0xfe, 0xf7, 0x33, 0x40, 0x21, 0x01, 0x62, 0xff, 0xe8, 0xf7, 0x3f, 0x0d,
+ 0xee, 0x44, 0xeb, 0x17, 0xec, 0xd4, 0x4d, 0xc5, 0x8a, 0xd1, 0xf7, 0x7d,
+ 0x16, 0xff, 0xfe, 0x6e, 0x16, 0x4f, 0x1d, 0x7d, 0xa6, 0xfc, 0x4f, 0x8b,
+ 0x17, 0x9f, 0xf0, 0xb1, 0x52, 0x3f, 0x9f, 0x2e, 0xdf, 0x7b, 0xe2, 0xdc,
+ 0x58, 0xbf, 0xd9, 0x1a, 0x79, 0x37, 0xd6, 0x2f, 0xf3, 0x19, 0xc8, 0xfb,
+ 0xee, 0xac, 0x56, 0x8f, 0xa7, 0xc6, 0x57, 0xef, 0x7f, 0xbc, 0x08, 0xb1,
+ 0x43, 0x4e, 0x6f, 0xb8, 0x4d, 0xb1, 0x11, 0xe1, 0x21, 0xf2, 0x2b, 0xf7,
+ 0x1c, 0xdf, 0xb2, 0xc5, 0xff, 0x6e, 0x8f, 0xe2, 0xe7, 0x72, 0x75, 0x8b,
+ 0x9b, 0xf8, 0x7d, 0x02, 0x29, 0xa8, 0x56, 0x59, 0x92, 0x90, 0xde, 0x17,
+ 0xb6, 0xc5, 0x8b, 0xfa, 0x51, 0x28, 0x3c, 0x96, 0x2a, 0x73, 0x7e, 0xc2,
+ 0x37, 0x83, 0xcd, 0x89, 0x62, 0xff, 0xed, 0x40, 0x3e, 0xd1, 0xa0, 0x1e,
+ 0x4b, 0x17, 0xd3, 0x7d, 0x80, 0xb1, 0x7d, 0x1f, 0x80, 0x2c, 0x54, 0x22,
+ 0x2c, 0xd4, 0x5d, 0xc2, 0x4b, 0xff, 0xf1, 0x39, 0x9e, 0xcf, 0xed, 0x0a,
+ 0x05, 0x36, 0x30, 0xb4, 0x15, 0x0a, 0x2c, 0x5f, 0xfe, 0x10, 0x0e, 0xc5,
+ 0x80, 0x2c, 0x79, 0x96, 0x2f, 0xf3, 0x7d, 0xa0, 0xa6, 0x12, 0xc5, 0xe8,
+ 0xf8, 0x55, 0x62, 0xfd, 0x98, 0x5d, 0xf9, 0x62, 0xff, 0x85, 0xa7, 0xe6,
+ 0xdf, 0x4e, 0x62, 0xc5, 0x9b, 0x47, 0xcf, 0xe2, 0x8a, 0x84, 0x71, 0x31,
+ 0x9b, 0xc2, 0x22, 0xfa, 0x7f, 0xe7, 0x96, 0x2f, 0xfa, 0x4e, 0x40, 0xda,
+ 0x66, 0x7d, 0x62, 0xfd, 0x37, 0x38, 0xd3, 0x2c, 0x5f, 0xf0, 0xf5, 0x82,
+ 0xfc, 0x1f, 0x16, 0x2b, 0x11, 0x40, 0xc7, 0x82, 0x2b, 0xbf, 0xfd, 0xbf,
+ 0x36, 0x87, 0xe6, 0xd3, 0x4e, 0xe7, 0x58, 0xbf, 0xc4, 0x00, 0xff, 0xf7,
+ 0x9d, 0x62, 0xb1, 0x10, 0xcc, 0xa1, 0x7d, 0xb9, 0x9a, 0x85, 0x8b, 0xff,
+ 0xfb, 0x73, 0x36, 0x96, 0x4e, 0x1c, 0xb6, 0xf3, 0x8c, 0x67, 0x16, 0x2d,
+ 0x93, 0xa2, 0x2c, 0x04, 0xb5, 0xf4, 0x6a, 0x94, 0x2b, 0x2a, 0x17, 0x52,
+ 0x30, 0x85, 0xa1, 0x5d, 0x31, 0x9e, 0x9d, 0x7f, 0x19, 0x5b, 0x99, 0x72,
+ 0x18, 0x9e, 0x8e, 0x26, 0xff, 0xf8, 0xb5, 0x1f, 0x76, 0xf4, 0x7c, 0xbb,
+ 0x65, 0x8b, 0xff, 0x7e, 0x34, 0x0d, 0x6a, 0x0f, 0xc5, 0x8b, 0xf3, 0xf0,
+ 0x9a, 0x16, 0x2f, 0xfe, 0x6d, 0x0f, 0xe2, 0xd6, 0x75, 0xfc, 0x58, 0xbf,
+ 0x36, 0x9c, 0x23, 0x2c, 0x54, 0x8f, 0xbf, 0xa4, 0x6b, 0xfa, 0x77, 0x9c,
+ 0x85, 0xe5, 0x8b, 0x88, 0x0b, 0x17, 0xde, 0x13, 0xf9, 0x62, 0xf0, 0x9f,
+ 0xcb, 0x15, 0xb4, 0xf0, 0x3c, 0x47, 0x7b, 0x7e, 0x69, 0x62, 0xa0, 0xf0,
+ 0xf0, 0x92, 0xfe, 0x70, 0x46, 0xfc, 0x25, 0x8a, 0x85, 0x4b, 0xd8, 0x9c,
+ 0x6a, 0x07, 0x70, 0x95, 0x62, 0x37, 0x30, 0x28, 0x4d, 0x70, 0x82, 0xfb,
+ 0x8d, 0xe6, 0x58, 0xb8, 0x43, 0x58, 0xad, 0x88, 0xdd, 0x08, 0x8a, 0xfe,
+ 0x99, 0xbf, 0xac, 0x3a, 0xc5, 0xf0, 0x7c, 0x8c, 0x58, 0xb9, 0x8c, 0x58,
+ 0xb8, 0x26, 0x2c, 0x53, 0xa2, 0x0c, 0x05, 0xfc, 0x23, 0xf0, 0xc5, 0xfd,
+ 0xc8, 0xf7, 0x3e, 0xcb, 0x17, 0xe2, 0xc3, 0xeb, 0x16, 0x2f, 0xa7, 0x93,
+ 0x8d, 0x62, 0xf6, 0xfc, 0x1a, 0xc5, 0xcd, 0xf5, 0x8a, 0xd1, 0xb6, 0xf8,
+ 0xfd, 0x62, 0x34, 0x0e, 0x5c, 0xe4, 0xe2, 0x5a, 0xbf, 0xdd, 0x7f, 0x3b,
+ 0xf0, 0x67, 0x58, 0xbf, 0x7e, 0x34, 0x79, 0x2c, 0x5e, 0x1e, 0x79, 0x62,
+ 0xff, 0x61, 0x6d, 0xfc, 0x66, 0xea, 0xc5, 0xff, 0x9b, 0xdc, 0xc1, 0xcc,
+ 0x50, 0x35, 0x8b, 0xe0, 0x37, 0x72, 0x58, 0xbf, 0xd0, 0x5e, 0x69, 0xca,
+ 0x16, 0x2f, 0xff, 0x36, 0x9a, 0x78, 0x2c, 0xfe, 0x85, 0xbd, 0x62, 0xa1,
+ 0x39, 0x69, 0x1c, 0x0c, 0xa4, 0xe3, 0xbf, 0x37, 0x01, 0xf9, 0x12, 0x78,
+ 0xca, 0xff, 0xf4, 0x17, 0x4f, 0xe7, 0x34, 0x39, 0xe2, 0x75, 0x8b, 0xff,
+ 0x30, 0xc5, 0xee, 0x3f, 0x9c, 0xd5, 0x8b, 0xfb, 0x0c, 0xee, 0x5c, 0xda,
+ 0x6a, 0x23, 0x9d, 0x3a, 0xff, 0xfe, 0xc2, 0xc3, 0x7e, 0xf3, 0x7d, 0xcd,
+ 0xcd, 0x67, 0x96, 0x2f, 0xfe, 0x0e, 0x3b, 0x0c, 0x8b, 0x1b, 0xbf, 0x2c,
+ 0x53, 0x23, 0xb7, 0xe9, 0x4e, 0xb9, 0x5b, 0x1b, 0xaf, 0xbf, 0xd8, 0x1b,
+ 0xe2, 0x3c, 0x89, 0xe1, 0x9d, 0x28, 0xc8, 0x07, 0x0e, 0x6c, 0x9f, 0x4b,
+ 0x36, 0x38, 0xce, 0x88, 0xbb, 0x8c, 0x45, 0xa3, 0x4f, 0x9a, 0x37, 0x2d,
+ 0x4a, 0x38, 0x3c, 0x61, 0x9f, 0x9c, 0x63, 0x79, 0x43, 0xa0, 0x8e, 0x84,
+ 0x2e, 0x68, 0x52, 0xd2, 0x79, 0x3b, 0x85, 0xe9, 0x5e, 0x42, 0x85, 0xa6,
+ 0xf8, 0x54, 0xee, 0x46, 0x18, 0x1c, 0x7a, 0x21, 0x23, 0xeb, 0xbf, 0xef,
+ 0x40, 0xf5, 0xa8, 0x3f, 0x16, 0x2f, 0xf4, 0xb0, 0x81, 0x98, 0x35, 0x8b,
+ 0xfd, 0x05, 0xe2, 0x83, 0xf1, 0x62, 0xa4, 0x7c, 0x83, 0x32, 0xb8, 0xde,
+ 0x96, 0x2f, 0xe3, 0xca, 0x23, 0x8c, 0xb1, 0x73, 0x81, 0x62, 0xa0, 0xf1,
+ 0x1c, 0xb6, 0xf8, 0x6e, 0xfd, 0xac, 0x5f, 0xcd, 0xdb, 0x75, 0x01, 0xac,
+ 0x53, 0x9e, 0x99, 0x11, 0xde, 0x60, 0xce, 0xb1, 0x7f, 0xe9, 0x30, 0xc3,
+ 0xf7, 0x7d, 0x31, 0xd6, 0x2f, 0xd9, 0xfe, 0xdf, 0x75, 0x62, 0xff, 0xf7,
+ 0xf0, 0x89, 0xfd, 0x05, 0xed, 0xcc, 0x58, 0xa9, 0x91, 0x72, 0x48, 0x7e,
+ 0x2c, 0xb9, 0xf7, 0xac, 0x5f, 0xe9, 0xf3, 0xd0, 0x4c, 0x05, 0x8a, 0xe8,
+ 0xf3, 0x18, 0x66, 0xff, 0xe9, 0xf3, 0xd0, 0x4c, 0x0c, 0xef, 0xcb, 0x17,
+ 0xfa, 0x69, 0x3e, 0xa7, 0xf8, 0x96, 0x2d, 0x32, 0xc5, 0x2c, 0x5f, 0x39,
+ 0x03, 0xd0, 0x5f, 0xe0, 0x9d, 0x42, 0x33, 0xce, 0x8b, 0xb8, 0xad, 0x77,
+ 0xb6, 0x61, 0x70, 0x9f, 0x21, 0x3c, 0x72, 0x2f, 0xaf, 0x3b, 0x98, 0x08,
+ 0x39, 0x0d, 0x7f, 0x3e, 0x07, 0x0f, 0x1b, 0xff, 0xff, 0x85, 0xdc, 0xb6,
+ 0x5c, 0xbd, 0x87, 0xe0, 0xff, 0x1a, 0x1b, 0xb9, 0x8b, 0x17, 0xfa, 0x0d,
+ 0xee, 0x5e, 0x83, 0x16, 0x2f, 0xd0, 0x66, 0xa0, 0xeb, 0x17, 0xd0, 0x66,
+ 0xce, 0x48, 0xf8, 0x08, 0xde, 0xb6, 0x57, 0xf5, 0xf2, 0x78, 0xa0, 0xa1,
+ 0x3b, 0xe8, 0x6b, 0xdf, 0xfe, 0xd9, 0x3b, 0xcb, 0x67, 0x35, 0xd3, 0xbf,
+ 0x4a, 0x89, 0xa4, 0xbf, 0xfd, 0xb2, 0x77, 0x96, 0xce, 0x6b, 0xa7, 0x7e,
+ 0x95, 0x13, 0x89, 0x78, 0x05, 0x0b, 0x17, 0xe9, 0x31, 0x01, 0x96, 0x2f,
+ 0xd2, 0xcf, 0x4a, 0x4b, 0x17, 0xfb, 0x7c, 0x7f, 0x69, 0x44, 0x96, 0x2f,
+ 0xfc, 0xf2, 0xd9, 0xcd, 0x74, 0xef, 0xd2, 0xa2, 0x81, 0x2f, 0xff, 0x34,
+ 0x1d, 0xc7, 0xa8, 0xf7, 0xf0, 0x6b, 0x17, 0xdc, 0x2e, 0xe4, 0xb1, 0x6d,
+ 0x98, 0x4d, 0x83, 0x07, 0x3b, 0x27, 0x62, 0x93, 0x9b, 0xfd, 0x43, 0xc9,
+ 0x37, 0x6c, 0x7b, 0x12, 0xc5, 0xef, 0xb1, 0xd6, 0x2f, 0xba, 0x77, 0xe9,
+ 0x51, 0x70, 0x17, 0xf8, 0x7f, 0x8d, 0xcc, 0xd4, 0x2c, 0x56, 0x8f, 0x9c,
+ 0x8c, 0x6e, 0xef, 0x8b, 0x17, 0xc6, 0xf4, 0xe3, 0x58, 0xba, 0x03, 0x58,
+ 0xbf, 0x8b, 0x3d, 0xd3, 0x71, 0x62, 0xe8, 0x65, 0x8b, 0xc2, 0x79, 0x2c,
+ 0x5a, 0x4b, 0x41, 0x5f, 0x36, 0x64, 0x3b, 0x7f, 0x8a, 0x50, 0xc3, 0xc3,
+ 0xac, 0x56, 0xc4, 0x9f, 0x30, 0xc8, 0xb2, 0x10, 0x9d, 0x90, 0xb0, 0xce,
+ 0x89, 0x4e, 0x31, 0xf2, 0xef, 0x24, 0x88, 0x82, 0xfd, 0x2d, 0x93, 0x42,
+ 0xa6, 0xac, 0x5f, 0x98, 0x7f, 0x63, 0x56, 0x2e, 0xcd, 0xeb, 0x17, 0x8d,
+ 0xd9, 0x7e, 0x8f, 0x0b, 0xc5, 0x35, 0xb2, 0x9a, 0x14, 0x42, 0x55, 0x9d,
+ 0x6f, 0xf0, 0x53, 0x63, 0x0a, 0xc8, 0x12, 0x65, 0x8b, 0xf8, 0xf1, 0xe1,
+ 0x4c, 0xeb, 0x17, 0xbb, 0x97, 0x16, 0x29, 0x62, 0xce, 0xe6, 0xac, 0x03,
+ 0xf7, 0xe9, 0xa5, 0x05, 0x25, 0x8a, 0x58, 0xac, 0x36, 0xa4, 0x53, 0x7e,
+ 0xc3, 0x4b, 0x00, 0xb1, 0x60, 0x2c, 0x54, 0x8d, 0xd1, 0x14, 0x5e, 0x06,
+ 0x18, 0xb1, 0x7c, 0x51, 0x9f, 0x58, 0xa8, 0x37, 0xf3, 0x8f, 0x5c, 0xdb,
+ 0x3b, 0x0d, 0x3c, 0xf8, 0x42, 0xd2, 0xd1, 0x2d, 0x79, 0x64, 0x35, 0xfb,
+ 0xdf, 0x6e, 0x96, 0x2f, 0xfb, 0x3d, 0xdf, 0x4d, 0xcf, 0xb2, 0xc5, 0x6e,
+ 0x9e, 0xc9, 0x0f, 0x5f, 0xb5, 0xd3, 0xbf, 0x4a, 0x89, 0x24, 0xba, 0x5b,
+ 0x30, 0x7b, 0x78, 0x49, 0x5f, 0x4d, 0x39, 0xe3, 0x1f, 0xbf, 0xa4, 0xfa,
+ 0x9f, 0xe2, 0x58, 0xbf, 0x72, 0x00, 0x1c, 0xeb, 0x17, 0xe8, 0x37, 0x64,
+ 0x79, 0x31, 0xed, 0xf0, 0xc2, 0xff, 0x46, 0x6c, 0x9d, 0xdc, 0x22, 0xc5,
+ 0x6c, 0xa3, 0xf9, 0xa1, 0x08, 0x48, 0x77, 0xec, 0x30, 0x02, 0xe2, 0xc5,
+ 0xc6, 0x01, 0x62, 0xff, 0xdd, 0x7e, 0x35, 0x9e, 0x28, 0x3a, 0xc5, 0xfe,
+ 0x7f, 0x16, 0x4e, 0xe4, 0xb1, 0x7e, 0x89, 0x8a, 0x06, 0xb1, 0x71, 0xa6,
+ 0x2c, 0x5e, 0x2e, 0xe1, 0x62, 0xfe, 0x93, 0xea, 0x71, 0xc2, 0xc5, 0xfd,
+ 0x84, 0xfd, 0xcb, 0x8b, 0x17, 0xff, 0xe1, 0x13, 0x9b, 0xe3, 0x60, 0xa5,
+ 0x9f, 0x63, 0xac, 0x5c, 0xfd, 0xac, 0x5f, 0xce, 0x77, 0xfb, 0x4c, 0xb1,
+ 0x5a, 0x3c, 0x6f, 0x0c, 0x5e, 0x6d, 0x49, 0x62, 0xff, 0xfd, 0x9d, 0x47,
+ 0xe0, 0xfd, 0x7d, 0xbd, 0x98, 0x75, 0x8b, 0xf1, 0xf5, 0x83, 0xf2, 0xc5,
+ 0xf0, 0x21, 0xa6, 0x58, 0xbf, 0xbb, 0x0f, 0xc5, 0x00, 0x58, 0xbf, 0xbb,
+ 0xf4, 0x16, 0x71, 0x62, 0xa0, 0xf7, 0x98, 0xc2, 0xa1, 0x19, 0x40, 0x29,
+ 0x14, 0x20, 0x6f, 0xc1, 0x3f, 0x04, 0x6a, 0xc5, 0xf9, 0xc8, 0x85, 0x3a,
+ 0xc5, 0x86, 0xb1, 0x7f, 0x4e, 0x59, 0xbc, 0x50, 0xb1, 0x53, 0x9e, 0x13,
+ 0x89, 0x5c, 0xfb, 0x33, 0xae, 0x2b, 0x0c, 0xab, 0x06, 0x4d, 0x3f, 0xe8,
+ 0xcb, 0xb2, 0x86, 0x1a, 0x98, 0x77, 0x45, 0xe7, 0x2e, 0x78, 0x4e, 0x00,
+ 0x88, 0x87, 0x79, 0x19, 0x07, 0x8d, 0x0c, 0x2b, 0xdc, 0x6a, 0xbf, 0xfa,
+ 0x7d, 0x9e, 0xc2, 0x61, 0x67, 0xdf, 0x8b, 0x15, 0x3b, 0xe4, 0x15, 0x4a,
+ 0xdb, 0xfa, 0xf4, 0xa7, 0x32, 0xf8, 0x23, 0xbf, 0xe4, 0xb9, 0x4f, 0x4e,
+ 0x29, 0x6f, 0x9c, 0x8c, 0x09, 0x18, 0x3d, 0xfb, 0x5e, 0x21, 0x79, 0x62,
+ 0xff, 0xc6, 0xbe, 0xce, 0x6b, 0xa7, 0x7e, 0x95, 0x16, 0xa1, 0x7d, 0xc8,
+ 0xf7, 0x16, 0x2f, 0xfc, 0xf2, 0xd9, 0xcd, 0x74, 0xef, 0xd2, 0xa2, 0x55,
+ 0x2e, 0x63, 0x16, 0x29, 0x62, 0xb1, 0x31, 0x13, 0x4a, 0x7b, 0x51, 0x39,
+ 0x1f, 0x94, 0x02, 0x0c, 0x5f, 0xff, 0xff, 0xff, 0x81, 0xb7, 0x6f, 0xf7,
+ 0x36, 0x77, 0xec, 0x31, 0x4f, 0x3b, 0xee, 0xee, 0xe4, 0x4b, 0xe1, 0x7e,
+ 0xda, 0x23, 0x63, 0x0b, 0x36, 0xed, 0xfe, 0xe2, 0xc5, 0x6c, 0xa6, 0x7e,
+ 0x14, 0x5b, 0xbf, 0xb3, 0x5d, 0x3b, 0xf4, 0xa8, 0x8a, 0x4b, 0xff, 0x3b,
+ 0x9f, 0x34, 0x02, 0x10, 0x16, 0x2f, 0xfb, 0xdc, 0xcd, 0x00, 0x84, 0x05,
+ 0x8b, 0x89, 0xd6, 0x2a, 0x0f, 0x40, 0x67, 0x57, 0x71, 0xd6, 0x2f, 0x72,
+ 0x1d, 0x62, 0xb0, 0xd9, 0xb0, 0xbd, 0xfe, 0x27, 0x07, 0x3d, 0x9d, 0x2c,
+ 0x5f, 0xb0, 0x73, 0xe1, 0x8b, 0x17, 0x1f, 0x67, 0xe9, 0xaf, 0x94, 0x23,
+ 0xb8, 0xa9, 0xe1, 0xfd, 0xe6, 0x95, 0xb2, 0x9f, 0xdb, 0xc7, 0x37, 0x7e,
+ 0xd7, 0x4e, 0xfd, 0x2a, 0x23, 0x42, 0xfe, 0x26, 0x1e, 0x9a, 0x75, 0x8b,
+ 0x6c, 0xe1, 0xf2, 0xb1, 0xbd, 0xff, 0x80, 0xd1, 0xed, 0x9f, 0xe3, 0x7d,
+ 0x62, 0xf0, 0x5b, 0xee, 0x6c, 0x6b, 0x17, 0xc1, 0x4d, 0x84, 0x16, 0xe1,
+ 0x6e, 0xb1, 0x7c, 0xdf, 0x63, 0xac, 0x5c, 0x2f, 0xac, 0x5e, 0xd4, 0x4c,
+ 0xb1, 0x7e, 0xfb, 0xcc, 0xc7, 0x58, 0xa6, 0x3c, 0x73, 0x8f, 0x5f, 0xf8,
+ 0x78, 0x76, 0xd6, 0x72, 0x68, 0x58, 0xbf, 0xde, 0xf3, 0x3e, 0xf8, 0xf2,
+ 0xc5, 0xff, 0xfe, 0x17, 0x3f, 0x83, 0x0c, 0x3e, 0x30, 0x7e, 0x6e, 0x4c,
+ 0x1a, 0xc5, 0x42, 0x27, 0x5c, 0xd6, 0xff, 0xf4, 0xcc, 0xdf, 0x9b, 0x3d,
+ 0x1e, 0x81, 0xac, 0x5e, 0x67, 0x31, 0x22, 0xff, 0xa3, 0xf1, 0x3e, 0xa3,
+ 0x06, 0xb1, 0x7f, 0xe8, 0x8d, 0xf0, 0x51, 0x34, 0x4c, 0xb1, 0x7e, 0x9b,
+ 0x8f, 0x9e, 0x58, 0xbf, 0xda, 0xd4, 0x77, 0xcf, 0x8d, 0x62, 0xdf, 0x83,
+ 0xdf, 0x62, 0x9b, 0xff, 0xe8, 0xfc, 0x4d, 0xc1, 0x78, 0x42, 0x9a, 0x37,
+ 0xac, 0x54, 0x2a, 0xd9, 0x62, 0x1d, 0xd8, 0x6e, 0x4c, 0x42, 0x74, 0xbf,
+ 0x8e, 0x91, 0xcf, 0xa1, 0x3f, 0xbc, 0x9a, 0xfe, 0x6e, 0x4d, 0x9a, 0x85,
+ 0x8b, 0xee, 0x9d, 0xfa, 0x54, 0x53, 0xe5, 0xff, 0xe6, 0xd7, 0xdf, 0xdc,
+ 0x7e, 0xdc, 0x80, 0xb1, 0x77, 0xa1, 0x62, 0xb4, 0x89, 0x2f, 0x98, 0xf9,
+ 0x2a, 0xf8, 0xce, 0xa6, 0x0a, 0xac, 0x5f, 0xff, 0x7d, 0xbd, 0xcc, 0xdf,
+ 0xf6, 0xdc, 0xcd, 0x1a, 0xb1, 0x7f, 0xf3, 0x6c, 0xff, 0x3e, 0xfb, 0xdb,
+ 0x9d, 0xac, 0x5f, 0xe6, 0xf3, 0x7b, 0xe2, 0xf2, 0xc5, 0xf0, 0x04, 0x2d,
+ 0x2c, 0x5f, 0x41, 0xf4, 0xeb, 0x17, 0xfa, 0x3d, 0xf7, 0x9b, 0x6e, 0x2c,
+ 0x5f, 0xfd, 0x11, 0xa8, 0xe3, 0x6b, 0x4d, 0xc5, 0x8a, 0x98, 0xfe, 0x7c,
+ 0x6d, 0x53, 0x26, 0xc1, 0xa4, 0xa0, 0x1a, 0x11, 0x27, 0xa1, 0x37, 0x7f,
+ 0xcf, 0x26, 0x1f, 0xe2, 0x5c, 0x58, 0xbf, 0x0b, 0xde, 0x8d, 0xeb, 0x17,
+ 0xff, 0x44, 0xd3, 0x30, 0x22, 0x69, 0xb0, 0x0b, 0x16, 0x8d, 0x1f, 0x99,
+ 0x15, 0xdf, 0x6f, 0x6e, 0x76, 0xb1, 0x6f, 0xb1, 0xe6, 0x39, 0x35, 0xdf,
+ 0x12, 0xc5, 0x61, 0xbe, 0x11, 0x35, 0xfb, 0x3e, 0xc5, 0xe5, 0x8b, 0xff,
+ 0x8e, 0x42, 0xfb, 0x6b, 0x39, 0x34, 0x2c, 0x5f, 0xff, 0xff, 0xa3, 0xcc,
+ 0x4f, 0xce, 0x67, 0xbe, 0xe7, 0xfe, 0x14, 0x47, 0x1c, 0x5b, 0xd6, 0x2f,
+ 0x9e, 0x66, 0xfa, 0xc5, 0xff, 0xed, 0x63, 0x4d, 0xc1, 0x47, 0x65, 0x1e,
+ 0x58, 0xbf, 0x6f, 0x16, 0xec, 0x01, 0x62, 0xa4, 0x9c, 0x4b, 0x13, 0xe9,
+ 0x14, 0xf0, 0x81, 0xf1, 0x18, 0x92, 0xef, 0x78, 0x5a, 0x58, 0xbf, 0x84,
+ 0x58, 0x01, 0x71, 0x62, 0xbb, 0x3c, 0xce, 0x0f, 0x5f, 0xfb, 0xda, 0x14,
+ 0xdc, 0xe9, 0xe6, 0xe2, 0xc5, 0x61, 0xf3, 0x88, 0x8e, 0xe0, 0x06, 0xb1,
+ 0x7f, 0x14, 0x78, 0xa3, 0xcb, 0x15, 0x23, 0xc5, 0x71, 0x9b, 0xd3, 0x37,
+ 0x16, 0x2f, 0x9a, 0x35, 0x8b, 0x17, 0xe8, 0xf7, 0x79, 0xe8, 0x37, 0xff,
+ 0x1e, 0xbf, 0xf4, 0xc2, 0x29, 0xf9, 0xd3, 0xcd, 0xc5, 0x8a, 0x84, 0x40,
+ 0xe1, 0xed, 0xcf, 0xc5, 0x8b, 0xf0, 0xa6, 0x99, 0xcd, 0x58, 0xbf, 0xef,
+ 0x47, 0x6f, 0x36, 0xa3, 0x7a, 0xc5, 0x6e, 0xa2, 0x03, 0x82, 0xfe, 0x2c,
+ 0xa5, 0x8b, 0xdf, 0x6d, 0x2c, 0x56, 0xc4, 0x6a, 0x44, 0x19, 0x6c, 0x58,
+ 0xb6, 0xce, 0xc6, 0xcd, 0xda, 0x0a, 0x16, 0x85, 0x4f, 0x36, 0x02, 0x28,
+ 0x96, 0x71, 0x3c, 0x23, 0x72, 0x18, 0x06, 0x98, 0x74, 0x56, 0xd1, 0xdb,
+ 0x1d, 0x43, 0xf1, 0x9b, 0x3c, 0x75, 0x25, 0x18, 0x7f, 0x19, 0xbd, 0x0e,
+ 0x11, 0x42, 0x87, 0x71, 0x70, 0x21, 0x35, 0xff, 0xed, 0x93, 0xbc, 0xb6,
+ 0x73, 0x5d, 0x3b, 0xf4, 0xa8, 0x9a, 0x8b, 0xff, 0xa4, 0x51, 0xb3, 0x13,
+ 0x61, 0x0b, 0x16, 0x2f, 0xec, 0xd7, 0x4e, 0xfd, 0x2a, 0x2b, 0xb2, 0xff,
+ 0xf6, 0x04, 0x6f, 0x34, 0xb6, 0x94, 0x7b, 0x8b, 0x17, 0xff, 0x41, 0xc3,
+ 0xf3, 0x10, 0xa5, 0x9c, 0x58, 0xbc, 0x44, 0x35, 0x8b, 0xc7, 0x8f, 0xac,
+ 0x52, 0xc5, 0xc6, 0x6c, 0xfd, 0x1a, 0xe0, 0x4d, 0x24, 0x51, 0x0e, 0x18,
+ 0x3b, 0x5b, 0x29, 0xb6, 0xb4, 0x62, 0x77, 0x01, 0x96, 0x2c, 0x35, 0x8b,
+ 0xa0, 0xeb, 0x15, 0xf3, 0x53, 0xc1, 0x2b, 0x6e, 0x2c, 0x58, 0x96, 0x2a,
+ 0x73, 0x4c, 0x71, 0x5b, 0xa7, 0x85, 0x8b, 0xee, 0x9d, 0xfa, 0x54, 0x57,
+ 0xc5, 0xe3, 0x0c, 0x31, 0x22, 0xc4, 0x91, 0xb2, 0x68, 0x6b, 0x47, 0xec,
+ 0x75, 0x2b, 0xfd, 0xfc, 0x35, 0xe3, 0xb0, 0x8b, 0x17, 0xa5, 0x1d, 0xac,
+ 0x5f, 0x76, 0x08, 0x25, 0x8b, 0xbe, 0xcb, 0x16, 0xc8, 0x37, 0x5e, 0x23,
+ 0xb8, 0x5c, 0x58, 0xbb, 0x3e, 0xb1, 0x43, 0x35, 0xf3, 0x0c, 0x5c, 0xfb,
+ 0xd6, 0x2f, 0xf1, 0x8f, 0xee, 0x46, 0x4e, 0xb1, 0x7b, 0x90, 0x05, 0x8a,
+ 0xf9, 0xe9, 0x78, 0xd6, 0xd0, 0xb1, 0x7c, 0x4f, 0xdf, 0x16, 0x2b, 0x0f,
+ 0x5b, 0x84, 0x5e, 0x11, 0xbc, 0x66, 0x69, 0x62, 0xde, 0x58, 0xbf, 0xe6,
+ 0xd6, 0x4e, 0xd2, 0xc1, 0xac, 0x5f, 0xed, 0x03, 0xdc, 0x70, 0x62, 0xc5,
+ 0x32, 0x27, 0x74, 0x3c, 0xe2, 0x42, 0x39, 0xbd, 0xf2, 0x02, 0xc5, 0xf0,
+ 0x4f, 0x88, 0x35, 0x8b, 0xd3, 0x64, 0xcb, 0x16, 0x65, 0x8a, 0xec, 0xf5,
+ 0xe6, 0x27, 0x38, 0xfd, 0xb4, 0xb1, 0x4b, 0x14, 0xc5, 0xf6, 0x84, 0xa9,
+ 0x62, 0xcc, 0xb1, 0x69, 0xcd, 0x2f, 0x7e, 0x19, 0x6d, 0xeb, 0x15, 0xf3,
+ 0xf8, 0x73, 0xc1, 0x14, 0x5f, 0x61, 0x44, 0x96, 0x2d, 0xb3, 0xb0, 0xd7,
+ 0x6b, 0xe1, 0x02, 0x74, 0x79, 0x11, 0x64, 0x23, 0xba, 0x22, 0x98, 0xdf,
+ 0x4b, 0x0e, 0xa8, 0x02, 0x22, 0x86, 0x0f, 0x21, 0x97, 0xe3, 0xb1, 0x3a,
+ 0x6e, 0x43, 0x1c, 0x32, 0xeb, 0xff, 0xdb, 0x27, 0x79, 0x6c, 0xe6, 0xba,
+ 0x77, 0xe9, 0x51, 0x3d, 0x96, 0x0b, 0xac, 0x5f, 0xf0, 0xdf, 0xa8, 0xe8,
+ 0x44, 0x35, 0x8b, 0xff, 0xe6, 0x97, 0x37, 0x7e, 0x2e, 0xb2, 0x7d, 0xa3,
+ 0xd2, 0xc5, 0xf4, 0x04, 0x7e, 0xd6, 0x2f, 0x31, 0x01, 0x62, 0xa7, 0x46,
+ 0xac, 0x8e, 0xfe, 0xb3, 0xbc, 0x96, 0xff, 0xe1, 0x6a, 0x6d, 0x34, 0xee,
+ 0x76, 0xe2, 0xc5, 0xf9, 0x87, 0x1a, 0xe2, 0xc5, 0xff, 0xd9, 0xfc, 0xf7,
+ 0x7d, 0x36, 0xbf, 0x8b, 0x17, 0xed, 0x74, 0xef, 0xd2, 0xa2, 0xe1, 0x2f,
+ 0x8e, 0x2f, 0x71, 0x62, 0xff, 0x7d, 0xa4, 0x20, 0x44, 0xcb, 0x17, 0xfe,
+ 0x6d, 0xef, 0x37, 0x1b, 0x50, 0x75, 0x8b, 0xfa, 0x1b, 0x5a, 0x63, 0x16,
+ 0x2f, 0x87, 0xfc, 0x99, 0x62, 0xdb, 0x21, 0x55, 0x60, 0x71, 0x0e, 0xb9,
+ 0xd0, 0x24, 0x8e, 0x32, 0x8c, 0x46, 0x34, 0xdd, 0x89, 0x26, 0x35, 0x3a,
+ 0x08, 0x8b, 0xaf, 0xfe, 0xd9, 0x79, 0x6c, 0xe6, 0xba, 0x77, 0xe9, 0x51,
+ 0x27, 0x97, 0xfe, 0x69, 0xb6, 0x60, 0x51, 0xe8, 0x02, 0xc5, 0xfe, 0x37,
+ 0x66, 0x6f, 0xc1, 0x1a, 0xb1, 0x50, 0xe8, 0x08, 0xa7, 0x94, 0x4d, 0x28,
+ 0x48, 0xe1, 0x49, 0xb4, 0xe1, 0xbe, 0xa3, 0x55, 0xed, 0x7e, 0x68, 0xec,
+ 0xf5, 0x3b, 0xb7, 0xf8, 0xc0, 0xb9, 0x2d, 0x8b, 0x7c, 0x2b, 0x0c, 0x59,
+ 0x0d, 0x0a, 0xff, 0x6c, 0xe6, 0xba, 0x77, 0xe9, 0x51, 0x15, 0x17, 0xed,
+ 0x74, 0xef, 0xd2, 0xa2, 0x99, 0x2f, 0xe6, 0xfe, 0x3f, 0x60, 0x58, 0xb6,
+ 0xce, 0x1f, 0x2e, 0xe1, 0xbd, 0xff, 0xed, 0x93, 0xbc, 0xb6, 0x73, 0x5d,
+ 0x3b, 0xf4, 0xa8, 0x99, 0xcb, 0xff, 0xdb, 0x27, 0x79, 0x6c, 0xe6, 0xba,
+ 0x77, 0xe9, 0x51, 0x46, 0x95, 0x3a, 0x72, 0xa3, 0x85, 0x51, 0xa5, 0xbe,
+ 0x5f, 0xbf, 0xf3, 0xcb, 0x67, 0x35, 0xd3, 0xbf, 0x4a, 0x88, 0xe8, 0xb8,
+ 0x1b, 0xd6, 0x2f, 0xe2, 0xcf, 0x72, 0x0e, 0xb1, 0x7b, 0x59, 0x3a, 0xc5,
+ 0xe8, 0xf7, 0x16, 0x2f, 0x6a, 0x7d, 0x9f, 0xa2, 0x0b, 0x83, 0x5e, 0x2d,
+ 0x0c, 0x7a, 0xff, 0xf1, 0x0b, 0xc2, 0x37, 0xdd, 0xf4, 0xda, 0xe2, 0xc5,
+ 0xff, 0xe1, 0x3b, 0x49, 0x81, 0xc1, 0x73, 0xe2, 0x58, 0xbd, 0xa9, 0x6c,
+ 0xe2, 0x26, 0xb8, 0x9f, 0x5b, 0x29, 0xfb, 0xc4, 0x34, 0x9a, 0x1d, 0xd7,
+ 0x0b, 0xeb, 0x17, 0xed, 0x88, 0x2b, 0xae, 0x71, 0x62, 0xfb, 0xae, 0x85,
+ 0xd2, 0xc5, 0xf7, 0x04, 0x76, 0x58, 0xbd, 0x07, 0x1a, 0xc5, 0xc6, 0x7d,
+ 0x62, 0x98, 0xf6, 0x48, 0x8c, 0xc1, 0xdb, 0xf6, 0x10, 0xf2, 0x75, 0x8b,
+ 0xfe, 0x6d, 0x70, 0xb0, 0x7f, 0x85, 0x8b, 0xd9, 0xd8, 0xd6, 0x2e, 0xd6,
+ 0x2c, 0x5f, 0x44, 0x75, 0x83, 0x36, 0xba, 0x1e, 0xa6, 0x46, 0x67, 0xca,
+ 0x09, 0xb6, 0xfd, 0x9a, 0xe8, 0x46, 0xac, 0x5f, 0xf7, 0x50, 0x7c, 0x63,
+ 0xc6, 0xea, 0xc5, 0xf3, 0x69, 0xd9, 0x62, 0xff, 0xc5, 0x86, 0xbc, 0xdc,
+ 0xfc, 0x0d, 0x62, 0xf4, 0xcf, 0xe5, 0x8b, 0xee, 0x9d, 0xfa, 0x54, 0x53,
+ 0x45, 0xe3, 0x1f, 0xeb, 0x17, 0xf4, 0x75, 0x9d, 0x7c, 0x4b, 0x16, 0xce,
+ 0xcf, 0x38, 0xe3, 0xd7, 0xff, 0x73, 0x08, 0x71, 0xb7, 0x61, 0xef, 0x03,
+ 0x2c, 0x5f, 0x9b, 0x9e, 0xcf, 0xac, 0x5f, 0xe6, 0xd6, 0x4d, 0x02, 0x0b,
+ 0xac, 0x50, 0xd5, 0x1d, 0xe1, 0x59, 0xa7, 0x8c, 0x43, 0x32, 0x06, 0x87,
+ 0x89, 0xff, 0x85, 0x1e, 0x4e, 0xde, 0x51, 0x7d, 0xa7, 0x1b, 0x2c, 0x5f,
+ 0xfe, 0xe9, 0xf5, 0xcf, 0xbb, 0x73, 0x99, 0xc5, 0x8b, 0xff, 0xfe, 0xc2,
+ 0xf7, 0x1b, 0xac, 0x2e, 0x75, 0xf6, 0xff, 0x41, 0xce, 0xb1, 0x7f, 0xdc,
+ 0x7e, 0xf2, 0x68, 0xff, 0x16, 0x2c, 0xdf, 0x47, 0x89, 0x25, 0xf9, 0xae,
+ 0xff, 0x6a, 0x7e, 0x6b, 0x50, 0x62, 0xc5, 0xfd, 0x93, 0xe7, 0x58, 0x35,
+ 0x8b, 0xff, 0xb6, 0xf5, 0xf6, 0xff, 0x4f, 0xcf, 0xc2, 0xc5, 0x7d, 0x1c,
+ 0x6e, 0x68, 0x46, 0xfc, 0x2f, 0xbf, 0xf7, 0xd8, 0xa7, 0xe0, 0xa3, 0x53,
+ 0x2c, 0x5f, 0xff, 0xb2, 0x78, 0xe3, 0x6b, 0x36, 0xe3, 0x14, 0x1d, 0x62,
+ 0xa4, 0x89, 0x6f, 0x20, 0xde, 0x91, 0xe4, 0xb1, 0x7d, 0xee, 0x38, 0x16,
+ 0x2f, 0xf4, 0x7b, 0x9a, 0x63, 0xe2, 0xc5, 0xe0, 0x79, 0x96, 0x2f, 0xf7,
+ 0x3a, 0x6d, 0x69, 0xa7, 0x58, 0xa8, 0x45, 0x4f, 0x64, 0x6e, 0x67, 0xc1,
+ 0xdb, 0xff, 0xfa, 0x71, 0x6a, 0x6e, 0x4f, 0x13, 0x73, 0xf8, 0x36, 0xde,
+ 0xb1, 0x7f, 0xff, 0xbe, 0xe6, 0x96, 0x4b, 0xf1, 0x2c, 0xf9, 0x63, 0xce,
+ 0xb1, 0x7f, 0xd9, 0xa7, 0x86, 0x28, 0x3a, 0xc5, 0xff, 0xff, 0xf4, 0x77,
+ 0xd7, 0xf3, 0x6f, 0xf3, 0xaf, 0xb7, 0xf0, 0x9c, 0xdc, 0xdf, 0x1d, 0xac,
+ 0x5f, 0xa7, 0xdb, 0xf0, 0x6f, 0x58, 0xa9, 0xd3, 0xac, 0x1b, 0x1f, 0x18,
+ 0x37, 0x9b, 0x07, 0x08, 0x4b, 0xfe, 0xdf, 0xd7, 0xd8, 0x1f, 0x63, 0xac,
+ 0x5f, 0xdb, 0x60, 0x8d, 0xfb, 0x2c, 0x5f, 0x61, 0x41, 0x8b, 0x15, 0x23,
+ 0xd2, 0x98, 0xc2, 0xb1, 0x30, 0x66, 0x54, 0x78, 0x47, 0xdd, 0xa1, 0x2c,
+ 0x5f, 0x67, 0xc3, 0xd2, 0xc5, 0x1c, 0xde, 0x10, 0xc5, 0xd3, 0xee, 0xac,
+ 0x5c, 0x7d, 0xc5, 0x8b, 0xf9, 0xcb, 0xad, 0xb3, 0xf1, 0x62, 0x8d, 0x3e,
+ 0x90, 0x0e, 0x08, 0x6e, 0xff, 0x75, 0xd0, 0xb4, 0x0f, 0x89, 0x62, 0xfe,
+ 0x82, 0xf6, 0xe6, 0x79, 0x62, 0xff, 0x9c, 0x1d, 0x36, 0xb4, 0xd3, 0xac,
+ 0x5f, 0xe7, 0x03, 0xfb, 0xd9, 0xf5, 0x8a, 0x92, 0x27, 0xa6, 0x30, 0x30,
+ 0xee, 0xfb, 0xed, 0x9a, 0x58, 0xbb, 0xe2, 0x58, 0xb4, 0x96, 0x2f, 0xf4,
+ 0xf9, 0xd7, 0x89, 0xe6, 0x58, 0xad, 0x81, 0x38, 0xac, 0x86, 0xb3, 0x19,
+ 0x00, 0x8b, 0x78, 0xc0, 0x62, 0x57, 0xbe, 0x60, 0x16, 0x2d, 0xe5, 0x8a,
+ 0x63, 0x63, 0xf1, 0xfb, 0x87, 0x0b, 0x17, 0xff, 0xef, 0x70, 0x3e, 0x6a,
+ 0x07, 0x9f, 0xeb, 0x0a, 0x75, 0x8a, 0x83, 0xf0, 0xc1, 0x7b, 0xfa, 0x18,
+ 0x0f, 0xe1, 0x2c, 0x5f, 0xfb, 0x01, 0x99, 0x34, 0xc5, 0x03, 0x58, 0xbf,
+ 0xf6, 0x80, 0x32, 0x89, 0x7f, 0x80, 0x58, 0xac, 0x4d, 0x70, 0xf0, 0x90,
+ 0xf9, 0x01, 0x16, 0x88, 0xfe, 0xf7, 0xa2, 0x4b, 0x17, 0xfc, 0x2f, 0x7f,
+ 0x26, 0x94, 0x76, 0xb1, 0x7f, 0xf8, 0x9f, 0xd9, 0xee, 0x67, 0xf3, 0x77,
+ 0xcb, 0x15, 0xf4, 0x52, 0x90, 0xee, 0xf3, 0xcb, 0xff, 0x36, 0xb4, 0xd3,
+ 0xf1, 0x81, 0xc5, 0x8b, 0x4c, 0xb1, 0x73, 0xfd, 0x62, 0xfd, 0x9f, 0x72,
+ 0x1a, 0xc5, 0x4e, 0x7a, 0x32, 0x13, 0x00, 0xbd, 0xd0, 0x6a, 0xc5, 0xed,
+ 0xed, 0xa5, 0x8b, 0x12, 0xc5, 0x61, 0xb0, 0x71, 0xfb, 0xee, 0x05, 0x81,
+ 0x60, 0x58, 0xb1, 0x67, 0x98, 0xf4, 0x80, 0x3f, 0x7f, 0x34, 0x1e, 0x7c,
+ 0x31, 0x62, 0xff, 0xfb, 0x3d, 0xfc, 0x96, 0x9c, 0xbd, 0xf7, 0x92, 0xc5,
+ 0xd0, 0x05, 0x8b, 0xfc, 0xfd, 0xc7, 0x4d, 0xd6, 0xce, 0x91, 0x2a, 0x45,
+ 0xe1, 0xa7, 0xd6, 0x2a, 0xa6, 0xe8, 0xc5, 0xa1, 0x23, 0xf3, 0x02, 0x84,
+ 0xd7, 0x21, 0x7b, 0x79, 0xe6, 0xe2, 0xc5, 0xf8, 0xb9, 0xfc, 0xdd, 0x58,
+ 0xb6, 0x96, 0x2b, 0x0d, 0xe8, 0x65, 0x77, 0xe0, 0x7e, 0x25, 0xc5, 0x8b,
+ 0xc4, 0x23, 0x56, 0x2f, 0x18, 0xf3, 0xac, 0x5f, 0xf4, 0x01, 0xfc, 0x00,
+ 0xca, 0x4b, 0x15, 0xf3, 0xd9, 0x21, 0xfa, 0x84, 0x60, 0x91, 0x4f, 0x9d,
+ 0xed, 0xb3, 0xb0, 0x36, 0xac, 0xe1, 0x68, 0x62, 0x0c, 0xe5, 0x08, 0x01,
+ 0xc3, 0xeb, 0x25, 0x34, 0x9b, 0x08, 0xee, 0xa3, 0xf6, 0xee, 0x1a, 0x2c,
+ 0x47, 0xa8, 0x63, 0xfe, 0x57, 0x73, 0xb7, 0x82, 0x11, 0x25, 0x1d, 0xd7,
+ 0x23, 0xf0, 0xf4, 0xb9, 0x91, 0x33, 0x6e, 0x2d, 0x87, 0x0e, 0x2b, 0xa7,
+ 0xdc, 0x58, 0xbf, 0xfe, 0xcf, 0x37, 0xc5, 0xf7, 0x6e, 0xf9, 0x06, 0xac,
+ 0x5f, 0x31, 0x01, 0x96, 0x2f, 0xba, 0x77, 0xe9, 0x51, 0x55, 0x15, 0x23,
+ 0xd2, 0xd1, 0x0d, 0xff, 0x9e, 0x5b, 0x39, 0xae, 0x9d, 0xfa, 0x54, 0x4d,
+ 0xa5, 0xb6, 0x67, 0x4c, 0xc4, 0x63, 0x99, 0x0a, 0x33, 0x91, 0x5f, 0xed,
+ 0x9c, 0xd7, 0x4e, 0xfd, 0x2a, 0x2b, 0xf2, 0xfd, 0xae, 0x9d, 0xfa, 0x54,
+ 0x58, 0xc5, 0xc1, 0x24, 0xb1, 0x6d, 0x9c, 0x3d, 0x19, 0x8d, 0xef, 0xff,
+ 0xe9, 0xf6, 0x66, 0xfc, 0x4f, 0x92, 0xfc, 0x36, 0xb0, 0x96, 0x2f, 0xba,
+ 0xfc, 0x1a, 0xb1, 0x7a, 0x3d, 0xc5, 0x8a, 0xe1, 0xe1, 0x78, 0x96, 0xff,
+ 0x4b, 0x08, 0x19, 0x83, 0x58, 0xbf, 0xe9, 0xe3, 0x8e, 0x0e, 0x30, 0xd6,
+ 0x2d, 0xe5, 0x8b, 0xe1, 0x4b, 0x38, 0xb0, 0xe5, 0x95, 0xfe, 0x16, 0x6b,
+ 0xaf, 0xb7, 0x16, 0x2a, 0x48, 0xe4, 0xd1, 0x91, 0x26, 0x70, 0xc6, 0xff,
+ 0x6a, 0x0c, 0xdc, 0x0f, 0xee, 0xb1, 0x7e, 0x1e, 0xc1, 0xb0, 0x11, 0xab,
+ 0x17, 0xde, 0xe3, 0xf6, 0xb1, 0x5b, 0x19, 0xec, 0x41, 0xa5, 0xff, 0x10,
+ 0xa7, 0x9a, 0x51, 0xa9, 0xd6, 0x2e, 0xd7, 0x96, 0x2f, 0x9e, 0x58, 0x35,
+ 0x8b, 0xfb, 0xd9, 0xa1, 0xe1, 0x2c, 0x5b, 0x06, 0x79, 0xfe, 0x22, 0xba,
+ 0x58, 0xb1, 0x7f, 0x3b, 0xfb, 0xd9, 0xf5, 0x8b, 0xff, 0xd8, 0x72, 0x73,
+ 0x4b, 0x01, 0xb4, 0xcd, 0x89, 0x62, 0x8d, 0x44, 0xb6, 0x85, 0xc8, 0xb6,
+ 0xff, 0x19, 0x06, 0x39, 0x77, 0xe5, 0x8b, 0xf6, 0xbd, 0xfc, 0x9d, 0x62,
+ 0xa0, 0xf8, 0x30, 0xda, 0xfe, 0xf3, 0x1f, 0xb9, 0x71, 0x62, 0xdb, 0x38,
+ 0xac, 0xd3, 0x47, 0x87, 0x84, 0x8f, 0xc9, 0x9c, 0xf4, 0x99, 0xf9, 0x0b,
+ 0xd0, 0xe1, 0x20, 0x10, 0x82, 0xb6, 0x57, 0x34, 0xb5, 0x38, 0x75, 0x50,
+ 0xbb, 0x4a, 0xd3, 0xae, 0x97, 0xed, 0x74, 0xef, 0xd2, 0xa2, 0xd5, 0x2f,
+ 0xda, 0xe9, 0xdf, 0xa5, 0x45, 0x04, 0x5d, 0x3f, 0xd6, 0x2f, 0xf8, 0xa3,
+ 0xdc, 0x9a, 0x4d, 0x32, 0xc5, 0xe7, 0x96, 0xce, 0x22, 0x2c, 0x06, 0xfe,
+ 0x19, 0xbf, 0x41, 0x9b, 0x99, 0xa5, 0x8b, 0x6c, 0xe2, 0x66, 0x27, 0x86,
+ 0x10, 0x68, 0x77, 0xde, 0xd3, 0xfd, 0x62, 0xfe, 0xfb, 0x4f, 0x38, 0xb8,
+ 0xb1, 0x7d, 0xa8, 0xf7, 0x16, 0x2f, 0x16, 0x4e, 0xb1, 0x6c, 0x19, 0xe0,
+ 0x74, 0x47, 0x7f, 0x41, 0xdf, 0xbf, 0x49, 0x62, 0xff, 0x67, 0xf9, 0xa2,
+ 0x6e, 0x96, 0x2b, 0x13, 0x1f, 0xe8, 0x8c, 0x9c, 0x78, 0x51, 0xe2, 0xfb,
+ 0xb5, 0xe5, 0x8b, 0xfb, 0x26, 0xe3, 0x76, 0x62, 0xc5, 0xfe, 0x6d, 0xc8,
+ 0xf7, 0xde, 0x65, 0x8b, 0xd9, 0xfd, 0x97, 0x44, 0x01, 0x0c, 0x70, 0xc6,
+ 0xe7, 0x33, 0x65, 0x30, 0xcf, 0x43, 0x2a, 0xfe, 0x0b, 0x41, 0x4f, 0x6e,
+ 0x67, 0xd6, 0x2f, 0xe2, 0x04, 0x6e, 0xb9, 0xd6, 0x2f, 0xf1, 0xb2, 0xc6,
+ 0xfb, 0xcc, 0xb1, 0x50, 0x7c, 0xac, 0x61, 0x7e, 0xfe, 0x75, 0x07, 0x58,
+ 0xbd, 0x05, 0x32, 0xc5, 0xff, 0xe9, 0xa3, 0x7b, 0xeb, 0x9c, 0x6d, 0x61,
+ 0xab, 0x17, 0xf9, 0xa6, 0x8d, 0xef, 0xae, 0x2c, 0x5b, 0x8b, 0x15, 0x07,
+ 0x90, 0x46, 0xd7, 0xff, 0x40, 0x05, 0xee, 0x14, 0x04, 0x89, 0xd6, 0x2e,
+ 0xd4, 0x2c, 0x54, 0x93, 0x7a, 0x19, 0x07, 0x45, 0x2c, 0x3b, 0xf8, 0x4b,
+ 0x6f, 0x20, 0x08, 0x8f, 0x7c, 0xdf, 0x7e, 0x2c, 0x5f, 0x74, 0xef, 0xd2,
+ 0xa2, 0xe2, 0x2f, 0xf9, 0xcf, 0xc6, 0xcd, 0xef, 0xa5, 0x8b, 0xf8, 0x4f,
+ 0xd8, 0xf3, 0x4b, 0x15, 0xa4, 0x4d, 0x11, 0x8f, 0x0e, 0xaf, 0xff, 0xf7,
+ 0xd8, 0x65, 0x0f, 0x39, 0x8f, 0xfe, 0x6d, 0xe4, 0x71, 0x62, 0xff, 0xfd,
+ 0x20, 0xff, 0x27, 0xf3, 0x80, 0x44, 0xfb, 0xc6, 0xb1, 0x70, 0x73, 0x2c,
+ 0x5f, 0xf7, 0x31, 0x80, 0x1f, 0x9f, 0xeb, 0x17, 0xf7, 0x7d, 0x37, 0x3e,
+ 0xcb, 0x15, 0x3a, 0x21, 0x3e, 0x35, 0xe3, 0xab, 0xff, 0xe9, 0x47, 0x81,
+ 0xb7, 0x3f, 0xac, 0x00, 0xa6, 0x58, 0xb1, 0xab, 0x17, 0x4c, 0xcb, 0x15,
+ 0x86, 0xad, 0xc4, 0xef, 0xf6, 0xfc, 0xf7, 0x37, 0xc7, 0xd6, 0x2a, 0x47,
+ 0xaf, 0xf1, 0xfb, 0xfd, 0xf8, 0x07, 0x30, 0x80, 0xb1, 0x58, 0x99, 0x5b,
+ 0x43, 0x59, 0xc8, 0xaf, 0xf1, 0x7a, 0x58, 0x4c, 0x35, 0x8b, 0xfe, 0x27,
+ 0x07, 0x3f, 0x05, 0xe5, 0x8a, 0xc3, 0xea, 0xf1, 0x95, 0xfb, 0x0e, 0xc1,
+ 0x06, 0xb1, 0x74, 0x1d, 0x62, 0xa0, 0xf8, 0xb7, 0x48, 0x74, 0x55, 0x7f,
+ 0x08, 0x9c, 0xd9, 0x01, 0x62, 0xf7, 0x59, 0xda, 0xc5, 0xe0, 0x8d, 0x3a,
+ 0xc5, 0x61, 0xbf, 0x71, 0xfb, 0xf7, 0xc4, 0x6e, 0x12, 0xc5, 0xf9, 0xf5,
+ 0xe2, 0x85, 0x8b, 0xd2, 0xf3, 0x2c, 0x5f, 0x87, 0x9b, 0xb1, 0xf5, 0x8b,
+ 0xc1, 0x1b, 0xa5, 0x8a, 0x1a, 0x2e, 0x3a, 0x29, 0x98, 0x9f, 0x43, 0xa1,
+ 0x0a, 0xef, 0xf1, 0xde, 0x5c, 0x61, 0xe2, 0xc5, 0xe3, 0x63, 0x8b, 0x17,
+ 0xfa, 0x51, 0x33, 0xfe, 0x37, 0x56, 0x2f, 0xfd, 0x30, 0xa4, 0x1e, 0xf8,
+ 0xfb, 0xef, 0x58, 0xa8, 0x44, 0xde, 0x0f, 0x39, 0xbd, 0xfc, 0x2d, 0xd7,
+ 0xf0, 0xa1, 0x62, 0x96, 0x2e, 0x89, 0xd6, 0x2b, 0xb3, 0xd5, 0xe1, 0x88,
+ 0x40, 0xcb, 0xfe, 0xcf, 0xf8, 0xa0, 0x1b, 0x59, 0x62, 0xfc, 0x5e, 0x27,
+ 0x35, 0x62, 0x96, 0x2b, 0x0d, 0xa6, 0xe1, 0x45, 0x3a, 0x30, 0xc8, 0xcb,
+ 0x8d, 0xd7, 0xf1, 0xdf, 0x7c, 0x68, 0x22, 0xc5, 0xff, 0x98, 0x79, 0xbc,
+ 0xf9, 0x2e, 0xe4, 0xb1, 0x7e, 0x7e, 0x39, 0x01, 0x62, 0xfe, 0x6d, 0xf2,
+ 0x3c, 0x4c, 0xb1, 0x7f, 0xe8, 0xc2, 0x3c, 0x7c, 0x23, 0x84, 0x58, 0xa9,
+ 0x1f, 0x96, 0x8c, 0x6f, 0xfb, 0x0f, 0x9a, 0xc9, 0xf0, 0xc5, 0x8b, 0xff,
+ 0xdf, 0x8d, 0xfe, 0xe3, 0x7b, 0xf8, 0x13, 0x8b, 0x15, 0x09, 0xdc, 0x61,
+ 0x91, 0xa8, 0x4d, 0x09, 0x9f, 0x91, 0x00, 0xea, 0x96, 0x2f, 0xe9, 0xdf,
+ 0x3d, 0x87, 0x58, 0xad, 0x8c, 0xdd, 0x38, 0x65, 0xf8, 0x6e, 0x58, 0x11,
+ 0x62, 0xfe, 0xcd, 0x3f, 0x85, 0x0b, 0x17, 0xff, 0xce, 0x50, 0xc1, 0x38,
+ 0xdc, 0xcf, 0xe6, 0xe2, 0xc5, 0x0c, 0xff, 0xf7, 0x96, 0xdf, 0xff, 0xcc,
+ 0x37, 0xef, 0x6e, 0x34, 0xa0, 0xa3, 0x7f, 0x9d, 0x62, 0xff, 0xe6, 0x21,
+ 0x4b, 0x39, 0xc6, 0x1e, 0x2c, 0x54, 0x26, 0xd9, 0x34, 0x2a, 0x3e, 0x49,
+ 0xe5, 0xdb, 0x6c, 0xec, 0x36, 0x79, 0xb4, 0x4a, 0x1b, 0x93, 0x76, 0x42,
+ 0xf3, 0xa2, 0xfe, 0xd9, 0x1a, 0x1b, 0xb3, 0x46, 0xb9, 0xa8, 0x7f, 0x9c,
+ 0xc7, 0xed, 0xcf, 0x0d, 0x70, 0x27, 0x14, 0x33, 0xb9, 0x1a, 0x2f, 0xa3,
+ 0xe6, 0xdc, 0x84, 0xa8, 0x71, 0xc8, 0xdf, 0xc1, 0x40, 0xa6, 0x9d, 0xe4,
+ 0xb1, 0x7f, 0xb6, 0x32, 0xd8, 0x3d, 0xb9, 0xb0, 0x0d, 0x62, 0xff, 0x05,
+ 0x30, 0x41, 0xfe, 0x0d, 0x58, 0xb9, 0xc2, 0xab, 0x14, 0x15, 0x3d, 0x52,
+ 0x3a, 0xbf, 0x6c, 0x20, 0xa8, 0xe0, 0x6b, 0x17, 0xed, 0x8b, 0x61, 0x00,
+ 0xd8, 0x58, 0xbf, 0xf3, 0x76, 0x16, 0x73, 0x5b, 0x76, 0xff, 0x71, 0x62,
+ 0xfb, 0x6e, 0xdf, 0xee, 0x2c, 0x5f, 0x6d, 0xdb, 0xfd, 0xc5, 0x8b, 0xd1,
+ 0xee, 0x96, 0x2b, 0x74, 0xfd, 0x26, 0x2b, 0xf9, 0x5d, 0x05, 0xa4, 0x7a,
+ 0x8e, 0x18, 0x57, 0xda, 0x3f, 0xbb, 0x58, 0xbf, 0x78, 0x01, 0x94, 0x96,
+ 0x2e, 0x8d, 0x6d, 0x3c, 0xf7, 0x25, 0xbf, 0xf8, 0xd3, 0x37, 0x67, 0x1e,
+ 0xc5, 0xb7, 0x6f, 0xf7, 0x16, 0x2f, 0xa3, 0x35, 0x25, 0x8a, 0x0b, 0x0f,
+ 0xf0, 0x96, 0xaf, 0x7a, 0x4e, 0xb1, 0x7d, 0xc7, 0xdf, 0x8b, 0x14, 0xe7,
+ 0x83, 0xc1, 0xdb, 0xee, 0x9d, 0xfa, 0x54, 0x5d, 0x25, 0xf8, 0x85, 0xe8,
+ 0xe2, 0xc5, 0x68, 0xf6, 0x7e, 0x63, 0x7c, 0xe2, 0x91, 0xd6, 0x2f, 0xe1,
+ 0x87, 0x26, 0x07, 0x16, 0x2b, 0xe7, 0xa6, 0xe4, 0x77, 0xc4, 0xe3, 0x85,
+ 0x8b, 0xfd, 0x1b, 0xdc, 0xa3, 0x7f, 0x16, 0x2a, 0x0f, 0x5f, 0xe4, 0x37,
+ 0xfe, 0xe7, 0x26, 0x90, 0x5f, 0x6e, 0xdf, 0xee, 0x2c, 0x5e, 0x94, 0x1d,
+ 0x62, 0xb6, 0x33, 0xeb, 0x1a, 0x75, 0xfd, 0x28, 0xed, 0xf9, 0x25, 0x8b,
+ 0xfe, 0x29, 0xb5, 0x1d, 0xc9, 0x8e, 0xb1, 0x7f, 0xed, 0xf0, 0x5e, 0xe0,
+ 0xbd, 0x9a, 0x58, 0xbf, 0xff, 0xfc, 0xdb, 0x42, 0xd6, 0xc7, 0xb0, 0xbf,
+ 0x0c, 0x32, 0x81, 0x74, 0x63, 0x8e, 0x3b, 0xe2, 0xc5, 0x42, 0x61, 0x38,
+ 0x76, 0x48, 0x37, 0xd2, 0x09, 0x9e, 0x58, 0xbe, 0xe4, 0x04, 0xe2, 0xc5,
+ 0x41, 0xe5, 0x04, 0x25, 0xbb, 0xc1, 0x16, 0x2f, 0xfe, 0xf7, 0xa2, 0x6e,
+ 0x16, 0x0f, 0xe2, 0x58, 0xbf, 0x1a, 0x68, 0x65, 0xd2, 0xc5, 0x42, 0x23,
+ 0x70, 0x69, 0x91, 0xaf, 0xba, 0x3b, 0x6e, 0xac, 0x5c, 0xe3, 0x58, 0xbf,
+ 0x49, 0xa2, 0x5b, 0xab, 0x15, 0xb4, 0xf0, 0xb0, 0x5e, 0xf0, 0xf0, 0x6b,
+ 0x17, 0x6a, 0x75, 0x8a, 0x84, 0x61, 0x0d, 0xa7, 0x08, 0xd8, 0x76, 0xff,
+ 0xff, 0xef, 0xe6, 0xfd, 0x67, 0x33, 0x5d, 0x46, 0x78, 0xb3, 0x9c, 0xc1,
+ 0xac, 0x5f, 0xe9, 0xe0, 0xba, 0x18, 0x7c, 0x58, 0xbf, 0xf8, 0x0c, 0x41,
+ 0x9a, 0xde, 0x70, 0x71, 0x62, 0xff, 0x9b, 0x0b, 0xf9, 0xe8, 0x1a, 0xc5,
+ 0xff, 0x98, 0xb5, 0x1e, 0x6e, 0x98, 0x6b, 0x15, 0x3a, 0x3c, 0x80, 0x6f,
+ 0xe4, 0x6d, 0xe6, 0xf7, 0xfb, 0x7c, 0x7b, 0x82, 0xe8, 0x2e, 0xb1, 0x50,
+ 0x9f, 0x0e, 0x46, 0xca, 0xe8, 0x17, 0xfd, 0xf6, 0x33, 0xdd, 0xf4, 0xdf,
+ 0x58, 0xbf, 0x08, 0x13, 0x17, 0x96, 0x28, 0x67, 0xcf, 0xa3, 0xdb, 0xfd,
+ 0x34, 0x9f, 0x53, 0xfc, 0x4b, 0x17, 0xd3, 0x48, 0x53, 0xac, 0x5c, 0xe1,
+ 0xac, 0x5f, 0xfb, 0xdb, 0x78, 0xe5, 0xd7, 0xdb, 0x4b, 0x15, 0x39, 0xed,
+ 0x60, 0xc5, 0x42, 0x36, 0x70, 0xdf, 0x90, 0x80, 0xbf, 0xd1, 0xe7, 0x9c,
+ 0x4d, 0x25, 0x8b, 0x83, 0xfa, 0xc5, 0x11, 0xe6, 0x86, 0x69, 0x7f, 0xfe,
+ 0x79, 0x14, 0x73, 0x3b, 0xe8, 0x9f, 0x3b, 0xe9, 0x62, 0xff, 0xf9, 0xc9,
+ 0xe7, 0x28, 0xed, 0x86, 0x51, 0x3a, 0xc5, 0xff, 0x37, 0xf3, 0xb0, 0x48,
+ 0x78, 0xb1, 0x6d, 0x9d, 0x8d, 0x9c, 0xfc, 0x14, 0x36, 0xd8, 0x21, 0x39,
+ 0xb0, 0xc9, 0x42, 0xc3, 0x38, 0x8c, 0xaa, 0x77, 0xd9, 0x42, 0xa8, 0x6c,
+ 0xf8, 0xf5, 0xd3, 0xab, 0x3c, 0x6e, 0xc2, 0x32, 0x62, 0x7d, 0x46, 0x70,
+ 0x77, 0x8f, 0xc2, 0xc1, 0xe1, 0xde, 0x52, 0x86, 0xf9, 0x09, 0xbf, 0x43,
+ 0xec, 0x50, 0x80, 0xde, 0x44, 0x62, 0xbe, 0xe2, 0x7d, 0xd1, 0xb8, 0xb1,
+ 0x7f, 0xf8, 0xbc, 0xc7, 0xfc, 0x31, 0x3e, 0x8d, 0x58, 0xbf, 0x9f, 0xd0,
+ 0x78, 0x25, 0x8a, 0xc3, 0xf5, 0xd2, 0x4d, 0xff, 0xc6, 0x9b, 0x05, 0xef,
+ 0x14, 0x7b, 0x8b, 0x17, 0xfd, 0xc1, 0x7a, 0x4d, 0xbf, 0xec, 0xb1, 0x4c,
+ 0x88, 0x23, 0xa3, 0x5f, 0xd9, 0x9c, 0xeb, 0xd0, 0xb1, 0x7e, 0xf6, 0x7a,
+ 0x3b, 0x58, 0xbf, 0xa7, 0x8f, 0x39, 0xa2, 0x58, 0xa5, 0x8b, 0xff, 0xa3,
+ 0x40, 0xdb, 0xcf, 0xc1, 0xdc, 0x96, 0x2f, 0xf8, 0x5e, 0x6f, 0xb1, 0xbf,
+ 0x65, 0x8b, 0xfd, 0x1a, 0x0f, 0xff, 0xc0, 0x2c, 0x54, 0x91, 0x6a, 0x34,
+ 0x6f, 0x9d, 0x5f, 0xd2, 0x79, 0x39, 0x74, 0xb1, 0x4b, 0x16, 0x85, 0x8a,
+ 0x19, 0x7a, 0x41, 0x96, 0xe2, 0xc5, 0x41, 0xb1, 0xf0, 0xfd, 0xff, 0xec,
+ 0xf4, 0x18, 0x1c, 0xfc, 0xc3, 0xc6, 0xea, 0xc5, 0x8e, 0xb1, 0x7f, 0x3c,
+ 0xb4, 0xc6, 0x32, 0xc5, 0xf1, 0x40, 0xf4, 0xb1, 0x7f, 0xe6, 0x93, 0x6b,
+ 0xb8, 0x28, 0xe2, 0xc5, 0x4e, 0x7c, 0x1e, 0x22, 0xb6, 0xce, 0xc6, 0xaa,
+ 0x83, 0x21, 0x83, 0x31, 0x87, 0xdf, 0x08, 0x83, 0xca, 0x1b, 0x82, 0x41,
+ 0xc2, 0x3a, 0xbb, 0x57, 0x0f, 0xa2, 0x93, 0xca, 0xd0, 0xbe, 0xc3, 0x36,
+ 0x33, 0xac, 0x5f, 0xc5, 0x1d, 0x9d, 0xfc, 0xb1, 0x7f, 0xf8, 0xc7, 0x1f,
+ 0xe3, 0xbf, 0x47, 0xdf, 0x75, 0x62, 0xcd, 0xa3, 0xfd, 0xf9, 0x75, 0xff,
+ 0xff, 0x0b, 0x52, 0xe7, 0xdd, 0xb5, 0xad, 0x0b, 0xb6, 0xd3, 0xf1, 0x62,
+ 0xfd, 0x86, 0x73, 0x3e, 0xb1, 0x7f, 0xee, 0xa3, 0x3f, 0x1e, 0x28, 0xf2,
+ 0xc5, 0xfc, 0xe5, 0xf8, 0xd4, 0x96, 0x2b, 0x47, 0xd7, 0xc3, 0xeb, 0xd0,
+ 0x53, 0x2c, 0x5f, 0xb5, 0xce, 0x39, 0x2c, 0x57, 0xcf, 0x14, 0x43, 0xb7,
+ 0x85, 0xfe, 0x2c, 0x5f, 0xf9, 0xcd, 0xeb, 0xed, 0x36, 0xa0, 0xc5, 0x8b,
+ 0xd1, 0x9d, 0xf4, 0x7c, 0x24, 0x3d, 0x7f, 0xf3, 0x9f, 0x9e, 0x27, 0x07,
+ 0x7e, 0x0b, 0x16, 0x2d, 0xed, 0x1f, 0xf0, 0x8c, 0xef, 0xfc, 0x4e, 0x67,
+ 0xb3, 0xef, 0x33, 0xac, 0x5f, 0xff, 0x80, 0x08, 0xdb, 0xf8, 0xf0, 0xba,
+ 0xfc, 0x13, 0xac, 0x5f, 0xff, 0x88, 0x4f, 0xbb, 0x92, 0xfe, 0x1b, 0x83,
+ 0x98, 0x4b, 0x15, 0x88, 0xb2, 0xfa, 0xc5, 0xdd, 0x62, 0xc5, 0xfd, 0x12,
+ 0x6e, 0xfd, 0x8b, 0x17, 0xff, 0xcf, 0xdc, 0xb9, 0xdf, 0x89, 0xff, 0x9d,
+ 0xf9, 0x62, 0xa1, 0x17, 0x66, 0x91, 0x68, 0x61, 0xcb, 0xaf, 0xb5, 0xc6,
+ 0xd2, 0xc5, 0xfe, 0xc1, 0x05, 0xfa, 0xfb, 0x4c, 0xb1, 0x7f, 0xff, 0xf3,
+ 0x49, 0xf9, 0xc8, 0xe6, 0x7d, 0x8a, 0x0f, 0xa8, 0x0d, 0xc9, 0x62, 0xff,
+ 0xff, 0xec, 0xe0, 0x7e, 0x6d, 0xed, 0xe9, 0x47, 0xda, 0x3d, 0xf1, 0x39,
+ 0xd6, 0x2d, 0xe8, 0x47, 0x1c, 0x9b, 0xef, 0xdc, 0x8f, 0x87, 0x32, 0xc5,
+ 0x31, 0xe9, 0xf8, 0xa2, 0xa1, 0x3b, 0x4c, 0x23, 0x78, 0xdc, 0x2f, 0x4a,
+ 0x0e, 0xb1, 0x7d, 0x2f, 0xe1, 0xd6, 0x2f, 0x16, 0x7d, 0x62, 0xa0, 0xdf,
+ 0xc8, 0x8e, 0x96, 0x2f, 0xec, 0x1e, 0xb1, 0xa6, 0x58, 0xbf, 0xd3, 0x96,
+ 0x77, 0xec, 0x31, 0x62, 0xfd, 0xdf, 0xa3, 0x0c, 0x23, 0xe4, 0x0c, 0xba,
+ 0xb6, 0x04, 0x58, 0x63, 0x85, 0xfc, 0x76, 0xf7, 0x05, 0x3a, 0xc5, 0xdc,
+ 0x92, 0xc5, 0xff, 0xf6, 0x0c, 0x5e, 0xe7, 0x5f, 0x6e, 0x09, 0xfb, 0x58,
+ 0xbf, 0xfe, 0x79, 0x70, 0x32, 0x14, 0xfe, 0xe6, 0x10, 0x16, 0x2b, 0xe8,
+ 0xa5, 0x12, 0x9d, 0x62, 0x62, 0x06, 0x98, 0x7a, 0x17, 0xb7, 0xfb, 0x5a,
+ 0x79, 0x4f, 0x86, 0x2c, 0x52, 0xc5, 0xd3, 0x09, 0x62, 0xb0, 0xf6, 0xfe,
+ 0x6c, 0x60, 0x65, 0xff, 0x7c, 0x3f, 0x36, 0x9a, 0x78, 0x58, 0xbf, 0xff,
+ 0x85, 0x22, 0x69, 0x16, 0x7b, 0x91, 0x21, 0xc7, 0x96, 0x2f, 0xfd, 0x1d,
+ 0xf5, 0xf6, 0xd6, 0x9e, 0x4b, 0x17, 0xfa, 0x72, 0xce, 0xfd, 0x86, 0x2c,
+ 0x5f, 0xc3, 0x7e, 0xfd, 0x87, 0x39, 0xfb, 0x86, 0x83, 0x7d, 0xa8, 0x33,
+ 0x8b, 0x17, 0xbf, 0x93, 0x2c, 0x5f, 0xfe, 0x2f, 0x73, 0x18, 0xf8, 0x38,
+ 0x94, 0x61, 0xe1, 0x78, 0x92, 0x99, 0x1c, 0xa2, 0x84, 0x45, 0x49, 0x52,
+ 0x3e, 0x17, 0xb1, 0xdf, 0x23, 0xb6, 0xbf, 0xfb, 0x07, 0x12, 0x8d, 0x40,
+ 0x6e, 0x4b, 0x17, 0xfe, 0xdf, 0x92, 0x38, 0xdb, 0x7c, 0x0d, 0x62, 0xff,
+ 0xf9, 0xbe, 0x23, 0x9d, 0xe5, 0xf7, 0x3b, 0x71, 0x62, 0x8e, 0x8d, 0x67,
+ 0x43, 0xf2, 0x1d, 0xcf, 0xb3, 0x3b, 0x33, 0x82, 0x4d, 0x39, 0x09, 0x4e,
+ 0x99, 0xfb, 0x8c, 0x06, 0x62, 0x8d, 0x47, 0x59, 0xf8, 0xfc, 0x1c, 0xd0,
+ 0x0b, 0x85, 0x0d, 0x0e, 0x46, 0x6f, 0xe9, 0x5b, 0x01, 0xc6, 0x33, 0x5f,
+ 0x67, 0x04, 0x95, 0x34, 0x1e, 0xfd, 0xc3, 0xc1, 0x4c, 0xb1, 0x7f, 0xa5,
+ 0x9e, 0xfc, 0x06, 0x4b, 0x17, 0xfe, 0xf3, 0x74, 0xc3, 0x72, 0x36, 0x16,
+ 0x2f, 0x0d, 0x8d, 0x58, 0xbf, 0xe8, 0xef, 0xef, 0xcf, 0x41, 0x8b, 0x15,
+ 0x08, 0x98, 0xc3, 0xfd, 0x0f, 0x5f, 0xf6, 0x08, 0x2e, 0xd3, 0x36, 0x12,
+ 0xc5, 0xff, 0xba, 0x21, 0x7b, 0x9a, 0x6e, 0xc0, 0xb1, 0x7e, 0x21, 0x4f,
+ 0xde, 0xea, 0xc5, 0x61, 0xf8, 0x79, 0x0a, 0xb1, 0x19, 0xaf, 0x0a, 0xcb,
+ 0x05, 0x56, 0x2e, 0x17, 0xd6, 0x2f, 0xc5, 0x9f, 0x7f, 0x2c, 0x5f, 0xd2,
+ 0x7c, 0xdf, 0x03, 0x58, 0xa0, 0xa9, 0xeb, 0x6c, 0x32, 0x7b, 0xf6, 0xc4,
+ 0x15, 0xd7, 0x38, 0xb1, 0x7c, 0xc2, 0x94, 0x2c, 0x5f, 0x67, 0x70, 0x75,
+ 0x8b, 0xe6, 0x28, 0x02, 0xc5, 0xff, 0xff, 0xb4, 0xdb, 0xe0, 0x6c, 0x4f,
+ 0xa3, 0x76, 0xfd, 0xf8, 0x64, 0x0d, 0x62, 0xff, 0x7e, 0x27, 0xd4, 0x60,
+ 0xd6, 0x2f, 0xd1, 0xbd, 0xf3, 0x4b, 0x17, 0x64, 0xeb, 0x17, 0x0e, 0x16,
+ 0x28, 0x33, 0x5e, 0x10, 0x62, 0xa1, 0x16, 0x1f, 0x34, 0x12, 0xc5, 0xf9,
+ 0xe6, 0x93, 0x79, 0x62, 0xff, 0x08, 0x23, 0x6f, 0xf6, 0x7d, 0x62, 0xff,
+ 0x87, 0xa8, 0x93, 0x77, 0xec, 0x58, 0xbe, 0xc2, 0x89, 0x2c, 0x54, 0x1e,
+ 0xdf, 0x8e, 0xaf, 0xff, 0x9f, 0xf1, 0x21, 0xfe, 0x3b, 0xf3, 0x1f, 0x8b,
+ 0x17, 0x6a, 0x16, 0x2a, 0x4a, 0xbe, 0xcd, 0x22, 0xe8, 0x8f, 0x44, 0x3f,
+ 0x8c, 0x84, 0x05, 0xe4, 0x53, 0xe8, 0x49, 0xef, 0x21, 0x08, 0xa3, 0x7f,
+ 0xda, 0xe7, 0xdb, 0xae, 0x85, 0x3a, 0xc5, 0xfc, 0x66, 0x6f, 0x21, 0x49,
+ 0x62, 0xfe, 0x11, 0xb8, 0x41, 0x31, 0x62, 0xff, 0xff, 0x7d, 0x8e, 0x76,
+ 0x33, 0x9d, 0xf4, 0xd9, 0xa1, 0xc7, 0x6b, 0x17, 0xff, 0xd1, 0x2c, 0xe3,
+ 0x10, 0x0b, 0x3d, 0xfc, 0x58, 0xbb, 0x52, 0xe9, 0x16, 0x44, 0xcb, 0x50,
+ 0x9c, 0x06, 0x1f, 0x11, 0x88, 0xa1, 0xc5, 0x7f, 0xff, 0xd0, 0x3f, 0xe7,
+ 0x7e, 0x27, 0xf8, 0x1f, 0x9c, 0x7d, 0x74, 0xb1, 0x7e, 0x89, 0x9d, 0xf4,
+ 0xb1, 0x7f, 0xd1, 0xcf, 0xe6, 0xf8, 0xce, 0xd6, 0x2d, 0xee, 0x1f, 0x1f,
+ 0x8a, 0x2f, 0xa7, 0xdc, 0x73, 0x56, 0x2f, 0xf6, 0x66, 0x1a, 0x6b, 0xc9,
+ 0x62, 0x8d, 0x4d, 0x3d, 0xa1, 0x97, 0xf2, 0x8f, 0x14, 0x5f, 0x73, 0xaf,
+ 0x42, 0xc5, 0xfe, 0x63, 0xb6, 0xb9, 0x28, 0x58, 0xac, 0x3d, 0x7f, 0x12,
+ 0x5f, 0xfc, 0x67, 0x3a, 0xfb, 0x77, 0xed, 0x6a, 0x16, 0x2f, 0x9c, 0xcd,
+ 0xb2, 0x58, 0xa6, 0x3e, 0xf2, 0x49, 0xbf, 0xf6, 0xbc, 0xf2, 0xe6, 0xf1,
+ 0x69, 0x96, 0x2f, 0xfe, 0x7e, 0x13, 0x9a, 0x3f, 0x89, 0xf8, 0xb1, 0x50,
+ 0x88, 0x71, 0x21, 0x5f, 0xff, 0xf3, 0x98, 0x1e, 0x68, 0x9f, 0xb9, 0x75,
+ 0x1e, 0xe6, 0x77, 0xe5, 0x8b, 0xf1, 0x60, 0x20, 0x0b, 0x17, 0xf4, 0xe1,
+ 0xe7, 0xdf, 0xb5, 0x8b, 0xfd, 0x26, 0x29, 0xa4, 0xdf, 0x58, 0xbd, 0xc1,
+ 0x1d, 0x62, 0xd1, 0x24, 0x55, 0x61, 0x3c, 0xc6, 0x3e, 0x34, 0xac, 0x55,
+ 0x61, 0xa8, 0x48, 0x7e, 0x14, 0xee, 0x44, 0x51, 0x8a, 0xdf, 0xb7, 0xb6,
+ 0xb0, 0x6b, 0x17, 0xff, 0xdc, 0xfb, 0x73, 0xdf, 0xc1, 0xb7, 0x30, 0x96,
+ 0x2c, 0x58, 0x7f, 0x22, 0x2a, 0xbf, 0xc4, 0xfa, 0x37, 0xd9, 0xd2, 0xc5,
+ 0xbf, 0x07, 0xb7, 0x84, 0xd7, 0xe7, 0xfc, 0x8b, 0xa5, 0x8b, 0xfd, 0x07,
+ 0xc6, 0x3c, 0x6e, 0xac, 0x5f, 0xe9, 0x1f, 0x8c, 0x5d, 0xc9, 0x62, 0xba,
+ 0x3e, 0xa9, 0x8d, 0x6f, 0xf3, 0x69, 0xc8, 0x18, 0x4b, 0x17, 0xfb, 0xcc,
+ 0x59, 0xdc, 0xa1, 0x62, 0xff, 0xed, 0x69, 0xe5, 0xc2, 0xc3, 0x87, 0xda,
+ 0xc5, 0x41, 0xfd, 0x61, 0x9d, 0xff, 0xfc, 0x37, 0x73, 0x73, 0xd1, 0xf7,
+ 0x6e, 0x72, 0x00, 0xb1, 0x7f, 0xcd, 0x22, 0xcf, 0x93, 0xc9, 0x62, 0xff,
+ 0xfd, 0x2c, 0x21, 0xfe, 0x30, 0xa0, 0x07, 0x79, 0x2c, 0x51, 0x22, 0x28,
+ 0x33, 0x7b, 0xce, 0xfd, 0x2a, 0x24, 0xc2, 0xfd, 0x3b, 0x9c, 0x6c, 0xb1,
+ 0x78, 0x23, 0x71, 0x62, 0xa4, 0x89, 0x5e, 0x88, 0xd8, 0xa8, 0x21, 0x4d,
+ 0xed, 0x8b, 0x63, 0x0a, 0xac, 0x5f, 0xf9, 0xdb, 0xd1, 0xf6, 0x3b, 0x8d,
+ 0x62, 0x82, 0xc3, 0xe9, 0xf9, 0x65, 0xff, 0xee, 0x0f, 0xf1, 0xf8, 0x3e,
+ 0xb4, 0xdd, 0x2c, 0x57, 0x47, 0xe6, 0xe4, 0xf7, 0xff, 0xff, 0xb3, 0xa8,
+ 0x17, 0x5f, 0x8d, 0x6d, 0xc2, 0x6e, 0xf8, 0x1c, 0xe5, 0x83, 0x58, 0xbf,
+ 0xdb, 0xdc, 0xf8, 0x6c, 0x71, 0x62, 0xf7, 0x72, 0xe6, 0xd4, 0x59, 0xe3,
+ 0xed, 0xfe, 0xce, 0xfd, 0xe7, 0x97, 0x16, 0x2a, 0x13, 0x41, 0xc8, 0x6a,
+ 0xe8, 0xde, 0xff, 0x13, 0xfb, 0x9d, 0x08, 0x96, 0x2f, 0xff, 0x80, 0xc0,
+ 0x33, 0x1b, 0x79, 0x67, 0xbe, 0xcb, 0x17, 0xa7, 0xf3, 0x2c, 0x5f, 0xfc,
+ 0x4e, 0x67, 0x0c, 0x71, 0xc7, 0x7c, 0x58, 0xb6, 0x2c, 0x56, 0x8f, 0x63,
+ 0xc8, 0xf7, 0xee, 0x3b, 0xcb, 0x8b, 0x17, 0xdf, 0x11, 0x4e, 0xb1, 0x7f,
+ 0x3c, 0xb9, 0x84, 0x05, 0x8b, 0x3e, 0xd4, 0xc4, 0x46, 0xed, 0xd9, 0x13,
+ 0x94, 0x78, 0x92, 0xda, 0xc4, 0xed, 0x3f, 0x1b, 0x15, 0xff, 0xfc, 0xf3,
+ 0x94, 0x77, 0xdf, 0x42, 0x7d, 0x03, 0x3b, 0xf2, 0xc5, 0x62, 0xa7, 0x76,
+ 0x8f, 0xa0, 0x8b, 0xef, 0xf9, 0xe5, 0xcc, 0x28, 0xef, 0x8b, 0x17, 0xdc,
+ 0x93, 0x01, 0x62, 0xff, 0xf1, 0xaf, 0xcd, 0x6b, 0x27, 0x01, 0xe2, 0x4b,
+ 0x17, 0xde, 0xf4, 0x69, 0x62, 0xbc, 0x7e, 0x01, 0xa6, 0xd4, 0x91, 0x6c,
+ 0x64, 0x24, 0xef, 0xff, 0xfd, 0xfc, 0x97, 0xf0, 0x65, 0x1d, 0x07, 0x06,
+ 0x67, 0x38, 0xe6, 0xac, 0x54, 0x22, 0x63, 0xc5, 0x37, 0xfe, 0x33, 0x06,
+ 0xf2, 0xf7, 0x1c, 0x0b, 0x17, 0xff, 0x8a, 0x0c, 0x0f, 0xc5, 0x00, 0xce,
+ 0xfc, 0xb1, 0x7f, 0xb3, 0x5f, 0x28, 0xee, 0x4b, 0x17, 0x3f, 0x78, 0x88,
+ 0x00, 0xd3, 0x29, 0x91, 0xde, 0x28, 0x60, 0x5f, 0xfc, 0xdd, 0x99, 0xef,
+ 0xb4, 0x16, 0x74, 0xb1, 0x7f, 0xe2, 0x73, 0x81, 0xb4, 0xdd, 0x81, 0x62,
+ 0xfb, 0x1b, 0x53, 0xac, 0x50, 0xcf, 0x88, 0x2e, 0x7f, 0x7f, 0xcc, 0x6c,
+ 0x0e, 0x73, 0xc6, 0x96, 0x2a, 0x4c, 0xc2, 0x51, 0x93, 0x64, 0x24, 0xcd,
+ 0x24, 0xea, 0x15, 0x6c, 0x41, 0xa8, 0xde, 0x4f, 0x29, 0x73, 0xf2, 0xaa,
+ 0xc0, 0x6a, 0x51, 0xc3, 0xf2, 0x31, 0x1f, 0x13, 0x8a, 0x15, 0x1b, 0xc9,
+ 0xaf, 0xe1, 0x80, 0x2b, 0xc0, 0x6e, 0x2c, 0x5e, 0x08, 0x12, 0x16, 0x2f,
+ 0xfe, 0xc3, 0x3e, 0xfe, 0xe4, 0x7c, 0x39, 0x96, 0x2f, 0xff, 0x66, 0xbe,
+ 0xed, 0xe1, 0x69, 0xf7, 0xe2, 0xc5, 0x0d, 0x12, 0x7f, 0x48, 0xbd, 0xc6,
+ 0x1a, 0xc5, 0xfc, 0x51, 0xd9, 0xdf, 0xcb, 0x17, 0xfb, 0xaf, 0x0b, 0xfa,
+ 0x83, 0x16, 0x2f, 0xfe, 0xce, 0xff, 0x83, 0xfe, 0x4d, 0x27, 0x58, 0xa8,
+ 0x3f, 0xd3, 0x9b, 0xdf, 0xff, 0xfe, 0x68, 0x2f, 0x75, 0xf6, 0xf6, 0x4c,
+ 0x50, 0x7c, 0xfb, 0x6b, 0xee, 0xb1, 0x7f, 0xcd, 0x86, 0x75, 0xf8, 0x6d,
+ 0xc5, 0x8b, 0xff, 0xd0, 0x52, 0xc1, 0x6a, 0x70, 0x66, 0x0d, 0x62, 0xff,
+ 0x74, 0xda, 0xe4, 0xd0, 0xeb, 0x17, 0xf9, 0xbc, 0x08, 0xf8, 0x7c, 0x58,
+ 0xbe, 0x79, 0x41, 0x2c, 0x5f, 0x85, 0xcf, 0xbc, 0xa4, 0x7a, 0xdf, 0x35,
+ 0xbf, 0x9c, 0x18, 0x43, 0x92, 0xc5, 0xff, 0xcf, 0xdf, 0xbf, 0x8c, 0x38,
+ 0x2e, 0x96, 0x28, 0xd4, 0xe1, 0xbb, 0x4a, 0xd4, 0x22, 0xc8, 0xff, 0x85,
+ 0xb6, 0x61, 0xab, 0x96, 0x98, 0x8f, 0x43, 0xa7, 0x85, 0x5f, 0xc8, 0x42,
+ 0xee, 0xde, 0x8f, 0x0e, 0xfc, 0x38, 0xe7, 0x99, 0x62, 0xfd, 0x93, 0x9d,
+ 0xa6, 0x58, 0xa8, 0x5d, 0x17, 0xfc, 0xe2, 0x53, 0xbd, 0x91, 0x45, 0xff,
+ 0xe7, 0x20, 0x02, 0x33, 0x7b, 0x17, 0x7e, 0x58, 0xbe, 0xf3, 0x1d, 0xd6,
+ 0x2f, 0x8c, 0xf8, 0xba, 0x58, 0xb1, 0xab, 0x17, 0xf7, 0xf9, 0x1e, 0x81,
+ 0xac, 0x54, 0x1f, 0x3e, 0x13, 0x30, 0x9d, 0x42, 0x60, 0x18, 0x97, 0xe8,
+ 0x44, 0xdf, 0xfe, 0x13, 0xfd, 0xc7, 0x23, 0xfe, 0x03, 0x25, 0x8b, 0xc5,
+ 0x07, 0x58, 0xbf, 0x37, 0x3f, 0x1a, 0x58, 0xa9, 0x8f, 0x13, 0xe3, 0x97,
+ 0xfb, 0xfe, 0x69, 0xcf, 0x1d, 0x2c, 0x5f, 0xff, 0xf6, 0xa7, 0x10, 0x36,
+ 0xfb, 0x99, 0xed, 0xb9, 0xe8, 0xc2, 0x92, 0xc5, 0x42, 0x28, 0x98, 0xda,
+ 0xff, 0xfc, 0xfd, 0x6a, 0x3e, 0x59, 0xec, 0xd9, 0x30, 0xc3, 0x12, 0x2a,
+ 0x4a, 0x81, 0x7a, 0x34, 0x78, 0x47, 0xf2, 0x18, 0xbe, 0x21, 0xbf, 0x74,
+ 0x2e, 0x8a, 0x16, 0x2f, 0xe3, 0x03, 0xd6, 0x9c, 0x6b, 0x17, 0xd3, 0x7e,
+ 0x3c, 0xb1, 0x4c, 0x7a, 0xbc, 0x31, 0xae, 0x91, 0x41, 0x33, 0xfd, 0xfc,
+ 0x16, 0x05, 0xbf, 0xb6, 0x10, 0x53, 0x75, 0x62, 0xfb, 0xdd, 0x0a, 0x75,
+ 0x8b, 0xfb, 0x87, 0x11, 0x4b, 0x8b, 0x14, 0x47, 0xab, 0xe2, 0x6b, 0xff,
+ 0xbb, 0x91, 0x44, 0xb5, 0x1e, 0x7f, 0x2c, 0x5f, 0xf0, 0xc3, 0x8e, 0xf7,
+ 0x33, 0x50, 0xb1, 0x74, 0x49, 0x62, 0xa1, 0x17, 0x78, 0x42, 0xe8, 0xa4,
+ 0x7d, 0x7c, 0x7d, 0x3f, 0x16, 0x2f, 0xfd, 0x13, 0xe7, 0x50, 0x76, 0xe7,
+ 0x4b, 0x17, 0xc2, 0xdd, 0x89, 0x2c, 0x5f, 0xf9, 0xfd, 0x1a, 0xe7, 0xe0,
+ 0xbc, 0xb1, 0x7e, 0xc9, 0x33, 0xef, 0x58, 0xaf, 0xa2, 0x34, 0x89, 0xb8,
+ 0x7d, 0x52, 0x4d, 0x67, 0x0e, 0x7e, 0x46, 0x28, 0x67, 0x5e, 0x3b, 0xfd,
+ 0x62, 0xff, 0xf1, 0x44, 0xb5, 0xa1, 0x76, 0xda, 0x7e, 0x2c, 0x5f, 0xff,
+ 0x73, 0x0d, 0x2c, 0xf7, 0x32, 0x44, 0xe6, 0x2c, 0x59, 0xbe, 0x89, 0xbf,
+ 0x25, 0xd3, 0x23, 0x83, 0x7c, 0x2e, 0x2f, 0xf4, 0x17, 0xb0, 0xa0, 0xd5,
+ 0x8b, 0xd1, 0xfe, 0x2c, 0x56, 0xf3, 0xcf, 0x08, 0x65, 0x7f, 0xd0, 0x7f,
+ 0x7f, 0x0a, 0x00, 0xb1, 0x7e, 0x3c, 0x4b, 0x77, 0xa5, 0x8b, 0xf1, 0x40,
+ 0xbd, 0xc5, 0x8a, 0x01, 0xea, 0xf8, 0xb6, 0xff, 0xb9, 0x26, 0xf0, 0x03,
+ 0x29, 0x2c, 0x54, 0xe7, 0xbb, 0xd9, 0x15, 0xfc, 0x59, 0xef, 0x86, 0x62,
+ 0xc5, 0xfd, 0xec, 0x9a, 0x4e, 0x4b, 0x15, 0xd9, 0xef, 0x1c, 0xc2, 0xb1,
+ 0x14, 0xad, 0x08, 0x2a, 0x85, 0x4a, 0x78, 0xf0, 0xc4, 0xda, 0x8e, 0x3e,
+ 0xff, 0xff, 0xbb, 0xeb, 0xec, 0x72, 0x69, 0xe3, 0xdc, 0x0f, 0xdf, 0xc1,
+ 0xac, 0x5f, 0xf1, 0xbb, 0x43, 0xcd, 0x6e, 0x39, 0xab, 0x16, 0x0b, 0xac,
+ 0x54, 0x1e, 0xc3, 0xa1, 0x5f, 0xff, 0xc4, 0xe6, 0xfe, 0x1a, 0x4c, 0x5e,
+ 0x96, 0x6b, 0x16, 0x2a, 0x13, 0x3c, 0x28, 0x61, 0x88, 0x82, 0xff, 0xf6,
+ 0x17, 0xdf, 0x85, 0x86, 0x9b, 0x9b, 0xab, 0x17, 0xfd, 0x1d, 0xc8, 0x53,
+ 0x8d, 0xb7, 0xac, 0x57, 0x48, 0x8b, 0xfa, 0x6d, 0xff, 0xbb, 0xf6, 0x10,
+ 0xbc, 0x08, 0x92, 0xc5, 0xdb, 0x86, 0xac, 0x58, 0x18, 0x7b, 0x8e, 0x81,
+ 0x7f, 0xf3, 0x73, 0x07, 0xd4, 0x4f, 0x19, 0xe5, 0x8b, 0xf0, 0xbf, 0xe8,
+ 0x99, 0x62, 0xff, 0xfe, 0xfb, 0xeb, 0xec, 0x58, 0x3d, 0x30, 0xa7, 0x0c,
+ 0xeb, 0x17, 0xff, 0xde, 0x8e, 0x9b, 0xcc, 0x7d, 0xbc, 0x71, 0x8d, 0x62,
+ 0xff, 0x67, 0x26, 0xfb, 0x19, 0xe5, 0x8b, 0xfd, 0xf7, 0x38, 0xf3, 0x69,
+ 0xd6, 0x2f, 0xfb, 0x5a, 0x8c, 0x7d, 0x77, 0x25, 0x8b, 0xf9, 0xa6, 0xd3,
+ 0x19, 0x3a, 0xc5, 0xc0, 0x85, 0x8a, 0x84, 0x77, 0x0c, 0xd9, 0x8d, 0xbe,
+ 0x74, 0x03, 0x1b, 0xff, 0x7d, 0xb7, 0xe6, 0xe8, 0xc9, 0xf4, 0xb1, 0x7c,
+ 0x29, 0xfb, 0xdd, 0x58, 0xae, 0x8f, 0xb0, 0x90, 0xef, 0xe6, 0x19, 0xe0,
+ 0x70, 0xb1, 0x43, 0x55, 0x42, 0xcb, 0xbc, 0x8d, 0x07, 0xd0, 0xb4, 0xdc,
+ 0x22, 0xbf, 0xfd, 0x13, 0x96, 0x64, 0xfe, 0x36, 0x0a, 0x4b, 0x17, 0xfa,
+ 0x7f, 0xb9, 0xdb, 0x8c, 0xb1, 0x7f, 0x86, 0xee, 0x60, 0x79, 0xda, 0xc5,
+ 0x9c, 0x8f, 0xab, 0xc6, 0x95, 0x0b, 0x9d, 0x59, 0x08, 0x0e, 0x89, 0xbe,
+ 0x8a, 0xf2, 0xb2, 0xc9, 0x64, 0xc8, 0x5a, 0xdf, 0xf0, 0xff, 0x18, 0x32,
+ 0xcd, 0xeb, 0x17, 0xe7, 0x3f, 0xb3, 0xa5, 0x8b, 0xff, 0x6e, 0xff, 0x30,
+ 0x65, 0x93, 0xc2, 0xc5, 0x7c, 0xfa, 0x84, 0x53, 0x7f, 0xfe, 0xfb, 0x16,
+ 0x4e, 0x71, 0x7f, 0x3e, 0xfd, 0x81, 0x62, 0xff, 0xbc, 0xdc, 0x61, 0x05,
+ 0xc7, 0x0b, 0x17, 0x8c, 0x30, 0xc4, 0x8b, 0xe9, 0xce, 0xdc, 0x48, 0xd9,
+ 0x34, 0x37, 0x40, 0xd6, 0x29, 0xcf, 0x38, 0x8d, 0xef, 0xc1, 0xfd, 0xff,
+ 0x0b, 0x17, 0xfc, 0xdc, 0x89, 0x4d, 0xf6, 0x02, 0xc5, 0xfe, 0xce, 0xf5,
+ 0x9b, 0x8c, 0x05, 0x8a, 0x92, 0xa8, 0x31, 0xc2, 0x90, 0xd2, 0x26, 0x57,
+ 0xd4, 0x2b, 0x0e, 0x41, 0xf2, 0x92, 0x3a, 0xbf, 0xff, 0x70, 0xb3, 0xfe,
+ 0x28, 0x04, 0xa2, 0x38, 0xcb, 0x16, 0xfa, 0xc5, 0x76, 0x7c, 0xa1, 0xa9,
+ 0xdf, 0xbd, 0xcf, 0x70, 0x28, 0xb1, 0x7e, 0x8c, 0x27, 0x3a, 0xc5, 0xff,
+ 0x9e, 0x5f, 0x6e, 0xc1, 0xa7, 0x1a, 0xc5, 0xef, 0x6b, 0x16, 0x2e, 0x19,
+ 0x8b, 0x17, 0xff, 0xec, 0xdf, 0x05, 0xe3, 0xc6, 0x10, 0xf3, 0xbf, 0x2c,
+ 0x5e, 0x72, 0xea, 0x11, 0x19, 0x38, 0xee, 0x86, 0x69, 0x93, 0x85, 0x72,
+ 0x40, 0x17, 0x11, 0x30, 0xa1, 0x99, 0x7e, 0xd4, 0xf1, 0xa9, 0xd6, 0x2f,
+ 0xcc, 0x5e, 0x0c, 0xeb, 0x16, 0x94, 0x1e, 0xa0, 0x0a, 0xef, 0xff, 0xdf,
+ 0x6e, 0xbf, 0x9e, 0xfb, 0x38, 0x3e, 0xc0, 0x58, 0xbf, 0xfd, 0xfc, 0xe7,
+ 0x30, 0xe3, 0x6d, 0xf0, 0x35, 0x8b, 0xfa, 0x0f, 0x37, 0xdb, 0x4b, 0x17,
+ 0xee, 0x61, 0xdf, 0xb5, 0x8b, 0xf1, 0xbb, 0x73, 0x34, 0xb1, 0x58, 0x7a,
+ 0x82, 0x29, 0xbf, 0x71, 0xb0, 0x80, 0xb1, 0x5a, 0x3c, 0x8e, 0x10, 0xde,
+ 0xd6, 0x6e, 0xac, 0x5f, 0xfe, 0x17, 0x3e, 0xd9, 0x33, 0x4f, 0x9d, 0xf9,
+ 0x62, 0xff, 0x8c, 0x0e, 0x7e, 0x61, 0xe3, 0x75, 0x62, 0xff, 0xf0, 0xbb,
+ 0xcd, 0x07, 0xee, 0x61, 0xad, 0xa5, 0x8b, 0xff, 0xcd, 0xd6, 0x10, 0xf4,
+ 0xfd, 0x67, 0x7e, 0x58, 0xa8, 0x46, 0xd7, 0xd0, 0x38, 0x9d, 0x7f, 0xe6,
+ 0x20, 0xf2, 0x6e, 0x37, 0x66, 0x2c, 0x5f, 0x38, 0x3c, 0x17, 0x58, 0xac,
+ 0x56, 0xdd, 0xd2, 0xb4, 0xc9, 0x9a, 0x86, 0x59, 0xc8, 0x88, 0x83, 0xd1,
+ 0x93, 0xef, 0x2f, 0x31, 0x0a, 0xfd, 0x9d, 0xfb, 0xf0, 0xb1, 0x7e, 0x6d,
+ 0xfe, 0x8c, 0x58, 0xbf, 0xcd, 0xbf, 0xb8, 0x28, 0xe2, 0xc5, 0xfd, 0x05,
+ 0xf7, 0x73, 0xac, 0x54, 0x8f, 0x84, 0x06, 0xb5, 0xf4, 0x6a, 0xf0, 0xa7,
+ 0xd0, 0x8a, 0xa8, 0x5d, 0x2d, 0xc9, 0x72, 0xaf, 0x1b, 0x1d, 0xfd, 0x1e,
+ 0xe0, 0x65, 0x25, 0x8b, 0xe8, 0xeb, 0x09, 0x62, 0xfe, 0x6e, 0x72, 0x35,
+ 0x2d, 0x1e, 0x8f, 0xcb, 0xef, 0xe0, 0xf3, 0x5b, 0x8e, 0x6a, 0xc5, 0xfb,
+ 0x35, 0xb8, 0xe6, 0xac, 0x5d, 0x9c, 0xda, 0x7b, 0xe1, 0x99, 0xdf, 0xfe,
+ 0x98, 0xa3, 0xdc, 0xf7, 0x7d, 0x31, 0x4e, 0xb1, 0x7f, 0xec, 0x2f, 0x69,
+ 0xdf, 0xb9, 0x71, 0x62, 0xff, 0x9c, 0xdd, 0xbf, 0x80, 0x46, 0xea, 0xc5,
+ 0xfd, 0x12, 0xcd, 0xed, 0xa5, 0x8a, 0xc4, 0xca, 0xd8, 0xc3, 0xe9, 0xce,
+ 0x7e, 0x47, 0xf7, 0xff, 0xfe, 0x00, 0x65, 0x9a, 0xd6, 0x19, 0x9b, 0xb8,
+ 0x50, 0x03, 0xbc, 0x96, 0x2f, 0xff, 0xff, 0xf8, 0xb3, 0x80, 0xeb, 0x09,
+ 0xbb, 0xe1, 0x67, 0xb9, 0x92, 0x27, 0x33, 0xbf, 0x09, 0xf8, 0xb1, 0x66,
+ 0x24, 0xc1, 0x37, 0xb7, 0xdf, 0xff, 0xde, 0xe0, 0x87, 0xf6, 0xc9, 0x9d,
+ 0xb7, 0x5b, 0xb9, 0x2c, 0x5f, 0xff, 0xc5, 0x80, 0x72, 0x06, 0xb5, 0x86,
+ 0x60, 0x1f, 0xb5, 0x8a, 0x24, 0x5d, 0xf9, 0x82, 0xfc, 0xde, 0x9f, 0x0c,
+ 0x58, 0xbf, 0xe8, 0xeb, 0xe4, 0x2f, 0x47, 0x16, 0x2f, 0xd3, 0x49, 0xb5,
+ 0xc5, 0x8b, 0xfe, 0x8e, 0xa0, 0xf8, 0x37, 0x3a, 0xc5, 0x68, 0xf8, 0xc2,
+ 0x15, 0x5f, 0xb7, 0x43, 0x28, 0xe9, 0x62, 0x98, 0xf4, 0x5c, 0x92, 0xff,
+ 0xe9, 0x73, 0x20, 0x6c, 0x4f, 0xa3, 0x56, 0x2f, 0xda, 0x8c, 0x1b, 0x2c,
+ 0x5f, 0xdf, 0x61, 0x8f, 0x0c, 0x58, 0xbf, 0x6b, 0x37, 0xff, 0x36, 0x9e,
+ 0xb7, 0x44, 0xf5, 0x08, 0xdd, 0x78, 0x4d, 0x5f, 0xff, 0xff, 0x03, 0x99,
+ 0x2f, 0xc3, 0x68, 0x00, 0x8d, 0x60, 0x8d, 0x1b, 0x69, 0xf8, 0xb1, 0x7f,
+ 0xfd, 0xfc, 0x96, 0xde, 0xbe, 0xde, 0xef, 0xa6, 0xd2, 0xc5, 0x42, 0x35,
+ 0x3c, 0xfd, 0x7f, 0xff, 0x05, 0xdb, 0xdf, 0x8d, 0x69, 0xbb, 0xfe, 0x61,
+ 0x74, 0xb1, 0x52, 0x5c, 0x98, 0x68, 0x72, 0xe8, 0x88, 0xe5, 0x5f, 0x87,
+ 0x70, 0x21, 0xfa, 0x50, 0xfa, 0x11, 0x15, 0xfe, 0x8c, 0xe6, 0xb3, 0xb9,
+ 0x2c, 0x5f, 0xfe, 0xf4, 0x1f, 0xa7, 0x1e, 0x18, 0x1e, 0xa4, 0xb1, 0x7f,
+ 0xef, 0xc1, 0x1b, 0xd3, 0x41, 0x49, 0x62, 0xf4, 0xfb, 0xc6, 0xb1, 0x52,
+ 0x3e, 0x02, 0x3f, 0xbf, 0xf3, 0xeb, 0x69, 0x3f, 0xa4, 0xe3, 0x58, 0xbf,
+ 0xff, 0x98, 0x87, 0xac, 0xeb, 0xf1, 0xfc, 0xd6, 0xa0, 0xd5, 0x8a, 0x92,
+ 0x27, 0x3e, 0x81, 0x7f, 0x3b, 0xfb, 0x71, 0xba, 0x58, 0xbf, 0xfc, 0x6e,
+ 0x7d, 0xfd, 0xce, 0xe4, 0x27, 0xf2, 0xc5, 0xf6, 0x9b, 0x3e, 0xb1, 0x7f,
+ 0x60, 0x79, 0xa6, 0x25, 0x8a, 0xd1, 0xe7, 0xef, 0x22, 0xbf, 0xff, 0xff,
+ 0xda, 0xe7, 0x23, 0x5d, 0x75, 0xf6, 0x99, 0xdf, 0x59, 0xdf, 0xbb, 0xe8,
+ 0x4e, 0x5d, 0xf9, 0x62, 0xff, 0x8e, 0xe3, 0x0c, 0x24, 0x14, 0x96, 0x2f,
+ 0xfb, 0xa1, 0x6e, 0xf1, 0x8c, 0xcd, 0x2c, 0x54, 0x1f, 0xdf, 0x47, 0x97,
+ 0xff, 0x7d, 0xa6, 0x27, 0x33, 0xd9, 0xf3, 0xac, 0x5f, 0x9b, 0x38, 0xe4,
+ 0xb1, 0x7e, 0xf0, 0xb4, 0xfc, 0xe8, 0xfb, 0x3c, 0x8d, 0x7f, 0xfb, 0x99,
+ 0xad, 0xbd, 0x7d, 0xb7, 0xb1, 0x0d, 0x62, 0x99, 0x11, 0xfc, 0x40, 0xbf,
+ 0xff, 0x39, 0x4e, 0x3f, 0xc6, 0xb5, 0x9c, 0xe0, 0x89, 0x62, 0xa1, 0x56,
+ 0x56, 0x12, 0x34, 0x62, 0x2f, 0x18, 0xe9, 0x84, 0x57, 0xfe, 0x61, 0x8b,
+ 0xdc, 0x82, 0x6c, 0x58, 0xbf, 0xe3, 0xc6, 0xb7, 0xe6, 0xa2, 0x65, 0x8b,
+ 0xff, 0xf6, 0x98, 0x53, 0xfb, 0xf0, 0xda, 0xd3, 0x14, 0xeb, 0x17, 0xe2,
+ 0x89, 0x05, 0x5d, 0x62, 0xff, 0xe8, 0xcd, 0x49, 0xfd, 0xf7, 0x20, 0x2c,
+ 0x5f, 0xff, 0xbe, 0x2e, 0xfd, 0xc7, 0xef, 0xad, 0xcc, 0xe7, 0x31, 0x62,
+ 0xff, 0x9c, 0xef, 0xef, 0xb9, 0x01, 0x62, 0x86, 0x9a, 0xd6, 0x2b, 0xfc,
+ 0xaf, 0xc8, 0x7b, 0xd7, 0x6f, 0xff, 0x31, 0x14, 0x19, 0xec, 0x9c, 0x2c,
+ 0x0b, 0x02, 0x8b, 0x15, 0x88, 0xa5, 0x74, 0xcb, 0xff, 0x6b, 0xa3, 0xc7,
+ 0x7c, 0xcd, 0xf8, 0xb1, 0x73, 0xee, 0xac, 0x5e, 0x7d, 0x1a, 0xb1, 0x7f,
+ 0xff, 0x4c, 0x50, 0x3c, 0xef, 0xd9, 0x28, 0x29, 0xcf, 0x8b, 0x17, 0x61,
+ 0xd6, 0x2f, 0xfc, 0x58, 0x36, 0x72, 0x9c, 0xf8, 0xb1, 0x78, 0x1b, 0x98,
+ 0x33, 0xd4, 0x0c, 0x5e, 0xb4, 0x98, 0x2f, 0xc7, 0x8a, 0x16, 0x17, 0xde,
+ 0x7d, 0x71, 0x62, 0xfd, 0xb7, 0x73, 0x35, 0x0b, 0x15, 0x39, 0xe8, 0x11,
+ 0x1d, 0x42, 0xa0, 0x99, 0xd0, 0xf2, 0x31, 0xf7, 0x84, 0x2d, 0xfe, 0x83,
+ 0x47, 0x93, 0x47, 0xd6, 0x2f, 0xfa, 0x4d, 0xee, 0x75, 0x1e, 0xe2, 0xc5,
+ 0xfc, 0x0d, 0xb8, 0x37, 0x92, 0xc5, 0x4c, 0x7d, 0x6e, 0x77, 0x63, 0x56,
+ 0x2f, 0xfe, 0xce, 0xbf, 0x1f, 0xcd, 0x6a, 0x0d, 0x58, 0xbf, 0x66, 0xb5,
+ 0x06, 0xac, 0x5f, 0x13, 0x03, 0x90, 0x88, 0x2d, 0x09, 0xfd, 0x1a, 0xff,
+ 0xbe, 0xe0, 0x3b, 0xc9, 0xf8, 0xb1, 0x7f, 0x9e, 0x52, 0x89, 0x75, 0xc5,
+ 0x8a, 0xc3, 0xee, 0x11, 0xcd, 0xff, 0xff, 0xcd, 0xef, 0xe0, 0xe4, 0xde,
+ 0xc3, 0xf1, 0xe5, 0xb9, 0x9c, 0xe6, 0x2c, 0x54, 0x95, 0x46, 0x64, 0x28,
+ 0x1a, 0x14, 0x9f, 0x85, 0x9f, 0x08, 0x6f, 0xff, 0x3c, 0xff, 0x68, 0x2c,
+ 0x99, 0xb4, 0xcb, 0x17, 0xff, 0xec, 0xde, 0x42, 0xe6, 0xa2, 0x4d, 0xe6,
+ 0x29, 0x2c, 0x54, 0x9b, 0x65, 0x31, 0xc7, 0x9d, 0x93, 0xbc, 0x66, 0xc2,
+ 0x1b, 0xb3, 0x46, 0x85, 0x74, 0xd0, 0xbd, 0xd1, 0x19, 0xcc, 0x7f, 0x2d,
+ 0x99, 0xd5, 0x40, 0x7a, 0x52, 0x8e, 0xf9, 0x28, 0xab, 0xd2, 0xb5, 0x0c,
+ 0x59, 0x0d, 0x26, 0xff, 0xbe, 0xfc, 0x62, 0x28, 0xed, 0x62, 0xff, 0x37,
+ 0xe3, 0xb9, 0x61, 0xd6, 0x2f, 0xb0, 0x98, 0x7c, 0x3e, 0xcd, 0xc3, 0x8b,
+ 0xff, 0x8b, 0xdc, 0x0f, 0xcc, 0x51, 0xdc, 0x96, 0x2f, 0xc5, 0x9f, 0x7f,
+ 0x2c, 0x5f, 0xfa, 0x50, 0x53, 0x87, 0xa2, 0x14, 0x96, 0x2f, 0x73, 0x34,
+ 0xb1, 0x7f, 0x13, 0x8c, 0x1d, 0x81, 0x62, 0xb1, 0x1f, 0x5b, 0xa8, 0xd3,
+ 0x13, 0xfd, 0x07, 0x83, 0xb7, 0xff, 0x39, 0x4b, 0x4f, 0xdf, 0xe3, 0x38,
+ 0xb1, 0x7f, 0xf7, 0x4d, 0xaf, 0xe4, 0xdf, 0x6d, 0x4e, 0xb1, 0x7f, 0xf8,
+ 0xb0, 0xc7, 0x06, 0xdf, 0x7e, 0x1b, 0xa5, 0x8b, 0xef, 0x4f, 0x83, 0x58,
+ 0xbf, 0xe6, 0x34, 0x3d, 0x00, 0xed, 0xc5, 0x8a, 0x35, 0x15, 0xb3, 0x26,
+ 0xee, 0x12, 0x5f, 0xfc, 0x58, 0x0c, 0xde, 0xc6, 0x81, 0xfc, 0xb1, 0x7f,
+ 0xe6, 0xef, 0x80, 0x72, 0x1c, 0xc2, 0x58, 0xbc, 0x61, 0x86, 0x2c, 0x5f,
+ 0xfc, 0x50, 0x0c, 0x1f, 0x30, 0xf1, 0xd2, 0x46, 0xc9, 0xa1, 0xa0, 0x22,
+ 0xe7, 0xcc, 0x57, 0xfb, 0xed, 0x83, 0x82, 0xf2, 0xc5, 0x49, 0x35, 0x43,
+ 0xc3, 0xff, 0x79, 0x1d, 0xff, 0x9c, 0x1d, 0x7d, 0xa6, 0x28, 0x02, 0xc5,
+ 0x61, 0xfc, 0x31, 0xc5, 0xfd, 0xac, 0x09, 0xf7, 0x1a, 0xc5, 0xff, 0xb3,
+ 0xbd, 0xa5, 0x9b, 0xf4, 0xdc, 0x58, 0xbf, 0xba, 0xfb, 0x41, 0x74, 0xb1,
+ 0x50, 0x7e, 0x58, 0x87, 0x7f, 0xb5, 0x1e, 0x6e, 0x98, 0x6b, 0x17, 0xe9,
+ 0x4d, 0x99, 0xd2, 0xc5, 0xfe, 0x14, 0xf0, 0xc3, 0xc3, 0xac, 0x5b, 0x4b,
+ 0x14, 0x14, 0x45, 0x24, 0x1a, 0x11, 0x50, 0x66, 0x97, 0xe3, 0x30, 0xef,
+ 0xda, 0xc5, 0xf0, 0x31, 0xf7, 0x56, 0x2a, 0x0f, 0x3d, 0x8a, 0xaa, 0x4b,
+ 0xde, 0x19, 0x19, 0xa1, 0xa9, 0xbd, 0xa2, 0x34, 0x3d, 0x7f, 0x28, 0x05,
+ 0xc8, 0x0a, 0x14, 0x5c, 0x86, 0x27, 0xa1, 0x1f, 0x7b, 0x9b, 0x4d, 0x58,
+ 0xbd, 0x3c, 0x7d, 0x62, 0xb6, 0x9b, 0xf2, 0x21, 0xbf, 0x7f, 0xdc, 0x16,
+ 0xea, 0xc5, 0xc6, 0x05, 0x16, 0x2a, 0x0f, 0x2b, 0xb2, 0xdb, 0xfe, 0x27,
+ 0x37, 0xdc, 0x26, 0x35, 0x62, 0xfd, 0xef, 0x31, 0xf8, 0xb1, 0x73, 0xb2,
+ 0xc5, 0xfb, 0xbf, 0x6f, 0xc2, 0x58, 0xbf, 0x3f, 0xa4, 0xe3, 0x58, 0xb1,
+ 0xb8, 0x7a, 0x64, 0x57, 0x74, 0xbe, 0xb1, 0x58, 0x98, 0x5b, 0x1d, 0x7c,
+ 0xa5, 0xda, 0x7c, 0x4f, 0x66, 0x58, 0xbf, 0xff, 0xc6, 0x41, 0x41, 0xa5,
+ 0x06, 0x87, 0xb9, 0x1a, 0x8e, 0xa1, 0x62, 0xff, 0xa2, 0x76, 0x3f, 0xb3,
+ 0x0e, 0xb1, 0x7f, 0xfd, 0x07, 0x28, 0xec, 0x03, 0xc3, 0xcf, 0x86, 0x2c,
+ 0x5f, 0xdf, 0x8d, 0xbd, 0x34, 0xeb, 0x17, 0xfe, 0x73, 0xe6, 0x8d, 0x34,
+ 0x45, 0xe5, 0x8b, 0xfd, 0x1e, 0xe7, 0x18, 0xa6, 0x58, 0xaf, 0x9f, 0xa9,
+ 0x20, 0xdf, 0xf8, 0xc7, 0x29, 0x7c, 0x51, 0xdf, 0x16, 0x2f, 0xff, 0xe7,
+ 0x3e, 0xb3, 0x7c, 0x17, 0xb3, 0xed, 0xaf, 0xba, 0xc5, 0xff, 0x3f, 0xb9,
+ 0xef, 0x3c, 0xb8, 0xb1, 0x53, 0x23, 0xdf, 0x44, 0x3f, 0x41, 0x25, 0xbb,
+ 0xff, 0x9f, 0x4f, 0x2c, 0xe3, 0xfb, 0x26, 0x58, 0xbf, 0xef, 0x6a, 0x33,
+ 0xbd, 0xaf, 0xc5, 0x8b, 0xfb, 0x4f, 0xa2, 0x89, 0x2c, 0x5f, 0xc5, 0x3b,
+ 0x6b, 0x7c, 0x96, 0x2f, 0xff, 0xf7, 0xbd, 0x12, 0x27, 0xfc, 0x1f, 0xf8,
+ 0x37, 0xec, 0x96, 0x2f, 0xd9, 0xde, 0x3e, 0xea, 0xc5, 0xff, 0xef, 0x7f,
+ 0x37, 0xfd, 0xb6, 0xf3, 0x8c, 0x75, 0x8a, 0x84, 0xc2, 0xf0, 0xc7, 0xec,
+ 0x0e, 0x57, 0x7f, 0xd2, 0x6d, 0x77, 0x05, 0x1c, 0x58, 0xbc, 0x63, 0xce,
+ 0xb1, 0x7f, 0xd1, 0x93, 0xea, 0x3c, 0xfe, 0x58, 0xa6, 0x44, 0x8f, 0xce,
+ 0x44, 0x3f, 0x5b, 0x09, 0x76, 0x42, 0x04, 0x67, 0x66, 0x91, 0xc8, 0xd4,
+ 0xb2, 0x39, 0xee, 0x8f, 0x7b, 0x44, 0xd1, 0xe1, 0x46, 0x71, 0xe8, 0x66,
+ 0x5f, 0xd2, 0x89, 0xb1, 0x80, 0xb1, 0x6d, 0x90, 0xa3, 0xf1, 0xf9, 0xec,
+ 0x02, 0xdb, 0x13, 0x70, 0x5a, 0x2c, 0x89, 0x65, 0xd3, 0xca, 0x1d, 0x94,
+ 0x71, 0xe3, 0x96, 0x95, 0x94, 0xd5, 0x23, 0x63, 0x00, 0xea, 0x75, 0x3b,
+ 0xb9, 0x69, 0x4d, 0x0f, 0x6d, 0xd2, 0x59, 0xa5, 0x59, 0x6a, 0x5b, 0xa9,
+ 0xe3, 0x7e, 0xfc, 0xed, 0x4b, 0xca, 0xf9, 0x04, 0xa6, 0x62, 0x9d, 0xce,
+ 0xe5, 0x6d, 0xc3, 0xea, 0x44, 0x08, 0xa1, 0xd8, 0x63, 0x66, 0xe4, 0x65,
+ 0xa1, 0xce, 0xec, 0x04, 0x85, 0x95, 0xff, 0x7d, 0xb6, 0x96, 0x79, 0xf7,
+ 0xac, 0x5f, 0x83, 0xfb, 0xfe, 0x16, 0x2f, 0xd2, 0xee, 0x08, 0x6b, 0x15,
+ 0x25, 0x59, 0x86, 0xca, 0x3e, 0x39, 0xe1, 0x14, 0xdf, 0xfe, 0xd6, 0x18,
+ 0x3f, 0xe4, 0xc5, 0x9a, 0x92, 0xc5, 0xed, 0x66, 0xea, 0xc5, 0xff, 0xa0,
+ 0xc0, 0xe7, 0xe6, 0x1e, 0x37, 0x56, 0x2b, 0x48, 0xb1, 0x3a, 0x67, 0x88,
+ 0x2f, 0xff, 0x9c, 0xf1, 0xae, 0xb4, 0x23, 0x74, 0x27, 0xe2, 0xc5, 0x62,
+ 0x20, 0xc4, 0x61, 0x7f, 0xb5, 0xd0, 0x9c, 0x67, 0x85, 0x8b, 0xff, 0xa3,
+ 0x41, 0xf9, 0xbd, 0xfc, 0x1b, 0x2c, 0x5f, 0xe2, 0xec, 0x19, 0xc7, 0xdd,
+ 0x58, 0xbf, 0xe2, 0x89, 0xc3, 0xff, 0xdf, 0x75, 0x62, 0xfa, 0x30, 0x7d,
+ 0xac, 0x56, 0x22, 0x63, 0xe6, 0xfb, 0xcf, 0xaf, 0xe7, 0x7f, 0x6e, 0x37,
+ 0x4b, 0x17, 0x6f, 0x08, 0xb1, 0x7f, 0xff, 0x89, 0x81, 0xcd, 0x67, 0x5f,
+ 0x8f, 0xe6, 0xb5, 0x06, 0xac, 0x5f, 0xfb, 0x27, 0x9d, 0xbd, 0xa1, 0x40,
+ 0x16, 0x29, 0x91, 0x47, 0xe6, 0x2a, 0x85, 0x4a, 0xb3, 0x9a, 0xe4, 0x37,
+ 0x74, 0x62, 0x03, 0x1f, 0x42, 0xfe, 0xf6, 0xc3, 0x0a, 0x49, 0x62, 0xf8,
+ 0x70, 0x5e, 0x58, 0xbc, 0xfa, 0x9d, 0x62, 0xff, 0x67, 0xb8, 0xdd, 0x61,
+ 0x2c, 0x5c, 0x61, 0x8b, 0x17, 0xfe, 0x14, 0xef, 0xef, 0x77, 0xd3, 0x12,
+ 0xc5, 0xe7, 0xeb, 0x67, 0x11, 0x9f, 0xd1, 0x11, 0x0f, 0x18, 0x66, 0x18,
+ 0xd5, 0xfb, 0x4f, 0x26, 0xfa, 0xc5, 0xff, 0xda, 0xe7, 0xd8, 0xcf, 0xb4,
+ 0xee, 0x4b, 0x15, 0x07, 0xdc, 0xe5, 0x17, 0xef, 0x77, 0xd3, 0x7d, 0x7a,
+ 0x89, 0x17, 0xff, 0xc5, 0xd8, 0x0e, 0x2e, 0xff, 0x9b, 0xf3, 0xdc, 0x58,
+ 0xbf, 0x4d, 0x28, 0xd4, 0xeb, 0x17, 0xfe, 0x38, 0x83, 0xcd, 0x4e, 0x27,
+ 0x1a, 0xc5, 0xf8, 0x26, 0x6b, 0x02, 0x2c, 0x56, 0x23, 0xbb, 0x4a, 0xa7,
+ 0x2b, 0xfa, 0x15, 0xfb, 0x0f, 0xf7, 0x1a, 0xc5, 0xb6, 0x42, 0x90, 0x84,
+ 0xb8, 0x88, 0x47, 0xca, 0x14, 0x63, 0x22, 0xc9, 0x76, 0xa6, 0x9d, 0x75,
+ 0x4e, 0xaf, 0xdd, 0x2f, 0x98, 0xa7, 0x50, 0xcc, 0xfc, 0x3e, 0xde, 0xf9,
+ 0xb9, 0x4a, 0x37, 0xae, 0x4a, 0x77, 0xf3, 0x16, 0xf8, 0x7b, 0x99, 0x0c,
+ 0xed, 0xc2, 0x00, 0xe3, 0x26, 0x08, 0x79, 0x52, 0x86, 0x4e, 0xc0, 0xeb,
+ 0x5a, 0x3e, 0xe5, 0x51, 0xe9, 0x30, 0xf0, 0x96, 0xfc, 0xee, 0x80, 0x23,
+ 0x5d, 0x29, 0x4d, 0x5c, 0xa7, 0xb7, 0x7a, 0x9f, 0x86, 0x2c, 0x43, 0x37,
+ 0x5c, 0x29, 0x2c, 0x52, 0xc5, 0xf0, 0xff, 0x06, 0x2c, 0x54, 0x1b, 0x0c,
+ 0x0c, 0xbf, 0xb9, 0x13, 0x49, 0xa6, 0x58, 0xba, 0x26, 0x58, 0xbf, 0xef,
+ 0x41, 0x30, 0x33, 0xbf, 0x2c, 0x5f, 0x6e, 0x39, 0x01, 0x62, 0xd3, 0xe1,
+ 0xef, 0x06, 0x73, 0x7f, 0x39, 0x03, 0xd1, 0x32, 0xc5, 0x41, 0xeb, 0xee,
+ 0x14, 0xd0, 0x13, 0x88, 0x24, 0x8e, 0x0f, 0xf8, 0xc0, 0x38, 0x66, 0xdd,
+ 0x9d, 0xac, 0x5f, 0xed, 0xf1, 0xa9, 0x7d, 0xe4, 0xb1, 0x78, 0xec, 0x05,
+ 0x8b, 0xdf, 0x63, 0x16, 0x2f, 0x9f, 0x5d, 0x6c, 0xc9, 0x11, 0x38, 0x31,
+ 0xc3, 0x6f, 0x0e, 0xdf, 0xfe, 0x93, 0xf3, 0x64, 0xa3, 0x3d, 0x1d, 0xc9,
+ 0x62, 0xf1, 0xad, 0xa5, 0x8b, 0xa0, 0x0b, 0x17, 0xde, 0xf4, 0x1d, 0x62,
+ 0xf3, 0x0f, 0x65, 0x8f, 0x63, 0xe3, 0xc1, 0x8b, 0xdf, 0xfa, 0x25, 0xb2,
+ 0x1c, 0x18, 0x1c, 0xdc, 0x58, 0xb3, 0x74, 0x88, 0xa0, 0x21, 0xd6, 0xca,
+ 0xa8, 0x89, 0xe1, 0xb2, 0xca, 0xfe, 0x8c, 0xbe, 0xff, 0xcf, 0xd6, 0xc8,
+ 0x80, 0xd2, 0xc9, 0x2c, 0x5f, 0xff, 0x67, 0x9b, 0xe2, 0xfb, 0xb7, 0x7c,
+ 0x83, 0x56, 0x2f, 0xda, 0xe9, 0xdf, 0xa5, 0x44, 0x6a, 0x5f, 0xff, 0x7d,
+ 0x8c, 0x72, 0xeb, 0x50, 0xd2, 0x7e, 0x2c, 0x5f, 0x85, 0xe1, 0x4d, 0x0b,
+ 0x17, 0xe6, 0x1b, 0xe7, 0x96, 0x2f, 0xbe, 0xdb, 0xd9, 0x62, 0xee, 0xf8,
+ 0xb1, 0x58, 0x6f, 0x4d, 0x24, 0xb6, 0xcc, 0xe9, 0xe5, 0x0d, 0x0f, 0x14,
+ 0x7a, 0x37, 0xfa, 0x83, 0x95, 0x79, 0x92, 0xff, 0xff, 0x6f, 0x82, 0xf6,
+ 0xcb, 0xef, 0x71, 0xe0, 0xdc, 0xee, 0x35, 0x8b, 0xf6, 0xba, 0x77, 0xe9,
+ 0x51, 0x52, 0x97, 0xb0, 0x0e, 0xb1, 0x6e, 0x95, 0x10, 0xd1, 0x4b, 0x14,
+ 0xe6, 0xb0, 0x04, 0x17, 0x39, 0xd6, 0x2d, 0xb3, 0x88, 0xb6, 0xf9, 0xbb,
+ 0xa4, 0x11, 0x05, 0xf7, 0x9f, 0xb0, 0x2c, 0x5f, 0xfe, 0xcf, 0xb0, 0x7e,
+ 0x62, 0x14, 0xb3, 0x8b, 0x17, 0xfb, 0x3e, 0x4f, 0xef, 0x42, 0xc5, 0xe2,
+ 0x7d, 0x97, 0x45, 0x07, 0x89, 0x03, 0x4a, 0xbd, 0xb1, 0xec, 0x2d, 0x89,
+ 0x62, 0xfc, 0xe7, 0x9d, 0xf7, 0x56, 0x2f, 0xba, 0x77, 0xe9, 0x51, 0x1f,
+ 0x17, 0x0e, 0x16, 0x2b, 0x47, 0x90, 0x73, 0x1b, 0xfd, 0xc6, 0xf9, 0x8f,
+ 0xa9, 0x2c, 0x5f, 0xe6, 0xd6, 0xd6, 0x1e, 0x1d, 0x62, 0xe7, 0xd2, 0xc5,
+ 0x7c, 0xf3, 0x1c, 0xd6, 0xef, 0x89, 0x62, 0xff, 0x86, 0x2f, 0x73, 0x24,
+ 0xdf, 0x58, 0xa1, 0x9e, 0x93, 0x0c, 0x5d, 0xdf, 0x16, 0x2c, 0x6a, 0xc5,
+ 0x61, 0xac, 0xdc, 0x19, 0xbf, 0xec, 0xde, 0x59, 0xc0, 0xf4, 0x6a, 0xc5,
+ 0xfc, 0xef, 0x3f, 0xb3, 0xa5, 0x8b, 0xff, 0x68, 0x1d, 0x7d, 0xa6, 0x28,
+ 0x02, 0xc5, 0x4c, 0x7e, 0x02, 0x2f, 0xbf, 0xd2, 0xcd, 0xd7, 0x20, 0x6c,
+ 0x4b, 0x17, 0xf8, 0x85, 0xd1, 0xe3, 0x5d, 0x2c, 0x5e, 0xf4, 0x62, 0xc5,
+ 0xff, 0xde, 0x94, 0x1b, 0xb6, 0x3d, 0xc8, 0x02, 0xc5, 0x8b, 0x0f, 0x91,
+ 0xc7, 0x2e, 0x96, 0xce, 0xc6, 0xaf, 0xca, 0x72, 0xec, 0x74, 0xec, 0x8a,
+ 0x68, 0x40, 0xbb, 0x98, 0x13, 0x48, 0x8f, 0x90, 0xad, 0xf1, 0x18, 0x8e,
+ 0xc3, 0x84, 0xd5, 0x74, 0xba, 0x00, 0xf3, 0x86, 0xb7, 0xf6, 0xcf, 0x1e,
+ 0x3b, 0x92, 0xc5, 0xfd, 0x3c, 0x6b, 0x4f, 0x25, 0x8b, 0xef, 0xc1, 0x1a,
+ 0xb1, 0x44, 0x7a, 0x5e, 0x2f, 0xbf, 0xb4, 0xe0, 0x7c, 0xd2, 0xc5, 0xe1,
+ 0x14, 0xeb, 0x17, 0x9c, 0xa6, 0x58, 0xaf, 0x9b, 0xb7, 0x1e, 0xbf, 0xb3,
+ 0x5e, 0x28, 0xed, 0x62, 0xfe, 0xfc, 0x36, 0xfc, 0x1a, 0xc5, 0xff, 0x9e,
+ 0x78, 0xfb, 0x69, 0xa0, 0xeb, 0x17, 0xfa, 0x35, 0x85, 0xec, 0xfa, 0xc5,
+ 0xd9, 0xb3, 0x09, 0xbb, 0x0c, 0x87, 0xed, 0x00, 0x20, 0xf1, 0x76, 0xe1,
+ 0x78, 0x67, 0xd4, 0x6a, 0xa7, 0x03, 0xc7, 0xf5, 0x5b, 0x2a, 0xb2, 0xa2,
+ 0x54, 0xf5, 0xff, 0xfe, 0x16, 0x8d, 0x7e, 0x60, 0xe3, 0xbe, 0x07, 0xe3,
+ 0x58, 0xd5, 0x8b, 0xdc, 0x7e, 0x2c, 0x5f, 0x66, 0x89, 0xd6, 0x2a, 0x0d,
+ 0xf3, 0x0e, 0xd4, 0x91, 0x89, 0x34, 0x29, 0x6f, 0x18, 0x6f, 0x4b, 0x17,
+ 0xee, 0xfb, 0x96, 0x79, 0x62, 0xb8, 0x79, 0x82, 0x21, 0xbf, 0xfc, 0x16,
+ 0x1a, 0x66, 0xec, 0xe3, 0xd8, 0xb6, 0xed, 0xfe, 0xe2, 0xc5, 0xff, 0x84,
+ 0xfa, 0x91, 0x67, 0x23, 0x4b, 0x17, 0xdd, 0x3b, 0xf4, 0xa8, 0xb1, 0xcb,
+ 0xf4, 0x7c, 0x9c, 0x35, 0x8b, 0x85, 0xa5, 0x8a, 0xd1, 0xf8, 0x9c, 0xc5,
+ 0xca, 0x2f, 0xf6, 0x31, 0x4f, 0xec, 0xfa, 0xc5, 0xcf, 0xc5, 0x8b, 0xfa,
+ 0x70, 0xf5, 0xac, 0xd2, 0xc5, 0xe3, 0xf2, 0x16, 0x2a, 0x47, 0xca, 0xe2,
+ 0xe2, 0x31, 0xbf, 0xe2, 0x73, 0x7e, 0xd0, 0x53, 0xac, 0x5f, 0xff, 0xec,
+ 0x2f, 0x73, 0x6f, 0x03, 0x8d, 0x03, 0x71, 0xbf, 0x9b, 0xd6, 0x2f, 0xe2,
+ 0xf6, 0x85, 0x07, 0x58, 0xbf, 0xff, 0x13, 0x9b, 0xb7, 0xc6, 0xc1, 0x4b,
+ 0x3e, 0xc7, 0x58, 0xa8, 0x47, 0x7b, 0xb4, 0x88, 0xba, 0xfe, 0x03, 0xfb,
+ 0x90, 0x6a, 0xc5, 0xf1, 0xa1, 0x97, 0x4b, 0x16, 0xc5, 0x8a, 0x34, 0xdb,
+ 0xef, 0x26, 0xbf, 0xcd, 0xe8, 0xd1, 0xbf, 0x65, 0x8b, 0xff, 0xe9, 0x4e,
+ 0x16, 0x46, 0xc1, 0x3f, 0x5a, 0xdb, 0xb7, 0xfb, 0x8b, 0x17, 0xfd, 0x9b,
+ 0xe2, 0x5d, 0xcb, 0x3c, 0xb1, 0x58, 0x9b, 0x0b, 0x33, 0x39, 0x20, 0x0d,
+ 0x09, 0x9e, 0xfd, 0x9b, 0xc3, 0x9b, 0x8b, 0x17, 0x34, 0x96, 0x2f, 0xf6,
+ 0x17, 0xf3, 0xd0, 0x35, 0x8b, 0xf6, 0x6f, 0xfb, 0xc9, 0x62, 0xde, 0x63,
+ 0xdc, 0x23, 0x2a, 0x1a, 0x26, 0x71, 0xce, 0xff, 0xa4, 0xde, 0x0f, 0x51,
+ 0xf8, 0x58, 0xbf, 0xff, 0x37, 0x03, 0xec, 0x19, 0xbd, 0xbd, 0x18, 0x52,
+ 0x58, 0xbf, 0x37, 0xbc, 0xde, 0x58, 0xbf, 0xff, 0x08, 0x9c, 0xdf, 0x1b,
+ 0x05, 0x2c, 0xfb, 0x1d, 0x62, 0xfb, 0x5a, 0xcd, 0xc5, 0x8b, 0xba, 0xe9,
+ 0x62, 0xfd, 0xa0, 0x37, 0xe1, 0x62, 0xb6, 0xa6, 0xf1, 0x23, 0xac, 0x58,
+ 0x39, 0x43, 0xab, 0x70, 0x98, 0x43, 0x57, 0xf0, 0xf0, 0xed, 0xf8, 0x58,
+ 0xbe, 0xd6, 0x64, 0xcb, 0x15, 0x07, 0xa1, 0x85, 0xb6, 0xd9, 0x86, 0x46,
+ 0x94, 0xee, 0xb2, 0x22, 0x1b, 0x2e, 0x42, 0xbc, 0xd2, 0xe6, 0x84, 0xc4,
+ 0xc5, 0xc7, 0x8c, 0xa3, 0xf1, 0xc7, 0xba, 0x39, 0x43, 0x1b, 0x91, 0xcd,
+ 0x07, 0x0b, 0x5b, 0xbd, 0x8b, 0x16, 0xd8, 0xd6, 0x2b, 0xb3, 0x5c, 0xc2,
+ 0xf7, 0x9b, 0x53, 0x2c, 0x5f, 0x4b, 0xc2, 0x1a, 0xc5, 0x1a, 0x78, 0x5d,
+ 0x8f, 0x5f, 0xff, 0xff, 0xbf, 0x8e, 0xdc, 0xfe, 0x03, 0x6f, 0x30, 0x78,
+ 0x76, 0xee, 0x45, 0x06, 0x81, 0x62, 0xfe, 0x27, 0x33, 0xd9, 0xf5, 0x8a,
+ 0x0a, 0x22, 0xce, 0x68, 0x42, 0xdc, 0x73, 0x56, 0x28, 0x2a, 0x78, 0xc1,
+ 0x61, 0x6d, 0xf8, 0xb3, 0xef, 0xe5, 0x8b, 0xc1, 0x6e, 0x14, 0x02, 0xc5,
+ 0x05, 0x4f, 0x40, 0x2c, 0x27, 0xbf, 0xed, 0x8c, 0x2a, 0x2c, 0xd1, 0x40,
+ 0x16, 0x2c, 0x35, 0x8a, 0x0a, 0x1e, 0xa6, 0xc3, 0x42, 0xbf, 0xf0, 0x57,
+ 0x61, 0x00, 0x10, 0x3f, 0x88, 0x22, 0xc5, 0xfd, 0x9d, 0x47, 0x9b, 0x7a,
+ 0xc5, 0xff, 0xb0, 0xce, 0x63, 0x73, 0xd9, 0xba, 0xb1, 0x5f, 0x3f, 0x22,
+ 0x30, 0xbd, 0xf1, 0x0d, 0x62, 0xed, 0x85, 0xb1, 0xac, 0x5f, 0xf8, 0xfc,
+ 0x28, 0x8e, 0xce, 0xc0, 0x58, 0xbf, 0xe2, 0x8f, 0xbb, 0x71, 0xb7, 0xac,
+ 0x5d, 0x87, 0xd8, 0xd1, 0x37, 0x04, 0x61, 0x9f, 0xdf, 0xd9, 0x29, 0x68,
+ 0x41, 0x55, 0x8a, 0x19, 0xf9, 0x92, 0x05, 0xff, 0x44, 0xcd, 0xee, 0x31,
+ 0x4c, 0xb1, 0x7f, 0xdc, 0x28, 0x8e, 0xce, 0xc0, 0x58, 0xbf, 0xfa, 0x01,
+ 0xfd, 0xd6, 0x3f, 0xb8, 0xfd, 0xac, 0x5f, 0xf4, 0x69, 0xce, 0x59, 0xdf,
+ 0x96, 0x2b, 0xa4, 0x41, 0x1d, 0x26, 0xec, 0x9d, 0x62, 0xe1, 0xc2, 0xc5,
+ 0x06, 0x6b, 0xc2, 0x0c, 0x53, 0x1f, 0xb8, 0x94, 0xef, 0xfd, 0xf6, 0xda,
+ 0x1f, 0x45, 0x9f, 0xc5, 0x8b, 0xf8, 0x1c, 0x7f, 0x79, 0xd6, 0x28, 0xd3,
+ 0xf0, 0x74, 0x2b, 0xfd, 0xc8, 0x98, 0xf1, 0xee, 0x2c, 0x5c, 0x7e, 0x96,
+ 0x2f, 0xf9, 0xc6, 0xdd, 0xcb, 0xcd, 0xa5, 0x8b, 0xff, 0x46, 0x80, 0x59,
+ 0x34, 0x9a, 0x65, 0x8a, 0x1a, 0xe2, 0xae, 0x10, 0xb4, 0x65, 0x9a, 0x21,
+ 0x39, 0xd7, 0xe3, 0x32, 0x28, 0x48, 0xf0, 0x8b, 0xc6, 0xbb, 0xc6, 0x42,
+ 0x1d, 0x5f, 0xbe, 0xd0, 0x5e, 0x58, 0xbf, 0xe3, 0x35, 0x84, 0xfd, 0xcb,
+ 0x8b, 0x17, 0x11, 0xab, 0x17, 0xf7, 0x7f, 0x68, 0x29, 0xd6, 0x2e, 0xc1,
+ 0xac, 0x50, 0xd1, 0x81, 0x84, 0xee, 0x76, 0x21, 0x8d, 0xe5, 0xf7, 0xef,
+ 0xb9, 0xe0, 0x96, 0x2f, 0xb9, 0xf6, 0x31, 0x62, 0xff, 0xe9, 0xb7, 0x5a,
+ 0x7f, 0xe4, 0xc5, 0x86, 0x2c, 0x5f, 0x9f, 0x5b, 0x8f, 0xf5, 0x8b, 0xf7,
+ 0x23, 0xcd, 0xbd, 0x62, 0xba, 0x3d, 0x5f, 0x15, 0xdd, 0xff, 0xac, 0x5f,
+ 0xa0, 0xcf, 0x67, 0xd6, 0x2e, 0x0f, 0x16, 0x2f, 0x87, 0x9d, 0xf9, 0x62,
+ 0xa0, 0xde, 0x30, 0xc5, 0x6d, 0x4e, 0xab, 0x09, 0xcd, 0x24, 0x68, 0x50,
+ 0x05, 0xc8, 0xc8, 0x63, 0x8c, 0xb7, 0xf1, 0x40, 0x25, 0xd4, 0xeb, 0x17,
+ 0xff, 0x44, 0x04, 0xfe, 0x38, 0xf3, 0x0e, 0xb1, 0x77, 0xb9, 0x31, 0xfa,
+ 0x7c, 0xc2, 0xdd, 0x2c, 0x5e, 0x06, 0xc7, 0xf5, 0x8a, 0xd8, 0x46, 0xdb,
+ 0x82, 0x77, 0xc2, 0xe7, 0xf1, 0x62, 0xff, 0xf3, 0x7c, 0x43, 0xfc, 0x75,
+ 0xf1, 0x38, 0x6b, 0x15, 0xa4, 0x4b, 0x91, 0x3f, 0x88, 0xef, 0xff, 0x60,
+ 0x4c, 0xeb, 0xdd, 0xcb, 0x08, 0x0e, 0xb1, 0x7f, 0xff, 0xf3, 0x16, 0xfc,
+ 0x19, 0x3b, 0xef, 0xcd, 0xdf, 0x6e, 0xb7, 0x8a, 0x00, 0xb1, 0x79, 0x84,
+ 0x05, 0x8b, 0x77, 0xba, 0x89, 0x59, 0x9e, 0x2f, 0x1d, 0xb4, 0xb1, 0x58,
+ 0x79, 0x60, 0x2e, 0xbd, 0x8e, 0x4b, 0x17, 0xbf, 0x13, 0x2c, 0x5c, 0xde,
+ 0x63, 0x72, 0xe3, 0x77, 0x48, 0x6b, 0x17, 0xfa, 0x71, 0x0f, 0xf9, 0xbf,
+ 0x8b, 0x17, 0xff, 0x61, 0x9c, 0x2c, 0x9a, 0x42, 0x2f, 0x2c, 0x5f, 0x4b,
+ 0x75, 0x8e, 0xb1, 0x7d, 0xc7, 0x7d, 0xd5, 0x8b, 0xef, 0xfe, 0x37, 0x56,
+ 0x2f, 0xd9, 0xfd, 0xd6, 0x27, 0x3f, 0x1f, 0x13, 0x06, 0x4b, 0x53, 0xa6,
+ 0x78, 0x47, 0x1b, 0xe1, 0x6f, 0x7f, 0xfe, 0xeb, 0x37, 0xb6, 0xb7, 0x1e,
+ 0x7d, 0xcd, 0x67, 0xf8, 0xb1, 0x58, 0x89, 0x87, 0x38, 0xbf, 0xed, 0xf9,
+ 0x3b, 0xb7, 0x58, 0x4b, 0x17, 0xe7, 0x6e, 0xb0, 0x96, 0x2f, 0x9b, 0xac,
+ 0x25, 0x8b, 0xa3, 0x9b, 0x4f, 0x25, 0xc9, 0xef, 0xff, 0x7e, 0x3b, 0xc9,
+ 0xc8, 0x42, 0xf4, 0x7d, 0x62, 0xff, 0x9b, 0xaf, 0xb7, 0xb8, 0xfd, 0xac,
+ 0x5f, 0x60, 0xf3, 0xfd, 0x22, 0x1f, 0xe9, 0x95, 0x89, 0xb9, 0xea, 0x10,
+ 0x85, 0x0b, 0x5b, 0xfd, 0xd3, 0x19, 0x93, 0x3e, 0xea, 0xc5, 0x68, 0xfc,
+ 0xbe, 0x73, 0x7f, 0xff, 0xe2, 0xc3, 0x90, 0x80, 0x6e, 0xeb, 0x10, 0xf2,
+ 0x73, 0x04, 0xf3, 0xac, 0x54, 0x22, 0x53, 0x08, 0xaf, 0xff, 0xf4, 0x19,
+ 0xfc, 0xd3, 0x9f, 0x3d, 0xfc, 0xc3, 0xe7, 0x4b, 0x17, 0xff, 0xb9, 0xd3,
+ 0xbe, 0xfd, 0x63, 0x7e, 0x06, 0xb1, 0x7f, 0xfb, 0x02, 0x16, 0x6f, 0x2c,
+ 0x01, 0xe2, 0x4b, 0x15, 0xd2, 0x26, 0x26, 0x4c, 0xa8, 0x4c, 0x7b, 0x21,
+ 0xf3, 0x7f, 0x16, 0x7b, 0x98, 0x62, 0xc5, 0xfe, 0x96, 0xd3, 0x1c, 0x8a,
+ 0x16, 0x2c, 0xfd, 0x9f, 0x1e, 0x8b, 0xaa, 0x19, 0x2a, 0x79, 0x0f, 0xce,
+ 0x8b, 0xda, 0x32, 0xdd, 0xd5, 0xa9, 0x8a, 0xb5, 0x1f, 0x67, 0xe5, 0x4d,
+ 0x14, 0x67, 0xe2, 0x84, 0x55, 0xdd, 0xf1, 0x62, 0xf6, 0x85, 0x25, 0x8b,
+ 0x7e, 0x0d, 0xbb, 0x0c, 0xdf, 0xf4, 0xed, 0xf9, 0x9e, 0x4d, 0xf5, 0x8b,
+ 0xf6, 0x81, 0xb8, 0x2f, 0x2c, 0x5f, 0xed, 0xff, 0x61, 0xff, 0x38, 0xb1,
+ 0x7f, 0xff, 0xc2, 0x17, 0x65, 0x9b, 0xf6, 0x8f, 0x3d, 0x2c, 0xff, 0xde,
+ 0x4b, 0x17, 0xfc, 0x7e, 0x7f, 0x3c, 0x50, 0x75, 0x8b, 0xc5, 0x9c, 0x24,
+ 0x52, 0xee, 0x36, 0x53, 0xa6, 0x21, 0xbe, 0x1b, 0x77, 0xff, 0xb5, 0xa8,
+ 0x9f, 0x0c, 0xee, 0x5e, 0x10, 0xd6, 0x2f, 0xb3, 0x08, 0xd5, 0x8b, 0xff,
+ 0x31, 0xb9, 0x26, 0x7d, 0xff, 0x65, 0x8b, 0x43, 0x22, 0xc7, 0x49, 0xff,
+ 0x22, 0xa8, 0x54, 0x98, 0xd1, 0x9e, 0xfe, 0x1b, 0x77, 0xf8, 0xbd, 0xb1,
+ 0x3f, 0x85, 0x0b, 0x17, 0xf4, 0x8b, 0x3b, 0xf3, 0xac, 0x5f, 0xc3, 0xf1,
+ 0xac, 0x43, 0x58, 0xa8, 0x44, 0xab, 0x9c, 0x08, 0xba, 0xf8, 0xec, 0x67,
+ 0x16, 0x2f, 0xf3, 0xcf, 0xee, 0x3b, 0xee, 0xac, 0x54, 0xe7, 0xb7, 0xbc,
+ 0x92, 0xfe, 0xfb, 0x4c, 0xef, 0x25, 0x8b, 0x8f, 0x25, 0x8b, 0x9b, 0x5d,
+ 0x1e, 0x30, 0x65, 0xd7, 0xfe, 0x83, 0xf5, 0xf6, 0xf6, 0x61, 0xd6, 0x2f,
+ 0xb8, 0x76, 0x02, 0xc5, 0x7c, 0xf8, 0x80, 0x7f, 0x7f, 0xf3, 0x14, 0xf9,
+ 0xd4, 0x6f, 0x14, 0x71, 0x62, 0xfb, 0x53, 0xc1, 0xab, 0x16, 0x65, 0x8b,
+ 0x9c, 0xdc, 0x36, 0xde, 0x25, 0xa8, 0x46, 0x58, 0xc8, 0x89, 0xf6, 0xff,
+ 0xf1, 0x67, 0xc3, 0xe7, 0x04, 0x7e, 0x3f, 0x6b, 0x17, 0xc0, 0xc6, 0x75,
+ 0x8b, 0xc0, 0x60, 0xd6, 0x2f, 0xec, 0x2c, 0xde, 0xda, 0x58, 0xbf, 0xff,
+ 0x31, 0xc7, 0x1f, 0xcd, 0xfb, 0xac, 0x43, 0xc9, 0xd6, 0x2f, 0xd0, 0x5e,
+ 0xe3, 0x74, 0x88, 0x8f, 0x97, 0x5f, 0x04, 0x8f, 0xf1, 0x62, 0xba, 0x4d,
+ 0xe1, 0xd3, 0x40, 0x43, 0xe8, 0x53, 0x04, 0x3f, 0xbf, 0xe7, 0xd4, 0xff,
+ 0x6c, 0xd4, 0xcb, 0x17, 0xff, 0x3b, 0x90, 0x39, 0x9b, 0xb3, 0x3b, 0xac,
+ 0x5f, 0xff, 0xff, 0xcd, 0xfd, 0xd6, 0x2c, 0xf7, 0xa2, 0x71, 0x94, 0x40,
+ 0x3d, 0x2c, 0x22, 0x79, 0x2c, 0x5f, 0xf6, 0x7b, 0x0e, 0xfa, 0x69, 0x96,
+ 0x2b, 0x11, 0x82, 0x50, 0x88, 0xae, 0x93, 0x68, 0x98, 0xef, 0xd1, 0x83,
+ 0xdf, 0xa5, 0xc9, 0xf0, 0xc5, 0x8b, 0xe8, 0x1e, 0x12, 0xc5, 0xec, 0xd4,
+ 0xeb, 0x17, 0x9c, 0xa6, 0x58, 0xaf, 0x9b, 0xb7, 0x1e, 0xbc, 0xef, 0xd2,
+ 0xa2, 0xd0, 0x2f, 0xff, 0xf6, 0x0e, 0x3a, 0x62, 0x9f, 0x9d, 0x7d, 0x86,
+ 0x3c, 0x25, 0x8b, 0xf3, 0xea, 0x7c, 0x31, 0x62, 0xf3, 0x98, 0x13, 0x6a,
+ 0x23, 0x3a, 0x62, 0xbf, 0x81, 0x05, 0x1e, 0xe2, 0xc5, 0xed, 0x47, 0x96,
+ 0x2f, 0xe8, 0x17, 0x89, 0xb7, 0xac, 0x5f, 0xde, 0xe6, 0x1a, 0xda, 0x98,
+ 0xf3, 0x34, 0x3b, 0x50, 0xa9, 0x5a, 0x72, 0xb1, 0xae, 0x74, 0x41, 0xa8,
+ 0x5b, 0x00, 0xe8, 0x37, 0x9b, 0xfb, 0xdb, 0x70, 0xd6, 0xd2, 0xc5, 0xe9,
+ 0x30, 0x16, 0x2f, 0xfb, 0xbf, 0x41, 0xbb, 0xac, 0x21, 0xac, 0x5f, 0xcd,
+ 0xef, 0xb9, 0x1a, 0xb1, 0x4c, 0x8b, 0xb9, 0x8c, 0x5c, 0x77, 0x87, 0xf7,
+ 0xdf, 0x27, 0xdd, 0x58, 0xbc, 0x21, 0x69, 0x62, 0xf1, 0x46, 0x96, 0x2e,
+ 0xd4, 0xd3, 0x1b, 0xae, 0x0f, 0x5f, 0xff, 0xee, 0x39, 0x7e, 0x37, 0xff,
+ 0x3d, 0x8e, 0x5d, 0x60, 0xd6, 0x2f, 0xff, 0xf3, 0x47, 0x9b, 0xf1, 0xcf,
+ 0xe7, 0x35, 0x9d, 0x67, 0x96, 0x2f, 0xfe, 0x80, 0x70, 0xb3, 0x74, 0x71,
+ 0xee, 0x2c, 0x59, 0xc9, 0x14, 0xfc, 0x60, 0xb6, 0xa1, 0x32, 0xff, 0xc6,
+ 0x11, 0x7f, 0x4f, 0xb6, 0x69, 0x44, 0xeb, 0x17, 0xf6, 0x6f, 0x89, 0x46,
+ 0x96, 0x2a, 0x15, 0x27, 0xe2, 0xfb, 0x46, 0xbc, 0xe5, 0xe4, 0x69, 0x7e,
+ 0x1c, 0x4c, 0xc7, 0x58, 0xbf, 0x8c, 0x2c, 0x9c, 0x39, 0x2c, 0x5f, 0x87,
+ 0x80, 0x78, 0x58, 0xbf, 0xff, 0xf3, 0xea, 0x5c, 0x61, 0xe6, 0xa7, 0x6e,
+ 0x7d, 0xc1, 0xcc, 0x25, 0x8a, 0xc4, 0x49, 0xf0, 0x9e, 0x99, 0x1c, 0xc2,
+ 0x86, 0x25, 0xfa, 0x73, 0xbb, 0x92, 0xc5, 0xfe, 0xdf, 0xfc, 0x29, 0xdb,
+ 0x8b, 0x17, 0xf8, 0x18, 0xdc, 0xe4, 0x01, 0x62, 0xa0, 0xfa, 0x5c, 0xda,
+ 0xa1, 0x16, 0x3c, 0x84, 0x8d, 0xff, 0x87, 0xb9, 0x9c, 0x1f, 0xdb, 0x53,
+ 0xac, 0x5f, 0xff, 0x61, 0x9e, 0x3c, 0x67, 0xbf, 0x98, 0x5d, 0x2c, 0x54,
+ 0x22, 0x53, 0xe8, 0x97, 0xf6, 0xfd, 0x67, 0x9f, 0xb5, 0x8b, 0xc1, 0x40,
+ 0xae, 0xc0, 0xb1, 0x7d, 0x85, 0x26, 0x58, 0xbf, 0xfb, 0x35, 0xa7, 0x90,
+ 0x64, 0xfe, 0xe2, 0xc5, 0x41, 0xf3, 0x48, 0x86, 0xb4, 0x8b, 0x2f, 0x42,
+ 0x46, 0xff, 0x68, 0x02, 0xc9, 0xa0, 0xeb, 0x14, 0xc7, 0xba, 0xe5, 0x17,
+ 0xfa, 0x6f, 0xc7, 0xbf, 0x13, 0x2c, 0x54, 0x36, 0x82, 0xb3, 0x92, 0xca,
+ 0x54, 0x38, 0xe1, 0xa1, 0x90, 0x89, 0x35, 0xaf, 0xa8, 0xd7, 0x1a, 0x3a,
+ 0x6d, 0xd8, 0xee, 0xb5, 0x2a, 0x3c, 0xf1, 0x94, 0x7e, 0x54, 0x5b, 0xa6,
+ 0x94, 0x61, 0xfc, 0x86, 0xc7, 0xa1, 0x76, 0x22, 0x2d, 0xf1, 0xa0, 0x06,
+ 0x41, 0x7f, 0xfa, 0x0b, 0xa1, 0xfe, 0x3b, 0xfc, 0x6f, 0xc5, 0x8b, 0xff,
+ 0xff, 0xcd, 0xf1, 0x13, 0xbe, 0xfe, 0xbe, 0xde, 0xc3, 0xf1, 0xb0, 0x80,
+ 0xeb, 0x17, 0xff, 0xdd, 0xc8, 0xa1, 0xc6, 0xdd, 0x67, 0xdf, 0xcb, 0x15,
+ 0x24, 0x63, 0xb3, 0xbd, 0x80, 0xb1, 0x78, 0x7f, 0x85, 0x8b, 0xec, 0xef,
+ 0xce, 0xb1, 0x6e, 0x6d, 0x3c, 0x02, 0x1d, 0xb0, 0xb4, 0x7f, 0x7e, 0x52,
+ 0xb6, 0x2c, 0x5f, 0xfe, 0x1f, 0xe2, 0x1b, 0xdc, 0x62, 0xee, 0x4b, 0x16,
+ 0x10, 0xcf, 0x6c, 0x84, 0x6e, 0xc3, 0xac, 0x5f, 0xff, 0x1a, 0xda, 0xce,
+ 0xfd, 0xf6, 0x0e, 0x07, 0x0b, 0x17, 0x39, 0x2c, 0x5e, 0x62, 0xc5, 0x8b,
+ 0xff, 0x73, 0xf0, 0x7f, 0x70, 0x9f, 0xb9, 0xcd, 0x8c, 0x85, 0xaf, 0xfd,
+ 0xde, 0xff, 0xee, 0xb7, 0x8a, 0x0e, 0xb1, 0x58, 0x98, 0xf7, 0x70, 0x83,
+ 0x75, 0x6b, 0xd1, 0x3b, 0x2c, 0x54, 0x2b, 0xe2, 0xc8, 0xc5, 0x0d, 0x84,
+ 0xeb, 0x42, 0x0f, 0x44, 0xef, 0x19, 0xa9, 0x1a, 0xdf, 0xff, 0xf6, 0xb0,
+ 0x64, 0xef, 0xbf, 0x99, 0xbb, 0xe2, 0xcc, 0xd4, 0xcb, 0x17, 0xe2, 0xf6,
+ 0xd3, 0xce, 0xb1, 0x7c, 0x23, 0xbf, 0x96, 0x2f, 0xff, 0xcd, 0x39, 0x66,
+ 0xff, 0xb7, 0xbb, 0x94, 0x14, 0xcb, 0x15, 0x08, 0xa8, 0x19, 0x67, 0xc8,
+ 0xef, 0xff, 0xfc, 0xda, 0x6c, 0xdf, 0x93, 0xe3, 0x7a, 0x0e, 0x4e, 0x6f,
+ 0xd9, 0x62, 0xff, 0xe9, 0x43, 0xcb, 0x6b, 0x4c, 0xd8, 0x4b, 0x17, 0xff,
+ 0xf9, 0xa0, 0xbd, 0xa8, 0xfb, 0xf0, 0xb0, 0x1c, 0xf3, 0x2c, 0x5f, 0xfd,
+ 0x9c, 0x6f, 0x41, 0xdb, 0xc2, 0x85, 0x8b, 0xff, 0x09, 0xfb, 0xe1, 0x66,
+ 0xf7, 0x92, 0xc5, 0xff, 0x4c, 0x50, 0x7f, 0xc6, 0xf3, 0xac, 0x5f, 0xfe,
+ 0x93, 0x68, 0x0f, 0xec, 0x9a, 0x4d, 0xe5, 0x8b, 0xf7, 0x9b, 0x73, 0x27,
+ 0x58, 0xbc, 0x14, 0xd8, 0xc2, 0x8b, 0x17, 0xfb, 0x99, 0xf6, 0xe0, 0xa7,
+ 0x58, 0xbe, 0x6d, 0xcc, 0x9d, 0x62, 0xe7, 0xef, 0x6a, 0x2c, 0x82, 0xc2,
+ 0xce, 0x15, 0xf8, 0xd6, 0xe7, 0xed, 0x62, 0xb1, 0x3a, 0x1e, 0xcf, 0x39,
+ 0x0f, 0xdf, 0x28, 0x59, 0x86, 0xae, 0x9b, 0xa2, 0xfe, 0xdb, 0x3e, 0x8a,
+ 0x4b, 0xdc, 0x43, 0xf4, 0x7c, 0x57, 0xfd, 0xf6, 0xf7, 0x1f, 0xb0, 0x18,
+ 0xb1, 0x78, 0x6f, 0x3a, 0xc5, 0xda, 0x9f, 0xa3, 0xda, 0x0c, 0xf2, 0xff,
+ 0xf8, 0x53, 0xe9, 0xbd, 0x38, 0xb5, 0x2e, 0x6e, 0xb2, 0xc5, 0x32, 0xf0,
+ 0x67, 0xe7, 0x2e, 0x1e, 0x19, 0x84, 0x63, 0x7f, 0x67, 0xb0, 0x9e, 0x65,
+ 0x8b, 0xfb, 0x4d, 0xd1, 0x47, 0xd6, 0x2f, 0xf8, 0x4f, 0xe7, 0x93, 0xf7,
+ 0x25, 0x8b, 0xfa, 0x53, 0x7d, 0xbb, 0xf2, 0xc5, 0xf0, 0x79, 0xdf, 0x96,
+ 0x2a, 0x0f, 0x59, 0xcc, 0x6e, 0xd7, 0x16, 0x2a, 0x49, 0x91, 0xe1, 0x6f,
+ 0x45, 0xdc, 0x84, 0x86, 0xe1, 0x05, 0xfe, 0x61, 0xe1, 0xf6, 0xe0, 0xd6,
+ 0x2e, 0x7e, 0x2c, 0x5f, 0x98, 0xcd, 0x8c, 0x2b, 0xb1, 0xac, 0x5f, 0xff,
+ 0x0b, 0x5a, 0x82, 0xc3, 0x5b, 0xff, 0xc0, 0xd6, 0x2c, 0x17, 0x58, 0xad,
+ 0x1f, 0x38, 0x94, 0x6f, 0xa3, 0x51, 0x32, 0xc5, 0xfe, 0x8d, 0xa6, 0x39,
+ 0x14, 0x2c, 0x5e, 0x28, 0x3a, 0xc5, 0xa1, 0x62, 0xa6, 0x35, 0xa7, 0x1c,
+ 0xbf, 0xc7, 0x11, 0x7b, 0x82, 0xd2, 0xc5, 0x49, 0x3e, 0x81, 0x9a, 0x9a,
+ 0x2f, 0xa8, 0x4f, 0x9c, 0x88, 0x04, 0x64, 0xc3, 0xb8, 0x45, 0x7e, 0xfb,
+ 0x9e, 0x09, 0x62, 0xf8, 0x27, 0xe0, 0x96, 0x2d, 0xa5, 0x8b, 0xda, 0xcc,
+ 0x58, 0xa9, 0xcf, 0x48, 0x04, 0x81, 0x04, 0xaf, 0xff, 0xee, 0xf9, 0x12,
+ 0xd6, 0x4f, 0x1a, 0xcf, 0x37, 0x66, 0x2c, 0x58, 0xd5, 0x8a, 0x9c, 0xfc,
+ 0x89, 0x7e, 0xfd, 0xdc, 0xb5, 0xce, 0x2c, 0x5f, 0x0e, 0x7c, 0x31, 0x62,
+ 0xa0, 0xfc, 0xb0, 0x88, 0x45, 0x77, 0xff, 0x04, 0x11, 0xff, 0x07, 0x9b,
+ 0x75, 0x86, 0xb1, 0x7e, 0xc9, 0xa6, 0x7e, 0x2c, 0x5f, 0xff, 0x67, 0xbb,
+ 0x94, 0x00, 0x10, 0x3f, 0x88, 0x22, 0xc5, 0xbb, 0xf9, 0xff, 0x11, 0x55,
+ 0x32, 0x3c, 0x9e, 0x19, 0x57, 0xf9, 0xc6, 0x51, 0x26, 0x25, 0x8b, 0xf3,
+ 0xcf, 0x3c, 0x76, 0xb1, 0x53, 0x9e, 0xe7, 0x8c, 0x6f, 0x8c, 0xf3, 0x4e,
+ 0xb1, 0x50, 0x79, 0x0e, 0x47, 0x7f, 0x17, 0x72, 0xf0, 0x86, 0xb1, 0x7e,
+ 0xdd, 0xc2, 0x3b, 0x2c, 0x54, 0x1e, 0xd3, 0x98, 0x5f, 0x14, 0x61, 0x8b,
+ 0x17, 0x8b, 0x00, 0xb1, 0x7f, 0xfc, 0xdb, 0x77, 0x5a, 0x7d, 0xbf, 0xc9,
+ 0x8b, 0x0c, 0x58, 0xbe, 0x9b, 0x32, 0x75, 0x8b, 0xf7, 0x1b, 0xc5, 0x0b,
+ 0x17, 0x67, 0xf8, 0x79, 0x7e, 0x24, 0xb1, 0x81, 0x54, 0xc3, 0xf4, 0x45,
+ 0xf1, 0xcf, 0x42, 0x92, 0xfe, 0x33, 0xc5, 0x07, 0xe2, 0xc5, 0x39, 0xfe,
+ 0x89, 0x3a, 0xfd, 0x37, 0xf0, 0x0e, 0xb1, 0x50, 0xba, 0xdf, 0x28, 0xc5,
+ 0xb2, 0x31, 0xfd, 0x43, 0x2b, 0xef, 0x45, 0x1d, 0x66, 0xf2, 0x1b, 0xff,
+ 0xfe, 0xfe, 0x7b, 0xcf, 0x3e, 0x78, 0xec, 0x22, 0x98, 0xb0, 0xc5, 0x8b,
+ 0xff, 0x3e, 0xbd, 0x9d, 0x81, 0xde, 0x65, 0x8b, 0xfe, 0x2c, 0x33, 0xf8,
+ 0x78, 0xe2, 0xc5, 0xff, 0x63, 0x4b, 0xf1, 0xf6, 0x35, 0x62, 0xff, 0x13,
+ 0x83, 0x9d, 0x7d, 0xa6, 0x3f, 0x22, 0x39, 0xa1, 0xa6, 0xc9, 0x33, 0x47,
+ 0xa1, 0x65, 0x7f, 0xbd, 0xdc, 0xb3, 0x78, 0xbe, 0xb1, 0x7f, 0x7b, 0xf9,
+ 0x29, 0x01, 0x62, 0xa1, 0x13, 0xc3, 0x37, 0x23, 0x8b, 0xfc, 0x4e, 0xfb,
+ 0xe5, 0xbc, 0x0b, 0x17, 0xff, 0xdc, 0x89, 0xbf, 0x1b, 0xcb, 0x07, 0xf8,
+ 0xe2, 0xc5, 0x0d, 0x11, 0x3e, 0x37, 0xbe, 0xea, 0x01, 0xc5, 0x8b, 0xfb,
+ 0xec, 0x66, 0xe4, 0x01, 0x62, 0xff, 0xf1, 0xdb, 0xb9, 0x70, 0xb3, 0xaf,
+ 0x08, 0x96, 0x2f, 0xf7, 0x33, 0x74, 0x0e, 0xf3, 0x2c, 0x5f, 0xfe, 0xcf,
+ 0x71, 0xb3, 0x50, 0x0e, 0x36, 0xf5, 0x8a, 0xc4, 0xd1, 0xfa, 0x23, 0x98,
+ 0x90, 0xe6, 0x5f, 0x4c, 0xdc, 0x37, 0xbe, 0x38, 0xe2, 0x4b, 0x17, 0xfe,
+ 0xfe, 0x6f, 0xdd, 0x61, 0x0f, 0x06, 0xb1, 0x50, 0x7c, 0xfe, 0x23, 0xbd,
+ 0xfc, 0xf2, 0xc5, 0xff, 0x70, 0x5a, 0x97, 0x44, 0xe1, 0x16, 0x2f, 0x9f,
+ 0xc5, 0x83, 0x3d, 0xaf, 0x0e, 0xdf, 0x4b, 0x8c, 0x35, 0x8b, 0x9b, 0x8b,
+ 0x16, 0x03, 0x1b, 0xa3, 0x91, 0xd4, 0x2b, 0xd3, 0xc8, 0xff, 0x9a, 0x18,
+ 0x6e, 0xf6, 0x27, 0x1b, 0x9a, 0x65, 0x8b, 0x32, 0xc5, 0xe2, 0xe9, 0xf4,
+ 0x6a, 0x78, 0x31, 0x7f, 0xff, 0x68, 0xa2, 0x3b, 0xdb, 0xcf, 0x14, 0x0f,
+ 0xf1, 0xe5, 0x8b, 0x9b, 0xeb, 0x17, 0xff, 0xe6, 0x37, 0x06, 0x77, 0x79,
+ 0xf5, 0x80, 0x04, 0x2c, 0x5f, 0x48, 0x9c, 0x35, 0x8b, 0xfc, 0x37, 0x06,
+ 0xb4, 0xe0, 0x58, 0xbe, 0xd7, 0x5b, 0xa6, 0x2c, 0x5f, 0x1a, 0x15, 0x73,
+ 0x16, 0x2b, 0x0f, 0x49, 0xca, 0x69, 0x91, 0x4c, 0x50, 0x86, 0xa8, 0x4f,
+ 0xaf, 0x0c, 0xb7, 0x57, 0x74, 0x2e, 0xea, 0xc2, 0x86, 0x4d, 0xfb, 0x1b,
+ 0xf0, 0x35, 0x8b, 0xa3, 0x75, 0x62, 0xfb, 0x45, 0x9b, 0xf4, 0x78, 0x3f,
+ 0x27, 0xbc, 0xfb, 0xac, 0xb1, 0x7f, 0xe0, 0xfc, 0x6b, 0x1b, 0x18, 0x50,
+ 0xb1, 0x6e, 0xd6, 0x2f, 0xff, 0x33, 0xbc, 0xde, 0xfe, 0x4b, 0xed, 0xbd,
+ 0x62, 0xff, 0xfb, 0x3d, 0xcc, 0x33, 0x3e, 0xda, 0x14, 0x01, 0x62, 0xa1,
+ 0x15, 0xfb, 0xa2, 0x64, 0x99, 0x7e, 0x0f, 0xc5, 0x00, 0x58, 0xa8, 0x4e,
+ 0x8b, 0xb3, 0xad, 0x0f, 0x9e, 0x1d, 0xfb, 0xcc, 0x6f, 0xd1, 0xec, 0xfc,
+ 0x2c, 0x5f, 0xe7, 0xd0, 0x05, 0xd1, 0xd9, 0x62, 0xff, 0xc2, 0x29, 0xbf,
+ 0x85, 0x8c, 0x35, 0x8b, 0xd3, 0xcd, 0x8b, 0x17, 0xff, 0xdb, 0xf3, 0xad,
+ 0x3b, 0xf7, 0x2e, 0x6e, 0xb1, 0x2c, 0x54, 0x1f, 0xab, 0x8f, 0xdf, 0xfd,
+ 0xba, 0xd9, 0xf8, 0xdf, 0xcf, 0xc7, 0x6b, 0x15, 0x09, 0xa9, 0x31, 0xaf,
+ 0xe1, 0x67, 0xc2, 0x0b, 0xe8, 0xf6, 0x1d, 0x62, 0xff, 0xdc, 0xfe, 0x19,
+ 0xf6, 0x30, 0xb1, 0x62, 0x80, 0x7c, 0x5b, 0xc8, 0xaf, 0xdd, 0xc8, 0xa0,
+ 0xeb, 0x17, 0xff, 0xff, 0xf8, 0xfb, 0xad, 0xf0, 0x63, 0x97, 0x59, 0xdc,
+ 0xb8, 0xde, 0xe3, 0x77, 0x22, 0x8f, 0xc2, 0xc5, 0xfd, 0x9f, 0x6c, 0xd4,
+ 0xcb, 0x17, 0xfe, 0xce, 0xe5, 0xc6, 0xf3, 0x96, 0x2c, 0x5f, 0xec, 0x3f,
+ 0xf2, 0x67, 0x99, 0x62, 0xfc, 0xd3, 0xfe, 0x23, 0x69, 0xf9, 0xf8, 0xfa,
+ 0xb6, 0xa3, 0x87, 0x21, 0x43, 0x7f, 0xfb, 0xf1, 0xde, 0x6a, 0x3c, 0xdd,
+ 0x30, 0xd6, 0x2f, 0x0b, 0x53, 0x2c, 0x5f, 0x64, 0xd9, 0xe1, 0x9f, 0x57,
+ 0x12, 0xec, 0xc3, 0x46, 0x67, 0xe1, 0x27, 0x50, 0xaa, 0x57, 0x0a, 0x7f,
+ 0x28, 0xfe, 0xf9, 0xf5, 0xf1, 0x2c, 0x5f, 0xff, 0x37, 0xb8, 0xde, 0x8f,
+ 0x70, 0xb3, 0x0c, 0x58, 0xa9, 0x1f, 0x96, 0x11, 0xdf, 0xff, 0xf9, 0x8b,
+ 0x3d, 0x07, 0x30, 0x4f, 0x3e, 0xdc, 0xfb, 0x6b, 0xee, 0xb1, 0x7e, 0x34,
+ 0xd7, 0xf7, 0x16, 0x2f, 0xff, 0xb2, 0x77, 0x1b, 0x0b, 0xad, 0x31, 0x93,
+ 0x32, 0xc5, 0x42, 0x3b, 0x31, 0xbb, 0x45, 0x77, 0xf1, 0xdc, 0x7f, 0x72,
+ 0x58, 0xb9, 0xc2, 0x2c, 0x5e, 0xfb, 0x18, 0xb1, 0x7e, 0xee, 0x5c, 0x2c,
+ 0x39, 0xb7, 0xf0, 0xcd, 0xff, 0x77, 0x2e, 0x4d, 0xa7, 0xf7, 0x16, 0x2f,
+ 0xff, 0xff, 0xdf, 0x8d, 0x73, 0x18, 0x8d, 0xdb, 0xf6, 0xdb, 0xc6, 0x17,
+ 0x67, 0x77, 0x21, 0xac, 0x5f, 0xff, 0xff, 0xff, 0xfe, 0xd6, 0xb1, 0x8a,
+ 0x7d, 0xbf, 0x6d, 0xbd, 0x7d, 0xbe, 0xe6, 0x6d, 0x04, 0x4d, 0xb7, 0xf9,
+ 0x9b, 0x4b, 0x07, 0xf7, 0xdb, 0x98, 0x67, 0x96, 0x2e, 0x9b, 0x68, 0xd3,
+ 0x68, 0xc8, 0x43, 0xd6, 0x27, 0xb8, 0xf1, 0xd2, 0xdf, 0x8a, 0x3a, 0x91,
+ 0xd6, 0x2f, 0xff, 0x66, 0xef, 0xc5, 0x37, 0xf2, 0x69, 0x47, 0x6b, 0x17,
+ 0xff, 0x73, 0x26, 0xfc, 0x6f, 0xcf, 0xfe, 0x16, 0x28, 0x68, 0xc1, 0xd1,
+ 0x4f, 0x94, 0x6f, 0xf3, 0x83, 0x87, 0x7e, 0xfc, 0xb1, 0x4b, 0x17, 0xfd,
+ 0xc2, 0x10, 0xbd, 0x28, 0x35, 0x62, 0xbb, 0x3c, 0x7f, 0x06, 0x56, 0x23,
+ 0x3d, 0xcc, 0x04, 0xf9, 0x7f, 0xec, 0x9f, 0x51, 0x1e, 0x6f, 0xc2, 0xc5,
+ 0xff, 0x9a, 0x6e, 0x13, 0xb8, 0xfe, 0xcb, 0x17, 0xf1, 0x67, 0x3f, 0x03,
+ 0x58, 0xa8, 0x3e, 0xbc, 0x3e, 0xbf, 0xff, 0xfe, 0x28, 0xfe, 0x16, 0x30,
+ 0xc1, 0x1d, 0xcb, 0x86, 0xc4, 0x17, 0x58, 0x35, 0x8a, 0x24, 0xd1, 0x79,
+ 0x0a, 0x9f, 0x10, 0x5f, 0xfe, 0x93, 0x1a, 0xde, 0x2c, 0x96, 0xb9, 0xc5,
+ 0x8b, 0xff, 0xb0, 0xe2, 0x93, 0x8f, 0x6f, 0x8e, 0x05, 0x8b, 0xfa, 0x26,
+ 0xcd, 0xed, 0xa5, 0x8b, 0xff, 0xd2, 0xfb, 0xcb, 0xa2, 0x70, 0x81, 0x02,
+ 0x32, 0xc5, 0x42, 0x20, 0x70, 0xc2, 0xf6, 0xb0, 0x96, 0x2f, 0xf6, 0x78,
+ 0xdc, 0x72, 0x02, 0xc5, 0x31, 0xe7, 0xcc, 0x39, 0x50, 0x9d, 0x37, 0xd2,
+ 0xca, 0x19, 0x3c, 0x70, 0xbf, 0x76, 0x3f, 0xb1, 0x8b, 0x17, 0xff, 0x08,
+ 0x78, 0x42, 0x93, 0x0f, 0x00, 0xb1, 0x50, 0x7d, 0xec, 0x57, 0x7f, 0xf0,
+ 0x9c, 0xfe, 0x2c, 0x9c, 0xb3, 0xb5, 0x8b, 0xfe, 0xce, 0xa3, 0xed, 0x04,
+ 0x35, 0x8b, 0xff, 0xbf, 0x86, 0x0b, 0x1b, 0xfc, 0x89, 0xd6, 0x2e, 0x61,
+ 0x4e, 0x7f, 0xdd, 0x9c, 0x54, 0xec, 0xff, 0xf1, 0xc6, 0xf3, 0x90, 0xa3,
+ 0xea, 0x55, 0xcc, 0xd0, 0xa9, 0xd4, 0x61, 0xa7, 0x2e, 0x76, 0x40, 0x4a,
+ 0x1a, 0x28, 0xee, 0x39, 0x1b, 0x9f, 0xa3, 0xdb, 0xdf, 0x0b, 0x03, 0x08,
+ 0x02, 0x43, 0x0e, 0xfa, 0x69, 0x34, 0xcb, 0x17, 0x14, 0xeb, 0x17, 0xc0,
+ 0xd3, 0xee, 0x2c, 0x56, 0xd3, 0xe3, 0xd8, 0x09, 0x7b, 0x18, 0xbf, 0xf3,
+ 0x19, 0xba, 0xd3, 0xf2, 0x22, 0x65, 0x8b, 0x04, 0x58, 0xbb, 0xe1, 0x16,
+ 0x2f, 0xff, 0x66, 0xff, 0xbc, 0x80, 0xfd, 0x81, 0xbb, 0x58, 0xb7, 0xa0,
+ 0xfa, 0x3e, 0x35, 0x7f, 0xfd, 0xa9, 0xe3, 0x77, 0x85, 0x9e, 0xf3, 0x6b,
+ 0xa5, 0x8b, 0xfb, 0x27, 0xe1, 0x66, 0xf5, 0x8a, 0x92, 0x65, 0x0c, 0xf8,
+ 0xe4, 0xfe, 0x55, 0xbb, 0xe1, 0xac, 0x58, 0xd5, 0x8a, 0x86, 0xcf, 0x53,
+ 0x2b, 0x05, 0x16, 0x8d, 0xe3, 0x74, 0xdd, 0xe3, 0x6c, 0xe1, 0xe0, 0x63,
+ 0x37, 0xff, 0xe9, 0x67, 0x1c, 0x81, 0xfc, 0x8f, 0x72, 0x00, 0xb1, 0x7c,
+ 0xe7, 0x79, 0x2c, 0x5f, 0xfd, 0xf6, 0xdb, 0x85, 0x8d, 0xa7, 0xde, 0xb1,
+ 0x7f, 0xf3, 0x13, 0x8c, 0xb0, 0x7f, 0x8e, 0x2c, 0x5f, 0xee, 0xb0, 0xb0,
+ 0x26, 0x0d, 0x62, 0xf0, 0x71, 0xa5, 0x8b, 0xfd, 0x87, 0x7f, 0xe7, 0x60,
+ 0x58, 0xbf, 0xe9, 0xcf, 0x1a, 0xf1, 0x44, 0xeb, 0x17, 0xdd, 0x76, 0x6f,
+ 0x4b, 0x17, 0x83, 0x80, 0x2c, 0x53, 0x1e, 0x30, 0x0a, 0x2f, 0xb7, 0xc1,
+ 0x74, 0xb1, 0x7f, 0xff, 0x41, 0x60, 0x39, 0x83, 0xfc, 0x4e, 0x71, 0x10,
+ 0xd6, 0x2f, 0xff, 0x38, 0x1f, 0xf8, 0x77, 0xfe, 0x76, 0x05, 0x8a, 0x64,
+ 0x65, 0x7c, 0x94, 0x96, 0xef, 0xcd, 0xef, 0x44, 0x96, 0x2e, 0x8e, 0xd6,
+ 0x2f, 0x9e, 0x59, 0xbd, 0x62, 0xa4, 0xae, 0x0c, 0x6a, 0x86, 0x91, 0x74,
+ 0x8c, 0xc8, 0x5a, 0x35, 0xf8, 0xf3, 0x9a, 0x14, 0x20, 0x7d, 0x0e, 0xbd,
+ 0xe5, 0xdb, 0x85, 0x01, 0x06, 0x2f, 0xe2, 0xf4, 0x73, 0xcc, 0xb1, 0x7f,
+ 0xfe, 0x72, 0xeb, 0xdc, 0xc9, 0xf9, 0x1b, 0x63, 0x79, 0x2c, 0x5f, 0xfe,
+ 0x1f, 0xe3, 0x7f, 0xf3, 0xc5, 0x10, 0x75, 0x8b, 0xff, 0xd8, 0x3f, 0xc6,
+ 0xff, 0xb1, 0x85, 0x9d, 0x2c, 0x5d, 0x13, 0x62, 0x26, 0x09, 0x2e, 0xff,
+ 0x86, 0x51, 0x2c, 0x3c, 0x74, 0xb1, 0x7f, 0x76, 0x31, 0xe3, 0xce, 0xb1,
+ 0x7f, 0x61, 0x9a, 0xcf, 0xf1, 0x62, 0xff, 0xf6, 0x9f, 0xac, 0xde, 0xda,
+ 0xdc, 0x79, 0xf7, 0x16, 0x2f, 0xff, 0xdf, 0x6d, 0xe5, 0x86, 0x63, 0x79,
+ 0xb4, 0xe0, 0x58, 0xbc, 0x50, 0x35, 0x8b, 0xe9, 0x67, 0xf1, 0x62, 0xf4,
+ 0xe2, 0x25, 0x8b, 0xbb, 0xe6, 0xd4, 0xe7, 0xa0, 0xe6, 0x73, 0x01, 0x97,
+ 0xf4, 0xa9, 0x32, 0xb3, 0x8e, 0x06, 0x45, 0x70, 0x50, 0x28, 0xb1, 0x7c,
+ 0xce, 0x43, 0x58, 0xbf, 0xbe, 0xd3, 0x3b, 0xce, 0xb1, 0x7a, 0x30, 0x0b,
+ 0x16, 0x80, 0xaa, 0x23, 0x06, 0x41, 0xd1, 0x0c, 0xc5, 0xf5, 0x0b, 0x88,
+ 0x38, 0x5a, 0x78, 0x79, 0x3c, 0x79, 0x60, 0x8c, 0x3e, 0xf9, 0xa7, 0x3c,
+ 0x2c, 0x5f, 0xd1, 0xa9, 0xe3, 0x53, 0xac, 0x5f, 0xfe, 0x27, 0x33, 0xf1,
+ 0x26, 0x2c, 0x3c, 0x2c, 0x5f, 0xfd, 0x9d, 0xfa, 0x33, 0x5a, 0x88, 0x08,
+ 0xb1, 0x63, 0x26, 0x44, 0x71, 0x24, 0x5a, 0x65, 0x8b, 0xfd, 0x3e, 0x19,
+ 0x1f, 0x11, 0x2c, 0x54, 0x1e, 0x43, 0x09, 0xd4, 0x93, 0x50, 0xc8, 0x5f,
+ 0x7d, 0xca, 0xfd, 0xfc, 0xeb, 0x0c, 0x58, 0xbf, 0xed, 0xee, 0x40, 0xfe,
+ 0x01, 0xd6, 0x2f, 0xcc, 0x6f, 0x9a, 0x75, 0x8b, 0xff, 0xd9, 0x80, 0x3c,
+ 0x4d, 0xc1, 0xfd, 0xe7, 0x58, 0xa6, 0x45, 0x87, 0xce, 0x88, 0xaa, 0xff,
+ 0xf4, 0x7e, 0x0f, 0x31, 0x61, 0x9e, 0xcf, 0xac, 0x5f, 0xf8, 0xb3, 0xb9,
+ 0x73, 0x51, 0xee, 0x2c, 0x5f, 0xc5, 0xfc, 0x04, 0x12, 0xc5, 0x2c, 0x5f,
+ 0xa5, 0xa8, 0xc1, 0xac, 0x5c, 0xc2, 0xec, 0xda, 0x10, 0x65, 0xff, 0x0b,
+ 0x5c, 0x72, 0x1e, 0x01, 0x62, 0xff, 0xff, 0x64, 0xba, 0xfb, 0x7e, 0x33,
+ 0x52, 0xf1, 0x41, 0xf8, 0xb1, 0x7f, 0xd8, 0x7e, 0x41, 0xdf, 0xbf, 0x2c,
+ 0x5f, 0xf3, 0xce, 0x28, 0xc2, 0x14, 0xeb, 0x15, 0x87, 0xe9, 0xa3, 0xaa,
+ 0x64, 0xcb, 0xfe, 0x73, 0xc8, 0x6a, 0xdf, 0xfd, 0x1c, 0x2c, 0x35, 0xbf,
+ 0xfc, 0xdd, 0x58, 0xbf, 0xe1, 0x7b, 0x77, 0x98, 0xc4, 0x35, 0x8b, 0xe1,
+ 0x47, 0x63, 0x58, 0xbf, 0xd8, 0x7c, 0x9a, 0x4d, 0x8b, 0x15, 0x0b, 0x8b,
+ 0xa3, 0x86, 0xd7, 0x45, 0xc7, 0x4b, 0x74, 0x0e, 0x30, 0x7a, 0x35, 0xb1,
+ 0x1a, 0xef, 0x47, 0x30, 0xf0, 0x32, 0x4b, 0x86, 0x75, 0x8b, 0xe7, 0x38,
+ 0x67, 0x58, 0xbd, 0x1a, 0x9d, 0x62, 0xbc, 0x78, 0x41, 0x09, 0x2f, 0x0b,
+ 0xdc, 0x58, 0xbc, 0x11, 0x8c, 0x58, 0xa8, 0x5d, 0xf7, 0xc9, 0xc9, 0x29,
+ 0xa1, 0x52, 0xeb, 0x42, 0x24, 0x08, 0x3d, 0x60, 0xaa, 0xc5, 0xf6, 0x37,
+ 0xc4, 0xb1, 0x7e, 0x82, 0xcd, 0xee, 0xb1, 0x6e, 0xa6, 0x3c, 0xad, 0x11,
+ 0x54, 0xe8, 0x8a, 0xd3, 0x05, 0xff, 0xf9, 0xbd, 0xc6, 0xe9, 0xf5, 0xd7,
+ 0xdb, 0x7b, 0x9d, 0x62, 0xff, 0xff, 0x9c, 0xde, 0x0d, 0xb3, 0xbe, 0x98,
+ 0x9f, 0xb3, 0xc4, 0x71, 0x62, 0xff, 0xf1, 0xe3, 0xaf, 0x73, 0x01, 0x19,
+ 0xdc, 0x96, 0x2f, 0x8d, 0x6e, 0x99, 0x62, 0xe8, 0x96, 0x1f, 0x87, 0x93,
+ 0x2b, 0xe9, 0x82, 0x14, 0x36, 0x2f, 0x0f, 0x24, 0xb1, 0x7b, 0x75, 0x8c,
+ 0x58, 0xbc, 0x6b, 0x74, 0xb1, 0x7e, 0x6d, 0xe5, 0x9c, 0xda, 0x7b, 0xbf,
+ 0x1d, 0xf1, 0x0d, 0xff, 0x6f, 0xc1, 0xcd, 0x98, 0x46, 0xac, 0x5f, 0xfe,
+ 0x94, 0x73, 0xf0, 0x5e, 0xfe, 0xeb, 0x1d, 0x62, 0x89, 0x11, 0x3e, 0x3c,
+ 0xbf, 0xf4, 0x1f, 0x8d, 0xa8, 0xf3, 0x6f, 0x58, 0xbf, 0x6e, 0xb7, 0xde,
+ 0x65, 0x8b, 0x7a, 0x0f, 0xb3, 0xe8, 0x17, 0xf4, 0x74, 0x4f, 0xdf, 0x96,
+ 0x2f, 0x88, 0x4f, 0x25, 0x8b, 0xfd, 0xcd, 0x44, 0xef, 0xae, 0x96, 0x2f,
+ 0xa7, 0xdc, 0x83, 0xac, 0x53, 0x1e, 0xe8, 0x66, 0xd7, 0xfe, 0x8e, 0xfd,
+ 0xc1, 0x1f, 0x3b, 0xf2, 0xc5, 0x49, 0x54, 0xf3, 0x43, 0x5f, 0x76, 0x11,
+ 0xc7, 0x27, 0xe1, 0x7f, 0x9f, 0xf7, 0x91, 0x5f, 0xa3, 0xd3, 0xe1, 0x8b,
+ 0x17, 0xfe, 0xef, 0xa2, 0x79, 0xde, 0x4d, 0xf5, 0x8a, 0xd1, 0xf5, 0x88,
+ 0xaa, 0xf3, 0x03, 0x8b, 0x17, 0xd9, 0x3e, 0xff, 0x2c, 0x56, 0x1e, 0x18,
+ 0x87, 0x6f, 0xfe, 0xe3, 0xf7, 0xef, 0x67, 0x43, 0x14, 0xeb, 0x16, 0xce,
+ 0x8f, 0xab, 0xc4, 0x37, 0xe1, 0xf4, 0x2c, 0xdd, 0x58, 0xbf, 0xf1, 0x47,
+ 0x7f, 0x86, 0x27, 0x1a, 0xc5, 0x4c, 0x7d, 0x47, 0x2d, 0xbe, 0xe6, 0x11,
+ 0xab, 0x17, 0xd1, 0x92, 0x75, 0x8a, 0xec, 0xf1, 0x3e, 0x47, 0x7f, 0xff,
+ 0xbf, 0x9e, 0xdc, 0xc2, 0x68, 0xec, 0xb3, 0x7c, 0x61, 0x8b, 0x17, 0xff,
+ 0xe1, 0x69, 0xf9, 0x02, 0x0b, 0xc7, 0xf1, 0xcb, 0xa5, 0x8a, 0xe2, 0x2f,
+ 0x7c, 0xc9, 0x7c, 0x0d, 0x80, 0x2a, 0x14, 0x58, 0xa6, 0x3d, 0x4d, 0x11,
+ 0xd4, 0x27, 0x78, 0x36, 0x77, 0x8c, 0xd2, 0xff, 0x0f, 0x7c, 0x17, 0xb0,
+ 0x0b, 0x17, 0xe8, 0xf7, 0xe3, 0xcb, 0x17, 0x10, 0x16, 0x2a, 0x73, 0xf4,
+ 0xd1, 0xab, 0x94, 0x5f, 0xe7, 0xef, 0x9a, 0xcf, 0xf1, 0x62, 0x96, 0x2f,
+ 0xe1, 0x77, 0x33, 0x16, 0x2c, 0x5f, 0xff, 0xfe, 0x16, 0xbf, 0x93, 0x4c,
+ 0xfa, 0x9b, 0xdf, 0x10, 0x39, 0x8d, 0xbc, 0x70, 0xb1, 0x7f, 0xcd, 0xfe,
+ 0x69, 0x8a, 0x0e, 0xb1, 0x7f, 0x47, 0x37, 0x5b, 0xbf, 0x2c, 0x5f, 0xd1,
+ 0xc9, 0x8b, 0x26, 0x58, 0xa6, 0x4c, 0x5f, 0x75, 0xfb, 0x47, 0x1f, 0x32,
+ 0xbf, 0x7b, 0xee, 0x46, 0xac, 0x5f, 0xe0, 0x84, 0x21, 0x74, 0xc6, 0xac,
+ 0x5b, 0xcb, 0x14, 0xb1, 0x7c, 0xc6, 0x1d, 0xfb, 0x2f, 0xbc, 0x25, 0x7f,
+ 0x85, 0x38, 0xff, 0x85, 0x0b, 0x15, 0x08, 0xc2, 0xe9, 0x58, 0x8e, 0x2f,
+ 0xf3, 0x61, 0x93, 0x49, 0x89, 0x62, 0xff, 0xfa, 0x0f, 0xba, 0xd1, 0x05,
+ 0xac, 0x63, 0xe2, 0xc5, 0xff, 0xd8, 0x3f, 0xc1, 0x9d, 0xcb, 0xc2, 0x1a,
+ 0xc5, 0xfc, 0x0c, 0x63, 0xc6, 0xea, 0xc5, 0xff, 0xc0, 0xfb, 0x0b, 0xdc,
+ 0xf8, 0xb3, 0xcb, 0x17, 0x67, 0x16, 0x2e, 0x7f, 0x2c, 0x5a, 0x5a, 0x35,
+ 0xdf, 0x17, 0xa7, 0x44, 0xd8, 0x9d, 0x2b, 0x11, 0xdb, 0xc8, 0x65, 0xd4,
+ 0xeb, 0x8f, 0xe3, 0x8d, 0x1b, 0x10, 0x3a, 0x87, 0x5e, 0xe9, 0x7c, 0xc6,
+ 0x84, 0x9f, 0xe8, 0xcd, 0x68, 0x28, 0xba, 0x29, 0x93, 0x91, 0x77, 0xff,
+ 0xb3, 0x5b, 0x17, 0x3c, 0x4d, 0xdf, 0x36, 0xf9, 0x62, 0xff, 0xfd, 0x9b,
+ 0xae, 0x40, 0x9f, 0x0c, 0x31, 0xc8, 0xa1, 0x62, 0xff, 0xf6, 0x41, 0x67,
+ 0x45, 0x9e, 0x13, 0x98, 0xb1, 0x7f, 0xf1, 0x7f, 0x23, 0xb7, 0x6e, 0x06,
+ 0x6a, 0xc5, 0xff, 0xfa, 0x4d, 0xed, 0xa3, 0xfc, 0x68, 0xb3, 0x7b, 0xf9,
+ 0x62, 0xa1, 0x13, 0xf3, 0x23, 0x5f, 0xff, 0x4e, 0xe5, 0xee, 0x08, 0xbd,
+ 0xef, 0xb8, 0xd6, 0x2f, 0xfb, 0x01, 0xb9, 0x8e, 0x3c, 0xe2, 0xc5, 0xff,
+ 0xcd, 0xef, 0xe3, 0x4b, 0x99, 0xdf, 0x96, 0x2a, 0x4a, 0x8d, 0x06, 0xb1,
+ 0x90, 0xe8, 0x72, 0x32, 0x51, 0xe1, 0xdd, 0xfc, 0x51, 0x2f, 0xf0, 0x0b,
+ 0x17, 0xfc, 0x02, 0xcf, 0x71, 0xdc, 0x96, 0x2f, 0xfe, 0x16, 0x4d, 0x8d,
+ 0xd1, 0x67, 0xf1, 0x62, 0xc0, 0x1a, 0x2a, 0x7a, 0x2e, 0x23, 0x7b, 0xc7,
+ 0x7e, 0xd6, 0x2f, 0xff, 0xe9, 0x30, 0xf3, 0xf9, 0x3c, 0x49, 0xb9, 0xcc,
+ 0xdd, 0x58, 0xad, 0x22, 0xc8, 0x06, 0xde, 0x1e, 0xb8, 0x46, 0xac, 0x5f,
+ 0xec, 0xf8, 0xff, 0x05, 0x3a, 0xc5, 0x87, 0xf3, 0xcd, 0x30, 0x66, 0xfb,
+ 0xf8, 0x36, 0x58, 0xa8, 0x3c, 0xbe, 0x14, 0xd4, 0x36, 0x83, 0x12, 0x24,
+ 0x1c, 0x6b, 0xb9, 0x2c, 0x8d, 0xa1, 0xbf, 0xa8, 0x67, 0xfe, 0x52, 0x73,
+ 0xc2, 0xa4, 0x05, 0xe5, 0x3a, 0x93, 0xc3, 0x1f, 0x4a, 0x87, 0x14, 0x76,
+ 0xc1, 0xc3, 0x22, 0xff, 0x60, 0xe7, 0xd0, 0xa0, 0x0b, 0x17, 0xff, 0xc0,
+ 0x7f, 0xe0, 0x00, 0xfa, 0xcd, 0xff, 0xc5, 0x8b, 0xff, 0xf7, 0xb8, 0x42,
+ 0x17, 0x72, 0xe0, 0xff, 0x8d, 0xe5, 0x8a, 0xd2, 0x37, 0x8e, 0x6a, 0x4a,
+ 0x37, 0xf4, 0xb5, 0xa8, 0x3f, 0x16, 0x2a, 0x0f, 0x7b, 0xb2, 0xfb, 0xff,
+ 0xc4, 0xc3, 0x1c, 0x7b, 0x83, 0xfc, 0x12, 0xc5, 0x8e, 0xb1, 0x7e, 0x03,
+ 0x14, 0xb8, 0xb1, 0x5d, 0x9b, 0xaf, 0x09, 0x56, 0x22, 0x95, 0xa1, 0x07,
+ 0x7f, 0x7e, 0x66, 0xfb, 0x1d, 0x62, 0xe0, 0x71, 0x62, 0xfb, 0xa2, 0x17,
+ 0x16, 0x2f, 0xf8, 0x78, 0x72, 0xcf, 0x7d, 0x96, 0x2f, 0x6a, 0x06, 0xb1,
+ 0x7e, 0x28, 0xe9, 0xdd, 0x62, 0xec, 0xe1, 0xa7, 0x89, 0xe1, 0xdb, 0xf0,
+ 0xb4, 0x0d, 0x8f, 0x61, 0x2c, 0x56, 0x26, 0x06, 0xc4, 0x9f, 0x7c, 0xe1,
+ 0x75, 0x62, 0x70, 0xcc, 0x5f, 0xf8, 0xc6, 0xef, 0xb8, 0x51, 0x3a, 0xc5,
+ 0xff, 0x78, 0x5b, 0x73, 0x3a, 0xc8, 0x58, 0xad, 0x1e, 0xf1, 0x11, 0xdf,
+ 0xff, 0x82, 0x16, 0x6f, 0x7e, 0x36, 0x17, 0xf7, 0x58, 0xeb, 0x16, 0x96,
+ 0x1f, 0xdb, 0x10, 0xde, 0x8c, 0x25, 0x8b, 0xa0, 0x96, 0x2b, 0x46, 0xc4,
+ 0xe3, 0x77, 0xc6, 0xea, 0x0e, 0xb1, 0x7a, 0x7c, 0x31, 0x62, 0xec, 0x9d,
+ 0x62, 0xb6, 0x9f, 0xe4, 0x10, 0x98, 0x49, 0xb8, 0x3f, 0x7f, 0x85, 0xcf,
+ 0xbc, 0x86, 0xcb, 0x17, 0xff, 0xff, 0xe8, 0x29, 0xfd, 0xcc, 0x33, 0xf1,
+ 0xbf, 0xc5, 0x1d, 0xff, 0x1c, 0x79, 0x87, 0x58, 0xbf, 0xcc, 0x5e, 0x96,
+ 0x6b, 0x16, 0x2f, 0xf0, 0xde, 0x5e, 0xe3, 0x81, 0x62, 0xf3, 0x41, 0xd6,
+ 0x2e, 0x8e, 0xb0, 0xf4, 0x34, 0x69, 0x53, 0xa6, 0x69, 0x28, 0x42, 0x94,
+ 0x20, 0xaf, 0xff, 0x1f, 0x07, 0xef, 0x88, 0x06, 0xe1, 0x79, 0x62, 0xff,
+ 0xe0, 0x3e, 0xb3, 0x7e, 0x30, 0xfe, 0xcb, 0x15, 0x88, 0x91, 0x3a, 0x65,
+ 0xff, 0x9c, 0x1a, 0x82, 0xf7, 0xf2, 0x4b, 0x17, 0xff, 0x81, 0x8c, 0x5e,
+ 0xc3, 0xbf, 0x80, 0xeb, 0x15, 0x09, 0xba, 0x64, 0x33, 0x18, 0x88, 0x47,
+ 0xd7, 0xb3, 0xee, 0xb1, 0x7f, 0xee, 0x0f, 0xf1, 0x34, 0x9b, 0x52, 0x58,
+ 0xbc, 0x21, 0x12, 0xc5, 0xf9, 0xbf, 0xfc, 0x1a, 0xc5, 0x2c, 0x0c, 0xf1,
+ 0x78, 0x3b, 0x5d, 0xa2, 0xc2, 0x68, 0x43, 0x50, 0xd1, 0xec, 0xf0, 0xcc,
+ 0xbf, 0xf6, 0x4b, 0xef, 0x2d, 0xbe, 0x93, 0x2c, 0x5f, 0x8b, 0x00, 0x2e,
+ 0x2c, 0x5f, 0xe8, 0xf7, 0xf1, 0x89, 0xd6, 0x2a, 0x73, 0xd9, 0xd1, 0x45,
+ 0xfe, 0x06, 0xe6, 0x38, 0xf3, 0x8b, 0x17, 0xb7, 0x58, 0xeb, 0x17, 0xff,
+ 0xce, 0x0e, 0x40, 0x3d, 0x8c, 0x3c, 0x29, 0x96, 0x3e, 0x68, 0x2a, 0x11,
+ 0xb1, 0x84, 0x6e, 0xad, 0x7f, 0xa5, 0xef, 0xe6, 0xa3, 0xcb, 0x17, 0xf1,
+ 0x99, 0xd7, 0x58, 0x62, 0xc5, 0xdd, 0x6f, 0x58, 0xb0, 0x16, 0x2f, 0xff,
+ 0x4b, 0x99, 0xa8, 0xe1, 0x60, 0x05, 0xc5, 0x8a, 0xc3, 0xdc, 0x71, 0x2a,
+ 0x84, 0x4b, 0xfd, 0xde, 0xb1, 0x1d, 0x7e, 0x86, 0x4d, 0xff, 0xfb, 0x23,
+ 0xf1, 0xbf, 0xf1, 0xbb, 0xb5, 0xfc, 0xe6, 0xac, 0x5f, 0xfe, 0xc0, 0x80,
+ 0x3c, 0x4d, 0xe6, 0x16, 0xb8, 0xb1, 0x7f, 0x8f, 0x98, 0x5e, 0xdc, 0xc5,
+ 0x8b, 0xff, 0xb9, 0xe8, 0x8d, 0x02, 0x62, 0xc3, 0x16, 0x2f, 0x80, 0x07,
+ 0x1a, 0xc5, 0xd9, 0xda, 0xc5, 0xbf, 0x86, 0xed, 0x88, 0xeb, 0xb4, 0x6d,
+ 0xb9, 0xa8, 0x21, 0x03, 0x78, 0xd9, 0x09, 0x62, 0xc7, 0x58, 0xb9, 0xfc,
+ 0xb1, 0x7b, 0xf1, 0xa9, 0xcd, 0x49, 0xc4, 0xaf, 0xf0, 0x9c, 0xbf, 0x8f,
+ 0x32, 0xc5, 0xbb, 0x98, 0xf9, 0x8c, 0x33, 0xa6, 0x46, 0xcb, 0xc2, 0xba,
+ 0xa1, 0x5f, 0xfe, 0x46, 0x3e, 0x69, 0x3b, 0x2e, 0x3c, 0x65, 0x25, 0x18,
+ 0x75, 0xff, 0x38, 0x4d, 0x61, 0x13, 0xcc, 0xb1, 0x77, 0xce, 0xb1, 0x50,
+ 0xcf, 0x25, 0x94, 0x31, 0xf2, 0x3a, 0xce, 0xe3, 0x0e, 0x68, 0x69, 0xe9,
+ 0x07, 0xf2, 0xb7, 0x1e, 0x33, 0x60, 0x13, 0x94, 0x6e, 0x5c, 0x9c, 0x2c,
+ 0x13, 0x39, 0x87, 0x57, 0xda, 0xcf, 0xf1, 0x62, 0xe1, 0x12, 0xc5, 0xf7,
+ 0x7c, 0x8e, 0xd6, 0x2b, 0x62, 0x3d, 0xf0, 0xb9, 0x19, 0x0b, 0xdf, 0xfe,
+ 0xfb, 0x08, 0xa7, 0xc1, 0xcc, 0x21, 0x69, 0x62, 0xfd, 0x33, 0x4f, 0x9d,
+ 0xac, 0x5e, 0xd0, 0xa4, 0xb1, 0x5d, 0x9e, 0x4f, 0x8a, 0xef, 0xed, 0xbe,
+ 0x28, 0x3f, 0x16, 0x2f, 0xb3, 0x98, 0x62, 0xc5, 0x49, 0x30, 0xc6, 0x84,
+ 0xb3, 0x91, 0x91, 0x85, 0x2c, 0x5f, 0x60, 0xde, 0x4b, 0x17, 0xcf, 0xad,
+ 0x66, 0xe9, 0xae, 0x0c, 0x32, 0xf1, 0x60, 0x16, 0x2d, 0x0b, 0x14, 0x03,
+ 0x5b, 0xe1, 0xcb, 0x9f, 0xcb, 0x15, 0xa3, 0x71, 0xf2, 0x1b, 0xe3, 0xc6,
+ 0xb8, 0xb1, 0x70, 0x7a, 0x58, 0xbf, 0x4e, 0xdc, 0x6d, 0xeb, 0x17, 0xfa,
+ 0x0e, 0x58, 0x01, 0x71, 0x62, 0xff, 0xb5, 0x9f, 0xc9, 0xf6, 0xb7, 0x16,
+ 0x2b, 0x11, 0xee, 0xc4, 0x3f, 0x23, 0x71, 0x92, 0x2b, 0x11, 0x9d, 0xfe,
+ 0x93, 0x73, 0x91, 0xa9, 0x2c, 0x5f, 0x39, 0xe1, 0x96, 0x2f, 0x79, 0x8c,
+ 0x58, 0xa1, 0x9f, 0x9c, 0xc6, 0x86, 0x10, 0xdf, 0xcc, 0x42, 0x96, 0x71,
+ 0x62, 0xff, 0xfd, 0x26, 0xf7, 0x3a, 0xfb, 0x7b, 0xb9, 0x37, 0xb8, 0xb1,
+ 0x7f, 0xb0, 0x71, 0xdc, 0xb3, 0xcb, 0x17, 0xb9, 0x2e, 0xd6, 0x2e, 0xc9,
+ 0xd6, 0x2f, 0xd0, 0x03, 0xbc, 0xb6, 0x9b, 0x7d, 0x0f, 0xde, 0x9f, 0x02,
+ 0x2c, 0x5f, 0xd1, 0x9e, 0xe3, 0xf6, 0xb1, 0x7f, 0xde, 0x8e, 0xc0, 0xff,
+ 0xfb, 0x2c, 0x5f, 0x36, 0xe6, 0x4e, 0xb1, 0x58, 0x7c, 0x1e, 0x3a, 0xb1,
+ 0xd6, 0x2f, 0xc4, 0x29, 0x67, 0x36, 0x9b, 0x3d, 0xe4, 0x37, 0x8c, 0x79,
+ 0xd6, 0x29, 0x8f, 0x83, 0xe8, 0x35, 0x0a, 0xb0, 0xcd, 0x31, 0x98, 0xb4,
+ 0xeb, 0x3f, 0x6b, 0x23, 0xfe, 0x10, 0x7a, 0x32, 0x1b, 0xef, 0x8b, 0x3c,
+ 0xb1, 0x7f, 0xe1, 0x77, 0x2e, 0x7f, 0x27, 0x11, 0x2c, 0x5f, 0xed, 0xba,
+ 0xdd, 0x60, 0x60, 0xd6, 0x2f, 0xc4, 0xfe, 0x73, 0xac, 0x5c, 0xfd, 0x2c,
+ 0x5f, 0x8d, 0xc1, 0x6a, 0x75, 0x8a, 0x73, 0xc3, 0x10, 0xc5, 0x32, 0x65,
+ 0x3a, 0x23, 0x3a, 0x10, 0x67, 0x21, 0x1a, 0xad, 0xb3, 0xb1, 0xc2, 0x80,
+ 0x60, 0x28, 0xc7, 0xb0, 0x46, 0x3b, 0xb1, 0x3d, 0xec, 0x37, 0xf0, 0xb7,
+ 0x2c, 0x89, 0xd1, 0x49, 0xe3, 0x6d, 0x94, 0x7e, 0x83, 0xa5, 0x1a, 0xe5,
+ 0x69, 0xfe, 0x6c, 0xe9, 0xc7, 0x53, 0xd0, 0x9d, 0xc6, 0xda, 0xd2, 0x8e,
+ 0xf7, 0x5e, 0xa6, 0x9d, 0xe8, 0xd4, 0xf2, 0x91, 0xe5, 0x33, 0xfe, 0xb6,
+ 0x14, 0x79, 0xc0, 0x20, 0x4e, 0x82, 0x85, 0xd6, 0xca, 0x7d, 0xab, 0x95,
+ 0xa8, 0x4f, 0xab, 0x15, 0xe1, 0x46, 0x87, 0xbe, 0x34, 0x33, 0x1b, 0xb7,
+ 0x23, 0x97, 0x0e, 0x5c, 0x48, 0x48, 0xe8, 0xaf, 0xdb, 0x23, 0xde, 0xd0,
+ 0xb1, 0x7f, 0xdb, 0x3c, 0xd4, 0x0b, 0xc2, 0x3a, 0xc5, 0xff, 0xe9, 0x73,
+ 0x64, 0x3c, 0xd7, 0xda, 0x69, 0x1d, 0x62, 0xa4, 0x88, 0xfe, 0xcf, 0xab,
+ 0x48, 0xe0, 0x78, 0x5e, 0x5f, 0xc1, 0x18, 0x65, 0x13, 0x2c, 0x5e, 0x87,
+ 0x25, 0x8b, 0xec, 0xfb, 0xf9, 0x62, 0xc1, 0x5c, 0x3e, 0xdf, 0x98, 0x10,
+ 0xdd, 0xfd, 0xb0, 0xf6, 0x07, 0xf6, 0x04, 0x58, 0xbf, 0xfa, 0x0e, 0x51,
+ 0xb6, 0x69, 0x46, 0xa7, 0x58, 0xbf, 0xfd, 0x1a, 0x14, 0xd3, 0x37, 0xd8,
+ 0xee, 0x35, 0x8b, 0xfb, 0x0f, 0xb6, 0x62, 0x99, 0x62, 0xfe, 0x80, 0x72,
+ 0x34, 0x35, 0x8b, 0xf3, 0xfb, 0x91, 0xba, 0xb1, 0x43, 0x44, 0x5f, 0xcc,
+ 0x88, 0xba, 0xfe, 0xf8, 0x61, 0x20, 0x80, 0xb1, 0x7d, 0x20, 0xcc, 0xc5,
+ 0x8b, 0xff, 0xff, 0x17, 0xb9, 0x0d, 0x2c, 0x08, 0x5e, 0x8f, 0xc1, 0xa2,
+ 0x80, 0x8b, 0x17, 0x82, 0x0e, 0x16, 0x2b, 0x11, 0x66, 0xe4, 0xa2, 0x6f,
+ 0xbf, 0x0b, 0xd3, 0x41, 0xab, 0x17, 0xfd, 0x13, 0xf2, 0x66, 0x3b, 0xcc,
+ 0xb1, 0x43, 0x55, 0x8f, 0xd2, 0x43, 0x43, 0x5e, 0x62, 0xff, 0xc3, 0x90,
+ 0x8b, 0x82, 0x15, 0xdf, 0xff, 0xfd, 0x81, 0x09, 0xfa, 0x09, 0xb3, 0xc6,
+ 0x30, 0xb3, 0x9b, 0x5f, 0xc2, 0x85, 0x8b, 0x7d, 0x62, 0xcc, 0xb1, 0x46,
+ 0x9a, 0x30, 0x09, 0x56, 0x91, 0x81, 0xc8, 0x4f, 0x5f, 0xdd, 0x3e, 0xa7,
+ 0xc3, 0x16, 0x2b, 0x0f, 0x65, 0x8a, 0x2f, 0xcf, 0x37, 0x9c, 0x6b, 0x17,
+ 0xff, 0xef, 0xe1, 0x61, 0xbf, 0x79, 0x7c, 0xc7, 0x0c, 0xeb, 0x16, 0xed,
+ 0x62, 0xff, 0xa1, 0xb9, 0x8d, 0xf8, 0xf2, 0xc5, 0x48, 0xf2, 0xbe, 0x27,
+ 0x7f, 0x4b, 0xf9, 0xef, 0xb2, 0xc5, 0xf7, 0x4e, 0xfd, 0x2a, 0x2d, 0x62,
+ 0xff, 0xe6, 0xd7, 0xdf, 0x8f, 0xe2, 0x70, 0x2c, 0x5f, 0xf3, 0x9f, 0x8d,
+ 0x9b, 0xdf, 0x4b, 0x17, 0xcd, 0xad, 0xd1, 0xac, 0x54, 0x93, 0xc6, 0x68,
+ 0x51, 0x6e, 0x91, 0x68, 0xbb, 0xe6, 0x24, 0x87, 0xbc, 0xea, 0xfd, 0x92,
+ 0x6f, 0x89, 0x62, 0xff, 0xa4, 0x26, 0xfc, 0xee, 0x43, 0x58, 0xbf, 0xf1,
+ 0x3e, 0xa2, 0x6d, 0xb9, 0xa6, 0x58, 0xbf, 0xff, 0x70, 0xa2, 0x6d, 0x30,
+ 0x21, 0x82, 0x0f, 0x38, 0xb1, 0x7f, 0x31, 0xde, 0x6c, 0xfa, 0xc5, 0x32,
+ 0x31, 0x66, 0x40, 0x3a, 0xbd, 0xf8, 0x18, 0x10, 0xbc, 0xb1, 0x7f, 0x84,
+ 0x58, 0x11, 0x8c, 0x65, 0x8b, 0xee, 0x39, 0x74, 0xb1, 0x5f, 0x3d, 0x80,
+ 0x86, 0xb7, 0xf8, 0xbc, 0xc6, 0x93, 0x9d, 0x62, 0xfe, 0x82, 0x00, 0x4c,
+ 0x9d, 0x62, 0xdf, 0x73, 0xe3, 0x30, 0xce, 0xe8, 0xf2, 0xc5, 0x42, 0x69,
+ 0x19, 0x08, 0x26, 0x84, 0x3c, 0xc5, 0x17, 0xb5, 0x07, 0x58, 0xbf, 0xbf,
+ 0x9c, 0x89, 0xc2, 0x2c, 0x5f, 0xfe, 0x1c, 0x1c, 0xa3, 0x6c, 0xd2, 0x8d,
+ 0x4e, 0xb1, 0x70, 0x06, 0xb1, 0x7d, 0xd3, 0xbf, 0x4a, 0x8a, 0x0c, 0xbf,
+ 0xfd, 0xf8, 0xfb, 0x1b, 0x9d, 0x7e, 0x09, 0xd6, 0x2b, 0x47, 0xf7, 0xc3,
+ 0x1b, 0xec, 0xeb, 0x3b, 0x58, 0xba, 0x5b, 0x30, 0x99, 0x38, 0xd3, 0xb2,
+ 0x12, 0x7f, 0x22, 0xac, 0x4e, 0xa1, 0xe3, 0x58, 0xbf, 0xef, 0x84, 0x70,
+ 0x6c, 0xc7, 0x0c, 0x58, 0xbd, 0x34, 0x79, 0x62, 0xf8, 0x5e, 0x8e, 0x2c,
+ 0x54, 0x22, 0x07, 0x10, 0x08, 0x7a, 0xdd, 0x2c, 0x5f, 0xfb, 0x07, 0x1a,
+ 0x9c, 0x5b, 0x79, 0x25, 0x8b, 0xfb, 0xf9, 0xef, 0xb9, 0xd6, 0x2f, 0xf6,
+ 0xdf, 0x41, 0xdb, 0x53, 0x2c, 0x56, 0x1f, 0x28, 0x0b, 0xaf, 0xec, 0x2e,
+ 0x9c, 0x80, 0xb1, 0x5b, 0x53, 0x09, 0xe8, 0x4c, 0xa1, 0x51, 0xc2, 0x1b,
+ 0xc6, 0xc7, 0x16, 0x2f, 0xf7, 0x8b, 0x00, 0xe4, 0x05, 0x8b, 0xe1, 0x39,
+ 0x75, 0x87, 0xa0, 0x18, 0xf5, 0xfe, 0x94, 0x6a, 0x78, 0xd4, 0xeb, 0x17,
+ 0xfb, 0xb9, 0x46, 0x7b, 0x6e, 0x2c, 0x5e, 0xea, 0x3a, 0x58, 0xa8, 0x44,
+ 0x5e, 0x1b, 0x39, 0xb5, 0xf8, 0xf8, 0x10, 0x80, 0xb1, 0x7b, 0x0e, 0xcb,
+ 0x17, 0xff, 0x9b, 0x93, 0x87, 0xe6, 0x21, 0x4b, 0x38, 0xb1, 0x79, 0x8d,
+ 0x3a, 0xc5, 0x0c, 0xfa, 0xb4, 0x99, 0x7b, 0xd9, 0xf5, 0x8b, 0xfd, 0x05,
+ 0xe8, 0xd3, 0x1d, 0x62, 0xef, 0x32, 0xc5, 0xff, 0xf6, 0x01, 0xf5, 0x9b,
+ 0xf0, 0x78, 0x78, 0xe9, 0x62, 0xa1, 0x38, 0x91, 0x95, 0x64, 0x21, 0x8d,
+ 0x22, 0xf8, 0xeb, 0x99, 0x10, 0xbd, 0xc7, 0x99, 0x62, 0xf8, 0x02, 0x29,
+ 0x96, 0x2e, 0x6e, 0x96, 0x2a, 0x0d, 0xe6, 0xe1, 0x25, 0xbf, 0xb4, 0xfe,
+ 0x36, 0x55, 0x6f, 0xed, 0x73, 0x35, 0x1c, 0x58, 0xbe, 0xe1, 0xe0, 0x0b,
+ 0x14, 0xc7, 0xa2, 0xe5, 0xd7, 0xe9, 0x80, 0xe5, 0x32, 0xc5, 0xc4, 0xcb,
+ 0x15, 0x07, 0x81, 0xd1, 0x55, 0xf3, 0x83, 0x34, 0xb1, 0x7d, 0x1b, 0x23,
+ 0x1a, 0xc5, 0xfe, 0xc1, 0x75, 0xf8, 0xd6, 0x2c, 0x5f, 0xf6, 0xa0, 0xc2,
+ 0xc1, 0xb6, 0x96, 0x2f, 0xff, 0xb3, 0xff, 0x76, 0xf4, 0x16, 0x7f, 0x3a,
+ 0x58, 0xac, 0x54, 0x06, 0x6b, 0xf3, 0x30, 0x7c, 0x88, 0x88, 0xb8, 0x4c,
+ 0x23, 0x4d, 0xc3, 0x9b, 0xff, 0xf6, 0x6c, 0x96, 0x31, 0x44, 0xce, 0x42,
+ 0x69, 0xd6, 0x2f, 0xe6, 0xf0, 0xa6, 0x6f, 0x2c, 0x50, 0xd1, 0x0b, 0x32,
+ 0xb5, 0xff, 0xce, 0x13, 0x98, 0x10, 0x9f, 0xd8, 0x11, 0x62, 0xff, 0x3c,
+ 0xef, 0x9e, 0xc3, 0xac, 0x5f, 0xff, 0xfd, 0xa0, 0x38, 0xe3, 0x41, 0x39,
+ 0x81, 0x08, 0x11, 0x30, 0x61, 0x04, 0x75, 0x8b, 0xff, 0xf9, 0xfd, 0x87,
+ 0xc6, 0x9a, 0x5f, 0xc1, 0x8b, 0xdc, 0x58, 0xbf, 0xfe, 0xf3, 0x98, 0x58,
+ 0xc0, 0x9b, 0x3e, 0x19, 0x2c, 0x5f, 0xff, 0x71, 0xa7, 0x7e, 0x39, 0x3f,
+ 0xbf, 0x13, 0x2c, 0x5f, 0xf9, 0xc8, 0x19, 0xe8, 0x26, 0x02, 0xc5, 0x42,
+ 0x76, 0x83, 0x7b, 0xfa, 0xe7, 0x94, 0x77, 0x14, 0x2f, 0xff, 0xfa, 0x4c,
+ 0x63, 0xfe, 0x07, 0xd3, 0xcf, 0xe2, 0xc9, 0xf5, 0x0b, 0x16, 0xd9, 0xd8,
+ 0x9b, 0x7b, 0xdd, 0x84, 0x6f, 0x12, 0xc0, 0xa5, 0x1c, 0x58, 0xc8, 0x32,
+ 0x3e, 0xf3, 0x5b, 0x7b, 0x28, 0x68, 0x7f, 0xcd, 0x1b, 0xc6, 0x91, 0x8f,
+ 0x1e, 0x2f, 0xe1, 0x52, 0xf1, 0x9b, 0x02, 0x12, 0xa5, 0x0c, 0x4e, 0x47,
+ 0x6d, 0xe9, 0x5c, 0x42, 0x87, 0xc9, 0x84, 0x9b, 0x89, 0x21, 0xc7, 0xce,
+ 0x11, 0x36, 0xff, 0x1b, 0xb2, 0xff, 0xfe, 0x4e, 0xb1, 0x7f, 0xfb, 0x64,
+ 0xef, 0x2d, 0x9c, 0xd7, 0x4e, 0xfd, 0x2a, 0x28, 0xb2, 0xff, 0x6c, 0xe6,
+ 0xba, 0x77, 0xe9, 0x51, 0x75, 0x15, 0x10, 0xd5, 0x9a, 0x94, 0xa1, 0x7c,
+ 0x6e, 0xea, 0x31, 0xc6, 0xa4, 0x56, 0x9e, 0x93, 0x89, 0xfc, 0x50, 0x9b,
+ 0xbc, 0xb8, 0x00, 0x57, 0x0a, 0x25, 0x1d, 0x1f, 0x0e, 0x7c, 0xbf, 0x7e,
+ 0xd7, 0x4e, 0xfd, 0x2a, 0x22, 0x12, 0xd3, 0xac, 0x5f, 0xe8, 0x3c, 0x30,
+ 0xf0, 0xeb, 0x17, 0xbe, 0xc4, 0xb1, 0x76, 0x0d, 0x62, 0xdd, 0x2c, 0x57,
+ 0x47, 0x8d, 0xf1, 0xc2, 0x17, 0xbe, 0xcd, 0xed, 0xa5, 0x8b, 0xe6, 0xd6,
+ 0x76, 0xb1, 0x58, 0x99, 0xc1, 0xa6, 0xfd, 0x09, 0xf6, 0xf1, 0xba, 0x5f,
+ 0xb8, 0x49, 0x7f, 0xf4, 0xf8, 0x66, 0xcf, 0x06, 0x27, 0xd4, 0x96, 0x2f,
+ 0x8a, 0x01, 0xc5, 0x8b, 0xfb, 0x42, 0xfe, 0xfc, 0x1a, 0xc5, 0xec, 0xc1,
+ 0xac, 0x5f, 0xff, 0xfe, 0xf3, 0x10, 0xa5, 0x9c, 0x2c, 0x9c, 0x39, 0x6d,
+ 0xe0, 0x80, 0x78, 0x92, 0xc5, 0xde, 0xd9, 0x99, 0x1d, 0x7a, 0x22, 0x23,
+ 0x10, 0xc7, 0x2b, 0x65, 0x3e, 0x39, 0x30, 0x64, 0x66, 0xd7, 0xff, 0x6c,
+ 0x85, 0xe0, 0xbc, 0x19, 0xcb, 0x27, 0x58, 0xb6, 0xe2, 0xc5, 0xf4, 0x7e,
+ 0x0e, 0xb1, 0x7d, 0xd3, 0xbf, 0x4a, 0x88, 0xd8, 0xae, 0x8f, 0x4f, 0x44,
+ 0x57, 0xb4, 0xf3, 0xac, 0x5b, 0x64, 0x68, 0xa9, 0xc6, 0x8f, 0x11, 0xdf,
+ 0xed, 0x9c, 0xd7, 0x4e, 0xfd, 0x2a, 0x29, 0xb2, 0xe7, 0x92, 0xc5, 0xf7,
+ 0x4e, 0xfd, 0x2a, 0x2a, 0x02, 0x86, 0x79, 0x1a, 0x17, 0xb1, 0x8b, 0x14,
+ 0xb1, 0x6c, 0xec, 0xbf, 0x98, 0x4e, 0xfb, 0xff, 0x81, 0xac, 0x5b, 0x67,
+ 0x11, 0x17, 0xf4, 0x10, 0xc9, 0xef, 0xf6, 0xce, 0x6b, 0xa7, 0x7e, 0x95,
+ 0x15, 0x31, 0x70, 0x19, 0x62, 0xfc, 0x2e, 0xdc, 0x5a, 0x58, 0xb7, 0x16,
+ 0x2f, 0x09, 0xb4, 0xb1, 0x7d, 0xd3, 0xbf, 0x4a, 0x8a, 0xc0, 0xbe, 0xf4,
+ 0x77, 0x25, 0x8a, 0xd1, 0xea, 0x9c, 0xc6, 0xfc, 0xc6, 0x0c, 0x5a, 0x58,
+ 0xb4, 0xeb, 0x17, 0x07, 0x25, 0x8b, 0xce, 0x5d, 0x2c, 0x54, 0x1e, 0x48,
+ 0x04, 0xfc, 0x33, 0x77, 0x09, 0x62, 0xe1, 0x9a, 0xb1, 0x7a, 0x00, 0xcb,
+ 0x17, 0x1f, 0x8b, 0x17, 0xe7, 0x97, 0x9a, 0x75, 0x8b, 0xf7, 0x38, 0x58,
+ 0x05, 0x8a, 0x63, 0xd1, 0x72, 0x9b, 0x9b, 0x71, 0x62, 0xda, 0x58, 0xbc,
+ 0xdb, 0x8f, 0x06, 0xb0, 0x43, 0x57, 0xfb, 0x67, 0x35, 0xd3, 0xbf, 0x4a,
+ 0x88, 0xfc, 0xb8, 0x5c, 0x58, 0xbc, 0x50, 0x35, 0x8b, 0xe8, 0x93, 0xf9,
+ 0x62, 0xa1, 0x19, 0xd2, 0x33, 0x1a, 0x2b, 0x0c, 0x10, 0xe5, 0xf6, 0x61,
+ 0x49, 0x62, 0xd0, 0xb1, 0x69, 0xd6, 0x2f, 0xcd, 0xcf, 0x09, 0xd6, 0x2a,
+ 0x0d, 0xd8, 0xc4, 0xea, 0x47, 0xd9, 0x89, 0x97, 0xa6, 0x16, 0x96, 0x2e,
+ 0x19, 0x2c, 0x54, 0x1b, 0x6f, 0x8f, 0xdf, 0xdd, 0xc9, 0xe4, 0xc4, 0xb1,
+ 0x7a, 0x0a, 0x65, 0x8b, 0xe9, 0xa5, 0x1d, 0xac, 0x5f, 0x47, 0x1a, 0x65,
+ 0x8a, 0xc4, 0x49, 0x9a, 0x5c, 0xc3, 0xba, 0x25, 0xbc, 0x6b, 0xf9, 0x62,
+ 0xec, 0xd2, 0xc5, 0xcf, 0xe5, 0x8b, 0x8e, 0x11, 0x62, 0xef, 0x79, 0x62,
+ 0xdb, 0x3b, 0x0d, 0x77, 0xbe, 0x05, 0xe7, 0x2a, 0x18, 0x96, 0x39, 0x74,
+ 0x45, 0xdb, 0x9b, 0x17, 0x6e, 0x8b, 0xe8, 0x64, 0xe3, 0x9f, 0x69, 0x78,
+ 0xc6, 0x80, 0x8e, 0x50, 0x8d, 0xe2, 0xbf, 0xa1, 0x66, 0x23, 0xc3, 0x07,
+ 0xb7, 0x05, 0xc3, 0x17, 0x08, 0x35, 0x7f, 0xfb, 0x64, 0xef, 0x2d, 0x9c,
+ 0xd7, 0x4e, 0xfd, 0x2a, 0x26, 0xf2, 0xff, 0xe3, 0xbc, 0xb6, 0x73, 0x5d,
+ 0x3b, 0xf4, 0xa8, 0x9f, 0x8b, 0xc1, 0x4d, 0x8c, 0x28, 0xb1, 0x7f, 0xff,
+ 0xdf, 0x17, 0x89, 0xcd, 0xef, 0xda, 0x8c, 0xed, 0xdb, 0xb7, 0x58, 0xb0,
+ 0x50, 0x28, 0x89, 0x4c, 0x2b, 0xbf, 0x1e, 0x0f, 0x01, 0xac, 0x5f, 0x66,
+ 0x6b, 0x8b, 0x14, 0xe7, 0x96, 0x02, 0x9b, 0xfe, 0x0a, 0xbc, 0xbe, 0xdb,
+ 0xf2, 0x75, 0x8b, 0xf8, 0x30, 0xfb, 0x09, 0xce, 0xd6, 0x2b, 0x63, 0x3f,
+ 0x60, 0xa2, 0x05, 0xcf, 0x25, 0x8b, 0x98, 0xeb, 0x15, 0xb1, 0xa6, 0xd6,
+ 0x14, 0x7b, 0x0a, 0xc2, 0x5f, 0x61, 0x15, 0xe8, 0x5e, 0xfa, 0x0d, 0x1c,
+ 0x2c, 0x5f, 0xe1, 0xe6, 0xf2, 0x10, 0x70, 0xb1, 0x7c, 0xfd, 0xca, 0x16,
+ 0x2c, 0x14, 0x83, 0xd9, 0x30, 0xda, 0xf8, 0x29, 0x3f, 0x00, 0xb1, 0x7e,
+ 0x79, 0xfc, 0x23, 0x56, 0x2f, 0xdd, 0x68, 0xa2, 0x4b, 0x14, 0x16, 0xe7,
+ 0xfb, 0xa2, 0x97, 0x2b, 0xbf, 0xf6, 0x4b, 0xf0, 0x42, 0xe7, 0xd9, 0x62,
+ 0xe0, 0xce, 0xb1, 0x7f, 0x61, 0xad, 0xe2, 0x85, 0x8a, 0xd8, 0x11, 0x09,
+ 0xd1, 0xf6, 0xe0, 0xcd, 0xd2, 0x3a, 0xc5, 0xfd, 0xc7, 0x3e, 0xa3, 0x8b,
+ 0x17, 0xfd, 0xbd, 0xba, 0x0a, 0x64, 0xd1, 0xe5, 0x8b, 0xf6, 0xa3, 0xe2,
+ 0x85, 0x8b, 0x8c, 0xfa, 0xc5, 0xf0, 0x52, 0x41, 0x49, 0xd6, 0x2f, 0xdf,
+ 0xcf, 0x40, 0xd6, 0x2f, 0xf6, 0x6b, 0xed, 0x34, 0x8e, 0xb1, 0x5b, 0x55,
+ 0xb4, 0xec, 0x6f, 0x81, 0x48, 0x54, 0x85, 0x61, 0x72, 0x16, 0x1c, 0x85,
+ 0xb8, 0xc6, 0x17, 0x32, 0x0c, 0xc5, 0x1a, 0x19, 0x72, 0xd0, 0xca, 0x2f,
+ 0xb0, 0xed, 0xe5, 0x8b, 0xdc, 0xc2, 0x58, 0xbf, 0xb6, 0x2d, 0x80, 0xf1,
+ 0x9e, 0x58, 0xbf, 0xc1, 0x6e, 0x14, 0x6d, 0xcf, 0xb0, 0x5d, 0x62, 0xe2,
+ 0xe9, 0x62, 0xfb, 0x93, 0x1f, 0x8b, 0x17, 0xe2, 0xf7, 0xd8, 0xeb, 0x17,
+ 0xd3, 0x09, 0xc3, 0x58, 0xa8, 0x3c, 0xd7, 0x28, 0xbc, 0x78, 0xe2, 0xc5,
+ 0xe2, 0x7d, 0xeb, 0x17, 0x75, 0xd2, 0xc5, 0xff, 0xb0, 0x7f, 0x63, 0xe7,
+ 0x04, 0x75, 0x8b, 0xfd, 0xd7, 0xdb, 0xd9, 0x87, 0x58, 0xbb, 0x7f, 0x4b,
+ 0x8c, 0x08, 0xa0, 0xaa, 0xa5, 0x6d, 0x88, 0x88, 0x2c, 0x1c, 0x0b, 0x73,
+ 0x88, 0x46, 0x61, 0x89, 0x9c, 0xb4, 0x40, 0x71, 0xd0, 0x0f, 0x10, 0xd7,
+ 0x0f, 0xfc, 0x69, 0x7c, 0x15, 0xdc, 0xce, 0xd6, 0x2f, 0xef, 0xc3, 0x69,
+ 0xb4, 0xb1, 0x5b, 0x19, 0xec, 0x74, 0x57, 0x7f, 0x05, 0x1e, 0x7f, 0xb6,
+ 0xea, 0xc5, 0xfb, 0x63, 0x0a, 0xcf, 0x86, 0x2c, 0x5f, 0xf6, 0xdf, 0x7f,
+ 0x0f, 0x9a, 0xc5, 0x8b, 0xf8, 0x2d, 0x6c, 0x7b, 0x18, 0x57, 0x90, 0xb1,
+ 0x7e, 0xd8, 0x0d, 0x37, 0x37, 0x56, 0x2f, 0xef, 0x31, 0x19, 0x84, 0xb1,
+ 0x77, 0x04, 0xb1, 0x78, 0x01, 0xf9, 0x63, 0x0b, 0x8b, 0xb7, 0xf4, 0xb8,
+ 0xc0, 0x4b, 0x7d, 0x62, 0xe0, 0x01, 0x62, 0x82, 0x8a, 0x81, 0xc2, 0xa5,
+ 0x1b, 0x01, 0xb6, 0xc4, 0x69, 0xb0, 0x8e, 0xc2, 0xdd, 0x0f, 0x0c, 0xdd,
+ 0x17, 0xc5, 0xa2, 0x28, 0x0c, 0x4a, 0xf6, 0xc4, 0x73, 0xac, 0x5e, 0x71,
+ 0xb2, 0xc5, 0xff, 0xc4, 0xfe, 0xe1, 0x46, 0xb4, 0xe3, 0x58, 0xa9, 0x1e,
+ 0xfe, 0x0e, 0x5f, 0xdf, 0x6f, 0x14, 0x4c, 0xb1, 0x73, 0xe2, 0xc5, 0x74,
+ 0x78, 0x9a, 0x2e, 0xbe, 0x71, 0xe1, 0xd6, 0x2f, 0x75, 0x04, 0xb1, 0x7f,
+ 0xed, 0xf1, 0xf6, 0x89, 0xa6, 0x8e, 0x96, 0x2b, 0x63, 0x4e, 0x30, 0x2b,
+ 0x08, 0x2d, 0x81, 0x97, 0x61, 0x91, 0xe1, 0x13, 0x0e, 0xdf, 0x6c, 0x53,
+ 0x9f, 0x8b, 0x17, 0xfb, 0x5f, 0x7e, 0x30, 0xf1, 0x62, 0xfa, 0x09, 0xbb,
+ 0x58, 0xb6, 0x61, 0xea, 0xcc, 0x67, 0x7f, 0x13, 0x1b, 0xf7, 0x92, 0xc5,
+ 0xff, 0xf3, 0xfa, 0x0b, 0xa6, 0x38, 0xc4, 0xfa, 0x92, 0xc5, 0x1c, 0xff,
+ 0x88, 0xba, 0xfc, 0x67, 0xbd, 0x07, 0x58, 0xad, 0x80, 0xf2, 0xe7, 0x21,
+ 0xbf, 0xe7, 0xfb, 0x6f, 0xd9, 0x30, 0xc3, 0x12, 0x2f, 0xf7, 0xdf, 0xde,
+ 0x77, 0x31, 0x62, 0xe8, 0x1a, 0xc5, 0xfb, 0x3a, 0x7e, 0x32, 0xc5, 0x6c,
+ 0x4a, 0x93, 0x36, 0x13, 0xfe, 0xc3, 0x87, 0x80, 0x5a, 0x28, 0x0b, 0x74,
+ 0x2e, 0xcd, 0x3e, 0x2f, 0x7f, 0xff, 0xbe, 0xdc, 0x89, 0x67, 0xdb, 0x5f,
+ 0x7c, 0x16, 0x7d, 0x62, 0xff, 0xfb, 0x50, 0xde, 0xfe, 0x0d, 0xb9, 0x84,
+ 0x05, 0x8b, 0x05, 0x5d, 0x15, 0xbc, 0x5f, 0xbb, 0x90, 0xb1, 0x7f, 0xdc,
+ 0x62, 0xef, 0xc5, 0x18, 0xb1, 0x5b, 0x19, 0xfd, 0xc8, 0xb3, 0x05, 0xef,
+ 0xed, 0xd8, 0xd3, 0xbc, 0x96, 0x2f, 0xdf, 0x67, 0x00, 0x5b, 0xac, 0x5e,
+ 0x8e, 0xe4, 0xb1, 0x41, 0x44, 0x58, 0x05, 0x86, 0x7e, 0x30, 0x08, 0x5f,
+ 0x7f, 0xb6, 0x32, 0x81, 0x86, 0x0e, 0x2c, 0x5f, 0xfb, 0x60, 0x0a, 0x4c,
+ 0x50, 0x3c, 0xef, 0xcb, 0x17, 0xf4, 0xd1, 0xb8, 0x12, 0x69, 0x96, 0x2f,
+ 0xb0, 0x6f, 0x25, 0x8b, 0xfd, 0x81, 0x9f, 0x0b, 0x37, 0x56, 0x2f, 0x6f,
+ 0xd4, 0x96, 0x2f, 0x68, 0x41, 0x16, 0x2b, 0x63, 0x4d, 0x4f, 0x60, 0x3a,
+ 0xd8, 0x92, 0xb6, 0x19, 0xb8, 0x5a, 0x22, 0xe1, 0xb0, 0x88, 0x2f, 0xff,
+ 0xc1, 0x42, 0x7f, 0x46, 0x14, 0x8f, 0x18, 0x43, 0x58, 0xbe, 0x2c, 0x60,
+ 0x2c, 0x5f, 0xf0, 0x52, 0x4d, 0xef, 0xc1, 0x1a, 0xb1, 0x78, 0x06, 0xc2,
+ 0xc5, 0x6c, 0x67, 0xb9, 0xb0, 0x8f, 0xaf, 0xcd, 0xa0, 0x02, 0x16, 0x2f,
+ 0xf7, 0xa4, 0x21, 0xb9, 0x01, 0x62, 0xe6, 0x9d, 0x62, 0xb6, 0x34, 0xdd,
+ 0x02, 0xaa, 0xdb, 0x13, 0xec, 0x8b, 0x5c, 0xa3, 0xc6, 0x97, 0x9f, 0x3e,
+ 0xb1, 0x7f, 0xcf, 0xee, 0xe5, 0xec, 0xd1, 0xab, 0x17, 0xfe, 0x6e, 0xf8,
+ 0x58, 0x38, 0xcd, 0x2c, 0x5c, 0xc0, 0x58, 0xa0, 0xa2, 0x2b, 0x42, 0xdc,
+ 0x70, 0x07, 0x84, 0x7d, 0x7f, 0x7f, 0xa0, 0xa7, 0x3e, 0xcb, 0x17, 0xb6,
+ 0x00, 0xb8, 0x51, 0x62, 0xff, 0xf6, 0xc7, 0x30, 0x57, 0x61, 0x10, 0x02,
+ 0xdf, 0x6e, 0xdf, 0xee, 0x2c, 0x56, 0xc3, 0x44, 0xb0, 0x0a, 0xef, 0xfd,
+ 0x11, 0x11, 0x11, 0x1d, 0xf1, 0x62, 0xf4, 0xd1, 0xe5, 0x8b, 0xa2, 0x20,
+ 0xf6, 0xa6, 0x3c, 0xb8, 0xec, 0xb1, 0x7f, 0xfb, 0xf1, 0x37, 0x7c, 0xce,
+ 0xf7, 0x62, 0x09, 0x62, 0xf3, 0x77, 0x8b, 0x17, 0xed, 0x34, 0xee, 0x74,
+ 0x8b, 0x8c, 0x31, 0x22, 0xb0, 0xf0, 0xcc, 0x29, 0xb0, 0x92, 0x36, 0x4d,
+ 0x15, 0xef, 0xe7, 0x4b, 0x15, 0x09, 0xab, 0xf4, 0x59, 0xf1, 0x70, 0x27,
+ 0xf2, 0x10, 0x41, 0x92, 0xdf, 0x85, 0xb9, 0x02, 0xed, 0x62, 0xe1, 0x49,
+ 0x62, 0xff, 0xd1, 0xfc, 0x06, 0x0f, 0xef, 0x25, 0x8b, 0xe7, 0x28, 0x08,
+ 0xb1, 0x7f, 0x4a, 0x0f, 0x1a, 0xd2, 0xc5, 0x62, 0x35, 0x37, 0x4b, 0x74,
+ 0x30, 0xe7, 0xc2, 0x23, 0xbf, 0xff, 0xbc, 0xc7, 0xc2, 0xf7, 0x20, 0xde,
+ 0x08, 0x7f, 0x65, 0x8b, 0xfa, 0x5b, 0x78, 0xc2, 0xd2, 0xc5, 0xff, 0x47,
+ 0x1f, 0x4d, 0xee, 0x62, 0xc5, 0x76, 0x7d, 0x20, 0x31, 0xbf, 0xfc, 0xec,
+ 0x58, 0x0d, 0xb1, 0xa9, 0xe3, 0xcb, 0x17, 0xfe, 0x08, 0xdb, 0xbf, 0x9a,
+ 0x37, 0x5c, 0xeb, 0x17, 0xfb, 0xdf, 0x82, 0x9d, 0xb7, 0xac, 0x5f, 0xb9,
+ 0x92, 0xdc, 0xc5, 0x8b, 0xd8, 0x78, 0xda, 0x7c, 0x3c, 0x36, 0xbf, 0xff,
+ 0xd0, 0xd2, 0xe0, 0x67, 0xc2, 0x14, 0x9f, 0xc6, 0x3f, 0x6b, 0x14, 0x34,
+ 0xe2, 0xfe, 0x96, 0x50, 0xa9, 0xf1, 0xa5, 0xf8, 0xee, 0x7c, 0x1a, 0xc5,
+ 0xff, 0x7b, 0xaf, 0xb1, 0x14, 0x76, 0xb1, 0x50, 0x7c, 0x4e, 0x51, 0x7f,
+ 0xe8, 0x9e, 0x38, 0xdb, 0x99, 0xa8, 0x58, 0xad, 0xaa, 0xde, 0x32, 0x18,
+ 0xad, 0x1d, 0x77, 0xe1, 0x48, 0x44, 0x17, 0xfc, 0x51, 0xb6, 0x69, 0x46,
+ 0xa7, 0x58, 0xbf, 0xd8, 0x36, 0xdf, 0xc0, 0x74, 0xb1, 0x7f, 0xff, 0xec,
+ 0xde, 0xde, 0x96, 0x03, 0x85, 0x80, 0xd4, 0x4e, 0xfa, 0xe9, 0x62, 0xe8,
+ 0x93, 0xa2, 0x9b, 0x86, 0xf7, 0xb2, 0x78, 0x58, 0xbf, 0xfe, 0xc0, 0x67,
+ 0xb8, 0xdb, 0xcb, 0x3d, 0xf6, 0x58, 0xbb, 0xdc, 0xc3, 0xed, 0x21, 0xdb,
+ 0xff, 0xf9, 0x8e, 0xda, 0x1c, 0x0f, 0x1a, 0x4f, 0xcc, 0x12, 0xc5, 0x1d,
+ 0x50, 0x17, 0xe1, 0xc6, 0x50, 0x9a, 0xf1, 0x65, 0xf7, 0x07, 0xe1, 0x2c,
+ 0x5f, 0xff, 0xfd, 0xbe, 0x35, 0x83, 0x27, 0xd1, 0xaf, 0xe1, 0x79, 0xbd,
+ 0xcf, 0xb2, 0xc5, 0xfe, 0xd0, 0x88, 0x5e, 0x17, 0x96, 0x2f, 0x7e, 0x09,
+ 0x62, 0x98, 0xf4, 0x7c, 0x6b, 0x7d, 0xa0, 0xfd, 0xc5, 0x8a, 0x83, 0xc6,
+ 0xc2, 0x1b, 0xfd, 0x13, 0x14, 0x1c, 0x53, 0xac, 0x5f, 0x9f, 0x8c, 0x71,
+ 0x2c, 0x51, 0xcf, 0x77, 0xe6, 0xb7, 0x1a, 0x62, 0xc5, 0xff, 0xf4, 0x11,
+ 0x44, 0xe6, 0x3c, 0xff, 0x68, 0x25, 0x8b, 0xc5, 0x80, 0x58, 0xa9, 0x1f,
+ 0x5e, 0x27, 0xd4, 0x2a, 0xbc, 0xe9, 0x21, 0x89, 0x3f, 0x18, 0x5b, 0xbe,
+ 0xf8, 0x88, 0x50, 0x85, 0xbe, 0x69, 0xdc, 0xeb, 0x17, 0xfa, 0x0c, 0x1f,
+ 0xe0, 0xba, 0x58, 0xb9, 0xa1, 0x62, 0x98, 0xf2, 0xc8, 0xd6, 0xfd, 0x9c,
+ 0xfc, 0x71, 0x62, 0xfd, 0x01, 0x9f, 0xec, 0xb1, 0x7f, 0xec, 0xef, 0xc1,
+ 0xcf, 0xed, 0x47, 0x16, 0x28, 0x69, 0x91, 0x69, 0xb8, 0xe4, 0x04, 0x51,
+ 0xc2, 0x9b, 0xff, 0x7e, 0x3b, 0x96, 0x1d, 0xa3, 0x75, 0x62, 0xfb, 0x7c,
+ 0x8f, 0x0b, 0x17, 0xfb, 0x58, 0x73, 0xe0, 0x82, 0xeb, 0x17, 0xe7, 0x9e,
+ 0x1f, 0xa5, 0x8b, 0xe8, 0xe4, 0x1d, 0x62, 0xff, 0x44, 0xe4, 0x2c, 0xef,
+ 0xcb, 0x16, 0x0f, 0x69, 0xeb, 0xfc, 0x8a, 0xa1, 0x34, 0xac, 0x42, 0x62,
+ 0x5f, 0x9c, 0x3c, 0x20, 0x2f, 0xdc, 0xf6, 0x11, 0xab, 0x17, 0xf6, 0xa0,
+ 0x79, 0x9c, 0x58, 0xbf, 0xcf, 0xdf, 0x1d, 0xfb, 0xe2, 0xc5, 0x49, 0x11,
+ 0x60, 0x29, 0xe1, 0x6d, 0xf7, 0x1e, 0x5b, 0xab, 0x17, 0xfe, 0x97, 0x22,
+ 0x50, 0x0e, 0x66, 0xf5, 0x8b, 0xd0, 0x36, 0x58, 0xbf, 0xda, 0x0f, 0xdc,
+ 0x9f, 0x0c, 0x58, 0xbb, 0x5b, 0xab, 0x17, 0xf9, 0xf5, 0xd6, 0x0b, 0x53,
+ 0xac, 0x5f, 0xf6, 0x6b, 0x3e, 0xda, 0xfb, 0xac, 0x5a, 0x27, 0x3e, 0xee,
+ 0x8d, 0xaf, 0xfe, 0xf7, 0x85, 0xd9, 0x60, 0x39, 0x1b, 0xab, 0x17, 0xff,
+ 0x9b, 0x98, 0x3d, 0x40, 0xbc, 0x4d, 0xbd, 0x62, 0xfe, 0x90, 0x79, 0xf7,
+ 0x3a, 0xc5, 0x2c, 0x59, 0xc8, 0xdd, 0x98, 0x5f, 0x58, 0x8f, 0x5e, 0x92,
+ 0x4c, 0x84, 0x35, 0xff, 0xd1, 0xa9, 0x75, 0xf6, 0x98, 0x9c, 0xc5, 0x8b,
+ 0xff, 0xb4, 0xf3, 0x8f, 0xf1, 0xcf, 0x0b, 0xeb, 0x15, 0xc4, 0x47, 0x79,
+ 0x1e, 0xf7, 0x9a, 0x65, 0x8b, 0x1e, 0x4a, 0xc0, 0x30, 0x73, 0xb3, 0x8d,
+ 0x42, 0x27, 0xf1, 0x8f, 0x72, 0x18, 0x9e, 0x23, 0xbe, 0x2c, 0x06, 0xe2,
+ 0xc5, 0xf4, 0x1e, 0x3e, 0xb1, 0x74, 0x71, 0x62, 0xfd, 0x06, 0x0f, 0x0e,
+ 0xb1, 0x66, 0x91, 0xf1, 0x11, 0x10, 0x62, 0xf5, 0x0b, 0x8f, 0x19, 0x2d,
+ 0x05, 0x9f, 0x3f, 0x08, 0x7b, 0xf9, 0xc0, 0xfd, 0x3e, 0x96, 0x2f, 0xe8,
+ 0x38, 0x33, 0x37, 0x56, 0x2f, 0xff, 0x69, 0xff, 0x2c, 0xf7, 0x1e, 0x71,
+ 0x49, 0x62, 0xff, 0xfe, 0x7c, 0xeb, 0x9f, 0x76, 0xf4, 0x85, 0x05, 0x12,
+ 0x58, 0xbf, 0xfc, 0x45, 0x06, 0x9f, 0xf1, 0xdf, 0xa3, 0xeb, 0x14, 0xe8,
+ 0xf1, 0x24, 0xc1, 0x2d, 0x5c, 0xf2, 0x58, 0xbf, 0xff, 0x7b, 0x82, 0x8f,
+ 0xc1, 0xcb, 0x00, 0x78, 0x92, 0xc5, 0x1c, 0xfb, 0x08, 0x5e, 0xf0, 0xdf,
+ 0xeb, 0x17, 0xfd, 0x1f, 0x8e, 0xe5, 0x28, 0x9d, 0x62, 0xd0, 0xb1, 0x73,
+ 0x69, 0x62, 0xdd, 0x68, 0xd4, 0x7c, 0x46, 0xfe, 0xdd, 0x2c, 0x9f, 0x0c,
+ 0x58, 0xa8, 0x47, 0xde, 0x10, 0xe8, 0x75, 0xd8, 0xc4, 0x51, 0x7f, 0xfb,
+ 0xec, 0x71, 0xc6, 0xdd, 0xc1, 0x7d, 0xb4, 0xb1, 0x7f, 0x7a, 0x3e, 0x51,
+ 0x25, 0x8b, 0xff, 0xfe, 0xfb, 0xb7, 0xa4, 0x28, 0x28, 0x94, 0x9b, 0x53,
+ 0x88, 0x0b, 0x15, 0xb5, 0x1c, 0x8c, 0xa1, 0xc2, 0xda, 0x58, 0xbf, 0x89,
+ 0xcd, 0x6d, 0x44, 0x8d, 0xef, 0xcc, 0x6f, 0xbd, 0x3e, 0x18, 0xb1, 0x76,
+ 0xa1, 0x62, 0xce, 0x46, 0xf3, 0xc4, 0xb7, 0xe8, 0xd6, 0x9e, 0x65, 0x8b,
+ 0x9b, 0xb5, 0x8b, 0xfc, 0x01, 0x60, 0x0e, 0xf2, 0x58, 0xbb, 0x21, 0x62,
+ 0xa4, 0x7c, 0x5d, 0x8c, 0x1c, 0xd2, 0xa7, 0x45, 0xdb, 0xc2, 0x2e, 0xff,
+ 0xff, 0x7d, 0xbb, 0x82, 0x8e, 0x0f, 0xf1, 0xc6, 0x2e, 0xe4, 0xb1, 0x7f,
+ 0xff, 0xdf, 0x71, 0xfd, 0x89, 0xfd, 0x13, 0x31, 0xac, 0x59, 0xbd, 0x62,
+ 0xff, 0x9b, 0xd9, 0xad, 0x0a, 0x7d, 0xeb, 0x17, 0xfd, 0xcc, 0xf0, 0xf3,
+ 0x01, 0xc5, 0x8a, 0xf9, 0xfb, 0x78, 0xf6, 0xff, 0x9b, 0xd9, 0xad, 0x0a,
+ 0x7d, 0xeb, 0x17, 0x08, 0xb6, 0x9e, 0xff, 0xc8, 0xaa, 0x13, 0xcc, 0xc6,
+ 0x1e, 0x46, 0x79, 0x52, 0x66, 0x5d, 0x0e, 0x72, 0x7b, 0x12, 0x4d, 0x2e,
+ 0xea, 0x32, 0x1d, 0x47, 0x2b, 0xf8, 0xda, 0x00, 0xfc, 0x50, 0xe0, 0xe4,
+ 0x7e, 0x97, 0xfa, 0x1f, 0x5f, 0x31, 0xc6, 0xb1, 0x79, 0x87, 0x0b, 0x14,
+ 0x33, 0xd0, 0x39, 0xa5, 0xfc, 0xdf, 0xd6, 0x9a, 0x75, 0x8a, 0x83, 0xd1,
+ 0xf9, 0x15, 0xc6, 0x79, 0x62, 0xff, 0xe2, 0x16, 0x71, 0xb9, 0x9f, 0xce,
+ 0x96, 0x2f, 0xda, 0x3b, 0xb8, 0xd6, 0x2f, 0xff, 0xce, 0x7d, 0xbc, 0x14,
+ 0x77, 0x9e, 0xe6, 0x47, 0x4b, 0x15, 0x88, 0x81, 0xf9, 0x45, 0xff, 0xcc,
+ 0xdf, 0x9b, 0x3d, 0x1e, 0x81, 0xac, 0x5f, 0xa3, 0xc6, 0xbf, 0x16, 0x2f,
+ 0x83, 0x34, 0x33, 0x56, 0x2d, 0x0b, 0x17, 0xff, 0xd1, 0xdc, 0x9c, 0x81,
+ 0xb4, 0x0d, 0xa6, 0x35, 0x62, 0xa1, 0x3f, 0x9c, 0x19, 0x68, 0x62, 0xcc,
+ 0x45, 0xf4, 0x43, 0x0a, 0x77, 0x0a, 0x02, 0x08, 0xdf, 0xd2, 0xcf, 0x31,
+ 0x42, 0xc5, 0xfe, 0x8e, 0xe6, 0xfc, 0x11, 0xab, 0x17, 0x14, 0xcb, 0x17,
+ 0xb9, 0xf6, 0x58, 0xa3, 0x9b, 0x5f, 0x0c, 0x5f, 0x4e, 0x76, 0x92, 0xc5,
+ 0xff, 0x8a, 0x0e, 0xec, 0x31, 0x7b, 0x8b, 0x17, 0xd0, 0x00, 0xce, 0xb1,
+ 0x7c, 0x42, 0x79, 0x2c, 0x54, 0x91, 0x09, 0xd1, 0xf7, 0x09, 0x2f, 0xe8,
+ 0x3e, 0xc8, 0x01, 0x0b, 0x17, 0x82, 0xf1, 0xe5, 0x8b, 0xf9, 0xfa, 0xdb,
+ 0x19, 0xc5, 0x8b, 0xf4, 0x61, 0x7b, 0x8b, 0x14, 0x33, 0xd7, 0x39, 0x85,
+ 0x7d, 0x19, 0x62, 0x31, 0x08, 0xf1, 0x50, 0x9e, 0xb6, 0x42, 0xa1, 0xa1,
+ 0xf9, 0x7d, 0xe6, 0x29, 0x2c, 0x5f, 0x9b, 0xfe, 0xce, 0x96, 0x2f, 0x61,
+ 0x01, 0x62, 0xa4, 0x7c, 0xf3, 0x11, 0x04, 0x29, 0xbf, 0xfd, 0xf8, 0x3c,
+ 0x0b, 0xb8, 0x62, 0xc3, 0x56, 0x2f, 0xd1, 0x37, 0x3c, 0xcb, 0x15, 0xb5,
+ 0x5e, 0x94, 0x16, 0x63, 0x5e, 0xa3, 0xf7, 0x78, 0x4f, 0xf8, 0xc8, 0x34,
+ 0xab, 0xff, 0xfa, 0x35, 0x1c, 0xfb, 0xb7, 0xa4, 0x28, 0x28, 0x92, 0xc5,
+ 0xfe, 0x18, 0x71, 0xbb, 0xf1, 0x71, 0x62, 0xfc, 0x11, 0x8f, 0x9e, 0x58,
+ 0xbf, 0x7b, 0x3c, 0x50, 0xb1, 0x53, 0xa3, 0x8f, 0xb5, 0x93, 0x9c, 0x91,
+ 0x55, 0xe1, 0x3f, 0x16, 0x2e, 0x83, 0x16, 0x2b, 0x46, 0xd7, 0x83, 0xb7,
+ 0xff, 0x37, 0x1c, 0xcf, 0x6d, 0xe4, 0x98, 0xd5, 0x8b, 0xfd, 0xfc, 0xcf,
+ 0x7d, 0xc0, 0xb1, 0x6f, 0xac, 0x54, 0x8f, 0x15, 0xcc, 0xee, 0x9a, 0x16,
+ 0x2e, 0x8f, 0x2c, 0x5f, 0xa3, 0x68, 0x73, 0x71, 0x62, 0xa0, 0xf7, 0x0d,
+ 0x18, 0x21, 0x7b, 0xe1, 0xe1, 0x49, 0x62, 0xfd, 0x8d, 0x2f, 0xc2, 0xc5,
+ 0xd3, 0x79, 0x8f, 0x27, 0xe4, 0x57, 0xff, 0xe1, 0xfe, 0x34, 0xc0, 0x80,
+ 0xe2, 0x62, 0x83, 0xac, 0x5f, 0xe3, 0x60, 0xbd, 0xc7, 0xfa, 0xc5, 0x42,
+ 0x2e, 0x18, 0xb9, 0xd5, 0xaf, 0xc5, 0x8e, 0x53, 0xac, 0x5f, 0xdd, 0xf1,
+ 0xe1, 0xb4, 0xb1, 0x50, 0xad, 0x43, 0x1c, 0xfa, 0x21, 0x68, 0x47, 0x3b,
+ 0xe9, 0x46, 0x5f, 0xc2, 0xd1, 0x13, 0xde, 0x7c, 0xd2, 0xc5, 0xff, 0x67,
+ 0x20, 0x7c, 0x86, 0x1a, 0xc5, 0xfd, 0x13, 0xea, 0x30, 0x6b, 0x17, 0xfe,
+ 0xc3, 0xf3, 0xf1, 0xdf, 0xa3, 0xeb, 0x17, 0x9e, 0x68, 0x58, 0xbf, 0xbf,
+ 0x1e, 0xf4, 0x1d, 0x62, 0xff, 0xfe, 0xd6, 0x0f, 0x84, 0x2c, 0x90, 0x9c,
+ 0x7c, 0xcd, 0x2c, 0x50, 0xd1, 0x12, 0xc5, 0xd5, 0xa4, 0xe2, 0x8e, 0x39,
+ 0xf3, 0x8f, 0x17, 0x6f, 0x40, 0x0e, 0x14, 0xd7, 0xc5, 0x07, 0xe2, 0xc5,
+ 0xe3, 0xbf, 0x6b, 0x1e, 0x34, 0x57, 0x7b, 0xa5, 0x8b, 0xe6, 0xd0, 0x38,
+ 0xb1, 0x58, 0x7d, 0x5a, 0x2e, 0xf0, 0xcd, 0xfc, 0x51, 0xb4, 0x00, 0x85,
+ 0x8b, 0xe7, 0x04, 0x49, 0x62, 0xf8, 0x1b, 0xc2, 0xa1, 0x45, 0x8b, 0xfe,
+ 0x3e, 0x4a, 0x34, 0x0c, 0x25, 0x8b, 0x4b, 0xe7, 0xcc, 0x19, 0x75, 0xfc,
+ 0xe5, 0x1f, 0xfc, 0x2c, 0x5f, 0xda, 0x78, 0x94, 0x49, 0x62, 0xff, 0x72,
+ 0x3a, 0xe3, 0x41, 0xd6, 0x2a, 0x0f, 0x85, 0xcb, 0x6e, 0x11, 0x2c, 0x5d,
+ 0x9d, 0x2c, 0x5d, 0x12, 0xf9, 0xaf, 0xf0, 0xbd, 0x76, 0x99, 0x8c, 0xc5,
+ 0x3a, 0x84, 0x69, 0x27, 0xdf, 0xff, 0x16, 0x6f, 0xe9, 0xf5, 0x3b, 0xf9,
+ 0xfb, 0x02, 0xc5, 0xfe, 0xc1, 0xb7, 0x0c, 0x7d, 0x2c, 0x54, 0x2b, 0xce,
+ 0x1c, 0x3b, 0x30, 0xbb, 0xa2, 0xf6, 0x8e, 0xe5, 0xd1, 0x3c, 0xa9, 0x7f,
+ 0x89, 0xe7, 0xee, 0x50, 0x11, 0x62, 0xfc, 0x08, 0xce, 0xe4, 0xb1, 0x7f,
+ 0xb9, 0xf7, 0x0f, 0xf1, 0x25, 0x8a, 0x9d, 0x12, 0xbd, 0x1b, 0xf6, 0x53,
+ 0x7f, 0xbf, 0x07, 0xf1, 0x47, 0x6b, 0x17, 0x64, 0xcb, 0x17, 0xfe, 0x21,
+ 0x60, 0xc9, 0xe5, 0x84, 0xb1, 0x7f, 0xe7, 0xef, 0xf0, 0xc0, 0x7f, 0x09,
+ 0x62, 0xff, 0xff, 0x43, 0x49, 0xf9, 0xc8, 0xc2, 0x89, 0x61, 0xdf, 0xb5,
+ 0x8b, 0x61, 0xd1, 0x3b, 0xe3, 0xfa, 0x92, 0x69, 0xb8, 0x68, 0xe3, 0x1c,
+ 0x86, 0xcd, 0xe2, 0x69, 0x2c, 0x5e, 0xe4, 0x4c, 0xb1, 0x7d, 0x3e, 0x77,
+ 0x25, 0x8a, 0x83, 0xc3, 0xc1, 0xeb, 0xfc, 0x77, 0x2c, 0xd0, 0x7e, 0x58,
+ 0xbf, 0xfe, 0xfc, 0x1d, 0xb4, 0xc1, 0x20, 0x39, 0xf0, 0xc5, 0x8b, 0xf4,
+ 0x48, 0xed, 0xe5, 0x8b, 0xff, 0x60, 0xe0, 0x33, 0x94, 0x77, 0x25, 0x8b,
+ 0xfb, 0x05, 0xd0, 0x79, 0xda, 0xc5, 0x49, 0x3a, 0x01, 0xaf, 0xe1, 0x04,
+ 0xc6, 0x87, 0x54, 0xe1, 0x46, 0xf4, 0x0b, 0xfe, 0xd4, 0x70, 0x32, 0x28,
+ 0xd2, 0xc5, 0xcf, 0xb8, 0xb1, 0x4c, 0x7a, 0x67, 0x39, 0xbf, 0xbf, 0x1e,
+ 0xfe, 0x01, 0x62, 0xff, 0x44, 0xc2, 0xec, 0xa2, 0x65, 0x8b, 0xfe, 0x89,
+ 0x13, 0xfa, 0x4d, 0xbd, 0x62, 0xf0, 0x70, 0x05, 0x8b, 0xc1, 0x1a, 0x75,
+ 0x8a, 0x3a, 0x2b, 0xbe, 0x6d, 0xc3, 0xaf, 0x0f, 0x5b, 0x75, 0x62, 0xff,
+ 0xb2, 0x62, 0x89, 0xf9, 0x1d, 0x2c, 0x5d, 0x2c, 0x58, 0xaf, 0x9e, 0x97,
+ 0x8e, 0xee, 0xe6, 0x2c, 0x5f, 0xa2, 0x66, 0x8e, 0x2c, 0x5f, 0xfa, 0x35,
+ 0xd7, 0x8b, 0x27, 0x72, 0x58, 0xbe, 0x03, 0x47, 0x16, 0x2b, 0x87, 0xc2,
+ 0x23, 0xfb, 0xff, 0x7b, 0xf9, 0xbd, 0xc8, 0x78, 0x05, 0x8b, 0x7d, 0x62,
+ 0xa1, 0x5c, 0x8c, 0xf0, 0xba, 0x19, 0x0e, 0x43, 0x71, 0x8f, 0x5d, 0x9c,
+ 0x04, 0x44, 0x2f, 0xe8, 0x44, 0x88, 0x88, 0xc4, 0x0b, 0xbc, 0x75, 0x8b,
+ 0xf9, 0xf3, 0x40, 0x04, 0x2c, 0x5f, 0x7d, 0x9e, 0x4b, 0x17, 0xff, 0xff,
+ 0xc5, 0x92, 0x16, 0xa3, 0x5a, 0xc1, 0xc3, 0x1b, 0x05, 0xd3, 0xf9, 0xcd,
+ 0x58, 0xac, 0x44, 0xfb, 0x91, 0x5f, 0x73, 0xb2, 0xd2, 0xc5, 0xfe, 0xd6,
+ 0x7d, 0x8a, 0x0e, 0xb1, 0x7f, 0xf4, 0x6e, 0xfc, 0xb3, 0xbf, 0x09, 0xf8,
+ 0xb1, 0x7f, 0x43, 0xeb, 0xd9, 0xf5, 0x8b, 0xff, 0xec, 0x62, 0xc9, 0xa2,
+ 0x77, 0x9c, 0xed, 0x3a, 0xc5, 0xff, 0xe3, 0xe0, 0xe2, 0x51, 0xc0, 0x3b,
+ 0xf6, 0xb1, 0x50, 0x9a, 0x11, 0xcc, 0xbe, 0x91, 0xc2, 0xd0, 0xd4, 0x6a,
+ 0x15, 0x5b, 0x38, 0xc7, 0x21, 0x99, 0xe2, 0x11, 0x46, 0xcd, 0x7f, 0xde,
+ 0x7e, 0x67, 0xfe, 0xc7, 0x58, 0xbb, 0xfc, 0x58, 0xbe, 0xcd, 0xf8, 0x4b,
+ 0x17, 0xfb, 0x98, 0xc3, 0x76, 0x9d, 0x62, 0xa0, 0xf5, 0xb0, 0x8e, 0xff,
+ 0xc4, 0xe0, 0xc2, 0xf7, 0x1e, 0x4b, 0x15, 0x09, 0x82, 0x1a, 0x73, 0xa6,
+ 0xef, 0x10, 0x5f, 0x8a, 0x27, 0x89, 0xd6, 0x28, 0x67, 0xcf, 0x31, 0xf5,
+ 0xfc, 0x38, 0x7d, 0x00, 0x4b, 0x17, 0x67, 0xd6, 0x2a, 0x73, 0xc5, 0xde,
+ 0x5d, 0x7e, 0xd3, 0xb6, 0xb1, 0x62, 0xfe, 0xc1, 0x81, 0x8b, 0xcb, 0x17,
+ 0xff, 0x1d, 0x80, 0xfe, 0x2c, 0x9f, 0x50, 0xb1, 0x4b, 0x16, 0xc6, 0x3d,
+ 0x0f, 0x22, 0x5e, 0xff, 0x99, 0x62, 0xfe, 0xdd, 0xcd, 0xe5, 0x92, 0x58,
+ 0xb9, 0xa6, 0x58, 0xa6, 0x3c, 0xaf, 0x19, 0x5e, 0xff, 0xe1, 0x62, 0xfe,
+ 0x35, 0xe5, 0xc6, 0x1a, 0xc5, 0x61, 0xe6, 0x30, 0xed, 0x42, 0xa4, 0xbc,
+ 0x68, 0x62, 0x5d, 0x13, 0xfd, 0xf5, 0xc9, 0xb8, 0xcf, 0xe6, 0xdb, 0x85,
+ 0x25, 0x8b, 0xfb, 0xed, 0xad, 0x67, 0x96, 0x2a, 0x73, 0xc6, 0xe8, 0x62,
+ 0xf9, 0xcf, 0x1b, 0xab, 0x17, 0x87, 0x12, 0x58, 0xb9, 0xb9, 0xf3, 0xc2,
+ 0x11, 0x2d, 0xd1, 0x25, 0x8b, 0xff, 0xd3, 0x49, 0xb7, 0xc6, 0xb1, 0xa4,
+ 0x2d, 0x2c, 0x56, 0x91, 0x23, 0xf2, 0xd7, 0x17, 0xb9, 0xe4, 0xb1, 0x7e,
+ 0x2f, 0x6e, 0x41, 0xd6, 0x29, 0xcf, 0x08, 0x42, 0xf7, 0x98, 0xce, 0x96,
+ 0x2f, 0x60, 0xf1, 0x62, 0xb7, 0x4d, 0xdf, 0xc7, 0xef, 0xda, 0x1e, 0x11,
+ 0xab, 0x16, 0x92, 0xc5, 0xff, 0xa3, 0xe2, 0x70, 0xf3, 0x7b, 0xe9, 0x62,
+ 0x98, 0xf4, 0xf8, 0x25, 0x79, 0x88, 0x6b, 0x15, 0x08, 0xdd, 0x72, 0x4f,
+ 0x3e, 0x6f, 0x21, 0xbe, 0x32, 0x0a, 0x16, 0x2f, 0xf1, 0xf8, 0xdb, 0x99,
+ 0xa8, 0x58, 0xbd, 0x87, 0xd2, 0xc5, 0xe6, 0x3b, 0x2c, 0x54, 0x22, 0x47,
+ 0x08, 0x88, 0xdb, 0xc3, 0xb4, 0x14, 0x7c, 0x38, 0x4d, 0x85, 0x0c, 0xa8,
+ 0x8f, 0x6a, 0x78, 0xcc, 0xa5, 0x2f, 0x0c, 0x73, 0xa3, 0x39, 0x1c, 0x8f,
+ 0x51, 0xca, 0x77, 0x0d, 0x76, 0xa6, 0x75, 0x6e, 0xc6, 0xab, 0x34, 0xa1,
+ 0xad, 0x4e, 0x26, 0x9e, 0x72, 0x93, 0xf3, 0xba, 0x4f, 0x18, 0x18, 0x23,
+ 0x80, 0x29, 0xd7, 0x2e, 0x4b, 0x5c, 0xf4, 0xe0, 0x58, 0xa1, 0x6b, 0xbe,
+ 0x1e, 0xfb, 0x8e, 0x21, 0xc6, 0x72, 0x12, 0x19, 0xd6, 0x65, 0x8b, 0xb6,
+ 0x81, 0x62, 0xb6, 0x9a, 0xbe, 0x08, 0xdc, 0x6f, 0x96, 0x2f, 0xff, 0xfb,
+ 0x61, 0xec, 0x51, 0x81, 0x6b, 0x5b, 0x10, 0x59, 0xbf, 0x74, 0x2d, 0xc5,
+ 0xb7, 0x6f, 0xf7, 0x16, 0x2f, 0xe0, 0x72, 0x62, 0x81, 0xac, 0x5f, 0xf6,
+ 0xfc, 0x1f, 0x7e, 0x2c, 0x02, 0xc5, 0xa5, 0x07, 0xd6, 0xc5, 0xf7, 0x06,
+ 0x75, 0x8b, 0xdf, 0xcf, 0x2c, 0x54, 0xc6, 0xd8, 0x03, 0x37, 0xfd, 0x9e,
+ 0xe6, 0x7b, 0xf8, 0x05, 0x8b, 0xfd, 0xb6, 0x36, 0x9d, 0x8b, 0xcb, 0x17,
+ 0xf9, 0x8d, 0x72, 0xf6, 0x12, 0xc5, 0xfe, 0x73, 0x5b, 0x9c, 0x76, 0x58,
+ 0xac, 0x4d, 0x4d, 0xd7, 0x08, 0x8b, 0x87, 0x3e, 0x37, 0xde, 0x65, 0x73,
+ 0x92, 0xc5, 0x68, 0xfb, 0x4e, 0xaf, 0x7b, 0xd8, 0x75, 0x8b, 0xe9, 0x46,
+ 0x12, 0xc5, 0x41, 0xbe, 0xf0, 0xed, 0xfb, 0xd0, 0x4c, 0x05, 0x8b, 0xbb,
+ 0xed, 0x62, 0xed, 0xbc, 0x58, 0xbf, 0x68, 0x5b, 0xc0, 0x62, 0xc5, 0xc5,
+ 0xc5, 0x8b, 0xfb, 0x0c, 0x70, 0x1f, 0x16, 0x2f, 0xe2, 0xcf, 0x09, 0xcc,
+ 0x58, 0xad, 0xa9, 0x8d, 0xe1, 0x07, 0x64, 0xe7, 0x1a, 0xf8, 0xd0, 0x0b,
+ 0x48, 0x5f, 0x79, 0x75, 0xfb, 0xdc, 0x6e, 0xcc, 0x58, 0xbf, 0xf4, 0x1d,
+ 0xbb, 0xe0, 0xa6, 0x11, 0xab, 0x17, 0xe2, 0xf7, 0xf2, 0x4b, 0x17, 0x73,
+ 0x16, 0x29, 0x8d, 0xfb, 0x94, 0x5f, 0xe2, 0x83, 0x37, 0x33, 0x50, 0xb1,
+ 0x7f, 0xfd, 0xbd, 0xb5, 0x80, 0x79, 0x71, 0x8b, 0x00, 0xb1, 0x7e, 0x7c,
+ 0x00, 0x7e, 0x58, 0xbf, 0xf0, 0x9b, 0xff, 0xcd, 0x69, 0x8e, 0xb1, 0x78,
+ 0x70, 0x11, 0x62, 0xfb, 0xec, 0xfb, 0xab, 0x14, 0x47, 0x89, 0xe1, 0xfa,
+ 0xda, 0x9f, 0xa4, 0xa1, 0x04, 0x31, 0xfc, 0x36, 0x35, 0x40, 0xe5, 0x2f,
+ 0x08, 0x3a, 0xd2, 0xa8, 0xf3, 0x25, 0x0f, 0xdf, 0x4f, 0x1e, 0xe2, 0xc5,
+ 0xe8, 0x07, 0x16, 0x2b, 0x47, 0x82, 0x44, 0x97, 0xcf, 0xa7, 0x92, 0xc5,
+ 0x61, 0xe1, 0x91, 0x0d, 0xbc, 0xb1, 0x7b, 0x90, 0x05, 0x8b, 0x67, 0x66,
+ 0xbf, 0xc2, 0x55, 0xa3, 0xf6, 0xfa, 0x7d, 0xff, 0xa0, 0xce, 0xe5, 0xc7,
+ 0xfe, 0x4c, 0xb1, 0x78, 0xc3, 0x0c, 0x58, 0xbe, 0x9c, 0x9a, 0x12, 0x36,
+ 0x4d, 0x0d, 0xfd, 0xf8, 0xf9, 0x61, 0xab, 0x17, 0x84, 0x5e, 0x58, 0xbf,
+ 0x9c, 0xa4, 0x38, 0x9d, 0x62, 0xb0, 0xf2, 0xfe, 0x3b, 0x7f, 0xce, 0xff,
+ 0x77, 0x77, 0x1a, 0xc5, 0x0d, 0x1a, 0x1b, 0xaf, 0x2e, 0x43, 0x7f, 0xfe,
+ 0x32, 0x4d, 0xe9, 0x41, 0x01, 0xc9, 0xbb, 0x92, 0xc5, 0xf3, 0xfa, 0x06,
+ 0xb1, 0x7b, 0x0b, 0xa5, 0x8b, 0xbb, 0x92, 0xc5, 0xfe, 0xd4, 0xf1, 0x93,
+ 0x36, 0x96, 0x2f, 0xf1, 0xb1, 0xee, 0x7d, 0xc4, 0xb1, 0x71, 0xe1, 0x62,
+ 0xfd, 0xf6, 0x2e, 0xf8, 0xb1, 0x7e, 0x69, 0xf3, 0xbf, 0x2c, 0x5f, 0xe7,
+ 0xf9, 0x66, 0xf7, 0xe9, 0x62, 0xf6, 0xa0, 0xc5, 0x8a, 0x58, 0xad, 0x1a,
+ 0xa0, 0x0f, 0x5b, 0xa5, 0x8b, 0xf0, 0x7a, 0xc1, 0x0d, 0x62, 0xb0, 0xf7,
+ 0x98, 0x87, 0x82, 0x75, 0x09, 0xeb, 0xe0, 0xc9, 0xa6, 0xac, 0x6b, 0x30,
+ 0xb9, 0xca, 0x48, 0xab, 0xd0, 0xbd, 0xbf, 0xe9, 0x77, 0xc6, 0xd7, 0x5f,
+ 0xc5, 0x8b, 0xf6, 0x05, 0x49, 0x86, 0xb1, 0x7c, 0xfc, 0xdf, 0x25, 0x8b,
+ 0xb0, 0x6b, 0x14, 0x69, 0xbc, 0xde, 0x4b, 0x5d, 0xa6, 0x79, 0xa7, 0x50,
+ 0x1e, 0x79, 0x9e, 0xfc, 0xe5, 0x26, 0x3a, 0xc5, 0xec, 0x16, 0xe2, 0xc5,
+ 0x6d, 0x67, 0x47, 0x85, 0x48, 0xc2, 0xc1, 0x98, 0x95, 0x86, 0x38, 0xde,
+ 0xf2, 0x58, 0x23, 0x46, 0x4f, 0xa2, 0x2f, 0xb1, 0xbc, 0x60, 0xa0, 0x32,
+ 0x25, 0x6e, 0x11, 0x0a, 0x59, 0x86, 0xf3, 0xfd, 0xc2, 0x7b, 0xc1, 0x4d,
+ 0x85, 0xb1, 0xac, 0x5f, 0xf7, 0xde, 0x62, 0x8c, 0xd4, 0x96, 0x2f, 0xf0,
+ 0x67, 0xc1, 0xc1, 0x74, 0xb1, 0x7f, 0xe7, 0x20, 0xe6, 0xe3, 0x17, 0x72,
+ 0x58, 0xbf, 0xf1, 0x99, 0xc2, 0x68, 0xd6, 0x4e, 0xb1, 0x5b, 0xa8, 0xee,
+ 0x39, 0xc8, 0x8d, 0x77, 0xa0, 0xdf, 0x0a, 0x78, 0x99, 0x62, 0xff, 0xff,
+ 0xff, 0xb6, 0xff, 0x3b, 0x97, 0xcf, 0xb7, 0xaf, 0x8b, 0xde, 0xc2, 0xfe,
+ 0x7a, 0x07, 0xb7, 0x6f, 0xf7, 0x16, 0x2a, 0x11, 0x93, 0xba, 0x4b, 0x7b,
+ 0x61, 0x05, 0x81, 0x55, 0x8b, 0xfb, 0xaf, 0xb9, 0x9d, 0xf1, 0x62, 0x82,
+ 0xdc, 0xf7, 0xe0, 0xb6, 0xfc, 0x51, 0xa7, 0xe2, 0xc5, 0xff, 0x0f, 0x04,
+ 0x17, 0x6f, 0xb9, 0xd6, 0x2f, 0xd0, 0x72, 0xc9, 0x96, 0x30, 0xde, 0xde,
+ 0x06, 0x71, 0x62, 0xf9, 0xfb, 0x3f, 0x6b, 0x16, 0xc0, 0x1e, 0x17, 0x87,
+ 0x6f, 0x0e, 0x26, 0x58, 0xbf, 0x73, 0x3e, 0xdf, 0x58, 0xbd, 0xa8, 0xde,
+ 0xb1, 0x7f, 0x89, 0xcc, 0xf6, 0x11, 0xab, 0x17, 0xb7, 0xe0, 0xd6, 0x2f,
+ 0xef, 0xb4, 0x10, 0xa1, 0x62, 0xff, 0x46, 0xe9, 0xb9, 0xc7, 0xdd, 0x58,
+ 0xbe, 0x03, 0x14, 0xcb, 0x14, 0x6a, 0x22, 0x7e, 0x59, 0xe3, 0xab, 0xf6,
+ 0x0c, 0x30, 0x71, 0x62, 0xfb, 0x8e, 0x52, 0x58, 0xbf, 0xff, 0xff, 0xed,
+ 0x0b, 0x59, 0xd6, 0x6b, 0x4f, 0x2c, 0xf4, 0x7b, 0x9c, 0x13, 0x9c, 0x3f,
+ 0xbf, 0xe1, 0x62, 0xb6, 0xaa, 0x0e, 0x98, 0x7f, 0xe6, 0x8f, 0x0a, 0x82,
+ 0x31, 0xe1, 0x50, 0x42, 0x2b, 0xed, 0xef, 0xf6, 0x58, 0xbf, 0xd9, 0xc7,
+ 0x7e, 0xe4, 0xcb, 0x17, 0x07, 0xf5, 0x8b, 0xd3, 0x08, 0x35, 0x8a, 0x83,
+ 0x72, 0xe3, 0x37, 0x17, 0x96, 0x2e, 0x89, 0x96, 0x2a, 0x11, 0xbd, 0x39,
+ 0x27, 0xdb, 0x1c, 0x7c, 0x85, 0xef, 0xcf, 0x37, 0x23, 0xb5, 0x8a, 0xda,
+ 0xba, 0x2c, 0x36, 0x4d, 0x3c, 0x9c, 0x9c, 0x03, 0xdc, 0x94, 0x6d, 0xe8,
+ 0xd3, 0x37, 0xa4, 0x5f, 0xd1, 0x2f, 0xc6, 0xf6, 0x58, 0xbe, 0x3c, 0xef,
+ 0xba, 0xb1, 0x7a, 0x0f, 0x0b, 0x15, 0x87, 0x87, 0xd1, 0x3d, 0xef, 0x87,
+ 0xc5, 0x8b, 0xfc, 0x5e, 0xf1, 0x47, 0xb8, 0xb1, 0x78, 0x84, 0x6a, 0xc5,
+ 0x41, 0xe8, 0xb1, 0x9d, 0xfd, 0x28, 0x07, 0xe5, 0x0b, 0x14, 0x69, 0xe7,
+ 0x31, 0x05, 0xf0, 0x8a, 0x0e, 0xb1, 0x79, 0xdc, 0xeb, 0x14, 0x73, 0x7d,
+ 0xf2, 0x2b, 0x0d, 0x62, 0xec, 0x08, 0xb1, 0x73, 0xf1, 0x62, 0xda, 0x39,
+ 0xe1, 0x7c, 0x48, 0x43, 0x35, 0x08, 0x98, 0x76, 0x3b, 0xa5, 0xe5, 0x8b,
+ 0xe9, 0xa3, 0xce, 0xb1, 0x5d, 0x1b, 0xb1, 0x0c, 0x5e, 0x2c, 0xe2, 0xc5,
+ 0xe1, 0x03, 0x08, 0xdf, 0x6f, 0x22, 0xb4, 0x96, 0x2a, 0x73, 0xc5, 0xf9,
+ 0x9d, 0xff, 0xd1, 0xf0, 0xc7, 0xe6, 0xc9, 0xa0, 0xeb, 0x17, 0xff, 0x74,
+ 0x4f, 0xe8, 0xc3, 0x1c, 0x9d, 0x62, 0xf4, 0x11, 0xab, 0x17, 0xfe, 0xf3,
+ 0x19, 0xd7, 0xdb, 0x7b, 0x0d, 0x62, 0xff, 0x6a, 0x5f, 0xcd, 0xf0, 0x75,
+ 0x8a, 0x58, 0xbb, 0x98, 0xb1, 0x52, 0x34, 0x61, 0x70, 0xcb, 0xb2, 0x75,
+ 0x8a, 0x11, 0xbd, 0x0c, 0x96, 0xa1, 0x35, 0xbe, 0x90, 0xfb, 0x1d, 0x64,
+ 0x37, 0x84, 0xb5, 0xf9, 0xe5, 0xc6, 0xde, 0xb1, 0x7d, 0x9a, 0x81, 0xac,
+ 0x5f, 0x4d, 0xfc, 0x99, 0x62, 0xf6, 0x6b, 0x36, 0x9e, 0x3b, 0x91, 0x5e,
+ 0x38, 0xb7, 0xac, 0x5f, 0xd9, 0x2e, 0xe5, 0x9e, 0x58, 0xb7, 0xa4, 0x88,
+ 0x2c, 0x33, 0xf9, 0x05, 0xcd, 0xd2, 0xc5, 0xf8, 0xfb, 0x10, 0x4d, 0xd1,
+ 0xac, 0x50, 0x0f, 0x30, 0x43, 0x14, 0xb1, 0x7b, 0xc2, 0x3a, 0xc5, 0xf7,
+ 0x72, 0xfb, 0x2c, 0x54, 0x1e, 0x13, 0x8f, 0x5f, 0xd0, 0x6f, 0xb8, 0x22,
+ 0x58, 0xbf, 0xbd, 0x1b, 0xd8, 0x80, 0xb1, 0x4a, 0x88, 0x38, 0xbf, 0x9e,
+ 0x70, 0x39, 0x0d, 0x15, 0x83, 0x4b, 0x73, 0x11, 0x09, 0xd1, 0x7e, 0xe0,
+ 0xcd, 0x05, 0x13, 0x5a, 0x3a, 0x77, 0xc8, 0x3d, 0x0b, 0x3b, 0xfe, 0x6c,
+ 0xf7, 0x35, 0x83, 0xc5, 0x8b, 0xfb, 0xee, 0x72, 0x8e, 0xd6, 0x2f, 0x8f,
+ 0xc7, 0x97, 0xcf, 0x98, 0x33, 0x8b, 0xce, 0xfa, 0x58, 0xbf, 0x81, 0xf2,
+ 0xcf, 0x71, 0x62, 0xfe, 0x2c, 0xde, 0x59, 0xc5, 0x8b, 0x44, 0xc7, 0xf1,
+ 0xa1, 0xcf, 0x17, 0x54, 0x27, 0x29, 0x90, 0xad, 0xe4, 0x2c, 0xad, 0xc5,
+ 0x8b, 0xf7, 0xe3, 0x74, 0x52, 0x58, 0xa8, 0x37, 0xce, 0x25, 0x7c, 0xfe,
+ 0xc3, 0x16, 0x2f, 0xf8, 0x71, 0xdf, 0xd8, 0x7a, 0xc5, 0x8a, 0x93, 0x2a,
+ 0xcc, 0x6e, 0x58, 0x44, 0x6c, 0x2f, 0xba, 0x87, 0xc6, 0xa1, 0xbe, 0x72,
+ 0x3f, 0xc7, 0x42, 0x04, 0xf2, 0x87, 0x9f, 0x21, 0x03, 0xe9, 0x62, 0x1b,
+ 0xdd, 0xf7, 0x07, 0xc2, 0x11, 0xdf, 0xd2, 0x2c, 0xef, 0xd8, 0xb1, 0x7a,
+ 0x5e, 0x9d, 0x62, 0xff, 0xf1, 0x67, 0xf1, 0xfa, 0xfc, 0x10, 0x86, 0xb1,
+ 0x7f, 0xf8, 0x11, 0xde, 0x4e, 0x37, 0x7e, 0x9c, 0x6b, 0x16, 0x0f, 0xa4,
+ 0x4a, 0x81, 0x26, 0xa1, 0x30, 0xd1, 0x97, 0x6a, 0x16, 0x97, 0xf1, 0x7a,
+ 0x59, 0xac, 0x58, 0xbf, 0x3b, 0xcf, 0x84, 0xb1, 0x76, 0xe3, 0xac, 0x53,
+ 0x9f, 0x77, 0x8b, 0x43, 0x27, 0xbf, 0xda, 0x9f, 0x8f, 0xd6, 0xb1, 0x62,
+ 0xff, 0x7e, 0x3e, 0xc6, 0xe1, 0x8b, 0x17, 0xf6, 0x74, 0xff, 0x8f, 0xac,
+ 0x54, 0x8f, 0x8f, 0xe6, 0xb7, 0xff, 0x3b, 0x7a, 0x0b, 0xac, 0xf7, 0xd9,
+ 0x62, 0xdc, 0x58, 0xbf, 0x30, 0x39, 0xf6, 0x58, 0xac, 0x37, 0x44, 0x25,
+ 0x76, 0x86, 0xb1, 0x71, 0x86, 0x2c, 0x54, 0x8d, 0x91, 0x83, 0x17, 0xa1,
+ 0xb7, 0xa4, 0x6c, 0x9a, 0x2b, 0xfe, 0x62, 0x60, 0x73, 0x3e, 0xeb, 0x17,
+ 0xf1, 0x61, 0x98, 0x43, 0x58, 0xac, 0x4e, 0x9f, 0xe4, 0x4e, 0xfb, 0xc7,
+ 0x3f, 0x18, 0x86, 0x6f, 0x7f, 0x41, 0x7b, 0xf9, 0x25, 0x8b, 0x81, 0xc5,
+ 0x8b, 0xf9, 0xbe, 0xc6, 0x9b, 0x0b, 0x16, 0x0c, 0x67, 0x8f, 0xe1, 0x8a,
+ 0xd2, 0x27, 0x78, 0xe9, 0x7c, 0x42, 0x70, 0xd6, 0x2a, 0x15, 0xbd, 0x34,
+ 0xa4, 0x00, 0xe1, 0xe8, 0x10, 0x8e, 0xf9, 0x8e, 0xf3, 0x2c, 0x5d, 0xcf,
+ 0x2c, 0x5e, 0x62, 0x75, 0x8b, 0x4e, 0xb1, 0x6c, 0x91, 0xae, 0x21, 0xbb,
+ 0xfe, 0x83, 0xed, 0xcd, 0x4e, 0xd3, 0xac, 0x50, 0xd1, 0x97, 0xd1, 0x1e,
+ 0xea, 0x31, 0x12, 0xdf, 0xf8, 0x84, 0xe1, 0xed, 0xcc, 0x23, 0x56, 0x2f,
+ 0x7e, 0x21, 0x62, 0xfe, 0x3e, 0x0e, 0x0b, 0xa5, 0x8a, 0xda, 0x88, 0xb3,
+ 0xa0, 0x86, 0x39, 0x78, 0xc3, 0x0c, 0x48, 0xa4, 0x8d, 0x93, 0x43, 0x7c,
+ 0xc6, 0x34, 0xc9, 0x15, 0xd1, 0xe1, 0xb0, 0xfd, 0xf6, 0xa3, 0x7e, 0x2c,
+ 0x5e, 0x9b, 0x3e, 0xb1, 0x58, 0x78, 0x4e, 0x49, 0x7d, 0x9e, 0x13, 0xac,
+ 0x5d, 0x81, 0x75, 0x8b, 0xfb, 0xfb, 0x74, 0xd1, 0xc5, 0x8a, 0xd8, 0x1b,
+ 0xce, 0x08, 0x8c, 0x6e, 0x78, 0xc2, 0xe5, 0x08, 0x4c, 0x9d, 0x3e, 0x6a,
+ 0x59, 0xc6, 0xa5, 0x05, 0x1e, 0x14, 0x7f, 0x97, 0x52, 0xf1, 0x8b, 0x82,
+ 0x19, 0x65, 0x09, 0x7e, 0x32, 0x78, 0x80, 0xc2, 0x20, 0xc6, 0xef, 0xc4,
+ 0xf2, 0xc1, 0xac, 0x5e, 0x90, 0xb1, 0x62, 0xfd, 0x9d, 0xf2, 0x24, 0xb1,
+ 0x5a, 0x3c, 0x63, 0x07, 0x6f, 0xfb, 0xfd, 0x34, 0x00, 0xf1, 0x25, 0x8b,
+ 0xff, 0xbc, 0x06, 0x29, 0x72, 0x7d, 0xfc, 0x65, 0x8b, 0xdf, 0xc9, 0xd6,
+ 0x2f, 0xd8, 0x00, 0x60, 0x16, 0x29, 0xcf, 0x18, 0x87, 0xaf, 0xc3, 0x8f,
+ 0xc4, 0x96, 0x2f, 0xec, 0xd4, 0x14, 0x71, 0x62, 0xff, 0xff, 0x73, 0x37,
+ 0x94, 0x77, 0x87, 0x7e, 0x66, 0x9f, 0xb3, 0x16, 0x2a, 0x11, 0x71, 0x85,
+ 0x1e, 0x2c, 0xbf, 0x78, 0x3f, 0xb8, 0x16, 0x2a, 0x73, 0xd8, 0xec, 0xba,
+ 0x86, 0x9f, 0x17, 0x70, 0x8e, 0x28, 0xcc, 0x2f, 0x13, 0x71, 0x62, 0xf3,
+ 0xe7, 0x4b, 0x17, 0x9b, 0x27, 0x58, 0xbf, 0xf1, 0x8e, 0x3d, 0xa1, 0x80,
+ 0x0c, 0x11, 0x62, 0xfc, 0x2f, 0x38, 0x38, 0xb1, 0x5f, 0x3e, 0xf0, 0x23,
+ 0x5f, 0xf4, 0xf0, 0xfd, 0x03, 0x59, 0xda, 0xc5, 0x68, 0xf7, 0x88, 0x8a,
+ 0xf8, 0x6e, 0x40, 0x58, 0xbf, 0xe7, 0x3b, 0x7f, 0xbe, 0x40, 0xd6, 0x2f,
+ 0xfe, 0x82, 0x01, 0x47, 0x73, 0x41, 0x01, 0x62, 0xb6, 0xae, 0x1e, 0x64,
+ 0xa1, 0xc6, 0x3c, 0xd0, 0xe7, 0xc7, 0x5e, 0x1d, 0x40, 0x21, 0x22, 0x2e,
+ 0x1d, 0x5f, 0xb6, 0x9e, 0x33, 0xcb, 0x17, 0x81, 0x22, 0x58, 0xa9, 0xcf,
+ 0x1e, 0x45, 0x57, 0xe9, 0xb7, 0x01, 0xb9, 0x8b, 0x17, 0xbc, 0xff, 0x58,
+ 0xbf, 0x78, 0xa0, 0xfc, 0x58, 0xbf, 0x71, 0xfb, 0xc3, 0xac, 0x54, 0x1f,
+ 0x77, 0x63, 0xbe, 0x28, 0xbf, 0xf3, 0xeb, 0x9f, 0x6e, 0x85, 0xa0, 0x2c,
+ 0x5f, 0xf6, 0x4e, 0x7c, 0xef, 0xd0, 0x75, 0x8a, 0x83, 0xfc, 0x1a, 0x0d,
+ 0xfb, 0x59, 0xbd, 0xfe, 0xb1, 0x66, 0x58, 0xbf, 0xe7, 0x37, 0xaf, 0xb0,
+ 0xde, 0x4b, 0x17, 0xd3, 0xce, 0xfd, 0xac, 0x5b, 0x8c, 0x7e, 0x44, 0x22,
+ 0x19, 0xdd, 0xff, 0xfe, 0xfc, 0x14, 0x0b, 0xaf, 0x3f, 0xf0, 0xed, 0xe0,
+ 0x09, 0x62, 0x8d, 0x4c, 0xc4, 0x10, 0x9c, 0xf1, 0xa5, 0xff, 0xe3, 0x5b,
+ 0xc5, 0x92, 0xdb, 0xd1, 0xc1, 0x0b, 0x17, 0xd9, 0xaf, 0xb2, 0xc5, 0xf9,
+ 0xa6, 0xfb, 0x01, 0x62, 0xff, 0xf3, 0xc8, 0xb3, 0x7b, 0xcd, 0x19, 0xee,
+ 0x2c, 0x54, 0x22, 0x5b, 0xe4, 0x4e, 0x53, 0x6d, 0xc5, 0x8b, 0xe1, 0xbb,
+ 0x0d, 0x62, 0xb6, 0x03, 0x6f, 0x82, 0xb7, 0xb7, 0xe1, 0x2c, 0x5d, 0xf6,
+ 0x58, 0xbd, 0xe0, 0x09, 0x62, 0xff, 0x98, 0xc9, 0xb6, 0xc6, 0xb5, 0x8b,
+ 0x15, 0x08, 0x90, 0x34, 0x79, 0x85, 0xe6, 0x1e, 0xbf, 0xd9, 0x38, 0x7f,
+ 0xfe, 0x6e, 0xac, 0x5f, 0xfc, 0x0f, 0xe6, 0x4e, 0xd9, 0xbe, 0x3b, 0x58,
+ 0xa8, 0x44, 0x01, 0x87, 0x37, 0xff, 0x41, 0xf5, 0xa8, 0x9f, 0xce, 0xe6,
+ 0xac, 0x5d, 0x06, 0x2c, 0x50, 0x0f, 0x78, 0x91, 0xaf, 0xff, 0x84, 0x17,
+ 0xe7, 0x3a, 0xfb, 0x77, 0xed, 0x6a, 0x16, 0x2f, 0xed, 0xed, 0xac, 0x1e,
+ 0xc0, 0xb1, 0x7c, 0xde, 0x8d, 0x2c, 0x5f, 0xf6, 0x73, 0x1a, 0x73, 0xb8,
+ 0x45, 0x8b, 0xbf, 0x8b, 0x15, 0x23, 0xd2, 0xe1, 0xdd, 0x42, 0x64, 0x78,
+ 0xb1, 0xf3, 0x51, 0x3a, 0x5e, 0x3c, 0x74, 0xb1, 0x7f, 0xcf, 0x2e, 0x01,
+ 0xf7, 0xe0, 0xd6, 0x2e, 0xcf, 0xe1, 0xec, 0xfc, 0x7a, 0xff, 0xfc, 0xda,
+ 0xf8, 0xbe, 0xed, 0xe8, 0x90, 0x87, 0x8b, 0x17, 0xed, 0x34, 0xee, 0x75,
+ 0x8b, 0x8c, 0x31, 0x62, 0xb0, 0xf0, 0xcc, 0x29, 0xbf, 0x9d, 0xbb, 0xe4,
+ 0x1a, 0xb1, 0x61, 0x24, 0x6c, 0x9e, 0x8f, 0xc8, 0xa8, 0xe9, 0x8e, 0x7e,
+ 0x1d, 0x37, 0xff, 0xb7, 0xfd, 0xb0, 0xba, 0xfb, 0x1e, 0x3a, 0x58, 0xbf,
+ 0x9c, 0x1d, 0xcb, 0x3c, 0xb1, 0x58, 0x7f, 0x8c, 0x9b, 0x7a, 0x41, 0x9d,
+ 0x62, 0xf9, 0xfb, 0x18, 0xd6, 0x2f, 0x40, 0x38, 0xb1, 0x52, 0x54, 0xda,
+ 0xd1, 0xa4, 0x7e, 0x14, 0xae, 0x41, 0xc1, 0xf1, 0x12, 0x5e, 0xc3, 0xee,
+ 0xac, 0x5f, 0xf9, 0xf7, 0xe0, 0x65, 0x1f, 0x69, 0xd6, 0x2f, 0xf6, 0x70,
+ 0xb3, 0xdf, 0x65, 0x8a, 0x1a, 0x24, 0xf4, 0x40, 0x48, 0x37, 0xf3, 0x7d,
+ 0xc9, 0x8e, 0xb1, 0x43, 0x65, 0x2d, 0xe4, 0x6a, 0x4c, 0x6f, 0x34, 0x39,
+ 0x34, 0xca, 0x78, 0x5a, 0xfe, 0x17, 0xa0, 0x84, 0x09, 0x46, 0x89, 0xe9,
+ 0x60, 0x5b, 0xe1, 0xea, 0x10, 0xbe, 0xff, 0x87, 0x80, 0x03, 0x16, 0xdd,
+ 0xc5, 0x8a, 0x58, 0xbf, 0xb0, 0x00, 0x62, 0xdc, 0x58, 0xbf, 0xa3, 0x8d,
+ 0xe2, 0x85, 0x8a, 0xda, 0x8a, 0x68, 0x3e, 0x18, 0x67, 0xcc, 0x2f, 0xe9,
+ 0x31, 0x7b, 0x0e, 0xb1, 0x7d, 0x9f, 0x63, 0x16, 0x2f, 0xf7, 0xb3, 0x40,
+ 0x3b, 0xc9, 0x62, 0xfa, 0x40, 0xc0, 0x2c, 0x5f, 0x3e, 0x07, 0x8b, 0x17,
+ 0xf7, 0xb2, 0x62, 0x83, 0xae, 0x20, 0x22, 0xe0, 0x82, 0x58, 0xbe, 0x21,
+ 0xfe, 0x15, 0x10, 0x11, 0xb2, 0x7a, 0xa7, 0x3b, 0xb8, 0xa1, 0x62, 0xa1,
+ 0x38, 0x49, 0xcb, 0x70, 0x8f, 0xb3, 0x4f, 0x91, 0xbb, 0xb8, 0x45, 0x0b,
+ 0xfc, 0x66, 0x6d, 0xe1, 0x46, 0x96, 0x2f, 0xfa, 0x68, 0x33, 0x59, 0xd3,
+ 0x7d, 0x62, 0xff, 0xa4, 0x4d, 0x3f, 0x9e, 0x5c, 0x58, 0xbf, 0xef, 0x64,
+ 0xf0, 0x11, 0xb5, 0x8b, 0x17, 0xd8, 0x78, 0xdd, 0x58, 0xbe, 0xcc, 0x2e,
+ 0xbb, 0x3e, 0x0e, 0x1d, 0xd6, 0x26, 0x1f, 0xd9, 0xe7, 0xe1, 0x35, 0x7f,
+ 0xdc, 0x1e, 0x14, 0x10, 0xa1, 0x62, 0xcc, 0x69, 0xf6, 0xf6, 0x6d, 0x7f,
+ 0xff, 0x7e, 0x3f, 0xd3, 0x73, 0x06, 0x59, 0x34, 0xd1, 0x3a, 0xc5, 0xf8,
+ 0xe0, 0xd6, 0x76, 0xb1, 0x43, 0x44, 0x46, 0x2f, 0x5f, 0xb4, 0xc2, 0x0b,
+ 0xc2, 0xc5, 0xfe, 0xd6, 0x77, 0xc0, 0x3f, 0x96, 0x2f, 0xf3, 0x17, 0xa0,
+ 0x1e, 0xe2, 0xc5, 0xd1, 0xda, 0xc5, 0xa6, 0x91, 0xe5, 0x98, 0x67, 0x50,
+ 0x8d, 0x63, 0x4b, 0x39, 0x08, 0x0b, 0x0a, 0x74, 0xcb, 0x7a, 0x87, 0xc5,
+ 0xfa, 0x24, 0xfd, 0x98, 0xb1, 0x7f, 0xdb, 0x75, 0xac, 0xff, 0x72, 0xe2,
+ 0xc5, 0xff, 0xfe, 0xce, 0x09, 0xfb, 0xcc, 0x23, 0x79, 0xcc, 0x2f, 0x71,
+ 0x62, 0xff, 0xa4, 0xc5, 0xef, 0xe4, 0xb7, 0x16, 0x2b, 0xa4, 0x6d, 0xf6,
+ 0x7c, 0x76, 0x1b, 0x8d, 0xde, 0xb1, 0x7f, 0xde, 0xd4, 0x67, 0x7b, 0x0b,
+ 0x61, 0xec, 0x0b, 0x17, 0xc7, 0x77, 0x1a, 0xc5, 0xff, 0x78, 0x51, 0x93,
+ 0xec, 0x2d, 0x87, 0xb0, 0x2c, 0x5c, 0xe6, 0x0d, 0x1a, 0xbd, 0x8d, 0xf1,
+ 0x30, 0x32, 0x2a, 0x85, 0xe1, 0x8c, 0x8e, 0xc9, 0xa3, 0xde, 0xd1, 0x8b,
+ 0xc6, 0x0a, 0x51, 0x83, 0xdf, 0x7b, 0x82, 0x92, 0xc5, 0xff, 0xa3, 0xb0,
+ 0x63, 0x3e, 0xf8, 0xd2, 0xc5, 0xf8, 0x5b, 0x99, 0xa0, 0x2c, 0x5f, 0xb4,
+ 0x03, 0xbc, 0x96, 0x29, 0xd1, 0x72, 0x44, 0x9c, 0x40, 0x0c, 0xb2, 0xd3,
+ 0xac, 0x5f, 0xb6, 0xe4, 0xcc, 0x75, 0x8b, 0xf8, 0x0f, 0x29, 0xde, 0x75,
+ 0x8b, 0xfe, 0xef, 0xd9, 0x26, 0x20, 0x32, 0xc5, 0xfc, 0x29, 0xd8, 0x84,
+ 0x75, 0x8a, 0x83, 0xe8, 0x23, 0x9b, 0xe3, 0xfe, 0x37, 0xac, 0x5f, 0xfb,
+ 0xb3, 0x5f, 0x9e, 0x26, 0xef, 0x8b, 0x15, 0x07, 0xce, 0xe4, 0xb7, 0xff,
+ 0x85, 0x1b, 0x42, 0x79, 0xb9, 0xfe, 0xdc, 0xc5, 0x8a, 0x9d, 0x3b, 0xbc,
+ 0x2b, 0x68, 0x4c, 0x6a, 0x10, 0xfc, 0x20, 0xbf, 0xf6, 0x0f, 0xef, 0xb3,
+ 0x1f, 0x8e, 0xd6, 0x2f, 0xfb, 0xef, 0xc6, 0x22, 0x8e, 0xd6, 0x29, 0x60,
+ 0x2a, 0xaa, 0x73, 0x51, 0xe7, 0x1d, 0x53, 0x88, 0x57, 0xfc, 0x46, 0xe8,
+ 0x9b, 0xa1, 0x12, 0xc5, 0xfb, 0xd1, 0x85, 0x0b, 0x14, 0xc7, 0xc0, 0x47,
+ 0x57, 0x83, 0x2f, 0x2c, 0x5e, 0x63, 0xba, 0xc5, 0xfe, 0xc6, 0x35, 0x86,
+ 0xe7, 0x58, 0xbf, 0xb5, 0xdf, 0x30, 0x8d, 0x58, 0xa1, 0x9f, 0x18, 0x66,
+ 0x77, 0xa0, 0x0c, 0xb1, 0x53, 0xa3, 0x70, 0xd1, 0xe3, 0xbf, 0x98, 0x47,
+ 0x7f, 0xe8, 0x6e, 0x47, 0xb9, 0x1f, 0x85, 0x8b, 0xfe, 0xdb, 0xc8, 0xd3,
+ 0xc9, 0xbe, 0xb1, 0x7f, 0xdd, 0x0b, 0x1b, 0xbf, 0x41, 0xd6, 0x2c, 0xdc,
+ 0x3f, 0x61, 0x1d, 0xdf, 0xf6, 0x4e, 0x50, 0x6e, 0x77, 0xe5, 0x8a, 0x35,
+ 0x31, 0x53, 0xc2, 0xcc, 0x32, 0x7b, 0xf7, 0x58, 0xdc, 0x3a, 0xc5, 0xff,
+ 0xdc, 0x82, 0xf0, 0x73, 0x7d, 0xbd, 0xc5, 0x8b, 0xec, 0xd4, 0x6f, 0x58,
+ 0xae, 0xcf, 0xaf, 0xc8, 0xf7, 0xf4, 0xa2, 0x78, 0xe0, 0x96, 0x2f, 0xff,
+ 0xc7, 0x89, 0x67, 0x43, 0x62, 0xcd, 0x75, 0x18, 0xb1, 0x6e, 0xa6, 0x44,
+ 0x20, 0x0b, 0xeb, 0xb4, 0x69, 0x14, 0x29, 0xe8, 0xe9, 0xc7, 0x3c, 0x6c,
+ 0xd5, 0x0b, 0x9e, 0x39, 0x0b, 0x16, 0x87, 0xe3, 0xc6, 0xaa, 0x28, 0xf1,
+ 0xaf, 0x04, 0x8e, 0xd6, 0x2f, 0xf1, 0x60, 0x38, 0x1b, 0xf9, 0x62, 0xf7,
+ 0x9c, 0x6b, 0x17, 0x61, 0xd6, 0x2f, 0xb5, 0x3c, 0x49, 0x62, 0xa0, 0xdd,
+ 0xe0, 0xbd, 0xcd, 0x8b, 0x17, 0xec, 0xd6, 0x9e, 0x4b, 0x17, 0xed, 0x69,
+ 0xa6, 0xe2, 0xc5, 0x48, 0xf4, 0xb0, 0xa2, 0xa4, 0x88, 0x9f, 0x34, 0x5e,
+ 0x3c, 0xf0, 0xb1, 0x7f, 0xb0, 0xa3, 0xbe, 0x3f, 0x4b, 0x14, 0x69, 0xfa,
+ 0xf4, 0x46, 0x60, 0xf5, 0xee, 0x4b, 0xa5, 0x8b, 0xe8, 0xdd, 0xd4, 0x2c,
+ 0x56, 0x1e, 0x27, 0x07, 0xef, 0x00, 0xfe, 0x58, 0xa9, 0x2a, 0x7e, 0x62,
+ 0x09, 0x8d, 0x0e, 0xb0, 0xf1, 0x8e, 0x81, 0xd8, 0x88, 0x6f, 0x75, 0x27,
+ 0x58, 0xbf, 0xe3, 0xc7, 0x4d, 0xed, 0x08, 0xeb, 0x15, 0xb4, 0xf6, 0x70,
+ 0x7a, 0xfd, 0xf7, 0x9c, 0x7b, 0xd6, 0x2f, 0xed, 0x43, 0x49, 0xf8, 0xb1,
+ 0x60, 0x8b, 0x17, 0x69, 0xa7, 0x3c, 0x19, 0x8b, 0x6f, 0xfc, 0xf9, 0x84,
+ 0x68, 0x7e, 0x10, 0xd6, 0x2f, 0xf3, 0xb0, 0xdb, 0x3b, 0xf2, 0xc5, 0xe9,
+ 0x9c, 0x6b, 0x17, 0x82, 0x36, 0xf5, 0x8b, 0x4f, 0xa4, 0x70, 0xfc, 0xbf,
+ 0xc8, 0x02, 0x33, 0x08, 0x3d, 0x79, 0xbb, 0xe2, 0xc5, 0xff, 0xdc, 0x89,
+ 0xf3, 0x53, 0x14, 0x03, 0x8b, 0x17, 0xff, 0x05, 0xca, 0x0f, 0xac, 0x6f,
+ 0xc0, 0xd6, 0x2f, 0xf3, 0x7f, 0x35, 0xac, 0xed, 0x62, 0xfd, 0x31, 0x46,
+ 0xa4, 0xb1, 0x68, 0x91, 0xee, 0xe1, 0xa5, 0xff, 0xf9, 0x8c, 0xc2, 0x17,
+ 0x4c, 0x6f, 0x3f, 0x05, 0xe5, 0x8a, 0x92, 0xb4, 0x9e, 0x88, 0xde, 0x34,
+ 0xe0, 0x29, 0xf8, 0x78, 0x48, 0xc6, 0x42, 0x90, 0x21, 0x35, 0xf6, 0x9e,
+ 0x53, 0x2c, 0x5f, 0xfb, 0xbf, 0x61, 0x40, 0x30, 0x80, 0xb1, 0x7d, 0xc8,
+ 0x00, 0x51, 0x62, 0xb0, 0xf9, 0x78, 0x7d, 0x46, 0xa2, 0xa8, 0xc8, 0x44,
+ 0xdf, 0x7f, 0x00, 0xeb, 0x15, 0x09, 0xbb, 0xbc, 0x65, 0x7c, 0x2a, 0xbf,
+ 0x70, 0x4d, 0x13, 0x2c, 0x5f, 0xb8, 0xc5, 0xe6, 0x58, 0xbf, 0x79, 0xba,
+ 0x79, 0x2c, 0x5c, 0x6f, 0x16, 0x2d, 0xa8, 0x44, 0x94, 0xc5, 0x2e, 0x4f,
+ 0xc2, 0x9b, 0xff, 0x49, 0x8e, 0x66, 0x10, 0xff, 0x0b, 0x17, 0xff, 0x14,
+ 0x7b, 0x33, 0x5a, 0xc8, 0xe9, 0x62, 0xff, 0x1b, 0x9a, 0x01, 0xdb, 0x8b,
+ 0x15, 0xda, 0x2d, 0xfe, 0x7e, 0x48, 0x77, 0xfb, 0xed, 0xd8, 0x34, 0xe3,
+ 0x58, 0xb4, 0xcb, 0x17, 0xdd, 0x83, 0x50, 0x91, 0x71, 0x86, 0x24, 0x54,
+ 0x1b, 0xe3, 0x09, 0x2c, 0xc9, 0x1b, 0x26, 0x86, 0xbe, 0x89, 0x62, 0x72,
+ 0xbf, 0xf0, 0xc5, 0xe6, 0xfb, 0x1b, 0xf6, 0x58, 0xbf, 0xff, 0xe6, 0xdd,
+ 0x81, 0xed, 0x78, 0xef, 0xaf, 0xc7, 0x7c, 0x78, 0x08, 0xb1, 0x7f, 0xff,
+ 0xb0, 0x24, 0x4c, 0xc7, 0x89, 0xb6, 0x97, 0x72, 0xf8, 0x80, 0xb1, 0x71,
+ 0x6c, 0xc2, 0x35, 0xf1, 0xbe, 0xfb, 0xa2, 0x79, 0x2c, 0x5c, 0xdd, 0x2c,
+ 0x5f, 0xe0, 0x0b, 0xc5, 0x1e, 0xe2, 0xc5, 0x82, 0x2c, 0x5f, 0x3e, 0xd0,
+ 0xce, 0xb1, 0x4e, 0x7d, 0xdb, 0xcd, 0x0c, 0x14, 0xbf, 0x86, 0xdb, 0xff,
+ 0x81, 0x16, 0x2d, 0x32, 0xc5, 0x61, 0xe2, 0xb1, 0x95, 0x2c, 0x5d, 0x39,
+ 0x2c, 0x5e, 0xe6, 0x69, 0x62, 0xf7, 0x4d, 0xa5, 0x8b, 0xb3, 0xeb, 0x15,
+ 0xd9, 0xb5, 0xdc, 0x1e, 0xbb, 0x52, 0xda, 0xb8, 0x1b, 0x28, 0x65, 0xe1,
+ 0x17, 0x71, 0x8b, 0xb1, 0x7e, 0x88, 0xff, 0x08, 0x67, 0x76, 0x01, 0x00,
+ 0x5c, 0x33, 0x83, 0x1e, 0x52, 0xa8, 0x5d, 0x05, 0x79, 0xc3, 0xdb, 0xef,
+ 0x79, 0xce, 0xb1, 0x7e, 0x29, 0x74, 0x29, 0xd6, 0x2f, 0x46, 0xa6, 0x58,
+ 0xa7, 0x3c, 0x91, 0x15, 0xdf, 0xff, 0xe2, 0xf4, 0x74, 0x42, 0x3e, 0x4b,
+ 0xf8, 0x46, 0x46, 0x96, 0x2f, 0xc7, 0x27, 0xf7, 0x16, 0x29, 0xd1, 0x12,
+ 0x1b, 0x0d, 0x6d, 0x76, 0x93, 0x7b, 0x03, 0x6c, 0x4e, 0x2f, 0xcf, 0x0d,
+ 0x29, 0x11, 0x8e, 0x13, 0xd9, 0x4b, 0x06, 0xee, 0x37, 0xd6, 0x8f, 0x0b,
+ 0x53, 0xcf, 0xc7, 0x8c, 0x9b, 0xf3, 0xf9, 0x2f, 0x2b, 0x74, 0xa7, 0x60,
+ 0xfd, 0x0c, 0x71, 0x4e, 0xff, 0x6f, 0x2c, 0x31, 0xb0, 0x38, 0x55, 0x5e,
+ 0x97, 0xa7, 0x58, 0xbd, 0xe6, 0x31, 0x62, 0xc6, 0xac, 0x5f, 0xb7, 0x05,
+ 0xf6, 0xd2, 0xc5, 0xfd, 0x06, 0x68, 0x50, 0x05, 0x8a, 0x9c, 0xf6, 0xfc,
+ 0x59, 0x7f, 0x8a, 0x5c, 0x1f, 0xd8, 0xc5, 0x8b, 0xd3, 0xb9, 0xd6, 0x2e,
+ 0xec, 0x96, 0x2f, 0xdd, 0xcb, 0xe1, 0xf1, 0x62, 0xcf, 0x87, 0x88, 0x43,
+ 0x17, 0x30, 0xd6, 0x2f, 0xc5, 0x1f, 0x7e, 0x2c, 0x5a, 0x65, 0x8b, 0x8f,
+ 0x0b, 0x17, 0xbc, 0xc6, 0x2e, 0x30, 0x82, 0xe7, 0x0d, 0x51, 0x03, 0x9d,
+ 0x9a, 0xba, 0xda, 0x88, 0xb6, 0x13, 0x12, 0x15, 0x49, 0x31, 0xff, 0x92,
+ 0x85, 0xc5, 0xfd, 0x0b, 0x2a, 0xda, 0xaa, 0x3a, 0x1b, 0x98, 0x8d, 0xcd,
+ 0x45, 0x1c, 0x0d, 0xe8, 0x9e, 0x16, 0x2f, 0xfe, 0x89, 0x67, 0xdf, 0xb0,
+ 0x67, 0x7e, 0x58, 0xb8, 0x18, 0x47, 0xc7, 0xc1, 0xdb, 0xf8, 0x4e, 0x13,
+ 0xf9, 0x3a, 0xc5, 0xfe, 0x17, 0xdb, 0x59, 0xdf, 0x96, 0x2f, 0xef, 0x63,
+ 0x6e, 0x7e, 0x16, 0x2d, 0xcd, 0xa8, 0x96, 0xdc, 0x31, 0x0c, 0xd6, 0xed,
+ 0x05, 0xd6, 0x2b, 0x49, 0x8d, 0x02, 0x18, 0x44, 0x79, 0x7f, 0x61, 0x03,
+ 0x30, 0x6b, 0x17, 0xf3, 0x03, 0x0f, 0x1d, 0x2c, 0x5c, 0xe6, 0x2c, 0x5f,
+ 0xce, 0xdd, 0xf1, 0x9d, 0x62, 0xff, 0xf7, 0x8a, 0x33, 0x7b, 0x7a, 0x30,
+ 0xa4, 0xb1, 0x46, 0x9f, 0xb3, 0x16, 0xdf, 0xff, 0xfa, 0x5d, 0x7d, 0xb5,
+ 0x39, 0xe3, 0xaf, 0xc3, 0x0e, 0x3f, 0x12, 0x58, 0xbd, 0xf8, 0x35, 0x62,
+ 0xbb, 0x44, 0x6e, 0xf6, 0xfb, 0xf8, 0x1a, 0xd3, 0x76, 0x05, 0x8b, 0xff,
+ 0xa5, 0x04, 0x0c, 0xd0, 0x0e, 0xdc, 0x58, 0xbf, 0xd9, 0xd4, 0x4e, 0x51,
+ 0xd2, 0xc5, 0xfb, 0xa2, 0x8e, 0xe4, 0xb1, 0x60, 0x2c, 0x5b, 0x77, 0x69,
+ 0xf8, 0xe1, 0xab, 0x15, 0x5e, 0x83, 0xc2, 0xc5, 0xfb, 0x3d, 0xc7, 0xed,
+ 0x62, 0xff, 0xf7, 0x33, 0xed, 0xc1, 0x4f, 0xb6, 0x68, 0x25, 0x8b, 0xa0,
+ 0x4b, 0x17, 0xe1, 0x10, 0x03, 0x92, 0xc5, 0xfe, 0xfc, 0x00, 0xef, 0x2d,
+ 0xb8, 0x78, 0x3c, 0x17, 0xa1, 0xa6, 0x07, 0xc2, 0x90, 0xe1, 0x1f, 0x7f,
+ 0xfe, 0x28, 0x96, 0x7d, 0xf5, 0x1e, 0x60, 0x44, 0x96, 0x2f, 0xf4, 0x02,
+ 0x69, 0x30, 0x82, 0xeb, 0x17, 0x67, 0x36, 0xa3, 0x0c, 0x66, 0xe1, 0xa9,
+ 0xd0, 0xd5, 0x10, 0x14, 0x7c, 0x54, 0x35, 0xcc, 0xa3, 0x61, 0x1c, 0xf0,
+ 0xaf, 0x22, 0x6f, 0x18, 0x0a, 0x16, 0xbb, 0xe5, 0x2c, 0x5f, 0xfd, 0xa6,
+ 0xec, 0x3f, 0x63, 0x49, 0xf8, 0xb1, 0x7f, 0xc2, 0x9e, 0x36, 0xc7, 0xa0,
+ 0x6b, 0x15, 0xa4, 0x41, 0x7d, 0x1a, 0xf8, 0x20, 0x48, 0xdd, 0x58, 0xbf,
+ 0xff, 0x47, 0xbf, 0x83, 0xf6, 0x7c, 0xb3, 0xdf, 0x65, 0x8b, 0x46, 0xd3,
+ 0xfe, 0xd1, 0x55, 0xf3, 0xc8, 0x07, 0x58, 0xbf, 0xff, 0xa0, 0x3d, 0x31,
+ 0xe0, 0xde, 0x7d, 0xbc, 0x50, 0x75, 0x8a, 0x39, 0xff, 0x80, 0x8e, 0xda,
+ 0xd2, 0x32, 0x81, 0x0a, 0x8b, 0xfe, 0x0f, 0xcc, 0x42, 0x96, 0x71, 0x62,
+ 0xf3, 0xea, 0x75, 0x8b, 0x8c, 0x31, 0x62, 0xfe, 0x6c, 0xde, 0x1c, 0xb6,
+ 0x7a, 0x37, 0x06, 0x0f, 0x57, 0x48, 0xbd, 0xd3, 0x95, 0xf1, 0x3f, 0x60,
+ 0x58, 0xbf, 0xb8, 0x20, 0x1e, 0x24, 0xb1, 0x7f, 0x49, 0x9f, 0x7f, 0xd9,
+ 0x62, 0xf4, 0x7f, 0x8b, 0x17, 0x31, 0xbb, 0x4f, 0xef, 0x0b, 0xc0, 0x5f,
+ 0x7f, 0xb9, 0x9e, 0x73, 0xe1, 0x2c, 0x50, 0xd5, 0xc3, 0x34, 0x6d, 0x7a,
+ 0x87, 0x59, 0xc9, 0x3f, 0x09, 0xef, 0x1e, 0x5f, 0xfb, 0x98, 0x59, 0xfc,
+ 0xeb, 0x09, 0x62, 0xff, 0xf3, 0x73, 0x0b, 0x68, 0x7a, 0x9b, 0x30, 0xc5,
+ 0x8b, 0xed, 0x34, 0x1d, 0x62, 0xff, 0x73, 0xdf, 0xc3, 0xe4, 0x96, 0x2f,
+ 0xff, 0x0a, 0x07, 0x9e, 0x00, 0x65, 0x2f, 0xe2, 0xc5, 0xd1, 0xc5, 0x8b,
+ 0x42, 0xc5, 0xff, 0xb6, 0x08, 0xe7, 0x33, 0xdf, 0x79, 0x2c, 0x5f, 0xff,
+ 0x7b, 0x91, 0xee, 0xe3, 0xff, 0x8d, 0xf1, 0xc5, 0x8a, 0x0a, 0xa2, 0x5f,
+ 0x11, 0x2f, 0x60, 0x37, 0x06, 0x8c, 0xec, 0x85, 0x45, 0x49, 0x39, 0xf1,
+ 0x9a, 0x01, 0x2c, 0xa1, 0xcb, 0x7f, 0xff, 0x6b, 0x25, 0xb9, 0x9d, 0x7d,
+ 0x86, 0x50, 0x66, 0x12, 0xc5, 0xf1, 0x8e, 0x19, 0xd6, 0x2f, 0x3f, 0x70,
+ 0xb1, 0x7e, 0xc3, 0x7e, 0xf2, 0xf9, 0xe1, 0x06, 0x4b, 0x52, 0x56, 0xdc,
+ 0x33, 0xd3, 0x53, 0x9a, 0x3c, 0x1d, 0x21, 0x14, 0x28, 0x2a, 0x17, 0x0e,
+ 0x72, 0x5e, 0xb5, 0xfe, 0xde, 0x66, 0x10, 0xff, 0x0b, 0x17, 0xf3, 0x0f,
+ 0x58, 0x7c, 0x58, 0xbf, 0xef, 0x70, 0x3d, 0x47, 0xa2, 0x4b, 0x17, 0xdd,
+ 0x3b, 0xf4, 0xa8, 0x86, 0x0b, 0xfc, 0xd1, 0xa9, 0x0a, 0x31, 0x62, 0xb6,
+ 0xa2, 0x7b, 0x47, 0x64, 0x63, 0x7c, 0x73, 0xbc, 0xb6, 0xa3, 0xf3, 0x21,
+ 0x97, 0x7f, 0xe2, 0xc9, 0xf4, 0xc6, 0x1e, 0x38, 0xb1, 0x7f, 0xff, 0x30,
+ 0xc2, 0x46, 0x6a, 0x78, 0x19, 0x39, 0xa6, 0xc2, 0xc5, 0x1a, 0x89, 0xed,
+ 0xe8, 0x17, 0xfc, 0xc0, 0x72, 0xf3, 0xbf, 0xd6, 0x2f, 0xba, 0x77, 0xe9,
+ 0x71, 0x88, 0x97, 0xff, 0xfb, 0x3a, 0xfc, 0x77, 0x2d, 0xcc, 0xff, 0x4d,
+ 0x84, 0xe6, 0xac, 0x56, 0x91, 0x2e, 0x46, 0x37, 0x74, 0x05, 0x8b, 0x9f,
+ 0x92, 0x4c, 0x27, 0x21, 0x9c, 0x72, 0x2a, 0xc5, 0x49, 0xaf, 0x0d, 0xe1,
+ 0x46, 0x5f, 0x4b, 0x14, 0xb1, 0x69, 0xc4, 0x5c, 0x6e, 0x06, 0x5f, 0xee,
+ 0x79, 0xfb, 0xdc, 0x63, 0x56, 0x2f, 0xd9, 0x34, 0x10, 0xd6, 0x2a, 0x0f,
+ 0x87, 0x47, 0x35, 0x0d, 0x96, 0x0c, 0x8d, 0x70, 0xb1, 0xa7, 0x3e, 0x3f,
+ 0x48, 0xbf, 0x72, 0xb2, 0x96, 0xff, 0xe5, 0x31, 0x42, 0x2e, 0xfc, 0x50,
+ 0x0e, 0xc0, 0xb1, 0x7e, 0xc9, 0x46, 0x80, 0xb1, 0x7f, 0xf4, 0xff, 0x86,
+ 0xf7, 0x22, 0x7c, 0xe2, 0xc5, 0xd0, 0x1a, 0xc5, 0xf9, 0xe7, 0x28, 0x92,
+ 0x45, 0x4c, 0x78, 0x1f, 0x18, 0xbf, 0xce, 0xde, 0x8d, 0x40, 0x16, 0x2f,
+ 0xde, 0xc3, 0xb7, 0x96, 0x2f, 0xfd, 0xe2, 0x80, 0x0c, 0x9b, 0xbf, 0x2c,
+ 0x5b, 0xdf, 0x44, 0xcb, 0x99, 0x06, 0x51, 0x7c, 0xe4, 0x1c, 0xeb, 0x17,
+ 0xf3, 0x9b, 0x83, 0x62, 0x58, 0xaf, 0x9e, 0x89, 0x12, 0x54, 0x95, 0x1d,
+ 0x9a, 0x53, 0xa2, 0x83, 0xc2, 0x18, 0xa1, 0x78, 0x64, 0x21, 0xef, 0xfc,
+ 0xdd, 0x47, 0x1f, 0x5a, 0x63, 0x16, 0x2f, 0x88, 0x7f, 0x85, 0x8b, 0xfe,
+ 0x9e, 0x47, 0x8f, 0xbb, 0x1a, 0xb1, 0x7f, 0xec, 0xe4, 0x7d, 0xfc, 0x1c,
+ 0x0d, 0x62, 0xff, 0x9d, 0xcc, 0xfb, 0x9d, 0xb8, 0xb1, 0x7f, 0xef, 0x31,
+ 0x4f, 0x9d, 0xfb, 0xee, 0xb1, 0x7f, 0xf3, 0x68, 0xde, 0xbe, 0xdf, 0x21,
+ 0x4e, 0xb1, 0x50, 0x98, 0x00, 0xcf, 0xf0, 0xe4, 0x08, 0x17, 0xff, 0x75,
+ 0xad, 0x67, 0x39, 0xc7, 0x29, 0x2c, 0x5f, 0xff, 0xc3, 0xd1, 0x39, 0x9b,
+ 0x5b, 0x50, 0x59, 0xfc, 0xe9, 0x62, 0x9d, 0x51, 0xe1, 0x11, 0x72, 0x33,
+ 0xb1, 0x1e, 0x18, 0x8d, 0x7c, 0x2c, 0xe3, 0x2c, 0x5d, 0xc1, 0x2c, 0x5f,
+ 0xd2, 0xfb, 0xb9, 0x42, 0xc5, 0xa3, 0xa3, 0xc4, 0xec, 0x62, 0xfc, 0x2f,
+ 0x68, 0x52, 0x58, 0xbf, 0xe8, 0xfb, 0x61, 0xa6, 0xc4, 0x96, 0x2d, 0x84,
+ 0x7c, 0x9e, 0x2a, 0xbf, 0x6b, 0xa7, 0x7e, 0x95, 0x10, 0x51, 0x7b, 0xf0,
+ 0x75, 0x8b, 0xff, 0x44, 0xef, 0xed, 0x64, 0xb7, 0x31, 0x62, 0xf4, 0xed,
+ 0xa5, 0x8a, 0x1a, 0x36, 0xb0, 0x99, 0x8d, 0xc8, 0x77, 0x88, 0x57, 0xef,
+ 0xc1, 0xc5, 0xda, 0xc5, 0xee, 0x47, 0x6b, 0x17, 0xde, 0xe4, 0x01, 0x22,
+ 0xf3, 0xea, 0x74, 0x8b, 0xe1, 0x13, 0x9a, 0x91, 0x7f, 0x9a, 0x7c, 0xf7,
+ 0x20, 0x09, 0x14, 0x91, 0x7f, 0x67, 0x51, 0xf8, 0x3a, 0x45, 0xc6, 0x18,
+ 0x91, 0x7f, 0x14, 0x14, 0xed, 0xa4, 0x8a, 0xc4, 0xc6, 0x7a, 0x23, 0x38,
+ 0xf7, 0xc8, 0xc0, 0x68, 0x41, 0x86, 0x17, 0x06, 0x35, 0x6d, 0x24, 0x6c,
+ 0x9f, 0x9d, 0xe9, 0x37, 0xd6, 0x29, 0x62, 0xbb, 0x4f, 0xe5, 0xa3, 0xaa,
+ 0x72, 0x60, 0xc7, 0x6a, 0x4a, 0xab, 0xa6, 0x47, 0xfc, 0xa2, 0x3b, 0xff,
+ 0xe3, 0x38, 0x59, 0xdf, 0x9c, 0xa7, 0xce, 0xfc, 0xb1, 0x7f, 0x6f, 0xda,
+ 0xf2, 0x96, 0x2c, 0x54, 0x22, 0x17, 0x14, 0xef, 0xff, 0xc5, 0x9e, 0x10,
+ 0x0e, 0xf2, 0x0c, 0xfb, 0x8c, 0x6a, 0xc5, 0xcf, 0xa5, 0x8b, 0xf4, 0xf8,
+ 0x38, 0x3a, 0xc5, 0xee, 0xa0, 0xe6, 0x1e, 0x00, 0x62, 0xf6, 0x85, 0x8b,
+ 0x37, 0xcf, 0x1f, 0xc6, 0xd4, 0x34, 0xc2, 0x7d, 0x0e, 0x2a, 0x86, 0x4e,
+ 0x1e, 0x34, 0xb4, 0xa7, 0xcd, 0x28, 0xfd, 0x99, 0xe7, 0x05, 0x4a, 0x17,
+ 0xe2, 0x8c, 0xaa, 0xff, 0xfe, 0x79, 0x78, 0xa3, 0x3b, 0xce, 0xa3, 0xdf,
+ 0x6d, 0xeb, 0x17, 0x38, 0xd6, 0x28, 0xd3, 0xf4, 0x3a, 0xed, 0xff, 0xff,
+ 0x16, 0x7b, 0xd1, 0xdc, 0xb6, 0xfe, 0x0e, 0x2e, 0xf9, 0xf8, 0x58, 0xbf,
+ 0xbe, 0xc6, 0x9b, 0x13, 0xac, 0x5f, 0xd8, 0x5c, 0x62, 0xc5, 0x8b, 0xf8,
+ 0xf8, 0x3f, 0xe4, 0xeb, 0x17, 0xff, 0x89, 0xcd, 0xe0, 0x3d, 0xee, 0xfd,
+ 0x9d, 0x2c, 0x5f, 0xbd, 0xb7, 0xda, 0x85, 0x8a, 0x84, 0x54, 0x1a, 0x5f,
+ 0xda, 0x75, 0xef, 0x88, 0xeb, 0x14, 0x6a, 0x7c, 0x3b, 0xa4, 0x7a, 0x6b,
+ 0xf9, 0x89, 0x43, 0x4c, 0x21, 0x8d, 0xfc, 0x59, 0xcd, 0x47, 0x16, 0x2f,
+ 0x0a, 0x58, 0xb1, 0x4e, 0x79, 0x40, 0x2d, 0xbf, 0x61, 0x3f, 0xb8, 0xb1,
+ 0x7d, 0xf8, 0x29, 0x2c, 0x5f, 0xb3, 0xe4, 0xf3, 0x2c, 0x50, 0xcf, 0xc7,
+ 0x09, 0xc8, 0x8a, 0xa4, 0x8b, 0xfe, 0x42, 0x4a, 0xec, 0xfa, 0xc5, 0xf4,
+ 0xdf, 0x14, 0xeb, 0x16, 0x79, 0x8d, 0xe8, 0x62, 0xf7, 0xbf, 0x13, 0x2c,
+ 0x5f, 0x4a, 0x26, 0x65, 0x8a, 0x19, 0xe0, 0xf6, 0x3d, 0x7f, 0x34, 0x6b,
+ 0x3b, 0xf2, 0xc5, 0xff, 0x43, 0x13, 0xfa, 0x66, 0x31, 0x62, 0xff, 0xd9,
+ 0x86, 0x73, 0xb8, 0x28, 0xe2, 0xc5, 0xb5, 0xb5, 0x33, 0x28, 0x69, 0x39,
+ 0x1f, 0x0b, 0xbc, 0x73, 0x50, 0x9f, 0x4b, 0x47, 0x2f, 0x7f, 0x1d, 0xc7,
+ 0xf8, 0x25, 0x8b, 0xda, 0xcf, 0xac, 0x5f, 0x78, 0x5e, 0xe2, 0xc5, 0xf7,
+ 0x72, 0xcf, 0x2c, 0x56, 0x1e, 0x46, 0x89, 0x2f, 0xf3, 0x3f, 0xb3, 0xa8,
+ 0x02, 0xc5, 0xff, 0xf3, 0xb0, 0x39, 0x86, 0xb9, 0xf5, 0x18, 0x4b, 0x17,
+ 0xba, 0x0c, 0x0b, 0x17, 0xff, 0xf7, 0xb9, 0xfc, 0x08, 0xe4, 0x68, 0xf1,
+ 0xb5, 0xa8, 0x58, 0xa8, 0x3f, 0xd7, 0x20, 0xbe, 0xfc, 0x77, 0xc5, 0x8b,
+ 0xe6, 0xce, 0xfc, 0xb1, 0x58, 0x78, 0xfe, 0x24, 0xbf, 0xff, 0xef, 0xb6,
+ 0xb0, 0x6e, 0x7c, 0x2f, 0x14, 0x19, 0x9e, 0xe2, 0xc5, 0xa1, 0x62, 0xfa,
+ 0x37, 0x8e, 0x3a, 0x3f, 0x60, 0x32, 0xdf, 0xf9, 0xe5, 0xf7, 0xf7, 0x30,
+ 0xa4, 0xb1, 0x5f, 0x3f, 0x9f, 0x1d, 0xd4, 0x95, 0xa5, 0x76, 0x5b, 0xa6,
+ 0x53, 0x90, 0xfc, 0xcc, 0xa1, 0x97, 0xc6, 0x7f, 0x46, 0x21, 0x7f, 0x0f,
+ 0xee, 0x1e, 0x4e, 0xb1, 0x7f, 0xe0, 0x7b, 0x59, 0x3f, 0xa3, 0x38, 0xb1,
+ 0x6c, 0xda, 0x7e, 0x1a, 0x30, 0xb6, 0x2c, 0x5f, 0xff, 0x40, 0x03, 0xcf,
+ 0xf9, 0xbb, 0x33, 0x3b, 0xf2, 0xc5, 0xff, 0xf9, 0xcd, 0x0f, 0xb0, 0x41,
+ 0x74, 0xfe, 0x7e, 0xc0, 0xb1, 0x7b, 0xac, 0x3a, 0xc5, 0xfa, 0x3b, 0x28,
+ 0x35, 0x62, 0xff, 0xfd, 0xd4, 0x0b, 0xaf, 0xc6, 0xbe, 0xe3, 0xfb, 0xe9,
+ 0x62, 0x86, 0x88, 0x1c, 0x29, 0xbf, 0x86, 0xfe, 0xe0, 0xa4, 0xb1, 0x50,
+ 0x8f, 0x0c, 0x84, 0xf8, 0x64, 0x56, 0x91, 0x26, 0xfd, 0xb9, 0x1a, 0x55,
+ 0xfc, 0xfa, 0x8f, 0x36, 0xf5, 0x8b, 0xff, 0xb9, 0x1b, 0x16, 0x49, 0xbd,
+ 0xc1, 0x6e, 0xac, 0x57, 0x68, 0xae, 0x23, 0x2e, 0x17, 0xdf, 0xff, 0xfb,
+ 0x5a, 0x8e, 0xe5, 0xdf, 0x1b, 0x5d, 0x7f, 0x03, 0xd3, 0x40, 0xd6, 0x2f,
+ 0xc4, 0x68, 0x79, 0xda, 0xc5, 0xff, 0x3e, 0xb3, 0xb9, 0x40, 0x21, 0x62,
+ 0xa1, 0x30, 0x5c, 0x30, 0x67, 0x11, 0x15, 0xdf, 0xf7, 0x72, 0xf6, 0x73,
+ 0xd9, 0xba, 0xb1, 0x7f, 0xfe, 0xe8, 0xd7, 0xe6, 0x6a, 0x4d, 0xf7, 0x2e,
+ 0xe4, 0xb1, 0x7f, 0xd1, 0xee, 0x67, 0x9b, 0xb3, 0x16, 0x2f, 0x0b, 0x46,
+ 0xac, 0x57, 0x47, 0xb5, 0xb8, 0x77, 0x58, 0x8d, 0x83, 0x61, 0x65, 0x50,
+ 0x99, 0xf3, 0xc6, 0x2d, 0x50, 0xbc, 0x9c, 0x38, 0x77, 0x74, 0x52, 0xc2,
+ 0x3f, 0x97, 0x0a, 0x51, 0xbc, 0xdf, 0xbd, 0x87, 0x79, 0x2c, 0x5f, 0x10,
+ 0xb7, 0xc9, 0x62, 0xa4, 0x79, 0xbc, 0x28, 0xbf, 0x61, 0x7f, 0x09, 0x62,
+ 0xf4, 0xe1, 0xf4, 0xb1, 0x7c, 0x4d, 0x36, 0xea, 0xc5, 0x42, 0x23, 0xfe,
+ 0x44, 0xe4, 0xdc, 0x21, 0xb9, 0xc0, 0xb1, 0x52, 0x3d, 0x2f, 0x1d, 0xdf,
+ 0xff, 0xfc, 0x2f, 0x73, 0x9e, 0x6c, 0x98, 0xf1, 0xc9, 0x8b, 0x0e, 0x68,
+ 0xa1, 0x62, 0xff, 0xa5, 0x9e, 0x3c, 0x61, 0x0d, 0x62, 0xfd, 0xd7, 0xf3,
+ 0xb0, 0x8b, 0x17, 0xff, 0xe7, 0x79, 0x3f, 0xf6, 0xe4, 0xe2, 0xf0, 0x9c,
+ 0x35, 0x45, 0xf6, 0x5e, 0xde, 0x2f, 0x2c, 0x5d, 0x03, 0x58, 0xa8, 0x36,
+ 0xe0, 0x20, 0xbf, 0x9f, 0xa8, 0x28, 0x02, 0xc5, 0xff, 0x44, 0x0d, 0xba,
+ 0x62, 0x9d, 0x62, 0xff, 0x98, 0xbb, 0x96, 0x85, 0x1c, 0x58, 0xbb, 0x02,
+ 0x2c, 0x57, 0x0f, 0x4c, 0xc3, 0xab, 0xf6, 0x6b, 0x07, 0x0b, 0x17, 0xe0,
+ 0x99, 0x84, 0x05, 0x8a, 0x1a, 0xac, 0x3e, 0xdd, 0x77, 0x4e, 0x26, 0x2d,
+ 0xd4, 0x27, 0x7e, 0x40, 0x45, 0xbe, 0x84, 0x66, 0xf2, 0x30, 0x84, 0xf7,
+ 0xef, 0xe4, 0xd1, 0xba, 0xb1, 0x7e, 0x1e, 0xb5, 0x86, 0x2c, 0x5f, 0xfb,
+ 0xd9, 0xf8, 0xd0, 0x09, 0xcd, 0x58, 0xbe, 0x0b, 0xbe, 0x71, 0x62, 0xa7,
+ 0x45, 0xd9, 0x16, 0x70, 0xa8, 0x47, 0xf7, 0xf3, 0x16, 0x7a, 0x26, 0x58,
+ 0xbf, 0xdf, 0x81, 0x77, 0x26, 0xdc, 0x58, 0xbf, 0xfa, 0x5c, 0x83, 0xe7,
+ 0x44, 0xf9, 0xd2, 0xc5, 0xf4, 0x11, 0xa3, 0x58, 0xbf, 0xfe, 0x72, 0x9c,
+ 0xb3, 0xbe, 0x3e, 0x7b, 0x0e, 0xb1, 0x79, 0xc1, 0x0b, 0x17, 0xff, 0x86,
+ 0xc7, 0xee, 0x5c, 0x2c, 0xd0, 0x7e, 0x58, 0xbd, 0xa7, 0x99, 0x62, 0xa1,
+ 0x3e, 0x09, 0x1e, 0xf4, 0x5b, 0xd9, 0xc7, 0xd1, 0x5c, 0x8f, 0x89, 0xfe,
+ 0x1c, 0x12, 0x6d, 0xd2, 0xe2, 0xc5, 0xfa, 0x4d, 0xd3, 0xe9, 0x62, 0xff,
+ 0xe6, 0xe9, 0x86, 0x59, 0xee, 0x41, 0xd6, 0x2f, 0xff, 0x39, 0x67, 0xa1,
+ 0xb4, 0xc6, 0x9b, 0x0b, 0x15, 0xc4, 0x5b, 0x78, 0xa4, 0x34, 0x4b, 0x8f,
+ 0x8b, 0x16, 0xe9, 0x62, 0xff, 0xfe, 0x6d, 0x1b, 0xf8, 0x3c, 0xd2, 0x62,
+ 0xfc, 0x6a, 0x16, 0x2c, 0x4b, 0x14, 0x03, 0xed, 0x12, 0xe5, 0x62, 0x28,
+ 0xb9, 0x08, 0x0a, 0x3a, 0x38, 0x3d, 0x0b, 0x9b, 0xcd, 0xac, 0x58, 0xbc,
+ 0x59, 0x25, 0x8a, 0xe8, 0xdc, 0x78, 0x72, 0xe8, 0x3a, 0xc5, 0xe2, 0x83,
+ 0xac, 0x5f, 0x9c, 0x71, 0x84, 0xb1, 0x50, 0x8d, 0xb6, 0x60, 0x22, 0x2e,
+ 0x0b, 0x88, 0x72, 0xff, 0x9a, 0x5e, 0xfe, 0x69, 0xb8, 0xb1, 0x7f, 0xfe,
+ 0x96, 0x10, 0xff, 0x18, 0x50, 0x03, 0xbc, 0x96, 0x28, 0x91, 0x18, 0x19,
+ 0xcd, 0xfd, 0xdc, 0xbc, 0xde, 0xe2, 0xc5, 0xf8, 0x3f, 0xbc, 0xf8, 0xb1,
+ 0x66, 0x34, 0xf6, 0x88, 0xc2, 0xff, 0x67, 0xfb, 0x97, 0xa0, 0xeb, 0x17,
+ 0xe9, 0x16, 0x64, 0xeb, 0x17, 0x6a, 0x75, 0x8b, 0xfe, 0x98, 0x2b, 0xe6,
+ 0x18, 0xf0, 0x96, 0x2a, 0x0f, 0xff, 0x0a, 0x18, 0x66, 0xff, 0x38, 0xe0,
+ 0x10, 0x67, 0x16, 0x28, 0x69, 0x9d, 0xe1, 0x3f, 0xe1, 0x68, 0xe5, 0x97,
+ 0xde, 0x97, 0x8d, 0x58, 0xbf, 0xb7, 0x02, 0xd6, 0xdd, 0xbf, 0xdc, 0x5c,
+ 0x40, 0x25, 0xfe, 0xf0, 0x03, 0x29, 0x7f, 0x17, 0x10, 0x09, 0x79, 0xf5,
+ 0x25, 0xc4, 0x02, 0x56, 0x1f, 0x60, 0x90, 0xae, 0x79, 0x2e, 0x20, 0x12,
+ 0xf9, 0xcb, 0xb9, 0x2e, 0x20, 0x12, 0xff, 0x37, 0x5f, 0xc0, 0x02, 0x17,
+ 0x10, 0x09, 0x79, 0x88, 0x6b, 0x88, 0x04, 0xa1, 0xa2, 0xf8, 0xe4, 0x9f,
+ 0x30, 0xde, 0x83, 0x63, 0x57, 0x10, 0x09, 0x7b, 0x51, 0xe5, 0xc4, 0x02,
+ 0x52, 0xe2, 0x01, 0x2f, 0x6e, 0x30, 0x17, 0x10, 0x09, 0x74, 0x1d, 0x71,
+ 0x00, 0xc1, 0x43, 0x3e, 0xec, 0x19, 0x62, 0xdb, 0xe6, 0x38, 0xe1, 0x71,
+ 0x00, 0x97, 0xbc, 0xfd, 0x2e, 0x20, 0x12, 0xff, 0xc4, 0xf2, 0xd9, 0xfb,
+ 0x74, 0xfa, 0x5c, 0x40, 0x25, 0xff, 0xcf, 0xe1, 0x4e, 0xc5, 0xef, 0xbc,
+ 0x97, 0x10, 0x09, 0x73, 0x8d, 0x71, 0x00, 0x97, 0xf8, 0x9c, 0xce, 0x72,
+ 0x00, 0xb8, 0x80, 0x4b, 0xf3, 0x1a, 0xe4, 0x05, 0xc4, 0x02, 0x5c, 0xdc,
+ 0x5c, 0x40, 0x25, 0x68, 0xf6, 0x7c, 0x6b, 0x7f, 0xfb, 0xed, 0xef, 0x67,
+ 0x36, 0xe9, 0xa0, 0xeb, 0x88, 0x04, 0xbf, 0x78, 0xa3, 0xb9, 0x2a, 0x20,
+ 0x12, 0xe0, 0x42, 0xe2, 0x01, 0x36, 0x4d, 0xb5, 0x2e, 0x20, 0x12, 0xfa,
+ 0x0e, 0xe3, 0x5c, 0x40, 0x25, 0x0c, 0xf2, 0x18, 0x66, 0xf8, 0x4e, 0x5d,
+ 0x2e, 0x20, 0x12, 0xf4, 0x6b, 0xa5, 0xc4, 0x02, 0x5f, 0xfb, 0x3b, 0xe0,
+ 0xe3, 0x08, 0x1c, 0x5c, 0x40, 0x25, 0xf1, 0xc3, 0x80, 0x2e, 0x20, 0x12,
+ 0xf9, 0xe5, 0x28, 0x5c, 0x40, 0x25, 0x61, 0xf0, 0x08, 0xc6, 0xfc, 0xfd,
+ 0x7e, 0x3b, 0x5c, 0x40, 0x25, 0x62, 0x60, 0x9f, 0x85, 0x60, 0x88, 0x6e,
+ 0xd0, 0x17, 0x10, 0x09, 0x52, 0x57, 0x90, 0x32, 0x4c, 0x84, 0xd7, 0x44,
+ 0x4d, 0x08, 0xff, 0xbf, 0x80, 0x87, 0x86, 0x1e, 0x8c, 0xbc, 0x46, 0xb7,
+ 0xec, 0xf7, 0x1f, 0xb5, 0xc4, 0x02, 0x5f, 0xe1, 0xc7, 0x53, 0x6a, 0x3c,
+ 0xb8, 0x80, 0x41, 0x9b, 0x6b, 0xda, 0x83, 0x17, 0x10, 0x09, 0x5d, 0x1f,
+ 0xf6, 0x94, 0xef, 0xf0, 0x9e, 0x52, 0x80, 0xce, 0xb8, 0x80, 0x4b, 0xe6,
+ 0x29, 0x71, 0x71, 0x00, 0x97, 0xf3, 0xcd, 0x2c, 0xee, 0x4b, 0x88, 0x04,
+ 0xac, 0x46, 0x8f, 0xc8, 0xc0, 0x84, 0x22, 0xfb, 0xfe, 0xfc, 0x73, 0x67,
+ 0x82, 0xd0, 0x17, 0x10, 0x0c, 0x16, 0x65, 0xc4, 0x02, 0x5c, 0xf3, 0x8c,
+ 0xfb, 0x7e, 0x9f, 0x76, 0x80, 0xb8, 0x80, 0x4b, 0xf3, 0xfb, 0x8d, 0xda,
+ 0xe2, 0x01, 0x2f, 0xe6, 0x21, 0x4b, 0x38, 0xb8, 0x80, 0x4a, 0x84, 0x4a,
+ 0x91, 0x2f, 0x8d, 0xaa, 0x19, 0x67, 0x43, 0x85, 0xce, 0x43, 0x7d, 0x8f,
+ 0xe6, 0x20, 0xd4, 0x26, 0x3e, 0x5a, 0xe5, 0xe0, 0x2b, 0x24, 0xfe, 0x4e,
+ 0x0d, 0x7a, 0x51, 0x0e, 0xe4, 0x2a, 0x43, 0x86, 0x1d, 0xef, 0x31, 0x8b,
+ 0x8c, 0x24, 0xbc, 0xef, 0xd2, 0xa2, 0x01, 0x36, 0x53, 0x16, 0xee, 0x1d,
+ 0x77, 0xa0, 0xce, 0x2c, 0x5b, 0xcb, 0x17, 0x8b, 0x3a, 0xe8, 0xd8, 0x30,
+ 0xf5, 0xc3, 0x3a, 0xc5, 0xff, 0xbf, 0x9d, 0x41, 0xf9, 0x3c, 0xa7, 0x58,
+ 0xbf, 0xc7, 0xd6, 0x4b, 0xf1, 0x25, 0x8b, 0x88, 0x1e, 0x3f, 0x70, 0xd0,
+ 0xef, 0xf0, 0xbd, 0x9c, 0xf6, 0x74, 0xb1, 0x5b, 0x09, 0x1e, 0x4f, 0x08,
+ 0xf0, 0x17, 0x5f, 0xde, 0x2c, 0x06, 0xe6, 0x2c, 0x50, 0xd3, 0x8e, 0x36,
+ 0x32, 0x43, 0x9d, 0x5f, 0xe9, 0x37, 0x8d, 0x37, 0x37, 0x56, 0x2f, 0xa3,
+ 0xd0, 0x35, 0x8b, 0x4e, 0xb1, 0x52, 0x36, 0xbb, 0xc8, 0xaf, 0xe9, 0xe3,
+ 0x5f, 0x7d, 0xd5, 0x8b, 0xfe, 0xe1, 0x41, 0xf9, 0xd4, 0x71, 0x62, 0xdc,
+ 0x58, 0xbf, 0xd9, 0xc2, 0x7e, 0x66, 0xea, 0xc5, 0xe8, 0x1f, 0xd6, 0x2b,
+ 0xe7, 0xa4, 0x46, 0xb5, 0x88, 0xbf, 0xf9, 0xd6, 0xf6, 0x4a, 0x84, 0xd1,
+ 0x70, 0x8d, 0xa1, 0xe3, 0x7f, 0xe2, 0xce, 0xbe, 0xc0, 0x00, 0xa6, 0x58,
+ 0xbe, 0xf3, 0xbe, 0x96, 0x2f, 0xf8, 0x78, 0x69, 0x67, 0xa0, 0xc5, 0x8b,
+ 0xfb, 0x35, 0x92, 0x94, 0x2c, 0x54, 0x91, 0x95, 0xda, 0x08, 0x08, 0x88,
+ 0xea, 0xf0, 0xdf, 0xeb, 0x17, 0xec, 0x9b, 0x91, 0x3a, 0xc5, 0xbd, 0x87,
+ 0x8f, 0xe1, 0xdb, 0x81, 0x09, 0x16, 0x35, 0x22, 0xf7, 0xe2, 0x75, 0x8b,
+ 0x8c, 0x31, 0x22, 0x98, 0xf8, 0xb7, 0x45, 0xe6, 0x13, 0x30, 0x7a, 0xdc,
+ 0x48, 0xd9, 0x3c, 0x0a, 0xc4, 0x77, 0xb4, 0x32, 0x6f, 0xfe, 0xc0, 0x49,
+ 0xbd, 0x07, 0x82, 0x1a, 0xc5, 0x1c, 0xfa, 0x5c, 0x9a, 0xfe, 0xc1, 0xfe,
+ 0x08, 0x6b, 0x17, 0xf7, 0xb9, 0x86, 0x7d, 0x96, 0x2d, 0xe5, 0x8a, 0xf1,
+ 0xe0, 0x88, 0xbe, 0xff, 0x67, 0x5b, 0x70, 0xf1, 0xd2, 0xc5, 0xfa, 0x27,
+ 0xe1, 0xe4, 0xb1, 0x4c, 0x88, 0x3f, 0x91, 0x78, 0xde, 0xff, 0xfd, 0xdc,
+ 0xb8, 0x5d, 0xc1, 0xbc, 0x8e, 0xe4, 0xc7, 0x58, 0xbf, 0xe3, 0x5b, 0x41,
+ 0x80, 0x11, 0xda, 0xc5, 0xf4, 0xbd, 0x06, 0x2c, 0x5d, 0xee, 0x61, 0xf0,
+ 0xf6, 0x7b, 0x5b, 0x13, 0x75, 0xf5, 0x10, 0xce, 0x9e, 0x3e, 0xc9, 0x43,
+ 0x4c, 0x71, 0xdc, 0x62, 0x0f, 0x54, 0xc7, 0x56, 0x94, 0x23, 0x31, 0xc6,
+ 0xa3, 0xb3, 0x78, 0x7e, 0x82, 0x3d, 0xc2, 0x21, 0xf4, 0x3c, 0x44, 0x5e,
+ 0x1c, 0x2e, 0xef, 0xf4, 0x98, 0x6f, 0xd7, 0x24, 0xb1, 0x77, 0x19, 0x62,
+ 0xb0, 0xf3, 0x3c, 0x6b, 0x7f, 0x98, 0xba, 0x6d, 0x30, 0x16, 0x2f, 0x66,
+ 0x01, 0x62, 0x8e, 0x79, 0xe4, 0x67, 0x5d, 0x22, 0x47, 0xee, 0x16, 0x85,
+ 0x8b, 0xef, 0x89, 0xc9, 0x62, 0xde, 0xda, 0x6c, 0xc6, 0x23, 0x7b, 0xaf,
+ 0x92, 0xc5, 0xff, 0xde, 0xdc, 0xc9, 0xa4, 0xfa, 0x9c, 0x70, 0xb1, 0x5d,
+ 0xa2, 0x44, 0xe5, 0x24, 0x3d, 0x7c, 0x37, 0x07, 0x16, 0x2f, 0xf6, 0xd6,
+ 0xce, 0x7f, 0x3c, 0xb1, 0x58, 0x7b, 0x1c, 0x23, 0xbf, 0xf9, 0xe5, 0xb4,
+ 0x9a, 0x36, 0xb1, 0xf1, 0x62, 0xee, 0xc0, 0xb1, 0x60, 0x1c, 0xf7, 0xc0,
+ 0x8d, 0x7a, 0x68, 0x31, 0x62, 0xff, 0xf7, 0xdb, 0x7b, 0x75, 0xa8, 0x9d,
+ 0xf5, 0xd2, 0xc5, 0xfd, 0x1d, 0xc1, 0x3f, 0x96, 0x2e, 0x20, 0x2c, 0x5d,
+ 0x1c, 0x58, 0xa6, 0x35, 0xdb, 0xc5, 0xeb, 0xe7, 0xfb, 0xbd, 0x6e, 0xa1,
+ 0x30, 0xfe, 0x87, 0xc3, 0x86, 0x65, 0x69, 0x3e, 0xe2, 0x84, 0x07, 0xa3,
+ 0x37, 0xbf, 0xff, 0xdf, 0x62, 0x1e, 0x1f, 0xd1, 0x98, 0x71, 0xc6, 0x12,
+ 0xc5, 0xfe, 0xce, 0xfd, 0xe7, 0x97, 0x16, 0x2f, 0xf9, 0xfb, 0xda, 0x27,
+ 0x0d, 0xa7, 0x58, 0xbf, 0xc1, 0xc1, 0x9a, 0x8c, 0x25, 0x8b, 0x82, 0xf2,
+ 0x58, 0xbf, 0x39, 0xa5, 0x93, 0x2c, 0x54, 0x8f, 0x14, 0x87, 0x2e, 0xee,
+ 0x4b, 0x8c, 0x00, 0xbf, 0xfd, 0x86, 0x47, 0xb2, 0x69, 0x37, 0xb8, 0xeb,
+ 0x15, 0x24, 0xc2, 0xfb, 0x79, 0x22, 0x1e, 0x13, 0x5c, 0x09, 0x2c, 0x5f,
+ 0xf8, 0x9f, 0xc2, 0xf0, 0xfe, 0xc6, 0xac, 0x5e, 0x8c, 0xf9, 0x1e, 0xc7,
+ 0x06, 0x2f, 0xf9, 0xbb, 0xe7, 0x8a, 0x0f, 0xc5, 0x8b, 0xff, 0xff, 0xff,
+ 0xf8, 0x5b, 0xa4, 0xf9, 0xf7, 0x0c, 0xb3, 0x7e, 0x13, 0x9b, 0x34, 0x85,
+ 0xce, 0x18, 0xe3, 0xfb, 0x19, 0xcc, 0x71, 0xac, 0x51, 0xa8, 0xf7, 0xe1,
+ 0xd5, 0xfe, 0xe6, 0x13, 0xef, 0x7f, 0xac, 0x5f, 0xcf, 0xf9, 0x9d, 0xa7,
+ 0x58, 0xa8, 0x5f, 0xb9, 0xc8, 0x74, 0x34, 0xa7, 0x69, 0x8e, 0xf4, 0xba,
+ 0x73, 0x57, 0x8d, 0x24, 0xa1, 0x2d, 0xe8, 0xca, 0x04, 0x48, 0x61, 0xa5,
+ 0xff, 0xf8, 0x88, 0x5d, 0xe7, 0x7e, 0x1e, 0x9f, 0xbc, 0x9d, 0x62, 0xfd,
+ 0x9e, 0xd4, 0x71, 0x62, 0x99, 0x10, 0x24, 0xb3, 0x78, 0x11, 0x25, 0x8b,
+ 0xf8, 0x9f, 0xb8, 0x69, 0x96, 0x2d, 0x3a, 0xc5, 0x2c, 0x5e, 0x9a, 0x51,
+ 0xa2, 0xfc, 0x02, 0x77, 0xd0, 0x6c, 0x1d, 0x62, 0xa4, 0x8e, 0x0e, 0xc8,
+ 0x58, 0x77, 0x49, 0xa7, 0x32, 0xbf, 0x8b, 0x0f, 0x1a, 0x35, 0x62, 0xfd,
+ 0xe6, 0xdf, 0xf6, 0x58, 0xba, 0x5c, 0xda, 0x7b, 0x18, 0x5d, 0x7f, 0xff,
+ 0x1c, 0x3c, 0xfb, 0x9f, 0x0e, 0xde, 0xc3, 0x5b, 0x4b, 0x17, 0xfa, 0x0f,
+ 0x81, 0x3c, 0xc6, 0x2c, 0x54, 0x22, 0x4b, 0x8b, 0x97, 0xff, 0xd9, 0xa9,
+ 0x8a, 0x01, 0xce, 0xbe, 0xda, 0x9d, 0x62, 0xa4, 0x7e, 0xbc, 0x22, 0xbf,
+ 0x6d, 0xdb, 0x9f, 0x75, 0x8b, 0xfe, 0xef, 0x8d, 0xdc, 0xbe, 0xdf, 0x58,
+ 0xbf, 0xef, 0xbb, 0x7a, 0x5f, 0x11, 0xab, 0x17, 0x9f, 0xfc, 0x58, 0xa7,
+ 0x44, 0xa7, 0x0f, 0x0c, 0x3b, 0xbf, 0xa5, 0x1a, 0x00, 0x67, 0x58, 0xbe,
+ 0x9b, 0xed, 0x32, 0xc5, 0xff, 0x8d, 0x35, 0x8b, 0xad, 0xb3, 0xfc, 0xd5,
+ 0x8a, 0xc3, 0xec, 0x62, 0x5b, 0xff, 0xff, 0xdf, 0x6f, 0x46, 0x9d, 0x86,
+ 0x28, 0xe4, 0x68, 0x52, 0x6d, 0x60, 0x16, 0x2f, 0xfe, 0xde, 0x59, 0xcf,
+ 0x61, 0x4b, 0x38, 0xb1, 0x7c, 0x78, 0x17, 0x96, 0x2b, 0x0f, 0xa1, 0xd1,
+ 0x6f, 0xa5, 0xa6, 0x3a, 0xc5, 0xef, 0x08, 0xd5, 0x8b, 0x13, 0x9e, 0x10,
+ 0x88, 0xef, 0xbd, 0xe7, 0xd2, 0xc5, 0xfb, 0x26, 0xfc, 0x4e, 0xb1, 0x58,
+ 0x7e, 0x6e, 0x4c, 0x44, 0x77, 0xfe, 0x27, 0xf7, 0x1b, 0xb2, 0x83, 0x16,
+ 0x2f, 0x79, 0xc9, 0x62, 0xcf, 0xb5, 0x59, 0x36, 0x18, 0x7e, 0x13, 0x8e,
+ 0x40, 0x50, 0xde, 0xe4, 0x35, 0x43, 0x2c, 0x08, 0x7f, 0x7f, 0x9c, 0x0e,
+ 0x1c, 0xcf, 0xe5, 0x8a, 0xda, 0xb9, 0x49, 0xf9, 0x7c, 0xc0, 0x84, 0x4d,
+ 0xff, 0x46, 0xe8, 0xff, 0x13, 0xb9, 0x2c, 0x5f, 0xff, 0x41, 0xc3, 0x2f,
+ 0x7c, 0x4f, 0x2f, 0x8b, 0x8b, 0x17, 0xf7, 0x3d, 0xdc, 0xa0, 0x35, 0x8b,
+ 0xfd, 0xd1, 0x66, 0xff, 0xbc, 0x96, 0x2f, 0x1c, 0x0c, 0xb1, 0x7d, 0x1d,
+ 0x41, 0xf6, 0xa2, 0x13, 0x0c, 0x58, 0xda, 0xbb, 0x5e, 0x60, 0xd4, 0xe6,
+ 0x37, 0xd0, 0x48, 0xf0, 0x24, 0x35, 0xaf, 0xe0, 0xcc, 0xd3, 0x67, 0xd2,
+ 0x2f, 0xf3, 0xfa, 0x24, 0x21, 0xe2, 0xc5, 0xf7, 0xe3, 0x27, 0x58, 0xa2,
+ 0x3d, 0x6e, 0x19, 0xdf, 0x71, 0xa0, 0x0b, 0x17, 0xfd, 0xe8, 0xef, 0xd8,
+ 0x78, 0xfa, 0xc5, 0xf4, 0xd9, 0x86, 0x2c, 0x5f, 0x49, 0xb5, 0xc5, 0x8b,
+ 0xff, 0x83, 0x3e, 0x7a, 0x37, 0xb7, 0xa5, 0x0b, 0x17, 0xcd, 0xe8, 0xd2,
+ 0xc5, 0xff, 0x36, 0x77, 0xe9, 0xa4, 0xfa, 0x58, 0xb0, 0x19, 0x14, 0x9f,
+ 0x47, 0x22, 0x2b, 0xff, 0x48, 0xa0, 0xff, 0x8e, 0x9f, 0x4b, 0x17, 0x36,
+ 0x2c, 0x57, 0x67, 0xaa, 0x03, 0xfb, 0xe9, 0xbe, 0xf3, 0x2c, 0x5f, 0x74,
+ 0xfa, 0x9d, 0x62, 0xf4, 0xcf, 0xe5, 0x8b, 0xf6, 0x4d, 0x28, 0xed, 0x62,
+ 0xff, 0xbf, 0x1c, 0xfb, 0xf2, 0x37, 0x56, 0x2e, 0x69, 0x96, 0x2f, 0x34,
+ 0x12, 0xc5, 0xfb, 0x34, 0x3f, 0xe2, 0xc5, 0x0c, 0xf0, 0xf8, 0x37, 0x5f,
+ 0x3f, 0xde, 0x2d, 0xde, 0x72, 0x02, 0xc5, 0xfd, 0xfc, 0xf7, 0x30, 0xc5,
+ 0x8b, 0xc5, 0x12, 0x48, 0xbf, 0xf1, 0x01, 0x82, 0x04, 0x14, 0xa3, 0x75,
+ 0x62, 0xc7, 0x58, 0xad, 0xa8, 0xbf, 0x18, 0xe6, 0x17, 0xb8, 0xe0, 0x68,
+ 0xd5, 0xb5, 0x72, 0x2e, 0x08, 0x67, 0x22, 0x19, 0xd6, 0x12, 0x77, 0x0c,
+ 0x76, 0x84, 0x4e, 0x88, 0xfe, 0x4a, 0xe4, 0xa4, 0x3d, 0xc2, 0xaf, 0x42,
+ 0xe4, 0x24, 0x38, 0x6f, 0xf4, 0x6e, 0xe6, 0xb5, 0x13, 0xac, 0x54, 0x33,
+ 0xac, 0xf2, 0x14, 0x4d, 0x3f, 0x2d, 0xf5, 0xc7, 0x9d, 0x11, 0x14, 0x35,
+ 0xef, 0xdc, 0xd6, 0xa3, 0xcb, 0x17, 0xfb, 0x3e, 0xf8, 0x00, 0xfc, 0xb1,
+ 0x7b, 0xcd, 0x3a, 0xc5, 0x76, 0x7f, 0x7b, 0xa5, 0x27, 0x34, 0xbd, 0xa7,
+ 0xe9, 0x62, 0xfd, 0x1a, 0xce, 0xfc, 0xb1, 0x6e, 0x1a, 0x78, 0xff, 0x1e,
+ 0xbf, 0xd3, 0x16, 0x0f, 0xf1, 0xc5, 0x8b, 0xff, 0xb0, 0x00, 0x7e, 0xf9,
+ 0xc8, 0x2e, 0x96, 0x2d, 0x25, 0x8a, 0x23, 0xd8, 0xe2, 0x35, 0x49, 0x1a,
+ 0xdf, 0x29, 0xdf, 0x08, 0xcb, 0xc5, 0xee, 0x2c, 0x5f, 0xfd, 0x9e, 0x0a,
+ 0x6c, 0x61, 0x46, 0xef, 0x82, 0xe2, 0xc5, 0xfe, 0xeb, 0xec, 0x38, 0x2f,
+ 0x2c, 0x5c, 0xd2, 0x58, 0xae, 0xcf, 0x2c, 0x8d, 0x2e, 0x20, 0x2c, 0x5f,
+ 0xb5, 0xf7, 0x73, 0xac, 0x5f, 0x08, 0x85, 0xd2, 0xc5, 0x39, 0xe6, 0x70,
+ 0xa2, 0xfe, 0xf4, 0xd2, 0xce, 0xe4, 0xb1, 0x50, 0x9e, 0x53, 0x1b, 0x9c,
+ 0x75, 0xe1, 0x3f, 0xe2, 0x21, 0x31, 0x86, 0x43, 0x7f, 0xc1, 0xe6, 0x0b,
+ 0xf9, 0xbe, 0x16, 0x2f, 0xfc, 0x64, 0x6b, 0x98, 0x63, 0xe8, 0xd5, 0x8b,
+ 0xba, 0x75, 0x8b, 0xd9, 0xc1, 0x2c, 0x5f, 0xff, 0xbf, 0x9d, 0x10, 0x86,
+ 0x50, 0x1e, 0x9a, 0x09, 0x62, 0xb1, 0x30, 0x7f, 0x9d, 0xba, 0x11, 0x0c,
+ 0x78, 0x76, 0xff, 0x19, 0x9d, 0xfb, 0xd0, 0x75, 0x8b, 0xf1, 0x60, 0x05,
+ 0xc5, 0x8b, 0xfe, 0xe9, 0xb0, 0xb3, 0x7b, 0xf1, 0x62, 0xa7, 0x3e, 0x2f,
+ 0x94, 0x53, 0xa2, 0xef, 0x90, 0x98, 0xbe, 0x18, 0xf0, 0xeb, 0x17, 0x02,
+ 0x12, 0x2e, 0x30, 0xc4, 0x8a, 0x63, 0x62, 0x60, 0xbd, 0xf8, 0x62, 0x7d,
+ 0x49, 0x23, 0x64, 0xd0, 0xd6, 0x22, 0xc4, 0xd7, 0x5b, 0xff, 0xde, 0xef,
+ 0xa6, 0xfe, 0xe4, 0x7b, 0xe1, 0xf1, 0x62, 0xff, 0x1d, 0xe5, 0x3e, 0x85,
+ 0x3a, 0xc5, 0xb6, 0x1a, 0xc5, 0xfe, 0x89, 0x37, 0xa5, 0x1e, 0x58, 0xb8,
+ 0x2f, 0xc5, 0x80, 0xb7, 0x3c, 0xbd, 0x0c, 0x5f, 0xf7, 0xdf, 0xdc, 0xe8,
+ 0xb2, 0x75, 0x8b, 0xc7, 0x11, 0xab, 0x17, 0xb6, 0x16, 0xc5, 0xb1, 0x2c,
+ 0x5f, 0xfb, 0x44, 0xe6, 0x37, 0xb4, 0x23, 0xac, 0x5d, 0xd3, 0x2c, 0x5f,
+ 0xfa, 0x37, 0x45, 0xac, 0xd6, 0xa3, 0xb5, 0x8b, 0xe2, 0x6e, 0xe4, 0xb1,
+ 0x7f, 0xcd, 0xdf, 0xf0, 0x7a, 0x7e, 0x96, 0x2a, 0x0f, 0x7b, 0x44, 0x77,
+ 0xd9, 0xbf, 0x09, 0x62, 0xf4, 0xb0, 0x6b, 0x17, 0xfb, 0x98, 0xde, 0x35,
+ 0xbe, 0xb1, 0x7f, 0xdf, 0x8d, 0x47, 0x4c, 0x5d, 0x2c, 0x5e, 0x35, 0xf9,
+ 0xb0, 0x93, 0xf6, 0x19, 0x77, 0x48, 0x1d, 0x8c, 0x6a, 0x14, 0x3f, 0x21,
+ 0x72, 0x3f, 0x0e, 0x84, 0x34, 0xbe, 0xf7, 0xa3, 0x4b, 0x15, 0x8a, 0xc4,
+ 0x98, 0xef, 0xd2, 0x85, 0x43, 0x84, 0xfd, 0x49, 0x79, 0xbf, 0xb8, 0xc0,
+ 0xf5, 0x0d, 0x83, 0x91, 0x81, 0x48, 0x50, 0x82, 0x32, 0x5a, 0x9d, 0xfb,
+ 0xed, 0xc1, 0x4e, 0xb1, 0x7f, 0x18, 0x6b, 0xf8, 0xa1, 0x62, 0xf1, 0xc5,
+ 0xa5, 0x8b, 0xdd, 0x37, 0x16, 0x2f, 0x84, 0x7c, 0x1a, 0xc5, 0x76, 0x88,
+ 0xe6, 0x2f, 0xf8, 0xf0, 0x41, 0xeb, 0xff, 0xfb, 0x52, 0x14, 0x67, 0xfa,
+ 0x6e, 0x60, 0xe7, 0xc3, 0x16, 0x2f, 0xfb, 0x02, 0x39, 0x1b, 0x9d, 0xf9,
+ 0x62, 0xfd, 0xa1, 0xfd, 0xa6, 0x58, 0xaf, 0x9f, 0x30, 0x67, 0x97, 0xc2,
+ 0x82, 0x35, 0x62, 0xfe, 0xfb, 0x0f, 0xe2, 0x35, 0x62, 0xfc, 0x51, 0x33,
+ 0x76, 0xb1, 0x6c, 0x19, 0xfe, 0x74, 0x46, 0xc6, 0x17, 0xbd, 0x9d, 0x2c,
+ 0x51, 0xcf, 0x4b, 0x86, 0x97, 0xa4, 0x70, 0x2c, 0x5f, 0xbc, 0x59, 0xa8,
+ 0x58, 0xa8, 0x54, 0x38, 0x6c, 0x31, 0x01, 0x0f, 0x1f, 0x11, 0x18, 0x3d,
+ 0x78, 0x98, 0xd5, 0x8b, 0xff, 0x07, 0xc8, 0xce, 0x6b, 0x4d, 0xe5, 0x8a,
+ 0xc3, 0xdd, 0xe0, 0xed, 0xff, 0x1a, 0xfb, 0x60, 0xe4, 0xc6, 0xac, 0x5f,
+ 0xf9, 0xf8, 0x78, 0x6d, 0x69, 0x8c, 0x58, 0xbf, 0x4f, 0x83, 0x83, 0xac,
+ 0x5b, 0x86, 0xa2, 0x93, 0xe7, 0x81, 0x9f, 0xdc, 0xc1, 0x16, 0x2f, 0xff,
+ 0xfe, 0xfc, 0x73, 0x01, 0x1e, 0xe6, 0xb2, 0x78, 0xd7, 0x3f, 0xd3, 0x71,
+ 0x62, 0xfb, 0x5a, 0x71, 0xac, 0x5e, 0x93, 0xe9, 0x62, 0x86, 0x8b, 0x4c,
+ 0x74, 0x72, 0x3b, 0xf8, 0xfa, 0xd3, 0x76, 0x05, 0x8b, 0xef, 0x3f, 0xe6,
+ 0x58, 0xbf, 0x8a, 0x3a, 0xfb, 0x04, 0x58, 0xbc, 0x6c, 0x71, 0x62, 0xff,
+ 0xb3, 0xde, 0x63, 0x7d, 0x9d, 0x2c, 0x5f, 0xd1, 0xdf, 0x33, 0xbf, 0x2c,
+ 0x5d, 0xa8, 0x58, 0xa1, 0x9e, 0x3f, 0x8c, 0x2f, 0xc2, 0x21, 0xec, 0x1b,
+ 0x02, 0xc5, 0xff, 0xf7, 0xb5, 0x19, 0xde, 0xe1, 0x1c, 0x5e, 0x03, 0xac,
+ 0x5f, 0xef, 0x37, 0x4c, 0x38, 0xf2, 0xc5, 0xfb, 0x91, 0xd6, 0x1d, 0x62,
+ 0xa0, 0xf7, 0x78, 0x69, 0x7c, 0xdd, 0xcb, 0x16, 0x2f, 0xf8, 0xd8, 0x29,
+ 0x64, 0xe2, 0x92, 0xc5, 0xff, 0x0f, 0xf1, 0x29, 0xb4, 0x29, 0xd6, 0x2d,
+ 0xcd, 0xaa, 0xad, 0xa0, 0x92, 0x46, 0x03, 0x1e, 0xc8, 0x41, 0x74, 0x45,
+ 0xd9, 0x9e, 0xa1, 0x62, 0x02, 0x1f, 0x11, 0x86, 0x77, 0x52, 0x5d, 0x8b,
+ 0xee, 0x18, 0xba, 0x38, 0x3c, 0x33, 0x5c, 0xbb, 0xd2, 0xb9, 0xaf, 0x9f,
+ 0xbc, 0x1a, 0xc5, 0xfe, 0xfe, 0x4b, 0xcc, 0xdd, 0xac, 0x5f, 0xf7, 0x9a,
+ 0x78, 0xec, 0x1a, 0x85, 0x8b, 0xbf, 0x3a, 0xc5, 0xde, 0x35, 0x62, 0xf7,
+ 0x3d, 0x8b, 0x16, 0xe6, 0xd4, 0x45, 0x74, 0x76, 0x43, 0x21, 0x8c, 0xdf,
+ 0xf4, 0xef, 0x84, 0x29, 0x67, 0x16, 0x2b, 0x0f, 0xff, 0x88, 0xd7, 0xe7,
+ 0x06, 0xe3, 0x1d, 0x62, 0xfe, 0xe9, 0xb8, 0x29, 0x32, 0xc5, 0xe2, 0x17,
+ 0x16, 0x2b, 0xe7, 0x99, 0xbc, 0xbe, 0xed, 0x87, 0xb8, 0xb1, 0x7e, 0x9b,
+ 0x08, 0x58, 0xb1, 0x7f, 0x79, 0xbb, 0x91, 0x46, 0xc4, 0x79, 0x30, 0x43,
+ 0x7f, 0x03, 0x3b, 0xf7, 0xd9, 0x62, 0xb0, 0xfd, 0xd9, 0x22, 0xff, 0x9d,
+ 0xbc, 0xc5, 0xe1, 0x7d, 0x62, 0xf7, 0xdb, 0x7a, 0xc5, 0xc2, 0x97, 0xcf,
+ 0x5c, 0x33, 0x8b, 0xff, 0x9c, 0x7f, 0x6d, 0x66, 0xf8, 0x29, 0x96, 0x2f,
+ 0xfe, 0xe0, 0xb4, 0x58, 0x3f, 0xc1, 0x90, 0xb1, 0x68, 0xda, 0x88, 0xbf,
+ 0x23, 0x5c, 0x3e, 0x96, 0x2e, 0xcd, 0xe3, 0x3c, 0x30, 0x15, 0x5f, 0xe3,
+ 0x7d, 0xdf, 0x4d, 0xae, 0x2c, 0x5f, 0xb3, 0xc0, 0x7f, 0x2c, 0x54, 0x2a,
+ 0xe7, 0x94, 0x39, 0x34, 0xef, 0xf8, 0x7e, 0x88, 0xbf, 0x70, 0xe2, 0xff,
+ 0xfd, 0x1f, 0x7c, 0x28, 0xd1, 0xa3, 0x13, 0xea, 0x4b, 0x15, 0x25, 0xc3,
+ 0x9e, 0x10, 0xfa, 0x5a, 0xf0, 0x46, 0x5a, 0x86, 0xc0, 0x7c, 0x70, 0x80,
+ 0xc8, 0x5c, 0x34, 0xa5, 0xb7, 0x9e, 0x3f, 0x03, 0x5f, 0x88, 0xc5, 0x3a,
+ 0xed, 0x7f, 0xfe, 0xf4, 0x0c, 0x0f, 0xd8, 0x1b, 0xb0, 0xf4, 0xfd, 0xac,
+ 0x5c, 0xc7, 0x58, 0xb9, 0xe4, 0xb1, 0x76, 0xb1, 0x62, 0x98, 0xd7, 0x38,
+ 0xbd, 0xb7, 0x16, 0x2a, 0x11, 0xa7, 0x25, 0xaf, 0xa2, 0xee, 0x0f, 0xdf,
+ 0xc5, 0x2c, 0xe0, 0x67, 0x58, 0xbc, 0x22, 0xf2, 0xc5, 0x61, 0xe6, 0x70,
+ 0xbe, 0xfc, 0x7e, 0x01, 0xdd, 0x62, 0xbc, 0x79, 0x21, 0x90, 0xdf, 0xec,
+ 0x2d, 0xbf, 0xce, 0xcc, 0x58, 0xbf, 0xa3, 0xed, 0xbf, 0x26, 0x58, 0xad,
+ 0x1f, 0x38, 0x0d, 0xef, 0xd3, 0x3b, 0x94, 0xeb, 0x17, 0xf0, 0x81, 0xb7,
+ 0xa3, 0x81, 0x62, 0xd2, 0xc3, 0xdc, 0x22, 0x9b, 0xf1, 0x60, 0x05, 0xc5,
+ 0x8a, 0x9d, 0x51, 0x54, 0xa1, 0xa9, 0x90, 0x8a, 0xed, 0xf8, 0x04, 0xd7,
+ 0xfb, 0xb9, 0x7c, 0x20, 0x48, 0xdd, 0x58, 0xbf, 0xe6, 0xee, 0x53, 0xce,
+ 0x0e, 0xc0, 0xb1, 0x58, 0x7f, 0x9f, 0x3d, 0xbf, 0xf7, 0xf8, 0xd2, 0x6f,
+ 0x47, 0xb8, 0xb1, 0x7f, 0xf8, 0x04, 0x2e, 0x7b, 0x91, 0xac, 0xef, 0xcb,
+ 0x14, 0xe8, 0x8b, 0x23, 0xfb, 0xfd, 0x9b, 0xf3, 0x40, 0x00, 0x96, 0x2f,
+ 0xfe, 0x6d, 0x6d, 0x78, 0x94, 0x10, 0xa4, 0xb1, 0x7d, 0x1a, 0xcd, 0xeb,
+ 0x17, 0xef, 0xb6, 0xe3, 0xce, 0xb1, 0x52, 0x44, 0xaf, 0x11, 0x7c, 0x49,
+ 0x7f, 0x81, 0xcc, 0x2c, 0xe0, 0x96, 0x2b, 0x0f, 0x8d, 0xcc, 0x2d, 0x25,
+ 0x8b, 0xfd, 0x19, 0xdf, 0xb3, 0x50, 0xb1, 0x5a, 0x3c, 0x52, 0x12, 0xbf,
+ 0xf4, 0x7c, 0x3e, 0x16, 0x7b, 0xf8, 0xb1, 0x7f, 0xf7, 0xc5, 0xce, 0x46,
0xba, 0xc0, 0xf1, 0x62, 0xf6, 0x01, 0xd6, 0x2d, 0xbd, 0x8f, 0x8f, 0xe8,
- 0xf7, 0xa4, 0x18, 0xb1, 0x7f, 0xf4, 0x0d, 0x70, 0xfc, 0xda, 0x91, 0x05,
- 0xd6, 0x2b, 0xe7, 0xce, 0xe3, 0x95, 0x88, 0xb1, 0x14, 0x24, 0x2f, 0xff,
- 0xf7, 0xbc, 0xc4, 0x6e, 0xdf, 0x1a, 0x2d, 0x73, 0x8d, 0x9d, 0xac, 0x5f,
- 0xee, 0xc5, 0x1c, 0x94, 0xf6, 0xb1, 0x58, 0x89, 0xd7, 0x67, 0xa9, 0x5c,
- 0xef, 0xc4, 0x96, 0x86, 0x7f, 0xe3, 0x19, 0x76, 0x50, 0x10, 0x94, 0x6a,
- 0x62, 0x86, 0x25, 0xff, 0xf8, 0xd6, 0xf1, 0x64, 0x3b, 0xf1, 0x34, 0x7c,
- 0x12, 0xc5, 0xf6, 0xf1, 0x8e, 0x56, 0x2f, 0xfe, 0xcd, 0x6d, 0xcf, 0xb9,
- 0xa4, 0x2e, 0x2c, 0x53, 0x23, 0x11, 0xd6, 0x04, 0x4b, 0x7f, 0xe3, 0x5f,
- 0xaf, 0xb4, 0x59, 0xdf, 0x96, 0x2f, 0xcf, 0x02, 0xc0, 0x2c, 0x5f, 0xff,
- 0xda, 0x86, 0xd1, 0xfe, 0x76, 0x96, 0x77, 0xe9, 0xc3, 0x16, 0x2e, 0xe7,
- 0x16, 0x2f, 0xd3, 0x9e, 0xe3, 0xac, 0x5f, 0x9d, 0xb8, 0x23, 0x56, 0x2f,
- 0x18, 0x61, 0x8b, 0x17, 0x01, 0xd2, 0x02, 0x1a, 0x1b, 0xfd, 0xa9, 0xdf,
- 0x98, 0x71, 0xac, 0x53, 0x26, 0x91, 0xa6, 0x13, 0x8c, 0x7c, 0x9f, 0x89,
- 0x42, 0x29, 0xbe, 0x83, 0x11, 0xab, 0x17, 0xf8, 0x9c, 0xd8, 0x89, 0xa2,
- 0x58, 0xb6, 0x44, 0x7b, 0x1c, 0x23, 0xbf, 0x81, 0x30, 0xf8, 0x7c, 0x58,
- 0xbf, 0x70, 0x40, 0xc2, 0x58, 0xbf, 0x98, 0x81, 0xd7, 0x4c, 0xb1, 0x79,
- 0xc1, 0x89, 0x15, 0x05, 0x6b, 0x5d, 0x97, 0x69, 0x0c, 0xf1, 0xb7, 0xfe,
- 0x15, 0xe0, 0x28, 0xf1, 0x86, 0xf2, 0x8d, 0x92, 0xfb, 0xe9, 0x1b, 0x0d,
- 0x62, 0xff, 0xfd, 0xae, 0xfd, 0x23, 0xc2, 0x2c, 0x37, 0x08, 0x0b, 0x17,
- 0xf7, 0x3e, 0xdd, 0x3e, 0x96, 0x2f, 0xc3, 0xd3, 0x0a, 0x35, 0x8b, 0xf6,
- 0x7b, 0x8f, 0xda, 0xc5, 0xfe, 0x33, 0x0b, 0x37, 0xb6, 0x96, 0x2f, 0xe2,
- 0xce, 0xc0, 0x1c, 0x16, 0x2e, 0xce, 0x2c, 0x5f, 0x61, 0xdb, 0xcb, 0x17,
- 0xff, 0x67, 0xc3, 0x3e, 0x75, 0x3f, 0x93, 0xac, 0x5b, 0x98, 0x7f, 0xe4,
- 0x2f, 0xe2, 0x2b, 0x71, 0x62, 0xb1, 0x3a, 0xb8, 0x8b, 0xf4, 0x54, 0x45,
- 0x3e, 0x35, 0x14, 0x2b, 0xcc, 0x33, 0xbf, 0x66, 0x7b, 0xf8, 0xb1, 0x73,
- 0x9d, 0x62, 0xff, 0xfe, 0xc2, 0x29, 0x86, 0xa7, 0x85, 0x9b, 0xdb, 0xe2,
- 0x58, 0xbf, 0xe1, 0x73, 0xd3, 0x10, 0xbb, 0xe2, 0xc5, 0xf3, 0x6b, 0x52,
- 0xb1, 0x7f, 0xb3, 0x7e, 0x04, 0x30, 0xc3, 0x12, 0x2f, 0x19, 0x9f, 0x58,
- 0xbf, 0x45, 0x39, 0xfe, 0x2c, 0x56, 0xd4, 0x70, 0xfc, 0xf4, 0x88, 0xbc,
- 0x76, 0x18, 0xf5, 0xfe, 0x0b, 0xc8, 0xba, 0xfb, 0x69, 0x62, 0xf1, 0xdf,
- 0xcb, 0x17, 0xf1, 0x4c, 0x42, 0x70, 0xd6, 0x2a, 0x25, 0x44, 0x67, 0x17,
- 0xfc, 0x67, 0x62, 0x4c, 0xde, 0x72, 0x18, 0xed, 0xff, 0xf6, 0x0d, 0xd8,
- 0x9f, 0xcc, 0x50, 0xe6, 0x2c, 0x5f, 0xdf, 0x7d, 0x36, 0x69, 0x62, 0xa4,
- 0xfe, 0x5d, 0x32, 0x96, 0x2f, 0xbb, 0xe9, 0xb4, 0xb1, 0x60, 0x05, 0x0d,
- 0x8f, 0x83, 0x2f, 0xf6, 0xff, 0xb6, 0x41, 0xf7, 0xac, 0x5f, 0xb7, 0xb9,
- 0xd8, 0xeb, 0x15, 0x28, 0x8c, 0xc2, 0xb2, 0x37, 0xbd, 0xaf, 0xe2, 0xc5,
- 0xf4, 0x50, 0x98, 0x2c, 0x54, 0x9e, 0x0e, 0x0e, 0xdf, 0x48, 0x6c, 0x05,
- 0x8b, 0x85, 0xf5, 0x8b, 0xff, 0xe6, 0xf7, 0x3e, 0xc3, 0x3f, 0x8a, 0x73,
- 0xb5, 0x8a, 0x8d, 0x11, 0x71, 0x11, 0xf8, 0x62, 0xfe, 0x8c, 0x73, 0x84,
- 0x35, 0x8a, 0x96, 0x44, 0xcc, 0x21, 0x23, 0x84, 0x4d, 0x28, 0x03, 0xed,
- 0x4f, 0x29, 0x28, 0xa1, 0xb9, 0xc8, 0x6e, 0xf9, 0xb8, 0x50, 0xab, 0x0c,
- 0xca, 0xfd, 0xb6, 0x79, 0x30, 0x58, 0xbc, 0xe0, 0x65, 0x8b, 0xff, 0x66,
- 0xf9, 0x9f, 0xcc, 0x73, 0xda, 0xc5, 0xff, 0x0c, 0x85, 0xcc, 0x8f, 0x23,
- 0x58, 0xbd, 0x3a, 0x25, 0x8b, 0xff, 0xc0, 0x92, 0xce, 0xfc, 0xfc, 0xe4,
- 0x9d, 0x62, 0xff, 0x60, 0xc9, 0xf8, 0xc3, 0x58, 0xb7, 0xd6, 0x2d, 0x19,
- 0x1e, 0x27, 0x0c, 0xac, 0x2c, 0x45, 0xb3, 0xc2, 0x3a, 0xb4, 0x8f, 0xef,
- 0x43, 0x4a, 0xf8, 0xfc, 0xc3, 0xac, 0x53, 0x1e, 0x5b, 0x94, 0x5f, 0xd3,
- 0xaf, 0x7b, 0x37, 0x16, 0x2e, 0x9d, 0xeb, 0x14, 0x35, 0x4e, 0xa7, 0x2a,
- 0xf8, 0xe3, 0xa0, 0x85, 0xe3, 0x84, 0x22, 0x0d, 0xd3, 0x1b, 0xf8, 0x31,
- 0x94, 0xe4, 0x6b, 0x17, 0xfb, 0x85, 0x80, 0x72, 0x02, 0xc5, 0x89, 0x62,
- 0xfa, 0x63, 0x98, 0x2c, 0x5f, 0xe1, 0xe7, 0xb8, 0xc6, 0x79, 0x62, 0x86,
- 0x8c, 0xae, 0xcb, 0xdc, 0xc8, 0x84, 0x4c, 0x23, 0xbf, 0xbe, 0xde, 0x29,
- 0x3a, 0xc5, 0xff, 0xc1, 0xfb, 0x65, 0xb9, 0xef, 0xb3, 0x81, 0x62, 0xff,
- 0xfe, 0x81, 0x4b, 0x6b, 0x07, 0xa9, 0xf3, 0x74, 0xc3, 0x58, 0xbf, 0xfd,
- 0x83, 0x73, 0xe7, 0x70, 0xc0, 0x60, 0xd6, 0x2e, 0xfb, 0xac, 0x5d, 0x17,
- 0x16, 0x2f, 0xd9, 0xbd, 0x88, 0x78, 0x6c, 0x03, 0x17, 0xbf, 0xb6, 0xfb,
- 0x39, 0xc9, 0x58, 0xbe, 0xce, 0xfd, 0x2b, 0x17, 0xff, 0x3e, 0xb0, 0xd6,
- 0xd6, 0x6f, 0x7d, 0x2c, 0x57, 0xcf, 0xa7, 0x79, 0x1d, 0xff, 0x8b, 0x35,
- 0xa6, 0x3e, 0x77, 0xe5, 0x8b, 0xf6, 0xeb, 0xc6, 0x1c, 0x16, 0x2b, 0x6a,
- 0x7c, 0x41, 0x1e, 0xa4, 0xfb, 0x21, 0x33, 0xc2, 0x41, 0x1f, 0xdd, 0xf7,
- 0x58, 0xbf, 0xf7, 0xd9, 0xc1, 0x85, 0x3d, 0xf1, 0x62, 0xc3, 0xc3, 0xd5,
- 0xf0, 0xbd, 0xff, 0x14, 0x3f, 0x84, 0x52, 0x62, 0xc5, 0xff, 0xe7, 0x8e,
- 0x75, 0xa7, 0x86, 0xd0, 0x0f, 0x16, 0x2b, 0x11, 0x0a, 0x47, 0x17, 0xb7,
- 0x0f, 0x8b, 0x17, 0xfd, 0x06, 0x8b, 0xb8, 0x7c, 0x40, 0x58, 0xbf, 0x16,
- 0x7b, 0xed, 0x27, 0xbb, 0x11, 0x05, 0xff, 0x6b, 0x4f, 0x0d, 0xbb, 0xe7,
- 0x71, 0x62, 0xa4, 0xff, 0xb0, 0xf6, 0xa5, 0x31, 0xc8, 0x43, 0xf2, 0x8d,
- 0x5d, 0x29, 0xed, 0x27, 0x52, 0x8f, 0x0a, 0x16, 0x9e, 0x8f, 0x22, 0xfd,
- 0x84, 0xfe, 0xe2, 0xc5, 0xfd, 0xcf, 0xe1, 0x37, 0x16, 0x2f, 0xf1, 0x74,
- 0x1f, 0xb8, 0x21, 0xac, 0x5f, 0xdd, 0x18, 0xe4, 0x52, 0xb1, 0x50, 0x45,
- 0xce, 0x89, 0xdc, 0xb4, 0x8d, 0xee, 0x0b, 0xe2, 0xc5, 0xf4, 0x5f, 0x6d,
- 0x2c, 0x5f, 0x38, 0xc3, 0x3a, 0xc5, 0xd9, 0xcd, 0xa7, 0xc6, 0x15, 0x1b,
- 0x81, 0x25, 0x4a, 0xfc, 0xbe, 0x25, 0x34, 0xea, 0xb3, 0xc6, 0x32, 0x50,
- 0x9e, 0xbf, 0xfe, 0x16, 0xb0, 0x7f, 0x96, 0xf7, 0x18, 0xa0, 0xb1, 0x7f,
- 0xd8, 0x3c, 0x29, 0x21, 0x4a, 0xc5, 0x8c, 0x58, 0xbf, 0xfc, 0x0c, 0xef,
- 0xd3, 0xdc, 0x3c, 0x09, 0x82, 0xc5, 0xfe, 0xf1, 0x37, 0x7c, 0x0c, 0xeb,
- 0x14, 0x48, 0x83, 0xe2, 0x6d, 0xf9, 0xdf, 0xb8, 0x71, 0x62, 0xa5, 0x1c,
- 0x2d, 0x09, 0x6d, 0x11, 0x54, 0xc2, 0x77, 0xe2, 0x39, 0x45, 0x10, 0xac,
- 0x6e, 0x07, 0x4a, 0x76, 0xc9, 0x5b, 0x86, 0xca, 0xd2, 0xea, 0x7f, 0xe7,
- 0xb8, 0xd0, 0x5a, 0x55, 0xf4, 0x52, 0xbe, 0x35, 0x5c, 0xa0, 0x1e, 0x7e,
- 0xb3, 0xf4, 0xda, 0x07, 0x86, 0xa8, 0x25, 0x6b, 0x15, 0x6b, 0x47, 0xc9,
- 0xff, 0x9f, 0x53, 0x4f, 0x05, 0x2c, 0xbf, 0x7d, 0x23, 0x4b, 0x65, 0x6c,
- 0x34, 0xfd, 0xd8, 0xc5, 0xef, 0xf6, 0x8a, 0x7d, 0x0c, 0xfa, 0xc5, 0xee,
- 0x48, 0x16, 0x2b, 0x0f, 0x43, 0xc6, 0x77, 0x6c, 0x7b, 0x0d, 0x62, 0xff,
- 0xdf, 0xc1, 0xff, 0x1c, 0xb3, 0x71, 0x62, 0xfe, 0x81, 0x67, 0x4d, 0xe5,
- 0x8b, 0xff, 0x8b, 0xa3, 0x5f, 0x99, 0x09, 0x2e, 0x96, 0x2f, 0xb0, 0x6f,
- 0x05, 0x8b, 0x9a, 0x35, 0x8a, 0x01, 0xba, 0xf1, 0x15, 0x62, 0x61, 0xfd,
- 0xa0, 0x31, 0x71, 0x42, 0x02, 0xfc, 0xd2, 0x77, 0x1a, 0xc5, 0xfe, 0xcf,
- 0x96, 0x7b, 0xec, 0xb1, 0x77, 0xb9, 0xf3, 0xd9, 0xf1, 0x3d, 0xf0, 0xf4,
- 0xf0, 0x58, 0xbb, 0x60, 0xdd, 0x58, 0xbd, 0x1e, 0x76, 0xb1, 0x5a, 0x37,
- 0xe4, 0x41, 0x78, 0x39, 0x02, 0xc5, 0xf7, 0xc5, 0x3c, 0x58, 0xbc, 0xee,
- 0x05, 0x8b, 0xdf, 0x9e, 0x49, 0xbf, 0xd1, 0x1d, 0xff, 0xbe, 0xc5, 0x3d,
- 0xf1, 0x8f, 0x2b, 0x17, 0xb9, 0x3a, 0x58, 0xbb, 0xdc, 0x1a, 0x23, 0x3a,
- 0x31, 0xec, 0xfa, 0xa5, 0x3d, 0x73, 0x4b, 0x99, 0x89, 0xc8, 0x05, 0x0e,
- 0x9b, 0xd0, 0xf1, 0xd6, 0x2f, 0xe2, 0xc8, 0x41, 0xf8, 0xb1, 0x7f, 0x48,
- 0x7c, 0x1f, 0x67, 0x58, 0xae, 0x8f, 0x78, 0x8b, 0x6f, 0xe7, 0x33, 0x00,
- 0x1f, 0x96, 0x2e, 0x1b, 0x2c, 0x5f, 0x77, 0xc9, 0xed, 0x62, 0xe7, 0x86,
- 0xd3, 0x78, 0xc2, 0xf7, 0x8d, 0xfb, 0x2c, 0x5f, 0xfd, 0x16, 0xa7, 0x7f,
- 0xe5, 0xb4, 0xd1, 0x2c, 0x5a, 0x35, 0x8a, 0x81, 0xfc, 0xf6, 0x3c, 0xe9,
- 0x17, 0xff, 0xfa, 0x4c, 0xfb, 0xfb, 0x99, 0xa2, 0x9e, 0xe1, 0x9d, 0xf9,
- 0x62, 0xfb, 0x3d, 0xc7, 0x58, 0xb0, 0xf4, 0x88, 0x5f, 0xb1, 0xdf, 0xee,
- 0x16, 0x1d, 0xde, 0x35, 0x8a, 0x73, 0xdc, 0x11, 0x4d, 0xfd, 0xcc, 0x1b,
- 0x72, 0x35, 0x8b, 0xd0, 0x90, 0x2c, 0x5f, 0x83, 0x8a, 0x13, 0xb8, 0x91,
- 0x52, 0xbe, 0xdb, 0x19, 0x0e, 0x46, 0x64, 0x6c, 0xa7, 0x1e, 0x93, 0x99,
- 0xf3, 0x44, 0x5f, 0x6c, 0x78, 0x53, 0x14, 0x62, 0x1c, 0x21, 0xf1, 0x78,
- 0x63, 0xb7, 0xf0, 0xf4, 0xfd, 0x3f, 0x4b, 0x17, 0xff, 0xfc, 0x16, 0xe3,
- 0x9d, 0x80, 0xf2, 0x16, 0xf6, 0x30, 0xb5, 0xf4, 0x60, 0xdb, 0xb7, 0xfb,
- 0x2b, 0x16, 0xe9, 0x62, 0xff, 0xc4, 0x27, 0x0f, 0x38, 0xd2, 0x4b, 0x17,
- 0xe8, 0x73, 0xdb, 0xc0, 0xb1, 0x46, 0x9f, 0x4f, 0x67, 0xb7, 0xb6, 0x58,
- 0x6b, 0x15, 0xa3, 0xc4, 0x39, 0x25, 0xfd, 0xb4, 0xb3, 0x7b, 0xe9, 0x62,
- 0xf4, 0xbe, 0x96, 0x2e, 0x2e, 0x96, 0x2f, 0xc1, 0xfb, 0xc2, 0xfa, 0xc5,
- 0x31, 0xe1, 0xef, 0x18, 0xbf, 0x8f, 0xef, 0xce, 0xf9, 0x58, 0xbf, 0xf6,
- 0xe6, 0xde, 0xbe, 0xda, 0x69, 0x3a, 0xc5, 0xe2, 0xe8, 0x0b, 0x15, 0x19,
- 0xf1, 0xe2, 0x2d, 0xfe, 0xf4, 0x27, 0xdf, 0x78, 0x2c, 0x5f, 0xfb, 0xc2,
- 0x3f, 0xe5, 0x89, 0xc6, 0xb1, 0x7d, 0x08, 0x3f, 0x96, 0x2a, 0x34, 0x4a,
- 0xf6, 0x68, 0xe7, 0xd7, 0xc6, 0xe9, 0xcc, 0x58, 0xbb, 0xad, 0xeb, 0x16,
- 0x0d, 0x51, 0x02, 0x96, 0xf2, 0xa8, 0x14, 0x2b, 0x47, 0xb5, 0xe1, 0xb3,
- 0x08, 0x2b, 0x11, 0x5e, 0xcf, 0xf7, 0xf7, 0x4d, 0x1f, 0x9c, 0x6b, 0x17,
- 0xf3, 0x05, 0xfa, 0xfc, 0x98, 0xb1, 0x7f, 0xbe, 0xc1, 0x84, 0x00, 0x25,
- 0x22, 0xb4, 0x7d, 0x7b, 0x26, 0x97, 0xec, 0x3b, 0xbc, 0x6b, 0x17, 0xe9,
- 0xeb, 0xf3, 0xa5, 0x8b, 0xdf, 0x11, 0xab, 0x17, 0xb7, 0x42, 0xfc, 0x58,
- 0xbc, 0xe7, 0x65, 0x8a, 0xf9, 0xf0, 0x10, 0xf8, 0x89, 0x6a, 0x34, 0xe7,
- 0xda, 0x13, 0x64, 0x4b, 0xe2, 0x80, 0xe1, 0x13, 0x7f, 0xe8, 0x7c, 0x3d,
- 0x48, 0xff, 0x86, 0x2c, 0x5f, 0xbf, 0x22, 0xed, 0x96, 0x2b, 0xb3, 0xeb,
- 0x3a, 0x15, 0xff, 0x10, 0x07, 0xf7, 0x0f, 0x23, 0x58, 0xbf, 0x60, 0x82,
- 0xf9, 0xc5, 0x8a, 0x63, 0xe7, 0xf9, 0xdd, 0xff, 0xe2, 0x35, 0xdc, 0x80,
- 0x42, 0x7e, 0xf6, 0x25, 0x8b, 0xf4, 0x81, 0xc8, 0x0b, 0x17, 0xe1, 0x77,
- 0xe6, 0x31, 0x62, 0xde, 0x81, 0xe9, 0x70, 0x9e, 0xb1, 0x19, 0x25, 0x0a,
- 0x1b, 0xfe, 0x2c, 0xd0, 0xff, 0x3d, 0xc1, 0x62, 0xff, 0xf4, 0x9c, 0x4e,
- 0x3f, 0x77, 0xd3, 0x11, 0x8b, 0x16, 0xc2, 0x44, 0x39, 0x87, 0x57, 0xfe,
- 0xef, 0xdd, 0x7d, 0x87, 0xfc, 0x8d, 0x62, 0xfe, 0x6e, 0xf9, 0xf6, 0x31,
- 0x62, 0xc1, 0x75, 0x8a, 0x01, 0xe3, 0x11, 0x85, 0x62, 0x2a, 0xb5, 0x08,
- 0x9b, 0xf9, 0xf9, 0x98, 0x46, 0xac, 0x56, 0x1e, 0xa0, 0x89, 0xef, 0x3b,
- 0x98, 0xb1, 0x52, 0xa8, 0x44, 0x70, 0xad, 0xfc, 0x64, 0xc4, 0x43, 0x7f,
- 0xbd, 0xcd, 0xb8, 0x76, 0x1a, 0xc5, 0xff, 0x3e, 0xa2, 0x29, 0x07, 0x04,
- 0xb1, 0x52, 0x7e, 0x03, 0x36, 0xbf, 0x7b, 0x04, 0x5e, 0x58, 0xbf, 0x43,
- 0x81, 0xce, 0xe2, 0xc5, 0xa7, 0x0f, 0x55, 0xca, 0x2f, 0xfd, 0xb4, 0x9c,
- 0xdd, 0xbc, 0x00, 0x25, 0x62, 0xff, 0xf4, 0x62, 0x07, 0x20, 0xdc, 0xe4,
- 0xea, 0x0b, 0x16, 0x63, 0x51, 0x23, 0xa4, 0x4b, 0xfc, 0xff, 0xef, 0x92,
- 0x5e, 0x58, 0xa8, 0x26, 0x27, 0xc8, 0x5b, 0x78, 0xa6, 0xff, 0xff, 0x0f,
- 0xf3, 0xd7, 0xda, 0x27, 0x78, 0x1a, 0xe1, 0xbe, 0xe2, 0xc5, 0xff, 0xff,
- 0xbe, 0xed, 0xc6, 0x86, 0x0f, 0xdf, 0x96, 0xd6, 0x98, 0xa3, 0x58, 0xbe,
- 0x2c, 0xdf, 0x8b, 0x15, 0x1a, 0x3d, 0x4e, 0xce, 0x63, 0x5d, 0xfe, 0xfb,
- 0x45, 0x09, 0x28, 0x2c, 0x5f, 0xff, 0xd3, 0xee, 0x06, 0x5e, 0xf8, 0x9e,
- 0x1e, 0xe6, 0x18, 0xb1, 0x7f, 0xe9, 0x8f, 0x3d, 0x0c, 0x26, 0x1a, 0xc5,
- 0xff, 0xfc, 0xf1, 0xe9, 0xdf, 0xb8, 0x73, 0xdd, 0xf4, 0xda, 0x35, 0x62,
- 0xff, 0xce, 0x67, 0xb3, 0xfe, 0x69, 0xdc, 0x58, 0xbf, 0xf4, 0x99, 0xc0,
- 0xab, 0xf5, 0x9d, 0xf9, 0x62, 0xa5, 0x3e, 0xbe, 0x8c, 0xb4, 0x69, 0xf5,
- 0xe7, 0x3e, 0x26, 0x1f, 0x21, 0x5f, 0x43, 0xf9, 0x1a, 0xc5, 0xff, 0x31,
- 0x61, 0xf6, 0x71, 0xbb, 0x58, 0xbf, 0xff, 0xce, 0x72, 0xce, 0xe7, 0x5a,
- 0x6d, 0xfa, 0xcf, 0x3f, 0x6b, 0x14, 0x34, 0x4f, 0x70, 0xee, 0xff, 0xfe,
- 0x1c, 0x39, 0xac, 0xf3, 0xf7, 0x13, 0x87, 0x3e, 0xe2, 0xc5, 0xff, 0xfd,
- 0x9e, 0x7e, 0xff, 0xf6, 0x9f, 0x7f, 0x37, 0xce, 0x96, 0x2f, 0xff, 0xf4,
- 0xbc, 0xb1, 0x3f, 0xa0, 0xdb, 0xf5, 0x9e, 0x7e, 0xd6, 0x2a, 0x53, 0x3f,
- 0x81, 0x1e, 0x97, 0xf6, 0x57, 0x6f, 0x3b, 0xee, 0xac, 0x5d, 0x27, 0xda,
- 0x7b, 0xe7, 0x40, 0xbe, 0x68, 0xfa, 0x82, 0xc5, 0xe2, 0xcd, 0xd5, 0x8b,
- 0xfe, 0x9e, 0xce, 0xfe, 0xce, 0xfc, 0xb1, 0x73, 0xc6, 0xb1, 0x5d, 0xab,
- 0x26, 0x69, 0x4c, 0x1a, 0x2f, 0x72, 0x52, 0x1f, 0x30, 0xee, 0xf7, 0xdf,
- 0x8b, 0x16, 0xed, 0x62, 0xa4, 0xd8, 0x0c, 0x76, 0xff, 0x1d, 0xf8, 0x53,
- 0x86, 0xac, 0x58, 0x4b, 0x17, 0xfc, 0x21, 0x7d, 0xbd, 0xf7, 0x82, 0xc5,
- 0xe8, 0x67, 0x96, 0x2f, 0x9f, 0xf9, 0xa5, 0x8a, 0xf9, 0xbf, 0xde, 0x3b,
- 0x7e, 0x17, 0xf5, 0x26, 0x2c, 0x5d, 0xb2, 0xeb, 0x17, 0x4f, 0x5b, 0x53,
- 0x45, 0xc2, 0x03, 0x4c, 0xce, 0x24, 0xef, 0x3e, 0x23, 0x0c, 0xaa, 0xf1,
- 0x05, 0xf8, 0xb1, 0x7d, 0x0f, 0xb6, 0xf5, 0x8b, 0xd2, 0x5e, 0xda, 0x78,
- 0xcc, 0x43, 0x76, 0x9d, 0x62, 0xff, 0xed, 0xed, 0xce, 0x61, 0x74, 0xe4,
- 0x05, 0x8b, 0xfd, 0xf6, 0x18, 0xf0, 0xc8, 0x96, 0x2f, 0x37, 0x7c, 0x58,
- 0xbf, 0x66, 0xfc, 0x80, 0x5d, 0x62, 0x8d, 0x3c, 0xcf, 0x8f, 0x58, 0x18,
- 0x8e, 0xbe, 0x91, 0xbd, 0x08, 0x2b, 0xe0, 0xfe, 0xfe, 0x58, 0xb4, 0xe8,
- 0xf7, 0xce, 0x77, 0x4c, 0x9d, 0xde, 0x8c, 0xff, 0x1b, 0x0d, 0xff, 0x9f,
- 0xbe, 0x67, 0x98, 0xef, 0x05, 0x8b, 0x79, 0x62, 0x80, 0x7a, 0x21, 0x9f,
- 0xdf, 0xff, 0x13, 0xe7, 0xdb, 0x5f, 0x71, 0x7f, 0x0e, 0xb1, 0x71, 0xb0,
- 0x58, 0xbf, 0xd3, 0xa0, 0x0d, 0xdc, 0xd5, 0x8b, 0xfb, 0xed, 0xd7, 0xf3,
- 0xd8, 0x79, 0xbf, 0x19, 0xa1, 0xa3, 0x7f, 0x21, 0x37, 0x7f, 0xff, 0xe7,
- 0xd1, 0xa3, 0xfc, 0xf3, 0xf9, 0xdc, 0x3c, 0xd1, 0x4f, 0x04, 0xb1, 0x58,
- 0x89, 0x77, 0x27, 0xbe, 0x2d, 0xbd, 0x44, 0xb1, 0x7f, 0xf4, 0xf5, 0x9a,
- 0xcf, 0xb6, 0xbe, 0xeb, 0x17, 0xff, 0x84, 0xe1, 0x96, 0x67, 0xdb, 0xaf,
- 0xe2, 0xc5, 0xf4, 0x45, 0x27, 0xd2, 0x23, 0x89, 0x12, 0xff, 0xf9, 0xf4,
- 0x0d, 0x9c, 0xd4, 0xc1, 0xbb, 0xf6, 0x2c, 0x5f, 0xf6, 0x17, 0xbe, 0xf0,
- 0x98, 0xd6, 0x2f, 0xff, 0xa0, 0xde, 0x0f, 0x53, 0xf9, 0xf7, 0x1f, 0xb5,
- 0x8b, 0xf0, 0xb9, 0xf7, 0x86, 0x22, 0x2f, 0x87, 0x37, 0xf4, 0x27, 0x6c,
- 0x9c, 0xeb, 0x17, 0xec, 0xdd, 0x69, 0x89, 0x62, 0xf9, 0xc1, 0x85, 0x27,
- 0xb7, 0xf3, 0x0b, 0xff, 0xdb, 0xfe, 0xc3, 0xc6, 0x35, 0x8b, 0x37, 0xac,
- 0x5f, 0xa7, 0x0b, 0xdb, 0x2b, 0x17, 0xf3, 0x76, 0x0d, 0x38, 0xd6, 0x2f,
- 0xff, 0x6f, 0x2c, 0xe6, 0xdc, 0x21, 0x43, 0x38, 0xb1, 0x4b, 0x15, 0x87,
- 0xb2, 0x74, 0xda, 0x3a, 0x34, 0xfe, 0x54, 0x50, 0x88, 0xbf, 0x7e, 0x75,
- 0xc6, 0x58, 0xbb, 0x5b, 0x8b, 0x17, 0xa0, 0x21, 0xac, 0x5b, 0xbd, 0xa8,
- 0x95, 0x19, 0xa4, 0x45, 0x0e, 0x37, 0x58, 0x9f, 0xdb, 0xc7, 0x6b, 0x7f,
- 0x9c, 0x83, 0x78, 0x60, 0xd6, 0x2a, 0x57, 0x3c, 0xb2, 0x16, 0xac, 0x73,
- 0xa8, 0x6f, 0x14, 0x26, 0xb9, 0x28, 0xc4, 0x45, 0x17, 0xf3, 0x6b, 0x63,
- 0xe7, 0x99, 0x62, 0xfc, 0x53, 0xfc, 0x1a, 0xc5, 0xff, 0xdc, 0x90, 0x67,
- 0xdb, 0x4e, 0x67, 0x96, 0x2f, 0x61, 0x46, 0x33, 0xec, 0xe1, 0x3d, 0xfc,
- 0x3c, 0x23, 0x75, 0x2b, 0x17, 0x6c, 0xf6, 0xb1, 0x7f, 0xe6, 0xd3, 0x46,
- 0xdd, 0x7e, 0x7c, 0xb1, 0x50, 0x6e, 0x4a, 0xc7, 0x2b, 0xef, 0xa8, 0x5c,
- 0x77, 0x1c, 0x4c, 0x52, 0xc5, 0xb5, 0x2e, 0x24, 0xf1, 0xea, 0x7e, 0x53,
- 0xa0, 0x21, 0x0e, 0x51, 0xcc, 0xfa, 0x74, 0x4f, 0x7b, 0xc9, 0x90, 0x9f,
- 0xd9, 0x33, 0x0c, 0xbb, 0x74, 0x72, 0xf7, 0x5f, 0x89, 0x62, 0xf9, 0xe3,
- 0x11, 0x8b, 0x17, 0x05, 0xf7, 0x56, 0x2f, 0x31, 0xf1, 0x62, 0xe9, 0x35,
- 0x62, 0xa0, 0x7f, 0x1d, 0x92, 0xe8, 0x7c, 0xc1, 0xcb, 0xfe, 0x2c, 0x33,
- 0x59, 0xd7, 0xf1, 0x62, 0xdd, 0x2c, 0x5f, 0xff, 0xd8, 0x3f, 0xc9, 0x85,
- 0x8d, 0x1e, 0xc8, 0xbe, 0xda, 0x58, 0xa8, 0xd1, 0x59, 0xb8, 0x74, 0x42,
- 0x75, 0x2d, 0xea, 0xce, 0x43, 0x01, 0xab, 0x9b, 0x58, 0xa3, 0x2f, 0x78,
- 0x4c, 0x0a, 0x1d, 0x57, 0xd3, 0xd3, 0x74, 0xb1, 0x7b, 0x4c, 0x62, 0xc5,
- 0xfe, 0xd0, 0xa3, 0x68, 0x1c, 0x6b, 0x17, 0xfb, 0x99, 0xa1, 0x93, 0xc1,
- 0x62, 0x86, 0x88, 0x7d, 0x0f, 0x70, 0xda, 0xfe, 0xf4, 0xc3, 0x66, 0x32,
- 0x58, 0xbf, 0xcf, 0xb4, 0xb0, 0x02, 0xe2, 0xc5, 0xef, 0xe0, 0x16, 0x2d,
- 0x2b, 0x17, 0xff, 0xd1, 0x3b, 0xc3, 0x92, 0x71, 0xfe, 0x4b, 0xa5, 0x8a,
- 0x93, 0xe2, 0x61, 0x1b, 0xfe, 0x17, 0x59, 0xa8, 0xe3, 0x14, 0x6b, 0x17,
- 0xfd, 0x91, 0x42, 0x7b, 0xce, 0xfc, 0xb1, 0x5b, 0x53, 0x4f, 0x93, 0x5c,
- 0x7f, 0x39, 0x01, 0x1f, 0xde, 0x8d, 0xbb, 0x58, 0xbb, 0xe3, 0x58, 0xa9,
- 0x54, 0x05, 0x1c, 0x70, 0x2c, 0x95, 0xc1, 0xfa, 0x82, 0xb2, 0x11, 0xc2,
- 0xaf, 0x52, 0x8c, 0xaf, 0x87, 0xf1, 0x46, 0xb1, 0x7f, 0x3c, 0x32, 0x31,
- 0x12, 0xc5, 0xd8, 0x35, 0x8a, 0x19, 0xe2, 0xf4, 0x5d, 0x7f, 0xed, 0x66,
- 0xe4, 0x5f, 0x73, 0xb7, 0x16, 0x2f, 0xef, 0x31, 0x87, 0x6f, 0x2c, 0x5f,
- 0xf3, 0x96, 0xb1, 0xbf, 0x23, 0x58, 0xb6, 0x78, 0xf9, 0xb7, 0x4b, 0xed,
- 0x1c, 0xa6, 0xc1, 0x8d, 0x5a, 0x23, 0xfc, 0x2a, 0x6c, 0xcb, 0x17, 0x05,
- 0xf1, 0x62, 0xb0, 0xfd, 0x34, 0x90, 0xe2, 0x37, 0xfe, 0xde, 0xde, 0x84,
- 0xed, 0xf4, 0x89, 0x62, 0xd1, 0x2c, 0x5e, 0xdf, 0x83, 0x58, 0xbf, 0x6c,
- 0x8b, 0xf9, 0xd2, 0xc5, 0xc7, 0xe2, 0xc5, 0x62, 0x2e, 0xa2, 0x43, 0x38,
- 0x9f, 0x87, 0xc4, 0x5b, 0x7f, 0x4f, 0x98, 0x13, 0x05, 0x8b, 0xa0, 0xeb,
- 0x15, 0xa3, 0xc4, 0x72, 0xdb, 0xfb, 0xb8, 0xde, 0x13, 0xb8, 0xb1, 0x71,
- 0x41, 0x62, 0xa4, 0xf2, 0xa3, 0x33, 0xb8, 0xc9, 0x58, 0xad, 0xae, 0xad,
- 0x77, 0x62, 0x30, 0x0a, 0xc2, 0x42, 0x61, 0x81, 0x19, 0x14, 0x0c, 0x71,
- 0x7c, 0xd2, 0x3e, 0xa1, 0x26, 0xd0, 0xb7, 0x3c, 0x38, 0x3f, 0x5f, 0x8c,
- 0xbc, 0xb9, 0x92, 0x94, 0x25, 0xc8, 0x73, 0xfa, 0x11, 0xc2, 0x6b, 0xd9,
- 0x22, 0xbf, 0xf0, 0x54, 0x39, 0x3f, 0x5f, 0x7e, 0xc0, 0xb1, 0x7f, 0xa1,
- 0x16, 0x13, 0xff, 0x16, 0x2f, 0xbb, 0x84, 0x9d, 0x62, 0xff, 0xa4, 0xa3,
- 0xe6, 0x1e, 0x77, 0x16, 0x2f, 0xff, 0xa3, 0xf6, 0x73, 0xe2, 0xe4, 0xc6,
- 0x22, 0x95, 0x8b, 0xa7, 0xeb, 0x17, 0xf3, 0xc4, 0x39, 0x28, 0xd6, 0x2a,
- 0x34, 0x7c, 0x0c, 0x93, 0x0f, 0x09, 0x4b, 0x78, 0xbd, 0xfc, 0xfe, 0x00,
- 0x65, 0x12, 0xc5, 0xfe, 0xfb, 0xfb, 0x86, 0x67, 0xd6, 0x2f, 0xa6, 0x26,
- 0xfa, 0xc5, 0xfd, 0xe2, 0xc8, 0xdb, 0x4b, 0x17, 0xec, 0xf3, 0x90, 0x16,
- 0x2a, 0x4f, 0x54, 0x45, 0xd7, 0xb7, 0x64, 0xeb, 0x15, 0x88, 0xee, 0x73,
- 0x5e, 0x3c, 0x6e, 0x90, 0xdf, 0x88, 0x7f, 0x98, 0x2c, 0x5e, 0x29, 0xe9,
- 0x62, 0xfa, 0x61, 0x9c, 0x58, 0xbf, 0xe7, 0x30, 0x32, 0x2c, 0xee, 0x0b,
- 0x15, 0x87, 0xf5, 0xf1, 0xd7, 0x22, 0xbe, 0xdd, 0x92, 0xe9, 0x62, 0xfe,
- 0xfe, 0x1a, 0xf3, 0x1a, 0xc5, 0xf4, 0xc5, 0xa9, 0x58, 0xb4, 0xac, 0x5b,
- 0x16, 0x2b, 0x46, 0x88, 0xe2, 0x34, 0x73, 0xe6, 0xfa, 0x2d, 0xf4, 0x88,
- 0x2e, 0xcb, 0x17, 0xdc, 0x29, 0x31, 0x62, 0xfc, 0x3f, 0xe1, 0x41, 0x62,
- 0xb0, 0xf2, 0xdc, 0x8e, 0xf4, 0x18, 0x0b, 0x17, 0xf4, 0xe4, 0x67, 0x10,
- 0xd6, 0x2f, 0xff, 0xec, 0xf7, 0x03, 0xe7, 0xbe, 0xe4, 0x6e, 0x6f, 0x93,
- 0x16, 0x2f, 0xb9, 0xe6, 0x89, 0x62, 0x8e, 0x88, 0x47, 0x60, 0xbf, 0xcd,
- 0xa9, 0x8d, 0xf5, 0xd2, 0xc5, 0xdd, 0x44, 0xb1, 0x5b, 0x55, 0xde, 0x49,
- 0xf0, 0xe1, 0x45, 0x85, 0xbd, 0x13, 0x34, 0x25, 0x74, 0x45, 0xf7, 0x17,
- 0x20, 0x21, 0xde, 0x42, 0xcf, 0xc4, 0x5b, 0x26, 0xb4, 0x75, 0xd9, 0xef,
- 0x4e, 0x6d, 0x5f, 0xfe, 0xd7, 0x45, 0x9b, 0xcb, 0x27, 0x53, 0xc5, 0x8b,
- 0xff, 0x1d, 0xb3, 0xbc, 0x61, 0xce, 0xea, 0xc5, 0xfe, 0x78, 0xbf, 0x87,
- 0xce, 0x2c, 0x56, 0x23, 0x03, 0x49, 0x7b, 0xd0, 0x6f, 0x6c, 0xcf, 0x96,
- 0x2f, 0xa7, 0x7b, 0x6f, 0x58, 0xbb, 0x0e, 0xb1, 0x63, 0x76, 0x9b, 0xd6,
- 0x26, 0xa8, 0xd1, 0x0c, 0x4b, 0xb7, 0xe3, 0x7d, 0x98, 0x75, 0x8b, 0xff,
- 0x42, 0x0d, 0xd4, 0x9e, 0x2e, 0x4a, 0xc5, 0xff, 0xe8, 0xc3, 0xfb, 0x49,
- 0x46, 0x03, 0xcc, 0x16, 0x2b, 0x11, 0xb4, 0xc4, 0x6e, 0x52, 0x24, 0x1b,
- 0xff, 0x8b, 0x0d, 0x35, 0xfd, 0xc6, 0x28, 0x96, 0x2f, 0x64, 0x19, 0x62,
- 0xa2, 0x3e, 0x2d, 0x23, 0x5e, 0xc8, 0xc9, 0x62, 0xf6, 0x0b, 0xb5, 0x8a,
- 0xf9, 0xbb, 0x21, 0xdb, 0xf6, 0x0d, 0xb5, 0xc5, 0x8a, 0x58, 0xbe, 0x83,
- 0x03, 0x8b, 0x15, 0xc3, 0x5e, 0x18, 0x65, 0xe1, 0x3e, 0x96, 0x2f, 0xba,
- 0x9c, 0x8d, 0x62, 0x98, 0xf0, 0x74, 0x3b, 0x7b, 0xde, 0xed, 0x62, 0xff,
- 0xee, 0xfa, 0x6f, 0xed, 0xdd, 0xcf, 0xb1, 0xd6, 0x28, 0x07, 0xd7, 0xe1,
- 0xfb, 0x85, 0xa5, 0x8b, 0xe9, 0xeb, 0x67, 0x16, 0x2b, 0x11, 0xd9, 0xc8,
- 0x46, 0x6c, 0x91, 0x06, 0x31, 0x51, 0xa7, 0xd6, 0x75, 0x73, 0x23, 0x4f,
- 0xbe, 0x0f, 0xf9, 0xd2, 0xc5, 0xfb, 0x9e, 0x77, 0x25, 0x8a, 0xec, 0xf3,
- 0x0c, 0x25, 0xa9, 0x45, 0x4b, 0x42, 0x16, 0xff, 0xfc, 0xfe, 0x88, 0xa4,
- 0x1c, 0xc8, 0x7d, 0x88, 0x0b, 0x15, 0x2c, 0xc9, 0x1c, 0x9d, 0xe9, 0x68,
- 0x77, 0x7e, 0x39, 0x17, 0x84, 0xe7, 0x17, 0xbd, 0x2a, 0xd0, 0x44, 0xd7,
- 0xfe, 0x26, 0x0f, 0xbc, 0xdf, 0xdc, 0x86, 0xb1, 0x68, 0x2c, 0x5f, 0xfe,
- 0x6c, 0xd0, 0xe4, 0xcc, 0xfc, 0xf7, 0xc5, 0x8b, 0xfb, 0xd3, 0xa2, 0xc8,
- 0xd6, 0x2f, 0x83, 0x9d, 0x01, 0x62, 0xff, 0xd3, 0xdf, 0xff, 0x31, 0xc8,
- 0x8e, 0xb1, 0x7f, 0xa2, 0xe0, 0xa0, 0x52, 0x75, 0x8b, 0x6c, 0x0b, 0x17,
- 0xff, 0x6b, 0x4e, 0x0c, 0xfb, 0x6b, 0xee, 0xb1, 0x68, 0x2c, 0x50, 0x54,
- 0xfb, 0x78, 0x2e, 0x1a, 0x25, 0xd9, 0xc5, 0x8b, 0x69, 0x62, 0xbe, 0x6a,
- 0x5c, 0x5e, 0xff, 0xfc, 0x6e, 0x79, 0xb9, 0xf1, 0x67, 0x80, 0xe3, 0x95,
- 0x8b, 0xfb, 0xcd, 0x19, 0xe7, 0xa5, 0x8a, 0x1a, 0x29, 0xb4, 0x41, 0xf5,
- 0x6b, 0xff, 0xb8, 0x37, 0x73, 0x3b, 0xf1, 0x3f, 0xd6, 0x2f, 0xa0, 0xda,
- 0x82, 0xc5, 0xfc, 0x08, 0xa0, 0xda, 0x82, 0xc4, 0x46, 0x8e, 0xff, 0x7f,
- 0x3f, 0x9d, 0x3f, 0x4b, 0x17, 0x34, 0x6b, 0x15, 0xd1, 0xe6, 0xf8, 0xd6,
- 0x8d, 0x4c, 0x6b, 0xb6, 0x9d, 0x42, 0x3a, 0xff, 0x75, 0x13, 0x1c, 0x4f,
- 0xc5, 0x8b, 0xec, 0x16, 0xa3, 0x58, 0xba, 0x77, 0x16, 0x2b, 0xb3, 0xf4,
- 0x39, 0xb7, 0xc9, 0x2f, 0xb5, 0x22, 0xdc, 0x58, 0xbd, 0x23, 0x1a, 0xc5,
- 0xd9, 0xba, 0xb1, 0x7c, 0x00, 0xca, 0x0b, 0x16, 0x72, 0x37, 0xde, 0x1a,
- 0xbf, 0x73, 0x98, 0x40, 0x58, 0xa0, 0x1e, 0x69, 0x12, 0xd4, 0xab, 0x15,
- 0x68, 0xd2, 0x9e, 0x15, 0x9c, 0x30, 0xf1, 0x30, 0xa1, 0x51, 0x68, 0x96,
- 0x2f, 0xf8, 0x4e, 0x1c, 0x50, 0xce, 0xe0, 0xb1, 0x5d, 0x9e, 0x81, 0x09,
- 0xdf, 0x13, 0xf7, 0xc5, 0x8b, 0xef, 0x00, 0xf8, 0xb1, 0x5e, 0x3c, 0x60,
- 0xc8, 0xe8, 0xe8, 0x8b, 0x03, 0x45, 0xd3, 0xc5, 0x8b, 0xe9, 0xfc, 0x8d,
- 0x62, 0xba, 0x37, 0x31, 0x0b, 0xdf, 0xff, 0xdf, 0xc2, 0xf7, 0x36, 0x87,
- 0x0f, 0xe1, 0x10, 0xa0, 0xb1, 0x7f, 0xc6, 0x8f, 0xf3, 0xa2, 0x98, 0x2c,
- 0x5f, 0xbe, 0xc4, 0xf1, 0xac, 0x5f, 0xf4, 0x1f, 0x5e, 0x29, 0x3f, 0x16,
- 0x2f, 0xf4, 0x8e, 0x74, 0x29, 0x02, 0xc5, 0xf6, 0xf9, 0xcd, 0x2c, 0x5d,
- 0x9d, 0xac, 0x56, 0x1b, 0xc2, 0x24, 0xb7, 0x3a, 0x47, 0x7c, 0x45, 0x07,
- 0x39, 0x26, 0xfa, 0x94, 0xdb, 0x4f, 0x19, 0x4d, 0xff, 0xf4, 0xe7, 0x7e,
- 0xfe, 0x34, 0x18, 0xd3, 0x71, 0x62, 0xfc, 0x53, 0xba, 0x52, 0xb1, 0x7f,
- 0xf9, 0xdf, 0x51, 0xfd, 0xfd, 0xf6, 0xd4, 0x16, 0x2f, 0xda, 0x1f, 0xda,
- 0x25, 0x8b, 0xfb, 0x18, 0x8a, 0x46, 0xb1, 0x73, 0x98, 0x34, 0x50, 0x62,
- 0x5f, 0xca, 0xaf, 0xf9, 0xcb, 0x3d, 0xe6, 0x33, 0xcb, 0x17, 0xff, 0xff,
- 0x45, 0x06, 0x2f, 0x48, 0x37, 0x7c, 0xc6, 0xeb, 0x27, 0xb8, 0x31, 0xd6,
- 0x2a, 0x51, 0x60, 0x47, 0x35, 0x2b, 0x93, 0x38, 0xb9, 0xd1, 0x1b, 0x47,
- 0x97, 0xa2, 0x97, 0x51, 0x28, 0x64, 0x8a, 0x1d, 0x75, 0xb1, 0xb7, 0x5b,
- 0x72, 0x8f, 0x0a, 0x6d, 0xe6, 0x42, 0x40, 0xd4, 0x4e, 0x84, 0x99, 0x2e,
- 0x22, 0xef, 0x92, 0x3a, 0x08, 0x21, 0x45, 0xc9, 0xc1, 0x8f, 0x4e, 0xed,
- 0x5f, 0xb6, 0x1f, 0x70, 0xcf, 0x2c, 0x5f, 0xfd, 0xee, 0xe1, 0x9e, 0x6d,
- 0xf2, 0x5d, 0x2c, 0x5f, 0xd2, 0x2e, 0xdb, 0xbd, 0xd5, 0x8b, 0xf6, 0x19,
- 0x9d, 0xf9, 0x62, 0xb6, 0x9e, 0xeb, 0x19, 0xdf, 0xee, 0xe1, 0x83, 0xfe,
- 0x46, 0xb1, 0x5d, 0xa3, 0xfb, 0x50, 0xa5, 0x22, 0x3b, 0xc1, 0x4d, 0x8f,
- 0xb5, 0x8b, 0xf7, 0x7b, 0x43, 0x9e, 0x2c, 0x5b, 0x8b, 0x16, 0xfc, 0x9b,
- 0xf0, 0xcb, 0x6f, 0xd3, 0xae, 0xe1, 0xc5, 0x8b, 0xfe, 0x98, 0xf6, 0xbe,
- 0xee, 0xeb, 0x81, 0x62, 0xff, 0xff, 0xb5, 0x13, 0xfd, 0xb9, 0x31, 0x37,
- 0xbd, 0x9f, 0x03, 0x6f, 0x58, 0xad, 0x8d, 0x36, 0x49, 0x67, 0x8c, 0x9f,
- 0x45, 0x42, 0x42, 0xbf, 0xf8, 0x5a, 0xc8, 0xe7, 0x93, 0x09, 0xd2, 0xc5,
- 0xed, 0x67, 0x16, 0x2f, 0xcc, 0x5b, 0xf2, 0x0b, 0x17, 0xb1, 0xa3, 0x58,
- 0xa3, 0x4f, 0x8c, 0xe3, 0xbf, 0x29, 0xbf, 0xa6, 0x3c, 0xf6, 0x1d, 0x62,
- 0xfc, 0x1e, 0xdf, 0xf3, 0x16, 0x2f, 0xfc, 0x42, 0xeb, 0xf8, 0x78, 0x9f,
- 0xa5, 0x8b, 0x85, 0xa5, 0x8a, 0xc3, 0xda, 0xd9, 0x42, 0xa8, 0x27, 0x60,
- 0xd0, 0xa8, 0xd1, 0x80, 0x0b, 0xb9, 0x08, 0x6b, 0xe3, 0xb4, 0x8d, 0x62,
- 0xff, 0x11, 0xbf, 0x93, 0x9c, 0x96, 0x2f, 0xed, 0xc6, 0x9d, 0xd1, 0x79,
- 0x62, 0xfd, 0x31, 0x66, 0x74, 0xb1, 0x78, 0xb3, 0x75, 0x62, 0xa5, 0x1a,
- 0x58, 0x44, 0xc6, 0x9f, 0x34, 0x11, 0x4d, 0xe3, 0xbf, 0x96, 0x2f, 0x8e,
- 0xf3, 0xda, 0xc5, 0x11, 0xe0, 0x18, 0x3b, 0x7f, 0xbd, 0xc6, 0xdf, 0xa6,
- 0xe2, 0xc5, 0xff, 0x19, 0x06, 0xd0, 0x65, 0x09, 0x58, 0xb9, 0xa0, 0xb1,
- 0x58, 0x88, 0x86, 0x36, 0x23, 0xbb, 0xff, 0xdc, 0x7c, 0xde, 0xde, 0x86,
- 0x1a, 0x6e, 0x2c, 0x5e, 0x36, 0x7a, 0x58, 0xbf, 0xec, 0x89, 0xa2, 0x16,
- 0xe8, 0xb8, 0xb1, 0x67, 0x58, 0xaf, 0x9e, 0x87, 0x8f, 0xef, 0x36, 0x8d,
- 0x58, 0xbe, 0xf3, 0x4f, 0x6b, 0x15, 0x28, 0xd2, 0x66, 0xf2, 0x22, 0xe0,
- 0xf5, 0xff, 0x4c, 0x53, 0xef, 0xe6, 0xba, 0x58, 0xbd, 0xf9, 0x89, 0x62,
- 0xd3, 0xd9, 0xec, 0xee, 0x9d, 0xd4, 0x11, 0x7d, 0xc8, 0x49, 0xde, 0x26,
- 0x65, 0x8b, 0x9e, 0x35, 0x8b, 0xf9, 0xcf, 0x9b, 0xdf, 0x4b, 0x15, 0x19,
- 0xe3, 0x9c, 0x62, 0xff, 0xd1, 0x37, 0xe7, 0xb8, 0x4c, 0x52, 0xb1, 0x4c,
- 0x7c, 0x82, 0x23, 0xbd, 0x3e, 0x3a, 0xc5, 0xdc, 0x3a, 0xc5, 0x1c, 0xda,
- 0xee, 0x8e, 0xdf, 0xf7, 0x05, 0x1c, 0xc5, 0xb4, 0x1e, 0x58, 0xbf, 0x0d,
- 0xca, 0x7e, 0xb1, 0x7f, 0x42, 0x7b, 0xf6, 0x7d, 0x62, 0xff, 0xf7, 0xb8,
- 0xc0, 0x98, 0x73, 0x33, 0xbf, 0x2c, 0x54, 0x47, 0xf5, 0xc2, 0xfa, 0xed,
- 0x30, 0x3f, 0x9f, 0x99, 0x0a, 0x1b, 0xfd, 0x9d, 0x61, 0x4e, 0x18, 0xb1,
- 0x7f, 0x8f, 0x31, 0x1e, 0x47, 0x2b, 0x17, 0xe8, 0xb1, 0xb7, 0x46, 0xb1,
- 0x6f, 0xb1, 0xf0, 0x39, 0xa5, 0xff, 0xa7, 0xdc, 0x76, 0x18, 0xbd, 0xc5,
- 0x8a, 0x95, 0x4a, 0xed, 0x19, 0x3f, 0xce, 0x39, 0x09, 0x33, 0x09, 0xaf,
- 0xd9, 0xdc, 0x3e, 0xcb, 0x17, 0xff, 0x31, 0x67, 0xa4, 0xfb, 0x77, 0x77,
- 0xf9, 0x62, 0xfb, 0x74, 0x85, 0x1a, 0xc5, 0x6d, 0x44, 0xde, 0xe1, 0x49,
- 0xd2, 0xef, 0xe6, 0xfb, 0x44, 0xd1, 0xac, 0x5a, 0x56, 0x2b, 0x87, 0x81,
- 0xe2, 0xfb, 0xf7, 0x98, 0xa1, 0x2b, 0x17, 0xf7, 0x70, 0xc1, 0x6a, 0x35,
- 0x8b, 0xff, 0xda, 0xd4, 0x96, 0x1a, 0xdf, 0xfe, 0x06, 0xb1, 0x58, 0x8a,
- 0x36, 0x27, 0x11, 0x8d, 0x4a, 0x6d, 0x18, 0xeb, 0xa8, 0x62, 0xdf, 0xcc,
- 0x6b, 0x79, 0xfe, 0xb1, 0x7b, 0xaf, 0xca, 0xc5, 0xda, 0x95, 0x8a, 0x81,
- 0xf1, 0xf6, 0x5d, 0x10, 0xf5, 0xfa, 0x5b, 0xdb, 0x10, 0x5a, 0xac, 0x5f,
- 0x9d, 0x87, 0x24, 0xb1, 0x74, 0x89, 0x62, 0xa5, 0x14, 0x5f, 0x31, 0x23,
- 0x4e, 0x13, 0x5d, 0xbb, 0x2b, 0x17, 0x17, 0x4b, 0x15, 0x26, 0xc9, 0x86,
- 0xaf, 0xf0, 0x98, 0xb3, 0x9c, 0xc5, 0x8a, 0x8c, 0xf4, 0x4e, 0x3f, 0x76,
- 0x74, 0xb1, 0x7d, 0xf0, 0x3f, 0x96, 0x2d, 0xf5, 0x8a, 0x73, 0x6a, 0x22,
- 0x3b, 0xfc, 0x59, 0xe9, 0x80, 0xb4, 0xb1, 0x47, 0x45, 0x06, 0xf4, 0xdd,
- 0xd2, 0x0b, 0xf0, 0x1c, 0xef, 0xda, 0xc5, 0xff, 0x8e, 0xdc, 0xfc, 0xb6,
- 0x85, 0xb8, 0xb1, 0x5d, 0x9f, 0x5b, 0x14, 0xd4, 0xa7, 0x0a, 0xd0, 0xc3,
- 0x78, 0x50, 0x5f, 0xc5, 0xc6, 0xdf, 0x23, 0x58, 0xbf, 0xe0, 0x31, 0x7a,
- 0x78, 0x2f, 0xac, 0x5f, 0xa4, 0x3e, 0x4f, 0x16, 0x2f, 0xf6, 0xa3, 0x6e,
- 0x9b, 0x58, 0xb1, 0x78, 0x98, 0xd5, 0x8b, 0xf3, 0xeb, 0x53, 0x1a, 0xc5,
- 0xfd, 0xe6, 0xd3, 0x78, 0x4b, 0x16, 0x9d, 0xa9, 0x85, 0xc6, 0x73, 0x85,
- 0x27, 0x35, 0xf0, 0xe8, 0x65, 0x37, 0xe0, 0xff, 0x9d, 0xf1, 0x62, 0xe7,
- 0xdc, 0x58, 0xa1, 0x1e, 0x28, 0x65, 0x77, 0xff, 0xff, 0xd3, 0xe2, 0x7e,
- 0x9b, 0x91, 0x36, 0xba, 0x9e, 0x7a, 0x7b, 0x90, 0xf3, 0x8b, 0x17, 0xfb,
- 0x99, 0xa9, 0xdf, 0x3b, 0x8b, 0x15, 0xa4, 0x5c, 0x7a, 0x10, 0x17, 0xfb,
- 0xf9, 0xdc, 0xe9, 0x8e, 0xb1, 0x7f, 0xd3, 0xd6, 0xb3, 0x98, 0xc3, 0x58,
- 0xbf, 0xfc, 0xda, 0xc8, 0x9b, 0x5b, 0xac, 0x1e, 0x41, 0x62, 0xb4, 0x88,
- 0x7e, 0x1c, 0xde, 0x93, 0xca, 0xc5, 0x68, 0xdf, 0xf8, 0x8e, 0xff, 0x1c,
- 0x9c, 0xd6, 0xf8, 0x96, 0x2f, 0xbe, 0xce, 0x05, 0x8b, 0x4e, 0xd3, 0xd6,
- 0xf1, 0xa5, 0xff, 0xff, 0xff, 0x73, 0x3d, 0xf7, 0x3f, 0x35, 0xa6, 0xef,
- 0xce, 0xe6, 0xe6, 0x44, 0x2f, 0x49, 0x9d, 0xca, 0xc5, 0xf8, 0x51, 0x66,
- 0xce, 0x2c, 0x5d, 0xf7, 0x58, 0xae, 0x23, 0x6f, 0xd0, 0x98, 0xde, 0x59,
- 0x7f, 0xdd, 0xf0, 0x98, 0xfe, 0xcd, 0xc5, 0x8b, 0xb3, 0x4b, 0x15, 0x27,
- 0xa9, 0xf3, 0xdb, 0xfb, 0xc4, 0xe0, 0xc2, 0x58, 0xba, 0x4d, 0x58, 0xbe,
- 0x70, 0x61, 0x2c, 0x54, 0x46, 0xe4, 0x86, 0x2b, 0x6a, 0x21, 0xbc, 0xcb,
- 0x52, 0xaf, 0xd0, 0x65, 0x19, 0x0f, 0xae, 0x9d, 0xde, 0x30, 0x4f, 0x42,
- 0x2c, 0x50, 0xa7, 0xbf, 0xd0, 0x7e, 0xdb, 0x75, 0x86, 0xb1, 0x7c, 0x07,
- 0xef, 0x8b, 0x17, 0x18, 0x62, 0xc5, 0x70, 0xdf, 0x18, 0x49, 0x7d, 0xf7,
- 0xcf, 0xa4, 0x04, 0x34, 0x57, 0xff, 0xe0, 0xd8, 0xe2, 0xe4, 0x86, 0xc7,
- 0x98, 0xa4, 0xc5, 0x8b, 0x9a, 0x35, 0x8a, 0x94, 0xcf, 0x1a, 0x12, 0xee,
- 0x69, 0xbd, 0x66, 0xfb, 0xa9, 0x17, 0x6b, 0x17, 0xe0, 0xf0, 0xed, 0xa5,
- 0x8b, 0xf3, 0x6b, 0xd9, 0xd2, 0xc5, 0xfb, 0xa6, 0xe7, 0xd9, 0x62, 0xfe,
- 0xed, 0xa3, 0x3b, 0x71, 0x62, 0xe3, 0xba, 0xc5, 0xfe, 0xf4, 0x97, 0x5b,
- 0x00, 0x0e, 0xb1, 0x52, 0x88, 0x1f, 0x98, 0x08, 0x5e, 0xf7, 0xe4, 0x0b,
- 0x17, 0xb7, 0x77, 0x65, 0x62, 0xff, 0x87, 0xf6, 0xd3, 0x77, 0x14, 0xac,
- 0x53, 0x9e, 0xf0, 0x88, 0xee, 0x0a, 0x6f, 0x58, 0xa9, 0x54, 0x15, 0x84,
- 0xa6, 0x94, 0xf6, 0x52, 0xd0, 0xaa, 0x72, 0xf2, 0x7b, 0xf1, 0x0d, 0xef,
- 0xed, 0xdc, 0x58, 0xbc, 0x5d, 0x32, 0xc5, 0xe2, 0xc8, 0xd6, 0x2f, 0xb9,
- 0xa6, 0x31, 0x62, 0xdf, 0x93, 0xc1, 0x71, 0xda, 0x94, 0x53, 0xb1, 0x1b,
- 0xaf, 0x5f, 0x9a, 0x37, 0x11, 0x2c, 0x5f, 0xb4, 0x28, 0xc5, 0x1a, 0xc5,
- 0xfd, 0x3e, 0x11, 0xc5, 0xe5, 0x8b, 0xfd, 0x25, 0xf7, 0x00, 0xa2, 0x58,
- 0xa9, 0x44, 0x7f, 0xcb, 0x37, 0x4b, 0xeb, 0x61, 0xb7, 0xf6, 0x33, 0x19,
- 0x74, 0x71, 0xcc, 0xc2, 0x50, 0x00, 0xe3, 0x26, 0xc8, 0x43, 0x9b, 0x0a,
- 0xae, 0x8b, 0x7b, 0x8f, 0x75, 0x8a, 0x37, 0x21, 0x8d, 0x14, 0xaa, 0xdd,
- 0x4a, 0x59, 0x3c, 0x67, 0x3f, 0x94, 0x86, 0xe7, 0x00, 0x8c, 0xe8, 0x2f,
- 0x0a, 0x52, 0x9c, 0xcf, 0xe4, 0x76, 0xbe, 0x94, 0x99, 0xbe, 0x31, 0xc0,
- 0xcb, 0x77, 0x61, 0x6f, 0x7d, 0xac, 0xf6, 0x2c, 0x5f, 0xee, 0xbe, 0xde,
- 0xe3, 0xf6, 0xb1, 0x7b, 0x35, 0xbd, 0x62, 0xf6, 0x83, 0x89, 0x62, 0xe3,
- 0xfd, 0x62, 0x98, 0xdc, 0x70, 0x82, 0xff, 0xc4, 0x03, 0xbc, 0x0a, 0x7d,
- 0xc5, 0x8b, 0xb3, 0x16, 0x2f, 0xba, 0xfb, 0x06, 0xb1, 0x58, 0x9a, 0x41,
- 0xa4, 0x4c, 0x6d, 0xf5, 0x77, 0x20, 0x0b, 0x9f, 0x06, 0x2d, 0x7e, 0x8a,
- 0x62, 0xfc, 0xac, 0x5f, 0xfe, 0x2f, 0x70, 0x3f, 0x31, 0x0a, 0x19, 0xc5,
- 0x8b, 0x83, 0x95, 0x8b, 0xec, 0xd3, 0xc1, 0x62, 0xfe, 0xfe, 0x44, 0xe5,
- 0x1a, 0xc5, 0xe3, 0x0c, 0x31, 0x22, 0xfa, 0x1e, 0xce, 0x92, 0x02, 0x1a,
- 0x1b, 0xf6, 0x0d, 0x81, 0xc5, 0xdd, 0xfc, 0x56, 0xd4, 0x5d, 0xe9, 0x40,
- 0x8d, 0xae, 0xe4, 0x16, 0x2f, 0x71, 0xc0, 0xb1, 0x52, 0x6d, 0x7b, 0x18,
- 0xb6, 0xf5, 0x8b, 0x6c, 0xac, 0x5b, 0x3a, 0x35, 0x27, 0x14, 0xa9, 0x54,
- 0x83, 0x85, 0x5a, 0x4b, 0x38, 0xc3, 0xc3, 0x74, 0x0c, 0xc4, 0x95, 0x7c,
- 0x71, 0xe1, 0x2c, 0x5d, 0xee, 0x2c, 0x5f, 0xfe, 0x1e, 0x61, 0xbb, 0x73,
- 0xcd, 0xcf, 0xb2, 0xc5, 0xfe, 0xf7, 0xe7, 0xdc, 0xfb, 0x2c, 0x5d, 0x08,
- 0xd6, 0x2e, 0x78, 0x2c, 0x5f, 0xb6, 0xe4, 0x4d, 0x1a, 0xc5, 0x6d, 0x44,
- 0x84, 0x0d, 0x0e, 0x33, 0xc1, 0x7b, 0x71, 0x62, 0xfd, 0x0f, 0xc9, 0x46,
- 0x91, 0x74, 0xc1, 0x62, 0xde, 0xec, 0xf0, 0x3e, 0x53, 0x7f, 0xec, 0xee,
- 0x0d, 0x84, 0x58, 0x35, 0x8b, 0xe3, 0x8b, 0xbf, 0x2c, 0x5f, 0x67, 0xe7,
- 0x7a, 0xc5, 0x46, 0x79, 0x3c, 0x25, 0xa9, 0x54, 0xaf, 0x18, 0xc7, 0x70,
- 0xdc, 0xd1, 0xf9, 0x29, 0x70, 0xa7, 0xd0, 0x86, 0xbf, 0xdd, 0x7d, 0x87,
- 0x2f, 0xa5, 0x8b, 0xcd, 0xc6, 0x58, 0xb3, 0x2c, 0x5f, 0x38, 0x6e, 0x35,
- 0x8b, 0xd3, 0xa3, 0x56, 0x2d, 0x0f, 0x9f, 0x73, 0x8e, 0x08, 0x44, 0xc2,
- 0x3b, 0xff, 0xfc, 0x3f, 0xe7, 0xbc, 0xe5, 0xd7, 0x27, 0x4f, 0x13, 0x7d,
- 0x62, 0x86, 0x9a, 0x37, 0x70, 0xa2, 0x64, 0x2b, 0xf1, 0xa1, 0xce, 0x80,
- 0xb1, 0x7f, 0xc5, 0x26, 0x71, 0x8b, 0xb8, 0x2c, 0x5f, 0xff, 0xfb, 0x80,
- 0x6d, 0x0f, 0x0b, 0xed, 0xd7, 0xdb, 0xc6, 0xc9, 0x41, 0x62, 0xe9, 0xe9,
- 0x62, 0xb4, 0x8e, 0xa2, 0x2b, 0xf1, 0xd6, 0xf6, 0xdb, 0xff, 0xcd, 0xf7,
- 0x8b, 0x07, 0xf6, 0xdf, 0x91, 0x2c, 0x5e, 0x0e, 0x77, 0x16, 0x2e, 0xfb,
- 0x2c, 0x58, 0x0b, 0x14, 0x69, 0xa9, 0x21, 0x7a, 0x8c, 0xfa, 0xd9, 0x2a,
- 0xff, 0xbd, 0xf6, 0x90, 0x47, 0xc3, 0x56, 0x2f, 0xc5, 0x26, 0x61, 0x2c,
- 0x5f, 0xf7, 0xfb, 0x93, 0x62, 0x84, 0xee, 0x2c, 0x5b, 0x83, 0x3e, 0x7c,
- 0x27, 0xad, 0x23, 0xb0, 0x88, 0xbd, 0x0a, 0x3a, 0x58, 0xbf, 0x43, 0x4d,
- 0x27, 0x58, 0xbc, 0x1f, 0x66, 0x2c, 0x54, 0x67, 0xab, 0xd8, 0x67, 0x0a,
- 0x2a, 0x57, 0x5c, 0xb2, 0x3b, 0x66, 0x8c, 0x83, 0xe7, 0xcf, 0x1d, 0x20,
- 0xa1, 0x13, 0x79, 0x81, 0x2b, 0x17, 0xd0, 0xcf, 0x32, 0xc5, 0xf6, 0x69,
- 0x8e, 0xb1, 0x5b, 0x4f, 0x83, 0xb1, 0xce, 0x11, 0x5f, 0xfe, 0x87, 0x85,
- 0xfd, 0x49, 0x90, 0x60, 0x62, 0xc5, 0xce, 0x75, 0x8a, 0xe9, 0x12, 0xa4,
- 0x65, 0xbd, 0x32, 0xff, 0xfd, 0xe7, 0xd6, 0x30, 0x39, 0x9f, 0x6d, 0x7d,
- 0xd6, 0x2f, 0xfb, 0xed, 0xa8, 0x8a, 0x67, 0xb5, 0x8b, 0xda, 0x7e, 0x2c,
- 0x5e, 0x92, 0x1a, 0xc5, 0xfb, 0xbe, 0x45, 0x9e, 0x58, 0xac, 0x4c, 0x93,
- 0xb3, 0x26, 0x54, 0x39, 0xd7, 0xc7, 0x48, 0x72, 0xfe, 0x6f, 0x13, 0x83,
- 0x8b, 0x17, 0xe9, 0x3f, 0xb3, 0xeb, 0x17, 0xc1, 0xc9, 0x44, 0xb1, 0x7d,
- 0xc6, 0x9e, 0x96, 0x2f, 0xb3, 0xbf, 0x32, 0xc5, 0xff, 0xd1, 0x66, 0xb1,
- 0xcf, 0x3f, 0x61, 0xac, 0x56, 0x22, 0x2b, 0xe4, 0x7e, 0x23, 0xbf, 0x84,
- 0x7c, 0xff, 0x6e, 0xb1, 0x46, 0xa6, 0xc3, 0xd1, 0x6f, 0xca, 0x0a, 0x15,
- 0xdc, 0x2f, 0xbf, 0xfc, 0xc3, 0x27, 0xec, 0xb3, 0xd8, 0xc0, 0x58, 0xbe,
- 0x8e, 0x37, 0xdc, 0x58, 0xbe, 0xe8, 0x62, 0x8d, 0x62, 0xf4, 0x38, 0x25,
- 0x8b, 0x9e, 0x0b, 0x17, 0xef, 0x37, 0xe0, 0x4b, 0x14, 0x73, 0x7e, 0x42,
- 0xf7, 0xff, 0xff, 0xef, 0xce, 0x47, 0x06, 0xf7, 0x27, 0x58, 0x11, 0x81,
- 0x33, 0xbe, 0x64, 0xba, 0x58, 0xb7, 0xb1, 0x32, 0x8f, 0x93, 0x3a, 0xef,
- 0x08, 0x2f, 0x18, 0x61, 0x8b, 0x17, 0xff, 0xc7, 0xce, 0xfc, 0x59, 0x19,
- 0xf0, 0xf8, 0x49, 0x01, 0x0d, 0x0d, 0x4a, 0x31, 0x59, 0x8e, 0xfa, 0x3c,
- 0xfb, 0xac, 0x5f, 0xed, 0x13, 0x99, 0x9f, 0x75, 0x8b, 0xe7, 0xd7, 0xf1,
- 0x62, 0xff, 0x89, 0xe3, 0xe6, 0x7d, 0xf7, 0x16, 0x2f, 0xbd, 0x3e, 0xe6,
- 0x1e, 0xf3, 0x91, 0x5f, 0xbe, 0xfa, 0xcd, 0x2c, 0x5f, 0xf7, 0x98, 0x13,
- 0x0c, 0xef, 0xcb, 0x17, 0xfc, 0xdd, 0x96, 0x7b, 0xec, 0x62, 0xc5, 0x49,
- 0xfa, 0x68, 0xea, 0xff, 0xe8, 0xc8, 0x51, 0x8b, 0x9e, 0xe6, 0x18, 0xb1,
- 0x7e, 0xef, 0xa6, 0x28, 0xd6, 0x2f, 0xf7, 0xe6, 0x11, 0x41, 0xc9, 0x62,
- 0xbc, 0x7b, 0xe1, 0x95, 0xd4, 0xa3, 0x2d, 0xe1, 0x51, 0x70, 0x9d, 0x62,
- 0x86, 0xaa, 0x37, 0x21, 0x23, 0xd1, 0xbe, 0xa1, 0x39, 0xf8, 0x76, 0x11,
- 0x35, 0xff, 0x00, 0xb3, 0xa6, 0xcf, 0x71, 0x62, 0xf7, 0xa4, 0x6b, 0x17,
- 0xd0, 0xf0, 0x86, 0xb1, 0x7e, 0x96, 0x83, 0xf1, 0x62, 0xa4, 0xfa, 0x3b,
- 0x1d, 0xd1, 0x25, 0xfd, 0x9e, 0xf8, 0xa7, 0xb5, 0x8b, 0xef, 0x36, 0xb1,
- 0x62, 0xfb, 0xbe, 0x31, 0xa3, 0x3d, 0x1c, 0x2f, 0xa8, 0xd3, 0xc2, 0xd3,
- 0x39, 0x42, 0x87, 0xd0, 0x80, 0xbf, 0xb8, 0x59, 0xbf, 0xec, 0xb1, 0x7b,
- 0xac, 0xe2, 0xc5, 0x61, 0xe6, 0x88, 0xbe, 0xff, 0xc7, 0x9e, 0xcb, 0x01,
- 0xc9, 0xdc, 0x58, 0xad, 0x1f, 0x19, 0xc8, 0x6f, 0xf0, 0xcb, 0x37, 0xb6,
- 0x9d, 0x62, 0xb6, 0x35, 0xdc, 0x09, 0x9c, 0x72, 0x68, 0x7c, 0x08, 0x8a,
- 0xfd, 0x1e, 0xe3, 0x67, 0x6b, 0x17, 0xe6, 0xe4, 0xc6, 0x75, 0xd9, 0xfa,
- 0x5f, 0xa5, 0xf4, 0x01, 0x2e, 0xcf, 0xd2, 0xe7, 0x82, 0xec, 0xfd, 0x2f,
- 0x85, 0x0c, 0xe2, 0xec, 0xfd, 0x28, 0x67, 0xa8, 0x44, 0x97, 0xe9, 0xce,
- 0x61, 0x2e, 0xcf, 0xd2, 0x97, 0x67, 0xe9, 0x73, 0xf9, 0x76, 0x7e, 0x87,
- 0x2e, 0x6d, 0x02, 0x3f, 0xf1, 0x26, 0x5f, 0x66, 0xcb, 0x01, 0x76, 0x7e,
- 0x94, 0xbb, 0x3f, 0x4b, 0x81, 0x2b, 0xb3, 0xf4, 0xbf, 0xec, 0x03, 0xeb,
- 0x37, 0xe0, 0xd7, 0x67, 0xe9, 0x7f, 0x67, 0xdb, 0x82, 0x8d, 0x76, 0x7e,
- 0x94, 0x04, 0x53, 0x91, 0x27, 0x11, 0xef, 0xb5, 0x1c, 0xf9, 0x76, 0x7e,
- 0x94, 0xbb, 0x3f, 0x4c, 0x36, 0x37, 0x18, 0x62, 0xec, 0xfd, 0x2a, 0x0a,
- 0xc9, 0xc6, 0x6d, 0x90, 0x89, 0xee, 0x14, 0x1a, 0x27, 0x39, 0x97, 0x21,
- 0x81, 0xe6, 0x03, 0x0a, 0x2e, 0x93, 0x53, 0x67, 0xe8, 0x08, 0x89, 0x0b,
- 0xfe, 0x8e, 0x77, 0xe3, 0x6b, 0x23, 0x58, 0xbf, 0xf9, 0xff, 0xd7, 0xd8,
- 0x9f, 0x4f, 0x05, 0x8a, 0x82, 0x2e, 0xb4, 0x75, 0xe3, 0xcb, 0xfa, 0x70,
- 0x39, 0x84, 0x16, 0x2f, 0xf7, 0x32, 0x10, 0x9f, 0x76, 0xb1, 0x7f, 0xd3,
- 0xa0, 0x79, 0x9c, 0xd8, 0x2c, 0x56, 0x23, 0x34, 0x8c, 0x38, 0x5c, 0x19,
- 0xad, 0xff, 0xb3, 0xa1, 0xe6, 0x8c, 0x7f, 0xc4, 0xb1, 0x74, 0x86, 0xb1,
- 0x4b, 0x17, 0xfe, 0x2c, 0x8a, 0x63, 0x03, 0xf7, 0xc5, 0x8a, 0x93, 0xcd,
- 0xe0, 0x65, 0xd0, 0x8d, 0x22, 0xfa, 0x27, 0x7d, 0x2c, 0x54, 0x69, 0xa0,
- 0x76, 0x79, 0xa4, 0x2f, 0xb2, 0x91, 0x0e, 0xe8, 0xcd, 0xcd, 0x1a, 0xc5,
- 0xfd, 0x3f, 0x27, 0x6d, 0x2c, 0x56, 0x97, 0xd2, 0xde, 0x7a, 0xaf, 0xcb,
- 0x9b, 0xc6, 0x2f, 0x8f, 0xb0, 0xe1, 0x12, 0xc5, 0xdb, 0x26, 0xac, 0x5f,
- 0xdc, 0x29, 0xf8, 0xb4, 0xb1, 0x7f, 0x70, 0xb3, 0xd8, 0x05, 0x8a, 0xec,
- 0xf6, 0xce, 0x5d, 0x7f, 0xd1, 0x16, 0x6f, 0xff, 0x6f, 0xb8, 0xb1, 0x7f,
- 0x7b, 0x3f, 0x3a, 0x02, 0xc5, 0xf6, 0x9b, 0x37, 0xac, 0x5f, 0xb3, 0x99,
- 0xdf, 0x96, 0x2f, 0x8f, 0x24, 0x6e, 0xd3, 0xcd, 0x72, 0x4b, 0xfe, 0xd3,
- 0x1f, 0x81, 0xce, 0x44, 0xb1, 0x7f, 0xdd, 0x48, 0x06, 0x27, 0xd4, 0x16,
- 0x2f, 0xfc, 0xef, 0x1e, 0x1d, 0xcb, 0xb8, 0x2c, 0x5e, 0x73, 0x79, 0x87,
- 0xf5, 0x11, 0xdd, 0xfe, 0xf7, 0xf0, 0xe1, 0xc8, 0x16, 0x2f, 0xdb, 0x11,
- 0xba, 0x7e, 0x96, 0x2f, 0xb9, 0x39, 0xe5, 0x8b, 0x7f, 0x6a, 0x21, 0xc2,
- 0xc3, 0x5c, 0x30, 0xbf, 0xfd, 0x3c, 0xc3, 0xcf, 0x4f, 0x83, 0x6d, 0xeb,
- 0x15, 0x88, 0x87, 0x23, 0xcb, 0x19, 0xb5, 0x56, 0x6e, 0x3d, 0xe8, 0xe8,
- 0xa1, 0x6b, 0xe8, 0xd0, 0xab, 0x6a, 0xe0, 0x2c, 0xbb, 0xe1, 0x1b, 0xcb,
- 0x0d, 0xbe, 0x63, 0x58, 0xc5, 0x8b, 0xef, 0x7f, 0x23, 0x58, 0xa3, 0x9e,
- 0x41, 0x12, 0x5c, 0x33, 0x16, 0x29, 0x62, 0xf9, 0xdc, 0xba, 0x58, 0xb8,
- 0x61, 0xc6, 0x6b, 0xb7, 0x86, 0x54, 0xa2, 0x67, 0x08, 0x59, 0x1e, 0xf1,
- 0xc1, 0xa5, 0x8b, 0xbc, 0x4b, 0x17, 0xe1, 0xbc, 0x3f, 0x8b, 0x17, 0x88,
- 0x1d, 0x2c, 0x50, 0xcf, 0x77, 0x05, 0xf8, 0x51, 0x7f, 0xfb, 0xbf, 0x7d,
- 0x83, 0x1e, 0x61, 0x71, 0x96, 0x2f, 0xff, 0xd0, 0xd4, 0xef, 0x78, 0xa4,
- 0x7f, 0x93, 0xbc, 0x4b, 0x17, 0xfb, 0x75, 0xf8, 0xdc, 0x8b, 0x16, 0x2f,
- 0xff, 0x4e, 0x81, 0x9b, 0xdb, 0xd3, 0x85, 0x05, 0x8a, 0xda, 0x9e, 0x70,
- 0x47, 0xbc, 0x2e, 0xed, 0x2f, 0x4b, 0x21, 0x9b, 0xdb, 0xcb, 0x17, 0xec,
- 0xe7, 0x0f, 0xda, 0xc5, 0xd3, 0xde, 0xd3, 0x79, 0x22, 0x57, 0x98, 0xa0,
- 0xb1, 0x52, 0xe9, 0x4d, 0xe3, 0x67, 0x84, 0xff, 0x5e, 0x4a, 0x86, 0x68,
- 0xed, 0xf7, 0x14, 0x62, 0x48, 0xd4, 0xa1, 0x5f, 0xce, 0xf0, 0xbc, 0xfc,
- 0xd8, 0x12, 0x4a, 0x70, 0xc3, 0x91, 0x93, 0x8a, 0x3f, 0xb3, 0x21, 0x33,
- 0xba, 0x5d, 0x7e, 0xf9, 0xe7, 0x60, 0xc5, 0x8b, 0xfd, 0xd4, 0xfb, 0xf3,
- 0xbf, 0x16, 0x2e, 0x8f, 0x16, 0x2d, 0xd6, 0x1e, 0x70, 0x0d, 0xa9, 0x62,
- 0xcf, 0xa3, 0x68, 0x72, 0x8b, 0xfb, 0x0f, 0x13, 0xbc, 0x16, 0x2f, 0xff,
- 0xe7, 0xfc, 0xc0, 0x26, 0x02, 0x61, 0xc1, 0xfe, 0x74, 0xb1, 0x66, 0x1a,
- 0x22, 0xfe, 0x5d, 0x7f, 0xe3, 0x67, 0xb2, 0x9f, 0xfc, 0x5d, 0x2c, 0x5f,
- 0xfa, 0x70, 0xb2, 0x0d, 0xfc, 0xde, 0xb1, 0x7f, 0xf1, 0x38, 0x39, 0xac,
- 0xeb, 0xf9, 0xda, 0xc5, 0x69, 0x10, 0x9e, 0x3e, 0xbe, 0xcd, 0x31, 0xab,
- 0x17, 0xef, 0xb7, 0x26, 0x0b, 0x17, 0xff, 0x9c, 0xde, 0x66, 0xf9, 0xef,
- 0xdc, 0x11, 0xd6, 0x29, 0xcf, 0xdc, 0x8a, 0x28, 0x68, 0xdd, 0x39, 0x19,
- 0x42, 0x6a, 0xfa, 0x4f, 0xb9, 0x2b, 0x17, 0xfc, 0x6b, 0x68, 0x3d, 0x34,
- 0x8d, 0x62, 0xe2, 0x0b, 0xac, 0x5f, 0x4f, 0xd8, 0xdc, 0x3d, 0x6d, 0x1d,
- 0xdf, 0xfb, 0x0e, 0xf0, 0xd9, 0x10, 0xdb, 0xeb, 0x15, 0xf3, 0xfa, 0x23,
- 0x8b, 0xf7, 0xbc, 0xf0, 0xe2, 0xc5, 0xfe, 0x29, 0xf7, 0x71, 0x39, 0xd6,
- 0x2f, 0xde, 0x17, 0xb0, 0x6b, 0x16, 0xc5, 0x8a, 0x73, 0x75, 0xbc, 0xa6,
- 0xff, 0x37, 0x30, 0xa3, 0x32, 0x25, 0x8b, 0xfd, 0xcc, 0xdb, 0xdc, 0x33,
- 0xcb, 0x17, 0x7f, 0x06, 0x7d, 0xbc, 0x36, 0xa8, 0x26, 0xea, 0x32, 0x13,
- 0x94, 0x93, 0x7f, 0xa1, 0x1f, 0x7e, 0xd0, 0x1f, 0x00, 0xb1, 0x7f, 0x66,
- 0xeb, 0x79, 0xa0, 0xb1, 0x7d, 0xf9, 0x8f, 0x98, 0x7b, 0x1f, 0x28, 0xbf,
- 0x89, 0xcd, 0xfb, 0xc1, 0x62, 0xf9, 0xb8, 0x19, 0xd6, 0x2f, 0xff, 0x77,
- 0xee, 0xbe, 0xc5, 0x9e, 0xe4, 0x9d, 0x62, 0xfa, 0x7a, 0x68, 0x2c, 0x5f,
- 0x1c, 0xb3, 0xd8, 0x7d, 0xe4, 0x99, 0x7f, 0xff, 0x7a, 0x7e, 0x59, 0xef,
- 0xb6, 0xd3, 0xe7, 0x9f, 0xcb, 0x14, 0xb1, 0x7f, 0xc5, 0x80, 0xfc, 0xbe,
- 0xb1, 0x62, 0x99, 0x13, 0xfa, 0x5c, 0xe0, 0x65, 0x74, 0x9c, 0xbb, 0x42,
- 0x4d, 0xe1, 0xab, 0x7e, 0xeb, 0x0f, 0x3c, 0x58, 0xbc, 0x61, 0x86, 0x24,
- 0x5e, 0x0e, 0x40, 0x90, 0x10, 0xd0, 0xdf, 0xf3, 0xc0, 0x3d, 0x66, 0xf7,
- 0xd2, 0xc5, 0xb4, 0xb1, 0x7f, 0x8a, 0x60, 0x6e, 0xb3, 0x8b, 0x17, 0xfe,
- 0x22, 0xc8, 0xe2, 0x84, 0xea, 0x35, 0x8b, 0xdf, 0xc8, 0x4a, 0x21, 0xf0,
- 0x48, 0x33, 0x4a, 0x24, 0xc0, 0xfd, 0x0c, 0x3b, 0xfc, 0xc3, 0xe4, 0xfd,
- 0xf4, 0xb1, 0x7f, 0x8a, 0x0c, 0x7c, 0xef, 0xcb, 0x17, 0xdd, 0xf4, 0xc4,
- 0xb1, 0x4e, 0x7b, 0x1e, 0x34, 0xa5, 0x8b, 0x4c, 0x0d, 0x68, 0x5c, 0x86,
- 0xba, 0x47, 0x10, 0x21, 0x71, 0x7e, 0xdb, 0x3d, 0x66, 0x96, 0x2f, 0xff,
- 0xf9, 0xbd, 0xf7, 0x80, 0x4c, 0xfb, 0xf6, 0x0f, 0x14, 0x9f, 0x8b, 0x17,
- 0xfe, 0xdb, 0x24, 0x23, 0xc9, 0x93, 0xc5, 0x8b, 0x60, 0xd1, 0xab, 0xf2,
- 0xb2, 0x69, 0xbf, 0xef, 0x39, 0x67, 0x35, 0x3c, 0x58, 0xbe, 0x84, 0x83,
- 0xb5, 0x8b, 0xc7, 0x18, 0xd6, 0x2f, 0xff, 0xf3, 0xb7, 0xa6, 0x0d, 0xa8,
- 0xc4, 0x0d, 0x9d, 0x9c, 0x1b, 0x2c, 0x5f, 0xff, 0xf3, 0xef, 0x6d, 0xe4,
- 0x2e, 0x06, 0x52, 0x3f, 0xbc, 0x33, 0x8b, 0x17, 0xf0, 0x24, 0xb3, 0xbf,
- 0x2c, 0x5c, 0xe0, 0xda, 0x9a, 0x0e, 0x12, 0x7c, 0x78, 0x99, 0xc3, 0x6a,
- 0xbf, 0xfc, 0x19, 0x44, 0x6b, 0x8f, 0xf9, 0xd6, 0x69, 0x62, 0x99, 0x5a,
- 0x87, 0xe1, 0xfc, 0xe6, 0x85, 0x1b, 0xcf, 0x15, 0xef, 0x7a, 0x0c, 0xb1,
- 0x7b, 0x7c, 0xe9, 0x62, 0xff, 0xdf, 0xc8, 0xfb, 0xe6, 0x74, 0xe1, 0xac,
- 0x5d, 0x9f, 0x58, 0xa6, 0x3d, 0xa1, 0x21, 0xd4, 0x6c, 0xed, 0xb8, 0x42,
- 0xc4, 0x65, 0x19, 0x1d, 0x1f, 0x66, 0x8d, 0x29, 0xaa, 0x28, 0x53, 0x9c,
- 0xe7, 0xf1, 0xe2, 0xb9, 0xd0, 0x12, 0x8a, 0x33, 0x3f, 0x4e, 0x2d, 0x09,
- 0x53, 0x78, 0xe9, 0x8f, 0x37, 0x34, 0x6b, 0x17, 0xf8, 0xba, 0x1b, 0x6f,
- 0x91, 0xac, 0x50, 0xcf, 0x38, 0x43, 0x17, 0xfb, 0x8c, 0x77, 0xd3, 0xf1,
- 0x62, 0xff, 0xf3, 0x6b, 0xf2, 0xde, 0xe3, 0x17, 0x70, 0x58, 0xbf, 0xf3,
- 0x19, 0xac, 0x39, 0xdc, 0xbc, 0xb1, 0x58, 0x88, 0x92, 0x4a, 0xbf, 0xb3,
- 0xaf, 0x6c, 0xe7, 0xd6, 0x29, 0x62, 0xbe, 0x6f, 0x80, 0x65, 0x7f, 0xf4,
- 0x5f, 0x98, 0xc3, 0xf7, 0xc4, 0xf0, 0x58, 0xbf, 0x8b, 0xf3, 0xd6, 0x1d,
- 0x62, 0xfc, 0x68, 0xa0, 0xe3, 0x58, 0xbf, 0xd3, 0xb9, 0xb7, 0xef, 0x9a,
- 0x58, 0xbd, 0x9a, 0x95, 0x8b, 0xef, 0xff, 0x3b, 0x58, 0xbb, 0x0f, 0xb2,
- 0x78, 0x01, 0x8e, 0x56, 0x22, 0xa4, 0x9e, 0x2d, 0xb8, 0xb1, 0x68, 0x96,
- 0x2c, 0x75, 0x8a, 0x63, 0x4a, 0xe2, 0x74, 0x69, 0xec, 0x9c, 0xea, 0xfd,
- 0x80, 0xe4, 0xc1, 0x62, 0xfc, 0xc7, 0x18, 0xf1, 0x62, 0xc0, 0x23, 0xd0,
- 0xd9, 0x28, 0xbf, 0xef, 0x7f, 0x39, 0xb7, 0xcd, 0x1a, 0xc5, 0xfd, 0x91,
- 0x66, 0x86, 0xcb, 0x15, 0x28, 0x95, 0x62, 0xa2, 0x3d, 0xbf, 0xe2, 0x61,
- 0x05, 0xf9, 0xb3, 0x3e, 0x58, 0xbf, 0xe9, 0xc3, 0x3b, 0x87, 0xa4, 0xc5,
- 0x8b, 0xfc, 0x0d, 0x36, 0x7c, 0x5c, 0x58, 0xbd, 0x9d, 0x9d, 0x62, 0xfe,
- 0xc0, 0x6e, 0xf9, 0x8e, 0xb1, 0x52, 0x88, 0x32, 0x34, 0xf0, 0xf5, 0xff,
- 0xcf, 0xed, 0x08, 0xdc, 0xf3, 0x03, 0x8b, 0x17, 0x9f, 0x40, 0x58, 0xa9,
- 0x5d, 0xc5, 0x8e, 0x17, 0x90, 0x5f, 0x19, 0x0e, 0x24, 0xb1, 0x74, 0x50,
- 0xd3, 0x3b, 0xd7, 0xe3, 0x08, 0x22, 0xde, 0x20, 0x7a, 0x17, 0xe6, 0x17,
- 0x6c, 0xa3, 0x5f, 0x7f, 0x3b, 0x82, 0xc5, 0xf6, 0x78, 0x38, 0xd6, 0x2f,
- 0xc5, 0x2d, 0xdc, 0x16, 0x2f, 0x18, 0x61, 0x89, 0x88, 0x40, 0x5f, 0x74,
- 0xef, 0xd2, 0x62, 0x10, 0x01, 0x0d, 0x7d, 0xf3, 0xeb, 0x0c, 0x58, 0xad,
- 0x1f, 0x3e, 0xf4, 0x4b, 0xc6, 0x18, 0x62, 0x62, 0x0f, 0x14, 0x98, 0x83,
- 0xc0, 0x43, 0x5f, 0x7f, 0x79, 0xce, 0x79, 0x3a, 0xc5, 0xf9, 0xfc, 0xe4,
- 0x05, 0x8b, 0xfb, 0x3d, 0xf1, 0x3c, 0x16, 0x2f, 0x18, 0x61, 0x8b, 0x17,
- 0xb9, 0x26, 0xa4, 0x04, 0x34, 0x35, 0x2a, 0x84, 0x72, 0x17, 0xdd, 0x29,
- 0xf6, 0x59, 0xf2, 0xe2, 0x27, 0xf2, 0x7d, 0x6e, 0x2a, 0xa0, 0x3c, 0xa3,
- 0x6b, 0xfd, 0xf9, 0xdf, 0x25, 0x3e, 0x58, 0xbf, 0xfd, 0xcf, 0xbc, 0x33,
- 0xec, 0x7e, 0x4e, 0xe2, 0xc5, 0xe3, 0x24, 0x96, 0x2f, 0xff, 0xfe, 0x92,
- 0x8f, 0x9f, 0x73, 0x9d, 0xe0, 0x19, 0x6f, 0xc1, 0xe7, 0x7e, 0x58, 0xbf,
- 0xfb, 0xf3, 0x06, 0xf6, 0x7f, 0xa9, 0x3a, 0xc5, 0x4a, 0x71, 0x10, 0x2f,
- 0xc3, 0x47, 0x4d, 0xe0, 0xee, 0xf7, 0x6b, 0xff, 0x7d, 0xa2, 0x27, 0x33,
- 0xd9, 0xf5, 0x8b, 0xa7, 0x8b, 0x15, 0xd1, 0xeb, 0xf9, 0x02, 0xff, 0xdf,
- 0x61, 0xc9, 0x7b, 0x3b, 0xf2, 0xc5, 0xee, 0x08, 0x96, 0x2f, 0xa0, 0x52,
- 0x35, 0x8b, 0xc5, 0x27, 0xe1, 0xbf, 0x0c, 0x76, 0xba, 0x45, 0x87, 0x1f,
- 0xaf, 0xfe, 0xfb, 0x6b, 0xef, 0x9c, 0x67, 0x8d, 0x62, 0xff, 0x18, 0xfe,
- 0xc3, 0xbf, 0x6b, 0x17, 0xfe, 0x9f, 0x66, 0xb3, 0x99, 0xdf, 0x96, 0x2b,
- 0x11, 0x71, 0xf4, 0x42, 0x35, 0xbf, 0xf4, 0x67, 0xc3, 0xe1, 0x7b, 0x3a,
- 0x58, 0xbe, 0x9f, 0x49, 0xd6, 0x2f, 0xf6, 0x13, 0x1b, 0xb7, 0xaf, 0xac,
- 0x56, 0xc6, 0xa9, 0xdb, 0xb8, 0x69, 0x9e, 0x1b, 0x84, 0x5d, 0xe4, 0x03,
- 0x08, 0xaf, 0x7e, 0x77, 0x56, 0x2f, 0xf4, 0x97, 0x5d, 0xf1, 0xf7, 0x16,
- 0x28, 0x67, 0xb1, 0xf2, 0x0b, 0xdb, 0xb3, 0x1a, 0xc5, 0xf1, 0x0a, 0x32,
- 0x58, 0xbc, 0xdd, 0xc1, 0x62, 0xa0, 0x78, 0x20, 0x23, 0xbf, 0x87, 0xcc,
- 0x3c, 0xee, 0x2c, 0x5f, 0xfd, 0xc1, 0x16, 0xb2, 0x7b, 0x84, 0x92, 0xc5,
- 0xf6, 0x0d, 0xe0, 0xb1, 0x78, 0x4e, 0x1a, 0xc5, 0xfe, 0xcf, 0xbf, 0x3f,
- 0x3c, 0x58, 0xba, 0x3e, 0xd6, 0x28, 0x67, 0xd7, 0xd8, 0xf0, 0x0c, 0xeb,
- 0x6a, 0x2f, 0x5e, 0x11, 0xb5, 0x05, 0x40, 0x23, 0x22, 0xed, 0x89, 0xc8,
- 0xb8, 0x62, 0x64, 0x60, 0x37, 0xfb, 0x9f, 0xce, 0x7b, 0x3a, 0x58, 0xbf,
- 0x17, 0xbf, 0x90, 0x58, 0xbc, 0xd2, 0x6a, 0xc5, 0x31, 0xfd, 0x39, 0xa9,
- 0x14, 0x5f, 0xf6, 0x14, 0xff, 0xf2, 0x63, 0x2c, 0x5f, 0x75, 0xf6, 0x31,
- 0x62, 0xed, 0xdd, 0x2c, 0x5e, 0x0e, 0x40, 0xb1, 0x7f, 0xff, 0xff, 0xdb,
- 0x4b, 0x0d, 0x6f, 0xff, 0x37, 0x36, 0xcf, 0x4e, 0x1e, 0xdc, 0x28, 0xdb,
- 0x4c, 0x20, 0xbe, 0x2c, 0x54, 0x69, 0xb2, 0x1a, 0x59, 0xd9, 0xc4, 0x44,
- 0xa7, 0x1b, 0x30, 0x7a, 0xfd, 0xd4, 0xfe, 0x4e, 0x91, 0x7e, 0x27, 0x22,
- 0xc4, 0x8b, 0xb3, 0xa4, 0x8b, 0x8c, 0x31, 0x22, 0xb1, 0x10, 0x1c, 0x29,
- 0xf1, 0x29, 0x83, 0x17, 0xf8, 0x83, 0x90, 0x7f, 0x37, 0x52, 0x02, 0x1b,
- 0xdb, 0xff, 0x87, 0xa7, 0xe8, 0xb3, 0x7e, 0x9b, 0x8b, 0x17, 0xa3, 0x6d,
- 0x2c, 0x54, 0x67, 0xcb, 0xf4, 0x7a, 0x95, 0xee, 0xbc, 0x95, 0x84, 0xd2,
- 0x8f, 0x9e, 0x31, 0xa1, 0x42, 0xba, 0xff, 0xef, 0xc8, 0x3d, 0xfc, 0x87,
- 0xdb, 0x7a, 0xc5, 0xff, 0xd2, 0x0e, 0x66, 0x0d, 0xc9, 0xcd, 0x58, 0xbf,
- 0xef, 0x71, 0xfb, 0x69, 0xef, 0xcb, 0x17, 0xfc, 0x40, 0xfb, 0xfb, 0xcc,
- 0x05, 0x8b, 0xff, 0xf7, 0xdb, 0x7b, 0x10, 0xf9, 0x3a, 0x6c, 0xef, 0x8b,
- 0x17, 0xfb, 0x37, 0xc9, 0x7a, 0x01, 0x75, 0x8b, 0xfd, 0xd3, 0x73, 0x07,
- 0x00, 0xba, 0xc5, 0xfe, 0xcc, 0x29, 0x84, 0x02, 0xeb, 0x17, 0xf1, 0x4e,
- 0x69, 0xc0, 0xb1, 0x7f, 0xe9, 0xd7, 0xe5, 0xbf, 0x24, 0xcb, 0x17, 0x43,
- 0x98, 0x9d, 0x07, 0x47, 0x3a, 0x57, 0xf9, 0xc9, 0x1c, 0xf8, 0xd8, 0xc2,
- 0xcb, 0xf8, 0xb0, 0xed, 0xdc, 0x16, 0x2f, 0xff, 0x3b, 0x7a, 0x4b, 0xa6,
- 0x3f, 0x07, 0xda, 0xc5, 0x49, 0xfc, 0xfc, 0xba, 0xff, 0x7e, 0x72, 0x13,
- 0x80, 0x58, 0xbf, 0xfc, 0x59, 0xd8, 0x1f, 0x8f, 0xa6, 0xec, 0x0b, 0x14,
- 0x33, 0xfd, 0xe1, 0x95, 0x41, 0x5c, 0x2f, 0x71, 0xed, 0xfa, 0x1d, 0x46,
- 0x42, 0x7a, 0xfa, 0x7a, 0xc3, 0xac, 0x5f, 0x1c, 0x45, 0x05, 0x8b, 0xa4,
- 0xeb, 0x17, 0xbe, 0xf0, 0x8c, 0xdd, 0x11, 0x1d, 0x0d, 0x11, 0xfe, 0x5d,
- 0xbe, 0xf7, 0x05, 0xc5, 0x8a, 0x82, 0xe9, 0xb7, 0xd1, 0xde, 0x5e, 0x41,
- 0x43, 0x83, 0x84, 0x77, 0xb7, 0x86, 0x75, 0x8b, 0xef, 0xc7, 0x86, 0x2c,
- 0x5f, 0x0c, 0x45, 0x05, 0x8b, 0x71, 0xcf, 0x20, 0x32, 0x5b, 0xd8, 0xe0,
- 0x58, 0xbc, 0xe7, 0xed, 0x62, 0xdd, 0x0c, 0xdd, 0x60, 0xe5, 0x82, 0xd5,
- 0x62, 0xff, 0xd9, 0xcf, 0x43, 0x0d, 0x2c, 0x02, 0xc5, 0xe1, 0xe1, 0x2c,
- 0x50, 0x54, 0xfd, 0x1c, 0x67, 0x74, 0xfe, 0x99, 0x1a, 0x02, 0x84, 0xdd,
- 0xf3, 0x7c, 0xee, 0xb1, 0x7f, 0xe3, 0x07, 0xa9, 0xfb, 0x8e, 0x07, 0x58,
- 0xbf, 0xff, 0xff, 0xb4, 0x09, 0xf7, 0x36, 0xfa, 0x18, 0x0d, 0x9c, 0xda,
- 0x3c, 0x1c, 0xbe, 0xb0, 0x80, 0x82, 0x0b, 0xff, 0xff, 0xff, 0xff, 0xfe,
- 0x69, 0x3b, 0x8e, 0x31, 0x73, 0x6e, 0x0c, 0x5a, 0x87, 0xdb, 0x6e, 0x68,
- 0x13, 0xee, 0x6d, 0xf4, 0x30, 0x1b, 0x39, 0xb4, 0x78, 0x39, 0x7d, 0x61,
- 0x01, 0x06, 0x17, 0xff, 0xdc, 0xef, 0x68, 0xf0, 0x72, 0xfa, 0xc2, 0x02,
- 0xc5, 0x7d, 0x35, 0x1f, 0x43, 0xfe, 0xff, 0xff, 0xdb, 0x7d, 0x0c, 0x06,
- 0xce, 0x6d, 0x1e, 0x0e, 0x5f, 0x58, 0x40, 0x42, 0x0b, 0xff, 0xb3, 0xdb,
- 0x7a, 0xfb, 0x7f, 0xec, 0x05, 0x42, 0x16, 0x54, 0x11, 0x97, 0xc7, 0x6b,
- 0xd3, 0x18, 0x4c, 0x55, 0xf9, 0xc8, 0xf9, 0x7d, 0x0f, 0x4b, 0xec, 0xe9,
- 0xfa, 0x58, 0xbf, 0x1f, 0x86, 0x3f, 0x6b, 0x14, 0x34, 0x4f, 0xf9, 0x40,
- 0x32, 0x4a, 0x95, 0xc2, 0xfe, 0xc8, 0xb9, 0x2f, 0x72, 0xfe, 0xc8, 0xa0,
- 0xda, 0xe2, 0xc5, 0xfa, 0x39, 0xf3, 0x44, 0xb1, 0x7c, 0x1f, 0x27, 0x16,
- 0x2b, 0xa3, 0xcd, 0xec, 0xaa, 0xfb, 0x9b, 0x75, 0x8b, 0x17, 0xdf, 0xe9,
- 0xb8, 0xb1, 0x52, 0x7d, 0xae, 0x49, 0xe2, 0x5b, 0xff, 0xfe, 0x0c, 0x7f,
- 0x98, 0x7b, 0x30, 0xce, 0x16, 0x7b, 0xcd, 0x1a, 0xc5, 0xcf, 0xda, 0xc5,
- 0xb1, 0x62, 0xcf, 0x1a, 0x24, 0x9d, 0xa7, 0x78, 0xc5, 0xe6, 0x2c, 0x58,
- 0xbf, 0x6b, 0x4e, 0x09, 0x58, 0xa8, 0x1e, 0x1b, 0x8d, 0xd0, 0x55, 0xda,
- 0x2d, 0x4d, 0x3e, 0x28, 0x71, 0xac, 0x64, 0xef, 0x3f, 0x50, 0xd9, 0x69,
- 0xc4, 0xcd, 0x52, 0x83, 0xde, 0x76, 0x60, 0x0a, 0xe1, 0x76, 0x92, 0x8c,
- 0xcb, 0x93, 0x8a, 0xde, 0x3a, 0x14, 0x3a, 0x4c, 0x85, 0xf8, 0x6f, 0x57,
- 0x05, 0x36, 0x05, 0x8b, 0xec, 0x06, 0xa5, 0x62, 0xf1, 0x86, 0x18, 0x91,
- 0x79, 0xc8, 0x69, 0x01, 0x0d, 0x0d, 0xf6, 0x6b, 0x3c, 0xb1, 0x5f, 0x44,
- 0x98, 0x10, 0xf8, 0x5d, 0x7d, 0xf6, 0x78, 0x2c, 0x5f, 0xe2, 0xcf, 0xf8,
- 0xa4, 0x0b, 0x17, 0xff, 0xf3, 0x45, 0xce, 0x09, 0xf4, 0x28, 0xe4, 0xd0,
- 0xcb, 0xcb, 0x17, 0xff, 0x11, 0x64, 0x73, 0xdc, 0x21, 0x27, 0x58, 0xaf,
- 0xa2, 0x94, 0x36, 0x0b, 0xc5, 0x30, 0x58, 0xbe, 0xd6, 0x98, 0xeb, 0x16,
- 0xe0, 0xcd, 0xfb, 0x0e, 0x54, 0x11, 0x13, 0xe6, 0x3b, 0xc7, 0x8c, 0x6b,
- 0x15, 0x1a, 0x74, 0x45, 0x1b, 0x07, 0x88, 0xef, 0xda, 0xce, 0xa7, 0xeb,
- 0x17, 0xb6, 0x9b, 0xb2, 0xb1, 0x7b, 0xce, 0x35, 0x8a, 0xd1, 0xe0, 0xf0,
- 0x92, 0xfe, 0xeb, 0xf2, 0x59, 0x12, 0xc5, 0xe8, 0x36, 0xea, 0xc5, 0x49,
- 0xe7, 0xc4, 0x5f, 0x7f, 0x8d, 0xef, 0xda, 0x9c, 0xed, 0x62, 0xf8, 0x0d,
- 0xa3, 0x52, 0x2f, 0xb5, 0xa6, 0x8d, 0x62, 0xdd, 0x49, 0xe4, 0x39, 0x25,
- 0xfb, 0x5f, 0xc3, 0x89, 0x62, 0xfd, 0x9a, 0xcc, 0x89, 0x62, 0x98, 0xf4,
- 0x43, 0x29, 0xbf, 0x3f, 0xf6, 0x8e, 0x56, 0x2a, 0x0b, 0x8d, 0x63, 0x30,
- 0xc8, 0xf1, 0x0d, 0x37, 0x66, 0xad, 0x38, 0xb9, 0x11, 0x3f, 0xf1, 0xe3,
- 0xc4, 0x57, 0xe7, 0xd6, 0xb3, 0xb5, 0x8b, 0xff, 0xde, 0xfb, 0x38, 0x33,
- 0x43, 0x92, 0x82, 0xc5, 0xff, 0xee, 0xf6, 0xf6, 0x09, 0x2e, 0x9e, 0x32,
- 0x75, 0x8a, 0x94, 0x60, 0xe1, 0x49, 0x24, 0xdf, 0xa7, 0x81, 0x94, 0x16,
- 0x2f, 0x74, 0xd0, 0x58, 0xbf, 0xd3, 0xe7, 0xd6, 0xb3, 0xb5, 0x8a, 0xda,
- 0x7a, 0x5f, 0x1e, 0xbf, 0xf7, 0x59, 0xac, 0x6e, 0x7e, 0x77, 0xac, 0x5f,
- 0xf9, 0xfb, 0x71, 0xbf, 0x7a, 0x63, 0x56, 0x2f, 0xd3, 0xbb, 0x1e, 0x18,
- 0xb1, 0x7f, 0xff, 0xf3, 0xb7, 0x9b, 0xfd, 0x36, 0xd8, 0x37, 0xdc, 0xbd,
- 0x0c, 0xd6, 0x2c, 0x5d, 0x9f, 0x58, 0xbb, 0x37, 0x56, 0x2a, 0x23, 0x63,
- 0xf1, 0x7a, 0xfa, 0x31, 0x5e, 0x14, 0x77, 0xe6, 0x03, 0x90, 0x16, 0x2f,
- 0xf4, 0xf7, 0xc9, 0xf4, 0x8d, 0x62, 0x80, 0x7b, 0x64, 0x4f, 0x7f, 0xfd,
- 0xfc, 0x6d, 0x43, 0xec, 0x2e, 0xbf, 0x80, 0x58, 0xbd, 0xc0, 0xf9, 0xb5,
- 0x1e, 0x99, 0x08, 0x2f, 0x10, 0xd0, 0xd5, 0x6a, 0xf6, 0x48, 0x74, 0x1f,
- 0xa0, 0xfa, 0x3e, 0x6b, 0xb9, 0x05, 0x8b, 0xfa, 0x0d, 0xe6, 0x28, 0x2c,
- 0x5f, 0xdc, 0x66, 0x8d, 0xbe, 0xb1, 0x6d, 0x49, 0xed, 0xc0, 0xb6, 0xff,
- 0xff, 0xff, 0xa7, 0x93, 0xe8, 0xf0, 0xcd, 0x67, 0xdc, 0x3e, 0x61, 0xae,
- 0x40, 0x92, 0x98, 0xbf, 0x2b, 0x17, 0xc2, 0x7c, 0x8d, 0x62, 0xf1, 0xf2,
- 0x35, 0x8b, 0xd0, 0x6d, 0xe4, 0x78, 0x21, 0x91, 0xdf, 0xb9, 0xf7, 0xea,
- 0x56, 0x2f, 0xcf, 0x19, 0x8f, 0x05, 0x8a, 0x94, 0xe1, 0x48, 0x9f, 0xd0,
- 0xd6, 0x30, 0xd4, 0x32, 0x9b, 0xfe, 0xe7, 0xe5, 0xf5, 0xac, 0xed, 0x62,
- 0xff, 0xff, 0xc6, 0xf7, 0x0f, 0x61, 0x7b, 0x9b, 0x79, 0xcc, 0xd6, 0x13,
- 0xc1, 0x62, 0xb1, 0x15, 0x4c, 0x75, 0x7c, 0x0f, 0x64, 0x6b, 0x16, 0x3a,
- 0xc5, 0x49, 0xb6, 0x39, 0x25, 0xff, 0xfe, 0x00, 0x9c, 0xba, 0x32, 0x74,
- 0x59, 0xdc, 0x3d, 0x3d, 0xac, 0x5f, 0xfc, 0x10, 0x65, 0x22, 0xeb, 0x0d,
- 0x6d, 0x2c, 0x5e, 0xd3, 0xf1, 0x62, 0xec, 0x31, 0x62, 0xa4, 0xff, 0x46,
- 0x91, 0xc1, 0xdb, 0xe9, 0x7d, 0x71, 0x62, 0xf7, 0xbf, 0x2b, 0x15, 0x87,
- 0xdb, 0xf2, 0xe7, 0x22, 0xbf, 0x7e, 0x49, 0xfe, 0xb1, 0x7f, 0x47, 0xf7,
- 0xf6, 0xa5, 0x62, 0xfb, 0x3d, 0x3f, 0x58, 0xbd, 0x0c, 0xe2, 0xc5, 0xe9,
- 0xef, 0x8b, 0x17, 0xf8, 0x7f, 0x98, 0x9d, 0xfb, 0x58, 0xbc, 0xde, 0xe2,
- 0xc5, 0xf7, 0x04, 0x50, 0x58, 0xbf, 0x13, 0xfa, 0x12, 0xb1, 0x5d, 0x1f,
- 0x3f, 0x63, 0xbc, 0x23, 0xbd, 0xf0, 0x6f, 0x58, 0xa8, 0xd3, 0x28, 0x18,
- 0xee, 0x87, 0x8a, 0x13, 0x9b, 0xa6, 0x37, 0xdf, 0xed, 0xf7, 0x16, 0x2f,
- 0x6c, 0xb1, 0xab, 0x17, 0xf7, 0xa7, 0x79, 0x3f, 0x6b, 0x15, 0x27, 0xa3,
- 0xd9, 0x0d, 0x41, 0x55, 0xd0, 0xcb, 0x74, 0x4f, 0xf2, 0xf7, 0x8d, 0x28,
- 0x94, 0xfc, 0xf1, 0x7e, 0x11, 0x0d, 0xe3, 0x58, 0xbf, 0xfe, 0xfb, 0x38,
- 0x30, 0xa7, 0xbe, 0x67, 0x7e, 0x58, 0xb1, 0xa7, 0x3f, 0x9f, 0x14, 0xdf,
- 0xfd, 0x9a, 0x01, 0xdb, 0x81, 0xf2, 0x71, 0x62, 0xf4, 0xf7, 0xb8, 0xb1,
- 0x7d, 0xc2, 0x63, 0x56, 0x2b, 0x47, 0x89, 0xe2, 0x1b, 0xec, 0x1b, 0xc1,
- 0x62, 0x86, 0x78, 0x86, 0x91, 0x5f, 0xfc, 0x69, 0x93, 0xaf, 0xcb, 0x3f,
- 0xb8, 0xb1, 0x7c, 0x72, 0x98, 0x96, 0x2f, 0xff, 0xbe, 0xd0, 0x6d, 0x38,
- 0x3c, 0x52, 0x7e, 0x2c, 0x5f, 0x7a, 0x74, 0x09, 0x3f, 0x2e, 0x88, 0xee,
- 0xdc, 0xe2, 0xc5, 0xff, 0x73, 0xaf, 0xb8, 0xc2, 0x81, 0x5d, 0x8d, 0x62,
- 0x8d, 0x44, 0xeb, 0x9c, 0xf8, 0x6e, 0xa5, 0x54, 0xf4, 0x0a, 0x72, 0x19,
- 0xac, 0x46, 0xf1, 0xaa, 0xde, 0xd8, 0x88, 0x0b, 0x17, 0x8e, 0x2e, 0x2c,
- 0x5f, 0x31, 0xf0, 0x96, 0x2d, 0x2e, 0x6f, 0xfc, 0x3d, 0x7e, 0x90, 0xc9,
- 0xe0, 0xb1, 0x7f, 0xfb, 0x4e, 0x5e, 0xc0, 0x6c, 0xc8, 0xc7, 0x2b, 0x17,
- 0xff, 0x14, 0x80, 0x62, 0x98, 0xe7, 0xb8, 0x2c, 0x5f, 0xd0, 0xd4, 0xc1,
- 0xf4, 0xb1, 0x7e, 0xf7, 0x02, 0xa6, 0xf9, 0x62, 0xc7, 0x58, 0xa9, 0x3c,
- 0x1c, 0x2f, 0xbd, 0xe9, 0x31, 0x62, 0xf7, 0xc3, 0xd2, 0xc5, 0x40, 0xde,
- 0xf8, 0x7a, 0xf7, 0xb0, 0x6b, 0x17, 0xfc, 0x2d, 0x1a, 0xed, 0xc6, 0xde,
- 0xb1, 0x7e, 0xd0, 0x0e, 0xdc, 0x58, 0xb8, 0x1b, 0x76, 0x4f, 0x94, 0x33,
- 0xcb, 0x67, 0x68, 0xb6, 0x28, 0x41, 0x5f, 0x3f, 0x45, 0x8b, 0x17, 0xf3,
- 0x7d, 0xb3, 0xbf, 0x2c, 0x50, 0xd3, 0xb1, 0xed, 0x74, 0xf0, 0xd7, 0x22,
- 0xdf, 0x11, 0x52, 0xc5, 0xf0, 0x3d, 0x80, 0x58, 0xbe, 0xe7, 0x1b, 0x7a,
- 0xc5, 0xff, 0xfb, 0x08, 0xd7, 0xe7, 0xdd, 0x80, 0x79, 0xee, 0x0b, 0x15,
- 0x27, 0xf7, 0xd1, 0x2d, 0xff, 0xbe, 0xdd, 0xf3, 0x08, 0xdc, 0x25, 0x8b,
- 0xff, 0xf9, 0xa2, 0xe7, 0x04, 0xfa, 0x14, 0x72, 0x68, 0x65, 0xe5, 0x8b,
- 0x73, 0xa4, 0x4f, 0xfc, 0xfe, 0xf8, 0xe4, 0x52, 0xb1, 0x7f, 0xcc, 0x3f,
- 0xcc, 0x33, 0xbf, 0x2c, 0x5f, 0xf7, 0x53, 0xbe, 0x78, 0xc0, 0xed, 0x62,
- 0xc6, 0xca, 0x26, 0x06, 0x43, 0x87, 0x55, 0x88, 0xf7, 0x78, 0x61, 0x5f,
- 0xbc, 0xfe, 0x14, 0xac, 0x5f, 0xdf, 0x91, 0x05, 0xf6, 0x8d, 0x62, 0xff,
- 0xfe, 0xfb, 0x7b, 0xef, 0x00, 0xc6, 0xf1, 0x8f, 0xec, 0x75, 0x8b, 0xff,
- 0x37, 0xa1, 0x80, 0xe1, 0x60, 0x16, 0x28, 0x6b, 0xd5, 0x78, 0x50, 0x6a,
- 0x67, 0x68, 0xcd, 0x28, 0x82, 0x25, 0x0d, 0x06, 0x7e, 0x13, 0xc5, 0x1d,
- 0xc7, 0x09, 0xbc, 0x50, 0x23, 0x5d, 0xeb, 0xd7, 0xb6, 0x7b, 0x95, 0x8b,
- 0xfd, 0xf2, 0x9e, 0xda, 0x7e, 0xb1, 0x7f, 0x3f, 0x80, 0x19, 0x41, 0x62,
- 0xba, 0x3e, 0x2f, 0x99, 0xd0, 0x51, 0xbe, 0x26, 0x99, 0xd1, 0xf8, 0x46,
- 0xa4, 0x32, 0xdc, 0x96, 0xa0, 0x6a, 0x9b, 0x47, 0xf1, 0xa8, 0x7d, 0x1d,
- 0x5f, 0xe4, 0x0f, 0x38, 0x10, 0x52, 0xe0, 0x78, 0xa7, 0xe6, 0x11, 0x4f,
- 0x68, 0x6c, 0xc3, 0x24, 0x38, 0x41, 0xdf, 0xf9, 0xd8, 0x62, 0xf7, 0x23,
- 0xc3, 0x16, 0x2e, 0xd8, 0x89, 0x62, 0xfd, 0xcc, 0x36, 0x78, 0xb1, 0x7e,
- 0xd9, 0xc2, 0x73, 0x56, 0x2f, 0xdd, 0x9d, 0xc8, 0x0b, 0x17, 0x9f, 0xfa,
- 0x58, 0xad, 0xa7, 0xe3, 0x25, 0x7a, 0x29, 0xbf, 0xb7, 0x38, 0xc5, 0xdc,
- 0x16, 0x2f, 0xdf, 0x7e, 0x36, 0x96, 0x2f, 0xfc, 0xfa, 0xd9, 0x6f, 0xe3,
- 0xf6, 0x05, 0x8b, 0xfd, 0x3a, 0xd4, 0xc1, 0xfe, 0xb1, 0x7e, 0x0c, 0xbf,
- 0x9d, 0xac, 0x57, 0x47, 0xba, 0x03, 0x3b, 0xff, 0xf3, 0x7a, 0x4f, 0x9d,
- 0xfa, 0x4e, 0x1e, 0x9c, 0x0b, 0x17, 0xcc, 0x4e, 0x35, 0x8b, 0xff, 0xfb,
- 0xdc, 0xc1, 0x05, 0xf0, 0xcc, 0x6d, 0xf9, 0x09, 0x25, 0x8b, 0xfe, 0xe4,
- 0xeb, 0xd2, 0x10, 0x6c, 0xb1, 0x50, 0x4c, 0x4c, 0x6a, 0xe4, 0x43, 0xc6,
- 0x0b, 0xff, 0xfb, 0x3f, 0xb7, 0x0e, 0xdf, 0x9d, 0xbc, 0xe6, 0x10, 0x16,
- 0x2f, 0xfe, 0x6d, 0x4c, 0x3f, 0x31, 0x10, 0x8d, 0x58, 0xaf, 0xa2, 0x93,
- 0x8b, 0xd7, 0xfe, 0x8e, 0x62, 0x29, 0xe6, 0x4c, 0x16, 0x2e, 0xeb, 0x65,
- 0x62, 0xfe, 0x37, 0xd3, 0xf9, 0xe2, 0xc5, 0xff, 0x70, 0xb3, 0xdc, 0x9d,
- 0x46, 0xb1, 0x7f, 0x87, 0xbb, 0xc9, 0x88, 0x5a, 0x58, 0xbf, 0x37, 0x7c,
- 0x7e, 0xd6, 0x2f, 0xff, 0xd9, 0xee, 0x49, 0xfb, 0xe3, 0x0f, 0xf8, 0xc6,
- 0xac, 0x57, 0xd1, 0x02, 0x45, 0x57, 0xfb, 0x07, 0x9a, 0x84, 0xe9, 0x62,
- 0xf7, 0xdb, 0xcb, 0x15, 0x29, 0xf8, 0x40, 0xfd, 0x87, 0x22, 0x2f, 0x73,
- 0xa0, 0x42, 0xeb, 0x84, 0x41, 0x99, 0xdf, 0x9f, 0xf9, 0xdf, 0x96, 0x2f,
- 0xfc, 0xfe, 0xe4, 0xe1, 0x0f, 0xf2, 0xb1, 0x7d, 0xd7, 0xe4, 0x4b, 0x15,
- 0xf3, 0xe1, 0xf1, 0xed, 0xff, 0x9c, 0xa3, 0x33, 0x08, 0x7f, 0x95, 0x8b,
- 0x9a, 0x35, 0x8a, 0xc3, 0xd7, 0x23, 0xfb, 0xfc, 0x2e, 0xe1, 0xc0, 0xe7,
- 0x71, 0x62, 0xf7, 0x53, 0xb8, 0xb1, 0x7f, 0xa2, 0xfb, 0xeb, 0x4c, 0x35,
- 0x8a, 0xc3, 0xd6, 0x72, 0x1b, 0xfc, 0xfd, 0x87, 0xa6, 0x3e, 0x2c, 0x5f,
- 0xce, 0x51, 0x9d, 0xfc, 0xb1, 0x44, 0x7c, 0x7c, 0x35, 0xbe, 0x6f, 0xb9,
- 0xd6, 0x2f, 0xf8, 0x8b, 0x23, 0xf7, 0xa4, 0xeb, 0x15, 0x05, 0x56, 0x59,
- 0x08, 0xa8, 0x9e, 0x74, 0x40, 0x50, 0x90, 0xe4, 0x20, 0xfc, 0x42, 0x19,
- 0x15, 0xfd, 0x14, 0x1b, 0x50, 0xd8, 0x16, 0x2e, 0xd8, 0xc2, 0xab, 0x17,
- 0xb8, 0xc6, 0x2c, 0x5f, 0xe3, 0x5c, 0x39, 0x00, 0x67, 0x58, 0xbf, 0xd0,
- 0x6d, 0x43, 0x3e, 0xeb, 0x17, 0xf7, 0xb9, 0x14, 0x1c, 0x96, 0x2f, 0xcf,
- 0xde, 0x7d, 0xd6, 0x2a, 0x4f, 0x5c, 0x45, 0xf6, 0xd6, 0xd4, 0xd5, 0x82,
- 0xd9, 0xae, 0x10, 0x9a, 0x3d, 0x11, 0xb9, 0x42, 0x2a, 0xf8, 0xf3, 0xae,
- 0x2c, 0x5f, 0xfe, 0x91, 0xfc, 0x46, 0x87, 0x23, 0xf8, 0xb8, 0xb1, 0x6d,
- 0xc1, 0x9f, 0x88, 0x64, 0x77, 0x64, 0x6b, 0x15, 0x27, 0x89, 0x85, 0x97,
- 0xf4, 0x7c, 0x98, 0x85, 0xa5, 0x8b, 0xfa, 0x77, 0x7a, 0xfc, 0xc6, 0xb1,
- 0x7b, 0xcf, 0xc5, 0x8b, 0xfe, 0x14, 0x01, 0xf9, 0x62, 0x8d, 0x62, 0xb1,
- 0x17, 0x66, 0x98, 0xb1, 0x99, 0x0e, 0xdd, 0xb0, 0x9d, 0x62, 0xff, 0xff,
- 0xe2, 0xeb, 0x0a, 0x4c, 0xf1, 0xaf, 0xc1, 0xcb, 0xeb, 0xe6, 0x38, 0xd6,
- 0x2e, 0x7e, 0xd6, 0x2d, 0xe9, 0x44, 0x67, 0x1d, 0x2f, 0xb0, 0xf3, 0xb8,
- 0xb1, 0x7f, 0xfe, 0x71, 0x88, 0xd1, 0x06, 0x27, 0x0e, 0x2d, 0xa0, 0xf2,
- 0xc5, 0x4a, 0x6a, 0x8d, 0x0a, 0x9e, 0x14, 0x08, 0x96, 0xfe, 0x0e, 0x45,
- 0xd0, 0x8e, 0xb1, 0x73, 0x12, 0xc5, 0xf4, 0x24, 0xba, 0x58, 0xa1, 0x9b,
- 0x9c, 0x16, 0xb4, 0x4b, 0x17, 0xc1, 0x57, 0x9e, 0xd6, 0x2d, 0x24, 0x6e,
- 0xbc, 0x27, 0x5b, 0x4f, 0xfd, 0x96, 0xaf, 0xa4, 0x18, 0x4b, 0x15, 0x06,
- 0x7f, 0x28, 0xe1, 0x35, 0x86, 0x06, 0x99, 0x74, 0x51, 0xdc, 0x27, 0xda,
- 0x33, 0x68, 0xa1, 0xc3, 0xa9, 0x42, 0x67, 0x96, 0x50, 0xf1, 0xec, 0x02,
- 0x32, 0x02, 0x86, 0xdf, 0x23, 0x8f, 0x12, 0x09, 0x90, 0xe9, 0xd9, 0x23,
- 0xbe, 0x38, 0x59, 0xb0, 0xb6, 0x05, 0x8b, 0xbd, 0xc5, 0x8a, 0x63, 0xcc,
- 0x88, 0xd2, 0xf8, 0x39, 0x33, 0x8b, 0x17, 0x03, 0xcb, 0x17, 0x03, 0xeb,
- 0x17, 0xda, 0xd6, 0x71, 0x62, 0xec, 0x89, 0x62, 0xd0, 0xda, 0x89, 0x08,
- 0xc9, 0x4e, 0x30, 0xe3, 0x01, 0x91, 0xdf, 0x79, 0xcb, 0x16, 0x2f, 0xb7,
- 0x64, 0xa0, 0xb1, 0x4c, 0x78, 0xc1, 0x90, 0xdf, 0x13, 0xfb, 0x8b, 0x17,
- 0xb4, 0xfb, 0xd6, 0x2f, 0xfb, 0x37, 0x5d, 0x86, 0x2f, 0x71, 0x62, 0xfd,
- 0xa1, 0xe6, 0x12, 0xc5, 0xf1, 0xba, 0x73, 0x16, 0x2f, 0xfc, 0xd9, 0xf9,
- 0xdf, 0xcf, 0xcf, 0x6b, 0x15, 0x87, 0xcd, 0xb8, 0x4b, 0x7f, 0x77, 0xa1,
- 0x77, 0xe8, 0x2c, 0x5f, 0xf3, 0xf6, 0x66, 0x10, 0xff, 0x2b, 0x17, 0x4c,
- 0x6b, 0x15, 0x89, 0xd9, 0x44, 0x45, 0xa1, 0xf7, 0x3c, 0xe4, 0x23, 0x44,
- 0x48, 0x61, 0x90, 0x67, 0x57, 0xe3, 0x3d, 0xec, 0x8d, 0x62, 0xfe, 0x79,
- 0x06, 0x77, 0x05, 0x8a, 0x58, 0xbf, 0xc5, 0xac, 0xe6, 0x37, 0xd6, 0x28,
- 0x2a, 0x6f, 0xb0, 0x32, 0xff, 0xfa, 0x1e, 0x2c, 0x7f, 0x16, 0x7b, 0xd8,
- 0x62, 0xc5, 0xfd, 0xa6, 0xf7, 0xf2, 0x0b, 0x17, 0xbf, 0x3b, 0xd6, 0x2b,
- 0x47, 0x9b, 0xe2, 0xeb, 0x9f, 0x75, 0x62, 0xff, 0x7b, 0x35, 0x1c, 0xfb,
- 0x8b, 0x15, 0x03, 0xcf, 0x71, 0xab, 0xff, 0xec, 0x1b, 0x7b, 0x0f, 0xf9,
- 0x9e, 0x8e, 0xeb, 0x17, 0x66, 0xf5, 0x8b, 0xfe, 0xeb, 0xf8, 0x33, 0xb6,
- 0xb1, 0x62, 0xfe, 0x9e, 0x7e, 0x48, 0xd5, 0x8a, 0x94, 0x68, 0x46, 0x9f,
- 0x83, 0x3a, 0x3a, 0xbd, 0xb3, 0x86, 0xac, 0x5f, 0xd3, 0x3a, 0xfc, 0xef,
- 0x58, 0xbf, 0xa2, 0x0f, 0x22, 0x1c, 0x16, 0x2f, 0x98, 0xa2, 0xdc, 0x58,
- 0xbe, 0x29, 0xee, 0x0b, 0x14, 0xe7, 0xf6, 0x03, 0x2f, 0x13, 0x5f, 0xa7,
- 0xdc, 0xcf, 0x2c, 0x5f, 0xd3, 0xbf, 0x3f, 0xf9, 0x58, 0xbe, 0xf7, 0x32,
- 0x25, 0x8f, 0x9a, 0xfb, 0xfb, 0xe3, 0x6d, 0xf2, 0x35, 0x8a, 0x1a, 0x2e,
- 0xf1, 0x5d, 0xcd, 0x2f, 0xb4, 0xcf, 0x1a, 0xc5, 0xe6, 0xc0, 0x2c, 0x56,
- 0x1b, 0xfe, 0x11, 0xdf, 0xe6, 0x16, 0xbf, 0x9b, 0xf8, 0xb1, 0x7f, 0xff,
- 0xb3, 0xcd, 0xdc, 0x0a, 0x76, 0xf9, 0xb3, 0x74, 0x7f, 0xc5, 0x8b, 0xec,
- 0xf3, 0x71, 0x62, 0xfe, 0xd8, 0xa2, 0x2d, 0x82, 0x31, 0x2c, 0x56, 0xe2,
- 0x3e, 0x22, 0x36, 0xe3, 0x2f, 0x88, 0xaf, 0xfc, 0x27, 0x3f, 0x18, 0x9f,
- 0x46, 0xac, 0x5f, 0x3f, 0x9c, 0x96, 0x2a, 0x0c, 0x91, 0xb1, 0xc7, 0xa9,
- 0x8f, 0x06, 0x95, 0xf4, 0xd9, 0xd9, 0x23, 0x42, 0x72, 0x27, 0x1d, 0x43,
- 0xc4, 0xe7, 0x9f, 0x21, 0x04, 0x2a, 0x8a, 0x1d, 0x3c, 0x6d, 0xf4, 0x63,
- 0x06, 0x20, 0xee, 0x9f, 0xdf, 0xbd, 0xf6, 0x20, 0x2c, 0x5f, 0x7b, 0xcd,
- 0x05, 0x8b, 0xfb, 0x0c, 0x2d, 0xfa, 0x82, 0xc5, 0xff, 0xfb, 0xcd, 0xc8,
- 0xf0, 0xce, 0x34, 0x64, 0xfd, 0xf9, 0x62, 0xff, 0xa1, 0x9e, 0xc1, 0xb1,
- 0x01, 0x62, 0xfa, 0x19, 0x3d, 0xac, 0x5f, 0xa7, 0x58, 0x4c, 0xb1, 0x78,
- 0xcc, 0xfa, 0xc5, 0xfd, 0x9a, 0xd0, 0x8d, 0xd2, 0xc5, 0xfc, 0x50, 0x31,
- 0xff, 0xc5, 0x8b, 0xf1, 0xbf, 0x72, 0x65, 0x8b, 0x73, 0x0f, 0x5d, 0x8b,
- 0xee, 0x36, 0x0b, 0x17, 0xda, 0x0e, 0x4c, 0x58, 0xbe, 0x19, 0x39, 0xab,
- 0x17, 0xff, 0x34, 0x1f, 0x59, 0xbf, 0xbe, 0x9b, 0xb5, 0x8a, 0x94, 0x48,
- 0xc6, 0x4b, 0xe2, 0x3b, 0xb0, 0x72, 0xab, 0x4e, 0x32, 0x3c, 0x31, 0xed,
- 0x66, 0x23, 0x8f, 0x91, 0xb9, 0x31, 0x0f, 0x7a, 0x10, 0xfb, 0x24, 0xc1,
- 0xc2, 0xaa, 0xfb, 0x07, 0xc3, 0x16, 0x2c, 0xdc, 0x46, 0xb6, 0xec, 0x2c,
- 0xaf, 0xf0, 0x05, 0xc6, 0x2e, 0xe0, 0xb1, 0x7f, 0x01, 0xb4, 0xdd, 0x81,
- 0x62, 0xcf, 0xb8, 0x7c, 0x91, 0x1a, 0xd8, 0x0b, 0x17, 0xf8, 0x78, 0x4c,
- 0x67, 0xc4, 0xb1, 0x7f, 0xfd, 0xf6, 0x9f, 0x30, 0x26, 0x01, 0x0c, 0x30,
- 0xc4, 0x8b, 0xff, 0x9a, 0x7c, 0x09, 0x80, 0x43, 0x0c, 0x31, 0x22, 0xb1,
- 0x13, 0xff, 0x55, 0xa8, 0xd1, 0xeb, 0xe8, 0x69, 0xdf, 0xef, 0x89, 0xce,
- 0x37, 0x3a, 0xc5, 0x11, 0xee, 0xf8, 0xa6, 0xf6, 0x61, 0xa9, 0x16, 0x02,
- 0xc5, 0xf3, 0x7e, 0x4e, 0xb1, 0x77, 0x32, 0x4d, 0xa1, 0xa2, 0x54, 0x33,
- 0xfd, 0xf2, 0x8d, 0xe0, 0x3f, 0x96, 0x2f, 0xbd, 0xc1, 0x6e, 0x2c, 0x5f,
- 0x4e, 0x9b, 0x7a, 0xc5, 0x39, 0xf4, 0x08, 0x74, 0x32, 0x7b, 0xfe, 0xd3,
- 0xf5, 0xb7, 0xf2, 0x19, 0x2c, 0x5e, 0x14, 0xe9, 0x62, 0xef, 0x70, 0x67,
- 0xb5, 0x11, 0xed, 0xf1, 0xa2, 0x07, 0x16, 0x2e, 0x21, 0x2a, 0x21, 0x92,
- 0xfe, 0x93, 0xcf, 0x35, 0x8b, 0x15, 0x03, 0xd1, 0x88, 0x92, 0xf7, 0xe6,
- 0x35, 0x8b, 0xf7, 0xa6, 0x06, 0x9d, 0x62, 0xff, 0x08, 0xba, 0xfc, 0xf7,
- 0xba, 0xb1, 0x78, 0xc3, 0x0c, 0x48, 0xbd, 0x85, 0xd2, 0x40, 0x43, 0x43,
- 0x7f, 0xec, 0x8f, 0x06, 0xf0, 0x29, 0x8d, 0x62, 0xa5, 0x1e, 0x4c, 0x54,
- 0x05, 0xa2, 0x2f, 0xbf, 0xfd, 0x9a, 0xf7, 0xb3, 0x85, 0x39, 0xa8, 0x2c,
- 0x5f, 0x9b, 0xff, 0xcf, 0x2c, 0x5a, 0x76, 0x9f, 0x8f, 0x12, 0x6f, 0xbe,
- 0xe4, 0x6a, 0xc5, 0x0c, 0xf3, 0x3c, 0x53, 0x7f, 0x77, 0x0e, 0x13, 0xf4,
- 0xb1, 0x7c, 0xfb, 0x9e, 0xe2, 0xc5, 0xe2, 0x0b, 0x7b, 0x1a, 0xc5, 0x61,
- 0xff, 0x76, 0x60, 0xe4, 0xd7, 0x05, 0xb0, 0xb6, 0xb1, 0x7e, 0x87, 0x59,
- 0xdf, 0x96, 0x2f, 0xd9, 0xef, 0x0a, 0x35, 0x8b, 0xff, 0x34, 0x7f, 0x67,
- 0x87, 0x9a, 0x35, 0x8b, 0x40, 0x2d, 0xa2, 0xe6, 0x04, 0x84, 0x57, 0xe2,
- 0xab, 0xf7, 0x30, 0x6f, 0xf5, 0x8b, 0xe1, 0xff, 0x3a, 0x58, 0xbc, 0xfb,
- 0x92, 0xb1, 0x7e, 0xc1, 0xfd, 0xf7, 0x16, 0x2f, 0xc5, 0x83, 0x93, 0xac,
- 0x56, 0xc0, 0xc8, 0x70, 0x98, 0xd9, 0x23, 0x84, 0xf0, 0xe1, 0x15, 0x90,
- 0x89, 0x34, 0xbf, 0xb7, 0x68, 0x88, 0xf5, 0x18, 0x81, 0xe1, 0xef, 0xf8,
- 0x50, 0x3c, 0x39, 0xc0, 0x90, 0x45, 0x02, 0x24, 0xde, 0x3e, 0x61, 0x5d,
- 0xfc, 0x7c, 0x6d, 0x45, 0x05, 0x8b, 0xff, 0xe3, 0x43, 0x72, 0xfb, 0xc3,
- 0x98, 0x79, 0xdc, 0x58, 0xa9, 0x44, 0x1b, 0x17, 0xdf, 0x4f, 0x84, 0x1a,
- 0xc5, 0xef, 0x34, 0xac, 0x5f, 0x9a, 0x63, 0x73, 0xac, 0x58, 0x96, 0x2e,
- 0x63, 0xac, 0x56, 0x1a, 0x82, 0x11, 0xa6, 0x44, 0x59, 0x0e, 0x09, 0x42,
- 0xfc, 0x53, 0xdc, 0xf1, 0x62, 0xff, 0xd8, 0xc4, 0xfe, 0xe1, 0x92, 0x4b,
- 0x17, 0xbe, 0xfa, 0x93, 0xe5, 0xe1, 0x45, 0xf3, 0x6a, 0x7c, 0xb1, 0x7f,
- 0xfe, 0x29, 0xd6, 0x9a, 0x63, 0xc0, 0x09, 0xcb, 0xa5, 0x8b, 0xee, 0x64,
- 0xc1, 0x62, 0x86, 0x89, 0x9e, 0x88, 0x89, 0x56, 0xf7, 0xf3, 0xb5, 0x8b,
- 0xf0, 0xf4, 0xd2, 0x75, 0x8b, 0x4c, 0x0f, 0x18, 0x87, 0xaf, 0xa0, 0xd3,
- 0xd2, 0xc5, 0xdd, 0x81, 0x62, 0xfe, 0x3c, 0xf0, 0x0d, 0xd2, 0xc5, 0xee,
- 0x49, 0xa0, 0x3c, 0x8e, 0x0c, 0xdf, 0xc5, 0x9b, 0xad, 0x31, 0x2c, 0x5f,
- 0xd9, 0xa0, 0x01, 0x89, 0x62, 0x9c, 0xf7, 0x44, 0x61, 0x7f, 0x17, 0x9a,
- 0x32, 0x95, 0x8b, 0x71, 0x62, 0xed, 0x82, 0x35, 0x8a, 0x93, 0xdd, 0x81,
- 0x6b, 0x89, 0x5f, 0x6b, 0x53, 0x05, 0x8b, 0xfc, 0xc3, 0xd6, 0x0d, 0xce,
- 0xb1, 0x7d, 0x17, 0x27, 0x8b, 0x16, 0xc3, 0x9e, 0xb8, 0x0c, 0xef, 0xb0,
- 0xe1, 0x8d, 0x62, 0xfe, 0x63, 0x7d, 0xc7, 0xed, 0x62, 0xfc, 0x6c, 0x52,
- 0x5e, 0x58, 0xa6, 0x4c, 0x7f, 0xef, 0x44, 0x4f, 0xc2, 0x41, 0x18, 0x5f,
- 0xff, 0xf6, 0xf9, 0x1b, 0x13, 0xe8, 0xd2, 0x76, 0x2c, 0x00, 0xb8, 0xb1,
- 0x7f, 0xef, 0x87, 0xcc, 0xd7, 0x4e, 0xfd, 0x2a, 0x20, 0xc2, 0xff, 0xe8,
- 0xe4, 0xdc, 0xd7, 0xbd, 0x39, 0xc5, 0x8a, 0x1a, 0x25, 0x49, 0x3e, 0xa5,
- 0x31, 0xd6, 0x87, 0xdd, 0xff, 0xbe, 0x27, 0x37, 0x3d, 0xec, 0xfa, 0xc5,
- 0xfe, 0xdf, 0x25, 0x81, 0xe1, 0xd6, 0x2f, 0xf7, 0xe4, 0xbc, 0x07, 0xf2,
- 0xc5, 0xff, 0xe8, 0x6a, 0x61, 0xd7, 0xdb, 0xe4, 0xe7, 0x58, 0xae, 0x1f,
- 0xf0, 0x8c, 0xef, 0xff, 0xe3, 0xc9, 0x74, 0xe4, 0x0c, 0x1f, 0x08, 0x4f,
- 0x05, 0x8b, 0xc4, 0x23, 0x56, 0x2f, 0xfb, 0xa6, 0x39, 0xdb, 0x6f, 0x04,
- 0xb1, 0x7f, 0x9f, 0xbe, 0x07, 0xaf, 0xba, 0xc5, 0xff, 0xd8, 0x63, 0x83,
- 0x6b, 0x87, 0x13, 0xf9, 0x62, 0xdc, 0x01, 0xff, 0x91, 0xb5, 0xfc, 0xff,
- 0xc2, 0x3e, 0x2c, 0x5f, 0x0b, 0xf9, 0xd2, 0xc5, 0x41, 0x57, 0x38, 0xc9,
- 0xd9, 0x03, 0x50, 0xb3, 0x39, 0x17, 0xd6, 0x88, 0x7b, 0xd0, 0xbc, 0xde,
- 0x4f, 0xb2, 0x59, 0x7f, 0xf7, 0xb9, 0x1c, 0x86, 0x53, 0xf6, 0x8d, 0x62,
- 0xff, 0x72, 0x75, 0x0e, 0x9a, 0x35, 0x8b, 0xef, 0xb3, 0x81, 0x62, 0x89,
- 0x13, 0xfc, 0x47, 0xf1, 0xb5, 0xcd, 0xe5, 0x8b, 0xff, 0xc3, 0xfe, 0x75,
- 0x9a, 0xe7, 0x7e, 0x0c, 0xeb, 0x17, 0xda, 0xd3, 0xc2, 0x4f, 0x9b, 0x82,
- 0xf7, 0xf0, 0x8d, 0x2c, 0x8c, 0x4b, 0x15, 0x28, 0xfd, 0xc8, 0x4a, 0xfc,
- 0xe2, 0xff, 0xfc, 0x5e, 0x17, 0xc3, 0xf3, 0x13, 0xf7, 0xe1, 0x4a, 0xc5,
- 0xef, 0x8b, 0x71, 0x62, 0xff, 0xcc, 0x5e, 0xe3, 0x0c, 0x1d, 0x81, 0x62,
- 0xff, 0xfb, 0xed, 0x9b, 0xf3, 0x8f, 0x06, 0x29, 0xde, 0xb1, 0x7f, 0xee,
- 0xfa, 0x6c, 0x30, 0x31, 0xbc, 0x6b, 0x15, 0xc4, 0x4a, 0xf9, 0x46, 0xff,
- 0xb0, 0xba, 0xfb, 0x00, 0x3f, 0x2c, 0x59, 0xf8, 0x7b, 0xdb, 0xc8, 0xea,
- 0x34, 0xd7, 0x35, 0x19, 0x9d, 0x4a, 0xe3, 0x44, 0x25, 0x1b, 0x31, 0x98,
- 0x5d, 0x5c, 0x51, 0xbe, 0xde, 0xc2, 0x35, 0x62, 0xff, 0x38, 0xff, 0x99,
- 0xdf, 0x96, 0x2b, 0x0f, 0x44, 0xd1, 0xda, 0xed, 0x97, 0xbf, 0xf8, 0x48,
- 0x93, 0xf7, 0x23, 0x4c, 0xf5, 0x22, 0xd7, 0x76, 0x15, 0xb7, 0xe9, 0x28,
- 0x40, 0xeb, 0x17, 0x8a, 0x4c, 0x58, 0xbe, 0x6e, 0x98, 0x6b, 0x17, 0x83,
- 0x81, 0xd6, 0x2a, 0x08, 0x87, 0xc2, 0x8f, 0x0e, 0x88, 0x8e, 0xff, 0xf7,
- 0x7e, 0x96, 0x2f, 0x6a, 0x7c, 0xfe, 0x58, 0xbe, 0x9f, 0x34, 0x4b, 0x17,
- 0xf0, 0x9c, 0x31, 0x38, 0x6b, 0x15, 0x11, 0xe9, 0xe8, 0x8e, 0xf3, 0xe4,
- 0x16, 0x2e, 0xdf, 0x8b, 0x15, 0x87, 0xb0, 0xc4, 0x6e, 0x39, 0x7f, 0xf3,
- 0xc3, 0x6e, 0x7b, 0x3f, 0x3a, 0x02, 0xc5, 0xc0, 0x02, 0xc5, 0xff, 0x75,
- 0xf6, 0xd1, 0x37, 0xb8, 0xb1, 0x50, 0x44, 0xc1, 0xd1, 0x80, 0x31, 0x7f,
- 0xfb, 0x0c, 0x21, 0x3f, 0x1b, 0x37, 0xbe, 0x96, 0x2f, 0xe6, 0xff, 0xf0,
- 0x0e, 0xb1, 0x79, 0xff, 0xc5, 0x8a, 0x94, 0x4a, 0x81, 0x2c, 0x45, 0xb7,
- 0xf7, 0x22, 0xfb, 0x19, 0xe5, 0x8b, 0xfd, 0xc6, 0xc2, 0xce, 0xcc, 0x58,
- 0xbf, 0xff, 0xd9, 0xef, 0x3e, 0x8a, 0x7b, 0x80, 0x7a, 0x01, 0xdb, 0x8b,
- 0x15, 0x88, 0xc8, 0xdc, 0x31, 0x39, 0xa5, 0xf8, 0x5d, 0xf5, 0x87, 0x58,
- 0xbf, 0xcc, 0x66, 0x10, 0xff, 0x2b, 0x17, 0xcf, 0xd9, 0x0d, 0x62, 0x8e,
- 0x7a, 0xc0, 0x33, 0xbf, 0xfd, 0x3e, 0xe0, 0xba, 0xdb, 0xf7, 0x29, 0x95,
- 0x8b, 0x09, 0x62, 0xfc, 0x00, 0xc0, 0xf0, 0x58, 0xaf, 0x9b, 0xc7, 0x12,
- 0xbe, 0xdc, 0xdb, 0xb9, 0x05, 0x8b, 0xff, 0xc4, 0x3f, 0xe7, 0x61, 0xb9,
- 0x78, 0x86, 0xb1, 0x68, 0x49, 0xfb, 0xb1, 0x65, 0xff, 0xfc, 0xc6, 0x7d,
- 0xfa, 0x92, 0x1e, 0x77, 0xef, 0xb8, 0xd6, 0x2f, 0xfa, 0x3f, 0x43, 0x37,
- 0x1c, 0x80, 0xb1, 0x7d, 0x17, 0xdf, 0xcb, 0x15, 0x87, 0xc2, 0xc7, 0xb7,
- 0xfb, 0x07, 0xfc, 0xef, 0x38, 0xb1, 0x79, 0x8c, 0xdc, 0x58, 0xbf, 0xd9,
- 0xbf, 0x9e, 0xf4, 0x9d, 0x62, 0xb4, 0x7a, 0xff, 0x21, 0xa9, 0x57, 0x4a,
- 0x33, 0x2c, 0x84, 0x09, 0xa4, 0x4d, 0x08, 0x88, 0xa1, 0x2f, 0xa2, 0x6f,
- 0xc2, 0xf8, 0x88, 0x39, 0x08, 0xbb, 0xff, 0x41, 0x8a, 0x01, 0xff, 0xf2,
- 0x35, 0x8b, 0x8c, 0x65, 0x8b, 0xd8, 0x5d, 0x2c, 0x5d, 0x27, 0x58, 0xb1,
- 0xfa, 0x36, 0x9b, 0x23, 0xb5, 0x27, 0xee, 0xc9, 0x97, 0xfd, 0x83, 0x35,
- 0xe2, 0xfc, 0xc6, 0xb1, 0x7e, 0x17, 0xa3, 0xe1, 0xab, 0x17, 0xff, 0x3c,
- 0x7c, 0x71, 0xcc, 0x73, 0x09, 0x58, 0xbf, 0xb3, 0x9b, 0x39, 0xa9, 0x58,
- 0xae, 0xd3, 0xb4, 0xd4, 0x2d, 0xfe, 0x40, 0x47, 0x9c, 0x2c, 0xd9, 0x45,
- 0xbe, 0x69, 0x28, 0x96, 0x2a, 0x36, 0xe8, 0x86, 0x10, 0xaf, 0x1c, 0x24,
- 0xf2, 0x19, 0x7d, 0x3b, 0x76, 0x4c, 0xd4, 0xc4, 0xa8, 0xa1, 0xfd, 0xa3,
- 0xc3, 0xc3, 0xd5, 0xe1, 0x88, 0x08, 0x62, 0xf2, 0x72, 0x73, 0xd2, 0x96,
- 0x0c, 0x60, 0xbf, 0xdc, 0xe6, 0x10, 0x36, 0x71, 0x62, 0xf8, 0x9b, 0x76,
- 0x56, 0x2e, 0x04, 0xac, 0x5e, 0x2c, 0xe2, 0xc5, 0x11, 0xb3, 0x0c, 0x5e,
- 0xd1, 0x2c, 0x5f, 0xdc, 0xc2, 0x06, 0xce, 0x2c, 0x56, 0xd4, 0x78, 0xe1,
- 0xb3, 0xab, 0x80, 0x87, 0x82, 0x77, 0xde, 0x77, 0x25, 0x8a, 0xde, 0x7d,
- 0x66, 0x25, 0x5f, 0xfc, 0x2e, 0xb3, 0x5a, 0x98, 0x72, 0x40, 0xb1, 0x7f,
- 0x80, 0xe0, 0x9d, 0xc9, 0x82, 0xc5, 0xff, 0xd0, 0x6c, 0xfb, 0xff, 0xf3,
- 0xdf, 0x16, 0x2f, 0xf7, 0xf0, 0x65, 0x38, 0x4b, 0x15, 0x04, 0x56, 0x76,
- 0x6c, 0x04, 0x5b, 0xb0, 0x96, 0x2f, 0x69, 0xfa, 0x58, 0xa1, 0x9b, 0x43,
- 0x45, 0xaf, 0xfe, 0x8e, 0x28, 0x4e, 0xa3, 0xff, 0x6f, 0xb8, 0xb1, 0x7e,
- 0x11, 0xe7, 0x3c, 0xb1, 0x7d, 0x80, 0x90, 0x2c, 0x50, 0x0f, 0x28, 0x8a,
- 0x2a, 0x34, 0x6d, 0x39, 0x17, 0xa1, 0x2f, 0x58, 0xa9, 0x99, 0xe1, 0xe4,
- 0x28, 0xcf, 0xee, 0x23, 0x56, 0x2f, 0xff, 0x14, 0x7b, 0x62, 0x62, 0xc1,
- 0xe1, 0x1a, 0xb1, 0x7f, 0xc2, 0x10, 0x64, 0xdb, 0x41, 0xe5, 0x8b, 0xd1,
- 0x02, 0x56, 0x2f, 0xfb, 0x7c, 0xf7, 0xb3, 0x3a, 0xc2, 0x58, 0xad, 0x8c,
- 0xf7, 0x30, 0x7a, 0xfe, 0x6e, 0xf7, 0x7f, 0x3e, 0x58, 0xbf, 0x0b, 0x8c,
- 0xdd, 0xac, 0x5f, 0x8b, 0x3d, 0xf6, 0x58, 0xbc, 0x1e, 0x4a, 0xc5, 0xc2,
- 0x35, 0x62, 0xfd, 0x24, 0x42, 0x3a, 0xc5, 0x7c, 0xf0, 0x03, 0x19, 0xbd,
- 0xe9, 0x0d, 0x62, 0xff, 0x60, 0xf4, 0xfd, 0x78, 0x0b, 0x17, 0xec, 0x21,
- 0xfe, 0x56, 0x2b, 0x0f, 0xeb, 0xe3, 0xc6, 0x1a, 0xde, 0x86, 0x71, 0x62,
- 0xfe, 0xeb, 0xf3, 0xe1, 0x06, 0xb1, 0x52, 0xac, 0x16, 0x34, 0xd3, 0x61,
- 0x33, 0xb8, 0x4d, 0x11, 0x96, 0x8a, 0x5c, 0x9c, 0x97, 0x79, 0x09, 0xdf,
- 0x17, 0x86, 0x3b, 0x7c, 0x3d, 0x3c, 0x16, 0x2f, 0xff, 0xf6, 0x13, 0xfb,
- 0x99, 0xa0, 0x02, 0x73, 0xbf, 0x71, 0x96, 0x2e, 0x84, 0xac, 0x5b, 0x65,
- 0x62, 0xb6, 0x9a, 0xcc, 0x17, 0xa1, 0xa2, 0xbb, 0xd0, 0x8c, 0xa9, 0x47,
- 0xcb, 0xc3, 0x46, 0xf0, 0xe4, 0x96, 0x2b, 0x6b, 0xe8, 0x20, 0x85, 0x10,
- 0x66, 0xb0, 0x01, 0x8e, 0x37, 0x91, 0xc2, 0xcb, 0x29, 0x36, 0x86, 0xc6,
- 0x1f, 0xd4, 0xbd, 0x1e, 0xe1, 0x28, 0xd4, 0x89, 0xbf, 0xc7, 0x3e, 0xf5,
- 0xd2, 0x10, 0x25, 0x35, 0x14, 0xa8, 0xbf, 0x1d, 0x8a, 0x58, 0xe9, 0x91,
- 0xd0, 0x86, 0x4d, 0x7b, 0xb8, 0xf7, 0xac, 0x5f, 0x84, 0x6b, 0x4c, 0x6b,
- 0x17, 0xfb, 0xaf, 0xb9, 0x48, 0xbb, 0x58, 0xbf, 0x75, 0xf9, 0xef, 0x75,
- 0x62, 0xe1, 0x05, 0xd6, 0x2f, 0xdf, 0x7d, 0x1d, 0x96, 0x2f, 0x07, 0x3b,
- 0x8b, 0x17, 0xf0, 0x7d, 0x7e, 0x7b, 0xdd, 0x58, 0xad, 0xa8, 0xc8, 0x81,
- 0x77, 0x43, 0x9c, 0x28, 0x11, 0x0d, 0xe6, 0x2c, 0x58, 0xbf, 0xbe, 0xc1,
- 0x7f, 0xcc, 0x6b, 0x16, 0x1c, 0x0f, 0x3b, 0xa1, 0xbb, 0x80, 0x62, 0xc5,
- 0xfd, 0xf9, 0x6d, 0xc3, 0xb2, 0xc5, 0x6d, 0x3c, 0x9e, 0x86, 0x6a, 0x35,
- 0x4b, 0x23, 0x2a, 0xee, 0x1f, 0xad, 0x09, 0xbf, 0x39, 0x5f, 0xd8, 0x66,
- 0x61, 0x1a, 0xb1, 0x73, 0x46, 0xb1, 0x74, 0x86, 0xb1, 0x79, 0xf3, 0x8b,
- 0x17, 0xe7, 0x8d, 0x85, 0x05, 0x8b, 0xc0, 0x04, 0xac, 0x54, 0x0f, 0xe8,
- 0xe3, 0x1f, 0x1c, 0x22, 0x9b, 0xd8, 0x46, 0xac, 0x53, 0x26, 0x30, 0x72,
- 0xe7, 0x84, 0x96, 0xe9, 0xdd, 0xff, 0xb9, 0xa9, 0xf1, 0x39, 0xce, 0xcb,
- 0x17, 0xff, 0xa7, 0x9c, 0x93, 0xe7, 0x9b, 0x9f, 0x75, 0x8b, 0xcc, 0x5e,
- 0x58, 0xae, 0x8f, 0x97, 0xe9, 0x37, 0xfe, 0xfb, 0x7e, 0x73, 0x50, 0xd4,
- 0x16, 0x2f, 0xfe, 0x3c, 0xfb, 0x8f, 0x9a, 0x01, 0xf1, 0x62, 0xfe, 0x29,
- 0x81, 0xe5, 0x96, 0x28, 0x07, 0xe0, 0x48, 0x97, 0xef, 0xcc, 0x73, 0xf5,
- 0x8b, 0xf6, 0x9c, 0xf3, 0xd2, 0xc5, 0xfb, 0x37, 0x96, 0x71, 0x62, 0xff,
- 0x79, 0xb7, 0xb7, 0xa1, 0x29, 0x16, 0x3a, 0xc5, 0xfd, 0x84, 0x6e, 0xa4,
- 0x23, 0x1e, 0x38, 0x66, 0xb7, 0x61, 0xab, 0x15, 0xb5, 0x55, 0xb6, 0x42,
- 0x8f, 0xa2, 0x36, 0x85, 0x7c, 0x44, 0x2e, 0x52, 0x45, 0x3c, 0x70, 0xd9,
- 0x46, 0xbf, 0xfc, 0xfb, 0xe7, 0x06, 0xf0, 0xcf, 0xb1, 0x8b, 0x17, 0x85,
- 0xdc, 0x16, 0x2f, 0x49, 0x4a, 0xc5, 0xed, 0x3e, 0xf5, 0x8b, 0xf0, 0xf5,
- 0xac, 0xe2, 0xc5, 0x40, 0xf2, 0x1c, 0x7e, 0xa0, 0x8e, 0xed, 0x25, 0x9c,
- 0x7c, 0x98, 0xef, 0xf1, 0x40, 0xb0, 0xf3, 0xd2, 0xc5, 0xe8, 0x9f, 0xcb,
- 0x17, 0x8a, 0x4e, 0xb1, 0x52, 0x6e, 0xa2, 0x1e, 0xbf, 0x37, 0xca, 0x60,
- 0xb1, 0x7d, 0xa7, 0x68, 0xd6, 0x2e, 0xe3, 0x2c, 0x53, 0x1b, 0xa7, 0x23,
- 0xb6, 0x2c, 0x5e, 0xcc, 0x35, 0x62, 0xc7, 0x19, 0xae, 0xdd, 0x11, 0xbf,
- 0xf7, 0x03, 0xd7, 0xa0, 0xc5, 0xee, 0x2c, 0x54, 0xa7, 0xc7, 0x87, 0x8c,
- 0xdb, 0xa2, 0x1f, 0xb0, 0xba, 0x68, 0x8a, 0xaf, 0xf9, 0xb7, 0xe6, 0xba,
- 0x77, 0xe9, 0x51, 0x86, 0x97, 0xb6, 0x45, 0xe5, 0x8b, 0x9b, 0x7a, 0xc5,
- 0xff, 0xba, 0xfc, 0x93, 0xfb, 0x99, 0x1a, 0xc5, 0xf6, 0x9a, 0x2e, 0x2c,
- 0x5e, 0xd3, 0x86, 0xb1, 0x58, 0x88, 0x2d, 0x20, 0x39, 0x25, 0xd8, 0x6a,
- 0xc5, 0xff, 0xd2, 0x76, 0x1e, 0x11, 0xbf, 0x93, 0xac, 0x57, 0xcf, 0x73,
- 0xc3, 0x17, 0xd8, 0x79, 0x0d, 0x62, 0x86, 0x9e, 0xa7, 0x49, 0x27, 0x21,
- 0xe4, 0x26, 0xfd, 0x08, 0xad, 0xe4, 0x57, 0x07, 0xf5, 0x8b, 0xf1, 0x39,
- 0x81, 0x9d, 0x62, 0xf9, 0xfb, 0xf6, 0x2c, 0x59, 0xa2, 0x3c, 0xde, 0x15,
- 0x51, 0xa8, 0x8e, 0xfb, 0x35, 0xff, 0xef, 0x7e, 0x79, 0x3f, 0x96, 0x8e,
- 0x4d, 0x58, 0xbf, 0xe1, 0xb9, 0xde, 0x12, 0xdd, 0x2c, 0x53, 0x22, 0x10,
- 0x92, 0xef, 0xf7, 0xe6, 0x28, 0x36, 0xa0, 0xb1, 0x7e, 0x28, 0x8a, 0x4e,
- 0xb1, 0x7f, 0xbc, 0xc6, 0x44, 0x4e, 0x62, 0xc5, 0xdf, 0x65, 0x8b, 0xfe,
- 0x97, 0x87, 0xe6, 0x37, 0x8d, 0x62, 0xff, 0xb3, 0x7c, 0x8f, 0xf8, 0xde,
- 0x58, 0xbd, 0xc7, 0x02, 0xc5, 0x11, 0xeb, 0xf8, 0xea, 0xb7, 0x11, 0x92,
- 0x71, 0x7f, 0x42, 0x46, 0xfe, 0x10, 0x60, 0x04, 0xf6, 0xb1, 0x7c, 0x7f,
- 0x67, 0x4b, 0x17, 0xb4, 0xf0, 0x58, 0xbe, 0x8e, 0x7b, 0x95, 0x8a, 0x93,
- 0xe5, 0xc2, 0x46, 0x1d, 0xb8, 0xcf, 0x2c, 0x5f, 0x40, 0x05, 0x8b, 0x17,
- 0xff, 0x80, 0x4e, 0x7d, 0x64, 0xf7, 0x06, 0x3a, 0xc5, 0x49, 0xf6, 0x08,
- 0x8a, 0xe6, 0x8d, 0x62, 0xa5, 0x59, 0xa8, 0xc8, 0x70, 0xd7, 0xb2, 0x86,
- 0x87, 0xfc, 0x47, 0x1f, 0x84, 0xb3, 0x96, 0x14, 0x21, 0x7c, 0x43, 0x7f,
- 0xff, 0xff, 0x37, 0xbf, 0x87, 0xf9, 0x66, 0xf7, 0xeb, 0xec, 0x1f, 0x98,
- 0xba, 0xcf, 0x7d, 0x96, 0x2f, 0xbd, 0xa9, 0xde, 0xb1, 0x43, 0x45, 0x83,
- 0xc2, 0x2e, 0xfc, 0xde, 0xe0, 0xb7, 0x16, 0x2f, 0xa7, 0xb1, 0x6e, 0x2c,
- 0x5f, 0xff, 0xba, 0x17, 0xcd, 0x62, 0x9f, 0xc9, 0x92, 0x58, 0xb1, 0x51,
- 0x1f, 0xe9, 0x13, 0xdf, 0x30, 0xf7, 0x59, 0x62, 0xa5, 0x31, 0x7f, 0x93,
- 0xbc, 0x2a, 0x4c, 0x22, 0xbf, 0xef, 0xcc, 0x18, 0xb0, 0xf2, 0xb1, 0x7c,
- 0xe3, 0x84, 0x6b, 0x17, 0xfd, 0x9e, 0xfe, 0x1c, 0x9f, 0xcb, 0x17, 0xf6,
- 0xf6, 0xd7, 0x73, 0xb8, 0xb1, 0x43, 0x3e, 0xcc, 0x38, 0xaf, 0xa2, 0xc4,
- 0xa1, 0x21, 0x7f, 0xd0, 0x6f, 0x4f, 0xdc, 0xbc, 0xb1, 0x71, 0x01, 0x62,
- 0xfc, 0x79, 0xea, 0x31, 0xac, 0x5f, 0x42, 0x4e, 0xeb, 0x17, 0xed, 0x00,
- 0xed, 0xc5, 0x8b, 0xbd, 0xcd, 0xa8, 0xc5, 0x0a, 0x9c, 0x60, 0xbb, 0x95,
- 0x86, 0x45, 0x52, 0x9a, 0x38, 0xa1, 0xd9, 0x6e, 0x2c, 0x5f, 0xd3, 0x1e,
- 0x13, 0x1a, 0xb1, 0x5a, 0x3c, 0x0e, 0x09, 0x5f, 0x37, 0x52, 0x75, 0x8b,
- 0xff, 0x13, 0xfe, 0x40, 0x13, 0x5c, 0xe2, 0x45, 0xef, 0xe0, 0xd6, 0x2a,
- 0x4f, 0x79, 0x90, 0x6f, 0xa7, 0xd0, 0x75, 0x8b, 0xff, 0xf3, 0xfa, 0x73,
- 0x53, 0xb5, 0xcb, 0x0e, 0x2f, 0xac, 0x5f, 0x70, 0x45, 0xe5, 0x8b, 0xf0,
- 0x65, 0x0f, 0xe2, 0xc5, 0x31, 0xe6, 0x00, 0x8e, 0xe8, 0xe3, 0x58, 0xb0,
- 0x16, 0x2d, 0x2b, 0x16, 0xc1, 0x9a, 0x3e, 0x84, 0xaa, 0x35, 0xca, 0x21,
- 0xca, 0x2f, 0xc6, 0x8d, 0x11, 0x1e, 0x10, 0x3f, 0x20, 0x22, 0x2f, 0x42,
- 0x84, 0x44, 0x3b, 0xcf, 0x6f, 0x1e, 0x7a, 0x58, 0xbf, 0x3c, 0x4d, 0x9c,
- 0x58, 0xbe, 0xe4, 0xea, 0x0b, 0x15, 0xb4, 0xf2, 0xf8, 0x51, 0x7d, 0xdf,
- 0x26, 0x0b, 0x14, 0x33, 0xc8, 0x39, 0x25, 0x4a, 0x34, 0xde, 0x16, 0x37,
- 0x9f, 0xf2, 0xb1, 0x7f, 0x87, 0xf9, 0xf7, 0xa4, 0xeb, 0x15, 0xf3, 0xd0,
- 0x21, 0xcb, 0x85, 0x1a, 0xc5, 0xf4, 0x87, 0xba, 0x35, 0x8b, 0xee, 0x37,
- 0xa5, 0x62, 0xee, 0xe1, 0x19, 0xe4, 0xf6, 0x4f, 0x79, 0xbb, 0xe2, 0xc5,
- 0x61, 0xe7, 0xb1, 0x8d, 0x62, 0x3c, 0x98, 0x87, 0xf0, 0xb1, 0xb9, 0xa2,
- 0x58, 0xbe, 0xd7, 0xb3, 0xeb, 0x17, 0x67, 0x4b, 0x16, 0xe2, 0xc7, 0x8b,
- 0x8b, 0xf0, 0xe4, 0xee, 0x35, 0x8a, 0xc3, 0xc9, 0x62, 0x1b, 0xe8, 0xe1,
- 0x27, 0x58, 0xbd, 0xec, 0xfa, 0xc5, 0xf4, 0x7e, 0x63, 0x56, 0x2a, 0x53,
- 0x22, 0x61, 0x8d, 0x42, 0x11, 0xc8, 0x04, 0x48, 0x18, 0xed, 0xff, 0xed,
- 0xae, 0xd9, 0xc9, 0x8f, 0x09, 0x8d, 0x58, 0xbb, 0x7c, 0xac, 0x50, 0xcf,
- 0x90, 0xe9, 0x77, 0xfb, 0x47, 0x9e, 0xfc, 0xfd, 0x2c, 0x5f, 0xff, 0xc5,
- 0x9e, 0xfe, 0x43, 0x3a, 0x9e, 0xbc, 0x4e, 0x75, 0x8a, 0xc4, 0x59, 0xb1,
- 0x17, 0x0d, 0xaf, 0xf9, 0xa0, 0xdc, 0xee, 0x0c, 0x4b, 0x17, 0xf8, 0x0d,
- 0x0d, 0x69, 0x8c, 0x58, 0xad, 0x1f, 0x71, 0x1c, 0xdf, 0x31, 0xe6, 0x25,
- 0x8b, 0xff, 0xb8, 0xdd, 0x96, 0x45, 0xa9, 0xf7, 0x16, 0x2f, 0xb2, 0x31,
- 0x41, 0x62, 0xf9, 0xb5, 0x31, 0xac, 0x53, 0x23, 0x46, 0x22, 0x10, 0x11,
- 0x98, 0x8c, 0x19, 0x25, 0xff, 0xa6, 0x13, 0x17, 0x3f, 0x9b, 0xf8, 0xb1,
- 0x7f, 0xa7, 0x4e, 0x45, 0x86, 0xac, 0x5f, 0x48, 0x58, 0x16, 0x05, 0x8b,
- 0x15, 0xc4, 0x53, 0x79, 0x0b, 0x74, 0xca, 0xf9, 0xf4, 0xfd, 0xac, 0x5f,
- 0xc0, 0x8d, 0xe1, 0x3b, 0x8b, 0x17, 0xed, 0xb3, 0x14, 0x98, 0xb1, 0x78,
- 0x63, 0x95, 0x8b, 0x98, 0x96, 0x28, 0xd4, 0x5a, 0x76, 0x46, 0x73, 0x21,
- 0x16, 0x06, 0x3b, 0x52, 0xa8, 0x99, 0xa1, 0xe4, 0xf0, 0xe7, 0xba, 0x63,
- 0x58, 0xbe, 0xd4, 0xe1, 0xd6, 0x2e, 0xc3, 0x16, 0x29, 0x38, 0x86, 0x0b,
- 0xfb, 0x81, 0xce, 0xa4, 0xe9, 0xc4, 0x30, 0x52, 0x71, 0x0c, 0x14, 0x9c,
- 0x43, 0x05, 0x27, 0x10, 0xc1, 0x49, 0xc4, 0x30, 0x54, 0x11, 0x7e, 0xc3,
- 0x40, 0x3d, 0x10, 0xd6, 0xc8, 0xd6, 0xe8, 0xd5, 0xdf, 0xc4, 0xe2, 0x18,
- 0x2f, 0xe7, 0x7f, 0x45, 0x27, 0x4e, 0x21, 0x83, 0x69, 0xa5, 0xb0, 0x5d,
- 0x38, 0x86, 0x0a, 0x4e, 0x21, 0x82, 0x93, 0x88, 0x60, 0xa8, 0x1b, 0x46,
- 0x1a, 0xa4, 0xe2, 0x18, 0x29, 0x38, 0x86, 0x0a, 0x4e, 0x21, 0x82, 0x93,
- 0x88, 0x60, 0xa4, 0xe2, 0x18, 0x29, 0x38, 0x86, 0x0a, 0x8d, 0x13, 0x83,
- 0x1a, 0x61, 0xa0, 0x0d, 0x70, 0x6b, 0x78, 0xd5, 0x27, 0x10, 0xc1, 0x49,
- 0xc4, 0x30, 0x54, 0x0d, 0xa7, 0x06, 0xa9, 0x38, 0x86, 0x0a, 0x4e, 0x21,
- 0x82, 0x93, 0x88, 0x60, 0xa4, 0xe2, 0x18, 0x2a, 0x07, 0xd0, 0x01, 0xaf,
- 0x0d, 0x6e, 0x8d, 0x52, 0x71, 0x0c, 0x14, 0x9c, 0x43, 0x05, 0x27, 0x10,
- 0xc1, 0x49, 0xc4, 0x30, 0x54, 0x67, 0xd0, 0x68, 0xd6, 0x86, 0xbe, 0x35,
- 0x63, 0x53, 0x88, 0x60, 0xa4, 0xe2, 0x18, 0x29, 0x38, 0x86, 0x0a, 0x4e,
- 0x21, 0x82, 0x93, 0x88, 0x60, 0xa1, 0x9f, 0x47, 0x63, 0x40, 0x1a, 0x10,
- 0xd5, 0x27, 0x10, 0xc1, 0x49, 0xc4, 0x30, 0x52, 0x71, 0x0c, 0x17, 0xef,
- 0xc8, 0x39, 0x89, 0xc4, 0x30, 0x52, 0x71, 0x0c, 0x15, 0x04, 0x4f, 0x74,
- 0x35, 0xf1, 0xa7, 0x1a, 0x01, 0xb5, 0xba, 0x4e, 0x21, 0x82, 0x93, 0x88,
- 0x60, 0xa4, 0xe2, 0x18, 0x29, 0x38, 0x86, 0x0a, 0x4e, 0x21, 0x82, 0xa0,
- 0x7d, 0x1d, 0x8d, 0x30, 0xd6, 0xf1, 0xaa, 0x4e, 0x21, 0x82, 0x93, 0x88,
- 0x60, 0xa4, 0xe2, 0x18, 0x29, 0x38, 0x86, 0x0a, 0x81, 0xf4, 0x0c, 0x6b,
- 0xe3, 0x44, 0x35, 0x6f, 0xa7, 0x10, 0xc1, 0x49, 0xc4, 0x30, 0x52, 0x71,
- 0x0c, 0x16, 0x82, 0x71, 0x0c, 0x14, 0x9c, 0x43, 0x07, 0x66, 0x82, 0x93,
- 0x88, 0x60, 0xa4, 0xe2, 0x18, 0x29, 0x38, 0x86, 0x0a, 0x4e, 0x21, 0x82,
- 0xa3, 0x47, 0x3c, 0x06, 0x8d, 0x3a, 0xe8, 0xae, 0x21, 0xa0, 0x0d, 0x78,
- 0x6a, 0xd8, 0x9c, 0x43, 0x05, 0x27, 0x10, 0xc1, 0x49, 0xc4, 0x30, 0x5a,
- 0x09, 0xc4, 0x30, 0x52, 0x71, 0x0c, 0x1d, 0x9a, 0x0a, 0x4e, 0x21, 0x82,
- 0x93, 0x88, 0x60, 0xa9, 0x45, 0x9c, 0x06, 0x98, 0xeb, 0x45, 0x67, 0x1a,
- 0xa4, 0xe2, 0x18, 0x29, 0x38, 0x86, 0x0a, 0x4e, 0x21, 0x82, 0x93, 0x88,
- 0x60, 0xa4, 0xe2, 0x18, 0x2a, 0x51, 0x05, 0xd8, 0xd6, 0x86, 0x8e, 0x34,
- 0x43, 0x54, 0x9c, 0x43, 0x05, 0x27, 0x10, 0xc1, 0x49, 0xc4, 0x30, 0x56,
- 0x8f, 0x3b, 0x83, 0x5e, 0x1a, 0xa4, 0xe2, 0x18, 0x29, 0x38, 0x86, 0x0a,
- 0x4e, 0x21, 0x82, 0x8e, 0x79, 0xc4, 0x35, 0xe1, 0xab, 0x1d, 0x38, 0x86,
- 0x0a, 0x4e, 0x21, 0x82, 0x93, 0x88, 0x60, 0xa0, 0x1b, 0x41, 0x0d, 0x52,
- 0x71, 0x0c, 0x14, 0x9c, 0x43, 0x05, 0x27, 0x10, 0xc1, 0x49, 0xc4, 0x30,
- 0x54, 0x9f, 0x44, 0x43, 0x5f, 0x1a, 0x10, 0xd5, 0x4b, 0x31, 0x72, 0x38,
- 0x40, 0xc1, 0x38, 0x6b, 0x19, 0x0b, 0xce, 0xa1, 0x1b, 0xdc, 0x22, 0x5a,
- 0x14, 0xfb, 0x87, 0xd1, 0x42, 0x27, 0x50, 0xdb, 0x3a, 0x57, 0xe1, 0x12,
- 0xf0, 0xa6, 0x01, 0xd9, 0x46, 0x0f, 0xc6, 0x8f, 0x43, 0x48, 0x50, 0xca,
- 0xdf, 0x09, 0x73, 0x1f, 0x76, 0x4b, 0x83, 0x54, 0xdd, 0x84, 0x4d, 0xfa,
- 0x05, 0x39, 0xc4, 0xe2, 0x18, 0x02, 0x27, 0x31, 0x79, 0xa4, 0xe9, 0xc4,
- 0x30, 0x5f, 0x37, 0x4f, 0xa5, 0xe2, 0x18, 0x5e, 0x61, 0xe2, 0xf1, 0x0c,
- 0x2c, 0x13, 0xb4, 0x66, 0xe9, 0x2b, 0xe5, 0x5e, 0x30, 0xad, 0xec, 0xfd,
- 0xe0, 0xe9, 0xf3, 0x17, 0x83, 0x93, 0x16, 0x2a, 0x4f, 0x49, 0xcc, 0xef,
- 0x31, 0x46, 0xb1, 0x7f, 0x31, 0x83, 0xd4, 0xc6, 0xb1, 0x50, 0x3c, 0xdf,
- 0x8e, 0xdd, 0xbe, 0x56, 0x2e, 0x7e, 0xd6, 0x2f, 0xa0, 0xdf, 0x12, 0xc5,
- 0xf4, 0xec, 0xcf, 0x96, 0x2f, 0x36, 0xf0, 0xba, 0xc5, 0xcd, 0xba, 0xb1,
- 0x43, 0x6c, 0x6b, 0xfa, 0x18, 0xee, 0xb0, 0x52, 0x89, 0xb4, 0xe4, 0x5f,
- 0x19, 0x71, 0x82, 0x23, 0xf1, 0x2e, 0xe9, 0x1d, 0xef, 0x8e, 0x0b, 0x17,
- 0xa2, 0x70, 0xd6, 0x28, 0x66, 0xf7, 0x07, 0xaf, 0xcc, 0x42, 0x7f, 0x2c,
- 0x5f, 0xff, 0xfb, 0x30, 0x85, 0xe6, 0xf9, 0x08, 0xd2, 0xce, 0xfd, 0x39,
- 0xa5, 0x8a, 0xc4, 0x59, 0x70, 0x83, 0x64, 0x9e, 0xf7, 0xc5, 0xd2, 0xc5,
- 0xf7, 0xf3, 0x7e, 0x2c, 0x57, 0xcf, 0x0f, 0xc3, 0xf7, 0x80, 0x2e, 0x2c,
- 0x5f, 0xe7, 0x20, 0xe2, 0x83, 0x12, 0xc5, 0xc0, 0x95, 0x8b, 0xfb, 0x4e,
- 0x41, 0xc8, 0x16, 0x2e, 0x7d, 0x2c, 0x59, 0x96, 0x3a, 0x2d, 0xed, 0xd2,
- 0xc5, 0x8e, 0xb1, 0x60, 0x8c, 0x8a, 0x2d, 0x0b, 0xfd, 0x15, 0xc8, 0x43,
- 0x13, 0xbf, 0xbb, 0x87, 0xe4, 0xa3, 0x58, 0xa3, 0xa6, 0xaf, 0xb3, 0x0d,
- 0x6d, 0xd5, 0x1b, 0xff, 0xff, 0x64, 0x3f, 0x3f, 0x63, 0x5d, 0x8a, 0x7e,
- 0xed, 0x06, 0x1a, 0xc5, 0xd0, 0xc5, 0x8b, 0xf8, 0x85, 0xef, 0xe6, 0xf5,
- 0x8b, 0xda, 0x68, 0xd6, 0x2f, 0xf4, 0x9f, 0x22, 0x92, 0x8d, 0x62, 0x96,
- 0x2e, 0x1e, 0xf5, 0x8a, 0xc4, 0x54, 0x68, 0xc3, 0xe3, 0xc0, 0x34, 0x20,
- 0xcb, 0xe3, 0xfe, 0x40, 0xb1, 0x7f, 0xa7, 0xa0, 0xc0, 0x09, 0xed, 0x62,
- 0xb0, 0xf6, 0xb8, 0x47, 0x7f, 0xf6, 0xd7, 0xe8, 0x7f, 0x90, 0x61, 0x01,
- 0x62, 0xff, 0xd9, 0xcc, 0x10, 0x5d, 0xcd, 0xfe, 0x2c, 0x5c, 0x09, 0x58,
- 0xac, 0x45, 0x0f, 0x48, 0xe0, 0x43, 0xa9, 0x5c, 0x8f, 0x81, 0x16, 0x46,
- 0xea, 0xc7, 0x91, 0x34, 0x82, 0x17, 0xfe, 0x85, 0x10, 0xa1, 0x85, 0x7d,
- 0x30, 0xe4, 0xac, 0x5f, 0xfc, 0x45, 0x31, 0x96, 0x36, 0xf9, 0xd9, 0x58,
- 0xbd, 0x3d, 0xf1, 0x62, 0x8e, 0x88, 0x77, 0x22, 0xe2, 0x3d, 0xe7, 0xd4,
- 0xac, 0x5f, 0x6c, 0xb9, 0x01, 0x62, 0xfb, 0xdc, 0xcf, 0x2c, 0x53, 0x1e,
- 0x43, 0x92, 0xdf, 0x9b, 0xbe, 0x3f, 0x6b, 0x15, 0x04, 0x57, 0x1d, 0x93,
- 0x84, 0x17, 0xdb, 0xcf, 0x2c, 0xb1, 0x7e, 0x89, 0x8e, 0xf1, 0x2c, 0x5f,
- 0xf0, 0x6e, 0x3e, 0x61, 0xe7, 0x71, 0x62, 0xf6, 0x76, 0x62, 0xc5, 0x68,
- 0xf7, 0x08, 0xf6, 0xff, 0x66, 0x14, 0x03, 0x21, 0xac, 0x58, 0x18, 0x7a,
- 0x91, 0x10, 0xdf, 0xfe, 0x6d, 0xc1, 0x1a, 0xdd, 0xf3, 0x22, 0x9f, 0x2c,
- 0x5b, 0x71, 0x62, 0xbb, 0x44, 0x69, 0xca, 0x1d, 0x42, 0xf4, 0xfd, 0xd6,
- 0x2e, 0x14, 0xac, 0x5e, 0xcd, 0x41, 0x62, 0x86, 0x6d, 0x37, 0x8b, 0xde,
- 0x1b, 0x92, 0xc5, 0x31, 0xbf, 0x72, 0x3b, 0xee, 0x9c, 0x8d, 0x58, 0xbf,
- 0xff, 0xf6, 0xbd, 0x85, 0x3d, 0x14, 0x9f, 0x9c, 0xc8, 0x7d, 0x88, 0x0b,
- 0x15, 0x28, 0x8f, 0x72, 0x4b, 0xff, 0x9f, 0x5a, 0x70, 0x48, 0x43, 0x0c,
- 0x31, 0x62, 0xf4, 0x18, 0x0b, 0x17, 0xfe, 0x37, 0x3b, 0xf3, 0x7b, 0x42,
- 0x3a, 0xc5, 0x6d, 0x45, 0x4b, 0xa5, 0x78, 0x76, 0xe9, 0x82, 0xc5, 0x49,
- 0xe4, 0x00, 0xc6, 0xa5, 0x71, 0x6f, 0x0c, 0x18, 0x91, 0xe3, 0x67, 0x23,
- 0x0e, 0x42, 0x3f, 0xd0, 0xae, 0x14, 0x62, 0x57, 0xf7, 0x4e, 0x2e, 0x8e,
- 0xcb, 0x17, 0xce, 0x3c, 0xf2, 0xc5, 0xff, 0xc5, 0x8d, 0xf9, 0xec, 0x19,
- 0xee, 0x2c, 0x5b, 0x8b, 0x17, 0xfe, 0x0e, 0x2d, 0xb2, 0x1b, 0xf5, 0x3f,
- 0x58, 0xa8, 0x8f, 0x5c, 0x42, 0x57, 0x11, 0xab, 0x17, 0xff, 0x01, 0xe1,
- 0xcc, 0x87, 0xe4, 0x8d, 0x58, 0xbf, 0x8f, 0xcc, 0x3c, 0xee, 0x2c, 0x54,
- 0x9f, 0xb3, 0x22, 0xdf, 0xe6, 0x37, 0x8c, 0x5d, 0xc1, 0x62, 0xd3, 0xa3,
- 0xd5, 0xf9, 0x05, 0x32, 0x61, 0x5b, 0xb0, 0xe3, 0xa0, 0xab, 0xe1, 0xa4,
- 0xcc, 0xa7, 0xb8, 0xe3, 0x6f, 0x84, 0xaf, 0xa1, 0xcb, 0x5e, 0xc9, 0x46,
- 0xa6, 0xc3, 0xcf, 0xa9, 0x7b, 0xbd, 0xca, 0x60, 0x69, 0xce, 0x4d, 0xc8,
- 0xdc, 0xe2, 0x8d, 0xa3, 0x51, 0xaa, 0x9e, 0x37, 0x2f, 0xcb, 0x93, 0x7a,
- 0xc7, 0xa0, 0x11, 0xc6, 0x94, 0xe8, 0x27, 0x23, 0x0e, 0xf4, 0xe9, 0xc0,
- 0xa1, 0x0b, 0xbc, 0xc3, 0x64, 0x88, 0x38, 0x4d, 0xee, 0xc6, 0x5b, 0x7f,
- 0xdc, 0xf7, 0xc4, 0xf0, 0x84, 0xac, 0x5e, 0x04, 0x78, 0xb1, 0x7f, 0xbd,
- 0x01, 0x0d, 0xc8, 0x0b, 0x17, 0x8f, 0xce, 0x96, 0x2f, 0x17, 0x52, 0xb1,
- 0x7d, 0x9e, 0x7e, 0xd6, 0x2b, 0x69, 0xef, 0xb0, 0xfe, 0x87, 0x6f, 0xfe,
- 0xe6, 0x74, 0x3c, 0xd1, 0x8f, 0xf8, 0x96, 0x2f, 0xfb, 0x86, 0xb9, 0x4e,
- 0x47, 0x2b, 0x17, 0xd0, 0xcd, 0x4a, 0xc5, 0xfc, 0x63, 0xeb, 0x4f, 0xda,
- 0xc5, 0xff, 0xfb, 0x9a, 0xd3, 0x45, 0xcd, 0x4f, 0x9b, 0xa6, 0x1a, 0xc5,
- 0x74, 0x9f, 0x71, 0xe1, 0x27, 0xf3, 0x07, 0x48, 0x01, 0xc9, 0x11, 0x18,
- 0x61, 0x78, 0x9a, 0x25, 0x8b, 0xa1, 0x1a, 0xc5, 0xfa, 0x76, 0x78, 0x22,
- 0x58, 0xbd, 0xe9, 0xe2, 0xc5, 0xf6, 0x1e, 0x7e, 0xb1, 0x62, 0x58, 0xbf,
- 0x0f, 0x30, 0x1c, 0x58, 0xad, 0x93, 0x72, 0x18, 0x8d, 0x74, 0x88, 0x00,
- 0x2d, 0xd7, 0x69, 0x82, 0xc4, 0x32, 0x72, 0xb2, 0x84, 0xed, 0xe8, 0xd8,
- 0x6b, 0x16, 0x12, 0xc5, 0x80, 0xc6, 0xc0, 0x87, 0xac, 0x15, 0x58, 0xbe,
- 0xd3, 0x11, 0xab, 0x17, 0xe1, 0x75, 0xf6, 0xd2, 0xc5, 0xd8, 0x6a, 0xc5,
- 0xbd, 0x27, 0x85, 0xc2, 0xab, 0xfb, 0x3a, 0xfc, 0xf7, 0x05, 0x8b, 0xf8,
- 0xfc, 0x63, 0x7c, 0x62, 0xc5, 0xf7, 0x7f, 0x98, 0x2c, 0x5c, 0x5d, 0x2c,
- 0x54, 0x9b, 0xc7, 0x24, 0xad, 0x8d, 0x35, 0xed, 0x0b, 0x13, 0x2f, 0x89,
- 0xc3, 0x30, 0xdd, 0x6d, 0xbf, 0x67, 0xbd, 0x91, 0xac, 0x5f, 0xf4, 0xf3,
- 0x99, 0xee, 0x64, 0x6b, 0x16, 0xec, 0x8f, 0x8c, 0x32, 0x9b, 0xfa, 0x7b,
- 0x86, 0x6e, 0xc1, 0x62, 0xb0, 0xf6, 0xce, 0x53, 0x77, 0x7e, 0x58, 0xbf,
- 0x61, 0x46, 0xda, 0x58, 0xbf, 0x79, 0xc8, 0x58, 0xb1, 0x7f, 0xb9, 0x87,
- 0x6f, 0x7d, 0xd6, 0x2b, 0x11, 0x37, 0xa1, 0x92, 0x28, 0xf1, 0x3d, 0xfd,
- 0x22, 0xf7, 0xdc, 0x0b, 0x17, 0xbf, 0x23, 0x58, 0xad, 0x1e, 0x5f, 0x0b,
- 0xaf, 0xa1, 0xa2, 0x12, 0xc5, 0x40, 0xf1, 0x7b, 0x22, 0xa9, 0x47, 0x73,
- 0xc3, 0x2e, 0xf6, 0xd3, 0xb2, 0xc5, 0xf6, 0xa7, 0xdc, 0x58, 0xbc, 0x2c,
- 0x25, 0x8b, 0x64, 0x46, 0xff, 0xc4, 0x77, 0xef, 0xb1, 0x49, 0xd6, 0x2c,
- 0x75, 0x8a, 0xc3, 0x72, 0x44, 0xf5, 0x04, 0x6e, 0x92, 0xf7, 0x18, 0x2f,
- 0x6e, 0xea, 0x56, 0x2f, 0xfc, 0x52, 0xf1, 0xf3, 0x37, 0xc9, 0x8b, 0x17,
- 0xfd, 0xf6, 0xd7, 0xdc, 0x2a, 0x61, 0x8b, 0x17, 0xfd, 0xed, 0x4e, 0x76,
- 0x16, 0xf6, 0x30, 0xaa, 0xc5, 0xff, 0xe2, 0x73, 0x38, 0x59, 0xdc, 0x3c,
- 0x28, 0xd6, 0x2f, 0xe6, 0x88, 0xb3, 0x7b, 0xac, 0x5d, 0xc6, 0x58, 0xad,
- 0x1e, 0x37, 0x0b, 0xef, 0xba, 0x7e, 0x9d, 0x62, 0xff, 0x61, 0x43, 0x38,
- 0xff, 0x58, 0xbf, 0xfd, 0xa3, 0x4c, 0x78, 0xcb, 0x37, 0xe9, 0xb8, 0xb1,
- 0x6e, 0x6d, 0x54, 0xe9, 0x25, 0xe3, 0x20, 0xc4, 0x1e, 0xd0, 0x22, 0x4a,
- 0xd4, 0x24, 0xdc, 0x8b, 0xc4, 0x81, 0x99, 0x5f, 0xed, 0x16, 0x0f, 0xf8,
- 0x4b, 0x17, 0xce, 0x42, 0xc5, 0x8b, 0xee, 0x72, 0x4e, 0xb1, 0x7d, 0x31,
- 0x4e, 0x96, 0x28, 0x67, 0x8d, 0xe2, 0x3a, 0xed, 0x35, 0x57, 0x84, 0xd0,
- 0x0c, 0x89, 0x9e, 0xff, 0x8a, 0x5e, 0x3f, 0xce, 0x80, 0xb1, 0x7f, 0x9b,
- 0x45, 0xef, 0x64, 0x6b, 0x17, 0xde, 0x8f, 0x0c, 0x58, 0xb9, 0xf7, 0xac,
- 0x5f, 0xd0, 0x26, 0x87, 0xf1, 0x62, 0xfd, 0x1b, 0x6a, 0x60, 0xb1, 0x46,
- 0xa3, 0x23, 0xb3, 0x48, 0x89, 0x74, 0x32, 0x45, 0xb7, 0xbc, 0xc6, 0xac,
- 0x5f, 0xe7, 0x78, 0xf5, 0x2f, 0xd2, 0xc5, 0xf8, 0x5e, 0xd9, 0xcf, 0x2c,
- 0x5e, 0x1b, 0x1a, 0xb1, 0x52, 0x79, 0x58, 0x59, 0x7f, 0x3f, 0xc3, 0xd3,
- 0x81, 0x62, 0xf6, 0x80, 0x1a, 0xc5, 0xff, 0xcd, 0xe9, 0xf7, 0x3e, 0xed,
- 0xf1, 0x2c, 0x54, 0x9f, 0x1b, 0x8f, 0xdf, 0x11, 0x0a, 0x0b, 0x17, 0xb8,
- 0xc6, 0x2c, 0x5f, 0xe2, 0x17, 0x30, 0xf3, 0xd2, 0xc5, 0xff, 0xbf, 0x3a,
- 0x01, 0x61, 0x8e, 0x05, 0x8b, 0xd9, 0x91, 0x2c, 0x51, 0xa8, 0x90, 0xf9,
- 0xa0, 0x0f, 0xef, 0xbc, 0x09, 0x82, 0xc5, 0x61, 0xea, 0x08, 0xc6, 0xff,
- 0xdf, 0x17, 0x83, 0xf7, 0xb0, 0x80, 0xb1, 0x7a, 0x7b, 0x31, 0x62, 0xfd,
- 0xa1, 0x1d, 0xc9, 0x62, 0xb1, 0x11, 0x1e, 0x41, 0x10, 0xfd, 0xf1, 0xe7,
- 0x23, 0x58, 0xbe, 0xde, 0x53, 0xda, 0xc5, 0xc6, 0x79, 0x62, 0xb0, 0xdf,
- 0x31, 0x2d, 0x32, 0x20, 0x38, 0xc3, 0x7d, 0x25, 0xee, 0x96, 0x2f, 0xda,
- 0x36, 0x37, 0xdc, 0x58, 0xa1, 0xae, 0xd5, 0x64, 0x60, 0x2c, 0x99, 0x10,
- 0xf6, 0x9f, 0x8e, 0x41, 0xf8, 0x49, 0x39, 0x00, 0x08, 0x8a, 0x30, 0x2e,
- 0x42, 0xa7, 0xd0, 0xaf, 0xd9, 0x22, 0x0c, 0x8e, 0xfd, 0xb3, 0xfc, 0x03,
- 0xac, 0x5f, 0xe0, 0x07, 0x84, 0x3f, 0xca, 0xc5, 0x4a, 0x67, 0xa7, 0x86,
- 0xf3, 0x95, 0xdf, 0xdc, 0xc3, 0xb7, 0xe5, 0x62, 0xf7, 0x70, 0xe2, 0xc5,
- 0x76, 0x79, 0x9a, 0x2d, 0xbd, 0xc0, 0x18, 0xb1, 0x7d, 0xdf, 0x27, 0xb5,
- 0x8b, 0xf4, 0x3d, 0xc9, 0x35, 0x62, 0xff, 0xe9, 0xd4, 0xc4, 0x4e, 0x67,
- 0xb3, 0xeb, 0x14, 0xe7, 0xde, 0x45, 0x56, 0x83, 0x22, 0xd0, 0xf0, 0x94,
- 0xa9, 0x4c, 0x8f, 0x08, 0xde, 0x1a, 0x77, 0xfc, 0x61, 0x66, 0xb9, 0xfc,
- 0xe9, 0x62, 0xff, 0xe2, 0xce, 0x60, 0xe2, 0x84, 0xea, 0x35, 0x8a, 0x64,
- 0x40, 0xf8, 0xee, 0xfe, 0x37, 0xc5, 0x27, 0xe2, 0xc5, 0xf6, 0x0d, 0x89,
- 0x62, 0xfe, 0x2c, 0xf1, 0x38, 0x16, 0x2f, 0x84, 0x6e, 0x46, 0xb1, 0x79,
- 0xf5, 0x05, 0x8a, 0xf9, 0xe1, 0x08, 0x96, 0xfa, 0x44, 0x17, 0xe2, 0x45,
- 0xfa, 0x01, 0x0c, 0x30, 0xc5, 0x8a, 0x23, 0xd6, 0x11, 0x3d, 0xf4, 0x3c,
- 0xc0, 0x58, 0xbf, 0x9d, 0xb9, 0xfc, 0xf2, 0xc5, 0xfb, 0x65, 0xe3, 0xfb,
- 0x2c, 0x5f, 0xff, 0x7d, 0x8d, 0x36, 0x7d, 0xc9, 0x22, 0xcf, 0x2c, 0x5f,
- 0x16, 0x1e, 0x56, 0x2f, 0xf4, 0xf9, 0xc0, 0xf9, 0xa5, 0x8b, 0x79, 0x62,
- 0xff, 0xcd, 0xc6, 0xdf, 0xa9, 0x0d, 0xc9, 0x62, 0xb0, 0xf4, 0x9c, 0x4a,
- 0xff, 0x7d, 0xcf, 0xee, 0x4e, 0x2c, 0x5f, 0xff, 0xde, 0x2c, 0x03, 0x90,
- 0x3c, 0x4e, 0x03, 0x33, 0xeb, 0x17, 0x17, 0x5b, 0x53, 0xce, 0xe8, 0xb1,
- 0x94, 0x0e, 0x43, 0xf8, 0x42, 0x78, 0x80, 0x33, 0x3b, 0xde, 0x3f, 0x96,
- 0x2f, 0xc2, 0x62, 0x6e, 0x2c, 0x53, 0x9e, 0x2f, 0x07, 0xaf, 0xdc, 0xd4,
- 0xbf, 0x4b, 0x17, 0xe9, 0x2e, 0xa7, 0x7a, 0xc5, 0x61, 0xe9, 0xfc, 0xa6,
- 0xb6, 0xae, 0x4c, 0xc0, 0x84, 0x6d, 0xd8, 0xf1, 0xd9, 0x0f, 0xc8, 0xde,
- 0x3f, 0xb0, 0x42, 0xfb, 0xce, 0x97, 0xf8, 0x05, 0x9b, 0xf4, 0xdc, 0x58,
- 0xbf, 0xc1, 0x91, 0x39, 0x8f, 0xf5, 0x8a, 0xda, 0xde, 0x5e, 0x85, 0x4e,
- 0xa6, 0x50, 0x64, 0x1a, 0xb2, 0x32, 0x2e, 0xdd, 0x1a, 0x38, 0x3d, 0x46,
- 0x3c, 0x78, 0xea, 0x9e, 0x73, 0x30, 0x13, 0xe5, 0x25, 0x1d, 0x1f, 0x21,
- 0x69, 0xe2, 0x21, 0x4e, 0x64, 0x6f, 0x84, 0x69, 0x86, 0xb7, 0xc0, 0x0e,
- 0x40, 0xb1, 0x78, 0x29, 0xb0, 0x82, 0xab, 0x17, 0xa0, 0x4e, 0xb1, 0x7f,
- 0xbd, 0x27, 0xee, 0x19, 0xe5, 0x8b, 0xdf, 0x60, 0x2c, 0x5f, 0xfd, 0x1b,
- 0xee, 0x75, 0xf6, 0xea, 0x7d, 0xc5, 0x8a, 0x0a, 0x23, 0x96, 0x4b, 0x30,
- 0x72, 0x23, 0x5e, 0x0e, 0xd4, 0xa6, 0xad, 0xdc, 0x61, 0x37, 0x36, 0xea,
- 0xc5, 0xfb, 0x76, 0x61, 0xa9, 0x58, 0xbf, 0xf7, 0x71, 0x7b, 0xf3, 0xee,
- 0x7d, 0x96, 0x2f, 0x7d, 0x8e, 0xb1, 0x73, 0x81, 0x62, 0xa4, 0xfd, 0x9d,
- 0x0b, 0xc3, 0xb7, 0xed, 0x47, 0x3a, 0x8d, 0x62, 0xfe, 0xcf, 0x70, 0x45,
- 0xe5, 0x8b, 0xf3, 0x17, 0x83, 0x3a, 0xc5, 0xe7, 0xd7, 0x16, 0x2a, 0x51,
- 0x3f, 0x85, 0x60, 0x2e, 0xf1, 0x4d, 0xff, 0xa4, 0xbd, 0xf1, 0x3c, 0x21,
- 0x2b, 0x17, 0xb4, 0x2d, 0xc5, 0x8b, 0x9a, 0x25, 0x8a, 0x63, 0x72, 0x44,
- 0x36, 0x8d, 0x62, 0xf8, 0xed, 0xed, 0x81, 0x62, 0xfa, 0x7e, 0xc6, 0xac,
- 0x56, 0x1e, 0x5e, 0x8a, 0x2f, 0xfa, 0x01, 0xf9, 0x8a, 0x7b, 0x82, 0xc5,
- 0xff, 0xb3, 0xbf, 0x1a, 0xfc, 0x0e, 0x46, 0xb1, 0x51, 0xa6, 0x36, 0x68,
- 0xff, 0x4b, 0xda, 0x21, 0x0c, 0xee, 0xfd, 0xa7, 0x62, 0x02, 0xc5, 0xfb,
- 0x85, 0xc9, 0xfa, 0xc5, 0xc5, 0xd2, 0xc5, 0xa2, 0x58, 0xb0, 0x30, 0xd5,
- 0xb8, 0xc5, 0x39, 0xfc, 0x09, 0x4e, 0xf6, 0xa6, 0x25, 0x8b, 0xfd, 0x86,
- 0x7c, 0xc7, 0x0c, 0xeb, 0x17, 0x3c, 0x4b, 0x15, 0x19, 0xe7, 0x91, 0xbd,
- 0xfb, 0x86, 0x3f, 0x7c, 0x58, 0xa6, 0x3c, 0xd7, 0x22, 0xbf, 0xf1, 0x49,
- 0xbf, 0x7f, 0x07, 0x80, 0x58, 0xbf, 0xee, 0x4f, 0xc9, 0x8f, 0x3c, 0x58,
- 0xbd, 0xcd, 0x62, 0xc5, 0xe2, 0xc8, 0x2c, 0x5f, 0xb4, 0x02, 0x10, 0x16,
- 0x2a, 0x4f, 0x17, 0x07, 0x29, 0x91, 0x05, 0xc6, 0x2b, 0x6e, 0x2c, 0x5f,
- 0xd8, 0x1c, 0xc4, 0xdc, 0x58, 0xa2, 0x3c, 0x4f, 0x0a, 0xd4, 0xaf, 0x52,
- 0x47, 0x0a, 0x18, 0x43, 0x30, 0x67, 0x79, 0x1c, 0x94, 0x49, 0xfa, 0x84,
- 0xf9, 0xc8, 0x7f, 0x0b, 0xa2, 0x20, 0xe2, 0x07, 0xa1, 0x75, 0xbd, 0x9a,
- 0xff, 0xa5, 0xbf, 0x27, 0x8f, 0x0c, 0x58, 0xbf, 0xf7, 0x25, 0x86, 0x53,
- 0x06, 0x02, 0xc5, 0xfb, 0xed, 0x1b, 0x92, 0xc5, 0xc3, 0x65, 0x8b, 0xdf,
- 0x68, 0x96, 0x2f, 0xc2, 0x35, 0xc8, 0x0b, 0x17, 0x7d, 0x96, 0x2a, 0x51,
- 0x3b, 0x85, 0x11, 0x0b, 0xfc, 0x7b, 0x74, 0xa6, 0xff, 0xa3, 0x2c, 0x87,
- 0xf0, 0x1c, 0x58, 0xbf, 0x8d, 0xe3, 0x17, 0x70, 0x58, 0xbf, 0xe9, 0x2e,
- 0xb6, 0x8c, 0x9c, 0xc5, 0x8b, 0xff, 0x61, 0x77, 0x0e, 0x68, 0x52, 0x05,
- 0x8b, 0xdc, 0xc3, 0x56, 0x2e, 0x73, 0xac, 0x57, 0x8d, 0xae, 0xf1, 0xeb,
- 0xff, 0x78, 0x5e, 0x88, 0x51, 0x9d, 0xbc, 0xb1, 0x58, 0x7c, 0xcc, 0x47,
- 0x7d, 0xd1, 0xc1, 0x2b, 0x17, 0xf4, 0x33, 0x9c, 0x61, 0xac, 0x5a, 0x1b,
- 0x4f, 0x4b, 0xc4, 0x95, 0x29, 0xf1, 0xc6, 0x60, 0xc7, 0x87, 0x86, 0xd8,
- 0x6e, 0x57, 0xfe, 0xd7, 0xcc, 0x71, 0xef, 0xf6, 0x74, 0xb1, 0x7d, 0x87,
- 0x9e, 0x96, 0x2f, 0x7f, 0x37, 0x56, 0x2f, 0xa0, 0xfe, 0xe2, 0xc5, 0xbd,
- 0xb4, 0xf0, 0xe2, 0x20, 0xa7, 0x46, 0xa8, 0x11, 0x09, 0x9a, 0xf0, 0xe7,
- 0x7a, 0xc5, 0xfb, 0x0d, 0xc2, 0x82, 0xc5, 0xf6, 0xbd, 0x91, 0xac, 0x5f,
- 0xff, 0x8d, 0x7d, 0xb8, 0x76, 0xf6, 0xdf, 0x70, 0x98, 0xd5, 0x8b, 0xa6,
- 0x25, 0x8b, 0xff, 0x8a, 0x4c, 0x19, 0x4f, 0x70, 0x62, 0x58, 0xa3, 0x51,
- 0x6f, 0xa5, 0xb2, 0x18, 0xbf, 0x1f, 0x3e, 0xfb, 0xab, 0x15, 0x29, 0x9b,
- 0x64, 0x36, 0xd8, 0xc2, 0xfd, 0xdf, 0x4d, 0xee, 0x2c, 0x5f, 0xfa, 0x28,
- 0x4e, 0xa3, 0xda, 0x66, 0x7d, 0x62, 0xff, 0x7d, 0xbe, 0x53, 0x9a, 0x58,
- 0xbf, 0x4e, 0xfd, 0x07, 0xc5, 0x8a, 0xda, 0x8a, 0x3e, 0x91, 0x7e, 0x65,
- 0x52, 0x98, 0x0b, 0xc3, 0x3a, 0xa5, 0x58, 0x30, 0xcb, 0xb4, 0x3f, 0xf8,
- 0xd7, 0x8a, 0x33, 0x4b, 0xfd, 0xfc, 0xf6, 0x0b, 0x51, 0xac, 0x5f, 0xff,
- 0xe6, 0xeb, 0xf9, 0xb7, 0xf3, 0xb7, 0x8c, 0x12, 0x7a, 0x70, 0xd6, 0x2f,
- 0x88, 0x4f, 0xe5, 0x8b, 0xee, 0xfa, 0x6e, 0xd6, 0x28, 0xe8, 0xe6, 0xf9,
- 0xa8, 0x1a, 0x78, 0x45, 0x7f, 0x8a, 0x61, 0x17, 0xe6, 0x35, 0x8b, 0xba,
- 0x65, 0x8b, 0xfe, 0x62, 0x8a, 0x7a, 0xd6, 0x76, 0xb1, 0x4e, 0x7a, 0x7c,
- 0x18, 0xa1, 0xa2, 0xa7, 0xd0, 0x88, 0xbf, 0x0c, 0xd3, 0x45, 0xda, 0xc5,
- 0x8d, 0x73, 0xd5, 0x11, 0x45, 0xff, 0x4f, 0xb3, 0x5d, 0x3b, 0xf4, 0xa8,
- 0xbe, 0x0b, 0xf9, 0xd8, 0x73, 0xee, 0x2c, 0x5f, 0xff, 0xef, 0x36, 0x76,
- 0x3f, 0x8b, 0x99, 0xd6, 0xdf, 0xb6, 0x1d, 0x62, 0xfb, 0x53, 0xdc, 0x16,
- 0x2f, 0xfe, 0xc3, 0x8a, 0x0e, 0x3c, 0xea, 0x78, 0xb1, 0x58, 0x7d, 0x3f,
- 0x24, 0xba, 0x4f, 0xd2, 0x6c, 0x7f, 0x47, 0xe1, 0x6f, 0xa1, 0x9d, 0x7f,
- 0xce, 0x6f, 0x1b, 0x8d, 0xdf, 0x96, 0x2b, 0xe8, 0x8a, 0x24, 0xfb, 0xff,
- 0xf1, 0x75, 0xb7, 0xf2, 0xda, 0x63, 0xb6, 0xcc, 0x9d, 0x62, 0xf3, 0xea,
- 0x35, 0x45, 0xfe, 0x5f, 0xc5, 0xd7, 0x39, 0x9b, 0x8b, 0x17, 0xfe, 0x20,
- 0x19, 0x9d, 0xfb, 0xd2, 0x75, 0x8a, 0x93, 0xf3, 0xc3, 0x2b, 0xff, 0x17,
- 0xb5, 0x93, 0xdc, 0x18, 0xeb, 0x17, 0xb2, 0x3d, 0xd5, 0x8a, 0x94, 0xe6,
- 0xb0, 0x8b, 0xa5, 0xaf, 0xc2, 0x79, 0xc8, 0x08, 0xfe, 0xf7, 0x98, 0xc5,
- 0x8b, 0xf9, 0xe3, 0x0c, 0x6f, 0xb8, 0xb1, 0x5e, 0x3d, 0x11, 0x0f, 0x5f,
- 0xed, 0x6b, 0x22, 0x3c, 0xf1, 0x62, 0xff, 0x9f, 0xdc, 0x62, 0xee, 0x07,
- 0x58, 0xbf, 0xe6, 0xd4, 0x62, 0x00, 0x27, 0xcb, 0x17, 0xfd, 0x39, 0xad,
- 0xb0, 0x6e, 0xe0, 0xb1, 0x50, 0x4c, 0x23, 0x08, 0x80, 0x6b, 0xc3, 0xaf,
- 0x1d, 0xdf, 0x75, 0x20, 0xdc, 0x58, 0xbf, 0xff, 0xdf, 0x7e, 0x34, 0xf3,
- 0x6f, 0xbf, 0x87, 0xce, 0x9f, 0x4b, 0x17, 0x4e, 0xea, 0xc5, 0xff, 0x4f,
- 0x70, 0xfb, 0x69, 0xe0, 0xb1, 0x7b, 0x8e, 0x75, 0x8a, 0x23, 0xd7, 0xe1,
- 0xd5, 0x69, 0x31, 0xcf, 0x93, 0x81, 0x8f, 0xce, 0x37, 0xc7, 0x29, 0x89,
- 0x62, 0xff, 0x77, 0xe0, 0xff, 0xfc, 0xdc, 0x58, 0xbf, 0x63, 0x47, 0x26,
- 0xac, 0x54, 0xa2, 0x1b, 0x08, 0xfe, 0x75, 0x7e, 0x07, 0x36, 0x67, 0xcb,
- 0x17, 0xd9, 0xa0, 0xe2, 0x58, 0xa8, 0xcf, 0xff, 0x0b, 0xb4, 0x59, 0x78,
- 0x6d, 0x12, 0xc5, 0xfe, 0xf4, 0xf7, 0xc2, 0x9d, 0xeb, 0x17, 0xf7, 0xb2,
- 0x12, 0x5e, 0x58, 0xa8, 0xd1, 0x03, 0xd8, 0xf1, 0x1b, 0x5f, 0x77, 0x0f,
- 0x3a, 0xc5, 0xff, 0xee, 0xbe, 0xc5, 0x9b, 0xde, 0x1c, 0x61, 0xac, 0x5f,
- 0xe8, 0x16, 0x1c, 0xef, 0x05, 0x8b, 0xe6, 0xe9, 0x86, 0xb1, 0x76, 0xa5,
- 0x8f, 0x5b, 0xc6, 0x74, 0x34, 0x67, 0x6a, 0x14, 0x57, 0xf7, 0x3c, 0x53,
- 0x9d, 0xac, 0x54, 0xa6, 0xf3, 0x86, 0x2f, 0x0f, 0x21, 0x14, 0x5f, 0xfe,
- 0xce, 0x7d, 0xdb, 0xd2, 0x72, 0x73, 0x56, 0x2f, 0x39, 0x74, 0xb1, 0x7e,
- 0x07, 0x3d, 0x9f, 0x58, 0xbe, 0x1f, 0xe7, 0xb5, 0x8b, 0xec, 0xfc, 0x31,
- 0x62, 0xc6, 0x31, 0xe3, 0x78, 0x92, 0xd8, 0xb1, 0x52, 0x8a, 0x87, 0x6f,
- 0xf1, 0x45, 0xf4, 0x87, 0x17, 0x16, 0x2a, 0x55, 0xe5, 0x42, 0x51, 0x4e,
- 0x20, 0x44, 0x92, 0x50, 0xc5, 0xe1, 0x75, 0xff, 0x80, 0x76, 0xce, 0xfc,
- 0x39, 0x1a, 0xc5, 0xfe, 0xfc, 0xf7, 0x03, 0x9b, 0x2b, 0x17, 0xf6, 0xd1,
- 0xe6, 0x03, 0x8b, 0x17, 0xff, 0xef, 0x66, 0xa3, 0x6e, 0x36, 0xff, 0xb6,
- 0x77, 0xe5, 0x8a, 0x3a, 0x22, 0x48, 0xc2, 0xff, 0x17, 0xb8, 0x21, 0xfd,
- 0x96, 0x2a, 0x4f, 0x5b, 0x08, 0xae, 0x7e, 0xd6, 0x2f, 0xb6, 0x98, 0x5e,
- 0x58, 0xbb, 0x98, 0x73, 0x7c, 0x43, 0x17, 0x8f, 0xa8, 0xd6, 0x2b, 0x0f,
- 0x29, 0x8a, 0xef, 0xfa, 0x79, 0xc9, 0x68, 0xdf, 0xcb, 0x17, 0xe7, 0x3c,
- 0x8e, 0x56, 0x2b, 0xc7, 0xc0, 0x23, 0x9b, 0xfe, 0x6c, 0x21, 0x9a, 0xd9,
- 0xa5, 0x8a, 0x95, 0x5a, 0xe3, 0x40, 0x68, 0xc5, 0x75, 0x0a, 0x8f, 0x42,
- 0x03, 0x74, 0x8a, 0xff, 0xb9, 0x91, 0xf1, 0x89, 0xe3, 0x58, 0xbf, 0xf6,
- 0x77, 0x06, 0x23, 0xc8, 0xe5, 0x62, 0xec, 0xed, 0x62, 0xff, 0xff, 0xd3,
- 0x1f, 0x70, 0xe1, 0x64, 0x5b, 0x7a, 0xfc, 0xf4, 0x6e, 0x9c, 0xc5, 0x8a,
- 0xc4, 0xc1, 0x98, 0xeb, 0xc7, 0xc2, 0x18, 0xbf, 0x9f, 0x5d, 0xc3, 0x3c,
- 0xb1, 0x7f, 0x9f, 0x03, 0xcc, 0xef, 0xcb, 0x17, 0xfd, 0xc6, 0xd7, 0x88,
- 0x4f, 0x05, 0x8a, 0x01, 0xf6, 0xf8, 0xd2, 0xff, 0xfc, 0xdc, 0xc1, 0xff,
- 0x3c, 0xd9, 0xc8, 0xf0, 0xc5, 0x8b, 0xff, 0xe2, 0xf7, 0x5f, 0x63, 0x38,
- 0x58, 0x01, 0x71, 0x62, 0xfd, 0x8d, 0xb2, 0xc3, 0x58, 0xbf, 0xfa, 0x76,
- 0x70, 0x45, 0x99, 0xbe, 0x7b, 0x58, 0xa9, 0x46, 0x20, 0xd4, 0x8e, 0x55,
- 0x7f, 0xd3, 0xa0, 0x79, 0x8d, 0xc2, 0x58, 0xbf, 0xf4, 0xe6, 0xb3, 0x40,
- 0x3b, 0x71, 0x62, 0xfb, 0xdc, 0x07, 0x4b, 0x17, 0x9f, 0xbd, 0xd5, 0x8b,
- 0xf9, 0xfd, 0xc9, 0xc8, 0xd6, 0x2a, 0x55, 0x79, 0x64, 0x27, 0x3a, 0x22,
- 0x68, 0xc6, 0xbe, 0x5e, 0x47, 0x22, 0x3e, 0xde, 0x4a, 0x61, 0x0d, 0xf8,
- 0x0f, 0xdc, 0x31, 0x62, 0xfe, 0xef, 0x8c, 0x5d, 0xc1, 0x62, 0xfe, 0x2f,
- 0x64, 0x53, 0xb8, 0xb1, 0x52, 0x7c, 0x38, 0x61, 0x7f, 0xf6, 0x00, 0x6e,
- 0xfd, 0x7c, 0xf2, 0x35, 0x8a, 0x94, 0x77, 0x9e, 0x11, 0x40, 0x20, 0xbf,
- 0xe1, 0x49, 0xf9, 0x87, 0x9d, 0xc5, 0x8b, 0xff, 0x6a, 0x3c, 0x1e, 0x7f,
- 0xf9, 0xb8, 0xb1, 0x63, 0x56, 0x2f, 0xf7, 0xb8, 0x1e, 0xf9, 0xce, 0xd6,
- 0x2a, 0x4f, 0x2c, 0x84, 0xef, 0xfd, 0xae, 0x1c, 0x3c, 0xd3, 0x4c, 0x4b,
- 0x15, 0x87, 0xc2, 0x22, 0x0b, 0x0d, 0x62, 0xf7, 0xf0, 0x96, 0x2f, 0x39,
- 0x47, 0xc3, 0x5d, 0xe1, 0x2a, 0xc4, 0xdc, 0x39, 0x0e, 0xf3, 0x13, 0xef,
- 0xbd, 0xfc, 0x25, 0x8b, 0xfc, 0x59, 0xef, 0x66, 0xa2, 0x58, 0xbf, 0xb8,
- 0xf0, 0x29, 0x3a, 0xc5, 0xe2, 0x9d, 0xc5, 0x8b, 0xff, 0xe8, 0x4e, 0xa3,
- 0xf3, 0x1b, 0xce, 0x39, 0x41, 0x62, 0xfe, 0x8f, 0x98, 0x79, 0xdc, 0x58,
- 0xa8, 0x91, 0x08, 0x1a, 0x95, 0x62, 0x69, 0x71, 0x11, 0x68, 0xd3, 0x85,
- 0xa6, 0x42, 0x8e, 0xfe, 0x27, 0xee, 0x19, 0xe5, 0x8b, 0xbe, 0xcb, 0x15,
- 0x19, 0xe2, 0xb1, 0x75, 0xfe, 0xc3, 0xb9, 0x0f, 0xf2, 0xb1, 0x7c, 0x3f,
- 0x66, 0xf5, 0x8a, 0x19, 0xeb, 0xfc, 0xca, 0xe1, 0xc1, 0x62, 0xff, 0x60,
- 0xc5, 0xee, 0x40, 0x2e, 0xb1, 0x76, 0x41, 0x62, 0xbe, 0x7a, 0x04, 0x73,
- 0x68, 0x4a, 0x2a, 0xf4, 0x45, 0xe6, 0x8b, 0xe3, 0xf9, 0xa3, 0x58, 0xac,
- 0x3d, 0x96, 0x35, 0xbf, 0xfb, 0x7f, 0x8d, 0x92, 0x86, 0x7d, 0x8e, 0xb1,
- 0x74, 0x7e, 0x58, 0xbf, 0xdb, 0xfe, 0xf0, 0x9c, 0x25, 0x8a, 0x93, 0xcd,
- 0xc1, 0x9b, 0xe8, 0x3e, 0xa0, 0xb1, 0x7f, 0xfa, 0x74, 0xfe, 0x17, 0x9b,
- 0xdc, 0xfb, 0x2c, 0x5a, 0x11, 0x1f, 0x6f, 0xc8, 0xe9, 0x62, 0xf8, 0x3f,
- 0xbf, 0x96, 0x2d, 0x9c, 0x36, 0x06, 0x06, 0x5f, 0xd0, 0x3f, 0x88, 0x51,
- 0x2c, 0x5f, 0xff, 0x07, 0x09, 0xde, 0xc4, 0x0d, 0x34, 0x9f, 0x12, 0x2b,
- 0x48, 0x81, 0xf1, 0x85, 0xf7, 0xc3, 0xef, 0xcb, 0x17, 0xec, 0x3e, 0x36,
- 0xf5, 0x8b, 0xd1, 0xc5, 0xb8, 0xb1, 0x63, 0x16, 0x2a, 0x53, 0xa9, 0x8d,
- 0x67, 0x21, 0x51, 0xd1, 0x1b, 0x13, 0x08, 0xa7, 0x64, 0x8e, 0xfd, 0x19,
- 0xc9, 0xcd, 0x58, 0xbb, 0xd8, 0xb1, 0x7f, 0x81, 0xcc, 0x29, 0xef, 0x8b,
- 0x17, 0xed, 0x34, 0x6e, 0x75, 0x4c, 0x26, 0x5f, 0x78, 0x52, 0xea, 0x98,
- 0x4c, 0xb8, 0x12, 0xaa, 0x04, 0xcb, 0xfc, 0x4e, 0x6f, 0xa7, 0x40, 0x55,
- 0x02, 0x65, 0xfe, 0xe6, 0x7d, 0xb8, 0x28, 0xd5, 0x30, 0x99, 0x76, 0x0d,
- 0x53, 0x09, 0x97, 0x18, 0x62, 0xe6, 0x13, 0x2b, 0x13, 0x57, 0xec, 0xd9,
- 0x8b, 0xce, 0x49, 0xc4, 0x1d, 0xe8, 0x46, 0x12, 0x5b, 0xc9, 0x98, 0x4c,
- 0x04, 0x3e, 0x7a, 0xed, 0x51, 0xe6, 0x85, 0xcc, 0x8f, 0xca, 0xfb, 0x06,
- 0x22, 0x58, 0xac, 0x55, 0x84, 0xd2, 0x99, 0x9c, 0xea, 0xff, 0xfc, 0x03,
- 0xbc, 0x39, 0xf9, 0xdf, 0x81, 0x8d, 0xe0, 0xb1, 0x52, 0xc8, 0xba, 0x68,
- 0x4b, 0x7e, 0x37, 0xd7, 0x20, 0x28, 0x4a, 0x72, 0x51, 0xb7, 0xa5, 0x97,
- 0x08, 0xda, 0xff, 0xfb, 0x0c, 0xfb, 0xb7, 0xa7, 0xc2, 0x06, 0x12, 0xc5,
- 0xff, 0xa0, 0x4e, 0x6c, 0x50, 0x6d, 0x41, 0x62, 0xff, 0x9c, 0xd2, 0xc8,
- 0xa1, 0x3d, 0xac, 0x56, 0x8f, 0xf0, 0x90, 0x6f, 0xff, 0xe2, 0x1e, 0x14,
- 0x99, 0xe3, 0x5f, 0x99, 0x84, 0x6a, 0xc5, 0xf3, 0xef, 0xc3, 0x16, 0x2d,
- 0xb1, 0x2c, 0x5f, 0xff, 0x3c, 0x3f, 0x32, 0xde, 0xe3, 0x17, 0x70, 0x58,
- 0xa8, 0x1f, 0x37, 0xc5, 0xef, 0x45, 0x3c, 0x58, 0xbc, 0x40, 0x3a, 0xc5,
- 0xff, 0x48, 0xbc, 0x4d, 0xbc, 0x33, 0xac, 0x5f, 0xf6, 0x79, 0xb3, 0x91,
- 0xe1, 0x8b, 0x17, 0x49, 0xd6, 0x2e, 0xce, 0x4a, 0x32, 0x30, 0x7b, 0x43,
- 0xbf, 0x3c, 0xd9, 0x3a, 0xbf, 0xfc, 0xf0, 0xfc, 0xef, 0x0c, 0xee, 0xfa,
- 0xe9, 0x62, 0xa5, 0x5b, 0x06, 0x43, 0x2d, 0x88, 0x74, 0xb6, 0xf0, 0x8b,
- 0x28, 0x75, 0x09, 0x5a, 0xff, 0x36, 0xfd, 0xbf, 0x7e, 0x6e, 0x2c, 0x5f,
- 0xde, 0x13, 0xf3, 0x9e, 0x58, 0xbf, 0x72, 0x70, 0x12, 0xb1, 0x7c, 0x0f,
- 0x96, 0x76, 0x7a, 0xde, 0x2f, 0xbf, 0xef, 0xc8, 0x67, 0xcd, 0xed, 0xd2,
- 0xc5, 0x62, 0x60, 0xef, 0x09, 0x1e, 0x1c, 0xde, 0x6d, 0x1a, 0xb1, 0x76,
- 0x80, 0xb1, 0x58, 0x6d, 0x98, 0x7a, 0xe8, 0xf4, 0xb1, 0x70, 0x22, 0x58,
- 0xbf, 0xf8, 0xf1, 0x41, 0xca, 0x31, 0xc9, 0x46, 0xb1, 0x52, 0x7f, 0x23,
- 0x19, 0xc1, 0x9b, 0xd9, 0xc8, 0x2c, 0x5f, 0x37, 0xdc, 0xeb, 0x17, 0xda,
- 0x9e, 0x46, 0xb1, 0x5a, 0x3e, 0x3f, 0x0e, 0x86, 0x45, 0x52, 0xec, 0x4a,
- 0x63, 0x94, 0x3a, 0x39, 0xc2, 0xbc, 0x8c, 0xf0, 0xd8, 0xce, 0xfa, 0x97,
- 0x5f, 0xdc, 0x76, 0x6d, 0x1b, 0x34, 0x53, 0xa1, 0xba, 0x96, 0x74, 0x78,
- 0xdc, 0x3f, 0x2c, 0xb8, 0x11, 0xbd, 0x11, 0xa7, 0x23, 0xac, 0xf5, 0x28,
- 0xef, 0x7c, 0xbe, 0xf3, 0x23, 0x77, 0xd9, 0x6a, 0x0e, 0x13, 0x1b, 0xb0,
- 0x90, 0xbe, 0x8c, 0xfe, 0xe2, 0xc5, 0xd8, 0x4b, 0x17, 0x7b, 0x8b, 0x15,
- 0x26, 0xb8, 0x85, 0xaf, 0xfe, 0xcf, 0xe7, 0xbb, 0xe9, 0xb5, 0xfc, 0x58,
- 0xbb, 0x38, 0xb1, 0x7f, 0xee, 0x66, 0xbc, 0x4e, 0x69, 0xb8, 0xb1, 0x50,
- 0x45, 0xe0, 0xc7, 0xc0, 0x8d, 0xc1, 0x7b, 0xff, 0x16, 0x01, 0xf5, 0x9b,
- 0xf0, 0x6b, 0x17, 0xe8, 0xa1, 0x25, 0xe5, 0x8b, 0xff, 0x6b, 0x39, 0xc1,
- 0x10, 0x67, 0x95, 0x8a, 0x81, 0xf4, 0xe8, 0xa6, 0xfe, 0xc8, 0x10, 0x9f,
- 0x8b, 0x17, 0xdd, 0xf1, 0xa5, 0x62, 0xff, 0x61, 0x6e, 0xf9, 0x88, 0xd5,
- 0x8a, 0x35, 0x35, 0x0e, 0xe1, 0x51, 0xa2, 0x2f, 0x96, 0x80, 0x8e, 0xfb,
- 0x34, 0xc6, 0xac, 0x5e, 0x32, 0x33, 0xac, 0x5f, 0xff, 0x6f, 0xd6, 0x47,
- 0xb4, 0x53, 0x9e, 0x9e, 0xe0, 0xb1, 0x7b, 0x42, 0x1a, 0xc5, 0xfe, 0x93,
- 0x93, 0xc3, 0x3e, 0xb1, 0x5a, 0x3d, 0x0f, 0x8f, 0x54, 0xa6, 0xba, 0x35,
- 0x2c, 0x23, 0x72, 0x0e, 0x42, 0x9a, 0xfd, 0x21, 0x97, 0x60, 0x58, 0xbf,
- 0xdf, 0x93, 0x43, 0xfb, 0xf9, 0x62, 0xbe, 0x7c, 0x1e, 0x2a, 0xbb, 0x37,
- 0x56, 0x2e, 0x0f, 0x8b, 0x17, 0xef, 0x19, 0x85, 0x1a, 0xc5, 0xa7, 0xe7,
- 0x86, 0x43, 0x35, 0xb0, 0x22, 0x0e, 0x0b, 0xb7, 0xb3, 0x0c, 0x58, 0xb9,
- 0x8d, 0x58, 0xa8, 0xcd, 0xab, 0x0e, 0xdf, 0xbd, 0x91, 0x31, 0xd6, 0x2f,
- 0xd3, 0xd8, 0x01, 0x2b, 0x15, 0x27, 0xa4, 0x45, 0x37, 0xdb, 0xe4, 0xbc,
- 0xb1, 0x7e, 0xfc, 0xb7, 0x25, 0x62, 0xa4, 0xf2, 0xdc, 0x92, 0xf7, 0xd8,
- 0x35, 0x8b, 0xf3, 0x6f, 0xf3, 0x46, 0xb1, 0x7e, 0xf7, 0xe7, 0x50, 0x58,
- 0xbf, 0xf6, 0x1e, 0x4a, 0x40, 0x77, 0x82, 0xc5, 0xff, 0x13, 0x1b, 0x3e,
- 0xe3, 0x69, 0x62, 0xff, 0xf7, 0xc4, 0xf0, 0xef, 0xda, 0x9c, 0xef, 0x16,
- 0x28, 0xe8, 0x85, 0xe1, 0xcd, 0xf4, 0x3d, 0x9d, 0x2c, 0x56, 0x1e, 0x3b,
- 0x91, 0xdc, 0x52, 0xb1, 0x7f, 0xdf, 0x78, 0x4c, 0x45, 0x27, 0x58, 0xbf,
- 0x86, 0xfe, 0xfb, 0x18, 0xb1, 0x7e, 0x2c, 0x0f, 0x22, 0x58, 0xbf, 0xff,
- 0x67, 0x40, 0x93, 0xe7, 0x9b, 0x99, 0x84, 0x6a, 0xc5, 0xfc, 0x76, 0x93,
- 0xb9, 0x2c, 0x57, 0xd1, 0x02, 0x05, 0x5b, 0xff, 0x98, 0xe3, 0x13, 0xea,
- 0x19, 0xdf, 0x96, 0x2c, 0x58, 0x7d, 0x3d, 0x11, 0xdf, 0xf9, 0xc8, 0x1d,
- 0xfb, 0x53, 0x86, 0x2c, 0x5f, 0xfb, 0x9f, 0x6d, 0xbd, 0xc2, 0x72, 0x35,
- 0x8b, 0xfd, 0x83, 0xd6, 0x9a, 0x2e, 0x2c, 0x5d, 0xb7, 0x75, 0x62, 0xd9,
- 0xb8, 0x8d, 0x50, 0x20, 0x79, 0x0f, 0x79, 0xad, 0xec, 0x1e, 0xca, 0xc5,
- 0xff, 0x7d, 0xcf, 0xf6, 0x9e, 0xe0, 0xb1, 0x7f, 0xb0, 0xe3, 0x60, 0x0a,
- 0x0b, 0x17, 0xdf, 0x77, 0x3a, 0xc5, 0xf3, 0xff, 0xec, 0xb1, 0x44, 0x78,
- 0x9b, 0xc8, 0xaf, 0xc5, 0x0d, 0x97, 0x8d, 0x62, 0xa4, 0xf3, 0xc3, 0x23,
- 0xa9, 0x55, 0x0d, 0x08, 0x7e, 0x1a, 0x8e, 0xc4, 0x1f, 0x3a, 0x04, 0x31,
- 0xef, 0xff, 0xf3, 0x6f, 0x21, 0x73, 0x68, 0x65, 0x23, 0xfb, 0xc3, 0x38,
- 0xb1, 0x71, 0xac, 0xb1, 0x51, 0xaf, 0x8e, 0x0d, 0xac, 0xd2, 0x0e, 0x87,
- 0xbb, 0x2b, 0xdc, 0x29, 0xd4, 0x61, 0x27, 0x20, 0xf8, 0xb3, 0x9c, 0x91,
- 0x7f, 0xa5, 0xcc, 0xef, 0x62, 0xd9, 0x65, 0xbf, 0xdf, 0xee, 0x1c, 0xfe,
- 0x46, 0xb1, 0x7f, 0xcf, 0xf8, 0x98, 0xbf, 0x9d, 0xac, 0x54, 0x9f, 0x8e,
+ 0xf7, 0xa0, 0x18, 0xb1, 0x7f, 0xf4, 0x8d, 0x70, 0xfc, 0xda, 0x81, 0x05,
+ 0xd6, 0x2b, 0xe7, 0xce, 0xe3, 0x95, 0x88, 0xb1, 0x14, 0x24, 0x2f, 0x7e,
+ 0x3b, 0x58, 0xbf, 0xff, 0xde, 0xf3, 0x11, 0xbb, 0x7c, 0x68, 0xb5, 0xce,
+ 0x36, 0x76, 0xb1, 0x7f, 0x0a, 0x78, 0x28, 0xed, 0x62, 0xfd, 0xd3, 0x41,
+ 0x49, 0x62, 0xbb, 0x3d, 0x72, 0x2f, 0xac, 0x47, 0x03, 0xc2, 0xfa, 0xa1,
+ 0x77, 0xcb, 0x21, 0xa6, 0xd0, 0xac, 0xd1, 0x0f, 0xe3, 0x2e, 0x76, 0x50,
+ 0x10, 0x94, 0x6a, 0x7e, 0x27, 0x14, 0x3f, 0xaf, 0xff, 0xc6, 0xb7, 0x8b,
+ 0x25, 0xdf, 0x89, 0xa7, 0xe0, 0x96, 0x2f, 0xb7, 0x8c, 0x70, 0xb1, 0x7f,
+ 0xf6, 0x6b, 0x6e, 0x7d, 0xcd, 0x21, 0x71, 0x62, 0x99, 0x18, 0x8e, 0xb0,
+ 0x22, 0x5b, 0xff, 0x1a, 0xfd, 0x7d, 0xa6, 0xce, 0xfc, 0xb1, 0x7e, 0x79,
+ 0x16, 0x01, 0x62, 0xff, 0xfe, 0xd4, 0xb6, 0x8f, 0xf1, 0xb4, 0xb3, 0xbf,
+ 0x46, 0x18, 0xb1, 0x77, 0x38, 0xb1, 0x7e, 0x8c, 0xf7, 0x1d, 0x62, 0xfc,
+ 0xed, 0xc1, 0x1a, 0xb1, 0x78, 0xc3, 0x0c, 0x58, 0xb8, 0x0e, 0x91, 0xb2,
+ 0x68, 0x6f, 0xf6, 0xa3, 0x7e, 0x61, 0xc6, 0xb1, 0x4c, 0x9a, 0x4e, 0x98,
+ 0x4e, 0x31, 0xf2, 0x7e, 0x25, 0x08, 0xaa, 0xfa, 0x4c, 0x46, 0xac, 0x5f,
+ 0xe2, 0x73, 0x66, 0x26, 0x99, 0x62, 0xa6, 0x3d, 0x8e, 0x11, 0xdf, 0x0b,
+ 0xc2, 0x75, 0x8a, 0xc3, 0xc6, 0x22, 0x3b, 0xf8, 0x11, 0x2f, 0x87, 0xc5,
+ 0x8b, 0xf7, 0x04, 0x0c, 0x25, 0x8b, 0xf9, 0x88, 0x1d, 0x74, 0xcb, 0x17,
+ 0x9c, 0x18, 0x91, 0x52, 0x57, 0x33, 0xd9, 0x76, 0x90, 0xcf, 0x1b, 0x87,
+ 0xe1, 0xea, 0x02, 0x0f, 0x18, 0x6f, 0x28, 0xdc, 0x2f, 0xbe, 0x81, 0xb0,
+ 0xd6, 0x2f, 0xdb, 0xf3, 0x37, 0x9a, 0xb1, 0x7f, 0xfd, 0xdf, 0xa0, 0x78,
+ 0x45, 0x86, 0xe1, 0x01, 0x62, 0xa0, 0xff, 0x34, 0x5b, 0x7f, 0x73, 0xed,
+ 0xd3, 0xe9, 0x62, 0xfc, 0x3d, 0x30, 0xa7, 0x58, 0xbe, 0xf7, 0x1f, 0xb5,
+ 0x8b, 0x79, 0x62, 0xb0, 0xdb, 0x1a, 0x49, 0x7f, 0x8c, 0xc2, 0xcd, 0xed,
+ 0xa5, 0x8b, 0xdd, 0x06, 0x75, 0x8b, 0xc0, 0x0c, 0xeb, 0x14, 0x03, 0x7f,
+ 0xe2, 0x0b, 0xf8, 0xb3, 0xb0, 0x07, 0x25, 0x8b, 0xb3, 0x8b, 0x17, 0xd8,
+ 0x76, 0xf2, 0xc5, 0xff, 0xd9, 0xf0, 0xcf, 0x9d, 0x47, 0xe0, 0xeb, 0x16,
+ 0xe6, 0x1f, 0xf9, 0x0b, 0xf8, 0x8a, 0xdc, 0x58, 0xac, 0x54, 0x73, 0x31,
+ 0x7e, 0x98, 0x08, 0x87, 0x8e, 0x9e, 0x21, 0x14, 0x2b, 0xcc, 0x33, 0xbf,
+ 0x7f, 0xee, 0x38, 0x58, 0xbe, 0xcf, 0x7f, 0x16, 0x2f, 0xa0, 0xfb, 0x78,
+ 0xb1, 0x50, 0x7d, 0xf8, 0x50, 0xc4, 0x57, 0x39, 0xd6, 0x2f, 0xff, 0xec,
+ 0x22, 0x89, 0x6a, 0x38, 0x59, 0xbd, 0xbe, 0x25, 0x8b, 0xf9, 0xdb, 0x9f,
+ 0x83, 0xac, 0x5f, 0xee, 0x7a, 0x26, 0x17, 0x7c, 0x58, 0xaf, 0x9f, 0x20,
+ 0x8b, 0x6f, 0x9b, 0x5a, 0x85, 0x8b, 0xfd, 0x9b, 0xf3, 0x64, 0xc3, 0x0c,
+ 0x48, 0xbc, 0x66, 0x7d, 0x62, 0xfd, 0x34, 0x67, 0xf8, 0xb1, 0x5b, 0x51,
+ 0x8f, 0xf2, 0x22, 0x22, 0xf1, 0xe0, 0x63, 0xd7, 0xf8, 0x2f, 0x02, 0xeb,
+ 0xed, 0xa5, 0x8b, 0xc7, 0x7f, 0x2c, 0x5f, 0xc5, 0x13, 0x09, 0xc3, 0x58,
+ 0xa9, 0x95, 0x36, 0x9c, 0x5f, 0xf1, 0xc2, 0x89, 0x33, 0x79, 0xc8, 0x63,
+ 0xb7, 0x8e, 0xdc, 0x58, 0xbf, 0xfe, 0xc1, 0xbb, 0x13, 0xf9, 0x8a, 0x5c,
+ 0xc5, 0x8b, 0xfb, 0xef, 0xa6, 0xcd, 0x2c, 0x54, 0x1f, 0xcb, 0xa6, 0x52,
+ 0xc5, 0xf7, 0x7d, 0x36, 0x96, 0x2c, 0x0d, 0x8c, 0xd8, 0xf8, 0x32, 0xff,
+ 0x6f, 0xfb, 0x64, 0x9f, 0x7a, 0xc5, 0xfb, 0x7b, 0x9d, 0x8e, 0xb1, 0x50,
+ 0x88, 0xdc, 0x2c, 0x23, 0x7b, 0xda, 0xfe, 0x2c, 0x5f, 0x4d, 0x28, 0x92,
+ 0xc5, 0x41, 0xe0, 0xe0, 0xed, 0xf4, 0x06, 0xc0, 0x58, 0xb8, 0x5f, 0x58,
+ 0xbf, 0xfe, 0x6f, 0x73, 0xec, 0x33, 0xf8, 0xa3, 0x3b, 0x58, 0xa9, 0xd1,
+ 0x17, 0x31, 0x1f, 0x86, 0x2f, 0xa3, 0x08, 0x6b, 0x16, 0xf2, 0xc5, 0xa7,
+ 0x19, 0xb3, 0xe8, 0x86, 0xa1, 0x95, 0x0f, 0x28, 0x48, 0xe4, 0x27, 0x9a,
+ 0x52, 0xd7, 0xe1, 0xce, 0xf2, 0xa6, 0x40, 0xc6, 0x50, 0x96, 0xe4, 0x37,
+ 0xbc, 0xdc, 0x28, 0x55, 0x86, 0xcb, 0x7e, 0xdb, 0x1c, 0x89, 0x2c, 0x5f,
+ 0xba, 0xc9, 0x31, 0x2c, 0x5e, 0x70, 0x32, 0xc5, 0xff, 0xb3, 0x7c, 0x47,
+ 0xe2, 0x78, 0xed, 0x62, 0xff, 0x86, 0x42, 0xe6, 0x4f, 0x93, 0xac, 0x5e,
+ 0x8d, 0x12, 0xc5, 0xff, 0xe0, 0x41, 0x67, 0x7e, 0x7e, 0x72, 0x0e, 0xb1,
+ 0x7f, 0xb0, 0x64, 0xfc, 0x61, 0xac, 0x5b, 0xeb, 0x16, 0x9c, 0x8f, 0x13,
+ 0x86, 0x56, 0x16, 0x22, 0xd9, 0xe1, 0x1d, 0x5a, 0x47, 0xf7, 0xa1, 0xa5,
+ 0x7c, 0x7e, 0x61, 0xd6, 0x29, 0x8f, 0x2d, 0xca, 0x2f, 0xe8, 0xd7, 0xbd,
+ 0x9b, 0xab, 0x17, 0x6b, 0xb5, 0x8b, 0xa3, 0x7a, 0xc5, 0x0d, 0x55, 0xb6,
+ 0x8a, 0x8e, 0x51, 0xf1, 0xc7, 0x41, 0x0b, 0xc7, 0x08, 0x44, 0x01, 0x98,
+ 0x84, 0x19, 0xbf, 0x83, 0x19, 0x46, 0x4e, 0xb1, 0x7f, 0xb8, 0x58, 0x07,
+ 0x20, 0x2c, 0x58, 0x96, 0x2f, 0x4f, 0x12, 0x58, 0xa5, 0x8a, 0x83, 0x55,
+ 0x38, 0xf5, 0xfe, 0x1e, 0x7b, 0x8c, 0x67, 0x96, 0x28, 0x68, 0xf2, 0xec,
+ 0xbd, 0xcc, 0x88, 0xec, 0xc2, 0x1b, 0xfb, 0xed, 0xe2, 0x83, 0xac, 0x5f,
+ 0xfc, 0x1f, 0xb7, 0x1b, 0x9e, 0xfb, 0x38, 0x16, 0x2f, 0xff, 0xe9, 0x14,
+ 0x36, 0xb0, 0x7a, 0x8f, 0x37, 0x4c, 0x35, 0x8b, 0xff, 0xd8, 0x37, 0x3e,
+ 0x77, 0x2c, 0x06, 0x0d, 0x62, 0xef, 0xba, 0xc5, 0xd3, 0x71, 0x62, 0xfd,
+ 0x9b, 0xd8, 0x87, 0x86, 0xc0, 0x31, 0x7b, 0xfb, 0x6f, 0xb3, 0x9c, 0x85,
+ 0x8b, 0xec, 0xef, 0xd0, 0xb1, 0x7f, 0xf3, 0xeb, 0x0d, 0x6d, 0x66, 0xf7,
+ 0xd2, 0xc5, 0x7c, 0xfa, 0x77, 0x91, 0xdf, 0xf8, 0xb3, 0x5a, 0x63, 0xe7,
+ 0x7e, 0x58, 0xbf, 0x04, 0x79, 0xc3, 0x92, 0xc5, 0x6d, 0x4f, 0x87, 0x65,
+ 0xea, 0x0f, 0xb2, 0x13, 0x3c, 0x24, 0x11, 0xfd, 0xdf, 0x75, 0x8b, 0xff,
+ 0x7d, 0x9c, 0x18, 0x51, 0xdf, 0x16, 0x2c, 0x3c, 0x3d, 0x5f, 0x0b, 0xdf,
+ 0xf1, 0x4b, 0xf8, 0x45, 0x06, 0x2c, 0x5f, 0xfe, 0x79, 0xe3, 0x5a, 0x79,
+ 0x6d, 0x00, 0xf1, 0x62, 0xb1, 0x10, 0xa4, 0x71, 0x7b, 0x74, 0xf8, 0xb1,
+ 0x7f, 0xbc, 0xda, 0x7f, 0xb9, 0xd6, 0x2f, 0xfa, 0x4d, 0x37, 0x72, 0xf8,
+ 0x80, 0xb1, 0x7e, 0x2c, 0xf7, 0xda, 0x11, 0x21, 0xd9, 0x04, 0xc6, 0x77,
+ 0xfd, 0xad, 0x3c, 0xb6, 0xef, 0x8d, 0xd5, 0x8a, 0x84, 0x46, 0xe2, 0x65,
+ 0x42, 0x6b, 0xf2, 0x8c, 0xfa, 0x8d, 0x5d, 0x6d, 0xed, 0x27, 0x52, 0x8e,
+ 0xca, 0x16, 0xbe, 0x94, 0x17, 0x7e, 0xc2, 0x7f, 0x71, 0x62, 0xfe, 0xe7,
+ 0xf0, 0x9b, 0x8b, 0x17, 0xf8, 0xba, 0x0f, 0xdc, 0x10, 0xd6, 0x2f, 0xee,
+ 0x8c, 0x72, 0x28, 0x58, 0xa9, 0x22, 0xe7, 0x44, 0xee, 0x5a, 0x46, 0xf7,
+ 0x05, 0xf1, 0x62, 0xfa, 0x6f, 0xb6, 0x96, 0x2f, 0x9c, 0x61, 0x9d, 0x62,
+ 0xec, 0xe6, 0xd3, 0xe3, 0x0a, 0x8d, 0xc8, 0x92, 0xa1, 0x7f, 0x73, 0x12,
+ 0x9a, 0x76, 0x69, 0xe3, 0x1a, 0x28, 0x4f, 0x5f, 0xff, 0x0b, 0x58, 0x3f,
+ 0xc3, 0x7b, 0x8c, 0x52, 0x58, 0xbf, 0xec, 0x1e, 0x14, 0x10, 0xa1, 0x62,
+ 0xc6, 0x2c, 0x5f, 0xb0, 0x65, 0x1d, 0xac, 0x5f, 0xfe, 0x06, 0x77, 0xe8,
+ 0xee, 0x5e, 0x04, 0x49, 0x62, 0xff, 0x78, 0x9b, 0xbe, 0x06, 0x75, 0x8a,
+ 0xfa, 0x2a, 0xc8, 0xa3, 0x89, 0xb7, 0xe7, 0x7e, 0xe5, 0xc5, 0x8b, 0xff,
+ 0xcc, 0x66, 0x7b, 0xb9, 0x66, 0xbb, 0x97, 0x16, 0x2a, 0x13, 0x64, 0x68,
+ 0x5f, 0x68, 0xbf, 0xc5, 0x35, 0xb6, 0x16, 0xc1, 0x50, 0x3f, 0x3c, 0xaa,
+ 0xc9, 0x56, 0x91, 0xe3, 0xa6, 0x4c, 0xe4, 0xad, 0xf3, 0x65, 0xaa, 0x75,
+ 0x49, 0xc0, 0xee, 0x39, 0x86, 0x95, 0xcb, 0x34, 0xb3, 0xad, 0x57, 0x6f,
+ 0x27, 0xa4, 0xdc, 0xfe, 0xb0, 0xc9, 0x78, 0x76, 0x02, 0x58, 0xd1, 0x56,
+ 0xff, 0xbc, 0xa4, 0xc1, 0x7a, 0x9f, 0x10, 0x29, 0x70, 0xfb, 0xe9, 0x2b,
+ 0x3b, 0x8b, 0x61, 0xa7, 0x84, 0x8e, 0x6a, 0xfa, 0x3c, 0xde, 0x58, 0xbf,
+ 0x47, 0xa5, 0x9f, 0x58, 0xb6, 0xbe, 0x79, 0x44, 0x45, 0x7b, 0x90, 0x05,
+ 0x8a, 0xc3, 0xc4, 0xf1, 0x3d, 0xdb, 0x16, 0xc2, 0x58, 0xbf, 0xf7, 0xf0,
+ 0x7f, 0xc7, 0x2c, 0xdd, 0x58, 0xbf, 0xa4, 0x59, 0xd3, 0x79, 0x62, 0xff,
+ 0xe2, 0xe8, 0xd7, 0xe6, 0x4a, 0x0b, 0xa5, 0x8b, 0xec, 0x1b, 0xc9, 0x62,
+ 0xe6, 0x9d, 0x62, 0x80, 0x6e, 0xbc, 0x45, 0x58, 0x98, 0x7f, 0x68, 0x0c,
+ 0x5c, 0x50, 0x80, 0xbf, 0x34, 0x1d, 0xc6, 0xb1, 0x7f, 0xb3, 0xe5, 0x9e,
+ 0xfb, 0x2c, 0x5d, 0xee, 0x7c, 0xf6, 0x7c, 0x4f, 0x7c, 0x3d, 0x3c, 0x96,
+ 0x2e, 0xd8, 0x02, 0x2c, 0x5e, 0x9f, 0x3b, 0x58, 0xad, 0x1b, 0xe2, 0x1f,
+ 0xba, 0x3b, 0x58, 0xba, 0x00, 0xb1, 0x5b, 0x86, 0xbc, 0x31, 0x8b, 0xfa,
+ 0x08, 0x53, 0x47, 0x16, 0x2f, 0xbe, 0x28, 0xe2, 0xc5, 0xe7, 0x70, 0x2c,
+ 0x5d, 0x1c, 0x83, 0x7f, 0xa2, 0x3b, 0xf7, 0x5e, 0x8e, 0xfc, 0xb1, 0x5f,
+ 0x3d, 0x61, 0x15, 0xdf, 0xfb, 0xec, 0x51, 0xdf, 0x18, 0xf0, 0xb1, 0x7b,
+ 0x91, 0xa5, 0x8b, 0x70, 0x67, 0xfb, 0xd1, 0x17, 0x67, 0xd5, 0x3a, 0x6e,
+ 0xfe, 0x8d, 0x02, 0xa1, 0x55, 0x29, 0xa5, 0xcc, 0xc2, 0xe9, 0xe2, 0x8e,
+ 0x72, 0xf4, 0xbc, 0x75, 0x8b, 0xf8, 0xb2, 0x52, 0x7e, 0x2c, 0x5f, 0xd0,
+ 0x1f, 0x07, 0xd9, 0xd6, 0x2b, 0xa3, 0xde, 0x22, 0xdb, 0xf7, 0x07, 0x01,
+ 0x9d, 0x62, 0xfc, 0x66, 0x00, 0x3f, 0x2c, 0x56, 0x1e, 0xab, 0x95, 0x5c,
+ 0x36, 0x58, 0xbe, 0xef, 0x91, 0xda, 0xc5, 0xcf, 0x2d, 0xa6, 0xf1, 0x85,
+ 0xef, 0x1b, 0xf6, 0x58, 0xbf, 0xfa, 0x6d, 0x46, 0xff, 0xc3, 0x69, 0xa6,
+ 0x58, 0xb4, 0xeb, 0x17, 0x81, 0xa6, 0x58, 0xa9, 0x22, 0x5b, 0xb1, 0xe7,
+ 0x48, 0x21, 0x3b, 0xed, 0xc7, 0xcf, 0xac, 0x5f, 0xff, 0xe8, 0x33, 0xef,
+ 0xee, 0x66, 0x8a, 0x3b, 0x96, 0x77, 0xe5, 0x8b, 0xec, 0xf7, 0x1d, 0x62,
+ 0xc3, 0xd2, 0x21, 0x7e, 0xc7, 0x7f, 0xb8, 0x58, 0x77, 0x79, 0xd6, 0x2a,
+ 0x49, 0x83, 0x3c, 0x2a, 0x84, 0x53, 0x7f, 0x73, 0x06, 0xdc, 0x9d, 0x62,
+ 0xf4, 0xa0, 0x0b, 0x17, 0xe0, 0xe6, 0x94, 0x6e, 0xa4, 0x54, 0x32, 0x39,
+ 0x67, 0x21, 0xc8, 0xcc, 0x8d, 0x96, 0x7f, 0xd2, 0x83, 0x3e, 0x69, 0xdf,
+ 0xeb, 0x8f, 0x0c, 0x32, 0x8d, 0x0b, 0x86, 0xbe, 0x2f, 0x0c, 0x76, 0xfe,
+ 0x1e, 0x9f, 0xa7, 0xe9, 0x62, 0xff, 0xff, 0x82, 0xd4, 0xf1, 0xb0, 0x1e,
+ 0x02, 0xd6, 0xc4, 0x16, 0xfe, 0x9c, 0x1b, 0x76, 0xff, 0x71, 0x62, 0xdd,
+ 0x2c, 0x5f, 0xf8, 0x84, 0xe1, 0xe7, 0x1a, 0x09, 0x62, 0xfd, 0x2e, 0x7b,
+ 0x78, 0x16, 0x28, 0xd3, 0xe9, 0xec, 0xf6, 0xf6, 0xe3, 0x0d, 0x62, 0xff,
+ 0x1b, 0xf7, 0x96, 0xa0, 0xd5, 0x8a, 0xd1, 0xfd, 0x1c, 0x90, 0x88, 0x2f,
+ 0xed, 0xa5, 0x9b, 0xdf, 0x4b, 0x17, 0xa1, 0xf4, 0xb1, 0x71, 0x74, 0xb1,
+ 0x7e, 0x0f, 0xde, 0x17, 0xd6, 0x29, 0x8f, 0x0f, 0x78, 0xc5, 0xfc, 0x7f,
+ 0x7e, 0x37, 0xc2, 0xc5, 0xff, 0xb7, 0x76, 0xf5, 0xf6, 0xd3, 0x41, 0xd6,
+ 0x2f, 0x17, 0x40, 0x58, 0xa9, 0xcf, 0x8f, 0x11, 0x6f, 0xf7, 0xa5, 0x1e,
+ 0xfb, 0xc9, 0x62, 0xff, 0xde, 0x11, 0xff, 0x0c, 0x4e, 0x35, 0x8b, 0xe9,
+ 0x49, 0xfc, 0xb1, 0x53, 0xa2, 0x57, 0xb3, 0x47, 0x3e, 0xbe, 0x37, 0x4e,
+ 0x62, 0xc5, 0xdd, 0x6f, 0x58, 0xb0, 0x6a, 0x88, 0x14, 0xb7, 0x95, 0x40,
+ 0xa1, 0x5a, 0x3d, 0xaf, 0x0d, 0x98, 0x41, 0x58, 0x8a, 0xf6, 0x7f, 0xbf,
+ 0xba, 0x69, 0xfc, 0xe3, 0x58, 0xbf, 0xbf, 0x1f, 0xce, 0xfc, 0xb1, 0x79,
+ 0xe3, 0xb5, 0x8b, 0xfc, 0x2e, 0x06, 0x59, 0xdc, 0x96, 0x2c, 0x13, 0x69,
+ 0xe9, 0xfc, 0x76, 0xfe, 0x60, 0xbf, 0x5f, 0x83, 0x16, 0x2f, 0xf7, 0xd8,
+ 0x3d, 0x90, 0x02, 0x12, 0x2b, 0x47, 0xd9, 0xb8, 0x69, 0x7e, 0xc3, 0xbb,
+ 0xce, 0xb1, 0x7e, 0x8e, 0xbf, 0x1a, 0x58, 0xbd, 0xf1, 0x1a, 0xb1, 0x78,
+ 0x20, 0x5f, 0x8b, 0x17, 0x9c, 0xec, 0xb1, 0x5f, 0x3d, 0xf2, 0x1f, 0x11,
+ 0x25, 0x4e, 0xa9, 0x34, 0xd3, 0x0e, 0xe1, 0x04, 0xd0, 0x98, 0x22, 0x5f,
+ 0x14, 0x07, 0x08, 0x8b, 0xff, 0x4b, 0xe1, 0xea, 0x07, 0xfc, 0x31, 0x62,
+ 0xfd, 0xf8, 0x17, 0x6c, 0xb1, 0x5d, 0x9f, 0x59, 0xd0, 0xaf, 0xf8, 0x80,
+ 0x3f, 0xb8, 0x79, 0x3a, 0xc5, 0xfb, 0x04, 0x17, 0xce, 0x2c, 0x53, 0x1f,
+ 0x3f, 0xce, 0xef, 0xff, 0x11, 0xae, 0xe4, 0x02, 0x13, 0xf6, 0x14, 0x58,
+ 0xbf, 0xef, 0x73, 0x3c, 0x50, 0x7e, 0x2c, 0x5f, 0xa0, 0x0e, 0x40, 0x58,
+ 0xbf, 0x0b, 0xbf, 0x31, 0x8b, 0x16, 0xf6, 0xd4, 0x45, 0xc8, 0xe7, 0x84,
+ 0xf5, 0x89, 0x88, 0x94, 0x36, 0x6f, 0xf8, 0xb3, 0x43, 0xfc, 0x77, 0x25,
+ 0x8b, 0xff, 0xd0, 0x71, 0x38, 0xfd, 0xdf, 0x4c, 0x46, 0x2c, 0x5b, 0x09,
+ 0x10, 0xe6, 0x1d, 0x5f, 0xff, 0x98, 0x53, 0x86, 0x7e, 0x37, 0x4d, 0x39,
+ 0x8f, 0xda, 0xc5, 0xff, 0xbb, 0xf7, 0x5f, 0x61, 0xff, 0x27, 0x58, 0xbf,
+ 0x9b, 0xbe, 0x7d, 0x8c, 0x58, 0xb0, 0x5d, 0x62, 0x80, 0x78, 0xc4, 0x61,
+ 0x58, 0x8a, 0xad, 0x42, 0x26, 0xfe, 0x7e, 0x66, 0x11, 0xab, 0x15, 0x87,
+ 0xa8, 0x22, 0x7b, 0xce, 0xe6, 0x2c, 0x54, 0x2a, 0x6e, 0x1c, 0x2b, 0xb4,
+ 0x51, 0xf8, 0xd6, 0x88, 0x86, 0xff, 0x7b, 0x9b, 0x70, 0xec, 0x35, 0x8b,
+ 0xfe, 0x7d, 0x4c, 0x50, 0x0e, 0x09, 0x62, 0xa0, 0xfc, 0x06, 0x6d, 0x7e,
+ 0xf6, 0x08, 0xbc, 0xb1, 0x7e, 0x97, 0x03, 0x8d, 0xd5, 0x8b, 0x46, 0x1e,
+ 0xab, 0x94, 0x5f, 0xfb, 0x69, 0x39, 0xbb, 0x78, 0x00, 0x42, 0xc5, 0xff,
+ 0xe9, 0xc4, 0x0e, 0x49, 0xb9, 0xc8, 0xd4, 0x96, 0x2c, 0xc6, 0xa2, 0x47,
+ 0x48, 0x97, 0xf9, 0xff, 0xdf, 0x20, 0xbc, 0xb1, 0x52, 0x4c, 0x4f, 0x90,
+ 0xb6, 0xf1, 0x4d, 0xff, 0xfe, 0x1f, 0xe3, 0xaf, 0xb4, 0xce, 0xf2, 0x35,
+ 0xc3, 0x7d, 0xd5, 0x8b, 0xff, 0xff, 0x7d, 0xdb, 0x8d, 0x2c, 0x1f, 0xbf,
+ 0x0d, 0xad, 0x31, 0x4e, 0xb1, 0x7c, 0x59, 0xbf, 0x16, 0x2a, 0x74, 0x7a,
+ 0x9d, 0x9c, 0xc6, 0xbb, 0xfd, 0xf6, 0x9a, 0x50, 0x52, 0x58, 0xbf, 0xff,
+ 0xa3, 0xdc, 0x0c, 0xbd, 0xf1, 0x3c, 0xbd, 0xcc, 0x31, 0x62, 0xff, 0xd1,
+ 0x3e, 0x7a, 0x58, 0x4c, 0x35, 0x8b, 0xff, 0xf9, 0xe7, 0xd3, 0xbf, 0x72,
+ 0xe7, 0xbb, 0xe9, 0xb4, 0x6a, 0xc5, 0xff, 0x9c, 0xcf, 0x67, 0xfc, 0xd1,
+ 0xba, 0xb1, 0x7f, 0xe8, 0x33, 0x81, 0x57, 0xeb, 0x3b, 0xf2, 0xc5, 0x42,
+ 0x7d, 0x7d, 0x19, 0x68, 0xd3, 0xeb, 0xce, 0x7c, 0x4c, 0x3e, 0x42, 0xbe,
+ 0x97, 0xf2, 0x75, 0x8b, 0xfe, 0x62, 0xc3, 0xee, 0x63, 0x76, 0xb1, 0x7f,
+ 0xff, 0x9c, 0xe5, 0x9d, 0xc6, 0xb4, 0xdb, 0xf5, 0x9e, 0x7e, 0xd6, 0x28,
+ 0x68, 0x9e, 0xe1, 0xdd, 0xff, 0xfc, 0x39, 0x73, 0x59, 0xe7, 0xee, 0x67,
+ 0x0e, 0x3d, 0xc5, 0x8b, 0xff, 0xfb, 0x3c, 0xfd, 0xff, 0xed, 0x1e, 0xfe,
+ 0x6f, 0x8d, 0x2c, 0x5f, 0xff, 0xe8, 0x78, 0x62, 0x7f, 0x49, 0xb7, 0xeb,
+ 0x3c, 0xfd, 0xac, 0x54, 0x26, 0x7f, 0x22, 0x3d, 0x2f, 0xee, 0x2e, 0xde,
+ 0x77, 0x08, 0xb1, 0x74, 0x1f, 0x69, 0xef, 0x1d, 0x02, 0xf9, 0xa7, 0xea,
+ 0x4b, 0x17, 0x8b, 0x02, 0x2c, 0x5f, 0xf4, 0x76, 0x77, 0xf6, 0x77, 0xe5,
+ 0x8b, 0x9e, 0x75, 0x8a, 0xed, 0x59, 0x23, 0x4a, 0x5f, 0xd1, 0x7b, 0x92,
+ 0x90, 0xf1, 0x87, 0x77, 0xbe, 0xfc, 0x58, 0xb7, 0x6b, 0x15, 0x06, 0xc0,
+ 0x63, 0xb7, 0xf8, 0xef, 0xc2, 0x8c, 0x35, 0x62, 0xc2, 0x58, 0xbf, 0xe1,
+ 0x0b, 0xed, 0xef, 0xbc, 0x96, 0x2f, 0x4b, 0x3c, 0xb1, 0x7c, 0xff, 0xcd,
+ 0x2c, 0x57, 0xcd, 0xfe, 0xf1, 0xdb, 0xf0, 0xbf, 0xa8, 0x31, 0x62, 0xed,
+ 0xc7, 0x58, 0xba, 0x3a, 0xda, 0x9a, 0x2e, 0x10, 0x1a, 0x66, 0x71, 0x27,
+ 0x79, 0xf1, 0x18, 0x65, 0x57, 0x88, 0x2f, 0xc5, 0x8b, 0xe9, 0x7d, 0xb7,
+ 0xac, 0x5e, 0x82, 0xf6, 0xd3, 0xc6, 0x62, 0x1b, 0xb4, 0xeb, 0x17, 0xff,
+ 0x6f, 0x6e, 0x73, 0x0b, 0xa7, 0x20, 0x2c, 0x5f, 0xef, 0xb0, 0xc7, 0x86,
+ 0x4c, 0xb1, 0x79, 0xbb, 0xe2, 0xc5, 0xfb, 0x37, 0xe4, 0x82, 0xeb, 0x14,
+ 0x69, 0xe6, 0x7c, 0x7a, 0xc0, 0xc4, 0x75, 0xf4, 0x8d, 0xe8, 0x41, 0x5f,
+ 0x07, 0xf7, 0xf2, 0xc5, 0xa3, 0x47, 0xbe, 0x73, 0xba, 0x64, 0xee, 0xf4,
+ 0x67, 0xf8, 0xd8, 0x6f, 0xfc, 0xfd, 0xf3, 0x3c, 0xc7, 0x79, 0x2c, 0x5b,
+ 0xcb, 0x14, 0x03, 0xd1, 0x0c, 0xfe, 0xff, 0xf8, 0x9f, 0x3e, 0xda, 0xfb,
+ 0x8b, 0xf8, 0x75, 0x8b, 0xff, 0x75, 0xf7, 0x2f, 0x70, 0xe5, 0x0b, 0x17,
+ 0x1b, 0x25, 0x8b, 0xfd, 0x1a, 0x00, 0xdd, 0xcd, 0x58, 0xac, 0x3c, 0xdf,
+ 0x8c, 0xdf, 0xbe, 0xdd, 0x7f, 0x38, 0x8a, 0xdf, 0x42, 0x32, 0x86, 0x9a,
+ 0x06, 0x43, 0xee, 0xff, 0xff, 0xb4, 0x68, 0xff, 0x1c, 0xfe, 0x77, 0x2f,
+ 0x34, 0xd1, 0xc1, 0x2c, 0x5f, 0xfc, 0xdf, 0x73, 0x87, 0x03, 0xd6, 0xa1,
+ 0x62, 0x9d, 0x16, 0x1e, 0x6b, 0xac, 0x47, 0xd3, 0xc3, 0x62, 0xfd, 0x05,
+ 0xec, 0xfa, 0xc5, 0xe8, 0xef, 0x8b, 0x14, 0xc7, 0x8b, 0xf2, 0x7b, 0xe2,
+ 0xdb, 0xd4, 0xcb, 0x17, 0xff, 0x47, 0x59, 0xac, 0xfb, 0x6b, 0xee, 0xb1,
+ 0x7f, 0xf8, 0x4e, 0x19, 0x66, 0x7d, 0xba, 0xfe, 0x2c, 0x5f, 0x4c, 0x50,
+ 0x7d, 0x22, 0x38, 0x91, 0x2f, 0xff, 0x9f, 0x40, 0xdc, 0xcd, 0x44, 0x9b,
+ 0xbf, 0x62, 0xc5, 0xff, 0x61, 0x7b, 0xef, 0x28, 0x9d, 0x62, 0xff, 0xfa,
+ 0x4d, 0xe0, 0xf5, 0x1f, 0x8f, 0x71, 0xfb, 0x58, 0xbf, 0x0b, 0x9f, 0x79,
+ 0x62, 0x22, 0xf8, 0x73, 0x7f, 0x4a, 0x36, 0xc1, 0xce, 0xb1, 0x7e, 0xc0,
+ 0x8d, 0x13, 0x2c, 0x5f, 0x38, 0x30, 0xa0, 0xf6, 0xbe, 0x61, 0x7f, 0xfb,
+ 0x7f, 0xd8, 0x78, 0xc6, 0xb1, 0x66, 0xf5, 0x8b, 0xf4, 0x61, 0x7b, 0x71,
+ 0x62, 0xfe, 0x6e, 0xc1, 0xa7, 0x1a, 0xc5, 0xff, 0xed, 0xe5, 0x9c, 0xdb,
+ 0x84, 0x29, 0x67, 0x16, 0x29, 0x62, 0xb0, 0xf6, 0x4e, 0x9b, 0x47, 0x46,
+ 0x9f, 0xca, 0x8a, 0x11, 0x17, 0xef, 0xc6, 0xb8, 0xcb, 0x17, 0x6b, 0x75,
+ 0x62, 0xf3, 0x44, 0x96, 0x2f, 0x48, 0x43, 0x58, 0xb7, 0x7b, 0x51, 0x62,
+ 0x33, 0x49, 0x8a, 0x3e, 0x36, 0xe3, 0x95, 0x8a, 0x89, 0x1e, 0x3d, 0x1b,
+ 0xfc, 0xe4, 0x1b, 0xcb, 0x06, 0xb1, 0x50, 0xba, 0x37, 0x90, 0xb5, 0x63,
+ 0x9d, 0x43, 0x78, 0xa1, 0x33, 0xc9, 0x4b, 0x42, 0x29, 0xbf, 0x9b, 0x5b,
+ 0x17, 0x3c, 0xcb, 0x17, 0x4a, 0x16, 0x2f, 0xc5, 0x1f, 0xc1, 0xac, 0x5f,
+ 0xfd, 0xc8, 0x06, 0x7d, 0xb4, 0xe6, 0x79, 0x62, 0xe2, 0x9c, 0x67, 0xd9,
+ 0xc2, 0x7a, 0x92, 0x2c, 0x72, 0x10, 0x77, 0xf0, 0xf0, 0x8d, 0xd4, 0x2c,
+ 0x5d, 0xb9, 0xda, 0xc5, 0xff, 0x9b, 0x4d, 0x3b, 0x75, 0xf8, 0xf2, 0xc5,
+ 0x49, 0xbb, 0x6c, 0x1c, 0xba, 0x0e, 0xa1, 0x8b, 0xdc, 0x71, 0x33, 0x4b,
+ 0x16, 0xd4, 0xb8, 0x73, 0xc7, 0xa9, 0xf9, 0x4e, 0x80, 0x84, 0x39, 0x4a,
+ 0x5d, 0xe3, 0x5f, 0xa7, 0x4f, 0x37, 0xbc, 0x99, 0x0e, 0x4d, 0xc2, 0x70,
+ 0xcb, 0x82, 0x0e, 0x5e, 0xeb, 0xf3, 0x2c, 0x5f, 0x3c, 0xe2, 0x31, 0x62,
+ 0xff, 0xdd, 0x7e, 0x3b, 0x97, 0x5f, 0xc1, 0xac, 0x5c, 0x17, 0x08, 0xb1,
+ 0x79, 0x8f, 0x8b, 0x17, 0x41, 0xab, 0x15, 0x24, 0x5d, 0x0c, 0x97, 0xb4,
+ 0x3d, 0x0f, 0x18, 0x39, 0x7f, 0xc5, 0x86, 0x6b, 0x3a, 0xfe, 0x2c, 0x5f,
+ 0xff, 0xfd, 0xa6, 0x9f, 0x82, 0x8d, 0xa5, 0x9f, 0x68, 0x2f, 0x1a, 0x28,
+ 0xd2, 0xc5, 0xba, 0x58, 0xbf, 0xff, 0x4d, 0x26, 0x33, 0xdf, 0xcf, 0xe7,
+ 0x72, 0x73, 0x16, 0x2f, 0xff, 0xec, 0x1f, 0xe0, 0xc2, 0xc6, 0x9f, 0x70,
+ 0x5f, 0x6d, 0x2c, 0x54, 0xe9, 0xbd, 0x0c, 0xeb, 0x75, 0xd3, 0x42, 0x64,
+ 0xb5, 0x50, 0xe8, 0x40, 0xb2, 0x1c, 0x4d, 0x5d, 0xfb, 0x4d, 0x19, 0xe3,
+ 0xc3, 0x68, 0x51, 0xe3, 0x5b, 0xb5, 0x8b, 0xe8, 0xe9, 0xba, 0x58, 0xbd,
+ 0xa6, 0x31, 0x62, 0xff, 0x68, 0x53, 0xb4, 0x8e, 0x35, 0x8b, 0xfd, 0xcc,
+ 0xd0, 0xc9, 0xe4, 0xb1, 0x43, 0x44, 0x3e, 0x87, 0xb8, 0x6d, 0x7f, 0x7a,
+ 0x25, 0xb9, 0x39, 0x2c, 0x5f, 0xc4, 0x2e, 0x36, 0x69, 0x62, 0xfe, 0xda,
+ 0x58, 0x01, 0x71, 0x62, 0xb0, 0xf7, 0x5c, 0xb6, 0xf7, 0xf0, 0x0b, 0x16,
+ 0x85, 0x8b, 0xff, 0xe9, 0x9d, 0xe5, 0xc8, 0x38, 0xff, 0x05, 0xd2, 0xc5,
+ 0x41, 0xf1, 0x30, 0x8d, 0xff, 0x0b, 0xac, 0xd4, 0xf3, 0x8a, 0x75, 0x8b,
+ 0xfe, 0xc9, 0xa5, 0x1d, 0xe7, 0x7e, 0x58, 0xad, 0xa9, 0x9d, 0x41, 0x06,
+ 0x3f, 0x9c, 0x80, 0x8f, 0xef, 0x4e, 0xdd, 0xac, 0x5d, 0xf1, 0xac, 0x54,
+ 0x2a, 0x4a, 0x9e, 0x3c, 0x96, 0x4a, 0xe0, 0xfd, 0x6d, 0x56, 0xf9, 0x21,
+ 0x31, 0xc2, 0xaf, 0x52, 0x9e, 0xaf, 0x87, 0xf1, 0x4e, 0xb1, 0x7f, 0x3c,
+ 0xb2, 0x71, 0x12, 0xc5, 0xd8, 0x35, 0x8a, 0x19, 0xe2, 0xf4, 0x5d, 0x7f,
+ 0xed, 0x66, 0xec, 0xdf, 0x73, 0xb7, 0x16, 0x2f, 0xef, 0x31, 0x87, 0x6f,
+ 0x2c, 0x5f, 0xf3, 0x96, 0xb1, 0xbf, 0x03, 0x58, 0xb6, 0x78, 0xf9, 0x82,
+ 0x17, 0xda, 0x78, 0x4d, 0x7f, 0x1a, 0xb4, 0x47, 0xf8, 0x54, 0xd9, 0x96,
+ 0x2e, 0x0b, 0xe2, 0xc5, 0x61, 0xfa, 0x69, 0x21, 0xc4, 0x6f, 0xfd, 0xbd,
+ 0xbd, 0x28, 0xdb, 0xe8, 0x12, 0xc5, 0xa6, 0x58, 0xbd, 0xbf, 0x06, 0xb1,
+ 0x7e, 0xdc, 0x17, 0xf3, 0xa5, 0x8b, 0x8f, 0xc5, 0x8a, 0xc4, 0x5d, 0x4c,
+ 0x86, 0x71, 0x3f, 0x0f, 0x88, 0xb6, 0xfe, 0x8f, 0x30, 0x22, 0x4b, 0x17,
+ 0x49, 0xd6, 0x2b, 0x47, 0x88, 0xe5, 0xb7, 0xf7, 0x73, 0xbc, 0xa3, 0x75,
+ 0x62, 0xe2, 0x92, 0xc5, 0x41, 0xe5, 0x4e, 0x67, 0x71, 0x90, 0xb1, 0x5b,
+ 0x5d, 0x83, 0x08, 0x50, 0xc0, 0x2b, 0x09, 0x08, 0x87, 0xb4, 0xe5, 0xd2,
+ 0x31, 0xc5, 0xf3, 0x48, 0xfa, 0x84, 0x9b, 0x42, 0xdc, 0xf0, 0xe0, 0xfd,
+ 0xa3, 0x70, 0x79, 0x7e, 0xc5, 0x28, 0x83, 0x90, 0xe7, 0xf4, 0x23, 0x84,
+ 0xd7, 0xb8, 0x45, 0x7f, 0xe0, 0xa8, 0x70, 0x7e, 0xbe, 0xfd, 0x81, 0x62,
+ 0xff, 0x4a, 0x6c, 0x27, 0xfe, 0x2c, 0x5f, 0x77, 0x28, 0x3a, 0xc5, 0xff,
+ 0x41, 0x4f, 0xcc, 0x3c, 0x6e, 0xac, 0x5f, 0xff, 0x4f, 0xec, 0xe7, 0xc5,
+ 0xc8, 0x9c, 0x45, 0x0b, 0x17, 0xff, 0xfd, 0x2d, 0x69, 0xbd, 0xcf, 0xe3,
+ 0x11, 0x67, 0x7e, 0xe3, 0x2c, 0x5d, 0x1f, 0x58, 0xbf, 0x82, 0xfd, 0x7d,
+ 0xc5, 0x25, 0x8b, 0xf9, 0xe6, 0x1c, 0x14, 0xeb, 0x15, 0x3a, 0x72, 0x43,
+ 0x24, 0xc3, 0xc7, 0x52, 0x26, 0x61, 0x0b, 0xef, 0x34, 0xbf, 0x9f, 0xc0,
+ 0x0c, 0xa6, 0x58, 0xbf, 0xdf, 0x7f, 0x70, 0xcc, 0xfa, 0xc5, 0xe9, 0x9b,
+ 0xeb, 0x17, 0x3c, 0x96, 0x2a, 0x0d, 0xae, 0x87, 0xaf, 0xef, 0x16, 0x4e,
+ 0xda, 0x58, 0xbf, 0x67, 0x9c, 0x80, 0xb1, 0x50, 0x7a, 0xa2, 0x2e, 0xbc,
+ 0x12, 0x0e, 0xb1, 0x58, 0x98, 0xfb, 0xb5, 0x71, 0xd4, 0x21, 0x0d, 0xf8,
+ 0x87, 0xf8, 0x92, 0xc5, 0xe2, 0x8e, 0x96, 0x2f, 0xd8, 0xc6, 0xb1, 0xab,
+ 0x17, 0xd1, 0x2c, 0xe2, 0xc5, 0xff, 0x39, 0x81, 0x91, 0x67, 0x72, 0x58,
+ 0xac, 0x45, 0x1e, 0x87, 0x7e, 0x52, 0xe4, 0x57, 0xc1, 0x20, 0xba, 0x58,
+ 0xbf, 0x61, 0xaf, 0x13, 0xac, 0x5e, 0xf7, 0xa1, 0x62, 0xbe, 0x78, 0xce,
+ 0x53, 0x7d, 0x13, 0x6a, 0x16, 0x2d, 0x0b, 0x16, 0xc5, 0x8a, 0xd1, 0xa2,
+ 0x38, 0x8d, 0x1c, 0xf9, 0xbe, 0x8b, 0x7d, 0x02, 0x0b, 0xb2, 0xc5, 0xf7,
+ 0x0a, 0x0c, 0x58, 0xbf, 0x0f, 0xf8, 0x52, 0x58, 0xac, 0x3c, 0xb7, 0x23,
+ 0xbd, 0x26, 0x02, 0xc5, 0xf4, 0xe7, 0x10, 0xd6, 0x2f, 0x04, 0x69, 0xd6,
+ 0x2d, 0x18, 0x78, 0xa1, 0x09, 0x6f, 0xff, 0xec, 0xf7, 0x03, 0xe7, 0xbe,
+ 0xe4, 0x6e, 0x6f, 0x83, 0x16, 0x2f, 0xb9, 0xe6, 0x99, 0x62, 0x8e, 0x88,
+ 0x47, 0x60, 0xbf, 0xcd, 0xa8, 0x9d, 0xf5, 0xd2, 0xc5, 0xdd, 0x4c, 0xb1,
+ 0x5b, 0x57, 0x1a, 0x20, 0xf8, 0x70, 0xcb, 0xc3, 0xbe, 0x9a, 0xda, 0x10,
+ 0xfa, 0x22, 0xfb, 0x8b, 0x90, 0x13, 0x17, 0x21, 0x59, 0xe2, 0x2d, 0xc3,
+ 0x5a, 0x3a, 0xf3, 0xe7, 0xa7, 0x6d, 0xef, 0xff, 0x6b, 0xa2, 0xcd, 0xe5,
+ 0x91, 0xa8, 0xe2, 0xc5, 0xff, 0x8e, 0xd9, 0xde, 0x30, 0xe0, 0x22, 0xc5,
+ 0xfe, 0x79, 0xbf, 0x87, 0xce, 0x2c, 0x56, 0x22, 0xff, 0x49, 0x7b, 0xd0,
+ 0x2f, 0x6f, 0x7f, 0xac, 0x5d, 0x1e, 0x58, 0xa8, 0x36, 0xdb, 0x83, 0xf7,
+ 0xd1, 0xbd, 0xb7, 0xac, 0x5d, 0x87, 0x58, 0xb1, 0xbb, 0x4d, 0xeb, 0x13,
+ 0x54, 0xe8, 0x89, 0x26, 0x0b, 0xf1, 0xbe, 0xcc, 0x3a, 0xc5, 0xff, 0xa5,
+ 0x26, 0xea, 0x0f, 0x37, 0x21, 0x62, 0xff, 0xf4, 0xe1, 0xfd, 0xa0, 0xa7,
+ 0x01, 0xe2, 0x4b, 0x15, 0x88, 0xda, 0x62, 0x37, 0x29, 0x12, 0x0d, 0xff,
+ 0xc5, 0x86, 0x9a, 0xfe, 0xe3, 0x14, 0xcb, 0x17, 0xb2, 0x4c, 0xb1, 0x6c,
+ 0x58, 0xa9, 0x8f, 0xcf, 0x48, 0xc0, 0x1c, 0xbd, 0x93, 0x92, 0xc5, 0xec,
+ 0x17, 0x6b, 0x15, 0xf3, 0x76, 0x43, 0xb7, 0xec, 0x1b, 0x6b, 0x8b, 0x14,
+ 0xb1, 0x7d, 0x26, 0x07, 0x16, 0x2b, 0x86, 0xbc, 0x30, 0xcb, 0xc2, 0x7d,
+ 0x2c, 0x5f, 0x75, 0x19, 0x3a, 0xc5, 0x31, 0xe0, 0xe8, 0x76, 0xf7, 0xbd,
+ 0xda, 0xc5, 0xff, 0xdd, 0xf4, 0xdf, 0xda, 0x13, 0x3e, 0xc7, 0x58, 0xa0,
+ 0x1f, 0x57, 0x87, 0xee, 0x16, 0x96, 0x2f, 0xa3, 0xad, 0xcc, 0x58, 0xac,
+ 0x47, 0x5f, 0x21, 0x17, 0xb8, 0x44, 0x18, 0xc5, 0x4e, 0x9f, 0x51, 0xd5,
+ 0xcc, 0x8d, 0x3a, 0xf8, 0x3f, 0xe7, 0x4b, 0x17, 0xee, 0x79, 0xdc, 0x96,
+ 0x2b, 0xb3, 0xcc, 0x30, 0x96, 0xa1, 0x15, 0x2d, 0x08, 0x5b, 0xff, 0xf3,
+ 0xfa, 0x62, 0x80, 0x73, 0x25, 0xf6, 0x20, 0x2c, 0x54, 0x33, 0x77, 0xb2,
+ 0x7b, 0x85, 0xa1, 0xdb, 0xf8, 0xf2, 0x9e, 0x15, 0xbc, 0x6b, 0xf4, 0xab,
+ 0x31, 0x13, 0x5f, 0xf8, 0x98, 0x3e, 0xf3, 0x7f, 0x70, 0x1a, 0xc5, 0xa4,
+ 0xb1, 0x7f, 0xed, 0x0e, 0x0c, 0xcf, 0xc7, 0x7c, 0x58, 0xbf, 0xfe, 0xe1,
+ 0x67, 0x98, 0x8c, 0xf7, 0x1f, 0xbe, 0x96, 0x2c, 0xd8, 0x89, 0x3e, 0xd0,
+ 0x6f, 0xef, 0x46, 0x8b, 0x27, 0x58, 0xbe, 0x0e, 0x34, 0x05, 0x8b, 0xff,
+ 0x47, 0x7f, 0xfc, 0x4f, 0x02, 0x3a, 0xc5, 0xfe, 0x9b, 0x82, 0x91, 0x41,
+ 0xd6, 0x2d, 0xb0, 0x2c, 0x5f, 0xfd, 0xad, 0x38, 0x33, 0xed, 0xaf, 0xba,
+ 0xc5, 0xa4, 0xb1, 0x41, 0x53, 0xed, 0xe0, 0xb8, 0x68, 0x97, 0xfd, 0x2e,
+ 0x7c, 0x50, 0x53, 0x81, 0x62, 0xf3, 0x18, 0x17, 0x58, 0xbb, 0x38, 0xb1,
+ 0x6d, 0x2c, 0x57, 0x68, 0x86, 0x98, 0xef, 0xe4, 0x4e, 0x2f, 0x7f, 0xfe,
+ 0x37, 0x3c, 0xdc, 0xf8, 0xb3, 0xc0, 0x71, 0xc2, 0xc5, 0xfd, 0xe6, 0x9c,
+ 0xf1, 0xd2, 0xc5, 0x0d, 0x18, 0x9a, 0x3e, 0xfa, 0xb5, 0xef, 0x66, 0xf5,
+ 0x8b, 0xff, 0x0d, 0xdc, 0xce, 0xfc, 0x4f, 0xf5, 0x8a, 0x73, 0xdf, 0xe0,
+ 0xfd, 0xf4, 0x9b, 0x52, 0x58, 0xbf, 0x81, 0x34, 0x9b, 0x52, 0x58, 0x98,
+ 0xd1, 0xdf, 0x67, 0x4f, 0xd2, 0xc5, 0xf4, 0x16, 0x69, 0x62, 0xef, 0xe7,
+ 0xcf, 0x17, 0x84, 0x97, 0x34, 0xeb, 0x15, 0xd1, 0xe2, 0xf8, 0xb6, 0x8d,
+ 0x4c, 0xcb, 0xb4, 0x4d, 0x43, 0x2e, 0xf4, 0xf8, 0x62, 0xc5, 0xfe, 0xea,
+ 0x66, 0x38, 0x9f, 0x8b, 0x17, 0xd8, 0x2d, 0x4e, 0xb1, 0x74, 0x6e, 0xac,
+ 0x50, 0xd1, 0x27, 0xd8, 0xf9, 0xcd, 0xbe, 0x49, 0x7d, 0xa8, 0x16, 0xea,
+ 0xc5, 0xe8, 0x18, 0xd6, 0x2e, 0xc0, 0x8b, 0x17, 0xc0, 0x0c, 0xa4, 0xb1,
+ 0x67, 0x23, 0x7b, 0xe1, 0x9b, 0xf7, 0x39, 0x84, 0x05, 0x8a, 0x01, 0xe6,
+ 0x91, 0x2d, 0x42, 0xbb, 0x86, 0x8f, 0x05, 0xe1, 0x97, 0xc3, 0xef, 0x13,
+ 0x0a, 0x14, 0xf6, 0x99, 0x62, 0xff, 0x84, 0xe1, 0xcd, 0x2c, 0xee, 0x4b,
+ 0x15, 0xd9, 0xe8, 0x10, 0x9d, 0xf1, 0x3f, 0x7c, 0x58, 0xbe, 0xf0, 0x0f,
+ 0x8b, 0x15, 0xe3, 0xc6, 0x0c, 0x8e, 0x8e, 0x88, 0xb0, 0x34, 0x5d, 0x1c,
+ 0x58, 0xbe, 0x8f, 0xc0, 0xd6, 0x2b, 0xa3, 0x73, 0x30, 0xbd, 0xff, 0xfd,
+ 0xfc, 0x2f, 0x73, 0x68, 0x72, 0xfe, 0x11, 0x0a, 0x4b, 0x17, 0xf7, 0xe3,
+ 0x45, 0x12, 0x58, 0xbf, 0xe2, 0xef, 0xd9, 0x28, 0x2e, 0x96, 0x2c, 0x68,
+ 0xcf, 0x9c, 0x45, 0xb7, 0xef, 0xb1, 0x3c, 0xeb, 0x17, 0xfd, 0x27, 0xd7,
+ 0x8a, 0x0f, 0xc5, 0x8b, 0xfd, 0x03, 0x8d, 0x0a, 0x00, 0xb1, 0x7d, 0xbe,
+ 0x33, 0x4b, 0x17, 0x67, 0x6b, 0x15, 0x86, 0xf0, 0x89, 0x2d, 0xce, 0x91,
+ 0xdf, 0x31, 0x41, 0xce, 0x49, 0xbe, 0xff, 0xf4, 0x6e, 0x87, 0x3f, 0x3f,
+ 0xd3, 0x73, 0x06, 0xb1, 0x50, 0x9d, 0x69, 0xe3, 0x18, 0xfa, 0x25, 0xff,
+ 0xf4, 0x67, 0x7e, 0xfe, 0x34, 0x98, 0xd3, 0x71, 0x62, 0xfc, 0x50, 0x10,
+ 0xa1, 0x62, 0xff, 0xf3, 0xbe, 0xa7, 0xfb, 0xfb, 0xed, 0xa9, 0x2c, 0x5f,
+ 0xb4, 0x3f, 0xb4, 0xcb, 0x17, 0xf1, 0x47, 0x72, 0x62, 0x58, 0xbd, 0xf8,
+ 0xd2, 0xc0, 0xcd, 0x6d, 0xfd, 0x8c, 0x45, 0x03, 0x58, 0xb9, 0xcc, 0x1a,
+ 0x3e, 0xb1, 0x2f, 0xa5, 0x7f, 0x96, 0xdf, 0xf3, 0x96, 0x7b, 0xcc, 0x67,
+ 0x96, 0x2f, 0xff, 0xfe, 0x9a, 0x4c, 0x5e, 0x80, 0x04, 0xf3, 0x1b, 0xac,
+ 0x8e, 0xe4, 0xc7, 0x58, 0xa8, 0x45, 0x79, 0x1c, 0xd4, 0x2e, 0xd9, 0xe2,
+ 0xe7, 0x44, 0x6d, 0x29, 0xcb, 0x46, 0xce, 0xa2, 0x51, 0x91, 0x0a, 0x1f,
+ 0x15, 0xb1, 0x37, 0xed, 0x90, 0x8f, 0x2a, 0x7d, 0x1e, 0x42, 0x40, 0xd4,
+ 0x4e, 0xa1, 0x4a, 0xc5, 0x13, 0x17, 0x7c, 0x91, 0xd0, 0x41, 0x0a, 0x2e,
+ 0x4e, 0x9b, 0x7a, 0x7b, 0xd2, 0xfd, 0xb0, 0xbb, 0x96, 0x79, 0x62, 0xfe,
+ 0x2c, 0x9a, 0x51, 0xda, 0xc5, 0xff, 0xbb, 0x96, 0x79, 0xb7, 0xc1, 0x74,
+ 0xb1, 0x52, 0x3f, 0x1f, 0x17, 0xdf, 0xd0, 0x2e, 0xdb, 0xb0, 0x8b, 0x17,
+ 0xec, 0x33, 0x3b, 0xf2, 0xc5, 0x6d, 0x3d, 0xc6, 0x32, 0xbf, 0xdd, 0xcb,
+ 0x07, 0xfc, 0x9d, 0x62, 0xbb, 0x46, 0xbe, 0x9f, 0x88, 0x8e, 0xf6, 0xc7,
+ 0xb1, 0x76, 0xb1, 0x7e, 0xef, 0x68, 0x71, 0xc5, 0x8b, 0x71, 0x62, 0xdf,
+ 0x83, 0x7e, 0x19, 0x6d, 0xfa, 0x35, 0xdc, 0xb8, 0xb1, 0x7f, 0xd1, 0x3e,
+ 0xd7, 0x08, 0x11, 0xc0, 0xb1, 0x7f, 0x3c, 0x80, 0xc5, 0xe5, 0x8b, 0xff,
+ 0xfe, 0xd4, 0xcf, 0xf6, 0xe4, 0x4c, 0xde, 0xf6, 0x7c, 0x0d, 0xbd, 0x62,
+ 0xb6, 0x24, 0xe4, 0x21, 0xa2, 0x72, 0x7d, 0x15, 0x1d, 0x00, 0x45, 0xb7,
+ 0xff, 0x0b, 0x59, 0x3c, 0x72, 0x25, 0x1a, 0x58, 0xbd, 0xac, 0xe2, 0xc5,
+ 0xf9, 0x8b, 0x7e, 0x49, 0x62, 0xf6, 0x34, 0xeb, 0x14, 0x69, 0xf1, 0x9c,
+ 0x77, 0xe5, 0x37, 0xf4, 0x4f, 0x9e, 0xc3, 0xac, 0x5f, 0x83, 0xdb, 0xfe,
+ 0x62, 0xc5, 0xff, 0x88, 0x5d, 0x7f, 0x0f, 0x33, 0xf4, 0xb1, 0x70, 0xb4,
+ 0xb1, 0x58, 0x7b, 0x5b, 0x88, 0x55, 0x24, 0xec, 0x1a, 0x15, 0x1a, 0x30,
+ 0x01, 0x77, 0x21, 0x0d, 0x7c, 0x76, 0x81, 0xac, 0x5f, 0xe2, 0x37, 0xf0,
+ 0x73, 0x92, 0xc5, 0xfd, 0xba, 0xd0, 0x10, 0x5e, 0x58, 0xbf, 0x44, 0xd9,
+ 0x9d, 0x2c, 0x5e, 0x2c, 0x08, 0xb1, 0x50, 0x8d, 0x0c, 0x22, 0x63, 0x4f,
+ 0x99, 0x88, 0xa6, 0xf1, 0xdf, 0xcb, 0x17, 0xc7, 0x78, 0xed, 0x62, 0x88,
+ 0xf0, 0x0c, 0x1d, 0xbf, 0xde, 0xe3, 0x6f, 0xd3, 0x71, 0x62, 0xfb, 0xdf,
+ 0x69, 0x96, 0x2f, 0xe6, 0xd0, 0x65, 0x28, 0x58, 0xb1, 0x90, 0x7a, 0x52,
+ 0x24, 0xb9, 0xa4, 0xb1, 0x58, 0x8c, 0x76, 0x84, 0x41, 0x14, 0x5f, 0xfe,
+ 0xe3, 0xe6, 0xf6, 0xf4, 0xb0, 0xd3, 0x71, 0x62, 0xf1, 0xb1, 0xd2, 0xc5,
+ 0xff, 0x64, 0xcd, 0x30, 0x82, 0x0b, 0x8b, 0x16, 0x75, 0x8a, 0xf9, 0xe7,
+ 0xf8, 0xfa, 0xfe, 0x89, 0xb0, 0x85, 0x8b, 0x17, 0x68, 0xd5, 0x8a, 0x83,
+ 0xc6, 0x62, 0xdb, 0xef, 0x34, 0x76, 0xb1, 0x7d, 0x93, 0xc4, 0xcb, 0x15,
+ 0x09, 0x9e, 0xb3, 0x71, 0x34, 0x70, 0x80, 0x44, 0x77, 0xfd, 0x13, 0x47,
+ 0xbf, 0x9a, 0xe9, 0x62, 0xf7, 0xe2, 0x65, 0x8b, 0x47, 0x67, 0xb2, 0x10,
+ 0xee, 0xa4, 0x8c, 0xbe, 0x42, 0x86, 0xf0, 0xa6, 0x65, 0x8b, 0x99, 0x96,
+ 0x2b, 0x74, 0xda, 0x10, 0xf5, 0xfb, 0xef, 0xef, 0x86, 0xb1, 0x73, 0xce,
+ 0xb1, 0x7f, 0x39, 0xf3, 0x7b, 0xe9, 0x62, 0xa7, 0x3c, 0x73, 0x8c, 0x5f,
+ 0xfa, 0x66, 0xfc, 0x77, 0x28, 0x9a, 0x16, 0x2b, 0xa4, 0x6a, 0xb3, 0x88,
+ 0x88, 0xef, 0x47, 0x8e, 0xb1, 0x7f, 0xfc, 0x1b, 0x1f, 0x69, 0xa4, 0x2e,
+ 0x77, 0xd3, 0x76, 0xb1, 0x63, 0xac, 0x54, 0x1f, 0x57, 0x16, 0x28, 0xe8,
+ 0xa8, 0x09, 0x08, 0x7b, 0xfe, 0xe0, 0xa7, 0x89, 0xb6, 0x83, 0xcb, 0x17,
+ 0xe1, 0xb9, 0x47, 0xd6, 0x2f, 0xf6, 0xf6, 0xd6, 0x6f, 0x7d, 0x2c, 0x5f,
+ 0xd2, 0x8e, 0xfd, 0x9f, 0x58, 0xbf, 0xfd, 0xee, 0x30, 0x22, 0x5c, 0xcc,
+ 0xef, 0xcb, 0x15, 0x88, 0xb1, 0x98, 0xdf, 0x85, 0xf5, 0xda, 0x68, 0xff,
+ 0x3f, 0x32, 0x1b, 0x17, 0xfb, 0x3a, 0xc2, 0x8c, 0x31, 0x62, 0xff, 0x1e,
+ 0x26, 0x3c, 0x0e, 0x16, 0x2f, 0xd3, 0x63, 0x04, 0x1a, 0xc5, 0xbe, 0xc7,
+ 0xbe, 0xe6, 0x97, 0xff, 0xf0, 0x6e, 0x4d, 0xdb, 0x4d, 0x01, 0x04, 0x18,
+ 0xb9, 0xe5, 0x8b, 0xff, 0x47, 0xb8, 0xec, 0x31, 0x7b, 0x8b, 0x15, 0x0a,
+ 0xc0, 0x5a, 0x37, 0x1f, 0x9c, 0x72, 0x12, 0x42, 0x26, 0x31, 0x86, 0xfd,
+ 0x9d, 0xcb, 0xec, 0xb1, 0x7f, 0xf3, 0x16, 0x7a, 0x0f, 0xb4, 0x26, 0xff,
+ 0x2c, 0x5f, 0x04, 0x21, 0x4e, 0xb1, 0x5b, 0x51, 0x33, 0xba, 0x52, 0x74,
+ 0xab, 0xf9, 0xbe, 0xd3, 0x34, 0xeb, 0x16, 0x85, 0x8a, 0xe1, 0xe0, 0x78,
+ 0xbe, 0xfd, 0xe6, 0x29, 0x42, 0xc5, 0xfd, 0xdc, 0xb0, 0x5a, 0x9d, 0x62,
+ 0xff, 0xf6, 0xb5, 0x05, 0x86, 0xb7, 0xff, 0x81, 0xac, 0x56, 0x22, 0x8d,
+ 0x89, 0xc4, 0x63, 0x78, 0xa2, 0x4b, 0x15, 0x09, 0xc2, 0x63, 0xae, 0xa1,
+ 0x8a, 0xe5, 0xd7, 0xf3, 0x1a, 0xde, 0x7f, 0xac, 0x5e, 0xeb, 0xf0, 0xb1,
+ 0x76, 0xa1, 0x62, 0xa4, 0x7c, 0x7d, 0x97, 0x4c, 0x3d, 0x7e, 0x86, 0xf0,
+ 0x50, 0x2d, 0xd6, 0x2f, 0xce, 0xc3, 0x82, 0x58, 0xba, 0x04, 0xb1, 0x50,
+ 0x8a, 0x1f, 0x98, 0x91, 0x9f, 0x09, 0xae, 0x09, 0x0b, 0x17, 0x17, 0x4b,
+ 0x15, 0x06, 0xc5, 0x86, 0x6f, 0xf0, 0x98, 0xb3, 0x9c, 0xc5, 0x8a, 0x9c,
+ 0xf4, 0x4e, 0x3f, 0x76, 0x74, 0xb1, 0x7f, 0xcf, 0xef, 0xc7, 0x04, 0x3c,
+ 0x58, 0xbe, 0xf8, 0x1f, 0xcb, 0x16, 0xfa, 0xc5, 0x39, 0xb5, 0x11, 0x1d,
+ 0xfe, 0x2c, 0xf4, 0x48, 0x5a, 0x58, 0xa3, 0xa3, 0x64, 0x86, 0x37, 0xb7,
+ 0x04, 0x20, 0xbf, 0x01, 0xce, 0xfd, 0xac, 0x5f, 0xf8, 0xed, 0xcf, 0xc3,
+ 0x68, 0x5b, 0xab, 0x15, 0xd9, 0xf5, 0xb1, 0x4d, 0x42, 0x79, 0x2d, 0x0f,
+ 0xc7, 0x85, 0x5d, 0xe7, 0xd7, 0x4b, 0x17, 0xee, 0x36, 0xf8, 0x1a, 0xc5,
+ 0x00, 0xf2, 0x08, 0x7a, 0xff, 0x80, 0xc5, 0xe8, 0xe0, 0xbe, 0xb1, 0x7e,
+ 0x80, 0xf9, 0x1c, 0x58, 0xbf, 0xda, 0x9d, 0xba, 0x6d, 0x62, 0xc5, 0xe2,
+ 0x63, 0x56, 0x2f, 0xcf, 0xad, 0x44, 0xeb, 0x17, 0xf7, 0x9b, 0x4d, 0xe1,
+ 0x2c, 0x5a, 0x36, 0xa6, 0x17, 0x39, 0xce, 0x14, 0x9c, 0xd7, 0xc3, 0xa1,
+ 0x94, 0xdf, 0x83, 0xfe, 0x77, 0xc5, 0x8b, 0x9f, 0x75, 0x62, 0x84, 0x78,
+ 0xa1, 0x95, 0xdf, 0xff, 0xd1, 0xce, 0xbe, 0xdf, 0xcd, 0xf8, 0xd1, 0x38,
+ 0x86, 0xb1, 0x7f, 0xff, 0xfd, 0x1e, 0x27, 0xe9, 0xb9, 0x33, 0x6b, 0xa8,
+ 0xe7, 0xa3, 0xb8, 0x0f, 0x38, 0xb1, 0x7f, 0xb9, 0x9a, 0x8d, 0xf1, 0xba,
+ 0xb1, 0x46, 0xa6, 0x2d, 0xa5, 0xef, 0x42, 0x02, 0xff, 0x7f, 0x3b, 0x8d,
+ 0x31, 0xd6, 0x2f, 0xfa, 0x3a, 0xd6, 0x73, 0x18, 0x6b, 0x17, 0xff, 0x9b,
+ 0x59, 0x33, 0x68, 0x23, 0x07, 0x92, 0x58, 0xad, 0x22, 0x1b, 0x87, 0x37,
+ 0xa0, 0xf0, 0xb1, 0x5a, 0x37, 0xfe, 0x23, 0xbf, 0xc7, 0x27, 0x35, 0xbe,
+ 0x25, 0x8b, 0xef, 0xb3, 0x81, 0x62, 0xd1, 0xb4, 0xf5, 0xbc, 0x69, 0x7f,
+ 0xff, 0xff, 0xdc, 0xcf, 0x7d, 0xcf, 0xcd, 0x69, 0xbb, 0xf3, 0xb9, 0xb9,
+ 0x93, 0x0b, 0xd0, 0x67, 0x70, 0xb1, 0x7e, 0x14, 0xd9, 0xb9, 0x8b, 0x17,
+ 0x7d, 0xd6, 0x2b, 0x88, 0xdb, 0xf4, 0x26, 0x37, 0x96, 0x5f, 0xf7, 0x7c,
+ 0x26, 0x3f, 0xb3, 0x75, 0x62, 0xec, 0xd2, 0xc5, 0x41, 0xea, 0x7c, 0xf6,
+ 0xfe, 0xf1, 0x38, 0x30, 0x96, 0x2e, 0x83, 0x56, 0x2f, 0x9c, 0x18, 0x4b,
+ 0x15, 0x31, 0xb9, 0x21, 0x8a, 0xda, 0x88, 0x6f, 0x32, 0xd4, 0x2e, 0x01,
+ 0x0c, 0xdf, 0x21, 0xf3, 0xd3, 0xbb, 0xc6, 0x09, 0xe8, 0x45, 0x8a, 0x14,
+ 0xf7, 0xfa, 0x4f, 0xdb, 0x04, 0x61, 0xac, 0x5f, 0x01, 0xfb, 0xe2, 0xc5,
+ 0xc6, 0x18, 0xb1, 0x5c, 0x37, 0xc6, 0x12, 0x5f, 0x7d, 0xf3, 0xe9, 0x1b,
+ 0x26, 0x8a, 0xff, 0xfc, 0x1b, 0x1c, 0x5c, 0x80, 0xd8, 0xf1, 0x34, 0x18,
+ 0xb1, 0x73, 0x4e, 0xb1, 0x50, 0x99, 0xe3, 0x42, 0x59, 0xcd, 0x77, 0xac,
+ 0xdf, 0x75, 0x02, 0xed, 0x62, 0xfc, 0x1e, 0x1d, 0xb4, 0xb1, 0x7e, 0x6d,
+ 0x7b, 0x3a, 0x58, 0xbf, 0x74, 0xdc, 0xfb, 0x2c, 0x5f, 0xdd, 0xb4, 0xe7,
+ 0x6e, 0x2c, 0x5c, 0x77, 0x58, 0xbf, 0xde, 0x82, 0xeb, 0x60, 0x01, 0xd6,
+ 0x2a, 0x11, 0x03, 0xf3, 0x01, 0x0b, 0xde, 0xfc, 0x01, 0x62, 0xf0, 0x40,
+ 0x90, 0xb1, 0x7f, 0xc3, 0xfb, 0x69, 0xbb, 0x9a, 0x16, 0x29, 0xcf, 0x70,
+ 0x44, 0x37, 0x6c, 0x7b, 0xd6, 0x2a, 0x15, 0x04, 0xe1, 0x29, 0xa5, 0x3d,
+ 0x94, 0xb4, 0x2a, 0x9c, 0xbc, 0x9e, 0x7c, 0x43, 0x7f, 0xff, 0x7f, 0x0d,
+ 0x78, 0x6d, 0xc8, 0xec, 0x27, 0x5f, 0x7e, 0xd6, 0x2f, 0xb4, 0xdd, 0x42,
+ 0xc5, 0x0d, 0x10, 0xd8, 0xc7, 0x7b, 0xfb, 0x77, 0x56, 0x2f, 0x17, 0x4c,
+ 0xb1, 0x78, 0xb2, 0x75, 0x8b, 0xee, 0x69, 0x8c, 0x58, 0xb7, 0xe0, 0xf0,
+ 0x5c, 0x76, 0xa1, 0x14, 0xec, 0x46, 0xeb, 0xd7, 0xff, 0xff, 0xe8, 0xf6,
+ 0xdf, 0x13, 0x80, 0x9a, 0x36, 0xc6, 0xf8, 0xd7, 0x1b, 0xd0, 0x53, 0xac,
+ 0x5f, 0x9a, 0x77, 0x11, 0x2c, 0x5f, 0xb4, 0x29, 0xc5, 0x3a, 0xc5, 0xfd,
+ 0x1e, 0x11, 0xc5, 0xe5, 0x8b, 0xfd, 0x05, 0xf7, 0x00, 0xa6, 0x58, 0xa8,
+ 0x44, 0x7f, 0xcb, 0x02, 0x17, 0xd6, 0xc2, 0x74, 0x98, 0x71, 0x1b, 0xc4,
+ 0xf1, 0xe0, 0x4a, 0x50, 0x68, 0xe3, 0x24, 0xc8, 0x43, 0x9b, 0x0e, 0x9e,
+ 0x8c, 0xbb, 0x94, 0xaa, 0xcb, 0x9b, 0xb0, 0xf8, 0x9a, 0x5e, 0xce, 0xa5,
+ 0x40, 0x1e, 0x34, 0x4f, 0xca, 0x86, 0x78, 0x40, 0x02, 0x32, 0xc0, 0xbc,
+ 0x29, 0x4a, 0x74, 0xef, 0x91, 0xdb, 0x7a, 0x52, 0x58, 0xa1, 0xf7, 0xbe,
+ 0x19, 0x3b, 0x85, 0xa1, 0xc2, 0x18, 0x24, 0x2d, 0xef, 0xb5, 0x9e, 0xc5,
+ 0x8b, 0xfd, 0xd7, 0xdb, 0xdc, 0x7e, 0xd6, 0x2f, 0x66, 0xb7, 0xac, 0x5e,
+ 0xd0, 0x73, 0x2c, 0x5c, 0x7f, 0xac, 0x53, 0x1b, 0x8e, 0x10, 0x5f, 0xf8,
+ 0x80, 0x77, 0x91, 0x47, 0xb8, 0xb1, 0x76, 0x62, 0xc5, 0xf7, 0x5f, 0x60,
+ 0xd6, 0x2b, 0x13, 0x48, 0x34, 0x89, 0x8d, 0xbe, 0xae, 0xe4, 0x01, 0x73,
+ 0xe0, 0xc5, 0xaf, 0xd3, 0x44, 0xdf, 0x85, 0x8b, 0xff, 0xc5, 0xee, 0x07,
+ 0xe6, 0x21, 0x4b, 0x38, 0xb1, 0x7f, 0xbe, 0x11, 0xcb, 0xdc, 0x02, 0xc5,
+ 0xff, 0x04, 0xe1, 0x3c, 0xc5, 0x07, 0x58, 0xb4, 0x2c, 0x50, 0x8f, 0x30,
+ 0x33, 0xbb, 0xec, 0xd3, 0xc9, 0x62, 0xfe, 0xfe, 0x4c, 0xe5, 0x3a, 0xc5,
+ 0xe3, 0x0c, 0x31, 0x22, 0xfa, 0x5e, 0xce, 0x92, 0x36, 0x4d, 0x0d, 0xfb,
+ 0x06, 0xc0, 0xe2, 0xee, 0xfe, 0x2b, 0x6a, 0x2f, 0x34, 0xa0, 0x46, 0xf7,
+ 0x72, 0x4b, 0x17, 0xb8, 0xe0, 0x58, 0xa8, 0x36, 0xbd, 0x8c, 0x5b, 0x7a,
+ 0xc5, 0xb7, 0x16, 0x2b, 0xa3, 0x52, 0x71, 0x4b, 0xf9, 0xb4, 0xd2, 0x83,
+ 0x56, 0x2b, 0x0f, 0x43, 0xc4, 0x55, 0x0a, 0xc6, 0x70, 0xa9, 0x92, 0xf5,
+ 0x08, 0x23, 0x91, 0xbc, 0x37, 0x80, 0xcc, 0x50, 0x9a, 0xbe, 0x38, 0xf0,
+ 0x96, 0x2e, 0xf7, 0x16, 0x2f, 0xff, 0x0f, 0x30, 0xdd, 0xb9, 0xe6, 0xe7,
+ 0xd9, 0x62, 0xff, 0x7b, 0xf1, 0xee, 0x7d, 0x96, 0x2e, 0x94, 0xeb, 0x17,
+ 0x3c, 0x96, 0x2f, 0xdb, 0x72, 0x66, 0x9d, 0x62, 0xb6, 0xa2, 0x42, 0x46,
+ 0x87, 0x19, 0xe0, 0xbd, 0xff, 0xfb, 0xe5, 0x9d, 0xc8, 0xb0, 0xd6, 0xff,
+ 0xf3, 0x75, 0x62, 0xdc, 0x58, 0xb9, 0xcd, 0x58, 0xbf, 0x4b, 0xf0, 0x53,
+ 0xa4, 0x5d, 0x12, 0x58, 0xae, 0xcf, 0x03, 0xe5, 0x34, 0xe7, 0xf7, 0xe5,
+ 0x8b, 0xff, 0x67, 0x72, 0x6c, 0x22, 0xc1, 0xac, 0x5f, 0x1c, 0x5d, 0xf9,
+ 0x62, 0xf7, 0xe3, 0x7a, 0xc5, 0xd0, 0x05, 0x8a, 0xc3, 0x6c, 0x18, 0xfd,
+ 0x4e, 0x7f, 0x9c, 0x5b, 0xa8, 0x56, 0x2d, 0x38, 0xc7, 0x70, 0xdc, 0x63,
+ 0xfd, 0x2c, 0x94, 0x23, 0x78, 0x43, 0xe8, 0x5c, 0xdf, 0xee, 0xbe, 0xc3,
+ 0x87, 0xd2, 0xc5, 0xe6, 0xe3, 0x2c, 0x59, 0x96, 0x2f, 0x9c, 0x37, 0x1a,
+ 0xc5, 0xe8, 0xd1, 0xab, 0x16, 0x97, 0xcf, 0xb9, 0xc7, 0x04, 0x22, 0x61,
+ 0x1d, 0xff, 0xfe, 0x1f, 0xf3, 0xde, 0x72, 0xeb, 0x91, 0xa7, 0x99, 0xbe,
+ 0xb1, 0x43, 0x4d, 0x1b, 0xb8, 0x51, 0x32, 0x15, 0xf8, 0xd0, 0xe3, 0x40,
+ 0x58, 0xbf, 0xe2, 0x83, 0x38, 0xc5, 0xdc, 0x96, 0x2f, 0xff, 0xfd, 0xc0,
+ 0x36, 0x87, 0x85, 0xf6, 0xeb, 0xed, 0xe3, 0x60, 0xa4, 0xb1, 0x74, 0x74,
+ 0xb1, 0x5a, 0x47, 0x51, 0x15, 0xf8, 0xeb, 0x7b, 0x6d, 0xff, 0x11, 0xbc,
+ 0x6d, 0xf0, 0x5e, 0x58, 0xbf, 0xfb, 0xef, 0x36, 0x0f, 0xed, 0xbf, 0x26,
+ 0x58, 0xa8, 0x44, 0x1b, 0x1d, 0xde, 0x0e, 0x37, 0x56, 0x2e, 0xfb, 0x2c,
+ 0x58, 0x0b, 0x14, 0x69, 0xa9, 0x21, 0x7a, 0x9c, 0xfa, 0xd9, 0x2a, 0xff,
+ 0xbd, 0xf6, 0x80, 0x4f, 0xc3, 0x56, 0x2f, 0xc5, 0x06, 0x61, 0x2c, 0x5f,
+ 0xf7, 0xfb, 0x83, 0x66, 0x94, 0x6e, 0xac, 0x5b, 0x83, 0x3e, 0x7c, 0x27,
+ 0xad, 0x23, 0xb0, 0x88, 0xbd, 0x0a, 0x3a, 0x58, 0xbf, 0x83, 0xf7, 0x1b,
+ 0x0d, 0x58, 0xbf, 0x4b, 0x4d, 0x07, 0x58, 0xbc, 0x1f, 0x66, 0x2c, 0x54,
+ 0xe8, 0x85, 0x18, 0x67, 0x66, 0x1c, 0x28, 0xa8, 0x5e, 0x18, 0xc8, 0xf1,
+ 0xda, 0x32, 0x0f, 0xc3, 0x05, 0xe3, 0x78, 0x14, 0x2e, 0x6f, 0x30, 0x21,
+ 0x62, 0xfa, 0x59, 0xe6, 0x58, 0xbe, 0xcd, 0x31, 0xd6, 0x2b, 0x69, 0xf0,
+ 0x76, 0x39, 0xc2, 0x2b, 0xff, 0xd2, 0xf0, 0xbf, 0xa8, 0x32, 0x4c, 0x0c,
+ 0x58, 0xb9, 0xce, 0xb1, 0x5d, 0x22, 0x54, 0x8c, 0xb7, 0xa6, 0x5f, 0xff,
+ 0xbc, 0xfa, 0xc6, 0x07, 0x33, 0xed, 0xaf, 0xba, 0xc5, 0xff, 0x7d, 0xb5,
+ 0x31, 0x44, 0x76, 0xb1, 0x7b, 0x4f, 0xc5, 0x8b, 0xd0, 0x43, 0x58, 0xbf,
+ 0x77, 0xc9, 0xb3, 0xcb, 0x15, 0x89, 0x92, 0x76, 0x64, 0xca, 0x87, 0x3a,
+ 0xf8, 0xe9, 0x0e, 0x5f, 0xcd, 0xe2, 0x70, 0x71, 0x62, 0xfd, 0x07, 0xf6,
+ 0x7d, 0x62, 0xec, 0xe9, 0x62, 0xf8, 0x02, 0x83, 0xac, 0x56, 0x1b, 0xb6,
+ 0x18, 0xbf, 0x08, 0xcf, 0xc6, 0xf5, 0x8b, 0xd0, 0x53, 0x2c, 0x54, 0xc7,
+ 0xd1, 0xf1, 0xf0, 0xcb, 0x2f, 0xb8, 0xd1, 0xd2, 0xc5, 0xf6, 0x77, 0xe6,
+ 0x58, 0xbf, 0xfa, 0x6c, 0xd6, 0x39, 0xe3, 0xec, 0x35, 0x8a, 0xc4, 0x45,
+ 0x7c, 0x8f, 0xc4, 0x76, 0xc5, 0x8b, 0xf1, 0xf3, 0xfd, 0xba, 0xc5, 0x4c,
+ 0x6e, 0x84, 0x23, 0x7d, 0x9a, 0x71, 0xac, 0x51, 0xaa, 0x98, 0x3a, 0x2d,
+ 0xfc, 0x32, 0xca, 0x17, 0x7c, 0x69, 0xde, 0x45, 0x7f, 0xf9, 0x86, 0x4f,
+ 0xd9, 0x67, 0xb1, 0x80, 0xb1, 0x7d, 0x3c, 0xef, 0xba, 0xb1, 0x7d, 0xd0,
+ 0xc5, 0x3a, 0xc5, 0xe9, 0x70, 0x4b, 0x17, 0x3c, 0x96, 0x2f, 0xde, 0x6f,
+ 0xc8, 0x96, 0x28, 0xe6, 0xfc, 0x85, 0xef, 0xff, 0xff, 0xdf, 0x8c, 0x9e,
+ 0x4d, 0xee, 0x46, 0xb3, 0x65, 0x81, 0x11, 0xbe, 0x20, 0xba, 0x58, 0xb7,
+ 0xb1, 0x32, 0x9f, 0x93, 0x3a, 0xef, 0x08, 0x2f, 0x18, 0x61, 0x8b, 0x17,
+ 0xff, 0xc7, 0xce, 0xfc, 0x59, 0x39, 0xf0, 0xf8, 0x49, 0x1b, 0x26, 0x86,
+ 0xe3, 0x00, 0xb1, 0x7d, 0xdf, 0x22, 0x4b, 0x15, 0x09, 0x81, 0xb3, 0x1b,
+ 0xb1, 0x80, 0x66, 0xfa, 0x7c, 0xfb, 0xac, 0x5e, 0x9e, 0x47, 0x58, 0xbf,
+ 0xf3, 0x70, 0x07, 0x17, 0x39, 0x00, 0x58, 0xbf, 0xda, 0x27, 0x33, 0x3e,
+ 0xeb, 0x17, 0xcf, 0xaf, 0xe2, 0xc5, 0xff, 0x13, 0xcf, 0xcc, 0xfb, 0xee,
+ 0xac, 0x5f, 0x7a, 0x3d, 0xcc, 0x3d, 0xe7, 0x22, 0xbf, 0x7d, 0xf5, 0x9a,
+ 0x58, 0xbf, 0xef, 0x30, 0x22, 0x59, 0xdf, 0x96, 0x2f, 0xf9, 0xbb, 0x2c,
+ 0xf7, 0xd8, 0xc5, 0x8a, 0x83, 0xf4, 0xd1, 0xd5, 0xff, 0xd3, 0x90, 0xa7,
+ 0x17, 0x3d, 0xcc, 0x31, 0x62, 0xfd, 0xdf, 0x4c, 0x53, 0xac, 0x5f, 0xef,
+ 0xc4, 0xa6, 0x93, 0x92, 0xc5, 0x78, 0xf7, 0xc3, 0x2b, 0xa8, 0x46, 0x5b,
+ 0xc2, 0xa2, 0xe1, 0x3a, 0xc5, 0x6d, 0x55, 0xd9, 0x21, 0xf1, 0xa0, 0x64,
+ 0x24, 0x7a, 0x37, 0xd4, 0x27, 0x3f, 0x0e, 0xc2, 0x26, 0xbf, 0xe0, 0x16,
+ 0x74, 0xd9, 0xee, 0x2c, 0x5e, 0xf4, 0x0d, 0x62, 0xfa, 0x5e, 0x10, 0xd6,
+ 0x2f, 0xd0, 0xd2, 0x7e, 0x2c, 0x54, 0x1f, 0x47, 0x63, 0xba, 0x24, 0xbf,
+ 0xb3, 0xdf, 0x14, 0x76, 0xb1, 0x7d, 0xe6, 0xd6, 0x2c, 0x5f, 0x77, 0xc6,
+ 0x34, 0x67, 0xa3, 0x85, 0xf5, 0x3a, 0x7b, 0xda, 0x84, 0x19, 0x42, 0x87,
+ 0xd0, 0x80, 0xbf, 0xb8, 0x59, 0xbf, 0xec, 0xb1, 0x7b, 0xac, 0xe2, 0xc5,
+ 0x61, 0xe6, 0x88, 0xbe, 0xff, 0xc7, 0x8e, 0xcb, 0x01, 0xc8, 0xdd, 0x58,
+ 0xad, 0x1f, 0x19, 0xc8, 0x6f, 0xf0, 0xcb, 0x37, 0xb6, 0x9d, 0x62, 0xb6,
+ 0x25, 0xe4, 0x08, 0x9c, 0xed, 0x68, 0x7e, 0x88, 0x8a, 0xfb, 0x75, 0xb3,
+ 0xb5, 0x8b, 0x9f, 0xa5, 0x8a, 0x9c, 0xdf, 0x39, 0x35, 0xf9, 0xb9, 0x13,
+ 0x9d, 0x76, 0x7e, 0x97, 0xe8, 0x7d, 0x00, 0x4b, 0xb3, 0xf4, 0xb9, 0xe4,
+ 0xbb, 0x3f, 0x4b, 0xe1, 0x4b, 0x38, 0xbb, 0x3f, 0x4a, 0x19, 0xea, 0x11,
+ 0x25, 0xfa, 0x33, 0x98, 0x4b, 0xb3, 0xf4, 0xa5, 0xd9, 0xfa, 0x5c, 0xfe,
+ 0x5d, 0x9f, 0xa1, 0xcb, 0x9b, 0x48, 0x8f, 0xfc, 0x49, 0x97, 0xd9, 0xb8,
+ 0xc0, 0x5d, 0x9f, 0xa5, 0x2e, 0xcf, 0xd2, 0xe0, 0x42, 0xec, 0xfd, 0x2f,
+ 0xfb, 0x00, 0xfa, 0xcd, 0xf8, 0x35, 0xd9, 0xfa, 0x5f, 0xd9, 0xf6, 0xe0,
+ 0xa7, 0x5d, 0x9f, 0xa5, 0x01, 0x14, 0xe4, 0x49, 0xc4, 0x7b, 0xed, 0x4f,
+ 0x1e, 0x5d, 0x9f, 0xa5, 0x2e, 0xcf, 0xd3, 0x0d, 0x8d, 0xc6, 0x18, 0xbb,
+ 0x3f, 0x4a, 0x92, 0xb2, 0x71, 0x9b, 0x64, 0x22, 0x7b, 0x85, 0x06, 0x89,
+ 0xce, 0x65, 0xc8, 0x60, 0x79, 0x80, 0xc2, 0x8b, 0xa0, 0xd4, 0xd9, 0xfa,
+ 0x36, 0x51, 0x21, 0x7f, 0xd3, 0xc6, 0xfc, 0x6d, 0x64, 0xeb, 0x17, 0xff,
+ 0x3f, 0xfa, 0xfb, 0x13, 0xe9, 0xe4, 0xb1, 0x52, 0x45, 0xde, 0x8e, 0xfc,
+ 0x79, 0x7f, 0x46, 0x07, 0x12, 0x92, 0xc5, 0xfe, 0xe6, 0x4a, 0x51, 0xee,
+ 0xd6, 0x2f, 0xfa, 0x34, 0x0f, 0x33, 0x9b, 0x25, 0x8a, 0xc4, 0x66, 0x91,
+ 0x87, 0x0b, 0x83, 0x35, 0xbf, 0xf6, 0x74, 0x3c, 0xd1, 0x8f, 0xf9, 0x96,
+ 0x2e, 0x80, 0xd6, 0x29, 0x62, 0xff, 0xc5, 0x93, 0x44, 0xe0, 0x7e, 0xf8,
+ 0xb1, 0x50, 0x79, 0xbc, 0x0c, 0xa4, 0x8b, 0xf3, 0x4c, 0xef, 0x25, 0x8b,
+ 0x4a, 0x73, 0x69, 0x81, 0x97, 0xd3, 0x3b, 0xe9, 0x62, 0xa7, 0x4e, 0x0b,
+ 0xb3, 0xcd, 0x21, 0x7d, 0x94, 0x95, 0x42, 0x13, 0xdc, 0xd3, 0xac, 0x5f,
+ 0xd1, 0xf2, 0x76, 0xd2, 0xc5, 0x69, 0x7e, 0x05, 0xe7, 0xb8, 0xbc, 0xb7,
+ 0xbc, 0x62, 0xf8, 0xfb, 0x0a, 0x53, 0x2c, 0x5d, 0xb8, 0x6a, 0xc5, 0xfd,
+ 0xc2, 0x8f, 0x8b, 0x4b, 0x17, 0xf7, 0x0b, 0x3d, 0x80, 0x58, 0xae, 0xcf,
+ 0x6c, 0xe5, 0xd7, 0xfd, 0x31, 0x66, 0xff, 0xf6, 0xfb, 0xab, 0x17, 0xf7,
+ 0xb3, 0xf1, 0xa0, 0x2c, 0x5f, 0x69, 0xb3, 0x7a, 0xc5, 0xfb, 0x39, 0x9d,
+ 0xf9, 0x62, 0xf8, 0xf0, 0x46, 0xed, 0x3c, 0xd7, 0x24, 0xbf, 0xed, 0x31,
+ 0xf8, 0x1c, 0x64, 0xcb, 0x17, 0xfd, 0xd4, 0x00, 0x62, 0x7d, 0x49, 0x62,
+ 0xff, 0xce, 0xf3, 0xe1, 0xdc, 0xbb, 0x92, 0xc5, 0xe7, 0x37, 0x98, 0x7f,
+ 0x53, 0x1d, 0xdf, 0xef, 0x7f, 0x0e, 0x1c, 0x01, 0x62, 0xfc, 0x14, 0x37,
+ 0x4f, 0xd2, 0xc5, 0xf7, 0x23, 0x3c, 0xb1, 0x7f, 0xe7, 0x6f, 0x48, 0x50,
+ 0x51, 0x25, 0x8b, 0x7f, 0x6a, 0x30, 0xc2, 0xc3, 0x5c, 0x2f, 0xf9, 0x15,
+ 0xff, 0xe8, 0xe6, 0x1e, 0x3a, 0x7c, 0x1b, 0x6f, 0x58, 0xac, 0x44, 0xa1,
+ 0x24, 0xdf, 0xb3, 0xf9, 0xdf, 0x96, 0x2c, 0x66, 0xd5, 0x67, 0xf8, 0xf7,
+ 0xa3, 0xa2, 0x85, 0xaf, 0xa3, 0x8b, 0xdc, 0x21, 0xad, 0xab, 0x90, 0xf0,
+ 0xef, 0x84, 0x6f, 0x2d, 0xfe, 0xf9, 0x8d, 0x63, 0x16, 0x2f, 0xbd, 0xfc,
+ 0x9d, 0x62, 0x8e, 0x79, 0x04, 0x49, 0x70, 0xcc, 0x58, 0xa5, 0x8b, 0xe7,
+ 0x72, 0xe9, 0x62, 0xe1, 0x87, 0x39, 0xae, 0xde, 0x19, 0x50, 0x89, 0x9c,
+ 0x21, 0x64, 0x7b, 0xc7, 0x06, 0x96, 0x2e, 0xf1, 0x2c, 0x5f, 0x86, 0xf2,
+ 0xfe, 0x2c, 0x5e, 0x20, 0x74, 0xb1, 0x43, 0x3d, 0xdc, 0x17, 0xe1, 0x45,
+ 0xff, 0xee, 0xfd, 0xf6, 0x0c, 0x79, 0x85, 0xc6, 0x58, 0xbf, 0xff, 0x4b,
+ 0x51, 0xbd, 0xe6, 0x81, 0xfe, 0x0e, 0xf3, 0x2c, 0x5f, 0xe0, 0x8f, 0xc6,
+ 0xe4, 0xd8, 0xb1, 0x7f, 0xfa, 0x34, 0x0c, 0xde, 0xde, 0x8c, 0x29, 0x2c,
+ 0x56, 0xd4, 0xf3, 0x76, 0x5e, 0xf0, 0xbb, 0xb4, 0xbd, 0x2c, 0x86, 0x6d,
+ 0x6f, 0x2c, 0x5f, 0xb3, 0x9c, 0x3f, 0x6b, 0x16, 0xef, 0x69, 0xbc, 0x81,
+ 0x2b, 0xd0, 0x38, 0x58, 0xa8, 0x3c, 0x53, 0x94, 0xde, 0x62, 0x92, 0xc5,
+ 0x43, 0xa9, 0xd2, 0x9d, 0xf6, 0x54, 0x95, 0x0c, 0x95, 0x16, 0xd2, 0xad,
+ 0xb7, 0x59, 0xa6, 0x48, 0xd4, 0xa5, 0x4f, 0xcf, 0x3d, 0xbd, 0x20, 0x3c,
+ 0x09, 0x25, 0x39, 0x65, 0xc8, 0xc9, 0xc5, 0x1f, 0xd1, 0x90, 0xdf, 0x08,
+ 0x43, 0x7e, 0xf9, 0xe3, 0x60, 0xc5, 0x8b, 0xa0, 0xeb, 0x17, 0xf4, 0x7b,
+ 0xf1, 0xbf, 0x16, 0x28, 0x67, 0x8d, 0xd0, 0xbd, 0xd3, 0xe2, 0xc5, 0xfd,
+ 0x9e, 0xf8, 0x9e, 0x4b, 0x16, 0xeb, 0x0f, 0xa4, 0x04, 0x64, 0x31, 0x4b,
+ 0x16, 0x7d, 0x1e, 0x01, 0xcd, 0x2f, 0xec, 0x3c, 0xce, 0xf2, 0x58, 0xbf,
+ 0xa0, 0xed, 0xd3, 0x0d, 0x62, 0xff, 0xfe, 0x7f, 0xc4, 0xb6, 0x70, 0x11,
+ 0x2e, 0x0f, 0xf1, 0xa5, 0x8b, 0x30, 0xd1, 0x75, 0xd1, 0x77, 0xcb, 0xaf,
+ 0xfc, 0x6c, 0x76, 0x51, 0xff, 0x8b, 0xa5, 0x8b, 0xff, 0x46, 0x16, 0x49,
+ 0xbf, 0x9b, 0xd6, 0x2f, 0xfe, 0x27, 0x07, 0x35, 0x9d, 0x7f, 0x3b, 0x58,
+ 0xad, 0x22, 0x13, 0xc7, 0xd7, 0xd9, 0xa6, 0x35, 0x62, 0xfd, 0xf6, 0xe4,
+ 0x49, 0x62, 0xff, 0xf3, 0x9b, 0xcc, 0xdf, 0x1d, 0xfb, 0x82, 0x3a, 0xc5,
+ 0x39, 0xfb, 0x91, 0x45, 0x0d, 0x1b, 0xa7, 0x23, 0x28, 0x4d, 0x5f, 0x41,
+ 0xf7, 0x61, 0x62, 0xff, 0x8d, 0x6d, 0x07, 0xa6, 0x81, 0xac, 0x5c, 0x41,
+ 0x75, 0x8b, 0xe8, 0xfb, 0x1b, 0x87, 0xad, 0xa3, 0xbb, 0xff, 0x61, 0xde,
+ 0x5b, 0x82, 0x1b, 0x7d, 0x62, 0xbe, 0x7f, 0x44, 0x71, 0x7e, 0xf7, 0x9e,
+ 0x5c, 0x58, 0xbf, 0xc5, 0x1e, 0xee, 0x67, 0x3a, 0xc5, 0xfb, 0xc2, 0xf6,
+ 0x0d, 0x62, 0xd8, 0xb1, 0x4e, 0x6e, 0xb7, 0x94, 0xdf, 0xe6, 0xe6, 0x14,
+ 0xe6, 0x4c, 0xb1, 0x7f, 0xb9, 0x9b, 0x7b, 0x96, 0x79, 0x62, 0xef, 0xe0,
+ 0xcf, 0xb7, 0x86, 0xd5, 0x24, 0xdd, 0x46, 0x42, 0x72, 0x92, 0x6f, 0xf4,
+ 0x23, 0xef, 0xda, 0x03, 0xe0, 0x16, 0x2f, 0xec, 0x08, 0xde, 0x69, 0x2c,
+ 0x5f, 0x7e, 0x27, 0xe6, 0x1e, 0xbf, 0xca, 0x2f, 0xe2, 0x73, 0x7e, 0xf2,
+ 0x58, 0xbe, 0x6e, 0x06, 0x75, 0x8b, 0xff, 0xdd, 0xfb, 0xaf, 0xb1, 0x67,
+ 0xb9, 0x07, 0x58, 0xbe, 0x8e, 0x9a, 0x4b, 0x17, 0xc7, 0x2c, 0xf6, 0x1f,
+ 0x79, 0x26, 0x5f, 0xff, 0xde, 0x8f, 0x96, 0x7b, 0xed, 0xb4, 0xf9, 0xe7,
+ 0xf2, 0xc5, 0x2c, 0x5f, 0xf1, 0x60, 0x3f, 0x0f, 0xac, 0x58, 0xa6, 0x44,
+ 0xfe, 0x97, 0x38, 0x19, 0x5d, 0x27, 0x2e, 0xd0, 0x93, 0x78, 0x6a, 0xdf,
+ 0xba, 0xc3, 0xc7, 0x16, 0x2f, 0x18, 0x61, 0x89, 0x17, 0x83, 0x80, 0x24,
+ 0x6c, 0x9a, 0x1b, 0xfe, 0x79, 0x07, 0xac, 0xde, 0xfa, 0x58, 0xb6, 0x96,
+ 0x2f, 0xf1, 0x44, 0x8d, 0xd6, 0x71, 0x62, 0xff, 0xc4, 0x59, 0x3c, 0xd2,
+ 0x8d, 0x4e, 0xb1, 0x7b, 0xf9, 0x28, 0x44, 0x3e, 0x09, 0x06, 0x69, 0x44,
+ 0x98, 0x1f, 0xa1, 0x87, 0x7f, 0x98, 0x7c, 0x8f, 0xbe, 0x96, 0x2f, 0xf1,
+ 0x49, 0x8f, 0x9d, 0xf9, 0x62, 0xfb, 0xbe, 0x98, 0x96, 0x29, 0xcf, 0x63,
+ 0xc6, 0x94, 0xb1, 0x68, 0x91, 0xad, 0x0b, 0x90, 0xd7, 0x48, 0xe2, 0x04,
+ 0x2e, 0x2f, 0xdb, 0x63, 0xac, 0xd2, 0xc5, 0xfe, 0xcd, 0x63, 0xf5, 0xc9,
+ 0x2c, 0x5f, 0xff, 0xf3, 0x7b, 0xef, 0x2d, 0x9c, 0xfb, 0xf6, 0x0f, 0x14,
+ 0x1f, 0x8b, 0x17, 0xfe, 0xdb, 0x04, 0x23, 0xc1, 0x91, 0xc5, 0x8b, 0x60,
+ 0xd3, 0x0a, 0x39, 0x5f, 0xcd, 0x09, 0xaa, 0xff, 0xbc, 0xe5, 0x9c, 0xd4,
+ 0x71, 0x62, 0xfa, 0x50, 0x0e, 0xd6, 0x2f, 0x1c, 0x63, 0x58, 0xbf, 0xff,
+ 0xce, 0xde, 0x89, 0x36, 0xa7, 0x10, 0x37, 0x37, 0x30, 0x6c, 0xb1, 0x7f,
+ 0xff, 0xcf, 0xbd, 0xb7, 0x90, 0xb8, 0x19, 0x40, 0xfe, 0xf2, 0xce, 0x2c,
+ 0x5f, 0xc0, 0x82, 0xce, 0xfc, 0xb1, 0x73, 0x83, 0x6a, 0x68, 0x38, 0x49,
+ 0xf1, 0xe2, 0x67, 0x0d, 0xaa, 0xff, 0xf0, 0x65, 0x31, 0xae, 0x3f, 0xe7,
+ 0x59, 0xa5, 0x8a, 0x65, 0x72, 0x7f, 0x8c, 0xcd, 0xd0, 0x8a, 0x37, 0x9e,
+ 0x2b, 0xde, 0xf4, 0x99, 0x62, 0xff, 0xbe, 0x51, 0x2f, 0xb9, 0x32, 0xc5,
+ 0xd1, 0xa5, 0x8a, 0x63, 0xce, 0xde, 0x6f, 0x7f, 0xef, 0xe4, 0xfd, 0xf3,
+ 0x3a, 0x70, 0xd6, 0x2e, 0xcf, 0xac, 0x53, 0x1e, 0xd0, 0x90, 0xea, 0x76,
+ 0x7d, 0x7c, 0xa1, 0xc2, 0x33, 0x6c, 0x8e, 0x8f, 0xb3, 0x46, 0x94, 0xd5,
+ 0x34, 0x29, 0x8e, 0x73, 0xf8, 0xf1, 0x5c, 0xe8, 0x09, 0x45, 0x19, 0xa7,
+ 0xa7, 0x27, 0x44, 0xab, 0xbd, 0xac, 0xc7, 0xdb, 0x9a, 0x75, 0x8b, 0xfc,
+ 0x5d, 0x0d, 0xb7, 0xc0, 0xd6, 0x28, 0x67, 0x9c, 0x21, 0x8b, 0xfd, 0xc6,
+ 0x3b, 0xe9, 0xf8, 0xb1, 0x7e, 0xf7, 0xb0, 0xa7, 0x58, 0xbf, 0xfc, 0xda,
+ 0xfc, 0x37, 0xb8, 0xc5, 0xdc, 0x96, 0x2f, 0xfc, 0xc6, 0x6b, 0x0e, 0x77,
+ 0x2f, 0x2c, 0x54, 0x22, 0xcb, 0x0a, 0x49, 0x2a, 0xfe, 0xce, 0xbd, 0xb9,
+ 0x9f, 0x58, 0xa5, 0x8a, 0xf9, 0xbe, 0x01, 0x95, 0xff, 0xd3, 0x7e, 0x27,
+ 0x0f, 0xdf, 0x13, 0xc9, 0x62, 0xfe, 0x2f, 0xc7, 0x58, 0x75, 0x8b, 0xf1,
+ 0xa2, 0x93, 0x8d, 0x62, 0xff, 0x46, 0xee, 0xdf, 0xbe, 0x69, 0x62, 0xff,
+ 0xef, 0x14, 0x79, 0xb0, 0xb6, 0xc6, 0xf5, 0x8b, 0x9b, 0xa5, 0x8b, 0xd9,
+ 0xa8, 0x58, 0xbe, 0xff, 0xf3, 0xb5, 0x8b, 0xb0, 0xfb, 0x87, 0x80, 0x18,
+ 0xe5, 0x62, 0x60, 0xec, 0x71, 0xf4, 0x62, 0x58, 0xb6, 0xea, 0xc5, 0xa6,
+ 0x58, 0xb1, 0xd6, 0x29, 0x8d, 0x2b, 0x89, 0xd1, 0xa7, 0xb2, 0x73, 0xab,
+ 0xf6, 0x03, 0x91, 0x25, 0x8b, 0xf3, 0x1c, 0x63, 0xc5, 0x8b, 0x00, 0x8f,
+ 0x43, 0x70, 0xa2, 0xff, 0xbd, 0xfc, 0xe6, 0xdf, 0x34, 0xeb, 0x17, 0xf6,
+ 0x4d, 0x9a, 0x1b, 0x2c, 0x54, 0x22, 0x55, 0x8a, 0x88, 0xf6, 0xff, 0x89,
+ 0x84, 0x17, 0xe6, 0xe4, 0x79, 0x62, 0xff, 0xa3, 0x0c, 0xee, 0x5e, 0x83,
+ 0x16, 0x2f, 0xf0, 0x34, 0xd9, 0xf1, 0x71, 0x62, 0xf6, 0x76, 0x75, 0x8b,
+ 0xfb, 0x00, 0x13, 0xcc, 0x75, 0x8a, 0x84, 0x41, 0x11, 0xa7, 0x87, 0xaf,
+ 0xf4, 0x17, 0xbc, 0x6b, 0xe9, 0x62, 0xff, 0xe7, 0xf6, 0x84, 0x6e, 0x79,
+ 0x81, 0xc5, 0x8b, 0xcf, 0xa0, 0x2c, 0x5e, 0xc6, 0x1a, 0xc5, 0x42, 0xf6,
+ 0x0c, 0xf0, 0xe5, 0x93, 0x58, 0xc8, 0x71, 0x25, 0x8b, 0xa6, 0x8c, 0xc4,
+ 0xf0, 0x94, 0xfc, 0x61, 0x04, 0x5b, 0xc4, 0x0f, 0x42, 0xfb, 0x79, 0x71,
+ 0x86, 0x9b, 0x88, 0xc1, 0x07, 0x6f, 0xbf, 0x9d, 0xc9, 0x62, 0xfb, 0x3c,
+ 0x1c, 0xeb, 0x17, 0xe2, 0x86, 0xee, 0x4b, 0x17, 0x8c, 0x30, 0xc4, 0xc4,
+ 0x20, 0x2f, 0xba, 0x77, 0xe9, 0x31, 0x08, 0x0d, 0x93, 0x5f, 0x7c, 0xfa,
+ 0xc3, 0x16, 0x2b, 0x47, 0xd1, 0xbd, 0x16, 0xf1, 0x86, 0x18, 0x98, 0x83,
+ 0xc5, 0x26, 0x20, 0xf1, 0xb2, 0x6b, 0xef, 0xef, 0x39, 0xcf, 0x07, 0x58,
+ 0xbf, 0x3f, 0x9c, 0x80, 0xb1, 0x7f, 0x67, 0xbe, 0x27, 0x92, 0xc5, 0xe3,
+ 0x0c, 0x31, 0x62, 0xf7, 0x20, 0xd4, 0x8d, 0x93, 0x43, 0x50, 0xa8, 0x53,
+ 0x21, 0x7f, 0xd2, 0x9f, 0x65, 0xbf, 0x2e, 0x22, 0x7f, 0x27, 0xd6, 0xea,
+ 0xaa, 0x33, 0xca, 0x39, 0xbf, 0xdf, 0x8d, 0xf0, 0x51, 0xe5, 0x8b, 0xfb,
+ 0x3b, 0x94, 0xa0, 0xeb, 0x17, 0xff, 0xb9, 0xf7, 0x96, 0x7d, 0x8f, 0xc8,
+ 0xdd, 0x58, 0xbc, 0x64, 0x12, 0xc5, 0xff, 0xff, 0xd0, 0x53, 0xf3, 0xee,
+ 0x73, 0xbc, 0x83, 0x2d, 0xf8, 0x3c, 0xef, 0xcb, 0x17, 0xff, 0x7e, 0x24,
+ 0xde, 0xcf, 0xf5, 0x07, 0x58, 0xa8, 0x4e, 0xde, 0x45, 0xe3, 0x34, 0xc2,
+ 0xf7, 0x4d, 0xe0, 0xee, 0xf7, 0x6b, 0xf7, 0x51, 0xf8, 0x3a, 0xc5, 0xff,
+ 0xbe, 0xd3, 0x13, 0x99, 0xec, 0xfa, 0xc5, 0xd1, 0xc5, 0x8a, 0xc4, 0x40,
+ 0x74, 0x53, 0xe4, 0x0b, 0xff, 0x7d, 0x87, 0x05, 0xec, 0xef, 0xcb, 0x17,
+ 0xb8, 0x22, 0x58, 0xbe, 0x91, 0x40, 0xd6, 0x2f, 0x14, 0x1f, 0x86, 0xfc,
+ 0x31, 0xda, 0xe9, 0x16, 0x1c, 0x7e, 0xbf, 0xfb, 0xed, 0xaf, 0xbe, 0x71,
+ 0x9e, 0x75, 0x8b, 0xfc, 0x63, 0xfb, 0x0e, 0xfd, 0xac, 0x5f, 0xfa, 0x3d,
+ 0x9a, 0xce, 0x67, 0x7e, 0x58, 0xac, 0x45, 0xc7, 0xd1, 0x08, 0xd6, 0xff,
+ 0x8f, 0x87, 0xc2, 0xf6, 0x74, 0xb1, 0x7f, 0x8d, 0xce, 0xa3, 0xf0, 0x75,
+ 0x8a, 0x9c, 0xfb, 0x9c, 0xe6, 0xfa, 0x3d, 0x07, 0x58, 0xbf, 0xd8, 0x4c,
+ 0x6e, 0xde, 0xbe, 0xb1, 0x5b, 0x12, 0xad, 0x3e, 0xe1, 0xc0, 0x78, 0x6e,
+ 0x14, 0x27, 0x3c, 0x44, 0x61, 0x15, 0xef, 0xc0, 0x45, 0x8b, 0xfd, 0x05,
+ 0xd7, 0x7c, 0x7d, 0xd5, 0x8a, 0x19, 0xeb, 0xfc, 0x7e, 0xf0, 0x48, 0x9d,
+ 0x62, 0xf8, 0x85, 0x39, 0x2c, 0x5e, 0x6e, 0xe4, 0xb1, 0x52, 0x3c, 0x10,
+ 0x11, 0xdf, 0xc3, 0xe6, 0x1e, 0x37, 0x56, 0x2f, 0xfe, 0xe0, 0x8b, 0x59,
+ 0x1d, 0xca, 0x09, 0x62, 0xfb, 0x06, 0xf2, 0x58, 0xbc, 0x27, 0x0d, 0x62,
+ 0xff, 0x67, 0xdf, 0x9f, 0x8e, 0x2c, 0x5d, 0x3f, 0x6b, 0x14, 0x33, 0xeb,
+ 0xec, 0x78, 0x06, 0x75, 0xb5, 0x17, 0xaf, 0x08, 0xda, 0x92, 0xa0, 0x01,
+ 0x91, 0x76, 0xc2, 0xe4, 0x5c, 0x31, 0x32, 0x30, 0x1b, 0xfd, 0xcf, 0xe7,
+ 0x3d, 0x9d, 0x2c, 0x5f, 0x8b, 0xdf, 0xc9, 0x2c, 0x5e, 0x68, 0x35, 0x62,
+ 0x98, 0xfe, 0x9c, 0xd4, 0x8a, 0x2f, 0xfb, 0x0a, 0x3f, 0xf8, 0x31, 0x96,
+ 0x2f, 0xba, 0xfb, 0x18, 0xb1, 0x70, 0x4d, 0x2c, 0x5e, 0x0e, 0x00, 0xb1,
+ 0x7f, 0xdd, 0x19, 0x9d, 0xfb, 0xd0, 0x75, 0x8b, 0xff, 0xff, 0xfe, 0xda,
+ 0x58, 0x6b, 0x7f, 0xf9, 0xbb, 0xb6, 0x3a, 0x70, 0xf6, 0xe1, 0x4e, 0xda,
+ 0x61, 0x05, 0xf1, 0x62, 0xa7, 0x4e, 0x80, 0xd2, 0xce, 0xce, 0x26, 0x25,
+ 0x38, 0xd1, 0x0f, 0x18, 0x7b, 0x7f, 0xff, 0xa3, 0x6f, 0xb7, 0x33, 0x6e,
+ 0x7d, 0xcb, 0x26, 0x94, 0x76, 0xb1, 0x7e, 0xea, 0x3f, 0x07, 0x48, 0xbf,
+ 0x13, 0x91, 0x62, 0x45, 0xd9, 0xd2, 0x45, 0xc6, 0x18, 0x91, 0x58, 0x88,
+ 0x0e, 0x14, 0xf8, 0x94, 0xc1, 0x8b, 0xf4, 0x03, 0xf8, 0x11, 0x23, 0x64,
+ 0xde, 0xd8, 0x86, 0x9b, 0x10, 0x71, 0x92, 0xdf, 0xfc, 0x3d, 0x3f, 0x45,
+ 0x9b, 0xf4, 0xdc, 0x58, 0xbd, 0x3b, 0x69, 0x62, 0xa7, 0x3e, 0x5f, 0xa3,
+ 0xd4, 0x2f, 0xe1, 0x64, 0xac, 0x56, 0x94, 0xf4, 0xf1, 0xe5, 0x8a, 0x12,
+ 0xb7, 0x07, 0xa5, 0x8b, 0x9f, 0xeb, 0x14, 0xe6, 0xc3, 0xc3, 0x37, 0xff,
+ 0x7e, 0x01, 0xef, 0xe4, 0xbe, 0xdb, 0xd6, 0x2f, 0xfe, 0x80, 0x73, 0x30,
+ 0x6e, 0x4e, 0x6a, 0xc5, 0xff, 0x7b, 0x8f, 0xdb, 0x47, 0x7e, 0x58, 0xbf,
+ 0xe2, 0x07, 0xdf, 0xde, 0x60, 0x2c, 0x5f, 0xff, 0xbe, 0xdb, 0xd8, 0x87,
+ 0xc8, 0xd3, 0x67, 0x7c, 0x58, 0xbf, 0xd9, 0xbe, 0x0b, 0xd2, 0x0b, 0xac,
+ 0x5f, 0xee, 0x9b, 0x98, 0x39, 0x05, 0xd6, 0x2f, 0x0c, 0x5c, 0x58, 0xbf,
+ 0xd9, 0x85, 0x12, 0x90, 0x5d, 0x62, 0xfe, 0x28, 0xcd, 0x38, 0x16, 0x2f,
+ 0xfd, 0x1a, 0xfc, 0x37, 0xe0, 0x99, 0x62, 0xe9, 0x73, 0x13, 0xbe, 0xe8,
+ 0xe7, 0x4a, 0xff, 0x39, 0x73, 0x92, 0x1e, 0xf1, 0xb1, 0x85, 0x97, 0xf1,
+ 0x61, 0xdb, 0xb9, 0x2c, 0x5f, 0xfe, 0x76, 0xf4, 0x17, 0x4c, 0x7e, 0x0f,
+ 0xb5, 0x8a, 0x83, 0xf9, 0xf9, 0x75, 0xfe, 0xfc, 0x64, 0xa3, 0x00, 0xb1,
+ 0x7f, 0xf8, 0xb3, 0xb0, 0x3f, 0x1f, 0x4d, 0xd8, 0x16, 0x28, 0x67, 0xfb,
+ 0xc3, 0x2a, 0x92, 0xba, 0xfe, 0xe3, 0xf9, 0xf4, 0x3d, 0x8c, 0x84, 0xf5,
+ 0xf4, 0x75, 0x87, 0x58, 0xbe, 0x38, 0x8a, 0x4b, 0x17, 0xcf, 0x34, 0x04,
+ 0x58, 0xba, 0x0e, 0xb1, 0x7b, 0xef, 0x29, 0xcf, 0x7f, 0xe4, 0x64, 0x4b,
+ 0x43, 0x46, 0x17, 0xa1, 0x05, 0x7e, 0xf9, 0xe3, 0x3c, 0xb1, 0x70, 0xb8,
+ 0xb1, 0x6f, 0x61, 0xe0, 0x70, 0xa2, 0xa4, 0xbb, 0xb7, 0xf4, 0x77, 0x97,
+ 0xe4, 0x51, 0x89, 0xf1, 0xa2, 0xf6, 0xf0, 0xce, 0xb1, 0x7d, 0xf9, 0xf0,
+ 0xc5, 0x8b, 0xe1, 0x88, 0xa4, 0xb1, 0x6e, 0x39, 0xe4, 0x06, 0x4b, 0x7b,
+ 0x1c, 0x0b, 0x17, 0x9c, 0xfd, 0xac, 0x5b, 0xa1, 0x9b, 0xac, 0x1c, 0xb0,
+ 0x5b, 0xac, 0x5f, 0xfb, 0x39, 0xe9, 0x61, 0xa5, 0x80, 0x58, 0xbc, 0x3c,
+ 0x25, 0x8a, 0x0a, 0x9f, 0xa3, 0x8c, 0x84, 0x3f, 0xa6, 0x46, 0x78, 0xa1,
+ 0x37, 0x7c, 0xdf, 0x3b, 0xac, 0x5f, 0xf8, 0xc1, 0xea, 0x3e, 0xe3, 0x91,
+ 0xd6, 0x2f, 0xff, 0xff, 0xed, 0x02, 0x3d, 0xcd, 0xbe, 0x96, 0x03, 0x73,
+ 0x36, 0x8f, 0x07, 0x0f, 0xac, 0x20, 0x20, 0x82, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x9a, 0x0e, 0xe3, 0x9c, 0x5c, 0xdb, 0x83, 0x16, 0xa5, 0xf6, 0xdb,
+ 0x9a, 0x04, 0x7b, 0x9b, 0x7d, 0x2c, 0x06, 0xe6, 0x6d, 0x1e, 0x0e, 0x1f,
+ 0x58, 0x40, 0x41, 0x85, 0xff, 0xf7, 0x3b, 0xda, 0x3c, 0x1c, 0x3e, 0xb0,
+ 0x80, 0xb1, 0x5f, 0x4d, 0x47, 0xd0, 0xff, 0xbf, 0xff, 0xf6, 0xdf, 0x4b,
+ 0x01, 0xb9, 0x9b, 0x47, 0x83, 0x87, 0xd6, 0x10, 0x10, 0x82, 0xff, 0xec,
+ 0xf6, 0xde, 0xbe, 0xdf, 0xfb, 0x01, 0x50, 0x85, 0x95, 0x24, 0x65, 0xf1,
+ 0xda, 0xf4, 0x4f, 0xb3, 0x8a, 0xbf, 0x39, 0x1f, 0x2f, 0xa1, 0xe9, 0x73,
+ 0xf9, 0x62, 0xf1, 0x60, 0x45, 0x8b, 0xec, 0xe9, 0xfa, 0x58, 0xbf, 0x1f,
+ 0x86, 0x3f, 0x6b, 0x14, 0x34, 0x6a, 0x9d, 0x45, 0xc5, 0xfc, 0x3c, 0x19,
+ 0x25, 0x42, 0xe3, 0xf7, 0x64, 0x5c, 0x9c, 0x12, 0xbf, 0xb2, 0x69, 0x36,
+ 0xb8, 0xb1, 0x7e, 0x9e, 0x3c, 0xd3, 0x2c, 0x5f, 0x07, 0xc8, 0xc5, 0x8b,
+ 0xf0, 0x61, 0x20, 0xa4, 0xb1, 0x5d, 0x1f, 0xc7, 0x65, 0x40, 0x23, 0xbe,
+ 0xe6, 0xdd, 0x62, 0xc5, 0xf7, 0xfa, 0x6e, 0x2c, 0x54, 0x1f, 0xd3, 0x98,
+ 0xf8, 0x96, 0xff, 0xff, 0x83, 0x1f, 0xe2, 0x5e, 0xcc, 0x33, 0x85, 0x9e,
+ 0xf3, 0x4e, 0xb1, 0x73, 0xf6, 0xb1, 0x6c, 0x58, 0xb3, 0xce, 0x89, 0x27,
+ 0x69, 0xde, 0x31, 0x79, 0x8b, 0x16, 0x2f, 0xda, 0xd3, 0x82, 0x16, 0x2a,
+ 0x47, 0x86, 0xe3, 0x74, 0x15, 0x77, 0x3a, 0x91, 0x58, 0x65, 0x8e, 0x35,
+ 0x8c, 0x9e, 0xe3, 0xea, 0x1f, 0xad, 0x38, 0xfd, 0xaa, 0x5b, 0xcf, 0xe1,
+ 0x24, 0xf3, 0xbf, 0x60, 0x58, 0x0b, 0xb4, 0x94, 0x66, 0x3c, 0x9c, 0xa5,
+ 0xf1, 0xd8, 0xa3, 0x21, 0x32, 0x17, 0xe1, 0xbd, 0x5d, 0xb1, 0xec, 0x0b,
+ 0x17, 0xd8, 0x0d, 0x42, 0xc5, 0xe3, 0x0c, 0x31, 0x22, 0xf3, 0x90, 0xd2,
+ 0x36, 0x4d, 0x0d, 0xf6, 0x6b, 0x3c, 0xb1, 0x5f, 0x44, 0xa0, 0x10, 0xf8,
+ 0x5f, 0x7f, 0xf1, 0xae, 0x19, 0x43, 0x0f, 0x3b, 0xf2, 0xc5, 0xe1, 0x05,
+ 0xf1, 0x62, 0xf3, 0x3c, 0x96, 0x2f, 0xff, 0x67, 0xbc, 0xe4, 0x6b, 0xf8,
+ 0x9c, 0x0b, 0x15, 0x08, 0xcc, 0x64, 0x6f, 0x90, 0x90, 0xe5, 0xfe, 0x2c,
+ 0xff, 0x8a, 0x00, 0xb1, 0x7f, 0xfa, 0x4c, 0x59, 0xe8, 0x30, 0x7a, 0x79,
+ 0x2c, 0x5f, 0xff, 0xcd, 0x37, 0x38, 0x27, 0xd0, 0xa7, 0x83, 0x43, 0x2f,
+ 0x2c, 0x5f, 0xfc, 0x45, 0x93, 0xc7, 0x72, 0x94, 0x1d, 0x62, 0xb1, 0x1d,
+ 0xff, 0x4a, 0x0d, 0x82, 0xf1, 0x44, 0x96, 0x2f, 0xb5, 0xa6, 0x3a, 0xc5,
+ 0xb8, 0x33, 0x7e, 0xc3, 0x95, 0x24, 0x4a, 0xf9, 0xbe, 0xe9, 0xc6, 0xb1,
+ 0x7f, 0xfe, 0xf4, 0x64, 0xef, 0xee, 0xbe, 0xfa, 0x31, 0xfb, 0x58, 0xa3,
+ 0x9f, 0x97, 0x06, 0x6a, 0x75, 0x4d, 0xa5, 0x1d, 0xb7, 0xa1, 0x2b, 0x7e,
+ 0xd6, 0x75, 0x1f, 0x58, 0xbd, 0xb4, 0xdd, 0xc5, 0x8b, 0xde, 0x71, 0xac,
+ 0x56, 0x8f, 0x07, 0x84, 0x97, 0xf7, 0x5f, 0x82, 0xc9, 0x96, 0x2f, 0x49,
+ 0x82, 0x2c, 0x54, 0x1e, 0x74, 0xc5, 0xf7, 0xf8, 0xde, 0xfd, 0xa8, 0xce,
+ 0xd6, 0x2f, 0x80, 0xda, 0x35, 0x22, 0xff, 0x43, 0xeb, 0xe6, 0x38, 0xd6,
+ 0x2f, 0xb5, 0xa6, 0x9d, 0x62, 0xdd, 0x41, 0xfe, 0x0c, 0x91, 0xcd, 0x2f,
+ 0xda, 0xfe, 0x1c, 0x4b, 0x17, 0xec, 0xd6, 0x64, 0xcb, 0x14, 0xc7, 0xa2,
+ 0x19, 0x4d, 0xf9, 0xff, 0xb4, 0x70, 0xb1, 0x52, 0x5e, 0x60, 0x1c, 0x3f,
+ 0x32, 0x55, 0x39, 0xa7, 0xac, 0xd5, 0xa7, 0x07, 0x22, 0x28, 0x59, 0xf2,
+ 0x10, 0xbe, 0x22, 0xbf, 0x3e, 0xb5, 0x9d, 0xac, 0x5f, 0xfe, 0xf7, 0xd9,
+ 0xc1, 0x9a, 0x1c, 0x14, 0x96, 0x2f, 0xff, 0x77, 0xb7, 0xb0, 0x41, 0x74,
+ 0xf3, 0x93, 0xac, 0x54, 0x23, 0x07, 0x0a, 0x49, 0x26, 0xfd, 0x1c, 0x0c,
+ 0xa4, 0xb1, 0x7b, 0xa6, 0x92, 0xc5, 0xfe, 0x8f, 0x3e, 0xb5, 0x9d, 0xac,
+ 0x56, 0xd3, 0xd2, 0xf8, 0xf5, 0xff, 0xba, 0xcd, 0x63, 0x73, 0xf1, 0xbd,
+ 0x62, 0xff, 0xcf, 0xdb, 0x8d, 0xfb, 0xd3, 0x1a, 0xb1, 0x7e, 0x80, 0x93,
+ 0xe1, 0x8b, 0x17, 0xff, 0xff, 0x3b, 0x79, 0xbf, 0xd3, 0x6d, 0x93, 0x7d,
+ 0xcb, 0xd2, 0xcd, 0x62, 0xc5, 0xd9, 0xf5, 0x8b, 0xb0, 0x22, 0xc5, 0x4c,
+ 0x6c, 0x3e, 0x2f, 0x5f, 0x46, 0x23, 0xc2, 0x8a, 0xfc, 0xc0, 0x72, 0x02,
+ 0xc5, 0xfe, 0x8e, 0xf9, 0x1e, 0x81, 0xac, 0x50, 0x0f, 0x6c, 0x89, 0xef,
+ 0xd9, 0xcc, 0xef, 0xcb, 0x17, 0xff, 0xdf, 0xc6, 0xd4, 0xbe, 0xc2, 0xeb,
+ 0xf8, 0x05, 0x8b, 0xdc, 0x0f, 0x9b, 0x53, 0x1d, 0xc8, 0x41, 0x39, 0x0f,
+ 0x8a, 0x68, 0x6a, 0xc2, 0x7b, 0x24, 0x3a, 0x0f, 0xd0, 0x7d, 0x28, 0x36,
+ 0xee, 0x49, 0x62, 0xf9, 0xe7, 0x17, 0x16, 0x2f, 0xe9, 0x37, 0x98, 0xa4,
+ 0xb1, 0x7f, 0x71, 0x9a, 0x76, 0xfa, 0xc5, 0xb5, 0x07, 0xb7, 0x22, 0xdb,
+ 0xf4, 0xc5, 0x1e, 0xe2, 0xc5, 0xff, 0xff, 0xff, 0x47, 0x23, 0xd3, 0xe1,
+ 0x9a, 0xcf, 0xb8, 0x7c, 0xc3, 0x5c, 0x81, 0x05, 0x13, 0x7e, 0x16, 0x2f,
+ 0x84, 0xf9, 0x3a, 0xc5, 0xe3, 0xe4, 0xeb, 0x17, 0xa4, 0xdb, 0xc8, 0xf0,
+ 0x43, 0x23, 0xbf, 0x73, 0xef, 0xd4, 0x2c, 0x5f, 0x9e, 0x73, 0x1e, 0x4b,
+ 0x15, 0x09, 0xd7, 0x4e, 0x4e, 0x45, 0x3e, 0x86, 0xb1, 0x86, 0xa1, 0x94,
+ 0xdf, 0xdd, 0xf3, 0x0e, 0xdf, 0x58, 0xbf, 0xee, 0x7e, 0x1f, 0x5a, 0xce,
+ 0xd6, 0x2f, 0xff, 0xfc, 0x6f, 0x72, 0xf6, 0x17, 0xb9, 0xb7, 0x9c, 0xcd,
+ 0x61, 0x3c, 0x96, 0x2b, 0x11, 0x54, 0xc7, 0x57, 0xc0, 0xf6, 0x4e, 0xb1,
+ 0x63, 0xac, 0x54, 0x1b, 0x63, 0x92, 0x5f, 0xff, 0xe0, 0x09, 0xcb, 0xa3,
+ 0x23, 0x45, 0x9d, 0xcb, 0xd1, 0xda, 0xc5, 0xff, 0xdb, 0x23, 0x28, 0x17,
+ 0x58, 0x6b, 0x69, 0x62, 0xf6, 0x9f, 0x8b, 0x17, 0x61, 0x8b, 0x15, 0x07,
+ 0xfc, 0x34, 0x9e, 0x0e, 0xdf, 0x43, 0xeb, 0x8b, 0x17, 0xbd, 0xf8, 0x58,
+ 0xac, 0x3e, 0xdf, 0x97, 0x39, 0x15, 0xfb, 0xf0, 0x4f, 0xf5, 0x8b, 0xfa,
+ 0x7f, 0xbf, 0xb5, 0x0b, 0x17, 0xd9, 0xe8, 0xfa, 0xc5, 0xe9, 0x67, 0x16,
+ 0x2f, 0x47, 0x7c, 0x58, 0xbf, 0xc3, 0xfc, 0x4c, 0xef, 0xda, 0xc5, 0xe6,
+ 0xf7, 0x16, 0x2f, 0xb8, 0x22, 0x92, 0xc5, 0xf8, 0x9f, 0xd2, 0x85, 0x8a,
+ 0xe8, 0xf9, 0xfb, 0x1d, 0xe1, 0x1d, 0xef, 0x83, 0x7a, 0xc5, 0x4e, 0x99,
+ 0x40, 0xc7, 0x74, 0x3c, 0x50, 0x9c, 0x08, 0x63, 0x7b, 0xb7, 0xdd, 0x58,
+ 0xbf, 0xde, 0xfb, 0x9f, 0x59, 0x3a, 0xc5, 0x7c, 0xf5, 0x80, 0x43, 0x7b,
+ 0x71, 0x8d, 0x58, 0xbf, 0xbd, 0x1b, 0xc9, 0xfb, 0x58, 0xa8, 0x3d, 0x1e,
+ 0xc8, 0x6a, 0x4a, 0xc2, 0x86, 0x5b, 0xa2, 0x7f, 0x97, 0xbc, 0x69, 0x45,
+ 0x0a, 0x8f, 0x39, 0xdf, 0x84, 0x43, 0x79, 0xd6, 0x2f, 0xff, 0xbe, 0xce,
+ 0x0c, 0x28, 0xef, 0x99, 0xdf, 0x96, 0x2c, 0x69, 0xcf, 0xe7, 0xc5, 0x37,
+ 0xff, 0x66, 0x80, 0x76, 0xe0, 0x7c, 0x8c, 0x58, 0xbd, 0x1d, 0xee, 0xac,
+ 0x5f, 0x70, 0x98, 0xd5, 0x8a, 0xd1, 0xe2, 0x78, 0x86, 0xfb, 0x06, 0xf2,
+ 0x58, 0xa1, 0x9e, 0x21, 0xa4, 0x57, 0xff, 0x1a, 0x64, 0x6b, 0xf0, 0xcf,
+ 0xee, 0x2c, 0x5f, 0x1c, 0xa2, 0x65, 0x8b, 0xff, 0xef, 0xb4, 0x9b, 0x4e,
+ 0x0f, 0x14, 0x1f, 0x8b, 0x17, 0xde, 0x8d, 0x02, 0x0f, 0xcb, 0xa2, 0x3b,
+ 0xb7, 0x78, 0xb1, 0x7f, 0xdc, 0xeb, 0xee, 0x3d, 0x8c, 0x2b, 0xb1, 0x2c,
+ 0x51, 0xa8, 0x9e, 0x73, 0x9f, 0x0d, 0xd4, 0x2a, 0x9f, 0x91, 0x4e, 0x43,
+ 0x35, 0x88, 0xde, 0x35, 0x6b, 0x88, 0x0b, 0x17, 0xf7, 0x72, 0xc3, 0xc7,
+ 0x4b, 0x17, 0xdb, 0xdd, 0xfb, 0x58, 0xa0, 0xa1, 0xf6, 0x40, 0xbb, 0x18,
+ 0x5e, 0x38, 0xb8, 0xb1, 0x7c, 0xc7, 0xc2, 0x58, 0xb4, 0x39, 0xbf, 0xf0,
+ 0xf5, 0xfa, 0x03, 0x27, 0x92, 0xc5, 0xff, 0xed, 0x39, 0x7b, 0x01, 0xb9,
+ 0x03, 0x1c, 0x2c, 0x5f, 0xfc, 0x50, 0x01, 0x8a, 0x27, 0x8e, 0xe4, 0xb1,
+ 0x7f, 0x4b, 0x51, 0x27, 0xd2, 0xc5, 0xfb, 0xdc, 0x0a, 0x9b, 0xe5, 0x8b,
+ 0x1d, 0x62, 0xa0, 0xf0, 0x70, 0xbe, 0xf7, 0xa0, 0xc5, 0x8b, 0xdf, 0x0f,
+ 0x4b, 0x15, 0x23, 0x7b, 0xe1, 0xeb, 0xde, 0xc1, 0xac, 0x5f, 0xf0, 0xb4,
+ 0x6b, 0xb7, 0x1b, 0x7a, 0xc5, 0xfb, 0x40, 0x3b, 0x71, 0x62, 0xe0, 0x6d,
+ 0xdc, 0x3e, 0x50, 0xcf, 0x2d, 0x9d, 0xa2, 0xd8, 0xa1, 0x05, 0x7c, 0xfd,
+ 0x16, 0x2c, 0x5f, 0xcd, 0xf6, 0xce, 0xfc, 0xb1, 0x43, 0x4e, 0xc7, 0xb5,
+ 0xd3, 0xc3, 0x5c, 0x8b, 0x7c, 0x45, 0x4b, 0x17, 0xc0, 0xf6, 0x01, 0x62,
+ 0xfb, 0x9c, 0x6d, 0xeb, 0x17, 0xff, 0xec, 0x23, 0x5f, 0x9f, 0x76, 0x01,
+ 0xe3, 0xb9, 0x2c, 0x54, 0x1f, 0xdf, 0x44, 0xb7, 0xfe, 0xfb, 0x77, 0xcc,
+ 0x23, 0x70, 0x96, 0x2f, 0xff, 0xe6, 0x9b, 0x9c, 0x13, 0xe8, 0x53, 0xc1,
+ 0xa1, 0x97, 0x96, 0x2d, 0xce, 0x91, 0x3f, 0xf3, 0xfb, 0xe3, 0x91, 0x42,
+ 0xc5, 0xff, 0x30, 0xff, 0x12, 0xce, 0xfc, 0xb1, 0x7f, 0xdd, 0x46, 0xf8,
+ 0xe3, 0x03, 0xb5, 0x8b, 0x1b, 0x08, 0x98, 0x19, 0x0e, 0x1d, 0x56, 0x23,
+ 0xdd, 0xe1, 0x85, 0x7e, 0xf3, 0xf8, 0x50, 0xb1, 0x7f, 0x7e, 0x04, 0x17,
+ 0xda, 0x35, 0x8b, 0xff, 0xfb, 0xed, 0xef, 0xbc, 0x83, 0x1b, 0xce, 0x3f,
+ 0xb1, 0xd6, 0x2f, 0xfc, 0xde, 0x96, 0x03, 0x85, 0x80, 0x58, 0xa1, 0xaf,
+ 0x55, 0xe1, 0x41, 0xa9, 0x9d, 0xa3, 0x34, 0xa2, 0x09, 0x94, 0x34, 0x19,
+ 0xf8, 0x4f, 0x14, 0x77, 0x1c, 0x26, 0xf1, 0x40, 0x8d, 0x77, 0xaf, 0x5e,
+ 0xdc, 0xee, 0x16, 0x2f, 0xf7, 0xca, 0x3b, 0x68, 0xfa, 0xc5, 0xfc, 0xfe,
+ 0x00, 0x65, 0x25, 0x8a, 0xe8, 0xf8, 0xbe, 0x67, 0x5b, 0x1b, 0xa1, 0xbe,
+ 0x89, 0xf1, 0x69, 0x46, 0xc4, 0x32, 0xdc, 0x97, 0x08, 0x6a, 0xa7, 0x63,
+ 0x0d, 0x28, 0xb7, 0x75, 0x7b, 0x50, 0xd9, 0x3a, 0xbf, 0xc8, 0x1e, 0x71,
+ 0x64, 0xa5, 0xc3, 0xf2, 0x17, 0xfe, 0x70, 0x14, 0xf6, 0x86, 0xe4, 0x32,
+ 0x43, 0x84, 0x1d, 0xff, 0x9d, 0x86, 0x2f, 0x72, 0x7c, 0x31, 0x62, 0xe0,
+ 0xa1, 0x2c, 0x5f, 0xb9, 0x86, 0xc7, 0x16, 0x2f, 0xdb, 0x98, 0x4e, 0x6a,
+ 0xc5, 0xfb, 0xb3, 0xb9, 0x01, 0x62, 0xf3, 0xff, 0x4b, 0x15, 0xb4, 0xfc,
+ 0x60, 0xaf, 0x45, 0x37, 0xf6, 0xef, 0x18, 0xbb, 0x92, 0xc5, 0xfb, 0xef,
+ 0xc6, 0xd2, 0xc5, 0xff, 0xc5, 0xf7, 0xe1, 0x61, 0xa6, 0xe6, 0xea, 0xc5,
+ 0xff, 0x6b, 0x71, 0xbf, 0x8f, 0xd8, 0x16, 0x2b, 0x11, 0x0a, 0xe9, 0x17,
+ 0xfa, 0x35, 0xa8, 0x93, 0xfd, 0x62, 0xfc, 0x19, 0x7f, 0x3b, 0x58, 0xae,
+ 0x8f, 0x74, 0x06, 0x77, 0xff, 0xe6, 0xf4, 0x1f, 0x3b, 0xf4, 0x1c, 0x3d,
+ 0x38, 0x16, 0x2f, 0x98, 0x9c, 0x6b, 0x17, 0xff, 0xf7, 0xb9, 0x82, 0x0b,
+ 0xe1, 0x98, 0xdb, 0xf2, 0x50, 0x4b, 0x17, 0xfd, 0xc8, 0xd7, 0xa3, 0x64,
+ 0x6c, 0xb1, 0x52, 0x4c, 0x50, 0x6a, 0xe4, 0x43, 0xc6, 0x0b, 0xdf, 0xfc,
+ 0x2c, 0x5d, 0xf8, 0x58, 0xac, 0x36, 0x8e, 0x3b, 0x7f, 0xff, 0x67, 0xf6,
+ 0xe1, 0xdb, 0xf1, 0xb7, 0x9c, 0xc2, 0x02, 0xc5, 0xff, 0xcd, 0xa8, 0x97,
+ 0xe2, 0x62, 0x11, 0xab, 0x15, 0xf4, 0x52, 0x71, 0x7a, 0xff, 0xd3, 0xc4,
+ 0xc5, 0x1c, 0xc8, 0x92, 0xc5, 0xdd, 0x6e, 0x2c, 0x5f, 0xc6, 0xfa, 0x3f,
+ 0x1c, 0x58, 0xbf, 0xee, 0x16, 0x7b, 0x91, 0xa9, 0xd6, 0x2f, 0xf0, 0xc2,
+ 0x72, 0x26, 0x16, 0x96, 0x2f, 0xd2, 0xef, 0xd9, 0xc5, 0x8b, 0xf3, 0x77,
+ 0xc7, 0xed, 0x62, 0xff, 0xfd, 0x9e, 0xe4, 0x1f, 0xbe, 0x30, 0xff, 0x8c,
+ 0x6a, 0xc5, 0xf7, 0x1b, 0x53, 0xac, 0x54, 0x23, 0x3f, 0xe5, 0x44, 0x55,
+ 0xc5, 0x7b, 0xfd, 0x83, 0xcd, 0x4a, 0x34, 0xb1, 0x7b, 0xed, 0xe5, 0x8a,
+ 0x85, 0x4a, 0xd2, 0x3f, 0x61, 0xc9, 0x8b, 0xdc, 0xe8, 0x11, 0x83, 0xf0,
+ 0xec, 0x33, 0x3b, 0xf3, 0xff, 0x3b, 0xf2, 0xc5, 0xff, 0x9f, 0xdc, 0x8c,
+ 0x21, 0xfe, 0x16, 0x2f, 0xba, 0xfc, 0x09, 0x62, 0xbe, 0x7c, 0x3e, 0x3d,
+ 0xbf, 0xf3, 0x94, 0xe6, 0x61, 0x0f, 0xf0, 0xb1, 0x73, 0x4e, 0xb1, 0x58,
+ 0x7a, 0xe4, 0x7f, 0x7f, 0x85, 0xdc, 0xb8, 0x1c, 0x6e, 0xac, 0x5e, 0xea,
+ 0x37, 0x56, 0x2f, 0xf4, 0xdf, 0x7d, 0x69, 0x86, 0xb1, 0x58, 0x7a, 0xce,
+ 0x43, 0x7f, 0x9f, 0xb0, 0xf4, 0xc7, 0xc5, 0x8b, 0xf9, 0xca, 0x73, 0xbf,
+ 0x96, 0x28, 0x8f, 0x8f, 0x86, 0xb7, 0xf6, 0x13, 0x0f, 0x09, 0x62, 0xf7,
+ 0xdc, 0xeb, 0x15, 0x23, 0xc8, 0x62, 0xbb, 0xf0, 0x7a, 0xcd, 0xf8, 0xb1,
+ 0x63, 0xac, 0x58, 0x7f, 0x37, 0xa4, 0x57, 0x7f, 0x8b, 0x27, 0xf7, 0xa0,
+ 0xeb, 0x15, 0x07, 0xb4, 0x44, 0xd5, 0x25, 0x6e, 0xf9, 0x08, 0xa9, 0x9e,
+ 0x74, 0x40, 0x50, 0x90, 0xe4, 0x20, 0xfc, 0xd2, 0x1c, 0x2e, 0x2f, 0xe9,
+ 0xa4, 0xda, 0x96, 0xc0, 0xb1, 0x76, 0xc4, 0x15, 0x58, 0xbd, 0xc6, 0x31,
+ 0x62, 0xff, 0x1a, 0xe1, 0xc0, 0x03, 0x3a, 0xc5, 0xfe, 0x93, 0x6a, 0x59,
+ 0xf7, 0x58, 0xbe, 0xc9, 0x9f, 0xcb, 0x17, 0xf7, 0xb9, 0x34, 0x9c, 0x96,
+ 0x2f, 0xcf, 0xde, 0x7d, 0xd6, 0x2a, 0x0f, 0x5c, 0x45, 0xf6, 0xd6, 0xd4,
+ 0xde, 0x42, 0xd1, 0xae, 0x10, 0x9a, 0x3d, 0x31, 0xbf, 0xcc, 0xc9, 0xea,
+ 0xf8, 0xf1, 0xae, 0x2c, 0x5f, 0xfe, 0x81, 0xfc, 0x46, 0x87, 0x03, 0xf8,
+ 0xb8, 0xb1, 0x6d, 0xd1, 0x9f, 0x88, 0x64, 0x77, 0x64, 0xeb, 0x15, 0x07,
+ 0x89, 0x85, 0x97, 0xf4, 0xfc, 0x89, 0x85, 0xa5, 0x8b, 0xfa, 0x02, 0x75,
+ 0xf8, 0x9d, 0x62, 0xf7, 0x9f, 0x8b, 0x17, 0xfc, 0x29, 0x03, 0xf0, 0xc5,
+ 0x3a, 0xc5, 0x62, 0x2e, 0x8d, 0x31, 0x63, 0x22, 0x1d, 0xbb, 0x61, 0xba,
+ 0xc5, 0xff, 0xff, 0xc5, 0xd6, 0x14, 0x19, 0xe3, 0x5f, 0x83, 0x87, 0xd7,
+ 0xcc, 0x71, 0xac, 0x5c, 0xfd, 0xac, 0x5b, 0xd0, 0x88, 0xce, 0x3a, 0x5f,
+ 0x61, 0xe3, 0x75, 0x62, 0xff, 0xfc, 0xe3, 0x11, 0xa2, 0x0c, 0x4e, 0x1c,
+ 0xdb, 0x41, 0xe5, 0x8a, 0x84, 0xd5, 0x1a, 0x15, 0x3c, 0x28, 0x11, 0x2d,
+ 0xcd, 0xa5, 0x8b, 0xf4, 0x0b, 0xa1, 0x1d, 0x62, 0x86, 0x78, 0x21, 0x8b,
+ 0xdc, 0xc4, 0xb1, 0x7d, 0x28, 0x2e, 0x96, 0x28, 0x66, 0xe7, 0x05, 0xad,
+ 0x32, 0xc5, 0xf0, 0x55, 0xe3, 0xb5, 0x8b, 0x41, 0x1b, 0xaf, 0x09, 0xd6,
+ 0xd3, 0xff, 0x65, 0xab, 0xe8, 0x06, 0x12, 0xc5, 0xf1, 0x73, 0xcc, 0xb1,
+ 0x52, 0x6c, 0x93, 0x87, 0x09, 0xac, 0x30, 0x34, 0xcb, 0xa8, 0x56, 0xf6,
+ 0xfc, 0xd1, 0x9b, 0xee, 0xb8, 0xcd, 0x0c, 0x3d, 0x4a, 0x79, 0x3c, 0xbe,
+ 0xf7, 0x94, 0x00, 0x08, 0xca, 0x0a, 0x1b, 0x5c, 0x8e, 0x3c, 0x50, 0x82,
+ 0x32, 0x1b, 0x7b, 0x84, 0x61, 0x90, 0xdf, 0x1c, 0x2c, 0xd8, 0x7b, 0x02,
+ 0xc5, 0xde, 0xe2, 0xc5, 0x31, 0xe6, 0x4c, 0x69, 0x7c, 0x1c, 0x19, 0xc5,
+ 0x8b, 0x81, 0xe5, 0x8b, 0x81, 0xf5, 0x8b, 0xed, 0x6b, 0x38, 0xb1, 0x76,
+ 0x4c, 0xb1, 0x69, 0x6d, 0x44, 0x84, 0xe4, 0xa7, 0x18, 0x71, 0x80, 0xc8,
+ 0xef, 0xfb, 0x82, 0xd0, 0x18, 0x7f, 0x85, 0x8b, 0xef, 0x39, 0x62, 0xc5,
+ 0xf0, 0x48, 0x29, 0x2c, 0x53, 0x1e, 0x28, 0x64, 0x37, 0xc4, 0xfe, 0xe2,
+ 0xc5, 0xed, 0x3e, 0xf5, 0x8b, 0xfe, 0xc0, 0x8e, 0xc3, 0x17, 0xb8, 0xb1,
+ 0x7e, 0xd0, 0xf3, 0x09, 0x62, 0xf8, 0xdd, 0x39, 0x8b, 0x17, 0xfe, 0x6c,
+ 0xfc, 0x6f, 0xe7, 0xe3, 0xb5, 0x8a, 0xc3, 0xe6, 0xdd, 0x25, 0xbf, 0xbb,
+ 0xd0, 0xbb, 0xf4, 0x96, 0x2f, 0xe3, 0x30, 0x87, 0xf8, 0x58, 0xbf, 0xdc,
+ 0x19, 0x41, 0x83, 0xc5, 0x8b, 0x3f, 0x67, 0xc5, 0xf2, 0xeb, 0xa2, 0x75,
+ 0x8a, 0xc5, 0x40, 0x33, 0x11, 0x68, 0x7d, 0xce, 0xf9, 0x08, 0xd1, 0x12,
+ 0x19, 0x09, 0x40, 0xca, 0x2f, 0xc6, 0x7b, 0xd9, 0x3a, 0xc5, 0xfc, 0xf0,
+ 0x0c, 0xee, 0x4b, 0x14, 0xb1, 0x7f, 0x8b, 0x59, 0xcc, 0x6f, 0xac, 0x50,
+ 0x54, 0xdf, 0x60, 0x65, 0xff, 0xd8, 0x45, 0x9f, 0xc1, 0xfc, 0x53, 0x2c,
+ 0x5f, 0xfc, 0x58, 0xfe, 0x2c, 0xf7, 0xb0, 0xc5, 0x8b, 0x49, 0x91, 0x0f,
+ 0xe4, 0x4b, 0xfb, 0x4d, 0xef, 0xe4, 0x96, 0x2f, 0x67, 0x72, 0x58, 0xa5,
+ 0x8f, 0x97, 0xd7, 0xbf, 0x1b, 0xd6, 0x2b, 0x48, 0x86, 0xfa, 0x67, 0x86,
+ 0xee, 0x70, 0x8b, 0x17, 0xff, 0x40, 0xf3, 0xa2, 0xcf, 0x7d, 0xbb, 0x58,
+ 0xbf, 0xde, 0xcd, 0x4f, 0x1e, 0xe2, 0xc5, 0x49, 0x12, 0x7f, 0x19, 0x74,
+ 0x5b, 0xff, 0xec, 0x1b, 0x7b, 0x0f, 0xf8, 0x8e, 0x8e, 0xeb, 0x17, 0x66,
+ 0xf5, 0x8b, 0xfe, 0xeb, 0xf8, 0x33, 0xb6, 0xb1, 0x62, 0xfe, 0x8e, 0x7e,
+ 0x08, 0xd5, 0x8a, 0x84, 0x68, 0x4e, 0x9f, 0x83, 0x3a, 0x3a, 0xbd, 0xb9,
+ 0x86, 0xac, 0x5f, 0xa3, 0x5f, 0x8d, 0xeb, 0x17, 0xdb, 0xdb, 0x9d, 0xac,
+ 0x54, 0x1e, 0x83, 0x95, 0x5f, 0xbf, 0x39, 0x34, 0x2c, 0x5f, 0x83, 0xc9,
+ 0x87, 0x25, 0x8b, 0x1a, 0xb1, 0x53, 0x9f, 0x34, 0xc5, 0x1b, 0x85, 0x77,
+ 0xcc, 0x53, 0x6e, 0xac, 0x5f, 0x14, 0x77, 0x25, 0x8a, 0x73, 0xfd, 0x01,
+ 0xa7, 0x89, 0xaf, 0xd1, 0xee, 0x67, 0x96, 0x2f, 0xe8, 0xdf, 0x9f, 0xfc,
+ 0x2c, 0x5f, 0x7b, 0x99, 0x32, 0xc7, 0xcd, 0x7d, 0xfd, 0xf1, 0xb6, 0xf8,
+ 0x1a, 0xc5, 0x0d, 0x17, 0x78, 0xae, 0xe6, 0x97, 0xda, 0x67, 0x9d, 0x62,
+ 0xf3, 0x60, 0x16, 0x2b, 0x0d, 0xff, 0x08, 0xef, 0xf3, 0x0b, 0x5f, 0xcd,
+ 0xfc, 0x58, 0xbf, 0xff, 0xbc, 0xdd, 0xc8, 0xa3, 0x6f, 0x9b, 0x02, 0x0f,
+ 0xf8, 0xb1, 0x7f, 0xfa, 0x0e, 0x59, 0xbc, 0xb3, 0x7e, 0x6a, 0x4b, 0x15,
+ 0x88, 0xab, 0x25, 0xfb, 0xfd, 0xee, 0x07, 0xff, 0xbe, 0xea, 0xc5, 0xf6,
+ 0x79, 0xb8, 0xb1, 0x7e, 0x98, 0xb6, 0x09, 0xc4, 0xb1, 0x77, 0xbe, 0xb1,
+ 0x41, 0x43, 0xc8, 0x73, 0x0a, 0xdd, 0x4f, 0x2a, 0x68, 0x70, 0xb9, 0x0f,
+ 0x0e, 0x7c, 0xd5, 0x7f, 0xe1, 0x39, 0xf8, 0xc4, 0xfa, 0x35, 0x62, 0xf9,
+ 0xfc, 0xe4, 0xb1, 0x53, 0xb3, 0x1d, 0x64, 0xfe, 0x39, 0x44, 0x78, 0xfc,
+ 0x69, 0x5f, 0x4d, 0x9d, 0xc2, 0xad, 0xa1, 0x5d, 0x34, 0x30, 0xf5, 0x0f,
+ 0xf3, 0x9e, 0x7d, 0xc4, 0x11, 0x81, 0x94, 0x3a, 0x78, 0xdb, 0xe8, 0xfa,
+ 0x8c, 0x53, 0x08, 0x7f, 0x7e, 0xf7, 0xd8, 0x80, 0xb1, 0x7d, 0xef, 0x34,
+ 0x96, 0x2e, 0x9a, 0x16, 0x2f, 0x6f, 0xd4, 0x96, 0x2e, 0xc3, 0x00, 0x6e,
+ 0x08, 0x62, 0xff, 0xfd, 0xe6, 0xe4, 0xf8, 0x67, 0x1a, 0x72, 0x7e, 0xfc,
+ 0xb1, 0x7f, 0xd2, 0xcf, 0x60, 0xd8, 0x80, 0xb1, 0x7d, 0x2c, 0x8e, 0xd6,
+ 0x2f, 0xd1, 0xac, 0x26, 0x58, 0xbc, 0x66, 0x7d, 0x62, 0xfe, 0xcd, 0x68,
+ 0x46, 0xe9, 0x62, 0xfe, 0x29, 0x18, 0xff, 0xe2, 0xc5, 0xf8, 0xdf, 0xb9,
+ 0x32, 0xc5, 0xb9, 0x87, 0xae, 0xc5, 0xf7, 0x1b, 0x25, 0x8b, 0xed, 0x07,
+ 0x06, 0x2c, 0x5f, 0x0c, 0x9c, 0xd5, 0x8b, 0xff, 0x9a, 0x4f, 0xac, 0xdf,
+ 0xdf, 0x4d, 0xda, 0xc5, 0x42, 0x24, 0x67, 0x25, 0xf1, 0x1d, 0xd8, 0x38,
+ 0x56, 0x0d, 0x3a, 0xde, 0x16, 0x76, 0xb3, 0x31, 0xc7, 0xc8, 0xdc, 0x98,
+ 0x87, 0xbd, 0x08, 0x7d, 0xc2, 0x60, 0xe1, 0x55, 0x7d, 0x83, 0xe1, 0x8b,
+ 0x16, 0x6e, 0x23, 0x58, 0x24, 0x2c, 0xaf, 0xf0, 0x05, 0xc6, 0x2e, 0xe4,
+ 0xb1, 0x7f, 0x01, 0xb4, 0xdd, 0x81, 0x62, 0xcf, 0xba, 0x7c, 0x93, 0x1a,
+ 0xd8, 0x0b, 0x17, 0xf8, 0x78, 0x4c, 0x67, 0xc4, 0xb1, 0x7e, 0xef, 0xa1,
+ 0x39, 0x2c, 0x5f, 0xff, 0x7d, 0xa3, 0xcc, 0x08, 0x96, 0xc9, 0x86, 0x18,
+ 0x91, 0x7f, 0xf3, 0x47, 0x81, 0x12, 0xd9, 0x30, 0xc3, 0x12, 0x2b, 0x11,
+ 0x43, 0xf5, 0x6a, 0x9d, 0x32, 0x1e, 0x8d, 0x3d, 0x0c, 0xbb, 0xfd, 0xf1,
+ 0x39, 0xc6, 0xe7, 0x58, 0xa2, 0x3e, 0xcf, 0x1c, 0x5e, 0xcc, 0x35, 0x22,
+ 0xc0, 0x58, 0xbe, 0x6f, 0xc1, 0xd6, 0x2e, 0xe6, 0x41, 0xb4, 0x34, 0x4a,
+ 0x86, 0x7f, 0xbe, 0x51, 0xbc, 0x07, 0xf2, 0xc5, 0xf7, 0xb8, 0x2d, 0xd5,
+ 0x8b, 0xe8, 0xd3, 0x6f, 0x58, 0xa7, 0x3e, 0x81, 0x0e, 0x86, 0x4f, 0x7f,
+ 0xda, 0x7e, 0xb6, 0xfe, 0x03, 0x25, 0x8b, 0xc2, 0x8d, 0x2c, 0x5d, 0xee,
+ 0x0c, 0xf6, 0xa6, 0x3d, 0xbe, 0x34, 0x40, 0xe2, 0xc5, 0xc4, 0x25, 0x44,
+ 0x32, 0x5f, 0xd0, 0x78, 0xe6, 0xb1, 0x62, 0xa4, 0x7a, 0x33, 0x12, 0x5e,
+ 0xfc, 0x4e, 0xb1, 0x7e, 0xf4, 0x48, 0xd3, 0xac, 0x5f, 0xe1, 0x17, 0x5f,
+ 0x8e, 0xc2, 0x2c, 0x5f, 0xcd, 0xbd, 0x8a, 0x0e, 0xb1, 0x78, 0xc3, 0x0c,
+ 0x48, 0xbd, 0x85, 0xd2, 0x46, 0xc9, 0xa1, 0xbf, 0xf6, 0x4f, 0x83, 0x79,
+ 0x14, 0x4e, 0xb1, 0x50, 0x99, 0x03, 0x15, 0x39, 0xc0, 0x13, 0xc8, 0xc2,
+ 0xff, 0xf6, 0x6b, 0xde, 0xce, 0x14, 0x66, 0xa4, 0xb1, 0x7e, 0x6f, 0xff,
+ 0x3c, 0xb1, 0x68, 0xda, 0x7e, 0x3c, 0x49, 0xbf, 0x7f, 0x3b, 0x11, 0x8b,
+ 0x17, 0xdf, 0x72, 0x35, 0x62, 0x86, 0x7e, 0xfd, 0x14, 0xf8, 0xae, 0xfe,
+ 0xee, 0x5c, 0x27, 0xe9, 0x62, 0xf9, 0xf7, 0x7d, 0xc5, 0x8b, 0xc4, 0x16,
+ 0xb6, 0x25, 0x8a, 0xc3, 0xfe, 0xec, 0xc1, 0xc9, 0xae, 0x0b, 0x41, 0x69,
+ 0x62, 0xfd, 0x2e, 0xb3, 0xbf, 0x2c, 0x5f, 0xb3, 0xde, 0x14, 0xeb, 0x17,
+ 0xfe, 0x69, 0xfe, 0xcf, 0x2f, 0x34, 0xeb, 0x16, 0x90, 0x5a, 0x45, 0xcc,
+ 0x89, 0x08, 0xaf, 0xc5, 0x57, 0xb7, 0xb9, 0xd6, 0x2f, 0xb0, 0x6f, 0xf5,
+ 0x8a, 0xc3, 0xc1, 0xe0, 0xfd, 0xf0, 0xff, 0x9d, 0x2c, 0x5e, 0x7d, 0xd8,
+ 0x58, 0xbf, 0x60, 0xfe, 0xfb, 0xab, 0x17, 0xe2, 0xc1, 0xc1, 0xd6, 0x2b,
+ 0x60, 0x64, 0xac, 0xc4, 0x73, 0xf3, 0xc2, 0x78, 0x70, 0x8a, 0xc8, 0x44,
+ 0x9a, 0x5f, 0xdb, 0xb4, 0xc4, 0x7a, 0x8c, 0xf8, 0xf1, 0x97, 0xfe, 0x15,
+ 0xcf, 0x0e, 0x70, 0x42, 0x24, 0x88, 0x44, 0x49, 0xbc, 0x7c, 0xc2, 0xbb,
+ 0xf8, 0xf8, 0xda, 0x9a, 0x4b, 0x17, 0xff, 0xc6, 0x86, 0xe5, 0xf7, 0x97,
+ 0x30, 0xf1, 0xba, 0xb1, 0x50, 0x88, 0x36, 0x2f, 0xbe, 0x8f, 0x08, 0x35,
+ 0x8b, 0xde, 0x68, 0x58, 0xbf, 0x34, 0x4e, 0xe7, 0x58, 0xbf, 0xdf, 0x82,
+ 0xf1, 0x0f, 0xb5, 0x8b, 0x12, 0xc5, 0xcc, 0x75, 0x8a, 0xc3, 0x50, 0x42,
+ 0x34, 0xc8, 0xbf, 0x21, 0xce, 0x14, 0x09, 0x72, 0xff, 0xda, 0x94, 0x8f,
+ 0xc6, 0x2e, 0xe4, 0xb1, 0x7e, 0x28, 0xee, 0x38, 0xb1, 0x7f, 0xec, 0x62,
+ 0x7f, 0x70, 0xc8, 0x25, 0x8b, 0x6a, 0x0f, 0x97, 0x85, 0x16, 0xfe, 0x23,
+ 0x35, 0xe1, 0x4d, 0x7c, 0xda, 0x8f, 0x2c, 0x5f, 0xff, 0x8a, 0x35, 0xa6,
+ 0x89, 0xf0, 0x02, 0x72, 0xe9, 0x62, 0xfb, 0x99, 0x12, 0x58, 0xa1, 0xa2,
+ 0x67, 0xa2, 0x22, 0x55, 0xbd, 0xfc, 0xed, 0x62, 0xfc, 0x3d, 0x34, 0x1d,
+ 0x62, 0xd1, 0x23, 0xc6, 0x21, 0xeb, 0xe9, 0x34, 0x74, 0xb1, 0x77, 0x60,
+ 0x58, 0xbf, 0x8f, 0x1c, 0x03, 0x74, 0xb1, 0x7b, 0x90, 0x68, 0x0f, 0x23,
+ 0x83, 0x37, 0xf1, 0x60, 0x46, 0x89, 0x96, 0x2f, 0xec, 0xd0, 0x00, 0xc4,
+ 0xb1, 0x4e, 0x7b, 0x82, 0x2f, 0xbf, 0x8b, 0xcd, 0x39, 0x42, 0xc5, 0xb8,
+ 0xb1, 0x76, 0xc1, 0x3a, 0xc5, 0x41, 0xee, 0xc8, 0xb5, 0xc4, 0xaf, 0xb5,
+ 0xa8, 0x92, 0xc5, 0xfe, 0x61, 0xeb, 0x06, 0xe7, 0x58, 0xbe, 0x9b, 0x91,
+ 0xc5, 0x8b, 0x61, 0xcf, 0x5c, 0x06, 0x77, 0xd8, 0x70, 0xc6, 0xb1, 0x7f,
+ 0x31, 0xbe, 0xe3, 0xf6, 0xb1, 0x7e, 0x36, 0x68, 0x2f, 0x2c, 0x53, 0x26,
+ 0x3f, 0xf7, 0xa2, 0x27, 0xe1, 0x20, 0x8c, 0x2f, 0x05, 0x3e, 0xcb, 0x17,
+ 0xff, 0xfd, 0xbe, 0x06, 0xc4, 0xfa, 0x34, 0x9d, 0x8b, 0x00, 0x2e, 0x2c,
+ 0x5f, 0xfb, 0xe1, 0xf3, 0x35, 0xd3, 0xbf, 0x4a, 0x88, 0x30, 0xbf, 0xfa,
+ 0x78, 0x37, 0x35, 0xef, 0x46, 0x71, 0x62, 0x86, 0x89, 0x52, 0x4f, 0xa8,
+ 0x4c, 0x75, 0xa1, 0xf7, 0x7f, 0xef, 0x89, 0xcd, 0xcf, 0x7b, 0x3e, 0xb1,
+ 0x7f, 0xb7, 0xc1, 0x60, 0x78, 0x75, 0x8b, 0xfd, 0xf8, 0x2f, 0x01, 0xfc,
+ 0xb1, 0x7f, 0xfa, 0x5a, 0x89, 0x75, 0xf6, 0xf9, 0x39, 0xd6, 0x2b, 0x87,
+ 0xfc, 0x23, 0x3b, 0xff, 0xf8, 0xf0, 0x5d, 0x39, 0x03, 0x07, 0xc2, 0x13,
+ 0xc9, 0x62, 0xf1, 0x08, 0xd5, 0x8b, 0xfe, 0xe9, 0x8e, 0x76, 0xdb, 0xc1,
+ 0x2c, 0x5f, 0xe7, 0xef, 0x81, 0xeb, 0xee, 0xb1, 0x7f, 0xf6, 0x18, 0xe0,
+ 0xda, 0xe1, 0xcc, 0xfe, 0x58, 0xb7, 0x00, 0x7f, 0xe4, 0x6d, 0x7f, 0x3f,
+ 0xf0, 0x8f, 0x8b, 0x17, 0xc2, 0xfe, 0x74, 0xb1, 0x52, 0x55, 0xce, 0x32,
+ 0x76, 0x40, 0xd4, 0x2c, 0xce, 0x45, 0xf5, 0xa2, 0x1e, 0xf4, 0x2f, 0x37,
+ 0x93, 0xee, 0x16, 0x5f, 0xfd, 0xee, 0x4f, 0x01, 0x94, 0x7d, 0xa7, 0x58,
+ 0xbf, 0xdc, 0x8d, 0x4b, 0xa6, 0x9d, 0x62, 0xfb, 0xec, 0xe0, 0x58, 0xa2,
+ 0x44, 0xff, 0x11, 0xfc, 0x6d, 0x7f, 0xb0, 0xbc, 0xda, 0x07, 0x16, 0x2e,
+ 0x6f, 0x2c, 0x5f, 0xfd, 0xfc, 0xeb, 0x35, 0xce, 0xfc, 0x19, 0xd6, 0x2f,
+ 0xd9, 0xbd, 0x88, 0x6b, 0x14, 0x33, 0xf2, 0x24, 0x9b, 0x9e, 0x50, 0x8a,
+ 0xae, 0x42, 0x26, 0xda, 0x35, 0x30, 0xfd, 0x43, 0x76, 0xfe, 0x11, 0xa5,
+ 0x93, 0x89, 0x62, 0xa1, 0x39, 0xec, 0x8c, 0xfb, 0xe6, 0x17, 0x7f, 0xa5,
+ 0x8b, 0xed, 0x01, 0xa4, 0xb1, 0x7e, 0x7f, 0x6a, 0x24, 0xb1, 0x7f, 0xde,
+ 0x62, 0x7e, 0xfc, 0x28, 0x58, 0xbe, 0x2f, 0x0b, 0xf0, 0x88, 0x4f, 0x91,
+ 0x86, 0x51, 0x7b, 0xe2, 0xdd, 0x58, 0xbf, 0xf3, 0x17, 0xb8, 0xc3, 0x07,
+ 0x60, 0x58, 0xbf, 0xfe, 0xfb, 0x66, 0xfc, 0xe3, 0xc9, 0x8a, 0x37, 0xac,
+ 0x5f, 0xf7, 0x4d, 0x86, 0x06, 0x37, 0x9d, 0x62, 0xdc, 0x58, 0xae, 0xcf,
+ 0x3e, 0x63, 0xda, 0xe2, 0x31, 0x3d, 0x0a, 0x0b, 0xfe, 0xc2, 0xeb, 0xec,
+ 0x00, 0xfc, 0xb1, 0x67, 0xe1, 0xf1, 0xef, 0x28, 0xa9, 0xd3, 0x90, 0xd4,
+ 0x6c, 0xf5, 0xb1, 0xb2, 0x7c, 0x62, 0x70, 0x96, 0x52, 0xb5, 0xf0, 0xd5,
+ 0xa1, 0x3a, 0x17, 0x47, 0x14, 0x76, 0x37, 0xb0, 0x8d, 0x58, 0xbf, 0xce,
+ 0x3f, 0xe6, 0x77, 0xe5, 0x8a, 0xc3, 0xd1, 0x34, 0x76, 0xbb, 0x66, 0xc7,
+ 0xfe, 0x12, 0x04, 0xfd, 0xc8, 0xd3, 0x3d, 0x4a, 0x3a, 0x09, 0x0d, 0x9b,
+ 0xf4, 0x14, 0xa4, 0x75, 0x8b, 0xc5, 0x06, 0x2c, 0x5f, 0x37, 0x4c, 0x35,
+ 0x8b, 0xc1, 0xc8, 0xeb, 0x15, 0x24, 0x43, 0xe1, 0x47, 0x87, 0x44, 0x47,
+ 0x7f, 0xfb, 0xbf, 0x43, 0x17, 0xb5, 0x1e, 0x7f, 0x2c, 0x5f, 0x47, 0x9a,
+ 0x65, 0x8b, 0xf8, 0x4e, 0x18, 0x9c, 0x35, 0x8a, 0x98, 0xf4, 0xf4, 0x47,
+ 0x79, 0xf2, 0x4b, 0x17, 0x6f, 0xc5, 0x8a, 0xc3, 0xd8, 0x62, 0x37, 0x1c,
+ 0xbf, 0xf9, 0xe5, 0xb7, 0x3d, 0x9f, 0x8d, 0x01, 0x62, 0xe0, 0x01, 0x62,
+ 0xff, 0xba, 0xfb, 0x68, 0x9b, 0xdc, 0x58, 0xa9, 0x22, 0x60, 0xe8, 0xc0,
+ 0x18, 0xbf, 0xfd, 0x86, 0x10, 0x9f, 0x8d, 0x9b, 0xdf, 0x4b, 0x17, 0xf3,
+ 0x7f, 0xf8, 0x07, 0x58, 0xbc, 0xff, 0xe2, 0xc5, 0x42, 0x25, 0x40, 0x96,
+ 0x22, 0xdb, 0xfb, 0x93, 0x7d, 0x8c, 0xf2, 0xc5, 0xfe, 0xe3, 0x61, 0x67,
+ 0x66, 0x2c, 0x5f, 0xff, 0xec, 0xf7, 0x9f, 0x45, 0x1d, 0xc8, 0x3d, 0x00,
+ 0xed, 0xc5, 0x8a, 0xc4, 0x64, 0x6e, 0x98, 0x9c, 0xd2, 0xfc, 0x2e, 0xfa,
+ 0xc3, 0xac, 0x5f, 0xe6, 0x33, 0x08, 0x7f, 0x85, 0x8b, 0xe7, 0xec, 0x86,
+ 0xb1, 0x47, 0x3d, 0x60, 0x19, 0xdf, 0xfe, 0x8f, 0x70, 0x5d, 0x6d, 0xfb,
+ 0x94, 0x42, 0xc5, 0x84, 0xb1, 0x7e, 0x00, 0x60, 0x79, 0x2c, 0x57, 0xcd,
+ 0xe3, 0x89, 0x5f, 0x6e, 0xed, 0xdd, 0x92, 0xc5, 0xff, 0xe2, 0x1f, 0xf3,
+ 0xb0, 0xdc, 0xbc, 0x43, 0x58, 0xb4, 0xa0, 0xfd, 0xd8, 0xb2, 0xff, 0xfe,
+ 0x63, 0x3e, 0xfd, 0x41, 0x0f, 0x3b, 0xf7, 0xdc, 0x6b, 0x17, 0xfd, 0x3f,
+ 0xa5, 0x9b, 0xae, 0x40, 0x58, 0xbe, 0x9b, 0xef, 0xe5, 0x8a, 0xc3, 0xe1,
+ 0x63, 0xdb, 0xf4, 0x3f, 0xdf, 0x75, 0x62, 0xfb, 0x3b, 0xce, 0x2c, 0x5d,
+ 0x83, 0xd1, 0xe6, 0xfc, 0xaa, 0xf3, 0x19, 0xba, 0xb1, 0x7f, 0xb3, 0x7f,
+ 0x3d, 0xe8, 0x3a, 0xc5, 0x68, 0xf5, 0xfe, 0x43, 0x50, 0xaf, 0xac, 0x66,
+ 0x59, 0x08, 0x13, 0x48, 0x9a, 0x11, 0x13, 0x42, 0x5f, 0x44, 0xdf, 0x85,
+ 0xf1, 0x36, 0xf2, 0x10, 0x97, 0xfe, 0x93, 0x14, 0x83, 0xff, 0xe0, 0x6b,
+ 0x17, 0x18, 0xcb, 0x17, 0xb0, 0xba, 0x58, 0xba, 0x0e, 0xb1, 0x63, 0xf4,
+ 0x6d, 0x37, 0x07, 0x6a, 0x0f, 0xdd, 0x93, 0x2f, 0xfb, 0x06, 0x6b, 0xcd,
+ 0xf8, 0x9d, 0x62, 0xfc, 0x2f, 0x4f, 0xc3, 0x56, 0x2f, 0xfe, 0x79, 0xf8,
+ 0xe3, 0x89, 0xe2, 0x50, 0xb1, 0x7f, 0x67, 0x37, 0x33, 0x50, 0xb1, 0x5d,
+ 0xa7, 0x69, 0xa8, 0x5b, 0xfc, 0x80, 0x8f, 0x38, 0x59, 0xb8, 0x8b, 0x7f,
+ 0xd0, 0x1f, 0xdf, 0xbf, 0x7e, 0x16, 0x2f, 0x9a, 0x0a, 0x65, 0x8a, 0x9d,
+ 0xbc, 0xf4, 0x94, 0x38, 0xc7, 0x18, 0x46, 0x43, 0x17, 0xa7, 0x6e, 0xc9,
+ 0x9a, 0x9b, 0xf5, 0x34, 0x3f, 0x74, 0x78, 0x78, 0x7a, 0xbc, 0x31, 0x01,
+ 0x0c, 0x5e, 0x4e, 0x71, 0x7a, 0x52, 0xc6, 0xf6, 0x03, 0x0e, 0xef, 0xf7,
+ 0x39, 0x84, 0x0d, 0xcc, 0x58, 0xbe, 0x26, 0x09, 0x0b, 0x17, 0x02, 0x16,
+ 0x2f, 0x16, 0x71, 0x62, 0x88, 0xd9, 0x86, 0x2f, 0x69, 0x96, 0x2f, 0xee,
+ 0x61, 0x03, 0x73, 0x16, 0x2f, 0x6c, 0x50, 0x4b, 0x15, 0xb5, 0x31, 0x1c,
+ 0x36, 0x75, 0x60, 0x10, 0xf0, 0x4c, 0xc3, 0x0b, 0xef, 0x3b, 0x92, 0xc5,
+ 0x6f, 0x3f, 0xa3, 0x16, 0x6f, 0xfe, 0x17, 0x59, 0xad, 0x44, 0xb9, 0x00,
+ 0x58, 0xbf, 0xc0, 0x70, 0x46, 0xec, 0x49, 0x62, 0xff, 0xe9, 0x36, 0x7d,
+ 0xff, 0xf8, 0xef, 0x8b, 0x17, 0xfb, 0xf8, 0x32, 0x8c, 0x25, 0x8a, 0x92,
+ 0x2b, 0x3b, 0x36, 0x02, 0x2d, 0xd8, 0x4b, 0x17, 0xb4, 0xfd, 0x2c, 0x50,
+ 0xcd, 0xa1, 0xa2, 0xd7, 0xff, 0x4f, 0x34, 0xa3, 0x53, 0xff, 0xb7, 0xdd,
+ 0x58, 0xbf, 0x08, 0xf1, 0x9e, 0x58, 0xbe, 0xc0, 0x40, 0x16, 0x28, 0x07,
+ 0x94, 0x45, 0x15, 0x3a, 0x36, 0x9c, 0x8b, 0xd0, 0x97, 0xac, 0x54, 0xcc,
+ 0xf0, 0xf2, 0x14, 0x67, 0xf7, 0x11, 0xab, 0x17, 0xff, 0x8a, 0x7d, 0xb3,
+ 0x31, 0x60, 0xf0, 0x8d, 0x58, 0xbf, 0xe1, 0x08, 0x32, 0x6d, 0xa0, 0xf2,
+ 0xc5, 0xe9, 0x81, 0x0b, 0x17, 0xfd, 0xbe, 0x3b, 0xdc, 0x8d, 0x61, 0x2c,
+ 0x56, 0xc4, 0x7b, 0x98, 0x3d, 0x7f, 0x37, 0x61, 0x3f, 0x1e, 0x58, 0xbf,
+ 0x0b, 0x8c, 0xdd, 0xac, 0x5f, 0xe1, 0x76, 0x13, 0xaf, 0xbf, 0x16, 0x2f,
+ 0xb3, 0xdf, 0x65, 0x8a, 0x73, 0xdb, 0x23, 0x9b, 0xc1, 0xe4, 0x2c, 0x5c,
+ 0x23, 0x56, 0x2f, 0xd0, 0x44, 0x23, 0xac, 0x57, 0xcf, 0x00, 0x31, 0x9b,
+ 0xde, 0x80, 0xd6, 0x2f, 0xf6, 0x0f, 0x4f, 0xd7, 0x80, 0xb1, 0x7e, 0xc2,
+ 0x1f, 0xe1, 0x62, 0xb0, 0xfe, 0xbe, 0x3c, 0x61, 0xad, 0xe9, 0x67, 0x16,
+ 0x2f, 0xee, 0xbf, 0x1e, 0x10, 0x6b, 0x15, 0x0a, 0xd6, 0x27, 0x4d, 0x36,
+ 0x13, 0x3b, 0xa4, 0xd3, 0x18, 0xea, 0x10, 0x8e, 0x40, 0x4b, 0xbc, 0x84,
+ 0xef, 0x8b, 0xc3, 0x1d, 0xbe, 0x1e, 0x9e, 0x4b, 0x17, 0xff, 0xfb, 0x09,
+ 0xfd, 0xcc, 0xd0, 0x01, 0x19, 0xdf, 0xb8, 0xcb, 0x17, 0x4a, 0x16, 0x2d,
+ 0xb8, 0xb1, 0x5b, 0x4d, 0x66, 0x0b, 0xd0, 0xd1, 0x5d, 0xe8, 0x46, 0x54,
+ 0x23, 0xe5, 0xe1, 0xa3, 0x78, 0x70, 0x4b, 0x15, 0xb5, 0xf6, 0xa1, 0xb6,
+ 0x34, 0x18, 0xac, 0x9a, 0x67, 0x8e, 0x78, 0x70, 0xb2, 0xca, 0x66, 0x41,
+ 0xb1, 0x94, 0x75, 0x38, 0x09, 0xdc, 0x24, 0xda, 0x93, 0x09, 0xf8, 0xe9,
+ 0x5e, 0xbd, 0x15, 0x04, 0xaa, 0x92, 0x95, 0x17, 0xe3, 0xb1, 0x4b, 0x70,
+ 0x32, 0x3a, 0x60, 0xc9, 0xaf, 0x86, 0x31, 0x12, 0xc5, 0xee, 0xe7, 0xde,
+ 0xb1, 0x7e, 0x11, 0xad, 0x13, 0xac, 0x5f, 0xee, 0xbe, 0xe5, 0x02, 0xed,
+ 0x62, 0xfd, 0xd7, 0xe3, 0xb0, 0x8b, 0x17, 0x08, 0x2e, 0xb1, 0x7e, 0xfb,
+ 0xe8, 0xec, 0xb1, 0x78, 0x38, 0xdd, 0x58, 0xbf, 0x83, 0xeb, 0xf1, 0xd8,
+ 0x45, 0x8a, 0xda, 0x8c, 0x69, 0x16, 0xf4, 0x39, 0xc2, 0x81, 0x10, 0xde,
+ 0x62, 0xc5, 0x8b, 0xfb, 0xec, 0x17, 0xfc, 0x4e, 0xb1, 0x61, 0xc8, 0xf3,
+ 0xba, 0x1b, 0xbe, 0x83, 0xbf, 0x16, 0x2e, 0x01, 0x8b, 0x17, 0xf7, 0xe1,
+ 0xb7, 0x4e, 0xcb, 0x17, 0xfb, 0x74, 0x5a, 0xfc, 0x30, 0xd6, 0x2b, 0x6a,
+ 0x20, 0x3a, 0x19, 0x63, 0x0a, 0x9d, 0x55, 0xe8, 0xca, 0xbb, 0x87, 0xdb,
+ 0x42, 0x6f, 0xe5, 0x3e, 0x85, 0x15, 0xfd, 0x86, 0x66, 0x11, 0xab, 0x17,
+ 0x34, 0xeb, 0x17, 0x40, 0x6b, 0x17, 0x9f, 0x38, 0xb1, 0x7e, 0x79, 0xd8,
+ 0x52, 0x58, 0xbc, 0x00, 0x42, 0xc5, 0x48, 0xfe, 0x8e, 0x31, 0xf1, 0xc2,
+ 0x29, 0xbd, 0x84, 0x6a, 0xc5, 0x32, 0x63, 0x07, 0x2e, 0x78, 0x49, 0x04,
+ 0x3b, 0xbf, 0xf7, 0x35, 0x1e, 0x27, 0x39, 0xd9, 0x62, 0xff, 0xf4, 0x73,
+ 0x90, 0x7c, 0xf3, 0x73, 0xee, 0xb1, 0x79, 0x8b, 0xcb, 0x15, 0xd1, 0xf2,
+ 0xfd, 0x26, 0xff, 0xdf, 0x6f, 0xc6, 0x6a, 0x5a, 0x92, 0xc5, 0xff, 0xc7,
+ 0x8f, 0x71, 0xf3, 0x40, 0x3e, 0x2c, 0x5f, 0xc5, 0x12, 0x3c, 0x32, 0xc5,
+ 0x00, 0xfc, 0x09, 0x12, 0xfd, 0xf8, 0x9e, 0x3e, 0xb1, 0x7e, 0xd3, 0x9e,
+ 0x3a, 0x58, 0xbf, 0x66, 0xf2, 0xce, 0x2c, 0x5f, 0xef, 0x36, 0xf6, 0xf4,
+ 0xa1, 0x22, 0xc7, 0x58, 0xbf, 0xb0, 0x8d, 0xd4, 0x6c, 0xb1, 0xe3, 0x86,
+ 0x6b, 0x76, 0x1a, 0xb1, 0x5b, 0x55, 0x5b, 0xe4, 0x28, 0xfa, 0x23, 0x68,
+ 0x57, 0xcc, 0x42, 0xe5, 0x24, 0x53, 0xc7, 0x0d, 0xc4, 0x7b, 0xff, 0xcf,
+ 0xbe, 0x30, 0x6f, 0x2c, 0xfb, 0x18, 0xb1, 0x78, 0x5d, 0xc9, 0x62, 0xf4,
+ 0x14, 0x2c, 0x5f, 0x38, 0xe3, 0x75, 0x62, 0xf6, 0x9f, 0x7a, 0xc5, 0xf8,
+ 0x7a, 0xd6, 0x71, 0x62, 0xa4, 0x79, 0x0e, 0x3f, 0x52, 0x4c, 0x4f, 0x49,
+ 0x67, 0x1f, 0x00, 0xd9, 0x36, 0xdf, 0xe2, 0x91, 0x61, 0xe3, 0xa5, 0x8b,
+ 0xd3, 0x3f, 0x96, 0x2f, 0x14, 0x1d, 0x62, 0xa0, 0xdd, 0x4c, 0x3d, 0x7e,
+ 0x6f, 0x94, 0x49, 0x62, 0xfb, 0x4e, 0xd3, 0xac, 0x5d, 0xc6, 0x58, 0xa6,
+ 0x37, 0x4e, 0x47, 0x6c, 0x58, 0xbd, 0x98, 0x6a, 0xc5, 0x0c, 0xd7, 0x04,
+ 0x11, 0xbc, 0x4f, 0x25, 0x8a, 0x39, 0xbf, 0xf9, 0x1d, 0xff, 0xb8, 0x1e,
+ 0xbd, 0x26, 0x2f, 0x71, 0x62, 0xa1, 0x51, 0x3e, 0x25, 0x33, 0x6e, 0x88,
+ 0x7e, 0xc2, 0xf0, 0x8c, 0x11, 0x0d, 0xff, 0x36, 0xfc, 0xd7, 0x4e, 0xfd,
+ 0x2a, 0x30, 0xd2, 0xf6, 0xe0, 0xbc, 0xb1, 0x73, 0x6f, 0x58, 0xbf, 0xf7,
+ 0x5f, 0x82, 0x7f, 0x73, 0x27, 0x58, 0xbe, 0xd3, 0x4d, 0xc5, 0x8b, 0xda,
+ 0x70, 0xd6, 0x2b, 0x11, 0x05, 0xa4, 0x07, 0x24, 0xbb, 0x0d, 0x58, 0xbf,
+ 0xfa, 0x0e, 0xc3, 0xc2, 0x37, 0xf0, 0x75, 0x8a, 0xf9, 0xee, 0x78, 0x62,
+ 0xfb, 0x0f, 0x01, 0xac, 0x50, 0xd3, 0xd4, 0xe9, 0x24, 0xe4, 0x3c, 0x84,
+ 0xdf, 0xa1, 0x15, 0xbc, 0x8a, 0xe0, 0xfe, 0xb1, 0x7e, 0x27, 0x30, 0x33,
+ 0xac, 0x5f, 0x3f, 0x7e, 0xc5, 0x8b, 0x34, 0xc7, 0x9b, 0xc2, 0xaa, 0x35,
+ 0x11, 0xdf, 0x66, 0xbf, 0xfd, 0xef, 0xc7, 0x23, 0xf0, 0xd3, 0xc1, 0xab,
+ 0x17, 0xfc, 0x37, 0x3b, 0xca, 0x1b, 0xa5, 0x8a, 0x64, 0x42, 0x12, 0x5d,
+ 0xfe, 0xfc, 0x4d, 0x26, 0xd4, 0x96, 0x2f, 0xc5, 0x31, 0x41, 0xd6, 0x2f,
+ 0xf7, 0x98, 0xc9, 0x89, 0xcc, 0x58, 0xbb, 0xec, 0xb1, 0x7f, 0xd0, 0xf2,
+ 0xfc, 0x4e, 0xf3, 0xac, 0x5f, 0xf6, 0x6f, 0x81, 0xff, 0x1b, 0xcb, 0x17,
+ 0xb8, 0xe0, 0x58, 0xa2, 0x3d, 0x7f, 0x1d, 0x56, 0xea, 0x32, 0x4e, 0x2f,
+ 0xe8, 0x48, 0xdf, 0xc2, 0x0c, 0x00, 0x8e, 0xd6, 0x2e, 0x69, 0xd6, 0x2f,
+ 0x8f, 0xec, 0xe9, 0x62, 0xf6, 0x9e, 0x4b, 0x17, 0x77, 0x0b, 0x17, 0xfc,
+ 0xef, 0xdf, 0xda, 0x77, 0x25, 0x8b, 0x4f, 0x07, 0xa2, 0x31, 0x8a, 0x84,
+ 0x5d, 0x61, 0x23, 0x37, 0x5c, 0x67, 0x96, 0x2f, 0xa4, 0x02, 0xc5, 0x8b,
+ 0xff, 0xc0, 0x27, 0x3e, 0xb2, 0x3b, 0x93, 0x1d, 0x62, 0xa0, 0xfb, 0x04,
+ 0x45, 0x73, 0x4e, 0xb1, 0x50, 0xae, 0x8c, 0x64, 0x38, 0x6b, 0xd9, 0x43,
+ 0x43, 0xfe, 0x63, 0x8d, 0x18, 0xfe, 0x1a, 0x4e, 0x5a, 0x50, 0x85, 0xf1,
+ 0x0d, 0xff, 0xff, 0xfc, 0xde, 0xfe, 0x1f, 0xe5, 0x9b, 0xdf, 0xaf, 0xb0,
+ 0x7e, 0x62, 0xeb, 0x3d, 0xf6, 0x58, 0xba, 0x3e, 0xb1, 0x7d, 0xed, 0x46,
+ 0xf5, 0x8a, 0x1a, 0x31, 0xcf, 0x08, 0xb7, 0x17, 0xbf, 0x37, 0xb8, 0x2d,
+ 0xd5, 0x8b, 0xe8, 0xec, 0x5b, 0xab, 0x17, 0xff, 0xee, 0x85, 0xf3, 0x58,
+ 0xa3, 0xf0, 0x64, 0x16, 0x2c, 0x54, 0xc7, 0xfa, 0x44, 0xf7, 0xcc, 0x30,
+ 0x8c, 0xb1, 0x50, 0x99, 0x1f, 0xcd, 0x1e, 0x15, 0x26, 0x11, 0x5f, 0xf7,
+ 0xe2, 0x4c, 0x58, 0x78, 0x58, 0xbe, 0x71, 0xca, 0x75, 0x8b, 0xde, 0x36,
+ 0x75, 0x8b, 0xfe, 0xcf, 0x7f, 0x0e, 0x4f, 0xe5, 0x8b, 0xfb, 0x7b, 0x6b,
+ 0xb8, 0xdd, 0x58, 0xa9, 0xd1, 0x18, 0x32, 0x0c, 0x38, 0xaf, 0xa3, 0x80,
+ 0xa1, 0x61, 0x7f, 0x9b, 0xd1, 0xf7, 0x2f, 0x2c, 0x5f, 0xdb, 0xe3, 0x6f,
+ 0x7e, 0xd8, 0x96, 0x2a, 0x47, 0xd7, 0x86, 0x57, 0x10, 0x16, 0x2f, 0xc7,
+ 0x8e, 0xa7, 0x1a, 0xc5, 0xf4, 0xa0, 0xee, 0xb1, 0x7f, 0x0d, 0x85, 0xac,
+ 0xe9, 0x62, 0xfd, 0xa0, 0x1d, 0xb8, 0xb1, 0x77, 0xb9, 0xb5, 0x1b, 0xa1,
+ 0x52, 0x1c, 0x17, 0x72, 0xbe, 0x11, 0x06, 0x5f, 0x50, 0x9e, 0xb8, 0xa3,
+ 0x6f, 0xb7, 0x16, 0x2f, 0xe8, 0x9f, 0x09, 0x8d, 0x58, 0xad, 0x1e, 0x07,
+ 0x04, 0xaf, 0x9b, 0xa8, 0x3a, 0xc5, 0xff, 0x89, 0xff, 0x00, 0xd9, 0xd7,
+ 0x38, 0x91, 0x7b, 0xf8, 0x35, 0x8a, 0x83, 0xdf, 0x64, 0x2b, 0xe8, 0xf4,
+ 0x9d, 0x62, 0xff, 0xfc, 0xfe, 0x8c, 0xd4, 0x6d, 0x72, 0xc3, 0x8b, 0xeb,
+ 0x17, 0xdc, 0x11, 0x79, 0x62, 0xfc, 0x19, 0x4b, 0xf8, 0xb1, 0x4c, 0x79,
+ 0x80, 0x23, 0xba, 0x79, 0xd6, 0x2c, 0x05, 0x8b, 0x42, 0xc5, 0xb0, 0x66,
+ 0x8f, 0xa1, 0x2b, 0xe0, 0x8c, 0x47, 0x58, 0xa9, 0xd7, 0x61, 0xc7, 0x2b,
+ 0xbb, 0x1a, 0x74, 0x44, 0x78, 0x41, 0x7c, 0x80, 0x88, 0xbd, 0x0a, 0x11,
+ 0x10, 0xef, 0x3d, 0x08, 0x4f, 0x78, 0xf1, 0xd2, 0xc5, 0xff, 0x81, 0xcc,
+ 0x2c, 0x07, 0x23, 0x75, 0x62, 0xfc, 0xf3, 0x36, 0x71, 0x62, 0xfb, 0x91,
+ 0xa9, 0x2c, 0x56, 0xd3, 0xcb, 0xe1, 0x45, 0xcd, 0xc5, 0x8b, 0xdc, 0x89,
+ 0x2c, 0x54, 0x1b, 0x4e, 0xc5, 0xe8, 0x67, 0xf2, 0x75, 0x8a, 0x84, 0xd1,
+ 0x70, 0x79, 0xe3, 0x05, 0xbc, 0xff, 0x85, 0x8b, 0xfc, 0x3f, 0xc7, 0xbd,
+ 0x07, 0x58, 0xaf, 0x9e, 0x81, 0x0e, 0x5e, 0x6d, 0x49, 0x62, 0xd3, 0xac,
+ 0x57, 0xcd, 0x80, 0x87, 0x6f, 0xa0, 0x30, 0x83, 0x58, 0xbe, 0xe3, 0x7a,
+ 0x16, 0x2e, 0xee, 0x53, 0x9e, 0x47, 0x64, 0xd7, 0x9b, 0xbe, 0x2c, 0x56,
+ 0x1e, 0x7b, 0x18, 0xd6, 0x26, 0x52, 0xca, 0x3f, 0x85, 0xc5, 0xcd, 0x32,
+ 0xc5, 0xf6, 0xbd, 0x9f, 0x58, 0xbb, 0x3a, 0x58, 0xb7, 0x16, 0x3c, 0x5c,
+ 0x5f, 0x41, 0xdc, 0x6b, 0x17, 0xe1, 0xb6, 0xf8, 0x1a, 0xc5, 0x0c, 0xf3,
+ 0x34, 0x45, 0x58, 0x88, 0xf6, 0x6d, 0xbe, 0x9e, 0x50, 0x75, 0x8b, 0xde,
+ 0xcf, 0xac, 0x5f, 0x4f, 0xe6, 0x35, 0x62, 0xa1, 0x36, 0x96, 0x18, 0xd4,
+ 0x32, 0x9c, 0x84, 0x44, 0x81, 0x8e, 0xdf, 0xa6, 0x7f, 0xc7, 0xd6, 0x2f,
+ 0xff, 0x6d, 0x76, 0xce, 0x44, 0xf8, 0x4c, 0x6a, 0xc5, 0xdb, 0xe1, 0x62,
+ 0x86, 0x7c, 0x87, 0x4b, 0xbf, 0x8f, 0x1d, 0xf9, 0xfa, 0x58, 0xb9, 0xa7,
+ 0x58, 0xbf, 0x34, 0x9b, 0xb9, 0x2c, 0x56, 0x8f, 0xc7, 0xe6, 0x1c, 0x18,
+ 0xbf, 0xff, 0x8b, 0x3d, 0xfc, 0x96, 0x75, 0x1d, 0x78, 0x9c, 0xeb, 0x15,
+ 0x09, 0xd5, 0x64, 0x23, 0x5a, 0x12, 0x7c, 0x2f, 0xbf, 0xfd, 0xc7, 0xf7,
+ 0xdf, 0x85, 0x9e, 0xc0, 0x2c, 0x5f, 0xf3, 0x49, 0xb9, 0xdc, 0x98, 0x96,
+ 0x2f, 0xf0, 0x1a, 0x5a, 0xd3, 0x18, 0xb1, 0x5a, 0x3e, 0xe2, 0x39, 0xbe,
+ 0x63, 0xc4, 0xcb, 0x17, 0xff, 0x71, 0xbb, 0x2c, 0x9b, 0x51, 0xee, 0x2c,
+ 0x5f, 0x64, 0xe2, 0x92, 0xc5, 0xf3, 0x6a, 0x27, 0x58, 0xa9, 0x27, 0x10,
+ 0xd0, 0xb7, 0x98, 0x84, 0x04, 0x66, 0x23, 0x06, 0x49, 0x7e, 0x6e, 0x0b,
+ 0x0e, 0xb1, 0x7f, 0xe8, 0x94, 0x4d, 0xcf, 0xe6, 0xfe, 0x2c, 0x5f, 0xe8,
+ 0xd3, 0x91, 0x61, 0xab, 0x17, 0xd0, 0x16, 0x05, 0x81, 0x62, 0xc5, 0x71,
+ 0x14, 0xde, 0x42, 0x08, 0x65, 0x7c, 0xfa, 0x7e, 0xd6, 0x2f, 0xe0, 0x4e,
+ 0xf2, 0x8d, 0xd5, 0x8b, 0xf6, 0xd8, 0x9a, 0x0c, 0x58, 0xbc, 0x31, 0xc2,
+ 0xc5, 0xcc, 0x4b, 0x14, 0x6a, 0x2d, 0x3b, 0x23, 0x39, 0x90, 0x8b, 0x03,
+ 0x1d, 0xbd, 0x81, 0x24, 0xb1, 0x50, 0xa9, 0xff, 0xa5, 0xf6, 0x86, 0x73,
+ 0xc3, 0x98, 0x93, 0x6e, 0x89, 0xd6, 0x2f, 0xb5, 0x18, 0x75, 0x8b, 0xb0,
+ 0xc5, 0x8a, 0x4e, 0x21, 0x82, 0xfe, 0xe0, 0x71, 0xa8, 0x3a, 0x71, 0x0c,
+ 0x14, 0x9c, 0x43, 0x05, 0x27, 0x10, 0xc1, 0x49, 0xc4, 0x30, 0x52, 0x71,
+ 0x0c, 0x15, 0x24, 0x5f, 0xb0, 0xd0, 0x0f, 0x44, 0x35, 0xb8, 0x34, 0x10,
+ 0x6a, 0xef, 0xe2, 0x71, 0x0c, 0x17, 0xf3, 0xbf, 0xa6, 0x83, 0xa7, 0x10,
+ 0xc1, 0xb4, 0xd2, 0xd8, 0x2e, 0x9c, 0x43, 0x05, 0x27, 0x10, 0xc1, 0x49,
+ 0xc4, 0x30, 0x54, 0x8d, 0xa3, 0x0d, 0x52, 0x71, 0x0c, 0x14, 0x9c, 0x43,
+ 0x05, 0x27, 0x10, 0xc1, 0x49, 0xc4, 0x30, 0x52, 0x71, 0x0c, 0x14, 0x9c,
+ 0x43, 0x05, 0x4e, 0x89, 0xc1, 0x8d, 0x30, 0xd0, 0x06, 0xb8, 0x35, 0xbc,
+ 0x6a, 0x93, 0x88, 0x60, 0xa4, 0xe2, 0x18, 0x2a, 0x46, 0xd3, 0x83, 0x54,
+ 0x9c, 0x43, 0x05, 0x27, 0x10, 0xc1, 0x49, 0xc4, 0x30, 0x52, 0x71, 0x0c,
+ 0x15, 0x23, 0xe8, 0x00, 0xd7, 0x86, 0x82, 0x0d, 0x52, 0x71, 0x0c, 0x14,
+ 0x9c, 0x43, 0x05, 0x27, 0x10, 0xc1, 0x49, 0xc4, 0x30, 0x54, 0xe7, 0xd0,
+ 0x68, 0xd6, 0x86, 0xbe, 0x35, 0x63, 0x53, 0x88, 0x60, 0xa4, 0xe2, 0x18,
+ 0x29, 0x38, 0x86, 0x0a, 0x4e, 0x21, 0x82, 0x93, 0x88, 0x60, 0xa1, 0x9f,
+ 0x47, 0x63, 0x40, 0x1a, 0x10, 0xd5, 0x27, 0x10, 0xc1, 0x49, 0xc4, 0x30,
+ 0x52, 0x71, 0x0c, 0x17, 0xef, 0xc0, 0x39, 0x89, 0xc4, 0x30, 0x52, 0x71,
+ 0x0c, 0x15, 0x24, 0x4f, 0x74, 0x35, 0xf1, 0xa7, 0x1a, 0x01, 0xb5, 0xba,
+ 0x4e, 0x21, 0x82, 0x93, 0x88, 0x60, 0xa4, 0xe2, 0x18, 0x29, 0x38, 0x86,
+ 0x0a, 0x4e, 0x21, 0x82, 0xa4, 0x7d, 0x1d, 0x8d, 0x30, 0xd6, 0xf1, 0xaa,
+ 0x4e, 0x21, 0x82, 0x93, 0x88, 0x60, 0xa4, 0xe2, 0x18, 0x29, 0x38, 0x86,
+ 0x0a, 0x91, 0xf4, 0x0c, 0x6b, 0xe3, 0x44, 0x35, 0x6f, 0xa7, 0x10, 0xc1,
+ 0x49, 0xc4, 0x30, 0x52, 0x71, 0x0c, 0x16, 0x92, 0x71, 0x0c, 0x14, 0x9c,
+ 0x43, 0x07, 0x66, 0x82, 0x93, 0x88, 0x60, 0xa4, 0xe2, 0x18, 0x29, 0x38,
+ 0x86, 0x0a, 0x4e, 0x21, 0x82, 0xa7, 0x47, 0x3c, 0x86, 0x8d, 0x3a, 0xe8,
+ 0xae, 0x61, 0xa0, 0x0d, 0x78, 0x6a, 0xd8, 0x9c, 0x43, 0x05, 0x27, 0x10,
+ 0xc1, 0x49, 0xc4, 0x30, 0x5a, 0x49, 0xc4, 0x30, 0x52, 0x71, 0x0c, 0x1d,
+ 0x9a, 0x0a, 0x4e, 0x21, 0x82, 0x93, 0x88, 0x60, 0xa8, 0x45, 0x9c, 0x86,
+ 0x98, 0xeb, 0x45, 0x67, 0x1a, 0xa4, 0xe2, 0x18, 0x29, 0x38, 0x86, 0x0a,
+ 0x4e, 0x21, 0x82, 0x93, 0x88, 0x60, 0xa4, 0xe2, 0x18, 0x2a, 0x11, 0x05,
+ 0xd8, 0xd6, 0x86, 0x8e, 0x34, 0x43, 0x54, 0x9c, 0x43, 0x05, 0x27, 0x10,
+ 0xc1, 0x49, 0xc4, 0x30, 0x56, 0x8f, 0x3b, 0x83, 0x5e, 0x1a, 0xa4, 0xe2,
+ 0x18, 0x29, 0x38, 0x86, 0x0a, 0x4e, 0x21, 0x82, 0x8e, 0x79, 0xc4, 0x35,
+ 0xe1, 0xab, 0x1d, 0x38, 0x86, 0x0a, 0x4e, 0x21, 0x82, 0x93, 0x88, 0x60,
+ 0xa0, 0x1b, 0x41, 0x0d, 0x52, 0x71, 0x0c, 0x14, 0x9c, 0x43, 0x05, 0x27,
+ 0x10, 0xc1, 0x49, 0xc4, 0x30, 0x54, 0x1f, 0x44, 0xc3, 0x5f, 0x1a, 0x10,
+ 0xd5, 0x43, 0x31, 0x6a, 0x78, 0x40, 0x49, 0x38, 0x6b, 0x19, 0x0b, 0xce,
+ 0xa1, 0x1b, 0xdc, 0x22, 0x5a, 0x14, 0xdb, 0xa7, 0xd3, 0x42, 0x27, 0x50,
+ 0xdb, 0x3a, 0x57, 0xe1, 0x12, 0xf0, 0xa6, 0x01, 0xd9, 0x46, 0x0f, 0xc6,
+ 0x8f, 0x43, 0x48, 0x50, 0xca, 0xdf, 0x09, 0x73, 0x1f, 0x77, 0x0b, 0x83,
+ 0x54, 0x09, 0x08, 0x9b, 0xf4, 0x8a, 0x33, 0x89, 0xc4, 0x30, 0x6c, 0xa7,
+ 0x2f, 0x79, 0xa0, 0xe9, 0xc4, 0x30, 0x5f, 0x37, 0x4f, 0xa5, 0xe2, 0x18,
+ 0x5e, 0x61, 0xe2, 0xf1, 0x0c, 0x2d, 0xb3, 0xda, 0x33, 0xb4, 0x97, 0xf2,
+ 0xaf, 0x18, 0x56, 0xf6, 0x7e, 0xe8, 0x74, 0xf9, 0x6b, 0xc1, 0xc1, 0x8b,
+ 0x15, 0x07, 0xa4, 0xe6, 0x77, 0x98, 0xa7, 0x58, 0xbf, 0x98, 0xc1, 0xea,
+ 0x27, 0x58, 0xa9, 0x1e, 0x6f, 0xc7, 0x6e, 0xdf, 0x0b, 0x17, 0x3f, 0x6b,
+ 0x17, 0xd2, 0x6f, 0x89, 0x62, 0xfa, 0x37, 0x23, 0xcb, 0x17, 0x9b, 0x78,
+ 0x5d, 0x62, 0xfe, 0xe4, 0x1d, 0xfb, 0xf2, 0xc5, 0xcc, 0x11, 0x62, 0x86,
+ 0xd8, 0xee, 0x74, 0x31, 0xdd, 0x60, 0xa3, 0x33, 0x69, 0xc8, 0xbe, 0x32,
+ 0xe3, 0x04, 0x47, 0xe2, 0x53, 0x08, 0xc2, 0x17, 0xde, 0xf8, 0xe4, 0xb1,
+ 0x7a, 0x67, 0x0d, 0x62, 0x86, 0x6f, 0x70, 0x7a, 0xfc, 0xc4, 0x27, 0xf2,
+ 0xc5, 0xff, 0xff, 0xb3, 0x08, 0x5e, 0x6f, 0x90, 0x8d, 0x2c, 0xef, 0xd1,
+ 0x9a, 0x58, 0xac, 0x45, 0x97, 0x08, 0x37, 0x09, 0xef, 0x7c, 0x5d, 0x2c,
+ 0x5f, 0x7f, 0x37, 0xe2, 0xc5, 0x7c, 0xf0, 0xfc, 0x3f, 0x78, 0x02, 0xe2,
+ 0xc5, 0xfe, 0x72, 0x0e, 0x69, 0x31, 0x2c, 0x5f, 0xfd, 0xc7, 0x20, 0x7f,
+ 0x26, 0x82, 0x1a, 0xc5, 0xc0, 0x85, 0x8b, 0xfb, 0x4e, 0x41, 0xc0, 0x16,
+ 0x2e, 0x7d, 0x2c, 0x59, 0x96, 0x3a, 0x2d, 0xed, 0xd2, 0xc5, 0x8e, 0xb1,
+ 0x6d, 0x96, 0x45, 0x16, 0x85, 0xfe, 0x8a, 0xe4, 0x21, 0x89, 0xdf, 0xdd,
+ 0xcb, 0xf0, 0x53, 0xac, 0x51, 0xd3, 0x9c, 0x01, 0xa6, 0xe4, 0x39, 0x82,
+ 0x29, 0x5f, 0xff, 0xfb, 0x25, 0xf8, 0xfb, 0x1a, 0xec, 0x51, 0xf7, 0x69,
+ 0x30, 0xd6, 0x2e, 0x96, 0x2c, 0x58, 0xeb, 0x17, 0xf3, 0x6b, 0xa7, 0xd4,
+ 0xeb, 0x17, 0xee, 0xbf, 0x02, 0x0b, 0xac, 0x5f, 0x85, 0xef, 0xe6, 0xf5,
+ 0x8a, 0x0a, 0xa2, 0x6e, 0x61, 0x2d, 0x18, 0x11, 0x75, 0xed, 0x34, 0xeb,
+ 0x17, 0xfa, 0x0f, 0x93, 0x41, 0x4e, 0xb1, 0x4b, 0x17, 0x0f, 0x7a, 0xc5,
+ 0xfb, 0x0f, 0xa7, 0x92, 0xc5, 0x62, 0x38, 0x74, 0x83, 0xf1, 0xe0, 0x1a,
+ 0x10, 0x66, 0xe0, 0xd5, 0xf1, 0xff, 0x00, 0x58, 0xbf, 0xfd, 0x83, 0xdc,
+ 0xd4, 0x6f, 0x6f, 0x73, 0x0d, 0x58, 0xbf, 0xd1, 0xd0, 0x60, 0x04, 0x76,
+ 0xb1, 0x58, 0x8a, 0xaf, 0x91, 0xf1, 0x42, 0xff, 0xed, 0xaf, 0xd0, 0xff,
+ 0x00, 0xc2, 0x02, 0xc5, 0xff, 0xb3, 0x98, 0x20, 0xbb, 0x9b, 0xfc, 0x58,
+ 0xb8, 0x10, 0xb1, 0x58, 0x8a, 0x1e, 0x91, 0xc0, 0x87, 0x50, 0xbc, 0x45,
+ 0x22, 0x2c, 0x8e, 0xe9, 0x92, 0x26, 0x69, 0x04, 0x72, 0x7e, 0x8c, 0x08,
+ 0x50, 0xd0, 0xbf, 0x4b, 0x06, 0xe7, 0x58, 0xbe, 0x89, 0x72, 0x16, 0x2f,
+ 0xfe, 0x22, 0x89, 0xcb, 0x1b, 0x7c, 0x6e, 0x2c, 0x5e, 0x8e, 0xf8, 0xb1,
+ 0x50, 0x8a, 0xf3, 0x94, 0x39, 0x17, 0x11, 0xef, 0x3e, 0xa1, 0x62, 0xfb,
+ 0x71, 0xc8, 0x0b, 0x17, 0xde, 0xe6, 0x79, 0x62, 0x98, 0xf2, 0x1c, 0x96,
+ 0xfc, 0xdd, 0xf1, 0xfb, 0x58, 0xa9, 0x22, 0xb8, 0xec, 0x9c, 0x20, 0xbe,
+ 0xde, 0x78, 0x65, 0x8b, 0xf4, 0xcc, 0x77, 0x99, 0x62, 0xff, 0xde, 0xfb,
+ 0xc8, 0x9f, 0xf9, 0xc5, 0x8b, 0x8e, 0xeb, 0x17, 0xff, 0xe2, 0x7f, 0x16,
+ 0x7b, 0xe2, 0xef, 0x0e, 0xfd, 0xac, 0x56, 0x22, 0xad, 0x8f, 0x9c, 0x5e,
+ 0xfc, 0x42, 0x7e, 0xe4, 0xb1, 0x7c, 0xe1, 0xb6, 0x2c, 0x5b, 0x8c, 0x79,
+ 0x62, 0x29, 0xbf, 0x9a, 0x78, 0xef, 0x09, 0x62, 0xfc, 0xdd, 0xf3, 0x6b,
+ 0x76, 0x7a, 0xba, 0x27, 0xbf, 0xe0, 0xdc, 0x7c, 0xc3, 0xc6, 0xea, 0xc5,
+ 0xec, 0xec, 0xc5, 0x8a, 0xd1, 0xee, 0x11, 0xed, 0xfe, 0xcc, 0x29, 0x06,
+ 0x43, 0x58, 0xb0, 0x30, 0xf5, 0x26, 0x21, 0xbf, 0xfc, 0xdb, 0xa2, 0x35,
+ 0xbb, 0xe6, 0x4d, 0x1e, 0x58, 0xb6, 0xea, 0xc5, 0x74, 0x9b, 0xff, 0x70,
+ 0xf2, 0x39, 0x43, 0xa8, 0x5d, 0xf7, 0x58, 0xbf, 0xf3, 0xff, 0x0e, 0xff,
+ 0xce, 0xc0, 0xb1, 0x7f, 0xdf, 0xc3, 0xbf, 0xf3, 0xb0, 0x2c, 0x58, 0x1b,
+ 0x4f, 0xe5, 0xcf, 0xea, 0x11, 0x72, 0xf0, 0x90, 0xb8, 0x50, 0xb1, 0x7b,
+ 0x35, 0x25, 0x8a, 0x19, 0xb4, 0xde, 0x2f, 0x78, 0x6e, 0x4b, 0x14, 0xc6,
+ 0xfd, 0xc8, 0xef, 0xba, 0x72, 0x35, 0x62, 0xff, 0xff, 0xda, 0xf6, 0x14,
+ 0x74, 0x50, 0x7e, 0x73, 0x25, 0xf6, 0x20, 0x2c, 0x54, 0x22, 0x3d, 0xc9,
+ 0x2f, 0xfe, 0x7d, 0x69, 0xc1, 0x1b, 0x26, 0x18, 0x62, 0xc5, 0xe9, 0x30,
+ 0x16, 0x2f, 0xfc, 0x6e, 0x77, 0xe6, 0xf6, 0x84, 0x75, 0x8a, 0xda, 0x8a,
+ 0xa7, 0x4b, 0xf0, 0xed, 0xd1, 0x25, 0x8a, 0x83, 0xc8, 0x01, 0x8d, 0x42,
+ 0xf7, 0x6e, 0x18, 0x31, 0x27, 0xe1, 0xaa, 0xf2, 0x93, 0x0a, 0x1f, 0xbc,
+ 0x84, 0xcf, 0xa1, 0x5c, 0x28, 0xc4, 0xef, 0xee, 0x9c, 0x5d, 0x1d, 0x96,
+ 0x2f, 0xec, 0x8e, 0xe4, 0xc7, 0x58, 0xbf, 0x64, 0xd2, 0x72, 0x58, 0xbc,
+ 0x52, 0xe6, 0x8f, 0x58, 0x32, 0xeb, 0xc3, 0xcf, 0x2c, 0x5e, 0x3f, 0xdd,
+ 0x62, 0x98, 0xfb, 0x9c, 0xd0, 0x43, 0xb7, 0xff, 0x16, 0x37, 0xe3, 0xb0,
+ 0x67, 0xb8, 0xb1, 0x7f, 0xf0, 0x83, 0x9b, 0x6c, 0x06, 0xfd, 0x47, 0xd6,
+ 0x2e, 0x23, 0x56, 0x2f, 0xfe, 0x03, 0xcb, 0x99, 0x2f, 0xc1, 0x1a, 0xb1,
+ 0x7f, 0x1f, 0x98, 0x78, 0xdd, 0x58, 0xa8, 0x3f, 0x66, 0x45, 0xbf, 0xcc,
+ 0x6f, 0x18, 0xbb, 0x92, 0xc5, 0xa3, 0x47, 0xab, 0xf2, 0x0a, 0x64, 0xc2,
+ 0x82, 0x43, 0x8e, 0xb6, 0xbe, 0x6c, 0xa0, 0x54, 0x8e, 0x25, 0x6f, 0xcf,
+ 0x1c, 0x0c, 0xa5, 0x7d, 0x0e, 0x5e, 0x3e, 0x4a, 0x3b, 0x36, 0x1e, 0x7d,
+ 0x4e, 0x25, 0xf7, 0x2a, 0x41, 0xa7, 0x72, 0x77, 0x63, 0xf4, 0x9a, 0x3a,
+ 0xdd, 0x47, 0x3a, 0x79, 0x40, 0xbf, 0x9c, 0x4c, 0x7a, 0xc8, 0xbc, 0x11,
+ 0xcd, 0x14, 0xf4, 0xbf, 0x23, 0x38, 0xf4, 0xfe, 0xb0, 0xa1, 0x3b, 0xbe,
+ 0x1e, 0x9b, 0x85, 0xa1, 0xa2, 0x04, 0x8d, 0x56, 0xff, 0xb9, 0xef, 0x89,
+ 0xe5, 0x28, 0x58, 0xbc, 0x09, 0xf1, 0x62, 0xff, 0x6a, 0x3c, 0xc0, 0x89,
+ 0x2c, 0x5f, 0xef, 0x48, 0x43, 0x72, 0x02, 0xc5, 0xe3, 0xf3, 0xa5, 0x8b,
+ 0xc5, 0xd4, 0x2c, 0x5f, 0x67, 0x9f, 0xb5, 0x8a, 0xda, 0x7b, 0xec, 0x3f,
+ 0xa1, 0xdb, 0xff, 0xb9, 0x9d, 0x0f, 0x34, 0x63, 0xfe, 0x65, 0x8b, 0xfe,
+ 0xe1, 0xae, 0x51, 0x93, 0xc2, 0xc5, 0xf4, 0xb3, 0x50, 0xb1, 0x7f, 0x18,
+ 0xfa, 0xd3, 0xf6, 0xb1, 0x7f, 0xfe, 0xe6, 0xb4, 0xd3, 0x73, 0x51, 0xe6,
+ 0xe9, 0x86, 0xb1, 0x52, 0x54, 0x43, 0xd1, 0x99, 0xe1, 0x27, 0xf3, 0x07,
+ 0x48, 0x01, 0xc9, 0x11, 0x18, 0x61, 0x78, 0x9a, 0x65, 0x8b, 0xa5, 0x3a,
+ 0xc5, 0xfa, 0x37, 0x38, 0x22, 0x58, 0xbd, 0xe8, 0xe2, 0xc5, 0xf6, 0x1e,
+ 0x3e, 0xb1, 0x62, 0x58, 0xbf, 0x0f, 0x30, 0x1c, 0x58, 0xad, 0xc3, 0x72,
+ 0x18, 0x8d, 0x74, 0x88, 0x00, 0x2d, 0xdf, 0xfb, 0x9b, 0x5f, 0xa8, 0x98,
+ 0x4f, 0xda, 0xc5, 0x76, 0x9a, 0x4c, 0xc3, 0x27, 0x2b, 0x28, 0x4e, 0xf8,
+ 0x92, 0xf4, 0xec, 0x35, 0x8b, 0x09, 0x62, 0xc0, 0x63, 0x60, 0x43, 0xd7,
+ 0x81, 0xee, 0x2c, 0x58, 0x2a, 0xb1, 0x7f, 0x73, 0xf3, 0x40, 0x04, 0xb1,
+ 0x7d, 0xa6, 0x23, 0x56, 0x2e, 0xf7, 0x16, 0x2f, 0xd8, 0x59, 0xd9, 0x8b,
+ 0x17, 0xe1, 0x75, 0xf6, 0xd2, 0xc5, 0xd8, 0x6a, 0xc5, 0xbc, 0x15, 0x3e,
+ 0xb8, 0x29, 0xe1, 0x55, 0xfd, 0x9d, 0x7e, 0x3b, 0x92, 0xc5, 0xfc, 0x7e,
+ 0x31, 0xbe, 0x31, 0x62, 0xfb, 0xbf, 0xc4, 0x96, 0x2e, 0x2e, 0x96, 0x2a,
+ 0x0d, 0xe3, 0x92, 0x56, 0xd4, 0xff, 0xb6, 0x21, 0xee, 0xc5, 0xb4, 0x60,
+ 0x02, 0x32, 0x84, 0x1f, 0x8e, 0x03, 0x30, 0x08, 0xdb, 0x7f, 0xfe, 0x62,
+ 0xeb, 0xaf, 0xbf, 0x5f, 0x86, 0xd0, 0xb7, 0x56, 0x2f, 0xbd, 0xec, 0x9d,
+ 0x62, 0xd0, 0xb1, 0x58, 0x6d, 0x58, 0x92, 0xff, 0xa3, 0x9c, 0xcf, 0x73,
+ 0x27, 0x58, 0xb7, 0x64, 0x7b, 0x21, 0x8f, 0xdf, 0xd1, 0xdc, 0xb0, 0x24,
+ 0x96, 0x2b, 0x0f, 0x68, 0xe5, 0x37, 0xff, 0x9c, 0xf8, 0x3e, 0xfd, 0xa8,
+ 0xce, 0xce, 0xb1, 0x77, 0x7e, 0x58, 0xbf, 0x61, 0x4e, 0xda, 0x58, 0xbf,
+ 0x79, 0xc8, 0x58, 0xb1, 0x7f, 0xb9, 0x87, 0x6f, 0x7d, 0xd6, 0x2a, 0x48,
+ 0xe7, 0xc4, 0xcd, 0x0c, 0x91, 0x47, 0x89, 0xef, 0xe8, 0x17, 0xbe, 0xe0,
+ 0x58, 0xbd, 0xf8, 0x1a, 0xc5, 0x68, 0xf2, 0xf8, 0x5d, 0x7d, 0x2d, 0x10,
+ 0x96, 0x2a, 0x47, 0x8b, 0xd9, 0x15, 0x42, 0x3e, 0xde, 0x1b, 0x17, 0xb6,
+ 0x9d, 0x96, 0x2f, 0xb5, 0x1e, 0xe2, 0xc5, 0xe1, 0x61, 0x2c, 0x5b, 0x26,
+ 0x37, 0xfe, 0x23, 0xbf, 0x7d, 0x8a, 0x0e, 0xb1, 0x63, 0xac, 0x56, 0x1b,
+ 0x92, 0x27, 0xa9, 0x23, 0x74, 0x97, 0xb8, 0xc1, 0x78, 0x26, 0xa1, 0x62,
+ 0xff, 0xc5, 0x0f, 0x3f, 0x33, 0x7c, 0x18, 0xb1, 0x7f, 0xdf, 0x6d, 0x7d,
+ 0xc2, 0xa6, 0x18, 0xb1, 0x7f, 0xde, 0xd4, 0x67, 0x61, 0x6b, 0x62, 0x0a,
+ 0xac, 0x5f, 0xfe, 0x27, 0x33, 0x85, 0x9d, 0xcb, 0xc2, 0x9d, 0x62, 0xfe,
+ 0x69, 0x8b, 0x37, 0xba, 0xc5, 0xdc, 0x65, 0x8a, 0xd1, 0xe3, 0x70, 0xbe,
+ 0xfb, 0xa7, 0xe9, 0xd6, 0x2f, 0xf6, 0x14, 0xb3, 0x8f, 0xf5, 0x8b, 0xff,
+ 0xda, 0x34, 0xc7, 0x9c, 0xb3, 0x7e, 0x9b, 0x8b, 0x16, 0xe6, 0xd5, 0x4e,
+ 0x70, 0x5e, 0x31, 0xfc, 0x41, 0xed, 0x02, 0x64, 0xad, 0x42, 0x4d, 0xc8,
+ 0xbc, 0x48, 0x19, 0x95, 0xa1, 0x62, 0xfd, 0x83, 0xfe, 0x12, 0xc5, 0xb5,
+ 0x39, 0xb8, 0x21, 0x1b, 0xe3, 0xe9, 0x8d, 0x58, 0xbc, 0x42, 0xc5, 0x8a,
+ 0x63, 0xc0, 0x72, 0x4b, 0xee, 0x72, 0x0e, 0xb1, 0x7d, 0x13, 0x46, 0x96,
+ 0x28, 0x67, 0x8d, 0xe2, 0x3b, 0xff, 0xfe, 0x9b, 0x98, 0x3c, 0xef, 0xdf,
+ 0x79, 0x9d, 0xf5, 0xe1, 0x3a, 0xc5, 0x76, 0xa8, 0xa9, 0xe1, 0xa4, 0x06,
+ 0x72, 0x66, 0xf1, 0x15, 0xfc, 0xf3, 0xfe, 0x34, 0x05, 0x8b, 0xe9, 0x71,
+ 0x86, 0xb1, 0x62, 0x83, 0xd2, 0x72, 0xfb, 0xfc, 0xda, 0x2f, 0x7b, 0x27,
+ 0x58, 0xbe, 0xf4, 0xf8, 0x62, 0xc5, 0xed, 0xcc, 0x02, 0xc5, 0xcf, 0xbd,
+ 0x62, 0xfe, 0x91, 0x34, 0xbf, 0x8b, 0x17, 0xe9, 0xdb, 0x51, 0x25, 0x8a,
+ 0x35, 0x1d, 0x1d, 0x9a, 0x31, 0x2c, 0xc4, 0x1a, 0x19, 0x22, 0xdb, 0xde,
+ 0x63, 0x56, 0x2f, 0xf3, 0xbc, 0xfa, 0x87, 0xe9, 0x62, 0xfc, 0x2f, 0x6e,
+ 0x67, 0x96, 0x2f, 0x0d, 0x8d, 0x58, 0xa8, 0x3c, 0xac, 0x2c, 0xbf, 0x9f,
+ 0xe1, 0xe9, 0xc0, 0xb1, 0x7b, 0x40, 0x0d, 0x62, 0xff, 0xe6, 0xf4, 0x7b,
+ 0x9f, 0x76, 0xf8, 0x96, 0x2a, 0x0f, 0x8d, 0xc7, 0xef, 0x88, 0x85, 0x25,
+ 0x8b, 0xdc, 0x63, 0x16, 0x2f, 0xf1, 0x0b, 0x98, 0x78, 0xe9, 0x62, 0xff,
+ 0xdf, 0x8d, 0x00, 0xb0, 0xc7, 0x02, 0xc5, 0xec, 0xc9, 0x96, 0x2f, 0xfd,
+ 0xe7, 0x07, 0x06, 0x27, 0xd4, 0x96, 0x28, 0xd4, 0x68, 0x7c, 0xd0, 0x07,
+ 0xfe, 0x1d, 0xbe, 0xf0, 0x22, 0x4b, 0x15, 0x87, 0xc2, 0x23, 0xeb, 0xff,
+ 0x7c, 0x5e, 0x0f, 0xde, 0xc2, 0x02, 0xc5, 0xe8, 0xec, 0xc5, 0x8b, 0xf6,
+ 0x84, 0x77, 0x25, 0x8a, 0xc4, 0x44, 0x79, 0x04, 0x43, 0xf7, 0xc7, 0x8c,
+ 0x9d, 0x62, 0xfb, 0x79, 0x47, 0x6b, 0x17, 0x19, 0xe5, 0x8a, 0xc3, 0x7c,
+ 0xc4, 0xb4, 0xc8, 0x80, 0xe3, 0x0d, 0xf4, 0x17, 0xba, 0x58, 0xbf, 0x68,
+ 0xd9, 0xdf, 0x75, 0x62, 0x86, 0xbc, 0x1f, 0x91, 0x86, 0xb2, 0xc4, 0xc3,
+ 0xda, 0x7e, 0x39, 0x07, 0xe1, 0x24, 0xe4, 0x00, 0x22, 0x28, 0xd3, 0xf9,
+ 0x0a, 0x9f, 0x42, 0xbf, 0x70, 0x88, 0x32, 0x3b, 0xf6, 0xe7, 0xf0, 0x0e,
+ 0xb1, 0x7f, 0x80, 0x1e, 0x10, 0xff, 0x0b, 0x15, 0x09, 0x9e, 0x9e, 0x1b,
+ 0xce, 0x57, 0x7c, 0x76, 0xfc, 0x2c, 0x5e, 0x8d, 0x01, 0x62, 0xdc, 0xc3,
+ 0x7e, 0x19, 0x15, 0xee, 0xe5, 0xc5, 0x8b, 0xfb, 0xef, 0xe3, 0x33, 0xeb,
+ 0x15, 0xd9, 0xfa, 0xe8, 0x9c, 0xc1, 0xfb, 0xdc, 0x01, 0x8b, 0x17, 0xdd,
+ 0xf2, 0x3b, 0x58, 0xbf, 0x4b, 0xdc, 0x83, 0x56, 0x2f, 0xfe, 0x8d, 0x44,
+ 0xc4, 0xe6, 0x7b, 0x3e, 0xb1, 0x4e, 0x7d, 0xe4, 0x55, 0x7f, 0xf7, 0xf0,
+ 0xa0, 0x1c, 0xfc, 0x17, 0x96, 0x2d, 0x26, 0x47, 0xb9, 0xe1, 0x29, 0xe2,
+ 0x0a, 0x84, 0xe0, 0x70, 0xc5, 0xe3, 0x16, 0xbf, 0xe3, 0x0b, 0x35, 0xcf,
+ 0xe7, 0x4b, 0x17, 0xff, 0x16, 0x73, 0x07, 0x34, 0xa3, 0x53, 0xac, 0x53,
+ 0x22, 0x07, 0xc7, 0x77, 0xf1, 0xbe, 0x28, 0x3f, 0x16, 0x2f, 0xb0, 0x6c,
+ 0x4b, 0x17, 0xf1, 0x67, 0x89, 0xc0, 0xb1, 0x7c, 0x23, 0x72, 0x75, 0x8b,
+ 0xcf, 0xa9, 0x2c, 0x57, 0xcf, 0x08, 0x44, 0xb7, 0xd0, 0x20, 0xbf, 0x12,
+ 0x2f, 0xd2, 0xd9, 0x30, 0xc3, 0x16, 0x28, 0x8f, 0x5c, 0x44, 0xf7, 0xd2,
+ 0xf3, 0x01, 0x62, 0xfe, 0x76, 0xe7, 0xf3, 0xcb, 0x17, 0xed, 0xc7, 0x9f,
+ 0xec, 0xb1, 0x7f, 0xfd, 0xf6, 0x34, 0xd8, 0xf7, 0x20, 0x8b, 0x3c, 0xb1,
+ 0x7c, 0x58, 0x78, 0x58, 0xbf, 0xd1, 0xe7, 0x03, 0xe6, 0x96, 0x2d, 0xe5,
+ 0x8b, 0xff, 0x37, 0x1b, 0x7e, 0xa0, 0x37, 0x25, 0x8a, 0xc3, 0xd2, 0x71,
+ 0x2b, 0xfd, 0xf7, 0x3f, 0xb9, 0x18, 0xb1, 0x79, 0xbb, 0x02, 0xc5, 0xfc,
+ 0x4e, 0x03, 0x33, 0xeb, 0x17, 0xfb, 0xc5, 0x80, 0x72, 0x06, 0x8f, 0x33,
+ 0xc3, 0xd7, 0x17, 0x5b, 0x55, 0x04, 0x74, 0x58, 0xca, 0x07, 0x21, 0xfc,
+ 0x21, 0x3c, 0x40, 0x1b, 0xfd, 0xef, 0x1f, 0xcb, 0x17, 0xe1, 0x31, 0x37,
+ 0x16, 0x29, 0xcf, 0x17, 0x83, 0xd7, 0xee, 0x6a, 0x1f, 0xa5, 0x8b, 0xf4,
+ 0x17, 0x51, 0xbd, 0x62, 0xb0, 0xf4, 0xfe, 0x53, 0x5b, 0x57, 0x35, 0x64,
+ 0x42, 0x36, 0xec, 0x79, 0xec, 0x87, 0xe4, 0x6f, 0x28, 0xd4, 0x10, 0xbf,
+ 0xf3, 0xa5, 0xfe, 0x01, 0x66, 0xfd, 0x37, 0x16, 0x2e, 0x61, 0xac, 0x5f,
+ 0xc4, 0x4e, 0x63, 0xfd, 0x62, 0xba, 0x3c, 0x40, 0xc5, 0xeb, 0x6b, 0xa1,
+ 0xcc, 0x0a, 0x9d, 0x44, 0xa3, 0xf9, 0x3c, 0x64, 0x6c, 0xdd, 0xc2, 0x05,
+ 0xa5, 0x11, 0xee, 0xc2, 0x3b, 0x51, 0xa1, 0x9e, 0x50, 0x1b, 0xce, 0xd0,
+ 0x02, 0x7f, 0xb8, 0xa5, 0x34, 0xf2, 0x16, 0xbe, 0x22, 0x14, 0xe8, 0x26,
+ 0xf8, 0x47, 0x18, 0xf3, 0x7c, 0x00, 0xe0, 0x0b, 0x17, 0xb6, 0x3d, 0x86,
+ 0x15, 0x58, 0xbd, 0x22, 0x75, 0x8b, 0xfd, 0xe8, 0x3f, 0x72, 0xcf, 0x2c,
+ 0x5e, 0xfb, 0x01, 0x62, 0xff, 0xe9, 0xdf, 0x77, 0xaf, 0xb7, 0x51, 0xee,
+ 0x2c, 0x56, 0xc6, 0x8e, 0x68, 0x2d, 0xc1, 0xc9, 0x8d, 0x78, 0x3b, 0x50,
+ 0x9a, 0xc7, 0x71, 0x85, 0x5c, 0xc1, 0x16, 0x2f, 0xc1, 0x22, 0x5a, 0x85,
+ 0x8b, 0xff, 0x77, 0x37, 0xbf, 0x1e, 0xe7, 0xd9, 0x62, 0xf7, 0xd8, 0xeb,
+ 0x17, 0x38, 0x16, 0x2a, 0x0f, 0xd9, 0xd0, 0xbc, 0x3b, 0x7e, 0xd4, 0xf1,
+ 0xa9, 0xd6, 0x2f, 0xec, 0xf7, 0x04, 0x5e, 0x58, 0xbf, 0x31, 0x78, 0x33,
+ 0xac, 0x5e, 0x7d, 0x71, 0x62, 0xa1, 0x13, 0xf8, 0x56, 0x02, 0xef, 0x14,
+ 0xdf, 0xfa, 0x0b, 0xdf, 0x13, 0xca, 0x50, 0xb1, 0x7b, 0x42, 0xdd, 0x58,
+ 0xb9, 0xa6, 0x58, 0xa6, 0x37, 0x24, 0x43, 0x69, 0xd6, 0x2f, 0x8e, 0xde,
+ 0xd8, 0x16, 0x2f, 0xa3, 0xec, 0x6a, 0xc5, 0x61, 0xe5, 0xe8, 0xa2, 0xff,
+ 0x07, 0xe6, 0x28, 0xee, 0x4b, 0x16, 0xc5, 0x8a, 0x91, 0xe3, 0x6f, 0x35,
+ 0xbf, 0xf6, 0x77, 0xe3, 0x5f, 0x81, 0xc0, 0xd6, 0x2a, 0x74, 0xd2, 0x8d,
+ 0x1f, 0xe9, 0x7b, 0x4c, 0xe1, 0x92, 0x5f, 0xb4, 0xec, 0x40, 0x58, 0xbf,
+ 0x70, 0xb9, 0x1f, 0x58, 0xb8, 0xba, 0x58, 0xb4, 0xcb, 0x16, 0x06, 0x1a,
+ 0xb7, 0x18, 0xa7, 0x3f, 0x81, 0x29, 0xde, 0xd4, 0x4c, 0xb1, 0x7f, 0xb0,
+ 0xcf, 0x98, 0xe1, 0x9d, 0x62, 0xe7, 0x99, 0x62, 0xa7, 0x3c, 0xf2, 0x37,
+ 0xbf, 0x70, 0xc7, 0xef, 0x8b, 0x14, 0xc7, 0x9a, 0xe4, 0x57, 0xf8, 0xfa,
+ 0x6e, 0x41, 0x4e, 0xb1, 0x7f, 0xd0, 0x6f, 0xdf, 0xc1, 0xe0, 0x16, 0x29,
+ 0xcf, 0xbc, 0x8d, 0x2f, 0xfb, 0x91, 0xf2, 0x63, 0xc7, 0x16, 0x2f, 0x73,
+ 0x58, 0xb1, 0x78, 0xb2, 0x4b, 0x17, 0xed, 0x00, 0x84, 0x05, 0x8a, 0x83,
+ 0xc5, 0xc1, 0xca, 0x64, 0x41, 0x71, 0x8a, 0xdb, 0xab, 0x17, 0xf6, 0x07,
+ 0x13, 0x37, 0x16, 0x28, 0x8f, 0x13, 0xc2, 0xb5, 0x0b, 0xe4, 0x33, 0xc2,
+ 0x82, 0x50, 0xcc, 0x19, 0xde, 0x47, 0x83, 0x32, 0x7e, 0xa1, 0x3e, 0x72,
+ 0x1f, 0xc2, 0xe8, 0xa1, 0x1f, 0xc2, 0x0f, 0x42, 0xeb, 0x7b, 0x35, 0xff,
+ 0x43, 0x7e, 0x0f, 0x3e, 0x18, 0xb1, 0x7f, 0xee, 0x43, 0x0c, 0xa2, 0x4c,
+ 0x05, 0x8b, 0xf7, 0xda, 0x77, 0x25, 0x8b, 0x86, 0xcb, 0x17, 0xbe, 0xd3,
+ 0x2c, 0x5d, 0xa9, 0xd6, 0x2f, 0x8d, 0x72, 0x02, 0xc5, 0x61, 0xbc, 0x10,
+ 0xcd, 0xdf, 0x65, 0x8a, 0x84, 0x68, 0x61, 0x44, 0xc2, 0xff, 0x5a, 0x08,
+ 0x41, 0x7f, 0xd3, 0x96, 0x4b, 0xf8, 0x0e, 0x2c, 0x5f, 0xc6, 0xf1, 0x8b,
+ 0xb9, 0x2c, 0x5f, 0x0c, 0x9c, 0xc5, 0x8b, 0xff, 0xf9, 0x84, 0x46, 0xf5,
+ 0xf6, 0xeb, 0xf1, 0xd9, 0x8f, 0xa5, 0x8b, 0xd0, 0x5d, 0x6d, 0x44, 0x1f,
+ 0x88, 0xef, 0xf9, 0xbf, 0x1d, 0x83, 0x3d, 0xc5, 0x8b, 0xc2, 0x80, 0x2c,
+ 0x5f, 0xb0, 0xbb, 0x97, 0x30, 0xf5, 0xf4, 0x75, 0x7b, 0x98, 0x6a, 0xc5,
+ 0xce, 0x75, 0x8a, 0xf1, 0xb5, 0xde, 0x3d, 0x7f, 0xef, 0x0b, 0xd3, 0x0a,
+ 0x73, 0xb7, 0x96, 0x2b, 0x0f, 0x99, 0x88, 0xef, 0xba, 0x38, 0x21, 0x62,
+ 0xfe, 0x96, 0x73, 0x8c, 0x35, 0x8b, 0x4b, 0x69, 0xe9, 0x78, 0x92, 0xa1,
+ 0x55, 0xac, 0xf0, 0xb3, 0x68, 0x46, 0x9e, 0x1b, 0x21, 0xb9, 0x5f, 0xff,
+ 0xef, 0x88, 0xbc, 0x59, 0xd8, 0x1f, 0xdc, 0x62, 0xee, 0x4b, 0x17, 0xfe,
+ 0xd7, 0xcc, 0x71, 0xef, 0xf6, 0x74, 0xb1, 0x7d, 0x87, 0x8e, 0x96, 0x2f,
+ 0xa3, 0xd8, 0x75, 0x8b, 0xce, 0xfd, 0xac, 0x5f, 0x49, 0xfd, 0xc5, 0x8a,
+ 0x19, 0xe0, 0x4c, 0x3b, 0x5d, 0x22, 0x17, 0xcc, 0x54, 0xe9, 0x88, 0x01,
+ 0x10, 0xa1, 0x51, 0x78, 0x71, 0xbd, 0x62, 0xf8, 0xdc, 0x29, 0x2c, 0x5f,
+ 0xe1, 0x4e, 0x72, 0x73, 0x59, 0x62, 0xb0, 0xf6, 0x18, 0x8e, 0xfb, 0x5e,
+ 0xc9, 0xd6, 0x2f, 0xff, 0xc6, 0xbe, 0xdc, 0x3b, 0x7b, 0x6f, 0xb8, 0x4c,
+ 0x6a, 0xc5, 0xd1, 0x32, 0xc5, 0xff, 0xc5, 0x06, 0x0c, 0xa3, 0xb9, 0x31,
+ 0x2c, 0x51, 0xa8, 0xb7, 0xd2, 0xd9, 0x0c, 0x5f, 0x8f, 0x9f, 0x70, 0x8b,
+ 0x15, 0x09, 0x9a, 0xe4, 0x36, 0xd8, 0xc2, 0xfd, 0xdf, 0x4d, 0xee, 0x2c,
+ 0x5f, 0xfa, 0x69, 0x46, 0xa7, 0xda, 0x66, 0x7d, 0x62, 0xff, 0x7d, 0xbe,
+ 0x51, 0x9a, 0x58, 0xbf, 0x46, 0xfd, 0x07, 0xc5, 0x8a, 0xda, 0x8a, 0x3e,
+ 0x91, 0x7e, 0x65, 0x50, 0x98, 0x0b, 0xc3, 0x3a, 0xa1, 0x5a, 0xd8, 0xcd,
+ 0x34, 0xef, 0xf8, 0xd5, 0x4a, 0x33, 0x4b, 0xfc, 0xe4, 0xe0, 0x04, 0x71,
+ 0x62, 0xff, 0x7f, 0x3d, 0x82, 0xd4, 0xeb, 0x17, 0xff, 0xf9, 0xba, 0xfe,
+ 0x6d, 0xfc, 0x6d, 0xe3, 0x6c, 0xc7, 0x4e, 0x1a, 0xc5, 0xf1, 0x09, 0xfc,
+ 0xb1, 0x7d, 0xdf, 0x4d, 0xda, 0xc5, 0x4e, 0x98, 0xc9, 0xcc, 0xbe, 0x6a,
+ 0x06, 0xae, 0x11, 0x5f, 0xe2, 0x89, 0x4d, 0xf8, 0x9d, 0x62, 0xee, 0x99,
+ 0x62, 0xff, 0x98, 0xa6, 0x8e, 0xb5, 0x9d, 0xac, 0x53, 0x9e, 0x9f, 0x06,
+ 0x28, 0x68, 0xa9, 0xf4, 0x22, 0x2f, 0xc3, 0x34, 0xd1, 0x76, 0xb1, 0x63,
+ 0x5c, 0xf5, 0x44, 0x51, 0x7f, 0xd1, 0xec, 0xd7, 0x4e, 0xfd, 0x2a, 0x2f,
+ 0x82, 0xfe, 0x76, 0x1c, 0x7b, 0x8b, 0x17, 0xff, 0xfb, 0xcd, 0x9d, 0x8f,
+ 0xe2, 0xe6, 0x75, 0xb7, 0xed, 0x87, 0x58, 0xbe, 0xd4, 0x77, 0x25, 0x8b,
+ 0xff, 0xb0, 0xe2, 0x93, 0x8f, 0x3a, 0x8e, 0x2c, 0x56, 0x1f, 0x4f, 0xc9,
+ 0x2e, 0x83, 0xf4, 0x9b, 0x1f, 0xd1, 0xf8, 0x5b, 0xe8, 0x67, 0x5f, 0xf3,
+ 0x9b, 0xc6, 0xe3, 0x77, 0xe5, 0x8a, 0xfa, 0x22, 0x89, 0x3e, 0xff, 0xfc,
+ 0x5d, 0x6d, 0xfc, 0x36, 0x98, 0xed, 0xb9, 0x07, 0x58, 0xbc, 0xfa, 0x9d,
+ 0x51, 0x7f, 0x97, 0xf1, 0x75, 0xce, 0x66, 0xea, 0xc5, 0xff, 0x88, 0x06,
+ 0x67, 0x7e, 0xf4, 0x1d, 0x62, 0xa0, 0xfc, 0xf0, 0xca, 0xff, 0xc5, 0xed,
+ 0x64, 0x77, 0x26, 0x3a, 0xc5, 0xec, 0x9c, 0x22, 0xc5, 0xfd, 0x9d, 0x83,
+ 0x3d, 0xc5, 0x8b, 0xf4, 0x17, 0x72, 0xe2, 0xc7, 0xcd, 0x7d, 0x42, 0xa0,
+ 0x1c, 0x22, 0xe9, 0x6b, 0xf0, 0x9e, 0x72, 0x02, 0x3f, 0x12, 0x7d, 0xef,
+ 0x31, 0x8b, 0x17, 0xf3, 0xce, 0x18, 0xdf, 0x75, 0x62, 0xbc, 0x7a, 0x22,
+ 0x1e, 0xbf, 0xda, 0xd6, 0x4c, 0x78, 0xe2, 0xc5, 0xff, 0x3f, 0xb8, 0xc5,
+ 0xdc, 0x8e, 0xb1, 0x7f, 0xcd, 0xa9, 0xc4, 0x00, 0x47, 0x96, 0x2f, 0xfa,
+ 0x33, 0x5b, 0x64, 0xdd, 0xc9, 0x62, 0xa4, 0x98, 0x46, 0x11, 0x00, 0xd7,
+ 0x87, 0x5e, 0x3b, 0xbe, 0xea, 0x01, 0xba, 0xb1, 0x7f, 0xff, 0xbe, 0xfc,
+ 0x68, 0xe6, 0xdf, 0x7f, 0x0f, 0x9d, 0x3e, 0x96, 0x2e, 0x80, 0x8b, 0x17,
+ 0xfd, 0x1d, 0xcb, 0xed, 0xa7, 0x92, 0xc5, 0xee, 0x39, 0xd6, 0x28, 0x8f,
+ 0x5f, 0x87, 0x55, 0xa4, 0xc6, 0xfe, 0x4e, 0x06, 0x3f, 0x38, 0x5f, 0x1c,
+ 0xa2, 0x65, 0x8b, 0xfd, 0xdf, 0x83, 0xff, 0xf3, 0x75, 0x62, 0xf4, 0x67,
+ 0x16, 0x2f, 0xd8, 0xd3, 0xc1, 0xab, 0x15, 0x08, 0xa2, 0xc2, 0x3d, 0x1d,
+ 0x7c, 0x72, 0xfc, 0x0e, 0x6e, 0x47, 0x96, 0x2f, 0xb3, 0x41, 0xcc, 0xb1,
+ 0x53, 0xa2, 0x33, 0x0e, 0xf4, 0x59, 0x78, 0x6d, 0x32, 0xc5, 0xfe, 0xf4,
+ 0x77, 0xc2, 0x8d, 0xeb, 0x16, 0x02, 0xc5, 0xf4, 0xa0, 0xbc, 0xb1, 0x7e,
+ 0x39, 0xd8, 0x33, 0xac, 0x5b, 0xd8, 0x79, 0x8c, 0x45, 0x53, 0xa3, 0x63,
+ 0xb1, 0xed, 0x1b, 0x12, 0xf5, 0xf7, 0x72, 0xf3, 0xac, 0x5f, 0xfe, 0xeb,
+ 0xec, 0x59, 0xbd, 0xe5, 0xc6, 0x1a, 0xc5, 0xfe, 0x91, 0x61, 0xce, 0xf2,
+ 0x58, 0xbe, 0x6e, 0x98, 0x6b, 0x17, 0x6a, 0x18, 0xf5, 0xbc, 0x67, 0x43,
+ 0x46, 0x76, 0xa1, 0x45, 0x7f, 0x73, 0xc5, 0x19, 0xda, 0xc5, 0x42, 0x70,
+ 0xd8, 0x7c, 0xf0, 0xf2, 0x11, 0x45, 0xff, 0xec, 0xe7, 0xdd, 0xbd, 0x07,
+ 0x27, 0x35, 0x62, 0xf3, 0x97, 0x4b, 0x17, 0xe0, 0x73, 0xd9, 0xf5, 0x8b,
+ 0xe1, 0xfe, 0x3b, 0x58, 0xbe, 0xcf, 0xcb, 0x16, 0x2c, 0x63, 0x1e, 0x37,
+ 0x89, 0x2d, 0x8b, 0x15, 0x08, 0xa8, 0x76, 0xff, 0x14, 0x5f, 0x40, 0x73,
+ 0x71, 0x62, 0xa1, 0x70, 0xbe, 0x52, 0xa3, 0xb1, 0x02, 0x64, 0x92, 0x86,
+ 0x2f, 0x0b, 0xaf, 0xfc, 0x03, 0xb6, 0x77, 0xe1, 0xc0, 0xd6, 0x2f, 0xf7,
+ 0xe3, 0xb9, 0x1c, 0xd8, 0x58, 0xbf, 0xff, 0xb7, 0xc1, 0x7b, 0x25, 0xf8,
+ 0xee, 0x5e, 0xe4, 0x69, 0x62, 0xfe, 0xda, 0x3c, 0xc0, 0x71, 0x62, 0xff,
+ 0xfd, 0xec, 0xd4, 0xed, 0xc6, 0xdf, 0xf6, 0xce, 0xfc, 0xb1, 0x47, 0x44,
+ 0x49, 0x18, 0x5f, 0xe2, 0xf7, 0x04, 0x3f, 0xb2, 0xc5, 0x41, 0xeb, 0x61,
+ 0x15, 0xcf, 0xda, 0xc5, 0xf6, 0xd3, 0x0b, 0xcb, 0x17, 0x73, 0x0e, 0x6f,
+ 0x88, 0x62, 0xfe, 0xcf, 0xb6, 0xbe, 0xeb, 0x17, 0x6a, 0x75, 0x8a, 0x9c,
+ 0xf1, 0x8e, 0x5b, 0x58, 0x89, 0x46, 0x71, 0xbf, 0xe8, 0xe7, 0x21, 0xa7,
+ 0x7f, 0x2c, 0x5f, 0x9c, 0xf0, 0x38, 0x58, 0xaf, 0x1f, 0x00, 0x8e, 0x6f,
+ 0xe2, 0xf9, 0x8e, 0x52, 0x58, 0xbf, 0xe6, 0xc2, 0x19, 0xad, 0x9a, 0x58,
+ 0xa8, 0x57, 0x5c, 0x34, 0x0c, 0x36, 0x68, 0xcf, 0x75, 0x0f, 0x2f, 0x42,
+ 0x04, 0x44, 0x41, 0x0b, 0xaf, 0xf6, 0x4f, 0xb5, 0xcd, 0xfb, 0x2c, 0x5f,
+ 0xf7, 0x32, 0x7e, 0x31, 0x3c, 0xeb, 0x17, 0xfe, 0xce, 0xe4, 0xc4, 0x78,
+ 0x1c, 0x2c, 0x5d, 0x9d, 0xac, 0x5f, 0xff, 0xfa, 0x27, 0xee, 0x5c, 0x2c,
+ 0x9b, 0x6f, 0x5f, 0x8e, 0x8d, 0xd3, 0x98, 0xb1, 0x50, 0x99, 0xee, 0x1b,
+ 0xb1, 0xd7, 0x8f, 0x84, 0x31, 0x7f, 0x3e, 0xbb, 0x96, 0x79, 0x62, 0xff,
+ 0x3e, 0x07, 0x99, 0xdf, 0x96, 0x2f, 0xfb, 0x8d, 0xaf, 0x10, 0x9e, 0x4b,
+ 0x14, 0x03, 0xed, 0xf1, 0xa5, 0xff, 0xf9, 0xb9, 0x83, 0xfe, 0x79, 0xb3,
+ 0x93, 0xe1, 0x8b, 0x17, 0xff, 0xc5, 0xee, 0xbe, 0xc6, 0x70, 0xb0, 0x02,
+ 0xe2, 0xc5, 0xfb, 0x1b, 0x71, 0x86, 0xb1, 0x7f, 0xf4, 0x6e, 0x60, 0x8b,
+ 0x33, 0x7c, 0x76, 0xb1, 0x50, 0x8c, 0x41, 0xa9, 0x1c, 0xaa, 0xff, 0xa3,
+ 0x40, 0xf3, 0x1b, 0x84, 0xb1, 0x7b, 0x98, 0x4b, 0x17, 0xff, 0xfc, 0xc4,
+ 0x01, 0xe7, 0x7c, 0x61, 0x75, 0xf6, 0xf7, 0x18, 0x6b, 0x17, 0xdc, 0x1e,
+ 0x12, 0xc5, 0x01, 0x14, 0xdc, 0x1c, 0xf3, 0x45, 0xff, 0xa3, 0x35, 0x9a,
+ 0x01, 0xdb, 0x8b, 0x17, 0xde, 0xe0, 0x3a, 0x58, 0xbc, 0xfd, 0x84, 0x58,
+ 0xbf, 0x9f, 0xdc, 0x8c, 0x9d, 0x62, 0xa1, 0x5e, 0x3e, 0x42, 0x73, 0xa2,
+ 0x26, 0x8c, 0x6b, 0xe5, 0xef, 0x0d, 0xf2, 0x30, 0x11, 0xf6, 0xf2, 0x53,
+ 0x08, 0x2f, 0xc0, 0x7e, 0xe5, 0x8b, 0x17, 0xfb, 0x0b, 0xd9, 0x34, 0x6e,
+ 0xac, 0x5f, 0xe8, 0x31, 0xf5, 0xa6, 0x02, 0xc5, 0xfc, 0xfd, 0x7c, 0xf0,
+ 0x35, 0x8b, 0xd8, 0x01, 0xfc, 0xf8, 0xdc, 0xd2, 0xa1, 0x1e, 0x87, 0x29,
+ 0x04, 0x26, 0x6f, 0xf8, 0x50, 0x7e, 0x61, 0xe3, 0x75, 0x62, 0xff, 0xda,
+ 0x9f, 0x07, 0x9f, 0xfe, 0x6e, 0xac, 0x58, 0xd5, 0x8b, 0xfd, 0xee, 0x07,
+ 0xbe, 0x33, 0xb5, 0x8a, 0x83, 0xcb, 0x21, 0x3b, 0xff, 0x6b, 0x87, 0x0f,
+ 0x34, 0xd1, 0x32, 0xc5, 0x61, 0xf0, 0x88, 0x82, 0xc3, 0x58, 0xbd, 0xfc,
+ 0x25, 0x8b, 0xce, 0x53, 0xf0, 0xd7, 0x78, 0x4a, 0xb1, 0x37, 0x0e, 0x43,
+ 0xbc, 0xc4, 0xfb, 0xef, 0x7f, 0x09, 0x62, 0xff, 0x16, 0x7b, 0xd9, 0xa9,
+ 0x96, 0x2f, 0xee, 0x3c, 0x8a, 0x0e, 0xb1, 0x78, 0xa3, 0x75, 0x62, 0xff,
+ 0xfa, 0x51, 0xa9, 0xfc, 0xc6, 0xf3, 0x8e, 0x52, 0x58, 0xbf, 0xa7, 0xe6,
+ 0x1e, 0x37, 0x56, 0x2a, 0x64, 0x42, 0x06, 0xa5, 0x58, 0x9a, 0x5c, 0xc4,
+ 0x5a, 0x34, 0xe1, 0x69, 0x90, 0xa3, 0xbf, 0x89, 0xfb, 0x96, 0x79, 0x62,
+ 0xef, 0xb2, 0xc5, 0xff, 0x18, 0x58, 0x08, 0x00, 0x67, 0x58, 0xa9, 0xd1,
+ 0x00, 0xc5, 0xc4, 0x2f, 0x7f, 0xb0, 0xee, 0x43, 0xfc, 0x2c, 0x5f, 0x0f,
+ 0xd9, 0xbd, 0x62, 0x86, 0x7a, 0xff, 0x32, 0xbf, 0xfe, 0x13, 0xea, 0x5b,
+ 0x98, 0x50, 0x03, 0xbc, 0x96, 0x2e, 0x1c, 0x96, 0x2f, 0xd9, 0xef, 0xb7,
+ 0x96, 0x2f, 0xf6, 0x0c, 0x5e, 0xe4, 0x82, 0xeb, 0x17, 0x64, 0x96, 0x2b,
+ 0xe7, 0xa0, 0x47, 0x36, 0x94, 0x26, 0x4a, 0x32, 0x2d, 0x29, 0x7c, 0x63,
+ 0xcf, 0x17, 0xc7, 0xf3, 0x4e, 0xb1, 0x58, 0x7e, 0x8c, 0xa1, 0x7f, 0xf6,
+ 0xff, 0x1b, 0x05, 0x2c, 0xfb, 0x1d, 0x62, 0xe9, 0xfc, 0xb1, 0x7f, 0xb7,
+ 0xfd, 0xe5, 0x18, 0x4b, 0x15, 0x07, 0x9b, 0x83, 0x37, 0xd2, 0x7d, 0x49,
+ 0x62, 0xff, 0xf4, 0x69, 0xfc, 0x2f, 0x37, 0xb9, 0xf6, 0x58, 0xb4, 0xa6,
+ 0x3e, 0xdf, 0x91, 0xd2, 0xc5, 0xf0, 0x7f, 0x7f, 0x2c, 0x5b, 0x38, 0x6c,
+ 0x0c, 0x0c, 0xbf, 0xa4, 0x7f, 0x10, 0xa6, 0x58, 0xbf, 0xfe, 0x0e, 0x51,
+ 0xbd, 0x88, 0x1a, 0x68, 0x3e, 0x24, 0x56, 0x91, 0x03, 0xe3, 0x0b, 0xef,
+ 0x87, 0xdf, 0x96, 0x2f, 0xd8, 0x7c, 0x6d, 0xeb, 0x17, 0xa7, 0x9b, 0x75,
+ 0x62, 0xc6, 0x2c, 0x54, 0x27, 0x53, 0x3a, 0xce, 0x42, 0xa3, 0xa2, 0x36,
+ 0x26, 0x11, 0x4e, 0xe1, 0x1d, 0xfa, 0x73, 0x93, 0x9a, 0xb1, 0x77, 0xb1,
+ 0x62, 0xff, 0x03, 0x98, 0x51, 0xdf, 0x16, 0x2f, 0xda, 0x69, 0xdc, 0xea,
+ 0x98, 0x4c, 0xbe, 0xf0, 0xa1, 0xd5, 0x30, 0x99, 0x70, 0x21, 0x54, 0x09,
+ 0x97, 0xf8, 0x9c, 0xdf, 0x46, 0x80, 0xaa, 0x04, 0xcb, 0xfd, 0xcc, 0xfb,
+ 0x70, 0x53, 0xaa, 0x61, 0x32, 0xec, 0x1a, 0xa6, 0x13, 0x2e, 0x30, 0xc5,
+ 0xcc, 0x26, 0x56, 0x26, 0xaf, 0xd9, 0xb3, 0x17, 0x9c, 0x93, 0x88, 0x3b,
+ 0xd0, 0x8c, 0x24, 0xb7, 0x93, 0x30, 0x98, 0xd9, 0x3e, 0x7a, 0xed, 0x51,
+ 0xee, 0x85, 0xcc, 0x8f, 0xca, 0xf0, 0xc4, 0x4b, 0x17, 0xee, 0x78, 0xb2,
+ 0x4b, 0x15, 0x87, 0x8a, 0x01, 0xda, 0xc5, 0x60, 0xed, 0x29, 0x9d, 0xdf,
+ 0xef, 0xff, 0xc0, 0x3b, 0xcb, 0x9f, 0x8d, 0xf8, 0x18, 0xde, 0x4b, 0x15,
+ 0x0c, 0x9d, 0xc6, 0x86, 0x8f, 0xe5, 0x0f, 0xb9, 0x01, 0x42, 0x53, 0x92,
+ 0x8d, 0xbd, 0x2d, 0xcc, 0x46, 0xd7, 0xff, 0xd8, 0x67, 0xdd, 0xbd, 0x1e,
+ 0x10, 0x30, 0x96, 0x2f, 0xfd, 0x22, 0x73, 0x66, 0x93, 0x6a, 0x4b, 0x17,
+ 0xfc, 0xe6, 0x96, 0x4d, 0x28, 0xed, 0x62, 0xb4, 0x7f, 0x84, 0x83, 0x7f,
+ 0xf8, 0xa0, 0xcf, 0x1a, 0xfc, 0xcc, 0x23, 0x56, 0x2f, 0xc7, 0xee, 0x4c,
+ 0x4b, 0x17, 0x10, 0xf0, 0xfd, 0x3c, 0x97, 0x7c, 0xfb, 0xf0, 0xc5, 0x8b,
+ 0x05, 0x16, 0x2f, 0xff, 0x9e, 0x5f, 0x88, 0x6f, 0x71, 0x8b, 0xb9, 0x2c,
+ 0x54, 0x8f, 0x97, 0xe2, 0xd7, 0xa6, 0x8e, 0x2c, 0x5e, 0x20, 0x1d, 0x62,
+ 0xff, 0xa0, 0x5e, 0x26, 0xde, 0x19, 0xd6, 0x2f, 0xfb, 0x3c, 0xd9, 0xc9,
+ 0xf0, 0xc5, 0x8b, 0xa0, 0xeb, 0x17, 0xc3, 0x1c, 0x49, 0x04, 0x57, 0x67,
+ 0x21, 0x1e, 0x18, 0x3d, 0xa1, 0xdf, 0x9e, 0x6e, 0x1d, 0x06, 0x2f, 0x7f,
+ 0xf9, 0xe5, 0xf8, 0xde, 0x19, 0xdd, 0xf5, 0xd2, 0xc5, 0x42, 0xbd, 0xac,
+ 0x86, 0x5b, 0x42, 0x57, 0x45, 0x8f, 0x08, 0xa2, 0x8c, 0x48, 0x4c, 0x97,
+ 0xf9, 0xb7, 0xed, 0xfb, 0xf3, 0x75, 0x62, 0xfe, 0xf0, 0x9f, 0x9c, 0xf2,
+ 0xc5, 0xfb, 0x91, 0x80, 0x85, 0x8b, 0x8b, 0x3b, 0x3d, 0x6f, 0x17, 0xdc,
+ 0xfa, 0x58, 0xb0, 0x3e, 0x78, 0x8e, 0x5b, 0x7f, 0xdf, 0x80, 0xcf, 0x9b,
+ 0xdb, 0xa5, 0x8a, 0xc4, 0xce, 0x5e, 0x1a, 0xbc, 0x27, 0xbc, 0xda, 0x35,
+ 0x62, 0xed, 0x01, 0x62, 0xb0, 0xdb, 0x30, 0xf5, 0xd3, 0xe9, 0x62, 0xe0,
+ 0x4c, 0xb1, 0x7f, 0xf1, 0xe6, 0x93, 0x94, 0xe3, 0x82, 0x9d, 0x62, 0xa0,
+ 0xfe, 0x46, 0x33, 0x83, 0x37, 0xb3, 0x92, 0x58, 0xbe, 0x6f, 0xb9, 0xd6,
+ 0x2f, 0xb5, 0x1c, 0x9d, 0x62, 0xb4, 0x7c, 0x7e, 0x1d, 0x0c, 0x8a, 0xa1,
+ 0xdc, 0x17, 0xcf, 0x2b, 0xbe, 0x4b, 0x63, 0x9c, 0xcd, 0xc8, 0xdb, 0xcd,
+ 0x8d, 0x2b, 0xa9, 0xc1, 0x6e, 0xe3, 0xc1, 0x68, 0xd9, 0x66, 0x9d, 0x9b,
+ 0xd4, 0xe0, 0x91, 0xe3, 0xbf, 0xfc, 0xe0, 0x78, 0x23, 0x90, 0x23, 0x4e,
+ 0x47, 0x59, 0xea, 0x5a, 0xee, 0xf9, 0xc6, 0xa3, 0x23, 0xaf, 0xdc, 0x6a,
+ 0x0e, 0x13, 0x01, 0x21, 0x21, 0x78, 0xfe, 0xe2, 0xc5, 0xf6, 0xb7, 0xe0,
+ 0xd6, 0x2a, 0x73, 0xc3, 0x71, 0xeb, 0xb0, 0x96, 0x2e, 0xf7, 0x16, 0x2a,
+ 0x0d, 0x71, 0x0b, 0x5f, 0xfd, 0x9f, 0xcf, 0x77, 0xd3, 0x6b, 0xf8, 0xb1,
+ 0x76, 0x71, 0x62, 0xff, 0xdc, 0xcd, 0x78, 0x9c, 0xd3, 0x71, 0x62, 0xa4,
+ 0x8b, 0xc1, 0x8f, 0x81, 0x1b, 0x82, 0xf7, 0xfe, 0x2c, 0x03, 0xeb, 0x37,
+ 0xe0, 0xd6, 0x2f, 0xd3, 0x4a, 0x0b, 0xcb, 0x17, 0xfe, 0xd6, 0x73, 0x82,
+ 0x20, 0xcf, 0x0b, 0x15, 0x23, 0xe9, 0xd1, 0x4d, 0xfd, 0x92, 0x21, 0x3f,
+ 0x16, 0x2f, 0xbb, 0xe3, 0x42, 0xc5, 0xfe, 0xc2, 0x09, 0xe6, 0x23, 0x56,
+ 0x28, 0xd4, 0xd3, 0xfb, 0x85, 0x46, 0x88, 0xbe, 0x5a, 0x02, 0x3b, 0xec,
+ 0xd3, 0x1a, 0xb1, 0x78, 0xc9, 0xce, 0xb1, 0x7f, 0xfd, 0xbf, 0x59, 0x3e,
+ 0xd1, 0x46, 0x7a, 0x3b, 0x92, 0xc5, 0xed, 0x08, 0x6b, 0x17, 0xfa, 0x0e,
+ 0x4f, 0x2c, 0xfa, 0xc5, 0x68, 0xf4, 0x3e, 0x3d, 0x50, 0x9a, 0xe8, 0xd4,
+ 0xb0, 0x8d, 0xc8, 0x39, 0x0a, 0x6b, 0xf4, 0x06, 0x5d, 0x81, 0x62, 0xff,
+ 0x7e, 0x0d, 0x0f, 0xef, 0xe5, 0x8a, 0xf9, 0xf0, 0x78, 0xaa, 0xec, 0x08,
+ 0xb1, 0x70, 0x7c, 0x58, 0xbf, 0x78, 0xcc, 0x29, 0xd6, 0x2d, 0x1f, 0x3c,
+ 0x32, 0x19, 0xad, 0x81, 0x10, 0x52, 0x5c, 0xb1, 0x8b, 0x14, 0xb1, 0x6c,
+ 0xc2, 0xff, 0x78, 0x9d, 0xcc, 0x6a, 0xc5, 0x4e, 0x6f, 0x98, 0x9a, 0xfe,
+ 0x68, 0x2f, 0x7f, 0x16, 0x2f, 0xde, 0xc9, 0x98, 0xeb, 0x17, 0xe8, 0xec,
+ 0x00, 0x85, 0x8a, 0x83, 0xd2, 0x22, 0x9b, 0xed, 0xf0, 0x5e, 0x58, 0xbf,
+ 0x7e, 0x1b, 0x90, 0xb1, 0x50, 0x79, 0x6e, 0x49, 0x7b, 0xec, 0x1a, 0xc5,
+ 0xf9, 0xb7, 0xf9, 0xa7, 0x58, 0xbf, 0x7b, 0xf1, 0xa9, 0x2c, 0x5f, 0xfb,
+ 0x0f, 0x05, 0x00, 0x3b, 0xc9, 0x62, 0xff, 0x89, 0x8d, 0x8f, 0x71, 0xb4,
+ 0xb1, 0x7f, 0xfb, 0xe2, 0x79, 0x77, 0xed, 0x46, 0x77, 0x8b, 0x14, 0x74,
+ 0x42, 0xf0, 0xe6, 0xfa, 0x5e, 0xce, 0x96, 0x2b, 0x0f, 0x1d, 0xc8, 0xee,
+ 0x28, 0x58, 0xbf, 0xef, 0xbc, 0xa2, 0x62, 0x83, 0xac, 0x5f, 0xc3, 0x7f,
+ 0x7d, 0x8c, 0x58, 0xbf, 0x16, 0x07, 0x93, 0x2c, 0x5f, 0xff, 0xf9, 0xb7,
+ 0x8e, 0x0b, 0x3e, 0xd0, 0x5e, 0xe7, 0x89, 0xc1, 0xc5, 0x8b, 0xfb, 0x25,
+ 0x33, 0xbc, 0xeb, 0x17, 0xff, 0xec, 0xe8, 0x10, 0x7c, 0xf3, 0x73, 0x30,
+ 0x8d, 0x58, 0xbf, 0x8e, 0xd0, 0x77, 0x25, 0x8a, 0xd2, 0x2c, 0x3e, 0x5e,
+ 0x05, 0x5b, 0xff, 0x98, 0xe3, 0x13, 0xea, 0x59, 0xdf, 0x96, 0x2c, 0x58,
+ 0x7e, 0xdd, 0x18, 0x5f, 0xf9, 0xc8, 0x1d, 0xfb, 0x51, 0x86, 0x2c, 0x5f,
+ 0xfb, 0x9f, 0x6d, 0xbd, 0xca, 0x32, 0x75, 0x8b, 0xfd, 0x83, 0xd6, 0x9a,
+ 0x6e, 0x2c, 0x5d, 0xb4, 0x22, 0xc5, 0xb3, 0x75, 0x1a, 0x80, 0x40, 0xf2,
+ 0x1e, 0xf3, 0x5b, 0xd8, 0x3d, 0xc5, 0x8b, 0xff, 0xff, 0x7a, 0x30, 0xbb,
+ 0xf6, 0xdc, 0xe3, 0x10, 0x0b, 0x3d, 0xfc, 0x58, 0xbe, 0x68, 0xee, 0x4b,
+ 0x17, 0xbe, 0xe7, 0xda, 0x88, 0xff, 0xb6, 0x5f, 0xec, 0x38, 0xd8, 0x02,
+ 0x92, 0xc5, 0xf7, 0xdd, 0xce, 0xb1, 0x7c, 0xff, 0xfb, 0x2c, 0x51, 0x1e,
+ 0x26, 0xf2, 0x2b, 0xf1, 0x4b, 0x71, 0xe7, 0x58, 0xa8, 0x3c, 0xf0, 0xc8,
+ 0xea, 0x15, 0x88, 0x4a, 0x1f, 0x66, 0xa3, 0xb4, 0x2b, 0xfe, 0x6c, 0x08,
+ 0x63, 0xdf, 0xff, 0xe6, 0xde, 0x42, 0xe6, 0xd0, 0xca, 0x07, 0xf7, 0x96,
+ 0x71, 0x62, 0xe3, 0x59, 0x62, 0x96, 0x2a, 0x76, 0x42, 0xf0, 0xda, 0xcd,
+ 0x20, 0xe8, 0x7b, 0xb2, 0xbd, 0xd2, 0x9d, 0x46, 0x12, 0x72, 0x0f, 0x8b,
+ 0x39, 0xc9, 0x17, 0xf0, 0xa7, 0xd3, 0x94, 0x3b, 0xd9, 0xf7, 0x19, 0x42,
+ 0x0c, 0x5f, 0xdc, 0x7c, 0x1b, 0x6f, 0x58, 0xbf, 0xdf, 0xee, 0x5c, 0xfe,
+ 0x4e, 0xb1, 0x7f, 0xcf, 0xf9, 0x98, 0xbf, 0x9d, 0xac, 0x54, 0x1f, 0x8e,
0x1b, 0xdf, 0xfe, 0x6e, 0x67, 0xc5, 0xd7, 0x9b, 0xcd, 0xda, 0xc5, 0xdd,
- 0xc6, 0xb1, 0x60, 0x2c, 0x50, 0x8d, 0x61, 0x83, 0x57, 0xe8, 0xa1, 0x3e,
- 0xe2, 0xc5, 0xdc, 0x02, 0xc5, 0x6d, 0x46, 0xe7, 0xde, 0x00, 0x45, 0xb2,
- 0x55, 0x7f, 0xff, 0xfd, 0xfc, 0x20, 0x61, 0x7b, 0xf9, 0xf9, 0xc8, 0x9b,
- 0x51, 0x7d, 0xbb, 0xf2, 0xc5, 0xfd, 0xa6, 0xeb, 0xf9, 0x12, 0xc5, 0xe8,
- 0x73, 0x16, 0x2f, 0xff, 0x64, 0x4e, 0x0c, 0xf4, 0xef, 0x62, 0x02, 0xc5,
- 0x39, 0xf4, 0x10, 0xed, 0x1d, 0x17, 0x1e, 0x84, 0xc5, 0xff, 0x60, 0x87,
- 0xb6, 0x79, 0x30, 0x58, 0xbe, 0x2f, 0x37, 0xd6, 0x2b, 0x69, 0xee, 0xb9,
- 0xdd, 0x62, 0x7b, 0xcf, 0x19, 0xb0, 0x21, 0x0b, 0x7a, 0x70, 0xc5, 0x8b,
- 0xfc, 0xdc, 0x29, 0xf4, 0xc1, 0x62, 0x88, 0xf3, 0xf8, 0x3b, 0x7d, 0x3d,
- 0xf1, 0xd6, 0x28, 0x28, 0xf9, 0xc4, 0xf3, 0x3d, 0x7d, 0x1c, 0x35, 0x60,
- 0x74, 0x38, 0x6d, 0x65, 0xb1, 0x75, 0xea, 0x3a, 0x1e, 0xe3, 0x0f, 0x69,
- 0x5d, 0x5b, 0x90, 0xad, 0x8a, 0x14, 0xba, 0x5d, 0x79, 0xf8, 0xf2, 0x8d,
- 0x2b, 0xd0, 0xfc, 0x14, 0xa2, 0x0d, 0xf0, 0x89, 0x0c, 0x86, 0xff, 0x4f,
- 0xc5, 0xe2, 0x73, 0x56, 0x2f, 0x73, 0x9c, 0x58, 0xbf, 0xfe, 0x62, 0xc3,
- 0xc8, 0x64, 0x28, 0x16, 0x1d, 0x62, 0xfc, 0x42, 0x86, 0x71, 0x62, 0xff,
- 0xb0, 0x7f, 0x9f, 0x7e, 0x78, 0xb1, 0x70, 0xdb, 0x0f, 0x84, 0x8a, 0x2f,
- 0xff, 0x34, 0xfb, 0xe2, 0x73, 0xc5, 0x09, 0x8d, 0x62, 0xfe, 0x2c, 0xd6,
- 0xb3, 0xb5, 0x8a, 0xf9, 0xfd, 0x71, 0x32, 0xff, 0xcf, 0xe2, 0x7e, 0x7d,
- 0xc1, 0xc5, 0x8b, 0xfd, 0xa9, 0xeb, 0xfd, 0xbe, 0xe2, 0xc5, 0x46, 0x7e,
- 0xfa, 0x3e, 0xbc, 0x53, 0xc5, 0x8b, 0xec, 0x2c, 0x3a, 0xc5, 0xff, 0x85,
- 0x31, 0x72, 0x48, 0xf3, 0xc5, 0x8a, 0x58, 0xa9, 0x44, 0x44, 0x07, 0x38,
- 0x42, 0x23, 0xfb, 0xf0, 0x9c, 0x67, 0x95, 0x8b, 0xff, 0xe6, 0x29, 0x8d,
- 0xc7, 0xf9, 0xf9, 0x61, 0xab, 0x15, 0xd1, 0xfb, 0xe8, 0xa2, 0xff, 0xbe,
- 0xd0, 0xfb, 0xc1, 0x8e, 0xb1, 0x7c, 0x52, 0x16, 0xf6, 0x1a, 0xc5, 0xff,
- 0xb8, 0xc5, 0xdc, 0x3c, 0xdc, 0x65, 0x8a, 0xc4, 0x53, 0x39, 0xcf, 0x8b,
- 0xaf, 0x98, 0x9a, 0x25, 0x8b, 0xf7, 0xbf, 0x22, 0x0b, 0xac, 0x5d, 0xf7,
- 0x58, 0xa7, 0x3c, 0x4f, 0x16, 0xdf, 0xf9, 0x8f, 0x83, 0xfb, 0x70, 0xb1,
- 0x62, 0xf8, 0xf2, 0x39, 0x58, 0xa2, 0x3d, 0xfe, 0x1e, 0xd4, 0x17, 0x52,
- 0x72, 0x15, 0xfd, 0x42, 0x95, 0xa1, 0x33, 0x14, 0x2a, 0xf5, 0x0b, 0x33,
- 0xc3, 0x27, 0xe5, 0xc4, 0xcd, 0xe8, 0x40, 0x5f, 0x7f, 0x00, 0xeb, 0x17,
- 0x05, 0x87, 0x58, 0xbe, 0x29, 0xd4, 0x16, 0x2f, 0xfb, 0xf3, 0x06, 0x22,
- 0x17, 0x6b, 0x17, 0xfd, 0xb8, 0x3f, 0xcc, 0x42, 0x26, 0x58, 0xbf, 0xe9,
- 0x83, 0x7a, 0x12, 0x40, 0x58, 0xbf, 0xe9, 0xcf, 0x06, 0x00, 0x4f, 0x6b,
- 0x17, 0xb0, 0x8d, 0x58, 0xbf, 0xfb, 0xef, 0xc2, 0x90, 0x07, 0x01, 0x69,
- 0x62, 0xda, 0x0a, 0xa7, 0x17, 0x23, 0xb8, 0x44, 0xc7, 0x3a, 0x3d, 0x39,
- 0xc0, 0x5c, 0xef, 0x83, 0xb6, 0x25, 0x8b, 0xfe, 0x9d, 0xc2, 0x7f, 0x41,
- 0xb7, 0xac, 0x5e, 0xfc, 0x8d, 0x62, 0xfe, 0x29, 0xeb, 0x53, 0x05, 0x8b,
- 0xff, 0xce, 0xde, 0x80, 0x8b, 0xdc, 0xfb, 0xc1, 0x60, 0x33, 0x5d, 0x7e,
- 0x1b, 0x0b, 0x46, 0xac, 0x5d, 0x3f, 0x58, 0xa6, 0x47, 0x3f, 0xd2, 0xdd,
- 0x6f, 0x79, 0x55, 0xff, 0xb8, 0x1f, 0x98, 0x85, 0x0c, 0xe2, 0xc5, 0xc3,
- 0xe2, 0xc5, 0x41, 0x3b, 0x9d, 0xc8, 0xc9, 0x3e, 0x7a, 0x48, 0x17, 0xff,
- 0xf6, 0x77, 0x9c, 0x72, 0xfb, 0x4f, 0xbe, 0x27, 0x3a, 0xc5, 0x6d, 0x5c,
- 0x94, 0x98, 0xeb, 0x59, 0xf5, 0xe3, 0xca, 0x24, 0x6b, 0xc7, 0x6c, 0x58,
- 0xbd, 0xc7, 0xe9, 0x62, 0xd8, 0xb1, 0x7e, 0x11, 0xdb, 0xf2, 0xb1, 0x7e,
- 0xcd, 0x75, 0x38, 0xb1, 0x51, 0x9f, 0x09, 0x08, 0x86, 0x51, 0x7f, 0xd8,
- 0x7c, 0xd3, 0x46, 0xe7, 0x58, 0xbf, 0xe9, 0x2e, 0xb6, 0xb6, 0xb3, 0xa5,
- 0x8b, 0xff, 0xdb, 0x7d, 0xfc, 0x3e, 0x75, 0x3f, 0x93, 0xac, 0x5e, 0x73,
- 0xf1, 0x62, 0xb0, 0xfa, 0x9d, 0x36, 0x80, 0x8c, 0x6f, 0x42, 0x9a, 0xec,
- 0x8d, 0x62, 0xfd, 0xac, 0xf7, 0xd9, 0x62, 0xff, 0xa1, 0x9a, 0xd6, 0x7b,
- 0xec, 0xb1, 0x7d, 0x3f, 0x0c, 0x7a, 0x3e, 0x1f, 0x14, 0x5f, 0xf1, 0x4f,
- 0x7b, 0x26, 0xfb, 0x3e, 0xb1, 0x77, 0xb6, 0x56, 0x2c, 0xe7, 0x3d, 0x92,
- 0x3e, 0xbd, 0xb2, 0xc0, 0x58, 0xbf, 0xfe, 0x2f, 0x3b, 0xfc, 0xa7, 0xdc,
- 0x33, 0x3e, 0xb1, 0x73, 0xee, 0x2c, 0x53, 0x22, 0x25, 0xc8, 0x3c, 0x9f,
- 0x7f, 0xec, 0x3e, 0x6e, 0xe6, 0x08, 0x2f, 0xc5, 0x8b, 0xf8, 0x31, 0xbe,
- 0xb0, 0xeb, 0x17, 0xdb, 0xe4, 0xa0, 0xb1, 0x6d, 0x6d, 0x3d, 0x3c, 0x2f,
- 0xaf, 0x23, 0x04, 0x38, 0x4c, 0x5f, 0xfc, 0x7e, 0x3c, 0x35, 0x3c, 0x92,
- 0x8d, 0x62, 0xff, 0xa7, 0xdf, 0xc3, 0xe6, 0xb1, 0x62, 0xfd, 0xef, 0xb4,
- 0xf1, 0x62, 0xe7, 0x2d, 0x1f, 0x07, 0x0e, 0x2f, 0xff, 0xb0, 0x7f, 0x9e,
- 0x41, 0xb9, 0xc9, 0xd4, 0x16, 0x2a, 0x33, 0xfc, 0xd9, 0x2c, 0xbf, 0xff,
- 0x7a, 0x7d, 0xc2, 0xcf, 0xb4, 0xfb, 0xef, 0x05, 0x8b, 0x32, 0xc5, 0x31,
- 0xf2, 0xfd, 0x52, 0xff, 0xa4, 0x1c, 0x18, 0x9f, 0x50, 0x58, 0xbe, 0xe9,
- 0xdf, 0xa5, 0xc4, 0x06, 0x5b, 0x20, 0x7d, 0x7a, 0x3a, 0xbf, 0xe3, 0xbf,
- 0x6f, 0x0e, 0x34, 0x16, 0x2f, 0xfa, 0x7f, 0xd3, 0x71, 0xda, 0x35, 0x8b,
- 0x4e, 0xd4, 0x4d, 0xe1, 0x3e, 0x8e, 0xaf, 0x1d, 0xe0, 0xb1, 0x5f, 0x3d,
- 0x30, 0x1b, 0x5c, 0x58, 0xb1, 0x73, 0x81, 0x62, 0xa4, 0xf3, 0xc8, 0x8b,
- 0xc2, 0xd6, 0xe9, 0x62, 0xb4, 0x78, 0x04, 0x5b, 0x58, 0xaf, 0x59, 0xe3,
- 0x21, 0xe4, 0x22, 0xc3, 0x94, 0x13, 0x43, 0x64, 0x10, 0x77, 0x0f, 0xfd,
- 0x14, 0x1d, 0xe7, 0xf0, 0x93, 0x04, 0x2b, 0xca, 0x1d, 0xfe, 0x97, 0xff,
- 0x7c, 0x3f, 0xce, 0xca, 0xc5, 0xff, 0xe3, 0xbf, 0xb8, 0x28, 0x7d, 0xd8,
- 0x9d, 0x62, 0xff, 0xfe, 0x61, 0x96, 0x72, 0x75, 0xb7, 0x9f, 0x71, 0xc8,
- 0xd6, 0x2f, 0x6f, 0x9f, 0xac, 0x54, 0xb2, 0x99, 0x60, 0x39, 0x8f, 0xed,
- 0x48, 0x50, 0x78, 0x48, 0x00, 0x9b, 0x89, 0x21, 0xae, 0x5f, 0x9b, 0xcf,
- 0xb3, 0x8b, 0x17, 0xec, 0xd4, 0x03, 0x82, 0xc5, 0xfe, 0x8f, 0x92, 0x77,
- 0xef, 0xcb, 0x15, 0x19, 0xf0, 0x11, 0x55, 0xcf, 0xda, 0xc5, 0xef, 0xbe,
- 0xe2, 0xc5, 0xf4, 0x83, 0x67, 0x16, 0x2f, 0x8e, 0x77, 0xf2, 0xc5, 0x41,
- 0x32, 0xcc, 0x84, 0x51, 0xc8, 0x80, 0x31, 0xe2, 0x00, 0xc9, 0x6f, 0xec,
- 0xdd, 0x77, 0xff, 0x16, 0x2f, 0xfe, 0xce, 0x79, 0xfb, 0x0f, 0x76, 0x4a,
- 0x0b, 0x16, 0xc5, 0x8b, 0xff, 0xb0, 0x9e, 0x1f, 0x73, 0x9d, 0xe0, 0xb1,
- 0x68, 0xb6, 0x03, 0xd4, 0xd8, 0xc4, 0x6f, 0xff, 0xf3, 0x0a, 0x38, 0x9d,
- 0xe3, 0xf6, 0x44, 0x52, 0x7f, 0xba, 0xc5, 0xfd, 0x18, 0xdb, 0x53, 0xbd,
- 0x62, 0xff, 0xfd, 0xcd, 0xb8, 0x3d, 0xbc, 0xcd, 0x00, 0xf9, 0xb3, 0x8b,
- 0x14, 0x48, 0x8e, 0xf1, 0x8d, 0xff, 0xfe, 0xcd, 0x6d, 0xeb, 0xec, 0x3d,
- 0x30, 0xa3, 0x0c, 0x6f, 0x1a, 0xc5, 0xe8, 0x68, 0xeb, 0x17, 0xdd, 0x7d,
- 0xa3, 0x58, 0xb8, 0x8d, 0xf9, 0xe1, 0xb8, 0xf5, 0xef, 0x00, 0x4b, 0x15,
- 0xd2, 0x3d, 0x9a, 0x15, 0x64, 0x5b, 0x7e, 0x38, 0x50, 0x28, 0x14, 0xd8,
- 0x96, 0x2f, 0xff, 0xe8, 0x67, 0x1b, 0x5a, 0x63, 0x87, 0xef, 0xe1, 0x9e,
- 0x58, 0xa9, 0x4f, 0x97, 0x23, 0x18, 0x63, 0x47, 0x3b, 0xbd, 0xc7, 0x65,
- 0x8b, 0xf8, 0xcf, 0xc8, 0xda, 0x56, 0x28, 0xe7, 0x94, 0xe3, 0x97, 0xff,
- 0xdf, 0x76, 0xf4, 0xb4, 0x30, 0x80, 0x09, 0x58, 0xbc, 0xff, 0x95, 0x8b,
- 0xb0, 0x0b, 0x16, 0x8f, 0xe6, 0xcc, 0xc1, 0xcb, 0xf0, 0x73, 0xac, 0x25,
- 0x8b, 0xfe, 0xfc, 0xf3, 0xdc, 0xc1, 0x05, 0xd6, 0x2f, 0xfd, 0x2d, 0xff,
- 0xe7, 0xbf, 0x90, 0x58, 0xbf, 0xd8, 0x50, 0xce, 0x06, 0x75, 0x8b, 0x10,
- 0xd1, 0x61, 0xa3, 0xef, 0x1f, 0x54, 0xa6, 0x1b, 0x90, 0xd8, 0xbf, 0xfd,
- 0x9f, 0x6d, 0xf3, 0x9a, 0x8c, 0x4e, 0x35, 0x8a, 0x89, 0x51, 0x4b, 0xc2,
- 0x00, 0xc8, 0xcd, 0x83, 0x27, 0xbf, 0xfd, 0x0c, 0xee, 0x01, 0xc8, 0x02,
- 0x18, 0x61, 0x89, 0x17, 0xe3, 0x99, 0x8d, 0xbd, 0x62, 0xec, 0x28, 0x8f,
- 0xf8, 0x35, 0x3b, 0xff, 0xee, 0x73, 0xe2, 0xea, 0x60, 0xda, 0x06, 0x12,
- 0xc5, 0x40, 0xff, 0xcc, 0x2e, 0xa9, 0x4d, 0xb1, 0xe3, 0x49, 0xbf, 0xfe,
- 0xd4, 0x07, 0xf9, 0xe1, 0x61, 0x8f, 0xa3, 0x56, 0x2f, 0x00, 0x5c, 0x58,
- 0xbf, 0x66, 0x14, 0xc1, 0x62, 0xdc, 0x93, 0xc4, 0x21, 0xea, 0x74, 0x5e,
- 0x7a, 0x12, 0xd5, 0x2c, 0x97, 0xe1, 0xae, 0xe1, 0x83, 0x42, 0x77, 0x46,
- 0x7f, 0x95, 0xac, 0xf0, 0x8a, 0x29, 0x76, 0xc2, 0x87, 0x25, 0xff, 0x31,
- 0x43, 0x81, 0x6f, 0x62, 0x0a, 0x6c, 0x4b, 0x17, 0x83, 0xd1, 0xab, 0x17,
- 0xd1, 0x73, 0x22, 0x58, 0xbf, 0x02, 0x7d, 0x9b, 0x8b, 0x17, 0xfc, 0x3d,
- 0x96, 0x34, 0xd9, 0x2f, 0x2c, 0x5f, 0xdc, 0xd6, 0x9a, 0x2e, 0x2c, 0x5f,
- 0xd9, 0xae, 0x9d, 0xfa, 0x54, 0x41, 0x25, 0xff, 0xa6, 0x05, 0x9f, 0xf1,
- 0x48, 0x16, 0x2a, 0x4f, 0xe4, 0x8f, 0x2f, 0xfa, 0x7d, 0x9a, 0xe9, 0xdf,
- 0xa5, 0x45, 0xf2, 0x5f, 0x9c, 0x7f, 0x93, 0x56, 0x2f, 0xff, 0xed, 0x60,
- 0xff, 0x3d, 0xc3, 0x53, 0xee, 0x06, 0x50, 0x58, 0xbf, 0xff, 0x08, 0x07,
- 0x78, 0x0d, 0xdc, 0xcc, 0x8a, 0x74, 0xb1, 0x6c, 0x64, 0x5a, 0xf9, 0x7a,
- 0xff, 0xc5, 0x9e, 0xf3, 0x73, 0xd8, 0x05, 0x8b, 0xb3, 0x81, 0x55, 0x4a,
- 0x63, 0x85, 0x4f, 0x44, 0x07, 0x47, 0x28, 0x6f, 0x70, 0x9e, 0xb1, 0x58,
- 0x19, 0x4a, 0x91, 0xa2, 0x56, 0xb1, 0xbe, 0x59, 0x75, 0xff, 0xd3, 0xf6,
- 0x37, 0x35, 0x19, 0xc5, 0xda, 0xc5, 0xff, 0x0f, 0x58, 0x7c, 0x83, 0x8d,
- 0x62, 0xff, 0xfc, 0x27, 0xe6, 0x17, 0x5f, 0x61, 0xff, 0x3b, 0xdd, 0x58,
- 0xa9, 0x5c, 0xa5, 0xc2, 0x06, 0x96, 0xfb, 0xf2, 0xd7, 0x48, 0x23, 0x9b,
- 0xf4, 0xeb, 0x07, 0x2b, 0x17, 0xe8, 0x60, 0x03, 0xf2, 0xc5, 0xfd, 0xfd,
- 0x9f, 0xb7, 0x5f, 0x58, 0xa6, 0x44, 0x23, 0x93, 0x88, 0xaa, 0xfc, 0x09,
- 0x87, 0x31, 0x62, 0xff, 0xfb, 0xaf, 0xce, 0xb3, 0x84, 0x27, 0x81, 0xae,
- 0xb1, 0x7f, 0xfe, 0x7d, 0xfb, 0x79, 0xf7, 0x6f, 0x4f, 0xbf, 0x9e, 0x58,
- 0xa1, 0x22, 0xa8, 0x35, 0x1b, 0xff, 0x3c, 0x7f, 0x98, 0xf3, 0xdc, 0xc5,
- 0x8a, 0x93, 0xe4, 0x22, 0x4b, 0xfe, 0xf4, 0x9f, 0xf9, 0xbf, 0x38, 0xb1,
- 0x7f, 0xd2, 0x7e, 0x4b, 0x46, 0xfe, 0x58, 0xa8, 0x1f, 0xa7, 0x8e, 0xef,
- 0xfd, 0x1b, 0xf7, 0xb3, 0x9e, 0x27, 0xde, 0xb1, 0x7f, 0xfb, 0xd2, 0x5e,
- 0xe6, 0x61, 0xa6, 0xbc, 0x16, 0x2f, 0xff, 0xfb, 0x4f, 0xfe, 0xe1, 0x9e,
- 0xdb, 0xce, 0x61, 0x74, 0xe4, 0x05, 0x8a, 0xc4, 0x5a, 0xba, 0x5d, 0xfc,
- 0x6e, 0x7b, 0xd8, 0x35, 0x8b, 0xff, 0x60, 0xe6, 0x13, 0xfc, 0x03, 0xac,
- 0x5f, 0xcf, 0x01, 0x41, 0xc6, 0xb1, 0x7f, 0xff, 0xdf, 0x13, 0xc7, 0xa9,
- 0xfb, 0xb7, 0x39, 0x86, 0xb9, 0x01, 0x62, 0xfc, 0xd1, 0xf3, 0x8e, 0xb1,
- 0x43, 0x44, 0x87, 0xd9, 0xef, 0xff, 0xbd, 0xce, 0x4e, 0x10, 0xff, 0x3f,
- 0x9e, 0x2c, 0x5e, 0x30, 0xc3, 0x12, 0x2f, 0xdf, 0xce, 0x9f, 0x49, 0x01,
- 0x0d, 0x0d, 0xff, 0xfe, 0x8b, 0x53, 0xbf, 0x69, 0xaf, 0xb4, 0x38, 0xb9,
- 0xb7, 0x3b, 0xf2, 0xc5, 0x4a, 0x67, 0xce, 0x47, 0xe7, 0x00, 0xce, 0xef,
- 0xfb, 0xec, 0x67, 0xa2, 0xd4, 0xf9, 0x62, 0xff, 0xcd, 0xe1, 0x67, 0x9c,
- 0xf8, 0x4b, 0x15, 0x03, 0xf9, 0xd1, 0xe5, 0xff, 0x48, 0x3d, 0x85, 0x0c,
- 0xe2, 0xc5, 0xff, 0x60, 0x1c, 0x81, 0x03, 0x60, 0xb1, 0x4c, 0x89, 0x4f,
- 0x91, 0x11, 0xc5, 0x46, 0xb9, 0xf7, 0xd4, 0x3e, 0xb4, 0x42, 0x72, 0xf0,
- 0x1e, 0x94, 0x7f, 0x9e, 0x8d, 0x2a, 0xe7, 0xf2, 0xc5, 0xee, 0x64, 0x6b,
- 0x17, 0x14, 0x60, 0x36, 0xbe, 0x17, 0xa5, 0x8a, 0x93, 0x72, 0x72, 0xda,
- 0x58, 0xa5, 0x8b, 0x70, 0xc2, 0xe3, 0x74, 0x32, 0xce, 0xb1, 0x69, 0x58,
- 0xbc, 0xed, 0x19, 0x1a, 0x21, 0x08, 0xdf, 0xff, 0x37, 0x4c, 0x3e, 0x4f,
- 0xdc, 0x85, 0x9f, 0x58, 0xa8, 0x23, 0x33, 0x89, 0x9e, 0x31, 0xbf, 0xb8,
- 0x59, 0x18, 0x70, 0x58, 0xbf, 0x07, 0xee, 0x08, 0x96, 0x2e, 0x3c, 0xf6,
- 0x7b, 0x44, 0x61, 0x7f, 0xff, 0x7d, 0xcb, 0xb8, 0x07, 0x09, 0x28, 0x39,
- 0xf0, 0x6b, 0x17, 0xfe, 0x81, 0x98, 0xdb, 0xf2, 0x12, 0x4b, 0x14, 0xc8,
- 0x9c, 0x0d, 0x72, 0xff, 0xf6, 0x67, 0xc7, 0xf9, 0xe6, 0x7d, 0x80, 0xb1,
- 0x7e, 0x8a, 0x13, 0xae, 0x2c, 0x5f, 0xec, 0x21, 0x43, 0x91, 0xba, 0xc5,
- 0x8d, 0xda, 0x7b, 0xc3, 0x2a, 0xbf, 0xf3, 0x7a, 0x31, 0x73, 0x6e, 0xb5,
- 0x2b, 0x15, 0x2a, 0xa2, 0xe3, 0x84, 0x54, 0x21, 0x92, 0x32, 0x36, 0x85,
- 0x3f, 0x8a, 0xef, 0xb6, 0xb7, 0xc4, 0xb1, 0x7e, 0xc8, 0x7e, 0x74, 0xb1,
- 0x7c, 0x6e, 0xdf, 0xb2, 0xc5, 0x74, 0x7e, 0x7b, 0x84, 0xba, 0x28, 0xbf,
- 0x40, 0x85, 0xdc, 0x16, 0x2e, 0xfb, 0x2c, 0x5d, 0xdf, 0xbb, 0x3c, 0x18,
- 0x8a, 0xaf, 0xcd, 0xf3, 0x67, 0xb5, 0x8b, 0xf6, 0x0c, 0xa7, 0xb5, 0x8b,
- 0x7a, 0x4f, 0x48, 0x8a, 0xaf, 0xff, 0xff, 0xdd, 0xf8, 0xa4, 0xfc, 0x1f,
- 0xe7, 0x99, 0x06, 0x34, 0xd7, 0xf1, 0x49, 0xf8, 0xb1, 0x7f, 0x81, 0x06,
- 0xf7, 0x03, 0x3a, 0xc5, 0xff, 0xb8, 0xf0, 0xe6, 0x75, 0x27, 0x65, 0x8a,
- 0xd1, 0xfa, 0xf8, 0xda, 0xff, 0xba, 0xfb, 0x00, 0x13, 0xa8, 0x2c, 0x5f,
- 0x6a, 0x36, 0x8d, 0x62, 0xee, 0xcb, 0x69, 0xf0, 0x61, 0xdd, 0x4a, 0xac,
- 0x8c, 0x74, 0x68, 0x41, 0xb9, 0x30, 0xa1, 0xf4, 0x1c, 0x20, 0xaf, 0xfb,
- 0xb9, 0x63, 0xe1, 0x66, 0xe2, 0xc5, 0xef, 0x3f, 0x4b, 0x17, 0xff, 0xa1,
- 0xcc, 0x1e, 0x7d, 0x9f, 0xdf, 0x95, 0x8a, 0x8d, 0x14, 0x5d, 0x1d, 0xf6,
- 0x3d, 0x7e, 0x8f, 0xf2, 0x2c, 0x58, 0xbf, 0xfe, 0x84, 0x9f, 0x52, 0xd0,
- 0x7e, 0x39, 0x01, 0x62, 0xfe, 0x6e, 0x60, 0xc3, 0xc5, 0x8b, 0xf6, 0xeb,
- 0x16, 0x6f, 0x58, 0xbf, 0xb0, 0x6c, 0x2e, 0xbf, 0xd1, 0xed, 0x39, 0x75,
- 0xfd, 0xc8, 0x31, 0xde, 0x0b, 0x15, 0x29, 0xa2, 0x76, 0x53, 0xa8, 0x54,
- 0x01, 0x16, 0xff, 0x70, 0xb3, 0x7f, 0xde, 0x0b, 0x17, 0xb9, 0x0d, 0xeb,
- 0x14, 0xc7, 0xab, 0xb8, 0x6b, 0x7f, 0xfa, 0x63, 0x0f, 0xf3, 0xdf, 0xb2,
- 0x32, 0x1a, 0xc5, 0xe7, 0xea, 0x56, 0x2b, 0x15, 0x4f, 0x34, 0x6e, 0xef,
- 0x09, 0x82, 0x24, 0xf2, 0x75, 0xfe, 0x01, 0xdc, 0x07, 0x70, 0x2c, 0x5f,
- 0xfc, 0xf0, 0xc1, 0x93, 0x3f, 0xe4, 0xeb, 0x17, 0x3f, 0xd6, 0x2b, 0xe7,
- 0xb3, 0xe4, 0x2b, 0x8c, 0xe9, 0x62, 0xff, 0x86, 0xe1, 0xe8, 0x9a, 0x4d,
- 0x58, 0xbe, 0x9c, 0x2f, 0x05, 0x4f, 0x50, 0x63, 0x57, 0xfb, 0xf9, 0xbf,
- 0x6f, 0x21, 0xd2, 0xc5, 0x70, 0xfd, 0x7c, 0x77, 0x5e, 0x4c, 0x34, 0x50,
- 0xeb, 0xbf, 0xfc, 0x59, 0xe6, 0x83, 0x96, 0x7b, 0xec, 0xb1, 0x7f, 0x13,
- 0xf7, 0x06, 0xc5, 0x8b, 0xfc, 0x40, 0x2c, 0xf7, 0xf3, 0x69, 0xfa, 0x7d,
- 0x1e, 0xfe, 0x2d, 0xa1, 0xeb, 0xee, 0xb1, 0x7f, 0xe1, 0x3c, 0x36, 0xcb,
- 0x0f, 0x0e, 0xb1, 0x4c, 0x8b, 0xb7, 0x4a, 0x23, 0x1b, 0xff, 0x69, 0x81,
- 0x1f, 0xe7, 0x82, 0xe2, 0xc5, 0xfb, 0x34, 0xfd, 0x98, 0xb1, 0x68, 0x2c,
- 0x5f, 0xff, 0x8c, 0x2c, 0x1e, 0x98, 0x51, 0x8f, 0xf2, 0x51, 0xac, 0x5a,
- 0x39, 0x3e, 0xac, 0x12, 0xa8, 0xd1, 0x77, 0xc8, 0x4a, 0x5f, 0xe8, 0x89,
- 0xcc, 0xf6, 0x7d, 0x62, 0xf7, 0xf3, 0xa5, 0x8b, 0xc6, 0x18, 0x62, 0x45,
- 0xfc, 0x09, 0x2c, 0xef, 0xc9, 0x01, 0x0d, 0x0d, 0x6d, 0x45, 0xa6, 0xc9,
- 0xa8, 0x67, 0xf7, 0xff, 0xf0, 0x5f, 0x6f, 0x5f, 0x61, 0x8f, 0x0c, 0xdb,
- 0xee, 0x64, 0x6b, 0x15, 0xf4, 0x4f, 0x08, 0xda, 0xa5, 0x54, 0xd3, 0x43,
- 0xf1, 0xe3, 0x7b, 0xbf, 0xff, 0x3e, 0xa5, 0x87, 0x24, 0xe0, 0xe4, 0xb0,
- 0xd6, 0x2f, 0xfb, 0x37, 0xe3, 0x0d, 0xdc, 0xd5, 0x8b, 0xff, 0xf3, 0x7b,
- 0xf3, 0xcc, 0x6f, 0x71, 0x8b, 0xb8, 0x2c, 0x57, 0x48, 0xe1, 0xfa, 0x90,
- 0x5c, 0xea, 0xfb, 0xfc, 0x9d, 0x2c, 0x5f, 0xfb, 0xb8, 0x14, 0xed, 0xd9,
- 0x78, 0xf8, 0xb1, 0x7f, 0xec, 0xff, 0x4d, 0x20, 0x3c, 0xc1, 0x62, 0xa5,
- 0x15, 0x0c, 0x47, 0xa4, 0x6b, 0xfe, 0x0e, 0x79, 0x86, 0x06, 0x5e, 0x58,
- 0xa8, 0xdd, 0x08, 0x9c, 0x27, 0x3c, 0xc7, 0x0e, 0x0c, 0x2e, 0xea, 0x33,
- 0x6e, 0xe1, 0x28, 0xd3, 0xa3, 0xb1, 0x43, 0x9f, 0x52, 0xe3, 0xcf, 0x2e,
- 0x8b, 0xf2, 0xe9, 0x5d, 0x4c, 0xa3, 0x9a, 0xe4, 0x6b, 0x1e, 0x95, 0x8e,
- 0x28, 0xc6, 0xf7, 0xc3, 0x74, 0x32, 0xeb, 0xfe, 0x62, 0x8d, 0xcb, 0xd8,
- 0x75, 0x8b, 0xa4, 0x0b, 0x15, 0x87, 0x9f, 0xe3, 0x8b, 0xff, 0x8d, 0x0f,
- 0xcd, 0xc2, 0xcd, 0xec, 0x35, 0x8b, 0xf8, 0xb0, 0x7f, 0x73, 0x16, 0x2b,
- 0x47, 0xec, 0x74, 0x8b, 0xff, 0xff, 0x16, 0x30, 0x36, 0xfd, 0xfd, 0xe1,
- 0x47, 0xb4, 0x3d, 0x6b, 0x23, 0x58, 0xbe, 0x62, 0x07, 0x16, 0x2f, 0x13,
- 0x9d, 0x62, 0xff, 0xdc, 0x6d, 0x3f, 0xdb, 0x93, 0x05, 0x8b, 0xf8, 0x7f,
- 0xcf, 0x6c, 0xe2, 0xc5, 0x9a, 0x09, 0x90, 0xf4, 0xe9, 0xf2, 0x2f, 0x0e,
- 0x18, 0x7d, 0x7f, 0xff, 0x10, 0xfe, 0xed, 0xe0, 0x31, 0x43, 0x98, 0x40,
- 0x58, 0xa9, 0x4f, 0xbb, 0xf1, 0xa1, 0x89, 0x4a, 0xff, 0x11, 0xbc, 0x6d,
- 0x3c, 0x16, 0x2f, 0x89, 0xfb, 0xf2, 0xc5, 0xec, 0x20, 0x2c, 0x5f, 0xdd,
- 0x4f, 0x65, 0x26, 0x2c, 0x5f, 0xe8, 0x0f, 0xe2, 0x38, 0xf1, 0x62, 0xf0,
- 0x7b, 0x38, 0xb1, 0x58, 0x7a, 0xc0, 0x35, 0xbe, 0xcf, 0x45, 0x05, 0x8b,
- 0xff, 0xb7, 0x4a, 0x77, 0x78, 0xe4, 0x18, 0x38, 0xb1, 0x69, 0x58, 0xaf,
- 0xa2, 0x01, 0xc9, 0x3c, 0x97, 0x7f, 0xec, 0xf4, 0xeb, 0x9f, 0x92, 0xf2,
- 0xe2, 0x08, 0x2f, 0xec, 0xd7, 0x4e, 0xfd, 0x2a, 0x20, 0x80, 0x21, 0xe5,
- 0xde, 0x91, 0xb2, 0xc5, 0x49, 0xf5, 0xf1, 0x3e, 0xff, 0xc4, 0x58, 0x6b,
- 0xe1, 0xdc, 0x96, 0x2e, 0xde, 0x35, 0x8b, 0xdb, 0xe4, 0xeb, 0x17, 0xdd,
- 0xf3, 0x34, 0xb1, 0x7e, 0x8f, 0x35, 0x30, 0x58, 0xbe, 0xd6, 0x98, 0xc5,
- 0x8a, 0x39, 0xe6, 0xfc, 0xa6, 0xa5, 0x12, 0x6e, 0xe3, 0x7f, 0x6e, 0x0c,
- 0xc7, 0x28, 0x2c, 0x54, 0xa6, 0xb7, 0x19, 0xe6, 0x0d, 0x14, 0x2c, 0x84,
- 0x43, 0x7f, 0xff, 0xfa, 0x4b, 0xae, 0x49, 0x7b, 0x98, 0x23, 0x87, 0xc7,
- 0xd4, 0xf5, 0x84, 0xb1, 0x7f, 0xfa, 0x28, 0x31, 0x7a, 0x41, 0x11, 0x34,
- 0x4b, 0x17, 0x14, 0x4b, 0x16, 0x91, 0x9f, 0x26, 0x26, 0x5f, 0xff, 0xa7,
- 0xdf, 0x78, 0xb8, 0xed, 0xd1, 0x3e, 0x74, 0xb1, 0x52, 0xbb, 0x43, 0x19,
- 0xa1, 0xa4, 0x7d, 0x0e, 0x6a, 0x10, 0xdf, 0x85, 0x08, 0x21, 0xca, 0x51,
- 0xbe, 0x79, 0x3b, 0x7c, 0x37, 0x36, 0x49, 0xaf, 0xf1, 0x09, 0xe2, 0x77,
- 0x8d, 0x62, 0xd0, 0x58, 0xbd, 0x3a, 0x02, 0xc5, 0x0c, 0xd7, 0xb0, 0x95,
- 0xe7, 0xd4, 0x6b, 0x14, 0x34, 0x50, 0xfd, 0x8c, 0xc2, 0x0b, 0xfb, 0xed,
- 0xa2, 0xc8, 0xd6, 0x2e, 0xe7, 0xd6, 0x2b, 0x47, 0x8c, 0x02, 0xeb, 0xf6,
- 0xa7, 0xac, 0x25, 0x8a, 0xc3, 0xca, 0x72, 0x2b, 0xfb, 0xf9, 0xef, 0x31,
- 0xd6, 0x2f, 0xfe, 0xe0, 0xc9, 0xa3, 0x0f, 0x45, 0x38, 0xb1, 0x7f, 0x78,
- 0x3c, 0xfb, 0xf6, 0xb1, 0x7b, 0x80, 0x75, 0x8a, 0xed, 0x18, 0x1f, 0x2e,
- 0x24, 0x5f, 0x18, 0x5f, 0xf1, 0x47, 0x9a, 0x01, 0x08, 0x0b, 0x17, 0xf6,
- 0x77, 0xed, 0x6a, 0x56, 0x2f, 0xfe, 0xe1, 0x3f, 0x9c, 0xe1, 0xcc, 0x78,
- 0xb1, 0x43, 0x3f, 0x4e, 0x17, 0xd4, 0xa6, 0x1a, 0xc7, 0xa2, 0x85, 0x75,
- 0xff, 0x3b, 0x79, 0xce, 0xe4, 0x05, 0x8b, 0xdb, 0xff, 0x8b, 0x16, 0xeb,
- 0xe7, 0xac, 0x19, 0xbd, 0xf0, 0xbd, 0x24, 0xb1, 0x58, 0x79, 0x9c, 0x2a,
- 0xbf, 0x6f, 0x1f, 0xe7, 0x8b, 0x16, 0x3a, 0xc5, 0xfe, 0x9f, 0x0f, 0xe2,
- 0x7e, 0x2c, 0x06, 0x59, 0x5c, 0x15, 0xe9, 0x62, 0xff, 0xec, 0xeb, 0xf3,
- 0xfc, 0xd6, 0xa4, 0xd5, 0x8b, 0x81, 0x2b, 0x16, 0x1e, 0x8f, 0x74, 0x08,
- 0xd5, 0xa4, 0x51, 0x13, 0xd5, 0xf1, 0x4f, 0x60, 0x58, 0xa6, 0x3c, 0x50,
- 0xc8, 0xaf, 0xf3, 0xc6, 0x19, 0x66, 0xfc, 0x58, 0xb1, 0xab, 0x17, 0x76,
- 0x05, 0x8a, 0x93, 0x58, 0xc2, 0x77, 0xfb, 0x34, 0xc0, 0x3b, 0xc1, 0x62,
- 0xe6, 0x25, 0x8b, 0xfe, 0x92, 0x34, 0x6d, 0x01, 0x69, 0x62, 0xc6, 0x2c,
- 0x50, 0xcf, 0x8c, 0xe2, 0xc1, 0x9d, 0x5e, 0x21, 0x46, 0xb1, 0x7a, 0x32,
- 0x95, 0x8b, 0xf7, 0xde, 0x18, 0x4b, 0x17, 0xf3, 0x78, 0xb3, 0xec, 0xb1,
- 0x73, 0x44, 0xb1, 0x7d, 0xbb, 0x3a, 0x35, 0x62, 0xdf, 0xda, 0x89, 0x29,
- 0x27, 0x72, 0xcd, 0xd1, 0x8b, 0xfe, 0x9e, 0x7d, 0xb5, 0xa7, 0x82, 0xc5,
- 0x61, 0xff, 0x92, 0x35, 0xce, 0x66, 0xd5, 0x4a, 0x23, 0x1f, 0xc8, 0x4b,
- 0x7c, 0xc1, 0xc7, 0xbd, 0x19, 0x75, 0xfd, 0x31, 0xfb, 0x99, 0xe5, 0x8a,
- 0x95, 0xfc, 0x08, 0x47, 0xdb, 0x90, 0xd6, 0x62, 0x1d, 0x1e, 0xfe, 0x32,
- 0xb7, 0x22, 0x29, 0x56, 0x66, 0x38, 0x5f, 0xdc, 0x61, 0x8f, 0x09, 0x62,
- 0xff, 0xff, 0xec, 0xf4, 0x9c, 0x79, 0xe9, 0xc2, 0x81, 0x67, 0x70, 0x9c,
- 0xf2, 0xc5, 0xff, 0xfb, 0xf9, 0xce, 0x66, 0x0b, 0x51, 0xe0, 0x8b, 0xcb,
- 0x14, 0x48, 0xc5, 0xf3, 0x7d, 0xff, 0x7e, 0x75, 0xe2, 0x9c, 0xed, 0x62,
- 0xff, 0xff, 0x9a, 0x39, 0x87, 0x35, 0xa6, 0xee, 0x28, 0x3e, 0x8f, 0x9d,
- 0xac, 0x5f, 0xe9, 0x78, 0xdf, 0x4e, 0x1a, 0xc5, 0xef, 0xe1, 0x0d, 0x1b,
- 0x1f, 0x39, 0xf3, 0x5d, 0x62, 0xa2, 0xc6, 0x87, 0x97, 0xa1, 0xf5, 0x7e,
- 0x9d, 0x45, 0xc8, 0xd6, 0x2f, 0xfb, 0xf3, 0x9a, 0x87, 0x04, 0x75, 0x8a,
- 0x8c, 0xf9, 0x7a, 0x2b, 0xb9, 0xb8, 0xb1, 0x7f, 0xd9, 0x1b, 0xf8, 0x01,
- 0x94, 0x16, 0x2f, 0x4c, 0x0d, 0x58, 0xbf, 0x67, 0x23, 0xc3, 0x16, 0x2e,
- 0x6e, 0x96, 0x2d, 0xed, 0xa7, 0xc1, 0x01, 0xed, 0x92, 0xab, 0xff, 0x7b,
- 0xef, 0x06, 0x1f, 0xe6, 0x0b, 0x14, 0xe7, 0xf2, 0x47, 0x57, 0xf0, 0x67,
- 0xe1, 0x8f, 0xda, 0xc5, 0x4a, 0xa4, 0x0c, 0x84, 0xf9, 0xa4, 0x9a, 0x17,
- 0x78, 0xc5, 0x3c, 0x41, 0x7e, 0xfe, 0x03, 0x52, 0xb1, 0x7f, 0xfb, 0xed,
- 0xd4, 0xb7, 0xbf, 0x26, 0x67, 0xd6, 0x2f, 0xf7, 0x9b, 0xf8, 0x59, 0xc5,
- 0x8a, 0xe8, 0xff, 0x43, 0x4b, 0xbd, 0x08, 0x62, 0xc5, 0xd2, 0x1a, 0xc5,
- 0x76, 0x6d, 0x5c, 0x76, 0xff, 0x4c, 0x03, 0xe0, 0x03, 0xe9, 0x62, 0x98,
- 0xf6, 0x7c, 0x43, 0x62, 0x82, 0x34, 0xc7, 0x0b, 0x2a, 0x82, 0x74, 0xb9,
- 0x1b, 0xc5, 0xed, 0x67, 0xd6, 0x2f, 0x71, 0x8e, 0xb1, 0x5a, 0x37, 0x5e,
- 0x1d, 0xbf, 0xbe, 0xfe, 0xfb, 0x9d, 0x62, 0xec, 0xed, 0x62, 0xe6, 0x8d,
- 0x62, 0xa4, 0xff, 0xd8, 0x84, 0x32, 0xed, 0xd1, 0x8b, 0xfd, 0xc2, 0xc3,
- 0x9d, 0xbc, 0xb1, 0x7f, 0xf7, 0xda, 0x4b, 0x6b, 0x94, 0x18, 0xeb, 0x17,
- 0xcd, 0x13, 0x18, 0xb1, 0x7f, 0xe7, 0xec, 0x3f, 0x36, 0xa4, 0x41, 0x75,
- 0x8b, 0x83, 0x8d, 0x62, 0x8e, 0x7b, 0xfe, 0x45, 0xbf, 0x3f, 0x0a, 0x62,
- 0x58, 0xbf, 0x7c, 0x45, 0x31, 0xac, 0x5d, 0xbf, 0x4b, 0x17, 0xff, 0xe1,
- 0x46, 0x53, 0x9f, 0x09, 0x3e, 0xcf, 0x8b, 0x4b, 0x17, 0xb8, 0x1f, 0x36,
- 0xa7, 0x58, 0x34, 0x4c, 0x84, 0x19, 0xa4, 0x4c, 0x50, 0x45, 0x21, 0x8d,
- 0x57, 0x4a, 0x97, 0x7d, 0x1e, 0xfd, 0xc4, 0x62, 0xc5, 0xfb, 0x87, 0xcf,
- 0x71, 0x62, 0xfe, 0x06, 0xa7, 0xac, 0x25, 0x8b, 0xff, 0x1b, 0x9e, 0x6f,
- 0xe7, 0xa7, 0x4b, 0x15, 0x27, 0xda, 0xc5, 0xd7, 0xe7, 0x81, 0x34, 0xac,
- 0x5f, 0x3f, 0x98, 0x0b, 0x17, 0xc5, 0xec, 0x25, 0x8a, 0xf9, 0xe1, 0xb9,
- 0x15, 0xfd, 0x87, 0xcc, 0x23, 0x56, 0x29, 0x62, 0xfe, 0xf7, 0x33, 0x7f,
- 0xd9, 0x62, 0x8d, 0x37, 0x8e, 0x19, 0x63, 0x46, 0x88, 0xa2, 0x69, 0xa9,
- 0x46, 0xa3, 0xc2, 0xae, 0xff, 0x89, 0xcc, 0x8a, 0x0f, 0xa8, 0x2c, 0x5f,
- 0xcd, 0xac, 0xdf, 0x3b, 0x8b, 0x15, 0x11, 0xf6, 0xfc, 0xee, 0xfe, 0x6d,
- 0x6a, 0x70, 0x96, 0x2f, 0xfa, 0x61, 0xcc, 0xe8, 0xa7, 0x4b, 0x14, 0x69,
- 0xf2, 0xe8, 0xb2, 0xcc, 0xb1, 0x7f, 0x71, 0xb5, 0xd7, 0xf1, 0x62, 0xf1,
- 0x39, 0xb8, 0x7c, 0x7d, 0x11, 0xf6, 0x23, 0x52, 0xbe, 0xe7, 0x08, 0x71,
- 0x64, 0xa9, 0xbe, 0x8b, 0x18, 0x63, 0x50, 0x96, 0x39, 0x01, 0x46, 0x7b,
- 0xc8, 0x49, 0x8a, 0x1d, 0x77, 0xff, 0xd1, 0xe6, 0xa3, 0x6f, 0x43, 0x35,
- 0xa7, 0x82, 0xc5, 0xff, 0xe6, 0xfc, 0xff, 0x3b, 0xe3, 0x7e, 0x46, 0xb1,
- 0x7b, 0xa6, 0x1a, 0xc5, 0xff, 0x1d, 0xfb, 0xdd, 0x9e, 0x8e, 0x75, 0x8b,
- 0xe9, 0xc0, 0xf6, 0x05, 0x8b, 0xf4, 0x8c, 0x28, 0x14, 0xd8, 0x96, 0x2d,
- 0xac, 0x44, 0xe9, 0x1f, 0x86, 0x51, 0x7f, 0xff, 0xb8, 0xdc, 0xe4, 0xf3,
- 0xa2, 0x78, 0xe4, 0xa6, 0x2e, 0x2c, 0x56, 0x27, 0xdd, 0xd2, 0x97, 0x69,
- 0x4f, 0x0b, 0xbf, 0x1a, 0xdf, 0xbe, 0xdb, 0x2c, 0x6a, 0xc5, 0xf6, 0x01,
- 0xb7, 0xac, 0x5f, 0x00, 0x02, 0x02, 0xc5, 0x74, 0x7e, 0x84, 0x58, 0x19,
- 0x25, 0xf0, 0xb5, 0xe6, 0x58, 0xbf, 0x14, 0x39, 0x18, 0x16, 0x2f, 0xfe,
- 0x04, 0xf0, 0xf2, 0xda, 0xd3, 0x18, 0xb1, 0x79, 0xde, 0x0b, 0x17, 0xf9,
- 0xbc, 0xd0, 0xce, 0xfc, 0xb1, 0x43, 0x47, 0x16, 0x11, 0xb1, 0x50, 0x11,
- 0x77, 0x47, 0x2f, 0xc7, 0x6f, 0x7a, 0x56, 0x2f, 0x36, 0x18, 0xb1, 0x7c,
- 0xdc, 0xc1, 0xb1, 0xe2, 0x91, 0x45, 0xfc, 0x5c, 0xc3, 0xce, 0xe2, 0xc5,
- 0xff, 0xa6, 0x00, 0x3c, 0x99, 0xc8, 0x46, 0xb1, 0x7f, 0xf6, 0x77, 0x0c,
- 0xfb, 0x68, 0x9a, 0x56, 0x2f, 0xfa, 0x67, 0x9c, 0x6d, 0x61, 0xd6, 0x2a,
- 0x07, 0xf6, 0x34, 0x3b, 0xed, 0xcf, 0xe4, 0x6b, 0x17, 0xfa, 0x47, 0x9e,
- 0x6f, 0x89, 0x62, 0xa4, 0xf6, 0x86, 0x4f, 0x7f, 0xe8, 0x79, 0xa3, 0xd4,
- 0xc1, 0xf4, 0xb1, 0x7c, 0x6b, 0x77, 0xc5, 0x8a, 0x94, 0xfb, 0xe3, 0x30,
- 0x8a, 0x17, 0xa7, 0x7c, 0x72, 0x1f, 0x20, 0x5f, 0xfb, 0xc1, 0x82, 0x43,
- 0x90, 0x48, 0x16, 0x2f, 0xf9, 0xb5, 0x18, 0x81, 0xb6, 0x77, 0x16, 0x2f,
- 0xff, 0x89, 0x8d, 0x36, 0x43, 0xf3, 0x7d, 0x8b, 0xcb, 0x15, 0x04, 0x48,
- 0x9d, 0x02, 0xff, 0xfc, 0x0e, 0x7d, 0xb0, 0xef, 0xdf, 0x3d, 0xf1, 0x76,
- 0xb1, 0x7f, 0x3f, 0x18, 0xa7, 0x8b, 0x17, 0x7d, 0xd6, 0x2f, 0x86, 0xe4,
- 0x0f, 0x9e, 0x18, 0x5c, 0xb2, 0xb1, 0x1b, 0x02, 0x84, 0xe5, 0xff, 0xff,
- 0x8e, 0xe4, 0x08, 0x37, 0x04, 0x7f, 0xb4, 0xfb, 0xe2, 0x73, 0xac, 0x5f,
- 0x72, 0x11, 0xe2, 0xc5, 0xff, 0xd8, 0x66, 0xa5, 0x8b, 0x00, 0x76, 0x58,
- 0xb8, 0xa5, 0x62, 0xff, 0xf0, 0xbd, 0x06, 0x07, 0xdd, 0xbc, 0xe7, 0x58,
- 0xaf, 0x9f, 0x01, 0x0b, 0x5d, 0xb7, 0x71, 0x62, 0xff, 0xfc, 0xed, 0xe6,
- 0x1e, 0x0f, 0x3c, 0xc7, 0x6d, 0x2c, 0x5f, 0x43, 0x92, 0x75, 0x8b, 0xff,
- 0xd3, 0xd0, 0xf0, 0x3f, 0x36, 0xa4, 0x41, 0x75, 0x8b, 0xc2, 0xc1, 0xac,
- 0x5e, 0xd3, 0xf3, 0x6a, 0x7d, 0x11, 0x92, 0x64, 0x28, 0xf4, 0x43, 0xf1,
- 0xd7, 0x53, 0x22, 0x3d, 0x95, 0x0b, 0x7a, 0x57, 0x00, 0x61, 0x0f, 0xb7,
- 0x27, 0x14, 0xa5, 0x4b, 0xff, 0x4f, 0x3a, 0xfb, 0x0e, 0x73, 0x4b, 0x15,
- 0xda, 0xeb, 0x13, 0x4e, 0x69, 0xe9, 0x42, 0xe8, 0x4a, 0xc5, 0xff, 0xbf,
- 0x3f, 0xce, 0xc1, 0x9e, 0xe2, 0xc5, 0xe8, 0x98, 0xeb, 0x14, 0x33, 0xde,
- 0xc4, 0x0b, 0xfd, 0x85, 0x2c, 0x6c, 0x9d, 0x62, 0xa3, 0x3d, 0x3f, 0x10,
- 0xd3, 0xa3, 0xac, 0x50, 0xc8, 0xbf, 0xff, 0xfd, 0xd6, 0xd8, 0xbf, 0x3a,
- 0x8f, 0x6f, 0x00, 0xe4, 0x0d, 0xb9, 0xd4, 0xfb, 0x8b, 0x15, 0x2c, 0xc1,
- 0xa1, 0xc3, 0x13, 0x23, 0x12, 0xea, 0x12, 0x0d, 0x28, 0x95, 0xe7, 0x6f,
- 0xca, 0x32, 0x61, 0x13, 0xde, 0xd6, 0xa5, 0x62, 0xff, 0xa3, 0x68, 0xf9,
- 0x87, 0x7f, 0xac, 0x5f, 0xf4, 0x24, 0x6c, 0x3c, 0x7f, 0xac, 0x59, 0xb4,
- 0x7e, 0x7e, 0x3b, 0xbf, 0xb5, 0x31, 0xb1, 0x79, 0x62, 0xe0, 0xce, 0xb1,
- 0x78, 0x0f, 0xc5, 0x8b, 0x82, 0x9b, 0x12, 0xc5, 0x0c, 0xf5, 0xfb, 0x19,
- 0xe0, 0xed, 0xed, 0x86, 0x16, 0xf6, 0x25, 0x8b, 0xf1, 0x48, 0xf2, 0x25,
- 0x8b, 0xfa, 0x0c, 0x07, 0xf0, 0x96, 0x2f, 0xb8, 0x2d, 0x1a, 0xb1, 0x7f,
- 0xe8, 0x08, 0x79, 0xaf, 0x10, 0xbc, 0xb1, 0x7e, 0x9f, 0xfa, 0x60, 0xb1,
- 0x7c, 0x31, 0x7b, 0x81, 0x44, 0xc4, 0xa4, 0xbf, 0x0a, 0x3b, 0x2e, 0x88,
- 0x94, 0x08, 0x17, 0xbe, 0x1e, 0x96, 0x2f, 0xf4, 0x93, 0xfc, 0x45, 0x1a,
- 0xc5, 0xff, 0xfb, 0xed, 0xaf, 0xbc, 0x91, 0xaf, 0x13, 0xbc, 0x6b, 0x17,
- 0xd8, 0xc0, 0xe2, 0xc5, 0xf3, 0x72, 0x61, 0x87, 0xf1, 0xa5, 0x6b, 0xd1,
- 0x8e, 0x56, 0x2f, 0xdb, 0x7b, 0xe4, 0xc1, 0x62, 0xf6, 0x9f, 0xa5, 0x8b,
- 0xc7, 0x9f, 0xac, 0x5e, 0x98, 0x05, 0x56, 0x2c, 0x01, 0x9e, 0xe6, 0x0f,
- 0x10, 0xed, 0xff, 0x4f, 0x27, 0xdc, 0xc2, 0x82, 0xc5, 0xff, 0xfd, 0x80,
- 0xd9, 0xce, 0x39, 0xb2, 0x5d, 0x3f, 0x9c, 0xd5, 0x8b, 0xff, 0xff, 0xd9,
- 0x1f, 0x24, 0xd7, 0xe7, 0xa1, 0x86, 0x9b, 0x9d, 0xfb, 0x53, 0x9d, 0xac,
- 0x5e, 0xd1, 0x41, 0x62, 0xff, 0x88, 0x1e, 0x61, 0xe1, 0x41, 0x62, 0xd3,
- 0xb4, 0xf5, 0x5c, 0x76, 0xbe, 0x9c, 0x89, 0x1c, 0x71, 0x7c, 0x50, 0xd2,
- 0xbc, 0x17, 0xfe, 0x2c, 0x56, 0xc6, 0xbd, 0x81, 0x08, 0x48, 0x0c, 0x9f,
- 0x21, 0x0a, 0xd1, 0xa1, 0x44, 0xe8, 0x71, 0xff, 0xc2, 0xad, 0xcd, 0xc0,
- 0x3c, 0x50, 0x88, 0xf4, 0x78, 0x82, 0x42, 0xb8, 0x3e, 0x2c, 0x5f, 0xfb,
- 0xdc, 0xc8, 0x9c, 0x1c, 0xc8, 0xd6, 0x2b, 0x47, 0xb4, 0x43, 0x37, 0xec,
- 0x33, 0xc1, 0x9d, 0x62, 0xfd, 0xb7, 0xb8, 0x67, 0x96, 0x2f, 0xff, 0xf0,
- 0x72, 0x01, 0xfe, 0x75, 0x84, 0xcf, 0x0e, 0x67, 0x96, 0x2a, 0x08, 0x8c,
- 0xe1, 0x65, 0xdc, 0x8d, 0x62, 0xfe, 0x29, 0x33, 0x52, 0x75, 0x8a, 0x19,
- 0xe3, 0xe0, 0xcd, 0x69, 0x11, 0x7e, 0x6a, 0xbf, 0xdc, 0x16, 0x81, 0x9f,
- 0x75, 0x8b, 0xee, 0x1d, 0xd9, 0x62, 0xa0, 0x7a, 0xde, 0x34, 0xbf, 0xfd,
- 0x0d, 0xba, 0x9e, 0x34, 0x90, 0x01, 0x2b, 0x15, 0x27, 0xda, 0xe4, 0x57,
- 0xe1, 0xe7, 0x04, 0x6a, 0xc5, 0xf3, 0x9f, 0x06, 0xb1, 0x7f, 0x60, 0xdc,
- 0x9f, 0x7a, 0xc5, 0x11, 0xfd, 0x78, 0xab, 0x79, 0x15, 0xff, 0x7e, 0x7b,
- 0xf4, 0xfd, 0xf7, 0x16, 0x29, 0x62, 0xe0, 0xe2, 0x58, 0xbf, 0xb3, 0x5c,
- 0xfe, 0x74, 0xb1, 0x6d, 0xeb, 0x15, 0xb5, 0x14, 0xdb, 0x0c, 0xf7, 0x41,
- 0x84, 0x35, 0xb2, 0x5f, 0x6e, 0xd6, 0x2e, 0xc3, 0x16, 0x2e, 0xf7, 0x98,
- 0xd5, 0xf8, 0x4e, 0xa5, 0x15, 0x6c, 0xff, 0x7e, 0x84, 0xc6, 0x42, 0x58,
- 0xbf, 0xe2, 0xeb, 0x35, 0xd3, 0xbf, 0x4a, 0x88, 0x44, 0xa8, 0x8f, 0xc5,
- 0xca, 0x6d, 0x1a, 0xc5, 0xf1, 0xae, 0x40, 0x58, 0xbc, 0xed, 0xba, 0xb1,
- 0x50, 0x3d, 0x56, 0x13, 0xf9, 0x1d, 0x4a, 0xec, 0xde, 0x10, 0xb4, 0x68,
- 0x47, 0x87, 0x33, 0xc2, 0x68, 0x11, 0xc0, 0x8a, 0x12, 0x5b, 0xdd, 0xef,
- 0x70, 0x0e, 0xb1, 0x7f, 0x7f, 0xa6, 0xe6, 0x0d, 0x62, 0xa3, 0x3c, 0xce,
- 0x87, 0x6f, 0xf3, 0x8f, 0x1b, 0x7b, 0x9d, 0x62, 0xff, 0xfd, 0xd6, 0x11,
- 0x36, 0x6a, 0x47, 0xf7, 0x26, 0x58, 0xad, 0x22, 0x18, 0x46, 0x97, 0xff,
- 0xff, 0xe6, 0x3e, 0x73, 0x08, 0x5e, 0xfe, 0x6f, 0x1c, 0xfd, 0xa7, 0xdf,
- 0x13, 0x9d, 0x62, 0xfe, 0xe3, 0xf5, 0xf6, 0x8d, 0x62, 0xb1, 0x38, 0x0d,
- 0x42, 0xab, 0xe4, 0x7e, 0x84, 0x1d, 0xf9, 0xb5, 0x0d, 0x9f, 0x2c, 0x5f,
- 0xfc, 0xfc, 0x8e, 0x7f, 0x9d, 0x07, 0xb2, 0xeb, 0x14, 0x73, 0xf6, 0x22,
- 0xcb, 0xff, 0xff, 0xdf, 0xc1, 0x68, 0xdf, 0xb7, 0x73, 0xe1, 0x7c, 0xb3,
- 0xbf, 0x09, 0xf8, 0xb1, 0x7f, 0xf6, 0x76, 0x1f, 0x98, 0x85, 0x0c, 0xe2,
- 0xc5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x0a, 0x32, 0x71, 0xc9, 0x47,
- 0x3a, 0x1e, 0x16, 0x7b, 0x8d, 0xd6, 0x10, 0x71, 0xe6, 0xa7, 0x84, 0xe6,
- 0xf3, 0x18, 0x00, 0x10, 0x09, 0xc7, 0x25, 0x1c, 0xe9, 0x62, 0xfd, 0xc3,
- 0x4d, 0xcd, 0xc5, 0x8b, 0xed, 0xdc, 0xef, 0xcb, 0x15, 0x27, 0xaa, 0xe5,
- 0xd7, 0xf4, 0x0b, 0x30, 0x41, 0x75, 0x8b, 0xfc, 0xfe, 0x86, 0x6b, 0x38,
- 0xb1, 0x52, 0xa8, 0xa3, 0x11, 0xbf, 0x1a, 0xf3, 0x90, 0x11, 0x8d, 0xff,
- 0x9b, 0xaf, 0xe6, 0xc8, 0x7a, 0x98, 0x2c, 0x5f, 0x9c, 0x00, 0x6f, 0xac,
- 0x5f, 0xfd, 0x9b, 0xfd, 0xe7, 0x62, 0x29, 0x3a, 0xc5, 0xd3, 0x0f, 0x9f,
- 0x67, 0x8a, 0x2b, 0xe8, 0xdd, 0x28, 0x58, 0x5f, 0xba, 0xf1, 0xad, 0xd2,
- 0xc5, 0xff, 0xef, 0xc9, 0x7b, 0x6f, 0xdc, 0x7f, 0x7d, 0x2c, 0x53, 0x9f,
- 0xc7, 0x0b, 0x2f, 0xfb, 0x39, 0xfc, 0x72, 0xcd, 0xc5, 0x8b, 0xfc, 0x19,
- 0xad, 0xbb, 0x25, 0x05, 0x8b, 0xfe, 0x2c, 0x6d, 0x14, 0xf7, 0x05, 0x8a,
- 0xc4, 0x55, 0x7c, 0xe9, 0xce, 0x2f, 0xff, 0xfb, 0xc2, 0x8f, 0x3e, 0xde,
- 0xfe, 0x1f, 0x35, 0x0c, 0xef, 0xcb, 0x17, 0xf7, 0xdb, 0xff, 0x93, 0xac,
- 0x5f, 0xa0, 0x53, 0x9c, 0x58, 0xbc, 0xe5, 0x1f, 0x47, 0xab, 0xd9, 0x75,
- 0x41, 0x1e, 0x7e, 0x85, 0xf5, 0xff, 0xfa, 0x41, 0x14, 0x26, 0x32, 0x73,
- 0x78, 0x53, 0x05, 0x8b, 0xff, 0x07, 0x9f, 0x73, 0x84, 0x30, 0xc3, 0x16,
- 0x2f, 0xff, 0xd9, 0xd7, 0xe4, 0x86, 0x4d, 0x1e, 0x13, 0x1a, 0xb1, 0x51,
- 0xa2, 0x6e, 0x08, 0xd7, 0xff, 0x46, 0x06, 0xef, 0x9d, 0x63, 0x17, 0x4b,
- 0x14, 0xe7, 0xd8, 0x44, 0x95, 0x04, 0xdf, 0x9e, 0x35, 0xeb, 0xff, 0xfa,
- 0x22, 0x90, 0x73, 0xaf, 0xb6, 0xa2, 0x29, 0x07, 0x16, 0x2f, 0xff, 0xef,
- 0x72, 0x4d, 0x83, 0x7d, 0xcb, 0xd0, 0xcd, 0x62, 0xc5, 0xff, 0x9b, 0x98,
- 0x3d, 0xae, 0x0d, 0x9c, 0x58, 0xb8, 0x5b, 0xd6, 0x2f, 0xf4, 0x9f, 0xbf,
- 0x4e, 0x76, 0xb1, 0x7f, 0xcd, 0xbf, 0xef, 0x0d, 0x49, 0xab, 0x17, 0xff,
- 0x48, 0x33, 0xd3, 0xd1, 0x4f, 0xb8, 0xb1, 0x5f, 0x44, 0x01, 0x1e, 0x56,
- 0x27, 0x1f, 0xd2, 0xde, 0x90, 0xfe, 0x35, 0xe8, 0x5a, 0xdf, 0xff, 0xb5,
- 0xdf, 0x98, 0xce, 0x7d, 0xbb, 0x06, 0x9c, 0x6b, 0x17, 0xef, 0x30, 0x88,
- 0xd5, 0x8a, 0x94, 0x41, 0x89, 0x6a, 0xfe, 0xc3, 0x30, 0x84, 0x05, 0x8b,
- 0xf4, 0x33, 0xd2, 0x05, 0x8b, 0xa4, 0xf1, 0x9e, 0xb7, 0x65, 0xd7, 0xff,
- 0x37, 0x0a, 0x7d, 0xcc, 0xde, 0xc6, 0xac, 0x5f, 0xff, 0xfc, 0x03, 0xbc,
- 0x3e, 0xed, 0xe6, 0x1e, 0x0f, 0x3c, 0xc7, 0x6d, 0x2c, 0x57, 0x11, 0xcb,
- 0xe2, 0xf1, 0x23, 0x5f, 0xb5, 0x83, 0xdf, 0x2b, 0x17, 0xfe, 0xfb, 0xee,
- 0xf5, 0xf6, 0x3c, 0xf4, 0xb1, 0x6e, 0x96, 0x2f, 0x14, 0x98, 0xb1, 0x76,
- 0x73, 0x0f, 0xd3, 0xa4, 0x43, 0x89, 0xd3, 0x23, 0x60, 0xa1, 0x3d, 0x7e,
- 0x8c, 0xf2, 0x39, 0x58, 0xa8, 0xd9, 0xb7, 0xb0, 0x21, 0x1c, 0xaa, 0x3c,
- 0x8c, 0xac, 0xd8, 0x4f, 0xf5, 0x0c, 0xbe, 0xe3, 0x21, 0x8a, 0x3a, 0x6d,
- 0x14, 0xfe, 0x3e, 0xde, 0x43, 0x4f, 0xd1, 0xae, 0xef, 0x8c, 0x20, 0x32,
- 0x6b, 0xff, 0x49, 0xa6, 0xc9, 0x67, 0xbe, 0xcb, 0x17, 0xff, 0xd1, 0xce,
- 0xb6, 0x8f, 0x0a, 0x3c, 0x11, 0x79, 0x62, 0xfd, 0xc9, 0x8f, 0x0c, 0x58,
- 0xb4, 0x91, 0xfe, 0xf1, 0x4e, 0xff, 0xf8, 0x7e, 0x13, 0xf7, 0xe0, 0x60,
- 0xf6, 0xfd, 0x96, 0x2f, 0xff, 0x9b, 0x78, 0xe4, 0xa7, 0xdc, 0xc1, 0x17,
- 0x96, 0x2f, 0xff, 0xb7, 0xbf, 0xfe, 0xc3, 0xcf, 0x70, 0x45, 0xe5, 0x8b,
- 0xef, 0x10, 0xbc, 0xb1, 0x70, 0x89, 0x62, 0xf6, 0x1f, 0x34, 0x6e, 0xbe,
- 0x47, 0x52, 0x8b, 0xdf, 0xc2, 0x32, 0x86, 0x9d, 0x73, 0x93, 0x71, 0x53,
- 0xd1, 0x86, 0xdf, 0x66, 0x8d, 0x65, 0x8a, 0x96, 0xc9, 0x3b, 0x29, 0xcf,
- 0x4d, 0x18, 0x23, 0xca, 0x6a, 0x12, 0x1d, 0xe3, 0x0c, 0x31, 0x22, 0xff,
- 0xb0, 0x0f, 0xac, 0xdf, 0x83, 0x48, 0x08, 0x68, 0x6e, 0x30, 0xc4, 0x8b,
- 0xc6, 0x18, 0x62, 0x45, 0xfc, 0xf1, 0x8f, 0xf3, 0xc4, 0x80, 0x86, 0x86,
- 0x89, 0x19, 0x06, 0x26, 0x6c, 0x9d, 0xdf, 0xba, 0x61, 0x86, 0x74, 0x80,
- 0x86, 0xce, 0xf1, 0x86, 0x18, 0x91, 0x7b, 0x93, 0xa4, 0x80, 0x86, 0x86,
- 0xf9, 0xcb, 0xbf, 0x2c, 0x58, 0x0c, 0x8b, 0x0f, 0x2f, 0x18, 0x5f, 0x76,
- 0xce, 0xc4, 0xb1, 0x7f, 0xcc, 0x5d, 0x16, 0x18, 0xe0, 0x58, 0xbf, 0x84,
- 0xf1, 0x90, 0xfb, 0x58, 0xbe, 0x98, 0x3f, 0x4b, 0x15, 0xf3, 0xd3, 0x23,
- 0x0b, 0xd9, 0x13, 0x2c, 0x50, 0xcd, 0xf0, 0x64, 0x37, 0xee, 0x0a, 0x3d,
- 0x92, 0x58, 0xbf, 0x0d, 0xb7, 0xc8, 0xd6, 0x2f, 0xb0, 0xb3, 0x71, 0x62,
- 0xb4, 0x79, 0xc7, 0x2a, 0xa6, 0x44, 0xe8, 0x6f, 0x77, 0xff, 0x7d, 0xe0,
- 0x4e, 0x6c, 0x44, 0xd1, 0x2c, 0x5f, 0xc1, 0x6a, 0x58, 0x63, 0x81, 0x62,
- 0xf1, 0x86, 0x18, 0x91, 0x78, 0x9c, 0xc4, 0x80, 0x86, 0x86, 0xf8, 0x78,
- 0x43, 0x58, 0xbf, 0xe8, 0xe7, 0xbe, 0x31, 0x60, 0x16, 0x2f, 0x9e, 0x0c,
- 0x05, 0x8a, 0xe8, 0xff, 0xb4, 0x45, 0xf3, 0xab, 0xf6, 0x46, 0x7c, 0x3a,
- 0xc5, 0xfd, 0x31, 0x8f, 0xf3, 0xc5, 0x8b, 0xfd, 0x39, 0xd6, 0x6f, 0x61,
- 0xac, 0x5b, 0x3a, 0x3e, 0x42, 0x2f, 0xa0, 0xb5, 0x4f, 0x9c, 0x6a, 0xd9,
- 0x0a, 0xd2, 0x30, 0xd9, 0x84, 0x6d, 0xfd, 0xfc, 0xdf, 0x9e, 0xe2, 0xc5,
- 0x74, 0xaa, 0xe8, 0x12, 0x8b, 0x7c, 0xbb, 0x50, 0x5c, 0xc0, 0x19, 0x06,
- 0xa1, 0x95, 0xf8, 0x5f, 0x94, 0xad, 0xdb, 0xfd, 0xe8, 0x67, 0xfe, 0xf0,
- 0x58, 0xb8, 0xdd, 0x2c, 0x5f, 0x33, 0x90, 0xd6, 0x2e, 0x10, 0x16, 0x28,
- 0x66, 0xe4, 0x04, 0x37, 0xe9, 0xc8, 0x9b, 0x4b, 0x15, 0x19, 0xe4, 0x91,
- 0x0d, 0xd1, 0xf9, 0x62, 0xa5, 0x79, 0x77, 0x27, 0x3d, 0x8d, 0x5d, 0xe8,
- 0xd1, 0xe1, 0x36, 0x44, 0x57, 0xdb, 0x3f, 0xce, 0x96, 0x2f, 0x80, 0xc5,
- 0xe5, 0x8a, 0x8c, 0xf2, 0x78, 0x4f, 0x70, 0x5b, 0xd8, 0x96, 0x2f, 0x72,
- 0x7c, 0xb1, 0x70, 0x0c, 0x58, 0xbf, 0x70, 0x44, 0x19, 0xd6, 0x2d, 0xc8,
- 0x8f, 0x81, 0xc7, 0x7c, 0x33, 0x58, 0x8d, 0xbe, 0xc8, 0xfd, 0x08, 0x3b,
- 0xf6, 0x19, 0x9a, 0x8d, 0x62, 0xfd, 0xd4, 0xfe, 0x4e, 0xb1, 0x73, 0xf9,
- 0x62, 0xfb, 0x71, 0xc8, 0x11, 0x9f, 0x56, 0x15, 0x11, 0x4d, 0xfe, 0xc3,
- 0x4d, 0x78, 0x40, 0x6b, 0x17, 0xf3, 0xb8, 0xfc, 0x27, 0x58, 0xbe, 0x1b,
- 0x90, 0x30, 0xf8, 0xc8, 0xda, 0xb1, 0x1c, 0x02, 0x85, 0x55, 0xff, 0x0c,
- 0xed, 0xae, 0x39, 0x01, 0x62, 0xff, 0xe0, 0x7b, 0xf3, 0x08, 0x37, 0x30,
- 0x6b, 0x17, 0xfe, 0xf6, 0x6a, 0x77, 0xf8, 0x9c, 0x0b, 0x16, 0x84, 0xa2,
- 0x15, 0x91, 0x69, 0x91, 0xcb, 0x14, 0x2f, 0xaf, 0xfa, 0x4a, 0x04, 0x3f,
- 0xcc, 0x6b, 0x17, 0xf0, 0xf3, 0x5b, 0x27, 0x1a, 0xc5, 0xef, 0xb4, 0x49,
- 0x15, 0xa3, 0xd0, 0xe1, 0x95, 0xff, 0x3f, 0x7e, 0xc8, 0x85, 0xa3, 0x56,
- 0x2d, 0xd3, 0x1e, 0xf8, 0x88, 0xaf, 0xf1, 0x67, 0x70, 0xe3, 0x1a, 0xb1,
- 0x70, 0x7a, 0x58, 0xbd, 0xa1, 0x46, 0xb1, 0x79, 0xf4, 0x6a, 0xc5, 0x8e,
- 0xb1, 0x46, 0x9f, 0x46, 0x86, 0x5c, 0x7f, 0x78, 0xf5, 0xff, 0x87, 0xf9,
- 0xe6, 0x6a, 0x39, 0x82, 0xc5, 0x8d, 0x58, 0xbf, 0xfb, 0x3a, 0xfc, 0xff,
- 0x35, 0xa9, 0x35, 0x62, 0xf3, 0x03, 0x92, 0x7b, 0x3a, 0x13, 0xad, 0xa9,
- 0xd3, 0x47, 0x09, 0xd8, 0x8f, 0x8a, 0x13, 0x37, 0xfd, 0x99, 0xd0, 0x27,
- 0x3b, 0x82, 0xc5, 0xff, 0x85, 0xcc, 0x29, 0xf8, 0xc3, 0x3a, 0xc5, 0xff,
- 0xde, 0xd0, 0xb9, 0xf7, 0x80, 0x18, 0x6b, 0x17, 0xd2, 0xe7, 0xde, 0x91,
- 0x7b, 0x59, 0xb1, 0xac, 0x5f, 0xf3, 0x1a, 0x19, 0x4f, 0xda, 0x35, 0x8b,
- 0xff, 0xbe, 0xce, 0x00, 0x48, 0x27, 0xfc, 0x58, 0xbf, 0xbf, 0x87, 0x3b,
- 0xc1, 0x62, 0xf1, 0x86, 0x18, 0x91, 0x7f, 0x8b, 0xdf, 0x69, 0x28, 0xd2,
- 0x02, 0x1a, 0x1b, 0xe9, 0xd3, 0xfd, 0x62, 0xf4, 0x83, 0x20, 0x8b, 0x6c,
- 0x4f, 0xf2, 0x2d, 0x62, 0x72, 0xdd, 0x11, 0x78, 0xec, 0x38, 0x7d, 0x5f,
- 0xda, 0x80, 0x70, 0x68, 0xd6, 0x2f, 0x38, 0x38, 0xb1, 0x76, 0x6d, 0xc3,
- 0xce, 0xf1, 0x8d, 0x74, 0xa9, 0xe8, 0xf1, 0xdd, 0x6f, 0x84, 0x95, 0xff,
- 0x38, 0x0b, 0x22, 0x84, 0xf6, 0xb1, 0x52, 0xac, 0xeb, 0x25, 0x60, 0x32,
- 0x05, 0xff, 0x39, 0x16, 0x6b, 0x4d, 0x12, 0xc5, 0xfc, 0x41, 0xe8, 0x85,
- 0x05, 0x8b, 0xf7, 0x0e, 0xda, 0xe2, 0xc5, 0x46, 0x89, 0x07, 0x38, 0x01,
- 0x7d, 0xff, 0xfd, 0x0f, 0xbc, 0x3a, 0xfb, 0x7a, 0x19, 0xff, 0xbc, 0x16,
- 0x2f, 0xd2, 0x09, 0xff, 0x16, 0x2b, 0x11, 0x0a, 0x05, 0xdb, 0xff, 0x83,
- 0x29, 0x61, 0xff, 0x21, 0xf6, 0x58, 0xbf, 0xf0, 0x73, 0xa0, 0x7b, 0xee,
- 0x36, 0x58, 0xbf, 0xe8, 0x45, 0x07, 0xf7, 0x1a, 0x56, 0x2f, 0xff, 0x9f,
- 0xc2, 0x96, 0x9e, 0xfa, 0xfe, 0x77, 0xc5, 0x8b, 0xf6, 0xb4, 0xde, 0xe2,
+ 0xce, 0xb1, 0x60, 0x2c, 0x50, 0x8d, 0x61, 0x83, 0x57, 0xfc, 0x0e, 0x7b,
+ 0x30, 0xbd, 0xc5, 0x8b, 0xf4, 0xd2, 0x8f, 0x71, 0x62, 0xfa, 0x34, 0x6c,
+ 0x2c, 0x5d, 0xc0, 0x2c, 0x56, 0xd4, 0xce, 0x3e, 0xf0, 0xe4, 0x40, 0x39,
+ 0xf1, 0x56, 0xe1, 0x1d, 0xff, 0xff, 0xf7, 0xf0, 0x81, 0x85, 0xef, 0xe7,
+ 0xe3, 0x26, 0x6d, 0x4d, 0xf6, 0xef, 0xcb, 0x17, 0xf6, 0x9b, 0xaf, 0xe4,
+ 0xcb, 0x17, 0xa5, 0xcc, 0x58, 0xbf, 0xfd, 0x93, 0x38, 0x33, 0xd1, 0xbd,
+ 0x88, 0x0b, 0x14, 0xe7, 0xd0, 0x43, 0xb4, 0x74, 0x5c, 0x7a, 0x13, 0x17,
+ 0xfd, 0x82, 0x1e, 0xd8, 0xe4, 0x49, 0x62, 0xf8, 0xbc, 0xdf, 0x58, 0xad,
+ 0xa7, 0xba, 0xe7, 0x75, 0x89, 0xef, 0x3c, 0x66, 0xc0, 0x84, 0x2d, 0xe8,
+ 0xc3, 0x16, 0x2f, 0xf3, 0x70, 0xa3, 0xd1, 0x25, 0x8a, 0x23, 0xcf, 0xe0,
+ 0xed, 0xf4, 0x77, 0xc7, 0x58, 0xad, 0x8d, 0xf6, 0x21, 0xe2, 0x7c, 0xea,
+ 0x78, 0x6d, 0x48, 0xe8, 0x71, 0x86, 0xe5, 0xb8, 0x7a, 0xea, 0x3f, 0x4e,
+ 0xe3, 0x0c, 0x69, 0x5d, 0x3b, 0xb0, 0xad, 0x9a, 0x14, 0x9a, 0x84, 0x2f,
+ 0xc8, 0x5e, 0x91, 0xb8, 0x17, 0x87, 0xb9, 0x42, 0x83, 0xd1, 0xac, 0x0a,
+ 0x51, 0xd6, 0xf8, 0x44, 0x86, 0x43, 0x7f, 0xa3, 0xe2, 0xf1, 0x39, 0xab,
+ 0x17, 0xb9, 0xce, 0x2c, 0x5f, 0xff, 0x31, 0x61, 0xe0, 0x32, 0x14, 0x8b,
+ 0x0e, 0xb1, 0x7e, 0x21, 0x4b, 0x38, 0xb1, 0x7f, 0xd8, 0x3f, 0xc7, 0xbf,
+ 0x1c, 0x58, 0xb8, 0x6d, 0x87, 0xc2, 0x45, 0x17, 0xff, 0x9a, 0x3d, 0xf1,
+ 0x39, 0xe6, 0x94, 0x4e, 0xb1, 0x7f, 0x16, 0x6b, 0x59, 0xda, 0xc5, 0x7c,
+ 0xfe, 0xb8, 0x99, 0x7f, 0xe7, 0xf1, 0x3f, 0x3e, 0xe0, 0xe2, 0xc5, 0xfe,
+ 0xd4, 0x75, 0xfe, 0xdf, 0x75, 0x62, 0xa7, 0x3f, 0x7d, 0x1f, 0x5e, 0x28,
+ 0xe2, 0xc5, 0xf6, 0x16, 0x1d, 0x62, 0xff, 0xc2, 0x89, 0xb9, 0x04, 0x78,
+ 0xe2, 0xc5, 0x2c, 0x54, 0x22, 0x22, 0x43, 0x9c, 0x21, 0x11, 0xfd, 0xf8,
+ 0x4e, 0x33, 0xc2, 0xc5, 0xff, 0xf3, 0x14, 0x4e, 0xe3, 0xfc, 0x7c, 0xb0,
+ 0xd5, 0x8a, 0xe8, 0xfd, 0xf4, 0x51, 0x7f, 0xdf, 0x69, 0x7d, 0xe4, 0xc7,
+ 0x58, 0xbe, 0x28, 0x0b, 0x5b, 0x09, 0x62, 0xff, 0xdc, 0x62, 0xee, 0x5e,
+ 0x6e, 0x32, 0xc5, 0x62, 0x29, 0x9c, 0xe7, 0xc5, 0xd7, 0xcc, 0x4d, 0x32,
+ 0xc5, 0xf8, 0x07, 0x8d, 0x32, 0xc5, 0xfb, 0xdf, 0x81, 0x05, 0xd6, 0x2e,
+ 0xfb, 0xac, 0x54, 0x1f, 0x63, 0x94, 0x78, 0xb6, 0xff, 0xcc, 0x7c, 0x1f,
+ 0xdb, 0x85, 0x8b, 0x17, 0xc7, 0x81, 0xc2, 0xc5, 0x11, 0xef, 0xf0, 0xf6,
+ 0xa4, 0xba, 0xfb, 0x90, 0xaf, 0xea, 0x14, 0xad, 0x09, 0x99, 0xa1, 0x57,
+ 0xa8, 0x59, 0x9e, 0x19, 0x3f, 0x2e, 0x28, 0x47, 0x7a, 0x11, 0x97, 0xdf,
+ 0xc0, 0x3a, 0xc5, 0xc1, 0x61, 0xd6, 0x2f, 0x8a, 0x35, 0x25, 0x8b, 0xfe,
+ 0xfc, 0x49, 0x88, 0x85, 0xda, 0xc5, 0xff, 0x6e, 0x8f, 0xf1, 0x30, 0x89,
+ 0x96, 0x2f, 0xfa, 0x24, 0xde, 0x94, 0x10, 0x16, 0x2f, 0xfa, 0x33, 0xc1,
+ 0x80, 0x11, 0xda, 0xc5, 0xec, 0x23, 0x56, 0x2f, 0xfe, 0xfb, 0xf0, 0xa0,
+ 0x01, 0xc8, 0x5a, 0x58, 0xb6, 0x82, 0xa9, 0xc5, 0xc0, 0xee, 0x11, 0x31,
+ 0xce, 0x8f, 0x4e, 0x70, 0x17, 0x3b, 0xe0, 0xed, 0xfe, 0xd6, 0x49, 0xf4,
+ 0xe1, 0xac, 0x58, 0x96, 0x2f, 0xfa, 0x37, 0x49, 0xfd, 0x26, 0xde, 0xb1,
+ 0x7b, 0xf0, 0x35, 0x8b, 0xf8, 0xa3, 0xad, 0x44, 0x96, 0x2f, 0xff, 0x3b,
+ 0x7a, 0x42, 0x2f, 0x73, 0xef, 0x25, 0x80, 0xcd, 0x75, 0xf8, 0x6c, 0x2d,
+ 0x1a, 0xb1, 0x74, 0x7d, 0x62, 0x99, 0x1c, 0xff, 0x4b, 0x75, 0xbd, 0xe5,
+ 0x57, 0xfe, 0xe0, 0x7e, 0x62, 0x14, 0xb3, 0x8b, 0x17, 0x0f, 0x8b, 0x15,
+ 0x24, 0xee, 0x77, 0x63, 0x24, 0xf9, 0xe9, 0x20, 0x5f, 0xff, 0xd9, 0xde,
+ 0x71, 0xcb, 0xed, 0x1e, 0xf8, 0x9c, 0xeb, 0x17, 0xf6, 0xa5, 0xce, 0xcb,
+ 0x4b, 0x15, 0xb5, 0x73, 0xe2, 0x23, 0xad, 0xc7, 0xd6, 0x34, 0x78, 0xf2,
+ 0x89, 0x18, 0x4b, 0x57, 0x36, 0x2c, 0x5f, 0xef, 0x70, 0x5b, 0xbe, 0x7f,
+ 0xac, 0x51, 0xcf, 0x3b, 0x78, 0xb5, 0xee, 0x3f, 0x4b, 0x16, 0xc5, 0x8b,
+ 0xf0, 0x8e, 0xdf, 0x85, 0x8b, 0xf6, 0x6b, 0xa8, 0xc5, 0x8a, 0x9c, 0xf8,
+ 0x48, 0x44, 0x32, 0x8b, 0xfe, 0xc3, 0xe6, 0x9a, 0x77, 0x3a, 0xc5, 0xfc,
+ 0xfa, 0x82, 0x8f, 0xac, 0x5f, 0xf4, 0x17, 0x5b, 0x5b, 0x59, 0xd2, 0xc5,
+ 0xff, 0xed, 0xbe, 0xfe, 0x1f, 0x3a, 0x8f, 0xc1, 0xd6, 0x2f, 0x39, 0xf8,
+ 0xb1, 0x58, 0x7d, 0x4e, 0x9b, 0x40, 0x46, 0x37, 0xa1, 0x4d, 0x76, 0x4e,
+ 0xb1, 0x7e, 0xd6, 0x7b, 0xec, 0xb1, 0x7f, 0xd2, 0xcd, 0x6b, 0x3d, 0xf6,
+ 0x58, 0xbe, 0x8f, 0x86, 0x3d, 0x1f, 0x0f, 0x8a, 0x2f, 0xf8, 0xa3, 0xbd,
+ 0xc3, 0x7d, 0x9f, 0x58, 0xbb, 0xdb, 0x8b, 0x16, 0x73, 0x9e, 0xc9, 0x1f,
+ 0x5e, 0xdc, 0x60, 0x2c, 0x5f, 0xff, 0x17, 0x9d, 0xfe, 0x51, 0xee, 0x19,
+ 0x9f, 0x58, 0xb9, 0xf7, 0x56, 0x29, 0x91, 0x12, 0xe4, 0x1e, 0x4f, 0xbf,
+ 0xf6, 0x1f, 0x02, 0x66, 0x08, 0x2f, 0xc5, 0x8b, 0xf8, 0x31, 0xbe, 0xb0,
+ 0xeb, 0x17, 0xfe, 0xc1, 0xbc, 0x89, 0xf4, 0xf2, 0x58, 0xbe, 0xdf, 0x05,
+ 0x25, 0x8b, 0x6b, 0x6a, 0x24, 0x06, 0x5f, 0x87, 0xb5, 0xe4, 0xc2, 0xc3,
+ 0x86, 0xa5, 0xff, 0xb9, 0x1a, 0x97, 0xe3, 0xac, 0x25, 0x8b, 0xff, 0x8f,
+ 0xc7, 0x96, 0xa3, 0x90, 0x53, 0xac, 0x5f, 0xf4, 0x7b, 0xf8, 0x7c, 0xd6,
+ 0x2c, 0x5f, 0xbd, 0xf6, 0x8e, 0x2c, 0x5c, 0xe5, 0xa3, 0xe0, 0xe1, 0xc5,
+ 0xff, 0xf6, 0x0f, 0xf1, 0xc9, 0x37, 0x39, 0x1a, 0x92, 0xc5, 0x4e, 0x7f,
+ 0x9b, 0x85, 0x97, 0xff, 0xef, 0x47, 0xb8, 0x59, 0xf6, 0x8f, 0x7d, 0xe4,
+ 0xb1, 0x66, 0x58, 0xa6, 0x3e, 0x5f, 0xaa, 0x5f, 0xf4, 0x03, 0x83, 0x13,
+ 0xea, 0x4b, 0x17, 0xdd, 0x3b, 0xf4, 0xb8, 0x80, 0xcb, 0x64, 0x8f, 0xaf,
+ 0x47, 0x57, 0xfc, 0x77, 0xed, 0xe5, 0xc6, 0x92, 0xc5, 0xff, 0x47, 0xfa,
+ 0x6e, 0x3b, 0x4e, 0xb1, 0x68, 0xda, 0x89, 0xbc, 0x27, 0xd1, 0xd5, 0xe3,
+ 0xbc, 0x96, 0x2b, 0xe7, 0xa6, 0x03, 0x6b, 0x8b, 0x16, 0x2e, 0x70, 0x2c,
+ 0x54, 0x1e, 0x79, 0x11, 0x78, 0x5a, 0xdd, 0x2c, 0x56, 0x8f, 0x00, 0x8b,
+ 0x6b, 0x15, 0xeb, 0x3c, 0x64, 0x3c, 0x84, 0x58, 0x72, 0x82, 0x68, 0x6c,
+ 0x8d, 0x6e, 0x8e, 0x7b, 0x87, 0x96, 0x8a, 0x0e, 0xf3, 0xf8, 0x49, 0x82,
+ 0x15, 0xe5, 0x19, 0xcf, 0x0a, 0xbd, 0x38, 0x2b, 0x7c, 0x3f, 0xc6, 0xe2,
+ 0xc5, 0xff, 0xe3, 0xbf, 0xb8, 0x29, 0x7d, 0xd8, 0x9d, 0x62, 0xff, 0xfe,
+ 0x61, 0x96, 0x72, 0x35, 0xb7, 0x9f, 0x71, 0xc0, 0xd6, 0x2f, 0x6f, 0x8f,
+ 0xac, 0x54, 0x32, 0xd0, 0x24, 0x49, 0x8f, 0xed, 0x49, 0x06, 0x78, 0x56,
+ 0x80, 0x9b, 0x89, 0x21, 0xae, 0x5f, 0x9b, 0xcf, 0xb9, 0x8b, 0x17, 0xec,
+ 0xd4, 0x83, 0x92, 0xc5, 0xfe, 0x9f, 0x90, 0x77, 0xef, 0xcb, 0x17, 0xfe,
+ 0x6f, 0x4b, 0xed, 0xee, 0x7d, 0x96, 0x2a, 0x74, 0x4f, 0x91, 0x56, 0xf3,
+ 0x6b, 0x9f, 0xb5, 0x8b, 0xdf, 0x7d, 0xd5, 0x8b, 0xe8, 0x06, 0xe6, 0x2c,
+ 0x5f, 0x1c, 0xef, 0xe5, 0x8a, 0x92, 0x6f, 0x79, 0x0c, 0x93, 0x99, 0x00,
+ 0x63, 0xc4, 0x01, 0x92, 0xdf, 0xd8, 0x11, 0xdf, 0xfc, 0x58, 0xbf, 0xfb,
+ 0x39, 0xe7, 0xec, 0x30, 0x90, 0x52, 0x58, 0xb6, 0x2c, 0x5f, 0xfd, 0x84,
+ 0xf2, 0xfb, 0x9c, 0xef, 0x25, 0x8b, 0x4d, 0xb0, 0x1e, 0xa6, 0xc4, 0x23,
+ 0x7f, 0xff, 0x98, 0x53, 0xcc, 0xef, 0x3f, 0xb2, 0x62, 0x83, 0xfd, 0xd6,
+ 0x2f, 0xe9, 0xc6, 0xda, 0x8d, 0xeb, 0x17, 0xff, 0xee, 0x6d, 0xc1, 0xed,
+ 0xe6, 0x68, 0x07, 0xcd, 0xcc, 0x58, 0xa2, 0x44, 0x77, 0x8c, 0x6f, 0xff,
+ 0xf6, 0x6b, 0x6f, 0x5f, 0x61, 0xe9, 0x85, 0x38, 0x63, 0x79, 0xd6, 0x2f,
+ 0x4b, 0x47, 0x58, 0xbe, 0xeb, 0xed, 0x3a, 0xc5, 0xc4, 0x6f, 0xcf, 0x0d,
+ 0xc7, 0xaf, 0x78, 0x02, 0x58, 0xae, 0x91, 0xec, 0xd0, 0xab, 0x22, 0xdb,
+ 0xf1, 0xf6, 0x3d, 0x8f, 0x63, 0x0a, 0x2c, 0x5f, 0xff, 0xd2, 0xce, 0x36,
+ 0xb4, 0xc7, 0x0f, 0xdf, 0xc3, 0x3c, 0xb1, 0x50, 0x9f, 0x3e, 0x46, 0x30,
+ 0xc6, 0x8e, 0x7b, 0x7b, 0x8e, 0xcb, 0x17, 0xf1, 0x9f, 0x81, 0xb4, 0x2c,
+ 0x51, 0xcf, 0x29, 0xc7, 0x2f, 0xff, 0xbe, 0xed, 0xe8, 0x69, 0x61, 0x00,
+ 0x10, 0xb1, 0x79, 0xff, 0x0b, 0x17, 0x60, 0x16, 0x2d, 0x3f, 0xcd, 0x99,
+ 0x83, 0x97, 0xe0, 0xe3, 0x58, 0x4b, 0x17, 0xfd, 0xf8, 0xe7, 0xb9, 0x82,
+ 0x0b, 0xac, 0x5f, 0xfa, 0x1b, 0xff, 0xcf, 0x7f, 0x24, 0xb1, 0x7f, 0xb0,
+ 0xa5, 0x9c, 0x0c, 0xeb, 0x16, 0x21, 0xa2, 0xc3, 0x47, 0xde, 0x3e, 0xa8,
+ 0x4c, 0x37, 0x21, 0xb1, 0x7f, 0xfb, 0x3e, 0xdb, 0xe3, 0x35, 0x38, 0x9c,
+ 0x6b, 0x15, 0x32, 0xa2, 0x97, 0x84, 0x01, 0x91, 0x9b, 0x06, 0x4f, 0x7f,
+ 0xfa, 0x59, 0xdc, 0x83, 0x80, 0x6c, 0x98, 0x61, 0x89, 0x17, 0xe3, 0x99,
+ 0x8d, 0xbd, 0x62, 0xec, 0x29, 0x8f, 0xfc, 0x35, 0x4b, 0xff, 0xee, 0x73,
+ 0xe2, 0xea, 0x24, 0xda, 0x06, 0x12, 0xc5, 0x48, 0xff, 0xcc, 0x2e, 0xa8,
+ 0x4d, 0xb5, 0xe3, 0x4a, 0xbf, 0xfe, 0xd4, 0x87, 0xf8, 0xe1, 0x61, 0x8f,
+ 0xa3, 0x56, 0x2f, 0x00, 0x5c, 0x58, 0xbf, 0x66, 0x14, 0x49, 0x62, 0xdc,
+ 0x83, 0xc4, 0x21, 0xea, 0x74, 0x5e, 0x7a, 0x12, 0xd5, 0x0c, 0x97, 0xf1,
+ 0xae, 0xe1, 0x7b, 0x42, 0x73, 0x46, 0x7f, 0x95, 0xb0, 0xf0, 0x8a, 0x29,
+ 0x76, 0xe2, 0x87, 0x25, 0xef, 0xb1, 0x8b, 0x17, 0xfc, 0xc5, 0x2e, 0x05,
+ 0xa0, 0xa6, 0xc6, 0x14, 0x58, 0xbc, 0x1e, 0x8d, 0x58, 0xbe, 0x9b, 0x99,
+ 0x32, 0xc5, 0xf8, 0x11, 0xec, 0xdd, 0x58, 0xba, 0x6c, 0x58, 0xbf, 0x98,
+ 0xd3, 0x60, 0xbc, 0xb1, 0x61, 0xb9, 0xe3, 0xee, 0x0c, 0x5f, 0xdc, 0xd6,
+ 0x9a, 0x6e, 0x2c, 0x5f, 0xd9, 0xae, 0x9d, 0xfa, 0x54, 0x41, 0x25, 0xff,
+ 0xa2, 0x45, 0x9f, 0xf1, 0x40, 0x16, 0x2a, 0x0f, 0xe4, 0x8f, 0x2f, 0xfa,
+ 0x3d, 0x9a, 0xe9, 0xdf, 0xa5, 0x45, 0xf2, 0x5f, 0x9c, 0x7f, 0x83, 0x56,
+ 0x2f, 0xff, 0xed, 0x60, 0xff, 0x1d, 0xcb, 0x51, 0xee, 0x06, 0x52, 0x58,
+ 0xbf, 0xff, 0x08, 0x07, 0x79, 0x0d, 0xdc, 0xcc, 0x9a, 0x34, 0xb1, 0x6c,
+ 0x64, 0x5a, 0xf9, 0x7a, 0xff, 0xc5, 0x9e, 0xf3, 0x73, 0xd8, 0x05, 0x8b,
+ 0xb3, 0x81, 0x55, 0x4a, 0x63, 0x85, 0x4f, 0x44, 0x07, 0x47, 0x28, 0x6f,
+ 0x70, 0x9e, 0xb1, 0x57, 0x79, 0x4a, 0x7d, 0xa2, 0x57, 0x17, 0xbe, 0x5b,
+ 0x0d, 0xff, 0xd1, 0xf6, 0x37, 0x35, 0x39, 0xc5, 0xda, 0xc5, 0xff, 0x0f,
+ 0x58, 0x7c, 0x93, 0x8d, 0x62, 0xff, 0xfc, 0x27, 0xe6, 0x17, 0x5f, 0x61,
+ 0xff, 0x3b, 0x08, 0xb1, 0x50, 0xb9, 0xaf, 0x84, 0x0d, 0x2e, 0xc3, 0xe5,
+ 0xae, 0x90, 0x47, 0x37, 0xff, 0x7f, 0x00, 0x38, 0x1e, 0x69, 0xf8, 0xb1,
+ 0x7e, 0x8d, 0x60, 0xe1, 0x62, 0xfd, 0x2c, 0x00, 0x7e, 0x58, 0xbf, 0xbf,
+ 0xb9, 0xf6, 0xeb, 0xeb, 0x15, 0x08, 0xc8, 0x64, 0x47, 0x27, 0x11, 0x55,
+ 0xf8, 0x11, 0x2e, 0x62, 0xc5, 0xff, 0xf7, 0x5f, 0x8d, 0x67, 0x08, 0x4f,
+ 0x23, 0x5d, 0x62, 0xff, 0xfc, 0xfb, 0xf6, 0xf3, 0xee, 0xde, 0x8f, 0x7f,
+ 0x3c, 0xb1, 0x42, 0x45, 0x50, 0x6a, 0x37, 0xfe, 0x79, 0xff, 0x13, 0xe7,
+ 0xb9, 0x8b, 0x15, 0x07, 0xc8, 0x44, 0x97, 0xfd, 0xe8, 0x3f, 0xf3, 0x7e,
+ 0x71, 0x62, 0xff, 0xa0, 0xfc, 0x86, 0x9d, 0xfc, 0xb1, 0x52, 0x3f, 0x4f,
+ 0x1d, 0xdf, 0xfa, 0x77, 0xef, 0x73, 0x3c, 0x4f, 0xbd, 0x62, 0xff, 0x85,
+ 0xee, 0x6d, 0x07, 0x5c, 0x65, 0x8b, 0xff, 0xde, 0x82, 0xf7, 0x33, 0x0d,
+ 0x35, 0xe4, 0xb1, 0x7f, 0xff, 0xda, 0x7f, 0xf7, 0x2c, 0xf6, 0xde, 0x73,
+ 0x0b, 0xa7, 0x20, 0x2c, 0x56, 0x22, 0xd5, 0xd2, 0xef, 0xff, 0x4b, 0xf8,
+ 0x46, 0xf3, 0xcd, 0xec, 0x02, 0xc5, 0xfc, 0x6e, 0x7b, 0xd8, 0x35, 0x8b,
+ 0xff, 0x60, 0xe2, 0x51, 0xfc, 0x03, 0xac, 0x5f, 0xcf, 0x21, 0x49, 0xc6,
+ 0xb1, 0x7f, 0xff, 0xdf, 0x13, 0xcf, 0xa8, 0xfb, 0xb7, 0x39, 0x86, 0xb9,
+ 0x01, 0x62, 0xfc, 0xd3, 0xf3, 0x8e, 0xb1, 0x43, 0x44, 0x87, 0xd9, 0xef,
+ 0xff, 0xbd, 0xce, 0x46, 0x10, 0xff, 0x1f, 0x8e, 0x2c, 0x5e, 0x30, 0xc3,
+ 0x12, 0x2f, 0xdf, 0xce, 0x9f, 0x49, 0x1b, 0x26, 0x86, 0xff, 0xff, 0x4d,
+ 0xa8, 0xdf, 0xb4, 0xd7, 0xda, 0x1c, 0xdc, 0xdb, 0x9d, 0xf9, 0x62, 0xa1,
+ 0x33, 0xf7, 0x23, 0xf3, 0x80, 0x67, 0x97, 0xfd, 0xf6, 0x33, 0xd3, 0x6a,
+ 0x3c, 0xb1, 0x7f, 0xe6, 0xf0, 0xb3, 0xce, 0x7c, 0x25, 0x8a, 0x91, 0xfc,
+ 0xe8, 0xf2, 0xff, 0xa0, 0x1e, 0xc2, 0x96, 0x71, 0x62, 0xe3, 0x64, 0xb1,
+ 0x7a, 0x1b, 0xa5, 0x8b, 0xf6, 0x01, 0xc8, 0x12, 0x36, 0xdf, 0x19, 0xa6,
+ 0x46, 0x67, 0xc8, 0x89, 0xba, 0xa7, 0x5d, 0xbd, 0x1a, 0x2f, 0x50, 0xf3,
+ 0xec, 0x87, 0x49, 0x67, 0x2f, 0x01, 0xe9, 0x47, 0xfb, 0xe8, 0xe0, 0xae,
+ 0x7f, 0x2c, 0x5e, 0xe6, 0x4e, 0xb1, 0x71, 0x4e, 0x03, 0x6b, 0xe1, 0x7a,
+ 0x58, 0xa8, 0x37, 0x27, 0x2d, 0xa5, 0x8a, 0x58, 0xb7, 0x0c, 0x2e, 0x02,
+ 0x06, 0x59, 0xd6, 0x2d, 0x0b, 0x17, 0x9d, 0xa7, 0x23, 0x44, 0x21, 0x1b,
+ 0xff, 0xe6, 0xe9, 0x87, 0xc8, 0xfb, 0x90, 0xb3, 0xeb, 0x15, 0x24, 0x65,
+ 0xf1, 0x2f, 0xc6, 0x37, 0xf7, 0x0b, 0x27, 0x0e, 0x4b, 0x17, 0xe0, 0xfd,
+ 0xc1, 0x12, 0xc5, 0xa3, 0xb3, 0xda, 0x23, 0x0b, 0xfc, 0x51, 0xce, 0x34,
+ 0x12, 0xc5, 0x1c, 0xf6, 0x1c, 0x9e, 0xff, 0xfe, 0xfb, 0x97, 0x72, 0x0e,
+ 0x50, 0x52, 0x73, 0xe0, 0xd6, 0x2f, 0xfd, 0x23, 0x31, 0xb7, 0xe4, 0xa0,
+ 0x96, 0x29, 0x91, 0x38, 0x1a, 0xe5, 0xff, 0xec, 0xcf, 0x8f, 0xf1, 0xcc,
+ 0xfb, 0x01, 0x62, 0xfd, 0x34, 0xa3, 0x5c, 0x58, 0xbf, 0xd8, 0x42, 0x97,
+ 0x27, 0x75, 0x8b, 0x1b, 0xb4, 0xf7, 0x86, 0x55, 0x7f, 0xe1, 0x3c, 0xbe,
+ 0xdc, 0x13, 0xc9, 0x62, 0xff, 0xcd, 0xe9, 0xc5, 0xcd, 0xba, 0xd4, 0x2c,
+ 0x54, 0x2b, 0x16, 0x9e, 0x1c, 0x52, 0x85, 0xe8, 0xc8, 0xda, 0x14, 0xe0,
+ 0x2b, 0xf1, 0xfd, 0xf6, 0xd6, 0xf8, 0x96, 0x2f, 0xd9, 0x2f, 0xc6, 0x96,
+ 0x2f, 0x8d, 0xdb, 0xf6, 0x58, 0xae, 0x8f, 0xcf, 0x74, 0x97, 0x45, 0x17,
+ 0xe9, 0x10, 0xbb, 0x92, 0xc5, 0xdf, 0x65, 0x8b, 0xbb, 0xf7, 0x67, 0x83,
+ 0x31, 0x55, 0xf9, 0xbe, 0x6c, 0x76, 0xb1, 0x7e, 0xc1, 0x94, 0x76, 0xb1,
+ 0x6f, 0x41, 0xe9, 0x11, 0x55, 0xff, 0xff, 0xfb, 0xbf, 0x14, 0x1f, 0x83,
+ 0xfc, 0x73, 0x24, 0xc6, 0x9a, 0xfe, 0x28, 0x3f, 0x16, 0x2f, 0xf0, 0x24,
+ 0xde, 0xe0, 0x67, 0x58, 0xbf, 0xf7, 0x1e, 0x5c, 0xce, 0xa0, 0xec, 0xb1,
+ 0x5a, 0x3f, 0x5f, 0x1b, 0x5f, 0xf7, 0x5f, 0x60, 0x02, 0x35, 0x25, 0x8b,
+ 0xed, 0x4e, 0xd3, 0xac, 0x5d, 0xd9, 0x6d, 0x3e, 0x0c, 0x3b, 0xa8, 0x55,
+ 0x91, 0x8e, 0x8d, 0x08, 0x37, 0x26, 0x14, 0x3e, 0x83, 0x84, 0x15, 0xff,
+ 0x77, 0x0c, 0x7c, 0x2c, 0xdd, 0x58, 0xbd, 0xe7, 0xe9, 0x62, 0xff, 0xf4,
+ 0xb9, 0x83, 0xcf, 0xb3, 0xfb, 0xf0, 0xb1, 0x53, 0xa2, 0x8b, 0xa3, 0xbe,
+ 0xc7, 0xaf, 0xd3, 0xfe, 0x05, 0x8b, 0x17, 0xff, 0xd2, 0x83, 0xea, 0x1a,
+ 0x4f, 0xc7, 0x20, 0x2c, 0x5f, 0xcd, 0xcc, 0x18, 0x78, 0xb1, 0x7e, 0x08,
+ 0xc5, 0x9b, 0xd6, 0x2f, 0xec, 0x1b, 0x0b, 0xaf, 0xf4, 0x7b, 0x2e, 0x5d,
+ 0x7f, 0x72, 0x4c, 0x77, 0x92, 0xc5, 0xff, 0xf0, 0xf2, 0x42, 0x1b, 0x90,
+ 0x35, 0xac, 0x31, 0x62, 0xa1, 0x39, 0x4e, 0xca, 0x75, 0x0a, 0x70, 0x22,
+ 0x98, 0x5d, 0x7f, 0xb8, 0x59, 0xbf, 0xef, 0x25, 0x8b, 0xdc, 0x96, 0xf5,
+ 0x8b, 0xf0, 0xf5, 0x19, 0xe5, 0x8a, 0x63, 0xfd, 0xdd, 0x35, 0x22, 0x0b,
+ 0xff, 0xd1, 0x38, 0x7f, 0x8e, 0xfd, 0x93, 0x90, 0xd6, 0x2f, 0x3f, 0x50,
+ 0xb1, 0x58, 0xac, 0xc1, 0xa3, 0xc7, 0x78, 0x67, 0x11, 0x87, 0x93, 0xaf,
+ 0xf0, 0x0e, 0xe0, 0x3b, 0x81, 0x62, 0xff, 0xe7, 0x96, 0x0c, 0x99, 0xff,
+ 0x07, 0x58, 0xb9, 0xfe, 0xb1, 0x5f, 0x3d, 0x9f, 0x21, 0x5c, 0x67, 0x4b,
+ 0x17, 0xfc, 0x37, 0x0f, 0x44, 0xd0, 0x6a, 0xc5, 0xf4, 0x61, 0x78, 0x2a,
+ 0x7a, 0x83, 0x1a, 0xbf, 0xdf, 0xcd, 0xfb, 0x79, 0x2e, 0x96, 0x2b, 0x87,
+ 0xeb, 0xe3, 0xba, 0xf2, 0x61, 0xa2, 0x87, 0x5d, 0xff, 0xe2, 0xcf, 0x34,
+ 0x9c, 0xb3, 0xdf, 0x65, 0x8b, 0xe0, 0x07, 0xd8, 0x55, 0x62, 0xfe, 0x27,
+ 0xee, 0x4d, 0x8b, 0x17, 0xf8, 0x80, 0x59, 0xef, 0xe6, 0xd4, 0x4f, 0x62,
+ 0x3f, 0xca, 0xaf, 0xe2, 0xda, 0x1e, 0xbe, 0xeb, 0x17, 0xed, 0x00, 0xed,
+ 0xc5, 0x8b, 0xfe, 0x79, 0x6d, 0x86, 0x1e, 0x1d, 0x62, 0xb0, 0xf8, 0xc4,
+ 0x53, 0x4c, 0x98, 0x63, 0xab, 0x94, 0x25, 0x2f, 0xfd, 0xa6, 0x04, 0xff,
+ 0x8e, 0x0b, 0x8b, 0x17, 0xec, 0xd3, 0xf6, 0x62, 0xc5, 0xa4, 0xb1, 0x7f,
+ 0xfb, 0x07, 0xa6, 0x14, 0xe3, 0xfc, 0x14, 0xeb, 0x17, 0xfd, 0xf7, 0xe3,
+ 0x11, 0x47, 0x6b, 0x16, 0x30, 0x91, 0x09, 0xc4, 0xcb, 0x4f, 0x08, 0xbf,
+ 0xc8, 0x4b, 0x54, 0xe9, 0x8b, 0x72, 0x1d, 0x37, 0xfa, 0x62, 0x73, 0x3d,
+ 0x9f, 0x58, 0xbd, 0xfc, 0xe9, 0x62, 0xf1, 0x86, 0x18, 0x91, 0x7f, 0x02,
+ 0x0b, 0x3b, 0xf2, 0x46, 0xc9, 0xa1, 0xad, 0xa8, 0xb5, 0xdc, 0x35, 0x0c,
+ 0xfe, 0xff, 0xfe, 0x0b, 0xed, 0xeb, 0xec, 0x31, 0xe1, 0x9b, 0x7d, 0xcc,
+ 0x9d, 0x62, 0xbe, 0x89, 0xe1, 0x1b, 0x5e, 0x9f, 0xda, 0x58, 0xa8, 0x56,
+ 0x2c, 0xd1, 0xab, 0xbc, 0x6f, 0xa1, 0x91, 0xdf, 0xff, 0x9f, 0x50, 0xc3,
+ 0x82, 0x70, 0x72, 0x18, 0x6b, 0x17, 0xfd, 0x9b, 0xf1, 0x86, 0xee, 0x6a,
+ 0xc5, 0xff, 0xf9, 0xbd, 0xf8, 0xe6, 0x37, 0xb8, 0xc5, 0xdc, 0x96, 0x2b,
+ 0xa4, 0x70, 0xfd, 0x48, 0x2e, 0x75, 0x7d, 0xfe, 0x46, 0x96, 0x2f, 0xfa,
+ 0x45, 0x1b, 0x77, 0x1e, 0x7e, 0x2c, 0x5f, 0xfb, 0xaf, 0xb0, 0xde, 0x44,
+ 0x27, 0x58, 0xae, 0xcf, 0xfb, 0x47, 0xf7, 0xfe, 0xcf, 0xf4, 0xd0, 0x03,
+ 0xc4, 0x96, 0x2a, 0x13, 0x03, 0x68, 0x50, 0xe8, 0x8e, 0xff, 0x83, 0x8e,
+ 0x61, 0x81, 0x97, 0x96, 0x2a, 0x1d, 0x29, 0x2c, 0xe3, 0xd2, 0x9d, 0x24,
+ 0x1c, 0x64, 0x98, 0x75, 0xd4, 0x66, 0xdd, 0xc2, 0x51, 0xa7, 0x77, 0xe6,
+ 0x8c, 0x0b, 0x53, 0x83, 0x27, 0x97, 0x5f, 0xf9, 0xc3, 0x77, 0x53, 0x28,
+ 0xe6, 0xb9, 0x1e, 0x9f, 0xa5, 0xa4, 0x8a, 0x32, 0xad, 0xf1, 0x9c, 0x06,
+ 0x69, 0x7f, 0xcc, 0x53, 0xb9, 0x7b, 0x0e, 0xb1, 0x7b, 0xa1, 0x76, 0xb1,
+ 0x74, 0x01, 0x62, 0xb0, 0xfb, 0xdc, 0xe3, 0xc4, 0x17, 0xff, 0x1a, 0x1f,
+ 0x9b, 0x85, 0x9b, 0xd8, 0x6b, 0x17, 0xf1, 0x60, 0xfe, 0xe6, 0x2c, 0x56,
+ 0x8f, 0xd8, 0xe9, 0x17, 0xff, 0xfe, 0x2c, 0x60, 0x6d, 0xfb, 0xfb, 0xc2,
+ 0x9f, 0x68, 0x7a, 0xd6, 0x4e, 0xb1, 0x7c, 0xc4, 0x0e, 0x2c, 0x5e, 0x27,
+ 0x3a, 0xc5, 0xff, 0xb8, 0xda, 0x7f, 0xb7, 0x22, 0x4b, 0x17, 0xf0, 0xff,
+ 0x9e, 0xdc, 0xc5, 0x8b, 0x34, 0x93, 0x21, 0xe9, 0xd3, 0xe4, 0x5e, 0x1c,
+ 0x30, 0xfa, 0xff, 0xfe, 0x21, 0xfd, 0xdb, 0xc0, 0x62, 0x97, 0x30, 0x80,
+ 0xb1, 0x50, 0x9f, 0x77, 0xe3, 0x43, 0x12, 0x95, 0xfe, 0x23, 0x78, 0xda,
+ 0x79, 0x2c, 0x5f, 0x13, 0xf7, 0xe5, 0x8b, 0xfe, 0xf3, 0xf7, 0x92, 0xfc,
+ 0x69, 0x62, 0xf6, 0x10, 0x16, 0x2f, 0xee, 0xa3, 0xb2, 0x83, 0x16, 0x2f,
+ 0xf4, 0x87, 0xf1, 0x1c, 0x78, 0xb1, 0x78, 0x3d, 0xcc, 0x58, 0xac, 0x3d,
+ 0x60, 0x1a, 0xdf, 0x67, 0xa6, 0x92, 0xc5, 0xff, 0xc1, 0x0a, 0x02, 0x71,
+ 0xc8, 0x30, 0x71, 0x62, 0xd0, 0xb1, 0x5f, 0x3f, 0xe7, 0x24, 0xf2, 0x4d,
+ 0xcd, 0x0b, 0x17, 0xfe, 0xcf, 0x46, 0xb9, 0xf8, 0x2f, 0x2e, 0x20, 0x82,
+ 0xfe, 0xcd, 0x74, 0xef, 0xd2, 0xa2, 0x08, 0x36, 0x4f, 0x2e, 0xf4, 0x0d,
+ 0x96, 0x2a, 0x0f, 0xb3, 0x8a, 0x17, 0xfe, 0x22, 0xc3, 0x5f, 0x0e, 0xe4,
+ 0xb1, 0x76, 0xf1, 0xac, 0x5e, 0xdf, 0x07, 0x58, 0xbe, 0xef, 0x99, 0xa5,
+ 0x8b, 0xf4, 0xf9, 0xa8, 0x92, 0xc5, 0xf6, 0xb4, 0xc6, 0x2c, 0x51, 0xcf,
+ 0x37, 0xe5, 0x35, 0x08, 0x93, 0x77, 0x1b, 0xfb, 0x74, 0x66, 0x39, 0x49,
+ 0x62, 0xa1, 0x35, 0xb9, 0xcf, 0x30, 0x68, 0xa1, 0x64, 0x22, 0x1b, 0xff,
+ 0xff, 0xd0, 0x5d, 0x72, 0x0b, 0xdc, 0xc1, 0x1c, 0x3e, 0x3e, 0xa3, 0xac,
+ 0x25, 0x8b, 0xff, 0xd3, 0x49, 0x8b, 0xd0, 0x09, 0x89, 0xa6, 0x58, 0xb8,
+ 0xa6, 0x58, 0xb4, 0x0c, 0xf9, 0x31, 0x32, 0xff, 0xfd, 0x1e, 0xfb, 0xcd,
+ 0xc7, 0x6e, 0x89, 0xf3, 0xa5, 0x8a, 0x85, 0xde, 0xf9, 0xcd, 0x30, 0x8c,
+ 0xd3, 0xae, 0x87, 0x35, 0x08, 0x6f, 0xc2, 0x7d, 0xcb, 0x81, 0x0c, 0xd2,
+ 0x8d, 0xf3, 0xc9, 0xdb, 0xe1, 0xb9, 0xb8, 0x4d, 0x7f, 0x88, 0x4f, 0x33,
+ 0xbc, 0xeb, 0x16, 0x92, 0xc5, 0xe8, 0xd0, 0x16, 0x28, 0x66, 0xbd, 0x84,
+ 0xaf, 0x3e, 0xa7, 0x58, 0xa1, 0xa2, 0x87, 0xec, 0x66, 0x10, 0x5e, 0x99,
+ 0x8c, 0x58, 0xbf, 0x36, 0x8b, 0x27, 0x58, 0xa6, 0x3c, 0x7f, 0x8f, 0xdd,
+ 0xcf, 0xac, 0x5f, 0xf4, 0xf3, 0x37, 0xfd, 0x19, 0x3a, 0xc5, 0x68, 0xfd,
+ 0x40, 0x42, 0x43, 0x17, 0xed, 0x47, 0x58, 0x4b, 0x15, 0x87, 0xac, 0xe5,
+ 0xd7, 0xf7, 0xf3, 0xde, 0x63, 0xac, 0x5f, 0xfd, 0xc1, 0x93, 0x4e, 0x1e,
+ 0x8a, 0x31, 0x62, 0xfe, 0xf0, 0x79, 0xf7, 0xed, 0x62, 0xf7, 0x00, 0xeb,
+ 0x15, 0xda, 0x30, 0x3e, 0x5c, 0x48, 0xbe, 0x30, 0xbf, 0xe2, 0x9f, 0x34,
+ 0x02, 0x10, 0x16, 0x2f, 0xf7, 0x0c, 0x71, 0xc7, 0x7c, 0x58, 0xbf, 0xb3,
+ 0xbf, 0x6b, 0x50, 0xb1, 0x7f, 0xf7, 0x09, 0xfc, 0xe7, 0x0e, 0x27, 0xc5,
+ 0x8a, 0x19, 0xfa, 0x70, 0xbe, 0xa1, 0x34, 0x36, 0x3d, 0x73, 0xa1, 0x42,
+ 0xaa, 0xff, 0x9d, 0xbc, 0xe7, 0x72, 0x02, 0xc5, 0xed, 0xff, 0xc5, 0x8b,
+ 0x75, 0xf3, 0xd6, 0x0c, 0xde, 0xf8, 0x5e, 0x82, 0x58, 0xac, 0x3c, 0xce,
+ 0x15, 0x5f, 0xb7, 0x8f, 0xf1, 0xc5, 0x8b, 0x1d, 0x62, 0xff, 0x47, 0x87,
+ 0xf1, 0x3f, 0x16, 0x03, 0x2c, 0xae, 0x0a, 0xf4, 0xb1, 0x7f, 0xf6, 0x75,
+ 0xf8, 0xfe, 0x6b, 0x50, 0x6a, 0xc5, 0xc0, 0x85, 0x8b, 0x0f, 0x47, 0xba,
+ 0x04, 0x6a, 0xd2, 0x28, 0x89, 0xea, 0xf8, 0xa3, 0xb0, 0x2c, 0x53, 0x1e,
+ 0x28, 0x64, 0x57, 0xf8, 0x4e, 0x3f, 0xc7, 0xb8, 0xb1, 0x7c, 0x59, 0xbf,
+ 0x16, 0x2e, 0x79, 0xfc, 0x7a, 0xe1, 0x9a, 0x58, 0xd5, 0x8b, 0xbb, 0x02,
+ 0xc5, 0xf3, 0xfa, 0x31, 0x62, 0xa0, 0xf3, 0x58, 0x4f, 0xe3, 0x37, 0xfb,
+ 0x34, 0xc0, 0x3b, 0xc9, 0x62, 0xe6, 0x25, 0x8b, 0xfe, 0x82, 0x34, 0x6d,
+ 0x21, 0x69, 0x62, 0xc6, 0x2c, 0x50, 0xcf, 0x8c, 0xe2, 0xc1, 0x9d, 0x5e,
+ 0x21, 0x4e, 0xb1, 0x7a, 0x72, 0x85, 0x8b, 0xf7, 0xde, 0x58, 0x4b, 0x17,
+ 0xf3, 0x78, 0xb3, 0xec, 0xb1, 0x73, 0x4c, 0xb1, 0x7c, 0x12, 0x34, 0x6a,
+ 0xc5, 0xbf, 0xb5, 0x12, 0x30, 0x4e, 0xe5, 0x81, 0x06, 0x2f, 0xfa, 0x39,
+ 0xf6, 0xd6, 0x9e, 0x4b, 0x15, 0x87, 0xfc, 0x48, 0xb7, 0x39, 0x9b, 0x55,
+ 0x2e, 0x8c, 0xb7, 0x21, 0x2d, 0xf3, 0x07, 0x1e, 0xf4, 0x65, 0x97, 0xf4,
+ 0x4f, 0xee, 0x67, 0x96, 0x2a, 0x19, 0x0f, 0xf2, 0x94, 0x47, 0x90, 0xe2,
+ 0x62, 0x1d, 0x1e, 0xfe, 0x32, 0xb7, 0x79, 0x29, 0x5b, 0x26, 0x38, 0x5f,
+ 0xdc, 0x61, 0x8f, 0x09, 0x62, 0xff, 0xff, 0xec, 0xf4, 0x1c, 0x79, 0xe8,
+ 0xc2, 0x91, 0x67, 0x72, 0x8c, 0xf2, 0xc5, 0xff, 0xfb, 0xf9, 0xce, 0x66,
+ 0x0b, 0x53, 0xe0, 0x8b, 0xcb, 0x14, 0x48, 0xc5, 0xf3, 0x7d, 0xff, 0x7e,
+ 0x35, 0xe2, 0x8c, 0xed, 0x62, 0xff, 0xff, 0x9a, 0x78, 0x97, 0x35, 0xa6,
+ 0xee, 0x69, 0x3e, 0x8f, 0x9d, 0xac, 0x5f, 0xe8, 0x79, 0xdf, 0x4e, 0x1a,
+ 0xc5, 0xef, 0xe1, 0x0d, 0x1b, 0x1f, 0x39, 0xf3, 0x5d, 0x62, 0xa2, 0xc6,
+ 0x87, 0x97, 0xa1, 0xf5, 0x7e, 0x8d, 0x4d, 0xc9, 0xd6, 0x2f, 0xfb, 0xf1,
+ 0x9a, 0x97, 0x04, 0x75, 0x8a, 0x9c, 0xf9, 0x7a, 0x2b, 0xb9, 0xb8, 0xb1,
+ 0x78, 0xc1, 0x71, 0x62, 0xff, 0x4e, 0xfe, 0x00, 0x65, 0x25, 0x8a, 0x83,
+ 0xd5, 0xc1, 0xfb, 0xd1, 0x23, 0x56, 0x2f, 0xd9, 0xc9, 0xf0, 0xc5, 0x8b,
+ 0x9b, 0xa5, 0x8b, 0x7b, 0x69, 0xf0, 0x48, 0x7b, 0x70, 0xaa, 0xff, 0xde,
+ 0xfb, 0xc9, 0x87, 0xf8, 0x92, 0xc5, 0x39, 0xfc, 0x91, 0xd5, 0xfc, 0x19,
+ 0xf8, 0x63, 0xf6, 0xb1, 0x50, 0xa9, 0xeb, 0x21, 0x3e, 0x69, 0x26, 0x9b,
+ 0x1e, 0x1f, 0x3e, 0x20, 0xbf, 0xfe, 0xc3, 0x3a, 0x2c, 0x9c, 0xb3, 0xdf,
+ 0x63, 0x16, 0x2f, 0xb0, 0x1a, 0x85, 0x8a, 0x9c, 0xfd, 0x3e, 0xa5, 0x7f,
+ 0xfb, 0xed, 0xd4, 0x37, 0xbf, 0x06, 0x67, 0xd6, 0x2f, 0xf7, 0x9b, 0xf8,
+ 0x59, 0xc5, 0x8a, 0xe8, 0xff, 0x43, 0x4b, 0xbd, 0x29, 0x62, 0xc5, 0xd0,
+ 0x1a, 0xc5, 0x76, 0x6d, 0x5c, 0x76, 0xff, 0x44, 0x83, 0xe0, 0x03, 0xe9,
+ 0x62, 0x98, 0xf6, 0x7c, 0x43, 0x62, 0x92, 0x34, 0xc7, 0x0b, 0x2a, 0x92,
+ 0x74, 0x19, 0x1b, 0x9d, 0xed, 0x67, 0xd6, 0x2f, 0x71, 0x8e, 0xb1, 0x5a,
+ 0x37, 0x5e, 0x1d, 0xbf, 0xbe, 0xfe, 0xfb, 0x9d, 0x62, 0xec, 0xed, 0x62,
+ 0xe6, 0x9d, 0x62, 0xa0, 0xff, 0xd8, 0x84, 0x32, 0xe0, 0x83, 0x17, 0xfb,
+ 0x85, 0x87, 0x3b, 0x79, 0x62, 0xff, 0xef, 0xb4, 0x16, 0xd7, 0x29, 0x31,
+ 0xd6, 0x2f, 0x9a, 0x66, 0x31, 0x62, 0xff, 0xcf, 0xd8, 0x7e, 0x6d, 0x40,
+ 0x82, 0xeb, 0x17, 0x07, 0x3a, 0xc5, 0x1c, 0xf7, 0xfc, 0x8b, 0x7e, 0x7e,
+ 0x14, 0x4c, 0xb1, 0x7e, 0xf8, 0x8a, 0x27, 0x58, 0xbb, 0x7e, 0x96, 0x2f,
+ 0xff, 0xc2, 0x9c, 0xa3, 0x3f, 0xb3, 0x1e, 0xcf, 0x8b, 0x4b, 0x17, 0xb8,
+ 0x1f, 0x36, 0xa7, 0x5a, 0x34, 0x4c, 0x84, 0x19, 0xa4, 0x4c, 0x50, 0x45,
+ 0x21, 0x8d, 0x57, 0x4a, 0x97, 0xbd, 0x1f, 0x05, 0xc4, 0x62, 0xc5, 0xfb,
+ 0x87, 0xcf, 0x71, 0x62, 0xfe, 0x06, 0xa3, 0xac, 0x25, 0x8b, 0xff, 0x1b,
+ 0x9e, 0x6f, 0xe7, 0xa3, 0x4b, 0x15, 0x07, 0xda, 0xc5, 0xd7, 0xe7, 0x91,
+ 0x34, 0x2c, 0x5f, 0x3f, 0x98, 0x0b, 0x17, 0xc5, 0xec, 0x25, 0x8a, 0xf9,
+ 0xe1, 0xb9, 0x15, 0xfd, 0x87, 0xcc, 0x23, 0x56, 0x29, 0x62, 0xfe, 0xf7,
+ 0x33, 0x7f, 0xd9, 0x62, 0x8d, 0x37, 0x8e, 0x19, 0x63, 0x46, 0x88, 0xa2,
+ 0x69, 0xa8, 0x46, 0xa3, 0xc2, 0xae, 0xff, 0x89, 0xcc, 0x9a, 0x4f, 0xa9,
+ 0x2c, 0x5f, 0xcd, 0xac, 0xdf, 0x1b, 0xab, 0x15, 0x31, 0xf6, 0xfc, 0xee,
+ 0xfe, 0x6d, 0x6a, 0x30, 0x96, 0x2f, 0xfa, 0x25, 0xcc, 0xe8, 0xa3, 0x4b,
+ 0x14, 0x69, 0xf2, 0xe8, 0xb2, 0xcc, 0xb1, 0x7f, 0x71, 0xb5, 0xd7, 0xf1,
+ 0x62, 0xf1, 0x39, 0xb8, 0x7c, 0x7d, 0x11, 0xf6, 0x23, 0x50, 0xbe, 0xe7,
+ 0x28, 0x71, 0x64, 0xa9, 0xbe, 0x8b, 0x18, 0x63, 0x50, 0x96, 0x39, 0x01,
+ 0x46, 0x7b, 0xc8, 0x49, 0x8a, 0x1d, 0x77, 0xff, 0xd3, 0xe6, 0xa7, 0x6f,
+ 0x4b, 0x35, 0xa7, 0x92, 0xc5, 0xc6, 0xf9, 0x62, 0xff, 0xf3, 0x7e, 0x3f,
+ 0x9d, 0xf1, 0xbf, 0x03, 0x58, 0xbd, 0xd3, 0x0d, 0x62, 0xf8, 0xb3, 0x27,
+ 0x58, 0xbe, 0xd3, 0x67, 0xd6, 0x2f, 0xf8, 0xef, 0xd8, 0x48, 0xe8, 0xe7,
+ 0x58, 0xbe, 0x8c, 0x0f, 0x60, 0x58, 0xbf, 0x40, 0xf6, 0x3d, 0x8c, 0x28,
+ 0xb1, 0x6d, 0x62, 0x27, 0x48, 0xf8, 0x32, 0x8b, 0xff, 0xfd, 0xc6, 0xe7,
+ 0x23, 0x9d, 0x13, 0xcf, 0x05, 0x13, 0x71, 0x62, 0xb1, 0x52, 0x59, 0xaa,
+ 0x5d, 0x0c, 0xf6, 0x94, 0xc3, 0xda, 0x22, 0x78, 0x5f, 0xf8, 0xd6, 0xfd,
+ 0xf6, 0xdc, 0x63, 0x56, 0x2f, 0xb0, 0x0d, 0xbd, 0x62, 0xf8, 0x00, 0x10,
+ 0x16, 0x2b, 0xa3, 0xf4, 0x22, 0xc0, 0xc9, 0x2f, 0x85, 0xaf, 0x32, 0xc5,
+ 0xf8, 0xa5, 0xc9, 0xc0, 0xb1, 0x7f, 0xf0, 0x23, 0x87, 0x86, 0xd6, 0x98,
+ 0xc5, 0x8b, 0xce, 0xf2, 0x58, 0xbf, 0xcd, 0xe6, 0x96, 0x77, 0xe5, 0x8a,
+ 0x1a, 0x38, 0xb0, 0x8d, 0x8a, 0x80, 0x8a, 0x10, 0x72, 0xff, 0xb5, 0x22,
+ 0x69, 0x77, 0xe0, 0xb4, 0xb1, 0x7e, 0x3b, 0x7b, 0xd0, 0xb1, 0x79, 0xb0,
+ 0xc5, 0x8b, 0xe6, 0xe6, 0x0f, 0x11, 0x0c, 0xc8, 0x24, 0x51, 0x7f, 0x17,
+ 0x30, 0xf1, 0xba, 0xb1, 0x7f, 0xe8, 0x90, 0x0f, 0x06, 0x72, 0x53, 0xac,
+ 0x5f, 0xfd, 0x9d, 0xcb, 0x3e, 0xda, 0x26, 0x85, 0x8b, 0xfe, 0x88, 0xe7,
+ 0x1b, 0x58, 0x75, 0x8a, 0x91, 0xfd, 0x8d, 0x0e, 0xfb, 0x77, 0xf9, 0x3a,
+ 0xc5, 0xfe, 0x81, 0xe7, 0x9b, 0xe2, 0x58, 0xa8, 0x3d, 0xa1, 0x93, 0xdf,
+ 0xfa, 0x5e, 0x69, 0xf5, 0x12, 0x7d, 0x2c, 0x5f, 0x1a, 0xdd, 0xf1, 0x62,
+ 0xa1, 0x3e, 0xf9, 0xcc, 0x26, 0x85, 0xe9, 0xdf, 0x1c, 0x87, 0xc8, 0x17,
+ 0xfe, 0xf0, 0x60, 0x80, 0xe0, 0x10, 0x05, 0x8b, 0xfe, 0x6d, 0x4e, 0x20,
+ 0x6d, 0x8d, 0xd5, 0x8b, 0xff, 0xe2, 0x63, 0x4d, 0x80, 0xfc, 0xdf, 0x62,
+ 0xf2, 0xc5, 0x49, 0x12, 0x27, 0x40, 0xbf, 0xf7, 0xde, 0x5e, 0x13, 0x90,
+ 0x38, 0xb1, 0x7f, 0xfd, 0xcf, 0xb6, 0x1d, 0xfb, 0xe7, 0xbe, 0x2e, 0xd6,
+ 0x2b, 0xe8, 0x92, 0x01, 0xfd, 0xf3, 0xfb, 0xd0, 0xb1, 0x7f, 0x3f, 0x18,
+ 0xa3, 0x8b, 0x17, 0x7d, 0xd6, 0x2f, 0x86, 0xe4, 0x0e, 0x8f, 0x97, 0xe4,
+ 0x41, 0x72, 0xca, 0xc4, 0x69, 0x0a, 0x11, 0x17, 0xff, 0xfe, 0x3b, 0x90,
+ 0x24, 0xdc, 0x11, 0xfe, 0xd1, 0xef, 0x89, 0xce, 0xb1, 0x7d, 0xc9, 0x4f,
+ 0x8b, 0x17, 0xff, 0x61, 0x9a, 0x86, 0x2c, 0x01, 0xd9, 0x62, 0xe2, 0x85,
+ 0x8b, 0xff, 0xc2, 0xf4, 0x98, 0x1f, 0x76, 0xf3, 0x9d, 0x62, 0xbe, 0x7c,
+ 0x04, 0x2d, 0x76, 0xdd, 0xd5, 0x8b, 0xff, 0xf3, 0xb7, 0x98, 0x78, 0x3c,
+ 0xf3, 0x1d, 0xb4, 0xb1, 0x7d, 0x2e, 0x41, 0xd6, 0x2f, 0xff, 0x47, 0x43,
+ 0xc0, 0xfc, 0xda, 0x81, 0x05, 0xd6, 0x2f, 0x0b, 0x06, 0xb1, 0x7b, 0x4f,
+ 0xcd, 0xa9, 0xf4, 0x4e, 0x49, 0x90, 0xa3, 0xd1, 0x0f, 0xc7, 0x5d, 0x4c,
+ 0x88, 0xf7, 0x14, 0x2d, 0xe8, 0x5c, 0x8d, 0x94, 0x70, 0xee, 0x4e, 0x29,
+ 0x4a, 0x97, 0xfe, 0x8e, 0x75, 0xf6, 0x1c, 0x66, 0x96, 0x2b, 0xb5, 0xde,
+ 0xf6, 0x9d, 0x5f, 0xd2, 0x8d, 0xd2, 0x85, 0x8b, 0xff, 0x7e, 0x3f, 0x9d,
+ 0x83, 0x3d, 0xc5, 0x8b, 0xd3, 0x31, 0xd6, 0x28, 0x67, 0xbd, 0x88, 0x17,
+ 0xfb, 0x0a, 0x18, 0xd8, 0x3a, 0xc5, 0x4e, 0x7a, 0x7e, 0x21, 0xa7, 0x47,
+ 0x58, 0xa1, 0x91, 0x7f, 0xff, 0xfb, 0xad, 0xb3, 0x7e, 0x35, 0x3e, 0xde,
+ 0x01, 0xc8, 0x1b, 0x73, 0xa8, 0xf7, 0x16, 0x2a, 0x19, 0xa3, 0x83, 0x87,
+ 0x66, 0x46, 0x25, 0xd4, 0x34, 0x1a, 0x51, 0x93, 0xcf, 0x26, 0x14, 0x64,
+ 0xc2, 0x27, 0xbd, 0xad, 0x42, 0xc5, 0xef, 0x8b, 0x75, 0x62, 0xff, 0xa7,
+ 0x69, 0xf9, 0x87, 0x7f, 0xac, 0x5f, 0xf4, 0xa0, 0x6c, 0x3c, 0x7f, 0xac,
+ 0x59, 0xb4, 0x7e, 0x7e, 0x3b, 0xbf, 0xb5, 0x13, 0xb1, 0x79, 0x62, 0xe0,
+ 0xce, 0xb1, 0x78, 0x0f, 0xc5, 0x8b, 0xb6, 0x30, 0xa2, 0xc5, 0x0c, 0xf5,
+ 0xfb, 0x19, 0xe0, 0xed, 0xed, 0x84, 0x16, 0x82, 0x8b, 0x17, 0xe2, 0x81,
+ 0xe4, 0xcb, 0x17, 0xf4, 0x98, 0x0f, 0xe1, 0x2c, 0x5f, 0x70, 0x5a, 0x35,
+ 0x62, 0xff, 0xd2, 0x10, 0xf3, 0x5e, 0x21, 0x79, 0x62, 0xfd, 0x1f, 0xf4,
+ 0x49, 0x62, 0xf8, 0x62, 0xf7, 0x36, 0x34, 0xc4, 0x60, 0xbb, 0x0a, 0x3b,
+ 0x2e, 0x98, 0x94, 0x08, 0x17, 0xbe, 0x1e, 0x96, 0x2f, 0xf4, 0x13, 0xfc,
+ 0x45, 0x3a, 0xc5, 0xff, 0xfb, 0xed, 0xaf, 0xbc, 0x11, 0xaf, 0x33, 0xbc,
+ 0xeb, 0x17, 0xd8, 0xc0, 0xe2, 0xc5, 0xf3, 0x72, 0x25, 0x87, 0xf1, 0xa5,
+ 0x6b, 0xd3, 0x8e, 0x16, 0x2f, 0xdb, 0x7b, 0xe4, 0x49, 0x62, 0xf6, 0x9f,
+ 0xa5, 0x8b, 0xc7, 0x8f, 0xac, 0x5e, 0x89, 0x05, 0x56, 0x2c, 0x01, 0x9e,
+ 0xe6, 0x0f, 0x10, 0xed, 0xe1, 0x8a, 0x16, 0x2f, 0xfa, 0x39, 0x1e, 0xe6,
+ 0x14, 0x96, 0x2f, 0xff, 0xec, 0x06, 0xe6, 0x71, 0xcd, 0x82, 0xe9, 0xfc,
+ 0xe6, 0xac, 0x5f, 0xff, 0xfe, 0xc9, 0xf9, 0x06, 0xbf, 0x3d, 0x2c, 0x34,
+ 0xdc, 0xef, 0xda, 0x8c, 0xed, 0x62, 0xf6, 0x8a, 0x4b, 0x17, 0xff, 0x87,
+ 0xfc, 0x1e, 0xeb, 0x11, 0xba, 0xc0, 0x8b, 0x17, 0xfc, 0x40, 0xf3, 0x0f,
+ 0x0a, 0x4b, 0x16, 0x8d, 0xa8, 0xa5, 0xc1, 0xd7, 0x50, 0xa6, 0x54, 0x17,
+ 0xf1, 0xd2, 0x38, 0xe2, 0xf8, 0xa3, 0x22, 0xbc, 0x17, 0xfe, 0x2c, 0x5f,
+ 0x8d, 0x62, 0xcd, 0xeb, 0x15, 0xb1, 0x2f, 0xc9, 0xc0, 0xec, 0xa1, 0x28,
+ 0x32, 0x7c, 0x84, 0x2b, 0x46, 0x83, 0x33, 0xa9, 0xc7, 0xff, 0x0a, 0xb7,
+ 0x37, 0x00, 0xf1, 0x42, 0x23, 0xd2, 0x8f, 0x84, 0xa0, 0x19, 0x0d, 0xc1,
+ 0xf1, 0x62, 0xff, 0xde, 0xe6, 0x4c, 0xe0, 0xe6, 0x4e, 0xb1, 0x5a, 0x3d,
+ 0xa2, 0x19, 0xbf, 0x61, 0x9e, 0x0c, 0xeb, 0x17, 0xed, 0xbd, 0xcb, 0x3c,
+ 0xb1, 0x7f, 0xff, 0x83, 0x80, 0x0f, 0xf1, 0xac, 0x26, 0x79, 0x73, 0x3c,
+ 0xb1, 0x52, 0x44, 0x67, 0x0b, 0x2e, 0xe4, 0xeb, 0x17, 0xf1, 0x41, 0x9a,
+ 0x83, 0xac, 0x5f, 0xff, 0x67, 0x84, 0x03, 0xbc, 0xb9, 0x9b, 0xe0, 0x6b,
+ 0x14, 0x34, 0x4c, 0xe0, 0xc9, 0x17, 0x56, 0x91, 0xd5, 0xe8, 0x5e, 0x5f,
+ 0xee, 0x0b, 0x40, 0xcf, 0xba, 0xc5, 0xf7, 0x0e, 0xec, 0xb1, 0x52, 0x3d,
+ 0x6f, 0x1a, 0x5f, 0xfe, 0x96, 0xdd, 0x47, 0x1a, 0x08, 0x00, 0x85, 0x8a,
+ 0x83, 0xed, 0x72, 0x2b, 0xfd, 0x1f, 0x76, 0xf4, 0x12, 0xc5, 0xf8, 0x79,
+ 0xc1, 0x1a, 0xb1, 0x7c, 0xe7, 0xc1, 0xac, 0x5f, 0x86, 0xe4, 0xfb, 0xd6,
+ 0x2e, 0x7e, 0x2c, 0x56, 0x1e, 0x06, 0x8a, 0x6b, 0x48, 0xde, 0x23, 0x1f,
+ 0x15, 0x6f, 0x62, 0xbf, 0xef, 0xc7, 0x7e, 0x8f, 0xbe, 0xea, 0xc5, 0x2c,
+ 0x5f, 0xf6, 0x98, 0x53, 0x80, 0x10, 0x11, 0x62, 0xff, 0x79, 0xb4, 0xff,
+ 0x73, 0xac, 0x5c, 0x1c, 0xcb, 0x17, 0xf6, 0x6b, 0x9f, 0xce, 0x96, 0x2d,
+ 0xbd, 0x62, 0xb6, 0xa6, 0x2d, 0xb0, 0x8f, 0x46, 0x19, 0xd9, 0xee, 0x8c,
+ 0xc8, 0x6b, 0x70, 0xbe, 0xfa, 0x62, 0x83, 0xac, 0x5b, 0xb5, 0x8b, 0xb0,
+ 0xc5, 0x8b, 0xbd, 0xe6, 0x35, 0x7e, 0x13, 0xa8, 0x47, 0x56, 0x38, 0x32,
+ 0x75, 0xe9, 0xc8, 0x4b, 0x17, 0xfe, 0x3e, 0xa3, 0xed, 0xd3, 0x13, 0xac,
+ 0x5a, 0x50, 0x7b, 0x8e, 0x3d, 0x7f, 0xc5, 0xd6, 0x6b, 0xa7, 0x7e, 0x95,
+ 0x10, 0x89, 0x53, 0x1f, 0x73, 0x93, 0x5a, 0x75, 0x8b, 0xe3, 0x5c, 0x80,
+ 0xb1, 0x79, 0xd8, 0x22, 0xc5, 0x48, 0xf5, 0x18, 0x4f, 0xe4, 0x75, 0x0b,
+ 0xf0, 0x98, 0x42, 0xd1, 0xd0, 0x9e, 0x1d, 0x6f, 0x0f, 0xe0, 0x4a, 0x3e,
+ 0x14, 0x3d, 0xf7, 0xbb, 0x5e, 0xe0, 0x1d, 0x62, 0xfe, 0xff, 0x4d, 0xcc,
+ 0x1a, 0xc5, 0x4e, 0x79, 0x9d, 0x0e, 0xdf, 0xe7, 0x1e, 0x36, 0xf7, 0x3a,
+ 0xc5, 0xff, 0xfb, 0xac, 0x22, 0x6c, 0xd4, 0x0f, 0xee, 0x4c, 0xb1, 0x5a,
+ 0x44, 0x30, 0x8d, 0x2f, 0xff, 0xff, 0xcc, 0x7c, 0xe6, 0x10, 0xbd, 0xfc,
+ 0xde, 0x38, 0xfb, 0x47, 0xbe, 0x27, 0x3a, 0xc5, 0xfd, 0xc7, 0xeb, 0xed,
+ 0x3a, 0xc5, 0x62, 0x70, 0x1a, 0x85, 0x57, 0xc8, 0xfd, 0x08, 0x3b, 0xf3,
+ 0x6a, 0x5b, 0x9e, 0x58, 0xbf, 0xf9, 0xf9, 0x3c, 0x7f, 0x3a, 0x0f, 0x71,
+ 0xd6, 0x28, 0xe7, 0xec, 0x45, 0x97, 0xff, 0xff, 0xbf, 0x82, 0xd1, 0xbf,
+ 0x6e, 0xe3, 0xc2, 0xf9, 0x67, 0x7e, 0x13, 0xf1, 0x62, 0xff, 0xec, 0xec,
+ 0x3f, 0x31, 0x0a, 0x59, 0xc5, 0x8b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6,
+ 0x14, 0xe4, 0xe3, 0x82, 0x9e, 0x34, 0x3c, 0x2c, 0xf7, 0x1b, 0xac, 0x20,
+ 0xe7, 0xcd, 0x47, 0x09, 0xcd, 0xe6, 0x30, 0x00, 0x20, 0x13, 0x8e, 0x0a,
+ 0x78, 0xd2, 0xc5, 0xfb, 0x86, 0x9b, 0x9b, 0xab, 0x17, 0xc1, 0x33, 0xbf,
+ 0x2c, 0x54, 0x1e, 0xa3, 0x97, 0x5f, 0xd2, 0x2c, 0xc1, 0x05, 0xd6, 0x2f,
+ 0xf3, 0xfa, 0x59, 0xac, 0xe2, 0xc5, 0x42, 0xa2, 0x7c, 0x46, 0xfc, 0x6b,
+ 0xae, 0x40, 0x46, 0x37, 0xfe, 0x6e, 0xbf, 0x9b, 0x81, 0xea, 0x24, 0xb1,
+ 0x7e, 0x70, 0x01, 0xbe, 0xb1, 0x7f, 0xf6, 0x6f, 0xf7, 0x9d, 0x88, 0xa0,
+ 0xeb, 0x17, 0x44, 0xbe, 0x7d, 0x9e, 0x28, 0xaf, 0xa3, 0x74, 0xa1, 0x61,
+ 0x7e, 0xeb, 0xc6, 0xb7, 0x4b, 0x17, 0xff, 0xbf, 0x05, 0xed, 0xbf, 0x71,
+ 0xfd, 0xf4, 0xb1, 0x4e, 0x7f, 0x1c, 0x2c, 0xbf, 0xec, 0xe7, 0xf1, 0xcb,
+ 0x37, 0x56, 0x2e, 0xc9, 0xd6, 0x2f, 0xf0, 0x66, 0xb0, 0x48, 0x29, 0x2c,
+ 0x5f, 0xf1, 0x63, 0x68, 0xa3, 0xb9, 0x2c, 0x56, 0x23, 0x07, 0x47, 0x5f,
+ 0x18, 0x73, 0x7b, 0xff, 0xfe, 0xf0, 0xa7, 0xcf, 0xb7, 0xbf, 0x87, 0xcd,
+ 0x4b, 0x3b, 0xf2, 0xc5, 0xfd, 0xf6, 0xff, 0xe0, 0xeb, 0x17, 0xe9, 0x14,
+ 0x67, 0x16, 0x2f, 0x39, 0x4f, 0xd1, 0xea, 0xf6, 0x5d, 0x52, 0x47, 0x9f,
+ 0xa1, 0x7d, 0x7f, 0xfe, 0x80, 0x4d, 0x28, 0x9c, 0x9c, 0xde, 0x14, 0x49,
+ 0x62, 0xff, 0xc1, 0xe7, 0xdc, 0xfb, 0x26, 0x18, 0x62, 0xc5, 0xff, 0xfb,
+ 0x3a, 0xfc, 0x10, 0xc9, 0xa7, 0xc2, 0x63, 0x56, 0x2a, 0x74, 0x4e, 0x49,
+ 0x1e, 0xff, 0xe9, 0xc0, 0xdd, 0xf3, 0xac, 0x62, 0xe9, 0x62, 0x9c, 0xfb,
+ 0x08, 0x92, 0xa4, 0x9b, 0xfb, 0xc6, 0xbf, 0x7f, 0xff, 0x4c, 0x50, 0x0e,
+ 0x75, 0xf6, 0xd4, 0xc5, 0x00, 0xe2, 0xc5, 0xff, 0xfd, 0xee, 0x41, 0xb2,
+ 0x6f, 0xb9, 0x7a, 0x59, 0xac, 0x58, 0xbf, 0xf3, 0x73, 0x07, 0xb5, 0xc1,
+ 0xb9, 0x8b, 0x17, 0x0b, 0x7a, 0xc5, 0xfe, 0x83, 0xf7, 0xe8, 0xce, 0xd6,
+ 0x2f, 0xf9, 0xb7, 0xfd, 0xe5, 0xa8, 0x35, 0x62, 0xff, 0xe8, 0x06, 0x7a,
+ 0x3a, 0x28, 0xf7, 0x16, 0x2b, 0xe8, 0x80, 0x23, 0xca, 0xc4, 0xe3, 0xfa,
+ 0x5b, 0xd2, 0x1f, 0xc6, 0xbd, 0x0b, 0x5b, 0xe8, 0x97, 0x37, 0x16, 0x2f,
+ 0xff, 0xda, 0xef, 0xcc, 0x67, 0x3e, 0xdd, 0x83, 0x4e, 0x35, 0x8b, 0xf7,
+ 0x98, 0x44, 0x6a, 0xc5, 0x42, 0x20, 0xc4, 0xb5, 0x7f, 0x61, 0x98, 0x42,
+ 0x02, 0xc5, 0xfa, 0x59, 0xe8, 0x02, 0xc5, 0xf6, 0x02, 0x00, 0xb1, 0x74,
+ 0x1e, 0x73, 0xf8, 0xec, 0xb8, 0x8a, 0x2f, 0xfe, 0x6e, 0x14, 0x7b, 0x99,
+ 0xbd, 0x8d, 0x58, 0xbf, 0xff, 0xf8, 0x07, 0x79, 0x7d, 0xdb, 0xcc, 0x3c,
+ 0x1e, 0x79, 0x8e, 0xda, 0x58, 0xae, 0x23, 0xc7, 0xc7, 0x62, 0x46, 0xbf,
+ 0x6b, 0x07, 0xbe, 0x16, 0x2f, 0xfd, 0xf7, 0x09, 0xd7, 0xd8, 0xf1, 0xd2,
+ 0xc5, 0xba, 0x58, 0xbc, 0x50, 0x62, 0xc5, 0xd9, 0xcc, 0x3f, 0x3e, 0x90,
+ 0xce, 0x27, 0x4c, 0x8d, 0x72, 0x84, 0xed, 0xfa, 0x73, 0xc0, 0xe1, 0x62,
+ 0xa7, 0x67, 0x1a, 0x48, 0x84, 0x72, 0xa8, 0xb2, 0x32, 0xb3, 0x61, 0x3f,
+ 0xd4, 0x38, 0xbb, 0x8c, 0xba, 0x68, 0xe9, 0xf4, 0x53, 0xf8, 0xfb, 0x40,
+ 0xa1, 0xc8, 0x54, 0xfa, 0x38, 0xbd, 0xf1, 0x83, 0x86, 0x4d, 0x7f, 0xe8,
+ 0x34, 0xd8, 0x2c, 0xf7, 0xd9, 0x62, 0xff, 0xfa, 0x78, 0xd6, 0xd1, 0xe1,
+ 0x4f, 0x82, 0x2f, 0x2c, 0x5f, 0xb9, 0x13, 0xe1, 0x8b, 0x16, 0x82, 0x3f,
+ 0xde, 0x29, 0xdf, 0xff, 0x0f, 0xc2, 0x7e, 0xfc, 0x0c, 0x1e, 0xdf, 0xb2,
+ 0xc5, 0xff, 0xf3, 0x6f, 0x1c, 0x14, 0x7b, 0x98, 0x22, 0xf2, 0xc5, 0xff,
+ 0xf6, 0xf7, 0xff, 0xd8, 0x79, 0xee, 0x08, 0xbc, 0xb1, 0x7f, 0x9b, 0x7e,
+ 0x73, 0x99, 0xba, 0xb1, 0x7d, 0xe2, 0x17, 0x96, 0x2e, 0x11, 0x2c, 0x5e,
+ 0xc3, 0xe6, 0x8d, 0xd7, 0xc8, 0xea, 0x11, 0xeb, 0x25, 0x2f, 0xb9, 0x50,
+ 0xd3, 0xee, 0x72, 0x6e, 0x2a, 0x7a, 0x34, 0x5b, 0xda, 0x35, 0x96, 0x2f,
+ 0xf0, 0x61, 0xe8, 0xe5, 0x06, 0x2c, 0x56, 0x1e, 0xab, 0x8f, 0x54, 0x36,
+ 0x6c, 0x99, 0x4e, 0xf1, 0x68, 0xc4, 0x5e, 0x55, 0x50, 0xa1, 0x31, 0x78,
+ 0xc3, 0x0c, 0x48, 0xbf, 0xec, 0x03, 0xeb, 0x37, 0xe0, 0xd2, 0x36, 0x4d,
+ 0x0d, 0xc6, 0x18, 0x91, 0x78, 0xc3, 0x0c, 0x48, 0xbf, 0x9e, 0x71, 0xfe,
+ 0x38, 0x91, 0xb2, 0x68, 0x68, 0x91, 0x94, 0x62, 0x6e, 0xe1, 0xdd, 0xfb,
+ 0xa6, 0x18, 0x67, 0x48, 0xd9, 0x36, 0x77, 0x8c, 0x30, 0xc4, 0x8b, 0xdc,
+ 0x8d, 0x24, 0x6c, 0x9a, 0x1b, 0xe7, 0x2e, 0xfc, 0xb1, 0x60, 0x32, 0x2c,
+ 0xbc, 0xbe, 0x61, 0x85, 0xdb, 0x81, 0x45, 0x8b, 0xfe, 0x62, 0xe8, 0xb0,
+ 0xc7, 0x02, 0xc5, 0xfc, 0x27, 0x9c, 0x87, 0xda, 0xc5, 0xf4, 0x49, 0xfa,
+ 0x58, 0xaf, 0x9e, 0x99, 0x18, 0x5e, 0xc9, 0x99, 0x62, 0x86, 0x6f, 0x83,
+ 0x21, 0xbf, 0x70, 0x53, 0xee, 0x12, 0xc5, 0xf8, 0x6d, 0xbe, 0x06, 0xb1,
+ 0x7d, 0x85, 0x9b, 0xab, 0x15, 0xa3, 0xce, 0x39, 0x55, 0x32, 0x27, 0x43,
+ 0x7b, 0xbf, 0xf3, 0xc8, 0x9c, 0xd9, 0x89, 0xa6, 0x58, 0xb8, 0x4e, 0xb1,
+ 0x5f, 0x3d, 0x7f, 0x20, 0x5f, 0xc1, 0x6e, 0x58, 0x63, 0x81, 0x62, 0xf1,
+ 0x86, 0x18, 0x91, 0x78, 0x9c, 0xc4, 0x8d, 0x93, 0x43, 0x7c, 0x3c, 0x21,
+ 0xac, 0x5f, 0xf4, 0xf1, 0xdf, 0x18, 0xb0, 0x0b, 0x17, 0xcf, 0x26, 0x02,
+ 0xc5, 0x74, 0x7f, 0xda, 0x22, 0xf9, 0xd5, 0xfb, 0x27, 0x3e, 0x1d, 0x62,
+ 0xfe, 0x89, 0xc7, 0xf8, 0xe2, 0xc5, 0xfe, 0x8c, 0xeb, 0x37, 0xb0, 0xd6,
+ 0x2d, 0x9d, 0x1f, 0x21, 0x17, 0xd0, 0x5b, 0xa7, 0xd0, 0x35, 0x6c, 0x85,
+ 0x71, 0x18, 0x6e, 0x42, 0x36, 0xfe, 0xfe, 0x6f, 0xcf, 0x71, 0x62, 0xba,
+ 0x55, 0x2e, 0x09, 0x41, 0x5e, 0x5d, 0xa9, 0x2e, 0x79, 0x8c, 0x7f, 0x50,
+ 0xca, 0xfc, 0x2f, 0xca, 0x58, 0x8d, 0xfe, 0xf4, 0xb3, 0xff, 0x79, 0x2c,
+ 0x5c, 0x6e, 0x96, 0x2f, 0xd3, 0x6b, 0x4d, 0x3a, 0xc5, 0xfb, 0x0b, 0xf8,
+ 0x4b, 0x17, 0xcc, 0xe4, 0x35, 0x8b, 0x84, 0x05, 0x8b, 0xf7, 0xf1, 0xb5,
+ 0x25, 0x8a, 0x19, 0xf0, 0x80, 0x87, 0xc3, 0x17, 0xe8, 0xc9, 0x9b, 0x4b,
+ 0x15, 0x39, 0xeb, 0x91, 0x7d, 0xd3, 0xf9, 0x62, 0xa1, 0x7c, 0x5f, 0x27,
+ 0x4a, 0x4d, 0x5d, 0xe8, 0xd1, 0x86, 0x7e, 0x56, 0xf0, 0xde, 0x22, 0x2b,
+ 0xed, 0xcf, 0xe7, 0x4b, 0x17, 0xc0, 0x62, 0xf2, 0xc5, 0x4e, 0x79, 0x3c,
+ 0x27, 0xb8, 0x2d, 0x05, 0x16, 0x2f, 0xbd, 0x06, 0x71, 0x62, 0xf7, 0x23,
+ 0xcb, 0x17, 0x00, 0xc5, 0x8b, 0xf7, 0x04, 0x41, 0x9d, 0x62, 0xdc, 0xd8,
+ 0x91, 0x09, 0x31, 0x23, 0x8e, 0xf8, 0x66, 0xb1, 0x31, 0x1e, 0xc8, 0xfd,
+ 0x0a, 0x6b, 0xff, 0xbd, 0xf7, 0x96, 0x68, 0x07, 0x6e, 0x2c, 0x5f, 0xb0,
+ 0xcc, 0xd4, 0xeb, 0x17, 0xee, 0xa3, 0xf0, 0x75, 0x8b, 0x9f, 0xcb, 0x17,
+ 0xdb, 0xae, 0x40, 0x9c, 0xfa, 0xb0, 0xa8, 0x8a, 0x6f, 0xf6, 0x1a, 0x6b,
+ 0xca, 0x43, 0x58, 0xbf, 0x9d, 0xc7, 0xe1, 0x3a, 0xc5, 0xf0, 0xdc, 0x81,
+ 0x87, 0xc6, 0x46, 0xd5, 0x09, 0xc7, 0xe4, 0x2b, 0xc5, 0x0a, 0xab, 0xfe,
+ 0x19, 0xdb, 0x5c, 0x72, 0x02, 0xc5, 0x82, 0x8b, 0x17, 0xfd, 0xf8, 0x94,
+ 0x9b, 0x98, 0x35, 0x8b, 0x03, 0x61, 0x9e, 0x7f, 0x85, 0xaf, 0xfd, 0xec,
+ 0xd4, 0x6f, 0xf1, 0x38, 0x16, 0x2a, 0x0f, 0xb9, 0x8b, 0xaf, 0xfe, 0x83,
+ 0xe3, 0x4c, 0xef, 0x2e, 0xa4, 0xb1, 0x52, 0x3e, 0x52, 0x20, 0xbe, 0x08,
+ 0x29, 0x8e, 0xb1, 0x4c, 0x9d, 0x1c, 0xd1, 0xad, 0xfc, 0x86, 0xff, 0xa0,
+ 0xa4, 0x43, 0xfc, 0x4e, 0xb1, 0x7e, 0xcd, 0x6e, 0x1c, 0x6b, 0x17, 0xfe,
+ 0xef, 0xc6, 0x9a, 0xff, 0x21, 0x79, 0x62, 0x86, 0x7d, 0xf8, 0x59, 0x7b,
+ 0xed, 0x32, 0x45, 0x68, 0xdf, 0xf0, 0x86, 0xff, 0x9f, 0xbf, 0x64, 0xc2,
+ 0xd1, 0xab, 0x16, 0xe9, 0x8f, 0x78, 0x44, 0x37, 0xf8, 0xb3, 0xb9, 0x71,
+ 0x8d, 0x58, 0xb8, 0x3d, 0x2c, 0x5e, 0xd0, 0xa7, 0x58, 0xbc, 0xfa, 0x35,
+ 0x62, 0xc7, 0x58, 0xa3, 0x4f, 0xa3, 0x43, 0x2e, 0x3f, 0xbc, 0x7a, 0xff,
+ 0xc3, 0xfc, 0x73, 0x35, 0x3c, 0x49, 0x62, 0xc6, 0xac, 0x5f, 0xfd, 0x9d,
+ 0x7e, 0x3f, 0x9a, 0xd4, 0x1a, 0xb1, 0x79, 0x81, 0xc8, 0x3d, 0x9d, 0x09,
+ 0xd6, 0xd4, 0xe9, 0xa7, 0x84, 0xec, 0xc7, 0xc5, 0x09, 0x9b, 0xfe, 0xcc,
+ 0xe8, 0x11, 0x9d, 0xc9, 0x62, 0xff, 0xc2, 0xe6, 0x14, 0x7c, 0x61, 0x9d,
+ 0x62, 0xff, 0xef, 0x68, 0x5c, 0xfb, 0xc8, 0x0c, 0x35, 0x8b, 0xe8, 0x73,
+ 0xef, 0x48, 0xbd, 0xac, 0xd8, 0x96, 0x2f, 0xf9, 0x8d, 0x0c, 0xa3, 0xed,
+ 0x3a, 0xc5, 0xff, 0xdf, 0x67, 0x00, 0x20, 0x11, 0xfe, 0x2c, 0x5f, 0xdf,
+ 0xc3, 0x9d, 0xe4, 0xb1, 0x78, 0xc3, 0x0c, 0x48, 0xbf, 0xc5, 0xef, 0xb4,
+ 0x14, 0xe9, 0x1b, 0x26, 0x86, 0xfa, 0x34, 0xff, 0x58, 0xbd, 0x00, 0xc9,
+ 0x22, 0xdf, 0x13, 0xfc, 0x8d, 0x58, 0x9c, 0xbf, 0x44, 0x5e, 0x3b, 0x0e,
+ 0x1f, 0x77, 0xf6, 0xa4, 0x1c, 0x9a, 0x75, 0x8b, 0xce, 0x0e, 0x2c, 0x5d,
+ 0x9b, 0x70, 0xf3, 0xbc, 0x63, 0x5d, 0x2a, 0x7b, 0x3c, 0x77, 0x7b, 0xe1,
+ 0x25, 0x7f, 0xce, 0x02, 0xc9, 0xa5, 0x1d, 0xac, 0x5f, 0xfa, 0x3b, 0xfe,
+ 0x76, 0x0c, 0xf7, 0x16, 0x2a, 0x15, 0xbe, 0x64, 0xac, 0x16, 0x40, 0x11,
+ 0xd5, 0xff, 0x39, 0x16, 0x6b, 0x4d, 0x32, 0xc5, 0xfc, 0x41, 0xe8, 0x85,
+ 0x25, 0x8b, 0xf7, 0x0e, 0xda, 0xe2, 0xc5, 0x4e, 0x89, 0x07, 0x38, 0x01,
+ 0x7d, 0xff, 0xfd, 0x2f, 0xbc, 0xba, 0xfb, 0x7a, 0x59, 0xff, 0xbc, 0x96,
+ 0x2f, 0xd0, 0x08, 0xff, 0x16, 0x2b, 0x11, 0x0a, 0x05, 0xdb, 0xff, 0x83,
+ 0x28, 0x61, 0xff, 0x25, 0xf6, 0x58, 0xbf, 0xf0, 0x71, 0xa0, 0x7b, 0xee,
+ 0x36, 0x58, 0xbf, 0xe9, 0x4d, 0x27, 0xf7, 0x1a, 0x16, 0x2f, 0xff, 0x9f,
+ 0xc2, 0x86, 0x8e, 0xfa, 0xfe, 0x77, 0xc5, 0x8b, 0xf6, 0xb4, 0xde, 0xe2,
0xc5, 0x6d, 0x4c, 0xe4, 0x68, 0x9d, 0xa0, 0x00, 0xe8, 0x35, 0x2b, 0xff,
- 0xe0, 0x6c, 0xe4, 0xf3, 0xf3, 0xdf, 0x8d, 0x16, 0x96, 0x2f, 0xfe, 0x8a,
- 0x02, 0x2f, 0x43, 0x35, 0x9c, 0x58, 0xbf, 0xff, 0x17, 0x5f, 0x68, 0xa1,
- 0x25, 0xed, 0x6a, 0x60, 0xb1, 0xc3, 0xc6, 0xbf, 0xff, 0x9b, 0x9a, 0x67,
- 0xd4, 0xb7, 0xbf, 0x9c, 0xe6, 0x2c, 0x5f, 0xec, 0x98, 0x37, 0x8a, 0x56,
- 0x2c, 0x0c, 0x47, 0x91, 0xda, 0x36, 0x56, 0x6f, 0xe7, 0x83, 0xc1, 0xbe,
- 0xb1, 0x52, 0xa9, 0x0b, 0x13, 0xde, 0x38, 0xe1, 0x1c, 0x5f, 0xff, 0xce,
- 0x02, 0xc3, 0x93, 0xfb, 0x81, 0xe9, 0xa4, 0x6b, 0x17, 0x43, 0x8b, 0x17,
- 0x4c, 0x06, 0x7e, 0x4c, 0xb5, 0x52, 0xcf, 0x60, 0x84, 0x6f, 0xf9, 0x18,
- 0x61, 0xa5, 0x1d, 0xc3, 0xa1, 0xa3, 0xce, 0x89, 0x2f, 0x47, 0x5f, 0x96,
- 0xf4, 0xf0, 0xc6, 0x04, 0x2d, 0x4a, 0x5c, 0xef, 0x21, 0x69, 0x7f, 0xff,
- 0x79, 0x8f, 0x85, 0xee, 0x49, 0xbc, 0x10, 0xfe, 0xcb, 0x17, 0xe7, 0xf1,
- 0x99, 0xf5, 0x8b, 0xc3, 0xfe, 0x2c, 0x5f, 0x63, 0x7c, 0xd5, 0x8a, 0xf9,
- 0xf4, 0xb9, 0x48, 0x07, 0x6f, 0xff, 0xb3, 0xa9, 0x27, 0xf7, 0x06, 0x27,
- 0xd4, 0x16, 0x2b, 0xb3, 0xfe, 0x39, 0x75, 0xf7, 0x3f, 0x9c, 0x58, 0xbe,
- 0x6f, 0x4f, 0x96, 0x29, 0x8f, 0x17, 0x44, 0x77, 0xcc, 0x0c, 0x1a, 0xc5,
- 0xfd, 0x25, 0xd0, 0x53, 0x61, 0x6c, 0x0b, 0x16, 0x95, 0x8b, 0xde, 0x68,
- 0xd6, 0x2a, 0x33, 0x5f, 0xd8, 0x8d, 0xfa, 0x4f, 0xa9, 0xde, 0xb1, 0x7f,
- 0xfb, 0xcc, 0x67, 0x0a, 0x7d, 0xcd, 0x6a, 0x56, 0x2e, 0x92, 0x58, 0xbe,
- 0xc2, 0x0f, 0xcb, 0x15, 0x03, 0x73, 0xa1, 0x6b, 0xc3, 0x93, 0x56, 0x2f,
- 0xfe, 0x9e, 0xbc, 0x52, 0x66, 0x7b, 0x9c, 0x58, 0xbf, 0x8a, 0x61, 0xfe,
- 0x01, 0x62, 0xff, 0xcf, 0xfd, 0x4f, 0x9b, 0xa6, 0x1a, 0xc5, 0xff, 0xf1,
- 0x0b, 0xdc, 0xce, 0xbb, 0xf3, 0xb9, 0xf8, 0xb1, 0x7f, 0xbf, 0x8d, 0xa8,
- 0x06, 0x75, 0x8a, 0xc4, 0x43, 0xf9, 0x4a, 0xec, 0x02, 0xc5, 0x0d, 0x32,
- 0xdf, 0x97, 0x72, 0x18, 0xde, 0x22, 0xa6, 0x4f, 0x53, 0x43, 0xc0, 0x8d,
- 0xce, 0xff, 0xa0, 0xda, 0x0f, 0xde, 0x68, 0xd6, 0x2f, 0xa7, 0xcd, 0xe5,
- 0x8b, 0xff, 0xff, 0x39, 0xe7, 0x5d, 0x0f, 0xf3, 0xc1, 0x3b, 0x43, 0x9f,
- 0x78, 0x2c, 0x53, 0x23, 0x2f, 0xe7, 0x84, 0x45, 0x7e, 0x31, 0xff, 0x27,
- 0x58, 0xbd, 0xd4, 0xf1, 0x62, 0xff, 0xe0, 0xe1, 0x9f, 0x7f, 0xb6, 0xb5,
- 0x2b, 0x15, 0x28, 0x8c, 0xc2, 0x90, 0x0f, 0x5f, 0x41, 0xc8, 0x0b, 0x17,
- 0xff, 0x9b, 0xc2, 0xd3, 0xf2, 0x0d, 0xc9, 0x8d, 0x62, 0xdf, 0xc3, 0xed,
- 0x72, 0x2b, 0xdc, 0xdf, 0x8b, 0x17, 0x4e, 0x96, 0x2b, 0xc6, 0xdb, 0x64,
- 0x7e, 0xfe, 0xdf, 0x25, 0xd6, 0xce, 0x2c, 0x5f, 0xd9, 0x1f, 0x37, 0x1b,
- 0xa5, 0x8a, 0x94, 0x45, 0x31, 0x21, 0x19, 0xdf, 0x85, 0xa3, 0x7e, 0xcb,
- 0x15, 0xb5, 0x91, 0x69, 0x31, 0xa1, 0xc6, 0xd1, 0x02, 0x11, 0x91, 0x63,
- 0x6f, 0x44, 0x7d, 0x95, 0x34, 0x21, 0x35, 0x1f, 0xab, 0xc6, 0x02, 0x50,
- 0xba, 0xe4, 0x26, 0xfd, 0x0e, 0x6d, 0x92, 0xdb, 0x18, 0xb1, 0x7f, 0xc4,
- 0x27, 0x34, 0x07, 0x98, 0x2c, 0x56, 0x8f, 0x34, 0x02, 0x77, 0x08, 0x0b,
- 0x17, 0xf8, 0x9c, 0xcc, 0x27, 0x35, 0x62, 0xff, 0xec, 0xf7, 0x03, 0xe1,
- 0xca, 0x75, 0x2b, 0x16, 0x28, 0xd1, 0x20, 0x31, 0x83, 0x99, 0xdf, 0xf9,
- 0xfd, 0xd7, 0xdb, 0xbe, 0x49, 0x8b, 0x16, 0xdf, 0x87, 0xf1, 0xf3, 0x6b,
- 0xff, 0x75, 0x3e, 0xfb, 0x6f, 0xce, 0xfc, 0xb1, 0x7f, 0xe9, 0xd1, 0x3c,
- 0x73, 0xa9, 0x82, 0xc5, 0x62, 0x20, 0x4c, 0x43, 0xa6, 0x46, 0x6f, 0xe1,
- 0x55, 0x7f, 0xff, 0xbe, 0xc6, 0x66, 0xeb, 0x1d, 0xfd, 0xc1, 0x43, 0x3b,
- 0xf2, 0xc5, 0xff, 0xda, 0x60, 0x07, 0xf9, 0x3b, 0xbf, 0x96, 0x2f, 0xff,
- 0xe8, 0xc7, 0xf9, 0xe6, 0x77, 0xc9, 0xd7, 0xb9, 0x91, 0xac, 0x50, 0xd3,
- 0x0a, 0xd3, 0x31, 0x22, 0xdd, 0x2c, 0xb1, 0x52, 0xad, 0xbb, 0x23, 0xf7,
- 0x78, 0xcc, 0x40, 0x61, 0x7f, 0xd1, 0x75, 0xf6, 0x3c, 0xe8, 0xd5, 0x8b,
- 0xfc, 0xda, 0x8b, 0x3d, 0x31, 0x2c, 0x5f, 0xd3, 0xf9, 0xf4, 0xfd, 0x62,
- 0xfb, 0x75, 0x8b, 0xa5, 0x8a, 0xc3, 0xd3, 0xdd, 0x2d, 0xbf, 0x47, 0xb4,
- 0x53, 0x12, 0xc5, 0xcf, 0x12, 0xc5, 0xa0, 0xb1, 0x7e, 0x87, 0x9b, 0x5d,
- 0x2c, 0x5e, 0x0c, 0xa2, 0x58, 0xad, 0xa7, 0xe7, 0x01, 0x8e, 0xc4, 0x80,
- 0x55, 0x58, 0x9e, 0x47, 0x47, 0xba, 0x84, 0x43, 0x92, 0x72, 0x14, 0x15,
- 0xb6, 0x18, 0x0d, 0xbb, 0x01, 0xa4, 0xce, 0xb3, 0xc7, 0x3a, 0x89, 0x0a,
- 0x55, 0xe0, 0xe9, 0x65, 0x59, 0x68, 0x6b, 0x4d, 0x8e, 0x8f, 0xa9, 0x50,
- 0xad, 0x3b, 0xaf, 0xb9, 0x1a, 0xe4, 0x54, 0x88, 0x1d, 0x4e, 0x80, 0x9e,
- 0x92, 0xf5, 0xfa, 0x75, 0xa3, 0xcf, 0xab, 0x02, 0x7b, 0x30, 0xab, 0x4a,
- 0x7e, 0x52, 0x22, 0xbd, 0x58, 0x74, 0x8a, 0x93, 0x38, 0x64, 0xe5, 0xa0,
- 0x72, 0x84, 0x2e, 0x93, 0xac, 0x5e, 0xfe, 0x71, 0x62, 0xe0, 0xfa, 0x58,
- 0xba, 0x4e, 0xb1, 0x6f, 0x00, 0xd8, 0xf8, 0x6a, 0xff, 0x31, 0xbe, 0xef,
- 0xa6, 0xfa, 0xc5, 0x76, 0x7b, 0xc4, 0x4f, 0x43, 0x46, 0x76, 0x42, 0xb2,
- 0xf6, 0xeb, 0x6f, 0x58, 0xb9, 0xbe, 0xb1, 0x7d, 0x98, 0x5e, 0x58, 0xba,
- 0x49, 0x62, 0xbe, 0x79, 0xdc, 0x17, 0xde, 0x43, 0x7f, 0xfd, 0x84, 0x13,
- 0xc6, 0xb7, 0x7c, 0xfe, 0x01, 0xd6, 0x2f, 0xff, 0x87, 0x2f, 0xaf, 0x98,
- 0xe3, 0xd9, 0x78, 0xf6, 0x56, 0x2a, 0x08, 0xdc, 0x19, 0x8f, 0x94, 0xef,
- 0x3b, 0x98, 0xb1, 0x7e, 0xeb, 0x3d, 0xf6, 0x58, 0xb3, 0x8c, 0xf1, 0x88,
- 0x76, 0xff, 0x43, 0xcd, 0xef, 0x60, 0x16, 0x2f, 0x7d, 0x82, 0xeb, 0x17,
- 0xf3, 0xc3, 0x06, 0xff, 0x58, 0xae, 0x8f, 0x38, 0xe4, 0x37, 0xed, 0xbd,
- 0xc3, 0x3c, 0xb1, 0x79, 0xb5, 0x2b, 0x17, 0xe8, 0x07, 0xc9, 0xc5, 0x8b,
- 0xb9, 0xfc, 0x3c, 0x57, 0x1c, 0xbf, 0x19, 0xee, 0x39, 0xd6, 0x2f, 0xff,
- 0xfb, 0x3e, 0xe1, 0xf3, 0x0d, 0x72, 0x04, 0x94, 0xc5, 0xf9, 0x58, 0xb4,
- 0xac, 0x5f, 0xff, 0xa7, 0x5f, 0x93, 0xee, 0x8a, 0x4a, 0x62, 0xfc, 0xac,
- 0x5f, 0x9b, 0x51, 0x4f, 0xf4, 0x8c, 0xf0, 0x33, 0x10, 0x8d, 0x41, 0x72,
- 0x5b, 0x09, 0xfb, 0x8d, 0x30, 0xee, 0xce, 0x4c, 0x08, 0x41, 0x11, 0x1f,
- 0x9c, 0x44, 0x58, 0x1c, 0x3e, 0x6f, 0xd1, 0x7e, 0x63, 0xc5, 0x8b, 0x7d,
- 0x62, 0xa0, 0x6f, 0x06, 0x55, 0x6d, 0x86, 0xb1, 0x7f, 0x7b, 0xef, 0x0f,
- 0x46, 0xb1, 0x7f, 0xdf, 0x78, 0x7a, 0x22, 0x93, 0xac, 0x51, 0x1f, 0x57,
- 0x8c, 0x2f, 0x30, 0xf1, 0x62, 0xfe, 0x37, 0x04, 0x42, 0xe9, 0x62, 0xfc,
- 0x31, 0x3e, 0xa0, 0xb1, 0x7e, 0xeb, 0xf3, 0xb8, 0x35, 0x8b, 0xa3, 0x75,
- 0x8b, 0xce, 0x40, 0xda, 0x7d, 0xce, 0x53, 0xc2, 0xdb, 0xc5, 0x1c, 0xac,
- 0x5d, 0x84, 0xb1, 0x4c, 0x6c, 0xf7, 0x8e, 0xdf, 0xdc, 0x2c, 0x8c, 0x38,
- 0x2c, 0x5d, 0x9c, 0x58, 0xbb, 0x52, 0xb1, 0x5f, 0x35, 0xde, 0x17, 0xbf,
- 0xe2, 0x93, 0xb1, 0x61, 0xe5, 0x62, 0xff, 0xda, 0xd3, 0x45, 0xcc, 0x35,
- 0xb4, 0xb1, 0x7b, 0xed, 0x05, 0x8b, 0x9a, 0x56, 0x2f, 0xf9, 0xa3, 0xcf,
- 0xb6, 0xbe, 0xeb, 0x17, 0x30, 0xf1, 0x30, 0x48, 0x88, 0x78, 0x6d, 0xe4,
- 0x13, 0x07, 0x77, 0x45, 0xa8, 0xd5, 0x5f, 0x9b, 0x90, 0x9e, 0xd3, 0x98,
- 0x08, 0x8a, 0x36, 0x2b, 0xf8, 0x63, 0x98, 0xbd, 0x8b, 0x17, 0xff, 0x17,
- 0xb9, 0xf7, 0x86, 0xdc, 0xef, 0xcb, 0x15, 0xb0, 0x97, 0x23, 0x26, 0x10,
- 0x50, 0x21, 0xc9, 0x63, 0x0c, 0xb4, 0x22, 0xfb, 0xfe, 0x7d, 0xc8, 0xb9,
- 0x3f, 0x7d, 0xc5, 0x8b, 0xfe, 0x0e, 0x62, 0x0e, 0x74, 0xf1, 0x2c, 0x5f,
- 0xb9, 0x99, 0xec, 0x58, 0xbd, 0x25, 0x1a, 0xc5, 0xf3, 0x7d, 0x8e, 0xb1,
- 0x4c, 0x6f, 0xe2, 0x1d, 0xae, 0xd1, 0x0f, 0xf6, 0x6b, 0xdc, 0xf3, 0x2c,
- 0x5d, 0x10, 0x96, 0x2e, 0x9e, 0xa4, 0xdb, 0x10, 0xed, 0xff, 0x4f, 0xbe,
- 0xe0, 0x7e, 0xf8, 0xb1, 0x43, 0x3e, 0x52, 0x2b, 0xbf, 0xfe, 0x1f, 0x04,
- 0xfa, 0x14, 0x72, 0x68, 0x65, 0xe5, 0x8b, 0xff, 0xf7, 0x84, 0xe3, 0x69,
- 0x39, 0x64, 0x71, 0x88, 0x96, 0x2f, 0xfe, 0xc8, 0xde, 0x2d, 0xbf, 0x9e,
- 0x71, 0xd6, 0x2f, 0xfe, 0x13, 0xb4, 0x24, 0xba, 0xce, 0xfc, 0xb1, 0x7c,
- 0x42, 0x7e, 0xb6, 0xa2, 0x37, 0x89, 0x17, 0x1d, 0x96, 0x2f, 0xf8, 0x1b,
- 0x7e, 0xdd, 0x0b, 0x40, 0x58, 0xbf, 0xbd, 0xf6, 0xda, 0x5d, 0xac, 0x5e,
- 0xdd, 0x9d, 0xc5, 0x8a, 0xd2, 0x24, 0x88, 0xfb, 0x74, 0xc6, 0xfb, 0x07,
- 0x26, 0xac, 0x5d, 0xbe, 0x56, 0x2f, 0x44, 0x2d, 0x2c, 0x5f, 0xd9, 0xe9,
- 0x7d, 0x1a, 0xb1, 0x7b, 0x1b, 0xcb, 0x17, 0xfc, 0xda, 0xce, 0xc2, 0x18,
- 0x61, 0x8b, 0x15, 0xf3, 0xdc, 0x71, 0xca, 0x0a, 0xa7, 0xc3, 0x30, 0xa9,
- 0x19, 0x93, 0x11, 0xb8, 0xc9, 0x0f, 0xf2, 0x11, 0x57, 0xff, 0xc5, 0x30,
- 0xda, 0x1f, 0x98, 0x85, 0x0c, 0xe2, 0xc5, 0xff, 0xfb, 0xe2, 0xe1, 0xe7,
- 0xbe, 0xbe, 0xc7, 0x26, 0x8d, 0x62, 0xff, 0xff, 0xcf, 0xb8, 0x58, 0xc4,
- 0x58, 0x0c, 0xf4, 0x9d, 0xbd, 0xf6, 0x58, 0xa1, 0xaf, 0x3e, 0x64, 0x31,
- 0x3a, 0x85, 0xfb, 0x10, 0xe9, 0x50, 0xf0, 0xe3, 0xfc, 0xa1, 0xd0, 0x37,
- 0xf1, 0x48, 0x4b, 0x37, 0x70, 0x4b, 0x17, 0xfb, 0xde, 0x6d, 0x67, 0x7e,
- 0x58, 0xbf, 0x31, 0xfa, 0x61, 0xac, 0x56, 0x8f, 0x7b, 0xe6, 0xb7, 0x80,
- 0xe7, 0x58, 0xbb, 0x00, 0xb1, 0x52, 0x6d, 0x30, 0x76, 0xf3, 0xe1, 0xd6,
- 0x2a, 0x34, 0xc1, 0xf1, 0xd8, 0x95, 0xb7, 0x47, 0xef, 0xfe, 0x70, 0xff,
- 0x30, 0xe6, 0xb5, 0x9d, 0xac, 0x58, 0xa0, 0x88, 0x7f, 0xa0, 0x5f, 0x4f,
- 0xc5, 0xa5, 0x8b, 0xfb, 0x85, 0x83, 0x27, 0x58, 0xa2, 0x3c, 0xf3, 0x08,
- 0xee, 0xe9, 0x96, 0x2f, 0xc5, 0x31, 0xcf, 0x6b, 0x17, 0xf3, 0xe8, 0xe2,
- 0xd0, 0x16, 0x2e, 0xd0, 0x16, 0x2a, 0x07, 0x8e, 0xc5, 0xf6, 0xe7, 0x48,
- 0xa9, 0x61, 0x87, 0x70, 0xa9, 0x4d, 0xdd, 0x9d, 0xde, 0x19, 0x77, 0xdc,
- 0x29, 0x8d, 0x62, 0xff, 0xa3, 0x7f, 0xb8, 0xc9, 0xfa, 0x58, 0xad, 0x1e,
- 0xe9, 0x11, 0xdf, 0xff, 0x19, 0x9d, 0x73, 0x3d, 0x16, 0x1a, 0x58, 0x05,
- 0x8a, 0xc3, 0xf4, 0x62, 0x1b, 0xfe, 0x23, 0x7e, 0xed, 0xe7, 0x3a, 0xc5,
- 0xff, 0x61, 0x99, 0xae, 0x9d, 0xfa, 0x54, 0x61, 0xc5, 0xff, 0xc2, 0xe0,
- 0xfe, 0xe7, 0xee, 0x0c, 0x4b, 0x17, 0xef, 0x7d, 0xc8, 0x0b, 0x15, 0x1a,
- 0x2d, 0xbe, 0x90, 0xe8, 0xd7, 0xfe, 0x7f, 0x64, 0x4f, 0x25, 0x31, 0x2c,
- 0x5f, 0xfb, 0xed, 0x81, 0xe4, 0x46, 0x4f, 0x6b, 0x16, 0x6c, 0x4e, 0x7f,
- 0x50, 0xef, 0xf9, 0x87, 0x0f, 0xae, 0xeb, 0xa5, 0x46, 0x08, 0x54, 0x15,
- 0x16, 0xf5, 0x1d, 0xf8, 0x11, 0xef, 0xe2, 0x9f, 0x71, 0xb7, 0xac, 0x5f,
- 0xed, 0x8b, 0x83, 0x2c, 0xf8, 0x55, 0x62, 0xec, 0x25, 0x8a, 0x58, 0xbf,
- 0xfa, 0x4b, 0xac, 0xf7, 0xdb, 0x40, 0xe9, 0x62, 0x88, 0xf4, 0xbc, 0x19,
- 0x7c, 0xdc, 0xfb, 0x2c, 0x5e, 0xce, 0xfc, 0xb1, 0x43, 0x3c, 0x03, 0x91,
- 0x5f, 0xcc, 0x59, 0xef, 0xb2, 0xc5, 0xa7, 0x0f, 0x3b, 0x84, 0x54, 0x34,
- 0xcf, 0x71, 0xa0, 0x50, 0xaf, 0xbf, 0xfd, 0xf6, 0x8b, 0xed, 0xdf, 0x8b,
- 0x37, 0xba, 0xc5, 0xe1, 0xbc, 0x4b, 0x17, 0xfc, 0xdb, 0xff, 0x9a, 0xd3,
- 0x6f, 0x58, 0xbb, 0x90, 0x58, 0xa9, 0x3f, 0x3f, 0x8f, 0x78, 0xf6, 0xe9,
- 0x02, 0xc5, 0xff, 0x72, 0x4d, 0xe0, 0x87, 0xf6, 0x58, 0xbb, 0x0a, 0x23,
- 0xd2, 0xf0, 0xbd, 0xfc, 0x7e, 0x71, 0xca, 0x35, 0x8b, 0x8e, 0x75, 0x8a,
- 0x93, 0xc7, 0x72, 0xfb, 0xfd, 0xec, 0x62, 0xf7, 0x31, 0x62, 0xfc, 0xdf,
- 0x76, 0x8d, 0x62, 0xe9, 0xdc, 0x58, 0xb8, 0x1c, 0x81, 0xe1, 0x31, 0x45,
- 0xf7, 0x30, 0xbc, 0xb1, 0x7b, 0x76, 0x74, 0xb1, 0x4c, 0x7d, 0xee, 0x5a,
- 0x22, 0x2b, 0xdf, 0x7f, 0x2c, 0x5e, 0xf3, 0xee, 0x2c, 0x5f, 0xef, 0x7d,
- 0x82, 0x01, 0xd9, 0x62, 0xff, 0x1b, 0xf9, 0x80, 0x9f, 0x4b, 0x16, 0x25,
- 0x8a, 0x63, 0xc6, 0x11, 0xad, 0xc1, 0xe2, 0xc5, 0x4a, 0xed, 0x9c, 0x65,
- 0xe3, 0x8d, 0xeb, 0xa3, 0x58, 0xa1, 0x80, 0x78, 0x40, 0x7d, 0xd1, 0xc8,
- 0x0a, 0x1c, 0x7c, 0x2d, 0xf0, 0xe8, 0x88, 0x36, 0x5e, 0xc3, 0x21, 0xbd,
- 0x16, 0x6e, 0x2c, 0x5f, 0x8d, 0x03, 0x45, 0xc5, 0x8b, 0xef, 0xb3, 0xc1,
- 0x62, 0xf0, 0xde, 0x0b, 0x15, 0x26, 0xff, 0x08, 0xaf, 0xf7, 0xde, 0x2d,
- 0xbd, 0x48, 0xd6, 0x2c, 0x29, 0x46, 0x08, 0x1a, 0xb8, 0x3f, 0x7f, 0x7e,
- 0x61, 0xf1, 0x0d, 0x62, 0xf0, 0x03, 0xed, 0x62, 0xf7, 0x8a, 0x0b, 0x16,
- 0x3e, 0x1b, 0xdd, 0xe4, 0x17, 0xff, 0xb6, 0x93, 0xfa, 0x74, 0x28, 0x6a,
- 0x60, 0xb1, 0x7e, 0x9f, 0x7e, 0x62, 0x58, 0xbb, 0xdc, 0x58, 0xbf, 0x39,
- 0xa6, 0x4e, 0x96, 0x2a, 0x09, 0xa5, 0xf4, 0xd8, 0xc5, 0x1f, 0x4c, 0x72,
- 0x92, 0x18, 0xbf, 0xcc, 0x5e, 0x86, 0x6b, 0x16, 0x2f, 0xfe, 0x6e, 0x8b,
- 0x0f, 0x31, 0x0e, 0x63, 0x58, 0xbf, 0xfa, 0x05, 0x87, 0x72, 0xcf, 0xb9,
- 0xd6, 0x2f, 0xf6, 0x7a, 0x77, 0xb1, 0x01, 0x62, 0xff, 0xf8, 0x07, 0x78,
- 0x43, 0x00, 0x1f, 0xa3, 0xe0, 0x96, 0x2b, 0xa4, 0x44, 0x68, 0xd2, 0xff,
- 0xc1, 0xf7, 0xb6, 0x76, 0xc4, 0x52, 0x75, 0x8b, 0xfd, 0xa9, 0x61, 0x93,
- 0xc1, 0x62, 0xff, 0xda, 0x62, 0xe8, 0xb2, 0x3c, 0x31, 0x62, 0xff, 0xb3,
- 0x7c, 0xe7, 0x7d, 0xf8, 0x2d, 0xac, 0x5f, 0xa7, 0xdc, 0xc2, 0xda, 0x8b,
+ 0xe0, 0x6e, 0x64, 0x73, 0xf1, 0xdf, 0x8d, 0x16, 0x96, 0x2f, 0xfe, 0x9a,
+ 0x42, 0x2f, 0x4b, 0x35, 0x9c, 0x58, 0xbf, 0xff, 0x17, 0x5f, 0x69, 0xa5,
+ 0x05, 0xed, 0x6a, 0x24, 0xb1, 0xc3, 0xc6, 0xbf, 0xff, 0x9b, 0x9a, 0x67,
+ 0xd4, 0x37, 0xbf, 0x9c, 0xe6, 0x2c, 0x5f, 0xfb, 0x51, 0x26, 0xf0, 0x32,
+ 0x6e, 0x2c, 0x5f, 0xec, 0x89, 0x37, 0x8a, 0x16, 0x2c, 0x0c, 0x4c, 0xc8,
+ 0xed, 0x1c, 0x59, 0xdc, 0x40, 0xbf, 0x9e, 0x4f, 0x26, 0xfa, 0xc5, 0x42,
+ 0xa9, 0x0c, 0x4f, 0x78, 0xf3, 0x84, 0x8d, 0x7f, 0xff, 0x38, 0x0b, 0x0e,
+ 0x4f, 0xee, 0x07, 0xa6, 0x81, 0xac, 0x5d, 0x2e, 0x2c, 0x5d, 0x12, 0x19,
+ 0xf9, 0x32, 0xd5, 0xff, 0x9c, 0x7f, 0x8e, 0xdf, 0xae, 0x49, 0x62, 0xa1,
+ 0xb1, 0xc0, 0x94, 0x78, 0xb9, 0x1e, 0xe1, 0xa6, 0xfd, 0xc6, 0x8a, 0xd1,
+ 0xe7, 0x4c, 0x97, 0xa3, 0xaf, 0xcb, 0xbc, 0x78, 0x69, 0x82, 0x16, 0xa5,
+ 0x2f, 0xaf, 0x90, 0xb4, 0x11, 0x65, 0xff, 0xfd, 0xe6, 0x3e, 0x17, 0xb9,
+ 0x06, 0xf0, 0x43, 0xfb, 0x2c, 0x5d, 0x9d, 0xac, 0x5f, 0x9f, 0xc6, 0x67,
+ 0xd6, 0x2f, 0x0f, 0xf8, 0xb1, 0x7d, 0x8d, 0xf3, 0x56, 0x2b, 0xe7, 0xd2,
+ 0xe5, 0x20, 0x1d, 0xbf, 0xfe, 0xce, 0xa0, 0x9f, 0xdc, 0x18, 0x9f, 0x52,
+ 0x58, 0xa9, 0xd1, 0xff, 0xdc, 0x20, 0x4e, 0x5d, 0x7d, 0xcf, 0xe7, 0x16,
+ 0x2f, 0x9b, 0xd1, 0xe5, 0x8a, 0x63, 0xc5, 0xd1, 0x1d, 0xf3, 0x03, 0x06,
+ 0xb1, 0x7f, 0x41, 0x75, 0xb1, 0xec, 0x3d, 0x81, 0x62, 0xd0, 0xb1, 0x7b,
+ 0xcd, 0x3a, 0xc5, 0x4e, 0x6b, 0xfb, 0x11, 0xbf, 0x41, 0xf5, 0x1b, 0xd6,
+ 0x2f, 0xff, 0x79, 0x8c, 0xe1, 0x47, 0xb9, 0xad, 0x42, 0xc5, 0xd0, 0x4b,
+ 0x17, 0xb0, 0xfb, 0x8b, 0x17, 0xd8, 0x41, 0xf9, 0x62, 0xa4, 0x7b, 0x23,
+ 0x16, 0xd1, 0x05, 0xe1, 0xc1, 0xab, 0x17, 0xff, 0x47, 0x5e, 0x28, 0x33,
+ 0x3d, 0xce, 0x2c, 0x5f, 0xc5, 0x12, 0xff, 0x00, 0xb1, 0x7f, 0xe7, 0xfe,
+ 0xa3, 0xcd, 0xd3, 0x0d, 0x62, 0xff, 0xf8, 0x85, 0xee, 0x67, 0x5d, 0xf9,
+ 0xdc, 0xfc, 0x58, 0xbf, 0xdf, 0xc6, 0xd4, 0x83, 0x3a, 0xc5, 0x62, 0x21,
+ 0xfc, 0xa5, 0x76, 0x01, 0x62, 0x86, 0x99, 0x6f, 0xcb, 0xb9, 0x0c, 0x6f,
+ 0x11, 0x53, 0x27, 0xa9, 0xa1, 0xe0, 0x46, 0xe7, 0x7f, 0x9b, 0x41, 0xfb,
+ 0xcd, 0x3a, 0xc5, 0xf6, 0xa3, 0x3b, 0x58, 0xa9, 0x1e, 0xcf, 0x8d, 0xaf,
+ 0xa3, 0xcd, 0xe5, 0x8b, 0xff, 0xff, 0x39, 0xe3, 0x5d, 0x0f, 0xf1, 0xc1,
+ 0x3b, 0x4b, 0x9f, 0x79, 0x2c, 0x53, 0x22, 0xc7, 0xe4, 0x44, 0x45, 0x7e,
+ 0x31, 0xff, 0x07, 0x58, 0xbd, 0xd4, 0x71, 0x62, 0xff, 0xe0, 0xe5, 0x9f,
+ 0x7f, 0xb6, 0xb5, 0x0b, 0x15, 0x08, 0x8c, 0xc2, 0x90, 0x0f, 0x5f, 0x49,
+ 0xc8, 0x0b, 0x17, 0xff, 0x9b, 0xc2, 0xd3, 0xf2, 0x4d, 0xc8, 0x9d, 0x62,
+ 0xdf, 0xc3, 0xed, 0x72, 0x2b, 0xdc, 0xdf, 0x8b, 0x17, 0x46, 0x96, 0x2b,
+ 0xc6, 0xdb, 0x70, 0x7e, 0xfe, 0xdf, 0x05, 0xd6, 0xe6, 0x2c, 0x5f, 0xd9,
+ 0x3f, 0x37, 0x5b, 0xa5, 0x8a, 0x84, 0x45, 0x31, 0x21, 0x19, 0xdf, 0x85,
+ 0xa3, 0x7e, 0xcb, 0x15, 0xb5, 0x92, 0x9d, 0x11, 0xad, 0xce, 0xf9, 0x22,
+ 0x11, 0x91, 0x63, 0x77, 0x44, 0x7d, 0x95, 0x34, 0x29, 0x35, 0x28, 0x0d,
+ 0xe3, 0x40, 0x28, 0x5d, 0x72, 0x13, 0x7e, 0x87, 0x36, 0xe1, 0x6d, 0x8c,
+ 0x58, 0xbf, 0xe2, 0x13, 0x9a, 0x03, 0xc4, 0x96, 0x2b, 0x47, 0x9a, 0x01,
+ 0x3b, 0x84, 0x05, 0x8b, 0xfc, 0x4e, 0x66, 0x13, 0x9a, 0xb1, 0x7f, 0xf6,
+ 0x7b, 0x81, 0xf0, 0xe5, 0x1a, 0x85, 0x8b, 0x14, 0xe8, 0x90, 0x18, 0xc1,
+ 0xcc, 0xef, 0xfc, 0xfe, 0xeb, 0xed, 0xdf, 0x20, 0xc5, 0x8b, 0x6f, 0xc3,
+ 0xf8, 0xf9, 0xb5, 0xf0, 0xf4, 0xf3, 0x2c, 0x5f, 0xfb, 0xa8, 0xf7, 0xdb,
+ 0x7e, 0x77, 0xe5, 0x8b, 0xff, 0x46, 0x89, 0xe7, 0x8d, 0x44, 0x96, 0x2a,
+ 0x11, 0x4b, 0x84, 0x86, 0x21, 0xd3, 0x23, 0xf7, 0xf0, 0xce, 0xbf, 0xff,
+ 0xdf, 0x63, 0x30, 0x23, 0x1d, 0xfd, 0xc1, 0x4b, 0x3b, 0xf2, 0xc5, 0xff,
+ 0xda, 0x60, 0x07, 0xf8, 0x3b, 0xbf, 0x96, 0x2f, 0xff, 0xe9, 0xc7, 0xf8,
+ 0xe6, 0x77, 0xc8, 0xd7, 0xb9, 0x93, 0xac, 0x50, 0xd3, 0x09, 0xd3, 0x29,
+ 0x22, 0xdd, 0x0c, 0xb1, 0x50, 0xae, 0x77, 0x25, 0x13, 0xbc, 0x66, 0x00,
+ 0x30, 0xbf, 0xe9, 0xba, 0xfb, 0x1e, 0x34, 0x6a, 0xc5, 0xf9, 0xbb, 0x03,
+ 0xf1, 0x62, 0xf7, 0xa2, 0x65, 0x8b, 0xcd, 0xa9, 0xa0, 0xf1, 0xf0, 0xa6,
+ 0xfe, 0x8f, 0xc7, 0xa3, 0xeb, 0x17, 0xc1, 0x18, 0xba, 0x58, 0xac, 0x3d,
+ 0x20, 0x85, 0xb7, 0xe9, 0xf6, 0x8a, 0x26, 0x58, 0xb9, 0xe6, 0x58, 0xb4,
+ 0x96, 0x2f, 0xd2, 0xf3, 0x6b, 0xa5, 0x8b, 0xc1, 0x94, 0xcb, 0x15, 0xb4,
+ 0xfc, 0xe4, 0x31, 0xd8, 0x90, 0x0a, 0xab, 0x15, 0x05, 0x75, 0x08, 0x4d,
+ 0x42, 0x11, 0xc8, 0xf9, 0x0a, 0x0a, 0xdb, 0x0d, 0x31, 0xdd, 0x80, 0xd2,
+ 0x27, 0x66, 0xe7, 0x9d, 0xad, 0x95, 0x2f, 0xf8, 0x74, 0xb7, 0xac, 0xb4,
+ 0xb7, 0xe6, 0xc7, 0xa9, 0xd4, 0xa9, 0x16, 0x9e, 0x25, 0xdd, 0x8d, 0xd2,
+ 0x6a, 0x4e, 0x16, 0xa7, 0x4f, 0x4f, 0x49, 0xe8, 0xfd, 0x60, 0x26, 0xf4,
+ 0x82, 0x90, 0x52, 0x34, 0x0a, 0xb5, 0xbe, 0xe5, 0x25, 0x37, 0xd5, 0x9c,
+ 0xc0, 0xa9, 0x48, 0xa6, 0x4e, 0x72, 0x07, 0x29, 0x4e, 0xe8, 0x3a, 0xc5,
+ 0xef, 0xe7, 0x16, 0x2e, 0x0f, 0xa5, 0x8b, 0xa0, 0xeb, 0x16, 0xf0, 0x0d,
+ 0x8f, 0x86, 0xaf, 0xf3, 0x1b, 0xee, 0xfa, 0x6f, 0xac, 0x57, 0x67, 0xbc,
+ 0x44, 0xf4, 0x34, 0x67, 0x64, 0x2b, 0x2f, 0x04, 0x6d, 0xeb, 0x17, 0xfb,
+ 0xed, 0xef, 0xb4, 0x01, 0x62, 0xe6, 0xfa, 0xc5, 0xf6, 0x61, 0x79, 0x62,
+ 0xe8, 0x25, 0x8a, 0xf9, 0xe7, 0x70, 0x5f, 0x79, 0x0d, 0xff, 0xf6, 0x16,
+ 0xcf, 0x8d, 0x6e, 0xf9, 0xfc, 0x03, 0xac, 0x5f, 0xff, 0x0e, 0x1f, 0x5f,
+ 0x31, 0xc7, 0xb8, 0xf3, 0xee, 0x2c, 0x54, 0x91, 0xba, 0x33, 0x1f, 0x2a,
+ 0x5e, 0x77, 0x31, 0x62, 0xfd, 0xd6, 0x7b, 0xec, 0xb1, 0x43, 0x3c, 0x62,
+ 0x1d, 0xbf, 0xfd, 0xa9, 0xa0, 0xfb, 0x4f, 0x9e, 0xe3, 0x71, 0x62, 0x9c,
+ 0xfb, 0xc4, 0x43, 0x7f, 0xa5, 0xe6, 0xf7, 0xb0, 0x0b, 0x17, 0xbe, 0xc1,
+ 0x75, 0x8b, 0xf9, 0xe5, 0x83, 0x7f, 0xac, 0x57, 0x47, 0x9c, 0x72, 0x1b,
+ 0xee, 0xe5, 0x9e, 0x58, 0xbf, 0x4b, 0x6e, 0x07, 0x8b, 0x15, 0xb4, 0xf3,
+ 0xe0, 0x92, 0xf3, 0x6a, 0x16, 0x2f, 0xd2, 0x0f, 0x91, 0x8b, 0x15, 0x87,
+ 0x8a, 0xe3, 0x97, 0xff, 0xe3, 0x96, 0x77, 0xe3, 0x31, 0xb7, 0xe9, 0xde,
+ 0x4b, 0x16, 0xe7, 0xcf, 0xe1, 0xc8, 0x2f, 0xc6, 0x7b, 0x8e, 0x75, 0x8b,
+ 0xff, 0xfe, 0xcf, 0xb8, 0x7c, 0xc3, 0x5c, 0x81, 0x05, 0x13, 0x7e, 0x16,
+ 0x2d, 0x0b, 0x17, 0xff, 0xe8, 0xd7, 0xe0, 0xe1, 0x05, 0x05, 0x13, 0x7e,
+ 0x16, 0x2f, 0xcd, 0xa9, 0xa3, 0xfa, 0x46, 0x70, 0x19, 0x88, 0x46, 0xa4,
+ 0xbb, 0xd7, 0x84, 0xfd, 0x10, 0xf7, 0x1a, 0xf1, 0xe1, 0xca, 0xe4, 0x20,
+ 0x84, 0x11, 0x39, 0x7a, 0x1c, 0x02, 0x27, 0x0e, 0x1f, 0x17, 0xe9, 0xbf,
+ 0x13, 0xe2, 0xc5, 0xbe, 0xb1, 0x76, 0x1d, 0x62, 0xa4, 0x7a, 0x63, 0x2a,
+ 0xdc, 0x12, 0xb6, 0xc2, 0x58, 0xbf, 0xbd, 0xf7, 0x97, 0xa7, 0x58, 0xbf,
+ 0xef, 0xbc, 0xbd, 0x31, 0x41, 0xd6, 0x28, 0x8f, 0xab, 0xc6, 0x17, 0x98,
+ 0x78, 0xb1, 0x7f, 0x1b, 0x82, 0x21, 0x74, 0xb1, 0x7c, 0x27, 0xd4, 0x96,
+ 0x2f, 0x85, 0xa7, 0xe2, 0xc5, 0x0c, 0xf1, 0xb8, 0x47, 0x7e, 0xeb, 0xf1,
+ 0xba, 0x35, 0x8b, 0xec, 0xe3, 0x6f, 0x58, 0xba, 0x77, 0x58, 0xbc, 0xe4,
+ 0x0d, 0xa8, 0x8b, 0x72, 0x22, 0x2d, 0xe1, 0x25, 0xe2, 0x9e, 0x16, 0x2e,
+ 0xc2, 0x58, 0xa6, 0x36, 0x7b, 0xc7, 0x6f, 0xee, 0x16, 0x4e, 0x1c, 0x96,
+ 0x2e, 0xce, 0x2c, 0x5d, 0xa8, 0x58, 0xaf, 0x9a, 0xef, 0x0b, 0xdf, 0xf1,
+ 0x41, 0xd8, 0xb0, 0xf0, 0xb1, 0x74, 0x74, 0xb1, 0x7f, 0xed, 0x69, 0xa6,
+ 0xe6, 0x1a, 0xda, 0x58, 0xbd, 0xf6, 0x92, 0xc5, 0xcd, 0x0b, 0x17, 0xfc,
+ 0xd3, 0xe7, 0xdb, 0x5f, 0x75, 0x8b, 0x98, 0x78, 0x98, 0xe4, 0xc4, 0x20,
+ 0x36, 0xe0, 0xc7, 0x90, 0x4c, 0x1d, 0x08, 0x2d, 0x46, 0xab, 0x90, 0xdd,
+ 0x8c, 0x07, 0x50, 0x80, 0x01, 0x11, 0x46, 0xf5, 0x7f, 0x0c, 0x71, 0x37,
+ 0xb1, 0x62, 0xff, 0xe2, 0xf7, 0x3e, 0xf2, 0xdb, 0x9d, 0xf9, 0x62, 0xb6,
+ 0x1a, 0xe9, 0x34, 0x42, 0x0a, 0x44, 0x39, 0x2e, 0xb1, 0x98, 0x04, 0x5f,
+ 0x7f, 0xb7, 0x66, 0xe4, 0x7d, 0xf7, 0x56, 0x2f, 0xf6, 0x7f, 0xbe, 0x9b,
+ 0x34, 0xb1, 0x7f, 0x66, 0xa4, 0xc5, 0x8b, 0x17, 0xa3, 0xbf, 0x31, 0xf0,
+ 0x88, 0xd6, 0x9d, 0x19, 0xe5, 0x09, 0xcb, 0xf8, 0x3f, 0xff, 0xb7, 0xdd,
+ 0x58, 0xbf, 0xe0, 0xe2, 0x60, 0xe3, 0x4f, 0x32, 0xc5, 0xfb, 0x99, 0x9e,
+ 0xc5, 0x8b, 0xd0, 0x53, 0xac, 0x5f, 0x37, 0xd8, 0xeb, 0x14, 0xc6, 0xfe,
+ 0x61, 0xda, 0xed, 0x10, 0xff, 0x66, 0xbd, 0xcf, 0x32, 0xc5, 0xd3, 0x09,
+ 0x62, 0xe8, 0xea, 0x0d, 0xb1, 0x0e, 0xdf, 0xf4, 0x7b, 0xee, 0x07, 0xef,
+ 0x8b, 0x14, 0x33, 0xe5, 0x22, 0xbb, 0xff, 0xe1, 0xf0, 0x4f, 0xa1, 0x4f,
+ 0x06, 0x86, 0x5e, 0x58, 0xbf, 0xff, 0x78, 0x4e, 0x36, 0x83, 0x96, 0x4f,
+ 0x38, 0x89, 0x62, 0xff, 0xec, 0x9d, 0xe6, 0xdb, 0xf8, 0xe7, 0x1d, 0x62,
+ 0xff, 0xe1, 0x3b, 0x4a, 0x0b, 0xac, 0xef, 0xcb, 0x17, 0xc4, 0x27, 0xeb,
+ 0x6a, 0x23, 0x78, 0x91, 0x71, 0xd9, 0x62, 0xfe, 0xfb, 0x74, 0x2d, 0x01,
+ 0x62, 0xff, 0xf1, 0x66, 0xf8, 0xe7, 0xf3, 0x0a, 0x5c, 0x58, 0xb0, 0x36,
+ 0x9f, 0xd7, 0x0c, 0x2f, 0xef, 0x7d, 0xb6, 0x97, 0x6b, 0x17, 0x82, 0x46,
+ 0xea, 0xc5, 0x68, 0xff, 0x48, 0xa8, 0x21, 0x8d, 0xf6, 0x0e, 0x0d, 0x58,
+ 0xbb, 0x7c, 0x2c, 0x5c, 0x12, 0x65, 0x8b, 0x85, 0xa5, 0x8b, 0x01, 0x62,
+ 0xa6, 0x35, 0x5e, 0x18, 0xbf, 0xb3, 0xd0, 0xfa, 0x35, 0x62, 0xf6, 0x37,
+ 0x96, 0x2f, 0xf9, 0xb5, 0x9d, 0xec, 0x98, 0x61, 0x8b, 0x15, 0xf3, 0xdd,
+ 0x71, 0xca, 0x0a, 0xaa, 0x8d, 0x88, 0xc3, 0x86, 0x60, 0xc4, 0x7b, 0xa3,
+ 0x2e, 0x8a, 0x44, 0x5c, 0x84, 0x5d, 0xff, 0xe8, 0x96, 0xd0, 0xfc, 0xc4,
+ 0x29, 0x67, 0x16, 0x2f, 0x49, 0xc6, 0xb1, 0x44, 0x7d, 0x42, 0x4d, 0xbf,
+ 0xc0, 0x14, 0xc2, 0xf0, 0xa6, 0x58, 0xbf, 0xff, 0x7c, 0x5c, 0x3c, 0x77,
+ 0xd7, 0xd8, 0xe4, 0xd3, 0xac, 0x5f, 0xff, 0xf9, 0xf7, 0x4b, 0x18, 0x8b,
+ 0x01, 0x9e, 0x83, 0xb7, 0xbe, 0xcb, 0x15, 0x3a, 0xfe, 0xf8, 0xcd, 0x32,
+ 0x18, 0x9d, 0x42, 0xfd, 0x88, 0x74, 0xa8, 0x78, 0x71, 0xfe, 0x56, 0x48,
+ 0x21, 0xd6, 0x44, 0x3c, 0x38, 0x12, 0xcd, 0xdc, 0x12, 0xc5, 0xfe, 0xf7,
+ 0x9b, 0x59, 0xdf, 0x96, 0x2f, 0xcc, 0x7e, 0x98, 0x6b, 0x15, 0xa3, 0xde,
+ 0xf9, 0xad, 0xed, 0x37, 0x96, 0x2f, 0x01, 0xce, 0xb1, 0x76, 0x01, 0x62,
+ 0xa0, 0xda, 0x60, 0xed, 0xe7, 0xc3, 0xac, 0x54, 0xe9, 0x92, 0x63, 0xb6,
+ 0x88, 0x89, 0x44, 0x20, 0xfd, 0xff, 0xce, 0x1f, 0xe2, 0x5c, 0xd6, 0xb3,
+ 0xb5, 0x8b, 0x14, 0x91, 0x27, 0xf4, 0xcb, 0xe8, 0xf8, 0xb4, 0xb1, 0x7f,
+ 0x70, 0xb0, 0x64, 0xeb, 0x14, 0x47, 0x9e, 0x61, 0x1d, 0xdd, 0x32, 0xc5,
+ 0xf8, 0xa2, 0x78, 0xed, 0x62, 0xf3, 0xee, 0x42, 0xc5, 0xfc, 0xfa, 0x38,
+ 0xb4, 0x05, 0x8b, 0xb4, 0x05, 0x8a, 0x91, 0xe3, 0xb1, 0x7d, 0xb9, 0xd2,
+ 0x32, 0x18, 0x63, 0x45, 0x2e, 0xcd, 0x50, 0x9d, 0x1b, 0x3b, 0xbc, 0x3a,
+ 0xaf, 0xb8, 0x51, 0x3a, 0xc5, 0xff, 0x4e, 0xff, 0x71, 0x93, 0xf4, 0xb1,
+ 0x5a, 0x3d, 0xd2, 0x23, 0xbf, 0xfe, 0x33, 0x3a, 0xe6, 0x7a, 0x6c, 0x34,
+ 0xb0, 0x0b, 0x15, 0x87, 0xe8, 0xc4, 0x37, 0xfc, 0x46, 0xfd, 0xdb, 0xce,
+ 0x75, 0x8b, 0xfe, 0xc3, 0x33, 0x5d, 0x3b, 0xf4, 0xa8, 0xc3, 0x8b, 0xff,
+ 0x85, 0xc1, 0xfd, 0xcf, 0xdc, 0x98, 0x96, 0x2f, 0xde, 0xfb, 0x90, 0x16,
+ 0x2a, 0x74, 0x5b, 0x7d, 0x21, 0xd1, 0xae, 0x63, 0xac, 0x5f, 0xf7, 0xb2,
+ 0x67, 0x82, 0x89, 0x96, 0x2a, 0x63, 0xd0, 0x71, 0x7b, 0xff, 0x7d, 0xb0,
+ 0x3c, 0x98, 0xc8, 0xed, 0x62, 0xcd, 0x89, 0xe9, 0xea, 0x1d, 0xff, 0x84,
+ 0x07, 0x08, 0xae, 0xeb, 0xa5, 0x46, 0x08, 0x54, 0x95, 0x33, 0x75, 0x1f,
+ 0x98, 0x13, 0x2f, 0xe2, 0x8f, 0x71, 0xb7, 0xac, 0x5f, 0xe0, 0xa7, 0x06,
+ 0x59, 0xf0, 0xaa, 0xc5, 0xd8, 0x4b, 0x14, 0xb1, 0x7f, 0xf4, 0x17, 0x59,
+ 0xef, 0xb6, 0x81, 0xd2, 0xc5, 0x11, 0xe9, 0x78, 0x32, 0xf9, 0xb9, 0xf6,
+ 0x58, 0xbd, 0x9d, 0xf9, 0x62, 0x86, 0x78, 0x07, 0x22, 0xbf, 0x98, 0xb3,
+ 0xdf, 0x65, 0x8b, 0x46, 0x1e, 0x77, 0x08, 0xa8, 0x69, 0x9e, 0xe3, 0x40,
+ 0xa1, 0x5f, 0x7e, 0x21, 0x4b, 0x37, 0x16, 0x2f, 0xff, 0x7d, 0xa6, 0xfb,
+ 0x77, 0xe2, 0xcd, 0xee, 0xb1, 0x78, 0x6f, 0x32, 0xc5, 0xff, 0x36, 0xff,
+ 0xe6, 0xb4, 0xdb, 0xd6, 0x2e, 0xe4, 0x96, 0x2a, 0x0f, 0xcf, 0xe3, 0xde,
+ 0x3d, 0xbb, 0xdc, 0x58, 0xba, 0x00, 0xb1, 0x7f, 0xdc, 0x83, 0x78, 0x21,
+ 0xfd, 0x96, 0x2a, 0x63, 0xd2, 0xf0, 0xbd, 0xb3, 0x11, 0x1a, 0x4d, 0x57,
+ 0xf1, 0xf9, 0xc7, 0x29, 0xd6, 0x2c, 0x75, 0x8b, 0xf1, 0x16, 0x77, 0x25,
+ 0x8a, 0x39, 0xba, 0x0c, 0x4a, 0xa1, 0x11, 0x6e, 0xd3, 0x7f, 0xbd, 0x8c,
+ 0x5e, 0xe6, 0x2c, 0x5f, 0x9b, 0xee, 0xd3, 0xac, 0x5d, 0x1b, 0xab, 0x17,
+ 0x03, 0x92, 0x3c, 0x26, 0x28, 0xbe, 0xe6, 0x17, 0x96, 0x2f, 0x04, 0x8d,
+ 0x2c, 0x53, 0x1f, 0x73, 0x96, 0x88, 0x8a, 0xf7, 0xdf, 0xcb, 0x17, 0xbc,
+ 0xfb, 0xab, 0x17, 0xe0, 0xf7, 0xef, 0x8e, 0x2c, 0x5f, 0xdf, 0x6d, 0x90,
+ 0x3b, 0x2c, 0x57, 0x0f, 0x7b, 0xc5, 0xd7, 0xf8, 0xdf, 0xc4, 0x84, 0xfa,
+ 0x58, 0xb1, 0x2c, 0x53, 0x1e, 0x30, 0x8d, 0x6a, 0x17, 0xa2, 0x27, 0x2f,
+ 0x1c, 0x6f, 0x38, 0x6b, 0xd1, 0x5c, 0xd0, 0xc0, 0x3c, 0x2e, 0xff, 0x0b,
+ 0x17, 0x21, 0x28, 0x71, 0x70, 0xb7, 0xc3, 0xa2, 0x7e, 0xdc, 0x68, 0xbd,
+ 0x36, 0x6e, 0xac, 0x5f, 0x8d, 0x03, 0x4d, 0xc5, 0x8b, 0xef, 0xb3, 0xc9,
+ 0x62, 0xf0, 0xde, 0x4b, 0x15, 0x06, 0xff, 0x08, 0xaf, 0xf7, 0xde, 0x6d,
+ 0xbd, 0x40, 0xd6, 0x2c, 0x28, 0x46, 0x08, 0x1a, 0xb8, 0x3f, 0x7f, 0x7e,
+ 0x25, 0xf1, 0x0d, 0x62, 0xf0, 0x03, 0xed, 0x62, 0xf7, 0x8a, 0x4b, 0x16,
+ 0x3e, 0x1b, 0xdd, 0xe4, 0x17, 0xff, 0xb6, 0x93, 0xfa, 0x34, 0x29, 0x6a,
+ 0x24, 0xb1, 0x7e, 0x8f, 0x7e, 0x26, 0x58, 0xbb, 0xdc, 0x58, 0xbf, 0x39,
+ 0xa6, 0x46, 0x96, 0x2a, 0x49, 0xa5, 0xf4, 0xd8, 0xc5, 0x1f, 0x4c, 0x72,
+ 0x92, 0x18, 0xbf, 0xcc, 0x5e, 0x96, 0x6b, 0x16, 0x2f, 0xfe, 0x6e, 0x8b,
+ 0x0f, 0x13, 0x0e, 0x27, 0x58, 0xbf, 0xfa, 0x45, 0x87, 0x72, 0xcf, 0xb9,
+ 0xd6, 0x2f, 0xf6, 0x7a, 0x37, 0xb1, 0x01, 0x62, 0xff, 0xf8, 0x07, 0x79,
+ 0x4b, 0x00, 0x1f, 0xa7, 0xe0, 0x96, 0x2b, 0xa4, 0x44, 0x68, 0xd2, 0xff,
+ 0xc1, 0xf7, 0xb6, 0x36, 0xcc, 0x50, 0x75, 0x8b, 0xfd, 0xa8, 0x61, 0x93,
+ 0xc9, 0x62, 0xff, 0xda, 0x62, 0xe8, 0xb2, 0x7c, 0x31, 0x62, 0xff, 0xb3,
+ 0x7c, 0x67, 0x7d, 0xf8, 0x2d, 0x2c, 0x5f, 0xa3, 0xdc, 0xc2, 0xda, 0x8b,
0x5d, 0x19, 0x7d, 0x02, 0x86, 0x9a, 0x40, 0xa1, 0xf7, 0x7e, 0xeb, 0xfd,
- 0xbe, 0xe2, 0xc5, 0xfe, 0xe4, 0xc0, 0xd3, 0x73, 0x71, 0x62, 0xff, 0xc3,
- 0x21, 0x7b, 0x92, 0x53, 0xc5, 0x8a, 0x93, 0xf7, 0x63, 0x9b, 0x05, 0xd6,
- 0x2a, 0x0a, 0xec, 0xba, 0x32, 0xed, 0x19, 0xa1, 0x94, 0x51, 0xb6, 0x08,
- 0xa7, 0x7c, 0x29, 0x4c, 0x20, 0xbf, 0x9e, 0x1f, 0x9d, 0x46, 0xb1, 0x7b,
- 0xec, 0x6a, 0xc5, 0xf7, 0x1f, 0x50, 0x58, 0xbf, 0x45, 0x85, 0x83, 0x58,
- 0xbf, 0xfc, 0xd3, 0xe2, 0xcf, 0x7f, 0x1a, 0x1b, 0xd6, 0x2f, 0xfb, 0xbe,
- 0x01, 0xc8, 0x71, 0x09, 0x62, 0xe2, 0x31, 0x62, 0xff, 0xec, 0x8c, 0x38,
- 0x0f, 0x3c, 0xdf, 0x12, 0xc5, 0xfb, 0x59, 0xbf, 0x07, 0xa3, 0xdf, 0x21,
- 0x8a, 0x64, 0x6d, 0x3c, 0x26, 0xef, 0xff, 0xc2, 0x28, 0x61, 0x79, 0xb6,
- 0x73, 0xc4, 0xf0, 0x58, 0xbf, 0xd2, 0x09, 0xfe, 0x77, 0x05, 0x8a, 0x64,
- 0x45, 0x12, 0xb5, 0x7d, 0x3f, 0x50, 0x46, 0x49, 0xe8, 0x58, 0x5f, 0x44,
- 0xf1, 0x3a, 0xc5, 0xe8, 0xf0, 0xc5, 0x8b, 0x41, 0x62, 0xe7, 0xf6, 0xd3,
- 0x62, 0x21, 0xfb, 0xa7, 0x8b, 0x15, 0xb5, 0x13, 0x44, 0xab, 0xe2, 0xeb,
- 0xfe, 0xfb, 0x96, 0x45, 0x09, 0xed, 0x62, 0xff, 0xef, 0xb6, 0xb3, 0x85,
- 0x9b, 0xfe, 0xcb, 0x17, 0xe2, 0xce, 0x0b, 0x6e, 0x1f, 0xfc, 0x47, 0x57,
- 0xfa, 0x40, 0x3f, 0xc9, 0x74, 0xb1, 0x7e, 0xd7, 0x4e, 0xfd, 0x2a, 0x20,
- 0x62, 0xfe, 0x78, 0xc0, 0xe4, 0x34, 0x56, 0x0f, 0x2f, 0x67, 0x04, 0x34,
- 0x53, 0xe1, 0xa6, 0xc9, 0xbd, 0xef, 0xbc, 0x36, 0xa6, 0x54, 0x50, 0xe7,
- 0xbf, 0xef, 0xb6, 0x16, 0x74, 0x3c, 0x58, 0xa1, 0xae, 0xd8, 0x74, 0x5e,
- 0xc3, 0xd1, 0x11, 0x9e, 0x50, 0xe9, 0x43, 0x5b, 0xd1, 0xed, 0x6f, 0x3b,
- 0xbd, 0xe1, 0x4a, 0xc5, 0xff, 0xef, 0xb7, 0xb3, 0x0f, 0xc9, 0xc1, 0xb2,
- 0xc5, 0xdc, 0xe2, 0xc5, 0xf0, 0xfe, 0xe7, 0x58, 0xbf, 0xec, 0x8c, 0x38,
- 0x34, 0xf7, 0xe5, 0x8b, 0x03, 0xa4, 0x5f, 0xe9, 0x21, 0xc6, 0x08, 0x8e,
- 0xff, 0x03, 0xcd, 0x19, 0xe7, 0xa5, 0x8a, 0xed, 0x35, 0x47, 0x86, 0xe1,
- 0x21, 0x5f, 0x87, 0xb0, 0x38, 0xf6, 0x05, 0x8b, 0xfb, 0xae, 0xff, 0xdb,
- 0xee, 0x2c, 0x5f, 0x9f, 0x5e, 0xce, 0x96, 0x2f, 0x86, 0xd3, 0x1a, 0xc5,
- 0xa7, 0x47, 0x98, 0x22, 0x9b, 0xff, 0x98, 0x7b, 0x73, 0x3b, 0x03, 0x97,
- 0x96, 0x2d, 0x08, 0x1f, 0x6f, 0x09, 0xea, 0x53, 0x16, 0x78, 0x77, 0x54,
- 0xb2, 0x6d, 0xf2, 0x78, 0xd9, 0xa3, 0xdc, 0x73, 0x51, 0x46, 0x93, 0x73,
- 0x41, 0x62, 0xfe, 0xef, 0xc3, 0xcc, 0x35, 0x62, 0xfe, 0xfb, 0x7b, 0x99,
- 0xe5, 0x8b, 0xec, 0x89, 0x8e, 0xb1, 0x43, 0x44, 0xc6, 0x0b, 0xf4, 0x60,
- 0x19, 0x75, 0xa5, 0x62, 0xfa, 0x49, 0x80, 0xb1, 0x6c, 0xf9, 0xb2, 0xf0,
- 0x8d, 0xfe, 0xd1, 0x39, 0x81, 0xf6, 0x62, 0xc5, 0xc0, 0xde, 0xb1, 0x7e,
- 0xf7, 0xc5, 0x18, 0x96, 0x28, 0x67, 0xfb, 0xf3, 0x81, 0x0d, 0x5f, 0xfe,
- 0x60, 0x75, 0xf6, 0xf9, 0x4e, 0x6b, 0x16, 0x2f, 0xf0, 0xfb, 0x86, 0x61,
- 0x46, 0xb1, 0x61, 0xac, 0x5f, 0xfa, 0x13, 0xb9, 0x9a, 0xf7, 0x26, 0x0b,
- 0x17, 0xfd, 0xd8, 0xe7, 0x8c, 0x3f, 0xca, 0xc5, 0xfd, 0xdf, 0xa2, 0xfc,
- 0x92, 0xc5, 0xfe, 0x6f, 0x71, 0xfb, 0x01, 0x8b, 0x17, 0x6a, 0x35, 0x46,
- 0x0a, 0x57, 0xcf, 0x71, 0xcd, 0xaf, 0xfc, 0xfa, 0xc2, 0x07, 0x3d, 0xce,
- 0xd6, 0x2f, 0xff, 0xff, 0xec, 0xf7, 0xdc, 0x8d, 0xdb, 0xcd, 0x3b, 0xfb,
- 0x7e, 0x0f, 0x6e, 0x1d, 0xcb, 0xb8, 0x2e, 0x20, 0xb2, 0xff, 0xce, 0xe6,
- 0xf4, 0xe3, 0xda, 0x69, 0x8b, 0x88, 0x2c, 0xbf, 0xfb, 0xed, 0xf6, 0x92,
- 0xf6, 0xd3, 0x4c, 0x5c, 0x41, 0x65, 0xfe, 0x96, 0x2f, 0x6d, 0x34, 0xc5,
- 0xc4, 0x16, 0x5f, 0xc7, 0xc1, 0xed, 0x34, 0xc5, 0xc4, 0x16, 0x5f, 0xff,
- 0xf3, 0x91, 0x31, 0xf6, 0xf3, 0xaf, 0xb6, 0x98, 0xd8, 0xf0, 0xc5, 0xc4,
- 0x16, 0x5d, 0xde, 0xd1, 0xa7, 0x47, 0xd2, 0x96, 0x95, 0x5d, 0x10, 0x90,
- 0x2a, 0x55, 0x6c, 0x7d, 0x00, 0xa5, 0x1f, 0xdf, 0xe6, 0x93, 0x79, 0xee,
- 0x76, 0xb1, 0x7c, 0xfa, 0x03, 0xac, 0x5f, 0xfd, 0xf6, 0xfb, 0x49, 0x7b,
- 0x69, 0xa6, 0x2e, 0x20, 0xb2, 0xff, 0xa2, 0xe7, 0x4d, 0x1e, 0xd3, 0x4c,
- 0x5c, 0x41, 0x65, 0xfb, 0xdc, 0x93, 0xed, 0xe9, 0x14, 0x81, 0xaa, 0xdf,
- 0xfe, 0xdb, 0xd7, 0xdb, 0xa9, 0xf7, 0x36, 0x9a, 0x62, 0xe2, 0x0b, 0x2f,
- 0xff, 0xfe, 0x22, 0x63, 0xed, 0x16, 0x6d, 0xe7, 0x5f, 0x6d, 0x31, 0xb1,
- 0xe1, 0x8b, 0x88, 0x2c, 0xac, 0x4c, 0xaf, 0xb4, 0x47, 0x61, 0xbf, 0xcd,
- 0xa6, 0x36, 0x3c, 0x31, 0x71, 0x05, 0x97, 0xfe, 0x8c, 0xe2, 0x63, 0xb9,
- 0x77, 0x05, 0xc4, 0x16, 0x57, 0xd1, 0x22, 0x24, 0x3b, 0xff, 0xe7, 0x7e,
- 0xe1, 0xcf, 0xb0, 0xc7, 0x3a, 0x94, 0x8b, 0xff, 0x64, 0x20, 0x2e, 0x68,
- 0xa3, 0xd9, 0x5c, 0x41, 0x65, 0x74, 0x8c, 0x4d, 0x11, 0xf1, 0x42, 0xff,
- 0xdd, 0x36, 0xbc, 0xe0, 0xe6, 0xd3, 0x17, 0x10, 0x59, 0x7f, 0x7d, 0xbf,
- 0xf6, 0x02, 0xa0, 0x0b, 0x2f, 0xd8, 0x0d, 0xa6, 0x98, 0xb8, 0x82, 0xcb,
- 0xb3, 0xdd, 0x1f, 0xaf, 0xce, 0xeb, 0xb4, 0x7a, 0x72, 0x18, 0xd7, 0xf1,
- 0xf0, 0x7b, 0x4d, 0x31, 0x71, 0x05, 0x97, 0xfe, 0xeb, 0xed, 0xa6, 0x36,
- 0x3c, 0x31, 0x71, 0x05, 0x97, 0x66, 0xd7, 0x44, 0x87, 0x10, 0x2f, 0xf0,
- 0x98, 0xee, 0x5d, 0xc1, 0x71, 0x05, 0x97, 0xfe, 0xc6, 0xdf, 0x85, 0x83,
- 0x78, 0x2e, 0x20, 0xb0, 0xe7, 0x83, 0x43, 0x5e, 0x8d, 0xd1, 0xb8, 0x0d,
- 0x8a, 0x3f, 0x1e, 0x47, 0x0b, 0xe8, 0xc9, 0x45, 0x0b, 0x93, 0x1c, 0x2e,
- 0x04, 0xaa, 0x20, 0xb0, 0x22, 0x22, 0xee, 0x7e, 0x96, 0x28, 0x6c, 0xb2,
- 0x7c, 0x3a, 0xea, 0x11, 0x80, 0xa5, 0x08, 0xf8, 0xe2, 0xb1, 0x98, 0x19,
- 0xd1, 0xac, 0x42, 0x5c, 0xa5, 0xb4, 0xdd, 0x0d, 0xd5, 0x8b, 0xd3, 0x0d,
- 0xd5, 0x8a, 0x93, 0x76, 0x43, 0x75, 0x1b, 0x38, 0xf0, 0x6e, 0x1d, 0xc2,
- 0x8f, 0x45, 0xe0, 0xa6, 0x2a, 0x94, 0x21, 0xaf, 0xfd, 0x02, 0xcf, 0x7d,
- 0xb3, 0xbf, 0x2c, 0x5f, 0xc5, 0x0e, 0x7b, 0xf2, 0xb1, 0x7f, 0xff, 0xec,
- 0xf7, 0xde, 0x03, 0xcd, 0x36, 0x6f, 0x0f, 0x5f, 0x6e, 0xfc, 0xb1, 0x73,
- 0x1a, 0xb1, 0x58, 0x8f, 0x56, 0x3f, 0x39, 0x77, 0xdc, 0x2f, 0xf4, 0xfd,
- 0x8c, 0xee, 0x1c, 0x58, 0xbf, 0x4f, 0xb9, 0xf6, 0x58, 0xbf, 0xf6, 0xb0,
- 0xdf, 0xe1, 0xc5, 0xa8, 0xd6, 0x2f, 0xfb, 0xb2, 0xc6, 0x3e, 0x10, 0x16,
- 0x2f, 0xff, 0xff, 0xcf, 0x11, 0x39, 0x99, 0xbd, 0xb9, 0xfc, 0x06, 0xce,
- 0x7b, 0x8e, 0x7c, 0xef, 0xcb, 0x17, 0xfe, 0x77, 0x8f, 0x0e, 0xe5, 0xdc,
- 0x16, 0x2f, 0x73, 0x09, 0x62, 0xd0, 0x88, 0xf6, 0xfc, 0x7f, 0x7f, 0xf9,
- 0xfa, 0x92, 0x19, 0x66, 0xfd, 0x37, 0x16, 0x2f, 0xfd, 0xc8, 0xa0, 0x21,
- 0xc5, 0x01, 0x0d, 0x62, 0xa3, 0x54, 0xe9, 0x03, 0x61, 0x94, 0x62, 0x11,
- 0xa7, 0x1d, 0xc3, 0x93, 0xe5, 0x3e, 0x4b, 0xbf, 0xec, 0xf1, 0x98, 0x43,
- 0xfc, 0xac, 0x5f, 0xfd, 0x3d, 0xc0, 0x33, 0xf3, 0xd3, 0xd9, 0x8b, 0x17,
- 0xe8, 0x6e, 0xee, 0x8a, 0x35, 0x8b, 0x7d, 0x8f, 0xed, 0xd2, 0xaf, 0xbc,
- 0x52, 0x75, 0x8b, 0xf6, 0xa7, 0xb8, 0x71, 0x62, 0xa3, 0x4c, 0x9a, 0x10,
- 0xb4, 0x62, 0x6d, 0x11, 0x5f, 0xf4, 0x9b, 0xfc, 0x22, 0xce, 0xd6, 0x2f,
- 0x1d, 0xfc, 0xb1, 0x73, 0xf1, 0x62, 0xee, 0x74, 0xb1, 0x7a, 0x0d, 0xe5,
- 0x8b, 0xff, 0xde, 0x62, 0x14, 0x33, 0x80, 0xf7, 0xbb, 0x58, 0xb1, 0x44,
- 0x7d, 0x21, 0x8e, 0xdf, 0xf7, 0x1f, 0xbd, 0x91, 0x7d, 0xb4, 0xb1, 0x7f,
- 0x66, 0x80, 0x76, 0xe2, 0xc5, 0xc2, 0xe7, 0x8f, 0xb3, 0x64, 0xfa, 0xf4,
- 0xb1, 0xd6, 0x2c, 0x6a, 0xc5, 0xb3, 0xa3, 0x5f, 0xa1, 0xcb, 0xff, 0xb7,
- 0xef, 0x9e, 0x3f, 0xfb, 0x86, 0x79, 0x62, 0xb1, 0x36, 0x60, 0x42, 0x57,
- 0x65, 0x80, 0x32, 0x7b, 0xf8, 0x51, 0x49, 0x71, 0x96, 0x2f, 0xf1, 0x07,
- 0x9a, 0x29, 0x3a, 0xc5, 0xfc, 0x2f, 0x14, 0xfb, 0x8b, 0x15, 0x87, 0xc2,
- 0x03, 0x3b, 0x4a, 0xc5, 0x41, 0x59, 0x19, 0xa3, 0xbf, 0x17, 0x04, 0x7d,
- 0x04, 0x8d, 0xc8, 0x47, 0xee, 0x90, 0xd4, 0xae, 0xd9, 0xe4, 0x74, 0x1d,
- 0xa1, 0xbc, 0xb5, 0xcb, 0xc7, 0x6e, 0x2c, 0x5f, 0xfb, 0x99, 0xf6, 0x83,
- 0x0f, 0x0e, 0xb1, 0x7e, 0x84, 0xef, 0x7f, 0xac, 0x54, 0x68, 0x85, 0x34,
- 0x75, 0xcf, 0xaf, 0xfe, 0xce, 0xfd, 0xc6, 0x29, 0x03, 0x9d, 0x62, 0xff,
- 0x8c, 0x0c, 0x9f, 0xac, 0x2e, 0x96, 0x2f, 0xb7, 0x73, 0x23, 0x58, 0xbf,
- 0xff, 0x67, 0xbe, 0xdb, 0x4d, 0x7d, 0xa5, 0x86, 0x38, 0x16, 0x2f, 0x8e,
- 0x3c, 0x3a, 0xc5, 0x2c, 0x5f, 0xe6, 0xf9, 0x67, 0xa4, 0x0b, 0x17, 0xbe,
- 0x30, 0xce, 0x6f, 0xbc, 0x19, 0x7f, 0xdb, 0xd8, 0x86, 0x2f, 0xe1, 0xd6,
- 0x2f, 0xe7, 0xfb, 0x72, 0x60, 0xb1, 0x5b, 0x51, 0xfb, 0x2c, 0x38, 0x69,
- 0xc3, 0xbb, 0xff, 0x05, 0xf0, 0x8b, 0x03, 0x92, 0x02, 0xc5, 0xf8, 0xe7,
- 0x67, 0x82, 0xc5, 0xfe, 0xcf, 0xb7, 0x18, 0x50, 0x58, 0xa8, 0xd5, 0x6b,
- 0x32, 0x27, 0xcf, 0x08, 0x9b, 0xd1, 0xab, 0x88, 0xf7, 0x7a, 0x0e, 0xe9,
- 0x45, 0xf7, 0x7c, 0x9e, 0xd6, 0x2f, 0xfd, 0x0c, 0xee, 0x1a, 0x9f, 0x3f,
- 0x96, 0x2f, 0x1e, 0x60, 0xb1, 0x7e, 0xc1, 0xfc, 0x46, 0x2c, 0x56, 0xd4,
- 0x56, 0x44, 0x4a, 0xe8, 0x04, 0x3b, 0x7f, 0xdd, 0x7d, 0x87, 0xf9, 0xf7,
- 0x16, 0x2f, 0x0d, 0xfc, 0xb1, 0x7f, 0xfe, 0xf7, 0xb2, 0x28, 0x64, 0x7b,
- 0x7b, 0x92, 0x9e, 0x2c, 0x5f, 0xfe, 0xf6, 0x45, 0x0c, 0x8f, 0xb9, 0x29,
- 0xe2, 0xc5, 0xe2, 0x9e, 0xf6, 0xa2, 0x9b, 0xcb, 0x57, 0xfe, 0xe4, 0x94,
- 0xc3, 0xdf, 0xc2, 0x58, 0xad, 0x27, 0x5e, 0x73, 0xe7, 0x3b, 0x04, 0x30,
- 0xf8, 0x6d, 0x79, 0xb6, 0x71, 0x62, 0xf3, 0x77, 0xe5, 0x8b, 0xdf, 0x8d,
- 0x96, 0x2e, 0xc3, 0x38, 0x6f, 0x04, 0x3d, 0x7f, 0xed, 0x13, 0x98, 0xfa,
- 0xd6, 0x76, 0xb1, 0x7f, 0x9b, 0x47, 0x9c, 0x21, 0xac, 0x5c, 0xc6, 0xac,
- 0x57, 0xcf, 0x28, 0x8c, 0xaf, 0xee, 0x30, 0xf0, 0xce, 0x2c, 0x5f, 0xcf,
- 0xa7, 0x1b, 0x62, 0xc5, 0xda, 0x02, 0xc5, 0xd8, 0x62, 0xc5, 0x39, 0xb0,
- 0xf0, 0xc5, 0x4a, 0x7b, 0xd1, 0xad, 0x8c, 0xb7, 0x21, 0x15, 0xd9, 0x0f,
- 0xcb, 0xfc, 0xb9, 0x7e, 0x72, 0xf7, 0x25, 0x62, 0xe7, 0x65, 0x8a, 0xd1,
- 0xbd, 0x39, 0x3d, 0x76, 0x8c, 0x80, 0x42, 0x9e, 0xf8, 0xcc, 0xfb, 0xac,
- 0x5f, 0x1b, 0xa6, 0x31, 0x62, 0xfd, 0x1b, 0xfe, 0x77, 0x16, 0x2f, 0xf8,
- 0xdc, 0x29, 0x87, 0xb3, 0xa5, 0x8b, 0xf4, 0x7e, 0xd9, 0xcf, 0x2c, 0x56,
- 0xc4, 0x8b, 0x8c, 0x25, 0x62, 0xc1, 0x1d, 0x5f, 0xc6, 0xfe, 0x7b, 0xf6,
- 0x2c, 0x5f, 0xe2, 0xc1, 0xfe, 0x4c, 0x25, 0x8b, 0xe8, 0x66, 0xa5, 0x62,
- 0xa5, 0x10, 0xba, 0x30, 0x23, 0x3b, 0xff, 0xfd, 0xa9, 0xfc, 0xeb, 0x53,
- 0x1f, 0x9d, 0xcd, 0xce, 0xfc, 0xb1, 0x52, 0xcb, 0x2e, 0xc9, 0x60, 0xed,
- 0x2b, 0x61, 0xe5, 0x7a, 0x80, 0xa4, 0xa1, 0xb6, 0x28, 0x62, 0x86, 0x5d,
- 0x7c, 0x51, 0x73, 0x16, 0x2f, 0xd0, 0xc8, 0xfd, 0x2b, 0x17, 0xff, 0xf4,
- 0xf8, 0x38, 0xc7, 0x9e, 0x9d, 0xed, 0xe0, 0x4c, 0x16, 0x2f, 0xfd, 0x31,
- 0x9f, 0xed, 0xad, 0x3c, 0x16, 0x2a, 0x34, 0x4f, 0x92, 0xfd, 0x2c, 0x53,
- 0x26, 0x35, 0x11, 0x19, 0x43, 0x23, 0x64, 0x8e, 0xff, 0x47, 0x1c, 0x97,
- 0x79, 0xe5, 0x8b, 0xf0, 0xf3, 0x0b, 0xa5, 0x8b, 0xf7, 0x7e, 0x27, 0xfa,
- 0xc5, 0xd3, 0x12, 0xc5, 0x46, 0x7d, 0x30, 0x28, 0x01, 0x4d, 0x62, 0x62,
- 0x8c, 0x8a, 0x28, 0x4f, 0xdf, 0xfd, 0xa2, 0x17, 0x7e, 0x2c, 0x8d, 0xc9,
- 0x62, 0xff, 0xfe, 0x1f, 0xc5, 0x1b, 0x66, 0xb5, 0x93, 0xdc, 0x18, 0xeb,
- 0x17, 0xf9, 0xe2, 0x21, 0x78, 0xa5, 0x62, 0xfe, 0x18, 0x7e, 0xf3, 0x18,
- 0xb1, 0x71, 0x44, 0xb1, 0x4e, 0x79, 0x22, 0x31, 0xbb, 0xe6, 0xac, 0x5f,
- 0xba, 0x1b, 0x14, 0x6b, 0x17, 0xfd, 0xf9, 0xec, 0xb0, 0x6f, 0x05, 0x8b,
- 0xcf, 0xa8, 0xd6, 0x2e, 0x04, 0xac, 0x5f, 0x34, 0x9f, 0x16, 0x29, 0x62,
- 0xfe, 0x73, 0x7d, 0x3a, 0x02, 0xc5, 0x0c, 0xdd, 0x90, 0x65, 0xff, 0xfe,
- 0x96, 0x19, 0x48, 0xba, 0xf6, 0x74, 0x39, 0xe8, 0x33, 0xac, 0x5c, 0x09,
- 0x58, 0xba, 0x4d, 0x58, 0xbf, 0xec, 0xf7, 0x24, 0xe1, 0xe4, 0x4b, 0x17,
- 0xfb, 0x99, 0xf6, 0xe0, 0xa3, 0x58, 0xb8, 0xc3, 0x12, 0x2f, 0xf8, 0xb3,
- 0x7b, 0xc3, 0x8c, 0x35, 0x8a, 0xe9, 0x50, 0x43, 0x0f, 0x68, 0x5c, 0xeb,
- 0x9f, 0x20, 0x03, 0x20, 0x5c, 0x5c, 0x86, 0x38, 0x76, 0x61, 0xa8, 0x63,
- 0x57, 0x8c, 0x30, 0xc4, 0x8b, 0x1d, 0x20, 0x21, 0xa1, 0xbc, 0xef, 0xa4,
- 0x80, 0x88, 0xe4, 0x0e, 0x18, 0x17, 0xff, 0xf8, 0x0f, 0xf7, 0x6f, 0x8b,
- 0xf3, 0xd3, 0x77, 0x06, 0x3a, 0xc5, 0x0d, 0x70, 0x37, 0x06, 0x7a, 0x2a,
- 0x8a, 0x59, 0x2f, 0x90, 0xea, 0x35, 0xda, 0x1e, 0x91, 0x7b, 0x5d, 0xfb,
- 0xe3, 0xce, 0x17, 0x5f, 0xff, 0xa1, 0x3a, 0x00, 0xf5, 0x8c, 0x6f, 0x3f,
- 0x27, 0x58, 0xbf, 0xbd, 0x39, 0xfc, 0x8d, 0x62, 0xec, 0x3a, 0xc5, 0x62,
- 0x27, 0x3b, 0x57, 0xe1, 0x75, 0xff, 0xd9, 0xff, 0xbb, 0x7a, 0x70, 0xa2,
- 0x58, 0xa0, 0xab, 0xef, 0x6b, 0x4c, 0xeb, 0xdc, 0x70, 0xd9, 0x84, 0xe5,
- 0x68, 0xda, 0x72, 0x7a, 0xf0, 0xd9, 0x75, 0x1d, 0xcb, 0x31, 0x69, 0xde,
- 0xc8, 0xa1, 0xb7, 0xa8, 0x71, 0x1e, 0x38, 0x0f, 0xd3, 0x6f, 0xde, 0x9e,
- 0x64, 0x08, 0xd9, 0x0a, 0x90, 0xc5, 0xca, 0x5f, 0xf7, 0xa5, 0x5f, 0x0a,
- 0x77, 0x57, 0x7c, 0x3c, 0xf6, 0x4c, 0x2e, 0x0f, 0xcb, 0x17, 0xf6, 0x00,
- 0x0d, 0xa8, 0x2c, 0x5e, 0xf8, 0x8d, 0x58, 0xbb, 0xac, 0x58, 0xbf, 0x64,
- 0x53, 0xdf, 0x16, 0x28, 0x68, 0x8f, 0x62, 0xe7, 0x1f, 0xe0, 0xc5, 0xff,
- 0xa4, 0xfb, 0x2f, 0x1e, 0x0d, 0x8c, 0x58, 0xbb, 0x0c, 0x58, 0xba, 0x7c,
- 0xb1, 0x7f, 0xfc, 0xc5, 0x20, 0xc1, 0x05, 0xdb, 0xed, 0xa8, 0x2c, 0x54,
- 0x68, 0x81, 0xe8, 0x63, 0x82, 0xf7, 0xcf, 0xf7, 0x02, 0xc5, 0x8e, 0xb1,
- 0x50, 0x4c, 0xab, 0x21, 0x89, 0xa3, 0x2f, 0x11, 0x5f, 0xe8, 0x31, 0x61,
- 0xc5, 0xf5, 0x8b, 0xf7, 0xdd, 0x89, 0xd6, 0x2f, 0xfa, 0x5b, 0x58, 0xdf,
- 0x91, 0xac, 0x5f, 0xfb, 0x3d, 0xcf, 0xb1, 0xdf, 0x34, 0xb1, 0x76, 0x0d,
- 0x62, 0xa5, 0x1c, 0xa6, 0x99, 0xfc, 0x98, 0x8d, 0xf7, 0x9f, 0x5f, 0xb3,
- 0x6e, 0x03, 0xcb, 0x17, 0xdb, 0x7d, 0x3b, 0xd6, 0x2f, 0x86, 0x52, 0x1a,
- 0xc5, 0xf7, 0x52, 0x76, 0x58, 0xad, 0xa7, 0x8d, 0x84, 0x77, 0x8f, 0x9e,
- 0x58, 0xbf, 0x61, 0x8d, 0x23, 0x58, 0xbf, 0xec, 0xc3, 0x87, 0xbb, 0x25,
- 0x05, 0x8a, 0xc4, 0x40, 0xb0, 0xef, 0x0a, 0x2f, 0xf7, 0x5f, 0x90, 0xda,
- 0x63, 0x58, 0xb9, 0xcd, 0x58, 0xad, 0x1e, 0x77, 0x8d, 0xaf, 0x9c, 0xef,
- 0x12, 0xc5, 0xff, 0xe8, 0x9a, 0x2d, 0xad, 0xdf, 0x1c, 0x36, 0x3a, 0xc5,
- 0xf9, 0xa4, 0xc9, 0x89, 0x62, 0xff, 0x6d, 0xfb, 0x80, 0x0d, 0xf5, 0x8b,
- 0x69, 0x62, 0xf7, 0xbb, 0xe2, 0xc5, 0x61, 0xb1, 0x71, 0x2a, 0x94, 0x7f,
- 0xb2, 0x83, 0x94, 0x93, 0x3d, 0xff, 0xff, 0x9e, 0x21, 0x40, 0x5d, 0x6d,
- 0xfb, 0x7b, 0xd3, 0xdc, 0xc7, 0x3c, 0x58, 0xbf, 0x13, 0xee, 0x47, 0x12,
- 0xc5, 0xf4, 0x5c, 0x9f, 0x2c, 0x57, 0x48, 0xc4, 0x89, 0xcc, 0x45, 0xb7,
- 0xf6, 0xfd, 0x3c, 0xb6, 0xca, 0xc5, 0xff, 0xc4, 0xfe, 0x6d, 0x7e, 0x4f,
- 0xc7, 0x58, 0xa5, 0x8a, 0x11, 0xe7, 0x98, 0x87, 0x7f, 0xf4, 0x3f, 0x3a,
- 0x8e, 0x7d, 0xc7, 0x82, 0xc5, 0xf1, 0x3b, 0xef, 0x58, 0x93, 0xc6, 0xbf,
- 0xa7, 0xaf, 0x71, 0xfb, 0x58, 0xbe, 0xfe, 0x3c, 0x6b, 0x17, 0xd8, 0x77,
- 0xed, 0x62, 0xb7, 0x11, 0x52, 0x46, 0x7c, 0x30, 0x0c, 0x8e, 0xf3, 0x77,
- 0x12, 0xc5, 0xf0, 0x82, 0xe7, 0x65, 0x8b, 0xf6, 0x64, 0x62, 0xe2, 0xc5,
- 0xf6, 0x89, 0x80, 0xb1, 0x7c, 0xdd, 0x3e, 0x96, 0x2e, 0x90, 0x2c, 0x5f,
- 0x0a, 0x31, 0x04, 0xf9, 0xba, 0x0c, 0x8e, 0x99, 0x13, 0x3f, 0x5c, 0xb0,
- 0x16, 0x2e, 0xce, 0x96, 0x2f, 0xd9, 0xad, 0x36, 0x96, 0x2b, 0x70, 0xf4,
- 0xbe, 0x24, 0x01, 0x8b, 0xe9, 0xef, 0x3a, 0x58, 0xbf, 0x06, 0xd3, 0xc7,
- 0x58, 0xa7, 0x3c, 0xc1, 0x12, 0x5f, 0xf7, 0xdf, 0x9f, 0x68, 0xdc, 0x96,
- 0x2f, 0x9e, 0x30, 0xe0, 0xb1, 0x41, 0x56, 0x5f, 0xae, 0xc7, 0x0a, 0x89,
- 0x8d, 0x96, 0x11, 0x93, 0x8d, 0x2f, 0x0a, 0x8d, 0x6d, 0xee, 0x14, 0x8c,
- 0xf9, 0xb8, 0x45, 0x14, 0x64, 0x5a, 0x87, 0xe9, 0xcc, 0xbf, 0x08, 0x17,
- 0x8c, 0x48, 0x08, 0x01, 0x71, 0xfe, 0x13, 0xfa, 0x18, 0x42, 0x74, 0x31,
- 0xf8, 0x32, 0x1d, 0xd3, 0x9b, 0xfd, 0x84, 0xc0, 0xe7, 0xd9, 0x62, 0xdb,
- 0x8b, 0x17, 0xc3, 0x3b, 0xc1, 0x62, 0x98, 0xdc, 0x08, 0x56, 0xb6, 0xa2,
- 0x28, 0x9a, 0xaf, 0x34, 0x62, 0x58, 0xb9, 0xe5, 0x62, 0xfd, 0x20, 0x6e,
- 0xf1, 0x62, 0xe3, 0x89, 0x62, 0xfc, 0xfe, 0xf8, 0x89, 0x62, 0xe3, 0xef,
- 0x58, 0xbf, 0xe1, 0x3b, 0x13, 0xf9, 0xfe, 0xb1, 0x5b, 0x51, 0x9f, 0x22,
- 0xcc, 0x51, 0xf1, 0x82, 0x28, 0xe0, 0xd5, 0xff, 0xd3, 0xc6, 0x04, 0xe9,
- 0xbf, 0x23, 0x58, 0xbc, 0xe2, 0x0b, 0xac, 0x5f, 0xfb, 0x3a, 0x2c, 0xe6,
- 0xce, 0x6a, 0x56, 0x28, 0x68, 0xfb, 0x25, 0x6f, 0x21, 0x86, 0x43, 0x7f,
- 0xfa, 0x05, 0x3b, 0x4e, 0x52, 0x6f, 0x9a, 0x35, 0x8b, 0xec, 0x16, 0xa3,
- 0x58, 0xbf, 0x39, 0xf3, 0xe7, 0x58, 0xae, 0xd1, 0x33, 0xa4, 0xdf, 0x12,
- 0x58, 0xc5, 0x8b, 0xde, 0xd4, 0xac, 0x5e, 0xe3, 0xf9, 0x62, 0xfb, 0x23,
- 0x0e, 0x0b, 0x17, 0x83, 0x20, 0x2c, 0x57, 0x67, 0xc0, 0x43, 0xbe, 0x25,
- 0xbf, 0xbd, 0xbf, 0x0b, 0x06, 0xb1, 0x51, 0x1e, 0xf7, 0x0b, 0xef, 0xdc,
- 0xc8, 0x36, 0x96, 0x2f, 0xd1, 0x41, 0xfb, 0xe2, 0xc5, 0x61, 0xe9, 0xf0,
- 0xa2, 0xf0, 0xb7, 0x37, 0x56, 0x2d, 0xbd, 0x62, 0xff, 0xb5, 0xf7, 0x0d,
- 0xfe, 0xc0, 0x58, 0xa9, 0x3c, 0xe6, 0x14, 0xbf, 0x98, 0xa3, 0xf8, 0xb8,
- 0xb1, 0x5f, 0x3c, 0xff, 0x10, 0x5f, 0x7f, 0x00, 0xeb, 0x17, 0x6e, 0x6e,
- 0xac, 0x5e, 0xe4, 0x23, 0x58, 0xa8, 0xd3, 0x42, 0xc8, 0x60, 0x91, 0x10,
- 0x88, 0x83, 0x1e, 0xa9, 0x5e, 0x2a, 0x81, 0x26, 0x47, 0xd0, 0xd0, 0xd6,
- 0x88, 0xc4, 0xe2, 0x6f, 0x0d, 0xb2, 0x76, 0xf4, 0x6c, 0x77, 0xa5, 0xb4,
- 0xb1, 0x76, 0xd0, 0xd6, 0x28, 0xe6, 0xdd, 0xc7, 0x2e, 0x6d, 0xeb, 0x17,
- 0xa2, 0x6f, 0xac, 0x5f, 0xd3, 0xa7, 0x89, 0xbe, 0xb1, 0x7e, 0xe0, 0xe4,
- 0xa3, 0x73, 0xcc, 0xe0, 0xf5, 0xff, 0xef, 0x7a, 0x4a, 0x4d, 0x36, 0x61,
- 0xb8, 0x75, 0x8b, 0xfb, 0x23, 0x9f, 0xfe, 0x56, 0x2f, 0xd9, 0x17, 0xf0,
- 0x96, 0x2f, 0xd8, 0x19, 0x08, 0x0b, 0x17, 0xe0, 0x3b, 0xc0, 0xeb, 0x15,
- 0x27, 0xa3, 0x85, 0x37, 0xcc, 0x66, 0x69, 0x62, 0x99, 0x33, 0x9d, 0x27,
- 0xfc, 0xb8, 0x9e, 0x78, 0x41, 0x78, 0xf2, 0x75, 0x8a, 0xc5, 0x48, 0x5d,
- 0xb2, 0xea, 0x37, 0x73, 0xa4, 0xdf, 0x1f, 0x5a, 0x95, 0x8b, 0xff, 0xef,
- 0x7a, 0x4f, 0x9f, 0xfc, 0xb1, 0x49, 0xd6, 0x2f, 0xdc, 0xe3, 0x94, 0x16,
- 0x2f, 0xff, 0x16, 0x0d, 0xe1, 0xe6, 0x22, 0xce, 0x96, 0x2f, 0xe6, 0xd7,
- 0x03, 0x90, 0x2c, 0x5f, 0xfd, 0x9e, 0xfb, 0x7b, 0xf8, 0x52, 0x05, 0x8b,
- 0x6f, 0xda, 0x8e, 0x2c, 0x28, 0x02, 0x41, 0x17, 0xdf, 0xfe, 0x86, 0xdc,
- 0x1b, 0x73, 0xbf, 0x09, 0xf8, 0xb1, 0x7f, 0xdc, 0xcf, 0x49, 0xdb, 0x50,
- 0x58, 0xae, 0xd3, 0xfc, 0x68, 0xcc, 0x09, 0x17, 0xc9, 0xd7, 0xef, 0x88,
- 0xa7, 0x7a, 0xc5, 0xfc, 0x4f, 0xe8, 0x49, 0xab, 0x15, 0x27, 0xb0, 0x19,
- 0x55, 0xfb, 0x63, 0x93, 0x64, 0xc5, 0x8b, 0x8f, 0xc5, 0x8b, 0xe8, 0xf6,
- 0xee, 0xf4, 0xb1, 0x7f, 0x7d, 0x8c, 0xce, 0xfc, 0xb1, 0x7f, 0xfb, 0x93,
- 0xae, 0xbd, 0xc6, 0xf7, 0xf0, 0x6b, 0x17, 0xd9, 0x9d, 0xc1, 0x62, 0xf7,
- 0x1a, 0x25, 0x8a, 0x23, 0xc1, 0xe1, 0x1d, 0xf9, 0xb7, 0xeb, 0x0e, 0xb1,
- 0x46, 0x9e, 0x5f, 0xc8, 0x6d, 0xc5, 0x8b, 0xf9, 0xdf, 0x46, 0x67, 0xd6,
- 0x2f, 0xf3, 0x4f, 0xb3, 0x7b, 0x8d, 0x62, 0xff, 0x7e, 0x74, 0xdd, 0x36,
- 0xf5, 0x8a, 0x89, 0x13, 0x1a, 0x2e, 0xf1, 0xa5, 0xff, 0xa3, 0x29, 0xed,
- 0x86, 0x53, 0x1a, 0xc5, 0xfe, 0x07, 0x3c, 0x52, 0x7e, 0x2c, 0x5f, 0xe3,
- 0xcf, 0xdf, 0x93, 0xb8, 0xb1, 0x52, 0x7d, 0x4e, 0x69, 0x4e, 0x8c, 0xa2,
- 0x85, 0x55, 0x0d, 0x57, 0xb7, 0x46, 0x1a, 0x86, 0xc1, 0xc8, 0xff, 0x0a,
- 0xa2, 0x87, 0xdd, 0xf1, 0xa6, 0x0c, 0xeb, 0x17, 0xed, 0xbf, 0x9d, 0x41,
- 0x62, 0xb6, 0xb2, 0x69, 0x26, 0x53, 0x14, 0x68, 0xb9, 0x28, 0x7f, 0xa8,
- 0x4d, 0xf6, 0x45, 0x11, 0x79, 0xc6, 0x1e, 0x59, 0x0f, 0x9a, 0x0c, 0x26,
- 0xbb, 0x92, 0xb1, 0x7d, 0xc7, 0x28, 0x2c, 0x51, 0xcd, 0xcf, 0x05, 0xef,
- 0xe8, 0xe2, 0x86, 0xc7, 0xa8, 0xd6, 0x2d, 0xd2, 0xc5, 0xec, 0x7f, 0xac,
- 0x50, 0xcd, 0x79, 0xc4, 0xed, 0x1a, 0xc5, 0xfb, 0xdf, 0x63, 0xe9, 0x62,
- 0xa0, 0x6f, 0x34, 0x27, 0x7b, 0xe3, 0x65, 0x8b, 0xf7, 0xf1, 0xa1, 0xc5,
- 0x8b, 0xff, 0xef, 0xc8, 0x61, 0x3c, 0x4e, 0x0e, 0x72, 0x40, 0x91, 0x7e,
- 0xcf, 0x38, 0x82, 0xeb, 0x16, 0xdc, 0x58, 0xbf, 0x6b, 0xa7, 0x7e, 0x97,
- 0x10, 0x21, 0x7b, 0x93, 0xda, 0xc5, 0xf3, 0x73, 0x50, 0x58, 0xb0, 0x25,
- 0x11, 0xb8, 0x2b, 0xd9, 0xb9, 0xc7, 0xaf, 0x8b, 0x0c, 0xdd, 0x58, 0xb9,
- 0xa3, 0x58, 0xa6, 0x37, 0xde, 0x26, 0xbc, 0x22, 0xe9, 0x62, 0xf9, 0xdd,
- 0xc3, 0x58, 0xbf, 0xfe, 0xcf, 0xb6, 0xbe, 0xfc, 0x6f, 0x49, 0x74, 0xb1,
- 0x7d, 0x19, 0x39, 0xd6, 0x2e, 0x72, 0x58, 0xa9, 0x37, 0x31, 0x91, 0xd4,
- 0x15, 0x5e, 0x8c, 0xa3, 0xb5, 0x3d, 0x42, 0xe4, 0xf0, 0x80, 0xf9, 0x03,
- 0x8f, 0x70, 0x8b, 0xd0, 0x88, 0xbf, 0x9f, 0x59, 0xbf, 0x06, 0xb1, 0x7e,
- 0xe9, 0xcd, 0xfb, 0x2c, 0x50, 0x0f, 0x64, 0x8b, 0xef, 0xb4, 0x36, 0x3a,
- 0xc5, 0xe1, 0xbc, 0x16, 0x2d, 0x05, 0x8a, 0x93, 0x5f, 0xba, 0x3b, 0x7d,
- 0xe8, 0xdc, 0x96, 0x2f, 0x1e, 0x7a, 0x58, 0xb9, 0xcd, 0x58, 0xac, 0x36,
- 0xc4, 0x3d, 0x68, 0x2c, 0x5f, 0xd9, 0x18, 0xbd, 0xbf, 0xcb, 0x15, 0x27,
- 0x88, 0x68, 0x95, 0xff, 0x3c, 0x35, 0x31, 0xbe, 0xba, 0x58, 0xb3, 0x2c,
- 0x5f, 0xff, 0x9f, 0xb0, 0x75, 0xf6, 0x88, 0x9c, 0xcf, 0x67, 0xd6, 0x2f,
- 0x1a, 0xde, 0x58, 0xbd, 0xc7, 0xf2, 0xc5, 0x4a, 0x29, 0x70, 0x44, 0xd5,
- 0x9e, 0xc7, 0xae, 0xdb, 0xf5, 0x8b, 0xf7, 0x98, 0x62, 0x95, 0x8b, 0xe7,
- 0x86, 0x0d, 0x62, 0x8e, 0x79, 0x44, 0x51, 0x62, 0x58, 0xb7, 0x4b, 0x16,
- 0x3c, 0x9a, 0x4f, 0x08, 0xdb, 0xd2, 0x7d, 0x78, 0x8b, 0x7f, 0x7b, 0x22,
- 0x83, 0x81, 0x62, 0xfe, 0x93, 0xe1, 0xb3, 0xc5, 0x8a, 0x8d, 0x5b, 0x86,
- 0x11, 0xf4, 0xb3, 0xa6, 0x33, 0x91, 0x7e, 0x1c, 0x00, 0x3d, 0x28, 0x67,
- 0xf0, 0x9b, 0xc5, 0xf7, 0x98, 0xf2, 0xb1, 0x7f, 0xe1, 0xc3, 0x6e, 0x4f,
- 0x5d, 0x61, 0x2c, 0x5d, 0x27, 0x58, 0xbd, 0x9a, 0xc5, 0x8a, 0xe8, 0xd9,
- 0x9c, 0x5e, 0xff, 0x81, 0xfc, 0xee, 0x1e, 0x68, 0x96, 0x2b, 0x0f, 0x78,
- 0x44, 0x57, 0x64, 0x6b, 0x16, 0x12, 0xc5, 0x0c, 0xd5, 0x68, 0x62, 0xff,
- 0x4e, 0x17, 0xb9, 0xb3, 0xbd, 0x62, 0xfe, 0x9d, 0xcf, 0xb3, 0xc1, 0x62,
- 0xf4, 0xf3, 0x69, 0xcf, 0xa0, 0x8e, 0x2f, 0xe7, 0x33, 0x9c, 0x90, 0x2c,
- 0x57, 0xcf, 0x8c, 0x8d, 0x2f, 0x4b, 0xe9, 0x62, 0xff, 0xdf, 0x72, 0xf7,
- 0x08, 0x4e, 0x1a, 0xc5, 0xff, 0x6b, 0x4d, 0xdc, 0x3c, 0xfd, 0xac, 0x5e,
- 0xd9, 0x73, 0x56, 0x2f, 0xfa, 0x4f, 0x0c, 0x8f, 0x04, 0x17, 0x58, 0xbf,
- 0xe9, 0x03, 0x43, 0xec, 0x40, 0x58, 0xb4, 0x6b, 0x17, 0x3f, 0xb4, 0x79,
- 0x61, 0x73, 0x8a, 0xc4, 0x6d, 0xb1, 0x0b, 0xc2, 0x26, 0xf1, 0x92, 0x1a,
- 0xc5, 0xff, 0xcf, 0xc0, 0xfc, 0xc4, 0x28, 0x67, 0x16, 0x2e, 0x21, 0xae,
- 0xaf, 0xa2, 0xa4, 0xfa, 0x5d, 0x16, 0xe0, 0x3a, 0xc5, 0xf4, 0x05, 0x26,
- 0xac, 0x58, 0x0b, 0x15, 0x86, 0xd9, 0xc9, 0x2a, 0x55, 0xe2, 0x8e, 0x1d,
- 0x86, 0x90, 0xf4, 0x38, 0xc7, 0xfa, 0x8c, 0x5f, 0xe6, 0x40, 0x84, 0x41,
- 0x10, 0x79, 0x36, 0xff, 0x0f, 0xee, 0x70, 0xe4, 0x96, 0x2f, 0xef, 0xe4,
- 0x3e, 0xdb, 0xd6, 0x2b, 0x70, 0xf9, 0x3c, 0x69, 0x62, 0x58, 0xbd, 0xa1,
- 0x46, 0xb1, 0x50, 0x36, 0x07, 0x11, 0xbf, 0xfe, 0x26, 0x34, 0x27, 0x3d,
- 0xf1, 0x3c, 0x21, 0x2b, 0x15, 0x27, 0xe9, 0x84, 0x37, 0xef, 0xe7, 0xb9,
- 0x2b, 0x16, 0xde, 0xb1, 0x7e, 0x2f, 0x0b, 0x3e, 0xb1, 0x61, 0x2c, 0x52,
- 0xc5, 0x6d, 0x2f, 0x84, 0x25, 0x52, 0x7d, 0x11, 0xa3, 0x5d, 0xba, 0xcb,
- 0x17, 0x6f, 0x95, 0x8b, 0xee, 0x7b, 0x34, 0xb1, 0x51, 0xab, 0x05, 0x84,
- 0x60, 0x06, 0xc3, 0x27, 0xa2, 0x08, 0x8a, 0x34, 0xf8, 0xe4, 0x5c, 0x1a,
- 0xf0, 0xcd, 0xe1, 0xbc, 0x16, 0x2e, 0x6d, 0x2c, 0x56, 0x1b, 0x4f, 0x8e,
- 0xdf, 0xf6, 0xf2, 0xce, 0x1b, 0xac, 0xe2, 0xc5, 0xf1, 0x13, 0x1d, 0x62,
- 0xb0, 0xf7, 0x5c, 0xf2, 0xf6, 0x6f, 0x0d, 0x62, 0xe6, 0xfa, 0xc5, 0xcf,
- 0x05, 0x8b, 0xff, 0x09, 0xcf, 0x3a, 0xe3, 0x14, 0x4b, 0x14, 0x33, 0xd6,
- 0x21, 0x7b, 0xf8, 0xd9, 0x39, 0x4c, 0x4b, 0x17, 0xce, 0x7c, 0x3a, 0xc5,
- 0xf3, 0x1e, 0x77, 0x16, 0x2e, 0x6d, 0x6d, 0x3c, 0x7c, 0x22, 0xa1, 0xa6,
- 0x65, 0x8d, 0xba, 0x21, 0xfb, 0xb5, 0xfd, 0xec, 0xe7, 0xc5, 0xc5, 0x8b,
- 0xf3, 0x1d, 0xcb, 0x16, 0x2f, 0x01, 0xfc, 0xb1, 0x79, 0xa6, 0x0b, 0x15,
- 0xb5, 0xb4, 0xc2, 0x0a, 0x10, 0xcb, 0x3c, 0x17, 0x46, 0x43, 0x92, 0xb6,
- 0x8d, 0x87, 0x47, 0x44, 0x2d, 0x2f, 0x0b, 0x50, 0x97, 0x38, 0xe7, 0xe1,
- 0xa6, 0xf3, 0xe2, 0xa0, 0x86, 0x11, 0x3e, 0xf0, 0x80, 0x51, 0xa9, 0x18,
- 0x7b, 0xb2, 0x5e, 0x19, 0x36, 0xe8, 0xed, 0xff, 0x37, 0xdf, 0x52, 0x6e,
- 0x44, 0xb1, 0x7f, 0xfd, 0xf9, 0x7d, 0x73, 0x99, 0xf6, 0xe0, 0xa3, 0x58,
- 0xbe, 0xcf, 0xb9, 0xd6, 0x2d, 0xe9, 0x45, 0x6f, 0x0e, 0x83, 0x51, 0xbf,
- 0x0e, 0x7f, 0x21, 0xac, 0x53, 0x9e, 0xf8, 0x8d, 0xaf, 0xf9, 0xf8, 0x59,
- 0xbd, 0xbe, 0x25, 0x8b, 0xfb, 0x3f, 0x9d, 0x0b, 0x16, 0x2f, 0xf8, 0xb3,
- 0xd3, 0xbd, 0x88, 0x0b, 0x17, 0xfb, 0xd3, 0xbd, 0xbd, 0x09, 0x58, 0xbf,
- 0xff, 0xb0, 0x39, 0xd0, 0x1b, 0xda, 0x11, 0xf9, 0xec, 0xd2, 0xc5, 0x62,
- 0x24, 0x88, 0xd6, 0xfc, 0x37, 0x2c, 0xdc, 0x58, 0xac, 0x4c, 0x58, 0x10,
- 0xcb, 0xe1, 0x0d, 0x2c, 0x5f, 0x9b, 0xdc, 0x16, 0xe2, 0xc5, 0xb4, 0x73,
- 0x71, 0xf0, 0xcb, 0xe6, 0xf4, 0xc1, 0x62, 0xff, 0x09, 0xda, 0x12, 0x5d,
- 0x2c, 0x56, 0x1f, 0xe7, 0xc9, 0xf8, 0x45, 0x7b, 0xf8, 0x05, 0x8b, 0xff,
- 0x36, 0xbe, 0xfc, 0x37, 0x5e, 0xe9, 0x62, 0xf8, 0x01, 0xcf, 0x16, 0x2f,
- 0xcd, 0xe9, 0xf7, 0x12, 0x2f, 0xba, 0x9f, 0x71, 0x22, 0xe3, 0x0c, 0x48,
- 0xa8, 0x1f, 0x36, 0x14, 0x18, 0x49, 0x49, 0x01, 0x0d, 0x7d, 0x41, 0x33,
- 0x6f, 0x8e, 0x92, 0x11, 0x90, 0xb9, 0xbc, 0xe4, 0x05, 0x8b, 0xcf, 0xf7,
- 0x58, 0xbf, 0x19, 0xe0, 0xe4, 0x0b, 0x17, 0xec, 0xe7, 0xb3, 0x71, 0x62,
- 0xb1, 0x1a, 0x26, 0xa1, 0xfc, 0x71, 0xc7, 0x3c, 0x57, 0x78, 0x9c, 0xc5,
- 0x8b, 0xf7, 0xda, 0x74, 0x05, 0x8a, 0x88, 0xf1, 0x7c, 0x3b, 0x77, 0xd9,
- 0x62, 0xf3, 0x6f, 0xc5, 0x8b, 0xd9, 0xce, 0x2c, 0x54, 0x47, 0xa5, 0xa1,
- 0x72, 0x1e, 0xbf, 0xec, 0x2f, 0x7d, 0xa4, 0xa3, 0x58, 0xbf, 0xff, 0xdf,
- 0xc3, 0x87, 0x20, 0xd4, 0xf0, 0xb3, 0x7b, 0x7c, 0x4b, 0x17, 0xbd, 0x3d,
- 0x62, 0x26, 0xfc, 0x71, 0x7f, 0xf8, 0xc7, 0xe7, 0x9b, 0xed, 0x86, 0xb6,
- 0x96, 0x29, 0x62, 0xb1, 0x11, 0x7f, 0x34, 0xe2, 0x5d, 0x0d, 0x7d, 0x13,
- 0xa2, 0x18, 0x8e, 0xb5, 0x1a, 0x21, 0xe1, 0xd2, 0x09, 0x46, 0xa5, 0x08,
- 0xee, 0x3a, 0x99, 0x1a, 0xad, 0xfc, 0xd9, 0x19, 0xdb, 0xcb, 0x17, 0xe9,
- 0x1f, 0xdf, 0x71, 0x62, 0xfe, 0x2f, 0x45, 0xb8, 0x40, 0x58, 0xad, 0x22,
- 0x2c, 0x8b, 0x84, 0x57, 0x7f, 0x14, 0xc3, 0x5a, 0x95, 0x8b, 0xd3, 0xa0,
- 0x2c, 0x5f, 0x14, 0xf6, 0x0c, 0x3c, 0xaf, 0x96, 0xdf, 0xfb, 0xdc, 0xce,
- 0xbe, 0xe5, 0xee, 0x2c, 0x5e, 0x62, 0x02, 0xc6, 0xd3, 0xc0, 0xa3, 0xa2,
- 0x9f, 0x7b, 0xc5, 0xdc, 0xf2, 0xc5, 0xff, 0x8e, 0xd8, 0x7f, 0x70, 0x45,
- 0xe5, 0x8b, 0xff, 0xfb, 0x42, 0xe7, 0xde, 0x1d, 0x7d, 0xbb, 0x84, 0xbc,
- 0x16, 0x28, 0xd4, 0x4e, 0xf8, 0xfe, 0xff, 0xfc, 0x4e, 0x7f, 0x7d, 0xcf,
- 0x90, 0x90, 0x73, 0x16, 0x2a, 0x4f, 0xe3, 0x09, 0x2a, 0x53, 0x72, 0xc2,
- 0x5f, 0xc6, 0x5b, 0x68, 0xd6, 0x2f, 0xee, 0x49, 0x9e, 0xce, 0x96, 0x2f,
- 0xfb, 0x37, 0xbe, 0x9e, 0x0f, 0x05, 0x8b, 0xa4, 0x7d, 0x1f, 0xef, 0x62,
- 0x7c, 0x30, 0xbf, 0xa7, 0xf3, 0xf9, 0x8d, 0x62, 0xf7, 0xa4, 0x6b, 0x17,
- 0xfe, 0x67, 0xee, 0x1e, 0xe1, 0x31, 0xab, 0x17, 0xf6, 0x6c, 0x8b, 0xed,
- 0xa5, 0x8a, 0x81, 0xf8, 0x86, 0x81, 0x52, 0x8b, 0x1c, 0x84, 0x75, 0x46,
- 0x98, 0x2c, 0x21, 0xbf, 0x6e, 0x2c, 0x52, 0xc5, 0x39, 0x7c, 0x60, 0x95,
- 0x49, 0xf4, 0x3a, 0x45, 0xfe, 0xc3, 0xb9, 0x7b, 0x92, 0xb1, 0x70, 0x19,
- 0x62, 0xb4, 0x79, 0x24, 0x65, 0x43, 0x54, 0x67, 0xf8, 0xea, 0x5d, 0xa6,
- 0xfd, 0x0f, 0x8a, 0x74, 0xb1, 0x7f, 0xa7, 0x7b, 0x6f, 0x21, 0x71, 0x62,
- 0xfe, 0x6e, 0x3f, 0x70, 0xc5, 0x8b, 0x9c, 0xfa, 0x3e, 0x5d, 0x93, 0x7b,
- 0xcd, 0xa3, 0x56, 0x2f, 0xf3, 0x4f, 0x8a, 0x4f, 0xc5, 0x8a, 0xed, 0x30,
- 0xef, 0xc2, 0x38, 0x06, 0x04, 0x3d, 0x7e, 0xc1, 0x1e, 0x78, 0xb1, 0x4b,
- 0x17, 0x64, 0x5a, 0x36, 0x9c, 0x28, 0xbf, 0xe6, 0x10, 0x5f, 0xf2, 0x19,
- 0x46, 0xb1, 0x7e, 0xef, 0xc5, 0x91, 0xac, 0x5f, 0xcd, 0xee, 0x31, 0x44,
- 0xb1, 0x74, 0xc7, 0x27, 0xb1, 0xf2, 0xab, 0xdb, 0xac, 0x62, 0xc5, 0x62,
- 0x62, 0x5d, 0x16, 0xb4, 0x25, 0xf7, 0x4b, 0x6f, 0xfe, 0x0f, 0x8d, 0xc8,
- 0x98, 0x78, 0x40, 0x58, 0xbd, 0x02, 0x75, 0x8b, 0xe7, 0xf6, 0x46, 0xb1,
- 0x74, 0xf6, 0xb1, 0x71, 0x4a, 0xc5, 0x8f, 0x27, 0xdb, 0xf1, 0xc2, 0x23,
- 0xf0, 0xc5, 0xfd, 0x91, 0x7e, 0x43, 0x25, 0x8b, 0xff, 0xe7, 0xdc, 0x0c,
- 0xa7, 0xee, 0xde, 0x9f, 0x71, 0x62, 0xa5, 0x10, 0x22, 0x2f, 0xa1, 0xa7,
- 0x2c, 0xf0, 0xb3, 0x28, 0x60, 0xdf, 0x74, 0xda, 0xc5, 0x8b, 0xff, 0x8b,
- 0x37, 0x23, 0x16, 0xa1, 0x9d, 0xf9, 0x62, 0xfe, 0xd3, 0x73, 0x33, 0x4b,
- 0x15, 0x12, 0xe1, 0xbe, 0xa3, 0x89, 0xfc, 0x7b, 0x64, 0x73, 0xc2, 0x3d,
- 0xe9, 0x57, 0x14, 0x6b, 0x17, 0xbf, 0x91, 0xac, 0x5b, 0x65, 0x62, 0xb0,
- 0xd9, 0xb8, 0xf5, 0xe8, 0x3e, 0x96, 0x2f, 0xe0, 0x1d, 0xe1, 0x83, 0x58,
- 0xbc, 0x2f, 0xe2, 0xc5, 0x84, 0xb1, 0x79, 0x9e, 0x0b, 0x17, 0xdf, 0x92,
- 0xf2, 0xc5, 0x6d, 0x37, 0xdc, 0x1c, 0xb6, 0x70, 0xfc, 0xf7, 0xa8, 0x5f,
- 0x67, 0xb0, 0x69, 0x17, 0xfc, 0xe4, 0x6e, 0x13, 0xfb, 0x8b, 0x17, 0xce,
- 0x68, 0x0c, 0x58, 0xa8, 0x1f, 0xff, 0xc8, 0x88, 0xe2, 0xfa, 0x48, 0xa5,
- 0x62, 0xa2, 0x4f, 0x47, 0x43, 0xa7, 0x2e, 0x28, 0x48, 0x7a, 0x15, 0x01,
- 0x97, 0x5f, 0xce, 0x63, 0xf9, 0xcd, 0x58, 0xbd, 0xc3, 0xe9, 0x62, 0xe6,
- 0xe9, 0x62, 0x80, 0x6d, 0xb8, 0x3d, 0x58, 0xac, 0x90, 0xd4, 0xb6, 0x8f,
- 0xc3, 0x4c, 0x7e, 0x65, 0xbf, 0xf6, 0xc7, 0x83, 0x17, 0x9b, 0xd3, 0xa5,
- 0x8b, 0xf1, 0xad, 0xad, 0xb8, 0xb1, 0x7d, 0xdc, 0x33, 0xc1, 0x53, 0xef,
- 0xc4, 0x4b, 0xfb, 0xcd, 0xa9, 0x10, 0x5d, 0x62, 0xed, 0x3f, 0xcf, 0xbc,
- 0x33, 0xdb, 0xdf, 0xc8, 0xd6, 0x2f, 0x42, 0x12, 0xb1, 0x7b, 0x3f, 0x9b,
- 0x4d, 0xd8, 0x87, 0xa9, 0xd1, 0x38, 0x4d, 0x37, 0xff, 0x79, 0xa3, 0xf7,
- 0x05, 0xb9, 0xe7, 0xfa, 0xc5, 0xff, 0xf1, 0x67, 0x9b, 0x0b, 0xf9, 0xef,
- 0xb7, 0x4b, 0x17, 0xfd, 0xe6, 0x3f, 0x3f, 0x21, 0x92, 0xc5, 0xe2, 0xcf,
- 0x2c, 0x5f, 0xcd, 0xce, 0x4f, 0xe5, 0x62, 0x98, 0xf2, 0x48, 0x72, 0xff,
- 0xa4, 0xba, 0x7f, 0x3f, 0x60, 0xda, 0x8f, 0x1e, 0xd3, 0x9a, 0x10, 0x77,
- 0xfd, 0x39, 0xde, 0x46, 0x63, 0xf6, 0xb1, 0x7f, 0xce, 0x66, 0xb1, 0xbf,
- 0x23, 0x58, 0xad, 0x1f, 0xa9, 0x1e, 0x54, 0x15, 0x1b, 0x02, 0x33, 0xbf,
- 0x43, 0x6a, 0xfe, 0x10, 0x5d, 0xb5, 0xac, 0x58, 0xbf, 0xff, 0x67, 0x70,
- 0xf3, 0x47, 0x9a, 0xf7, 0x9b, 0x52, 0xb1, 0x7f, 0xbf, 0x86, 0xbc, 0xb6,
- 0xca, 0xc5, 0xfe, 0xce, 0x66, 0xe7, 0xe4, 0x6b, 0x17, 0x4c, 0x6b, 0x17,
- 0xbf, 0x31, 0x2c, 0x5f, 0xe9, 0x62, 0xc8, 0xc3, 0x82, 0xc5, 0xbb, 0x19,
- 0xf5, 0x60, 0xc7, 0xc7, 0xaf, 0xcf, 0x11, 0x34, 0x4b, 0x15, 0xd2, 0x66,
- 0x9f, 0x36, 0x14, 0x28, 0x37, 0x9a, 0xd6, 0x27, 0xa3, 0xc8, 0xe2, 0xef,
- 0xbc, 0x6e, 0x7d, 0x62, 0xf1, 0x34, 0xac, 0x5d, 0xa8, 0x2c, 0x5f, 0xf8,
- 0xb3, 0xde, 0x14, 0x7e, 0xce, 0x96, 0x2f, 0xc3, 0x13, 0xea, 0x0b, 0x17,
- 0xf3, 0xf7, 0xcc, 0xef, 0xcb, 0x17, 0x61, 0x8b, 0x14, 0x03, 0xc8, 0x23,
- 0x0b, 0xe3, 0xf0, 0x33, 0xac, 0x54, 0x9e, 0x36, 0x10, 0xdb, 0x8b, 0x16,
- 0x31, 0x62, 0xe6, 0x02, 0xc5, 0xf1, 0x8e, 0x50, 0x58, 0xb8, 0x6c, 0xb1,
- 0x77, 0xd9, 0x62, 0xfa, 0x1c, 0xfe, 0x2c, 0x5f, 0x30, 0x82, 0xf8, 0xb1,
- 0x6e, 0x6d, 0x45, 0x88, 0xc5, 0xfa, 0x23, 0x88, 0x5d, 0xc5, 0xc0, 0x47,
- 0x4c, 0x99, 0x20, 0xa1, 0x89, 0x4e, 0x9a, 0xf0, 0x23, 0x36, 0xb8, 0x12,
- 0xb1, 0x70, 0x25, 0x62, 0xfc, 0x28, 0x61, 0x04, 0x63, 0x5c, 0x01, 0x7b,
- 0xff, 0xfe, 0xfe, 0x0b, 0x46, 0xf7, 0x0f, 0xe1, 0x1b, 0xf2, 0x9c, 0xd2,
- 0xc5, 0x4a, 0xbc, 0xb8, 0xc9, 0x06, 0x36, 0x68, 0xc3, 0x20, 0xea, 0x16,
- 0xe0, 0x8d, 0xf8, 0x95, 0xfc, 0x7d, 0x7f, 0x68, 0x3f, 0x72, 0x01, 0x75,
- 0x8b, 0xfc, 0x2c, 0x8a, 0x4f, 0x00, 0xba, 0xc5, 0xfb, 0x07, 0x30, 0x9c,
- 0x3e, 0xe0, 0x1a, 0xdf, 0xfe, 0x27, 0xef, 0x86, 0x9a, 0xfb, 0x7a, 0x38,
- 0x16, 0x2f, 0xa7, 0x53, 0xf5, 0x8b, 0xa1, 0xda, 0xc5, 0x62, 0x23, 0x1d,
- 0x47, 0x84, 0x57, 0xfe, 0xf4, 0x8f, 0xa6, 0x8f, 0x3b, 0xf2, 0xc5, 0xff,
- 0x63, 0x77, 0xed, 0x4e, 0x76, 0xb1, 0x7f, 0xf8, 0x9b, 0xbe, 0x44, 0x59,
- 0x1e, 0x77, 0xe5, 0x8b, 0xff, 0x7f, 0x0e, 0x1c, 0x83, 0x3b, 0xf2, 0xc5,
- 0x62, 0x23, 0xbc, 0x9b, 0x7f, 0xbb, 0xe9, 0xb4, 0x1c, 0x8d, 0x62, 0xf8,
- 0x07, 0x78, 0x6d, 0x4e, 0x46, 0x4b, 0x89, 0x0b, 0x90, 0xc8, 0xf1, 0x15,
- 0xc2, 0xf2, 0xc5, 0xdb, 0x32, 0xb1, 0x7f, 0x00, 0xe1, 0xf0, 0x38, 0xd6,
- 0x2f, 0xee, 0x31, 0x14, 0xf6, 0xb1, 0x76, 0x76, 0xb1, 0x5d, 0x9f, 0xc7,
- 0x8c, 0xf6, 0x4b, 0x6f, 0xff, 0x07, 0x26, 0x4c, 0x50, 0x72, 0xce, 0xfc,
- 0xb1, 0x7b, 0x4d, 0xa5, 0x8b, 0xff, 0xff, 0x67, 0xa5, 0xa0, 0xfc, 0xe4,
- 0xea, 0x60, 0xdd, 0x10, 0xb8, 0xb1, 0x40, 0x44, 0x47, 0x07, 0x6a, 0x55,
- 0x1e, 0x41, 0x9f, 0x06, 0x1e, 0x12, 0x5c, 0x33, 0x32, 0x1a, 0xb7, 0xf1,
- 0x67, 0x60, 0x68, 0x2c, 0x5f, 0xdc, 0xe4, 0xc2, 0x74, 0xb1, 0x7f, 0xda,
- 0x93, 0xb4, 0x52, 0xfb, 0x8b, 0x15, 0x87, 0xd5, 0xd1, 0x75, 0xe1, 0x77,
- 0xe5, 0x8b, 0x3a, 0xc5, 0xd1, 0x71, 0x62, 0xa3, 0x4c, 0x0c, 0xa1, 0x31,
- 0xc2, 0x2f, 0x0f, 0x86, 0x23, 0x7f, 0xff, 0xfe, 0x2c, 0xef, 0xc3, 0xcf,
- 0x49, 0x75, 0x9e, 0xfb, 0x77, 0xe9, 0x01, 0x99, 0xf5, 0x8b, 0xb0, 0xc5,
- 0x8b, 0xfe, 0x11, 0x75, 0xfc, 0x8f, 0x8c, 0xb1, 0x7f, 0xd3, 0xde, 0x02,
- 0x77, 0xe4, 0x6b, 0x17, 0xf1, 0x67, 0xb8, 0xe0, 0x58, 0xa9, 0x4d, 0x07,
- 0x50, 0x85, 0x38, 0xc0, 0x0e, 0xf8, 0x79, 0x7f, 0xff, 0xce, 0xde, 0x83,
- 0x0f, 0x21, 0xf9, 0x6d, 0x00, 0xef, 0x05, 0x8b, 0xfa, 0x36, 0xd7, 0x7f,
- 0x8d, 0x62, 0xbe, 0x89, 0x72, 0x65, 0xbf, 0xb9, 0xac, 0xea, 0x63, 0x58,
- 0xbf, 0xfd, 0xe6, 0x8e, 0x39, 0x2c, 0xf3, 0x76, 0x62, 0xc5, 0x46, 0x7f,
- 0xb0, 0x30, 0xbe, 0x9e, 0xfd, 0xb8, 0xb1, 0x52, 0x79, 0x50, 0x23, 0xbf,
- 0xfd, 0xe7, 0xd3, 0x8e, 0x49, 0xf4, 0xf0, 0x58, 0xbf, 0xe0, 0xbe, 0xa7,
- 0xcd, 0xd3, 0x0d, 0x62, 0xff, 0x61, 0x47, 0x83, 0x7f, 0xac, 0x54, 0x48,
- 0xda, 0xf1, 0x08, 0x92, 0x0c, 0x3e, 0xb8, 0x18, 0xb1, 0x7f, 0x61, 0xf0,
- 0x6c, 0x62, 0xc5, 0xc7, 0x95, 0x8b, 0xfe, 0x93, 0x7b, 0xf6, 0xa7, 0x0c,
- 0x58, 0xbf, 0xf6, 0x6f, 0xfb, 0x77, 0x0f, 0x49, 0x8b, 0x17, 0xf6, 0xb4,
- 0xe5, 0x0e, 0x2c, 0x54, 0x11, 0x5b, 0xf3, 0xce, 0x21, 0xd1, 0xd3, 0x22,
- 0x72, 0xef, 0x43, 0x12, 0xef, 0x71, 0x62, 0xff, 0x9e, 0x1b, 0x46, 0xdb,
- 0xe4, 0x6b, 0x17, 0xec, 0x8b, 0xed, 0xe5, 0x8b, 0xff, 0xf1, 0x39, 0xb1,
- 0x4e, 0x7a, 0x4f, 0x3f, 0x90, 0x2c, 0x5f, 0xff, 0xbc, 0x53, 0xba, 0xda,
- 0xce, 0xe1, 0xec, 0x2e, 0x96, 0x2f, 0xff, 0xe1, 0xfd, 0xb6, 0x30, 0xfc,
- 0xdc, 0x2c, 0xde, 0xdf, 0x12, 0xc5, 0x62, 0x62, 0x2c, 0xaa, 0x25, 0x9a,
- 0x24, 0xda, 0x79, 0x19, 0xd5, 0xf6, 0x67, 0xf8, 0xb1, 0x52, 0xba, 0xf3,
- 0x91, 0xe1, 0xf6, 0x7e, 0xf1, 0x9c, 0x85, 0xcd, 0x48, 0x63, 0xd1, 0xd3,
- 0x6e, 0x94, 0xde, 0x30, 0xc3, 0x12, 0x2f, 0xd8, 0x69, 0x0b, 0x89, 0x01,
- 0x0d, 0x0d, 0xe3, 0xbf, 0x96, 0x2f, 0x82, 0x18, 0x61, 0x8b, 0x17, 0x60,
- 0x16, 0x2b, 0x0f, 0x03, 0xc5, 0x37, 0xa4, 0x1c, 0x58, 0xa9, 0x46, 0xb1,
- 0xce, 0xfc, 0xba, 0x19, 0x0d, 0xf6, 0xa4, 0xe0, 0x58, 0xbf, 0xfe, 0x68,
- 0x3f, 0x0e, 0x77, 0x83, 0x9b, 0xf6, 0x58, 0xbf, 0x1d, 0xfc, 0x29, 0x58,
- 0xbf, 0xfd, 0x9b, 0xdb, 0xe2, 0xfb, 0x70, 0xb0, 0xeb, 0x15, 0x27, 0xe6,
- 0x45, 0x17, 0xcd, 0xa0, 0x71, 0x62, 0xff, 0xc2, 0x0b, 0xe6, 0xc9, 0x61,
- 0x8e, 0x05, 0x8b, 0xff, 0x48, 0x26, 0x13, 0xad, 0x61, 0x8b, 0x17, 0xff,
- 0xd3, 0xc1, 0xfd, 0x8c, 0xf9, 0xc5, 0xe1, 0x4a, 0xc5, 0xfe, 0x2c, 0x37,
- 0x6b, 0x6f, 0x65, 0x8a, 0x8d, 0x19, 0x1d, 0x1f, 0xf9, 0x4a, 0xa5, 0x34,
- 0x06, 0x8c, 0x3a, 0xff, 0xfe, 0xf7, 0x18, 0xbb, 0x87, 0xe5, 0x87, 0x3f,
- 0x98, 0x2c, 0x5f, 0xed, 0x48, 0xbc, 0x4d, 0xbd, 0x62, 0x99, 0x12, 0x1c,
- 0x5b, 0xbf, 0xf1, 0x67, 0x3a, 0xfb, 0x75, 0x24, 0xb1, 0x7f, 0xff, 0x8d,
- 0x31, 0xf4, 0x68, 0x4e, 0x64, 0x08, 0x4f, 0xcc, 0x25, 0x8b, 0xff, 0xde,
- 0xfb, 0x38, 0x30, 0xbd, 0xfc, 0x82, 0xc5, 0xff, 0xdf, 0x6d, 0x7d, 0xf5,
- 0x9d, 0x3f, 0x96, 0x2f, 0xff, 0xef, 0xb1, 0xe7, 0x0b, 0xdc, 0x93, 0xcc,
- 0x53, 0xf5, 0x8b, 0xff, 0xdf, 0x6e, 0x4c, 0x20, 0xc3, 0x27, 0xfa, 0xc5,
- 0xf1, 0xce, 0xf0, 0xda, 0x99, 0x8e, 0x24, 0xf4, 0x8a, 0xeb, 0x55, 0x2a,
- 0x93, 0x70, 0x89, 0x8f, 0xc5, 0x1c, 0xb5, 0xfd, 0xa1, 0x75, 0xf6, 0xe2,
- 0xc5, 0xf1, 0x8e, 0x50, 0x58, 0xbf, 0xef, 0x4f, 0x60, 0x7f, 0xfd, 0x96,
- 0x2d, 0xf5, 0x8b, 0xdf, 0xcd, 0xd5, 0x8a, 0xc3, 0xec, 0xe8, 0xea, 0x21,
- 0x2b, 0xda, 0x7e, 0x96, 0x2f, 0xe8, 0xdb, 0xaf, 0xcf, 0x96, 0x2f, 0xa6,
- 0x32, 0x12, 0xc5, 0x68, 0xf4, 0xfe, 0x61, 0x7d, 0xc6, 0x3c, 0xac, 0x5f,
- 0xfa, 0x70, 0xa3, 0xc2, 0x7e, 0xf8, 0xb1, 0x7e, 0x2c, 0xf4, 0xe9, 0x62,
- 0xf1, 0x86, 0x18, 0x91, 0x7e, 0x73, 0x7e, 0xde, 0x48, 0x08, 0x68, 0x6a,
- 0x51, 0x06, 0xc9, 0x17, 0xc7, 0xe4, 0xf9, 0x62, 0xf6, 0xf9, 0x3a, 0xc5,
- 0xef, 0x31, 0x8b, 0x17, 0xb8, 0xfa, 0x58, 0xae, 0xcd, 0xdf, 0x87, 0xae,
- 0x91, 0xac, 0x5f, 0xed, 0x6a, 0x63, 0x1e, 0x12, 0xc5, 0x7c, 0xf2, 0xdc,
- 0x5e, 0xa5, 0x30, 0xbc, 0x23, 0x65, 0xa7, 0x6d, 0xbe, 0x06, 0x64, 0x4b,
- 0x17, 0xdc, 0xc2, 0xf2, 0xc5, 0x61, 0xe2, 0xb9, 0x1d, 0xf8, 0x3e, 0x37,
- 0xc4, 0xb1, 0x77, 0xcd, 0x58, 0xb7, 0x36, 0xab, 0xb4, 0x19, 0x86, 0x38,
- 0xf6, 0x45, 0x11, 0x16, 0xa1, 0x83, 0xf8, 0xcb, 0x09, 0xff, 0x84, 0x1b,
- 0xca, 0xaf, 0x6c, 0xe7, 0x6b, 0x16, 0x80, 0xd7, 0x41, 0xb2, 0x71, 0x0d,
- 0xa1, 0x45, 0x5b, 0x1a, 0xeb, 0xd0, 0xa7, 0x4d, 0xaf, 0xe9, 0x3c, 0xfe,
- 0x40, 0xb1, 0x7a, 0x63, 0x12, 0xc5, 0x82, 0xf8, 0x79, 0x7f, 0x2d, 0xbf,
- 0xf9, 0xbd, 0x3a, 0xc2, 0xf3, 0xb9, 0x2c, 0x54, 0x19, 0x65, 0xd1, 0x10,
- 0x6a, 0x36, 0x3f, 0xcb, 0x05, 0x29, 0xdb, 0xc1, 0x3f, 0x6f, 0x2b, 0xbf,
- 0xfa, 0x70, 0xb0, 0x6f, 0x02, 0x98, 0xd6, 0x2f, 0xba, 0xd4, 0xc1, 0x62,
- 0xed, 0xf2, 0xb1, 0x7f, 0xe6, 0xd7, 0x5f, 0x6e, 0xbe, 0xc4, 0xb1, 0x7f,
- 0xff, 0xf9, 0xc8, 0x1e, 0xfe, 0x1f, 0xdc, 0xcd, 0xff, 0x6e, 0xbe, 0xc1,
- 0x8a, 0x35, 0x8a, 0x8d, 0x17, 0xa0, 0x40, 0xa9, 0x47, 0xd6, 0x43, 0x5a,
- 0xff, 0xb3, 0x72, 0x4f, 0xdc, 0x33, 0xcb, 0x15, 0x2c, 0xe5, 0x6c, 0x23,
- 0x6a, 0x5f, 0x8e, 0x9f, 0xdd, 0x08, 0xa3, 0x1e, 0xe1, 0x35, 0xf6, 0x73,
- 0xcc, 0xb1, 0x7f, 0x67, 0x39, 0x9a, 0x8d, 0x62, 0xdd, 0x40, 0xf4, 0x46,
- 0x45, 0x78, 0xa7, 0x7a, 0xc5, 0xff, 0xda, 0x9e, 0xbe, 0x4f, 0xe2, 0x93,
- 0x16, 0x2e, 0x0b, 0xb2, 0xc5, 0x2c, 0x5b, 0xeb, 0x15, 0x02, 0xf9, 0x83,
- 0x2a, 0x33, 0xd8, 0xd1, 0xcd, 0x4a, 0x30, 0x1e, 0x13, 0xb7, 0xa2, 0x78,
- 0xd6, 0x2f, 0x70, 0x5b, 0x8b, 0x15, 0x87, 0x81, 0xe1, 0xfb, 0xe1, 0x46,
- 0x28, 0xd6, 0x2f, 0xd0, 0x26, 0x9e, 0xd6, 0x2d, 0x3a, 0x3c, 0xe2, 0x26,
- 0xa9, 0x77, 0x77, 0x71, 0xc6, 0x57, 0x09, 0x52, 0x43, 0x95, 0xcb, 0x93,
- 0xaf, 0x86, 0xcb, 0x8c, 0xea, 0x3c, 0xbe, 0xe5, 0x2b, 0xb1, 0xec, 0x52,
- 0x80, 0xf5, 0x2f, 0xd0, 0xf0, 0xf8, 0xfc, 0xe4, 0xab, 0xc6, 0xc8, 0x08,
- 0xe4, 0x8a, 0x79, 0x7f, 0x91, 0xc0, 0xfa, 0x9d, 0x26, 0x28, 0x61, 0xef,
- 0x29, 0xd9, 0x86, 0xf0, 0x6c, 0xdb, 0xad, 0xf7, 0xe6, 0x8a, 0x0c, 0x4b,
- 0x17, 0x6c, 0x4c, 0xb1, 0x7d, 0xd6, 0x9b, 0xa5, 0x8b, 0xfe, 0x8b, 0xdb,
- 0xbc, 0x98, 0x85, 0xa5, 0x8b, 0xfc, 0x39, 0x23, 0xc8, 0xe5, 0x62, 0xa4,
- 0xfc, 0x9d, 0x02, 0xff, 0xbf, 0x31, 0xea, 0x60, 0xfa, 0x58, 0xbf, 0xfd,
- 0xf9, 0xf9, 0x61, 0xa3, 0xc2, 0x9d, 0xc5, 0x8b, 0xf1, 0x1a, 0x1c, 0x81,
- 0x62, 0xff, 0x81, 0xa9, 0x17, 0x89, 0xb7, 0xac, 0x5f, 0xf3, 0xf7, 0xef,
- 0xcf, 0x59, 0x12, 0xc5, 0x61, 0xfb, 0x91, 0xdd, 0xf9, 0x87, 0xf6, 0x35,
- 0x62, 0xf0, 0x6e, 0x4b, 0x14, 0x34, 0xd4, 0xf1, 0x30, 0xa1, 0x43, 0xe2,
- 0x0d, 0xd2, 0x9b, 0xf4, 0x93, 0x1f, 0x16, 0x2f, 0x8c, 0xf6, 0x6e, 0x2c,
- 0x54, 0x67, 0x9b, 0xd9, 0x35, 0xff, 0xf8, 0x9c, 0xcd, 0x34, 0xfc, 0x3f,
- 0x37, 0xe7, 0x7a, 0xc5, 0xff, 0x9b, 0xf2, 0x3f, 0x8a, 0x7b, 0xe2, 0xc5,
- 0xe2, 0x2c, 0x58, 0xac, 0x3d, 0xb7, 0x40, 0xbc, 0x33, 0x40, 0xb1, 0x7e,
- 0x3e, 0xb4, 0xfe, 0x58, 0xbd, 0xb7, 0x77, 0xa5, 0x8b, 0xb3, 0xcb, 0x15,
- 0x19, 0xbb, 0xf9, 0x25, 0xff, 0x8e, 0x39, 0x2c, 0xde, 0x59, 0xc5, 0x8b,
- 0xdf, 0x23, 0xac, 0x56, 0xd4, 0xc0, 0x64, 0x7f, 0x19, 0x18, 0x89, 0xcf,
- 0xef, 0xfe, 0x89, 0xfa, 0xfc, 0xc3, 0xc5, 0x87, 0x58, 0xbf, 0xb5, 0x84,
- 0x4f, 0x1a, 0xc5, 0xff, 0x83, 0x93, 0xe6, 0x8e, 0xe4, 0x6a, 0xc5, 0x74,
- 0x8b, 0x36, 0x46, 0xf1, 0x6d, 0xff, 0x8c, 0xee, 0x1c, 0xdb, 0x9f, 0xc2,
- 0x58, 0xbf, 0xe9, 0xef, 0x9a, 0x6d, 0xf8, 0x35, 0x8b, 0xff, 0xe2, 0xce,
- 0x78, 0xd9, 0x28, 0x67, 0xd8, 0xeb, 0x15, 0x12, 0x22, 0xf7, 0x9e, 0x54,
- 0xa3, 0xd3, 0x21, 0x9d, 0x7f, 0x64, 0x66, 0x9a, 0x22, 0x58, 0xbf, 0xfc,
- 0x7e, 0xe1, 0xcd, 0xb8, 0x45, 0x8c, 0x05, 0x8b, 0xf9, 0xf4, 0x29, 0xee,
- 0x0b, 0x15, 0x28, 0xac, 0x63, 0x17, 0x4c, 0xbf, 0xfa, 0x46, 0x7c, 0xea,
- 0x79, 0xfc, 0x3a, 0xc5, 0xf9, 0xf0, 0x6d, 0xbd, 0x62, 0xf3, 0x61, 0x8b,
- 0x15, 0xa4, 0x45, 0x9d, 0x14, 0x32, 0x9b, 0xcd, 0xf1, 0x2c, 0x5f, 0x79,
- 0xbe, 0x25, 0x8b, 0xfb, 0x35, 0xdc, 0x3d, 0x2b, 0x16, 0xdc, 0x0b, 0x67,
- 0xa4, 0x19, 0x1d, 0xf8, 0xcc, 0xea, 0x40, 0xb1, 0x7d, 0xd7, 0xf3, 0x4b,
- 0x15, 0x28, 0x80, 0x63, 0x2d, 0xd2, 0xaa, 0xda, 0xca, 0x19, 0x0a, 0x14,
- 0x48, 0xe4, 0x21, 0x2e, 0x32, 0x0c, 0x8e, 0x35, 0xa1, 0x3d, 0x11, 0x26,
- 0xa1, 0x67, 0xf8, 0xc8, 0x5e, 0x1f, 0x85, 0x19, 0x27, 0xa1, 0xa4, 0x28,
- 0x5c, 0x6f, 0x31, 0xdd, 0x87, 0x7d, 0x82, 0x05, 0x27, 0x38, 0xe4, 0xb6,
- 0x29, 0x53, 0x61, 0x59, 0x4c, 0xdb, 0x04, 0xac, 0x5d, 0x8e, 0x51, 0x96,
- 0xc3, 0x95, 0x73, 0xb0, 0xa5, 0x0e, 0x85, 0xb8, 0xdf, 0xc2, 0xc8, 0xec,
- 0xc2, 0xd6, 0x30, 0x59, 0xb6, 0xff, 0xf1, 0xd3, 0x8c, 0x61, 0x5c, 0xe5,
- 0x8e, 0xd7, 0x36, 0xe6, 0x27, 0xd6, 0x4d, 0xa4, 0xcf, 0x75, 0x6b, 0x0a,
- 0x7b, 0xaf, 0x06, 0xda, 0xd0, 0x47, 0xee, 0x4b, 0x15, 0x8a, 0xd3, 0xf0,
- 0x6a, 0xda, 0xc1, 0x1e, 0xbf, 0x58, 0xfd, 0xe8, 0xb8, 0xbd, 0xe2, 0x57,
- 0x02, 0xbe, 0xb4, 0x0b, 0xca, 0x8d, 0x2b, 0xce, 0x51, 0xe6, 0x30, 0x72,
- 0x7d, 0x7c, 0x19, 0xa2, 0xa6, 0xcf, 0xef, 0xa4, 0x18, 0x99, 0x4a, 0x6e,
- 0xd9, 0xad, 0x6d, 0x43, 0xbc, 0x56, 0x5d, 0xda, 0x5e, 0xa5, 0x04, 0x9c,
- 0xe9, 0x12, 0x86, 0xe7, 0x2c, 0x95, 0xe3, 0xe7, 0x96, 0x2f, 0xf3, 0x9e,
- 0x7c, 0xdc, 0x65, 0x8b, 0xf6, 0x68, 0x3f, 0x71, 0x62, 0xef, 0xca, 0xc5,
- 0x82, 0x01, 0x12, 0x04, 0x3b, 0xc3, 0x20, 0xca, 0xaf, 0xba, 0x29, 0xc5,
- 0x8b, 0xf6, 0xba, 0x77, 0xe9, 0x51, 0x71, 0x97, 0xf4, 0x1c, 0xa0, 0xc7,
- 0x58, 0xb0, 0x49, 0x44, 0x36, 0x11, 0x39, 0xbd, 0xfe, 0x09, 0x9a, 0xe9,
- 0xdf, 0xa5, 0x45, 0xd6, 0x5f, 0xfc, 0x11, 0xe0, 0x13, 0x35, 0xd3, 0xbf,
- 0x4a, 0x89, 0x44, 0xa9, 0x9c, 0xf5, 0xa1, 0x8c, 0xe2, 0x10, 0xd7, 0x19,
- 0x51, 0xb1, 0x8b, 0xf4, 0x70, 0xd3, 0xc1, 0x5b, 0x91, 0x9a, 0xbe, 0xe7,
- 0x4b, 0x78, 0x21, 0xa1, 0xc8, 0x65, 0xf8, 0xd7, 0x75, 0x12, 0xff, 0xf0,
- 0x43, 0xbc, 0x02, 0x66, 0xba, 0x77, 0xe9, 0x51, 0x2d, 0x17, 0xfe, 0x0a,
- 0x85, 0x75, 0xa7, 0x98, 0x7b, 0x75, 0x62, 0xff, 0x82, 0xd7, 0xed, 0xb8,
- 0xf3, 0xde, 0xea, 0xc5, 0xff, 0xf1, 0x9d, 0x6c, 0x41, 0x50, 0x05, 0xf5,
- 0xb0, 0x6d, 0xdb, 0xfd, 0x95, 0x8b, 0xff, 0xff, 0x6e, 0xfb, 0x63, 0x19,
- 0xf6, 0x32, 0x60, 0xb7, 0xe0, 0xbe, 0xb6, 0x0d, 0xbb, 0x7f, 0xb2, 0xb1,
- 0x5f, 0x4c, 0x08, 0xc6, 0xfb, 0xf0, 0x5e, 0x1b, 0x18, 0x71, 0xac, 0x5e,
- 0xdc, 0x3b, 0x2c, 0x5f, 0xf6, 0x10, 0xff, 0x3a, 0x72, 0x58, 0xa9, 0x3d,
- 0x7c, 0x20, 0xbc, 0xef, 0xd2, 0xa2, 0x37, 0x2f, 0xdd, 0xc4, 0x52, 0x35,
- 0x8a, 0xe8, 0xf5, 0x1c, 0xaa, 0xfc, 0x3f, 0xce, 0x69, 0x62, 0xb4, 0x79,
- 0x44, 0x45, 0x7f, 0xb4, 0xc1, 0x7e, 0xbf, 0x26, 0x2c, 0x5e, 0x16, 0xc9,
- 0x8b, 0x17, 0xda, 0x14, 0x81, 0x62, 0x98, 0xff, 0xe2, 0x3a, 0x0c, 0x8a,
- 0xff, 0xff, 0xfb, 0x79, 0x67, 0x38, 0x39, 0xcd, 0x74, 0xef, 0xd0, 0x48,
- 0x37, 0xa7, 0xdc, 0x54, 0x61, 0xe5, 0x4a, 0x2f, 0xd8, 0xc2, 0xfe, 0x70,
- 0x9b, 0x8e, 0x40, 0x58, 0xaf, 0x9e, 0x99, 0x10, 0xdf, 0xdc, 0x08, 0x67,
- 0x37, 0x03, 0x58, 0xbf, 0x34, 0x7f, 0x6d, 0x95, 0x8b, 0xf6, 0x71, 0xf5,
- 0x05, 0x8a, 0xdc, 0x3d, 0x4d, 0x16, 0x5f, 0xb7, 0x42, 0x68, 0x2e, 0x62,
- 0xc5, 0xf0, 0xcb, 0x00, 0xb1, 0x7d, 0x26, 0x1c, 0x6b, 0x17, 0xdd, 0x7e,
- 0x4c, 0x58, 0xbd, 0xf9, 0x35, 0x62, 0xb1, 0x11, 0x3a, 0x22, 0x0b, 0x92,
- 0x06, 0x4b, 0x7f, 0xe7, 0x80, 0x4c, 0xd7, 0x4e, 0xfd, 0x2a, 0x25, 0xf2,
- 0xd8, 0xb1, 0x7b, 0xef, 0xe5, 0x8b, 0x7b, 0x86, 0xb8, 0x31, 0x1b, 0xf8,
- 0x9a, 0x4c, 0x16, 0xe2, 0xc5, 0xfc, 0x1b, 0x77, 0xbb, 0xa3, 0x16, 0x2f,
- 0xf9, 0xb5, 0xa6, 0xf0, 0x33, 0x8b, 0x15, 0x28, 0xc7, 0xc2, 0x86, 0x31,
- 0x73, 0x5b, 0xfa, 0x5b, 0x73, 0x3b, 0x82, 0xc5, 0xfb, 0x46, 0xfc, 0x5c,
- 0x58, 0xaf, 0x9e, 0xe0, 0x66, 0x37, 0xa7, 0x52, 0xb1, 0x58, 0x6f, 0xd8,
- 0x8e, 0xe7, 0xfa, 0xc5, 0xf0, 0x07, 0xc9, 0x58, 0xbe, 0x7d, 0x47, 0x1a,
- 0xc5, 0xb0, 0x8f, 0x23, 0x79, 0x1d, 0x41, 0x10, 0xfc, 0x5f, 0xbf, 0xdf,
- 0x09, 0xd7, 0xdb, 0xfb, 0xab, 0x17, 0x81, 0x26, 0x2c, 0x5f, 0xec, 0x6d,
- 0x43, 0xec, 0x62, 0xc5, 0x62, 0x23, 0x77, 0x0e, 0xfe, 0x3d, 0x73, 0x06,
- 0xb1, 0x7a, 0x30, 0xe0, 0xb1, 0x6d, 0xd8, 0x8d, 0xc3, 0x8c, 0x5f, 0x0b,
- 0xed, 0xa5, 0x8b, 0xee, 0x7e, 0x7e, 0xb1, 0x7f, 0xa6, 0x39, 0x28, 0xf3,
- 0x75, 0x62, 0xee, 0x69, 0x62, 0xa4, 0xfc, 0xa3, 0x23, 0x88, 0xde, 0xc1,
- 0x02, 0xac, 0xb4, 0xb0, 0xb6, 0x97, 0x31, 0xa4, 0xc6, 0x4a, 0x38, 0x46,
- 0x64, 0x2f, 0xba, 0x8e, 0xcb, 0xb2, 0x16, 0x84, 0x5e, 0xe1, 0x2e, 0xa1,
- 0x7a, 0x74, 0x1f, 0xc6, 0x88, 0x50, 0xd4, 0xe4, 0x29, 0xbd, 0x0b, 0x01,
- 0x35, 0x6c, 0x95, 0x07, 0x09, 0x5b, 0xff, 0xf1, 0x4f, 0x41, 0x3d, 0xdf,
- 0x4d, 0xc2, 0xcd, 0xee, 0xb1, 0x7f, 0xf4, 0x3c, 0xd1, 0x04, 0x1b, 0x6f,
- 0x91, 0xac, 0x5f, 0x8c, 0x08, 0xc6, 0xc6, 0xb1, 0x43, 0x46, 0x9f, 0x6b,
- 0x6c, 0x95, 0x7e, 0xd7, 0x4e, 0xfd, 0x2a, 0x2a, 0xb2, 0xfd, 0x9c, 0xfc,
- 0xf6, 0xb1, 0x60, 0x98, 0x7c, 0x1f, 0x37, 0xbf, 0x05, 0x47, 0xa7, 0xe9,
- 0x62, 0xf8, 0x5b, 0xa3, 0x95, 0x8b, 0x05, 0x16, 0x2b, 0xe6, 0xf3, 0x64,
- 0x9a, 0xe6, 0xdd, 0x58, 0xbb, 0x34, 0xb1, 0x7b, 0x3b, 0xf2, 0xc5, 0xf3,
- 0x1d, 0xf7, 0xac, 0x51, 0xa7, 0xe6, 0xe3, 0x40, 0x17, 0xf0, 0xf5, 0xe2,
- 0xdd, 0x31, 0x62, 0xfe, 0xfc, 0xef, 0x10, 0xf1, 0x62, 0xfe, 0x7f, 0xc4,
- 0x52, 0x35, 0x8b, 0xff, 0xef, 0x00, 0xe2, 0x1e, 0x67, 0x80, 0x71, 0x76,
- 0xb1, 0x7f, 0xf7, 0xbf, 0x3c, 0x27, 0x10, 0x5d, 0xb4, 0xb1, 0x7a, 0x61,
- 0x8b, 0x17, 0xf4, 0xf3, 0x63, 0xc7, 0x3a, 0xc5, 0xfc, 0xc2, 0xe8, 0xa6,
- 0x25, 0x8b, 0xdc, 0x0d, 0xd6, 0x2a, 0x09, 0xca, 0x0c, 0xc3, 0x0b, 0xbb,
- 0x53, 0x89, 0x23, 0x43, 0x9f, 0x32, 0xf1, 0x7d, 0xff, 0x1b, 0x85, 0x9d,
- 0xf9, 0xce, 0xb1, 0x6d, 0xd5, 0x8b, 0x18, 0xb1, 0x5d, 0x9a, 0x8f, 0x0a,
- 0xde, 0xdd, 0x9f, 0x2c, 0x5f, 0xd2, 0x70, 0xe4, 0xba, 0x58, 0xba, 0x74,
- 0xb1, 0x5a, 0x3c, 0x6e, 0x17, 0xdf, 0xb0, 0xe7, 0x68, 0x96, 0x2e, 0x7e,
- 0xd6, 0x2f, 0x07, 0x20, 0x58, 0xb6, 0xe2, 0xc5, 0x76, 0x79, 0x7e, 0x18,
- 0xd9, 0x1e, 0xbe, 0x88, 0x85, 0xd2, 0xc5, 0xfd, 0x87, 0x89, 0xde, 0x35,
- 0x8b, 0xf7, 0x1b, 0xec, 0x6a, 0xc5, 0xcf, 0xda, 0xc5, 0x11, 0xe0, 0xf8,
- 0xa6, 0xff, 0xfa, 0x1f, 0x78, 0x1a, 0xfc, 0xc1, 0x73, 0x8c, 0xb1, 0x4b,
- 0x15, 0x87, 0xbb, 0xba, 0xa3, 0x52, 0x99, 0xbb, 0x12, 0xbb, 0x81, 0x3f,
- 0x5c, 0x36, 0x58, 0xbf, 0xe2, 0x98, 0x79, 0x8e, 0x39, 0x58, 0xbf, 0x6b,
- 0xa7, 0x7e, 0x95, 0x12, 0x01, 0x7d, 0xac, 0x2f, 0x2c, 0x5f, 0x0c, 0x29,
- 0xb0, 0xb6, 0x05, 0x8b, 0xff, 0xf7, 0xf0, 0xfe, 0x61, 0x14, 0x30, 0x9a,
- 0x3e, 0x2c, 0x50, 0xd3, 0x19, 0xc3, 0x8d, 0x1b, 0xf0, 0x8b, 0xc6, 0x75,
- 0xb5, 0x37, 0xa0, 0x91, 0x98, 0x5f, 0xb8, 0xe4, 0xfd, 0xac, 0x5f, 0xf7,
- 0x9b, 0x8c, 0x20, 0xb8, 0xe5, 0x62, 0xec, 0x25, 0x8b, 0x85, 0x2b, 0x15,
- 0x04, 0x60, 0x76, 0x5c, 0xc5, 0x1b, 0x87, 0xba, 0x16, 0xbf, 0xa7, 0x51,
- 0xce, 0xa3, 0x58, 0xbe, 0x63, 0xcf, 0x16, 0x2a, 0x07, 0xa4, 0x69, 0x85,
- 0xfe, 0xd4, 0x67, 0x92, 0x87, 0x16, 0x2a, 0x4f, 0x63, 0x08, 0xef, 0xff,
- 0x8e, 0xc4, 0x00, 0xfc, 0xc4, 0x28, 0x67, 0x16, 0x2f, 0xfe, 0x69, 0x3b,
- 0x8c, 0x3d, 0xd9, 0x28, 0x2c, 0x5f, 0xff, 0xf3, 0x78, 0xb3, 0x79, 0x67,
- 0x23, 0xc3, 0x36, 0x45, 0xf6, 0xd2, 0xc5, 0x62, 0x60, 0x7f, 0x50, 0x02,
- 0x3d, 0xf8, 0x0e, 0x02, 0x3a, 0xc5, 0xe8, 0xdc, 0x6b, 0x17, 0xff, 0xbb,
- 0x72, 0x10, 0x35, 0x3f, 0x62, 0x3a, 0xc5, 0xfc, 0xdb, 0xdb, 0xd1, 0x4a,
- 0xc5, 0x4a, 0x30, 0x30, 0xa1, 0x87, 0xb8, 0x95, 0x7f, 0x07, 0xb1, 0xe9,
- 0xa4, 0xeb, 0x17, 0x72, 0x0b, 0x14, 0xe7, 0x99, 0xc3, 0x4b, 0xff, 0xfa,
- 0x7a, 0xf3, 0x6b, 0x58, 0x0e, 0x79, 0xfe, 0xe3, 0x58, 0xb8, 0x2b, 0xf5,
- 0x8b, 0xff, 0xa2, 0xfb, 0x9f, 0xdf, 0x9f, 0x08, 0xeb, 0x17, 0xff, 0x60,
- 0xe6, 0x13, 0x83, 0x92, 0xf2, 0xc5, 0x62, 0x22, 0x4e, 0x8f, 0x7b, 0x76,
- 0x7c, 0xb1, 0x5b, 0x1b, 0x36, 0xde, 0x5a, 0xa3, 0x84, 0xb8, 0xcf, 0x32,
- 0x3b, 0x53, 0x5c, 0xfb, 0x62, 0xdc, 0x22, 0x89, 0x9b, 0x44, 0x47, 0x74,
- 0xfc, 0x6d, 0x4f, 0x29, 0xd0, 0xa1, 0xef, 0xc8, 0xc8, 0xfd, 0x0f, 0x01,
- 0x42, 0x1b, 0x79, 0x0e, 0xca, 0xe0, 0x70, 0xa5, 0xdd, 0x22, 0xbf, 0xf4,
- 0x27, 0x01, 0xfc, 0xc2, 0xe9, 0x62, 0xfd, 0x24, 0x59, 0xe5, 0x8b, 0xed,
- 0x69, 0xba, 0x58, 0xbe, 0x2c, 0x8c, 0x26, 0x22, 0x23, 0x64, 0xf8, 0x32,
- 0x6b, 0xfc, 0x1f, 0x33, 0x5d, 0x7e, 0x56, 0x2f, 0xfb, 0x22, 0x83, 0xea,
- 0x3f, 0x89, 0x62, 0xff, 0x1a, 0xe5, 0x86, 0x38, 0x16, 0x2f, 0x8d, 0x87,
- 0xf1, 0x62, 0xfa, 0x02, 0x90, 0xd6, 0x2c, 0x12, 0x51, 0xdc, 0x33, 0x63,
- 0x4f, 0x38, 0x68, 0x19, 0x25, 0xfe, 0x09, 0xf7, 0x3e, 0x48, 0xd6, 0x28,
- 0x22, 0xba, 0xbd, 0x47, 0xd2, 0x64, 0x67, 0x5b, 0x2a, 0x77, 0xf8, 0x26,
- 0x6b, 0xa7, 0x7e, 0x95, 0x16, 0x41, 0x7f, 0xff, 0xbe, 0xfa, 0x09, 0xf7,
- 0xf1, 0x0a, 0x3e, 0x61, 0xe7, 0x71, 0x62, 0xfe, 0x6d, 0xe1, 0x39, 0x3d,
- 0xac, 0x5f, 0xff, 0xe1, 0x0f, 0x02, 0x07, 0x9f, 0x21, 0x3e, 0xe6, 0x1b,
- 0x3c, 0x58, 0xbf, 0xff, 0x74, 0xdc, 0xc1, 0xe1, 0x49, 0x9e, 0x35, 0xf8,
- 0xb1, 0x7f, 0xdf, 0x67, 0x06, 0x0b, 0x51, 0xac, 0x5f, 0xbe, 0x27, 0x34,
- 0x27, 0xd1, 0x23, 0xe5, 0x7b, 0x4c, 0x13, 0x3b, 0x1c, 0x3e, 0x2b, 0x89,
- 0xce, 0x7a, 0x36, 0xea, 0x1a, 0xa2, 0xd6, 0x94, 0x07, 0x7f, 0x82, 0x66,
- 0xba, 0x77, 0xe9, 0x51, 0x6b, 0x97, 0xe8, 0xbc, 0x39, 0x25, 0x8b, 0xfc,
- 0x59, 0x1e, 0xb4, 0xc6, 0x2c, 0x5f, 0x7d, 0xa6, 0x25, 0x8b, 0xf6, 0x07,
- 0x31, 0x84, 0xc4, 0x40, 0xf4, 0x53, 0xba, 0x6b, 0x7f, 0x82, 0x66, 0xba,
- 0x77, 0xe9, 0x51, 0x72, 0x17, 0xed, 0x74, 0xef, 0xd2, 0xa2, 0xec, 0x2f,
- 0xb6, 0x67, 0xd8, 0xb1, 0x7f, 0xe7, 0x80, 0x4c, 0xd7, 0x4e, 0xfd, 0x2a,
- 0x28, 0xe2, 0xc1, 0x31, 0x15, 0x6c, 0x6e, 0x72, 0x5b, 0xff, 0xc4, 0x13,
- 0xee, 0xdc, 0xfe, 0x43, 0x92, 0xb1, 0x7c, 0x53, 0x03, 0xac, 0x5f, 0xa0,
- 0xc4, 0x06, 0x58, 0xbf, 0xf6, 0xc6, 0x15, 0x3c, 0xea, 0x18, 0xdb, 0xd6,
- 0x2d, 0x05, 0x8b, 0xf6, 0xba, 0x77, 0xe9, 0x51, 0x4a, 0x97, 0xfd, 0xd7,
- 0xda, 0x2f, 0xcc, 0x78, 0xb1, 0x7f, 0xfb, 0xf3, 0x1c, 0xfd, 0xb7, 0xb8,
- 0xfe, 0xcb, 0x01, 0x0d, 0xe5, 0xd0, 0x09, 0x88, 0xd1, 0x89, 0xce, 0xbb,
- 0x4c, 0x51, 0xe1, 0xc7, 0x7f, 0xe7, 0x6f, 0x40, 0x43, 0x72, 0x02, 0xc5,
- 0xdf, 0x12, 0xc5, 0x82, 0x0d, 0x51, 0x36, 0x11, 0x76, 0x4e, 0x78, 0xd7,
- 0xbe, 0x53, 0xc3, 0xeb, 0xff, 0xff, 0x9f, 0xd8, 0x09, 0x80, 0x40, 0xcf,
- 0x83, 0x98, 0x48, 0xdd, 0xcd, 0x58, 0xa8, 0xdd, 0x43, 0x14, 0x29, 0x75,
- 0x19, 0x28, 0xa7, 0xb8, 0x48, 0x35, 0x63, 0x16, 0x75, 0x17, 0x94, 0xe2,
- 0x02, 0xb2, 0x86, 0x2f, 0x14, 0xfd, 0x0e, 0xf1, 0x1b, 0x6f, 0x94, 0xe2,
- 0x63, 0x3d, 0xff, 0x40, 0x26, 0x6b, 0xa7, 0x7e, 0x95, 0x11, 0xc1, 0x7f,
- 0xcc, 0x13, 0x35, 0xd3, 0xbf, 0x4a, 0x8a, 0xd4, 0xb0, 0x47, 0x44, 0x9f,
- 0x92, 0xaf, 0xff, 0x04, 0x3b, 0xc0, 0x26, 0x6b, 0xa7, 0x7e, 0x95, 0x12,
- 0xd9, 0x78, 0x28, 0x14, 0xe2, 0xc5, 0xba, 0x58, 0xbc, 0x2d, 0x01, 0x62,
- 0xec, 0xed, 0x62, 0xfc, 0x73, 0xcb, 0x71, 0x62, 0xfe, 0x9d, 0x01, 0xfb,
- 0xe2, 0xc5, 0x87, 0x87, 0xaf, 0xf2, 0x8b, 0xf7, 0xa7, 0xe1, 0xf1, 0x62,
- 0xf6, 0xf1, 0x41, 0x62, 0x82, 0xa9, 0x88, 0xf4, 0x27, 0xd8, 0xf3, 0x37,
- 0x91, 0x3e, 0xf2, 0xab, 0x87, 0x05, 0x8b, 0xff, 0xec, 0x33, 0x23, 0xf7,
- 0xb0, 0xc7, 0xf3, 0x9a, 0xb1, 0x5f, 0x3e, 0xb2, 0x18, 0xb4, 0xac, 0x5f,
- 0x6e, 0x8e, 0x7b, 0x58, 0xa0, 0xb5, 0x37, 0x0c, 0x23, 0x7f, 0xd9, 0xd9,
- 0x60, 0x00, 0xf0, 0x58, 0xb8, 0xfd, 0x2c, 0x5f, 0xcd, 0xdf, 0x07, 0x84,
- 0xb1, 0x7f, 0x77, 0x90, 0x9d, 0x01, 0x62, 0xb0, 0xf7, 0x5c, 0xba, 0xff,
- 0xfa, 0x4a, 0x3e, 0x09, 0xda, 0x1c, 0xfb, 0xc1, 0x62, 0xa5, 0x31, 0xf8,
- 0x1c, 0xe9, 0xdb, 0xe4, 0x17, 0x9f, 0xe1, 0xac, 0x5f, 0x14, 0xf7, 0x05,
- 0x8b, 0xfe, 0x2f, 0x70, 0x62, 0x7d, 0x41, 0x62, 0xf6, 0x9e, 0x25, 0x8a,
- 0x63, 0xd8, 0x11, 0xd5, 0xf7, 0x4f, 0xa0, 0x2c, 0x5f, 0xa4, 0xf9, 0xdf,
- 0x96, 0x2d, 0x1c, 0x9e, 0x69, 0x12, 0x5f, 0xfb, 0x5f, 0x7c, 0x21, 0x43,
- 0x38, 0xb1, 0x7f, 0xfd, 0xd8, 0x07, 0xf7, 0x86, 0x70, 0x84, 0xe1, 0xac,
- 0x53, 0x22, 0x41, 0xcf, 0xaf, 0x81, 0x9a, 0x89, 0x62, 0xff, 0x3f, 0xb8,
- 0x1f, 0x27, 0x16, 0x2f, 0xcd, 0xf9, 0x0e, 0x25, 0x8b, 0xde, 0x93, 0xac,
- 0x50, 0xd5, 0x3f, 0x74, 0x3d, 0x13, 0xde, 0x9b, 0xbf, 0x0b, 0x70, 0x10,
- 0x91, 0x27, 0x8d, 0x37, 0x4a, 0xaf, 0xfe, 0x36, 0x4b, 0xd9, 0xa6, 0x8d,
- 0xce, 0xb1, 0x7c, 0xf0, 0x35, 0x96, 0x29, 0x63, 0xe6, 0x8e, 0xff, 0x6d,
- 0x9c, 0xfb, 0x0b, 0xa5, 0x8a, 0x34, 0xf4, 0x80, 0x39, 0x7c, 0x4d, 0xee,
- 0x2c, 0x5e, 0x27, 0xed, 0x62, 0xcd, 0xa3, 0x7f, 0xf2, 0x2b, 0xf6, 0x9c,
- 0xb2, 0x56, 0x29, 0x51, 0x0d, 0x8c, 0x8a, 0xef, 0xb1, 0x39, 0x35, 0xd2,
- 0x4b, 0x17, 0xb1, 0x86, 0xb1, 0x78, 0x78, 0x75, 0x8b, 0x98, 0x86, 0x6e,
- 0x58, 0x72, 0xff, 0xc5, 0x39, 0xd7, 0xdb, 0x7b, 0xe9, 0x62, 0xa5, 0x17,
- 0x30, 0x4f, 0xf1, 0x55, 0xe1, 0x49, 0xd6, 0x2f, 0xe8, 0x14, 0xfb, 0xf2,
- 0xb1, 0x5c, 0x3c, 0xaf, 0x0e, 0xdf, 0xbe, 0xda, 0x91, 0xac, 0x5f, 0xe1,
- 0x6e, 0x45, 0xf1, 0x17, 0x96, 0x2f, 0xfc, 0xf1, 0x86, 0x59, 0xc2, 0x17,
- 0xd6, 0x2b, 0xa4, 0x50, 0xfc, 0xa1, 0xce, 0x6f, 0xf9, 0xa0, 0xfc, 0x3c,
- 0xe7, 0x96, 0x2f, 0x45, 0x0c, 0x58, 0xbf, 0xd3, 0x1c, 0x1b, 0xa9, 0x3a,
- 0xc5, 0x4a, 0x22, 0xf0, 0xe3, 0x43, 0xd7, 0x3c, 0x16, 0x2f, 0xfa, 0x01,
- 0x33, 0x5d, 0x3b, 0xf4, 0xa8, 0x98, 0x0a, 0x93, 0xe1, 0x71, 0x7b, 0xf0,
- 0x9f, 0xcd, 0xe5, 0x8b, 0x81, 0xda, 0xc5, 0xc1, 0x76, 0x58, 0xba, 0x10,
- 0x58, 0xbf, 0xd1, 0xbf, 0x80, 0x19, 0x41, 0x62, 0xd2, 0xb1, 0x74, 0x6c,
- 0xb1, 0x7f, 0xd3, 0x9c, 0x8b, 0xec, 0x67, 0x96, 0x2b, 0x0f, 0x90, 0x84,
- 0x78, 0x31, 0x77, 0x25, 0x62, 0xa5, 0x35, 0x28, 0xca, 0x20, 0x33, 0xd0,
- 0xdb, 0x0c, 0x3c, 0x26, 0x84, 0x5b, 0x78, 0xc6, 0x02, 0xc5, 0xdb, 0x38,
- 0xb1, 0x7d, 0xc7, 0x20, 0x2c, 0x5e, 0x29, 0x8d, 0x62, 0xa2, 0x3f, 0x7f,
- 0x8f, 0x00, 0x68, 0x2e, 0x45, 0x7f, 0x77, 0xa9, 0x0d, 0xc9, 0x62, 0xff,
- 0x4e, 0x6b, 0xde, 0xce, 0x2c, 0x53, 0x9f, 0x10, 0x0b, 0xef, 0xf0, 0xbb,
- 0xd3, 0x49, 0xf1, 0x62, 0xfd, 0xf6, 0x92, 0x8d, 0x62, 0xff, 0xa6, 0x3f,
- 0x14, 0x8b, 0xdc, 0x58, 0xaf, 0xa2, 0x5b, 0x86, 0x9b, 0x25, 0x17, 0xc5,
- 0x9c, 0x95, 0x8a, 0xf1, 0xea, 0x6f, 0x33, 0xbd, 0x06, 0x02, 0xc5, 0xf8,
- 0x8b, 0x3c, 0xcb, 0x17, 0xdd, 0xf4, 0xc6, 0xac, 0x5f, 0x9c, 0xdc, 0xfb,
- 0xac, 0x56, 0x22, 0xd6, 0x22, 0x47, 0x1d, 0xf1, 0x30, 0x89, 0xaf, 0xff,
- 0x43, 0xf8, 0x46, 0x07, 0xaf, 0xb4, 0x9d, 0x62, 0xfe, 0x6f, 0x61, 0xe7,
- 0xeb, 0x17, 0xfc, 0xc0, 0x8f, 0xf3, 0xc1, 0x71, 0x62, 0xff, 0x41, 0xfd,
- 0xc6, 0x29, 0x58, 0xb4, 0xe8, 0xfb, 0x48, 0xee, 0xbb, 0x4c, 0x33, 0x49,
- 0x9e, 0x84, 0xd5, 0xff, 0xe2, 0x73, 0x33, 0xaf, 0xcf, 0x70, 0xd9, 0xc5,
- 0x8b, 0xb7, 0x1d, 0x62, 0xfe, 0x68, 0xb9, 0xe6, 0x8d, 0x62, 0xff, 0xd8,
- 0x7c, 0xd6, 0x77, 0x0c, 0xf2, 0xc5, 0xfc, 0xdf, 0x63, 0xe1, 0xab, 0x15,
- 0xf3, 0xed, 0xe1, 0xfd, 0xff, 0x3f, 0xf5, 0x2d, 0x07, 0xe2, 0xc5, 0xff,
- 0xe7, 0x8f, 0xed, 0x25, 0x91, 0x36, 0x99, 0x62, 0xb1, 0x3e, 0x08, 0x8d,
- 0xf4, 0x9f, 0xf1, 0xaf, 0x42, 0x74, 0x44, 0x46, 0x1c, 0x58, 0x96, 0x2d,
- 0xb2, 0xb1, 0x7d, 0xd3, 0x60, 0xd6, 0x29, 0x62, 0xdd, 0x2c, 0x61, 0x32,
- 0xe1, 0x01, 0x22, 0xe8, 0x0d, 0x62, 0x82, 0x88, 0xa5, 0x8c, 0x47, 0xb1,
- 0x56, 0x2f, 0xd1, 0x01, 0xc6, 0x2f, 0xc6, 0xcc, 0x30, 0x6b, 0x17, 0xd9,
- 0xef, 0xe2, 0xc5, 0xce, 0x6a, 0xc5, 0xd8, 0x32, 0x37, 0x5b, 0x24, 0x57,
- 0x6c, 0x7d, 0x2e, 0x30, 0xa2, 0xef, 0x01, 0x62, 0xf8, 0x7f, 0xc8, 0xd6,
- 0x2e, 0xdd, 0x82, 0xc5, 0xf9, 0xf3, 0xd8, 0x75, 0x8b, 0xd9, 0xdf, 0x96,
- 0x2a, 0x33, 0xc5, 0x34, 0x9e, 0xa3, 0x46, 0x03, 0x0c, 0x68, 0x91, 0xd8,
- 0x2f, 0xc1, 0xec, 0xb9, 0x01, 0x62, 0xfe, 0xcf, 0xb8, 0x65, 0xe5, 0x8a,
- 0x8c, 0xf6, 0x86, 0x59, 0x79, 0xdf, 0xa5, 0x8b, 0xfd, 0x16, 0x69, 0xa3,
- 0x73, 0xac, 0x5f, 0xd9, 0xef, 0x4e, 0xb8, 0xb1, 0x7f, 0x39, 0x02, 0x30,
- 0x79, 0x62, 0xfc, 0x1f, 0xb9, 0x3e, 0x58, 0xa9, 0x47, 0xe4, 0x64, 0x78,
- 0x3a, 0x46, 0xbb, 0x25, 0xc1, 0x97, 0xd8, 0x20, 0x5b, 0x6e, 0x22, 0xa6,
- 0x33, 0x78, 0xe1, 0x93, 0x05, 0x91, 0xc6, 0x8d, 0x92, 0xae, 0xcd, 0x84,
- 0x4f, 0x51, 0xb4, 0x77, 0x0f, 0xc6, 0x79, 0x8a, 0x18, 0x7a, 0x85, 0xd9,
- 0xe1, 0x1f, 0xf8, 0xdc, 0x9e, 0x1c, 0x00, 0x85, 0x19, 0x47, 0x81, 0xc9,
- 0x66, 0xbe, 0x8c, 0x40, 0x4b, 0x9b, 0xd8, 0xcc, 0x2e, 0xd9, 0x87, 0x58,
- 0x71, 0xc9, 0x5e, 0x38, 0xb4, 0x91, 0x7f, 0xe7, 0x80, 0x4c, 0xd7, 0x4e,
- 0xfd, 0x2a, 0x26, 0x32, 0xe9, 0xdd, 0x58, 0xbb, 0x58, 0xb1, 0x69, 0xd1,
- 0xb1, 0xf8, 0xd5, 0xfe, 0xc3, 0x79, 0xf9, 0x2f, 0x2c, 0x5f, 0x7a, 0x12,
- 0x6a, 0xc5, 0x11, 0xec, 0x06, 0x69, 0x60, 0x8c, 0x99, 0xf1, 0xc7, 0xbf,
- 0x08, 0x0e, 0x3f, 0x5f, 0xf0, 0xdb, 0x78, 0x4e, 0xc0, 0x1c, 0x16, 0x2f,
- 0x18, 0x61, 0x8b, 0x17, 0xf0, 0x54, 0x29, 0xb0, 0xa1, 0x0f, 0xac, 0x5e,
- 0xd8, 0x70, 0x1a, 0xc5, 0x05, 0x0f, 0x88, 0x2c, 0x3e, 0xbf, 0xb5, 0xa1,
- 0x16, 0x7d, 0x62, 0xfa, 0x49, 0xbe, 0xb1, 0x7d, 0x31, 0xce, 0x96, 0x2f,
- 0xf7, 0x24, 0x0f, 0xe7, 0x35, 0x62, 0xf7, 0xa6, 0x25, 0x8b, 0xe9, 0x89,
- 0x8e, 0xb1, 0x7f, 0xf9, 0x88, 0xb0, 0x5d, 0x16, 0x46, 0x1c, 0x16, 0x2b,
- 0x0f, 0xbb, 0x44, 0x77, 0xdc, 0x9d, 0x4a, 0xc5, 0xf4, 0x62, 0x1e, 0xe2,
- 0xc5, 0xff, 0x6e, 0xb0, 0x36, 0xe4, 0x52, 0x75, 0x8a, 0x1a, 0x75, 0xcc,
- 0x43, 0xb8, 0x47, 0x11, 0xa6, 0xa1, 0x19, 0xe2, 0x10, 0xc8, 0xb7, 0x4a,
- 0x2d, 0x05, 0x8b, 0xf1, 0xe7, 0x3d, 0xc5, 0x8b, 0xf7, 0x18, 0xbb, 0x82,
- 0xc5, 0xd9, 0x12, 0xc5, 0x8c, 0xda, 0x78, 0x38, 0x53, 0x5b, 0x02, 0x29,
- 0x46, 0x25, 0x8d, 0x37, 0xfb, 0xf3, 0xa8, 0xc3, 0x10, 0x16, 0x2f, 0x6f,
- 0x3f, 0x16, 0x2f, 0x46, 0xe4, 0xb1, 0x46, 0x9b, 0xd1, 0x10, 0x5f, 0xff,
- 0xf0, 0xba, 0xd6, 0x6f, 0x92, 0xf6, 0x85, 0x1f, 0xe7, 0xdc, 0x65, 0x8b,
- 0xff, 0x47, 0xfc, 0x8b, 0xf2, 0x3c, 0xe9, 0x62, 0x99, 0x15, 0xa2, 0x6b,
- 0xb9, 0xf8, 0xb1, 0x7d, 0xb7, 0xd9, 0xf5, 0x8a, 0xf9, 0xbc, 0xe0, 0xbd,
- 0xff, 0xfc, 0xdd, 0xfb, 0x91, 0xeb, 0x39, 0xb7, 0x3a, 0xf8, 0xb7, 0x16,
- 0x2a, 0x51, 0x0d, 0xa2, 0x1b, 0xd2, 0x51, 0xac, 0x5f, 0xff, 0xff, 0x43,
- 0x9f, 0xc1, 0x19, 0xcf, 0xe7, 0x59, 0xcd, 0xb9, 0xdc, 0x38, 0xc4, 0xcb,
- 0x17, 0x9d, 0xfa, 0x54, 0x56, 0x25, 0xf3, 0x87, 0x26, 0xac, 0x57, 0x47,
- 0x9d, 0xa2, 0xab, 0xf7, 0xd8, 0xf3, 0xa5, 0x8b, 0xff, 0xc2, 0x78, 0xf5,
- 0x87, 0xfc, 0xc6, 0x42, 0x58, 0xa6, 0x3f, 0x42, 0x28, 0xbf, 0xc2, 0x86,
- 0x70, 0x1d, 0x81, 0x62, 0xff, 0x02, 0x7f, 0x9f, 0x6d, 0xd5, 0x8b, 0xff,
- 0x6c, 0xe7, 0x8b, 0x05, 0x25, 0xe5, 0x8b, 0xfb, 0x51, 0xfb, 0x8e, 0x05,
- 0x8b, 0xfc, 0x59, 0xc0, 0x66, 0x0d, 0x62, 0x86, 0xae, 0xe0, 0xd8, 0x72,
- 0x74, 0x45, 0xd8, 0xee, 0xa1, 0xa1, 0xf8, 0x4b, 0x91, 0x07, 0x0d, 0xbc,
- 0x6c, 0x24, 0x0d, 0xe6, 0x17, 0xfe, 0x17, 0xb8, 0x59, 0xbc, 0xb3, 0x8b,
- 0x17, 0xde, 0x2c, 0xdd, 0x58, 0xbc, 0xc2, 0x1a, 0xc5, 0x1a, 0x88, 0x26,
- 0x40, 0xdc, 0x25, 0xbf, 0xf8, 0xbc, 0x68, 0xa4, 0xb3, 0xa9, 0xd2, 0xc5,
- 0xf9, 0x82, 0xee, 0x2e, 0x96, 0x2f, 0x64, 0x61, 0x75, 0x8a, 0x93, 0xcf,
- 0x62, 0xdb, 0xfd, 0xa8, 0xfd, 0xc7, 0xef, 0xa5, 0x8b, 0xff, 0xe3, 0xef,
- 0xcd, 0x69, 0xb7, 0xf1, 0x84, 0xfa, 0x58, 0xa9, 0x4d, 0x03, 0xf0, 0x94,
- 0x72, 0x01, 0x1c, 0x5f, 0xec, 0xf6, 0x14, 0x99, 0xb2, 0xb1, 0x7f, 0xe2,
- 0x73, 0x98, 0xe3, 0x9e, 0xf8, 0xb1, 0x7f, 0xa7, 0x50, 0x68, 0x98, 0xc5,
- 0x8b, 0xff, 0x98, 0xfc, 0xdb, 0xf6, 0xf1, 0x49, 0xd6, 0x2a, 0x08, 0xf1,
- 0x01, 0xb7, 0x10, 0x3c, 0x6b, 0x7c, 0xfe, 0x7e, 0x96, 0x2f, 0xfa, 0x77,
- 0xbe, 0xba, 0xfb, 0xee, 0xac, 0x5a, 0x56, 0x2f, 0x9c, 0xf8, 0x4b, 0x15,
- 0x26, 0xcb, 0xe2, 0x37, 0xf9, 0xa7, 0xa2, 0xc6, 0x8d, 0x62, 0x8e, 0x8e,
- 0x7f, 0x91, 0xf9, 0xc7, 0x74, 0x82, 0xff, 0x49, 0x7b, 0xf8, 0x07, 0x58,
- 0xbe, 0x93, 0xbf, 0x96, 0x2a, 0x07, 0xa9, 0xc3, 0x2b, 0xf6, 0xef, 0xb3,
- 0xb8, 0x96, 0x2e, 0xd4, 0xac, 0x5e, 0x89, 0x8d, 0x58, 0xa8, 0x8d, 0xb7,
- 0x05, 0xef, 0xd8, 0x3e, 0x7e, 0x56, 0x2f, 0x1e, 0x74, 0xb1, 0x70, 0xcc,
- 0x58, 0xbf, 0xff, 0xff, 0xcf, 0xef, 0x67, 0xf8, 0xf0, 0x62, 0xf4, 0x33,
- 0x59, 0xcc, 0xfb, 0xc6, 0x53, 0x05, 0x8b, 0xde, 0x98, 0x96, 0x2a, 0x53,
- 0x8e, 0xc6, 0x4d, 0x11, 0x00, 0xa0, 0x87, 0x78, 0x32, 0x1c, 0x23, 0x2f,
- 0xfd, 0x17, 0x7e, 0x61, 0xe1, 0x61, 0xd6, 0x2f, 0xe1, 0x6c, 0xf5, 0xf6,
- 0x0b, 0xac, 0x5f, 0x77, 0x09, 0xfa, 0xc5, 0xfe, 0xe0, 0xff, 0x9d, 0x0b,
- 0x71, 0x62, 0xd9, 0xc3, 0xdd, 0x11, 0x25, 0xd3, 0xbd, 0x62, 0xbe, 0x78,
- 0x04, 0x4f, 0x7f, 0x7d, 0x86, 0x58, 0x25, 0x8b, 0xfd, 0x13, 0xe3, 0x40,
- 0x33, 0xac, 0x50, 0xd1, 0x07, 0xd1, 0x0b, 0x16, 0xdf, 0xee, 0xe1, 0x14,
- 0x1f, 0x51, 0xac, 0x5f, 0x43, 0xcd, 0x1a, 0xc5, 0x49, 0xee, 0x39, 0xc5,
- 0xff, 0xfe, 0x93, 0x9a, 0x6b, 0xf7, 0xf9, 0x6f, 0x71, 0x8b, 0xb8, 0x2c,
- 0x5f, 0xff, 0x7a, 0x7a, 0x6f, 0x31, 0xf6, 0xf1, 0xc6, 0x35, 0x8b, 0xff,
- 0xc0, 0x3b, 0xf7, 0xed, 0x63, 0x7e, 0x46, 0xb1, 0x4c, 0x89, 0xee, 0x29,
- 0xd4, 0xab, 0x27, 0xc8, 0xd5, 0xda, 0x11, 0x9f, 0x20, 0x78, 0xc0, 0xae,
- 0x87, 0x96, 0x2f, 0xe9, 0x01, 0xe7, 0x84, 0xb1, 0x7f, 0x64, 0x78, 0x59,
- 0x05, 0x8a, 0x93, 0xf2, 0x61, 0x8d, 0x16, 0xdf, 0xfd, 0xcf, 0xe6, 0xeb,
- 0x79, 0xa1, 0xc1, 0x2c, 0x5f, 0xc7, 0xf0, 0x9e, 0x39, 0x58, 0xb3, 0x76,
- 0x7e, 0xe1, 0xa4, 0x5e, 0x17, 0x78, 0xb1, 0x7f, 0xb4, 0xc2, 0x8c, 0x1c,
- 0x82, 0xc5, 0xfc, 0x71, 0x77, 0x0e, 0x6e, 0x2c, 0x5f, 0x4f, 0xdf, 0x71,
- 0x62, 0xd0, 0x93, 0xd9, 0x23, 0x4b, 0xcd, 0x31, 0xac, 0x5f, 0xfc, 0x39,
- 0xe4, 0xb7, 0x7e, 0xf4, 0x9d, 0x62, 0xfe, 0x93, 0x22, 0x29, 0x1a, 0xc5,
- 0xff, 0xc5, 0x9c, 0x60, 0x6d, 0x98, 0xe7, 0x8b, 0x15, 0x1a, 0x75, 0x43,
- 0x1e, 0xee, 0x11, 0xf1, 0x13, 0x68, 0x77, 0xc8, 0xbb, 0xcb, 0xef, 0xdd,
- 0x7e, 0x48, 0xd5, 0x8a, 0xc4, 0x4c, 0xbb, 0x7d, 0xf1, 0xdf, 0xbf, 0x2c,
- 0x5f, 0xfd, 0x1c, 0xfb, 0x68, 0x7d, 0x07, 0xba, 0x1f, 0x16, 0x2f, 0xfe,
- 0x7d, 0xcc, 0x27, 0x1b, 0xe7, 0x7e, 0x58, 0xbf, 0xed, 0x4f, 0x1f, 0x45,
- 0x30, 0x58, 0xad, 0x23, 0x3f, 0xea, 0x3b, 0xd1, 0xaf, 0x41, 0xe3, 0x58,
- 0xbd, 0xb6, 0x33, 0xac, 0x5f, 0xf3, 0xf7, 0x06, 0xff, 0xdf, 0x71, 0x62,
- 0xfe, 0x29, 0x8c, 0xa6, 0x35, 0x8b, 0x79, 0x62, 0xff, 0x3c, 0x65, 0x9e,
- 0xc0, 0x2c, 0x5f, 0xf8, 0xde, 0x73, 0x3e, 0xdc, 0x14, 0x6b, 0x14, 0x34,
- 0x43, 0xe0, 0x90, 0x8c, 0xeb, 0x63, 0x55, 0x0b, 0x90, 0xf3, 0xec, 0xc9,
- 0x87, 0xb4, 0x42, 0xe7, 0xa5, 0x0b, 0x5b, 0xe9, 0x8a, 0x63, 0x58, 0xbf,
- 0xf1, 0x38, 0xff, 0x3b, 0xfe, 0xe4, 0xb1, 0x7f, 0xfa, 0x18, 0x5e, 0x17,
- 0xdb, 0x77, 0x76, 0x77, 0x16, 0x2f, 0xff, 0xff, 0x61, 0xf3, 0x40, 0x00,
- 0xb9, 0xf6, 0xf4, 0x33, 0xee, 0x06, 0x1c, 0xac, 0x5d, 0x3b, 0x8b, 0x17,
- 0xff, 0xfb, 0x3a, 0xda, 0x42, 0xdd, 0xdb, 0x9d, 0xc3, 0x04, 0x40, 0xe2,
- 0xc5, 0xd0, 0xe2, 0xc5, 0x85, 0x1a, 0x20, 0x9d, 0xaa, 0xff, 0xf4, 0x79,
- 0xdf, 0xb8, 0xc5, 0x20, 0x73, 0xac, 0x5f, 0xee, 0xcb, 0x07, 0xf7, 0x31,
- 0x62, 0xb1, 0x10, 0x0e, 0x97, 0x51, 0xaa, 0x93, 0x19, 0x27, 0x67, 0xff,
- 0x53, 0x77, 0x72, 0x84, 0xe7, 0x21, 0x53, 0x7d, 0xe8, 0x4b, 0x2c, 0x5f,
- 0xe1, 0xc7, 0x86, 0x67, 0xdd, 0x62, 0xff, 0x7c, 0xb3, 0xb8, 0x6e, 0x44,
- 0xb1, 0x58, 0x7d, 0xce, 0x6b, 0x7f, 0x47, 0x14, 0x36, 0x3d, 0x46, 0xb1,
- 0x7c, 0x45, 0x9e, 0x58, 0xbf, 0x36, 0xe6, 0xb4, 0xcb, 0x14, 0x14, 0x44,
- 0x24, 0x9c, 0x7c, 0x86, 0xfe, 0x8c, 0x3d, 0x97, 0x20, 0x2c, 0x5f, 0x6e,
- 0x4f, 0x09, 0x62, 0xff, 0xdf, 0x73, 0xfb, 0xf3, 0xe1, 0x1d, 0x62, 0xb0,
- 0xf9, 0x62, 0x25, 0xbf, 0xfb, 0x30, 0xd3, 0xcb, 0x6b, 0x4c, 0x62, 0xc5,
- 0xe7, 0x7d, 0x2c, 0x5f, 0xf7, 0xbe, 0x27, 0x80, 0x54, 0x0c, 0xb1, 0x7f,
- 0xcd, 0x06, 0xf8, 0x8e, 0x76, 0x58, 0xbb, 0x3c, 0xb1, 0x52, 0x9d, 0x4e,
- 0x42, 0x63, 0x44, 0x5f, 0x45, 0x21, 0xcf, 0x1f, 0x6c, 0x9c, 0xdc, 0xfb,
- 0xab, 0x17, 0xbf, 0x87, 0x58, 0xbf, 0xfd, 0x3b, 0x87, 0x91, 0x96, 0x7b,
- 0xce, 0x4b, 0x14, 0x48, 0x82, 0xf0, 0xd6, 0xe8, 0xed, 0xef, 0xb0, 0x4d,
- 0x81, 0xd1, 0x05, 0xec, 0x38, 0x41, 0x85, 0xb2, 0xb9, 0x8f, 0x72, 0x38,
- 0xc8, 0xe0, 0x68, 0x37, 0x4c, 0x9c, 0x87, 0x36, 0x32, 0xfe, 0xa3, 0x73,
- 0xee, 0x33, 0x26, 0x8c, 0x92, 0x28, 0x4a, 0x6a, 0x3b, 0x03, 0xb4, 0x7e,
- 0x5b, 0x3b, 0xc3, 0x2c, 0x10, 0xa4, 0x29, 0x4d, 0x9c, 0x95, 0x4d, 0xe9,
- 0x60, 0xa2, 0x70, 0xdf, 0x09, 0x0d, 0x98, 0x52, 0x07, 0x1e, 0xe6, 0xec,
- 0x3b, 0x2f, 0x05, 0xae, 0xc8, 0x51, 0x62, 0xfb, 0xdb, 0x39, 0xf5, 0x8b,
- 0x12, 0xc5, 0x05, 0x4d, 0xbc, 0x09, 0xae, 0xd8, 0xf6, 0x12, 0xc5, 0xe0,
- 0xa6, 0xc3, 0xd9, 0x58, 0xbd, 0xe9, 0xfa, 0xc5, 0xf4, 0x8f, 0x0e, 0xb1,
- 0x6d, 0x49, 0xbf, 0xd0, 0xed, 0xb7, 0x16, 0x2e, 0x6d, 0xd5, 0x8b, 0xe8,
- 0xf5, 0x31, 0xac, 0x5c, 0x18, 0x16, 0x2e, 0xcf, 0xac, 0x5e, 0xfe, 0x44,
- 0xb1, 0x7b, 0xec, 0x75, 0x8b, 0x44, 0xb1, 0x51, 0x9f, 0x28, 0xc5, 0xdc,
- 0x78, 0x43, 0xb7, 0xe7, 0x28, 0xc5, 0xc5, 0x8b, 0xf6, 0x0f, 0x4f, 0xd2,
- 0xc5, 0xf3, 0xc7, 0x3a, 0x58, 0xbd, 0xa7, 0x8d, 0x62, 0xe9, 0x1f, 0xcf,
- 0xa8, 0x8a, 0x7c, 0x47, 0x61, 0xac, 0x53, 0x2a, 0x12, 0x88, 0x98, 0xe2,
- 0xae, 0x34, 0x02, 0x52, 0x7e, 0xe1, 0xe7, 0xa1, 0x27, 0xb2, 0x73, 0x7b,
- 0x5c, 0x12, 0xc5, 0xbe, 0xb1, 0x7b, 0x81, 0xf1, 0x62, 0xe2, 0x89, 0x62,
- 0xe9, 0x35, 0x62, 0xf6, 0xa6, 0x0b, 0x16, 0xee, 0x33, 0x6b, 0xa1, 0x8a,
- 0x94, 0x62, 0xc6, 0x3c, 0x31, 0x2c, 0x1f, 0x12, 0x6d, 0xfb, 0xb8, 0x79,
- 0xfb, 0x58, 0xbb, 0x9d, 0x2c, 0x5a, 0x56, 0x29, 0xcf, 0x54, 0x8a, 0xfc,
- 0x33, 0x7f, 0xbb, 0xd4, 0xb4, 0x1f, 0x8b, 0x17, 0xd8, 0x53, 0x05, 0x8a,
- 0xc3, 0xd5, 0x39, 0xa5, 0xb6, 0x56, 0x2f, 0xdc, 0xcf, 0x36, 0x96, 0x2f,
- 0x67, 0x7e, 0x58, 0xb6, 0x00, 0xf1, 0xb8, 0x51, 0x73, 0x8d, 0x62, 0xf7,
- 0xb3, 0x8b, 0x17, 0x14, 0xac, 0x54, 0x0f, 0x28, 0x42, 0xfb, 0xc7, 0x6f,
- 0xf9, 0x85, 0x1c, 0xf6, 0x0d, 0x4a, 0xc5, 0xe8, 0x4f, 0x6b, 0x16, 0xdc,
- 0x58, 0xa8, 0x8d, 0x99, 0x0f, 0x5e, 0xd3, 0x92, 0xc5, 0xb6, 0x56, 0x2f,
- 0xe2, 0xcd, 0xfa, 0x6e, 0x2c, 0x54, 0x67, 0x88, 0x60, 0xad, 0xbb, 0x58,
- 0xa9, 0x44, 0xbb, 0x30, 0x08, 0x92, 0xfd, 0x9a, 0x84, 0x9d, 0x62, 0xfb,
- 0xef, 0x9a, 0x58, 0xbf, 0x47, 0x84, 0xc6, 0xac, 0x54, 0x9e, 0x5b, 0x11,
- 0x5f, 0xda, 0x80, 0x1b, 0xbe, 0x2c, 0x5f, 0xee, 0x06, 0x53, 0xf6, 0x8d,
- 0x62, 0x9c, 0xf9, 0x7c, 0x61, 0x7d, 0xce, 0x48, 0x16, 0x2a, 0x55, 0xd7,
- 0x0c, 0x87, 0x16, 0xd9, 0xc7, 0x46, 0x27, 0x6e, 0xfc, 0x2e, 0x1c, 0xb8,
- 0x9c, 0xc5, 0x08, 0x53, 0x08, 0x6f, 0xfd, 0x85, 0x86, 0x96, 0x7b, 0xec,
- 0xb1, 0x7f, 0x39, 0xb8, 0x37, 0x82, 0xc5, 0x7c, 0xfa, 0xc8, 0xf6, 0xfe,
- 0x62, 0x2c, 0xde, 0xeb, 0x17, 0x07, 0xe5, 0x8b, 0xfb, 0xed, 0x91, 0x38,
- 0x16, 0x2a, 0x07, 0x8f, 0xe1, 0x9b, 0xda, 0xd3, 0xac, 0x5f, 0x40, 0x02,
- 0x82, 0xc5, 0xf6, 0x83, 0x90, 0x2c, 0x5e, 0x9f, 0xca, 0xc5, 0x49, 0xf2,
- 0x31, 0x27, 0xc9, 0x2f, 0xe8, 0xdc, 0xe0, 0x04, 0xac, 0x5f, 0x42, 0x4a,
- 0x0b, 0x14, 0xc7, 0xa3, 0x11, 0x7d, 0xcc, 0x35, 0x8b, 0x9f, 0xb5, 0x8b,
- 0xfb, 0xf9, 0x11, 0x48, 0xd6, 0x2f, 0xfa, 0x12, 0x7e, 0x66, 0xa7, 0x8b,
- 0x15, 0xd1, 0xf3, 0xf6, 0x5d, 0x7d, 0x11, 0x39, 0x8b, 0x17, 0xfd, 0x25,
- 0x9b, 0xf0, 0x9c, 0xd5, 0x8a, 0x34, 0xf7, 0x74, 0x49, 0x43, 0x4c, 0x8d,
- 0x9f, 0xde, 0x10, 0x37, 0xbc, 0xc0, 0x58, 0xbe, 0x04, 0x97, 0x4b, 0x16,
- 0x0b, 0xac, 0x51, 0xa7, 0xad, 0xd8, 0xe8, 0x88, 0xef, 0xa1, 0xec, 0x0d,
- 0x62, 0xfd, 0xe6, 0xfb, 0x9d, 0x62, 0xe9, 0x02, 0xc5, 0x49, 0xbf, 0xe8,
- 0xa2, 0xf6, 0xa4, 0xeb, 0x14, 0xc8, 0xd2, 0x73, 0x11, 0x31, 0x98, 0x43,
- 0x7e, 0xce, 0xfc, 0xe7, 0x58, 0xbb, 0x22, 0x58, 0xb4, 0x64, 0x78, 0x21,
- 0x94, 0xde, 0x9d, 0x46, 0xb1, 0x52, 0x78, 0xec, 0x53, 0x4b, 0x17, 0xba,
- 0x90, 0x2c, 0x58, 0xa0, 0x6a, 0xb0, 0x32, 0xfe, 0xfb, 0x1f, 0x3e, 0xeb,
- 0x15, 0x27, 0xa4, 0x22, 0x5b, 0xef, 0x13, 0x6e, 0xac, 0x5c, 0x2e, 0x2c,
- 0x5f, 0x85, 0x0e, 0x7c, 0x6b, 0x15, 0x27, 0x84, 0x43, 0x17, 0xec, 0x8a,
- 0x0f, 0xc5, 0x8a, 0x82, 0xf4, 0xf8, 0xc8, 0x7b, 0x74, 0x62, 0x28, 0xa1,
- 0x03, 0xa7, 0xe3, 0x91, 0x7e, 0x33, 0xa2, 0x8d, 0x73, 0x90, 0xc4, 0xf4,
- 0x27, 0x04, 0x43, 0xbd, 0x9c, 0x32, 0x0b, 0xf9, 0xe1, 0xbb, 0xba, 0x28,
- 0xd6, 0x2f, 0xee, 0x07, 0x23, 0xd8, 0x61, 0x55, 0x8b, 0x12, 0xc5, 0xd0,
- 0xdc, 0x58, 0xaf, 0xa2, 0x71, 0xcd, 0xb8, 0x75, 0xe1, 0x1b, 0xbd, 0xc5,
- 0x8b, 0xda, 0x0e, 0x25, 0x8b, 0xfb, 0x8f, 0xdf, 0x9a, 0x35, 0x8a, 0xd1,
- 0xe8, 0x78, 0x82, 0x96, 0x29, 0x8d, 0x76, 0xc9, 0x15, 0xfd, 0x91, 0x8f,
- 0xed, 0xa5, 0x8a, 0x64, 0x74, 0x7e, 0x12, 0xc4, 0x47, 0x7f, 0xe9, 0xce,
- 0x6d, 0x96, 0x18, 0x70, 0x58, 0xbf, 0x98, 0xce, 0x47, 0x86, 0x2c, 0x51,
- 0x1f, 0x97, 0x90, 0x6e, 0x29, 0x58, 0xbc, 0x00, 0x4a, 0xc5, 0xd9, 0xd2,
- 0xc5, 0xd2, 0x3e, 0x1b, 0x5f, 0x0e, 0xde, 0x92, 0xe9, 0x62, 0xff, 0xfe,
- 0x73, 0x06, 0xef, 0xa8, 0xfe, 0xfe, 0xfb, 0x6a, 0x0b, 0x17, 0xee, 0xba,
- 0xfc, 0xe9, 0x62, 0xbe, 0x8a, 0x52, 0x1d, 0x12, 0xed, 0x41, 0x36, 0xce,
- 0x88, 0x78, 0x97, 0xe8, 0x68, 0xdf, 0x39, 0x3c, 0x4b, 0x17, 0xec, 0xd0,
- 0x7e, 0xe2, 0xc5, 0xf9, 0xbc, 0x59, 0x05, 0x8b, 0xe9, 0x32, 0x62, 0x58,
- 0xbf, 0xf7, 0x37, 0xbf, 0xe4, 0xdc, 0xf7, 0x16, 0x2e, 0x0c, 0xeb, 0x17,
- 0xd9, 0xa1, 0x62, 0xc5, 0x80, 0xb1, 0x44, 0x6d, 0x03, 0x22, 0xbe, 0x8e,
- 0x39, 0xdc, 0x58, 0xbc, 0xfd, 0x92, 0xc5, 0xfd, 0xe2, 0x70, 0x61, 0x2c,
- 0x5f, 0x89, 0xc1, 0x84, 0xb1, 0x5b, 0x4f, 0x4b, 0xc5, 0x95, 0x28, 0xbb,
- 0x19, 0x40, 0x9b, 0xea, 0x35, 0x46, 0x30, 0x22, 0x34, 0xa9, 0x89, 0xe2,
- 0x24, 0xfa, 0x10, 0x13, 0x4a, 0x1b, 0x97, 0xdc, 0xc2, 0xe9, 0x62, 0xfe,
- 0x92, 0xf7, 0x42, 0x8d, 0x62, 0xfd, 0x9d, 0x7b, 0x3a, 0x58, 0xb7, 0x16,
- 0x2f, 0xf4, 0x98, 0x31, 0x3e, 0xa0, 0xb1, 0x7b, 0x93, 0x05, 0x8b, 0xf7,
- 0xf3, 0x4d, 0xc5, 0x8b, 0x9b, 0x5d, 0x9e, 0x2f, 0x87, 0x6f, 0xe6, 0xd3,
- 0x72, 0x63, 0x58, 0xb6, 0xf5, 0x8a, 0x94, 0xde, 0x60, 0x47, 0x86, 0x11,
- 0x15, 0x68, 0x4b, 0xef, 0x5c, 0x2e, 0xdd, 0x2e, 0xb8, 0x72, 0xb1, 0x7f,
- 0xef, 0xe4, 0x3d, 0x38, 0x5d, 0xf9, 0x62, 0xb0, 0xf5, 0xbc, 0x2f, 0x60,
- 0xd6, 0x28, 0x8d, 0xa6, 0xe9, 0x0d, 0xe2, 0x63, 0x56, 0x2f, 0xb0, 0x6d,
- 0xbd, 0x62, 0xe9, 0x3e, 0x1e, 0x0b, 0x8e, 0xdf, 0xa1, 0xe6, 0x3f, 0x96,
- 0x2f, 0xe7, 0xef, 0xf2, 0x19, 0x2c, 0x5b, 0x3b, 0x3d, 0x83, 0x0a, 0x6f,
- 0x07, 0xd9, 0x2c, 0x5f, 0xcf, 0x07, 0x2c, 0xdd, 0x58, 0xb9, 0x86, 0xb1,
- 0x7d, 0xcf, 0xbc, 0x16, 0x2d, 0xe5, 0x8a, 0x94, 0xea, 0x99, 0x93, 0x50,
- 0x83, 0xf9, 0x4b, 0x8f, 0x80, 0xbc, 0x42, 0xe1, 0x91, 0xde, 0xc2, 0x89,
- 0x62, 0xdd, 0xac, 0x5c, 0x09, 0x48, 0xb8, 0xc3, 0x12, 0x29, 0x8d, 0x89,
- 0x82, 0xf7, 0xe2, 0xcf, 0x7d, 0x92, 0x02, 0x1a, 0x1b, 0xe3, 0x4b, 0x38,
- 0xb1, 0x50, 0x3d, 0xc1, 0x9c, 0xdd, 0xd0, 0x16, 0x2f, 0xf3, 0x9b, 0x24,
- 0x59, 0xe5, 0x8b, 0xf3, 0x0e, 0x70, 0x96, 0x2e, 0x03, 0xac, 0x5f, 0x36,
- 0x9b, 0xcb, 0x14, 0xc6, 0xe6, 0x21, 0x7a, 0x94, 0xf2, 0xc6, 0x3a, 0xf0,
- 0xc1, 0x01, 0x11, 0x0c, 0xf0, 0xc8, 0x4b, 0xf7, 0xbf, 0x26, 0x2c, 0x5e,
- 0x7e, 0xf8, 0xb1, 0x6e, 0x2c, 0x5f, 0x07, 0xf7, 0xf2, 0xc5, 0x46, 0x7e,
- 0x43, 0x1e, 0xec, 0x7b, 0xc2, 0x57, 0xa4, 0xa2, 0x58, 0xa5, 0x8b, 0x4a,
- 0xc5, 0x00, 0xbd, 0x20, 0xca, 0x58, 0xa5, 0x8a, 0x88, 0xb8, 0x38, 0x65,
- 0xdf, 0x89, 0x62, 0xe6, 0x02, 0xc5, 0x49, 0xb0, 0x00, 0xcd, 0x44, 0x8e,
- 0x2d, 0x1d, 0x39, 0xb8, 0x14, 0x6f, 0xfe, 0x35, 0x8b, 0xae, 0x49, 0xdf,
- 0xbf, 0x2c, 0x5e, 0x06, 0x6e, 0xac, 0x5f, 0xff, 0x16, 0x03, 0x0e, 0x29,
- 0xd6, 0x98, 0x5d, 0x2c, 0x5f, 0x14, 0x9e, 0x25, 0x8a, 0x35, 0x1b, 0x5a,
- 0x47, 0x22, 0x0f, 0x28, 0x5f, 0x1f, 0x82, 0x3a, 0xc5, 0x8d, 0x58, 0xb6,
- 0xca, 0xc5, 0xda, 0x35, 0x62, 0xa4, 0xf9, 0x58, 0x90, 0x42, 0x61, 0x8a,
- 0xdf, 0xff, 0x7f, 0x21, 0xc9, 0xf4, 0x33, 0x71, 0xc8, 0x0b, 0x17, 0xfc,
- 0xde, 0xfe, 0x77, 0xe1, 0x4a, 0xc5, 0xf0, 0x73, 0xa0, 0x2c, 0x54, 0x0f,
- 0x7b, 0xe7, 0x57, 0x67, 0x16, 0x2f, 0xff, 0x64, 0x36, 0x70, 0xd7, 0xcf,
- 0x4f, 0xb8, 0xb1, 0x52, 0x88, 0x68, 0x11, 0x00, 0x5e, 0xb8, 0x9b, 0x2f,
- 0xa3, 0x36, 0xba, 0x78, 0xb1, 0x60, 0x2c, 0x5f, 0x49, 0xe4, 0xeb, 0x17,
- 0xe6, 0x30, 0xef, 0xe5, 0x8a, 0x63, 0xcb, 0xd1, 0x15, 0xf7, 0x5f, 0x9e,
- 0x2c, 0x5b, 0x16, 0x29, 0x91, 0xe9, 0xa2, 0xa7, 0x17, 0xe2, 0xe9, 0x84,
- 0x3b, 0x24, 0x97, 0xfc, 0x3c, 0x18, 0x48, 0xba, 0x11, 0x2c, 0x58, 0xd5,
- 0x8a, 0x95, 0xe1, 0x7c, 0x8c, 0x81, 0xa3, 0x17, 0xfc, 0x28, 0x9e, 0x54,
- 0xa0, 0x6b, 0x3b, 0xa7, 0xd7, 0xd2, 0x60, 0xa2, 0x58, 0xbd, 0xc9, 0x89,
- 0x62, 0xfe, 0xc1, 0xe6, 0xf6, 0xd2, 0xc5, 0xf4, 0x51, 0x37, 0xd6, 0x29,
- 0x62, 0xda, 0x58, 0xb1, 0xd6, 0x2b, 0x87, 0xab, 0xe2, 0x51, 0x06, 0x6f,
- 0x12, 0xbe, 0x1b, 0xbf, 0x6b, 0x17, 0xe0, 0x36, 0x98, 0xd5, 0x8b, 0xb9,
- 0xe5, 0x8b, 0x1a, 0xb1, 0x52, 0x6a, 0xdc, 0x62, 0xec, 0xed, 0x62, 0xba,
- 0x4e, 0xce, 0x22, 0x53, 0x8f, 0x7e, 0x10, 0x8e, 0x7c, 0x02, 0x32, 0x54,
- 0xd9, 0x1f, 0xbb, 0x3e, 0xb1, 0x7f, 0x17, 0xb0, 0x98, 0xc5, 0x8b, 0xfb,
- 0xdc, 0xc3, 0xb7, 0x96, 0x2d, 0xa5, 0x8a, 0x93, 0xc0, 0xc2, 0xea, 0x58,
- 0xa5, 0x8b, 0x4a, 0xc5, 0x05, 0xcd, 0x49, 0x06, 0x78, 0x32, 0xf6, 0x6f,
- 0x75, 0x8b, 0xef, 0xff, 0x00, 0xb1, 0x69, 0xf9, 0xe0, 0x86, 0x3d, 0x52,
- 0x9b, 0x3b, 0x0b, 0x9d, 0xb5, 0xd2, 0x40, 0xe5, 0x7f, 0x7b, 0x3b, 0x84,
- 0xc1, 0x62, 0xfd, 0xec, 0xfb, 0x9a, 0xb1, 0x5d, 0x9e, 0xc3, 0x17, 0xdf,
- 0xbb, 0x06, 0xc4, 0x2e, 0x2c, 0x5e, 0xfb, 0x9d, 0x62, 0xfe, 0x7f, 0x00,
- 0x32, 0x82, 0xc5, 0xfb, 0x99, 0xa6, 0x35, 0x62, 0x86, 0x7e, 0xbb, 0x83,
- 0xbe, 0x2f, 0xbf, 0xbc, 0x36, 0x04, 0x92, 0xc5, 0xe8, 0xfe, 0xcb, 0x17,
- 0x7c, 0x5d, 0x9e, 0x5b, 0x96, 0xdb, 0xeb, 0x17, 0x8c, 0x30, 0xc4, 0x8b,
- 0xfd, 0x31, 0x87, 0x9f, 0x7e, 0xd2, 0x02, 0x1a, 0x1b, 0xfc, 0xc3, 0x72,
- 0xee, 0x1c, 0x58, 0xa1, 0x9f, 0xe7, 0xd2, 0x2e, 0xc8, 0xd6, 0x2f, 0xc7,
- 0x0e, 0x74, 0x05, 0x8a, 0x58, 0xa5, 0x8b, 0x49, 0xcb, 0x80, 0x06, 0x54,
- 0x9f, 0x3c, 0x10, 0xaf, 0xfd, 0xc9, 0x87, 0xf3, 0x0a, 0x1c, 0x58, 0xbf,
- 0x9f, 0xda, 0xd6, 0x46, 0xb1, 0x43, 0x54, 0x19, 0x85, 0xdd, 0x42, 0xbd,
- 0x88, 0xa2, 0x7f, 0xf1, 0x09, 0x87, 0xd7, 0xa4, 0xec, 0xb1, 0x7a, 0x19,
- 0xd2, 0xc5, 0xf4, 0x8d, 0x8e, 0xb1, 0x7f, 0xb9, 0xfc, 0xe7, 0x9a, 0x35,
- 0x8b, 0xb8, 0xeb, 0x15, 0xb0, 0x2e, 0x21, 0x4c, 0x29, 0x72, 0x54, 0x4f,
- 0x4d, 0x9d, 0x8e, 0x30, 0xf3, 0x91, 0x78, 0xd6, 0xff, 0xb4, 0x1c, 0x27,
- 0x7b, 0x10, 0x16, 0x2f, 0x6b, 0x74, 0x6b, 0x16, 0xfa, 0xc5, 0x49, 0xf7,
- 0xb1, 0xe6, 0xe9, 0x0d, 0xfb, 0xf3, 0xdb, 0xee, 0x2c, 0x5f, 0xff, 0x4f,
- 0xb8, 0x3c, 0xf3, 0x7c, 0x59, 0xdf, 0x96, 0x2b, 0xe7, 0xfb, 0xe2, 0xcb,
- 0xc5, 0x9f, 0x58, 0xb6, 0x96, 0x2f, 0xf9, 0x86, 0x1f, 0xbb, 0xe9, 0x8e,
- 0xb1, 0x7f, 0x67, 0x41, 0xef, 0xfe, 0x2c, 0x54, 0x0f, 0xbf, 0x0f, 0x6f,
- 0xfa, 0x4b, 0xc5, 0x9e, 0x93, 0x16, 0x2f, 0xe3, 0x38, 0xc5, 0xdc, 0x16,
- 0x2f, 0xa3, 0xf6, 0x7d, 0x62, 0xb0, 0xf5, 0x04, 0x61, 0x4b, 0x14, 0xc8,
- 0xb9, 0xd4, 0x23, 0x1c, 0x86, 0xfb, 0x9e, 0x76, 0x58, 0xbf, 0x44, 0x03,
- 0xe4, 0x4b, 0x17, 0xbd, 0xf9, 0x58, 0xac, 0x3c, 0x87, 0x2b, 0xbe, 0xf7,
- 0x24, 0x0b, 0x17, 0x68, 0x4b, 0x15, 0x86, 0xef, 0xc4, 0x76, 0xe2, 0xc5,
- 0x11, 0xb2, 0x11, 0x05, 0xfe, 0x7d, 0xf8, 0x38, 0xf0, 0xc5, 0x8b, 0xff,
- 0xd3, 0x9d, 0x87, 0xe6, 0x21, 0x43, 0x38, 0xb1, 0x7a, 0x72, 0x35, 0x8b,
- 0x60, 0xcf, 0xa3, 0x7a, 0x5d, 0xf6, 0x7c, 0x3d, 0x2c, 0x5c, 0x70, 0x2c,
- 0x5c, 0xe4, 0xb1, 0x5f, 0x35, 0xce, 0x31, 0x73, 0x1a, 0xb1, 0x7c, 0xde,
- 0x03, 0xac, 0x5f, 0xa7, 0xb8, 0x61, 0xd6, 0x2a, 0x07, 0xc6, 0x71, 0x8f,
- 0x91, 0x5f, 0x72, 0x48, 0xd5, 0x8a, 0x8d, 0x75, 0xff, 0x21, 0x5a, 0xc4,
- 0x5b, 0x83, 0x91, 0x42, 0x07, 0x50, 0xda, 0x39, 0x9f, 0xda, 0x9e, 0x11,
- 0xa0, 0x20, 0x28, 0x4f, 0xf0, 0xa7, 0xca, 0x42, 0x84, 0x18, 0x65, 0xf7,
- 0x68, 0xd5, 0x8b, 0xe9, 0x3b, 0xfd, 0x62, 0xf7, 0xbc, 0xeb, 0x17, 0xda,
- 0x14, 0xef, 0x58, 0xbc, 0xe4, 0x01, 0x9f, 0x23, 0x91, 0x78, 0x76, 0xfe,
- 0xe1, 0x64, 0x61, 0xc1, 0x62, 0xd9, 0xb8, 0x7d, 0xc0, 0x3e, 0xba, 0x40,
- 0xb1, 0x7b, 0xcd, 0x1a, 0xc5, 0x44, 0x6d, 0x7e, 0x2f, 0x7f, 0xba, 0x6e,
- 0x16, 0x6f, 0x75, 0x8b, 0xe9, 0x8d, 0xe0, 0xb1, 0x70, 0x0e, 0xb1, 0x7b,
- 0x9f, 0x65, 0x8a, 0xd1, 0xb5, 0xf0, 0xc5, 0xfc, 0x4f, 0xe8, 0xf0, 0xc5,
- 0x8a, 0x58, 0xa2, 0x37, 0x7e, 0x2f, 0xa9, 0x3f, 0xcc, 0x5c, 0xbe, 0x8c,
- 0xb3, 0xb5, 0x8b, 0xf8, 0x1c, 0xc1, 0xbc, 0x16, 0x2b, 0x0f, 0x49, 0xc9,
- 0x2f, 0xbc, 0xc5, 0xc5, 0x8b, 0xed, 0xb9, 0xdf, 0x96, 0x2f, 0xee, 0x4f,
- 0x70, 0xcf, 0x2c, 0x57, 0x47, 0xab, 0xc2, 0x6b, 0xec, 0xf3, 0x71, 0x62,
- 0x96, 0x2b, 0xb3, 0x5c, 0xe4, 0x55, 0x88, 0xe9, 0x67, 0x77, 0x51, 0xa9,
- 0x5c, 0x1d, 0x84, 0x3a, 0xf1, 0x7f, 0xb2, 0x2d, 0x1a, 0xfe, 0x1a, 0x84,
- 0xe5, 0xc8, 0xc2, 0x69, 0x62, 0xe1, 0x06, 0xb1, 0x51, 0x1a, 0x50, 0xc3,
- 0x2f, 0x13, 0x6e, 0x2c, 0x5f, 0xdf, 0x9f, 0x73, 0xec, 0xb1, 0x73, 0x9a,
- 0xb1, 0x61, 0xf8, 0xf1, 0xb6, 0x4b, 0xaf, 0x77, 0xc1, 0xac, 0x54, 0xa2,
- 0xbf, 0x19, 0x58, 0xae, 0xdb, 0x2b, 0x17, 0x48, 0xd6, 0x28, 0x2a, 0x6b,
- 0x3e, 0x2b, 0x6e, 0x2c, 0x58, 0xeb, 0x16, 0xd2, 0xc5, 0x39, 0xa4, 0x10,
- 0x95, 0x68, 0xf5, 0xbe, 0x6d, 0x7f, 0x46, 0x3d, 0x30, 0xa3, 0x58, 0xb0,
- 0x6b, 0x16, 0x02, 0xc5, 0x2c, 0x31, 0xfc, 0x39, 0x10, 0x8c, 0x76, 0x44,
- 0xef, 0xf4, 0x94, 0x1c, 0xf8, 0x35, 0x8b, 0xef, 0x1c, 0xfa, 0x58, 0xbf,
- 0xf8, 0x12, 0x5d, 0x3f, 0x80, 0x19, 0x41, 0x62, 0xf4, 0x1b, 0xeb, 0x17,
- 0xde, 0x2c, 0x82, 0xc5, 0xf0, 0x82, 0xfc, 0x75, 0x8b, 0xf4, 0x63, 0x77,
- 0x31, 0x62, 0xb0, 0xf4, 0x44, 0x4f, 0x7f, 0xf7, 0x3f, 0x83, 0x2c, 0xde,
- 0x59, 0xc5, 0x8b, 0xe9, 0x84, 0x0e, 0xb1, 0x79, 0xe2, 0xe2, 0xc5, 0x32,
- 0x21, 0x89, 0x17, 0xc4, 0x75, 0x05, 0x40, 0x26, 0x99, 0x76, 0x49, 0x12,
- 0x36, 0x87, 0x49, 0xcf, 0xd0, 0xa7, 0xb8, 0x3e, 0x96, 0x28, 0x28, 0xf8,
- 0x00, 0x1b, 0x1b, 0x1e, 0xc2, 0x25, 0x0b, 0x52, 0x39, 0x94, 0xf9, 0x1c,
- 0x69, 0x70, 0x84, 0xf0, 0xe7, 0x0c, 0x32, 0x7e, 0xa8, 0xd8, 0xdf, 0x3a,
- 0x8c, 0x93, 0xb9, 0x42, 0x2d, 0x29, 0xd6, 0x28, 0xfc, 0xb5, 0x2a, 0xa0,
- 0xf2, 0x90, 0x3f, 0x3d, 0xe0, 0xf2, 0x8c, 0x81, 0x1f, 0x08, 0x5e, 0x14,
- 0x05, 0x38, 0xc9, 0xc9, 0xe7, 0x1f, 0x4e, 0x86, 0x0a, 0x14, 0xfb, 0xe1,
- 0xa4, 0x62, 0xce, 0xcc, 0x3c, 0xc3, 0x94, 0x8d, 0xba, 0xdb, 0x7f, 0xc1,
- 0x3c, 0xd9, 0xbb, 0xc1, 0x4a, 0xc5, 0xe0, 0x07, 0x05, 0x8b, 0xff, 0xee,
- 0x37, 0xdd, 0xbd, 0x9a, 0x01, 0xde, 0x0b, 0x16, 0x09, 0xd9, 0xf7, 0x78,
- 0x7e, 0xff, 0x70, 0x24, 0xef, 0x91, 0x74, 0xb1, 0x61, 0x49, 0xf2, 0x78,
- 0xae, 0x82, 0x2b, 0x7c, 0x8e, 0x52, 0x28, 0xe3, 0x10, 0xbf, 0x6b, 0xa7,
- 0x7e, 0x95, 0x15, 0xb9, 0x7f, 0xe7, 0x80, 0x4c, 0xd7, 0x4e, 0xfd, 0x2a,
- 0x27, 0x02, 0xc1, 0x31, 0x10, 0xc7, 0x37, 0xbb, 0x63, 0x1a, 0xc5, 0xbe,
- 0xb1, 0x6e, 0x2c, 0x50, 0x8d, 0x26, 0xc8, 0x95, 0xfb, 0x0c, 0xe3, 0x18,
- 0xb1, 0x7a, 0x1c, 0xe2, 0xc5, 0xf7, 0x4e, 0xfd, 0x2a, 0x2d, 0x12, 0xff,
- 0xf6, 0x0f, 0xee, 0x6c, 0x51, 0x37, 0x04, 0x75, 0x8b, 0xf6, 0x7f, 0xa6,
- 0xe2, 0xc5, 0xfe, 0x98, 0xff, 0x9a, 0x17, 0x4b, 0x17, 0xf3, 0xf7, 0x3e,
- 0x91, 0xac, 0x56, 0x93, 0x0c, 0xf9, 0x89, 0x27, 0x70, 0xa7, 0x79, 0xb5,
- 0xe6, 0x2e, 0x96, 0x2f, 0x39, 0x01, 0x62, 0xb0, 0xdc, 0xf4, 0x3b, 0x7c,
- 0x09, 0x2e, 0x96, 0x2f, 0x6f, 0x98, 0x96, 0x2f, 0xf6, 0x6e, 0x73, 0x5a,
- 0x7f, 0x2c, 0x5f, 0xd3, 0x1b, 0xfd, 0xce, 0xb1, 0x4c, 0x88, 0x58, 0x88,
- 0x3e, 0x6f, 0x7f, 0x4f, 0xb0, 0xba, 0xc5, 0x8b, 0x71, 0x62, 0x98, 0xdf,
- 0xfc, 0xb6, 0xfe, 0x97, 0x21, 0x0f, 0x16, 0x2f, 0x0b, 0xdc, 0x58, 0xbf,
- 0x0f, 0xee, 0x5e, 0x58, 0xbe, 0x8b, 0x0d, 0x1a, 0xc5, 0xb4, 0x33, 0xeb,
- 0xc1, 0xef, 0x14, 0x5f, 0xf4, 0xc7, 0xfc, 0xe7, 0xf3, 0x71, 0x62, 0xfd,
- 0xd6, 0x31, 0x74, 0xb1, 0x7f, 0xb3, 0xa2, 0x90, 0x72, 0x56, 0x2e, 0x9e,
- 0xb6, 0x9e, 0xe7, 0x0a, 0x6f, 0xfb, 0x7f, 0x33, 0xf8, 0x41, 0x8d, 0x62,
- 0xa4, 0xfb, 0x30, 0xc2, 0xbe, 0x99, 0x29, 0x46, 0x0b, 0x7f, 0xb3, 0x40,
- 0xc8, 0x83, 0xe2, 0xc5, 0x8d, 0x58, 0xbf, 0xec, 0x98, 0xf2, 0x2d, 0x37,
- 0x16, 0x29, 0x8f, 0x36, 0x21, 0x3b, 0xff, 0xf4, 0x73, 0xe9, 0x1e, 0xa7,
- 0xef, 0xc2, 0xc0, 0x2c, 0x5f, 0xfa, 0x7b, 0x7d, 0xcf, 0x93, 0xee, 0x46,
- 0xb1, 0x7f, 0xe9, 0xd0, 0x31, 0xb3, 0x5e, 0x12, 0xc5, 0x4a, 0x36, 0x7e,
- 0xab, 0xc4, 0x6a, 0x1a, 0x7a, 0xcc, 0x53, 0x14, 0x20, 0xf9, 0x0f, 0xbb,
- 0xfa, 0x77, 0x93, 0xfb, 0x8b, 0x17, 0xff, 0xde, 0x91, 0xfc, 0x4e, 0x6f,
- 0x58, 0xc5, 0xd2, 0xc5, 0xff, 0xb9, 0xfc, 0x04, 0x5c, 0x27, 0xfa, 0xc5,
- 0xf1, 0xd8, 0xa0, 0xb1, 0x4c, 0x8b, 0x4d, 0xc5, 0x2e, 0x20, 0x54, 0xae,
- 0x46, 0x64, 0xb2, 0xff, 0xa4, 0x3c, 0x38, 0xed, 0xbd, 0x62, 0xe9, 0xfa,
- 0xc5, 0xdc, 0x3a, 0xc5, 0x31, 0xe1, 0xc4, 0x29, 0xf1, 0x7a, 0x58, 0xb1,
- 0xab, 0x17, 0xb5, 0x26, 0xac, 0x5f, 0x9b, 0xc5, 0x27, 0x58, 0xa0, 0xa1,
- 0xf2, 0x48, 0x64, 0x42, 0x7f, 0x1e, 0xbf, 0xd2, 0x7d, 0x69, 0x81, 0xc5,
- 0x8b, 0xdd, 0x61, 0x8b, 0x16, 0xc8, 0x8f, 0x4f, 0xe6, 0x97, 0xff, 0xcd,
- 0xee, 0x37, 0x4f, 0xae, 0xb1, 0x8b, 0xa5, 0x8b, 0x18, 0xb1, 0x7f, 0xb5,
- 0x3e, 0xee, 0x19, 0xe5, 0x8b, 0xff, 0xfb, 0x22, 0x72, 0x8c, 0x0d, 0xdf,
- 0x3a, 0xc6, 0x2e, 0x96, 0x2e, 0xc1, 0xac, 0x5e, 0x8d, 0xce, 0xb1, 0x70,
- 0x35, 0x26, 0xd5, 0x85, 0xef, 0xda, 0x3c, 0xe7, 0x16, 0x2a, 0x4f, 0x4f,
- 0x0a, 0xef, 0xfe, 0xef, 0x9e, 0x2c, 0xdf, 0xef, 0x30, 0xd6, 0x2a, 0x09,
- 0xf3, 0xb2, 0x8c, 0x42, 0x64, 0x6b, 0xc8, 0x73, 0x08, 0x82, 0xe6, 0x82,
- 0xc5, 0xfd, 0x9b, 0xfc, 0x29, 0xe9, 0x62, 0xff, 0x7f, 0xe2, 0x34, 0xf3,
- 0xc5, 0x8b, 0xe8, 0x7c, 0x3e, 0x2c, 0x5f, 0x4e, 0xf9, 0xd2, 0xc5, 0x6d,
- 0x3c, 0x98, 0xc9, 0x6e, 0x34, 0x6b, 0x17, 0xff, 0xdc, 0x2c, 0xde, 0xfe,
- 0x2c, 0xe7, 0xde, 0x25, 0x8a, 0xc3, 0xea, 0x61, 0x9b, 0xbe, 0x75, 0x8b,
- 0xf4, 0xfb, 0x81, 0xfd, 0x62, 0xa5, 0x3b, 0x81, 0x8b, 0xe1, 0x8b, 0x3f,
- 0xc5, 0x08, 0xf3, 0x90, 0x10, 0xc5, 0xf1, 0x37, 0x70, 0x58, 0xbc, 0x07,
- 0xfa, 0xc5, 0xfe, 0x8f, 0x18, 0x6e, 0xe6, 0xac, 0x56, 0x1e, 0x8b, 0x8e,
- 0xdf, 0xda, 0x91, 0xc9, 0x44, 0xb1, 0x6e, 0x2c, 0x54, 0x67, 0x81, 0xf2,
- 0xeb, 0x04, 0x0a, 0xb3, 0xfb, 0x36, 0x04, 0x18, 0xc9, 0x06, 0x55, 0x91,
- 0x95, 0x75, 0x08, 0x5e, 0xc8, 0x62, 0x85, 0x46, 0x9b, 0xce, 0x41, 0xf9,
- 0xd2, 0x37, 0x84, 0x60, 0x21, 0x26, 0x50, 0x93, 0xe4, 0xa0, 0xff, 0x4a,
- 0x14, 0x13, 0x3e, 0xcb, 0xa0, 0x6c, 0x17, 0xb8, 0x7e, 0x2c, 0x5f, 0xe0,
- 0xac, 0xb7, 0xa1, 0x9c, 0x58, 0xbf, 0xfe, 0x6f, 0x36, 0x9c, 0x13, 0xf6,
- 0xea, 0x40, 0xb1, 0x74, 0x20, 0xb1, 0x7f, 0xf6, 0x14, 0xe1, 0xb3, 0x0f,
- 0x64, 0x6b, 0x17, 0xfe, 0x7f, 0xed, 0x9c, 0xf7, 0xd8, 0xeb, 0x17, 0xff,
- 0xf9, 0xbd, 0x3f, 0x2c, 0xf6, 0xa7, 0xe5, 0x9b, 0xc5, 0xd2, 0xc5, 0xff,
- 0xf4, 0xe7, 0xbe, 0xf0, 0xd0, 0x87, 0x25, 0x2b, 0x15, 0x04, 0xe6, 0xf7,
- 0x13, 0xfe, 0x30, 0x24, 0x4d, 0xe8, 0x1b, 0xac, 0x57, 0xc6, 0x3e, 0xb8,
- 0xb1, 0x7f, 0xf9, 0xbe, 0xed, 0x1f, 0x98, 0x98, 0x1c, 0x58, 0xbf, 0xe2,
- 0x98, 0x67, 0x31, 0xa5, 0x62, 0xd1, 0xac, 0x54, 0x9e, 0x49, 0x1b, 0x5f,
- 0xff, 0xf4, 0x80, 0xef, 0x0d, 0xbe, 0xfe, 0x1f, 0x3a, 0x9f, 0xc9, 0xd6,
- 0x2f, 0xff, 0x98, 0xbc, 0x2f, 0xb7, 0x36, 0x5f, 0xd8, 0x35, 0x8a, 0xfa,
- 0x2e, 0xfc, 0xd3, 0x7f, 0x34, 0x7b, 0x5c, 0x80, 0xb1, 0x7f, 0xff, 0xdf,
- 0x76, 0xe6, 0x1a, 0xe4, 0x0d, 0xb9, 0xb9, 0x24, 0xe6, 0xac, 0x5e, 0x77,
- 0xe9, 0x51, 0x6d, 0x15, 0x28, 0x94, 0xe9, 0xaa, 0xff, 0x89, 0x8d, 0xd6,
- 0x47, 0x3e, 0x58, 0xbf, 0xff, 0xa5, 0xfd, 0x3f, 0x9e, 0x33, 0x41, 0xb5,
- 0x83, 0x58, 0xbf, 0xbf, 0x27, 0x96, 0x1a, 0xc5, 0x32, 0x79, 0x31, 0x11,
- 0xea, 0x18, 0x87, 0x23, 0xe1, 0xd7, 0x96, 0x2f, 0xe7, 0x80, 0xfe, 0xc7,
- 0x58, 0xbf, 0xd9, 0x11, 0x49, 0xf6, 0xf4, 0xb1, 0x77, 0xd8, 0x67, 0xcb,
- 0xe2, 0xeb, 0xff, 0xdf, 0xc8, 0x39, 0x79, 0xe0, 0xc6, 0xca, 0xc5, 0xff,
- 0x66, 0x75, 0xb2, 0x2f, 0xb6, 0x96, 0x2f, 0xfe, 0xfe, 0x47, 0xc6, 0xd4,
- 0xee, 0xb9, 0x2c, 0x5d, 0x8c, 0xb1, 0x5d, 0x1e, 0xee, 0xf4, 0x7b, 0xde,
- 0x03, 0x2c, 0x5f, 0xd3, 0xb1, 0xf2, 0x3c, 0x31, 0x62, 0xa4, 0xfd, 0xf0,
- 0x97, 0x43, 0xb6, 0xd8, 0x96, 0x2f, 0xe3, 0x5b, 0xc4, 0xfd, 0xac, 0x5f,
- 0xfb, 0xd2, 0x72, 0x73, 0x4b, 0x00, 0xb1, 0x52, 0x7d, 0xb8, 0x5f, 0x60,
- 0x2c, 0x54, 0x48, 0xb6, 0x28, 0x42, 0x78, 0x82, 0xff, 0xcc, 0x43, 0x99,
- 0x3e, 0xeb, 0xc1, 0x62, 0xff, 0xa4, 0x1f, 0x98, 0xcb, 0x38, 0xb1, 0x52,
- 0x7f, 0x22, 0x40, 0xbf, 0xfc, 0xda, 0x9c, 0xf8, 0x9b, 0x9f, 0xc0, 0x2c,
- 0x5f, 0xff, 0x0c, 0x5e, 0xe0, 0xf2, 0x1f, 0x9d, 0xe3, 0x95, 0x8a, 0x1a,
- 0x27, 0x19, 0x26, 0xdb, 0x12, 0xc5, 0xff, 0x4c, 0x27, 0x51, 0xce, 0xa3,
- 0x58, 0xbf, 0xfd, 0x30, 0xfc, 0x91, 0xa5, 0x91, 0x87, 0x05, 0x8b, 0xff,
- 0xfd, 0x2c, 0x4f, 0xe1, 0x7b, 0x07, 0x27, 0x1f, 0xe7, 0xb5, 0x8b, 0xfc,
- 0xc7, 0x1c, 0xf0, 0x3e, 0x2c, 0x5e, 0xf6, 0x74, 0xb1, 0x7f, 0xfc, 0x4d,
- 0xbd, 0xbd, 0xf9, 0xf7, 0x27, 0x7c, 0xac, 0x53, 0x26, 0xa3, 0xa4, 0xcf,
- 0xb0, 0x78, 0xd4, 0x43, 0xd7, 0xf8, 0x78, 0x50, 0x6f, 0x89, 0x62, 0xc3,
- 0x58, 0xbf, 0x85, 0xd7, 0xe7, 0x58, 0xb1, 0x7b, 0xbe, 0x7d, 0x62, 0xb0,
- 0xf3, 0x9c, 0xbe, 0x99, 0x16, 0x6e, 0x67, 0xc6, 0x0b, 0xff, 0xbc, 0xed,
- 0x93, 0xa7, 0x83, 0x7d, 0x62, 0xfc, 0xe3, 0xc2, 0x02, 0xc5, 0x40, 0xfa,
- 0x59, 0x0a, 0xff, 0xa7, 0x5b, 0x79, 0x3f, 0x76, 0x58, 0xbf, 0x99, 0xe1,
- 0xe6, 0x8d, 0x62, 0xfa, 0x39, 0xfb, 0x2c, 0x57, 0xcf, 0x45, 0xcb, 0xaf,
- 0xa7, 0x09, 0x96, 0x2f, 0xbd, 0x38, 0x35, 0x8a, 0x19, 0xe1, 0x76, 0x41,
- 0x7b, 0xd9, 0x1a, 0xc5, 0x6c, 0x4c, 0xee, 0xa0, 0xa8, 0xf4, 0xc7, 0xa5,
- 0x1b, 0x04, 0x09, 0x07, 0x09, 0x2c, 0x95, 0x49, 0xd4, 0x30, 0x98, 0xb6,
- 0x24, 0x9d, 0x46, 0x22, 0x78, 0x71, 0xfe, 0x15, 0xcf, 0x0b, 0xd0, 0x11,
- 0x10, 0xbf, 0x23, 0x8c, 0xf4, 0x3f, 0x45, 0x09, 0x73, 0x08, 0x76, 0x61,
- 0x16, 0x1b, 0x1e, 0xe9, 0x1d, 0xec, 0xc3, 0x56, 0x2f, 0xe9, 0x87, 0x1f,
- 0x3a, 0x58, 0xba, 0x42, 0x68, 0xf2, 0xfe, 0x3b, 0x7f, 0xd3, 0xa7, 0xf0,
- 0x03, 0x28, 0x2c, 0x5f, 0xc2, 0x72, 0x2c, 0x02, 0xc5, 0xff, 0xfd, 0xa9,
- 0xf3, 0x74, 0xc3, 0x96, 0xd3, 0x41, 0xb8, 0xb1, 0x7f, 0x1a, 0xfa, 0x18,
- 0x89, 0x62, 0xfc, 0xc7, 0x7f, 0x4a, 0xc5, 0xfe, 0xf3, 0x74, 0xc3, 0xec,
- 0x96, 0x2f, 0xe9, 0x3e, 0x0b, 0x0e, 0xb1, 0x52, 0x7c, 0x4c, 0x6b, 0x7f,
- 0xff, 0xff, 0xe1, 0x94, 0xf5, 0xdf, 0x4d, 0xd9, 0xdc, 0x8d, 0xc2, 0x7e,
- 0xcc, 0xeb, 0xed, 0x11, 0x31, 0xf8, 0xb1, 0x7d, 0xe0, 0xf3, 0x75, 0x62,
- 0xff, 0xcd, 0xe9, 0xf3, 0x6f, 0x92, 0xe9, 0x62, 0xee, 0xe0, 0xb1, 0x58,
- 0x99, 0x03, 0x42, 0x81, 0xc9, 0xc4, 0x81, 0x7d, 0xae, 0xc5, 0x1a, 0xc5,
- 0xfb, 0x65, 0xb5, 0x86, 0xac, 0x56, 0x1e, 0x91, 0x13, 0x5d, 0xef, 0xac,
- 0x5f, 0xf6, 0x7b, 0x81, 0xf3, 0xd9, 0xf5, 0x8a, 0x8c, 0xf4, 0xce, 0x31,
- 0x78, 0xf3, 0xd2, 0xc5, 0xf1, 0x49, 0xf8, 0xb1, 0x66, 0x8c, 0xf0, 0x3c,
- 0x3d, 0x7e, 0x7e, 0xe0, 0x1f, 0x16, 0x2f, 0xfc, 0xd1, 0x73, 0x7b, 0x94,
- 0x62, 0x1a, 0xc5, 0x82, 0x46, 0xb9, 0x6c, 0x33, 0xac, 0x2c, 0x35, 0x6a,
- 0x22, 0xfd, 0x42, 0x27, 0xf1, 0xa0, 0x14, 0x24, 0xb8, 0xe7, 0xe6, 0x3d,
- 0xe5, 0x01, 0x95, 0xd0, 0x45, 0xf7, 0xcc, 0x8f, 0x4c, 0x13, 0x9c, 0xb7,
- 0x1f, 0xeb, 0x17, 0xed, 0x74, 0xef, 0xd2, 0xa2, 0xe5, 0x2f, 0xe7, 0x1f,
- 0xe4, 0xa3, 0x58, 0xb8, 0xdf, 0xac, 0x5e, 0x97, 0x3a, 0xc5, 0x82, 0x0d,
- 0x16, 0x58, 0x31, 0xf3, 0x77, 0x2e, 0x21, 0x9b, 0x98, 0xeb, 0x17, 0x31,
- 0xab, 0x17, 0xed, 0x74, 0xef, 0xd2, 0xa2, 0xed, 0x2f, 0x47, 0x86, 0x2c,
- 0x5e, 0x06, 0xf7, 0x58, 0xbf, 0xe6, 0x84, 0x18, 0x81, 0x30, 0x58, 0xb8,
- 0xfb, 0x2b, 0x17, 0xfd, 0xe9, 0x26, 0x06, 0xcb, 0xc6, 0xb1, 0x7b, 0x4e,
- 0x05, 0x8a, 0xc3, 0xd9, 0x63, 0xcb, 0xcf, 0x1c, 0xac, 0x58, 0x24, 0xa7,
- 0x1a, 0x31, 0x7c, 0x18, 0x39, 0xbf, 0xc7, 0xdc, 0x7c, 0x8e, 0x38, 0xe8,
- 0x22, 0x0a, 0x98, 0x58, 0x06, 0x46, 0x55, 0x0a, 0xe3, 0x9c, 0x72, 0xbf,
- 0xb1, 0x28, 0xdb, 0x44, 0x98, 0xd7, 0x8b, 0x03, 0xb9, 0x0c, 0x8f, 0xd6,
- 0x02, 0xc5, 0x5b, 0xda, 0xf2, 0x1e, 0x9e, 0x8f, 0x72, 0xff, 0x04, 0xcd,
- 0x74, 0xef, 0xd2, 0xa2, 0xa7, 0x2f, 0xf6, 0xbc, 0xde, 0x8c, 0x5c, 0x58,
- 0xbb, 0x9c, 0x58, 0xb0, 0x4c, 0x3c, 0xed, 0x1b, 0x5f, 0xe0, 0x9c, 0x1e,
- 0x60, 0x38, 0xb1, 0x44, 0x7b, 0xfb, 0xca, 0x6f, 0xfe, 0x6d, 0xf3, 0xf6,
- 0x98, 0xa2, 0x9e, 0x96, 0x2e, 0x8f, 0x16, 0x2f, 0xb8, 0x5f, 0xf2, 0xc5,
- 0xfe, 0xfc, 0xf2, 0x4e, 0x28, 0x96, 0x2f, 0x85, 0x09, 0x8d, 0x62, 0xff,
- 0xbb, 0x87, 0x36, 0xe6, 0xf7, 0xd2, 0xc5, 0x41, 0x17, 0x63, 0x23, 0xd1,
- 0xaf, 0xc9, 0x2f, 0xe1, 0x76, 0x77, 0x72, 0x58, 0xb7, 0x96, 0x2f, 0xbb,
- 0xe4, 0x8d, 0x62, 0xc2, 0x58, 0xbd, 0x2f, 0x1e, 0xd3, 0x6c, 0x02, 0x4a,
- 0x63, 0xfc, 0x24, 0x8b, 0xee, 0x9d, 0xfa, 0x54, 0x57, 0x25, 0xc7, 0x95,
- 0x8b, 0xf6, 0xba, 0x77, 0xe9, 0x51, 0x67, 0x17, 0xfe, 0x35, 0xbb, 0xe1,
- 0x61, 0x8e, 0x05, 0x8b, 0x04, 0x94, 0x47, 0xe0, 0xbf, 0x8d, 0xee, 0x78,
- 0x2c, 0x5f, 0xd0, 0xf7, 0x7d, 0x37, 0x16, 0x29, 0xcf, 0x20, 0x42, 0xf7,
- 0xf3, 0x73, 0x09, 0xcc, 0x58, 0xbc, 0x28, 0x4a, 0xc5, 0x69, 0x3a, 0x9f,
- 0xc3, 0x00, 0x9f, 0xbc, 0x43, 0xbc, 0xb6, 0xff, 0xf4, 0x3e, 0x2d, 0x60,
- 0xe7, 0x77, 0xed, 0xd2, 0xc5, 0xff, 0xef, 0x4f, 0x36, 0x8b, 0x9e, 0x98,
- 0xa2, 0x65, 0x8b, 0xff, 0xf3, 0xff, 0x0f, 0x27, 0xdb, 0x98, 0x69, 0xaf,
- 0x05, 0x8b, 0xf9, 0x8f, 0x18, 0xb5, 0x05, 0x8b, 0xf1, 0xf2, 0x27, 0x02,
- 0xc5, 0xf4, 0x7f, 0x7f, 0x2c, 0x53, 0x9e, 0x68, 0x8a, 0x6f, 0x8f, 0xb0,
- 0x05, 0x7c, 0xb1, 0x7e, 0x98, 0xa2, 0x9e, 0x96, 0x2e, 0x9f, 0xed, 0x3d,
- 0x86, 0x2d, 0xac, 0x4f, 0x2e, 0x24, 0xff, 0xac, 0x13, 0xee, 0xf7, 0x9b,
- 0xfe, 0x29, 0x3f, 0x05, 0x07, 0x35, 0x62, 0xfd, 0xac, 0xf3, 0x1d, 0x62,
- 0xe3, 0xef, 0x58, 0xbc, 0x52, 0x35, 0x8a, 0xc3, 0x6c, 0xe3, 0x57, 0x7f,
- 0x16, 0x2f, 0xd9, 0x14, 0x42, 0x8d, 0x62, 0xb0, 0xf0, 0xfe, 0x2f, 0x7f,
- 0xcd, 0xd6, 0xde, 0x44, 0x4e, 0x62, 0xc5, 0x1a, 0x7b, 0xff, 0x21, 0xbf,
- 0x45, 0x27, 0x90, 0xd6, 0x2f, 0xff, 0xfb, 0x4d, 0xc0, 0x66, 0xd6, 0xdf,
- 0x3f, 0x69, 0x8a, 0x29, 0xe9, 0x62, 0xe8, 0x1d, 0x62, 0xa5, 0x1a, 0x38,
- 0x46, 0xe5, 0x44, 0xd9, 0x7e, 0x3c, 0x9f, 0x09, 0x62, 0xf0, 0x9f, 0x8b,
- 0x17, 0xf8, 0x36, 0x8a, 0x78, 0xc7, 0x58, 0xbf, 0xfd, 0xf6, 0xdb, 0xf7,
- 0x6f, 0x4e, 0x0d, 0x96, 0x2f, 0xfc, 0xda, 0xdb, 0x27, 0x6d, 0xc7, 0x89,
- 0x62, 0xf6, 0xd6, 0xd2, 0xc5, 0xf7, 0x4e, 0xfd, 0x2a, 0x24, 0x22, 0xff,
- 0x4c, 0x35, 0x83, 0x73, 0xac, 0x51, 0xa8, 0xc7, 0x89, 0x13, 0x43, 0xfc,
- 0x31, 0xbf, 0xec, 0xf7, 0x05, 0x09, 0x8e, 0x56, 0x2f, 0xff, 0xcd, 0xae,
- 0xbf, 0x9b, 0x75, 0xac, 0x33, 0x66, 0x4e, 0xb1, 0x50, 0x44, 0xbf, 0x0e,
- 0xaf, 0xf4, 0x5f, 0x9e, 0x6d, 0x63, 0x56, 0x2f, 0xe7, 0x7e, 0xe1, 0xc6,
- 0x58, 0xbf, 0xc0, 0x9d, 0xc9, 0xf4, 0x8d, 0x62, 0xff, 0x8f, 0x8f, 0xa8,
- 0xf6, 0xf6, 0x75, 0x8a, 0x93, 0xf4, 0xc3, 0x6b, 0xff, 0x0f, 0x39, 0x26,
- 0x4b, 0x77, 0xc5, 0x8b, 0xfd, 0xdf, 0x3c, 0x52, 0x7e, 0x2c, 0x5f, 0xfe,
- 0x72, 0xeb, 0x68, 0xc9, 0xe1, 0xf7, 0x82, 0xc5, 0x32, 0x20, 0x44, 0x6b,
- 0x7f, 0x61, 0x30, 0x39, 0x2b, 0x15, 0x2b, 0x89, 0x10, 0x35, 0xc8, 0xc4,
- 0x7b, 0x86, 0xb3, 0x11, 0xe8, 0xe3, 0xf0, 0xa2, 0x72, 0x00, 0x43, 0x07,
- 0x84, 0x57, 0x16, 0x2c, 0x56, 0xd5, 0xd1, 0xb0, 0x93, 0x8c, 0xad, 0x0a,
- 0x0b, 0x9b, 0xeb, 0x17, 0xfe, 0x70, 0xe2, 0x26, 0xf1, 0x48, 0x16, 0x2a,
- 0x35, 0xdd, 0xb8, 0x4e, 0xa1, 0x76, 0x87, 0xe1, 0x7b, 0xff, 0x31, 0xf3,
- 0x9b, 0x7b, 0x86, 0x79, 0x62, 0xfb, 0x83, 0x1c, 0xac, 0x57, 0xcf, 0x97,
- 0xc8, 0x57, 0xd0, 0xf8, 0x7c, 0x58, 0xbf, 0xff, 0x80, 0x0d, 0x80, 0x51,
- 0x05, 0xbd, 0xdd, 0xe4, 0x16, 0xf6, 0xed, 0xfe, 0xca, 0xc5, 0xdb, 0x0b,
- 0x60, 0x58, 0xb8, 0xd0, 0x2c, 0x5f, 0xff, 0xbe, 0xd1, 0x7d, 0xbb, 0xf7,
- 0xfa, 0x6e, 0x60, 0xd6, 0x2f, 0xa5, 0x85, 0xc5, 0x8b, 0x04, 0xd8, 0x68,
- 0xb7, 0x92, 0x3e, 0x86, 0x7e, 0xb3, 0x52, 0x9e, 0x36, 0x11, 0x7c, 0x95,
- 0xe3, 0x34, 0xbd, 0xf9, 0x3a, 0xc5, 0xff, 0xfb, 0x01, 0x20, 0xd6, 0xa4,
- 0xcd, 0xba, 0x77, 0x82, 0xc5, 0x6c, 0x07, 0xea, 0x43, 0xb7, 0xee, 0x73,
- 0x35, 0x1a, 0xc5, 0xee, 0x49, 0xab, 0x15, 0xf3, 0xc8, 0xe1, 0x55, 0xd2,
- 0x62, 0xc5, 0xff, 0x03, 0x06, 0x4e, 0x09, 0xde, 0xb1, 0x7f, 0xd9, 0x1f,
- 0x1b, 0x0f, 0x3d, 0x2c, 0x56, 0x22, 0xb9, 0x88, 0x9c, 0x63, 0x87, 0x57,
- 0x8f, 0xbe, 0x0b, 0x17, 0xe9, 0xd6, 0xd0, 0x79, 0x62, 0xc1, 0xac, 0x5f,
- 0xfd, 0x20, 0x3b, 0xc3, 0x9e, 0xcc, 0x3a, 0xc5, 0x0c, 0xf5, 0xfe, 0x27,
- 0x7a, 0x23, 0xc4, 0xb1, 0x60, 0x9b, 0x1b, 0x68, 0x4a, 0x16, 0xd2, 0x26,
- 0x1a, 0x71, 0x9e, 0x8e, 0x15, 0x59, 0x1e, 0x4f, 0x6a, 0x2d, 0x28, 0x6a,
- 0x24, 0xcd, 0x1d, 0x1d, 0x7b, 0xf1, 0xc9, 0x3c, 0xf0, 0xa1, 0x4a, 0x75,
- 0xe4, 0x2d, 0xbd, 0x18, 0xe0, 0x8e, 0x8c, 0x20, 0x0e, 0x10, 0x5b, 0xa4,
- 0x57, 0xf8, 0x4f, 0xa8, 0x7c, 0xc7, 0x58, 0xbf, 0xff, 0xff, 0xa7, 0xc4,
- 0xe0, 0x27, 0xde, 0xdb, 0xc8, 0x5c, 0x0c, 0xa4, 0x7f, 0x78, 0x67, 0x16,
- 0x2f, 0xfc, 0x19, 0x48, 0xfe, 0xf0, 0xce, 0x2c, 0x5f, 0xf1, 0x48, 0xfe,
- 0xf0, 0xce, 0x2c, 0x5f, 0xe7, 0xde, 0xdb, 0xc8, 0x5c, 0xda, 0x7e, 0xe1,
- 0x9f, 0xde, 0xce, 0xc2, 0x0d, 0x38, 0x6d, 0x1a, 0x94, 0x60, 0x37, 0xff,
- 0x04, 0xfb, 0xf0, 0xb3, 0xde, 0x90, 0x2c, 0x5f, 0xfe, 0x08, 0x77, 0x80,
- 0x4c, 0xd7, 0x4e, 0xfd, 0x2a, 0x27, 0xc2, 0xff, 0xf4, 0x02, 0x66, 0xf6,
- 0x37, 0x9c, 0x93, 0x89, 0x62, 0xff, 0xb0, 0xcc, 0xde, 0xde, 0x84, 0xac,
- 0x5f, 0x0b, 0x53, 0xc5, 0x8b, 0xff, 0x77, 0xe8, 0xa0, 0xfa, 0x8f, 0xe2,
- 0x58, 0xbe, 0x3e, 0x67, 0x4b, 0x17, 0xb7, 0x8e, 0x56, 0x2f, 0x6c, 0xec,
- 0x66, 0x2c, 0x56, 0x1e, 0x36, 0xe8, 0xfd, 0xf8, 0xd7, 0xf6, 0x18, 0xb1,
- 0x7f, 0xa6, 0x30, 0xf6, 0x5c, 0x80, 0xb1, 0x60, 0x91, 0xa7, 0x22, 0x33,
- 0xbc, 0x23, 0x74, 0x42, 0x69, 0x11, 0x20, 0x65, 0x54, 0xea, 0x93, 0x7d,
- 0x1f, 0x0d, 0x74, 0xdd, 0xc3, 0xb4, 0x3c, 0x77, 0x2b, 0x44, 0x8d, 0x4a,
- 0xea, 0x3a, 0x57, 0xd1, 0x9e, 0x55, 0x55, 0xff, 0xe0, 0xb0, 0xd3, 0x37,
- 0x23, 0x1e, 0xc7, 0xb7, 0x6f, 0xf6, 0x56, 0x2f, 0xf1, 0x3f, 0xb8, 0x5c,
- 0xf2, 0xc5, 0xff, 0xfc, 0x22, 0x73, 0x76, 0xf8, 0xd9, 0x28, 0x67, 0xd8,
- 0xeb, 0x17, 0x37, 0x6b, 0x17, 0xff, 0xd0, 0x8c, 0x2c, 0x9d, 0x82, 0x3e,
- 0xb5, 0xb7, 0x6f, 0xf6, 0x56, 0x2a, 0x07, 0xfe, 0x01, 0x8b, 0x83, 0xe2,
- 0xc5, 0xff, 0xd1, 0xfe, 0x5b, 0xdc, 0x62, 0xee, 0x0b, 0x15, 0xf3, 0xdf,
- 0x21, 0x9b, 0xff, 0xb3, 0xcd, 0x85, 0xfc, 0xf4, 0x8d, 0x62, 0xff, 0xde,
- 0x36, 0x4a, 0x19, 0xf6, 0x3a, 0xc5, 0xff, 0x1b, 0x25, 0x0c, 0xfb, 0x1d,
- 0x62, 0xf8, 0x44, 0xe6, 0xed, 0x3f, 0x8f, 0x1f, 0xdf, 0xb4, 0x06, 0xfc,
- 0xac, 0x51, 0xcf, 0x8c, 0x47, 0x77, 0xec, 0xd6, 0x64, 0x4b, 0x16, 0x09,
- 0x05, 0x6f, 0xd8, 0xca, 0x73, 0x3f, 0xc3, 0x75, 0xe1, 0x02, 0x44, 0x3c,
- 0x8c, 0x74, 0x32, 0x2b, 0xf6, 0xba, 0x77, 0xe9, 0x51, 0x59, 0x17, 0xfe,
- 0x78, 0x04, 0xcd, 0x74, 0xef, 0xd2, 0xa2, 0x6e, 0x2c, 0x13, 0x11, 0x0c,
- 0x73, 0x7a, 0xe9, 0x33, 0x96, 0x8c, 0x3e, 0xff, 0x89, 0xc2, 0x72, 0x41,
- 0x32, 0xb1, 0x7b, 0x62, 0xef, 0xa5, 0x8b, 0xff, 0xe8, 0x37, 0xdc, 0xbd,
- 0x0c, 0xd6, 0x6c, 0x41, 0x45, 0x8b, 0xff, 0x0d, 0x88, 0x5d, 0x67, 0x36,
- 0x20, 0xa2, 0xc5, 0xff, 0xef, 0x37, 0xc5, 0xf7, 0x6e, 0xf9, 0x26, 0xac,
- 0x54, 0xa2, 0x57, 0x12, 0x6f, 0xba, 0x77, 0xe9, 0x51, 0x2b, 0x17, 0xff,
- 0xda, 0x8c, 0xa7, 0x4e, 0x32, 0x7d, 0x4e, 0xf5, 0x8a, 0xd2, 0x20, 0x84,
- 0x63, 0x7f, 0xce, 0xd0, 0x62, 0x14, 0x9d, 0x62, 0xfa, 0x46, 0xff, 0x58,
- 0xa5, 0x8b, 0xfc, 0xd0, 0x62, 0x14, 0x9d, 0x62, 0xfc, 0x4e, 0xdd, 0xf4,
- 0x73, 0x7c, 0xe1, 0x94, 0x48, 0x9d, 0xdd, 0x60, 0xbf, 0x98, 0xa6, 0x13,
- 0xba, 0xb1, 0x79, 0xa7, 0xcb, 0x15, 0x27, 0x97, 0xa2, 0xfb, 0xe1, 0x0f,
- 0x0d, 0x58, 0xbc, 0xf0, 0x09, 0xb0, 0x95, 0xb0, 0xc9, 0x28, 0xe1, 0xdb,
- 0x90, 0xa3, 0xe8, 0x8d, 0xa1, 0xa9, 0xc7, 0x0d, 0x92, 0x1a, 0xe9, 0x70,
- 0xd8, 0xf2, 0xe6, 0xaf, 0xc1, 0x1e, 0x2e, 0x62, 0xc5, 0xf8, 0x26, 0x42,
- 0x40, 0xb1, 0x41, 0x11, 0x07, 0x19, 0x74, 0x0a, 0xef, 0xfd, 0xec, 0x09,
- 0x9a, 0x68, 0xdc, 0xeb, 0x17, 0xf0, 0x55, 0xcf, 0xa9, 0xe2, 0xc5, 0xff,
- 0xed, 0x88, 0x28, 0x15, 0xe6, 0x3c, 0x1b, 0x35, 0x8b, 0x17, 0xfe, 0x6e,
- 0x08, 0xe4, 0xdb, 0xc4, 0xeb, 0x17, 0xff, 0xdf, 0x98, 0x30, 0x35, 0x9f,
- 0x72, 0x78, 0x2c, 0x5f, 0xd2, 0x4f, 0xd3, 0xee, 0x2c, 0x5f, 0x0b, 0x74,
- 0x72, 0xb1, 0x7f, 0xff, 0x9f, 0xbf, 0xe7, 0x27, 0x9c, 0x7f, 0xcf, 0x7f,
- 0x63, 0xac, 0x5f, 0xf4, 0xf5, 0x3a, 0x6f, 0x4f, 0x4b, 0x15, 0x04, 0xe0,
- 0x3b, 0x40, 0x3a, 0x77, 0xcc, 0x08, 0x9b, 0xcc, 0x56, 0xd2, 0xc5, 0xff,
- 0x81, 0xec, 0xfc, 0x97, 0xb6, 0x71, 0x62, 0x86, 0x7a, 0x62, 0x12, 0xbf,
- 0xfe, 0xfb, 0x83, 0x98, 0x4f, 0x06, 0x1e, 0x1d, 0x62, 0xe3, 0x92, 0xc5,
- 0xfc, 0x59, 0xd7, 0xdb, 0x4b, 0x03, 0x2d, 0xef, 0xba, 0x77, 0xe9, 0x51,
- 0x2e, 0x17, 0xff, 0x36, 0xbe, 0xfc, 0x98, 0x60, 0xa0, 0xb1, 0x7f, 0xfd,
- 0xfc, 0x1c, 0xfe, 0x60, 0x53, 0xa7, 0x1a, 0xc5, 0x0d, 0x36, 0x56, 0x65,
- 0xd1, 0xef, 0xcc, 0x78, 0x89, 0x78, 0x9c, 0xeb, 0x16, 0x8d, 0x62, 0xf4,
- 0x33, 0xce, 0x6b, 0xf7, 0x47, 0x2f, 0x1b, 0x06, 0x58, 0xbf, 0xcf, 0x0f,
- 0x14, 0x9f, 0x8b, 0x17, 0xfe, 0xe0, 0x8d, 0xe6, 0x1d, 0xbf, 0x2b, 0x17,
- 0xb5, 0x3f, 0x58, 0xa6, 0x3d, 0xdd, 0x20, 0x53, 0x22, 0xc5, 0xe1, 0x21,
- 0x7e, 0x86, 0xcb, 0x7d, 0xd6, 0x2e, 0xd9, 0x95, 0x8b, 0xff, 0x8a, 0x0e,
- 0x37, 0x98, 0x49, 0x3a, 0xc5, 0x49, 0xed, 0xe0, 0xd5, 0xf8, 0xa7, 0xa7,
- 0xd2, 0xc5, 0xff, 0xfd, 0x82, 0xeb, 0xf2, 0x53, 0x07, 0x1c, 0xf7, 0xa6,
- 0x58, 0xbf, 0xf7, 0x18, 0x85, 0xed, 0x96, 0xde, 0x75, 0x8b, 0xff, 0xff,
- 0xe2, 0xcf, 0x73, 0x06, 0xe3, 0x92, 0x7e, 0xff, 0x9c, 0x9e, 0x71, 0xfe,
- 0xb1, 0x79, 0x8a, 0x56, 0x2f, 0xf8, 0x46, 0xb9, 0xb9, 0x1e, 0x46, 0xb1,
- 0x50, 0x54, 0x80, 0x38, 0x43, 0x31, 0x06, 0xe1, 0x41, 0xd6, 0xc9, 0x13,
- 0x7b, 0xde, 0xc8, 0xdd, 0xfb, 0xed, 0xa7, 0xe2, 0xc5, 0xff, 0xa4, 0x80,
- 0xe3, 0x9d, 0xc7, 0xd2, 0xc5, 0xb3, 0xc7, 0xd1, 0xba, 0x51, 0x7f, 0x6f,
- 0x92, 0xe9, 0xf8, 0xb1, 0x7f, 0xf1, 0x4c, 0x30, 0x79, 0x0c, 0x20, 0x2c,
- 0x5b, 0xd2, 0x7e, 0x4c, 0x61, 0x7c, 0x00, 0x37, 0x6b, 0x17, 0xe1, 0x1a,
- 0x58, 0x05, 0x8b, 0xfe, 0x7d, 0x1a, 0x59, 0xef, 0xb2, 0xc5, 0x32, 0x21,
- 0x8e, 0x48, 0x45, 0x37, 0xfd, 0x3f, 0x76, 0x83, 0x1b, 0x2b, 0x17, 0xff,
- 0x10, 0xa1, 0xf7, 0x86, 0x77, 0x09, 0x58, 0xbf, 0xf8, 0x50, 0x26, 0x84,
- 0xf8, 0x85, 0x05, 0x8b, 0xf4, 0xf0, 0x07, 0xf2, 0xc5, 0x31, 0xf6, 0xfd,
- 0x12, 0x86, 0x98, 0x5f, 0x0e, 0x3d, 0x0b, 0x2b, 0x74, 0xb1, 0x52, 0xa8,
- 0xbb, 0x21, 0x58, 0xf1, 0x9c, 0x80, 0xda, 0xfe, 0x87, 0xf0, 0xb3, 0xa5,
- 0x8b, 0xd0, 0xff, 0x96, 0x29, 0x8f, 0x33, 0xe5, 0xd7, 0xdd, 0xfe, 0x7a,
- 0x58, 0xb7, 0xe4, 0xf1, 0x9c, 0x86, 0xff, 0xe2, 0x60, 0x73, 0x52, 0xd0,
- 0x7e, 0x2c, 0x5f, 0xcf, 0xd8, 0x1d, 0xf4, 0xb1, 0x58, 0x89, 0x76, 0x26,
- 0xe2, 0x1d, 0xe6, 0x8c, 0x2e, 0xb1, 0x7e, 0x63, 0x93, 0xc1, 0x62, 0xb7,
- 0x0f, 0x27, 0x44, 0x57, 0xff, 0x09, 0xf7, 0x1a, 0x3c, 0xfb, 0x77, 0xc5,
- 0x8b, 0xff, 0x77, 0x0c, 0xf6, 0x6b, 0xa9, 0xc5, 0x8b, 0xcf, 0x00, 0x9b,
- 0x03, 0x39, 0x87, 0x61, 0x19, 0x4c, 0x7a, 0xd0, 0x85, 0x5e, 0x47, 0x0f,
- 0xdb, 0xce, 0x8d, 0x3f, 0x0c, 0xf7, 0x94, 0xcc, 0x50, 0xe6, 0xe4, 0xac,
- 0xaf, 0x46, 0xe0, 0x27, 0x7d, 0x92, 0x5d, 0xd4, 0x9b, 0xff, 0x08, 0xe1,
- 0x39, 0x25, 0xec, 0xd2, 0xc5, 0xff, 0xfb, 0x3e, 0x13, 0x93, 0xe9, 0xdf,
- 0x25, 0xd3, 0xf1, 0x62, 0xff, 0x87, 0x81, 0x27, 0x4d, 0xf1, 0x2c, 0x5f,
- 0xfc, 0x39, 0x09, 0xbb, 0x9d, 0xc3, 0xf3, 0xc5, 0x8b, 0x04, 0x66, 0xc3,
- 0x88, 0xf4, 0xea, 0x2e, 0x46, 0x41, 0xe4, 0x11, 0x2c, 0xef, 0x3b, 0xbf,
- 0xf8, 0x23, 0xc0, 0x26, 0x6b, 0xa7, 0x7e, 0x95, 0x11, 0xd9, 0x7f, 0xfc,
- 0x29, 0xee, 0x0c, 0x73, 0x30, 0x87, 0xf9, 0x58, 0xbf, 0xff, 0xf8, 0xf3,
- 0xd7, 0x5f, 0x68, 0xbe, 0xc4, 0x37, 0xd4, 0x9a, 0x68, 0xa3, 0x58, 0xb8,
- 0x41, 0xac, 0x5f, 0x13, 0xbf, 0x6b, 0x17, 0xdd, 0xf9, 0x8c, 0x58, 0xa9,
- 0x3c, 0x73, 0x91, 0x5d, 0x18, 0x41, 0xa6, 0x95, 0x8a, 0x27, 0x78, 0x0d,
- 0x82, 0xff, 0xff, 0x38, 0x02, 0x07, 0x31, 0xe7, 0xa4, 0x98, 0x19, 0xdf,
- 0x96, 0x2f, 0xdc, 0x6d, 0xff, 0xde, 0xb1, 0x71, 0x71, 0x62, 0xfb, 0xf9,
- 0x00, 0x92, 0x78, 0x8e, 0x5b, 0x58, 0x99, 0x74, 0x49, 0xbe, 0x85, 0x45,
- 0xe0, 0xae, 0xd1, 0xac, 0x5f, 0xf0, 0x57, 0x67, 0x0d, 0x6f, 0x14, 0xac,
- 0x5f, 0xdb, 0x19, 0x4f, 0x58, 0x4b, 0x17, 0x0b, 0xeb, 0x17, 0xf0, 0x54,
- 0xb3, 0xef, 0xe5, 0x8b, 0x18, 0xb1, 0x7d, 0x87, 0xd4, 0xac, 0x5f, 0xb0,
- 0x98, 0x01, 0xac, 0x51, 0x1e, 0x57, 0x08, 0xaf, 0x66, 0xa5, 0x62, 0xff,
- 0x7e, 0x63, 0xd4, 0xe0, 0xd6, 0x2f, 0x6e, 0x8e, 0x56, 0x2a, 0x4f, 0x50,
- 0x46, 0x97, 0xff, 0xe8, 0x30, 0xfe, 0xdb, 0xf6, 0xe0, 0xf4, 0xc2, 0xe9,
- 0x62, 0xfa, 0x75, 0x3a, 0x58, 0xad, 0x8d, 0x38, 0xc6, 0x5d, 0xd1, 0x0f,
- 0xdc, 0x3c, 0x42, 0x1a, 0xdd, 0xe8, 0xa6, 0x35, 0x8b, 0xe9, 0x2f, 0x71,
- 0x62, 0xec, 0x32, 0x4f, 0x07, 0x83, 0xf7, 0xfe, 0xe7, 0xb3, 0xf2, 0x5e,
- 0xfb, 0x2c, 0x5f, 0xef, 0x72, 0x62, 0x77, 0xd2, 0xc5, 0xff, 0x4e, 0x79,
- 0x9e, 0x39, 0xd2, 0xc5, 0xc1, 0x9d, 0x62, 0xb1, 0x18, 0x6c, 0x7c, 0x03,
- 0x4f, 0x1c, 0x5d, 0xb1, 0x71, 0x62, 0xfe, 0x01, 0x67, 0x7e, 0xc5, 0x8b,
- 0xa3, 0xdc, 0x58, 0xbf, 0xfb, 0x7c, 0x8f, 0xd9, 0x2d, 0xe9, 0x89, 0x62,
- 0xf8, 0xdf, 0xe0, 0x16, 0x2f, 0xe7, 0x33, 0x3d, 0x3d, 0x2c, 0x53, 0x9e,
- 0x99, 0x12, 0x5f, 0xff, 0xfc, 0xe6, 0xce, 0x80, 0x29, 0xcc, 0xff, 0x4d,
- 0x25, 0x39, 0xf1, 0x2c, 0x5f, 0xc4, 0x07, 0xd3, 0x86, 0xb1, 0x7f, 0xfd,
- 0x3e, 0x9f, 0x6d, 0xf7, 0xf0, 0x9f, 0x46, 0xac, 0x56, 0xc0, 0xa8, 0x42,
- 0x47, 0x63, 0x2e, 0x61, 0xcd, 0x42, 0x67, 0xe4, 0x0e, 0xe0, 0x45, 0xd7,
- 0xff, 0xdf, 0xda, 0x58, 0xda, 0x68, 0xdc, 0xe7, 0x65, 0x8b, 0xff, 0xff,
- 0xbe, 0xe3, 0x27, 0xdb, 0xcf, 0xcf, 0x36, 0x89, 0xf6, 0xc3, 0x37, 0xca,
- 0xc5, 0xff, 0x1b, 0xb7, 0x18, 0xdd, 0x67, 0x16, 0x2b, 0xe8, 0xb6, 0x27,
- 0x9b, 0xff, 0xc5, 0x86, 0xfd, 0xe1, 0xf3, 0x1c, 0x33, 0xac, 0x54, 0x9f,
- 0x7e, 0x11, 0x53, 0x27, 0x2d, 0xf8, 0xdd, 0xaf, 0xda, 0xd4, 0xef, 0xe2,
- 0xc5, 0xff, 0x9b, 0x5b, 0x78, 0x58, 0x79, 0xe9, 0x62, 0xff, 0x0b, 0xcc,
- 0xfb, 0xde, 0x0b, 0x17, 0xf8, 0xa4, 0x1b, 0x7e, 0xe7, 0x58, 0xbf, 0x9f,
- 0x78, 0xf0, 0x8d, 0x58, 0xb4, 0x92, 0x26, 0xbc, 0x6a, 0x19, 0xad, 0xff,
- 0xff, 0xc0, 0x92, 0xe9, 0xfc, 0xfd, 0x83, 0x6e, 0x13, 0x48, 0xbf, 0xf9,
- 0x58, 0xbf, 0xf1, 0x0a, 0x1b, 0x71, 0x8a, 0x4e, 0xb1, 0x7f, 0x72, 0x0d,
- 0xd3, 0xe9, 0x62, 0xf3, 0xbf, 0x4a, 0x8a, 0x84, 0xbf, 0xfc, 0xdb, 0xf1,
- 0x8b, 0x35, 0x3d, 0x4e, 0x96, 0x2c, 0x75, 0x8b, 0xd8, 0x2f, 0x11, 0xee,
- 0x09, 0x2a, 0xff, 0x38, 0x26, 0x2f, 0x88, 0x0b, 0x15, 0x29, 0x8e, 0x74,
- 0x5f, 0xa8, 0x43, 0x08, 0xca, 0xfe, 0x98, 0xa0, 0x2e, 0xe0, 0xb1, 0x7f,
- 0xc0, 0xe6, 0xde, 0x01, 0xf2, 0x25, 0x8b, 0xfb, 0x75, 0xc8, 0x61, 0xf6,
- 0xb1, 0x4c, 0x7e, 0x0e, 0x7b, 0x7f, 0x0b, 0xa6, 0x35, 0xfa, 0x58, 0xbe,
- 0xd7, 0x42, 0x02, 0xc5, 0xfd, 0x84, 0xfa, 0xd3, 0x2c, 0x53, 0x1e, 0x8f,
- 0xc9, 0x6f, 0xd2, 0x42, 0x78, 0xd6, 0x2b, 0x0f, 0x27, 0x84, 0x37, 0xe9,
- 0x8c, 0xa6, 0x35, 0x8b, 0xff, 0xd2, 0x66, 0xdc, 0xde, 0xde, 0x9c, 0x28,
- 0x2c, 0x5f, 0xb3, 0xa7, 0x23, 0x56, 0x2a, 0x0b, 0xb8, 0x38, 0x52, 0x69,
- 0x5f, 0x50, 0xdb, 0xec, 0xd5, 0x9c, 0xf5, 0x1a, 0xd9, 0xd0, 0xff, 0x0a,
- 0x12, 0x20, 0xe4, 0x32, 0xfc, 0x43, 0xbc, 0xa4, 0x34, 0xdb, 0xdb, 0x8f,
- 0x2b, 0x16, 0xc5, 0x8b, 0xff, 0xe6, 0x3c, 0xf5, 0xb7, 0xaf, 0xb6, 0xec,
- 0x9e, 0x56, 0x2f, 0xfe, 0x13, 0xc7, 0xcc, 0x6e, 0xba, 0xcd, 0xeb, 0x15,
- 0x04, 0x58, 0x7c, 0x44, 0x95, 0xaf, 0xf7, 0x9b, 0x4f, 0xd3, 0x12, 0xc5,
- 0xff, 0xfe, 0x9d, 0x1b, 0xb7, 0x84, 0x2c, 0xf4, 0xc1, 0x87, 0xf6, 0x58,
- 0xa8, 0x22, 0x5b, 0x86, 0x77, 0x81, 0xcc, 0x58, 0xbf, 0xdc, 0x14, 0x4e,
- 0x37, 0x89, 0x62, 0xff, 0xfe, 0xe1, 0x8f, 0xbb, 0xc6, 0xd4, 0x5c, 0x93,
- 0xbf, 0x7e, 0x58, 0xbf, 0xa7, 0xa6, 0x29, 0x82, 0xc5, 0xb6, 0x56, 0x2f,
- 0xfb, 0x6c, 0xb1, 0x61, 0xf5, 0x2b, 0x15, 0x04, 0xcc, 0x3b, 0x1d, 0x88,
- 0xd8, 0xec, 0x40, 0x2d, 0xe0, 0xad, 0xf8, 0xa3, 0x04, 0x86, 0xb1, 0x7f,
- 0x43, 0x72, 0x7d, 0x24, 0xb1, 0x58, 0x7b, 0x5b, 0xa5, 0x57, 0xf4, 0xee,
- 0x1e, 0x5b, 0x4b, 0x15, 0x27, 0xa9, 0x02, 0x4b, 0xf4, 0x0a, 0x4e, 0x6a,
- 0xc5, 0xff, 0xc7, 0xcd, 0x16, 0x36, 0xf6, 0xd3, 0xac, 0x5f, 0xcd, 0xd3,
- 0x0f, 0xa3, 0xac, 0x57, 0x68, 0x9d, 0x72, 0x9f, 0x22, 0x5f, 0xff, 0x9b,
- 0x5b, 0x73, 0xc2, 0x9c, 0x8f, 0xf8, 0xd0, 0x58, 0xbf, 0xf1, 0x64, 0x5e,
- 0xfe, 0x69, 0xb8, 0xb1, 0x7f, 0xe3, 0xed, 0x3b, 0xfb, 0x6f, 0xfd, 0xa5,
- 0x8b, 0xfd, 0x27, 0xc6, 0xd0, 0xb7, 0x16, 0x29, 0xcf, 0xec, 0x48, 0xb5,
- 0xf4, 0x6d, 0x94, 0x2e, 0xaf, 0xdd, 0x93, 0x1d, 0x96, 0x2f, 0x47, 0x86,
- 0x2c, 0x5e, 0xcd, 0x7d, 0x62, 0xd3, 0xb1, 0x9b, 0xce, 0x87, 0xef, 0xb6,
- 0x45, 0xbb, 0x2b, 0x15, 0x2a, 0x90, 0x86, 0x61, 0x91, 0x99, 0x31, 0x3e,
- 0x99, 0x04, 0x59, 0x7f, 0x79, 0xff, 0xb4, 0x72, 0xb1, 0x7f, 0xde, 0xe0,
- 0x7c, 0x7e, 0xe1, 0x8b, 0x17, 0xf9, 0xe1, 0xb7, 0x82, 0x03, 0xac, 0x5f,
- 0x4f, 0xe6, 0x35, 0x8b, 0x30, 0xcf, 0x67, 0xe6, 0xd5, 0x28, 0xec, 0xc3,
- 0x01, 0x42, 0x56, 0xfd, 0xc6, 0xfe, 0x0d, 0x62, 0xfd, 0x09, 0xf6, 0x46,
- 0xb1, 0x5b, 0x87, 0xa3, 0xa2, 0x8b, 0xd3, 0xc8, 0xd6, 0x2e, 0xef, 0xcb,
- 0x17, 0x7b, 0x16, 0x2a, 0x4d, 0x87, 0x63, 0x37, 0xf7, 0x18, 0xba, 0xfc,
- 0xac, 0x56, 0x23, 0x0b, 0xa2, 0x5d, 0x27, 0x78, 0x86, 0xf9, 0xb6, 0x5b,
- 0xeb, 0x17, 0xfe, 0xcf, 0x73, 0x59, 0x17, 0xd8, 0xd5, 0x8b, 0xff, 0xfd,
- 0xc6, 0x10, 0x5f, 0xed, 0xb7, 0x3b, 0xf7, 0xc3, 0xe4, 0x72, 0xb1, 0x7f,
- 0xfe, 0xce, 0xb6, 0xff, 0x36, 0xf3, 0xc5, 0x80, 0xd9, 0xc5, 0x8b, 0x79,
- 0x91, 0x91, 0xc6, 0xbb, 0xff, 0xf9, 0xb8, 0x0c, 0x81, 0x48, 0x1f, 0xfd,
- 0xc3, 0x3c, 0xb1, 0x7f, 0xf7, 0x4d, 0xad, 0x3c, 0x1f, 0xa1, 0x76, 0xb1,
- 0x78, 0x0d, 0xf5, 0x8b, 0xfe, 0xc3, 0x70, 0xed, 0xb3, 0x27, 0x58, 0xa6,
- 0x4c, 0x93, 0x45, 0x1f, 0x5b, 0x02, 0x41, 0x0e, 0xdf, 0xf6, 0xd7, 0x2c,
- 0xdd, 0xdb, 0xf1, 0x2c, 0x5f, 0x8c, 0x6d, 0x61, 0xab, 0x15, 0x2a, 0xd0,
- 0xb0, 0xf5, 0x89, 0x5e, 0x51, 0x68, 0x92, 0x43, 0x40, 0xbf, 0xef, 0x37,
- 0x18, 0x41, 0x71, 0xca, 0xc5, 0xd3, 0xda, 0xc5, 0xfd, 0x3e, 0xc2, 0x7d,
- 0xc5, 0x8b, 0xf0, 0x36, 0x38, 0xf0, 0xc5, 0x8a, 0x64, 0x5a, 0x68, 0xf4,
- 0x03, 0x04, 0x5f, 0x76, 0xc6, 0x15, 0x58, 0xbf, 0xf3, 0x97, 0x5e, 0xcf,
- 0xfb, 0xc2, 0x58, 0xa6, 0x3e, 0x11, 0x10, 0xdf, 0xd3, 0xa8, 0xe7, 0x51,
- 0xac, 0x5f, 0x0a, 0x39, 0x82, 0xc5, 0x40, 0xf5, 0x38, 0x61, 0x7f, 0x8d,
- 0xdb, 0xa6, 0xef, 0xd8, 0xb1, 0x7f, 0xfd, 0xf9, 0x1e, 0xdf, 0xe6, 0xdc,
- 0xd3, 0xc3, 0x16, 0x2f, 0xfd, 0xcc, 0x2f, 0x73, 0x20, 0xdf, 0x58, 0xbf,
- 0xfd, 0x90, 0xc8, 0x9b, 0x58, 0x2e, 0x9c, 0x96, 0x2f, 0xd9, 0xbc, 0xa7,
- 0xb5, 0x8a, 0xf9, 0xfa, 0x71, 0x2a, 0xe1, 0x7d, 0x62, 0xa5, 0x37, 0x7e,
- 0x8e, 0x38, 0xa7, 0xe8, 0x59, 0x6c, 0x91, 0x5f, 0xff, 0x48, 0x30, 0xb6,
- 0xbf, 0xb6, 0xff, 0x00, 0xeb, 0x17, 0x14, 0x6b, 0x15, 0x2a, 0x95, 0xb2,
- 0x39, 0x96, 0x53, 0x25, 0x2b, 0xfc, 0x3c, 0x3e, 0xde, 0x3f, 0xd6, 0x2f,
- 0x0a, 0x78, 0xb1, 0x4c, 0x7a, 0x7f, 0x36, 0xbb, 0x90, 0x58, 0xbf, 0xfd,
- 0xf9, 0x39, 0x39, 0xa5, 0x80, 0xec, 0x0b, 0x17, 0xf6, 0xf7, 0x3f, 0xcc,
- 0x75, 0x8b, 0xff, 0xfc, 0xd3, 0xe7, 0xf8, 0x4e, 0x7f, 0x0b, 0xdb, 0x41,
- 0x0e, 0x2c, 0x5f, 0xf3, 0x13, 0x67, 0x53, 0xee, 0x2c, 0x54, 0x13, 0x19,
- 0x64, 0xb2, 0x31, 0xf3, 0x2d, 0xee, 0x0b, 0x4b, 0x17, 0xf8, 0x4f, 0xcc,
- 0xfb, 0x1d, 0x62, 0xf3, 0x7d, 0x96, 0x2f, 0xe9, 0x38, 0x57, 0x63, 0xcd,
- 0x2c, 0x5e, 0x3b, 0x71, 0x62, 0xfe, 0xd3, 0x90, 0x01, 0x2b, 0x15, 0x2a,
- 0x9f, 0x23, 0x21, 0xc8, 0xcc, 0x58, 0xf3, 0x43, 0xce, 0x66, 0x43, 0x82,
- 0x37, 0x0c, 0x76, 0xff, 0x16, 0x7b, 0x80, 0x6e, 0xd6, 0x2f, 0xc5, 0x83,
- 0x27, 0x58, 0xa8, 0x1e, 0xd6, 0x1a, 0x5f, 0x0a, 0x78, 0x4b, 0x17, 0x66,
- 0xf5, 0x8b, 0xf4, 0x9d, 0xfb, 0xf2, 0xc5, 0xd9, 0x1a, 0xc5, 0xff, 0xc3,
- 0xe6, 0x68, 0xb0, 0x1c, 0xcd, 0x2c, 0x57, 0xd1, 0x3d, 0xc1, 0x9f, 0x14,
- 0x88, 0x62, 0xfd, 0x9d, 0x09, 0xe3, 0x58, 0xae, 0x93, 0x27, 0xfc, 0x30,
- 0x08, 0xf6, 0xff, 0xfb, 0x44, 0x2e, 0xcb, 0x1b, 0x5d, 0x7e, 0x78, 0xb1,
- 0x7f, 0xff, 0x74, 0xff, 0xc8, 0x4e, 0xa4, 0x1a, 0x90, 0xdc, 0x96, 0x2f,
- 0xc0, 0xcf, 0xb0, 0xd6, 0x2a, 0x51, 0xa9, 0x8a, 0x2e, 0xb7, 0x7d, 0x1b,
- 0x96, 0xf5, 0x8b, 0xf8, 0x18, 0x5f, 0x11, 0x2c, 0x56, 0x1e, 0x93, 0x92,
- 0xdf, 0xff, 0xff, 0xd0, 0xdb, 0xef, 0xb4, 0xf3, 0x6e, 0x0b, 0xa9, 0xdf,
- 0xb7, 0x35, 0xac, 0xde, 0x27, 0xfa, 0xc5, 0xf7, 0xb6, 0x00, 0xae, 0xc4,
- 0xb1, 0x52, 0x8c, 0x6c, 0x84, 0xa5, 0xf7, 0xc9, 0xf7, 0x56, 0x2f, 0x8e,
- 0xdb, 0xb2, 0xb1, 0x52, 0xb8, 0x4f, 0x91, 0xa4, 0x7e, 0x30, 0xa2, 0x7f,
- 0xe4, 0x39, 0xbc, 0x4c, 0x22, 0x5b, 0xfc, 0xfd, 0xf1, 0x8f, 0x3d, 0x2c,
- 0x5f, 0x60, 0xcf, 0xc5, 0x8b, 0xd9, 0x9c, 0x58, 0xb6, 0x96, 0x2f, 0x7b,
- 0x0e, 0xb1, 0x52, 0x6b, 0xf0, 0x4a, 0xd1, 0x8c, 0xfa, 0x9d, 0x2e, 0xf0,
- 0x7b, 0x2e, 0xb1, 0x7f, 0xfe, 0x68, 0xfe, 0xed, 0xe9, 0xfb, 0x7b, 0x98,
- 0x35, 0x8b, 0xfe, 0xdb, 0x9f, 0x67, 0xf7, 0xe5, 0x62, 0xb7, 0x11, 0x1e,
- 0x4a, 0xb5, 0xf4, 0x6a, 0xbc, 0x2c, 0x29, 0xd3, 0x24, 0x14, 0x3f, 0x6f,
- 0xfd, 0xbd, 0xe1, 0x84, 0x32, 0x98, 0x2c, 0x5d, 0x1c, 0xac, 0x56, 0x1e,
- 0xb8, 0x8f, 0xef, 0xb3, 0xe7, 0x95, 0x8a, 0x23, 0xc3, 0xe1, 0x0d, 0xe6,
- 0x32, 0x25, 0x8b, 0xfe, 0x7f, 0xb7, 0x38, 0x27, 0x02, 0xc5, 0x0c, 0xf6,
- 0x1c, 0x7e, 0xc1, 0x02, 0x8e, 0xaf, 0xc7, 0x62, 0x24, 0x0a, 0xa0, 0x6c,
- 0x06, 0x5b, 0x18, 0xc4, 0xc7, 0x7b, 0x1c, 0x27, 0xa1, 0x0f, 0x01, 0xca,
- 0x4b, 0xc9, 0xfd, 0x13, 0x61, 0xb5, 0xd4, 0x33, 0xfb, 0x86, 0x2b, 0x46,
- 0xa7, 0x14, 0x61, 0x1a, 0x96, 0x00, 0x78, 0xd2, 0x3f, 0x39, 0x10, 0xf1,
- 0x88, 0x82, 0x13, 0x85, 0x2b, 0x2f, 0x92, 0xc4, 0x3d, 0x3a, 0x08, 0x27,
- 0x5d, 0xe6, 0xbb, 0x31, 0xd8, 0x87, 0x0c, 0x2d, 0xd7, 0x9b, 0xc4, 0xc6,
- 0x2c, 0x5f, 0x74, 0xef, 0xd2, 0xa2, 0xa8, 0x2f, 0xf6, 0xa7, 0x7f, 0x70,
- 0xcf, 0x2c, 0x56, 0x8f, 0xa0, 0x46, 0x37, 0xf8, 0xd9, 0xf7, 0x37, 0xe0,
- 0xd6, 0x2f, 0xe1, 0x68, 0x1e, 0x7e, 0xd6, 0x2f, 0xfb, 0x3c, 0xfd, 0xed,
- 0x8f, 0x0c, 0x58, 0xbf, 0xf3, 0xc0, 0x26, 0x6b, 0xa7, 0x7e, 0x95, 0x13,
- 0x59, 0x7f, 0xdf, 0x93, 0xf3, 0x8e, 0x5d, 0x2c, 0x5f, 0x4e, 0xa7, 0xcb,
- 0x17, 0x3f, 0x96, 0x28, 0x66, 0xe4, 0xe4, 0x57, 0xfc, 0xfd, 0xf0, 0x9a,
- 0x43, 0x3a, 0xc5, 0xfe, 0x27, 0xf7, 0x22, 0xfb, 0x2c, 0x58, 0x24, 0x15,
- 0x4e, 0xe4, 0x21, 0x4d, 0x22, 0xe8, 0xdf, 0x46, 0x07, 0x3e, 0xfa, 0x7b,
- 0xb9, 0x80, 0x84, 0x33, 0xab, 0xff, 0xed, 0xc6, 0x1e, 0x1f, 0x6f, 0xb3,
- 0x71, 0xb7, 0xf1, 0x62, 0xfd, 0xae, 0x9d, 0xfa, 0x54, 0x55, 0x85, 0xed,
- 0x49, 0xd6, 0x2f, 0xfa, 0x61, 0x3a, 0x8e, 0x75, 0x1a, 0xc5, 0xff, 0xd2,
- 0x43, 0x9d, 0xf1, 0x36, 0xf2, 0x02, 0xc5, 0x82, 0x4a, 0x66, 0x38, 0xb5,
- 0xa3, 0x72, 0x1d, 0xf1, 0xdd, 0xf1, 0x60, 0x82, 0xeb, 0x17, 0xf7, 0x7e,
- 0x9f, 0xbe, 0xe2, 0xc5, 0xf9, 0xff, 0x9a, 0xc5, 0x8a, 0x93, 0xd9, 0x73,
- 0x2b, 0xfb, 0x42, 0x8b, 0x93, 0xe5, 0x8a, 0x94, 0x67, 0xfd, 0xfc, 0x44,
- 0x17, 0xff, 0x03, 0x08, 0x24, 0x01, 0xc8, 0xdc, 0x96, 0x28, 0x21, 0xfb,
- 0x49, 0x7d, 0xfc, 0x36, 0x17, 0xb3, 0x8b, 0x17, 0xf3, 0x1d, 0xbd, 0xf9,
- 0x58, 0xbe, 0x98, 0xa7, 0xb5, 0x8a, 0xf9, 0xe8, 0xf0, 0xb6, 0xff, 0x37,
- 0xe4, 0xe7, 0x78, 0x2c, 0x5f, 0xb5, 0xd3, 0xbf, 0x4a, 0x89, 0x10, 0xbf,
- 0xf6, 0x6e, 0xb4, 0x7d, 0xe6, 0xb4, 0xeb, 0x17, 0xf3, 0x1e, 0x31, 0x6a,
- 0x0b, 0x17, 0x40, 0x24, 0xa3, 0x77, 0x0c, 0xf7, 0x9b, 0xec, 0xa1, 0xdf,
- 0xd1, 0xce, 0xbe, 0xec, 0xb1, 0x60, 0x81, 0x44, 0xfe, 0xb1, 0xfd, 0xe1,
- 0xff, 0xc4, 0xeb, 0xf6, 0xba, 0x77, 0xe9, 0x51, 0x69, 0x17, 0xfe, 0x78,
- 0x04, 0xcd, 0x74, 0xef, 0xd2, 0xa2, 0x7d, 0x2c, 0x13, 0x11, 0x0c, 0x73,
- 0x7b, 0xff, 0x3c, 0x02, 0x66, 0xba, 0x77, 0xe9, 0x51, 0x42, 0x17, 0xe2,
- 0x7e, 0x67, 0x96, 0x2c, 0x10, 0xe7, 0xec, 0xe9, 0xf7, 0xff, 0x61, 0x81,
- 0x3c, 0x6b, 0xf1, 0xbd, 0x2b, 0x17, 0xef, 0x0b, 0xa7, 0xe2, 0xc5, 0xd3,
- 0xa5, 0x8b, 0xff, 0xa4, 0xe2, 0xd7, 0x4e, 0xc3, 0x98, 0x96, 0x2c, 0xd1,
- 0x9e, 0xec, 0x42, 0xf4, 0x74, 0x58, 0x7e, 0x10, 0xf7, 0xed, 0x74, 0xef,
- 0xd2, 0xa2, 0x8f, 0x2d, 0x8b, 0x17, 0xf0, 0xbc, 0x76, 0x33, 0x8b, 0x14,
- 0x33, 0xc1, 0x21, 0x1b, 0xe6, 0xc0, 0x71, 0x62, 0xe7, 0xe9, 0x62, 0xd8,
- 0x33, 0x75, 0xba, 0x45, 0x7e, 0x9e, 0x44, 0x52, 0xb1, 0x7f, 0xd3, 0x09,
- 0xd4, 0x73, 0xa8, 0xd6, 0x2f, 0xff, 0xff, 0xf0, 0x6d, 0xa8, 0xa7, 0xfa,
- 0xcf, 0xb8, 0x7c, 0xc3, 0x5c, 0x81, 0x25, 0x31, 0x7e, 0x56, 0x2f, 0xcf,
- 0xc6, 0xf4, 0xac, 0x5f, 0xf4, 0xc5, 0x25, 0x31, 0x7e, 0x56, 0x2a, 0x51,
- 0xe0, 0x6c, 0x24, 0x08, 0x9e, 0xf8, 0xf1, 0xe1, 0x8b, 0x17, 0xff, 0xe1,
- 0xfe, 0x43, 0x09, 0xe2, 0x70, 0x73, 0x92, 0x04, 0x8a, 0x93, 0xfe, 0xc2,
- 0x5b, 0xcf, 0x00, 0x92, 0xad, 0x27, 0x0a, 0x22, 0x78, 0xd2, 0xdf, 0xca,
- 0x48, 0xa3, 0xd1, 0x95, 0xec, 0xc2, 0xca, 0xff, 0xec, 0xf8, 0x4f, 0x1a,
- 0xfc, 0x6f, 0x4a, 0xc5, 0x82, 0x46, 0xba, 0x34, 0x79, 0xc4, 0x1f, 0x42,
- 0x4a, 0xa5, 0xf4, 0x6d, 0xe3, 0xac, 0x45, 0x60, 0xe9, 0x92, 0xb3, 0xcd,
- 0xb5, 0x84, 0xfd, 0x4e, 0x5d, 0xf7, 0x1e, 0x63, 0x47, 0x2b, 0x14, 0xa1,
- 0xdf, 0xc3, 0x4c, 0x10, 0xa0, 0xf4, 0xea, 0x1d, 0xff, 0xf1, 0x9d, 0x6c,
- 0x41, 0x50, 0x05, 0xf5, 0xb0, 0x6d, 0xdb, 0xfd, 0x95, 0x8b, 0xff, 0xff,
- 0x6e, 0xfb, 0x63, 0x19, 0xf6, 0x32, 0x60, 0xb7, 0xe0, 0xbe, 0xb6, 0x0d,
- 0xbb, 0x7f, 0xb2, 0xb1, 0x5f, 0x4c, 0x08, 0xc6, 0xfb, 0xff, 0xbf, 0x2d,
- 0xa6, 0x0b, 0xf5, 0xf9, 0x31, 0x62, 0xff, 0xdc, 0x0b, 0xb1, 0xbb, 0x76,
- 0xff, 0x64, 0x24, 0x9f, 0x7f, 0x44, 0xb7, 0xff, 0xff, 0xfb, 0x74, 0x2e,
- 0xc6, 0xed, 0xdb, 0xfd, 0x90, 0x93, 0xf3, 0x3a, 0xd8, 0x82, 0xa0, 0x0b,
- 0xeb, 0x60, 0xdb, 0xb7, 0xfb, 0x2b, 0x17, 0xed, 0x74, 0xef, 0xd2, 0xa2,
- 0x22, 0x2f, 0xf7, 0x05, 0x31, 0x79, 0xb7, 0xac, 0x58, 0x26, 0x1f, 0x74,
- 0x46, 0xf7, 0xf6, 0x6b, 0xa7, 0x7e, 0x95, 0x11, 0x59, 0x7e, 0xd7, 0x4e,
- 0xfd, 0x2a, 0x2b, 0x82, 0xe9, 0xfa, 0xc5, 0xdb, 0x81, 0x30, 0xf3, 0xb7,
- 0x9b, 0xd0, 0x44, 0x5f, 0x3c, 0x22, 0xaf, 0xbe, 0xfa, 0x65, 0x8b, 0xf7,
- 0x80, 0x19, 0x41, 0x62, 0xfc, 0x09, 0x2e, 0x82, 0x49, 0xe6, 0x39, 0x15,
- 0xd1, 0x6e, 0x2c, 0x5f, 0xc4, 0xdd, 0x7a, 0x60, 0xb1, 0x60, 0x91, 0x9e,
- 0x56, 0x87, 0x2c, 0xdd, 0xa2, 0xd0, 0x10, 0x89, 0xbf, 0xc1, 0x5d, 0x88,
- 0xa7, 0xa7, 0xed, 0x62, 0xfb, 0x3e, 0xfe, 0x58, 0xbf, 0xd8, 0xda, 0x00,
- 0x05, 0xc5, 0x8b, 0x05, 0x48, 0xf5, 0xb8, 0x45, 0x7f, 0xff, 0xff, 0xb6,
- 0x20, 0xa0, 0x56, 0x79, 0xfc, 0x37, 0x06, 0x59, 0x1b, 0x43, 0x92, 0x39,
- 0xf9, 0x3e, 0xe2, 0xc5, 0xfd, 0xa9, 0xf3, 0x96, 0x2c, 0x5f, 0xff, 0xb8,
- 0xdf, 0x76, 0x83, 0x17, 0x85, 0xfd, 0x62, 0xc5, 0x32, 0x20, 0x3c, 0x59,
- 0x7e, 0x07, 0x3c, 0x52, 0xb1, 0x7f, 0xbd, 0xc9, 0x89, 0xdf, 0x4b, 0x15,
- 0x27, 0xb8, 0xc5, 0x17, 0xf9, 0xdc, 0xd3, 0x1f, 0x5c, 0x58, 0xbf, 0xff,
- 0x7f, 0x0b, 0x0d, 0xfb, 0xc3, 0xe6, 0x38, 0x67, 0x58, 0xbe, 0xe9, 0xdf,
- 0xa5, 0x45, 0x3c, 0x5f, 0xff, 0x9b, 0x5f, 0x79, 0xde, 0x59, 0xcc, 0x26,
- 0x3a, 0xc5, 0xff, 0x8a, 0x77, 0xb7, 0xa1, 0x38, 0x4b, 0x15, 0x04, 0xc6,
- 0xf4, 0xb1, 0xf3, 0x1f, 0x2a, 0x5f, 0xe1, 0x83, 0x6c, 0xee, 0x4c, 0x16,
- 0x2f, 0xf1, 0xd8, 0x62, 0x7d, 0x41, 0x62, 0xe3, 0xb2, 0xc5, 0x49, 0xe5,
- 0xf4, 0x69, 0x7f, 0xff, 0x4f, 0xb8, 0x23, 0xf4, 0xc0, 0x9c, 0xfb, 0x0b,
- 0xa5, 0x8b, 0x9b, 0x8b, 0x17, 0xf4, 0x9f, 0x92, 0xd1, 0xac, 0x54, 0x11,
- 0x45, 0x8b, 0xbe, 0x17, 0xbf, 0xff, 0x9f, 0x4f, 0xfe, 0xe1, 0x9e, 0xc2,
- 0x17, 0x84, 0x6a, 0xc5, 0xf4, 0x27, 0x23, 0x58, 0xbf, 0xff, 0x68, 0x5a,
- 0xd4, 0x96, 0x1a, 0xdf, 0xfe, 0x06, 0xb1, 0x61, 0xac, 0x59, 0x96, 0x2b,
- 0xa4, 0x7d, 0x76, 0xbb, 0xa2, 0x33, 0xab, 0xef, 0x12, 0xbc, 0xc5, 0xe5,
- 0x8b, 0xf8, 0x79, 0x0f, 0xcf, 0x4b, 0x17, 0xfe, 0x71, 0xce, 0x17, 0xb9,
- 0x24, 0xb1, 0x79, 0xe0, 0x11, 0xcf, 0xac, 0x8b, 0xef, 0xc1, 0x90, 0x7d,
- 0xf1, 0x62, 0xf1, 0x30, 0x16, 0x28, 0x67, 0x90, 0x72, 0xcb, 0xfe, 0xd3,
- 0xc6, 0x31, 0x3e, 0xa0, 0xb1, 0x52, 0x7b, 0xac, 0x45, 0x7f, 0xd8, 0x40,
- 0x93, 0xb6, 0xa0, 0xb1, 0x7f, 0x9b, 0x8c, 0x20, 0xb8, 0xe5, 0x62, 0xa0,
- 0x7d, 0xfe, 0x38, 0xbf, 0xfe, 0x3e, 0x37, 0x85, 0xe9, 0x83, 0x0f, 0x06,
- 0xb1, 0x4c, 0x7e, 0x20, 0x22, 0xbf, 0x6a, 0x39, 0xd4, 0x6b, 0x17, 0xe6,
- 0x2f, 0x06, 0x75, 0x8a, 0x93, 0xd4, 0x01, 0x5d, 0xfe, 0xd4, 0xcf, 0xb8,
- 0xdb, 0xd6, 0x2f, 0xe9, 0x8d, 0xc6, 0xfe, 0x58, 0xa8, 0x22, 0x10, 0xe4,
- 0x3b, 0xa6, 0xb7, 0xdb, 0x49, 0xe0, 0xb1, 0x7e, 0x7c, 0xfb, 0x1d, 0x62,
- 0xb8, 0x79, 0x7b, 0xc9, 0x2a, 0x51, 0x45, 0x8f, 0xd7, 0xf3, 0x79, 0xcd,
- 0xfb, 0x2c, 0x5f, 0xf4, 0xf5, 0xf7, 0x6d, 0x99, 0xd2, 0xc5, 0xfe, 0x73,
- 0xed, 0x1f, 0xd8, 0xeb, 0x14, 0x73, 0xf2, 0xde, 0x79, 0x7f, 0xc5, 0x27,
- 0x98, 0x16, 0x1d, 0x62, 0xff, 0xf1, 0xe7, 0x51, 0xcf, 0x78, 0x20, 0xbe,
- 0x0d, 0x62, 0xfb, 0xd0, 0x93, 0x56, 0x2a, 0x09, 0xb7, 0xe4, 0x28, 0x18,
- 0x91, 0xcd, 0xc3, 0x50, 0xbf, 0x75, 0x8c, 0x51, 0x2c, 0x5f, 0xe2, 0xeb,
- 0x37, 0xe7, 0xb8, 0xb1, 0x7e, 0x18, 0xa7, 0x51, 0xac, 0x5f, 0xff, 0x78,
- 0x13, 0x0c, 0xde, 0xde, 0x9c, 0x28, 0x2c, 0x5c, 0xe6, 0xac, 0x54, 0xa3,
- 0x23, 0x0d, 0x98, 0xab, 0x4a, 0x17, 0xbd, 0xf6, 0x58, 0xbb, 0x42, 0x58,
- 0xbe, 0xcf, 0x61, 0xd6, 0x2d, 0x1c, 0x9b, 0xa7, 0x18, 0xac, 0x3f, 0xd7,
- 0x57, 0xad, 0x81, 0x9c, 0xd1, 0xb1, 0xc2, 0x53, 0x61, 0x15, 0xcc, 0x63,
- 0xd0, 0x7e, 0x19, 0x06, 0x46, 0xa0, 0x69, 0xf7, 0x50, 0x84, 0xee, 0x18,
- 0x8d, 0x19, 0x4c, 0x49, 0xc7, 0x84, 0x3f, 0xe1, 0xb0, 0xf1, 0x80, 0x14,
- 0x73, 0x7c, 0x8e, 0x43, 0xc9, 0xdb, 0xe1, 0xe3, 0xb3, 0x0b, 0x7b, 0xfb,
- 0x3d, 0xcc, 0x7d, 0xc5, 0x8b, 0xf9, 0xcc, 0xe7, 0x24, 0x0b, 0x17, 0xcf,
- 0x00, 0x83, 0x93, 0xdf, 0x23, 0x0b, 0xff, 0xc0, 0x00, 0xb8, 0x10, 0x32,
- 0x73, 0x94, 0xac, 0x5f, 0xfc, 0x58, 0x07, 0x20, 0x04, 0x3b, 0x1d, 0x62,
- 0xb4, 0x89, 0x2f, 0x26, 0xdf, 0x9f, 0xff, 0x68, 0x96, 0x2f, 0xfe, 0xce,
- 0x31, 0x00, 0xb3, 0xdf, 0xc5, 0x8b, 0xff, 0x31, 0x00, 0xb3, 0xdf, 0xc0,
- 0x9f, 0x3e, 0xb0, 0xca, 0x68, 0x22, 0xb7, 0xa1, 0xc7, 0x96, 0xd0, 0xcb,
- 0xe4, 0x23, 0xad, 0x8b, 0x17, 0xe2, 0x91, 0x05, 0xf8, 0xb1, 0x73, 0x7d,
- 0x62, 0xff, 0xf9, 0xc6, 0x6b, 0xfb, 0x3e, 0x59, 0xef, 0xb2, 0xc5, 0xfc,
- 0x6e, 0x9c, 0x6e, 0x4b, 0x14, 0x34, 0x68, 0xe0, 0x8e, 0x8b, 0x3e, 0x2e,
- 0xe9, 0xf7, 0xff, 0x30, 0xf4, 0xfd, 0x84, 0xd6, 0xa6, 0x35, 0x8a, 0x08,
- 0x89, 0x1f, 0xa4, 0x5a, 0x56, 0x2f, 0xee, 0x4f, 0x45, 0x23, 0x58, 0xa1,
- 0x9b, 0xf6, 0x11, 0xbf, 0xfe, 0x9d, 0x64, 0x19, 0xfd, 0x83, 0x61, 0x74,
- 0x91, 0x70, 0xbb, 0x58, 0xaf, 0x9f, 0x41, 0x27, 0xde, 0x60, 0x71, 0x62,
- 0xdd, 0x2c, 0x5f, 0xa6, 0x00, 0x14, 0x16, 0x2f, 0xba, 0x77, 0xe9, 0x51,
- 0x59, 0x97, 0x49, 0x8b, 0x15, 0x1a, 0x28, 0xb0, 0x76, 0x21, 0x3d, 0x14,
- 0xef, 0x31, 0xbe, 0xf3, 0x1f, 0x8b, 0x16, 0xd2, 0xc5, 0x8d, 0x58, 0xa6,
- 0x34, 0xbc, 0x12, 0xbd, 0xc1, 0x74, 0xb1, 0x46, 0x9b, 0xfe, 0x10, 0x58,
- 0x35, 0x8b, 0xda, 0x9d, 0xeb, 0x15, 0x26, 0xcb, 0x82, 0x77, 0xf6, 0xf2,
- 0x29, 0xdc, 0x89, 0x62, 0xfc, 0x79, 0x28, 0x71, 0x62, 0xe9, 0x89, 0x62,
- 0xa4, 0xfc, 0xe3, 0x33, 0xd1, 0x45, 0xf7, 0xb8, 0x1f, 0x16, 0x2f, 0xb9,
- 0xc9, 0x31, 0x62, 0xce, 0xb1, 0x58, 0x7b, 0x4c, 0x4b, 0xc2, 0x4b, 0xa3,
- 0x65, 0x8b, 0xfd, 0xc8, 0x98, 0xbf, 0x9d, 0xac, 0x54, 0x9e, 0x6e, 0x0c,
- 0x5c, 0xfe, 0x58, 0xbe, 0x00, 0x65, 0x05, 0x8a, 0x19, 0xbb, 0xf0, 0xbd,
- 0xff, 0xf4, 0x9f, 0xd9, 0x85, 0xee, 0x7f, 0x00, 0xeb, 0x17, 0xf8, 0xf3,
- 0xdf, 0x35, 0x3b, 0xd6, 0x2e, 0x7e, 0x2c, 0x54, 0x9e, 0x70, 0x8d, 0xef,
- 0xf4, 0x18, 0x5b, 0x9b, 0x00, 0x0e, 0xb1, 0x7e, 0x29, 0xfb, 0x62, 0xc5,
- 0xd3, 0x05, 0x8a, 0xc3, 0xfa, 0x73, 0xd0, 0x13, 0x59, 0x96, 0x2f, 0xd8,
- 0x44, 0xfe, 0x58, 0xe1, 0x63, 0x78, 0x50, 0x1a, 0xc5, 0x7c, 0xf4, 0xc8,
- 0xd6, 0xfc, 0x5e, 0xfc, 0xef, 0x58, 0xbc, 0xee, 0x75, 0x8b, 0xf6, 0x45,
- 0x18, 0x80, 0xb1, 0x7f, 0x7a, 0x74, 0x09, 0x89, 0x62, 0xc1, 0x25, 0x7c,
- 0x38, 0x70, 0x88, 0xc8, 0x61, 0xf6, 0x9a, 0xd0, 0x87, 0x89, 0x53, 0x50,
- 0x93, 0x3c, 0x22, 0x7e, 0xf4, 0xeb, 0x60, 0x21, 0x28, 0x4e, 0x72, 0x13,
- 0x7e, 0x84, 0x88, 0x88, 0x77, 0x95, 0x06, 0x39, 0xba, 0x57, 0x7f, 0x43,
- 0x0e, 0x1c, 0xee, 0x2c, 0x5f, 0xef, 0x3e, 0xa3, 0x96, 0x1a, 0xc5, 0xfd,
- 0xee, 0x0d, 0xa4, 0x96, 0x29, 0x8f, 0x85, 0xcd, 0x2f, 0xe9, 0x3c, 0x62,
- 0xd4, 0x16, 0x2f, 0xb5, 0x86, 0x79, 0x62, 0xbe, 0x7e, 0x9e, 0x20, 0xde,
- 0x61, 0x7f, 0xa3, 0xfe, 0x75, 0xf9, 0xd2, 0xc5, 0xff, 0x49, 0x43, 0x87,
- 0x72, 0x35, 0x62, 0xa4, 0xfb, 0xfc, 0x6d, 0x74, 0x8d, 0x62, 0xff, 0x84,
- 0x7c, 0xeb, 0x5d, 0xb9, 0x8b, 0x15, 0x03, 0xf5, 0xe1, 0x0f, 0x85, 0xef,
- 0xf6, 0xa4, 0xdc, 0x26, 0x35, 0x62, 0xff, 0xf9, 0xde, 0x3f, 0xb4, 0x94,
- 0x1b, 0xef, 0xc5, 0x8b, 0xdb, 0xa7, 0x95, 0x8b, 0xff, 0xe1, 0xfe, 0x79,
- 0xb7, 0x1b, 0x4c, 0x79, 0x35, 0x62, 0xd2, 0xb1, 0x58, 0x7c, 0x7c, 0x52,
- 0xbc, 0x4f, 0xe5, 0x8b, 0xf6, 0x76, 0x09, 0xfa, 0xc5, 0xff, 0xe9, 0x30,
- 0x33, 0x96, 0x77, 0xe9, 0xc3, 0x16, 0x2f, 0xde, 0x62, 0xc3, 0xac, 0x5e,
- 0x72, 0x08, 0x35, 0xc2, 0xac, 0x8c, 0x1f, 0xb8, 0xc5, 0x74, 0x5e, 0x73,
- 0x4f, 0xa7, 0x14, 0x20, 0xf7, 0x90, 0xec, 0x8e, 0x06, 0x53, 0xba, 0x9b,
- 0x7f, 0xce, 0x60, 0x41, 0xc9, 0xfb, 0x95, 0x8a, 0x82, 0x60, 0x65, 0x0c,
- 0x6b, 0xff, 0x3c, 0x02, 0x66, 0xba, 0x77, 0xe9, 0x51, 0x22, 0x97, 0xff,
- 0xef, 0x7f, 0x08, 0x27, 0x9d, 0xfb, 0xe1, 0xa6, 0xba, 0xc5, 0xff, 0x9f,
- 0xc1, 0x25, 0xb4, 0xde, 0x12, 0xc5, 0x04, 0x47, 0x4c, 0xa7, 0xba, 0xd5,
- 0xff, 0x6b, 0x4c, 0x66, 0x44, 0xc7, 0x58, 0xbe, 0xea, 0x7f, 0x2b, 0x14,
- 0xc7, 0xbc, 0x47, 0x77, 0xed, 0x74, 0xef, 0xd2, 0xa2, 0xc9, 0x2a, 0x4f,
- 0x5f, 0x08, 0x2f, 0x98, 0xa1, 0xc5, 0x8b, 0xf4, 0xf3, 0xcd, 0x1a, 0xc5,
- 0x46, 0x79, 0x66, 0x91, 0x5f, 0xe1, 0x47, 0xf9, 0xf7, 0x19, 0x62, 0xfe,
- 0x10, 0xdb, 0x4f, 0xc5, 0x8b, 0x9b, 0xcb, 0x17, 0xef, 0x70, 0x3e, 0x04,
- 0xc4, 0x4f, 0x68, 0x93, 0x86, 0xbe, 0x2e, 0xa0, 0x89, 0xb3, 0x64, 0x61,
- 0x37, 0xff, 0xd2, 0x77, 0x18, 0x4f, 0x4f, 0x70, 0x8f, 0x0c, 0x58, 0xbe,
- 0xc3, 0x39, 0xf5, 0x8b, 0xe9, 0x3b, 0x18, 0xb1, 0x7f, 0x31, 0xe7, 0xe1,
- 0x8d, 0x62, 0xa2, 0x3d, 0x2d, 0xd2, 0x3b, 0xfb, 0xed, 0xa9, 0x87, 0x16,
- 0x2f, 0x9a, 0x44, 0x17, 0x58, 0xbf, 0x8f, 0xe6, 0xfb, 0x9d, 0x62, 0xff,
- 0xf3, 0x7b, 0xf9, 0xec, 0x29, 0xf4, 0x8d, 0x62, 0xa4, 0xfd, 0x9c, 0xba,
- 0xf9, 0xb6, 0x37, 0xe9, 0x62, 0xff, 0x37, 0x85, 0xa7, 0xe0, 0x48, 0xd3,
- 0xae, 0xc7, 0x6e, 0x89, 0xb4, 0x5d, 0xf8, 0x4e, 0x78, 0x82, 0x99, 0x54,
- 0x5b, 0xca, 0x03, 0xbf, 0xff, 0xde, 0x7e, 0xc0, 0x10, 0x65, 0x3d, 0xc3,
- 0xcc, 0x40, 0xe2, 0xc5, 0xfd, 0x9a, 0xe9, 0xdf, 0xa5, 0x45, 0xb0, 0x5f,
- 0xff, 0xbf, 0xb4, 0xb3, 0x5e, 0xe7, 0xe2, 0xdb, 0xb7, 0xfb, 0x2b, 0x17,
- 0xef, 0xbe, 0x98, 0xeb, 0x14, 0x15, 0x44, 0x57, 0x4c, 0x57, 0xec, 0xdf,
- 0xa7, 0xe2, 0xc5, 0xff, 0xb5, 0x1c, 0xf9, 0x9a, 0x1c, 0x95, 0x8b, 0xda,
- 0x17, 0xd6, 0x2e, 0xf0, 0x49, 0x45, 0x78, 0xca, 0x30, 0xab, 0x47, 0xf4,
- 0x11, 0x3b, 0xe6, 0x8d, 0xd6, 0xf6, 0x73, 0x16, 0x2f, 0xba, 0x77, 0xe9,
- 0x51, 0x6d, 0x97, 0x3e, 0x96, 0x2d, 0x05, 0x8b, 0x72, 0x33, 0x52, 0x21,
- 0x7a, 0xd2, 0x20, 0xbc, 0xb5, 0x7e, 0xff, 0x98, 0x02, 0x58, 0xbf, 0xfd,
- 0x31, 0xf9, 0x87, 0x85, 0x06, 0xf8, 0x96, 0x29, 0x8f, 0xcf, 0xe5, 0x37,
- 0xe7, 0x88, 0xa4, 0xeb, 0x17, 0xe8, 0x04, 0xe1, 0xe5, 0x62, 0xff, 0xa6,
- 0x13, 0xa8, 0xe7, 0x51, 0xac, 0x5f, 0x4c, 0x5c, 0x65, 0x8a, 0x82, 0xa0,
- 0x6c, 0x84, 0xf4, 0x50, 0x96, 0x39, 0x0b, 0x94, 0x11, 0x5e, 0xe9, 0xdd,
- 0xff, 0x87, 0xa6, 0x14, 0x61, 0x39, 0xaf, 0x2c, 0x50, 0x44, 0x5a, 0xe3,
- 0x8d, 0xef, 0xe4, 0x6b, 0x17, 0xf3, 0x8f, 0x30, 0x8d, 0x58, 0xbf, 0xbe,
- 0xda, 0xd3, 0xc1, 0x62, 0xff, 0xde, 0x68, 0x37, 0xc4, 0x73, 0xb2, 0xc5,
- 0x44, 0x8b, 0x83, 0x8f, 0x70, 0xb4, 0x32, 0xeb, 0xfd, 0x81, 0x35, 0x9b,
- 0x2c, 0x6a, 0xc5, 0xec, 0x20, 0x04, 0x3f, 0x8d, 0x93, 0xfb, 0x12, 0xc5,
- 0xa0, 0xb1, 0x5b, 0x19, 0xa3, 0x18, 0x8d, 0xed, 0x8f, 0xe3, 0x58, 0xbd,
- 0x1f, 0xd9, 0x62, 0xff, 0xdb, 0x1e, 0xc7, 0xb0, 0xfd, 0xfc, 0x29, 0x02,
- 0xc5, 0xed, 0x84, 0x16, 0xbb, 0x09, 0x62, 0xfd, 0xe9, 0xfb, 0xc4, 0xb1,
- 0x7e, 0x28, 0x0c, 0x47, 0x58, 0xbf, 0x8c, 0x0f, 0x65, 0xc8, 0x0b, 0x15,
- 0x27, 0xb9, 0x85, 0x37, 0xf3, 0x07, 0x17, 0x05, 0xda, 0xc5, 0xf7, 0x5f,
- 0x16, 0x96, 0x2d, 0xb1, 0xac, 0x50, 0xcd, 0xe6, 0x89, 0x6b, 0xe8, 0x8f,
- 0x76, 0xeb, 0xfe, 0xcd, 0x6a, 0x60, 0xfd, 0x98, 0xb1, 0x7d, 0xd3, 0xbf,
- 0x4a, 0x8b, 0xc0, 0xbf, 0x7b, 0xbe, 0x9b, 0x4b, 0x17, 0xfc, 0x0e, 0x6d,
- 0xe0, 0x1f, 0x22, 0x58, 0xbf, 0xda, 0xd6, 0x7b, 0x92, 0x75, 0x8a, 0x63,
- 0xf1, 0x73, 0xdb, 0xff, 0x3f, 0xa7, 0x7e, 0xb5, 0x9d, 0xf1, 0x62, 0xfd,
- 0xac, 0xde, 0xfa, 0x58, 0xbf, 0xf6, 0x83, 0xf3, 0x7c, 0xb3, 0xd8, 0xb1,
- 0x4c, 0x7d, 0x2e, 0x55, 0x5a, 0x4e, 0xe0, 0xe6, 0x3f, 0x84, 0xe1, 0x10,
- 0x6f, 0x85, 0x5d, 0xf7, 0x82, 0xde, 0x44, 0xb1, 0x74, 0xca, 0xc5, 0x68,
- 0xf0, 0x3c, 0x55, 0x7f, 0x4c, 0x65, 0x2c, 0x35, 0x8b, 0x9f, 0x8b, 0x17,
- 0xb6, 0x73, 0xeb, 0x14, 0x03, 0x6f, 0xe1, 0x7b, 0xf1, 0xe4, 0xa0, 0xeb,
- 0x17, 0xf4, 0x97, 0xb7, 0xbf, 0x4b, 0x17, 0xf4, 0x27, 0x7c, 0xeb, 0xb5,
- 0x8b, 0xff, 0xf9, 0xe3, 0x8a, 0x13, 0xa8, 0xfd, 0x0c, 0xdc, 0x72, 0x02,
- 0xc5, 0x41, 0x18, 0x58, 0x60, 0xe6, 0x37, 0xfc, 0xdd, 0xff, 0x06, 0x1c,
- 0xf6, 0xb1, 0x78, 0xb2, 0x25, 0x8a, 0xd1, 0xec, 0xfc, 0xf2, 0xfe, 0xf3,
- 0xff, 0x68, 0xe5, 0x62, 0xff, 0x9f, 0xdc, 0x96, 0x1e, 0x1d, 0x62, 0xa4,
- 0xfa, 0x08, 0xc2, 0xfd, 0x06, 0x6f, 0xba, 0xc5, 0xf1, 0x63, 0x1a, 0xb1,
- 0x7f, 0xc7, 0xee, 0x1e, 0xc2, 0xf7, 0x16, 0x2b, 0xb4, 0x42, 0x1c, 0x9c,
- 0x32, 0x2b, 0xb0, 0xd5, 0x8b, 0xf3, 0xc3, 0xcd, 0x1a, 0xc5, 0xff, 0xde,
- 0x92, 0xe9, 0x8e, 0x76, 0xe0, 0x96, 0x2f, 0xfe, 0x0e, 0x75, 0x0d, 0xbc,
- 0xc3, 0xce, 0x2c, 0x53, 0x22, 0x33, 0xc8, 0xb5, 0x29, 0x90, 0xe1, 0x93,
- 0x0c, 0x3c, 0x2d, 0x6e, 0xc3, 0xac, 0x5f, 0x9b, 0xe3, 0x6e, 0x2c, 0x59,
- 0xa3, 0x37, 0xf0, 0x17, 0xbf, 0x61, 0x03, 0x76, 0x56, 0x2e, 0x7e, 0x2c,
- 0x5e, 0x13, 0xf1, 0x62, 0xbc, 0x6d, 0x03, 0x17, 0xbf, 0x45, 0xa6, 0x8c,
- 0xeb, 0x15, 0x27, 0x9b, 0x84, 0x57, 0x44, 0x35, 0x8b, 0xff, 0xff, 0xe2,
- 0x13, 0xf3, 0x0b, 0x9c, 0xcf, 0xb7, 0x05, 0x1f, 0x3f, 0x9d, 0xfa, 0x56,
- 0x2f, 0xcd, 0xa7, 0xec, 0xc5, 0x8b, 0xff, 0x4f, 0x5b, 0x70, 0x85, 0x0c,
- 0xe2, 0xc5, 0x41, 0x1d, 0x31, 0x3f, 0x1c, 0xaa, 0xff, 0x7d, 0x8c, 0x37,
- 0x4e, 0x62, 0xc5, 0xfb, 0x7c, 0x8c, 0xfc, 0x58, 0xbf, 0xb3, 0x82, 0xf4,
- 0x92, 0xc5, 0xff, 0xff, 0x9d, 0xbc, 0xe7, 0x72, 0x07, 0x5f, 0x6d, 0x40,
- 0x38, 0x61, 0x2c, 0x5f, 0xb7, 0xe6, 0x11, 0xab, 0x17, 0xf6, 0x0f, 0xf3,
- 0xcd, 0xc5, 0x8b, 0xfa, 0x7b, 0xee, 0x0f, 0xda, 0xc5, 0x0d, 0x55, 0xd6,
- 0x46, 0x05, 0xd1, 0x8b, 0x1b, 0xc4, 0x57, 0xf2, 0xd0, 0x36, 0x11, 0x50,
- 0x8c, 0x6f, 0xe2, 0xcf, 0x03, 0x3b, 0x58, 0xbf, 0xce, 0x40, 0xf6, 0xce,
- 0x7d, 0x62, 0xff, 0xbe, 0xf0, 0x3b, 0x4e, 0xa0, 0xb1, 0x5b, 0x87, 0xdf,
- 0xf3, 0x6a, 0x94, 0x61, 0x64, 0x27, 0x6e, 0x3f, 0x16, 0x2f, 0xa4, 0xa1,
- 0xb8, 0xb1, 0x7f, 0xf0, 0x1c, 0x80, 0x59, 0xbf, 0xf8, 0x35, 0x8b, 0xff,
- 0x9c, 0x18, 0x3c, 0xfb, 0x6b, 0xee, 0xb1, 0x5d, 0xa2, 0x23, 0x88, 0xb7,
- 0xff, 0x33, 0x83, 0xcd, 0xcf, 0xc9, 0x79, 0x62, 0xfb, 0x3c, 0x67, 0x4b,
- 0x17, 0x48, 0x16, 0x2a, 0x09, 0xc7, 0x61, 0x31, 0xa3, 0x0d, 0x0a, 0xdf,
- 0x92, 0x71, 0x0f, 0xc4, 0xb7, 0xf9, 0xfe, 0xe1, 0x9f, 0x38, 0xb1, 0x6e,
- 0x96, 0x2e, 0xea, 0x0b, 0x15, 0xd1, 0xac, 0xf0, 0x9d, 0x05, 0x1b, 0x11,
- 0x60, 0xa9, 0x36, 0xc6, 0x47, 0xb0, 0x87, 0x82, 0xd5, 0x3e, 0x4c, 0x63,
- 0x84, 0x2c, 0x21, 0x5e, 0x32, 0x2c, 0x8f, 0xcc, 0xd8, 0x4b, 0x74, 0x45,
- 0xdb, 0x23, 0x10, 0xc5, 0x0e, 0x9d, 0x42, 0x1c, 0xf0, 0x8a, 0xfc, 0x78,
- 0xae, 0xfc, 0x02, 0x72, 0x85, 0x5f, 0x25, 0x6d, 0x7a, 0x56, 0xae, 0xf6,
- 0x9d, 0x96, 0x0b, 0xde, 0x91, 0xac, 0x5f, 0x01, 0xf5, 0xc5, 0x8b, 0xbb,
- 0x09, 0x27, 0x81, 0x83, 0xb7, 0xf8, 0x01, 0x22, 0x84, 0x97, 0x96, 0x28,
- 0x22, 0xa5, 0x59, 0x8f, 0xbf, 0x45, 0xf6, 0x25, 0x8b, 0x76, 0xb1, 0x71,
- 0x0f, 0x0d, 0x20, 0x62, 0x37, 0x67, 0x6b, 0x17, 0xe3, 0x0b, 0x23, 0x12,
- 0xc5, 0xee, 0x0a, 0x35, 0x8a, 0x93, 0xc9, 0x72, 0xaa, 0x64, 0x40, 0xe9,
- 0x86, 0xfd, 0xae, 0x9d, 0xfa, 0x54, 0x5e, 0x85, 0xfb, 0x3c, 0x53, 0x1a,
- 0xc5, 0xff, 0x9d, 0xbc, 0x2d, 0x3e, 0xfc, 0x1a, 0xc5, 0xe1, 0x8b, 0x8b,
- 0x17, 0xe9, 0x3b, 0xfe, 0x56, 0x2f, 0x1d, 0xbc, 0xb1, 0x7f, 0xcf, 0xe8,
- 0x49, 0xbe, 0x68, 0xd6, 0x2b, 0x47, 0xfe, 0x72, 0x72, 0x1d, 0xbf, 0x61,
- 0xfe, 0xe3, 0x58, 0xa9, 0x54, 0xc2, 0x38, 0x56, 0xe1, 0x16, 0x8d, 0xfe,
- 0x50, 0xe8, 0x01, 0xc2, 0x77, 0x74, 0xba, 0xff, 0xec, 0x1f, 0xf0, 0xe7,
- 0x78, 0x61, 0x2c, 0x5e, 0x14, 0x81, 0x62, 0xfb, 0x7e, 0x10, 0x41, 0x9f,
- 0x06, 0x90, 0xef, 0xf0, 0x4f, 0x64, 0x50, 0x71, 0xac, 0x53, 0x1f, 0x9f,
- 0xcf, 0x28, 0x22, 0x6e, 0x59, 0x1a, 0x8d, 0x05, 0x8f, 0x93, 0xce, 0x16,
- 0xac, 0xb3, 0x19, 0x74, 0x70, 0xe8, 0x84, 0x65, 0x39, 0x59, 0x08, 0x75,
- 0x1d, 0x93, 0x4f, 0xb9, 0x45, 0x3c, 0xad, 0xa8, 0xc4, 0x4f, 0x29, 0x2f,
- 0xf2, 0xad, 0x9c, 0xa8, 0x12, 0x88, 0xca, 0x57, 0x37, 0x23, 0x54, 0x15,
- 0x67, 0x8a, 0x64, 0xe1, 0x85, 0xe2, 0xf7, 0x16, 0x2e, 0x39, 0xd6, 0x2d,
- 0xf5, 0x8a, 0xd8, 0x8d, 0x50, 0x86, 0x2f, 0xfe, 0x14, 0xc4, 0x59, 0xbd,
- 0xce, 0x76, 0x58, 0xbe, 0xcf, 0xbf, 0x96, 0x2f, 0xf6, 0x36, 0x80, 0x01,
- 0x71, 0x62, 0xc1, 0x53, 0x51, 0x38, 0x48, 0xdc, 0x22, 0xbc, 0xd9, 0xc5,
- 0x8b, 0xff, 0xde, 0xe0, 0xa7, 0x99, 0xe6, 0x3b, 0xc1, 0x62, 0xf4, 0xf7,
- 0x1a, 0xc5, 0x11, 0xf4, 0xf9, 0x2a, 0xf9, 0xb6, 0x64, 0xeb, 0x17, 0xfb,
- 0xf3, 0x1e, 0xa7, 0x06, 0xb1, 0x7f, 0xfd, 0x16, 0x61, 0x9b, 0x43, 0x84,
- 0xef, 0x62, 0x02, 0xc5, 0xff, 0xd9, 0x86, 0x07, 0x09, 0xde, 0xc4, 0x05,
- 0x8b, 0xd8, 0xdb, 0xf6, 0xa2, 0x76, 0x25, 0x6a, 0x94, 0xc2, 0x7f, 0x0d,
- 0x1b, 0xfe, 0xf7, 0x33, 0xb8, 0x7c, 0x46, 0xac, 0x5e, 0xe4, 0xc4, 0xb1,
- 0x43, 0x54, 0xae, 0xd0, 0x85, 0x39, 0x0f, 0xe3, 0x2e, 0x22, 0x8e, 0x1e,
- 0xde, 0x27, 0xfa, 0xc5, 0xed, 0xf3, 0x05, 0x8b, 0xdf, 0xce, 0x2c, 0x5f,
- 0xf1, 0x31, 0xbe, 0xef, 0xa6, 0xfa, 0xc5, 0xee, 0x4c, 0x6b, 0x15, 0x28,
- 0x96, 0x18, 0xfe, 0x0e, 0xf6, 0x79, 0x7f, 0xbd, 0xf6, 0x70, 0x02, 0x56,
- 0x2f, 0xbb, 0x80, 0xa3, 0x58, 0xbf, 0x8d, 0xe3, 0xcf, 0x70, 0x58, 0xb6,
- 0x76, 0x7a, 0xcc, 0x4d, 0x7f, 0x3e, 0xa0, 0x42, 0x75, 0x8b, 0x98, 0xeb,
- 0x15, 0x88, 0xf4, 0xd4, 0x22, 0x44, 0x4f, 0xba, 0x5b, 0x7c, 0x71, 0x10,
- 0xd6, 0x2f, 0x1b, 0x26, 0x2c, 0x5e, 0x77, 0xe9, 0x51, 0x11, 0x97, 0xc6,
- 0xf4, 0xfa, 0x58, 0xa3, 0x4f, 0xbb, 0xa1, 0xf6, 0x2a, 0xbf, 0x6c, 0x7e,
- 0xe3, 0x81, 0x62, 0xfc, 0xce, 0x7c, 0xd2, 0xc5, 0xff, 0x09, 0xfb, 0x2c,
- 0x8c, 0x38, 0x2c, 0x5e, 0xe8, 0x33, 0xac, 0x5f, 0xff, 0xf4, 0xc5, 0xe9,
- 0xe6, 0xa7, 0xcd, 0xd3, 0x0f, 0x69, 0xa4, 0xeb, 0x15, 0x28, 0x8a, 0x22,
- 0x0b, 0xff, 0x9b, 0x9f, 0xc3, 0x4d, 0x7d, 0xa3, 0xed, 0x62, 0xa3, 0x54,
- 0x8f, 0xa8, 0x48, 0x9c, 0xc3, 0xe5, 0xdc, 0x27, 0xf4, 0x31, 0xb7, 0x90,
- 0xdf, 0xcf, 0xdf, 0xf1, 0x8c, 0x58, 0xba, 0x1f, 0x58, 0xad, 0x1e, 0x3b,
- 0x97, 0xdf, 0xec, 0xf6, 0x1e, 0x3c, 0x31, 0x62, 0x86, 0x7a, 0xc4, 0x43,
- 0x7f, 0xf7, 0x39, 0x87, 0x2c, 0xdf, 0xb6, 0x76, 0x25, 0x8a, 0x63, 0xee,
- 0x11, 0x0d, 0xfe, 0xc8, 0xfe, 0x58, 0x21, 0xac, 0x57, 0xcf, 0x54, 0x88,
- 0x6f, 0xf4, 0x7a, 0xcf, 0x79, 0xbc, 0xb1, 0x4b, 0x17, 0xff, 0x7f, 0x3c,
- 0x53, 0x16, 0xd3, 0x49, 0xd6, 0x2e, 0x14, 0xc4, 0x7a, 0x7e, 0x0c, 0xa9,
- 0x45, 0xb7, 0x21, 0x11, 0x78, 0xa7, 0xb5, 0x8a, 0x81, 0xe2, 0x0c, 0x9e,
- 0xe7, 0xfa, 0xc5, 0xfe, 0xd6, 0x73, 0x1c, 0xa3, 0x58, 0xbc, 0x71, 0x76,
- 0xb1, 0x43, 0x3e, 0x9c, 0x17, 0x01, 0x9d, 0xfe, 0x10, 0xc3, 0xff, 0xde,
- 0x0b, 0x16, 0x3a, 0xc5, 0xfe, 0x0e, 0x13, 0xbd, 0x88, 0x0b, 0x17, 0xf4,
- 0x27, 0x7b, 0x10, 0x16, 0x2c, 0x66, 0xd3, 0xe5, 0x0c, 0xda, 0x86, 0x8a,
- 0x3c, 0x77, 0xbf, 0xfa, 0x63, 0xda, 0x59, 0xee, 0x7f, 0x0d, 0x58, 0xbf,
- 0x3c, 0x61, 0xb0, 0xd6, 0x2f, 0xfe, 0xc3, 0x05, 0x31, 0xf8, 0x73, 0xee,
- 0x2c, 0x5c, 0xd1, 0x2c, 0x54, 0x13, 0xcc, 0xc8, 0x6c, 0xfc, 0x89, 0xd2,
- 0x08, 0xab, 0xc8, 0xf7, 0xff, 0xa0, 0xc6, 0x9a, 0xfc, 0x96, 0x8d, 0xfc,
- 0xb1, 0x7f, 0xff, 0x3b, 0x7a, 0x7e, 0x59, 0xef, 0xb7, 0xf1, 0x8c, 0x58,
- 0xa6, 0x45, 0x2f, 0xd3, 0x2f, 0xff, 0xff, 0x7b, 0xcc, 0x7d, 0x36, 0x76,
- 0x42, 0xf4, 0xff, 0x6e, 0xf6, 0xf4, 0x52, 0xb1, 0x7f, 0xb1, 0x89, 0xb5,
- 0xac, 0x58, 0xbf, 0xec, 0x72, 0x06, 0x85, 0x20, 0x58, 0xa9, 0x4c, 0x23,
- 0x08, 0xbb, 0x7d, 0xd1, 0x8d, 0xff, 0xf8, 0xfb, 0x8c, 0xef, 0x17, 0xbf,
- 0x90, 0xfb, 0x6f, 0x58, 0xbf, 0xbb, 0x86, 0x85, 0x20, 0x58, 0xbf, 0x7a,
- 0x75, 0x20, 0x58, 0xb9, 0xe2, 0x58, 0xbf, 0xff, 0x61, 0xce, 0xdb, 0xbb,
- 0x71, 0xb4, 0xc7, 0x93, 0x56, 0x2e, 0x93, 0xe8, 0xfc, 0x88, 0x62, 0xe0,
- 0xce, 0xb1, 0x7e, 0xcd, 0x42, 0x4e, 0xb1, 0x51, 0x9e, 0x09, 0xc6, 0x6a,
- 0x53, 0xb5, 0xc5, 0xb6, 0x30, 0xfc, 0x26, 0x9d, 0xb6, 0xe8, 0xce, 0x91,
- 0x71, 0x86, 0x24, 0x5f, 0xef, 0xb4, 0x5f, 0x98, 0xc2, 0x00, 0xd9, 0x98,
- 0x33, 0x7d, 0x83, 0xfe, 0x2c, 0x58, 0x27, 0x47, 0xe0, 0x49, 0xd7, 0xfb,
- 0x85, 0x9e, 0xd9, 0xcf, 0x2c, 0x5f, 0x6f, 0x9f, 0x4a, 0xc5, 0xed, 0xef,
- 0xa5, 0x8b, 0xec, 0xf9, 0x62, 0xc5, 0x61, 0xe0, 0x70, 0x7e, 0xa0, 0x8e,
- 0x5c, 0x2a, 0x63, 0x6f, 0x32, 0x5b, 0x75, 0x62, 0xfc, 0xe7, 0xce, 0xfc,
- 0xb1, 0x7b, 0x8f, 0xb8, 0xb1, 0x7f, 0x9c, 0xba, 0xda, 0x67, 0xb8, 0xb1,
- 0x51, 0xa2, 0x5b, 0x05, 0x58, 0xa4, 0x44, 0x17, 0xa3, 0x9d, 0xc5, 0x8b,
- 0xff, 0xef, 0xb1, 0xbc, 0x6c, 0x20, 0x0f, 0x4f, 0xd2, 0xc5, 0xff, 0xf6,
- 0x30, 0x39, 0xb7, 0x0e, 0x1f, 0xdf, 0xf2, 0xb1, 0x7f, 0xff, 0xf0, 0xa6,
- 0x3e, 0xe1, 0xc2, 0xc8, 0xb6, 0xf5, 0xf9, 0xe8, 0xdd, 0x39, 0x8b, 0x17,
- 0xfc, 0x06, 0x8b, 0x8d, 0xf6, 0x3a, 0xc5, 0xfe, 0xc3, 0x96, 0x18, 0xe0,
- 0x58, 0xbf, 0xd3, 0xfc, 0x8a, 0x0f, 0x1a, 0xc5, 0xff, 0xc5, 0x9d, 0xc3,
- 0x83, 0x6d, 0xf2, 0x35, 0x8a, 0x8d, 0x51, 0x48, 0xc8, 0x74, 0xa2, 0x75,
- 0x20, 0x3e, 0x78, 0xe8, 0x46, 0x7b, 0xa6, 0xb7, 0xe6, 0xf4, 0xfb, 0x8b,
- 0x17, 0xf9, 0xfb, 0xe3, 0x90, 0xb1, 0x62, 0xf9, 0xb4, 0xe0, 0x58, 0xa8,
- 0x1f, 0xe8, 0x0a, 0x38, 0x67, 0x7f, 0x81, 0x3b, 0xdf, 0xff, 0x65, 0x8a,
- 0x08, 0x7c, 0x9e, 0x2f, 0xbf, 0xee, 0x0b, 0x5a, 0x69, 0x6d, 0x2c, 0x56,
- 0x27, 0x6a, 0xf1, 0xac, 0x78, 0x92, 0xdb, 0x8b, 0x17, 0xc5, 0xdc, 0x52,
- 0xb1, 0x73, 0xee, 0x2c, 0x5f, 0xf4, 0xe7, 0x72, 0xf0, 0x78, 0x2c, 0x5f,
- 0xd8, 0x0d, 0xa5, 0x80, 0x58, 0xb8, 0xfd, 0x2c, 0x50, 0xcf, 0x21, 0xcb,
- 0xef, 0xfd, 0x86, 0x6d, 0x71, 0xb4, 0x4d, 0x2b, 0x17, 0xe9, 0x2f, 0x48,
- 0x16, 0x2f, 0x78, 0x0e, 0xb1, 0x74, 0xc6, 0xb1, 0x5a, 0x3d, 0xc3, 0x93,
- 0xee, 0x8e, 0xdf, 0x16, 0x3e, 0xe2, 0xc5, 0xfa, 0x4c, 0x0f, 0xf2, 0xb1,
- 0x41, 0x45, 0x42, 0x32, 0x2b, 0x19, 0x20, 0xc6, 0xb2, 0x10, 0x1a, 0x21,
- 0x78, 0x4e, 0xf0, 0xc8, 0x32, 0x4b, 0xf8, 0x89, 0xf7, 0xc5, 0x2b, 0x17,
- 0xfd, 0x9f, 0xfb, 0xc3, 0xd9, 0xf5, 0x8b, 0xf1, 0x67, 0xdf, 0xcb, 0x17,
- 0xb6, 0xf3, 0xa5, 0x8a, 0xdc, 0x3c, 0x8f, 0x93, 0xdf, 0xe6, 0x70, 0x6b,
- 0x42, 0xfa, 0xc5, 0xfd, 0x26, 0xe1, 0x31, 0xab, 0x17, 0xf6, 0x7b, 0x77,
- 0xd9, 0xf5, 0x8a, 0x94, 0xda, 0x20, 0x5f, 0x90, 0x81, 0xf9, 0x29, 0x1a,
- 0x70, 0xba, 0xfe, 0x8e, 0x29, 0xe0, 0xbb, 0x58, 0xbf, 0xc1, 0x93, 0x9b,
- 0xad, 0x4a, 0xc5, 0x49, 0xf3, 0xb9, 0x95, 0xff, 0xfd, 0xd0, 0x4d, 0x39,
- 0x37, 0x82, 0x6a, 0x7c, 0x4e, 0x05, 0x8b, 0xb6, 0x08, 0x2c, 0x5e, 0x7c,
- 0x25, 0x8b, 0xff, 0xbc, 0x52, 0x07, 0xf0, 0x03, 0x28, 0x2c, 0x5f, 0x86,
- 0xd1, 0x34, 0xac, 0x5f, 0xb3, 0xdb, 0x39, 0xe5, 0x8b, 0xcd, 0xad, 0xae,
- 0x7a, 0x64, 0x51, 0x7f, 0xff, 0xb9, 0x9d, 0x6e, 0xf8, 0x5d, 0xc3, 0x9c,
- 0xf4, 0xcf, 0xb8, 0xb1, 0x7e, 0xf4, 0xcf, 0xb8, 0xb1, 0x7d, 0x33, 0xee,
- 0x2c, 0x5e, 0xee, 0x1c, 0xe1, 0xe5, 0x78, 0xa2, 0xb1, 0x1c, 0xe2, 0x85,
- 0x95, 0x7d, 0x34, 0x1f, 0x46, 0x35, 0x41, 0x47, 0x40, 0x95, 0xb0, 0x23,
- 0xec, 0x70, 0xc2, 0x99, 0x52, 0x31, 0xb1, 0x42, 0x16, 0x43, 0x8c, 0xc3,
- 0x25, 0x45, 0xf5, 0x1e, 0x9f, 0x71, 0x8d, 0xb4, 0x22, 0xe2, 0x8f, 0xeb,
- 0x52, 0x81, 0xff, 0x1f, 0x93, 0xc7, 0xa8, 0x08, 0x68, 0x94, 0xe0, 0xd7,
- 0x25, 0x23, 0x7a, 0x3f, 0x51, 0x43, 0x07, 0x79, 0x01, 0x8b, 0xfb, 0x23,
- 0xa1, 0x8d, 0xee, 0xc7, 0xb3, 0x78, 0x3f, 0xfd, 0x62, 0xed, 0xdf, 0xac,
- 0x5f, 0xb5, 0xd3, 0xbf, 0x4a, 0x88, 0xb8, 0xbd, 0xa1, 0x7d, 0x62, 0xfd,
- 0xe0, 0x06, 0x50, 0x48, 0xbf, 0x73, 0xdf, 0x90, 0x2c, 0x5f, 0x9e, 0x39,
- 0xd0, 0x96, 0x2c, 0x12, 0x53, 0x0b, 0x8c, 0x7f, 0x06, 0xf4, 0x6e, 0xe3,
- 0xc2, 0x2a, 0xd9, 0x29, 0xbf, 0x10, 0xa1, 0x9c, 0x58, 0xbd, 0xb2, 0xc0,
- 0x58, 0xbc, 0x44, 0x35, 0x8b, 0xa0, 0x13, 0x0f, 0x91, 0x8a, 0x08, 0x82,
- 0x82, 0x2b, 0xef, 0x84, 0xae, 0x3e, 0xe1, 0xa5, 0x7f, 0xf1, 0xde, 0x01,
- 0x33, 0x5d, 0x3b, 0xf4, 0xa8, 0x99, 0x8b, 0xff, 0x86, 0x10, 0x84, 0xe1,
- 0x8f, 0xec, 0x6a, 0xc5, 0xff, 0xed, 0x88, 0x0f, 0xef, 0x7f, 0x08, 0x9f,
- 0xcb, 0x17, 0xbe, 0xdc, 0x58, 0xbe, 0x0a, 0xf2, 0x7c, 0xb1, 0x7f, 0x4f,
- 0x0a, 0x7d, 0xc5, 0x8a, 0xd8, 0x67, 0xa8, 0x72, 0x7a, 0x0a, 0x23, 0x9f,
- 0x60, 0x4e, 0x0b, 0x1c, 0x6f, 0xde, 0xd0, 0xa7, 0x7a, 0xc5, 0xff, 0x8d,
- 0x9c, 0xd6, 0xdc, 0x16, 0xa3, 0x58, 0xa0, 0xa9, 0xf7, 0x05, 0x85, 0x77,
- 0xd8, 0x2d, 0x46, 0xb1, 0x76, 0xc8, 0x51, 0x62, 0xe3, 0x3c, 0xb1, 0x5b,
- 0x19, 0xee, 0x6c, 0x32, 0x41, 0x8f, 0xdf, 0xc1, 0x6c, 0x28, 0x14, 0x0a,
- 0xf2, 0x56, 0x2d, 0x12, 0xc5, 0xd3, 0xc5, 0x8b, 0xb6, 0x38, 0x2c, 0x56,
- 0xc3, 0x44, 0x44, 0x68, 0x3d, 0x89, 0xc4, 0x2f, 0x73, 0xf1, 0x62, 0xff,
- 0x3f, 0x7c, 0x72, 0x16, 0x2c, 0x5f, 0xfa, 0x19, 0xff, 0xbc, 0x19, 0x89,
- 0x62, 0xb4, 0x88, 0x70, 0x0b, 0xf8, 0xce, 0xed, 0x90, 0xa2, 0xc5, 0xfb,
- 0x8c, 0x4f, 0x1a, 0xc5, 0xff, 0xbe, 0xde, 0xe3, 0xf7, 0x1e, 0x18, 0xb1,
- 0x7f, 0xed, 0xf3, 0xf6, 0x98, 0xa2, 0x9e, 0x96, 0x28, 0x2a, 0x8f, 0xcd,
- 0x8c, 0xc3, 0x61, 0x0f, 0xf4, 0x50, 0xc8, 0x57, 0x31, 0xd6, 0x2f, 0xde,
- 0x26, 0xef, 0xcb, 0x15, 0xd1, 0xe0, 0x06, 0x2f, 0x7f, 0xc1, 0x40, 0x1c,
- 0x3d, 0x34, 0x72, 0xb1, 0x78, 0x29, 0xf8, 0x96, 0x2f, 0x79, 0xc9, 0x62,
- 0x82, 0x86, 0xff, 0x63, 0x23, 0xbe, 0xd8, 0x82, 0xd7, 0x92, 0xb1, 0x61,
- 0x2c, 0x50, 0x5b, 0x3c, 0x16, 0x2f, 0xbb, 0x64, 0x28, 0xb1, 0x7f, 0xff,
- 0xff, 0x05, 0xfb, 0x9d, 0x85, 0xb0, 0xc7, 0xd6, 0xfd, 0x42, 0x2d, 0xe2,
- 0x0b, 0x61, 0x60, 0x5c, 0x2d, 0x42, 0xde, 0xdd, 0xbf, 0xd9, 0x58, 0xbf,
- 0xf1, 0x4c, 0x7a, 0x7f, 0xc9, 0xd9, 0x62, 0xfb, 0x01, 0x20, 0x58, 0xbf,
- 0xc4, 0xf1, 0x66, 0xf9, 0xe2, 0xc5, 0xfd, 0xcd, 0x4e, 0x7b, 0x8b, 0x16,
- 0x12, 0xc5, 0x49, 0xe0, 0x61, 0x75, 0xff, 0x72, 0x43, 0xfb, 0x42, 0x4e,
- 0xb1, 0x7e, 0x03, 0x0f, 0x37, 0x16, 0x2f, 0xe1, 0xb9, 0xf5, 0x3c, 0x58,
- 0xac, 0x3d, 0x97, 0x2b, 0xbf, 0xf6, 0xf1, 0x3f, 0x43, 0x6d, 0xf2, 0x35,
- 0x8b, 0xfa, 0x4e, 0xf0, 0x9f, 0x2c, 0x5f, 0xfd, 0x27, 0x7f, 0x67, 0x60,
- 0x38, 0x7f, 0x58, 0xbf, 0xfd, 0xd6, 0x85, 0x1f, 0x7c, 0x6d, 0x75, 0xfc,
- 0x58, 0xbe, 0x6d, 0xee, 0x05, 0x8a, 0x93, 0xf4, 0xf2, 0x85, 0x0d, 0x36,
- 0xdc, 0x20, 0x35, 0x13, 0xe5, 0xa5, 0x0b, 0xbb, 0xe6, 0x8c, 0x44, 0xb1,
- 0x7e, 0xc8, 0xf0, 0x11, 0x2c, 0x56, 0xd3, 0xcd, 0xf1, 0x1d, 0xf9, 0xb7,
- 0x4d, 0x6e, 0x96, 0x2f, 0xf8, 0x50, 0xe3, 0x9d, 0xc8, 0x0b, 0x15, 0xa3,
- 0xe6, 0x72, 0xdb, 0xfa, 0x79, 0xb5, 0x9e, 0x25, 0x8b, 0xfd, 0xb7, 0x09,
- 0xf4, 0x0d, 0x95, 0x8b, 0x8a, 0x0b, 0x17, 0xb5, 0x26, 0xac, 0x5f, 0xff,
- 0x3f, 0xf3, 0xb0, 0x7c, 0xc7, 0xfc, 0x5f, 0x12, 0xc5, 0x32, 0x22, 0x62,
- 0x17, 0x38, 0xf5, 0xfe, 0x1e, 0x9c, 0x0f, 0x9a, 0x58, 0xbf, 0xb3, 0x92,
- 0x19, 0x4a, 0xc5, 0x0d, 0x35, 0x1c, 0x86, 0x0b, 0x18, 0x7c, 0xce, 0xd8,
- 0xb1, 0x73, 0x9d, 0x62, 0xb8, 0x6a, 0x37, 0x44, 0x6e, 0xdd, 0xf2, 0xc5,
- 0x82, 0xeb, 0x16, 0x04, 0x9b, 0x11, 0x0d, 0xde, 0x3b, 0xf9, 0x62, 0xc1,
- 0x75, 0x8a, 0xc3, 0x66, 0x43, 0xb7, 0xed, 0x91, 0x93, 0x98, 0xb1, 0x52,
- 0x79, 0x7e, 0x1f, 0xbf, 0xff, 0xba, 0x29, 0x3e, 0xd9, 0xd6, 0x9b, 0x7e,
- 0x9d, 0xc0, 0xb1, 0x7e, 0x83, 0xf9, 0xcd, 0x58, 0xa9, 0x44, 0x46, 0x2f,
- 0xdf, 0x16, 0x02, 0x56, 0x28, 0x8f, 0x0b, 0x79, 0x0d, 0xe1, 0xe0, 0xd6,
- 0x29, 0x62, 0xfb, 0x3d, 0x80, 0x58, 0xb1, 0xa0, 0x35, 0xc4, 0x19, 0x58,
- 0x7e, 0x4e, 0x97, 0x7f, 0x31, 0x8d, 0xcc, 0xe9, 0x62, 0x99, 0x1c, 0x9a,
- 0x84, 0xaf, 0x08, 0x2f, 0x9b, 0xd3, 0x05, 0x8b, 0xc7, 0x98, 0x2c, 0x5f,
- 0x36, 0xf9, 0xd2, 0xc5, 0xee, 0x3c, 0x4b, 0x15, 0x27, 0xbf, 0xf1, 0xdf,
- 0x12, 0x5f, 0xc1, 0x22, 0x0a, 0xfd, 0xc9, 0x62, 0x82, 0x8c, 0xae, 0xed,
- 0x86, 0x3f, 0x1c, 0x32, 0x46, 0x7d, 0x84, 0x5d, 0x3a, 0xf6, 0x40, 0xd2,
- 0x80, 0x22, 0x84, 0xe6, 0xa1, 0x14, 0x72, 0x1f, 0xc7, 0x02, 0xed, 0x20,
- 0x55, 0x28, 0x52, 0x7a, 0x3c, 0xfd, 0xe6, 0x81, 0xc2, 0x07, 0x74, 0xba,
- 0xf9, 0xe0, 0x19, 0xd6, 0x2f, 0x74, 0x40, 0x58, 0xb6, 0xb4, 0x78, 0x5c,
- 0x24, 0xbc, 0xe5, 0xd2, 0xc5, 0xef, 0x14, 0xac, 0x5f, 0x11, 0x67, 0x96,
- 0x28, 0x2a, 0x6f, 0x64, 0x72, 0xb8, 0x7f, 0xc6, 0x2d, 0x5f, 0x3f, 0xda,
- 0x25, 0x8b, 0xe2, 0x8a, 0x46, 0xb1, 0x77, 0x7e, 0x58, 0xbe, 0xfc, 0x52,
- 0x35, 0x8b, 0xda, 0x8c, 0x6b, 0x17, 0xed, 0x48, 0x6e, 0x4b, 0x14, 0x33,
- 0xc7, 0x00, 0xfd, 0x4a, 0x76, 0xb9, 0x0a, 0x6e, 0x88, 0xd8, 0x8e, 0x22,
- 0x37, 0x19, 0x13, 0x5d, 0xef, 0xcf, 0x6b, 0x17, 0xe9, 0x39, 0x64, 0x4b,
- 0x17, 0xf3, 0x61, 0x0f, 0xf2, 0xb1, 0x63, 0xac, 0x58, 0xeb, 0x17, 0x49,
- 0x2c, 0x54, 0x66, 0xa0, 0xc1, 0x2a, 0x1a, 0x2c, 0x7a, 0x28, 0xdc, 0x2c,
- 0xe1, 0xd5, 0x2c, 0x5d, 0x3c, 0x58, 0xbf, 0xb5, 0x24, 0x2c, 0xfa, 0xc5,
- 0xff, 0x3f, 0x78, 0xdd, 0x74, 0xe3, 0x58, 0xbe, 0xd4, 0xe1, 0x2c, 0x5f,
- 0x3f, 0xa0, 0x05, 0x8b, 0xde, 0xe6, 0x2c, 0x5f, 0xe1, 0x1c, 0xb2, 0x26,
- 0x8d, 0x62, 0xc2, 0x58, 0xbf, 0xcd, 0xd3, 0xe6, 0xb3, 0xcb, 0x14, 0x03,
- 0xc5, 0xe0, 0x95, 0xfe, 0x7d, 0x34, 0xee, 0x31, 0xd6, 0x2f, 0x08, 0x28,
- 0x4b, 0x14, 0x6a, 0x7a, 0x5d, 0x0b, 0xe8, 0xb4, 0xe7, 0x7f, 0x21, 0x72,
- 0x3e, 0x0e, 0xf9, 0xeb, 0x79, 0x16, 0xe9, 0xad, 0xff, 0x6a, 0x72, 0x13,
- 0xf9, 0x02, 0xc5, 0xff, 0xed, 0xbf, 0x76, 0xf0, 0x04, 0x44, 0xf0, 0x58,
- 0xbf, 0x34, 0x50, 0x10, 0xd6, 0x2f, 0xf8, 0x33, 0xe7, 0x1d, 0xfb, 0x82,
- 0xc5, 0xc1, 0x40, 0xaa, 0xc5, 0xff, 0x7e, 0x58, 0x6d, 0xc8, 0xdd, 0x62,
- 0xb6, 0x11, 0xec, 0xb1, 0x05, 0x41, 0x73, 0xa3, 0x21, 0x9f, 0xd2, 0x0b,
- 0x47, 0xbd, 0xa8, 0x49, 0x1c, 0xe3, 0xe9, 0x60, 0x2a, 0x28, 0x4a, 0x5f,
- 0xff, 0xff, 0xff, 0xfe, 0xd8, 0x41, 0x5c, 0xd8, 0x5b, 0x1e, 0xc3, 0xd8,
- 0x7d, 0x05, 0xe4, 0x2d, 0x76, 0x3d, 0x47, 0xbb, 0x82, 0x18, 0x5b, 0x9d,
- 0x9e, 0xc3, 0xfe, 0xc7, 0x33, 0xb1, 0xee, 0x05, 0x9e, 0xdb, 0xb7, 0xfb,
- 0x2b, 0x17, 0xff, 0xda, 0xf9, 0x8e, 0x3c, 0x8c, 0x5e, 0xd6, 0xa5, 0x62,
- 0xff, 0xfb, 0xb8, 0x7c, 0x53, 0xa0, 0x9f, 0x6e, 0x9f, 0x4b, 0x14, 0xe8,
- 0xa8, 0x02, 0x9d, 0xb8, 0xb1, 0x78, 0x5a, 0x02, 0xc5, 0xc2, 0x86, 0xd3,
- 0x61, 0xd0, 0x95, 0xff, 0xbf, 0x85, 0x86, 0xe1, 0x60, 0xd6, 0x2f, 0xfe,
- 0xec, 0xc9, 0xf0, 0xdb, 0x73, 0x92, 0x75, 0x8b, 0xee, 0x67, 0x7e, 0x58,
- 0xbe, 0xc8, 0xa4, 0xc5, 0x8b, 0xf0, 0xff, 0x25, 0x1a, 0xc5, 0xf3, 0x17,
- 0xb8, 0xb1, 0x7f, 0xff, 0xc7, 0x6d, 0x7c, 0x5c, 0x84, 0xef, 0xd4, 0x97,
- 0xbf, 0x90, 0x58, 0xa8, 0x22, 0x2d, 0x88, 0xaf, 0xfc, 0xde, 0x6e, 0x98,
- 0x7e, 0xce, 0x96, 0x2a, 0x35, 0x42, 0xb0, 0x30, 0xc3, 0xdd, 0x25, 0x7c,
- 0x90, 0x89, 0x3d, 0x0b, 0x4d, 0xd2, 0x2b, 0x8e, 0x35, 0x8b, 0xf1, 0x3e,
- 0x9e, 0x0b, 0x17, 0x36, 0xf5, 0x8a, 0x93, 0xc0, 0x19, 0x3d, 0xe9, 0x1c,
- 0xac, 0x5f, 0xb3, 0xff, 0xc0, 0x2c, 0x5b, 0xa3, 0x9e, 0x21, 0x0e, 0x5f,
- 0x39, 0x8f, 0xb8, 0xb1, 0x4e, 0x79, 0xc4, 0x51, 0x7e, 0x17, 0x5f, 0x63,
- 0x16, 0x2f, 0xbd, 0xb3, 0x9f, 0x58, 0xbf, 0xff, 0xce, 0x5d, 0x16, 0x0f,
- 0xe2, 0xdb, 0xf9, 0x86, 0xa6, 0x35, 0x8a, 0xc4, 0x45, 0x08, 0x9a, 0xe9,
- 0xfa, 0xc5, 0xfc, 0x19, 0x4f, 0xe6, 0x0b, 0x17, 0xff, 0xf1, 0xa5, 0x80,
- 0x17, 0x36, 0xc1, 0xbf, 0x3d, 0x13, 0xac, 0x51, 0xa8, 0xa3, 0x38, 0xbb,
- 0x97, 0x5f, 0xf3, 0x75, 0x14, 0x3f, 0x24, 0x6a, 0xc5, 0xe9, 0x3f, 0x96,
- 0x28, 0x8f, 0x64, 0xc3, 0xcb, 0xfd, 0x86, 0x4f, 0x89, 0xf8, 0xb1, 0x79,
- 0xbe, 0xcb, 0x15, 0x27, 0xe2, 0xc4, 0x5e, 0x33, 0xba, 0x49, 0x62, 0xfb,
- 0x3a, 0x1e, 0x2c, 0x5f, 0x10, 0xc3, 0xed, 0x62, 0xe1, 0x79, 0x62, 0xf3,
- 0xea, 0x1b, 0x4f, 0x81, 0xc8, 0xf6, 0x49, 0x6b, 0x63, 0x64, 0xa0, 0xcc,
- 0x7b, 0x59, 0x29, 0x9c, 0xd7, 0xa6, 0x58, 0xd4, 0x2c, 0xce, 0x41, 0xf8,
- 0x5a, 0xbc, 0x31, 0x4a, 0x1f, 0x5e, 0x2d, 0x13, 0xb5, 0xfe, 0x35, 0xf7,
- 0xf5, 0x9d, 0xf9, 0x62, 0xe7, 0x1a, 0xc5, 0xdb, 0xf7, 0x16, 0x28, 0xd3,
- 0xed, 0xd1, 0xcb, 0x8b, 0xdf, 0xff, 0xb5, 0xa6, 0xcd, 0xe4, 0x2e, 0x6d,
- 0xe0, 0x9f, 0x8b, 0x14, 0xb1, 0x7f, 0xfd, 0xc6, 0xd9, 0xce, 0xbe, 0xc4,
- 0x42, 0xd4, 0x6b, 0x15, 0xa3, 0xe0, 0xf0, 0x65, 0xfd, 0xec, 0x3f, 0x78,
- 0x75, 0x8a, 0x94, 0xc2, 0xf2, 0x17, 0x4c, 0x45, 0x7f, 0x8e, 0x77, 0x87,
- 0x1a, 0x0b, 0x17, 0xf8, 0xdd, 0xb3, 0xd8, 0x35, 0x2b, 0x15, 0x87, 0xd8,
- 0xe6, 0x94, 0xc9, 0xfc, 0xfe, 0x33, 0xa2, 0x84, 0xfd, 0xff, 0xed, 0xf8,
- 0x3f, 0xce, 0xf3, 0xc9, 0x38, 0x6b, 0x16, 0x89, 0x62, 0xb0, 0xf8, 0x44,
- 0x9d, 0x7f, 0xd0, 0xeb, 0xec, 0x64, 0x90, 0xd6, 0x2f, 0xe1, 0xbc, 0x38,
- 0xd0, 0x58, 0xad, 0x22, 0x29, 0xc8, 0x44, 0x77, 0x7c, 0x22, 0xf7, 0x16,
- 0x2f, 0xee, 0x09, 0x89, 0xb8, 0xb1, 0x7a, 0x75, 0x2b, 0x15, 0xb4, 0xf2,
- 0x7e, 0x5b, 0x5d, 0x22, 0x43, 0x4d, 0x97, 0xa1, 0xb2, 0x62, 0xc5, 0xc0,
- 0x65, 0x8b, 0xf1, 0xe1, 0xf0, 0xf8, 0xb1, 0x6d, 0x6d, 0x3c, 0x20, 0xc5,
- 0xef, 0xce, 0x61, 0x60, 0xd6, 0x2a, 0x51, 0x6e, 0xcc, 0x9a, 0x2b, 0xbf,
- 0xf1, 0x4f, 0x46, 0xbe, 0x69, 0x80, 0xb1, 0x7f, 0x73, 0x1b, 0x5a, 0x75,
- 0x8b, 0xf7, 0x36, 0x81, 0xfc, 0xb1, 0x51, 0xa2, 0x5c, 0x07, 0xfe, 0x2d,
- 0xba, 0x74, 0xb1, 0x7f, 0xf4, 0x79, 0xc6, 0x7f, 0x84, 0x30, 0xc3, 0x12,
- 0x2c, 0xc0, 0x3e, 0x22, 0x17, 0xbf, 0xe1, 0x3e, 0xb6, 0x45, 0xf6, 0xd2,
- 0xc5, 0x4a, 0x3d, 0x87, 0x09, 0x3f, 0x93, 0x5f, 0xdd, 0xe7, 0xc5, 0xd8,
- 0x16, 0x2d, 0xf5, 0x8b, 0xf8, 0xfc, 0xfc, 0x97, 0x96, 0x2f, 0xb5, 0x3e,
- 0xe2, 0xc5, 0xe8, 0xfe, 0x25, 0x8b, 0xff, 0x7d, 0xf9, 0xfc, 0xdf, 0x9e,
- 0xe2, 0xc5, 0x49, 0xf0, 0x38, 0xfd, 0x32, 0x34, 0x62, 0x2e, 0xfc, 0x20,
- 0xef, 0xcc, 0x2e, 0x9a, 0x35, 0x8a, 0xc4, 0xdc, 0xfa, 0x31, 0xf4, 0x38,
- 0xf6, 0x4d, 0x6f, 0xff, 0x3f, 0x85, 0xb7, 0x9f, 0x61, 0x94, 0xee, 0x2c,
- 0x5f, 0xec, 0x93, 0x5f, 0xce, 0x6a, 0xc5, 0x01, 0x10, 0x64, 0x9f, 0x7f,
- 0x40, 0x3f, 0x72, 0x7c, 0xb1, 0x7f, 0x8f, 0x9d, 0x13, 0xe7, 0x4b, 0x17,
- 0x0a, 0x25, 0x8b, 0xa1, 0xc9, 0x3c, 0xd0, 0x1a, 0x5f, 0x1f, 0x81, 0xf1,
- 0x62, 0xf7, 0x42, 0xe9, 0x62, 0xa5, 0x1d, 0xfd, 0xbe, 0xb1, 0x68, 0x89,
- 0x6f, 0xfb, 0xde, 0x93, 0xe6, 0x11, 0xab, 0x17, 0xff, 0xde, 0xfe, 0x6e,
- 0xfb, 0x3e, 0x59, 0xef, 0xb2, 0xc5, 0x76, 0x88, 0xb2, 0x39, 0xbf, 0x89,
- 0xfd, 0x09, 0x35, 0x62, 0xff, 0x60, 0x06, 0x27, 0xd4, 0x16, 0x2a, 0x4f,
- 0x8a, 0x32, 0xeb, 0xf9, 0xdc, 0x7b, 0xf0, 0x6b, 0x17, 0xcd, 0xb8, 0xfc,
- 0x58, 0xb9, 0xfa, 0x54, 0x59, 0xe5, 0x7c, 0xf2, 0x9c, 0x96, 0xff, 0x49,
- 0x1b, 0xa1, 0x49, 0x2c, 0x5f, 0xc0, 0x72, 0x83, 0x1d, 0x62, 0xa5, 0x3a,
- 0x18, 0xe1, 0x0a, 0x32, 0x2e, 0x9e, 0x58, 0x84, 0x06, 0x77, 0xfb, 0xfe,
- 0xe3, 0xf6, 0x19, 0xd6, 0x2f, 0xf4, 0xc1, 0xbd, 0x3e, 0xe2, 0xc5, 0xfe,
- 0xe0, 0x8e, 0xde, 0x03, 0xac, 0x5e, 0x0f, 0xf2, 0xb1, 0x50, 0x3d, 0x20,
- 0x1a, 0x5e, 0x18, 0xdd, 0x62, 0xbe, 0x8c, 0x42, 0x84, 0x2f, 0x88, 0xaf,
- 0xe8, 0x07, 0x9f, 0x7e, 0xd6, 0x2a, 0x53, 0x5f, 0x68, 0x7d, 0xb9, 0xa5,
- 0xff, 0x1a, 0xe5, 0x9b, 0xcb, 0x38, 0xb1, 0x7f, 0x6f, 0x2c, 0xe6, 0x12,
- 0xc5, 0xb7, 0x16, 0x2b, 0x0f, 0x0f, 0x85, 0xd7, 0x9a, 0x12, 0xb1, 0x67,
- 0xda, 0x6f, 0x78, 0x43, 0x6d, 0x1a, 0x8e, 0x2f, 0xc2, 0xea, 0xff, 0x30,
- 0xf0, 0xe6, 0x67, 0xd6, 0x2d, 0x1a, 0xc5, 0xff, 0xff, 0x67, 0xb9, 0x9d,
- 0x39, 0x03, 0x6e, 0xa4, 0x85, 0xe9, 0xfa, 0xc5, 0xfb, 0x83, 0x69, 0x25,
- 0x8a, 0x94, 0x6b, 0x1c, 0xd0, 0x84, 0xfc, 0xd1, 0x6d, 0x2c, 0x5f, 0xfb,
- 0xcd, 0x11, 0x8e, 0x39, 0xef, 0x8b, 0x14, 0xe7, 0xa9, 0xc1, 0x2a, 0x64,
- 0xed, 0x5e, 0x30, 0x51, 0x42, 0x3e, 0xff, 0x43, 0x93, 0x0e, 0x31, 0x2c,
- 0x5c, 0x00, 0x2c, 0x5e, 0x30, 0xc3, 0x12, 0x2f, 0xfa, 0x1c, 0x2c, 0xe8,
- 0x79, 0xa4, 0x80, 0x86, 0x86, 0xd0, 0x58, 0xa9, 0x46, 0x53, 0x19, 0xb9,
- 0xcf, 0x93, 0x2f, 0xfa, 0x03, 0xfc, 0x94, 0xe1, 0x8b, 0x17, 0xed, 0xd1,
- 0x1f, 0x06, 0xb1, 0x7f, 0xfd, 0xbc, 0x85, 0x0c, 0xde, 0xde, 0x9e, 0xb3,
- 0xeb, 0x17, 0xff, 0xf0, 0x8b, 0xdc, 0x92, 0x37, 0xed, 0xb7, 0xf8, 0x07,
- 0x58, 0xbf, 0x66, 0xfd, 0xb0, 0x3a, 0xc5, 0xbd, 0x28, 0xde, 0x82, 0xa7,
- 0xd7, 0x6a, 0x53, 0x78, 0xc3, 0x91, 0x46, 0x15, 0x7f, 0xee, 0xe0, 0x42,
- 0x06, 0xde, 0x8e, 0x05, 0x8b, 0xa4, 0xd5, 0x8b, 0xfe, 0x1c, 0x94, 0x82,
- 0x1f, 0x65, 0x8b, 0xde, 0x68, 0xd6, 0x2f, 0xff, 0x77, 0x90, 0x21, 0x3f,
- 0x3f, 0x80, 0x75, 0x8a, 0x34, 0xfa, 0x1c, 0x7a, 0xa5, 0x31, 0xf8, 0xd1,
- 0x58, 0x60, 0x50, 0xa0, 0xbf, 0xdf, 0x61, 0x93, 0xbc, 0x4b, 0x17, 0xf8,
- 0x7f, 0x13, 0x83, 0x67, 0x16, 0x2f, 0x9c, 0x13, 0xa5, 0x8b, 0xff, 0xfd,
- 0x9a, 0xd3, 0x48, 0x36, 0xf5, 0xf6, 0x90, 0x14, 0x81, 0x62, 0xa5, 0x1d,
- 0xcc, 0x67, 0xc3, 0x7f, 0x11, 0x5f, 0x4f, 0xb2, 0x35, 0x8b, 0xe8, 0x00,
- 0x12, 0xb1, 0x7f, 0xa7, 0x6f, 0xb3, 0x9c, 0x95, 0x8b, 0xf8, 0x61, 0x8c,
- 0x5e, 0xe2, 0xc5, 0xb6, 0x56, 0x2f, 0xf4, 0xf9, 0xb7, 0xc9, 0x74, 0xb1,
- 0x7d, 0x38, 0x50, 0x63, 0xca, 0xe0, 0xad, 0x1a, 0x99, 0x67, 0x64, 0x7a,
- 0x23, 0x23, 0x5f, 0x3d, 0xdf, 0xd9, 0xc8, 0x7c, 0x3e, 0x2c, 0x53, 0x1f,
- 0xe1, 0x26, 0x5e, 0x92, 0x35, 0x62, 0xff, 0xd2, 0x72, 0xcf, 0x70, 0x5a,
- 0x82, 0xc5, 0x41, 0xb6, 0x82, 0x1c, 0x64, 0xb9, 0x0b, 0xf3, 0x61, 0xb7,
- 0xd4, 0x77, 0x7d, 0xc7, 0x4e, 0xd0, 0xc9, 0x8a, 0x31, 0x1d, 0x4a, 0x68,
- 0x3c, 0x77, 0x9f, 0x95, 0x94, 0x08, 0xc1, 0x0a, 0x3b, 0x2e, 0x46, 0xa9,
- 0xe8, 0xcc, 0x37, 0xc7, 0xc6, 0x19, 0x06, 0xe8, 0xed, 0xff, 0x66, 0x8b,
- 0x37, 0xbe, 0xa0, 0xb1, 0x70, 0x38, 0xb1, 0x7b, 0x5b, 0x06, 0xea, 0xc5,
- 0xcf, 0x05, 0x8b, 0xf1, 0x7b, 0x00, 0x75, 0x8b, 0xed, 0x34, 0xf9, 0x62,
- 0xfe, 0xe1, 0x64, 0x52, 0x75, 0x8a, 0x01, 0xe8, 0x78, 0x8a, 0x99, 0x1a,
- 0xe7, 0x26, 0x71, 0x71, 0x3c, 0x5d, 0x3e, 0x58, 0xbe, 0x03, 0x99, 0xe5,
- 0x8b, 0xfc, 0xe6, 0x7d, 0xa7, 0x52, 0xb1, 0x7f, 0x08, 0xfc, 0x16, 0xa3,
- 0x58, 0xbf, 0x36, 0xf9, 0x2f, 0x2c, 0x54, 0xaa, 0x2c, 0x19, 0xd1, 0xb0,
- 0xef, 0xec, 0xed, 0x85, 0xf4, 0x48, 0x46, 0x7c, 0x31, 0xbf, 0xf6, 0x9b,
- 0x90, 0x0f, 0xf2, 0x52, 0xb1, 0x79, 0xa4, 0xeb, 0x17, 0x37, 0xd6, 0x2b,
- 0x46, 0xcf, 0x64, 0x72, 0xff, 0xfd, 0xe3, 0x45, 0x38, 0x3f, 0xe7, 0x3b,
- 0x84, 0xfd, 0x62, 0xb4, 0x8e, 0xe3, 0xb9, 0x11, 0x25, 0xfe, 0xda, 0x59,
- 0xbc, 0xb3, 0x8b, 0x17, 0xc0, 0x16, 0xa3, 0x58, 0xbd, 0x10, 0xb4, 0xb1,
- 0x73, 0xc1, 0x62, 0xfe, 0xe4, 0xf7, 0xb0, 0xc6, 0x75, 0x8b, 0xf8, 0xf8,
- 0x5e, 0xd9, 0xc5, 0x8b, 0xff, 0xfd, 0x9e, 0x10, 0x0e, 0xf0, 0x71, 0xc9,
- 0x3e, 0x9e, 0x0b, 0x17, 0xf1, 0x39, 0x9e, 0xcf, 0xe2, 0x23, 0xc8, 0xc2,
- 0xff, 0x67, 0xfe, 0x2f, 0x39, 0x2c, 0x5c, 0xc3, 0x58, 0xbf, 0xbf, 0xd3,
- 0xe9, 0xe0, 0xb1, 0x6e, 0xa0, 0x78, 0xd8, 0x2f, 0x79, 0xa2, 0xe2, 0xc5,
- 0x49, 0xe3, 0x1c, 0xa2, 0xff, 0xef, 0x37, 0xdc, 0xfb, 0x22, 0xfb, 0x69,
- 0x62, 0xfe, 0x7f, 0x1e, 0x73, 0xcb, 0x14, 0xe7, 0xea, 0x24, 0x8b, 0x71,
- 0x62, 0xfe, 0x90, 0x37, 0xd8, 0xeb, 0x15, 0x26, 0xfd, 0x84, 0xaf, 0x16,
- 0x74, 0xb1, 0x5f, 0x37, 0x9c, 0x1f, 0xa1, 0xab, 0x31, 0xec, 0x5e, 0x28,
- 0x62, 0xe9, 0x0c, 0xf0, 0xbf, 0x28, 0x4b, 0x7a, 0x13, 0x97, 0xdf, 0xed,
- 0xf7, 0x16, 0x2f, 0xdf, 0x73, 0xb7, 0x16, 0x28, 0x67, 0x9f, 0xd1, 0x3d,
- 0x62, 0xe1, 0xeb, 0x4b, 0x50, 0x78, 0x65, 0x5f, 0x9b, 0xee, 0x76, 0x58,
- 0xbc, 0x00, 0xfc, 0xb1, 0x79, 0xc8, 0x0b, 0x15, 0xb4, 0xf8, 0xb0, 0x9f,
- 0xa1, 0xfb, 0xdb, 0xf0, 0x6b, 0x16, 0xd4, 0x67, 0xa1, 0x11, 0x8d, 0xcf,
- 0xf5, 0x8b, 0xe8, 0xa0, 0xe4, 0xb1, 0x5a, 0x37, 0x5c, 0x17, 0xbf, 0xdb,
- 0xba, 0xcd, 0xd2, 0x11, 0x8b, 0x15, 0x19, 0xee, 0x18, 0x43, 0x7b, 0x75,
- 0x86, 0xb1, 0x58, 0x78, 0x8e, 0x49, 0x52, 0xbd, 0xb3, 0x19, 0x7b, 0x1b,
- 0x7e, 0x71, 0x89, 0xe1, 0xdc, 0x51, 0x82, 0x5f, 0xc7, 0xeb, 0x6e, 0x1f,
- 0x8b, 0x17, 0xff, 0xff, 0xc0, 0xe6, 0x61, 0x1a, 0x1e, 0x8a, 0x73, 0xe1,
- 0x38, 0x59, 0x19, 0xf0, 0xeb, 0x17, 0x6b, 0x16, 0x2e, 0xe3, 0x2c, 0x54,
- 0x66, 0xbb, 0x42, 0xf7, 0x07, 0x05, 0x8b, 0xe9, 0x20, 0xce, 0xb1, 0x58,
- 0x7b, 0xc7, 0x22, 0x0c, 0x66, 0xb1, 0x33, 0xbf, 0x46, 0x19, 0x70, 0x38,
- 0xb1, 0x7d, 0xb4, 0xa7, 0xa5, 0x8b, 0xe7, 0xfc, 0x86, 0xb1, 0x58, 0x7c,
- 0x1f, 0x18, 0xde, 0x4b, 0x7d, 0x26, 0x60, 0xd6, 0x2f, 0xff, 0x85, 0xdc,
- 0x38, 0x3f, 0xce, 0x86, 0xee, 0x62, 0xc5, 0xc1, 0x4d, 0x84, 0xb1, 0x58,
- 0x9a, 0x8b, 0x42, 0x27, 0x46, 0x04, 0x46, 0x1a, 0x9d, 0xd9, 0xe5, 0x8b,
- 0x8e, 0xcb, 0x14, 0x33, 0x5c, 0x42, 0xf7, 0xc6, 0x4f, 0x7c, 0x58, 0xbd,
- 0xe0, 0xf1, 0x62, 0xe9, 0x8d, 0x62, 0x9c, 0xdb, 0x70, 0x7a, 0xf0, 0xe6,
- 0x0b, 0x17, 0xe8, 0xa1, 0x3d, 0xf9, 0x62, 0xfe, 0xeb, 0xed, 0xbd, 0xf4,
- 0xb1, 0x69, 0x8c, 0xf7, 0x30, 0xae, 0xec, 0xfa, 0xc5, 0x3a, 0x2d, 0xc9,
- 0xe7, 0x64, 0x9e, 0xec, 0x1a, 0xc5, 0xde, 0x0b, 0xac, 0x54, 0x6b, 0x9e,
- 0x10, 0x95, 0x7d, 0x8f, 0x9f, 0x20, 0xe2, 0xdf, 0xa1, 0xaf, 0xbc, 0xc7,
- 0x64, 0x5e, 0xc1, 0x62, 0xc5, 0xfb, 0x40, 0x3b, 0x71, 0x62, 0xe9, 0xde,
- 0xb1, 0x58, 0x78, 0x5b, 0xca, 0x6f, 0x7c, 0x46, 0x2c, 0x5e, 0xfb, 0xc6,
- 0xb1, 0x78, 0x4d, 0xd2, 0xc5, 0xf7, 0x9a, 0x7b, 0x58, 0xaf, 0x9e, 0x0f,
- 0x07, 0xae, 0x17, 0x4b, 0x17, 0xfd, 0x31, 0x9d, 0xc0, 0x06, 0xfa, 0xc5,
- 0x40, 0xfd, 0x40, 0x45, 0xc1, 0x9b, 0xde, 0xc0, 0xd6, 0x2f, 0xe3, 0x8b,
- 0x9e, 0xcf, 0x2c, 0x5f, 0xe3, 0x1f, 0xac, 0x2c, 0x1a, 0xc5, 0xf9, 0xff,
- 0xdc, 0x38, 0xb1, 0x52, 0x88, 0xde, 0x17, 0x88, 0xd2, 0xfd, 0x9c, 0x04,
- 0xc4, 0xb1, 0x7e, 0xef, 0x9b, 0x75, 0x2b, 0x17, 0xf7, 0x58, 0x71, 0x73,
- 0xcb, 0x15, 0x27, 0xb8, 0x22, 0xcb, 0xd0, 0x9e, 0x2c, 0x58, 0x4b, 0x15,
- 0x03, 0x5e, 0x01, 0xdb, 0xc3, 0x17, 0x4b, 0x17, 0xc3, 0x29, 0x82, 0xc5,
- 0x49, 0xf1, 0x31, 0x0b, 0x8f, 0xde, 0xc6, 0x1a, 0xc5, 0xff, 0xe0, 0xf6,
- 0xf7, 0xe2, 0x9c, 0xdb, 0x9d, 0xf9, 0x62, 0xff, 0xa7, 0xed, 0x31, 0x45,
- 0x3d, 0x2c, 0x56, 0xc0, 0xb9, 0x07, 0x2b, 0x23, 0x23, 0x34, 0x7f, 0xb8,
- 0x6a, 0x31, 0x7c, 0x50, 0xab, 0xd1, 0x79, 0xe1, 0x0b, 0xf8, 0x59, 0x78,
- 0xb0, 0x43, 0x9b, 0xd4, 0x6f, 0xf3, 0x44, 0xe4, 0xdd, 0xf1, 0x62, 0xec,
- 0xe9, 0x62, 0xff, 0x17, 0xb8, 0x53, 0xee, 0x2c, 0x5f, 0xef, 0x96, 0x30,
- 0x24, 0x0b, 0x17, 0xe6, 0xdf, 0x85, 0xc5, 0x8b, 0xff, 0xfa, 0x7e, 0x2e,
- 0xe7, 0xdd, 0x7e, 0x74, 0x2c, 0x14, 0x4b, 0x15, 0x88, 0xed, 0x63, 0x3d,
- 0x19, 0x7c, 0xa6, 0xfd, 0xec, 0xf8, 0xb7, 0x16, 0x2f, 0xfd, 0x1f, 0xd8,
- 0xf3, 0xb9, 0xfc, 0x8d, 0x62, 0xbb, 0x3f, 0x0d, 0x16, 0x5f, 0xda, 0xcf,
- 0xfc, 0x5e, 0x58, 0xbf, 0x82, 0x73, 0xd3, 0xee, 0x2e, 0x20, 0xd2, 0xf8,
- 0xa7, 0x34, 0xa1, 0x5d, 0x1e, 0xff, 0xcf, 0xaf, 0xec, 0xd4, 0x62, 0x71,
- 0xaa, 0x20, 0xd0, 0x21, 0xa3, 0xa8, 0xd1, 0xff, 0x08, 0x58, 0xdf, 0xf7,
- 0xb8, 0xfa, 0x1e, 0x9e, 0x0b, 0x15, 0xa3, 0xe3, 0xe1, 0x4d, 0xf1, 0x7f,
- 0x3b, 0x58, 0xa9, 0x4f, 0x29, 0xa3, 0x85, 0x72, 0x2b, 0xf3, 0xf4, 0xc7,
- 0x95, 0x8b, 0xfa, 0x1f, 0x27, 0xef, 0xcb, 0x15, 0xd1, 0xeb, 0x91, 0x45,
- 0xf0, 0x64, 0xf1, 0xac, 0x5f, 0xb8, 0xda, 0x60, 0x2c, 0x56, 0x1f, 0x77,
- 0x08, 0xb7, 0x49, 0x2f, 0xde, 0xfc, 0xea, 0x35, 0x8b, 0xf4, 0xfb, 0x69,
- 0xcc, 0x58, 0xbf, 0xf4, 0x7e, 0xfc, 0xff, 0x37, 0xbc, 0x16, 0x2f, 0x1e,
- 0x7a, 0x58, 0xbe, 0x20, 0x0b, 0x8b, 0x15, 0x87, 0x83, 0xa1, 0xeb, 0xf7,
- 0x71, 0x7d, 0xfb, 0x58, 0xa9, 0x46, 0x83, 0x42, 0x0d, 0xc8, 0x6f, 0xcf,
- 0x19, 0x39, 0xab, 0x17, 0xfc, 0x3e, 0x73, 0x34, 0x3f, 0xe2, 0xc5, 0xef,
- 0xce, 0x96, 0x2f, 0xfb, 0x8e, 0x53, 0x13, 0x0e, 0x35, 0x8b, 0xfd, 0x06,
- 0x3c, 0xfc, 0x31, 0xac, 0x5f, 0xfe, 0x9c, 0x2e, 0xfd, 0x9a, 0x68, 0xdc,
- 0xeb, 0x17, 0x19, 0xf5, 0x8b, 0xb3, 0xfb, 0x51, 0xa5, 0xc3, 0xaf, 0x1a,
- 0x98, 0x95, 0x76, 0x71, 0x62, 0xbc, 0x7c, 0x5b, 0x29, 0x75, 0x04, 0xdd,
- 0x8c, 0x8d, 0x46, 0xa5, 0x3d, 0xb7, 0x8e, 0xc2, 0xff, 0xb2, 0x1f, 0xc2,
- 0x7d, 0x1a, 0xb1, 0x71, 0xcc, 0x58, 0xa0, 0x87, 0xa5, 0x03, 0x9b, 0xf4,
- 0x9f, 0xd9, 0xf5, 0x8a, 0xda, 0xc8, 0xfa, 0xd8, 0x0d, 0x26, 0x30, 0x58,
- 0x4a, 0x75, 0xc8, 0x7c, 0xb1, 0x8e, 0x8a, 0xbf, 0x0f, 0xc7, 0x32, 0x29,
- 0x40, 0x82, 0x7a, 0xdd, 0x24, 0xbf, 0x37, 0x52, 0x79, 0x58, 0xbf, 0xdd,
- 0xeb, 0x1b, 0xf2, 0x35, 0x8b, 0xfe, 0xe9, 0xb9, 0x82, 0xe9, 0xc9, 0x62,
- 0xe1, 0xca, 0xc5, 0xd9, 0x05, 0x8b, 0xff, 0xef, 0xc9, 0xf6, 0xfe, 0x5f,
- 0x43, 0x29, 0x82, 0xc5, 0x41, 0x31, 0x5c, 0x28, 0xf9, 0xa3, 0x9d, 0x70,
- 0x5c, 0x42, 0xf7, 0x60, 0x6b, 0x17, 0xf9, 0xfc, 0xf8, 0x36, 0xde, 0xb1,
- 0x7c, 0x0f, 0xc8, 0xd6, 0x2f, 0xef, 0xb1, 0x85, 0x23, 0x58, 0xbf, 0xe9,
- 0x01, 0xe7, 0x0b, 0xdc, 0x58, 0xbf, 0xee, 0x61, 0x9f, 0x73, 0xb7, 0x16,
- 0x2f, 0xd9, 0xa8, 0xc5, 0xc5, 0x8a, 0xe9, 0x32, 0x16, 0x34, 0x88, 0x8f,
- 0xe5, 0xdc, 0x38, 0xde, 0x75, 0x7e, 0x6e, 0xe0, 0xc4, 0xb1, 0x79, 0xbf,
- 0x8b, 0x17, 0xf7, 0x9c, 0xe7, 0x93, 0xac, 0x56, 0x1f, 0x97, 0x45, 0x1d,
- 0x8e, 0x52, 0xc5, 0x1c, 0xde, 0x18, 0x61, 0x7f, 0xc2, 0x8f, 0x6e, 0x7b,
- 0xf3, 0xe5, 0x8b, 0xf7, 0x04, 0x0c, 0xfa, 0xc5, 0xcd, 0x12, 0xc5, 0x4a,
- 0x28, 0x3a, 0x22, 0xf1, 0xee, 0xe9, 0x4d, 0xff, 0xc4, 0x23, 0x4e, 0x2f,
- 0x7e, 0x44, 0x17, 0x58, 0xbe, 0x3c, 0xe8, 0xd5, 0x8b, 0xec, 0x00, 0x1d,
- 0x62, 0xf0, 0x7f, 0x75, 0x8a, 0xc3, 0xe4, 0x22, 0x4d, 0x92, 0x2a, 0x8d,
- 0x1b, 0xe6, 0x42, 0xbe, 0xf8, 0x39, 0x2e, 0x96, 0x2f, 0x73, 0xf2, 0xb1,
- 0x50, 0x3c, 0x11, 0x92, 0x5f, 0x8b, 0x46, 0x3c, 0x6b, 0x15, 0x28, 0xb7,
- 0xc6, 0xb7, 0x22, 0xbe, 0xeb, 0xf2, 0x62, 0xc5, 0xfb, 0x3d, 0xc6, 0x3a,
- 0xc5, 0xc2, 0x25, 0x8b, 0xd1, 0x8b, 0xcb, 0x17, 0x8b, 0x23, 0x58, 0xa9,
- 0x5d, 0xdb, 0x82, 0xb6, 0x46, 0x72, 0xd1, 0xd4, 0xea, 0x3d, 0x60, 0xb9,
- 0x69, 0x12, 0xf0, 0xa0, 0x42, 0xe1, 0x8f, 0xdf, 0xf4, 0x9e, 0x7c, 0xc5,
- 0x90, 0x58, 0xb4, 0x16, 0x2f, 0xb8, 0x29, 0x02, 0xc5, 0xc2, 0xdd, 0x58,
- 0xad, 0x22, 0x1f, 0xe6, 0xe0, 0x12, 0x22, 0x3b, 0xb0, 0x96, 0x2f, 0xdc,
- 0x0f, 0x9f, 0x12, 0xc5, 0x7c, 0xf0, 0x7c, 0x2d, 0x7f, 0xfb, 0x4d, 0x27,
- 0xcd, 0xb9, 0xf6, 0xc3, 0xac, 0x5f, 0x37, 0x25, 0xd6, 0x2b, 0x69, 0xf5,
- 0xf1, 0x2a, 0xff, 0x61, 0x67, 0x7e, 0x81, 0xd6, 0x2e, 0xf4, 0xac, 0x54,
- 0x9e, 0x5b, 0x9a, 0x5f, 0xf3, 0xc0, 0x6c, 0x20, 0xbb, 0x69, 0x62, 0xfd,
- 0x84, 0x52, 0x35, 0x8b, 0xef, 0xbf, 0xe5, 0x62, 0xfe, 0x98, 0xce, 0xf1,
- 0x4a, 0xc5, 0xb4, 0xb1, 0x50, 0x3e, 0x38, 0x88, 0x84, 0x5f, 0x7f, 0xfc,
- 0xe6, 0xfa, 0x74, 0x0d, 0x4f, 0x89, 0xc0, 0xb1, 0x7f, 0xa7, 0xa1, 0xfc,
- 0x4f, 0xc5, 0x8b, 0x9c, 0xd5, 0x8b, 0xfa, 0x32, 0xcf, 0x6a, 0x56, 0x2f,
- 0xba, 0x0f, 0xdc, 0x58, 0xbf, 0x8b, 0x01, 0x85, 0x05, 0x8b, 0xff, 0xe3,
- 0x76, 0x86, 0x4f, 0xee, 0x37, 0x7f, 0x63, 0x16, 0x2b, 0x11, 0x04, 0xe5,
- 0x97, 0xb5, 0x26, 0xac, 0x54, 0xa6, 0x2a, 0xc5, 0xc5, 0x0a, 0x8e, 0x10,
- 0xd4, 0xae, 0x40, 0xe3, 0xeb, 0x42, 0x37, 0x4d, 0xe7, 0x20, 0xf9, 0xeb,
- 0xc2, 0x24, 0x8c, 0x38, 0xa1, 0xe3, 0x51, 0x46, 0x5b, 0x79, 0xfb, 0x02,
- 0xc5, 0xb7, 0xac, 0x54, 0x0d, 0x97, 0x07, 0xae, 0x6f, 0x2c, 0x5f, 0xd0,
- 0xc2, 0x8d, 0xb4, 0xb1, 0x7c, 0xc4, 0xe3, 0x58, 0xb8, 0x3f, 0x2c, 0x5f,
- 0xb9, 0x3a, 0xf4, 0xac, 0x50, 0xcf, 0x8b, 0x44, 0x3c, 0x19, 0xb9, 0x82,
- 0xeb, 0x17, 0x40, 0x35, 0x8b, 0xe3, 0x32, 0x0c, 0xb1, 0x7b, 0x18, 0xd5,
- 0x8b, 0xe8, 0x9d, 0xf4, 0xb1, 0x4e, 0x7c, 0x64, 0x46, 0x18, 0xed, 0xec,
- 0x6d, 0xeb, 0x17, 0xa0, 0x19, 0xd6, 0x2b, 0xe6, 0xf5, 0xc7, 0xaf, 0xee,
- 0x36, 0xb0, 0x5a, 0x58, 0xbf, 0xff, 0xa2, 0xda, 0xdd, 0x0b, 0x5c, 0x16,
- 0xd3, 0xb7, 0xbe, 0xcb, 0x17, 0x49, 0xab, 0x15, 0x27, 0xf6, 0xcc, 0x75,
- 0x8a, 0xb8, 0x8d, 0x21, 0xec, 0x5d, 0xa1, 0x21, 0x11, 0x7e, 0x86, 0xce,
- 0xf9, 0xf6, 0xbf, 0x10, 0x6e, 0xc2, 0xa6, 0xf0, 0xcf, 0xc5, 0x8b, 0x8e,
- 0x15, 0x54, 0x5f, 0x85, 0xfa, 0x3e, 0xe1, 0x23, 0x58, 0xbf, 0x61, 0x37,
- 0x70, 0x58, 0xbd, 0xac, 0xc5, 0x8a, 0x0a, 0x1f, 0x7b, 0x15, 0xf0, 0xa2,
- 0xf1, 0x48, 0x16, 0x2f, 0x36, 0x7d, 0x62, 0xe2, 0xea, 0x4d, 0xc6, 0x87,
- 0x2f, 0xfe, 0x87, 0x85, 0x08, 0x1f, 0xde, 0x93, 0xac, 0x5f, 0xef, 0x72,
- 0x63, 0xce, 0x0d, 0x62, 0xef, 0xe2, 0xc5, 0xff, 0xf7, 0xe4, 0x79, 0xd6,
- 0xdc, 0x2c, 0x1f, 0xe5, 0x62, 0xff, 0xb5, 0x3f, 0x6d, 0xfa, 0x98, 0x2c,
- 0x5f, 0xff, 0xe0, 0x4f, 0x70, 0xe0, 0xf3, 0x0b, 0x3a, 0xfb, 0x0b, 0xcb,
- 0x17, 0xfe, 0xc2, 0xcc, 0xe6, 0xd8, 0x70, 0xeb, 0x17, 0xfe, 0xcf, 0x60,
- 0x36, 0xe7, 0xca, 0x56, 0x29, 0x8f, 0xfc, 0x90, 0x2f, 0xfc, 0xf3, 0xdc,
- 0x36, 0xf3, 0xb1, 0xca, 0xc5, 0xfc, 0xf1, 0x96, 0x46, 0x25, 0x8a, 0x1a,
- 0xb2, 0x8c, 0x6a, 0xec, 0xb1, 0x91, 0xf7, 0x0d, 0x62, 0x17, 0xd2, 0x88,
- 0x0e, 0xf9, 0x0e, 0x1f, 0x10, 0x6c, 0xa1, 0xdf, 0xf3, 0x73, 0x07, 0xb7,
- 0x85, 0x2b, 0x17, 0x8d, 0x9d, 0x2c, 0x5f, 0x1d, 0xc6, 0x25, 0x8b, 0xd1,
- 0x49, 0xd6, 0x2f, 0xe9, 0xfb, 0x72, 0x43, 0x58, 0xac, 0x3c, 0xc0, 0xc7,
- 0xaf, 0x80, 0x4f, 0x05, 0x8b, 0xfb, 0xec, 0x77, 0x7d, 0xd5, 0x8b, 0xf4,
- 0x08, 0x4e, 0x6a, 0xc5, 0xe1, 0x77, 0xc5, 0x8b, 0xc5, 0x9b, 0xab, 0x17,
- 0x8f, 0x9b, 0xd6, 0x2b, 0x69, 0xee, 0xe0, 0xfb, 0x8f, 0xde, 0xd3, 0x46,
- 0xb1, 0x63, 0xac, 0x5e, 0xd6, 0x76, 0xb1, 0x70, 0xe6, 0x06, 0xc0, 0x02,
- 0x56, 0xd9, 0x58, 0xbf, 0x3f, 0x9c, 0x80, 0xb1, 0x41, 0x15, 0x36, 0x48,
- 0xf0, 0xdb, 0xcd, 0x22, 0xe8, 0x8b, 0xb3, 0x08, 0xa1, 0x0d, 0xa2, 0xf3,
- 0xa7, 0x05, 0xcb, 0x36, 0x45, 0x6f, 0xf9, 0x8d, 0x9d, 0x16, 0x31, 0xab,
- 0x17, 0x75, 0x1a, 0xc5, 0xfb, 0x1b, 0x51, 0x41, 0x62, 0xf8, 0x9f, 0xdc,
- 0x58, 0xb4, 0x9c, 0xf2, 0xf7, 0x94, 0xdc, 0xd1, 0x2c, 0x5f, 0xfb, 0x23,
- 0xdb, 0xf9, 0x89, 0xbb, 0x82, 0xc5, 0xfd, 0x26, 0x8c, 0xa7, 0xb5, 0x8a,
- 0x93, 0xf3, 0xd2, 0x25, 0xf1, 0x4e, 0x8d, 0x58, 0xbe, 0x92, 0xc3, 0x56,
- 0x2f, 0x72, 0x4d, 0x58, 0xbf, 0xcf, 0x9d, 0xfb, 0xcf, 0xf5, 0x8b, 0xff,
- 0x84, 0x3c, 0xd4, 0xc1, 0x87, 0x24, 0xb1, 0x7f, 0xc4, 0xf1, 0xce, 0xb4,
- 0xf0, 0x58, 0xa8, 0x1f, 0xe7, 0xd0, 0xef, 0xfc, 0x7c, 0xe7, 0x30, 0x81,
- 0xb3, 0x8b, 0x17, 0xff, 0xda, 0x7e, 0x16, 0x46, 0x1c, 0x05, 0x2c, 0x4b,
- 0x15, 0x28, 0xb3, 0x72, 0x21, 0x20, 0xd7, 0x69, 0xd7, 0xfc, 0x7b, 0xd1,
- 0xb1, 0xdf, 0xff, 0xe6, 0xe0, 0x33, 0x6b, 0x6f, 0x9f, 0xb4, 0xc5, 0x14,
- 0xf4, 0xb1, 0x7b, 0xcd, 0x1a, 0xc5, 0xf8, 0x0f, 0xdc, 0xc4, 0xb1, 0x78,
- 0xa7, 0xa5, 0x8b, 0xfd, 0x9c, 0x8b, 0xec, 0x67, 0x96, 0x2f, 0xcf, 0x09,
- 0xdc, 0x3a, 0xc5, 0xff, 0x9a, 0x2f, 0xce, 0xbb, 0x84, 0xe9, 0x62, 0xff,
- 0xf7, 0xbf, 0x3b, 0xf8, 0x4f, 0xe8, 0x9b, 0x7a, 0xc5, 0xff, 0x98, 0xf9,
- 0xac, 0x98, 0x98, 0xeb, 0x15, 0x88, 0x8d, 0xd2, 0x7d, 0x4a, 0x6a, 0x31,
- 0x9b, 0x0c, 0xaf, 0x90, 0xce, 0xbe, 0xcf, 0x48, 0xd6, 0x2f, 0xa2, 0xd4,
- 0xf6, 0xb1, 0x7f, 0xf9, 0x89, 0xfb, 0xe7, 0x33, 0x43, 0xfe, 0x2c, 0x56,
- 0xd5, 0xdc, 0x88, 0x42, 0x2f, 0x08, 0x7a, 0x23, 0x68, 0xf4, 0x74, 0x70,
- 0x76, 0x67, 0x1e, 0x22, 0xae, 0x46, 0xdc, 0x62, 0x18, 0x64, 0x5b, 0xa4,
- 0xb4, 0xb1, 0x7f, 0x3f, 0x67, 0x27, 0x31, 0x62, 0xa4, 0xdd, 0xe8, 0x32,
- 0x96, 0x2f, 0x66, 0x01, 0x62, 0xf7, 0xdb, 0xcb, 0x16, 0xdf, 0x87, 0xca,
- 0xc4, 0x04, 0x18, 0x18, 0xe5, 0x80, 0xb1, 0x7e, 0xd4, 0x62, 0x71, 0xac,
- 0x5b, 0x65, 0x62, 0xa0, 0x7a, 0x38, 0x24, 0x19, 0x55, 0xe9, 0xdd, 0xe2,
- 0xc5, 0x1a, 0x79, 0xfd, 0x17, 0xdf, 0xb5, 0xac, 0xdc, 0x89, 0x62, 0xe3,
- 0x38, 0xb1, 0x52, 0xd8, 0xda, 0x42, 0x13, 0x63, 0x1e, 0xc9, 0x78, 0x1d,
- 0x42, 0x95, 0xa5, 0x53, 0x6e, 0x42, 0xac, 0xe7, 0x3f, 0x65, 0x79, 0xdf,
- 0x10, 0x46, 0xd4, 0x28, 0x71, 0x6f, 0x24, 0x0c, 0xb6, 0xff, 0x6e, 0xf3,
- 0x92, 0x79, 0xf2, 0xc5, 0xce, 0x1a, 0xc5, 0x49, 0xe7, 0x9c, 0xde, 0xff,
- 0x14, 0x0b, 0x0f, 0x3d, 0x2c, 0x5d, 0x9b, 0x2b, 0x15, 0x87, 0x9b, 0xf3,
- 0x3b, 0xf7, 0xdb, 0x7e, 0x0d, 0x62, 0xf6, 0xdf, 0x32, 0xc5, 0xff, 0x87,
- 0x25, 0x84, 0x28, 0x67, 0x16, 0x2e, 0xdb, 0xda, 0xc5, 0xf9, 0xce, 0xdb,
- 0xb8, 0xb1, 0x7f, 0x67, 0xdf, 0xcf, 0x12, 0xc5, 0xd3, 0xda, 0xc5, 0x76,
- 0x78, 0xde, 0x2e, 0xac, 0x44, 0x9b, 0xb8, 0x5f, 0xf6, 0x08, 0xb3, 0xc4,
- 0xe7, 0x58, 0xb4, 0x4b, 0x17, 0xbf, 0x80, 0x58, 0xa6, 0x36, 0x1e, 0x13,
- 0xbf, 0xdc, 0x98, 0x4c, 0x73, 0x1a, 0xc5, 0xd8, 0x6a, 0xc5, 0xff, 0xec,
- 0x37, 0xed, 0xcf, 0xe6, 0xf9, 0xce, 0xd6, 0x2a, 0x51, 0x74, 0xc4, 0x1f,
- 0x35, 0x21, 0x8b, 0x4a, 0xc5, 0xf3, 0x87, 0x26, 0x2c, 0x54, 0x9b, 0x5e,
- 0xc4, 0x6e, 0xd6, 0x2c, 0x5f, 0x4f, 0xa7, 0xa5, 0x8b, 0x82, 0x9b, 0xab,
- 0x14, 0x03, 0xc2, 0x22, 0x3b, 0xe6, 0xd4, 0xc1, 0x62, 0xfa, 0x33, 0xcf,
- 0x16, 0x2a, 0x33, 0xc6, 0xc2, 0x2b, 0xff, 0x4f, 0x9c, 0x5e, 0x7e, 0xf3,
- 0xcb, 0x17, 0xfd, 0xad, 0xb2, 0x3f, 0xe7, 0x52, 0xb1, 0x7f, 0xf4, 0xe0,
- 0xdb, 0x85, 0x9b, 0xd8, 0x96, 0x2b, 0xe8, 0xbe, 0x73, 0xf1, 0x1e, 0x5f,
- 0xba, 0x79, 0x6d, 0x95, 0x8b, 0xc5, 0x9c, 0x58, 0xbf, 0xff, 0xf4, 0xfd,
- 0x8e, 0x12, 0x28, 0x3e, 0x83, 0xfb, 0x77, 0xce, 0x9a, 0x35, 0x8a, 0x8d,
- 0x78, 0x7c, 0x6d, 0xc6, 0x90, 0xf4, 0x54, 0xc3, 0xfb, 0x87, 0xb1, 0x42,
- 0xbb, 0x44, 0x3f, 0x8c, 0x85, 0xdb, 0xc0, 0x42, 0x4b, 0x3c, 0x67, 0xf4,
- 0x38, 0x04, 0x5e, 0x19, 0x5e, 0xe8, 0xe5, 0xfe, 0xf4, 0x33, 0x71, 0xc8,
- 0x0b, 0x17, 0xb5, 0xc1, 0x2c, 0x5b, 0x8b, 0x17, 0xfb, 0xa0, 0x38, 0x18,
- 0xba, 0x58, 0xaf, 0x9e, 0x39, 0x09, 0x56, 0x22, 0x19, 0x99, 0x6f, 0xf4,
- 0x63, 0xcf, 0x71, 0xfb, 0x58, 0xa5, 0x8b, 0xa1, 0xb1, 0x2c, 0x5b, 0x6b,
- 0x1a, 0x97, 0x0c, 0xbe, 0xc1, 0x6a, 0x35, 0x8b, 0xe8, 0x70, 0x67, 0x58,
- 0xa6, 0x3c, 0x87, 0x24, 0xbf, 0xfb, 0x37, 0xe0, 0xf0, 0x85, 0x0c, 0xe2,
- 0xc5, 0xfb, 0x53, 0xf0, 0xc6, 0xb1, 0x5a, 0x3e, 0xf7, 0x45, 0xb0, 0x16,
- 0x2e, 0x8e, 0x56, 0x2f, 0xd8, 0x3f, 0xb4, 0x6b, 0x16, 0x98, 0xcf, 0x4d,
- 0x84, 0x88, 0x62, 0xf8, 0xc7, 0xce, 0x2c, 0x5f, 0xc3, 0x90, 0x16, 0x76,
- 0xb1, 0x7f, 0xd0, 0x3b, 0xc3, 0xdc, 0x93, 0x56, 0x2a, 0x51, 0x19, 0x84,
- 0x6e, 0x5d, 0x7d, 0x32, 0x5d, 0x2c, 0x5e, 0xe3, 0x12, 0xc5, 0x80, 0xb1,
- 0x7d, 0xd6, 0xde, 0x76, 0xb1, 0x5a, 0x37, 0x44, 0x25, 0x7f, 0x83, 0x84,
- 0xef, 0x62, 0x02, 0xc5, 0xf3, 0xee, 0xe1, 0x2c, 0x56, 0x23, 0x41, 0xd5,
- 0x88, 0x83, 0x86, 0xd7, 0xff, 0x80, 0x1f, 0x9a, 0x0d, 0xa0, 0x1d, 0xb8,
- 0xb1, 0x43, 0x5d, 0x12, 0xc8, 0x5e, 0x74, 0x43, 0xb8, 0xbe, 0x76, 0xf7,
- 0x84, 0x78, 0x1d, 0x0a, 0x17, 0xfc, 0x2d, 0x14, 0x3c, 0xb7, 0x9d, 0x5f,
- 0x72, 0x31, 0x71, 0x62, 0xe8, 0xe0, 0xb1, 0x79, 0xbe, 0xcb, 0x17, 0x1e,
- 0x56, 0x2b, 0x0f, 0xc7, 0xb2, 0x5f, 0x0c, 0x88, 0x72, 0xff, 0xe8, 0xfa,
- 0xfb, 0x07, 0xa3, 0x73, 0xbf, 0x2c, 0x5f, 0x67, 0x70, 0x95, 0x8b, 0xc2,
- 0x7e, 0x2c, 0x56, 0x22, 0x2f, 0xe9, 0x61, 0x91, 0xde, 0xf3, 0x46, 0xb1,
- 0x7f, 0xcc, 0x6c, 0x8e, 0x77, 0xe7, 0xd6, 0x2f, 0xd2, 0x40, 0x3f, 0x96,
- 0x2f, 0xf3, 0x19, 0xdc, 0x39, 0x9d, 0x2c, 0x5f, 0xd0, 0x0c, 0x00, 0x9e,
- 0xd6, 0x29, 0x91, 0x21, 0xf2, 0x87, 0x37, 0xbf, 0x85, 0xc9, 0x88, 0x5a,
- 0x58, 0xbc, 0x2c, 0xed, 0x62, 0xbe, 0x79, 0xde, 0x30, 0xbf, 0xbd, 0x93,
- 0xec, 0x3a, 0xc5, 0xfd, 0x87, 0xd6, 0xa4, 0x6b, 0x17, 0xee, 0xf9, 0xe6,
- 0x8d, 0x62, 0xfe, 0x11, 0x47, 0xc6, 0xed, 0x62, 0xff, 0xe9, 0x8c, 0xc7,
- 0xef, 0x98, 0x36, 0xe2, 0xc5, 0x4a, 0x28, 0xa0, 0x56, 0x46, 0x17, 0xec,
- 0x37, 0xcd, 0x1a, 0xc5, 0xe0, 0x67, 0x6b, 0x15, 0xd9, 0xe4, 0x00, 0xaa,
- 0xff, 0xfe, 0x87, 0x0b, 0x22, 0xdb, 0xd7, 0xe7, 0xa3, 0x74, 0xe6, 0x2c,
- 0x5e, 0xc6, 0x8d, 0x62, 0xf0, 0xa6, 0x3e, 0xd1, 0x00, 0x4c, 0x77, 0xff,
- 0xe9, 0xd0, 0x33, 0x84, 0x27, 0x87, 0xc4, 0xf1, 0xac, 0x5f, 0xbd, 0x8e,
- 0x5d, 0x2c, 0x57, 0xcf, 0xfb, 0x75, 0x5a, 0xf7, 0x72, 0x75, 0x8b, 0xff,
- 0xc3, 0xfc, 0xf7, 0x02, 0xc3, 0xe7, 0x7e, 0x58, 0xbf, 0x1f, 0x3f, 0x84,
- 0xb1, 0x4c, 0x7e, 0x6e, 0x99, 0x7f, 0xc2, 0x78, 0x0f, 0x30, 0x1c, 0x58,
- 0xbf, 0xfb, 0x37, 0xfd, 0xe1, 0xb7, 0xdf, 0x73, 0x56, 0x2f, 0xc7, 0xcd,
- 0x39, 0x2c, 0x5f, 0xfb, 0xb8, 0x7e, 0x4e, 0xfd, 0xc3, 0x16, 0x2f, 0xe6,
- 0xef, 0xb8, 0x67, 0x96, 0x2a, 0x51, 0x31, 0x84, 0xe0, 0x41, 0xaf, 0xa6,
- 0x92, 0x47, 0x3c, 0x87, 0x15, 0xfb, 0xbe, 0x1d, 0xb7, 0x16, 0x2f, 0xfe,
- 0xfb, 0xb7, 0x80, 0x22, 0x27, 0x82, 0xc5, 0xf4, 0x90, 0x82, 0xeb, 0x17,
- 0x67, 0x36, 0x9f, 0x4f, 0xd0, 0xea, 0x51, 0x8a, 0x50, 0x96, 0xbf, 0x9e,
- 0x30, 0x39, 0x0d, 0x62, 0xff, 0xf9, 0xb0, 0xce, 0xe1, 0xce, 0x49, 0xdf,
- 0xbf, 0x2c, 0x54, 0x6b, 0xfe, 0x43, 0x86, 0x5f, 0x4f, 0x9d, 0x91, 0x31,
- 0x6c, 0x50, 0xd0, 0xd3, 0xb1, 0xe1, 0x47, 0xf8, 0x59, 0x91, 0x2f, 0x21,
- 0x23, 0xe8, 0xda, 0x77, 0xc3, 0xeb, 0x64, 0x9b, 0x74, 0xba, 0xfa, 0x2c,
- 0xce, 0x96, 0x2f, 0xb2, 0x26, 0x3a, 0xc5, 0x68, 0xf1, 0xc0, 0x49, 0x7f,
- 0xdf, 0xfe, 0x37, 0x70, 0xcd, 0x2c, 0x54, 0x9e, 0xe3, 0x91, 0x5f, 0xef,
- 0x0a, 0x39, 0xf4, 0x8d, 0x62, 0xf7, 0xb0, 0x96, 0x2f, 0x7d, 0xf7, 0x16,
- 0x2f, 0xc2, 0x86, 0x03, 0x8b, 0x17, 0xf8, 0x39, 0xeb, 0x67, 0x35, 0x2b,
- 0x17, 0xfc, 0x3c, 0x16, 0xa3, 0xe9, 0xa3, 0x58, 0xbc, 0x5b, 0x07, 0x96,
- 0x2f, 0xff, 0x6f, 0xc2, 0x19, 0x39, 0x9c, 0xe4, 0x81, 0x62, 0xff, 0xff,
- 0xe3, 0xb7, 0x36, 0xc5, 0x01, 0x17, 0xb6, 0xfe, 0x60, 0xc5, 0x87, 0x95,
- 0x8a, 0xc4, 0x61, 0x09, 0x32, 0xf9, 0xb5, 0x27, 0x58, 0xad, 0x1e, 0x27,
- 0xc8, 0xaf, 0x16, 0x18, 0xb1, 0x7f, 0xfd, 0xd7, 0xc4, 0x59, 0xdc, 0x1b,
- 0x85, 0x9b, 0xd6, 0x2f, 0xdf, 0x9f, 0xb1, 0xab, 0x17, 0x3c, 0x5c, 0x3f,
- 0xcd, 0xd5, 0x3a, 0x94, 0x76, 0x44, 0x45, 0xf8, 0x4c, 0xdf, 0xff, 0xe6,
- 0xde, 0x42, 0xe6, 0xd0, 0xca, 0x47, 0xf7, 0x86, 0x71, 0x62, 0xa0, 0xae,
- 0x20, 0xd1, 0xcd, 0x10, 0x7c, 0xa5, 0xce, 0x08, 0xf7, 0xd2, 0x85, 0x37,
- 0x9a, 0xdf, 0xb3, 0x45, 0x20, 0x58, 0xa9, 0x67, 0x2f, 0xc6, 0x61, 0x94,
- 0x81, 0x06, 0x8e, 0x83, 0x44, 0x0f, 0x2e, 0xf4, 0x4f, 0x77, 0xdf, 0xfb,
- 0x1a, 0xb1, 0x74, 0x42, 0x58, 0xb1, 0xd6, 0x2b, 0x0f, 0x3f, 0xb2, 0x40,
- 0xb8, 0xcd, 0xfe, 0xf0, 0x04, 0x5c, 0x61, 0xac, 0x5f, 0xa0, 0x0c, 0xc1,
- 0xac, 0x5b, 0x7b, 0x1e, 0xe3, 0x9a, 0x5f, 0xbe, 0xda, 0x00, 0x96, 0x2d,
- 0xac, 0x3d, 0x18, 0x8a, 0x2f, 0xe3, 0x38, 0xf3, 0xdc, 0x16, 0x2a, 0x4f,
- 0x63, 0x0a, 0x2f, 0xfb, 0x3b, 0x7f, 0x4f, 0x9c, 0x0b, 0x17, 0xff, 0xa2,
- 0x29, 0xf7, 0x3d, 0xdf, 0x4c, 0x51, 0xac, 0x5f, 0xe6, 0x23, 0x5c, 0x50,
- 0x1a, 0xc5, 0xf1, 0xc3, 0x8b, 0x8b, 0x15, 0x87, 0xb4, 0xc6, 0x97, 0xf1,
- 0x67, 0x85, 0x24, 0xb1, 0x7e, 0xee, 0x05, 0x23, 0x58, 0xa3, 0x9e, 0xab,
- 0x96, 0x5f, 0xd0, 0x62, 0x3b, 0xf9, 0x62, 0xff, 0x87, 0x9b, 0x78, 0xc5,
- 0xdc, 0x16, 0x2d, 0x3d, 0x9f, 0x49, 0x85, 0xb5, 0x2a, 0x82, 0x58, 0xe7,
- 0xf0, 0xa8, 0x77, 0x52, 0x84, 0x55, 0xec, 0x8e, 0x56, 0x2f, 0x7b, 0x3e,
- 0xb1, 0x67, 0x81, 0xba, 0xf8, 0xed, 0xff, 0xd3, 0xce, 0x61, 0xfc, 0x52,
- 0x7e, 0x2c, 0x5f, 0xf4, 0xe8, 0xdf, 0x94, 0xe6, 0x96, 0x2f, 0xe3, 0x76,
- 0xe1, 0xe7, 0xa5, 0x8b, 0xff, 0xa7, 0xb8, 0x78, 0x53, 0x1b, 0x77, 0xe5,
- 0x8b, 0xfc, 0xdf, 0x7e, 0xa4, 0x86, 0xb1, 0x4c, 0x8a, 0xd2, 0x32, 0xe2,
- 0x45, 0xfd, 0x3d, 0x00, 0xe2, 0x02, 0xc5, 0xf6, 0xf6, 0x21, 0xac, 0x5f,
- 0xf8, 0xa4, 0x7f, 0x93, 0x96, 0x74, 0xb1, 0x79, 0x8b, 0xcb, 0x15, 0x87,
- 0xfd, 0x11, 0x27, 0xcf, 0xaf, 0xf0, 0xf8, 0xdf, 0xfe, 0x0d, 0x62, 0xff,
- 0xe6, 0x9e, 0x13, 0xc3, 0x6f, 0x33, 0x4b, 0x17, 0xf8, 0x65, 0x90, 0xfc,
- 0x8d, 0x62, 0xf1, 0x3e, 0x96, 0x2f, 0x9d, 0xdf, 0x75, 0x62, 0xff, 0xff,
- 0xff, 0x7f, 0x1b, 0x50, 0xda, 0x59, 0x14, 0x24, 0xbd, 0xb4, 0x1c, 0xdb,
- 0xc3, 0xbc, 0x0d, 0xf2, 0xc5, 0xff, 0xfd, 0x83, 0xda, 0xc0, 0x9d, 0xbe,
- 0xfe, 0x7b, 0xef, 0x05, 0x8b, 0xff, 0xb9, 0x1e, 0x19, 0x84, 0x2d, 0xd9,
- 0x09, 0x89, 0x9b, 0x1c, 0x73, 0xc4, 0x9b, 0xe1, 0x2f, 0x7f, 0xf7, 0x02,
- 0x74, 0xc6, 0xfd, 0xe1, 0x9c, 0x58, 0xa9, 0x54, 0x6a, 0xd1, 0xb4, 0x87,
- 0x08, 0x3b, 0xfd, 0xdc, 0x39, 0x14, 0x26, 0x35, 0x8a, 0x1a, 0xeb, 0xef,
- 0x44, 0xd1, 0x22, 0x6a, 0x1c, 0xc7, 0x2e, 0xfc, 0x2b, 0x9c, 0xbc, 0x8d,
- 0x3d, 0x29, 0xe8, 0x47, 0x97, 0xff, 0xf7, 0xb3, 0xbf, 0x6b, 0x53, 0xe0,
- 0x06, 0x50, 0xfe, 0x2c, 0x5c, 0xdb, 0xd6, 0x2f, 0xa4, 0xa1, 0xc5, 0x8b,
- 0x37, 0x68, 0x99, 0x89, 0x78, 0x03, 0x37, 0xfb, 0x51, 0x94, 0xf4, 0xd0,
- 0x58, 0xaf, 0x9f, 0x63, 0x9b, 0xdf, 0xbf, 0x3b, 0xc7, 0x2b, 0x17, 0x86,
- 0xe4, 0xb1, 0x6d, 0xeb, 0x17, 0xee, 0xfc, 0x53, 0xf5, 0x8b, 0x6a, 0x4d,
- 0xeb, 0x8a, 0x5f, 0x77, 0x14, 0xe9, 0x62, 0xda, 0x58, 0xac, 0x36, 0xe2,
- 0x25, 0xbf, 0xff, 0x4f, 0xbe, 0xf1, 0x71, 0xdb, 0xa2, 0x7c, 0xe9, 0x62,
- 0xa0, 0x9a, 0xa8, 0xca, 0xb4, 0xb3, 0xc5, 0xcd, 0x92, 0x0b, 0xe6, 0xdf,
- 0x83, 0x58, 0xbe, 0x2f, 0x61, 0x2c, 0x5c, 0x5e, 0xd1, 0xe2, 0xb9, 0x25,
- 0xff, 0x77, 0x0e, 0x0b, 0xd3, 0xee, 0x2c, 0x5f, 0xb5, 0x07, 0xec, 0xc5,
- 0x8b, 0xfd, 0xc3, 0x1c, 0x73, 0xdf, 0x16, 0x2a, 0x51, 0x93, 0x85, 0x8c,
- 0x78, 0xe5, 0x77, 0xee, 0x0b, 0xd2, 0x4b, 0x17, 0xf8, 0x5d, 0xc3, 0xdc,
- 0x16, 0xe2, 0xc5, 0xee, 0x4f, 0x6b, 0x17, 0xa7, 0xfc, 0x58, 0xb9, 0xcc,
- 0xec, 0xdd, 0x80, 0x7a, 0xa0, 0x98, 0x26, 0x1c, 0xfc, 0xa0, 0x9d, 0x6f,
- 0xf6, 0x77, 0xb7, 0x3e, 0xdf, 0x58, 0xbb, 0xe3, 0x58, 0xb9, 0xba, 0x58,
- 0xb9, 0xfc, 0x33, 0x61, 0xb2, 0x31, 0x5a, 0x44, 0xab, 0xb3, 0x5a, 0x56,
- 0x2f, 0xed, 0x4b, 0x41, 0xf8, 0xb1, 0x43, 0x37, 0xdd, 0x88, 0xdf, 0xf7,
- 0xb8, 0x28, 0x06, 0x36, 0xf2, 0xc5, 0xfe, 0x27, 0x36, 0x29, 0xcd, 0x2c,
- 0x54, 0xa2, 0x49, 0xc8, 0x84, 0x79, 0x7e, 0xfc, 0xe4, 0x1d, 0x62, 0xf6,
- 0x37, 0x16, 0x2f, 0xde, 0xf6, 0x0a, 0x35, 0x8b, 0xff, 0xe8, 0xdf, 0xf8,
- 0x3d, 0xb8, 0x45, 0x8c, 0x05, 0x8a, 0x8d, 0x12, 0xdd, 0x0e, 0x68, 0xaa,
- 0xff, 0xde, 0x16, 0x9f, 0x9b, 0x7d, 0x19, 0x8b, 0x17, 0xfb, 0xa6, 0x7d,
- 0xbc, 0x7f, 0xac, 0x53, 0x1f, 0xdf, 0xd1, 0x68, 0x69, 0xc5, 0xe4, 0x2f,
- 0x5e, 0x15, 0xb7, 0xc5, 0x30, 0x65, 0x8b, 0xce, 0x51, 0x2c, 0x5e, 0xee,
- 0x0c, 0xb1, 0x67, 0x39, 0xbb, 0x21, 0xdb, 0xc2, 0x92, 0x58, 0xbf, 0xff,
- 0xcd, 0xe9, 0x27, 0x86, 0x0f, 0x8f, 0xa6, 0xfb, 0x6f, 0x58, 0xbe, 0x92,
- 0x87, 0x16, 0x2b, 0x49, 0x8f, 0xfd, 0x70, 0x89, 0x77, 0x8e, 0x06, 0xc1,
- 0x7f, 0xfe, 0xe1, 0x6d, 0xfb, 0xb7, 0x80, 0x22, 0x27, 0x82, 0xc5, 0xff,
- 0xff, 0xd3, 0xac, 0x8a, 0x4f, 0x9d, 0x30, 0xff, 0x3e, 0xe1, 0xba, 0xcd,
- 0xd5, 0x8b, 0xf9, 0x8d, 0xd9, 0x16, 0x8d, 0x58, 0xbf, 0xc5, 0x22, 0xef,
- 0x8f, 0xb8, 0xb1, 0x5f, 0x3e, 0xb7, 0x34, 0xbe, 0x9c, 0x33, 0xcb, 0x17,
- 0xfc, 0x79, 0x2e, 0x9c, 0x80, 0x15, 0x58, 0xb8, 0xba, 0x58, 0xbf, 0x6b,
- 0x36, 0x58, 0x0b, 0x16, 0x6c, 0x3c, 0x33, 0x8c, 0x5f, 0xf4, 0x83, 0x5a,
- 0x93, 0x07, 0xda, 0xc5, 0xfe, 0x30, 0xff, 0x96, 0x28, 0xd6, 0x2f, 0xff,
- 0x3c, 0x1b, 0x59, 0xdc, 0x50, 0x9d, 0x46, 0xb1, 0x7f, 0xff, 0x80, 0x77,
- 0x86, 0x6f, 0x6e, 0x7f, 0x01, 0xb3, 0x9f, 0x65, 0x8a, 0x94, 0x73, 0x80,
- 0xd4, 0x49, 0xb7, 0xff, 0xc5, 0x9c, 0xc3, 0xcf, 0x59, 0xe6, 0xd6, 0x2c,
- 0x57, 0x4a, 0xa2, 0xa2, 0x21, 0x39, 0x1f, 0xe1, 0x00, 0x02, 0x6f, 0x46,
- 0x47, 0xbc, 0xbe, 0xff, 0xb9, 0xe1, 0x77, 0x83, 0x72, 0x58, 0xbf, 0xff,
- 0xfa, 0x13, 0xb4, 0x78, 0x4f, 0xcf, 0xb8, 0x39, 0xb7, 0x3d, 0x3e, 0xe2,
- 0xc5, 0x44, 0x8a, 0xff, 0x1d, 0x5c, 0x2e, 0xd6, 0x2f, 0xe9, 0x3c, 0xe7,
- 0x7e, 0x58, 0xb6, 0x1c, 0xf1, 0xfc, 0x33, 0x52, 0xba, 0x45, 0x92, 0xdb,
- 0x1e, 0x32, 0x41, 0x35, 0xdf, 0x7b, 0x9b, 0x59, 0x62, 0xfe, 0x8f, 0x34,
- 0xdd, 0x4a, 0xc5, 0xf1, 0x0e, 0x4e, 0xb1, 0x7f, 0xfc, 0x22, 0xf7, 0x3e,
- 0xd1, 0x14, 0x9d, 0xe0, 0xb1, 0x7f, 0x6a, 0x5a, 0x0f, 0xc5, 0x8b, 0x84,
- 0xeb, 0x16, 0xcd, 0xa7, 0x88, 0x45, 0xb4, 0x74, 0x5e, 0x6f, 0x84, 0xa5,
- 0xfc, 0xe0, 0xc1, 0xbc, 0x16, 0x2a, 0x53, 0x35, 0xc8, 0x6f, 0x31, 0x55,
- 0xf0, 0x38, 0x16, 0x05, 0x56, 0x2f, 0xba, 0x7d, 0x46, 0xb1, 0x7e, 0x07,
- 0x36, 0xcf, 0x96, 0x2a, 0x4f, 0x41, 0xc9, 0x6a, 0x55, 0x2c, 0xb1, 0x2f,
- 0xe3, 0x64, 0x73, 0x32, 0x7d, 0xbf, 0x7c, 0x0d, 0xa3, 0x56, 0x2f, 0x74,
- 0x1c, 0x16, 0x2f, 0xa7, 0x41, 0x7e, 0x2c, 0x57, 0xcf, 0x1c, 0x04, 0x17,
- 0xf8, 0x7f, 0xc0, 0x0b, 0xdc, 0x58, 0xbf, 0xff, 0xff, 0xb3, 0x73, 0x07,
- 0xc9, 0x1c, 0xfb, 0xf8, 0x2e, 0xbf, 0x3c, 0xfe, 0x71, 0xe4, 0xeb, 0x17,
- 0xef, 0xe4, 0x20, 0xeb, 0x17, 0xff, 0xd9, 0xfe, 0xbe, 0xd1, 0x13, 0x99,
- 0xec, 0xfa, 0xc5, 0x62, 0x79, 0xac, 0xe2, 0xe4, 0x5c, 0x35, 0xf4, 0x22,
- 0xf6, 0x4a, 0x2f, 0xbf, 0xc9, 0xe9, 0x62, 0xfb, 0xcd, 0x91, 0x2c, 0x58,
- 0xd5, 0x8a, 0xc3, 0xda, 0xec, 0x91, 0x88, 0xef, 0x70, 0x30, 0x2c, 0x5e,
- 0x92, 0x35, 0x62, 0xa4, 0xde, 0x70, 0x7e, 0xa5, 0xbf, 0x7c, 0x8e, 0x33,
- 0x81, 0xca, 0x29, 0xc9, 0xe0, 0x9e, 0xa3, 0xa4, 0x68, 0xdd, 0xa2, 0x94,
- 0xc1, 0xa8, 0x68, 0x9e, 0x1e, 0x5f, 0x8e, 0xe5, 0xe3, 0x58, 0x02, 0x69,
- 0x4e, 0xbc, 0x7a, 0x55, 0x18, 0xa5, 0x0d, 0x99, 0x0b, 0x70, 0xda, 0xaf,
- 0xfe, 0xf7, 0x3f, 0x91, 0x10, 0xbb, 0x87, 0x16, 0x2f, 0xfe, 0xc2, 0x06,
- 0x66, 0xb9, 0xe9, 0xc5, 0x8b, 0xfe, 0xef, 0xd9, 0xa6, 0x8d, 0xce, 0xb1,
- 0x7b, 0x37, 0xe2, 0xc5, 0x01, 0x13, 0x64, 0x85, 0xc3, 0xba, 0x94, 0xc4,
- 0xb2, 0x1c, 0x77, 0x82, 0xf0, 0x65, 0x8b, 0xe9, 0x27, 0x82, 0xc5, 0xfb,
- 0x37, 0x1c, 0x81, 0xb4, 0xf0, 0xb4, 0x43, 0x78, 0xef, 0x12, 0xc5, 0xfc,
- 0xc7, 0x9f, 0x86, 0x35, 0x8b, 0xfe, 0x0f, 0xcc, 0x42, 0x86, 0x71, 0x62,
- 0xa0, 0x7d, 0x2c, 0x5f, 0x7e, 0xfb, 0x4e, 0xb8, 0xb1, 0x5d, 0x23, 0x43,
- 0xf0, 0x87, 0xde, 0x43, 0x7f, 0xfe, 0x87, 0x0b, 0x3d, 0xc6, 0xc3, 0xfb,
- 0x58, 0x62, 0xc5, 0xff, 0xbe, 0xc7, 0x1e, 0x45, 0x39, 0xa5, 0x8b, 0xd0,
- 0x9e, 0xd6, 0x2f, 0xc2, 0x21, 0x4f, 0x6b, 0x17, 0x8f, 0x9e, 0x58, 0xbe,
- 0x90, 0x39, 0xd6, 0x2d, 0x0c, 0x46, 0x2c, 0x47, 0xe7, 0x1e, 0x01, 0x49,
- 0x0e, 0xd7, 0x69, 0xb5, 0x14, 0x63, 0x76, 0xe9, 0x62, 0xef, 0x4a, 0xc5,
- 0xb8, 0x15, 0x35, 0x4c, 0x27, 0x52, 0x7f, 0xce, 0xa9, 0x7e, 0x2c, 0x00,
- 0xb8, 0xb1, 0x7f, 0xb6, 0x93, 0xc6, 0x53, 0xda, 0xc5, 0xff, 0xbe, 0xde,
- 0xfe, 0x37, 0xa4, 0x0b, 0x17, 0x74, 0xd8, 0x89, 0xcd, 0x14, 0x70, 0xda,
- 0xee, 0x79, 0x62, 0xfc, 0x37, 0x29, 0x02, 0xc5, 0x74, 0x6f, 0xc3, 0x18,
- 0xbf, 0x9f, 0xc0, 0x0c, 0xa0, 0xb1, 0x51, 0x9e, 0x97, 0xc8, 0xef, 0xf0,
- 0xa7, 0x7e, 0x79, 0xb4, 0xb1, 0x7d, 0xd7, 0xda, 0x25, 0x8b, 0xff, 0xfe,
- 0xd0, 0x00, 0x2e, 0x7d, 0xbd, 0x0c, 0xfb, 0x81, 0x87, 0x2b, 0x17, 0xfc,
- 0xfa, 0xcd, 0xf9, 0xbe, 0x46, 0xb1, 0x58, 0x8a, 0x30, 0x33, 0xdf, 0xff,
- 0x61, 0xa6, 0xb0, 0xfe, 0xd1, 0x7d, 0xbb, 0xf2, 0xc5, 0x1c, 0xfd, 0x88,
- 0x8a, 0xa5, 0x35, 0xfc, 0x8c, 0xfa, 0xe1, 0x69, 0x62, 0xf7, 0x4f, 0xa5,
- 0x8b, 0xff, 0x47, 0x84, 0x7c, 0xf7, 0x03, 0xe2, 0xc5, 0xfb, 0x9d, 0x4e,
- 0x8d, 0x58, 0xbf, 0xa3, 0xfe, 0x75, 0x27, 0x58, 0xbf, 0x98, 0x1d, 0xc3,
- 0x3c, 0xb1, 0x51, 0xa6, 0x03, 0xf1, 0x87, 0x1e, 0x02, 0x09, 0x15, 0xef,
- 0x30, 0xbe, 0x87, 0xb0, 0x0b, 0x17, 0xb8, 0xd1, 0x2c, 0x57, 0x67, 0x83,
- 0xc2, 0x3b, 0xef, 0x7c, 0x5d, 0x2c, 0x5f, 0xb1, 0x87, 0xf6, 0x58, 0xa8,
- 0xcf, 0x32, 0x04, 0xb7, 0xf7, 0x38, 0xc5, 0xdc, 0x16, 0x2e, 0xd1, 0xab,
- 0x15, 0xd9, 0xe4, 0x39, 0x7d, 0xff, 0xcf, 0x0d, 0xbc, 0x2c, 0xf7, 0x33,
- 0x71, 0x62, 0xa5, 0x34, 0x5c, 0x6f, 0x76, 0xb1, 0x11, 0x5f, 0xfb, 0xbf,
- 0x71, 0x8a, 0x40, 0xe7, 0x58, 0xa5, 0x8a, 0xc3, 0xcb, 0xde, 0x7f, 0x7a,
- 0x07, 0xfa, 0xc5, 0x46, 0x78, 0x3e, 0x23, 0xbf, 0xff, 0xf6, 0xce, 0x7b,
- 0xee, 0x30, 0x85, 0x9b, 0xcb, 0x39, 0xc6, 0xef, 0xcb, 0x16, 0xed, 0x62,
- 0xfb, 0x0f, 0x3b, 0x8b, 0x16, 0xec, 0x2e, 0x6e, 0x38, 0x27, 0x78, 0xd6,
- 0x31, 0x62, 0xfc, 0x63, 0x61, 0x1a, 0xb1, 0x4c, 0x79, 0x02, 0x1f, 0xbf,
- 0xc3, 0x0f, 0x22, 0xfb, 0x9d, 0x62, 0xb1, 0x39, 0x96, 0x23, 0x78, 0x55,
- 0x93, 0xa0, 0x88, 0x6f, 0xbe, 0xfb, 0xbc, 0x58, 0xbf, 0xf6, 0x77, 0xe3,
- 0x30, 0x87, 0xf9, 0x58, 0xb3, 0xf4, 0x7c, 0xda, 0x26, 0xb6, 0x2c, 0x5f,
- 0x6a, 0x36, 0x8d, 0x62, 0xf7, 0xdb, 0x4b, 0x16, 0x76, 0x3c, 0x28, 0x89,
- 0x6b, 0x69, 0xfd, 0x7d, 0x4e, 0xfb, 0x85, 0x27, 0x58, 0xbf, 0xe8, 0xe7,
- 0x98, 0xdb, 0xdc, 0xeb, 0x17, 0xb7, 0xe1, 0x2c, 0x54, 0xa2, 0x7f, 0xb2,
- 0x47, 0x22, 0xf1, 0xdd, 0xef, 0xc0, 0xeb, 0x17, 0x7d, 0x96, 0x2b, 0x0d,
- 0xaf, 0x87, 0xaa, 0x59, 0xd8, 0xd0, 0x69, 0xc8, 0xc4, 0x8d, 0x94, 0x41,
- 0xdc, 0x2f, 0x1a, 0x19, 0x9a, 0x23, 0xfc, 0x72, 0x8f, 0x19, 0x49, 0x47,
- 0xbf, 0xc9, 0x4c, 0x1e, 0x85, 0x90, 0xa3, 0x41, 0xd9, 0x71, 0xbe, 0xcf,
- 0xe7, 0x4b, 0x17, 0xdd, 0xf0, 0x47, 0x58, 0xb8, 0x0c, 0xb1, 0x74, 0xc4,
- 0xc6, 0xf1, 0xc9, 0x6e, 0x63, 0x16, 0x2d, 0xd2, 0xc5, 0x61, 0xab, 0x38,
- 0xc5, 0xf8, 0xd3, 0x5b, 0x50, 0x58, 0xbc, 0xfd, 0xc1, 0x62, 0xa5, 0x31,
- 0xe8, 0xd7, 0xc6, 0xad, 0xa2, 0x0f, 0x15, 0xdf, 0xde, 0x62, 0x60, 0x71,
- 0x62, 0xf8, 0x65, 0x9f, 0x58, 0xb0, 0xf6, 0x9e, 0x78, 0x65, 0xb7, 0xec,
- 0xe0, 0xb5, 0x1a, 0xc5, 0xff, 0xff, 0xff, 0x76, 0x0d, 0x75, 0xcd, 0xcd,
- 0xed, 0xb0, 0x1a, 0x1e, 0xc5, 0xc8, 0x6c, 0x3d, 0x6c, 0x2d, 0xa0, 0xdc,
- 0xdb, 0xb7, 0xfb, 0x2b, 0x15, 0x89, 0x8d, 0x91, 0x58, 0x65, 0x57, 0x8e,
- 0xfe, 0x58, 0xba, 0x1e, 0x58, 0xbf, 0xba, 0x1b, 0x6f, 0x91, 0xac, 0x5b,
- 0xeb, 0x16, 0x02, 0xc5, 0xdc, 0x82, 0xc5, 0x4a, 0x28, 0x86, 0x3a, 0xe3,
- 0x00, 0x31, 0xe0, 0x90, 0x84, 0xaf, 0xe8, 0xe2, 0x86, 0xc7, 0xa8, 0xd6,
- 0x2e, 0x80, 0x16, 0x2f, 0x3e, 0x69, 0x62, 0xf1, 0x67, 0x96, 0x2f, 0x7f,
- 0x0e, 0xb1, 0x5d, 0x9f, 0x6f, 0xc6, 0x08, 0x73, 0xc3, 0x97, 0x78, 0x96,
- 0x2f, 0x4f, 0x7c, 0x58, 0xbe, 0x62, 0x86, 0x2c, 0x5c, 0x1f, 0xd6, 0x2f,
- 0x46, 0xe4, 0xb1, 0x43, 0x3f, 0x53, 0x8f, 0x7c, 0x87, 0xc3, 0x37, 0x6b,
- 0xeb, 0x17, 0xd2, 0x37, 0x82, 0xc5, 0xfb, 0x3d, 0xf6, 0xf2, 0xc5, 0xf9,
- 0xfb, 0xce, 0xfc, 0xb1, 0x5f, 0x3d, 0x2f, 0x14, 0x5e, 0x7d, 0x41, 0x62,
- 0xf7, 0xf0, 0xeb, 0x15, 0x03, 0x75, 0xe1, 0xdb, 0xfe, 0x36, 0x2c, 0xce,
- 0xbd, 0x26, 0xac, 0x5f, 0xcf, 0xac, 0xfc, 0x81, 0x62, 0xf0, 0x8a, 0x35,
- 0x8b, 0xc1, 0xfd, 0xd6, 0x2b, 0x6a, 0x75, 0xf1, 0x8c, 0x1a, 0xe9, 0xda,
- 0xe6, 0x88, 0x4e, 0x7b, 0xf2, 0xde, 0x0f, 0x5f, 0x1f, 0x67, 0x70, 0x6b,
- 0x16, 0x8d, 0x62, 0xda, 0x58, 0xa8, 0xcd, 0x2b, 0x09, 0xdf, 0x46, 0xef,
- 0xf5, 0x8b, 0xf0, 0xa3, 0x77, 0xfa, 0xc5, 0xfb, 0x06, 0x07, 0xf2, 0xc5,
- 0x6d, 0x3f, 0x4f, 0x91, 0xef, 0x29, 0xbf, 0x07, 0x01, 0x4f, 0x16, 0x2a,
- 0x33, 0xdd, 0x34, 0xce, 0xfc, 0x36, 0xdf, 0x23, 0x58, 0xb7, 0x96, 0x2f,
- 0xe3, 0x30, 0xa7, 0xbe, 0x2c, 0x54, 0x0f, 0xaf, 0xb2, 0xa7, 0x12, 0xbf,
- 0x84, 0xfa, 0x83, 0x81, 0x62, 0xff, 0x8b, 0x35, 0xa9, 0xe8, 0x33, 0xac,
- 0x5f, 0xe6, 0xd6, 0x1d, 0xfb, 0x08, 0x33, 0xe9, 0x0c, 0xba, 0xfd, 0x17,
- 0xdb, 0xbf, 0x2c, 0x57, 0xcf, 0xe3, 0xc9, 0xb7, 0xec, 0x21, 0xfe, 0x56,
- 0x28, 0x28, 0xbd, 0xf1, 0x30, 0xa5, 0x81, 0xe6, 0x42, 0x31, 0xa3, 0xeb,
- 0x3b, 0xbf, 0xd3, 0xde, 0x1e, 0x45, 0x08, 0xf1, 0x46, 0x20, 0x61, 0x15,
- 0xff, 0x60, 0xc6, 0xdd, 0xe7, 0x7e, 0x58, 0xbe, 0xe8, 0xa6, 0x0b, 0x15,
- 0xf3, 0xde, 0x73, 0xbb, 0xfd, 0x39, 0xe9, 0xfb, 0x8d, 0x62, 0xfb, 0x3e,
- 0xc7, 0x58, 0xbf, 0xec, 0xf4, 0xf4, 0x1c, 0x83, 0x16, 0x2f, 0x4f, 0x70,
- 0x58, 0xa8, 0xd1, 0x9a, 0x32, 0x10, 0x19, 0x18, 0x45, 0xba, 0x75, 0x7d,
- 0x98, 0x5e, 0x58, 0xbf, 0xfd, 0xbd, 0x88, 0x1f, 0x67, 0x87, 0x9a, 0x35,
- 0x8b, 0xe1, 0x3e, 0xa0, 0xb1, 0x52, 0x7d, 0xe3, 0x4c, 0xbf, 0xf4, 0x8f,
- 0x53, 0xe6, 0xe9, 0x86, 0xb1, 0x7d, 0xee, 0x3f, 0x4b, 0x14, 0x33, 0xe3,
- 0x11, 0xfd, 0xf0, 0x9f, 0x50, 0x58, 0xbd, 0x3b, 0xb0, 0x58, 0xa1, 0x9e,
- 0x1c, 0x44, 0x77, 0xf7, 0xba, 0x18, 0xcf, 0xa5, 0x8b, 0xf7, 0x98, 0xa4,
- 0x0b, 0x17, 0xfd, 0x17, 0x37, 0xb9, 0x46, 0x21, 0xac, 0x5f, 0xce, 0x60,
- 0x00, 0x7d, 0x95, 0x8b, 0xec, 0xf6, 0x1d, 0x62, 0xe2, 0x35, 0x62, 0x9c,
- 0xdd, 0x08, 0x8a, 0xa0, 0x88, 0xde, 0x36, 0xdf, 0xa0, 0x42, 0x7e, 0x2c,
- 0x5f, 0xfa, 0x48, 0x5e, 0x80, 0x8b, 0xdc, 0x58, 0xac, 0x3e, 0x7d, 0x14,
- 0x5f, 0xff, 0x87, 0x30, 0x9c, 0x87, 0xe4, 0x65, 0x3e, 0xe2, 0xc5, 0xff,
- 0x4f, 0xa1, 0x9b, 0x8e, 0x40, 0x58, 0xac, 0x44, 0x79, 0x2a, 0x5e, 0x03,
- 0x01, 0x62, 0xfa, 0x38, 0xbe, 0xcb, 0x16, 0xfe, 0x1e, 0x10, 0x87, 0x6e,
- 0x73, 0xac, 0x5f, 0xf6, 0xe7, 0xdb, 0x69, 0xba, 0xce, 0x2c, 0x57, 0x47,
- 0xae, 0x21, 0x7b, 0xff, 0x13, 0x9b, 0xf7, 0x87, 0x18, 0x6b, 0x17, 0xef,
- 0xb1, 0x3c, 0x6b, 0x16, 0xe9, 0x62, 0xf8, 0x50, 0xce, 0x74, 0x6e, 0xc8,
- 0xa2, 0x8e, 0x8b, 0x22, 0x7a, 0xbf, 0xff, 0xa3, 0x6d, 0x13, 0x9b, 0xcf,
- 0xcb, 0xf7, 0x23, 0x65, 0x8b, 0xb3, 0xcb, 0x15, 0x87, 0xe6, 0x4b, 0x97,
- 0x06, 0x75, 0x8a, 0x64, 0x67, 0x14, 0x25, 0x7c, 0x41, 0x7f, 0x87, 0x9c,
- 0xe6, 0x6a, 0x35, 0x8b, 0x0d, 0x62, 0xba, 0x3c, 0x7e, 0xcd, 0x6e, 0xde,
- 0xeb, 0x17, 0xfa, 0x75, 0x3d, 0x66, 0xfc, 0x58, 0xbd, 0x3b, 0xb2, 0xb1,
- 0x52, 0xbf, 0xaf, 0x1a, 0x7c, 0x21, 0x20, 0x38, 0x42, 0x63, 0x29, 0xa4,
- 0x7d, 0x98, 0xb1, 0x3c, 0x50, 0xcb, 0xd4, 0x22, 0x8f, 0x0b, 0x0f, 0xb1,
- 0x93, 0xf7, 0xa3, 0xa3, 0x13, 0xd6, 0xf2, 0x4d, 0x91, 0x9d, 0xd3, 0x5b,
- 0xf4, 0x53, 0xe2, 0xde, 0xb1, 0x7d, 0x16, 0x30, 0x16, 0x2b, 0x69, 0xe7,
- 0x49, 0x5d, 0xff, 0xd3, 0xbf, 0x53, 0xac, 0x6f, 0xc8, 0xd6, 0x2e, 0x9c,
- 0x58, 0xa2, 0x3d, 0xbe, 0x22, 0xdc, 0xe7, 0x58, 0xba, 0x2d, 0x95, 0x8a,
- 0x23, 0x67, 0xbc, 0x5e, 0xff, 0xfc, 0xc7, 0xee, 0x1c, 0xdb, 0xfc, 0xf7,
- 0x09, 0xfc, 0xb1, 0x70, 0xbc, 0xb1, 0x7e, 0x11, 0x7b, 0x00, 0xb1, 0x50,
- 0x4e, 0x37, 0x1f, 0x99, 0x53, 0xc4, 0x5b, 0x2b, 0x3b, 0xa3, 0x16, 0x08,
- 0x14, 0x87, 0x3b, 0x7e, 0xc5, 0x0a, 0xc0, 0xac, 0x21, 0xf6, 0x08, 0x61,
- 0x6c, 0x71, 0xe4, 0xec, 0x38, 0x4c, 0xec, 0x22, 0x40, 0xb6, 0xfe, 0x16,
- 0x35, 0xcd, 0x2c, 0x56, 0x39, 0x66, 0xf0, 0x9d, 0x50, 0x1d, 0x27, 0x57,
- 0x2b, 0x9b, 0x33, 0x65, 0xc2, 0x75, 0x48, 0x3e, 0xee, 0x75, 0x69, 0xa7,
- 0x42, 0x22, 0xa4, 0xe5, 0xea, 0x7e, 0xf0, 0xf3, 0xb5, 0x3f, 0xad, 0x5b,
- 0x9e, 0x7d, 0x94, 0x13, 0xc2, 0x61, 0x78, 0xc8, 0xca, 0x9e, 0x4d, 0xcb,
- 0x40, 0x8d, 0xea, 0xc4, 0x70, 0x52, 0x87, 0x37, 0xc7, 0x6a, 0x64, 0x34,
- 0xb6, 0x67, 0xd3, 0x43, 0xa4, 0xde, 0xee, 0xca, 0xf8, 0xbf, 0x04, 0x6d,
- 0x3e, 0x96, 0x28, 0x24, 0x3b, 0x04, 0xd9, 0x57, 0xf8, 0xe8, 0x9f, 0x04,
- 0xaf, 0x5b, 0xff, 0xc1, 0x0e, 0xf0, 0x09, 0x9a, 0xe9, 0xdf, 0xa5, 0x44,
- 0xd8, 0x5f, 0xb5, 0xd3, 0xbf, 0x4a, 0x8a, 0xb4, 0xb8, 0x1b, 0xd6, 0x2e,
- 0xe6, 0xca, 0xc5, 0x82, 0x61, 0xf6, 0x7c, 0xdf, 0x83, 0x57, 0x6f, 0xd2,
- 0xc5, 0xcf, 0x2b, 0x17, 0xfa, 0x10, 0x17, 0x8a, 0x60, 0xb1, 0x7d, 0x9f,
- 0x7f, 0x2c, 0x58, 0x2b, 0x87, 0xac, 0x46, 0x97, 0xff, 0xfe, 0x84, 0xef,
- 0x96, 0xd7, 0x4c, 0x77, 0x83, 0x16, 0x0f, 0x0d, 0x58, 0xbf, 0xbc, 0xdb,
- 0x79, 0x8c, 0xb1, 0x7f, 0xe8, 0x64, 0x31, 0xe0, 0x52, 0x75, 0x8b, 0x6a,
- 0x4f, 0xb1, 0x8b, 0xef, 0xf6, 0xb3, 0xa9, 0x00, 0x67, 0x58, 0xbf, 0xdc,
- 0x7f, 0x04, 0xe1, 0x4a, 0xc5, 0xfd, 0x31, 0xea, 0x70, 0x6b, 0x15, 0x03,
- 0xe3, 0xf9, 0xad, 0xff, 0xfa, 0x63, 0x9d, 0x49, 0xe6, 0x7d, 0xf6, 0x01,
- 0xd6, 0x2a, 0x4f, 0xdf, 0xe4, 0x57, 0x36, 0xca, 0xc5, 0xe9, 0x1c, 0x4b,
- 0x15, 0x05, 0x4d, 0x0d, 0x0d, 0x9d, 0x13, 0x7e, 0x31, 0x0e, 0x10, 0xf8,
- 0x6a, 0xfb, 0x47, 0xf8, 0xd6, 0x2f, 0xfe, 0xd4, 0x0b, 0x3d, 0xc9, 0x3f,
- 0xba, 0x58, 0xa9, 0x3e, 0xa1, 0x12, 0x5d, 0x84, 0xb1, 0x6e, 0xd6, 0x2f,
- 0xe3, 0x76, 0x45, 0xf6, 0xd2, 0xc5, 0xb6, 0x70, 0xf1, 0x98, 0x4e, 0x86,
- 0x88, 0x5c, 0x5c, 0xbf, 0xf3, 0xb6, 0xec, 0xff, 0xc5, 0x90, 0x58, 0xbf,
- 0x41, 0xba, 0x7d, 0x2c, 0x57, 0xcf, 0xa7, 0x88, 0x17, 0x9d, 0xfa, 0x54,
- 0x56, 0x85, 0xf8, 0xde, 0xf8, 0x2e, 0xd6, 0x2a, 0x4f, 0xe7, 0xa2, 0x26,
- 0x2a, 0xbf, 0x84, 0xc6, 0xea, 0x46, 0xb1, 0x7f, 0xa7, 0x40, 0x0f, 0x93,
- 0x8b, 0x17, 0xfa, 0x46, 0x3c, 0xc0, 0x71, 0x62, 0xff, 0xf3, 0x7a, 0x13,
- 0xd7, 0xdb, 0xdc, 0x7e, 0xd6, 0x2b, 0x49, 0x88, 0x1c, 0xbb, 0xe5, 0xfe,
- 0x34, 0xde, 0x67, 0x7f, 0x03, 0x6e, 0x69, 0x8d, 0x58, 0xbf, 0xec, 0x1b,
- 0x72, 0x22, 0x91, 0xac, 0x50, 0xcf, 0xa9, 0xcc, 0x6f, 0xfa, 0x7a, 0xc3,
- 0xe1, 0x7b, 0x65, 0x62, 0xff, 0x7e, 0x74, 0x0f, 0x64, 0x6b, 0x17, 0xf8,
- 0xb2, 0x1b, 0x5b, 0xf0, 0x58, 0xbb, 0xec, 0x74, 0x53, 0x7c, 0xf3, 0xc6,
- 0xb7, 0xff, 0x3c, 0x36, 0xea, 0x7c, 0xdd, 0x30, 0xd6, 0x2d, 0x05, 0x8b,
- 0x42, 0x4f, 0x67, 0xb4, 0x7b, 0xc2, 0xe7, 0x96, 0x2f, 0xff, 0xd0, 0x72,
- 0x6f, 0x4f, 0xfa, 0xc1, 0x94, 0xf1, 0x62, 0xff, 0xfc, 0xdb, 0xb2, 0x42,
- 0x83, 0x73, 0x93, 0xb4, 0xfd, 0x2c, 0x53, 0x22, 0xbd, 0xd5, 0x2f, 0xff,
- 0xba, 0x9d, 0x60, 0x1c, 0xef, 0x09, 0x6e, 0x96, 0x2f, 0xff, 0xa1, 0xcc,
- 0x29, 0x3b, 0xe7, 0xbd, 0x27, 0x58, 0xb7, 0xa5, 0x13, 0xce, 0xa1, 0x47,
- 0x4e, 0xcf, 0xf0, 0xcd, 0xf4, 0x2f, 0xef, 0xff, 0xfe, 0xde, 0xde, 0xe6,
- 0x1b, 0xd7, 0xdb, 0xd9, 0x11, 0x49, 0xe3, 0xc3, 0x16, 0x2f, 0xff, 0xbc,
- 0xf9, 0xc1, 0xe4, 0x3f, 0x3b, 0xc7, 0x2b, 0x17, 0xff, 0xff, 0xf3, 0x78,
- 0x78, 0x2e, 0x6d, 0xfe, 0x75, 0xf1, 0x46, 0xd8, 0x5d, 0xc3, 0x9c, 0x14,
- 0xac, 0x53, 0xa3, 0x7c, 0x94, 0x6a, 0x53, 0x78, 0x78, 0xd5, 0xef, 0xef,
- 0x3f, 0xf6, 0x8e, 0x56, 0x2f, 0x40, 0x51, 0x2c, 0x54, 0x9e, 0x7b, 0x98,
- 0x5f, 0x43, 0xcd, 0x1a, 0xc5, 0xfb, 0x9c, 0x72, 0x8d, 0x62, 0xfc, 0x1f,
- 0x8a, 0x40, 0xb1, 0x6f, 0xac, 0x57, 0x68, 0x88, 0x39, 0x26, 0xf2, 0x90,
- 0xca, 0x6f, 0xff, 0x80, 0xf9, 0xf7, 0x6d, 0xd9, 0x39, 0x39, 0xab, 0x17,
- 0xfe, 0x6e, 0x60, 0xfb, 0xe4, 0xeb, 0x8b, 0x17, 0xf9, 0xe1, 0xe6, 0x8f,
- 0xec, 0xb1, 0x52, 0x98, 0x36, 0x20, 0xf4, 0xa2, 0xc8, 0x17, 0xec, 0xfb,
- 0x61, 0xd6, 0x2f, 0xcc, 0x03, 0xb6, 0x96, 0x2f, 0xfc, 0x36, 0xde, 0xc3,
- 0xc3, 0x33, 0xeb, 0x17, 0xff, 0x49, 0x0d, 0xce, 0xf0, 0x96, 0xe9, 0x62,
- 0xff, 0xff, 0x9f, 0xd2, 0x4f, 0x1c, 0xea, 0x5a, 0x12, 0x72, 0x93, 0x56,
- 0x2f, 0xf3, 0x71, 0x84, 0x17, 0x1c, 0xac, 0x51, 0x22, 0x6f, 0xcc, 0x97,
- 0xf7, 0xe7, 0xa2, 0x73, 0xac, 0x5f, 0xf9, 0xdb, 0xaf, 0xb8, 0xa3, 0xd3,
- 0x2c, 0x53, 0x1f, 0x71, 0x17, 0x5e, 0xe8, 0x52, 0xb1, 0x7f, 0xa3, 0x9c,
- 0x21, 0xfe, 0x56, 0x2d, 0x8c, 0x7a, 0x2e, 0x3d, 0x51, 0xaa, 0x94, 0x19,
- 0x3e, 0x14, 0x74, 0x82, 0xd0, 0xde, 0xfc, 0x24, 0x09, 0xc6, 0xff, 0xf3,
- 0xf7, 0xcf, 0xcf, 0x33, 0xc4, 0xe6, 0xac, 0x5f, 0xe8, 0x4e, 0xa3, 0x9d,
- 0x46, 0xb1, 0x7d, 0x0d, 0x61, 0xd6, 0x2f, 0x66, 0x80, 0xb1, 0x7e, 0x8b,
- 0x06, 0x7d, 0xc5, 0x8b, 0xfc, 0x79, 0xef, 0x53, 0xdf, 0x96, 0x2f, 0xe2,
- 0x93, 0x3b, 0x87, 0x16, 0x2b, 0xb4, 0x69, 0xb1, 0x1c, 0x43, 0xa7, 0x2d,
- 0xdd, 0x36, 0xbc, 0x68, 0xba, 0x58, 0xa9, 0x4d, 0xdf, 0x23, 0x09, 0x35,
- 0x3a, 0xff, 0xff, 0xfc, 0xdd, 0x67, 0xa4, 0xbd, 0xcd, 0xb2, 0xc3, 0xc3,
- 0xed, 0xd4, 0xb4, 0x1f, 0x8b, 0x17, 0xff, 0x9d, 0xbc, 0x2d, 0x3f, 0x03,
- 0xc2, 0xe9, 0x62, 0xff, 0xff, 0x61, 0xbc, 0xfc, 0x97, 0x87, 0xf9, 0xe1,
- 0x09, 0xfc, 0xb1, 0x7f, 0xfd, 0xa0, 0x70, 0x1f, 0x78, 0x37, 0x8a, 0x40,
- 0xb1, 0x58, 0x9c, 0x0f, 0xe1, 0x0a, 0x49, 0x62, 0x61, 0xbf, 0xb3, 0xce,
- 0x40, 0x12, 0xc5, 0xfd, 0xfd, 0xad, 0x1b, 0x92, 0xc5, 0xfc, 0x7e, 0x0c,
- 0x9c, 0xc5, 0x8b, 0xf0, 0x38, 0x16, 0x05, 0x81, 0x62, 0xc5, 0x49, 0xf4,
- 0x39, 0x7d, 0xfb, 0xa6, 0x1e, 0x12, 0xc5, 0xf6, 0x9a, 0x4e, 0xb1, 0x73,
- 0x8d, 0x62, 0xbb, 0x37, 0x20, 0x22, 0xac, 0x44, 0x1b, 0xb0, 0xdf, 0xe7,
- 0xf3, 0x79, 0x81, 0xc5, 0x8a, 0x82, 0x77, 0x98, 0x5a, 0x50, 0x98, 0xe4,
- 0x28, 0xc4, 0x43, 0x7f, 0x4e, 0xbd, 0xcc, 0x82, 0xc5, 0xff, 0x6a, 0x22,
- 0xc1, 0xfe, 0x77, 0xac, 0x5f, 0xf6, 0x81, 0x83, 0x7f, 0x0a, 0x56, 0x2f,
- 0xfc, 0x3f, 0x89, 0xcd, 0xc1, 0xbc, 0x16, 0x2b, 0x11, 0x6a, 0xe7, 0x84,
- 0x73, 0x41, 0x46, 0xe1, 0xf0, 0x2a, 0x35, 0xb1, 0xb6, 0x4c, 0xa9, 0x28,
- 0xe1, 0x9a, 0x38, 0x53, 0x64, 0xa1, 0x43, 0x61, 0x6f, 0xd4, 0x31, 0xfb,
- 0x84, 0xa3, 0x47, 0xb7, 0xa8, 0xec, 0xce, 0xef, 0xf8, 0xeb, 0x9e, 0x56,
- 0x80, 0x1b, 0xca, 0x3c, 0x2e, 0x47, 0x6f, 0xe8, 0xff, 0x77, 0xa9, 0x87,
- 0x0e, 0x3b, 0xe0, 0x87, 0x0f, 0x71, 0x62, 0x82, 0x27, 0x5e, 0x6c, 0x70,
- 0xb7, 0xf3, 0x01, 0xf7, 0xcf, 0x96, 0x2f, 0xa7, 0xa6, 0xe9, 0x62, 0xa0,
- 0x7a, 0x66, 0x17, 0xdf, 0xff, 0xbf, 0x85, 0x86, 0xfd, 0xe1, 0xf3, 0x1c,
- 0x33, 0xac, 0x5f, 0x74, 0xef, 0xd2, 0xa2, 0xc0, 0x2a, 0x08, 0x89, 0xd2,
- 0xc5, 0xfe, 0x3b, 0x70, 0x53, 0xa8, 0x96, 0x2f, 0xd1, 0x73, 0x53, 0xbd,
- 0x62, 0xfb, 0xa0, 0xff, 0x12, 0xc5, 0x4a, 0x22, 0x18, 0xd5, 0xcb, 0x2f,
- 0x00, 0x30, 0x2c, 0x5f, 0x87, 0x98, 0x0e, 0x2c, 0x54, 0xa7, 0x97, 0x90,
- 0xac, 0xe4, 0x2a, 0xfc, 0x5a, 0x18, 0xfd, 0xfe, 0x1c, 0x84, 0xef, 0xc2,
- 0x95, 0x8a, 0x08, 0x88, 0xb1, 0x2a, 0x5f, 0xb5, 0xd3, 0xbf, 0x4a, 0x89,
- 0xd4, 0xbf, 0xff, 0xdf, 0x98, 0xc7, 0x87, 0x09, 0xce, 0x67, 0xdb, 0x82,
- 0x8d, 0x62, 0xfc, 0x10, 0xef, 0x00, 0x98, 0x89, 0xd8, 0x8d, 0xef, 0xff,
- 0xe2, 0x14, 0xfb, 0x98, 0x41, 0x00, 0x09, 0xfb, 0xc6, 0xb1, 0x79, 0xe2,
- 0x75, 0x8b, 0xa7, 0x8b, 0x17, 0x10, 0x48, 0x8d, 0xa7, 0x87, 0x6a, 0x51,
- 0x81, 0x90, 0x91, 0xbc, 0x6c, 0x9d, 0x62, 0xf4, 0x73, 0xd2, 0xc5, 0xff,
- 0x7c, 0x5d, 0x8d, 0xb7, 0xc8, 0xd6, 0x2d, 0x91, 0x9e, 0xe7, 0x87, 0xef,
- 0x9f, 0xa0, 0xce, 0xb1, 0x7a, 0x1c, 0x08, 0x6a, 0x31, 0xc9, 0xeb, 0x79,
- 0x45, 0xf7, 0x4e, 0xfd, 0x2a, 0x2d, 0x92, 0xff, 0x36, 0xbe, 0xfb, 0xd8,
- 0x2e, 0xb1, 0x5a, 0x3e, 0xaf, 0x98, 0xdf, 0xfd, 0xf6, 0xf7, 0xc5, 0xde,
- 0x1d, 0xfb, 0x58, 0xbf, 0xbc, 0xff, 0xda, 0x39, 0x58, 0xbf, 0xff, 0xa0,
- 0x13, 0x92, 0xd8, 0x36, 0xce, 0x67, 0x8a, 0x56, 0x2a, 0x51, 0x14, 0xe6,
- 0x17, 0xe8, 0x4b, 0x6f, 0x95, 0x8b, 0xf6, 0x10, 0x0f, 0x8b, 0x17, 0xfd,
- 0x3c, 0x09, 0xf6, 0xe9, 0xf4, 0xb1, 0x7f, 0xcd, 0x84, 0x6c, 0xef, 0x7f,
- 0xac, 0x54, 0xa3, 0x1b, 0xa2, 0x90, 0x13, 0xec, 0x9e, 0x5f, 0xf4, 0xc2,
- 0x75, 0x1c, 0xea, 0x35, 0x8b, 0xef, 0xb1, 0x9b, 0x1a, 0xc5, 0xff, 0xfe,
- 0xef, 0xed, 0xc7, 0xf4, 0x9c, 0xd9, 0xe3, 0x6c, 0xcf, 0x96, 0x28, 0x68,
- 0x8e, 0x72, 0x9b, 0xfd, 0xe8, 0x3c, 0x3f, 0x31, 0xac, 0x58, 0x26, 0x2b,
- 0x3a, 0xe8, 0x88, 0xf0, 0xd1, 0x78, 0x73, 0x92, 0x07, 0x21, 0x93, 0xe2,
- 0x2b, 0xff, 0xf0, 0x36, 0x70, 0x27, 0xe5, 0xbd, 0xc9, 0x8f, 0x38, 0xb1,
- 0x7f, 0xe2, 0x08, 0x71, 0x37, 0x89, 0xf7, 0x56, 0x2f, 0xcf, 0xcf, 0xbc,
- 0x16, 0x2f, 0xf0, 0xbc, 0x0d, 0x0a, 0x1c, 0x58, 0xad, 0x1e, 0xf1, 0x14,
- 0x5f, 0xcf, 0xad, 0x97, 0x23, 0x56, 0x2f, 0x0b, 0x81, 0x30, 0xf4, 0x88,
- 0x86, 0xc0, 0xc4, 0xc9, 0xc1, 0x0f, 0x3a, 0xc4, 0xec, 0x1e, 0x38, 0x2b,
- 0xbb, 0xe9, 0x62, 0xfb, 0xa7, 0x7e, 0x95, 0x17, 0x31, 0x63, 0xac, 0x56,
- 0x8f, 0x0c, 0xc3, 0x1b, 0xf8, 0xb3, 0xb0, 0x34, 0x16, 0x2c, 0x17, 0x58,
- 0xad, 0x1e, 0x26, 0xf2, 0xeb, 0xce, 0x7e, 0x2c, 0x5d, 0x11, 0xd6, 0x2c,
- 0x4b, 0x14, 0xb1, 0x85, 0x8d, 0x4a, 0x69, 0x38, 0xba, 0xcc, 0xee, 0x48,
- 0x60, 0xee, 0xc9, 0x55, 0xfd, 0x18, 0x4d, 0x88, 0x28, 0x14, 0xd8, 0x96,
- 0x2f, 0xee, 0xc2, 0x7b, 0x8f, 0xa5, 0x8a, 0x08, 0x8c, 0xfc, 0x58, 0x74,
- 0x5b, 0xf6, 0xba, 0x77, 0xe9, 0x51, 0x77, 0x97, 0xfa, 0x01, 0x39, 0xad,
- 0x31, 0x8b, 0x16, 0x09, 0x87, 0xde, 0xe6, 0xf7, 0xfc, 0x52, 0xf1, 0xf7,
- 0xc9, 0x1a, 0xc5, 0xc3, 0x02, 0xc5, 0xd3, 0xba, 0xb1, 0x78, 0xb2, 0x35,
- 0x8b, 0x04, 0x1a, 0x22, 0x4d, 0x3a, 0x00, 0xc1, 0x0d, 0x54, 0xc6, 0x2e,
- 0x97, 0x98, 0xec, 0x54, 0xe9, 0x6b, 0xb8, 0x64, 0xb5, 0x74, 0xc3, 0xa9,
- 0x5a, 0xc7, 0x86, 0x17, 0xe3, 0x04, 0x78, 0x76, 0x82, 0x5f, 0x51, 0x4a,
- 0x2b, 0xe4, 0xa4, 0x0f, 0x42, 0x7c, 0x38, 0x58, 0xdf, 0xf8, 0xc7, 0x28,
- 0xf8, 0xc5, 0xdc, 0x16, 0x2f, 0xfe, 0xc8, 0xf0, 0xcf, 0xe7, 0x31, 0x89,
- 0x62, 0xff, 0xcc, 0x45, 0x86, 0xf4, 0x27, 0x1a, 0xc5, 0xfb, 0x3e, 0x37,
- 0x25, 0x8b, 0x98, 0x27, 0xd1, 0xd6, 0x48, 0x3c, 0x44, 0x0c, 0xfe, 0xfd,
- 0xce, 0x1d, 0xe0, 0xb1, 0x7f, 0xfe, 0xfc, 0x94, 0x7c, 0x13, 0xb4, 0x39,
- 0xf7, 0x82, 0xc5, 0xff, 0xfb, 0xf2, 0x51, 0xf0, 0x4e, 0xd0, 0xe7, 0xde,
- 0x0b, 0x17, 0xff, 0xff, 0xf3, 0x49, 0x78, 0x9c, 0xdc, 0xf0, 0xbc, 0xde,
- 0xe7, 0xdb, 0x53, 0x1b, 0xeb, 0xa5, 0x8b, 0xbe, 0xc3, 0x46, 0xff, 0xd5,
- 0xae, 0xe4, 0xac, 0x5f, 0xfd, 0xdf, 0x42, 0x7e, 0xfd, 0x98, 0x46, 0xac,
- 0x5e, 0x27, 0x09, 0x29, 0xf5, 0x8c, 0xa7, 0xa8, 0xcd, 0x78, 0x5d, 0xe1,
- 0x7b, 0xf8, 0x29, 0xb0, 0x4f, 0x7a, 0x8d, 0x62, 0xf1, 0xc5, 0xb8, 0xb1,
- 0x78, 0x4e, 0x75, 0x8b, 0xe1, 0x6e, 0x8e, 0x56, 0x2f, 0xd9, 0xbb, 0xe9,
- 0x35, 0x62, 0xdb, 0xab, 0x15, 0x19, 0xe0, 0xe1, 0x65, 0xf7, 0x1b, 0xad,
- 0x2c, 0x54, 0x68, 0xeb, 0xd1, 0x0f, 0xc7, 0x49, 0x9c, 0xc2, 0x2b, 0xff,
- 0x71, 0xcd, 0xfb, 0x49, 0x0a, 0x56, 0x2f, 0xfd, 0xf7, 0xf3, 0xff, 0xb8,
- 0x67, 0x96, 0x2b, 0x0f, 0xf9, 0x8f, 0xae, 0x70, 0x2c, 0x5f, 0xff, 0xfe,
- 0x27, 0x30, 0xb3, 0xde, 0xc8, 0xe4, 0x9c, 0xde, 0x1e, 0x70, 0x86, 0xb1,
- 0x7b, 0x03, 0xe2, 0xc5, 0x62, 0x2a, 0xf4, 0x2f, 0xba, 0xed, 0x79, 0xa2,
- 0xe2, 0xc5, 0xfc, 0x52, 0x03, 0xbc, 0x16, 0x2f, 0xe2, 0x90, 0x1d, 0xe0,
- 0xb1, 0x7f, 0x82, 0x9b, 0x01, 0x60, 0xfe, 0x25, 0x8b, 0xf6, 0x6f, 0x92,
- 0xf6, 0x1f, 0x57, 0x0b, 0x6f, 0xc4, 0x2e, 0x7d, 0xb6, 0xa3, 0xcf, 0x07,
- 0xb5, 0x09, 0x7b, 0xf0, 0xdb, 0x7e, 0xb1, 0x62, 0xdf, 0x93, 0xfc, 0xc5,
- 0x2b, 0xfc, 0xf0, 0xd6, 0x6c, 0xb0, 0x16, 0x2f, 0xf4, 0x94, 0xf5, 0xc0,
- 0x1d, 0x62, 0xfa, 0x62, 0xfb, 0x2c, 0x5e, 0x77, 0xe9, 0x51, 0x2b, 0x97,
- 0xf8, 0xd7, 0x20, 0x7b, 0x3e, 0xb1, 0x51, 0xa2, 0x07, 0xa2, 0x36, 0x2a,
- 0xbd, 0xfc, 0xe9, 0x62, 0xfb, 0x00, 0x2e, 0x2c, 0x5c, 0xfd, 0xe1, 0xe0,
- 0x90, 0xf5, 0xf9, 0xcd, 0x7f, 0x41, 0x62, 0xff, 0xfb, 0x8c, 0xfd, 0xfd,
- 0xdb, 0xc2, 0xd3, 0xf1, 0x62, 0xdd, 0x91, 0xfc, 0xf8, 0xa6, 0xff, 0xef,
- 0xe4, 0x3a, 0xfb, 0x0e, 0x4b, 0xcb, 0x14, 0xc7, 0xdb, 0xe2, 0x8a, 0x82,
- 0xab, 0x61, 0x93, 0x74, 0x6d, 0xa8, 0x5a, 0x9d, 0xc8, 0xa3, 0x12, 0xbf,
- 0xf4, 0x03, 0x86, 0x17, 0xa3, 0xc1, 0xac, 0x5f, 0xfb, 0xa6, 0xd6, 0x7d,
- 0xb5, 0xf7, 0x58, 0xbf, 0xf8, 0x5c, 0xfb, 0xc3, 0xcc, 0xe4, 0x05, 0x8a,
- 0xed, 0x10, 0x7a, 0x3f, 0xbb, 0xed, 0xa4, 0x74, 0x7a, 0x18, 0x97, 0xf6,
- 0x9e, 0x0f, 0xdc, 0x16, 0x2f, 0xc4, 0xe6, 0x06, 0x75, 0x8a, 0x93, 0xd9,
- 0xf1, 0x7d, 0xfd, 0x09, 0x60, 0x31, 0xd6, 0x2f, 0xd3, 0x1f, 0xb3, 0xeb,
- 0x17, 0xf4, 0x9c, 0x7a, 0x7e, 0x96, 0x2b, 0xe7, 0xb0, 0x45, 0x37, 0xff,
- 0x8b, 0xdf, 0xc8, 0x77, 0xed, 0x4e, 0x18, 0xb1, 0x7f, 0xff, 0xf9, 0xc8,
- 0x39, 0x06, 0x43, 0xf3, 0xbc, 0x72, 0x13, 0x08, 0x50, 0xce, 0x2c, 0x54,
- 0xa3, 0x1b, 0x49, 0x97, 0x42, 0x35, 0x8b, 0xee, 0x9e, 0x18, 0xb1, 0x7f,
- 0xff, 0xff, 0xfe, 0x1b, 0x9c, 0xef, 0x08, 0x48, 0x72, 0x36, 0xd3, 0xf6,
- 0x3f, 0xce, 0xb8, 0xce, 0xe5, 0x3d, 0x7e, 0x62, 0x58, 0xbf, 0x8b, 0xc2,
- 0xf8, 0x56, 0x56, 0x2e, 0x6f, 0x4a, 0x38, 0xda, 0x16, 0x35, 0x89, 0x9b,
- 0xbc, 0x60, 0xd7, 0xf1, 0x03, 0x5a, 0x68, 0xd6, 0x2f, 0xf6, 0x6b, 0x8f,
- 0xd0, 0xbb, 0x58, 0xbf, 0xff, 0xbb, 0xe6, 0x6b, 0xde, 0x78, 0xc3, 0x38,
- 0xfe, 0xc6, 0xac, 0x56, 0x22, 0x5d, 0xcd, 0xaf, 0xf7, 0x78, 0xdc, 0xe0,
- 0xa5, 0x62, 0xc2, 0x58, 0xbe, 0xf3, 0x66, 0x96, 0x2f, 0x3c, 0x36, 0x25,
- 0x8a, 0x8c, 0xf5, 0xbe, 0x25, 0xbc, 0x8a, 0xff, 0xb1, 0xb7, 0x94, 0xe6,
- 0xa0, 0xb1, 0x7f, 0xfe, 0xf4, 0x33, 0x71, 0xc8, 0x1d, 0xfb, 0x53, 0x86,
- 0x2c, 0x18, 0x6e, 0x6f, 0xdd, 0xfb, 0xf2, 0x05, 0x8a, 0xc4, 0xc0, 0x1d,
- 0xac, 0x4d, 0x77, 0xff, 0xfb, 0x06, 0xdd, 0x7d, 0x86, 0x3c, 0x30, 0x38,
- 0xbe, 0x23, 0x56, 0x2f, 0xff, 0x44, 0x53, 0xee, 0x7b, 0xbe, 0x98, 0xa3,
- 0x58, 0xbf, 0xe7, 0x30, 0x7f, 0x98, 0xf0, 0xc5, 0x8a, 0x64, 0x45, 0x12,
- 0x75, 0xff, 0xf3, 0x03, 0x0e, 0xde, 0xe4, 0x9d, 0xfb, 0xf2, 0xc5, 0xff,
- 0xfd, 0xbf, 0x07, 0xa9, 0x17, 0x1b, 0x7b, 0xb0, 0xc5, 0x2b, 0x15, 0x88,
- 0xae, 0x65, 0x0b, 0xff, 0xfd, 0xd3, 0xe9, 0xff, 0xdc, 0x33, 0xd9, 0xe9,
- 0x10, 0x5f, 0x16, 0x2f, 0xfe, 0x7e, 0xe0, 0xde, 0xfc, 0xeb, 0xd2, 0xb1,
- 0x7f, 0xd2, 0x7f, 0x64, 0x50, 0x6f, 0x2c, 0x54, 0x13, 0x06, 0x62, 0x13,
- 0xb3, 0x79, 0x16, 0xff, 0xff, 0x7d, 0x86, 0x3c, 0x33, 0xbf, 0x09, 0xf9,
- 0xf3, 0x1c, 0x6b, 0x17, 0xc2, 0x7d, 0x41, 0x62, 0xfe, 0x29, 0x8c, 0x0f,
- 0xe5, 0x8b, 0xfc, 0xe3, 0x0f, 0x76, 0x4a, 0x0b, 0x16, 0x9e, 0x8f, 0x94,
- 0xe5, 0xd7, 0xff, 0xc7, 0x72, 0x07, 0xcc, 0x72, 0x8f, 0xa6, 0x8d, 0x62,
- 0xff, 0xfe, 0xd3, 0xf3, 0x0a, 0x70, 0x1c, 0xc8, 0xa7, 0xbe, 0x2c, 0x5c,
- 0xde, 0x74, 0x57, 0x09, 0x4e, 0x86, 0x9c, 0x5b, 0x42, 0x21, 0xe1, 0xad,
- 0x7f, 0xc2, 0x01, 0xde, 0x1c, 0xd0, 0xd6, 0x2f, 0xff, 0xf6, 0x31, 0x7b,
- 0x0b, 0x69, 0x38, 0xe4, 0xa3, 0x9d, 0x2c, 0x57, 0x91, 0x35, 0xbc, 0xee,
- 0xda, 0x58, 0xbf, 0xff, 0x77, 0xe2, 0x9f, 0xbf, 0x33, 0xa2, 0x7c, 0xe9,
- 0x62, 0xb1, 0x11, 0xbd, 0x12, 0x88, 0x4a, 0xff, 0xff, 0xf7, 0xf0, 0xe0,
- 0x7d, 0x66, 0xfc, 0x1e, 0x70, 0x4f, 0xdf, 0xcc, 0x7f, 0x2c, 0x5f, 0xe9,
- 0xfb, 0x7b, 0x8f, 0xda, 0xc5, 0xff, 0xb3, 0xbf, 0x7a, 0x4f, 0xfc, 0x8d,
- 0x62, 0xff, 0xa2, 0xeb, 0xec, 0x79, 0xd1, 0xab, 0x17, 0xf8, 0x19, 0xac,
- 0xcf, 0x71, 0x62, 0xfa, 0x3f, 0x67, 0x4b, 0x15, 0x88, 0x95, 0xec, 0xf7,
- 0x46, 0x75, 0x2c, 0x83, 0x81, 0xc3, 0xc7, 0x23, 0xd5, 0xe8, 0xf7, 0xf1,
- 0xf8, 0x14, 0x6c, 0x1e, 0x30, 0x13, 0xd9, 0x86, 0x81, 0xc3, 0x5a, 0xf6,
- 0x01, 0xd6, 0x2f, 0x6b, 0x3b, 0x58, 0xbd, 0xf7, 0x87, 0xcd, 0xd0, 0x07,
- 0x2f, 0xfe, 0x76, 0xf4, 0x97, 0x4c, 0x73, 0xb2, 0xc5, 0xf7, 0xe4, 0xbc,
- 0xb1, 0x73, 0x0f, 0xe7, 0xcb, 0xc4, 0x3b, 0x67, 0xd1, 0x88, 0x50, 0x97,
- 0xbf, 0xec, 0xef, 0x83, 0x97, 0x28, 0xd6, 0x2f, 0xf3, 0xf2, 0x4b, 0xdf,
- 0x65, 0x8b, 0xf1, 0xe2, 0xe3, 0x12, 0xc5, 0xff, 0xdd, 0x36, 0xbf, 0x91,
- 0x7d, 0xb5, 0x1a, 0xc5, 0xff, 0xce, 0x0c, 0x2e, 0xfd, 0xa9, 0xc3, 0x16,
- 0x2f, 0xf9, 0xe1, 0xcf, 0xce, 0x83, 0x1a, 0xc5, 0x41, 0x38, 0x9c, 0x2c,
- 0x34, 0xeb, 0xa3, 0x2e, 0xca, 0x49, 0x23, 0xc8, 0xb7, 0xe0, 0x44, 0xc2,
- 0x0b, 0xac, 0x5f, 0xff, 0xef, 0xe7, 0x45, 0x87, 0xc2, 0xcf, 0x08, 0x07,
- 0x78, 0x2c, 0x5f, 0xdf, 0x73, 0x94, 0xf6, 0xb1, 0x7f, 0xe2, 0xcf, 0xe4,
- 0x50, 0x6d, 0x41, 0x62, 0xff, 0xff, 0xf8, 0x12, 0x5d, 0x3f, 0x9f, 0xb0,
- 0x66, 0xf6, 0xf4, 0x3e, 0xde, 0xe3, 0x0d, 0x62, 0xff, 0xcd, 0xbd, 0xbd,
- 0x14, 0x24, 0xbc, 0xb1, 0x52, 0x9d, 0xe4, 0x0b, 0xb1, 0x83, 0xa2, 0xee,
- 0xcf, 0xfd, 0x08, 0x0b, 0xff, 0xcf, 0x90, 0xfe, 0x31, 0x60, 0x36, 0x71,
- 0x62, 0xf3, 0xc0, 0x26, 0xc0, 0xde, 0x71, 0x4c, 0x64, 0xb0, 0x86, 0x48,
- 0xe1, 0x97, 0x93, 0x8a, 0xfd, 0x46, 0x99, 0xdc, 0x23, 0x18, 0x86, 0x28,
- 0x42, 0xea, 0x1c, 0xe7, 0x22, 0xfc, 0x6a, 0x0e, 0x50, 0x08, 0x63, 0x05,
- 0xc8, 0x4a, 0x38, 0xae, 0x52, 0x19, 0xfd, 0x2c, 0xc8, 0x39, 0x44, 0x5b,
- 0xab, 0xb7, 0x05, 0xf1, 0x62, 0xfd, 0xe9, 0x10, 0x5f, 0x16, 0x2f, 0xfa,
- 0x19, 0xef, 0xb4, 0xe8, 0x0b, 0x17, 0xec, 0xe9, 0xe1, 0x8b, 0x17, 0xfb,
- 0x06, 0xc5, 0xec, 0xfa, 0xc5, 0xff, 0xfc, 0x3f, 0xc9, 0x47, 0xc1, 0x3b,
- 0x43, 0x9f, 0x78, 0x2c, 0x5e, 0xcf, 0x84, 0x0b, 0x13, 0x36, 0xc1, 0xbe,
- 0xcb, 0x3e, 0x72, 0x45, 0x1c, 0x32, 0xbf, 0xff, 0xfe, 0x1e, 0x04, 0xe4,
- 0x1b, 0xf3, 0xdc, 0x30, 0xf9, 0xbd, 0xbc, 0x09, 0x1c, 0xac, 0x5e, 0x69,
- 0x75, 0x8b, 0xde, 0x91, 0xa4, 0x5f, 0xfe, 0xfb, 0xb7, 0xa6, 0x0d, 0xa8,
- 0xc4, 0x04, 0x8b, 0xda, 0x0b, 0x84, 0x93, 0xe8, 0xe0, 0xed, 0xe7, 0xe8,
- 0x24, 0x11, 0x78, 0x38, 0x41, 0xd8, 0x20, 0xdd, 0x20, 0xef, 0x52, 0x8d,
- 0x4f, 0x5e, 0xa2, 0xfa, 0x55, 0xd8, 0x9b, 0xf7, 0xc6, 0x7b, 0x7f, 0xf8,
- 0x21, 0xde, 0x01, 0x33, 0x5d, 0x3b, 0xf4, 0xa8, 0x98, 0x4b, 0xe9, 0x60,
- 0xfe, 0xb1, 0x7f, 0xbf, 0x24, 0xe7, 0x9d, 0xd5, 0x8b, 0xcc, 0x1f, 0xd6,
- 0x2f, 0xff, 0xec, 0xde, 0xe3, 0xfc, 0x84, 0xf7, 0xf0, 0x62, 0xf7, 0x16,
- 0x2f, 0xff, 0x69, 0xc0, 0x10, 0xdf, 0x40, 0xc9, 0xe4, 0x16, 0x2e, 0xc0,
- 0x83, 0x4c, 0x99, 0xc8, 0xc0, 0x6a, 0x43, 0xc1, 0xb0, 0x5d, 0xb1, 0x6c,
- 0x25, 0x8b, 0x6f, 0x58, 0xa0, 0xa9, 0xb7, 0x39, 0x1d, 0xf9, 0xbf, 0xfc,
- 0x8d, 0x62, 0xf6, 0xc7, 0xf1, 0xac, 0x5f, 0xfc, 0x15, 0xce, 0xe0, 0x27,
- 0xf1, 0x4c, 0x16, 0x2f, 0xb6, 0x1e, 0x40, 0xeb, 0x17, 0xed, 0x83, 0x60,
- 0xd8, 0xb6, 0x42, 0x8b, 0x17, 0x78, 0x2c, 0x58, 0xbb, 0xbd, 0xc5, 0x8b,
- 0xf7, 0xd8, 0xf3, 0xd2, 0xc5, 0xd8, 0x7d, 0xa7, 0x8b, 0xd0, 0xe5, 0xfd,
- 0x27, 0xc0, 0x4e, 0xf5, 0x8b, 0xff, 0xde, 0xe0, 0xa7, 0x6f, 0x5f, 0x6d,
- 0x97, 0x8d, 0x62, 0x86, 0x8b, 0x1f, 0x98, 0x11, 0x7d, 0xfe, 0xd6, 0x75,
- 0x20, 0x0c, 0xeb, 0x17, 0xef, 0x3c, 0x6f, 0xc5, 0x8b, 0xe9, 0x3b, 0x69,
- 0x62, 0xd3, 0x11, 0xe5, 0xe8, 0xa6, 0xf8, 0x41, 0xe4, 0x6b, 0x17, 0xd2,
- 0x4d, 0x12, 0xc5, 0xff, 0xfb, 0x23, 0xdb, 0x98, 0x5e, 0xfb, 0xb7, 0x1b,
- 0x7a, 0xc5, 0xfb, 0xf2, 0x36, 0x35, 0x62, 0x99, 0x3a, 0x0d, 0x17, 0x9e,
- 0x10, 0x3f, 0x28, 0x22, 0x5f, 0x11, 0x6e, 0xac, 0x5f, 0xf6, 0x19, 0xf6,
- 0xf7, 0x1f, 0x4b, 0x17, 0xc3, 0xea, 0x4e, 0xb1, 0x78, 0x3e, 0x12, 0xc5,
- 0x31, 0xe1, 0x7c, 0x92, 0xe0, 0xa7, 0x96, 0x2f, 0xa2, 0x63, 0x22, 0x58,
- 0xbf, 0xd2, 0x76, 0xfc, 0xe1, 0x2c, 0x5c, 0xfc, 0x58, 0xa3, 0x9f, 0x77,
- 0x89, 0xb7, 0x98, 0xdf, 0xde, 0x9d, 0xe4, 0xfd, 0xac, 0x5f, 0x8b, 0xa6,
- 0x2c, 0x58, 0xbf, 0xf7, 0x07, 0xa2, 0x73, 0x33, 0xbf, 0x2c, 0x5f, 0xe3,
- 0x0b, 0x3b, 0xf6, 0x7d, 0x62, 0xb0, 0xfd, 0x99, 0x06, 0xff, 0x4b, 0xc7,
- 0xe3, 0x5f, 0x4b, 0x17, 0xe7, 0xd4, 0x1c, 0xeb, 0x14, 0x35, 0x40, 0xb9,
- 0x08, 0xae, 0xcc, 0x58, 0xc3, 0xf0, 0x9d, 0x22, 0x01, 0x1a, 0xd8, 0xeb,
- 0x17, 0xfb, 0xdf, 0x76, 0xe3, 0x6f, 0x58, 0xb0, 0x51, 0x62, 0x88, 0xf2,
- 0xf6, 0x4d, 0x6f, 0xf7, 0x27, 0x08, 0x7f, 0x95, 0x8b, 0xfa, 0x70, 0x87,
- 0xf9, 0x58, 0xbc, 0x2d, 0x45, 0xb4, 0xf7, 0xb8, 0x65, 0x7d, 0xd1, 0x4f,
- 0xd6, 0x2f, 0xf1, 0x9b, 0x70, 0x7f, 0x9d, 0xeb, 0x17, 0xfe, 0x16, 0x1b,
- 0x9e, 0x14, 0xf6, 0x35, 0x8a, 0x93, 0xfa, 0x63, 0x9b, 0xfc, 0x42, 0xf6,
- 0x78, 0x38, 0xd6, 0x2b, 0x11, 0xe7, 0xa8, 0x4e, 0xf8, 0x82, 0xec, 0x31,
- 0x62, 0xff, 0x87, 0x90, 0xfc, 0xef, 0x1c, 0xac, 0x5d, 0xbe, 0x35, 0x8b,
- 0xda, 0xfb, 0xed, 0x3d, 0x66, 0x3b, 0xbf, 0xf0, 0xdf, 0xf2, 0xed, 0xac,
- 0xed, 0x62, 0x98, 0xfc, 0x83, 0x34, 0xbf, 0xe3, 0x03, 0xfc, 0xf5, 0xf6,
- 0x89, 0x62, 0xf8, 0x47, 0xc1, 0xac, 0x57, 0x67, 0xc3, 0xba, 0x7d, 0x7f,
- 0xff, 0xdf, 0xc8, 0x64, 0x3f, 0x85, 0x86, 0xfd, 0xe1, 0x90, 0x3a, 0xc5,
- 0x62, 0x23, 0x3c, 0x4d, 0x7e, 0xd4, 0xc3, 0x98, 0xb1, 0x7c, 0xde, 0xcd,
- 0xeb, 0x17, 0xfb, 0x0c, 0xf1, 0x38, 0x38, 0xb1, 0x52, 0x88, 0x0f, 0x94,
- 0x78, 0x92, 0xff, 0xff, 0xba, 0x7d, 0x4f, 0xa6, 0x1b, 0x43, 0xf1, 0x60,
- 0x1c, 0x80, 0xb1, 0x7b, 0xef, 0x05, 0x8a, 0x82, 0xec, 0x1e, 0x2e, 0xf5,
- 0x08, 0x2d, 0x46, 0x54, 0x73, 0x4f, 0xc3, 0x80, 0xa3, 0x0f, 0xf4, 0x28,
- 0x84, 0x5f, 0xbd, 0xa6, 0xff, 0xdc, 0xfc, 0x9f, 0xdc, 0x27, 0xed, 0x62,
- 0xf8, 0x85, 0xa9, 0x58, 0xb3, 0xf6, 0x7c, 0x4e, 0x81, 0x7f, 0xfd, 0x25,
- 0xed, 0x4b, 0x40, 0xb0, 0xef, 0x05, 0x8b, 0xf1, 0xcf, 0x82, 0x89, 0x62,
- 0xff, 0xf4, 0xf5, 0xc1, 0x79, 0xbe, 0xc6, 0xfd, 0x96, 0x2f, 0xe3, 0xce,
- 0x17, 0xb6, 0x56, 0x2f, 0xb4, 0xdd, 0xc1, 0x62, 0xdc, 0x58, 0xbf, 0x4e,
- 0x17, 0xb6, 0x56, 0x2f, 0x71, 0xfb, 0xda, 0x89, 0x06, 0x30, 0x88, 0x90,
- 0xe2, 0x54, 0x34, 0xe9, 0x34, 0x9a, 0x72, 0xaf, 0x43, 0x72, 0xff, 0xb7,
- 0x30, 0x7f, 0x9d, 0xc2, 0x95, 0x8a, 0x64, 0x40, 0xba, 0x1d, 0xff, 0x6a,
- 0x3e, 0xbe, 0xdf, 0x17, 0x96, 0x2b, 0xe7, 0xbc, 0xe4, 0x37, 0xf9, 0x8d,
- 0xd6, 0x47, 0x31, 0xac, 0x5f, 0xa4, 0xfb, 0xc1, 0x05, 0x8a, 0xe1, 0xf0,
- 0xf8, 0xda, 0xef, 0x32, 0xc5, 0xc2, 0xc5, 0x8b, 0xb5, 0xc5, 0x8a, 0x81,
- 0xf4, 0x1a, 0x44, 0x01, 0x7d, 0x91, 0x7b, 0xff, 0xf4, 0x05, 0xa9, 0xe8,
- 0xcc, 0x6f, 0xf4, 0xd1, 0xee, 0xac, 0x5e, 0xd4, 0xef, 0x58, 0xba, 0x7c,
- 0xb1, 0x52, 0x6d, 0xb4, 0x3f, 0x7e, 0xe9, 0xb9, 0xf6, 0x58, 0xbf, 0xb1,
- 0x8b, 0xc2, 0xfa, 0xc5, 0x76, 0x7a, 0xdf, 0x29, 0xbf, 0x74, 0x4d, 0xdc,
- 0x16, 0x2a, 0x24, 0xd5, 0xb9, 0x09, 0x3f, 0x3b, 0x08, 0x8e, 0xf1, 0xf6,
- 0xe2, 0xc5, 0xfd, 0xac, 0x6f, 0xc8, 0xd6, 0x2f, 0x68, 0x5c, 0x58, 0xbe,
- 0x92, 0x8b, 0xa5, 0x8b, 0xff, 0xd2, 0x59, 0xef, 0xe7, 0xbf, 0x22, 0x0b,
- 0xac, 0x56, 0x8f, 0xc7, 0xe4, 0x97, 0xf3, 0x6b, 0x6b, 0x90, 0x16, 0x2f,
- 0x7f, 0x3b, 0x58, 0xbf, 0xff, 0xc6, 0x6e, 0xfb, 0x3f, 0xb4, 0xb2, 0x36,
- 0xc2, 0xee, 0x1c, 0x58, 0xbf, 0x19, 0xec, 0xff, 0x4b, 0x15, 0x88, 0x93,
- 0x76, 0x8a, 0x94, 0xff, 0x86, 0x3f, 0x85, 0xad, 0x08, 0xff, 0x91, 0x39,
- 0x79, 0x42, 0xc6, 0xff, 0xf7, 0x89, 0xc1, 0xfc, 0x61, 0x8b, 0xdc, 0x58,
- 0xbe, 0xdf, 0x83, 0x95, 0x8b, 0xf3, 0xc5, 0xc0, 0xf7, 0xac, 0x5f, 0x08,
- 0x7f, 0x95, 0x8a, 0x81, 0xe8, 0x11, 0x6d, 0xf4, 0x32, 0x7b, 0x58, 0xbf,
- 0xe9, 0x8c, 0x38, 0x7c, 0x4f, 0x1a, 0xc5, 0xe9, 0xee, 0x0b, 0x15, 0x29,
- 0xae, 0xe2, 0x53, 0x3a, 0x44, 0x43, 0xa2, 0x32, 0x3d, 0xbf, 0xf7, 0x70,
- 0xdb, 0xf7, 0xea, 0x48, 0x6b, 0x17, 0xf1, 0x30, 0x0f, 0x3b, 0xd6, 0x2f,
- 0x68, 0x07, 0x58, 0xa6, 0x3c, 0xd1, 0x17, 0xdf, 0xcc, 0x4f, 0xd1, 0x62,
- 0xc5, 0x62, 0x37, 0x79, 0x09, 0x01, 0x10, 0xdf, 0x16, 0x31, 0xab, 0x17,
- 0xcd, 0x3d, 0xf1, 0x62, 0xfc, 0x1f, 0x8a, 0x40, 0xb1, 0x47, 0x3e, 0xef,
- 0x11, 0x6f, 0x23, 0xbe, 0xf7, 0xb0, 0xc5, 0x8b, 0xff, 0xd3, 0xe0, 0x4c,
- 0x33, 0xbf, 0x46, 0x23, 0x16, 0x2f, 0xd2, 0x7d, 0x3c, 0x4b, 0x17, 0xff,
- 0xbd, 0x0c, 0xd6, 0x72, 0x58, 0x78, 0x75, 0x8b, 0xfc, 0xdf, 0x61, 0x3b,
- 0x7d, 0x62, 0x98, 0xfe, 0xfe, 0x93, 0x7b, 0x8e, 0x05, 0x8a, 0x94, 0xe1,
- 0x70, 0xc5, 0x89, 0x3e, 0x9c, 0xf0, 0xa4, 0xf1, 0x0d, 0x2c, 0x5f, 0x49,
- 0xda, 0x0b, 0x17, 0x7e, 0x60, 0x6b, 0xb4, 0x19, 0x7a, 0x48, 0xd5, 0x8b,
- 0x9e, 0x0b, 0x17, 0xe9, 0xe8, 0x9c, 0xeb, 0x17, 0xfe, 0x98, 0x6d, 0xcf,
- 0xb6, 0xbe, 0xeb, 0x16, 0x6f, 0x9f, 0x47, 0x0a, 0x2f, 0x7e, 0x7e, 0xb1,
- 0x43, 0x4c, 0x33, 0xb2, 0xcd, 0xc1, 0xdf, 0xbf, 0xf8, 0x9e, 0xe1, 0x46,
- 0xb1, 0x7d, 0x9a, 0x9e, 0x96, 0x2e, 0x8b, 0x83, 0x37, 0x9f, 0x19, 0xbf,
- 0xff, 0xfd, 0x3f, 0xfb, 0xf3, 0x6f, 0xdd, 0xb9, 0xfc, 0x06, 0xdd, 0x67,
- 0x9f, 0xb5, 0x8b, 0xff, 0x77, 0xce, 0xbe, 0xc3, 0x6d, 0x74, 0xb1, 0x7f,
- 0x38, 0x35, 0xa6, 0xd2, 0xc5, 0xef, 0x6d, 0xc5, 0x8a, 0x94, 0xce, 0xb4,
- 0x5c, 0xef, 0x80, 0x43, 0x0c, 0xba, 0xf6, 0x30, 0x16, 0x2f, 0xbe, 0x2e,
- 0xfc, 0xb1, 0x7f, 0xf7, 0xf2, 0x74, 0x58, 0x73, 0x8a, 0x25, 0x8b, 0xfb,
- 0xc1, 0x80, 0x13, 0xda, 0xc5, 0xff, 0x37, 0x9b, 0x0e, 0x59, 0x1a, 0xc5,
- 0x31, 0xf4, 0xfc, 0xc6, 0xfe, 0xe3, 0x1a, 0x77, 0xf2, 0xc5, 0xff, 0xb7,
- 0xc9, 0xb0, 0x62, 0x9d, 0x4a, 0xc5, 0xff, 0xff, 0xb5, 0x9b, 0xe4, 0xbd,
- 0xb4, 0x32, 0x9f, 0xbb, 0x7a, 0x7d, 0xc5, 0x8b, 0xff, 0x7d, 0x9c, 0x1b,
- 0x75, 0xa1, 0x7d, 0x62, 0xee, 0xb6, 0x35, 0x8b, 0xe2, 0x7f, 0x9a, 0xb1,
- 0x7a, 0x31, 0x41, 0x62, 0xf1, 0x67, 0x36, 0x9f, 0x00, 0xc7, 0xb0, 0x8e,
- 0xf9, 0xc1, 0x01, 0xac, 0x5f, 0xe9, 0x3f, 0x44, 0xf9, 0xd2, 0xc5, 0x0d,
- 0x57, 0x37, 0x50, 0xae, 0xec, 0x85, 0x8b, 0xf4, 0x81, 0xe6, 0xfd, 0xf0,
- 0xa2, 0x31, 0x00, 0x32, 0x3b, 0xed, 0xbb, 0xf7, 0x63, 0x58, 0xa1, 0xab,
- 0xc6, 0xc9, 0x61, 0x66, 0xc2, 0x3e, 0xdb, 0x8b, 0x16, 0xdc, 0x58, 0xbd,
- 0x83, 0xf2, 0xc5, 0x31, 0xb2, 0xd0, 0xad, 0xf9, 0xe2, 0x6f, 0x71, 0x62,
- 0x8e, 0x79, 0x3f, 0x20, 0xbf, 0x4e, 0xf7, 0x8a, 0x25, 0x8b, 0xc5, 0x9d,
- 0xac, 0x5d, 0xec, 0x58, 0xbf, 0xf3, 0x6f, 0xc1, 0xff, 0x3a, 0xc2, 0x58,
- 0xbf, 0xd2, 0x52, 0x07, 0x7d, 0xd5, 0x8b, 0xda, 0x78, 0x2c, 0x5f, 0xe1,
- 0xff, 0x3a, 0xfc, 0xe9, 0x62, 0x86, 0x88, 0x6d, 0x1a, 0x10, 0xed, 0xfb,
- 0x99, 0xed, 0x4a, 0xc5, 0xff, 0xe0, 0xb9, 0x49, 0xdd, 0xbe, 0xfe, 0xfc,
- 0xac, 0x54, 0xa7, 0x01, 0x01, 0x76, 0x86, 0x37, 0x0b, 0xc4, 0x51, 0x73,
- 0xf4, 0xb1, 0x7f, 0x34, 0x4f, 0xd7, 0x20, 0xb1, 0x7f, 0xff, 0xc3, 0x1e,
- 0x6c, 0xce, 0xb0, 0x87, 0xf9, 0x0c, 0x00, 0x9e, 0xd6, 0x2b, 0xa4, 0x59,
- 0xfc, 0x61, 0xcc, 0x2f, 0xff, 0x6a, 0x58, 0xb3, 0xdc, 0x9f, 0xb9, 0xd6,
- 0x2f, 0xff, 0xf7, 0xd8, 0x87, 0xac, 0xeb, 0xf3, 0xfc, 0xd6, 0xa4, 0xd5,
- 0x8b, 0xf0, 0xb7, 0x5b, 0x0e, 0xb1, 0x7e, 0xcf, 0x7a, 0x62, 0x58, 0xbf,
- 0x79, 0xce, 0xde, 0x58, 0xa3, 0x4f, 0xf3, 0x45, 0x64, 0x53, 0x4b, 0x17,
- 0xd3, 0x90, 0x75, 0x8a, 0x39, 0xad, 0xf8, 0x65, 0xff, 0x9b, 0xc2, 0xd3,
- 0xf3, 0x69, 0xfc, 0xb1, 0x52, 0x8b, 0xf1, 0xae, 0x39, 0x0d, 0xfe, 0x6c,
- 0x39, 0x64, 0x6e, 0xb1, 0x7f, 0xb8, 0xdb, 0xc7, 0x20, 0x8d, 0x62, 0xb0,
- 0xfa, 0x5c, 0xca, 0xfb, 0xdc, 0x00, 0x96, 0x2f, 0x31, 0xfc, 0xb1, 0x78,
- 0x83, 0xf2, 0xc5, 0xf8, 0x43, 0x72, 0x06, 0xd3, 0x76, 0xe3, 0xb7, 0xfb,
- 0x35, 0x26, 0x3f, 0xf8, 0xb1, 0x52, 0x8d, 0x18, 0x2f, 0x91, 0xf5, 0xfd,
- 0xf6, 0xf1, 0x49, 0xd6, 0x2f, 0xa7, 0x79, 0x4a, 0xc5, 0xe7, 0x86, 0x2c,
- 0x54, 0x47, 0xd8, 0x72, 0xd2, 0x23, 0xa0, 0xa2, 0xff, 0x14, 0xc2, 0x42,
- 0x04, 0x43, 0x2c, 0xc8, 0xe7, 0x7a, 0x8c, 0x05, 0x8c, 0x22, 0x48, 0xfc,
- 0x73, 0xa5, 0x09, 0x7f, 0x43, 0xc4, 0x50, 0x9a, 0xbf, 0xda, 0x9e, 0x1a,
- 0x07, 0x89, 0x62, 0xff, 0xf9, 0xce, 0x3f, 0xcf, 0xe4, 0xe2, 0xee, 0x1c,
- 0x58, 0xbf, 0xfd, 0x9e, 0xfb, 0x67, 0x7e, 0xcd, 0xf3, 0xc5, 0x8b, 0x7f,
- 0xe8, 0x9e, 0x25, 0x2b, 0xe7, 0xe7, 0xa3, 0x58, 0xbf, 0x33, 0x83, 0x6f,
- 0x96, 0x2f, 0xfe, 0x72, 0xfc, 0xb0, 0xdb, 0x99, 0x05, 0x8b, 0x80, 0x1a,
- 0xc5, 0xfc, 0x0e, 0x7e, 0x4b, 0xcb, 0x15, 0x27, 0x8e, 0xe3, 0x37, 0xf6,
- 0x6f, 0xfb, 0x02, 0x25, 0x8a, 0x95, 0x44, 0x99, 0x0d, 0x43, 0x4a, 0x3e,
- 0x48, 0xe5, 0x45, 0x08, 0x9e, 0x10, 0x5c, 0x52, 0xb1, 0x7d, 0xf9, 0xe4,
- 0xac, 0x5e, 0x0c, 0x78, 0xb1, 0x78, 0x2f, 0xcd, 0x8d, 0x62, 0xa3, 0x3f,
- 0xd1, 0x8b, 0x39, 0x17, 0x07, 0xaf, 0x71, 0xb8, 0xb1, 0x7d, 0xb4, 0xfb,
- 0x7a, 0x58, 0xbf, 0xa3, 0x8a, 0x1b, 0x1e, 0xa3, 0x58, 0xbd, 0x9d, 0x0d,
- 0x62, 0xfb, 0xd8, 0x40, 0x58, 0xbf, 0x9c, 0xc9, 0xf6, 0x46, 0xb1, 0x7f,
- 0x66, 0xb5, 0x32, 0x35, 0x8a, 0x0a, 0x23, 0x53, 0x0e, 0x18, 0x78, 0x88,
- 0xb6, 0x4b, 0xef, 0xfe, 0x8f, 0xf8, 0x31, 0xb7, 0x79, 0xdf, 0x96, 0x2f,
- 0xa3, 0x0c, 0x51, 0xac, 0x5f, 0x45, 0x09, 0x8d, 0x62, 0xa4, 0xf3, 0x30,
- 0x9e, 0xff, 0x14, 0x65, 0x82, 0x9e, 0x2c, 0x5f, 0xcd, 0xe0, 0x06, 0x50,
- 0x58, 0xbe, 0x2c, 0xfe, 0x2c, 0x5f, 0x19, 0x17, 0x25, 0x62, 0xf4, 0x9f,
- 0x16, 0x2e, 0x04, 0xac, 0x53, 0x1b, 0x30, 0x0e, 0x5f, 0xa4, 0xdc, 0xf7,
- 0x16, 0x2f, 0xff, 0xec, 0x26, 0x1f, 0x33, 0x9c, 0xcf, 0xb7, 0x05, 0x1a,
- 0xc5, 0xfc, 0x3d, 0x3f, 0xbe, 0x25, 0x8b, 0x9f, 0xd0, 0x44, 0x57, 0x16,
- 0xef, 0xe6, 0xf8, 0x8e, 0x76, 0x58, 0xbf, 0xf8, 0x50, 0xce, 0x6d, 0xf3,
- 0x6c, 0xe4, 0x6b, 0x15, 0x03, 0xf9, 0x22, 0xeb, 0xec, 0x86, 0x12, 0xc5,
- 0x31, 0xe1, 0x00, 0x86, 0xa5, 0x5b, 0x64, 0x70, 0x94, 0xc2, 0x03, 0x4c,
- 0xfa, 0x2f, 0xec, 0x87, 0x4b, 0x1f, 0x20, 0x28, 0x59, 0xfa, 0x1d, 0x36,
- 0x08, 0x14, 0x76, 0x73, 0x7b, 0x11, 0x28, 0x54, 0xa7, 0x63, 0x23, 0xd8,
- 0x69, 0x21, 0x6c, 0xa4, 0x2c, 0x40, 0x99, 0x56, 0x71, 0xb5, 0xc1, 0xf0,
- 0x72, 0x89, 0xb2, 0x77, 0xc4, 0xd8, 0xc3, 0x3a, 0x95, 0x55, 0xdc, 0x3a,
- 0x9a, 0x39, 0x68, 0xa5, 0x21, 0x6a, 0x3c, 0x73, 0xc6, 0x65, 0xf9, 0x44,
- 0xef, 0x1c, 0x98, 0x23, 0xc5, 0x0b, 0xa5, 0x14, 0xbe, 0x2e, 0x52, 0x08,
- 0x3d, 0x2b, 0xd0, 0x50, 0xea, 0xde, 0x78, 0x60, 0xee, 0xcc, 0x3f, 0x43,
- 0x97, 0x75, 0x7f, 0xfc, 0x15, 0x0a, 0x05, 0x58, 0x3f, 0xe7, 0x70, 0xcd,
- 0xde, 0x2c, 0x5f, 0xe8, 0x9b, 0xd9, 0xaf, 0x4a, 0xc5, 0xfb, 0x0c, 0xcf,
- 0xba, 0xc5, 0xff, 0xef, 0x37, 0xc5, 0xf7, 0x6e, 0xf9, 0x26, 0xac, 0x5f,
- 0xfe, 0x6e, 0xe1, 0xc6, 0xf7, 0xe7, 0x5e, 0x95, 0x8b, 0xf8, 0x1c, 0x9d,
- 0xcd, 0x4a, 0xc5, 0x62, 0x32, 0x34, 0x98, 0xe9, 0x77, 0xfa, 0x74, 0xf1,
- 0x3f, 0x20, 0xb1, 0x79, 0xdf, 0xa5, 0x45, 0x5c, 0x5f, 0xce, 0x1f, 0xfe,
- 0xe7, 0x58, 0xae, 0x8f, 0x67, 0xe5, 0x57, 0xf3, 0x6b, 0xee, 0x19, 0xd6,
- 0x2f, 0x9b, 0xd0, 0x95, 0x8a, 0x1a, 0x60, 0x3a, 0x84, 0x6f, 0xc8, 0xf7,
- 0x97, 0xdf, 0x16, 0xef, 0x1d, 0x62, 0xf8, 0xb2, 0x29, 0x58, 0xb6, 0xe2,
- 0xc5, 0xff, 0xe9, 0x8f, 0xcc, 0x3c, 0x28, 0x37, 0xc4, 0xb1, 0x7d, 0xdc,
- 0x51, 0x12, 0xc5, 0x62, 0x29, 0xce, 0x45, 0xf1, 0x57, 0x4a, 0xba, 0x4e,
- 0xb1, 0x77, 0x06, 0xb1, 0x5a, 0x35, 0xee, 0x2f, 0x7f, 0xa7, 0x5e, 0x92,
- 0x90, 0x2c, 0x5f, 0xe0, 0x99, 0xae, 0x9d, 0xfa, 0x54, 0x47, 0x85, 0xfb,
- 0xed, 0xaf, 0xba, 0xc5, 0xe2, 0xf3, 0xac, 0x5d, 0x83, 0xc3, 0xc4, 0xe1,
- 0x45, 0x41, 0x16, 0x87, 0x84, 0x45, 0xfe, 0x84, 0xea, 0x39, 0xd4, 0x6b,
- 0x17, 0xff, 0xf1, 0x66, 0xef, 0x36, 0xf0, 0x1b, 0xf6, 0xbf, 0x21, 0xa7,
- 0x58, 0xbf, 0x9f, 0xf2, 0x52, 0x05, 0x8a, 0xde, 0x89, 0x1d, 0x96, 0x5b,
- 0xff, 0xa3, 0x9d, 0x75, 0x9c, 0xe6, 0x0f, 0x16, 0x2a, 0x53, 0x35, 0xc8,
- 0x63, 0xb9, 0x45, 0xfa, 0x47, 0xcd, 0xd8, 0x96, 0x2f, 0xf3, 0x08, 0x2f,
- 0x90, 0x8e, 0x25, 0x8a, 0x8c, 0xf9, 0xfc, 0x5b, 0x7f, 0xff, 0xda, 0x2c,
- 0x8f, 0x69, 0x66, 0xf2, 0xcd, 0xde, 0x6d, 0xe0, 0x37, 0xac, 0x5f, 0xf6,
- 0x7b, 0x81, 0xf3, 0x6f, 0x50, 0x58, 0xbf, 0x8b, 0x3d, 0xcc, 0x31, 0x62,
- 0xa5, 0x30, 0x2c, 0x23, 0x3b, 0x93, 0x9f, 0xdf, 0xee, 0x9b, 0x9f, 0x6f,
- 0x32, 0xc5, 0xfb, 0x23, 0x72, 0xed, 0x62, 0xbb, 0x3d, 0xd2, 0x34, 0xbf,
- 0xc3, 0x7e, 0x02, 0x7b, 0x25, 0x8b, 0xef, 0x61, 0x01, 0x62, 0xbb, 0x3d,
- 0x6f, 0x1a, 0x5f, 0xed, 0xd7, 0x1c, 0xe0, 0xd9, 0x62, 0xc1, 0x02, 0x8c,
- 0x99, 0x79, 0x62, 0x8c, 0xd0, 0x70, 0xf0, 0xc8, 0xcb, 0xd9, 0x16, 0x28,
- 0x66, 0x69, 0xab, 0xe4, 0x0f, 0x0e, 0x62, 0x8d, 0x77, 0x91, 0xce, 0x7a,
- 0x13, 0x01, 0xbc, 0x6e, 0x91, 0xde, 0xfb, 0x9d, 0x62, 0xfb, 0xa7, 0x7e,
- 0x95, 0x16, 0x09, 0x61, 0xac, 0x56, 0x8f, 0x0f, 0xe6, 0x37, 0x8d, 0x98,
- 0xd6, 0x2f, 0xe6, 0xd1, 0x66, 0xfc, 0x58, 0xbf, 0xff, 0x09, 0xe3, 0x3e,
- 0x6c, 0x8b, 0x59, 0xa8, 0x07, 0x05, 0x8a, 0xfa, 0x22, 0x88, 0xba, 0xe3,
- 0x7c, 0xb1, 0x7e, 0xc2, 0xcf, 0x71, 0x62, 0xfd, 0x9c, 0x13, 0xf6, 0xb1,
- 0x7f, 0x39, 0xc3, 0xd3, 0xf6, 0xb1, 0x7f, 0xff, 0xfe, 0x68, 0x74, 0x42,
- 0x78, 0xcf, 0x9b, 0x22, 0xd4, 0x50, 0x9e, 0xf3, 0x50, 0x0e, 0x0b, 0x15,
- 0xa4, 0x5e, 0x78, 0xc2, 0xc1, 0x25, 0x54, 0xae, 0x30, 0x1a, 0x45, 0xd4,
- 0x2a, 0x74, 0x44, 0xe3, 0x24, 0x4e, 0x1c, 0x39, 0x6f, 0xf0, 0x4c, 0xd7,
- 0x4e, 0xfd, 0x2a, 0x2c, 0xa2, 0xff, 0xd9, 0xe8, 0x60, 0x36, 0x73, 0xe2,
- 0x58, 0xbc, 0x6b, 0x92, 0xc5, 0xff, 0xec, 0x71, 0xff, 0x35, 0xa9, 0xde,
- 0x6c, 0xac, 0x5f, 0x74, 0xef, 0xd2, 0xa2, 0xd3, 0x28, 0xd4, 0x4d, 0x6e,
- 0x0e, 0xe9, 0x32, 0xf4, 0x8b, 0xb5, 0x8b, 0xec, 0x8d, 0x8c, 0x58, 0xaf,
- 0x9e, 0x11, 0x0f, 0x5f, 0xd9, 0x9d, 0x7b, 0x3a, 0x58, 0xbf, 0xc3, 0xfb,
- 0xc5, 0xf6, 0x3a, 0xc5, 0x2c, 0x39, 0xb5, 0xbf, 0xd2, 0x7c, 0x19, 0x4f,
- 0x6b, 0x17, 0xe1, 0xb0, 0x24, 0x96, 0x2f, 0xcf, 0xc9, 0xce, 0x2c, 0x5f,
- 0x66, 0x9f, 0x8b, 0x15, 0xf3, 0xc9, 0x11, 0x3d, 0x82, 0x0d, 0x55, 0xbe,
- 0x43, 0x73, 0xa7, 0x68, 0x88, 0x4e, 0xc9, 0xf1, 0xb7, 0x33, 0xe3, 0x85,
- 0xfb, 0x62, 0x0a, 0x6c, 0x2d, 0x85, 0xb0, 0x96, 0x2f, 0xb6, 0x10, 0x50,
- 0x29, 0xb0, 0x2c, 0x56, 0xc4, 0x7f, 0x9b, 0x0d, 0x16, 0xfd, 0xb0, 0x79,
- 0xff, 0x8b, 0x17, 0xfd, 0xb1, 0xfd, 0x8c, 0x1b, 0xbf, 0x4b, 0x17, 0xe0,
- 0xa8, 0xf4, 0xfd, 0x2c, 0x5f, 0xd2, 0x7c, 0xfb, 0x41, 0x62, 0xfd, 0xb0,
- 0xc2, 0xbc, 0xc9, 0x58, 0xbf, 0xdb, 0x62, 0x6f, 0x90, 0xbc, 0xb1, 0x7f,
- 0x05, 0xb7, 0xfb, 0x6e, 0xca, 0xc5, 0x6c, 0x23, 0xed, 0x0b, 0x66, 0xf7,
- 0xf8, 0x33, 0xe7, 0xb8, 0xdc, 0x58, 0xb3, 0x2c, 0x56, 0xc6, 0x78, 0xdb,
- 0x26, 0xb7, 0xf0, 0x55, 0xba, 0x9e, 0xf8, 0xb1, 0x7f, 0xa6, 0x3d, 0x38,
- 0xe3, 0x75, 0x8b, 0xff, 0xf7, 0xdc, 0xbd, 0x0c, 0xd6, 0x49, 0x16, 0x79,
- 0x62, 0xa0, 0x88, 0x76, 0x35, 0xbf, 0xfe, 0x78, 0xdf, 0x7f, 0x36, 0xbe,
- 0xfe, 0xbe, 0xda, 0x58, 0xbf, 0x6f, 0x71, 0xe1, 0xd6, 0x2f, 0x9c, 0x1b,
- 0x38, 0xb1, 0x7f, 0xdc, 0x9f, 0xc8, 0xfe, 0xe6, 0xac, 0x56, 0xd3, 0xdf,
- 0xf1, 0x2d, 0xd9, 0xbd, 0x62, 0xdc, 0x93, 0x7a, 0x44, 0x97, 0xf6, 0x7a,
- 0x4a, 0x62, 0x58, 0xbf, 0x8e, 0xdb, 0xb2, 0x4c, 0xb1, 0x7b, 0x74, 0x72,
- 0xb1, 0x4c, 0x79, 0xe2, 0x2f, 0xbf, 0x49, 0x75, 0xf9, 0x58, 0xbf, 0xfb,
- 0x3d, 0xf6, 0x3e, 0x7b, 0x81, 0xf1, 0x62, 0xff, 0xd8, 0xe0, 0x98, 0x6a,
- 0x70, 0x96, 0x2b, 0xa4, 0x41, 0x32, 0x35, 0xf3, 0x6f, 0xfe, 0xf5, 0x8b,
- 0xee, 0x49, 0x44, 0xb1, 0x7d, 0x3b, 0xb1, 0x62, 0xc5, 0x39, 0xe4, 0x91,
- 0x1d, 0xff, 0xe7, 0x88, 0x39, 0x8f, 0x6c, 0xff, 0x35, 0x8b, 0x17, 0xfb,
- 0x75, 0x81, 0xb5, 0xfe, 0x25, 0x8a, 0x82, 0xbe, 0x61, 0x91, 0x62, 0xc3,
- 0x43, 0x1a, 0x22, 0x5f, 0xbe, 0x00, 0x84, 0xa1, 0x55, 0xc2, 0x3f, 0x38,
- 0x6f, 0x20, 0xdd, 0x4e, 0xbf, 0xfd, 0x9b, 0x67, 0x7b, 0xeb, 0x93, 0xa6,
- 0xe2, 0xc5, 0xdd, 0xc4, 0xb1, 0x7f, 0xc5, 0x83, 0x29, 0xea, 0x74, 0xb1,
- 0x51, 0x22, 0x7c, 0xe9, 0xae, 0x35, 0x7f, 0x8e, 0x19, 0xc0, 0x76, 0x02,
- 0xc5, 0xfb, 0x6e, 0xb4, 0x2f, 0xac, 0x5f, 0x98, 0xd9, 0x2e, 0x96, 0x2b,
- 0x87, 0xab, 0xe2, 0xcb, 0xfd, 0xee, 0x4c, 0x4e, 0xfa, 0x58, 0xa9, 0x47,
- 0x0e, 0x42, 0x2d, 0x88, 0xaf, 0x36, 0x46, 0xb1, 0x7f, 0xfb, 0xaf, 0xb7,
- 0xdb, 0x53, 0x11, 0x99, 0xf5, 0x8a, 0xf9, 0xf5, 0x10, 0xed, 0xe0, 0x16,
- 0x2c, 0x5c, 0x58, 0xb1, 0x5b, 0x4d, 0x90, 0x07, 0x2f, 0x1e, 0x74, 0xb1,
- 0x7f, 0xcd, 0xb7, 0xef, 0xa9, 0xdf, 0x2b, 0x15, 0x27, 0xb3, 0xc1, 0xdb,
- 0xfe, 0x3b, 0xc3, 0x64, 0x5f, 0x6d, 0x2c, 0x54, 0x68, 0xda, 0xd3, 0xe1,
- 0xc8, 0x6f, 0xcf, 0xcf, 0x48, 0xd6, 0x2a, 0x4f, 0x64, 0x46, 0x37, 0xf9,
- 0xf5, 0x07, 0xf3, 0xf4, 0xb1, 0x7f, 0xfb, 0x30, 0xb0, 0x05, 0x9e, 0xfe,
- 0x41, 0x62, 0xa5, 0x51, 0x17, 0xe3, 0x86, 0x11, 0x0e, 0xe9, 0xa5, 0xff,
- 0xc7, 0x27, 0x34, 0xb0, 0x11, 0xe1, 0x8b, 0x17, 0xff, 0x8b, 0x0d, 0xfb,
- 0xc3, 0xe6, 0x38, 0x67, 0x58, 0xb7, 0xe5, 0x12, 0x78, 0x8d, 0x7f, 0x49,
- 0x78, 0x65, 0x2b, 0x17, 0xe9, 0x87, 0x0f, 0x05, 0x8b, 0xe9, 0x0e, 0x7e,
- 0xb1, 0x73, 0x46, 0xb1, 0x79, 0xdf, 0xa5, 0x45, 0xb8, 0x5d, 0x17, 0x16,
- 0x2f, 0xde, 0xe7, 0x1a, 0x25, 0x8a, 0x8d, 0x10, 0xbd, 0x0c, 0x31, 0x50,
- 0x63, 0x37, 0xfe, 0x6d, 0x7d, 0xf3, 0x51, 0xb4, 0x6b, 0x17, 0xd1, 0x48,
- 0xf1, 0x62, 0xfe, 0x01, 0xf3, 0x82, 0x25, 0x8b, 0xb6, 0x92, 0xc5, 0xfd,
- 0xc9, 0xd6, 0xb0, 0xc5, 0x8a, 0x81, 0xe4, 0x78, 0x66, 0x99, 0x13, 0x0e,
- 0xed, 0x7f, 0xec, 0xd6, 0x16, 0xdf, 0xe7, 0x66, 0x2c, 0x5f, 0x88, 0x0f,
- 0xdf, 0x16, 0x2a, 0x4f, 0xad, 0xd0, 0xaa, 0x0a, 0xc2, 0x86, 0x4e, 0x69,
- 0x67, 0x65, 0x3a, 0x85, 0x47, 0xcf, 0xdd, 0x00, 0xa1, 0x77, 0xc8, 0x46,
- 0x5f, 0xf9, 0xc6, 0x4f, 0xbf, 0xf3, 0x17, 0x16, 0x29, 0x62, 0xf4, 0xf4,
- 0x4b, 0x15, 0xe3, 0x53, 0xbc, 0x32, 0xfe, 0x20, 0x44, 0x52, 0x75, 0x8a,
- 0x35, 0x17, 0x67, 0x6a, 0x72, 0x3b, 0xc7, 0x26, 0x58, 0xb1, 0x2c, 0x5b,
- 0xa5, 0x8b, 0xfe, 0xf8, 0x9f, 0x99, 0x84, 0x6a, 0xc5, 0xff, 0xfa, 0x7a,
- 0xdb, 0x9f, 0x6d, 0x4f, 0xf0, 0x87, 0x2b, 0x17, 0xee, 0x3f, 0x6e, 0x35,
- 0x8b, 0x30, 0xd1, 0x70, 0x73, 0x9f, 0x2b, 0x5f, 0xe7, 0x08, 0x59, 0x1c,
- 0x9a, 0xb1, 0x52, 0x9b, 0x1e, 0x0e, 0x30, 0x8f, 0xe1, 0x96, 0x46, 0xb7,
- 0xfd, 0x2e, 0x5f, 0xcc, 0x2e, 0x96, 0x2f, 0xf8, 0x45, 0x19, 0x3e, 0x9e,
- 0x0b, 0x15, 0x03, 0xf0, 0xe1, 0xbd, 0xfe, 0x21, 0x1e, 0x79, 0xe6, 0x58,
- 0xbf, 0xcc, 0x52, 0x79, 0xef, 0x8b, 0x17, 0xe9, 0xd6, 0xb3, 0x75, 0x62,
- 0xa5, 0x12, 0x31, 0x19, 0x91, 0x9d, 0xfe, 0x10, 0xcb, 0x37, 0xbc, 0x16,
- 0x2f, 0xff, 0xdf, 0x8b, 0x69, 0xc5, 0xe6, 0x8f, 0x3c, 0x6e, 0x7d, 0x62,
- 0xfe, 0x29, 0x8a, 0x2c, 0x02, 0xc5, 0xff, 0xe9, 0x8f, 0xcc, 0x3c, 0x28,
- 0x37, 0xc4, 0xb1, 0x7f, 0xd0, 0x6d, 0xf9, 0xf7, 0x28, 0xd6, 0x2f, 0x4e,
- 0x69, 0x62, 0xff, 0x7e, 0x60, 0xdb, 0x38, 0x75, 0x8a, 0x19, 0xe9, 0x70,
- 0x72, 0xfd, 0xb7, 0xbe, 0x31, 0xab, 0x15, 0x19, 0xe7, 0xf6, 0x45, 0x5d,
- 0xa6, 0x00, 0xf0, 0xdc, 0xbf, 0xf6, 0x7d, 0xb4, 0x3f, 0xc9, 0x74, 0xb1,
- 0x7f, 0xe2, 0xcf, 0x72, 0x76, 0xfb, 0x3a, 0x58, 0xbe, 0xdb, 0xec, 0x02,
- 0xc5, 0x41, 0x14, 0xac, 0x7f, 0xf4, 0x1b, 0xfd, 0xdc, 0x24, 0xbd, 0x80,
- 0x58, 0xbe, 0xe0, 0x1b, 0xcb, 0x15, 0x05, 0x6b, 0xdd, 0x1a, 0xb2, 0xe7,
- 0xcb, 0xde, 0x34, 0xae, 0x43, 0x38, 0x45, 0xe1, 0x9a, 0x5f, 0x9f, 0x5e,
- 0xcf, 0xac, 0x5f, 0xf9, 0x81, 0x30, 0x1f, 0xe4, 0xba, 0x58, 0xa8, 0x1f,
- 0x3f, 0x8a, 0x2f, 0xef, 0x43, 0x35, 0x9c, 0x58, 0xa5, 0x8b, 0xc2, 0x7f,
- 0x2c, 0x5c, 0x29, 0x58, 0xa8, 0x1b, 0x4f, 0x0e, 0xd2, 0xc5, 0xf7, 0x7d,
- 0x36, 0x96, 0x2e, 0x38, 0x4c, 0x44, 0x97, 0x68, 0x07, 0x21, 0xf0, 0x65,
- 0xf6, 0x0c, 0x86, 0xb1, 0x52, 0x7d, 0xbb, 0xd2, 0xef, 0xf8, 0xbd, 0xf7,
- 0x80, 0x9c, 0x35, 0x8a, 0x94, 0xeb, 0x30, 0x89, 0xa3, 0x2d, 0x72, 0x3b,
- 0xef, 0x6d, 0xd8, 0x44, 0xb1, 0x79, 0xda, 0x35, 0x8a, 0xc3, 0xc8, 0x34,
- 0xae, 0xcc, 0xb1, 0x6d, 0x95, 0x8b, 0x10, 0x0d, 0x37, 0x84, 0x6f, 0x6d,
- 0xd8, 0x36, 0x05, 0x8b, 0xfb, 0x35, 0xd3, 0xbf, 0x4a, 0x8a, 0x1c, 0xba,
- 0x43, 0x58, 0xb4, 0x02, 0x1e, 0xa1, 0x1e, 0x5f, 0xa1, 0xb7, 0x79, 0xe5,
- 0x62, 0xe6, 0x82, 0xc5, 0x4a, 0x6b, 0x2c, 0x91, 0x11, 0x33, 0xbf, 0x11,
- 0x48, 0x8b, 0x6f, 0x68, 0xde, 0x96, 0x2e, 0xc3, 0xac, 0x5e, 0xf6, 0x6e,
- 0xac, 0x5a, 0x7a, 0x36, 0xfe, 0x17, 0xa8, 0x1f, 0xf0, 0x15, 0xef, 0xa7,
- 0x70, 0x52, 0xb1, 0x7a, 0x2c, 0x1a, 0xc5, 0xe8, 0xa7, 0xcb, 0x15, 0x26,
- 0xf0, 0x43, 0xd5, 0xa4, 0x51, 0x80, 0x8b, 0x8c, 0x37, 0x08, 0x35, 0x8b,
- 0xf7, 0x1f, 0xf9, 0xd2, 0xc5, 0x76, 0x78, 0x5c, 0x19, 0xbc, 0x39, 0x3a,
- 0xc5, 0xff, 0x64, 0x8f, 0xf3, 0xbb, 0x31, 0x2c, 0x5f, 0xe0, 0x37, 0xff,
- 0x80, 0x75, 0x8a, 0x39, 0xf7, 0x80, 0xf2, 0xff, 0xd9, 0xee, 0x7f, 0x35,
- 0xac, 0x31, 0x62, 0xff, 0xc5, 0xba, 0xe4, 0xe7, 0x1e, 0x0d, 0x62, 0xa5,
- 0x3c, 0x3c, 0x72, 0x62, 0x37, 0x84, 0x60, 0x64, 0x5b, 0xa8, 0x17, 0xfe,
- 0x71, 0xc8, 0xfe, 0xc4, 0xc7, 0x58, 0xbf, 0xf6, 0xf7, 0xd7, 0x1f, 0xfc,
- 0x98, 0xd6, 0x2f, 0xf7, 0x05, 0xd6, 0x78, 0xa5, 0x62, 0x8e, 0x8b, 0x3f,
- 0x9e, 0xf9, 0x0a, 0xff, 0xdd, 0xf3, 0x6e, 0xfc, 0x91, 0x8a, 0x35, 0x8b,
- 0xde, 0xce, 0x96, 0x2e, 0xce, 0x96, 0x2d, 0x9b, 0x4d, 0xb7, 0x87, 0xaf,
- 0xfb, 0xef, 0xae, 0xfd, 0x2d, 0x1a, 0xc5, 0xfe, 0x2e, 0xb6, 0xc5, 0xd7,
- 0xe2, 0x58, 0xa8, 0x1f, 0xb3, 0x9d, 0xd3, 0xa6, 0x76, 0x4f, 0x82, 0x84,
- 0xf5, 0xfe, 0x84, 0xea, 0x39, 0xd4, 0x6b, 0x17, 0xd2, 0xfa, 0x02, 0xc5,
- 0xf9, 0xbe, 0x42, 0xf2, 0xc5, 0xfe, 0xe9, 0xb9, 0x83, 0x7e, 0x96, 0x2f,
- 0xef, 0xe1, 0x37, 0xc4, 0xb1, 0x43, 0x45, 0x64, 0x44, 0x5f, 0x28, 0xf1,
- 0xad, 0xfa, 0x39, 0xfb, 0xf9, 0x62, 0xfc, 0xfc, 0xdf, 0x9c, 0x58, 0xbf,
- 0x3f, 0xb6, 0xcc, 0xac, 0x54, 0xa7, 0x39, 0x90, 0xe2, 0x73, 0xe0, 0x14,
- 0x88, 0xaa, 0xfd, 0xb7, 0xf8, 0x07, 0x58, 0xbf, 0xda, 0x9f, 0xb8, 0xe0,
- 0x75, 0x8b, 0xfe, 0x3b, 0x7b, 0x67, 0x09, 0xcd, 0x58, 0xbf, 0xa0, 0xfa,
- 0xce, 0xfc, 0xb1, 0x7f, 0x0d, 0xcf, 0xf6, 0x31, 0x62, 0xa4, 0xf7, 0xb0,
- 0xbe, 0xff, 0xb3, 0xdc, 0x0f, 0x9a, 0x7e, 0x2c, 0x5d, 0x1c, 0x6b, 0x17,
- 0xdb, 0x4d, 0xc1, 0xac, 0x50, 0xcf, 0x00, 0x03, 0x57, 0xe6, 0xf7, 0x1d,
- 0x96, 0x2f, 0xff, 0xd9, 0xf6, 0xe0, 0xa3, 0xeb, 0xed, 0xef, 0x64, 0x6b,
- 0x17, 0xfd, 0xa0, 0x69, 0xcb, 0xd8, 0x05, 0x8a, 0x8d, 0x53, 0x70, 0xca,
- 0xb0, 0xd3, 0x50, 0x9a, 0x39, 0x03, 0xbd, 0x80, 0x8b, 0x84, 0xe2, 0x59,
- 0xbc, 0x1e, 0xa0, 0xb1, 0x7f, 0x07, 0xe1, 0x4e, 0x46, 0xb1, 0x7f, 0x03,
- 0xee, 0xdf, 0x12, 0xc5, 0xee, 0x14, 0x16, 0x2a, 0x08, 0x9a, 0x88, 0x7f,
- 0x46, 0x1e, 0x2e, 0xbf, 0xfb, 0xa2, 0x9f, 0x16, 0x6f, 0xcd, 0x41, 0x62,
- 0xfc, 0xfc, 0xe4, 0x7c, 0x58, 0xbf, 0x9c, 0x80, 0x18, 0x38, 0xb1, 0x7b,
- 0x87, 0x75, 0x8b, 0xfc, 0x46, 0x87, 0xff, 0x8b, 0x8b, 0x14, 0x6a, 0x20,
- 0xe2, 0x2f, 0x10, 0xed, 0xff, 0xc2, 0xe7, 0xde, 0x12, 0x43, 0xcf, 0xac,
- 0x5f, 0xf0, 0x72, 0x08, 0xa1, 0x3a, 0x8d, 0x62, 0xfe, 0x27, 0xf0, 0x73,
- 0xd2, 0xc5, 0x1c, 0xfb, 0x08, 0xf6, 0xf8, 0x81, 0x18, 0x16, 0x2f, 0xff,
- 0xf4, 0x5c, 0x61, 0xed, 0x89, 0x8b, 0x7b, 0xc4, 0xfe, 0x14, 0xac, 0x56,
- 0x22, 0xb1, 0x88, 0x5c, 0x92, 0xff, 0x8f, 0xcd, 0xb8, 0x39, 0x2f, 0x2c,
- 0x5f, 0xa1, 0xb7, 0x9c, 0xc5, 0x8b, 0xfd, 0xcd, 0xbe, 0xda, 0x3c, 0x25,
- 0x8b, 0x01, 0x62, 0xbb, 0x3c, 0xad, 0x1c, 0x54, 0xa3, 0x4f, 0x0e, 0xd9,
- 0xd6, 0xfe, 0x17, 0x5f, 0x9d, 0x62, 0xc5, 0xf7, 0x7c, 0xf3, 0x2c, 0x56,
- 0x1e, 0x9b, 0x97, 0xd4, 0xae, 0x2f, 0xe1, 0xf1, 0xa8, 0xcd, 0x0a, 0xdd,
- 0x19, 0x7e, 0x35, 0xc2, 0x8c, 0x03, 0x90, 0x80, 0xbf, 0x38, 0x8d, 0x90,
- 0xd6, 0x2f, 0xdb, 0x1e, 0x6a, 0x78, 0xb1, 0x51, 0x1e, 0xb9, 0x15, 0x5f,
- 0xd9, 0xe6, 0x1e, 0x1d, 0x62, 0xf8, 0xa0, 0xc7, 0x58, 0xb6, 0xd8, 0x8f,
- 0x3d, 0xcb, 0x6f, 0xe6, 0x2d, 0xef, 0x10, 0x5b, 0x58, 0xbf, 0xa6, 0x2e,
- 0xe1, 0x9b, 0xd6, 0x2a, 0x23, 0xe8, 0xe1, 0xb5, 0x0d, 0x16, 0xaf, 0x09,
- 0x2b, 0xff, 0xf0, 0xff, 0x21, 0x84, 0xf1, 0x38, 0x39, 0xc9, 0x02, 0x45,
- 0xc3, 0xc5, 0x8b, 0xf4, 0x73, 0x1b, 0xf1, 0x62, 0xb1, 0x13, 0x4c, 0xb2,
- 0xe2, 0xf7, 0xf6, 0xeb, 0x80, 0xf3, 0xc5, 0x8b, 0xa4, 0x0b, 0x16, 0x12,
- 0xc0, 0x65, 0xbd, 0x7c, 0xfa, 0x80, 0x91, 0x7f, 0x84, 0x5e, 0xda, 0x40,
- 0x02, 0xc5, 0xff, 0xb9, 0xbd, 0xe2, 0x8d, 0xc9, 0xe2, 0x58, 0xbf, 0xf4,
- 0xee, 0xc4, 0xfb, 0xdf, 0xdb, 0xe5, 0x62, 0xff, 0xd8, 0x39, 0x84, 0xe8,
- 0xfe, 0xed, 0x62, 0xfe, 0x70, 0x44, 0x52, 0x35, 0x8b, 0xfe, 0x2c, 0x8c,
- 0x7f, 0xc2, 0xf2, 0xc5, 0xef, 0x37, 0x16, 0x2a, 0x53, 0xa5, 0x8c, 0x8a,
- 0x23, 0x6d, 0x21, 0x9d, 0x1b, 0xe8, 0x04, 0x5d, 0xc3, 0x9a, 0xd8, 0x9d,
- 0x8a, 0x98, 0x54, 0xb7, 0x60, 0x2d, 0xd8, 0xd0, 0x36, 0x19, 0x76, 0xc2,
- 0x2d, 0x0b, 0x70, 0x9f, 0x0b, 0x1d, 0x02, 0xd4, 0xaa, 0x67, 0x28, 0x63,
- 0x8d, 0x4e, 0x11, 0x88, 0x8e, 0x55, 0xf6, 0x4b, 0xe4, 0x36, 0x34, 0xae,
- 0xa3, 0x93, 0xee, 0x17, 0x8d, 0x0b, 0x38, 0xa5, 0xc6, 0xea, 0x54, 0x89,
- 0xe3, 0xe1, 0xfc, 0xb3, 0x97, 0x8c, 0x40, 0x11, 0xb5, 0x94, 0x7a, 0x1c,
- 0x95, 0x77, 0xe9, 0xd7, 0xd1, 0x43, 0x7b, 0x7c, 0x64, 0xdb, 0x30, 0xc1,
- 0x0e, 0x51, 0xe5, 0xfd, 0xee, 0xf8, 0xc4, 0x35, 0x8b, 0xff, 0xb5, 0x9d,
- 0xf5, 0xf6, 0xf7, 0x1f, 0xb5, 0x8b, 0xf4, 0xf3, 0x42, 0x02, 0xc5, 0xff,
- 0xfc, 0x7c, 0xf7, 0x03, 0xe1, 0x67, 0x84, 0x03, 0xbc, 0x16, 0x2f, 0xb0,
- 0x6f, 0x05, 0x8b, 0xc1, 0x94, 0x16, 0x29, 0x8f, 0x00, 0x04, 0x57, 0x74,
- 0x11, 0x93, 0x5e, 0x01, 0x79, 0x24, 0x70, 0xa7, 0xd0, 0x9d, 0xa0, 0x8b,
- 0x84, 0x82, 0x97, 0x8f, 0x7d, 0x3a, 0x81, 0xd6, 0x2f, 0xfa, 0x27, 0x92,
- 0x98, 0x85, 0x2b, 0x17, 0xdb, 0x39, 0xa9, 0x58, 0xbd, 0xc7, 0xdc, 0x58,
- 0xac, 0x3c, 0x5e, 0xc9, 0x6f, 0xd8, 0x31, 0x7b, 0x8b, 0x17, 0xf9, 0xfe,
- 0xe1, 0x9f, 0x38, 0xb1, 0x79, 0xf4, 0x6a, 0xc5, 0x82, 0x46, 0x99, 0xf6,
- 0x11, 0xb3, 0xf1, 0x11, 0x6f, 0x29, 0x30, 0xd2, 0xff, 0x04, 0xcd, 0x74,
- 0xef, 0xd2, 0xa2, 0xf3, 0x2a, 0x61, 0x03, 0x73, 0x08, 0x43, 0x0e, 0x38,
- 0x3c, 0xb6, 0x85, 0x3d, 0xd2, 0xfa, 0xf5, 0x2e, 0x60, 0xf0, 0x84, 0xfc,
- 0xaf, 0xb2, 0xb6, 0xce, 0x7c, 0x8d, 0xb7, 0x7b, 0x0d, 0xfe, 0x09, 0x9a,
- 0xe9, 0xdf, 0xa5, 0x45, 0x2c, 0x5c, 0x14, 0x0b, 0x16, 0x2e, 0xf4, 0x6b,
- 0x17, 0xe6, 0x09, 0xcc, 0x65, 0x8b, 0xff, 0xf7, 0xf0, 0xb0, 0xdf, 0xbc,
- 0x3e, 0x63, 0x86, 0x75, 0x8b, 0xee, 0x9d, 0xfa, 0x54, 0x58, 0x45, 0x41,
- 0x11, 0x3a, 0x58, 0xbe, 0xf4, 0x8f, 0x16, 0x2f, 0xff, 0xb0, 0x87, 0x3f,
- 0x9e, 0xfd, 0x84, 0xe7, 0x58, 0xbc, 0x42, 0xe9, 0x62, 0xa4, 0xfb, 0x1d,
- 0x3a, 0xff, 0xfe, 0xf6, 0x36, 0xb9, 0xe2, 0x60, 0x72, 0x7d, 0xc6, 0x58,
- 0xa5, 0x8a, 0x93, 0xe6, 0xe2, 0xd5, 0xfc, 0x2d, 0x34, 0x6e, 0x75, 0x8b,
- 0x04, 0x0b, 0x15, 0x39, 0xc9, 0x08, 0xc6, 0x72, 0x16, 0x4c, 0x46, 0x78,
- 0x47, 0x72, 0x10, 0xdb, 0x24, 0x37, 0xf8, 0x26, 0x6b, 0xa7, 0x7e, 0x95,
- 0x16, 0x59, 0x68, 0x2c, 0x5d, 0xa3, 0x56, 0x2f, 0x82, 0x1a, 0x16, 0x6c,
- 0x4b, 0x14, 0x91, 0x78, 0x20, 0x67, 0x58, 0xae, 0x8f, 0x7b, 0x86, 0x22,
- 0x0c, 0xa3, 0x51, 0x72, 0x42, 0x5c, 0x77, 0xba, 0x7e, 0xb1, 0x60, 0x2c,
- 0x5c, 0x6c, 0x6b, 0x16, 0xd4, 0x0d, 0x66, 0x09, 0x57, 0x47, 0xd2, 0xe8,
- 0x74, 0xb1, 0x7a, 0x05, 0x2b, 0x14, 0x03, 0x51, 0xe0, 0xcb, 0xa1, 0xf5,
- 0x8b, 0x1a, 0xb1, 0x4c, 0x79, 0x80, 0x21, 0xf0, 0xc5, 0xff, 0xf8, 0x6d,
- 0xef, 0xe0, 0xdb, 0x06, 0xf1, 0xb9, 0x2c, 0x5f, 0xf3, 0xf6, 0x59, 0xdf,
- 0xa4, 0xd5, 0x8b, 0xfd, 0x1f, 0x7c, 0x91, 0xf9, 0x96, 0x2f, 0xd3, 0x9b,
- 0xe7, 0x8b, 0x16, 0x97, 0x3d, 0xf3, 0x0d, 0xaf, 0x3e, 0xa0, 0xb1, 0x52,
- 0x99, 0x93, 0xaa, 0x14, 0x26, 0x84, 0x4f, 0x7c, 0xf0, 0x80, 0xd6, 0x2f,
- 0xfe, 0xd7, 0xdc, 0x65, 0x22, 0xeb, 0xee, 0xb1, 0x7e, 0xd4, 0xf9, 0xfe,
- 0xb1, 0x4c, 0x7d, 0xae, 0x8b, 0x78, 0xc3, 0x0c, 0x48, 0xbf, 0xe9, 0x87,
- 0x7e, 0xd4, 0xe7, 0x69, 0x01, 0x0d, 0x0d, 0xff, 0x09, 0xfb, 0xcf, 0x37,
- 0x66, 0x2c, 0x5d, 0x3c, 0x58, 0xa1, 0xa6, 0xe3, 0xf8, 0x48, 0x12, 0x0f,
- 0x13, 0x77, 0x9e, 0x5c, 0x16, 0x6c, 0x4b, 0x17, 0xf3, 0x3f, 0x01, 0xc1,
- 0x2c, 0x5f, 0xfc, 0xd0, 0x7e, 0x39, 0x0b, 0xac, 0xe2, 0x45, 0xff, 0xfd,
- 0xf6, 0xf7, 0xf3, 0x85, 0x87, 0x17, 0x3e, 0xf0, 0x58, 0xbf, 0xd3, 0x0f,
- 0x3f, 0xdc, 0x6b, 0x17, 0xcf, 0xe3, 0x78, 0xb1, 0x52, 0x8f, 0x6c, 0x44,
- 0xd2, 0xdb, 0x99, 0xdf, 0x37, 0x4f, 0xa5, 0x8b, 0x41, 0x62, 0xd0, 0x58,
- 0xb4, 0x16, 0x2f, 0x18, 0x61, 0x8b, 0x16, 0xe9, 0x20, 0x21, 0xa1, 0xa9,
- 0x3f, 0xc3, 0x44, 0x98, 0x48, 0x06, 0x74, 0xb1, 0x7e, 0x17, 0x3e, 0xf0,
- 0x58, 0xc2, 0x65, 0xff, 0xf7, 0x1b, 0xac, 0x2d, 0x49, 0x60, 0xf0, 0xd5,
- 0x8a, 0x3a, 0x21, 0x7c, 0x6d, 0x6e, 0xd6, 0x2c, 0x6a, 0xc5, 0x84, 0xb1,
- 0x44, 0x69, 0x78, 0x27, 0x58, 0x7f, 0x7c, 0x23, 0xf1, 0xc5, 0xdc, 0x35,
- 0x62, 0xd8, 0xb1, 0x70, 0x81, 0x26, 0xa8, 0x63, 0x37, 0x34, 0xac, 0x5f,
- 0xc5, 0x27, 0x29, 0xc5, 0x8b, 0xff, 0xa5, 0xf5, 0xef, 0xe0, 0xc5, 0xee,
- 0x2c, 0x5d, 0x09, 0x58, 0xbd, 0xc1, 0x9a, 0xb1, 0x51, 0xa3, 0xa0, 0x65,
- 0x91, 0x0b, 0x7c, 0xac, 0x48, 0xa1, 0x8b, 0xdf, 0xfe, 0xce, 0xfc, 0x1f,
- 0x9b, 0xdf, 0xc1, 0xb2, 0xc5, 0xff, 0xff, 0xe9, 0xf7, 0x1b, 0x9c, 0x9f,
- 0x7d, 0xa7, 0x40, 0x3b, 0xc2, 0x1e, 0x35, 0x62, 0x8d, 0x46, 0x2f, 0xd3,
- 0x2e, 0x6e, 0xd6, 0x2f, 0x02, 0x1f, 0x58, 0xba, 0x4e, 0xb1, 0x7f, 0xfe,
- 0x92, 0x14, 0x21, 0x3e, 0xfe, 0x1c, 0x39, 0x02, 0xc5, 0xff, 0xcd, 0x1c,
- 0xfd, 0xa7, 0xdc, 0x17, 0x16, 0x2f, 0xfe, 0x14, 0x33, 0x9a, 0x96, 0x83,
- 0xf1, 0x22, 0xcd, 0xa4, 0x44, 0x92, 0x2d, 0x41, 0x30, 0x6f, 0x43, 0x7e,
- 0xee, 0x82, 0x4b, 0x2f, 0xda, 0x38, 0x4c, 0xc2, 0x12, 0xc3, 0x8d, 0x83,
- 0x23, 0xb1, 0x35, 0x47, 0xa2, 0x2d, 0x46, 0x49, 0xf3, 0xa7, 0x84, 0xf9,
- 0x46, 0x8f, 0xc8, 0xd0, 0x3d, 0x18, 0xfe, 0xf2, 0x43, 0x06, 0x36, 0x47,
- 0x83, 0x8c, 0x76, 0xff, 0xf0, 0x43, 0xbc, 0x02, 0x66, 0xba, 0x77, 0xe9,
- 0x51, 0x46, 0x17, 0xcd, 0xe7, 0xd9, 0x58, 0xbf, 0x9f, 0x40, 0x3c, 0x81,
- 0x62, 0xfa, 0x75, 0x20, 0x58, 0xbf, 0xa4, 0x72, 0x79, 0x0d, 0x62, 0xa2,
- 0x45, 0x1f, 0xc9, 0x77, 0x97, 0x06, 0x45, 0x7f, 0x13, 0xfb, 0xed, 0x12,
- 0xc5, 0xf6, 0x61, 0x32, 0xc5, 0xfb, 0xf3, 0x1e, 0x0d, 0x62, 0xff, 0xfb,
- 0x4c, 0x6e, 0x78, 0x5f, 0x63, 0xe7, 0xdd, 0x62, 0xfc, 0x4e, 0x09, 0x0d,
- 0x62, 0xff, 0x67, 0xb8, 0x1c, 0x73, 0x1a, 0xc5, 0xfe, 0xcc, 0x88, 0xc7,
- 0xef, 0x8b, 0x17, 0xf7, 0x33, 0xf9, 0x0e, 0x2c, 0x5b, 0x00, 0x7c, 0x9e,
- 0x36, 0xbf, 0xf3, 0x77, 0x0e, 0x16, 0x7b, 0xe2, 0x58, 0xbf, 0xe6, 0xd7,
- 0xf3, 0x0a, 0x1c, 0x58, 0xa8, 0x1f, 0xc7, 0x48, 0x17, 0xcf, 0xbf, 0x09,
- 0x62, 0xff, 0xff, 0xb0, 0xff, 0x69, 0xf1, 0x67, 0xbf, 0x85, 0x86, 0x38,
- 0x16, 0x2b, 0xb4, 0x55, 0x68, 0x8f, 0xe4, 0x77, 0x6e, 0x6e, 0xac, 0x5f,
- 0xf9, 0xe1, 0xd7, 0xd8, 0xf3, 0xa3, 0x56, 0x2f, 0xe8, 0xc3, 0xd9, 0x72,
- 0x02, 0xc5, 0xfd, 0xb7, 0x34, 0xfe, 0xe2, 0xc5, 0xff, 0x9c, 0x81, 0x9e,
- 0x92, 0x60, 0x2c, 0x54, 0xa2, 0x7c, 0xe6, 0x7b, 0x26, 0x16, 0x09, 0x2b,
- 0x8e, 0xb8, 0x82, 0x69, 0x74, 0x44, 0x07, 0x29, 0xfa, 0x80, 0x0a, 0x0a,
- 0x13, 0x7e, 0x8d, 0x24, 0x46, 0x26, 0x0f, 0x07, 0x0e, 0x0a, 0x83, 0x6f,
- 0x4f, 0xa9, 0x56, 0xe7, 0x84, 0x7b, 0xd3, 0x3c, 0xf9, 0x19, 0xc7, 0xa7,
- 0x5d, 0x6f, 0xfe, 0x08, 0xf0, 0x09, 0x9a, 0xe9, 0xdf, 0xa5, 0x44, 0x72,
- 0x5f, 0xfe, 0x08, 0x77, 0x80, 0x4c, 0xd7, 0x4e, 0xfd, 0x2a, 0x27, 0x22,
- 0xff, 0x04, 0xcd, 0x74, 0xef, 0xd2, 0xa2, 0xcc, 0x2e, 0xf0, 0x16, 0x2f,
- 0xd9, 0xf2, 0xcd, 0x2c, 0x5e, 0x8e, 0x74, 0xb1, 0x7e, 0x87, 0x1c, 0xe1,
- 0x3e, 0x7b, 0xa4, 0x31, 0xc2, 0x7b, 0xe0, 0xb5, 0xd8, 0xb6, 0x20, 0xb5,
- 0x58, 0xbf, 0xc3, 0xc3, 0xcf, 0x72, 0x75, 0x8a, 0xd8, 0x8f, 0xc0, 0x2d,
- 0x4f, 0x2d, 0xbd, 0x62, 0xff, 0x6a, 0x7d, 0xf7, 0xee, 0x0b, 0x17, 0xff,
- 0xff, 0xd3, 0x17, 0xe7, 0xd2, 0x1b, 0x6a, 0x29, 0xfe, 0x6f, 0xcf, 0xe0,
- 0xf7, 0xe2, 0xc5, 0x01, 0x16, 0xe4, 0x6b, 0x7f, 0xd9, 0xc7, 0xf0, 0x03,
- 0x28, 0x2c, 0x58, 0x0b, 0x17, 0xf7, 0x35, 0xac, 0xef, 0x8b, 0x15, 0xb1,
- 0x1e, 0x16, 0x09, 0x5e, 0xd6, 0x1d, 0x62, 0xf9, 0x8b, 0x38, 0xb1, 0x6c,
- 0xf1, 0xbe, 0xdd, 0x1d, 0xbf, 0xff, 0xf7, 0xe4, 0x85, 0xce, 0x48, 0x7e,
- 0x62, 0x14, 0x33, 0x9e, 0x65, 0x8b, 0xa3, 0xc5, 0x8b, 0xf1, 0x66, 0xfc,
- 0x25, 0x8b, 0xef, 0x79, 0xb4, 0xb1, 0x77, 0x00, 0xb1, 0x50, 0x47, 0x39,
- 0xad, 0x8c, 0x31, 0xa2, 0x8f, 0x11, 0xdb, 0xcb, 0x16, 0xdd, 0x58, 0xad,
- 0x93, 0x4e, 0x18, 0x95, 0xe7, 0x2e, 0x96, 0x2f, 0x72, 0x78, 0xb1, 0x76,
- 0xcf, 0x16, 0x2f, 0xce, 0x64, 0x78, 0x62, 0xc5, 0x46, 0x78, 0xc4, 0x37,
- 0x76, 0xc7, 0xf5, 0x8b, 0x32, 0xc5, 0xfe, 0x9e, 0x4f, 0xa3, 0xc3, 0x16,
- 0x2c, 0xc7, 0x3c, 0x62, 0x11, 0xbb, 0xa8, 0x2c, 0x5f, 0xbd, 0xc2, 0x98,
- 0x2c, 0x5f, 0x19, 0xe9, 0x35, 0x62, 0xa4, 0xf9, 0xb0, 0x65, 0x8a, 0x2f,
- 0xb0, 0x6f, 0x05, 0x8b, 0xf0, 0x33, 0x81, 0xfd, 0x62, 0xef, 0x46, 0xb1,
- 0x76, 0xf9, 0x58, 0xbf, 0xe1, 0xfe, 0x79, 0xcc, 0xd4, 0xac, 0x5d, 0xbe,
- 0x56, 0x2e, 0xdf, 0x2b, 0x15, 0x04, 0x74, 0xf6, 0x44, 0xc5, 0x47, 0x19,
- 0x21, 0x9e, 0x1c, 0xec, 0x8c, 0xde, 0x1c, 0x89, 0x62, 0xe0, 0x3a, 0xc5,
- 0xd8, 0x4b, 0x17, 0x00, 0x4b, 0x15, 0x26, 0xbb, 0x42, 0xd7, 0xcf, 0x0f,
- 0xe2, 0xc5, 0xef, 0x64, 0xac, 0x50, 0xcd, 0xf7, 0x64, 0x57, 0x75, 0x2b,
- 0x14, 0x34, 0x4c, 0x62, 0xf7, 0x44, 0x56, 0x0d, 0x62, 0xff, 0xf7, 0x53,
- 0xce, 0x61, 0xfb, 0xf0, 0x8b, 0xcb, 0x17, 0xbd, 0x87, 0x58, 0xbf, 0xd2,
- 0x0c, 0x29, 0xef, 0x8b, 0x15, 0xb5, 0x16, 0x18, 0x26, 0xc9, 0xbc, 0x1d,
- 0xbf, 0x9c, 0xbd, 0xb2, 0xe6, 0xac, 0x5f, 0xba, 0xfb, 0xb0, 0x5d, 0x62,
- 0xfc, 0x2e, 0x4f, 0x25, 0x62, 0xb4, 0x7a, 0xae, 0x5b, 0x7f, 0x10, 0x3f,
- 0x80, 0x75, 0x8b, 0xe2, 0x9d, 0xe2, 0x58, 0xa6, 0x3d, 0x17, 0x2d, 0xbb,
- 0xb3, 0xac, 0x5f, 0xc3, 0xda, 0x14, 0x2c, 0xdd, 0x58, 0xa5, 0x8b, 0xfe,
- 0x20, 0x67, 0xa4, 0x98, 0x0b, 0x15, 0x87, 0x86, 0xe1, 0x95, 0x28, 0x9a,
- 0xd9, 0x7a, 0xbc, 0x42, 0x89, 0x62, 0xc1, 0x36, 0x26, 0x56, 0x90, 0x54,
- 0xba, 0x61, 0x97, 0x19, 0x14, 0x1f, 0x06, 0xc9, 0x91, 0x88, 0x1a, 0xe3,
- 0xd1, 0x2f, 0x63, 0xb1, 0x31, 0xe8, 0x88, 0xec, 0x7f, 0x84, 0x63, 0xc6,
- 0x2a, 0x06, 0x60, 0xb8, 0xe9, 0x43, 0x77, 0x90, 0xe0, 0xf1, 0xe8, 0xa1,
- 0x0d, 0xbd, 0xcb, 0x64, 0x80, 0x38, 0x59, 0xee, 0x92, 0xdf, 0xb5, 0xd3,
- 0xbf, 0x4a, 0x8b, 0x74, 0xb7, 0x16, 0x2b, 0x0f, 0x24, 0x06, 0xf7, 0xbf,
- 0x3a, 0x58, 0xbf, 0x44, 0x5d, 0xe7, 0x4b, 0x17, 0xfe, 0x10, 0xc9, 0xcd,
- 0xc1, 0xbc, 0x16, 0x2c, 0x10, 0x68, 0x87, 0xc1, 0xde, 0x15, 0xd0, 0x44,
- 0x6f, 0xfe, 0x15, 0x17, 0xe6, 0x07, 0x33, 0x75, 0x62, 0xfe, 0x27, 0x09,
- 0xa8, 0xfe, 0xb1, 0x79, 0xbb, 0x02, 0xc5, 0xfb, 0xb8, 0x7d, 0x80, 0xb1,
- 0x7f, 0xf6, 0x9f, 0xa0, 0x0b, 0x9e, 0x9e, 0xcc, 0x58, 0xb8, 0x8d, 0x58,
- 0xb3, 0xac, 0x5f, 0x74, 0xef, 0xd2, 0xa2, 0x90, 0x2b, 0x0f, 0x6a, 0x21,
- 0x8d, 0x08, 0xdf, 0xe8, 0x79, 0x8c, 0xe0, 0x19, 0x62, 0xf6, 0x67, 0x4b,
- 0x17, 0xfe, 0xcf, 0xb6, 0xff, 0xe6, 0x17, 0x4b, 0x17, 0xf6, 0x7f, 0x3e,
- 0xc6, 0xac, 0x5f, 0xbd, 0x3b, 0xdb, 0x7a, 0xc5, 0xe7, 0x80, 0x49, 0x4f,
- 0xa0, 0x65, 0x59, 0x0a, 0x3e, 0xcb, 0xe2, 0x35, 0xe0, 0xef, 0x90, 0x37,
- 0x97, 0x5f, 0x67, 0x3e, 0x25, 0x8b, 0xfa, 0x4b, 0x9c, 0x63, 0xac, 0x56,
+ 0xbe, 0xea, 0xc5, 0xfe, 0xe4, 0x48, 0xd3, 0x73, 0x75, 0x62, 0xff, 0xc3,
+ 0x21, 0x7b, 0x90, 0x51, 0xc5, 0x8a, 0x83, 0xf7, 0x63, 0x9b, 0x05, 0xd6,
+ 0x2a, 0x4a, 0xec, 0xba, 0x32, 0xed, 0x19, 0xa1, 0x94, 0x51, 0xb6, 0x08,
+ 0xa7, 0x7c, 0x29, 0x4c, 0x20, 0xbf, 0xc5, 0x80, 0xe3, 0x90, 0x16, 0x2f,
+ 0xd2, 0xfc, 0x6a, 0x75, 0x8a, 0x63, 0xdc, 0x73, 0x2b, 0xdf, 0x63, 0x56,
+ 0x2f, 0x3e, 0xa4, 0xb1, 0x7d, 0x00, 0xfb, 0xac, 0x57, 0x0d, 0xff, 0x87,
+ 0x6f, 0xd3, 0x61, 0x60, 0xd6, 0x2f, 0xff, 0x34, 0x78, 0xb3, 0xdf, 0xc6,
+ 0x96, 0xf5, 0x8b, 0xfe, 0xef, 0x80, 0x72, 0x1c, 0xc2, 0x58, 0xb8, 0x8c,
+ 0x58, 0xbf, 0xfb, 0x27, 0x0e, 0x43, 0xcf, 0x37, 0xc4, 0xb1, 0x7e, 0xd6,
+ 0x6f, 0xc1, 0xe8, 0xf7, 0xc8, 0x62, 0x99, 0x1b, 0x4f, 0x09, 0xbb, 0xff,
+ 0xf0, 0x8a, 0x58, 0x5e, 0x6d, 0xcc, 0xf1, 0x3c, 0x96, 0x2f, 0xf4, 0x02,
+ 0x3f, 0x9d, 0xc9, 0x62, 0x99, 0x11, 0x44, 0xad, 0x5f, 0x4f, 0xd4, 0x11,
+ 0x92, 0x7a, 0x16, 0x17, 0xd3, 0x3c, 0xce, 0xb1, 0x7a, 0x7c, 0x31, 0x62,
+ 0xd2, 0x58, 0xb7, 0xb6, 0x9b, 0x11, 0x0f, 0xda, 0x4b, 0x14, 0xe6, 0xec,
+ 0x45, 0x37, 0x47, 0x16, 0x2b, 0x6a, 0x31, 0xca, 0x12, 0x1e, 0x20, 0xbf,
+ 0xef, 0xb9, 0x64, 0xd2, 0x8e, 0xd6, 0x2f, 0xfe, 0xfb, 0x6b, 0x38, 0x59,
+ 0xbf, 0xec, 0xb1, 0x7e, 0x2c, 0xe0, 0xb6, 0xe1, 0xff, 0xcc, 0x75, 0x7f,
+ 0xa0, 0x03, 0xfc, 0x17, 0x4b, 0x17, 0xed, 0x74, 0xef, 0xd2, 0xa2, 0x06,
+ 0x2f, 0xe7, 0x9c, 0x0e, 0x43, 0x45, 0x60, 0xf2, 0xf6, 0x70, 0x43, 0x45,
+ 0x3e, 0x1a, 0x6e, 0x1b, 0xde, 0xfb, 0xcb, 0x6a, 0x65, 0x45, 0x0e, 0x7b,
+ 0xfe, 0xfb, 0x61, 0x67, 0x43, 0xc5, 0x8a, 0x1a, 0xf0, 0x87, 0x44, 0x0c,
+ 0xbb, 0x31, 0x09, 0xe5, 0x0e, 0x94, 0x60, 0x7e, 0x8f, 0x7f, 0x79, 0xdd,
+ 0xef, 0x0a, 0x16, 0x2f, 0xff, 0x7d, 0xbd, 0x98, 0x7e, 0x46, 0x0d, 0x96,
+ 0x2e, 0xe7, 0x16, 0x2f, 0x87, 0xf7, 0x3a, 0xc5, 0xff, 0x64, 0xe1, 0xc9,
+ 0xa3, 0xbf, 0x2c, 0x58, 0x1d, 0x22, 0xff, 0x49, 0x0e, 0x30, 0x44, 0x77,
+ 0xf8, 0x1e, 0x69, 0xcf, 0x1d, 0x2c, 0x57, 0x69, 0xaa, 0x3c, 0x37, 0x09,
+ 0x0a, 0xfc, 0x3d, 0x81, 0xc7, 0xb0, 0x2c, 0x5f, 0xdd, 0x77, 0xfe, 0xdf,
+ 0x75, 0x62, 0xfd, 0x8d, 0xa0, 0xe6, 0x58, 0xbf, 0x3e, 0xbd, 0x9d, 0x2c,
+ 0x5f, 0x0d, 0xa2, 0x75, 0x8b, 0x46, 0x8f, 0x30, 0x45, 0x37, 0xfb, 0x33,
+ 0xb0, 0x39, 0x79, 0x62, 0xfd, 0x18, 0x36, 0x25, 0x8b, 0xc5, 0x9c, 0x58,
+ 0xb9, 0x87, 0xb4, 0xfd, 0x44, 0x67, 0xbc, 0x9a, 0xd2, 0x92, 0x36, 0xb9,
+ 0x09, 0xca, 0x84, 0xec, 0xfb, 0x35, 0x78, 0xd4, 0x2a, 0x19, 0x64, 0x19,
+ 0x3d, 0xe4, 0xd1, 0xee, 0xb9, 0xa8, 0xa3, 0xe6, 0xb9, 0xa4, 0xb1, 0x7f,
+ 0x77, 0xe1, 0xe6, 0x1a, 0xb1, 0x7f, 0x7d, 0xbd, 0xcc, 0xf2, 0xc5, 0xf6,
+ 0x4c, 0xc7, 0x58, 0xa1, 0xa2, 0x63, 0x05, 0xfa, 0x30, 0x0c, 0xba, 0xff,
+ 0xfb, 0x51, 0xdc, 0x8e, 0xd9, 0xdf, 0xf3, 0x53, 0xac, 0x5a, 0x16, 0x2f,
+ 0xa0, 0x98, 0x0b, 0x16, 0xcf, 0x9b, 0x2f, 0x08, 0xdf, 0xed, 0x13, 0x98,
+ 0x1f, 0x66, 0x2c, 0x5c, 0x0d, 0xeb, 0x17, 0xef, 0x7c, 0x53, 0x89, 0x62,
+ 0x86, 0x7f, 0xbf, 0x38, 0x10, 0xd5, 0xff, 0x7d, 0xbe, 0x51, 0x9a, 0xc5,
+ 0x8b, 0xfd, 0x22, 0xcd, 0xec, 0x43, 0x58, 0xb9, 0x81, 0xd1, 0xf5, 0xb9,
+ 0xbd, 0xf8, 0x9f, 0xcf, 0xda, 0xc5, 0xef, 0x3e, 0xf5, 0x8b, 0xfc, 0x3e,
+ 0xe5, 0x98, 0x53, 0xac, 0x58, 0x6b, 0x17, 0xfe, 0x94, 0x6e, 0xe6, 0xbd,
+ 0xc8, 0x92, 0xc5, 0xff, 0x76, 0x38, 0xe3, 0x0f, 0xf0, 0xb1, 0x7f, 0x77,
+ 0xe9, 0xbf, 0x04, 0xb1, 0x7f, 0x9b, 0xdc, 0x7e, 0xc0, 0x62, 0xc5, 0xda,
+ 0x9d, 0x51, 0x82, 0x95, 0xf3, 0xdc, 0x73, 0x6b, 0xff, 0x3e, 0xb0, 0x81,
+ 0xcf, 0x73, 0xb5, 0x8b, 0xff, 0xff, 0xfb, 0x3d, 0xf7, 0x23, 0x76, 0xf3,
+ 0x4e, 0xfe, 0xdf, 0x83, 0xdb, 0x87, 0x72, 0xee, 0x4b, 0x88, 0x2c, 0xbf,
+ 0xf3, 0xb9, 0xbd, 0x38, 0xf6, 0x9a, 0x62, 0xe2, 0x0b, 0x2f, 0xfe, 0xfb,
+ 0x7d, 0xa0, 0xbd, 0xb4, 0xd3, 0x17, 0x10, 0x59, 0x7f, 0xa1, 0x8b, 0xdb,
+ 0x4d, 0x31, 0x71, 0x05, 0x97, 0xf1, 0xf0, 0x7b, 0x4d, 0x31, 0x71, 0x05,
+ 0x97, 0xff, 0xfc, 0xe4, 0x4c, 0x7d, 0xbc, 0xeb, 0xed, 0xa6, 0x36, 0x7c,
+ 0x31, 0x71, 0x05, 0x97, 0x77, 0xb4, 0x69, 0xd1, 0xf4, 0xa5, 0xa5, 0x57,
+ 0x44, 0x24, 0x0a, 0x85, 0x5b, 0x1f, 0x40, 0x29, 0x47, 0xf7, 0xf9, 0xa0,
+ 0xde, 0x7b, 0x9d, 0xac, 0x5f, 0x3e, 0x80, 0xeb, 0x17, 0xff, 0x7d, 0xbe,
+ 0xd0, 0x5e, 0xda, 0x69, 0x8b, 0x88, 0x2c, 0xbf, 0xe9, 0xb9, 0xd3, 0x4f,
+ 0xb4, 0xd3, 0x17, 0x10, 0x59, 0x7e, 0xf7, 0x20, 0xfb, 0x7a, 0x45, 0x20,
+ 0x6a, 0xb7, 0xff, 0xb6, 0xf5, 0xf6, 0xea, 0x3d, 0xcd, 0xa6, 0x98, 0xb8,
+ 0x82, 0xcb, 0xff, 0xff, 0x88, 0x98, 0xfb, 0x45, 0x9b, 0x79, 0xd7, 0xdb,
+ 0x4c, 0x6c, 0xf8, 0x62, 0xe2, 0x0b, 0x2b, 0x13, 0x2b, 0xed, 0x11, 0xd8,
+ 0x6f, 0xf3, 0x69, 0x8d, 0x9f, 0x0c, 0x5c, 0x41, 0x65, 0xff, 0xa7, 0x38,
+ 0x98, 0xee, 0x5d, 0xc9, 0x71, 0x05, 0x95, 0xf4, 0x48, 0x89, 0x0e, 0xff,
+ 0xf9, 0xdf, 0xb9, 0x73, 0xec, 0x31, 0xc6, 0xa1, 0x22, 0xff, 0xd9, 0x29,
+ 0x0b, 0x9a, 0x29, 0xf7, 0x17, 0x10, 0x59, 0x5d, 0x23, 0x13, 0x44, 0x7c,
+ 0x50, 0xbf, 0xf7, 0x4d, 0xaf, 0x38, 0x39, 0xb4, 0xc5, 0xc4, 0x16, 0x5f,
+ 0xdf, 0x6f, 0xfd, 0x80, 0xa8, 0x02, 0xcb, 0xf6, 0x03, 0x69, 0xa6, 0x2e,
+ 0x20, 0xb2, 0xec, 0xf7, 0x47, 0xeb, 0xf3, 0xba, 0xed, 0x1e, 0x9c, 0x86,
+ 0x35, 0xfc, 0x7c, 0x1e, 0xd3, 0x4c, 0x5c, 0x41, 0x65, 0xff, 0xba, 0xfb,
+ 0x69, 0x8d, 0x9f, 0x0c, 0x5c, 0x41, 0x65, 0xd9, 0xb5, 0xd1, 0x21, 0xc4,
+ 0x0b, 0xfc, 0x26, 0x3b, 0x97, 0x72, 0x5c, 0x41, 0x65, 0xff, 0xb1, 0xb7,
+ 0xe1, 0x60, 0xde, 0x4b, 0x88, 0x2c, 0x39, 0xe0, 0xd0, 0xd7, 0xa3, 0x74,
+ 0x6e, 0x03, 0x62, 0x8f, 0xc7, 0x91, 0xc2, 0xfa, 0x32, 0x51, 0x42, 0xe4,
+ 0xc7, 0x0b, 0x81, 0x0a, 0x88, 0x2c, 0xd9, 0x44, 0x5d, 0xcf, 0xd2, 0xc5,
+ 0x0d, 0x96, 0x51, 0x87, 0x5d, 0x42, 0x30, 0x14, 0xa1, 0x1f, 0x1c, 0xd6,
+ 0x33, 0x03, 0x7a, 0x35, 0x98, 0x4b, 0x94, 0xb6, 0xab, 0xa4, 0x11, 0x62,
+ 0xf4, 0x48, 0x22, 0xc5, 0x41, 0xb9, 0x21, 0xaa, 0x9d, 0x9e, 0x49, 0x23,
+ 0xe1, 0xc2, 0x17, 0xb8, 0x51, 0xea, 0x13, 0x5f, 0x2d, 0x72, 0x80, 0x53,
+ 0x0b, 0x0a, 0x10, 0x97, 0xf4, 0x1f, 0xa6, 0xfe, 0x2c, 0x5f, 0xfa, 0x45,
+ 0x9e, 0xfb, 0x67, 0x7e, 0x58, 0xbf, 0x8a, 0x5c, 0xf7, 0xe1, 0x62, 0xff,
+ 0xff, 0xd9, 0xef, 0xbc, 0x87, 0x9a, 0x6c, 0xde, 0x1e, 0xbe, 0xdd, 0xf9,
+ 0x62, 0xe6, 0x35, 0x62, 0xff, 0x14, 0xb3, 0x79, 0x67, 0x16, 0x2a, 0x49,
+ 0xab, 0xe1, 0x73, 0x1f, 0x9c, 0xbb, 0xee, 0x01, 0x8c, 0x5e, 0x01, 0xc0,
+ 0xb1, 0x7f, 0xa3, 0xec, 0x67, 0x72, 0xe2, 0xc5, 0xfa, 0x3d, 0xcf, 0xb2,
+ 0xc5, 0xff, 0xb5, 0x86, 0xff, 0x0e, 0x2d, 0x4e, 0xb1, 0x7f, 0xdd, 0x96,
+ 0x31, 0xf0, 0x80, 0xb1, 0x7f, 0xff, 0xfe, 0x79, 0x89, 0xcc, 0xcd, 0xed,
+ 0xcf, 0xe0, 0x37, 0x33, 0xdc, 0x73, 0xe7, 0x7e, 0x58, 0xbf, 0xf3, 0xbc,
+ 0xf8, 0x77, 0x2e, 0xe4, 0xb1, 0x7b, 0x98, 0x4b, 0x16, 0x94, 0xc7, 0xb7,
+ 0xe3, 0xfb, 0xff, 0xcf, 0xd4, 0x10, 0xcb, 0x37, 0xe9, 0xb8, 0xb1, 0x7f,
+ 0xee, 0x4d, 0x21, 0x0e, 0x69, 0x08, 0x6b, 0x15, 0xb5, 0x54, 0x94, 0xe3,
+ 0xd2, 0x36, 0x19, 0x46, 0x21, 0x1a, 0x71, 0xdc, 0x39, 0x3e, 0x53, 0xe4,
+ 0xbb, 0xfe, 0xcf, 0x19, 0x84, 0x3f, 0xc2, 0xc5, 0xee, 0x31, 0x8b, 0x17,
+ 0xff, 0x47, 0x72, 0x0c, 0xfc, 0xf4, 0x76, 0x62, 0xc5, 0xfa, 0x41, 0x02,
+ 0x0a, 0x75, 0x8a, 0x63, 0xf9, 0x74, 0xaa, 0xed, 0x16, 0xff, 0x84, 0xbd,
+ 0xf7, 0x8a, 0x0e, 0xb1, 0x7e, 0xd4, 0x77, 0x2e, 0x2c, 0x5f, 0xb7, 0x30,
+ 0x26, 0x12, 0xc5, 0x4e, 0x9c, 0x8c, 0xa1, 0xe0, 0xc5, 0x3a, 0x22, 0x01,
+ 0x55, 0xff, 0x41, 0xbf, 0xc2, 0x2c, 0xed, 0x62, 0xf1, 0xdf, 0xcb, 0x17,
+ 0x3f, 0x16, 0x2e, 0xe7, 0x4b, 0x17, 0xa4, 0xde, 0x58, 0xbf, 0xfd, 0xe6,
+ 0x21, 0x4b, 0x38, 0x0f, 0x7b, 0xb5, 0x8b, 0x14, 0xc7, 0xd2, 0x18, 0xed,
+ 0xff, 0x71, 0xfb, 0xdc, 0x17, 0xdb, 0x4b, 0x17, 0xf6, 0x68, 0x07, 0x6e,
+ 0x2c, 0x5c, 0x2e, 0x78, 0xfb, 0x37, 0x0f, 0xaf, 0x43, 0x1d, 0x62, 0xc6,
+ 0xac, 0x5b, 0x3a, 0x35, 0xfa, 0x1c, 0xbf, 0xfb, 0x7e, 0xf8, 0xe3, 0xff,
+ 0xb9, 0x67, 0x96, 0x2b, 0x13, 0x66, 0x04, 0x25, 0x77, 0x18, 0x03, 0x27,
+ 0xbf, 0x85, 0x34, 0x17, 0x19, 0x62, 0xff, 0x10, 0x79, 0xa2, 0x83, 0xac,
+ 0x5f, 0xc2, 0xf1, 0x47, 0xb8, 0xb1, 0x58, 0x7c, 0x20, 0x33, 0xb4, 0x2c,
+ 0x54, 0x95, 0x91, 0x9a, 0x3b, 0xf1, 0x70, 0x47, 0xd0, 0x48, 0xdc, 0x84,
+ 0x78, 0x42, 0x1a, 0x85, 0xe3, 0x9c, 0x94, 0x35, 0xda, 0x83, 0xcb, 0x5c,
+ 0xbc, 0x76, 0xe2, 0xc5, 0xf8, 0xd1, 0xc3, 0x92, 0xc5, 0xff, 0xb9, 0x9f,
+ 0x69, 0x30, 0xf0, 0xeb, 0x17, 0xe9, 0x46, 0xf7, 0xfa, 0xc5, 0x4e, 0x8a,
+ 0xdc, 0x1d, 0x34, 0xa1, 0xcf, 0xaf, 0xfe, 0xce, 0xfd, 0xc6, 0x28, 0x03,
+ 0x9d, 0x62, 0xff, 0xfe, 0x37, 0x6f, 0xf3, 0x5a, 0xc0, 0x99, 0xd6, 0xeb,
+ 0x16, 0xf5, 0x8b, 0xfe, 0x30, 0x32, 0x7e, 0xb0, 0xba, 0x58, 0xbe, 0x09,
+ 0x99, 0x3a, 0xc5, 0xff, 0xf7, 0xbe, 0xdb, 0x4d, 0x7d, 0xa5, 0x86, 0x38,
+ 0x16, 0x2f, 0xe3, 0x75, 0x12, 0x73, 0x56, 0x2b, 0x11, 0x0a, 0xea, 0xb7,
+ 0xc7, 0x1e, 0x1d, 0x62, 0x96, 0x2f, 0xf3, 0x7c, 0xb3, 0xd0, 0x05, 0x8b,
+ 0xdf, 0x18, 0x67, 0x37, 0xde, 0x0c, 0xbf, 0xed, 0xec, 0x43, 0x17, 0xf0,
+ 0xeb, 0x17, 0xf3, 0xfd, 0xb9, 0x12, 0x58, 0xad, 0xa8, 0xfd, 0x86, 0x1c,
+ 0x34, 0xe1, 0xdd, 0xff, 0x82, 0xf8, 0x45, 0x81, 0xc1, 0x01, 0x62, 0xfc,
+ 0x73, 0xb3, 0xc9, 0x62, 0xff, 0x67, 0xdb, 0x8c, 0x29, 0x2c, 0x54, 0xea,
+ 0xe1, 0xf1, 0x11, 0x99, 0xbe, 0x78, 0x50, 0xaa, 0xf4, 0x63, 0xc2, 0x3d,
+ 0xde, 0x82, 0x10, 0xa2, 0xfb, 0xbe, 0x47, 0x6b, 0x17, 0xff, 0xfe, 0xfb,
+ 0x69, 0xa0, 0xf8, 0x4d, 0x1f, 0x76, 0xd6, 0x9a, 0x75, 0x8b, 0xff, 0x4b,
+ 0x3b, 0x96, 0xa3, 0xcf, 0xe5, 0x8b, 0xc7, 0x89, 0x2c, 0x5f, 0xb0, 0x7f,
+ 0x11, 0x8b, 0x17, 0xff, 0xe2, 0x16, 0xef, 0xdb, 0x51, 0xf7, 0xe1, 0x60,
+ 0x16, 0x2b, 0x6a, 0x6d, 0x9d, 0x12, 0xcc, 0xd2, 0xe8, 0x04, 0x3a, 0x19,
+ 0x55, 0xff, 0x75, 0xf6, 0x1f, 0xe3, 0xdc, 0x58, 0xbc, 0x37, 0xf2, 0xc5,
+ 0xff, 0xf1, 0x67, 0x7e, 0xd4, 0x49, 0xb8, 0x1f, 0x60, 0x58, 0xbf, 0xff,
+ 0x7b, 0xd9, 0x34, 0xb2, 0x7d, 0xbd, 0xc1, 0x47, 0x16, 0x2f, 0xff, 0x7b,
+ 0x26, 0x96, 0x4f, 0xdc, 0x14, 0x71, 0x62, 0xe8, 0xef, 0x6a, 0x29, 0xbc,
+ 0xb5, 0x50, 0x99, 0x51, 0x43, 0xe6, 0xff, 0xdc, 0x82, 0x89, 0x7b, 0xf8,
+ 0x4b, 0x15, 0xa5, 0x48, 0x27, 0x5b, 0x73, 0xb0, 0x46, 0x8f, 0xc2, 0x7b,
+ 0xcd, 0xb9, 0x8b, 0x17, 0x9b, 0xbf, 0x2c, 0x5e, 0xfc, 0xec, 0xb1, 0x76,
+ 0x19, 0xc3, 0x78, 0x21, 0xeb, 0xff, 0x68, 0x9c, 0xc7, 0xd6, 0xb3, 0xb5,
+ 0x8b, 0xfc, 0xda, 0x3c, 0x61, 0x0d, 0x62, 0xe6, 0x35, 0x62, 0xbe, 0x79,
+ 0x44, 0x65, 0x7f, 0x71, 0x87, 0x86, 0x71, 0x62, 0xfe, 0x7d, 0x38, 0xdb,
+ 0x16, 0x2d, 0x32, 0xc5, 0xda, 0x02, 0xc5, 0xd8, 0x62, 0xc5, 0x7c, 0xf0,
+ 0xdc, 0x4f, 0xc3, 0x15, 0x09, 0xff, 0xce, 0xb6, 0x32, 0xdc, 0x84, 0x57,
+ 0x64, 0x3f, 0x2f, 0xf3, 0x7d, 0xcd, 0xa5, 0x8b, 0xf3, 0x97, 0xb9, 0x0b,
+ 0x17, 0x3b, 0x2c, 0x56, 0x8d, 0xe9, 0xc9, 0xeb, 0xb4, 0x6f, 0xfd, 0xa8,
+ 0x0a, 0x97, 0xc6, 0x67, 0xdd, 0x62, 0xf8, 0xdd, 0x31, 0x8b, 0x17, 0xe9,
+ 0xdf, 0xf1, 0xba, 0xb1, 0x7f, 0xc6, 0xe1, 0x44, 0xbd, 0x9d, 0x2c, 0x5e,
+ 0xe4, 0x0d, 0x62, 0xf6, 0xe6, 0x79, 0x62, 0xd3, 0xf6, 0x6f, 0x7c, 0x3b,
+ 0x41, 0x44, 0x78, 0xe1, 0x2b, 0x16, 0x09, 0xde, 0xfe, 0x37, 0xf1, 0xdf,
+ 0xb1, 0x62, 0xff, 0x16, 0x0f, 0xf0, 0x61, 0x2c, 0x5e, 0xcd, 0x42, 0xc5,
+ 0xfc, 0x3f, 0xb8, 0x79, 0x3a, 0xc5, 0x48, 0xf3, 0x3c, 0x39, 0x50, 0x8d,
+ 0x1d, 0x18, 0x13, 0xfd, 0xff, 0xfe, 0xd4, 0x7e, 0x35, 0xa8, 0x9f, 0xce,
+ 0xe6, 0xe7, 0x7e, 0x58, 0xa8, 0x67, 0x09, 0xe4, 0xbc, 0x46, 0x9c, 0x3a,
+ 0x79, 0x65, 0xe0, 0x31, 0x28, 0xc5, 0x05, 0x18, 0x80, 0x65, 0xd7, 0xc5,
+ 0x37, 0x31, 0x62, 0xfd, 0x2c, 0x9f, 0xd0, 0xb1, 0x7f, 0xff, 0x47, 0x83,
+ 0x9c, 0x79, 0xe8, 0xde, 0xde, 0x04, 0x49, 0x62, 0xff, 0xa7, 0x3f, 0xdb,
+ 0x5a, 0x79, 0x2c, 0x5f, 0xf0, 0xc6, 0x50, 0x60, 0xf3, 0x75, 0x62, 0xa0,
+ 0xfe, 0x04, 0x77, 0x53, 0xa3, 0xe0, 0xa1, 0xaf, 0x4b, 0x14, 0xc9, 0xbc,
+ 0x4c, 0x46, 0x51, 0x90, 0xee, 0x14, 0x5f, 0xe9, 0xe7, 0x82, 0xef, 0x3c,
+ 0xb1, 0x7e, 0x1e, 0x61, 0x74, 0xb1, 0x7e, 0xef, 0xc4, 0xff, 0x58, 0xba,
+ 0x26, 0x58, 0xa9, 0xcf, 0xa6, 0x45, 0x00, 0x29, 0xac, 0x4c, 0x55, 0x91,
+ 0x85, 0x09, 0xfb, 0xff, 0xb4, 0x42, 0xef, 0xc5, 0x93, 0xb9, 0x2c, 0x5e,
+ 0xe8, 0x33, 0xac, 0x5f, 0xff, 0xc3, 0xf8, 0xa7, 0x6c, 0xd6, 0xb2, 0x3b,
+ 0x93, 0x1d, 0x62, 0xff, 0x3c, 0xc4, 0x2f, 0x14, 0x2c, 0x5f, 0xc3, 0x0f,
+ 0xde, 0x63, 0x16, 0x2e, 0x29, 0x96, 0x29, 0xcf, 0x24, 0x46, 0x37, 0x7c,
+ 0xd5, 0x8b, 0xf7, 0x43, 0x62, 0x9d, 0x62, 0xff, 0xbf, 0x1d, 0x96, 0x0d,
+ 0xe4, 0xb1, 0x79, 0xf5, 0x3a, 0xc5, 0xc0, 0x85, 0x8b, 0xe6, 0x83, 0xe2,
+ 0xc5, 0x2c, 0x5f, 0xce, 0x6f, 0xa3, 0x40, 0x58, 0xa1, 0x9b, 0xb2, 0x0c,
+ 0xbf, 0xff, 0xd0, 0xc3, 0x28, 0x17, 0x5e, 0xce, 0x87, 0x1d, 0x06, 0x75,
+ 0x8b, 0x81, 0x0b, 0x17, 0x41, 0xab, 0x17, 0xfd, 0x9e, 0xe4, 0x1c, 0x3c,
+ 0x99, 0x62, 0xff, 0x73, 0x3e, 0xdc, 0x14, 0xeb, 0x17, 0x18, 0x62, 0x45,
+ 0xff, 0x16, 0x6f, 0x79, 0x71, 0x86, 0xb1, 0x5d, 0x2a, 0x08, 0x61, 0xed,
+ 0x0b, 0x9d, 0x73, 0xe4, 0x00, 0x64, 0x0b, 0x8b, 0x90, 0xc7, 0x0e, 0xcc,
+ 0x35, 0x0c, 0x6a, 0xf1, 0x86, 0x18, 0x91, 0x63, 0xa4, 0x6c, 0x9a, 0x1b,
+ 0xce, 0xfa, 0x48, 0xd9, 0x47, 0x28, 0x70, 0xc0, 0xbf, 0xff, 0xc0, 0x7f,
+ 0xbb, 0x7c, 0x5f, 0x8e, 0x9b, 0xb9, 0x31, 0xd6, 0x29, 0x62, 0x86, 0xb8,
+ 0x37, 0x83, 0x3d, 0x15, 0x4d, 0x2c, 0x9b, 0xc8, 0x81, 0xb1, 0x54, 0xeb,
+ 0xbb, 0xa3, 0x45, 0xe8, 0x83, 0xb5, 0xdf, 0xbe, 0x3c, 0xe1, 0xe5, 0xff,
+ 0xfa, 0x51, 0xa0, 0x0f, 0x58, 0xc6, 0xf3, 0xf0, 0x75, 0x8b, 0xfb, 0xd1,
+ 0x9f, 0xc9, 0xd6, 0x2e, 0xc3, 0xac, 0x56, 0x22, 0x73, 0xb5, 0x7e, 0x17,
+ 0x5f, 0xfd, 0x9f, 0xfb, 0xb7, 0xa3, 0x0a, 0x65, 0x8a, 0x0a, 0xbf, 0x5f,
+ 0xf4, 0x4f, 0x68, 0x4f, 0x18, 0x44, 0xa7, 0x56, 0x07, 0x19, 0xc6, 0x52,
+ 0x01, 0x4d, 0x9c, 0x1c, 0xee, 0x5b, 0x53, 0x4f, 0x60, 0xcd, 0x0d, 0xed,
+ 0x43, 0x88, 0xf1, 0xc0, 0x7e, 0x9e, 0x50, 0xf5, 0x80, 0xd0, 0x23, 0xf6,
+ 0x2a, 0x49, 0x17, 0x29, 0xe1, 0x9e, 0x96, 0x40, 0x29, 0xe1, 0x1d, 0xf1,
+ 0x80, 0x6e, 0x18, 0x5c, 0x1f, 0x96, 0x2f, 0xec, 0x00, 0x1b, 0x52, 0x58,
+ 0xbd, 0xf1, 0x1a, 0xb1, 0x77, 0x58, 0xb1, 0x7e, 0xc9, 0xa3, 0xbe, 0x2c,
+ 0x50, 0xd1, 0x1e, 0xc5, 0xce, 0x3f, 0xc1, 0x8b, 0xff, 0x41, 0xf7, 0x1e,
+ 0x7c, 0x1b, 0x18, 0xb1, 0x76, 0x18, 0xb1, 0x74, 0x79, 0x62, 0xff, 0xf9,
+ 0x8a, 0x01, 0x82, 0x0b, 0xb7, 0xdb, 0x52, 0x58, 0xa9, 0xd1, 0x03, 0xd0,
+ 0xc7, 0x05, 0xef, 0x9f, 0xee, 0x05, 0x8b, 0x1d, 0x62, 0xa4, 0x99, 0x56,
+ 0x43, 0x13, 0x46, 0x5e, 0x22, 0xbf, 0xd2, 0x62, 0xc3, 0x8b, 0xeb, 0x17,
+ 0xef, 0xbb, 0x13, 0xac, 0x5f, 0xf4, 0x36, 0xb1, 0xbf, 0x03, 0x58, 0xbf,
+ 0xf6, 0x7b, 0x9f, 0x63, 0xbe, 0x69, 0x62, 0xff, 0xf7, 0xc5, 0xcd, 0x41,
+ 0x4d, 0xf7, 0x04, 0x2c, 0x5d, 0x83, 0x58, 0xbe, 0x8c, 0xfb, 0xac, 0x54,
+ 0x26, 0xa2, 0x69, 0x9f, 0xc9, 0x88, 0xdc, 0x47, 0xdb, 0xd2, 0xc2, 0x0b,
+ 0xdf, 0xb3, 0x6e, 0x03, 0xcb, 0x17, 0xdb, 0x7d, 0x1b, 0xd6, 0x2f, 0x86,
+ 0x50, 0x1a, 0xc5, 0xf7, 0x50, 0x76, 0x58, 0xad, 0xa7, 0x8d, 0x84, 0x77,
+ 0xff, 0x13, 0xeb, 0x3c, 0x51, 0xf6, 0x92, 0xc5, 0xe3, 0xe7, 0x96, 0x2f,
+ 0xd8, 0x63, 0x40, 0xd6, 0x2f, 0xfb, 0x30, 0xe1, 0x84, 0x82, 0x92, 0xc5,
+ 0x62, 0x20, 0x18, 0x77, 0x85, 0x17, 0xfb, 0xaf, 0xc0, 0x6d, 0x13, 0xac,
+ 0x5c, 0xe6, 0xac, 0x56, 0x8f, 0x3b, 0xc6, 0xd7, 0xce, 0x77, 0x99, 0x62,
+ 0xff, 0xe6, 0x9b, 0x6b, 0x77, 0xc7, 0x0d, 0x8e, 0xb1, 0x7f, 0xe6, 0x8f,
+ 0x38, 0x64, 0xdd, 0xc9, 0x62, 0xa6, 0x44, 0x47, 0x12, 0x6f, 0xcd, 0x06,
+ 0x44, 0xcb, 0x17, 0xfb, 0x6f, 0xdc, 0x00, 0x6f, 0xac, 0x5b, 0x4b, 0x17,
+ 0xbd, 0xdf, 0x16, 0x2b, 0x0d, 0x8b, 0x89, 0x54, 0x23, 0x4d, 0x89, 0x1c,
+ 0xa4, 0x99, 0xef, 0xff, 0xfc, 0xf3, 0x0a, 0x42, 0xeb, 0x6f, 0xdb, 0xde,
+ 0x8e, 0xe2, 0x78, 0xe2, 0xc5, 0xf8, 0x9f, 0x76, 0x79, 0x96, 0x2f, 0xa3,
+ 0x4d, 0xda, 0xc5, 0xf4, 0xdc, 0x8f, 0x2c, 0x57, 0x48, 0xe7, 0x99, 0xcd,
+ 0xcb, 0x44, 0x47, 0x7f, 0x6f, 0xd3, 0xc3, 0x6e, 0x2c, 0x5f, 0xfc, 0x4f,
+ 0xe6, 0xd7, 0xe0, 0xfc, 0x75, 0x8a, 0x58, 0xa1, 0x1e, 0x79, 0x88, 0x77,
+ 0xff, 0x84, 0xfd, 0xed, 0xc3, 0x8b, 0x82, 0xe3, 0xac, 0x5f, 0xfd, 0x2f,
+ 0xc6, 0xa7, 0x8f, 0x71, 0xe4, 0xb1, 0x7c, 0x4e, 0xfb, 0xd6, 0x20, 0xf1,
+ 0xaf, 0xe8, 0xeb, 0xdc, 0x7e, 0xd6, 0x2f, 0xbf, 0x8f, 0x3a, 0xc5, 0xf6,
+ 0x1d, 0xfb, 0x58, 0xae, 0xd3, 0x3d, 0xdd, 0x84, 0xa1, 0x19, 0xf0, 0xc0,
+ 0x32, 0x3b, 0xcd, 0xdc, 0xcb, 0x17, 0xc2, 0x0b, 0x9d, 0x96, 0x2f, 0xd9,
+ 0x93, 0x8b, 0x8b, 0x17, 0xda, 0x26, 0x02, 0xc5, 0xf3, 0x74, 0xfa, 0x58,
+ 0xba, 0x00, 0xb1, 0x7c, 0x29, 0xc5, 0xb3, 0xf3, 0x74, 0x19, 0x1d, 0x32,
+ 0x26, 0xbe, 0xb9, 0x60, 0x2c, 0x5d, 0x9d, 0x2c, 0x5f, 0xb3, 0x5a, 0x6d,
+ 0x2c, 0x56, 0xe9, 0xe9, 0x7c, 0x48, 0x03, 0x17, 0xee, 0xbe, 0xe2, 0xd2,
+ 0xc5, 0xf4, 0x77, 0x9d, 0x2c, 0x5f, 0x83, 0x68, 0xe3, 0xac, 0x53, 0x9e,
+ 0x60, 0x89, 0x2f, 0x07, 0x1b, 0xab, 0x17, 0xfd, 0xf7, 0xe7, 0xda, 0x77,
+ 0x25, 0x8b, 0xe7, 0x9c, 0x39, 0x2c, 0x50, 0x55, 0x9b, 0xf1, 0xb1, 0x42,
+ 0xa2, 0x23, 0x65, 0x94, 0x72, 0x63, 0x68, 0xc2, 0xa3, 0x5b, 0x7a, 0x23,
+ 0xee, 0x18, 0x4c, 0xf9, 0xba, 0x45, 0x34, 0x6f, 0xda, 0x8c, 0x80, 0xe7,
+ 0xdf, 0x84, 0x0b, 0xc6, 0xc0, 0x05, 0x40, 0xb8, 0xff, 0x09, 0xfd, 0x0c,
+ 0x31, 0x3a, 0x6f, 0x32, 0x31, 0xdb, 0x70, 0x84, 0x32, 0x10, 0x87, 0x37,
+ 0xfb, 0x09, 0x81, 0xcf, 0xb2, 0xc5, 0xc4, 0x05, 0x8b, 0x6e, 0xac, 0x5f,
+ 0x0c, 0xef, 0x25, 0x8a, 0x63, 0x70, 0x21, 0x5a, 0xda, 0x8a, 0x1f, 0x99,
+ 0x12, 0x7d, 0xe6, 0x9c, 0x4b, 0x17, 0xfe, 0xde, 0xda, 0x10, 0x47, 0x9c,
+ 0x39, 0x2c, 0x5a, 0x16, 0x2b, 0x0f, 0x5d, 0xd1, 0xaf, 0xd0, 0x06, 0xef,
+ 0x16, 0x2e, 0x38, 0x96, 0x2f, 0xcf, 0xef, 0x88, 0x96, 0x2e, 0x3e, 0xf5,
+ 0x8b, 0xfe, 0x13, 0xb1, 0x3f, 0x9f, 0xeb, 0x15, 0xb5, 0x1b, 0x30, 0x40,
+ 0xc5, 0x1f, 0x18, 0x22, 0x8e, 0x0d, 0x5f, 0xfd, 0x1c, 0x60, 0x46, 0x9b,
+ 0xf0, 0x35, 0x8b, 0xce, 0x20, 0xba, 0xc5, 0xff, 0xb3, 0xa2, 0xce, 0x6e,
+ 0x66, 0xa1, 0x62, 0x86, 0x8f, 0xb2, 0x56, 0xf2, 0x18, 0x64, 0x37, 0xff,
+ 0xa4, 0x51, 0xb4, 0xe5, 0x06, 0xf9, 0xa7, 0x58, 0xbe, 0xc1, 0x6a, 0x75,
+ 0x8b, 0xf3, 0x9f, 0x3e, 0x75, 0x8a, 0xed, 0x13, 0x3a, 0x4d, 0xf1, 0x25,
+ 0x8c, 0x58, 0xbf, 0xa3, 0xb9, 0x31, 0x62, 0xc5, 0xef, 0x6a, 0x16, 0x2f,
+ 0x71, 0xfc, 0xb1, 0x7d, 0x93, 0x87, 0x25, 0x8b, 0xc1, 0x90, 0x16, 0x2b,
+ 0xb3, 0xe0, 0x21, 0xdf, 0x12, 0xdf, 0xde, 0xdf, 0x85, 0x83, 0x58, 0xa9,
+ 0x8f, 0x7b, 0x85, 0xf7, 0xee, 0x64, 0x9b, 0x4b, 0x17, 0xe9, 0xa4, 0xfd,
+ 0xf1, 0x62, 0xb0, 0xf4, 0xf8, 0x51, 0x78, 0x5b, 0xa1, 0x16, 0x2d, 0xbd,
+ 0x62, 0xff, 0xb5, 0xf7, 0x0d, 0xfe, 0xc0, 0x58, 0xa8, 0x3c, 0xe6, 0x14,
+ 0xbf, 0x98, 0xa7, 0xf8, 0xb8, 0xb1, 0x5f, 0x3c, 0xff, 0x10, 0x5f, 0x7f,
+ 0x00, 0xeb, 0x17, 0x6e, 0x84, 0x58, 0xbd, 0xc9, 0x4e, 0xb1, 0x53, 0xa6,
+ 0x81, 0x90, 0xc0, 0x22, 0x21, 0x11, 0x06, 0x3b, 0x50, 0xbd, 0x87, 0x23,
+ 0x1c, 0x94, 0x92, 0xd0, 0xd6, 0x98, 0xc7, 0x42, 0x67, 0x2d, 0x78, 0x6d,
+ 0x93, 0xb7, 0xa3, 0x61, 0xbd, 0x0d, 0xa5, 0x8b, 0xb6, 0x86, 0xb1, 0x47,
+ 0x36, 0xee, 0x39, 0x73, 0x6f, 0x58, 0xbd, 0x33, 0x7d, 0x62, 0xfe, 0x8d,
+ 0x3c, 0xcd, 0xf5, 0x8b, 0xf7, 0x07, 0x05, 0x3b, 0x9e, 0x67, 0x07, 0xaf,
+ 0xff, 0x7b, 0xd0, 0x50, 0x69, 0xb1, 0x2d, 0xd3, 0xac, 0x5f, 0xd9, 0x3c,
+ 0x7f, 0xf0, 0xb1, 0x7e, 0xc9, 0xbf, 0x84, 0xb1, 0x7e, 0xc0, 0xc8, 0x40,
+ 0x58, 0xbf, 0x01, 0xde, 0x47, 0x58, 0xa8, 0x3d, 0x1c, 0x29, 0xbe, 0x63,
+ 0x33, 0x4b, 0x17, 0xff, 0x7f, 0x0f, 0x9b, 0xdc, 0xf9, 0xa9, 0x2c, 0x53,
+ 0x26, 0xff, 0xa4, 0xff, 0x97, 0x13, 0xcf, 0x08, 0x3c, 0x47, 0x78, 0xf0,
+ 0x75, 0x8b, 0xd1, 0x3e, 0x2c, 0x56, 0x2a, 0xb2, 0xed, 0x97, 0x51, 0xde,
+ 0x9d, 0x5b, 0xc3, 0xb7, 0xc7, 0xd6, 0xa1, 0x62, 0xff, 0xfb, 0xde, 0x83,
+ 0xe7, 0xff, 0x0c, 0x50, 0x75, 0x8b, 0xf7, 0x38, 0xe5, 0x25, 0x8b, 0xff,
+ 0xc5, 0x83, 0x79, 0x79, 0x88, 0xb3, 0xa5, 0x8b, 0xf9, 0xb5, 0xc0, 0xe0,
+ 0x0b, 0x17, 0xff, 0x67, 0xbe, 0xde, 0xfe, 0x14, 0x01, 0x62, 0xdb, 0xf6,
+ 0xa3, 0x8b, 0x0a, 0x00, 0x90, 0x45, 0xf7, 0xff, 0xa5, 0xb7, 0x06, 0xdc,
+ 0xef, 0xc2, 0x7e, 0x2c, 0x5f, 0xf7, 0x33, 0xd0, 0x76, 0xd4, 0x96, 0x2b,
+ 0xb4, 0xff, 0x1a, 0x33, 0x02, 0x45, 0xf2, 0x75, 0xfb, 0xe2, 0x28, 0xde,
+ 0xb1, 0x7f, 0x13, 0xfa, 0x50, 0x6a, 0xc5, 0x41, 0xec, 0x06, 0x55, 0x7e,
+ 0xd8, 0xa0, 0xd8, 0x31, 0x62, 0xe3, 0xf1, 0x62, 0xfa, 0x7d, 0xa1, 0x3a,
+ 0x58, 0xbf, 0xbe, 0xc6, 0x67, 0x7e, 0x58, 0xbf, 0xfd, 0xc8, 0xd7, 0x5e,
+ 0xe3, 0x7b, 0xf8, 0x35, 0x8b, 0xd3, 0xec, 0x5b, 0x09, 0x62, 0xf6, 0x77,
+ 0x25, 0x8b, 0x9c, 0x6b, 0x15, 0x86, 0xd5, 0xc7, 0xaf, 0x71, 0xa6, 0x58,
+ 0xa2, 0x37, 0xbc, 0x1f, 0xbf, 0x36, 0xfd, 0x61, 0xd6, 0x2b, 0x11, 0xcc,
+ 0x6c, 0x27, 0x3e, 0x41, 0x6e, 0x2c, 0x5e, 0x35, 0x86, 0xb1, 0x7f, 0x3b,
+ 0xe8, 0xcc, 0xfa, 0xc5, 0xfe, 0x68, 0xf6, 0x6f, 0x71, 0xac, 0x5f, 0xef,
+ 0xc6, 0x9b, 0xa6, 0xde, 0xb1, 0x46, 0xa2, 0xda, 0x61, 0xed, 0x17, 0x78,
+ 0xd2, 0xfa, 0x09, 0x8e, 0xb1, 0x7f, 0xe9, 0xca, 0x3b, 0x61, 0x94, 0x4e,
+ 0xb1, 0x7f, 0x81, 0xcf, 0x14, 0x1f, 0x8b, 0x17, 0xf8, 0xf1, 0xf7, 0xe4,
+ 0x6e, 0xac, 0x54, 0x1f, 0x53, 0x9a, 0x57, 0x48, 0xeb, 0x72, 0x12, 0x85,
+ 0x55, 0x0d, 0x5d, 0xef, 0x46, 0x1a, 0x8c, 0xc8, 0xe6, 0xbf, 0x86, 0x41,
+ 0x46, 0x55, 0x7c, 0x69, 0x83, 0x3a, 0xc5, 0xfb, 0x6f, 0xe3, 0x52, 0x58,
+ 0xad, 0xac, 0xae, 0x98, 0x95, 0xa5, 0x3a, 0x96, 0x4a, 0x1f, 0xea, 0x13,
+ 0x7d, 0x91, 0x4c, 0x5e, 0x71, 0x87, 0x97, 0xcf, 0xe6, 0xa3, 0x09, 0xae,
+ 0xe4, 0x2c, 0x5f, 0x71, 0xca, 0x4b, 0x14, 0x73, 0x73, 0xc1, 0x7b, 0xfa,
+ 0x79, 0xa5, 0xb1, 0x6a, 0x75, 0x8b, 0xde, 0xce, 0x96, 0x2d, 0xd2, 0xc5,
+ 0xec, 0x7f, 0xac, 0x50, 0xcd, 0x79, 0xc4, 0xed, 0x3a, 0xc5, 0xff, 0x0f,
+ 0x0e, 0xdd, 0xc8, 0xa1, 0x62, 0xfd, 0xef, 0xb1, 0xf4, 0xb1, 0x52, 0x3f,
+ 0x56, 0x13, 0xd1, 0xcd, 0xef, 0x8d, 0x96, 0x2d, 0xbd, 0x62, 0xfd, 0xfc,
+ 0x69, 0x71, 0x62, 0xff, 0xfb, 0xf0, 0x1e, 0xcf, 0x89, 0xc1, 0xce, 0x40,
+ 0x12, 0x2f, 0xd9, 0xe7, 0x10, 0x5d, 0x62, 0xdb, 0xab, 0x17, 0xed, 0x74,
+ 0xef, 0xd2, 0xe2, 0x04, 0x2f, 0x72, 0x3b, 0x58, 0xbd, 0xcd, 0x49, 0x62,
+ 0xff, 0xfe, 0x96, 0xdc, 0xfb, 0x96, 0x7b, 0x8f, 0xee, 0x67, 0x96, 0x29,
+ 0x8f, 0xe9, 0xc7, 0xac, 0x08, 0x4c, 0x13, 0x05, 0x7b, 0x37, 0x3c, 0x26,
+ 0x2f, 0x8b, 0x0c, 0x08, 0xb1, 0x73, 0x4e, 0xb1, 0x4c, 0x6f, 0x7c, 0x4b,
+ 0x78, 0x45, 0xd2, 0xc5, 0xf3, 0xbb, 0x86, 0xb1, 0x7f, 0xfd, 0x9f, 0x6d,
+ 0x7d, 0xf8, 0xde, 0x82, 0xe9, 0x62, 0xfa, 0x72, 0x73, 0xac, 0x5c, 0xe4,
+ 0xb1, 0x50, 0x6e, 0x67, 0x23, 0xa0, 0xaa, 0xb4, 0xe9, 0x0a, 0x0c, 0xa3,
+ 0xb5, 0x4d, 0x46, 0x60, 0x78, 0x42, 0xfc, 0x81, 0xc7, 0xb8, 0x45, 0xe8,
+ 0x44, 0x5f, 0x4d, 0xfc, 0xf2, 0xc5, 0xfc, 0xfa, 0xcd, 0xf8, 0x35, 0x8b,
+ 0xf7, 0x4e, 0x6f, 0xd9, 0x62, 0x9c, 0xff, 0x40, 0x48, 0x45, 0xf7, 0xda,
+ 0x1b, 0x1d, 0x62, 0xf0, 0xde, 0x4b, 0x16, 0x92, 0xc5, 0x41, 0xaf, 0x08,
+ 0x3b, 0x7d, 0xe9, 0xdc, 0x96, 0x2f, 0x1e, 0x3a, 0x58, 0xb9, 0xcd, 0x58,
+ 0xac, 0x36, 0xc4, 0x3d, 0x69, 0x2c, 0x5f, 0xd9, 0x38, 0xbd, 0xbf, 0xcb,
+ 0x15, 0x07, 0x88, 0x68, 0x95, 0xc0, 0x31, 0x62, 0xff, 0x4b, 0x51, 0x3b,
+ 0xeb, 0xa5, 0x8a, 0xda, 0x79, 0xee, 0x33, 0x66, 0x58, 0xbf, 0xff, 0x3f,
+ 0x60, 0xeb, 0xed, 0x31, 0x39, 0x9e, 0xcf, 0xac, 0x5e, 0x35, 0xbc, 0xb1,
+ 0x7b, 0x8f, 0xe5, 0x8a, 0x84, 0x52, 0xe0, 0x89, 0xab, 0x3d, 0x8f, 0x5d,
+ 0xb7, 0xeb, 0x17, 0xef, 0x30, 0xc5, 0x0b, 0x17, 0xcf, 0x2c, 0x1a, 0xc5,
+ 0x1c, 0xf2, 0x88, 0xa2, 0xc4, 0xb1, 0x6e, 0x96, 0x2c, 0x78, 0x34, 0x9e,
+ 0x11, 0xb7, 0xa0, 0xfa, 0xf1, 0x16, 0xfe, 0xf6, 0x4d, 0x27, 0x02, 0xc5,
+ 0xfd, 0x07, 0xc3, 0x63, 0x8b, 0x15, 0x3a, 0xba, 0x6c, 0x22, 0xe9, 0x67,
+ 0x4c, 0x67, 0x71, 0xfc, 0x32, 0x00, 0x7a, 0x50, 0xcf, 0xe1, 0x37, 0x8b,
+ 0xef, 0xfc, 0x59, 0xa9, 0x64, 0x83, 0x7d, 0xd5, 0x8b, 0xcc, 0x78, 0x58,
+ 0xbf, 0xe9, 0x6d, 0xc8, 0xeb, 0xac, 0x25, 0x8b, 0xdf, 0x6d, 0x2c, 0x50,
+ 0xcf, 0x67, 0xc7, 0x97, 0xef, 0x96, 0x37, 0x96, 0x2e, 0x83, 0xac, 0x5e,
+ 0xcd, 0x62, 0xc5, 0x74, 0x6c, 0xce, 0x2f, 0x7f, 0xc0, 0xfe, 0x77, 0x2f,
+ 0x34, 0xcb, 0x15, 0x08, 0xb8, 0xc5, 0xa1, 0x11, 0x5d, 0x93, 0xac, 0x58,
+ 0x4b, 0x14, 0x33, 0x55, 0xa1, 0x8b, 0xfd, 0x18, 0x5e, 0xe6, 0xe6, 0xf5,
+ 0x8b, 0xfa, 0x37, 0x7e, 0xcf, 0x25, 0x8b, 0xd1, 0xcd, 0xa7, 0x3e, 0x82,
+ 0x38, 0xbf, 0x9c, 0xce, 0x72, 0x00, 0xb1, 0x5f, 0x3e, 0x32, 0x34, 0xbd,
+ 0x0f, 0xa5, 0x8b, 0xff, 0x7d, 0xcb, 0xdc, 0x21, 0x38, 0x6b, 0x17, 0xfd,
+ 0xad, 0x37, 0x72, 0xf3, 0xf6, 0xb1, 0x7b, 0x71, 0xcd, 0x58, 0xbf, 0xe8,
+ 0x3c, 0xb2, 0x7c, 0x10, 0x5d, 0x62, 0xff, 0xa0, 0x0d, 0x2f, 0xb1, 0x01,
+ 0x62, 0xd3, 0xac, 0x5c, 0xfe, 0xd1, 0xe5, 0x85, 0xce, 0x2b, 0x11, 0xb6,
+ 0xc4, 0x2f, 0x08, 0x9b, 0x9e, 0x75, 0x8b, 0xa0, 0x35, 0x8a, 0x73, 0x60,
+ 0x60, 0xc5, 0xff, 0xcf, 0xc0, 0xfc, 0xc4, 0x29, 0x67, 0x16, 0x2f, 0x18,
+ 0x61, 0x8b, 0xab, 0xe9, 0x8d, 0xc4, 0x35, 0xd5, 0xf4, 0x6c, 0x9b, 0x3a,
+ 0x84, 0x57, 0xbb, 0xc5, 0xc0, 0x75, 0x8b, 0xe9, 0x0a, 0x0d, 0x58, 0xb0,
+ 0x16, 0x2b, 0x0d, 0xb3, 0x92, 0x5e, 0x27, 0x02, 0xc5, 0x42, 0xe2, 0xd0,
+ 0xe1, 0xd8, 0x69, 0x0f, 0x43, 0x8c, 0x7f, 0xa8, 0xc5, 0xfe, 0xc4, 0x08,
+ 0x68, 0x11, 0x0f, 0x93, 0x43, 0x1f, 0xbf, 0xc3, 0xfb, 0x9c, 0x38, 0x25,
+ 0x8b, 0xfb, 0xf9, 0x2f, 0xb6, 0xf5, 0x8a, 0xdd, 0x3e, 0x4f, 0x1a, 0x58,
+ 0x96, 0x2f, 0x68, 0x53, 0xac, 0x54, 0x8d, 0x81, 0xc4, 0x6f, 0xff, 0x89,
+ 0x8d, 0xd9, 0xe7, 0xbe, 0x27, 0x94, 0xa1, 0x62, 0xa0, 0xfd, 0x70, 0x86,
+ 0xfd, 0xfc, 0xf7, 0x21, 0x62, 0xdb, 0xd6, 0x2f, 0xc5, 0xe1, 0x67, 0xd6,
+ 0x2c, 0x25, 0x8a, 0x58, 0xad, 0xa5, 0xf0, 0x84, 0xaa, 0x0f, 0xa2, 0x74,
+ 0x6b, 0x82, 0x32, 0xc5, 0xdb, 0xe1, 0x62, 0xfb, 0x9e, 0xcd, 0x2c, 0x54,
+ 0xea, 0xc5, 0x25, 0x18, 0x79, 0xb0, 0xca, 0xe8, 0x82, 0x62, 0x8d, 0x3e,
+ 0x39, 0x17, 0x06, 0x7c, 0x33, 0x78, 0x6f, 0x25, 0x8b, 0x9b, 0x4b, 0x15,
+ 0x86, 0xd3, 0xe3, 0xb7, 0xfd, 0xbc, 0xb3, 0x86, 0xeb, 0x38, 0xb1, 0x7c,
+ 0x44, 0xc7, 0x58, 0xac, 0x3d, 0xd7, 0x3c, 0xbd, 0x9b, 0xc3, 0x58, 0xb9,
+ 0xbe, 0xb1, 0x73, 0xc9, 0x62, 0xff, 0xc2, 0x73, 0xc6, 0xb8, 0xc5, 0x32,
+ 0xc5, 0x0c, 0xf5, 0x88, 0x5e, 0xfe, 0x36, 0x0e, 0x51, 0x32, 0xc5, 0xf3,
+ 0x9f, 0x0e, 0xb1, 0x7c, 0xc7, 0x8d, 0xd5, 0x8b, 0x9b, 0x5b, 0x4f, 0x1f,
+ 0x08, 0xa8, 0x69, 0x99, 0x63, 0x6e, 0x88, 0x7e, 0xed, 0x7f, 0x7b, 0x39,
+ 0xf1, 0x71, 0x62, 0xf8, 0xee, 0x58, 0xb1, 0x78, 0x81, 0xba, 0xb1, 0x4c,
+ 0x78, 0x2e, 0x43, 0x71, 0x4c, 0xb1, 0x73, 0xf9, 0x62, 0xa0, 0xd7, 0x80,
+ 0x62, 0xf3, 0x44, 0x96, 0x2b, 0x6b, 0x6f, 0xdf, 0xb1, 0x90, 0xec, 0x47,
+ 0x10, 0x9b, 0x28, 0x4b, 0x0c, 0xbb, 0x25, 0xb5, 0x9b, 0x18, 0xf7, 0x45,
+ 0xad, 0x2f, 0xe2, 0x68, 0x4b, 0xe9, 0x08, 0xee, 0xbf, 0x86, 0xd3, 0xcf,
+ 0xe3, 0x02, 0x18, 0x44, 0xfb, 0xc2, 0x01, 0x46, 0xa4, 0x61, 0xee, 0xe3,
+ 0x80, 0x69, 0xe1, 0x08, 0x2f, 0xf9, 0xbe, 0xfa, 0x83, 0x72, 0x65, 0x8b,
+ 0xff, 0xef, 0xc3, 0xeb, 0x9c, 0xcf, 0xb7, 0x05, 0x3a, 0xc5, 0xf6, 0x7d,
+ 0xce, 0xb1, 0x6f, 0x42, 0x2b, 0x78, 0x74, 0x1a, 0x8d, 0xf8, 0x71, 0xf8,
+ 0x0d, 0x62, 0x9c, 0xf7, 0xc4, 0x6d, 0x7f, 0xcf, 0xc2, 0xcd, 0xed, 0xf1,
+ 0x2c, 0x5f, 0xbf, 0x9d, 0x0b, 0x16, 0x2e, 0xce, 0x2c, 0x56, 0x1e, 0x03,
+ 0x94, 0xdf, 0xf1, 0x67, 0xa3, 0x7b, 0x10, 0x16, 0x2f, 0xf7, 0xa3, 0x7b,
+ 0x7a, 0x50, 0xb1, 0x7f, 0xff, 0x60, 0x71, 0xa0, 0x37, 0xb4, 0x23, 0xf3,
+ 0xd9, 0xa5, 0x8b, 0xf1, 0xc3, 0x8d, 0x01, 0x62, 0xb1, 0x17, 0x84, 0x6a,
+ 0x1a, 0xed, 0xf8, 0x6e, 0x59, 0xba, 0xb1, 0x58, 0x9a, 0x70, 0x21, 0xeb,
+ 0xc2, 0xfa, 0x58, 0xbf, 0x37, 0xb8, 0x2d, 0xd5, 0x8b, 0x68, 0xe6, 0xe3,
+ 0xe1, 0x97, 0xcd, 0xe8, 0x92, 0xc5, 0xfe, 0x13, 0xb4, 0xa0, 0xba, 0x58,
+ 0xac, 0x3f, 0xcf, 0x93, 0xf0, 0x8a, 0xf7, 0xf0, 0x0b, 0x17, 0xfe, 0x6d,
+ 0x7d, 0xf8, 0x6e, 0xbd, 0xd2, 0xc5, 0xf0, 0x03, 0x8e, 0x2c, 0x5f, 0x9b,
+ 0xd1, 0xee, 0x24, 0x5f, 0x75, 0x1e, 0xe2, 0x45, 0xc6, 0x18, 0x91, 0x52,
+ 0x3e, 0x6c, 0x28, 0x30, 0x92, 0x92, 0x36, 0x4d, 0x7d, 0x49, 0x33, 0x7f,
+ 0x8e, 0x92, 0x11, 0x90, 0xb9, 0xbc, 0xe4, 0x05, 0x8b, 0x05, 0x8b, 0x17,
+ 0x9f, 0xee, 0xb1, 0x7e, 0x33, 0xc1, 0xc0, 0x16, 0x2f, 0xd9, 0xcf, 0x66,
+ 0xea, 0xc5, 0x62, 0x3a, 0x0d, 0x43, 0x38, 0xe7, 0xc5, 0xdc, 0x73, 0xc5,
+ 0x77, 0x89, 0xcc, 0x58, 0xbf, 0xb8, 0x3f, 0xc1, 0x4e, 0xb1, 0x7e, 0xfb,
+ 0x46, 0x80, 0xb1, 0x53, 0x1f, 0xa0, 0x07, 0x7c, 0x5f, 0x77, 0xd9, 0x62,
+ 0xf3, 0x6f, 0xc5, 0x8b, 0xd9, 0xce, 0x2c, 0x54, 0xc7, 0xa5, 0xa1, 0x72,
+ 0x1e, 0xbf, 0x83, 0xcd, 0x77, 0xc8, 0x58, 0xbf, 0xf9, 0xbe, 0x2d, 0x8b,
+ 0x9e, 0xfb, 0x38, 0x16, 0x2d, 0x87, 0x3f, 0xaf, 0x18, 0x5f, 0xf6, 0x17,
+ 0xbe, 0xd0, 0x53, 0xac, 0x5f, 0xff, 0xef, 0xe1, 0xc3, 0x80, 0x6a, 0x38,
+ 0x59, 0xbd, 0xbe, 0x25, 0x8b, 0xde, 0x8e, 0xb1, 0x13, 0x7e, 0x38, 0xbf,
+ 0xfc, 0x63, 0xf3, 0xcd, 0xf6, 0xc3, 0x5b, 0x4b, 0x14, 0xb1, 0x43, 0x4d,
+ 0x37, 0x21, 0x85, 0xf3, 0x4e, 0x25, 0xd0, 0xd9, 0x18, 0x7d, 0x10, 0xcc,
+ 0xf5, 0xa8, 0xdb, 0x8f, 0x0e, 0x90, 0x4a, 0x4d, 0x28, 0x65, 0x72, 0x10,
+ 0x46, 0x47, 0xed, 0x7f, 0x36, 0x4e, 0x76, 0xf2, 0xc5, 0xfa, 0x07, 0xf7,
+ 0xdd, 0x58, 0xbf, 0x8b, 0xd3, 0x6e, 0x90, 0x16, 0x2b, 0x48, 0x8b, 0x22,
+ 0xe1, 0x15, 0xdf, 0xc5, 0x12, 0xd6, 0xa1, 0x62, 0xf4, 0x68, 0x0b, 0x17,
+ 0xc5, 0x1d, 0x83, 0x0f, 0x2b, 0xe5, 0xb7, 0xf4, 0x9f, 0xcc, 0x2e, 0x2c,
+ 0x5f, 0xfb, 0xdc, 0xce, 0xbe, 0xe5, 0xee, 0x2c, 0x5e, 0x62, 0x02, 0xc6,
+ 0xd3, 0xc0, 0xa3, 0xa3, 0x54, 0x8e, 0x37, 0xb7, 0x5d, 0xcf, 0x2c, 0x5f,
+ 0xf8, 0xed, 0x87, 0xf7, 0x04, 0x5e, 0x58, 0xbf, 0xff, 0xb4, 0x2e, 0x7d,
+ 0xe5, 0xd7, 0xdb, 0xb9, 0x43, 0xc9, 0x62, 0x8d, 0x44, 0xef, 0x8f, 0xef,
+ 0xff, 0xc4, 0xe7, 0xf7, 0xdc, 0xf9, 0x28, 0x07, 0x31, 0x62, 0xa0, 0xfe,
+ 0x30, 0x92, 0xa1, 0x37, 0xec, 0x31, 0xfc, 0x65, 0xb6, 0x9d, 0x62, 0xfe,
+ 0xe4, 0x19, 0xec, 0xe9, 0x62, 0xff, 0xb3, 0x7b, 0xe9, 0xe4, 0xf2, 0x58,
+ 0xba, 0x07, 0xd1, 0xfe, 0xf6, 0x27, 0xc3, 0x0b, 0xfa, 0x3f, 0x1f, 0x89,
+ 0xd6, 0x2f, 0x7a, 0x06, 0xb1, 0x7f, 0xe6, 0x7e, 0xe5, 0xee, 0x13, 0x1a,
+ 0xb1, 0x7f, 0x66, 0xe0, 0xbe, 0xda, 0x58, 0xa9, 0x1f, 0x88, 0x68, 0x15,
+ 0x08, 0xb1, 0xc8, 0x47, 0x54, 0xe9, 0x82, 0xca, 0x1b, 0xf6, 0xe2, 0xc5,
+ 0x2c, 0x53, 0x97, 0xc6, 0x09, 0x54, 0x1f, 0x43, 0xa4, 0x5f, 0xec, 0x3b,
+ 0x97, 0xb9, 0x0b, 0x17, 0x01, 0x96, 0x2b, 0x47, 0x92, 0x46, 0x54, 0x35,
+ 0x46, 0x7f, 0x8e, 0xa5, 0xda, 0x6f, 0xd2, 0xf8, 0xa3, 0x4b, 0x17, 0xfa,
+ 0x37, 0xb6, 0xf2, 0x17, 0x16, 0x2f, 0xe6, 0xe3, 0xf7, 0x2c, 0x58, 0xb9,
+ 0xcf, 0xa3, 0xe5, 0xdc, 0x37, 0xbc, 0xda, 0x35, 0x62, 0xff, 0x34, 0x78,
+ 0xa0, 0xfc, 0x58, 0xae, 0xd3, 0x0e, 0xfc, 0x23, 0x80, 0x60, 0x43, 0xd7,
+ 0xec, 0x11, 0xe3, 0x8b, 0x14, 0xb1, 0x76, 0x4d, 0xa3, 0x69, 0xc2, 0x8b,
+ 0xfe, 0x61, 0x05, 0xff, 0x01, 0x94, 0xeb, 0x17, 0xee, 0xfc, 0x59, 0x3a,
+ 0xc5, 0xfc, 0xde, 0xe3, 0x14, 0xcb, 0x17, 0x44, 0xf0, 0x7b, 0x1f, 0x2a,
+ 0xbc, 0x11, 0x8c, 0x58, 0xac, 0x4c, 0x47, 0xa2, 0xd6, 0x84, 0xb8, 0x42,
+ 0xdb, 0xff, 0x83, 0xe3, 0x72, 0x66, 0x1e, 0x10, 0x16, 0x2f, 0x48, 0x9d,
+ 0x62, 0xf9, 0xfd, 0x93, 0xac, 0x5d, 0x1d, 0xac, 0x5c, 0x50, 0xb1, 0x63,
+ 0xc1, 0xf6, 0xfc, 0x70, 0x88, 0xfc, 0x31, 0x7f, 0x64, 0xdf, 0x80, 0xc9,
+ 0x62, 0xff, 0xf9, 0xf7, 0x43, 0x28, 0xfb, 0xb7, 0xa3, 0xdc, 0x58, 0xa8,
+ 0x44, 0x08, 0x8b, 0xef, 0xe2, 0x13, 0x9e, 0x37, 0x56, 0x28, 0x69, 0xe3,
+ 0x3c, 0x2c, 0xca, 0x18, 0x3e, 0x22, 0xb6, 0x2c, 0x52, 0xc5, 0x9b, 0x45,
+ 0xee, 0xf1, 0x1b, 0xec, 0x01, 0xf8, 0xb1, 0x5d, 0x1e, 0x57, 0x89, 0xef,
+ 0xfe, 0x2c, 0xdd, 0x9c, 0x5a, 0x96, 0x77, 0xe5, 0x8b, 0xfb, 0x4d, 0xcc,
+ 0xcd, 0x2c, 0x54, 0xcb, 0x9b, 0x3a, 0x8e, 0x23, 0xf2, 0x82, 0x8a, 0x15,
+ 0xbc, 0x23, 0xde, 0x95, 0x71, 0x4e, 0xb1, 0x7b, 0xf9, 0x3a, 0xc5, 0xb7,
+ 0x16, 0x2b, 0x0d, 0x9b, 0x8f, 0x5e, 0x93, 0xe9, 0x62, 0xe8, 0xf2, 0xc5,
+ 0xf8, 0xef, 0x2c, 0x1a, 0xc5, 0x31, 0xbf, 0x00, 0xbd, 0xe1, 0x7f, 0x16,
+ 0x2c, 0x25, 0x8b, 0xcc, 0xf2, 0x58, 0xbe, 0xfc, 0x17, 0x96, 0x2b, 0x69,
+ 0xbe, 0xe0, 0xe5, 0xb3, 0x87, 0xe7, 0xbd, 0x42, 0xfb, 0x3d, 0x83, 0x48,
+ 0xbf, 0xe7, 0x23, 0x70, 0x9f, 0xdc, 0x58, 0xbe, 0x73, 0x40, 0x62, 0xc5,
+ 0x48, 0xff, 0xfe, 0x44, 0x47, 0x17, 0xd0, 0x45, 0x0b, 0x15, 0x32, 0xa0,
+ 0x2d, 0x2e, 0x1c, 0x80, 0xa1, 0x21, 0xe8, 0x54, 0x06, 0x5d, 0x7f, 0x39,
+ 0x8f, 0xe7, 0x35, 0x62, 0xf7, 0x0f, 0xa5, 0x8b, 0x9b, 0xa5, 0x8a, 0x01,
+ 0xb6, 0xe0, 0xf5, 0x62, 0xb5, 0x63, 0x52, 0xda, 0x51, 0x0e, 0x99, 0x3c,
+ 0xcb, 0x79, 0x8c, 0xe2, 0xc5, 0xff, 0xd2, 0x0f, 0x80, 0xc1, 0x75, 0x04,
+ 0x05, 0x8b, 0xff, 0x6c, 0x58, 0x31, 0x79, 0xbd, 0x1a, 0x58, 0xbe, 0x6d,
+ 0x6d, 0xc5, 0x8b, 0xfc, 0xfa, 0x89, 0xdf, 0x5d, 0x2c, 0x51, 0xa7, 0xb3,
+ 0xf2, 0x4b, 0xee, 0xe5, 0x9e, 0x0a, 0xa3, 0x03, 0x21, 0x3b, 0x7f, 0x79,
+ 0xb5, 0x02, 0x0b, 0xac, 0x5d, 0xa7, 0xed, 0x37, 0xcf, 0xc6, 0x0e, 0x1a,
+ 0x1d, 0xef, 0xe4, 0xeb, 0x17, 0xa5, 0x28, 0x58, 0xbd, 0x9f, 0xcd, 0xa6,
+ 0xec, 0x43, 0xd5, 0xd2, 0xa4, 0xc7, 0x8e, 0x68, 0x9f, 0xee, 0x61, 0x2c,
+ 0x5f, 0xf9, 0xa7, 0xf7, 0x05, 0xbb, 0xe7, 0xfa, 0xc5, 0x48, 0xf6, 0xfc,
+ 0x2f, 0x7f, 0xfc, 0x59, 0xe6, 0xc2, 0xfe, 0x7b, 0xed, 0xd2, 0xc5, 0xfa,
+ 0x35, 0xec, 0xdd, 0x58, 0xbf, 0xef, 0x31, 0xf9, 0xf8, 0x0c, 0x96, 0x2f,
+ 0x16, 0x79, 0x62, 0xfe, 0x6e, 0x72, 0x3f, 0x0b, 0x14, 0xc7, 0x92, 0x43,
+ 0x97, 0xff, 0x13, 0x75, 0xcf, 0xc3, 0x79, 0xbc, 0xb1, 0x7f, 0xd0, 0x5d,
+ 0x3f, 0x9f, 0xb0, 0x6d, 0x4d, 0x83, 0xa4, 0xee, 0xca, 0xda, 0x10, 0x7a,
+ 0x20, 0xbf, 0xe8, 0xce, 0xf2, 0x73, 0x1f, 0xb5, 0x8b, 0xfe, 0x73, 0x35,
+ 0x8d, 0xf8, 0x1a, 0xc5, 0x68, 0xfd, 0x48, 0xf2, 0xa4, 0xaa, 0x64, 0x11,
+ 0xc1, 0x7a, 0x1e, 0xd7, 0xf0, 0x82, 0xed, 0xad, 0x62, 0xc5, 0xff, 0xfb,
+ 0x3b, 0x97, 0x9a, 0x7c, 0xd7, 0xbc, 0xda, 0x85, 0x8b, 0xfd, 0xfc, 0x35,
+ 0xe1, 0xb7, 0x16, 0x2f, 0xf6, 0x73, 0x37, 0x7f, 0x03, 0x58, 0xb9, 0xc0,
+ 0xb1, 0x74, 0x4e, 0xb1, 0x7b, 0xf1, 0x32, 0xc5, 0xfe, 0x86, 0x2c, 0x9c,
+ 0x39, 0x2c, 0x5b, 0xb1, 0x9f, 0x56, 0x0c, 0x7c, 0x7a, 0xfc, 0xf3, 0x13,
+ 0x4c, 0xb1, 0x5d, 0x26, 0x97, 0xf3, 0x6f, 0x1b, 0x0a, 0x10, 0x3b, 0xcd,
+ 0x6b, 0x13, 0xf5, 0xe4, 0x74, 0x57, 0xde, 0x37, 0x3e, 0xb1, 0x78, 0x9a,
+ 0x16, 0x2e, 0xd4, 0x96, 0x2f, 0xfc, 0x59, 0xef, 0x0a, 0x7f, 0x67, 0x4b,
+ 0x17, 0xc2, 0x7d, 0x49, 0x62, 0xff, 0x16, 0x4d, 0xf8, 0xd4, 0xeb, 0x17,
+ 0xfc, 0x32, 0x8e, 0xfc, 0x2c, 0xd2, 0xc5, 0xd0, 0x6f, 0x0f, 0xbf, 0xc6,
+ 0xb4, 0x34, 0x60, 0x1e, 0x12, 0x57, 0xf3, 0xf7, 0xcc, 0xef, 0xcb, 0x17,
+ 0x61, 0x8b, 0x14, 0x03, 0xc8, 0x23, 0x0b, 0xe3, 0xf0, 0x33, 0xac, 0x5f,
+ 0xde, 0xcf, 0xc7, 0x7c, 0x58, 0xa8, 0x3f, 0x5c, 0x21, 0x11, 0x2d, 0xb8,
+ 0xb1, 0x63, 0x16, 0x2e, 0x60, 0x2c, 0x5f, 0x18, 0xe5, 0x25, 0x8b, 0x86,
+ 0xcb, 0x17, 0x7d, 0x96, 0x2f, 0xa5, 0xcf, 0xe2, 0xc5, 0xf3, 0x08, 0x2f,
+ 0x8b, 0x16, 0xe6, 0xd4, 0x58, 0x8c, 0x5f, 0xa2, 0x39, 0x85, 0xdc, 0x5c,
+ 0x04, 0x74, 0xc9, 0x92, 0x0a, 0x18, 0x94, 0xe9, 0xaf, 0x02, 0x33, 0x6b,
+ 0x81, 0x0b, 0x17, 0x02, 0x16, 0x2f, 0xc2, 0x96, 0x16, 0xcb, 0x1a, 0xe0,
+ 0x0b, 0xdf, 0xff, 0xf7, 0xf0, 0x5a, 0x37, 0xb9, 0x7f, 0x08, 0xdf, 0x94,
+ 0x66, 0x96, 0x2a, 0x17, 0x31, 0xe7, 0x24, 0x18, 0xd9, 0xa3, 0x0d, 0x18,
+ 0x0e, 0xa1, 0xca, 0x08, 0xe2, 0xc9, 0x5f, 0xc7, 0xf7, 0xf6, 0x83, 0xf7,
+ 0x24, 0x17, 0x58, 0xbf, 0xc2, 0xc9, 0xa0, 0xf2, 0x0b, 0xac, 0x5f, 0xb0,
+ 0x71, 0x28, 0xc3, 0xee, 0x01, 0xad, 0xf7, 0x86, 0x38, 0x58, 0xbf, 0xfc,
+ 0x4f, 0xdf, 0x0d, 0x35, 0xf6, 0xf4, 0x70, 0x2c, 0x5f, 0x46, 0xa3, 0xeb,
+ 0x17, 0x4b, 0xb5, 0x8a, 0xc4, 0x46, 0x3a, 0x8f, 0x08, 0xaf, 0xfd, 0xe8,
+ 0x1f, 0x4d, 0x3e, 0x77, 0xe5, 0x8b, 0xfe, 0xc6, 0xef, 0xda, 0x8c, 0xed,
+ 0x62, 0xff, 0xf1, 0x37, 0x7c, 0x98, 0xb2, 0x7c, 0xef, 0xcb, 0x17, 0xfe,
+ 0xfe, 0x1c, 0x38, 0x06, 0x77, 0xe5, 0x8a, 0xc4, 0x47, 0x79, 0x36, 0xff,
+ 0x77, 0xd3, 0x68, 0x38, 0x1a, 0xc5, 0xe3, 0xbc, 0xb6, 0xa7, 0x23, 0x05,
+ 0xc4, 0x85, 0xc8, 0x64, 0x78, 0x8a, 0x9d, 0x55, 0x08, 0x25, 0x20, 0x5c,
+ 0x2f, 0x2c, 0x5d, 0xb9, 0x0b, 0x17, 0xf0, 0x0e, 0x1f, 0x03, 0x9d, 0x62,
+ 0xff, 0xd0, 0x3f, 0xc0, 0x7a, 0xd6, 0x4c, 0xb1, 0x7e, 0x62, 0x28, 0xed,
+ 0x62, 0xbe, 0x7d, 0x1c, 0x41, 0xbb, 0x3b, 0x58, 0xae, 0xd1, 0xab, 0xe8,
+ 0x4d, 0xee, 0x11, 0x5f, 0xfe, 0x0e, 0x0c, 0x89, 0xa4, 0xe5, 0x9d, 0xf9,
+ 0x62, 0xf6, 0x9b, 0x4b, 0x17, 0xff, 0xfe, 0xcf, 0x43, 0x49, 0xf9, 0xc8,
+ 0xd4, 0x49, 0xba, 0x21, 0x71, 0x62, 0x80, 0x88, 0x8e, 0x0e, 0xd4, 0x2a,
+ 0x63, 0x91, 0x5e, 0x0c, 0x3c, 0x3b, 0xf8, 0x72, 0x64, 0x35, 0x6f, 0xe2,
+ 0xce, 0xc0, 0xd2, 0x58, 0xbf, 0xbb, 0xf6, 0xa3, 0x3b, 0x58, 0xbf, 0xb9,
+ 0xc8, 0x94, 0x69, 0x62, 0xff, 0xb5, 0x07, 0x69, 0xa1, 0xf7, 0x56, 0x2b,
+ 0x0f, 0xab, 0xa2, 0xeb, 0xc2, 0xef, 0xcb, 0x17, 0xe8, 0x94, 0xf8, 0x62,
+ 0xc5, 0x2c, 0x51, 0xcd, 0xb3, 0x95, 0x5d, 0x37, 0x16, 0x2a, 0x74, 0xde,
+ 0x37, 0x4b, 0x8a, 0x13, 0x5c, 0x22, 0xf2, 0xa8, 0x64, 0x17, 0xff, 0xff,
+ 0xe2, 0xce, 0xfc, 0x3c, 0xf4, 0x17, 0x59, 0xef, 0xb7, 0x7e, 0x80, 0x19,
+ 0x9f, 0x58, 0xbb, 0x0c, 0x58, 0xbf, 0xe1, 0x17, 0x5f, 0xc9, 0xf8, 0xcb,
+ 0x17, 0xfd, 0x1d, 0xe0, 0x23, 0x7e, 0x4e, 0xb1, 0x7f, 0x16, 0x7b, 0x8e,
+ 0x05, 0x8a, 0x84, 0xd0, 0x75, 0x08, 0x53, 0x8c, 0x00, 0xef, 0x87, 0x97,
+ 0xff, 0xfc, 0xed, 0xe9, 0x30, 0xf2, 0x5f, 0x86, 0xd0, 0x0e, 0xf2, 0x58,
+ 0xbf, 0xa7, 0x6d, 0x77, 0xf9, 0xd6, 0x2b, 0xe8, 0x97, 0x26, 0x5b, 0xfb,
+ 0x9a, 0xce, 0xa2, 0x75, 0x8b, 0xff, 0xde, 0x69, 0xe7, 0x82, 0xcf, 0x37,
+ 0x66, 0x2c, 0x54, 0xe7, 0xfb, 0x23, 0x0b, 0xe8, 0xef, 0xdb, 0xab, 0x15,
+ 0x07, 0x95, 0x22, 0x3b, 0xff, 0xde, 0x7d, 0x38, 0xe0, 0x9f, 0x4f, 0x25,
+ 0x8b, 0xfe, 0x0b, 0xea, 0x3c, 0xdd, 0x30, 0xd6, 0x2f, 0xf6, 0x14, 0xf8,
+ 0x37, 0xfa, 0xc5, 0x4c, 0x8d, 0xaf, 0x10, 0x89, 0x20, 0xc3, 0xeb, 0x81,
+ 0x8b, 0x17, 0xfb, 0xaf, 0xb7, 0xc9, 0xce, 0xb1, 0x7e, 0x3e, 0x0d, 0x8c,
+ 0x58, 0xbb, 0xd3, 0xac, 0x5f, 0x77, 0xd3, 0x69, 0x62, 0xd1, 0x23, 0x7d,
+ 0xe1, 0x9a, 0xc4, 0x46, 0x93, 0x3d, 0xc7, 0x85, 0x8b, 0xfe, 0x83, 0x7b,
+ 0xf6, 0xa3, 0x0c, 0x58, 0xbf, 0xf6, 0x6f, 0xfb, 0x77, 0x2f, 0x41, 0x8b,
+ 0x17, 0xf6, 0xb4, 0xe5, 0x2e, 0x2c, 0x54, 0x91, 0x5b, 0xf3, 0xce, 0x21,
+ 0xd6, 0x93, 0xd6, 0x3c, 0x30, 0x5c, 0x87, 0xd0, 0xc4, 0xbb, 0xdc, 0x58,
+ 0xbf, 0xfe, 0x9e, 0x26, 0x94, 0x78, 0x3c, 0xd3, 0xb8, 0xd6, 0x2f, 0xf4,
+ 0xb6, 0x8d, 0xb7, 0xc0, 0xd6, 0x2b, 0x11, 0x14, 0xea, 0x57, 0xec, 0x9b,
+ 0xed, 0xe5, 0x8b, 0xff, 0xf1, 0x39, 0xb3, 0x46, 0x7a, 0x0f, 0x1f, 0x80,
+ 0x2c, 0x5f, 0xff, 0xbc, 0x50, 0x11, 0xb5, 0x9d, 0xcb, 0xd8, 0x5d, 0x2c,
+ 0x5f, 0xff, 0xc3, 0xfb, 0x6c, 0x41, 0xf9, 0xb8, 0x59, 0xbd, 0xbe, 0x25,
+ 0x8a, 0xc4, 0xc4, 0x19, 0x54, 0x4b, 0x14, 0x49, 0xb4, 0x72, 0x33, 0x9b,
+ 0xec, 0xcf, 0xf1, 0x62, 0xa1, 0x7a, 0xb3, 0x23, 0xc3, 0xec, 0xfd, 0xe3,
+ 0xed, 0x0b, 0xa3, 0x94, 0x28, 0xbd, 0x1c, 0x48, 0x42, 0x9b, 0xc6, 0x18,
+ 0x62, 0x45, 0xfb, 0x0d, 0x21, 0x71, 0x23, 0x64, 0xd0, 0xde, 0x3b, 0xf9,
+ 0x62, 0xfb, 0x64, 0xc3, 0x0c, 0x58, 0xbb, 0x00, 0xb1, 0x58, 0x78, 0x3e,
+ 0x2a, 0xbd, 0x00, 0xe2, 0xc5, 0x42, 0x36, 0x0e, 0x79, 0xe5, 0xe0, 0xc8,
+ 0x6f, 0xb5, 0x07, 0x02, 0xc5, 0xff, 0xf3, 0x49, 0xf8, 0x73, 0xbc, 0x9c,
+ 0xdf, 0xb2, 0xc5, 0xf8, 0xef, 0xe1, 0x42, 0xc5, 0xff, 0xec, 0xde, 0xdf,
+ 0x17, 0xdb, 0x85, 0x87, 0x58, 0xa8, 0x3f, 0x32, 0x28, 0xbe, 0x6d, 0x03,
+ 0x8b, 0x17, 0xfe, 0x10, 0x5f, 0x37, 0x0b, 0x0c, 0x70, 0x2c, 0x5f, 0xfa,
+ 0x01, 0x12, 0x8d, 0x6b, 0x0c, 0x58, 0xbf, 0xfe, 0x8e, 0x0f, 0xec, 0x67,
+ 0xce, 0x2f, 0x0a, 0x16, 0x2f, 0xf1, 0x61, 0xbb, 0x5b, 0x7b, 0x2c, 0x54,
+ 0xe8, 0xc8, 0xe8, 0xff, 0xca, 0x55, 0x09, 0xa0, 0x34, 0x61, 0xd7, 0xc5,
+ 0x9d, 0xf9, 0x62, 0xff, 0xfe, 0xf7, 0x18, 0xbb, 0x97, 0xe1, 0x87, 0x1f,
+ 0x89, 0x2c, 0x5f, 0xed, 0x40, 0xbc, 0x4d, 0xbd, 0x62, 0x99, 0x12, 0x1c,
+ 0x5b, 0xbf, 0xf1, 0x67, 0x3a, 0xfb, 0x75, 0x04, 0xb1, 0x7f, 0xff, 0x8d,
+ 0x31, 0xf4, 0x6e, 0xcf, 0x32, 0x44, 0x27, 0xe6, 0x12, 0xc5, 0xff, 0xef,
+ 0x7d, 0x9c, 0x18, 0x5e, 0xfe, 0x49, 0x62, 0xff, 0xef, 0xb6, 0xbe, 0xfa,
+ 0xce, 0x9f, 0xcb, 0x17, 0xff, 0xf7, 0xd8, 0xf1, 0x85, 0xee, 0x41, 0xe2,
+ 0x68, 0xfa, 0xc5, 0xff, 0xef, 0xb7, 0x22, 0x52, 0x61, 0x93, 0xfd, 0x62,
+ 0xf8, 0xe7, 0x79, 0x6d, 0x4c, 0xc7, 0x12, 0x7a, 0x45, 0x75, 0xaa, 0x85,
+ 0x49, 0xd8, 0x44, 0xc7, 0xe2, 0x8e, 0x5e, 0xfe, 0xd0, 0xba, 0xfb, 0x71,
+ 0x62, 0xf8, 0xc7, 0x29, 0x2c, 0x5f, 0xf7, 0xa3, 0xb0, 0x3f, 0xfe, 0xcb,
+ 0x16, 0xfa, 0xc5, 0xef, 0xe0, 0x45, 0x8a, 0xc3, 0xeb, 0xe8, 0xea, 0x61,
+ 0x2b, 0xda, 0x7e, 0x96, 0x2f, 0xe9, 0xdb, 0xaf, 0xc7, 0x96, 0x2f, 0xa2,
+ 0x72, 0x12, 0xc5, 0x68, 0xf4, 0xfe, 0x61, 0x7d, 0xc6, 0x3c, 0x2c, 0x5f,
+ 0xfa, 0x30, 0xa7, 0xc2, 0x7e, 0xf8, 0xb1, 0x7e, 0x2c, 0xf4, 0x69, 0x62,
+ 0xf1, 0x86, 0x18, 0x91, 0x7e, 0x73, 0x7e, 0xde, 0x48, 0xd9, 0x34, 0x35,
+ 0x08, 0x84, 0x64, 0x8b, 0xe3, 0xf2, 0x3c, 0xb1, 0x7b, 0x7c, 0x1d, 0x62,
+ 0xf7, 0x98, 0xc5, 0x8b, 0xdc, 0x7d, 0x2c, 0x57, 0x66, 0xef, 0xc3, 0xd7,
+ 0x40, 0xd6, 0x2f, 0xf6, 0xb5, 0x13, 0x8f, 0x09, 0x62, 0xbe, 0x79, 0x6e,
+ 0x2f, 0x50, 0x98, 0x5e, 0x11, 0xb2, 0xd3, 0xb6, 0xdf, 0x03, 0x32, 0x65,
+ 0x8b, 0xee, 0x61, 0x79, 0x62, 0xb0, 0xf1, 0x5c, 0x8e, 0xfc, 0x1f, 0x1b,
+ 0xe2, 0x58, 0xbb, 0xe6, 0xac, 0x5b, 0x9b, 0x55, 0xda, 0x8c, 0xc3, 0x1c,
+ 0x7b, 0x22, 0x98, 0x8b, 0x50, 0xc2, 0xfc, 0x65, 0x84, 0xff, 0xc2, 0x0d,
+ 0xe5, 0x57, 0xb7, 0x33, 0xb5, 0x8b, 0x48, 0x6b, 0xa0, 0xd9, 0x38, 0x86,
+ 0xd0, 0xa2, 0xad, 0x89, 0x75, 0xe8, 0x53, 0xa6, 0xd7, 0xf4, 0x1e, 0x3f,
+ 0x00, 0x58, 0xbd, 0x13, 0x89, 0x62, 0xc1, 0x7c, 0x3c, 0xbf, 0x96, 0xdf,
+ 0xfc, 0xde, 0x8d, 0x61, 0x79, 0xdc, 0x96, 0x2a, 0x4c, 0xb5, 0x29, 0x88,
+ 0x35, 0x1b, 0x19, 0xca, 0x3f, 0x2c, 0x04, 0xa7, 0x6f, 0x04, 0xfd, 0xbc,
+ 0xae, 0xff, 0xe8, 0xc2, 0xc1, 0xbc, 0x8a, 0x27, 0x58, 0xbe, 0xeb, 0x51,
+ 0x25, 0x8b, 0xf7, 0xe3, 0xac, 0x25, 0x8b, 0x42, 0xc5, 0x00, 0xdc, 0xef,
+ 0x28, 0xbf, 0xf3, 0x6b, 0xaf, 0xb7, 0x5f, 0x62, 0x58, 0xbf, 0xff, 0xfc,
+ 0xe4, 0x0f, 0x7f, 0x0f, 0xee, 0x66, 0xff, 0xb7, 0x5f, 0x60, 0xc5, 0x3a,
+ 0xc5, 0x4e, 0x8b, 0xd0, 0x20, 0x54, 0x26, 0x09, 0x90, 0xe0, 0xbf, 0xec,
+ 0xdd, 0x83, 0xf7, 0x2c, 0xf2, 0xc5, 0x43, 0x3b, 0x2f, 0x08, 0xda, 0x98,
+ 0x2b, 0xa8, 0x46, 0x3a, 0x11, 0x46, 0xc3, 0xc2, 0x7b, 0xec, 0xe7, 0x99,
+ 0x62, 0xfe, 0xce, 0x73, 0x35, 0x3a, 0xc5, 0xba, 0x91, 0xe8, 0x8c, 0x8a,
+ 0xf1, 0x46, 0xf5, 0x8b, 0xff, 0xb5, 0x1d, 0x7c, 0x9f, 0xc5, 0x06, 0x2c,
+ 0x5c, 0x17, 0x65, 0x8a, 0x58, 0xb7, 0xd6, 0x2a, 0x45, 0xf3, 0x06, 0x5f,
+ 0xc0, 0xd6, 0x9a, 0x6e, 0x2c, 0x54, 0xe8, 0x88, 0xd1, 0xc9, 0x0f, 0xd4,
+ 0x23, 0xf5, 0xe1, 0x9b, 0x7a, 0x67, 0x9d, 0x62, 0xf7, 0x05, 0xba, 0xb1,
+ 0x58, 0x78, 0x1e, 0x1f, 0xbe, 0x14, 0xe2, 0x9d, 0x62, 0xfd, 0x22, 0x68,
+ 0xed, 0x62, 0xd1, 0xa3, 0xce, 0x22, 0x6a, 0x87, 0xc2, 0xc3, 0x9e, 0x33,
+ 0x19, 0x4a, 0xcc, 0x1c, 0xae, 0x5c, 0x9e, 0x1e, 0x36, 0x5e, 0x27, 0x52,
+ 0xa7, 0xbb, 0x96, 0x56, 0xc7, 0xb3, 0x4a, 0x27, 0xd4, 0xe7, 0x81, 0xe1,
+ 0xff, 0xf9, 0xd4, 0x07, 0x8f, 0x64, 0x11, 0xd1, 0x14, 0xfc, 0x97, 0x23,
+ 0x87, 0xf5, 0x3c, 0x20, 0x50, 0xc8, 0xde, 0x53, 0xb9, 0x18, 0xd8, 0x6c,
+ 0xc1, 0x1b, 0xef, 0xcd, 0x34, 0x98, 0x96, 0x2e, 0x0a, 0x32, 0xc5, 0xed,
+ 0x37, 0x4b, 0x17, 0xcc, 0x37, 0x31, 0x62, 0xba, 0x3c, 0x1f, 0x8f, 0x5f,
+ 0xf4, 0xde, 0x09, 0xc8, 0x98, 0x5a, 0x58, 0xbf, 0xc3, 0x82, 0x3c, 0x0e,
+ 0x16, 0x2a, 0x0f, 0xc5, 0xcf, 0xef, 0xfb, 0xf1, 0x3e, 0xa2, 0x4f, 0xa5,
+ 0x8b, 0xff, 0xdf, 0x8f, 0x96, 0x1a, 0x3c, 0x28, 0xdd, 0x58, 0xbf, 0x11,
+ 0xa1, 0xc0, 0x16, 0x2f, 0xf8, 0x1a, 0x81, 0x78, 0x9b, 0x7a, 0xc5, 0xff,
+ 0x3f, 0x7e, 0xfc, 0x75, 0x93, 0x2c, 0x56, 0x1f, 0xb9, 0x1d, 0xdf, 0x98,
+ 0x7f, 0x63, 0x56, 0x2f, 0x06, 0xe4, 0xb1, 0x43, 0x4d, 0x4f, 0x13, 0x0a,
+ 0x14, 0x3e, 0x20, 0x08, 0x53, 0x7e, 0x82, 0x63, 0xe2, 0xc5, 0xf1, 0x9e,
+ 0xcd, 0xd5, 0x8a, 0x9c, 0xf3, 0x7b, 0x26, 0xbf, 0xff, 0x13, 0x99, 0xa6,
+ 0x8f, 0x87, 0xe6, 0xfc, 0x6f, 0x58, 0xbf, 0xf3, 0x7e, 0x07, 0xf1, 0x47,
+ 0x7c, 0x58, 0xbc, 0x45, 0x8b, 0x15, 0x87, 0xb6, 0xe8, 0x17, 0x86, 0x68,
+ 0x16, 0x2f, 0xb5, 0xa7, 0xf2, 0xc5, 0xfb, 0x71, 0xb5, 0x86, 0xac, 0x51,
+ 0xcf, 0x3f, 0x84, 0x77, 0xb6, 0x84, 0xe9, 0x62, 0xec, 0xf2, 0xc5, 0x4e,
+ 0x6e, 0xbe, 0x47, 0x7f, 0xe3, 0x8e, 0x0b, 0x37, 0x96, 0x71, 0x62, 0xf7,
+ 0xc8, 0xeb, 0x15, 0xb5, 0x34, 0x88, 0x6e, 0xc5, 0xc6, 0x22, 0x73, 0xfb,
+ 0xff, 0xa6, 0x7e, 0xbf, 0x12, 0xf1, 0x61, 0xd6, 0x2f, 0xed, 0x61, 0x13,
+ 0xce, 0xb1, 0x7f, 0xe0, 0xe0, 0xf9, 0xa3, 0xb9, 0x1a, 0xb1, 0x5d, 0x22,
+ 0xcd, 0x91, 0xbc, 0x5b, 0x7f, 0xe3, 0x3b, 0x97, 0x36, 0xe7, 0xf0, 0x96,
+ 0x2f, 0xfa, 0x3b, 0xe6, 0x9b, 0x7e, 0x0d, 0x62, 0xff, 0xf8, 0xb3, 0x9e,
+ 0x36, 0x0a, 0x59, 0xf6, 0x3a, 0xc5, 0x4c, 0x88, 0xbd, 0xe7, 0x95, 0x08,
+ 0xf4, 0xc8, 0x67, 0x5f, 0xd9, 0x39, 0xa6, 0x88, 0x96, 0x2f, 0xff, 0x1f,
+ 0xb9, 0x73, 0x6e, 0x11, 0x63, 0x01, 0x62, 0xfe, 0x7d, 0x0a, 0x3b, 0x92,
+ 0xc5, 0x42, 0x2b, 0x18, 0xc5, 0xd3, 0x2f, 0xfe, 0x81, 0x9f, 0x3a, 0x8e,
+ 0x7f, 0x0e, 0xb1, 0x7e, 0x7c, 0x1b, 0x6f, 0x58, 0xbc, 0xd8, 0x62, 0xc5,
+ 0x69, 0x11, 0x67, 0x45, 0x0c, 0xa6, 0xf3, 0x7c, 0x4b, 0x17, 0xde, 0x6f,
+ 0x89, 0x62, 0xfe, 0xcd, 0x77, 0x2f, 0x42, 0xc5, 0xb7, 0x42, 0xd1, 0xe9,
+ 0x06, 0x47, 0x7e, 0x33, 0x3a, 0x80, 0x2c, 0x5f, 0x75, 0xfc, 0xd2, 0xc5,
+ 0x42, 0x20, 0x18, 0xc8, 0x21, 0x55, 0x6d, 0x65, 0x4d, 0xec, 0x65, 0x10,
+ 0xb9, 0x28, 0x4a, 0x0c, 0x83, 0x23, 0x8d, 0x68, 0x4e, 0xcc, 0x49, 0xa8,
+ 0x59, 0xfe, 0x36, 0x87, 0x87, 0xe1, 0x46, 0x49, 0xe8, 0x69, 0x0a, 0x17,
+ 0x1b, 0xcc, 0x42, 0x43, 0xbe, 0xdb, 0x3b, 0x1c, 0xec, 0x66, 0x18, 0x52,
+ 0x5e, 0x60, 0x56, 0x59, 0x0e, 0xc1, 0x2c, 0x9b, 0x62, 0x94, 0x89, 0xb0,
+ 0xa5, 0x5d, 0xec, 0x39, 0x4c, 0x41, 0x6a, 0x39, 0xb0, 0xb2, 0x3f, 0x40,
+ 0xb7, 0x8c, 0x4a, 0x2f, 0x0f, 0x2e, 0x7a, 0xc2, 0xea, 0x55, 0xef, 0x78,
+ 0xed, 0xae, 0x0e, 0x62, 0xdd, 0xd8, 0xda, 0x5b, 0x37, 0x56, 0xc4, 0xbb,
+ 0xbb, 0x41, 0x58, 0xd6, 0x96, 0x9b, 0x76, 0x5a, 0x0c, 0xd6, 0xb5, 0x4f,
+ 0x56, 0xeb, 0xf8, 0xf6, 0x8c, 0x13, 0xf7, 0xb7, 0xb8, 0xf7, 0x9d, 0xf6,
+ 0x0b, 0x47, 0xa8, 0x17, 0x95, 0x5a, 0x57, 0xb1, 0x63, 0xcc, 0x6a, 0x52,
+ 0x7a, 0xfb, 0x7e, 0x05, 0x4f, 0xad, 0xdf, 0x49, 0x0e, 0x32, 0x97, 0x83,
+ 0xb9, 0x5c, 0x71, 0x07, 0x79, 0xc2, 0x41, 0x29, 0x8b, 0x35, 0xb3, 0x3b,
+ 0x25, 0x3b, 0x2d, 0xd8, 0xf1, 0x8b, 0xc7, 0xcf, 0x2c, 0x5f, 0xe7, 0x3c,
+ 0x79, 0xb8, 0xcb, 0x17, 0xec, 0xd0, 0x7e, 0xe2, 0xc5, 0xdf, 0x85, 0x8b,
+ 0x6c, 0x81, 0x12, 0x04, 0x3b, 0xc3, 0x20, 0xca, 0xaf, 0xba, 0x28, 0xc5,
+ 0x8b, 0xf6, 0xba, 0x77, 0xe9, 0x51, 0x71, 0x97, 0xf4, 0x9c, 0xa4, 0xc7,
+ 0x58, 0xb6, 0xcc, 0x22, 0x1b, 0x08, 0x9c, 0xde, 0xff, 0x6c, 0xe6, 0xba,
+ 0x77, 0xe9, 0x51, 0x75, 0x97, 0xff, 0x6c, 0xbc, 0xb6, 0x73, 0x5d, 0x3b,
+ 0xf4, 0xa8, 0x94, 0x4a, 0x89, 0xd9, 0xfa, 0xa9, 0xce, 0x65, 0x0f, 0x61,
+ 0x9c, 0x1b, 0x18, 0xc7, 0x47, 0x2d, 0x3c, 0x69, 0xbb, 0x1a, 0x8b, 0xee,
+ 0xc9, 0x7e, 0x02, 0x1a, 0x3c, 0x86, 0x67, 0x8d, 0x82, 0x22, 0xdf, 0xfe,
+ 0xd9, 0x3b, 0xcb, 0x67, 0x35, 0xd3, 0xbf, 0x4a, 0x89, 0x68, 0xbf, 0xf0,
+ 0x54, 0x2b, 0xad, 0x3c, 0x4b, 0xc1, 0x16, 0x2f, 0xf8, 0x2d, 0xfe, 0xdb,
+ 0xaf, 0x1d, 0x84, 0x58, 0xbf, 0xfe, 0x33, 0xa0, 0xa0, 0x54, 0x01, 0x7d,
+ 0x6c, 0x1b, 0x76, 0xff, 0x71, 0x62, 0xff, 0xff, 0xc1, 0x3d, 0xb1, 0x0c,
+ 0xfb, 0x11, 0x30, 0x5a, 0xf0, 0x5f, 0x5b, 0x06, 0xdd, 0xbf, 0xdc, 0x58,
+ 0xaf, 0xa6, 0x00, 0x63, 0x75, 0xf8, 0x2f, 0x2d, 0x88, 0x39, 0xd6, 0x2f,
+ 0x6e, 0x9d, 0x96, 0x2f, 0xfb, 0x08, 0x7f, 0x8d, 0x39, 0x2c, 0x54, 0x1e,
+ 0xbe, 0x10, 0x5e, 0x77, 0xe9, 0x51, 0x1b, 0x97, 0xee, 0xe6, 0x28, 0x1a,
+ 0xc5, 0x74, 0x7a, 0x8e, 0x55, 0x7e, 0x1f, 0xe3, 0x34, 0xb1, 0x5a, 0x3c,
+ 0xa2, 0x22, 0xbf, 0xda, 0x60, 0xbf, 0x5f, 0x83, 0x16, 0x2f, 0x0b, 0x70,
+ 0xc5, 0x8b, 0xed, 0x0a, 0x00, 0xb1, 0x4c, 0x7f, 0xf3, 0x1d, 0x06, 0x45,
+ 0x7f, 0xff, 0xfd, 0xbc, 0xb3, 0x9c, 0x1c, 0x66, 0xba, 0x77, 0xeb, 0x66,
+ 0x4d, 0xe8, 0xf7, 0x15, 0x18, 0x79, 0x50, 0x8c, 0x06, 0x30, 0xbf, 0x9f,
+ 0x67, 0x75, 0xc8, 0x0b, 0x15, 0xf3, 0xd4, 0x22, 0x1b, 0xfb, 0x9b, 0x26,
+ 0x73, 0x74, 0x35, 0x8b, 0xf3, 0x4f, 0xf6, 0xdc, 0x58, 0xbf, 0x67, 0x1f,
+ 0x52, 0x58, 0xad, 0xd3, 0xd4, 0xd1, 0x65, 0xf8, 0x26, 0xce, 0x82, 0xe6,
+ 0x2c, 0x5f, 0x0c, 0xb0, 0x0b, 0x17, 0xd0, 0x61, 0xc6, 0xb1, 0x7d, 0xd7,
+ 0xe0, 0xc5, 0x8b, 0xdf, 0x83, 0x56, 0x2b, 0x11, 0x13, 0xa2, 0x20, 0xb9,
+ 0x20, 0x64, 0xb7, 0xed, 0x74, 0xef, 0xd2, 0xa2, 0x5f, 0x2f, 0xe1, 0x75,
+ 0xa6, 0x82, 0x58, 0xbc, 0xf2, 0xd9, 0xc3, 0xe5, 0xf9, 0xbd, 0xb1, 0x62,
+ 0xf7, 0xdf, 0xcb, 0x16, 0xf7, 0x0d, 0x70, 0x62, 0x37, 0xc2, 0x0b, 0xef,
+ 0x85, 0x8b, 0xf3, 0x41, 0x82, 0xdd, 0x58, 0xac, 0x3d, 0x52, 0x29, 0xbf,
+ 0x83, 0x6e, 0xc2, 0x68, 0xc5, 0x8b, 0xfe, 0x6d, 0x69, 0xbc, 0x0c, 0xe2,
+ 0xc5, 0x42, 0x61, 0x58, 0xfa, 0xc4, 0x0e, 0x69, 0x7f, 0x43, 0x6e, 0xe7,
+ 0x72, 0x58, 0xbf, 0x68, 0xdf, 0x8b, 0x8b, 0x15, 0xf3, 0xdc, 0x0c, 0xc6,
+ 0xf4, 0x6a, 0x16, 0x2b, 0x0d, 0xfb, 0x11, 0xdc, 0xff, 0x58, 0xbe, 0x00,
+ 0xf9, 0x0b, 0x17, 0xcf, 0xa9, 0xe7, 0x58, 0xb6, 0x11, 0xe4, 0x6f, 0x23,
+ 0xa9, 0x22, 0x1f, 0x8b, 0xf7, 0xfb, 0xfb, 0x3d, 0x7d, 0xbe, 0x11, 0x62,
+ 0xf0, 0x20, 0xc5, 0x8b, 0xfd, 0x8d, 0xa9, 0x7d, 0x8c, 0x58, 0xac, 0x44,
+ 0x6e, 0xe9, 0xdf, 0xc7, 0xae, 0x60, 0xd6, 0x2f, 0x4e, 0x1c, 0x96, 0x2c,
+ 0x12, 0x63, 0x70, 0xe3, 0x17, 0xc2, 0xfb, 0x69, 0x62, 0xfb, 0x9f, 0x8f,
+ 0xac, 0x5f, 0xe8, 0x9e, 0x0a, 0x7c, 0x08, 0xb1, 0x77, 0x34, 0xb1, 0x50,
+ 0x7e, 0x33, 0x91, 0xcc, 0x6d, 0x6d, 0x90, 0xab, 0x2f, 0x5c, 0x2d, 0x25,
+ 0x44, 0x68, 0xd3, 0x92, 0x8e, 0x11, 0x99, 0x0b, 0xee, 0xa3, 0xb4, 0xec,
+ 0x85, 0xa1, 0x19, 0xba, 0x4b, 0xa8, 0x5e, 0x9e, 0x14, 0xdf, 0x8d, 0xb4,
+ 0xa1, 0xab, 0xc8, 0x53, 0x7a, 0x16, 0x02, 0x6a, 0xdc, 0x29, 0x0e, 0x12,
+ 0x97, 0xfb, 0xad, 0x9d, 0x88, 0x29, 0xb0, 0x05, 0x19, 0x62, 0xff, 0xfc,
+ 0x51, 0xd6, 0xcf, 0xbb, 0xe9, 0xb8, 0x59, 0xbd, 0xd6, 0x2f, 0xfe, 0x97,
+ 0x9a, 0x6d, 0x91, 0xb6, 0xf8, 0x1a, 0xc5, 0xf8, 0xcd, 0x96, 0x36, 0x75,
+ 0x8a, 0x1a, 0x35, 0xbb, 0x5c, 0x64, 0xbb, 0xff, 0xf9, 0xb9, 0x83, 0xd9,
+ 0xe0, 0xf5, 0x1f, 0x71, 0xc8, 0xeb, 0x17, 0xed, 0x74, 0xef, 0xd2, 0xa2,
+ 0xab, 0x2f, 0xd9, 0xcf, 0xc7, 0x6b, 0x16, 0xd9, 0xc3, 0xe0, 0xf9, 0xbd,
+ 0xf8, 0x2a, 0x3d, 0x3f, 0x4b, 0x17, 0xc2, 0x08, 0x38, 0x58, 0xb6, 0xc6,
+ 0xb1, 0x5f, 0x37, 0x9b, 0x84, 0xb7, 0x30, 0x45, 0x8b, 0xb3, 0x4b, 0x17,
+ 0xb3, 0xbf, 0x2c, 0x5f, 0x31, 0xdf, 0x7a, 0xc5, 0x1a, 0x7e, 0x4e, 0x32,
+ 0x01, 0x7f, 0x0f, 0x5e, 0x20, 0x86, 0x2c, 0x5f, 0xdf, 0x8d, 0xe2, 0x1e,
+ 0x2c, 0x5f, 0xcf, 0xf9, 0x8a, 0x06, 0xb1, 0x7f, 0xfd, 0xe0, 0x1c, 0x43,
+ 0xcc, 0xf0, 0x0e, 0x2e, 0xd6, 0x2f, 0xfe, 0xf7, 0xe3, 0x84, 0xe2, 0x0b,
+ 0xb6, 0x96, 0x2f, 0x44, 0xb1, 0x62, 0xfe, 0x8e, 0x6c, 0x58, 0xe7, 0x58,
+ 0xbf, 0x98, 0x5d, 0x14, 0x4c, 0xb1, 0x7b, 0x81, 0xba, 0xc5, 0x49, 0x39,
+ 0x41, 0x98, 0x61, 0x77, 0x6a, 0x73, 0x24, 0x68, 0x73, 0xe6, 0x5e, 0x2f,
+ 0xbf, 0xe3, 0x70, 0xb3, 0xbf, 0x39, 0xd6, 0x2c, 0x11, 0x62, 0xc6, 0x2c,
+ 0x57, 0x66, 0x9f, 0xc2, 0x97, 0x82, 0x47, 0x96, 0x2f, 0xe8, 0x38, 0x70,
+ 0x5d, 0x2c, 0x5d, 0x1a, 0x58, 0xad, 0x1e, 0x37, 0x0b, 0xef, 0x8e, 0x76,
+ 0x99, 0x62, 0xfb, 0xf0, 0x46, 0xac, 0x56, 0x1e, 0x3c, 0xc4, 0x97, 0x3f,
+ 0x6b, 0x17, 0xbb, 0xe4, 0xcb, 0x17, 0x37, 0x96, 0x2f, 0x07, 0x00, 0x58,
+ 0xb6, 0xea, 0xc5, 0x76, 0x88, 0x2d, 0x0c, 0x70, 0x83, 0xc2, 0xfb, 0x83,
+ 0xd7, 0xd3, 0x10, 0xba, 0x58, 0xbf, 0xb0, 0xf3, 0x3b, 0xce, 0xb1, 0x7e,
+ 0xe3, 0x7d, 0x8d, 0x58, 0xb9, 0xfb, 0x58, 0xa2, 0x3c, 0x1f, 0x14, 0xdf,
+ 0xff, 0x4b, 0xef, 0x23, 0x5f, 0x98, 0x2e, 0x71, 0x96, 0x29, 0x62, 0xb0,
+ 0xf7, 0x42, 0x28, 0xd4, 0x26, 0x6c, 0xc4, 0xae, 0xe0, 0x4f, 0xd7, 0x0d,
+ 0x96, 0x2f, 0xf8, 0xa2, 0x5e, 0x63, 0x8e, 0x16, 0x2f, 0xf1, 0x34, 0xa6,
+ 0xfc, 0x4e, 0xb1, 0x79, 0xdf, 0xa5, 0x44, 0x80, 0x5b, 0x52, 0x3d, 0xfe,
+ 0x8d, 0x6f, 0xb5, 0x85, 0xe5, 0x8b, 0xe1, 0xec, 0x7b, 0x0f, 0x60, 0x58,
+ 0xbf, 0xff, 0x7f, 0x0f, 0xe6, 0x11, 0x4b, 0x09, 0xa7, 0xe2, 0xc5, 0x0d,
+ 0x36, 0xbc, 0x84, 0xbe, 0x8a, 0x78, 0x45, 0xe3, 0x4b, 0xdb, 0xdf, 0xeb,
+ 0x15, 0xb5, 0x3f, 0x0d, 0x98, 0xe0, 0xa1, 0x3e, 0xfd, 0xc7, 0x27, 0xed,
+ 0x62, 0xff, 0xbc, 0xdc, 0x61, 0x05, 0xc7, 0x0b, 0x17, 0x61, 0x2c, 0x5c,
+ 0x28, 0x58, 0xa9, 0x23, 0x37, 0xb3, 0xb6, 0x28, 0xdd, 0x3d, 0xd0, 0xb5,
+ 0xfd, 0x1a, 0x9e, 0x35, 0x3a, 0xc5, 0xf3, 0x1e, 0x38, 0xb1, 0x52, 0x3d,
+ 0x23, 0x4c, 0x2f, 0xf6, 0xa7, 0x3c, 0x14, 0xb8, 0xb1, 0x50, 0x7b, 0x18,
+ 0x47, 0x7f, 0xfc, 0x76, 0x20, 0x07, 0xe6, 0x21, 0x4b, 0x38, 0xb1, 0x7f,
+ 0xf3, 0x41, 0xdc, 0x61, 0x84, 0x82, 0x92, 0xc5, 0xff, 0xff, 0x37, 0x8b,
+ 0x37, 0x96, 0x72, 0x7c, 0x33, 0x70, 0x5f, 0x6d, 0x2c, 0x56, 0x26, 0x05,
+ 0xf5, 0x00, 0x23, 0x5f, 0x80, 0xe0, 0x23, 0xac, 0x5c, 0xe3, 0x58, 0xbf,
+ 0xe9, 0x37, 0x81, 0x19, 0xdc, 0x96, 0x2a, 0x73, 0xd1, 0x98, 0x5e, 0xff,
+ 0xf7, 0x6e, 0x42, 0x06, 0xa3, 0xec, 0x47, 0x58, 0xbf, 0x9b, 0x7b, 0x7a,
+ 0x68, 0x58, 0xa8, 0x4c, 0x5f, 0x1e, 0x58, 0x93, 0x89, 0x57, 0xf0, 0x7b,
+ 0x16, 0x9a, 0x0e, 0xb1, 0x77, 0x24, 0xb1, 0x4e, 0x79, 0x9c, 0x34, 0xbf,
+ 0xff, 0xa3, 0xaf, 0x36, 0xb5, 0x80, 0xe7, 0x9f, 0xee, 0x35, 0x8b, 0x82,
+ 0xbf, 0x58, 0xbf, 0xfd, 0x93, 0x7d, 0xcf, 0xef, 0xc7, 0x84, 0x75, 0x8b,
+ 0xc1, 0x23, 0xcb, 0x15, 0xb1, 0x33, 0xaf, 0xa1, 0xaa, 0x78, 0x4b, 0x0c,
+ 0xf3, 0x23, 0xb4, 0x35, 0xcf, 0xb6, 0x1d, 0xd2, 0x29, 0x99, 0x74, 0xd2,
+ 0x78, 0x52, 0x7e, 0x38, 0x47, 0x95, 0xee, 0x50, 0xf7, 0xe4, 0x64, 0x5e,
+ 0x8d, 0x1c, 0x50, 0x87, 0xde, 0x43, 0xb8, 0xb8, 0x18, 0xe0, 0x44, 0xcb,
+ 0xff, 0x4a, 0x30, 0x1f, 0xcc, 0x2e, 0x96, 0x2f, 0xd0, 0x45, 0x9e, 0x58,
+ 0xbe, 0xd6, 0x9b, 0xa5, 0x8b, 0xe2, 0xc9, 0xf6, 0x71, 0x11, 0x1b, 0x87,
+ 0xc1, 0x93, 0x5f, 0x75, 0xf7, 0xe9, 0x62, 0xff, 0x07, 0xcc, 0xd7, 0x5f,
+ 0x85, 0x8b, 0xfe, 0xc9, 0xa4, 0xfa, 0x9f, 0xe2, 0x58, 0xbf, 0xc6, 0xb9,
+ 0x61, 0x8e, 0x05, 0x8b, 0xe3, 0x65, 0xfc, 0x58, 0xbc, 0x28, 0x0d, 0x62,
+ 0xff, 0x9a, 0x4d, 0xf1, 0x1c, 0xec, 0xb1, 0x52, 0x3d, 0x7f, 0x0f, 0x5b,
+ 0x64, 0x2c, 0x4d, 0xa2, 0x09, 0x46, 0x6c, 0x69, 0xe7, 0x0d, 0x03, 0x7b,
+ 0xbf, 0xdb, 0x3f, 0x73, 0xe4, 0x0d, 0x62, 0xb6, 0x57, 0x0e, 0xf5, 0x1f,
+ 0x49, 0x91, 0xda, 0xee, 0x33, 0xdf, 0xed, 0x9c, 0xd7, 0x4e, 0xfd, 0x2a,
+ 0x2c, 0x82, 0xff, 0xff, 0x7d, 0xf5, 0xb3, 0xf7, 0xf1, 0x0a, 0x7e, 0x61,
+ 0xe3, 0x75, 0x62, 0xfe, 0x6d, 0xfb, 0x3c, 0x8e, 0xd6, 0x2f, 0xff, 0xf0,
+ 0x87, 0x9b, 0x21, 0xe7, 0xc8, 0x4f, 0xbb, 0x86, 0xc7, 0x16, 0x2f, 0xff,
+ 0xdd, 0x37, 0x30, 0x78, 0x50, 0x67, 0x8d, 0x7e, 0x2c, 0x5f, 0xf7, 0xd9,
+ 0xc1, 0x82, 0xd4, 0xeb, 0x17, 0xef, 0x89, 0xcd, 0xd9, 0xfa, 0x24, 0x7c,
+ 0xaf, 0x68, 0x92, 0x67, 0xa3, 0x87, 0xcd, 0x71, 0x39, 0xff, 0x46, 0xe3,
+ 0x43, 0x54, 0x62, 0xd2, 0x81, 0xef, 0xf6, 0xce, 0x6b, 0xa7, 0x7e, 0x95,
+ 0x16, 0xb9, 0x7e, 0x9b, 0xc3, 0x82, 0x58, 0xbf, 0xc5, 0x93, 0xeb, 0x4c,
+ 0x62, 0xc5, 0xf7, 0xda, 0x26, 0x58, 0xbf, 0x60, 0x71, 0x3e, 0xce, 0x22,
+ 0x07, 0xa2, 0x90, 0x86, 0xb7, 0xfb, 0x67, 0x35, 0xd3, 0xbf, 0x4a, 0x8b,
+ 0x90, 0xbf, 0x6b, 0xa7, 0x7e, 0x95, 0x17, 0x61, 0x7d, 0xb9, 0x1e, 0xc5,
+ 0x8b, 0xff, 0x3c, 0xb6, 0x73, 0x5d, 0x3b, 0xf4, 0xa8, 0xa3, 0x8b, 0x6c,
+ 0xe2, 0x2b, 0x18, 0xdc, 0xe4, 0xb7, 0xfc, 0xed, 0xcf, 0xe4, 0xb9, 0x0b,
+ 0x17, 0xfd, 0x9d, 0x0a, 0x0b, 0xb9, 0x71, 0x62, 0xfe, 0xd6, 0xa3, 0xaf,
+ 0xb2, 0xc5, 0xc5, 0xb3, 0xf4, 0x51, 0x11, 0xc7, 0x0e, 0xef, 0x8a, 0x24,
+ 0x75, 0x8b, 0xf4, 0x98, 0x80, 0xcb, 0x17, 0xfe, 0xd8, 0x82, 0xa7, 0x8d,
+ 0x4b, 0x1b, 0x7a, 0xc5, 0xa4, 0xb1, 0x7e, 0xd7, 0x4e, 0xfd, 0x2a, 0x29,
+ 0x52, 0xff, 0xba, 0xfb, 0x4d, 0xf8, 0x9f, 0x16, 0x2f, 0xff, 0x7e, 0x27,
+ 0x8f, 0xb6, 0xf7, 0x1f, 0xd9, 0x63, 0x64, 0xde, 0x5d, 0x2d, 0x9c, 0x46,
+ 0x94, 0xce, 0x75, 0xda, 0x62, 0xcf, 0x0e, 0x4b, 0xff, 0x3b, 0x7a, 0x42,
+ 0x1b, 0x90, 0x16, 0x2e, 0xf8, 0x96, 0x2f, 0xfe, 0xe3, 0xf6, 0x78, 0xff,
+ 0xb1, 0xb7, 0xac, 0x5b, 0x64, 0x6a, 0x9b, 0xf0, 0x8b, 0xb2, 0x73, 0xc6,
+ 0xc1, 0xf2, 0x9e, 0x1f, 0x78, 0x62, 0xff, 0xff, 0xe7, 0xf6, 0x02, 0x25,
+ 0xb2, 0x19, 0xf0, 0x71, 0x28, 0x1b, 0xb9, 0xab, 0x15, 0x3b, 0xac, 0x32,
+ 0x95, 0x30, 0xd8, 0x71, 0xae, 0x64, 0x64, 0x3d, 0x18, 0x77, 0x0b, 0xf6,
+ 0xac, 0xc8, 0xce, 0xa6, 0xf2, 0x9d, 0x80, 0x56, 0x50, 0xc6, 0xe2, 0x9f,
+ 0xa1, 0xe2, 0x28, 0x6c, 0xef, 0x95, 0x58, 0x63, 0xad, 0xff, 0x4b, 0x67,
+ 0x35, 0xd3, 0xbf, 0x4a, 0x88, 0xe0, 0xbf, 0xe6, 0xd9, 0xcd, 0x74, 0xef,
+ 0xd2, 0xa2, 0xb5, 0x2d, 0xb2, 0xe8, 0x95, 0xf2, 0x5d, 0xff, 0xed, 0x93,
+ 0xbc, 0xb6, 0x73, 0x5d, 0x3b, 0xf4, 0xa8, 0x96, 0xcb, 0xb6, 0x2d, 0x84,
+ 0xb1, 0x7b, 0x63, 0xd8, 0xf8, 0xb1, 0x6e, 0x96, 0x2f, 0x0b, 0x40, 0x58,
+ 0xbb, 0x3b, 0x58, 0xbf, 0x1c, 0xf0, 0xdc, 0x58, 0xbf, 0xa3, 0x40, 0x7e,
+ 0xf8, 0xb1, 0x61, 0xe1, 0xeb, 0xfc, 0xa2, 0xfd, 0xe8, 0xf8, 0x7c, 0x58,
+ 0xbd, 0xbc, 0x52, 0x58, 0xa0, 0xaa, 0x62, 0x3d, 0x09, 0xf6, 0x3c, 0xcd,
+ 0xe4, 0x4f, 0xbc, 0xaa, 0xff, 0x8c, 0x9a, 0x4f, 0xa9, 0xfe, 0x25, 0x8b,
+ 0x87, 0x25, 0x8b, 0xff, 0xec, 0x33, 0x27, 0xf7, 0xb0, 0xc7, 0xf3, 0x9a,
+ 0xb1, 0x7f, 0xda, 0x94, 0x1f, 0x3e, 0xd2, 0x58, 0xac, 0x47, 0x17, 0xcf,
+ 0x88, 0x60, 0x4a, 0x76, 0x85, 0x8b, 0xe0, 0x83, 0x8e, 0xd6, 0x28, 0x2d,
+ 0xcd, 0xbb, 0x08, 0xdf, 0xf6, 0x76, 0x58, 0x00, 0x3c, 0x96, 0x2e, 0x3f,
+ 0x4b, 0x17, 0xf3, 0x77, 0xc1, 0xe1, 0x2c, 0x5f, 0xdd, 0xe4, 0xa3, 0x40,
+ 0x58, 0xac, 0x3d, 0xd7, 0x2e, 0xbf, 0xfe, 0x82, 0x9f, 0x82, 0x76, 0x97,
+ 0x3e, 0xf2, 0x58, 0xa8, 0x4c, 0x7e, 0x47, 0x3a, 0x76, 0xf9, 0x05, 0xe7,
+ 0xf8, 0x6b, 0x17, 0xc5, 0x1d, 0xc9, 0x62, 0xe0, 0xe7, 0x58, 0xbf, 0xde,
+ 0xe0, 0xc4, 0xfa, 0x92, 0xc5, 0x1c, 0xf3, 0xc8, 0x6a, 0xf6, 0x9e, 0x65,
+ 0x8a, 0x63, 0x7e, 0x22, 0x1b, 0xee, 0x9f, 0x40, 0x58, 0xbf, 0x41, 0xf3,
+ 0xbf, 0x2c, 0x5a, 0x78, 0x3c, 0xd2, 0x24, 0xbf, 0xf6, 0xbe, 0xf8, 0x42,
+ 0x96, 0x71, 0x62, 0xff, 0xfb, 0xb0, 0x0f, 0xef, 0x2c, 0xe1, 0x09, 0xc3,
+ 0x58, 0xa6, 0x44, 0x83, 0x9f, 0x5f, 0x03, 0x35, 0x32, 0xc5, 0xfe, 0x7f,
+ 0x70, 0x3e, 0x46, 0x2c, 0x5f, 0x9b, 0xf0, 0x1c, 0xcb, 0x17, 0xbd, 0x07,
+ 0x58, 0xa1, 0xaa, 0xb3, 0xe8, 0x7a, 0x68, 0x58, 0xe9, 0xb7, 0xf0, 0xb7,
+ 0x01, 0x09, 0x12, 0x78, 0xd0, 0x21, 0x55, 0xff, 0xc6, 0xc1, 0x7b, 0x34,
+ 0xd3, 0xb9, 0xd6, 0x2f, 0x9e, 0x46, 0xb2, 0xc5, 0x2c, 0x7c, 0xd1, 0xdf,
+ 0xed, 0xb1, 0x9f, 0x61, 0x74, 0xb1, 0x46, 0x9e, 0x90, 0x07, 0x2f, 0x89,
+ 0xbd, 0xc5, 0x8b, 0xc4, 0xfd, 0xac, 0x59, 0xb4, 0x6f, 0xfe, 0x45, 0x7e,
+ 0xd3, 0x96, 0x42, 0xc5, 0x2a, 0x21, 0xb1, 0x91, 0x5d, 0xf6, 0x27, 0x26,
+ 0xba, 0x09, 0x62, 0xf6, 0x30, 0xd6, 0x2f, 0x0f, 0x0e, 0xb1, 0x73, 0x10,
+ 0xcd, 0xcb, 0x0e, 0x5f, 0xf8, 0xa3, 0x3a, 0xfb, 0x6f, 0x7d, 0x2c, 0x54,
+ 0x22, 0xe6, 0x49, 0xfe, 0x2a, 0xb8, 0x52, 0x58, 0xbc, 0x28, 0x3a, 0xc5,
+ 0xfd, 0x22, 0x8f, 0x7e, 0x16, 0x28, 0x07, 0xc5, 0xc1, 0x8f, 0x0e, 0xdf,
+ 0xbe, 0xda, 0x81, 0xac, 0x5f, 0xe1, 0x6e, 0xcd, 0xf1, 0x17, 0x96, 0x2f,
+ 0xfc, 0xf3, 0x86, 0x59, 0xc2, 0x17, 0xd6, 0x2b, 0xa4, 0x50, 0xfc, 0xa1,
+ 0xce, 0x6f, 0xf9, 0xa4, 0xfc, 0x3c, 0x67, 0x96, 0x2e, 0x96, 0x2c, 0x5f,
+ 0xe7, 0x6f, 0x4d, 0xf1, 0x1a, 0xb1, 0x53, 0x1e, 0x6f, 0xc5, 0xef, 0xf4,
+ 0x4f, 0x26, 0xea, 0x0e, 0xb1, 0x50, 0x8d, 0xdc, 0x84, 0x2e, 0x88, 0xee,
+ 0x79, 0x2c, 0x5f, 0xf4, 0xb6, 0x73, 0x5d, 0x3b, 0xf4, 0xa8, 0x98, 0x0a,
+ 0x83, 0xe2, 0x71, 0x7b, 0xdf, 0x6f, 0xac, 0x5f, 0x3f, 0x9b, 0xcb, 0x15,
+ 0xba, 0x6f, 0xc4, 0x3b, 0x70, 0x3b, 0x58, 0xb8, 0x2e, 0xcb, 0x17, 0x4a,
+ 0x4b, 0x17, 0xfa, 0x77, 0xf0, 0x03, 0x29, 0x2c, 0x5a, 0x16, 0x2e, 0x9d,
+ 0x96, 0x2f, 0xfa, 0x33, 0x93, 0x7d, 0x8c, 0xf2, 0xc5, 0x61, 0xf2, 0x10,
+ 0x8f, 0x06, 0x2e, 0xe4, 0x2c, 0x54, 0x26, 0x9d, 0x39, 0x24, 0x86, 0x7a,
+ 0x1b, 0x61, 0x87, 0x84, 0xd0, 0x8b, 0x6f, 0x18, 0xc0, 0x58, 0xbb, 0x73,
+ 0x16, 0x2f, 0xb8, 0xe4, 0x05, 0x8b, 0xc5, 0x13, 0xac, 0x54, 0xc7, 0xef,
+ 0xf1, 0xe0, 0x0d, 0x05, 0xc8, 0xaf, 0xee, 0xf5, 0x01, 0xb9, 0x2c, 0x5f,
+ 0xe8, 0xcd, 0x7b, 0xd9, 0xc5, 0x8a, 0x73, 0xe2, 0x01, 0x7d, 0xfe, 0x17,
+ 0x7a, 0x68, 0x3e, 0x2c, 0x5f, 0xbe, 0xd0, 0x53, 0xac, 0x5f, 0xf4, 0x4f,
+ 0xe2, 0x81, 0x7b, 0x8b, 0x15, 0xf4, 0x4b, 0x70, 0xd3, 0x70, 0xa2, 0xf8,
+ 0xb3, 0x90, 0xb1, 0x5e, 0x3d, 0x4d, 0xe6, 0x77, 0xa4, 0xc0, 0x58, 0xbf,
+ 0x11, 0x67, 0x99, 0x62, 0xe2, 0x85, 0x8b, 0xee, 0xfa, 0x63, 0x56, 0x2f,
+ 0xce, 0x6e, 0x7d, 0xd6, 0x2b, 0x11, 0x97, 0x31, 0x23, 0x8e, 0x80, 0x9b,
+ 0xc2, 0xc2, 0x26, 0xbf, 0xfb, 0x4f, 0xf0, 0xf0, 0xb2, 0x68, 0xdd, 0x58,
+ 0xbf, 0xfd, 0x2f, 0xe1, 0x18, 0x1e, 0xbe, 0xd0, 0x75, 0x8b, 0xf9, 0xbd,
+ 0x87, 0x8f, 0xac, 0x5f, 0xf3, 0x02, 0x7f, 0xc7, 0x05, 0xc5, 0x8b, 0xfd,
+ 0x27, 0xf7, 0x18, 0xa1, 0x62, 0xd1, 0xa3, 0xed, 0x23, 0xba, 0xed, 0x30,
+ 0xcd, 0x26, 0x7a, 0x13, 0x57, 0xff, 0x89, 0xcc, 0xce, 0xbf, 0x1d, 0xcb,
+ 0x73, 0x16, 0x2e, 0xdd, 0x75, 0x8b, 0xf9, 0xa6, 0xe7, 0x9a, 0x75, 0x8b,
+ 0xff, 0x61, 0xf3, 0x59, 0xdc, 0xb3, 0xcb, 0x17, 0xf3, 0x7d, 0x8f, 0x86,
+ 0xac, 0x57, 0xcf, 0xb7, 0x87, 0xf7, 0xfc, 0xff, 0xd4, 0x34, 0x9f, 0x8b,
+ 0x17, 0xff, 0x9e, 0x7f, 0xb4, 0x16, 0x4c, 0xda, 0x65, 0x8a, 0x1a, 0xb3,
+ 0x4c, 0x8d, 0x52, 0x63, 0x7d, 0x27, 0xfc, 0x6b, 0xd0, 0x9d, 0x11, 0x11,
+ 0x87, 0x16, 0x25, 0x8b, 0x6e, 0x2c, 0x5f, 0x74, 0xd8, 0x35, 0x8a, 0x58,
+ 0xb7, 0x4b, 0x18, 0x4c, 0xb8, 0x40, 0x48, 0xba, 0x43, 0x58, 0xad, 0x8d,
+ 0x14, 0xb3, 0x88, 0xf6, 0x2a, 0xc5, 0xfa, 0x20, 0x38, 0xc5, 0xf8, 0xd8,
+ 0x96, 0x0d, 0x62, 0xfb, 0x3d, 0xfc, 0x58, 0xb9, 0xcd, 0x58, 0xbb, 0x06,
+ 0x46, 0xeb, 0x70, 0x8a, 0xed, 0x8b, 0xa5, 0xc6, 0x14, 0x5d, 0xe0, 0x2c,
+ 0x5f, 0x0f, 0xf9, 0x3a, 0xc5, 0xc1, 0x24, 0xb1, 0x7e, 0x7c, 0xf6, 0x1d,
+ 0x62, 0xf6, 0x77, 0xe5, 0x8a, 0x9c, 0xf1, 0x4d, 0x27, 0xa9, 0xd1, 0x7e,
+ 0xc3, 0x1a, 0x24, 0x75, 0xfb, 0xf0, 0x7b, 0x8e, 0x40, 0x58, 0xbf, 0xb3,
+ 0xee, 0x19, 0x79, 0x62, 0xa7, 0x3d, 0xa1, 0x96, 0x5e, 0x77, 0xe9, 0x62,
+ 0xff, 0x4d, 0x9a, 0x69, 0xdc, 0xeb, 0x17, 0xf6, 0x7b, 0xd1, 0xae, 0x2c,
+ 0x5f, 0xce, 0x40, 0x9c, 0x1e, 0x58, 0xbf, 0x07, 0xee, 0x47, 0x96, 0x2a,
+ 0x11, 0xf9, 0x39, 0x1e, 0x0e, 0x91, 0xae, 0xe1, 0x70, 0x65, 0xf6, 0xd9,
+ 0xd8, 0xdb, 0xaa, 0xf0, 0xb4, 0x47, 0x11, 0x9c, 0xcf, 0x1a, 0x04, 0x9c,
+ 0x87, 0x1a, 0x36, 0x4a, 0xf0, 0x36, 0x11, 0xbd, 0x46, 0xd1, 0xdc, 0x3f,
+ 0x1a, 0x12, 0x33, 0x43, 0x43, 0x51, 0x86, 0x9e, 0x12, 0xbf, 0x8e, 0xb5,
+ 0xe1, 0xc0, 0x08, 0x51, 0x94, 0x7a, 0xdc, 0x97, 0x15, 0xe8, 0xc9, 0x04,
+ 0xbb, 0xbd, 0x8c, 0xc2, 0xed, 0xc8, 0x75, 0x07, 0x1c, 0x95, 0xe3, 0x8b,
+ 0x49, 0x17, 0xfe, 0x79, 0x6c, 0xe6, 0xba, 0x77, 0xe9, 0x51, 0x31, 0x97,
+ 0x40, 0x45, 0x8b, 0xb5, 0x8b, 0x16, 0x8d, 0x1b, 0x0f, 0x8c, 0xdf, 0xec,
+ 0x37, 0x9f, 0x82, 0xf2, 0xc5, 0xf7, 0xa5, 0x06, 0xac, 0x51, 0x1e, 0xc0,
+ 0x66, 0x96, 0xd9, 0x64, 0xcf, 0x8e, 0x3d, 0xf8, 0x40, 0x71, 0xfa, 0xff,
+ 0x86, 0xdb, 0xf6, 0x7b, 0x00, 0x72, 0x58, 0xbc, 0x61, 0x86, 0x2c, 0x5f,
+ 0xc1, 0x5d, 0x8f, 0x61, 0xca, 0x5f, 0x58, 0xbd, 0xb0, 0xa4, 0x35, 0x8a,
+ 0xd8, 0xcf, 0x8c, 0x2c, 0x3f, 0xbf, 0xb5, 0xa1, 0x16, 0x7d, 0x62, 0xfa,
+ 0x09, 0xbe, 0xb1, 0x7d, 0x13, 0xc6, 0x96, 0x2f, 0xf7, 0x20, 0x0f, 0xe7,
+ 0x35, 0x62, 0xf7, 0xa2, 0x65, 0x8b, 0xe8, 0x99, 0x8e, 0xb1, 0x7f, 0xe2,
+ 0xc1, 0x74, 0x59, 0x38, 0x72, 0x58, 0xb8, 0x78, 0xb1, 0x66, 0x23, 0xd8,
+ 0x08, 0x83, 0x58, 0x8a, 0x3d, 0x3d, 0xdf, 0x72, 0x35, 0x0b, 0x17, 0xd3,
+ 0x88, 0x7b, 0xab, 0x17, 0xfc, 0x11, 0x81, 0xb7, 0x26, 0x83, 0xac, 0x50,
+ 0xd3, 0xe3, 0x62, 0x1d, 0xd2, 0x39, 0x8d, 0x35, 0x0c, 0x1f, 0x11, 0x06,
+ 0x44, 0x10, 0xa2, 0xd2, 0x58, 0xbf, 0x1e, 0x33, 0xdc, 0x58, 0xbf, 0x71,
+ 0x8b, 0xb9, 0x2c, 0x5d, 0x93, 0x2c, 0x58, 0xcd, 0xa7, 0x83, 0x85, 0x35,
+ 0xb0, 0x22, 0x94, 0x62, 0x58, 0xd3, 0x7f, 0xbf, 0x1a, 0x9c, 0x31, 0x01,
+ 0x62, 0xf6, 0xf3, 0xf1, 0x62, 0xf4, 0xee, 0x4b, 0x14, 0x69, 0xbd, 0x11,
+ 0x05, 0xff, 0xff, 0x0b, 0xad, 0x66, 0xf8, 0x2f, 0x68, 0x53, 0xfe, 0x3d,
+ 0xc6, 0x58, 0xbf, 0xf4, 0xff, 0xc9, 0xbf, 0x03, 0xce, 0x96, 0x29, 0x91,
+ 0x5a, 0x26, 0xbb, 0x9f, 0x8b, 0x17, 0xdb, 0x7d, 0x9f, 0x58, 0xaf, 0x9b,
+ 0xce, 0x0b, 0xdf, 0xff, 0xcd, 0xdf, 0xb9, 0x3e, 0xb3, 0x9b, 0x73, 0xaf,
+ 0x8b, 0x75, 0x62, 0xa1, 0x10, 0xda, 0x21, 0xbd, 0x05, 0x3a, 0xc5, 0xff,
+ 0xff, 0xf4, 0xb9, 0xfc, 0x11, 0x9c, 0xfe, 0x75, 0x9c, 0xdb, 0x9d, 0xcb,
+ 0x8c, 0x4c, 0xb1, 0x79, 0xdf, 0xa5, 0x45, 0x62, 0x5f, 0x38, 0x70, 0x6a,
+ 0xc5, 0x74, 0x79, 0xda, 0x2a, 0xbf, 0x7d, 0x8f, 0x1a, 0x58, 0xbf, 0xfc,
+ 0x27, 0x9f, 0x58, 0x7f, 0xc4, 0xe4, 0x25, 0x8a, 0x63, 0xf4, 0x22, 0x8b,
+ 0xfc, 0x29, 0x67, 0x01, 0xd8, 0x16, 0x2f, 0xf0, 0x23, 0xf9, 0xf6, 0x08,
+ 0xb1, 0x7f, 0xed, 0xcc, 0xf1, 0x60, 0xa0, 0xbc, 0xb1, 0x7f, 0x6a, 0x7f,
+ 0x71, 0xc0, 0xb1, 0x7f, 0xce, 0x5d, 0x39, 0x0b, 0x3e, 0xb1, 0x7f, 0x67,
+ 0x01, 0x98, 0x35, 0x8a, 0x73, 0xe5, 0x23, 0x8a, 0x1a, 0xe0, 0x51, 0xb0,
+ 0xe4, 0xe8, 0x8b, 0xb1, 0xdd, 0x43, 0x43, 0xf0, 0x97, 0x22, 0x0e, 0x1b,
+ 0x78, 0xd4, 0x48, 0x1b, 0xe1, 0x2b, 0x7f, 0xe1, 0x7b, 0x85, 0x9b, 0xcb,
+ 0x38, 0xb1, 0x7d, 0xe2, 0xc0, 0x8b, 0x17, 0x98, 0x43, 0x58, 0xa3, 0x51,
+ 0x02, 0xc8, 0x1b, 0xa4, 0x97, 0xff, 0x17, 0x8d, 0x14, 0x16, 0x75, 0x1a,
+ 0x58, 0xbf, 0x30, 0x5d, 0xc5, 0xd2, 0xc5, 0xec, 0x9c, 0x2e, 0xb1, 0x50,
+ 0x79, 0xec, 0x5b, 0x7f, 0xb5, 0x3f, 0xb8, 0xfd, 0xf4, 0xb1, 0x7f, 0xfc,
+ 0x7d, 0xf9, 0xad, 0x36, 0xfe, 0x30, 0x9f, 0x4b, 0x15, 0x09, 0xa0, 0x7e,
+ 0x12, 0x8e, 0x40, 0x23, 0x8b, 0xfb, 0xd8, 0x50, 0x66, 0xe2, 0xc5, 0xff,
+ 0xf4, 0x67, 0x30, 0xb6, 0xf1, 0xb7, 0x20, 0x80, 0xb1, 0x58, 0x88, 0x32,
+ 0x31, 0xbf, 0xf1, 0x39, 0xcc, 0x71, 0xc7, 0x7c, 0x58, 0xbf, 0xd1, 0xa9,
+ 0x34, 0xcc, 0x62, 0xc5, 0xff, 0xcc, 0x7e, 0x6d, 0xfb, 0x78, 0xa0, 0xeb,
+ 0x15, 0x24, 0x6e, 0x00, 0x87, 0x88, 0x1e, 0x35, 0xbf, 0xdc, 0xfb, 0x6e,
+ 0x89, 0xc6, 0xb1, 0x7c, 0xfe, 0x7e, 0x96, 0x2f, 0xfa, 0x37, 0xbe, 0xba,
+ 0xfb, 0x84, 0x58, 0xb4, 0x2c, 0x5f, 0x39, 0xf0, 0x96, 0x2a, 0x0d, 0x97,
+ 0xc4, 0x6f, 0xf3, 0x47, 0x45, 0x8d, 0x3a, 0xc5, 0x76, 0x98, 0xe9, 0xcd,
+ 0xfe, 0x47, 0xe7, 0x00, 0x84, 0x17, 0xfa, 0x0b, 0xdf, 0xc0, 0x3a, 0xc5,
+ 0xf4, 0x1d, 0xfc, 0xb1, 0x52, 0x3d, 0x4e, 0x19, 0x5f, 0x82, 0x7b, 0x3b,
+ 0x99, 0x62, 0xed, 0x42, 0xc5, 0xe9, 0x98, 0xd5, 0x8a, 0x98, 0xdb, 0x70,
+ 0x5e, 0xfd, 0x07, 0x9f, 0x0c, 0x58, 0xbf, 0x60, 0xf9, 0xf8, 0x58, 0xbc,
+ 0x78, 0xd2, 0xc5, 0xc3, 0x31, 0x62, 0xff, 0xff, 0xff, 0x3f, 0xbd, 0x9f,
+ 0xe3, 0xc9, 0x8b, 0xd2, 0xcd, 0x67, 0x33, 0xef, 0x39, 0x44, 0x96, 0x2f,
+ 0x7a, 0x26, 0x58, 0xa8, 0x4e, 0xdf, 0x18, 0xd8, 0x8b, 0x45, 0x40, 0x28,
+ 0x21, 0xde, 0x0c, 0x87, 0x08, 0xcb, 0xff, 0x4d, 0xdf, 0x98, 0x78, 0x58,
+ 0x75, 0x8b, 0xf8, 0x5b, 0x9d, 0x7d, 0x82, 0xeb, 0x17, 0xdd, 0xca, 0x3e,
+ 0xb1, 0x7f, 0xb8, 0x3f, 0xe7, 0x42, 0xdd, 0x58, 0xb6, 0x70, 0xf7, 0x44,
+ 0x49, 0x74, 0x6f, 0x58, 0xaf, 0x9e, 0x01, 0x13, 0xdf, 0xdf, 0x61, 0x96,
+ 0x09, 0x62, 0xff, 0x4c, 0xf8, 0xd2, 0x0c, 0xeb, 0x14, 0x34, 0x41, 0xf4,
+ 0x42, 0xc5, 0xb7, 0xfb, 0xb9, 0x4d, 0x27, 0xd4, 0xeb, 0x17, 0x39, 0x2c,
+ 0x5f, 0xda, 0x61, 0xb6, 0x76, 0xb1, 0x7d, 0x2f, 0x34, 0xeb, 0x15, 0x08,
+ 0xa0, 0x9c, 0xe3, 0x05, 0x9c, 0xba, 0xff, 0xff, 0x41, 0xcd, 0x35, 0xfb,
+ 0xfc, 0x37, 0xb8, 0xc5, 0xdc, 0x96, 0x2f, 0xff, 0xbd, 0x1d, 0x37, 0x98,
+ 0xfb, 0x78, 0xe3, 0x1a, 0xc5, 0xff, 0xe0, 0x1d, 0xfb, 0xf6, 0xb1, 0xbf,
+ 0x03, 0x58, 0xa6, 0x44, 0xf7, 0x14, 0xea, 0x15, 0xc3, 0x64, 0x6a, 0xed,
+ 0x0d, 0x0f, 0x9d, 0xbc, 0x60, 0x57, 0x4b, 0xcb, 0x17, 0xcc, 0x77, 0x92,
+ 0xc5, 0xfd, 0x00, 0x3c, 0x70, 0x96, 0x2f, 0xec, 0x9f, 0x0b, 0x24, 0xb1,
+ 0x50, 0x89, 0x49, 0x0c, 0x31, 0x16, 0x8b, 0x6f, 0xfe, 0xe7, 0xf0, 0x23,
+ 0x79, 0xa5, 0xc1, 0x2c, 0x5f, 0xc7, 0xf0, 0x9e, 0x78, 0x58, 0xb3, 0x76,
+ 0x7e, 0xc1, 0xa3, 0xdf, 0xcd, 0xe9, 0x47, 0x99, 0x62, 0xd2, 0x58, 0xbc,
+ 0x2e, 0xf1, 0x62, 0xff, 0x69, 0x85, 0x38, 0x39, 0x25, 0x8b, 0xfb, 0x3b,
+ 0x06, 0x7b, 0x8b, 0x17, 0xf0, 0xa0, 0xbb, 0x97, 0x16, 0x3e, 0x6b, 0xef,
+ 0xe3, 0x8b, 0xb9, 0x73, 0x75, 0x62, 0xfa, 0x3e, 0xfb, 0xab, 0x16, 0x94,
+ 0x1e, 0xc9, 0x1a, 0x5e, 0x68, 0x9d, 0x62, 0xff, 0xe1, 0xc7, 0x21, 0xbb,
+ 0xf7, 0xa0, 0xeb, 0x17, 0xf4, 0x19, 0x31, 0x40, 0xd6, 0x2f, 0xfe, 0x2c,
+ 0xe3, 0x03, 0x6c, 0x4f, 0x1c, 0x58, 0xa9, 0xd5, 0x0c, 0x0c, 0x7b, 0xa6,
+ 0x5e, 0xe1, 0x31, 0x31, 0x36, 0x87, 0x7c, 0x8b, 0xbc, 0xbe, 0xfd, 0xd7,
+ 0xe0, 0x8d, 0x58, 0xbf, 0xe7, 0xf7, 0xe0, 0xc6, 0x8f, 0x2c, 0x54, 0x2b,
+ 0x0b, 0xc9, 0x45, 0x4e, 0xfc, 0x22, 0xab, 0xe3, 0xbf, 0x7e, 0x58, 0xbf,
+ 0xfa, 0x78, 0xf6, 0xd0, 0xfa, 0x0c, 0x20, 0x7c, 0x58, 0xbf, 0xf9, 0xf7,
+ 0x70, 0x9c, 0x6f, 0x9d, 0xf9, 0x62, 0xff, 0xb5, 0x1c, 0x7d, 0x14, 0x49,
+ 0x62, 0xe8, 0x92, 0xc5, 0x69, 0x1c, 0xbf, 0x50, 0xde, 0x8c, 0x10, 0xe2,
+ 0xf4, 0x9e, 0x75, 0x8b, 0xdb, 0x67, 0x3a, 0xc5, 0xff, 0x3f, 0x72, 0x6f,
+ 0xfd, 0xf7, 0x56, 0x2f, 0xb0, 0x6e, 0x05, 0x8b, 0xf4, 0x4e, 0x51, 0x3a,
+ 0xc5, 0x1c, 0xf2, 0xc8, 0x8a, 0xde, 0x58, 0xbf, 0xcf, 0x39, 0x67, 0xb0,
+ 0x0b, 0x17, 0xfe, 0x37, 0x9c, 0xcf, 0xb7, 0x05, 0x3a, 0xc5, 0x0d, 0x10,
+ 0xf8, 0x24, 0x23, 0x3b, 0xfd, 0xf7, 0x9f, 0xde, 0xc3, 0x16, 0x2b, 0x62,
+ 0x56, 0x3d, 0x91, 0x84, 0xf6, 0x82, 0xc3, 0xda, 0x21, 0x78, 0x44, 0x14,
+ 0x2a, 0x04, 0x5f, 0x7d, 0x13, 0x44, 0xeb, 0x17, 0xc3, 0x72, 0x02, 0xc5,
+ 0xff, 0x89, 0xc7, 0xf8, 0xdf, 0xf7, 0x25, 0x8b, 0xff, 0xd2, 0xc2, 0xf0,
+ 0xbe, 0xc1, 0x02, 0x46, 0xea, 0xc5, 0xff, 0xff, 0xec, 0x3e, 0x68, 0x00,
+ 0x17, 0x3e, 0xde, 0x96, 0x7d, 0xc0, 0xc3, 0x85, 0x8b, 0xa3, 0x75, 0x62,
+ 0xff, 0xff, 0x67, 0x5b, 0x48, 0x41, 0x36, 0xe7, 0x72, 0xc1, 0x10, 0x38,
+ 0xb1, 0x74, 0xb8, 0xb1, 0x61, 0x4e, 0x88, 0x17, 0x69, 0xbf, 0xfd, 0x3e,
+ 0x77, 0xee, 0x31, 0x40, 0x1c, 0xeb, 0x17, 0xfb, 0xb2, 0xc1, 0xfd, 0xcc,
+ 0x58, 0xac, 0x44, 0x03, 0xa5, 0xd4, 0xea, 0xac, 0xa4, 0x48, 0x32, 0x2e,
+ 0xcf, 0xfe, 0xa2, 0xee, 0xe5, 0x09, 0xbe, 0x42, 0xa6, 0xfb, 0xd2, 0x86,
+ 0x58, 0xbf, 0xc3, 0x9f, 0x0c, 0xcf, 0xba, 0xc5, 0xe1, 0x40, 0x16, 0x2f,
+ 0xe2, 0xce, 0xe5, 0xbb, 0x32, 0xc5, 0x68, 0xf4, 0x3e, 0x3b, 0x58, 0x8a,
+ 0x77, 0x84, 0x2d, 0xfd, 0x3c, 0xd2, 0xd8, 0xb5, 0x3a, 0xc5, 0xf1, 0x16,
+ 0x79, 0x62, 0xfc, 0xdb, 0xba, 0xd3, 0x2c, 0x5e, 0xfb, 0x1d, 0x62, 0xb6,
+ 0x34, 0x50, 0xc1, 0xc7, 0xc8, 0x44, 0x57, 0x7f, 0xd9, 0x34, 0x9f, 0x53,
+ 0xfc, 0x4b, 0x17, 0xdb, 0x8e, 0x40, 0x58, 0xb4, 0xe3, 0x3e, 0x10, 0xcf,
+ 0x2f, 0xb7, 0x63, 0x84, 0xb1, 0x7f, 0xef, 0xb9, 0xfd, 0xf8, 0xf0, 0x8e,
+ 0xb1, 0x58, 0x7c, 0xb3, 0x12, 0xdf, 0xfd, 0x98, 0x69, 0xe1, 0xb5, 0xa6,
+ 0x31, 0x62, 0xf3, 0xbe, 0x96, 0x2f, 0xfb, 0xdf, 0x13, 0xc8, 0x2a, 0x06,
+ 0x58, 0xbf, 0xe6, 0x93, 0x7c, 0x47, 0x3b, 0x2c, 0x5d, 0x9e, 0x58, 0xa8,
+ 0x4e, 0x83, 0x21, 0x1f, 0xa2, 0x2f, 0xa2, 0x90, 0xe7, 0x8f, 0xb7, 0x0e,
+ 0x6e, 0x70, 0x8b, 0x17, 0xbf, 0x87, 0x58, 0xbf, 0xfd, 0x1b, 0xa7, 0x81,
+ 0x96, 0x7b, 0xce, 0x4b, 0x14, 0x48, 0x81, 0xf0, 0xc8, 0x41, 0xdb, 0xdf,
+ 0x6d, 0x9d, 0x81, 0xd3, 0x5e, 0x6c, 0x28, 0x42, 0x05, 0xa2, 0xc8, 0x94,
+ 0x23, 0x3c, 0x64, 0x52, 0x34, 0x1b, 0xa6, 0x4e, 0x6c, 0x9b, 0x19, 0xa7,
+ 0x51, 0xb9, 0xf7, 0x1d, 0x03, 0x46, 0xb5, 0x34, 0x28, 0xb5, 0x1e, 0xc9,
+ 0xdd, 0x3f, 0x2f, 0x19, 0xe1, 0xda, 0x08, 0x58, 0x85, 0xca, 0x4a, 0x59,
+ 0xc7, 0x25, 0xb0, 0xfa, 0x59, 0xb8, 0x9f, 0x77, 0xc3, 0x27, 0x72, 0x18,
+ 0xe1, 0xca, 0x42, 0x09, 0x0e, 0xbb, 0xc1, 0x6f, 0xb9, 0xb1, 0xac, 0x5c,
+ 0x14, 0xed, 0x62, 0xfb, 0xdb, 0x99, 0xf5, 0x8b, 0x12, 0xc5, 0x05, 0x4d,
+ 0xbc, 0x89, 0xad, 0xb0, 0xd6, 0x2e, 0xd8, 0xc2, 0x8b, 0x15, 0xb1, 0x1b,
+ 0x9d, 0x86, 0x31, 0x76, 0xc2, 0xdc, 0x58, 0xbe, 0xc1, 0xb9, 0xd6, 0x2b,
+ 0x63, 0x3c, 0x3d, 0x10, 0xde, 0xf4, 0x7d, 0x62, 0xfa, 0x07, 0x87, 0x58,
+ 0xb6, 0xa0, 0xdf, 0xe8, 0x76, 0xdb, 0xab, 0x17, 0x30, 0x45, 0x8b, 0xe9,
+ 0xf5, 0x13, 0xac, 0x5c, 0x18, 0x16, 0x2e, 0xcf, 0xac, 0x5e, 0xfe, 0x4c,
+ 0xb1, 0x7b, 0xec, 0x75, 0x8b, 0x4c, 0xb1, 0x53, 0x9f, 0x28, 0xc5, 0xdc,
+ 0x78, 0x43, 0xb7, 0xe7, 0x29, 0xc5, 0xc5, 0x8b, 0xf6, 0x0f, 0x4f, 0xd2,
+ 0xc5, 0xf3, 0xcf, 0x1a, 0x58, 0xbd, 0xa7, 0x9d, 0x62, 0xe8, 0x1f, 0xcf,
+ 0xa8, 0x8a, 0x7c, 0x47, 0x7c, 0xc3, 0x79, 0x2c, 0x58, 0x6b, 0x14, 0xca,
+ 0x8c, 0xe6, 0x26, 0x38, 0xab, 0x8c, 0x80, 0x94, 0x9f, 0xb8, 0x79, 0xe8,
+ 0x49, 0xef, 0x39, 0xdc, 0x22, 0xbd, 0xae, 0x09, 0x62, 0xdf, 0x58, 0xbd,
+ 0xc0, 0xf8, 0xb1, 0x71, 0x4c, 0xb1, 0x74, 0x1a, 0xb1, 0x7b, 0x51, 0x25,
+ 0x8b, 0xe2, 0xc0, 0x71, 0x62, 0xdd, 0xce, 0x7a, 0xfa, 0x18, 0x71, 0xda,
+ 0x84, 0x7a, 0x4e, 0x3c, 0x31, 0x2c, 0x1f, 0x13, 0x7d, 0xfb, 0xb9, 0x79,
+ 0xfb, 0x58, 0xbb, 0x9d, 0x2c, 0x5a, 0x16, 0x29, 0xcf, 0x54, 0x8a, 0xfc,
+ 0x33, 0x7f, 0xbb, 0xd4, 0x34, 0x9f, 0x8b, 0x17, 0xd8, 0x51, 0x25, 0x8a,
+ 0xc3, 0xd5, 0x39, 0xa5, 0xb7, 0x16, 0x2f, 0xdc, 0xcf, 0x36, 0x96, 0x2f,
+ 0x67, 0x7e, 0x58, 0xa0, 0x1e, 0x37, 0x0a, 0x2f, 0x7d, 0x8c, 0x58, 0xac,
+ 0x3c, 0x0e, 0x88, 0xae, 0x97, 0x16, 0x2e, 0x71, 0xac, 0x5e, 0xf6, 0x71,
+ 0x62, 0xe2, 0x85, 0x8a, 0x91, 0xe5, 0x08, 0x5f, 0x78, 0xed, 0xff, 0x30,
+ 0xa7, 0x8e, 0xc1, 0xa8, 0x58, 0xbd, 0x28, 0xed, 0x62, 0xdb, 0xab, 0x15,
+ 0x31, 0xb3, 0x21, 0xeb, 0xda, 0x72, 0x58, 0xb6, 0xe2, 0xc5, 0xfc, 0x59,
+ 0xbf, 0x4d, 0xc5, 0x8a, 0x9c, 0xf1, 0x0c, 0x15, 0xb7, 0x6b, 0x15, 0x08,
+ 0x97, 0x66, 0x01, 0x12, 0x5f, 0x6a, 0x50, 0x75, 0x8b, 0xf7, 0x67, 0x8c,
+ 0xf2, 0xc5, 0x61, 0xe6, 0x39, 0x1d, 0xf7, 0xdf, 0x34, 0xb1, 0x7e, 0x9f,
+ 0x09, 0x8d, 0x58, 0xa8, 0x3c, 0xb6, 0x22, 0xbf, 0xb5, 0x20, 0x37, 0x7c,
+ 0x58, 0xbf, 0xdc, 0x0c, 0xa3, 0xed, 0x3a, 0xc5, 0x39, 0xf2, 0xf8, 0xc2,
+ 0xfb, 0x9c, 0x80, 0x2c, 0x54, 0x2e, 0x22, 0x8c, 0x87, 0x21, 0x37, 0xd9,
+ 0x13, 0x31, 0x68, 0xc4, 0xed, 0xdf, 0x85, 0xc3, 0xbd, 0x13, 0x58, 0xa1,
+ 0x0a, 0x61, 0x0d, 0xff, 0xb0, 0xb0, 0xd2, 0xcf, 0x7d, 0x96, 0x2f, 0xe7,
+ 0x37, 0x06, 0xf2, 0x58, 0xaf, 0x9f, 0x59, 0x1e, 0xdf, 0xcc, 0x45, 0x9b,
+ 0xdd, 0x62, 0xe0, 0xfc, 0xb1, 0x7f, 0x7d, 0xb2, 0x67, 0x02, 0xc5, 0x48,
+ 0xf1, 0xfc, 0x33, 0x7b, 0x5a, 0x75, 0x8b, 0xe9, 0x00, 0x52, 0x58, 0xbe,
+ 0xd0, 0x70, 0x05, 0x8b, 0xd1, 0xf8, 0x58, 0xa8, 0x3e, 0x46, 0x24, 0xf9,
+ 0x25, 0xfd, 0x3b, 0x9c, 0x00, 0x85, 0x8b, 0xe9, 0x41, 0x49, 0x62, 0x98,
+ 0xf4, 0x66, 0x2f, 0xbc, 0x46, 0xfd, 0x62, 0xc3, 0x58, 0xa8, 0x36, 0x0c,
+ 0x3d, 0x73, 0xf6, 0xb1, 0x7f, 0x7f, 0x26, 0x28, 0x1a, 0xc5, 0xff, 0x4a,
+ 0x0f, 0xcc, 0xd4, 0x71, 0x62, 0xba, 0x3e, 0x7e, 0xcb, 0xaf, 0xa6, 0x27,
+ 0x31, 0x62, 0xff, 0xa0, 0xb3, 0x7e, 0x13, 0x9a, 0xb1, 0x46, 0x9e, 0xee,
+ 0x89, 0x28, 0x69, 0x91, 0xb3, 0xfb, 0xc2, 0x06, 0xf7, 0x98, 0x0b, 0x17,
+ 0xc0, 0x82, 0xe9, 0x62, 0xc1, 0x75, 0x8a, 0x34, 0xf5, 0xbb, 0x1d, 0x11,
+ 0x1d, 0xf4, 0xbd, 0x81, 0xac, 0x5f, 0xbc, 0xdf, 0x73, 0xac, 0x5d, 0x00,
+ 0x58, 0xa8, 0x37, 0xfd, 0x14, 0x5e, 0xd4, 0x1d, 0x62, 0x99, 0x1a, 0x4e,
+ 0x62, 0x26, 0x33, 0x08, 0x6f, 0xd9, 0xdf, 0x9c, 0xeb, 0x17, 0x64, 0xcb,
+ 0x16, 0x9c, 0x8f, 0x04, 0x32, 0x9b, 0xd1, 0xa9, 0xd6, 0x2a, 0x0f, 0x1d,
+ 0x8a, 0x69, 0x62, 0xf7, 0x50, 0x05, 0x8b, 0x14, 0x8d, 0x56, 0x06, 0x5f,
+ 0xf3, 0x9b, 0xc6, 0xdf, 0x05, 0xe5, 0x8b, 0xfb, 0xec, 0x7c, 0xfb, 0xac,
+ 0x54, 0x22, 0x34, 0x89, 0x44, 0x77, 0x7d, 0xe2, 0x60, 0x8b, 0x17, 0x0b,
+ 0x8b, 0x17, 0xe1, 0x4b, 0x9f, 0x1a, 0xc5, 0x41, 0xe1, 0x10, 0xc5, 0xfb,
+ 0x26, 0x93, 0xf1, 0x62, 0xa4, 0xbe, 0x3c, 0x32, 0x1e, 0xdd, 0x18, 0x8a,
+ 0x68, 0x40, 0xe9, 0xf8, 0xea, 0x5f, 0x8d, 0x08, 0xa3, 0x5c, 0xe4, 0x31,
+ 0x3d, 0x0d, 0x71, 0x17, 0x6f, 0x66, 0x0c, 0x82, 0xc4, 0xb1, 0x7f, 0x3c,
+ 0x82, 0x04, 0x14, 0xeb, 0x17, 0xf7, 0x03, 0x81, 0xec, 0x20, 0xaa, 0xc5,
+ 0xd9, 0xc5, 0x8b, 0x12, 0xc5, 0xd2, 0xdd, 0x58, 0xa3, 0xa3, 0x0b, 0xe2,
+ 0x2e, 0x68, 0x47, 0x5c, 0x17, 0xf0, 0x8d, 0xde, 0xe2, 0xc5, 0xed, 0x07,
+ 0x32, 0xc5, 0xfd, 0xc7, 0xef, 0xcd, 0x3a, 0xc5, 0x68, 0xf4, 0x3c, 0x41,
+ 0x4b, 0x14, 0xc6, 0xbb, 0x70, 0x8a, 0xfe, 0xc9, 0xc7, 0xf6, 0xd2, 0xc5,
+ 0x32, 0x3a, 0x3f, 0x09, 0x62, 0x23, 0xbf, 0x9c, 0xbf, 0xdb, 0xee, 0xac,
+ 0x5f, 0xfa, 0x33, 0x9b, 0x61, 0x86, 0x1c, 0x96, 0x2f, 0xe6, 0x33, 0x93,
+ 0xe1, 0x8b, 0x15, 0x08, 0xa3, 0x23, 0x1f, 0x20, 0xdc, 0x50, 0xb1, 0x78,
+ 0x00, 0x85, 0x8b, 0xb3, 0xa5, 0x8b, 0xa0, 0x7c, 0x36, 0xbe, 0x1d, 0xbd,
+ 0x05, 0xd2, 0xc5, 0xff, 0xfc, 0xe6, 0x0d, 0xdf, 0x53, 0xfd, 0xfd, 0xf6,
+ 0xd4, 0x96, 0x2f, 0xdd, 0x75, 0xf8, 0xd2, 0xc5, 0x7d, 0x14, 0xa4, 0x3a,
+ 0x25, 0xda, 0x92, 0x6f, 0x3d, 0x17, 0x71, 0x2f, 0xd0, 0xd1, 0xbe, 0x72,
+ 0x79, 0x96, 0x2f, 0xd9, 0xa0, 0xfd, 0xc5, 0x8b, 0xf3, 0x78, 0xb2, 0x4b,
+ 0x17, 0xd0, 0x64, 0x4c, 0xb1, 0x7f, 0xee, 0x6f, 0x7f, 0xc1, 0xb9, 0xee,
+ 0x2c, 0x5c, 0x19, 0xd6, 0x2f, 0xb3, 0x42, 0xc5, 0x8b, 0x01, 0x62, 0x88,
+ 0xda, 0x06, 0x45, 0x7d, 0x3c, 0xf1, 0xba, 0xb1, 0x79, 0xfb, 0x25, 0x8b,
+ 0xfb, 0xc4, 0xe0, 0xc2, 0x58, 0xbf, 0x13, 0x83, 0x09, 0x62, 0xb6, 0x9e,
+ 0x97, 0x8b, 0x2a, 0x11, 0x76, 0x32, 0x81, 0x37, 0xd4, 0xea, 0x8c, 0x64,
+ 0x44, 0x69, 0x53, 0x13, 0xcc, 0x49, 0xf4, 0x20, 0x26, 0x94, 0x37, 0x2f,
+ 0xb9, 0x85, 0xd2, 0xc5, 0xfb, 0x93, 0x4a, 0x3b, 0x58, 0xbe, 0xf7, 0x42,
+ 0x9d, 0x62, 0xd1, 0xf3, 0xd1, 0x22, 0xbb, 0xf6, 0x75, 0xec, 0xe9, 0x62,
+ 0xdc, 0x58, 0xbf, 0x8c, 0x18, 0x9f, 0x52, 0x58, 0xa5, 0x8a, 0x83, 0x78,
+ 0x19, 0x85, 0xee, 0x44, 0x96, 0x2f, 0xdf, 0xcd, 0x37, 0x16, 0x2e, 0x6d,
+ 0x76, 0x78, 0xbe, 0x1d, 0xbf, 0x9b, 0x4d, 0xc8, 0x9d, 0x62, 0xdb, 0xd6,
+ 0x2a, 0x13, 0xe8, 0x93, 0xa6, 0x13, 0x4c, 0x55, 0xa4, 0xef, 0xb3, 0x70,
+ 0xb8, 0x21, 0x75, 0xc3, 0x85, 0x8b, 0xff, 0x7f, 0x25, 0xe8, 0xc2, 0xef,
+ 0xcb, 0x15, 0x87, 0xad, 0xe1, 0x7b, 0xfc, 0xd3, 0x93, 0xce, 0x2e, 0x2c,
+ 0x58, 0x35, 0x8a, 0x23, 0xe9, 0xf1, 0x08, 0x43, 0x5b, 0xc4, 0xc6, 0xac,
+ 0x5f, 0x60, 0xdb, 0x7a, 0xc5, 0xd0, 0x7c, 0x3c, 0x17, 0x1d, 0xbf, 0x4b,
+ 0xcc, 0x7f, 0x2c, 0x5f, 0xcf, 0xdf, 0xe0, 0x32, 0x58, 0xb6, 0x76, 0x7b,
+ 0x06, 0x14, 0xde, 0x0f, 0xb2, 0x58, 0xbf, 0x9e, 0x4e, 0x58, 0x11, 0x62,
+ 0xe6, 0x1a, 0xc5, 0xf7, 0x3e, 0xf2, 0x58, 0xb7, 0x96, 0x2a, 0x13, 0xb6,
+ 0x67, 0x1d, 0x42, 0x0f, 0xe5, 0x2e, 0x3e, 0x02, 0xe1, 0x0b, 0x86, 0x47,
+ 0x71, 0x4c, 0xb1, 0x63, 0x56, 0x2b, 0x0d, 0x5e, 0x86, 0x2d, 0xda, 0xc5,
+ 0xc0, 0x84, 0x8b, 0x8c, 0x31, 0x22, 0x98, 0xd8, 0x98, 0x2f, 0x7e, 0x2c,
+ 0xf7, 0xd9, 0x23, 0x64, 0xd0, 0xde, 0x2c, 0xe2, 0xc5, 0xd8, 0x35, 0x8a,
+ 0x34, 0xd9, 0xef, 0x1c, 0xa9, 0x22, 0x44, 0x6d, 0xb7, 0x74, 0x05, 0x8b,
+ 0xfc, 0xe6, 0xc1, 0x16, 0x79, 0x62, 0xfc, 0xc3, 0x8c, 0x25, 0x8b, 0x80,
+ 0xeb, 0x17, 0xcd, 0xa6, 0xf2, 0xc5, 0x31, 0xb9, 0x98, 0x5e, 0xa1, 0x50,
+ 0x20, 0xc8, 0x1e, 0x1e, 0xc0, 0x23, 0x21, 0x9e, 0x19, 0x09, 0x7e, 0xf7,
+ 0xe0, 0xc5, 0x8b, 0xcf, 0xdf, 0x16, 0x2d, 0xc5, 0x8b, 0xe0, 0xfe, 0xfe,
+ 0x58, 0xa9, 0xcf, 0xc8, 0x63, 0xdd, 0x8f, 0x78, 0x4a, 0xda, 0x58, 0xbd,
+ 0x05, 0x32, 0xc5, 0x2c, 0x5a, 0x16, 0x28, 0x05, 0xe9, 0x06, 0x52, 0xc5,
+ 0x2c, 0x54, 0xc5, 0xc1, 0xc3, 0x2e, 0xfc, 0xcb, 0x17, 0x30, 0x16, 0x2a,
+ 0x0d, 0x80, 0x06, 0x6b, 0x11, 0xe9, 0x30, 0x96, 0x8e, 0x9c, 0xdc, 0x0a,
+ 0x37, 0xff, 0x1a, 0xc5, 0xd7, 0x20, 0xef, 0xdf, 0x96, 0x2f, 0x03, 0x02,
+ 0x2c, 0x5f, 0xff, 0x16, 0x03, 0x0e, 0x28, 0xd6, 0x98, 0x5d, 0x2c, 0x5f,
+ 0x14, 0x1e, 0x65, 0x8a, 0x35, 0x1b, 0x3a, 0x47, 0x21, 0xff, 0x28, 0x5f,
+ 0x1f, 0x82, 0x3a, 0xc5, 0x8d, 0x58, 0xb6, 0xe2, 0xc5, 0xda, 0x35, 0x62,
+ 0xa0, 0xf9, 0x58, 0x90, 0x42, 0x61, 0x8a, 0xdf, 0x46, 0xe6, 0x76, 0xb1,
+ 0x7f, 0xfb, 0x25, 0xc8, 0xf4, 0xb3, 0x75, 0xc8, 0x0b, 0x17, 0xc6, 0xb9,
+ 0x01, 0x62, 0xbe, 0x7d, 0xe2, 0x4c, 0xbf, 0xe6, 0xf7, 0xf3, 0xbf, 0x0a,
+ 0x16, 0x2f, 0x83, 0x8d, 0x01, 0x62, 0xa4, 0x7b, 0xdf, 0x3a, 0xbb, 0x38,
+ 0xb1, 0x7f, 0xfb, 0x25, 0xb9, 0x86, 0xbe, 0x7a, 0x3d, 0xc5, 0x8a, 0x84,
+ 0x43, 0x48, 0x88, 0x02, 0xf5, 0xc4, 0xcd, 0x7d, 0x18, 0x35, 0xd1, 0xc5,
+ 0x8b, 0x01, 0x62, 0xfa, 0x0f, 0x07, 0x58, 0xbf, 0x31, 0x87, 0x7f, 0x2c,
+ 0x53, 0x1e, 0x5e, 0x88, 0xaf, 0xba, 0xfc, 0x71, 0x62, 0xd8, 0xb1, 0x52,
+ 0x55, 0x7c, 0xd1, 0xe5, 0x68, 0xa9, 0xc5, 0xf8, 0xba, 0x61, 0x0e, 0xe1,
+ 0x25, 0xc6, 0x79, 0x62, 0xff, 0x87, 0x83, 0xd9, 0x9b, 0xa1, 0x12, 0xc5,
+ 0x8d, 0x58, 0xa8, 0x5e, 0xc8, 0xc8, 0xcc, 0x9a, 0x32, 0x2f, 0xc2, 0x89,
+ 0xe5, 0x7c, 0x89, 0xb8, 0x31, 0x90, 0x87, 0xf7, 0xd0, 0x60, 0xa6, 0x58,
+ 0xbd, 0xc8, 0x99, 0x62, 0xfe, 0xc1, 0xe6, 0xf6, 0xd2, 0xc5, 0xf4, 0xd3,
+ 0x37, 0xd6, 0x29, 0x62, 0xda, 0x58, 0xb1, 0xd6, 0x2b, 0x87, 0xab, 0xe2,
+ 0x51, 0x06, 0x6f, 0x12, 0xbe, 0x1b, 0xbf, 0x6b, 0x17, 0xe0, 0x36, 0x98,
+ 0xd5, 0x8b, 0xb9, 0xe5, 0x8b, 0x1a, 0xb1, 0x50, 0x6a, 0xdc, 0x62, 0xec,
+ 0xed, 0x62, 0xba, 0x4e, 0xce, 0x62, 0x53, 0x8f, 0x7e, 0x10, 0x8e, 0x7c,
+ 0x02, 0x32, 0x54, 0xdc, 0x1f, 0xbb, 0x3e, 0xb1, 0x7b, 0x34, 0x6a, 0xc5,
+ 0xfc, 0x5e, 0xc2, 0x63, 0x16, 0x2f, 0xef, 0x73, 0x0e, 0xde, 0x58, 0xb6,
+ 0x96, 0x2a, 0x0f, 0x03, 0x0b, 0xa9, 0x62, 0x96, 0x2d, 0x0b, 0x14, 0x17,
+ 0x35, 0x24, 0x19, 0xe0, 0xcb, 0xd9, 0xbd, 0xd6, 0x2f, 0xbf, 0xfc, 0x02,
+ 0xc5, 0xa3, 0xe7, 0x82, 0x18, 0xf5, 0x42, 0x70, 0xb8, 0x2e, 0xc3, 0xc7,
+ 0x6d, 0x74, 0x90, 0x39, 0x5f, 0xde, 0xce, 0xe5, 0x12, 0x58, 0xbf, 0x7b,
+ 0x3e, 0xe6, 0xac, 0x57, 0x67, 0xb0, 0xc5, 0xf7, 0xee, 0xc0, 0x14, 0x17,
+ 0x16, 0x2f, 0x7d, 0xce, 0xb1, 0x7f, 0x3f, 0x80, 0x19, 0x49, 0x62, 0xfd,
+ 0xcc, 0xd3, 0x1a, 0xb1, 0x43, 0x3f, 0x5d, 0xd1, 0xdf, 0x17, 0xdd, 0xbb,
+ 0x32, 0xc5, 0xfd, 0xe1, 0xb0, 0x20, 0x96, 0x2f, 0x4f, 0xf6, 0x58, 0xbb,
+ 0xe2, 0xec, 0xf2, 0xdc, 0xb6, 0xdf, 0x58, 0xbc, 0x61, 0x86, 0x24, 0x5f,
+ 0xe8, 0x9c, 0x3c, 0xfb, 0xf6, 0x91, 0xb2, 0x68, 0x6f, 0xf3, 0x0d, 0xcb,
+ 0xb9, 0x71, 0x62, 0x86, 0x7f, 0xbf, 0x49, 0xbb, 0x27, 0x58, 0xbf, 0x1c,
+ 0x38, 0xd0, 0x16, 0x29, 0x62, 0x96, 0x2d, 0x07, 0x2e, 0x00, 0x19, 0x50,
+ 0x7c, 0xf2, 0x42, 0xbf, 0xf7, 0x22, 0x5f, 0xcc, 0x29, 0x71, 0x62, 0xfe,
+ 0x7f, 0x6b, 0x59, 0x3a, 0xc5, 0x42, 0xa7, 0x41, 0xb3, 0xe1, 0x77, 0x50,
+ 0xb0, 0x62, 0x29, 0x9f, 0xfc, 0x42, 0x61, 0xf5, 0xe8, 0x3b, 0x2c, 0x5e,
+ 0x96, 0x74, 0xb1, 0x7d, 0x03, 0x63, 0xac, 0x5f, 0xee, 0x7f, 0x39, 0xe6,
+ 0x9d, 0x62, 0xee, 0x3a, 0xc5, 0x6c, 0x0b, 0x8d, 0x51, 0x0a, 0x4c, 0x95,
+ 0x4d, 0xd3, 0xc7, 0x63, 0x8c, 0x3c, 0xe4, 0x5e, 0x35, 0xbf, 0xed, 0x07,
+ 0x28, 0xde, 0xc4, 0x05, 0x8b, 0xda, 0x08, 0x35, 0x8b, 0x7d, 0x62, 0xa0,
+ 0xfb, 0x98, 0xf0, 0x21, 0x05, 0xff, 0x47, 0x7f, 0xc9, 0x9c, 0xa7, 0x58,
+ 0xbf, 0x9c, 0xce, 0xe5, 0x9e, 0x58, 0xaf, 0x9f, 0x59, 0x1d, 0xdf, 0xbf,
+ 0x1d, 0xbe, 0xea, 0xc5, 0xff, 0xf4, 0x7b, 0x83, 0xcf, 0x37, 0xc5, 0x9d,
+ 0xf9, 0x62, 0xbe, 0x7f, 0xbe, 0x2c, 0xbc, 0x59, 0xf5, 0x8b, 0x69, 0x62,
+ 0xff, 0x98, 0x61, 0xfb, 0xbe, 0x98, 0xeb, 0x17, 0xf6, 0x74, 0x1e, 0xff,
+ 0xe2, 0xc5, 0x48, 0xfb, 0xf0, 0xf6, 0xff, 0xa0, 0xbc, 0x59, 0xe8, 0x31,
+ 0x62, 0xc6, 0x2c, 0x5f, 0xc6, 0x71, 0x8b, 0xb9, 0x2c, 0x5f, 0x4f, 0xec,
+ 0xfa, 0xc5, 0x41, 0xf3, 0xe0, 0x98, 0x8c, 0x29, 0x62, 0x99, 0x1b, 0x1a,
+ 0x84, 0xfb, 0x96, 0xdf, 0x73, 0xce, 0xcb, 0x17, 0xe9, 0x80, 0x7c, 0x99,
+ 0x62, 0xf7, 0xbf, 0x0b, 0x15, 0x87, 0x90, 0xe5, 0x77, 0x0a, 0x4b, 0x17,
+ 0xde, 0xe4, 0x01, 0x62, 0xed, 0x09, 0x62, 0xb0, 0xdd, 0xf8, 0x8e, 0xdc,
+ 0x58, 0xa9, 0xd1, 0x0a, 0x4a, 0x62, 0x20, 0xbf, 0xcf, 0xbf, 0x07, 0x3e,
+ 0x18, 0xb1, 0x7f, 0xfa, 0x33, 0xb0, 0xfc, 0xc4, 0x29, 0x67, 0x16, 0x2f,
+ 0xf7, 0x20, 0xfd, 0xcb, 0x3c, 0xb1, 0x7a, 0x32, 0x75, 0x8b, 0x60, 0xd1,
+ 0x3b, 0xe4, 0xbd, 0xe6, 0xb7, 0xd9, 0xf0, 0xf4, 0xb1, 0x77, 0x66, 0x2c,
+ 0x5c, 0x70, 0x2c, 0x5c, 0xe4, 0xb1, 0x50, 0x79, 0x1f, 0x1a, 0x71, 0x8b,
+ 0x98, 0xd5, 0x8b, 0xe6, 0xf0, 0x1d, 0x62, 0xfd, 0x1d, 0xcb, 0x0e, 0xb1,
+ 0x52, 0x3e, 0x33, 0x8c, 0x7c, 0x8a, 0xf7, 0xc4, 0x4b, 0x17, 0xdc, 0x82,
+ 0x35, 0x62, 0xa7, 0x5e, 0xd8, 0x1c, 0x26, 0xb2, 0x13, 0xcc, 0x45, 0xba,
+ 0x39, 0x34, 0x20, 0x75, 0x0f, 0x93, 0x99, 0xfd, 0xa9, 0xe1, 0x4a, 0x03,
+ 0x02, 0x86, 0xa7, 0x0d, 0xfc, 0xd8, 0x28, 0x48, 0x6f, 0x2f, 0x0c, 0x76,
+ 0xed, 0x1a, 0xb1, 0x7d, 0x07, 0x7f, 0xac, 0x5e, 0xf7, 0x9d, 0x62, 0xfb,
+ 0x42, 0x8d, 0xeb, 0x17, 0x9c, 0x80, 0x33, 0xe4, 0x72, 0x2f, 0x0e, 0xdf,
+ 0xdc, 0x2c, 0x9c, 0x39, 0x2c, 0x5b, 0x37, 0x4f, 0xb8, 0x07, 0xd7, 0x40,
+ 0x16, 0x2f, 0x79, 0xa7, 0x58, 0xa9, 0x8d, 0xaf, 0xc5, 0xef, 0xf7, 0x4d,
+ 0xc2, 0xcd, 0xee, 0xb1, 0x7d, 0x13, 0xbc, 0x96, 0x2e, 0x01, 0xd6, 0x2f,
+ 0x73, 0xec, 0xb1, 0x5a, 0x36, 0xbe, 0x18, 0xbf, 0x89, 0xfd, 0x3e, 0x18,
+ 0xb1, 0x4b, 0x14, 0x46, 0xef, 0xc5, 0xf5, 0x07, 0xf9, 0x8b, 0x97, 0xd3,
+ 0x96, 0x76, 0xb1, 0x7f, 0x03, 0x98, 0x37, 0x92, 0xc5, 0x61, 0xe9, 0x39,
+ 0x25, 0xff, 0x48, 0x6e, 0x0f, 0x47, 0x7e, 0x58, 0xbf, 0xb3, 0xdf, 0x62,
+ 0x02, 0xc5, 0xe6, 0x2e, 0x2c, 0x5e, 0xf3, 0x4e, 0xb1, 0x44, 0x7c, 0xfe,
+ 0x2d, 0xde, 0x39, 0x7d, 0xb7, 0x3b, 0xf2, 0xc5, 0xfd, 0xc8, 0xee, 0x59,
+ 0xe5, 0x8a, 0xe8, 0xf5, 0x78, 0x4d, 0x7d, 0x9e, 0x6e, 0x2c, 0x52, 0xc5,
+ 0x76, 0x6b, 0x9c, 0x8a, 0xa1, 0x39, 0x9c, 0x85, 0x13, 0x42, 0x15, 0xd4,
+ 0x6e, 0x8f, 0x2c, 0x54, 0x2e, 0x7d, 0xca, 0x1d, 0x78, 0xbf, 0xd9, 0x16,
+ 0x8d, 0x7f, 0x0d, 0x42, 0x72, 0xe4, 0x77, 0x3e, 0x44, 0xa5, 0x8b, 0x84,
+ 0x1a, 0xc5, 0x4c, 0x69, 0x43, 0x0c, 0xbc, 0x4d, 0xba, 0xb1, 0x7f, 0x7e,
+ 0x3d, 0xcf, 0xb2, 0xc5, 0xce, 0x6a, 0xc5, 0x87, 0xe3, 0xc6, 0xdc, 0x2e,
+ 0xbd, 0xdf, 0x06, 0xb1, 0x50, 0x8a, 0xfc, 0x65, 0x62, 0xbb, 0x6e, 0x2c,
+ 0x5d, 0x03, 0x58, 0xa0, 0xa9, 0xac, 0xf8, 0xad, 0xb8, 0xb1, 0x63, 0xac,
+ 0x5b, 0x4b, 0x14, 0xe6, 0x90, 0x42, 0x55, 0xa3, 0xd6, 0xf9, 0xb5, 0xfd,
+ 0x38, 0xf4, 0xc2, 0x9d, 0x62, 0xc1, 0xac, 0x58, 0x0b, 0x14, 0xb0, 0xc7,
+ 0xf0, 0xe4, 0x42, 0x31, 0xdc, 0x13, 0xbf, 0xd0, 0x52, 0x73, 0xe0, 0xd6,
+ 0x2f, 0xbc, 0x73, 0xe9, 0x62, 0xff, 0xe0, 0x41, 0x74, 0xfe, 0x00, 0x65,
+ 0x25, 0x8b, 0xd2, 0x6f, 0xac, 0x5f, 0x78, 0xb2, 0x4b, 0x17, 0xe9, 0xf4,
+ 0x27, 0xe2, 0xc5, 0xf0, 0x82, 0xfc, 0x75, 0x8b, 0xce, 0xe6, 0x2c, 0x5f,
+ 0x69, 0x81, 0xc5, 0x8b, 0x4e, 0x33, 0xc0, 0xe0, 0xed, 0x62, 0x24, 0x04,
+ 0xcf, 0x7f, 0xf7, 0x3f, 0x83, 0x2c, 0xde, 0x59, 0xc5, 0x8b, 0xe8, 0x94,
+ 0x8e, 0xb1, 0x79, 0xe6, 0xe2, 0xc5, 0x32, 0x21, 0x89, 0x17, 0xc4, 0x75,
+ 0x25, 0x4d, 0x66, 0x99, 0x76, 0x49, 0x32, 0x36, 0x87, 0x5c, 0x88, 0xa1,
+ 0x75, 0xe8, 0x54, 0x5c, 0x1f, 0x4b, 0x15, 0xb1, 0xbe, 0x3d, 0x38, 0x50,
+ 0xb7, 0x62, 0x54, 0xd8, 0x6b, 0xc1, 0x6e, 0xdf, 0x12, 0xa6, 0x67, 0x8e,
+ 0x26, 0x50, 0x9e, 0x1c, 0xe6, 0x3e, 0x52, 0x0f, 0x4d, 0x8e, 0x8b, 0xa8,
+ 0xcf, 0x7b, 0x94, 0x9e, 0xd2, 0x9d, 0x66, 0x94, 0xc3, 0xa9, 0x5d, 0x07,
+ 0x95, 0x49, 0xf9, 0xfa, 0x27, 0x94, 0x7c, 0x08, 0xff, 0xc2, 0xf0, 0xac,
+ 0x29, 0xc8, 0xce, 0x4f, 0xe4, 0xfa, 0x78, 0x2c, 0x50, 0xb4, 0xdf, 0x0d,
+ 0x23, 0x16, 0x77, 0x21, 0xe6, 0x1c, 0xab, 0x00, 0x8f, 0xd7, 0xfb, 0xf0,
+ 0x5e, 0x2c, 0x9d, 0x62, 0xfe, 0x6c, 0x09, 0xc1, 0x42, 0xc5, 0xf6, 0x14,
+ 0x49, 0x62, 0xdb, 0x23, 0x44, 0x1f, 0x8c, 0xc3, 0x2f, 0xbc, 0x00, 0xe4,
+ 0xb1, 0x7f, 0xfd, 0xc6, 0xfb, 0xb7, 0xb3, 0x40, 0x3b, 0xc9, 0x62, 0xdb,
+ 0x3d, 0x9f, 0x77, 0x87, 0xef, 0xb7, 0xc0, 0xba, 0x58, 0xbf, 0xe8, 0x10,
+ 0x5f, 0x93, 0x9d, 0xe7, 0x58, 0xbb, 0x9b, 0x30, 0x7c, 0xc3, 0x26, 0xb0,
+ 0xa1, 0x18, 0x5e, 0x84, 0x95, 0x6c, 0xae, 0x39, 0x4f, 0x2b, 0x6c, 0x71,
+ 0xb5, 0x5f, 0xb5, 0xd3, 0xbf, 0x4a, 0x8a, 0xdc, 0xbf, 0xf3, 0xcb, 0x67,
+ 0x35, 0xd3, 0xbf, 0x4a, 0x89, 0xc0, 0xb6, 0xce, 0x22, 0x1c, 0xe6, 0xf4,
+ 0xb1, 0x73, 0x8d, 0x62, 0xdb, 0x10, 0xcd, 0x1f, 0x83, 0x2d, 0xf5, 0x8b,
+ 0x71, 0x62, 0x84, 0x69, 0x37, 0x04, 0xaf, 0xd8, 0x67, 0x18, 0xc5, 0x8b,
+ 0xd2, 0xe7, 0x16, 0x2e, 0x0a, 0x71, 0x62, 0xfb, 0xa7, 0x7e, 0x95, 0x16,
+ 0x89, 0x7d, 0xf2, 0x7d, 0xd5, 0x8b, 0xff, 0x87, 0xf7, 0x36, 0x69, 0x9b,
+ 0x82, 0x3a, 0xc5, 0x41, 0xf7, 0x61, 0x2d, 0xfb, 0x3f, 0xd3, 0x71, 0x62,
+ 0xfe, 0x9f, 0xf9, 0xa1, 0x74, 0xb1, 0x7f, 0xff, 0xc4, 0x02, 0xcf, 0x7f,
+ 0x36, 0x80, 0x9f, 0xdf, 0x79, 0xb8, 0xb1, 0x50, 0x89, 0x96, 0x31, 0xbf,
+ 0x9f, 0xb8, 0xf4, 0x0d, 0x62, 0xb6, 0x1a, 0x7d, 0x9a, 0x1c, 0xfc, 0x27,
+ 0xc8, 0x83, 0x90, 0xc2, 0xde, 0x43, 0x79, 0x8b, 0xa5, 0x8b, 0xce, 0x40,
+ 0x58, 0xac, 0x37, 0x3d, 0x0e, 0xdf, 0x02, 0x0b, 0xa5, 0x8b, 0xdb, 0xe2,
+ 0x65, 0x8b, 0xfd, 0x9b, 0xbc, 0xd6, 0x9f, 0xcb, 0x17, 0xf4, 0x4e, 0xff,
+ 0x73, 0xac, 0x53, 0x22, 0x16, 0x62, 0x0f, 0x9b, 0xdf, 0xd1, 0xec, 0x2e,
+ 0xb1, 0x62, 0xdc, 0x58, 0xa6, 0x37, 0xff, 0x2d, 0xbf, 0xa1, 0xc8, 0x43,
+ 0xc5, 0x8b, 0xc2, 0xf7, 0x16, 0x2f, 0xc3, 0xfb, 0x97, 0x96, 0x2f, 0xa6,
+ 0xc3, 0x46, 0xb1, 0x6d, 0x0c, 0xfa, 0xf0, 0x7b, 0xc5, 0x17, 0xfd, 0x13,
+ 0xff, 0x39, 0xfc, 0xdd, 0x58, 0xbf, 0x75, 0x8c, 0x5d, 0x2c, 0x5f, 0xec,
+ 0xe8, 0xa0, 0x1c, 0x85, 0x8b, 0xa3, 0xad, 0xa7, 0xb9, 0xc2, 0x9b, 0xfe,
+ 0xdf, 0xcc, 0xfe, 0x10, 0x63, 0x58, 0xa8, 0x3e, 0xcc, 0x30, 0xaf, 0xa6,
+ 0x4a, 0x51, 0x82, 0xdf, 0xec, 0xd0, 0x32, 0x60, 0xf8, 0xb1, 0x63, 0x56,
+ 0x2f, 0xfb, 0x22, 0x7c, 0x9b, 0x4d, 0xc5, 0x8a, 0x63, 0xcd, 0x98, 0x4e,
+ 0xff, 0xfd, 0x3c, 0x7a, 0x07, 0xa8, 0xfb, 0xf0, 0xb0, 0x0b, 0x17, 0xfe,
+ 0x8e, 0xdf, 0x77, 0xe4, 0xfb, 0xb3, 0xac, 0x5f, 0xfa, 0x34, 0x0c, 0x6c,
+ 0xd7, 0x84, 0xb1, 0x50, 0x8d, 0x9f, 0xaa, 0xf1, 0x1a, 0x86, 0x9e, 0xb3,
+ 0x14, 0xcd, 0x08, 0x3e, 0x43, 0xee, 0xfe, 0x8d, 0xe4, 0xfe, 0xe2, 0xc5,
+ 0xff, 0xf7, 0xa0, 0x7f, 0x13, 0x9b, 0xd6, 0x31, 0x74, 0xb1, 0x7f, 0xee,
+ 0x7f, 0x01, 0x37, 0x09, 0xfe, 0xb1, 0x7c, 0x76, 0x29, 0x2c, 0x53, 0x22,
+ 0xd3, 0x75, 0x4b, 0x88, 0x15, 0x0b, 0x91, 0x99, 0x2c, 0xbf, 0xe9, 0x0f,
+ 0x0e, 0x3b, 0x6f, 0x58, 0xba, 0x3e, 0xb1, 0x77, 0x0e, 0xb1, 0x4c, 0x78,
+ 0x73, 0x0a, 0x7c, 0x5e, 0x96, 0x2c, 0x6a, 0xc5, 0xed, 0x41, 0xab, 0x17,
+ 0xe6, 0xf1, 0x41, 0xd6, 0x2b, 0x63, 0x3e, 0x48, 0x0c, 0x98, 0x4f, 0xe3,
+ 0xd7, 0xfa, 0x0f, 0xad, 0x30, 0x38, 0xb1, 0x7b, 0xac, 0x31, 0x62, 0xd9,
+ 0x31, 0xe9, 0xfc, 0xd2, 0xff, 0xf9, 0xbd, 0xc6, 0xe9, 0xf5, 0xd6, 0x31,
+ 0x74, 0xb1, 0x63, 0x16, 0x2f, 0xf6, 0xa3, 0xdd, 0xcb, 0x3c, 0xb1, 0x7f,
+ 0xff, 0x64, 0xce, 0x53, 0x81, 0xbb, 0xe7, 0x58, 0xc5, 0xd2, 0xc5, 0xd8,
+ 0x35, 0x8b, 0xd3, 0xb9, 0xd6, 0x2e, 0x06, 0xa0, 0xda, 0xb0, 0xbd, 0xfb,
+ 0x47, 0x8c, 0xe2, 0xc5, 0x41, 0xe9, 0xe1, 0x5d, 0xff, 0xdd, 0xf3, 0xc5,
+ 0x9b, 0xfd, 0xe6, 0x1a, 0xc5, 0xf7, 0x27, 0x17, 0x16, 0x2a, 0x4a, 0x83,
+ 0x19, 0x46, 0x61, 0x32, 0x35, 0xe4, 0x39, 0x84, 0x40, 0x1a, 0x45, 0xcd,
+ 0x25, 0x8b, 0xfb, 0x37, 0xf8, 0x51, 0xd2, 0xc5, 0xfe, 0xff, 0xc4, 0x69,
+ 0xe3, 0x8b, 0x17, 0xd2, 0xf8, 0x7c, 0x58, 0xbe, 0x8d, 0xf1, 0xa5, 0x8a,
+ 0xda, 0x79, 0x33, 0x92, 0xdc, 0x68, 0xd6, 0x2f, 0xff, 0xb8, 0x59, 0xbd,
+ 0xfc, 0x59, 0xcf, 0xbc, 0xcb, 0x15, 0x87, 0xd4, 0xc3, 0x37, 0x7c, 0xeb,
+ 0x17, 0xe8, 0xf7, 0x03, 0xfa, 0xc5, 0x42, 0x77, 0x03, 0x17, 0xc3, 0x16,
+ 0x7f, 0x9a, 0x11, 0xe7, 0x20, 0x21, 0x8b, 0xe2, 0x6e, 0xe4, 0xb1, 0x78,
+ 0x0f, 0xf5, 0x8b, 0xfd, 0x3e, 0x30, 0xdd, 0xcd, 0x58, 0xac, 0x3d, 0x17,
+ 0x1d, 0xbf, 0xb5, 0x03, 0x82, 0x99, 0x62, 0xdc, 0x58, 0xa9, 0xcf, 0x03,
+ 0xe5, 0xd6, 0xd9, 0x0a, 0xb6, 0x25, 0xbb, 0x02, 0x84, 0xe4, 0x83, 0x2a,
+ 0xc9, 0x41, 0x5d, 0x42, 0x8b, 0xb2, 0x19, 0xa1, 0x51, 0xa6, 0xf3, 0x90,
+ 0x7e, 0x74, 0x8d, 0xe1, 0x18, 0x08, 0x49, 0x94, 0x25, 0x39, 0x28, 0xd3,
+ 0xd2, 0x88, 0xc4, 0xcf, 0xb8, 0xe8, 0x1b, 0x05, 0xee, 0x1f, 0x8b, 0x17,
+ 0xf8, 0x2b, 0x0d, 0xe9, 0x67, 0x16, 0x2f, 0xff, 0x9b, 0xcd, 0xa7, 0x04,
+ 0x7d, 0xba, 0x80, 0x2c, 0x5f, 0xff, 0xf7, 0xe0, 0xee, 0x4c, 0x50, 0x53,
+ 0x9f, 0x0e, 0x13, 0x06, 0xb1, 0x74, 0xa4, 0xb1, 0x7f, 0xf6, 0x14, 0x61,
+ 0xb1, 0x2f, 0x64, 0xeb, 0x17, 0xfe, 0x7f, 0xed, 0x8c, 0xf7, 0xd8, 0xeb,
+ 0x17, 0xff, 0xf9, 0xbd, 0x1f, 0x2c, 0xf6, 0xa3, 0xe5, 0x9b, 0xc5, 0xd2,
+ 0xc5, 0xff, 0xf4, 0x67, 0xbe, 0xf2, 0xd0, 0x87, 0x05, 0x0b, 0x15, 0x25,
+ 0x40, 0x2c, 0x9f, 0xba, 0xcd, 0xf1, 0x81, 0x22, 0x6f, 0x40, 0x08, 0xc5,
+ 0x7c, 0x63, 0xeb, 0x8b, 0x17, 0xff, 0x9b, 0xee, 0xd3, 0xf9, 0x89, 0x81,
+ 0xc5, 0x8b, 0xfe, 0x28, 0x96, 0x73, 0x1a, 0x16, 0x2d, 0x3a, 0xc5, 0x41,
+ 0xe4, 0x91, 0xb5, 0xff, 0xff, 0x40, 0x0e, 0xf2, 0xdb, 0xef, 0xe1, 0xf3,
+ 0xa8, 0xfc, 0x1d, 0x62, 0xff, 0xf9, 0x8b, 0xc2, 0xfb, 0x73, 0x71, 0xfd,
+ 0x83, 0x58, 0xaf, 0xa2, 0xef, 0xcd, 0x37, 0xf3, 0x4f, 0xb5, 0xc8, 0x0b,
+ 0x17, 0xff, 0xfd, 0xf7, 0x6e, 0x61, 0xae, 0x40, 0xdb, 0x9b, 0xb0, 0x4e,
+ 0x6a, 0xc5, 0xe7, 0x7e, 0x95, 0x16, 0xd1, 0x50, 0x89, 0x4e, 0x9a, 0xaf,
+ 0xf8, 0x98, 0xdd, 0x64, 0xf1, 0xe5, 0x8b, 0xff, 0xfe, 0x7f, 0x73, 0x67,
+ 0x3d, 0xac, 0xf8, 0x9b, 0xed, 0xc8, 0x3a, 0xc5, 0xff, 0xfd, 0x0f, 0xe8,
+ 0xfc, 0x71, 0x9a, 0x4d, 0xac, 0x1a, 0xc5, 0xfd, 0xf8, 0x3c, 0x30, 0xd6,
+ 0x29, 0x95, 0x19, 0x4c, 0x47, 0xa8, 0x62, 0x1c, 0x8c, 0x8e, 0xb8, 0xd3,
+ 0xe5, 0x8b, 0xf9, 0xe4, 0x3f, 0xb1, 0xd6, 0x2f, 0xf6, 0x4c, 0x50, 0x7d,
+ 0xbd, 0x2c, 0x5d, 0xf6, 0x19, 0xf2, 0xf8, 0xba, 0xff, 0xf7, 0xf2, 0x4e,
+ 0x5e, 0x79, 0x31, 0xb0, 0xb1, 0x7f, 0xd9, 0x9d, 0x6e, 0x0b, 0xed, 0xa5,
+ 0x8b, 0xff, 0xbf, 0x93, 0xf1, 0xb5, 0x01, 0x1c, 0x96, 0x2e, 0xc6, 0x58,
+ 0xae, 0x8f, 0x73, 0x7a, 0x35, 0xef, 0x01, 0x96, 0x2f, 0xe8, 0xd8, 0xb9,
+ 0x3e, 0x18, 0xb1, 0x50, 0x7e, 0xf8, 0x4b, 0xa1, 0xdb, 0x05, 0x16, 0x2f,
+ 0xe3, 0x5b, 0xc4, 0xfd, 0xac, 0x5f, 0xfb, 0xd0, 0x72, 0x73, 0x4b, 0x00,
+ 0xb1, 0x50, 0x7d, 0xb8, 0x5f, 0x60, 0x2c, 0x54, 0xc8, 0xb5, 0x28, 0x41,
+ 0xf8, 0x82, 0xff, 0xcc, 0x43, 0x88, 0x38, 0x47, 0x92, 0xc5, 0xff, 0x40,
+ 0x3f, 0x13, 0x96, 0x71, 0x62, 0xa0, 0xfe, 0x04, 0x7f, 0x7f, 0xf9, 0xb5,
+ 0x19, 0xf1, 0x37, 0x3f, 0x80, 0x58, 0xbf, 0xfe, 0x18, 0xbd, 0xc1, 0xe4,
+ 0xbf, 0x1b, 0xc7, 0x0b, 0x14, 0x34, 0x4e, 0x32, 0x4d, 0x82, 0x8b, 0x17,
+ 0xfd, 0x12, 0x8d, 0x4f, 0x1a, 0x9d, 0x62, 0xff, 0xf4, 0x4b, 0xf0, 0x46,
+ 0x96, 0x4e, 0x1c, 0x96, 0x2f, 0xff, 0xf4, 0x31, 0x3f, 0x85, 0xec, 0x1c,
+ 0x1c, 0x7f, 0x8e, 0xd6, 0x2f, 0xf3, 0x1c, 0x71, 0xc0, 0xf8, 0xb1, 0x7b,
+ 0xd9, 0xd2, 0xc5, 0xff, 0xf1, 0x36, 0xf6, 0xf7, 0xe3, 0xdc, 0x8d, 0xf0,
+ 0xb1, 0x4c, 0x9a, 0x8e, 0x93, 0x3e, 0xc1, 0xe3, 0x51, 0x0f, 0x5f, 0xe1,
+ 0xe1, 0x49, 0xbe, 0x25, 0x8b, 0x0d, 0x62, 0xfe, 0x17, 0x5f, 0x8d, 0x62,
+ 0xc5, 0xee, 0xf9, 0xf5, 0x8a, 0xc3, 0xce, 0x72, 0xfa, 0x64, 0x59, 0xb9,
+ 0x9f, 0x18, 0x2f, 0xfe, 0xf3, 0xb6, 0x46, 0x9e, 0x4d, 0xf5, 0x8b, 0xf3,
+ 0x8f, 0x08, 0x0b, 0x15, 0x23, 0xe9, 0x64, 0x2b, 0xfe, 0x8d, 0x6d, 0xe4,
+ 0x7d, 0xd9, 0x62, 0xfe, 0x67, 0x97, 0x9a, 0x75, 0x8b, 0xe9, 0xe3, 0xec,
+ 0xb1, 0x5f, 0x3d, 0x17, 0x2e, 0xbe, 0x8c, 0x26, 0x58, 0xbe, 0xf4, 0x60,
+ 0xd6, 0x28, 0x67, 0x85, 0xd9, 0x05, 0xef, 0x64, 0xeb, 0x14, 0x14, 0x67,
+ 0xe7, 0x05, 0x47, 0xa2, 0x51, 0xc4, 0xed, 0x92, 0x24, 0x1c, 0x24, 0xb2,
+ 0x58, 0x6f, 0x50, 0xcf, 0x62, 0xd9, 0x92, 0x75, 0x18, 0x81, 0xe1, 0xc5,
+ 0xf8, 0x56, 0xbc, 0x2f, 0x40, 0x44, 0x42, 0xdc, 0x8e, 0x33, 0xd0, 0xfd,
+ 0x14, 0x25, 0xcc, 0x21, 0xdc, 0x84, 0x58, 0x6c, 0x61, 0x08, 0xef, 0x66,
+ 0x1a, 0xb1, 0x7f, 0x44, 0xb8, 0xf9, 0xd2, 0xc5, 0xd1, 0xb3, 0xa3, 0xcb,
+ 0xf8, 0xed, 0xff, 0x46, 0x9f, 0xc0, 0x0c, 0xa4, 0xb1, 0x7f, 0x09, 0xc8,
+ 0xb0, 0x0b, 0x17, 0xff, 0xf6, 0xa3, 0xcd, 0xd3, 0x0e, 0x1b, 0x4d, 0x26,
+ 0xe2, 0xc5, 0xfc, 0x6b, 0xe8, 0x62, 0x25, 0x8b, 0xf3, 0x1d, 0xfd, 0x0b,
+ 0x17, 0xfb, 0xcd, 0xd3, 0x0f, 0xb2, 0x58, 0xbf, 0xa0, 0xf8, 0x2c, 0x3a,
+ 0xc5, 0x41, 0xf1, 0x31, 0xad, 0xff, 0xff, 0xff, 0x86, 0x51, 0xd7, 0x7d,
+ 0x37, 0x67, 0x72, 0x37, 0x09, 0xfb, 0x33, 0xaf, 0xb4, 0xc4, 0xc7, 0xe2,
+ 0xc5, 0xf7, 0x83, 0xc0, 0x8b, 0x17, 0xfe, 0x6f, 0x47, 0x9b, 0x7c, 0x17,
+ 0x4b, 0x17, 0x77, 0x25, 0x8a, 0xc4, 0xc7, 0xda, 0x14, 0x0e, 0x4c, 0x24,
+ 0x0b, 0xed, 0x76, 0x29, 0xd6, 0x2f, 0xdb, 0x8d, 0xac, 0x35, 0x62, 0xb0,
+ 0xf4, 0x88, 0x9a, 0xef, 0x7d, 0x62, 0xff, 0xb3, 0xdc, 0x0f, 0x9e, 0xcf,
+ 0xac, 0x54, 0xe7, 0xa6, 0x71, 0x8b, 0xc7, 0x8e, 0x96, 0x2f, 0x8a, 0x0f,
+ 0xc5, 0x8b, 0x34, 0xe7, 0x81, 0xe1, 0xeb, 0xf3, 0xf7, 0x20, 0xf8, 0xb1,
+ 0x7f, 0xe6, 0x9b, 0x9b, 0xdc, 0xa7, 0x10, 0xd6, 0x2d, 0xb3, 0x3a, 0xe5,
+ 0xa8, 0xce, 0xb0, 0xb0, 0xd5, 0xa9, 0x8b, 0xf5, 0x08, 0x9f, 0xc6, 0x7e,
+ 0x50, 0x92, 0xe3, 0x9f, 0x98, 0xf7, 0x94, 0x06, 0x57, 0x5b, 0x2b, 0xef,
+ 0x99, 0x1e, 0x90, 0x27, 0x39, 0x6e, 0x3f, 0xd6, 0x2f, 0xda, 0xe9, 0xdf,
+ 0xa5, 0x45, 0xca, 0x5f, 0xce, 0x3f, 0xc1, 0x4e, 0xb1, 0x71, 0xbf, 0x58,
+ 0xb9, 0xce, 0xb1, 0x6e, 0x2c, 0x54, 0x1a, 0x97, 0x17, 0xb6, 0xc8, 0xd1,
+ 0xbd, 0x83, 0x1f, 0x37, 0x72, 0xe2, 0x42, 0xb0, 0x58, 0xb1, 0x73, 0x1d,
+ 0x62, 0xe6, 0x35, 0x62, 0xfd, 0xae, 0x9d, 0xfa, 0x54, 0x5d, 0xa5, 0xfc,
+ 0x78, 0xe9, 0x89, 0xd6, 0x2f, 0x4f, 0x86, 0x2c, 0x5e, 0x06, 0xf7, 0x58,
+ 0xbf, 0xe6, 0x94, 0x98, 0x81, 0x12, 0x58, 0xb8, 0xfb, 0x8b, 0x17, 0xfd,
+ 0xe8, 0x26, 0x06, 0xe3, 0xce, 0xb1, 0x7b, 0x4e, 0x05, 0x8a, 0xc3, 0xd9,
+ 0x63, 0xcb, 0x69, 0x62, 0xe9, 0xe1, 0x62, 0xb0, 0xd5, 0x38, 0x95, 0xb6,
+ 0x42, 0xc4, 0xff, 0x60, 0x5c, 0x62, 0xf8, 0x30, 0xc6, 0xe7, 0x2d, 0xf8,
+ 0xfb, 0x8f, 0x91, 0xc7, 0x1d, 0x04, 0x95, 0x51, 0x0c, 0x2b, 0xd9, 0xca,
+ 0xe5, 0x5d, 0x87, 0x0e, 0x58, 0xc6, 0x25, 0x9b, 0x69, 0xbf, 0x9a, 0xf3,
+ 0x8c, 0x77, 0x61, 0x97, 0xfa, 0xc5, 0xec, 0xab, 0x89, 0xce, 0x46, 0x43,
+ 0xe9, 0x49, 0xb7, 0xfb, 0x67, 0x35, 0xd3, 0xbf, 0x4a, 0x8a, 0x9c, 0xbf,
+ 0xda, 0xf3, 0x7a, 0x71, 0x71, 0x62, 0xee, 0x71, 0x62, 0xdb, 0x38, 0x79,
+ 0xda, 0x36, 0xbf, 0xff, 0x68, 0x46, 0xff, 0x0b, 0xaf, 0xb6, 0xe3, 0x41,
+ 0x8b, 0x17, 0xe1, 0xe6, 0x03, 0x8b, 0x16, 0xd9, 0x64, 0x41, 0xf1, 0x6e,
+ 0x89, 0x1b, 0x1b, 0xe1, 0x5b, 0x7f, 0xf3, 0x6f, 0x8f, 0xb4, 0x4d, 0x34,
+ 0x74, 0xb1, 0x74, 0xf8, 0xb1, 0x7d, 0xc2, 0xff, 0x96, 0x2f, 0xf7, 0xe3,
+ 0x90, 0x71, 0x4c, 0xb1, 0x7e, 0xe8, 0xa3, 0xf8, 0xb1, 0x70, 0xa7, 0x58,
+ 0xbe, 0x14, 0xa2, 0x75, 0x8b, 0xfe, 0xee, 0x5c, 0xdb, 0x9b, 0xdf, 0x4b,
+ 0x15, 0x24, 0x7e, 0x0c, 0x8d, 0x8d, 0x66, 0x28, 0xd0, 0xcf, 0xc9, 0x2f,
+ 0xe1, 0x76, 0x77, 0x72, 0x58, 0xb7, 0x96, 0x2f, 0xbb, 0xe4, 0x0d, 0x62,
+ 0xc2, 0x58, 0xbd, 0x0f, 0x3e, 0xd3, 0x6c, 0x02, 0x4a, 0x63, 0xfc, 0x24,
+ 0x8b, 0xee, 0x9d, 0xfa, 0x54, 0x57, 0x25, 0xc7, 0x85, 0x8b, 0xf6, 0xba,
+ 0x77, 0xe9, 0x51, 0x67, 0x17, 0xfe, 0x35, 0xbb, 0xe1, 0x61, 0x8e, 0x05,
+ 0x8b, 0x6c, 0xc2, 0x23, 0xf0, 0x5f, 0xc6, 0xf7, 0x82, 0x3f, 0xd6, 0x2e,
+ 0x79, 0x2c, 0x5f, 0xd2, 0xf7, 0x7d, 0x37, 0x16, 0x29, 0xcf, 0x20, 0x42,
+ 0xf7, 0xf3, 0x73, 0x09, 0xcc, 0x58, 0xbc, 0x29, 0x42, 0xc5, 0xff, 0xa2,
+ 0x67, 0x6e, 0xf9, 0xb6, 0x79, 0xd6, 0x2b, 0x4a, 0x83, 0xbf, 0x0c, 0x07,
+ 0x37, 0x26, 0x7f, 0x10, 0xef, 0x2d, 0x08, 0x3b, 0x7f, 0xf7, 0xda, 0x6f,
+ 0xc1, 0x0c, 0xa2, 0x4b, 0x17, 0xff, 0xa5, 0xf1, 0x6b, 0x07, 0x01, 0x3e,
+ 0xdd, 0x2c, 0x5f, 0xfe, 0xf4, 0x73, 0x68, 0xb9, 0xe8, 0x9a, 0x66, 0x58,
+ 0xbf, 0xff, 0x3f, 0xf0, 0xf0, 0x7d, 0xb9, 0x86, 0x9a, 0xf2, 0x58, 0xbf,
+ 0x98, 0xf3, 0x8b, 0x52, 0x58, 0xbf, 0x1f, 0x26, 0x70, 0x2c, 0x5f, 0x4f,
+ 0xf7, 0xf2, 0xc5, 0x39, 0xe6, 0x88, 0xa6, 0xf8, 0xfb, 0x00, 0x57, 0xcb,
+ 0x17, 0xe8, 0x9a, 0x68, 0xe9, 0x62, 0xe8, 0xfe, 0xd3, 0xd8, 0x62, 0xda,
+ 0xc4, 0xf2, 0xe6, 0x4f, 0xfa, 0xc1, 0x3e, 0xef, 0x79, 0xbf, 0xe2, 0x83,
+ 0xf0, 0x52, 0x73, 0x56, 0x2e, 0x3e, 0xf5, 0x8b, 0xc5, 0x03, 0x58, 0xac,
+ 0x36, 0xce, 0x35, 0x77, 0xf1, 0x62, 0xfd, 0x93, 0x4c, 0x29, 0xd6, 0x2b,
+ 0x0f, 0x0f, 0xe2, 0xf7, 0xda, 0x00, 0x21, 0x62, 0xff, 0x9b, 0xad, 0xbc,
+ 0x98, 0x9c, 0xc5, 0x8a, 0x35, 0x10, 0x4c, 0x43, 0xf2, 0x3b, 0xf4, 0xd0,
+ 0x78, 0x0d, 0x62, 0xfd, 0xb4, 0x79, 0xc1, 0x2c, 0x5f, 0xff, 0xf6, 0x9b,
+ 0x80, 0xcd, 0xad, 0xbe, 0x3e, 0xd1, 0x34, 0xd1, 0xd2, 0xc5, 0xd2, 0x3a,
+ 0xc5, 0x42, 0x61, 0x38, 0x60, 0xc5, 0x4e, 0x56, 0x4d, 0x97, 0xe3, 0xc1,
+ 0xf0, 0x96, 0x2f, 0x09, 0xf8, 0xb1, 0x7f, 0x83, 0x69, 0xa3, 0x8c, 0x75,
+ 0x8b, 0xff, 0xdf, 0x6d, 0xbf, 0x76, 0xf4, 0x60, 0xd9, 0x62, 0xf7, 0xbe,
+ 0xcb, 0x17, 0xfd, 0xad, 0xb0, 0x76, 0xdd, 0x79, 0x96, 0x2a, 0x0f, 0x71,
+ 0x87, 0x6f, 0x6d, 0x6d, 0x2c, 0x5f, 0x74, 0xef, 0xd2, 0xa2, 0x42, 0x2f,
+ 0xf4, 0x4b, 0x58, 0x37, 0x3a, 0xc5, 0x1a, 0x8a, 0x39, 0x88, 0x34, 0x3f,
+ 0xc3, 0x1b, 0xfe, 0xcf, 0x70, 0x52, 0x89, 0xe1, 0x62, 0xff, 0xfc, 0xda,
+ 0xeb, 0xf9, 0xb7, 0x5a, 0xc3, 0x37, 0x20, 0xeb, 0x15, 0x24, 0x4b, 0xf0,
+ 0xea, 0xff, 0x4d, 0xf8, 0xe6, 0xd6, 0x35, 0x62, 0xfe, 0x77, 0xee, 0x5c,
+ 0x65, 0x8b, 0xfc, 0x08, 0xdd, 0x8f, 0x40, 0xd6, 0x2f, 0xf8, 0xf8, 0xfa,
+ 0x9f, 0x6f, 0x67, 0x58, 0xa8, 0x3f, 0x4c, 0x36, 0xbf, 0xf0, 0xf3, 0x90,
+ 0x64, 0x37, 0x7c, 0x58, 0xbf, 0xdd, 0xf3, 0xc5, 0x07, 0xe2, 0xc5, 0xff,
+ 0xe7, 0x2e, 0xb6, 0x8c, 0x9e, 0x5f, 0x79, 0x2c, 0x53, 0x22, 0x04, 0x46,
+ 0xb7, 0xf6, 0x13, 0x03, 0x90, 0xb1, 0x50, 0xb9, 0x01, 0x23, 0x5c, 0x8d,
+ 0x27, 0xb8, 0x6b, 0x31, 0x1e, 0x8e, 0x3f, 0x0a, 0x27, 0x20, 0x04, 0x30,
+ 0x78, 0x45, 0x71, 0x62, 0xc5, 0x6d, 0x5d, 0x53, 0xd9, 0x9c, 0x9d, 0x68,
+ 0x50, 0x5c, 0xdf, 0x58, 0xbf, 0xf3, 0x87, 0x31, 0x37, 0x8a, 0x00, 0xb1,
+ 0x53, 0xaf, 0x0a, 0x4a, 0x75, 0xeb, 0xb4, 0x4f, 0x0b, 0xdf, 0xf9, 0x8f,
+ 0x9c, 0xdb, 0xdc, 0xb3, 0xcb, 0x17, 0xdc, 0x18, 0xe1, 0x62, 0xbe, 0x7c,
+ 0xbe, 0x42, 0xbe, 0x97, 0xc3, 0xe2, 0xc5, 0xff, 0xfc, 0x00, 0x6c, 0x02,
+ 0x98, 0x2d, 0x04, 0xde, 0x41, 0x6b, 0x6e, 0xdf, 0xee, 0x2c, 0x5d, 0xb0,
+ 0xf6, 0x05, 0x8b, 0x8d, 0x02, 0xc5, 0xff, 0xfb, 0xed, 0x37, 0xdb, 0xbf,
+ 0x7f, 0xa6, 0xe6, 0x0d, 0x62, 0xfa, 0x18, 0x5c, 0x58, 0xb6, 0xce, 0xc2,
+ 0x45, 0xbc, 0x11, 0xf4, 0x33, 0xf5, 0x9a, 0x84, 0xf1, 0xb0, 0x8b, 0xe4,
+ 0xaf, 0x19, 0x9d, 0xef, 0xc1, 0xd6, 0x2f, 0xff, 0xd8, 0x08, 0x06, 0xb5,
+ 0x06, 0x6d, 0xd3, 0xbc, 0x96, 0x2f, 0xfe, 0x89, 0xe3, 0x6c, 0x4d, 0x1c,
+ 0x14, 0xcb, 0x17, 0x9b, 0x73, 0x16, 0x2a, 0x47, 0xd1, 0xe4, 0x9a, 0xd8,
+ 0x11, 0xfe, 0x43, 0xa2, 0x86, 0x05, 0xfb, 0x9c, 0xcd, 0x4e, 0xb1, 0x7b,
+ 0x90, 0x6a, 0xc5, 0x7c, 0xf2, 0x38, 0x55, 0x74, 0x18, 0xb1, 0x7f, 0xc0,
+ 0xc1, 0x93, 0x82, 0x37, 0xac, 0x5f, 0xf6, 0x4f, 0xc6, 0xc3, 0xc7, 0x4b,
+ 0x15, 0x88, 0xae, 0x62, 0x27, 0x18, 0xe1, 0xd5, 0xff, 0xa6, 0x7f, 0x7c,
+ 0x5d, 0x7f, 0x26, 0x58, 0xbb, 0x7c, 0x96, 0x2a, 0x63, 0xdd, 0x3a, 0x1d,
+ 0xfa, 0x35, 0xb4, 0x1e, 0x58, 0xb0, 0x6b, 0x17, 0xff, 0x40, 0x0e, 0xf2,
+ 0xe7, 0xb3, 0x0e, 0xb1, 0x43, 0x3d, 0x7f, 0x89, 0xde, 0x98, 0xf3, 0x2c,
+ 0x5b, 0x67, 0x62, 0x6d, 0xae, 0x82, 0xd2, 0x44, 0x46, 0x29, 0x3a, 0xb8,
+ 0xe1, 0x55, 0x92, 0x8b, 0xba, 0x6d, 0xed, 0x11, 0xa5, 0x0c, 0xcc, 0x98,
+ 0x77, 0x0f, 0xc7, 0xda, 0xf3, 0xcb, 0x45, 0x29, 0xd7, 0x91, 0xa0, 0x7a,
+ 0x32, 0xf1, 0x42, 0x5c, 0xc2, 0x30, 0xe1, 0x04, 0x10, 0x8a, 0xff, 0x09,
+ 0xf5, 0x2f, 0x98, 0xeb, 0x17, 0xff, 0xff, 0xf4, 0x78, 0x9c, 0x04, 0xfb,
+ 0xdb, 0x79, 0x0b, 0x81, 0x94, 0x0f, 0xef, 0x2c, 0xe2, 0xc5, 0xff, 0x83,
+ 0x28, 0x1f, 0xde, 0x59, 0xc5, 0x8b, 0xfe, 0x28, 0x1f, 0xde, 0x59, 0xc5,
+ 0x8b, 0xfc, 0xfb, 0xdb, 0x79, 0x0b, 0x9b, 0x4f, 0xdc, 0x33, 0xfb, 0xd9,
+ 0xde, 0xc8, 0xd3, 0x86, 0xd1, 0xa9, 0x46, 0x03, 0x7f, 0xf6, 0xcf, 0xdf,
+ 0x85, 0x9e, 0xf4, 0x01, 0x62, 0xff, 0xf6, 0xc9, 0xde, 0x5b, 0x39, 0xae,
+ 0x9d, 0xfa, 0x54, 0x4f, 0x85, 0xff, 0xe9, 0x6c, 0xe6, 0xf6, 0x37, 0x9c,
+ 0x83, 0x89, 0x62, 0xff, 0xb0, 0xcc, 0xde, 0xde, 0x94, 0x2c, 0x5f, 0xf3,
+ 0x90, 0xff, 0x07, 0x08, 0x25, 0x8b, 0xda, 0x8e, 0x2c, 0x53, 0x1e, 0xc0,
+ 0x8e, 0xef, 0xfd, 0xdf, 0xa6, 0x93, 0xea, 0x7f, 0x89, 0x62, 0xf8, 0xf9,
+ 0x9d, 0x2c, 0x5e, 0xde, 0x38, 0x58, 0xbf, 0x88, 0x98, 0xfe, 0xc5, 0x8b,
+ 0xdb, 0x9b, 0x11, 0x8b, 0x15, 0x87, 0xe4, 0xe3, 0xe1, 0x0b, 0x2f, 0xc6,
+ 0xbf, 0xb0, 0xc5, 0x8b, 0xfa, 0x70, 0xf7, 0x1c, 0x80, 0xb1, 0x7f, 0xcd,
+ 0x26, 0xf8, 0x8e, 0x76, 0x58, 0xbf, 0xec, 0x9a, 0x4f, 0xa9, 0xfe, 0x25,
+ 0x8b, 0xa2, 0x65, 0x8b, 0xce, 0x40, 0x23, 0xd4, 0xf1, 0xe5, 0x42, 0x3c,
+ 0x7c, 0x67, 0xb9, 0x08, 0xdb, 0x6c, 0xce, 0xac, 0x38, 0x70, 0x93, 0xc2,
+ 0x17, 0x44, 0x28, 0x4a, 0x88, 0xbc, 0x38, 0xc6, 0xe9, 0xd5, 0xee, 0xfa,
+ 0x5a, 0xfd, 0x74, 0xe8, 0x0e, 0x9a, 0x36, 0xbd, 0xda, 0xdb, 0x8f, 0x52,
+ 0xbc, 0xce, 0x97, 0xf4, 0x77, 0x9c, 0x3c, 0xbf, 0xfc, 0x16, 0x1a, 0x66,
+ 0xec, 0xe3, 0xd8, 0xb6, 0xed, 0xfe, 0xe2, 0xc5, 0xfc, 0xfe, 0xe1, 0x73,
+ 0xcb, 0x17, 0xe7, 0x10, 0x5c, 0xee, 0xb1, 0x44, 0x7b, 0x5e, 0x2e, 0xbf,
+ 0xff, 0x84, 0x4e, 0x6e, 0xdf, 0x1b, 0x05, 0x2c, 0xfb, 0x1d, 0x62, 0xe6,
+ 0xed, 0x62, 0xff, 0xfa, 0x53, 0x85, 0x91, 0xb0, 0x4f, 0xd6, 0xb6, 0xed,
+ 0xfe, 0xe2, 0xc5, 0x48, 0xff, 0xc0, 0x31, 0x70, 0x7c, 0x58, 0xbf, 0xfa,
+ 0x7f, 0xc3, 0x7b, 0x8c, 0x5d, 0xc9, 0x62, 0xbe, 0x7b, 0xe4, 0x33, 0x7f,
+ 0xf6, 0x79, 0xb0, 0xbf, 0x9e, 0x81, 0xac, 0x5f, 0xfb, 0xc6, 0xc1, 0x4b,
+ 0x3e, 0xc7, 0x58, 0xbf, 0xe3, 0x60, 0xa5, 0x9f, 0x63, 0xac, 0x5f, 0x08,
+ 0x9c, 0xdd, 0xa7, 0xf1, 0xe3, 0xfb, 0xf6, 0x80, 0xdf, 0x85, 0x8a, 0x39,
+ 0xf1, 0x88, 0xee, 0xfd, 0x9a, 0xcc, 0x99, 0x62, 0xdb, 0x32, 0x57, 0x8d,
+ 0x90, 0xbf, 0x39, 0x0f, 0xe1, 0xba, 0xf0, 0x81, 0x22, 0x1e, 0x46, 0x3a,
+ 0x19, 0x15, 0xfb, 0x5d, 0x3b, 0xf4, 0xa8, 0xac, 0x8b, 0xff, 0x3c, 0xb6,
+ 0x73, 0x5d, 0x3b, 0xf4, 0xa8, 0x9b, 0x8b, 0x6c, 0xe2, 0x21, 0xce, 0x6f,
+ 0x5d, 0x26, 0x82, 0xd1, 0x8b, 0x5f, 0xff, 0x3f, 0x5b, 0x33, 0xe1, 0x9c,
+ 0x8f, 0x7f, 0x09, 0x62, 0xff, 0x89, 0xf6, 0x79, 0x00, 0x88, 0x58, 0xbc,
+ 0x14, 0xef, 0xa5, 0x8b, 0xff, 0xe9, 0x37, 0xdc, 0xbd, 0x2c, 0xd6, 0x05,
+ 0x36, 0x35, 0x8b, 0xff, 0x0d, 0x88, 0x5d, 0x67, 0x02, 0x9b, 0x1a, 0xc5,
+ 0xff, 0xef, 0x37, 0xc5, 0xf7, 0x6e, 0xf9, 0x06, 0xac, 0x54, 0x22, 0x57,
+ 0x12, 0x6f, 0xba, 0x77, 0xe9, 0x51, 0x2b, 0x17, 0xff, 0xda, 0x9c, 0xa3,
+ 0x4e, 0x32, 0x7d, 0x46, 0xf5, 0x8a, 0xd2, 0x20, 0x84, 0x63, 0x7f, 0xce,
+ 0xd2, 0x62, 0x14, 0x1d, 0x62, 0xfa, 0x06, 0xff, 0x58, 0xb3, 0x2c, 0x52,
+ 0xc5, 0xfe, 0x69, 0x31, 0x0a, 0x0e, 0xb1, 0x7e, 0x27, 0x6e, 0xfa, 0x39,
+ 0xbe, 0x70, 0xca, 0x24, 0x57, 0x6f, 0x22, 0x08, 0x9f, 0x7f, 0x31, 0x44,
+ 0xa0, 0x22, 0xc5, 0xe6, 0x8f, 0x2c, 0x54, 0x1e, 0x56, 0x8b, 0xaf, 0x84,
+ 0x3c, 0x35, 0x62, 0xf3, 0xcb, 0x67, 0x61, 0xab, 0x7e, 0x82, 0x41, 0xc3,
+ 0xb7, 0x21, 0x47, 0xd1, 0x1b, 0x43, 0x97, 0x8f, 0xbb, 0x84, 0x35, 0x3a,
+ 0xe5, 0x57, 0x4a, 0xa7, 0x97, 0x71, 0x7e, 0xd9, 0x79, 0xb9, 0x8b, 0x17,
+ 0xed, 0x9c, 0x94, 0x01, 0x62, 0xb6, 0x51, 0x27, 0x39, 0xe4, 0x8b, 0x2f,
+ 0xfd, 0xec, 0xd9, 0xcd, 0x34, 0xee, 0x75, 0x8b, 0xf8, 0x2a, 0xe7, 0xd4,
+ 0x71, 0x62, 0xff, 0xf0, 0x53, 0x63, 0x0a, 0xf3, 0x1e, 0x4d, 0x9a, 0xc5,
+ 0x8b, 0xff, 0x37, 0x04, 0x72, 0x6d, 0xe2, 0x75, 0x8b, 0xff, 0xef, 0xc4,
+ 0x98, 0x1a, 0xcf, 0xb9, 0x3c, 0x96, 0x2f, 0xff, 0x9f, 0x4f, 0xf9, 0x67,
+ 0xb8, 0xf3, 0x8a, 0x4b, 0x17, 0xf3, 0x49, 0x87, 0x87, 0x58, 0xbf, 0xec,
+ 0xf4, 0x1e, 0x06, 0xfe, 0x58, 0xae, 0x91, 0x6d, 0xf5, 0x12, 0x2d, 0xbf,
+ 0xa0, 0x9f, 0xa7, 0xdd, 0x58, 0xbe, 0x10, 0x41, 0xc2, 0xc5, 0xff, 0xfe,
+ 0x7e, 0xff, 0x9c, 0x8e, 0x71, 0xff, 0x1d, 0xfd, 0x8e, 0xb1, 0x7f, 0xd1,
+ 0xd4, 0x69, 0xbd, 0x1d, 0x2c, 0x54, 0x95, 0x32, 0xf6, 0x80, 0xd1, 0x82,
+ 0x1c, 0xc3, 0xe6, 0x04, 0x4b, 0xe6, 0x2b, 0xfe, 0xc3, 0x23, 0xed, 0x85,
+ 0xe5, 0x8b, 0x69, 0x62, 0xff, 0xc0, 0xf6, 0x7e, 0x0b, 0xdb, 0x98, 0xb1,
+ 0x43, 0x3d, 0x31, 0x09, 0x5f, 0xff, 0x7d, 0xc1, 0xcc, 0x27, 0x93, 0x0f,
+ 0x0e, 0xb1, 0x71, 0xc9, 0x62, 0xfe, 0x2c, 0xeb, 0xed, 0xa5, 0x81, 0x96,
+ 0xf7, 0xdd, 0x3b, 0xf4, 0xa8, 0x97, 0x0b, 0xff, 0x9b, 0x5f, 0x7e, 0x44,
+ 0xb0, 0x52, 0x58, 0xbf, 0xfe, 0xfe, 0x0e, 0x3f, 0x12, 0x28, 0xd3, 0x8d,
+ 0x62, 0x86, 0x9b, 0x2b, 0x32, 0xe8, 0xf7, 0xe6, 0x3c, 0x44, 0xbc, 0x4e,
+ 0x75, 0x8b, 0x4e, 0xb1, 0x7a, 0x59, 0xe7, 0x35, 0xe1, 0x07, 0x2f, 0x1b,
+ 0x26, 0x58, 0xbf, 0xff, 0xdf, 0x69, 0xce, 0xf2, 0xc1, 0x05, 0xf8, 0xff,
+ 0xe9, 0xb8, 0xb1, 0x7f, 0xff, 0xdd, 0x40, 0xba, 0xfb, 0x6b, 0x07, 0xc8,
+ 0x21, 0x74, 0xc6, 0xac, 0x54, 0x23, 0x47, 0x19, 0xef, 0x80, 0xfb, 0x86,
+ 0xac, 0x5f, 0xe7, 0x97, 0x8a, 0x0f, 0xc5, 0x8b, 0xff, 0x70, 0x46, 0xf3,
+ 0x0e, 0xdf, 0x85, 0x8b, 0xda, 0x8f, 0xac, 0x53, 0x1e, 0xee, 0x90, 0x2b,
+ 0x11, 0xb0, 0xc4, 0xef, 0x09, 0x0b, 0xf4, 0xb7, 0x1b, 0xee, 0xb1, 0x7f,
+ 0x9c, 0xb5, 0x04, 0xf2, 0x58, 0xb4, 0x2c, 0x57, 0x0f, 0x0b, 0x70, 0xc6,
+ 0xff, 0xe2, 0x93, 0x8d, 0xe2, 0x50, 0x4e, 0xb1, 0x50, 0x7c, 0xd8, 0x4b,
+ 0x7e, 0x28, 0xe9, 0xf4, 0xb1, 0x7f, 0xff, 0x60, 0xba, 0xfc, 0x14, 0x49,
+ 0xc7, 0x1d, 0xe9, 0x96, 0x2f, 0xfd, 0xc6, 0x21, 0x7b, 0x71, 0xb7, 0x9d,
+ 0x62, 0xff, 0xec, 0xf6, 0x7c, 0x9e, 0x42, 0x7e, 0x2c, 0x5f, 0xff, 0xfe,
+ 0xcf, 0x73, 0x06, 0xe3, 0x82, 0x7e, 0xff, 0x9c, 0x8e, 0x71, 0xfe, 0xb1,
+ 0x4c, 0x8b, 0x92, 0x43, 0xbc, 0xc5, 0x0b, 0x17, 0xfc, 0x23, 0x5c, 0xdc,
+ 0x9f, 0x27, 0x58, 0xa9, 0x2a, 0xec, 0x1c, 0x34, 0xd8, 0x83, 0x74, 0xa0,
+ 0xeb, 0x65, 0x0f, 0xdd, 0xe4, 0x3b, 0x83, 0x77, 0xfd, 0x87, 0x62, 0x03,
+ 0x7c, 0x4b, 0x17, 0xef, 0xb6, 0x9f, 0x8b, 0x17, 0xf0, 0xe1, 0xbf, 0x07,
+ 0x58, 0xbf, 0x0e, 0x37, 0x5f, 0x4b, 0x17, 0xa0, 0x81, 0x87, 0xb0, 0xe5,
+ 0xb5, 0xe4, 0x58, 0x04, 0x84, 0x05, 0x4e, 0x98, 0x96, 0x43, 0xa2, 0xfe,
+ 0xdf, 0x05, 0xd3, 0xf1, 0x62, 0xff, 0xe2, 0x89, 0x60, 0xf2, 0x58, 0x40,
+ 0x58, 0xbf, 0x38, 0x39, 0x84, 0xb1, 0x6f, 0x42, 0x26, 0x58, 0xc3, 0x88,
+ 0x57, 0xc0, 0x03, 0x76, 0xb1, 0x7e, 0x11, 0xa5, 0x80, 0x58, 0xbf, 0xe7,
+ 0xd1, 0xa5, 0x9e, 0xfb, 0x2c, 0x53, 0x22, 0x18, 0xe4, 0x84, 0x53, 0x7f,
+ 0xec, 0xf3, 0xf7, 0x92, 0xfc, 0x69, 0x62, 0xff, 0xa3, 0xee, 0xd2, 0x63,
+ 0x61, 0x62, 0xff, 0xff, 0xfe, 0x20, 0x39, 0x03, 0x98, 0x77, 0xfe, 0x0d,
+ 0xd8, 0xa3, 0xee, 0xd2, 0x61, 0xac, 0x5e, 0xee, 0x50, 0xb1, 0x74, 0x80,
+ 0xb1, 0x7f, 0x10, 0xa5, 0xf7, 0x96, 0x1b, 0x66, 0x1e, 0xbf, 0xf8, 0x52,
+ 0x26, 0x94, 0x78, 0x85, 0x25, 0x8b, 0xf4, 0x70, 0x07, 0xf2, 0xc5, 0x31,
+ 0xf6, 0xfd, 0x12, 0x86, 0x9e, 0x03, 0x1c, 0x72, 0x17, 0x3e, 0x85, 0x75,
+ 0xba, 0x58, 0xa8, 0x56, 0x83, 0x90, 0xba, 0x62, 0xe7, 0x8f, 0xfc, 0x08,
+ 0xf7, 0xf4, 0xbf, 0x85, 0x9d, 0x2c, 0x5e, 0x97, 0xfc, 0xb1, 0x4c, 0x79,
+ 0x9f, 0x2e, 0xbe, 0xef, 0xf1, 0xd2, 0xc5, 0xbf, 0x07, 0x8c, 0xe4, 0x37,
+ 0xff, 0x13, 0x03, 0x9a, 0x86, 0x93, 0xf1, 0x62, 0xff, 0xf1, 0x8f, 0xa8,
+ 0x63, 0xe0, 0xe2, 0x50, 0xb1, 0x7c, 0x07, 0x7d, 0x2c, 0x59, 0xe4, 0x7d,
+ 0x7d, 0xa4, 0xd6, 0x23, 0xf1, 0x89, 0xb9, 0x0a, 0xeb, 0xcd, 0x38, 0x5d,
+ 0x62, 0xfc, 0xc7, 0x27, 0x92, 0xc5, 0xff, 0xde, 0xfe, 0x6f, 0xfb, 0x1f,
+ 0x04, 0x17, 0x58, 0xad, 0xd4, 0x4a, 0x68, 0x89, 0xc9, 0xef, 0xfe, 0x13,
+ 0xee, 0xb4, 0xf9, 0xf6, 0xef, 0x8b, 0x17, 0xfa, 0x26, 0x7f, 0x7d, 0xc0,
+ 0xb1, 0x7f, 0xee, 0xe5, 0x9e, 0xcd, 0x75, 0x18, 0xb1, 0x79, 0xe5, 0xb3,
+ 0xb0, 0x36, 0x89, 0x7b, 0x0c, 0xca, 0x25, 0x5d, 0xce, 0xd7, 0x28, 0x45,
+ 0xe4, 0x70, 0xfd, 0xbc, 0xe8, 0xcc, 0xf0, 0xef, 0xfc, 0x3e, 0x5e, 0x58,
+ 0xf1, 0x47, 0x2b, 0xc9, 0xc0, 0x3f, 0x47, 0xc2, 0x28, 0x63, 0xee, 0x19,
+ 0x06, 0x92, 0x10, 0xd2, 0xff, 0xc2, 0x3e, 0xcf, 0x20, 0xbd, 0x9a, 0x58,
+ 0xbb, 0x7b, 0x2c, 0x5f, 0xfa, 0x3d, 0x1b, 0xe0, 0xba, 0x7e, 0x2c, 0x5e,
+ 0xcf, 0xec, 0xb1, 0xec, 0xf0, 0x66, 0xff, 0x87, 0x9b, 0x31, 0xa6, 0xf8,
+ 0x96, 0x2f, 0xfe, 0x1c, 0x6c, 0x84, 0xce, 0xe5, 0xf8, 0xe2, 0xc5, 0xb6,
+ 0x59, 0xb7, 0x3b, 0x3d, 0x69, 0x1b, 0xc8, 0xd5, 0xfd, 0x09, 0xb1, 0x1a,
+ 0xef, 0x3c, 0xbd, 0x04, 0x6a, 0xc5, 0xff, 0x4b, 0x67, 0x35, 0xd3, 0xbf,
+ 0x4a, 0x88, 0xec, 0xb6, 0xcf, 0xcf, 0xa1, 0xc7, 0x6f, 0xff, 0x85, 0x1d,
+ 0xc9, 0x8e, 0x66, 0x10, 0xff, 0x0b, 0x17, 0xff, 0xff, 0x1e, 0x3a, 0xeb,
+ 0xed, 0x37, 0xd8, 0x86, 0xfa, 0x83, 0x4d, 0x14, 0xeb, 0x17, 0x08, 0x35,
+ 0x8b, 0xe2, 0x77, 0xed, 0x62, 0xfb, 0xbf, 0x31, 0x8b, 0x15, 0x07, 0x8e,
+ 0x72, 0x2b, 0xa7, 0xd9, 0x1a, 0x69, 0x58, 0xa2, 0x77, 0x80, 0xd8, 0x2f,
+ 0xff, 0xf3, 0x83, 0x64, 0x38, 0x9f, 0x3d, 0x04, 0xc0, 0xce, 0xfc, 0xb1,
+ 0x7e, 0xe3, 0x6f, 0xfe, 0xf5, 0x8b, 0x8b, 0x8b, 0x17, 0xdf, 0xc9, 0x6c,
+ 0xc1, 0xe2, 0x39, 0x6d, 0x62, 0x66, 0x33, 0x27, 0x7a, 0x15, 0x37, 0x82,
+ 0xbb, 0x46, 0xb1, 0x7f, 0xc1, 0x5d, 0xcc, 0x35, 0xbc, 0x50, 0xb1, 0x7f,
+ 0x6c, 0x45, 0x1d, 0x61, 0x2c, 0x5c, 0x2f, 0xac, 0x5f, 0xc1, 0x52, 0xcf,
+ 0xbf, 0x96, 0x2c, 0x62, 0xc5, 0xff, 0x73, 0x98, 0x59, 0xa7, 0xf2, 0xc5,
+ 0xfd, 0xcc, 0x26, 0x00, 0x6b, 0x17, 0xb3, 0x50, 0xb1, 0x7f, 0xbf, 0x13,
+ 0xea, 0x30, 0x6b, 0x17, 0x64, 0xeb, 0x17, 0x82, 0x0e, 0x16, 0x2a, 0x0f,
+ 0xac, 0x8d, 0x04, 0x31, 0x7f, 0xff, 0xf7, 0xdd, 0xba, 0xc2, 0xdb, 0x2c,
+ 0xe7, 0xb3, 0xf0, 0x5e, 0xfb, 0x2c, 0x5f, 0xff, 0xa4, 0xc3, 0xfb, 0x6f,
+ 0xdb, 0x83, 0xd3, 0x0b, 0xa5, 0x8b, 0xe8, 0xd4, 0x69, 0x62, 0xb6, 0x25,
+ 0x43, 0x98, 0x26, 0xc7, 0x1a, 0x2e, 0xfc, 0x21, 0xc8, 0xb7, 0xce, 0x41,
+ 0xad, 0xde, 0x9a, 0x27, 0x58, 0xbe, 0x82, 0xf7, 0x16, 0x2e, 0xc3, 0x20,
+ 0xf0, 0x78, 0x3f, 0x7f, 0xee, 0x7b, 0x3f, 0x05, 0xef, 0xb2, 0xc5, 0xfe,
+ 0xf7, 0x22, 0x67, 0x7d, 0x2c, 0x5f, 0xf4, 0x67, 0x99, 0xe7, 0x8d, 0x2c,
+ 0x58, 0xeb, 0x16, 0x3a, 0xc5, 0x05, 0x4d, 0x20, 0x62, 0x57, 0xff, 0xe1,
+ 0xe6, 0xb6, 0xe1, 0xc5, 0x1a, 0xd3, 0x0b, 0xa5, 0x8a, 0xc4, 0xd3, 0x58,
+ 0xf8, 0x06, 0x9e, 0x5c, 0x11, 0x35, 0xc1, 0x4e, 0x2c, 0x5f, 0xc0, 0x2c,
+ 0xef, 0xd8, 0xb1, 0x74, 0xfb, 0xab, 0x17, 0xff, 0x6f, 0x81, 0xfb, 0x21,
+ 0xbd, 0x13, 0x2c, 0x5f, 0x1b, 0xfc, 0x02, 0xc5, 0xfc, 0xe6, 0x67, 0xa3,
+ 0xa5, 0x8a, 0x73, 0xd3, 0x22, 0x4b, 0xff, 0xff, 0x9c, 0xd8, 0xd0, 0x05,
+ 0x19, 0x9f, 0xe9, 0xa0, 0xa3, 0x3e, 0x25, 0x8b, 0xf8, 0x80, 0xfa, 0x70,
+ 0xd6, 0x2f, 0xff, 0xa3, 0xd1, 0xed, 0xbe, 0xfe, 0x13, 0xe8, 0xd5, 0x8a,
+ 0xd8, 0x15, 0x07, 0xc0, 0xe4, 0xe5, 0xcc, 0x39, 0xa8, 0x4c, 0xfc, 0x81,
+ 0xdc, 0x08, 0xba, 0xff, 0xfb, 0xfb, 0x4b, 0x1b, 0x4d, 0x3b, 0x9c, 0xec,
+ 0xb1, 0x7f, 0xff, 0xf7, 0xdc, 0x64, 0xfb, 0x79, 0xf8, 0xe6, 0xd1, 0x3e,
+ 0xd9, 0x66, 0xf8, 0x58, 0xbf, 0xe3, 0x76, 0xe3, 0x1b, 0xac, 0xe2, 0xc5,
+ 0x7d, 0x16, 0xc4, 0xf3, 0x7f, 0xf8, 0xb0, 0xdf, 0xbc, 0xbe, 0x63, 0x86,
+ 0x75, 0x8a, 0x83, 0xef, 0xc2, 0x2a, 0x64, 0xe5, 0xbf, 0x1b, 0xb5, 0xff,
+ 0x9b, 0x5b, 0x78, 0x58, 0x78, 0xe9, 0x62, 0xff, 0x0b, 0xcc, 0xfb, 0xde,
+ 0x4b, 0x17, 0xf8, 0xa0, 0x1b, 0x7e, 0xe7, 0x58, 0xbf, 0x9f, 0x78, 0xf0,
+ 0x8d, 0x58, 0xb4, 0x12, 0x26, 0xbc, 0x6a, 0x19, 0xad, 0xff, 0xff, 0xc0,
+ 0x82, 0xe9, 0xfc, 0xfd, 0x83, 0x6e, 0x13, 0x40, 0xbf, 0xf8, 0x58, 0xbf,
+ 0xf1, 0x0a, 0x5b, 0x71, 0x8a, 0x0e, 0xb1, 0x7f, 0x72, 0x4d, 0xd3, 0xe9,
+ 0x62, 0xf3, 0xbf, 0x4a, 0x8a, 0x84, 0xbf, 0x8d, 0xe7, 0xe0, 0xbc, 0xb1,
+ 0x7f, 0xf9, 0xb7, 0xe3, 0x16, 0x6a, 0x3a, 0x8d, 0x2c, 0x58, 0xeb, 0x17,
+ 0xb0, 0x5e, 0x23, 0xdc, 0x12, 0x55, 0xfe, 0x70, 0x44, 0xdf, 0x10, 0x16,
+ 0x2a, 0x13, 0x4b, 0xe8, 0xbd, 0x8a, 0xb5, 0x08, 0xb1, 0x19, 0x5f, 0xd1,
+ 0x34, 0x85, 0xdc, 0x96, 0x2f, 0xf8, 0x1c, 0xdb, 0xc0, 0x3e, 0x4c, 0xb1,
+ 0x7f, 0x04, 0x72, 0x18, 0x7d, 0xac, 0x53, 0x1f, 0x7b, 0x9e, 0xdf, 0xe3,
+ 0xf1, 0xb3, 0x7b, 0xe9, 0x62, 0xff, 0xfd, 0x9f, 0xc3, 0x76, 0xe0, 0xf6,
+ 0xb0, 0x80, 0x08, 0x58, 0xbe, 0x63, 0x5f, 0xa5, 0x8b, 0xff, 0xec, 0x3e,
+ 0xd2, 0x17, 0x36, 0xf3, 0x34, 0xfe, 0x58, 0xae, 0x8f, 0xe3, 0x84, 0x94,
+ 0xe9, 0x95, 0x78, 0xd4, 0x50, 0xd2, 0xbe, 0xd7, 0x42, 0x02, 0xc5, 0xfd,
+ 0x84, 0xfa, 0xd3, 0x2c, 0x53, 0x1e, 0x8f, 0xc9, 0x6f, 0xd0, 0x42, 0x79,
+ 0xd6, 0x2b, 0x0f, 0x27, 0x84, 0x37, 0xd3, 0x94, 0x4e, 0xb1, 0x7f, 0xf6,
+ 0x9b, 0xc5, 0x86, 0xed, 0x6d, 0xec, 0xb1, 0x50, 0x7d, 0x8c, 0x49, 0x7f,
+ 0xfa, 0x0c, 0xdb, 0x9b, 0xdb, 0xd1, 0x85, 0x25, 0x8b, 0xf6, 0x74, 0xe4,
+ 0x6a, 0xc5, 0x49, 0x7d, 0x84, 0xd2, 0x9e, 0xa1, 0xb7, 0xd9, 0xab, 0x39,
+ 0xea, 0x38, 0xa3, 0xa7, 0xfe, 0x14, 0x05, 0x1a, 0x57, 0x21, 0x9f, 0xe8,
+ 0x46, 0xef, 0x20, 0x0d, 0x36, 0xf6, 0xeb, 0xc2, 0xc5, 0xb1, 0x62, 0xff,
+ 0xf9, 0x8f, 0x1d, 0x6d, 0xeb, 0xec, 0x12, 0x0f, 0x0b, 0x17, 0xff, 0x09,
+ 0xe7, 0xe6, 0x37, 0x5d, 0x66, 0xf5, 0x8a, 0x92, 0x2b, 0xfe, 0x22, 0x4a,
+ 0xb7, 0xef, 0x6d, 0xf7, 0xce, 0xb1, 0x7f, 0x36, 0x9f, 0xa6, 0x25, 0x8a,
+ 0xc3, 0xd9, 0xf1, 0x65, 0xff, 0xfe, 0x8d, 0x1b, 0xb7, 0x84, 0x2c, 0xf4,
+ 0x49, 0x87, 0xf6, 0x58, 0xa9, 0x22, 0x13, 0x84, 0x37, 0x81, 0xcc, 0x58,
+ 0xbf, 0xdc, 0x14, 0xce, 0x37, 0x99, 0x62, 0xff, 0xfe, 0xe1, 0x8e, 0x13,
+ 0x8d, 0xa9, 0xb9, 0x07, 0x7e, 0xfc, 0xb1, 0x7f, 0x47, 0x4c, 0x51, 0x25,
+ 0x8b, 0x6e, 0x2c, 0x5f, 0xde, 0xc9, 0xcf, 0x1d, 0x2c, 0x54, 0x93, 0x26,
+ 0xec, 0x76, 0x63, 0x63, 0xb0, 0x80, 0xb7, 0xc2, 0xb7, 0xe2, 0x9c, 0x10,
+ 0x1a, 0xc5, 0xfd, 0x2d, 0xd8, 0xf4, 0x12, 0xc5, 0x61, 0xed, 0x04, 0x2a,
+ 0xbf, 0x6e, 0x9e, 0x1b, 0x4b, 0x17, 0xe2, 0xc3, 0x87, 0x0b, 0x15, 0x07,
+ 0xa6, 0xc5, 0x75, 0x08, 0x96, 0x93, 0xb5, 0xfa, 0x45, 0x07, 0x35, 0x62,
+ 0xff, 0xe3, 0xe6, 0x8b, 0x1b, 0x7b, 0x69, 0xd6, 0x2f, 0xe6, 0xe9, 0x87,
+ 0xd1, 0xd6, 0x2b, 0xb4, 0x4e, 0xb9, 0x4f, 0x91, 0x2f, 0xff, 0xcd, 0xad,
+ 0xb9, 0xe1, 0x46, 0x4f, 0xfc, 0x69, 0x2c, 0x5f, 0xf8, 0xb2, 0x6f, 0x7f,
+ 0x34, 0xdc, 0x58, 0xbf, 0xf1, 0xf6, 0x9d, 0xfd, 0xb7, 0xfe, 0xd2, 0xc5,
+ 0xfe, 0x83, 0xe3, 0x68, 0x5b, 0xab, 0x14, 0xe7, 0xf6, 0x24, 0x5a, 0xfa,
+ 0x36, 0xca, 0x17, 0x57, 0xee, 0xc9, 0x8e, 0xcb, 0x17, 0xa7, 0xc3, 0x16,
+ 0x2f, 0x66, 0xbe, 0xb1, 0x68, 0xd8, 0x8d, 0xe7, 0x43, 0xf7, 0xdb, 0x82,
+ 0x09, 0x0b, 0x15, 0x0a, 0x90, 0x46, 0x61, 0x91, 0x99, 0x31, 0x3e, 0x99,
+ 0x04, 0x59, 0x7e, 0x7f, 0xed, 0x1c, 0x2c, 0x5f, 0xf6, 0x7d, 0xcf, 0xe1,
+ 0x3f, 0x96, 0x2b, 0xc7, 0xc7, 0xb8, 0x55, 0x7f, 0xde, 0xe0, 0x7c, 0x7e,
+ 0xe5, 0x8b, 0x17, 0xf9, 0xe5, 0xb7, 0x82, 0x03, 0xac, 0x5f, 0x47, 0xe2,
+ 0x75, 0x8b, 0x30, 0xcf, 0x67, 0xe6, 0xd5, 0x08, 0xe1, 0xc2, 0x51, 0x42,
+ 0x56, 0xfd, 0xc6, 0xfe, 0x0d, 0x62, 0xfd, 0x28, 0xf6, 0x4e, 0xb1, 0x5b,
+ 0xa7, 0xa3, 0xa2, 0x8b, 0xd1, 0xc9, 0xd6, 0x2e, 0xef, 0xcb, 0x17, 0x7b,
+ 0x16, 0x2a, 0x0d, 0x87, 0x63, 0x37, 0xf7, 0x18, 0xba, 0xfc, 0x2c, 0x56,
+ 0x23, 0x0b, 0xa2, 0x5d, 0x27, 0x78, 0x86, 0xf9, 0xb7, 0x1b, 0xeb, 0x17,
+ 0xfe, 0xcf, 0x73, 0x59, 0x37, 0xd8, 0xd5, 0x8b, 0xff, 0xfd, 0xc6, 0x10,
+ 0x5f, 0xed, 0xb7, 0x3b, 0xf7, 0xc3, 0xe4, 0xf0, 0xb1, 0x7e, 0x94, 0x03,
+ 0x98, 0xb1, 0x7f, 0xec, 0xdb, 0xcf, 0x16, 0x03, 0x73, 0x16, 0x2f, 0x67,
+ 0x5b, 0x70, 0xfa, 0xfe, 0x51, 0x6f, 0x32, 0x61, 0x7c, 0x86, 0xb5, 0xff,
+ 0xfc, 0xdc, 0x06, 0x48, 0xa0, 0x0f, 0xfe, 0xe5, 0x9e, 0x58, 0xbf, 0xfb,
+ 0xa6, 0xd6, 0x9e, 0x4f, 0xd0, 0xbb, 0x58, 0xbc, 0x06, 0xfa, 0xc5, 0xff,
+ 0x61, 0xb8, 0x76, 0xdc, 0x83, 0xac, 0x53, 0x26, 0x55, 0xa2, 0xef, 0xad,
+ 0x81, 0x20, 0x87, 0x6f, 0xfb, 0x6b, 0x96, 0x04, 0xdb, 0xf1, 0x2c, 0x5f,
+ 0x8c, 0x6d, 0x61, 0xab, 0x15, 0x0a, 0xe2, 0xb0, 0xf5, 0x89, 0x5e, 0x53,
+ 0xb0, 0x92, 0x43, 0x3f, 0xbf, 0xfe, 0x7f, 0xed, 0x8d, 0xb9, 0xbe, 0x25,
+ 0xb6, 0x34, 0xb1, 0x7f, 0xde, 0x6e, 0x30, 0x82, 0xe3, 0x85, 0x8b, 0xa3,
+ 0xb5, 0x8b, 0xff, 0xef, 0x7a, 0x3d, 0xdc, 0xbf, 0x84, 0x68, 0x67, 0x58,
+ 0xbf, 0xa3, 0xd8, 0x4f, 0xba, 0xb1, 0x7e, 0x06, 0xc5, 0x3e, 0x18, 0xb1,
+ 0x43, 0x4d, 0x7d, 0x95, 0xf4, 0x7a, 0xe3, 0x00, 0x54, 0x22, 0xfb, 0xb6,
+ 0x20, 0xaa, 0xc5, 0xff, 0x9c, 0xba, 0xf6, 0x7f, 0xde, 0x12, 0xc5, 0x31,
+ 0xf0, 0x88, 0x86, 0xf4, 0x6f, 0x85, 0x8b, 0xfa, 0x35, 0x3c, 0x6a, 0x75,
+ 0x8b, 0xe1, 0x4f, 0x12, 0x58, 0xa9, 0x1e, 0xa7, 0x0c, 0x2f, 0xf1, 0xbb,
+ 0x74, 0xdd, 0xfb, 0x16, 0x2f, 0xff, 0xbf, 0x03, 0xdb, 0xfc, 0xdb, 0x9a,
+ 0x79, 0x62, 0xc5, 0xff, 0x40, 0x0e, 0xf2, 0xd8, 0x02, 0xa1, 0x45, 0x8b,
+ 0x8c, 0x0b, 0xac, 0x5f, 0x8c, 0xf8, 0x8b, 0xa5, 0x8b, 0xfc, 0x5e, 0xe6,
+ 0x49, 0xbe, 0xb1, 0x50, 0x7b, 0xd8, 0x57, 0x50, 0x89, 0xbe, 0x3d, 0xdf,
+ 0xfe, 0xc9, 0x64, 0xcd, 0xac, 0x17, 0x4e, 0x4b, 0x17, 0xec, 0xde, 0x51,
+ 0xda, 0xc5, 0x7c, 0xfd, 0x38, 0x95, 0x70, 0xbe, 0xb1, 0x50, 0xa8, 0xf7,
+ 0xa3, 0x82, 0x53, 0xe4, 0x38, 0xbd, 0x09, 0x6d, 0xc2, 0x2b, 0xff, 0xe8,
+ 0x06, 0x16, 0xd7, 0xf6, 0xdf, 0xe0, 0x1d, 0x62, 0xe2, 0x9d, 0x62, 0xa1,
+ 0x59, 0x76, 0x4a, 0x5f, 0x66, 0x52, 0x52, 0xbf, 0xff, 0xee, 0xfa, 0x2c,
+ 0xdf, 0x83, 0xcc, 0x22, 0x13, 0xcf, 0x1a, 0x58, 0xbf, 0xc3, 0xc3, 0xed,
+ 0xe3, 0xfd, 0x62, 0xf0, 0xa3, 0x8b, 0x15, 0x88, 0xbb, 0x66, 0x8f, 0x9b,
+ 0x5d, 0xc9, 0x2c, 0x5f, 0xfe, 0xfc, 0x1c, 0x9c, 0xd2, 0xc0, 0x76, 0x05,
+ 0x8b, 0xfb, 0x7b, 0x9f, 0xe6, 0x3a, 0xc5, 0xff, 0xfe, 0x68, 0xf3, 0xff,
+ 0x67, 0x9f, 0xc2, 0xf6, 0xd0, 0x4b, 0x8b, 0x17, 0xfc, 0xc4, 0xd9, 0xd4,
+ 0x7b, 0x8b, 0x15, 0x24, 0xc6, 0x99, 0x2c, 0x8c, 0x7c, 0xcd, 0x7b, 0x82,
+ 0xd2, 0xc5, 0xfe, 0x13, 0xf3, 0x3e, 0xc7, 0x58, 0xbc, 0xdf, 0x65, 0x8b,
+ 0xfa, 0x0e, 0x15, 0xd8, 0xb3, 0x4b, 0x17, 0x8e, 0xdc, 0x58, 0xbf, 0xb4,
+ 0xe4, 0x00, 0x42, 0xc5, 0x42, 0xa8, 0xa9, 0xcb, 0xb2, 0x33, 0x26, 0x3c,
+ 0xd0, 0xf3, 0x99, 0x90, 0xe0, 0x8d, 0xc3, 0x1d, 0xbf, 0xc5, 0x9e, 0xe0,
+ 0x1b, 0xb5, 0x8b, 0xf1, 0x60, 0xc9, 0xd6, 0x2a, 0x47, 0xb5, 0x86, 0x97,
+ 0xc2, 0x8e, 0x12, 0xc5, 0xd9, 0xbd, 0x62, 0xfd, 0x07, 0x7e, 0xfc, 0xb1,
+ 0x76, 0x4e, 0xb1, 0x7f, 0xf0, 0xf9, 0x9a, 0x2c, 0x07, 0x33, 0x4b, 0x15,
+ 0xf4, 0x4f, 0x70, 0x67, 0xc5, 0x22, 0x18, 0xbf, 0x67, 0x42, 0x79, 0xd6,
+ 0x2b, 0xa4, 0xc9, 0xff, 0x0c, 0x02, 0x3d, 0xbf, 0xff, 0xff, 0xf8, 0x51,
+ 0x21, 0x39, 0xbb, 0x79, 0x85, 0x81, 0x22, 0x5b, 0x70, 0x9a, 0x3e, 0xc5,
+ 0x9e, 0xcd, 0xeb, 0x17, 0xff, 0xda, 0x21, 0x76, 0x58, 0xda, 0xeb, 0xf1,
+ 0xc5, 0x8b, 0xff, 0xfb, 0xa7, 0xfe, 0x4a, 0x35, 0x00, 0xd4, 0x06, 0xe4,
+ 0xb1, 0x7e, 0x06, 0x7d, 0x86, 0xb1, 0x7f, 0xfc, 0xf2, 0xe3, 0x0f, 0x6c,
+ 0x98, 0x7f, 0x0f, 0x8b, 0x15, 0x09, 0x94, 0x62, 0x8b, 0xad, 0x88, 0xa2,
+ 0xfa, 0x77, 0x2d, 0xeb, 0x17, 0xf0, 0x30, 0xbe, 0x22, 0x58, 0xac, 0x3d,
+ 0x27, 0x25, 0xbf, 0xff, 0xff, 0xa5, 0xb7, 0xdf, 0x68, 0xe6, 0xdc, 0x17,
+ 0x51, 0xbf, 0x6e, 0x6b, 0x59, 0xbc, 0x4f, 0xf5, 0x8b, 0xef, 0x6c, 0x01,
+ 0x50, 0xa2, 0xc5, 0x42, 0x31, 0x72, 0x12, 0x97, 0xdf, 0x27, 0x08, 0xb1,
+ 0x7c, 0x76, 0x09, 0x0b, 0x15, 0x0b, 0xa5, 0x39, 0x1a, 0x46, 0x8d, 0xbf,
+ 0x1e, 0x59, 0x42, 0x37, 0x90, 0xe5, 0xf1, 0x30, 0x89, 0x2f, 0xf3, 0xf7,
+ 0xc6, 0x3c, 0x74, 0xb1, 0x7d, 0x83, 0x3f, 0x16, 0x2f, 0x66, 0x71, 0x62,
+ 0xda, 0x58, 0xbd, 0xec, 0x3a, 0xc5, 0x41, 0xaf, 0xc1, 0x2b, 0x4e, 0x33,
+ 0xea, 0x74, 0xbb, 0xc1, 0xee, 0x3a, 0xc5, 0xff, 0xf9, 0xa7, 0xfb, 0xb7,
+ 0xa3, 0xed, 0xee, 0x60, 0xd6, 0x2f, 0xfb, 0x6e, 0x7d, 0x9f, 0xdf, 0x85,
+ 0x8a, 0xdd, 0x44, 0x79, 0x2a, 0xd7, 0xd1, 0xaa, 0xf0, 0xb0, 0xa7, 0x4c,
+ 0x90, 0x50, 0xfd, 0xbe, 0xeb, 0xf1, 0xa5, 0x8b, 0xff, 0x6f, 0x79, 0x61,
+ 0x0c, 0xa2, 0x4b, 0x17, 0xfe, 0xe0, 0x87, 0xf6, 0xdb, 0x3e, 0x18, 0xb1,
+ 0x74, 0xf0, 0xb1, 0x58, 0x89, 0xbf, 0x1f, 0x89, 0x12, 0xfb, 0x3e, 0x78,
+ 0x58, 0xbe, 0xf9, 0x8f, 0x3a, 0xc5, 0x69, 0x33, 0x52, 0x85, 0xff, 0x0b,
+ 0xfc, 0x45, 0x79, 0x8c, 0x99, 0x62, 0xff, 0x9f, 0xed, 0xce, 0x09, 0xc0,
+ 0xb1, 0x43, 0x3d, 0x87, 0x1f, 0xb6, 0xce, 0xc6, 0xec, 0xfd, 0x42, 0x84,
+ 0x81, 0x54, 0x0d, 0x80, 0xcb, 0x62, 0x18, 0x89, 0x49, 0xb3, 0xc2, 0xf2,
+ 0x51, 0xbd, 0x0e, 0x52, 0xc6, 0x52, 0x5c, 0x4d, 0x86, 0xcf, 0x50, 0xce,
+ 0xee, 0x30, 0xc6, 0x8d, 0x26, 0x68, 0xd2, 0xb5, 0x2c, 0x00, 0xf1, 0xd0,
+ 0x7e, 0x73, 0x41, 0xe3, 0xbc, 0x04, 0x2d, 0x82, 0xe4, 0x25, 0x2e, 0x83,
+ 0x92, 0xe1, 0xfd, 0x3c, 0x0c, 0x28, 0x43, 0xef, 0x35, 0xdc, 0x8e, 0xc4,
+ 0x38, 0xd7, 0x42, 0x42, 0x6a, 0xf1, 0x31, 0x8b, 0x17, 0xdd, 0x3b, 0xf4,
+ 0xa8, 0xaa, 0x0b, 0xfd, 0xa8, 0xdf, 0xdc, 0xb3, 0xcb, 0x15, 0xa3, 0xe8,
+ 0x11, 0x8d, 0xfe, 0x36, 0x3d, 0xcd, 0xf8, 0x35, 0x8b, 0xf8, 0x5a, 0x07,
+ 0x9f, 0xb5, 0x8b, 0xfe, 0xcf, 0x3f, 0x7b, 0x67, 0xc3, 0x16, 0x2f, 0xfc,
+ 0xf2, 0xd9, 0xcd, 0x74, 0xef, 0xd2, 0xa2, 0x6b, 0x2f, 0xfb, 0xf0, 0x7e,
+ 0x71, 0xcb, 0xa5, 0x8b, 0xe8, 0xd4, 0x79, 0x62, 0xe7, 0xf2, 0xc5, 0x0c,
+ 0xdc, 0x9c, 0x8a, 0xff, 0x9f, 0xbe, 0x13, 0x40, 0x67, 0x58, 0xbf, 0x8c,
+ 0xcf, 0xcb, 0x38, 0xb1, 0x7f, 0x89, 0xfd, 0xc9, 0xbe, 0xcb, 0x16, 0xd9,
+ 0x92, 0xac, 0xdc, 0x84, 0x29, 0xa4, 0x5d, 0x1b, 0xe8, 0xc0, 0xe7, 0xdf,
+ 0x50, 0x77, 0x30, 0x10, 0xf0, 0xe8, 0x32, 0xfb, 0xff, 0xed, 0xd6, 0x1e,
+ 0x1f, 0x6f, 0xb3, 0x75, 0xb7, 0xf1, 0x62, 0xfd, 0xae, 0x9d, 0xfa, 0x54,
+ 0x55, 0x85, 0xed, 0x41, 0xd6, 0x2f, 0xfa, 0x25, 0x1a, 0x9e, 0x35, 0x3a,
+ 0xc5, 0xff, 0x88, 0x71, 0xbe, 0x66, 0xde, 0x40, 0x58, 0xbf, 0xf9, 0x9c,
+ 0x1b, 0x63, 0xa1, 0x10, 0xc4, 0xb1, 0x50, 0x88, 0xaf, 0xa1, 0xdb, 0x66,
+ 0x13, 0x95, 0xc5, 0xad, 0x1b, 0x90, 0xef, 0xa1, 0x8b, 0x7c, 0x58, 0x20,
+ 0xba, 0xc5, 0xfd, 0xdf, 0xa3, 0xef, 0xba, 0xb1, 0x7e, 0x7f, 0xe6, 0xb1,
+ 0x62, 0xa0, 0xf6, 0x5c, 0xca, 0xfe, 0xef, 0x99, 0xf8, 0x3a, 0xc5, 0xfd,
+ 0xa1, 0x4d, 0xc8, 0xf2, 0xc5, 0x42, 0x3f, 0xbe, 0xff, 0xe2, 0x01, 0x17,
+ 0xdf, 0xfc, 0x0c, 0x2d, 0x99, 0x03, 0x93, 0xb9, 0x2c, 0x56, 0xca, 0x21,
+ 0x20, 0xf2, 0xfe, 0x1b, 0x0b, 0xd9, 0xc5, 0x8b, 0xf9, 0x8e, 0xde, 0xfc,
+ 0x2c, 0x5f, 0x44, 0xd1, 0xda, 0xc5, 0x7c, 0xf4, 0x78, 0x5b, 0x7f, 0xfe,
+ 0xd0, 0xa7, 0x1e, 0x9f, 0xa2, 0xcd, 0xfa, 0x6e, 0x2c, 0x5f, 0xe6, 0xfc,
+ 0x1c, 0xef, 0x25, 0x8b, 0xf6, 0xba, 0x77, 0xe9, 0x51, 0x22, 0x17, 0xfe,
+ 0xc0, 0x8d, 0x3f, 0x79, 0xad, 0x3a, 0xc5, 0xfc, 0xc7, 0x9c, 0x5a, 0x92,
+ 0xc5, 0xd2, 0xd9, 0x84, 0x6e, 0x61, 0x9e, 0xf3, 0x7d, 0xc4, 0x2b, 0xfa,
+ 0x78, 0xd7, 0xdd, 0x96, 0x2d, 0xb3, 0xb1, 0xaa, 0x54, 0xc7, 0xfd, 0x11,
+ 0x3c, 0x66, 0xdc, 0x4f, 0xbf, 0x6b, 0xa7, 0x7e, 0x95, 0x16, 0x91, 0x7f,
+ 0xe7, 0x96, 0xce, 0x6b, 0xa7, 0x7e, 0x95, 0x13, 0xe9, 0x6d, 0x9c, 0x44,
+ 0x39, 0xcd, 0xef, 0xfc, 0xf2, 0xd9, 0xcd, 0x74, 0xef, 0xd2, 0xa2, 0x84,
+ 0x2f, 0xc4, 0xfc, 0xcf, 0x2c, 0x5b, 0x64, 0xe7, 0xee, 0xea, 0x17, 0xff,
+ 0x61, 0x9b, 0x3e, 0x35, 0xf8, 0xde, 0x85, 0x8b, 0xf7, 0x85, 0xd3, 0xf1,
+ 0x62, 0xe8, 0xd2, 0xc5, 0xff, 0xd0, 0x71, 0x6b, 0xa7, 0x61, 0xc4, 0xcb,
+ 0x16, 0x69, 0xcf, 0x76, 0x61, 0x7a, 0x3a, 0x2c, 0x3f, 0x08, 0x7b, 0xf6,
+ 0xba, 0x77, 0xe9, 0x51, 0x47, 0x96, 0xc5, 0x8b, 0xf8, 0x5e, 0x3b, 0x19,
+ 0xc5, 0x8a, 0x19, 0xe0, 0x90, 0x8d, 0xf3, 0x60, 0x38, 0xb1, 0x73, 0xf4,
+ 0xb1, 0x6c, 0x19, 0xba, 0x08, 0x45, 0x7e, 0x8e, 0x4c, 0x50, 0xb1, 0x7f,
+ 0xd1, 0x28, 0xd4, 0xf1, 0xa9, 0xd6, 0x2f, 0xff, 0xff, 0xf0, 0x6d, 0xa9,
+ 0xa3, 0xfa, 0xcf, 0xb8, 0x7c, 0xc3, 0x5c, 0x81, 0x05, 0x13, 0x7e, 0x16,
+ 0x2f, 0xcf, 0xc6, 0xf4, 0x2c, 0x5f, 0xf4, 0x4d, 0x05, 0x13, 0x7e, 0x16,
+ 0x2a, 0x11, 0xe0, 0x6c, 0x24, 0x08, 0x9e, 0xf8, 0xf3, 0xe1, 0x8b, 0x17,
+ 0xff, 0xe1, 0xfe, 0x03, 0xd9, 0xf1, 0x38, 0x39, 0xc8, 0x02, 0x45, 0x41,
+ 0xff, 0xe1, 0x2d, 0xe7, 0x96, 0xcc, 0x2b, 0x49, 0xc2, 0x89, 0x9e, 0x34,
+ 0xb7, 0xf2, 0x82, 0x28, 0xf4, 0x65, 0x7b, 0x90, 0xb3, 0xbf, 0xfb, 0x3f,
+ 0xb3, 0xe3, 0x5f, 0x8d, 0xe8, 0x58, 0xbf, 0xff, 0xf9, 0xa7, 0xd9, 0x6f,
+ 0x64, 0xc4, 0xdc, 0xf4, 0x06, 0xda, 0x9a, 0x3e, 0xb1, 0x6d, 0x99, 0xd7,
+ 0x65, 0x0f, 0x38, 0x85, 0xe8, 0x49, 0x84, 0x48, 0xa8, 0x7e, 0x25, 0xa9,
+ 0xeb, 0x76, 0xf9, 0x43, 0x8f, 0x25, 0x52, 0x9b, 0x6d, 0x0a, 0xfa, 0x9d,
+ 0x0b, 0xee, 0x51, 0xf3, 0x47, 0xb1, 0x34, 0xa7, 0x9f, 0xc3, 0x94, 0x10,
+ 0xa2, 0xf4, 0xed, 0xf5, 0xff, 0xf1, 0x9d, 0x05, 0x02, 0xa0, 0x0b, 0xeb,
+ 0x60, 0xdb, 0xb7, 0xfb, 0x8b, 0x17, 0xff, 0xfe, 0x09, 0xed, 0x88, 0x67,
+ 0xd8, 0x89, 0x82, 0xd7, 0x82, 0xfa, 0xd8, 0x36, 0xed, 0xfe, 0xe2, 0xc5,
+ 0x7d, 0x30, 0x03, 0x1b, 0xaf, 0xfe, 0xfc, 0x36, 0x98, 0x2f, 0xd7, 0xe0,
+ 0xc5, 0x8b, 0xff, 0x70, 0x2e, 0xc6, 0xed, 0xdb, 0xfd, 0xcd, 0x98, 0x3e,
+ 0xfe, 0x89, 0x6f, 0xff, 0xff, 0xf0, 0x40, 0xbb, 0x1b, 0xb7, 0x6f, 0xf7,
+ 0x36, 0x63, 0xe6, 0x74, 0x14, 0x0a, 0x80, 0x2f, 0xad, 0x83, 0x6e, 0xdf,
+ 0xee, 0x2c, 0x5f, 0xb5, 0xd3, 0xbf, 0x4a, 0x88, 0x88, 0xbf, 0xdc, 0x14,
+ 0x4d, 0xe6, 0xde, 0xb1, 0x6d, 0x9c, 0x3e, 0xe9, 0x8d, 0xef, 0xec, 0xd7,
+ 0x4e, 0xfd, 0x2a, 0x22, 0xb2, 0xfd, 0xae, 0x9d, 0xfa, 0x54, 0x57, 0x05,
+ 0xd1, 0xf5, 0x8b, 0xb7, 0x76, 0x70, 0xf3, 0xb7, 0x9b, 0xd6, 0xca, 0x2f,
+ 0xde, 0x11, 0x57, 0xdf, 0x7d, 0x32, 0xc5, 0xfb, 0xc0, 0x0c, 0xa4, 0xb1,
+ 0x7e, 0x04, 0x17, 0x5b, 0x30, 0x79, 0x8e, 0x45, 0x74, 0xdb, 0xab, 0x17,
+ 0xf1, 0x37, 0x5e, 0x89, 0x2c, 0x5b, 0x66, 0x73, 0xca, 0xd0, 0xe5, 0x9b,
+ 0xb4, 0x5b, 0x02, 0x11, 0x57, 0xf8, 0x2a, 0x14, 0x28, 0xe9, 0xfb, 0x58,
+ 0xbe, 0xcf, 0xbf, 0x96, 0x2f, 0xf6, 0x36, 0x80, 0x01, 0x71, 0x62, 0xc1,
+ 0x52, 0x3d, 0x6e, 0x11, 0x5f, 0xff, 0xff, 0xe0, 0xa6, 0xc6, 0x15, 0x8e,
+ 0x7f, 0x0d, 0xc1, 0x96, 0x4e, 0xd2, 0xe4, 0x0e, 0x3e, 0x4f, 0xba, 0xb1,
+ 0x7f, 0xd0, 0x5d, 0x3f, 0xdc, 0x86, 0xb1, 0x7e, 0x8f, 0x39, 0x62, 0xc5,
+ 0x1a, 0x7b, 0xda, 0x38, 0xbf, 0xff, 0x71, 0xbe, 0xed, 0x26, 0x2f, 0x0b,
+ 0xfa, 0xc5, 0x8b, 0xff, 0x14, 0x04, 0x8f, 0xb1, 0x41, 0xd6, 0x29, 0x91,
+ 0x6b, 0xe2, 0x30, 0x8a, 0x97, 0xe0, 0x73, 0xc5, 0x0b, 0x17, 0xfb, 0xdc,
+ 0x89, 0x9d, 0xf4, 0xb1, 0x50, 0x7b, 0x8c, 0x51, 0x7f, 0x9d, 0xcd, 0x31,
+ 0xf5, 0xc5, 0x8b, 0xff, 0xf7, 0xf0, 0xb0, 0xdf, 0xbc, 0xbe, 0x63, 0x86,
+ 0x75, 0x8b, 0xee, 0x9d, 0xfa, 0x54, 0x53, 0xc5, 0xff, 0xf9, 0xb5, 0xf7,
+ 0x8d, 0xe5, 0x9c, 0xc2, 0x63, 0xac, 0x5f, 0xf3, 0x9f, 0x8d, 0x9b, 0xdf,
+ 0x4b, 0x17, 0xfe, 0x28, 0xde, 0xde, 0x94, 0x61, 0x2c, 0x54, 0x93, 0x55,
+ 0xd2, 0xc7, 0xcc, 0x49, 0x53, 0xc7, 0x57, 0xf8, 0x60, 0xdb, 0x1b, 0xb1,
+ 0x25, 0x8b, 0xfc, 0x76, 0x18, 0x9f, 0x52, 0x58, 0xb8, 0xec, 0xb1, 0x50,
+ 0x79, 0x7d, 0x1a, 0x5f, 0xff, 0xd1, 0xee, 0x08, 0xfd, 0x30, 0x23, 0x3e,
+ 0xc2, 0xe9, 0x62, 0xe6, 0xe2, 0xc5, 0xfd, 0x07, 0xe4, 0x34, 0xeb, 0x15,
+ 0x24, 0x51, 0x62, 0xef, 0x85, 0xef, 0xff, 0xe7, 0xd3, 0xff, 0xb9, 0x67,
+ 0xb0, 0x85, 0xe1, 0x1a, 0xb1, 0x7d, 0x28, 0xc9, 0xd6, 0x2f, 0xff, 0xda,
+ 0x16, 0xb5, 0x05, 0x86, 0xb7, 0xff, 0x81, 0xac, 0x58, 0x6b, 0x16, 0x65,
+ 0x8a, 0xe9, 0x1f, 0x5d, 0xae, 0xe8, 0x8c, 0xea, 0xfb, 0xc4, 0xaf, 0x31,
+ 0x79, 0x62, 0xfe, 0x1e, 0x4b, 0xf1, 0xd2, 0xc5, 0xff, 0x9c, 0x71, 0x85,
+ 0xee, 0x41, 0x2c, 0x5e, 0x79, 0x6c, 0xb9, 0xf5, 0x91, 0x7d, 0xf8, 0x32,
+ 0x0f, 0xbe, 0x2c, 0x5e, 0x26, 0x02, 0xc5, 0x0c, 0xf2, 0x0e, 0x59, 0x7f,
+ 0xda, 0x79, 0xc6, 0x27, 0xd4, 0x96, 0x2f, 0xfe, 0x6e, 0x0b, 0x4c, 0xec,
+ 0x38, 0x25, 0x8a, 0x84, 0x4f, 0xb1, 0x13, 0x9d, 0xdf, 0xcc, 0x3c, 0x38,
+ 0xbc, 0xb1, 0x7f, 0xd8, 0x40, 0x83, 0xb6, 0xa4, 0xb1, 0x7f, 0x9b, 0x8c,
+ 0x20, 0xb8, 0xe1, 0x62, 0xa4, 0x7d, 0xfe, 0x38, 0xbf, 0xfe, 0x3e, 0x37,
+ 0x85, 0xe8, 0x93, 0x0f, 0x06, 0xb1, 0x52, 0x4c, 0x39, 0xa1, 0x3a, 0x02,
+ 0x2b, 0xf6, 0xa7, 0x8d, 0x4e, 0xb1, 0x7e, 0x62, 0xf0, 0x67, 0x58, 0xa8,
+ 0x3d, 0x40, 0x15, 0xdf, 0xed, 0x44, 0x7b, 0x8d, 0xbd, 0x62, 0xfe, 0x89,
+ 0xdc, 0x6f, 0xe5, 0x8a, 0x92, 0x21, 0x0e, 0x42, 0x10, 0xd6, 0xfd, 0x07,
+ 0xe8, 0x04, 0xb1, 0x7d, 0xb4, 0x9e, 0x4b, 0x17, 0xe7, 0xcf, 0xb1, 0xd6,
+ 0x2a, 0x63, 0xf4, 0xe1, 0x4e, 0xf2, 0x4a, 0x84, 0x6c, 0x64, 0x29, 0xaf,
+ 0xe6, 0xf3, 0x9b, 0xf6, 0x58, 0xbf, 0xe8, 0xeb, 0xee, 0xdb, 0x91, 0xa5,
+ 0x8b, 0xfc, 0xe7, 0xda, 0x3f, 0xb1, 0xd6, 0x28, 0xe7, 0xe5, 0xbc, 0xf2,
+ 0xff, 0x8a, 0x0f, 0x12, 0x2c, 0x3a, 0xc5, 0xff, 0x89, 0xcc, 0xf6, 0x7d,
+ 0xda, 0x65, 0x8b, 0xff, 0xc7, 0x8d, 0x4f, 0x1d, 0xe0, 0x82, 0xf8, 0x35,
+ 0x8b, 0xff, 0xd9, 0xe1, 0x00, 0xef, 0x2d, 0xba, 0x7e, 0x2c, 0x5f, 0x7a,
+ 0x50, 0x6a, 0xc5, 0x49, 0x3f, 0xbc, 0x85, 0x03, 0x12, 0x4c, 0x6e, 0xe7,
+ 0xe4, 0xa0, 0x1a, 0x6d, 0xf6, 0x31, 0x4c, 0xb1, 0x7c, 0xda, 0x89, 0xd6,
+ 0x2b, 0xa3, 0xc5, 0xe1, 0x15, 0xfe, 0x2e, 0xb3, 0x7e, 0x7b, 0x8b, 0x17,
+ 0xe1, 0x8a, 0x35, 0x3a, 0xc5, 0xff, 0xf7, 0x81, 0x12, 0xcd, 0xed, 0xe8,
+ 0xc2, 0x92, 0xc5, 0xce, 0x6a, 0xc5, 0x42, 0x32, 0x30, 0xd9, 0x8a, 0xb4,
+ 0xa1, 0x7b, 0xdf, 0x65, 0x8b, 0xb4, 0x25, 0x8b, 0xec, 0xf6, 0x1d, 0x62,
+ 0xd3, 0xc1, 0xba, 0x71, 0x8a, 0xc3, 0xfd, 0x75, 0x7b, 0xf7, 0xbe, 0x63,
+ 0xce, 0xb1, 0x5b, 0x03, 0x62, 0x59, 0xb1, 0x42, 0x4f, 0x61, 0x95, 0xc4,
+ 0x76, 0x32, 0x84, 0x68, 0xc8, 0x32, 0x38, 0xa3, 0x52, 0xba, 0x84, 0x27,
+ 0x70, 0xc4, 0x68, 0xca, 0x66, 0x4e, 0x3c, 0x21, 0xff, 0x18, 0xdb, 0xc6,
+ 0x76, 0x51, 0xf2, 0xf2, 0x51, 0x0f, 0xa1, 0x5b, 0xbe, 0x1d, 0x7b, 0x90,
+ 0xb7, 0x0c, 0x82, 0xfe, 0xcf, 0x73, 0x1f, 0x75, 0x62, 0xfe, 0x73, 0x39,
+ 0xc8, 0x02, 0xc5, 0x41, 0xef, 0x91, 0x85, 0xa7, 0x58, 0xbc, 0xf2, 0xd9,
+ 0x19, 0xb3, 0x30, 0x82, 0xff, 0xf0, 0x00, 0x2e, 0x6c, 0x86, 0x4e, 0x72,
+ 0x85, 0x8b, 0xff, 0x8b, 0x00, 0xe4, 0x0d, 0x93, 0xb1, 0xd6, 0x2b, 0x48,
+ 0x94, 0xf2, 0x75, 0xff, 0xa0, 0xcd, 0x92, 0xc9, 0xa4, 0x2f, 0x2c, 0x5f,
+ 0x9f, 0xff, 0x69, 0x96, 0x2f, 0xfe, 0xce, 0x31, 0x00, 0xb3, 0xdf, 0xc5,
+ 0x8b, 0xff, 0x31, 0x00, 0xb3, 0xdf, 0xcd, 0x9f, 0x9f, 0x58, 0x65, 0x35,
+ 0xb2, 0xb8, 0x18, 0x39, 0x43, 0x2d, 0x0c, 0xad, 0x11, 0xf2, 0x15, 0xf6,
+ 0xc5, 0x8b, 0xf1, 0x40, 0x82, 0xfc, 0x58, 0xb9, 0xbe, 0xb1, 0x7f, 0xfc,
+ 0xe3, 0x35, 0xfd, 0x9f, 0x2c, 0xf7, 0xd9, 0x62, 0xfe, 0x37, 0x4e, 0x37,
+ 0x25, 0x8a, 0x1a, 0x34, 0x70, 0x47, 0x45, 0x9f, 0x17, 0x74, 0xfb, 0xff,
+ 0x98, 0x7a, 0x7e, 0xf6, 0x75, 0xa8, 0x9d, 0x62, 0xb6, 0x51, 0x25, 0xf4,
+ 0x8b, 0x42, 0xc5, 0xfd, 0xc8, 0xe8, 0xa0, 0x6b, 0x14, 0x33, 0x7e, 0xc2,
+ 0x37, 0xcf, 0xd8, 0xe1, 0x62, 0xff, 0xfa, 0x35, 0x92, 0x67, 0xf6, 0x0d,
+ 0x85, 0xd2, 0x45, 0xc2, 0xed, 0x62, 0xbe, 0x7d, 0x04, 0x9f, 0x79, 0x81,
+ 0xc5, 0x8b, 0x74, 0xb1, 0x7e, 0x89, 0x00, 0x52, 0x58, 0xbe, 0xe9, 0xdf,
+ 0xa5, 0x45, 0x66, 0x5d, 0x06, 0x2c, 0x54, 0xe8, 0xa2, 0xc1, 0xd9, 0x84,
+ 0xf4, 0x53, 0xbc, 0xc6, 0xfb, 0xcc, 0x7e, 0x2c, 0x5b, 0x4b, 0x16, 0x35,
+ 0x62, 0x98, 0xd2, 0xf0, 0x4a, 0xf7, 0x05, 0xd2, 0xc5, 0x1a, 0x6f, 0xf8,
+ 0x41, 0x60, 0xd6, 0x2f, 0x6a, 0x37, 0xac, 0x54, 0x1b, 0x2e, 0x09, 0xdf,
+ 0xdb, 0xc8, 0xa3, 0x76, 0x65, 0x8b, 0xf1, 0xe0, 0xa5, 0xc5, 0x8b, 0xa2,
+ 0x65, 0x8a, 0x83, 0xf3, 0x9c, 0xcf, 0x45, 0x17, 0xde, 0xe0, 0x7c, 0x58,
+ 0xbe, 0xe7, 0x20, 0xc5, 0x8b, 0x3a, 0xc5, 0x61, 0xed, 0x31, 0x2f, 0x09,
+ 0x2e, 0x9d, 0x96, 0x2f, 0x73, 0xe2, 0x58, 0xbf, 0xa6, 0x62, 0xfe, 0x76,
+ 0xb1, 0x58, 0x79, 0xbc, 0x1e, 0xa8, 0x44, 0x36, 0x32, 0xdc, 0xfe, 0x58,
+ 0xbe, 0x00, 0x65, 0x25, 0x8a, 0x19, 0xbb, 0xf0, 0xbd, 0xff, 0xf4, 0x1f,
+ 0xd9, 0x85, 0xee, 0x7f, 0x00, 0xeb, 0x17, 0xf8, 0xf1, 0xdf, 0x35, 0x1b,
+ 0xd6, 0x2e, 0x7e, 0x2c, 0x54, 0x1e, 0x70, 0x8d, 0xef, 0xf4, 0x98, 0x5b,
+ 0xbb, 0x00, 0x0e, 0xb1, 0x7e, 0x28, 0xfb, 0x62, 0xc5, 0xd1, 0x25, 0x8a,
+ 0xc3, 0xfa, 0x73, 0xd0, 0x13, 0x5f, 0xda, 0x07, 0x33, 0xbf, 0x2c, 0x5f,
+ 0x40, 0x22, 0x4b, 0x16, 0x65, 0x8b, 0xc4, 0xfe, 0x58, 0xe1, 0x63, 0x6c,
+ 0x91, 0xef, 0x11, 0x9d, 0xe1, 0x48, 0x6b, 0x14, 0xc8, 0xd2, 0xfc, 0x23,
+ 0x88, 0x9a, 0xfd, 0x37, 0xd8, 0xa7, 0x58, 0xbe, 0xf7, 0xe3, 0x7a, 0xc5,
+ 0x76, 0x79, 0xe4, 0x55, 0x79, 0xdc, 0xeb, 0x17, 0xe7, 0x9c, 0x0d, 0xe5,
+ 0x8b, 0xf6, 0x4d, 0x38, 0x80, 0xb1, 0x7f, 0x7a, 0x34, 0x08, 0x99, 0x62,
+ 0xdb, 0x30, 0xc8, 0x5b, 0x91, 0x00, 0xe1, 0x17, 0x90, 0xc3, 0xed, 0x35,
+ 0xa1, 0x0f, 0x32, 0xa6, 0xa1, 0x26, 0x78, 0x44, 0xfe, 0x16, 0x6e, 0xb8,
+ 0x02, 0x12, 0x84, 0xe7, 0x21, 0x37, 0xe8, 0x7f, 0x8a, 0x10, 0x5b, 0xc8,
+ 0xb7, 0x07, 0x03, 0x29, 0x08, 0x57, 0x7f, 0x4b, 0x0e, 0x1c, 0x6e, 0xac,
+ 0x5f, 0xef, 0x3e, 0xa7, 0x86, 0x1a, 0xc5, 0xfd, 0xee, 0x0d, 0xa0, 0x96,
+ 0x29, 0x8f, 0x85, 0xcd, 0x2f, 0xe8, 0x3c, 0xe2, 0xd4, 0x96, 0x2f, 0xb5,
+ 0x86, 0x79, 0x62, 0xbe, 0x7e, 0x9e, 0x20, 0xde, 0x61, 0x7f, 0xa7, 0xfe,
+ 0x75, 0xf8, 0xd2, 0xc5, 0xff, 0x41, 0x4b, 0x87, 0x72, 0x35, 0x62, 0xa0,
+ 0xfb, 0xfc, 0x6d, 0x74, 0x0d, 0x62, 0xff, 0x84, 0x7c, 0xeb, 0x5d, 0xb9,
+ 0x8b, 0x15, 0x23, 0xf5, 0xe1, 0x0f, 0x85, 0xef, 0xf6, 0xa0, 0xdc, 0x26,
+ 0x35, 0x62, 0xff, 0xf9, 0xde, 0x7f, 0xb4, 0x14, 0x9b, 0xef, 0xc5, 0x8b,
+ 0xfc, 0xda, 0x0c, 0x7f, 0x89, 0x2c, 0x5c, 0x78, 0x58, 0xa7, 0x3c, 0xc0,
+ 0x86, 0xb7, 0xff, 0xc3, 0xfc, 0x73, 0x6e, 0x36, 0x98, 0xf0, 0x6a, 0xc5,
+ 0xa1, 0x62, 0xb0, 0xf8, 0xf8, 0xa5, 0x78, 0x9f, 0xcb, 0x17, 0xec, 0xec,
+ 0x11, 0xf5, 0x8b, 0xff, 0xd0, 0x60, 0x67, 0x2c, 0xef, 0xd1, 0x86, 0x2c,
+ 0x5f, 0xbc, 0xc5, 0x87, 0x58, 0xbc, 0xe5, 0xb2, 0x35, 0xc7, 0x9c, 0x8c,
+ 0x1f, 0xb8, 0xc5, 0x74, 0x5e, 0x73, 0x4f, 0xc2, 0x68, 0xa1, 0x0d, 0xbc,
+ 0x87, 0x70, 0x70, 0x32, 0x90, 0x89, 0xb7, 0xfc, 0xe6, 0x6c, 0x8e, 0x0f,
+ 0xdc, 0x2c, 0x54, 0x93, 0x09, 0x28, 0x65, 0xdf, 0xf9, 0xe5, 0xb3, 0x9a,
+ 0xe9, 0xdf, 0xa5, 0x44, 0x8a, 0x5f, 0xff, 0xbd, 0xfc, 0x2d, 0x9f, 0x3b,
+ 0xf7, 0xc3, 0x4d, 0x75, 0x8b, 0xff, 0x3f, 0xb6, 0x61, 0xb4, 0xde, 0x12,
+ 0xc5, 0x6c, 0xa3, 0xb2, 0x14, 0x1d, 0x6e, 0xff, 0xb5, 0xa6, 0x33, 0x26,
+ 0x63, 0xac, 0x5f, 0x75, 0x1f, 0x85, 0x8a, 0x63, 0xde, 0x23, 0xbb, 0xf6,
+ 0xba, 0x77, 0xe9, 0x51, 0x64, 0x95, 0x07, 0xaf, 0x84, 0x17, 0xf4, 0x8a,
+ 0x3e, 0xe7, 0x58, 0xbe, 0x62, 0x97, 0x16, 0x2f, 0xd1, 0xcf, 0x34, 0xeb,
+ 0x15, 0x39, 0xe5, 0x9a, 0x45, 0x7f, 0x85, 0x3f, 0xe3, 0xdc, 0x65, 0x8b,
+ 0xf8, 0x43, 0x6d, 0x3f, 0x16, 0x2e, 0x6f, 0x2c, 0x5f, 0xbd, 0xc0, 0xf9,
+ 0xb3, 0x09, 0x8b, 0x63, 0xc6, 0x89, 0x38, 0x6b, 0xe2, 0xea, 0xd9, 0x4e,
+ 0x87, 0x23, 0x36, 0xbf, 0xfe, 0x83, 0xb8, 0xf6, 0x7d, 0x1d, 0xca, 0x7c,
+ 0x31, 0x62, 0xfb, 0x0c, 0xe7, 0xd6, 0x2f, 0xa0, 0xec, 0x62, 0xc5, 0xfc,
+ 0xc7, 0x8f, 0x86, 0x35, 0x8a, 0x98, 0xf4, 0x82, 0x11, 0xdf, 0xdf, 0x6d,
+ 0x44, 0xb8, 0xb1, 0x7c, 0xd0, 0x20, 0xba, 0xc5, 0xfc, 0x7f, 0x37, 0xdc,
+ 0xeb, 0x17, 0xff, 0x9b, 0xdf, 0xcf, 0x61, 0x47, 0xa0, 0x6b, 0x15, 0x07,
+ 0xec, 0xe5, 0xd7, 0xcd, 0xb1, 0x3f, 0x4b, 0x17, 0xf9, 0xbc, 0x2d, 0x3f,
+ 0x36, 0x67, 0x4e, 0xb7, 0x1d, 0xba, 0x25, 0xd1, 0x77, 0xe1, 0x39, 0xe2,
+ 0x0a, 0x65, 0x51, 0x8f, 0x28, 0x0e, 0xff, 0xff, 0x79, 0xfb, 0x06, 0xc8,
+ 0xca, 0x3b, 0x97, 0x98, 0x81, 0xc5, 0x8b, 0xfb, 0x35, 0xd3, 0xbf, 0x4a,
+ 0x8b, 0x60, 0xbf, 0xff, 0x7f, 0x69, 0x66, 0xbd, 0xcf, 0xcd, 0xb7, 0x6f,
+ 0xf7, 0x16, 0x2f, 0xdf, 0x7d, 0x31, 0xd6, 0x28, 0x2a, 0x88, 0xae, 0x98,
+ 0xaf, 0xd9, 0xbf, 0x4f, 0xc5, 0x8b, 0xff, 0x6a, 0x78, 0xf3, 0x34, 0xb9,
+ 0x0b, 0x17, 0xb4, 0x2f, 0xac, 0x5f, 0xfd, 0x03, 0xce, 0xfc, 0x6b, 0x81,
+ 0xbc, 0xb1, 0x77, 0xb6, 0x61, 0x1e, 0xa3, 0x28, 0xc2, 0xad, 0x1f, 0x86,
+ 0x3d, 0x5b, 0x2a, 0x84, 0xda, 0x3b, 0xbb, 0xd9, 0xcc, 0x58, 0xbe, 0xe9,
+ 0xdf, 0xa5, 0x45, 0xb6, 0x5c, 0xfa, 0x58, 0xb4, 0x96, 0x2d, 0xc9, 0xcd,
+ 0x48, 0x85, 0xeb, 0x48, 0x82, 0xf2, 0xd5, 0xfb, 0xfe, 0x60, 0x09, 0x62,
+ 0xff, 0xf4, 0x4f, 0xe6, 0x1e, 0x14, 0x9b, 0xe2, 0x58, 0xa6, 0x3f, 0x3f,
+ 0x94, 0xdf, 0x9e, 0x62, 0x83, 0xac, 0x5f, 0xa5, 0xb3, 0xc3, 0xc2, 0xc5,
+ 0xfe, 0x94, 0x6a, 0x78, 0xd4, 0xeb, 0x17, 0xb4, 0x1f, 0x96, 0x2a, 0x0f,
+ 0x57, 0x0d, 0xaf, 0xa2, 0x6e, 0x32, 0xc5, 0x49, 0x52, 0x0e, 0x42, 0x7a,
+ 0x68, 0x4b, 0x1c, 0x85, 0xca, 0x0a, 0x10, 0x21, 0x08, 0x2f, 0xfc, 0x3d,
+ 0x30, 0xa7, 0xd9, 0xe6, 0xbc, 0xb1, 0x5b, 0x28, 0xba, 0xc7, 0x5b, 0xfd,
+ 0x9c, 0xe4, 0x00, 0x39, 0xd6, 0x2f, 0x7f, 0x27, 0x58, 0xbf, 0x9c, 0x79,
+ 0x84, 0x6a, 0xc5, 0xfd, 0xf6, 0xd6, 0x9e, 0x4b, 0x17, 0xfe, 0xf3, 0x49,
+ 0xbe, 0x23, 0x9d, 0x96, 0x28, 0x68, 0xee, 0x98, 0xd8, 0xe3, 0xdc, 0x2d,
+ 0x0c, 0xba, 0xff, 0x66, 0xce, 0xb3, 0x71, 0x8d, 0x58, 0xbd, 0x84, 0x0d,
+ 0x94, 0x43, 0x6e, 0x26, 0x58, 0x96, 0x2d, 0x25, 0x8a, 0xd8, 0x8d, 0x18,
+ 0xc4, 0x6f, 0x6c, 0x5f, 0x1a, 0xc5, 0xe9, 0xfe, 0xcb, 0x17, 0xfe, 0xd8,
+ 0xb6, 0x2d, 0x85, 0xef, 0xe1, 0x40, 0x16, 0x2f, 0x6c, 0x30, 0xb7, 0xd8,
+ 0x6b, 0x17, 0xef, 0x47, 0xde, 0x65, 0x8b, 0xf1, 0x48, 0x62, 0x3a, 0xc5,
+ 0xfc, 0x60, 0x7b, 0x8e, 0x40, 0x58, 0xa8, 0x3d, 0xcc, 0x29, 0xbf, 0x98,
+ 0x39, 0xb8, 0x2e, 0xd6, 0x2f, 0xba, 0xf8, 0xb4, 0xb1, 0x6d, 0x89, 0x62,
+ 0x86, 0x6f, 0x34, 0x4b, 0x5f, 0x44, 0x7b, 0xb7, 0x5f, 0xf6, 0x6b, 0x51,
+ 0x27, 0xec, 0xc5, 0x8b, 0xee, 0x9d, 0xfa, 0x54, 0x5e, 0x05, 0xfb, 0xdd,
+ 0xf4, 0xda, 0x58, 0xbf, 0xe0, 0x73, 0x6f, 0x00, 0xf9, 0x32, 0xc5, 0xfe,
+ 0xd6, 0xb3, 0xdc, 0x83, 0xac, 0x53, 0x1f, 0x8b, 0x9e, 0xdf, 0xf9, 0xfd,
+ 0x1b, 0xf5, 0xac, 0xef, 0x8b, 0x17, 0xed, 0x66, 0xf7, 0xd2, 0xc5, 0xff,
+ 0xb4, 0x1f, 0x9b, 0xe5, 0x9e, 0xc5, 0x8a, 0x63, 0xe9, 0x72, 0xaa, 0xd2,
+ 0x77, 0x07, 0x31, 0xfc, 0x27, 0x08, 0x83, 0x7c, 0x2a, 0xef, 0xbc, 0x16,
+ 0xb2, 0x65, 0x8b, 0xa2, 0x16, 0x2b, 0x47, 0x81, 0xe2, 0xab, 0xf4, 0xe5,
+ 0x0c, 0x35, 0x8b, 0xff, 0xcd, 0xef, 0xb3, 0x83, 0xb9, 0x09, 0xfc, 0xb1,
+ 0x7f, 0xfc, 0xc7, 0x8e, 0xb6, 0xe1, 0xf0, 0xbd, 0xb9, 0x8b, 0x15, 0x08,
+ 0xc7, 0x19, 0x47, 0xd2, 0xee, 0x7e, 0x2c, 0x5e, 0xdc, 0xcf, 0xac, 0x50,
+ 0x0d, 0xbf, 0x85, 0xef, 0xc7, 0x82, 0x93, 0xac, 0x5f, 0xd0, 0x5e, 0xde,
+ 0xfd, 0x2c, 0x5f, 0xd2, 0x8d, 0xf1, 0xae, 0xd6, 0x2f, 0xff, 0xe7, 0x9e,
+ 0x69, 0x46, 0xa7, 0xf4, 0xb3, 0x75, 0xc8, 0x0b, 0x15, 0x24, 0x61, 0x61,
+ 0x83, 0x98, 0xdc, 0x1f, 0x16, 0x2f, 0xf9, 0xbb, 0xfe, 0x0c, 0x38, 0xed,
+ 0x62, 0xf1, 0x64, 0xcb, 0x15, 0x31, 0xf9, 0x68, 0x67, 0xe7, 0x97, 0xf7,
+ 0x9f, 0xfb, 0x47, 0x0b, 0x17, 0xfc, 0xfe, 0xe4, 0x30, 0xf0, 0xeb, 0x15,
+ 0x07, 0xd0, 0x46, 0x17, 0xe9, 0x33, 0x7d, 0xd6, 0x2f, 0x8b, 0x18, 0xd5,
+ 0x8b, 0xfe, 0x3f, 0x72, 0xf6, 0x17, 0xb8, 0xb1, 0x5d, 0xa2, 0x10, 0xe4,
+ 0xe1, 0x91, 0x5d, 0x86, 0xac, 0x5f, 0x9e, 0x5e, 0x69, 0xd6, 0x2f, 0xfe,
+ 0xf4, 0x17, 0x4c, 0x73, 0xb7, 0x04, 0xb1, 0x7f, 0xf0, 0x71, 0xa9, 0x6d,
+ 0xe6, 0x1e, 0x31, 0x62, 0x99, 0x11, 0x9e, 0x45, 0xa8, 0x4c, 0x87, 0x0c,
+ 0x98, 0x61, 0xe1, 0x6b, 0x76, 0x1d, 0x62, 0xfc, 0xdf, 0x1b, 0x71, 0x62,
+ 0xcd, 0x39, 0xbf, 0x90, 0xbd, 0xfb, 0x08, 0x01, 0x21, 0x62, 0xe7, 0xe2,
+ 0xc5, 0xe1, 0x3f, 0x16, 0x2b, 0xc6, 0xd0, 0x31, 0x7b, 0xf4, 0xda, 0x69,
+ 0xce, 0xb1, 0x50, 0x79, 0xb8, 0x45, 0x74, 0xc3, 0x58, 0xbf, 0xff, 0xfe,
+ 0x21, 0x3f, 0x30, 0xb9, 0xcc, 0xfb, 0x70, 0x53, 0xf3, 0xf9, 0xdf, 0xa1,
+ 0x62, 0xfc, 0xda, 0x7e, 0xcc, 0x58, 0xbf, 0xf4, 0x75, 0xb7, 0x08, 0x52,
+ 0xce, 0x2c, 0x54, 0x91, 0xd3, 0x33, 0xf1, 0xca, 0xaf, 0xf7, 0xd8, 0xc3,
+ 0x74, 0xe6, 0x2c, 0x5f, 0xb7, 0xc0, 0xcf, 0xc5, 0x8b, 0xfb, 0x38, 0x2f,
+ 0x41, 0x2c, 0x5f, 0xff, 0xf9, 0xdb, 0xce, 0x77, 0x20, 0x75, 0xf6, 0xd4,
+ 0x83, 0x96, 0x12, 0xc5, 0xfb, 0x7e, 0x61, 0x1a, 0xb1, 0x7f, 0x60, 0xff,
+ 0x1c, 0xdd, 0x58, 0xbf, 0xa3, 0xbe, 0xe4, 0xfd, 0xac, 0x50, 0xd5, 0x5d,
+ 0x64, 0x60, 0x5d, 0x18, 0xb1, 0xbc, 0xc5, 0x7f, 0x2d, 0x03, 0x61, 0x15,
+ 0x08, 0xc6, 0xfe, 0x2c, 0xf0, 0x33, 0xb5, 0x8b, 0xfc, 0xe4, 0x0f, 0x6e,
+ 0x67, 0xd6, 0x2f, 0xfb, 0xef, 0x23, 0xb4, 0x6a, 0x4b, 0x15, 0xba, 0x7d,
+ 0xff, 0x36, 0xa8, 0x46, 0x16, 0x42, 0x76, 0xe3, 0xf1, 0x62, 0xfa, 0x0a,
+ 0x5b, 0xab, 0x17, 0xff, 0x01, 0xc8, 0x05, 0x9b, 0xff, 0x83, 0x58, 0xbf,
+ 0xf9, 0xc1, 0x83, 0xcf, 0xb6, 0xbe, 0xeb, 0x15, 0xda, 0x22, 0x38, 0x8b,
+ 0x7f, 0xf3, 0x38, 0x3c, 0xdc, 0xfc, 0x17, 0x96, 0x2f, 0xf0, 0x65, 0x20,
+ 0xf4, 0xe0, 0x58, 0xbe, 0xcf, 0x19, 0xd2, 0xc5, 0xd0, 0x05, 0x8a, 0x92,
+ 0x78, 0x98, 0x4c, 0x68, 0xc3, 0x42, 0xb7, 0xe4, 0x80, 0x43, 0xe1, 0xb7,
+ 0x89, 0x6f, 0xf3, 0xfd, 0xc3, 0x3e, 0x71, 0x62, 0xdd, 0x2c, 0x5d, 0xd4,
+ 0x96, 0x2b, 0xa3, 0x59, 0xe1, 0x3b, 0xfe, 0x22, 0xc9, 0xc1, 0xc8, 0x25,
+ 0x8a, 0xd8, 0xdb, 0x28, 0x00, 0xa9, 0x36, 0xc4, 0x47, 0xb0, 0xc7, 0x82,
+ 0xdd, 0x3e, 0x0c, 0x67, 0x84, 0x2c, 0xa1, 0x5e, 0x32, 0x2c, 0x8f, 0xcc,
+ 0xd8, 0x4b, 0x75, 0x0e, 0x9e, 0xd9, 0x98, 0x86, 0x68, 0x74, 0xea, 0x14,
+ 0x07, 0x84, 0xc7, 0xe3, 0xc5, 0x77, 0xe0, 0x13, 0x94, 0x2a, 0xb9, 0x2b,
+ 0x6b, 0xd2, 0xc2, 0xf7, 0xbb, 0x6e, 0x30, 0x06, 0x45, 0x7b, 0xd0, 0x35,
+ 0x8b, 0xe0, 0x3e, 0xb8, 0xb1, 0x77, 0x7b, 0x30, 0x78, 0x18, 0x3b, 0x7f,
+ 0x81, 0xb3, 0x34, 0xa0, 0xbc, 0xb1, 0x5b, 0x2a, 0x9a, 0xe2, 0x50, 0x1e,
+ 0x8c, 0x2c, 0x4b, 0x16, 0xed, 0x62, 0xe2, 0x1e, 0x1a, 0x40, 0xc4, 0x6e,
+ 0xce, 0xd6, 0x2f, 0xc6, 0x16, 0x4e, 0x25, 0x8b, 0xdc, 0x14, 0xeb, 0x15,
+ 0x07, 0x92, 0xe5, 0x54, 0xc8, 0x81, 0xd3, 0x0d, 0xfb, 0x5d, 0x3b, 0xf4,
+ 0xa8, 0xbd, 0x0b, 0xf6, 0x78, 0xa2, 0x75, 0x8b, 0xff, 0x3b, 0x78, 0x5a,
+ 0x7d, 0xf8, 0x35, 0x8b, 0x85, 0xc5, 0x8b, 0xee, 0x7d, 0xf7, 0x56, 0x28,
+ 0x66, 0xfb, 0xe3, 0x17, 0xe8, 0x3b, 0xfe, 0x16, 0x2f, 0x1d, 0xbc, 0xb1,
+ 0x7f, 0xcf, 0xe9, 0x41, 0xbe, 0x69, 0xd6, 0x2b, 0x47, 0xfe, 0x72, 0x72,
+ 0x1d, 0xbf, 0x61, 0xfe, 0xe3, 0x58, 0xa8, 0x55, 0x44, 0x38, 0x56, 0xe1,
+ 0x16, 0x8d, 0xfe, 0x50, 0xef, 0xc1, 0xc2, 0x80, 0x21, 0x75, 0xff, 0xd8,
+ 0x3f, 0xe1, 0xce, 0xf2, 0xc2, 0x58, 0xbc, 0x28, 0x02, 0xc5, 0xf6, 0xfc,
+ 0x2d, 0x91, 0x9f, 0x06, 0x90, 0xef, 0xd9, 0x34, 0x9c, 0x6b, 0x17, 0xc1,
+ 0x1b, 0x53, 0xac, 0x5b, 0x67, 0xc7, 0x9e, 0x10, 0xa6, 0x99, 0x17, 0x3f,
+ 0x84, 0x65, 0x6c, 0xa7, 0x7b, 0x91, 0xcb, 0x50, 0x58, 0xfa, 0x49, 0xa1,
+ 0x6e, 0xcd, 0x11, 0x96, 0xcf, 0x0e, 0xa9, 0x46, 0x59, 0x95, 0xab, 0x37,
+ 0x51, 0xe1, 0xb5, 0x23, 0x02, 0x69, 0xed, 0x3d, 0x46, 0x28, 0x79, 0x50,
+ 0xff, 0x95, 0x70, 0xe5, 0x40, 0x94, 0xf2, 0x52, 0xca, 0x39, 0x1c, 0xc8,
+ 0xab, 0x54, 0x73, 0x27, 0x2f, 0xaf, 0x17, 0xb8, 0xb1, 0x71, 0xce, 0xb1,
+ 0x6f, 0xac, 0x50, 0x50, 0xd5, 0x08, 0x62, 0xff, 0xe1, 0x44, 0xc5, 0x9b,
+ 0xdc, 0xe7, 0x65, 0x8b, 0xec, 0xfb, 0xf9, 0x62, 0xff, 0x63, 0x68, 0x00,
+ 0x17, 0x16, 0x2c, 0x15, 0x35, 0x13, 0x84, 0x8d, 0xc2, 0x2b, 0xcd, 0x9c,
+ 0x58, 0xbf, 0xfd, 0xee, 0x0a, 0x39, 0x9e, 0x63, 0xbc, 0x96, 0x2f, 0x47,
+ 0x73, 0xac, 0x51, 0x1f, 0x4f, 0x92, 0xaf, 0x9b, 0x72, 0x0e, 0xb1, 0x7f,
+ 0xbf, 0x13, 0xea, 0x30, 0x6b, 0x17, 0xff, 0xd3, 0x66, 0x19, 0xb4, 0x39,
+ 0x46, 0xf6, 0x20, 0x2c, 0x5f, 0xfd, 0x98, 0x60, 0x72, 0x8d, 0xec, 0x40,
+ 0x58, 0xbd, 0x8d, 0xbf, 0x6a, 0x27, 0x66, 0x56, 0xa8, 0x4c, 0x27, 0xf0,
+ 0xd1, 0xbf, 0xef, 0x73, 0x3b, 0x97, 0xc4, 0x6a, 0xc5, 0xee, 0x44, 0xcb,
+ 0x17, 0x6a, 0x16, 0x28, 0x6a, 0x9b, 0x9a, 0x10, 0xa7, 0x21, 0xfc, 0x65,
+ 0xc4, 0x51, 0xc3, 0xd0, 0x83, 0xd7, 0x89, 0xfe, 0xb1, 0x7b, 0x7c, 0x49,
+ 0x62, 0xf7, 0xf3, 0x8b, 0x17, 0xfc, 0x4c, 0x6f, 0xbb, 0xe9, 0xbe, 0xb1,
+ 0x7b, 0x91, 0x3a, 0xc5, 0x42, 0x25, 0x86, 0x3f, 0x83, 0xbd, 0x9e, 0x5f,
+ 0xef, 0x7d, 0x9c, 0x00, 0x85, 0x8b, 0xee, 0xe4, 0x29, 0xd6, 0x2f, 0xe3,
+ 0x78, 0xf1, 0xdc, 0x96, 0x2d, 0x9d, 0x9e, 0xb3, 0x13, 0x5f, 0xcf, 0xa9,
+ 0x10, 0x9d, 0x62, 0xe6, 0x3a, 0xc5, 0x62, 0x3d, 0x35, 0x08, 0x91, 0x13,
+ 0x84, 0x2d, 0xbe, 0x38, 0x88, 0x6b, 0x17, 0xff, 0xf4, 0x6a, 0x6e, 0x75,
+ 0xf1, 0x73, 0x90, 0x69, 0x66, 0xf5, 0x8b, 0xc6, 0xc1, 0x8b, 0x17, 0x9d,
+ 0xfa, 0x54, 0x44, 0x65, 0xf1, 0xbd, 0x3e, 0x96, 0x28, 0xd3, 0xee, 0xe8,
+ 0x7d, 0x8a, 0xaf, 0xdb, 0x17, 0xb8, 0xe0, 0x58, 0xbf, 0x33, 0x9f, 0x34,
+ 0xb1, 0x7f, 0xc2, 0x7e, 0xcb, 0x27, 0x0e, 0x4b, 0x17, 0xba, 0x0c, 0xeb,
+ 0x17, 0xff, 0xfd, 0x13, 0x7a, 0x39, 0xa8, 0xf3, 0x74, 0xc3, 0xda, 0x69,
+ 0x3a, 0xc5, 0x42, 0x22, 0x88, 0x82, 0xff, 0xe6, 0xe7, 0xf0, 0xd3, 0x5f,
+ 0x68, 0xfb, 0x58, 0xa9, 0xd5, 0x54, 0x74, 0x47, 0xa8, 0x67, 0x9c, 0xc3,
+ 0xe5, 0xdc, 0x27, 0xf4, 0x31, 0xb7, 0x90, 0xdf, 0x7d, 0xb8, 0x6a, 0xc5,
+ 0xfc, 0xfd, 0xff, 0x18, 0xc5, 0x8b, 0xa5, 0xf5, 0x8a, 0xd1, 0xe3, 0xb9,
+ 0x7d, 0xfe, 0xcf, 0x61, 0xe7, 0xc3, 0x16, 0x28, 0x67, 0xac, 0x44, 0x37,
+ 0xff, 0x73, 0x98, 0x72, 0xcd, 0xfb, 0x60, 0x28, 0xb1, 0x4c, 0x7d, 0xa2,
+ 0x21, 0xbf, 0xd9, 0x3f, 0xcb, 0x04, 0x35, 0x8a, 0xf9, 0xea, 0x91, 0x0d,
+ 0xfe, 0x9f, 0x59, 0xef, 0x37, 0x96, 0x29, 0x62, 0xff, 0xef, 0xe7, 0x8a,
+ 0x26, 0xda, 0x69, 0x3a, 0xc5, 0xc2, 0x89, 0x8f, 0x4f, 0xc1, 0x95, 0x08,
+ 0xb6, 0xe4, 0x22, 0x2f, 0x14, 0x76, 0xb1, 0x52, 0x3c, 0x41, 0x93, 0xdc,
+ 0xff, 0x58, 0xbf, 0xda, 0xce, 0x63, 0x94, 0xeb, 0x17, 0x8e, 0x2e, 0xd6,
+ 0x28, 0x67, 0xd3, 0x82, 0xe0, 0x33, 0xbf, 0xc2, 0x18, 0x7f, 0xfb, 0xc9,
+ 0x62, 0xc7, 0x58, 0xbf, 0xc1, 0xca, 0x37, 0xb1, 0x01, 0x62, 0xfe, 0x94,
+ 0x6f, 0x62, 0x02, 0xc5, 0x8c, 0xda, 0x7c, 0xa1, 0x9b, 0x50, 0xd1, 0x47,
+ 0x8e, 0xf7, 0xff, 0x44, 0xfb, 0x4b, 0x3d, 0xcf, 0xe1, 0xab, 0x17, 0xe7,
+ 0x9c, 0x36, 0x1a, 0xc5, 0xff, 0xd8, 0x60, 0xa2, 0x7f, 0x0e, 0x3d, 0xc5,
+ 0x8b, 0x9a, 0x65, 0x8a, 0x92, 0x79, 0x99, 0x0d, 0x9f, 0x91, 0x3a, 0x41,
+ 0x15, 0x79, 0x1e, 0xff, 0xf4, 0x98, 0xd3, 0x5f, 0x90, 0xd3, 0xbf, 0x96,
+ 0x2f, 0xff, 0xe7, 0x6f, 0x47, 0xcb, 0x3d, 0xf6, 0xfe, 0x31, 0x8b, 0x14,
+ 0xc8, 0xa5, 0xfa, 0x65, 0xff, 0xff, 0xef, 0x79, 0x8f, 0xa6, 0xce, 0xc8,
+ 0x5e, 0x8f, 0xed, 0xde, 0xde, 0x9a, 0x16, 0x2f, 0xf6, 0x31, 0x36, 0xb5,
+ 0x8b, 0x17, 0xfd, 0x8e, 0x40, 0xd0, 0xa0, 0x0b, 0x15, 0x09, 0x84, 0x61,
+ 0x17, 0x6f, 0xba, 0x31, 0xbf, 0xff, 0x1f, 0x75, 0x9d, 0xe6, 0xf7, 0xf2,
+ 0x5f, 0x6d, 0xeb, 0x17, 0xff, 0x73, 0xd1, 0xec, 0xf4, 0xd2, 0x8f, 0xac,
+ 0x5e, 0x14, 0x01, 0x62, 0xee, 0xe5, 0x07, 0xc7, 0xa4, 0x6b, 0xfd, 0xa9,
+ 0xb7, 0x1b, 0x58, 0x6a, 0xc5, 0xf4, 0x6a, 0x00, 0xb1, 0x58, 0x7b, 0x7e,
+ 0x39, 0xb9, 0xe6, 0x58, 0xbf, 0xff, 0x61, 0xce, 0xc1, 0x36, 0xe3, 0x69,
+ 0x8f, 0x06, 0xac, 0x5d, 0x07, 0xd1, 0xf8, 0x90, 0xc5, 0xc1, 0x9d, 0x62,
+ 0xfd, 0x9a, 0x94, 0x1d, 0x62, 0xa7, 0x3c, 0x13, 0x8c, 0xd4, 0x2a, 0x69,
+ 0xc8, 0x5f, 0x34, 0x22, 0x7f, 0x09, 0x27, 0x6d, 0xba, 0x73, 0xa4, 0x5c,
+ 0x61, 0x89, 0x17, 0xfb, 0xed, 0x37, 0xe2, 0x7d, 0x90, 0x1b, 0x33, 0x06,
+ 0x6f, 0xb0, 0x7f, 0xc5, 0x8b, 0x6c, 0xf4, 0x7e, 0x24, 0x9f, 0x7f, 0xb8,
+ 0x59, 0xed, 0xcc, 0xf2, 0xc5, 0xf6, 0xf8, 0xf4, 0x2c, 0x5e, 0xde, 0xfa,
+ 0x58, 0xbe, 0xcf, 0x96, 0x2c, 0x56, 0x1e, 0x07, 0x07, 0xea, 0x48, 0xe6,
+ 0xc2, 0xb6, 0x36, 0xf3, 0x25, 0x82, 0x2c, 0x5f, 0x9c, 0xf9, 0xdf, 0x96,
+ 0x2f, 0x71, 0xf7, 0x56, 0x2f, 0xf3, 0x97, 0x5b, 0x4c, 0xf7, 0x16, 0x2a,
+ 0x74, 0x4a, 0xe0, 0xa3, 0x14, 0x88, 0x82, 0xf4, 0xf1, 0xba, 0xb1, 0x7f,
+ 0xfd, 0xf6, 0x37, 0x8d, 0x84, 0x01, 0xe9, 0xfa, 0x58, 0xbf, 0xfe, 0xc6,
+ 0x07, 0x36, 0xe1, 0xc3, 0xfb, 0xfe, 0x16, 0x2f, 0xff, 0xfe, 0x14, 0x4f,
+ 0xdc, 0xb8, 0x59, 0x36, 0xde, 0xbf, 0x1d, 0x1b, 0xa7, 0x31, 0x62, 0xff,
+ 0x80, 0xd3, 0x71, 0xbe, 0xc7, 0x58, 0xbf, 0xd8, 0x72, 0xc3, 0x1c, 0x0b,
+ 0x17, 0xfa, 0x3f, 0x93, 0x49, 0xe7, 0x58, 0xbf, 0xf8, 0xb3, 0xb9, 0x70,
+ 0x6d, 0xbe, 0x06, 0xb1, 0x53, 0xaa, 0x29, 0x19, 0x0e, 0x94, 0x4e, 0xa4,
+ 0x07, 0xcf, 0x1d, 0x08, 0xcc, 0x21, 0xad, 0xf9, 0xbd, 0x1e, 0xe2, 0xc5,
+ 0xfe, 0x7e, 0xf8, 0xe4, 0x2c, 0x58, 0xbe, 0x6d, 0x38, 0x16, 0x2a, 0x47,
+ 0xfa, 0x02, 0x8e, 0x19, 0xdf, 0xe0, 0x46, 0xf7, 0xff, 0xd9, 0x62, 0xb6,
+ 0x4f, 0x93, 0xc5, 0xf7, 0xfd, 0xc1, 0x6b, 0x4d, 0x0d, 0xa5, 0x8a, 0xc4,
+ 0xed, 0x5e, 0x35, 0x7f, 0x12, 0xdb, 0x75, 0x62, 0xf8, 0xbb, 0x9a, 0x16,
+ 0x2e, 0x7d, 0xd5, 0x8b, 0xfe, 0x8c, 0xee, 0x1e, 0x4f, 0x25, 0x8b, 0xfb,
+ 0x01, 0xb4, 0xb0, 0x0b, 0x17, 0x1f, 0xa5, 0x8a, 0x19, 0xe4, 0x39, 0x7d,
+ 0xff, 0xb0, 0xcd, 0xae, 0x36, 0x99, 0xa1, 0x62, 0xfd, 0x05, 0xe8, 0x02,
+ 0xc5, 0xef, 0x01, 0xd6, 0x2e, 0x89, 0xd6, 0x2b, 0x47, 0xb8, 0x72, 0x70,
+ 0x83, 0xb7, 0xc5, 0x8f, 0xba, 0xb1, 0x7f, 0xef, 0xb1, 0x00, 0x3f, 0xfd,
+ 0xe7, 0x58, 0xbf, 0x41, 0x81, 0xfe, 0x16, 0x2b, 0x63, 0x54, 0xa3, 0x02,
+ 0xb3, 0x92, 0x0c, 0x6b, 0x21, 0x01, 0xa2, 0x17, 0x84, 0xef, 0x0c, 0x7c,
+ 0x48, 0x1a, 0x0d, 0xfc, 0x44, 0xfb, 0xe6, 0x85, 0x8b, 0xfe, 0xcf, 0xfd,
+ 0xe5, 0xec, 0xfa, 0xc5, 0xf8, 0xb3, 0xef, 0xe5, 0x8b, 0xdb, 0x79, 0xd2,
+ 0xc5, 0x6e, 0x9e, 0x47, 0xc9, 0xef, 0xbb, 0x90, 0xb7, 0x56, 0x2f, 0xf3,
+ 0x38, 0x35, 0xa1, 0x7d, 0x62, 0xfe, 0x83, 0x70, 0x98, 0xd5, 0x8b, 0xfb,
+ 0x3c, 0x13, 0xd9, 0xf5, 0x8a, 0x84, 0xe3, 0xe4, 0x5f, 0x90, 0x81, 0x62,
+ 0x5f, 0x94, 0x11, 0xa7, 0x0b, 0xaf, 0xe9, 0xe6, 0x8e, 0x0b, 0xb5, 0x8b,
+ 0x85, 0xf5, 0x8b, 0xfc, 0x19, 0x39, 0xba, 0xd4, 0x2c, 0x54, 0x1f, 0xfc,
+ 0xe6, 0x4e, 0x31, 0x7f, 0xff, 0x75, 0xb3, 0xa7, 0x26, 0xf6, 0xce, 0xa3,
+ 0xc4, 0xe0, 0x58, 0xbb, 0x60, 0x92, 0xc5, 0xe7, 0xc2, 0x58, 0xbf, 0xfb,
+ 0xc5, 0x00, 0x7f, 0x00, 0x32, 0x92, 0xc5, 0xf3, 0x4c, 0xd0, 0xb1, 0x6e,
+ 0x2c, 0x50, 0xcd, 0xa6, 0x11, 0x5f, 0xb3, 0xdb, 0x99, 0xe5, 0x8b, 0xcd,
+ 0xad, 0xae, 0x79, 0x64, 0x41, 0x7f, 0xff, 0xb9, 0x9d, 0x04, 0xf0, 0xbb,
+ 0x97, 0x39, 0xe8, 0x8f, 0x71, 0x62, 0xfd, 0xe8, 0x8f, 0x71, 0x62, 0xfa,
+ 0x23, 0xdc, 0x58, 0xbd, 0xdc, 0xb9, 0xc3, 0xca, 0xf1, 0x45, 0x62, 0x39,
+ 0x85, 0x0b, 0x1a, 0xfa, 0x68, 0x1e, 0x8c, 0x66, 0xb6, 0x37, 0x45, 0x29,
+ 0xb0, 0x23, 0xec, 0x50, 0xc1, 0x89, 0x55, 0x13, 0xb8, 0xca, 0x16, 0x43,
+ 0x8c, 0xc3, 0x25, 0x75, 0x9b, 0x08, 0x1e, 0xa3, 0x83, 0xee, 0x31, 0xb6,
+ 0x84, 0x5c, 0xd1, 0xfd, 0x6a, 0x50, 0x3f, 0xe5, 0x53, 0x3c, 0x7c, 0x20,
+ 0x86, 0x81, 0x4e, 0x0d, 0x72, 0x54, 0x37, 0xa5, 0x15, 0x0a, 0x1c, 0xbb,
+ 0xcb, 0x8c, 0x61, 0xdc, 0x1d, 0x0c, 0x6c, 0x24, 0xa0, 0x4b, 0xc1, 0xff,
+ 0xeb, 0x17, 0x04, 0xfa, 0xc5, 0xfb, 0x5d, 0x3b, 0xf4, 0xa8, 0x8b, 0x8b,
+ 0xda, 0x17, 0xd6, 0x2f, 0xde, 0x00, 0x65, 0x24, 0x8b, 0xf7, 0x3d, 0xf8,
+ 0x02, 0xc5, 0xf9, 0xe7, 0x8d, 0x09, 0x62, 0xe7, 0x3a, 0xc5, 0xb6, 0x61,
+ 0x32, 0x19, 0xc7, 0xf0, 0x6b, 0x46, 0xee, 0x3c, 0x22, 0xad, 0xc2, 0x90,
+ 0xca, 0x6f, 0xc4, 0x29, 0x67, 0x16, 0x2f, 0x6e, 0x30, 0x16, 0x2f, 0x63,
+ 0x7d, 0x62, 0xf1, 0x10, 0xd6, 0x2e, 0x96, 0xce, 0x22, 0x01, 0x8a, 0x3e,
+ 0x40, 0x43, 0x95, 0xb2, 0xb8, 0xab, 0x29, 0x61, 0xfd, 0xc3, 0xf6, 0xff,
+ 0xe3, 0xbc, 0xb6, 0x73, 0x5d, 0x3b, 0xf4, 0xa8, 0x99, 0x8b, 0xed, 0x90,
+ 0xb3, 0x1d, 0x62, 0xff, 0xe1, 0xec, 0x90, 0x9c, 0x31, 0xfd, 0x8d, 0x58,
+ 0xbf, 0xfc, 0x14, 0x03, 0xfb, 0xdf, 0xc2, 0x27, 0xf2, 0xc5, 0xef, 0xb7,
+ 0x16, 0x2f, 0x82, 0xbc, 0x8f, 0x2c, 0x5f, 0xd1, 0xc2, 0x8f, 0x71, 0x62,
+ 0xb6, 0x11, 0xea, 0x1c, 0x9e, 0xb6, 0x34, 0x73, 0x6c, 0x09, 0xa1, 0x63,
+ 0x8d, 0xfb, 0xda, 0x14, 0x6f, 0x58, 0xbf, 0xf1, 0xb1, 0x9a, 0xdb, 0x82,
+ 0xd4, 0xeb, 0x17, 0x41, 0xd6, 0x28, 0x2a, 0x88, 0x50, 0xb0, 0xae, 0x48,
+ 0x77, 0xd8, 0x2d, 0x4e, 0xb1, 0x76, 0xe6, 0xc6, 0xb1, 0x71, 0x9e, 0x58,
+ 0xad, 0x88, 0xf7, 0x76, 0x11, 0x20, 0xc8, 0x2f, 0xb6, 0x30, 0xaf, 0x21,
+ 0x62, 0xf6, 0xc6, 0x16, 0xe1, 0x6e, 0xb1, 0x60, 0xb5, 0xb1, 0x9e, 0xee,
+ 0xc3, 0x2c, 0xb4, 0xcb, 0x17, 0x47, 0x16, 0x2e, 0xd8, 0xa4, 0xb1, 0x5b,
+ 0x09, 0x10, 0x13, 0x9c, 0xf6, 0x27, 0x30, 0xbd, 0xcf, 0xc5, 0x8b, 0xfc,
+ 0xfd, 0xf1, 0xc8, 0x58, 0xb1, 0x7f, 0xe9, 0x67, 0xfe, 0xf2, 0x66, 0x25,
+ 0x8a, 0xd2, 0x21, 0xc0, 0x2f, 0xe3, 0x3b, 0xb7, 0x36, 0x35, 0x8b, 0xf7,
+ 0x18, 0x9e, 0x75, 0x8b, 0xff, 0x7d, 0xbd, 0xc7, 0xee, 0x7c, 0x31, 0x62,
+ 0xff, 0xdb, 0xe3, 0xed, 0x13, 0x4d, 0x1d, 0x2c, 0x50, 0x55, 0x1f, 0xbb,
+ 0x11, 0x86, 0xc3, 0x20, 0xe8, 0xa1, 0x90, 0xae, 0x63, 0xac, 0x5f, 0xbc,
+ 0x4d, 0xdf, 0x96, 0x2b, 0xa3, 0xc0, 0x0c, 0x5e, 0xff, 0xb6, 0x30, 0x1c,
+ 0x3d, 0x34, 0xf0, 0xb1, 0x7b, 0x63, 0xfc, 0xcb, 0x17, 0xbc, 0xe4, 0xb1,
+ 0x5b, 0x19, 0xe0, 0x6c, 0x44, 0x97, 0xc1, 0x40, 0xb7, 0xe4, 0x2c, 0x58,
+ 0x4b, 0x14, 0x16, 0x8f, 0x01, 0x8b, 0xae, 0xdc, 0xd8, 0xd6, 0x2f, 0xff,
+ 0xff, 0xe0, 0xbf, 0x71, 0xb0, 0xf6, 0x10, 0xfa, 0xdf, 0xa9, 0x4d, 0xbc,
+ 0x41, 0x68, 0x2c, 0x0b, 0x85, 0xb8, 0x5a, 0xdb, 0xb7, 0xfb, 0x8b, 0x17,
+ 0xfe, 0x28, 0x9f, 0x4f, 0xf8, 0x3b, 0x2c, 0x5f, 0xff, 0xf3, 0x78, 0x3d,
+ 0x47, 0xe3, 0x3a, 0x1b, 0x14, 0xe7, 0x89, 0x2c, 0x5e, 0x04, 0x01, 0x62,
+ 0xff, 0xb0, 0xc2, 0xc3, 0x7e, 0xfb, 0xab, 0x15, 0x87, 0xb4, 0x43, 0xb7,
+ 0xf8, 0x9e, 0x6c, 0xdf, 0x1c, 0x58, 0xbf, 0xb9, 0xa8, 0xcf, 0x71, 0x62,
+ 0xc2, 0x58, 0xa8, 0x3c, 0x0c, 0x2e, 0xbf, 0xee, 0x40, 0x7f, 0x69, 0x41,
+ 0xd6, 0x2f, 0xc0, 0x61, 0xe6, 0xea, 0xc5, 0xfc, 0x37, 0x3e, 0xa3, 0x8b,
+ 0x15, 0x87, 0xb2, 0xe5, 0x77, 0xfe, 0xde, 0x27, 0xe8, 0x6d, 0xbe, 0x06,
+ 0xb1, 0x7f, 0x41, 0xde, 0x51, 0xe5, 0x8b, 0xff, 0xa0, 0xef, 0xec, 0xec,
+ 0x07, 0x0f, 0xeb, 0x17, 0xff, 0xba, 0xd0, 0xa7, 0xef, 0x8d, 0xae, 0xbf,
+ 0x8b, 0x17, 0xcd, 0xbd, 0xc0, 0xb1, 0x50, 0x7e, 0x9e, 0x50, 0xa1, 0xa6,
+ 0xdb, 0x84, 0x06, 0xa2, 0x7c, 0xb4, 0xa1, 0x77, 0x7c, 0xd3, 0x88, 0x96,
+ 0x2f, 0xd9, 0x3e, 0x02, 0x65, 0x8a, 0xda, 0x79, 0xbe, 0x23, 0xbf, 0x30,
+ 0x43, 0x5b, 0xa5, 0x8b, 0xfe, 0x14, 0xb8, 0xe7, 0x72, 0x02, 0xc5, 0x68,
+ 0xf9, 0x5c, 0xb2, 0xfc, 0x08, 0xe6, 0x76, 0xb1, 0x7d, 0xb5, 0x9e, 0x65,
+ 0x8b, 0x46, 0x8f, 0x3b, 0x85, 0x37, 0xfb, 0x6e, 0x13, 0xe8, 0x1b, 0x8b,
+ 0x17, 0x14, 0x96, 0x2f, 0x6a, 0x0d, 0x58, 0xbf, 0xfe, 0x7f, 0xe7, 0x60,
+ 0xf9, 0x8f, 0xf9, 0xbe, 0x25, 0x8a, 0x64, 0x44, 0xcc, 0x2e, 0x71, 0xeb,
+ 0xfc, 0x3d, 0x38, 0x1f, 0x34, 0xb1, 0x7f, 0x67, 0x20, 0x32, 0x85, 0x8a,
+ 0x1a, 0x6a, 0x39, 0x0c, 0x16, 0x30, 0xf9, 0x9d, 0xb1, 0x62, 0xe7, 0x3a,
+ 0xc5, 0x70, 0xd4, 0x04, 0x11, 0xb8, 0x27, 0x96, 0x2c, 0x17, 0x58, 0xb0,
+ 0x20, 0xd8, 0x08, 0x6a, 0xf1, 0xdf, 0xcb, 0x16, 0x0b, 0xac, 0x56, 0x1b,
+ 0x32, 0x1d, 0xbf, 0x6e, 0x0c, 0x9c, 0xc5, 0x8a, 0x83, 0xcb, 0xf0, 0xfd,
+ 0xfe, 0x27, 0x9e, 0x0a, 0x00, 0xb1, 0x7f, 0xff, 0x74, 0x50, 0x7d, 0xb1,
+ 0xad, 0x36, 0xfd, 0x3b, 0x81, 0x62, 0xfd, 0x27, 0xf3, 0x9a, 0xb1, 0x50,
+ 0x88, 0x8c, 0x5f, 0xbe, 0x2c, 0x04, 0x2c, 0x51, 0x1e, 0x16, 0xf2, 0x1b,
+ 0xc3, 0xc1, 0xac, 0x52, 0xc5, 0xf6, 0x7b, 0x00, 0xb1, 0x63, 0x40, 0x6b,
+ 0x88, 0x32, 0xb0, 0xfc, 0x9d, 0x2e, 0xfe, 0x63, 0x1b, 0x99, 0xd2, 0xc5,
+ 0x32, 0x39, 0x35, 0x09, 0x5e, 0x10, 0x5e, 0xf4, 0x49, 0x62, 0xff, 0xd3,
+ 0x89, 0xe6, 0xc6, 0xd0, 0xb7, 0x56, 0x29, 0x8f, 0x85, 0xc7, 0x6f, 0x1e,
+ 0x24, 0xb1, 0x7c, 0xdb, 0xe3, 0x4b, 0x17, 0xb8, 0xf3, 0x2c, 0x54, 0x1e,
+ 0xff, 0xc7, 0x7c, 0x49, 0x7f, 0x6c, 0xcc, 0x15, 0xfb, 0x92, 0xc5, 0x6c,
+ 0x6c, 0xc8, 0x3d, 0x84, 0x41, 0x3c, 0x32, 0x64, 0x7c, 0x38, 0x61, 0x61,
+ 0x07, 0x4e, 0xbd, 0x90, 0x34, 0xa0, 0x09, 0xa1, 0x39, 0xa8, 0x44, 0x9d,
+ 0xbf, 0xf1, 0xbc, 0x3b, 0x48, 0x14, 0xca, 0x14, 0x9c, 0x21, 0xf4, 0x7c,
+ 0x1b, 0xe1, 0x2a, 0x1b, 0xf8, 0x42, 0xeb, 0xe7, 0x90, 0x67, 0x58, 0xbd,
+ 0xd1, 0x01, 0x62, 0xda, 0xd1, 0xe1, 0x70, 0x92, 0xf3, 0x97, 0x4b, 0x17,
+ 0xbc, 0x50, 0xb1, 0x7c, 0x45, 0x9e, 0x58, 0xa0, 0xa9, 0xbd, 0x81, 0xca,
+ 0xe1, 0xff, 0x18, 0xb5, 0x7c, 0xff, 0x69, 0x96, 0x2f, 0x8a, 0x68, 0x1a,
+ 0xc5, 0xdd, 0xf9, 0x62, 0xfb, 0xf3, 0x40, 0xd6, 0x2f, 0x05, 0x45, 0x0b,
+ 0x17, 0xb5, 0x38, 0xd6, 0x2f, 0xda, 0x80, 0xdc, 0x96, 0x28, 0x67, 0x8e,
+ 0x01, 0xfa, 0x84, 0xf5, 0xb2, 0x14, 0xdd, 0x11, 0xb1, 0x1c, 0xc4, 0x6e,
+ 0x32, 0x02, 0x41, 0x34, 0x5f, 0xf9, 0xf0, 0x23, 0x68, 0xd1, 0x67, 0xd6,
+ 0x2f, 0x7e, 0x3b, 0x58, 0xbf, 0x41, 0xcb, 0x26, 0x58, 0xbf, 0x9b, 0x08,
+ 0x7f, 0x85, 0x8b, 0x1d, 0x62, 0xc7, 0x58, 0xba, 0x09, 0x62, 0xa7, 0x35,
+ 0x06, 0x09, 0x5e, 0xfe, 0x4c, 0xb1, 0x43, 0x46, 0x7f, 0x45, 0x1b, 0xa5,
+ 0x9c, 0x3a, 0xf1, 0x1d, 0x2c, 0x5d, 0x1c, 0x58, 0xbf, 0xb5, 0x04, 0x2c,
+ 0xfa, 0xc5, 0xff, 0x3f, 0x78, 0xdd, 0x74, 0xe3, 0x58, 0xbe, 0xd4, 0x61,
+ 0x2c, 0x5f, 0x3f, 0xa4, 0x05, 0x8b, 0xde, 0xe6, 0x2c, 0x5f, 0xe1, 0x1c,
+ 0xb2, 0x66, 0x9d, 0x62, 0xc2, 0x58, 0xbf, 0xcd, 0xd3, 0xe6, 0xb3, 0xcb,
+ 0x14, 0x03, 0xc5, 0xe0, 0x95, 0xe1, 0x6c, 0x64, 0xb1, 0x46, 0xa7, 0x3d,
+ 0xd0, 0xbe, 0x8b, 0x4e, 0x77, 0xf2, 0x17, 0x23, 0xe0, 0xef, 0x9e, 0x82,
+ 0x11, 0x5f, 0xf6, 0xa3, 0x25, 0x1f, 0x80, 0x2c, 0x5f, 0xfe, 0xdb, 0xf7,
+ 0x6f, 0x00, 0x44, 0x4f, 0x25, 0x8b, 0xff, 0xcd, 0xc1, 0x1f, 0x3a, 0xfc,
+ 0x17, 0xb8, 0xb1, 0x7a, 0x42, 0x1a, 0xc5, 0x9a, 0x47, 0xd3, 0x32, 0x5d,
+ 0xff, 0x06, 0x7c, 0xe3, 0xbf, 0x72, 0x58, 0xbb, 0x63, 0x0a, 0xac, 0x5f,
+ 0xf7, 0xe1, 0x86, 0xdc, 0x9d, 0xd6, 0x2b, 0x61, 0x9e, 0xd3, 0x10, 0xd4,
+ 0xeb, 0xaf, 0x12, 0x41, 0xc8, 0x76, 0xf4, 0x9c, 0xd1, 0xd5, 0x6a, 0x10,
+ 0x47, 0x38, 0xfc, 0x2d, 0x00, 0x50, 0x50, 0x95, 0xbf, 0xff, 0xff, 0xff,
+ 0xfd, 0xb0, 0xc2, 0xb9, 0xb0, 0xf6, 0x2d, 0x85, 0xb0, 0xba, 0x0b, 0xc0,
+ 0x5b, 0xec, 0x5a, 0x9c, 0x26, 0x08, 0x61, 0x6a, 0x37, 0x3b, 0x0f, 0xfb,
+ 0x14, 0x46, 0xc5, 0xba, 0x16, 0x7b, 0x6e, 0xdf, 0xee, 0x2c, 0x5f, 0xf1,
+ 0x0e, 0x66, 0x2e, 0xe5, 0xc5, 0x8b, 0xff, 0xed, 0x7c, 0xc7, 0x1e, 0x4e,
+ 0x2f, 0x6b, 0x50, 0xb1, 0x7f, 0xfa, 0x5f, 0x14, 0x6b, 0x67, 0xed, 0xd3,
+ 0xe9, 0x62, 0xfc, 0x1e, 0xb8, 0xe4, 0xb1, 0x5d, 0x9f, 0xc7, 0xd3, 0xea,
+ 0x13, 0x29, 0x73, 0xb0, 0x43, 0x2e, 0xdc, 0x58, 0xbc, 0x2d, 0x01, 0x62,
+ 0xe1, 0x4b, 0x69, 0xb0, 0xe8, 0x4a, 0xff, 0xdf, 0xc2, 0xc3, 0x70, 0xb0,
+ 0x6b, 0x17, 0xfe, 0x32, 0x3c, 0x36, 0xdd, 0xe4, 0x1d, 0x62, 0xfe, 0xfb,
+ 0x78, 0xa0, 0xeb, 0x15, 0xd9, 0xf8, 0x12, 0x1d, 0xf7, 0x33, 0xbf, 0x2c,
+ 0x5e, 0x9a, 0x0c, 0x58, 0xbe, 0x7e, 0x30, 0xd6, 0x2b, 0x0f, 0x04, 0xc1,
+ 0xfb, 0xf0, 0xff, 0x05, 0x3a, 0xc5, 0xf3, 0x17, 0xb8, 0xb1, 0x7f, 0xff,
+ 0xc7, 0x6d, 0x7c, 0x5c, 0x94, 0x6f, 0xd4, 0x17, 0xbf, 0x92, 0x58, 0xa9,
+ 0x22, 0x2d, 0x88, 0xaf, 0xfc, 0xde, 0x6e, 0x98, 0x7e, 0xce, 0x96, 0x2a,
+ 0x75, 0x53, 0x92, 0x30, 0xc8, 0x56, 0xe8, 0x8b, 0xec, 0xa4, 0x45, 0xe8,
+ 0x5a, 0x04, 0x22, 0xb8, 0xe3, 0x58, 0xbf, 0x13, 0xe9, 0xe4, 0xb1, 0x73,
+ 0x6f, 0x58, 0xbf, 0xc4, 0x3f, 0xc1, 0xc2, 0x09, 0x62, 0xa0, 0xfd, 0x86,
+ 0x4e, 0xe3, 0x37, 0xa0, 0x70, 0xb1, 0x7e, 0xcf, 0xff, 0x00, 0xb1, 0x6e,
+ 0x8e, 0x78, 0x84, 0x39, 0x7c, 0xe6, 0x3e, 0xea, 0xc5, 0x39, 0xe7, 0x11,
+ 0x45, 0xf8, 0x5d, 0x7d, 0x8c, 0x58, 0xbe, 0xf6, 0xe6, 0x7d, 0x62, 0xfd,
+ 0x3c, 0x98, 0xb1, 0x62, 0xff, 0xff, 0x39, 0x74, 0x58, 0x3f, 0x8b, 0x6f,
+ 0xe2, 0x5a, 0x89, 0xd6, 0x2b, 0x11, 0x64, 0xe4, 0xc2, 0x28, 0xba, 0x3e,
+ 0xb1, 0x7f, 0x06, 0x51, 0xf8, 0x92, 0xc5, 0xff, 0xfc, 0x69, 0x60, 0x05,
+ 0xcd, 0xb2, 0x6f, 0xc7, 0x44, 0xeb, 0x17, 0xee, 0x46, 0xee, 0xa1, 0x62,
+ 0x8d, 0x46, 0x71, 0xc5, 0xdc, 0xb8, 0x0b, 0xd7, 0xfc, 0xdd, 0x4d, 0x2f,
+ 0xc1, 0x1a, 0xb1, 0x7f, 0x75, 0xb7, 0xee, 0x4c, 0xb1, 0x7a, 0x0f, 0xe5,
+ 0x8a, 0x24, 0x44, 0x88, 0xf0, 0xc3, 0x0b, 0xfd, 0x86, 0x47, 0x89, 0xf8,
+ 0xb1, 0x79, 0xbe, 0xcb, 0x15, 0x07, 0xfe, 0xc6, 0x1e, 0x33, 0xba, 0x09,
+ 0x62, 0xfb, 0x3a, 0x1e, 0x2c, 0x52, 0xc5, 0xf1, 0x0c, 0x3e, 0xd6, 0x2f,
+ 0xcd, 0x39, 0xe3, 0xa5, 0x8b, 0x85, 0xe5, 0x8b, 0xcf, 0xa9, 0x6d, 0x44,
+ 0xb3, 0x11, 0xb8, 0x67, 0x89, 0x77, 0x0a, 0xab, 0x62, 0x65, 0xcd, 0x44,
+ 0xa5, 0xac, 0x96, 0x00, 0x6b, 0xf3, 0x42, 0x3b, 0x50, 0xbf, 0x39, 0x07,
+ 0xe1, 0xba, 0xf0, 0xfc, 0x28, 0xd1, 0x7c, 0x5a, 0x28, 0x56, 0x5f, 0xe3,
+ 0x5f, 0x7f, 0x59, 0xdf, 0x96, 0x2e, 0x71, 0xac, 0x5d, 0xbf, 0x75, 0x62,
+ 0x8d, 0x3e, 0xdd, 0x1c, 0xb8, 0xbd, 0xff, 0xfb, 0x5a, 0x6c, 0xde, 0x42,
+ 0xe6, 0xde, 0x09, 0xf8, 0xb1, 0x4b, 0x17, 0xff, 0xdc, 0x6d, 0xcc, 0xeb,
+ 0xec, 0x44, 0x2d, 0x4e, 0xb1, 0x5a, 0x3e, 0x0f, 0x06, 0x5f, 0xde, 0xc3,
+ 0xf7, 0x87, 0x58, 0xa8, 0x4c, 0x2f, 0x21, 0x74, 0xc4, 0x57, 0xf8, 0xe7,
+ 0x79, 0x71, 0xa4, 0xb1, 0x7f, 0x8d, 0xdb, 0x1d, 0x83, 0x50, 0xb1, 0x58,
+ 0x7d, 0x8e, 0x69, 0x4c, 0x9f, 0xcf, 0xe3, 0x3a, 0x28, 0x4f, 0xdf, 0xf1,
+ 0x84, 0xe6, 0xe0, 0xd8, 0x96, 0x2f, 0xff, 0x6f, 0xc1, 0xfe, 0x37, 0x9e,
+ 0x09, 0xc3, 0x58, 0xb4, 0xcb, 0x15, 0x87, 0xc2, 0x24, 0xeb, 0xfe, 0x97,
+ 0x5f, 0x63, 0x20, 0x86, 0xb1, 0x7f, 0x0d, 0xe5, 0xc6, 0x92, 0xc5, 0x42,
+ 0x64, 0x9a, 0x84, 0xd3, 0x90, 0x88, 0xee, 0xf8, 0x45, 0xee, 0x2c, 0x5f,
+ 0xdc, 0x13, 0x13, 0x71, 0x62, 0xf4, 0x6a, 0x16, 0x2b, 0x69, 0xe4, 0xfc,
+ 0xb6, 0xe8, 0xe9, 0x62, 0xba, 0x45, 0x46, 0x9b, 0x02, 0x12, 0x5e, 0x96,
+ 0xe1, 0x8b, 0x17, 0x01, 0x96, 0x2f, 0xc7, 0x97, 0xc3, 0xe2, 0xc5, 0xb5,
+ 0xb4, 0xf0, 0x83, 0x17, 0xbf, 0x39, 0x85, 0x83, 0x58, 0xa8, 0x45, 0xbb,
+ 0x32, 0x68, 0xae, 0xff, 0xc5, 0x1d, 0x1a, 0xf9, 0xa6, 0x02, 0xc5, 0xfd,
+ 0xcc, 0x6d, 0x69, 0xd6, 0x2f, 0xdc, 0xda, 0x07, 0xf2, 0xc5, 0x4e, 0x89,
+ 0x70, 0x1f, 0xf8, 0xb6, 0xe8, 0xd2, 0xc5, 0xff, 0xd3, 0xe7, 0x19, 0xff,
+ 0xb2, 0x61, 0x86, 0x24, 0x59, 0x80, 0x7c, 0x64, 0x2f, 0x7f, 0x77, 0x29,
+ 0x98, 0x41, 0x75, 0x8b, 0xfc, 0xfa, 0xdc, 0x17, 0xdb, 0x4b, 0x15, 0x07,
+ 0xd8, 0x23, 0x5a, 0x84, 0xd1, 0xc7, 0x09, 0x4f, 0xc2, 0x4a, 0xfb, 0xe2,
+ 0xee, 0x4b, 0x17, 0xf7, 0x79, 0xf1, 0x76, 0x05, 0x8b, 0x7d, 0x62, 0xfe,
+ 0x3f, 0x3f, 0x05, 0xe5, 0x8b, 0xed, 0x47, 0xb8, 0xb1, 0x7a, 0x7f, 0x89,
+ 0x62, 0xff, 0xdf, 0x7e, 0x7f, 0x37, 0xe7, 0xb8, 0xb1, 0x50, 0x7c, 0x0e,
+ 0x3f, 0x4c, 0x8d, 0x19, 0x8b, 0xbf, 0x08, 0x3b, 0xf3, 0x0b, 0xa6, 0x9d,
+ 0x62, 0xa4, 0x9c, 0xc6, 0x12, 0xf4, 0x63, 0xe8, 0x71, 0xee, 0x1a, 0xdf,
+ 0xfe, 0x7f, 0x0b, 0x6f, 0x3e, 0xc3, 0x28, 0xdd, 0x58, 0xbf, 0xd9, 0x06,
+ 0xbf, 0x9c, 0xd5, 0x8a, 0x02, 0x20, 0xc9, 0x3e, 0xfc, 0x1f, 0xb9, 0x1e,
+ 0x58, 0xbd, 0x3f, 0x09, 0x62, 0xa4, 0x79, 0x1a, 0x2a, 0xbf, 0xc7, 0xce,
+ 0x89, 0xf3, 0xa5, 0x8b, 0x85, 0x32, 0xc5, 0xd2, 0xe4, 0x1e, 0x68, 0x0d,
+ 0x2f, 0x8f, 0xc0, 0xf8, 0xb1, 0x7b, 0xa1, 0x74, 0xb1, 0x50, 0x8e, 0x1e,
+ 0xdb, 0xd8, 0xb4, 0x44, 0xb7, 0xfd, 0xef, 0x41, 0xf3, 0x08, 0xd5, 0x8b,
+ 0xff, 0xef, 0x7f, 0x02, 0x7b, 0x3e, 0x59, 0xef, 0xb2, 0xc5, 0x76, 0x88,
+ 0xa2, 0x39, 0xbf, 0x89, 0xfd, 0x28, 0x35, 0x62, 0xff, 0x60, 0x06, 0x27,
+ 0xd4, 0x96, 0x2a, 0x0f, 0x8a, 0x72, 0xeb, 0xf9, 0xdc, 0x7b, 0xf0, 0x6b,
+ 0x16, 0x31, 0x62, 0xf9, 0xb7, 0x5f, 0x8b, 0x17, 0x3f, 0x4a, 0x8b, 0x3c,
+ 0xbd, 0x84, 0x35, 0x8a, 0x63, 0xf9, 0xf8, 0x9b, 0x92, 0x98, 0x4b, 0x7f,
+ 0xa0, 0x8d, 0xd0, 0xa0, 0x96, 0x2f, 0xe0, 0x39, 0x49, 0x8e, 0xb1, 0x77,
+ 0x4c, 0xb1, 0x50, 0xa8, 0x0a, 0x78, 0x42, 0x8c, 0x8b, 0xa8, 0x54, 0x31,
+ 0xd8, 0x0c, 0xc4, 0x5b, 0x7f, 0xbf, 0xee, 0x3f, 0x61, 0x9d, 0x62, 0xff,
+ 0xf1, 0x7b, 0x73, 0x26, 0x93, 0xea, 0x71, 0xc2, 0xc5, 0xfe, 0x89, 0x37,
+ 0xa3, 0xdc, 0x58, 0xbf, 0xdc, 0x11, 0xdb, 0xc0, 0x75, 0x8b, 0xc1, 0xfe,
+ 0x16, 0x2a, 0x47, 0xa4, 0x03, 0x4b, 0xc3, 0x1b, 0xac, 0x57, 0xd1, 0x88,
+ 0x50, 0x85, 0xf1, 0x15, 0xfd, 0x20, 0xf3, 0xef, 0xda, 0xc5, 0xff, 0xfe,
+ 0x62, 0x13, 0xfb, 0x6e, 0x0f, 0x6e, 0x49, 0x8d, 0x35, 0xd6, 0x2f, 0xde,
+ 0x28, 0xce, 0xd6, 0x2a, 0x15, 0x1d, 0xe1, 0xbb, 0x46, 0x26, 0xe6, 0x9c,
+ 0x30, 0x0d, 0x96, 0xff, 0x8d, 0x72, 0xcd, 0xe5, 0x9c, 0x58, 0xbf, 0xb7,
+ 0x96, 0x73, 0x09, 0x62, 0xdb, 0xab, 0x15, 0x87, 0x87, 0xc2, 0xeb, 0xcd,
+ 0x28, 0x58, 0xb3, 0xed, 0x37, 0xbc, 0x21, 0xb6, 0x8d, 0x47, 0x17, 0xe1,
+ 0x75, 0x7f, 0x98, 0x78, 0x73, 0x33, 0xeb, 0x16, 0x9d, 0x62, 0xff, 0xff,
+ 0xb3, 0xdc, 0xce, 0x9c, 0x81, 0xb7, 0x50, 0x42, 0xf4, 0x7d, 0x62, 0xfd,
+ 0xc1, 0xb4, 0x12, 0xc5, 0x42, 0x35, 0x8e, 0x68, 0x42, 0x7e, 0x68, 0xb6,
+ 0x96, 0x2f, 0xfd, 0xe6, 0x98, 0xc7, 0x1c, 0x77, 0xc5, 0x8a, 0x73, 0xd4,
+ 0xe0, 0x95, 0x32, 0x76, 0xaf, 0x18, 0x28, 0xa1, 0x1f, 0x7f, 0xa5, 0xc8,
+ 0x97, 0x18, 0x96, 0x2e, 0x00, 0x16, 0x2f, 0x18, 0x61, 0x89, 0x17, 0xfd,
+ 0x2e, 0x16, 0x74, 0x3c, 0xd2, 0x46, 0xc9, 0xa1, 0xb4, 0x96, 0x2f, 0xfb,
+ 0xd9, 0xa9, 0xe3, 0x7b, 0x9d, 0x62, 0xa1, 0x30, 0x76, 0x33, 0x73, 0x9f,
+ 0x26, 0x86, 0x25, 0x7f, 0x87, 0xf8, 0x28, 0xc3, 0x16, 0x2f, 0xfb, 0xee,
+ 0x7f, 0xc0, 0xda, 0x16, 0x2a, 0x47, 0xd7, 0xe3, 0x3b, 0xf0, 0x41, 0x1f,
+ 0x06, 0xb1, 0x7f, 0xfb, 0xdc, 0xf1, 0xb0, 0x52, 0xc9, 0xc5, 0x25, 0x8b,
+ 0xff, 0xed, 0xe4, 0x29, 0x66, 0xf6, 0xf4, 0x75, 0x9f, 0x58, 0xbf, 0xff,
+ 0x84, 0x5e, 0xe4, 0x11, 0xbf, 0x6d, 0xbf, 0xc0, 0x3a, 0xc5, 0xfb, 0x37,
+ 0xed, 0x91, 0xd6, 0x2d, 0xe8, 0x46, 0xf4, 0x95, 0x3e, 0xbb, 0x50, 0x9d,
+ 0x6e, 0x11, 0x39, 0x58, 0xa3, 0x2b, 0xbf, 0xf7, 0x72, 0x21, 0x03, 0x6f,
+ 0x47, 0x02, 0xc5, 0xd0, 0x6a, 0xc5, 0xe2, 0x89, 0x2c, 0x5f, 0xf0, 0xe0,
+ 0xa0, 0x12, 0xfb, 0x2c, 0x5e, 0xf3, 0x4e, 0xb1, 0x7f, 0xfb, 0xbc, 0x91,
+ 0x09, 0xf9, 0xfc, 0x03, 0xac, 0x51, 0xa7, 0xd0, 0xe3, 0xd5, 0x09, 0x9d,
+ 0xce, 0x8a, 0x31, 0x86, 0x1c, 0x14, 0x28, 0x2f, 0xf7, 0xd8, 0x64, 0xef,
+ 0x32, 0xc5, 0xfe, 0x1f, 0xc4, 0xe0, 0xdc, 0xc5, 0x8b, 0xe7, 0x04, 0x69,
+ 0x62, 0xff, 0xff, 0x66, 0xb4, 0xd0, 0x0d, 0xbd, 0x7d, 0xa0, 0x05, 0x00,
+ 0x58, 0xa8, 0x47, 0x73, 0x19, 0xf0, 0xdf, 0xc4, 0x57, 0xd1, 0xec, 0x9d,
+ 0x62, 0xfa, 0x40, 0x04, 0x2c, 0x5f, 0xe8, 0xdb, 0xec, 0xe7, 0x21, 0x62,
+ 0xf4, 0x61, 0x2c, 0x5f, 0x0c, 0x5e, 0xe2, 0xc5, 0x86, 0x03, 0x7e, 0x18,
+ 0xdd, 0xb7, 0x16, 0x2f, 0xf4, 0x79, 0xb7, 0xc1, 0x74, 0xb1, 0x7d, 0x18,
+ 0x52, 0x63, 0xca, 0xe0, 0xad, 0x1a, 0x9b, 0x17, 0x64, 0x7a, 0x23, 0x27,
+ 0x4f, 0x39, 0x5f, 0xd9, 0xc9, 0x7c, 0x3e, 0x2c, 0x53, 0x1f, 0xe1, 0x26,
+ 0x5e, 0x82, 0x35, 0x62, 0xff, 0xd0, 0x72, 0xcf, 0x70, 0x5a, 0x92, 0xc5,
+ 0x49, 0xba, 0x86, 0x1c, 0x6b, 0xd9, 0x0e, 0x93, 0x61, 0xd5, 0xd4, 0xa0,
+ 0xce, 0xe3, 0xd2, 0x68, 0x6b, 0x4d, 0x1a, 0x5e, 0xa5, 0x64, 0x1e, 0x55,
+ 0x5f, 0xe5, 0x79, 0x82, 0x34, 0x12, 0x94, 0xc3, 0xc8, 0xdf, 0x3d, 0x19,
+ 0xee, 0xf9, 0x43, 0x21, 0x90, 0x04, 0x1d, 0xb6, 0xc6, 0xb1, 0x7f, 0xd9,
+ 0xa2, 0xcd, 0xef, 0xa9, 0x2c, 0x5c, 0x0e, 0x2c, 0x5e, 0xd6, 0xc0, 0x11,
+ 0x62, 0xe7, 0x92, 0xc5, 0xf8, 0xbd, 0x80, 0x3a, 0xc5, 0xf6, 0x9a, 0x3c,
+ 0xb1, 0x7f, 0x70, 0xb2, 0x68, 0x3a, 0xc5, 0x00, 0xf4, 0x3c, 0x45, 0x4c,
+ 0x8d, 0x63, 0x92, 0xb8, 0xb8, 0x9e, 0x2e, 0x8f, 0x2c, 0x5f, 0x01, 0xcc,
+ 0xf2, 0xc5, 0xfe, 0x73, 0x3e, 0xd1, 0xa8, 0x58, 0xbf, 0x84, 0x7e, 0x0b,
+ 0x53, 0xac, 0x5f, 0x9b, 0x7c, 0x17, 0x96, 0x2b, 0x63, 0x54, 0x85, 0x02,
+ 0xe3, 0x3a, 0x36, 0x1d, 0xdd, 0x9d, 0xb0, 0xbe, 0x89, 0x08, 0xcf, 0x86,
+ 0x37, 0xfe, 0xd3, 0x72, 0x41, 0xfe, 0x0a, 0x16, 0x2f, 0x34, 0x1d, 0x62,
+ 0xe6, 0xfa, 0xc5, 0x68, 0xd9, 0xee, 0x0e, 0x5f, 0xff, 0xbc, 0x68, 0xa3,
+ 0x07, 0xfc, 0xe7, 0x72, 0x8f, 0xac, 0x56, 0x91, 0xdc, 0x77, 0x22, 0x24,
+ 0xbf, 0xdb, 0x4b, 0x37, 0x96, 0x71, 0x62, 0xf8, 0x02, 0xd4, 0xeb, 0x17,
+ 0xa6, 0x16, 0x96, 0x2e, 0x79, 0x2c, 0x5f, 0xdc, 0x8e, 0xf6, 0x10, 0xce,
+ 0xb1, 0x7f, 0x1f, 0x0b, 0xdb, 0x98, 0xb1, 0x7f, 0xff, 0xb3, 0xc2, 0x01,
+ 0xde, 0x4e, 0x38, 0x27, 0xd3, 0xc9, 0x62, 0xfe, 0x27, 0x33, 0xd9, 0xfc,
+ 0x44, 0x79, 0x18, 0x5f, 0xec, 0xff, 0xc5, 0xe7, 0x25, 0x8b, 0x98, 0x6b,
+ 0x17, 0xf7, 0xfa, 0x7d, 0x3c, 0x96, 0x2d, 0xd4, 0x8f, 0x1b, 0x05, 0xef,
+ 0x34, 0xdc, 0x58, 0xa8, 0x3c, 0x63, 0x94, 0x5f, 0xfd, 0xe6, 0xfb, 0x9f,
+ 0x70, 0x5f, 0x6d, 0x2c, 0x5f, 0xcf, 0xe3, 0xc6, 0x79, 0x62, 0x9c, 0xfd,
+ 0x44, 0x91, 0x7d, 0xf8, 0xef, 0x8b, 0x16, 0xe2, 0xc5, 0xfd, 0x00, 0x6f,
+ 0xb1, 0xd6, 0x2a, 0x0d, 0xfb, 0x09, 0x5e, 0x2c, 0xe9, 0x62, 0xbe, 0x6f,
+ 0x38, 0x3f, 0x43, 0x56, 0xab, 0xd8, 0xbc, 0xd0, 0xc5, 0xd2, 0x19, 0xe1,
+ 0x7e, 0x50, 0x96, 0xe1, 0x0f, 0xa1, 0x3f, 0x7d, 0xfe, 0xdf, 0x75, 0x62,
+ 0xfd, 0xf7, 0x3b, 0x71, 0x62, 0x86, 0x79, 0xfd, 0x13, 0xd6, 0x2e, 0x37,
+ 0x34, 0xb7, 0x47, 0x86, 0xbd, 0xf9, 0xbe, 0xe7, 0x65, 0x8b, 0xc0, 0x0f,
+ 0xcb, 0x17, 0x9c, 0x80, 0xb1, 0x5b, 0x4f, 0x8b, 0x09, 0xfa, 0x1f, 0xbd,
+ 0xbf, 0x06, 0xb1, 0x6d, 0x4e, 0x7a, 0x13, 0x18, 0xdc, 0xff, 0x58, 0xbe,
+ 0x9a, 0x4e, 0x4b, 0x15, 0xa3, 0x75, 0xc1, 0x7b, 0xfc, 0x13, 0x58, 0x10,
+ 0x84, 0x62, 0xc5, 0x4e, 0x7b, 0x46, 0x10, 0xde, 0x08, 0xc3, 0x58, 0xac,
+ 0x3c, 0x37, 0x24, 0xa8, 0x5f, 0x07, 0x9c, 0xbd, 0x8d, 0xbf, 0x39, 0x26,
+ 0xf0, 0xee, 0x28, 0xc0, 0x6f, 0xe3, 0xf5, 0xb7, 0x0f, 0xc5, 0x8b, 0xff,
+ 0xff, 0xe0, 0x73, 0x30, 0x8d, 0x0f, 0x45, 0x19, 0xfd, 0x9e, 0x16, 0x4e,
+ 0x7c, 0x3a, 0xc5, 0xda, 0xc5, 0x8b, 0xb8, 0xcb, 0x15, 0x39, 0xae, 0xd0,
+ 0xbd, 0xc1, 0xc9, 0x62, 0xfa, 0x08, 0x33, 0xac, 0x56, 0x1e, 0xf1, 0xc8,
+ 0x83, 0x19, 0xac, 0x4c, 0xf3, 0xd1, 0x86, 0xdc, 0x0e, 0x2c, 0x5f, 0x6d,
+ 0x28, 0xe9, 0x62, 0xf9, 0xff, 0x01, 0xac, 0x56, 0x1f, 0x07, 0xc6, 0x37,
+ 0x92, 0xdf, 0x41, 0x98, 0x35, 0x8b, 0xff, 0xe1, 0x77, 0x2e, 0x0f, 0xf1,
+ 0xa1, 0xbb, 0x98, 0xb1, 0x76, 0xc7, 0xb0, 0xd6, 0x2b, 0x13, 0x52, 0x68,
+ 0x44, 0xe8, 0xc0, 0x88, 0xc3, 0x53, 0xbb, 0x3c, 0xb1, 0x71, 0xd9, 0x62,
+ 0x86, 0x6b, 0x88, 0x5e, 0xf8, 0xc8, 0xef, 0x8b, 0x17, 0xbc, 0x1e, 0x2c,
+ 0x5d, 0x13, 0xac, 0x53, 0x9b, 0x6e, 0x0f, 0x5e, 0x1c, 0x49, 0x62, 0xfd,
+ 0x34, 0xa3, 0xbf, 0x2c, 0x5f, 0xdd, 0x7d, 0xb7, 0xbe, 0x96, 0x2d, 0x13,
+ 0x9e, 0xe6, 0x15, 0xdf, 0x4e, 0xc5, 0xe5, 0x8b, 0xb3, 0xeb, 0x14, 0xe8,
+ 0xda, 0x27, 0x91, 0x13, 0xee, 0x11, 0xdd, 0x83, 0x58, 0xbb, 0xc1, 0x75,
+ 0x8a, 0x9d, 0x74, 0x8a, 0x52, 0xb0, 0x31, 0xf3, 0xe4, 0x1c, 0x5b, 0xf4,
+ 0x3e, 0xb7, 0x9f, 0x6e, 0x0b, 0xd8, 0x2c, 0x58, 0xbf, 0x68, 0x07, 0x6e,
+ 0x2c, 0x5d, 0x1b, 0xd6, 0x2b, 0x0f, 0x0b, 0x79, 0x4d, 0xef, 0x88, 0xc5,
+ 0x8b, 0xdf, 0x79, 0xd6, 0x2e, 0x10, 0x16, 0x2f, 0x09, 0xba, 0x58, 0xbe,
+ 0xf3, 0x47, 0x6b, 0x15, 0x23, 0xd9, 0xf8, 0xc7, 0x07, 0xae, 0x17, 0x4b,
+ 0x17, 0xfd, 0x13, 0x9d, 0xc0, 0x06, 0xfa, 0xc5, 0x49, 0x10, 0x40, 0x2f,
+ 0xe0, 0xcd, 0xef, 0x60, 0x6b, 0x17, 0xf1, 0xc5, 0xcf, 0x67, 0x96, 0x2f,
+ 0xf1, 0x8f, 0xd6, 0x16, 0x0d, 0x62, 0xfc, 0xff, 0xee, 0x5c, 0x58, 0xa8,
+ 0x44, 0x6f, 0x0b, 0xc4, 0x69, 0x7e, 0xce, 0x02, 0x26, 0x58, 0xbe, 0xe6,
+ 0xdd, 0x42, 0xc5, 0xf3, 0x8e, 0x0e, 0xb1, 0x5d, 0x9e, 0x3c, 0xc4, 0xb7,
+ 0xf7, 0x58, 0x71, 0x73, 0xcb, 0x15, 0x07, 0xa8, 0x22, 0x4b, 0xd2, 0x8e,
+ 0x2c, 0x5c, 0x47, 0x58, 0xb0, 0x96, 0x2a, 0x47, 0x8c, 0x31, 0xd0, 0x0b,
+ 0xde, 0x18, 0xba, 0x58, 0xbe, 0x19, 0x44, 0x96, 0x2a, 0x0f, 0xc1, 0x8b,
+ 0xdc, 0x7e, 0xf6, 0x30, 0xd6, 0x2f, 0xff, 0x07, 0xb7, 0xbf, 0x14, 0x66,
+ 0xdc, 0xef, 0xcb, 0x17, 0xfd, 0x1f, 0x68, 0x9a, 0x68, 0xe9, 0x62, 0xb6,
+ 0x05, 0xd0, 0xd8, 0x59, 0x19, 0x19, 0xa3, 0xfd, 0xc3, 0xe5, 0x8c, 0x26,
+ 0x85, 0x5e, 0x8b, 0xcf, 0x0c, 0x4f, 0xc3, 0x5f, 0xc5, 0x82, 0x1c, 0xde,
+ 0xa3, 0x7f, 0x9a, 0x67, 0x26, 0xef, 0x8b, 0x17, 0x67, 0x4b, 0x17, 0xf8,
+ 0xbd, 0xc2, 0x8f, 0x71, 0x62, 0xff, 0x7c, 0xb1, 0x81, 0x00, 0x58, 0xbf,
+ 0x36, 0xfc, 0x2e, 0x2c, 0x5f, 0xff, 0xd1, 0xf1, 0x77, 0x1e, 0xeb, 0xf1,
+ 0xa1, 0x60, 0xa6, 0x58, 0xac, 0x47, 0x6b, 0x19, 0xe8, 0xcb, 0xe5, 0x37,
+ 0xef, 0x67, 0xc5, 0xba, 0xb1, 0x7f, 0xe9, 0xfe, 0xc7, 0x8d, 0xdf, 0xe4,
+ 0xeb, 0x15, 0xd9, 0xf8, 0x68, 0xb2, 0xfe, 0xd6, 0x7f, 0xe2, 0xf2, 0xc5,
+ 0xfd, 0xb3, 0xcf, 0x47, 0xb8, 0xb8, 0x83, 0x4b, 0xe2, 0x8c, 0xd2, 0x85,
+ 0x74, 0x7c, 0x1f, 0x3f, 0xbf, 0xb3, 0x53, 0x89, 0xc6, 0xa8, 0x83, 0x4d,
+ 0x93, 0x47, 0x53, 0xa6, 0x03, 0x28, 0x59, 0x5f, 0xf7, 0xb8, 0xfa, 0x1e,
+ 0x9e, 0x4b, 0x15, 0xa3, 0xe4, 0xe1, 0x55, 0xf1, 0x7f, 0x3b, 0x58, 0xa8,
+ 0x4f, 0x35, 0xa3, 0x88, 0x72, 0x2b, 0xfd, 0xbf, 0x8c, 0x4f, 0xa3, 0x56,
+ 0x2f, 0xcf, 0xd3, 0x1e, 0x16, 0x2f, 0xe9, 0x7c, 0x9f, 0xbf, 0x2c, 0x57,
+ 0x47, 0xae, 0x45, 0x17, 0xc1, 0x93, 0xce, 0xb1, 0x7e, 0xe3, 0x69, 0x80,
+ 0xb1, 0x58, 0x7d, 0xdc, 0x22, 0x08, 0x49, 0x7e, 0xf7, 0xe3, 0x53, 0xac,
+ 0x5f, 0xa3, 0xdb, 0x4e, 0x62, 0xc5, 0xff, 0xa7, 0xf7, 0xe3, 0xf9, 0xbd,
+ 0xe4, 0xb1, 0x78, 0xf1, 0xd2, 0xc5, 0xf1, 0x00, 0x5c, 0x58, 0xac, 0x3c,
+ 0x1d, 0x0f, 0x5f, 0xbb, 0x9b, 0xef, 0xda, 0xc5, 0xfb, 0xb9, 0x67, 0x7e,
+ 0x58, 0xa8, 0x47, 0xdb, 0x42, 0x0d, 0xc8, 0x44, 0x59, 0x7c, 0xee, 0x0e,
+ 0x2c, 0x5c, 0xe6, 0xac, 0x5c, 0xf3, 0xcc, 0x6e, 0x88, 0x8a, 0xff, 0x87,
+ 0xce, 0x66, 0x87, 0xfc, 0x58, 0xbd, 0xf8, 0xd2, 0xc5, 0xff, 0x71, 0xca,
+ 0x26, 0x61, 0xce, 0xb1, 0x60, 0x2c, 0x5f, 0xe9, 0x31, 0xe3, 0xe1, 0x8d,
+ 0x62, 0xff, 0xf4, 0x61, 0x77, 0xec, 0xd3, 0x4e, 0xe7, 0x58, 0xb8, 0xcf,
+ 0xac, 0x5d, 0x9f, 0xda, 0x8e, 0x4e, 0x8e, 0xb8, 0x25, 0xe3, 0x53, 0x12,
+ 0xae, 0xce, 0x2c, 0x57, 0x8f, 0xc3, 0x71, 0x66, 0xa4, 0x9c, 0xb1, 0x91,
+ 0xb8, 0xd4, 0x27, 0xf6, 0xf1, 0xe8, 0x5f, 0xf6, 0x4b, 0xf8, 0x4f, 0xa3,
+ 0x56, 0x2e, 0x39, 0x8b, 0x15, 0xb2, 0x7a, 0x52, 0x39, 0xbf, 0x41, 0xfd,
+ 0x9f, 0x58, 0xad, 0xac, 0x9c, 0x9d, 0x80, 0xd2, 0x23, 0x05, 0x94, 0xa7,
+ 0x81, 0x9a, 0x64, 0x3e, 0xd8, 0xc3, 0x45, 0x5f, 0x8c, 0x9d, 0xde, 0x4a,
+ 0x51, 0x40, 0x9e, 0x82, 0x12, 0xdf, 0x9b, 0xa8, 0x3c, 0x2c, 0x5f, 0xee,
+ 0xf5, 0x8d, 0xf8, 0x1a, 0xc5, 0xff, 0x74, 0xdc, 0xc1, 0x74, 0xe4, 0xb1,
+ 0x70, 0xe1, 0x62, 0xfd, 0x37, 0xdc, 0x10, 0xb1, 0x76, 0x49, 0x62, 0xff,
+ 0xfb, 0xf0, 0x7d, 0xbf, 0x87, 0xd0, 0xca, 0x24, 0xb1, 0x52, 0x4c, 0xfb,
+ 0x0a, 0x3e, 0x68, 0xe7, 0x44, 0x2f, 0xc2, 0x91, 0x0b, 0xdd, 0x81, 0xac,
+ 0x5f, 0xe3, 0x5f, 0xdc, 0x3b, 0x79, 0x62, 0xff, 0x3f, 0x9f, 0x06, 0xdb,
+ 0xd6, 0x2f, 0x81, 0xf8, 0x1a, 0xc5, 0xfd, 0xf6, 0x30, 0xa0, 0x6b, 0x17,
+ 0xfd, 0x00, 0x3c, 0x61, 0x7b, 0x8b, 0x17, 0xfd, 0xcc, 0x33, 0xee, 0x76,
+ 0xe2, 0xc5, 0xfb, 0x35, 0x38, 0xb8, 0xb1, 0x46, 0xa6, 0xad, 0xd1, 0xab,
+ 0x1a, 0x4c, 0x47, 0xf2, 0xee, 0x1c, 0x6f, 0x3a, 0xbf, 0x37, 0x72, 0x62,
+ 0x58, 0xbc, 0xdf, 0xc5, 0x8b, 0xfb, 0xce, 0x73, 0xc1, 0xd6, 0x2b, 0x0f,
+ 0xcb, 0xa2, 0x8e, 0xc7, 0x29, 0x62, 0x8e, 0x6f, 0x0c, 0x30, 0xbf, 0xe1,
+ 0x4f, 0xb7, 0x3d, 0xf8, 0xf2, 0xc5, 0xfb, 0x82, 0x06, 0x7d, 0x62, 0xe6,
+ 0x99, 0x62, 0xa1, 0x14, 0x1d, 0x11, 0x78, 0xf4, 0x21, 0x4d, 0xff, 0xc4,
+ 0x23, 0x4e, 0x2f, 0x7e, 0x04, 0x17, 0x58, 0xbe, 0x3c, 0x68, 0xd5, 0x8b,
+ 0xec, 0x00, 0x1d, 0x62, 0xf0, 0x7f, 0x75, 0x8a, 0xc3, 0xe4, 0x22, 0x4d,
+ 0xc2, 0x2a, 0x9d, 0x1b, 0xe6, 0x42, 0xbe, 0xf8, 0x38, 0x2e, 0x96, 0x2f,
+ 0x73, 0xf0, 0xb1, 0x52, 0x3c, 0x11, 0x92, 0x5f, 0x8b, 0x46, 0x3c, 0xeb,
+ 0x17, 0xfb, 0xfb, 0xf0, 0x7c, 0xc0, 0xd6, 0x2a, 0x11, 0xdd, 0x8d, 0x6e,
+ 0x44, 0x22, 0xab, 0xee, 0xbf, 0x06, 0x2c, 0x5f, 0xb3, 0xdc, 0x63, 0xac,
+ 0x5c, 0x22, 0x58, 0xbd, 0x38, 0xbc, 0xb1, 0x78, 0xb2, 0x75, 0x8a, 0x85,
+ 0xe6, 0xd9, 0x31, 0x64, 0x6d, 0xcd, 0x1d, 0xbe, 0xa5, 0x06, 0x05, 0xce,
+ 0x88, 0x97, 0x85, 0x02, 0x17, 0x0c, 0x7e, 0xff, 0xa0, 0xf1, 0xe6, 0x2c,
+ 0x92, 0xc5, 0xa4, 0xb1, 0x7d, 0xc1, 0x40, 0x16, 0x2e, 0x10, 0x45, 0x8a,
+ 0xd2, 0x21, 0xbe, 0x6e, 0x01, 0x22, 0x23, 0xbb, 0x09, 0x62, 0xfd, 0xc0,
+ 0xf9, 0xf1, 0x2c, 0x57, 0xcf, 0x07, 0xc2, 0xd7, 0xff, 0xb4, 0xd0, 0x7c,
+ 0xdb, 0x9f, 0x6c, 0x3a, 0xc5, 0xf3, 0x72, 0x1d, 0x62, 0xb6, 0x9f, 0x5f,
+ 0x12, 0xaf, 0xf6, 0x16, 0x77, 0xe9, 0x1d, 0x62, 0xef, 0x42, 0xc5, 0x41,
+ 0xe5, 0xb9, 0xa5, 0xff, 0x3c, 0x86, 0xc2, 0x0b, 0xb6, 0x96, 0x2f, 0xd8,
+ 0x45, 0x03, 0x58, 0xbe, 0xfb, 0xfe, 0x16, 0x2f, 0xe8, 0x9c, 0xef, 0x34,
+ 0x2c, 0x5b, 0x4b, 0x15, 0x23, 0xe3, 0x98, 0x88, 0x45, 0xf7, 0xff, 0xce,
+ 0x6f, 0xa3, 0x40, 0xd4, 0x78, 0x9c, 0x0b, 0x17, 0xfa, 0x3a, 0x1f, 0xc4,
+ 0xfc, 0x58, 0xb9, 0xcd, 0x58, 0xbf, 0xa7, 0x2c, 0xf6, 0xa1, 0x62, 0xfb,
+ 0xa0, 0xfd, 0xc5, 0x8b, 0xf8, 0xb0, 0x18, 0x52, 0x58, 0xbf, 0xfe, 0x37,
+ 0x68, 0x64, 0xfe, 0xe3, 0x77, 0xf6, 0x31, 0x62, 0xb1, 0x10, 0x4e, 0x59,
+ 0x7b, 0x50, 0x6a, 0xc5, 0x42, 0x62, 0xac, 0x5c, 0x50, 0xa8, 0xe1, 0x0d,
+ 0x42, 0xe4, 0x0e, 0x3e, 0xb4, 0x23, 0x74, 0xde, 0x72, 0x0f, 0x9e, 0xbc,
+ 0x22, 0x48, 0xc3, 0x8a, 0x1e, 0x35, 0x14, 0x65, 0xb7, 0x9f, 0xb0, 0x2c,
+ 0x5b, 0x7a, 0xc5, 0x48, 0xd9, 0x70, 0x7a, 0xe6, 0xf2, 0xc5, 0xff, 0xc5,
+ 0xf7, 0xe1, 0x61, 0xa6, 0xe6, 0xea, 0xc5, 0xfc, 0x21, 0xe7, 0xa2, 0x65,
+ 0x8a, 0xc3, 0xf7, 0xe9, 0x22, 0xfe, 0x96, 0x14, 0xed, 0xa5, 0x8b, 0xc4,
+ 0xe3, 0x58, 0xbf, 0xd0, 0x2e, 0xb0, 0xf1, 0xd2, 0xc5, 0x31, 0xe8, 0x90,
+ 0xe5, 0xc1, 0xf9, 0x62, 0xfd, 0xc8, 0xd7, 0xa1, 0x62, 0x86, 0x7c, 0x3a,
+ 0x20, 0xe0, 0xcd, 0xcc, 0x17, 0x58, 0xba, 0x41, 0xac, 0x5f, 0x19, 0x92,
+ 0x65, 0x8b, 0xd8, 0xc6, 0xac, 0x5e, 0xcc, 0x9d, 0x62, 0xc3, 0x58, 0xbc,
+ 0xef, 0xa5, 0x8a, 0x83, 0x5d, 0x30, 0x95, 0x3a, 0x2b, 0x08, 0x8f, 0xc3,
+ 0xa1, 0xa5, 0xde, 0xc6, 0xde, 0xb1, 0x7a, 0x41, 0x9d, 0x62, 0xbe, 0x6f,
+ 0x5c, 0x7a, 0xfe, 0xe3, 0x6b, 0x05, 0xa5, 0x8b, 0xc3, 0x6d, 0x2c, 0x5f,
+ 0xff, 0xd3, 0x6d, 0x6e, 0x85, 0xae, 0x0b, 0x69, 0xdb, 0xdf, 0x65, 0x8b,
+ 0xa0, 0xd5, 0x8a, 0x83, 0xfb, 0x66, 0x3a, 0xc5, 0xc3, 0xf3, 0x48, 0x7a,
+ 0x84, 0x77, 0x64, 0x4d, 0x0e, 0x09, 0x8b, 0xf4, 0x36, 0x78, 0x62, 0xfd,
+ 0xe7, 0xc4, 0x02, 0x2e, 0x09, 0x09, 0x8b, 0xc3, 0x3f, 0x16, 0x2e, 0x38,
+ 0x55, 0x51, 0x7e, 0x17, 0xe9, 0xfb, 0x94, 0x0d, 0x62, 0xf8, 0x9b, 0xb9,
+ 0x2c, 0x5f, 0xd3, 0x37, 0x04, 0x23, 0xac, 0x56, 0x1e, 0x9b, 0x91, 0xde,
+ 0xd6, 0x62, 0xc5, 0x6c, 0x68, 0xba, 0x67, 0xee, 0x10, 0x5e, 0x28, 0x02,
+ 0xc5, 0xe6, 0xcf, 0xac, 0x5c, 0x5d, 0x41, 0xb8, 0xd0, 0xe5, 0xe1, 0x98,
+ 0x05, 0x8b, 0xff, 0xa5, 0xe1, 0x4a, 0x47, 0xf7, 0xa0, 0xeb, 0x17, 0xe8,
+ 0xfb, 0x03, 0x8b, 0x17, 0xf7, 0x22, 0x7c, 0xe0, 0xd6, 0x2b, 0x47, 0xaf,
+ 0xe2, 0x8b, 0xbf, 0x8b, 0x17, 0xff, 0xdf, 0x81, 0xe7, 0x5b, 0x70, 0xb0,
+ 0x7f, 0x85, 0x8b, 0xfe, 0xd4, 0x7d, 0xb7, 0xea, 0x24, 0xb1, 0x7f, 0xff,
+ 0x81, 0x1d, 0xcb, 0x83, 0xcc, 0x2c, 0xeb, 0xec, 0x2f, 0x2c, 0x5f, 0xfb,
+ 0x0b, 0x33, 0x9b, 0x65, 0xc3, 0xac, 0x5f, 0xfb, 0x3d, 0x80, 0xdb, 0x9f,
+ 0x28, 0x58, 0xa6, 0x3f, 0xf2, 0x40, 0xbf, 0xf3, 0xc7, 0x72, 0xdb, 0xce,
+ 0xc7, 0x0b, 0x17, 0xf3, 0xce, 0x59, 0x38, 0x96, 0x28, 0x6a, 0xe3, 0x71,
+ 0xb3, 0xa2, 0xce, 0xc7, 0xda, 0x13, 0xdb, 0xa4, 0x53, 0x0b, 0xe9, 0x44,
+ 0x07, 0x7c, 0x87, 0x0f, 0x88, 0x37, 0x10, 0xef, 0xf9, 0xb9, 0x83, 0xdb,
+ 0xc2, 0x85, 0x8b, 0xc6, 0xc6, 0x96, 0x2f, 0x8e, 0xe3, 0x12, 0xc5, 0xe9,
+ 0xa0, 0xeb, 0x17, 0xf4, 0x7d, 0xb9, 0x01, 0xac, 0x56, 0x1e, 0x60, 0x63,
+ 0xd7, 0xc0, 0x27, 0x92, 0xc5, 0xfd, 0xf6, 0x3b, 0xb8, 0x45, 0x8b, 0xf4,
+ 0x88, 0x4e, 0x6a, 0xc5, 0xe1, 0x77, 0xc5, 0x8b, 0xc5, 0x81, 0x16, 0x2f,
+ 0x1f, 0x37, 0xac, 0x56, 0xd3, 0xdc, 0xc1, 0xf7, 0x1e, 0xbd, 0xa6, 0x9d,
+ 0x62, 0xc7, 0x58, 0xbd, 0xac, 0xed, 0x62, 0xf8, 0xe0, 0xec, 0x0b, 0x17,
+ 0x0e, 0x24, 0x7a, 0xa0, 0x12, 0x0c, 0x7a, 0xdb, 0x8b, 0x17, 0xe7, 0xf3,
+ 0x90, 0x16, 0x2b, 0x65, 0x54, 0xf4, 0x0f, 0x0d, 0xbc, 0xd2, 0x2e, 0x88,
+ 0xbb, 0x2f, 0x9a, 0x10, 0xba, 0x2f, 0x3b, 0x98, 0x5c, 0xef, 0x70, 0x56,
+ 0xff, 0x98, 0xd8, 0xd1, 0x63, 0x1a, 0xb1, 0x77, 0x53, 0xac, 0x5f, 0xb1,
+ 0xb5, 0x34, 0x96, 0x2f, 0x89, 0xfd, 0xc5, 0x8b, 0x41, 0xcf, 0x2f, 0x79,
+ 0x4d, 0xcd, 0x32, 0xc5, 0xff, 0xb2, 0x7d, 0xbf, 0x89, 0x9b, 0xb9, 0x2c,
+ 0x5f, 0xd0, 0x68, 0xca, 0x3b, 0x58, 0xb9, 0x8e, 0xb1, 0x50, 0x88, 0xad,
+ 0x22, 0x6f, 0x2f, 0xbe, 0x28, 0xd1, 0xab, 0x17, 0xd0, 0x58, 0x6a, 0xc5,
+ 0xee, 0x41, 0xab, 0x17, 0xf9, 0xf3, 0xbf, 0x79, 0xfe, 0xb1, 0x7f, 0xf0,
+ 0x87, 0x9a, 0x89, 0x30, 0xe0, 0x96, 0x2f, 0xf8, 0x9e, 0x78, 0xd6, 0x9e,
+ 0x4b, 0x17, 0xfe, 0x6f, 0x68, 0x52, 0xee, 0x59, 0xe5, 0x8a, 0x92, 0x2f,
+ 0x7e, 0x87, 0xbc, 0xe6, 0xff, 0x73, 0x98, 0x40, 0xdc, 0xc5, 0x8b, 0xff,
+ 0x9b, 0x92, 0x6f, 0x07, 0xa8, 0xfc, 0x2c, 0x58, 0xf8, 0x7f, 0x7f, 0x36,
+ 0xbf, 0xfe, 0xd3, 0xf0, 0xb2, 0x70, 0xe4, 0x28, 0x62, 0x58, 0xa8, 0x4c,
+ 0x91, 0xe1, 0x5a, 0x22, 0x7a, 0xed, 0x53, 0x3f, 0xc7, 0xbd, 0x28, 0x56,
+ 0xff, 0xff, 0x37, 0x01, 0x9b, 0x5b, 0x7c, 0x7d, 0xa2, 0x69, 0xa3, 0xa5,
+ 0x8b, 0xde, 0x69, 0xd6, 0x2f, 0xc0, 0x7e, 0xe2, 0x65, 0x8b, 0xc5, 0x1d,
+ 0x2c, 0x5f, 0xec, 0xe4, 0xdf, 0x63, 0x3c, 0xb1, 0x7e, 0x79, 0x46, 0xe9,
+ 0xd6, 0x2f, 0xfc, 0xd3, 0x7e, 0x35, 0xdc, 0xa3, 0x4b, 0x17, 0xf4, 0xa3,
+ 0x74, 0xf1, 0x25, 0x8b, 0xff, 0xde, 0xfc, 0x6f, 0xe1, 0x3f, 0xa6, 0x6d,
+ 0xeb, 0x17, 0xfe, 0x63, 0xe6, 0xb2, 0x26, 0x63, 0xac, 0x56, 0x22, 0x37,
+ 0x49, 0xf5, 0x09, 0xc1, 0x4e, 0x6c, 0x32, 0xb9, 0x90, 0x79, 0x0b, 0xeb,
+ 0xec, 0xf4, 0x0d, 0x62, 0xfa, 0x6d, 0x47, 0x6b, 0x17, 0xff, 0x13, 0xf7,
+ 0xce, 0x66, 0x87, 0xfc, 0x58, 0xbf, 0xfd, 0x1d, 0x6d, 0xd6, 0x30, 0x82,
+ 0xf8, 0x13, 0x16, 0x29, 0x91, 0x2e, 0x48, 0xb5, 0xb5, 0x7d, 0x5a, 0x50,
+ 0xa2, 0xc3, 0x1e, 0x88, 0xda, 0x54, 0x4e, 0x8e, 0x8e, 0xcc, 0xe3, 0xc4,
+ 0x55, 0xc8, 0xe7, 0xcc, 0x51, 0x0c, 0x88, 0x24, 0x2f, 0x29, 0x62, 0xfe,
+ 0x7e, 0xce, 0x4e, 0x62, 0xc5, 0x41, 0xbb, 0xd0, 0x65, 0x2c, 0x5e, 0xcc,
+ 0x02, 0xc5, 0xef, 0xb7, 0x96, 0x2d, 0xbf, 0x0f, 0x95, 0x88, 0x08, 0x30,
+ 0x31, 0xcb, 0x01, 0x62, 0xfd, 0xa9, 0xc4, 0xe3, 0x58, 0xb6, 0xe2, 0xc5,
+ 0x48, 0xf4, 0x70, 0x48, 0x32, 0xab, 0xd0, 0x13, 0x8b, 0x14, 0x69, 0xe7,
+ 0x74, 0x5f, 0x7e, 0xd6, 0xb3, 0x76, 0x65, 0x8b, 0x8c, 0xe2, 0xc5, 0x43,
+ 0x68, 0xc3, 0x28, 0x60, 0x0c, 0x7b, 0x27, 0x1c, 0x3a, 0x85, 0xc3, 0x4a,
+ 0xd8, 0xdd, 0x85, 0x61, 0xce, 0x7e, 0xca, 0xf3, 0xef, 0xe0, 0x8d, 0xbc,
+ 0x50, 0xe1, 0xde, 0x48, 0x19, 0x6d, 0xfe, 0x09, 0xce, 0x41, 0xe3, 0xcb,
+ 0x17, 0x38, 0x6b, 0x15, 0x07, 0x9c, 0x73, 0x6b, 0xfc, 0x52, 0x2c, 0x3c,
+ 0x74, 0xb1, 0x76, 0x6e, 0x2c, 0x56, 0x1e, 0x6f, 0xcc, 0xef, 0xdf, 0x6d,
+ 0xf8, 0x35, 0x8b, 0xdb, 0x7c, 0xcb, 0x17, 0xfe, 0x1c, 0x16, 0x10, 0xa5,
+ 0x9c, 0x58, 0xbb, 0x6f, 0x6b, 0x17, 0xe7, 0x3b, 0x04, 0xc5, 0x8b, 0xfb,
+ 0x3e, 0xfe, 0x79, 0x96, 0x2e, 0x8e, 0xd6, 0x2b, 0xb3, 0xc6, 0xf1, 0x75,
+ 0x62, 0x24, 0x9d, 0xbe, 0xff, 0xb0, 0x45, 0x9e, 0x27, 0x3a, 0xc5, 0xa6,
+ 0x58, 0xbd, 0xfc, 0x02, 0xc5, 0x31, 0xb0, 0xf0, 0x9d, 0xfe, 0xe4, 0x4a,
+ 0x27, 0x89, 0xd6, 0x2e, 0xc3, 0x56, 0x2f, 0xff, 0x61, 0xbf, 0x6e, 0x7f,
+ 0x37, 0xc6, 0x76, 0xb1, 0x50, 0x8b, 0xa6, 0x20, 0xf9, 0xa9, 0x0c, 0x5a,
+ 0x16, 0x2f, 0x9c, 0x38, 0x31, 0x62, 0xa0, 0xda, 0xf6, 0x23, 0x76, 0xb1,
+ 0x62, 0xff, 0xc3, 0xc3, 0xea, 0x18, 0xb2, 0x16, 0x2e, 0x8e, 0x96, 0x2d,
+ 0x0c, 0x7a, 0x9e, 0x3c, 0xbb, 0x63, 0x08, 0xb1, 0x40, 0x3c, 0x52, 0x26,
+ 0xbe, 0x6d, 0x44, 0x96, 0x2f, 0xa7, 0x3c, 0x71, 0x62, 0xa7, 0x3c, 0x6c,
+ 0x22, 0xbf, 0xf4, 0x79, 0xc5, 0xe7, 0xef, 0x3c, 0xb1, 0x7f, 0xda, 0xdb,
+ 0x03, 0xfe, 0x75, 0x0b, 0x17, 0xff, 0x46, 0x0d, 0xb8, 0x59, 0xbd, 0x89,
+ 0x62, 0xbe, 0x8b, 0xe7, 0x3f, 0x11, 0xe5, 0xfb, 0xa7, 0x86, 0xdc, 0x58,
+ 0xbc, 0x59, 0xc5, 0x8b, 0xff, 0xff, 0x47, 0xd8, 0xfb, 0x33, 0x49, 0xf4,
+ 0x1f, 0xdb, 0xbe, 0x74, 0xd3, 0xac, 0x54, 0xeb, 0xce, 0xc3, 0x6e, 0x34,
+ 0x87, 0xa2, 0xa6, 0x1f, 0xdd, 0x3d, 0x9a, 0x15, 0xba, 0x21, 0xfc, 0x64,
+ 0x2e, 0xde, 0x02, 0x12, 0x85, 0x87, 0x19, 0xfd, 0x0e, 0x01, 0x17, 0x86,
+ 0x56, 0x10, 0x72, 0xff, 0x7a, 0x59, 0xba, 0xe4, 0x05, 0x8b, 0xda, 0xe0,
+ 0x96, 0x2d, 0xc5, 0x8b, 0xfd, 0xd0, 0x1c, 0x0c, 0x5d, 0x2c, 0x57, 0xcf,
+ 0x1c, 0x84, 0xab, 0x11, 0x0c, 0xcc, 0xb7, 0xfa, 0x71, 0xe7, 0xb8, 0xfd,
+ 0xac, 0x5e, 0x07, 0xb8, 0xb1, 0x6e, 0x2c, 0x52, 0xc5, 0x78, 0xbe, 0xde,
+ 0x25, 0x5b, 0x4f, 0x78, 0x07, 0x94, 0xb1, 0x74, 0x82, 0x8b, 0x16, 0xda,
+ 0xc6, 0xa1, 0xc3, 0x2f, 0xb0, 0x5a, 0x9d, 0x62, 0xfa, 0x5c, 0x19, 0xd6,
+ 0x29, 0x8f, 0x21, 0xc9, 0x2f, 0xfe, 0xcd, 0xf8, 0x3c, 0x21, 0x4b, 0x38,
+ 0xb1, 0x7e, 0xd4, 0x7c, 0x31, 0xac, 0x56, 0x8f, 0xbd, 0xd1, 0x6c, 0x05,
+ 0x8b, 0xa7, 0x85, 0x8b, 0xf6, 0x0f, 0xed, 0x3a, 0xc5, 0xa2, 0x73, 0xd3,
+ 0x61, 0x22, 0x18, 0xbe, 0x31, 0xf3, 0x8b, 0x17, 0xf0, 0xe0, 0x05, 0x9d,
+ 0xac, 0x5f, 0xf4, 0x8e, 0xf2, 0xf7, 0x20, 0xd5, 0x8a, 0x84, 0x46, 0x61,
+ 0x1b, 0x97, 0x5f, 0x44, 0x17, 0x4b, 0x17, 0xb8, 0xc4, 0xb1, 0x60, 0x2c,
+ 0x5f, 0x75, 0xb7, 0x9d, 0xac, 0x56, 0x8d, 0xd1, 0x09, 0x5f, 0xe0, 0xe5,
+ 0x1b, 0xd8, 0x80, 0xb1, 0x7c, 0xe1, 0x30, 0x96, 0x2b, 0x11, 0x9e, 0xea,
+ 0xc4, 0x41, 0xc3, 0x6b, 0xff, 0xc0, 0x0f, 0xcd, 0x26, 0xd0, 0x0e, 0xdc,
+ 0x58, 0xa1, 0xae, 0xc9, 0x64, 0x2f, 0x3a, 0x21, 0x68, 0x4a, 0x6e, 0xa6,
+ 0x1d, 0xbd, 0xe1, 0x1e, 0x07, 0x42, 0x85, 0xff, 0x0b, 0x45, 0x0f, 0x1d,
+ 0xe7, 0x57, 0xdc, 0x9c, 0x5c, 0x58, 0xba, 0x79, 0x2c, 0x5e, 0x6f, 0xb2,
+ 0xc5, 0xc7, 0x85, 0x8a, 0xc3, 0xf1, 0xec, 0x97, 0xc3, 0x22, 0x1c, 0xbf,
+ 0xfa, 0x7e, 0xbe, 0xc1, 0xe8, 0xdc, 0xef, 0xcb, 0x17, 0xd9, 0xdc, 0xa1,
+ 0x62, 0xf0, 0x9f, 0x8b, 0x15, 0x88, 0x8b, 0xfa, 0x58, 0x64, 0x77, 0xbc,
+ 0xd3, 0xac, 0x5f, 0xf3, 0x1b, 0x03, 0x8d, 0xf9, 0xf5, 0x8b, 0xf4, 0x10,
+ 0x0f, 0xe5, 0x8b, 0xfc, 0xc6, 0x77, 0x2e, 0x67, 0x4b, 0x17, 0xf4, 0x83,
+ 0x00, 0x23, 0xb5, 0x8a, 0x64, 0x48, 0x7c, 0xa1, 0xcd, 0xef, 0xe1, 0x72,
+ 0x26, 0x16, 0x96, 0x2f, 0x0b, 0x3b, 0x58, 0xbf, 0xb3, 0xb0, 0x67, 0xb8,
+ 0xb1, 0x7e, 0x82, 0xee, 0x5c, 0x58, 0xf9, 0xaf, 0xaf, 0xa2, 0xdb, 0xc6,
+ 0x02, 0x4d, 0xbf, 0xbd, 0x91, 0xec, 0x3a, 0xc5, 0xfd, 0x87, 0xd6, 0xa0,
+ 0x6b, 0x17, 0xee, 0xf9, 0xe6, 0x9d, 0x62, 0xfe, 0x11, 0x4f, 0xc6, 0xed,
+ 0x62, 0xff, 0xe8, 0x9c, 0xc7, 0xef, 0x98, 0x36, 0xe2, 0xc5, 0x42, 0x28,
+ 0xa4, 0x56, 0x46, 0x16, 0xf2, 0xc5, 0xfb, 0x0d, 0xf3, 0x4e, 0xb1, 0x78,
+ 0x19, 0xda, 0xc5, 0xe8, 0x2f, 0x2c, 0x54, 0x1f, 0xb7, 0x62, 0x40, 0x2a,
+ 0xde, 0x3d, 0x7f, 0xff, 0x4b, 0x85, 0x93, 0x6d, 0xeb, 0xf1, 0xd1, 0xba,
+ 0x73, 0x16, 0x2f, 0x63, 0x4e, 0xb1, 0x78, 0x51, 0x3f, 0x68, 0x80, 0x26,
+ 0x3b, 0xff, 0xf4, 0x68, 0x19, 0xc2, 0x13, 0xcb, 0xe2, 0x79, 0xd6, 0x2f,
+ 0x16, 0x6f, 0x58, 0xbf, 0x7b, 0x1c, 0xba, 0x58, 0xaf, 0xa2, 0x73, 0xca,
+ 0xc1, 0x07, 0xaf, 0x77, 0x07, 0x58, 0xbf, 0xfc, 0x3f, 0xc7, 0x72, 0x2c,
+ 0x3e, 0x77, 0xe5, 0x8b, 0xf1, 0xf3, 0xf8, 0x4b, 0x14, 0xc7, 0xe6, 0xe9,
+ 0x97, 0xfc, 0x27, 0x90, 0xf3, 0x01, 0xc5, 0x8b, 0xff, 0xb3, 0x7f, 0xde,
+ 0x5b, 0x7d, 0xf7, 0x35, 0x62, 0xe7, 0x25, 0x8b, 0x9c, 0x22, 0xc5, 0xc7,
+ 0xcd, 0x1a, 0xff, 0x8b, 0x5f, 0xfb, 0xb9, 0x7e, 0x0e, 0xfd, 0xcb, 0x16,
+ 0x2f, 0xe6, 0xef, 0xb9, 0x67, 0x96, 0x2a, 0x11, 0x3b, 0x85, 0x80, 0x41,
+ 0xaf, 0xa6, 0xfa, 0x47, 0x3c, 0x8c, 0x5a, 0xfd, 0xdf, 0x0e, 0xdb, 0xab,
+ 0x17, 0xff, 0x7d, 0xdb, 0xc0, 0x11, 0x13, 0xc9, 0x62, 0xff, 0x9c, 0x98,
+ 0xfd, 0xf2, 0x26, 0x58, 0xbe, 0x82, 0x10, 0x5d, 0x62, 0xec, 0xe6, 0xd4,
+ 0x51, 0xce, 0x87, 0xf3, 0xaa, 0x84, 0xc3, 0x8a, 0x1a, 0x17, 0xce, 0x0f,
+ 0x05, 0xd6, 0x2f, 0xe7, 0x9c, 0x0e, 0x43, 0x58, 0xbf, 0xfe, 0x6c, 0x33,
+ 0xb9, 0x73, 0x90, 0x77, 0xef, 0xcb, 0x15, 0x3b, 0x26, 0x08, 0x70, 0xcb,
+ 0xea, 0x1c, 0x9d, 0x98, 0x31, 0x6c, 0xd0, 0xd0, 0xd4, 0x29, 0x0f, 0x0b,
+ 0xef, 0xc3, 0x44, 0x8c, 0xb9, 0x09, 0x1f, 0x47, 0x3b, 0xbe, 0x34, 0x43,
+ 0x09, 0xf7, 0x09, 0xc2, 0x17, 0x5f, 0x4d, 0x99, 0xd2, 0xc5, 0xf6, 0x4c,
+ 0xc7, 0x58, 0xad, 0x1e, 0x38, 0x09, 0x2f, 0xfb, 0xff, 0xc6, 0xee, 0x59,
+ 0xa5, 0x8a, 0x83, 0xdc, 0x72, 0x2b, 0xfd, 0xe1, 0x4f, 0x1e, 0x81, 0xac,
+ 0x5e, 0xf6, 0x12, 0xc5, 0xef, 0xbe, 0xea, 0xc5, 0xf8, 0x52, 0xc0, 0x71,
+ 0x62, 0xff, 0x07, 0x1d, 0x6e, 0x66, 0xa1, 0x62, 0xff, 0x87, 0x82, 0xd4,
+ 0xfd, 0x34, 0xeb, 0x17, 0x8b, 0x60, 0xf2, 0xc5, 0xff, 0xed, 0xf8, 0x43,
+ 0x27, 0x33, 0x9c, 0x80, 0x2c, 0x5f, 0xff, 0xfc, 0x76, 0xe6, 0xd9, 0xa4,
+ 0x22, 0xf6, 0xdf, 0xc4, 0x98, 0xb0, 0xf0, 0xb1, 0x58, 0x8c, 0x21, 0x26,
+ 0x5f, 0x36, 0xa0, 0xeb, 0x15, 0xa3, 0xc4, 0xf9, 0x15, 0xe2, 0xc3, 0x16,
+ 0x2f, 0xff, 0xba, 0xf8, 0x8b, 0x3b, 0x93, 0x70, 0xb3, 0x7a, 0xc5, 0xfb,
+ 0xf1, 0xf6, 0x35, 0x62, 0xe7, 0x9b, 0x87, 0xf8, 0x11, 0x4e, 0xa1, 0x1d,
+ 0x73, 0x11, 0x7e, 0x13, 0x37, 0xff, 0xf9, 0xb7, 0x90, 0xb9, 0xb4, 0x32,
+ 0x81, 0xfd, 0xe5, 0x9c, 0x58, 0xa9, 0x2b, 0x87, 0x34, 0x73, 0x44, 0x1f,
+ 0x29, 0x73, 0x82, 0x3d, 0xf4, 0xa1, 0x3d, 0xe6, 0xb7, 0xec, 0xd1, 0x40,
+ 0x16, 0x2a, 0x1b, 0x00, 0x79, 0xcc, 0x32, 0x93, 0x40, 0xd1, 0xdc, 0xe8,
+ 0x81, 0xe5, 0xde, 0x09, 0xee, 0xfb, 0xff, 0x63, 0x56, 0x2e, 0x98, 0x4b,
+ 0x16, 0x3a, 0xc5, 0x61, 0xe7, 0xf6, 0x48, 0x17, 0x19, 0xbf, 0xde, 0x00,
+ 0x8b, 0x8c, 0x35, 0x8b, 0xf4, 0x81, 0x98, 0x35, 0x8b, 0x6f, 0x63, 0xdc,
+ 0x73, 0x4b, 0xf7, 0xdb, 0x40, 0x12, 0xc5, 0xe6, 0xf8, 0x96, 0x2d, 0xac,
+ 0x3e, 0xe9, 0x8a, 0x3c, 0x53, 0x7f, 0x19, 0xc7, 0x8e, 0xe4, 0xb1, 0x50,
+ 0x7c, 0xb8, 0x6b, 0x7f, 0xd9, 0xdb, 0xfa, 0x3c, 0xe0, 0x58, 0xbf, 0xf8,
+ 0xa3, 0xdc, 0xf7, 0x7d, 0x31, 0x4e, 0xb1, 0x7e, 0x08, 0xdd, 0xcb, 0x8b,
+ 0x15, 0x31, 0xf9, 0xba, 0x3d, 0xfe, 0x62, 0x35, 0xc5, 0x21, 0xac, 0x5f,
+ 0x1c, 0x39, 0xb8, 0xb1, 0x58, 0x7b, 0x4c, 0x69, 0x7f, 0x16, 0x78, 0x50,
+ 0x4b, 0x17, 0xee, 0xe4, 0x50, 0x35, 0x8a, 0x39, 0xea, 0xb9, 0x65, 0xfd,
+ 0x26, 0x23, 0xbf, 0x96, 0x2f, 0xf8, 0x79, 0xb7, 0x8c, 0x5d, 0xc9, 0x62,
+ 0xd1, 0xd9, 0xf4, 0x98, 0x5b, 0x50, 0xa9, 0x41, 0xa1, 0x59, 0xf7, 0xc7,
+ 0x75, 0x28, 0x45, 0x5e, 0xc9, 0xe1, 0x62, 0xf7, 0xb3, 0xeb, 0x16, 0x79,
+ 0x1b, 0xaf, 0x8e, 0xdf, 0xff, 0x7f, 0x08, 0x30, 0x6d, 0xce, 0xb1, 0x8a,
+ 0x16, 0x2f, 0xfe, 0x8e, 0x73, 0x0f, 0xe2, 0x83, 0xf1, 0x62, 0xff, 0xa3,
+ 0x46, 0xfc, 0xa3, 0x34, 0xb1, 0x7f, 0x1b, 0xb7, 0x0f, 0x1d, 0x2c, 0x5f,
+ 0xfd, 0x1d, 0xcb, 0xc2, 0x89, 0xdb, 0xbf, 0x2c, 0x5f, 0xe6, 0xfb, 0xf5,
+ 0x04, 0x35, 0x8a, 0x64, 0x56, 0x91, 0x97, 0x12, 0x2f, 0xe8, 0xe8, 0x07,
+ 0x10, 0x16, 0x2f, 0xb7, 0xb1, 0x0d, 0x62, 0xff, 0xc5, 0x03, 0xfc, 0x1c,
+ 0xb3, 0xa5, 0x8b, 0xcc, 0x5e, 0x58, 0xac, 0x3f, 0xe9, 0x89, 0x3e, 0x7d,
+ 0x7f, 0x87, 0xc6, 0xff, 0xf0, 0x6b, 0x17, 0xff, 0x34, 0x70, 0x9e, 0x5b,
+ 0x79, 0x9a, 0x58, 0xbf, 0x0f, 0x0a, 0x37, 0x56, 0x2f, 0xe2, 0xc9, 0x7e,
+ 0x06, 0xb1, 0x53, 0x9e, 0xb8, 0xca, 0xaf, 0x13, 0xe9, 0x62, 0xf9, 0xdd,
+ 0xc2, 0x2c, 0x5f, 0xff, 0xff, 0xef, 0xe3, 0x6a, 0x5b, 0x4b, 0x26, 0x94,
+ 0x17, 0xb6, 0x83, 0x9b, 0x78, 0x77, 0x91, 0xbe, 0x58, 0xbf, 0xff, 0xb0,
+ 0x7b, 0x58, 0x11, 0xb7, 0xdf, 0xcf, 0x7d, 0xe4, 0xb1, 0x7f, 0xf7, 0x27,
+ 0xc3, 0x30, 0x84, 0x12, 0x36, 0x71, 0x33, 0x53, 0x8e, 0x78, 0x8f, 0x7c,
+ 0x25, 0xef, 0xfe, 0xe6, 0xcf, 0x4c, 0x6f, 0xde, 0x59, 0xc5, 0x8a, 0x85,
+ 0x44, 0xad, 0x1a, 0xc0, 0x70, 0x83, 0xbf, 0xdd, 0xcb, 0x93, 0x4a, 0x27,
+ 0x58, 0xbf, 0xed, 0x61, 0xae, 0x3f, 0xc6, 0x96, 0x28, 0x6b, 0xc9, 0xf8,
+ 0x4d, 0xd2, 0x8c, 0xc8, 0x9a, 0x87, 0x31, 0xcb, 0xbf, 0x0a, 0xe7, 0x2f,
+ 0x23, 0x4f, 0x4a, 0xc1, 0x11, 0xe6, 0xf3, 0x8b, 0xff, 0xfb, 0xd9, 0xdf,
+ 0xb5, 0xa8, 0xf0, 0x03, 0x29, 0x7f, 0x16, 0x2e, 0x6d, 0xeb, 0x17, 0xd0,
+ 0x52, 0xe2, 0xc5, 0x9b, 0xb4, 0x4c, 0xcc, 0xbc, 0x01, 0x9b, 0xfd, 0xa9,
+ 0xca, 0x3a, 0x69, 0x2c, 0x57, 0xcf, 0xb1, 0xcd, 0xef, 0xdf, 0x8d, 0xe3,
+ 0x85, 0x8b, 0xc3, 0x72, 0x58, 0xb6, 0xf5, 0x8b, 0xf7, 0x7e, 0x28, 0xfa,
+ 0xc5, 0xb5, 0x06, 0xf5, 0xc5, 0x2f, 0xbb, 0x9a, 0x34, 0xb1, 0x6d, 0x2c,
+ 0x56, 0x1b, 0x71, 0x12, 0xdf, 0xff, 0xa3, 0xdf, 0x79, 0xb8, 0xed, 0xd1,
+ 0x3e, 0x74, 0xb1, 0x52, 0x4d, 0x54, 0x65, 0x5a, 0x59, 0xe2, 0xe6, 0xe1,
+ 0x05, 0xf3, 0x6f, 0xc1, 0xac, 0x5f, 0x17, 0xb0, 0x96, 0x2e, 0x2f, 0x68,
+ 0xf1, 0x5c, 0x92, 0xff, 0xbb, 0x97, 0x05, 0xe8, 0xf7, 0x16, 0x2f, 0xda,
+ 0x93, 0xf6, 0x62, 0xc5, 0xfe, 0xe1, 0x8e, 0x38, 0xef, 0x8b, 0x15, 0x08,
+ 0xc9, 0xc2, 0xc6, 0x3c, 0x72, 0xbb, 0xf7, 0x05, 0xe8, 0x25, 0x8b, 0xfc,
+ 0x2e, 0xe5, 0xee, 0x0b, 0x75, 0x62, 0xf7, 0x23, 0xb5, 0x8b, 0xd1, 0xfe,
+ 0x2c, 0x5f, 0xb3, 0xf2, 0xec, 0x0b, 0x17, 0x39, 0x9d, 0x9f, 0x28, 0x07,
+ 0xbc, 0x3b, 0x52, 0x4c, 0xf3, 0x0e, 0x7e, 0x50, 0x50, 0x9f, 0xbf, 0xd9,
+ 0xde, 0xdc, 0xfb, 0x7d, 0x62, 0xef, 0x8d, 0x62, 0xe6, 0xe9, 0x62, 0xe7,
+ 0xf0, 0xcd, 0x86, 0xe0, 0xc5, 0x69, 0x12, 0xae, 0xcd, 0x68, 0x58, 0xbf,
+ 0xb5, 0x0d, 0x27, 0xe2, 0xc5, 0x0c, 0xdf, 0x76, 0x23, 0x7f, 0x9c, 0x19,
+ 0x34, 0x1d, 0x96, 0x2f, 0xfb, 0xdc, 0x14, 0x83, 0x1b, 0x79, 0x62, 0xff,
+ 0x13, 0x9b, 0x34, 0x66, 0x96, 0x2a, 0x11, 0x8b, 0x84, 0x4e, 0x66, 0x23,
+ 0xcb, 0xff, 0xfd, 0xb3, 0x9a, 0x11, 0x73, 0xdd, 0xf4, 0xda, 0xf3, 0x83,
+ 0x8b, 0x17, 0xd1, 0x92, 0x75, 0x8a, 0x1a, 0x22, 0x3e, 0xcf, 0x7b, 0x1b,
+ 0x8b, 0x17, 0xef, 0x7b, 0x05, 0x3a, 0xc5, 0xff, 0xf4, 0xef, 0xfc, 0x1e,
+ 0xdc, 0x22, 0xc6, 0x02, 0xc5, 0x4e, 0x89, 0x6e, 0x87, 0x34, 0x55, 0x7e,
+ 0x03, 0xf7, 0x23, 0xac, 0x5f, 0xe9, 0x78, 0xb3, 0x9f, 0x65, 0x8a, 0x98,
+ 0xf7, 0x5c, 0xaa, 0xff, 0xf6, 0x6b, 0x4f, 0x2d, 0xbf, 0x8f, 0x71, 0xd6,
+ 0x2f, 0xf6, 0x9f, 0x9b, 0x7d, 0x39, 0x8b, 0x16, 0xf4, 0x91, 0x0a, 0x24,
+ 0xcb, 0xfd, 0xd3, 0x3e, 0xde, 0x3f, 0xd6, 0x29, 0x8f, 0x7f, 0xe5, 0x34,
+ 0x35, 0x4d, 0xf9, 0x0b, 0x96, 0x84, 0x7b, 0xc6, 0x0d, 0x7b, 0x82, 0x35,
+ 0x62, 0xf8, 0xa2, 0x4c, 0xb1, 0x79, 0xca, 0x65, 0x8b, 0xdd, 0xc9, 0x96,
+ 0x2c, 0xe7, 0x37, 0x64, 0x3b, 0x78, 0x50, 0x4b, 0x17, 0xff, 0xf9, 0xbd,
+ 0x04, 0xf2, 0xc1, 0xf1, 0xf4, 0xdf, 0x6d, 0xeb, 0x17, 0xd0, 0x52, 0xe2,
+ 0xc5, 0x62, 0x67, 0xda, 0x1f, 0xfa, 0xe1, 0x12, 0xef, 0x1c, 0x0d, 0x82,
+ 0xff, 0xfd, 0xc2, 0xdb, 0xf7, 0x6f, 0x00, 0x44, 0x4f, 0x25, 0x8b, 0xff,
+ 0xff, 0xa3, 0x59, 0x34, 0x1f, 0x3a, 0x61, 0xfe, 0x3d, 0xc3, 0x75, 0x81,
+ 0x16, 0x2f, 0xc5, 0x12, 0x03, 0x2c, 0x5f, 0xcc, 0x6e, 0xe0, 0xb4, 0x6a,
+ 0xc5, 0xfe, 0x28, 0x17, 0x7c, 0x7d, 0xd5, 0x8a, 0xf9, 0xf5, 0xb9, 0xa5,
+ 0xf4, 0x61, 0x9e, 0x58, 0xbf, 0xe3, 0xc1, 0x74, 0xe4, 0x00, 0xaa, 0xc5,
+ 0xc5, 0xd2, 0xc5, 0xfb, 0x59, 0xb8, 0xc0, 0x58, 0xb3, 0x61, 0xe1, 0x9c,
+ 0x62, 0xff, 0xa0, 0x1a, 0xd4, 0x18, 0x3e, 0xd6, 0x2f, 0xf1, 0x87, 0xfc,
+ 0x31, 0x4e, 0xb1, 0x7f, 0xf9, 0xe4, 0xda, 0xce, 0xe6, 0x94, 0x6a, 0x75,
+ 0x8b, 0xff, 0xfc, 0x03, 0xbc, 0xb3, 0x7b, 0x73, 0xf8, 0x0d, 0xcc, 0xfb,
+ 0x2c, 0x54, 0x23, 0x9c, 0x06, 0xa2, 0x4d, 0xbf, 0xe3, 0xc7, 0x59, 0xe6,
+ 0xd6, 0x2c, 0x5c, 0xfe, 0x58, 0xbc, 0x59, 0xcc, 0x3d, 0x02, 0x39, 0xbf,
+ 0x9e, 0x71, 0xe6, 0x71, 0x62, 0xb1, 0x5b, 0xe7, 0x50, 0x92, 0x98, 0x84,
+ 0xe4, 0x7f, 0x84, 0x00, 0x09, 0xbd, 0x19, 0x1e, 0xf7, 0xfd, 0xc3, 0x0b,
+ 0xfe, 0xe7, 0x85, 0xde, 0x0d, 0xc9, 0x62, 0xff, 0xff, 0xe9, 0x46, 0xd1,
+ 0xe1, 0x3f, 0x3e, 0xe0, 0xe6, 0xdc, 0xf4, 0x7b, 0x8b, 0x15, 0x32, 0x2b,
+ 0xfc, 0x75, 0x70, 0xbb, 0x58, 0xbf, 0xa0, 0xf1, 0x9d, 0xf9, 0x62, 0xd8,
+ 0x73, 0xc7, 0xf0, 0xcd, 0x42, 0xee, 0x4e, 0x4b, 0xf2, 0x78, 0xd1, 0x44,
+ 0xd7, 0x7e, 0xd7, 0xdd, 0xce, 0xb1, 0x76, 0x8d, 0x58, 0xac, 0x3c, 0x10,
+ 0xca, 0x2f, 0xbd, 0xcd, 0xac, 0xb1, 0x7f, 0x4f, 0x9a, 0x6e, 0xa1, 0x62,
+ 0xf8, 0x87, 0x07, 0x58, 0xbf, 0xfe, 0x11, 0x7b, 0x9f, 0x69, 0x8a, 0x0e,
+ 0xf2, 0x58, 0xbf, 0xb5, 0x0d, 0x27, 0xe2, 0xc5, 0xc2, 0x75, 0x8b, 0x66,
+ 0xd3, 0xc4, 0x22, 0xda, 0x3a, 0x2f, 0x37, 0xc2, 0x52, 0xfe, 0x70, 0x60,
+ 0xde, 0x4b, 0x15, 0x09, 0x9a, 0xe4, 0x37, 0x98, 0xaa, 0xf8, 0x1c, 0x0b,
+ 0x02, 0xab, 0x17, 0xdd, 0x3e, 0xa7, 0x58, 0xbf, 0x03, 0x9b, 0x63, 0xcb,
+ 0x15, 0x07, 0xa0, 0xe4, 0xb5, 0x0a, 0x96, 0x58, 0x97, 0xf1, 0xb2, 0x39,
+ 0x99, 0x3e, 0xdf, 0xbe, 0x06, 0xd1, 0xab, 0x17, 0xba, 0x0e, 0x4b, 0x17,
+ 0xd1, 0xa0, 0xbf, 0x16, 0x2b, 0xe7, 0x8e, 0x02, 0x0b, 0xfc, 0x03, 0x1c,
+ 0x71, 0xdf, 0x16, 0x2f, 0xf0, 0xff, 0x80, 0x17, 0xb8, 0xb1, 0x7d, 0x81,
+ 0x23, 0x4b, 0x17, 0xff, 0xff, 0xf6, 0x6e, 0xe0, 0xf9, 0x03, 0x8f, 0x7f,
+ 0x05, 0xd7, 0xe3, 0x9f, 0xce, 0x3c, 0x1d, 0x62, 0xfd, 0xfc, 0x94, 0x9d,
+ 0x62, 0xff, 0xfb, 0x3f, 0xd7, 0xda, 0x62, 0x73, 0x3d, 0x9f, 0x58, 0xac,
+ 0x54, 0x4e, 0xce, 0x3a, 0x22, 0x73, 0x62, 0x35, 0xe1, 0x27, 0xa1, 0x17,
+ 0xb8, 0x51, 0x7d, 0xfe, 0x47, 0x4b, 0x17, 0xde, 0x6c, 0x99, 0x62, 0xc6,
+ 0xac, 0x56, 0x1e, 0xd7, 0x64, 0x8c, 0x47, 0x7d, 0x22, 0x89, 0xd6, 0x2e,
+ 0x0c, 0x0b, 0x15, 0xa3, 0x79, 0xc2, 0x3b, 0xd8, 0xd3, 0x2c, 0x5e, 0x82,
+ 0x35, 0x62, 0xa0, 0xf6, 0xc6, 0x43, 0xc1, 0xda, 0x87, 0x49, 0xcf, 0x3c,
+ 0x6c, 0x43, 0x94, 0xe1, 0x93, 0xdb, 0x7d, 0x47, 0x7e, 0xd1, 0xbb, 0x4d,
+ 0x2a, 0x63, 0x50, 0xd6, 0x3c, 0x64, 0xbf, 0x96, 0x62, 0xf1, 0xc5, 0x01,
+ 0x64, 0xa7, 0x87, 0xf9, 0x08, 0xbf, 0x4a, 0x7b, 0x14, 0xa7, 0x53, 0x21,
+ 0xa2, 0x1c, 0x31, 0x6f, 0xfe, 0xf7, 0x3f, 0x93, 0x10, 0xbb, 0x97, 0x16,
+ 0x2f, 0xfe, 0xc2, 0x06, 0x66, 0xb9, 0xe8, 0xc5, 0x8b, 0xfe, 0xef, 0xd9,
+ 0xa6, 0x9d, 0xce, 0xb1, 0x7b, 0x37, 0xe2, 0xc5, 0x01, 0x13, 0x64, 0x85,
+ 0xc3, 0xba, 0x84, 0xc4, 0xb2, 0x1c, 0x77, 0x82, 0xf2, 0x65, 0x8b, 0xe8,
+ 0x27, 0x92, 0xc5, 0xf7, 0x03, 0x9e, 0x16, 0x2f, 0xd9, 0xba, 0xe4, 0x0d,
+ 0xa7, 0xcf, 0xa2, 0x1e, 0x10, 0xde, 0x3b, 0xcc, 0xb1, 0x7f, 0xe9, 0x39,
+ 0x18, 0xe3, 0x8e, 0xf8, 0xb1, 0x7f, 0x31, 0xe3, 0xe1, 0x8d, 0x62, 0xff,
+ 0x83, 0xf3, 0x10, 0xa5, 0x9c, 0x58, 0xa9, 0x1f, 0x4b, 0x17, 0xdf, 0xbe,
+ 0xd1, 0xae, 0x2c, 0x57, 0x49, 0x88, 0x4c, 0x3d, 0xf8, 0x54, 0xef, 0x21,
+ 0xbf, 0xff, 0x4b, 0x85, 0x9e, 0xe3, 0x61, 0xfd, 0xac, 0x31, 0x62, 0xff,
+ 0xdf, 0x63, 0x8f, 0x26, 0x8c, 0xd2, 0xc5, 0xe9, 0x47, 0x6b, 0x17, 0xe1,
+ 0x10, 0xa3, 0xb5, 0x8b, 0xc7, 0xcf, 0x2c, 0x5f, 0x40, 0x1c, 0xeb, 0x16,
+ 0x96, 0x23, 0x16, 0x63, 0xf3, 0x8f, 0x00, 0xa4, 0x87, 0x6b, 0xb4, 0xda,
+ 0x8a, 0x31, 0xbb, 0x74, 0xb1, 0x77, 0xa1, 0x62, 0xdc, 0x0a, 0x9a, 0xa6,
+ 0x13, 0xbe, 0x96, 0x4f, 0x25, 0x8a, 0x84, 0x51, 0x3a, 0xa1, 0x15, 0x5f,
+ 0x8b, 0x00, 0x2e, 0x2c, 0x5f, 0xed, 0xa4, 0xf3, 0x94, 0x76, 0xb1, 0x7f,
+ 0xef, 0xb7, 0xbf, 0x8d, 0xe8, 0x02, 0xc5, 0xdd, 0x36, 0x22, 0x73, 0x45,
+ 0x1c, 0x36, 0xbb, 0x9e, 0x58, 0xbf, 0x0d, 0xca, 0x00, 0xb1, 0x5d, 0x1b,
+ 0xf0, 0xc6, 0x2f, 0xe7, 0xf0, 0x03, 0x29, 0x2c, 0x54, 0xe7, 0xa5, 0xf2,
+ 0x3b, 0xfc, 0x28, 0xdf, 0x9e, 0x6d, 0x2c, 0x5f, 0x75, 0xf6, 0x99, 0x62,
+ 0xff, 0xff, 0xb4, 0x00, 0x0b, 0x9f, 0x6f, 0x4b, 0x3e, 0xe0, 0x61, 0xc2,
+ 0xc5, 0xff, 0x3e, 0xb3, 0x7e, 0x6f, 0x81, 0xac, 0x56, 0x22, 0x8c, 0x0c,
+ 0xf7, 0xff, 0xd8, 0x69, 0xac, 0x3f, 0xb4, 0xdf, 0x6e, 0xfc, 0xb1, 0x47,
+ 0x3f, 0x62, 0x22, 0xbf, 0xdb, 0x7e, 0xf2, 0x26, 0x31, 0x62, 0xa1, 0x39,
+ 0x5c, 0x8c, 0xf9, 0x88, 0x6e, 0x16, 0x96, 0x2f, 0x74, 0xfa, 0x58, 0xbf,
+ 0xf4, 0xf8, 0x47, 0xcf, 0x70, 0x3e, 0x2c, 0x5f, 0xb9, 0xd4, 0x68, 0xd5,
+ 0x8b, 0xfa, 0x7f, 0xe7, 0x50, 0x75, 0x8b, 0xf9, 0x81, 0xdc, 0xb3, 0xcb,
+ 0x15, 0x3a, 0x60, 0x3f, 0x18, 0x71, 0xe0, 0x20, 0x91, 0x5e, 0xf3, 0x0b,
+ 0xfe, 0x0c, 0xa5, 0x9b, 0xcb, 0x38, 0xb1, 0x7d, 0x2f, 0x60, 0x16, 0x2f,
+ 0x71, 0xa6, 0x58, 0xae, 0xcf, 0x07, 0x84, 0x77, 0xde, 0xf8, 0xba, 0x58,
+ 0xbf, 0x63, 0x0f, 0xec, 0xb1, 0x53, 0x9e, 0x64, 0x89, 0x6f, 0xee, 0x71,
+ 0x8b, 0xb9, 0x2c, 0x5d, 0xa3, 0x56, 0x2b, 0xb3, 0xc8, 0x72, 0xfb, 0xff,
+ 0x9e, 0x5b, 0x78, 0x59, 0xee, 0x66, 0xea, 0xc5, 0x42, 0x68, 0xb8, 0xde,
+ 0xed, 0x62, 0x22, 0xbf, 0xf7, 0x7e, 0xe3, 0x14, 0x01, 0xce, 0xb1, 0x4b,
+ 0x15, 0x87, 0x97, 0xbc, 0xfe, 0xf4, 0x8f, 0xf5, 0x8a, 0x9c, 0xf0, 0x7c,
+ 0x47, 0x7f, 0xff, 0xed, 0xcc, 0xf7, 0xdc, 0x7b, 0x25, 0x9b, 0xcb, 0x39,
+ 0xc6, 0xef, 0xcb, 0x16, 0xed, 0x62, 0xfb, 0x0f, 0x1b, 0xab, 0x16, 0xec,
+ 0x2e, 0x6e, 0x38, 0x27, 0x78, 0xd6, 0x31, 0x62, 0xfc, 0x63, 0x61, 0x1a,
+ 0xb1, 0x4c, 0x79, 0x02, 0x1f, 0xbf, 0xc3, 0x0f, 0x26, 0xfb, 0x9d, 0x62,
+ 0xb1, 0x39, 0xa6, 0x23, 0x78, 0x56, 0x13, 0xa0, 0x88, 0x6f, 0xbe, 0xe1,
+ 0x38, 0xb1, 0x7f, 0xec, 0xef, 0xc6, 0x61, 0x0f, 0xf0, 0xb1, 0x67, 0xe8,
+ 0xf9, 0x74, 0x4b, 0x6c, 0x58, 0xbe, 0xd4, 0xed, 0x3a, 0xc5, 0xef, 0xb6,
+ 0x96, 0x2c, 0xec, 0x78, 0x53, 0x12, 0xd6, 0xd3, 0xfa, 0xfa, 0x9d, 0xf7,
+ 0x0a, 0x0e, 0xb1, 0x7f, 0xd3, 0xc7, 0x31, 0xb7, 0xb9, 0xd6, 0x2f, 0x6f,
+ 0xc2, 0x58, 0xa8, 0x44, 0xff, 0x64, 0x8e, 0x45, 0xe3, 0xbb, 0xdf, 0x91,
+ 0xd6, 0x2e, 0xfb, 0x2c, 0x56, 0x1b, 0x5f, 0x0f, 0x54, 0x33, 0xfd, 0x65,
+ 0x08, 0xec, 0x8d, 0x7c, 0xd9, 0x4a, 0x7d, 0xc3, 0x25, 0xa1, 0x99, 0xa2,
+ 0x3f, 0xc7, 0x94, 0xf1, 0x9a, 0x81, 0x64, 0xa3, 0xc1, 0xe4, 0xa6, 0x1f,
+ 0x42, 0xc4, 0x51, 0xa0, 0xee, 0x38, 0xdf, 0x69, 0xa3, 0xb5, 0x8b, 0xec,
+ 0xfe, 0x74, 0xb1, 0x7d, 0xdf, 0x04, 0x75, 0x8b, 0x80, 0xcb, 0x17, 0x44,
+ 0xcc, 0x6f, 0x1c, 0x96, 0xe6, 0x31, 0x62, 0xdd, 0x2c, 0x56, 0x1a, 0xb3,
+ 0x8c, 0x5f, 0x8d, 0x35, 0xb5, 0x25, 0x8b, 0xfe, 0x14, 0x7d, 0xfc, 0x21,
+ 0x76, 0xb1, 0x79, 0xfb, 0x92, 0xc5, 0x05, 0x53, 0x7c, 0x82, 0x39, 0xd7,
+ 0xc6, 0xad, 0xa2, 0x02, 0x2b, 0xf1, 0xdd, 0xfd, 0xe6, 0x26, 0x07, 0x16,
+ 0x2f, 0x86, 0x59, 0xf5, 0x8b, 0x0f, 0x69, 0xe7, 0x86, 0x5b, 0x7e, 0xce,
+ 0x0b, 0x53, 0xac, 0x5f, 0xff, 0xff, 0xf7, 0x60, 0xd7, 0x5c, 0xdd, 0xde,
+ 0xdb, 0x01, 0xa1, 0x85, 0x39, 0x2d, 0x85, 0xad, 0x87, 0xb4, 0x1b, 0xbb,
+ 0x76, 0xff, 0x71, 0x62, 0xb1, 0x31, 0xa2, 0x2b, 0x0c, 0xaa, 0xf1, 0xdf,
+ 0xcb, 0x17, 0x4b, 0xcb, 0x17, 0xde, 0x7e, 0xf8, 0xb1, 0x7e, 0x1b, 0x6f,
+ 0x81, 0xac, 0x54, 0xe7, 0x9d, 0xd1, 0x25, 0xbe, 0xb1, 0x60, 0x2c, 0x5d,
+ 0xc9, 0x2c, 0x54, 0x23, 0x8c, 0x63, 0xae, 0xcc, 0x02, 0x4e, 0x09, 0x08,
+ 0x4a, 0xfe, 0x9e, 0x69, 0x6c, 0x5a, 0x9d, 0x62, 0xe9, 0x01, 0x62, 0xf3,
+ 0xe6, 0x96, 0x2f, 0x16, 0x79, 0x62, 0xf7, 0xf0, 0xeb, 0x15, 0xd9, 0xf6,
+ 0xfc, 0x60, 0x87, 0x3c, 0x39, 0x77, 0x89, 0x62, 0xf4, 0x77, 0xc5, 0x8b,
+ 0xe6, 0x29, 0x62, 0xc5, 0xc1, 0xfd, 0x62, 0xf4, 0xee, 0x4b, 0x14, 0x33,
+ 0xf5, 0x38, 0xf7, 0xc8, 0x7c, 0x33, 0x76, 0xbe, 0xb1, 0x7d, 0x03, 0x79,
+ 0x2c, 0x5f, 0xb3, 0xdf, 0x6f, 0x2c, 0x5f, 0x9f, 0xbc, 0xef, 0xcb, 0x15,
+ 0xf3, 0xd2, 0xf1, 0x45, 0xe7, 0xd4, 0x96, 0x2f, 0x7f, 0x0e, 0xb1, 0x52,
+ 0x37, 0x5e, 0x1d, 0xbf, 0xe3, 0x66, 0xcc, 0xeb, 0xd0, 0x6a, 0xc5, 0xfc,
+ 0xfa, 0xcf, 0xc0, 0x16, 0x2e, 0x6e, 0x2c, 0x5c, 0x53, 0xac, 0x57, 0x46,
+ 0xbc, 0x42, 0xf7, 0x83, 0xfb, 0xac, 0x56, 0xd4, 0xf8, 0xa7, 0x18, 0x35,
+ 0xd3, 0xb5, 0xcd, 0x10, 0x9c, 0xf7, 0xeb, 0x9c, 0x22, 0xbe, 0x3e, 0xe6,
+ 0xe8, 0xd6, 0x2d, 0x3a, 0xc5, 0xb4, 0xb1, 0x53, 0x9a, 0x56, 0x13, 0xbe,
+ 0x9d, 0xdf, 0xeb, 0x17, 0xe1, 0x4e, 0xef, 0xf5, 0x8b, 0xf6, 0x0c, 0x0f,
+ 0xe5, 0x8a, 0xda, 0x7e, 0x9f, 0x23, 0xde, 0x53, 0x7e, 0x0e, 0x42, 0x8e,
+ 0x2c, 0x54, 0xe7, 0xba, 0x69, 0x9d, 0xf8, 0x6d, 0xbe, 0x06, 0xb1, 0x6f,
+ 0x2c, 0x5d, 0xb9, 0xd2, 0xc5, 0xfc, 0x66, 0x14, 0x77, 0xc5, 0x8a, 0x92,
+ 0x21, 0xfb, 0x2a, 0xd0, 0x93, 0x8e, 0x5f, 0xc2, 0x7d, 0x49, 0xc0, 0xb1,
+ 0x7f, 0xc5, 0x9a, 0xd4, 0x74, 0x19, 0xd6, 0x2f, 0xf3, 0x6b, 0x0e, 0xfd,
+ 0xec, 0x8c, 0xfa, 0x43, 0x2e, 0xbf, 0x4d, 0xf6, 0xef, 0xcb, 0x15, 0xf3,
+ 0xf9, 0xf2, 0x75, 0xfb, 0x08, 0x7f, 0x85, 0x8a, 0xd8, 0xd7, 0xd5, 0xa2,
+ 0x14, 0xb2, 0x3c, 0xc8, 0x46, 0x34, 0xa1, 0xe3, 0xbb, 0xfd, 0x3d, 0xe1,
+ 0xe4, 0x50, 0xab, 0x14, 0x63, 0xe6, 0x11, 0x5f, 0xf6, 0x0c, 0x6d, 0xde,
+ 0x77, 0xe5, 0x8b, 0xee, 0x8a, 0x24, 0xb1, 0x5f, 0x3d, 0xe7, 0x3b, 0xbf,
+ 0xd1, 0x9e, 0x8f, 0xb8, 0xd6, 0x2e, 0xe6, 0xea, 0xc5, 0xf6, 0x7d, 0x8e,
+ 0xb1, 0x7f, 0xd9, 0xe8, 0xe8, 0x38, 0x06, 0x2c, 0x5e, 0x8e, 0xe4, 0xb1,
+ 0x53, 0xa3, 0xa0, 0x64, 0x3a, 0x32, 0x00, 0xd9, 0x84, 0x41, 0x0e, 0xaf,
+ 0xb3, 0x0b, 0xcb, 0x17, 0xff, 0xb7, 0xb1, 0x03, 0xec, 0xf2, 0xf3, 0x4e,
+ 0xb1, 0x7c, 0x27, 0xd4, 0x96, 0x2a, 0x0f, 0xbc, 0x69, 0x97, 0xfe, 0x81,
+ 0xea, 0x3c, 0xdd, 0x30, 0xd6, 0x2f, 0xbd, 0xc7, 0xe9, 0x62, 0x86, 0x7c,
+ 0x62, 0x3f, 0xbe, 0x13, 0xea, 0x4b, 0x17, 0xa0, 0x24, 0x96, 0x28, 0x67,
+ 0x85, 0x31, 0x1d, 0xfd, 0xee, 0x86, 0x33, 0xe9, 0x62, 0xfd, 0xe6, 0x28,
+ 0x02, 0xc5, 0xff, 0x4d, 0xcd, 0xee, 0x53, 0x88, 0x6b, 0x17, 0xf3, 0x98,
+ 0x00, 0x1f, 0x71, 0x62, 0xfb, 0x3d, 0x87, 0x58, 0xb8, 0x8d, 0x58, 0xa7,
+ 0x37, 0x42, 0x22, 0xa9, 0x22, 0x37, 0x8d, 0xb7, 0xe9, 0x10, 0x9f, 0x8b,
+ 0x17, 0xfe, 0x82, 0x17, 0xa4, 0x22, 0xf7, 0x16, 0x2b, 0x0f, 0x9f, 0x45,
+ 0x17, 0xff, 0xe1, 0xc4, 0xa3, 0x25, 0xf8, 0x19, 0x47, 0xb8, 0xb1, 0x7f,
+ 0xd1, 0xe9, 0x66, 0xeb, 0x90, 0x16, 0x2b, 0x11, 0x1e, 0x4a, 0x97, 0x80,
+ 0xc0, 0x58, 0xbe, 0x9e, 0x6f, 0xb2, 0xc5, 0xbf, 0x87, 0x84, 0x21, 0xdb,
+ 0x9c, 0xeb, 0x17, 0xfd, 0xbb, 0xf6, 0xda, 0x6e, 0xb3, 0x8b, 0x15, 0xd1,
+ 0xeb, 0x88, 0x5e, 0xff, 0xc4, 0xe6, 0xfd, 0xe5, 0xc6, 0x1a, 0xc5, 0xfb,
+ 0xec, 0x4f, 0x3a, 0xc5, 0xba, 0x58, 0xbe, 0x14, 0xb3, 0x9d, 0x1b, 0xb2,
+ 0x28, 0xa3, 0xa2, 0xc8, 0x9e, 0xaf, 0xff, 0xe9, 0xdb, 0x44, 0xe6, 0xf3,
+ 0xf0, 0xfd, 0xc0, 0xd9, 0x62, 0xec, 0xf2, 0xc5, 0x61, 0xf9, 0x92, 0xe5,
+ 0xc1, 0x9d, 0x62, 0x99, 0x19, 0xc5, 0x09, 0x5f, 0x10, 0x5f, 0xe1, 0xe7,
+ 0x39, 0x9a, 0x9d, 0x62, 0xc3, 0x58, 0xae, 0x8f, 0x1f, 0xb3, 0x5b, 0xb7,
+ 0xba, 0xc5, 0xfd, 0xa8, 0xeb, 0x37, 0xe2, 0xc5, 0xfe, 0x20, 0x6b, 0x4d,
+ 0x37, 0x16, 0x2a, 0x0f, 0x95, 0xcc, 0x2f, 0x40, 0x48, 0x58, 0xa8, 0x64,
+ 0x18, 0xce, 0xb7, 0x28, 0x48, 0x0e, 0x10, 0x98, 0xc8, 0x69, 0x1f, 0x66,
+ 0x2c, 0x4f, 0x34, 0x32, 0xf5, 0x08, 0xa3, 0xc2, 0xc3, 0xec, 0x64, 0xfd,
+ 0xe8, 0xe8, 0xc4, 0xf5, 0xbc, 0x93, 0x71, 0xf8, 0x21, 0x05, 0xfa, 0x68,
+ 0xf1, 0x6f, 0x58, 0xbe, 0x9b, 0x18, 0x0b, 0x15, 0xb4, 0xf3, 0xa0, 0xae,
+ 0xff, 0xe8, 0xdf, 0xa8, 0xd6, 0x37, 0xe0, 0x6b, 0x17, 0x46, 0x2c, 0x51,
+ 0x1e, 0xdf, 0x11, 0x6e, 0x73, 0xac, 0x5d, 0x36, 0xe2, 0xc5, 0x11, 0xb3,
+ 0xde, 0x2f, 0x7f, 0x47, 0x9e, 0x67, 0xf2, 0xc5, 0xff, 0xf9, 0x8f, 0xdc,
+ 0xb9, 0xb7, 0xf9, 0xee, 0x13, 0xf9, 0x62, 0xe1, 0x79, 0x62, 0xfc, 0x22,
+ 0xf6, 0x01, 0x62, 0xa4, 0x9d, 0xde, 0x3f, 0x32, 0xa1, 0xc8, 0xbc, 0x5d,
+ 0xb8, 0xb2, 0x10, 0x62, 0xdb, 0x3b, 0x1c, 0x60, 0x57, 0x01, 0x48, 0x62,
+ 0x05, 0x61, 0x2d, 0xb0, 0x46, 0x2f, 0xb1, 0x47, 0x95, 0xb0, 0xa1, 0x33,
+ 0xb0, 0xc9, 0x02, 0xd4, 0x20, 0x42, 0xc6, 0xc8, 0xa6, 0x55, 0x4f, 0x2d,
+ 0xde, 0x53, 0xbd, 0xa3, 0xa6, 0x20, 0xe5, 0x7b, 0x86, 0x6c, 0xb9, 0xde,
+ 0xa9, 0x0f, 0xdd, 0xce, 0xc6, 0x34, 0xec, 0x94, 0xd4, 0xa9, 0xad, 0x52,
+ 0x21, 0x0f, 0x3b, 0x53, 0xfa, 0xe5, 0xe1, 0xe7, 0xef, 0x01, 0x3d, 0x2e,
+ 0x17, 0x8c, 0xd0, 0xab, 0x0c, 0xee, 0x5a, 0x5b, 0x2f, 0x56, 0x4c, 0xa2,
+ 0x95, 0x19, 0xbe, 0x3d, 0x13, 0x23, 0x13, 0xdc, 0x9f, 0xab, 0x0e, 0x94,
+ 0x68, 0x12, 0x59, 0x35, 0xfb, 0x65, 0xb4, 0xfa, 0x58, 0xad, 0x98, 0xc1,
+ 0xe4, 0xa7, 0x56, 0x62, 0xaf, 0xe6, 0x07, 0xd0, 0x09, 0x5f, 0xf7, 0xff,
+ 0xb6, 0x4e, 0xf2, 0xd9, 0xcd, 0x74, 0xef, 0xd2, 0xa2, 0x6c, 0x2f, 0xda,
+ 0xe9, 0xdf, 0xa5, 0x45, 0x5a, 0x5c, 0x0d, 0xeb, 0x17, 0x73, 0x71, 0x62,
+ 0xdb, 0x38, 0x7d, 0x9f, 0x37, 0xe0, 0xd5, 0xdb, 0xf4, 0xb1, 0x73, 0xc2,
+ 0xc5, 0xfe, 0x94, 0x85, 0xe2, 0x89, 0x2c, 0x5f, 0x67, 0xdf, 0xcb, 0x15,
+ 0x87, 0xac, 0x46, 0x97, 0xfe, 0x07, 0xde, 0x4d, 0x2f, 0xb6, 0xf5, 0x8a,
+ 0x0a, 0x9f, 0x0f, 0x08, 0x2f, 0xff, 0xf6, 0xf8, 0x6d, 0x74, 0xc7, 0x79,
+ 0x31, 0x60, 0xf0, 0xd5, 0x8b, 0xff, 0x13, 0xb0, 0x46, 0x29, 0xe0, 0xd5,
+ 0x8b, 0x4a, 0x11, 0x44, 0xec, 0x57, 0xb9, 0x8c, 0xb1, 0x66, 0x58, 0xbb,
+ 0xcd, 0xb4, 0xd6, 0xef, 0x1c, 0xbf, 0xf4, 0xb2, 0x58, 0xf2, 0x28, 0x3a,
+ 0xc5, 0x41, 0xf6, 0xb1, 0x85, 0xff, 0x3f, 0xde, 0x59, 0x3e, 0x18, 0xb1,
+ 0x5a, 0x3d, 0xa3, 0x90, 0x5f, 0xed, 0x67, 0x50, 0x00, 0xce, 0xb1, 0x7f,
+ 0xb8, 0xfe, 0xd9, 0xe1, 0x42, 0xc5, 0xfd, 0x13, 0xea, 0x30, 0x6b, 0x15,
+ 0x23, 0xe4, 0xf9, 0xb5, 0xff, 0xfa, 0x27, 0x8d, 0x41, 0xe2, 0x3d, 0xf6,
+ 0x01, 0xd6, 0x2a, 0x0f, 0xdf, 0xe4, 0x57, 0x36, 0xe2, 0xc5, 0xe8, 0x1c,
+ 0xcb, 0x15, 0x25, 0x54, 0xed, 0x18, 0xde, 0x88, 0xbf, 0x18, 0x8f, 0x08,
+ 0x7c, 0x35, 0x7d, 0xa3, 0xfc, 0x6b, 0x17, 0xff, 0x6a, 0x45, 0x9e, 0xe4,
+ 0x1f, 0xdd, 0x2c, 0x54, 0x1f, 0x50, 0x89, 0x2e, 0xc2, 0x58, 0xb7, 0x6b,
+ 0x17, 0xf1, 0xbb, 0x82, 0xfb, 0x69, 0x62, 0xdb, 0x98, 0x78, 0xcc, 0x27,
+ 0x43, 0x44, 0x2e, 0x2e, 0x5f, 0xfb, 0x91, 0xef, 0xb9, 0xcf, 0xd7, 0x4b,
+ 0x17, 0xfe, 0x76, 0x09, 0x1f, 0xf1, 0x64, 0x96, 0x2f, 0xd2, 0x6e, 0x9f,
+ 0x4b, 0x15, 0x24, 0x55, 0x7d, 0x0b, 0x87, 0xf7, 0x9d, 0xfa, 0x54, 0x56,
+ 0x85, 0xf8, 0xde, 0xf8, 0x2e, 0xd6, 0x2a, 0x11, 0x0f, 0xd1, 0x83, 0x15,
+ 0x5f, 0xc2, 0x63, 0x75, 0x03, 0x58, 0xbf, 0xd1, 0xa0, 0x07, 0xc8, 0xc5,
+ 0x8b, 0xfe, 0x73, 0xf1, 0xb3, 0x7b, 0xe9, 0x62, 0xfe, 0x18, 0xf3, 0x01,
+ 0xc5, 0x8b, 0xfa, 0x01, 0xee, 0x0b, 0x75, 0x62, 0xa0, 0xf8, 0x38, 0x5d,
+ 0x7f, 0xf9, 0xbd, 0x28, 0xeb, 0xed, 0xee, 0x3f, 0x6b, 0x15, 0xa4, 0xe6,
+ 0x4e, 0x5f, 0xf2, 0xf2, 0x34, 0xf4, 0x26, 0xb7, 0x90, 0xdf, 0xc0, 0xdb,
+ 0x9a, 0x63, 0x56, 0x2f, 0xfb, 0x06, 0xdc, 0x98, 0xa0, 0x6b, 0x14, 0x33,
+ 0xea, 0x73, 0x1b, 0xfe, 0x8e, 0xb0, 0xf8, 0x5e, 0xdc, 0x58, 0xbf, 0xdf,
+ 0x8d, 0x03, 0xd9, 0x3a, 0xc5, 0xfe, 0x2c, 0x96, 0xd6, 0xfc, 0x96, 0x2e,
+ 0xfb, 0x1d, 0x14, 0xdf, 0x3c, 0xf1, 0xad, 0xff, 0xcf, 0x2d, 0xba, 0x8f,
+ 0x37, 0x4c, 0x35, 0x8b, 0xf4, 0x14, 0xe4, 0x6a, 0xc5, 0xa4, 0xb1, 0x69,
+ 0x42, 0x20, 0xa4, 0x8f, 0xd9, 0x4d, 0xe1, 0x73, 0xcb, 0x17, 0xff, 0xe9,
+ 0x39, 0x37, 0xa3, 0xfd, 0x60, 0xca, 0x38, 0xb1, 0x7f, 0xfe, 0x60, 0x90,
+ 0x42, 0x93, 0x73, 0x91, 0xb4, 0xfd, 0x2c, 0x53, 0x22, 0xb9, 0xd5, 0x2f,
+ 0xff, 0xba, 0x8d, 0x60, 0x1c, 0xef, 0x28, 0x6e, 0x96, 0x2f, 0xff, 0xa5,
+ 0xcc, 0x28, 0x3b, 0xe7, 0xbd, 0x07, 0x58, 0xb7, 0xa1, 0x13, 0xce, 0xa1,
+ 0x47, 0x4e, 0xcb, 0xf0, 0xcc, 0xf4, 0x2f, 0xef, 0xfb, 0xed, 0xaf, 0x3f,
+ 0xdc, 0x6b, 0x17, 0xff, 0xff, 0x6f, 0x6f, 0x73, 0x0d, 0xeb, 0xed, 0xec,
+ 0x98, 0xa0, 0xf3, 0xe1, 0x8b, 0x17, 0xa7, 0x10, 0x45, 0x8b, 0xff, 0xef,
+ 0x3e, 0x70, 0x79, 0x2f, 0xc6, 0xf1, 0xc2, 0xc5, 0xff, 0xff, 0xfc, 0xde,
+ 0x1e, 0x0b, 0x9b, 0x7f, 0x9d, 0x7c, 0x53, 0xb6, 0x17, 0x72, 0xe7, 0x05,
+ 0x0b, 0x14, 0xe8, 0xdf, 0x25, 0x1a, 0x84, 0xe6, 0x71, 0xe1, 0xe3, 0x00,
+ 0xbf, 0xbc, 0xff, 0xda, 0x38, 0x58, 0xbd, 0x21, 0x4c, 0xb1, 0x50, 0x79,
+ 0xee, 0x61, 0x7d, 0x2f, 0x34, 0xeb, 0x17, 0xee, 0x71, 0xca, 0x75, 0x8b,
+ 0xf0, 0x7e, 0x28, 0x02, 0xc5, 0xbe, 0xb1, 0x5d, 0xa2, 0x20, 0xe4, 0x9b,
+ 0xca, 0x43, 0x29, 0xbf, 0xfe, 0x03, 0xe7, 0xdd, 0x82, 0x41, 0xc9, 0xcd,
+ 0x58, 0xbf, 0xf3, 0x73, 0x07, 0xdf, 0x23, 0x5c, 0x58, 0xbf, 0xcf, 0x2f,
+ 0x34, 0xff, 0x65, 0x8a, 0x84, 0xc1, 0x71, 0x07, 0xa5, 0x06, 0x40, 0xbf,
+ 0x67, 0xdb, 0x0e, 0xb1, 0x7e, 0x60, 0x1d, 0xb4, 0xb1, 0x7f, 0xe1, 0xb6,
+ 0xf6, 0x1e, 0x19, 0x9f, 0x58, 0xbf, 0xfa, 0x08, 0x6e, 0x77, 0x94, 0x37,
+ 0x4b, 0x17, 0xff, 0xfc, 0xfe, 0x82, 0x79, 0xe3, 0x50, 0xd2, 0x83, 0x94,
+ 0x1a, 0xb1, 0x7f, 0x9b, 0x8c, 0x20, 0xb8, 0xe1, 0x62, 0x89, 0x13, 0x7e,
+ 0x64, 0xbf, 0xbf, 0x1d, 0x13, 0x9d, 0x62, 0xff, 0xce, 0xdd, 0x7d, 0xc5,
+ 0x3e, 0x99, 0x62, 0x98, 0xfb, 0x88, 0xba, 0xf7, 0x42, 0x85, 0x8b, 0xfd,
+ 0x3c, 0x61, 0x0f, 0xf0, 0xb1, 0x6c, 0x63, 0xd1, 0x71, 0xea, 0x9d, 0x54,
+ 0xa0, 0xc9, 0xf0, 0xa3, 0xa4, 0x16, 0x86, 0xf7, 0xe1, 0x20, 0x4e, 0x37,
+ 0xec, 0xec, 0xc7, 0x31, 0x62, 0xff, 0xee, 0xf9, 0xf8, 0xe6, 0x78, 0x9c,
+ 0xd5, 0x8a, 0xd1, 0xf8, 0xb9, 0x5d, 0xfe, 0x94, 0x6a, 0x78, 0xd4, 0xeb,
+ 0x17, 0xd2, 0xd6, 0x1d, 0x62, 0xf6, 0x68, 0x0b, 0x17, 0xe9, 0xb0, 0x67,
+ 0xdd, 0x58, 0xbf, 0xc7, 0x8e, 0xf5, 0x1d, 0xf9, 0x62, 0xfe, 0x28, 0x33,
+ 0xb9, 0x71, 0x62, 0xbb, 0x46, 0x9b, 0x11, 0xcc, 0x3a, 0x72, 0xd0, 0x86,
+ 0xd7, 0x8d, 0x17, 0x4b, 0x17, 0x67, 0x16, 0x2a, 0x13, 0x8d, 0xc8, 0xc2,
+ 0x4d, 0x4d, 0x0c, 0x82, 0xff, 0xff, 0xfc, 0xdd, 0x67, 0xa0, 0xbd, 0xcd,
+ 0xb0, 0xc3, 0xc3, 0xed, 0xd4, 0x34, 0x9f, 0x8b, 0x17, 0xff, 0x9d, 0xbc,
+ 0x2d, 0x3f, 0x03, 0xc2, 0xe9, 0x62, 0xfd, 0x12, 0xfc, 0x4e, 0xb1, 0x7f,
+ 0xff, 0x1b, 0xcf, 0xc1, 0x78, 0x7f, 0x8e, 0x10, 0x9f, 0xcb, 0x15, 0x24,
+ 0x42, 0xe1, 0x4d, 0xff, 0xd8, 0x43, 0x1c, 0x7f, 0x30, 0xba, 0x58, 0xbf,
+ 0xfe, 0xd0, 0x38, 0x0f, 0xbc, 0x9b, 0xc5, 0x00, 0x58, 0xac, 0x54, 0x15,
+ 0xf8, 0x42, 0x94, 0x34, 0x38, 0x44, 0x24, 0x3b, 0xfb, 0x3c, 0xe4, 0x01,
+ 0x2c, 0x5f, 0xdf, 0xda, 0xd3, 0xb9, 0x2c, 0x5f, 0xc7, 0xe0, 0xc9, 0xcc,
+ 0x58, 0xbf, 0x03, 0x81, 0x60, 0x58, 0x16, 0x2c, 0x54, 0x1f, 0x43, 0x97,
+ 0xdf, 0xba, 0x61, 0xe1, 0x2c, 0x5f, 0x69, 0xa0, 0xeb, 0x17, 0x38, 0xd6,
+ 0x2b, 0xb3, 0x72, 0x02, 0x2a, 0xc4, 0x41, 0xbb, 0x0d, 0xfe, 0x7f, 0x37,
+ 0x98, 0x1c, 0x58, 0xa9, 0x27, 0x79, 0x85, 0xa5, 0x09, 0x8e, 0x42, 0x8c,
+ 0x44, 0x37, 0xf4, 0x6b, 0xdc, 0xc9, 0x2c, 0x5f, 0xf6, 0xa6, 0x2c, 0x1f,
+ 0xe3, 0x7a, 0xc5, 0xff, 0x68, 0x18, 0x37, 0xf0, 0xa1, 0x62, 0xff, 0xc3,
+ 0xf8, 0x9c, 0xdc, 0x1b, 0xc9, 0x62, 0xfb, 0xe6, 0x3c, 0xeb, 0x15, 0x88,
+ 0xda, 0x73, 0xc2, 0x39, 0xf2, 0x05, 0x6c, 0x6d, 0xe3, 0xc0, 0x54, 0x6b,
+ 0x62, 0x86, 0x6c, 0x4b, 0x6f, 0x9e, 0x19, 0xc3, 0x85, 0x36, 0x4a, 0xec,
+ 0x36, 0x19, 0x1d, 0x43, 0x1f, 0xb8, 0x5e, 0xb4, 0x7d, 0x13, 0x1d, 0xea,
+ 0x3d, 0x23, 0xc2, 0x0f, 0xf1, 0xd6, 0xbc, 0xad, 0x00, 0x43, 0x80, 0xa3,
+ 0xae, 0xe4, 0xa4, 0xef, 0x4a, 0x10, 0xde, 0xa6, 0x1c, 0x61, 0x17, 0xdb,
+ 0x27, 0x0f, 0x75, 0x62, 0xb6, 0x53, 0xd1, 0x36, 0x3a, 0x6b, 0xf9, 0x80,
+ 0xfb, 0xe3, 0xcb, 0x17, 0xd1, 0xd3, 0x74, 0xb1, 0x52, 0x3d, 0x33, 0x0b,
+ 0xef, 0xf0, 0xbb, 0x72, 0xc0, 0x71, 0x62, 0xff, 0xfd, 0xfc, 0x2c, 0x37,
+ 0xef, 0x2f, 0x98, 0xe1, 0x9d, 0x62, 0xfb, 0xa7, 0x7e, 0x95, 0x16, 0x01,
+ 0x52, 0x44, 0x4e, 0x96, 0x2f, 0xf1, 0xdb, 0x82, 0x8d, 0x4c, 0xb1, 0x7e,
+ 0x9b, 0x9a, 0x8d, 0xeb, 0x17, 0xdd, 0x07, 0xf9, 0x96, 0x2a, 0x11, 0x10,
+ 0xc6, 0xae, 0x59, 0x78, 0x01, 0x81, 0x62, 0xfc, 0x3c, 0xc0, 0x71, 0x62,
+ 0xa1, 0x3f, 0xf9, 0xc8, 0xf2, 0x17, 0xbc, 0x85, 0x5f, 0x8b, 0x43, 0x1f,
+ 0xbf, 0xc3, 0x8d, 0x9e, 0xfc, 0x28, 0x58, 0xad, 0x94, 0x4d, 0x09, 0x8a,
+ 0xfd, 0xae, 0x9d, 0xfa, 0x54, 0x4e, 0xa5, 0xff, 0xfe, 0xfc, 0x4e, 0x3c,
+ 0x3e, 0xcf, 0x39, 0x9f, 0x6e, 0x0a, 0x75, 0x8b, 0xf6, 0xc9, 0xde, 0x5b,
+ 0x38, 0x89, 0xe9, 0x8d, 0xef, 0xff, 0xe2, 0x14, 0x7b, 0x98, 0x5b, 0x20,
+ 0x04, 0x7d, 0xe7, 0x58, 0xbc, 0xf3, 0x3a, 0xc5, 0xd1, 0xc5, 0x8b, 0x8b,
+ 0x66, 0x63, 0x69, 0xe1, 0xda, 0x84, 0x61, 0x64, 0x24, 0xaf, 0x1b, 0x07,
+ 0x58, 0xbd, 0x3c, 0x74, 0xb1, 0x7f, 0xdf, 0x17, 0x63, 0x6d, 0xf0, 0x35,
+ 0x8b, 0x64, 0xe7, 0xb9, 0xe1, 0xfb, 0xe7, 0xe8, 0x33, 0xac, 0x5e, 0x97,
+ 0x36, 0x4d, 0x46, 0x39, 0x3d, 0x6f, 0x28, 0xbd, 0x87, 0x65, 0x8b, 0xee,
+ 0x9d, 0xfa, 0x54, 0x5b, 0x25, 0xfe, 0x6d, 0x7d, 0xf7, 0xb0, 0x5d, 0x62,
+ 0xb4, 0x7d, 0x5f, 0x31, 0xbf, 0xfb, 0xed, 0xef, 0x8b, 0xbc, 0x3b, 0xf6,
+ 0xb1, 0x76, 0xf6, 0x58, 0xbf, 0xbc, 0xff, 0xda, 0x38, 0x58, 0xbf, 0xff,
+ 0xa5, 0xb3, 0xc8, 0x6c, 0x1b, 0x67, 0x33, 0xc5, 0x0b, 0x15, 0x08, 0x8b,
+ 0x73, 0x0b, 0xf4, 0xa1, 0xb7, 0xc2, 0xc5, 0xfb, 0x08, 0x07, 0xc5, 0x8b,
+ 0xfe, 0x8e, 0x6c, 0xfd, 0xba, 0x7d, 0x2c, 0x5f, 0xf3, 0x61, 0x1b, 0x1b,
+ 0xdf, 0xeb, 0x15, 0x08, 0xc7, 0xe8, 0xa4, 0x04, 0xfb, 0x87, 0xb7, 0xfa,
+ 0x51, 0xa9, 0xe3, 0x53, 0xac, 0x5f, 0xef, 0x7d, 0xa6, 0xfc, 0x4e, 0xb1,
+ 0x50, 0x7d, 0x98, 0x6d, 0x7d, 0xf6, 0x33, 0x62, 0x58, 0xbf, 0xff, 0xbe,
+ 0xdc, 0x7f, 0x41, 0xcd, 0x8e, 0x36, 0xe4, 0x79, 0x62, 0xfd, 0xfc, 0xd4,
+ 0x79, 0x62, 0xbb, 0x44, 0x37, 0x97, 0xa8, 0x68, 0xd3, 0x78, 0x57, 0xdf,
+ 0xef, 0x49, 0xe5, 0xf8, 0x9d, 0x62, 0xfd, 0xef, 0x98, 0xf3, 0xac, 0x5b,
+ 0x64, 0x6b, 0x94, 0x39, 0x08, 0x6e, 0x88, 0x99, 0x1c, 0xf0, 0xa4, 0x78,
+ 0x74, 0x14, 0x2b, 0x39, 0x0f, 0x3f, 0x13, 0x86, 0x6b, 0x7f, 0xd0, 0xde,
+ 0xe4, 0x4f, 0x9c, 0x58, 0xba, 0x5e, 0x58, 0xbe, 0x06, 0xe6, 0x6c, 0xfc,
+ 0xf4, 0x40, 0x73, 0x7f, 0xe2, 0xd9, 0x38, 0x9b, 0xc4, 0xe1, 0x16, 0x2f,
+ 0xcf, 0xcf, 0xbc, 0x96, 0x2f, 0xf0, 0xbc, 0x0d, 0x0a, 0x5c, 0x58, 0xad,
+ 0x1e, 0xf1, 0x14, 0x5f, 0xcf, 0xad, 0xc7, 0x23, 0x56, 0x2f, 0x0b, 0x9b,
+ 0x38, 0x7a, 0x44, 0x43, 0x60, 0x62, 0x65, 0x00, 0x87, 0x9d, 0x62, 0x72,
+ 0xaf, 0x1b, 0x3d, 0xdd, 0xf4, 0xb1, 0x7d, 0xd3, 0xbf, 0x4a, 0x8b, 0x98,
+ 0xb1, 0xd6, 0x2b, 0x47, 0x86, 0x61, 0x8d, 0xfc, 0x59, 0xd8, 0x1a, 0x4b,
+ 0x16, 0x0b, 0xac, 0x56, 0x8f, 0x13, 0x79, 0x75, 0xe7, 0x3f, 0x16, 0x2f,
+ 0x46, 0x7d, 0x62, 0xe9, 0x8e, 0xb1, 0x62, 0x58, 0xa5, 0x8c, 0x2c, 0x6a,
+ 0x13, 0x65, 0xc5, 0xd6, 0x67, 0x72, 0x42, 0x1d, 0x30, 0x73, 0x70, 0xaa,
+ 0xfe, 0x9f, 0x64, 0x29, 0xb1, 0xec, 0x61, 0x45, 0x8b, 0xfa, 0x4f, 0xa9,
+ 0xfe, 0x25, 0x8b, 0xf7, 0x20, 0x01, 0xce, 0xb1, 0x6c, 0x98, 0xf6, 0xf8,
+ 0x61, 0x7b, 0x8f, 0xa5, 0x8b, 0xb0, 0x96, 0x2f, 0xf9, 0xa4, 0xdf, 0x11,
+ 0xce, 0xcb, 0x14, 0x33, 0xcf, 0xf0, 0xb5, 0xdd, 0xec, 0x8d, 0x16, 0xde,
+ 0x28, 0x0d, 0xb2, 0xb6, 0x53, 0xfc, 0xc6, 0x47, 0x8d, 0x5e, 0xfd, 0xae,
+ 0x9d, 0xfa, 0x54, 0x5d, 0xe5, 0xfe, 0x96, 0xcf, 0x35, 0xa6, 0x31, 0x62,
+ 0xef, 0x79, 0x62, 0xdb, 0x38, 0x88, 0x87, 0x37, 0xf1, 0xcd, 0xff, 0x14,
+ 0x3c, 0xfd, 0xf2, 0x06, 0xb1, 0x66, 0x58, 0xba, 0x3a, 0x58, 0xa9, 0x1a,
+ 0x93, 0x88, 0xdc, 0x30, 0x2c, 0x5d, 0x01, 0x16, 0x2f, 0x16, 0x4e, 0xb1,
+ 0x7d, 0x93, 0x8b, 0x7a, 0xc5, 0xb6, 0x46, 0x8f, 0x8c, 0x63, 0x34, 0x84,
+ 0x03, 0x04, 0x32, 0x18, 0xed, 0x44, 0x67, 0x56, 0x59, 0x98, 0x3e, 0xaf,
+ 0x4d, 0x7d, 0xc3, 0x2d, 0xab, 0xe8, 0x0d, 0x4b, 0x1a, 0x3c, 0x31, 0x3f,
+ 0x18, 0x43, 0xc3, 0xb4, 0x13, 0x9d, 0x05, 0x2a, 0x53, 0x92, 0xe2, 0x7d,
+ 0x0c, 0x00, 0xe3, 0x2f, 0xbf, 0xf1, 0x8e, 0x53, 0xf1, 0x8b, 0xb9, 0x2c,
+ 0x5f, 0xfa, 0x7c, 0x33, 0xf9, 0xcc, 0x62, 0x58, 0xb7, 0x16, 0x2b, 0x0f,
+ 0x44, 0x07, 0xf7, 0xfe, 0x62, 0x2c, 0x37, 0xa1, 0x38, 0xd6, 0x2f, 0xbe,
+ 0xda, 0x92, 0xc5, 0xfb, 0x3e, 0x37, 0x25, 0x8b, 0x9b, 0x67, 0xe9, 0x9e,
+ 0x14, 0x24, 0xb8, 0x43, 0xe3, 0xf0, 0xc8, 0xef, 0xdc, 0xe1, 0xde, 0x4b,
+ 0x17, 0xc1, 0x79, 0x48, 0x2e, 0xb1, 0x7f, 0xfd, 0x05, 0x3f, 0x04, 0xed,
+ 0x2e, 0x7d, 0xe4, 0xb1, 0x5a, 0x3f, 0xcf, 0x96, 0x5f, 0xff, 0xbf, 0x05,
+ 0x3f, 0x04, 0xed, 0x2e, 0x7d, 0xe4, 0xb1, 0x7f, 0xff, 0xff, 0x34, 0x17,
+ 0x89, 0xcd, 0xcf, 0x0b, 0xcd, 0xee, 0x7d, 0xb5, 0x13, 0xbe, 0xba, 0x58,
+ 0xbb, 0xec, 0x34, 0x6f, 0xfd, 0x5a, 0xff, 0xfe, 0x76, 0xf4, 0x6f, 0x2c,
+ 0xe7, 0xde, 0x43, 0xd0, 0x5d, 0x62, 0xee, 0x42, 0xc5, 0xff, 0xdd, 0xf4,
+ 0x27, 0xef, 0xd9, 0x84, 0x6a, 0xc5, 0xe2, 0x7d, 0x98, 0x55, 0x26, 0x38,
+ 0x52, 0xf5, 0x18, 0x0f, 0xcb, 0xb8, 0xc1, 0xe1, 0x7b, 0xfb, 0x63, 0xd8,
+ 0x23, 0xbd, 0x4e, 0xb1, 0x78, 0xe2, 0xdd, 0x58, 0xbf, 0xc6, 0xc1, 0xc6,
+ 0xee, 0x62, 0xc5, 0xe1, 0x39, 0xd6, 0x2f, 0x84, 0x10, 0x70, 0xb1, 0x7e,
+ 0xc0, 0x9e, 0x83, 0x56, 0x2c, 0x11, 0x62, 0xa7, 0x37, 0xf8, 0x57, 0x7d,
+ 0xc6, 0xeb, 0x4b, 0x15, 0x3a, 0x63, 0x8c, 0x43, 0xa3, 0x5f, 0x8e, 0x93,
+ 0x21, 0x84, 0x37, 0xfe, 0xe3, 0x9b, 0xf6, 0x82, 0x14, 0x2c, 0x5f, 0xf3,
+ 0xf9, 0xff, 0xdc, 0xb3, 0xcb, 0x17, 0xe0, 0x3f, 0x05, 0x0b, 0x15, 0xf3,
+ 0xe2, 0xf1, 0xd5, 0x62, 0x30, 0x9a, 0x14, 0x17, 0x38, 0x16, 0x2f, 0xfa,
+ 0x61, 0xbb, 0x99, 0x9d, 0xf9, 0x62, 0xff, 0xff, 0xf1, 0x39, 0x85, 0x9e,
+ 0xf6, 0x4f, 0x04, 0xe6, 0xf0, 0xf1, 0x84, 0x35, 0x8b, 0xd8, 0x1f, 0x16,
+ 0x2b, 0x11, 0xce, 0xc2, 0xfa, 0x3c, 0x08, 0xed, 0x79, 0xa6, 0xe2, 0xc5,
+ 0xfc, 0x50, 0x03, 0xbc, 0x96, 0x2f, 0xe2, 0x80, 0x1d, 0xe4, 0xb1, 0x7f,
+ 0xb6, 0x3d, 0x80, 0xb0, 0x7f, 0x12, 0xc5, 0xfb, 0x37, 0xc1, 0x7b, 0x0f,
+ 0xaf, 0x85, 0xb7, 0xe2, 0x17, 0x3e, 0xdb, 0x51, 0xe9, 0x83, 0xda, 0x84,
+ 0xc5, 0xf8, 0x6d, 0xbf, 0x58, 0xb1, 0x6f, 0xc1, 0xfe, 0x62, 0x95, 0xfe,
+ 0x79, 0x6b, 0x37, 0x18, 0x0b, 0x17, 0xfa, 0x0a, 0x3a, 0xe0, 0x0e, 0xb1,
+ 0x7d, 0x13, 0x7d, 0x96, 0x2f, 0x3b, 0xf4, 0xa8, 0x95, 0xcb, 0xfc, 0x6b,
+ 0x90, 0x3d, 0x9f, 0x58, 0xa9, 0xd1, 0x03, 0xd1, 0x1b, 0x15, 0x5e, 0xfe,
+ 0x74, 0xb1, 0x7d, 0x80, 0x17, 0x16, 0x2e, 0x7e, 0xf0, 0xf0, 0x48, 0x7a,
+ 0xff, 0xff, 0xe3, 0x3c, 0x6b, 0xf3, 0xfd, 0x37, 0x30, 0x7e, 0x90, 0x86,
+ 0xe4, 0x05, 0x8b, 0xf3, 0x9a, 0xfe, 0x92, 0xc5, 0xff, 0xf7, 0x19, 0xfb,
+ 0xfb, 0xb7, 0x85, 0xa7, 0xe2, 0xc5, 0xbb, 0x23, 0xf9, 0xf1, 0x4d, 0xff,
+ 0xdf, 0xc9, 0x75, 0xf6, 0x1c, 0x17, 0x96, 0x2a, 0x13, 0x5c, 0x68, 0x77,
+ 0xf8, 0xa2, 0xa4, 0xac, 0xfc, 0x64, 0xdd, 0x1b, 0x6a, 0x16, 0xa7, 0x72,
+ 0x28, 0xe2, 0x2f, 0xfd, 0x20, 0xe5, 0x85, 0xe9, 0xf0, 0x6b, 0x17, 0xfe,
+ 0xe9, 0xb5, 0x9f, 0x6d, 0x7d, 0xd6, 0x2f, 0xfe, 0x17, 0x3e, 0xf2, 0xf3,
+ 0x39, 0x01, 0x62, 0xbb, 0x44, 0x1e, 0x8f, 0xee, 0xfb, 0x69, 0x1d, 0x1e,
+ 0x86, 0x25, 0xed, 0x37, 0x96, 0x2f, 0xcf, 0x27, 0xee, 0x4b, 0x15, 0x31,
+ 0xe3, 0x68, 0x76, 0xfc, 0x4e, 0x60, 0x67, 0x58, 0xa8, 0x3c, 0xdf, 0x11,
+ 0xdf, 0xd2, 0x86, 0x03, 0x1d, 0x62, 0xfd, 0x13, 0xfb, 0x3e, 0xb1, 0x7f,
+ 0x41, 0xc7, 0xa7, 0xe9, 0x62, 0xbe, 0x7b, 0x04, 0x53, 0x7f, 0xf8, 0xbd,
+ 0xfc, 0x97, 0x7e, 0xd4, 0x61, 0x8b, 0x17, 0xff, 0xff, 0x9c, 0x83, 0x80,
+ 0x64, 0xbf, 0x1b, 0xc7, 0x1b, 0x38, 0x42, 0x96, 0x71, 0x62, 0xa1, 0x18,
+ 0xfa, 0x4c, 0xba, 0x53, 0xac, 0x5e, 0x79, 0x62, 0xc5, 0xe7, 0xdc, 0x35,
+ 0x62, 0xba, 0x37, 0xa0, 0x1c, 0xbf, 0xff, 0xff, 0xff, 0x0d, 0xce, 0x77,
+ 0x94, 0xa0, 0x38, 0x1b, 0x69, 0xfb, 0x1f, 0xe3, 0x5c, 0x67, 0x72, 0x8e,
+ 0xbf, 0x13, 0x2c, 0x5f, 0xc5, 0xe1, 0x7c, 0x2b, 0x0b, 0x17, 0x37, 0xa1,
+ 0x1c, 0x6d, 0x0b, 0x1a, 0xc4, 0xcd, 0x9e, 0x30, 0x5b, 0xff, 0xff, 0xf0,
+ 0x4c, 0xd3, 0x4e, 0xe7, 0xeb, 0xed, 0xf6, 0x82, 0xf7, 0xdf, 0xa8, 0x21,
+ 0xac, 0x5f, 0x81, 0xad, 0x34, 0xeb, 0x14, 0xe8, 0xaf, 0x28, 0x42, 0xdf,
+ 0xec, 0xd7, 0x1f, 0xa1, 0x76, 0xb1, 0x7f, 0xfb, 0x5e, 0xf3, 0xce, 0x19,
+ 0xc7, 0xf6, 0x35, 0x62, 0xff, 0xd3, 0xc4, 0xe5, 0x9e, 0xf6, 0x4e, 0xb1,
+ 0x77, 0x7c, 0xc4, 0x48, 0x06, 0x9f, 0x58, 0x8f, 0x67, 0x86, 0x35, 0xfe,
+ 0xef, 0x1b, 0x9c, 0x14, 0x2c, 0x58, 0x4b, 0x17, 0xde, 0x6c, 0xd2, 0xc5,
+ 0xe7, 0x90, 0x51, 0x62, 0xa7, 0x3d, 0x5f, 0x89, 0x6f, 0x22, 0xbf, 0xec,
+ 0x6d, 0xe5, 0x19, 0xa9, 0x2c, 0x5f, 0xff, 0xbd, 0x2c, 0xdd, 0x72, 0x07,
+ 0x7e, 0xd4, 0x61, 0x8b, 0x06, 0x1b, 0x9b, 0xef, 0x7e, 0x00, 0xb1, 0x60,
+ 0x2c, 0x57, 0x66, 0xd7, 0x44, 0x75, 0x89, 0x96, 0xbb, 0x58, 0xa1, 0x41,
+ 0x7f, 0xff, 0xb0, 0x6d, 0xd7, 0xd8, 0x63, 0xc3, 0x03, 0x9b, 0xe2, 0x35,
+ 0x62, 0xff, 0xf4, 0xc5, 0x1e, 0xe7, 0xbb, 0xe9, 0x8a, 0x75, 0x8b, 0xfe,
+ 0x73, 0x07, 0xf8, 0x9f, 0x0c, 0x58, 0xa6, 0x44, 0x51, 0x27, 0x5f, 0xff,
+ 0x30, 0x30, 0xed, 0xee, 0x41, 0xdf, 0xbf, 0x2c, 0x5f, 0xff, 0xdb, 0xf0,
+ 0x7a, 0x81, 0x71, 0xb7, 0xbb, 0x0c, 0x50, 0xb1, 0x58, 0x8a, 0xe6, 0x50,
+ 0xbf, 0xff, 0xdd, 0x3e, 0x9f, 0xfd, 0xcb, 0x3d, 0x9e, 0x81, 0x05, 0xf1,
+ 0x62, 0xff, 0xe7, 0xee, 0x4d, 0xef, 0xc6, 0xbd, 0x0b, 0x17, 0xfd, 0x07,
+ 0xf6, 0x4d, 0x26, 0xf2, 0xc5, 0x49, 0x30, 0x66, 0x21, 0x3b, 0x37, 0x91,
+ 0x6f, 0xff, 0xf7, 0xd8, 0x63, 0xc3, 0x3b, 0xf0, 0x9f, 0x9f, 0x31, 0xc6,
+ 0xb1, 0x7c, 0x27, 0xd4, 0x96, 0x2f, 0xe2, 0x89, 0xc0, 0xfe, 0x58, 0xbf,
+ 0xce, 0x30, 0xc2, 0x41, 0x49, 0x62, 0xd1, 0xd1, 0xf2, 0x1c, 0xba, 0xff,
+ 0xf8, 0xee, 0x40, 0xf9, 0x8e, 0x53, 0xf4, 0xd3, 0xac, 0x5f, 0xff, 0xda,
+ 0x7e, 0x61, 0x46, 0x03, 0x99, 0x34, 0x77, 0xc5, 0x8b, 0x9b, 0xce, 0x8a,
+ 0xe1, 0x29, 0xd0, 0xd3, 0x8a, 0x68, 0x43, 0xbc, 0x35, 0xaf, 0xf8, 0x40,
+ 0x3b, 0xcb, 0x9a, 0x1a, 0xc5, 0xff, 0xfe, 0xc6, 0x2f, 0x61, 0x6d, 0x27,
+ 0x1c, 0x14, 0xf1, 0xa5, 0x8a, 0xf2, 0x26, 0xb7, 0x9d, 0xdb, 0x4b, 0x17,
+ 0xff, 0xee, 0xfc, 0x51, 0xf7, 0xe6, 0x74, 0x4f, 0x9d, 0x2c, 0x56, 0x22,
+ 0x37, 0xa2, 0x51, 0x09, 0x5f, 0xff, 0xfe, 0xfe, 0x1c, 0x0f, 0xac, 0xdf,
+ 0x83, 0xce, 0x09, 0xfb, 0xf9, 0x8f, 0xe5, 0x8b, 0xfd, 0x1f, 0x6f, 0x71,
+ 0xfb, 0x58, 0xbf, 0xf6, 0x77, 0xef, 0x41, 0xff, 0x93, 0xac, 0x5f, 0xf4,
+ 0xdd, 0x7d, 0x8f, 0x1a, 0x35, 0x62, 0xff, 0x03, 0x35, 0x99, 0xee, 0x2c,
+ 0x5f, 0x4f, 0xec, 0xe9, 0x62, 0xb1, 0x12, 0xbd, 0x9e, 0xe8, 0xce, 0xa1,
+ 0x90, 0x6e, 0x38, 0x78, 0xe4, 0x7a, 0xbd, 0x1e, 0xfe, 0x3e, 0xf2, 0x8d,
+ 0x83, 0xc6, 0x02, 0x7b, 0x30, 0xd0, 0x38, 0x6b, 0x5e, 0xc0, 0x3a, 0xc5,
+ 0xed, 0x67, 0x6b, 0x17, 0xbe, 0xf2, 0xf9, 0xba, 0x00, 0xe5, 0xff, 0xce,
+ 0xde, 0x82, 0xe9, 0x8e, 0x76, 0x58, 0xbe, 0xfc, 0x17, 0x96, 0x2e, 0x61,
+ 0xfc, 0xf9, 0x78, 0x87, 0x6c, 0xfa, 0x31, 0x0a, 0x12, 0xf7, 0xfd, 0x9d,
+ 0xf0, 0x70, 0xe5, 0x3a, 0xc5, 0xfe, 0x7e, 0x41, 0x7b, 0xec, 0xb1, 0x7e,
+ 0x3c, 0xdc, 0x62, 0x58, 0xbf, 0xfb, 0xa6, 0xd7, 0xf2, 0x6f, 0xb6, 0xa7,
+ 0x58, 0xbf, 0xf9, 0xc1, 0x85, 0xdf, 0xb5, 0x18, 0x62, 0xc5, 0xff, 0x3c,
+ 0xb9, 0xf8, 0xd0, 0x63, 0x58, 0xa9, 0x27, 0x13, 0x85, 0x86, 0x9d, 0x74,
+ 0x65, 0xd9, 0x49, 0x24, 0x79, 0x16, 0xfc, 0x09, 0x98, 0x41, 0x75, 0x8b,
+ 0xff, 0xfd, 0xfc, 0xe8, 0xb0, 0xf8, 0x59, 0xe1, 0x00, 0xef, 0x25, 0x8b,
+ 0xfb, 0xee, 0x72, 0x8e, 0xd6, 0x2f, 0xfc, 0x59, 0xfc, 0x9a, 0x4d, 0xa9,
+ 0x2c, 0x5f, 0xff, 0xff, 0x02, 0x0b, 0xa7, 0xf3, 0xf6, 0x0c, 0xde, 0xde,
+ 0x97, 0xdb, 0xdc, 0x61, 0xac, 0x5f, 0xec, 0x10, 0x5f, 0xf8, 0x07, 0x58,
+ 0xbf, 0xe8, 0xcf, 0x16, 0x03, 0x73, 0x16, 0x2f, 0xfc, 0xdb, 0xdb, 0xd3,
+ 0x4a, 0x0b, 0xcb, 0x15, 0x0a, 0x8b, 0x64, 0x5d, 0x8c, 0x1d, 0x17, 0x76,
+ 0x7e, 0x50, 0x80, 0xe1, 0xbf, 0x8e, 0xaf, 0xff, 0x3e, 0x4b, 0xf8, 0xc5,
+ 0x80, 0xdc, 0xc5, 0x8b, 0xcf, 0x2d, 0x9d, 0x81, 0xd0, 0x3c, 0x44, 0x6a,
+ 0xf2, 0x8c, 0x68, 0x71, 0x86, 0xe4, 0xe7, 0x67, 0x51, 0xa6, 0x77, 0x0c,
+ 0x66, 0x21, 0x9a, 0x10, 0xba, 0x87, 0x41, 0xc8, 0xbf, 0x1c, 0x63, 0xc3,
+ 0x5c, 0x11, 0x8e, 0x05, 0xc9, 0x8a, 0x3b, 0x6e, 0x52, 0x1a, 0xfd, 0x2c,
+ 0xc8, 0x39, 0x52, 0x61, 0x1d, 0xee, 0x0b, 0xe2, 0xc5, 0xfb, 0xd0, 0x20,
+ 0xbe, 0x2c, 0x5f, 0xf4, 0xb3, 0xdf, 0x68, 0xd0, 0x16, 0x2f, 0xba, 0x79,
+ 0x62, 0xc5, 0x80, 0xb1, 0x58, 0x6d, 0x58, 0x8e, 0xff, 0x60, 0xd8, 0xbd,
+ 0x9f, 0x58, 0xbf, 0xff, 0x87, 0xf8, 0x29, 0xf8, 0x27, 0x69, 0x73, 0xef,
+ 0x25, 0x8b, 0xd9, 0xfd, 0x90, 0xb1, 0x36, 0x2c, 0x1b, 0xec, 0xb3, 0xed,
+ 0xc4, 0x3f, 0xc3, 0x2b, 0xff, 0xff, 0xe1, 0xe6, 0xcf, 0x24, 0xdf, 0x8e,
+ 0xe5, 0x87, 0xcd, 0xed, 0xe0, 0x40, 0xe1, 0x62, 0xf3, 0x43, 0xac, 0x5e,
+ 0xf4, 0x0d, 0x22, 0xff, 0xf7, 0xdd, 0xbd, 0x12, 0x6d, 0x4e, 0x20, 0x24,
+ 0x5e, 0xd0, 0x5f, 0x66, 0x0f, 0xa3, 0x83, 0xb7, 0x9f, 0xad, 0x99, 0x22,
+ 0xf4, 0x70, 0x83, 0xb6, 0xc8, 0xdd, 0x45, 0xe7, 0x52, 0xbc, 0x4f, 0x68,
+ 0x3b, 0xfd, 0x2b, 0xc0, 0x4e, 0x1b, 0xe3, 0x3f, 0xbf, 0xfd, 0xb2, 0x77,
+ 0x96, 0xce, 0x6b, 0xa7, 0x7e, 0x95, 0x13, 0x09, 0x7d, 0x0c, 0x1f, 0xd6,
+ 0x2f, 0xf7, 0xe0, 0x9c, 0xf0, 0x11, 0x62, 0xf3, 0x07, 0xf5, 0x8b, 0xff,
+ 0xfb, 0x37, 0xb8, 0xff, 0x1b, 0x3e, 0xfe, 0x0c, 0x5e, 0xe2, 0xc5, 0xff,
+ 0xed, 0x38, 0x36, 0x4d, 0xf4, 0x8c, 0x8e, 0x49, 0x62, 0xec, 0xd9, 0x1a,
+ 0x64, 0xee, 0x46, 0x03, 0x42, 0x1e, 0x0d, 0x86, 0xe0, 0xa6, 0xc3, 0x58,
+ 0xb6, 0xf5, 0x8a, 0x0a, 0x9b, 0x63, 0x91, 0x5f, 0x9b, 0xff, 0xc9, 0xd6,
+ 0x2f, 0x6c, 0x5f, 0x1a, 0xc5, 0xfa, 0x41, 0xca, 0x34, 0xb1, 0x7f, 0xf0,
+ 0x57, 0x3b, 0x90, 0x9f, 0xc5, 0x12, 0x58, 0xbe, 0xd8, 0x59, 0x23, 0xac,
+ 0x5f, 0xb6, 0x0d, 0x80, 0x29, 0xb9, 0xb1, 0xac, 0x5d, 0xe0, 0xb1, 0x62,
+ 0xee, 0xf7, 0x56, 0x2f, 0xdf, 0x63, 0xc7, 0x4b, 0x17, 0x61, 0xf6, 0x9e,
+ 0x2f, 0x43, 0x97, 0xf4, 0x1f, 0x01, 0x1b, 0xd6, 0x2f, 0xff, 0x7b, 0x82,
+ 0x8d, 0xbd, 0x7d, 0xb7, 0x1e, 0x75, 0x8a, 0x1a, 0x2c, 0x7e, 0x60, 0x45,
+ 0xf7, 0xfb, 0x59, 0xd4, 0x00, 0x33, 0xac, 0x5f, 0xbc, 0xf3, 0xbf, 0x16,
+ 0x2f, 0xa0, 0xed, 0xa5, 0x8b, 0x44, 0xc7, 0x97, 0xa2, 0x9b, 0xe1, 0x07,
+ 0x93, 0xac, 0x5f, 0x41, 0x34, 0xcb, 0x17, 0xff, 0xec, 0x9f, 0x6e, 0x61,
+ 0x7b, 0xee, 0xdc, 0x6d, 0xeb, 0x17, 0xef, 0xc0, 0xd8, 0xd5, 0x8a, 0x64,
+ 0xe8, 0x34, 0x5e, 0x78, 0x40, 0xfc, 0xa0, 0x89, 0x7c, 0x44, 0x11, 0x62,
+ 0xff, 0xb0, 0xcf, 0xb7, 0xb8, 0xfa, 0x58, 0xbe, 0x1f, 0x50, 0x75, 0x8b,
+ 0xc1, 0xf0, 0x96, 0x29, 0x8f, 0x0b, 0xe4, 0x97, 0xf9, 0xf5, 0x84, 0x15,
+ 0x33, 0xa5, 0x8b, 0xb6, 0x3f, 0x2c, 0x5f, 0x4c, 0xc6, 0x4c, 0xb1, 0x7f,
+ 0xa0, 0xed, 0xf8, 0xc2, 0x58, 0xb9, 0xf8, 0xb1, 0x47, 0x3e, 0xef, 0x13,
+ 0x6f, 0x31, 0xbf, 0xbd, 0x1b, 0xc9, 0xfb, 0x58, 0xbf, 0x17, 0x4c, 0x58,
+ 0xb1, 0x7f, 0x14, 0xfe, 0xc6, 0x1a, 0xc5, 0xff, 0xb8, 0x3d, 0x13, 0x99,
+ 0x9d, 0xf9, 0x62, 0xff, 0x18, 0x59, 0xdf, 0xb3, 0xeb, 0x15, 0x08, 0xa4,
+ 0xc2, 0xe6, 0x41, 0xbf, 0xd0, 0xf3, 0xf8, 0xd7, 0xd2, 0xc5, 0xf9, 0xf5,
+ 0x27, 0x3a, 0xc5, 0x42, 0xa7, 0xa1, 0x9c, 0xe4, 0x22, 0xfb, 0x31, 0x63,
+ 0x0f, 0xc3, 0x2c, 0x8b, 0x44, 0x6b, 0x63, 0xac, 0x5f, 0xef, 0x7d, 0xdb,
+ 0x8d, 0xbd, 0x62, 0xdb, 0x1a, 0xc5, 0x11, 0xe6, 0x6e, 0x1a, 0xdf, 0xee,
+ 0x46, 0x10, 0xff, 0x0b, 0x17, 0xf4, 0x61, 0x0f, 0xf0, 0xb1, 0x78, 0x5a,
+ 0x9b, 0x69, 0xef, 0x70, 0xca, 0xef, 0xee, 0xac, 0x5f, 0xf8, 0xd7, 0x98,
+ 0x7a, 0xc2, 0xc3, 0x16, 0x2a, 0x47, 0xb8, 0x68, 0xdd, 0xf7, 0x45, 0x1f,
+ 0x58, 0xbf, 0xc6, 0x6d, 0xc1, 0xfe, 0x37, 0xac, 0x5f, 0xf8, 0x58, 0x6e,
+ 0x78, 0x51, 0xd8, 0xd6, 0x2a, 0x0f, 0xe9, 0x8e, 0x6f, 0xf1, 0x0b, 0xd9,
+ 0xe0, 0xe7, 0x58, 0xac, 0x47, 0x9e, 0xa1, 0x3b, 0xe2, 0x0b, 0xb0, 0xc5,
+ 0x8b, 0xfe, 0x1e, 0x4b, 0xf1, 0xbc, 0x70, 0xb1, 0x76, 0xf9, 0xd6, 0x2f,
+ 0x6b, 0xef, 0xb4, 0xf5, 0x98, 0xee, 0xff, 0xc3, 0x7f, 0xc3, 0xb6, 0xb3,
+ 0xb5, 0x8a, 0x63, 0xf2, 0x0c, 0xd2, 0xff, 0x8c, 0x0f, 0xf1, 0xd7, 0xda,
+ 0x65, 0x8b, 0xe1, 0x1f, 0x06, 0xb1, 0x5d, 0x9f, 0x08, 0x43, 0xeb, 0xfc,
+ 0x7e, 0x36, 0x6f, 0x7d, 0x2c, 0x5f, 0xff, 0xf7, 0xf2, 0x59, 0x2f, 0xe1,
+ 0x61, 0xbf, 0x79, 0x64, 0x8e, 0xb1, 0x58, 0x8c, 0x07, 0x25, 0xf1, 0xad,
+ 0xf7, 0x03, 0x89, 0xd6, 0x2f, 0xda, 0x89, 0x73, 0x16, 0x2f, 0x9b, 0xd9,
+ 0xbd, 0x62, 0xff, 0x61, 0x9e, 0x27, 0x07, 0x16, 0x2a, 0x11, 0x01, 0xf2,
+ 0x8f, 0x12, 0x5f, 0xff, 0xf7, 0x4f, 0xa8, 0xf4, 0x4b, 0x68, 0x7e, 0x2c,
+ 0x03, 0x90, 0x16, 0x2f, 0x7d, 0xe4, 0xb1, 0x52, 0x5e, 0x68, 0xc5, 0xee,
+ 0xa1, 0x04, 0xd0, 0x93, 0xd4, 0x62, 0xc7, 0x34, 0xfc, 0x38, 0x0a, 0x34,
+ 0x3e, 0x17, 0x7a, 0x14, 0xa2, 0x2f, 0xde, 0xd3, 0x7f, 0xee, 0x7e, 0x0f,
+ 0xee, 0x13, 0xf6, 0xb1, 0x7c, 0x42, 0xd4, 0x2c, 0x59, 0xfb, 0x3e, 0x27,
+ 0x40, 0xbf, 0xfe, 0x82, 0xf6, 0xa1, 0xa4, 0x58, 0x77, 0x92, 0xc5, 0xff,
+ 0x10, 0xb8, 0x58, 0x6c, 0x71, 0x62, 0xfc, 0x73, 0xe0, 0xa6, 0x58, 0xbf,
+ 0xfd, 0x1d, 0x70, 0x5e, 0x6f, 0xb1, 0xbf, 0x65, 0x8b, 0xf8, 0xf1, 0x85,
+ 0xed, 0xc5, 0x8b, 0xed, 0x37, 0x72, 0x58, 0xb7, 0x16, 0x2f, 0xd1, 0x85,
+ 0xed, 0xc5, 0x8b, 0xdc, 0x7e, 0xf6, 0xa2, 0x41, 0x8c, 0x26, 0x24, 0x38,
+ 0x95, 0x0d, 0x3d, 0xd3, 0x53, 0x74, 0x72, 0x72, 0xaf, 0x43, 0x72, 0xff,
+ 0xb7, 0x70, 0x7f, 0x8d, 0xd2, 0x85, 0x8a, 0x64, 0x47, 0xba, 0x8d, 0xff,
+ 0x6a, 0x7e, 0xbe, 0xdf, 0x17, 0x96, 0x2b, 0xe7, 0xbc, 0xe4, 0x37, 0xf9,
+ 0x8d, 0xd6, 0x4f, 0x13, 0xac, 0x5f, 0xa0, 0xfb, 0xc1, 0x25, 0x8a, 0xe1,
+ 0xf0, 0xf8, 0xda, 0xef, 0x32, 0xc5, 0xc2, 0xc5, 0x8b, 0xb5, 0xc5, 0x8a,
+ 0x91, 0xf4, 0x1a, 0x44, 0x01, 0x7d, 0xc1, 0x7b, 0xff, 0xe1, 0x6a, 0x3a,
+ 0x33, 0x1b, 0xfd, 0x34, 0xe1, 0x16, 0x2f, 0x43, 0x74, 0xb1, 0x52, 0x3f,
+ 0x39, 0x95, 0xaf, 0xa3, 0x59, 0x3a, 0xc5, 0xed, 0x46, 0xf5, 0x8b, 0xa3,
+ 0xcb, 0x15, 0x06, 0xdb, 0x43, 0xf7, 0xee, 0x9b, 0x9f, 0x65, 0x8b, 0xfb,
+ 0x18, 0xbc, 0x2f, 0xac, 0x57, 0x67, 0xad, 0xf2, 0x9b, 0xf7, 0x44, 0xdd,
+ 0xc9, 0x62, 0xe0, 0xfe, 0xb1, 0x53, 0x26, 0xb1, 0xf2, 0x3e, 0x2c, 0xf9,
+ 0xd8, 0x44, 0x7b, 0x85, 0x57, 0x8f, 0xb7, 0x16, 0x2f, 0xed, 0x63, 0x7e,
+ 0x06, 0xb1, 0x7d, 0xd7, 0xb3, 0xa5, 0x8b, 0x85, 0xc5, 0x8a, 0xc3, 0x7b,
+ 0xa2, 0x5b, 0xe8, 0x29, 0xba, 0x58, 0xbf, 0xfd, 0x05, 0x9e, 0xfe, 0x7b,
+ 0xf0, 0x20, 0xba, 0xc5, 0x68, 0xfc, 0x7e, 0x49, 0x7f, 0x36, 0xb6, 0xb9,
+ 0x01, 0x62, 0xf7, 0xf3, 0xb5, 0x8b, 0xff, 0xfc, 0x60, 0x4f, 0x67, 0xf6,
+ 0x96, 0x4e, 0xd8, 0x5d, 0xcb, 0x8b, 0x17, 0xe3, 0x3d, 0x9f, 0xe9, 0x62,
+ 0xb1, 0x12, 0x4e, 0xcf, 0x50, 0xa8, 0xf0, 0x63, 0xf8, 0xd4, 0xd0, 0x91,
+ 0xf9, 0x13, 0x97, 0x94, 0x2c, 0x2f, 0xfb, 0xa6, 0x1f, 0xb3, 0xe5, 0x0b,
+ 0x17, 0xfe, 0x70, 0x7f, 0x18, 0x62, 0xf7, 0x16, 0x2d, 0xe6, 0x3f, 0x82,
+ 0x39, 0xbe, 0xdf, 0x83, 0x85, 0x8b, 0xf3, 0xcd, 0xc0, 0xf7, 0xac, 0x5f,
+ 0x08, 0x7f, 0x85, 0x8a, 0x91, 0xe8, 0x11, 0x6d, 0xf4, 0xb2, 0x3b, 0x58,
+ 0xbf, 0xe8, 0x9c, 0x39, 0x7c, 0x4f, 0x3a, 0xc5, 0xff, 0x8b, 0xdf, 0x79,
+ 0x6d, 0xe7, 0xc6, 0xb1, 0x7a, 0x3b, 0x92, 0xc5, 0x42, 0x6f, 0x78, 0x4c,
+ 0xce, 0x93, 0x10, 0xe8, 0x8d, 0xcf, 0x49, 0x0a, 0xff, 0x4d, 0xc7, 0x29,
+ 0x98, 0xeb, 0x17, 0xfd, 0x2d, 0xbf, 0x7e, 0xa0, 0x86, 0xb1, 0x58, 0x7e,
+ 0x3d, 0x9a, 0xdf, 0xc4, 0xc0, 0x3c, 0x6f, 0x58, 0xbd, 0xa0, 0x1d, 0x62,
+ 0x98, 0xf3, 0x44, 0x5f, 0x7e, 0x27, 0xe8, 0xb1, 0x62, 0xfe, 0x96, 0x7f,
+ 0xef, 0x25, 0x8a, 0x63, 0xd5, 0xf1, 0x3d, 0x62, 0x60, 0xdc, 0x6f, 0x13,
+ 0xb5, 0xf1, 0x63, 0x1a, 0xb1, 0x7c, 0xd1, 0xdf, 0x16, 0x2f, 0xc1, 0xf8,
+ 0xa0, 0x0b, 0x14, 0x73, 0xee, 0xf1, 0x16, 0xf2, 0x3b, 0xc1, 0xb9, 0xd6,
+ 0x2f, 0xfe, 0x1e, 0x9b, 0xb9, 0x16, 0x1b, 0x1c, 0x58, 0xbd, 0xec, 0x31,
+ 0x62, 0xb4, 0x88, 0x22, 0x1e, 0xf2, 0x35, 0xff, 0xcd, 0xcc, 0x1f, 0xe0,
+ 0xf3, 0xe1, 0x8b, 0x17, 0xff, 0x78, 0x11, 0x2c, 0xef, 0xd3, 0x88, 0xc5,
+ 0x8b, 0xfc, 0x58, 0x73, 0xe0, 0xa6, 0x58, 0xa8, 0x3f, 0xdd, 0x24, 0xdf,
+ 0xa0, 0xfa, 0x79, 0x96, 0x2f, 0x9b, 0x4f, 0xa5, 0x8b, 0xff, 0xde, 0x96,
+ 0x6b, 0x39, 0x0c, 0x3c, 0x3a, 0xc5, 0xfe, 0x6f, 0xb0, 0x9d, 0xbe, 0xb1,
+ 0x52, 0x44, 0xeb, 0x11, 0x7d, 0x26, 0xf7, 0x1c, 0x0b, 0x15, 0x0a, 0xb6,
+ 0x32, 0x16, 0x7d, 0x17, 0xb4, 0x30, 0xfe, 0x42, 0xf0, 0xc6, 0xf1, 0x7d,
+ 0x2c, 0x5f, 0x41, 0xda, 0x4b, 0x17, 0x7e, 0x24, 0x6b, 0xb4, 0x19, 0x7a,
+ 0x08, 0xd5, 0x8b, 0x9e, 0x4b, 0x17, 0x9f, 0x98, 0xb1, 0x7e, 0x8e, 0x89,
+ 0xce, 0xb1, 0x7f, 0xe8, 0x96, 0xdc, 0xfb, 0x6b, 0xee, 0xb1, 0x66, 0xf9,
+ 0xf4, 0x70, 0xa2, 0xf7, 0xe3, 0xeb, 0x14, 0x34, 0xca, 0x3b, 0x2c, 0xdd,
+ 0x1d, 0x98, 0x5f, 0xf0, 0x84, 0xf1, 0x3d, 0xc2, 0x9d, 0x62, 0xfb, 0x35,
+ 0x1d, 0x2c, 0x5d, 0x37, 0x06, 0x6f, 0x3e, 0x33, 0x7f, 0x7b, 0x51, 0xd6,
+ 0x69, 0x62, 0xff, 0xff, 0xf4, 0x7f, 0xef, 0xcd, 0xbf, 0x76, 0xe7, 0xf0,
+ 0x1b, 0x75, 0x9e, 0x7e, 0xd6, 0x2f, 0xfd, 0xdf, 0x3a, 0xfb, 0x0d, 0xb5,
+ 0xd2, 0xc5, 0xfc, 0xe0, 0xd6, 0x9b, 0x4b, 0x17, 0xbd, 0xb7, 0x16, 0x2a,
+ 0x13, 0x69, 0x62, 0xed, 0x17, 0xbb, 0xe0, 0x10, 0xc3, 0x2e, 0xbd, 0x8c,
+ 0x05, 0x8b, 0xff, 0xef, 0x73, 0x59, 0xbe, 0x0b, 0xce, 0x42, 0xc5, 0x8b,
+ 0xef, 0x8b, 0xbf, 0x2c, 0x5f, 0xfd, 0xfc, 0x8d, 0x16, 0x1c, 0xe2, 0x99,
+ 0x62, 0xfe, 0xf0, 0x60, 0x04, 0x76, 0xb1, 0x7f, 0xcd, 0xe6, 0xc3, 0x96,
+ 0x4e, 0xb1, 0x4c, 0x7d, 0x3f, 0x31, 0xbf, 0xb8, 0xc6, 0x9d, 0xfc, 0xb1,
+ 0x7f, 0xed, 0xf0, 0x6c, 0x98, 0xa3, 0x50, 0xb1, 0x7f, 0xff, 0xed, 0x66,
+ 0xf8, 0x2f, 0x6d, 0x0c, 0xa3, 0xee, 0xde, 0x8f, 0x71, 0x62, 0xff, 0xdf,
+ 0x67, 0x06, 0xdd, 0x68, 0x5f, 0x58, 0xbb, 0xad, 0x89, 0x62, 0xf8, 0x9f,
+ 0xe6, 0xac, 0x5e, 0x9c, 0x52, 0x58, 0xbc, 0x59, 0xcd, 0xa7, 0xc0, 0x31,
+ 0xec, 0x23, 0xbe, 0x70, 0x48, 0x6b, 0x17, 0xfa, 0x0f, 0xd1, 0x3e, 0x74,
+ 0xb1, 0x43, 0x55, 0xcd, 0xd4, 0x2b, 0xbb, 0x21, 0x62, 0xfd, 0x20, 0x79,
+ 0xbf, 0x7c, 0x28, 0x8c, 0x40, 0x0c, 0x8e, 0xfb, 0x6e, 0xf0, 0x93, 0xac,
+ 0x54, 0x2e, 0x0a, 0x8d, 0x43, 0x25, 0x85, 0x9b, 0x08, 0xfb, 0x6e, 0xac,
+ 0x5b, 0x75, 0x62, 0xf6, 0x0f, 0xcb, 0x14, 0xc6, 0xcb, 0x42, 0xb7, 0xe7,
+ 0x99, 0xbd, 0xc5, 0x8a, 0x39, 0xe4, 0xfc, 0x82, 0xfd, 0x1b, 0xde, 0x69,
+ 0x96, 0x2f, 0x16, 0x76, 0xb1, 0x77, 0xb1, 0x62, 0xff, 0xcd, 0xbf, 0x07,
+ 0xfc, 0xeb, 0x09, 0x62, 0xff, 0x41, 0x40, 0x1d, 0xc2, 0x2c, 0x5e, 0xd3,
+ 0xc9, 0x62, 0xff, 0x0f, 0xf9, 0xd7, 0xe3, 0x4b, 0x14, 0x34, 0x42, 0xe8,
+ 0xcc, 0x87, 0x6f, 0xdc, 0xcf, 0x6a, 0x16, 0x2f, 0xff, 0x05, 0xca, 0x0e,
+ 0xed, 0xf7, 0xf7, 0xe1, 0x62, 0xa1, 0x37, 0xf9, 0x0b, 0xb4, 0x31, 0x78,
+ 0x5e, 0x22, 0x8b, 0x9f, 0xa5, 0x8b, 0xf9, 0xa6, 0x7e, 0xb9, 0x25, 0x8b,
+ 0xff, 0xfe, 0x18, 0xf3, 0x72, 0x35, 0x84, 0x3f, 0xc0, 0x60, 0x04, 0x76,
+ 0xb1, 0x5d, 0x22, 0xcf, 0xe3, 0x0e, 0x61, 0x7f, 0xfb, 0x50, 0xc5, 0x9e,
+ 0xe4, 0x7d, 0xce, 0xb1, 0x7f, 0xff, 0xbe, 0xc4, 0x3d, 0x67, 0x5f, 0x8f,
+ 0xe6, 0xb5, 0x06, 0xac, 0x5f, 0x84, 0x11, 0xb0, 0xeb, 0x17, 0xec, 0xf7,
+ 0xa2, 0x65, 0x8b, 0xf7, 0x9c, 0xed, 0xe5, 0x8a, 0x34, 0xfe, 0xf4, 0x54,
+ 0x45, 0x34, 0xb1, 0x7d, 0x19, 0x27, 0x58, 0xa3, 0x9a, 0xdf, 0x86, 0x5f,
+ 0xf9, 0xbc, 0x2d, 0x3f, 0x36, 0x9f, 0xcb, 0x15, 0x08, 0xbf, 0x1a, 0xe3,
+ 0x90, 0xdf, 0xe6, 0xc3, 0x96, 0x4e, 0xeb, 0x17, 0xfb, 0x8d, 0xbc, 0x70,
+ 0x09, 0xd6, 0x2b, 0x0f, 0xa5, 0xcc, 0xaf, 0xbd, 0xc0, 0x09, 0x62, 0xf3,
+ 0x1f, 0xcb, 0x17, 0x88, 0x3f, 0x2c, 0x5f, 0x84, 0x37, 0x20, 0x6d, 0x37,
+ 0x6e, 0x3b, 0x7f, 0x03, 0x50, 0x20, 0xbe, 0x2c, 0x5f, 0xda, 0x83, 0x1f,
+ 0xfc, 0x58, 0xbf, 0x81, 0xc6, 0x99, 0x8c, 0x58, 0xa8, 0x44, 0x8e, 0x19,
+ 0x39, 0x7d, 0x42, 0x6b, 0x72, 0x5f, 0x28, 0x67, 0xdf, 0xdf, 0x6f, 0x14,
+ 0x1d, 0x62, 0xfa, 0x37, 0x94, 0x2c, 0x5e, 0x79, 0x62, 0xc5, 0x4c, 0x7d,
+ 0x87, 0x2d, 0x22, 0x3a, 0xd8, 0xd9, 0x0e, 0x11, 0x09, 0x09, 0x11, 0x0c,
+ 0xb3, 0x23, 0x9c, 0xea, 0x30, 0x16, 0x30, 0x99, 0x23, 0xf1, 0xce, 0x14,
+ 0x25, 0xfd, 0x1b, 0xd8, 0xa1, 0x41, 0x7f, 0xb5, 0x1c, 0x34, 0x0f, 0x32,
+ 0xc5, 0xff, 0xf3, 0x9c, 0x7f, 0x8f, 0xc1, 0xc5, 0xdc, 0xb8, 0xb1, 0x7f,
+ 0xfb, 0x3d, 0xf6, 0xce, 0xfd, 0x9b, 0xe3, 0x8b, 0x16, 0xff, 0xd1, 0x3c,
+ 0x4a, 0x57, 0xcf, 0xcf, 0x4e, 0xb1, 0x7e, 0x67, 0x06, 0xdf, 0x2c, 0x5f,
+ 0xfc, 0xe5, 0xf8, 0x61, 0xb7, 0x32, 0x4b, 0x17, 0x3b, 0x2c, 0x58, 0x35,
+ 0x8a, 0x63, 0x52, 0x01, 0x6b, 0xf8, 0x1c, 0xfc, 0x17, 0x96, 0x2a, 0x0f,
+ 0x39, 0xc8, 0x2f, 0xec, 0xdf, 0xf6, 0x04, 0xcb, 0x15, 0x0a, 0x95, 0x32,
+ 0x1a, 0x86, 0x94, 0x7c, 0x91, 0xca, 0x8a, 0x17, 0x3c, 0x20, 0xb8, 0xa1,
+ 0x62, 0xfb, 0xf1, 0xc8, 0x58, 0xbc, 0x18, 0xf1, 0x62, 0xf0, 0x5f, 0x9b,
+ 0x12, 0xc5, 0x4e, 0x7f, 0xa3, 0x16, 0x72, 0x2e, 0x0f, 0x5e, 0xe3, 0x71,
+ 0x62, 0xfb, 0x69, 0xf6, 0xf4, 0xb1, 0x7f, 0x4f, 0x34, 0xb6, 0x2d, 0x4e,
+ 0xb1, 0x7b, 0x3a, 0x1a, 0xc5, 0xf7, 0xb0, 0x80, 0xb1, 0x7f, 0x39, 0x91,
+ 0xec, 0x9d, 0x62, 0xfe, 0xcd, 0x6a, 0x20, 0x6b, 0x15, 0xb1, 0xa3, 0x53,
+ 0x0e, 0x18, 0x78, 0x88, 0xb7, 0x0b, 0xef, 0xfe, 0x9f, 0xf8, 0x31, 0xb7,
+ 0x79, 0xdf, 0x96, 0x2f, 0xa7, 0x0c, 0x53, 0xac, 0x5f, 0x4d, 0x28, 0x9d,
+ 0x62, 0xa0, 0xf3, 0x30, 0x9e, 0xf7, 0xdc, 0xd5, 0x8b, 0xfc, 0x53, 0x96,
+ 0x0a, 0x38, 0xb1, 0x4b, 0x17, 0xc0, 0x0c, 0xa4, 0xb1, 0x66, 0x83, 0x61,
+ 0xe0, 0xcb, 0xe2, 0xcf, 0xe2, 0xc5, 0xf1, 0x93, 0x72, 0x16, 0x2f, 0x41,
+ 0xf1, 0x62, 0xe0, 0x42, 0xc5, 0x31, 0xb3, 0x00, 0xe5, 0xf1, 0x43, 0xf4,
+ 0xb1, 0x7e, 0x83, 0x73, 0xdc, 0x58, 0xbf, 0xff, 0xb0, 0x98, 0x7c, 0xce,
+ 0x73, 0x3e, 0xdc, 0x14, 0xeb, 0x17, 0xf0, 0xf4, 0xfe, 0xf8, 0x96, 0x2e,
+ 0x7f, 0x49, 0x11, 0x5c, 0x5b, 0xbf, 0x9b, 0xe2, 0x39, 0xd9, 0x62, 0xff,
+ 0xe1, 0x4b, 0x39, 0xb7, 0xcd, 0xb9, 0x93, 0xac, 0x54, 0x8f, 0xe4, 0x8b,
+ 0xaf, 0xb2, 0x58, 0x4b, 0x14, 0xc7, 0x84, 0x02, 0x1a, 0x85, 0x7a, 0x53,
+ 0xc2, 0x50, 0x64, 0x18, 0x3c, 0x6b, 0x1f, 0x44, 0xbd, 0x90, 0xe9, 0x60,
+ 0xe4, 0x1f, 0x22, 0x28, 0x59, 0xfa, 0x1d, 0x36, 0xd9, 0xd8, 0xdd, 0xd8,
+ 0x38, 0x50, 0x94, 0x2a, 0x53, 0xb0, 0x11, 0xec, 0x45, 0x5b, 0x09, 0x24,
+ 0x2d, 0x14, 0x85, 0x88, 0x11, 0x2a, 0xce, 0x76, 0xa9, 0x3e, 0x0e, 0x54,
+ 0xde, 0x4f, 0x71, 0x1b, 0x19, 0x57, 0x52, 0xbc, 0x7b, 0x87, 0x53, 0x4a,
+ 0x0b, 0x9a, 0x54, 0xc6, 0xa5, 0x2f, 0x1e, 0x3d, 0x8f, 0xcb, 0x76, 0x78,
+ 0xf2, 0x01, 0x28, 0x1c, 0x2e, 0xac, 0x53, 0x86, 0x3c, 0xa4, 0x5d, 0xfa,
+ 0x59, 0x38, 0xa1, 0xd5, 0xbc, 0xf0, 0xc1, 0xdd, 0xc8, 0x7e, 0x87, 0x38,
+ 0x43, 0x7f, 0xfc, 0x15, 0xd8, 0xc2, 0xac, 0x1f, 0xf3, 0xb9, 0x60, 0x4e,
+ 0x2c, 0x5f, 0xcd, 0xec, 0xd7, 0xa1, 0x62, 0xed, 0x42, 0xc5, 0x4c, 0x78,
+ 0x81, 0x0b, 0x6f, 0xd8, 0x66, 0x7d, 0xd6, 0x2f, 0xe6, 0x9c, 0x39, 0xe2,
+ 0x75, 0x8b, 0xff, 0xde, 0x6f, 0x8b, 0xee, 0xdd, 0xf2, 0x0d, 0x58, 0xbf,
+ 0xfc, 0xdd, 0xcb, 0x8d, 0xef, 0xc6, 0xbd, 0x0b, 0x17, 0xf0, 0x39, 0x1b,
+ 0xba, 0x85, 0x8a, 0xc4, 0x64, 0x69, 0x31, 0xd2, 0xef, 0xf4, 0x69, 0xe6,
+ 0x7e, 0x49, 0x62, 0xf3, 0xbf, 0x4a, 0x8a, 0xb8, 0xbf, 0x9c, 0x3f, 0xfd,
+ 0xce, 0xb1, 0x5d, 0x1e, 0xcf, 0xca, 0xaf, 0xe6, 0xd7, 0xdc, 0x33, 0xac,
+ 0x5f, 0x37, 0xa5, 0x0b, 0x14, 0x34, 0xc0, 0x75, 0x08, 0xdf, 0x91, 0xef,
+ 0x2f, 0xbe, 0x20, 0x9c, 0x75, 0x8b, 0xe2, 0xc9, 0xa1, 0x62, 0xdb, 0xab,
+ 0x17, 0xff, 0xa2, 0x7f, 0x30, 0xf0, 0xa4, 0xdf, 0x12, 0xc5, 0xf7, 0x73,
+ 0x4c, 0x4b, 0x15, 0x88, 0xa7, 0x39, 0x17, 0xc5, 0x5d, 0x2a, 0xe8, 0x3a,
+ 0xc5, 0xdc, 0x1a, 0xc5, 0x68, 0xd7, 0xb8, 0xbd, 0xfb, 0xd0, 0x50, 0x05,
+ 0x8b, 0xff, 0xbc, 0x50, 0x08, 0x71, 0xc3, 0x4c, 0xb1, 0x68, 0xd1, 0xf5,
+ 0x1c, 0x9e, 0xff, 0x6c, 0xe6, 0xba, 0x77, 0xe9, 0x51, 0x1e, 0x17, 0xef,
+ 0xb6, 0xbe, 0xeb, 0x17, 0x8b, 0xce, 0xb1, 0x76, 0x0f, 0x0f, 0x13, 0x85,
+ 0x15, 0x24, 0x5a, 0x9e, 0x11, 0x37, 0xfa, 0x51, 0xa9, 0xe3, 0x53, 0xac,
+ 0x5f, 0xff, 0xc5, 0x81, 0x39, 0xb7, 0x80, 0xdf, 0xb5, 0xf9, 0x2d, 0x3a,
+ 0xc5, 0xfc, 0xff, 0x82, 0x80, 0x2c, 0x56, 0xf4, 0x48, 0x6e, 0x32, 0x5f,
+ 0xfd, 0x3c, 0x6b, 0xac, 0xe7, 0x30, 0x78, 0xb1, 0x50, 0x99, 0xa6, 0x43,
+ 0x19, 0xca, 0x2f, 0xd0, 0x3e, 0x04, 0x99, 0x62, 0xff, 0x30, 0x82, 0xf9,
+ 0x29, 0xe6, 0x58, 0xa9, 0xcf, 0x9b, 0xc5, 0x97, 0xff, 0xfd, 0xa2, 0xc9,
+ 0xf6, 0x96, 0x6f, 0x2c, 0x09, 0xcd, 0xbc, 0x06, 0xf5, 0x8b, 0xfe, 0xcf,
+ 0x70, 0x3e, 0x6d, 0xea, 0x4b, 0x17, 0xf1, 0x67, 0xb9, 0x86, 0x2c, 0x54,
+ 0x26, 0x03, 0x84, 0x67, 0x71, 0x73, 0xfb, 0xfd, 0xd3, 0x73, 0xed, 0xe6,
+ 0x58, 0xbf, 0x0e, 0x3d, 0x03, 0x58, 0xbf, 0x64, 0xee, 0x5d, 0xac, 0x57,
+ 0x68, 0x85, 0x63, 0x42, 0x28, 0xbd, 0xed, 0x85, 0x8b, 0x17, 0xf8, 0x6f,
+ 0xc0, 0x47, 0x64, 0xb1, 0x7d, 0xec, 0x20, 0x2c, 0x57, 0x67, 0xad, 0xe3,
+ 0x4b, 0xfc, 0x11, 0xc7, 0x18, 0x36, 0x58, 0xb6, 0xce, 0xc6, 0xca, 0xb1,
+ 0x88, 0x53, 0x4e, 0x4b, 0x22, 0x81, 0xc3, 0xeb, 0x23, 0x2f, 0x64, 0x59,
+ 0xa1, 0x97, 0xa6, 0xaf, 0xc2, 0x29, 0xe1, 0xb8, 0x51, 0xae, 0x72, 0x39,
+ 0xaf, 0x43, 0x03, 0x79, 0x78, 0x6f, 0x21, 0x08, 0xef, 0x7d, 0xce, 0xb1,
+ 0x7d, 0xd3, 0xbf, 0x4a, 0x8b, 0x04, 0xb0, 0xd6, 0x2b, 0x47, 0x87, 0xf3,
+ 0x1b, 0xc6, 0xc4, 0xeb, 0x17, 0xf3, 0x68, 0xb3, 0x7e, 0x2c, 0x5f, 0xff,
+ 0x84, 0xf3, 0x9f, 0x37, 0x05, 0xac, 0xd4, 0x83, 0x92, 0xc5, 0x7d, 0x11,
+ 0x44, 0x5d, 0x71, 0xbe, 0x58, 0xbf, 0x61, 0x67, 0xb8, 0xb1, 0x7e, 0xce,
+ 0x09, 0xfb, 0x58, 0xbf, 0x9c, 0xe1, 0xe9, 0xfb, 0x58, 0xbf, 0xff, 0xff,
+ 0x34, 0xba, 0x21, 0x3c, 0xe7, 0xcd, 0xc1, 0x6a, 0x69, 0x47, 0x79, 0xa9,
+ 0x07, 0x25, 0x8a, 0xd2, 0x2f, 0x3c, 0x61, 0x6d, 0x98, 0x55, 0x2b, 0x8c,
+ 0x06, 0x91, 0x75, 0x0a, 0x9d, 0x11, 0x38, 0xc9, 0x13, 0x87, 0x0e, 0x5b,
+ 0xfd, 0xb3, 0x9a, 0xe9, 0xdf, 0xa5, 0x45, 0x94, 0x5f, 0xfb, 0x3d, 0x2c,
+ 0x06, 0xe6, 0x7c, 0x4b, 0x17, 0x8d, 0x72, 0x58, 0xbf, 0xfd, 0x8e, 0x3f,
+ 0xe6, 0xb5, 0x1b, 0xcd, 0x85, 0x8b, 0xee, 0x9d, 0xfa, 0x54, 0x5a, 0x65,
+ 0x1a, 0x89, 0xad, 0xd1, 0xdd, 0x26, 0x5e, 0x81, 0x76, 0xb1, 0x7d, 0x93,
+ 0xb1, 0x8b, 0x15, 0xf3, 0xc2, 0x21, 0xeb, 0xfb, 0x33, 0xaf, 0x67, 0x4b,
+ 0x17, 0xf8, 0x7f, 0x79, 0xbe, 0xc7, 0x58, 0xa5, 0x87, 0x36, 0xb7, 0xfa,
+ 0x0f, 0x83, 0x28, 0xed, 0x62, 0xfc, 0x36, 0x04, 0x12, 0xc5, 0xf7, 0x0a,
+ 0x00, 0xb1, 0x7f, 0xbd, 0x03, 0x6d, 0x46, 0xf5, 0x8a, 0xc3, 0xd7, 0x72,
+ 0x2b, 0xfb, 0xef, 0xc8, 0xce, 0x2c, 0x50, 0xd5, 0x78, 0x64, 0x37, 0x3a,
+ 0x76, 0x98, 0x84, 0xec, 0x9f, 0x1b, 0x73, 0x32, 0x7e, 0xe1, 0x05, 0xff,
+ 0xfc, 0x7d, 0x97, 0xe7, 0x1c, 0x9c, 0xb2, 0x73, 0xc7, 0x4b, 0x15, 0xb2,
+ 0x8e, 0x2c, 0x84, 0x25, 0xfe, 0xd8, 0x7b, 0x18, 0x57, 0x0e, 0xde, 0x58,
+ 0xbf, 0x05, 0x36, 0x3d, 0x87, 0xb0, 0xf6, 0x1a, 0xc5, 0xf6, 0xc3, 0xd8,
+ 0xf6, 0x3d, 0x81, 0x62, 0x82, 0x87, 0xfd, 0xb0, 0x91, 0x6f, 0xdb, 0x07,
+ 0x9f, 0xf8, 0xb1, 0x7f, 0xdb, 0x17, 0xd8, 0xc1, 0xbb, 0xf4, 0xb1, 0x7b,
+ 0x4f, 0xd2, 0xc5, 0xef, 0xb4, 0xcb, 0x14, 0x33, 0x78, 0xc3, 0xd7, 0xe1,
+ 0xb9, 0x3f, 0x4b, 0x14, 0x15, 0x3c, 0x80, 0xb4, 0x41, 0x7f, 0x41, 0xf3,
+ 0xed, 0x25, 0x8b, 0xf6, 0xc2, 0x0a, 0xf3, 0x21, 0x62, 0xff, 0x6d, 0x99,
+ 0xbe, 0x42, 0xf2, 0xc5, 0xfc, 0x16, 0x9f, 0xec, 0x12, 0x16, 0x2b, 0x61,
+ 0x9f, 0x60, 0x5a, 0x37, 0xbf, 0xc1, 0x9f, 0x3d, 0xc6, 0xe2, 0xc5, 0x99,
+ 0x62, 0xb6, 0x23, 0xc6, 0xdc, 0x35, 0xbf, 0x82, 0xad, 0xd4, 0x77, 0xc5,
+ 0x8b, 0xfd, 0x13, 0xe9, 0xc7, 0x3b, 0xac, 0x5f, 0xff, 0xbe, 0xe5, 0xe9,
+ 0x66, 0xb2, 0x08, 0xb3, 0xcb, 0x15, 0x24, 0x43, 0xb1, 0xad, 0xff, 0xf3,
+ 0xce, 0xfb, 0xf9, 0xb5, 0xf7, 0xf5, 0xf6, 0xd2, 0xc5, 0xfb, 0x7b, 0x8f,
+ 0x0e, 0xb1, 0x7f, 0x71, 0xe7, 0x28, 0x9d, 0x62, 0xf9, 0xc1, 0xb9, 0x8b,
+ 0x17, 0xfd, 0xc8, 0xfc, 0x0f, 0xee, 0x6a, 0xc5, 0x6d, 0x3d, 0xff, 0x12,
+ 0xdd, 0x9b, 0xd6, 0x2d, 0xc8, 0x37, 0xa4, 0x49, 0x7f, 0x67, 0xa0, 0xa2,
+ 0x65, 0x8b, 0xf3, 0x04, 0x82, 0x65, 0x8b, 0xd1, 0xee, 0x2c, 0x51, 0xcf,
+ 0x14, 0x8a, 0x2f, 0x04, 0x1c, 0x2c, 0x53, 0x1e, 0x00, 0x88, 0x6f, 0xd0,
+ 0x5d, 0x7e, 0x16, 0x2f, 0xfe, 0xcf, 0x7d, 0x8f, 0x9e, 0xe0, 0x7c, 0x58,
+ 0xbf, 0xf6, 0x38, 0x22, 0x5a, 0x8c, 0x25, 0x8a, 0xe9, 0x10, 0x4c, 0x8d,
+ 0x7c, 0xdb, 0xff, 0xbd, 0x62, 0xfb, 0x90, 0x53, 0x2c, 0x5f, 0x40, 0x49,
+ 0xb1, 0x62, 0x9c, 0xf2, 0x08, 0x8e, 0xff, 0xf0, 0xe0, 0xdd, 0xb0, 0xda,
+ 0x8f, 0x47, 0xd6, 0x2f, 0xdd, 0x39, 0x40, 0x6b, 0x15, 0x87, 0xeb, 0xf4,
+ 0xcb, 0xff, 0xa6, 0x0e, 0x27, 0xdb, 0x1f, 0xcd, 0x62, 0xc5, 0x61, 0xf5,
+ 0x39, 0x0d, 0xfe, 0x08, 0xc0, 0xda, 0xff, 0x12, 0xc5, 0x49, 0x73, 0xe8,
+ 0x64, 0x58, 0xb1, 0xd9, 0x53, 0x43, 0x2e, 0x62, 0x5f, 0xc2, 0xc8, 0x04,
+ 0x25, 0x0a, 0xae, 0x11, 0xf9, 0xbf, 0x7c, 0x3f, 0xc2, 0x10, 0x5f, 0xfe,
+ 0xcd, 0xb1, 0xbd, 0xf5, 0xc8, 0xd3, 0x71, 0x62, 0xee, 0xe6, 0x58, 0xbf,
+ 0xe2, 0xc1, 0x94, 0x75, 0x1a, 0x58, 0xa9, 0x91, 0x3e, 0x74, 0xd7, 0x1a,
+ 0xbf, 0xc7, 0x0c, 0xe0, 0x3b, 0x01, 0x62, 0xfd, 0xb7, 0x5a, 0x17, 0xd6,
+ 0x2f, 0xcc, 0x6c, 0x17, 0x4b, 0x15, 0xc3, 0xd5, 0xf1, 0x65, 0xfe, 0xf7,
+ 0x22, 0x67, 0x7d, 0x2c, 0x54, 0x23, 0x87, 0x21, 0x16, 0xc4, 0x57, 0x9b,
+ 0x27, 0x58, 0xbf, 0xfd, 0xd7, 0xdb, 0xed, 0xa8, 0x98, 0xcc, 0xfa, 0xc5,
+ 0x7c, 0xfa, 0x88, 0x76, 0xf0, 0x0b, 0x16, 0x2e, 0x2c, 0x58, 0xad, 0xa6,
+ 0xc8, 0x03, 0x97, 0x8f, 0x1a, 0x58, 0xbf, 0xe6, 0xdb, 0xf7, 0xd4, 0x6f,
+ 0x85, 0x8a, 0x83, 0xd9, 0xe0, 0xed, 0xff, 0x1d, 0xe5, 0xb8, 0x2f, 0xb6,
+ 0x96, 0x2a, 0x74, 0x6d, 0x69, 0xf0, 0xe4, 0x37, 0xe7, 0xe7, 0xa0, 0x6b,
+ 0x15, 0x07, 0xb2, 0x23, 0x1b, 0xfc, 0xe6, 0x06, 0x31, 0xe1, 0x8b, 0x17,
+ 0xf9, 0xf5, 0x27, 0xf3, 0xf4, 0xb1, 0x7f, 0xfb, 0x30, 0xb0, 0x05, 0x9e,
+ 0xfe, 0x49, 0x62, 0xa1, 0x52, 0xcf, 0xe3, 0x86, 0x72, 0x11, 0x1b, 0x84,
+ 0x34, 0xbf, 0xf8, 0xe4, 0xe6, 0x96, 0x02, 0x7c, 0x31, 0x62, 0xff, 0xf1,
+ 0x61, 0xbf, 0x79, 0x7c, 0xc7, 0x0c, 0xeb, 0x16, 0xfc, 0x22, 0x4f, 0x11,
+ 0xaf, 0xe8, 0x2f, 0x0c, 0xa1, 0x62, 0xfa, 0x5c, 0x3c, 0x96, 0x2f, 0xed,
+ 0x66, 0x80, 0x08, 0x58, 0xa8, 0x3d, 0x26, 0x24, 0xbe, 0x80, 0xe3, 0xeb,
+ 0x17, 0x34, 0xeb, 0x17, 0x9d, 0xfa, 0x54, 0x5b, 0x85, 0xd3, 0x71, 0x62,
+ 0xfd, 0xee, 0x71, 0xa6, 0x58, 0xa9, 0xd1, 0x0b, 0xd0, 0xc3, 0x15, 0x06,
+ 0x33, 0x7f, 0x37, 0xa6, 0x28, 0x1a, 0xc5, 0xff, 0x9b, 0x5f, 0x7c, 0xd4,
+ 0xed, 0x3a, 0xc5, 0xf4, 0xd0, 0x3c, 0x58, 0xbf, 0x80, 0x7c, 0xe0, 0x89,
+ 0x62, 0xed, 0xa4, 0xb1, 0x7f, 0x71, 0xb3, 0x7b, 0xe9, 0x62, 0xfe, 0xe4,
+ 0x6b, 0x58, 0x62, 0xc5, 0x48, 0xfd, 0xce, 0x33, 0xe2, 0xfa, 0x64, 0x6a,
+ 0x3c, 0x29, 0x6f, 0xfd, 0x9a, 0xc2, 0xdb, 0xfc, 0xec, 0xc5, 0x8b, 0xf1,
+ 0x01, 0xfb, 0xe2, 0xc5, 0xfd, 0x9b, 0xdb, 0xe7, 0x75, 0x8a, 0x84, 0x4d,
+ 0x3a, 0x11, 0x14, 0xd4, 0x95, 0xff, 0x0c, 0x9c, 0xd7, 0xee, 0xc8, 0x35,
+ 0x0a, 0x83, 0x9f, 0xfc, 0xb9, 0xd0, 0x0a, 0x1e, 0xfc, 0x86, 0x05, 0xff,
+ 0x9c, 0x64, 0xfb, 0xff, 0x13, 0x71, 0x62, 0x96, 0x2f, 0x47, 0x44, 0xb1,
+ 0x5e, 0x35, 0x3b, 0xc3, 0x2f, 0xe2, 0x04, 0xc5, 0x07, 0x58, 0xa3, 0x51,
+ 0x76, 0x76, 0xa7, 0x23, 0xbc, 0x72, 0x65, 0x8b, 0x12, 0xc5, 0xba, 0x58,
+ 0xbf, 0xef, 0x89, 0xf9, 0x98, 0x46, 0xac, 0x5f, 0xff, 0xa3, 0xad, 0xb9,
+ 0xf6, 0xd4, 0x7f, 0x08, 0x70, 0xb1, 0x7e, 0xe3, 0xf6, 0xe3, 0x58, 0xb3,
+ 0x0d, 0x17, 0x07, 0x39, 0xf2, 0xb5, 0xfe, 0x7d, 0x92, 0xc9, 0xe0, 0xd5,
+ 0x8a, 0x84, 0xd9, 0x30, 0x71, 0x84, 0x7f, 0x0c, 0xb2, 0x35, 0xbf, 0xe8,
+ 0x72, 0xfe, 0x61, 0x74, 0xb1, 0x74, 0x82, 0xab, 0x17, 0xf8, 0xa7, 0x27,
+ 0xd3, 0xc9, 0x62, 0xa0, 0xf3, 0xc4, 0x39, 0x52, 0x45, 0x3f, 0x21, 0x0d,
+ 0x7f, 0x88, 0x47, 0x8e, 0x79, 0x96, 0x2f, 0xf3, 0x14, 0x1e, 0x3b, 0xe2,
+ 0xc5, 0xfa, 0x35, 0xac, 0x08, 0xb1, 0x50, 0x89, 0x09, 0x8c, 0xc8, 0xce,
+ 0xff, 0x08, 0x65, 0x9b, 0xde, 0x4b, 0x17, 0xff, 0xef, 0xcd, 0xb4, 0xe2,
+ 0xf3, 0x4f, 0x9e, 0x37, 0x3e, 0xb1, 0x7f, 0x14, 0x4d, 0x36, 0x01, 0x62,
+ 0xff, 0xf4, 0x4f, 0xe6, 0x1e, 0x14, 0x9b, 0xe2, 0x58, 0xbf, 0xcd, 0xbf,
+ 0x3e, 0xe5, 0x3a, 0xc5, 0xd8, 0x75, 0x8a, 0x91, 0xe6, 0x70, 0xd6, 0xf4,
+ 0x66, 0x96, 0x2f, 0xf7, 0xe2, 0x4d, 0xb9, 0x87, 0x58, 0xa1, 0x9e, 0x97,
+ 0x07, 0x2f, 0xdb, 0x7b, 0xe3, 0x1a, 0xb1, 0x53, 0x9e, 0x7f, 0x64, 0x55,
+ 0xda, 0x39, 0xde, 0x18, 0x77, 0xfe, 0xcf, 0xb6, 0x87, 0xf8, 0x2e, 0x96,
+ 0x2f, 0x87, 0x9c, 0x12, 0xc5, 0xff, 0x8b, 0x3d, 0xc8, 0xdb, 0xec, 0xe9,
+ 0x62, 0xfb, 0x6f, 0xb0, 0x0b, 0x15, 0x24, 0x64, 0x61, 0xfb, 0x11, 0xfd,
+ 0x06, 0xff, 0x77, 0x28, 0x2f, 0x60, 0x16, 0x2f, 0xb8, 0x06, 0xf2, 0xc5,
+ 0x49, 0x5d, 0xff, 0x46, 0xac, 0xb9, 0xf2, 0xf7, 0x8d, 0xf7, 0x90, 0xf0,
+ 0x11, 0xd8, 0x66, 0x97, 0xe7, 0xd7, 0xb3, 0xeb, 0x17, 0xfe, 0x60, 0x44,
+ 0x87, 0xf8, 0x2e, 0x96, 0x2a, 0x47, 0xcf, 0xe2, 0x8b, 0xfb, 0xd2, 0xcd,
+ 0x67, 0x16, 0x29, 0x62, 0xf0, 0x9f, 0xcb, 0x17, 0x0a, 0x16, 0x2a, 0x46,
+ 0xd3, 0xc3, 0xb4, 0xb1, 0x7d, 0xdf, 0x4d, 0xa5, 0x8b, 0x8f, 0xb3, 0x88,
+ 0x92, 0xed, 0x00, 0xe4, 0x3e, 0x0c, 0xbe, 0xc1, 0x90, 0xd6, 0x2a, 0x0f,
+ 0xbb, 0x7a, 0x65, 0xff, 0x17, 0xbe, 0xf2, 0x13, 0x86, 0xb1, 0x50, 0x9d,
+ 0x6e, 0x11, 0x34, 0x65, 0xce, 0x47, 0x62, 0x58, 0xbd, 0xa0, 0x90, 0xb1,
+ 0x77, 0xb6, 0xec, 0x33, 0x61, 0x30, 0x8d, 0xe7, 0x69, 0xd6, 0x2b, 0x0f,
+ 0x4c, 0xd3, 0x6b, 0x32, 0xc5, 0xb7, 0x16, 0x2c, 0x40, 0x34, 0xde, 0x11,
+ 0xbd, 0xb7, 0x60, 0xd8, 0x16, 0x2f, 0xec, 0xd7, 0x4e, 0xfd, 0x2a, 0x28,
+ 0x72, 0xc3, 0x58, 0xbf, 0xed, 0x67, 0xb6, 0xca, 0x7e, 0x32, 0xc5, 0xd0,
+ 0x1a, 0xc5, 0xa5, 0xb2, 0x8a, 0x39, 0xcf, 0x30, 0x48, 0x8f, 0x6f, 0xd2,
+ 0xdb, 0xbc, 0xf0, 0xb1, 0x69, 0x2c, 0x5f, 0xc2, 0xf1, 0x47, 0xb8, 0xb1,
+ 0x4c, 0x78, 0x00, 0x12, 0xa8, 0x54, 0x1c, 0xc9, 0x13, 0x13, 0x3c, 0x33,
+ 0x49, 0x14, 0x4d, 0xb7, 0xb4, 0x6f, 0x4b, 0x17, 0x61, 0xd6, 0x2f, 0x7b,
+ 0x02, 0x2c, 0x5a, 0x3a, 0x36, 0xde, 0x17, 0xa9, 0x1f, 0xe8, 0x15, 0xaf,
+ 0xe2, 0xcf, 0x73, 0x06, 0xb1, 0x7d, 0x1b, 0xa2, 0x85, 0x8b, 0xd3, 0x60,
+ 0xd6, 0x2f, 0x4d, 0x1e, 0x58, 0xa8, 0x37, 0x82, 0x1e, 0xad, 0x23, 0x40,
+ 0xe4, 0x40, 0x2d, 0xe3, 0x0d, 0xc2, 0x0d, 0x62, 0xf3, 0xee, 0x1a, 0xb1,
+ 0x7e, 0xe3, 0xff, 0x3a, 0x58, 0xae, 0xcf, 0x8c, 0x03, 0x3c, 0x21, 0xbc,
+ 0x38, 0x3a, 0xc5, 0xec, 0xd3, 0xac, 0x5f, 0xf6, 0x40, 0xff, 0x01, 0x22,
+ 0x65, 0x8b, 0xfc, 0x06, 0xff, 0xf0, 0x0e, 0xb1, 0x5d, 0x22, 0x28, 0xe3,
+ 0x80, 0x3b, 0xbf, 0xf6, 0x7b, 0x9f, 0xcd, 0x6b, 0x0c, 0x58, 0xbf, 0xf1,
+ 0x04, 0x72, 0x73, 0x8f, 0x06, 0xb1, 0x50, 0xa8, 0x9f, 0x21, 0x40, 0xc6,
+ 0x0f, 0x0a, 0x70, 0xcc, 0x42, 0x20, 0x5f, 0xf9, 0xc7, 0x03, 0xfb, 0x13,
+ 0x1d, 0x62, 0xff, 0xdb, 0xdf, 0x5c, 0x7f, 0xf2, 0x27, 0x58, 0xbf, 0xba,
+ 0x8e, 0x3f, 0x60, 0x58, 0xbf, 0xdc, 0x17, 0x59, 0xe2, 0x85, 0x8a, 0x3a,
+ 0x38, 0xfe, 0x7a, 0x48, 0x5e, 0x30, 0xbf, 0xf7, 0x7c, 0xdb, 0xbf, 0x20,
+ 0x62, 0x9d, 0x62, 0xf7, 0xb3, 0xa5, 0x8b, 0xb3, 0xa5, 0x8b, 0x66, 0xd3,
+ 0x6d, 0xe1, 0xeb, 0xfe, 0xfb, 0xeb, 0xbf, 0x43, 0x4e, 0xb1, 0x7f, 0x8b,
+ 0xad, 0xb3, 0x75, 0xf9, 0x96, 0x2a, 0x47, 0xec, 0xe7, 0x74, 0xe9, 0x9d,
+ 0x93, 0xe0, 0xa1, 0x3d, 0x7f, 0xa5, 0x1a, 0x9e, 0x35, 0x3a, 0xc5, 0xf4,
+ 0x3e, 0x80, 0xb1, 0x7e, 0x6f, 0x90, 0xbc, 0xb1, 0x7f, 0xba, 0x6e, 0x60,
+ 0xdf, 0xa5, 0x8b, 0xfb, 0xf8, 0x4d, 0xf1, 0x2c, 0x50, 0xd1, 0x59, 0x31,
+ 0x17, 0xca, 0x3c, 0x6b, 0x7e, 0x9e, 0x3e, 0xfe, 0x58, 0xbf, 0x3f, 0x37,
+ 0xe7, 0x16, 0x2f, 0xcf, 0xed, 0xb1, 0x0b, 0x15, 0x09, 0xce, 0x64, 0x38,
+ 0x9c, 0xf8, 0x05, 0x22, 0x2a, 0xbf, 0x6d, 0xfe, 0x01, 0xd6, 0x2f, 0xf6,
+ 0xa3, 0xee, 0x39, 0x1d, 0x62, 0xff, 0x8e, 0xde, 0xdc, 0xc2, 0x73, 0x56,
+ 0x2f, 0xdb, 0x67, 0x16, 0xa4, 0xb1, 0x7f, 0x49, 0xf5, 0x9d, 0xf9, 0x62,
+ 0xfe, 0x1b, 0x9f, 0xec, 0x62, 0xc5, 0x41, 0xef, 0x61, 0x7d, 0xff, 0x67,
+ 0xb8, 0x1f, 0x34, 0xfc, 0x58, 0xba, 0x79, 0xd6, 0x2f, 0xb6, 0x9b, 0x83,
+ 0x58, 0xa1, 0x9e, 0x00, 0x06, 0xaf, 0xcd, 0xee, 0x3b, 0x2c, 0x5f, 0xfb,
+ 0x0c, 0x7d, 0x1b, 0x1d, 0x61, 0xd6, 0x2f, 0xff, 0xd9, 0xf6, 0xe0, 0xa7,
+ 0xeb, 0xed, 0xef, 0x64, 0xeb, 0x17, 0xfd, 0xa0, 0x69, 0xcb, 0xd8, 0x05,
+ 0x8a, 0x9d, 0x56, 0xe0, 0xca, 0xb0, 0xd1, 0x8f, 0x35, 0x08, 0xb3, 0x90,
+ 0x3b, 0xd8, 0x08, 0x88, 0x9f, 0x88, 0x22, 0x59, 0xbc, 0x1e, 0xa4, 0xb1,
+ 0x7f, 0x07, 0xe1, 0x46, 0x4e, 0xb1, 0x7f, 0x03, 0xee, 0xdf, 0x12, 0xc5,
+ 0xee, 0x14, 0x96, 0x2a, 0x48, 0x9a, 0x98, 0x7f, 0x46, 0x1e, 0x2e, 0xbf,
+ 0xfb, 0xa2, 0x8f, 0x16, 0x6f, 0xcd, 0x49, 0x62, 0xfc, 0xfc, 0xe4, 0xfc,
+ 0x58, 0xbf, 0x9c, 0x80, 0x18, 0x38, 0xb1, 0x7e, 0xf1, 0x38, 0x38, 0xb1,
+ 0x7b, 0x87, 0x75, 0x8b, 0xfc, 0x46, 0x87, 0xff, 0x8b, 0x8b, 0x14, 0x6a,
+ 0x2a, 0xfb, 0x2f, 0x98, 0xa0, 0x43, 0xb7, 0xff, 0x0b, 0x9f, 0x79, 0x41,
+ 0x0f, 0x3e, 0xb1, 0x7f, 0xc1, 0xc0, 0x26, 0x94, 0x6a, 0x75, 0x8b, 0xf8,
+ 0x9f, 0xc1, 0xc7, 0x4b, 0x14, 0x73, 0xec, 0x23, 0xdb, 0xe2, 0x04, 0xe0,
+ 0x58, 0xbf, 0xff, 0xd3, 0x71, 0x87, 0xb6, 0x66, 0x2d, 0xef, 0x33, 0xf8,
+ 0x50, 0xb1, 0x58, 0x8a, 0xc6, 0x21, 0x72, 0x4b, 0xe9, 0xb4, 0xfa, 0x58,
+ 0xbf, 0xe0, 0xca, 0x59, 0xbc, 0xb3, 0x8b, 0x17, 0xfc, 0x7e, 0x6d, 0xc1,
+ 0xc1, 0x79, 0x62, 0xfd, 0x2d, 0xbc, 0xe6, 0x2c, 0x5f, 0xee, 0x6d, 0xf6,
+ 0xd1, 0xe1, 0x2c, 0x58, 0x0b, 0x15, 0xd9, 0xe5, 0x68, 0xe2, 0xa1, 0x1a,
+ 0x78, 0x76, 0xce, 0xb7, 0xf0, 0xba, 0xfc, 0x6b, 0x16, 0x2f, 0xbb, 0xe7,
+ 0x99, 0x62, 0xb0, 0xf4, 0xdc, 0xbe, 0xa1, 0x73, 0xd3, 0x0f, 0x8d, 0x46,
+ 0x68, 0x6a, 0xe9, 0x03, 0xf1, 0xae, 0x39, 0x68, 0x09, 0x0a, 0x30, 0xee,
+ 0x42, 0x02, 0xfc, 0xe2, 0x36, 0x03, 0x58, 0xbe, 0xcd, 0x47, 0x16, 0x2f,
+ 0x74, 0x15, 0xd2, 0xc5, 0x6c, 0x47, 0x8a, 0x22, 0x2a, 0x99, 0x12, 0xc4,
+ 0xdf, 0x7f, 0x67, 0x98, 0x78, 0x75, 0x8b, 0xe2, 0x93, 0x1d, 0x62, 0xdb,
+ 0x66, 0x3c, 0xf7, 0x2d, 0xbf, 0x98, 0xb7, 0xbc, 0xc1, 0x69, 0x62, 0xfe,
+ 0x89, 0xbb, 0x96, 0x6f, 0x58, 0xa9, 0x8f, 0xa3, 0x86, 0xd7, 0x05, 0x36,
+ 0x05, 0x8a, 0x1a, 0x35, 0x9e, 0x12, 0x5e, 0x23, 0xbf, 0xff, 0x0f, 0xf0,
+ 0x1e, 0xcf, 0x89, 0xc1, 0xce, 0x40, 0x12, 0x2e, 0x1e, 0x2c, 0x5f, 0xa7,
+ 0x89, 0xdf, 0x8b, 0x15, 0x88, 0x9b, 0x65, 0xa7, 0x17, 0xbf, 0x82, 0x38,
+ 0x0f, 0x1c, 0x58, 0xbf, 0x73, 0x37, 0xfd, 0x96, 0x2e, 0x80, 0x2c, 0x52,
+ 0xc0, 0x65, 0xbd, 0x78, 0xf7, 0x44, 0x83, 0x5f, 0x45, 0x78, 0x21, 0x1b,
+ 0x7f, 0x84, 0x5e, 0xda, 0x40, 0x02, 0xc5, 0xff, 0xb9, 0xbd, 0xe6, 0x9d,
+ 0xc9, 0xe6, 0x58, 0xbf, 0xf4, 0x04, 0x99, 0xf7, 0xbf, 0xb7, 0xc2, 0xc5,
+ 0xff, 0xb0, 0x71, 0x28, 0xd1, 0xfd, 0xda, 0xc5, 0xfc, 0xe0, 0x98, 0xa0,
+ 0x6b, 0x17, 0xfc, 0x59, 0x38, 0xff, 0x85, 0xe5, 0x8b, 0xde, 0x6e, 0x2c,
+ 0x5f, 0xe6, 0xd4, 0x6f, 0x82, 0xf2, 0xc5, 0x42, 0x7b, 0xd3, 0x94, 0x4c,
+ 0x6d, 0xa4, 0x33, 0xa2, 0xfd, 0x00, 0x8b, 0xb8, 0x73, 0xe1, 0xda, 0xd8,
+ 0xdd, 0xcc, 0xb8, 0x52, 0x18, 0x21, 0x52, 0xcd, 0x80, 0xb7, 0x62, 0x86,
+ 0x26, 0xc2, 0x2c, 0xd8, 0x65, 0xa1, 0x6a, 0x13, 0xc1, 0x63, 0xa0, 0x5b,
+ 0x95, 0x44, 0xed, 0xac, 0xf1, 0xb5, 0xca, 0x31, 0x11, 0xca, 0xf5, 0xc9,
+ 0xce, 0x33, 0x63, 0x57, 0xea, 0x39, 0x4e, 0xe1, 0xe6, 0xd0, 0xb8, 0x9a,
+ 0x5f, 0x76, 0xa5, 0x49, 0x1e, 0x56, 0x8f, 0xe5, 0xe7, 0xbc, 0x68, 0xa0,
+ 0x8d, 0xdc, 0xa3, 0xd0, 0xe4, 0xb2, 0x9f, 0x4f, 0x15, 0x0a, 0x33, 0x6d,
+ 0xf1, 0xa4, 0x6e, 0x43, 0x3c, 0x39, 0x57, 0x57, 0xf7, 0xbb, 0xe3, 0x10,
+ 0xd6, 0x2f, 0xfe, 0xd6, 0x77, 0xd7, 0xdb, 0xdc, 0x7e, 0xd6, 0x2f, 0xd1,
+ 0xcd, 0x08, 0x0b, 0x17, 0xff, 0xf1, 0xf3, 0xdc, 0x0f, 0x85, 0x9e, 0x10,
+ 0x0e, 0xf2, 0x58, 0xbe, 0xc1, 0xbc, 0x96, 0x2f, 0x06, 0x52, 0x58, 0xa6,
+ 0x3c, 0x00, 0x11, 0x5d, 0xd6, 0xcb, 0x26, 0xbc, 0x02, 0xf2, 0x48, 0xe1,
+ 0x4f, 0xa1, 0x3b, 0x5b, 0x2b, 0x88, 0x62, 0x97, 0xcb, 0x7d, 0x1a, 0x91,
+ 0xd6, 0x2f, 0xfa, 0x67, 0x82, 0x89, 0x85, 0x0b, 0x17, 0xbe, 0xdb, 0xab,
+ 0x17, 0xdb, 0x99, 0xa8, 0x58, 0xbd, 0xc7, 0xdd, 0x58, 0xac, 0x3c, 0x5e,
+ 0xc9, 0x6f, 0xd8, 0x31, 0x7b, 0x8b, 0x17, 0xff, 0xe2, 0xc9, 0x7e, 0x35,
+ 0x98, 0x46, 0xeb, 0x50, 0xb1, 0x7f, 0x9f, 0xee, 0x19, 0xf3, 0x8b, 0x17,
+ 0x9f, 0x46, 0xac, 0x5b, 0x66, 0x74, 0xec, 0xb0, 0x8f, 0xa3, 0x96, 0x65,
+ 0x22, 0x2e, 0x14, 0xef, 0x54, 0x30, 0xd2, 0xff, 0x6c, 0xe6, 0xba, 0x77,
+ 0xe9, 0x51, 0x79, 0x95, 0x10, 0x93, 0xc3, 0x94, 0x22, 0x07, 0x1c, 0x36,
+ 0x5b, 0xb9, 0x5e, 0xe9, 0xa3, 0xba, 0x97, 0x7e, 0x78, 0x42, 0xfe, 0x70,
+ 0x5c, 0xad, 0xf0, 0x27, 0x23, 0xe2, 0xde, 0xfb, 0x7f, 0xb6, 0x73, 0x5d,
+ 0x3b, 0xf4, 0xa8, 0xa5, 0x8b, 0xb6, 0x30, 0xb1, 0x62, 0xef, 0x4e, 0xb1,
+ 0x7e, 0x6d, 0x9e, 0x63, 0x2c, 0x5f, 0xff, 0xbf, 0x85, 0x86, 0xfd, 0xe5,
+ 0xf3, 0x1c, 0x33, 0xac, 0x5f, 0x74, 0xef, 0xd2, 0xa2, 0xc2, 0x2a, 0x48,
+ 0x89, 0xd2, 0xc5, 0xf7, 0xa0, 0x78, 0xb1, 0x7f, 0xfd, 0x84, 0x38, 0xfc,
+ 0x77, 0xec, 0x27, 0x3a, 0xc5, 0xe2, 0x17, 0x4b, 0x15, 0x07, 0xd8, 0xe9,
+ 0xd7, 0xff, 0xf7, 0xb1, 0xb5, 0xcf, 0x13, 0x03, 0x91, 0xee, 0x32, 0xc5,
+ 0x2c, 0x54, 0x1f, 0x37, 0x16, 0xaf, 0xe1, 0x69, 0xa7, 0x73, 0xac, 0x5b,
+ 0x64, 0x2c, 0x54, 0xeb, 0x04, 0x43, 0x19, 0xc8, 0x59, 0xb1, 0x19, 0xe1,
+ 0x1d, 0xc8, 0x43, 0x6e, 0x10, 0xdf, 0xed, 0x9c, 0xd7, 0x4e, 0xfd, 0x2a,
+ 0x2c, 0xb2, 0xe9, 0x32, 0xc5, 0xa4, 0xb1, 0x76, 0x8d, 0x58, 0xbe, 0xd9,
+ 0x34, 0x2c, 0x0a, 0x2c, 0x52, 0x45, 0xed, 0x90, 0xce, 0xb1, 0x5d, 0x1e,
+ 0xff, 0x0c, 0x44, 0x19, 0x7d, 0x9a, 0x71, 0xac, 0x51, 0xa8, 0xdc, 0x21,
+ 0x2e, 0x3c, 0x78, 0xc2, 0xe8, 0xfa, 0xc5, 0x80, 0xb1, 0x71, 0xb3, 0xac,
+ 0x5b, 0x52, 0x35, 0x98, 0x25, 0x5d, 0x1f, 0x4b, 0xa1, 0xd2, 0xc5, 0xe9,
+ 0x14, 0x2c, 0x50, 0x0d, 0x47, 0x83, 0x2e, 0x97, 0xd6, 0x2c, 0x6a, 0xc5,
+ 0x31, 0xe6, 0x00, 0x87, 0xc3, 0x17, 0xff, 0xe1, 0xb7, 0xbf, 0x83, 0x6c,
+ 0x1b, 0xce, 0xe4, 0xb1, 0x7f, 0xcf, 0xd9, 0x67, 0x7e, 0x83, 0x56, 0x2f,
+ 0xf4, 0xfd, 0xf2, 0x07, 0xe6, 0x58, 0xbf, 0x46, 0x6f, 0x8e, 0x2c, 0x5a,
+ 0x1c, 0xf7, 0xcc, 0x36, 0xbf, 0x88, 0xd0, 0x3f, 0xb8, 0xb1, 0x76, 0xa4,
+ 0xb1, 0x50, 0x78, 0xee, 0x5f, 0x50, 0x9b, 0xe3, 0xaa, 0x14, 0x26, 0x84,
+ 0xdd, 0x7c, 0xf2, 0x90, 0xd6, 0x2e, 0xf7, 0x96, 0x2f, 0xe2, 0x81, 0x75,
+ 0xf7, 0x58, 0xbd, 0xaf, 0xbc, 0xe7, 0x8c, 0x31, 0x8b, 0xf6, 0xa3, 0xcf,
+ 0xf5, 0x8a, 0x63, 0xdc, 0x73, 0x4b, 0xc6, 0x18, 0x62, 0x45, 0xff, 0x44,
+ 0xbb, 0xf6, 0xa3, 0x3b, 0x48, 0xd9, 0x34, 0x37, 0xfc, 0x27, 0xef, 0x3c,
+ 0xdd, 0x98, 0xb1, 0x74, 0x71, 0x62, 0x86, 0x9d, 0x3f, 0xe1, 0x8a, 0x48,
+ 0x3c, 0x4e, 0xde, 0x79, 0x70, 0x58, 0x14, 0x58, 0xbf, 0x99, 0xf8, 0x0e,
+ 0x09, 0x62, 0xff, 0xe6, 0x93, 0xf1, 0xc8, 0x5d, 0x67, 0x12, 0x2f, 0xff,
+ 0xef, 0xb7, 0xbf, 0x9c, 0x2c, 0x38, 0xb9, 0xf7, 0x92, 0xc5, 0xfe, 0x89,
+ 0x79, 0xfe, 0xe3, 0x58, 0xbe, 0x7f, 0x1b, 0xc5, 0x8a, 0x84, 0x7b, 0x62,
+ 0x26, 0x96, 0xdc, 0xce, 0xf7, 0x4f, 0xa5, 0x8b, 0xff, 0xfe, 0x6f, 0x41,
+ 0x3f, 0xb9, 0x85, 0xdf, 0xa0, 0xf1, 0xa9, 0x96, 0x29, 0x91, 0x08, 0xe3,
+ 0xd6, 0x92, 0xc5, 0xa4, 0xb1, 0x69, 0x2c, 0x5e, 0x30, 0xc3, 0x16, 0x2d,
+ 0xd2, 0x46, 0xc9, 0xa1, 0xa8, 0x3f, 0xd3, 0x44, 0x98, 0x48, 0x06, 0x74,
+ 0xb1, 0x7e, 0x17, 0x3e, 0xf2, 0x58, 0xc2, 0x65, 0xff, 0xf7, 0x1b, 0xac,
+ 0x2d, 0x41, 0x60, 0xf0, 0xd5, 0x8a, 0x3a, 0x21, 0x7c, 0x6d, 0x7f, 0xff,
+ 0xfe, 0x1b, 0x1c, 0x5c, 0xfb, 0xcb, 0x58, 0x3f, 0xbb, 0x4a, 0x59, 0xe7,
+ 0x20, 0x2c, 0x5b, 0xb5, 0x8b, 0x1a, 0xb1, 0x61, 0x2c, 0x51, 0x1a, 0x5e,
+ 0x09, 0xd6, 0x23, 0xf5, 0xc8, 0xf9, 0x08, 0x2f, 0x1c, 0x5d, 0xc3, 0x56,
+ 0x2d, 0x8b, 0x17, 0x08, 0x10, 0x6a, 0x86, 0x33, 0x73, 0x42, 0xc5, 0xff,
+ 0xff, 0xf7, 0xa0, 0x6c, 0x3f, 0xc4, 0xb4, 0xef, 0xdc, 0xb9, 0xee, 0xfa,
+ 0x6d, 0x1a, 0xb1, 0x7f, 0x14, 0x1c, 0xa3, 0x16, 0x2f, 0xfe, 0x87, 0xd7,
+ 0xbf, 0x83, 0x17, 0xb8, 0xb1, 0x74, 0xa1, 0x62, 0xf7, 0x06, 0x6a, 0xc5,
+ 0x4e, 0x9b, 0x50, 0xcb, 0x30, 0x5a, 0x68, 0x41, 0x7c, 0xac, 0x48, 0xa1,
+ 0x8b, 0xdf, 0xfe, 0xce, 0xfc, 0x1f, 0x9b, 0xdf, 0xc1, 0xb2, 0xc5, 0xff,
+ 0xff, 0xe8, 0xf7, 0x1b, 0x9c, 0x8f, 0x7d, 0xa3, 0x40, 0x3b, 0xca, 0x5e,
+ 0x35, 0x62, 0x8d, 0x46, 0x2f, 0xd3, 0x2e, 0x6e, 0xd6, 0x2f, 0xbe, 0x4d,
+ 0x0b, 0x17, 0x4b, 0xeb, 0x14, 0xe6, 0xe4, 0x04, 0x37, 0x41, 0xd6, 0x2f,
+ 0xff, 0xd0, 0x42, 0x94, 0xa3, 0xdf, 0xc3, 0x87, 0x00, 0x58, 0xbf, 0xf9,
+ 0xa7, 0x8f, 0xb4, 0x7b, 0x82, 0xe2, 0xc5, 0xff, 0xc2, 0x96, 0x73, 0x50,
+ 0xd2, 0x7e, 0x24, 0x59, 0xb4, 0x88, 0x92, 0x45, 0xa9, 0x26, 0x0d, 0xe8,
+ 0x6f, 0xdd, 0xd6, 0xce, 0xc0, 0xcf, 0x5b, 0x88, 0x79, 0xcf, 0x0a, 0x69,
+ 0x42, 0x58, 0x71, 0xd5, 0x64, 0x7c, 0xe6, 0xa8, 0xf4, 0x43, 0xa8, 0xc9,
+ 0x3f, 0x0b, 0xe7, 0x84, 0xf1, 0x47, 0x93, 0xc8, 0xf5, 0x3d, 0x19, 0x8e,
+ 0xf2, 0x43, 0x14, 0x77, 0x08, 0x03, 0x8c, 0x76, 0xff, 0xf6, 0xc9, 0xde,
+ 0x5b, 0x39, 0xae, 0x9d, 0xfa, 0x54, 0x51, 0x85, 0xf3, 0x79, 0xf7, 0x16,
+ 0x2f, 0xe7, 0xd0, 0x0f, 0x00, 0x58, 0xbe, 0x8d, 0x40, 0x16, 0x2f, 0xe8,
+ 0x1c, 0x1e, 0x03, 0x58, 0xa9, 0x91, 0x47, 0xf2, 0x5d, 0xe5, 0xc1, 0x91,
+ 0x5f, 0xe7, 0x97, 0x18, 0xb0, 0x0b, 0x17, 0xe7, 0xf7, 0xda, 0x65, 0x8a,
+ 0x01, 0xed, 0x91, 0x95, 0xf6, 0x61, 0x32, 0xc5, 0xf4, 0x4f, 0x83, 0x58,
+ 0xb8, 0xc9, 0x96, 0x2b, 0xe6, 0xf5, 0xc8, 0xef, 0xff, 0xb4, 0xc6, 0xe7,
+ 0x85, 0xf6, 0x3e, 0x7d, 0xd6, 0x2f, 0xc4, 0xe0, 0x80, 0xd6, 0x2f, 0xf0,
+ 0xc5, 0xdf, 0x3f, 0x9c, 0x58, 0xbf, 0xd9, 0xee, 0x07, 0x3c, 0x4e, 0xb1,
+ 0x7f, 0xb3, 0x26, 0x31, 0xfb, 0xe2, 0xc5, 0xfd, 0xcc, 0xfe, 0x4b, 0x8b,
+ 0x16, 0xc0, 0x1f, 0x27, 0x8d, 0xaf, 0xfc, 0xdd, 0xcb, 0x85, 0x9e, 0xf8,
+ 0x96, 0x2f, 0xf9, 0xb5, 0xfc, 0xc2, 0x97, 0x16, 0x2a, 0x47, 0xf1, 0xd2,
+ 0x05, 0xf3, 0xef, 0xc2, 0x58, 0xbf, 0xff, 0xec, 0x3f, 0xda, 0x3c, 0x59,
+ 0xef, 0xe1, 0x61, 0x8e, 0x05, 0x8b, 0xec, 0xe0, 0x7c, 0x58, 0xae, 0xd1,
+ 0x9d, 0xa2, 0x3f, 0x91, 0x93, 0x25, 0xdb, 0xa1, 0x16, 0x2f, 0xf7, 0x5f,
+ 0x63, 0xc6, 0x8d, 0x58, 0xbf, 0x1b, 0x98, 0x46, 0xac, 0x59, 0xe4, 0x7b,
+ 0xfa, 0x36, 0xb8, 0x01, 0x45, 0x8b, 0xfa, 0x70, 0xf7, 0x1c, 0x80, 0xb1,
+ 0x7f, 0x6d, 0xcd, 0x3f, 0xb8, 0xb1, 0x7f, 0xe7, 0x20, 0x67, 0xa0, 0x98,
+ 0x0b, 0x15, 0x08, 0x9f, 0x39, 0x9e, 0xe1, 0x85, 0xb6, 0x61, 0x76, 0xf7,
+ 0x21, 0x38, 0x69, 0x0c, 0xcb, 0xa7, 0x20, 0xfa, 0x83, 0x94, 0x00, 0xd8,
+ 0xa1, 0x37, 0xe8, 0xdb, 0x44, 0x7a, 0x63, 0xe6, 0xe1, 0x38, 0x70, 0xbb,
+ 0xa9, 0x37, 0x7c, 0x3a, 0x95, 0x74, 0x78, 0x48, 0x3d, 0x3e, 0x83, 0x91,
+ 0xaa, 0xfa, 0x7a, 0xfe, 0xff, 0xed, 0x97, 0x96, 0xce, 0x6b, 0xa7, 0x7e,
+ 0x95, 0x11, 0xc9, 0x7f, 0xfb, 0x64, 0xef, 0x2d, 0x9c, 0xd7, 0x4e, 0xfd,
+ 0x2a, 0x27, 0x22, 0xff, 0x6c, 0xe6, 0xba, 0x77, 0xe9, 0x51, 0x66, 0x17,
+ 0x78, 0x0b, 0x17, 0xec, 0xf9, 0x66, 0x96, 0x2f, 0x4f, 0x1a, 0x58, 0xbf,
+ 0x4b, 0x8e, 0x7d, 0x9f, 0x9e, 0xe9, 0x0c, 0x70, 0x9e, 0xf8, 0x2d, 0xc2,
+ 0x81, 0x40, 0xb7, 0x58, 0xbf, 0xc3, 0xc3, 0xc7, 0x70, 0x75, 0x8a, 0x0a,
+ 0x1f, 0x70, 0x5b, 0x9d, 0x5b, 0x7a, 0xc5, 0xfe, 0xd4, 0x7b, 0xef, 0xdc,
+ 0x96, 0x2f, 0xff, 0xff, 0xa2, 0x6f, 0xc7, 0xa0, 0x36, 0xd4, 0xd1, 0xfc,
+ 0xdf, 0x9f, 0xc1, 0xef, 0xc5, 0x8a, 0x02, 0x2d, 0xc8, 0xd6, 0xff, 0xb3,
+ 0x8f, 0xe0, 0x06, 0x52, 0x58, 0xb0, 0x16, 0x2f, 0xee, 0x6b, 0x59, 0xdf,
+ 0x16, 0x28, 0x28, 0x78, 0x58, 0x25, 0x7e, 0xe4, 0x00, 0x39, 0xd6, 0x2f,
+ 0x6b, 0x0e, 0xb1, 0x7c, 0xc5, 0x9c, 0x58, 0xb6, 0x70, 0xfa, 0x7c, 0x56,
+ 0x10, 0x76, 0xff, 0xff, 0xdf, 0x82, 0x17, 0x39, 0x01, 0xf9, 0x88, 0x52,
+ 0xce, 0x79, 0x96, 0x2e, 0x9f, 0x16, 0x2f, 0xc5, 0x9b, 0xf0, 0x96, 0x2f,
+ 0xbd, 0xe6, 0xd2, 0xc5, 0xdc, 0x02, 0xc5, 0x49, 0x1c, 0xe6, 0xb6, 0x30,
+ 0xc6, 0x8a, 0x3c, 0x47, 0x6f, 0x2c, 0x58, 0x22, 0xc5, 0x6e, 0x1a, 0x60,
+ 0xc4, 0xae, 0xfc, 0xcb, 0x17, 0x17, 0x4b, 0x15, 0x23, 0x62, 0xe3, 0x37,
+ 0xb9, 0x1c, 0x58, 0xbb, 0x73, 0x8b, 0x17, 0x10, 0x16, 0x2f, 0xce, 0x64,
+ 0xf8, 0x62, 0xc5, 0x4e, 0x7b, 0xae, 0x36, 0x42, 0xf6, 0xfa, 0xc5, 0xf1,
+ 0xbf, 0x6e, 0x2c, 0x56, 0xc4, 0x6d, 0x84, 0x25, 0x66, 0x58, 0xbf, 0xd1,
+ 0xc8, 0xf4, 0xf8, 0x62, 0xc5, 0x98, 0xe7, 0x8c, 0x42, 0x37, 0x75, 0x25,
+ 0x8b, 0xf7, 0xb8, 0x51, 0x25, 0x8b, 0xe3, 0x3d, 0x06, 0xac, 0x54, 0x1f,
+ 0x36, 0x0c, 0xb1, 0x45, 0xf6, 0x0d, 0xe4, 0xb1, 0x7e, 0x06, 0x70, 0x3f,
+ 0xac, 0x5d, 0xe9, 0xd6, 0x2e, 0xdf, 0x0b, 0x17, 0xfc, 0x3f, 0xc7, 0x39,
+ 0x9a, 0x85, 0x8b, 0xb7, 0xc2, 0xc5, 0xdb, 0xe1, 0x62, 0xa4, 0x8e, 0x9e,
+ 0xc8, 0x98, 0xa8, 0xe3, 0x24, 0x33, 0xc3, 0x9d, 0xc1, 0x9b, 0xc3, 0x81,
+ 0x2c, 0x5c, 0x07, 0x58, 0xbb, 0x09, 0x62, 0xe0, 0x09, 0x62, 0xa0, 0xd7,
+ 0x68, 0x5a, 0xf9, 0xe5, 0xfc, 0x58, 0xbd, 0xec, 0x85, 0x8a, 0x19, 0xbe,
+ 0xec, 0x8a, 0xee, 0xa1, 0x62, 0x86, 0x89, 0x8c, 0x5e, 0xe8, 0x8a, 0xc1,
+ 0xac, 0x5f, 0xfe, 0xea, 0x39, 0xcc, 0x3f, 0x7e, 0x11, 0x79, 0x62, 0xf7,
+ 0xb0, 0xeb, 0x17, 0xfa, 0x01, 0x85, 0x1d, 0xf1, 0x62, 0xf0, 0x33, 0x8b,
+ 0x15, 0xb5, 0x19, 0xb8, 0x26, 0xc9, 0xbc, 0x1d, 0xf1, 0x9d, 0xfc, 0xe5,
+ 0xed, 0xc7, 0x35, 0x62, 0xfd, 0xd7, 0xdd, 0x82, 0xeb, 0x17, 0xe1, 0x72,
+ 0x39, 0x0b, 0x15, 0xa3, 0xd5, 0x72, 0xdb, 0xf8, 0x81, 0xfc, 0x03, 0xac,
+ 0x5f, 0x14, 0x6f, 0x12, 0xc5, 0x31, 0xe8, 0xb9, 0x6d, 0x8e, 0xb1, 0x71,
+ 0xbb, 0x8b, 0x15, 0xd9, 0xae, 0x61, 0x2b, 0xf8, 0x7b, 0x76, 0x32, 0xc0,
+ 0x8b, 0x14, 0xb1, 0x7f, 0xc4, 0x0c, 0xf4, 0x13, 0x01, 0x62, 0xb0, 0xf0,
+ 0xdc, 0x32, 0xa1, 0x13, 0x5b, 0x8f, 0x57, 0x88, 0x53, 0x2c, 0x5b, 0x64,
+ 0x28, 0xcb, 0xfd, 0x0a, 0x96, 0xc4, 0x32, 0xe7, 0x22, 0x93, 0xe0, 0xe1,
+ 0x1d, 0x91, 0x8e, 0x9a, 0xe1, 0xd2, 0xb7, 0x64, 0x13, 0x3d, 0x69, 0x90,
+ 0xed, 0x9f, 0x84, 0x63, 0xc6, 0x2a, 0x06, 0x60, 0xb8, 0xe9, 0x43, 0x77,
+ 0x90, 0xfd, 0xf2, 0x50, 0xa1, 0x0d, 0xbd, 0xcb, 0x71, 0x38, 0x38, 0x5d,
+ 0x84, 0x25, 0xbf, 0x6b, 0xa7, 0x7e, 0x95, 0x16, 0xe9, 0x71, 0x09, 0x62,
+ 0xdc, 0x58, 0xac, 0x3e, 0x0d, 0x1b, 0x80, 0x5e, 0xf7, 0xe3, 0x4b, 0x17,
+ 0xe9, 0x8b, 0xbc, 0xe9, 0x62, 0xff, 0xc2, 0x19, 0x39, 0xb8, 0x37, 0x92,
+ 0xc5, 0xb6, 0x46, 0x88, 0x7c, 0x1d, 0xe1, 0x5d, 0x6c, 0xa3, 0xb7, 0xf0,
+ 0xb5, 0xbf, 0x30, 0x39, 0x81, 0x16, 0x2f, 0xe2, 0x7d, 0x9d, 0x4f, 0xf5,
+ 0x8b, 0xd9, 0x9d, 0x2c, 0x5e, 0x6e, 0xc0, 0xb1, 0x7e, 0xee, 0x5f, 0x60,
+ 0x2c, 0x5f, 0xfd, 0xa7, 0xe8, 0x02, 0xe7, 0xa3, 0xb3, 0x16, 0x2e, 0x23,
+ 0x56, 0x2c, 0xeb, 0x17, 0xdd, 0x3b, 0xf4, 0xa8, 0xa4, 0x0a, 0xc3, 0xda,
+ 0x98, 0x63, 0x42, 0x37, 0xfa, 0x5e, 0x63, 0x38, 0x06, 0x58, 0xbf, 0xb7,
+ 0x7a, 0xfc, 0x36, 0x96, 0x2f, 0x66, 0x74, 0xb1, 0x7b, 0x1b, 0xeb, 0x17,
+ 0xfe, 0x7d, 0xc8, 0x2e, 0xb3, 0xdf, 0x65, 0x8b, 0xff, 0x67, 0xdb, 0x7f,
+ 0xf3, 0x0b, 0xa5, 0x8b, 0xfb, 0x3f, 0x9f, 0x63, 0x56, 0x2f, 0xde, 0x8d,
+ 0xed, 0xbd, 0x62, 0xf3, 0xcb, 0x66, 0x15, 0x3b, 0x8c, 0xab, 0x21, 0x47,
+ 0xd9, 0x7b, 0x1a, 0xcc, 0x65, 0xf1, 0xd2, 0x1c, 0xe2, 0x0f, 0x90, 0x37,
+ 0x97, 0x5f, 0x67, 0x3e, 0x25, 0x8b, 0xfa, 0x0b, 0x9c, 0x63, 0xac, 0x56,
0x1e, 0x83, 0x11, 0xdf, 0xe6, 0x18, 0xbd, 0xc3, 0x92, 0xc5, 0xf1, 0x87,
- 0x9e, 0x2c, 0x5e, 0x72, 0x82, 0xc5, 0x82, 0x4a, 0xbd, 0x2e, 0x8a, 0xf4,
- 0x62, 0x79, 0x40, 0xdf, 0x86, 0xe3, 0x90, 0x08, 0xd0, 0xc2, 0x4b, 0xff,
- 0x82, 0x3c, 0x02, 0x66, 0xba, 0x77, 0xe9, 0x51, 0x29, 0x15, 0x1b, 0x69,
- 0x03, 0x12, 0xb9, 0xd7, 0x5e, 0x14, 0x20, 0xa5, 0xc7, 0x94, 0xac, 0x3f,
- 0x4b, 0xfc, 0xdd, 0x84, 0x3d, 0xe0, 0x8f, 0xd2, 0xc5, 0xfc, 0xc5, 0x9f,
- 0xce, 0x96, 0x2f, 0xe6, 0x2f, 0x63, 0x0d, 0x62, 0xe8, 0x79, 0x62, 0xf1,
- 0x49, 0x8b, 0x17, 0x48, 0x4d, 0x1b, 0x52, 0x18, 0xa8, 0x22, 0x3b, 0xcc,
- 0x37, 0xb8, 0x23, 0xac, 0x5a, 0x0b, 0x17, 0x71, 0xd6, 0x2c, 0x14, 0x58,
- 0xb0, 0x48, 0x26, 0x77, 0xdc, 0x2e, 0xd8, 0x8e, 0x21, 0xe0, 0x09, 0x6c,
- 0x8b, 0xdf, 0xf3, 0x7b, 0x93, 0x13, 0xbe, 0x96, 0x2f, 0xff, 0xb3, 0xcd,
- 0xf1, 0x7d, 0xdb, 0xbe, 0x49, 0xab, 0x17, 0x89, 0xe0, 0xb1, 0x7e, 0xd8,
- 0xc2, 0xba, 0xe7, 0x16, 0x2f, 0xff, 0x37, 0x60, 0xd6, 0x0e, 0x74, 0xdd,
- 0x81, 0x62, 0xfd, 0xae, 0x9d, 0xfa, 0x54, 0x4e, 0xc5, 0xf9, 0xf5, 0xd6,
- 0xb1, 0x62, 0xff, 0x37, 0x38, 0xdf, 0x9e, 0x2c, 0x54, 0x67, 0xb8, 0x72,
- 0x9b, 0xdf, 0x73, 0x16, 0x2f, 0xf8, 0x9e, 0x02, 0x01, 0xde, 0x0b, 0x16,
- 0xc1, 0x9e, 0xbf, 0xc7, 0xaf, 0xf8, 0xd6, 0xf7, 0x1b, 0xa7, 0xd2, 0xc5,
- 0xe7, 0x80, 0x40, 0xb6, 0x9f, 0x74, 0x99, 0xe2, 0x63, 0xc2, 0x4c, 0x9e,
- 0x83, 0x27, 0xb6, 0xe2, 0xc5, 0xff, 0xfd, 0x84, 0x4f, 0xef, 0xe7, 0x1f,
- 0x34, 0x03, 0xe2, 0xc5, 0x46, 0x7d, 0xae, 0x2b, 0x7f, 0xfe, 0x61, 0x88,
- 0xf3, 0xba, 0xe3, 0x29, 0x2c, 0xe9, 0x62, 0xff, 0x42, 0x75, 0x1c, 0xea,
- 0x35, 0x8b, 0xff, 0x7c, 0x9e, 0x02, 0x01, 0xde, 0x0b, 0x15, 0x27, 0xeb,
- 0x86, 0xd7, 0x18, 0xcb, 0x17, 0xf9, 0xe3, 0x7c, 0xf6, 0x1d, 0x62, 0xff,
- 0xfd, 0x9d, 0xc3, 0xf3, 0xc7, 0xd4, 0xee, 0xfd, 0xfa, 0x58, 0xb0, 0x48,
- 0x2e, 0x93, 0x8c, 0xe7, 0x14, 0x4f, 0x28, 0x2b, 0xf0, 0xe0, 0x72, 0x22,
- 0x86, 0x61, 0x84, 0x1b, 0x23, 0x1b, 0xa6, 0x77, 0xd2, 0x39, 0x25, 0x8b,
- 0xe6, 0xd4, 0xef, 0x58, 0xbb, 0x3e, 0xb1, 0x7f, 0xf6, 0xcb, 0x90, 0x33,
- 0xd2, 0x4c, 0x05, 0x8b, 0x04, 0x24, 0x50, 0xf0, 0x87, 0x64, 0x90, 0x31,
- 0x7b, 0xff, 0x9c, 0xff, 0xce, 0x9f, 0xf2, 0x1c, 0x16, 0x2f, 0xde, 0xd6,
- 0x49, 0x8b, 0x17, 0x98, 0x6e, 0xb1, 0x7f, 0xf1, 0x67, 0xde, 0x3c, 0xe1,
- 0x3f, 0x6b, 0x17, 0x6c, 0x84, 0x1a, 0x33, 0xd9, 0x1b, 0xe5, 0x3c, 0x1c,
- 0xa9, 0x64, 0xcd, 0xc2, 0x35, 0xb3, 0xce, 0xc8, 0x72, 0x34, 0xcd, 0x98,
- 0xc5, 0xef, 0xfe, 0xd3, 0xf6, 0x10, 0x79, 0x13, 0xbc, 0x6b, 0x17, 0xfd,
- 0x25, 0xd8, 0x39, 0xc9, 0x02, 0xc5, 0xf6, 0xb0, 0xcf, 0x2c, 0x57, 0x0f,
- 0x7b, 0x79, 0xd5, 0xfe, 0xd6, 0x70, 0x84, 0xe1, 0xac, 0x5f, 0xff, 0xff,
- 0xf7, 0xdb, 0xce, 0xfd, 0xf3, 0x9c, 0x93, 0xcf, 0xf3, 0x23, 0xc2, 0xce,
- 0xfd, 0xc9, 0xed, 0x62, 0xff, 0x4c, 0x1b, 0xcc, 0x50, 0x58, 0xbf, 0xff,
- 0xf7, 0x42, 0x8f, 0x37, 0xcf, 0x78, 0x37, 0x80, 0x67, 0xe6, 0x38, 0xd6,
- 0x2e, 0xf0, 0x4c, 0x4e, 0x44, 0xd2, 0x4e, 0x8d, 0x35, 0x09, 0x5e, 0x19,
- 0x58, 0x6c, 0xaa, 0x5d, 0xe5, 0x1c, 0x5f, 0xfd, 0x17, 0x7c, 0x63, 0xed,
- 0x0f, 0x59, 0x1a, 0xc5, 0xf7, 0x4e, 0xfd, 0x2a, 0x22, 0xc2, 0xfe, 0x6d,
- 0x39, 0x75, 0x2b, 0x17, 0xcc, 0x45, 0x2b, 0x15, 0xa3, 0xfe, 0xf9, 0x8e,
- 0xf2, 0xdb, 0xec, 0xf0, 0x19, 0x62, 0xff, 0xcf, 0x00, 0x99, 0xae, 0x9d,
- 0xfa, 0x54, 0x4b, 0xa5, 0xfe, 0x71, 0xc9, 0x7e, 0x78, 0xb1, 0x7d, 0xa6,
- 0x14, 0x6b, 0x17, 0xff, 0xf6, 0x0f, 0xf2, 0x18, 0x4f, 0x13, 0x83, 0x9c,
- 0x90, 0x24, 0x58, 0x24, 0xaa, 0x20, 0xc8, 0x65, 0x68, 0xc4, 0xe4, 0x5f,
- 0x4f, 0xf1, 0x96, 0xc9, 0x25, 0xff, 0xc7, 0x78, 0x04, 0xcd, 0x74, 0xef,
- 0xd2, 0xa2, 0x62, 0x2f, 0xef, 0xc9, 0x77, 0x13, 0xac, 0x5f, 0xf3, 0xb9,
- 0x67, 0x9b, 0xb3, 0x16, 0x2f, 0xf3, 0xb6, 0xcb, 0x03, 0x06, 0xb1, 0x7f,
- 0xfe, 0x27, 0x01, 0xdb, 0x6e, 0x7d, 0xa6, 0x0f, 0x05, 0x8b, 0xec, 0xea,
- 0x42, 0x4a, 0x3c, 0x8e, 0x5f, 0xf3, 0x9f, 0x1a, 0xd0, 0x44, 0xe7, 0x3f,
- 0x1a, 0x3d, 0xfe, 0xfb, 0x9c, 0x23, 0x88, 0x6b, 0x17, 0xed, 0x74, 0xef,
- 0xd2, 0xa2, 0xa9, 0x2d, 0x8b, 0x15, 0x87, 0x90, 0x69, 0xbd, 0xff, 0x6b,
- 0x4c, 0x45, 0x82, 0xe9, 0x62, 0xff, 0xc2, 0x7d, 0x40, 0xb0, 0xc7, 0x02,
- 0xc5, 0xff, 0xcf, 0xcd, 0x31, 0x9e, 0xfb, 0x6a, 0x0b, 0x17, 0xfd, 0xa7,
- 0xff, 0x70, 0xcf, 0x04, 0x94, 0x5f, 0x0c, 0xe7, 0xe7, 0xf4, 0x11, 0x34,
- 0x07, 0x87, 0x05, 0xff, 0x82, 0x7e, 0x4f, 0x83, 0x92, 0xf2, 0xc5, 0xef,
- 0x34, 0x6b, 0x17, 0xfe, 0x78, 0x04, 0xcd, 0x74, 0xef, 0xd2, 0xa2, 0x74,
- 0x2f, 0x85, 0xc6, 0x02, 0xc5, 0xe6, 0xec, 0xc5, 0x8a, 0x01, 0xe1, 0x70,
- 0x8e, 0x8d, 0x46, 0x89, 0xc7, 0x81, 0x09, 0x1b, 0xe6, 0xcd, 0x6f, 0x58,
- 0xbe, 0x72, 0xf7, 0x16, 0x2f, 0xa3, 0x29, 0x8d, 0x62, 0xf8, 0xf2, 0x68,
- 0x4d, 0xc3, 0xea, 0x39, 0x20, 0x88, 0xaf, 0xfc, 0x01, 0x70, 0x20, 0xcc,
- 0x72, 0x82, 0xc5, 0x04, 0x4c, 0xbd, 0xa1, 0x40, 0x04, 0xcb, 0xfc, 0xcf,
- 0xa9, 0x83, 0xef, 0x58, 0xbe, 0x62, 0x03, 0x2c, 0x5f, 0xa2, 0x98, 0xa7,
- 0x8b, 0x17, 0xf1, 0x98, 0xdb, 0xf0, 0x96, 0x29, 0x8f, 0x67, 0x85, 0x57,
- 0x9b, 0xf2, 0xb0, 0x10, 0xd0, 0xdf, 0xfc, 0x2e, 0x7a, 0x7b, 0x08, 0x28,
- 0x98, 0xeb, 0x15, 0x04, 0xc4, 0xcf, 0x09, 0xbf, 0x97, 0x5d, 0xfe, 0x2c,
- 0x5f, 0xb5, 0xd3, 0xbf, 0x4a, 0x89, 0xdc, 0xbf, 0xff, 0xa4, 0xe2, 0xd4,
- 0x52, 0x7d, 0xa7, 0xcf, 0x71, 0xb8, 0xb1, 0x79, 0xe0, 0x13, 0x11, 0x2d,
- 0xe3, 0x7b, 0xf7, 0x84, 0xe7, 0x64, 0x8b, 0xff, 0x14, 0xfb, 0x39, 0x99,
- 0xdc, 0x16, 0x2f, 0xff, 0xc5, 0xac, 0x33, 0x37, 0x27, 0xf2, 0xc4, 0x39,
- 0x58, 0xa1, 0xab, 0x1c, 0xc8, 0xd1, 0xfa, 0x36, 0x3c, 0x2b, 0x9c, 0xd7,
- 0xc5, 0x01, 0x9f, 0x5f, 0xf0, 0xe6, 0x12, 0x10, 0xce, 0x01, 0x62, 0xfd,
- 0xc2, 0x90, 0x71, 0x62, 0xf1, 0x60, 0xd6, 0x2e, 0x90, 0x92, 0x78, 0x80,
- 0x28, 0xa0, 0x89, 0x90, 0x63, 0x89, 0x42, 0x06, 0xff, 0xbd, 0xc6, 0x3b,
- 0x78, 0x0e, 0xb1, 0x77, 0xa5, 0x62, 0xee, 0x04, 0x93, 0xd0, 0xe8, 0xe6,
- 0xff, 0xf0, 0x43, 0xbc, 0x02, 0x66, 0xba, 0x77, 0xe9, 0x51, 0x42, 0x97,
- 0x4e, 0x96, 0x2f, 0xc0, 0x98, 0xf0, 0xc5, 0x8b, 0xff, 0x3f, 0xa1, 0x84,
- 0xc3, 0x09, 0xc8, 0xcf, 0x04, 0x02, 0xf7, 0xc4, 0xfa, 0xde, 0xb1, 0x78,
- 0xee, 0x62, 0xc5, 0x82, 0x49, 0xe1, 0x46, 0x49, 0x74, 0x6c, 0xb1, 0x7f,
- 0xfb, 0xe2, 0xf4, 0x96, 0x46, 0x68, 0xa6, 0x25, 0x8b, 0xf8, 0x47, 0x3b,
- 0xc0, 0x24, 0x9f, 0x2f, 0x43, 0x17, 0xff, 0xfe, 0x2c, 0xde, 0xdf, 0x10,
- 0x4e, 0xbe, 0xdf, 0x29, 0xcd, 0x61, 0xd6, 0x2a, 0x09, 0xa2, 0xfe, 0x11,
- 0xfc, 0x47, 0xbf, 0x0b, 0xbf, 0x37, 0x4b, 0x17, 0xec, 0x06, 0x39, 0x2c,
- 0x5f, 0xfd, 0xbd, 0xbd, 0x3f, 0x2c, 0xf6, 0xa5, 0x62, 0xf3, 0x19, 0xe5,
- 0x8a, 0xc3, 0xe3, 0xe2, 0x2d, 0xff, 0x1e, 0x28, 0x3e, 0xa3, 0xf8, 0x96,
- 0x2f, 0x48, 0x02, 0x46, 0x98, 0x91, 0x15, 0xfa, 0x11, 0x21, 0x90, 0xd3,
- 0x27, 0x3e, 0x51, 0xa4, 0x5f, 0xff, 0x85, 0xd0, 0x47, 0xf7, 0xf0, 0xf3,
- 0xa2, 0x90, 0x2c, 0x5f, 0xf1, 0xdf, 0x98, 0x64, 0x90, 0xd6, 0x2f, 0xfc,
- 0xf0, 0x09, 0x9a, 0xe9, 0xdf, 0xa5, 0x45, 0x24, 0x5f, 0xec, 0xf9, 0x60,
- 0xfe, 0x25, 0x8b, 0xd2, 0x43, 0x58, 0xb0, 0x48, 0xd3, 0x2f, 0xc5, 0x83,
- 0x9c, 0xf9, 0x3c, 0xc3, 0x3b, 0xff, 0xfe, 0xc2, 0x17, 0x27, 0x0b, 0xc4,
- 0xe6, 0xe4, 0x52, 0x43, 0x58, 0xb8, 0xe4, 0xb1, 0x7f, 0xf4, 0x5f, 0x73,
- 0xfb, 0xf3, 0xe1, 0x1d, 0x62, 0xfb, 0x0a, 0x63, 0x58, 0xac, 0x3e, 0x9d,
- 0x23, 0xde, 0xce, 0x04, 0x24, 0xc1, 0x78, 0xc8, 0x1c, 0x20, 0x2a, 0x5b,
- 0x4f, 0x18, 0xe5, 0x28, 0x42, 0x50, 0x86, 0x16, 0x75, 0x1d, 0xf4, 0x45,
- 0x5a, 0x94, 0x80, 0x79, 0xc7, 0x37, 0x84, 0x30, 0x0c, 0x0a, 0x13, 0xde,
- 0x96, 0xfa, 0x28, 0xd5, 0xf6, 0x63, 0x59, 0xb8, 0x28, 0x16, 0xd6, 0x2f,
- 0xba, 0x77, 0xe9, 0x51, 0x12, 0x17, 0xff, 0xe6, 0xd7, 0xdf, 0x6c, 0x5f,
- 0x98, 0xc2, 0xfa, 0x9d, 0x95, 0x8a, 0xd2, 0x24, 0xbe, 0x63, 0x7f, 0xff,
- 0xbf, 0x31, 0x85, 0xf5, 0x3b, 0x21, 0x34, 0xd2, 0x78, 0xf0, 0xc5, 0x8b,
- 0xf3, 0x7b, 0xf8, 0x75, 0x8b, 0x04, 0x0a, 0x26, 0xd9, 0x90, 0xb4, 0x88,
- 0x8c, 0x2e, 0xdb, 0x7b, 0x4f, 0xa5, 0x8b, 0xff, 0x3c, 0x02, 0x66, 0xba,
- 0x77, 0xe9, 0x51, 0x2f, 0x17, 0xcf, 0xe7, 0x8d, 0x62, 0xc1, 0x19, 0x11,
- 0xe7, 0x1d, 0xd9, 0x4f, 0xbf, 0xfa, 0x77, 0xbc, 0x4d, 0xae, 0xe1, 0x31,
- 0x2c, 0x5e, 0xd8, 0x8e, 0x05, 0x8b, 0xf0, 0x54, 0x33, 0x94, 0xac, 0x5d,
- 0x11, 0x2c, 0x5f, 0xfb, 0x61, 0x3b, 0x0c, 0x52, 0x53, 0x05, 0x8b, 0xfe,
- 0xdb, 0x3e, 0x6d, 0x4e, 0xf8, 0x96, 0x2f, 0xff, 0x7e, 0x78, 0x18, 0xe7,
- 0x51, 0x61, 0x01, 0x62, 0xfb, 0x42, 0xf7, 0x16, 0x2f, 0xe1, 0xb1, 0xae,
- 0x40, 0x58, 0xbf, 0x49, 0x00, 0x67, 0x58, 0xbf, 0x68, 0x07, 0x6e, 0x2c,
- 0x5c, 0x03, 0xac, 0x5e, 0x92, 0xed, 0x62, 0xfd, 0xe0, 0xce, 0x52, 0xb1,
- 0x66, 0xd1, 0xef, 0x7c, 0x60, 0x87, 0x6f, 0xff, 0x7f, 0x7c, 0x90, 0x37,
- 0x30, 0x79, 0xae, 0xd6, 0x2f, 0xf3, 0x69, 0xc6, 0xc4, 0x6a, 0xc5, 0xd3,
- 0xe5, 0x8b, 0xfe, 0x78, 0xf5, 0x3d, 0xc1, 0x8e, 0xb1, 0x7f, 0xf8, 0x43,
- 0x6d, 0x07, 0x16, 0xe8, 0x9c, 0xa2, 0x58, 0xa8, 0x26, 0xb2, 0xc6, 0x7f,
- 0x50, 0x01, 0x99, 0x0b, 0xf0, 0xee, 0xfe, 0x07, 0xe7, 0x4c, 0x75, 0x8b,
- 0xff, 0x45, 0xc9, 0xde, 0xff, 0x9e, 0xe2, 0x58, 0xa9, 0x3f, 0x27, 0x2e,
- 0xbd, 0xba, 0x19, 0xd6, 0x2e, 0xf8, 0x16, 0x29, 0x8d, 0xd3, 0x91, 0x5f,
- 0xb2, 0x3c, 0xe1, 0xd6, 0x2f, 0xda, 0x9f, 0x36, 0xf5, 0x8b, 0xf4, 0x6f,
- 0xc7, 0x02, 0xc5, 0x31, 0xe9, 0xb9, 0x55, 0xff, 0xd1, 0x6d, 0x0c, 0xa7,
- 0x7b, 0xef, 0x98, 0x96, 0x29, 0x62, 0xfb, 0xd9, 0xa8, 0x96, 0x2f, 0x79,
- 0xf7, 0xac, 0x5a, 0x18, 0x78, 0x6e, 0x49, 0x7e, 0x7e, 0x4e, 0xfc, 0x58,
- 0xa8, 0x8f, 0x3f, 0x79, 0x35, 0x4a, 0x62, 0x18, 0x9a, 0xf0, 0x9e, 0xbb,
- 0x52, 0xb1, 0x5b, 0x12, 0xf0, 0xdc, 0x0f, 0x86, 0x99, 0x84, 0x9d, 0x97,
- 0x31, 0x44, 0x51, 0xf0, 0x6a, 0x19, 0x1f, 0x5a, 0x21, 0xff, 0x3e, 0x6f,
- 0x8c, 0xc3, 0x74, 0xce, 0xec, 0x25, 0x8b, 0xfb, 0x6f, 0x3f, 0x8d, 0xe5,
- 0x8a, 0x19, 0xe3, 0x30, 0xb5, 0xbb, 0x58, 0xbf, 0xe0, 0x3f, 0xa3, 0x14,
- 0x53, 0xb8, 0xb1, 0x43, 0x3d, 0x26, 0x13, 0xbf, 0x88, 0x5e, 0x8a, 0x4d,
- 0x58, 0xbc, 0x17, 0x6d, 0x2c, 0x53, 0x9e, 0x88, 0x8c, 0x2f, 0xfe, 0xc6,
- 0xef, 0x9e, 0x98, 0xce, 0xf0, 0x58, 0xa6, 0x3e, 0x7d, 0x10, 0xdf, 0xe1,
- 0x7b, 0xe5, 0x39, 0xa5, 0x8b, 0xf1, 0x64, 0x61, 0xef, 0x58, 0xbe, 0xc8,
- 0xc3, 0xde, 0xb1, 0x7e, 0x1c, 0xf6, 0x37, 0xda, 0x7a, 0x64, 0x59, 0x7f,
- 0xfc, 0xda, 0xdb, 0xf9, 0x6f, 0x70, 0x5d, 0x0a, 0x56, 0x2f, 0x9a, 0x30,
- 0x6e, 0x2c, 0x5b, 0xb5, 0x8b, 0xce, 0xfd, 0x2a, 0x29, 0x72, 0x96, 0x2b,
- 0x0f, 0x27, 0xa1, 0x38, 0x8a, 0xaf, 0x8b, 0xd3, 0xa5, 0x8b, 0xfe, 0xcd,
- 0x6e, 0x60, 0xf3, 0x5d, 0xac, 0x53, 0x1e, 0xfe, 0xf2, 0x2b, 0xff, 0x4c,
- 0x3e, 0xed, 0xdf, 0x24, 0xd5, 0x8a, 0x8d, 0x53, 0xdc, 0x21, 0x0c, 0x6a,
- 0x04, 0x4a, 0x7a, 0x70, 0xfc, 0x23, 0xc8, 0x8e, 0xff, 0x9b, 0xdc, 0x7e,
- 0xf5, 0xce, 0x2c, 0x5f, 0xfe, 0xd4, 0x7b, 0x77, 0x8b, 0xf2, 0xc7, 0x91,
- 0xac, 0x57, 0xd1, 0x16, 0xe7, 0x77, 0xa7, 0x5e, 0x58, 0xbf, 0x87, 0xdc,
- 0xe9, 0xbb, 0x58, 0xbe, 0xf4, 0x78, 0x62, 0xc5, 0x40, 0xfc, 0x98, 0x74,
- 0x8c, 0x2f, 0xff, 0xd1, 0x3e, 0xa3, 0xf3, 0x6e, 0x64, 0x6f, 0x14, 0xee,
- 0x2c, 0x5f, 0x1b, 0xac, 0xe2, 0xc5, 0x4a, 0x20, 0xd9, 0x7e, 0xff, 0xd2,
- 0x53, 0xfd, 0xa2, 0x21, 0x74, 0xb1, 0x78, 0x4f, 0xc5, 0x8b, 0xc7, 0x28,
- 0x96, 0x2f, 0x09, 0xe2, 0x58, 0xac, 0x37, 0x91, 0x0f, 0x5f, 0xa4, 0x0f,
- 0xdf, 0x16, 0x2f, 0x13, 0x01, 0x62, 0xf6, 0x7b, 0x8b, 0x15, 0x26, 0xe7,
- 0x83, 0x97, 0xff, 0xe7, 0xf7, 0xe4, 0x8d, 0xdb, 0x31, 0xfa, 0x77, 0xf1,
- 0x62, 0xa0, 0x9d, 0xc8, 0xc8, 0x62, 0x41, 0xfa, 0xc8, 0x08, 0x7c, 0xc5,
- 0xbc, 0x82, 0xff, 0xd8, 0x37, 0x20, 0x06, 0x72, 0x95, 0x8b, 0xe7, 0x21,
- 0xee, 0xac, 0x5f, 0xe2, 0xc8, 0x6d, 0xfc, 0xee, 0x2c, 0x56, 0xe1, 0xee,
- 0x9c, 0x96, 0x96, 0x2f, 0xdc, 0xf6, 0xa7, 0x8b, 0x16, 0x9e, 0xcd, 0xaf,
- 0x83, 0x2f, 0xf8, 0x1c, 0xd4, 0xf7, 0x06, 0x3a, 0xc5, 0xef, 0x3e, 0xf5,
- 0x8b, 0xf4, 0x62, 0x8a, 0x77, 0x16, 0x2f, 0x85, 0x14, 0xee, 0x2c, 0x5c,
- 0xf1, 0xed, 0x3d, 0x58, 0xcb, 0xaa, 0x51, 0xc0, 0xe7, 0x62, 0x74, 0xbf,
- 0xe9, 0x60, 0x72, 0x4e, 0xfe, 0x58, 0xbf, 0xe6, 0xe4, 0x4c, 0x5e, 0x90,
- 0x2c, 0x5f, 0xfc, 0x5e, 0xdf, 0x3a, 0xe3, 0x94, 0xee, 0x2c, 0x5f, 0xce,
- 0xd1, 0xed, 0x3e, 0x2c, 0x54, 0x13, 0x17, 0xd1, 0x71, 0xce, 0x38, 0x73,
- 0xe4, 0x8b, 0xfd, 0x3b, 0x9c, 0x93, 0xbf, 0x96, 0x2e, 0x72, 0x58, 0xbf,
- 0xe9, 0x06, 0xdf, 0xc9, 0xdc, 0x96, 0x2b, 0xb3, 0xd0, 0xde, 0x2d, 0x7f,
- 0xfd, 0x83, 0x0e, 0x2e, 0x7b, 0xf8, 0x31, 0x7b, 0x8b, 0x15, 0x04, 0x7f,
- 0xea, 0x10, 0xdf, 0x25, 0xbf, 0xa4, 0xc6, 0xf8, 0xb7, 0x16, 0x2f, 0xee,
- 0xe1, 0xc7, 0x2e, 0xd6, 0x2a, 0x57, 0x16, 0x60, 0xb5, 0x92, 0x87, 0x9a,
- 0x34, 0xad, 0x1a, 0x86, 0x65, 0x7f, 0xe2, 0x8b, 0x6e, 0xa7, 0xb8, 0x31,
- 0xd6, 0x2f, 0xff, 0x6f, 0x92, 0xf7, 0xbf, 0x83, 0x17, 0xb8, 0xb1, 0x7f,
- 0xff, 0xef, 0x6c, 0xe7, 0x83, 0xde, 0xfe, 0x0e, 0x36, 0xf9, 0x60, 0xdc,
- 0xeb, 0x17, 0x49, 0xd6, 0x2a, 0x53, 0x1b, 0xc4, 0x36, 0x4d, 0xd3, 0xa5,
- 0xf8, 0xa2, 0xf3, 0x1a, 0xb1, 0x74, 0xc1, 0x62, 0xfc, 0xc3, 0x11, 0x62,
- 0xc5, 0xff, 0xde, 0xfe, 0x43, 0x6c, 0x8f, 0xef, 0xda, 0xc5, 0x44, 0x7d,
- 0xe4, 0x4f, 0x52, 0x8d, 0x26, 0x2a, 0x14, 0x21, 0xaf, 0xfa, 0x19, 0xa8,
- 0xb0, 0xa4, 0xeb, 0x17, 0xe0, 0x4f, 0x58, 0x75, 0x8b, 0xfd, 0x91, 0xf2,
- 0x62, 0x16, 0x96, 0x2f, 0xc7, 0xc7, 0x68, 0xd6, 0x29, 0x91, 0x81, 0xa3,
- 0x92, 0x29, 0xe1, 0xb5, 0xd0, 0xc5, 0x8b, 0xf7, 0x0d, 0xd3, 0x98, 0xb1,
- 0x78, 0xa4, 0xeb, 0x14, 0x33, 0xc7, 0xd1, 0x5d, 0xf7, 0x7b, 0x99, 0x05,
- 0x8b, 0xfc, 0xfa, 0x8b, 0x3d, 0xbb, 0xbd, 0x62, 0xe0, 0x71, 0x62, 0xf0,
- 0xf8, 0xcb, 0x15, 0x26, 0xd5, 0xc6, 0x2a, 0x53, 0x70, 0x19, 0xde, 0x2f,
- 0x39, 0x10, 0x89, 0xcc, 0x6f, 0xbe, 0x7f, 0xbc, 0x6b, 0x17, 0xef, 0x88,
- 0xdc, 0x25, 0x8b, 0xc6, 0x3c, 0x16, 0x2f, 0xf1, 0x84, 0xfe, 0x83, 0x8d,
- 0x62, 0xfd, 0xe0, 0xe3, 0x9f, 0xac, 0x5f, 0xb3, 0xde, 0x63, 0x56, 0x2f,
- 0xfa, 0x7f, 0xc7, 0xf4, 0xeb, 0x75, 0x62, 0xff, 0xc7, 0x71, 0x87, 0x14,
- 0x24, 0xbb, 0x58, 0xa1, 0x9f, 0xf3, 0x1e, 0x5f, 0xc2, 0xfc, 0xeb, 0x00,
- 0xb1, 0x7b, 0x7c, 0xe9, 0x62, 0xfb, 0x40, 0x0f, 0x7a, 0xc5, 0xe6, 0x33,
- 0xcb, 0x15, 0x04, 0x49, 0x31, 0x77, 0xc7, 0xf8, 0x4f, 0x51, 0xaa, 0x5f,
- 0x19, 0x1e, 0x14, 0xf6, 0x3d, 0x11, 0xa6, 0x8a, 0xff, 0x0a, 0x7f, 0x42,
- 0xce, 0xff, 0x17, 0xb3, 0x8c, 0xff, 0x58, 0xbe, 0xe4, 0x38, 0xeb, 0x17,
- 0xfc, 0x06, 0xfe, 0x69, 0xe2, 0xe2, 0xc5, 0xff, 0xf4, 0x0a, 0x63, 0x0e,
- 0x2e, 0x7f, 0x37, 0x74, 0x05, 0x8b, 0xd0, 0x1e, 0xf5, 0x8a, 0x93, 0xf7,
- 0x75, 0x7b, 0xfb, 0x69, 0xf3, 0xcf, 0xe5, 0x8b, 0xfb, 0xec, 0x36, 0xd7,
- 0x4b, 0x14, 0xb1, 0x7c, 0xe5, 0xdc, 0x16, 0x2b, 0xa3, 0x5f, 0xf0, 0xcb,
- 0x73, 0x11, 0x61, 0xd1, 0x83, 0xaf, 0x5e, 0xee, 0x2e, 0x2c, 0x57, 0x67,
- 0xaa, 0xe6, 0xb7, 0xa5, 0x86, 0xb1, 0x7f, 0xa2, 0xfb, 0x78, 0xa4, 0xeb,
- 0x17, 0x3e, 0xf5, 0x8a, 0x95, 0x56, 0xc3, 0x32, 0xec, 0x8c, 0xf0, 0xb1,
- 0x78, 0xc9, 0x78, 0x44, 0x21, 0xcd, 0xd3, 0x4b, 0xfd, 0x86, 0x41, 0xb8,
- 0x23, 0xac, 0x5d, 0xbf, 0x8b, 0x17, 0xf0, 0xb9, 0x31, 0x0b, 0x4b, 0x17,
- 0xec, 0x8f, 0x3f, 0xc5, 0x8a, 0x93, 0xf3, 0xf8, 0xd1, 0x18, 0x5f, 0x1c,
- 0x51, 0x69, 0x62, 0xed, 0x71, 0x62, 0xff, 0xd9, 0xcd, 0xbf, 0x96, 0x21,
- 0x46, 0xb1, 0x58, 0x7b, 0x24, 0x31, 0x5d, 0x23, 0x2c, 0xe5, 0xbb, 0xdf,
- 0xaf, 0xf8, 0x12, 0x00, 0xf7, 0xc9, 0x6e, 0xac, 0x5f, 0xff, 0xa3, 0x9f,
- 0x4f, 0xdb, 0xd0, 0x6d, 0x75, 0xf9, 0x58, 0xa9, 0x54, 0x79, 0x91, 0xb9,
- 0xb1, 0x9b, 0x9f, 0xdf, 0xff, 0xf6, 0xbb, 0xe9, 0xbb, 0xda, 0x6b, 0xed,
- 0xe7, 0xdf, 0xa9, 0x21, 0xac, 0x5f, 0xf3, 0xf0, 0x3f, 0x77, 0xd3, 0x1d,
- 0x62, 0xdf, 0x94, 0x56, 0x89, 0xc2, 0xf9, 0x8d, 0xd9, 0xc5, 0x8b, 0xf8,
- 0x3f, 0x4c, 0x65, 0xda, 0xc5, 0xff, 0xf7, 0x5f, 0x78, 0x83, 0x8a, 0x0c,
- 0x58, 0x79, 0x58, 0xbc, 0x4c, 0x75, 0x8a, 0xd2, 0x31, 0x80, 0x4c, 0x46,
- 0x3e, 0x53, 0xbf, 0xfb, 0xdc, 0x0f, 0x98, 0x42, 0xf4, 0xfd, 0x62, 0xfe,
- 0x97, 0x2f, 0x61, 0x2c, 0x56, 0x1f, 0x89, 0x23, 0x5f, 0xdb, 0x7d, 0x31,
- 0xcc, 0x4b, 0x17, 0xee, 0x6e, 0x4e, 0x8d, 0x58, 0xb4, 0x9a, 0x7b, 0xfd,
- 0x99, 0x5f, 0xcf, 0x13, 0x6a, 0x63, 0x58, 0xba, 0x63, 0x58, 0xaf, 0x9e,
- 0x3e, 0xe9, 0x7d, 0xfb, 0x74, 0xf3, 0x9e, 0x58, 0xbf, 0xf8, 0x3f, 0x42,
- 0x46, 0xe5, 0x9e, 0x02, 0xc5, 0x61, 0xf8, 0x68, 0xae, 0xec, 0x3a, 0xc5,
- 0x0d, 0x5a, 0xbe, 0x43, 0xb8, 0xf0, 0xad, 0xfb, 0xfb, 0xb8, 0x0a, 0x12,
- 0xbb, 0xc8, 0x6f, 0xdb, 0xac, 0x79, 0xe2, 0xc5, 0xf9, 0xf7, 0xe6, 0xb8,
- 0xb1, 0x7e, 0x8c, 0x3d, 0xef, 0x05, 0x8a, 0x1a, 0x20, 0x8e, 0x56, 0x45,
- 0x56, 0x31, 0x62, 0xf1, 0x31, 0xd6, 0x2d, 0x1a, 0xc5, 0xbe, 0xe6, 0xbc,
- 0x31, 0xcb, 0xd1, 0x72, 0x56, 0x2f, 0xb4, 0x0d, 0x9c, 0x58, 0xa3, 0x4f,
- 0x11, 0xc7, 0xaf, 0xfa, 0x7d, 0xf7, 0x89, 0xe2, 0xc5, 0x8b, 0xf8, 0x1d,
- 0x83, 0x35, 0x8b, 0x17, 0xf7, 0x52, 0xde, 0x68, 0x2c, 0x5e, 0x9c, 0xf2,
- 0xc5, 0xfb, 0x35, 0xa1, 0x46, 0xb1, 0x73, 0x80, 0xe7, 0x8d, 0xe1, 0xca,
- 0x94, 0x68, 0x61, 0x7b, 0x3a, 0x5f, 0x0f, 0xef, 0xda, 0xc5, 0xfc, 0x0e,
- 0x4f, 0xe7, 0x8b, 0x15, 0x27, 0xa4, 0xe4, 0x97, 0xde, 0xe6, 0x46, 0xb1,
- 0x7f, 0xff, 0xbe, 0xdb, 0xdc, 0x0d, 0x09, 0xde, 0xe7, 0x9f, 0xee, 0xba,
- 0xc5, 0x76, 0x88, 0xaf, 0x92, 0x5d, 0x91, 0xac, 0x53, 0x9b, 0xc2, 0x24,
- 0xa9, 0x57, 0x18, 0x32, 0xfc, 0x42, 0x66, 0xb8, 0x88, 0xbf, 0x18, 0x51,
- 0x3f, 0xf2, 0x1c, 0xd7, 0x9d, 0xc6, 0xb1, 0x7f, 0xff, 0x74, 0xdc, 0xc1,
- 0xf5, 0xf6, 0xf6, 0x44, 0x52, 0x75, 0x8a, 0x88, 0xfe, 0x7e, 0x39, 0x70,
- 0x3a, 0x58, 0xb7, 0x16, 0x2c, 0x6f, 0x0d, 0x58, 0x86, 0x6f, 0xe8, 0xdf,
- 0x3d, 0x87, 0x58, 0xa6, 0x3d, 0x67, 0x28, 0xbc, 0x07, 0xe9, 0x62, 0xf8,
- 0xc8, 0xb9, 0x2b, 0x17, 0xff, 0xb4, 0x07, 0x1e, 0xdc, 0xfc, 0x94, 0x7b,
- 0xab, 0x17, 0xcf, 0x1c, 0xf9, 0x62, 0xfc, 0xe4, 0xdb, 0x9b, 0xd6, 0x28,
- 0x8f, 0x3f, 0x79, 0x1d, 0x7d, 0x18, 0x5c, 0x84, 0xfd, 0xfa, 0x37, 0xe6,
- 0x41, 0x62, 0xff, 0xf8, 0x79, 0xbd, 0xf5, 0x10, 0x70, 0x7f, 0x39, 0xd6,
- 0x2e, 0xcd, 0xc5, 0x8a, 0x94, 0x4b, 0xb1, 0x4e, 0x95, 0x2f, 0xe7, 0xec,
- 0x07, 0x6e, 0x2c, 0x58, 0xd5, 0x8b, 0xf6, 0xb3, 0x78, 0xe5, 0x62, 0xa5,
- 0x52, 0xf7, 0x63, 0xd1, 0x43, 0x9f, 0x50, 0xbf, 0xf9, 0x70, 0x0b, 0xfc,
- 0x27, 0x7f, 0x31, 0x8f, 0x14, 0x9d, 0x62, 0xf6, 0xec, 0xf1, 0x62, 0xbc,
- 0x79, 0xe2, 0x2f, 0xb0, 0x40, 0xab, 0xb0, 0xb8, 0xd8, 0x12, 0x76, 0x32,
- 0x3d, 0x84, 0x5a, 0x16, 0xa3, 0x13, 0x3c, 0xbd, 0x1c, 0x62, 0xb0, 0x73,
- 0x1c, 0x36, 0x72, 0x54, 0xe7, 0x50, 0xfd, 0xee, 0x12, 0x8d, 0x29, 0xa7,
- 0x71, 0xa2, 0x29, 0xcf, 0x4d, 0x47, 0x00, 0x78, 0xc3, 0x7f, 0x29, 0x8d,
- 0xe5, 0x5a, 0x82, 0x59, 0xa9, 0x4a, 0xbc, 0xe4, 0xe2, 0x2f, 0xa7, 0x20,
- 0xc5, 0x0f, 0x4d, 0x98, 0x52, 0x07, 0x29, 0xfb, 0x76, 0x18, 0x17, 0xed,
- 0x74, 0xef, 0xd2, 0xa2, 0x9c, 0x2f, 0xef, 0xb1, 0xc9, 0xcd, 0x58, 0xb0,
- 0x4c, 0x3e, 0x56, 0x37, 0xbc, 0x16, 0x78, 0x2c, 0x58, 0xbf, 0xa4, 0xf9,
- 0xbb, 0x3e, 0x58, 0xbe, 0xfc, 0x91, 0xab, 0x17, 0xd3, 0xd4, 0xfd, 0x62,
- 0x8e, 0x7e, 0xde, 0x30, 0x0c, 0x8e, 0xfb, 0x38, 0x1c, 0x16, 0x2f, 0xfb,
- 0x4f, 0xcf, 0xe6, 0x17, 0x4b, 0x17, 0xf0, 0xb9, 0x9e, 0x0e, 0x35, 0x8a,
- 0x63, 0xea, 0xf9, 0xcd, 0xf8, 0xfa, 0xd6, 0x71, 0x62, 0xff, 0xfd, 0xf1,
- 0x7b, 0x53, 0xee, 0x67, 0x5c, 0x9d, 0x74, 0xb1, 0x7c, 0x2d, 0xd7, 0x89,
- 0x62, 0xff, 0x31, 0xb9, 0x09, 0x07, 0x16, 0x2a, 0x07, 0xb7, 0xc2, 0x7b,
- 0xc3, 0x93, 0xac, 0x5f, 0xe9, 0xf3, 0x74, 0xc3, 0x95, 0x8b, 0x69, 0x62,
- 0xff, 0xfa, 0x22, 0x6e, 0x7a, 0x43, 0x6d, 0x45, 0x3f, 0x58, 0xa8, 0x1f,
- 0x26, 0x09, 0x50, 0xd1, 0xab, 0xa1, 0xdf, 0x42, 0x5e, 0xf6, 0x71, 0x96,
- 0x2f, 0xf4, 0xfa, 0x58, 0x83, 0xe2, 0xc5, 0x61, 0xe7, 0xe8, 0x72, 0xff,
- 0xfd, 0x9e, 0xe0, 0x7c, 0xf3, 0x49, 0x78, 0x9c, 0x0b, 0x17, 0xf7, 0x70,
- 0x93, 0x8a, 0x25, 0x8b, 0xf8, 0xe3, 0x9e, 0x08, 0x96, 0x2f, 0x42, 0x4e,
- 0xb1, 0x7f, 0xbd, 0x0c, 0x35, 0xc8, 0x0b, 0x17, 0x7d, 0x96, 0x2b, 0xb3,
- 0xe8, 0x61, 0xdf, 0x1a, 0x54, 0xa3, 0xd9, 0x8c, 0x5e, 0x12, 0xd7, 0xdc,
- 0xdb, 0xc0, 0xd6, 0x2f, 0xfe, 0xcd, 0xf8, 0x3d, 0x4b, 0x41, 0xf8, 0xb1,
- 0x67, 0xec, 0xfb, 0x34, 0x4f, 0x7e, 0xf7, 0x70, 0x93, 0x16, 0x2f, 0xe7,
- 0x0f, 0x37, 0xcf, 0x16, 0x2b, 0x0f, 0x6c, 0x45, 0x77, 0xff, 0x7d, 0x83,
- 0xf3, 0x10, 0xa1, 0x9c, 0x58, 0xbf, 0xee, 0xf8, 0x58, 0x3f, 0xb9, 0x8b,
- 0x17, 0xdc, 0x6f, 0x4a, 0xc5, 0x31, 0xee, 0xb9, 0xdd, 0xff, 0xf6, 0x47,
- 0x9d, 0xfb, 0x8c, 0x52, 0x07, 0x3a, 0xc5, 0x62, 0x62, 0x46, 0xc2, 0x8b,
- 0x84, 0x17, 0xfe, 0xcf, 0xce, 0xb0, 0x21, 0x86, 0x18, 0x91, 0x73, 0x18,
- 0xb1, 0x74, 0x61, 0x02, 0xc6, 0x41, 0x3c, 0xc2, 0x7a, 0x06, 0x03, 0x84,
- 0x76, 0x10, 0xf4, 0x53, 0xdc, 0x2d, 0x1a, 0x1e, 0xf1, 0x42, 0x10, 0xe4,
- 0x3f, 0x8d, 0x2c, 0x10, 0x9e, 0x28, 0x41, 0xfa, 0x33, 0x3d, 0x93, 0x6d,
- 0xd4, 0x4b, 0xf6, 0xba, 0x77, 0xe9, 0x51, 0x5e, 0x17, 0xff, 0xf6, 0x0f,
- 0xf2, 0x18, 0x4f, 0x13, 0x83, 0x9c, 0x90, 0x24, 0x58, 0x26, 0x22, 0x57,
- 0x64, 0xde, 0xff, 0xe0, 0x8f, 0x00, 0x99, 0xae, 0x9d, 0xfa, 0x54, 0x48,
- 0xe5, 0xd8, 0x75, 0x8b, 0xbd, 0x8b, 0x15, 0xd1, 0xae, 0xec, 0x5e, 0xff,
- 0xfb, 0x3c, 0xdf, 0x17, 0xdd, 0xbb, 0xe4, 0x9a, 0xb1, 0x7f, 0xf8, 0xd6,
- 0xd6, 0x6a, 0x13, 0xff, 0xb0, 0x16, 0x2e, 0xf8, 0xd6, 0x2f, 0xff, 0xde,
- 0x91, 0xc8, 0x82, 0xfa, 0x9f, 0x30, 0x26, 0x0b, 0x17, 0x89, 0xc2, 0x40,
- 0xfc, 0x77, 0x8c, 0x5f, 0xfb, 0xa1, 0x3f, 0xf0, 0x6e, 0xfd, 0x2c, 0x5f,
- 0xfe, 0x31, 0xa2, 0x08, 0x59, 0xac, 0xce, 0xcc, 0x58, 0xbc, 0xc0, 0x95,
- 0x8b, 0xdd, 0x61, 0xd2, 0x02, 0x17, 0x97, 0xd8, 0xfd, 0x81, 0x62, 0xff,
- 0xfd, 0xf9, 0x21, 0x73, 0xed, 0xac, 0xdf, 0x25, 0xe5, 0x8b, 0xff, 0x9b,
- 0x59, 0xa8, 0x4f, 0xfe, 0xc0, 0x58, 0xbe, 0xe9, 0xdf, 0xa5, 0x44, 0x90,
- 0x5f, 0xcf, 0xac, 0xdf, 0xfc, 0x58, 0xa8, 0xd3, 0x1d, 0x81, 0x19, 0xaa,
- 0xda, 0x44, 0x01, 0x8d, 0xf4, 0x5e, 0xce, 0x96, 0x2f, 0xd2, 0xc0, 0x63,
- 0xac, 0x54, 0x9e, 0x64, 0x09, 0x6f, 0xf4, 0x97, 0x8a, 0x4f, 0xc5, 0x8b,
- 0xff, 0xf3, 0x69, 0xb7, 0x64, 0xa3, 0x9f, 0x37, 0xde, 0x35, 0x8b, 0xf3,
- 0xc3, 0xcd, 0x1a, 0xc5, 0x4a, 0x20, 0x59, 0x62, 0xff, 0xf3, 0xfa, 0x2e,
- 0x60, 0xc6, 0x27, 0xd4, 0x16, 0x2f, 0xff, 0x9f, 0xbe, 0x67, 0xdc, 0xb2,
- 0x33, 0x8b, 0xeb, 0x17, 0xff, 0x7d, 0xbb, 0xf6, 0x77, 0xed, 0x6a, 0x56,
- 0x2f, 0xfe, 0x69, 0x3b, 0x8c, 0x3d, 0xd9, 0x28, 0x2c, 0x56, 0x23, 0x7f,
- 0xa5, 0x1f, 0xa3, 0xdf, 0xfd, 0x80, 0xd9, 0xcd, 0x4c, 0x6f, 0xae, 0x96,
- 0x2f, 0xce, 0x0f, 0x60, 0x16, 0x28, 0x8f, 0xc7, 0x89, 0x37, 0xfb, 0x3e,
- 0xe7, 0x29, 0xed, 0x62, 0xe8, 0x04, 0x95, 0xcf, 0xac, 0x8d, 0x31, 0xa1,
- 0x33, 0x11, 0x0f, 0xe1, 0x66, 0x02, 0x1e, 0x46, 0x57, 0xe8, 0x50, 0x86,
- 0x43, 0x7e, 0x17, 0x7d, 0x37, 0x16, 0x2f, 0xd9, 0xf0, 0x98, 0x75, 0x8b,
- 0xe3, 0x48, 0x47, 0x58, 0xb0, 0x49, 0x64, 0x16, 0x8c, 0x8f, 0x14, 0x7a,
- 0x85, 0xe7, 0x66, 0xcc, 0x80, 0xf3, 0xac, 0xa0, 0x85, 0x4f, 0x8a, 0xc3,
- 0x2a, 0xbf, 0xf8, 0x23, 0xc0, 0x26, 0x6b, 0xa7, 0x7e, 0x95, 0x12, 0x51,
- 0x7e, 0xd7, 0x4e, 0xfd, 0x2a, 0x2f, 0x12, 0xff, 0xa0, 0x13, 0x35, 0xd3,
- 0xbf, 0x4a, 0x89, 0x34, 0xb0, 0x4c, 0x44, 0x0b, 0x9b, 0xdf, 0x75, 0xf6,
- 0x25, 0x8b, 0xc1, 0x61, 0x91, 0xac, 0x5c, 0x3d, 0x8d, 0x62, 0xff, 0x82,
- 0xbb, 0x06, 0xc1, 0xfc, 0x3e, 0x71, 0x62, 0xfe, 0xd8, 0xb6, 0x30, 0x7b,
- 0xdd, 0xac, 0x5f, 0xb9, 0xcc, 0x2c, 0x58, 0xbf, 0xed, 0x75, 0x31, 0xe6,
- 0x17, 0x96, 0x2f, 0xe2, 0x0e, 0x2d, 0x4e, 0xf5, 0x8b, 0xe7, 0x6e, 0xf8,
- 0xb1, 0x6f, 0xac, 0x56, 0x23, 0x21, 0x89, 0xf7, 0x0e, 0xbe, 0x64, 0x61,
- 0x1d, 0xf0, 0xff, 0x31, 0xac, 0x5f, 0xe9, 0xfc, 0x88, 0x36, 0xdd, 0x58,
- 0xbf, 0x81, 0x85, 0x3d, 0xf1, 0x62, 0xa3, 0x3e, 0x56, 0x37, 0xbf, 0x13,
- 0x74, 0xc3, 0x58, 0xbd, 0xbe, 0x60, 0xb1, 0x7e, 0x9f, 0x73, 0x3c, 0xb1,
- 0x79, 0xc8, 0x78, 0x78, 0xff, 0x1f, 0xbf, 0xcc, 0x6f, 0x7c, 0xc2, 0x35,
- 0x62, 0xff, 0x9f, 0x50, 0xe6, 0x0b, 0x51, 0xac, 0x56, 0x26, 0x22, 0xcd,
- 0xff, 0x31, 0x11, 0xb5, 0xfb, 0x05, 0xd3, 0x92, 0xc5, 0xe9, 0x9f, 0x2c,
- 0x5f, 0xf6, 0x00, 0x7f, 0x92, 0x93, 0x16, 0x2f, 0x81, 0xcc, 0x25, 0x8a,
- 0x93, 0xdb, 0x63, 0x9b, 0xff, 0x0b, 0xae, 0x71, 0xf5, 0xe9, 0x35, 0x62,
- 0xfd, 0xff, 0x73, 0x3c, 0xb1, 0x7f, 0xbc, 0xdf, 0x63, 0x7e, 0xcb, 0x14,
- 0xc8, 0x9f, 0x74, 0x21, 0x14, 0xdf, 0xff, 0xbe, 0xec, 0x0e, 0x61, 0xae,
- 0x7d, 0x4e, 0x12, 0xc5, 0xfd, 0x9e, 0x36, 0x4a, 0x0b, 0x17, 0x30, 0xd6,
- 0x2a, 0x51, 0x32, 0x35, 0x4f, 0x97, 0x5f, 0xee, 0x03, 0x32, 0x20, 0xce,
- 0xb1, 0x78, 0x53, 0xda, 0xc5, 0x49, 0xea, 0x40, 0xda, 0xff, 0xa3, 0x6e,
- 0x71, 0xc1, 0xf1, 0x2c, 0x5f, 0x0c, 0xa7, 0xb5, 0x8b, 0x69, 0x62, 0xcd,
- 0xa3, 0x6a, 0x22, 0x3b, 0xfe, 0xc3, 0x4d, 0x78, 0x67, 0x7e, 0x58, 0xbd,
- 0x1c, 0xc6, 0xb1, 0x78, 0x4f, 0xde, 0x1e, 0xd8, 0x67, 0x97, 0xfc, 0x58,
- 0x37, 0x3e, 0x77, 0xe5, 0x8b, 0xf6, 0x67, 0xbf, 0x8b, 0x15, 0x27, 0xc1,
- 0xf3, 0x9b, 0xfe, 0x98, 0x73, 0x5a, 0x72, 0xf2, 0xc5, 0x6d, 0x5c, 0xa8,
- 0x8c, 0xa2, 0x0e, 0xe3, 0x85, 0xff, 0x50, 0xc7, 0x8a, 0x10, 0x7a, 0x21,
- 0xfb, 0x87, 0x21, 0x03, 0xe8, 0x4a, 0x6f, 0x21, 0xbf, 0x9b, 0x0a, 0x7b,
- 0xe2, 0xc5, 0xfb, 0xde, 0x92, 0x8d, 0x62, 0xff, 0xe3, 0xcf, 0x5b, 0x43,
- 0xf7, 0x1c, 0x8d, 0x58, 0xac, 0x3f, 0x36, 0x29, 0xbf, 0x60, 0xf6, 0x19,
- 0x6e, 0x2c, 0x5f, 0xce, 0x40, 0xd8, 0x65, 0xb8, 0xb1, 0x73, 0x8f, 0x79,
- 0xf3, 0xec, 0x98, 0xd1, 0xd3, 0x59, 0xfc, 0x28, 0x05, 0x08, 0x7b, 0xce,
- 0x5d, 0x2c, 0x5e, 0xfc, 0x86, 0xb1, 0x5e, 0x37, 0x66, 0x0e, 0xdd, 0x9e,
- 0x58, 0xbf, 0xd0, 0x6f, 0xbc, 0x1b, 0xeb, 0x16, 0xff, 0xcf, 0x29, 0xc5,
- 0xef, 0xff, 0x0b, 0x50, 0x29, 0x84, 0xfb, 0xf8, 0x4b, 0x17, 0xf1, 0x38,
- 0x09, 0xce, 0xb1, 0x7e, 0x1f, 0xf7, 0x18, 0x96, 0x2f, 0xf1, 0x61, 0xf6,
- 0x73, 0x52, 0xb1, 0x52, 0x7c, 0x11, 0x15, 0xde, 0x9f, 0x71, 0x62, 0xff,
- 0xa4, 0xff, 0xc1, 0x8d, 0xbb, 0x58, 0xbf, 0xe9, 0x34, 0xb0, 0x7f, 0x73,
- 0x16, 0x2f, 0x77, 0xe9, 0x58, 0xac, 0x46, 0x8f, 0x64, 0x4c, 0x3b, 0xa3,
- 0xa1, 0x1d, 0x5f, 0x6e, 0xb4, 0x9a, 0xb1, 0x7a, 0x1d, 0x9a, 0xb1, 0x61,
- 0xac, 0x5f, 0xa0, 0xf3, 0xde, 0xea, 0xc5, 0xfb, 0xdf, 0x17, 0xb8, 0xb1,
- 0x43, 0x3e, 0x8e, 0xc4, 0x8e, 0x59, 0x7e, 0x1c, 0xf0, 0x3e, 0x2c, 0x5c,
- 0x3e, 0xd6, 0x28, 0xe7, 0x86, 0x22, 0xab, 0xc2, 0x9e, 0x2c, 0x5f, 0xf8,
- 0x1d, 0x7d, 0xb4, 0x4d, 0xee, 0x2c, 0x5f, 0xf4, 0xe7, 0x22, 0xfb, 0x19,
- 0xe5, 0x8a, 0x3a, 0x26, 0x1c, 0x77, 0x88, 0x17, 0xe8, 0x7e, 0x48, 0xd5,
- 0x8b, 0xf3, 0x3e, 0xa7, 0xa5, 0x8b, 0x6f, 0xc3, 0xd1, 0xe1, 0x4d, 0xc5,
- 0x1a, 0xc5, 0x4a, 0xa9, 0xc1, 0x93, 0x64, 0x22, 0x19, 0xcd, 0xe1, 0x74,
- 0x08, 0x40, 0x06, 0x53, 0x4b, 0x17, 0xf4, 0x8c, 0xf3, 0x9e, 0x58, 0xaf,
- 0x1b, 0x90, 0xc3, 0x2f, 0xfa, 0x74, 0x07, 0xf6, 0xce, 0x79, 0x62, 0xed,
- 0x62, 0xc5, 0xf7, 0x6d, 0xdc, 0x16, 0x2e, 0x0e, 0x35, 0x8a, 0x63, 0x7e,
- 0x02, 0x5a, 0xd2, 0x35, 0x3e, 0x44, 0x03, 0xc2, 0x56, 0xbb, 0x0e, 0xb1,
- 0x7b, 0x5b, 0xfe, 0xb1, 0x7e, 0xcd, 0x3c, 0x8d, 0x62, 0xa4, 0xf7, 0x9c,
- 0x5c, 0x88, 0x2f, 0x0f, 0x09, 0x62, 0xff, 0xda, 0x11, 0xfe, 0xd2, 0x77,
- 0x25, 0x8b, 0xfe, 0xe4, 0x9c, 0xb2, 0x12, 0x4b, 0x17, 0xf9, 0x8b, 0x6e,
- 0x1d, 0xbc, 0xb1, 0x5a, 0x45, 0x4f, 0x8f, 0xb7, 0x9b, 0xdc, 0x50, 0x58,
- 0xbb, 0x63, 0x31, 0x62, 0x84, 0x6d, 0x76, 0x45, 0xea, 0x53, 0x50, 0xc8,
- 0x62, 0xee, 0xb3, 0xdf, 0xfd, 0xd0, 0x9c, 0x7b, 0xf0, 0x7b, 0x0c, 0xb7,
- 0x16, 0x2f, 0x9b, 0xf3, 0xbd, 0x62, 0xb4, 0x7e, 0xbe, 0x51, 0xbf, 0xd3,
- 0xa9, 0xec, 0x1a, 0x95, 0x8b, 0xff, 0x6b, 0x59, 0xfc, 0x22, 0x91, 0xac,
- 0x5e, 0x6d, 0xd8, 0xd6, 0x2d, 0x1a, 0xc5, 0x49, 0xb4, 0x22, 0x1b, 0xdf,
- 0x16, 0xe2, 0xc5, 0xfc, 0x53, 0xef, 0xbc, 0x16, 0x2a, 0x4f, 0x3a, 0x22,
- 0x1b, 0xde, 0x9d, 0x2c, 0x54, 0xa6, 0xe7, 0x19, 0x13, 0x1a, 0x44, 0xe2,
- 0xed, 0xa2, 0x22, 0xb9, 0xfa, 0x58, 0xbf, 0xff, 0xfd, 0x84, 0x4f, 0x0f,
- 0xb6, 0xd0, 0xf5, 0xa9, 0x83, 0x79, 0xb4, 0xe0, 0x58, 0xbf, 0x0c, 0x51,
- 0x86, 0x75, 0x8b, 0xff, 0xf1, 0x48, 0xf8, 0x27, 0x68, 0x30, 0x38, 0x2e,
- 0x2c, 0x5f, 0xd9, 0xef, 0xb7, 0x70, 0x58, 0xa8, 0x91, 0x08, 0x4a, 0xb5,
- 0xd2, 0x34, 0xff, 0x0b, 0x0b, 0xfb, 0xbe, 0x61, 0xdf, 0x8b, 0x17, 0xc3,
- 0xcf, 0xca, 0xc5, 0xb4, 0xb1, 0x7e, 0x8f, 0x53, 0xde, 0x96, 0x2a, 0x33,
- 0x7b, 0x82, 0x57, 0xff, 0xf7, 0xb6, 0x8e, 0x5f, 0x58, 0x40, 0xdb, 0xcf,
- 0x73, 0xb5, 0x8b, 0xf8, 0x79, 0x09, 0x07, 0x16, 0x2b, 0x11, 0x1e, 0x26,
- 0x1a, 0x95, 0x5d, 0x90, 0x18, 0xc8, 0xd2, 0xd8, 0xa5, 0xcb, 0xc9, 0x7f,
- 0x90, 0xb0, 0xbf, 0xff, 0x82, 0xc1, 0x6c, 0x12, 0x7f, 0x6d, 0x8f, 0x3f,
- 0xb7, 0x6f, 0xf6, 0x56, 0x2f, 0xff, 0x67, 0xfa, 0xfb, 0x77, 0xec, 0x3b,
- 0xf1, 0x62, 0xf1, 0xe7, 0xcb, 0x17, 0xd1, 0x9c, 0x5b, 0x8b, 0x17, 0xef,
- 0x1e, 0x22, 0x1a, 0xc5, 0xf7, 0xc3, 0xd9, 0x75, 0x8a, 0xc4, 0x4b, 0x38,
- 0xe9, 0x14, 0x08, 0xaa, 0xfd, 0x17, 0x38, 0xc7, 0x58, 0xbd, 0xc1, 0x76,
- 0xb1, 0x7f, 0xa2, 0x83, 0xea, 0x3f, 0x89, 0x62, 0xff, 0xfa, 0x33, 0x1e,
- 0x1c, 0xe6, 0x68, 0xc9, 0xd1, 0xab, 0x16, 0x25, 0x8b, 0xf9, 0xfd, 0xc8,
- 0xf0, 0xc5, 0x8b, 0xff, 0xf9, 0xb8, 0xf0, 0xe3, 0x6f, 0xe0, 0x9d, 0xa0,
- 0xdb, 0xd6, 0x2e, 0x0c, 0x35, 0x8a, 0xc4, 0xe3, 0xa2, 0x2a, 0x38, 0xfb,
- 0x9b, 0x81, 0x54, 0x84, 0x7c, 0x60, 0x1a, 0xf5, 0xfb, 0x34, 0x00, 0x4a,
- 0xc5, 0xdb, 0x21, 0x02, 0x8d, 0xea, 0xe6, 0xc4, 0x46, 0x15, 0x25, 0xd8,
- 0x63, 0xa1, 0x62, 0x44, 0xc6, 0x07, 0x1a, 0x64, 0x21, 0x12, 0x38, 0xcc,
- 0xf2, 0x73, 0x93, 0xa9, 0x42, 0x9d, 0xbb, 0x33, 0x66, 0xe1, 0x3c, 0x49,
- 0x3a, 0x8d, 0x77, 0xf2, 0xb9, 0x5e, 0x37, 0xf0, 0x42, 0x68, 0xa3, 0x7c,
- 0xe4, 0xa1, 0xff, 0x4b, 0x43, 0x13, 0x61, 0x8e, 0x5b, 0x30, 0xe2, 0x0e,
- 0x3c, 0x8d, 0xd7, 0x1b, 0xfc, 0x28, 0xc2, 0x6e, 0xee, 0xb1, 0xab, 0x15,
- 0x2f, 0xd0, 0xef, 0x1c, 0x38, 0xa1, 0x6c, 0x3c, 0x87, 0x2a, 0x01, 0xa9,
- 0x09, 0xf1, 0x47, 0x74, 0x72, 0xdf, 0xd2, 0x2c, 0xbd, 0x0a, 0x81, 0x43,
- 0x60, 0x3a, 0xf6, 0x17, 0x76, 0x3f, 0x7a, 0x9a, 0x72, 0xb9, 0x4c, 0x73,
- 0xd7, 0xf0, 0xac, 0x5e, 0x87, 0x58, 0x3a, 0xe6, 0xa0, 0x9c, 0x73, 0x69,
- 0xad, 0x3d, 0x66, 0x04, 0xfd, 0xdd, 0xbf, 0x01, 0x6b, 0x41, 0x35, 0xb9,
- 0x29, 0xea, 0x2c, 0x5c, 0x01, 0xeb, 0x18, 0x2a, 0xa7, 0xdc, 0xf9, 0x64,
- 0xfd, 0xa9, 0x58, 0x7c, 0x58, 0xce, 0x02, 0xbc, 0x81, 0x0b, 0xce, 0x9f,
- 0x95, 0xeb, 0x4d, 0x72, 0xf3, 0x13, 0xfd, 0x99, 0xe7, 0xa0, 0xb1, 0x4f,
- 0xb3, 0xbe, 0xb8, 0x8a, 0x32, 0xb4, 0xff, 0xd9, 0xa5, 0x1a, 0x87, 0x5b,
- 0xf9, 0x6e, 0xdf, 0x57, 0x4d, 0x00,
+ 0x8e, 0x2c, 0x5e, 0x72, 0x92, 0xc5, 0xb6, 0x61, 0x72, 0x97, 0xa2, 0xa9,
+ 0x8c, 0xb4, 0x3a, 0x79, 0x52, 0xbf, 0x8c, 0x0d, 0xc8, 0x04, 0x68, 0x61,
+ 0x25, 0xff, 0xdb, 0x2f, 0x2d, 0x9c, 0xd7, 0x4e, 0xfd, 0x2a, 0x25, 0x22,
+ 0xa7, 0x6d, 0xb0, 0x26, 0x59, 0x3a, 0xfb, 0xc2, 0x88, 0x14, 0xcb, 0x92,
+ 0x95, 0xd9, 0xe9, 0xcd, 0x00, 0x90, 0x98, 0xbd, 0xb2, 0xfd, 0x2c, 0x5f,
+ 0xcc, 0x59, 0xfc, 0xe9, 0x62, 0xfe, 0x62, 0xf6, 0x30, 0xd6, 0x2e, 0x97,
+ 0x96, 0x2f, 0x14, 0x18, 0xb1, 0x74, 0x6c, 0xe8, 0xda, 0x90, 0xc5, 0x49,
+ 0x11, 0xfe, 0x61, 0xbd, 0xc1, 0x1d, 0x62, 0xd2, 0x58, 0xbb, 0x8e, 0xb1,
+ 0x77, 0xb1, 0x62, 0xdb, 0x1a, 0xc5, 0xb6, 0x64, 0x9a, 0xa7, 0x70, 0xbc,
+ 0x62, 0x39, 0x87, 0x80, 0x25, 0xbc, 0x5f, 0x70, 0x5e, 0xfe, 0x2f, 0x6e,
+ 0x64, 0x69, 0x62, 0xff, 0xf6, 0xa2, 0x5b, 0x99, 0xee, 0x37, 0xa7, 0x92,
+ 0xc5, 0xfe, 0xf7, 0x22, 0x67, 0x7d, 0x2c, 0x54, 0x22, 0x0d, 0x93, 0xef,
+ 0xff, 0xb3, 0xcd, 0xf1, 0x7d, 0xdb, 0xbe, 0x41, 0xab, 0x17, 0x89, 0xe4,
+ 0xb1, 0x76, 0xf6, 0x58, 0xbf, 0x6c, 0x41, 0x5d, 0x73, 0x8b, 0x17, 0xff,
+ 0x9b, 0xb0, 0x6b, 0x07, 0x1a, 0x6e, 0xc0, 0xb1, 0x7e, 0xd7, 0x4e, 0xfd,
+ 0x2a, 0x27, 0x62, 0xfd, 0x80, 0x7d, 0xc3, 0x56, 0x2f, 0xcf, 0xae, 0xb5,
+ 0x8b, 0x17, 0xf9, 0xb9, 0xc6, 0xfc, 0x71, 0x62, 0xa7, 0x3d, 0xc3, 0x94,
+ 0xde, 0xfb, 0x98, 0xb1, 0x7f, 0xc4, 0xf2, 0x10, 0x0e, 0xf2, 0x58, 0xb6,
+ 0x0c, 0xf5, 0xfe, 0x3d, 0x7f, 0xc6, 0xb7, 0xb8, 0xdd, 0x3e, 0x96, 0x2f,
+ 0x3c, 0xb6, 0x42, 0xd2, 0xa1, 0xa8, 0x33, 0xc4, 0xcf, 0x9b, 0xbc, 0x22,
+ 0x09, 0xe8, 0x32, 0x7b, 0x6e, 0xac, 0x5f, 0xff, 0xd8, 0x44, 0xfe, 0xfe,
+ 0x71, 0xf3, 0x40, 0x3e, 0x2c, 0x54, 0xe7, 0xda, 0xe2, 0xb7, 0xff, 0xe6,
+ 0x18, 0x8f, 0x01, 0x1c, 0x65, 0x05, 0x9d, 0x2c, 0x5e, 0x6d, 0x49, 0x62,
+ 0xff, 0x4a, 0x35, 0x3c, 0x6a, 0x75, 0x8b, 0xff, 0x7c, 0x9e, 0x42, 0x01,
+ 0xde, 0x4b, 0x15, 0x07, 0xeb, 0x86, 0xd7, 0x18, 0xcb, 0x17, 0xf9, 0xe7,
+ 0x7c, 0xf6, 0x1d, 0x62, 0xfe, 0xd0, 0x30, 0x9f, 0xeb, 0x17, 0xff, 0xec,
+ 0xee, 0x5f, 0x8e, 0x3e, 0xa0, 0x27, 0xdf, 0xa5, 0x8b, 0x6c, 0xc2, 0xf2,
+ 0xf4, 0xa1, 0x66, 0x32, 0x1c, 0x51, 0x61, 0xc3, 0xca, 0x33, 0xfc, 0x3b,
+ 0xdc, 0x88, 0x0a, 0xc5, 0x09, 0x23, 0x08, 0x37, 0x06, 0x03, 0x33, 0x08,
+ 0x5b, 0x70, 0x37, 0x16, 0x2f, 0xa0, 0x70, 0x4b, 0x17, 0xcd, 0xa8, 0xde,
+ 0xb1, 0x76, 0x7d, 0x62, 0xff, 0xed, 0xc7, 0x20, 0x67, 0xa0, 0x98, 0x0b,
+ 0x16, 0xd9, 0xdd, 0x45, 0xe1, 0x0d, 0xf0, 0x87, 0x70, 0x90, 0x31, 0x7b,
+ 0xff, 0x9c, 0xff, 0xce, 0x9f, 0xf0, 0x1c, 0x96, 0x2f, 0xde, 0xd6, 0x41,
+ 0x8b, 0x17, 0x98, 0x6e, 0xb1, 0x7f, 0xf1, 0x67, 0xde, 0x7c, 0xe1, 0x3f,
+ 0x6b, 0x17, 0x6e, 0x6c, 0x8d, 0x19, 0xec, 0x8d, 0xf2, 0x9e, 0x0e, 0x54,
+ 0x32, 0xd8, 0x65, 0x1b, 0xa9, 0xe7, 0xb5, 0xf9, 0x1c, 0xfe, 0xe4, 0x65,
+ 0x17, 0xff, 0x69, 0xfb, 0xd9, 0x1e, 0x4c, 0xef, 0x3a, 0xc5, 0xff, 0x41,
+ 0x76, 0x0e, 0x72, 0x00, 0xb1, 0x7d, 0xac, 0x33, 0xcb, 0x15, 0xc3, 0xde,
+ 0xde, 0x75, 0x7f, 0xb5, 0x9c, 0x21, 0x38, 0x6b, 0x17, 0xff, 0xff, 0xfd,
+ 0xf6, 0xf3, 0xbf, 0x7c, 0xe7, 0x20, 0xf1, 0xfc, 0xc9, 0xf0, 0xb3, 0xbf,
+ 0x72, 0x3b, 0x58, 0xbf, 0xd1, 0x26, 0xf3, 0x14, 0x96, 0x2f, 0xff, 0xfd,
+ 0xd0, 0xa7, 0xcd, 0xf1, 0xde, 0x0d, 0xe4, 0x19, 0xf9, 0x8e, 0x35, 0x8b,
+ 0xbd, 0xb3, 0x89, 0xc8, 0x9a, 0x49, 0xd1, 0xa6, 0xa1, 0x2b, 0xc3, 0x2b,
+ 0x0d, 0x95, 0x4c, 0xbc, 0xa3, 0x9b, 0xff, 0xa6, 0xef, 0x8c, 0x7d, 0xa1,
+ 0xeb, 0x27, 0x58, 0xbe, 0xe9, 0xdf, 0xa5, 0x44, 0x58, 0x5f, 0xcd, 0xa7,
+ 0x2e, 0xa1, 0x62, 0xf9, 0x88, 0xa1, 0x62, 0xb4, 0x7f, 0xdf, 0x31, 0xde,
+ 0x5b, 0x7d, 0x9e, 0x03, 0x2c, 0x5f, 0xf9, 0xe5, 0xb3, 0x9a, 0xe9, 0xdf,
+ 0xa5, 0x44, 0xba, 0x5f, 0xe7, 0x1c, 0x17, 0xe3, 0x8b, 0x17, 0xda, 0x61,
+ 0x4e, 0xb1, 0x7f, 0xff, 0x60, 0xff, 0x01, 0xec, 0xf8, 0x9c, 0x1c, 0xe4,
+ 0x01, 0x22, 0xdb, 0x30, 0xa8, 0x8b, 0x21, 0x95, 0xa3, 0x13, 0x91, 0x7d,
+ 0x43, 0xc6, 0x5b, 0x84, 0x97, 0xff, 0x1d, 0xe5, 0xb3, 0x9a, 0xe9, 0xdf,
+ 0xa5, 0x44, 0xc4, 0x5f, 0xdf, 0x82, 0xee, 0x67, 0x58, 0xbf, 0xe7, 0x72,
+ 0xcf, 0x37, 0x66, 0x2c, 0x5f, 0xe7, 0x6d, 0xc6, 0x06, 0x0d, 0x62, 0xff,
+ 0xfc, 0x4e, 0x03, 0xb6, 0xdc, 0xfb, 0x44, 0x9e, 0x4b, 0x17, 0xd9, 0xd4,
+ 0x6c, 0xc2, 0x3c, 0x8e, 0x5f, 0xf3, 0x9f, 0x1a, 0xd6, 0xca, 0x73, 0xdf,
+ 0x8d, 0x22, 0xff, 0x7d, 0xcf, 0xb2, 0xe2, 0x1a, 0xc5, 0x86, 0xb1, 0x7e,
+ 0xd7, 0x4e, 0xfd, 0x2a, 0x2a, 0x92, 0xd8, 0xb1, 0x53, 0x9e, 0xd6, 0x09,
+ 0x1a, 0x6f, 0x7f, 0xda, 0xd3, 0x11, 0x60, 0xba, 0x58, 0xbf, 0xf0, 0x9f,
+ 0x52, 0x2c, 0x31, 0xc0, 0xb1, 0x7f, 0xf3, 0xf3, 0x4c, 0x67, 0xbe, 0xda,
+ 0x92, 0xc5, 0xff, 0x69, 0xff, 0xdc, 0xb3, 0xdb, 0x30, 0x8b, 0xe1, 0x9c,
+ 0xfc, 0xfe, 0xb6, 0x53, 0x4f, 0x78, 0x77, 0x5f, 0xfb, 0x67, 0xf0, 0x7c,
+ 0x1c, 0x17, 0x96, 0x2f, 0x79, 0xa7, 0x58, 0xbf, 0xf3, 0xcb, 0x67, 0x35,
+ 0xd3, 0xbf, 0x4a, 0x89, 0xd0, 0xbe, 0x17, 0x18, 0x0b, 0x17, 0x9b, 0xb3,
+ 0x16, 0x28, 0x07, 0x85, 0xc2, 0x3a, 0x35, 0x1a, 0x47, 0x1e, 0x04, 0x24,
+ 0xaf, 0x9b, 0x35, 0xbd, 0x62, 0xf9, 0xcb, 0xdc, 0x58, 0xbe, 0x9c, 0xa2,
+ 0x75, 0x8b, 0xe3, 0xc1, 0xbb, 0x3b, 0xa7, 0xd4, 0x72, 0x41, 0x11, 0x5f,
+ 0xf8, 0x02, 0xe6, 0xc8, 0xcc, 0x72, 0x92, 0xc5, 0x6c, 0xa6, 0x62, 0xd0,
+ 0xa0, 0x02, 0x6d, 0xff, 0xe6, 0xd3, 0xf7, 0xf7, 0x6e, 0xf9, 0x06, 0xac,
+ 0x5f, 0xe6, 0x7d, 0x44, 0x9f, 0x7a, 0xc5, 0xf3, 0x10, 0x19, 0x62, 0xfd,
+ 0x34, 0x4d, 0x1c, 0x58, 0xbf, 0x8c, 0xc6, 0xdf, 0x84, 0xb1, 0x4c, 0x7b,
+ 0x3c, 0x2a, 0xbc, 0xdf, 0x85, 0x8d, 0x93, 0x43, 0x7f, 0xf0, 0xb9, 0xe8,
+ 0xef, 0x64, 0x53, 0x31, 0xd6, 0x2a, 0x49, 0x8a, 0x9e, 0x13, 0x7f, 0x2f,
+ 0xbb, 0xfc, 0x58, 0xbf, 0x6b, 0xa7, 0x7e, 0x95, 0x13, 0xb9, 0x7f, 0xff,
+ 0x41, 0xc5, 0xa9, 0xa0, 0xfb, 0x4f, 0x9e, 0xe3, 0x71, 0x62, 0xf3, 0xcb,
+ 0x67, 0x11, 0x2d, 0xe3, 0x7b, 0xf3, 0x6f, 0xd4, 0x49, 0x62, 0xfd, 0xe1,
+ 0x39, 0xd9, 0x22, 0xe3, 0xee, 0x2c, 0x5f, 0xd8, 0xc3, 0x77, 0x35, 0x62,
+ 0xff, 0xc5, 0x1e, 0xce, 0x66, 0x77, 0x25, 0x8b, 0xff, 0xf1, 0x6b, 0x0c,
+ 0xcd, 0xd8, 0xfc, 0x31, 0x0e, 0x16, 0x2a, 0x4a, 0xf7, 0x46, 0x99, 0x91,
+ 0xa4, 0xf4, 0x6c, 0x78, 0x57, 0x7c, 0xd9, 0xca, 0x88, 0xa3, 0x83, 0x7e,
+ 0x2d, 0x0c, 0xfa, 0xff, 0x87, 0x12, 0x8d, 0x93, 0x38, 0x05, 0x8b, 0xf7,
+ 0x0a, 0x01, 0xc5, 0x8b, 0xc5, 0x83, 0x58, 0xba, 0x36, 0x60, 0xf1, 0x00,
+ 0x51, 0x5b, 0x29, 0xaa, 0xe4, 0x29, 0x0a, 0x10, 0x57, 0xff, 0xa0, 0x07,
+ 0x79, 0x6c, 0xf0, 0x65, 0x9f, 0x58, 0xbf, 0xef, 0x71, 0x8e, 0xde, 0x03,
+ 0xac, 0x5d, 0xe8, 0x58, 0xbb, 0x9b, 0x30, 0x7a, 0x1d, 0x1c, 0xdf, 0xfe,
+ 0xd9, 0x3b, 0xcb, 0x67, 0x35, 0xd3, 0xbf, 0x4a, 0x8a, 0x14, 0xba, 0x34,
+ 0xb1, 0x7e, 0x04, 0x4f, 0x86, 0x2c, 0x5f, 0xf9, 0xfd, 0x2c, 0x26, 0x1e,
+ 0xcf, 0x27, 0x3c, 0x10, 0x0b, 0xdf, 0x13, 0xeb, 0x7a, 0xc5, 0xe3, 0xb9,
+ 0x8b, 0x16, 0xd9, 0x83, 0xc2, 0x9c, 0x92, 0xe9, 0xd9, 0x62, 0xff, 0xf7,
+ 0xc5, 0xe8, 0x2c, 0x9c, 0xd1, 0x44, 0xcb, 0x17, 0xf0, 0x8e, 0x77, 0x96,
+ 0xcc, 0x1f, 0x2f, 0x43, 0x17, 0xff, 0xfe, 0x2c, 0xde, 0xdf, 0x16, 0xcf,
+ 0x5f, 0x6f, 0x94, 0x66, 0xb0, 0xeb, 0x15, 0x24, 0xd2, 0x3f, 0x09, 0x0e,
+ 0x24, 0x5f, 0x85, 0xdf, 0x9b, 0xa5, 0x8b, 0xe2, 0xc3, 0x3e, 0xb1, 0x7f,
+ 0xb3, 0x9c, 0x80, 0x07, 0x3a, 0xc5, 0xfb, 0x01, 0x8e, 0x4b, 0x17, 0xff,
+ 0x6f, 0x6f, 0x47, 0xcb, 0x3d, 0xa8, 0x58, 0xbf, 0x3e, 0x81, 0xb9, 0x8b,
+ 0x17, 0x98, 0xcf, 0x2c, 0x56, 0x22, 0x39, 0x91, 0x78, 0x57, 0x7f, 0xc7,
+ 0x9a, 0x4f, 0xa9, 0xfe, 0x25, 0x8b, 0xd0, 0x0d, 0x99, 0xd3, 0xa3, 0x91,
+ 0x58, 0xc8, 0xc8, 0xdb, 0xd0, 0xb4, 0x0c, 0xba, 0x99, 0x52, 0x59, 0x47,
+ 0xb3, 0x7f, 0xfe, 0x17, 0x5b, 0x2f, 0xef, 0xe1, 0xe3, 0x45, 0x00, 0x58,
+ 0xbf, 0xe3, 0xbf, 0x30, 0xc8, 0x21, 0xac, 0x5f, 0xf9, 0xe5, 0xb3, 0x9a,
+ 0xe9, 0xdf, 0xa5, 0x45, 0x24, 0x5f, 0xec, 0xf9, 0x60, 0xfe, 0x25, 0x8b,
+ 0xd0, 0x43, 0x58, 0xb6, 0xcc, 0xe9, 0x98, 0xe2, 0xc9, 0xce, 0x7c, 0xa0,
+ 0x61, 0x9d, 0xff, 0xff, 0x61, 0x0b, 0x91, 0x85, 0xe2, 0x73, 0x72, 0x68,
+ 0x21, 0xac, 0x5c, 0x72, 0x58, 0xbf, 0xfa, 0x6f, 0xb9, 0xfd, 0xf8, 0xf0,
+ 0x8e, 0xb1, 0x7d, 0x85, 0x13, 0xac, 0x56, 0x1f, 0x4e, 0x91, 0xef, 0x67,
+ 0x36, 0x49, 0x30, 0x5e, 0x32, 0x07, 0x08, 0x0a, 0x86, 0xdc, 0x82, 0x79,
+ 0x4a, 0x52, 0x94, 0x27, 0x85, 0xbd, 0x47, 0xc1, 0x31, 0x5e, 0xa5, 0x22,
+ 0x1e, 0x75, 0xab, 0xe7, 0x8f, 0x09, 0xd0, 0x18, 0x94, 0x28, 0x3d, 0x38,
+ 0x5a, 0x28, 0xd6, 0xb7, 0x23, 0x5a, 0xbb, 0x63, 0x0b, 0x4b, 0x17, 0xdd,
+ 0x3b, 0xf4, 0xa8, 0x89, 0x0b, 0xff, 0xf3, 0x6b, 0xef, 0xb6, 0x6f, 0xc4,
+ 0xe1, 0x7d, 0x46, 0xe2, 0xc5, 0x69, 0x12, 0x5f, 0x31, 0xbf, 0xff, 0xdf,
+ 0x89, 0xc2, 0xfa, 0x8d, 0xcd, 0x9d, 0x34, 0x1e, 0x7c, 0x31, 0x62, 0xfc,
+ 0xde, 0xfe, 0x1d, 0x62, 0xdb, 0x3b, 0x1a, 0x6d, 0xd9, 0x0b, 0x59, 0x88,
+ 0xc2, 0xed, 0xd7, 0xb4, 0xfa, 0x58, 0xbf, 0xf3, 0xcb, 0x67, 0x35, 0xd3,
+ 0xbf, 0x4a, 0x89, 0x78, 0xbe, 0x7f, 0x3c, 0xeb, 0x16, 0xd9, 0x64, 0x48,
+ 0x1c, 0x77, 0x71, 0x42, 0xff, 0xe8, 0xde, 0xf3, 0x36, 0xbb, 0x94, 0x4c,
+ 0xb1, 0x78, 0x28, 0x70, 0x2c, 0x5f, 0xc3, 0xfe, 0x31, 0x1a, 0xb1, 0x78,
+ 0xe5, 0x0b, 0x16, 0x0a, 0xf0, 0xf2, 0x83, 0x2e, 0xba, 0x62, 0x58, 0xbf,
+ 0xf6, 0xc3, 0x76, 0x18, 0xa0, 0xa2, 0x4b, 0x17, 0xfd, 0xb6, 0x3c, 0xda,
+ 0x8d, 0xf3, 0x2c, 0x5f, 0xfe, 0xfc, 0x70, 0x31, 0xc6, 0xa6, 0xc2, 0x02,
+ 0xc5, 0xf6, 0x85, 0xee, 0x2c, 0x5f, 0xc3, 0x63, 0x5c, 0x80, 0xb1, 0x7e,
+ 0x82, 0x00, 0xce, 0xb1, 0x7e, 0xd0, 0x0e, 0xdc, 0x58, 0xb8, 0x07, 0x58,
+ 0xbd, 0x05, 0xda, 0xc5, 0xfb, 0xc1, 0x9c, 0xa1, 0x62, 0xcd, 0xa3, 0xde,
+ 0xf8, 0xc1, 0x0e, 0xdf, 0xfe, 0xfe, 0xf8, 0x20, 0x6e, 0xe0, 0xf3, 0x5d,
+ 0xac, 0x5f, 0xe6, 0xd3, 0x8d, 0x88, 0xd5, 0x8b, 0xa3, 0xcb, 0x17, 0xfc,
+ 0xf3, 0xea, 0x3b, 0x93, 0x1d, 0x62, 0xff, 0xf0, 0x86, 0xda, 0x0e, 0x60,
+ 0x82, 0x72, 0x99, 0x62, 0xa4, 0x9a, 0xc3, 0x19, 0xfd, 0x40, 0x06, 0x64,
+ 0x2f, 0xc3, 0xbb, 0xf8, 0x1f, 0x8d, 0x31, 0xd6, 0x2f, 0xfd, 0x37, 0x23,
+ 0x7b, 0xfe, 0x3b, 0x99, 0x62, 0xa0, 0xfc, 0x9c, 0xba, 0xfb, 0x3c, 0x1c,
+ 0xeb, 0x17, 0xfc, 0x51, 0x36, 0x9e, 0x67, 0xe2, 0xc5, 0xc1, 0x9d, 0x62,
+ 0xb7, 0x9e, 0x98, 0x43, 0xab, 0xbe, 0x05, 0x8a, 0x63, 0x7c, 0xe4, 0xd7,
+ 0xec, 0x9f, 0x38, 0x75, 0x8b, 0xf6, 0xa3, 0xcd, 0xbd, 0x62, 0xfd, 0x3b,
+ 0xf1, 0xc0, 0xb1, 0x4c, 0x7a, 0x6e, 0x55, 0x7f, 0xf4, 0xdb, 0x43, 0x28,
+ 0xde, 0xfb, 0xe2, 0x65, 0x8a, 0x58, 0xbf, 0xf7, 0xb9, 0x9c, 0x82, 0xf6,
+ 0x01, 0x62, 0xfb, 0xd9, 0xa9, 0x96, 0x2f, 0x79, 0xf7, 0xac, 0x56, 0x1e,
+ 0x1b, 0x92, 0x54, 0x22, 0x86, 0x50, 0x81, 0xbc, 0x7c, 0x08, 0xb1, 0x7e,
+ 0x7e, 0x46, 0xfc, 0x58, 0xa9, 0x8f, 0xbf, 0x44, 0xfb, 0xc7, 0xea, 0x13,
+ 0x9b, 0xc4, 0xd7, 0x8c, 0x72, 0xed, 0x42, 0xc5, 0x05, 0x17, 0xc8, 0xa4,
+ 0x7c, 0x34, 0xcc, 0x24, 0xec, 0xb9, 0x8a, 0x26, 0x8f, 0x7f, 0x50, 0xc8,
+ 0x39, 0x07, 0xe1, 0x6c, 0x43, 0xfe, 0x7c, 0xdf, 0x1d, 0xd8, 0x43, 0x4b,
+ 0xb0, 0x96, 0x2f, 0xc6, 0x46, 0xec, 0x1d, 0x62, 0xfe, 0xdb, 0xcf, 0xe3,
+ 0x79, 0x62, 0x86, 0x7e, 0x58, 0x2c, 0xc5, 0x96, 0xed, 0x62, 0xff, 0x80,
+ 0xfe, 0x9c, 0x53, 0x46, 0xea, 0xc5, 0x0c, 0xf4, 0x98, 0x4e, 0xfe, 0x21,
+ 0x7a, 0x68, 0x35, 0x62, 0xf0, 0x5d, 0xb4, 0xb1, 0x4e, 0x7a, 0x22, 0x30,
+ 0xbf, 0xfb, 0x1b, 0xbe, 0x7a, 0x27, 0x3b, 0xc9, 0x62, 0x98, 0xf9, 0xf4,
+ 0x43, 0x7f, 0x85, 0xef, 0x94, 0x66, 0x96, 0x2f, 0xc5, 0x93, 0x87, 0xbd,
+ 0x62, 0xfb, 0x27, 0x0f, 0x7a, 0xc5, 0xf4, 0x76, 0x37, 0xda, 0x7a, 0x64,
+ 0x59, 0x7f, 0xff, 0x4b, 0xe1, 0xf7, 0xef, 0xb3, 0x83, 0x72, 0x35, 0x84,
+ 0xb1, 0x43, 0x44, 0xd3, 0x1d, 0x5f, 0xff, 0x36, 0xb6, 0xfe, 0x1b, 0xdc,
+ 0x17, 0x42, 0x85, 0x8b, 0xe6, 0x9c, 0x1b, 0xab, 0x16, 0xed, 0x62, 0xf3,
+ 0xbf, 0x4a, 0x8a, 0x5c, 0xa5, 0x8a, 0xc3, 0xc9, 0xe8, 0x4e, 0x62, 0xab,
+ 0xe2, 0xf4, 0x69, 0x62, 0xff, 0xb3, 0x5b, 0xb8, 0x3c, 0xd7, 0x6b, 0x14,
+ 0xc7, 0xbf, 0xbc, 0x8a, 0xff, 0xd1, 0x2f, 0xbb, 0x77, 0xc8, 0x35, 0x62,
+ 0xa7, 0x55, 0xef, 0x28, 0xc8, 0x0d, 0x22, 0x99, 0x4f, 0x4e, 0x1f, 0x84,
+ 0x79, 0x11, 0xdf, 0xf3, 0x7b, 0x8f, 0xde, 0xb9, 0xc5, 0x8b, 0xff, 0xda,
+ 0x9f, 0x6e, 0xf1, 0x7e, 0x18, 0xf0, 0x35, 0x8a, 0xfa, 0x22, 0xdc, 0xee,
+ 0xf4, 0x6b, 0xcb, 0x17, 0xf0, 0xfb, 0x8d, 0x37, 0x6b, 0x17, 0xde, 0x9f,
+ 0x0c, 0x58, 0xa9, 0x1f, 0x93, 0x0e, 0x91, 0x85, 0xff, 0xfa, 0x67, 0xd4,
+ 0xfe, 0x6d, 0xdc, 0x9d, 0xe6, 0x8d, 0xd5, 0x8b, 0xe3, 0x75, 0x9c, 0x58,
+ 0xa8, 0x44, 0x1b, 0x2f, 0xdf, 0xfa, 0x0a, 0x3f, 0xb4, 0x44, 0x2e, 0x96,
+ 0x2f, 0x4c, 0x7c, 0x58, 0xbc, 0x27, 0xe2, 0xc5, 0xe3, 0x94, 0xcb, 0x17,
+ 0x84, 0xf3, 0x2c, 0x56, 0x1b, 0xc9, 0x87, 0xaf, 0xd0, 0x07, 0xef, 0x8b,
+ 0x17, 0x89, 0x80, 0xb1, 0x7f, 0xc3, 0x72, 0x03, 0x8c, 0x5b, 0xab, 0x17,
+ 0xb3, 0xdc, 0x58, 0xa8, 0x3f, 0x5c, 0x1c, 0xe1, 0xe5, 0xff, 0xf9, 0xfd,
+ 0xf8, 0x23, 0x76, 0xc4, 0xfe, 0x8d, 0xfc, 0x58, 0xa9, 0x2a, 0x20, 0x19,
+ 0x0e, 0x20, 0xcc, 0x3d, 0xf5, 0x90, 0x10, 0xfa, 0x13, 0xdb, 0xcb, 0x6f,
+ 0xfd, 0x83, 0x72, 0x00, 0x67, 0x28, 0x58, 0xbe, 0x72, 0x18, 0x45, 0x8b,
+ 0xfc, 0x59, 0x2d, 0xbf, 0x8d, 0xd5, 0x8a, 0xdd, 0x3d, 0xc3, 0x92, 0x52,
+ 0xc5, 0xfb, 0x9e, 0xd4, 0x71, 0x62, 0xd1, 0xd9, 0xb5, 0xf0, 0x65, 0xff,
+ 0x03, 0x9a, 0x8e, 0xe4, 0xc7, 0x58, 0xbd, 0xe7, 0xde, 0xb1, 0x7e, 0x9c,
+ 0x53, 0x46, 0xea, 0xc5, 0xf0, 0xa6, 0x8d, 0xd5, 0x8b, 0x9e, 0x7d, 0xa7,
+ 0xab, 0x39, 0x75, 0x42, 0x38, 0x1c, 0xec, 0x4e, 0x97, 0xfd, 0x0c, 0x0e,
+ 0x41, 0xdf, 0xcb, 0x17, 0xfc, 0xdc, 0x99, 0x8b, 0xd0, 0x05, 0x8b, 0xfa,
+ 0x01, 0xc7, 0x20, 0x2c, 0x5f, 0xfc, 0x5e, 0xdf, 0x1a, 0xe3, 0x94, 0x6e,
+ 0xac, 0x5f, 0xce, 0xd3, 0xed, 0x3e, 0x2c, 0x54, 0x93, 0x44, 0xd1, 0x71,
+ 0xce, 0x3e, 0x73, 0xc2, 0xdf, 0x24, 0x5f, 0xe8, 0xdd, 0xe4, 0x1d, 0xfc,
+ 0xb1, 0x73, 0x92, 0xc5, 0xff, 0x40, 0x36, 0xfe, 0x0e, 0xe4, 0xb1, 0x5d,
+ 0x9e, 0x86, 0xf1, 0x6b, 0xff, 0xec, 0x18, 0x73, 0x73, 0xdf, 0xc1, 0x8b,
+ 0xdc, 0x58, 0xa9, 0x23, 0xff, 0x50, 0x86, 0xf9, 0x2d, 0xfd, 0x06, 0x37,
+ 0xc5, 0xba, 0xb1, 0x7f, 0x77, 0x2e, 0x39, 0x76, 0xb1, 0x50, 0xb9, 0x27,
+ 0x25, 0xac, 0x94, 0x96, 0xd1, 0xab, 0xe8, 0xd4, 0x33, 0x2b, 0xff, 0x14,
+ 0xdb, 0x75, 0x1d, 0xc9, 0x8e, 0xb1, 0x7f, 0xfb, 0x7c, 0x17, 0xbd, 0xfc,
+ 0x18, 0xbd, 0xc5, 0x8b, 0xff, 0xff, 0x7b, 0x73, 0x3c, 0x1e, 0xf7, 0xf0,
+ 0x73, 0xb7, 0xcb, 0x06, 0xe7, 0x58, 0xba, 0x0e, 0xb1, 0x50, 0x98, 0xde,
+ 0x21, 0xb2, 0x6e, 0x9d, 0x2f, 0xc5, 0x37, 0x98, 0xd5, 0x8b, 0xa2, 0x4b,
+ 0x17, 0xe6, 0x18, 0x8b, 0x16, 0x2f, 0xd0, 0x3f, 0xbf, 0x6b, 0x17, 0xfd,
+ 0xf9, 0x67, 0x9c, 0x01, 0xf6, 0xb1, 0x7d, 0xef, 0xe4, 0xb6, 0x9f, 0x2b,
+ 0x14, 0xd4, 0xc8, 0xc6, 0x28, 0x46, 0x54, 0x26, 0x5e, 0xc5, 0x42, 0x86,
+ 0xed, 0xff, 0x4b, 0x35, 0x36, 0x14, 0x1d, 0x62, 0xfc, 0x08, 0xeb, 0x0e,
+ 0xb1, 0x7f, 0xb2, 0x7e, 0x44, 0xc2, 0xd2, 0xc5, 0xf8, 0xf8, 0xed, 0x3a,
+ 0xc5, 0x32, 0x30, 0x34, 0x72, 0x45, 0x3c, 0x36, 0xba, 0x58, 0xb1, 0x7e,
+ 0xe1, 0xba, 0x73, 0x16, 0x2f, 0x14, 0x1d, 0x62, 0x86, 0x78, 0xfa, 0x2b,
+ 0xbe, 0xef, 0x77, 0x24, 0xb1, 0x7f, 0x9f, 0x53, 0x67, 0x82, 0x6f, 0x58,
+ 0xb8, 0x1c, 0x58, 0xbc, 0x3e, 0x32, 0xc5, 0x41, 0xb5, 0x71, 0x8a, 0x84,
+ 0xdb, 0xc6, 0x77, 0x8b, 0xce, 0x44, 0x22, 0x73, 0x1b, 0xaf, 0x9f, 0xef,
+ 0x3a, 0xc5, 0xfb, 0xe2, 0x37, 0x09, 0x62, 0xf1, 0x8f, 0x25, 0x8b, 0xf4,
+ 0xce, 0x07, 0xe9, 0x62, 0xfb, 0x5e, 0x28, 0x58, 0xac, 0x3c, 0xc7, 0x2a,
+ 0xbf, 0xc6, 0x13, 0xfa, 0x4e, 0x35, 0x8b, 0xb7, 0x19, 0x62, 0xfd, 0xe0,
+ 0xe7, 0x8f, 0xac, 0x5f, 0xb3, 0xde, 0x63, 0x56, 0x2f, 0xfa, 0x3f, 0xc7,
+ 0xf4, 0x68, 0x22, 0xc5, 0xff, 0x8e, 0xe3, 0x0e, 0x69, 0x41, 0x76, 0xb1,
+ 0x43, 0x3f, 0xd6, 0x3b, 0xbf, 0x85, 0xf8, 0xd6, 0x01, 0x62, 0xf6, 0xf8,
+ 0xd2, 0xc5, 0xf6, 0x80, 0x1e, 0xf5, 0x8b, 0xcc, 0x67, 0x96, 0x2a, 0x48,
+ 0x92, 0x62, 0xef, 0x8f, 0xf0, 0x9e, 0xa7, 0x55, 0xc8, 0x32, 0x3c, 0x29,
+ 0xe9, 0xab, 0xb2, 0x06, 0x34, 0x98, 0x6b, 0x45, 0x7f, 0x85, 0x37, 0xa1,
+ 0x67, 0x7f, 0x8b, 0xd9, 0xc6, 0x7f, 0xac, 0x5f, 0x72, 0x5c, 0x75, 0x8b,
+ 0xfe, 0x03, 0x7f, 0x34, 0xf3, 0x71, 0x62, 0xff, 0xfa, 0x45, 0x13, 0x87,
+ 0x37, 0x3f, 0x81, 0x34, 0x05, 0x8b, 0xd2, 0x1e, 0xf5, 0x8a, 0x83, 0xf6,
+ 0x75, 0x6b, 0xfb, 0x69, 0xf3, 0xcf, 0xe5, 0x8b, 0xfb, 0xec, 0x36, 0xd7,
+ 0x4b, 0x14, 0xb1, 0x7c, 0xe5, 0xdc, 0x96, 0x2b, 0xa3, 0x5f, 0xf0, 0xcb,
+ 0x73, 0x11, 0x61, 0xd1, 0x83, 0xaf, 0x5e, 0xee, 0x6e, 0x2c, 0x57, 0x67,
+ 0xaa, 0xe6, 0xb7, 0xa1, 0x86, 0xb1, 0x7f, 0x7d, 0xbc, 0x50, 0x75, 0x8b,
+ 0xfe, 0x2e, 0x9f, 0xfd, 0xcb, 0x3c, 0xb1, 0x53, 0x1f, 0x43, 0x96, 0xd4,
+ 0x2a, 0xf2, 0x19, 0x97, 0x64, 0x67, 0x85, 0x83, 0xc6, 0x4b, 0xc2, 0x21,
+ 0x42, 0x12, 0xff, 0x61, 0x92, 0x6e, 0x08, 0xeb, 0x17, 0x6f, 0xe2, 0xc5,
+ 0xfc, 0x2e, 0x44, 0xc2, 0xd2, 0xc5, 0xfb, 0x27, 0xcf, 0xf1, 0x62, 0xa0,
+ 0xfc, 0xfe, 0x34, 0x46, 0x17, 0xc7, 0x14, 0xda, 0x58, 0xbb, 0x5c, 0x58,
+ 0xbf, 0xf6, 0x73, 0x6f, 0xe1, 0x88, 0x53, 0xac, 0x56, 0x1e, 0xc9, 0x0c,
+ 0x57, 0x48, 0xcb, 0x39, 0x6e, 0xf7, 0xeb, 0xfe, 0x04, 0x00, 0x3d, 0xf0,
+ 0x41, 0x16, 0x2f, 0xff, 0xd3, 0xc7, 0xa3, 0xed, 0xe9, 0x36, 0xba, 0xfc,
+ 0x2c, 0x5d, 0x07, 0x58, 0xa8, 0x54, 0xa5, 0x91, 0xb9, 0xb1, 0x9b, 0x9f,
+ 0x09, 0x5e, 0xff, 0xa2, 0x6f, 0x30, 0xf0, 0xa6, 0x58, 0xbf, 0xff, 0xed,
+ 0x77, 0xd3, 0x77, 0xb4, 0xd7, 0xdb, 0xcf, 0xbf, 0x50, 0x43, 0x58, 0xbf,
+ 0xe7, 0xe0, 0x7e, 0xef, 0xa6, 0x3a, 0xc5, 0xbf, 0x08, 0xad, 0x13, 0x85,
+ 0xf3, 0x1b, 0xb9, 0x8b, 0x17, 0xf0, 0x7e, 0x89, 0xcb, 0xb5, 0x8b, 0xff,
+ 0xee, 0xbe, 0xf3, 0x07, 0x34, 0x98, 0xb0, 0xf0, 0xb1, 0x78, 0x98, 0xeb,
+ 0x15, 0xa4, 0x63, 0x00, 0x98, 0x8c, 0x7c, 0xa7, 0x7f, 0xde, 0x6f, 0x16,
+ 0x1b, 0x9f, 0x58, 0xbf, 0xfb, 0xdc, 0x0f, 0x98, 0x42, 0xf4, 0x7d, 0x62,
+ 0xfe, 0x87, 0x2f, 0x61, 0x2c, 0x56, 0x1f, 0x89, 0x23, 0x5f, 0xdb, 0x7d,
+ 0x13, 0xc4, 0xcb, 0x17, 0xee, 0x6e, 0xc6, 0x8d, 0x58, 0xb4, 0x1a, 0x7b,
+ 0xfd, 0x99, 0x5f, 0xcf, 0x33, 0x6a, 0x27, 0x58, 0xba, 0x27, 0x58, 0xaf,
+ 0x9e, 0x38, 0x42, 0xfb, 0xf0, 0x43, 0xc6, 0x79, 0x62, 0xff, 0xe0, 0xfd,
+ 0x28, 0x1b, 0x96, 0x78, 0x0b, 0x17, 0xf9, 0xb7, 0xf7, 0x2c, 0x09, 0x25,
+ 0x8a, 0xc4, 0x54, 0x68, 0xa8, 0x91, 0x6e, 0xc3, 0xac, 0x54, 0x97, 0x2e,
+ 0xc7, 0x0e, 0x7c, 0x87, 0x73, 0x1e, 0x1e, 0x15, 0x5f, 0x7f, 0x77, 0x01,
+ 0x43, 0x33, 0x79, 0x75, 0xf8, 0x23, 0x1e, 0x38, 0xb1, 0x7e, 0x7d, 0xf9,
+ 0xae, 0x2c, 0x5f, 0xa7, 0x0f, 0x7b, 0xc9, 0x62, 0x86, 0x88, 0x13, 0x95,
+ 0x11, 0x55, 0x8c, 0x58, 0xbc, 0x4c, 0x75, 0x8b, 0x4e, 0xb1, 0x6f, 0xb9,
+ 0xaf, 0x0c, 0x72, 0xf4, 0xdc, 0x85, 0x8b, 0xed, 0x03, 0x73, 0x16, 0x28,
+ 0xd3, 0xc4, 0x71, 0xeb, 0xa6, 0xc5, 0x8a, 0x58, 0xbf, 0x47, 0xbe, 0xf3,
+ 0x39, 0xa4, 0xe0, 0xc5, 0xfc, 0x0e, 0xc1, 0x9a, 0xc5, 0x8b, 0xfb, 0xa8,
+ 0x6f, 0x34, 0x96, 0x2f, 0x46, 0x79, 0x62, 0xfd, 0x9a, 0xd0, 0xa7, 0x58,
+ 0xb9, 0xc0, 0x73, 0xc6, 0xf0, 0xe5, 0x42, 0x34, 0x30, 0xbd, 0x9d, 0x2f,
+ 0x87, 0xf7, 0xed, 0x62, 0xfe, 0x07, 0x23, 0xf1, 0xc5, 0x8a, 0x83, 0xd2,
+ 0x72, 0x4b, 0xef, 0x73, 0x27, 0x58, 0xbf, 0xff, 0xdf, 0x6d, 0xee, 0x06,
+ 0x94, 0x6f, 0x73, 0xc7, 0xc2, 0x3a, 0xc5, 0x76, 0x88, 0x9f, 0x92, 0x5d,
+ 0x93, 0xac, 0x53, 0x9b, 0xc2, 0x24, 0xa8, 0x57, 0x64, 0x32, 0xfc, 0x42,
+ 0x66, 0xb9, 0x91, 0xbf, 0x18, 0x69, 0x3f, 0xf2, 0x1c, 0xb7, 0xff, 0xed,
+ 0x38, 0xf6, 0xc7, 0xf6, 0xfd, 0xb5, 0x92, 0xde, 0xb1, 0x73, 0x8d, 0x62,
+ 0x98, 0xfc, 0xdd, 0x72, 0xff, 0xfe, 0xe9, 0xb9, 0x83, 0xeb, 0xed, 0xec,
+ 0x98, 0xa0, 0xeb, 0x15, 0x31, 0xfe, 0xfc, 0x82, 0xe0, 0x74, 0xb1, 0x6e,
+ 0x2c, 0x58, 0xde, 0x1a, 0xb1, 0x0c, 0xdf, 0xd3, 0xbe, 0x7b, 0x0e, 0xb1,
+ 0x4c, 0x7a, 0xce, 0x51, 0x78, 0x0f, 0xd2, 0xc5, 0xf1, 0x9e, 0x28, 0x58,
+ 0xbf, 0xc5, 0x8d, 0xac, 0xf4, 0x2c, 0x5f, 0xd8, 0xda, 0xcf, 0x42, 0xc5,
+ 0xe2, 0x8f, 0xed, 0x3d, 0xd2, 0x31, 0xac, 0x45, 0x98, 0xa1, 0x01, 0x7f,
+ 0xff, 0x3e, 0x9f, 0xb9, 0x07, 0xc0, 0x60, 0xba, 0x82, 0x02, 0xc5, 0xf1,
+ 0x93, 0x72, 0x16, 0x2f, 0xff, 0x68, 0x0e, 0x3d, 0xb9, 0xf8, 0x29, 0xc2,
+ 0x2c, 0x5f, 0x89, 0xe7, 0x8f, 0x2c, 0x57, 0xcf, 0xdf, 0x89, 0xf7, 0xe9,
+ 0xdf, 0x99, 0x25, 0x8b, 0xff, 0xe1, 0xe6, 0xf7, 0xd4, 0xc1, 0xc9, 0xfc,
+ 0xe7, 0x58, 0xbb, 0x37, 0x56, 0x2a, 0x11, 0x2e, 0xc5, 0x3a, 0x54, 0xbf,
+ 0x9f, 0xb0, 0x1d, 0xb8, 0xb1, 0x63, 0x56, 0x2f, 0xda, 0xcd, 0xe3, 0x85,
+ 0x8a, 0x85, 0x68, 0xb3, 0xc3, 0x47, 0xa2, 0x7e, 0xd7, 0xa6, 0x84, 0xe6,
+ 0xa1, 0x73, 0xf2, 0xe0, 0x17, 0xf8, 0x4e, 0xff, 0xf4, 0x6b, 0xa6, 0x33,
+ 0x51, 0xdc, 0x98, 0xeb, 0x17, 0xf3, 0x18, 0xf3, 0x41, 0xd6, 0x2f, 0x04,
+ 0x8e, 0x2c, 0x57, 0x11, 0x37, 0xe4, 0xd1, 0x17, 0xdb, 0x64, 0x2a, 0xed,
+ 0xe8, 0xf6, 0x04, 0x9d, 0x89, 0xb3, 0x61, 0x96, 0x85, 0xb8, 0xc4, 0x4f,
+ 0xb2, 0xcf, 0x1a, 0x8c, 0x9f, 0xc7, 0x0d, 0x9c, 0x96, 0x31, 0xd4, 0x3f,
+ 0xbb, 0x84, 0xa3, 0x4a, 0xd0, 0xdd, 0x7a, 0x9a, 0x74, 0xb7, 0x51, 0xc0,
+ 0x1e, 0x36, 0xaf, 0xca, 0x63, 0x79, 0x67, 0x40, 0x97, 0x16, 0x52, 0xb1,
+ 0xf9, 0x3a, 0x13, 0xe9, 0xcc, 0x71, 0x46, 0xd7, 0xb9, 0x0a, 0x40, 0xe5,
+ 0xb2, 0x84, 0x8c, 0xb6, 0xfd, 0xae, 0x9d, 0xfa, 0x54, 0x53, 0x85, 0xfd,
+ 0xf6, 0x39, 0x39, 0xab, 0x16, 0xd9, 0xc3, 0xe5, 0x63, 0x7b, 0xc1, 0x67,
+ 0x82, 0xc5, 0x8b, 0xfa, 0x0f, 0x81, 0x23, 0xcb, 0x17, 0xdf, 0x82, 0x35,
+ 0x62, 0xfa, 0x3a, 0x8f, 0xac, 0x51, 0xcf, 0xd7, 0xc5, 0xe1, 0x91, 0xde,
+ 0xe0, 0x72, 0x58, 0xbf, 0xef, 0xb9, 0x79, 0xe4, 0xc0, 0x58, 0xac, 0x3d,
+ 0x76, 0x1f, 0xbf, 0xed, 0x3f, 0x3f, 0x98, 0x5d, 0x2c, 0x5f, 0xc2, 0xe6,
+ 0x78, 0x39, 0xd6, 0x29, 0x8f, 0xab, 0xe7, 0x37, 0xe3, 0xeb, 0x59, 0xc5,
+ 0x8b, 0xff, 0xf7, 0xc5, 0xed, 0x47, 0xb9, 0x9d, 0x72, 0x35, 0xd2, 0xc5,
+ 0xf0, 0x82, 0x3c, 0xcb, 0x17, 0xf9, 0x8d, 0xc9, 0x40, 0x38, 0xb1, 0x52,
+ 0x3d, 0xae, 0x13, 0x5e, 0x1c, 0x1d, 0x62, 0xff, 0x47, 0x9b, 0xa6, 0x1c,
+ 0x2c, 0x5b, 0x4b, 0x17, 0xff, 0xd3, 0x13, 0x73, 0xd0, 0x1b, 0x6a, 0x68,
+ 0xfa, 0xc5, 0x48, 0xf9, 0x30, 0x4a, 0x86, 0x8d, 0x5d, 0x0e, 0xfa, 0x12,
+ 0xf7, 0xb3, 0x8c, 0xb1, 0x7f, 0xa3, 0xd0, 0xc4, 0x1f, 0x16, 0x2b, 0x0f,
+ 0x3f, 0x43, 0x97, 0xff, 0xec, 0xf7, 0x03, 0xe7, 0x9a, 0x0b, 0xc4, 0xe0,
+ 0x58, 0xbf, 0xbb, 0x94, 0x1c, 0x53, 0x2c, 0x5f, 0xc7, 0x1c, 0x70, 0x44,
+ 0xb1, 0x7a, 0x50, 0x75, 0x8b, 0xfd, 0xe9, 0x61, 0xae, 0x40, 0x58, 0xbb,
+ 0xec, 0xb1, 0x5d, 0x9f, 0x43, 0x0e, 0xf8, 0xd2, 0xa1, 0x1e, 0xcc, 0x62,
+ 0xf0, 0x96, 0xbf, 0xba, 0x7d, 0x78, 0xa1, 0x62, 0xfb, 0x9b, 0x78, 0x1a,
+ 0xc5, 0xff, 0xd9, 0xbf, 0x07, 0xa8, 0x69, 0x3f, 0x16, 0x2c, 0xfd, 0x9f,
+ 0x66, 0x89, 0xef, 0xde, 0xee, 0x50, 0x62, 0xc5, 0xfc, 0xe1, 0xe6, 0xf8,
+ 0xe2, 0xc5, 0x61, 0xed, 0x88, 0xae, 0xff, 0xef, 0xb0, 0x7e, 0x62, 0x14,
+ 0xb3, 0x8b, 0x17, 0xfd, 0xdf, 0x0b, 0x07, 0xf7, 0x31, 0x62, 0xfb, 0x8d,
+ 0xe8, 0x58, 0xa6, 0x3d, 0xd7, 0x3b, 0xbf, 0xfe, 0xc9, 0xf3, 0xbf, 0x71,
+ 0x8a, 0x00, 0xe7, 0x58, 0xac, 0x4c, 0x48, 0xd8, 0x51, 0x70, 0x82, 0xff,
+ 0xd9, 0xf8, 0xd6, 0x6c, 0x98, 0x61, 0x89, 0x17, 0x31, 0x8b, 0x17, 0x4f,
+ 0xb2, 0x16, 0x32, 0x29, 0xe2, 0x13, 0xb2, 0x84, 0x38, 0xe1, 0x15, 0x84,
+ 0x3d, 0x14, 0xf7, 0x0b, 0x36, 0x87, 0xbc, 0xd0, 0x84, 0x39, 0x0f, 0xe3,
+ 0x4b, 0x73, 0x20, 0x42, 0x68, 0xa1, 0x07, 0xe8, 0xcc, 0xf7, 0x0d, 0x82,
+ 0x22, 0xdf, 0xb5, 0xd3, 0xbf, 0x4a, 0x8a, 0xf0, 0xbf, 0xff, 0xb0, 0x7f,
+ 0x80, 0xf6, 0x7c, 0x4e, 0x0e, 0x72, 0x00, 0x91, 0x6d, 0x9c, 0x44, 0xb6,
+ 0xe1, 0xbd, 0xff, 0xdb, 0x2f, 0x2d, 0x9c, 0xd7, 0x4e, 0xfd, 0x2a, 0x24,
+ 0x72, 0xec, 0x3a, 0xc5, 0xde, 0xc5, 0x8a, 0xe8, 0xd7, 0x76, 0x2f, 0x7f,
+ 0xfd, 0x9e, 0x6f, 0x8b, 0xee, 0xdd, 0xf2, 0x0d, 0x58, 0xbf, 0xfc, 0x6b,
+ 0x6b, 0x35, 0x28, 0xff, 0xd8, 0x0b, 0x17, 0x7c, 0x6b, 0x17, 0xff, 0xef,
+ 0x40, 0xe0, 0x41, 0x7d, 0x47, 0x98, 0x11, 0x25, 0x8b, 0xc4, 0xfb, 0x32,
+ 0x3f, 0x1d, 0xe3, 0x17, 0xfc, 0x27, 0xfe, 0x0d, 0xdf, 0xa5, 0x8b, 0xff,
+ 0xda, 0x8c, 0xef, 0x67, 0xd2, 0x80, 0x1d, 0x96, 0x2b, 0xa4, 0x43, 0xf8,
+ 0xe6, 0xff, 0xf1, 0x8d, 0x36, 0xc9, 0x66, 0xb3, 0x3b, 0x31, 0x62, 0xf3,
+ 0x02, 0x16, 0x2f, 0x75, 0x87, 0x48, 0xd9, 0x2f, 0x2f, 0xb1, 0xfb, 0x02,
+ 0xc5, 0xff, 0xfb, 0xf0, 0x42, 0xe7, 0xdb, 0x59, 0xbe, 0x0b, 0xcb, 0x17,
+ 0xff, 0x36, 0xb3, 0x52, 0x8f, 0xfd, 0x80, 0xb1, 0x7d, 0xd3, 0xbf, 0x4a,
+ 0x89, 0x20, 0xbf, 0x9f, 0x59, 0xbf, 0xf8, 0xb1, 0x53, 0xa6, 0x3b, 0x22,
+ 0x33, 0x55, 0xb4, 0x88, 0x03, 0x1b, 0xe9, 0xbd, 0x9d, 0x2c, 0x5f, 0xa1,
+ 0x80, 0xc7, 0x58, 0xa8, 0x3c, 0xc9, 0x12, 0xdf, 0xe8, 0x2f, 0x14, 0x1f,
+ 0x8b, 0x17, 0xff, 0xe6, 0xd3, 0x04, 0x82, 0x9e, 0x3c, 0xdf, 0x79, 0xd6,
+ 0x2f, 0xcf, 0x2f, 0x34, 0xeb, 0x15, 0x08, 0x80, 0x65, 0x7b, 0xff, 0xcf,
+ 0xe9, 0xb9, 0x83, 0x18, 0x9f, 0x52, 0x58, 0xbf, 0xfe, 0x7e, 0xf9, 0x9f,
+ 0x72, 0xc9, 0xce, 0x2f, 0xac, 0x5f, 0xfd, 0xf6, 0xef, 0xd9, 0xdf, 0xb5,
+ 0xa8, 0x58, 0xbf, 0xf9, 0xa0, 0xee, 0x30, 0xc2, 0x41, 0x49, 0x62, 0xde,
+ 0x58, 0xac, 0x47, 0x87, 0x4a, 0x3f, 0x47, 0xf2, 0x35, 0xff, 0xd8, 0x0d,
+ 0xcc, 0xd4, 0x4e, 0xfa, 0xe9, 0x62, 0xfc, 0xe0, 0xf6, 0x01, 0x62, 0x88,
+ 0xfc, 0x78, 0x93, 0x7f, 0xb3, 0xee, 0x72, 0x8e, 0xd6, 0x2e, 0x96, 0xcc,
+ 0x2e, 0x8c, 0x64, 0x69, 0xad, 0x09, 0x99, 0x88, 0x7f, 0x0b, 0x20, 0x10,
+ 0xf2, 0x33, 0xcf, 0x42, 0xb8, 0x32, 0x1b, 0xf0, 0xbb, 0xe9, 0xb8, 0xb1,
+ 0x7f, 0xd9, 0xe6, 0xe6, 0xb5, 0x92, 0x58, 0xb8, 0x2d, 0x05, 0x16, 0x2e,
+ 0x70, 0x2c, 0x52, 0xc5, 0x68, 0xd1, 0x9c, 0x5e, 0xf6, 0x7f, 0x67, 0x62,
+ 0x3e, 0x6c, 0x45, 0xbe, 0x34, 0x84, 0x75, 0x8b, 0x6c, 0xc3, 0x25, 0xa0,
+ 0x64, 0x78, 0xa3, 0xd4, 0x2f, 0x3b, 0x85, 0xf3, 0x12, 0x3c, 0xec, 0x20,
+ 0x21, 0x55, 0xc2, 0xbf, 0x42, 0x7c, 0x33, 0xab, 0xff, 0xb6, 0x5e, 0x5b,
+ 0x39, 0xae, 0x9d, 0xfa, 0x54, 0x49, 0x45, 0xf7, 0x4e, 0xfd, 0x2a, 0x2f,
+ 0x12, 0xf0, 0x70, 0x05, 0x8a, 0xd1, 0xe7, 0x9c, 0xc6, 0xff, 0xa5, 0xb3,
+ 0x9a, 0xe9, 0xdf, 0xa5, 0x44, 0x9a, 0x5b, 0x67, 0x0f, 0xb5, 0xc8, 0xaf,
+ 0xba, 0xfb, 0x12, 0xc5, 0xe0, 0xb0, 0xc9, 0xd6, 0x2e, 0x1e, 0xc4, 0xb1,
+ 0x7f, 0xc1, 0x5d, 0x83, 0x60, 0xfe, 0x1f, 0x38, 0xb1, 0x7f, 0xfe, 0x1b,
+ 0xcb, 0x82, 0xf4, 0x7b, 0x80, 0xf7, 0xbb, 0x58, 0xbd, 0xef, 0x76, 0xb1,
+ 0x70, 0x53, 0x62, 0xc3, 0xf8, 0x02, 0xcd, 0xfb, 0x9c, 0xc2, 0xc5, 0x8b,
+ 0xfe, 0xd7, 0x51, 0x3e, 0x61, 0x79, 0x62, 0xfe, 0x20, 0xe6, 0xd4, 0x6f,
+ 0x58, 0xbe, 0x76, 0xef, 0x8b, 0x17, 0xfb, 0x9c, 0xc0, 0x1b, 0xe2, 0x58,
+ 0xbf, 0xff, 0x7b, 0x80, 0x2c, 0xf7, 0xf3, 0xc5, 0x10, 0x75, 0x8b, 0x7d,
+ 0x62, 0xb1, 0x35, 0x16, 0x27, 0xdd, 0x3a, 0xf9, 0x93, 0x91, 0x91, 0xa9,
+ 0x8a, 0x97, 0xc3, 0xfc, 0x4e, 0xb1, 0x7f, 0xa3, 0xf0, 0x20, 0xd8, 0x22,
+ 0xc5, 0xfc, 0x0c, 0x28, 0xef, 0x8b, 0x15, 0x39, 0xf2, 0x31, 0xb5, 0xf8,
+ 0x9b, 0xa6, 0x1a, 0xc5, 0xed, 0xf1, 0x25, 0x8b, 0xf4, 0x7b, 0x99, 0xe5,
+ 0x8b, 0xce, 0x43, 0xc3, 0xc7, 0xf8, 0xfd, 0xfe, 0x63, 0x7b, 0xe6, 0x11,
+ 0xab, 0x17, 0xfc, 0xfa, 0x97, 0x30, 0x5a, 0x9d, 0x62, 0xb1, 0x31, 0x16,
+ 0x6f, 0xf9, 0x88, 0x8d, 0xaf, 0xd8, 0x2e, 0x9c, 0x96, 0x2f, 0x44, 0x79,
+ 0x62, 0xff, 0xb0, 0x03, 0xfc, 0x14, 0x18, 0xb1, 0x7c, 0x0e, 0x61, 0x2c,
+ 0x54, 0x1e, 0xdb, 0x1c, 0xdf, 0xf8, 0x5d, 0x73, 0x8f, 0xaf, 0x41, 0xab,
+ 0x17, 0xef, 0xfb, 0x99, 0xe5, 0x8b, 0xfd, 0xe6, 0xfb, 0x1b, 0xf6, 0x58,
+ 0xa6, 0x44, 0xfb, 0xa1, 0x08, 0xa6, 0xff, 0xfd, 0xf7, 0x60, 0x73, 0x0d,
+ 0x73, 0xea, 0x30, 0x96, 0x2f, 0xec, 0xf1, 0xb0, 0x52, 0x58, 0xb9, 0x86,
+ 0xb1, 0x50, 0x89, 0x91, 0xaa, 0x7c, 0xba, 0xff, 0x70, 0x19, 0x93, 0x06,
+ 0x75, 0x8b, 0xc2, 0x8e, 0xd6, 0x2a, 0x0f, 0x52, 0x46, 0xd7, 0xfd, 0x3b,
+ 0x73, 0x8e, 0x0f, 0x89, 0x62, 0xf8, 0x65, 0x1d, 0xac, 0x5b, 0x4b, 0x16,
+ 0x6d, 0x1b, 0x51, 0x11, 0xdf, 0xf6, 0x1a, 0x6b, 0xcb, 0x3b, 0xf2, 0xc5,
+ 0xe9, 0xe2, 0x75, 0x8b, 0xc2, 0x7e, 0xf0, 0xf6, 0xc3, 0x3c, 0xbf, 0xe2,
+ 0xc1, 0xb9, 0xf3, 0xbf, 0x2c, 0x5f, 0xb3, 0x3d, 0xfc, 0x58, 0xa8, 0x3e,
+ 0x0f, 0x9c, 0xdf, 0xe9, 0x73, 0x5a, 0x72, 0xf2, 0xc5, 0xff, 0xfb, 0x5e,
+ 0xfe, 0x11, 0x3f, 0xa0, 0xbd, 0xb9, 0x8b, 0x15, 0x08, 0x8a, 0x63, 0x4a,
+ 0xda, 0xba, 0x35, 0x39, 0x44, 0x9d, 0xc7, 0x0b, 0xfe, 0xa1, 0x8f, 0x34,
+ 0x20, 0xf4, 0x43, 0xf7, 0x0e, 0x42, 0x07, 0xd0, 0x94, 0xdf, 0x0a, 0xbb,
+ 0xf7, 0x30, 0xf1, 0xba, 0xb1, 0x7f, 0x36, 0x14, 0x77, 0xc5, 0x8b, 0xda,
+ 0x63, 0xac, 0x5f, 0xbd, 0xe8, 0x29, 0xd6, 0x2f, 0xfe, 0x3c, 0x75, 0xb4,
+ 0x3f, 0x71, 0xc8, 0xd5, 0x8a, 0x84, 0x48, 0x60, 0xeb, 0x14, 0xdf, 0xb0,
+ 0x7b, 0x08, 0xb7, 0x56, 0x2f, 0xe7, 0x20, 0x6c, 0x22, 0xdd, 0x58, 0xb9,
+ 0xc7, 0xbc, 0xf9, 0xf7, 0x0c, 0x68, 0xe9, 0xc1, 0xfe, 0x17, 0xa2, 0x84,
+ 0xa5, 0xe7, 0x2e, 0x96, 0x2f, 0x7e, 0x03, 0x58, 0xaf, 0x1b, 0xb3, 0x07,
+ 0x6f, 0xed, 0xbe, 0xe3, 0x91, 0xab, 0x17, 0xf1, 0x93, 0x7e, 0x08, 0xd5,
+ 0x8b, 0xd1, 0xb4, 0xeb, 0x17, 0x67, 0x96, 0x2f, 0xf4, 0x9b, 0xef, 0x26,
+ 0xfa, 0xc5, 0x7c, 0xf2, 0x9c, 0x5e, 0xa4, 0x8e, 0xcc, 0x31, 0xd1, 0x8f,
+ 0xda, 0x6f, 0xff, 0x0b, 0x52, 0x28, 0x94, 0x7b, 0xf8, 0x4b, 0x17, 0x77,
+ 0xe5, 0x8b, 0xbf, 0x0b, 0x17, 0xa3, 0xdc, 0xc3, 0x60, 0x18, 0xcd, 0xf6,
+ 0xa0, 0xa6, 0x58, 0xbf, 0x38, 0x09, 0xce, 0xb1, 0x52, 0x3f, 0xc6, 0x32,
+ 0x22, 0x3b, 0xf0, 0xff, 0xba, 0xc4, 0xb1, 0x7f, 0x8b, 0x0f, 0xb9, 0x9a,
+ 0x85, 0x8a, 0x83, 0xe0, 0x98, 0xae, 0xf4, 0x7b, 0x8b, 0x17, 0xfd, 0x07,
+ 0xfe, 0x0c, 0x6d, 0xda, 0xc5, 0xff, 0x7e, 0x0b, 0x26, 0x8d, 0x4e, 0xb1,
+ 0x7f, 0x16, 0x0f, 0xee, 0x62, 0xc5, 0xfd, 0x27, 0xd4, 0xff, 0x12, 0xc5,
+ 0xa0, 0x68, 0x98, 0x34, 0xea, 0x62, 0xeb, 0xfd, 0xee, 0xc2, 0xa6, 0x9a,
+ 0xc3, 0x58, 0xbf, 0xf3, 0xf7, 0x2e, 0x6d, 0x8e, 0x9c, 0x35, 0x8b, 0xdd,
+ 0xfa, 0x16, 0x2b, 0x13, 0xe6, 0xec, 0x89, 0x87, 0x75, 0x0d, 0x23, 0x9b,
+ 0xb9, 0xe0, 0x91, 0x2f, 0x82, 0x34, 0x1a, 0xb1, 0x7a, 0x5d, 0x9a, 0xb1,
+ 0x61, 0xac, 0x5f, 0xa4, 0xf1, 0xd8, 0x45, 0x8b, 0xf7, 0xbe, 0x2f, 0x71,
+ 0x62, 0x86, 0x7c, 0xfd, 0x89, 0x1c, 0xae, 0xfc, 0x38, 0xe0, 0x7c, 0x58,
+ 0xb8, 0x7d, 0xac, 0x51, 0xcf, 0x0c, 0x45, 0x57, 0x85, 0x1c, 0x58, 0xbf,
+ 0xf0, 0x3a, 0xfb, 0x68, 0x9b, 0xdc, 0x58, 0xbf, 0xe8, 0xce, 0x4d, 0xf6,
+ 0x33, 0xcb, 0x14, 0x74, 0x4c, 0x38, 0xef, 0x10, 0x2f, 0xd2, 0xfc, 0x11,
+ 0xab, 0x17, 0xe6, 0x7d, 0x47, 0x4b, 0x16, 0xdf, 0x87, 0xa3, 0xc2, 0x9b,
+ 0x8a, 0x75, 0x8a, 0x85, 0x53, 0x43, 0x25, 0xc8, 0x43, 0xb3, 0x9b, 0xc2,
+ 0xe8, 0x10, 0x80, 0x0c, 0xa6, 0x96, 0x2f, 0xe8, 0x19, 0xe3, 0x3c, 0xb1,
+ 0x5e, 0x37, 0x21, 0x86, 0x5f, 0xf4, 0x68, 0x0f, 0xed, 0xcc, 0xf2, 0xc5,
+ 0xda, 0xc5, 0x8b, 0xee, 0xdb, 0xb9, 0x2c, 0x5c, 0x1c, 0xeb, 0x14, 0xc6,
+ 0xfc, 0x04, 0xb5, 0xa4, 0x6a, 0x7c, 0x88, 0x07, 0x84, 0xad, 0x76, 0x1d,
+ 0x62, 0xf6, 0xb7, 0xfd, 0x62, 0xfd, 0x9a, 0x78, 0x1a, 0xc5, 0x41, 0xef,
+ 0x38, 0xb9, 0x10, 0x5e, 0x1e, 0x12, 0xc5, 0xf0, 0xa5, 0xe0, 0xd6, 0x2f,
+ 0xfd, 0xa1, 0x1f, 0xed, 0x07, 0x72, 0x58, 0xbf, 0xee, 0x41, 0xcb, 0x25,
+ 0x04, 0xb1, 0x7f, 0x98, 0xb6, 0xe1, 0xdb, 0xcb, 0x15, 0x3a, 0x33, 0xb4,
+ 0x4b, 0xe3, 0xed, 0xe6, 0xf7, 0xf1, 0x13, 0x1f, 0xd8, 0xb1, 0x71, 0x49,
+ 0x62, 0xed, 0x88, 0xc5, 0x8a, 0x11, 0xb5, 0xdc, 0x17, 0xa8, 0x4e, 0xbf,
+ 0x21, 0xd4, 0xe8, 0x01, 0x18, 0x6f, 0xfe, 0xe8, 0x4e, 0x3d, 0xf8, 0x3d,
+ 0x84, 0x5b, 0xab, 0x17, 0xcd, 0xf8, 0xde, 0xb1, 0x5a, 0x3f, 0x5f, 0x28,
+ 0xdf, 0xe8, 0xd4, 0x76, 0x0d, 0x42, 0xc5, 0xff, 0xb5, 0xac, 0xfe, 0x11,
+ 0x40, 0xd6, 0x2f, 0x30, 0x49, 0xd6, 0x2d, 0x3a, 0xc5, 0x41, 0xb3, 0x22,
+ 0x0b, 0xdf, 0x16, 0xea, 0xc5, 0xfc, 0x51, 0xef, 0xbc, 0x96, 0x2a, 0x0f,
+ 0x3a, 0x62, 0x1b, 0xde, 0x8d, 0x2c, 0x54, 0x26, 0xe5, 0x39, 0x13, 0x1a,
+ 0x4c, 0xe0, 0xed, 0xa2, 0x22, 0xb9, 0xfa, 0x58, 0xbf, 0xff, 0xfd, 0x84,
+ 0x4f, 0x2f, 0xb6, 0xd0, 0xf5, 0xa8, 0x93, 0x79, 0xb4, 0xe0, 0x58, 0xbf,
+ 0x0c, 0x53, 0x86, 0x75, 0x8b, 0xff, 0xf1, 0x40, 0xf8, 0x27, 0x69, 0x30,
+ 0x38, 0x2e, 0x2c, 0x5f, 0xd9, 0xef, 0xb7, 0x72, 0x58, 0xa9, 0x91, 0x08,
+ 0x4a, 0xb5, 0xd2, 0x34, 0xff, 0x0b, 0x0b, 0xfb, 0xbe, 0x61, 0xdf, 0x8b,
+ 0x17, 0xc3, 0xcf, 0xc2, 0xc5, 0xb4, 0xb1, 0x7e, 0x9f, 0x51, 0xde, 0x96,
+ 0x2a, 0x73, 0x7b, 0x82, 0x57, 0xff, 0xf7, 0xb6, 0x8e, 0x1f, 0x58, 0x40,
+ 0xdb, 0xcf, 0x73, 0xb5, 0x8b, 0xed, 0x4e, 0x0f, 0x2c, 0x5f, 0xc3, 0xc9,
+ 0x40, 0x38, 0xb1, 0x58, 0x8b, 0x46, 0x61, 0x11, 0x2d, 0x42, 0xb1, 0xd9,
+ 0x0c, 0x64, 0x69, 0x6c, 0x52, 0xe5, 0xe4, 0xbf, 0xc8, 0x6a, 0xdf, 0xff,
+ 0xc1, 0x60, 0xb6, 0x08, 0x3f, 0xb6, 0xcf, 0x9f, 0xdb, 0xb7, 0xfb, 0x8b,
+ 0x17, 0xff, 0xb3, 0xfd, 0x7d, 0xbb, 0xf6, 0x1d, 0xf8, 0xb1, 0x78, 0xf1,
+ 0xe5, 0x8b, 0xe9, 0xce, 0x2d, 0xd5, 0x8b, 0xf7, 0x8f, 0x31, 0x0d, 0x62,
+ 0xfb, 0xe1, 0xee, 0x3a, 0xc5, 0x62, 0x25, 0x9c, 0x74, 0x8a, 0x04, 0x55,
+ 0x7d, 0xce, 0x31, 0xd6, 0x2f, 0xfe, 0xfb, 0x76, 0x64, 0x1f, 0xf0, 0xd2,
+ 0x58, 0xa9, 0x8f, 0xa7, 0xe4, 0x77, 0xb8, 0x2e, 0xd6, 0x2f, 0xf4, 0xd2,
+ 0x7d, 0x4f, 0xf1, 0x2c, 0x5f, 0xff, 0x4e, 0x63, 0xcb, 0x9c, 0xcd, 0x19,
+ 0x1a, 0x35, 0x62, 0xc4, 0xb1, 0x7f, 0x3f, 0xb9, 0x3e, 0x18, 0xb1, 0x7f,
+ 0xff, 0x37, 0x1e, 0x5c, 0x6d, 0xfc, 0x13, 0xb4, 0x9b, 0x7a, 0xc5, 0xc1,
+ 0x86, 0xb1, 0x58, 0x9c, 0x3c, 0xc4, 0x67, 0x1f, 0x73, 0x70, 0x2a, 0x90,
+ 0x8f, 0x8c, 0x03, 0x5e, 0xbf, 0x66, 0x80, 0x08, 0x58, 0xbb, 0x73, 0x67,
+ 0x63, 0x74, 0x59, 0xc1, 0x42, 0x30, 0xa9, 0x2e, 0xc2, 0x1d, 0x0b, 0x21,
+ 0x81, 0x11, 0xc3, 0xce, 0xcb, 0x28, 0x44, 0x0e, 0x33, 0x3c, 0x9d, 0x56,
+ 0x36, 0x18, 0x1d, 0x47, 0x5d, 0xdb, 0xb3, 0x46, 0x1d, 0xba, 0x79, 0x34,
+ 0x3d, 0x75, 0x29, 0xcf, 0xf2, 0xc0, 0x9e, 0x37, 0xf0, 0x42, 0x68, 0xa3,
+ 0xdb, 0xe4, 0xa2, 0x9f, 0x4b, 0x74, 0x13, 0x61, 0x8e, 0x5b, 0x90, 0xe2,
+ 0x0e, 0x51, 0x50, 0x47, 0x1b, 0xfc, 0x29, 0xf6, 0x42, 0x04, 0x63, 0x56,
+ 0x2a, 0x1f, 0xdc, 0x92, 0x78, 0x72, 0xca, 0xdb, 0xef, 0x0e, 0x54, 0x13,
+ 0x52, 0x34, 0x26, 0x8f, 0x30, 0xe5, 0xdf, 0xa4, 0xf7, 0xfa, 0x18, 0x02,
+ 0x8c, 0x54, 0x3b, 0x45, 0xee, 0x12, 0x50, 0xe5, 0x45, 0x60, 0x49, 0x19,
+ 0x3d, 0x22, 0xfe, 0x55, 0x99, 0x88, 0xeb, 0x4b, 0x8c, 0xd4, 0x81, 0x18,
+ 0x6d, 0x60, 0x77, 0xd6, 0x63, 0xc8, 0x9d, 0xde, 0x49, 0xbb, 0x5a, 0x32,
+ 0xcd, 0xd9, 0x53, 0x93, 0x63, 0x30, 0x53, 0x58, 0xda, 0x94, 0x3e, 0xed,
+ 0x1d, 0x8f, 0xed, 0x69, 0x3b, 0xe3, 0x11, 0xd0, 0x16, 0x84, 0xd8, 0x2f,
+ 0x3b, 0x24, 0x57, 0xcf, 0x83, 0xcb, 0xd4, 0xb9, 0xf6, 0x6c, 0x61, 0x82,
+ 0xc5, 0xf6, 0xb6, 0xfa, 0xf3, 0x14, 0xca, 0xdc, 0xfb, 0x72, 0x97, 0xf6,
+ 0x1d, 0x74, 0x46, 0x12, 0xfe, 0x69, 0xa8,
};
-static const unsigned kPreloadedHSTSBits = 957160;
+static const unsigned kPreloadedHSTSBits = 1077941;
-static const unsigned kHSTSRootPosition = 956503;
+static const unsigned kHSTSRootPosition = 1077280;
#endif // NET_HTTP_TRANSPORT_SECURITY_STATE_STATIC_H_
diff --git a/chromium/net/http/transport_security_state_static.json b/chromium/net/http/transport_security_state_static.json
index 03394843fc9..35985af9415 100644
--- a/chromium/net/http/transport_security_state_static.json
+++ b/chromium/net/http/transport_security_state_static.json
@@ -22,22 +22,30 @@
// match up with the file of certificates.
//
// "entries" is a list of objects. Each object has the following members:
-// name: (string) the DNS name of the host in question
-// include_subdomains: (optional bool) For backwards compatibility, this
+// name: (string) the DNS name of the host in question.
+// include_subdomains: (optional boolean) For backwards compatibility, this
// means:
-// - If mode == "force-https", then apply force-https to subdomains
-// - If "pins" is set, then apply the pinset to subdomains
-// include_subdomains_for_pinning: (optional bool) whether subdomains
+// - If mode == "force-https", then apply force-https to subdomains.
+// - If "pins" is set, then apply the pinset to subdomains.
+// include_subdomains_for_pinning: (optional boolean) whether subdomains
// of |name| are also covered for pinning. As noted above,
// |include_subdomains| also has the same effect on pinning.
// mode: (optional string) "force-https" iff covered names should require
-// HTTPS
-// pins: (optional string) the |name| member of an object in |pinsets|
+// HTTPS.
+// pins: (optional string) the |name| member of an object in |pinsets|.
+//
// expect_ct: (optional boolean) true if the site expects Certificate
-// Transparency information to be present on requests to |name|
-// expect_ct_report_uri: (optional string) if expect_ct is true, the
+// Transparency information to be present on requests to |name|.
+// expect_ct_report_uri: (optional string) if |expect_ct| is true, the
// URI to which reports should be sent when valid Certificate
-// Transparency information is not present
+// Transparency information is not present.
+//
+// expect_staple: (optional boolean) true if the site expects responses to
+// contain stapled OCSP repsponses
+// expect_staple_report_uri: (optional string) if expect_staple is true, the
+// URI to which expect_staple reports should be sent.
+// include_subdomains_for_expect_staple: (optional boolean) whether subdomains
+// of |name| are also covered for |expect_staple|.
{
"pinsets": [
@@ -52,7 +60,8 @@
"static_spki_hashes": [
"GoogleBackup2048",
"GoogleG2",
- "GeoTrustGlobal"
+ "GeoTrustGlobal",
+ "GlobalSignRootCA_R2"
],
"report_uri": "http://clients3.google.com/cert_upload_json"
},
@@ -216,6 +225,22 @@
"SwehackBackup",
"COMODORSADomainValidationSecureServerCA"
]
+ },
+ {
+ "name": "nightx",
+ "static_spki_hashes": [
+ "LetsEncryptAuthorityPrimary_X1_X3",
+ "LetsEncryptAuthorityBackup_X2_X4",
+ "VeriSignClass3_G4",
+ "VeriSignClass3_G5",
+ "VeriSignUniversal",
+ "DigiCertGlobalRoot",
+ "DigiCertEVRoot",
+ "DigiCertAssuredIDRoot",
+ "COMODOCertificationAuthority",
+ "AddTrustExternalCARoot"
+ ],
+ "report_uri": "http://l.nightx.uk/report/hpkp"
}
],
@@ -223,7 +248,7 @@
// Dummy entries to test certificate pinning and expect-CT.
{ "name": "pinningtest.appspot.com", "include_subdomains": true, "pins": "test" },
{ "name": "pinning-test.badssl.com", "include_subdomains": true, "pins": "test" },
- { "name": "preloaded-expect-ct.badssl.com", "expect_ct": true, "expect_ct_report_uri": "https://report.badssl.com/expect-ct" },
+ { "name": "preloaded-expect-ct.badssl.com", "expect_ct": true, "expect_ct_report_uri": "https://clients3.google.com/ct_upload" },
{ "name": "preloaded-expect-staple.badssl.com", "expect_staple": true, "expect_staple_report_uri": "https://report.badssl.com/expect-staple" },
{ "name": "preloaded-expect-staple-include-subdomains.badssl.com", "expect_staple": true, "expect_staple_report_uri": "https://report.badssl.com/expect-staple", "include_subdomains_for_expect_staple": true },
@@ -233,6 +258,7 @@
{ "name": "google", "include_subdomains": true, "mode": "force-https", "pins": "google" },
// Google domains using Expect-CT.
+ { "name": "mail.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google", "expect_ct": true, "expect_ct_report_uri": "https://clients3.google.com/ct_upload" },
{ "name": "plus.sandbox.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google", "expect_ct": true, "expect_ct_report_uri": "https://clients3.google.com/ct_upload" },
// Now we force HTTPS for subtrees of google.com.
@@ -254,7 +280,6 @@
{ "name": "hostedtalkgadget.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
{ "name": "inbox.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
{ "name": "login.corp.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
- { "name": "mail.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
{ "name": "mail-settings.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
{ "name": "myaccount.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
{ "name": "passwords.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
@@ -290,6 +315,7 @@
{ "name": "googlecode.com", "include_subdomains": true, "pins": "google" },
{ "name": "googlemail.com", "mode": "force-https", "pins": "google" },
{ "name": "googleplex.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+ { "name": "googlesource.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
{ "name": "groups.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
{ "name": "gvt2.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
{ "name": "gvt3.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
@@ -894,6 +920,7 @@
{ "name": "wildbee.org", "include_subdomains": true, "mode": "force-https" },
{ "name": "portal.tirol.gv.at", "include_subdomains": true, "mode": "force-https" },
{ "name": "dropbox.com", "mode": "force-https", "include_subdomains": true, "pins": "dropbox" },
+ { "name": "www.dropbox.com", "mode": "force-https", "include_subdomains": true, "pins": "dropbox", "expect_staple": true, "expect_staple_report_uri": "https://log.getdropbox.com/log/ocsp_expect_staple", "include_subdomains_for_expect_staple": true },
{ "name": "dropboxstatic.com", "include_subdomains_for_pinning": true, "pins": "dropbox" },
{ "name": "dropboxusercontent.com", "include_subdomains_for_pinning": true, "pins": "dropbox" },
{ "name": "code-poets.co.uk", "include_subdomains": true, "mode": "force-https" },
@@ -2182,7 +2209,6 @@
{ "name": "mehmetince.net", "include_subdomains": true, "mode": "force-https" },
{ "name": "mh-bloemen.co.jp", "include_subdomains": true, "mode": "force-https" },
{ "name": "mimovrste.com", "include_subdomains": true, "mode": "force-https" },
- { "name": "mitell.jp", "include_subdomains": true, "mode": "force-https" },
{ "name": "mittenhacks.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "mnemotiv.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "munuc.org", "include_subdomains": true, "mode": "force-https" },
@@ -4088,7 +4114,6 @@
{ "name": "workwithgo.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "yoloboatrentals.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "yoloseo.com", "include_subdomains": true, "mode": "force-https" },
- { "name": "zen-trader.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "andreas-kluge.eu", "include_subdomains": true, "mode": "force-https" },
{ "name": "andreaskluge.eu", "include_subdomains": true, "mode": "force-https" },
{ "name": "fastaim.de", "include_subdomains": true, "mode": "force-https" },
@@ -4146,7 +4171,6 @@
{ "name": "econsumer.gov", "include_subdomains": true, "mode": "force-https" },
{ "name": "elephpant.cz", "include_subdomains": true, "mode": "force-https" },
{ "name": "elimdengelen.com", "include_subdomains": true, "mode": "force-https" },
- { "name": "elisa.ee", "include_subdomains": true, "mode": "force-https" },
{ "name": "entersynapse.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "epay.bg", "include_subdomains": true, "mode": "force-https" },
{ "name": "escalate.eu", "include_subdomains": true, "mode": "force-https" },
@@ -4155,7 +4179,6 @@
{ "name": "evdenevenakliyatankara.pw", "include_subdomains": true, "mode": "force-https" },
{ "name": "exfiles.cz", "include_subdomains": true, "mode": "force-https" },
{ "name": "expxkcd.com", "include_subdomains": true, "mode": "force-https" },
- { "name": "eyyit.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "fandomservices.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "fasdoutreach.ca", "include_subdomains": true, "mode": "force-https" },
{ "name": "fca-tools.com", "include_subdomains": true, "mode": "force-https" },
@@ -4666,7 +4689,6 @@
{ "name": "meozcraft.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "mfcatalin.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "michalborka.cz", "include_subdomains": true, "mode": "force-https" },
- { "name": "mijailovic.net", "include_subdomains": true, "mode": "force-https" },
{ "name": "mijnkredietpaspoort.nl", "include_subdomains": true, "mode": "force-https" },
{ "name": "monitman.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "monitman.solutions", "include_subdomains": true, "mode": "force-https" },
@@ -5088,7 +5110,6 @@
{ "name": "bougeret.fr", "include_subdomains": true, "mode": "force-https" },
{ "name": "bowling.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "brasalcosmetics.com", "include_subdomains": true, "mode": "force-https" },
- { "name": "bratteng.me", "include_subdomains": true, "mode": "force-https" },
{ "name": "bugcrowd.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "cadoth.net", "include_subdomains": true, "mode": "force-https" },
{ "name": "caffeinatedcode.com", "include_subdomains": true, "mode": "force-https" },
@@ -5876,7 +5897,6 @@
{ "name": "alexismeza.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "alexn.org", "include_subdomains": true, "mode": "force-https" },
{ "name": "allbenjoy.de", "include_subdomains": true, "mode": "force-https" },
- { "name": "almeria.fr", "include_subdomains": true, "mode": "force-https" },
{ "name": "am3.se", "include_subdomains": true, "mode": "force-https" },
{ "name": "amavis.org", "include_subdomains": true, "mode": "force-https" },
{ "name": "ambiente.one", "include_subdomains": true, "mode": "force-https" },
@@ -6801,7 +6821,6 @@
{ "name": "suprlink.net", "include_subdomains": true, "mode": "force-https" },
{ "name": "supweb.ovh", "include_subdomains": true, "mode": "force-https" },
{ "name": "sushifrick.de", "include_subdomains": true, "mode": "force-https" },
- { "name": "svallee.fr", "include_subdomains": true, "mode": "force-https" },
{ "name": "svenluijten.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "swedishhost.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "swedishhost.se", "include_subdomains": true, "mode": "force-https" },
@@ -7064,7 +7083,6 @@
{ "name": "cerebelo.info", "include_subdomains": true, "mode": "force-https" },
{ "name": "chaulootz.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "chazay.net", "include_subdomains": true, "mode": "force-https" },
- { "name": "chrishamper.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "christophheich.me", "include_subdomains": true, "mode": "force-https" },
{ "name": "cigarblogs.net", "include_subdomains": true, "mode": "force-https" },
{ "name": "cimalando.eu", "include_subdomains": true, "mode": "force-https" },
@@ -7868,7 +7886,6 @@
{ "name": "slamdjapan.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "smartairkey.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "snl.no", "include_subdomains": true, "mode": "force-https" },
- { "name": "soleus.nu", "include_subdomains": true, "mode": "force-https" },
{ "name": "sowncloud.de", "include_subdomains": true, "mode": "force-https" },
{ "name": "spielcasinos.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "spiet.nl", "include_subdomains": true, "mode": "force-https" },
@@ -7995,7 +8012,6 @@
{ "name": "tobiasofficial.at", "include_subdomains": true, "mode": "force-https" },
{ "name": "traffixdevices.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "trusteecar.com", "include_subdomains": true, "mode": "force-https" },
- { "name": "vjirovsky.cz", "include_subdomains": true, "mode": "force-https" },
{ "name": "windscribe.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "wlaws.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "xolphin.nl", "include_subdomains": true, "mode": "force-https" },
@@ -8504,7 +8520,6 @@
{ "name": "toysperiod.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "trabbel.org", "include_subdomains": true, "mode": "force-https" },
{ "name": "trackchair.com", "include_subdomains": true, "mode": "force-https" },
- { "name": "tradeacademy.in", "include_subdomains": true, "mode": "force-https" },
{ "name": "tradedesk.co.za", "include_subdomains": true, "mode": "force-https" },
{ "name": "transformify.org", "include_subdomains": true, "mode": "force-https" },
{ "name": "trell.co.in", "include_subdomains": true, "mode": "force-https" },
@@ -8896,7 +8911,6 @@
{ "name": "allmbw.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "allstarswithus.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "allthingssquared.com", "include_subdomains": true, "mode": "force-https" },
- { "name": "almeria-si.fr", "include_subdomains": true, "mode": "force-https" },
{ "name": "alnitech.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "alphabuild.io", "include_subdomains": true, "mode": "force-https" },
{ "name": "alt-three.com", "include_subdomains": true, "mode": "force-https" },
@@ -12724,7 +12738,6 @@
{ "name": "warekon.dk", "include_subdomains": true, "mode": "force-https" },
{ "name": "wbt-solutions.net", "include_subdomains": true, "mode": "force-https" },
{ "name": "wayohoo.net", "include_subdomains": true, "mode": "force-https" },
- { "name": "vozp.cz", "include_subdomains": true, "mode": "force-https" },
{ "name": "wbt-solutions.ch", "include_subdomains": true, "mode": "force-https" },
{ "name": "wefinanceinc.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "web-torrent.com", "include_subdomains": true, "mode": "force-https" },
@@ -13044,7 +13057,6 @@
{ "name": "goalbookapp.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "goldenhost.ca", "include_subdomains": true, "mode": "force-https" },
{ "name": "golfburn.com", "include_subdomains": true, "mode": "force-https" },
- { "name": "googlesource.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "goudenharynck.be", "include_subdomains": true, "mode": "force-https" },
{ "name": "grandpadusercontent.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "grasshoppervape.com", "include_subdomains": true, "mode": "force-https" },
@@ -13409,7 +13421,6 @@
{ "name": "simus.fr", "include_subdomains": true, "mode": "force-https" },
{ "name": "sistersurprise.de", "include_subdomains": true, "mode": "force-https" },
{ "name": "skile.ru", "include_subdomains": true, "mode": "force-https" },
- { "name": "skyo.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "sleep10.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "slimspots.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "slow.zone", "include_subdomains": true, "mode": "force-https" },
@@ -13573,6 +13584,1795 @@
{ "name": "zning.net.cn", "include_subdomains": true, "mode": "force-https" },
{ "name": "zorgclustertool.nl", "include_subdomains": true, "mode": "force-https" },
{ "name": "zyria.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "00f.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "0x17.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "0xdefaced.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "1066.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "112app.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "123.gg", "include_subdomains": true, "mode": "force-https" },
+ { "name": "123comparer.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "1536.cf", "include_subdomains": true, "mode": "force-https" },
+ { "name": "16packets.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "174.net.nz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "188betwarriors.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "1px.tv", "include_subdomains": true, "mode": "force-https" },
+ { "name": "1rs.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "1ststop.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "2-cpu.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "2859cc.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "2cash.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "2hypeenterprises.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "31tv.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "3delivered.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "4th-ave-studio.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "4vf.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "540.co", "include_subdomains": true, "mode": "force-https" },
+ { "name": "54below.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "7thcircledesigns.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "88.to", "include_subdomains": true, "mode": "force-https" },
+ { "name": "8mpay.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "922.be", "include_subdomains": true, "mode": "force-https" },
+ { "name": "9906753.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "99rst.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "9tolife.be", "include_subdomains": true, "mode": "force-https" },
+ { "name": "a-theme.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "abloop.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "abyssproject.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "academialowcost.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "accwing.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "acg.sb", "include_subdomains": true, "mode": "force-https" },
+ { "name": "acgmoon.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "achow101.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "acsports.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "adamdixon.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "adamwk.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "adblockextreme.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "addtoany.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "adfa-1.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "adhoc.is", "include_subdomains": true, "mode": "force-https" },
+ { "name": "adonnante.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "advocatenalkmaar.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "adxperience.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "aerialmediapro.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "aflattr.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "agileui.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "aidanmontare.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "aify.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "aiois.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "airbnbopen.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "airhelp.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "airnow.gov", "include_subdomains": true, "mode": "force-https" },
+ { "name": "akpwebdesign.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "alexberts.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "algolia.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "aljaspod.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "alldaymonitoring.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "alldewall.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "allfreelancers.su", "include_subdomains": true, "mode": "force-https" },
+ { "name": "alliances-faq.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "almstrom.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "alza.at", "include_subdomains": true, "mode": "force-https" },
+ { "name": "alza.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "alza.hu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "amadvice.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "amilum.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "analyticsinmotion.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "andiplusben.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "andrewregan.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "androide.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "annejan.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "anojan.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ansogning-sg.dk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "anthonyavon.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "anystack.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "aojiao.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "apis.world", "include_subdomains": true, "mode": "force-https" },
+ { "name": "aponkral.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "aponkralsunucu.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "appelboomdefilm.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "applelife.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "applian.jp", "include_subdomains": true, "mode": "force-https" },
+ { "name": "appui-de-fenetre.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ar.al", "include_subdomains": true, "mode": "force-https" },
+ { "name": "archimedicx.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ariege-pyrenees.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "aritec-la.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "armored.ninja", "include_subdomains": true, "mode": "force-https" },
+ { "name": "armstrongsengineering.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "arnetdigital.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "arpr.co", "include_subdomains": true, "mode": "force-https" },
+ { "name": "arrow-api.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "arrow-cloud.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "arrowwebprojects.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "arthurlaw.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "artisphere.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "artlogo.biz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "artlogo.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "artlogo.sk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "artweby.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "asadatec.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ashleymedway.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "assemble-together.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "atelier-naruby.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ateliernaruby.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "atitude.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "attogproductions.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "attogtech.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "au2pb.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "auditos.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ausoptic.com.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "avaaz.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "avaq.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "avqueen.cn", "include_subdomains": true, "mode": "force-https" },
+ { "name": "axolsoft.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ayesh.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "aymerick.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "azlk-team.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "b1c1l1.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "babybic.hu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bacon-monitoring.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "balist.es", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ballejaune.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bancacrs.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bankcircle.co.in", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bankinter.pt", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bannisbierblog.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "barbosha.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "barclays.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bardiharborow.tk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "baysse.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bb-shiokaze.jp", "include_subdomains": true, "mode": "force-https" },
+ { "name": "be-real.life", "include_subdomains": true, "mode": "force-https" },
+ { "name": "beatnikbreaks.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "beerians.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "beetman.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "belani.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "belgers.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "belmontgoessolar.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "belmontprom.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "belt.black", "include_subdomains": true, "mode": "force-https" },
+ { "name": "benohead.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "benzou-space.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "berna.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bertrand.bio", "include_subdomains": true, "mode": "force-https" },
+ { "name": "besola.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bestmotherfucking.website", "include_subdomains": true, "mode": "force-https" },
+ { "name": "betterbabyshop.com.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "beyond-edge.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "beyondtrust.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "beyonic.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bezprawnik.pl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bftbradio.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bilgo.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "billigpoker.dk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "billionairemailinglist.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "billkiss.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "binimo.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bioknowme.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "birkhoff.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bitbit.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bitvest.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bitwolk.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "biyou-homme.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bizzartech.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "blakerandall.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "blankersfamily.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "blayne.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "blendr.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "blenheimchalcot.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "blissplan.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "blizz.news", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bloglikepro.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bluefuzz.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bolt.cm", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bombsquad.studio", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bonnyprints.at", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bonnyprints.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bookcelerator.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "boonbox.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bostadsportal.se", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bownty.be", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bownty.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bownty.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bownty.es", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bownty.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bownty.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bownty.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bownty.pt", "include_subdomains": true, "mode": "force-https" },
+ { "name": "brandspray.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "brashear.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "brasilmorar.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bratislava-airport-taxi.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "brava.bg", "include_subdomains": true, "mode": "force-https" },
+ { "name": "brave.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "brettabel.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "brevboxar.se", "include_subdomains": true, "mode": "force-https" },
+ { "name": "brinkhu.is", "include_subdomains": true, "mode": "force-https" },
+ { "name": "brix.ninja", "include_subdomains": true, "mode": "force-https" },
+ { "name": "brockmeyer.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "brokenhands.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "brunoonline.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "btc-e.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "btcarmory.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bucket.tk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "buka.jp", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bulbcompare.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bulkcandystore.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bunkyo-life.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "burrow.ovh", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bustimes.org.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bw.codes", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bwilkinson.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bymike.co", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bypassed.bid", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bypassed.club", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bypassed.date", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bypassed.download", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bypassed.faith", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bypassed.host", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bypassed.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bypassed.online", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bypassed.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bypassed.party", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bypassed.press", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bypassed.pw", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bypassed.site", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bytema.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bytesatwork.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "c-shock.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "c-world.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cadmail.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cainhosting.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "calculator.tf", "include_subdomains": true, "mode": "force-https" },
+ { "name": "caltonnutrition.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "calvin.my", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cambier.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cambridgeanalytica.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "camjackson.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "canadabread.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cancelmyprofile.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "candylion.rocks", "include_subdomains": true, "mode": "force-https" },
+ { "name": "canva.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "capacent.is", "include_subdomains": true, "mode": "force-https" },
+ { "name": "capitalcap.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "capitalonecardservice.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "car.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "carauctionnetwork.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "carauctionsalabama.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "carauctionsgeorgia.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cardranking.jp", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cardse.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "caretta.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "carey.bio", "include_subdomains": true, "mode": "force-https" },
+ { "name": "caroli.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cashplk.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cazes.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cbecrft.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cbtistexcalac.mx", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cdkeyworld.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cellsites.nz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cerize.love", "include_subdomains": true, "mode": "force-https" },
+ { "name": "certspotter.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "certspotter.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cgcookiemarkets.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "charteroak.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cheapticket.in", "include_subdomains": true, "mode": "force-https" },
+ { "name": "chelseafs.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "chennien.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cherryonit.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cherysunzhang.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "chicisimo.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "chiryotaisaku.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "choiralberta.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "chourishi-shigoto.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "chrismcclendon.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "christophertruncer.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "chunche.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cianmawhinney.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cigi.site", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cigoteket.se", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cim2b.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cinartelorgu.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cinemaclub.co", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cinsects.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ciplanutrition.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "circara.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "classicalpilates.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "clemovementlaw.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cleververmarkten.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cleververmarkten.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "clientboss.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cliniko.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "clint.id.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "clip.mx", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cloudspotterapp.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "club-is.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "clubon.space", "include_subdomains": true, "mode": "force-https" },
+ { "name": "clvs7.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "codiva.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "coin.dance", "include_subdomains": true, "mode": "force-https" },
+ { "name": "coldwatericecream.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "colinstark.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "collabra.email", "include_subdomains": true, "mode": "force-https" },
+ { "name": "colmexpro.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "colo-tech.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "colorcodedlyrics.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "comalia.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cometcache.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "comico.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "comparexcloudcenter.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "completeid.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "computerhilfe-feucht.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "conclave.global", "include_subdomains": true, "mode": "force-https" },
+ { "name": "connectum.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "constant-rough.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cookiecrook.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "coolviewthermostat.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "coralrosado.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "core-networks.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cornodo.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "counterglobal.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "couragefound.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "courses.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cousincouples.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cprnearme.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "craigrouse.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "crazy-crawler.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "crazypaul.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "critcola.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "criticalsurveys.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "crownruler.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cs-ubladego.pl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "csgoelemental.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "csgohandouts.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ctrld.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cubecraftstore.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cubecraftstore.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cubos.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cubostecnologia.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cubostecnologia.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cucc.date", "include_subdomains": true, "mode": "force-https" },
+ { "name": "culturedcode.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cuongquach.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cupi.co", "include_subdomains": true, "mode": "force-https" },
+ { "name": "current.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cybozulive-dev.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "czechvirus.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "czerno.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "d66.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "daemen.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dalfsennet.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "danielmarquard.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "darktime.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dashburst.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "datadit.hu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dataswamp.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "davescomputertips.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "davidlillo.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dayman.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "daytonaseaside.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "db.gy", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dbcom.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ddns-anbieter.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "debian-vhost.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "decosoftware.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "deeprecce.link", "include_subdomains": true, "mode": "force-https" },
+ { "name": "demilitarized.ninja", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dengchangdong.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "deroo.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "designsbyjanith.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "desterman.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "destom.be", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dev-tek.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "devdom.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "developmentsites.melbourne", "include_subdomains": true, "mode": "force-https" },
+ { "name": "devistravaux.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "devlogr.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "devonsawatzky.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dezeregio.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dezmembrariromania.ro", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dhedegaard.dk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "diagnostix.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dianlujitao.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dicionariodenomesproprios.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dietbrand.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "diezel.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "diff2html.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "diffnow.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "digimagical.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "digwp.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dir2epub.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dir2epub.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "discordapp.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "disowned.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "distinguishedprisoner.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "distractionco.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "djangosnippets.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dlaspania.pl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dmarc.dk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dn3s.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dns-control.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "docupet.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dokan.online", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dokuraum.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "doleta.gov", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dolevik.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dollywiki.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dominationgame.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "donotlink.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dooleytackaberry.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "doomleika.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "doomsworld.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "doooonoooob.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "doorflow.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dot42.no", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dotkod.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dotkod.pl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "doujinshi.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "downloadaja.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "downloadgram.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dragonteam.ninja", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dragontrainingmobilezoo.com.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "drakenprospero.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "draugr.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "drewgle.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "drivercopilot.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "driverscollection.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "drivya.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dronografia.es", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dubaieveningsafari.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "duch.cloud", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dwnld.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "e5tv.hu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "earthrise16.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "easychiller.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "eaton-works.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ebankingabersicher.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ebankingbutsecure.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ebankingentoutesecurite.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ebankingmasicuro.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ebas.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ebataw.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ebonyriddle.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ecole-maternelle-saint-joseph.be", "include_subdomains": true, "mode": "force-https" },
+ { "name": "edenaya.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "edusantorini.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "edwardsnowden.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "edzilla.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "eewna.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "egge.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "eiyoushi-shigoto.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ekodevices.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "eksik.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "elaxy-online.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "elblein.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "eldinhadzic.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "elgacien.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "eliott.be", "include_subdomains": true, "mode": "force-https" },
+ { "name": "elizabethgreenfield.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "emkei.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "emmable.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "empathy.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "enargia.jp", "include_subdomains": true, "mode": "force-https" },
+ { "name": "encode.space", "include_subdomains": true, "mode": "force-https" },
+ { "name": "enigmacpt.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "enlightened.si", "include_subdomains": true, "mode": "force-https" },
+ { "name": "enterprise-threat-monitor.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "entrainr.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "epoch.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "equalparts.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "equidam.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ericbond.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "erichalv.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ericleuthardt.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "erikhubers.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "eriner.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "esoko.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "esoterikerforum.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "espace-gestion.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "etmirror.top", "include_subdomains": true, "mode": "force-https" },
+ { "name": "etmirror.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "etproxy.tech", "include_subdomains": true, "mode": "force-https" },
+ { "name": "etv.cx", "include_subdomains": true, "mode": "force-https" },
+ { "name": "eureka.archi", "include_subdomains": true, "mode": "force-https" },
+ { "name": "eurekaarchi.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "eurekaarchitecture.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "euren.se", "include_subdomains": true, "mode": "force-https" },
+ { "name": "european-agency.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "eurotravelstar.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "evanhandgraaf.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "evelyndayman.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "evlear.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ewex.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ewycena.pl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "excelgum.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "exitus.jp", "include_subdomains": true, "mode": "force-https" },
+ { "name": "experteasy.com.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "exploit.party", "include_subdomains": true, "mode": "force-https" },
+ { "name": "extratorrentlive.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "extratorrents.tech", "include_subdomains": true, "mode": "force-https" },
+ { "name": "extreme-gaming.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "extreme-gaming.us", "include_subdomains": true, "mode": "force-https" },
+ { "name": "eye-carat.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ezequiel-garzon.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fabriziorocca.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "facilitrak.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "failforward.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "falconfrag.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "familie-sprink.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fanboi.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "farhadexchange.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fashionholic.my", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fashionunited.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fedoramagazine.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fehnladen.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "feistyduck.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "felixklein.at", "include_subdomains": true, "mode": "force-https" },
+ { "name": "felixsanz.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "feriahuamantla.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "festivalxdentro.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fics-twosigma.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fifieldtech.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "figurasdelinguagem.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "filmipop.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "findigo.fish", "include_subdomains": true, "mode": "force-https" },
+ { "name": "findyourvoice.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "flam.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "flashback.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fleep.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "flightschoolcandidates.gov", "include_subdomains": true, "mode": "force-https" },
+ { "name": "florisvdk.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fluxforge.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "flyss.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "focalforest.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fondy.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fontlibrary.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "foodies.my", "include_subdomains": true, "mode": "force-https" },
+ { "name": "foorack.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "forex.ee", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fossilfreeyale.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "foto-janvanaefst.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fotografiadellalucerossa.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fran.cr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "francoz.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "frankl.in", "include_subdomains": true, "mode": "force-https" },
+ { "name": "frankwei.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "frappant.cc", "include_subdomains": true, "mode": "force-https" },
+ { "name": "frbracch.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fredloya.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "free-your-pc.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "freeflow.tv", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fretworksec.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "friends24.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "frost-ci.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fsinf.at", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ftctele.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ftrsecure.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fuckgfw233.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fumblers.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "funktionel.co", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fuseos.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fuyu.moe", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fveevaete.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fxopen.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fxopen.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fxopen.com.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fxopen.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fxopen.com.mx", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fxopen.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gaestehaus-monika.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gamberorosso.menu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gambetti.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gambitcloud.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "game-gentle.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "game.yt", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gamechasm.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gameguardian.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gameofbay.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gamepiece.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gapdirect.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gartenplanung-brendes.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gazee.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gdegem.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gecem.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "geek.tw", "include_subdomains": true, "mode": "force-https" },
+ { "name": "geeknik.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "geluidsstudio.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "genesiseureka.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "genie-seiner-generation.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gerwinvanderkamp.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ges-bo.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "get4x.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "getbooks.co.il", "include_subdomains": true, "mode": "force-https" },
+ { "name": "getgeek.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "getmondo.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ggmmontascale.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ggss.cf", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ggss.ml", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ghostwritershigh.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "giakki.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gianproperties.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ginkel.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gis3m.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "globalonetechnology.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "glopoi.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gmbh-kiekin.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gnetion.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gnunet.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "goarmy.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gong8.win", "include_subdomains": true, "mode": "force-https" },
+ { "name": "goolok.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "goozz.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gopokego.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gorod74.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gospelofmark.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "goto.world", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gottcode.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gracethrufaith.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "grademymac.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "grandwailea.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "greenaddress.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "greg.red", "include_subdomains": true, "mode": "force-https" },
+ { "name": "groenaquasolutions.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "grunwasser.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "guillaume-leduc.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "guscaplan.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gw2reload.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gxlrx.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gymnasium-farmsen.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "h-og.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "h11.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "h11.moe", "include_subdomains": true, "mode": "force-https" },
+ { "name": "haavard.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "habbotalk.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hackerchai.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hackerone-ext-adroll.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hacksnack.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hail2u.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hantse.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hao-zhang.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hardenize.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "harrisonswebsites.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hartmancpa.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hasdf.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hatethe.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "haxoff.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hcs-company.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hdrtranscon.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "healthjoy.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "healtious.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hearty.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hearty.space", "include_subdomains": true, "mode": "force-https" },
+ { "name": "heartyme.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "heavensattic.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hebaus.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hegen.sk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hegenshop.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "heidilein.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hellomouse.cf", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hesaplama.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hexacon.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "highsurf-miyazaki.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hilaolu.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hintergedanken.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hlyue.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hmhotelec.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hoe.re", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hollyforrest.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hollyforrestphotography.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "homehuntertoronto.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hongzhaxiaofendui.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hoodtrader.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hoovism.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hord.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hotelvue.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hotornot.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "houkago-step.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "howbigismybuilding.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "howlongtobeatsteam.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hsivonen.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hsivonen.fi", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hsivonen.iki.fi", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hszhyy120.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "html-lab.tk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "httpstatuscode418.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hugofs.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "huihui.moe", "include_subdomains": true, "mode": "force-https" },
+ { "name": "huutonauru.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hyper-matrix.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "hypotecnicentrum.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "i1314.gdn", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ic3.gov", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ice.yt", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ich-tanke.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ichnichtskaufmann.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "icij.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "icloud.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "icntorrent.download", "include_subdomains": true, "mode": "force-https" },
+ { "name": "icymint.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "idconsult.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "idmobile.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "idsafe.co.za", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ifad.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "iformbuilder.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ifsac.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "igule.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ikachalife.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ikujii.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ikwilthepiratebay.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ilamparas.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ilprof.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "imakepoems.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "imed.pt", "include_subdomains": true, "mode": "force-https" },
+ { "name": "imgaa.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "immunicity.host", "include_subdomains": true, "mode": "force-https" },
+ { "name": "immunicity.top", "include_subdomains": true, "mode": "force-https" },
+ { "name": "immunicity.win", "include_subdomains": true, "mode": "force-https" },
+ { "name": "impact.health.nz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "imppac.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "in10tion.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "incubos.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ineed.coffee", "include_subdomains": true, "mode": "force-https" },
+ { "name": "info-beamer.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ingalls.run", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ins1gn1a.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "insertcoins.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "instinctiveads.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "insurance321.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "intafe.co.jp", "include_subdomains": true, "mode": "force-https" },
+ { "name": "integraxor.com.tw", "include_subdomains": true, "mode": "force-https" },
+ { "name": "intencje.pl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "interleucina.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "internet-pornografie.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "inthepicture.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "inthouse.cloud", "include_subdomains": true, "mode": "force-https" },
+ { "name": "intranetsec-regionra.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "investpay.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "invitescene.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ioiart.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ipawind.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ipcareers.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "iron-guard.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ironcarnival.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "isbc-telecom.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "isdf.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "isgp-studies.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "istgame.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "istherrienstillcoach.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "it-rotter.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "itactiq.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "itskayla.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "itsok.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "itspersonaltraining.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "itsryan.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "itu2015.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ivi-fertilite.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ivi-fruchtbarkeit.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ivi.com.ar", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ivi.com.pa", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ivi.mx", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ivi.net.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ivi.pt", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ivinet.cl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ivitalia.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ixio.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jacobian.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jadopado.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jakereynolds.co", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jamesf.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jamesgreenfield.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jamourtney.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "janverlaan.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jaredbates.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jasperespejo.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jasperhuttenmedia.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jayxu.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jbfp.dk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jccrew.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jedwarddurrett.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jeffanderson.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jeffersonregan.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jeffersonregan.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jeffersonregan.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jeffersonregan.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jellow.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jennifercherniack.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jessevictors.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jetlagphotography.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jfx.space", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jhermsmeier.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jing.su", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jlhmedia.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jncde.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jncie.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jncip.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "joehenry.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "johannes-sprink.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "johnmh.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "johnnybet.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "johnroach.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jonferwerda.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jonnystoten.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jonoalderson.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jonsno.ws", "include_subdomains": true, "mode": "force-https" },
+ { "name": "joran.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jornane.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jornane.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jornane.no", "include_subdomains": true, "mode": "force-https" },
+ { "name": "joyceclerkx.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jproxx.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jslay.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jubileum.online", "include_subdomains": true, "mode": "force-https" },
+ { "name": "juchit.at", "include_subdomains": true, "mode": "force-https" },
+ { "name": "judoprodeti.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "juliangonggrijp.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "juliekoubova.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "junaos.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "justice4assange.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "justpaste.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jysperm.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "k2mts.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kabeuchi.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kadmec.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kaiusaltd.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kanar.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kartec.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kasadara.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kashmirobserver.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kasilag.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kat.al", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kateduggan.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kati-raumplaner.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "katproxy.al", "include_subdomains": true, "mode": "force-https" },
+ { "name": "katproxy.online", "include_subdomains": true, "mode": "force-https" },
+ { "name": "katproxy.tech", "include_subdomains": true, "mode": "force-https" },
+ { "name": "katproxy.top", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kellyandantony.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kenguntokku.jp", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kennedy.ie", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kenoschwalb.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kentec.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kerforhome.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kfbrussels.be", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kiadoapartman.hu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kickass-proxies.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kickstart.com.pk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kiedys.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kiekin.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kilogram.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kimpost.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kingbird.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kini24.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kintawifi.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kionetworks.es", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kirstenbos.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kisskiss.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kjaer.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kkyy.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "klamathrestoration.gov", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kncg.pw", "include_subdomains": true, "mode": "force-https" },
+ { "name": "knthost.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "koethen-markt.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "koldanews.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "komidoc.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kommune42.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "konkurs.ba", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kralik.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "krang.org.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "krayx.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kreditkacs.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kshlm.in", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kuemmerlin.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kundenerreichen.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kundenerreichen.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kusaka-abacus.jp", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kuschku.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kutukupret.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kwok.tv", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kyliehunt.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kyy.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "kzjnet.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "l2guru.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "la-cave-a-nodo.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "labourreedevergheas.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lacaverne.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lacyc3.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "laextra.mx", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lamapoll.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lancehoteis.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lancehoteis.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "landofelves.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "langly.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "langworth.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lastchancetraveler.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "latinred.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lattyware.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lattyware.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lauftrainer-ausbildung.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lavita.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lavoieducoeur.be", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lawrencemurgatroyd.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lazerus.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lebanesearmy.gov.lb", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lebarmy.gov.lb", "include_subdomains": true, "mode": "force-https" },
+ { "name": "leen.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "leertipp.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "legaltip.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "leighneithardt.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "leisure-blog.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lerasenglish.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lesscloud.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "leu.to", "include_subdomains": true, "mode": "force-https" },
+ { "name": "leuthardtfamily.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lew.im", "include_subdomains": true, "mode": "force-https" },
+ { "name": "liangji.com.tw", "include_subdomains": true, "mode": "force-https" },
+ { "name": "liaoshuma.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lichess.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "liduan.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "liduan.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lightarmory.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lightcloud.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "likeablehub.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "likeabox.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "linost.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lintmx.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "listminut.be", "include_subdomains": true, "mode": "force-https" },
+ { "name": "liveregistratie.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "loadlow.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lofttravel.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "loganmarchione.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lolicon.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lolkot.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "loopower.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "loveismore.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "loveismore.es", "include_subdomains": true, "mode": "force-https" },
+ { "name": "loveismore.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "loveismore.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "loveismore.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "loveismore.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "loveismore.pl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "loveismore.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "loveismore.sk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lovelivewiki.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lowhangingfruitgrabber.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "loxis.be", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lrhsclubs.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ltba.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ltbytes.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lunchbunch.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "luongvu.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "luuppi.fi", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lynx.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lynxbroker.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "lyonl.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "m-ali.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "m2epro.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "m2tc.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "maartenterpstra.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mac1.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "macchedil.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "macdj.tk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "madeglobal.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "madokami.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "maisgasolina.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "majaweb.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "makeuplove.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "malinheadview.ie", "include_subdomains": true, "mode": "force-https" },
+ { "name": "malkaso.com.ua", "include_subdomains": true, "mode": "force-https" },
+ { "name": "manage4all.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "manageall.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "manageforall.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "manageforall.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "manesht.ir", "include_subdomains": true, "mode": "force-https" },
+ { "name": "maniadeprazer.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mansion-note.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "marble.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "marinazarza.es", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mariviolin.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "markepps.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "markorszulak.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "martinmuc.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "martinreed.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "masiniunelte.store.ro", "include_subdomains": true, "mode": "force-https" },
+ { "name": "master-net.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "masterdigitale.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "matthewgrill.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "maupiknik.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "maur.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mcb-bank.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mcdonalds.design", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mchopkins.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mckinley.school", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mckinley1.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mdmed.clinic", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mediamag.am", "include_subdomains": true, "mode": "force-https" },
+ { "name": "medicinia.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "megaflowers.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mehostdd.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "meikan.moe", "include_subdomains": true, "mode": "force-https" },
+ { "name": "melted.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "memeblast.ninja", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mencap.org.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mensmaximus.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "meshok.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "metagrader.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "metronaut.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "meusigno.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mexbt.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mhealthdemocamp.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "micbase.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "michaelscrivo.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "michalwiglasz.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mikii.club", "include_subdomains": true, "mode": "force-https" },
+ { "name": "miknight.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mikonmaa.fi", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mikroskeem.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "milang.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "milcoresonline.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mind.sh", "include_subdomains": true, "mode": "force-https" },
+ { "name": "minux.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mipla.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "miragrow.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "missoy.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mivcon.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mixtape.moe", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mkuznets.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mnt-tech.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mobilcom-debitel.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "modecaso.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "model9.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "moe.pe", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mon-agenda.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "monarca.systems", "include_subdomains": true, "mode": "force-https" },
+ { "name": "moneycrownmedia.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "monika-sokol.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "monolithapps.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "monolithinteractive.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "moonless.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mor.gl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "morfitronik.pl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "morninglory.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mountainactivitysection.org.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "movabletype.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "movepin.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "movie4kto.site", "include_subdomains": true, "mode": "force-https" },
+ { "name": "moy.cat", "include_subdomains": true, "mode": "force-https" },
+ { "name": "moylen.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mrdani.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mrdayman.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mrizzio.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "multiworldsoftware.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "museminder2.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mustard.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mutuals.cool", "include_subdomains": true, "mode": "force-https" },
+ { "name": "muusikoiden.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mwba.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "my-hps.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "myadself.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "myfedloan.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "myfrenchtattoo.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mygdut.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mygpsite.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "myimmitracker.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mymotor.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mypaperwriter.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "myptsite.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "myrepublic.co.id", "include_subdomains": true, "mode": "force-https" },
+ { "name": "myschoolphoto.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mythengay.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nacktetatsachen.at", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nakedfacts.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nakliyatsirketi.biz.tr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "namaho.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nametaken-cloud.duckdns.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "namu.moe", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nanokamo.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "naralogics.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "natalia-fadeeva.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "naudles.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "navdeep.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "near.st", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nefertitis.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "neillans.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "neillans.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "neons.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "neoxcrf.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nercp.org.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nerds.company", "include_subdomains": true, "mode": "force-https" },
+ { "name": "netraising.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "netzfrauen.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "neuflizeobc.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "neurogroove.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "newtonwarp.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nframe.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nfsec.pl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nglr.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "niagarafalls.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nicolas-simond.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nidro.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nien.chat", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nien.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nien.com.tw", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nien.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nien.taipei", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nigelwakefield.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nightsnack.cf", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nimeshjm.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ninchisho-online.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ninjan.co", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ninux.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nitrix.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nkadvertising.online", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nootropicsource.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "noreply.mx", "include_subdomains": true, "mode": "force-https" },
+ { "name": "notjustvacs.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "notnl.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "novabench.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "novaco.in", "include_subdomains": true, "mode": "force-https" },
+ { "name": "novoresume.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nozoe.jp", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nrechn.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ntotten.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nubu.at", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nuvechtdal.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nwerc.party", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nwk1.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "nyxi.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "o2careers.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ocg-card.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "octod.tk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "oe8.bet", "include_subdomains": true, "mode": "force-https" },
+ { "name": "office-de-tourisme.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "olegon.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ominto.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "omniverse.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "omquote.gq", "include_subdomains": true, "mode": "force-https" },
+ { "name": "oneazcu.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "onlinebiller.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "onmuvo.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "onpatient.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "oogartsennet.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "oparl.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "openquery.com.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "openssl.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "orangefinanse.com.pl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ordr.mobi", "include_subdomains": true, "mode": "force-https" },
+ { "name": "origami.to", "include_subdomains": true, "mode": "force-https" },
+ { "name": "originalmockups.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ostan-collections.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "osusume-houhou.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "otvaracie-hodiny.sk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ourcodinglives.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "outgress.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "outlookonthedesktop.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "outurnate.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "paintingat.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "papermasters.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "paraborsa.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "parser.nu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "partnersfcu.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pasadenapooch.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "passionatefoodie.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "passumpsicbank.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "paulov.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "paultibbetts.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "paulwatabe.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "payme.uz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "paystack.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pbraunschdash.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pciconcursos.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pedrosluiter.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "peliculasaudiolatinoonline.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "periscope.tv", "include_subdomains": true, "mode": "force-https" },
+ { "name": "periscopeliveweb.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "personalinjurylist.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "petersontoscano.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "petitsfrenchies.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "petrasestakova.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pexieapp.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pgnetwork.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "phcnetworks.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "phenomeno-porto.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "phenomeno.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "phenomenoporto.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "phenomenoporto.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "philpropertygroup.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "philsturgeon.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "phonenumberinfo.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "phosagro.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "photographyforchange.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "phpbbchinese.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "phpmyadmin.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "phpprime.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "physicaltherapist.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "picotronic.biz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "picotronic.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pillowandpepper.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pimhaarsma.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pimhaarsmamedia.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pimspage.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pin.net.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pinkinked.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pirate.trade", "include_subdomains": true, "mode": "force-https" },
+ { "name": "piratebayproxy.tf", "include_subdomains": true, "mode": "force-https" },
+ { "name": "piratebit.tech", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pirateproxy.red", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pirateproxy.tf", "include_subdomains": true, "mode": "force-https" },
+ { "name": "placker.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "plattner.club", "include_subdomains": true, "mode": "force-https" },
+ { "name": "playmyplay.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "playsharp.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "plur.com.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pmp-art.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "podemos.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "points4unitedway.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pole.net.nz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "polycrypt.us", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pomar.club", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ponteencima.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pontokay.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pornbay.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "portofrotterdam.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "porybox.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "potsky.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "poupatempo.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ppuu.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "praguepsychology.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "praguepsychology.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "praxis-research.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "preezzie.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "prespanok.sk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "prinice.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "printerest.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "prnav.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "prodct.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "productdesignsoftware.com.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "producto8.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "proefteksten.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "profusion.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "prok.pw", "include_subdomains": true, "mode": "force-https" },
+ { "name": "propertygroup.pl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "prospanek.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "prosperident.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "prot.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "protecciondelconsumidor.gov", "include_subdomains": true, "mode": "force-https" },
+ { "name": "proxybay.one", "include_subdomains": true, "mode": "force-https" },
+ { "name": "prt.in.th", "include_subdomains": true, "mode": "force-https" },
+ { "name": "prxio.site", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pstrozniak.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ptonet.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "publiccarauctionscalifornia.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "publicintegrity.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pucchi.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "puhe.se", "include_subdomains": true, "mode": "force-https" },
+ { "name": "push.world", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pwdgen.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pwolk.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "pypi.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "qccqld.org.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "qldconservation.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "qldconservation.org.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "qm-marzahnnordwest.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "qqq.gg", "include_subdomains": true, "mode": "force-https" },
+ { "name": "qr-city.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "qtpass.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "qtpower.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "qtpower.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "quanglepro.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "queminventou.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "quemmeliga.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "quikchange.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "qwaser.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "qwikdash.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ra-schaal.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ra4wvpn.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "radioilusion.es", "include_subdomains": true, "mode": "force-https" },
+ { "name": "railgun.com.cn", "include_subdomains": true, "mode": "force-https" },
+ { "name": "raissarobles.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ralfs-zusizone.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ranzbak.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "raspberry.us", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rationalops.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rbqcloud.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "react-db.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "readouble.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "realloc.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "reapdrive.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "redable.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "redirectman.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rediske.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "redstoner.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "redy.host", "include_subdomains": true, "mode": "force-https" },
+ { "name": "reganclassics.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "reganclassics.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "reganparty.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "regio-salland.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "regiobeveland.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "regiosalland.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rehabili-shigoto.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "reikiqueen.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "reinencaressa.be", "include_subdomains": true, "mode": "force-https" },
+ { "name": "reliancebank.bank", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rema.site", "include_subdomains": true, "mode": "force-https" },
+ { "name": "renewablefreedom.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "renrenss.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rentasweb.gob.ar", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rentbrowsertrain.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "replacemychina.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "responer.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "respostas.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "revealdata.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rewardingexcellence.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rezexpert.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "riceglue.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "richardlangworth.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "richmtdriver.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rideaudiscount.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rideforwade.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rideforwade.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rideforwade.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rileyevans.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rmf.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "roadfeast.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "robin.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "robinhoodbingo.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rockeyscrivo.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rondommen.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "roslynpad.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rosslug.org.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "roughgrain.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rpgmaker.es", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rsblake.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rtfpessoa.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rudd-o.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "runvs.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rustfanatic.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rva-asbestgroep.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "rynekpierwotny.pl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "s-mainte.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "s16e.no", "include_subdomains": true, "mode": "force-https" },
+ { "name": "safegroup.pl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "saferchildren.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "safersurfing.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "safing.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "safire.ac.za", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sail-nyc.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "saiputra.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sakurabuff.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "samel.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sapporobeer.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sarahvictor.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sarindia.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sas-snowboarding.sk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "saturn.pl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sauvagebridge.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "savannahtasteexperience.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "savvysuit.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sb.im", "include_subdomains": true, "mode": "force-https" },
+ { "name": "schawe.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "schd.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "schizoids.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "schlechtewitze.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "schnellsuche.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "schopenhauer-institut.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "schrauger.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "schrauger.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "schrauger.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "schrauger.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "schrauger.run", "include_subdomains": true, "mode": "force-https" },
+ { "name": "schreibers.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "schrikdraad.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sclgroup.cc", "include_subdomains": true, "mode": "force-https" },
+ { "name": "screensaversplanet.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "scrumstack.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sealbaker.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sebastian-bair.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sebastianblade.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "secnews.gr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "secure.link", "include_subdomains": true, "mode": "force-https" },
+ { "name": "securitybsides.pl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "seedalpha.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "seedboxers.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "segurosbalboa.com.ec", "include_subdomains": true, "mode": "force-https" },
+ { "name": "senorcontento.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "senshudo.tv", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sensiblemn.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "seo-linz.at", "include_subdomains": true, "mode": "force-https" },
+ { "name": "seokay.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "seoquake.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "seppelec.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "septs.pw", "include_subdomains": true, "mode": "force-https" },
+ { "name": "serathius.ovh", "include_subdomains": true, "mode": "force-https" },
+ { "name": "serf.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "servdiscount.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "servecrypt.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "servecrypt.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "servecrypt.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "servepublic.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "servepublic.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "serverfrog.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sethcaplan.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "settberg.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "seyr.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sfsltd.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "shadowplus.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "shadowrocket.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "shadowsocks.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "shanetully.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "shansing.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "shansing.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "shansing.space", "include_subdomains": true, "mode": "force-https" },
+ { "name": "shellj.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "shemissed.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "shg-pornographieabhaengigkeit.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "shirtsofholland.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "shotbow.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "shrinkhub.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "shrub.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "shwongacc.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "siamojo.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "signaltransmitter.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "signix.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "signosquecombinam.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "siliconchip.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "silvergoldbull.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "silvergoldbull.kr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "simonwoodside.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "simplecontacts.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "simplerses.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "simpte.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sinful.pw", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sistem-maklumat.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "skepticalsports.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "skillproxy.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "skillproxy.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "skillproxy.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "skontakt.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "skontorp-enterprise.no", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sktsolution.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sky-aroma.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "slimmerbouwen.be", "include_subdomains": true, "mode": "force-https" },
+ { "name": "smartest-trading.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "smartrade.tech", "include_subdomains": true, "mode": "force-https" },
+ { "name": "smpetrey.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "snapfinance.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "snow.dog", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sokolkarvina.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sol-computers.es", "include_subdomains": true, "mode": "force-https" },
+ { "name": "soledadpenades.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "solus-project.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "solvops.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "somanao.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sonarqube.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sonerezh.bzh", "include_subdomains": true, "mode": "force-https" },
+ { "name": "songzhuolun.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sophiakligys.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sor.so", "include_subdomains": true, "mode": "force-https" },
+ { "name": "soucorneteiro.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "soulboy.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "soundtalks.be", "include_subdomains": true, "mode": "force-https" },
+ { "name": "southmeriden-vfd.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "space-it.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "spacehost.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "spenglerei-shop.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sperohub.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sperohub.lt", "include_subdomains": true, "mode": "force-https" },
+ { "name": "spilsbury.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "spinalien.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "splitreflection.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sponc.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "spookbook.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sporthit.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sportstraineradvisor.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "spotlightsrule.ddns.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "spr.id.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "spricknet.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sproutconnections.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sptk.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "stalschermer.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "standoutbooks.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "starfm.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "starina.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "starkbim.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "starttraffic.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "starttraffic.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "startupum.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "stcu.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "steemit.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "steenackers.be", "include_subdomains": true, "mode": "force-https" },
+ { "name": "stephanieschreiber.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "stephenhaunts.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "stephenschrauger.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "stephenschrauger.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "stephenschrauger.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "stephenschrauger.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "stitchfiddle.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "stopfraud.gov", "include_subdomains": true, "mode": "force-https" },
+ { "name": "storiesofhealth.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "stp-ip.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "stp-ip.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "stpip.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "stpip.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "strangemusicinc.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "streetspotr.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "studiomarcella.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "subohm.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "suborbital.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "subsys.no", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sudoschool.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "suitocracy.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "superpase.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "superuser.fi", "include_subdomains": true, "mode": "force-https" },
+ { "name": "suwalls.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "svendubbeld.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "swat4stats.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "swiggy.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sykl.us", "include_subdomains": true, "mode": "force-https" },
+ { "name": "syndic-discount.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sys.tf", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sysert.tv", "include_subdomains": true, "mode": "force-https" },
+ { "name": "t-complex.space", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tailify.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "taiwantour.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "talentos.pt", "include_subdomains": true, "mode": "force-https" },
+ { "name": "taler.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tatt.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tcp.expert", "include_subdomains": true, "mode": "force-https" },
+ { "name": "teachpeople.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tealdrones.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "teamhood.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "teamnetsol.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "techademy.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "techcultivation.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "techcultivation.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "techcultivation.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "techmasters.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "technogroup.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "techwords.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "telefonnummer.online", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tendermaster.com.ua", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tenkofx.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tenpolab.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tensei-slime.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "testosterone-complex.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tffans.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tflite.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tgbyte.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tgbyte.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thatgudstuff.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thatpodcast.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thechunk.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thediaryofadam.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thegreenfields.se", "include_subdomains": true, "mode": "force-https" },
+ { "name": "theidiotboard.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thelanscape.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "themusthaves.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thenanfang.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thenexwork.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thenib.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thepiratebay.tech", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thermity.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "theseosystem.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thesplit.is", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thestack.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thewhiterabbit.space", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thewoodkid.com.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thinkcash.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thomaswoo.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thompsonfamily.cloud", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tiernanx.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tilkah.com.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tillcraft.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "time2060.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "time22.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "timetotrade.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "timstoffel.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tintencenter.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tipbox.is", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tipoftheday.tips", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tism.in", "include_subdomains": true, "mode": "force-https" },
+ { "name": "titanleaf.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "titiansgirlphotography.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "todamateria.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tokenloan.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tokotamz.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tokyopopline.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "toleressea.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "toles-sur-mesure.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tomlankhorst.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tomssl.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "torrentdownloads.bid", "include_subdomains": true, "mode": "force-https" },
+ { "name": "torrentz.website", "include_subdomains": true, "mode": "force-https" },
+ { "name": "torservers.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "touchpointidg.us", "include_subdomains": true, "mode": "force-https" },
+ { "name": "toutmonexam.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tpblist.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tpbunblocked.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "trade.gov.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "traindb.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "transfile.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "transparentcorp.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "travality.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "travisforte.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "travisfranck.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "travler.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "treinaweb.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tributh.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tripcombi.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "trotec.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "trueinstincts.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "trustcase.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tsuyuzakihiroyuki.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ttbonline.gov", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tts.co.nz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ttt.tt", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tucker.wales", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tumedico.es", "include_subdomains": true, "mode": "force-https" },
+ { "name": "turnoffthelights.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tv2vie.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "twun.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "twuni.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tyler.rs", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tyleromeara.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "udruga-point.hr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "uhrenlux.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "uicchy.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ukpirate.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unblockall.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unblockat.tk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unblocked.faith", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unblocked.host", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unblocked.live", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unblockedall.site", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unblockedbay.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unblockerproxy.site", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unblockerproxy.top", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unblockmyproxy.site", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unblockweb.co", "include_subdomains": true, "mode": "force-https" },
+ { "name": "underskatten.tk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "uniprimebr.com.br", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unitlabs.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unlocken.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unmanaged.space", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unseen.is", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unser-gartenforum.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "unsupervised.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "upaknship.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "upplevelse.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "url.rw", "include_subdomains": true, "mode": "force-https" },
+ { "name": "used-in.jp", "include_subdomains": true, "mode": "force-https" },
+ { "name": "usedesk.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "utvbloggen.se", "include_subdomains": true, "mode": "force-https" },
+ { "name": "uzmandroid.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "uzmandroid.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "uzmandroid.top", "include_subdomains": true, "mode": "force-https" },
+ { "name": "v2ex.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "va-reitartikel.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "validator.nu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vanwunnik.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vcelin-na-doliku.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "veblr.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vecozo.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "veii.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "verdeandco.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "verdict.gg", "include_subdomains": true, "mode": "force-https" },
+ { "name": "verein-kiekin.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "verfassungsklage.at", "include_subdomains": true, "mode": "force-https" },
+ { "name": "verifyos.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vertner.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "veterinaire-cazeres-foucault.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "veto.fish", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vetofish.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vidbuchanan.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "videosqr.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vietnamhost.vn", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vigrey.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vinciconps4.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "viserproject.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "visibox.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vitastic.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vorm2.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "voter-info.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "votoot.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vpip.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vpn.black", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vrijgezellen-feest.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vubey.yt", "include_subdomains": true, "mode": "force-https" },
+ { "name": "waixingrenfuli.vip", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wakapp.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wallethub.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "walls.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wandervoll.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wangqiliang.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wangzuan168.cc", "include_subdomains": true, "mode": "force-https" },
+ { "name": "warmlyyours.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "watchface.watch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "web-industry.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "web2033.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "webcamtoy.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "webdosh.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "webduck.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "webeconomia.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "weblate.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "webmail.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "webmandesign.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "webtropia.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "weddywood.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wegenaer.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wellproducedwines.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wereldkoffie.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "westendzone.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wettbonus.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wh-guide.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "whatismyipaddress.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "whats.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "where2trip.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "whisker.network", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wigle.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wikileaks.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wikileaks.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wikisports.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "winaes.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "winged.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wint.global", "include_subdomains": true, "mode": "force-https" },
+ { "name": "winterbergwebcams.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wircon-int.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wireshark.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wirhabenspass.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wishcert.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "witzemaschine.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wochenentwicklung.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wodinaz.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "woodmafia.com.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "woodsidepottery.ca", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wowhelp.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wp-mix.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "writeoff.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "wuhengmin.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "x-ripped-hd.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "xbtce.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "xecureit.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "xfix.pw", "include_subdomains": true, "mode": "force-https" },
+ { "name": "xjoin.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "xliu.cf", "include_subdomains": true, "mode": "force-https" },
+ { "name": "xmedius.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "xmr.my", "include_subdomains": true, "mode": "force-https" },
+ { "name": "xn--7v8h.cf", "include_subdomains": true, "mode": "force-https" },
+ { "name": "xombra.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "xpj.sx", "include_subdomains": true, "mode": "force-https" },
+ { "name": "xrippedhd.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "xscapers.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "yachts-magazine.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "yarogneva.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "yesdevnull.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ylk.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "yntongji.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "yoga-school.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "yoitsu.moe", "include_subdomains": true, "mode": "force-https" },
+ { "name": "yolocelebs.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "yourbapp.ch", "include_subdomains": true, "mode": "force-https" },
+ { "name": "yout.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ytcuber.xyz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "yunpan.blue", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zachgibbens.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zakoncontrol.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zappbuildapps.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zelezny.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zelfrijdendeautos.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zemlova.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zenlogic.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zerossl.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zihao.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zilore.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zk.gd", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zkillboard.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zonemaster.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zoom.earth", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zor.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zubel.it", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zundappachterhoek.nl", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zup.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zwy.me", "include_subdomains": true, "mode": "force-https" },
// END OF BULK ADDITIONS
// Manual additions in Chrome 51 or later that do not belong in a
@@ -13604,6 +15404,10 @@
{ "name": "sogravatas.com.br", "include_subdomains": true, "mode": "force-https" },
{ "name": "xn--neb-tma3u8u.xyz", "include_subdomains": true, "mode": "force-https" },
{ "name": "swehack.org", "include_subdomains": true, "mode": "force-https", "pins": "swehackCom" },
+ { "name": "nightx.uk", "include_subdomains": true, "mode": "force-https", "pins": "nightx" },
+ { "name": "relaxpointhyncice.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "crt.sh", "include_subdomains": true, "mode": "force-https", "expect_ct": true, "expect_ct_report_uri": "https://clients3.google.com/ct_upload" },
+ { "name": "caddyserver.com", "expect_staple": true, "expect_staple_report_uri": "https://reporting.caddyserver.com/expect-staple" },
// END OF MANUAL ADDITIONS
// To avoid trailing comma changes from showing up in diffs, we place a
@@ -13889,6 +15693,8 @@
"GOOGLEVIDEO_COM",
"GOOGLEWEBLIGHT_COM",
"GOOGLEADSSERVING_CN",
- "SWEHACK_ORG"
+ "SWEHACK_ORG",
+ "GOOGLESOURCE_COM",
+ "NIGHTX_UK"
]
}
diff --git a/chromium/net/http/transport_security_state_unittest.cc b/chromium/net/http/transport_security_state_unittest.cc
index ee281f7366e..bdc2dd2f179 100644
--- a/chromium/net/http/transport_security_state_unittest.cc
+++ b/chromium/net/http/transport_security_state_unittest.cc
@@ -11,6 +11,7 @@
#include "base/base64.h"
#include "base/files/file_path.h"
#include "base/json/json_reader.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/rand_util.h"
#include "base/sha1.h"
@@ -31,7 +32,6 @@
#include "net/cert/x509_cert_types.h"
#include "net/cert/x509_certificate.h"
#include "net/http/http_util.h"
-#include "net/log/net_log.h"
#include "net/ssl/ssl_info.h"
#include "net/test/cert_test_util.h"
#include "net/test/test_data_directory.h"
@@ -47,7 +47,7 @@ const char kSubdomain[] = "foo.example.test";
const uint16_t kPort = 443;
const char kReportUri[] = "http://report-example.test/test";
const char kExpectCTStaticHostname[] = "preloaded-expect-ct.badssl.com";
-const char kExpectCTStaticReportURI[] = "https://report.badssl.com/expect-ct";
+const char kExpectCTStaticReportURI[] = "https://clients3.google.com/ct_upload";
const char kExpectStapleStaticHostname[] = "preloaded-expect-staple.badssl.com";
const char kExpectStapleStaticReportURI[] =
"https://report.badssl.com/expect-staple";
@@ -89,9 +89,12 @@ class MockCertificateReportSender
MockCertificateReportSender() {}
~MockCertificateReportSender() override {}
- void Send(const GURL& report_uri, const std::string& report) override {
+ void Send(const GURL& report_uri,
+ base::StringPiece content_type,
+ base::StringPiece report) override {
latest_report_uri_ = report_uri;
- latest_report_ = report;
+ report.CopyToString(&latest_report_);
+ content_type.CopyToString(&latest_content_type_);
}
void SetErrorCallback(
@@ -100,14 +103,17 @@ class MockCertificateReportSender
void Clear() {
latest_report_uri_ = GURL();
latest_report_ = std::string();
+ latest_content_type_ = std::string();
}
const GURL& latest_report_uri() { return latest_report_uri_; }
const std::string& latest_report() { return latest_report_; }
+ const std::string& latest_content_type() { return latest_content_type_; }
private:
GURL latest_report_uri_;
std::string latest_report_;
+ std::string latest_content_type_;
};
// A mock ReportSenderInterface that simulates a net error on every report sent.
@@ -120,7 +126,9 @@ class MockFailingCertificateReportSender
int net_error() { return net_error_; }
// TransportSecurityState::ReportSenderInterface:
- void Send(const GURL& report_uri, const std::string& report) override {
+ void Send(const GURL& report_uri,
+ base::StringPiece content_type,
+ base::StringPiece report) override {
ASSERT_FALSE(error_callback_.is_null());
error_callback_.Run(report_uri, net_error_);
}
@@ -240,6 +248,111 @@ void CheckHPKPReport(
validated_certificate_chain, report_validated_certificate_chain));
}
+// Checks the following hold for |report| such that it is a valid Expect-Staple
+// report:
+// 1. |report| is a JSON dictionary.
+// 2. The "hostname" and "port" fields match |host_port_pair|.
+// 3. The "response-status" field matches |response_status|
+// 4. The "ocsp-response" field is a base64-encoded verson of |ocsp_response|,
+// and is not present when |ocsp_response| is empty.
+// 5. The "cert-status" field matches |cert_status|, and is not present when
+// |cert_status| is empty.
+// 6. The "validated-chain" and "serverd-chain" fields match those in
+// |ssl_info|, and are only present when |ssl_info.is_issued_by_known_root|
+// is true.
+void CheckSerializedExpectStapleReport(const std::string& report,
+ const HostPortPair& host_port_pair,
+ const SSLInfo& ssl_info,
+ const std::string& ocsp_response,
+ const std::string& response_status,
+ 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));
+
+ base::DictionaryValue* report_dict;
+ ASSERT_TRUE(value->GetAsDictionary(&report_dict));
+
+ std::string report_hostname;
+ EXPECT_TRUE(report_dict->GetString("hostname", &report_hostname));
+ EXPECT_EQ(host_port_pair.host(), report_hostname);
+
+ int report_port;
+ EXPECT_TRUE(report_dict->GetInteger("port", &report_port));
+ EXPECT_EQ(host_port_pair.port(), report_port);
+
+ std::string report_response_status;
+ EXPECT_TRUE(
+ report_dict->GetString("response-status", &report_response_status));
+ EXPECT_EQ(response_status, report_response_status);
+
+ std::string report_ocsp_response;
+ bool has_ocsp_response =
+ report_dict->GetString("ocsp-response", &report_ocsp_response);
+
+ if (!ocsp_response.empty()) {
+ EXPECT_TRUE(has_ocsp_response);
+ std::string decoded_ocsp_response;
+ EXPECT_TRUE(
+ base::Base64Decode(report_ocsp_response, &decoded_ocsp_response));
+ EXPECT_EQ(ocsp_response, decoded_ocsp_response);
+ } else {
+ EXPECT_FALSE(has_ocsp_response);
+ }
+
+ std::string report_cert_status;
+ bool has_cert_status =
+ report_dict->GetString("cert-status", &report_cert_status);
+ if (!cert_status.empty()) {
+ EXPECT_TRUE(has_cert_status);
+ EXPECT_EQ(cert_status, report_cert_status);
+ } else {
+ EXPECT_FALSE(has_cert_status);
+ }
+
+ base::ListValue* report_served_certificate_chain;
+ bool has_served_chain = report_dict->GetList(
+ "served-certificate-chain", &report_served_certificate_chain);
+
+ base::ListValue* report_validated_certificate_chain;
+ bool has_validated_chain = report_dict->GetList(
+ "validated-certificate-chain", &report_validated_certificate_chain);
+
+ if (ssl_info.is_issued_by_known_root) {
+ EXPECT_TRUE(has_served_chain);
+ EXPECT_NO_FATAL_FAILURE(CompareCertificateChainWithList(
+ ssl_info.unverified_cert, report_served_certificate_chain));
+
+ EXPECT_TRUE(has_validated_chain);
+ EXPECT_NO_FATAL_FAILURE(CompareCertificateChainWithList(
+ ssl_info.cert, report_validated_certificate_chain));
+ } else {
+ EXPECT_FALSE(has_served_chain);
+ EXPECT_FALSE(has_validated_chain);
+ }
+}
+
+// Set up |state| for ExpectStaple, call CheckExpectStaple(), and verify the
+// serialized report caught by |reporter|.
+void CheckExpectStapleReport(TransportSecurityState* state,
+ MockCertificateReportSender* reporter,
+ const SSLInfo& ssl_info,
+ const std::string& ocsp_response,
+ const std::string& response_status,
+ const std::string& cert_status) {
+ // Expect-Staple is preload list based, so we use the baked-in test hostname
+ // from the list ("preloaded-expect-staple.badssl.com").
+ HostPortPair host_port(kExpectStapleStaticHostname, 443);
+ state->SetReportSender(reporter);
+ state->CheckExpectStaple(host_port, ssl_info, ocsp_response);
+ EXPECT_EQ(GURL(kExpectStapleStaticReportURI), reporter->latest_report_uri());
+ EXPECT_EQ("application/json; charset=utf-8", reporter->latest_content_type());
+ std::string serialized_report = reporter->latest_report();
+ EXPECT_NO_FATAL_FAILURE(CheckSerializedExpectStapleReport(
+ serialized_report, host_port, ssl_info, ocsp_response, response_status,
+ cert_status));
+}
+
} // namespace
class TransportSecurityStateTest : public testing::Test {
@@ -260,8 +373,9 @@ class TransportSecurityStateTest : public testing::Test {
state->enable_static_expect_ct_ = true;
}
- static void EnableStaticExpectStaple(TransportSecurityState* state) {
- state->enable_static_expect_staple_ = true;
+ static void SetEnableStaticExpectStaple(TransportSecurityState* state,
+ bool enabled) {
+ state->enable_static_expect_staple_ = enabled;
}
static HashValueVector GetSampleSPKIHashes() {
@@ -1034,7 +1148,13 @@ TEST_F(TransportSecurityStateTest, Preloaded) {
EXPECT_TRUE(StaticShouldRedirect("foo.crate.io"));
}
-TEST_F(TransportSecurityStateTest, PreloadedPins) {
+// http://crbug.com/624946
+#if defined(OS_IOS)
+#define MAYBE_PreloadedPins DISABLED_PreloadedPins
+#else
+#define MAYBE_PreloadedPins PreloadedPins
+#endif
+TEST_F(TransportSecurityStateTest, MAYBE_PreloadedPins) {
TransportSecurityState state;
EnableStaticPins(&state);
TransportSecurityState::STSState sts_state;
@@ -1209,7 +1329,13 @@ TEST_F(TransportSecurityStateTest, PinValidationWithoutRejectedCerts) {
EXPECT_FALSE(pkp_state.CheckPublicKeyPins(bad_hashes, &failure_log));
}
-TEST_F(TransportSecurityStateTest, OptionalHSTSCertPins) {
+// http://crbug.com/624946
+#if defined(OS_IOS)
+#define MAYBE_OptionalHSTSCertPins DISABLED_OptionalHSTSCertPins
+#else
+#define MAYBE_OptionalHSTSCertPins OptionalHSTSCertPins
+#endif
+TEST_F(TransportSecurityStateTest, MAYBE_OptionalHSTSCertPins) {
TransportSecurityState state;
EnableStaticPins(&state);
@@ -1326,6 +1452,8 @@ TEST_F(TransportSecurityStateTest, HPKPReporting) {
EXPECT_EQ(report_uri, mock_report_sender.latest_report_uri());
std::string report = mock_report_sender.latest_report();
ASSERT_FALSE(report.empty());
+ EXPECT_EQ("application/json; charset=utf-8",
+ mock_report_sender.latest_content_type());
ASSERT_NO_FATAL_FAILURE(CheckHPKPReport(report, host_port_pair, true, kHost,
cert1.get(), cert2.get(),
good_hashes));
@@ -1341,6 +1469,8 @@ TEST_F(TransportSecurityStateTest, HPKPReporting) {
EXPECT_EQ(report_uri, mock_report_sender.latest_report_uri());
report = mock_report_sender.latest_report();
ASSERT_FALSE(report.empty());
+ EXPECT_EQ("application/json; charset=utf-8",
+ mock_report_sender.latest_content_type());
ASSERT_NO_FATAL_FAILURE(CheckHPKPReport(report, subdomain_host_port_pair,
true, kHost, cert1.get(), cert2.get(),
good_hashes));
@@ -1350,7 +1480,7 @@ TEST_F(TransportSecurityStateTest, HPKPReporting) {
// fails to send an HPKP violation report.
TEST_F(TransportSecurityStateTest, UMAOnHPKPReportingFailure) {
base::HistogramTester histograms;
- const std::string histogram_name = "Net.PublicKeyPinReportSendingFailure";
+ const std::string histogram_name = "Net.PublicKeyPinReportSendingFailure2";
HostPortPair host_port_pair(kHost, kPort);
GURL report_uri(kReportUri);
// Two dummy certs to use as the server-sent and validated chains. The
@@ -1389,7 +1519,7 @@ TEST_F(TransportSecurityStateTest, UMAOnHPKPReportingFailure) {
// Check that the UMA histogram was updated when the report failed to
// send.
histograms.ExpectTotalCount(histogram_name, 1);
- histograms.ExpectBucketCount(histogram_name, mock_report_sender.net_error(),
+ histograms.ExpectBucketCount(histogram_name, -mock_report_sender.net_error(),
1);
}
@@ -1451,6 +1581,8 @@ TEST_F(TransportSecurityStateTest, HPKPReportOnly) {
EXPECT_EQ(report_uri, mock_report_sender.latest_report_uri());
std::string report = mock_report_sender.latest_report();
ASSERT_FALSE(report.empty());
+ EXPECT_EQ("application/json; charset=utf-8",
+ mock_report_sender.latest_content_type());
ASSERT_NO_FATAL_FAILURE(CheckHPKPReport(report, host_port_pair, true, kHost,
cert1.get(), cert2.get(),
ssl_info.public_key_hashes));
@@ -1577,6 +1709,8 @@ TEST_F(TransportSecurityStateTest, PreloadedPKPReportUri) {
std::string report = mock_report_sender.latest_report();
ASSERT_FALSE(report.empty());
+ EXPECT_EQ("application/json; charset=utf-8",
+ mock_report_sender.latest_content_type());
ASSERT_NO_FATAL_FAILURE(CheckHPKPReport(
report, host_port_pair, pkp_state.include_subdomains, pkp_state.domain,
cert1.get(), cert2.get(), pkp_state.spki_hashes));
@@ -1725,9 +1859,10 @@ TEST_F(TransportSecurityStateTest, PreloadedExpectCT) {
TEST_F(TransportSecurityStateTest, PreloadedExpectStaple) {
TransportSecurityState state;
TransportSecurityState::ExpectStapleState expect_staple_state;
+ TransportSecurityStateTest::SetEnableStaticExpectStaple(&state, false);
EXPECT_FALSE(GetExpectStapleState(&state, kExpectStapleStaticHostname,
&expect_staple_state));
- TransportSecurityStateTest::EnableStaticExpectStaple(&state);
+ TransportSecurityStateTest::SetEnableStaticExpectStaple(&state, true);
EXPECT_TRUE(GetExpectStapleState(&state, kExpectStapleStaticHostname,
&expect_staple_state));
EXPECT_EQ(kExpectStapleStaticHostname, expect_staple_state.domain);
@@ -1742,7 +1877,7 @@ TEST_F(TransportSecurityStateTest, PreloadedExpectStaple) {
TEST_F(TransportSecurityStateTest, PreloadedExpectStapleIncludeSubdomains) {
TransportSecurityState state;
- TransportSecurityStateTest::EnableStaticExpectStaple(&state);
+ TransportSecurityStateTest::SetEnableStaticExpectStaple(&state, true);
TransportSecurityState::ExpectStapleState expect_staple_state;
std::string subdomain = "subdomain.";
subdomain += kExpectStapleStaticIncludeSubdomainsHostname;
@@ -1890,6 +2025,190 @@ TEST_F(TransportSecurityStateTest, ExpectCTReporter) {
EXPECT_EQ(GURL(kExpectCTStaticReportURI), reporter.report_uri());
}
+static const struct ExpectStapleErrorResponseData {
+ OCSPVerifyResult::ResponseStatus response_status;
+ std::string response_status_string;
+} kExpectStapleReportData[] = {
+ {OCSPVerifyResult::MISSING, "MISSING"},
+ {OCSPVerifyResult::ERROR_RESPONSE, "ERROR_RESPONSE"},
+ {OCSPVerifyResult::BAD_PRODUCED_AT, "BAD_PRODUCED_AT"},
+ {OCSPVerifyResult::NO_MATCHING_RESPONSE, "NO_MATCHING_RESPONSE"},
+ {OCSPVerifyResult::INVALID_DATE, "INVALID_DATE"},
+ {OCSPVerifyResult::PARSE_RESPONSE_ERROR, "PARSE_RESPONSE_ERROR"},
+ {OCSPVerifyResult::PARSE_RESPONSE_DATA_ERROR, "PARSE_RESPONSE_DATA_ERROR"},
+};
+
+class ExpectStapleErrorResponseTest
+ : public TransportSecurityStateTest,
+ public testing::WithParamInterface<ExpectStapleErrorResponseData> {};
+
+// For every |response_status| indicating an OCSP response was provided, but had
+// some sort of parsing/validation error, test that the ExpectStaple report is
+// serialized correctly.
+TEST_P(ExpectStapleErrorResponseTest, CheckResponseStatusSerialization) {
+ TransportSecurityState state;
+ TransportSecurityStateTest::SetEnableStaticExpectStaple(&state, true);
+ MockCertificateReportSender reporter;
+ ExpectStapleErrorResponseData test = GetParam();
+
+ std::string ocsp_response;
+ if (test.response_status != OCSPVerifyResult::MISSING)
+ ocsp_response = "dummy_response";
+
+ // Two dummy certs to use as the server-sent and validated chains. The
+ // contents don't matter.
+ scoped_refptr<X509Certificate> cert1 =
+ ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem");
+ scoped_refptr<X509Certificate> cert2 =
+ ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem");
+
+ SSLInfo ssl_info;
+ ssl_info.cert = cert1;
+ ssl_info.unverified_cert = cert2;
+ ssl_info.ocsp_result.response_status = test.response_status;
+
+ // Certificate chains should only be included when |is_issued_by_known_root|
+ // is true.
+ ssl_info.is_issued_by_known_root = true;
+ ASSERT_NO_FATAL_FAILURE(
+ CheckExpectStapleReport(&state, &reporter, ssl_info, ocsp_response,
+ test.response_status_string, std::string()));
+
+ // No certificate chains should be included in the report.
+ ssl_info.is_issued_by_known_root = false;
+ ASSERT_NO_FATAL_FAILURE(
+ CheckExpectStapleReport(&state, &reporter, ssl_info, ocsp_response,
+ test.response_status_string, std::string()));
+}
+
+INSTANTIATE_TEST_CASE_P(ExpectStaple,
+ ExpectStapleErrorResponseTest,
+ testing::ValuesIn(kExpectStapleReportData));
+
+static const struct ExpectStapleErrorCertStatusData {
+ OCSPRevocationStatus revocation_status;
+ std::string cert_status_string;
+} kExpectStapleErrorCertStatusData[] = {
+ {OCSPRevocationStatus::REVOKED, "REVOKED"},
+ {OCSPRevocationStatus::UNKNOWN, "UNKNOWN"},
+};
+
+class ExpectStapleErrorCertStatusTest
+ : public TransportSecurityStateTest,
+ public testing::WithParamInterface<ExpectStapleErrorCertStatusData> {};
+
+// Test that |revocation_status| is serialized into the |cert-status| field of
+// the Expect-Staple report whenever |response_status| is PROVIDED and
+// |revocation_status| != GOOD.
+TEST_P(ExpectStapleErrorCertStatusTest, CheckCertStatusSerialization) {
+ TransportSecurityState state;
+ TransportSecurityStateTest::SetEnableStaticExpectStaple(&state, true);
+ MockCertificateReportSender reporter;
+ ExpectStapleErrorCertStatusData test = GetParam();
+ std::string ocsp_response = "dummy_response";
+
+ // Two dummy certs to use as the server-sent and validated chains. The
+ // contents don't matter.
+ scoped_refptr<X509Certificate> cert1 =
+ ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem");
+ scoped_refptr<X509Certificate> cert2 =
+ ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem");
+
+ SSLInfo ssl_info;
+ ssl_info.cert = cert1;
+ ssl_info.unverified_cert = cert2;
+ // |response_status| must be set to PROVIDED for |revocation_status| to have
+ // meaning.
+ ssl_info.ocsp_result.response_status = OCSPVerifyResult::PROVIDED;
+ ssl_info.ocsp_result.revocation_status = test.revocation_status;
+
+ // Certificate chains should only be included when |is_issued_by_known_root|
+ // is true.
+ ssl_info.is_issued_by_known_root = true;
+ ASSERT_NO_FATAL_FAILURE(CheckExpectStapleReport(&state, &reporter, ssl_info,
+ ocsp_response, "PROVIDED",
+ test.cert_status_string));
+
+ // No certificate chains should be included in the report.
+ ssl_info.is_issued_by_known_root = false;
+ ASSERT_NO_FATAL_FAILURE(CheckExpectStapleReport(&state, &reporter, ssl_info,
+ ocsp_response, "PROVIDED",
+ test.cert_status_string));
+};
+
+INSTANTIATE_TEST_CASE_P(ExpectStaple,
+ ExpectStapleErrorCertStatusTest,
+ testing::ValuesIn(kExpectStapleErrorCertStatusData));
+
+TEST_F(TransportSecurityStateTest, ExpectStapleDoesNotReportValidStaple) {
+ TransportSecurityState state;
+ TransportSecurityStateTest::SetEnableStaticExpectStaple(&state, true);
+ MockCertificateReportSender reporter;
+ state.SetReportSender(&reporter);
+
+ // Baked-in preloaded Expect-Staple test hosts.
+ HostPortPair host_port(kExpectStapleStaticHostname, 443);
+
+ // Two dummy certs to use as the server-sent and validated chains. The
+ // contents don't matter.
+ scoped_refptr<X509Certificate> cert1 =
+ ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem");
+ scoped_refptr<X509Certificate> cert2 =
+ ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem");
+
+ SSLInfo ssl_info;
+ ssl_info.cert = cert1;
+ ssl_info.unverified_cert = cert2;
+ ssl_info.ocsp_result.response_status = OCSPVerifyResult::PROVIDED;
+ ssl_info.ocsp_result.revocation_status = OCSPRevocationStatus::GOOD;
+
+ std::string ocsp_response = "dummy response";
+
+ ssl_info.is_issued_by_known_root = true;
+ state.CheckExpectStaple(host_port, ssl_info, ocsp_response);
+ EXPECT_EQ(GURL(), reporter.latest_report_uri());
+ EXPECT_TRUE(reporter.latest_report().empty());
+
+ ssl_info.is_issued_by_known_root = false;
+ state.CheckExpectStaple(host_port, ssl_info, ocsp_response);
+ EXPECT_EQ(GURL(), reporter.latest_report_uri());
+ EXPECT_TRUE(reporter.latest_report().empty());
+}
+
+TEST_F(TransportSecurityStateTest, ExpectStapleRequiresPreload) {
+ TransportSecurityState state;
+ TransportSecurityStateTest::SetEnableStaticExpectStaple(&state, true);
+ MockCertificateReportSender reporter;
+ state.SetReportSender(&reporter);
+
+ HostPortPair host_port("not-preloaded.host.example", 443);
+
+ // Two dummy certs to use as the server-sent and validated chains. The
+ // contents don't matter.
+ scoped_refptr<X509Certificate> cert1 =
+ ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem");
+ scoped_refptr<X509Certificate> cert2 =
+ ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem");
+
+ SSLInfo ssl_info;
+ ssl_info.cert = cert1;
+ ssl_info.unverified_cert = cert2;
+ ssl_info.ocsp_result.response_status = OCSPVerifyResult::MISSING;
+
+ // Empty response
+ std::string ocsp_response;
+
+ ssl_info.is_issued_by_known_root = true;
+ state.CheckExpectStaple(host_port, ssl_info, ocsp_response);
+ EXPECT_EQ(GURL(), reporter.latest_report_uri());
+ EXPECT_TRUE(reporter.latest_report().empty());
+
+ ssl_info.is_issued_by_known_root = false;
+ state.CheckExpectStaple(host_port, ssl_info, ocsp_response);
+ EXPECT_EQ(GURL(), reporter.latest_report_uri());
+ EXPECT_TRUE(reporter.latest_report().empty());
+}
+
// Tests that TransportSecurityState always consults the RequireCTDelegate,
// if supplied.
TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) {
@@ -2013,7 +2332,8 @@ TEST_F(TransportSecurityStateTest, RequireCTForSymantec) {
// necessary.
hashes.clear();
hashes.push_back(HashValue(symantec_hash_value));
- base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
+ base::FieldTrialList field_trial_list(
+ base::MakeUnique<base::MockEntropyProvider>());
base::FieldTrialList::CreateFieldTrial("EnforceCTForProblematicRoots",
"disabled");
diff --git a/chromium/net/interfaces/BUILD.gn b/chromium/net/interfaces/BUILD.gn
index ba7b53ff23d..fa40505de31 100644
--- a/chromium/net/interfaces/BUILD.gn
+++ b/chromium/net/interfaces/BUILD.gn
@@ -12,4 +12,6 @@ mojom("interfaces") {
public_deps = [
"//url/mojo:url_mojom_gurl",
]
+
+ use_new_wrapper_types = false
}
diff --git a/chromium/net/log/bounded_file_net_log_observer.cc b/chromium/net/log/bounded_file_net_log_observer.cc
new file mode 100644
index 00000000000..833e84753d5
--- /dev/null
+++ b/chromium/net/log/bounded_file_net_log_observer.cc
@@ -0,0 +1,405 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/log/bounded_file_net_log_observer.h"
+
+#include <memory>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread.h"
+#include "base/values.h"
+#include "net/log/net_log_entry.h"
+#include "net/log/net_log_util.h"
+#include "net/url_request/url_request_context.h"
+
+namespace {
+
+// Number of events that can build up in |write_queue_| before file thread
+// is triggered to drain the queue.
+const int kNumWriteQueueEvents = 15;
+
+} // namespace
+
+namespace net {
+
+// Used to store events to be written to file.
+using EventQueue = std::queue<std::unique_ptr<std::string>>;
+
+// WriteQueue receives events from BoundedFileNetLogObserver on the main
+// thread and holds them in a queue until they are drained from the queue
+// and written to file on the file thread.
+//
+// WriteQueue contains the resources shared between the main thread and the
+// file thread. |lock_| must be acquired to read or write to |queue_| and
+// |memory_|.
+//
+// WriteQueue is refcounted and should be destroyed once all events on the
+// file thread have finished executing.
+class BoundedFileNetLogObserver::WriteQueue
+ : public base::RefCountedThreadSafe<WriteQueue> {
+ public:
+ // |memory_max| indicates the maximum amount of memory that the virtual write
+ // queue can use. If |memory_| exceeds |memory_max_|, the |queue_| of events
+ // is overwritten.
+ WriteQueue(size_t memory_max);
+
+ // Adds |event| to |queue_|. Also manages the size of |memory_|; if it
+ // exceeds |memory_max_|, then old events are dropped from |queue_| without
+ // being written to file.
+ //
+ // Returns the number of events in the |queue_|.
+ size_t AddEntryToQueue(std::unique_ptr<std::string> event);
+
+ // Swaps |queue_| with |local_queue|. |local_queue| should be empty, so that
+ // |queue_| is emptied. Resets |memory_| to 0.
+ void SwapQueue(EventQueue* local_queue);
+
+ private:
+ friend class base::RefCountedThreadSafe<WriteQueue>;
+
+ ~WriteQueue();
+
+ // Queue of events to be written shared between main thread and file thread.
+ // Main thread adds events to the queue and the file thread drains them and
+ // writes the events to file.
+ //
+ // |lock_| must be acquired to read or write to this.
+ EventQueue queue_;
+
+ // Tracks how much memory is being used by the virtual write queue.
+ // Incremented in AddEntryToQueue() when events are added to the
+ // buffer, and decremented when SwapQueue() is called and the file thread's
+ // local queue is swapped with the shared write queue.
+ //
+ // |lock_| must be acquired to read or write to this.
+ size_t memory_;
+
+ // Indicates the maximum amount of memory that the |queue_| is allowed to
+ // use.
+ const size_t memory_max_;
+
+ // Protects access to |queue_| and |memory_|.
+ //
+ // A lock is necessary because |queue_| and |memory_| are shared between the
+ // file thread and the main thread. NetLog's lock protects OnAddEntry(),
+ // which calls AddEntryToQueue(), but it does not protect access to the
+ // observer's member variables. Thus, a race condition exists if a thread is
+ // calling OnAddEntry() at the same time that the file thread is accessing
+ // |memory_| and |queue_| to write events to file. The |queue_| and |memory_|
+ // counter are necessary to bound the amount of memory that is used for the
+ // queue in the event that the file thread lags significantly behind the main
+ // thread in writing events to file.
+ base::Lock lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(WriteQueue);
+};
+
+// FileWriter drains events from WriteQueue and writes them to file.
+//
+// Owned by BoundedFileNetLogObserver. FileWriter can be constructed on any
+// thread, and afterwards is only accessed on the file thread.
+class BoundedFileNetLogObserver::FileWriter {
+ public:
+ FileWriter(const base::FilePath& path,
+ size_t max_file_size,
+ size_t total_num_files,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
+ ~FileWriter();
+
+ // Writes |constants_value| to constants.json, and opens the
+ // events array (closed in Stop()).
+ void Initialize(std::unique_ptr<base::Value> constants_value);
+
+ // Closes the events array opened in Initialize() and writes |tab_info| to
+ // end_netlog.json. If |tab_info| cannot be converted to proper JSON, then it
+ // is ignored.
+ void Stop(std::unique_ptr<base::Value> tab_info);
+
+ // Drains |queue_| from WriteQueue into a local file queue and writes the
+ // events in the queue to file.
+ void Flush(scoped_refptr<WriteQueue> write_queue);
+
+ // Deletes all netlog files, including constants.json and end_netlog.json.
+ // It is not valid to call any method of BoundedFileNetLogObserver after
+ // DeleteAllFiles().
+ void DeleteAllFiles();
+
+ private:
+ // Increments |current_file_idx_|, and handles the clearing and openining of
+ // the new current file. Also sets |event_files_[current_file_idx_]| to point
+ // to the new current file.
+ void IncrementCurrentFile();
+
+ // Each ScopedFILE points to a netlog event file with the file name
+ // "event_file_<index>.json".
+ std::vector<base::ScopedFILE> event_files_;
+
+ // The directory where the netlog files are created.
+ const base::FilePath directory_;
+
+ // Indicates the total number of netlog event files, which does not include
+ // the constants file (constants.json), or closing file (end_netlog.json).
+ const size_t total_num_files_;
+
+ // Indicates the index of the file in |event_files_| currently being written
+ // into.
+ size_t current_file_idx_;
+
+ // Indicates the maximum size of each individual netlogging file, excluding
+ // the constant file.
+ const size_t max_file_size_;
+
+ // Task runner from the file thread.
+ const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileWriter);
+};
+
+BoundedFileNetLogObserver::BoundedFileNetLogObserver(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : capture_mode_(NetLogCaptureMode::Default()), task_runner_(task_runner) {}
+
+BoundedFileNetLogObserver::~BoundedFileNetLogObserver() {
+ if (net_log()) {
+ // StopObserving was not called.
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BoundedFileNetLogObserver::FileWriter::DeleteAllFiles,
+ base::Unretained(file_writer_)));
+ net_log()->DeprecatedRemoveObserver(this);
+ }
+
+ task_runner_->DeleteSoon(FROM_HERE, file_writer_);
+}
+
+void BoundedFileNetLogObserver::set_capture_mode(
+ NetLogCaptureMode capture_mode) {
+ DCHECK(!net_log());
+ capture_mode_ = capture_mode;
+}
+
+void BoundedFileNetLogObserver::StartObserving(
+ NetLog* net_log,
+ const base::FilePath& filepath,
+ base::Value* constants,
+ URLRequestContext* url_request_context,
+ size_t max_total_size,
+ size_t total_num_files) {
+ DCHECK_GT(total_num_files, 0u);
+
+ file_writer_ = new FileWriter(filepath, max_total_size / total_num_files,
+ total_num_files, task_runner_);
+
+ // The |file_writer_| uses a soft limit to write events to file that allows
+ // the size of the file to exceed the limit, but the |write_queue_| uses a
+ // hard limit which the size of the |queue_| cannot exceed. Thus, the
+ // |file_writer_| may write more events to file than can be contained by the
+ // |write_queue_| if they have the same size limit. The maximum size of the
+ // |write_queue_| is doubled to allow the |queue_| to hold enough events for
+ // the |file_writer_| to fill all files. As long as all events have sizes <=
+ // the size of an individual event file, the discrepancy between the hard
+ // limit and the soft limit will not cause an issue.
+ // TODO(dconnol): Handle the case when the |write_queue_| still doesn't
+ // contain enough events to fill all files, because of very large events
+ // relative to file size.
+ write_queue_ = make_scoped_refptr(new WriteQueue(max_total_size * 2));
+
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&BoundedFileNetLogObserver::FileWriter::Initialize,
+ base::Unretained(file_writer_),
+ base::Passed(constants ? constants->CreateDeepCopy()
+ : GetNetConstants())));
+
+ if (url_request_context) {
+ DCHECK(url_request_context->CalledOnValidThread());
+ std::set<URLRequestContext*> contexts;
+ contexts.insert(url_request_context);
+ CreateNetLogEntriesForActiveObjects(contexts, this);
+ }
+
+ net_log->DeprecatedAddObserver(this, capture_mode_);
+}
+
+void BoundedFileNetLogObserver::StopObserving(
+ URLRequestContext* url_request_context,
+ const base::Closure& callback) {
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&BoundedFileNetLogObserver::FileWriter::Flush,
+ base::Unretained(file_writer_), write_queue_));
+
+ task_runner_->PostTaskAndReply(
+ FROM_HERE, base::Bind(&BoundedFileNetLogObserver::FileWriter::Stop,
+ base::Unretained(file_writer_),
+ base::Passed(url_request_context
+ ? GetNetInfo(url_request_context,
+ NET_INFO_ALL_SOURCES)
+ : nullptr)),
+ callback);
+
+ net_log()->DeprecatedRemoveObserver(this);
+}
+
+void BoundedFileNetLogObserver::OnAddEntry(const NetLogEntry& entry) {
+ std::unique_ptr<std::string> json(new std::string);
+
+ // If |entry| cannot be converted to proper JSON, ignore it.
+ if (!base::JSONWriter::Write(*entry.ToValue(), json.get()))
+ return;
+
+ size_t queue_size = write_queue_->AddEntryToQueue(std::move(json));
+
+ // If events build up in |write_queue_|, trigger the file thread to drain
+ // the queue.
+ if (queue_size >= kNumWriteQueueEvents) {
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&BoundedFileNetLogObserver::FileWriter::Flush,
+ base::Unretained(file_writer_), write_queue_));
+ }
+}
+
+BoundedFileNetLogObserver::WriteQueue::WriteQueue(size_t memory_max)
+ : memory_(0), memory_max_(memory_max) {}
+
+size_t BoundedFileNetLogObserver::WriteQueue::AddEntryToQueue(
+ std::unique_ptr<std::string> event) {
+ base::AutoLock lock(lock_);
+
+ memory_ += event->size();
+ queue_.push(std::move(event));
+
+ while (memory_ > memory_max_ && !queue_.empty()) {
+ // Delete oldest events in the queue.
+ DCHECK(queue_.front());
+ memory_ -= queue_.front()->size();
+ queue_.pop();
+ }
+
+ return queue_.size();
+}
+void BoundedFileNetLogObserver::WriteQueue::SwapQueue(EventQueue* local_queue) {
+ DCHECK(local_queue->empty());
+ base::AutoLock lock(lock_);
+ queue_.swap(*local_queue);
+ memory_ = 0;
+}
+
+BoundedFileNetLogObserver::WriteQueue::~WriteQueue() {}
+
+BoundedFileNetLogObserver::FileWriter::FileWriter(
+ const base::FilePath& path,
+ size_t max_file_size,
+ size_t total_num_files,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : directory_(path),
+ total_num_files_(total_num_files),
+ current_file_idx_(0),
+ max_file_size_(max_file_size),
+ task_runner_(task_runner) {
+ event_files_.resize(total_num_files_);
+}
+
+BoundedFileNetLogObserver::FileWriter::~FileWriter() {}
+
+void BoundedFileNetLogObserver::FileWriter::Initialize(
+ std::unique_ptr<base::Value> constants_value) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ event_files_[current_file_idx_] = base::ScopedFILE(
+ base::OpenFile(directory_.AppendASCII("event_file_0.json"), "w"));
+
+ base::ScopedFILE constants_file(
+ base::OpenFile(directory_.AppendASCII("constants.json"), "w"));
+
+ // Print constants to file and open events array.
+ std::string json;
+
+ // It should always be possible to convert constants to JSON.
+ if (!base::JSONWriter::Write(*constants_value, &json))
+ DCHECK(false);
+ fprintf(constants_file.get(), "{\"constants\":%s,\n\"events\": [\n",
+ json.c_str());
+}
+
+void BoundedFileNetLogObserver::FileWriter::Stop(
+ std::unique_ptr<base::Value> tab_info) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ base::ScopedFILE closing_file(
+ base::OpenFile(directory_.AppendASCII("end_netlog.json"), "w"));
+
+ std::string json;
+ if (tab_info)
+ base::JSONWriter::Write(*tab_info, &json);
+
+ fprintf(closing_file.get(), "]%s}",
+ json.empty() ? "" : (",\"tabInfo\": " + json + "\n").c_str());
+
+ // Flush all fprintfs to disk so that files can be safely accessed on
+ // callback.
+ event_files_.clear();
+}
+
+void BoundedFileNetLogObserver::FileWriter::IncrementCurrentFile() {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ current_file_idx_++;
+ current_file_idx_ %= total_num_files_;
+ event_files_[current_file_idx_].reset();
+ event_files_[current_file_idx_] = base::ScopedFILE(base::OpenFile(
+ directory_.AppendASCII("event_file_" +
+ base::SizeTToString(current_file_idx_) + ".json"),
+ "w"));
+}
+
+void BoundedFileNetLogObserver::FileWriter::Flush(
+ scoped_refptr<BoundedFileNetLogObserver::WriteQueue> write_queue) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ EventQueue local_file_queue;
+ write_queue->SwapQueue(&local_file_queue);
+
+ std::string to_print;
+ size_t file_size = ftell(event_files_[current_file_idx_].get());
+ size_t memory_freed = 0;
+
+ while (!local_file_queue.empty()) {
+ if (file_size >= max_file_size_) {
+ // The current file is full. Start a new current file.
+ IncrementCurrentFile();
+ file_size = 0;
+ }
+ fprintf(event_files_[current_file_idx_].get(), "%s,\n",
+ local_file_queue.front().get()->c_str());
+ file_size += local_file_queue.front()->size();
+ memory_freed += local_file_queue.front()->size();
+ local_file_queue.pop();
+ }
+}
+
+void BoundedFileNetLogObserver::FileWriter::DeleteAllFiles() {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ // Reset |event_files_| to release all file handles so base::DeleteFile can
+ // safely access files.
+ event_files_.clear();
+
+ base::DeleteFile(directory_.AppendASCII("constants.json"), false);
+ base::DeleteFile(directory_.AppendASCII("end_netlog.json"), false);
+ for (size_t i = 0; i < total_num_files_; i++) {
+ base::DeleteFile(directory_.AppendASCII("event_file_" +
+ base::SizeTToString(i) + ".json"),
+ false);
+ }
+}
+
+} // namespace net
diff --git a/chromium/net/log/bounded_file_net_log_observer.h b/chromium/net/log/bounded_file_net_log_observer.h
new file mode 100644
index 00000000000..918398ca941
--- /dev/null
+++ b/chromium/net/log/bounded_file_net_log_observer.h
@@ -0,0 +1,136 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BOUNDED_FILE_NET_LOG_OBSERVER_H_
+#define BOUNDED_FILE_NET_LOG_OBSERVER_H_
+
+#include <queue>
+
+#include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "net/base/net_export.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+
+namespace base {
+class DictionaryValue;
+class Value;
+} // namespace base
+
+namespace net {
+
+class URLRequestContext;
+
+// BoundedFileNetLogObserver watches the NetLog event stream and sends all
+// entries to a group of files in the directory specified when observation
+// starts.
+//
+// The events are written to a single JSON object that is split across the
+// files, and the files must be stitched together once the observation period
+// is over. The first file is constants.json, followed by a consumer-specified
+// number of event files named event_file_<index>.json, and the last file is
+// end_netlog.json.
+//
+// The user is able to specify an approximate maximum cumulative size for the
+// netlog files and the observer overwrites old events when the maximum file
+// size is reached.
+//
+// The consumer must call StartObserving before calling StopObserving, and must
+// call each method exactly once in the lifetime of the observer. StartObserving
+// and StopObserving must be called on the same thread, but there is no
+// restriction on which thread is used.
+class NET_EXPORT BoundedFileNetLogObserver : public NetLog::ThreadSafeObserver {
+ public:
+ // |task_runner| indicates the task runner that should be used to post tasks
+ // from the main thread to the file thread.
+ //
+ // |num_event_files| sets the number of event files that should be used to
+ // write events to file.
+ BoundedFileNetLogObserver(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
+ ~BoundedFileNetLogObserver() override;
+
+ // Sets the capture mode to log at. Must be called before StartObserving.
+ void set_capture_mode(NetLogCaptureMode capture_mode);
+
+ // Starts observing |net_log| and writes output to files in |filepath|.
+ // May only be called once in the lifetime of the object.
+ //
+ // |max_total_size| is the approximate limit on the cumulative size of all
+ // netlog files.
+ //
+ // |total_num_files| sets the total number of event files that are used to
+ // write the events. It must be greater than 0.
+ //
+ // |constants| is an optional legend for decoding constant values used in
+ // the log. It should generally be a modified version of GetNetConstants().
+ // If not present, the output of GetNetConstants() will be used.
+ //
+ // |url_request_context| is an optional URLRequestContext that will be used
+ // to pre-populate the log with information about in-progress events. If the
+ // context is non-NULL, StartObserving() must be called on the context's
+ // thread.
+ void StartObserving(NetLog* net_log,
+ const base::FilePath& filepath,
+ base::Value* constants,
+ URLRequestContext* url_request_context,
+ size_t max_total_size,
+ size_t total_num_files);
+
+ // Stops observing net_log(). Must be called after StartObserving(). Should
+ // be called before destruction of the BoundedFileNetLogObserver and the
+ // NetLog, or the NetLog files will be deleted when the observer is
+ // destroyed.
+ //
+ // |callback| will be run on whichever thread StopObserving() was called on
+ // once all file writing is complete and the netlog files can be accessed
+ // safely.
+ //
+ // |url_request_context| is an optional argument used to add additional
+ // network stack state to the log. If the context is non-NULL,
+ // StopObserving() must be called on the context's thread.
+ void StopObserving(URLRequestContext* url_request_context,
+ const base::Closure& callback);
+
+ // NetLog::ThreadSafeObserver
+ void OnAddEntry(const NetLogEntry& entry) override;
+
+ private:
+ class WriteQueue;
+ class FileWriter;
+
+ // The capture mode to log at.
+ NetLogCaptureMode capture_mode_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ // The |write_queue_| object is shared between the file thread and the main
+ // thread, and should be alive for the entirety of the observer's lifetime.
+ // It should be destroyed once both the observer has been destroyed and all
+ // tasks posted to the file thread have completed.
+ scoped_refptr<WriteQueue> write_queue_;
+
+ // This is the owning reference to a file thread object. The observer is
+ // responsible for destroying the file thread object by posting a task from
+ // the main thread to the file thread to destroy the FileWriter when the
+ // observer is destroyed.
+ //
+ // The use of base::Unretained with |file_writer_| to post tasks to the file
+ // thread is safe because the FileWriter object will be alive until the
+ // observer's destruction.
+ FileWriter* file_writer_;
+
+ DISALLOW_COPY_AND_ASSIGN(BoundedFileNetLogObserver);
+};
+
+} // namespace net
+
+#endif // BOUNDED_FILE_NET_LOG_OBSERVER_H_
diff --git a/chromium/net/log/bounded_file_net_log_observer_unittest.cc b/chromium/net/log/bounded_file_net_log_observer_unittest.cc
new file mode 100644
index 00000000000..6296c446df1
--- /dev/null
+++ b/chromium/net/log/bounded_file_net_log_observer_unittest.cc
@@ -0,0 +1,860 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/log/bounded_file_net_log_observer.h"
+
+#include <math.h>
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "net/base/test_completion_callback.h"
+#include "net/log/net_log_entry.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_parameters_callback.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
+#include "net/log/net_log_util.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+// Indicates the number of event files used in test cases.
+const int kTotalNumFiles = 10;
+
+// Used to set the total file size maximum in test cases where the file size
+// doesn't matter.
+const int kLargeFileSize = 100000000;
+
+// Used to set the size of events to be sent to the observer in test cases
+// where event size doesn't matter.
+const size_t kDummyEventSize = 150;
+
+const std::string kWinLineEnd = "\r\n";
+const std::string kLinuxLineEnd = "\n";
+
+class BoundedFileNetLogObserverTest : public testing::Test {
+ public:
+ void SetUp() override {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ log_path_ = temp_dir_.GetPath();
+ file_thread_.reset(new base::Thread("NetLog File Thread"));
+ file_thread_->StartWithOptions(
+ base::Thread::Options(base::MessageLoop::TYPE_DEFAULT, 0));
+ if (file_thread_->WaitUntilThreadStarted()) {
+ logger_ = std::unique_ptr<BoundedFileNetLogObserver>(
+ new BoundedFileNetLogObserver(file_thread_->task_runner()));
+ }
+ }
+
+ // Concatenates all files together, including constants file and end file.
+ void AddAllFiles(std::string* input) {
+ base::ReadFileToString(log_path_.AppendASCII("constants.json"), input);
+ std::string to_add;
+ size_t input_no_events = input->length();
+ for (int i = 0; i < kTotalNumFiles; i++) {
+ base::ReadFileToString(
+ log_path_.AppendASCII("event_file_" + std::to_string(i) + ".json"),
+ &to_add);
+ *input += to_add;
+ }
+
+ // Delete the hanging comma and newline from the events array.
+ if (input->length() > input_no_events) {
+ // Remove carriage returns in case of Windows machine.
+ base::ReplaceSubstringsAfterOffset(input, 0, kWinLineEnd, kLinuxLineEnd);
+ ASSERT_GE(input->length() - input_no_events, 2u);
+ ASSERT_EQ(std::string(",\n"), std::string(*input, input->length() - 2));
+ input->erase(input->end() - 2, input->end() - 1);
+ }
+
+ base::ReadFileToString(log_path_.AppendASCII("end_netlog.json"), &to_add);
+ *input += to_add;
+ }
+
+ // Sends |num_entries_to_add| number of events of size |entry_size| to
+ // |logger_|.
+ //
+ // |entry_size| must be >= 101, since the size of entries without a message,
+ // |base_entry_size|, is dependent on TimeTicks formatting, and
+ // |base_entry_size| can be up to 101 and cannot be shortened.
+ void AddEntries(int num_entries_to_add, size_t entry_size) {
+ // Get base size of event.
+ const int kDummyId = 0;
+ std::string message = "";
+ NetLogParametersCallback callback =
+ NetLog::StringCallback("message", &message);
+ NetLogSource source(NetLogSourceType::HTTP2_SESSION, kDummyId);
+ NetLogEntryData base_entry_data(NetLogEventType::PAC_JAVASCRIPT_ERROR,
+ source, NetLogEventPhase::BEGIN,
+ base::TimeTicks::Now(), &callback);
+ NetLogEntry base_entry(&base_entry_data,
+ NetLogCaptureMode::IncludeSocketBytes());
+ std::unique_ptr<base::Value> value(base_entry.ToValue());
+ std::string json;
+ base::JSONWriter::Write(*value, &json);
+ size_t base_entry_size = json.size();
+
+ // The maximum value of base::TimeTicks::Now() will be the maximum value of
+ // int64_t, and if the maximum number of digits are included, the
+ // |base_entry_size| could be up to 101 characters. Check that the event
+ // format does not include additional padding.
+ DCHECK_LE(base_entry_size, 101u);
+
+ // |entry_size| should be at least as big as the largest possible base
+ // entry.
+ EXPECT_GE(entry_size, 101u);
+
+ // |entry_size| cannot be smaller than the minimum event size.
+ EXPECT_GE(entry_size, base_entry_size);
+
+ for (int i = 0; i < num_entries_to_add; i++) {
+ source = NetLogSource(NetLogSourceType::HTTP2_SESSION, i);
+ std::string id = std::to_string(i);
+
+ // String size accounts for the number of digits in id so that all events
+ // are the same size.
+ message = std::string(entry_size - base_entry_size - id.size() + 1, 'x');
+ callback = NetLog::StringCallback("message", &message);
+ NetLogEntryData entry_data(NetLogEventType::PAC_JAVASCRIPT_ERROR, source,
+ NetLogEventPhase::BEGIN,
+ base::TimeTicks::Now(), &callback);
+ NetLogEntry entry(&entry_data, NetLogCaptureMode::IncludeSocketBytes());
+ logger_->OnAddEntry(entry);
+ }
+ }
+
+ protected:
+ base::FilePath log_path_;
+ NetLog net_log_;
+ std::unique_ptr<base::Thread> file_thread_;
+ std::unique_ptr<BoundedFileNetLogObserver> logger_;
+
+ private:
+ base::ScopedTempDir temp_dir_;
+};
+
+TEST_F(BoundedFileNetLogObserverTest, ObserverDestroyedWithoutStopObserving) {
+ logger_->StartObserving(&net_log_, log_path_, nullptr, nullptr,
+ kLargeFileSize, kTotalNumFiles);
+
+ // Send dummy event
+ AddEntries(1, kDummyEventSize);
+
+ logger_.reset();
+ file_thread_.reset();
+
+ ASSERT_FALSE(base::PathExists(log_path_.AppendASCII("constants.json")));
+ ASSERT_FALSE(base::PathExists(log_path_.AppendASCII("end_netlog.json")));
+ for (int i = 0; i < kTotalNumFiles; i++) {
+ ASSERT_FALSE(base::PathExists(
+ log_path_.AppendASCII("event_file_" + std::to_string(i) + ".json")));
+ }
+}
+
+TEST_F(BoundedFileNetLogObserverTest, GeneratesValidJSONForNoEvents) {
+ TestClosure closure;
+
+ logger_->StartObserving(&net_log_, log_path_, nullptr, nullptr,
+ kLargeFileSize, kTotalNumFiles);
+ logger_->StopObserving(nullptr, closure.closure());
+
+ closure.WaitForResult();
+
+ std::string input;
+ AddAllFiles(&input);
+ ASSERT_FALSE(input.empty());
+
+ // Parse JSON
+ base::JSONReader reader;
+ std::unique_ptr<base::Value> root(reader.Read(input));
+ ASSERT_TRUE(root) << reader.GetErrorMessage();
+
+ // Check that there are no events
+ base::DictionaryValue* dict;
+ ASSERT_TRUE(root->GetAsDictionary(&dict));
+ base::ListValue* events;
+ ASSERT_TRUE(dict->GetList("events", &events));
+ ASSERT_EQ(0u, events->GetSize());
+
+ // Check that constants are printed
+ base::DictionaryValue* constants;
+ ASSERT_TRUE(dict->GetDictionary("constants", &constants));
+}
+
+// Checks that capture_mode_ defaults correctly when set_capture_mode is not
+// called, and that |capture_mode_| is changed when set_capture_mode is called.
+TEST_F(BoundedFileNetLogObserverTest, SetsCaptureMode) {
+ TestClosure default_closure;
+
+ logger_->StartObserving(&net_log_, log_path_, nullptr, nullptr,
+ kLargeFileSize, kTotalNumFiles);
+ EXPECT_EQ(NetLogCaptureMode::Default(), logger_->capture_mode());
+ logger_->StopObserving(nullptr, default_closure.closure());
+
+ default_closure.WaitForResult();
+
+ TestClosure new_capture_mode_closure;
+ logger_ = std::unique_ptr<BoundedFileNetLogObserver>(
+ new BoundedFileNetLogObserver(file_thread_->task_runner()));
+
+ logger_->set_capture_mode(NetLogCaptureMode::IncludeCookiesAndCredentials());
+ logger_->StartObserving(&net_log_, log_path_, nullptr, nullptr,
+ kLargeFileSize, kTotalNumFiles);
+ EXPECT_EQ(NetLogCaptureMode::IncludeCookiesAndCredentials(),
+ logger_->capture_mode());
+ logger_->StopObserving(nullptr, new_capture_mode_closure.closure());
+
+ new_capture_mode_closure.WaitForResult();
+
+ std::string input;
+ AddAllFiles(&input);
+ ASSERT_FALSE(input.empty());
+}
+
+TEST_F(BoundedFileNetLogObserverTest, GeneratesValidJSONWithOneEvent) {
+ TestClosure closure;
+
+ logger_->StartObserving(&net_log_, log_path_, nullptr, nullptr,
+ kLargeFileSize, kTotalNumFiles);
+
+ // Send dummy event.
+ AddEntries(1, kDummyEventSize);
+
+ logger_->StopObserving(nullptr, closure.closure());
+
+ closure.WaitForResult();
+
+ std::string input;
+ AddAllFiles(&input);
+ ASSERT_FALSE(input.empty());
+
+ // Parse input.
+ base::JSONReader reader;
+ std::unique_ptr<base::Value> root(reader.ReadToValue(input));
+
+ ASSERT_TRUE(root) << reader.GetErrorMessage();
+
+ // Check that there is 1 event written.
+ base::DictionaryValue* dict;
+ ASSERT_TRUE(root->GetAsDictionary(&dict));
+ base::ListValue* events;
+ ASSERT_TRUE(dict->GetList("events", &events));
+ ASSERT_EQ(1u, events->GetSize());
+}
+
+TEST_F(BoundedFileNetLogObserverTest, GeneratesValidJSONWithMultipleEvents) {
+ const int kTotalFileSize = 250000;
+ TestClosure closure;
+
+ logger_->StartObserving(&net_log_, log_path_, nullptr, nullptr,
+ kTotalFileSize, kTotalNumFiles);
+
+ AddEntries(2, kDummyEventSize);
+
+ logger_->StopObserving(nullptr, closure.closure());
+
+ closure.WaitForResult();
+
+ std::string input;
+ AddAllFiles(&input);
+ ASSERT_FALSE(input.empty());
+
+ base::JSONReader reader;
+ std::unique_ptr<base::Value> root(reader.ReadToValue(input));
+ ASSERT_TRUE(root) << reader.GetErrorMessage();
+
+ // Check that 2 events are written.
+ base::DictionaryValue* dict;
+ ASSERT_TRUE(root->GetAsDictionary(&dict));
+ base::ListValue* events;
+ ASSERT_TRUE(dict->GetList("events", &events));
+ ASSERT_EQ(2u, events->GetSize());
+}
+
+// Sends enough events to the observer to completely fill one file, but not
+// write any events to an additional file. Checks the file bounds.
+TEST_F(BoundedFileNetLogObserverTest, EqualToOneFile) {
+ // The total size of the events is equal to the size of one file.
+ // |kNumEvents| * |kEventSize| = |kTotalFileSize| / |kTotalNumEvents|
+ const int kTotalFileSize = 5000;
+ const int kNumEvents = 2;
+ const int kEventSize = 250;
+ TestClosure closure;
+
+ logger_->StartObserving(&net_log_, log_path_, nullptr, nullptr,
+ kTotalFileSize, kTotalNumFiles);
+
+ AddEntries(kNumEvents, kEventSize);
+ logger_->StopObserving(nullptr, closure.closure());
+
+ closure.WaitForResult();
+
+ std::string input;
+ AddAllFiles(&input);
+ ASSERT_FALSE(input.empty());
+
+ base::JSONReader reader;
+ std::unique_ptr<base::Value> root(reader.ReadToValue(input));
+ ASSERT_TRUE(root) << reader.GetErrorMessage();
+
+ // Check that the correct number of events were written.
+ base::DictionaryValue* dict;
+ ASSERT_TRUE(root->GetAsDictionary(&dict));
+ base::ListValue* events;
+ ASSERT_TRUE(dict->GetList("events", &events));
+ ASSERT_EQ(static_cast<size_t>(kNumEvents), events->GetSize());
+
+ // Check that the last event in array is the last event written.
+ base::Value* last_event = nullptr;
+ ASSERT_TRUE(events->Get(events->GetSize() - 1, &last_event));
+ last_event->GetAsDictionary(&dict);
+ base::Value* id_value = nullptr;
+ ASSERT_TRUE(dict->Get("source.id", &id_value));
+ int id;
+ ASSERT_TRUE(id_value->GetAsInteger(&id));
+ ASSERT_EQ(kNumEvents - 1, id);
+
+ // Check that events have been written to the first file.
+ base::ScopedFILE first_file(base::OpenFile(
+ log_path_.AppendASCII("event_file_" + std::to_string(0) + ".json"),
+ "rb"));
+ ASSERT_TRUE(first_file.get());
+ fseek(first_file.get(), 0, SEEK_END);
+ ASSERT_TRUE(ftell(first_file.get()));
+
+ // Check that all event files except the first do not exist.
+ for (int i = 1; i < kTotalNumFiles; i++) {
+ ASSERT_FALSE(base::PathExists(
+ log_path_.AppendASCII("event_file_" + std::to_string(i) + ".json")));
+ }
+}
+
+// Sends enough events to fill one file, and partially fill a second file.
+// Checks the file bounds and writing to a new file.
+TEST_F(BoundedFileNetLogObserverTest, OneEventOverOneFile) {
+ // The total size of the events is greater than the size of one file, and
+ // less than the size of two files. The total size of all events except one
+ // is equal to the size of one file, so the last event will be the only event
+ // in the second file.
+ // (|kNumEvents| - 1) * kEventSize = |kTotalFileSize| / |kTotalNumEvents|
+ const int kTotalFileSize = 6000;
+ const int kNumEvents = 4;
+ const int kEventSize = 200;
+ TestClosure closure;
+
+ logger_->StartObserving(&net_log_, log_path_, nullptr, nullptr,
+ kTotalFileSize, kTotalNumFiles);
+
+ AddEntries(kNumEvents, kEventSize);
+
+ logger_->StopObserving(nullptr, closure.closure());
+
+ closure.WaitForResult();
+
+ std::string input;
+ AddAllFiles(&input);
+ ASSERT_FALSE(input.empty());
+
+ base::JSONReader reader;
+ std::unique_ptr<base::Value> root(reader.ReadToValue(input));
+ ASSERT_TRUE(root) << reader.GetErrorMessage();
+
+ // Check that the correct number of events were written.
+ base::DictionaryValue* dict;
+ ASSERT_TRUE(root->GetAsDictionary(&dict));
+ base::ListValue* events;
+ ASSERT_TRUE(dict->GetList("events", &events));
+ ASSERT_EQ(static_cast<size_t>(kNumEvents), events->GetSize());
+
+ // Check that the last event in array is the last event written.
+ base::Value* last_event = nullptr;
+ ASSERT_TRUE(events->Get(events->GetSize() - 1, &last_event));
+ last_event->GetAsDictionary(&dict);
+ base::Value* id_value = nullptr;
+ ASSERT_TRUE(dict->Get("source.id", &id_value));
+ int id;
+ ASSERT_TRUE(id_value->GetAsInteger(&id));
+ ASSERT_EQ(kNumEvents - 1, id);
+
+ // Check that all event files except the first two do not exist.
+ for (int i = 2; i < kTotalNumFiles; i++) {
+ ASSERT_FALSE(base::PathExists(
+ log_path_.AppendASCII("event_file_" + std::to_string(i) + ".json")));
+ }
+}
+
+// Sends enough events to the observer to completely fill two files.
+TEST_F(BoundedFileNetLogObserverTest, EqualToTwoFiles) {
+ // The total size of the events is equal to the total size of two files.
+ // |kNumEvents| * |kEventSize| = 2 * |kTotalFileSize| / |kTotalNumEvents|
+ const int kTotalFileSize = 6000;
+ const int kNumEvents = 6;
+ const int kEventSize = 200;
+ TestClosure closure;
+
+ logger_->StartObserving(&net_log_, log_path_, nullptr, nullptr,
+ kTotalFileSize, kTotalNumFiles);
+
+ AddEntries(kNumEvents, kEventSize);
+
+ logger_->StopObserving(nullptr, closure.closure());
+
+ closure.WaitForResult();
+
+ std::string input;
+ AddAllFiles(&input);
+ ASSERT_FALSE(input.empty());
+
+ base::JSONReader reader;
+ std::unique_ptr<base::Value> root(reader.ReadToValue(input));
+ ASSERT_TRUE(root) << reader.GetErrorMessage();
+
+ // Check that the correct number of events were written.
+ base::DictionaryValue* dict;
+ ASSERT_TRUE(root->GetAsDictionary(&dict));
+ base::ListValue* events;
+ ASSERT_TRUE(dict->GetList("events", &events));
+ ASSERT_EQ(static_cast<size_t>(kNumEvents), events->GetSize());
+
+ // Check that the last event in array is the last event written.
+ base::Value* last_event = nullptr;
+ ASSERT_TRUE(events->Get(events->GetSize() - 1, &last_event));
+ last_event->GetAsDictionary(&dict);
+ base::Value* id_value = nullptr;
+ ASSERT_TRUE(dict->Get("source.id", &id_value));
+ int id;
+ ASSERT_TRUE(id_value->GetAsInteger(&id));
+ ASSERT_EQ(kNumEvents - 1, id);
+
+ // Check that the first two event files are full.
+ for (int i = 0; i < (kNumEvents * kEventSize) /
+ ((kTotalFileSize - 1) / kTotalNumFiles + 1);
+ i++) {
+ base::ScopedFILE file_to_test(base::OpenFile(
+ log_path_.AppendASCII("event_file_" + std::to_string(i) + ".json"),
+ "rb"));
+ ASSERT_TRUE(file_to_test.get());
+ fseek(file_to_test.get(), 0, SEEK_END);
+ ASSERT_GE(ftell(file_to_test.get()), kTotalFileSize / kTotalNumFiles);
+ }
+
+ // Check that all event files except the first two do not exist.
+ for (int i = 2; i < kTotalNumFiles; i++) {
+ ASSERT_FALSE(base::PathExists(
+ log_path_.AppendASCII("event_file_" + std::to_string(i) + ".json")));
+ }
+}
+
+// Sends exactly enough events to the observer to completely fill all files,
+// so that all events fit into the event files and no files need to be
+// overwritten.
+TEST_F(BoundedFileNetLogObserverTest, FillAllFilesNoOverwriting) {
+ // The total size of events is equal to the total size of all files.
+ // |kEventSize| * |kNumEvents| = |kTotalFileSize|
+ const int kTotalFileSize = 10000;
+ const int kEventSize = 200;
+ const int kFileSize = kTotalFileSize / kTotalNumFiles;
+ const int kNumEvents = kTotalNumFiles * ((kFileSize - 1) / kEventSize + 1);
+ TestClosure closure;
+
+ logger_->StartObserving(&net_log_, log_path_, nullptr, nullptr,
+ kTotalFileSize, kTotalNumFiles);
+
+ AddEntries(kNumEvents, kEventSize);
+
+ logger_->StopObserving(nullptr, closure.closure());
+
+ closure.WaitForResult();
+
+ std::string input;
+ AddAllFiles(&input);
+ ASSERT_FALSE(input.empty());
+
+ base::JSONReader reader;
+ std::unique_ptr<base::Value> root(reader.ReadToValue(input));
+ ASSERT_TRUE(root) << reader.GetErrorMessage();
+
+ // Check that the correct number of events were written.
+ base::DictionaryValue* dict;
+ ASSERT_TRUE(root->GetAsDictionary(&dict));
+ base::ListValue* events;
+ ASSERT_TRUE(dict->GetList("events", &events));
+ ASSERT_EQ(static_cast<size_t>(kNumEvents), events->GetSize());
+
+ // Check that the last event in array is the last event written.
+ base::Value* last_event = nullptr;
+ ASSERT_TRUE(events->Get(events->GetSize() - 1, &last_event));
+ last_event->GetAsDictionary(&dict);
+ base::Value* id_value = nullptr;
+ ASSERT_TRUE(dict->Get("source.id", &id_value));
+ int id;
+ ASSERT_TRUE(id_value->GetAsInteger(&id));
+ ASSERT_EQ(kNumEvents - 1, id);
+
+ // Check that all the event files are full.
+ for (int i = 0; i < kTotalNumFiles; i++) {
+ base::ScopedFILE file_to_test(base::OpenFile(
+ log_path_.AppendASCII("event_file_" + std::to_string(i) + ".json"),
+ "rb"));
+ ASSERT_TRUE(file_to_test.get());
+ fseek(file_to_test.get(), 0, SEEK_END);
+ ASSERT_GE(ftell(file_to_test.get()), kTotalFileSize / kTotalNumFiles);
+ }
+}
+
+// Sends more events to the observer than will fill the WriteQueue, forcing the
+// queue to drop an event. Checks that the queue drops the oldest event.
+TEST_F(BoundedFileNetLogObserverTest, DropOldEventsFromWriteQueue) {
+ // The total size of events is greater than the WriteQueue's memory limit, so
+ // the oldest event must be dropped from the queue and not written to any
+ // file.
+ // |kNumEvents| * |kEventSize| > |kTotalFileSize| * 2
+ const int kTotalFileSize = 1000;
+ const int kNumEvents = 11;
+ const int kEventSize = 200;
+ const int kFileSize = kTotalFileSize / kTotalNumFiles;
+ TestClosure closure;
+
+ logger_->StartObserving(&net_log_, log_path_, nullptr, nullptr,
+ kTotalFileSize, kTotalNumFiles);
+
+ AddEntries(kNumEvents, kEventSize);
+
+ logger_->StopObserving(nullptr, closure.closure());
+
+ closure.WaitForResult();
+
+ std::string input;
+ AddAllFiles(&input);
+ ASSERT_FALSE(input.empty());
+
+ base::JSONReader reader;
+ std::unique_ptr<base::Value> root(reader.ReadToValue(input));
+ ASSERT_TRUE(root) << reader.GetErrorMessage();
+
+ // Check that the correct number of events were written.
+ base::DictionaryValue* dict;
+ ASSERT_TRUE(root->GetAsDictionary(&dict));
+ base::ListValue* events;
+ ASSERT_TRUE(dict->GetList("events", &events));
+ ASSERT_EQ(
+ static_cast<size_t>(kTotalNumFiles * ((kFileSize - 1) / kEventSize + 1)),
+ events->GetSize());
+
+ // Check that the oldest event was dropped from the queue.
+ base::Value* event_to_check = nullptr;
+ ASSERT_TRUE(events->Get(0, &event_to_check));
+ event_to_check->GetAsDictionary(&dict);
+ base::Value* id_value = nullptr;
+ ASSERT_TRUE(dict->Get("source.id", &id_value));
+ int id;
+ ASSERT_TRUE(id_value->GetAsInteger(&id));
+ ASSERT_EQ(1, id);
+
+ // Check that the last event was written last.
+ event_to_check = nullptr;
+ ASSERT_TRUE(events->Get(events->GetSize() - 1, &event_to_check));
+ event_to_check->GetAsDictionary(&dict);
+ ASSERT_TRUE(dict->Get("source.id", &id_value));
+ ASSERT_TRUE(id_value->GetAsInteger(&id));
+ ASSERT_EQ(kNumEvents - 1, id);
+}
+
+// Sends twice as many events as will fill all files to the observer, so that
+// all of the event files will be filled twice, and every file will be
+// overwritten.
+TEST_F(BoundedFileNetLogObserverTest, OverwriteAllFiles) {
+ // The total size of the events is much greater than twice the number of
+ // events that can fit in the event files, to make sure that the extra events
+ // are written to a file, not just dropped from the queue.
+ // |kNumEvents| * |kEventSize| >= 2 * |kTotalFileSize|
+ const int kTotalFileSize = 6000;
+ const int kNumEvents = 60;
+ const int kEventSize = 200;
+ const int kFileSize = kTotalFileSize / kTotalNumFiles;
+ TestClosure closure;
+
+ logger_->StartObserving(&net_log_, log_path_, nullptr, nullptr,
+ kTotalFileSize, kTotalNumFiles);
+
+ AddEntries(kNumEvents, kEventSize);
+
+ logger_->StopObserving(nullptr, closure.closure());
+
+ closure.WaitForResult();
+
+ std::string input;
+ AddAllFiles(&input);
+ ASSERT_FALSE(input.empty());
+
+ base::JSONReader reader;
+ std::unique_ptr<base::Value> root(reader.ReadToValue(input));
+ ASSERT_TRUE(root) << reader.GetErrorMessage();
+
+ // Check that the correct number of events were written.
+ base::DictionaryValue* dict;
+ ASSERT_TRUE(root->GetAsDictionary(&dict));
+ base::ListValue* events;
+ ASSERT_TRUE(dict->GetList("events", &events));
+
+ // Check that the minimum number of events that should fit in event files
+ // have been written to all files.
+ int events_per_file = (kFileSize - 1) / kEventSize + 1;
+ int events_in_last_file = (kNumEvents - 1) % events_per_file + 1;
+
+ // Indicates the total number of events that should be written to all files.
+ int num_events_in_files =
+ (kTotalNumFiles - 1) * events_per_file + events_in_last_file;
+
+ // Tracks whether each of the events that should be written to all files
+ // actually appears in the |events| array. The bool at each index corresponds
+ // to the event with id = index + |kNumEvents| - |num_events_in_files|.
+ std::vector<bool> events_written(num_events_in_files, false);
+
+ base::Value* event = nullptr;
+ base::Value* id_value = nullptr;
+ int id;
+
+ // Iterate through each event in |events| and if it is supposed to appear in
+ // file, mark the corresponding bool in |events_written| as true.
+ for (size_t i = 0; i < events->GetSize(); i++) {
+ ASSERT_TRUE(events->Get(i, &event));
+ event->GetAsDictionary(&dict);
+ ASSERT_TRUE(dict->Get("source.id", &id_value));
+ ASSERT_TRUE(id_value->GetAsInteger(&id));
+ ASSERT_LT(id, kNumEvents);
+ if (id >= kNumEvents - num_events_in_files) {
+ events_written[id - (kNumEvents - num_events_in_files)] = true;
+ }
+ }
+
+ // Check that all events that are supposed to be written to all files
+ // appeared in the |events| array.
+ ASSERT_TRUE(std::all_of(std::begin(events_written), std::end(events_written),
+ [](bool j) { return j; }));
+
+ // Check that there are events written to all files.
+ for (int i = 0; i < kTotalNumFiles; i++) {
+ base::ScopedFILE file_to_test(base::OpenFile(
+ log_path_.AppendASCII("event_file_" + std::to_string(i) + ".json"),
+ "rb"));
+ ASSERT_TRUE(file_to_test.get());
+ fseek(file_to_test.get(), 0, SEEK_END);
+ ASSERT_GE(ftell(file_to_test.get()), kEventSize);
+ }
+}
+
+// Sends enough events to the observer to fill all event files, plus overwrite
+// some files, without overwriting all of them. Checks that the FileWriter
+// overwrites the file with the oldest events.
+TEST_F(BoundedFileNetLogObserverTest, PartiallyOverwriteFiles) {
+ // The number of events sent to the observer is greater than the number of
+ // events that can fit into the event files, but the events can fit in less
+ // than twice the number of event files, so not every file will need to be
+ // overwritten.
+ // |kTotalFileSize| < |kNumEvents| * |kEventSize|
+ // |kNumEvents| * |kEventSize| <= (2 * |kTotalNumFiles| - 1) * |kFileSize|
+ const int kTotalFileSize = 6000;
+ const int kNumEvents = 50;
+ const int kEventSize = 200;
+ const int kFileSize = kTotalFileSize / kTotalNumFiles;
+ TestClosure closure;
+
+ logger_->StartObserving(&net_log_, log_path_, nullptr, nullptr,
+ kTotalFileSize, kTotalNumFiles);
+
+ AddEntries(kNumEvents, kEventSize);
+
+ logger_->StopObserving(nullptr, closure.closure());
+
+ closure.WaitForResult();
+
+ std::string input;
+ AddAllFiles(&input);
+ ASSERT_FALSE(input.empty());
+
+ base::JSONReader reader;
+ std::unique_ptr<base::Value> root(reader.ReadToValue(input));
+ ASSERT_TRUE(root) << reader.GetErrorMessage();
+
+ base::DictionaryValue* dict;
+ ASSERT_TRUE(root->GetAsDictionary(&dict));
+ base::ListValue* events;
+ ASSERT_TRUE(dict->GetList("events", &events));
+
+ // Check that the minimum number of events that should fit in event files
+ // have been written to a file.
+ int events_per_file = (kFileSize - 1) / kEventSize + 1;
+ int events_in_last_file = kNumEvents % events_per_file;
+ if (!events_in_last_file)
+ events_in_last_file = events_per_file;
+ int num_events_in_files =
+ (kTotalNumFiles - 1) * events_per_file + events_in_last_file;
+ std::vector<bool> events_written(num_events_in_files, false);
+ base::Value* event = nullptr;
+ base::Value* id_value = nullptr;
+ int id;
+ for (size_t i = 0; i < events->GetSize(); i++) {
+ ASSERT_TRUE(events->Get(i, &event));
+ event->GetAsDictionary(&dict);
+ ASSERT_TRUE(dict->Get("source.id", &id_value));
+ ASSERT_TRUE(id_value->GetAsInteger(&id));
+ ASSERT_LT(id, kNumEvents);
+ if (id >= kNumEvents - num_events_in_files) {
+ events_written[id - (kNumEvents - num_events_in_files)] = true;
+ }
+ }
+ ASSERT_TRUE(std::all_of(std::begin(events_written), std::end(events_written),
+ [](bool j) { return j; }));
+
+ // Check that there are events written to all files.
+ for (int i = 0; i < kTotalNumFiles; i++) {
+ base::ScopedFILE file_to_test(base::OpenFile(
+ log_path_.AppendASCII("event_file_" + std::to_string(i) + ".json"),
+ "rb"));
+ ASSERT_TRUE(file_to_test.get());
+ fseek(file_to_test.get(), 0, SEEK_END);
+ ASSERT_GE(ftell(file_to_test.get()), kEventSize);
+ }
+}
+
+TEST_F(BoundedFileNetLogObserverTest, CustomConstants) {
+ TestClosure closure;
+
+ const char kConstantString[] = "awesome constant";
+ std::unique_ptr<base::Value> constants(
+ new base::StringValue(kConstantString));
+
+ logger_->StartObserving(&net_log_, log_path_, constants.get(), nullptr,
+ kLargeFileSize, kTotalNumFiles);
+
+ logger_->StopObserving(nullptr, closure.closure());
+
+ closure.WaitForResult();
+
+ std::string input;
+ AddAllFiles(&input);
+ ASSERT_FALSE(input.empty());
+
+ base::JSONReader reader;
+ std::unique_ptr<base::Value> root(reader.ReadToValue(input));
+ ASSERT_TRUE(root) << reader.GetErrorMessage();
+
+ // Check that custom constant was correctly printed.
+ base::DictionaryValue* dict;
+ ASSERT_TRUE(root->GetAsDictionary(&dict));
+ std::string constants_string;
+ ASSERT_TRUE(dict->GetString("constants", &constants_string));
+ ASSERT_EQ(kConstantString, constants_string);
+}
+
+TEST_F(BoundedFileNetLogObserverTest, GeneratesValidJSONWithContext) {
+ TestClosure closure;
+
+ logger_->StartObserving(&net_log_, log_path_, nullptr, nullptr,
+ kLargeFileSize, kTotalNumFiles);
+
+ // Create unique context.
+ TestURLRequestContext context(true);
+ context.set_net_log(&net_log_);
+ const int kDummyParam = 75;
+ std::unique_ptr<HttpNetworkSession::Params> params(
+ new HttpNetworkSession::Params);
+ params->quic_idle_connection_timeout_seconds = kDummyParam;
+ context.set_http_network_session_params(std::move(params));
+ context.Init();
+
+ logger_->StopObserving(&context, closure.closure());
+
+ closure.WaitForResult();
+
+ std::string input;
+ AddAllFiles(&input);
+ ASSERT_FALSE(input.empty());
+
+ base::JSONReader reader;
+ std::unique_ptr<base::Value> root(reader.ReadToValue(input));
+ ASSERT_TRUE(root) << reader.GetErrorMessage();
+
+ // Check that no events were written.
+ base::DictionaryValue* dict;
+ ASSERT_TRUE(root->GetAsDictionary(&dict));
+ base::ListValue* events;
+ ASSERT_TRUE(dict->GetList("events", &events));
+ ASSERT_EQ(0u, events->GetSize());
+
+ // Make sure additional information is present and validate it.
+ base::DictionaryValue* tab_info;
+ base::DictionaryValue* quic_info;
+ ASSERT_TRUE(dict->GetDictionary("tabInfo", &tab_info));
+ ASSERT_TRUE(tab_info->GetDictionary("quicInfo", &quic_info));
+ base::Value* timeout_value = nullptr;
+ int timeout;
+ ASSERT_TRUE(
+ quic_info->Get("idle_connection_timeout_seconds", &timeout_value));
+ ASSERT_TRUE(timeout_value->GetAsInteger(&timeout));
+ ASSERT_EQ(timeout, kDummyParam);
+}
+
+TEST_F(BoundedFileNetLogObserverTest,
+ GeneratesValidJSONWithContextWithActiveRequest) {
+ TestClosure closure;
+
+ // Create context, start a request.
+ TestURLRequestContext context(true);
+ context.set_net_log(&net_log_);
+ context.Init();
+ TestDelegate delegate;
+ delegate.set_quit_on_complete(false);
+
+ // URL doesn't matter. Requests can't fail synchronously.
+ std::unique_ptr<URLRequest> request(
+ context.CreateRequest(GURL("blah:blah"), IDLE, &delegate));
+ request->Start();
+
+ logger_->StartObserving(&net_log_, log_path_, nullptr, &context,
+ kLargeFileSize, kTotalNumFiles);
+
+ logger_->StopObserving(&context, closure.closure());
+
+ closure.WaitForResult();
+
+ std::string input;
+ AddAllFiles(&input);
+ ASSERT_FALSE(input.empty());
+
+ base::JSONReader reader;
+ std::unique_ptr<base::Value> root(reader.ReadToValue(input));
+ ASSERT_TRUE(root) << reader.GetErrorMessage();
+
+ // Check that 1 event was written
+ base::DictionaryValue* dict;
+ ASSERT_TRUE(root->GetAsDictionary(&dict));
+ base::ListValue* events;
+ ASSERT_TRUE(dict->GetList("events", &events));
+ ASSERT_EQ(1u, events->GetSize());
+
+ // Make sure additional information is present, but don't validate it.
+ base::DictionaryValue* tab_info;
+ ASSERT_TRUE(dict->GetDictionary("tabInfo", &tab_info));
+}
+
+} // namespace
+
+} // namespace net
diff --git a/chromium/net/log/net_log.cc b/chromium/net/log/net_log.cc
index b038519651a..cec37e18f0b 100644
--- a/chromium/net/log/net_log.cc
+++ b/chromium/net/log/net_log.cc
@@ -7,44 +7,15 @@
#include <utility>
#include "base/bind.h"
-#include "base/debug/alias.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
#include "base/values.h"
-#include "net/base/net_errors.h"
namespace net {
namespace {
-// Returns parameters for logging data transferred events. At a minimum includes
-// the number of bytes transferred. If the capture mode allows logging byte
-// contents and |byte_count| > 0, then will include the actual bytes. The
-// bytes are hex-encoded, since base::StringValue only supports UTF-8.
-std::unique_ptr<base::Value> BytesTransferredCallback(
- int byte_count,
- const char* bytes,
- NetLogCaptureMode capture_mode) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetInteger("byte_count", byte_count);
- if (capture_mode.include_socket_bytes() && byte_count > 0)
- dict->SetString("hex_encoded_bytes", base::HexEncode(bytes, byte_count));
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> SourceEventParametersCallback(
- const NetLog::Source source,
- NetLogCaptureMode /* capture_mode */) {
- if (!source.IsValid())
- return std::unique_ptr<base::Value>();
- std::unique_ptr<base::DictionaryValue> event_params(
- new base::DictionaryValue());
- source.AddToEventParameters(event_params.get());
- return std::move(event_params);
-}
-
std::unique_ptr<base::Value> NetLogBoolCallback(
const char* name,
bool value,
@@ -107,107 +78,6 @@ std::unique_ptr<base::Value> NetLogString16Callback(
} // namespace
-// LoadTimingInfo requires this be 0.
-const uint32_t NetLog::Source::kInvalidId = 0;
-
-NetLog::Source::Source() : type(SOURCE_NONE), id(kInvalidId) {
-}
-
-NetLog::Source::Source(SourceType type, uint32_t id) : type(type), id(id) {}
-
-bool NetLog::Source::IsValid() const {
- return id != kInvalidId;
-}
-
-void NetLog::Source::AddToEventParameters(
- base::DictionaryValue* event_params) const {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetInteger("type", static_cast<int>(type));
- dict->SetInteger("id", static_cast<int>(id));
- event_params->Set("source_dependency", std::move(dict));
-}
-
-NetLog::ParametersCallback NetLog::Source::ToEventParametersCallback() const {
- return base::Bind(&SourceEventParametersCallback, *this);
-}
-
-// static
-bool NetLog::Source::FromEventParameters(base::Value* event_params,
- Source* source) {
- base::DictionaryValue* dict = NULL;
- base::DictionaryValue* source_dict = NULL;
- int source_id = -1;
- int source_type = NetLog::SOURCE_COUNT;
- if (!event_params || !event_params->GetAsDictionary(&dict) ||
- !dict->GetDictionary("source_dependency", &source_dict) ||
- !source_dict->GetInteger("id", &source_id) ||
- !source_dict->GetInteger("type", &source_type)) {
- *source = Source();
- return false;
- }
-
- DCHECK_GE(source_id, 0);
- DCHECK_LT(source_type, NetLog::SOURCE_COUNT);
- *source = Source(static_cast<SourceType>(source_type), source_id);
- return true;
-}
-
-std::unique_ptr<base::Value> NetLog::Entry::ToValue() const {
- std::unique_ptr<base::DictionaryValue> entry_dict(
- new base::DictionaryValue());
-
- entry_dict->SetString("time", TickCountToString(data_->time));
-
- // Set the entry source.
- std::unique_ptr<base::DictionaryValue> source_dict(
- new base::DictionaryValue());
- source_dict->SetInteger("id", data_->source.id);
- source_dict->SetInteger("type", static_cast<int>(data_->source.type));
- entry_dict->Set("source", std::move(source_dict));
-
- // Set the event info.
- entry_dict->SetInteger("type", static_cast<int>(data_->type));
- entry_dict->SetInteger("phase", static_cast<int>(data_->phase));
-
- // Set the event-specific parameters.
- if (data_->parameters_callback) {
- std::unique_ptr<base::Value> value(
- data_->parameters_callback->Run(capture_mode_));
- if (value)
- entry_dict->Set("params", std::move(value));
- }
-
- return std::move(entry_dict);
-}
-
-std::unique_ptr<base::Value> NetLog::Entry::ParametersToValue() const {
- if (data_->parameters_callback)
- return data_->parameters_callback->Run(capture_mode_);
- return nullptr;
-}
-
-NetLog::EntryData::EntryData(EventType type,
- Source source,
- EventPhase phase,
- base::TimeTicks time,
- const ParametersCallback* parameters_callback)
- : type(type),
- source(source),
- phase(phase),
- time(time),
- parameters_callback(parameters_callback) {
-}
-
-NetLog::EntryData::~EntryData() {
-}
-
-NetLog::Entry::Entry(const EntryData* data, NetLogCaptureMode capture_mode)
- : data_(data), capture_mode_(capture_mode) {
-}
-
-NetLog::Entry::~Entry() {
-}
-
NetLog::ThreadSafeObserver::ThreadSafeObserver() : net_log_(NULL) {
}
@@ -227,8 +97,9 @@ NetLog* NetLog::ThreadSafeObserver::net_log() const {
return net_log_;
}
-void NetLog::ThreadSafeObserver::OnAddEntryData(const EntryData& entry_data) {
- OnAddEntry(Entry(&entry_data, capture_mode()));
+void NetLog::ThreadSafeObserver::OnAddEntryData(
+ const NetLogEntryData& entry_data) {
+ OnAddEntry(NetLogEntry(&entry_data, capture_mode()));
}
NetLog::NetLog() : last_id_(0), is_capturing_(0) {
@@ -237,16 +108,16 @@ NetLog::NetLog() : last_id_(0), is_capturing_(0) {
NetLog::~NetLog() {
}
-void NetLog::AddGlobalEntry(EventType type) {
- AddEntry(type, Source(NetLog::SOURCE_NONE, NextID()), NetLog::PHASE_NONE,
- NULL);
+void NetLog::AddGlobalEntry(NetLogEventType type) {
+ AddEntry(type, NetLogSource(NetLogSourceType::NONE, NextID()),
+ NetLogEventPhase::NONE, NULL);
}
void NetLog::AddGlobalEntry(
- EventType type,
- const NetLog::ParametersCallback& parameters_callback) {
- AddEntry(type, Source(NetLog::SOURCE_NONE, NextID()), NetLog::PHASE_NONE,
- &parameters_callback);
+ NetLogEventType type,
+ const NetLogParametersCallback& parameters_callback) {
+ AddEntry(type, NetLogSource(NetLogSourceType::NONE, NextID()),
+ NetLogEventPhase::NONE, &parameters_callback);
}
uint32_t NetLog::NextID() {
@@ -301,10 +172,10 @@ std::string NetLog::TickCountToString(const base::TimeTicks& time) {
}
// static
-const char* NetLog::EventTypeToString(EventType event) {
+const char* NetLog::EventTypeToString(NetLogEventType event) {
switch (event) {
-#define EVENT_TYPE(label) \
- case TYPE_##label: \
+#define EVENT_TYPE(label) \
+ case NetLogEventType::label: \
return #label;
#include "net/log/net_log_event_type_list.h"
#undef EVENT_TYPE
@@ -317,17 +188,17 @@ const char* NetLog::EventTypeToString(EventType event) {
// static
base::Value* NetLog::GetEventTypesAsValue() {
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- for (int i = 0; i < EVENT_COUNT; ++i) {
- dict->SetInteger(EventTypeToString(static_cast<EventType>(i)), i);
+ for (int i = 0; i < static_cast<int>(NetLogEventType::COUNT); ++i) {
+ dict->SetInteger(EventTypeToString(static_cast<NetLogEventType>(i)), i);
}
return dict.release();
}
// static
-const char* NetLog::SourceTypeToString(SourceType source) {
+const char* NetLog::SourceTypeToString(NetLogSourceType source) {
switch (source) {
-#define SOURCE_TYPE(label) \
- case SOURCE_##label: \
+#define SOURCE_TYPE(label) \
+ case NetLogSourceType::label: \
return #label;
#include "net/log/net_log_source_type_list.h"
#undef SOURCE_TYPE
@@ -340,20 +211,20 @@ const char* NetLog::SourceTypeToString(SourceType source) {
// static
base::Value* NetLog::GetSourceTypesAsValue() {
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- for (int i = 0; i < SOURCE_COUNT; ++i) {
- dict->SetInteger(SourceTypeToString(static_cast<SourceType>(i)), i);
+ for (int i = 0; i < static_cast<int>(NetLogSourceType::COUNT); ++i) {
+ dict->SetInteger(SourceTypeToString(static_cast<NetLogSourceType>(i)), i);
}
return dict.release();
}
// static
-const char* NetLog::EventPhaseToString(EventPhase phase) {
+const char* NetLog::EventPhaseToString(NetLogEventPhase phase) {
switch (phase) {
- case PHASE_BEGIN:
+ case NetLogEventPhase::BEGIN:
return "PHASE_BEGIN";
- case PHASE_END:
+ case NetLogEventPhase::END:
return "PHASE_END";
- case PHASE_NONE:
+ case NetLogEventPhase::NONE:
return "PHASE_NONE";
}
NOTREACHED();
@@ -361,158 +232,54 @@ const char* NetLog::EventPhaseToString(EventPhase phase) {
}
// static
-NetLog::ParametersCallback NetLog::BoolCallback(const char* name, bool value) {
+NetLogParametersCallback NetLog::BoolCallback(const char* name, bool value) {
return base::Bind(&NetLogBoolCallback, name, value);
}
// static
-NetLog::ParametersCallback NetLog::IntCallback(const char* name, int value) {
+NetLogParametersCallback NetLog::IntCallback(const char* name, int value) {
return base::Bind(&NetLogIntCallback, name, value);
}
// static
-NetLog::ParametersCallback NetLog::Int64Callback(const char* name,
- int64_t value) {
+NetLogParametersCallback NetLog::Int64Callback(const char* name,
+ int64_t value) {
return base::Bind(&NetLogInt64Callback, name, value);
}
// static
-NetLog::ParametersCallback NetLog::StringCallback(const char* name,
- const std::string* value) {
+NetLogParametersCallback NetLog::StringCallback(const char* name,
+ const std::string* value) {
DCHECK(value);
return base::Bind(&NetLogStringCallback, name, value);
}
// static
-NetLog::ParametersCallback NetLog::StringCallback(const char* name,
- const char* value) {
+NetLogParametersCallback NetLog::StringCallback(const char* name,
+ const char* value) {
DCHECK(value);
return base::Bind(&NetLogCharStringCallback, name, value);
}
// static
-NetLog::ParametersCallback NetLog::StringCallback(const char* name,
- const base::string16* value) {
+NetLogParametersCallback NetLog::StringCallback(const char* name,
+ const base::string16* value) {
DCHECK(value);
return base::Bind(&NetLogString16Callback, name, value);
}
-void NetLog::AddEntry(EventType type,
- const Source& source,
- EventPhase phase,
- const NetLog::ParametersCallback* parameters_callback) {
+void NetLog::AddEntry(NetLogEventType type,
+ const NetLogSource& source,
+ NetLogEventPhase phase,
+ const NetLogParametersCallback* parameters_callback) {
if (!IsCapturing())
return;
- EntryData entry_data(type, source, phase, base::TimeTicks::Now(),
- parameters_callback);
+ NetLogEntryData entry_data(type, source, phase, base::TimeTicks::Now(),
+ parameters_callback);
// Notify all of the log observers.
base::AutoLock lock(lock_);
FOR_EACH_OBSERVER(ThreadSafeObserver, observers_, OnAddEntryData(entry_data));
}
-BoundNetLog::~BoundNetLog() {
- liveness_ = DEAD;
-}
-
-void BoundNetLog::AddEntry(NetLog::EventType type,
- NetLog::EventPhase phase) const {
- CrashIfInvalid();
-
- if (!net_log_)
- return;
- net_log_->AddEntry(type, source_, phase, NULL);
-}
-
-void BoundNetLog::AddEntry(
- NetLog::EventType type,
- NetLog::EventPhase phase,
- const NetLog::ParametersCallback& get_parameters) const {
- CrashIfInvalid();
-
- if (!net_log_)
- return;
- net_log_->AddEntry(type, source_, phase, &get_parameters);
-}
-
-void BoundNetLog::AddEvent(NetLog::EventType type) const {
- AddEntry(type, NetLog::PHASE_NONE);
-}
-
-void BoundNetLog::AddEvent(
- NetLog::EventType type,
- const NetLog::ParametersCallback& get_parameters) const {
- AddEntry(type, NetLog::PHASE_NONE, get_parameters);
-}
-
-void BoundNetLog::BeginEvent(NetLog::EventType type) const {
- AddEntry(type, NetLog::PHASE_BEGIN);
-}
-
-void BoundNetLog::BeginEvent(
- NetLog::EventType type,
- const NetLog::ParametersCallback& get_parameters) const {
- AddEntry(type, NetLog::PHASE_BEGIN, get_parameters);
-}
-
-void BoundNetLog::EndEvent(NetLog::EventType type) const {
- AddEntry(type, NetLog::PHASE_END);
-}
-
-void BoundNetLog::EndEvent(
- NetLog::EventType type,
- const NetLog::ParametersCallback& get_parameters) const {
- AddEntry(type, NetLog::PHASE_END, get_parameters);
-}
-
-void BoundNetLog::AddEventWithNetErrorCode(NetLog::EventType event_type,
- int net_error) const {
- DCHECK_NE(ERR_IO_PENDING, net_error);
- if (net_error >= 0) {
- AddEvent(event_type);
- } else {
- AddEvent(event_type, NetLog::IntCallback("net_error", net_error));
- }
-}
-
-void BoundNetLog::EndEventWithNetErrorCode(NetLog::EventType event_type,
- int net_error) const {
- DCHECK_NE(ERR_IO_PENDING, net_error);
- if (net_error >= 0) {
- EndEvent(event_type);
- } else {
- EndEvent(event_type, NetLog::IntCallback("net_error", net_error));
- }
-}
-
-void BoundNetLog::AddByteTransferEvent(NetLog::EventType event_type,
- int byte_count,
- const char* bytes) const {
- AddEvent(event_type, base::Bind(BytesTransferredCallback, byte_count, bytes));
-}
-
-bool BoundNetLog::IsCapturing() const {
- CrashIfInvalid();
- return net_log_ && net_log_->IsCapturing();
-}
-
-// static
-BoundNetLog BoundNetLog::Make(NetLog* net_log, NetLog::SourceType source_type) {
- if (!net_log)
- return BoundNetLog();
-
- NetLog::Source source(source_type, net_log->NextID());
- return BoundNetLog(source, net_log);
-}
-
-void BoundNetLog::CrashIfInvalid() const {
- Liveness liveness = liveness_;
-
- if (liveness == ALIVE)
- return;
-
- base::debug::Alias(&liveness);
- CHECK_EQ(ALIVE, liveness);
-}
-
} // namespace net
diff --git a/chromium/net/log/net_log.h b/chromium/net/log/net_log.h
index aeb845a9a6c..486e6b6fd70 100644
--- a/chromium/net/log/net_log.h
+++ b/chromium/net/log/net_log.h
@@ -7,11 +7,9 @@
#include <stdint.h>
-#include <memory>
#include <string>
#include "base/atomicops.h"
-#include "base/callback_forward.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/observer_list.h"
@@ -21,6 +19,11 @@
#include "build/build_config.h"
#include "net/base/net_export.h"
#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_entry.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_parameters_callback.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
namespace base {
class DictionaryValue;
@@ -35,7 +38,7 @@ namespace net {
// SpdySession).
//
// To avoid needing to pass in the "source ID" to the logging functions, NetLog
-// is usually accessed through a BoundNetLog, which will always pass in a
+// is usually accessed through a NetLogWithSource, which will always pass in a
// specific source ID.
//
// All methods are thread safe, with the exception that no NetLog or
@@ -46,110 +49,6 @@ namespace net {
// https://sites.google.com/a/chromium.org/dev/developers/design-documents/network-stack/netlog
class NET_EXPORT NetLog {
public:
- enum EventType {
-#define EVENT_TYPE(label) TYPE_##label,
-#include "net/log/net_log_event_type_list.h"
-#undef EVENT_TYPE
- EVENT_COUNT
- };
-
- // The 'phase' of an event trace (whether it marks the beginning or end
- // of an event.).
- enum EventPhase {
- PHASE_NONE,
- PHASE_BEGIN,
- PHASE_END,
- };
-
- // The "source" identifies the entity that generated the log message.
- enum SourceType {
-#define SOURCE_TYPE(label) SOURCE_##label,
-#include "net/log/net_log_source_type_list.h"
-#undef SOURCE_TYPE
- SOURCE_COUNT
- };
-
- // A callback that returns a Value representation of the parameters
- // associated with an event. If called, it will be called synchronously,
- // so it need not have owning references. May be called more than once, or
- // not at all. May return NULL.
- typedef base::Callback<std::unique_ptr<base::Value>(NetLogCaptureMode)>
- ParametersCallback;
-
- // Identifies the entity that generated this log. The |id| field should
- // uniquely identify the source, and is used by log observers to infer
- // message groupings. Can use NetLog::NextID() to create unique IDs.
- struct NET_EXPORT Source {
- static const uint32_t kInvalidId;
-
- Source();
- Source(SourceType type, uint32_t id);
- bool IsValid() const;
-
- // Adds the source to a DictionaryValue containing event parameters,
- // using the name "source_dependency".
- void AddToEventParameters(base::DictionaryValue* event_params) const;
-
- // Returns a callback that returns a dictionary with a single entry
- // named "source_dependency" that describes |this|.
- ParametersCallback ToEventParametersCallback() const;
-
- // Attempts to extract a Source from a set of event parameters. Returns
- // true and writes the result to |source| on success. Returns false and
- // makes |source| an invalid source on failure.
- // TODO(mmenke): Long term, we want to remove this.
- static bool FromEventParameters(base::Value* event_params, Source* source);
-
- SourceType type;
- uint32_t id;
- };
-
- struct NET_EXPORT EntryData {
- EntryData(EventType type,
- Source source,
- EventPhase phase,
- base::TimeTicks time,
- const ParametersCallback* parameters_callback);
- ~EntryData();
-
- const EventType type;
- const Source source;
- const EventPhase phase;
- const base::TimeTicks time;
- const ParametersCallback* const parameters_callback;
- };
-
- // An Entry pre-binds EntryData to a capture mode, so observers will observe
- // the output of ToValue() and ParametersToValue() at their log capture mode
- // rather than the current maximum.
- class NET_EXPORT Entry {
- public:
- Entry(const EntryData* data, NetLogCaptureMode capture_mode);
- ~Entry();
-
- EventType type() const { return data_->type; }
- Source source() const { return data_->source; }
- EventPhase phase() const { return data_->phase; }
-
- // Serializes the specified event to a Value. The Value also includes the
- // current time. Takes in a time to allow back-dating entries.
- std::unique_ptr<base::Value> ToValue() const;
-
- // Returns the parameters as a Value. Returns NULL if there are no
- // parameters.
- std::unique_ptr<base::Value> ParametersToValue() const;
-
- private:
- const EntryData* const data_;
-
- // Log capture mode when the event occurred.
- const NetLogCaptureMode capture_mode_;
-
- // It is not safe to copy this class, since |parameters_callback_| may
- // include pointers that become stale immediately after the event is added,
- // even if the code were modified to keep its own copy of the callback.
- DISALLOW_COPY_AND_ASSIGN(Entry);
- };
// An observer that is notified of entries added to the NetLog. The
// "ThreadSafe" prefix of the name emphasizes that this observer may be
@@ -189,7 +88,7 @@ class NET_EXPORT NetLog {
// * It is illegal for an observer to call back into the NetLog, or the
// observer itself, as this can result in deadlock or violating
// expectations of non re-entrancy into ThreadSafeObserver.
- virtual void OnAddEntry(const Entry& entry) = 0;
+ virtual void OnAddEntry(const NetLogEntry& entry) = 0;
protected:
virtual ~ThreadSafeObserver();
@@ -197,7 +96,7 @@ class NET_EXPORT NetLog {
private:
friend class NetLog;
- void OnAddEntryData(const EntryData& entry_data);
+ void OnAddEntryData(const NetLogEntryData& entry_data);
// Both of these values are only modified by the NetLog.
NetLogCaptureMode capture_mode_;
@@ -210,9 +109,9 @@ class NET_EXPORT NetLog {
virtual ~NetLog();
// Emits a global event to the log stream, with its own unique source ID.
- void AddGlobalEntry(EventType type);
- void AddGlobalEntry(EventType type,
- const NetLog::ParametersCallback& parameters_callback);
+ void AddGlobalEntry(NetLogEventType type);
+ void AddGlobalEntry(NetLogEventType type,
+ const NetLogParametersCallback& parameters_callback);
// Returns a unique ID which can be used as a source ID. All returned IDs
// will be unique and greater than 0.
@@ -253,54 +152,57 @@ class NET_EXPORT NetLog {
static std::string TickCountToString(const base::TimeTicks& time);
// Returns a C-String symbolic name for |event_type|.
- static const char* EventTypeToString(EventType event_type);
+ static const char* EventTypeToString(NetLogEventType event_type);
// Returns a dictionary that maps event type symbolic names to their enum
// values. Caller takes ownership of the returned Value.
static base::Value* GetEventTypesAsValue();
// Returns a C-String symbolic name for |source_type|.
- static const char* SourceTypeToString(SourceType source_type);
+ static const char* SourceTypeToString(NetLogSourceType source_type);
// Returns a dictionary that maps source type symbolic names to their enum
// values. Caller takes ownership of the returned Value.
static base::Value* GetSourceTypesAsValue();
// Returns a C-String symbolic name for |event_phase|.
- static const char* EventPhaseToString(EventPhase event_phase);
+ static const char* EventPhaseToString(NetLogEventPhase event_phase);
- // Creates a ParametersCallback that encapsulates a single bool.
+ // Creates a NetLogParametersCallback that encapsulates a single bool.
// Warning: |name| must remain valid for the life of the callback.
- static ParametersCallback BoolCallback(const char* name, bool value);
+ static NetLogParametersCallback BoolCallback(const char* name, bool value);
// Warning: |name| must remain valid for the life of the callback.
- static ParametersCallback IntCallback(const char* name, int value);
+ static NetLogParametersCallback IntCallback(const char* name, int value);
- // Creates a ParametersCallback that encapsulates a single int64_t. The
+ // Creates a NetLogParametersCallback that encapsulates a single int64_t. The
// callback will return the value as a StringValue, since IntegerValues
// only support 32-bit values.
// Warning: |name| must remain valid for the life of the callback.
- static ParametersCallback Int64Callback(const char* name, int64_t value);
+ static NetLogParametersCallback Int64Callback(const char* name,
+ int64_t value);
- // Creates a ParametersCallback that encapsulates a single UTF8 string. Takes
+ // Creates a NetLogParametersCallback that encapsulates a single UTF8 string.
+ // Takes
// |value| as a pointer to avoid copying, and emphasize it must be valid for
// the life of the callback. |value| may not be NULL.
// Warning: |name| and |value| must remain valid for the life of the callback.
- static ParametersCallback StringCallback(const char* name,
- const std::string* value);
- static ParametersCallback StringCallback(const char* name, const char* value);
+ static NetLogParametersCallback StringCallback(const char* name,
+ const std::string* value);
+ static NetLogParametersCallback StringCallback(const char* name,
+ const char* value);
// Same as above, but takes in a UTF16 string.
- static ParametersCallback StringCallback(const char* name,
- const base::string16* value);
+ static NetLogParametersCallback StringCallback(const char* name,
+ const base::string16* value);
private:
- friend class BoundNetLog;
+ friend class NetLogWithSource;
- void AddEntry(EventType type,
- const Source& source,
- EventPhase phase,
- const NetLog::ParametersCallback* parameters_callback);
+ void AddEntry(NetLogEventType type,
+ const NetLogSource& source,
+ NetLogEventPhase phase,
+ const NetLogParametersCallback* parameters_callback);
// Called whenever an observer is added or removed, to update
// |has_observers_|. Must have acquired |lock_| prior to calling.
@@ -323,82 +225,6 @@ class NET_EXPORT NetLog {
DISALLOW_COPY_AND_ASSIGN(NetLog);
};
-// Helper that binds a Source to a NetLog, and exposes convenience methods to
-// output log messages without needing to pass in the source.
-class NET_EXPORT BoundNetLog {
- public:
- BoundNetLog() : net_log_(NULL) {}
- ~BoundNetLog();
-
- // Add a log entry to the NetLog for the bound source.
- void AddEntry(NetLog::EventType type, NetLog::EventPhase phase) const;
- void AddEntry(NetLog::EventType type,
- NetLog::EventPhase phase,
- const NetLog::ParametersCallback& get_parameters) const;
-
- // Convenience methods that call AddEntry with a fixed "capture phase"
- // (begin, end, or none).
- void BeginEvent(NetLog::EventType type) const;
- void BeginEvent(NetLog::EventType type,
- const NetLog::ParametersCallback& get_parameters) const;
-
- void EndEvent(NetLog::EventType type) const;
- void EndEvent(NetLog::EventType type,
- const NetLog::ParametersCallback& get_parameters) const;
-
- void AddEvent(NetLog::EventType type) const;
- void AddEvent(NetLog::EventType type,
- const NetLog::ParametersCallback& get_parameters) const;
-
- // Just like AddEvent, except |net_error| is a net error code. A parameter
- // called "net_error" with the indicated value will be recorded for the event.
- // |net_error| must be negative, and not ERR_IO_PENDING, as it's not a true
- // error.
- void AddEventWithNetErrorCode(NetLog::EventType event_type,
- int net_error) const;
-
- // Just like EndEvent, except |net_error| is a net error code. If it's
- // negative, a parameter called "net_error" with a value of |net_error| is
- // associated with the event. Otherwise, the end event has no parameters.
- // |net_error| must not be ERR_IO_PENDING, as it's not a true error.
- void EndEventWithNetErrorCode(NetLog::EventType event_type,
- int net_error) const;
-
- // Logs a byte transfer event to the NetLog. Determines whether to log the
- // received bytes or not based on the current logging level.
- void AddByteTransferEvent(NetLog::EventType event_type,
- int byte_count,
- const char* bytes) const;
-
- bool IsCapturing() const;
-
- // Helper to create a BoundNetLog given a NetLog and a SourceType. Takes care
- // of creating a unique source ID, and handles the case of NULL net_log.
- static BoundNetLog Make(NetLog* net_log, NetLog::SourceType source_type);
-
- const NetLog::Source& source() const { return source_; }
- NetLog* net_log() const { return net_log_; }
-
- private:
- // TODO(eroman): Temporary until crbug.com/467797 is solved.
- enum Liveness {
- ALIVE = 0xCA11AB13,
- DEAD = 0xDEADBEEF,
- };
-
- BoundNetLog(const NetLog::Source& source, NetLog* net_log)
- : source_(source), net_log_(net_log) {}
-
- // TODO(eroman): Temporary until crbug.com/467797 is solved.
- void CrashIfInvalid() const;
-
- NetLog::Source source_;
- NetLog* net_log_;
-
- // TODO(eroman): Temporary until crbug.com/467797 is solved.
- Liveness liveness_ = ALIVE;
-};
-
} // namespace net
#endif // NET_LOG_NET_LOG_H_
diff --git a/chromium/net/log/net_log_entry.cc b/chromium/net/log/net_log_entry.cc
new file mode 100644
index 00000000000..1258139f748
--- /dev/null
+++ b/chromium/net/log/net_log_entry.cc
@@ -0,0 +1,69 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/log/net_log_entry.h"
+
+#include <utility>
+
+#include "base/callback.h"
+#include "base/values.h"
+#include "net/log/net_log.h"
+
+namespace net {
+
+std::unique_ptr<base::Value> NetLogEntry::ToValue() const {
+ std::unique_ptr<base::DictionaryValue> entry_dict(
+ new base::DictionaryValue());
+
+ entry_dict->SetString("time", NetLog::TickCountToString(data_->time));
+
+ // Set the entry source.
+ std::unique_ptr<base::DictionaryValue> source_dict(
+ new base::DictionaryValue());
+ source_dict->SetInteger("id", data_->source.id);
+ source_dict->SetInteger("type", static_cast<int>(data_->source.type));
+ entry_dict->Set("source", std::move(source_dict));
+
+ // Set the event info.
+ entry_dict->SetInteger("type", static_cast<int>(data_->type));
+ entry_dict->SetInteger("phase", static_cast<int>(data_->phase));
+
+ // Set the event-specific parameters.
+ if (data_->parameters_callback) {
+ std::unique_ptr<base::Value> value(
+ data_->parameters_callback->Run(capture_mode_));
+ if (value)
+ entry_dict->Set("params", std::move(value));
+ }
+
+ return std::move(entry_dict);
+}
+
+std::unique_ptr<base::Value> NetLogEntry::ParametersToValue() const {
+ if (data_->parameters_callback)
+ return data_->parameters_callback->Run(capture_mode_);
+ return nullptr;
+}
+
+NetLogEntryData::NetLogEntryData(
+ NetLogEventType type,
+ NetLogSource source,
+ NetLogEventPhase phase,
+ base::TimeTicks time,
+ const NetLogParametersCallback* parameters_callback)
+ : type(type),
+ source(source),
+ phase(phase),
+ time(time),
+ parameters_callback(parameters_callback) {}
+
+NetLogEntryData::~NetLogEntryData() {}
+
+NetLogEntry::NetLogEntry(const NetLogEntryData* data,
+ NetLogCaptureMode capture_mode)
+ : data_(data), capture_mode_(capture_mode) {}
+
+NetLogEntry::~NetLogEntry() {}
+
+} // namespace net
diff --git a/chromium/net/log/net_log_entry.h b/chromium/net/log/net_log_entry.h
new file mode 100644
index 00000000000..4812704185b
--- /dev/null
+++ b/chromium/net/log/net_log_entry.h
@@ -0,0 +1,73 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_LOG_NET_LOG_ENTRY_H_
+#define NET_LOG_NET_LOG_ENTRY_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "net/base/net_export.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_parameters_callback.h"
+#include "net/log/net_log_source.h"
+
+namespace base {
+class Value;
+}
+
+namespace net {
+
+struct NET_EXPORT NetLogEntryData {
+ NetLogEntryData(NetLogEventType type,
+ NetLogSource source,
+ NetLogEventPhase phase,
+ base::TimeTicks time,
+ const NetLogParametersCallback* parameters_callback);
+ ~NetLogEntryData();
+
+ const NetLogEventType type;
+ const NetLogSource source;
+ const NetLogEventPhase phase;
+ const base::TimeTicks time;
+ const NetLogParametersCallback* const parameters_callback;
+};
+
+// A NetLogEntry pre-binds NetLogEntryData to a capture mode, so observers will
+// observe the output of ToValue() and ParametersToValue() at their log
+// capture mode rather than the current maximum.
+class NET_EXPORT NetLogEntry {
+ public:
+ NetLogEntry(const NetLogEntryData* data, NetLogCaptureMode capture_mode);
+ ~NetLogEntry();
+
+ NetLogEventType type() const { return data_->type; }
+ NetLogSource source() const { return data_->source; }
+ NetLogEventPhase phase() const { return data_->phase; }
+
+ // Serializes the specified event to a Value. The Value also includes the
+ // current time. Takes in a time to allow back-dating entries.
+ std::unique_ptr<base::Value> ToValue() const;
+
+ // Returns the parameters as a Value. Returns nullptr if there are no
+ // parameters.
+ std::unique_ptr<base::Value> ParametersToValue() const;
+
+ private:
+ const NetLogEntryData* const data_;
+
+ // Log capture mode when the event occurred.
+ const NetLogCaptureMode capture_mode_;
+
+ // It is not safe to copy this class, since |parameters_callback_| may
+ // include pointers that become stale immediately after the event is added,
+ // even if the code were modified to keep its own copy of the callback.
+ DISALLOW_COPY_AND_ASSIGN(NetLogEntry);
+};
+
+} // namespace net
+
+#endif // NET_LOG_NET_LOG_ENTRY_H_
diff --git a/chromium/net/log/net_log_event_type.h b/chromium/net/log/net_log_event_type.h
new file mode 100644
index 00000000000..d9d4bf60aba
--- /dev/null
+++ b/chromium/net/log/net_log_event_type.h
@@ -0,0 +1,27 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_LOG_NET_LOG_EVENT_TYPE_H_
+#define NET_LOG_NET_LOG_EVENT_TYPE_H_
+
+namespace net {
+
+enum class NetLogEventType {
+#define EVENT_TYPE(label) label,
+#include "net/log/net_log_event_type_list.h"
+#undef EVENT_TYPE
+ COUNT
+};
+
+// The 'phase' of an event trace (whether it marks the beginning or end
+// of an event.).
+enum class NetLogEventPhase {
+ NONE,
+ BEGIN,
+ END,
+};
+
+} // namespace net
+
+#endif // NET_LOG_NET_LOG_EVENT_TYPE_H_
diff --git a/chromium/net/log/net_log_event_type_list.h b/chromium/net/log/net_log_event_type_list.h
index 4ac7d8b1f1f..ec5cc418486 100644
--- a/chromium/net/log/net_log_event_type_list.h
+++ b/chromium/net/log/net_log_event_type_list.h
@@ -475,7 +475,7 @@ EVENT_TYPE(SSL_CLIENT_CERT_REQUESTED)
// "type": <type of the key>,
// "hash": <hash function used>,
// }
-EVENT_TYPE(SSL_PRIVATE_KEY_OPERATION)
+EVENT_TYPE(SSL_PRIVATE_KEY_OP)
// The start/end of getting a domain-bound certificate and private key.
//
@@ -797,7 +797,7 @@ EVENT_TYPE(BACKUP_CONNECT_JOB_CREATED)
// }
EVENT_TYPE(SOCKET_POOL_BOUND_TO_CONNECT_JOB)
-// Identifies the NetLog::Source() for the Socket assigned to the pending
+// Identifies the NetLogSource() for the Socket assigned to the pending
// request. The event parameters are:
// {
// "source_dependency": <Source identifier for the socket we acquired>,
@@ -1043,21 +1043,21 @@ EVENT_TYPE(HTTP_STREAM_REQUEST)
// }
EVENT_TYPE(HTTP_STREAM_JOB)
-// Identifies the NetLog::Source() for a Job started by the Request.
+// Identifies the NetLogSource() for a Job started by the Request.
// The event parameters are:
// {
// "source_dependency": <Source identifier for Job we started>,
// }
EVENT_TYPE(HTTP_STREAM_REQUEST_STARTED_JOB)
-// Identifies the NetLog::Source() for the Job that fulfilled the Request.
+// Identifies the NetLogSource() for the Job that fulfilled the Request.
// The event parameters are:
// {
// "source_dependency": <Source identifier for Job we acquired>,
// }
EVENT_TYPE(HTTP_STREAM_REQUEST_BOUND_TO_JOB)
-// Identifies the NetLog::Source() for the Request that the Job was attached to.
+// Identifies the NetLogSource() for the Request that the Job was attached to.
// The event parameters are:
// {
// "source_dependency": <Source identifier for the Request to which we were
@@ -1188,6 +1188,23 @@ EVENT_TYPE(HTTP_TRANSACTION_RESTART_AFTER_ERROR)
// }
EVENT_TYPE(BIDIRECTIONAL_STREAM_ALIVE)
+// Marks the ReadData call of a net::BidirectionalStream.
+// The following parameters are attached:
+// {
+// "rv": <The value in int that is returned to the caller>
+// }
+EVENT_TYPE(BIDIRECTIONAL_STREAM_READ_DATA)
+
+// Marks the SendData call of a net::BidirectionalStream.
+EVENT_TYPE(BIDIRECTIONAL_STREAM_SEND_DATA)
+
+// Marks the SendvData call of a net::BidirectionalStream.
+// The following parameters are attached:
+// {
+// "num_buffers": <The number of buffers passed to SendvData>
+// }
+EVENT_TYPE(BIDIRECTIONAL_STREAM_SENDV_DATA)
+
// Marks the beginning/end of buffers sent in a net::BidirectionalStream.
// The following parameters are attached:
// {
@@ -1261,34 +1278,6 @@ EVENT_TYPE(HTTP2_SESSION)
// }
EVENT_TYPE(HTTP2_SESSION_INITIALIZED)
-// This event is sent for a SPDY SYN_STREAM. Note that there is no SYN_STREAM
-// frame in HTTP/2.
-// The following parameters are attached:
-// {
-// "flags": <The control frame flags>,
-// "headers": <The list of header:value pairs>,
-// "fin": <True if this is the final data set by the peer on this stream>,
-// "unidirectional": <True if this stream is unidirectional>,
-// "priority": <The priority value of the stream>,
-// "stream_id": <The stream id>,
-// }
-EVENT_TYPE(HTTP2_SESSION_SYN_STREAM)
-
-// This event is sent for a SPDY SYN_STREAM pushed by the server, where a
-// net::URLRequest is already waiting for the stream. Note that there is no
-// SYN_STREAM frame in HTTP/2.
-// The following parameters are attached:
-// {
-// "flags": <The control frame flags>,
-// "headers": <The list of header:value pairs>,
-// "fin": <True if this is the final data set by the peer on this stream>,
-// "unidirectional": <True if this stream is unidirectional>,
-// "priority": <The priority value of the stream>,
-// "stream_id": <The stream id>,
-// "associated_stream": <The stream id>,
-// }
-EVENT_TYPE(HTTP2_SESSION_PUSHED_SYN_STREAM)
-
// This event is sent for sending an HTTP/2 HEADERS frame.
// The following parameters are attached:
// {
@@ -1302,7 +1291,7 @@ EVENT_TYPE(HTTP2_SESSION_PUSHED_SYN_STREAM)
// }
EVENT_TYPE(HTTP2_SESSION_SEND_HEADERS)
-// This event is sent for receiving an HTTP/2 (or SPDY) HEADERS frame.
+// This event is sent for receiving an HTTP/2 HEADERS frame.
// The following parameters are attached:
// {
// "flags": <The control frame flags>,
@@ -1311,24 +1300,14 @@ EVENT_TYPE(HTTP2_SESSION_SEND_HEADERS)
// }
EVENT_TYPE(HTTP2_SESSION_RECV_HEADERS)
-// This event is sent for a SPDY SYN_REPLY. Not that there is no SYN_REPLY
-// frame in HTTP/2.
-// The following parameters are attached:
-// {
-// "flags": <The control frame flags>,
-// "headers": <The list of header:value pairs>,
-// "id": <The stream id>,
-// }
-EVENT_TYPE(HTTP2_SESSION_SYN_REPLY)
-
-// On sending an HTTP/2 (or SPDY) SETTINGS frame.
+// On sending an HTTP/2 SETTINGS frame.
// The following parameters are attached:
// {
// "settings": <The list of setting id, flags and value>,
// }
EVENT_TYPE(HTTP2_SESSION_SEND_SETTINGS)
-// Receipt of an HTTP/2 (or SPDY) SETTINGS frame is received.
+// Receipt of an HTTP/2 SETTINGS frame.
// The following parameters are attached:
// {
// "host": <The host-port string>,
@@ -1337,7 +1316,7 @@ EVENT_TYPE(HTTP2_SESSION_SEND_SETTINGS)
// }
EVENT_TYPE(HTTP2_SESSION_RECV_SETTINGS)
-// Receipt of an individual HTTP/2 (or SPDY) setting.
+// Receipt of an individual HTTP/2 setting.
// The following parameters are attached:
// {
// "id": <The setting id>,
@@ -1346,7 +1325,7 @@ EVENT_TYPE(HTTP2_SESSION_RECV_SETTINGS)
// }
EVENT_TYPE(HTTP2_SESSION_RECV_SETTING)
-// The receipt of a RST_STREAM
+// The receipt of a RST_STREAM frame.
// The following parameters are attached:
// {
// "stream_id": <The stream ID for the window update>,
@@ -1363,7 +1342,7 @@ EVENT_TYPE(HTTP2_SESSION_RST_STREAM)
// }
EVENT_TYPE(HTTP2_SESSION_SEND_RST_STREAM)
-// Sending of an HTTP/2 (or SPDY) PING frame.
+// Sending of an HTTP/2 PING frame.
// The following parameters are attached:
// {
// "unique_id": <The unique id of the PING message>,
@@ -1371,7 +1350,7 @@ EVENT_TYPE(HTTP2_SESSION_SEND_RST_STREAM)
// }
EVENT_TYPE(HTTP2_SESSION_PING)
-// Receipt of an HTTP/2 (or SPDY) GOAWAY frame.
+// Receipt of an HTTP/2 GOAWAY frame.
// The following parameters are attached:
// {
// "last_accepted_stream_id": <Last stream id accepted by the server, duh>,
@@ -1381,15 +1360,14 @@ EVENT_TYPE(HTTP2_SESSION_PING)
// }
EVENT_TYPE(HTTP2_SESSION_GOAWAY)
-// Receipt of an HTTP/2 (or SPDY) WINDOW_UPDATE frame (which controls the send
-// window).
+// Receipt of an HTTP/2 WINDOW_UPDATE frame (which controls the send window).
// {
// "stream_id": <The stream ID for the window update>,
// "delta" : <The delta window size>,
// }
EVENT_TYPE(HTTP2_SESSION_RECEIVED_WINDOW_UPDATE_FRAME)
-// Sending of an HTTP/2 (or SPDY) WINDOW_UPDATE frame (which controls the
+// Sending of an HTTP/2 WINDOW_UPDATE frame (which controls the
// receive window).
// {
// "stream_id": <The stream ID for the window update>,
@@ -1427,7 +1405,7 @@ EVENT_TYPE(HTTP2_SESSION_SEND_DATA)
// }
EVENT_TYPE(HTTP2_SESSION_RECV_DATA)
-// This event is sent for receiving an HTTP/2 (or SPDY) PUSH_PROMISE frame.
+// This event is sent for receiving an HTTP/2 PUSH_PROMISE frame.
// The following parameters are attached:
// {
// "headers": <The list of header:value pairs>,
@@ -1489,8 +1467,8 @@ EVENT_TYPE(HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION_FROM_IP_POOL)
// }
EVENT_TYPE(HTTP2_SESSION_POOL_CREATED_NEW_SESSION)
-// This event indicates that a SSL socket has been upgraded to an HTTP/2 (or
-// SPDY) session.
+// This event indicates that a SSL socket has been upgraded to an HTTP/2
+// session.
// {
// "source_dependency": <The session id>,
// }
@@ -1506,7 +1484,7 @@ EVENT_TYPE(HTTP2_SESSION_POOL_REMOVE_SESSION)
// SpdyStream
// ------------------------------------------------------------------------
-// The begin and end of an HTTP/2 (or SPDY) STREAM.
+// The begin and end of an HTTP/2 STREAM.
EVENT_TYPE(HTTP2_STREAM)
// A stream is attached to a pushed stream.
@@ -1548,7 +1526,7 @@ EVENT_TYPE(HTTP2_STREAM_ERROR)
// ------------------------------------------------------------------------
EVENT_TYPE(HTTP2_PROXY_CLIENT_SESSION)
-// Identifies the HTTP/2 (or SPDY) session a source is using.
+// Identifies the HTTP/2 session a source is using.
// {
// "source_dependency": <Source identifier for the underlying session>,
// }
@@ -1906,7 +1884,7 @@ EVENT_TYPE(QUIC_HTTP_STREAM_PUSH_PROMISE_RENDEZVOUS)
// }
EVENT_TYPE(QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM)
-// Identifies the NetLog::Source() for the QuicSesssion that handled the stream.
+// Identifies the NetLogSource() for the QuicSesssion that handled the stream.
// The event parameters are:
// {
// "source_dependency": <Source identifier for session that was used>,
@@ -2484,6 +2462,12 @@ EVENT_TYPE(DOWNLOAD_URL_REQUEST)
// one of these events.
EVENT_TYPE(DOWNLOAD_ITEM_ACTIVE)
+// Recorded when the DownloadFile is created.
+// {
+// "source_dependency": <Source ID of DownloadFile>
+// }
+EVENT_TYPE(DOWNLOAD_FILE_CREATED)
+
// This event is created when a download item's danger type
// has been modified.
// {
@@ -2546,6 +2530,12 @@ EVENT_TYPE(DOWNLOAD_ITEM_CANCELED)
// DownloadFile events.
// ------------------------------------------------------------------------
+// A new download file was created.
+// {
+// "source_dependency": <Source ID of owning DownloadItem>
+// }
+EVENT_TYPE(DOWNLOAD_FILE_ACTIVE)
+
// This event is created when a download file is opened, and lasts until
// the file is closed.
// The BEGIN event has the following parameters:
@@ -2563,6 +2553,13 @@ EVENT_TYPE(DOWNLOAD_FILE_OPENED)
// }
EVENT_TYPE(DOWNLOAD_STREAM_DRAINED)
+// Created when a buffer is written to the download file. The END event has the
+// following paramters:
+// {
+// "bytes": <Count of bytes written>
+// }
+EVENT_TYPE(DOWNLOAD_FILE_WRITTEN)
+
// This event is created when a download file is renamed.
// {
// "old_filename": <Old filename>,
@@ -2570,10 +2567,6 @@ EVENT_TYPE(DOWNLOAD_STREAM_DRAINED)
// }
EVENT_TYPE(DOWNLOAD_FILE_RENAMED)
-// This event is created when a download file is closed. This event is allowed
-// to occur even if the file is not open.
-EVENT_TYPE(DOWNLOAD_FILE_CLOSED)
-
// This event is created when a download file is detached.
EVENT_TYPE(DOWNLOAD_FILE_DETACHED)
@@ -3026,3 +3019,41 @@ EVENT_TYPE(SAFE_BROWSING_CHECKING_URL)
// "resumed_redirect", "unchecked_redirect">
// }
EVENT_TYPE(SAFE_BROWSING_DEFERRED)
+
+// The start/end of a Safe Browsing ping being sent.
+//
+// The BEGIN phase contains the following parameters:
+// {
+// "url": <The URL the ping is going to, which identifies the type of ping
+// that is being sent (eg: ThreatReport, SafeBrowsingHit)>
+// "data": <The base64 encoding of the payload sent with the ping>
+//
+// The END phase contains the following parameters:
+// {
+// "status": <The integer status of the report transmission. Corresponds to
+// URLRequestStatus::Status>
+// "error": <The error code returned by the server, 0 indicating success>
+EVENT_TYPE(SAFE_BROWSING_PING)
+
+// Marks start of UploadDataStream that is logged on initialization.
+// The END phase contains the following parameters:
+// {
+// "net_error": <Result of the initialization step>,
+// "total_size": <Shows total content length>,
+// "is_chunked": <Shows whether data is chunked or not>
+// }
+EVENT_TYPE(UPLOAD_DATA_STREAM_INIT)
+
+// The start/end of UploadDataStream::Read method.
+//
+// The BEGIN phase contains the following information:
+// {
+// "current_position": <Shows current read position>,
+// }
+//
+// The END phase contains the following information:
+// {
+// "result": <Result of reading. Result > 0 is bytes read. Result == 0 means
+// the end of file. Result < 0 means an error.>
+// }
+EVENT_TYPE(UPLOAD_DATA_STREAM_READ)
diff --git a/chromium/net/log/net_log_parameters_callback.h b/chromium/net/log/net_log_parameters_callback.h
new file mode 100644
index 00000000000..e472a330edc
--- /dev/null
+++ b/chromium/net/log/net_log_parameters_callback.h
@@ -0,0 +1,28 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_LOG_NET_LOG_PARAMETERS_CALLBACK_H_
+#define NET_LOG_NET_LOG_PARAMETERS_CALLBACK_H_
+
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "net/log/net_log_capture_mode.h"
+
+namespace base {
+class Value;
+}
+
+namespace net {
+
+// A callback that returns a Value representation of the parameters
+// associated with an event. If called, it will be called synchronously,
+// so it need not have owning references. May be called more than once, or
+// not at all. May return nullptr.
+typedef base::Callback<std::unique_ptr<base::Value>(NetLogCaptureMode)>
+ NetLogParametersCallback;
+
+} // namespace net
+
+#endif // NET_LOG_NET_LOG_PARAMETERS_CALLBACK_H_
diff --git a/chromium/net/log/net_log_source.cc b/chromium/net/log/net_log_source.cc
new file mode 100644
index 00000000000..b8104b68c9a
--- /dev/null
+++ b/chromium/net/log/net_log_source.cc
@@ -0,0 +1,78 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/log/net_log_source.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/values.h"
+#include "net/log/net_log_capture_mode.h"
+
+namespace net {
+
+namespace {
+
+std::unique_ptr<base::Value> SourceEventParametersCallback(
+ const NetLogSource source,
+ NetLogCaptureMode /* capture_mode */) {
+ if (!source.IsValid())
+ return std::unique_ptr<base::Value>();
+ std::unique_ptr<base::DictionaryValue> event_params(
+ new base::DictionaryValue());
+ source.AddToEventParameters(event_params.get());
+ return std::move(event_params);
+}
+
+} // namespace
+
+// LoadTimingInfo requires this be 0.
+const uint32_t NetLogSource::kInvalidId = 0;
+
+NetLogSource::NetLogSource() : type(NetLogSourceType::NONE), id(kInvalidId) {}
+
+NetLogSource::NetLogSource(NetLogSourceType type, uint32_t id)
+ : type(type), id(id) {}
+
+bool NetLogSource::IsValid() const {
+ return id != kInvalidId;
+}
+
+void NetLogSource::AddToEventParameters(
+ base::DictionaryValue* event_params) const {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetInteger("type", static_cast<int>(type));
+ dict->SetInteger("id", static_cast<int>(id));
+ event_params->Set("source_dependency", std::move(dict));
+}
+
+NetLogParametersCallback NetLogSource::ToEventParametersCallback() const {
+ return base::Bind(&SourceEventParametersCallback, *this);
+}
+
+// static
+bool NetLogSource::FromEventParameters(base::Value* event_params,
+ NetLogSource* source) {
+ base::DictionaryValue* dict = NULL;
+ base::DictionaryValue* source_dict = NULL;
+ int source_id = -1;
+ int source_type = static_cast<int>(NetLogSourceType::COUNT);
+ if (!event_params || !event_params->GetAsDictionary(&dict) ||
+ !dict->GetDictionary("source_dependency", &source_dict) ||
+ !source_dict->GetInteger("id", &source_id) ||
+ !source_dict->GetInteger("type", &source_type)) {
+ *source = NetLogSource();
+ return false;
+ }
+
+ DCHECK_GE(source_id, 0);
+ DCHECK_LT(source_type, static_cast<int>(NetLogSourceType::COUNT));
+ *source = NetLogSource(static_cast<NetLogSourceType>(source_type), source_id);
+ return true;
+}
+
+} // namespace net
diff --git a/chromium/net/log/net_log_source.h b/chromium/net/log/net_log_source.h
new file mode 100644
index 00000000000..9ec89902657
--- /dev/null
+++ b/chromium/net/log/net_log_source.h
@@ -0,0 +1,52 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_LOG_NET_LOG_SOURCE_H_
+#define NET_LOG_NET_LOG_SOURCE_H_
+
+#include <stdint.h>
+
+#include "net/base/net_export.h"
+#include "net/log/net_log_parameters_callback.h"
+#include "net/log/net_log_source_type.h"
+
+namespace base {
+class DictionaryValue;
+class Value;
+}
+
+namespace net {
+
+// Identifies the entity that generated this log. The |id| field should
+// uniquely identify the source, and is used by log observers to infer
+// message groupings. Can use NetLog::NextID() to create unique IDs.
+struct NET_EXPORT NetLogSource {
+ static const uint32_t kInvalidId;
+
+ NetLogSource();
+ NetLogSource(NetLogSourceType type, uint32_t id);
+ bool IsValid() const;
+
+ // Adds the source to a DictionaryValue containing event parameters,
+ // using the name "source_dependency".
+ void AddToEventParameters(base::DictionaryValue* event_params) const;
+
+ // Returns a callback that returns a dictionary with a single entry
+ // named "source_dependency" that describes |this|.
+ NetLogParametersCallback ToEventParametersCallback() const;
+
+ // Attempts to extract a NetLogSource from a set of event parameters. Returns
+ // true and writes the result to |source| on success. Returns false and
+ // makes |source| an invalid source on failure.
+ // TODO(mmenke): Long term, we want to remove this.
+ static bool FromEventParameters(base::Value* event_params,
+ NetLogSource* source);
+
+ NetLogSourceType type;
+ uint32_t id;
+};
+
+} // namespace net
+
+#endif // NET_LOG_NET_LOG_SOURCE_H_
diff --git a/chromium/net/log/net_log_source_type.h b/chromium/net/log/net_log_source_type.h
new file mode 100644
index 00000000000..8fe57e5416d
--- /dev/null
+++ b/chromium/net/log/net_log_source_type.h
@@ -0,0 +1,20 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_LOG_NET_LOG_SOURCE_TYPE_H_
+#define NET_LOG_NET_LOG_SOURCE_TYPE_H_
+
+namespace net {
+
+// The "source" identifies the entity that generated the log message.
+enum class NetLogSourceType {
+#define SOURCE_TYPE(label) label,
+#include "net/log/net_log_source_type_list.h"
+#undef SOURCE_TYPE
+ COUNT
+};
+
+} // namespace net
+
+#endif // NET_LOG_NET_LOG_SOURCE_TYPE_H_
diff --git a/chromium/net/log/net_log_source_type_list.h b/chromium/net/log/net_log_source_type_list.h
index 777b571191c..1c729a68895 100644
--- a/chromium/net/log/net_log_source_type_list.h
+++ b/chromium/net/log/net_log_source_type_list.h
@@ -23,6 +23,7 @@ SOURCE_TYPE(EXPONENTIAL_BACKOFF_THROTTLING)
SOURCE_TYPE(UDP_SOCKET)
SOURCE_TYPE(CERT_VERIFIER_JOB)
SOURCE_TYPE(DOWNLOAD)
+SOURCE_TYPE(DOWNLOAD_FILE)
SOURCE_TYPE(FILESTREAM)
SOURCE_TYPE(DNS_PROBER)
SOURCE_TYPE(PROXY_CLIENT_SOCKET)
diff --git a/chromium/net/log/net_log_unittest.cc b/chromium/net/log/net_log_unittest.cc
index f8650a754e8..4e67951b266 100644
--- a/chromium/net/log/net_log_unittest.cc
+++ b/chromium/net/log/net_log_unittest.cc
@@ -13,6 +13,8 @@
#include "base/threading/simple_thread.h"
#include "base/values.h"
#include "net/base/net_errors.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source_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"
@@ -41,8 +43,8 @@ int CaptureModeToInt(NetLogCaptureMode capture_mode) {
std::unique_ptr<base::Value> CaptureModeToValue(
NetLogCaptureMode capture_mode) {
- return base::WrapUnique(
- new base::FundamentalValue(CaptureModeToInt(capture_mode)));
+ return base::MakeUnique<base::FundamentalValue>(
+ CaptureModeToInt(capture_mode));
}
std::unique_ptr<base::Value> NetCaptureModeCallback(
@@ -58,14 +60,14 @@ TEST(NetLogTest, Basic) {
net_log.GetEntries(&entries);
EXPECT_EQ(0u, entries.size());
- net_log.AddGlobalEntry(NetLog::TYPE_CANCELLED);
+ net_log.AddGlobalEntry(NetLogEventType::CANCELLED);
net_log.GetEntries(&entries);
ASSERT_EQ(1u, entries.size());
- EXPECT_EQ(NetLog::TYPE_CANCELLED, entries[0].type);
- EXPECT_EQ(NetLog::SOURCE_NONE, entries[0].source.type);
- EXPECT_NE(NetLog::Source::kInvalidId, entries[0].source.id);
- EXPECT_EQ(NetLog::PHASE_NONE, entries[0].phase);
+ EXPECT_EQ(NetLogEventType::CANCELLED, entries[0].type);
+ EXPECT_EQ(NetLogSourceType::NONE, entries[0].source.type);
+ EXPECT_NE(NetLogSource::kInvalidId, entries[0].source.id);
+ EXPECT_EQ(NetLogEventPhase::NONE, entries[0].phase);
EXPECT_GE(base::TimeTicks::Now(), entries[0].time);
EXPECT_FALSE(entries[0].params);
}
@@ -84,17 +86,17 @@ TEST(NetLogTest, CaptureModes) {
net_log.SetCaptureMode(mode);
EXPECT_EQ(mode, net_log.GetObserver()->capture_mode());
- net_log.AddGlobalEntry(NetLog::TYPE_SOCKET_ALIVE,
+ net_log.AddGlobalEntry(NetLogEventType::SOCKET_ALIVE,
base::Bind(NetCaptureModeCallback));
TestNetLogEntry::List entries;
net_log.GetEntries(&entries);
ASSERT_EQ(1u, entries.size());
- EXPECT_EQ(NetLog::TYPE_SOCKET_ALIVE, entries[0].type);
- EXPECT_EQ(NetLog::SOURCE_NONE, entries[0].source.type);
- EXPECT_NE(NetLog::Source::kInvalidId, entries[0].source.id);
- EXPECT_EQ(NetLog::PHASE_NONE, entries[0].phase);
+ EXPECT_EQ(NetLogEventType::SOCKET_ALIVE, entries[0].type);
+ EXPECT_EQ(NetLogSourceType::NONE, entries[0].source.type);
+ EXPECT_NE(NetLogSource::kInvalidId, entries[0].source.id);
+ EXPECT_EQ(NetLogEventPhase::NONE, entries[0].phase);
EXPECT_GE(base::TimeTicks::Now(), entries[0].time);
int logged_capture_mode;
@@ -115,7 +117,7 @@ class CountingObserver : public NetLog::ThreadSafeObserver {
net_log()->DeprecatedRemoveObserver(this);
}
- void OnAddEntry(const NetLog::Entry& entry) override { ++count_; }
+ void OnAddEntry(const NetLogEntry& entry) override { ++count_; }
int count() const { return count_; }
@@ -132,7 +134,7 @@ class LoggingObserver : public NetLog::ThreadSafeObserver {
net_log()->DeprecatedRemoveObserver(this);
}
- void OnAddEntry(const NetLog::Entry& entry) override {
+ void OnAddEntry(const NetLogEntry& entry) override {
std::unique_ptr<base::DictionaryValue> dict =
base::DictionaryValue::From(entry.ToValue());
ASSERT_TRUE(dict);
@@ -149,7 +151,7 @@ class LoggingObserver : public NetLog::ThreadSafeObserver {
};
void AddEvent(NetLog* net_log) {
- net_log->AddGlobalEntry(NetLog::TYPE_CANCELLED,
+ net_log->AddGlobalEntry(NetLogEventType::CANCELLED,
base::Bind(CaptureModeToValue));
}
diff --git a/chromium/net/log/net_log_util.cc b/chromium/net/log/net_log_util.cc
index 478fafc8867..da724e9f0bb 100644
--- a/chromium/net/log/net_log_util.cc
+++ b/chromium/net/log/net_log_util.cc
@@ -29,11 +29,16 @@
#include "net/http/http_server_properties.h"
#include "net/http/http_transaction_factory.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_entry.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_parameters_callback.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_retry_info.h"
#include "net/proxy/proxy_service.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_utils.h"
#include "net/socket/ssl_client_socket.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
@@ -246,9 +251,9 @@ std::unique_ptr<base::DictionaryValue> GetNetConstants() {
{
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetInteger("PHASE_BEGIN", NetLog::PHASE_BEGIN);
- dict->SetInteger("PHASE_END", NetLog::PHASE_END);
- dict->SetInteger("PHASE_NONE", NetLog::PHASE_NONE);
+ dict->SetInteger("PHASE_BEGIN", static_cast<int>(NetLogEventPhase::BEGIN));
+ dict->SetInteger("PHASE_END", static_cast<int>(NetLogEventPhase::END));
+ dict->SetInteger("PHASE_NONE", static_cast<int>(NetLogEventPhase::NONE));
constants_dict->Set("logEventPhase", std::move(dict));
}
@@ -431,12 +436,8 @@ NET_EXPORT std::unique_ptr<base::DictionaryValue> GetNetInfo(
if (info_sources & NET_INFO_SPDY_STATUS) {
base::DictionaryValue* status_dict = new base::DictionaryValue();
- status_dict->SetBoolean("enable_spdy31",
- http_network_session->params().enable_spdy31 &&
- HttpStreamFactory::spdy_enabled());
status_dict->SetBoolean("enable_http2",
- http_network_session->params().enable_http2 &&
- HttpStreamFactory::spdy_enabled());
+ http_network_session->params().enable_http2);
NextProtoVector alpn_protos;
http_network_session->GetAlpnProtos(&alpn_protos);
@@ -450,18 +451,6 @@ NET_EXPORT std::unique_ptr<base::DictionaryValue> GetNetInfo(
status_dict->SetString("alpn_protos", next_protos_string);
}
- NextProtoVector npn_protos;
- http_network_session->GetNpnProtos(&npn_protos);
- if (!npn_protos.empty()) {
- std::string next_protos_string;
- for (NextProto proto : npn_protos) {
- if (!next_protos_string.empty())
- next_protos_string.append(",");
- next_protos_string.append(SSLClientSocket::NextProtoToString(proto));
- }
- status_dict->SetString("npn_protos", next_protos_string);
- }
-
net_info_dict->Set(NetInfoSourceToString(NET_INFO_SPDY_STATUS),
status_dict);
}
@@ -534,15 +523,15 @@ NET_EXPORT void CreateNetLogEntriesForActiveObjects(
// Create fake events.
for (auto* request : requests) {
- NetLog::ParametersCallback callback =
+ NetLogParametersCallback callback =
base::Bind(&GetRequestStateAsValue, base::Unretained(request));
// Note that passing the hardcoded NetLogCaptureMode::Default() below is
// fine, since GetRequestStateAsValue() ignores the capture mode.
- NetLog::EntryData entry_data(
- NetLog::TYPE_REQUEST_ALIVE, request->net_log().source(),
- NetLog::PHASE_BEGIN, request->creation_time(), &callback);
- NetLog::Entry entry(&entry_data, NetLogCaptureMode::Default());
+ NetLogEntryData entry_data(
+ NetLogEventType::REQUEST_ALIVE, request->net_log().source(),
+ NetLogEventPhase::BEGIN, request->creation_time(), &callback);
+ NetLogEntry entry(&entry_data, NetLogCaptureMode::Default());
observer->OnAddEntry(entry);
}
}
diff --git a/chromium/net/log/net_log_util.h b/chromium/net/log/net_log_util.h
index e6a65e44469..829dcf569a5 100644
--- a/chromium/net/log/net_log_util.h
+++ b/chromium/net/log/net_log_util.h
@@ -45,7 +45,7 @@ NET_EXPORT std::unique_ptr<base::DictionaryValue> GetNetInfo(
int info_sources);
// Takes in a set of contexts and a NetLog::Observer, and passes in
-// NetLog::Entries to the observer for certain NetLog::Sources with pending
+// NetLog::Entries to the observer for certain NetLogSources with pending
// events. This allows requests that were ongoing when logging was started to
// have an initial event that has some information. This is particularly useful
// for hung requests. Note that these calls are not protected by the NetLog's
diff --git a/chromium/net/log/net_log_util_unittest.cc b/chromium/net/log/net_log_util_unittest.cc
index f21be4d8fe1..b885625a374 100644
--- a/chromium/net/log/net_log_util_unittest.cc
+++ b/chromium/net/log/net_log_util_unittest.cc
@@ -15,6 +15,8 @@
#include "net/base/test_completion_callback.h"
#include "net/http/http_cache.h"
#include "net/http/http_transaction.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
#include "net/log/test_net_log_entry.h"
#include "net/url_request/url_request_test_util.h"
diff --git a/chromium/net/log/net_log_with_source.cc b/chromium/net/log/net_log_with_source.cc
new file mode 100644
index 00000000000..8a03c8c66b8
--- /dev/null
+++ b/chromium/net/log/net_log_with_source.cc
@@ -0,0 +1,145 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/log/net_log_with_source.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/debug/alias.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+#include "net/base/net_errors.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+
+namespace net {
+
+namespace {
+
+// Returns parameters for logging data transferred events. At a minimum includes
+// the number of bytes transferred. If the capture mode allows logging byte
+// contents and |byte_count| > 0, then will include the actual bytes. The
+// bytes are hex-encoded, since base::StringValue only supports UTF-8.
+std::unique_ptr<base::Value> BytesTransferredCallback(
+ int byte_count,
+ const char* bytes,
+ NetLogCaptureMode capture_mode) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetInteger("byte_count", byte_count);
+ if (capture_mode.include_socket_bytes() && byte_count > 0)
+ dict->SetString("hex_encoded_bytes", base::HexEncode(bytes, byte_count));
+ return std::move(dict);
+}
+
+} // namespace
+
+NetLogWithSource::~NetLogWithSource() {
+ liveness_ = DEAD;
+}
+
+void NetLogWithSource::AddEntry(NetLogEventType type,
+ NetLogEventPhase phase) const {
+ CrashIfInvalid();
+
+ if (!net_log_)
+ return;
+ net_log_->AddEntry(type, source_, phase, NULL);
+}
+
+void NetLogWithSource::AddEntry(
+ NetLogEventType type,
+ NetLogEventPhase phase,
+ const NetLogParametersCallback& get_parameters) const {
+ CrashIfInvalid();
+
+ if (!net_log_)
+ return;
+ net_log_->AddEntry(type, source_, phase, &get_parameters);
+}
+
+void NetLogWithSource::AddEvent(NetLogEventType type) const {
+ AddEntry(type, NetLogEventPhase::NONE);
+}
+
+void NetLogWithSource::AddEvent(
+ NetLogEventType type,
+ const NetLogParametersCallback& get_parameters) const {
+ AddEntry(type, NetLogEventPhase::NONE, get_parameters);
+}
+
+void NetLogWithSource::BeginEvent(NetLogEventType type) const {
+ AddEntry(type, NetLogEventPhase::BEGIN);
+}
+
+void NetLogWithSource::BeginEvent(
+ NetLogEventType type,
+ const NetLogParametersCallback& get_parameters) const {
+ AddEntry(type, NetLogEventPhase::BEGIN, get_parameters);
+}
+
+void NetLogWithSource::EndEvent(NetLogEventType type) const {
+ AddEntry(type, NetLogEventPhase::END);
+}
+
+void NetLogWithSource::EndEvent(
+ NetLogEventType type,
+ const NetLogParametersCallback& get_parameters) const {
+ AddEntry(type, NetLogEventPhase::END, get_parameters);
+}
+
+void NetLogWithSource::AddEventWithNetErrorCode(NetLogEventType event_type,
+ int net_error) const {
+ DCHECK_NE(ERR_IO_PENDING, net_error);
+ if (net_error >= 0) {
+ AddEvent(event_type);
+ } else {
+ AddEvent(event_type, NetLog::IntCallback("net_error", net_error));
+ }
+}
+
+void NetLogWithSource::EndEventWithNetErrorCode(NetLogEventType event_type,
+ int net_error) const {
+ DCHECK_NE(ERR_IO_PENDING, net_error);
+ if (net_error >= 0) {
+ EndEvent(event_type);
+ } else {
+ EndEvent(event_type, NetLog::IntCallback("net_error", net_error));
+ }
+}
+
+void NetLogWithSource::AddByteTransferEvent(NetLogEventType event_type,
+ int byte_count,
+ const char* bytes) const {
+ AddEvent(event_type, base::Bind(BytesTransferredCallback, byte_count, bytes));
+}
+
+bool NetLogWithSource::IsCapturing() const {
+ CrashIfInvalid();
+ return net_log_ && net_log_->IsCapturing();
+}
+
+// static
+NetLogWithSource NetLogWithSource::Make(NetLog* net_log,
+ NetLogSourceType source_type) {
+ if (!net_log)
+ return NetLogWithSource();
+
+ NetLogSource source(source_type, net_log->NextID());
+ return NetLogWithSource(source, net_log);
+}
+
+void NetLogWithSource::CrashIfInvalid() const {
+ Liveness liveness = liveness_;
+
+ if (liveness == ALIVE)
+ return;
+
+ base::debug::Alias(&liveness);
+ CHECK_EQ(ALIVE, liveness);
+}
+
+} // namespace net
diff --git a/chromium/net/log/net_log_with_source.h b/chromium/net/log/net_log_with_source.h
new file mode 100644
index 00000000000..67d135363c7
--- /dev/null
+++ b/chromium/net/log/net_log_with_source.h
@@ -0,0 +1,97 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_LOG_NET_LOG_WITH_SOURCE_H_
+#define NET_LOG_NET_LOG_WITH_SOURCE_H_
+
+#include "net/base/net_export.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_parameters_callback.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
+
+namespace net {
+
+class NetLog;
+
+// Helper that binds a Source to a NetLog, and exposes convenience methods to
+// output log messages without needing to pass in the source.
+class NET_EXPORT NetLogWithSource {
+ public:
+ NetLogWithSource() : net_log_(NULL) {}
+ ~NetLogWithSource();
+
+ // Add a log entry to the NetLog for the bound source.
+ void AddEntry(NetLogEventType type, NetLogEventPhase phase) const;
+ void AddEntry(NetLogEventType type,
+ NetLogEventPhase phase,
+ const NetLogParametersCallback& get_parameters) const;
+
+ // Convenience methods that call AddEntry with a fixed "capture phase"
+ // (begin, end, or none).
+ void BeginEvent(NetLogEventType type) const;
+ void BeginEvent(NetLogEventType type,
+ const NetLogParametersCallback& get_parameters) const;
+
+ void EndEvent(NetLogEventType type) const;
+ void EndEvent(NetLogEventType type,
+ const NetLogParametersCallback& get_parameters) const;
+
+ void AddEvent(NetLogEventType type) const;
+ void AddEvent(NetLogEventType type,
+ const NetLogParametersCallback& get_parameters) const;
+
+ // Just like AddEvent, except |net_error| is a net error code. A parameter
+ // called "net_error" with the indicated value will be recorded for the event.
+ // |net_error| must be negative, and not ERR_IO_PENDING, as it's not a true
+ // error.
+ void AddEventWithNetErrorCode(NetLogEventType event_type,
+ int net_error) const;
+
+ // Just like EndEvent, except |net_error| is a net error code. If it's
+ // negative, a parameter called "net_error" with a value of |net_error| is
+ // associated with the event. Otherwise, the end event has no parameters.
+ // |net_error| must not be ERR_IO_PENDING, as it's not a true error.
+ void EndEventWithNetErrorCode(NetLogEventType event_type,
+ int net_error) const;
+
+ // Logs a byte transfer event to the NetLog. Determines whether to log the
+ // received bytes or not based on the current logging level.
+ void AddByteTransferEvent(NetLogEventType event_type,
+ int byte_count,
+ const char* bytes) const;
+
+ bool IsCapturing() const;
+
+ // Helper to create a NetLogWithSource given a NetLog and a NetLogSourceType.
+ // Takes care of creating a unique source ID, and handles
+ // the case of NULL net_log.
+ static NetLogWithSource Make(NetLog* net_log, NetLogSourceType source_type);
+
+ const NetLogSource& source() const { return source_; }
+ NetLog* net_log() const { return net_log_; }
+
+ private:
+ // TODO(eroman): Temporary until crbug.com/467797 is solved.
+ enum Liveness {
+ ALIVE = 0xCA11AB13,
+ DEAD = 0xDEADBEEF,
+ };
+
+ NetLogWithSource(const NetLogSource& source, NetLog* net_log)
+ : source_(source), net_log_(net_log) {}
+
+ // TODO(eroman): Temporary until crbug.com/467797 is solved.
+ void CrashIfInvalid() const;
+
+ NetLogSource source_;
+ NetLog* net_log_;
+
+ // TODO(eroman): Temporary until crbug.com/467797 is solved.
+ Liveness liveness_ = ALIVE;
+};
+
+} // namespace net
+
+#endif // NET_LOG_NET_LOG_WITH_SOURCE_H_
diff --git a/chromium/net/log/stitch_net_log_files.py b/chromium/net/log/stitch_net_log_files.py
new file mode 100755
index 00000000000..922d852038c
--- /dev/null
+++ b/chromium/net/log/stitch_net_log_files.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+'''
+This script stitches the NetLog files in a specified directory.
+
+The complete NetLog will be written to net-internals-log.json in the directory
+passed as argument to --path.
+'''
+
+import argparse, os
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--path', action='store',
+ help="Specifies the complete filepath of the directory where the log "
+ "files are located.")
+ # TODO(dconnol): Automatically pull all event files matching the format
+ # event_file_<num>.json and remove the num_files argument.
+ parser.add_argument('--num_files', action='store',
+ help="Specifies the number of event files (not including the constants "
+ "file or the end_netlog file) that need need to be stitched together. "
+ "The number of event files passed to the script must not be greater "
+ "than the number of event files in the directory.")
+ args = parser.parse_args()
+
+ num_files = int(args.num_files)
+ filepath = args.path
+ if filepath[-1:] != "/":
+ filepath += "/"
+
+ os.chdir(filepath)
+
+ with open("net-internals-log.json", "w") as stitched_file:
+ try:
+ file = open("constants.json")
+ with file:
+ for line in file:
+ stitched_file.write(line)
+ except IOError:
+ os.remove("net-internals-log.json")
+ print "File \"constants.json\" not found."
+ return
+
+ events_written = False;
+ for i in range(num_files):
+ try:
+ file = open("event_file_%d.json" % i)
+ with file:
+ if not events_written:
+ line = file.readline();
+ events_written = True
+ for next_line in file:
+ if next_line.strip() == "":
+ line += next_line
+ else:
+ stitched_file.write(line)
+ line = next_line
+ except IOError:
+ os.remove("net-internals-log.json")
+ print "File \"event_file_%d.json\" not found." % i
+ return
+ # Remove hanging comma from last event
+ # TODO(dconnol): Check if the last line is a valid JSON object. If not,
+ # do not write the line to file. This handles incomplete logs.
+ line = line.strip()
+ if line[-1:] == ",":
+ stitched_file.write(line[:-1])
+ elif line:
+ raise ValueError('Last event is not properly formed')
+
+ try:
+ file = open("end_netlog.json")
+ with file:
+ for line in file:
+ stitched_file.write(line)
+ except IOError:
+ os.remove("net-internals-log.json")
+ print "File \"end_netlog\" not found."
+ return
+
+ # Delete old NetLog files
+ for i in range (num_files):
+ os.remove("event_file_%d.json" % i)
+ os.remove("constants.json")
+ os.remove("end_netlog.json")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/chromium/net/log/test_net_log.cc b/chromium/net/log/test_net_log.cc
index 3287cf0a9d4..aacb6553d3e 100644
--- a/chromium/net/log/test_net_log.cc
+++ b/chromium/net/log/test_net_log.cc
@@ -7,6 +7,10 @@
#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "base/values.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_entry.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
namespace net {
@@ -24,7 +28,7 @@ class TestNetLog::Observer : public NetLog::ThreadSafeObserver {
}
// Fills |entry_list| with all entries in the log from the specified Source.
- void GetEntriesForSource(NetLog::Source source,
+ void GetEntriesForSource(NetLogSource source,
TestNetLogEntry::List* entry_list) const {
base::AutoLock lock(lock_);
entry_list->clear();
@@ -47,7 +51,7 @@ class TestNetLog::Observer : public NetLog::ThreadSafeObserver {
private:
// ThreadSafeObserver implementation:
- void OnAddEntry(const NetLog::Entry& entry) override {
+ void OnAddEntry(const NetLogEntry& entry) override {
// Using Dictionaries instead of Values makes checking values a little
// simpler.
std::unique_ptr<base::DictionaryValue> param_dict =
@@ -85,7 +89,7 @@ void TestNetLog::GetEntries(TestNetLogEntry::List* entry_list) const {
observer_->GetEntries(entry_list);
}
-void TestNetLog::GetEntriesForSource(NetLog::Source source,
+void TestNetLog::GetEntriesForSource(NetLogSource source,
TestNetLogEntry::List* entry_list) const {
observer_->GetEntriesForSource(source, entry_list);
}
@@ -103,7 +107,7 @@ NetLog::ThreadSafeObserver* TestNetLog::GetObserver() const {
}
BoundTestNetLog::BoundTestNetLog()
- : net_log_(BoundNetLog::Make(&test_net_log_, NetLog::SOURCE_NONE)) {
+ : net_log_(NetLogWithSource::Make(&test_net_log_, NetLogSourceType::NONE)) {
}
BoundTestNetLog::~BoundTestNetLog() {
@@ -114,7 +118,7 @@ void BoundTestNetLog::GetEntries(TestNetLogEntry::List* entry_list) const {
}
void BoundTestNetLog::GetEntriesForSource(
- NetLog::Source source,
+ NetLogSource source,
TestNetLogEntry::List* entry_list) const {
test_net_log_.GetEntriesForSource(source, entry_list);
}
diff --git a/chromium/net/log/test_net_log.h b/chromium/net/log/test_net_log.h
index 6190ab873c5..f7aff174e6b 100644
--- a/chromium/net/log/test_net_log.h
+++ b/chromium/net/log/test_net_log.h
@@ -13,10 +13,14 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log_entry.h"
namespace net {
+class NetLogCaptureMode;
+struct NetLogSource;
+
// TestNetLog is NetLog subclass which records all NetLog events that occur and
// their parameters. It is intended for testing only, and is part of the
// net_test_support project.
@@ -29,7 +33,7 @@ class TestNetLog : public NetLog {
// Below methods are forwarded to test_net_log_observer_.
void GetEntries(TestNetLogEntry::List* entry_list) const;
- void GetEntriesForSource(Source source,
+ void GetEntriesForSource(NetLogSource source,
TestNetLogEntry::List* entry_list) const;
size_t GetSize() const;
void Clear();
@@ -48,24 +52,24 @@ class TestNetLog : public NetLog {
DISALLOW_COPY_AND_ASSIGN(TestNetLog);
};
-// Helper class that exposes a similar API as BoundNetLog, but uses a
+// Helper class that exposes a similar API as NetLogWithSource, but uses a
// TestNetLog rather than the more generic NetLog.
//
-// A BoundTestNetLog can easily be converted to a BoundNetLog using the
+// A BoundTestNetLog can easily be converted to a NetLogWithSource using the
// bound() method.
class BoundTestNetLog {
public:
BoundTestNetLog();
~BoundTestNetLog();
- // The returned BoundNetLog is only valid while |this| is alive.
- BoundNetLog bound() const { return net_log_; }
+ // The returned NetLogWithSource is only valid while |this| is alive.
+ NetLogWithSource bound() const { return net_log_; }
// Fills |entry_list| with all entries in the log.
void GetEntries(TestNetLogEntry::List* entry_list) const;
// Fills |entry_list| with all entries in the log from the specified Source.
- void GetEntriesForSource(NetLog::Source source,
+ void GetEntriesForSource(NetLogSource source,
TestNetLogEntry::List* entry_list) const;
// Returns number of entries in the log.
@@ -78,7 +82,7 @@ class BoundTestNetLog {
private:
TestNetLog test_net_log_;
- const BoundNetLog net_log_;
+ const NetLogWithSource net_log_;
DISALLOW_COPY_AND_ASSIGN(BoundTestNetLog);
};
diff --git a/chromium/net/log/test_net_log_entry.cc b/chromium/net/log/test_net_log_entry.cc
index be226718272..e8beb757c31 100644
--- a/chromium/net/log/test_net_log_entry.cc
+++ b/chromium/net/log/test_net_log_entry.cc
@@ -12,10 +12,10 @@
namespace net {
-TestNetLogEntry::TestNetLogEntry(NetLog::EventType type,
+TestNetLogEntry::TestNetLogEntry(NetLogEventType type,
const base::TimeTicks& time,
- NetLog::Source source,
- NetLog::EventPhase phase,
+ NetLogSource source,
+ NetLogEventPhase phase,
std::unique_ptr<base::DictionaryValue> params)
: type(type),
time(time),
diff --git a/chromium/net/log/test_net_log_entry.h b/chromium/net/log/test_net_log_entry.h
index 0508ede818c..92c0c5e8736 100644
--- a/chromium/net/log/test_net_log_entry.h
+++ b/chromium/net/log/test_net_log_entry.h
@@ -10,7 +10,8 @@
#include <vector>
#include "base/time/time.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
namespace base {
class DictionaryValue;
@@ -19,7 +20,7 @@ class ListValue;
namespace net {
-// TestNetLogEntry is much like NetLog::Entry, except it has its own copy of all
+// TestNetLogEntry is much like NetLogEntry, except it has its own copy of all
// log data, so a list of entries can be gathered over the course of a test, and
// then inspected at the end. It is intended for testing only, and is part of
// the net_test_support project.
@@ -27,10 +28,10 @@ struct TestNetLogEntry {
// Ordered set of logged entries.
typedef std::vector<TestNetLogEntry> List;
- TestNetLogEntry(NetLog::EventType type,
+ TestNetLogEntry(NetLogEventType type,
const base::TimeTicks& time,
- NetLog::Source source,
- NetLog::EventPhase phase,
+ NetLogSource source,
+ NetLogEventPhase phase,
std::unique_ptr<base::DictionaryValue> params);
// Copy constructor needed to store in a std::vector because of the
// scoped_ptr.
@@ -58,10 +59,10 @@ struct TestNetLogEntry {
// parameters.
std::string GetParamsJson() const;
- NetLog::EventType type;
+ NetLogEventType type;
base::TimeTicks time;
- NetLog::Source source;
- NetLog::EventPhase phase;
+ NetLogSource source;
+ NetLogEventPhase phase;
std::unique_ptr<base::DictionaryValue> params;
};
diff --git a/chromium/net/log/test_net_log_util.cc b/chromium/net/log/test_net_log_util.cc
index 66e48217655..db79aeea33c 100644
--- a/chromium/net/log/test_net_log_util.cc
+++ b/chromium/net/log/test_net_log_util.cc
@@ -6,6 +6,8 @@
#include <cstddef>
+#include "net/log/net_log.h"
+
namespace net {
namespace {
@@ -30,8 +32,8 @@ size_t GetIndex(const TestNetLogEntry::List& entries, int offset) {
::testing::AssertionResult LogContainsEvent(
const TestNetLogEntry::List& entries,
int offset,
- NetLog::EventType expected_event,
- NetLog::EventPhase expected_phase) {
+ NetLogEventType expected_event,
+ NetLogEventPhase expected_phase) {
size_t index = GetIndex(entries, offset);
if (index >= entries.size())
return ::testing::AssertionFailure() << index << " is out of bounds.";
@@ -44,8 +46,8 @@ size_t GetIndex(const TestNetLogEntry::List& entries, int offset) {
}
if (expected_phase != entry.phase) {
return ::testing::AssertionFailure()
- << "Actual phase: " << entry.phase
- << ". Expected phase: " << expected_phase << ".";
+ << "Actual phase: " << static_cast<int>(entry.phase)
+ << ". Expected phase: " << static_cast<int>(expected_phase) << ".";
}
return ::testing::AssertionSuccess();
}
@@ -53,21 +55,23 @@ size_t GetIndex(const TestNetLogEntry::List& entries, int offset) {
::testing::AssertionResult LogContainsBeginEvent(
const TestNetLogEntry::List& entries,
int offset,
- NetLog::EventType expected_event) {
- return LogContainsEvent(entries, offset, expected_event, NetLog::PHASE_BEGIN);
+ NetLogEventType expected_event) {
+ return LogContainsEvent(entries, offset, expected_event,
+ NetLogEventPhase::BEGIN);
}
::testing::AssertionResult LogContainsEndEvent(
const TestNetLogEntry::List& entries,
int offset,
- NetLog::EventType expected_event) {
- return LogContainsEvent(entries, offset, expected_event, NetLog::PHASE_END);
+ NetLogEventType expected_event) {
+ return LogContainsEvent(entries, offset, expected_event,
+ NetLogEventPhase::END);
}
::testing::AssertionResult LogContainsEntryWithType(
const TestNetLogEntry::List& entries,
int offset,
- NetLog::EventType type) {
+ NetLogEventType type) {
size_t index = GetIndex(entries, offset);
if (index >= entries.size())
return ::testing::AssertionFailure() << index << " is out of bounds.";
@@ -80,7 +84,7 @@ size_t GetIndex(const TestNetLogEntry::List& entries, int offset) {
::testing::AssertionResult LogContainsEntryWithTypeAfter(
const TestNetLogEntry::List& entries,
int start_offset,
- NetLog::EventType type) {
+ NetLogEventType type) {
for (size_t i = GetIndex(entries, start_offset); i < entries.size(); ++i) {
const TestNetLogEntry& entry = entries[i];
if (entry.type == type)
@@ -91,8 +95,8 @@ size_t GetIndex(const TestNetLogEntry::List& entries, int offset) {
size_t ExpectLogContainsSomewhere(const TestNetLogEntry::List& entries,
size_t min_offset,
- NetLog::EventType expected_event,
- NetLog::EventPhase expected_phase) {
+ NetLogEventType expected_event,
+ NetLogEventPhase expected_phase) {
size_t min_index = GetIndex(entries, min_offset);
size_t i = 0;
for (; i < entries.size(); ++i) {
@@ -107,8 +111,8 @@ size_t ExpectLogContainsSomewhere(const TestNetLogEntry::List& entries,
size_t ExpectLogContainsSomewhereAfter(const TestNetLogEntry::List& entries,
size_t start_offset,
- NetLog::EventType expected_event,
- NetLog::EventPhase expected_phase) {
+ NetLogEventType expected_event,
+ NetLogEventPhase expected_phase) {
size_t i = GetIndex(entries, start_offset);
for (; i < entries.size(); ++i) {
const TestNetLogEntry& entry = entries[i];
diff --git a/chromium/net/log/test_net_log_util.h b/chromium/net/log/test_net_log_util.h
index 8734cea9530..4863c46ac44 100644
--- a/chromium/net/log/test_net_log_util.h
+++ b/chromium/net/log/test_net_log_util.h
@@ -7,7 +7,7 @@
#include <stddef.h>
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
#include "net/log/test_net_log_entry.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -20,27 +20,27 @@ namespace net {
::testing::AssertionResult LogContainsEvent(
const TestNetLogEntry::List& entries,
int offset,
- NetLog::EventType expected_event,
- NetLog::EventPhase expected_phase);
+ NetLogEventType expected_event,
+ NetLogEventPhase expected_phase);
// Just like LogContainsEvent, but always checks for an EventPhase of
// PHASE_BEGIN.
::testing::AssertionResult LogContainsBeginEvent(
const TestNetLogEntry::List& entries,
int offset,
- NetLog::EventType expected_event);
+ NetLogEventType expected_event);
// Just like LogContainsEvent, but always checks for an EventPhase of PHASE_END.
::testing::AssertionResult LogContainsEndEvent(
const TestNetLogEntry::List& entries,
int offset,
- NetLog::EventType expected_event);
+ NetLogEventType expected_event);
// Just like LogContainsEvent, but does not check phase.
::testing::AssertionResult LogContainsEntryWithType(
const TestNetLogEntry::List& entries,
int offset,
- NetLog::EventType type);
+ NetLogEventType type);
// Check if the log contains an entry of the given type at |start_offset| or
// after. It is not a failure if there's an earlier matching entry. Negative
@@ -48,23 +48,23 @@ namespace net {
::testing::AssertionResult LogContainsEntryWithTypeAfter(
const TestNetLogEntry::List& entries,
int start_offset,
- NetLog::EventType type);
+ NetLogEventType type);
// Check if the first entry with the specified values is at |start_offset| or
// after. It is a failure if there's an earlier matching entry. Negative
// offsets are relative to the end of the array.
size_t ExpectLogContainsSomewhere(const TestNetLogEntry::List& entries,
size_t min_offset,
- NetLog::EventType expected_event,
- NetLog::EventPhase expected_phase);
+ NetLogEventType expected_event,
+ NetLogEventPhase expected_phase);
// Check if the log contains an entry with the given values at |start_offset|
// or after. It is not a failure if there's an earlier matching entry.
// Negative offsets are relative to the end of the array.
size_t ExpectLogContainsSomewhereAfter(const TestNetLogEntry::List& entries,
size_t start_offset,
- NetLog::EventType expected_event,
- NetLog::EventPhase expected_phase);
+ NetLogEventType expected_event,
+ NetLogEventPhase expected_phase);
} // namespace net
diff --git a/chromium/net/log/trace_net_log_observer.cc b/chromium/net/log/trace_net_log_observer.cc
index 81d8d8aa027..4c7b7dcc605 100644
--- a/chromium/net/log/trace_net_log_observer.cc
+++ b/chromium/net/log/trace_net_log_observer.cc
@@ -14,7 +14,8 @@
#include "base/logging.h"
#include "base/trace_event/trace_event.h"
#include "base/values.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_entry.h"
+#include "net/log/net_log_event_type.h"
namespace net {
@@ -55,10 +56,10 @@ TraceNetLogObserver::~TraceNetLogObserver() {
DCHECK(!net_log());
}
-void TraceNetLogObserver::OnAddEntry(const NetLog::Entry& entry) {
+void TraceNetLogObserver::OnAddEntry(const NetLogEntry& entry) {
std::unique_ptr<base::Value> params(entry.ParametersToValue());
switch (entry.phase()) {
- case NetLog::PHASE_BEGIN:
+ case NetLogEventPhase::BEGIN:
TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(
kNetLogTracingCategory, NetLog::EventTypeToString(entry.type()),
entry.source().id, "source_type",
@@ -66,7 +67,7 @@ void TraceNetLogObserver::OnAddEntry(const NetLog::Entry& entry) {
std::unique_ptr<base::trace_event::ConvertableToTraceFormat>(
new TracedValue(std::move(params))));
break;
- case NetLog::PHASE_END:
+ case NetLogEventPhase::END:
TRACE_EVENT_NESTABLE_ASYNC_END2(
kNetLogTracingCategory, NetLog::EventTypeToString(entry.type()),
entry.source().id, "source_type",
@@ -74,7 +75,7 @@ void TraceNetLogObserver::OnAddEntry(const NetLog::Entry& entry) {
std::unique_ptr<base::trace_event::ConvertableToTraceFormat>(
new TracedValue(std::move(params))));
break;
- case NetLog::PHASE_NONE:
+ case NetLogEventPhase::NONE:
TRACE_EVENT_NESTABLE_ASYNC_INSTANT2(
kNetLogTracingCategory, NetLog::EventTypeToString(entry.type()),
entry.source().id, "source_type",
diff --git a/chromium/net/log/trace_net_log_observer.h b/chromium/net/log/trace_net_log_observer.h
index 08907f2e230..4c8b572c5f2 100644
--- a/chromium/net/log/trace_net_log_observer.h
+++ b/chromium/net/log/trace_net_log_observer.h
@@ -22,7 +22,7 @@ class NET_EXPORT TraceNetLogObserver
~TraceNetLogObserver() override;
// net::NetLog::ThreadSafeObserver implementation:
- void OnAddEntry(const NetLog::Entry& entry) override;
+ void OnAddEntry(const NetLogEntry& entry) override;
// Start to watch for TraceLog enable and disable events.
// This can't be called if already watching for events.
diff --git a/chromium/net/log/trace_net_log_observer_unittest.cc b/chromium/net/log/trace_net_log_observer_unittest.cc
index 1844067a38b..60c54ee0f9f 100644
--- a/chromium/net/log/trace_net_log_observer_unittest.cc
+++ b/chromium/net/log/trace_net_log_observer_unittest.cc
@@ -18,7 +18,10 @@
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_impl.h"
#include "base/values.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_parameters_callback.h"
+#include "net/log/net_log_source_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
#include "net/log/test_net_log_entry.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -150,7 +153,7 @@ class TraceNetLogObserverTest : public testing::Test {
TEST_F(TraceNetLogObserverTest, TracingNotEnabled) {
trace_net_log_observer()->WatchForTraceStart(net_log());
- net_log()->AddGlobalEntry(NetLog::TYPE_REQUEST_ALIVE);
+ net_log()->AddGlobalEntry(NetLogEventType::REQUEST_ALIVE);
EndTraceAndFlush();
trace_net_log_observer()->StopWatchForTraceStart();
@@ -165,11 +168,11 @@ TEST_F(TraceNetLogObserverTest, TraceEventCaptured) {
trace_net_log_observer()->WatchForTraceStart(net_log());
EnableTraceLog();
- BoundNetLog bound_net_log =
- BoundNetLog::Make(net_log(), net::NetLog::SOURCE_NONE);
- net_log()->AddGlobalEntry(NetLog::TYPE_CANCELLED);
- bound_net_log.BeginEvent(NetLog::TYPE_URL_REQUEST_START_JOB);
- bound_net_log.EndEvent(NetLog::TYPE_REQUEST_ALIVE);
+ NetLogWithSource net_log_with_source =
+ NetLogWithSource::Make(net_log(), net::NetLogSourceType::NONE);
+ net_log()->AddGlobalEntry(NetLogEventType::CANCELLED);
+ net_log_with_source.BeginEvent(NetLogEventType::URL_REQUEST_START_JOB);
+ net_log_with_source.EndEvent(NetLogEventType::REQUEST_ALIVE);
net_log()->GetEntries(&entries);
EXPECT_EQ(3u, entries.size());
@@ -190,7 +193,7 @@ TEST_F(TraceNetLogObserverTest, TraceEventCaptured) {
EXPECT_EQ(base::StringPrintf("0x%d", entries[0].source.id), actual_item1.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
actual_item1.phase);
- EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_CANCELLED),
+ EXPECT_EQ(NetLog::EventTypeToString(NetLogEventType::CANCELLED),
actual_item1.name);
EXPECT_EQ(NetLog::SourceTypeToString(entries[0].source.type),
actual_item1.source_type);
@@ -199,7 +202,7 @@ TEST_F(TraceNetLogObserverTest, TraceEventCaptured) {
EXPECT_EQ(base::StringPrintf("0x%d", entries[1].source.id), actual_item2.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN),
actual_item2.phase);
- EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_URL_REQUEST_START_JOB),
+ EXPECT_EQ(NetLog::EventTypeToString(NetLogEventType::URL_REQUEST_START_JOB),
actual_item2.name);
EXPECT_EQ(NetLog::SourceTypeToString(entries[1].source.type),
actual_item2.source_type);
@@ -208,7 +211,7 @@ TEST_F(TraceNetLogObserverTest, TraceEventCaptured) {
EXPECT_EQ(base::StringPrintf("0x%d", entries[2].source.id), actual_item3.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_END),
actual_item3.phase);
- EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_REQUEST_ALIVE),
+ EXPECT_EQ(NetLog::EventTypeToString(NetLogEventType::REQUEST_ALIVE),
actual_item3.name);
EXPECT_EQ(NetLog::SourceTypeToString(entries[2].source.type),
actual_item3.source_type);
@@ -217,11 +220,11 @@ TEST_F(TraceNetLogObserverTest, TraceEventCaptured) {
TEST_F(TraceNetLogObserverTest, EnableAndDisableTracing) {
trace_net_log_observer()->WatchForTraceStart(net_log());
EnableTraceLog();
- net_log()->AddGlobalEntry(NetLog::TYPE_CANCELLED);
+ net_log()->AddGlobalEntry(NetLogEventType::CANCELLED);
TraceLog::GetInstance()->SetDisabled();
- net_log()->AddGlobalEntry(NetLog::TYPE_REQUEST_ALIVE);
+ net_log()->AddGlobalEntry(NetLogEventType::REQUEST_ALIVE);
EnableTraceLog();
- net_log()->AddGlobalEntry(NetLog::TYPE_URL_REQUEST_START_JOB);
+ net_log()->AddGlobalEntry(NetLogEventType::URL_REQUEST_START_JOB);
EndTraceAndFlush();
trace_net_log_observer()->StopWatchForTraceStart();
@@ -241,7 +244,7 @@ TEST_F(TraceNetLogObserverTest, EnableAndDisableTracing) {
EXPECT_EQ(base::StringPrintf("0x%d", entries[0].source.id), actual_item1.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
actual_item1.phase);
- EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_CANCELLED),
+ EXPECT_EQ(NetLog::EventTypeToString(NetLogEventType::CANCELLED),
actual_item1.name);
EXPECT_EQ(NetLog::SourceTypeToString(entries[0].source.type),
actual_item1.source_type);
@@ -250,7 +253,7 @@ TEST_F(TraceNetLogObserverTest, EnableAndDisableTracing) {
EXPECT_EQ(base::StringPrintf("0x%d", entries[2].source.id), actual_item2.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
actual_item2.phase);
- EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_URL_REQUEST_START_JOB),
+ EXPECT_EQ(NetLog::EventTypeToString(NetLogEventType::URL_REQUEST_START_JOB),
actual_item2.name);
EXPECT_EQ(NetLog::SourceTypeToString(entries[2].source.type),
actual_item2.source_type);
@@ -259,10 +262,10 @@ TEST_F(TraceNetLogObserverTest, EnableAndDisableTracing) {
TEST_F(TraceNetLogObserverTest, DestroyObserverWhileTracing) {
trace_net_log_observer()->WatchForTraceStart(net_log());
EnableTraceLog();
- net_log()->AddGlobalEntry(NetLog::TYPE_CANCELLED);
+ net_log()->AddGlobalEntry(NetLogEventType::CANCELLED);
trace_net_log_observer()->StopWatchForTraceStart();
set_trace_net_log_observer(NULL);
- net_log()->AddGlobalEntry(NetLog::TYPE_REQUEST_ALIVE);
+ net_log()->AddGlobalEntry(NetLogEventType::REQUEST_ALIVE);
EndTraceAndFlush();
@@ -279,7 +282,7 @@ TEST_F(TraceNetLogObserverTest, DestroyObserverWhileTracing) {
EXPECT_EQ(base::StringPrintf("0x%d", entries[0].source.id), actual_item1.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
actual_item1.phase);
- EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_CANCELLED),
+ EXPECT_EQ(NetLog::EventTypeToString(NetLogEventType::CANCELLED),
actual_item1.name);
EXPECT_EQ(NetLog::SourceTypeToString(entries[0].source.type),
actual_item1.source_type);
@@ -287,11 +290,11 @@ TEST_F(TraceNetLogObserverTest, DestroyObserverWhileTracing) {
TEST_F(TraceNetLogObserverTest, DestroyObserverWhileNotTracing) {
trace_net_log_observer()->WatchForTraceStart(net_log());
- net_log()->AddGlobalEntry(NetLog::TYPE_CANCELLED);
+ net_log()->AddGlobalEntry(NetLogEventType::CANCELLED);
trace_net_log_observer()->StopWatchForTraceStart();
set_trace_net_log_observer(NULL);
- net_log()->AddGlobalEntry(NetLog::TYPE_REQUEST_ALIVE);
- net_log()->AddGlobalEntry(NetLog::TYPE_URL_REQUEST_START_JOB);
+ net_log()->AddGlobalEntry(NetLogEventType::REQUEST_ALIVE);
+ net_log()->AddGlobalEntry(NetLogEventType::URL_REQUEST_START_JOB);
EndTraceAndFlush();
@@ -306,10 +309,10 @@ TEST_F(TraceNetLogObserverTest, CreateObserverAfterTracingStarts) {
EnableTraceLog();
set_trace_net_log_observer(new TraceNetLogObserver());
trace_net_log_observer()->WatchForTraceStart(net_log());
- net_log()->AddGlobalEntry(NetLog::TYPE_CANCELLED);
+ net_log()->AddGlobalEntry(NetLogEventType::CANCELLED);
trace_net_log_observer()->StopWatchForTraceStart();
- net_log()->AddGlobalEntry(NetLog::TYPE_REQUEST_ALIVE);
- net_log()->AddGlobalEntry(NetLog::TYPE_URL_REQUEST_START_JOB);
+ net_log()->AddGlobalEntry(NetLogEventType::REQUEST_ALIVE);
+ net_log()->AddGlobalEntry(NetLogEventType::URL_REQUEST_START_JOB);
EndTraceAndFlush();
@@ -322,12 +325,12 @@ TEST_F(TraceNetLogObserverTest, CreateObserverAfterTracingStarts) {
TEST_F(TraceNetLogObserverTest, EventsWithAndWithoutParameters) {
trace_net_log_observer()->WatchForTraceStart(net_log());
EnableTraceLog();
- NetLog::ParametersCallback net_log_callback;
+ NetLogParametersCallback net_log_callback;
std::string param = "bar";
net_log_callback = NetLog::StringCallback("foo", &param);
- net_log()->AddGlobalEntry(NetLog::TYPE_CANCELLED, net_log_callback);
- net_log()->AddGlobalEntry(NetLog::TYPE_REQUEST_ALIVE);
+ net_log()->AddGlobalEntry(NetLogEventType::CANCELLED, net_log_callback);
+ net_log()->AddGlobalEntry(NetLogEventType::REQUEST_ALIVE);
EndTraceAndFlush();
trace_net_log_observer()->StopWatchForTraceStart();
@@ -347,7 +350,7 @@ TEST_F(TraceNetLogObserverTest, EventsWithAndWithoutParameters) {
EXPECT_EQ(base::StringPrintf("0x%d", entries[0].source.id), actual_item1.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
actual_item1.phase);
- EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_CANCELLED),
+ EXPECT_EQ(NetLog::EventTypeToString(NetLogEventType::CANCELLED),
actual_item1.name);
EXPECT_EQ(NetLog::SourceTypeToString(entries[0].source.type),
actual_item1.source_type);
@@ -356,7 +359,7 @@ TEST_F(TraceNetLogObserverTest, EventsWithAndWithoutParameters) {
EXPECT_EQ(base::StringPrintf("0x%d", entries[1].source.id), actual_item2.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
actual_item2.phase);
- EXPECT_EQ(NetLog::EventTypeToString(NetLog::TYPE_REQUEST_ALIVE),
+ EXPECT_EQ(NetLog::EventTypeToString(NetLogEventType::REQUEST_ALIVE),
actual_item2.name);
EXPECT_EQ(NetLog::SourceTypeToString(entries[1].source.type),
actual_item2.source_type);
diff --git a/chromium/net/log/write_to_file_net_log_observer.cc b/chromium/net/log/write_to_file_net_log_observer.cc
index f724da49efa..5470ebbcd44 100644
--- a/chromium/net/log/write_to_file_net_log_observer.cc
+++ b/chromium/net/log/write_to_file_net_log_observer.cc
@@ -13,6 +13,7 @@
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/values.h"
+#include "net/log/net_log_entry.h"
#include "net/log/net_log_util.h"
#include "net/url_request/url_request_context.h"
@@ -87,7 +88,7 @@ void WriteToFileNetLogObserver::StopObserving(
file_.reset();
}
-void WriteToFileNetLogObserver::OnAddEntry(const NetLog::Entry& entry) {
+void WriteToFileNetLogObserver::OnAddEntry(const NetLogEntry& entry) {
// Add a comma and newline for every event but the first. Newlines are needed
// so can load partial log files by just ignoring the last line. For this to
// work, lines cannot be pretty printed.
diff --git a/chromium/net/log/write_to_file_net_log_observer.h b/chromium/net/log/write_to_file_net_log_observer.h
index a04fdeb01cb..0d6372465b8 100644
--- a/chromium/net/log/write_to_file_net_log_observer.h
+++ b/chromium/net/log/write_to_file_net_log_observer.h
@@ -10,6 +10,7 @@
#include "base/files/scoped_file.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "net/base/net_export.h"
#include "net/log/net_log.h"
namespace base {
@@ -60,7 +61,7 @@ class NET_EXPORT WriteToFileNetLogObserver : public NetLog::ThreadSafeObserver {
void StopObserving(URLRequestContext* url_request_context);
// net::NetLog::ThreadSafeObserver implementation:
- void OnAddEntry(const NetLog::Entry& entry) override;
+ void OnAddEntry(const NetLogEntry& entry) override;
private:
// ----------------
diff --git a/chromium/net/log/write_to_file_net_log_observer_unittest.cc b/chromium/net/log/write_to_file_net_log_observer_unittest.cc
index c1ab52f36f3..06c2065e754 100644
--- a/chromium/net/log/write_to_file_net_log_observer_unittest.cc
+++ b/chromium/net/log/write_to_file_net_log_observer_unittest.cc
@@ -14,6 +14,10 @@
#include "base/json/json_reader.h"
#include "base/values.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_entry.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
#include "net/log/net_log_util.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
@@ -28,7 +32,7 @@ class WriteToFileNetLogObserverTest : public testing::Test {
public:
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- log_path_ = temp_dir_.path().AppendASCII("NetLogFile");
+ log_path_ = temp_dir_.GetPath().AppendASCII("NetLogFile");
}
protected:
@@ -89,11 +93,11 @@ TEST_F(WriteToFileNetLogObserverTest, GeneratesValidJSONWithOneEvent) {
logger->StartObserving(&net_log_, std::move(file), nullptr, nullptr);
const int kDummyId = 1;
- NetLog::Source source(NetLog::SOURCE_HTTP2_SESSION, kDummyId);
- NetLog::EntryData entry_data(NetLog::TYPE_PROXY_SERVICE, source,
- NetLog::PHASE_BEGIN, base::TimeTicks::Now(),
- NULL);
- NetLog::Entry entry(&entry_data, NetLogCaptureMode::IncludeSocketBytes());
+ NetLogSource source(NetLogSourceType::HTTP2_SESSION, kDummyId);
+ NetLogEntryData entry_data(NetLogEventType::PROXY_SERVICE, source,
+ NetLogEventPhase::BEGIN, base::TimeTicks::Now(),
+ NULL);
+ NetLogEntry entry(&entry_data, NetLogCaptureMode::IncludeSocketBytes());
logger->OnAddEntry(entry);
logger->StopObserving(nullptr);
logger.reset();
@@ -120,11 +124,11 @@ TEST_F(WriteToFileNetLogObserverTest, GeneratesValidJSONWithMultipleEvents) {
logger->StartObserving(&net_log_, std::move(file), nullptr, nullptr);
const int kDummyId = 1;
- NetLog::Source source(NetLog::SOURCE_HTTP2_SESSION, kDummyId);
- NetLog::EntryData entry_data(NetLog::TYPE_PROXY_SERVICE, source,
- NetLog::PHASE_BEGIN, base::TimeTicks::Now(),
- NULL);
- NetLog::Entry entry(&entry_data, NetLogCaptureMode::IncludeSocketBytes());
+ NetLogSource source(NetLogSourceType::HTTP2_SESSION, kDummyId);
+ NetLogEntryData entry_data(NetLogEventType::PROXY_SERVICE, source,
+ NetLogEventPhase::BEGIN, base::TimeTicks::Now(),
+ NULL);
+ NetLogEntry entry(&entry_data, NetLogCaptureMode::IncludeSocketBytes());
// Add the entry multiple times.
logger->OnAddEntry(entry);
diff --git a/chromium/net/net.gyp b/chromium/net/net.gyp
deleted file mode 100644
index dfeee21b7b3..00000000000
--- a/chromium/net/net.gyp
+++ /dev/null
@@ -1,1784 +0,0 @@
-# Copyright 2013 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.
-
-{
- 'variables': {
- 'chromium_code': 1,
- 'linux_link_kerberos%': 0,
- 'conditions': [
- ['chromeos==1 or embedded==1 or OS=="ios"', {
- # Disable Kerberos on ChromeOS and iOS, at least for now.
- # It needs configuration (krb5.conf and so on).
- 'use_kerberos%': 0,
- }, { # chromeos == 0 and embedded==0 and OS!="ios"
- 'use_kerberos%': 1,
- }],
- ['OS=="android" and target_arch != "ia32"', {
- # The way the cache uses mmap() is inefficient on some Android devices.
- # If this flag is set, we hackily avoid using mmap() in the disk cache.
- # We are pretty confident that mmap-ing the index would not hurt any
- # existing x86 android devices, but we cannot be so sure about the
- # variety of ARM devices. So enable it for x86 only for now.
- 'posix_avoid_mmap%': 1,
- }, {
- 'posix_avoid_mmap%': 0,
- }],
- ['OS=="ios"', {
- # Websockets and socket stream are not used on iOS.
- 'enable_websockets%': 0,
- # iOS does not use V8.
- 'use_v8_in_net%': 0,
- 'enable_built_in_dns%': 0,
- }, {
- 'enable_websockets%': 1,
- 'use_v8_in_net%': 1,
- 'enable_built_in_dns%': 1,
- }],
- ],
- },
- 'includes': [
- '../build/win_precompile.gypi',
- 'net.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'net_derived_sources',
- 'type': 'none',
- 'sources': [
- 'base/registry_controlled_domains/effective_tld_names.gperf',
- 'base/registry_controlled_domains/effective_tld_names_unittest1.gperf',
- 'base/registry_controlled_domains/effective_tld_names_unittest2.gperf',
- 'base/registry_controlled_domains/effective_tld_names_unittest3.gperf',
- 'base/registry_controlled_domains/effective_tld_names_unittest4.gperf',
- 'base/registry_controlled_domains/effective_tld_names_unittest5.gperf',
- 'base/registry_controlled_domains/effective_tld_names_unittest6.gperf',
- 'base/stale_while_revalidate_experiment_domains.gperf',
- ],
- 'rules': [
- {
- 'rule_name': 'dafsa',
- 'extension': 'gperf',
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/net/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT)-inc.cc',
- ],
- 'inputs': [
- 'tools/dafsa/make_dafsa.py',
- ],
- 'action': [
- 'python',
- 'tools/dafsa/make_dafsa.py',
- '<(RULE_INPUT_PATH)',
- '<(SHARED_INTERMEDIATE_DIR)/net/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT)-inc.cc',
- ],
- },
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)'
- ],
- },
- },
- {
- # Protobuf compiler / generator for QUIC crypto protocol buffer.
- # GN version: //net:net_quic_proto
- 'target_name': 'net_quic_proto',
- 'type': 'static_library',
- 'sources': [
- 'quic/proto/cached_network_parameters.proto',
- 'quic/proto/source_address_token.proto',
- ],
- 'variables': {
- 'enable_wexit_time_destructors': 1,
- 'proto_in_dir': 'quic/proto',
- 'proto_out_dir': 'net/quic/proto',
- 'cc_generator_options': 'dllexport_decl=NET_EXPORT_PRIVATE:',
- 'cc_include': 'net/base/net_export.h',
- },
- 'includes': [
- '../build/protoc.gypi',
- ],
- 'defines': [
- 'NET_IMPLEMENTATION',
- ],
- },
- {
- # GN version: //net
- 'target_name': 'net',
- 'dependencies': [
- '../url/url.gyp:url_lib',
- ],
- 'includes': [ 'net_common.gypi' ],
-
- 'conditions': [
- # ICU Alternatives
- ['use_platform_icu_alternatives == 1', {
- 'conditions': [
- ['OS == "android"', {
- 'sources': [
- 'base/net_string_util_icu_alternatives_android.cc',
- 'base/net_string_util_icu_alternatives_android.h',
- ],
- }],
- ['OS == "ios"', {
- 'sources': [
- 'base/net_string_util_icu_alternatives_ios.mm',
- ],
- }],
- ],
- },
- # 'use_platform_icu_alternatives != 1'
- {
- 'sources': [
- 'base/filename_util_icu.cc',
- 'base/net_string_util_icu.cc',
- ],
- 'dependencies': [
- '../base/base.gyp:base_i18n',
- '../third_party/icu/icu.gyp:icui18n',
- '../third_party/icu/icu.gyp:icuuc',
- '../third_party/protobuf/protobuf.gyp:protobuf_lite',
- 'net_quic_proto',
- ],
- }],
- # Brotli support.
- ['disable_brotli_filter == 1', {
- 'sources': [
- 'filter/brotli_filter_disabled.cc',
- ],
- },
- # 'disable_brotli_filter != 1'
- {
- 'sources': [
- 'filter/brotli_filter.cc',
- ],
- 'dependencies': [
- '../third_party/brotli/brotli.gyp:brotli',
- ],
- }],
- ],
- },
- {
- # GN version: //net:net_unittests
- 'target_name': 'net_unittests',
- 'type': '<(gtest_target_type)',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../crypto/crypto.gyp:crypto',
- '../crypto/crypto.gyp:crypto_test_support',
- '../testing/gmock.gyp:gmock',
- '../testing/gtest.gyp:gtest',
- '../third_party/boringssl/boringssl.gyp:boringssl',
- '../third_party/zlib/zlib.gyp:zlib',
- '../url/url.gyp:url_url_features',
- '../url/url.gyp:url_lib',
- 'balsa',
- 'net',
- 'net_quic_proto',
- 'net_derived_sources',
- 'net_extras',
- 'net_test_support',
- 'simple_quic_tools',
- 'stale_while_revalidate_experiment_domains',
- ],
- 'sources': [
- '<@(net_test_sources)',
- ],
- 'conditions': [
- ['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', {
- 'dependencies': [
- 'epoll_quic_tools',
- 'epoll_server',
- 'flip_in_mem_edsm_server_base',
- ],
- 'sources': [
- '<@(net_linux_test_sources)',
- ],
- }],
- ['OS == "mac" or OS == "ios"', {
- 'sources': [
- '<@(net_base_test_mac_ios_sources)',
- ],
- }],
- ['chromeos==1', {
- 'sources!': [
- 'proxy/proxy_config_service_linux_unittest.cc',
- ],
- }],
- [ 'OS == "android"', {
- 'dependencies': [
- 'net_javatests',
- ],
- }],
- [ 'use_nss_certs != 1', {
- 'sources!': [
- 'cert/nss_cert_database_chromeos_unittest.cc',
- 'cert/nss_cert_database_unittest.cc',
- 'cert/nss_profile_filter_chromeos_unittest.cc',
- 'ssl/client_cert_store_nss_unittest.cc',
- ],
- }],
- [ 'use_nss_certs == 1', {
- 'conditions': [
- [ 'desktop_linux == 1 or chromeos == 1', {
- 'dependencies': [
- '../build/linux/system.gyp:nss',
- ],
- }, { # desktop_linux == 0 and chromeos == 0
- 'dependencies': [
- '../third_party/nss/nss.gyp:nspr',
- '../third_party/nss/nss.gyp:nss',
- 'third_party/nss/ssl.gyp:libssl',
- ],
- }],
- ],
- }],
- [ 'use_kerberos==1', {
- 'defines': [
- 'USE_KERBEROS',
- ],
- }],
- [ 'use_kerberos==0 or OS == "android"', {
- # These are excluded on Android, because the actual Kerberos support,
- # which these test, is in a separate app on Android.
- 'sources!': [
- 'http/http_auth_gssapi_posix_unittest.cc',
- 'http/mock_gssapi_library_posix.cc',
- 'http/mock_gssapi_library_posix.h',
- ],
- }],
- [ 'use_kerberos==0', {
- 'sources!': [
- 'http/http_auth_handler_negotiate_unittest.cc',
- ],
- }],
- [ 'use_nss_certs == 0', {
- # Only include this test when using NSS for cert verification.
- 'sources!': [
- 'cert_net/nss_ocsp_unittest.cc',
- ],
- }],
- [ 'OS == "ios"', {
- # Only include these files on iOS when using NSS for cert
- # verification.
- 'sources!': [
- 'cert/x509_util_ios.cc',
- 'cert/x509_util_ios.h',
- ],
- }],
- [ 'use_openssl_certs == 0', {
- 'sources!': [
- 'ssl/openssl_client_key_store_unittest.cc',
- ],
- }],
- [ 'enable_websockets == 1', {
- 'sources': [
- '<@(net_websockets_test_sources)',
- ],
- 'defines': [
- 'ENABLE_WEBSOCKETS',
- ],
- 'dependencies': [
- 'http_server',
- ],
- }],
- ['disable_file_support==1', {
- 'sources!': [
- 'base/directory_lister_unittest.cc',
- 'base/directory_listing_unittest.cc',
- 'url_request/url_request_file_dir_job_unittest.cc',
- 'url_request/url_request_file_job_unittest.cc',
- ],
- }],
- [ 'disable_ftp_support==1', {
- 'sources/': [
- ['exclude', '^ftp/'],
- ],
- 'sources!': [
- 'url_request/url_request_ftp_job_unittest.cc',
- ],
- },
- ],
- [ 'enable_built_in_dns!=1', {
- 'sources!': [
- 'dns/address_sorter_posix_unittest.cc',
- 'dns/address_sorter_unittest.cc',
- ],
- },
- ],
- [ 'use_v8_in_net==1', {
- 'dependencies': [
- 'net_with_v8',
- ],
- }, { # else: !use_v8_in_net
- 'sources!': [
- 'proxy/proxy_resolver_v8_tracing_unittest.cc',
- 'proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc',
- 'proxy/proxy_resolver_v8_unittest.cc',
- ],
- },
- ],
-
- [ 'use_v8_in_net==1 and OS != "android"', {
- 'dependencies': [
- 'net_with_v8',
- 'net_browser_services',
- 'net_utility_services',
- '../mojo/mojo_edk.gyp:mojo_system_impl',
- ],
- }, { # else
- 'sources!': [
- 'dns/host_resolver_mojo_unittest.cc',
- 'dns/mojo_host_resolver_impl_unittest.cc',
- 'proxy/mojo_proxy_resolver_factory_impl_unittest.cc',
- 'proxy/mojo_proxy_resolver_impl_unittest.cc',
- 'proxy/mojo_proxy_resolver_v8_tracing_bindings_unittest.cc',
- 'proxy/proxy_resolver_factory_mojo_unittest.cc',
- 'proxy/proxy_service_mojo_unittest.cc',
- ],
- },
- ],
-
- [ 'enable_mdns != 1', {
- 'sources!' : [
- 'dns/mdns_cache_unittest.cc',
- 'dns/mdns_client_unittest.cc',
- 'dns/mdns_query_unittest.cc',
- 'dns/record_parsed_unittest.cc',
- 'dns/record_rdata_unittest.cc',
- ],
- }],
- [ 'OS == "win"', {
- 'sources!': [
- 'dns/dns_config_service_posix_unittest.cc',
- 'http/http_auth_gssapi_posix_unittest.cc',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- 'conditions': [
- [ 'icu_use_data_file_flag == 0', {
- # This is needed to trigger the dll copy step on windows.
- # TODO(mark): Specifying this here shouldn't be necessary.
- 'dependencies': [
- '../third_party/icu/icu.gyp:icudata',
- ],
- }],
- ],
- },
- ],
- [ 'OS == "ios"', {
- 'actions': [
- {
- 'action_name': 'copy_test_data',
- 'variables': {
- 'test_data_files': [
- '<@(net_test_support_data_sources)',
- '<@(net_unittests_data_sources)',
- ],
- 'test_data_prefix': 'net',
- },
- 'includes': [ '../build/copy_test_data_ios.gypi' ],
- },
- ],
- 'sources!': [
- # Need TestServer.
- "cert_net/cert_net_fetcher_impl_unittest.cc",
- # TODO(droger): The following tests are disabled because the
- # implementation is missing or incomplete.
- # KeygenHandler::GenKeyAndSignChallenge() is not ported to iOS.
- 'base/keygen_handler_unittest.cc',
- 'disk_cache/backend_unittest.cc',
- 'disk_cache/blockfile/block_files_unittest.cc',
- # Need to read input data files.
- 'filter/brotli_filter_unittest.cc',
- 'filter/gzip_filter_unittest.cc',
- 'proxy/proxy_script_fetcher_impl_unittest.cc',
- 'socket/ssl_client_socket_unittest.cc',
- 'socket/ssl_server_socket_unittest.cc',
- 'spdy/fuzzing/hpack_fuzz_util_test.cc',
- # Needs GetAppOutput().
- 'test/python_utils_unittest.cc',
- 'url_request/url_fetcher_impl_unittest.cc',
- 'url_request/url_request_context_builder_unittest.cc',
-
- # The following tests are disabled because they don't apply to
- # iOS.
- # OS is not "linux" or "freebsd" or "openbsd".
- 'socket/unix_domain_client_socket_posix_unittest.cc',
- 'socket/unix_domain_server_socket_posix_unittest.cc',
- ],
- }],
- ['OS == "android"', {
- # TODO(mmenke): This depends on test_support_base, which depends on
- # icu. Figure out a way to remove that dependency.
- 'dependencies': [
- '../testing/android/native_test.gyp:native_test_native_code',
- ]
- }],
- ['use_v8_in_net==1 and v8_use_external_startup_data==1', {
- 'dependencies': [
- '../gin/gin.gyp:gin',
- ]
- }],
- # Unit tests that are not supported by the current ICU alternatives on Android.
- ['OS == "android" and use_platform_icu_alternatives == 1', {
- 'sources!': [
- 'base/filename_util_unittest.cc',
- 'url_request/url_request_job_unittest.cc',
- ],
- }],
- # Unit tests that are not supported by the current ICU alternatives on iOS.
- ['OS == "ios" and use_platform_icu_alternatives == 1', {
- 'sources!': [
- 'base/filename_util_unittest.cc',
- 'base/url_util_unittest.cc',
- 'cert/x509_certificate_unittest.cc',
- 'http/http_auth_handler_basic_unittest.cc',
- 'http/http_auth_handler_digest_unittest.cc',
- 'http/http_auth_handler_factory_unittest.cc',
- 'http/http_auth_unittest.cc',
- 'http/http_content_disposition_unittest.cc',
- 'http/http_network_transaction_unittest.cc',
- 'http/http_proxy_client_socket_pool_unittest.cc',
- 'socket/ssl_client_socket_pool_unittest.cc',
- 'spdy/spdy_network_transaction_unittest.cc',
- 'spdy/spdy_proxy_client_socket_unittest.cc',
- 'url_request/url_request_job_unittest.cc',
- 'url_request/url_request_unittest.cc',
- ],
- }],
- # Exclude brotli test if the support for brotli is disabled.
- ['disable_brotli_filter == 1', {
- 'sources!': [
- 'filter/brotli_filter_unittest.cc',
- ],
- }],
- ],
- 'target_conditions': [
- # These source files are excluded by default platform rules, but they
- # are needed in specific cases on other platforms. Re-including them can
- # only be done in target_conditions as it is evaluated after the
- # platform rules.
- ['OS == "android"', {
- 'sources/': [
- ['include', '^base/address_tracker_linux_unittest\\.cc$'],
- ],
- }],
- ['OS == "ios"', {
- 'sources/': [
- ['include', '^base/mac/url_conversions_unittest\\.mm$'],
- ],
- }],
- ],
- },
- {
- 'target_name': 'net_perftests',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../base/base.gyp:test_support_perf',
- '../testing/gtest.gyp:gtest',
- '../url/url.gyp:url_lib',
- 'net',
- 'net_extras',
- 'net_test_support',
- ],
- 'sources': [
- 'base/mime_sniffer_perftest.cc',
- 'cookies/cookie_monster_perftest.cc',
- 'disk_cache/disk_cache_perftest.cc',
- 'extras/sqlite/sqlite_persistent_cookie_store_perftest.cc',
- 'proxy/proxy_resolver_perftest.cc',
- 'udp/udp_socket_perftest.cc',
- 'websockets/websocket_frame_perftest.cc',
- ],
- 'conditions': [
- [ 'use_v8_in_net==1', {
- 'dependencies': [
- 'net_with_v8',
- ],
- }, { # else: !use_v8_in_net
- 'sources!': [
- 'proxy/proxy_resolver_perftest.cc',
- ],
- },
- ],
- [ 'OS == "win"', {
- 'conditions': [
- [ 'icu_use_data_file_flag == 0', {
- # This is needed to trigger the dll copy step on windows.
- # TODO(mark): Specifying this here shouldn't be necessary.
- 'dependencies': [
- '../third_party/icu/icu.gyp:icudata',
- ],
- }],
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- }],
- [ 'enable_websockets != 1', {
- 'sources!': [
- 'websockets/websocket_frame_perftest.cc',
- ],
- }],
- ],
- },
- {
- 'target_name': 'net_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_base',
- '../crypto/crypto.gyp:crypto',
- '../net/tools/tld_cleanup/tld_cleanup.gyp:tld_cleanup_util',
- '../testing/gtest.gyp:gtest',
- '../testing/gmock.gyp:gmock',
- '../url/url.gyp:url_lib',
- 'net',
- ],
- 'export_dependent_settings': [
- '../base/base.gyp:base',
- # TODO(mmenke): This depends on icu, figure out a way to build tests
- # without icu.
- '../base/base.gyp:test_support_base',
- '../crypto/crypto.gyp:crypto',
- '../testing/gtest.gyp:gtest',
- '../testing/gmock.gyp:gmock',
- ],
- 'sources': [
- 'base/load_timing_info_test_util.cc',
- 'base/load_timing_info_test_util.h',
- 'base/mock_file_stream.cc',
- 'base/mock_file_stream.h',
- 'base/test_completion_callback.cc',
- 'base/test_completion_callback.h',
- 'cert/mock_cert_verifier.cc',
- 'cert/mock_cert_verifier.h',
- 'cert/mock_client_cert_verifier.cc',
- 'cert/mock_client_cert_verifier.h',
- 'cookies/cookie_monster_store_test.cc',
- 'cookies/cookie_monster_store_test.h',
- 'cookies/cookie_store_test_callbacks.cc',
- 'cookies/cookie_store_test_callbacks.h',
- 'cookies/cookie_store_test_helpers.cc',
- 'cookies/cookie_store_test_helpers.h',
- 'cookies/cookie_store_unittest.h',
- 'disk_cache/disk_cache_test_base.cc',
- 'disk_cache/disk_cache_test_base.h',
- 'disk_cache/disk_cache_test_util.cc',
- 'disk_cache/disk_cache_test_util.h',
- 'dns/dns_test_util.cc',
- 'dns/dns_test_util.h',
- 'dns/mock_host_resolver.cc',
- 'dns/mock_host_resolver.h',
- 'dns/mock_mdns_socket_factory.cc',
- 'dns/mock_mdns_socket_factory.h',
- 'http/http_stream_factory_test_util.cc',
- 'http/http_stream_factory_test_util.h',
- 'http/http_transaction_test_util.cc',
- 'http/http_transaction_test_util.h',
- 'log/test_net_log.cc',
- 'log/test_net_log.h',
- 'log/test_net_log_entry.cc',
- 'log/test_net_log_entry.h',
- 'log/test_net_log_util.cc',
- 'log/test_net_log_util.h',
- 'proxy/mock_proxy_resolver.cc',
- 'proxy/mock_proxy_resolver.h',
- 'proxy/mock_proxy_script_fetcher.cc',
- 'proxy/mock_proxy_script_fetcher.h',
- 'proxy/proxy_config_service_common_unittest.cc',
- 'proxy/proxy_config_service_common_unittest.h',
- 'socket/socket_test_util.cc',
- 'socket/socket_test_util.h',
- 'test/cert_test_util.cc',
- 'test/cert_test_util.h',
- 'test/cert_test_util_nss.cc',
- 'test/channel_id_test_util.cc',
- 'test/channel_id_test_util.h',
- 'test/ct_test_util.cc',
- 'test/ct_test_util.h',
- 'test/embedded_test_server/default_handlers.cc',
- 'test/embedded_test_server/default_handlers.h',
- 'test/embedded_test_server/embedded_test_server.cc',
- 'test/embedded_test_server/embedded_test_server.h',
- 'test/embedded_test_server/http_connection.cc',
- 'test/embedded_test_server/http_connection.h',
- 'test/embedded_test_server/http_request.cc',
- 'test/embedded_test_server/http_request.h',
- 'test/embedded_test_server/http_response.cc',
- 'test/embedded_test_server/http_response.h',
- 'test/embedded_test_server/request_handler_util.cc',
- 'test/embedded_test_server/request_handler_util.h',
- 'test/event_waiter.h',
- 'test/gtest_util.h',
- 'test/net_test_suite.cc',
- 'test/net_test_suite.h',
- 'test/python_utils.cc',
- 'test/python_utils.h',
- 'test/scoped_disable_exit_on_dfatal.cc',
- 'test/scoped_disable_exit_on_dfatal.h',
- 'test/spawned_test_server/base_test_server.cc',
- 'test/spawned_test_server/base_test_server.h',
- 'test/spawned_test_server/local_test_server.cc',
- 'test/spawned_test_server/local_test_server.h',
- 'test/spawned_test_server/local_test_server_posix.cc',
- 'test/spawned_test_server/local_test_server_win.cc',
- 'test/spawned_test_server/spawned_test_server.h',
- 'test/test_certificate_data.h',
- 'test/test_data_directory.cc',
- 'test/test_data_directory.h',
- 'test/url_request/ssl_certificate_error_job.cc',
- 'test/url_request/ssl_certificate_error_job.h',
- 'test/url_request/url_request_failed_job.cc',
- 'test/url_request/url_request_failed_job.h',
- 'test/url_request/url_request_hanging_read_job.cc',
- 'test/url_request/url_request_hanging_read_job.h',
- 'test/url_request/url_request_mock_data_job.cc',
- 'test/url_request/url_request_mock_data_job.h',
- 'test/url_request/url_request_slow_download_job.cc',
- 'test/url_request/url_request_slow_download_job.h',
- 'url_request/test_url_fetcher_factory.cc',
- 'url_request/test_url_fetcher_factory.h',
- 'url_request/url_request_test_util.cc',
- 'url_request/url_request_test_util.h',
- ],
- 'conditions': [
- ['OS != "ios"', {
- 'dependencies': [
- '../third_party/protobuf/protobuf.gyp:py_proto',
- ],
- }, {
- 'sources!': [
- 'test/spawned_test_server/base_test_server.cc',
- 'test/spawned_test_server/base_test_server.h',
- 'test/spawned_test_server/local_test_server.cc',
- 'test/spawned_test_server/local_test_server.h',
- 'test/spawned_test_server/local_test_server_posix.cc',
- 'test/spawned_test_server/local_test_server_win.cc',
- 'test/spawned_test_server/spawned_test_server.h',
- ],
- }],
- ['use_nss_certs == 1', {
- 'conditions': [
- [ 'desktop_linux == 1 or chromeos == 1', {
- 'dependencies': [
- '../build/linux/system.gyp:nss',
- ],
- }, { # desktop_linux == 0 and chromeos == 0
- 'dependencies': [
- '../third_party/nss/nss.gyp:nspr',
- '../third_party/nss/nss.gyp:nss',
- 'third_party/nss/ssl.gyp:libssl',
- ],
- }],
- ],
- }],
- ['OS == "android"', {
- 'dependencies': [
- 'net_test_jni_headers',
- ],
- 'sources': [
- 'test/embedded_test_server/android/embedded_test_server_android.cc',
- 'test/embedded_test_server/android/embedded_test_server_android.h',
- 'test/spawned_test_server/remote_test_server.cc',
- 'test/spawned_test_server/remote_test_server.h',
- 'test/spawned_test_server/spawner_communicator.cc',
- 'test/spawned_test_server/spawner_communicator.h',
- ],
- }],
- [ 'use_v8_in_net==1', {
- 'dependencies': [
- 'net_with_v8',
- ],
- },
- ],
- [ 'enable_mdns != 1', {
- 'sources!' : [
- 'dns/mock_mdns_socket_factory.cc',
- 'dns/mock_mdns_socket_factory.h'
- ]
- }],
- [ 'use_nss_certs != 1', {
- 'sources!': [
- 'test/cert_test_util_nss.cc',
- ],
- }],
- ['disable_file_support != 1', {
- 'sources': [
- 'test/url_request/url_request_mock_http_job.cc',
- 'test/url_request/url_request_mock_http_job.h',
- 'url_request/test_url_request_interceptor.cc',
- 'url_request/test_url_request_interceptor.h',
- ],
- }],
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- 'target_name': 'net_resources',
- 'type': 'none',
- 'variables': {
- 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/net',
- },
- 'actions': [
- {
- 'action_name': 'net_resources',
- 'variables': {
- 'grit_grd_file': 'base/net_resources.grd',
- },
- 'includes': [ '../build/grit_action.gypi' ],
- },
- ],
- },
- {
- 'target_name': 'net_extras',
- 'type': 'static_library',
- 'variables': { 'enable_wexit_time_destructors': 1, },
- 'dependencies': [
- '../base/base.gyp:base',
- '../sql/sql.gyp:sql',
- 'net',
- ],
- 'sources': [
- '<@(net_extras_sources)',
- ],
- },
- {
- 'target_name': 'http_server',
- 'type': 'static_library',
- 'variables': { 'enable_wexit_time_destructors': 1, },
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- ],
- 'sources': [
- 'server/http_connection.cc',
- 'server/http_connection.h',
- 'server/http_server.cc',
- 'server/http_server.h',
- 'server/http_server_request_info.cc',
- 'server/http_server_request_info.h',
- 'server/http_server_response_info.cc',
- 'server/http_server_response_info.h',
- 'server/web_socket.cc',
- 'server/web_socket.h',
- 'server/web_socket_encoder.cc',
- 'server/web_socket_encoder.h',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- { # GN version: //net:balsa
- 'target_name': 'balsa',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- ],
- 'sources': [
- 'tools/balsa/balsa_enums.h',
- 'tools/balsa/balsa_frame.cc',
- 'tools/balsa/balsa_frame.h',
- 'tools/balsa/balsa_headers.cc',
- 'tools/balsa/balsa_headers.h',
- 'tools/balsa/balsa_headers_token_utils.cc',
- 'tools/balsa/balsa_headers_token_utils.h',
- 'tools/balsa/balsa_visitor_interface.h',
- 'tools/balsa/http_message_constants.cc',
- 'tools/balsa/http_message_constants.h',
- 'tools/balsa/noop_balsa_visitor.h',
- 'tools/balsa/simple_buffer.cc',
- 'tools/balsa/simple_buffer.h',
- 'tools/balsa/string_piece_utils.h',
- 'tools/quic/spdy_balsa_utils.cc',
- 'tools/quic/spdy_balsa_utils.h',
- ],
- },
- {
- 'target_name': 'dump_cache',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- 'net_test_support',
- ],
- 'sources': [
- 'tools/dump_cache/dump_cache.cc',
- 'tools/dump_cache/dump_files.cc',
- 'tools/dump_cache/dump_files.h',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- 'target_name': 'simple_quic_tools',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../url/url.gyp:url_lib',
- 'net',
- 'net_quic_proto',
- ],
- 'sources': [
- 'tools/quic/chlo_extractor.h',
- 'tools/quic/chlo_extractor.cc',
- 'tools/quic/quic_client_base.cc',
- 'tools/quic/quic_client_base.h',
- 'tools/quic/quic_client_session.cc',
- 'tools/quic/quic_client_session.h',
- 'tools/quic/quic_dispatcher.cc',
- 'tools/quic/quic_dispatcher.h',
- 'tools/quic/quic_in_memory_cache.cc',
- 'tools/quic/quic_in_memory_cache.h',
- 'tools/quic/quic_per_connection_packet_writer.cc',
- 'tools/quic/quic_per_connection_packet_writer.h',
- 'tools/quic/quic_process_packet_interface.h',
- 'tools/quic/quic_simple_client.cc',
- 'tools/quic/quic_simple_client.h',
- 'tools/quic/quic_simple_per_connection_packet_writer.cc',
- 'tools/quic/quic_simple_per_connection_packet_writer.h',
- 'tools/quic/quic_simple_server.cc',
- 'tools/quic/quic_simple_server.h',
- 'tools/quic/quic_simple_server_packet_writer.cc',
- 'tools/quic/quic_simple_server_packet_writer.h',
- 'tools/quic/quic_simple_server_session.cc',
- 'tools/quic/quic_simple_server_session.h',
- 'tools/quic/quic_simple_server_session_helper.cc',
- 'tools/quic/quic_simple_server_session_helper.h',
- 'tools/quic/quic_simple_server_stream.cc',
- 'tools/quic/quic_simple_server_stream.h',
- 'tools/quic/quic_spdy_client_stream.cc',
- 'tools/quic/quic_spdy_client_stream.h',
- 'tools/quic/quic_time_wait_list_manager.cc',
- 'tools/quic/quic_time_wait_list_manager.h',
- 'tools/quic/stateless_rejector.cc',
- 'tools/quic/stateless_rejector.h',
- 'tools/quic/synchronous_host_resolver.cc',
- 'tools/quic/synchronous_host_resolver.h',
- ],
- },
- {
- # GN version: //net:stale_while_revalidate_experiment_domains
- 'target_name': 'stale_while_revalidate_experiment_domains',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- 'net_derived_sources',
- ],
- 'sources': [
- 'base/stale_while_revalidate_experiment_domains.cc',
- 'base/stale_while_revalidate_experiment_domains.h',
- ],
- },
- ],
- 'conditions': [
- ['use_v8_in_net == 1', {
- 'targets': [
- {
- 'target_name': 'net_with_v8',
- 'type': '<(component)',
- 'variables': { 'enable_wexit_time_destructors': 1, },
- 'dependencies': [
- '../base/base.gyp:base',
- '../gin/gin.gyp:gin',
- '../url/url.gyp:url_lib',
- '../v8/src/v8.gyp:v8',
- 'net'
- ],
- 'defines': [
- 'NET_IMPLEMENTATION',
- ],
- 'sources': [
- 'proxy/proxy_resolver_v8.cc',
- 'proxy/proxy_resolver_v8.h',
- 'proxy/proxy_resolver_v8_tracing.cc',
- 'proxy/proxy_resolver_v8_tracing.h',
- 'proxy/proxy_resolver_v8_tracing_wrapper.cc',
- 'proxy/proxy_resolver_v8_tracing_wrapper.h',
- 'proxy/proxy_service_v8.cc',
- 'proxy/proxy_service_v8.h',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- ],
- }],
- ['use_v8_in_net == 1 and OS != "android"', {
- 'targets': [
- {
- # GN version: //net/interfaces
- 'target_name': 'net_interfaces',
- 'type': 'static_library',
- 'sources': [
- 'interfaces/host_resolver_service.mojom',
- 'interfaces/proxy_resolver_service.mojom',
- ],
- 'dependencies': [
- '../url/url.gyp:url_mojom',
- ],
- 'variables': {
- 'mojom_typemaps': [
- '../url/mojo/gurl.typemap',
- ],
- },
- 'includes': [
- '../mojo/mojom_bindings_generator.gypi',
- ],
- },
- {
- # GN version: //net:net_browser_services
- 'target_name': 'net_browser_services',
- 'type': 'static_library',
- 'sources': [
- 'dns/mojo_host_resolver_impl.cc',
- 'dns/mojo_host_resolver_impl.h',
- 'proxy/in_process_mojo_proxy_resolver_factory.cc',
- 'proxy/in_process_mojo_proxy_resolver_factory.h',
- 'proxy/mojo_proxy_resolver_factory.h',
- 'proxy/proxy_resolver_factory_mojo.cc',
- 'proxy/proxy_resolver_factory_mojo.h',
- 'proxy/proxy_service_mojo.cc',
- 'proxy/proxy_service_mojo.h',
- ],
- 'dependencies': [
- 'mojo_type_converters',
- 'net',
- 'net_interfaces',
- '../mojo/mojo_base.gyp:mojo_common_lib',
- '../mojo/mojo_public.gyp:mojo_cpp_bindings',
-
- # NOTE(amistry): As long as we support in-process Mojo v8 PAC, we
- # need this dependency since in_process_mojo_proxy_resolver_factory
- # creates the utility process side Mojo services in the browser
- # process. Ultimately, this will go away when we only support
- # out-of-process.
- 'net_utility_services',
- ],
- },
- {
- # GN version: //net:net_utility_services
- 'target_name': 'net_utility_services',
- 'type': 'static_library',
- 'sources': [
- 'dns/host_resolver_mojo.cc',
- 'dns/host_resolver_mojo.h',
- 'proxy/mojo_proxy_resolver_factory_impl.cc',
- 'proxy/mojo_proxy_resolver_factory_impl.h',
- 'proxy/mojo_proxy_resolver_impl.cc',
- 'proxy/mojo_proxy_resolver_impl.h',
- 'proxy/mojo_proxy_resolver_v8_tracing_bindings.h',
- ],
- 'dependencies': [
- 'mojo_type_converters',
- 'net_interfaces',
- 'net_with_v8',
- '../mojo/mojo_public.gyp:mojo_cpp_bindings',
- ],
- },
- {
- # GN version: //net:mojo_type_converters
- 'target_name': 'mojo_type_converters',
- 'type': 'static_library',
- 'sources': [
- 'dns/mojo_host_type_converters.cc',
- 'dns/mojo_host_type_converters.h',
- 'proxy/mojo_proxy_type_converters.cc',
- 'proxy/mojo_proxy_type_converters.h',
- ],
- 'dependencies': [
- 'net',
- 'net_interfaces',
- '../mojo/mojo_public.gyp:mojo_cpp_bindings',
- ],
- },
- ],
- }],
- ['OS != "ios" and OS != "android"', {
- 'targets': [
- # iOS doesn't have the concept of simple executables, these targets
- # can't be compiled on the platform.
- {
- 'target_name': 'cert_verify_tool',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- 'net_test_support',
- ],
- 'sources': [
- 'tools/cert_verify_tool/cert_verify_tool.cc',
- 'tools/cert_verify_tool/cert_verify_tool_util.cc',
- 'tools/cert_verify_tool/cert_verify_tool_util.h',
- 'tools/cert_verify_tool/verify_using_cert_verify_proc.cc',
- 'tools/cert_verify_tool/verify_using_cert_verify_proc.h',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- 'target_name': 'crash_cache',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- 'net_test_support',
- ],
- 'sources': [
- 'tools/crash_cache/crash_cache.cc',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- 'target_name': 'crl_set_dump',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- ],
- 'sources': [
- 'tools/crl_set_dump/crl_set_dump.cc',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- # GN version: //net:dns_fuzz_stub
- {
- 'target_name': 'dns_fuzz_stub',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- ],
- 'sources': [
- 'tools/dns_fuzz_stub/dns_fuzz_stub.cc',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- 'target_name': 'gdig',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- ],
- 'sources': [
- 'tools/gdig/file_net_log.cc',
- 'tools/gdig/gdig.cc',
- ],
- },
- {
- 'target_name': 'get_server_time',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../url/url.gyp:url_lib',
- 'net',
- ],
- 'sources': [
- 'tools/get_server_time/get_server_time.cc',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- 'target_name': 'hpack_example_generator',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- ],
- 'sources': [
- 'spdy/fuzzing/hpack_example_generator.cc',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- 'target_name': 'hpack_fuzz_mutator',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- ],
- 'sources': [
- 'spdy/fuzzing/hpack_fuzz_mutator.cc',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- # GN version: //net:hpack_fuzz_wrapper
- {
- 'target_name': 'hpack_fuzz_wrapper',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- ],
- 'sources': [
- 'spdy/fuzzing/hpack_fuzz_wrapper.cc',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- 'target_name': 'net_watcher',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- 'net_with_v8',
- ],
- 'conditions': [
- [ 'use_glib == 1', {
- 'dependencies': [
- '../build/linux/system.gyp:gconf',
- '../build/linux/system.gyp:gio',
- ],
- },
- ],
- ],
- 'sources': [
- 'tools/net_watcher/net_watcher.cc',
- ],
- },
- {
- 'target_name': 'run_testserver',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_base',
- '../testing/gtest.gyp:gtest',
- 'net_test_support',
- ],
- 'sources': [
- 'tools/testserver/run_testserver.cc',
- ],
- },
- {
- 'target_name': 'quic_client',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- '../url/url.gyp:url_lib',
- 'net',
- 'simple_quic_tools',
- ],
- 'sources': [
- 'tools/quic/quic_simple_client_bin.cc',
- ],
- },
- {
- 'target_name': 'quic_packet_printer',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- 'net_quic_proto',
- 'simple_quic_tools',
- ],
- 'sources': [
- 'tools/quic/quic_packet_printer_bin.cc',
- ],
- },
- {
- 'target_name': 'crypto_message_printer',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- ],
- 'sources': [
- 'tools/quic/crypto_message_printer_bin.cc',
- ],
- },
- {
- 'target_name': 'quic_server',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- 'net_quic_proto',
- 'simple_quic_tools',
- ],
- 'sources': [
- 'tools/quic/quic_simple_server_bin.cc',
- ],
- },
- {
- 'target_name': 'stress_cache',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- 'net_test_support',
- ],
- 'sources': [
- 'tools/stress_cache/stress_cache.cc',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- {
- 'target_name': 'tld_cleanup',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_i18n',
- '../net/tools/tld_cleanup/tld_cleanup.gyp:tld_cleanup_util',
- ],
- 'sources': [
- 'tools/tld_cleanup/tld_cleanup.cc',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- },
- ],
- }],
- ['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', {
- 'targets': [
- {
- 'target_name': 'epoll_server',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- ],
- 'sources': [
- 'tools/epoll_server/epoll_server.cc',
- 'tools/epoll_server/epoll_server.h',
- ],
- },
- {
- 'target_name': 'flip_in_mem_edsm_server_base',
- 'type': 'static_library',
- 'cflags': [
- '-Wno-deprecated',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- '../third_party/boringssl/boringssl.gyp:boringssl',
- 'balsa',
- 'epoll_server',
- 'net',
- ],
- 'sources': [
- 'tools/flip_server/acceptor_thread.cc',
- 'tools/flip_server/acceptor_thread.h',
- 'tools/flip_server/constants.h',
- 'tools/flip_server/flip_config.cc',
- 'tools/flip_server/flip_config.h',
- 'tools/flip_server/http_interface.cc',
- 'tools/flip_server/http_interface.h',
- 'tools/flip_server/mem_cache.cc',
- 'tools/flip_server/mem_cache.h',
- 'tools/flip_server/output_ordering.cc',
- 'tools/flip_server/output_ordering.h',
- 'tools/flip_server/ring_buffer.cc',
- 'tools/flip_server/ring_buffer.h',
- 'tools/flip_server/sm_connection.cc',
- 'tools/flip_server/sm_connection.h',
- 'tools/flip_server/sm_interface.h',
- 'tools/flip_server/spdy_interface.cc',
- 'tools/flip_server/spdy_interface.h',
- 'tools/flip_server/spdy_ssl.cc',
- 'tools/flip_server/spdy_ssl.h',
- 'tools/flip_server/spdy_util.cc',
- 'tools/flip_server/spdy_util.h',
- 'tools/flip_server/streamer_interface.cc',
- 'tools/flip_server/streamer_interface.h',
- 'tools/flip_server/tcp_socket_util.cc',
- 'tools/flip_server/tcp_socket_util.h',
- 'tools/flip_server/url_to_filename_encoder.cc',
- 'tools/flip_server/url_to_filename_encoder.h',
- 'tools/flip_server/url_utilities.cc',
- 'tools/flip_server/url_utilities.h',
- ],
- },
- {
- 'target_name': 'flip_in_mem_edsm_server_unittests',
- 'type': 'executable',
- 'dependencies': [
- '../testing/gtest.gyp:gtest',
- '../testing/gmock.gyp:gmock',
- '../third_party/boringssl/boringssl.gyp:boringssl',
- 'flip_in_mem_edsm_server_base',
- 'net',
- 'net_test_support',
- ],
- 'sources': [
- 'tools/flip_server/flip_test_utils.cc',
- 'tools/flip_server/flip_test_utils.h',
- 'tools/flip_server/http_interface_test.cc',
- 'tools/flip_server/mem_cache_test.cc',
- 'tools/flip_server/run_all_tests.cc',
- 'tools/flip_server/spdy_interface_test.cc',
- 'tools/flip_server/url_to_filename_encoder_unittest.cc',
- 'tools/flip_server/url_utilities_unittest.cc',
- ],
- },
- {
- 'target_name': 'flip_in_mem_edsm_server',
- 'type': 'executable',
- 'cflags': [
- '-Wno-deprecated',
- ],
- 'dependencies': [
- '../base/base.gyp:base',
- 'flip_in_mem_edsm_server_base',
- 'net',
- ],
- 'sources': [
- 'tools/flip_server/flip_in_mem_edsm_server.cc',
- ],
- },
- {
- 'target_name': 'epoll_quic_tools',
- 'type': 'static_library',
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../url/url.gyp:url_lib',
- 'balsa',
- 'epoll_server',
- 'net',
- 'net_quic_proto',
- ],
- 'sources': [
- 'tools/quic/quic_client.cc',
- 'tools/quic/quic_client.h',
- 'tools/quic/quic_default_packet_writer.cc',
- 'tools/quic/quic_default_packet_writer.h',
- 'tools/quic/quic_epoll_alarm_factory.cc',
- 'tools/quic/quic_epoll_alarm_factory.h',
- 'tools/quic/quic_epoll_clock.cc',
- 'tools/quic/quic_epoll_clock.h',
- 'tools/quic/quic_epoll_connection_helper.cc',
- 'tools/quic/quic_epoll_connection_helper.h',
- 'tools/quic/quic_packet_reader.cc',
- 'tools/quic/quic_packet_reader.h',
- 'tools/quic/quic_packet_writer_wrapper.cc',
- 'tools/quic/quic_packet_writer_wrapper.h',
- 'tools/quic/quic_server.cc',
- 'tools/quic/quic_server.h',
- 'tools/quic/quic_socket_utils.cc',
- 'tools/quic/quic_socket_utils.h',
- ],
- },
- {
- 'target_name': 'epoll_quic_client',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- 'epoll_quic_tools',
- 'simple_quic_tools',
- ],
- 'sources': [
- 'tools/quic/quic_client_bin.cc',
- ],
- },
- {
- 'target_name': 'epoll_quic_server',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- 'net_quic_proto',
- 'epoll_quic_tools',
- 'simple_quic_tools',
- ],
- 'sources': [
- 'tools/quic/quic_server_bin.cc',
- ],
- },
- ]
- }],
- ['OS=="android"', {
- 'targets': [
- {
- 'target_name': 'net_jni_headers',
- 'type': 'none',
- 'sources': [
- 'android/java/src/org/chromium/net/AndroidCertVerifyResult.java',
- 'android/java/src/org/chromium/net/AndroidKeyStore.java',
- 'android/java/src/org/chromium/net/AndroidNetworkLibrary.java',
- 'android/java/src/org/chromium/net/AndroidTrafficStats.java',
- 'android/java/src/org/chromium/net/GURLUtils.java',
- 'android/java/src/org/chromium/net/HttpNegotiateAuthenticator.java',
- 'android/java/src/org/chromium/net/NetStringUtil.java',
- 'android/java/src/org/chromium/net/NetworkChangeNotifier.java',
- 'android/java/src/org/chromium/net/ProxyChangeListener.java',
- 'android/java/src/org/chromium/net/X509Util.java',
- ],
- 'variables': {
- 'jni_gen_package': 'net',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
- 'target_name': 'net_test_jni_headers',
- 'type': 'none',
- 'sources': [
- 'android/javatests/src/org/chromium/net/AndroidKeyStoreTestUtil.java',
- 'test/android/javatests/src/org/chromium/net/test/EmbeddedTestServerImpl.java',
- 'test/android/javatests/src/org/chromium/net/test/DummySpnegoAuthenticator.java',
- ],
- 'variables': {
- 'jni_gen_package': 'net/test',
- },
- 'includes': [ '../build/jni_generator.gypi' ],
- },
- {
- 'target_name': 'net_java',
- 'type': 'none',
- 'variables': {
- 'java_in_dir': '../net/android/java',
- },
- 'dependencies': [
- '../base/base.gyp:base',
- 'cert_verify_status_android_java',
- 'certificate_mime_types_java',
- 'network_change_notifier_types_java',
- 'network_change_notifier_android_types_java',
- 'net_errors_java',
- 'private_key_types_java',
- 'traffic_stats_error_java',
- ],
- 'includes': [ '../build/java.gypi' ],
- },
- {
- 'target_name': 'embedded_test_server_aidl',
- 'type': 'none',
- 'variables': {
- 'aidl_interface_file': '../net/test/android/javatests/src/org/chromium/net/test/IEmbeddedTestServerInterface.aidl',
- },
- 'sources': [
- '../net/test/android/javatests/src/org/chromium/net/test/IEmbeddedTestServerImpl.aidl',
- ],
- 'includes': [ '../build/java_aidl.gypi' ],
- },
- {
- 'target_name': 'net_java_test_support',
- 'type': 'none',
- 'variables': {
- 'java_in_dir': '../net/test/android/javatests',
- # TODO(jbudorick): remove chromium_code: 0 line once crbug.com/488192 is fixed.
- 'chromium_code': 0,
- },
- 'dependencies': [
- 'embedded_test_server_aidl',
- 'net_java',
- 'url_request_failed_job_java',
- '../base/base.gyp:base_java',
- '../base/base.gyp:base_java_test_support',
- '../third_party/android_tools/android_tools.gyp:legacy_http_javalib',
- ],
- 'includes': [ '../build/java.gypi' ],
- },
- {
- 'target_name': 'libnet_java_test_support',
- 'type': 'shared_library',
- 'dependencies': [
- 'net_test_support',
- '../base/base.gyp:base',
- ],
- 'sources': [
- 'test/android/net_test_entry_point.cc',
- 'test/android/net_test_jni_onload.cc',
- 'test/android/net_test_jni_onload.h',
- ],
- },
- {
- 'target_name': 'net_test_support_apk',
- 'type': 'none',
- 'dependencies': [
- 'net_java_test_support',
- ],
- 'variables': {
- 'android_manifest_path': 'test/android/javatests/AndroidManifest.xml',
- 'apk_name': 'ChromiumNetTestSupport',
- 'is_test_apk': 1,
- 'java_in_dir': 'test/android/javatests',
- 'java_in_dir_suffix': '/src_dummy',
- 'native_lib_target': 'libnet_java_test_support',
- 'never_lint': 1,
- },
- 'includes': [
- '../build/java_apk.gypi',
- ],
- },
- {
- # Targets that need the net test support APK should depend on this
- # target. It ensures that the APK is built without passing the
- # classpath on to dependent targets.
- 'target_name': 'require_net_test_support_apk',
- 'type': 'none',
- 'actions': [
- {
- 'action_name': 'require_ChromiumNetTestSupport',
- 'variables': {
- 'required_file': '<(PRODUCT_DIR)/net_test_support_apk/ChromiumNetTestSupport.apk.required',
- },
- 'inputs': [
- '<(PRODUCT_DIR)/apks/ChromiumNetTestSupport.apk',
- ],
- 'outputs': [
- '<(required_file)',
- ],
- 'action': [
- 'python', '../build/android/gyp/touch.py', '<(required_file)',
- ],
- },
- ],
- },
- {
- 'target_name': 'url_request_failed_job_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'test/url_request/url_request_failed_job.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- {
- 'target_name': 'net_javatests',
- 'type': 'none',
- 'variables': {
- 'java_in_dir': '../net/android/javatests',
- },
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/base.gyp:base_java_test_support',
- 'net_java',
- 'net_java_test_support',
- ],
- 'includes': [ '../build/java.gypi' ],
- },
- {
- 'target_name': 'net_errors_java',
- 'type': 'none',
- 'sources': [
- 'android/java/NetError.template',
- ],
- 'variables': {
- 'package_name': 'org/chromium/net',
- 'template_deps': ['base/net_error_list.h'],
- },
- 'includes': [ '../build/android/java_cpp_template.gypi' ],
- },
- {
- 'target_name': 'certificate_mime_types_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'base/mime_util.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- {
- 'target_name': 'cert_verify_status_android_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'android/cert_verify_result_android.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- {
- 'target_name': 'network_change_notifier_types_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'base/network_change_notifier.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- {
- 'target_name': 'network_change_notifier_android_types_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'android/network_change_notifier_android.cc',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- {
- 'target_name': 'private_key_types_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'android/keystore.h',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- {
- 'target_name': 'traffic_stats_error_java',
- 'type': 'none',
- 'variables': {
- 'source_file': 'android/traffic_stats.cc',
- },
- 'includes': [ '../build/android/java_cpp_enum.gypi' ],
- },
- {
- 'target_name': 'net_unittests_apk',
- 'type': 'none',
- 'dependencies': [
- 'net_java',
- 'net_javatests',
- 'net_java_test_support',
- 'net_unittests',
- ],
- 'conditions': [
- ['v8_use_external_startup_data==1', {
- 'dependencies': [
- '../v8/src/v8.gyp:v8_external_snapshot',
- ],
- 'variables': {
- 'dest_path': '<(asset_location)',
- 'renaming_sources': [
- '<(PRODUCT_DIR)/natives_blob.bin',
- '<(PRODUCT_DIR)/snapshot_blob.bin',
- ],
- 'renaming_destinations': [
- 'natives_blob_<(arch_suffix).bin',
- 'snapshot_blob_<(arch_suffix).bin',
- ],
- 'clear': 1,
- },
- 'includes': ['../build/android/copy_ex.gypi'],
- }],
- ],
- 'variables': {
- 'test_suite_name': 'net_unittests',
- 'isolate_file': 'net_unittests.isolate',
- 'android_manifest_path': 'android/unittest_support/AndroidManifest.xml',
- 'resource_dir': 'android/unittest_support/res',
- 'shard_timeout': 300,
- 'conditions': [
- ['v8_use_external_startup_data==1', {
- 'asset_location': '<(PRODUCT_DIR)/net_unittests_apk/assets',
- 'additional_input_paths': [
- '<(PRODUCT_DIR)/net_unittests_apk/assets/natives_blob_<(arch_suffix).bin',
- '<(PRODUCT_DIR)/net_unittests_apk/assets/snapshot_blob_<(arch_suffix).bin',
- ],
- }],
- ],
- },
- 'includes': [
- '../build/apk_test.gypi',
- '../build/android/v8_external_startup_data_arch_suffix.gypi',
- ],
- },
- {
- 'target_name': 'net_junit_tests',
- 'type': 'none',
- 'dependencies': [
- 'net_java',
- '../base/base.gyp:base',
- '../base/base.gyp:base_java_test_support',
- '../base/base.gyp:base_junit_test_support',
- '../testing/android/junit/junit_test.gyp:junit_test_support',
- ],
- 'variables': {
- 'main_class': 'org.chromium.testing.local.JunitTestMain',
- 'src_paths': [
- 'android/junit/',
- ],
- 'test_type': 'junit',
- 'wrapper_script_name': 'helper/<(_target_name)',
- },
- 'includes': [
- '../build/android/test_runner.gypi',
- '../build/host_jar.gypi',
- ],
- },
- ],
- 'conditions': [
- ['test_isolation_mode != "noop"',
- {
- 'targets': [
- {
- 'target_name': 'net_unittests_apk_run',
- 'type': 'none',
- 'dependencies': [
- 'net_unittests_apk',
- ],
- 'includes': [
- '../build/isolate.gypi',
- ],
- 'sources': [
- 'net_unittests_apk.isolate',
- ],
- },
- ]
- }
- ],
- ],
- }],
- ['OS == "android" or OS == "linux"', {
- 'targets': [
- {
- 'target_name': 'disk_cache_memory_test',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- ],
- 'sources': [
- 'tools/disk_cache_memory_test/disk_cache_memory_test.cc',
- ],
- },
- ],
- }],
- ['OS == "linux" or OS == "mac"', {
- 'targets': [
- {
- 'target_name': 'cachetool',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- 'net',
- 'net_test_support',
- ],
- 'sources': [
- 'tools/cachetool/cachetool.cc',
- ],
- },
- {
- 'target_name': 'content_decoder_tool',
- 'type': 'executable',
- 'dependencies': [
- '../base/base.gyp:base',
- '../url/url.gyp:url_lib',
- 'net',
- ],
- 'sources': [
- 'filter/mock_filter_context.cc',
- 'tools/content_decoder_tool/content_decoder_tool.cc',
- ],
- }
- ],
- }],
- ['test_isolation_mode != "noop"', {
- 'targets': [
- {
- 'target_name': 'net_unittests_run',
- 'type': 'none',
- 'dependencies': [
- 'net_unittests',
- ],
- 'includes': [
- '../build/isolate.gypi',
- ],
- 'sources': [
- 'net_unittests.isolate',
- ],
- },
- ],
- }],
- ],
-}
diff --git a/chromium/net/net.gypi b/chromium/net/net.gypi
index 1f50893f208..5554b4ded46 100644
--- a/chromium/net/net.gypi
+++ b/chromium/net/net.gypi
@@ -86,6 +86,14 @@
'cert/ct_verifier.h',
'cert/ct_verify_result.cc',
'cert/ct_verify_result.h',
+ 'cert/internal/cert_error_id.cc',
+ 'cert/internal/cert_error_id.h',
+ 'cert/internal/cert_error_params.cc',
+ 'cert/internal/cert_error_params.h',
+ 'cert/internal/cert_error_scoper.cc',
+ 'cert/internal/cert_error_scoper.h',
+ 'cert/internal/cert_errors.cc',
+ 'cert/internal/cert_errors.h',
'cert/internal/cert_issuer_source.h',
'cert/internal/cert_issuer_source_aia.cc',
'cert/internal/cert_issuer_source_aia.h',
@@ -105,22 +113,35 @@
'cert/internal/parse_ocsp.h',
'cert/internal/parsed_certificate.cc',
'cert/internal/parsed_certificate.h',
+ 'cert/internal/path_builder.cc',
+ 'cert/internal/path_builder.h',
'cert/internal/signature_algorithm.cc',
'cert/internal/signature_algorithm.h',
'cert/internal/signature_policy.cc',
'cert/internal/signature_policy.h',
'cert/internal/trust_store.cc',
'cert/internal/trust_store.h',
+ 'cert/internal/trust_store_collection.cc',
+ 'cert/internal/trust_store_collection.h',
+ 'cert/internal/trust_store_in_memory.cc',
+ 'cert/internal/trust_store_in_memory.h',
'cert/internal/verify_certificate_chain.cc',
'cert/internal/verify_certificate_chain.h',
'cert/internal/verify_name_match.cc',
'cert/internal/verify_name_match.h',
'cert/internal/verify_signed_data.cc',
'cert/internal/verify_signed_data.h',
+ 'cert/ocsp_revocation_status.h',
+ 'cert/ocsp_verify_result.cc',
+ 'cert/ocsp_verify_result.h',
'cert/pem_tokenizer.cc',
'cert/pem_tokenizer.h',
+ 'cert/sct_status_flags.h',
+ 'cert/sct_status_flags.cc',
'cert/signed_certificate_timestamp.cc',
'cert/signed_certificate_timestamp.h',
+ 'cert/signed_certificate_timestamp_and_status.cc',
+ 'cert/signed_certificate_timestamp_and_status.h',
'cert/signed_tree_head.cc',
'cert/signed_tree_head.h',
'cert/sth_distributor.cc',
@@ -140,6 +161,8 @@
'cert/x509_util_openssl.h',
'der/input.cc',
'der/input.h',
+ 'der/encode_values.cc',
+ 'der/encode_values.h',
'der/parse_values.cc',
'der/parse_values.h',
'der/parser.cc',
@@ -174,6 +197,12 @@
'http/transport_security_state.h',
'log/net_log.cc',
'log/net_log.h',
+ 'log/net_log_entry.cc',
+ 'log/net_log_entry.h',
+ 'log/net_log_source.cc',
+ 'log/net_log_source.h',
+ 'log/net_log_with_source.cc',
+ 'log/net_log_with_source.h',
'log/net_log_capture_mode.cc',
'log/net_log_capture_mode.h',
'log/net_log_event_type_list.h',
@@ -181,7 +210,6 @@
'socket/client_socket_handle.cc',
'socket/client_socket_handle.h',
'socket/connection_attempts.h',
- 'socket/next_proto.cc',
'socket/next_proto.h',
'socket/socket.h',
'socket/socket_performance_watcher.h',
@@ -203,8 +231,6 @@
'ssl/openssl_client_key_store.h',
'ssl/openssl_ssl_util.cc',
'ssl/openssl_ssl_util.h',
- 'ssl/signed_certificate_timestamp_and_status.cc',
- 'ssl/signed_certificate_timestamp_and_status.h',
'ssl/ssl_cert_request_info.cc',
'ssl/ssl_cert_request_info.h',
'ssl/ssl_cipher_suite_names.cc',
@@ -227,6 +253,8 @@
'ssl/token_binding.h',
],
'net_non_nacl_sources': [
+ 'android/cellular_signal_strength.cc',
+ 'android/cellular_signal_strength.h',
'android/cert_verify_result_android.cc',
'android/cert_verify_result_android.h',
'android/gurl_utils.cc',
@@ -235,8 +263,6 @@
'android/http_auth_negotiate_android.h',
'android/keystore.cc',
'android/keystore.h',
- 'android/keystore_openssl.cc',
- 'android/keystore_openssl.h',
'android/legacy_openssl.h',
'android/net_jni_registrar.cc',
'android/net_jni_registrar.h',
@@ -410,6 +436,8 @@
'cert/ct_signed_certificate_timestamp_log_param.h',
'cert/ev_root_ca_metadata.cc',
'cert/ev_root_ca_metadata.h',
+ 'cert/internal/trust_store_nss.cc',
+ 'cert/internal/trust_store_nss.h',
'cert/jwk_serializer.cc',
'cert/jwk_serializer.h',
'cert/merkle_audit_proof.cc',
@@ -428,7 +456,8 @@
'cert/nss_cert_database_chromeos.h',
'cert/nss_profile_filter_chromeos.cc',
'cert/nss_profile_filter_chromeos.h',
- 'cert/sct_status_flags.h',
+ 'cert/test_keychain_search_list_mac.cc',
+ 'cert/test_keychain_search_list_mac.h',
'cert/test_root_certs.cc',
'cert/test_root_certs.h',
'cert/test_root_certs_android.cc',
@@ -540,6 +569,8 @@
'log/trace_net_log_observer.h',
'log/write_to_file_net_log_observer.cc',
'log/write_to_file_net_log_observer.h',
+ 'log/bounded_file_net_log_observer.cc',
+ 'log/bounded_file_net_log_observer.h',
'disk_cache/simple/simple_histogram_macros.h' ,
'cert_net/nss_ocsp.cc',
'cert_net/nss_ocsp.h',
@@ -613,16 +644,21 @@
'dns/record_rdata.h',
'dns/serial_worker.cc',
'dns/serial_worker.h',
- 'dns/single_request_host_resolver.cc',
- 'dns/single_request_host_resolver.h',
'filter/filter.cc',
'filter/filter.h',
+ 'filter/filter_source_stream.cc',
+ 'filter/filter_source_stream.h',
'filter/gzip_filter.cc',
'filter/gzip_filter.h',
'filter/gzip_header.cc',
'filter/gzip_header.h',
+ 'filter/gzip_source_stream.cc',
+ 'filter/gzip_source_stream.h',
'filter/sdch_filter.cc',
'filter/sdch_filter.h',
+ 'filter/source_stream.cc',
+ 'filter/source_stream.h',
+ 'filter/source_stream_type_list.h',
'http/bidirectional_stream.cc',
'http/bidirectional_stream.h',
'http/bidirectional_stream_impl.cc',
@@ -737,13 +773,20 @@
'http/url_security_manager_win.cc',
'nqe/cached_network_quality.cc',
'nqe/cached_network_quality.h',
+ 'nqe/effective_connection_type.cc',
+ 'nqe/effective_connection_type.h',
'nqe/external_estimate_provider.h',
+ 'nqe/network_id.h',
+ 'nqe/network_qualities_prefs_manager.cc',
+ 'nqe/network_qualities_prefs_manager.h',
'nqe/network_quality.cc',
'nqe/network_quality.h',
'nqe/network_quality_estimator.cc',
'nqe/network_quality_estimator.h',
'nqe/network_quality_observation.h',
'nqe/network_quality_observation_source.h',
+ 'nqe/network_quality_store.cc',
+ 'nqe/network_quality_store.h',
'nqe/observation_buffer.h',
'nqe/socket_watcher.cc',
'nqe/socket_watcher.h',
@@ -813,245 +856,239 @@
'proxy/proxy_server_mac.cc',
'proxy/proxy_service.cc',
'proxy/proxy_service.h',
- 'quic/bidirectional_stream_quic_impl.cc',
- 'quic/bidirectional_stream_quic_impl.h',
- 'quic/congestion_control/cubic.cc',
- 'quic/congestion_control/cubic.h',
- 'quic/congestion_control/cubic_bytes.cc',
- 'quic/congestion_control/cubic_bytes.h',
- 'quic/congestion_control/general_loss_algorithm.cc',
- 'quic/congestion_control/general_loss_algorithm.h',
- 'quic/congestion_control/hybrid_slow_start.cc',
- 'quic/congestion_control/hybrid_slow_start.h',
- 'quic/congestion_control/loss_detection_interface.h',
- 'quic/congestion_control/pacing_sender.cc',
- 'quic/congestion_control/pacing_sender.h',
- 'quic/congestion_control/prr_sender.cc',
- 'quic/congestion_control/prr_sender.h',
- 'quic/congestion_control/rtt_stats.cc',
- 'quic/congestion_control/rtt_stats.h',
- 'quic/congestion_control/send_algorithm_interface.cc',
- 'quic/congestion_control/send_algorithm_interface.h',
- 'quic/congestion_control/tcp_cubic_sender_base.cc',
- 'quic/congestion_control/tcp_cubic_sender_base.h',
- 'quic/congestion_control/tcp_cubic_sender_base.h',
- 'quic/congestion_control/tcp_cubic_sender_bytes.cc',
- 'quic/congestion_control/tcp_cubic_sender_packets.cc',
- 'quic/congestion_control/tcp_cubic_sender_packets.h',
- 'quic/congestion_control/windowed_filter.h',
- 'quic/crypto/aead_base_decrypter.cc',
- 'quic/crypto/aead_base_decrypter.h',
- 'quic/crypto/aead_base_encrypter.cc',
- 'quic/crypto/aead_base_encrypter.h',
- 'quic/crypto/aes_128_gcm_12_decrypter.cc',
- 'quic/crypto/aes_128_gcm_12_decrypter.h',
- 'quic/crypto/aes_128_gcm_12_encrypter.cc',
- 'quic/crypto/aes_128_gcm_12_encrypter.h',
- 'quic/crypto/cert_compressor.cc',
- 'quic/crypto/cert_compressor.h',
- 'quic/crypto/chacha20_poly1305_decrypter.cc',
- 'quic/crypto/chacha20_poly1305_decrypter.h',
- 'quic/crypto/chacha20_poly1305_encrypter.cc',
- 'quic/crypto/chacha20_poly1305_encrypter.h',
- 'quic/crypto/channel_id.cc',
- 'quic/crypto/channel_id.h',
- 'quic/crypto/channel_id_chromium.cc',
- 'quic/crypto/channel_id_chromium.h',
- 'quic/crypto/common_cert_set.cc',
- 'quic/crypto/common_cert_set.h',
- 'quic/crypto/crypto_framer.cc',
- 'quic/crypto/crypto_framer.h',
- 'quic/crypto/crypto_handshake.cc',
- 'quic/crypto/crypto_handshake.h',
- 'quic/crypto/crypto_handshake_message.cc',
- 'quic/crypto/crypto_handshake_message.h',
- 'quic/crypto/crypto_protocol.h',
- 'quic/crypto/crypto_secret_boxer.cc',
- 'quic/crypto/crypto_secret_boxer.h',
- 'quic/crypto/crypto_server_config_protobuf.cc',
- 'quic/crypto/crypto_server_config_protobuf.h',
- 'quic/crypto/crypto_utils.cc',
- 'quic/crypto/crypto_utils.h',
- 'quic/crypto/curve25519_key_exchange.cc',
- 'quic/crypto/curve25519_key_exchange.h',
- 'quic/crypto/ephemeral_key_source.h',
- 'quic/crypto/key_exchange.h',
- 'quic/crypto/local_strike_register_client.cc',
- 'quic/crypto/local_strike_register_client.h',
- 'quic/crypto/null_decrypter.cc',
- 'quic/crypto/null_decrypter.h',
- 'quic/crypto/null_encrypter.cc',
- 'quic/crypto/null_encrypter.h',
- 'quic/crypto/p256_key_exchange.cc',
- 'quic/crypto/p256_key_exchange.h',
- 'quic/crypto/proof_source.cc',
- 'quic/crypto/proof_source.h',
- 'quic/crypto/proof_source_chromium.cc',
- 'quic/crypto/proof_source_chromium.h',
- 'quic/crypto/proof_verifier.h',
- 'quic/crypto/proof_verifier_chromium.cc',
- 'quic/crypto/proof_verifier_chromium.h',
- 'quic/crypto/properties_based_quic_server_info.cc',
- 'quic/crypto/properties_based_quic_server_info.h',
- 'quic/crypto/quic_compressed_certs_cache.cc',
- 'quic/crypto/quic_compressed_certs_cache.h',
- 'quic/crypto/quic_crypto_client_config.cc',
- 'quic/crypto/quic_crypto_client_config.h',
- 'quic/crypto/quic_crypto_server_config.cc',
- 'quic/crypto/quic_crypto_server_config.h',
- 'quic/crypto/quic_decrypter.cc',
- 'quic/crypto/quic_decrypter.h',
- 'quic/crypto/quic_encrypter.cc',
- 'quic/crypto/quic_encrypter.h',
- 'quic/crypto/quic_random.cc',
- 'quic/crypto/quic_random.h',
- 'quic/crypto/quic_server_info.cc',
- 'quic/crypto/quic_server_info.h',
- 'quic/crypto/scoped_evp_aead_ctx.cc',
- 'quic/crypto/scoped_evp_aead_ctx.h',
- 'quic/crypto/strike_register.cc',
- 'quic/crypto/strike_register.h',
- 'quic/crypto/strike_register_client.h',
- 'quic/interval.h',
- 'quic/interval_set.h',
- 'quic/iovector.cc',
- 'quic/iovector.h',
- 'quic/network_connection.cc',
- 'quic/network_connection.h',
- 'quic/p2p/quic_p2p_crypto_config.cc',
- 'quic/p2p/quic_p2p_crypto_config.h',
- 'quic/p2p/quic_p2p_crypto_stream.cc',
- 'quic/p2p/quic_p2p_crypto_stream.h',
- 'quic/p2p/quic_p2p_session.cc',
- 'quic/p2p/quic_p2p_session.h',
- 'quic/p2p/quic_p2p_stream.cc',
- 'quic/p2p/quic_p2p_stream.h',
- 'quic/port_suggester.cc',
- 'quic/port_suggester.h',
- 'quic/quic_address_mismatch.cc',
- 'quic/quic_address_mismatch.h',
- 'quic/quic_alarm.cc',
- 'quic/quic_alarm.h',
- 'quic/quic_arena_scoped_ptr.h',
- 'quic/quic_bandwidth.cc',
- 'quic/quic_bandwidth.h',
- 'quic/quic_blocked_writer_interface.h',
- 'quic/quic_buffered_packet_store.cc',
- 'quic/quic_buffered_packet_store.h',
- 'quic/quic_bug_tracker.h',
- 'quic/quic_chromium_alarm_factory.cc',
- 'quic/quic_chromium_alarm_factory.h',
- 'quic/quic_chromium_client_session.cc',
- 'quic/quic_chromium_client_session.h',
- 'quic/quic_chromium_client_stream.cc',
- 'quic/quic_chromium_client_stream.h',
- 'quic/quic_chromium_connection_helper.cc',
- 'quic/quic_chromium_connection_helper.h',
- 'quic/quic_chromium_packet_reader.cc',
- 'quic/quic_chromium_packet_reader.h',
- 'quic/quic_chromium_packet_writer.cc',
- 'quic/quic_chromium_packet_writer.h',
- 'quic/quic_client_promised_info.cc',
- 'quic/quic_client_promised_info.h',
- 'quic/quic_client_push_promise_index.cc',
- 'quic/quic_client_push_promise_index.h',
- 'quic/quic_client_session_base.cc',
- 'quic/quic_client_session_base.h',
- 'quic/quic_clock.cc',
- 'quic/quic_clock.h',
- 'quic/quic_config.cc',
- 'quic/quic_config.h',
- 'quic/quic_connection.cc',
- 'quic/quic_connection.h',
- 'quic/quic_connection_logger.cc',
- 'quic/quic_connection_logger.h',
- 'quic/quic_connection_stats.cc',
- 'quic/quic_connection_stats.h',
- 'quic/quic_crypto_client_stream.cc',
- 'quic/quic_crypto_client_stream.h',
- 'quic/quic_crypto_client_stream_factory.cc',
- 'quic/quic_crypto_client_stream_factory.h',
- 'quic/quic_crypto_server_stream.cc',
- 'quic/quic_crypto_server_stream.h',
- 'quic/quic_crypto_stream.cc',
- 'quic/quic_crypto_stream.h',
- 'quic/quic_data_reader.cc',
- 'quic/quic_data_reader.h',
- 'quic/quic_data_writer.cc',
- 'quic/quic_data_writer.h',
- 'quic/quic_flags.cc',
- 'quic/quic_flags.h',
- 'quic/quic_flow_controller.cc',
- 'quic/quic_flow_controller.h',
- 'quic/quic_frame_list.cc',
- 'quic/quic_frame_list.h',
- 'quic/quic_framer.cc',
- 'quic/quic_framer.h',
- 'quic/quic_header_list.cc',
- 'quic/quic_header_list.h',
- 'quic/quic_headers_stream.cc',
- 'quic/quic_headers_stream.h',
- 'quic/quic_http_stream.cc',
- 'quic/quic_http_stream.h',
- 'quic/quic_http_utils.cc',
- 'quic/quic_http_utils.h',
- 'quic/quic_multipath_received_packet_manager.cc',
- 'quic/quic_multipath_received_packet_manager.h',
- 'quic/quic_multipath_transmissions_map.cc',
- 'quic/quic_multipath_transmissions_map.h',
- 'quic/quic_one_block_arena.h',
- 'quic/quic_packet_creator.cc',
- 'quic/quic_packet_creator.h',
- 'quic/quic_packet_generator.cc',
- 'quic/quic_packet_generator.h',
- 'quic/quic_packet_writer.h',
- 'quic/quic_protocol.cc',
- 'quic/quic_protocol.h',
- 'quic/quic_received_packet_manager.cc',
- 'quic/quic_received_packet_manager.h',
- 'quic/quic_sent_entropy_manager.cc',
- 'quic/quic_sent_entropy_manager.h',
- 'quic/quic_sent_packet_manager.cc',
- 'quic/quic_sent_packet_manager.h',
- 'quic/quic_sent_packet_manager_interface.h',
- 'quic/quic_server_id.cc',
- 'quic/quic_server_id.h',
- 'quic/quic_session.cc',
- 'quic/quic_session.h',
- 'quic/quic_simple_buffer_allocator.cc',
- 'quic/quic_simple_buffer_allocator.h',
- 'quic/quic_socket_address_coder.cc',
- 'quic/quic_socket_address_coder.h',
- 'quic/quic_spdy_session.cc',
- 'quic/quic_spdy_session.h',
- 'quic/quic_spdy_stream.cc',
- 'quic/quic_spdy_stream.h',
- 'quic/quic_stream_factory.cc',
- 'quic/quic_stream_factory.h',
- 'quic/quic_stream_sequencer.cc',
- 'quic/quic_stream_sequencer.h',
- 'quic/quic_stream_sequencer_buffer.cc',
- 'quic/quic_stream_sequencer_buffer.h',
- 'quic/quic_stream_sequencer_buffer_interface.h',
- 'quic/quic_sustained_bandwidth_recorder.cc',
- 'quic/quic_sustained_bandwidth_recorder.h',
- 'quic/quic_time.cc',
- 'quic/quic_time.h',
- 'quic/quic_types.cc',
- 'quic/quic_types.h',
- 'quic/quic_unacked_packet_map.cc',
- 'quic/quic_unacked_packet_map.h',
- 'quic/quic_utils.cc',
- 'quic/quic_utils.h',
- 'quic/quic_utils_chromium.h',
- 'quic/quic_write_blocked_list.cc',
- 'quic/quic_write_blocked_list.h',
- 'quic/reliable_quic_stream.cc',
- 'quic/reliable_quic_stream.h',
- 'quic/quic_server_session_base.cc',
- 'quic/quic_server_session_base.h',
- 'quic/spdy_utils.cc',
- 'quic/spdy_utils.h',
+ 'quic/chromium/bidirectional_stream_quic_impl.cc',
+ 'quic/chromium/bidirectional_stream_quic_impl.h',
+ 'quic/chromium/crypto/channel_id_chromium.cc',
+ 'quic/chromium/crypto/channel_id_chromium.h',
+ 'quic/chromium/crypto/proof_source_chromium.cc',
+ 'quic/chromium/crypto/proof_source_chromium.h',
+ 'quic/chromium/crypto/proof_verifier_chromium.cc',
+ 'quic/chromium/crypto/proof_verifier_chromium.h',
+ 'quic/chromium/quic_stream_factory.cc',
+ 'quic/chromium/quic_stream_factory.h',
+ 'quic/chromium/quic_http_stream.cc',
+ 'quic/chromium/quic_http_stream.h',
+ 'quic/chromium/quic_chromium_alarm_factory.cc',
+ 'quic/chromium/quic_chromium_alarm_factory.h',
+ 'quic/chromium/quic_chromium_client_session.cc',
+ 'quic/chromium/quic_chromium_client_session.h',
+ 'quic/chromium/quic_chromium_client_stream.cc',
+ 'quic/chromium/quic_chromium_client_stream.h',
+ 'quic/chromium/quic_chromium_connection_helper.cc',
+ 'quic/chromium/quic_chromium_connection_helper.h',
+ 'quic/chromium/quic_chromium_packet_reader.cc',
+ 'quic/chromium/quic_chromium_packet_reader.h',
+ 'quic/chromium/quic_chromium_packet_writer.cc',
+ 'quic/chromium/quic_chromium_packet_writer.h',
+ 'quic/chromium/quic_connection_logger.cc',
+ 'quic/chromium/quic_connection_logger.h',
+ 'quic/chromium/quic_utils_chromium.h',
+ 'quic/chromium/network_connection.cc',
+ 'quic/chromium/network_connection.h',
+ 'quic/chromium/port_suggester.cc',
+ 'quic/chromium/port_suggester.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',
+ 'quic/core/congestion_control/general_loss_algorithm.h',
+ 'quic/core/congestion_control/hybrid_slow_start.cc',
+ 'quic/core/congestion_control/hybrid_slow_start.h',
+ 'quic/core/congestion_control/loss_detection_interface.h',
+ 'quic/core/congestion_control/pacing_sender.cc',
+ 'quic/core/congestion_control/pacing_sender.h',
+ 'quic/core/congestion_control/prr_sender.cc',
+ 'quic/core/congestion_control/prr_sender.h',
+ 'quic/core/congestion_control/rtt_stats.cc',
+ '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_base.h',
+ 'quic/core/congestion_control/tcp_cubic_sender_bytes.cc',
+ 'quic/core/congestion_control/tcp_cubic_sender_packets.cc',
+ 'quic/core/congestion_control/tcp_cubic_sender_packets.h',
+ 'quic/core/congestion_control/windowed_filter.h',
+ 'quic/core/crypto/aead_base_decrypter.cc',
+ 'quic/core/crypto/aead_base_decrypter.h',
+ 'quic/core/crypto/aead_base_encrypter.cc',
+ 'quic/core/crypto/aead_base_encrypter.h',
+ 'quic/core/crypto/aes_128_gcm_12_decrypter.cc',
+ 'quic/core/crypto/aes_128_gcm_12_decrypter.h',
+ 'quic/core/crypto/aes_128_gcm_12_encrypter.cc',
+ 'quic/core/crypto/aes_128_gcm_12_encrypter.h',
+ 'quic/core/crypto/cert_compressor.cc',
+ 'quic/core/crypto/cert_compressor.h',
+ 'quic/core/crypto/chacha20_poly1305_decrypter.cc',
+ 'quic/core/crypto/chacha20_poly1305_decrypter.h',
+ 'quic/core/crypto/chacha20_poly1305_encrypter.cc',
+ 'quic/core/crypto/chacha20_poly1305_encrypter.h',
+ 'quic/core/crypto/channel_id.cc',
+ 'quic/core/crypto/channel_id.h',
+ 'quic/core/crypto/common_cert_set.cc',
+ 'quic/core/crypto/common_cert_set.h',
+ 'quic/core/crypto/crypto_framer.cc',
+ 'quic/core/crypto/crypto_framer.h',
+ 'quic/core/crypto/crypto_handshake.cc',
+ 'quic/core/crypto/crypto_handshake.h',
+ 'quic/core/crypto/crypto_handshake_message.cc',
+ 'quic/core/crypto/crypto_handshake_message.h',
+ 'quic/core/crypto/crypto_protocol.h',
+ 'quic/core/crypto/crypto_secret_boxer.cc',
+ 'quic/core/crypto/crypto_secret_boxer.h',
+ 'quic/core/crypto/crypto_server_config_protobuf.cc',
+ 'quic/core/crypto/crypto_server_config_protobuf.h',
+ 'quic/core/crypto/crypto_utils.cc',
+ 'quic/core/crypto/crypto_utils.h',
+ 'quic/core/crypto/curve25519_key_exchange.cc',
+ 'quic/core/crypto/curve25519_key_exchange.h',
+ 'quic/core/crypto/ephemeral_key_source.h',
+ 'quic/core/crypto/key_exchange.h',
+ 'quic/core/crypto/local_strike_register_client.cc',
+ 'quic/core/crypto/local_strike_register_client.h',
+ 'quic/core/crypto/null_decrypter.cc',
+ 'quic/core/crypto/null_decrypter.h',
+ 'quic/core/crypto/null_encrypter.cc',
+ 'quic/core/crypto/null_encrypter.h',
+ 'quic/core/crypto/p256_key_exchange.cc',
+ 'quic/core/crypto/p256_key_exchange.h',
+ 'quic/core/crypto/proof_source.cc',
+ 'quic/core/crypto/proof_source.h',
+ 'quic/core/crypto/proof_verifier.h',
+ 'quic/core/crypto/properties_based_quic_server_info.cc',
+ 'quic/core/crypto/properties_based_quic_server_info.h',
+ 'quic/core/crypto/quic_compressed_certs_cache.cc',
+ 'quic/core/crypto/quic_compressed_certs_cache.h',
+ 'quic/core/crypto/quic_crypto_client_config.cc',
+ 'quic/core/crypto/quic_crypto_client_config.h',
+ 'quic/core/crypto/quic_crypto_server_config.cc',
+ 'quic/core/crypto/quic_crypto_server_config.h',
+ 'quic/core/crypto/quic_decrypter.cc',
+ 'quic/core/crypto/quic_decrypter.h',
+ 'quic/core/crypto/quic_encrypter.cc',
+ 'quic/core/crypto/quic_encrypter.h',
+ 'quic/core/crypto/quic_random.cc',
+ 'quic/core/crypto/quic_random.h',
+ 'quic/core/crypto/quic_server_info.cc',
+ 'quic/core/crypto/quic_server_info.h',
+ 'quic/core/crypto/scoped_evp_aead_ctx.cc',
+ 'quic/core/crypto/scoped_evp_aead_ctx.h',
+ 'quic/core/crypto/strike_register.cc',
+ 'quic/core/crypto/strike_register.h',
+ 'quic/core/crypto/strike_register_client.h',
+ 'quic/core/interval.h',
+ 'quic/core/interval_set.h',
+ 'quic/core/iovector.cc',
+ 'quic/core/iovector.h',
+ 'quic/core/quic_address_mismatch.cc',
+ 'quic/core/quic_address_mismatch.h',
+ 'quic/core/quic_alarm.cc',
+ 'quic/core/quic_alarm.h',
+ 'quic/core/quic_arena_scoped_ptr.h',
+ 'quic/core/quic_bandwidth.cc',
+ 'quic/core/quic_bandwidth.h',
+ 'quic/core/quic_blocked_writer_interface.h',
+ 'quic/core/quic_buffered_packet_store.cc',
+ 'quic/core/quic_buffered_packet_store.h',
+ 'quic/core/quic_bug_tracker.h',
+ 'quic/core/quic_client_promised_info.cc',
+ 'quic/core/quic_client_promised_info.h',
+ 'quic/core/quic_client_push_promise_index.cc',
+ 'quic/core/quic_client_push_promise_index.h',
+ 'quic/core/quic_client_session_base.cc',
+ 'quic/core/quic_client_session_base.h',
+ 'quic/core/quic_clock.cc',
+ 'quic/core/quic_clock.h',
+ 'quic/core/quic_config.cc',
+ 'quic/core/quic_config.h',
+ 'quic/core/quic_connection.cc',
+ 'quic/core/quic_connection.h',
+ 'quic/core/quic_connection_stats.cc',
+ 'quic/core/quic_connection_stats.h',
+ 'quic/core/quic_crypto_client_stream.cc',
+ 'quic/core/quic_crypto_client_stream.h',
+ 'quic/core/quic_crypto_client_stream_factory.cc',
+ 'quic/core/quic_crypto_client_stream_factory.h',
+ 'quic/core/quic_crypto_server_stream.cc',
+ 'quic/core/quic_crypto_server_stream.h',
+ 'quic/core/quic_crypto_stream.cc',
+ 'quic/core/quic_crypto_stream.h',
+ 'quic/core/quic_data_reader.cc',
+ 'quic/core/quic_data_reader.h',
+ 'quic/core/quic_data_writer.cc',
+ 'quic/core/quic_data_writer.h',
+ 'quic/core/quic_flags.cc',
+ 'quic/core/quic_flags.h',
+ 'quic/core/quic_flow_controller.cc',
+ 'quic/core/quic_flow_controller.h',
+ 'quic/core/quic_frame_list.cc',
+ 'quic/core/quic_frame_list.h',
+ 'quic/core/quic_framer.cc',
+ 'quic/core/quic_framer.h',
+ 'quic/core/quic_header_list.cc',
+ 'quic/core/quic_header_list.h',
+ 'quic/core/quic_headers_stream.cc',
+ 'quic/core/quic_headers_stream.h',
+ 'quic/core/quic_http_utils.cc',
+ 'quic/core/quic_http_utils.h',
+ 'quic/core/quic_multipath_received_packet_manager.cc',
+ 'quic/core/quic_multipath_received_packet_manager.h',
+ 'quic/core/quic_multipath_sent_packet_manager.cc',
+ 'quic/core/quic_multipath_sent_packet_manager.h',
+ 'quic/core/quic_multipath_transmissions_map.cc',
+ 'quic/core/quic_multipath_transmissions_map.h',
+ 'quic/core/quic_one_block_arena.h',
+ 'quic/core/quic_packet_creator.cc',
+ 'quic/core/quic_packet_creator.h',
+ 'quic/core/quic_packet_generator.cc',
+ 'quic/core/quic_packet_generator.h',
+ 'quic/core/quic_packet_writer.h',
+ 'quic/core/quic_protocol.cc',
+ 'quic/core/quic_protocol.h',
+ 'quic/core/quic_received_packet_manager.cc',
+ 'quic/core/quic_received_packet_manager.h',
+ 'quic/core/quic_sent_entropy_manager.cc',
+ 'quic/core/quic_sent_entropy_manager.h',
+ 'quic/core/quic_sent_packet_manager.cc',
+ 'quic/core/quic_sent_packet_manager.h',
+ 'quic/core/quic_sent_packet_manager_interface.h',
+ 'quic/core/quic_server_id.cc',
+ 'quic/core/quic_server_id.h',
+ 'quic/core/quic_session.cc',
+ 'quic/core/quic_session.h',
+ 'quic/core/quic_simple_buffer_allocator.cc',
+ 'quic/core/quic_simple_buffer_allocator.h',
+ 'quic/core/quic_socket_address_coder.cc',
+ 'quic/core/quic_socket_address_coder.h',
+ 'quic/core/quic_spdy_session.cc',
+ 'quic/core/quic_spdy_session.h',
+ 'quic/core/quic_spdy_stream.cc',
+ 'quic/core/quic_spdy_stream.h',
+ 'quic/core/quic_stream_sequencer.cc',
+ 'quic/core/quic_stream_sequencer.h',
+ 'quic/core/quic_stream_sequencer_buffer.cc',
+ 'quic/core/quic_stream_sequencer_buffer.h',
+ 'quic/core/quic_stream_sequencer_buffer_interface.h',
+ 'quic/core/quic_sustained_bandwidth_recorder.cc',
+ 'quic/core/quic_sustained_bandwidth_recorder.h',
+ 'quic/core/quic_time.cc',
+ 'quic/core/quic_time.h',
+ 'quic/core/quic_types.cc',
+ 'quic/core/quic_types.h',
+ 'quic/core/quic_unacked_packet_map.cc',
+ 'quic/core/quic_unacked_packet_map.h',
+ 'quic/core/quic_utils.cc',
+ 'quic/core/quic_utils.h',
+ 'quic/core/quic_write_blocked_list.cc',
+ 'quic/core/quic_write_blocked_list.h',
+ 'quic/core/reliable_quic_stream.cc',
+ 'quic/core/reliable_quic_stream.h',
+ 'quic/core/quic_server_session_base.cc',
+ 'quic/core/quic_server_session_base.h',
+ 'quic/core/spdy_utils.cc',
+ 'quic/core/spdy_utils.h',
'sdch/sdch_owner.cc',
'sdch/sdch_owner.h',
'socket/client_socket_factory.cc',
@@ -1258,8 +1295,6 @@
'url_request/url_range_request_job.h',
'url_request/url_request.cc',
'url_request/url_request.h',
- 'url_request/url_request_backoff_manager.cc',
- 'url_request/url_request_backoff_manager.h',
'url_request/url_request_context.cc',
'url_request/url_request_context.h',
'url_request/url_request_context_builder.cc',
@@ -1330,10 +1365,10 @@
'extras/sqlite/sqlite_persistent_cookie_store.h',
],
'net_test_sources': [
+ 'android/cellular_signal_strength_unittest.cc',
'android/dummy_spnego_authenticator.cc',
'android/dummy_spnego_authenticator.h',
'android/http_auth_negotiate_android_unittest.cc',
- 'android/keystore_unittest.cc',
'android/network_change_notifier_android_unittest.cc',
'android/traffic_stats_unittest.cc',
'base/address_family_unittest.cc',
@@ -1402,11 +1437,19 @@
'cert/internal/parse_certificate_unittest.cc',
'cert/internal/parse_name_unittest.cc',
'cert/internal/parse_ocsp_unittest.cc',
+ 'cert/internal/path_builder_pkits_unittest.cc',
+ 'cert/internal/path_builder_unittest.cc',
+ 'cert/internal/path_builder_verify_certificate_chain_unittest.cc',
'cert/internal/signature_algorithm_unittest.cc',
'cert/internal/test_helpers.cc',
'cert/internal/test_helpers.h',
- 'cert/internal/verify_certificate_chain_unittest.cc',
+ 'cert/internal/trust_store_collection_unittest.cc',
+ 'cert/internal/trust_store_nss_unittest.cc',
+ 'cert/internal/trust_store_test_helpers.cc',
+ 'cert/internal/trust_store_test_helpers.h',
'cert/internal/verify_certificate_chain_pkits_unittest.cc',
+ 'cert/internal/verify_certificate_chain_typed_unittest.h',
+ 'cert/internal/verify_certificate_chain_unittest.cc',
'cert/internal/verify_name_match_unittest.cc',
'cert/internal/verify_signed_data_unittest.cc',
'cert/jwk_serializer_unittest.cc',
@@ -1418,6 +1461,7 @@
'cert/nss_cert_database_unittest.cc',
'cert/nss_profile_filter_chromeos_unittest.cc',
'cert/pem_tokenizer_unittest.cc',
+ 'cert/cert_verify_proc_ios_unittest.cc',
'cert/signed_certificate_timestamp_unittest.cc',
'cert/sth_distributor_unittest.cc',
'cert/test_root_certs_unittest.cc',
@@ -1433,6 +1477,7 @@
'cookies/cookie_util_unittest.cc',
'cookies/parsed_cookie_unittest.cc',
'der/input_unittest.cc',
+ 'der/encode_values_unittest.cc',
'der/parse_values_unittest.cc',
'der/parser_unittest.cc',
'disk_cache/backend_unittest.cc',
@@ -1471,14 +1516,18 @@
'dns/record_parsed_unittest.cc',
'dns/record_rdata_unittest.cc',
'dns/serial_worker_unittest.cc',
- 'dns/single_request_host_resolver_unittest.cc',
'extras/sqlite/sqlite_channel_id_store_unittest.cc',
'extras/sqlite/sqlite_persistent_cookie_store_unittest.cc',
'filter/brotli_filter_unittest.cc',
+ 'filter/brotli_source_stream_unittest.cc',
+ 'filter/filter_source_stream_unittest.cc',
'filter/filter_unittest.cc',
'filter/gzip_filter_unittest.cc',
+ 'filter/gzip_source_stream_unittest.cc',
'filter/mock_filter_context.cc',
'filter/mock_filter_context.h',
+ 'filter/mock_source_stream.cc',
+ 'filter/mock_source_stream.h',
'filter/sdch_filter_unittest.cc',
'ftp/ftp_auth_cache_unittest.cc',
'ftp/ftp_ctrl_response_buffer_unittest.cc',
@@ -1549,8 +1598,14 @@
'log/net_log_util_unittest.cc',
'log/trace_net_log_observer_unittest.cc',
'log/write_to_file_net_log_observer_unittest.cc',
+ 'log/bounded_file_net_log_observer_unittest.cc',
+ 'nqe/effective_connection_type_unittest.cc',
+ 'nqe/network_qualities_prefs_manager_unittest.cc',
+ 'nqe/network_quality_estimator_test_util.cc',
+ 'nqe/network_quality_estimator_test_util.h',
'nqe/network_quality_estimator_unittest.cc',
- 'nqe/network_quality_observation_unittest.cc',
+ 'nqe/network_quality_store_unittest.cc',
+ 'nqe/observation_buffer_unittest.cc',
'nqe/throughput_analyzer_unittest.cc',
'proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc',
'proxy/dhcp_proxy_script_fetcher_factory_unittest.cc',
@@ -1576,104 +1631,111 @@
'proxy/proxy_server_unittest.cc',
'proxy/proxy_service_mojo_unittest.cc',
'proxy/proxy_service_unittest.cc',
- 'quic/bidirectional_stream_quic_impl_unittest.cc',
- 'quic/congestion_control/cubic_bytes_test.cc',
- 'quic/congestion_control/cubic_test.cc',
- 'quic/congestion_control/general_loss_algorithm_test.cc',
- 'quic/congestion_control/hybrid_slow_start_test.cc',
- 'quic/congestion_control/pacing_sender_test.cc',
- 'quic/congestion_control/prr_sender_test.cc',
- 'quic/congestion_control/rtt_stats_test.cc',
- 'quic/congestion_control/send_algorithm_simulator.cc',
- 'quic/congestion_control/send_algorithm_simulator.h',
- 'quic/congestion_control/tcp_cubic_sender_bytes_test.cc',
- 'quic/congestion_control/tcp_cubic_sender_packets_test.cc',
- 'quic/congestion_control/windowed_filter_test.cc',
- 'quic/crypto/aes_128_gcm_12_decrypter_test.cc',
- 'quic/crypto/aes_128_gcm_12_encrypter_test.cc',
- 'quic/crypto/cert_compressor_test.cc',
- 'quic/crypto/chacha20_poly1305_decrypter_test.cc',
- 'quic/crypto/chacha20_poly1305_encrypter_test.cc',
- 'quic/crypto/channel_id_test.cc',
- 'quic/crypto/common_cert_set_test.cc',
- 'quic/crypto/crypto_framer_test.cc',
- 'quic/crypto/crypto_handshake_message_test.cc',
- 'quic/crypto/crypto_secret_boxer_test.cc',
- 'quic/crypto/crypto_server_test.cc',
- 'quic/crypto/crypto_utils_test.cc',
- 'quic/crypto/curve25519_key_exchange_test.cc',
- 'quic/crypto/local_strike_register_client_test.cc',
- 'quic/crypto/null_decrypter_test.cc',
- 'quic/crypto/null_encrypter_test.cc',
- 'quic/crypto/p256_key_exchange_test.cc',
- 'quic/crypto/proof_test.cc',
- 'quic/crypto/proof_verifier_chromium_test.cc',
- 'quic/crypto/properties_based_quic_server_info_test.cc',
- 'quic/crypto/quic_compressed_certs_cache_test.cc',
- 'quic/crypto/quic_crypto_client_config_test.cc',
- 'quic/crypto/quic_crypto_server_config_test.cc',
- 'quic/crypto/quic_random_test.cc',
- 'quic/crypto/strike_register_test.cc',
- 'quic/interval_set_test.cc',
- 'quic/interval_test.cc',
- 'quic/iovector_test.cc',
- 'quic/network_connection_unittest.cc',
- 'quic/p2p/quic_p2p_session_test.cc',
- 'quic/port_suggester_unittest.cc',
- 'quic/quic_address_mismatch_test.cc',
- 'quic/quic_alarm_test.cc',
- 'quic/quic_arena_scoped_ptr_test.cc',
- 'quic/quic_bandwidth_test.cc',
- 'quic/quic_buffered_packet_store_test.cc',
- 'quic/quic_chromium_alarm_factory_test.cc',
- 'quic/quic_chromium_client_session_test.cc',
- 'quic/quic_chromium_client_stream_test.cc',
- 'quic/quic_chromium_connection_helper_test.cc',
- 'quic/quic_client_push_promise_index_test.cc',
- 'quic/quic_clock_test.cc',
- 'quic/quic_config_test.cc',
- 'quic/quic_connection_logger_unittest.cc',
- 'quic/quic_connection_test.cc',
- 'quic/quic_crypto_client_stream_test.cc',
- 'quic/quic_crypto_server_stream_test.cc',
- 'quic/quic_crypto_stream_test.cc',
- 'quic/quic_data_writer_test.cc',
- 'quic/quic_flow_controller_test.cc',
- 'quic/quic_framer_test.cc',
- 'quic/quic_header_list_test.cc',
- 'quic/quic_headers_stream_test.cc',
- 'quic/quic_http_stream_test.cc',
- 'quic/quic_http_utils_test.cc',
- 'quic/quic_multipath_received_packet_manager_test.cc',
- 'quic/quic_multipath_transmissions_map_test.cc',
- 'quic/quic_network_transaction_unittest.cc',
- 'quic/quic_one_block_arena_test.cc',
- 'quic/quic_packet_creator_test.cc',
- 'quic/quic_packet_generator_test.cc',
- 'quic/quic_protocol_test.cc',
- 'quic/quic_received_packet_manager_test.cc',
- 'quic/quic_sent_entropy_manager_test.cc',
- 'quic/quic_sent_packet_manager_test.cc',
- 'quic/quic_server_id_test.cc',
- 'quic/quic_server_session_base_test.cc',
- 'quic/quic_session_test.cc',
- 'quic/quic_simple_buffer_allocator_test.cc',
- 'quic/quic_socket_address_coder_test.cc',
- 'quic/quic_spdy_stream_test.cc',
- 'quic/quic_stream_factory_test.cc',
- 'quic/quic_stream_sequencer_test.cc',
- 'quic/quic_sustained_bandwidth_recorder_test.cc',
- 'quic/quic_time_test.cc',
- 'quic/quic_unacked_packet_map_test.cc',
- 'quic/quic_utils_chromium_test.cc',
- 'quic/quic_utils_test.cc',
- 'quic/quic_write_blocked_list_test.cc',
- 'quic/reliable_quic_stream_test.cc',
- 'quic/spdy_utils_test.cc',
- 'quic/quic_stream_sequencer_buffer_test.cc',
+ 'quic/chromium/bidirectional_stream_quic_impl_unittest.cc',
+ 'quic/chromium/crypto/proof_verifier_chromium_test.cc',
+ 'quic/chromium/crypto_test_utils_chromium.cc',
+ 'quic/chromium/crypto/proof_test_chromium.cc',
+ 'quic/chromium/mock_network_change_notifier.cc',
+ 'quic/chromium/mock_network_change_notifier.h',
+ 'quic/chromium/mock_quic_data.cc',
+ 'quic/chromium/mock_quic_data.h',
+ 'quic/chromium/network_connection_unittest.cc',
+ 'quic/chromium/port_suggester_unittest.cc',
+ 'quic/chromium/quic_chromium_alarm_factory_test.cc',
+ 'quic/chromium/quic_chromium_client_session_test.cc',
+ 'quic/chromium/quic_chromium_client_stream_test.cc',
+ 'quic/chromium/quic_chromium_connection_helper_test.cc',
+ 'quic/chromium/quic_end_to_end_unittest.cc',
+ 'quic/chromium/quic_http_stream_test.cc',
+ 'quic/chromium/quic_network_transaction_unittest.cc',
+ 'quic/chromium/quic_stream_factory_test.cc',
+ 'quic/chromium/quic_utils_chromium_test.cc',
+ 'quic/chromium/quic_chromium_client_session_peer.cc',
+ 'quic/chromium/quic_chromium_client_session_peer.h',
+ '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',
+ 'quic/core/congestion_control/prr_sender_test.cc',
+ 'quic/core/congestion_control/rtt_stats_test.cc',
+ 'quic/core/congestion_control/send_algorithm_simulator.cc',
+ 'quic/core/congestion_control/send_algorithm_simulator.h',
+ 'quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc',
+ 'quic/core/congestion_control/tcp_cubic_sender_packets_test.cc',
+ 'quic/core/congestion_control/windowed_filter_test.cc',
+ 'quic/core/crypto/aes_128_gcm_12_decrypter_test.cc',
+ 'quic/core/crypto/aes_128_gcm_12_encrypter_test.cc',
+ 'quic/core/crypto/cert_compressor_test.cc',
+ 'quic/core/crypto/chacha20_poly1305_decrypter_test.cc',
+ 'quic/core/crypto/chacha20_poly1305_encrypter_test.cc',
+ 'quic/core/crypto/channel_id_test.cc',
+ 'quic/core/crypto/common_cert_set_test.cc',
+ 'quic/core/crypto/crypto_framer_test.cc',
+ 'quic/core/crypto/crypto_handshake_message_test.cc',
+ 'quic/core/crypto/crypto_secret_boxer_test.cc',
+ 'quic/core/crypto/crypto_server_test.cc',
+ 'quic/core/crypto/crypto_utils_test.cc',
+ 'quic/core/crypto/curve25519_key_exchange_test.cc',
+ 'quic/core/crypto/local_strike_register_client_test.cc',
+ 'quic/core/crypto/null_decrypter_test.cc',
+ 'quic/core/crypto/null_encrypter_test.cc',
+ 'quic/core/crypto/p256_key_exchange_test.cc',
+ 'quic/core/crypto/properties_based_quic_server_info_test.cc',
+ 'quic/core/crypto/quic_compressed_certs_cache_test.cc',
+ 'quic/core/crypto/quic_crypto_client_config_test.cc',
+ 'quic/core/crypto/quic_crypto_server_config_test.cc',
+ 'quic/core/crypto/quic_random_test.cc',
+ 'quic/core/crypto/strike_register_test.cc',
+ 'quic/core/interval_set_test.cc',
+ 'quic/core/interval_test.cc',
+ 'quic/core/iovector_test.cc',
+ 'quic/core/quic_address_mismatch_test.cc',
+ 'quic/core/quic_alarm_test.cc',
+ 'quic/core/quic_arena_scoped_ptr_test.cc',
+ 'quic/core/quic_bandwidth_test.cc',
+ 'quic/core/quic_buffered_packet_store_test.cc',
+ 'quic/core/quic_client_push_promise_index_test.cc',
+ 'quic/core/quic_clock_test.cc',
+ 'quic/core/quic_config_test.cc',
+ 'quic/core/quic_connection_test.cc',
+ 'quic/core/quic_crypto_client_stream_test.cc',
+ 'quic/core/quic_crypto_server_stream_test.cc',
+ 'quic/core/quic_crypto_stream_test.cc',
+ 'quic/core/quic_data_writer_test.cc',
+ 'quic/core/quic_flow_controller_test.cc',
+ 'quic/core/quic_framer_test.cc',
+ 'quic/core/quic_header_list_test.cc',
+ 'quic/core/quic_headers_stream_test.cc',
+ 'quic/core/quic_http_utils_test.cc',
+ 'quic/core/quic_multipath_received_packet_manager_test.cc',
+ 'quic/core/quic_multipath_sent_packet_manager_test.cc',
+ 'quic/core/quic_multipath_transmissions_map_test.cc',
+ 'quic/core/quic_one_block_arena_test.cc',
+ 'quic/core/quic_packet_creator_test.cc',
+ 'quic/core/quic_packet_generator_test.cc',
+ 'quic/core/quic_protocol_test.cc',
+ 'quic/core/quic_received_packet_manager_test.cc',
+ 'quic/core/quic_sent_entropy_manager_test.cc',
+ 'quic/core/quic_sent_packet_manager_test.cc',
+ 'quic/core/quic_server_id_test.cc',
+ 'quic/core/quic_server_session_base_test.cc',
+ 'quic/core/quic_session_test.cc',
+ 'quic/core/quic_simple_buffer_allocator_test.cc',
+ 'quic/core/quic_socket_address_coder_test.cc',
+ 'quic/core/quic_spdy_stream_test.cc',
+ 'quic/core/quic_stream_sequencer_test.cc',
+ 'quic/core/quic_sustained_bandwidth_recorder_test.cc',
+ 'quic/core/quic_time_test.cc',
+ 'quic/core/quic_unacked_packet_map_test.cc',
+ 'quic/core/quic_utils_test.cc',
+ 'quic/core/quic_write_blocked_list_test.cc',
+ 'quic/core/reliable_quic_stream_test.cc',
+ 'quic/core/spdy_utils_test.cc',
+ 'quic/core/quic_stream_sequencer_buffer_test.cc',
'quic/test_tools/crypto_test_utils.cc',
'quic/test_tools/crypto_test_utils.h',
- 'quic/test_tools/crypto_test_utils_chromium.cc',
+ 'quic/test_tools/crypto_test_utils_test.cc',
'quic/test_tools/delayed_verify_strike_register_client.cc',
'quic/test_tools/delayed_verify_strike_register_client.h',
'quic/test_tools/mock_clock.cc',
@@ -1690,8 +1752,8 @@
'quic/test_tools/mock_quic_spdy_client_stream.h',
'quic/test_tools/mock_random.cc',
'quic/test_tools/mock_random.h',
- 'quic/test_tools/quic_chromium_client_session_peer.cc',
- 'quic/test_tools/quic_chromium_client_session_peer.h',
+ 'quic/test_tools/quic_buffered_packet_store_peer.cc',
+ 'quic/test_tools/quic_buffered_packet_store_peer.h',
'quic/test_tools/quic_config_peer.cc',
'quic/test_tools/quic_config_peer.h',
'quic/test_tools/quic_connection_peer.cc',
@@ -1702,6 +1764,10 @@
'quic/test_tools/quic_flow_controller_peer.h',
'quic/test_tools/quic_framer_peer.cc',
'quic/test_tools/quic_framer_peer.h',
+ 'quic/test_tools/quic_headers_stream_peer.cc',
+ 'quic/test_tools/quic_headers_stream_peer.h',
+ 'quic/test_tools/quic_multipath_sent_packet_manager_peer.h',
+ 'quic/test_tools/quic_multipath_sent_packet_manager_peer.cc',
'quic/test_tools/quic_packet_creator_peer.cc',
'quic/test_tools/quic_packet_creator_peer.h',
'quic/test_tools/quic_packet_generator_peer.cc',
@@ -1718,6 +1784,8 @@
'quic/test_tools/quic_spdy_stream_peer.h',
'quic/test_tools/quic_stream_factory_peer.cc',
'quic/test_tools/quic_stream_factory_peer.h',
+ 'quic/test_tools/quic_stream_sequencer_buffer_peer.cc',
+ 'quic/test_tools/quic_stream_sequencer_buffer_peer.h',
'quic/test_tools/quic_stream_sequencer_peer.cc',
'quic/test_tools/quic_stream_sequencer_peer.h',
'quic/test_tools/quic_sustained_bandwidth_recorder_peer.cc',
@@ -1726,12 +1794,31 @@
'quic/test_tools/quic_test_packet_maker.h',
'quic/test_tools/quic_test_utils.cc',
'quic/test_tools/quic_test_utils.h',
+ 'quic/test_tools/quic_test_utils_test.cc',
'quic/test_tools/reliable_quic_stream_peer.cc',
'quic/test_tools/reliable_quic_stream_peer.h',
'quic/test_tools/rtt_stats_peer.cc',
'quic/test_tools/rtt_stats_peer.h',
'quic/test_tools/simple_quic_framer.cc',
'quic/test_tools/simple_quic_framer.h',
+ 'quic/test_tools/simulator/actor.cc',
+ 'quic/test_tools/simulator/actor.h',
+ 'quic/test_tools/simulator/alarm_factory.cc',
+ 'quic/test_tools/simulator/alarm_factory.h',
+ 'quic/test_tools/simulator/link.cc',
+ 'quic/test_tools/simulator/link.h',
+ 'quic/test_tools/simulator/port.cc',
+ 'quic/test_tools/simulator/port.h',
+ 'quic/test_tools/simulator/queue.cc',
+ 'quic/test_tools/simulator/queue.h',
+ 'quic/test_tools/simulator/quic_endpoint.cc',
+ 'quic/test_tools/simulator/quic_endpoint.h',
+ 'quic/test_tools/simulator/quic_endpoint_test.cc',
+ 'quic/test_tools/simulator/simulator.cc',
+ 'quic/test_tools/simulator/simulator.h',
+ 'quic/test_tools/simulator/simulator_test.cc',
+ 'quic/test_tools/simulator/switch.cc',
+ 'quic/test_tools/simulator/switch.h',
'quic/test_tools/test_task_runner.cc',
'quic/test_tools/test_task_runner.h',
'sdch/sdch_owner_unittest.cc',
@@ -1759,6 +1846,7 @@
'spdy/bidirectional_stream_spdy_impl_unittest.cc',
'spdy/buffered_spdy_framer_unittest.cc',
'spdy/fuzzing/hpack_fuzz_util_test.cc',
+ 'spdy/header_coalescer_test.cc',
'spdy/hpack/hpack_decoder_test.cc',
'spdy/hpack/hpack_encoder_test.cc',
'spdy/hpack/hpack_entry_test.cc',
@@ -1776,6 +1864,9 @@
'spdy/priority_write_scheduler_test.cc',
'spdy/spdy_alt_svc_wire_format_test.cc',
'spdy/spdy_buffer_unittest.cc',
+ 'spdy/spdy_deframer_visitor.cc',
+ 'spdy/spdy_deframer_visitor.h',
+ 'spdy/spdy_deframer_visitor_test.cc',
'spdy/spdy_frame_builder_test.cc',
'spdy/spdy_frame_reader_test.cc',
'spdy/spdy_framer_test.cc',
@@ -1784,9 +1875,13 @@
'spdy/spdy_http_stream_unittest.cc',
'spdy/spdy_http_utils_unittest.cc',
'spdy/spdy_network_transaction_unittest.cc',
+ 'spdy/spdy_no_op_visitor.h',
+ 'spdy/spdy_no_op_visitor.cc',
'spdy/spdy_pinnable_buffer_piece_test.cc',
'spdy/spdy_prefixed_buffer_reader_test.cc',
'spdy/spdy_protocol_test.cc',
+ 'spdy/spdy_protocol_test_utils.cc',
+ 'spdy/spdy_protocol_test_utils.h',
'spdy/spdy_proxy_client_socket_unittest.cc',
'spdy/spdy_read_queue_unittest.cc',
'spdy/spdy_session_pool_unittest.cc',
@@ -1815,6 +1910,7 @@
'ssl/ssl_config_service_unittest.cc',
'ssl/ssl_config_unittest.cc',
'ssl/ssl_connection_status_flags_unittest.cc',
+ 'ssl/ssl_platform_key_android_unittest.cc',
'test/embedded_test_server/embedded_test_server_unittest.cc',
'test/embedded_test_server/http_request_unittest.cc',
'test/embedded_test_server/http_response_unittest.cc',
@@ -1826,13 +1922,14 @@
'tools/quic/quic_simple_client_test.cc',
'tools/quic/test_tools/mock_quic_server_session_visitor.cc',
'tools/quic/test_tools/mock_quic_server_session_visitor.h',
+ 'tools/quic/test_tools/quic_in_memory_cache_peer.cc',
+ 'tools/quic/test_tools/quic_in_memory_cache_peer.h',
'tools/tld_cleanup/tld_cleanup_util_unittest.cc',
'udp/udp_socket_unittest.cc',
'url_request/report_sender_unittest.cc',
'url_request/sdch_dictionary_fetcher_unittest.cc',
'url_request/url_fetcher_impl_unittest.cc',
'url_request/url_fetcher_response_writer_unittest.cc',
- 'url_request/url_request_backoff_manager_unittest.cc',
'url_request/url_request_context_builder_unittest.cc',
'url_request/url_request_data_job_unittest.cc',
'url_request/url_request_file_dir_job_unittest.cc',
@@ -1842,6 +1939,7 @@
'url_request/url_request_http_job_unittest.cc',
'url_request/url_request_job_factory_impl_unittest.cc',
'url_request/url_request_job_unittest.cc',
+ 'url_request/url_request_quic_unittest.cc',
'url_request/url_request_simple_job_unittest.cc',
'url_request/url_request_throttler_simulation_unittest.cc',
'url_request/url_request_throttler_test_support.cc',
@@ -1851,7 +1949,6 @@
'url_request/view_cache_helper_unittest.cc',
],
'net_linux_test_sources': [
- 'quic/quic_end_to_end_unittest.cc',
'tools/quic/chlo_extractor_test.cc',
'tools/quic/end_to_end_test.cc',
'tools/quic/quic_client_session_test.cc',
@@ -1880,12 +1977,12 @@
'tools/quic/test_tools/mock_quic_time_wait_list_manager.h',
'tools/quic/test_tools/packet_dropping_test_writer.cc',
'tools/quic/test_tools/packet_dropping_test_writer.h',
+ 'tools/quic/test_tools/packet_reordering_writer.cc',
+ 'tools/quic/test_tools/packet_reordering_writer.h',
'tools/quic/test_tools/quic_client_peer.cc',
'tools/quic/test_tools/quic_client_peer.h',
'tools/quic/test_tools/quic_dispatcher_peer.cc',
'tools/quic/test_tools/quic_dispatcher_peer.h',
- 'tools/quic/test_tools/quic_in_memory_cache_peer.cc',
- 'tools/quic/test_tools/quic_in_memory_cache_peer.h',
'tools/quic/test_tools/quic_server_peer.cc',
'tools/quic/test_tools/quic_server_peer.h',
'tools/quic/test_tools/quic_test_client.cc',
@@ -2048,11 +2145,6 @@
'data/ssl/certificates/aia-cert.pem',
'data/ssl/certificates/aia-intermediate.der',
'data/ssl/certificates/aia-root.pem',
- 'data/ssl/certificates/android-test-key-dsa-public.pem',
- 'data/ssl/certificates/android-test-key-dsa.pem',
- 'data/ssl/certificates/android-test-key-ecdsa-public.pem',
- 'data/ssl/certificates/android-test-key-ecdsa.pem',
- 'data/ssl/certificates/android-test-key-rsa.pem',
'data/ssl/certificates/bad_validity.pem',
'data/ssl/certificates/client-nokey.p12',
'data/ssl/certificates/client.p12',
@@ -2068,6 +2160,11 @@
'data/ssl/certificates/client_3.pem',
'data/ssl/certificates/client_3.pk8',
'data/ssl/certificates/client_3_ca.pem',
+ 'data/ssl/certificates/client_4.key',
+ 'data/ssl/certificates/client_4.pem',
+ 'data/ssl/certificates/client_4.pk8',
+ 'data/ssl/certificates/client_4_ca.pem',
+ 'data/ssl/certificates/client_root_ca.pem',
'data/ssl/certificates/comodo.chain.pem',
'data/ssl/certificates/crit-codeSigning-chain.pem',
'data/ssl/certificates/crlset_by_intermediate_serial.raw',
@@ -2324,22 +2421,19 @@
'data/parse_certificate_unittest/cert_signature_not_bit_string.pem',
'data/parse_certificate_unittest/cert_skeleton.pem',
'data/parse_certificate_unittest/cert_version3.pem',
+ 'data/parse_certificate_unittest/extended_key_usage.pem',
'data/parse_certificate_unittest/extension_critical.pem',
'data/parse_certificate_unittest/extension_critical_0.pem',
'data/parse_certificate_unittest/extension_critical_3.pem',
'data/parse_certificate_unittest/extension_not_critical.pem',
- 'data/parse_certificate_unittest/extensions_basic_constraints.pem',
'data/parse_certificate_unittest/extensions_data_after_sequence.pem',
'data/parse_certificate_unittest/extensions_duplicate_key_usage.pem',
'data/parse_certificate_unittest/extensions_empty_sequence.pem',
- 'data/parse_certificate_unittest/extensions_extended_key_usage.pem',
- 'data/parse_certificate_unittest/extensions_key_usage.pem',
'data/parse_certificate_unittest/extensions_not_sequence.pem',
- 'data/parse_certificate_unittest/extensions_policies.pem',
'data/parse_certificate_unittest/extensions_real.pem',
- 'data/parse_certificate_unittest/extensions_subject_alt_name.pem',
- 'data/parse_certificate_unittest/extensions_unknown_critical.pem',
- 'data/parse_certificate_unittest/extensions_unknown_non_critical.pem',
+ 'data/parse_certificate_unittest/key_usage.pem',
+ 'data/parse_certificate_unittest/policies.pem',
+ 'data/parse_certificate_unittest/subject_alt_name.pem',
'data/parse_certificate_unittest/tbs_explicit_v1.pem',
'data/parse_certificate_unittest/tbs_negative_serial_number.pem',
'data/parse_certificate_unittest/tbs_serial_number_21_octets_leading_0.pem',
@@ -2447,21 +2541,30 @@
'data/url_request_unittest/with-headers.html',
'data/url_request_unittest/with-headers.html.mock-http-headers',
'data/verify_certificate_chain_unittest/basic-constraints-pathlen-0-self-issued.pem',
- 'data/verify_certificate_chain_unittest/expired-intermediary.pem',
- 'data/verify_certificate_chain_unittest/expired-root.pem',
+ 'data/verify_certificate_chain_unittest/constrained-non-self-signed-root.pem',
+ 'data/verify_certificate_chain_unittest/constrained-root-basic-constraints-ca-false.pem',
+ 'data/verify_certificate_chain_unittest/constrained-root-lacks-basic-constraints.pem',
+ 'data/verify_certificate_chain_unittest/expired-constrained-root.pem',
+ 'data/verify_certificate_chain_unittest/expired-intermediate.pem',
'data/verify_certificate_chain_unittest/expired-target-notBefore.pem',
'data/verify_certificate_chain_unittest/expired-target.pem',
- 'data/verify_certificate_chain_unittest/intermediary-basic-constraints-ca-false.pem',
- 'data/verify_certificate_chain_unittest/intermediary-basic-constraints-not-critical.pem',
- 'data/verify_certificate_chain_unittest/intermediary-lacks-basic-constraints.pem',
- 'data/verify_certificate_chain_unittest/intermediary-lacks-signing-key-usage.pem',
- 'data/verify_certificate_chain_unittest/intermediary-signed-with-md5.pem',
- 'data/verify_certificate_chain_unittest/intermediary-unknown-critical-extension.pem',
- 'data/verify_certificate_chain_unittest/intermediary-unknown-non-critical-extension.pem',
+ 'data/verify_certificate_chain_unittest/expired-unconstrained-root.pem',
+ 'data/verify_certificate_chain_unittest/incorrect-trust-anchor.pem',
+ 'data/verify_certificate_chain_unittest/intermediate-basic-constraints-ca-false.pem',
+ 'data/verify_certificate_chain_unittest/intermediate-basic-constraints-not-critical.pem',
+ 'data/verify_certificate_chain_unittest/intermediate-lacks-basic-constraints.pem',
+ 'data/verify_certificate_chain_unittest/intermediate-lacks-signing-key-usage.pem',
+ 'data/verify_certificate_chain_unittest/intermediate-signed-with-md5.pem',
+ 'data/verify_certificate_chain_unittest/intermediate-unknown-critical-extension.pem',
+ 'data/verify_certificate_chain_unittest/intermediate-unknown-non-critical-extension.pem',
'data/verify_certificate_chain_unittest/issuer-and-subject-not-byte-for-byte-equal-anchor.pem',
'data/verify_certificate_chain_unittest/issuer-and-subject-not-byte-for-byte-equal.pem',
+ 'data/verify_certificate_chain_unittest/key-rollover-longrolloverchain.pem',
+ 'data/verify_certificate_chain_unittest/key-rollover-newchain.pem',
+ 'data/verify_certificate_chain_unittest/key-rollover-oldchain.pem',
+ 'data/verify_certificate_chain_unittest/key-rollover-rolloverchain.pem',
'data/verify_certificate_chain_unittest/non-self-signed-root.pem',
- 'data/verify_certificate_chain_unittest/target-and-intermediary.pem',
+ 'data/verify_certificate_chain_unittest/target-and-intermediate.pem',
'data/verify_certificate_chain_unittest/target-has-keycertsign-but-not-ca.pem',
'data/verify_certificate_chain_unittest/target-has-pathlen-but-not-ca.pem',
'data/verify_certificate_chain_unittest/target-not-end-entity.pem',
@@ -2470,9 +2573,12 @@
'data/verify_certificate_chain_unittest/target-signed-with-md5.pem',
'data/verify_certificate_chain_unittest/target-unknown-critical-extension.pem',
'data/verify_certificate_chain_unittest/target-wrong-signature.pem',
- 'data/verify_certificate_chain_unittest/unknown-root.pem',
+ 'data/verify_certificate_chain_unittest/unconstrained-non-self-signed-root.pem',
+ 'data/verify_certificate_chain_unittest/unconstrained-root-basic-constraints-ca-false.pem',
+ 'data/verify_certificate_chain_unittest/unconstrained-root-lacks-basic-constraints.pem',
'data/verify_certificate_chain_unittest/violates-basic-constraints-pathlen-0.pem',
- 'data/verify_certificate_chain_unittest/violates-pathlen-1-root.pem',
+ 'data/verify_certificate_chain_unittest/violates-pathlen-1-constrained-root.pem',
+ 'data/verify_certificate_chain_unittest/violates-pathlen-1-unconstrained-root.pem',
'data/verify_name_match_unittest/names/ascii-BMPSTRING-case_swap-dupe_attr.pem',
'data/verify_name_match_unittest/names/ascii-BMPSTRING-case_swap-extra_attr.pem',
'data/verify_name_match_unittest/names/ascii-BMPSTRING-case_swap-extra_rdn.pem',
diff --git a/chromium/net/net_common.gypi b/chromium/net/net_common.gypi
deleted file mode 100644
index 9f9124455c6..00000000000
--- a/chromium/net/net_common.gypi
+++ /dev/null
@@ -1,366 +0,0 @@
-# Copyright 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 target is included by 'net' target.
- 'type': '<(component)',
- 'variables': { 'enable_wexit_time_destructors': 1, },
- 'dependencies': [
- '../base/base.gyp:base',
- '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../crypto/crypto.gyp:crypto',
- '../sdch/sdch.gyp:sdch',
- '../third_party/boringssl/boringssl.gyp:boringssl',
- '../third_party/protobuf/protobuf.gyp:protobuf_lite',
- '../third_party/zlib/zlib.gyp:zlib',
- '../url/url.gyp:url_url_features',
- 'net_derived_sources',
- 'net_quic_proto',
- 'net_resources',
- ],
- 'sources': [
- '<@(net_nacl_common_sources)',
- '<@(net_non_nacl_sources)',
- ],
- 'defines': [
- 'NET_IMPLEMENTATION',
- ],
- 'export_dependent_settings': [
- '../base/base.gyp:base',
- '../third_party/boringssl/boringssl.gyp:boringssl',
- ],
- 'conditions': [
- ['chromeos==1', {
- 'sources!': [
- 'base/network_change_notifier_linux.cc',
- 'base/network_change_notifier_linux.h',
- 'base/network_change_notifier_netlink_linux.cc',
- 'base/network_change_notifier_netlink_linux.h',
- 'proxy/proxy_config_service_linux.cc',
- 'proxy/proxy_config_service_linux.h',
- ],
- }],
- ['use_kerberos==1', {
- 'defines': [
- 'USE_KERBEROS',
- ],
- 'conditions': [
- ['OS=="openbsd"', {
- 'include_dirs': [
- '/usr/include/kerberosV'
- ],
- }],
- ['linux_link_kerberos==1', {
- 'link_settings': {
- 'ldflags': [
- '<!@(krb5-config --libs gssapi)',
- ],
- },
- }, { # linux_link_kerberos==0
- 'defines': [
- 'DLOPEN_KERBEROS',
- ],
- }],
- ],
- }, { # use_kerberos == 0
- 'sources!': [
- 'http/http_auth_gssapi_posix.cc',
- 'http/http_auth_gssapi_posix.h',
- 'http/http_auth_handler_negotiate.cc',
- 'http/http_auth_handler_negotiate.h',
- ],
- }],
- ['posix_avoid_mmap==1', {
- 'defines': [
- 'POSIX_AVOID_MMAP',
- ],
- 'direct_dependent_settings': {
- 'defines': [
- 'POSIX_AVOID_MMAP',
- ],
- },
- 'sources!': [
- 'disk_cache/blockfile/mapped_file_posix.cc',
- ],
- }, { # else
- 'sources!': [
- 'disk_cache/blockfile/mapped_file_avoid_mmap_posix.cc',
- ],
- }],
- ['disable_file_support!=1', {
- # TODO(mmenke): Should probably get rid of the dependency on
- # net_resources in this case (It's used in net_util, to format
- # directory listings. Also used outside of net/).
- 'sources': ['<@(net_file_support_sources)']
- }],
- ['disable_ftp_support!=1', {
- 'sources': ['<@(net_ftp_support_sources)']
- }],
- ['enable_built_in_dns==1', {
- 'defines': [
- 'ENABLE_BUILT_IN_DNS',
- ]
- }, { # else
- 'sources!': [
- 'dns/address_sorter_posix.cc',
- 'dns/address_sorter_posix.h',
- 'dns/dns_client.cc',
- ],
- }],
- [ 'use_nss_certs == 1', {
- 'dependencies': [
- '../build/linux/system.gyp:nss',
- ],
- }, {
- 'sources!': [
- 'cert/x509_util_nss.h',
- ]
- }
- ],
- ['chromecast==1 and use_nss_certs==1', {
- 'sources': [
- 'ssl/ssl_platform_key_chromecast.cc',
- ],
- 'sources!': [
- 'ssl/ssl_platform_key_nss.cc',
- ],
- }],
- [ 'use_openssl_certs == 0', {
- 'sources!': [
- 'base/crypto_module_openssl.cc',
- 'base/keygen_handler_openssl.cc',
- 'base/openssl_private_key_store.h',
- 'base/openssl_private_key_store_android.cc',
- 'base/openssl_private_key_store_memory.cc',
- 'cert/cert_database_openssl.cc',
- 'cert/cert_verify_proc_openssl.cc',
- 'cert/cert_verify_proc_openssl.h',
- 'cert/test_root_certs_openssl.cc',
- 'cert/x509_certificate_openssl.cc',
- 'ssl/openssl_client_key_store.cc',
- 'ssl/openssl_client_key_store.h',
- ],
- }],
- [ 'use_glib == 1', {
- 'dependencies': [
- '../build/linux/system.gyp:gconf',
- '../build/linux/system.gyp:gio',
- ],
- }],
- [ 'desktop_linux == 1 or chromeos == 1', {
- 'conditions': [
- ['os_bsd==1', {
- 'sources!': [
- 'base/network_change_notifier_linux.cc',
- 'base/network_change_notifier_netlink_linux.cc',
- 'proxy/proxy_config_service_linux.cc',
- ],
- },{
- 'dependencies': [
- '../build/linux/system.gyp:libresolv',
- ],
- }],
- ['OS=="solaris"', {
- 'link_settings': {
- 'ldflags': [
- '-R/usr/lib/mps',
- ],
- },
- }],
- ],
- },
- ],
- [ 'use_nss_certs != 1', {
- 'sources!': [
- 'base/crypto_module_nss.cc',
- 'base/keygen_handler_nss.cc',
- 'cert/cert_database_nss.cc',
- 'cert/cert_verify_proc_nss.cc',
- 'cert/cert_verify_proc_nss.h',
- 'cert/nss_cert_database.cc',
- 'cert/nss_cert_database.h',
- 'cert/nss_cert_database_chromeos.cc',
- 'cert/nss_cert_database_chromeos.h',
- 'cert/nss_profile_filter_chromeos.cc',
- 'cert/nss_profile_filter_chromeos.h',
- 'cert/test_root_certs_nss.cc',
- 'cert/x509_certificate_nss.cc',
- 'cert/x509_util_nss.cc',
- 'cert_net/nss_ocsp.cc',
- 'cert_net/nss_ocsp.h',
- 'ssl/client_cert_store_nss.cc',
- 'ssl/client_cert_store_nss.h',
- 'ssl/client_key_store.cc',
- 'ssl/client_key_store.h',
- 'ssl/ssl_platform_key_nss.cc',
- 'third_party/mozilla_security_manager/nsKeygenHandler.cpp',
- 'third_party/mozilla_security_manager/nsKeygenHandler.h',
- 'third_party/mozilla_security_manager/nsNSSCertificateDB.cpp',
- 'third_party/mozilla_security_manager/nsNSSCertificateDB.h',
- 'third_party/mozilla_security_manager/nsPKCS12Blob.cpp',
- 'third_party/mozilla_security_manager/nsPKCS12Blob.h',
- ],
- },
- ],
- # client_cert_store_nss.c requires NSS_CmpCertChainWCANames from NSS's
- # libssl, but our bundled copy is not built in OpenSSL ports. Pull that
- # file in directly.
- [ 'use_nss_certs == 1', {
- 'sources': [
- 'third_party/nss/ssl/cmpcert.c',
- ],
- }],
- [ 'enable_websockets == 1', {
- 'defines': ['ENABLE_WEBSOCKETS'],
- 'sources': ['<@(net_websockets_sources)']
- }],
- [ 'enable_mdns != 1', {
- 'sources!' : [
- 'dns/mdns_cache.cc',
- 'dns/mdns_cache.h',
- 'dns/mdns_client.cc',
- 'dns/mdns_client.h',
- 'dns/mdns_client_impl.cc',
- 'dns/mdns_client_impl.h',
- 'dns/record_parsed.cc',
- 'dns/record_parsed.h',
- 'dns/record_rdata.cc',
- 'dns/record_rdata.h',
- ]
- }],
- [ 'OS == "win"', {
- 'sources!': [
- 'http/http_auth_handler_ntlm_portable.cc',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [4267, ],
- 'all_dependent_settings': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalDependencies': [
- 'crypt32.lib',
- 'dhcpcsvc.lib',
- 'iphlpapi.lib',
- 'rpcrt4.lib',
- 'secur32.lib',
- 'urlmon.lib',
- 'winhttp.lib',
- ],
- },
- },
- },
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalDependencies': [
- 'crypt32.lib',
- 'dhcpcsvc.lib',
- 'iphlpapi.lib',
- 'rpcrt4.lib',
- 'secur32.lib',
- 'urlmon.lib',
- 'winhttp.lib',
- ],
- },
- },
- }, { # else: OS != "win"
- 'sources!': [
- 'base/winsock_init.cc',
- 'base/winsock_init.h',
- 'base/winsock_util.cc',
- 'base/winsock_util.h',
- 'proxy/proxy_resolver_winhttp.cc',
- 'proxy/proxy_resolver_winhttp.h',
- ],
- },
- ],
- [ 'OS == "mac"', {
- 'link_settings': {
- 'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
- '$(SDKROOT)/System/Library/Frameworks/Security.framework',
- '$(SDKROOT)/System/Library/Frameworks/SystemConfiguration.framework',
- '$(SDKROOT)/usr/lib/libresolv.dylib',
- ]
- },
- },
- ],
- [ 'OS == "ios"', {
- 'sources!': [
- 'disk_cache/blockfile/file_posix.cc',
- ],
- 'link_settings': {
- 'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/CFNetwork.framework',
- '$(SDKROOT)/System/Library/Frameworks/MobileCoreServices.framework',
- '$(SDKROOT)/System/Library/Frameworks/Security.framework',
- '$(SDKROOT)/System/Library/Frameworks/SystemConfiguration.framework',
- ],
- 'xcode_settings': {
- 'OTHER_LDFLAGS': [
- '-lresolv',
- ],
- },
- },
- },
- ],
- [ 'OS == "ios" or OS == "mac"', {
- 'sources': [
- '<@(net_base_mac_ios_sources)',
- ],
- },
- ],
- ['OS=="android" and _toolset=="target"', {
- 'dependencies': [
- 'net_java',
- ],
- }],
- [ 'OS == "android"', {
- 'dependencies': [
- 'net_jni_headers',
- ],
- 'sources!': [
- 'base/openssl_private_key_store_memory.cc',
- 'cert/cert_database_openssl.cc',
- 'cert/cert_verify_proc_openssl.cc',
- 'cert/test_root_certs_openssl.cc',
- 'http/http_auth_gssapi_posix.cc',
- 'http/http_auth_gssapi_posix.h',
- ],
- },
- ],
- ],
- 'target_conditions': [
- # These source files are excluded by default platform rules, but they
- # are needed in specific cases on other platforms. Re-including them can
- # only be done in target_conditions as it is evaluated after the
- # platform rules.
- ['OS == "android"', {
- 'sources/': [
- ['include', '^base/platform_mime_util_linux\\.cc$'],
- ['include', '^base/address_tracker_linux\\.cc$'],
- ['include', '^base/address_tracker_linux\\.h$'],
- ['include', '^base/network_interfaces_linux\\.cc$'],
- ['include', '^base/network_interfaces_linux\\.h$'],
- ],
- }],
- ['OS == "ios"', {
- 'sources/': [
- ['include', '^base/mac/url_conversions\\.h$'],
- ['include', '^base/mac/url_conversions\\.mm$'],
- ['include', '^base/network_change_notifier_mac\\.cc$'],
- ['include', '^base/network_config_watcher_mac\\.cc$'],
- ['include', '^base/network_interfaces_mac\\.cc$'],
- ['include', '^base/network_interfaces_mac\\.h$'],
- ['include', '^base/platform_mime_util_mac\\.mm$'],
- ['include', '^proxy/proxy_resolver_mac\\.cc$'],
- ['include', '^proxy/proxy_server_mac\\.cc$'],
- ],
- }],
- ['OS == "ios"', {
- 'sources/': [
- ['include', '^cert/test_root_certs_mac\\.cc$'],
- ],
- }],
- ],
-}
diff --git a/chromium/net/net_nacl.gyp b/chromium/net/net_nacl.gyp
deleted file mode 100644
index 14c345c23a6..00000000000
--- a/chromium/net/net_nacl.gyp
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'includes': [
- '../native_client/build/untrusted.gypi',
- 'net.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'net_nacl',
- 'type': 'none',
- 'variables': {
- 'nacl_untrusted_build': 1,
- 'nlib_target': 'libnet_nacl.a',
- 'build_glibc': 0,
- 'build_newlib': 0,
- 'build_pnacl_newlib': 1,
- },
- 'dependencies': [
- '../crypto/crypto_nacl.gyp:crypto_nacl',
- '../native_client_sdk/native_client_sdk_untrusted.gyp:nacl_io_untrusted',
- '../third_party/boringssl/boringssl_nacl.gyp:boringssl_nacl',
- '../third_party/protobuf/protobuf.gyp:protobuf_lite',
- '../url/url_nacl.gyp:url_nacl',
- 'net.gyp:net_derived_sources',
- 'net.gyp:net_quic_proto',
- 'net.gyp:net_resources',
- ],
- 'defines': [
- 'NET_IMPLEMENTATION',
- ],
- 'pnacl_compile_flags': [
- '-Wno-bind-to-temporary-copy',
- ],
- 'sources': [
- '<@(net_nacl_common_sources)',
- ],
- },
- ],
-}
diff --git a/chromium/net/net_unittests.isolate b/chromium/net/net_unittests.isolate
deleted file mode 100644
index 7d00f054b60..00000000000
--- a/chromium/net/net_unittests.isolate
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-{
- 'conditions': [
- ['OS=="android" or OS=="linux" or OS=="mac" or OS=="win"', {
- 'variables': {
- 'files': [
- 'data/',
- 'third_party/nist-pkits/certs/',
- 'third_party/nist-pkits/crls/',
- ],
- },
- }],
- ['OS=="linux" or OS=="mac" or OS=="win"', {
- 'variables': {
- 'command': [
- '../testing/test_env.py',
- '<(PRODUCT_DIR)/net_unittests<(EXECUTABLE_SUFFIX)',
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- '--asan=<(asan)',
- '--msan=<(msan)',
- '--tsan=<(tsan)',
- ],
- 'files': [
- '../testing/test_env.py',
- '../third_party/pyftpdlib/',
- '../third_party/pywebsocket/',
- '../third_party/tlslite/',
- '<(PRODUCT_DIR)/pyproto/google/',
- 'tools/testserver/',
- ],
- },
- }],
- ['OS=="mac" and asan==1 and fastbuild==0', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/net_unittests.dSYM/',
- ],
- },
- }],
- ['OS=="win" and (fastbuild==0 or fastbuild==1)', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/net_unittests.exe.pdb',
- ],
- },
- }],
- ],
- 'includes': [
- '../base/base.isolate',
- '../gin/v8.isolate',
- ],
-}
diff --git a/chromium/net/net_unittests_apk.isolate b/chromium/net/net_unittests_apk.isolate
deleted file mode 100644
index 07ef7280ca9..00000000000
--- a/chromium/net/net_unittests_apk.isolate
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 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.
-{
- 'includes': [
- '../build/android/android.isolate',
- 'net_unittests.isolate',
- 'tools/testserver/testserver.isolate',
- ],
- 'variables': {
- 'command': [
- '<(PRODUCT_DIR)/bin/run_net_unittests',
- '--logcat-output-dir', '${ISOLATED_OUTDIR}/logcats',
- ],
- 'files': [
- '../base/base.isolate',
- '../build/config/',
- '../gin/v8.isolate',
- '../third_party/icu/icu.isolate',
- '../third_party/instrumented_libraries/instrumented_libraries.isolate',
- '<(PRODUCT_DIR)/bin/run_net_unittests',
- '<(PRODUCT_DIR)/net_unittests_apk/',
- 'net_unittests.isolate',
- ]
- },
-}
diff --git a/chromium/net/nqe/cached_network_quality.cc b/chromium/net/nqe/cached_network_quality.cc
index 5902f75a08d..8b65c34c6a2 100644
--- a/chromium/net/nqe/cached_network_quality.cc
+++ b/chromium/net/nqe/cached_network_quality.cc
@@ -10,17 +10,25 @@ namespace nqe {
namespace internal {
+CachedNetworkQuality::CachedNetworkQuality()
+ : effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {}
+
CachedNetworkQuality::CachedNetworkQuality(
- const NetworkQuality& network_quality)
- : last_update_time_(base::TimeTicks::Now()),
- network_quality_(network_quality) {}
+ base::TimeTicks last_update_time,
+ const NetworkQuality& network_quality,
+ EffectiveConnectionType effective_connection_type)
+ : last_update_time_(last_update_time),
+ network_quality_(network_quality),
+ effective_connection_type_(effective_connection_type) {}
-CachedNetworkQuality::CachedNetworkQuality(const CachedNetworkQuality& other)
- : last_update_time_(other.last_update_time_),
- network_quality_(other.network_quality_) {}
+CachedNetworkQuality::CachedNetworkQuality(const CachedNetworkQuality& other) =
+ default;
CachedNetworkQuality::~CachedNetworkQuality() {}
+CachedNetworkQuality& CachedNetworkQuality::operator=(
+ const CachedNetworkQuality& other) = default;
+
bool CachedNetworkQuality::OlderThan(
const CachedNetworkQuality& cached_network_quality) const {
return last_update_time_ < cached_network_quality.last_update_time_;
diff --git a/chromium/net/nqe/cached_network_quality.h b/chromium/net/nqe/cached_network_quality.h
index cc0af2f1b8d..4aeebd74f05 100644
--- a/chromium/net/nqe/cached_network_quality.h
+++ b/chromium/net/nqe/cached_network_quality.h
@@ -5,9 +5,9 @@
#ifndef NET_NQE_CACHED_NETWORK_QUALITY_H_
#define NET_NQE_CACHED_NETWORK_QUALITY_H_
-#include "base/macros.h"
#include "base/time/time.h"
#include "net/base/net_export.h"
+#include "net/nqe/effective_connection_type.h"
#include "net/nqe/network_quality.h"
namespace net {
@@ -19,25 +19,41 @@ namespace internal {
// CachedNetworkQuality stores the quality of a previously seen network.
class NET_EXPORT_PRIVATE CachedNetworkQuality {
public:
- explicit CachedNetworkQuality(const NetworkQuality& network_quality);
+ CachedNetworkQuality();
+
+ // |last_update_time| is the time when the |network_quality| was computed.
+ CachedNetworkQuality(base::TimeTicks last_update_time,
+ const NetworkQuality& network_quality,
+ EffectiveConnectionType effective_connection_type);
CachedNetworkQuality(const CachedNetworkQuality& other);
~CachedNetworkQuality();
// Returns the network quality associated with this cached entry.
const NetworkQuality& network_quality() const { return network_quality_; }
+ CachedNetworkQuality& operator=(const CachedNetworkQuality& other);
+
// Returns true if this cache entry was updated before
// |cached_network_quality|.
bool OlderThan(const CachedNetworkQuality& cached_network_quality) const;
+ 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_;
+ }
+
+ private:
// Time when this cache entry was last updated.
- const base::TimeTicks last_update_time_;
+ base::TimeTicks last_update_time_;
// Quality of this cached network.
- const NetworkQuality network_quality_;
+ NetworkQuality network_quality_;
- private:
- DISALLOW_ASSIGN(CachedNetworkQuality);
+ // Effective connection type of the cached network.
+ EffectiveConnectionType effective_connection_type_;
};
} // namespace internal
diff --git a/chromium/net/nqe/effective_connection_type.cc b/chromium/net/nqe/effective_connection_type.cc
new file mode 100644
index 00000000000..94908d4c046
--- /dev/null
+++ b/chromium/net/nqe/effective_connection_type.cc
@@ -0,0 +1,74 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/nqe/effective_connection_type.h"
+
+#include "base/logging.h"
+
+namespace {
+
+const char kEffectiveConnectionTypeUnknown[] = "Unknown";
+const char kEffectiveConnectionTypeOffline[] = "Offline";
+const char kEffectiveConnectionTypeSlow2G[] = "Slow2G";
+const char kEffectiveConnectionType2G[] = "2G";
+const char kEffectiveConnectionType3G[] = "3G";
+const char kEffectiveConnectionType4G[] = "4G";
+
+} // namespace
+
+namespace net {
+
+const char* GetNameForEffectiveConnectionType(EffectiveConnectionType type) {
+ switch (type) {
+ case EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
+ return kEffectiveConnectionTypeUnknown;
+ case EFFECTIVE_CONNECTION_TYPE_OFFLINE:
+ return kEffectiveConnectionTypeOffline;
+ case EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
+ return kEffectiveConnectionTypeSlow2G;
+ case EFFECTIVE_CONNECTION_TYPE_2G:
+ return kEffectiveConnectionType2G;
+ case EFFECTIVE_CONNECTION_TYPE_3G:
+ return kEffectiveConnectionType3G;
+ case EFFECTIVE_CONNECTION_TYPE_4G:
+ return kEffectiveConnectionType4G;
+ default:
+ NOTREACHED();
+ break;
+ }
+ return "";
+}
+
+bool GetEffectiveConnectionTypeForName(
+ const std::string& connection_type_name,
+ EffectiveConnectionType* effective_connection_type) {
+ if (connection_type_name == kEffectiveConnectionTypeUnknown) {
+ *effective_connection_type = EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+ return true;
+ }
+ if (connection_type_name == kEffectiveConnectionTypeOffline) {
+ *effective_connection_type = EFFECTIVE_CONNECTION_TYPE_OFFLINE;
+ return true;
+ }
+ if (connection_type_name == kEffectiveConnectionTypeSlow2G) {
+ *effective_connection_type = EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
+ return true;
+ }
+ if (connection_type_name == kEffectiveConnectionType2G) {
+ *effective_connection_type = EFFECTIVE_CONNECTION_TYPE_2G;
+ return true;
+ }
+ if (connection_type_name == kEffectiveConnectionType3G) {
+ *effective_connection_type = EFFECTIVE_CONNECTION_TYPE_3G;
+ return true;
+ }
+ if (connection_type_name == kEffectiveConnectionType4G) {
+ *effective_connection_type = EFFECTIVE_CONNECTION_TYPE_4G;
+ return true;
+ }
+ *effective_connection_type = EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+ return false;
+}
+
+} // namespace net \ No newline at end of file
diff --git a/chromium/net/nqe/effective_connection_type.h b/chromium/net/nqe/effective_connection_type.h
new file mode 100644
index 00000000000..a40618bb78b
--- /dev/null
+++ b/chromium/net/nqe/effective_connection_type.h
@@ -0,0 +1,70 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_NQE_EFFECTIVE_CONNECTION_TYPE_H_
+#define NET_NQE_EFFECTIVE_CONNECTION_TYPE_H_
+
+#include <string>
+
+#include "net/base/net_export.h"
+
+namespace net {
+
+// EffectiveConnectionType is the connection type whose typical performance is
+// most similar to the measured performance of the network in use. In many
+// cases, the "effective" connection type and the actual type of connection in
+// use are the same, but often a network connection performs significantly
+// differently, usually worse, from its expected capabilities.
+// EffectiveConnectionType of a network is independent of if the current
+// connection is metered or not. For example, an unmetered slow connection may
+// have EFFECTIVE_CONNECTION_TYPE_SLOW_2G as its effective connection type. The
+// effective connection type enums are be in increasing order of quality.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.net
+// GENERATED_JAVA_PREFIX_TO_STRIP: EFFECTIVE_CONNECTION_
+enum EffectiveConnectionType {
+ // Effective connection type reported when the network quality is unknown.
+ EFFECTIVE_CONNECTION_TYPE_UNKNOWN = 0,
+
+ // Effective connection type reported when the Internet is unreachable, either
+ // because the device does not have a connection or because the
+ // connection is too slow to be usable.
+ EFFECTIVE_CONNECTION_TYPE_OFFLINE,
+
+ // Effective connection type reported when the network has the quality of a
+ // poor 2G connection.
+ EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
+
+ // Effective connection type reported when the network has the quality of a
+ // faster 2G connection.
+ EFFECTIVE_CONNECTION_TYPE_2G,
+
+ // Effective connection type reported when the network has the quality of a 3G
+ // connection.
+ EFFECTIVE_CONNECTION_TYPE_3G,
+
+ // Effective connection type reported when the network has the quality of a 4G
+ // connection.
+ EFFECTIVE_CONNECTION_TYPE_4G,
+
+ // Last value of the effective connection type. This value is unused.
+ EFFECTIVE_CONNECTION_TYPE_LAST,
+};
+
+// Returns the string equivalent of |type|.
+NET_EXPORT const char* GetNameForEffectiveConnectionType(
+ EffectiveConnectionType type);
+
+// Returns true if the EffectiveConnectionType that corresponds to
+// |connection_type_name| is available, and sets |effective_connection_type| to
+// that value. If the effective connection type is unavailable, false is
+// returned, and |effective_connection_type| is set to
+// EFFECTIVE_CONNECTION_TYPE_UNKNOWN. |effective_connection_type| must be
+// non-null.
+NET_EXPORT bool GetEffectiveConnectionTypeForName(
+ const std::string& connection_type_name,
+ EffectiveConnectionType* effective_connection_type);
+
+} // namespace net
+
+#endif // NET_NQE_EFFECTIVE_CONNECTION_TYPE_H_
diff --git a/chromium/net/nqe/effective_connection_type_unittest.cc b/chromium/net/nqe/effective_connection_type_unittest.cc
new file mode 100644
index 00000000000..f5dffba9eb9
--- /dev/null
+++ b/chromium/net/nqe/effective_connection_type_unittest.cc
@@ -0,0 +1,53 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/nqe/effective_connection_type.h"
+
+#include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+// Tests that the effective connection type is converted correctly to a
+// descriptive string name, and vice-versa.
+TEST(EffectiveConnectionTypeTest, NameConnectionTypeConversion) {
+ // Initialize |converted_effective_connection_type| to a value other than
+ // EFFECTIVE_CONNECTION_TYPE_UNKNOWN, and verify that it is set to
+ // EFFECTIVE_CONNECTION_TYPE_UNKNOWN when an invalid effective connection
+ // type name is provided.
+ EffectiveConnectionType converted_effective_connection_type =
+ EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
+ EXPECT_FALSE(
+ GetEffectiveConnectionTypeForName("InvalidEffectiveConnectionTypeName",
+ &converted_effective_connection_type));
+ EXPECT_EQ(EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+ converted_effective_connection_type);
+
+ // Reset |converted_effective_connection_type| to a value other than
+ // EFFECTIVE_CONNECTION_TYPE_UNKNOWN.
+ converted_effective_connection_type = EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
+ EXPECT_FALSE(GetEffectiveConnectionTypeForName(
+ std::string(), &converted_effective_connection_type));
+ EXPECT_EQ(EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+ converted_effective_connection_type);
+
+ for (size_t i = 0; i < EFFECTIVE_CONNECTION_TYPE_LAST; ++i) {
+ const EffectiveConnectionType effective_connection_type =
+ static_cast<EffectiveConnectionType>(i);
+ std::string connection_type_name = std::string(
+ GetNameForEffectiveConnectionType(effective_connection_type));
+ EXPECT_FALSE(connection_type_name.empty());
+
+ EXPECT_TRUE(GetEffectiveConnectionTypeForName(
+ connection_type_name, &converted_effective_connection_type));
+ EXPECT_EQ(effective_connection_type, converted_effective_connection_type);
+ }
+}
+
+} // namespace
+
+} // namespace net \ No newline at end of file
diff --git a/chromium/net/nqe/network_id.h b/chromium/net/nqe/network_id.h
new file mode 100644
index 00000000000..4620ce3bd92
--- /dev/null
+++ b/chromium/net/nqe/network_id.h
@@ -0,0 +1,68 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_NQE_NETWORK_ID_H_
+#define NET_NQE_NETWORK_ID_H_
+
+#include <string>
+#include <tuple>
+
+#include "net/base/net_export.h"
+#include "net/base/network_change_notifier.h"
+
+namespace {
+const char kValueSeparator[] = ",";
+}
+
+namespace net {
+namespace nqe {
+namespace internal {
+
+// NetworkID is used to uniquely identify a network.
+// For the purpose of network quality estimation and caching, a network is
+// uniquely identified by a combination of |type| and
+// |id|. This approach is unable to distinguish networks with
+// same name (e.g., different Wi-Fi networks with same SSID).
+// This is a protected member to expose it to tests.
+struct NET_EXPORT_PRIVATE NetworkID {
+ NetworkID(NetworkChangeNotifier::ConnectionType type, const std::string& id)
+ : type(type), id(id) {}
+ NetworkID(const NetworkID& other) : type(other.type), id(other.id) {}
+ ~NetworkID() {}
+
+ NetworkID& operator=(const NetworkID& other) {
+ type = other.type;
+ id = other.id;
+ return *this;
+ }
+
+ // Overloaded to support ordered collections.
+ bool operator<(const NetworkID& other) const {
+ return std::tie(type, id) < std::tie(other.type, other.id);
+ }
+
+ std::string ToString() const {
+ return id + kValueSeparator +
+ NetworkChangeNotifier::ConnectionTypeToString(type);
+ }
+
+ // Connection type of the network.
+ NetworkChangeNotifier::ConnectionType type;
+
+ // Name of this network. This is set to:
+ // - Wi-Fi SSID if the device is connected to a Wi-Fi access point and the
+ // SSID name is available, or
+ // - MCC/MNC code of the cellular carrier if the device is connected to a
+ // cellular network, or
+ // - "Ethernet" in case the device is connected to ethernet.
+ // - An empty string in all other cases or if the network name is not
+ // exposed by platform APIs.
+ std::string id;
+};
+
+} // namespace internal
+} // namespace nqe
+} // namespace net
+
+#endif // NET_NQE_NETWORK_QUALITY_ESTIMATOR_H_ \ No newline at end of file
diff --git a/chromium/net/nqe/network_qualities_prefs_manager.cc b/chromium/net/nqe/network_qualities_prefs_manager.cc
new file mode 100644
index 00000000000..bddfa06e821
--- /dev/null
+++ b/chromium/net/nqe/network_qualities_prefs_manager.cc
@@ -0,0 +1,80 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/nqe/network_qualities_prefs_manager.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/values.h"
+#include "net/nqe/cached_network_quality.h"
+#include "net/nqe/network_quality_estimator.h"
+
+namespace net {
+
+NetworkQualitiesPrefsManager::NetworkQualitiesPrefsManager(
+ std::unique_ptr<PrefDelegate> pref_delegate)
+ : pref_delegate_(std::move(pref_delegate)),
+ pref_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ network_quality_estimator_(nullptr),
+ pref_weak_ptr_factory_(this) {
+ DCHECK(pref_delegate_);
+
+ pref_weak_ptr_ = pref_weak_ptr_factory_.GetWeakPtr();
+}
+
+NetworkQualitiesPrefsManager::~NetworkQualitiesPrefsManager() {
+ DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
+ if (network_quality_estimator_)
+ network_quality_estimator_->RemoveNetworkQualitiesCacheObserver(this);
+}
+
+void NetworkQualitiesPrefsManager::InitializeOnNetworkThread(
+ NetworkQualityEstimator* network_quality_estimator) {
+ DCHECK(!network_task_runner_);
+ DCHECK(network_quality_estimator);
+
+ network_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ network_quality_estimator_ = network_quality_estimator;
+ network_quality_estimator_->AddNetworkQualitiesCacheObserver(this);
+}
+
+void NetworkQualitiesPrefsManager::OnChangeInCachedNetworkQuality(
+ const nqe::internal::NetworkID& network_id,
+ const nqe::internal::CachedNetworkQuality& cached_network_quality) {
+ DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
+
+ // Notify |this| on the pref thread.
+ pref_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&NetworkQualitiesPrefsManager::
+ OnChangeInCachedNetworkQualityOnPrefThread,
+ pref_weak_ptr_, network_id, cached_network_quality));
+}
+
+void NetworkQualitiesPrefsManager::ShutdownOnPrefThread() {
+ DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
+ pref_delegate_.reset();
+}
+
+void NetworkQualitiesPrefsManager::OnChangeInCachedNetworkQualityOnPrefThread(
+ const nqe::internal::NetworkID& network_id,
+ const nqe::internal::CachedNetworkQuality& cached_network_quality) {
+ // The prefs can only be written on the pref thread.
+ DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
+
+ base::DictionaryValue dictionary_value;
+ dictionary_value.SetString(
+ network_id.ToString(),
+ GetNameForEffectiveConnectionType(
+ cached_network_quality.effective_connection_type()));
+
+ // Notify the pref delegate so that it updates the prefs on the disk.
+ pref_delegate_->SetDictionaryValue(dictionary_value);
+}
+
+} // namespace net
diff --git a/chromium/net/nqe/network_qualities_prefs_manager.h b/chromium/net/nqe/network_qualities_prefs_manager.h
new file mode 100644
index 00000000000..99784096068
--- /dev/null
+++ b/chromium/net/nqe/network_qualities_prefs_manager.h
@@ -0,0 +1,104 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_NQE_NETWORK_QUALITIES_PREFS_MANAGER_H_
+#define NET_NQE_NETWORK_QUALITIES_PREFS_MANAGER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "net/base/net_export.h"
+#include "net/nqe/effective_connection_type.h"
+#include "net/nqe/network_id.h"
+#include "net/nqe/network_quality_store.h"
+
+namespace base {
+class DictionaryValue;
+class SequencedTaskRunner;
+}
+
+namespace net {
+namespace nqe {
+namespace internal {
+class CachedNetworkQuality;
+}
+}
+class NetworkQualityEstimator;
+
+typedef base::Callback<void(
+ const nqe::internal::NetworkID& network_id,
+ const nqe::internal::CachedNetworkQuality& cached_network_quality)>
+ OnChangeInCachedNetworkQualityCallback;
+
+// Using the provided PrefDelegate, NetworkQualitiesPrefsManager creates and
+// updates network quality information that is stored in prefs. Instances of
+// this class must be constructed on the pref thread, and should later be moved
+// to the network thread by calling InitializeOnNetworkThread.
+//
+// This class interacts with both the pref thread and the network thread, and
+// propagates network quality pref changes from the network thread to the
+// provided pref delegate on the pref thread.
+//
+// ShutdownOnPrefThread must be called from the pref thread before destruction.
+class NET_EXPORT NetworkQualitiesPrefsManager
+ : public nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver {
+ public:
+ // Provides an interface that must be implemented by the embedder.
+ class NET_EXPORT PrefDelegate {
+ public:
+ // Sets the persistent pref to the given value.
+ virtual void SetDictionaryValue(const base::DictionaryValue& value) = 0;
+ };
+
+ // Creates an instance of the NetworkQualitiesPrefsManager. Ownership of
+ // |pref_delegate| is taken by this class. Must be constructed on the pref
+ // thread, and then moved to network thread.
+ explicit NetworkQualitiesPrefsManager(
+ std::unique_ptr<PrefDelegate> pref_delegate);
+ ~NetworkQualitiesPrefsManager() override;
+
+ // Initialize on the Network thread.
+ void InitializeOnNetworkThread(
+ NetworkQualityEstimator* network_quality_estimator);
+
+ // Prepare for shutdown. Must be called on the pref thread before destruction.
+ void ShutdownOnPrefThread();
+
+ private:
+ // Pref thread members:
+ // Called on pref thread when there is a change in the cached network quality.
+ void OnChangeInCachedNetworkQualityOnPrefThread(
+ const nqe::internal::NetworkID& network_id,
+ const nqe::internal::CachedNetworkQuality& cached_network_quality);
+
+ // Responsible for writing the persistent prefs to the disk.
+ std::unique_ptr<PrefDelegate> pref_delegate_;
+
+ scoped_refptr<base::SequencedTaskRunner> pref_task_runner_;
+
+ // Should be accessed only on the pref thread.
+ base::WeakPtr<NetworkQualitiesPrefsManager> pref_weak_ptr_;
+
+ // Network thread members:
+ // nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver
+ // implementation:
+ void OnChangeInCachedNetworkQuality(
+ const nqe::internal::NetworkID& network_id,
+ const nqe::internal::CachedNetworkQuality& cached_network_quality)
+ override;
+
+ NetworkQualityEstimator* network_quality_estimator_;
+
+ scoped_refptr<base::SequencedTaskRunner> network_task_runner_;
+
+ // Used to get |weak_ptr_| to self on the pref thread.
+ base::WeakPtrFactory<NetworkQualitiesPrefsManager> pref_weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkQualitiesPrefsManager);
+};
+
+} // namespace net
+
+#endif // NET_NQE_NETWORK_QUALITIES_PREFS_MANAGER_H_
diff --git a/chromium/net/nqe/network_qualities_prefs_manager_unittest.cc b/chromium/net/nqe/network_qualities_prefs_manager_unittest.cc
new file mode 100644
index 00000000000..cfd659ba67c
--- /dev/null
+++ b/chromium/net/nqe/network_qualities_prefs_manager_unittest.cc
@@ -0,0 +1,75 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/nqe/network_qualities_prefs_manager.h"
+
+#include <map>
+#include <memory>
+
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/values.h"
+#include "net/base/network_change_notifier.h"
+#include "net/nqe/effective_connection_type.h"
+#include "net/nqe/network_quality_estimator_test_util.h"
+#include "net/nqe/network_quality_store.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+class MockPrefDelegate : public NetworkQualitiesPrefsManager::PrefDelegate {
+ public:
+ MockPrefDelegate() : write_count_(0) {}
+ ~MockPrefDelegate() {}
+
+ void SetDictionaryValue(const base::DictionaryValue& value) override {
+ write_count_++;
+ }
+
+ size_t write_count() const { return write_count_; }
+
+ private:
+ // Number of times prefs were written.
+ mutable size_t write_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockPrefDelegate);
+};
+
+TEST(NetworkQualitiesPrefManager, Write) {
+ std::map<std::string, std::string> variation_params;
+ TestNetworkQualityEstimator estimator(variation_params, nullptr);
+
+ std::unique_ptr<MockPrefDelegate> prefs_delegate(new MockPrefDelegate());
+ MockPrefDelegate* prefs_delegate_ptr = prefs_delegate.get();
+
+ NetworkQualitiesPrefsManager manager(std::move(prefs_delegate));
+ manager.InitializeOnNetworkThread(&estimator);
+ base::RunLoop().RunUntilIdle();
+
+ estimator.SimulateNetworkChange(
+ NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test");
+ EXPECT_EQ(0u, 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(1u, 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(2u, prefs_delegate_ptr->write_count());
+
+ manager.ShutdownOnPrefThread();
+}
+
+} // namespace
+
+} // namespace net \ No newline at end of file
diff --git a/chromium/net/nqe/network_quality.cc b/chromium/net/nqe/network_quality.cc
index 94bcc80357d..6831dd4b213 100644
--- a/chromium/net/nqe/network_quality.cc
+++ b/chromium/net/nqe/network_quality.cc
@@ -5,9 +5,7 @@
#include "net/nqe/network_quality.h"
namespace net {
-
namespace nqe {
-
namespace internal {
base::TimeDelta InvalidRTT() {
@@ -40,8 +38,23 @@ NetworkQuality& NetworkQuality::operator=(const NetworkQuality& other) {
return *this;
}
-} // namespace internal
+bool NetworkQuality::operator==(const NetworkQuality& other) const {
+ return http_rtt_ == other.http_rtt_ &&
+ transport_rtt_ == other.transport_rtt_ &&
+ downstream_throughput_kbps_ == other.downstream_throughput_kbps_;
+}
-} // namespace nqe
+bool NetworkQuality::IsFaster(const NetworkQuality& other) const {
+ return (http_rtt() == InvalidRTT() || other.http_rtt() == InvalidRTT() ||
+ http_rtt() <= other.http_rtt()) &&
+ (transport_rtt() == InvalidRTT() ||
+ other.transport_rtt() == InvalidRTT() ||
+ transport_rtt() <= other.transport_rtt()) &&
+ (downstream_throughput_kbps() == kInvalidThroughput ||
+ other.downstream_throughput_kbps() == kInvalidThroughput ||
+ downstream_throughput_kbps() >= other.downstream_throughput_kbps());
+}
+} // namespace internal
+} // namespace nqe
} // namespace net \ No newline at end of file
diff --git a/chromium/net/nqe/network_quality.h b/chromium/net/nqe/network_quality.h
index 2c7372fd898..457c71e8887 100644
--- a/chromium/net/nqe/network_quality.h
+++ b/chromium/net/nqe/network_quality.h
@@ -13,9 +13,7 @@
#include "net/base/net_export.h"
namespace net {
-
namespace nqe {
-
namespace internal {
// Returns the RTT value to be used when the valid RTT is unavailable. Readers
@@ -43,18 +41,34 @@ class NET_EXPORT_PRIVATE NetworkQuality {
NetworkQuality& operator=(const NetworkQuality& other);
+ bool operator==(const NetworkQuality& other) const;
+
+ // Returns true if |this| is at least as fast as |other| for all parameters
+ // (HTTP RTT, transport RTT etc.)
+ 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_; }
+ void set_http_rtt(const base::TimeDelta& http_rtt) { http_rtt_ = http_rtt; }
+
// Returns the estimate of the round trip time at the transport layer.
const base::TimeDelta& transport_rtt() const { return transport_rtt_; }
+ void set_transport_rtt(const base::TimeDelta& transport_rtt) {
+ transport_rtt_ = transport_rtt;
+ }
+
// Returns the estimate of the downstream throughput in Kbps (Kilobits per
// second).
int32_t downstream_throughput_kbps() const {
return downstream_throughput_kbps_;
}
+ void set_downstream_throughput_kbps(int32_t downstream_throughput_kbps) {
+ downstream_throughput_kbps_ = downstream_throughput_kbps;
+ }
+
private:
// Estimated round trip time at the HTTP layer.
base::TimeDelta http_rtt_;
@@ -67,9 +81,7 @@ class NET_EXPORT_PRIVATE NetworkQuality {
};
} // namespace internal
-
} // namespace nqe
-
} // namespace net
#endif // NET_NQE_NETWORK_QUALITY_H_ \ No newline at end of file
diff --git a/chromium/net/nqe/network_quality_estimator.cc b/chromium/net/nqe/network_quality_estimator.cc
index 3756629a07e..f97084a10be 100644
--- a/chromium/net/nqe/network_quality_estimator.cc
+++ b/chromium/net/nqe/network_quality_estimator.cc
@@ -15,8 +15,12 @@
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_base.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/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_tick_clock.h"
#include "base/trace_event/trace_event.h"
@@ -25,12 +29,15 @@
#include "net/base/load_timing_info.h"
#include "net/base/network_interfaces.h"
#include "net/base/url_util.h"
+#include "net/http/http_status_code.h"
#include "net/nqe/socket_watcher_factory.h"
#include "net/nqe/throughput_analyzer.h"
#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_status.h"
#include "url/gurl.h"
#if defined(OS_ANDROID)
+#include "net/android/cellular_signal_strength.h"
#include "net/android/network_library.h"
#endif // OS_ANDROID
@@ -93,6 +100,13 @@ const char kDefaultKbpsObservationSuffix[] = ".DefaultMedianKbps";
const char kThresholdURLRTTMsecSuffix[] = ".ThresholdMedianHttpRTTMsec";
// Suffix of the name of the variation parameter that contains the threshold
+// transport RTTs (in milliseconds) for different effective connection types.
+// Complete name of the variation parameter would be
+// |EffectiveConnectionType|.|kThresholdTransportRTTMsecSuffix|.
+const char kThresholdTransportRTTMsecSuffix[] =
+ ".ThresholdMedianTransportRTTMsec";
+
+// Suffix of the name of the variation parameter that contains the threshold
// downlink throughput (in kbps) for different effective connection types.
// Complete name of the variation parameter would be
// |EffectiveConnectionType|.|kThresholdKbpsSuffix|.
@@ -132,13 +146,48 @@ base::HistogramBase* GetHistogram(
max_limit, kBucketCount, base::HistogramBase::kUmaTargetedHistogramFlag);
}
-bool GetValueForVariationParam(
+// Sets |variations_value| to the value of |parameter_name| read from
+// |variation_params|. If the value is unavailable from |variation_params|, then
+// |variations_value| is set to |default_value|.
+void GetValueForVariationParam(
const std::map<std::string, std::string>& variation_params,
const std::string& parameter_name,
- int32_t* variations_value) {
+ int64_t default_value,
+ int64_t* variations_value) {
const auto it = variation_params.find(parameter_name);
- return it != variation_params.end() &&
- base::StringToInt(it->second, variations_value);
+ if (it != variation_params.end() &&
+ base::StringToInt64(it->second, variations_value)) {
+ return;
+ }
+ *variations_value = default_value;
+}
+
+// Returns the variation value for |parameter_name|. If the value is
+// unavailable, |default_value| is returned.
+double GetDoubleValueForVariationParamWithDefaultValue(
+ const std::map<std::string, std::string>& variation_params,
+ const std::string& parameter_name,
+ double default_value) {
+ const auto it = variation_params.find(parameter_name);
+ if (it == variation_params.end())
+ return default_value;
+
+ double variations_value = default_value;
+ if (!base::StringToDouble(it->second, &variations_value))
+ return default_value;
+ return variations_value;
+}
+
+// Returns the variation value for |parameter_name|. If the value is
+// unavailable, |default_value| is returned.
+std::string GetStringValueForVariationParamWithDefaultValue(
+ const std::map<std::string, std::string>& variation_params,
+ const std::string& parameter_name,
+ const std::string& default_value) {
+ const auto it = variation_params.find(parameter_name);
+ if (it == variation_params.end())
+ return default_value;
+ return it->second;
}
// Returns the algorithm that should be used for computing effective connection
@@ -172,7 +221,7 @@ bool RequestSchemeIsHTTPOrHTTPS(const net::URLRequest& request) {
// Returns the suffix of the histogram that should be used for recording the
// accuracy when the observed RTT is |observed_rtt|. The width of the intervals
// are in exponentially increasing order.
-std::string GetHistogramSuffixObservedRTT(const base::TimeDelta& observed_rtt) {
+const char* GetHistogramSuffixObservedRTT(const base::TimeDelta& observed_rtt) {
const float rtt_milliseconds = observed_rtt.InMillisecondsF();
DCHECK_GE(rtt_milliseconds, 0);
@@ -192,7 +241,7 @@ std::string GetHistogramSuffixObservedRTT(const base::TimeDelta& observed_rtt) {
// accuracy when the observed throughput in kilobits per second is
// |observed_throughput_kbps|. The width of the intervals are in exponentially
// increasing order.
-std::string GetHistogramSuffixObservedThroughput(
+const char* GetHistogramSuffixObservedThroughput(
const int32_t& observed_throughput_kbps) {
DCHECK_GE(observed_throughput_kbps, 0);
@@ -208,6 +257,90 @@ std::string 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.
+ 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);
+ return metric;
+}
+
+void RecordRTTAccuracy(const char* prefix,
+ int32_t metric,
+ base::TimeDelta measuring_duration,
+ base::TimeDelta observed_rtt) {
+ const std::string histogram_name =
+ base::StringPrintf("%s.EstimatedObservedDiff.%s.%d.%s", prefix,
+ metric >= 0 ? "Positive" : "Negative",
+ static_cast<int32_t>(measuring_duration.InSeconds()),
+ GetHistogramSuffixObservedRTT(observed_rtt));
+
+ base::HistogramBase* histogram = base::Histogram::FactoryGet(
+ histogram_name, 1, 10 * 1000 /* 10 seconds */, 50 /* Number of buckets */,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->Add(std::abs(metric));
+}
+
+void RecordThroughputAccuracy(const char* prefix,
+ int32_t metric,
+ base::TimeDelta measuring_duration,
+ int32_t observed_throughput_kbps) {
+ const std::string histogram_name = base::StringPrintf(
+ "%s.EstimatedObservedDiff.%s.%d.%s", prefix,
+ metric >= 0 ? "Positive" : "Negative",
+ static_cast<int32_t>(measuring_duration.InSeconds()),
+ GetHistogramSuffixObservedThroughput(observed_throughput_kbps));
+
+ base::HistogramBase* histogram = base::Histogram::FactoryGet(
+ histogram_name, 1, 1000 * 1000 /* 1 Gbps */, 50 /* Number of buckets */,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->Add(std::abs(metric));
+}
+
+void RecordEffectiveConnectionTypeAccuracy(
+ const char* prefix,
+ int32_t metric,
+ base::TimeDelta measuring_duration,
+ net::EffectiveConnectionType observed_effective_connection_type) {
+ const std::string histogram_name =
+ base::StringPrintf("%s.EstimatedObservedDiff.%s.%d.%s", prefix,
+ metric >= 0 ? "Positive" : "Negative",
+ static_cast<int32_t>(measuring_duration.InSeconds()),
+ net::GetNameForEffectiveConnectionType(
+ observed_effective_connection_type));
+
+ base::HistogramBase* histogram = base::Histogram::FactoryGet(
+ histogram_name, 0, net::EFFECTIVE_CONNECTION_TYPE_LAST,
+ net::EFFECTIVE_CONNECTION_TYPE_LAST /* Number of buckets */,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->Add(std::abs(metric));
+}
+
} // namespace
namespace net {
@@ -227,7 +360,10 @@ NetworkQualityEstimator::NetworkQualityEstimator(
bool use_smaller_responses_for_tests)
: algorithm_name_to_enum_({{"HttpRTTAndDownstreamThroughput",
EffectiveConnectionTypeAlgorithm::
- HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT}}),
+ HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT},
+ {"TransportRTTOrDownstreamThroughput",
+ EffectiveConnectionTypeAlgorithm::
+ TRANSPORT_RTT_OR_DOWNSTREAM_THROUGHOUT}}),
use_localhost_requests_(use_local_host_requests_for_tests),
use_small_responses_(use_smaller_responses_for_tests),
weight_multiplier_per_second_(
@@ -240,27 +376,36 @@ NetworkQualityEstimator::NetworkQualityEstimator(
.find(GetEffectiveConnectionTypeAlgorithm(variation_params))
->second),
tick_clock_(new base::DefaultTickClock()),
- effective_connection_type_recomputation_interval_(
- base::TimeDelta::FromSeconds(15)),
last_connection_change_(tick_clock_->NowTicks()),
- current_network_id_(
- NetworkID(NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN,
- std::string())),
+ current_network_id_(nqe::internal::NetworkID(
+ NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN,
+ std::string())),
downstream_throughput_kbps_observations_(weight_multiplier_per_second_),
rtt_observations_(weight_multiplier_per_second_),
effective_connection_type_at_last_main_frame_(
EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
external_estimate_provider_(std::move(external_estimates_provider)),
+ effective_connection_type_recomputation_interval_(
+ base::TimeDelta::FromSeconds(10)),
+ rtt_observations_size_at_last_ect_computation_(0),
+ throughput_observations_size_at_last_ect_computation_(0),
effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
+ min_signal_strength_since_connection_change_(INT32_MAX),
+ max_signal_strength_since_connection_change_(INT32_MIN),
+ correlation_uma_logging_probability_(
+ GetDoubleValueForVariationParamWithDefaultValue(
+ variation_params,
+ "correlation_logging_probability",
+ 0.0)),
+ forced_effective_connection_type_set_(
+ !GetStringValueForVariationParamWithDefaultValue(
+ variation_params,
+ "force_effective_connection_type",
+ "")
+ .empty()),
weak_ptr_factory_(this) {
static_assert(kDefaultHalfLifeSeconds > 0,
"Default half life duration must be > 0");
- 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");
// None of the algorithms can have an empty name.
DCHECK(algorithm_name_to_enum_.end() ==
algorithm_name_to_enum_.find(std::string()));
@@ -271,7 +416,10 @@ NetworkQualityEstimator::NetworkQualityEstimator(
DCHECK_NE(EffectiveConnectionTypeAlgorithm::
EFFECTIVE_CONNECTION_TYPE_ALGORITHM_LAST,
effective_connection_type_algorithm_);
+ DCHECK_LE(0.0, correlation_uma_logging_probability_);
+ DCHECK_GE(1.0, correlation_uma_logging_probability_);
+ network_quality_store_.reset(new nqe::internal::NetworkQualityStore());
ObtainOperatingParams(variation_params);
ObtainEffectiveConnectionTypeModelParams(variation_params);
NetworkChangeNotifier::AddConnectionTypeObserver(this);
@@ -303,6 +451,20 @@ NetworkQualityEstimator::NetworkQualityEstimator(
accuracy_recording_intervals_.push_back(base::TimeDelta::FromSeconds(15));
accuracy_recording_intervals_.push_back(base::TimeDelta::FromSeconds(30));
accuracy_recording_intervals_.push_back(base::TimeDelta::FromSeconds(60));
+
+ if (forced_effective_connection_type_set_) {
+ std::string forced_value = GetStringValueForVariationParamWithDefaultValue(
+ variation_params, "force_effective_connection_type",
+ GetNameForEffectiveConnectionType(EFFECTIVE_CONNECTION_TYPE_UNKNOWN));
+ DCHECK(!forced_value.empty());
+ bool effective_connection_type_available =
+ GetEffectiveConnectionTypeForName(forced_value,
+ &forced_effective_connection_type_);
+ DCHECK(effective_connection_type_available);
+
+ // Silence unused variable warning in release builds.
+ (void)effective_connection_type_available;
+ }
}
void NetworkQualityEstimator::ObtainOperatingParams(
@@ -353,6 +515,38 @@ void NetworkQualityEstimator::ObtainEffectiveConnectionTypeModelParams(
const std::map<std::string, std::string>& variation_params) {
DCHECK(thread_checker_.CalledOnValidThread());
+ default_effective_connection_type_thresholds_
+ [EFFECTIVE_CONNECTION_TYPE_SLOW_2G] = nqe::internal::NetworkQuality(
+ // Set to 2010 milliseconds, which corresponds to the 33rd percentile
+ // of 2G HTTP RTT observations on Android.
+ base::TimeDelta::FromMilliseconds(2010),
+ // Set to 1870 milliseconds, which corresponds to the 33rd percentile
+ // of 2G transport RTT observations on Android.
+ base::TimeDelta::FromMilliseconds(1870),
+ nqe::internal::kInvalidThroughput);
+
+ default_effective_connection_type_thresholds_[EFFECTIVE_CONNECTION_TYPE_2G] =
+ nqe::internal::NetworkQuality(
+ // Set to 1420 milliseconds, which corresponds to 50th percentile of
+ // 2G
+ // HTTP RTT observations on Android.
+ base::TimeDelta::FromMilliseconds(1420),
+ // Set to 1280 milliseconds, which corresponds to 50th percentile of
+ // 2G
+ // transport RTT observations on Android.
+ base::TimeDelta::FromMilliseconds(1280),
+ nqe::internal::kInvalidThroughput);
+
+ default_effective_connection_type_thresholds_[EFFECTIVE_CONNECTION_TYPE_3G] =
+ nqe::internal::NetworkQuality(
+ // Set to 273 milliseconds, which corresponds to 50th percentile of
+ // 3G HTTP RTT observations on Android.
+ base::TimeDelta::FromMilliseconds(273),
+ // Set to 204 milliseconds, which corresponds to 50th percentile of
+ // 3G transport RTT observations on Android.
+ base::TimeDelta::FromMilliseconds(204),
+ nqe::internal::kInvalidThroughput);
+
for (size_t i = 0; i < EFFECTIVE_CONNECTION_TYPE_LAST; ++i) {
EffectiveConnectionType effective_connection_type =
static_cast<EffectiveConnectionType>(i);
@@ -368,42 +562,34 @@ void NetworkQualityEstimator::ObtainEffectiveConnectionTypeModelParams(
std::string connection_type_name = std::string(
GetNameForEffectiveConnectionType(effective_connection_type));
- int32_t variations_value = kMinimumRTTVariationParameterMsec - 1;
- if (GetValueForVariationParam(
- variation_params, connection_type_name + kThresholdURLRTTMsecSuffix,
- &variations_value) &&
- variations_value >= kMinimumRTTVariationParameterMsec) {
- base::TimeDelta rtt(base::TimeDelta::FromMilliseconds(variations_value));
- connection_thresholds_[i] = nqe::internal::NetworkQuality(
- rtt, connection_thresholds_[i].transport_rtt(),
- connection_thresholds_[i].downstream_throughput_kbps());
-
- // Verify that the RTT values are in decreasing order as the network
- // quality improves.
- DCHECK(i == 0 ||
- connection_thresholds_[i - 1].http_rtt() ==
- nqe::internal::InvalidRTT() ||
- rtt <= connection_thresholds_[i - 1].http_rtt());
- }
-
- variations_value = kMinimumThroughputVariationParameterKbps - 1;
- if (GetValueForVariationParam(variation_params,
- connection_type_name + kThresholdKbpsSuffix,
- &variations_value) &&
- variations_value >= kMinimumThroughputVariationParameterKbps) {
- int32_t throughput_kbps = variations_value;
- connection_thresholds_[i] = nqe::internal::NetworkQuality(
- connection_thresholds_[i].http_rtt(),
- connection_thresholds_[i].transport_rtt(), throughput_kbps);
-
- // Verify that the throughput values are in increasing order as the
- // network quality improves.
- DCHECK(i == 0 ||
- connection_thresholds_[i - 1].downstream_throughput_kbps() ==
- kMinimumThroughputVariationParameterKbps ||
- throughput_kbps >=
- connection_thresholds_[i - 1].downstream_throughput_kbps());
- }
+ int64_t variations_value;
+ GetValueForVariationParam(variation_params,
+ connection_type_name + kThresholdURLRTTMsecSuffix,
+ default_effective_connection_type_thresholds_[i]
+ .http_rtt()
+ .InMilliseconds(),
+ &variations_value);
+ connection_thresholds_[i].set_http_rtt(
+ base::TimeDelta::FromMilliseconds(variations_value));
+
+ GetValueForVariationParam(
+ variation_params,
+ connection_type_name + kThresholdTransportRTTMsecSuffix,
+ default_effective_connection_type_thresholds_[i]
+ .transport_rtt()
+ .InMilliseconds(),
+ &variations_value);
+ connection_thresholds_[i].set_transport_rtt(
+ base::TimeDelta::FromMilliseconds(variations_value));
+
+ GetValueForVariationParam(variation_params,
+ connection_type_name + kThresholdKbpsSuffix,
+ default_effective_connection_type_thresholds_[i]
+ .downstream_throughput_kbps(),
+ &variations_value);
+ connection_thresholds_[i].set_downstream_throughput_kbps(variations_value);
+ DCHECK(i == 0 ||
+ connection_thresholds_[i].IsFaster(connection_thresholds_[i - 1]));
}
}
@@ -468,27 +654,30 @@ void NetworkQualityEstimator::NotifyHeadersReceived(const URLRequest& request) {
// Update |estimated_quality_at_last_main_frame_| if this is a main frame
// request.
- if (request.load_flags() & LOAD_MAIN_FRAME) {
+ if (request.load_flags() & LOAD_MAIN_FRAME_DEPRECATED) {
last_main_frame_request_ = now;
base::TimeDelta estimated_http_rtt;
- if (!GetHttpRTTEstimate(&estimated_http_rtt))
+ if (!GetHttpRTT(&estimated_http_rtt))
estimated_http_rtt = nqe::internal::InvalidRTT();
base::TimeDelta estimated_transport_rtt;
- if (!GetTransportRTTEstimate(&estimated_transport_rtt))
+ if (!GetTransportRTT(&estimated_transport_rtt))
estimated_transport_rtt = nqe::internal::InvalidRTT();
int32_t downstream_throughput_kbps;
- if (!GetDownlinkThroughputKbpsEstimate(&downstream_throughput_kbps))
+ if (!GetDownlinkThroughputKbps(&downstream_throughput_kbps))
downstream_throughput_kbps = nqe::internal::kInvalidThroughput;
estimated_quality_at_last_main_frame_ = nqe::internal::NetworkQuality(
estimated_http_rtt, estimated_transport_rtt,
downstream_throughput_kbps);
+
+ ComputeEffectiveConnectionType();
effective_connection_type_at_last_main_frame_ =
GetEffectiveConnectionType();
RecordMetricsOnMainFrameRequest();
+ MaybeQueryExternalEstimateProvider();
// Post the tasks which will run in the future and record the estimation
// accuracy based on the observations received between now and the time of
@@ -503,6 +692,7 @@ void NetworkQualityEstimator::NotifyHeadersReceived(const URLRequest& request) {
weak_ptr_factory_.GetWeakPtr(), measuring_delay),
measuring_delay);
}
+ UpdateSignalStrength();
}
LoadTimingInfo load_timing_info;
@@ -514,6 +704,7 @@ void NetworkQualityEstimator::NotifyHeadersReceived(const URLRequest& request) {
load_timing_info.receive_headers_end.is_null()) {
return;
}
+ DCHECK(!request.response_info().was_cached);
// Duration between when the resource was requested and when the response
// headers were received.
@@ -561,64 +752,41 @@ void NetworkQualityEstimator::RecordAccuracyAfterMainFrame(
base::TimeDelta recent_http_rtt;
if (estimated_quality_at_last_main_frame_.http_rtt() !=
nqe::internal::InvalidRTT() &&
- GetRecentHttpRTTMedian(last_main_frame_request_, &recent_http_rtt)) {
+ GetRecentHttpRTT(last_main_frame_request_, &recent_http_rtt)) {
const int estimated_observed_diff_milliseconds =
estimated_quality_at_last_main_frame_.http_rtt().InMilliseconds() -
recent_http_rtt.InMilliseconds();
- const std::string sign_suffix =
- estimated_observed_diff_milliseconds >= 0 ? "Positive." : "Negative.";
-
- base::HistogramBase* histogram = base::Histogram::FactoryGet(
- "NQE.Accuracy.HttpRTT.EstimatedObservedDiff." + sign_suffix +
- base::IntToString(measuring_duration.InSeconds()) + "." +
- GetHistogramSuffixObservedRTT(recent_http_rtt),
- 1, 10 * 1000 /* 10 seconds */, 50 /* Number of buckets */,
- base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->Add(std::abs(estimated_observed_diff_milliseconds));
+ RecordRTTAccuracy("NQE.Accuracy.HttpRTT",
+ estimated_observed_diff_milliseconds, measuring_duration,
+ recent_http_rtt);
}
base::TimeDelta recent_transport_rtt;
if (estimated_quality_at_last_main_frame_.transport_rtt() !=
nqe::internal::InvalidRTT() &&
- GetRecentTransportRTTMedian(last_main_frame_request_,
- &recent_transport_rtt)) {
+ GetRecentTransportRTT(last_main_frame_request_, &recent_transport_rtt)) {
const int estimated_observed_diff_milliseconds =
estimated_quality_at_last_main_frame_.transport_rtt().InMilliseconds() -
recent_transport_rtt.InMilliseconds();
- const std::string sign_suffix =
- estimated_observed_diff_milliseconds >= 0 ? "Positive." : "Negative.";
-
- base::HistogramBase* histogram = base::Histogram::FactoryGet(
- "NQE.Accuracy.TransportRTT.EstimatedObservedDiff." + sign_suffix +
- base::IntToString(measuring_duration.InSeconds()) + "." +
- GetHistogramSuffixObservedRTT(recent_transport_rtt),
- 1, 10 * 1000 /* 10 seconds */, 50 /* Number of buckets */,
- base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->Add(std::abs(estimated_observed_diff_milliseconds));
+ RecordRTTAccuracy("NQE.Accuracy.TransportRTT",
+ estimated_observed_diff_milliseconds, measuring_duration,
+ recent_transport_rtt);
}
int32_t recent_downstream_throughput_kbps;
if (estimated_quality_at_last_main_frame_.downstream_throughput_kbps() !=
nqe::internal::kInvalidThroughput &&
- GetRecentMedianDownlinkThroughputKbps(
- last_main_frame_request_, &recent_downstream_throughput_kbps)) {
+ GetRecentDownlinkThroughputKbps(last_main_frame_request_,
+ &recent_downstream_throughput_kbps)) {
const int estimated_observed_diff =
estimated_quality_at_last_main_frame_.downstream_throughput_kbps() -
recent_downstream_throughput_kbps;
- const std::string sign_suffix =
- estimated_observed_diff >= 0 ? "Positive." : "Negative.";
-
- base::HistogramBase* histogram = base::Histogram::FactoryGet(
- "NQE.Accuracy.DownstreamThroughputKbps.EstimatedObservedDiff." +
- sign_suffix + base::IntToString(measuring_duration.InSeconds()) +
- "." + GetHistogramSuffixObservedThroughput(
- recent_downstream_throughput_kbps),
- 1, 1000 * 1000 /* 1 Gbps */, 50 /* Number of buckets */,
- base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->Add(std::abs(estimated_observed_diff));
+ RecordThroughputAccuracy("NQE.Accuracy.DownstreamThroughputKbps",
+ estimated_observed_diff, measuring_duration,
+ recent_downstream_throughput_kbps);
}
EffectiveConnectionType recent_effective_connection_type =
@@ -630,23 +798,27 @@ void NetworkQualityEstimator::RecordAccuracyAfterMainFrame(
static_cast<int>(effective_connection_type_at_last_main_frame_) -
static_cast<int>(recent_effective_connection_type);
- const std::string sign_suffix =
- estimated_observed_diff >= 0 ? "Positive." : "Negative.";
-
- base::HistogramBase* histogram = base::Histogram::FactoryGet(
- "NQE.Accuracy.EffectiveConnectionType.EstimatedObservedDiff." +
- sign_suffix + base::IntToString(measuring_duration.InSeconds()) +
- "." +
- GetNameForEffectiveConnectionType(recent_effective_connection_type),
- 0, EFFECTIVE_CONNECTION_TYPE_LAST,
- EFFECTIVE_CONNECTION_TYPE_LAST /* Number of buckets */,
- base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->Add(std::abs(estimated_observed_diff));
+ RecordEffectiveConnectionTypeAccuracy(
+ "NQE.Accuracy.EffectiveConnectionType", estimated_observed_diff,
+ measuring_duration, recent_effective_connection_type);
+ }
+
+ // Add histogram to evaluate the accuracy of the external estimate provider.
+ if (external_estimate_provider_quality_.http_rtt() !=
+ nqe::internal::InvalidRTT() &&
+ recent_http_rtt != nqe::internal::InvalidRTT()) {
+ const int estimated_observed_diff_milliseconds =
+ external_estimate_provider_quality_.http_rtt().InMilliseconds() -
+ recent_http_rtt.InMilliseconds();
+
+ RecordRTTAccuracy("NQE.ExternalEstimateProvider.RTT.Accuracy",
+ estimated_observed_diff_milliseconds, measuring_duration,
+ recent_http_rtt);
}
}
-void NetworkQualityEstimator::NotifyRequestCompleted(
- const URLRequest& request) {
+void NetworkQualityEstimator::NotifyRequestCompleted(const URLRequest& request,
+ int net_error) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("net"),
"NetworkQualityEstimator::NotifyRequestCompleted");
DCHECK(thread_checker_.CalledOnValidThread());
@@ -655,13 +827,109 @@ void NetworkQualityEstimator::NotifyRequestCompleted(
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 with probability
+ // |correlation_uma_logging_probability_| to reduce overhead involved with
+ // sparse histograms. Also, recording the correlation on each request is
+ // unnecessary.
+ if (RandDouble() >= 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.GetResponseCode() != HTTP_OK)
+ return;
+ if (load_timing_info.receive_headers_end < last_main_frame_request_)
+ return;
+
+ const base::TimeTicks now = tick_clock_->NowTicks();
+ // Record UMA only for requests that started recently.
+ if (now - last_main_frame_request_ > base::TimeDelta::FromSeconds(15))
+ return;
+
+ DCHECK_GE(now, load_timing_info.send_start);
+
+ int32_t rtt = 0;
+
+ if (UseTransportRTT()) {
+ rtt = estimated_quality_at_last_main_frame_.transport_rtt() !=
+ nqe::internal::InvalidRTT()
+ ? FitInKBitsPerMetricBits(
+ estimated_quality_at_last_main_frame_.transport_rtt()
+ .InMilliseconds())
+ : 0;
+ } else {
+ rtt = estimated_quality_at_last_main_frame_.http_rtt() !=
+ nqe::internal::InvalidRTT()
+ ? FitInKBitsPerMetricBits(
+ estimated_quality_at_last_main_frame_.http_rtt()
+ .InMilliseconds())
+ : 0;
+ }
+
+ const int32_t downstream_throughput =
+ estimated_quality_at_last_main_frame_.downstream_throughput_kbps() !=
+ nqe::internal::kInvalidThroughput
+ ? FitInKBitsPerMetricBits(estimated_quality_at_last_main_frame_
+ .downstream_throughput_kbps())
+ : 0;
+
+ 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(
const URLRequest& request) {
DCHECK(thread_checker_.CalledOnValidThread());
- NotifyRequestCompleted(request);
+ if (!RequestSchemeIsHTTPOrHTTPS(request))
+ return;
+
+ throughput_analyzer_->NotifyRequestCompleted(request);
}
void NetworkQualityEstimator::AddRTTObserver(RTTObserver* rtt_observer) {
@@ -708,6 +976,14 @@ void NetworkQualityEstimator::SetUseSmallResponsesForTesting(
throughput_analyzer_->SetUseSmallResponsesForTesting(use_small_responses_);
}
+void NetworkQualityEstimator::ReportEffectiveConnectionTypeForTesting(
+ EffectiveConnectionType effective_connection_type) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ FOR_EACH_OBSERVER(
+ EffectiveConnectionTypeObserver, effective_connection_type_observer_list_,
+ OnEffectiveConnectionTypeChanged(effective_connection_type));
+}
+
bool NetworkQualityEstimator::RequestProvidesRTTObservation(
const URLRequest& request) const {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -733,15 +1009,50 @@ void NetworkQualityEstimator::OnConnectionTypeChanged(
RecordMetricsOnConnectionTypeChanged();
// Write the estimates of the previous network to the cache.
- CacheNetworkQualityEstimate();
+ network_quality_store_->Add(
+ current_network_id_,
+ nqe::internal::CachedNetworkQuality(
+ last_effective_connection_type_computation_,
+ estimated_quality_at_last_main_frame_, effective_connection_type_));
// Clear the local state.
last_connection_change_ = tick_clock_->NowTicks();
peak_network_quality_ = nqe::internal::NetworkQuality();
downstream_throughput_kbps_observations_.Clear();
rtt_observations_.Clear();
+
+#if defined(OS_ANDROID)
+ if (NetworkChangeNotifier::IsConnectionCellular(current_network_id_.type)) {
+ UMA_HISTOGRAM_BOOLEAN(
+ "NQE.CellularSignalStrengthAvailable",
+ min_signal_strength_since_connection_change_ != INT32_MAX &&
+ max_signal_strength_since_connection_change_ != INT32_MIN);
+ }
+#endif // OS_ANDROID
+ min_signal_strength_since_connection_change_ = INT32_MAX;
+ max_signal_strength_since_connection_change_ = INT32_MIN;
+ estimated_quality_at_last_main_frame_ = nqe::internal::NetworkQuality();
+ effective_connection_type_ = EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+ effective_connection_type_at_last_main_frame_ =
+ EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+
+ // Update the local state as part of preparation for the new connection.
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();
+ estimated_quality_at_last_main_frame_ = nqe::internal::NetworkQuality();
+ throughput_analyzer_->OnConnectionTypeChanged();
+ MaybeComputeEffectiveConnectionType();
+ UpdateSignalStrength();
+}
+void NetworkQualityEstimator::MaybeQueryExternalEstimateProvider() const {
// Query the external estimate provider on certain connection types. Once the
// updated estimates are available, OnUpdatedEstimateAvailable will be called
// by |external_estimate_provider_| with updated estimates.
@@ -754,14 +1065,20 @@ void NetworkQualityEstimator::OnConnectionTypeChanged(
EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERIED);
external_estimate_provider_->Update();
}
+}
- // Read any cached estimates for the new network. If cached estimates are
- // unavailable, add the default estimates.
- if (!ReadCachedNetworkQualityEstimate())
- AddDefaultEstimates();
- estimated_quality_at_last_main_frame_ = nqe::internal::NetworkQuality();
- throughput_analyzer_->OnConnectionTypeChanged();
- MaybeRecomputeEffectiveConnectionType();
+void NetworkQualityEstimator::UpdateSignalStrength() {
+#if defined(OS_ANDROID)
+ int32_t signal_strength_dbm;
+ if (!android::cellular_signal_strength::GetSignalStrengthDbm(
+ &signal_strength_dbm)) {
+ return;
+ }
+ min_signal_strength_since_connection_change_ = std::min(
+ min_signal_strength_since_connection_change_, signal_strength_dbm);
+ max_signal_strength_since_connection_change_ = std::max(
+ max_signal_strength_since_connection_change_, signal_strength_dbm);
+#endif // OS_ANDROID
}
void NetworkQualityEstimator::RecordMetricsOnConnectionTypeChanged() const {
@@ -781,7 +1098,7 @@ void NetworkQualityEstimator::RecordMetricsOnConnectionTypeChanged() const {
}
base::TimeDelta rtt;
- if (GetHttpRTTEstimate(&rtt)) {
+ if (GetHttpRTT(&rtt)) {
// Add the 50th percentile value.
base::HistogramBase* rtt_percentile =
GetHistogram("RTT.Percentile50.", current_network_id_.type, 10 * 1000);
@@ -805,7 +1122,7 @@ void NetworkQualityEstimator::RecordMetricsOnConnectionTypeChanged() const {
}
}
- if (GetTransportRTTEstimate(&rtt)) {
+ if (GetTransportRTT(&rtt)) {
// Add the 50th percentile value.
base::HistogramBase* transport_rtt_percentile = GetHistogram(
"TransportRTT.Percentile50.", current_network_id_.type, 10 * 1000);
@@ -835,11 +1152,21 @@ void NetworkQualityEstimator::RecordMetricsOnConnectionTypeChanged() const {
}
}
+void NetworkQualityEstimator::RecordNetworkIDAvailability() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (current_network_id_.type ==
+ NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI ||
+ NetworkChangeNotifier::IsConnectionCellular(current_network_id_.type)) {
+ UMA_HISTOGRAM_BOOLEAN("NQE.NetworkIdAvailable",
+ !current_network_id_.id.empty());
+ }
+}
+
void NetworkQualityEstimator::RecordMetricsOnMainFrameRequest() const {
DCHECK(thread_checker_.CalledOnValidThread());
base::TimeDelta http_rtt;
- if (GetHttpRTTEstimate(&http_rtt)) {
+ if (GetHttpRTT(&http_rtt)) {
// Add the 50th percentile value.
base::HistogramBase* rtt_percentile = GetHistogram(
"MainFrame.RTT.Percentile50.", current_network_id_.type, 10 * 1000);
@@ -847,7 +1174,7 @@ void NetworkQualityEstimator::RecordMetricsOnMainFrameRequest() const {
}
base::TimeDelta transport_rtt;
- if (GetTransportRTTEstimate(&transport_rtt)) {
+ if (GetTransportRTT(&transport_rtt)) {
// Add the 50th percentile value.
base::HistogramBase* transport_rtt_percentile =
GetHistogram("MainFrame.TransportRTT.Percentile50.",
@@ -856,7 +1183,7 @@ void NetworkQualityEstimator::RecordMetricsOnMainFrameRequest() const {
}
int32_t kbps;
- if (GetDownlinkThroughputKbpsEstimate(&kbps)) {
+ if (GetDownlinkThroughputKbps(&kbps)) {
// Add the 50th percentile value.
base::HistogramBase* throughput_percentile = GetHistogram(
"MainFrame.Kbps.Percentile50.", current_network_id_.type, 1000 * 1000);
@@ -876,48 +1203,137 @@ void NetworkQualityEstimator::RecordMetricsOnMainFrameRequest() const {
effective_connection_type_histogram->Add(effective_connection_type);
}
-NetworkQualityEstimator::EffectiveConnectionType
-NetworkQualityEstimator::GetEffectiveConnectionType() const {
+void NetworkQualityEstimator::ComputeEffectiveConnectionType() {
DCHECK(thread_checker_.CalledOnValidThread());
- return GetRecentEffectiveConnectionType(base::TimeTicks());
+
+ const base::TimeTicks now = tick_clock_->NowTicks();
+
+ const EffectiveConnectionType past_type = effective_connection_type_;
+ last_effective_connection_type_computation_ = now;
+
+ effective_connection_type_ =
+ GetRecentEffectiveConnectionType(base::TimeTicks());
+
+ if (past_type != effective_connection_type_)
+ NotifyObserversOfEffectiveConnectionTypeChanged();
+
+ rtt_observations_size_at_last_ect_computation_ = rtt_observations_.Size();
+ throughput_observations_size_at_last_ect_computation_ =
+ downstream_throughput_kbps_observations_.Size();
+}
+
+EffectiveConnectionType NetworkQualityEstimator::GetEffectiveConnectionType()
+ const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return effective_connection_type_;
}
-NetworkQualityEstimator::EffectiveConnectionType
+EffectiveConnectionType
NetworkQualityEstimator::GetRecentEffectiveConnectionType(
const base::TimeTicks& start_time) const {
DCHECK(thread_checker_.CalledOnValidThread());
if (effective_connection_type_algorithm_ ==
EffectiveConnectionTypeAlgorithm::HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT) {
- return GetRecentEffectiveConnectionTypeHttpRTTAndDownstreamThroughput(
- start_time);
+ return GetRecentEffectiveConnectionTypeUsingMetrics(
+ start_time, NetworkQualityEstimator::MetricUsage::
+ MUST_BE_USED /* http_rtt_metric */,
+ NetworkQualityEstimator::MetricUsage::
+ DO_NOT_USE /* transport_rtt_metric */,
+ NetworkQualityEstimator::MetricUsage::
+ MUST_BE_USED /* downstream_throughput_kbps_metric */);
+ }
+ if (effective_connection_type_algorithm_ ==
+ EffectiveConnectionTypeAlgorithm::
+ TRANSPORT_RTT_OR_DOWNSTREAM_THROUGHOUT) {
+ return GetRecentEffectiveConnectionTypeUsingMetrics(
+ start_time,
+ NetworkQualityEstimator::MetricUsage::DO_NOT_USE /* http_rtt_metric */,
+ NetworkQualityEstimator::MetricUsage::
+ USE_IF_AVAILABLE /* transport_rtt_metric */,
+ NetworkQualityEstimator::MetricUsage::
+ USE_IF_AVAILABLE /* downstream_throughput_kbps_metric */);
}
// Add additional algorithms here.
NOTREACHED();
return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
}
-NetworkQualityEstimator::EffectiveConnectionType NetworkQualityEstimator::
- GetRecentEffectiveConnectionTypeHttpRTTAndDownstreamThroughput(
- const base::TimeTicks& start_time) const {
+bool NetworkQualityEstimator::UseTransportRTT() const {
DCHECK(thread_checker_.CalledOnValidThread());
+ if (effective_connection_type_algorithm_ ==
+ EffectiveConnectionTypeAlgorithm::HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT) {
+ return false;
+ }
+ if (effective_connection_type_algorithm_ ==
+ EffectiveConnectionTypeAlgorithm::
+ TRANSPORT_RTT_OR_DOWNSTREAM_THROUGHOUT) {
+ return true;
+ }
+ // Add additional algorithms here.
+ NOTREACHED();
+ return false;
+}
+
+EffectiveConnectionType
+NetworkQualityEstimator::GetRecentEffectiveConnectionTypeUsingMetrics(
+ const base::TimeTicks& start_time,
+ NetworkQualityEstimator::MetricUsage http_rtt_metric,
+ NetworkQualityEstimator::MetricUsage transport_rtt_metric,
+ NetworkQualityEstimator::MetricUsage downstream_throughput_kbps_metric)
+ const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (forced_effective_connection_type_set_)
+ return forced_effective_connection_type_;
+
// If the device is currently offline, then return
// EFFECTIVE_CONNECTION_TYPE_OFFLINE.
- if (GetCurrentNetworkID().type == NetworkChangeNotifier::CONNECTION_NONE)
+ if (current_network_id_.type == NetworkChangeNotifier::CONNECTION_NONE)
return EFFECTIVE_CONNECTION_TYPE_OFFLINE;
base::TimeDelta http_rtt = nqe::internal::InvalidRTT();
- if (!GetRecentHttpRTTMedian(start_time, &http_rtt))
+ if (http_rtt_metric != NetworkQualityEstimator::MetricUsage::DO_NOT_USE &&
+ !GetRecentHttpRTT(start_time, &http_rtt)) {
http_rtt = nqe::internal::InvalidRTT();
+ }
+
+ base::TimeDelta transport_rtt = nqe::internal::InvalidRTT();
+ if (transport_rtt_metric !=
+ NetworkQualityEstimator::MetricUsage::DO_NOT_USE &&
+ !GetRecentTransportRTT(start_time, &transport_rtt)) {
+ transport_rtt = nqe::internal::InvalidRTT();
+ }
int32_t kbps = nqe::internal::kInvalidThroughput;
- if (!GetRecentMedianDownlinkThroughputKbps(start_time, &kbps))
+ if (downstream_throughput_kbps_metric !=
+ NetworkQualityEstimator::MetricUsage::DO_NOT_USE &&
+ !GetRecentDownlinkThroughputKbps(start_time, &kbps)) {
kbps = nqe::internal::kInvalidThroughput;
+ }
+
+ if (http_rtt == nqe::internal::InvalidRTT() &&
+ http_rtt_metric == NetworkQualityEstimator::MetricUsage::MUST_BE_USED) {
+ return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+ }
+
+ if (transport_rtt == nqe::internal::InvalidRTT() &&
+ transport_rtt_metric ==
+ NetworkQualityEstimator::MetricUsage::MUST_BE_USED) {
+ return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+ }
- if (http_rtt == nqe::internal::InvalidRTT() ||
+ if (kbps == nqe::internal::kInvalidThroughput &&
+ downstream_throughput_kbps_metric ==
+ NetworkQualityEstimator::MetricUsage::MUST_BE_USED) {
+ return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+ }
+
+ if (http_rtt == nqe::internal::InvalidRTT() &&
+ transport_rtt == nqe::internal::InvalidRTT() &&
kbps == nqe::internal::kInvalidThroughput) {
- // Quality of the current network is unknown.
+ // None of the metrics are available.
return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
}
@@ -928,20 +1344,26 @@ NetworkQualityEstimator::EffectiveConnectionType NetworkQualityEstimator::
EffectiveConnectionType type = static_cast<EffectiveConnectionType>(i);
if (i == EFFECTIVE_CONNECTION_TYPE_UNKNOWN)
continue;
- bool estimated_http_rtt_is_higher_than_threshold =
+
+ const bool estimated_http_rtt_is_higher_than_threshold =
http_rtt != nqe::internal::InvalidRTT() &&
connection_thresholds_[i].http_rtt() != nqe::internal::InvalidRTT() &&
http_rtt >= connection_thresholds_[i].http_rtt();
- bool estimated_throughput_is_lower_than_threshold =
+
+ const bool estimated_transport_rtt_is_higher_than_threshold =
+ transport_rtt != nqe::internal::InvalidRTT() &&
+ connection_thresholds_[i].transport_rtt() !=
+ nqe::internal::InvalidRTT() &&
+ transport_rtt >= connection_thresholds_[i].transport_rtt();
+
+ const bool estimated_throughput_is_lower_than_threshold =
kbps != nqe::internal::kInvalidThroughput &&
connection_thresholds_[i].downstream_throughput_kbps() !=
nqe::internal::kInvalidThroughput &&
kbps <= connection_thresholds_[i].downstream_throughput_kbps();
- // Return |type| as the effective connection type if the current network's
- // RTT is worse than the threshold RTT for |type|, or if the current
- // network's throughput is lower than the threshold throughput for |type|.
if (estimated_http_rtt_is_higher_than_threshold ||
+ estimated_transport_rtt_is_higher_than_threshold ||
estimated_throughput_is_lower_than_threshold) {
return type;
}
@@ -963,24 +1385,22 @@ void NetworkQualityEstimator::RemoveEffectiveConnectionTypeObserver(
effective_connection_type_observer_list_.RemoveObserver(observer);
}
-bool NetworkQualityEstimator::GetHttpRTTEstimate(base::TimeDelta* rtt) const {
+bool NetworkQualityEstimator::GetHttpRTT(base::TimeDelta* rtt) const {
DCHECK(thread_checker_.CalledOnValidThread());
- return GetRecentHttpRTTMedian(base::TimeTicks(), rtt);
+ return GetRecentHttpRTT(base::TimeTicks(), rtt);
}
-bool NetworkQualityEstimator::GetTransportRTTEstimate(
- base::TimeDelta* rtt) const {
+bool NetworkQualityEstimator::GetTransportRTT(base::TimeDelta* rtt) const {
DCHECK(thread_checker_.CalledOnValidThread());
- return GetRecentTransportRTTMedian(base::TimeTicks(), rtt);
+ return GetRecentTransportRTT(base::TimeTicks(), rtt);
}
-bool NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimate(
- int32_t* kbps) const {
+bool NetworkQualityEstimator::GetDownlinkThroughputKbps(int32_t* kbps) const {
DCHECK(thread_checker_.CalledOnValidThread());
- return GetRecentMedianDownlinkThroughputKbps(base::TimeTicks(), kbps);
+ return GetRecentDownlinkThroughputKbps(base::TimeTicks(), kbps);
}
-bool NetworkQualityEstimator::GetRecentHttpRTTMedian(
+bool NetworkQualityEstimator::GetRecentHttpRTT(
const base::TimeTicks& start_time,
base::TimeDelta* rtt) const {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -993,7 +1413,7 @@ bool NetworkQualityEstimator::GetRecentHttpRTTMedian(
return (*rtt != nqe::internal::InvalidRTT());
}
-bool NetworkQualityEstimator::GetRecentTransportRTTMedian(
+bool NetworkQualityEstimator::GetRecentTransportRTT(
const base::TimeTicks& start_time,
base::TimeDelta* rtt) const {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -1012,7 +1432,7 @@ bool NetworkQualityEstimator::GetRecentTransportRTTMedian(
return (*rtt != nqe::internal::InvalidRTT());
}
-bool NetworkQualityEstimator::GetRecentMedianDownlinkThroughputKbps(
+bool NetworkQualityEstimator::GetRecentDownlinkThroughputKbps(
const base::TimeTicks& start_time,
int32_t* kbps) const {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -1053,8 +1473,7 @@ int32_t NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimateInternal(
return kbps;
}
-NetworkQualityEstimator::NetworkID
-NetworkQualityEstimator::GetCurrentNetworkID() const {
+nqe::internal::NetworkID NetworkQualityEstimator::GetCurrentNetworkID() const {
DCHECK(thread_checker_.CalledOnValidThread());
// TODO(tbansal): crbug.com/498068 Add NetworkQualityEstimatorAndroid class
@@ -1067,7 +1486,7 @@ NetworkQualityEstimator::GetCurrentNetworkID() const {
// capture majority of cases, and should not significantly affect estimates
// (that are approximate to begin with).
while (true) {
- NetworkQualityEstimator::NetworkID network_id(
+ nqe::internal::NetworkID network_id(
NetworkChangeNotifier::GetConnectionType(), std::string());
switch (network_id.type) {
@@ -1103,42 +1522,47 @@ NetworkQualityEstimator::GetCurrentNetworkID() const {
bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() {
DCHECK(thread_checker_.CalledOnValidThread());
- // If the network name is unavailable, caching should not be performed.
- if (current_network_id_.id.empty())
- return false;
+ nqe::internal::CachedNetworkQuality cached_network_quality;
- CachedNetworkQualities::const_iterator it =
- cached_network_qualities_.find(current_network_id_);
+ const bool cached_estimate_available = network_quality_store_->GetById(
+ current_network_id_, &cached_network_quality);
+ UMA_HISTOGRAM_BOOLEAN("NQE.CachedNetworkQualityAvailable",
+ cached_estimate_available);
- if (it == cached_network_qualities_.end())
+ if (!cached_estimate_available)
return false;
- nqe::internal::NetworkQuality network_quality(it->second.network_quality());
-
const base::TimeTicks now = tick_clock_->NowTicks();
- bool read_cached_estimate = false;
- if (network_quality.downstream_throughput_kbps() !=
+ if (effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
+ // Read the effective connection type from the cached estimate.
+ last_effective_connection_type_computation_ = now;
+ effective_connection_type_ =
+ cached_network_quality.effective_connection_type();
+
+ if (effective_connection_type_ != EFFECTIVE_CONNECTION_TYPE_UNKNOWN)
+ NotifyObserversOfEffectiveConnectionTypeChanged();
+ }
+
+ if (cached_network_quality.network_quality().downstream_throughput_kbps() !=
nqe::internal::kInvalidThroughput) {
- read_cached_estimate = true;
ThroughputObservation througphput_observation(
- network_quality.downstream_throughput_kbps(), now,
- NETWORK_QUALITY_OBSERVATION_SOURCE_CACHED_ESTIMATE);
+ cached_network_quality.network_quality().downstream_throughput_kbps(),
+ now, NETWORK_QUALITY_OBSERVATION_SOURCE_CACHED_ESTIMATE);
downstream_throughput_kbps_observations_.AddObservation(
througphput_observation);
NotifyObserversOfThroughput(througphput_observation);
}
- if (network_quality.http_rtt() != nqe::internal::InvalidRTT()) {
- read_cached_estimate = true;
+ if (cached_network_quality.network_quality().http_rtt() !=
+ nqe::internal::InvalidRTT()) {
RttObservation rtt_observation(
- network_quality.http_rtt(), now,
+ cached_network_quality.network_quality().http_rtt(), now,
NETWORK_QUALITY_OBSERVATION_SOURCE_CACHED_ESTIMATE);
rtt_observations_.AddObservation(rtt_observation);
NotifyObserversOfRTT(rtt_observation);
}
-
- return read_cached_estimate;
+ return true;
}
void NetworkQualityEstimator::OnUpdatedEstimateAvailable(
@@ -1151,6 +1575,8 @@ void NetworkQualityEstimator::OnUpdatedEstimateAvailable(
RecordExternalEstimateProviderMetrics(
EXTERNAL_ESTIMATE_PROVIDER_STATUS_CALLBACK);
+ external_estimate_provider_quality_ = nqe::internal::NetworkQuality();
+
if (rtt > base::TimeDelta()) {
RecordExternalEstimateProviderMetrics(
EXTERNAL_ESTIMATE_PROVIDER_STATUS_RTT_AVAILABLE);
@@ -1158,6 +1584,7 @@ void NetworkQualityEstimator::OnUpdatedEstimateAvailable(
rtt_observations_.AddObservation(
RttObservation(rtt, tick_clock_->NowTicks(),
NETWORK_QUALITY_OBSERVATION_SOURCE_EXTERNAL_ESTIMATE));
+ external_estimate_provider_quality_.set_http_rtt(rtt);
}
if (downstream_throughput_kbps > 0) {
@@ -1169,105 +1596,19 @@ void NetworkQualityEstimator::OnUpdatedEstimateAvailable(
ThroughputObservation(
downstream_throughput_kbps, tick_clock_->NowTicks(),
NETWORK_QUALITY_OBSERVATION_SOURCE_EXTERNAL_ESTIMATE));
+ external_estimate_provider_quality_.set_downstream_throughput_kbps(
+ downstream_throughput_kbps);
}
}
-// static
-const char* NetworkQualityEstimator::GetNameForEffectiveConnectionType(
- EffectiveConnectionType type) {
- switch (type) {
- case EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
- return "Unknown";
- case EFFECTIVE_CONNECTION_TYPE_OFFLINE:
- return "Offline";
- case EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
- return "Slow2G";
- case EFFECTIVE_CONNECTION_TYPE_2G:
- return "2G";
- case EFFECTIVE_CONNECTION_TYPE_3G:
- return "3G";
- case EFFECTIVE_CONNECTION_TYPE_4G:
- return "4G";
- case EFFECTIVE_CONNECTION_TYPE_BROADBAND:
- return "Broadband";
- default:
- NOTREACHED();
- break;
- }
- return "";
-}
-
-// static
-NetworkQualityEstimator::EffectiveConnectionType
-NetworkQualityEstimator::GetEffectiveConnectionTypeForName(
- const std::string& connection_type_name) {
- if (connection_type_name == "Unknown")
- return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
- if (connection_type_name == "Offline")
- return EFFECTIVE_CONNECTION_TYPE_OFFLINE;
- if (connection_type_name == "Slow2G")
- return EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
- if (connection_type_name == "2G")
- return EFFECTIVE_CONNECTION_TYPE_2G;
- if (connection_type_name == "3G")
- return EFFECTIVE_CONNECTION_TYPE_3G;
- if (connection_type_name == "4G")
- return EFFECTIVE_CONNECTION_TYPE_4G;
- if (connection_type_name == "Broadband")
- return EFFECTIVE_CONNECTION_TYPE_BROADBAND;
- NOTREACHED();
- return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
-}
-
void NetworkQualityEstimator::SetTickClockForTesting(
std::unique_ptr<base::TickClock> tick_clock) {
DCHECK(thread_checker_.CalledOnValidThread());
tick_clock_ = std::move(tick_clock);
}
-void NetworkQualityEstimator::CacheNetworkQualityEstimate() {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_LE(cached_network_qualities_.size(),
- static_cast<size_t>(kMaximumNetworkQualityCacheSize));
-
- // If the network name is unavailable, caching should not be performed.
- if (current_network_id_.id.empty())
- return;
-
- base::TimeDelta http_rtt = nqe::internal::InvalidRTT();
- int32_t downlink_throughput_kbps = nqe::internal::kInvalidThroughput;
-
- if (!GetHttpRTTEstimate(&http_rtt) ||
- !GetDownlinkThroughputKbpsEstimate(&downlink_throughput_kbps)) {
- return;
- }
-
- // |transport_rtt| is currently not cached.
- nqe::internal::NetworkQuality network_quality = nqe::internal::NetworkQuality(
- http_rtt, nqe::internal::InvalidRTT() /* transport_rtt */,
- downlink_throughput_kbps);
-
- if (cached_network_qualities_.size() == kMaximumNetworkQualityCacheSize) {
- // Remove the oldest entry.
- CachedNetworkQualities::iterator oldest_entry_iterator =
- cached_network_qualities_.begin();
-
- for (CachedNetworkQualities::iterator it =
- cached_network_qualities_.begin();
- it != cached_network_qualities_.end(); ++it) {
- if ((it->second).OlderThan(oldest_entry_iterator->second))
- oldest_entry_iterator = it;
- }
- cached_network_qualities_.erase(oldest_entry_iterator);
- }
- DCHECK_LT(cached_network_qualities_.size(),
- static_cast<size_t>(kMaximumNetworkQualityCacheSize));
-
- cached_network_qualities_.insert(
- std::make_pair(current_network_id_,
- nqe::internal::CachedNetworkQuality(network_quality)));
- DCHECK_LE(cached_network_qualities_.size(),
- static_cast<size_t>(kMaximumNetworkQualityCacheSize));
+double NetworkQualityEstimator::RandDouble() const {
+ return base::RandDouble();
}
void NetworkQualityEstimator::OnUpdatedRTTAvailable(
@@ -1289,7 +1630,7 @@ void NetworkQualityEstimator::NotifyObserversOfRTT(
// Maybe recompute the effective connection type since a new RTT observation
// is available.
- MaybeRecomputeEffectiveConnectionType();
+ MaybeComputeEffectiveConnectionType();
FOR_EACH_OBSERVER(
RTTObserver, rtt_observer_list_,
OnRTTObservation(observation.value.InMilliseconds(),
@@ -1303,7 +1644,7 @@ void NetworkQualityEstimator::NotifyObserversOfThroughput(
// Maybe recompute the effective connection type since a new throughput
// observation is available.
- MaybeRecomputeEffectiveConnectionType();
+ MaybeComputeEffectiveConnectionType();
FOR_EACH_OBSERVER(
ThroughputObserver, throughput_observer_list_,
OnThroughputObservation(observation.value, observation.timestamp,
@@ -1332,7 +1673,7 @@ void NetworkQualityEstimator::OnNewThroughputObservationAvailable(
NotifyObserversOfThroughput(throughput_observation);
}
-void NetworkQualityEstimator::MaybeRecomputeEffectiveConnectionType() {
+void NetworkQualityEstimator::MaybeComputeEffectiveConnectionType() {
DCHECK(thread_checker_.CalledOnValidThread());
const base::TimeTicks now = tick_clock_->NowTicks();
@@ -1344,26 +1685,54 @@ void NetworkQualityEstimator::MaybeRecomputeEffectiveConnectionType() {
// has not updated.
if (now - last_effective_connection_type_computation_ <
effective_connection_type_recomputation_interval_ &&
- last_connection_change_ < last_effective_connection_type_computation_) {
+ last_connection_change_ < last_effective_connection_type_computation_ &&
+ // Recompute the effective connection type if the previously computed
+ // effective connection type was unknown.
+ effective_connection_type_ != EFFECTIVE_CONNECTION_TYPE_UNKNOWN &&
+ // Recompute the effective connection type if the number of samples
+ // available now are 50% more than the number of samples that were
+ // available when the effective connection type was last computed.
+ rtt_observations_size_at_last_ect_computation_ * 1.5 >=
+ rtt_observations_.Size() &&
+ throughput_observations_size_at_last_ect_computation_ * 1.5 >=
+ downstream_throughput_kbps_observations_.Size()) {
return;
}
-
- const EffectiveConnectionType past_type = effective_connection_type_;
- last_effective_connection_type_computation_ = now;
- effective_connection_type_ = GetEffectiveConnectionType();
-
- if (past_type != effective_connection_type_)
- NotifyObserversOfEffectiveConnectionTypeChanged();
+ ComputeEffectiveConnectionType();
}
void NetworkQualityEstimator::
NotifyObserversOfEffectiveConnectionTypeChanged() {
DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_NE(EFFECTIVE_CONNECTION_TYPE_LAST, effective_connection_type_);
// TODO(tbansal): Add hysteresis in the notification.
FOR_EACH_OBSERVER(
EffectiveConnectionTypeObserver, effective_connection_type_observer_list_,
OnEffectiveConnectionTypeChanged(effective_connection_type_));
+
+ // Add the estimates of the current network to the cache store.
+ if (effective_connection_type_ != EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
+ network_quality_store_->Add(
+ current_network_id_,
+ nqe::internal::CachedNetworkQuality(
+ tick_clock_->NowTicks(), estimated_quality_at_last_main_frame_,
+ effective_connection_type_));
+ }
+}
+
+void NetworkQualityEstimator::AddNetworkQualitiesCacheObserver(
+ nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver*
+ observer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ network_quality_store_->AddNetworkQualitiesCacheObserver(observer);
+}
+
+void NetworkQualityEstimator::RemoveNetworkQualitiesCacheObserver(
+ nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver*
+ observer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ network_quality_store_->RemoveNetworkQualitiesCacheObserver(observer);
}
} // namespace net
diff --git a/chromium/net/nqe/network_quality_estimator.h b/chromium/net/nqe/network_quality_estimator.h
index b7fc886b5ab..46b6a8f5017 100644
--- a/chromium/net/nqe/network_quality_estimator.h
+++ b/chromium/net/nqe/network_quality_estimator.h
@@ -10,7 +10,6 @@
#include <map>
#include <memory>
#include <string>
-#include <tuple>
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
@@ -23,10 +22,13 @@
#include "net/base/net_export.h"
#include "net/base/network_change_notifier.h"
#include "net/nqe/cached_network_quality.h"
+#include "net/nqe/effective_connection_type.h"
#include "net/nqe/external_estimate_provider.h"
+#include "net/nqe/network_id.h"
#include "net/nqe/network_quality.h"
#include "net/nqe/network_quality_observation.h"
#include "net/nqe/network_quality_observation_source.h"
+#include "net/nqe/network_quality_store.h"
#include "net/nqe/observation_buffer.h"
#include "net/socket/socket_performance_watcher_factory.h"
@@ -52,32 +54,12 @@ class URLRequest;
// A single instance of NQE can be attached to multiple URLRequestContexts,
// thereby increasing the single NQE instance's accuracy by providing more
// observed traffic characteristics.
-class NET_EXPORT_PRIVATE NetworkQualityEstimator
+class NET_EXPORT NetworkQualityEstimator
: public NetworkChangeNotifier::ConnectionTypeObserver,
public ExternalEstimateProvider::UpdatedEstimateDelegate {
public:
- // EffectiveConnectionType is the connection type whose typical performance is
- // most similar to the measured performance of the network in use. In many
- // cases, the "effective" connection type and the actual type of connection in
- // use are the same, but often a network connection performs significantly
- // different, usually worse, from its expected capabilities.
- // EffectiveConnectionType of a network is independent of if the current
- // connection is metered or not. For example, an unmetered slow connection may
- // have EFFECTIVE_CONNECTION_TYPE_SLOW_2G as its effective connection type.
- enum EffectiveConnectionType {
- // The connection types should be in increasing order of quality.
- EFFECTIVE_CONNECTION_TYPE_UNKNOWN = 0,
- EFFECTIVE_CONNECTION_TYPE_OFFLINE,
- EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
- EFFECTIVE_CONNECTION_TYPE_2G,
- EFFECTIVE_CONNECTION_TYPE_3G,
- EFFECTIVE_CONNECTION_TYPE_4G,
- EFFECTIVE_CONNECTION_TYPE_BROADBAND,
- EFFECTIVE_CONNECTION_TYPE_LAST,
- };
-
// Observes changes in effective connection type.
- class NET_EXPORT_PRIVATE EffectiveConnectionTypeObserver {
+ class NET_EXPORT EffectiveConnectionTypeObserver {
public:
// Notifies the observer of a change in the effective connection type.
// NetworkQualityEstimator computes the effective connection type once in
@@ -138,6 +120,21 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
DISALLOW_COPY_AND_ASSIGN(ThroughputObserver);
};
+ // Provides simple interface to obtain the effective connection type.
+ class NET_EXPORT NetworkQualityProvider {
+ public:
+ // Returns the current effective connection type.
+ virtual EffectiveConnectionType GetEffectiveConnectionType() const = 0;
+
+ virtual ~NetworkQualityProvider() {}
+
+ protected:
+ NetworkQualityProvider() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NetworkQualityProvider);
+ };
+
// Creates a new NetworkQualityEstimator.
// |variation_params| is the map containing all field trial parameters
// related to NetworkQualityEstimator field trial.
@@ -166,8 +163,10 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
~NetworkQualityEstimator() override;
- // Returns the effective type of the current connection. Virtualized for
- // testing.
+ // Returns the last computed effective type of the current connection. The
+ // effective connection type is computed by the network quality estimator at
+ // regular intervals and at certain events (e.g., connection change).
+ // Virtualized for testing.
virtual EffectiveConnectionType GetEffectiveConnectionType() const;
// Returns the effective type of the current connection based on only the
@@ -196,7 +195,7 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// Notifies NetworkQualityEstimator that the response body of |request| has
// been received.
- void NotifyRequestCompleted(const URLRequest& request);
+ void NotifyRequestCompleted(const URLRequest& request, int net_error);
// Notifies NetworkQualityEstimator that |request| will be destroyed.
void NotifyURLRequestDestroyed(const URLRequest& request);
@@ -219,14 +218,6 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
SocketPerformanceWatcherFactory* GetSocketPerformanceWatcherFactory();
- // Returns a string equivalent to |type|.
- static const char* GetNameForEffectiveConnectionType(
- EffectiveConnectionType type);
-
- // Returns an EffectiveConnectionType equivalent to |connection_type_name|.
- static EffectiveConnectionType GetEffectiveConnectionTypeForName(
- const std::string& connection_type_name);
-
// |use_localhost_requests| should only be true when testing against local
// HTTP server and allows the requests to local host to be used for network
// quality estimation.
@@ -237,47 +228,20 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// network quality estimation.
void SetUseSmallResponsesForTesting(bool use_small_responses);
- protected:
- // NetworkID is used to uniquely identify a network.
- // For the purpose of network quality estimation and caching, a network is
- // uniquely identified by a combination of |type| and
- // |id|. This approach is unable to distinguish networks with
- // same name (e.g., different Wi-Fi networks with same SSID).
- // This is a protected member to expose it to tests.
- struct NET_EXPORT_PRIVATE NetworkID {
- NetworkID(NetworkChangeNotifier::ConnectionType type, const std::string& id)
- : type(type), id(id) {}
- NetworkID(const NetworkID& other) : type(other.type), id(other.id) {}
- ~NetworkID() {}
-
- NetworkID& operator=(const NetworkID& other) {
- type = other.type;
- id = other.id;
- return *this;
- }
-
- // Overloaded because NetworkID is used as key in a map.
- bool operator<(const NetworkID& other) const {
- return std::tie(type, id) < std::tie(other.type, other.id);
- }
-
- // Connection type of the network.
- NetworkChangeNotifier::ConnectionType type;
-
- // Name of this network. This is set to:
- // - Wi-Fi SSID if the device is connected to a Wi-Fi access point and the
- // SSID name is available, or
- // - MCC/MNC code of the cellular carrier if the device is connected to a
- // cellular network, or
- // - "Ethernet" in case the device is connected to ethernet.
- // - An empty string in all other cases or if the network name is not
- // exposed by platform APIs.
- std::string id;
- };
+ // Reports |effective_connection_type| to all
+ // EffectiveConnectionTypeObservers.
+ void ReportEffectiveConnectionTypeForTesting(
+ EffectiveConnectionType effective_connection_type);
- // Returns true if the cached network quality estimate was successfully read.
- bool ReadCachedNetworkQualityEstimate();
+ // Adds and removes |observer| from the list of cache observers.
+ void AddNetworkQualitiesCacheObserver(
+ nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver*
+ observer);
+ void RemoveNetworkQualitiesCacheObserver(
+ nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver*
+ observer);
+ protected:
// NetworkChangeNotifier::ConnectionTypeObserver implementation:
void OnConnectionTypeChanged(
NetworkChangeNotifier::ConnectionType type) override;
@@ -292,18 +256,19 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// at the HTTP layer measures the time from when the request was sent (this
// happens after the connection is established) to the time when the response
// headers were received.
- virtual bool GetHttpRTTEstimate(base::TimeDelta* rtt) const
- WARN_UNUSED_RESULT;
+ // TODO(tbansal): Change it to return HTTP RTT as base::TimeDelta.
+ virtual bool GetHttpRTT(base::TimeDelta* rtt) const WARN_UNUSED_RESULT;
// Returns true if the RTT is available and sets |rtt| to the RTT estimated at
// the transport layer. |rtt| should not be null. Virtualized for testing.
- virtual bool GetTransportRTTEstimate(base::TimeDelta* rtt) const
- WARN_UNUSED_RESULT;
+ // TODO(tbansal): Change it to return transport RTT as base::TimeDelta.
+ virtual bool GetTransportRTT(base::TimeDelta* rtt) const WARN_UNUSED_RESULT;
// Returns true if downlink throughput is available and sets |kbps| to
// estimated downlink throughput (in kilobits per second).
// Virtualized for testing. |kbps| should not be null.
- virtual bool GetDownlinkThroughputKbpsEstimate(int32_t* kbps) const;
+ // TODO(tbansal): Change it to return throughput as int32.
+ virtual bool GetDownlinkThroughputKbps(int32_t* kbps) const;
// Returns true if median RTT at the HTTP layer is available and sets |rtt|
// to the median of RTT observations since |start_time|.
@@ -311,22 +276,24 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// layer measures the time from when the request was sent (this happens after
// the connection is established) to the time when the response headers were
// received.
- virtual bool GetRecentHttpRTTMedian(const base::TimeTicks& start_time,
- base::TimeDelta* rtt) const
- WARN_UNUSED_RESULT;
+ // TODO(tbansal): Change it to return HTTP RTT as base::TimeDelta.
+ virtual bool GetRecentHttpRTT(const base::TimeTicks& start_time,
+ base::TimeDelta* rtt) const WARN_UNUSED_RESULT;
// Returns true if the median RTT at the transport layer is available and sets
// |rtt| to the median of transport layer RTT observations since
// |start_time|. |rtt| should not be null. Virtualized for testing.
- virtual bool GetRecentTransportRTTMedian(const base::TimeTicks& start_time,
- base::TimeDelta* rtt) const
+ // TODO(tbansal): Change it to return transport RTT as base::TimeDelta.
+ virtual bool GetRecentTransportRTT(const base::TimeTicks& start_time,
+ base::TimeDelta* rtt) const
WARN_UNUSED_RESULT;
// Returns true if median downstream throughput is available and sets |kbps|
// to the median of downstream throughput (in kilobits per second)
// observations since |start_time|. Virtualized for testing. |kbps|
// should not be null. Virtualized for testing.
- virtual bool GetRecentMedianDownlinkThroughputKbps(
+ // TODO(tbansal): Change it to return throughput as int32.
+ virtual bool GetRecentDownlinkThroughputKbps(
const base::TimeTicks& start_time,
int32_t* kbps) const WARN_UNUSED_RESULT;
@@ -338,7 +305,12 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// 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;
+
private:
+ FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
+ AdaptiveRecomputationEffectiveConnectionType);
FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, StoreObservations);
FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestAddObservation);
FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, ObtainOperatingParams);
@@ -346,12 +318,11 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
ObtainAlgorithmToUseFromParams);
FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, HalfLifeParam);
FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, ComputedPercentiles);
- FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestCaching);
- FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
- TestLRUCacheMaximumSize);
FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestGetMetricsSince);
FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
TestExternalEstimateProviderMergeEstimates);
+ FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
+ UnknownEffectiveConnectionType);
// Value of round trip time observations is in base::TimeDelta.
typedef nqe::internal::Observation<base::TimeDelta> RttObservation;
@@ -362,20 +333,31 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
typedef nqe::internal::Observation<int32_t> ThroughputObservation;
typedef nqe::internal::ObservationBuffer<int32_t> ThroughputObservationBuffer;
- // This does not use a unordered_map or hash_map for code simplicity (key just
- // implements operator<, rather than hash and equality) and because the map is
- // tiny.
- typedef std::map<NetworkID, nqe::internal::CachedNetworkQuality>
- CachedNetworkQualities;
-
// Algorithms supported by network quality estimator for computing effective
// connection type.
enum class EffectiveConnectionTypeAlgorithm {
HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT = 0,
+ TRANSPORT_RTT_OR_DOWNSTREAM_THROUGHOUT,
EFFECTIVE_CONNECTION_TYPE_ALGORITHM_LAST
};
+ // Defines how a metric (e.g, transport RTT) should be used when computing
+ // the effective connection type.
+ enum class MetricUsage {
+ // The metric should not be used when computing the effective connection
+ // type.
+ DO_NOT_USE = 0,
+ // If the metric is available, then it should be used when computing the
+ // effective connection type.
+ USE_IF_AVAILABLE,
+ // The metric is required when computing the effective connection type.
+ // If the value of the metric is unavailable, effective connection type
+ // should be set to |EFFECTIVE_CONNECTION_TYPE_UNKNOWN|.
+ MUST_BE_USED,
+ };
+
// Map from algorithm names to EffectiveConnectionTypeAlgorithm.
+ // TODO(tbansal): Consider using an autogenerated enum using macros.
const std::map<std::string, EffectiveConnectionTypeAlgorithm>
algorithm_name_to_enum_;
@@ -393,18 +375,21 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// kilobits per second) values.
static const int kMinimumThroughputVariationParameterKbps = 1;
- // Maximum size of the cache that holds network quality estimates.
- // Smaller size may reduce the cache hit rate due to frequent evictions.
- // Larger size may affect performance.
- static const size_t kMaximumNetworkQualityCacheSize = 10;
-
// Returns the RTT value to be used when the valid RTT is unavailable. Readers
// should discard RTT if it is set to the value returned by |InvalidRTT()|.
static const base::TimeDelta InvalidRTT();
+ // Queries external estimate provider for network quality. When the network
+ // 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;
+
// Records UMA on main frame requests.
void RecordMetricsOnMainFrameRequest() const;
@@ -452,10 +437,7 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// Returns the current network ID checking by calling the platform APIs.
// Virtualized for testing.
- virtual NetworkID GetCurrentNetworkID() const;
-
- // Writes the estimated quality of the current network to the cache.
- void CacheNetworkQualityEstimate();
+ virtual nqe::internal::NetworkID GetCurrentNetworkID() const;
void NotifyObserversOfRTT(const RttObservation& observation);
@@ -466,7 +448,7 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// Recomputes effective connection type, if it was computed more than the
// specified duration ago, or if there has been a connection change recently.
- void MaybeRecomputeEffectiveConnectionType();
+ void MaybeComputeEffectiveConnectionType();
// Notify observers of a change in effective connection type.
void NotifyObserversOfEffectiveConnectionTypeChanged();
@@ -477,13 +459,21 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// main frame request is observed.
void RecordAccuracyAfterMainFrame(base::TimeDelta measuring_duration) const;
+ // Obtains the current cellular signal strength value and updates
+ // |min_signal_strength_since_connection_change_| and
+ // |max_signal_strength_since_connection_change_|.
+ void UpdateSignalStrength();
+
// Returns the effective type of the current connection based on only the
- // samples observed after |start_time|. Uses HTTP RTT and downstream
- // throughput to compute the effective connection type, and requires both of
- // them to have a valid value.
- EffectiveConnectionType
- GetRecentEffectiveConnectionTypeHttpRTTAndDownstreamThroughput(
- const base::TimeTicks& start_time) const;
+ // samples observed after |start_time|. May use HTTP RTT, transport RTT and
+ // downstream throughput to compute the effective connection type based on
+ // |http_rtt_metric|, |transport_rtt_metric| and
+ // |downstream_throughput_kbps_metric|, respectively.
+ EffectiveConnectionType GetRecentEffectiveConnectionTypeUsingMetrics(
+ const base::TimeTicks& start_time,
+ MetricUsage http_rtt_metric,
+ MetricUsage transport_rtt_metric,
+ MetricUsage downstream_throughput_kbps_metric) const;
// Values of external estimate provider status. This enum must remain
// synchronized with the enum of the same name in
@@ -503,6 +493,22 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
void RecordExternalEstimateProviderMetrics(
NQEExternalEstimateProviderStatus status) const;
+ // 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;
+
+ // Forces computation of effective connection type, and notifies observers
+ // if there is a change in its value.
+ void ComputeEffectiveConnectionType();
+
// Determines if the requests to local host can be used in estimating the
// network quality. Set to true only for tests.
bool use_localhost_requests_;
@@ -524,13 +530,6 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// Tick clock used by the network quality estimator.
std::unique_ptr<base::TickClock> tick_clock_;
- // Minimum duration between two consecutive computations of effective
- // connection type. Set to non-zero value as a performance optimization.
- const base::TimeDelta effective_connection_type_recomputation_interval_;
-
- // Time when the effective connection type was last computed.
- base::TimeTicks last_effective_connection_type_computation_;
-
// Intervals after the main frame request arrives at which accuracy of network
// quality prediction is recorded.
std::vector<base::TimeDelta> accuracy_recording_intervals_;
@@ -539,7 +538,7 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
base::TimeTicks last_connection_change_;
// ID of the current network.
- NetworkID current_network_id_;
+ nqe::internal::NetworkID current_network_id_;
// Peak network quality (fastest round-trip-time (RTT) and highest
// downstream throughput) measured since last connectivity change. RTT is
@@ -549,9 +548,6 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// 2) Includes server processing time.
nqe::internal::NetworkQuality peak_network_quality_;
- // Cache that stores quality of previously seen networks.
- CachedNetworkQualities cached_network_qualities_;
-
// Buffer that holds throughput observations (in kilobits per second) sorted
// by timestamp.
ThroughputObservationBuffer downstream_throughput_kbps_observations_;
@@ -565,12 +561,18 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
nqe::internal::NetworkQuality
default_observations_[NetworkChangeNotifier::CONNECTION_LAST + 1];
+ // Default thresholds for different effective connection types. The default
+ // values are used if the thresholds are unavailable from the variation
+ // params.
+ nqe::internal::NetworkQuality default_effective_connection_type_thresholds_
+ [EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_LAST];
+
// Thresholds for different effective connection types obtained from field
// trial variation params. These thresholds encode how different connection
// types behave in general. In future, complex encodings (e.g., curve
// fitting) may be used.
- nqe::internal::NetworkQuality
- connection_thresholds_[EFFECTIVE_CONNECTION_TYPE_LAST];
+ nqe::internal::NetworkQuality connection_thresholds_
+ [EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_LAST];
// Latest time when the headers for a main frame request were received.
base::TimeTicks last_main_frame_request_;
@@ -580,6 +582,10 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
nqe::internal::NetworkQuality estimated_quality_at_last_main_frame_;
EffectiveConnectionType effective_connection_type_at_last_main_frame_;
+ // Estimated network quality obtained from external estimate provider when the
+ // external estimate provider was last queried.
+ nqe::internal::NetworkQuality external_estimate_provider_quality_;
+
// ExternalEstimateProvider that provides network quality using operating
// system APIs. May be NULL.
const std::unique_ptr<ExternalEstimateProvider> external_estimate_provider_;
@@ -600,12 +606,45 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator
// estimating the throughput.
std::unique_ptr<nqe::internal::ThroughputAnalyzer> throughput_analyzer_;
+ // Minimum duration between two consecutive computations of effective
+ // connection type. Set to non-zero value as a performance optimization.
+ const base::TimeDelta effective_connection_type_recomputation_interval_;
+
+ // Time when the effective connection type was last computed.
+ base::TimeTicks last_effective_connection_type_computation_;
+
+ // Number of RTT and bandwidth samples available when effective connection
+ // type was last recomputed.
+ size_t rtt_observations_size_at_last_ect_computation_;
+ size_t throughput_observations_size_at_last_ect_computation_;
+
// Current effective connection type. It is updated on connection change
// events. It is also updated every time there is network traffic (provided
// the last computation was more than
// |effective_connection_type_recomputation_interval_| ago).
EffectiveConnectionType effective_connection_type_;
+ // Minimum and Maximum signal strength (in dbM) observed since last connection
+ // change. Updated on connection change and main frame requests.
+ int32_t min_signal_strength_since_connection_change_;
+ int32_t max_signal_strength_since_connection_change_;
+
+ // It is costlier to add values to a sparse histogram. So, the correlation UMA
+ // is recorded with |correlation_uma_logging_probability_| since recording it
+ // in a sparse histogram for each request is unnecessary and cost-prohibitive.
+ // e.g., if it is 0.0, then the UMA will never be recorded. On the other hand,
+ // if it is 1.0, then it will be recorded for all valid HTTP requests.
+ const double correlation_uma_logging_probability_;
+
+ // Stores the qualities of different networks.
+ std::unique_ptr<nqe::internal::NetworkQualityStore> network_quality_store_;
+
+ // True if effective connection type value has been forced via variation
+ // parameters. If set to true, GetEffectiveConnectionType() will always return
+ // |forced_effective_connection_type_|.
+ const bool forced_effective_connection_type_set_;
+ EffectiveConnectionType forced_effective_connection_type_;
+
base::ThreadChecker thread_checker_;
base::WeakPtrFactory<NetworkQualityEstimator> weak_ptr_factory_;
diff --git a/chromium/net/nqe/network_quality_estimator_test_util.cc b/chromium/net/nqe/network_quality_estimator_test_util.cc
new file mode 100644
index 00000000000..80e7889ffb6
--- /dev/null
+++ b/chromium/net/nqe/network_quality_estimator_test_util.cc
@@ -0,0 +1,191 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/nqe/network_quality_estimator_test_util.h"
+
+#include "base/files/file_path.h"
+#include "base/run_loop.h"
+#include "net/base/load_flags.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_test_util.h"
+
+namespace net {
+
+TestNetworkQualityEstimator::TestNetworkQualityEstimator(
+ const std::map<std::string, std::string>& variation_params,
+ std::unique_ptr<net::ExternalEstimateProvider> external_estimate_provider)
+ : TestNetworkQualityEstimator(std::move(external_estimate_provider),
+ variation_params,
+ true,
+ true) {}
+
+TestNetworkQualityEstimator::TestNetworkQualityEstimator(
+ std::unique_ptr<net::ExternalEstimateProvider> external_estimate_provider,
+ const std::map<std::string, std::string>& variation_params,
+ bool allow_local_host_requests_for_tests,
+ bool allow_smaller_responses_for_tests)
+ : NetworkQualityEstimator(std::move(external_estimate_provider),
+ variation_params,
+ allow_local_host_requests_for_tests,
+ allow_smaller_responses_for_tests),
+ effective_connection_type_set_(false),
+ effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
+ recent_effective_connection_type_set_(false),
+ recent_effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
+ current_network_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN),
+ accuracy_recording_intervals_set_(false),
+ http_rtt_set_(false),
+ recent_http_rtt_set_(false),
+ transport_rtt_set_(false),
+ recent_transport_rtt_set_(false),
+ downlink_throughput_kbps_set_(false),
+ recent_downlink_throughput_kbps_set_(false),
+ rand_double_(0.0) {
+ // Set up the embedded test server.
+ embedded_test_server_.ServeFilesFromDirectory(
+ base::FilePath(FILE_PATH_LITERAL("net/data/url_request_unittest")));
+ EXPECT_TRUE(embedded_test_server_.Start());
+ embedded_test_server_.RegisterRequestHandler(base::Bind(
+ &TestNetworkQualityEstimator::HandleRequest, base::Unretained(this)));
+}
+
+TestNetworkQualityEstimator::TestNetworkQualityEstimator(
+ const std::map<std::string, std::string>& variation_params)
+ : TestNetworkQualityEstimator(variation_params,
+ std::unique_ptr<ExternalEstimateProvider>()) {
+}
+
+TestNetworkQualityEstimator::~TestNetworkQualityEstimator() {}
+
+void TestNetworkQualityEstimator::RunOneRequest() {
+ TestDelegate test_delegate;
+ TestURLRequestContext context(true);
+ context.set_network_quality_estimator(this);
+ context.Init();
+ std::unique_ptr<URLRequest> request(
+ context.CreateRequest(GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
+ request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
+ request->Start();
+ base::RunLoop().Run();
+}
+
+void TestNetworkQualityEstimator::SimulateNetworkChange(
+ NetworkChangeNotifier::ConnectionType new_connection_type,
+ const std::string& network_id) {
+ current_network_type_ = new_connection_type;
+ current_network_id_ = network_id;
+ OnConnectionTypeChanged(new_connection_type);
+}
+
+std::unique_ptr<test_server::HttpResponse>
+TestNetworkQualityEstimator::HandleRequest(
+ const test_server::HttpRequest& request) {
+ std::unique_ptr<test_server::BasicHttpResponse> http_response(
+ new test_server::BasicHttpResponse());
+ http_response->set_code(HTTP_OK);
+ http_response->set_content("hello");
+ http_response->set_content_type("text/plain");
+ return std::move(http_response);
+}
+
+const GURL TestNetworkQualityEstimator::GetEchoURL() const {
+ return embedded_test_server_.GetURL("/echo.html");
+}
+
+EffectiveConnectionType
+TestNetworkQualityEstimator::GetEffectiveConnectionType() const {
+ if (effective_connection_type_set_)
+ return effective_connection_type_;
+ return NetworkQualityEstimator::GetEffectiveConnectionType();
+}
+
+EffectiveConnectionType
+TestNetworkQualityEstimator::GetRecentEffectiveConnectionType(
+ const base::TimeTicks& start_time) const {
+ if (recent_effective_connection_type_set_)
+ return recent_effective_connection_type_;
+ return NetworkQualityEstimator::GetRecentEffectiveConnectionType(start_time);
+}
+
+bool TestNetworkQualityEstimator::GetHttpRTT(base::TimeDelta* rtt) const {
+ if (http_rtt_set_) {
+ *rtt = http_rtt_;
+ return true;
+ }
+ return NetworkQualityEstimator::GetHttpRTT(rtt);
+}
+
+bool TestNetworkQualityEstimator::GetRecentHttpRTT(
+ const base::TimeTicks& start_time,
+ base::TimeDelta* rtt) const {
+ if (recent_http_rtt_set_) {
+ *rtt = recent_http_rtt_;
+ return true;
+ }
+ return NetworkQualityEstimator::GetRecentHttpRTT(start_time, rtt);
+}
+
+bool TestNetworkQualityEstimator::GetTransportRTT(base::TimeDelta* rtt) const {
+ if (transport_rtt_set_) {
+ *rtt = transport_rtt_;
+ return true;
+ }
+ return NetworkQualityEstimator::GetTransportRTT(rtt);
+}
+
+bool TestNetworkQualityEstimator::GetRecentTransportRTT(
+ const base::TimeTicks& start_time,
+ base::TimeDelta* rtt) const {
+ if (recent_transport_rtt_set_) {
+ *rtt = recent_transport_rtt_;
+ return true;
+ }
+ return NetworkQualityEstimator::GetRecentTransportRTT(start_time, rtt);
+}
+
+bool TestNetworkQualityEstimator::GetDownlinkThroughputKbps(
+ int32_t* kbps) const {
+ if (downlink_throughput_kbps_set_) {
+ *kbps = downlink_throughput_kbps_;
+ return true;
+ }
+ return NetworkQualityEstimator::GetDownlinkThroughputKbps(kbps);
+}
+
+bool TestNetworkQualityEstimator::GetRecentDownlinkThroughputKbps(
+ const base::TimeTicks& start_time,
+ int32_t* kbps) const {
+ if (recent_downlink_throughput_kbps_set_) {
+ *kbps = recent_downlink_throughput_kbps_;
+ return true;
+ }
+ return NetworkQualityEstimator::GetRecentDownlinkThroughputKbps(start_time,
+ kbps);
+}
+
+void TestNetworkQualityEstimator::SetAccuracyRecordingIntervals(
+ const std::vector<base::TimeDelta>& accuracy_recording_intervals) {
+ accuracy_recording_intervals_set_ = true;
+ accuracy_recording_intervals_ = accuracy_recording_intervals;
+}
+
+const std::vector<base::TimeDelta>&
+TestNetworkQualityEstimator::GetAccuracyRecordingIntervals() const {
+ if (accuracy_recording_intervals_set_)
+ return accuracy_recording_intervals_;
+
+ return NetworkQualityEstimator::GetAccuracyRecordingIntervals();
+}
+
+double TestNetworkQualityEstimator::RandDouble() const {
+ return rand_double_;
+}
+
+nqe::internal::NetworkID TestNetworkQualityEstimator::GetCurrentNetworkID()
+ const {
+ return nqe::internal::NetworkID(current_network_type_, current_network_id_);
+}
+
+} // namespace net
diff --git a/chromium/net/nqe/network_quality_estimator_test_util.h b/chromium/net/nqe/network_quality_estimator_test_util.h
new file mode 100644
index 00000000000..15203aac232
--- /dev/null
+++ b/chromium/net/nqe/network_quality_estimator_test_util.h
@@ -0,0 +1,197 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/nqe/network_quality_estimator.h"
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "net/base/network_change_notifier.h"
+#include "net/nqe/effective_connection_type.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace net {
+
+class ExternalEstimateProvider;
+
+namespace test_server {
+struct HttpRequest;
+class HttpResponse;
+}
+
+// Helps in setting the current network type and id.
+class TestNetworkQualityEstimator : public NetworkQualityEstimator {
+ public:
+ TestNetworkQualityEstimator(
+ const std::map<std::string, std::string>& variation_params,
+ std::unique_ptr<net::ExternalEstimateProvider>
+ external_estimate_provider);
+
+ TestNetworkQualityEstimator(
+ std::unique_ptr<net::ExternalEstimateProvider> external_estimate_provider,
+ const std::map<std::string, std::string>& variation_params,
+ bool allow_local_host_requests_for_tests,
+ bool allow_smaller_responses_for_tests);
+
+ explicit TestNetworkQualityEstimator(
+ const std::map<std::string, std::string>& variation_params);
+
+ ~TestNetworkQualityEstimator() override;
+
+ // Runs one URL request to completion.
+ void RunOneRequest();
+
+ // Overrides the current network type and id.
+ // Notifies network quality estimator of a change in connection.
+ void SimulateNetworkChange(
+ NetworkChangeNotifier::ConnectionType new_connection_type,
+ const std::string& network_id);
+
+ // Called by the embedded server when an HTTP request is received.
+ std::unique_ptr<test_server::HttpResponse> HandleRequest(
+ const test_server::HttpRequest& request);
+
+ // Returns a GURL hosted at the embedded test server.
+ const GURL GetEchoURL() const;
+
+ void set_effective_connection_type(EffectiveConnectionType type) {
+ effective_connection_type_set_ = true;
+ effective_connection_type_ = type;
+ }
+
+ // Returns the effective connection type that was set using
+ // |set_effective_connection_type|. If the connection type has not been set,
+ // then the base implementation is called.
+ EffectiveConnectionType GetEffectiveConnectionType() const override;
+
+ void set_recent_effective_connection_type(EffectiveConnectionType type) {
+ recent_effective_connection_type_set_ = true;
+ recent_effective_connection_type_ = type;
+ }
+
+ // Returns the effective connection type that was set using
+ // |set_effective_connection_type|. If the connection type has not been set,
+ // then the base implementation is called.
+ EffectiveConnectionType GetRecentEffectiveConnectionType(
+ const base::TimeTicks& start_time) const override;
+
+ void set_http_rtt(const base::TimeDelta& http_rtt) {
+ http_rtt_set_ = true;
+ http_rtt_ = http_rtt;
+ }
+ // Returns the HTTP RTT that was set using |set_http_rtt|. If the HTTP RTT has
+ // not been set, then the base implementation is called.
+ bool GetHttpRTT(base::TimeDelta* rtt) const override;
+
+ void set_recent_http_rtt(const base::TimeDelta& recent_http_rtt) {
+ recent_http_rtt_set_ = true;
+ recent_http_rtt_ = recent_http_rtt;
+ }
+ // Returns the recent HTTP RTT that was set using |set_recent_http_rtt|. If
+ // the recent HTTP RTT has not been set, then the base implementation is
+ // called.
+ bool GetRecentHttpRTT(const base::TimeTicks& start_time,
+ base::TimeDelta* rtt) const override;
+
+ void set_transport_rtt(const base::TimeDelta& transport_rtt) {
+ transport_rtt_set_ = true;
+ transport_rtt_ = transport_rtt;
+ }
+ // Returns the transport RTT that was set using |set_transport_rtt|. If the
+ // transport RTT has not been set, then the base implementation is called.
+ bool GetTransportRTT(base::TimeDelta* rtt) const override;
+
+ void set_recent_transport_rtt(const base::TimeDelta& recent_transport_rtt) {
+ recent_transport_rtt_set_ = true;
+ recent_transport_rtt_ = recent_transport_rtt;
+ }
+ // Returns the recent transport RTT that was set using
+ // |set_recent_transport_rtt|. If the recent transport RTT has not been set,
+ // then the base implementation is called.
+ bool GetRecentTransportRTT(const base::TimeTicks& start_time,
+ base::TimeDelta* rtt) const override;
+
+ void set_downlink_throughput_kbps(int32_t downlink_throughput_kbps) {
+ downlink_throughput_kbps_set_ = true;
+ downlink_throughput_kbps_ = downlink_throughput_kbps;
+ }
+ // Returns the downlink throughput that was set using
+ // |set_downlink_throughput_kbps|. If the downlink throughput has not been
+ // set, then the base implementation is called.
+ bool GetDownlinkThroughputKbps(int32_t* kbps) const override;
+
+ void set_recent_downlink_throughput_kbps(
+ int32_t recent_downlink_throughput_kbps) {
+ recent_downlink_throughput_kbps_set_ = true;
+ recent_downlink_throughput_kbps_ = recent_downlink_throughput_kbps;
+ }
+ // Returns the downlink throughput that was set using
+ // |set_recent_downlink_throughput_kbps|. If the downlink throughput has not
+ // been set, then the base implementation is called.
+ bool GetRecentDownlinkThroughputKbps(const base::TimeTicks& start_time,
+ int32_t* kbps) const override;
+
+ void SetAccuracyRecordingIntervals(
+ const std::vector<base::TimeDelta>& accuracy_recording_intervals);
+
+ const std::vector<base::TimeDelta>& GetAccuracyRecordingIntervals()
+ const override;
+
+ void set_rand_double(double rand_double) { rand_double_ = rand_double; }
+
+ double RandDouble() const override;
+
+ using NetworkQualityEstimator::SetTickClockForTesting;
+ using NetworkQualityEstimator::OnConnectionTypeChanged;
+
+ private:
+ // NetworkQualityEstimator implementation that returns the overridden
+ // network
+ // id (instead of invoking platform APIs).
+ nqe::internal::NetworkID GetCurrentNetworkID() const override;
+
+ bool effective_connection_type_set_;
+ EffectiveConnectionType effective_connection_type_;
+
+ bool recent_effective_connection_type_set_;
+ EffectiveConnectionType recent_effective_connection_type_;
+
+ NetworkChangeNotifier::ConnectionType current_network_type_;
+ std::string current_network_id_;
+
+ bool accuracy_recording_intervals_set_;
+ std::vector<base::TimeDelta> accuracy_recording_intervals_;
+
+ bool http_rtt_set_;
+ base::TimeDelta http_rtt_;
+
+ bool recent_http_rtt_set_;
+ base::TimeDelta recent_http_rtt_;
+
+ bool transport_rtt_set_;
+ base::TimeDelta transport_rtt_;
+
+ bool recent_transport_rtt_set_;
+ base::TimeDelta recent_transport_rtt_;
+
+ bool downlink_throughput_kbps_set_;
+ int32_t downlink_throughput_kbps_;
+
+ bool recent_downlink_throughput_kbps_set_;
+ int32_t recent_downlink_throughput_kbps_;
+
+ double rand_double_;
+
+ EmbeddedTestServer embedded_test_server_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestNetworkQualityEstimator);
+};
+
+} // namespace net
diff --git a/chromium/net/nqe/network_quality_estimator_unittest.cc b/chromium/net/nqe/network_quality_estimator_unittest.cc
index 40a28c55e53..442a42b3853 100644
--- a/chromium/net/nqe/network_quality_estimator_unittest.cc
+++ b/chromium/net/nqe/network_quality_estimator_unittest.cc
@@ -14,7 +14,6 @@
#include <utility>
#include <vector>
-#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/metrics/histogram_samples.h"
@@ -28,15 +27,14 @@
#include "net/base/load_flags.h"
#include "net/base/network_change_notifier.h"
#include "net/http/http_status_code.h"
+#include "net/nqe/effective_connection_type.h"
#include "net/nqe/external_estimate_provider.h"
+#include "net/nqe/network_quality_estimator_test_util.h"
#include "net/nqe/network_quality_observation.h"
#include "net/nqe/network_quality_observation_source.h"
#include "net/nqe/observation_buffer.h"
#include "net/socket/socket_performance_watcher.h"
#include "net/socket/socket_performance_watcher_factory.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/url_request/url_request.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -46,289 +44,20 @@ namespace net {
namespace {
-// Helps in setting the current network type and id.
-class TestNetworkQualityEstimator : public NetworkQualityEstimator {
- public:
- TestNetworkQualityEstimator(
- const std::map<std::string, std::string>& variation_params,
- std::unique_ptr<net::ExternalEstimateProvider> external_estimate_provider)
- : TestNetworkQualityEstimator(std::move(external_estimate_provider),
- variation_params,
- true,
- true) {}
-
- TestNetworkQualityEstimator(
- std::unique_ptr<net::ExternalEstimateProvider> external_estimate_provider,
- const std::map<std::string, std::string>& variation_params,
- bool allow_local_host_requests_for_tests,
- bool allow_smaller_responses_for_tests)
- : NetworkQualityEstimator(std::move(external_estimate_provider),
- variation_params,
- allow_local_host_requests_for_tests,
- allow_smaller_responses_for_tests),
- effective_connection_type_set_(false),
- effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
- recent_effective_connection_type_set_(false),
- recent_effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
- current_network_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN),
- accuracy_recording_intervals_set_(false),
- http_rtt_set_(false),
- recent_http_rtt_set_(false),
- transport_rtt_set_(false),
- recent_transport_rtt_set_(false),
- downlink_throughput_kbps_set_(false),
- recent_downlink_throughput_kbps_set_(false) {
- // Set up embedded test server.
- embedded_test_server_.ServeFilesFromDirectory(
- base::FilePath(FILE_PATH_LITERAL("net/data/url_request_unittest")));
- EXPECT_TRUE(embedded_test_server_.Start());
- embedded_test_server_.RegisterRequestHandler(base::Bind(
- &TestNetworkQualityEstimator::HandleRequest, base::Unretained(this)));
- }
-
- explicit TestNetworkQualityEstimator(
- const std::map<std::string, std::string>& variation_params)
- : TestNetworkQualityEstimator(
- variation_params,
- std::unique_ptr<ExternalEstimateProvider>()) {}
-
- ~TestNetworkQualityEstimator() override {}
-
- // Overrides the current network type and id.
- // Notifies network quality estimator of change in connection.
- void SimulateNetworkChangeTo(NetworkChangeNotifier::ConnectionType type,
- const std::string& network_id) {
- current_network_type_ = type;
- current_network_id_ = network_id;
- OnConnectionTypeChanged(type);
- }
-
- // Called by embedded server when a HTTP request is received.
- std::unique_ptr<test_server::HttpResponse> HandleRequest(
- const test_server::HttpRequest& request) {
- std::unique_ptr<test_server::BasicHttpResponse> http_response(
- new test_server::BasicHttpResponse());
- http_response->set_code(HTTP_OK);
- http_response->set_content("hello");
- http_response->set_content_type("text/plain");
- return std::move(http_response);
- }
-
- // Returns a GURL hosted at embedded test server.
- const GURL GetEchoURL() const {
- return embedded_test_server_.GetURL("/echo.html");
- }
-
- void set_effective_connection_type(EffectiveConnectionType type) {
- effective_connection_type_set_ = true;
- effective_connection_type_ = type;
- }
-
- // Returns the effective connection type that was set using
- // |set_effective_connection_type|. If connection type has not been set, then
- // the base implementation is called.
- EffectiveConnectionType GetEffectiveConnectionType() const override {
- if (effective_connection_type_set_)
- return effective_connection_type_;
- return NetworkQualityEstimator::GetEffectiveConnectionType();
- }
-
- void set_recent_effective_connection_type(EffectiveConnectionType type) {
- recent_effective_connection_type_set_ = true;
- recent_effective_connection_type_ = type;
- }
-
- // Returns the effective connection type that was set using
- // |set_effective_connection_type|. If connection type has not been set, then
- // the base implementation is called.
- EffectiveConnectionType GetRecentEffectiveConnectionType(
- const base::TimeTicks& start_time) const override {
- if (recent_effective_connection_type_set_)
- return recent_effective_connection_type_;
- return NetworkQualityEstimator::GetRecentEffectiveConnectionType(
- start_time);
- }
-
- void set_http_rtt(const base::TimeDelta& http_rtt) {
- http_rtt_set_ = true;
- http_rtt_ = http_rtt;
- }
-
- // Returns the HTTP RTT that was set using |set_http_rtt|. If the HTTP RTT has
- // not been set, then the base implementation is called.
- bool GetHttpRTTEstimate(base::TimeDelta* rtt) const override {
- if (http_rtt_set_) {
- *rtt = http_rtt_;
- return true;
- }
- return NetworkQualityEstimator::GetHttpRTTEstimate(rtt);
- }
-
- void set_recent_http_rtt(const base::TimeDelta& recent_http_rtt) {
- recent_http_rtt_set_ = true;
- recent_http_rtt_ = recent_http_rtt;
- }
-
- // Returns the recent HTTP RTT that was set using |set_recent_http_rtt|. If
- // the recent HTTP RTT has not been set, then the base implementation is
- // called.
- bool GetRecentHttpRTTMedian(const base::TimeTicks& start_time,
- base::TimeDelta* rtt) const override {
- if (recent_http_rtt_set_) {
- *rtt = recent_http_rtt_;
- return true;
- }
- return NetworkQualityEstimator::GetRecentHttpRTTMedian(start_time, rtt);
- }
-
- void set_transport_rtt(const base::TimeDelta& transport_rtt) {
- transport_rtt_set_ = true;
- transport_rtt_ = transport_rtt;
- }
-
- // Returns the transport RTT that was set using |set_transport_rtt|. If the
- // transport RTT has not been set, then the base implementation is called.
- bool GetTransportRTTEstimate(base::TimeDelta* rtt) const override {
- if (transport_rtt_set_) {
- *rtt = transport_rtt_;
- return true;
- }
- return NetworkQualityEstimator::GetTransportRTTEstimate(rtt);
- }
-
- void set_recent_transport_rtt(const base::TimeDelta& recent_transport_rtt) {
- recent_transport_rtt_set_ = true;
- recent_transport_rtt_ = recent_transport_rtt;
- }
-
- // Returns the recent transport RTT that was set using
- // |set_recent_transport_rtt|. If the recent transport RTT has not been set,
- // then the base implementation is called.
- bool GetRecentTransportRTTMedian(const base::TimeTicks& start_time,
- base::TimeDelta* rtt) const override {
- if (recent_transport_rtt_set_) {
- *rtt = recent_transport_rtt_;
- return true;
- }
- return NetworkQualityEstimator::GetRecentTransportRTTMedian(start_time,
- rtt);
- }
-
- void set_downlink_throughput_kbps(int32_t downlink_throughput_kbps) {
- downlink_throughput_kbps_set_ = true;
- downlink_throughput_kbps_ = downlink_throughput_kbps;
- }
-
- // Returns the downlink throughput that was set using
- // |set_downlink_throughput_kbps|. If the downlink throughput has not been
- // set, then the base implementation is called.
- bool GetDownlinkThroughputKbpsEstimate(int32_t* kbps) const override {
- if (downlink_throughput_kbps_set_) {
- *kbps = downlink_throughput_kbps_;
- return true;
- }
- return NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimate(kbps);
- }
-
- void set_recent_downlink_throughput_kbps(
- int32_t recent_downlink_throughput_kbps) {
- recent_downlink_throughput_kbps_set_ = true;
- recent_downlink_throughput_kbps_ = recent_downlink_throughput_kbps;
- }
-
- // Returns the downlink throughput that was set using
- // |set_recent_downlink_throughput_kbps|. If the downlink throughput has not
- // been set, then the base implementation is called.
- bool GetRecentMedianDownlinkThroughputKbps(const base::TimeTicks& start_time,
- int32_t* kbps) const override {
- if (recent_downlink_throughput_kbps_set_) {
- *kbps = recent_downlink_throughput_kbps_;
- return true;
- }
- return NetworkQualityEstimator::GetRecentMedianDownlinkThroughputKbps(
- start_time, kbps);
- }
-
- void SetAccuracyRecordingIntervals(
- const std::vector<base::TimeDelta>& accuracy_recording_intervals) {
- accuracy_recording_intervals_set_ = true;
- accuracy_recording_intervals_ = accuracy_recording_intervals;
- }
-
- const std::vector<base::TimeDelta>& GetAccuracyRecordingIntervals()
- const override {
- if (accuracy_recording_intervals_set_)
- return accuracy_recording_intervals_;
-
- return NetworkQualityEstimator::GetAccuracyRecordingIntervals();
- }
-
- using NetworkQualityEstimator::SetTickClockForTesting;
- using NetworkQualityEstimator::ReadCachedNetworkQualityEstimate;
- using NetworkQualityEstimator::OnConnectionTypeChanged;
-
- private:
- // NetworkQualityEstimator implementation that returns the overridden
- // network
- // id (instead of invoking platform APIs).
- NetworkQualityEstimator::NetworkID GetCurrentNetworkID() const override {
- return NetworkQualityEstimator::NetworkID(current_network_type_,
- current_network_id_);
- }
-
- bool effective_connection_type_set_;
- EffectiveConnectionType effective_connection_type_;
-
- bool recent_effective_connection_type_set_;
- EffectiveConnectionType recent_effective_connection_type_;
-
- NetworkChangeNotifier::ConnectionType current_network_type_;
- std::string current_network_id_;
-
- bool accuracy_recording_intervals_set_;
- std::vector<base::TimeDelta> accuracy_recording_intervals_;
-
- bool http_rtt_set_;
- base::TimeDelta http_rtt_;
-
- bool recent_http_rtt_set_;
- base::TimeDelta recent_http_rtt_;
-
- bool transport_rtt_set_;
- base::TimeDelta transport_rtt_;
-
- bool recent_transport_rtt_set_;
- base::TimeDelta recent_transport_rtt_;
-
- bool downlink_throughput_kbps_set_;
- int32_t downlink_throughput_kbps_;
-
- bool recent_downlink_throughput_kbps_set_;
- int32_t recent_downlink_throughput_kbps_;
-
- // Embedded server used for testing.
- EmbeddedTestServer embedded_test_server_;
-
- DISALLOW_COPY_AND_ASSIGN(TestNetworkQualityEstimator);
-};
-
class TestEffectiveConnectionTypeObserver
: public NetworkQualityEstimator::EffectiveConnectionTypeObserver {
public:
- std::vector<NetworkQualityEstimator::EffectiveConnectionType>&
- effective_connection_types() {
+ std::vector<EffectiveConnectionType>& effective_connection_types() {
return effective_connection_types_;
}
// EffectiveConnectionTypeObserver implementation:
- void OnEffectiveConnectionTypeChanged(
- NetworkQualityEstimator::EffectiveConnectionType type) override {
+ void OnEffectiveConnectionTypeChanged(EffectiveConnectionType type) override {
effective_connection_types_.push_back(type);
}
private:
- std::vector<NetworkQualityEstimator::EffectiveConnectionType>
- effective_connection_types_;
+ std::vector<EffectiveConnectionType> effective_connection_types_;
};
class TestRTTObserver : public NetworkQualityEstimator::RTTObserver {
@@ -391,10 +120,15 @@ TEST(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) {
std::map<std::string, std::string> variation_params;
TestNetworkQualityEstimator estimator(variation_params);
+ estimator.SimulateNetworkChange(
+ NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test");
+ histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable",
+ false, 1);
+
base::TimeDelta rtt;
int32_t kbps;
- EXPECT_FALSE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_FALSE(estimator.GetHttpRTT(&rtt));
+ EXPECT_FALSE(estimator.GetDownlinkThroughputKbps(&kbps));
TestDelegate test_delegate;
TestURLRequestContext context(true);
@@ -403,34 +137,34 @@ TEST(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) {
std::unique_ptr<URLRequest> request(context.CreateRequest(
estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
- request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME);
+ request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
request->Start();
base::RunLoop().Run();
// Both RTT and downstream throughput should be updated.
- EXPECT_TRUE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
- EXPECT_FALSE(estimator.GetTransportRTTEstimate(&rtt));
+ EXPECT_TRUE(estimator.GetHttpRTT(&rtt));
+ EXPECT_TRUE(estimator.GetDownlinkThroughputKbps(&kbps));
+ EXPECT_FALSE(estimator.GetTransportRTT(&rtt));
// Check UMA histograms.
histogram_tester.ExpectTotalCount("NQE.PeakKbps.Unknown", 0);
histogram_tester.ExpectTotalCount("NQE.FastestRTT.Unknown", 0);
histogram_tester.ExpectUniqueSample(
"NQE.MainFrame.EffectiveConnectionType.Unknown",
- NetworkQualityEstimator::EffectiveConnectionType::
- EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
- 1);
+ EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_UNKNOWN, 1);
std::unique_ptr<URLRequest> request2(context.CreateRequest(
estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
- request2->SetLoadFlags(request2->load_flags() | LOAD_MAIN_FRAME);
+ request2->SetLoadFlags(request2->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
request2->Start();
base::RunLoop().Run();
histogram_tester.ExpectTotalCount(
"NQE.MainFrame.EffectiveConnectionType.Unknown", 2);
- estimator.SimulateNetworkChangeTo(
+ estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1");
+ histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable",
+ false, 2);
histogram_tester.ExpectTotalCount("NQE.PeakKbps.Unknown", 1);
histogram_tester.ExpectTotalCount("NQE.FastestRTT.Unknown", 1);
@@ -444,8 +178,8 @@ TEST(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) {
histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile50.Unknown", 0);
- EXPECT_FALSE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_FALSE(estimator.GetHttpRTT(&rtt));
+ EXPECT_FALSE(estimator.GetDownlinkThroughputKbps(&kbps));
// Verify that metrics are logged correctly on main-frame requests.
histogram_tester.ExpectTotalCount("NQE.MainFrame.RTT.Percentile50.Unknown",
@@ -455,24 +189,98 @@ TEST(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) {
histogram_tester.ExpectTotalCount("NQE.MainFrame.Kbps.Percentile50.Unknown",
1);
- estimator.SimulateNetworkChangeTo(
+ estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, std::string());
+ histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable",
+ false, 3);
histogram_tester.ExpectTotalCount("NQE.PeakKbps.Unknown", 1);
histogram_tester.ExpectTotalCount("NQE.FastestRTT.Unknown", 1);
- EXPECT_FALSE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_FALSE(estimator.GetHttpRTT(&rtt));
+ EXPECT_FALSE(estimator.GetDownlinkThroughputKbps(&kbps));
std::unique_ptr<URLRequest> request3(context.CreateRequest(
estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
- request3->SetLoadFlags(request2->load_flags() | LOAD_MAIN_FRAME);
+ request3->SetLoadFlags(request2->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
request3->Start();
base::RunLoop().Run();
histogram_tester.ExpectUniqueSample(
"NQE.MainFrame.EffectiveConnectionType.WiFi",
- NetworkQualityEstimator::EffectiveConnectionType::
- EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
- 1);
+ EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_UNKNOWN, 1);
+
+ estimator.SimulateNetworkChange(
+ NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test");
+ histogram_tester.ExpectBucketCount("NQE.CachedNetworkQualityAvailable", false,
+ 3);
+ histogram_tester.ExpectBucketCount("NQE.CachedNetworkQualityAvailable", true,
+ 1);
+}
+
+// Tests that the network quality estimator writes and reads network quality
+// from the cache store correctly.
+TEST(NetworkQualityEstimatorTest, Caching) {
+ base::HistogramTester histogram_tester;
+ std::map<std::string, std::string> variation_params;
+ TestNetworkQualityEstimator estimator(variation_params);
+
+ estimator.SimulateNetworkChange(
+ NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test");
+ histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable",
+ false, 1);
+
+ base::TimeDelta rtt;
+ int32_t kbps;
+ EXPECT_FALSE(estimator.GetHttpRTT(&rtt));
+ EXPECT_FALSE(estimator.GetDownlinkThroughputKbps(&kbps));
+
+ TestDelegate test_delegate;
+ TestURLRequestContext context(true);
+ context.set_network_quality_estimator(&estimator);
+ context.Init();
+
+ // Start two requests so that the network quality is added to cache store at
+ // the beginning of the second request from the network traffic observed from
+ // the first request.
+ for (size_t i = 0; i < 2; ++i) {
+ std::unique_ptr<URLRequest> request(context.CreateRequest(
+ estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
+ request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
+ request->Start();
+ base::RunLoop().Run();
+ }
+
+ base::RunLoop().RunUntilIdle();
+
+ // Both RTT and downstream throughput should be updated.
+ EXPECT_TRUE(estimator.GetHttpRTT(&rtt));
+ EXPECT_TRUE(estimator.GetDownlinkThroughputKbps(&kbps));
+ EXPECT_NE(EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+ estimator.GetEffectiveConnectionType());
+ EXPECT_FALSE(estimator.GetTransportRTT(&rtt));
+
+ histogram_tester.ExpectBucketCount("NQE.CachedNetworkQualityAvailable", false,
+ 1);
+
+ // Add the observers before changing the network type.
+ TestEffectiveConnectionTypeObserver observer;
+ estimator.AddEffectiveConnectionTypeObserver(&observer);
+ TestRTTObserver rtt_observer;
+ estimator.AddRTTObserver(&rtt_observer);
+ TestThroughputObserver throughput_observer;
+ estimator.AddThroughputObserver(&throughput_observer);
+
+ estimator.SimulateNetworkChange(
+ NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test");
+ histogram_tester.ExpectBucketCount("NQE.CachedNetworkQualityAvailable", true,
+ 1);
+ histogram_tester.ExpectTotalCount("NQE.CachedNetworkQualityAvailable", 2);
+ base::RunLoop().RunUntilIdle();
+
+ // Verify that the cached network quality was read, and observers were
+ // notified.
+ EXPECT_EQ(1U, observer.effective_connection_types().size());
+ EXPECT_EQ(1U, rtt_observer.observations().size());
+ EXPECT_EQ(1U, throughput_observer.observations().size());
}
TEST(NetworkQualityEstimatorTest, StoreObservations) {
@@ -481,8 +289,8 @@ TEST(NetworkQualityEstimatorTest, StoreObservations) {
base::TimeDelta rtt;
int32_t kbps;
- EXPECT_FALSE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_FALSE(estimator.GetHttpRTT(&rtt));
+ EXPECT_FALSE(estimator.GetDownlinkThroughputKbps(&kbps));
TestDelegate test_delegate;
TestURLRequestContext context(true);
@@ -496,15 +304,15 @@ TEST(NetworkQualityEstimatorTest, StoreObservations) {
estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
request->Start();
base::RunLoop().Run();
- EXPECT_TRUE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_TRUE(estimator.GetHttpRTT(&rtt));
+ EXPECT_TRUE(estimator.GetDownlinkThroughputKbps(&kbps));
}
// Verify that the stored observations are cleared on network change.
- estimator.SimulateNetworkChangeTo(
+ estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-2");
- EXPECT_FALSE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_FALSE(estimator.GetHttpRTT(&rtt));
+ EXPECT_FALSE(estimator.GetDownlinkThroughputKbps(&kbps));
}
// This test notifies NetworkQualityEstimator of received data. Next,
@@ -579,24 +387,24 @@ TEST(NetworkQualityEstimatorTest, ObtainOperatingParams) {
TestNetworkQualityEstimator estimator(variation_params);
base::TimeDelta rtt;
- EXPECT_TRUE(estimator.GetHttpRTTEstimate(&rtt));
+ EXPECT_TRUE(estimator.GetHttpRTT(&rtt));
int32_t kbps;
- EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_TRUE(estimator.GetDownlinkThroughputKbps(&kbps));
EXPECT_EQ(100, kbps);
EXPECT_EQ(base::TimeDelta::FromMilliseconds(1000), rtt);
- EXPECT_FALSE(estimator.GetTransportRTTEstimate(&rtt));
+ EXPECT_FALSE(estimator.GetTransportRTT(&rtt));
// Simulate network change to Wi-Fi.
- estimator.SimulateNetworkChangeTo(
+ estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1");
- EXPECT_TRUE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_TRUE(estimator.GetHttpRTT(&rtt));
+ EXPECT_TRUE(estimator.GetDownlinkThroughputKbps(&kbps));
EXPECT_EQ(200, kbps);
EXPECT_EQ(base::TimeDelta::FromMilliseconds(2000), rtt);
- EXPECT_FALSE(estimator.GetTransportRTTEstimate(&rtt));
+ EXPECT_FALSE(estimator.GetTransportRTT(&rtt));
// Peak network quality should not be affected by the network quality
// estimator field trial.
@@ -607,19 +415,19 @@ TEST(NetworkQualityEstimatorTest, ObtainOperatingParams) {
// Simulate network change to 2G. Only the Kbps default estimate should be
// available.
- estimator.SimulateNetworkChangeTo(
+ estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-2");
- EXPECT_FALSE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_FALSE(estimator.GetHttpRTT(&rtt));
+ EXPECT_TRUE(estimator.GetDownlinkThroughputKbps(&kbps));
EXPECT_EQ(300, kbps);
// Simulate network change to 3G. Default estimates should be unavailable.
- estimator.SimulateNetworkChangeTo(
+ estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-3");
- EXPECT_FALSE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_FALSE(estimator.GetHttpRTT(&rtt));
+ EXPECT_FALSE(estimator.GetDownlinkThroughputKbps(&kbps));
}
TEST(NetworkQualityEstimatorTest, ObtainAlgorithmToUseFromParams) {
@@ -636,6 +444,9 @@ TEST(NetworkQualityEstimatorTest, ObtainAlgorithmToUseFromParams) {
{true, "HttpRTTAndDownstreamThroughput",
NetworkQualityEstimator::EffectiveConnectionTypeAlgorithm::
HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT},
+ {true, "TransportRTTOrDownstreamThroughput",
+ NetworkQualityEstimator::EffectiveConnectionTypeAlgorithm::
+ TRANSPORT_RTT_OR_DOWNSTREAM_THROUGHOUT},
};
for (const auto& test : tests) {
@@ -647,27 +458,84 @@ TEST(NetworkQualityEstimatorTest, ObtainAlgorithmToUseFromParams) {
EXPECT_EQ(test.expected_algorithm,
estimator.effective_connection_type_algorithm_)
<< test.algorithm;
+
+ // Make sure no two values are same in the map.
+ typedef std::map<std::string,
+ NetworkQualityEstimator::EffectiveConnectionTypeAlgorithm>
+ Algorithms;
+
+ for (Algorithms::const_iterator it_first =
+ estimator.algorithm_name_to_enum_.begin();
+ it_first != estimator.algorithm_name_to_enum_.end(); ++it_first) {
+ for (Algorithms::const_iterator it_second =
+ estimator.algorithm_name_to_enum_.begin();
+ it_second != estimator.algorithm_name_to_enum_.end(); ++it_second) {
+ if (it_first != it_second) {
+ DCHECK_NE(it_first->second, it_second->second);
+ }
+ }
+ }
+ }
+}
+
+// Tests that |GetEffectiveConnectionType| returns
+// EFFECTIVE_CONNECTION_TYPE_OFFLINE when the device is currently offline.
+TEST(NetworkQualityEstimatorTest, Offline) {
+ std::map<std::string, std::string> variation_params;
+ TestNetworkQualityEstimator estimator(variation_params);
+
+ const struct {
+ NetworkChangeNotifier::ConnectionType connection_type;
+ EffectiveConnectionType expected_connection_type;
+ } tests[] = {
+ {NetworkChangeNotifier::CONNECTION_2G, EFFECTIVE_CONNECTION_TYPE_UNKNOWN},
+ {NetworkChangeNotifier::CONNECTION_NONE,
+ EFFECTIVE_CONNECTION_TYPE_OFFLINE},
+ {NetworkChangeNotifier::CONNECTION_3G, EFFECTIVE_CONNECTION_TYPE_UNKNOWN},
+ };
+
+ for (const auto& test : tests) {
+ estimator.SimulateNetworkChange(test.connection_type, "test");
+ EXPECT_EQ(test.expected_connection_type,
+ estimator.GetEffectiveConnectionType());
}
}
// Tests that |GetEffectiveConnectionType| returns correct connection type when
-// no variation params are specified.
-TEST(NetworkQualityEstimatorTest, ObtainThresholdsNone) {
+// only RTT thresholds are specified in the variation params.
+TEST(NetworkQualityEstimatorTest, ObtainThresholdsOnlyRTT) {
std::map<std::string, std::string> variation_params;
+ variation_params["Offline.ThresholdMedianHttpRTTMsec"] = "4000";
+ variation_params["Slow2G.ThresholdMedianHttpRTTMsec"] = "2000";
+ variation_params["2G.ThresholdMedianHttpRTTMsec"] = "1000";
+ variation_params["3G.ThresholdMedianHttpRTTMsec"] = "500";
+ variation_params["4G.ThresholdMedianHttpRTTMsec"] = "300";
+
TestNetworkQualityEstimator estimator(variation_params);
// Simulate the connection type as Wi-Fi so that GetEffectiveConnectionType
// does not return Offline if the device is offline.
- estimator.SimulateNetworkChangeTo(NetworkChangeNotifier::CONNECTION_WIFI,
- "test");
+ estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI,
+ "test");
const struct {
int32_t rtt_msec;
- NetworkQualityEstimator::EffectiveConnectionType expected_conn_type;
+ EffectiveConnectionType expected_conn_type;
} tests[] = {
- {5000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND},
- {20, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND},
+ {5000, EFFECTIVE_CONNECTION_TYPE_OFFLINE},
+ {4000, EFFECTIVE_CONNECTION_TYPE_OFFLINE},
+ {3000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {2000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {1500, EFFECTIVE_CONNECTION_TYPE_2G},
+ {1000, EFFECTIVE_CONNECTION_TYPE_2G},
+ {700, EFFECTIVE_CONNECTION_TYPE_3G},
+ {500, EFFECTIVE_CONNECTION_TYPE_3G},
+ {400, EFFECTIVE_CONNECTION_TYPE_4G},
+ {300, EFFECTIVE_CONNECTION_TYPE_4G},
+ {200, EFFECTIVE_CONNECTION_TYPE_4G},
+ {100, EFFECTIVE_CONNECTION_TYPE_4G},
+ {20, EFFECTIVE_CONNECTION_TYPE_4G},
};
for (const auto& test : tests) {
@@ -676,86 +544,184 @@ TEST(NetworkQualityEstimatorTest, ObtainThresholdsNone) {
base::TimeDelta::FromMilliseconds(test.rtt_msec));
estimator.set_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());
}
}
-// Tests that |GetEffectiveConnectionType| returns
-// EFFECTIVE_CONNECTION_TYPE_OFFLINE when the device is currently offline.
-TEST(NetworkQualityEstimatorTest, Offline) {
- std::map<std::string, std::string> variation_params;
- TestNetworkQualityEstimator estimator(variation_params);
+// Tests that default transport RTT thresholds for different effective
+// connection types are correctly set.
+TEST(NetworkQualityEstimatorTest, DefaultTransportRTTBasedThresholds) {
+ const struct {
+ bool override_defaults_using_variation_params;
+ int32_t transport_rtt_msec;
+ EffectiveConnectionType expected_conn_type;
+ } tests[] = {
+ // When the variation params do not override connection thresholds,
+ // default values should be used.
+ {false, 5000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {false, 4000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {false, 3000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {false, 2000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {false, 1500, EFFECTIVE_CONNECTION_TYPE_2G},
+ {false, 1000, EFFECTIVE_CONNECTION_TYPE_3G},
+ {false, 100, EFFECTIVE_CONNECTION_TYPE_4G},
+ {false, 20, EFFECTIVE_CONNECTION_TYPE_4G},
+ // Override default thresholds using variation params.
+ {true, 5000, EFFECTIVE_CONNECTION_TYPE_OFFLINE},
+ {true, 4000, EFFECTIVE_CONNECTION_TYPE_OFFLINE},
+ {true, 3000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {true, 2000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {true, 1500, EFFECTIVE_CONNECTION_TYPE_2G},
+ {true, 1000, EFFECTIVE_CONNECTION_TYPE_2G},
+ {true, 20, EFFECTIVE_CONNECTION_TYPE_4G},
+ };
+
+ for (const auto& test : tests) {
+ std::map<std::string, std::string> variation_params;
+ variation_params["effective_connection_type_algorithm"] =
+ "TransportRTTOrDownstreamThroughput";
+ if (test.override_defaults_using_variation_params) {
+ variation_params["Offline.ThresholdMedianTransportRTTMsec"] = "4000";
+ variation_params["Slow2G.ThresholdMedianTransportRTTMsec"] = "2000";
+ variation_params["2G.ThresholdMedianTransportRTTMsec"] = "1000";
+ }
+ TestNetworkQualityEstimator estimator(variation_params);
+
+ // Simulate the connection type as Wi-Fi so that GetEffectiveConnectionType
+ // does not return Offline if the device is offline.
+ estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI,
+ "test");
+
+ estimator.set_transport_rtt(
+ base::TimeDelta::FromMilliseconds(test.transport_rtt_msec));
+ estimator.set_recent_transport_rtt(
+ base::TimeDelta::FromMilliseconds(test.transport_rtt_msec));
+ estimator.set_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());
+ }
+}
+
+// Tests that default HTTP RTT thresholds for different effective
+// connection types are correctly set.
+TEST(NetworkQualityEstimatorTest, DefaultHttpRTTBasedThresholds) {
const struct {
- NetworkChangeNotifier::ConnectionType connection_type;
- NetworkQualityEstimator::EffectiveConnectionType expected_connection_type;
+ bool override_defaults_using_variation_params;
+ int32_t http_rtt_msec;
+ EffectiveConnectionType expected_conn_type;
} tests[] = {
- {NetworkChangeNotifier::CONNECTION_2G,
- NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_UNKNOWN},
- {NetworkChangeNotifier::CONNECTION_NONE,
- NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_OFFLINE},
- {NetworkChangeNotifier::CONNECTION_3G,
- NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_UNKNOWN},
+ // When the variation params do not override connection thresholds,
+ // default values should be used.
+ {false, 5000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {false, 4000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {false, 3000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {false, 2000, EFFECTIVE_CONNECTION_TYPE_2G},
+ {false, 1500, EFFECTIVE_CONNECTION_TYPE_2G},
+ {false, 1000, EFFECTIVE_CONNECTION_TYPE_3G},
+ {false, 100, EFFECTIVE_CONNECTION_TYPE_4G},
+ {false, 20, EFFECTIVE_CONNECTION_TYPE_4G},
+ // Override default thresholds using variation params.
+ {true, 5000, EFFECTIVE_CONNECTION_TYPE_OFFLINE},
+ {true, 4000, EFFECTIVE_CONNECTION_TYPE_OFFLINE},
+ {true, 3000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {true, 2000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {true, 1500, EFFECTIVE_CONNECTION_TYPE_2G},
+ {true, 1000, EFFECTIVE_CONNECTION_TYPE_2G},
+ {true, 20, EFFECTIVE_CONNECTION_TYPE_4G},
};
for (const auto& test : tests) {
- estimator.SimulateNetworkChangeTo(test.connection_type, "test");
- EXPECT_EQ(test.expected_connection_type,
- estimator.GetEffectiveConnectionType());
+ std::map<std::string, std::string> variation_params;
+ if (test.override_defaults_using_variation_params) {
+ variation_params["Offline.ThresholdMedianHttpRTTMsec"] = "4000";
+ variation_params["Slow2G.ThresholdMedianHttpRTTMsec"] = "2000";
+ variation_params["2G.ThresholdMedianHttpRTTMsec"] = "1000";
+ }
+
+ TestNetworkQualityEstimator estimator(variation_params);
+
+ // Simulate the connection type as Wi-Fi so that GetEffectiveConnectionType
+ // does not return Offline if the device is offline.
+ estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI,
+ "test");
+
+ estimator.set_http_rtt(
+ base::TimeDelta::FromMilliseconds(test.http_rtt_msec));
+ estimator.set_recent_http_rtt(
+ base::TimeDelta::FromMilliseconds(test.http_rtt_msec));
+ estimator.set_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());
}
}
// Tests that |GetEffectiveConnectionType| returns correct connection type when
-// only RTT thresholds are specified in the variation params.
-TEST(NetworkQualityEstimatorTest, ObtainThresholdsOnlyRTT) {
+// only transport RTT thresholds are specified in the variation params.
+TEST(NetworkQualityEstimatorTest, ObtainThresholdsOnlyTransportRTT) {
std::map<std::string, std::string> variation_params;
+ variation_params["effective_connection_type_algorithm"] =
+ "TransportRTTOrDownstreamThroughput";
- variation_params["Offline.ThresholdMedianHttpRTTMsec"] = "4000";
- variation_params["Slow2G.ThresholdMedianHttpRTTMsec"] = "2000";
- variation_params["2G.ThresholdMedianHttpRTTMsec"] = "1000";
- variation_params["3G.ThresholdMedianHttpRTTMsec"] = "500";
- variation_params["4G.ThresholdMedianHttpRTTMsec"] = "300";
- variation_params["Broadband.ThresholdMedianHttpRTTMsec"] = "100";
+ variation_params["Offline.ThresholdMedianTransportRTTMsec"] = "4000";
+ variation_params["Slow2G.ThresholdMedianTransportRTTMsec"] = "2000";
+ variation_params["2G.ThresholdMedianTransportRTTMsec"] = "1000";
+ variation_params["3G.ThresholdMedianTransportRTTMsec"] = "500";
+ variation_params["4G.ThresholdMedianTransportRTTMsec"] = "300";
TestNetworkQualityEstimator estimator(variation_params);
// Simulate the connection type as Wi-Fi so that GetEffectiveConnectionType
// does not return Offline if the device is offline.
- estimator.SimulateNetworkChangeTo(NetworkChangeNotifier::CONNECTION_WIFI,
- "test");
+ estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI,
+ "test");
const struct {
- int32_t rtt_msec;
- NetworkQualityEstimator::EffectiveConnectionType expected_conn_type;
+ int32_t transport_rtt_msec;
+ EffectiveConnectionType expected_conn_type;
} tests[] = {
- {5000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_OFFLINE},
- {4000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_OFFLINE},
- {3000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
- {2000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
- {1500, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G},
- {1000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G},
- {700, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_3G},
- {500, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_3G},
- {400, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_4G},
- {300, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_4G},
- {200, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND},
- {100, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND},
- {20, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND},
+ {5000, EFFECTIVE_CONNECTION_TYPE_OFFLINE},
+ {4000, EFFECTIVE_CONNECTION_TYPE_OFFLINE},
+ {3000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {2000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {1500, EFFECTIVE_CONNECTION_TYPE_2G},
+ {1000, EFFECTIVE_CONNECTION_TYPE_2G},
+ {700, EFFECTIVE_CONNECTION_TYPE_3G},
+ {500, EFFECTIVE_CONNECTION_TYPE_3G},
+ {400, EFFECTIVE_CONNECTION_TYPE_4G},
+ {300, EFFECTIVE_CONNECTION_TYPE_4G},
+ {200, EFFECTIVE_CONNECTION_TYPE_4G},
+ {100, EFFECTIVE_CONNECTION_TYPE_4G},
+ {20, EFFECTIVE_CONNECTION_TYPE_4G},
};
for (const auto& test : tests) {
- estimator.set_http_rtt(base::TimeDelta::FromMilliseconds(test.rtt_msec));
- estimator.set_recent_http_rtt(
- base::TimeDelta::FromMilliseconds(test.rtt_msec));
+ estimator.set_transport_rtt(
+ base::TimeDelta::FromMilliseconds(test.transport_rtt_msec));
+ estimator.set_recent_transport_rtt(
+ base::TimeDelta::FromMilliseconds(test.transport_rtt_msec));
estimator.set_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());
}
}
// Tests that |GetEffectiveConnectionType| returns correct connection type when
-// both RTT and throughput thresholds are specified in the variation params.
-TEST(NetworkQualityEstimatorTest, ObtainThresholdsRTTandThroughput) {
+// both HTTP RTT and throughput thresholds are specified in the variation
+// params.
+TEST(NetworkQualityEstimatorTest, ObtainThresholdsHttpRTTandThroughput) {
std::map<std::string, std::string> variation_params;
variation_params["Offline.ThresholdMedianHttpRTTMsec"] = "4000";
@@ -763,44 +729,42 @@ TEST(NetworkQualityEstimatorTest, ObtainThresholdsRTTandThroughput) {
variation_params["2G.ThresholdMedianHttpRTTMsec"] = "1000";
variation_params["3G.ThresholdMedianHttpRTTMsec"] = "500";
variation_params["4G.ThresholdMedianHttpRTTMsec"] = "300";
- variation_params["Broadband.ThresholdMedianHttpRTTMsec"] = "100";
variation_params["Offline.ThresholdMedianKbps"] = "10";
variation_params["Slow2G.ThresholdMedianKbps"] = "100";
variation_params["2G.ThresholdMedianKbps"] = "300";
variation_params["3G.ThresholdMedianKbps"] = "500";
variation_params["4G.ThresholdMedianKbps"] = "1000";
- variation_params["Broadband.ThresholdMedianKbps"] = "2000";
TestNetworkQualityEstimator estimator(variation_params);
// Simulate the connection type as Wi-Fi so that GetEffectiveConnectionType
// does not return Offline if the device is offline.
- estimator.SimulateNetworkChangeTo(NetworkChangeNotifier::CONNECTION_WIFI,
- "test");
+ estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI,
+ "test");
const struct {
int32_t rtt_msec;
int32_t downlink_throughput_kbps;
- NetworkQualityEstimator::EffectiveConnectionType expected_conn_type;
+ EffectiveConnectionType expected_conn_type;
} tests[] = {
// Set RTT to a very low value to observe the effect of throughput.
// Throughput is the bottleneck.
- {1, 5, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_OFFLINE},
- {1, 10, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_OFFLINE},
- {1, 50, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
- {1, 100, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
- {1, 150, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G},
- {1, 300, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G},
- {1, 400, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_3G},
- {1, 500, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_3G},
- {1, 700, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_4G},
- {1, 1000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_4G},
- {1, 1500, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND},
- {1, 2500, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND},
+ {1, 5, EFFECTIVE_CONNECTION_TYPE_OFFLINE},
+ {1, 10, EFFECTIVE_CONNECTION_TYPE_OFFLINE},
+ {1, 50, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {1, 100, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {1, 150, EFFECTIVE_CONNECTION_TYPE_2G},
+ {1, 300, EFFECTIVE_CONNECTION_TYPE_2G},
+ {1, 400, EFFECTIVE_CONNECTION_TYPE_3G},
+ {1, 500, EFFECTIVE_CONNECTION_TYPE_3G},
+ {1, 700, EFFECTIVE_CONNECTION_TYPE_4G},
+ {1, 1000, EFFECTIVE_CONNECTION_TYPE_4G},
+ {1, 1500, EFFECTIVE_CONNECTION_TYPE_4G},
+ {1, 2500, EFFECTIVE_CONNECTION_TYPE_4G},
// Set both RTT and throughput. RTT is the bottleneck.
- {3000, 25000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
- {700, 25000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_3G},
+ {3000, 25000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {700, 25000, EFFECTIVE_CONNECTION_TYPE_3G},
};
for (const auto& test : tests) {
@@ -810,6 +774,75 @@ TEST(NetworkQualityEstimatorTest, ObtainThresholdsRTTandThroughput) {
estimator.set_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();
+ EXPECT_EQ(test.expected_conn_type, estimator.GetEffectiveConnectionType());
+ }
+}
+
+// Tests that |GetEffectiveConnectionType| returns correct connection type when
+// both transport RTT and throughput thresholds are specified in the variation
+// params.
+TEST(NetworkQualityEstimatorTest, ObtainThresholdsTransportRTTandThroughput) {
+ std::map<std::string, std::string> variation_params;
+ variation_params["effective_connection_type_algorithm"] =
+ "TransportRTTOrDownstreamThroughput";
+
+ variation_params["Offline.ThresholdMedianTransportRTTMsec"] = "4000";
+ variation_params["Slow2G.ThresholdMedianTransportRTTMsec"] = "2000";
+ variation_params["2G.ThresholdMedianTransportRTTMsec"] = "1000";
+ variation_params["3G.ThresholdMedianTransportRTTMsec"] = "500";
+ variation_params["4G.ThresholdMedianTransportRTTMsec"] = "300";
+
+ variation_params["Offline.ThresholdMedianKbps"] = "10";
+ variation_params["Slow2G.ThresholdMedianKbps"] = "100";
+ variation_params["2G.ThresholdMedianKbps"] = "300";
+ variation_params["3G.ThresholdMedianKbps"] = "500";
+ variation_params["4G.ThresholdMedianKbps"] = "1000";
+
+ TestNetworkQualityEstimator estimator(variation_params);
+
+ // Simulate the connection type as Wi-Fi so that GetEffectiveConnectionType
+ // does not return Offline if the device is offline.
+ estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI,
+ "test");
+
+ const struct {
+ int32_t transport_rtt_msec;
+ int32_t downlink_throughput_kbps;
+ EffectiveConnectionType expected_conn_type;
+ } tests[] = {
+ // Set RTT to a very low value to observe the effect of throughput.
+ // Throughput is the bottleneck.
+ {1, 5, EFFECTIVE_CONNECTION_TYPE_OFFLINE},
+ {1, 10, EFFECTIVE_CONNECTION_TYPE_OFFLINE},
+ {1, 50, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {1, 100, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {1, 150, EFFECTIVE_CONNECTION_TYPE_2G},
+ {1, 300, EFFECTIVE_CONNECTION_TYPE_2G},
+ {1, 400, EFFECTIVE_CONNECTION_TYPE_3G},
+ {1, 500, EFFECTIVE_CONNECTION_TYPE_3G},
+ {1, 700, EFFECTIVE_CONNECTION_TYPE_4G},
+ {1, 1000, EFFECTIVE_CONNECTION_TYPE_4G},
+ {1, 1500, EFFECTIVE_CONNECTION_TYPE_4G},
+ {1, 2500, EFFECTIVE_CONNECTION_TYPE_4G},
+ // Set both RTT and throughput. RTT is the bottleneck.
+ {3000, 25000, EFFECTIVE_CONNECTION_TYPE_SLOW_2G},
+ {700, 25000, EFFECTIVE_CONNECTION_TYPE_3G},
+ };
+
+ for (const auto& test : tests) {
+ estimator.set_transport_rtt(
+ base::TimeDelta::FromMilliseconds(test.transport_rtt_msec));
+ estimator.set_recent_transport_rtt(
+ base::TimeDelta::FromMilliseconds(test.transport_rtt_msec));
+ estimator.set_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();
EXPECT_EQ(test.expected_conn_type, estimator.GetEffectiveConnectionType());
}
}
@@ -842,176 +875,17 @@ TEST(NetworkQualityEstimatorTest, HalfLifeParam) {
}
}
-// Test if the network estimates are cached when network change notification
-// is invoked.
-TEST(NetworkQualityEstimatorTest, TestCaching) {
- std::map<std::string, std::string> variation_params;
- TestNetworkQualityEstimator estimator(variation_params);
- size_t expected_cache_size = 0;
- EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size());
-
- // Cache entry will not be added for (NONE, "").
- estimator.downstream_throughput_kbps_observations_.AddObservation(
- NetworkQualityEstimator::ThroughputObservation(
- 1, base::TimeTicks::Now(),
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- estimator.rtt_observations_.AddObservation(
- NetworkQualityEstimator::RttObservation(
- base::TimeDelta::FromMilliseconds(1000), base::TimeTicks::Now(),
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- estimator.SimulateNetworkChangeTo(
- NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-1");
- EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size());
-
- // Entry will be added for (2G, "test1").
- // Also, set the network quality for (2G, "test1") so that it is stored in
- // the cache.
- estimator.downstream_throughput_kbps_observations_.AddObservation(
- NetworkQualityEstimator::ThroughputObservation(
- 1, base::TimeTicks::Now(),
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- estimator.rtt_observations_.AddObservation(
- NetworkQualityEstimator::RttObservation(
- base::TimeDelta::FromMilliseconds(1000), base::TimeTicks::Now(),
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
-
- estimator.SimulateNetworkChangeTo(
- NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-1");
- ++expected_cache_size;
- EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size());
-
- // Entry will be added for (3G, "test1").
- // Also, set the network quality for (3G, "test1") so that it is stored in
- // the cache.
- estimator.downstream_throughput_kbps_observations_.AddObservation(
- NetworkQualityEstimator::ThroughputObservation(
- 2, base::TimeTicks::Now(),
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- estimator.rtt_observations_.AddObservation(
- NetworkQualityEstimator::RttObservation(
- base::TimeDelta::FromMilliseconds(500), base::TimeTicks::Now(),
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- estimator.SimulateNetworkChangeTo(
- NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-2");
- ++expected_cache_size;
- EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size());
-
- // Entry will not be added for (3G, "test2").
- estimator.SimulateNetworkChangeTo(
- NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-1");
- EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size());
-
- // Read the network quality for (2G, "test-1").
- EXPECT_TRUE(estimator.ReadCachedNetworkQualityEstimate());
-
- base::TimeDelta rtt;
- int32_t kbps;
- EXPECT_TRUE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
- EXPECT_EQ(1, kbps);
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(1000), rtt);
- EXPECT_FALSE(estimator.GetTransportRTTEstimate(&rtt));
-
- // No new entry should be added for (2G, "test-1") since it already exists
- // in the cache.
- estimator.SimulateNetworkChangeTo(
- NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-1");
- EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size());
-
- // Read the network quality for (3G, "test-1").
- EXPECT_TRUE(estimator.ReadCachedNetworkQualityEstimate());
- EXPECT_TRUE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
- EXPECT_EQ(2, kbps);
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(500), rtt);
- // No new entry should be added for (3G, "test1") since it already exists
- // in the cache.
- estimator.SimulateNetworkChangeTo(
- NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-2");
- EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size());
-
- // Reading quality of (3G, "test-2") should return false.
- EXPECT_FALSE(estimator.ReadCachedNetworkQualityEstimate());
-
- // Reading quality of (2G, "test-3") should return false.
- estimator.SimulateNetworkChangeTo(
- NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-3");
- EXPECT_FALSE(estimator.ReadCachedNetworkQualityEstimate());
-}
-
-// Tests if the cache size remains bounded. Also, ensure that the cache is
-// LRU.
-TEST(NetworkQualityEstimatorTest, TestLRUCacheMaximumSize) {
- std::map<std::string, std::string> variation_params;
- TestNetworkQualityEstimator estimator(variation_params);
- estimator.SimulateNetworkChangeTo(
- NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, std::string());
- EXPECT_EQ(0U, estimator.cached_network_qualities_.size());
-
- // Add 100 more networks than the maximum size of the cache.
- size_t network_count =
- NetworkQualityEstimator::kMaximumNetworkQualityCacheSize + 100;
-
- base::TimeTicks update_time_of_network_100;
- for (size_t i = 0; i < network_count; ++i) {
- estimator.downstream_throughput_kbps_observations_.AddObservation(
- NetworkQualityEstimator::ThroughputObservation(
- 2, base::TimeTicks::Now(),
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- estimator.rtt_observations_.AddObservation(
- NetworkQualityEstimator::RttObservation(
- base::TimeDelta::FromMilliseconds(500), base::TimeTicks::Now(),
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
-
- if (i == 100)
- update_time_of_network_100 = base::TimeTicks::Now();
-
- estimator.SimulateNetworkChangeTo(
- NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI,
- base::SizeTToString(i));
- if (i < NetworkQualityEstimator::kMaximumNetworkQualityCacheSize)
- EXPECT_EQ(i, estimator.cached_network_qualities_.size());
- EXPECT_LE(estimator.cached_network_qualities_.size(),
- static_cast<size_t>(
- NetworkQualityEstimator::kMaximumNetworkQualityCacheSize));
- }
- // One more call so that the last network is also written to cache.
- estimator.downstream_throughput_kbps_observations_.AddObservation(
- NetworkQualityEstimator::ThroughputObservation(
- 2, base::TimeTicks::Now(),
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- estimator.rtt_observations_.AddObservation(
- NetworkQualityEstimator::RttObservation(
- base::TimeDelta::FromMilliseconds(500), base::TimeTicks::Now(),
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- estimator.SimulateNetworkChangeTo(
- NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI,
- base::SizeTToString(network_count - 1));
- EXPECT_EQ(static_cast<size_t>(
- NetworkQualityEstimator::kMaximumNetworkQualityCacheSize),
- estimator.cached_network_qualities_.size());
-
- // Test that the cache is LRU by examining its contents. Networks in cache
- // must all be newer than the 100th network.
- for (NetworkQualityEstimator::CachedNetworkQualities::iterator it =
- estimator.cached_network_qualities_.begin();
- it != estimator.cached_network_qualities_.end(); ++it) {
- EXPECT_GE((it->second).last_update_time_, update_time_of_network_100);
- }
-}
-
TEST(NetworkQualityEstimatorTest, TestGetMetricsSince) {
std::map<std::string, std::string> variation_params;
- const base::TimeDelta rtt_threshold_4g =
+ const base::TimeDelta rtt_threshold_3g =
base::TimeDelta::FromMilliseconds(30);
- const base::TimeDelta rtt_threshold_broadband =
- base::TimeDelta::FromMilliseconds(1);
+ const base::TimeDelta rtt_threshold_4g = base::TimeDelta::FromMilliseconds(1);
+ variation_params["3G.ThresholdMedianHttpRTTMsec"] =
+ base::IntToString(rtt_threshold_3g.InMilliseconds());
variation_params["4G.ThresholdMedianHttpRTTMsec"] =
base::IntToString(rtt_threshold_4g.InMilliseconds());
- variation_params["Broadband.ThresholdMedianHttpRTTMsec"] =
- base::IntToString(rtt_threshold_broadband.InMilliseconds());
variation_params["HalfLifeSeconds"] = "300000";
TestNetworkQualityEstimator estimator(variation_params);
@@ -1019,15 +893,15 @@ TEST(NetworkQualityEstimatorTest, TestGetMetricsSince) {
base::TimeTicks old = now - base::TimeDelta::FromMilliseconds(1);
ASSERT_NE(old, now);
- estimator.SimulateNetworkChangeTo(
+ estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test");
const int32_t old_downlink_kbps = 1;
const base::TimeDelta old_url_rtt = base::TimeDelta::FromMilliseconds(1);
const base::TimeDelta old_tcp_rtt = base::TimeDelta::FromMilliseconds(10);
- DCHECK_LT(old_url_rtt, rtt_threshold_4g);
- DCHECK_LT(old_tcp_rtt, rtt_threshold_4g);
+ DCHECK_LT(old_url_rtt, rtt_threshold_3g);
+ DCHECK_LT(old_tcp_rtt, rtt_threshold_3g);
// First sample has very old timestamp.
for (size_t i = 0; i < 2; ++i) {
@@ -1050,10 +924,10 @@ TEST(NetworkQualityEstimatorTest, TestGetMetricsSince) {
DCHECK_NE(old_downlink_kbps, new_downlink_kbps);
DCHECK_NE(old_url_rtt, new_url_rtt);
DCHECK_NE(old_tcp_rtt, new_tcp_rtt);
+ DCHECK_GT(new_url_rtt, rtt_threshold_3g);
+ DCHECK_GT(new_tcp_rtt, rtt_threshold_3g);
DCHECK_GT(new_url_rtt, rtt_threshold_4g);
DCHECK_GT(new_tcp_rtt, rtt_threshold_4g);
- DCHECK_GT(new_url_rtt, rtt_threshold_broadband);
- DCHECK_GT(new_tcp_rtt, rtt_threshold_broadband);
estimator.downstream_throughput_kbps_observations_.AddObservation(
NetworkQualityEstimator::ThroughputObservation(
@@ -1072,32 +946,28 @@ TEST(NetworkQualityEstimatorTest, TestGetMetricsSince) {
base::TimeDelta expected_http_rtt;
base::TimeDelta expected_transport_rtt;
int32_t expected_downstream_throughput;
- NetworkQualityEstimator::EffectiveConnectionType
- expected_effective_connection_type;
+ EffectiveConnectionType expected_effective_connection_type;
} tests[] = {
{now + base::TimeDelta::FromSeconds(10), false,
base::TimeDelta::FromMilliseconds(0),
- base::TimeDelta::FromMilliseconds(0), 0,
- NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND},
+ base::TimeDelta::FromMilliseconds(0), 0, EFFECTIVE_CONNECTION_TYPE_4G},
{now, true, new_url_rtt, new_tcp_rtt, new_downlink_kbps,
- NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_4G},
+ EFFECTIVE_CONNECTION_TYPE_3G},
{old - base::TimeDelta::FromMicroseconds(500), true, old_url_rtt,
- old_tcp_rtt, old_downlink_kbps,
- NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND},
+ old_tcp_rtt, old_downlink_kbps, EFFECTIVE_CONNECTION_TYPE_4G},
};
for (const auto& test : tests) {
base::TimeDelta http_rtt;
base::TimeDelta transport_rtt;
int32_t downstream_throughput_kbps;
+ EXPECT_EQ(test.expect_network_quality_available,
+ estimator.GetRecentHttpRTT(test.start_timestamp, &http_rtt));
EXPECT_EQ(
test.expect_network_quality_available,
- estimator.GetRecentHttpRTTMedian(test.start_timestamp, &http_rtt));
+ estimator.GetRecentTransportRTT(test.start_timestamp, &transport_rtt));
EXPECT_EQ(test.expect_network_quality_available,
- estimator.GetRecentTransportRTTMedian(test.start_timestamp,
- &transport_rtt));
- EXPECT_EQ(test.expect_network_quality_available,
- estimator.GetRecentMedianDownlinkThroughputKbps(
+ estimator.GetRecentDownlinkThroughputKbps(
test.start_timestamp, &downstream_throughput_kbps));
if (test.expect_network_quality_available) {
@@ -1166,14 +1036,14 @@ TEST(NetworkQualityEstimatorTest, InvalidExternalEstimateProvider) {
TestNetworkQualityEstimator estimator(std::map<std::string, std::string>(),
std::move(external_estimate_provider));
- estimator.SimulateNetworkChangeTo(net::NetworkChangeNotifier::CONNECTION_WIFI,
- "test");
+ estimator.SimulateNetworkChange(net::NetworkChangeNotifier::CONNECTION_WIFI,
+ "test");
base::TimeDelta rtt;
int32_t kbps;
EXPECT_EQ(1U, invalid_external_estimate_provider->update_count());
- EXPECT_FALSE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_FALSE(estimator.GetHttpRTT(&rtt));
+ EXPECT_FALSE(estimator.GetDownlinkThroughputKbps(&kbps));
histogram_tester.ExpectTotalCount("NQE.ExternalEstimateProviderStatus", 2);
histogram_tester.ExpectBucketCount(
@@ -1270,13 +1140,13 @@ TEST(NetworkQualityEstimatorTest, TestExternalEstimateProvider) {
std::map<std::string, std::string> variation_params;
TestNetworkQualityEstimator estimator(variation_params,
std::move(external_estimate_provider));
- estimator.SimulateNetworkChangeTo(net::NetworkChangeNotifier::CONNECTION_WIFI,
- "test");
+ estimator.SimulateNetworkChange(net::NetworkChangeNotifier::CONNECTION_WIFI,
+ "test");
base::TimeDelta rtt;
int32_t kbps;
- EXPECT_TRUE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_FALSE(estimator.GetTransportRTTEstimate(&rtt));
- EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_TRUE(estimator.GetHttpRTT(&rtt));
+ EXPECT_FALSE(estimator.GetTransportRTT(&rtt));
+ EXPECT_TRUE(estimator.GetDownlinkThroughputKbps(&kbps));
histogram_tester.ExpectTotalCount("NQE.ExternalEstimateProviderStatus", 5);
@@ -1304,20 +1174,20 @@ TEST(NetworkQualityEstimatorTest, TestExternalEstimateProvider) {
// Change network type to WiFi. Number of queries to External estimate
// provider must increment.
- estimator.SimulateNetworkChangeTo(
+ estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1");
- EXPECT_TRUE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_TRUE(estimator.GetHttpRTT(&rtt));
+ EXPECT_TRUE(estimator.GetDownlinkThroughputKbps(&kbps));
EXPECT_EQ(2U, test_external_estimate_provider->update_count());
test_external_estimate_provider->set_should_notify_delegate(false);
- estimator.SimulateNetworkChangeTo(
+ estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-2");
EXPECT_EQ(3U, test_external_estimate_provider->update_count());
// Estimates are unavailable because external estimate provider never
// notifies network quality estimator of the updated estimates.
- EXPECT_FALSE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_FALSE(estimator.GetHttpRTT(&rtt));
+ EXPECT_FALSE(estimator.GetDownlinkThroughputKbps(&kbps));
}
// Tests if the estimate from the external estimate provider is merged with the
@@ -1336,17 +1206,17 @@ TEST(NetworkQualityEstimatorTest, TestExternalEstimateProviderMergeEstimates) {
std::map<std::string, std::string> variation_params;
TestNetworkQualityEstimator estimator(variation_params,
std::move(external_estimate_provider));
- estimator.SimulateNetworkChangeTo(net::NetworkChangeNotifier::CONNECTION_WIFI,
- "test");
+ estimator.SimulateNetworkChange(net::NetworkChangeNotifier::CONNECTION_WIFI,
+ "test");
base::TimeDelta rtt;
// Estimate provided by network quality estimator should match the estimate
// provided by external estimate provider.
- EXPECT_TRUE(estimator.GetHttpRTTEstimate(&rtt));
+ EXPECT_TRUE(estimator.GetHttpRTT(&rtt));
EXPECT_EQ(external_estimate_provider_rtt, rtt);
int32_t kbps;
- EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_TRUE(estimator.GetDownlinkThroughputKbps(&kbps));
EXPECT_EQ(external_estimate_provider_downstream_throughput, kbps);
TestDelegate test_delegate;
@@ -1359,10 +1229,10 @@ TEST(NetworkQualityEstimatorTest, TestExternalEstimateProviderMergeEstimates) {
request->Start();
base::RunLoop().Run();
- EXPECT_TRUE(estimator.GetHttpRTTEstimate(&rtt));
+ EXPECT_TRUE(estimator.GetHttpRTT(&rtt));
EXPECT_NE(external_estimate_provider_rtt, rtt);
- EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_TRUE(estimator.GetDownlinkThroughputKbps(&kbps));
EXPECT_NE(external_estimate_provider_downstream_throughput, kbps);
}
@@ -1390,9 +1260,9 @@ TEST(NetworkQualityEstimatorTest, TestThroughputNoRequestOverlap) {
test.allow_small_localhost_requests);
base::TimeDelta rtt;
- EXPECT_FALSE(estimator.GetHttpRTTEstimate(&rtt));
+ EXPECT_FALSE(estimator.GetHttpRTT(&rtt));
int32_t kbps;
- EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ EXPECT_FALSE(estimator.GetDownlinkThroughputKbps(&kbps));
TestDelegate test_delegate;
TestURLRequestContext context(true);
@@ -1401,14 +1271,13 @@ TEST(NetworkQualityEstimatorTest, TestThroughputNoRequestOverlap) {
std::unique_ptr<URLRequest> request(context.CreateRequest(
estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
- request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME);
+ request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
request->Start();
base::RunLoop().Run();
+ EXPECT_EQ(test.allow_small_localhost_requests, estimator.GetHttpRTT(&rtt));
EXPECT_EQ(test.allow_small_localhost_requests,
- estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_EQ(test.allow_small_localhost_requests,
- estimator.GetDownlinkThroughputKbpsEstimate(&kbps));
+ estimator.GetDownlinkThroughputKbps(&kbps));
}
}
@@ -1433,46 +1302,169 @@ TEST(NetworkQualityEstimatorTest, TestEffectiveConnectionTypeObserver) {
EXPECT_EQ(0U, observer.effective_connection_types().size());
- estimator.set_effective_connection_type(
- NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G);
+ estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G);
tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(60));
std::unique_ptr<URLRequest> request(context.CreateRequest(
estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
- request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME);
+ request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
request->Start();
base::RunLoop().Run();
EXPECT_EQ(1U, observer.effective_connection_types().size());
histogram_tester.ExpectUniqueSample(
"NQE.MainFrame.EffectiveConnectionType.Unknown",
- NetworkQualityEstimator::EffectiveConnectionType::
- EFFECTIVE_CONNECTION_TYPE_2G,
- 1);
+ EFFECTIVE_CONNECTION_TYPE_2G, 1);
// Next request should not trigger recomputation of effective connection type
// since there has been no change in the clock.
std::unique_ptr<URLRequest> request2(context.CreateRequest(
estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
- request2->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME);
+ request2->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
request2->Start();
base::RunLoop().Run();
EXPECT_EQ(1U, observer.effective_connection_types().size());
// Change in connection type should send out notification to the observers.
- estimator.set_effective_connection_type(
- NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_3G);
- estimator.SimulateNetworkChangeTo(NetworkChangeNotifier::CONNECTION_WIFI,
- "test");
+ estimator.set_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_3G);
+ estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI,
+ "test");
EXPECT_EQ(2U, 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_effective_connection_type(
- NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_3G);
+ estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_3G);
EXPECT_EQ(2U, observer.effective_connection_types().size());
}
+// 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();
+
+ TestEffectiveConnectionTypeObserver observer;
+ std::map<std::string, std::string> variation_params;
+ TestNetworkQualityEstimator estimator(variation_params);
+ estimator.SetTickClockForTesting(std::move(tick_clock));
+ estimator.AddEffectiveConnectionTypeObserver(&observer);
+ tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(60));
+
+ size_t expected_effective_connection_type_notifications = 0;
+ estimator.set_recent_effective_connection_type(
+ EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
+ // Run one main frame request to force recomputation of effective connection
+ // type.
+ estimator.RunOneRequest();
+ estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI,
+ "test");
+
+ NetworkQualityEstimator::RttObservation rtt_observation(
+ base::TimeDelta::FromSeconds(5), tick_clock_ptr->NowTicks(),
+ NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST);
+
+ for (size_t i = 0; i < 10; ++i) {
+ estimator.NotifyObserversOfRTT(rtt_observation);
+ EXPECT_EQ(expected_effective_connection_type_notifications,
+ observer.effective_connection_types().size());
+ }
+ estimator.set_recent_effective_connection_type(
+ EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+ // Even though there are 10 RTT samples already available, the addition of one
+ // more RTT sample should trigger recomputation of the effective connection
+ // type since the last computed effective connection type was unknown.
+ estimator.NotifyObserversOfRTT(NetworkQualityEstimator::RttObservation(
+ base::TimeDelta::FromSeconds(5), tick_clock_ptr->NowTicks(),
+ NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+ ++expected_effective_connection_type_notifications;
+ EXPECT_EQ(expected_effective_connection_type_notifications,
+ observer.effective_connection_types().size());
+}
+
+// Tests that the effective connection type is computed regularly depending
+// on the number of RTT and bandwidth samples.
+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();
+
+ TestEffectiveConnectionTypeObserver observer;
+ std::map<std::string, std::string> variation_params;
+ TestNetworkQualityEstimator estimator(variation_params);
+ estimator.SetTickClockForTesting(std::move(tick_clock));
+ estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI,
+ "test");
+ estimator.AddEffectiveConnectionTypeObserver(&observer);
+
+ TestDelegate test_delegate;
+ TestURLRequestContext context(true);
+ context.set_network_quality_estimator(&estimator);
+ context.Init();
+
+ 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));
+
+ std::unique_ptr<URLRequest> request(context.CreateRequest(
+ estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
+ request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
+ request->Start();
+ base::RunLoop().Run();
+ EXPECT_EQ(1U, observer.effective_connection_types().size());
+ histogram_tester.ExpectUniqueSample(
+ "NQE.MainFrame.EffectiveConnectionType.WiFi",
+ EFFECTIVE_CONNECTION_TYPE_2G, 1);
+
+ size_t expected_effective_connection_type_notifications = 1;
+ EXPECT_EQ(expected_effective_connection_type_notifications,
+ observer.effective_connection_types().size());
+
+ EXPECT_EQ(expected_effective_connection_type_notifications,
+ estimator.rtt_observations_.Size());
+
+ // Increase the number of RTT observations. Every time the number of RTT
+ // observations is more than doubled, effective connection type must be
+ // recomputed and notified to observers.
+ for (size_t repetition = 0; repetition < 2; ++repetition) {
+ // Change the effective connection type so that the observers are
+ // notified when the effective connection type is recomputed.
+ if (repetition % 2 == 0) {
+ estimator.set_recent_effective_connection_type(
+ EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+ } else {
+ estimator.set_recent_effective_connection_type(
+ EFFECTIVE_CONNECTION_TYPE_3G);
+ }
+ size_t rtt_observations_count = estimator.rtt_observations_.Size() * 0.5;
+ // Increase the number of RTT observations to more than twice the number
+ // of current observations. This should trigger recomputation of
+ // effective connection type.
+ for (size_t i = 0; i < rtt_observations_count + 1; ++i) {
+ estimator.rtt_observations_.AddObservation(
+ NetworkQualityEstimator::RttObservation(
+ base::TimeDelta::FromSeconds(5), tick_clock_ptr->NowTicks(),
+ NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+
+ estimator.NotifyObserversOfRTT(NetworkQualityEstimator::RttObservation(
+ base::TimeDelta::FromSeconds(5), tick_clock_ptr->NowTicks(),
+ NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+
+ if (i == rtt_observations_count) {
+ // Effective connection type must be recomputed since the number of RTT
+ // samples are now more than twice the number of RTT samples that were
+ // available when effective connection type was last computed.
+ ++expected_effective_connection_type_notifications;
+ }
+ EXPECT_EQ(expected_effective_connection_type_notifications,
+ observer.effective_connection_types().size());
+ }
+ }
+}
+
TEST(NetworkQualityEstimatorTest, TestRttThroughputObservers) {
TestRTTObserver rtt_observer;
TestThroughputObserver throughput_observer;
@@ -1492,22 +1484,22 @@ TEST(NetworkQualityEstimatorTest, TestRttThroughputObservers) {
std::unique_ptr<URLRequest> request(context.CreateRequest(
estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
- request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME);
+ request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
request->Start();
base::RunLoop().Run();
std::unique_ptr<URLRequest> request2(context.CreateRequest(
estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
- request2->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME);
+ request2->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
request2->Start();
base::RunLoop().Run();
// Both RTT and downstream throughput should be updated.
base::TimeDelta rtt;
- EXPECT_TRUE(estimator.GetHttpRTTEstimate(&rtt));
+ EXPECT_TRUE(estimator.GetHttpRTT(&rtt));
int32_t throughput;
- EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&throughput));
+ EXPECT_TRUE(estimator.GetDownlinkThroughputKbps(&throughput));
EXPECT_EQ(2U, rtt_observer.observations().size());
EXPECT_EQ(2U, throughput_observer.observations().size());
@@ -1524,7 +1516,7 @@ TEST(NetworkQualityEstimatorTest, TestRttThroughputObservers) {
observation.source);
}
- EXPECT_FALSE(estimator.GetTransportRTTEstimate(&rtt));
+ EXPECT_FALSE(estimator.GetTransportRTT(&rtt));
// Verify that observations from TCP and QUIC are passed on to the observers.
base::TimeDelta tcp_rtt(base::TimeDelta::FromMilliseconds(1));
@@ -1552,7 +1544,7 @@ TEST(NetworkQualityEstimatorTest, TestRttThroughputObservers) {
EXPECT_EQ(quic_rtt.InMilliseconds(),
rtt_observer.observations().at(3).rtt_ms);
- EXPECT_TRUE(estimator.GetTransportRTTEstimate(&rtt));
+ EXPECT_TRUE(estimator.GetTransportRTT(&rtt));
}
// TestTCPSocketRTT requires kernel support for tcp_info struct, and so it is
@@ -1585,8 +1577,8 @@ TEST(NetworkQualityEstimatorTest, MAYBE_TestTCPSocketRTT) {
EXPECT_EQ(0U, rtt_observer.observations().size());
base::TimeDelta rtt;
- EXPECT_FALSE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_FALSE(estimator.GetTransportRTTEstimate(&rtt));
+ EXPECT_FALSE(estimator.GetHttpRTT(&rtt));
+ EXPECT_FALSE(estimator.GetTransportRTT(&rtt));
// Send two requests. Verify that the completion of each request generates at
// least one TCP RTT observation.
@@ -1600,7 +1592,7 @@ TEST(NetworkQualityEstimatorTest, MAYBE_TestTCPSocketRTT) {
std::unique_ptr<URLRequest> request(context.CreateRequest(
estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
- request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME);
+ request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
request->Start();
base::RunLoop().Run();
@@ -1615,10 +1607,10 @@ TEST(NetworkQualityEstimatorTest, MAYBE_TestTCPSocketRTT) {
before_count_tcp_rtt_observations)
<< i;
}
- EXPECT_TRUE(estimator.GetHttpRTTEstimate(&rtt));
- EXPECT_TRUE(estimator.GetTransportRTTEstimate(&rtt));
+ EXPECT_TRUE(estimator.GetHttpRTT(&rtt));
+ EXPECT_TRUE(estimator.GetTransportRTT(&rtt));
- estimator.SimulateNetworkChangeTo(
+ estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1");
histogram_tester.ExpectTotalCount("NQE.TransportRTT.Percentile50.Unknown", 1);
histogram_tester.ExpectBucketCount("NQE.TransportRTT.Percentile50.Unknown",
@@ -1636,9 +1628,7 @@ TEST(NetworkQualityEstimatorTest, MAYBE_TestTCPSocketRTT) {
"NQE.MainFrame.EffectiveConnectionType.Unknown", num_requests);
histogram_tester.ExpectBucketCount(
"NQE.MainFrame.EffectiveConnectionType.Unknown",
- NetworkQualityEstimator::EffectiveConnectionType::
- EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
- 1);
+ EFFECTIVE_CONNECTION_TYPE_UNKNOWN, 1);
}
#if defined(OS_IOS)
@@ -1661,31 +1651,27 @@ TEST(NetworkQualityEstimatorTest, MAYBE_RecordAccuracy) {
base::TimeDelta recent_rtt;
int32_t downstream_throughput_kbps;
int32_t recent_downstream_throughput_kbps;
- NetworkQualityEstimator::EffectiveConnectionType effective_connection_type;
- NetworkQualityEstimator::EffectiveConnectionType
- recent_effective_connection_type;
+ EffectiveConnectionType effective_connection_type;
+ EffectiveConnectionType recent_effective_connection_type;
} tests[] = {
{base::TimeDelta::FromMilliseconds(expected_rtt_msec),
base::TimeDelta::FromMilliseconds(expected_rtt_msec),
expected_downstream_throughput_kbps, expected_downstream_throughput_kbps,
- NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G,
- NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G},
+ EFFECTIVE_CONNECTION_TYPE_2G, EFFECTIVE_CONNECTION_TYPE_2G},
{
base::TimeDelta::FromMilliseconds(expected_rtt_msec + 1),
base::TimeDelta::FromMilliseconds(expected_rtt_msec),
expected_downstream_throughput_kbps + 1,
- expected_downstream_throughput_kbps,
- NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_3G,
- NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G,
+ expected_downstream_throughput_kbps, EFFECTIVE_CONNECTION_TYPE_3G,
+ EFFECTIVE_CONNECTION_TYPE_2G,
},
{
base::TimeDelta::FromMilliseconds(expected_rtt_msec - 1),
base::TimeDelta::FromMilliseconds(expected_rtt_msec),
expected_downstream_throughput_kbps - 1,
expected_downstream_throughput_kbps,
- NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
- NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G,
+ EFFECTIVE_CONNECTION_TYPE_SLOW_2G, EFFECTIVE_CONNECTION_TYPE_2G,
},
};
@@ -1696,10 +1682,15 @@ TEST(NetworkQualityEstimatorTest, MAYBE_RecordAccuracy) {
base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
tick_clock_ptr->Advance(base::TimeDelta::FromSeconds(1));
+ std::unique_ptr<ExternalEstimateProvider> external_estimate_provider(
+ new TestExternalEstimateProvider(test.rtt, 0));
+
std::map<std::string, std::string> variation_params;
- TestNetworkQualityEstimator estimator(variation_params);
+ TestNetworkQualityEstimator estimator(
+ variation_params, std::move(external_estimate_provider));
+
estimator.SetTickClockForTesting(std::move(tick_clock));
- estimator.SimulateNetworkChangeTo(
+ estimator.SimulateNetworkChange(
NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1");
tick_clock_ptr->Advance(base::TimeDelta::FromSeconds(1));
@@ -1731,7 +1722,7 @@ TEST(NetworkQualityEstimatorTest, MAYBE_RecordAccuracy) {
// to record accuracy UMA.
std::unique_ptr<URLRequest> request(context.CreateRequest(
estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
- request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME);
+ request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
request->Start();
base::RunLoop().Run();
@@ -1790,25 +1781,312 @@ TEST(NetworkQualityEstimatorTest, MAYBE_RecordAccuracy) {
"NQE.Accuracy.TransportRTT.EstimatedObservedDiff." +
sign_suffix_with_zero_samples + "." + interval_value + ".60_140",
0);
+
+ histogram_tester.ExpectUniqueSample(
+ "NQE.ExternalEstimateProvider.RTT.Accuracy.EstimatedObservedDiff." +
+ sign_suffix_with_one_sample + "." + interval_value + ".60_140",
+ diff, 1);
+ histogram_tester.ExpectTotalCount(
+ "NQE.ExternalEstimateProvider.RTT.Accuracy.EstimatedObservedDiff." +
+ sign_suffix_with_zero_samples + "." + interval_value + ".60_140",
+ 0);
}
}
}
-// Tests that the effective connection type is converted correctly to a
-// descriptive string name, and vice-versa.
-TEST(NetworkQualityEstimatorTest, NameConnectionTypeConversion) {
- for (size_t i = 0;
- i < NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_LAST; ++i) {
- const NetworkQualityEstimator::EffectiveConnectionType
- effective_connection_type =
- static_cast<NetworkQualityEstimator::EffectiveConnectionType>(i);
- std::string connection_type_name =
- std::string(NetworkQualityEstimator::GetNameForEffectiveConnectionType(
- effective_connection_type));
- EXPECT_FALSE(connection_type_name.empty());
- EXPECT_EQ(effective_connection_type,
- NetworkQualityEstimator::GetEffectiveConnectionTypeForName(
- connection_type_name));
+TEST(NetworkQualityEstimatorTest, TestRecordNetworkIDAvailability) {
+ base::HistogramTester histogram_tester;
+ std::map<std::string, std::string> variation_params;
+ TestNetworkQualityEstimator estimator(variation_params);
+
+ // The NetworkID is recorded as available on Wi-Fi connection.
+ estimator.SimulateNetworkChange(
+ NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1");
+ histogram_tester.ExpectUniqueSample("NQE.NetworkIdAvailable", 1, 1);
+
+ // The histogram is not recorded on an unknown connection.
+ estimator.SimulateNetworkChange(
+ NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "");
+ histogram_tester.ExpectTotalCount("NQE.NetworkIdAvailable", 1);
+
+ // The NetworkID is recorded as not being available on a Wi-Fi connection
+ // with an empty SSID.
+ estimator.SimulateNetworkChange(
+ NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "");
+ histogram_tester.ExpectBucketCount("NQE.NetworkIdAvailable", 0, 1);
+ histogram_tester.ExpectTotalCount("NQE.NetworkIdAvailable", 2);
+
+ // The NetworkID is recorded as being available on a Wi-Fi connection.
+ estimator.SimulateNetworkChange(
+ NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1");
+ histogram_tester.ExpectBucketCount("NQE.NetworkIdAvailable", 1, 2);
+ histogram_tester.ExpectTotalCount("NQE.NetworkIdAvailable", 3);
+
+ // The NetworkID is recorded as being available on a cellular connection.
+ estimator.SimulateNetworkChange(
+ NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-1");
+ histogram_tester.ExpectBucketCount("NQE.NetworkIdAvailable", 1, 3);
+ 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 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::DoubleToString(test.correlation_logging_probability);
+ if (test.use_transport_rtt) {
+ variation_params["effective_connection_type_algorithm"] =
+ "TransportRTTOrDownstreamThroughput";
+ }
+ TestNetworkQualityEstimator estimator(variation_params);
+
+ estimator.set_transport_rtt(test.transport_rtt);
+ estimator.set_recent_transport_rtt(test.transport_rtt);
+ estimator.set_http_rtt(test.http_rtt);
+ estimator.set_recent_http_rtt(test.http_rtt);
+ estimator.set_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();
+
+ // 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));
+ request_1->SetLoadFlags(request_1->load_flags() |
+ LOAD_MAIN_FRAME_DEPRECATED);
+ request_1->Start();
+ base::RunLoop().Run();
+ histogram_tester.ExpectTotalCount(
+ "NQE.Correlation.ResourceLoadTime.0Kb_128Kb", 0);
+
+ // Start another main-frame request which should cause network quality
+ // estimator to record the correlation UMA.
+ std::unique_ptr<URLRequest> request_2(context.CreateRequest(
+ estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
+ request_2->Start();
+ base::RunLoop().Run();
+
+ if (test.rand_double >= test.correlation_logging_probability) {
+ 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);
+ }
+}
+
+class TestNetworkQualitiesCacheObserver
+ : public nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver {
+ public:
+ TestNetworkQualitiesCacheObserver()
+ : network_id_(net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
+ std::string()),
+ notification_received_(0) {}
+ ~TestNetworkQualitiesCacheObserver() override {}
+
+ void OnChangeInCachedNetworkQuality(
+ const nqe::internal::NetworkID& network_id,
+ const nqe::internal::CachedNetworkQuality& cached_network_quality)
+ override {
+ network_id_ = network_id;
+ notification_received_++;
+ }
+
+ size_t get_notification_received_and_reset() {
+ size_t notification_received = notification_received_;
+ notification_received_ = 0;
+ return notification_received;
+ }
+
+ nqe::internal::NetworkID network_id() const { return network_id_; }
+
+ private:
+ nqe::internal::NetworkID network_id_;
+ size_t notification_received_;
+ DISALLOW_COPY_AND_ASSIGN(TestNetworkQualitiesCacheObserver);
+};
+
+TEST(NetworkQualityEstimatorTest, CacheObserver) {
+ TestNetworkQualitiesCacheObserver observer;
+ std::map<std::string, std::string> variation_params;
+ TestNetworkQualityEstimator estimator(variation_params);
+
+ // Add |observer| as a persistent caching observer.
+ estimator.AddNetworkQualitiesCacheObserver(&observer);
+
+ estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_3G);
+ estimator.SimulateNetworkChange(
+ NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test3g");
+ estimator.RunOneRequest();
+ EXPECT_EQ(1u, observer.get_notification_received_and_reset());
+ EXPECT_EQ("test3g", observer.network_id().id);
+
+ estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G);
+ estimator.SimulateNetworkChange(
+ NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test2g");
+ // One notification should be received for the previous network
+ // ("test3g") right before the connection change event. The second
+ // notification should be received for the second network ("test2g").
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(2u, observer.get_notification_received_and_reset());
+ estimator.RunOneRequest();
+ EXPECT_EQ("test2g", observer.network_id().id);
+
+ estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_4G);
+ // Start multiple requests, but there should be only one notification
+ // received, since the effective connection type does not change.
+ estimator.RunOneRequest();
+ estimator.RunOneRequest();
+ estimator.RunOneRequest();
+ EXPECT_EQ(1u, observer.get_notification_received_and_reset());
+
+ estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G);
+ estimator.RunOneRequest();
+ EXPECT_EQ(1u, observer.get_notification_received_and_reset());
+
+ // Remove |observer|, and it should not receive any notifications.
+ estimator.RemoveNetworkQualitiesCacheObserver(&observer);
+ estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_3G);
+ estimator.SimulateNetworkChange(
+ NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test2g");
+ EXPECT_EQ(0u, observer.get_notification_received_and_reset());
+ estimator.RunOneRequest();
+ EXPECT_EQ(0u, observer.get_notification_received_and_reset());
+}
+
+// Tests that the value of the effective connection type can be forced through
+// field trial parameters.
+TEST(NetworkQualityEstimatorTest,
+ ForceEffectiveConnectionTypeThroughFieldTrial) {
+ for (int i = 0; i < EFFECTIVE_CONNECTION_TYPE_LAST; ++i) {
+ std::map<std::string, std::string> variation_params;
+ variation_params["force_effective_connection_type"] =
+ GetNameForEffectiveConnectionType(
+ static_cast<EffectiveConnectionType>(i));
+ TestNetworkQualityEstimator estimator(variation_params);
+
+ TestEffectiveConnectionTypeObserver observer;
+ estimator.AddEffectiveConnectionTypeObserver(&observer);
+
+ TestDelegate test_delegate;
+ TestURLRequestContext context(true);
+ context.set_network_quality_estimator(&estimator);
+ context.Init();
+
+ EXPECT_EQ(0U, observer.effective_connection_types().size());
+
+ std::unique_ptr<URLRequest> request(context.CreateRequest(
+ estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate));
+ request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
+ request->Start();
+ base::RunLoop().Run();
+
+ EXPECT_EQ(i, estimator.GetEffectiveConnectionType());
+
+ size_t expected_count = static_cast<EffectiveConnectionType>(i) ==
+ EFFECTIVE_CONNECTION_TYPE_UNKNOWN
+ ? 0
+ : 1;
+ ASSERT_EQ(expected_count, observer.effective_connection_types().size());
+ if (expected_count == 1) {
+ EffectiveConnectionType last_notified_type =
+ observer.effective_connection_types().at(
+ observer.effective_connection_types().size() - 1);
+ EXPECT_EQ(i, last_notified_type);
+ }
}
}
diff --git a/chromium/net/nqe/network_quality_observation_source.h b/chromium/net/nqe/network_quality_observation_source.h
index da64c6766d1..c1614027f27 100644
--- a/chromium/net/nqe/network_quality_observation_source.h
+++ b/chromium/net/nqe/network_quality_observation_source.h
@@ -32,7 +32,9 @@ enum NetworkQualityObservationSource {
NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_FROM_PLATFORM,
// The observation came from a Chromium-external source.
- NETWORK_QUALITY_OBSERVATION_SOURCE_EXTERNAL_ESTIMATE
+ NETWORK_QUALITY_OBSERVATION_SOURCE_EXTERNAL_ESTIMATE,
+
+ NETWORK_QUALITY_OBSERVATION_SOURCE_MAX,
};
} // namespace net
diff --git a/chromium/net/nqe/network_quality_observation_unittest.cc b/chromium/net/nqe/network_quality_observation_unittest.cc
deleted file mode 100644
index f8215a23f4e..00000000000
--- a/chromium/net/nqe/network_quality_observation_unittest.cc
+++ /dev/null
@@ -1,332 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/nqe/network_quality_observation.h"
-
-#include <stddef.h>
-
-#include <vector>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "net/nqe/network_quality_observation_source.h"
-#include "net/nqe/observation_buffer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-namespace nqe {
-
-namespace {
-
-// Verifies that the percentiles are correctly computed. All observations have
-// the same timestamp.
-TEST(NetworkQualityObservationTest, PercentileSameTimestamps) {
- internal::ObservationBuffer<int32_t> int_buffer(0.5);
- internal::ObservationBuffer<base::TimeDelta> time_delta_buffer(0.5);
- ASSERT_EQ(0u, int_buffer.Size());
- ASSERT_LT(0u, int_buffer.Capacity());
- ASSERT_EQ(0u, time_delta_buffer.Size());
- ASSERT_LT(0u, time_delta_buffer.Capacity());
-
- const base::TimeTicks now = base::TimeTicks::Now();
-
- int32_t result;
- base::TimeDelta time_delta_result;
-
- // Percentiles should be unavailable when no observations are available.
- EXPECT_FALSE(
- int_buffer.GetPercentile(base::TimeTicks(), &result, 50,
- std::vector<NetworkQualityObservationSource>()));
- EXPECT_FALSE(time_delta_buffer.GetPercentile(
- base::TimeTicks(), &time_delta_result, 50,
- std::vector<NetworkQualityObservationSource>()));
-
- // Insert samples from {1,2,3,..., 100}. First insert odd samples, then even
- // samples. This helps in verifying that the order of samples does not matter.
- for (int i = 1; i <= 99; i += 2) {
- int_buffer.AddObservation(internal::Observation<int32_t>(
- i, now, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- time_delta_buffer.AddObservation(internal::Observation<base::TimeDelta>(
- base::TimeDelta::FromMilliseconds(i), now,
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- EXPECT_TRUE(int_buffer.GetPercentile(
- base::TimeTicks(), &result, 50,
- std::vector<NetworkQualityObservationSource>()));
- ASSERT_EQ(static_cast<size_t>(i / 2 + 1), int_buffer.Size());
- EXPECT_TRUE(time_delta_buffer.GetPercentile(
- base::TimeTicks(), &time_delta_result, 50,
- std::vector<NetworkQualityObservationSource>()));
- ASSERT_EQ(static_cast<size_t>(i / 2 + 1), time_delta_buffer.Size());
- }
-
- for (int i = 2; i <= 100; i += 2) {
- int_buffer.AddObservation(internal::Observation<int32_t>(
- i, now, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- time_delta_buffer.AddObservation(internal::Observation<base::TimeDelta>(
- base::TimeDelta::FromMilliseconds(i), now,
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- EXPECT_TRUE(int_buffer.GetPercentile(
- base::TimeTicks(), &result, 50,
- std::vector<NetworkQualityObservationSource>()));
- ASSERT_EQ(static_cast<size_t>(i / 2 + 50), int_buffer.Size());
- EXPECT_TRUE(time_delta_buffer.GetPercentile(
- base::TimeTicks(), &time_delta_result, 50,
- std::vector<NetworkQualityObservationSource>()));
- ASSERT_EQ(static_cast<size_t>(i / 2 + 50), time_delta_buffer.Size());
- }
-
- ASSERT_EQ(100u, int_buffer.Size());
- ASSERT_EQ(100u, time_delta_buffer.Size());
-
- for (int i = 0; i <= 100; ++i) {
- // Checks if the difference between the two integers is less than 1. This is
- // required because computed percentiles may be slightly different from
- // what is expected due to floating point computation errors and integer
- // rounding off errors.
- EXPECT_TRUE(int_buffer.GetPercentile(
- base::TimeTicks(), &result, i,
- std::vector<NetworkQualityObservationSource>()));
- EXPECT_TRUE(time_delta_buffer.GetPercentile(
- base::TimeTicks(), &time_delta_result, i,
- std::vector<NetworkQualityObservationSource>()));
- EXPECT_NEAR(result, i, 1);
- EXPECT_NEAR(time_delta_result.InMilliseconds(), i, 1);
- }
-
- EXPECT_FALSE(int_buffer.GetPercentile(
- now + base::TimeDelta::FromSeconds(1), &result, 50,
- std::vector<NetworkQualityObservationSource>()));
- EXPECT_FALSE(time_delta_buffer.GetPercentile(
- now + base::TimeDelta::FromSeconds(1), &time_delta_result, 50,
- std::vector<NetworkQualityObservationSource>()));
-
- // Percentiles should be unavailable when no observations are available.
- int_buffer.Clear();
- time_delta_buffer.Clear();
- EXPECT_FALSE(
- int_buffer.GetPercentile(base::TimeTicks(), &result, 50,
- std::vector<NetworkQualityObservationSource>()));
- EXPECT_FALSE(time_delta_buffer.GetPercentile(
- base::TimeTicks(), &time_delta_result, 50,
- std::vector<NetworkQualityObservationSource>()));
-}
-
-// Verifies that the percentiles are correctly computed. Observations have
-// different timestamps with half the observations being very old and the rest
-// of them being very recent. Percentiles should factor in recent observations
-// much more heavily than older samples.
-TEST(NetworkQualityObservationTest, PercentileDifferentTimestamps) {
- internal::ObservationBuffer<int32_t> int_buffer(0.5);
- internal::ObservationBuffer<base::TimeDelta> time_delta_buffer(0.5);
- const base::TimeTicks now = base::TimeTicks::Now();
- const base::TimeTicks very_old = now - base::TimeDelta::FromDays(365);
-
- int32_t result;
- base::TimeDelta time_delta_result;
-
- // Network quality should be unavailable when no observations are available.
- EXPECT_FALSE(
- int_buffer.GetPercentile(base::TimeTicks(), &result, 50,
- std::vector<NetworkQualityObservationSource>()));
- EXPECT_FALSE(time_delta_buffer.GetPercentile(
- base::TimeTicks(), &time_delta_result, 50,
- std::vector<NetworkQualityObservationSource>()));
-
- // First 50 samples have very old timestamp.
- for (int i = 1; i <= 50; ++i) {
- int_buffer.AddObservation(internal::Observation<int32_t>(
- i, very_old, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- time_delta_buffer.AddObservation(internal::Observation<base::TimeDelta>(
- base::TimeDelta::FromMilliseconds(i), very_old,
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- }
-
- // Next 50 (i.e., from 51 to 100) have recent timestamp.
- for (int i = 51; i <= 100; ++i) {
- int_buffer.AddObservation(internal::Observation<int32_t>(
- i, now, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- time_delta_buffer.AddObservation(internal::Observation<base::TimeDelta>(
- base::TimeDelta::FromMilliseconds(i), now,
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- }
-
- // Older samples have very little weight. So, all percentiles are >= 51
- // (lowest value among recent observations).
- for (int i = 1; i < 100; ++i) {
- // Checks if the difference between the two integers is less than 1. This is
- // required because computed percentiles may be slightly different from
- // what is expected due to floating point computation errors and integer
- // rounding off errors.
- EXPECT_TRUE(int_buffer.GetPercentile(
- base::TimeTicks(), &result, i,
- std::vector<NetworkQualityObservationSource>()));
- EXPECT_NEAR(result, 51 + 0.49 * i, 1);
-
- EXPECT_TRUE(time_delta_buffer.GetPercentile(
- base::TimeTicks(), &time_delta_result, i,
- std::vector<NetworkQualityObservationSource>()));
- EXPECT_NEAR(time_delta_result.InMilliseconds(), 51 + 0.49 * i, 1);
- }
-
- EXPECT_FALSE(int_buffer.GetPercentile(
- now + base::TimeDelta::FromSeconds(1), &result, 50,
- std::vector<NetworkQualityObservationSource>()));
- EXPECT_FALSE(time_delta_buffer.GetPercentile(
- now + base::TimeDelta::FromSeconds(1), &time_delta_result, 50,
- std::vector<NetworkQualityObservationSource>()));
-}
-
-// Verifies that the percentiles are correctly computed when some of the
-// observation sources are disallowed. All observations have the same timestamp.
-TEST(NetworkQualityObservationTest, DisallowedObservationSources) {
- internal::ObservationBuffer<int32_t> int_buffer(0.5);
- internal::ObservationBuffer<base::TimeDelta> time_delta_buffer(0.5);
- const base::TimeTicks now = base::TimeTicks::Now();
-
- int32_t result;
- base::TimeDelta time_delta_result;
-
- // Network quality should be unavailable when no observations are available.
- EXPECT_FALSE(
- int_buffer.GetPercentile(base::TimeTicks(), &result, 50,
- std::vector<NetworkQualityObservationSource>()));
- EXPECT_FALSE(time_delta_buffer.GetPercentile(
- base::TimeTicks(), &time_delta_result, 50,
- std::vector<NetworkQualityObservationSource>()));
-
- // Insert samples from {1,2,3,..., 100}. First insert odd samples, then even
- // samples. This helps in verifying that the order of samples does not matter.
- for (int i = 1; i <= 99; i += 2) {
- int_buffer.AddObservation(internal::Observation<int32_t>(
- i, now, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- time_delta_buffer.AddObservation(internal::Observation<base::TimeDelta>(
- base::TimeDelta::FromMilliseconds(i), now,
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- }
-
- // Add samples for TCP and QUIC observations which should not be taken into
- // account when computing the percentile.
- for (int i = 1; i <= 99; i += 2) {
- int_buffer.AddObservation(internal::Observation<int32_t>(
- 10000, now, NETWORK_QUALITY_OBSERVATION_SOURCE_TCP));
- int_buffer.AddObservation(internal::Observation<int32_t>(
- 10000, now, NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC));
- time_delta_buffer.AddObservation(internal::Observation<base::TimeDelta>(
- base::TimeDelta::FromMilliseconds(10000), now,
- NETWORK_QUALITY_OBSERVATION_SOURCE_TCP));
- time_delta_buffer.AddObservation(internal::Observation<base::TimeDelta>(
- base::TimeDelta::FromMilliseconds(10000), now,
- NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC));
- }
-
- for (int i = 2; i <= 100; i += 2) {
- int_buffer.AddObservation(internal::Observation<int32_t>(
- i, now, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- time_delta_buffer.AddObservation(internal::Observation<base::TimeDelta>(
- base::TimeDelta::FromMilliseconds(i), now,
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- }
-
- std::vector<NetworkQualityObservationSource> disallowed_observation_sources;
- disallowed_observation_sources.push_back(
- NETWORK_QUALITY_OBSERVATION_SOURCE_TCP);
- disallowed_observation_sources.push_back(
- NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC);
-
- for (int i = 0; i <= 100; ++i) {
- // Checks if the difference between the two integers is less than 1. This is
- // required because computed percentiles may be slightly different from
- // what is expected due to floating point computation errors and integer
- // rounding off errors.
- EXPECT_TRUE(int_buffer.GetPercentile(base::TimeTicks(), &result, i,
- disallowed_observation_sources));
- EXPECT_NEAR(result, i, 1);
- EXPECT_TRUE(
- time_delta_buffer.GetPercentile(base::TimeTicks(), &time_delta_result,
- i, disallowed_observation_sources));
- EXPECT_NEAR(time_delta_result.InMilliseconds(), i, 1);
- }
-
- // Now check the percentile value for TCP and QUIC observations.
- disallowed_observation_sources.clear();
- disallowed_observation_sources.push_back(
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST);
- for (int i = 0; i <= 100; ++i) {
- // Checks if the difference between the two integers is less than 1. This is
- // required because computed percentiles may be slightly different from
- // what is expected due to floating point computation errors and integer
- // rounding off errors.
- EXPECT_TRUE(int_buffer.GetPercentile(base::TimeTicks(), &result, i,
- disallowed_observation_sources));
- EXPECT_NEAR(result, 10000, 1);
- EXPECT_TRUE(
- time_delta_buffer.GetPercentile(base::TimeTicks(), &time_delta_result,
- i, disallowed_observation_sources));
- EXPECT_NEAR(time_delta_result.InMilliseconds(), 10000, 1);
- }
-}
-
-TEST(NetworkQualityObservationTest, TestGetMedianRTTSince) {
- internal::ObservationBuffer<int32_t> int_buffer(0.5);
- internal::ObservationBuffer<base::TimeDelta> time_delta_buffer(0.5);
- base::TimeTicks now = base::TimeTicks::Now();
- base::TimeTicks old = now - base::TimeDelta::FromMilliseconds(1);
- ASSERT_NE(old, now);
-
- // First sample has very old timestamp.
- int_buffer.AddObservation(internal::Observation<int32_t>(
- 1, old, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- time_delta_buffer.AddObservation(internal::Observation<base::TimeDelta>(
- base::TimeDelta::FromMilliseconds(1), old,
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
-
- int_buffer.AddObservation(internal::Observation<int32_t>(
- 100, now, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
- time_delta_buffer.AddObservation(internal::Observation<base::TimeDelta>(
- base::TimeDelta::FromMilliseconds(100), now,
- NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
-
- const struct {
- base::TimeTicks start_timestamp;
- bool expect_network_quality_available;
- base::TimeDelta expected_url_request_rtt;
- int32_t expected_downstream_throughput;
- } tests[] = {
- {now + base::TimeDelta::FromSeconds(10), false,
- base::TimeDelta::FromMilliseconds(0), 0},
- {now, true, base::TimeDelta::FromMilliseconds(100), 100},
- {now - base::TimeDelta::FromMicroseconds(500), true,
- base::TimeDelta::FromMilliseconds(100), 100},
-
- };
-
- for (const auto& test : tests) {
- base::TimeDelta url_request_rtt;
- int32_t downstream_throughput_kbps;
- std::vector<NetworkQualityObservationSource> disallowed_observation_sources;
-
- EXPECT_EQ(
- test.expect_network_quality_available,
- time_delta_buffer.GetPercentile(test.start_timestamp, &url_request_rtt,
- 50, disallowed_observation_sources));
- EXPECT_EQ(test.expect_network_quality_available,
- int_buffer.GetPercentile(test.start_timestamp,
- &downstream_throughput_kbps, 50,
- disallowed_observation_sources));
-
- if (test.expect_network_quality_available) {
- EXPECT_EQ(test.expected_url_request_rtt, url_request_rtt);
- EXPECT_EQ(test.expected_downstream_throughput,
- downstream_throughput_kbps);
- }
- }
-}
-
-} // namespace
-
-} // namespace nqe
-
-} // namespace net \ No newline at end of file
diff --git a/chromium/net/nqe/network_quality_store.cc b/chromium/net/nqe/network_quality_store.cc
new file mode 100644
index 00000000000..7a1c253bdba
--- /dev/null
+++ b/chromium/net/nqe/network_quality_store.cc
@@ -0,0 +1,101 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/nqe/network_quality_store.h"
+
+#include "net/base/network_change_notifier.h"
+
+namespace net {
+
+namespace nqe {
+
+namespace internal {
+
+NetworkQualityStore::NetworkQualityStore() {
+ 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");
+}
+
+NetworkQualityStore::~NetworkQualityStore() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void NetworkQualityStore::Add(
+ const nqe::internal::NetworkID& network_id,
+ const nqe::internal::CachedNetworkQuality& cached_network_quality) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_LE(cached_network_qualities_.size(),
+ static_cast<size_t>(kMaximumNetworkQualityCacheSize));
+
+ // If the network name is unavailable, caching should not be performed.
+ if (network_id.type != net::NetworkChangeNotifier::CONNECTION_ETHERNET &&
+ network_id.id.empty()) {
+ return;
+ }
+
+ // Remove the entry from the map, if it is already present.
+ cached_network_qualities_.erase(network_id);
+
+ if (cached_network_qualities_.size() == kMaximumNetworkQualityCacheSize) {
+ // Remove the oldest entry.
+ CachedNetworkQualities::iterator oldest_entry_iterator =
+ cached_network_qualities_.begin();
+
+ for (CachedNetworkQualities::iterator it =
+ cached_network_qualities_.begin();
+ it != cached_network_qualities_.end(); ++it) {
+ if ((it->second).OlderThan(oldest_entry_iterator->second))
+ oldest_entry_iterator = it;
+ }
+ cached_network_qualities_.erase(oldest_entry_iterator);
+ }
+
+ cached_network_qualities_.insert(
+ std::make_pair(network_id, cached_network_quality));
+ DCHECK_LE(cached_network_qualities_.size(),
+ static_cast<size_t>(kMaximumNetworkQualityCacheSize));
+
+ FOR_EACH_OBSERVER(
+ NetworkQualitiesCacheObserver, network_qualities_cache_observer_list_,
+ OnChangeInCachedNetworkQuality(network_id, cached_network_quality));
+}
+
+bool NetworkQualityStore::GetById(
+ const nqe::internal::NetworkID& network_id,
+ nqe::internal::CachedNetworkQuality* cached_network_quality) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ CachedNetworkQualities::const_iterator it =
+ cached_network_qualities_.find(network_id);
+
+ if (it == cached_network_qualities_.end())
+ return false;
+
+ *cached_network_quality = it->second;
+ return true;
+}
+
+void NetworkQualityStore::AddNetworkQualitiesCacheObserver(
+ nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver*
+ observer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ network_qualities_cache_observer_list_.AddObserver(observer);
+}
+
+void NetworkQualityStore::RemoveNetworkQualitiesCacheObserver(
+ nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver*
+ observer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ network_qualities_cache_observer_list_.RemoveObserver(observer);
+}
+
+} // namespace internal
+
+} // namespace nqe
+
+} // namespace net
diff --git a/chromium/net/nqe/network_quality_store.h b/chromium/net/nqe/network_quality_store.h
new file mode 100644
index 00000000000..6b71a646b46
--- /dev/null
+++ b/chromium/net/nqe/network_quality_store.h
@@ -0,0 +1,100 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_NQE_NETWORK_QUALITY_STORE_H_
+#define NET_NQE_NETWORK_QUALITY_STORE_H_
+
+#include <map>
+
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "base/threading/thread_checker.h"
+#include "net/base/net_export.h"
+#include "net/nqe/cached_network_quality.h"
+#include "net/nqe/effective_connection_type.h"
+#include "net/nqe/network_id.h"
+
+namespace net {
+
+namespace nqe {
+
+namespace internal {
+
+// NetworkQualityStore holds the network qualities of different networks in
+// memory. Entries are stored in LRU order, and older entries may be evicted.
+class NET_EXPORT_PRIVATE NetworkQualityStore {
+ public:
+ // Observes changes in the cached network qualities.
+ class NET_EXPORT NetworkQualitiesCacheObserver {
+ public:
+ // Notifies the observer of a change in the cached network quality. The
+ // observer must register and unregister itself on the IO thread. All the
+ // observers would be notified on the IO thread. |network_id| is the ID of
+ // the network whose cached quality is being reported.
+ virtual void OnChangeInCachedNetworkQuality(
+ const nqe::internal::NetworkID& network_id,
+ const nqe::internal::CachedNetworkQuality& cached_network_quality) = 0;
+
+ protected:
+ NetworkQualitiesCacheObserver() {}
+ virtual ~NetworkQualitiesCacheObserver() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NetworkQualitiesCacheObserver);
+ };
+
+ NetworkQualityStore();
+ ~NetworkQualityStore();
+
+ // Stores the network quality |cached_network_quality| of network with ID
+ // |network_id|.
+ void Add(const nqe::internal::NetworkID& network_id,
+ const nqe::internal::CachedNetworkQuality& cached_network_quality);
+
+ // 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);
+
+ // Adds and removes |observer| from the list of cache observers. The
+ // observers are notified on the same thread on which it was added. Addition
+ // and removal of the observer must happen on the same thread.
+ void AddNetworkQualitiesCacheObserver(
+ NetworkQualitiesCacheObserver* observer);
+ void RemoveNetworkQualitiesCacheObserver(
+ NetworkQualitiesCacheObserver* observer);
+
+ private:
+ // 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;
+
+ // This does not use an unordered_map or hash_map for code simplicity (the key
+ // just implements operator<, rather than hash and equality) and because the
+ // map is tiny.
+ typedef std::map<nqe::internal::NetworkID,
+ nqe::internal::CachedNetworkQuality>
+ CachedNetworkQualities;
+
+ // Data structure that stores the qualities of networks.
+ CachedNetworkQualities cached_network_qualities_;
+
+ // Observer list for changes in the cached network quality.
+ base::ObserverList<NetworkQualitiesCacheObserver>
+ network_qualities_cache_observer_list_;
+
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkQualityStore);
+};
+
+} // namespace internal
+
+} // namespace nqe
+
+} // namespace net
+
+#endif // NET_NQE_NETWORK_QUALITY_STORE_H_
diff --git a/chromium/net/nqe/network_quality_store_unittest.cc b/chromium/net/nqe/network_quality_store_unittest.cc
new file mode 100644
index 00000000000..5a17e639169
--- /dev/null
+++ b/chromium/net/nqe/network_quality_store_unittest.cc
@@ -0,0 +1,189 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/nqe/network_quality_store.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "base/time/time.h"
+#include "net/base/network_change_notifier.h"
+#include "net/nqe/cached_network_quality.h"
+#include "net/nqe/effective_connection_type.h"
+#include "net/nqe/network_id.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+TEST(NetworkQualityStoreTest, TestCaching) {
+ 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_2g_test1(
+ tick_clock.NowTicks(),
+ nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromSeconds(1), 1),
+ EFFECTIVE_CONNECTION_TYPE_2G);
+
+ {
+ // Entry will be added for (2G, "test1").
+ nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G,
+ "test1");
+ nqe::internal::CachedNetworkQuality read_network_quality;
+ network_quality_store.Add(network_id, cached_network_quality_2g_test1);
+ EXPECT_TRUE(
+ network_quality_store.GetById(network_id, &read_network_quality));
+ EXPECT_EQ(cached_network_quality_2g_test1.network_quality(),
+ read_network_quality.network_quality());
+ }
+
+ {
+ // Entry will be added for (2G, "test2").
+ nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G,
+ "test2");
+ nqe::internal::CachedNetworkQuality read_network_quality;
+ nqe::internal::CachedNetworkQuality cached_network_quality(
+ tick_clock.NowTicks(),
+ nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(2),
+ base::TimeDelta::FromSeconds(2), 2),
+ EFFECTIVE_CONNECTION_TYPE_2G);
+ network_quality_store.Add(network_id, cached_network_quality);
+ EXPECT_TRUE(
+ network_quality_store.GetById(network_id, &read_network_quality));
+ EXPECT_EQ(read_network_quality.network_quality(),
+ cached_network_quality.network_quality());
+ }
+
+ {
+ // Entry will be added for (3G, "test3").
+ nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_3G,
+ "test3");
+ nqe::internal::CachedNetworkQuality read_network_quality;
+ nqe::internal::CachedNetworkQuality cached_network_quality(
+ tick_clock.NowTicks(),
+ nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(3),
+ base::TimeDelta::FromSeconds(3), 3),
+ EFFECTIVE_CONNECTION_TYPE_3G);
+ network_quality_store.Add(network_id, cached_network_quality);
+ EXPECT_TRUE(
+ network_quality_store.GetById(network_id, &read_network_quality));
+ EXPECT_EQ(read_network_quality.network_quality(),
+ cached_network_quality.network_quality());
+ }
+
+ {
+ // Entry will not be added for (Unknown, "").
+ nqe::internal::NetworkID network_id(
+ NetworkChangeNotifier::CONNECTION_UNKNOWN, "");
+ nqe::internal::CachedNetworkQuality read_network_quality;
+ nqe::internal::CachedNetworkQuality set_network_quality(
+ tick_clock.NowTicks(),
+ nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(4),
+ base::TimeDelta::FromSeconds(4), 4),
+ EFFECTIVE_CONNECTION_TYPE_4G);
+ network_quality_store.Add(network_id, set_network_quality);
+ EXPECT_FALSE(
+ 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");
+ nqe::internal::CachedNetworkQuality read_network_quality;
+ EXPECT_TRUE(
+ network_quality_store.GetById(network_id, &read_network_quality));
+ EXPECT_EQ(cached_network_quality_2g_test1.network_quality(),
+ read_network_quality.network_quality());
+ }
+
+ {
+ // Existing entry will be overwritten for (2G, "test1").
+ nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G,
+ "test1");
+ nqe::internal::CachedNetworkQuality read_network_quality;
+ const nqe::internal::CachedNetworkQuality cached_network_quality(
+ tick_clock.NowTicks(),
+ nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(5),
+ base::TimeDelta::FromSeconds(5), 5),
+ EFFECTIVE_CONNECTION_TYPE_4G);
+ network_quality_store.Add(network_id, cached_network_quality);
+ EXPECT_TRUE(
+ network_quality_store.GetById(network_id, &read_network_quality));
+ EXPECT_EQ(cached_network_quality.network_quality(),
+ read_network_quality.network_quality());
+ }
+
+ {
+ // No entry should exist for (2G, "test4").
+ nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G,
+ "test4");
+ 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) {
+ nqe::internal::NetworkQualityStore network_quality_store;
+ base::SimpleTestTickClock tick_clock;
+
+ // Add more networks than the maximum size of the cache.
+ const size_t network_count = 11;
+
+ nqe::internal::CachedNetworkQuality read_network_quality(
+ tick_clock.NowTicks(),
+ nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(0),
+ base::TimeDelta::FromSeconds(0), 0),
+ EFFECTIVE_CONNECTION_TYPE_2G);
+
+ for (size_t i = 0; i < network_count; ++i) {
+ nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G,
+ "test" + base::IntToString(i));
+
+ const nqe::internal::CachedNetworkQuality network_quality(
+ tick_clock.NowTicks(),
+ nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromSeconds(1), 1),
+ EFFECTIVE_CONNECTION_TYPE_2G);
+ network_quality_store.Add(network_id, network_quality);
+ tick_clock.Advance(base::TimeDelta::FromSeconds(1));
+ }
+
+ base::TimeTicks earliest_last_update_time = tick_clock.NowTicks();
+ 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));
+
+ nqe::internal::CachedNetworkQuality read_network_quality(
+ tick_clock.NowTicks(),
+ nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(0),
+ base::TimeDelta::FromSeconds(0), 0),
+ EFFECTIVE_CONNECTION_TYPE_2G);
+ if (network_quality_store.GetById(network_id, &read_network_quality)) {
+ cache_match_count++;
+ earliest_last_update_time = std::min(
+ earliest_last_update_time, read_network_quality.last_update_time());
+ }
+ }
+
+ // Ensure that the number of entries in cache are fewer than |network_count|.
+ EXPECT_LT(cache_match_count, network_count);
+ EXPECT_GT(cache_match_count, 0u);
+
+ // Ensure that only LRU entries are cached by comparing the
+ // |earliest_last_update_time|.
+ EXPECT_EQ(
+ tick_clock.NowTicks() - base::TimeDelta::FromSeconds(cache_match_count),
+ earliest_last_update_time);
+}
+
+} // namespace
+
+} // namespace net \ No newline at end of file
diff --git a/chromium/net/nqe/observation_buffer.h b/chromium/net/nqe/observation_buffer.h
index cc3f1d86dba..9a4ce3ab238 100644
--- a/chromium/net/nqe/observation_buffer.h
+++ b/chromium/net/nqe/observation_buffer.h
@@ -9,12 +9,16 @@
#include <algorithm>
#include <deque>
+#include <memory>
+#include <utility>
#include <vector>
-#include "base/gtest_prod_util.h"
#include "base/macros.h"
+#include "base/time/default_tick_clock.h"
+#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "net/base/net_export.h"
+#include "net/nqe/network_quality_observation.h"
#include "net/nqe/network_quality_observation_source.h"
#include "net/nqe/weighted_observation.h"
@@ -29,7 +33,8 @@ template <typename ValueType>
class NET_EXPORT_PRIVATE ObservationBuffer {
public:
explicit ObservationBuffer(double weight_multiplier_per_second)
- : weight_multiplier_per_second_(weight_multiplier_per_second) {
+ : weight_multiplier_per_second_(weight_multiplier_per_second),
+ tick_clock_(new base::DefaultTickClock()) {
static_assert(kMaximumObservationsBufferSize > 0U,
"Minimum size of observation buffer must be > 0");
DCHECK_GE(weight_multiplier_per_second_, 0.0);
@@ -70,6 +75,7 @@ class NET_EXPORT_PRIVATE ObservationBuffer {
// value is unavailable if all the values in observation buffer are older
// than |begin_timestamp|.
// |result| must not be null.
+ // TODO(tbansal): Move out param |result| as the last param of the function.
bool GetPercentile(const base::TimeTicks& begin_timestamp,
ValueType* result,
int percentile,
@@ -116,6 +122,10 @@ class NET_EXPORT_PRIVATE ObservationBuffer {
return true;
}
+ void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock) {
+ tick_clock_ = std::move(tick_clock);
+ }
+
private:
// Maximum number of observations that can be held in the ObservationBuffer.
static const size_t kMaximumObservationsBufferSize = 300;
@@ -136,7 +146,7 @@ class NET_EXPORT_PRIVATE ObservationBuffer {
weighted_observations.clear();
double total_weight_observations = 0.0;
- base::TimeTicks now = base::TimeTicks::Now();
+ base::TimeTicks now = tick_clock_->NowTicks();
for (const auto& observation : observations_) {
if (observation.timestamp < begin_timestamp)
@@ -174,6 +184,8 @@ class NET_EXPORT_PRIVATE ObservationBuffer {
// weight_multiplier_per_second_ ^ kHalfLifeSeconds = 0.5
const double weight_multiplier_per_second_;
+ std::unique_ptr<base::TickClock> tick_clock_;
+
DISALLOW_COPY_AND_ASSIGN(ObservationBuffer);
};
diff --git a/chromium/net/nqe/observation_buffer_unittest.cc b/chromium/net/nqe/observation_buffer_unittest.cc
new file mode 100644
index 00000000000..4da54e44ddf
--- /dev/null
+++ b/chromium/net/nqe/observation_buffer_unittest.cc
@@ -0,0 +1,397 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/nqe/observation_buffer.h"
+
+#include <stddef.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "base/time/time.h"
+#include "net/nqe/network_quality_observation.h"
+#include "net/nqe/network_quality_observation_source.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace nqe {
+
+namespace internal {
+
+namespace {
+
+// Verify that the buffer size is never exceeded.
+TEST(NetworkQualityObservationBufferTest, BoundedBuffer) {
+ ObservationBuffer<int32_t> observation_buffer(1.0);
+ const base::TimeTicks now =
+ base::TimeTicks() + base::TimeDelta::FromSeconds(1);
+ for (int i = 1; i <= 1000; ++i) {
+ observation_buffer.AddObservation(
+ Observation<int32_t>(i, now, NETWORK_QUALITY_OBSERVATION_SOURCE_TCP));
+ // The number of entries should be at most the maximum buffer size.
+ EXPECT_GE(300u, observation_buffer.Size());
+ }
+}
+
+// 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) {
+ std::unique_ptr<base::SimpleTestTickClock> tick_clock(
+ new base::SimpleTestTickClock());
+ base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
+
+ ObservationBuffer<int32_t> observation_buffer(0.98);
+ observation_buffer.SetTickClockForTesting(std::move(tick_clock));
+ const base::TimeTicks now = tick_clock_ptr->NowTicks();
+ for (int i = 1; i <= 100; ++i) {
+ tick_clock_ptr->Advance(base::TimeDelta::FromSeconds(1));
+ observation_buffer.AddObservation(Observation<int32_t>(
+ i, tick_clock_ptr->NowTicks(), NETWORK_QUALITY_OBSERVATION_SOURCE_TCP));
+ }
+ EXPECT_EQ(100U, observation_buffer.Size());
+
+ int32_t result_lowest = INT32_MAX;
+ int32_t result_highest = INT32_MIN;
+
+ for (int i = 1; i <= 100; ++i) {
+ // Verify that i'th percentile is more than i-1'th percentile.
+ int32_t result_i;
+ EXPECT_TRUE(observation_buffer.GetPercentile(
+ now, &result_i, i, std::vector<NetworkQualityObservationSource>()));
+ result_lowest = std::min(result_lowest, result_i);
+
+ result_highest = std::max(result_highest, result_i);
+
+ int32_t result_i_1;
+ EXPECT_TRUE(observation_buffer.GetPercentile(
+ now, &result_i_1, i - 1,
+ std::vector<NetworkQualityObservationSource>()));
+
+ EXPECT_LE(result_i_1, result_i);
+ }
+ EXPECT_LT(result_lowest, result_highest);
+}
+#endif
+
+// Verifies that the percentiles are correctly computed. All observations have
+// the same timestamp.
+TEST(NetworkQualityObservationBufferTest, PercentileSameTimestamps) {
+ ObservationBuffer<int32_t> int_buffer(0.5);
+ ObservationBuffer<base::TimeDelta> time_delta_buffer(0.5);
+ ASSERT_EQ(0u, int_buffer.Size());
+ ASSERT_LT(0u, int_buffer.Capacity());
+ ASSERT_EQ(0u, time_delta_buffer.Size());
+ ASSERT_LT(0u, time_delta_buffer.Capacity());
+
+ const base::TimeTicks now = base::TimeTicks::Now();
+
+ int32_t result;
+ base::TimeDelta time_delta_result;
+
+ // Percentiles should be unavailable when no observations are available.
+ EXPECT_FALSE(
+ int_buffer.GetPercentile(base::TimeTicks(), &result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+ EXPECT_FALSE(time_delta_buffer.GetPercentile(
+ base::TimeTicks(), &time_delta_result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+
+ // Insert samples from {1,2,3,..., 100}. First insert odd samples, then even
+ // samples. This helps in verifying that the order of samples does not matter.
+ for (int i = 1; i <= 99; i += 2) {
+ int_buffer.AddObservation(Observation<int32_t>(
+ i, now, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+ time_delta_buffer.AddObservation(Observation<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(i), now,
+ NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+ EXPECT_TRUE(int_buffer.GetPercentile(
+ base::TimeTicks(), &result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+ ASSERT_EQ(static_cast<size_t>(i / 2 + 1), int_buffer.Size());
+ EXPECT_TRUE(time_delta_buffer.GetPercentile(
+ base::TimeTicks(), &time_delta_result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+ ASSERT_EQ(static_cast<size_t>(i / 2 + 1), time_delta_buffer.Size());
+ }
+
+ for (int i = 2; i <= 100; i += 2) {
+ int_buffer.AddObservation(Observation<int32_t>(
+ i, now, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+ time_delta_buffer.AddObservation(Observation<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(i), now,
+ NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+ EXPECT_TRUE(int_buffer.GetPercentile(
+ base::TimeTicks(), &result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+ ASSERT_EQ(static_cast<size_t>(i / 2 + 50), int_buffer.Size());
+ EXPECT_TRUE(time_delta_buffer.GetPercentile(
+ base::TimeTicks(), &time_delta_result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+ ASSERT_EQ(static_cast<size_t>(i / 2 + 50), time_delta_buffer.Size());
+ }
+
+ ASSERT_EQ(100u, int_buffer.Size());
+ ASSERT_EQ(100u, time_delta_buffer.Size());
+
+ for (int i = 0; i <= 100; ++i) {
+ // Checks if the difference between the two integers is less than 1. This is
+ // required because computed percentiles may be slightly different from
+ // what is expected due to floating point computation errors and integer
+ // rounding off errors.
+ EXPECT_TRUE(int_buffer.GetPercentile(
+ base::TimeTicks(), &result, i,
+ std::vector<NetworkQualityObservationSource>()));
+ EXPECT_TRUE(time_delta_buffer.GetPercentile(
+ base::TimeTicks(), &time_delta_result, i,
+ std::vector<NetworkQualityObservationSource>()));
+ EXPECT_NEAR(result, i, 1);
+ EXPECT_NEAR(time_delta_result.InMilliseconds(), i, 1);
+ }
+
+ EXPECT_FALSE(int_buffer.GetPercentile(
+ now + base::TimeDelta::FromSeconds(1), &result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+ EXPECT_FALSE(time_delta_buffer.GetPercentile(
+ now + base::TimeDelta::FromSeconds(1), &time_delta_result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+
+ // Percentiles should be unavailable when no observations are available.
+ int_buffer.Clear();
+ time_delta_buffer.Clear();
+ EXPECT_FALSE(
+ int_buffer.GetPercentile(base::TimeTicks(), &result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+ EXPECT_FALSE(time_delta_buffer.GetPercentile(
+ base::TimeTicks(), &time_delta_result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+}
+
+// Verifies that the percentiles are correctly computed. Observations have
+// different timestamps with half the observations being very old and the rest
+// of them being very recent. Percentiles should factor in recent observations
+// much more heavily than older samples.
+TEST(NetworkQualityObservationBufferTest, PercentileDifferentTimestamps) {
+ ObservationBuffer<int32_t> int_buffer(0.5);
+ ObservationBuffer<base::TimeDelta> time_delta_buffer(0.5);
+ const base::TimeTicks now = base::TimeTicks::Now();
+ const base::TimeTicks very_old = now - base::TimeDelta::FromDays(365);
+
+ int32_t result;
+ base::TimeDelta time_delta_result;
+
+ // Network quality should be unavailable when no observations are available.
+ EXPECT_FALSE(
+ int_buffer.GetPercentile(base::TimeTicks(), &result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+ EXPECT_FALSE(time_delta_buffer.GetPercentile(
+ base::TimeTicks(), &time_delta_result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+
+ // First 50 samples have very old timestamp.
+ for (int i = 1; i <= 50; ++i) {
+ int_buffer.AddObservation(Observation<int32_t>(
+ i, very_old, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+ time_delta_buffer.AddObservation(Observation<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(i), very_old,
+ NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+ }
+
+ // Next 50 (i.e., from 51 to 100) have recent timestamp.
+ for (int i = 51; i <= 100; ++i) {
+ int_buffer.AddObservation(Observation<int32_t>(
+ i, now, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+ time_delta_buffer.AddObservation(Observation<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(i), now,
+ NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+ }
+
+ // Older samples have very little weight. So, all percentiles are >= 51
+ // (lowest value among recent observations).
+ for (int i = 1; i < 100; ++i) {
+ // Checks if the difference between the two integers is less than 1. This is
+ // required because computed percentiles may be slightly different from
+ // what is expected due to floating point computation errors and integer
+ // rounding off errors.
+ EXPECT_TRUE(int_buffer.GetPercentile(
+ base::TimeTicks(), &result, i,
+ std::vector<NetworkQualityObservationSource>()));
+ EXPECT_NEAR(result, 51 + 0.49 * i, 1);
+
+ EXPECT_TRUE(time_delta_buffer.GetPercentile(
+ base::TimeTicks(), &time_delta_result, i,
+ std::vector<NetworkQualityObservationSource>()));
+ EXPECT_NEAR(time_delta_result.InMilliseconds(), 51 + 0.49 * i, 1);
+ }
+
+ EXPECT_FALSE(int_buffer.GetPercentile(
+ now + base::TimeDelta::FromSeconds(1), &result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+ EXPECT_FALSE(time_delta_buffer.GetPercentile(
+ now + base::TimeDelta::FromSeconds(1), &time_delta_result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+}
+
+// Verifies that the percentiles are correctly computed when some of the
+// observation sources are disallowed. All observations have the same timestamp.
+TEST(NetworkQualityObservationBufferTest, DisallowedObservationSources) {
+ ObservationBuffer<int32_t> int_buffer(0.5);
+ ObservationBuffer<base::TimeDelta> time_delta_buffer(0.5);
+ const base::TimeTicks now = base::TimeTicks::Now();
+
+ int32_t result;
+ base::TimeDelta time_delta_result;
+
+ // Network quality should be unavailable when no observations are available.
+ EXPECT_FALSE(
+ int_buffer.GetPercentile(base::TimeTicks(), &result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+ EXPECT_FALSE(time_delta_buffer.GetPercentile(
+ base::TimeTicks(), &time_delta_result, 50,
+ std::vector<NetworkQualityObservationSource>()));
+
+ // Insert samples from {1,2,3,..., 100}. First insert odd samples, then even
+ // samples. This helps in verifying that the order of samples does not matter.
+ for (int i = 1; i <= 99; i += 2) {
+ int_buffer.AddObservation(Observation<int32_t>(
+ i, now, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+ time_delta_buffer.AddObservation(Observation<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(i), now,
+ NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+ }
+
+ // Add samples for TCP and QUIC observations which should not be taken into
+ // account when computing the percentile.
+ for (int i = 1; i <= 99; i += 2) {
+ int_buffer.AddObservation(Observation<int32_t>(
+ 10000, now, NETWORK_QUALITY_OBSERVATION_SOURCE_TCP));
+ int_buffer.AddObservation(Observation<int32_t>(
+ 10000, now, NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC));
+ time_delta_buffer.AddObservation(Observation<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(10000), now,
+ NETWORK_QUALITY_OBSERVATION_SOURCE_TCP));
+ time_delta_buffer.AddObservation(Observation<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(10000), now,
+ NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC));
+ }
+
+ for (int i = 2; i <= 100; i += 2) {
+ int_buffer.AddObservation(Observation<int32_t>(
+ i, now, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+ time_delta_buffer.AddObservation(Observation<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(i), now,
+ NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+ }
+
+ std::vector<NetworkQualityObservationSource> disallowed_observation_sources;
+ disallowed_observation_sources.push_back(
+ NETWORK_QUALITY_OBSERVATION_SOURCE_TCP);
+ disallowed_observation_sources.push_back(
+ NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC);
+
+ for (int i = 0; i <= 100; ++i) {
+ // Checks if the difference between the two integers is less than 1. This is
+ // required because computed percentiles may be slightly different from
+ // what is expected due to floating point computation errors and integer
+ // rounding off errors.
+ EXPECT_TRUE(int_buffer.GetPercentile(base::TimeTicks(), &result, i,
+ disallowed_observation_sources));
+ EXPECT_NEAR(result, i, 1);
+ EXPECT_TRUE(
+ time_delta_buffer.GetPercentile(base::TimeTicks(), &time_delta_result,
+ i, disallowed_observation_sources));
+ EXPECT_NEAR(time_delta_result.InMilliseconds(), i, 1);
+ }
+
+ // Now check the percentile value for TCP and QUIC observations.
+ disallowed_observation_sources.clear();
+ disallowed_observation_sources.push_back(
+ NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST);
+ for (int i = 0; i <= 100; ++i) {
+ // Checks if the difference between the two integers is less than 1. This is
+ // required because computed percentiles may be slightly different from
+ // what is expected due to floating point computation errors and integer
+ // rounding off errors.
+ EXPECT_TRUE(int_buffer.GetPercentile(base::TimeTicks(), &result, i,
+ disallowed_observation_sources));
+ EXPECT_NEAR(result, 10000, 1);
+ EXPECT_TRUE(
+ time_delta_buffer.GetPercentile(base::TimeTicks(), &time_delta_result,
+ i, disallowed_observation_sources));
+ EXPECT_NEAR(time_delta_result.InMilliseconds(), 10000, 1);
+ }
+}
+
+TEST(NetworkQualityObservationBufferTest, TestGetMedianRTTSince) {
+ ObservationBuffer<int32_t> int_buffer(0.5);
+ ObservationBuffer<base::TimeDelta> time_delta_buffer(0.5);
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::TimeTicks old = now - base::TimeDelta::FromMilliseconds(1);
+ ASSERT_NE(old, now);
+
+ // First sample has very old timestamp.
+ int_buffer.AddObservation(Observation<int32_t>(
+ 1, old, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+ time_delta_buffer.AddObservation(Observation<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(1), old,
+ NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+
+ int_buffer.AddObservation(Observation<int32_t>(
+ 100, now, NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+ time_delta_buffer.AddObservation(Observation<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(100), now,
+ NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST));
+
+ const struct {
+ base::TimeTicks start_timestamp;
+ bool expect_network_quality_available;
+ base::TimeDelta expected_url_request_rtt;
+ int32_t expected_downstream_throughput;
+ } tests[] = {
+ {now + base::TimeDelta::FromSeconds(10), false,
+ base::TimeDelta::FromMilliseconds(0), 0},
+ {now, true, base::TimeDelta::FromMilliseconds(100), 100},
+ {now - base::TimeDelta::FromMicroseconds(500), true,
+ base::TimeDelta::FromMilliseconds(100), 100},
+
+ };
+
+ for (const auto& test : tests) {
+ base::TimeDelta url_request_rtt;
+ int32_t downstream_throughput_kbps;
+ std::vector<NetworkQualityObservationSource> disallowed_observation_sources;
+
+ EXPECT_EQ(
+ test.expect_network_quality_available,
+ time_delta_buffer.GetPercentile(test.start_timestamp, &url_request_rtt,
+ 50, disallowed_observation_sources));
+ EXPECT_EQ(test.expect_network_quality_available,
+ int_buffer.GetPercentile(test.start_timestamp,
+ &downstream_throughput_kbps, 50,
+ disallowed_observation_sources));
+
+ if (test.expect_network_quality_available) {
+ EXPECT_EQ(test.expected_url_request_rtt, url_request_rtt);
+ EXPECT_EQ(test.expected_downstream_throughput,
+ downstream_throughput_kbps);
+ }
+ }
+}
+
+} // namespace
+
+} // namespace internal
+
+} // namespace nqe
+
+} // namespace net \ No newline at end of file
diff --git a/chromium/net/nqe/throughput_analyzer_unittest.cc b/chromium/net/nqe/throughput_analyzer_unittest.cc
index a65055cf541..4e5eb762b17 100644
--- a/chromium/net/nqe/throughput_analyzer_unittest.cc
+++ b/chromium/net/nqe/throughput_analyzer_unittest.cc
@@ -237,4 +237,4 @@ TEST(ThroughputAnalyzerTest, TestThroughputWithNetworkRequestsOverlap) {
} // namespace nqe
-} // namespace net \ No newline at end of file
+} // namespace net
diff --git a/chromium/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc b/chromium/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc
index b114eb59deb..dee94a4c556 100644
--- a/chromium/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc
+++ b/chromium/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc
@@ -15,9 +15,14 @@
#include "net/proxy/mock_proxy_script_fetcher.h"
#include "net/proxy/proxy_script_fetcher_impl.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/gtest_util.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -139,12 +144,13 @@ class FetcherClient {
FetcherClient()
: url_request_context_(new TestURLRequestContext()),
worker_pool_(
- new base::SequencedWorkerPool(4, "DhcpAdapterFetcherTest")),
+ new base::SequencedWorkerPool(4,
+ "DhcpAdapterFetcherTest",
+ base::TaskPriority::USER_VISIBLE)),
fetcher_(new MockDhcpProxyScriptAdapterFetcher(
url_request_context_.get(),
worker_pool_->GetTaskRunnerWithShutdownBehavior(
- base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN))) {
- }
+ base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN))) {}
~FetcherClient() {
worker_pool_->Shutdown();
@@ -176,7 +182,7 @@ TEST(DhcpProxyScriptAdapterFetcher, NormalCaseURLNotInDhcp) {
client.RunTest();
client.WaitForResult(ERR_PAC_NOT_IN_DHCP);
ASSERT_TRUE(client.fetcher_->DidFinish());
- EXPECT_EQ(ERR_PAC_NOT_IN_DHCP, client.fetcher_->GetResult());
+ EXPECT_THAT(client.fetcher_->GetResult(), IsError(ERR_PAC_NOT_IN_DHCP));
EXPECT_EQ(base::string16(L""), client.fetcher_->GetPacScript());
}
@@ -185,7 +191,7 @@ TEST(DhcpProxyScriptAdapterFetcher, NormalCaseURLInDhcp) {
client.RunTest();
client.WaitForResult(OK);
ASSERT_TRUE(client.fetcher_->DidFinish());
- EXPECT_EQ(OK, client.fetcher_->GetResult());
+ EXPECT_THAT(client.fetcher_->GetResult(), IsOk());
EXPECT_EQ(base::string16(L"bingo"), client.fetcher_->GetPacScript());
EXPECT_EQ(GURL(kPacUrl), client.fetcher_->GetPacURL());
}
@@ -208,7 +214,7 @@ TEST(DhcpProxyScriptAdapterFetcher, TimeoutDuringDhcp) {
client.WaitForResult(ERR_TIMED_OUT);
ASSERT_TRUE(client.fetcher_->DidFinish());
- EXPECT_EQ(ERR_TIMED_OUT, client.fetcher_->GetResult());
+ EXPECT_THAT(client.fetcher_->GetResult(), IsError(ERR_TIMED_OUT));
EXPECT_EQ(base::string16(L""), client.fetcher_->GetPacScript());
EXPECT_EQ(GURL(), client.fetcher_->GetPacURL());
client.FinishTestAllowCleanup();
@@ -221,7 +227,7 @@ TEST(DhcpProxyScriptAdapterFetcher, CancelWhileDhcp) {
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(client.fetcher_->DidFinish());
ASSERT_TRUE(client.fetcher_->WasCancelled());
- EXPECT_EQ(ERR_ABORTED, client.fetcher_->GetResult());
+ EXPECT_THAT(client.fetcher_->GetResult(), IsError(ERR_ABORTED));
EXPECT_EQ(base::string16(L""), client.fetcher_->GetPacScript());
EXPECT_EQ(GURL(), client.fetcher_->GetPacURL());
client.FinishTestAllowCleanup();
@@ -242,7 +248,7 @@ TEST(DhcpProxyScriptAdapterFetcher, CancelWhileFetcher) {
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(client.fetcher_->DidFinish());
ASSERT_TRUE(client.fetcher_->WasCancelled());
- EXPECT_EQ(ERR_ABORTED, client.fetcher_->GetResult());
+ EXPECT_THAT(client.fetcher_->GetResult(), IsError(ERR_ABORTED));
EXPECT_EQ(base::string16(L""), client.fetcher_->GetPacScript());
// GetPacURL() still returns the URL fetched in this case.
EXPECT_EQ(GURL(kPacUrl), client.fetcher_->GetPacURL());
@@ -257,7 +263,7 @@ TEST(DhcpProxyScriptAdapterFetcher, CancelAtCompletion) {
// Canceling after you're done should have no effect, so these
// are identical expectations to the NormalCaseURLInDhcp test.
ASSERT_TRUE(client.fetcher_->DidFinish());
- EXPECT_EQ(OK, client.fetcher_->GetResult());
+ EXPECT_THAT(client.fetcher_->GetResult(), IsOk());
EXPECT_EQ(base::string16(L"bingo"), client.fetcher_->GetPacScript());
EXPECT_EQ(GURL(kPacUrl), client.fetcher_->GetPacURL());
client.FinishTestAllowCleanup();
@@ -304,7 +310,7 @@ TEST(DhcpProxyScriptAdapterFetcher, MockDhcpRealFetch) {
client.RunTest();
client.WaitForResult(OK);
ASSERT_TRUE(client.fetcher_->DidFinish());
- EXPECT_EQ(OK, client.fetcher_->GetResult());
+ EXPECT_THAT(client.fetcher_->GetResult(), IsOk());
EXPECT_EQ(base::string16(L"-downloadable.pac-\n"),
client.fetcher_->GetPacScript());
EXPECT_EQ(configured_url,
diff --git a/chromium/net/proxy/dhcp_proxy_script_fetcher_factory.cc b/chromium/net/proxy/dhcp_proxy_script_fetcher_factory.cc
index f663d79d3ea..1ebe225b455 100644
--- a/chromium/net/proxy/dhcp_proxy_script_fetcher_factory.cc
+++ b/chromium/net/proxy/dhcp_proxy_script_fetcher_factory.cc
@@ -22,7 +22,7 @@ DhcpProxyScriptFetcherFactory::DhcpProxyScriptFetcherFactory()
std::unique_ptr<DhcpProxyScriptFetcher> DhcpProxyScriptFetcherFactory::Create(
URLRequestContext* context) {
if (!feature_enabled_) {
- return base::WrapUnique(new DoNothingDhcpProxyScriptFetcher());
+ return base::MakeUnique<DoNothingDhcpProxyScriptFetcher>();
} else {
DCHECK(IsSupported());
std::unique_ptr<DhcpProxyScriptFetcher> ret;
diff --git a/chromium/net/proxy/dhcp_proxy_script_fetcher_win.cc b/chromium/net/proxy/dhcp_proxy_script_fetcher_win.cc
index 87006114929..1a28eea5dbf 100644
--- a/chromium/net/proxy/dhcp_proxy_script_fetcher_win.cc
+++ b/chromium/net/proxy/dhcp_proxy_script_fetcher_win.cc
@@ -58,8 +58,8 @@ DhcpProxyScriptFetcherWin::DhcpProxyScriptFetcherWin(
url_request_context_(url_request_context) {
DCHECK(url_request_context_);
- worker_pool_ = new base::SequencedWorkerPool(kMaxDhcpLookupThreads,
- "PacDhcpLookup");
+ worker_pool_ = new base::SequencedWorkerPool(
+ kMaxDhcpLookupThreads, "PacDhcpLookup", base::TaskPriority::USER_VISIBLE);
}
DhcpProxyScriptFetcherWin::~DhcpProxyScriptFetcherWin() {
diff --git a/chromium/net/proxy/dhcp_proxy_script_fetcher_win.h b/chromium/net/proxy/dhcp_proxy_script_fetcher_win.h
index 1bca0635036..bb9d8dc259a 100644
--- a/chromium/net/proxy/dhcp_proxy_script_fetcher_win.h
+++ b/chromium/net/proxy/dhcp_proxy_script_fetcher_win.h
@@ -15,6 +15,7 @@
#include "base/threading/non_thread_safe.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
+#include "net/base/net_export.h"
#include "net/proxy/dhcp_proxy_script_fetcher.h"
namespace base {
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 40bc928647b..3c5c4f0584f 100644
--- a/chromium/net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc
+++ b/chromium/net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc
@@ -15,9 +15,14 @@
#include "base/timer/elapsed_timer.h"
#include "net/base/completion_callback.h"
#include "net/proxy/dhcp_proxy_script_adapter_fetcher_win.h"
+#include "net/test/gtest_util.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -384,7 +389,7 @@ class FetcherClient {
int result = fetcher_.Fetch(
&pac_text_,
base::Bind(&FetcherClient::OnCompletion, base::Unretained(this)));
- ASSERT_EQ(ERR_IO_PENDING, result);
+ ASSERT_THAT(result, IsError(ERR_IO_PENDING));
}
void RunMessageLoopUntilComplete() {
@@ -436,7 +441,7 @@ void TestNormalCaseURLConfiguredOneAdapter(FetcherClient* client) {
client->fetcher_.PushBackAdapter("a", adapter_fetcher.release());
client->RunTest();
client->RunMessageLoopUntilComplete();
- ASSERT_EQ(OK, client->result_);
+ ASSERT_THAT(client->result_, IsOk());
ASSERT_EQ(L"bingo", client->pac_text_);
}
@@ -455,7 +460,7 @@ void TestNormalCaseURLConfiguredMultipleAdapters(FetcherClient* client) {
"third", true, OK, L"rocko", base::TimeDelta::FromMilliseconds(1));
client->RunTest();
client->RunMessageLoopUntilComplete();
- ASSERT_EQ(OK, client->result_);
+ ASSERT_THAT(client->result_, IsOk());
ASSERT_EQ(L"bingo", client->pac_text_);
}
@@ -477,7 +482,7 @@ void TestNormalCaseURLConfiguredMultipleAdaptersWithTimeout(
"third", true, OK, L"rocko", base::TimeDelta::FromMilliseconds(1));
client->RunTest();
client->RunMessageLoopUntilComplete();
- ASSERT_EQ(OK, client->result_);
+ ASSERT_THAT(client->result_, IsOk());
ASSERT_EQ(L"rocko", client->pac_text_);
}
@@ -506,7 +511,7 @@ void TestFailureCaseURLConfiguredMultipleAdaptersWithTimeout(
base::TimeDelta::FromMilliseconds(1));
client->RunTest();
client->RunMessageLoopUntilComplete();
- ASSERT_EQ(ERR_PAC_STATUS_NOT_OK, client->result_);
+ ASSERT_THAT(client->result_, IsError(ERR_PAC_STATUS_NOT_OK));
ASSERT_EQ(L"", client->pac_text_);
}
@@ -531,7 +536,7 @@ void TestFailureCaseNoURLConfigured(FetcherClient* client) {
base::TimeDelta::FromMilliseconds(1));
client->RunTest();
client->RunMessageLoopUntilComplete();
- ASSERT_EQ(ERR_PAC_NOT_IN_DHCP, client->result_);
+ ASSERT_THAT(client->result_, IsError(ERR_PAC_NOT_IN_DHCP));
ASSERT_EQ(L"", client->pac_text_);
}
@@ -543,7 +548,7 @@ TEST(DhcpProxyScriptFetcherWin, FailureCaseNoURLConfigured) {
void TestFailureCaseNoDhcpAdapters(FetcherClient* client) {
client->RunTest();
client->RunMessageLoopUntilComplete();
- ASSERT_EQ(ERR_PAC_NOT_IN_DHCP, client->result_);
+ ASSERT_THAT(client->result_, IsError(ERR_PAC_NOT_IN_DHCP));
ASSERT_EQ(L"", client->pac_text_);
ASSERT_EQ(0, client->fetcher_.num_fetchers_created_);
}
diff --git a/chromium/net/proxy/dhcpcsvc_init_win.cc b/chromium/net/proxy/dhcpcsvc_init_win.cc
index 7e32aeae9cd..d243f1859aa 100644
--- a/chromium/net/proxy/dhcpcsvc_init_win.cc
+++ b/chromium/net/proxy/dhcpcsvc_init_win.cc
@@ -19,15 +19,12 @@ class DhcpcsvcInitSingleton {
DWORD err = DhcpCApiInitialize(&version);
DCHECK(err == ERROR_SUCCESS); // DCHECK_EQ complains of unsigned mismatch.
}
-
- ~DhcpcsvcInitSingleton() {
- // Worker pool threads that use the DHCP API may still be running, so skip
- // cleanup.
- }
};
-static base::LazyInstance<DhcpcsvcInitSingleton> g_dhcpcsvc_init_singleton =
- LAZY_INSTANCE_INITIALIZER;
+// Worker pool threads that use the DHCP API may still be running at shutdown.
+// Leak instance and skip cleanup.
+static base::LazyInstance<DhcpcsvcInitSingleton>::Leaky
+ g_dhcpcsvc_init_singleton = LAZY_INSTANCE_INITIALIZER;
} // namespace
diff --git a/chromium/net/proxy/in_process_mojo_proxy_resolver_factory.cc b/chromium/net/proxy/in_process_mojo_proxy_resolver_factory.cc
index ff9dd852247..2f04b241d07 100644
--- a/chromium/net/proxy/in_process_mojo_proxy_resolver_factory.cc
+++ b/chromium/net/proxy/in_process_mojo_proxy_resolver_factory.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/memory/singleton.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
#include "net/proxy/mojo_proxy_resolver_factory_impl.h"
namespace net {
@@ -18,10 +19,8 @@ InProcessMojoProxyResolverFactory::GetInstance() {
}
InProcessMojoProxyResolverFactory::InProcessMojoProxyResolverFactory() {
- // Implementation lifetime is strongly bound to the life of the connection via
- // |factory_|. When |factory_| is destroyed, the Mojo connection is terminated
- // which causes this object to be destroyed.
- new MojoProxyResolverFactoryImpl(mojo::GetProxy(&factory_));
+ mojo::MakeStrongBinding(base::MakeUnique<MojoProxyResolverFactoryImpl>(),
+ mojo::GetProxy(&factory_));
}
InProcessMojoProxyResolverFactory::~InProcessMojoProxyResolverFactory() =
diff --git a/chromium/net/proxy/mock_proxy_resolver.cc b/chromium/net/proxy/mock_proxy_resolver.cc
index bdeee461f5c..eace850c17e 100644
--- a/chromium/net/proxy/mock_proxy_resolver.cc
+++ b/chromium/net/proxy/mock_proxy_resolver.cc
@@ -30,11 +30,12 @@ MockAsyncProxyResolver::Request::~Request() {}
MockAsyncProxyResolver::~MockAsyncProxyResolver() {}
-int MockAsyncProxyResolver::GetProxyForURL(const GURL& url,
- ProxyInfo* results,
- const CompletionCallback& callback,
- RequestHandle* request_handle,
- const BoundNetLog& /*net_log*/) {
+int MockAsyncProxyResolver::GetProxyForURL(
+ const GURL& url,
+ ProxyInfo* results,
+ const CompletionCallback& callback,
+ RequestHandle* request_handle,
+ const NetLogWithSource& /*net_log*/) {
scoped_refptr<Request> request = new Request(this, url, results, callback);
pending_requests_.push_back(request);
@@ -95,7 +96,7 @@ void MockAsyncProxyResolverFactory::Request::CompleteNowWithForwarder(
int rv,
ProxyResolver* resolver) {
DCHECK(resolver);
- CompleteNow(rv, base::WrapUnique(new ForwardingProxyResolver(resolver)));
+ CompleteNow(rv, base::MakeUnique<ForwardingProxyResolver>(resolver));
}
void MockAsyncProxyResolverFactory::Request::FactoryDestroyed() {
@@ -160,7 +161,7 @@ int ForwardingProxyResolver::GetProxyForURL(const GURL& query_url,
ProxyInfo* results,
const CompletionCallback& callback,
RequestHandle* request,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
return impl_->GetProxyForURL(query_url, results, callback, request, net_log);
}
diff --git a/chromium/net/proxy/mock_proxy_resolver.h b/chromium/net/proxy/mock_proxy_resolver.h
index fceaa102f4b..f705abd6195 100644
--- a/chromium/net/proxy/mock_proxy_resolver.h
+++ b/chromium/net/proxy/mock_proxy_resolver.h
@@ -54,7 +54,7 @@ class MockAsyncProxyResolver : public ProxyResolver {
ProxyInfo* results,
const CompletionCallback& callback,
RequestHandle* request_handle,
- const BoundNetLog& /*net_log*/) override;
+ const NetLogWithSource& /*net_log*/) override;
void CancelRequest(RequestHandle request_handle) override;
LoadState GetLoadState(RequestHandle request_handle) const override;
const RequestsList& pending_requests() const {
@@ -147,7 +147,7 @@ class ForwardingProxyResolver : public ProxyResolver {
ProxyInfo* results,
const CompletionCallback& callback,
RequestHandle* request,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void CancelRequest(RequestHandle request) override;
LoadState GetLoadState(RequestHandle request) const override;
diff --git a/chromium/net/proxy/mojo_proxy_resolver_factory_impl.cc b/chromium/net/proxy/mojo_proxy_resolver_factory_impl.cc
index 65b6a482531..89af70d138b 100644
--- a/chromium/net/proxy/mojo_proxy_resolver_factory_impl.cc
+++ b/chromium/net/proxy/mojo_proxy_resolver_factory_impl.cc
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
#include "net/base/net_errors.h"
#include "net/proxy/mojo_proxy_resolver_impl.h"
#include "net/proxy/mojo_proxy_resolver_v8_tracing_bindings.h"
@@ -17,40 +17,6 @@
#include "net/proxy/proxy_resolver_v8_tracing.h"
namespace net {
-namespace {
-
-// A class to manage the lifetime of a MojoProxyResolverImpl. An instance will
-// remain while the message pipe for the mojo connection remains open.
-class MojoProxyResolverHolder {
- public:
- MojoProxyResolverHolder(
- std::unique_ptr<ProxyResolverV8Tracing> proxy_resolver_impl,
- mojo::InterfaceRequest<interfaces::ProxyResolver> request);
-
- private:
- // Mojo error handler.
- void OnConnectionError();
-
- MojoProxyResolverImpl mojo_proxy_resolver_;
- mojo::Binding<interfaces::ProxyResolver> binding_;
-
- DISALLOW_COPY_AND_ASSIGN(MojoProxyResolverHolder);
-};
-
-MojoProxyResolverHolder::MojoProxyResolverHolder(
- std::unique_ptr<ProxyResolverV8Tracing> proxy_resolver_impl,
- mojo::InterfaceRequest<interfaces::ProxyResolver> request)
- : mojo_proxy_resolver_(std::move(proxy_resolver_impl)),
- binding_(&mojo_proxy_resolver_, std::move(request)) {
- binding_.set_connection_error_handler(base::Bind(
- &MojoProxyResolverHolder::OnConnectionError, base::Unretained(this)));
-}
-
-void MojoProxyResolverHolder::OnConnectionError() {
- delete this;
-}
-
-} // namespace
class MojoProxyResolverFactoryImpl::Job {
public:
@@ -92,9 +58,8 @@ MojoProxyResolverFactoryImpl::Job::Job(
base::Unretained(this)));
factory_->CreateProxyResolverV8Tracing(
pac_script,
- base::WrapUnique(new MojoProxyResolverV8TracingBindings<
- interfaces::ProxyResolverFactoryRequestClient>(
- client_ptr_.get())),
+ base::MakeUnique<MojoProxyResolverV8TracingBindings<
+ interfaces::ProxyResolverFactoryRequestClient>>(client_ptr_.get()),
&proxy_resolver_impl_,
base::Bind(&MojoProxyResolverFactoryImpl::Job::OnProxyResolverCreated,
base::Unretained(this)),
@@ -110,28 +75,22 @@ void MojoProxyResolverFactoryImpl::Job::OnConnectionError() {
void MojoProxyResolverFactoryImpl::Job::OnProxyResolverCreated(int error) {
if (error == OK) {
- // The MojoProxyResolverHolder will delete itself if |proxy_request_|
- // encounters a connection error.
- new MojoProxyResolverHolder(std::move(proxy_resolver_impl_),
- std::move(proxy_request_));
+ mojo::MakeStrongBinding(base::MakeUnique<MojoProxyResolverImpl>(
+ std::move(proxy_resolver_impl_)),
+ std::move(proxy_request_));
}
client_ptr_->ReportResult(error);
parent_->RemoveJob(this);
}
MojoProxyResolverFactoryImpl::MojoProxyResolverFactoryImpl(
- std::unique_ptr<ProxyResolverV8TracingFactory> proxy_resolver_factory,
- mojo::InterfaceRequest<interfaces::ProxyResolverFactory> request)
- : proxy_resolver_impl_factory_(std::move(proxy_resolver_factory)),
- binding_(this, std::move(request)) {}
+ std::unique_ptr<ProxyResolverV8TracingFactory> proxy_resolver_factory)
+ : proxy_resolver_impl_factory_(std::move(proxy_resolver_factory)) {}
-MojoProxyResolverFactoryImpl::MojoProxyResolverFactoryImpl(
- mojo::InterfaceRequest<interfaces::ProxyResolverFactory> request)
- : MojoProxyResolverFactoryImpl(ProxyResolverV8TracingFactory::Create(),
- std::move(request)) {}
+MojoProxyResolverFactoryImpl::MojoProxyResolverFactoryImpl()
+ : MojoProxyResolverFactoryImpl(ProxyResolverV8TracingFactory::Create()) {}
MojoProxyResolverFactoryImpl::~MojoProxyResolverFactoryImpl() {
- STLDeleteElements(&jobs_);
}
void MojoProxyResolverFactoryImpl::CreateResolver(
@@ -140,16 +99,18 @@ void MojoProxyResolverFactoryImpl::CreateResolver(
interfaces::ProxyResolverFactoryRequestClientPtr client) {
// The Job will call RemoveJob on |this| when either the create request
// finishes or |request| or |client| encounters a connection error.
- jobs_.insert(new Job(
+ std::unique_ptr<Job> job = base::MakeUnique<Job>(
this, ProxyResolverScriptData::FromUTF8(pac_script.To<std::string>()),
proxy_resolver_impl_factory_.get(), std::move(request),
- std::move(client)));
+ std::move(client));
+ Job* job_ptr = job.get();
+ jobs_[job_ptr] = std::move(job);
}
void MojoProxyResolverFactoryImpl::RemoveJob(Job* job) {
- size_t erased = jobs_.erase(job);
- DCHECK_EQ(1u, erased);
- delete job;
+ auto it = jobs_.find(job);
+ DCHECK(it != jobs_.end());
+ jobs_.erase(it);
}
} // namespace net
diff --git a/chromium/net/proxy/mojo_proxy_resolver_factory_impl.h b/chromium/net/proxy/mojo_proxy_resolver_factory_impl.h
index e305e47fd4a..aecebac1221 100644
--- a/chromium/net/proxy/mojo_proxy_resolver_factory_impl.h
+++ b/chromium/net/proxy/mojo_proxy_resolver_factory_impl.h
@@ -5,11 +5,10 @@
#ifndef NET_PROXY_MOJO_PROXY_RESOLVER_FACTORY_IMPL_H_
#define NET_PROXY_MOJO_PROXY_RESOLVER_FACTORY_IMPL_H_
-#include <set>
+#include <map>
#include "base/callback.h"
#include "base/macros.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
#include "net/interfaces/proxy_resolver_service.mojom.h"
namespace net {
@@ -19,11 +18,9 @@ class ProxyResolverV8TracingFactory;
class MojoProxyResolverFactoryImpl : public interfaces::ProxyResolverFactory {
public:
+ MojoProxyResolverFactoryImpl();
explicit MojoProxyResolverFactoryImpl(
- mojo::InterfaceRequest<interfaces::ProxyResolverFactory> request);
- MojoProxyResolverFactoryImpl(
- std::unique_ptr<ProxyResolverV8TracingFactory> proxy_resolver_factory,
- mojo::InterfaceRequest<interfaces::ProxyResolverFactory> request);
+ std::unique_ptr<ProxyResolverV8TracingFactory> proxy_resolver_factory);
~MojoProxyResolverFactoryImpl() override;
@@ -33,16 +30,15 @@ class MojoProxyResolverFactoryImpl : public interfaces::ProxyResolverFactory {
// interfaces::ProxyResolverFactory override.
void CreateResolver(
const mojo::String& pac_script,
- mojo::InterfaceRequest<interfaces::ProxyResolver> request,
+ interfaces::ProxyResolverRequest request,
interfaces::ProxyResolverFactoryRequestClientPtr client) override;
void RemoveJob(Job* job);
const std::unique_ptr<ProxyResolverV8TracingFactory>
proxy_resolver_impl_factory_;
- mojo::StrongBinding<interfaces::ProxyResolverFactory> binding_;
- std::set<Job*> jobs_;
+ std::map<Job*, std::unique_ptr<Job>> jobs_;
DISALLOW_COPY_AND_ASSIGN(MojoProxyResolverFactoryImpl);
};
diff --git a/chromium/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc b/chromium/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc
index a3c6216d907..2d95eec2910 100644
--- a/chromium/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc
+++ b/chromium/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc
@@ -9,12 +9,18 @@
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
#include "net/base/test_completion_callback.h"
#include "net/proxy/mock_proxy_resolver.h"
#include "net/proxy/proxy_resolver_v8_tracing.h"
#include "net/test/event_waiter.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -99,8 +105,9 @@ class MojoProxyResolverFactoryImplTest
public:
void SetUp() override {
mock_factory_ = new TestProxyResolverFactory(&waiter_);
- new MojoProxyResolverFactoryImpl(base::WrapUnique(mock_factory_),
- mojo::GetProxy(&factory_));
+ mojo::MakeStrongBinding(base::MakeUnique<MojoProxyResolverFactoryImpl>(
+ base::WrapUnique(mock_factory_)),
+ mojo::GetProxy(&factory_));
}
void OnConnectionError() { waiter_.NotifyEvent(CONNECTION_ERROR); }
@@ -152,7 +159,7 @@ TEST_F(MojoProxyResolverFactoryImplTest, DisconnectProxyResolverClient) {
&MojoProxyResolverFactoryImplTest::OnFakeProxyInstanceDestroyed,
base::Unretained(this))));
mock_factory_->pending_request()->callback.Run(OK);
- EXPECT_EQ(OK, create_callback.WaitForResult());
+ EXPECT_THAT(create_callback.WaitForResult(), IsOk());
proxy_resolver.reset();
waiter_.WaitForEvent(RESOLVER_DESTROYED);
EXPECT_EQ(1, instances_destroyed_);
@@ -176,7 +183,7 @@ TEST_F(MojoProxyResolverFactoryImplTest, Error) {
create_callback_ = create_callback.callback();
ASSERT_TRUE(mock_factory_->pending_request());
mock_factory_->pending_request()->callback.Run(ERR_PAC_SCRIPT_FAILED);
- EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, create_callback.WaitForResult());
+ EXPECT_THAT(create_callback.WaitForResult(), IsError(ERR_PAC_SCRIPT_FAILED));
}
TEST_F(MojoProxyResolverFactoryImplTest,
diff --git a/chromium/net/proxy/mojo_proxy_resolver_impl.cc b/chromium/net/proxy/mojo_proxy_resolver_impl.cc
index e72008b57f7..8e782db0208 100644
--- a/chromium/net/proxy/mojo_proxy_resolver_impl.cc
+++ b/chromium/net/proxy/mojo_proxy_resolver_impl.cc
@@ -8,9 +8,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
#include "net/base/net_errors.h"
-#include "net/log/net_log.h"
#include "net/proxy/mojo_proxy_resolver_v8_tracing_bindings.h"
#include "net/proxy/mojo_proxy_type_converters.h"
#include "net/proxy/proxy_info.h"
@@ -51,23 +49,23 @@ MojoProxyResolverImpl::MojoProxyResolverImpl(
: resolver_(std::move(resolver)) {}
MojoProxyResolverImpl::~MojoProxyResolverImpl() {
- STLDeleteElements(&resolve_jobs_);
}
void MojoProxyResolverImpl::GetProxyForUrl(
const GURL& url,
interfaces::ProxyResolverRequestClientPtr client) {
DVLOG(1) << "GetProxyForUrl(" << url << ")";
- Job* job = new Job(std::move(client), this, url);
- bool inserted = resolve_jobs_.insert(job).second;
- DCHECK(inserted);
- job->Start();
+ std::unique_ptr<Job> job =
+ base::MakeUnique<Job>(std::move(client), this, url);
+ Job* job_ptr = job.get();
+ resolve_jobs_[job_ptr] = std::move(job);
+ job_ptr->Start();
}
void MojoProxyResolverImpl::DeleteJob(Job* job) {
- size_t num_erased = resolve_jobs_.erase(job);
- DCHECK(num_erased);
- delete job;
+ auto it = resolve_jobs_.find(job);
+ DCHECK(it != resolve_jobs_.end());
+ resolve_jobs_.erase(it);
}
MojoProxyResolverImpl::Job::Job(
@@ -89,8 +87,8 @@ void MojoProxyResolverImpl::Job::Start() {
resolver_->resolver_->GetProxyForURL(
url_, &result_, base::Bind(&Job::GetProxyDone, base::Unretained(this)),
&request_handle_,
- base::WrapUnique(new MojoProxyResolverV8TracingBindings<
- interfaces::ProxyResolverRequestClient>(client_.get())));
+ base::MakeUnique<MojoProxyResolverV8TracingBindings<
+ interfaces::ProxyResolverRequestClient>>(client_.get()));
client_.set_connection_error_handler(base::Bind(
&MojoProxyResolverImpl::Job::OnConnectionError, base::Unretained(this)));
}
diff --git a/chromium/net/proxy/mojo_proxy_resolver_impl.h b/chromium/net/proxy/mojo_proxy_resolver_impl.h
index 9295c499c0c..7951b4ab87d 100644
--- a/chromium/net/proxy/mojo_proxy_resolver_impl.h
+++ b/chromium/net/proxy/mojo_proxy_resolver_impl.h
@@ -8,7 +8,6 @@
#include <map>
#include <memory>
#include <queue>
-#include <set>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
@@ -36,7 +35,7 @@ class MojoProxyResolverImpl : public interfaces::ProxyResolver {
void DeleteJob(Job* job);
std::unique_ptr<ProxyResolverV8Tracing> resolver_;
- std::set<Job*> resolve_jobs_;
+ std::map<Job*, std::unique_ptr<Job>> resolve_jobs_;
DISALLOW_COPY_AND_ASSIGN(MojoProxyResolverImpl);
};
diff --git a/chromium/net/proxy/mojo_proxy_resolver_impl_unittest.cc b/chromium/net/proxy/mojo_proxy_resolver_impl_unittest.cc
index e6484449624..277374bea43 100644
--- a/chromium/net/proxy/mojo_proxy_resolver_impl_unittest.cc
+++ b/chromium/net/proxy/mojo_proxy_resolver_impl_unittest.cc
@@ -17,8 +17,13 @@
#include "net/proxy/proxy_resolver_v8_tracing.h"
#include "net/proxy/proxy_server.h"
#include "net/test/event_waiter.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -208,7 +213,7 @@ TEST_F(MojoProxyResolverImplTest, GetProxyForUrl) {
request.callback.Run(OK);
client.WaitForResult();
- EXPECT_EQ(OK, client.error());
+ EXPECT_THAT(client.error(), IsOk());
std::vector<ProxyServer> servers =
client.results().To<std::vector<ProxyServer>>();
ASSERT_EQ(6u, servers.size());
@@ -247,7 +252,7 @@ TEST_F(MojoProxyResolverImplTest, GetProxyForUrlFailure) {
request.callback.Run(ERR_FAILED);
client.WaitForResult();
- EXPECT_EQ(ERR_FAILED, client.error());
+ EXPECT_THAT(client.error(), IsError(ERR_FAILED));
std::vector<ProxyServer> proxy_servers =
client.results().To<std::vector<ProxyServer>>();
EXPECT_TRUE(proxy_servers.empty());
@@ -276,7 +281,7 @@ TEST_F(MojoProxyResolverImplTest, GetProxyForUrlMultiple) {
client1.WaitForResult();
client2.WaitForResult();
- EXPECT_EQ(OK, client1.error());
+ EXPECT_THAT(client1.error(), IsOk());
std::vector<ProxyServer> proxy_servers1 =
client1.results().To<std::vector<ProxyServer>>();
ASSERT_EQ(1u, proxy_servers1.size());
@@ -285,7 +290,7 @@ TEST_F(MojoProxyResolverImplTest, GetProxyForUrlMultiple) {
EXPECT_EQ("proxy.example.com", server1.host_port_pair().host());
EXPECT_EQ(12345, server1.host_port_pair().port());
- EXPECT_EQ(OK, client2.error());
+ EXPECT_THAT(client2.error(), IsOk());
std::vector<ProxyServer> proxy_servers2 =
client2.results().To<std::vector<ProxyServer>>();
ASSERT_EQ(1u, proxy_servers1.size());
diff --git a/chromium/net/proxy/mojo_proxy_resolver_v8_tracing_bindings.h b/chromium/net/proxy/mojo_proxy_resolver_v8_tracing_bindings.h
index e4b84bdae3a..d09644786a4 100644
--- a/chromium/net/proxy/mojo_proxy_resolver_v8_tracing_bindings.h
+++ b/chromium/net/proxy/mojo_proxy_resolver_v8_tracing_bindings.h
@@ -11,6 +11,7 @@
#include "mojo/common/common_type_converters.h"
#include "net/dns/host_resolver_mojo.h"
#include "net/interfaces/proxy_resolver_service.mojom.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_resolver_v8_tracing.h"
namespace net {
@@ -18,7 +19,8 @@ namespace net {
// An implementation of ProxyResolverV8Tracing::Bindings that forwards requests
// onto a Client mojo interface. Alert() and OnError() may be called from any
// thread; when they are called from another thread, the calls are proxied to
-// the origin task runner. GetHostResolver() and GetBoundNetLog() may only be
+// the origin task runner. GetHostResolver() and GetNetLogWithSource() may only
+// be
// called from the origin task runner.
template <typename Client>
class MojoProxyResolverV8TracingBindings
@@ -46,9 +48,9 @@ class MojoProxyResolverV8TracingBindings
return &host_resolver_;
}
- BoundNetLog GetBoundNetLog() override {
+ NetLogWithSource GetNetLogWithSource() override {
DCHECK(thread_checker_.CalledOnValidThread());
- return BoundNetLog();
+ return NetLogWithSource();
}
private:
diff --git a/chromium/net/proxy/mojo_proxy_resolver_v8_tracing_bindings_unittest.cc b/chromium/net/proxy/mojo_proxy_resolver_v8_tracing_bindings_unittest.cc
index 47d12486475..b743d3e0ce1 100644
--- a/chromium/net/proxy/mojo_proxy_resolver_v8_tracing_bindings_unittest.cc
+++ b/chromium/net/proxy/mojo_proxy_resolver_v8_tracing_bindings_unittest.cc
@@ -51,7 +51,7 @@ TEST_F(MojoProxyResolverV8TracingBindingsTest, Basic) {
bindings_->OnError(-1, base::ASCIIToUTF16("error"));
EXPECT_TRUE(bindings_->GetHostResolver());
- EXPECT_FALSE(bindings_->GetBoundNetLog().net_log());
+ EXPECT_FALSE(bindings_->GetNetLogWithSource().net_log());
ASSERT_EQ(1u, alerts_.size());
EXPECT_EQ("alert", alerts_[0]);
diff --git a/chromium/net/proxy/multi_threaded_proxy_resolver.cc b/chromium/net/proxy/multi_threaded_proxy_resolver.cc
index 8f6ab5dab1e..70f5023ba54 100644
--- a/chromium/net/proxy/multi_threaded_proxy_resolver.cc
+++ b/chromium/net/proxy/multi_threaded_proxy_resolver.cc
@@ -21,6 +21,8 @@
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/net_errors.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_resolver.h"
@@ -118,7 +120,7 @@ class MultiThreadedProxyResolver : public ProxyResolver,
ProxyInfo* results,
const CompletionCallback& callback,
RequestHandle* request,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void CancelRequest(RequestHandle request) override;
LoadState GetLoadState(RequestHandle request) const override;
@@ -281,7 +283,7 @@ class MultiThreadedProxyResolver::GetProxyForURLJob : public Job {
GetProxyForURLJob(const GURL& url,
ProxyInfo* results,
const CompletionCallback& callback,
- const BoundNetLog& net_log)
+ const NetLogWithSource& net_log)
: Job(TYPE_GET_PROXY_FOR_URL, callback),
results_(results),
net_log_(net_log),
@@ -290,22 +292,22 @@ class MultiThreadedProxyResolver::GetProxyForURLJob : public Job {
DCHECK(!callback.is_null());
}
- BoundNetLog* net_log() { return &net_log_; }
+ NetLogWithSource* net_log() { return &net_log_; }
void WaitingForThread() override {
was_waiting_for_thread_ = true;
- net_log_.BeginEvent(NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD);
+ net_log_.BeginEvent(NetLogEventType::WAITING_FOR_PROXY_RESOLVER_THREAD);
}
void FinishedWaitingForThread() override {
DCHECK(executor());
if (was_waiting_for_thread_) {
- net_log_.EndEvent(NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD);
+ net_log_.EndEvent(NetLogEventType::WAITING_FOR_PROXY_RESOLVER_THREAD);
}
net_log_.AddEvent(
- NetLog::TYPE_SUBMITTED_TO_RESOLVER_THREAD,
+ NetLogEventType::SUBMITTED_TO_RESOLVER_THREAD,
NetLog::IntCallback("thread_number", executor()->thread_number()));
}
@@ -341,7 +343,7 @@ class MultiThreadedProxyResolver::GetProxyForURLJob : public Job {
ProxyInfo* results_;
// Can be used on either "origin" or worker thread.
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
const GURL url_;
// Usable from within DoQuery on the worker thread.
@@ -442,8 +444,11 @@ MultiThreadedProxyResolver::~MultiThreadedProxyResolver() {
}
int MultiThreadedProxyResolver::GetProxyForURL(
- const GURL& url, ProxyInfo* results, const CompletionCallback& callback,
- RequestHandle* request, const BoundNetLog& net_log) {
+ const GURL& url,
+ ProxyInfo* results,
+ const CompletionCallback& callback,
+ RequestHandle* request,
+ const NetLogWithSource& net_log) {
DCHECK(CalledOnValidThread());
DCHECK(!callback.is_null());
diff --git a/chromium/net/proxy/multi_threaded_proxy_resolver_unittest.cc b/chromium/net/proxy/multi_threaded_proxy_resolver_unittest.cc
index 6c26d6aed17..37a9347b7f8 100644
--- a/chromium/net/proxy/multi_threaded_proxy_resolver_unittest.cc
+++ b/chromium/net/proxy/multi_threaded_proxy_resolver_unittest.cc
@@ -19,16 +19,22 @@
#include "base/threading/platform_thread.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.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/proxy/mock_proxy_resolver.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_resolver_factory.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+using net::test::IsError;
+using net::test::IsOk;
+
using base::ASCIIToUTF16;
namespace net {
@@ -48,7 +54,7 @@ class MockProxyResolver : public ProxyResolver {
ProxyInfo* results,
const CompletionCallback& callback,
RequestHandle* request,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
if (!resolve_latency_.is_zero())
base::PlatformThread::Sleep(resolve_latency_);
@@ -58,7 +64,7 @@ class MockProxyResolver : public ProxyResolver {
EXPECT_TRUE(request == NULL);
// Write something into |net_log| (doesn't really have any meaning.)
- net_log.BeginEvent(NetLog::TYPE_PAC_JAVASCRIPT_ALERT);
+ net_log.BeginEvent(NetLogEventType::PAC_JAVASCRIPT_ALERT);
results->UseNamedProxy(query_url.host());
@@ -123,7 +129,7 @@ class BlockableProxyResolver : public MockProxyResolver {
ProxyInfo* results,
const CompletionCallback& callback,
RequestHandle* request,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
if (should_block_) {
blocked_.Signal();
unblocked_.Wait();
@@ -207,7 +213,7 @@ class MultiThreadedProxyResolverTest : public testing::Test {
ProxyResolverScriptData::FromUTF8("pac script bytes"), &resolver_,
ready_callback.callback(), &request);
EXPECT_TRUE(request);
- ASSERT_EQ(OK, ready_callback.WaitForResult());
+ ASSERT_THAT(ready_callback.WaitForResult(), IsOk());
// Verify that the script data reaches the synchronous resolver factory.
ASSERT_EQ(1u, factory_->script_data().size());
@@ -244,7 +250,7 @@ TEST_F(MultiThreadedProxyResolverTest, SingleThread_Basic) {
ProxyInfo results0;
rv = resolver().GetProxyForURL(GURL("http://request0"), &results0,
callback0.callback(), NULL, log0.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Wait for request 0 to finish.
rv = callback0.WaitForResult();
@@ -259,27 +265,30 @@ TEST_F(MultiThreadedProxyResolverTest, SingleThread_Basic) {
log0.GetEntries(&entries0);
ASSERT_EQ(2u, entries0.size());
- EXPECT_EQ(NetLog::TYPE_SUBMITTED_TO_RESOLVER_THREAD, entries0[0].type);
+ EXPECT_EQ(NetLogEventType::SUBMITTED_TO_RESOLVER_THREAD, entries0[0].type);
// Start 3 more requests (request1 to request3).
TestCompletionCallback callback1;
ProxyInfo results1;
- rv = resolver().GetProxyForURL(GURL("http://request1"), &results1,
- callback1.callback(), NULL, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv =
+ resolver().GetProxyForURL(GURL("http://request1"), &results1,
+ callback1.callback(), NULL, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestCompletionCallback callback2;
ProxyInfo results2;
- rv = resolver().GetProxyForURL(GURL("http://request2"), &results2,
- callback2.callback(), NULL, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv =
+ resolver().GetProxyForURL(GURL("http://request2"), &results2,
+ callback2.callback(), NULL, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestCompletionCallback callback3;
ProxyInfo results3;
- rv = resolver().GetProxyForURL(GURL("http://request3"), &results3,
- callback3.callback(), NULL, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv =
+ resolver().GetProxyForURL(GURL("http://request3"), &results3,
+ callback3.callback(), NULL, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Wait for the requests to finish (they must finish in the order they were
// started, which is what we check for from their magic return value)
@@ -316,7 +325,7 @@ TEST_F(MultiThreadedProxyResolverTest,
BoundTestNetLog log0;
rv = resolver().GetProxyForURL(GURL("http://request0"), &results0,
callback0.callback(), &request0, log0.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Start 2 more requests (request1 and request2).
@@ -325,7 +334,7 @@ TEST_F(MultiThreadedProxyResolverTest,
BoundTestNetLog log1;
rv = resolver().GetProxyForURL(GURL("http://request1"), &results1,
callback1.callback(), NULL, log1.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ProxyResolver::RequestHandle request2;
TestCompletionCallback callback2;
@@ -333,7 +342,7 @@ TEST_F(MultiThreadedProxyResolverTest,
BoundTestNetLog log2;
rv = resolver().GetProxyForURL(GURL("http://request2"), &results2,
callback2.callback(), &request2, log2.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Unblock the worker thread so the requests can continue running.
factory().resolvers()[0]->WaitUntilBlocked();
@@ -349,8 +358,7 @@ TEST_F(MultiThreadedProxyResolverTest,
log0.GetEntries(&entries0);
ASSERT_EQ(2u, entries0.size());
- EXPECT_EQ(NetLog::TYPE_SUBMITTED_TO_RESOLVER_THREAD,
- entries0[0].type);
+ EXPECT_EQ(NetLogEventType::SUBMITTED_TO_RESOLVER_THREAD, entries0[0].type);
// Check that request 1 completed as expected.
EXPECT_EQ(1, callback1.WaitForResult());
@@ -361,11 +369,9 @@ TEST_F(MultiThreadedProxyResolverTest,
ASSERT_EQ(4u, entries1.size());
EXPECT_TRUE(LogContainsBeginEvent(
- entries1, 0,
- NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
+ entries1, 0, NetLogEventType::WAITING_FOR_PROXY_RESOLVER_THREAD));
EXPECT_TRUE(LogContainsEndEvent(
- entries1, 1,
- NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
+ entries1, 1, NetLogEventType::WAITING_FOR_PROXY_RESOLVER_THREAD));
// Check that request 2 completed as expected.
EXPECT_EQ(2, callback2.WaitForResult());
@@ -376,11 +382,9 @@ TEST_F(MultiThreadedProxyResolverTest,
ASSERT_EQ(4u, entries2.size());
EXPECT_TRUE(LogContainsBeginEvent(
- entries2, 0,
- NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
+ entries2, 0, NetLogEventType::WAITING_FOR_PROXY_RESOLVER_THREAD));
EXPECT_TRUE(LogContainsEndEvent(
- entries2, 1,
- NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
+ entries2, 1, NetLogEventType::WAITING_FOR_PROXY_RESOLVER_THREAD));
}
// Cancel a request which is in progress, and then cancel a request which
@@ -398,10 +402,10 @@ TEST_F(MultiThreadedProxyResolverTest, SingleThread_CancelRequest) {
ProxyResolver::RequestHandle request0;
TestCompletionCallback callback0;
ProxyInfo results0;
- rv =
- resolver().GetProxyForURL(GURL("http://request0"), &results0,
- callback0.callback(), &request0, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = resolver().GetProxyForURL(GURL("http://request0"), &results0,
+ callback0.callback(), &request0,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Wait until requests 0 reaches the worker thread.
factory().resolvers()[0]->WaitUntilBlocked();
@@ -410,23 +414,25 @@ TEST_F(MultiThreadedProxyResolverTest, SingleThread_CancelRequest) {
TestCompletionCallback callback1;
ProxyInfo results1;
- rv = resolver().GetProxyForURL(GURL("http://request1"), &results1,
- callback1.callback(), NULL, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv =
+ resolver().GetProxyForURL(GURL("http://request1"), &results1,
+ callback1.callback(), NULL, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ProxyResolver::RequestHandle request2;
TestCompletionCallback callback2;
ProxyInfo results2;
- rv =
- resolver().GetProxyForURL(GURL("http://request2"), &results2,
- callback2.callback(), &request2, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = resolver().GetProxyForURL(GURL("http://request2"), &results2,
+ callback2.callback(), &request2,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestCompletionCallback callback3;
ProxyInfo results3;
- rv = resolver().GetProxyForURL(GURL("http://request3"), &results3,
- callback3.callback(), NULL, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv =
+ resolver().GetProxyForURL(GURL("http://request3"), &results3,
+ callback3.callback(), NULL, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Cancel request0 (inprogress) and request2 (pending).
resolver().CancelRequest(request0);
@@ -469,21 +475,24 @@ TEST_F(MultiThreadedProxyResolverTest, SingleThread_CancelRequestByDeleting) {
TestCompletionCallback callback0;
ProxyInfo results0;
- rv = resolver().GetProxyForURL(GURL("http://request0"), &results0,
- callback0.callback(), NULL, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv =
+ resolver().GetProxyForURL(GURL("http://request0"), &results0,
+ callback0.callback(), NULL, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestCompletionCallback callback1;
ProxyInfo results1;
- rv = resolver().GetProxyForURL(GURL("http://request1"), &results1,
- callback1.callback(), NULL, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv =
+ resolver().GetProxyForURL(GURL("http://request1"), &results1,
+ callback1.callback(), NULL, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestCompletionCallback callback2;
ProxyInfo results2;
- rv = resolver().GetProxyForURL(GURL("http://request2"), &results2,
- callback2.callback(), NULL, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv =
+ resolver().GetProxyForURL(GURL("http://request2"), &results2,
+ callback2.callback(), NULL, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Wait until request 0 reaches the worker thread.
factory().resolvers()[0]->WaitUntilBlocked();
@@ -530,8 +539,8 @@ TEST_F(MultiThreadedProxyResolverTest, ThreeThreads_Basic) {
// going on right now.
rv = resolver().GetProxyForURL(GURL("http://request0"), &results[0],
callback[0].callback(), &request[0],
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Wait for request 0 to finish.
rv = callback[0].WaitForResult();
@@ -547,13 +556,13 @@ TEST_F(MultiThreadedProxyResolverTest, ThreeThreads_Basic) {
factory().resolvers()[0]->Block();
rv = resolver().GetProxyForURL(GURL("http://request1"), &results[1],
callback[1].callback(), &request[1],
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
factory().resolvers()[0]->WaitUntilBlocked();
rv = resolver().GetProxyForURL(GURL("http://request2"), &results[2],
callback[2].callback(), &request[2],
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(0, callback[2].WaitForResult());
ASSERT_EQ(2u, factory().resolvers().size());
@@ -562,13 +571,13 @@ TEST_F(MultiThreadedProxyResolverTest, ThreeThreads_Basic) {
factory().resolvers()[1]->Block();
rv = resolver().GetProxyForURL(GURL("http://request3"), &results[3],
callback[3].callback(), &request[3],
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
factory().resolvers()[1]->WaitUntilBlocked();
rv = resolver().GetProxyForURL(GURL("http://request4"), &results[4],
callback[4].callback(), &request[4],
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(0, callback[4].WaitForResult());
// We should now have a total of 3 threads, each with its own ProxyResolver
@@ -589,16 +598,16 @@ TEST_F(MultiThreadedProxyResolverTest, ThreeThreads_Basic) {
// the first request.
rv = resolver().GetProxyForURL(GURL("http://request5"), &results[5],
callback[5].callback(), &request[5],
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = resolver().GetProxyForURL(GURL("http://request6"), &results[6],
callback[6].callback(), &request[6],
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = resolver().GetProxyForURL(GURL("http://request7"), &results[7],
callback[7].callback(), &request[7],
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
resolver().CancelRequest(request[5]);
resolver().CancelRequest(request[6]);
@@ -644,9 +653,9 @@ TEST_F(MultiThreadedProxyResolverTest, OneThreadBlocked) {
rv = resolver().GetProxyForURL(GURL("http://request0"), &results[0],
callback[0].callback(), &request[0],
- BoundNetLog());
+ NetLogWithSource());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
factory().resolvers()[0]->WaitUntilBlocked();
// Start 3 more requests -- they should all be serviced by thread #2
@@ -655,8 +664,8 @@ TEST_F(MultiThreadedProxyResolverTest, OneThreadBlocked) {
for (int i = 1; i < kNumRequests; ++i) {
rv = resolver().GetProxyForURL(
GURL(base::StringPrintf("http://request%d", i)), &results[i],
- callback[i].callback(), &request[i], BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback[i].callback(), &request[i], NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
}
// Wait for the three requests to complete (they should complete in FIFO
@@ -704,7 +713,7 @@ TEST_F(MultiThreadedProxyResolverTest, ProxyResolverFactoryError) {
ProxyResolverScriptData::FromUTF8("pac script bytes"),
&resolver, ready_callback.callback(), &request));
EXPECT_TRUE(request);
- EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, ready_callback.WaitForResult());
+ EXPECT_THAT(ready_callback.WaitForResult(), IsError(ERR_PAC_SCRIPT_FAILED));
EXPECT_FALSE(resolver);
}
@@ -755,7 +764,7 @@ TEST_F(MultiThreadedProxyResolverTest, DeleteRequestInFactoryCallback) {
base::Unretained(&request)),
&request));
EXPECT_TRUE(request);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
}
// Test that deleting the factory with a request in-progress works correctly.
diff --git a/chromium/net/proxy/network_delegate_error_observer.h b/chromium/net/proxy/network_delegate_error_observer.h
index 1b68ceabdb2..9aa3902b3ff 100644
--- a/chromium/net/proxy/network_delegate_error_observer.h
+++ b/chromium/net/proxy/network_delegate_error_observer.h
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "net/base/net_export.h"
#include "net/proxy/proxy_resolver_error_observer.h"
namespace base {
diff --git a/chromium/net/proxy/network_delegate_error_observer_unittest.cc b/chromium/net/proxy/network_delegate_error_observer_unittest.cc
index 8bfe7eaa1da..4e38b620624 100644
--- a/chromium/net/proxy/network_delegate_error_observer_unittest.cc
+++ b/chromium/net/proxy/network_delegate_error_observer_unittest.cc
@@ -50,8 +50,8 @@ class TestNetworkDelegate : public NetworkDelegateImpl {
}
void OnBeforeRedirect(URLRequest* request,
const GURL& new_location) override {}
- void OnResponseStarted(URLRequest* request) override {}
- void OnCompleted(URLRequest* request, bool started) override {}
+ void OnResponseStarted(URLRequest* request, int net_error) override {}
+ void OnCompleted(URLRequest* request, bool started, int net_error) override {}
void OnURLRequestDestroyed(URLRequest* request) override {}
void OnPACScriptError(int line_number, const base::string16& error) override {
diff --git a/chromium/net/proxy/parse_proxy_bypass_rules_fuzzer.cc b/chromium/net/proxy/parse_proxy_bypass_rules_fuzzer.cc
index 1a9c63c816d..37b8971c218 100644
--- a/chromium/net/proxy/parse_proxy_bypass_rules_fuzzer.cc
+++ b/chromium/net/proxy/parse_proxy_bypass_rules_fuzzer.cc
@@ -12,5 +12,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
net::ProxyBypassRules rules;
std::string input(data, data + size);
rules.ParseFromString(input);
+ rules.ParseFromStringUsingSuffixMatching(input);
return 0;
}
diff --git a/chromium/net/proxy/polling_proxy_config_service.h b/chromium/net/proxy/polling_proxy_config_service.h
index f4db0df6648..c613134210a 100644
--- a/chromium/net/proxy/polling_proxy_config_service.h
+++ b/chromium/net/proxy/polling_proxy_config_service.h
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
+#include "net/base/net_export.h"
#include "net/proxy/proxy_config_service.h"
namespace net {
diff --git a/chromium/net/proxy/proxy_bypass_rules.cc b/chromium/net/proxy/proxy_bypass_rules.cc
index 963f6b0ec60..b1ebb0a4636 100644
--- a/chromium/net/proxy/proxy_bypass_rules.cc
+++ b/chromium/net/proxy/proxy_bypass_rules.cc
@@ -4,7 +4,7 @@
#include "net/proxy/proxy_bypass_rules.h"
-#include "base/stl_util.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/pattern.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_tokenizer.h"
@@ -50,10 +50,9 @@ class HostnamePatternRule : public ProxyBypassRules::Rule {
return str;
}
- Rule* Clone() const override {
- return new HostnamePatternRule(optional_scheme_,
- hostname_pattern_,
- optional_port_);
+ std::unique_ptr<Rule> Clone() const override {
+ return base::MakeUnique<HostnamePatternRule>(
+ optional_scheme_, hostname_pattern_, optional_port_);
}
private:
@@ -73,7 +72,9 @@ class BypassLocalRule : public ProxyBypassRules::Rule {
std::string ToString() const override { return "<local>"; }
- Rule* Clone() const override { return new BypassLocalRule(); }
+ std::unique_ptr<Rule> Clone() const override {
+ return base::MakeUnique<BypassLocalRule>();
+ }
};
// Rule for matching a URL that is an IP address, if that IP address falls
@@ -110,11 +111,9 @@ class BypassIPBlockRule : public ProxyBypassRules::Rule {
std::string ToString() const override { return description_; }
- Rule* Clone() const override {
- return new BypassIPBlockRule(description_,
- optional_scheme_,
- ip_prefix_,
- prefix_length_in_bits_);
+ std::unique_ptr<Rule> Clone() const override {
+ return base::MakeUnique<BypassIPBlockRule>(
+ description_, optional_scheme_, ip_prefix_, prefix_length_in_bits_);
}
private:
@@ -198,14 +197,13 @@ bool ProxyBypassRules::AddRuleForHostname(const std::string& optional_scheme,
if (hostname_pattern.empty())
return false;
- rules_.push_back(new HostnamePatternRule(optional_scheme,
- hostname_pattern,
- optional_port));
+ rules_.push_back(base::MakeUnique<HostnamePatternRule>(
+ optional_scheme, hostname_pattern, optional_port));
return true;
}
void ProxyBypassRules::AddRuleToBypassLocal() {
- rules_.push_back(new BypassLocalRule);
+ rules_.push_back(base::MakeUnique<BypassLocalRule>());
}
bool ProxyBypassRules::AddRuleFromString(const std::string& raw) {
@@ -229,7 +227,7 @@ std::string ProxyBypassRules::ToString() const {
}
void ProxyBypassRules::Clear() {
- STLDeleteElements(&rules_);
+ rules_.clear();
}
void ProxyBypassRules::AssignFrom(const ProxyBypassRules& other) {
@@ -289,8 +287,8 @@ bool ProxyBypassRules::AddRuleFromStringInternal(
if (!ParseCIDRBlock(raw, &ip_prefix, &prefix_length_in_bits))
return false;
- rules_.push_back(
- new BypassIPBlockRule(raw, scheme, ip_prefix, prefix_length_in_bits));
+ rules_.push_back(base::MakeUnique<BypassIPBlockRule>(
+ raw, scheme, ip_prefix, prefix_length_in_bits));
return true;
}
diff --git a/chromium/net/proxy/proxy_bypass_rules.h b/chromium/net/proxy/proxy_bypass_rules.h
index c7960743f81..5bedcc813e7 100644
--- a/chromium/net/proxy/proxy_bypass_rules.h
+++ b/chromium/net/proxy/proxy_bypass_rules.h
@@ -5,6 +5,7 @@
#ifndef NET_PROXY_PROXY_BYPASS_RULES_H_
#define NET_PROXY_PROXY_BYPASS_RULES_H_
+#include <memory>
#include <string>
#include <vector>
@@ -32,8 +33,8 @@ class NET_EXPORT ProxyBypassRules {
// visualizing the rules, and also to test equality of a rules list.
virtual std::string ToString() const = 0;
- // Creates a copy of this rule. (Caller is responsible for deleting it)
- virtual Rule* Clone() const = 0;
+ // Creates a copy of this rule.
+ virtual std::unique_ptr<Rule> Clone() const = 0;
bool Equals(const Rule& rule) const;
@@ -41,7 +42,7 @@ class NET_EXPORT ProxyBypassRules {
DISALLOW_COPY_AND_ASSIGN(Rule);
};
- typedef std::vector<const Rule*> RuleList;
+ typedef std::vector<std::unique_ptr<Rule>> RuleList;
// Note: This class supports copy constructor and assignment.
ProxyBypassRules();
@@ -69,7 +70,7 @@ class NET_EXPORT ProxyBypassRules {
// This is a variant of ParseFromString, which interprets hostname patterns
// as suffix tests rather than hostname tests (so "google.com" would actually
// match "*google.com"). This is only currently used for the linux no_proxy
- // evironment variable. It is less flexible, since with the suffix matching
+ // environment variable. It is less flexible, since with the suffix matching
// format you can't match an individual host.
// NOTE: Use ParseFromString() unless you truly need this behavior.
void ParseFromStringUsingSuffixMatching(const std::string& raw);
diff --git a/chromium/net/proxy/proxy_config.h b/chromium/net/proxy/proxy_config.h
index 4ebd60aca79..8f88dc11f0c 100644
--- a/chromium/net/proxy/proxy_config.h
+++ b/chromium/net/proxy/proxy_config.h
@@ -16,6 +16,7 @@
namespace base {
class Value;
+class DictionaryValue;
}
namespace net {
diff --git a/chromium/net/proxy/proxy_config_service_android.cc b/chromium/net/proxy/proxy_config_service_android.cc
index 990b614fb8b..25049911136 100644
--- a/chromium/net/proxy/proxy_config_service_android.cc
+++ b/chromium/net/proxy/proxy_config_service_android.cc
@@ -31,7 +31,9 @@ using base::android::ConvertUTF8ToJavaString;
using base::android::ConvertJavaStringToUTF8;
using base::android::CheckException;
using base::android::ClearException;
+using base::android::JavaParamRef;
using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
namespace net {
@@ -156,7 +158,7 @@ std::string GetJavaProperty(const std::string& property) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(env, property);
ScopedJavaLocalRef<jstring> result =
- Java_ProxyChangeListener_getProperty(env, str.obj());
+ Java_ProxyChangeListener_getProperty(env, str);
return result.is_null() ?
std::string() : ConvertJavaStringToUTF8(env, result.obj());
}
@@ -211,10 +213,8 @@ class ProxyConfigServiceAndroid::Delegate
env, base::android::GetApplicationContext()));
CHECK(!java_proxy_change_listener_.is_null());
}
- Java_ProxyChangeListener_start(
- env,
- java_proxy_change_listener_.obj(),
- reinterpret_cast<intptr_t>(&jni_delegate_));
+ Java_ProxyChangeListener_start(env, java_proxy_change_listener_,
+ reinterpret_cast<intptr_t>(&jni_delegate_));
}
void FetchInitialConfig() {
@@ -329,7 +329,7 @@ class ProxyConfigServiceAndroid::Delegate
if (java_proxy_change_listener_.is_null())
return;
JNIEnv* env = AttachCurrentThread();
- Java_ProxyChangeListener_stop(env, java_proxy_change_listener_.obj());
+ Java_ProxyChangeListener_stop(env, java_proxy_change_listener_);
}
// Called on the network thread.
diff --git a/chromium/net/proxy/proxy_config_service_android_unittest.cc b/chromium/net/proxy/proxy_config_service_android_unittest.cc
index ecc3185b851..4692553212d 100644
--- a/chromium/net/proxy/proxy_config_service_android_unittest.cc
+++ b/chromium/net/proxy/proxy_config_service_android_unittest.cc
@@ -11,6 +11,7 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_info.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -64,7 +65,7 @@ class ProxyConfigServiceAndroidTestBase : public testing::Test {
// testing::Test:
void SetUp() override {
- message_loop_->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
service_.AddObserver(&observer_);
}
@@ -87,7 +88,7 @@ class ProxyConfigServiceAndroidTestBase : public testing::Test {
void ProxySettingsChanged() {
service_.ProxySettingsChanged();
- message_loop_->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
void TestMapping(const std::string& url, const std::string& expected) {
diff --git a/chromium/net/proxy/proxy_config_service_fixed.h b/chromium/net/proxy/proxy_config_service_fixed.h
index a95bf78636b..84c6eab5e54 100644
--- a/chromium/net/proxy/proxy_config_service_fixed.h
+++ b/chromium/net/proxy/proxy_config_service_fixed.h
@@ -7,6 +7,7 @@
#include "base/compiler_specific.h"
#include "net/base/net_errors.h"
+#include "net/base/net_export.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_config_service.h"
diff --git a/chromium/net/proxy/proxy_config_service_win.cc b/chromium/net/proxy/proxy_config_service_win.cc
index e819bf48000..6341c61d0ab 100644
--- a/chromium/net/proxy/proxy_config_service_win.cc
+++ b/chromium/net/proxy/proxy_config_service_win.cc
@@ -12,7 +12,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
-#include "base/stl_util.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -46,10 +46,10 @@ ProxyConfigServiceWin::ProxyConfigServiceWin()
}
ProxyConfigServiceWin::~ProxyConfigServiceWin() {
- // The registry functions below will end up going to disk. Do this on another
- // thread to avoid slowing the IO thread. http://crbug.com/61453
+ // The registry functions below will end up going to disk. TODO: Do this on
+ // another thread to avoid slowing the IO thread. http://crbug.com/61453
base::ThreadRestrictions::ScopedAllowIO allow_io;
- STLDeleteElements(&keys_to_watch_);
+ keys_to_watch_.clear();
}
void ProxyConfigServiceWin::AddObserver(Observer* observer) {
@@ -96,7 +96,8 @@ void ProxyConfigServiceWin::StartWatchingRegistryForChanges() {
bool ProxyConfigServiceWin::AddKeyToWatchList(HKEY rootkey,
const wchar_t* subkey) {
- std::unique_ptr<base::win::RegKey> key(new base::win::RegKey);
+ std::unique_ptr<base::win::RegKey> key =
+ base::MakeUnique<base::win::RegKey>();
if (key->Create(rootkey, subkey, KEY_NOTIFY) != ERROR_SUCCESS)
return false;
@@ -106,21 +107,22 @@ bool ProxyConfigServiceWin::AddKeyToWatchList(HKEY rootkey,
return false;
}
- keys_to_watch_.push_back(key.release());
+ keys_to_watch_.push_back(std::move(key));
return true;
}
void ProxyConfigServiceWin::OnObjectSignaled(base::win::RegKey* key) {
// Figure out which registry key signalled this change.
- RegKeyList::iterator it =
- std::find(keys_to_watch_.begin(), keys_to_watch_.end(), key);
+ auto it = std::find_if(keys_to_watch_.begin(), keys_to_watch_.end(),
+ [key](const std::unique_ptr<base::win::RegKey>& ptr) {
+ return ptr.get() == key;
+ });
DCHECK(it != keys_to_watch_.end());
// Keep watching the registry key.
if (!key->StartWatching(base::Bind(&ProxyConfigServiceWin::OnObjectSignaled,
base::Unretained(this),
base::Unretained(key)))) {
- delete *it;
keys_to_watch_.erase(it);
}
diff --git a/chromium/net/proxy/proxy_config_service_win.h b/chromium/net/proxy/proxy_config_service_win.h
index ce17e05700b..d14b5df54ef 100644
--- a/chromium/net/proxy/proxy_config_service_win.h
+++ b/chromium/net/proxy/proxy_config_service_win.h
@@ -8,10 +8,12 @@
#include <windows.h>
#include <winhttp.h>
+#include <memory>
#include <vector>
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
+#include "net/base/net_export.h"
#include "net/proxy/polling_proxy_config_service.h"
namespace base {
@@ -55,7 +57,6 @@ class NET_EXPORT_PRIVATE ProxyConfigServiceWin
private:
FRIEND_TEST_ALL_PREFIXES(ProxyConfigServiceWinTest, SetFromIEConfig);
- typedef std::vector<base::win::RegKey*> RegKeyList;
// Registers change observers on the registry keys relating to proxy settings.
void StartWatchingRegistryForChanges();
@@ -74,7 +75,7 @@ class NET_EXPORT_PRIVATE ProxyConfigServiceWin
ProxyConfig* config,
const WINHTTP_CURRENT_USER_IE_PROXY_CONFIG& ie_config);
- RegKeyList keys_to_watch_;
+ std::vector<std::unique_ptr<base::win::RegKey>> keys_to_watch_;
};
} // namespace net
diff --git a/chromium/net/proxy/proxy_info.cc b/chromium/net/proxy/proxy_info.cc
index 75000791c52..642a421f900 100644
--- a/chromium/net/proxy/proxy_info.cc
+++ b/chromium/net/proxy/proxy_info.cc
@@ -69,7 +69,7 @@ std::string ProxyInfo::ToPacString() const {
return proxy_list_.ToPacString();
}
-bool ProxyInfo::Fallback(int net_error, const BoundNetLog& net_log) {
+bool ProxyInfo::Fallback(int net_error, const NetLogWithSource& net_log) {
return proxy_list_.Fallback(&proxy_retry_info_, net_error, net_log);
}
diff --git a/chromium/net/proxy/proxy_info.h b/chromium/net/proxy/proxy_info.h
index 3d06a751647..eb3f90fe330 100644
--- a/chromium/net/proxy/proxy_info.h
+++ b/chromium/net/proxy/proxy_info.h
@@ -10,7 +10,6 @@
#include "base/gtest_prod_util.h"
#include "base/time/time.h"
#include "net/base/net_export.h"
-#include "net/log/net_log.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_list.h"
#include "net/proxy/proxy_retry_info.h"
@@ -18,6 +17,8 @@
namespace net {
+class NetLogWithSource;
+
// This object holds proxy information returned by ResolveProxy.
class NET_EXPORT ProxyInfo {
public:
@@ -141,7 +142,7 @@ class NET_EXPORT ProxyInfo {
// is not because of a network error, then |OK| should be passed in (eg. for
// reasons such as local policy). Returns true if there is another proxy is
// available to try in proxy list_.
- bool Fallback(int net_error, const BoundNetLog& net_log);
+ bool Fallback(int net_error, const NetLogWithSource& net_log);
// De-prioritizes the proxies that we have cached as not working, by moving
// them to the end of the proxy list.
diff --git a/chromium/net/proxy/proxy_info_unittest.cc b/chromium/net/proxy/proxy_info_unittest.cc
index 06a0497e4f9..a8b0e8014c4 100644
--- a/chromium/net/proxy/proxy_info_unittest.cc
+++ b/chromium/net/proxy/proxy_info_unittest.cc
@@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "net/proxy/proxy_info.h"
+
#include "net/base/net_errors.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_config.h"
-#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_list.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -37,7 +39,7 @@ TEST(ProxyInfoTest, ProxyInfoIsDirectOnly) {
EXPECT_EQ(2u, info.proxy_list().size());
EXPECT_EQ("PROXY myproxy:80;DIRECT", info.proxy_list().ToPacString());
// After falling back to direct, we shouldn't consider it DIRECT only.
- EXPECT_TRUE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, BoundNetLog()));
+ EXPECT_TRUE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
EXPECT_TRUE(info.is_direct());
EXPECT_FALSE(info.is_direct_only());
}
diff --git a/chromium/net/proxy/proxy_list.cc b/chromium/net/proxy/proxy_list.cc
index 6d26abf4ddf..2f65c720419 100644
--- a/chromium/net/proxy/proxy_list.cc
+++ b/chromium/net/proxy/proxy_list.cc
@@ -9,6 +9,9 @@
#include "base/strings/string_tokenizer.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_server.h"
using base::TimeDelta;
@@ -153,7 +156,7 @@ std::unique_ptr<base::ListValue> ProxyList::ToValue() const {
bool ProxyList::Fallback(ProxyRetryInfoMap* proxy_retry_info,
int net_error,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
// TODO(eroman): It would be good if instead of removing failed proxies
// from the list, we simply annotated them with the error code they failed
// with. Of course, ProxyService::ReconsiderProxyAfterError() would need to
@@ -186,7 +189,7 @@ void ProxyList::AddProxyToRetryList(ProxyRetryInfoMap* proxy_retry_info,
bool try_while_bad,
const ProxyServer& proxy_to_retry,
int net_error,
- const BoundNetLog& net_log) const {
+ const NetLogWithSource& net_log) const {
// Mark this proxy as bad.
TimeTicks bad_until = TimeTicks::Now() + retry_delay;
std::string proxy_key = proxy_to_retry.ToURI();
@@ -199,7 +202,7 @@ void ProxyList::AddProxyToRetryList(ProxyRetryInfoMap* proxy_retry_info,
retry_info.net_error = net_error;
(*proxy_retry_info)[proxy_key] = retry_info;
}
- net_log.AddEvent(NetLog::TYPE_PROXY_LIST_FALLBACK,
+ net_log.AddEvent(NetLogEventType::PROXY_LIST_FALLBACK,
NetLog::StringCallback("bad_proxy", &proxy_key));
}
@@ -209,7 +212,7 @@ void ProxyList::UpdateRetryInfoOnFallback(
bool reconsider,
const std::vector<ProxyServer>& additional_proxies_to_bypass,
int net_error,
- const BoundNetLog& net_log) const {
+ const NetLogWithSource& net_log) const {
DCHECK(!retry_delay.is_zero());
if (proxies_.empty()) {
diff --git a/chromium/net/proxy/proxy_list.h b/chromium/net/proxy/proxy_list.h
index 36cf9383482..7455c23fc85 100644
--- a/chromium/net/proxy/proxy_list.h
+++ b/chromium/net/proxy/proxy_list.h
@@ -7,11 +7,11 @@
#include <stddef.h>
+#include <memory>
#include <string>
#include <vector>
#include "net/base/net_export.h"
-#include "net/log/net_log.h"
#include "net/proxy/proxy_retry_info.h"
namespace base {
@@ -22,6 +22,7 @@ class TimeDelta;
namespace net {
class ProxyServer;
+class NetLogWithSource;
// This class is used to hold a list of proxies returned by GetProxyForUrl or
// manually configured. It handles proxy fallback if multiple servers are
@@ -92,7 +93,7 @@ class NET_EXPORT_PRIVATE ProxyList {
// is another server available in the list.
bool Fallback(ProxyRetryInfoMap* proxy_retry_info,
int net_error,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Updates |proxy_retry_info| to indicate that the first proxy in the list
// is bad. This is distinct from Fallback(), above, to allow updating proxy
@@ -109,7 +110,7 @@ class NET_EXPORT_PRIVATE ProxyList {
bool reconsider,
const std::vector<ProxyServer>& additional_proxies_to_bypass,
int net_error,
- const BoundNetLog& net_log) const;
+ const NetLogWithSource& net_log) const;
private:
// Updates |proxy_retry_info| to indicate that the |proxy_to_retry| in
@@ -122,7 +123,7 @@ class NET_EXPORT_PRIVATE ProxyList {
bool try_while_bad,
const ProxyServer& proxy_to_retry,
int net_error,
- const BoundNetLog& net_log) const;
+ const NetLogWithSource& net_log) const;
// List of proxies.
std::vector<ProxyServer> proxies_;
diff --git a/chromium/net/proxy/proxy_list_unittest.cc b/chromium/net/proxy/proxy_list_unittest.cc
index e98d9c51977..52a65bd707b 100644
--- a/chromium/net/proxy/proxy_list_unittest.cc
+++ b/chromium/net/proxy/proxy_list_unittest.cc
@@ -7,11 +7,15 @@
#include <vector>
#include "net/base/net_errors.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_retry_info.h"
#include "net/proxy/proxy_server.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -174,7 +178,7 @@ TEST(ProxyListTest, UpdateRetryInfoOnFallback) {
{
ProxyList list;
ProxyRetryInfoMap retry_info_map;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
ProxyServer proxy_server(
ProxyServer::FromURI("foopy1:80", ProxyServer::SCHEME_HTTP));
std::vector<ProxyServer> bad_proxies;
@@ -194,7 +198,7 @@ TEST(ProxyListTest, UpdateRetryInfoOnFallback) {
{
ProxyList list;
ProxyRetryInfoMap retry_info_map;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
ProxyServer proxy_server(
ProxyServer::FromURI("foopy1:80", ProxyServer::SCHEME_HTTP));
std::vector<ProxyServer> bad_proxies;
@@ -204,7 +208,7 @@ TEST(ProxyListTest, UpdateRetryInfoOnFallback) {
base::TimeDelta::FromSeconds(60), true,
bad_proxies, OK, net_log);
EXPECT_TRUE(retry_info_map.end() != retry_info_map.find("foopy1:80"));
- EXPECT_EQ(OK, retry_info_map[proxy_server.ToURI()].net_error);
+ EXPECT_THAT(retry_info_map[proxy_server.ToURI()].net_error, IsOk());
EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy2:80"));
EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy3:80"));
}
@@ -213,7 +217,7 @@ TEST(ProxyListTest, UpdateRetryInfoOnFallback) {
{
ProxyList list;
ProxyRetryInfoMap retry_info_map;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
ProxyServer proxy_server = ProxyServer::FromURI("foopy3:80",
ProxyServer::SCHEME_HTTP);
std::vector<ProxyServer> bad_proxies;
@@ -233,7 +237,7 @@ TEST(ProxyListTest, UpdateRetryInfoOnFallback) {
{
ProxyList list;
ProxyRetryInfoMap retry_info_map;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
ProxyServer proxy_server = ProxyServer::FromURI("foopy2:80",
ProxyServer::SCHEME_HTTP);
std::vector<ProxyServer> bad_proxies;
@@ -251,7 +255,7 @@ TEST(ProxyListTest, UpdateRetryInfoOnFallback) {
{
ProxyList list;
ProxyRetryInfoMap retry_info_map;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
// First, mark the proxy as bad for 60 seconds.
@@ -281,7 +285,7 @@ TEST(ProxyListTest, UpdateRetryInfoOnFallback) {
{
ProxyList list;
ProxyRetryInfoMap retry_info_map;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
// First, mark the proxy as bad for 1 second.
diff --git a/chromium/net/proxy/proxy_resolver.h b/chromium/net/proxy/proxy_resolver.h
index 81efe0577ba..b343c427adc 100644
--- a/chromium/net/proxy/proxy_resolver.h
+++ b/chromium/net/proxy/proxy_resolver.h
@@ -18,7 +18,7 @@
namespace net {
-class BoundNetLog;
+class NetLogWithSource;
class ProxyInfo;
// Interface for "proxy resolvers". A ProxyResolver fills in a list of proxies
@@ -44,7 +44,7 @@ class NET_EXPORT_PRIVATE ProxyResolver {
ProxyInfo* results,
const CompletionCallback& callback,
RequestHandle* request,
- const BoundNetLog& net_log) = 0;
+ const NetLogWithSource& net_log) = 0;
// Cancels |request|.
virtual void CancelRequest(RequestHandle request) = 0;
diff --git a/chromium/net/proxy/proxy_resolver_factory_mojo.cc b/chromium/net/proxy/proxy_resolver_factory_mojo.cc
index c4b1ecaac4b..0a14cac3589 100644
--- a/chromium/net/proxy/proxy_resolver_factory_mojo.cc
+++ b/chromium/net/proxy/proxy_resolver_factory_mojo.cc
@@ -21,6 +21,10 @@
#include "net/dns/mojo_host_resolver_impl.h"
#include "net/interfaces/host_resolver_service.mojom.h"
#include "net/interfaces/proxy_resolver_service.mojom.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/mojo_proxy_resolver_factory.h"
#include "net/proxy/mojo_proxy_type_converters.h"
#include "net/proxy/proxy_info.h"
@@ -29,6 +33,7 @@
#include "net/proxy/proxy_resolver_script_data.h"
namespace net {
+
namespace {
std::unique_ptr<base::Value> NetLogErrorCallback(
@@ -50,27 +55,29 @@ class ClientMixin : public ClientInterface {
ClientMixin(HostResolver* host_resolver,
ProxyResolverErrorObserver* error_observer,
NetLog* net_log,
- const BoundNetLog& bound_net_log)
- : host_resolver_(host_resolver, bound_net_log),
+ const NetLogWithSource& net_log_with_source)
+ : host_resolver_(host_resolver, net_log_with_source),
error_observer_(error_observer),
net_log_(net_log),
- bound_net_log_(bound_net_log) {}
+ net_log_with_source_(net_log_with_source) {}
// Overridden from ClientInterface:
void Alert(const mojo::String& message) override {
base::string16 message_str = message.To<base::string16>();
auto callback = NetLog::StringCallback("message", &message_str);
- bound_net_log_.AddEvent(NetLog::TYPE_PAC_JAVASCRIPT_ALERT, callback);
+ net_log_with_source_.AddEvent(NetLogEventType::PAC_JAVASCRIPT_ALERT,
+ callback);
if (net_log_)
- net_log_->AddGlobalEntry(NetLog::TYPE_PAC_JAVASCRIPT_ALERT, callback);
+ net_log_->AddGlobalEntry(NetLogEventType::PAC_JAVASCRIPT_ALERT, callback);
}
void OnError(int32_t line_number, const mojo::String& message) override {
base::string16 message_str = message.To<base::string16>();
auto callback = base::Bind(&NetLogErrorCallback, line_number, &message_str);
- bound_net_log_.AddEvent(NetLog::TYPE_PAC_JAVASCRIPT_ERROR, callback);
+ net_log_with_source_.AddEvent(NetLogEventType::PAC_JAVASCRIPT_ERROR,
+ callback);
if (net_log_)
- net_log_->AddGlobalEntry(NetLog::TYPE_PAC_JAVASCRIPT_ERROR, callback);
+ net_log_->AddGlobalEntry(NetLogEventType::PAC_JAVASCRIPT_ERROR, callback);
if (error_observer_)
error_observer_->OnPACScriptError(line_number, message_str);
}
@@ -89,7 +96,7 @@ class ClientMixin : public ClientInterface {
MojoHostResolverImpl host_resolver_;
ProxyResolverErrorObserver* const error_observer_;
NetLog* const net_log_;
- const BoundNetLog bound_net_log_;
+ const NetLogWithSource net_log_with_source_;
};
// Implementation of ProxyResolver that connects to a Mojo service to evaluate
@@ -119,7 +126,7 @@ class ProxyResolverMojo : public ProxyResolver {
ProxyInfo* results,
const net::CompletionCallback& callback,
RequestHandle* request,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void CancelRequest(RequestHandle request) override;
LoadState GetLoadState(RequestHandle request) const override;
@@ -156,7 +163,7 @@ class ProxyResolverMojo::Job
const GURL& url,
ProxyInfo* results,
const CompletionCallback& callback,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
~Job() override;
// Cancels the job and prevents the callback from being run.
@@ -187,7 +194,7 @@ ProxyResolverMojo::Job::Job(ProxyResolverMojo* resolver,
const GURL& url,
ProxyInfo* results,
const CompletionCallback& callback,
- const BoundNetLog& net_log)
+ const NetLogWithSource& net_log)
: ClientMixin<interfaces::ProxyResolverRequestClient>(
resolver->host_resolver_,
resolver->error_observer_.get(),
@@ -284,7 +291,7 @@ int ProxyResolverMojo::GetProxyForURL(const GURL& url,
ProxyInfo* results,
const CompletionCallback& callback,
RequestHandle* request,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!mojo_proxy_resolver_ptr_)
@@ -318,7 +325,7 @@ LoadState ProxyResolverMojo::GetLoadState(RequestHandle request) const {
//
// Note: a Job instance is not tied to a particular resolve request, and hence
// there is no per-request logging to be done (any netlog events are only sent
-// globally) so this always uses an empty BoundNetLog.
+// globally) so this always uses an empty NetLogWithSource.
class ProxyResolverFactoryMojo::Job
: public ClientMixin<interfaces::ProxyResolverFactoryRequestClient>,
public ProxyResolverFactory::Request {
@@ -332,7 +339,7 @@ class ProxyResolverFactoryMojo::Job
factory->host_resolver_,
error_observer.get(),
factory->net_log_,
- BoundNetLog()),
+ NetLogWithSource()),
factory_(factory),
resolver_(resolver),
callback_(callback),
diff --git a/chromium/net/proxy/proxy_resolver_factory_mojo_unittest.cc b/chromium/net/proxy/proxy_resolver_factory_mojo_unittest.cc
index 364462a8330..2c5dee1b7d4 100644
--- a/chromium/net/proxy/proxy_resolver_factory_mojo_unittest.cc
+++ b/chromium/net/proxy/proxy_resolver_factory_mojo_unittest.cc
@@ -14,6 +14,7 @@
#include "base/bind.h"
#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/values.h"
@@ -23,6 +24,8 @@
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/dns/host_resolver.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
#include "net/proxy/mojo_proxy_resolver_factory.h"
#include "net/proxy/mojo_proxy_type_converters.h"
@@ -31,9 +34,14 @@
#include "net/proxy/proxy_resolver_error_observer.h"
#include "net/proxy/proxy_resolver_script_data.h"
#include "net/test/event_waiter.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -267,7 +275,12 @@ void MockMojoProxyResolver::GetProxyForUrl(
break;
}
case GetProxyForUrlAction::WAIT_FOR_CLIENT_DISCONNECT: {
- ASSERT_FALSE(client.WaitForIncomingResponse());
+ base::MessageLoop::ScopedNestableTaskAllower nestable_allower(
+ base::MessageLoop::current());
+ base::RunLoop run_loop;
+ client.set_connection_error_handler(run_loop.QuitClosure());
+ run_loop.Run();
+ ASSERT_TRUE(client.encountered_error());
break;
}
case GetProxyForUrlAction::MAKE_DNS_REQUEST: {
@@ -278,8 +291,9 @@ void MockMojoProxyResolver::GetProxyForUrl(
interfaces::HostResolverRequestClientPtr dns_client;
mojo::GetProxy(&dns_client);
client->ResolveDns(std::move(request), std::move(dns_client));
- blocked_clients_.push_back(base::WrapUnique(
- new interfaces::ProxyResolverRequestClientPtr(std::move(client))));
+ blocked_clients_.push_back(
+ base::MakeUnique<interfaces::ProxyResolverRequestClientPtr>(
+ std::move(client)));
break;
}
}
@@ -413,16 +427,16 @@ void MockMojoProxyResolverFactory::CreateResolver(
}
case CreateProxyResolverAction::DROP_CLIENT: {
// Save |request| so its pipe isn't closed.
- blocked_resolver_requests_.push_back(base::WrapUnique(
- new mojo::InterfaceRequest<interfaces::ProxyResolver>(
- std::move(request))));
+ blocked_resolver_requests_.push_back(
+ base::MakeUnique<mojo::InterfaceRequest<interfaces::ProxyResolver>>(
+ std::move(request)));
break;
}
case CreateProxyResolverAction::DROP_RESOLVER: {
// Save |client| so its pipe isn't closed.
blocked_clients_.push_back(
- base::WrapUnique(new interfaces::ProxyResolverFactoryRequestClientPtr(
- std::move(client))));
+ base::MakeUnique<interfaces::ProxyResolverFactoryRequestClientPtr>(
+ std::move(client)));
break;
}
case CreateProxyResolverAction::DROP_BOTH: {
@@ -430,7 +444,12 @@ void MockMojoProxyResolverFactory::CreateResolver(
break;
}
case CreateProxyResolverAction::WAIT_FOR_CLIENT_DISCONNECT: {
- ASSERT_FALSE(client.WaitForIncomingResponse());
+ base::MessageLoop::ScopedNestableTaskAllower nestable_allower(
+ base::MessageLoop::current());
+ base::RunLoop run_loop;
+ client.set_connection_error_handler(run_loop.QuitClosure());
+ run_loop.Run();
+ ASSERT_TRUE(client.encountered_error());
break;
}
case CreateProxyResolverAction::MAKE_DNS_REQUEST: {
@@ -442,8 +461,8 @@ void MockMojoProxyResolverFactory::CreateResolver(
mojo::GetProxy(&dns_client);
client->ResolveDns(std::move(request), std::move(dns_client));
blocked_clients_.push_back(
- base::WrapUnique(new interfaces::ProxyResolverFactoryRequestClientPtr(
- std::move(client))));
+ base::MakeUnique<interfaces::ProxyResolverFactoryRequestClientPtr>(
+ std::move(client)));
break;
}
}
@@ -471,17 +490,18 @@ class MockHostResolver : public HostResolver {
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* request_handle,
- const BoundNetLog& source_net_log) override {
+ std::unique_ptr<Request>* request,
+ const NetLogWithSource& source_net_log) override {
waiter_.NotifyEvent(DNS_REQUEST);
return ERR_IO_PENDING;
}
+
int ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& source_net_log) override {
+ const NetLogWithSource& source_net_log) override {
return ERR_DNS_CACHE_MISS;
}
- void CancelRequest(RequestHandle req) override {}
+
HostCache* GetHostCache() override { return nullptr; }
EventWaiter<Event>& waiter() { return waiter_; }
@@ -493,13 +513,13 @@ class MockHostResolver : public HostResolver {
void CheckCapturedNetLogEntries(const std::string& expected_string,
const TestNetLogEntry::List& entries) {
ASSERT_EQ(2u, entries.size());
- EXPECT_EQ(NetLog::TYPE_PAC_JAVASCRIPT_ALERT, entries[0].type);
+ EXPECT_EQ(NetLogEventType::PAC_JAVASCRIPT_ALERT, entries[0].type);
std::string message;
ASSERT_TRUE(entries[0].GetStringValue("message", &message));
EXPECT_EQ(expected_string, message);
ASSERT_FALSE(entries[0].params->HasKey("line_number"));
message.clear();
- EXPECT_EQ(NetLog::TYPE_PAC_JAVASCRIPT_ERROR, entries[1].type);
+ EXPECT_EQ(NetLogEventType::PAC_JAVASCRIPT_ERROR, entries[1].type);
ASSERT_TRUE(entries[1].GetStringValue("message", &message));
EXPECT_EQ(expected_string, message);
int line_number = 0;
@@ -522,7 +542,7 @@ class ProxyResolverFactoryMojoTest : public testing::Test,
}
std::unique_ptr<Request> MakeRequest(const GURL& url) {
- return base::WrapUnique(new Request(proxy_resolver_mojo_.get(), url));
+ return base::MakeUnique<Request>(proxy_resolver_mojo_.get(), url);
}
std::unique_ptr<base::ScopedClosureRunner> CreateResolver(
@@ -530,8 +550,8 @@ class ProxyResolverFactoryMojoTest : public testing::Test,
mojo::InterfaceRequest<interfaces::ProxyResolver> req,
interfaces::ProxyResolverFactoryRequestClientPtr client) override {
factory_ptr_->CreateResolver(pac_script, std::move(req), std::move(client));
- return base::WrapUnique(
- new base::ScopedClosureRunner(on_delete_callback_.closure()));
+ return base::MakeUnique<base::ScopedClosureRunner>(
+ on_delete_callback_.closure());
}
mojo::Array<interfaces::ProxyServerPtr> ProxyServersFromPacString(
@@ -735,8 +755,8 @@ TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL) {
net_log_.Clear();
std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
- EXPECT_EQ(ERR_IO_PENDING, request->Resolve());
- EXPECT_EQ(OK, request->WaitForResult());
+ EXPECT_THAT(request->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(request->WaitForResult(), IsOk());
EXPECT_EQ("DIRECT", request->results().ToPacString());
@@ -757,8 +777,8 @@ TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_MultipleResults) {
CreateProxyResolver();
std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
- EXPECT_EQ(ERR_IO_PENDING, request->Resolve());
- EXPECT_EQ(OK, request->WaitForResult());
+ EXPECT_THAT(request->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(request->WaitForResult(), IsOk());
EXPECT_EQ(kPacString, request->results().ToPacString());
}
@@ -769,8 +789,8 @@ TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_Error) {
CreateProxyResolver();
std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
- EXPECT_EQ(ERR_IO_PENDING, request->Resolve());
- EXPECT_EQ(ERR_UNEXPECTED, request->WaitForResult());
+ EXPECT_THAT(request->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(request->WaitForResult(), IsError(ERR_UNEXPECTED));
EXPECT_TRUE(request->results().is_empty());
}
@@ -781,7 +801,7 @@ TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_Cancel) {
CreateProxyResolver();
std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
- EXPECT_EQ(ERR_IO_PENDING, request->Resolve());
+ EXPECT_THAT(request->Resolve(), IsError(ERR_IO_PENDING));
request->Cancel();
// The Mojo request is still made.
@@ -797,13 +817,13 @@ TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_MultipleRequests) {
CreateProxyResolver();
std::unique_ptr<Request> request1(MakeRequest(GURL(kExampleUrl)));
- EXPECT_EQ(ERR_IO_PENDING, request1->Resolve());
+ EXPECT_THAT(request1->Resolve(), IsError(ERR_IO_PENDING));
std::unique_ptr<Request> request2(
MakeRequest(GURL("https://www.chromium.org")));
- EXPECT_EQ(ERR_IO_PENDING, request2->Resolve());
+ EXPECT_THAT(request2->Resolve(), IsError(ERR_IO_PENDING));
- EXPECT_EQ(OK, request1->WaitForResult());
- EXPECT_EQ(OK, request2->WaitForResult());
+ EXPECT_THAT(request1->WaitForResult(), IsOk());
+ EXPECT_THAT(request2->WaitForResult(), IsOk());
EXPECT_EQ("DIRECT", request1->results().ToPacString());
EXPECT_EQ("HTTPS foo:443", request2->results().ToPacString());
@@ -815,15 +835,15 @@ TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_Disconnect) {
CreateProxyResolver();
{
std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
- EXPECT_EQ(ERR_IO_PENDING, request->Resolve());
- EXPECT_EQ(ERR_PAC_SCRIPT_TERMINATED, request->WaitForResult());
+ EXPECT_THAT(request->Resolve(), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(request->WaitForResult(), IsError(ERR_PAC_SCRIPT_TERMINATED));
EXPECT_TRUE(request->results().is_empty());
}
{
// Calling GetProxyForURL after a disconnect should fail.
std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
- EXPECT_EQ(ERR_PAC_SCRIPT_TERMINATED, request->Resolve());
+ EXPECT_THAT(request->Resolve(), IsError(ERR_PAC_SCRIPT_TERMINATED));
}
}
@@ -833,9 +853,9 @@ TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_ClientClosed) {
CreateProxyResolver();
std::unique_ptr<Request> request1(MakeRequest(GURL(kExampleUrl)));
- EXPECT_EQ(ERR_IO_PENDING, request1->Resolve());
+ EXPECT_THAT(request1->Resolve(), IsError(ERR_IO_PENDING));
- EXPECT_EQ(ERR_PAC_SCRIPT_TERMINATED, request1->WaitForResult());
+ EXPECT_THAT(request1->WaitForResult(), IsError(ERR_PAC_SCRIPT_TERMINATED));
}
TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_DeleteInCallback) {
@@ -846,7 +866,7 @@ TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_DeleteInCallback) {
ProxyInfo results;
TestCompletionCallback callback;
ProxyResolver::RequestHandle handle;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
EXPECT_EQ(
OK,
callback.GetResult(proxy_resolver_mojo_->GetProxyForURL(
@@ -866,7 +886,7 @@ TEST_F(ProxyResolverFactoryMojoTest,
ProxyInfo results;
TestCompletionCallback callback;
ProxyResolver::RequestHandle handle;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
EXPECT_EQ(
ERR_PAC_SCRIPT_TERMINATED,
callback.GetResult(proxy_resolver_mojo_->GetProxyForURL(
@@ -883,7 +903,7 @@ TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_DnsRequest) {
CreateProxyResolver();
std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
- EXPECT_EQ(ERR_IO_PENDING, request->Resolve());
+ EXPECT_THAT(request->Resolve(), IsError(ERR_IO_PENDING));
EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, request->load_state());
host_resolver_.waiter().WaitForEvent(MockHostResolver::DNS_REQUEST);
diff --git a/chromium/net/proxy/proxy_resolver_mac.cc b/chromium/net/proxy/proxy_resolver_mac.cc
index 6498ccd4287..fa1de89858a 100644
--- a/chromium/net/proxy/proxy_resolver_mac.cc
+++ b/chromium/net/proxy/proxy_resolver_mac.cc
@@ -192,7 +192,7 @@ class ProxyResolverMac : public ProxyResolver {
ProxyInfo* results,
const CompletionCallback& callback,
RequestHandle* request,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void CancelRequest(RequestHandle request) override;
@@ -215,7 +215,7 @@ int ProxyResolverMac::GetProxyForURL(const GURL& query_url,
ProxyInfo* results,
const CompletionCallback& /*callback*/,
RequestHandle* /*request*/,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
base::ScopedCFTypeRef<CFStringRef> query_ref(
base::SysUTF8ToCFStringRef(query_url.spec()));
base::ScopedCFTypeRef<CFURLRef> query_url_ref(
diff --git a/chromium/net/proxy/proxy_resolver_perftest.cc b/chromium/net/proxy/proxy_resolver_perftest.cc
index 2f352369f47..1c57e92cd6a 100644
--- a/chromium/net/proxy/proxy_resolver_perftest.cc
+++ b/chromium/net/proxy/proxy_resolver_perftest.cc
@@ -14,11 +14,14 @@
#include "base/test/perf_time_logger.h"
#include "net/base/net_errors.h"
#include "net/dns/mock_host_resolver.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_resolver.h"
#include "net/proxy/proxy_resolver_factory.h"
#include "net/proxy/proxy_resolver_v8.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
@@ -27,6 +30,8 @@
#include "net/proxy/proxy_resolver_mac.h"
#endif
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -118,7 +123,7 @@ class PacPerfSuiteRunner {
int rv = factory_->CreateProxyResolver(
ProxyResolverScriptData::FromURL(pac_url), &resolver,
CompletionCallback(), nullptr);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
} else {
resolver = LoadPacScriptAndCreateResolver(script_name);
}
@@ -129,10 +134,10 @@ class PacPerfSuiteRunner {
// the PAC script.
{
ProxyInfo proxy_info;
- int result =
- resolver->GetProxyForURL(GURL("http://www.warmup.com"), &proxy_info,
- CompletionCallback(), NULL, BoundNetLog());
- ASSERT_EQ(OK, result);
+ int result = resolver->GetProxyForURL(GURL("http://www.warmup.com"),
+ &proxy_info, CompletionCallback(),
+ NULL, NetLogWithSource());
+ ASSERT_THAT(result, IsOk());
}
// Start the perf timer.
@@ -145,13 +150,13 @@ class PacPerfSuiteRunner {
// Resolve.
ProxyInfo proxy_info;
- int result =
- resolver->GetProxyForURL(GURL(query.query_url), &proxy_info,
- CompletionCallback(), NULL, BoundNetLog());
+ int result = resolver->GetProxyForURL(GURL(query.query_url), &proxy_info,
+ CompletionCallback(), NULL,
+ NetLogWithSource());
// Check that the result was correct. Note that ToPacString() and
// ASSERT_EQ() are fast, so they won't skew the results.
- ASSERT_EQ(OK, result);
+ ASSERT_THAT(result, IsOk());
ASSERT_EQ(query.expected_result, proxy_info.ToPacString());
}
@@ -183,7 +188,7 @@ class PacPerfSuiteRunner {
int rv = factory_->CreateProxyResolver(
ProxyResolverScriptData::FromUTF8(file_contents), &resolver,
CompletionCallback(), nullptr);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
return resolver;
}
@@ -235,7 +240,7 @@ class ProxyResolverV8Wrapper : public ProxyResolver {
ProxyInfo* results,
const CompletionCallback& /*callback*/,
RequestHandle* /*request*/,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
return resolver_->GetProxyForURL(url, results, bindings_.get());
}
diff --git a/chromium/net/proxy/proxy_resolver_v8_tracing.cc b/chromium/net/proxy/proxy_resolver_v8_tracing.cc
index ef25fc80ece..e53ba49a7bf 100644
--- a/chromium/net/proxy/proxy_resolver_v8_tracing.cc
+++ b/chromium/net/proxy/proxy_resolver_v8_tracing.cc
@@ -24,6 +24,7 @@
#include "net/base/net_errors.h"
#include "net/base/network_interfaces.h"
#include "net/dns/host_resolver.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_resolver_error_observer.h"
#include "net/proxy/proxy_resolver_v8.h"
@@ -284,7 +285,7 @@ class Job : public base::RefCountedThreadSafe<Job>,
// Handle to the outstanding request in the HostResolver, or NULL.
// This is mutated and used on the origin thread, however it may be read by
// the worker thread for some DCHECKS().
- HostResolver::RequestHandle pending_dns_;
+ std::unique_ptr<HostResolver::Request> pending_dns_;
// Indicates if the outstanding DNS request completed synchronously. Written
// on the origin thread, and read by the worker thread.
@@ -338,8 +339,7 @@ Job::Job(const Job::Params* params,
bindings_(std::move(bindings)),
event_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED),
- last_num_dns_(0),
- pending_dns_(NULL) {
+ last_num_dns_(0) {
CheckIsOnOriginThread();
}
@@ -394,10 +394,7 @@ void Job::Cancel() {
ReleaseCallback();
- if (pending_dns_) {
- host_resolver()->CancelRequest(pending_dns_);
- pending_dns_ = NULL;
- }
+ pending_dns_.reset();
// The worker thread might be blocked waiting for DNS.
event_.Signal();
@@ -710,11 +707,11 @@ void Job::DoDnsOperation() {
if (cancelled_.IsSet())
return;
- HostResolver::RequestHandle dns_request = NULL;
+ std::unique_ptr<HostResolver::Request> dns_request;
int result = host_resolver()->Resolve(
MakeDnsRequestInfo(pending_dns_host_, pending_dns_op_), DEFAULT_PRIORITY,
&pending_dns_addresses_, base::Bind(&Job::OnDnsOperationComplete, this),
- &dns_request, bindings_->GetBoundNetLog());
+ &dns_request, bindings_->GetNetLogWithSource());
pending_dns_completed_synchronously_ = result != ERR_IO_PENDING;
@@ -728,7 +725,7 @@ void Job::DoDnsOperation() {
OnDnsOperationComplete(result);
} else {
DCHECK(dns_request);
- pending_dns_ = dns_request;
+ pending_dns_ = std::move(dns_request);
// OnDnsOperationComplete() will be called by host resolver on completion.
}
@@ -747,7 +744,7 @@ void Job::OnDnsOperationComplete(int result) {
SaveDnsToLocalCache(pending_dns_host_, pending_dns_op_, result,
pending_dns_addresses_);
- pending_dns_ = NULL;
+ pending_dns_.reset();
if (blocking_dns_) {
event_.Signal();
diff --git a/chromium/net/proxy/proxy_resolver_v8_tracing.h b/chromium/net/proxy/proxy_resolver_v8_tracing.h
index 6bca78bb64c..cc329cd04f7 100644
--- a/chromium/net/proxy/proxy_resolver_v8_tracing.h
+++ b/chromium/net/proxy/proxy_resolver_v8_tracing.h
@@ -16,6 +16,7 @@
namespace net {
class HostResolver;
+class NetLogWithSource;
// ProxyResolverV8Tracing is a non-blocking proxy resolver.
class NET_EXPORT ProxyResolverV8Tracing {
@@ -38,9 +39,9 @@ class NET_EXPORT ProxyResolverV8Tracing {
// Returns a HostResolver to use for DNS resolution.
virtual HostResolver* GetHostResolver() = 0;
- // Returns a BoundNetLog to be passed to the HostResolver returned by
+ // Returns a NetLogWithSource to be passed to the HostResolver returned by
// GetHostResolver().
- virtual BoundNetLog GetBoundNetLog() = 0;
+ virtual NetLogWithSource GetNetLogWithSource() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(Bindings);
diff --git a/chromium/net/proxy/proxy_resolver_v8_tracing_unittest.cc b/chromium/net/proxy/proxy_resolver_v8_tracing_unittest.cc
index 2aa782045fe..6967491881b 100644
--- a/chromium/net/proxy/proxy_resolver_v8_tracing_unittest.cc
+++ b/chromium/net/proxy/proxy_resolver_v8_tracing_unittest.cc
@@ -20,12 +20,17 @@
#include "net/base/test_completion_callback.h"
#include "net/dns/host_cache.h"
#include "net/dns/mock_host_resolver.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_info.h"
#include "net/test/event_waiter.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -90,7 +95,7 @@ class MockBindings {
}
std::unique_ptr<ProxyResolverV8Tracing::Bindings> CreateBindings() {
- return base::WrapUnique(new ForwardingBindings(this));
+ return base::MakeUnique<ForwardingBindings>(this);
}
private:
@@ -109,9 +114,9 @@ class MockBindings {
bindings_->OnError(line_number, error);
}
- BoundNetLog GetBoundNetLog() override {
+ NetLogWithSource GetNetLogWithSource() override {
DCHECK(thread_checker_.CalledOnValidThread());
- return BoundNetLog();
+ return NetLogWithSource();
}
HostResolver* GetHostResolver() override {
@@ -146,7 +151,7 @@ std::unique_ptr<ProxyResolverV8Tracing> CreateResolver(
factory->CreateProxyResolverV8Tracing(LoadScriptData(filename),
std::move(bindings), &resolver,
callback.callback(), &request);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(resolver);
return resolver;
}
@@ -165,7 +170,7 @@ TEST_F(ProxyResolverV8TracingTest, Simple) {
callback.callback(), NULL,
mock_bindings.CreateBindings());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ("foo:99", proxy_info.proxy_server().ToURI());
@@ -190,7 +195,7 @@ TEST_F(ProxyResolverV8TracingTest, JavascriptError) {
callback.callback(), NULL,
mock_bindings.CreateBindings());
- EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_PAC_SCRIPT_FAILED));
EXPECT_EQ(0u, host_resolver.num_resolve());
@@ -217,7 +222,7 @@ TEST_F(ProxyResolverV8TracingTest, TooManyAlerts) {
callback.callback(), NULL,
mock_bindings.CreateBindings());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// Iteration1 does a DNS resolve
// Iteration2 exceeds the alert buffer
@@ -253,7 +258,7 @@ TEST_F(ProxyResolverV8TracingTest, TooManyEmptyAlerts) {
callback.callback(), NULL,
mock_bindings.CreateBindings());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ("foo:3", proxy_info.proxy_server().ToURI());
@@ -299,7 +304,7 @@ TEST_F(ProxyResolverV8TracingTest, Dns) {
callback.callback(), NULL,
mock_bindings.CreateBindings());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// The test does 13 DNS resolution, however only 7 of them are unique.
EXPECT_EQ(7u, host_resolver.num_resolve());
@@ -351,7 +356,7 @@ TEST_F(ProxyResolverV8TracingTest, DnsChecksCache) {
callback1.callback(), NULL,
mock_bindings.CreateBindings());
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
// The test does 2 DNS resolutions.
EXPECT_EQ(2u, host_resolver.num_resolve());
@@ -363,7 +368,7 @@ TEST_F(ProxyResolverV8TracingTest, DnsChecksCache) {
callback2.callback(), NULL,
mock_bindings.CreateBindings());
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_EQ(4u, host_resolver.num_resolve());
@@ -395,7 +400,7 @@ TEST_F(ProxyResolverV8TracingTest, FallBackToSynchronous1) {
resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
callback.callback(), NULL,
mock_bindings.CreateBindings());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// The script itself only does 2 DNS resolves per execution, however it
// constructs the hostname using a global counter which changes on each
@@ -434,7 +439,7 @@ TEST_F(ProxyResolverV8TracingTest, FallBackToSynchronous2) {
resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
callback.callback(), NULL,
mock_bindings.CreateBindings());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(3u, host_resolver.num_resolve());
@@ -465,7 +470,7 @@ TEST_F(ProxyResolverV8TracingTest, InfiniteDNSSequence) {
resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
callback.callback(), NULL,
mock_bindings.CreateBindings());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(20u, host_resolver.num_resolve());
@@ -505,7 +510,7 @@ TEST_F(ProxyResolverV8TracingTest, InfiniteDNSSequence2) {
resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
callback.callback(), NULL,
mock_bindings.CreateBindings());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(20u, host_resolver.num_resolve());
@@ -545,7 +550,7 @@ void DnsDuringInitHelper(bool synchronous_host_resolver) {
resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
callback.callback(), NULL,
mock_bindings.CreateBindings());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// Fetched host1 and host2 again, since the ones done during initialization
// should not have been cached.
@@ -628,7 +633,7 @@ TEST_F(ProxyResolverV8TracingTest, CancelSome) {
resolver->CancelRequest(request1);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
}
// Cancel a request after it has finished running on the worker thread, and has
@@ -664,7 +669,7 @@ TEST_F(ProxyResolverV8TracingTest, CancelWhilePendingCompletionTask) {
&proxy_info2, callback.callback(), &request2,
mock_bindings.CreateBindings());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ("i-approve-this-message:42", proxy_info2.proxy_server().ToURI());
}
@@ -680,8 +685,8 @@ class BlockableHostResolver : public HostResolver {
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) override {
+ std::unique_ptr<Request>* out_req,
+ const NetLogWithSource& net_log) override {
EXPECT_FALSE(callback.is_null());
EXPECT_TRUE(out_req);
@@ -695,7 +700,7 @@ class BlockableHostResolver : public HostResolver {
// This line is intentionally after action_.Run(), since one of the
// tests does a cancellation inside of Resolve(), and it is more
// interesting if *out_req hasn't been written yet at that point.
- *out_req = reinterpret_cast<RequestHandle*>(1); // Magic value.
+ out_req->reset(new RequestImpl(this));
// Return ERR_IO_PENDING as this request will NEVER be completed.
// Expectation is for the caller to later cancel the request.
@@ -704,15 +709,12 @@ class BlockableHostResolver : public HostResolver {
int ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
NOTREACHED();
return ERR_DNS_CACHE_MISS;
}
- void CancelRequest(RequestHandle req) override {
- EXPECT_EQ(reinterpret_cast<RequestHandle*>(1), req);
- num_cancelled_requests_++;
- }
+ void IncreaseNumOfCancelledRequests() { num_cancelled_requests_++; }
void SetAction(const base::Callback<void(void)>& action) {
action_ = action;
@@ -731,6 +733,23 @@ class BlockableHostResolver : public HostResolver {
}
private:
+ class RequestImpl : public HostResolver::Request {
+ public:
+ RequestImpl(BlockableHostResolver* resolver) : resolver_(resolver) {}
+
+ ~RequestImpl() override {
+ if (resolver_)
+ resolver_->IncreaseNumOfCancelledRequests();
+ }
+
+ void ChangeRequestPriority(RequestPriority priority) override {}
+
+ private:
+ BlockableHostResolver* resolver_;
+
+ DISALLOW_COPY_AND_ASSIGN(RequestImpl);
+ };
+
int num_cancelled_requests_;
bool waiting_for_resolve_;
base::Callback<void(void)> action_;
@@ -880,7 +899,7 @@ TEST_F(ProxyResolverV8TracingTest, ErrorLoadingScript) {
LoadScriptData("error_on_load.js"), mock_bindings.CreateBindings(),
&resolver, callback.callback(), &request);
- EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_PAC_SCRIPT_FAILED));
EXPECT_FALSE(resolver);
}
@@ -902,7 +921,7 @@ TEST_F(ProxyResolverV8TracingTest, Terminate) {
resolver->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info,
callback.callback(), NULL,
mock_bindings.CreateBindings());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// The test does 2 DNS resolutions.
EXPECT_EQ(2u, host_resolver.num_resolve());
@@ -1003,7 +1022,7 @@ TEST_F(ProxyResolverV8TracingTest, MultipleResolvers) {
for (size_t i = 0; i < kNumResults; ++i) {
size_t resolver_i = i % kNumResolvers;
- EXPECT_EQ(OK, callback[i].WaitForResult());
+ EXPECT_THAT(callback[i].WaitForResult(), IsOk());
std::string proxy_uri = proxy_info[i].proxy_server().ToURI();
diff --git a/chromium/net/proxy/proxy_resolver_v8_tracing_wrapper.cc b/chromium/net/proxy/proxy_resolver_v8_tracing_wrapper.cc
index 8c23cab5e25..c99916cee16 100644
--- a/chromium/net/proxy/proxy_resolver_v8_tracing_wrapper.cc
+++ b/chromium/net/proxy/proxy_resolver_v8_tracing_wrapper.cc
@@ -13,9 +13,14 @@
#include "base/values.h"
#include "net/base/net_errors.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_parameters_callback.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_resolver_error_observer.h"
namespace net {
+
namespace {
// Returns event parameters for a PAC error message (line number + message).
@@ -34,24 +39,24 @@ class BindingsImpl : public ProxyResolverV8Tracing::Bindings {
BindingsImpl(ProxyResolverErrorObserver* error_observer,
HostResolver* host_resolver,
NetLog* net_log,
- const BoundNetLog& bound_net_log)
+ const NetLogWithSource& net_log_with_source)
: error_observer_(error_observer),
host_resolver_(host_resolver),
net_log_(net_log),
- bound_net_log_(bound_net_log) {}
+ net_log_with_source_(net_log_with_source) {}
// ProxyResolverV8Tracing::Bindings overrides.
void Alert(const base::string16& message) override {
// Send to the NetLog.
LogEventToCurrentRequestAndGlobally(
- NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
+ NetLogEventType::PAC_JAVASCRIPT_ALERT,
NetLog::StringCallback("message", &message));
}
void OnError(int line_number, const base::string16& message) override {
// Send the error to the NetLog.
LogEventToCurrentRequestAndGlobally(
- NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
+ NetLogEventType::PAC_JAVASCRIPT_ERROR,
base::Bind(&NetLogErrorCallback, line_number, &message));
if (error_observer_)
error_observer_->OnPACScriptError(line_number, message);
@@ -59,13 +64,15 @@ class BindingsImpl : public ProxyResolverV8Tracing::Bindings {
HostResolver* GetHostResolver() override { return host_resolver_; }
- BoundNetLog GetBoundNetLog() override { return bound_net_log_; }
+ NetLogWithSource GetNetLogWithSource() override {
+ return net_log_with_source_;
+ }
private:
void LogEventToCurrentRequestAndGlobally(
- NetLog::EventType type,
- const NetLog::ParametersCallback& parameters_callback) {
- bound_net_log_.AddEvent(type, parameters_callback);
+ NetLogEventType type,
+ const NetLogParametersCallback& parameters_callback) {
+ net_log_with_source_.AddEvent(type, parameters_callback);
// Emit to the global NetLog event stream.
if (net_log_)
@@ -75,7 +82,7 @@ class BindingsImpl : public ProxyResolverV8Tracing::Bindings {
ProxyResolverErrorObserver* error_observer_;
HostResolver* host_resolver_;
NetLog* net_log_;
- BoundNetLog bound_net_log_;
+ NetLogWithSource net_log_with_source_;
};
class ProxyResolverV8TracingWrapper : public ProxyResolver {
@@ -90,7 +97,7 @@ class ProxyResolverV8TracingWrapper : public ProxyResolver {
ProxyInfo* results,
const CompletionCallback& callback,
RequestHandle* request,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void CancelRequest(RequestHandle request) override;
@@ -120,7 +127,7 @@ int ProxyResolverV8TracingWrapper::GetProxyForURL(
ProxyInfo* results,
const CompletionCallback& callback,
RequestHandle* request,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
resolver_impl_->GetProxyForURL(
url, results, callback, request,
base::WrapUnique(new BindingsImpl(error_observer_.get(), host_resolver_,
@@ -170,7 +177,7 @@ int ProxyResolverFactoryV8TracingWrapper::CreateProxyResolver(
factory_impl_->CreateProxyResolverV8Tracing(
pac_script,
base::WrapUnique(new BindingsImpl(error_observer_local, host_resolver_,
- net_log_, BoundNetLog())),
+ net_log_, NetLogWithSource())),
v8_resolver_local,
base::Bind(&ProxyResolverFactoryV8TracingWrapper::OnProxyResolverCreated,
base::Unretained(this), base::Passed(&v8_resolver), resolver,
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 ea198067362..19ab3cd65a8 100644
--- a/chromium/net/proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc
+++ b/chromium/net/proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc
@@ -22,16 +22,22 @@
#include "net/base/test_completion_callback.h"
#include "net/dns/host_cache.h"
#include "net/dns/mock_host_resolver.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.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/proxy/proxy_info.h"
#include "net/proxy/proxy_resolver_error_observer.h"
#include "net/test/event_waiter.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -83,8 +89,8 @@ std::unique_ptr<ProxyResolver> CreateResolver(
std::unique_ptr<ProxyResolverFactory::Request> request;
int rv = factory.CreateProxyResolver(LoadScriptData(filename), &resolver,
callback.callback(), &request);
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(resolver);
return resolver;
}
@@ -134,8 +140,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, Simple) {
resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
callback.callback(), NULL, request_log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ("foo:99", proxy_info.proxy_server().ToURI());
@@ -165,8 +171,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, JavascriptError) {
resolver->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info,
callback.callback(), NULL, request_log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_PAC_SCRIPT_FAILED));
EXPECT_EQ(0u, host_resolver.num_resolve());
@@ -184,10 +190,12 @@ TEST_F(ProxyResolverV8TracingWrapperTest, JavascriptError) {
for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
const TestNetLogEntry::List& entries = entries_list[list_i];
EXPECT_EQ(2u, entries.size());
- EXPECT_TRUE(LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEvent(entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
- NetLog::PHASE_NONE));
+ EXPECT_TRUE(LogContainsEvent(entries, 0,
+ NetLogEventType::PAC_JAVASCRIPT_ALERT,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEvent(entries, 1,
+ NetLogEventType::PAC_JAVASCRIPT_ERROR,
+ NetLogEventPhase::NONE));
EXPECT_EQ("{\"message\":\"Prepare to DIE!\"}", entries[0].GetParamsJson());
EXPECT_EQ(
@@ -214,8 +222,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, TooManyAlerts) {
resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
callback.callback(), NULL, request_log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// Iteration1 does a DNS resolve
// Iteration2 exceeds the alert buffer
@@ -237,8 +245,9 @@ TEST_F(ProxyResolverV8TracingWrapperTest, TooManyAlerts) {
const TestNetLogEntry::List& entries = entries_list[list_i];
EXPECT_EQ(50u, entries.size());
for (size_t i = 0; i < entries.size(); ++i) {
- ASSERT_TRUE(LogContainsEvent(
- entries, i, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, NetLog::PHASE_NONE));
+ ASSERT_TRUE(LogContainsEvent(entries, i,
+ NetLogEventType::PAC_JAVASCRIPT_ALERT,
+ NetLogEventPhase::NONE));
}
}
}
@@ -262,8 +271,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, TooManyEmptyAlerts) {
resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
callback.callback(), NULL, request_log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ("foo:3", proxy_info.proxy_server().ToURI());
@@ -282,8 +291,9 @@ TEST_F(ProxyResolverV8TracingWrapperTest, TooManyEmptyAlerts) {
const TestNetLogEntry::List& entries = entries_list[list_i];
EXPECT_EQ(1000u, entries.size());
for (size_t i = 0; i < entries.size(); ++i) {
- ASSERT_TRUE(LogContainsEvent(
- entries, i, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, NetLog::PHASE_NONE));
+ ASSERT_TRUE(LogContainsEvent(entries, i,
+ NetLogEventType::PAC_JAVASCRIPT_ALERT,
+ NetLogEventPhase::NONE));
}
}
}
@@ -319,8 +329,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, Dns) {
resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
callback.callback(), NULL, request_log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// The test does 13 DNS resolution, however only 7 of them are unique.
EXPECT_EQ(7u, host_resolver.num_resolve());
@@ -355,8 +365,9 @@ TEST_F(ProxyResolverV8TracingWrapperTest, Dns) {
for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
const TestNetLogEntry::List& entries = entries_list[list_i];
EXPECT_EQ(1u, entries.size());
- EXPECT_TRUE(LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
- NetLog::PHASE_NONE));
+ EXPECT_TRUE(LogContainsEvent(entries, 0,
+ NetLogEventType::PAC_JAVASCRIPT_ALERT,
+ NetLogEventPhase::NONE));
EXPECT_EQ("{\"message\":\"iteration: 7\"}", entries[0].GetParamsJson());
}
}
@@ -384,8 +395,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, DnsChecksCache) {
resolver->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info,
callback1.callback(), NULL, request_log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
// The test does 2 DNS resolutions.
EXPECT_EQ(2u, host_resolver.num_resolve());
@@ -397,8 +408,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, DnsChecksCache) {
resolver->GetProxyForURL(GURL("http://foopy/req2"), &proxy_info,
callback2.callback(), NULL, request_log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_EQ(4u, host_resolver.num_resolve());
@@ -435,8 +446,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, FallBackToSynchronous1) {
int rv =
resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
callback.callback(), NULL, request_log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// The script itself only does 2 DNS resolves per execution, however it
// constructs the hostname using a global counter which changes on each
@@ -458,8 +469,9 @@ TEST_F(ProxyResolverV8TracingWrapperTest, FallBackToSynchronous1) {
for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
const TestNetLogEntry::List& entries = entries_list[list_i];
EXPECT_EQ(1u, entries.size());
- EXPECT_TRUE(LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
- NetLog::PHASE_NONE));
+ EXPECT_TRUE(LogContainsEvent(entries, 0,
+ NetLogEventType::PAC_JAVASCRIPT_ALERT,
+ NetLogEventPhase::NONE));
EXPECT_EQ("{\"message\":\"iteration: 4\"}", entries[0].GetParamsJson());
}
}
@@ -489,8 +501,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, FallBackToSynchronous2) {
int rv =
resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
callback.callback(), NULL, request_log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(3u, host_resolver.num_resolve());
@@ -527,8 +539,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, InfiniteDNSSequence) {
int rv =
resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
callback.callback(), NULL, request_log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(20u, host_resolver.num_resolve());
@@ -572,8 +584,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, InfiniteDNSSequence2) {
int rv =
resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
callback.callback(), NULL, request_log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(20u, host_resolver.num_resolve());
@@ -616,8 +628,8 @@ void DnsDuringInitHelper(bool synchronous_host_resolver) {
int rv =
resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
callback.callback(), NULL, request_log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// Fetched host1 and host2 again, since the ones done during initialization
// should not have been cached.
@@ -632,10 +644,12 @@ void DnsDuringInitHelper(bool synchronous_host_resolver) {
log.GetEntries(&entries);
ASSERT_EQ(2u, entries.size());
- EXPECT_TRUE(LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEvent(entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
- NetLog::PHASE_NONE));
+ EXPECT_TRUE(LogContainsEvent(entries, 0,
+ NetLogEventType::PAC_JAVASCRIPT_ALERT,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEvent(entries, 1,
+ NetLogEventType::PAC_JAVASCRIPT_ALERT,
+ NetLogEventPhase::NONE));
EXPECT_EQ("{\"message\":\"Watsup\"}", entries[0].GetParamsJson());
EXPECT_EQ("{\"message\":\"Watsup2\"}", entries[1].GetParamsJson());
@@ -674,8 +688,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, CancelAll) {
for (size_t i = 0; i < kNumRequests; ++i) {
int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info[i],
base::Bind(&CrashCallback), &request[i],
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
}
for (size_t i = 0; i < kNumRequests; ++i) {
@@ -703,16 +717,17 @@ TEST_F(ProxyResolverV8TracingWrapperTest, CancelSome) {
int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info1,
base::Bind(&CrashCallback), &request1,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info2,
- callback.callback(), &request2, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &request2,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
resolver->CancelRequest(request1);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
}
// Cancel a request after it has finished running on the worker thread, and has
@@ -734,8 +749,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, CancelWhilePendingCompletionTask) {
int rv = resolver->GetProxyForURL(GURL("http://throw-an-error/"),
&proxy_info1, base::Bind(&CrashCallback),
- &request1, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ &request1, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Wait until the first request has finished running on the worker thread.
// Cancel the first request, while it has a pending completion task on
@@ -747,10 +762,10 @@ TEST_F(ProxyResolverV8TracingWrapperTest, CancelWhilePendingCompletionTask) {
// Start another request, to make sure it is able to complete.
rv = resolver->GetProxyForURL(GURL("http://i-have-no-idea-what-im-doing/"),
&proxy_info2, callback.callback(), &request2,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ("i-approve-this-message:42", proxy_info2.proxy_server().ToURI());
}
@@ -766,8 +781,8 @@ class BlockableHostResolver : public HostResolver {
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) override {
+ std::unique_ptr<Request>* out_req,
+ const NetLogWithSource& net_log) override {
EXPECT_FALSE(callback.is_null());
EXPECT_TRUE(out_req);
@@ -781,7 +796,7 @@ class BlockableHostResolver : public HostResolver {
// This line is intentionally after action_.Run(), since one of the
// tests does a cancellation inside of Resolve(), and it is more
// interesting if *out_req hasn't been written yet at that point.
- *out_req = reinterpret_cast<RequestHandle*>(1); // Magic value.
+ out_req->reset(new RequestImpl(this));
// Return ERR_IO_PENDING as this request will NEVER be completed.
// Expectation is for the caller to later cancel the request.
@@ -790,15 +805,12 @@ class BlockableHostResolver : public HostResolver {
int ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
NOTREACHED();
return ERR_DNS_CACHE_MISS;
}
- void CancelRequest(RequestHandle req) override {
- EXPECT_EQ(reinterpret_cast<RequestHandle*>(1), req);
- num_cancelled_requests_++;
- }
+ void IncreaseNumOfCancelledRequests() { num_cancelled_requests_++; }
void SetAction(const base::Callback<void(void)>& action) { action_ = action; }
@@ -813,6 +825,23 @@ class BlockableHostResolver : public HostResolver {
int num_cancelled_requests() const { return num_cancelled_requests_; }
private:
+ class RequestImpl : public HostResolver::Request {
+ public:
+ RequestImpl(BlockableHostResolver* resolver) : resolver_(resolver) {}
+
+ ~RequestImpl() override {
+ if (resolver_)
+ resolver_->IncreaseNumOfCancelledRequests();
+ }
+
+ void ChangeRequestPriority(RequestPriority priority) override {}
+
+ private:
+ BlockableHostResolver* resolver_;
+
+ DISALLOW_COPY_AND_ASSIGN(RequestImpl);
+ };
+
int num_cancelled_requests_;
bool waiting_for_resolve_;
base::Callback<void(void)> action_;
@@ -835,17 +864,17 @@ TEST_F(ProxyResolverV8TracingWrapperTest,
int rv = resolver->GetProxyForURL(GURL("http://foo/req1"), &proxy_info1,
base::Bind(&CrashCallback), &request1,
- BoundNetLog());
+ NetLogWithSource());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
host_resolver.WaitUntilRequestIsReceived();
rv = resolver->GetProxyForURL(GURL("http://foo/req2"), &proxy_info2,
base::Bind(&CrashCallback), &request2,
- BoundNetLog());
+ NetLogWithSource());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
host_resolver.WaitUntilRequestIsReceived();
@@ -884,9 +913,9 @@ TEST_F(ProxyResolverV8TracingWrapperTest, CancelWhileBlockedInNonBlockingDns) {
int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
base::Bind(&CrashCallback), &request,
- BoundNetLog());
+ NetLogWithSource());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
host_resolver.SetAction(
base::Bind(CancelRequestAndPause, resolver.get(), request));
@@ -908,9 +937,9 @@ TEST_F(ProxyResolverV8TracingWrapperTest, CancelWhileBlockedInNonBlockingDns2) {
int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info,
base::Bind(&CrashCallback), &request,
- BoundNetLog());
+ NetLogWithSource());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Wait a bit, so the DNS task has hopefully been posted. The test will
// work whatever the delay is here, but it is most useful if the delay
@@ -936,7 +965,7 @@ TEST_F(ProxyResolverV8TracingWrapperTest,
int rv = factory.CreateProxyResolver(LoadScriptData("dns_during_init.js"),
&resolver, base::Bind(&CrashCallback),
&request);
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
host_resolver.WaitUntilRequestIsReceived();
@@ -960,7 +989,7 @@ TEST_F(ProxyResolverV8TracingWrapperTest,
int rv = factory.CreateProxyResolver(LoadScriptData("dns_during_init.js"),
&resolver, base::Bind(&CrashCallback),
&request);
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
host_resolver.WaitUntilRequestIsReceived();
}
EXPECT_EQ(1, host_resolver.num_cancelled_requests());
@@ -981,8 +1010,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, ErrorLoadingScript) {
int rv =
factory.CreateProxyResolver(LoadScriptData("error_on_load.js"), &resolver,
callback.callback(), &request);
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_PAC_SCRIPT_FAILED));
EXPECT_FALSE(resolver);
}
@@ -1007,8 +1036,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, Terminate) {
resolver->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info,
callback.callback(), NULL, request_log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// The test does 2 DNS resolutions.
EXPECT_EQ(2u, host_resolver.num_resolve());
@@ -1088,8 +1117,8 @@ TEST_F(ProxyResolverV8TracingWrapperTest, MultipleResolvers) {
size_t resolver_i = i % kNumResolvers;
int rv = resolver[resolver_i]->GetProxyForURL(
GURL("http://foo/"), &proxy_info[i], callback[i].callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
}
// ------------------------
@@ -1114,7 +1143,7 @@ TEST_F(ProxyResolverV8TracingWrapperTest, MultipleResolvers) {
for (size_t i = 0; i < kNumResults; ++i) {
size_t resolver_i = i % kNumResolvers;
- EXPECT_EQ(OK, callback[i].WaitForResult());
+ EXPECT_THAT(callback[i].WaitForResult(), IsOk());
std::string proxy_uri = proxy_info[i].proxy_server().ToURI();
diff --git a/chromium/net/proxy/proxy_resolver_v8_unittest.cc b/chromium/net/proxy/proxy_resolver_v8_unittest.cc
index 93243e6794d..d6f5215968c 100644
--- a/chromium/net/proxy/proxy_resolver_v8_unittest.cc
+++ b/chromium/net/proxy/proxy_resolver_v8_unittest.cc
@@ -13,9 +13,14 @@
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_resolver_script_data.h"
#include "net/proxy/proxy_resolver_v8.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -140,12 +145,12 @@ const GURL kQueryUrl("http://www.google.com");
const GURL kPacUrl;
TEST_F(ProxyResolverV8Test, Direct) {
- ASSERT_EQ(OK, CreateResolver("direct.js"));
+ ASSERT_THAT(CreateResolver("direct.js"), IsOk());
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(kQueryUrl, &proxy_info, bindings());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
EXPECT_TRUE(proxy_info.is_direct());
EXPECT_EQ(0U, bindings()->alerts.size());
@@ -153,12 +158,12 @@ TEST_F(ProxyResolverV8Test, Direct) {
}
TEST_F(ProxyResolverV8Test, ReturnEmptyString) {
- ASSERT_EQ(OK, CreateResolver("return_empty_string.js"));
+ ASSERT_THAT(CreateResolver("return_empty_string.js"), IsOk());
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(kQueryUrl, &proxy_info, bindings());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
EXPECT_TRUE(proxy_info.is_direct());
EXPECT_EQ(0U, bindings()->alerts.size());
@@ -166,7 +171,7 @@ TEST_F(ProxyResolverV8Test, ReturnEmptyString) {
}
TEST_F(ProxyResolverV8Test, Basic) {
- ASSERT_EQ(OK, CreateResolver("passthrough.js"));
+ ASSERT_THAT(CreateResolver("passthrough.js"), IsOk());
// The "FindProxyForURL" of this PAC script simply concatenates all of the
// arguments into a pseudo-host. The purpose of this test is to verify that
@@ -175,7 +180,7 @@ TEST_F(ProxyResolverV8Test, Basic) {
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(GURL("http://query.com/path"),
&proxy_info, bindings());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
EXPECT_EQ("http.query.com.path.query.com:80",
proxy_info.proxy_server().ToURI());
}
@@ -183,7 +188,7 @@ TEST_F(ProxyResolverV8Test, Basic) {
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(GURL("ftp://query.com:90/path"),
&proxy_info, bindings());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
// Note that FindProxyForURL(url, host) does not expect |host| to contain
// the port number.
EXPECT_EQ("ftp.query.com.90.path.query.com:80",
@@ -207,13 +212,13 @@ TEST_F(ProxyResolverV8Test, BadReturnType) {
"return_null.js"};
for (size_t i = 0; i < arraysize(filenames); ++i) {
- ASSERT_EQ(OK, CreateResolver(filenames[i]));
+ ASSERT_THAT(CreateResolver(filenames[i]), IsOk());
MockJSBindings bindings;
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(kQueryUrl, &proxy_info, &bindings);
- EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, result);
+ EXPECT_THAT(result, IsError(ERR_PAC_SCRIPT_FAILED));
EXPECT_EQ(0U, bindings.alerts.size());
ASSERT_EQ(1U, bindings.errors.size());
@@ -224,7 +229,8 @@ TEST_F(ProxyResolverV8Test, BadReturnType) {
// Try using a PAC script which defines no "FindProxyForURL" function.
TEST_F(ProxyResolverV8Test, NoEntryPoint) {
- EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, CreateResolver("no_entrypoint.js"));
+ EXPECT_THAT(CreateResolver("no_entrypoint.js"),
+ IsError(ERR_PAC_SCRIPT_FAILED));
ASSERT_EQ(1U, bindings()->errors.size());
EXPECT_EQ("FindProxyForURL is undefined or not a function.",
@@ -234,7 +240,8 @@ TEST_F(ProxyResolverV8Test, NoEntryPoint) {
// Try loading a malformed PAC script.
TEST_F(ProxyResolverV8Test, ParseError) {
- EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, CreateResolver("missing_close_brace.js"));
+ EXPECT_THAT(CreateResolver("missing_close_brace.js"),
+ IsError(ERR_PAC_SCRIPT_FAILED));
EXPECT_EQ(0U, bindings()->alerts.size());
@@ -248,25 +255,25 @@ TEST_F(ProxyResolverV8Test, ParseError) {
// Run a PAC script several times, which has side-effects.
TEST_F(ProxyResolverV8Test, SideEffects) {
- ASSERT_EQ(OK, CreateResolver("side_effects.js"));
+ ASSERT_THAT(CreateResolver("side_effects.js"), IsOk());
// The PAC script increments a counter each time we invoke it.
for (int i = 0; i < 3; ++i) {
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(kQueryUrl, &proxy_info, bindings());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
EXPECT_EQ(base::StringPrintf("sideffect_%d:80", i),
proxy_info.proxy_server().ToURI());
}
// Reload the script -- the javascript environment should be reset, hence
// the counter starts over.
- ASSERT_EQ(OK, CreateResolver("side_effects.js"));
+ ASSERT_THAT(CreateResolver("side_effects.js"), IsOk());
for (int i = 0; i < 3; ++i) {
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(kQueryUrl, &proxy_info, bindings());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
EXPECT_EQ(base::StringPrintf("sideffect_%d:80", i),
proxy_info.proxy_server().ToURI());
}
@@ -274,12 +281,12 @@ TEST_F(ProxyResolverV8Test, SideEffects) {
// Execute a PAC script which throws an exception in FindProxyForURL.
TEST_F(ProxyResolverV8Test, UnhandledException) {
- ASSERT_EQ(OK, CreateResolver("unhandled_exception.js"));
+ ASSERT_THAT(CreateResolver("unhandled_exception.js"), IsOk());
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(kQueryUrl, &proxy_info, bindings());
- EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, result);
+ EXPECT_THAT(result, IsError(ERR_PAC_SCRIPT_FAILED));
EXPECT_EQ(0U, bindings()->alerts.size());
ASSERT_EQ(1U, bindings()->errors.size());
@@ -305,12 +312,13 @@ TEST_F(ProxyResolverV8Test, ExceptionAccessingFindProxyForURLDuringInit) {
// Execute a PAC script which throws an exception during the second access to
// FindProxyForURL
TEST_F(ProxyResolverV8Test, ExceptionAccessingFindProxyForURLDuringResolve) {
- ASSERT_EQ(OK, CreateResolver("exception_findproxyforurl_during_resolve.js"));
+ ASSERT_THAT(CreateResolver("exception_findproxyforurl_during_resolve.js"),
+ IsOk());
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(kQueryUrl, &proxy_info, bindings());
- EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, result);
+ EXPECT_THAT(result, IsError(ERR_PAC_SCRIPT_FAILED));
ASSERT_EQ(2U, bindings()->errors.size());
EXPECT_EQ("Uncaught crash!", bindings()->errors[0]);
@@ -321,26 +329,26 @@ TEST_F(ProxyResolverV8Test, ExceptionAccessingFindProxyForURLDuringResolve) {
}
TEST_F(ProxyResolverV8Test, ReturnUnicode) {
- ASSERT_EQ(OK, CreateResolver("return_unicode.js"));
+ ASSERT_THAT(CreateResolver("return_unicode.js"), IsOk());
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(kQueryUrl, &proxy_info, bindings());
// The result from this resolve was unparseable, because it
// wasn't ASCII.
- EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, result);
+ EXPECT_THAT(result, IsError(ERR_PAC_SCRIPT_FAILED));
}
// Test the PAC library functions that we expose in the JS environment.
TEST_F(ProxyResolverV8Test, JavascriptLibrary) {
- ASSERT_EQ(OK, CreateResolver("pac_library_unittest.js"));
+ ASSERT_THAT(CreateResolver("pac_library_unittest.js"), IsOk());
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(kQueryUrl, &proxy_info, bindings());
// If the javascript side of this unit-test fails, it will throw a javascript
// exception. Otherwise it will return "PROXY success:80".
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
EXPECT_EQ("success:80", proxy_info.proxy_server().ToURI());
EXPECT_EQ(0U, bindings()->alerts.size());
@@ -349,13 +357,13 @@ TEST_F(ProxyResolverV8Test, JavascriptLibrary) {
// Test marshalling/un-marshalling of values between C++/V8.
TEST_F(ProxyResolverV8Test, V8Bindings) {
- ASSERT_EQ(OK, CreateResolver("bindings.js"));
+ ASSERT_THAT(CreateResolver("bindings.js"), IsOk());
bindings()->dns_resolve_result = "127.0.0.1";
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(kQueryUrl, &proxy_info, bindings());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
EXPECT_TRUE(proxy_info.is_direct());
EXPECT_EQ(0U, bindings()->errors.size());
@@ -389,7 +397,7 @@ TEST_F(ProxyResolverV8Test, V8Bindings) {
// Test calling a binding (myIpAddress()) from the script's global scope.
// http://crbug.com/40026
TEST_F(ProxyResolverV8Test, BindingCalledDuringInitialization) {
- ASSERT_EQ(OK, CreateResolver("binding_from_global.js"));
+ ASSERT_THAT(CreateResolver("binding_from_global.js"), IsOk());
// myIpAddress() got called during initialization of the script.
EXPECT_EQ(1, bindings()->my_ip_address_count);
@@ -397,7 +405,7 @@ TEST_F(ProxyResolverV8Test, BindingCalledDuringInitialization) {
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(kQueryUrl, &proxy_info, bindings());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
EXPECT_FALSE(proxy_info.is_direct());
EXPECT_EQ("127.0.0.1:80", proxy_info.proxy_server().ToURI());
@@ -414,12 +422,12 @@ TEST_F(ProxyResolverV8Test, BindingCalledDuringInitialization) {
// that we add to the script's environment.
// http://crbug.com/22864
TEST_F(ProxyResolverV8Test, EndsWithCommentNoNewline) {
- ASSERT_EQ(OK, CreateResolver("ends_with_comment.js"));
+ ASSERT_THAT(CreateResolver("ends_with_comment.js"), IsOk());
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(kQueryUrl, &proxy_info, bindings());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
EXPECT_FALSE(proxy_info.is_direct());
EXPECT_EQ("success:80", proxy_info.proxy_server().ToURI());
}
@@ -429,12 +437,12 @@ TEST_F(ProxyResolverV8Test, EndsWithCommentNoNewline) {
// that we add to the script's environment.
// http://crbug.com/22864
TEST_F(ProxyResolverV8Test, EndsWithStatementNoNewline) {
- ASSERT_EQ(OK, CreateResolver("ends_with_statement_no_semicolon.js"));
+ ASSERT_THAT(CreateResolver("ends_with_statement_no_semicolon.js"), IsOk());
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(kQueryUrl, &proxy_info, bindings());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
EXPECT_FALSE(proxy_info.is_direct());
EXPECT_EQ("success:3", proxy_info.proxy_server().ToURI());
}
@@ -444,24 +452,24 @@ TEST_F(ProxyResolverV8Test, EndsWithStatementNoNewline) {
// returns empty string (failure). This simulates the return values from
// those functions when the underlying DNS resolution fails.
TEST_F(ProxyResolverV8Test, DNSResolutionFailure) {
- ASSERT_EQ(OK, CreateResolver("dns_fail.js"));
+ ASSERT_THAT(CreateResolver("dns_fail.js"), IsOk());
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(kQueryUrl, &proxy_info, bindings());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
EXPECT_FALSE(proxy_info.is_direct());
EXPECT_EQ("success:80", proxy_info.proxy_server().ToURI());
}
TEST_F(ProxyResolverV8Test, DNSResolutionOfInternationDomainName) {
- ASSERT_EQ(OK, CreateResolver("international_domain_names.js"));
+ ASSERT_THAT(CreateResolver("international_domain_names.js"), IsOk());
// Execute FindProxyForURL().
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(kQueryUrl, &proxy_info, bindings());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
EXPECT_TRUE(proxy_info.is_direct());
// Check that the international domain name was converted to punycode
@@ -478,13 +486,13 @@ TEST_F(ProxyResolverV8Test, DNSResolutionOfInternationDomainName) {
// If we don't do this, then subsequent calls to dnsResolveEx(host) will be
// doomed to fail since it won't correspond with a valid name.
TEST_F(ProxyResolverV8Test, IPv6HostnamesNotBracketed) {
- ASSERT_EQ(OK, CreateResolver("resolve_host.js"));
+ ASSERT_THAT(CreateResolver("resolve_host.js"), IsOk());
ProxyInfo proxy_info;
int result = resolver().GetProxyForURL(
GURL("http://[abcd::efff]:99/watsupdawg"), &proxy_info, bindings());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
EXPECT_TRUE(proxy_info.is_direct());
// We called dnsResolveEx() exactly once, by passing through the "host"
@@ -497,7 +505,7 @@ TEST_F(ProxyResolverV8Test, IPv6HostnamesNotBracketed) {
// termination of the script. Also test that repeatedly calling terminate is
// safe, and running the script again after termination still works.
TEST_F(ProxyResolverV8Test, Terminate) {
- ASSERT_EQ(OK, CreateResolver("terminate.js"));
+ ASSERT_THAT(CreateResolver("terminate.js"), IsOk());
// Terminate script execution upon reaching dnsResolve(). Note that
// termination may not take effect right away (so the subsequent dnsResolve()
@@ -509,7 +517,7 @@ TEST_F(ProxyResolverV8Test, Terminate) {
resolver().GetProxyForURL(GURL("http://hang/"), &proxy_info, bindings());
// The script execution was terminated.
- EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, result);
+ EXPECT_THAT(result, IsError(ERR_PAC_SCRIPT_FAILED));
EXPECT_EQ(1U, bindings()->dns_resolves.size());
EXPECT_GE(2U, bindings()->dns_resolves_ex.size());
@@ -527,7 +535,7 @@ TEST_F(ProxyResolverV8Test, Terminate) {
result = resolver().GetProxyForURL(GURL("http://kittens/"), &proxy_info,
bindings());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
EXPECT_EQ(0u, bindings()->errors.size());
EXPECT_EQ("kittens:88", proxy_info.proxy_server().ToURI());
}
diff --git a/chromium/net/proxy/proxy_resolver_winhttp.cc b/chromium/net/proxy/proxy_resolver_winhttp.cc
index b1d3ce356d2..6f184c7561d 100644
--- a/chromium/net/proxy/proxy_resolver_winhttp.cc
+++ b/chromium/net/proxy/proxy_resolver_winhttp.cc
@@ -61,7 +61,7 @@ class ProxyResolverWinHttp : public ProxyResolver {
ProxyInfo* results,
const CompletionCallback& /*callback*/,
RequestHandle* /*request*/,
- const BoundNetLog& /*net_log*/) override;
+ const NetLogWithSource& /*net_log*/) override;
void CancelRequest(RequestHandle request) override;
LoadState GetLoadState(RequestHandle request) const override;
@@ -94,7 +94,7 @@ int ProxyResolverWinHttp::GetProxyForURL(const GURL& query_url,
ProxyInfo* results,
const CompletionCallback& /*callback*/,
RequestHandle* /*request*/,
- const BoundNetLog& /*net_log*/) {
+ const NetLogWithSource& /*net_log*/) {
// If we don't have a WinHTTP session, then create a new one.
if (!session_handle_ && !OpenWinHttpSession())
return ERR_FAILED;
diff --git a/chromium/net/proxy/proxy_script_decider.cc b/chromium/net/proxy/proxy_script_decider.cc
index 7695b4cbc36..761d69d96cb 100644
--- a/chromium/net/proxy/proxy_script_decider.cc
+++ b/chromium/net/proxy/proxy_script_decider.cc
@@ -16,6 +16,9 @@
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "net/base/net_errors.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source_type.h"
#include "net/proxy/dhcp_proxy_script_fetcher.h"
#include "net/proxy/dhcp_proxy_script_fetcher_factory.h"
#include "net/proxy/proxy_script_fetcher.h"
@@ -86,14 +89,15 @@ ProxyScriptDecider::ProxyScriptDecider(
current_pac_source_index_(0u),
pac_mandatory_(false),
next_state_(STATE_NONE),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_PROXY_SCRIPT_DECIDER)),
+ net_log_(NetLogWithSource::Make(net_log,
+ NetLogSourceType::PROXY_SCRIPT_DECIDER)),
fetch_pac_bytes_(false),
- quick_check_enabled_(true) {
+ quick_check_enabled_(true),
+ host_resolver_(nullptr) {
if (proxy_script_fetcher &&
proxy_script_fetcher->GetRequestContext() &&
proxy_script_fetcher->GetRequestContext()->host_resolver()) {
- host_resolver_.reset(new SingleRequestHostResolver(
- proxy_script_fetcher->GetRequestContext()->host_resolver()));
+ host_resolver_ = proxy_script_fetcher->GetRequestContext()->host_resolver();
}
}
@@ -109,7 +113,7 @@ int ProxyScriptDecider::Start(
DCHECK(!callback.is_null());
DCHECK(config.HasAutomaticSettings());
- net_log_.BeginEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER);
+ net_log_.BeginEvent(NetLogEventType::PROXY_SCRIPT_DECIDER);
fetch_pac_bytes_ = fetch_pac_bytes;
@@ -232,15 +236,15 @@ int ProxyScriptDecider::DoWait() {
// Otherwise wait the specified amount of time.
wait_timer_.Start(FROM_HERE, wait_delay_, this,
&ProxyScriptDecider::OnWaitTimerFired);
- net_log_.BeginEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT);
+ net_log_.BeginEvent(NetLogEventType::PROXY_SCRIPT_DECIDER_WAIT);
return ERR_IO_PENDING;
}
int ProxyScriptDecider::DoWaitComplete(int result) {
DCHECK_EQ(OK, result);
if (wait_delay_.ToInternalValue() != 0) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT,
- result);
+ net_log_.EndEventWithNetErrorCode(
+ NetLogEventType::PROXY_SCRIPT_DECIDER_WAIT, result);
}
if (quick_check_enabled_ && current_pac_source().type == PacSource::WPAD_DNS)
next_state_ = STATE_QUICK_CHECK;
@@ -251,7 +255,7 @@ int ProxyScriptDecider::DoWaitComplete(int result) {
int ProxyScriptDecider::DoQuickCheck() {
DCHECK(quick_check_enabled_);
- if (host_resolver_.get() == NULL) {
+ if (host_resolver_ == nullptr) {
// If we have no resolver, skip QuickCheck altogether.
next_state_ = GetStartState();
return OK;
@@ -272,8 +276,8 @@ int ProxyScriptDecider::DoQuickCheck() {
base::Bind(callback, ERR_NAME_NOT_RESOLVED));
// We use HIGHEST here because proxy decision blocks doing any other requests.
- return host_resolver_->Resolve(reqinfo, HIGHEST, &wpad_addresses_,
- callback, net_log_);
+ return host_resolver_->Resolve(reqinfo, HIGHEST, &wpad_addresses_, callback,
+ &request_, net_log_);
}
int ProxyScriptDecider::DoQuickCheckComplete(int result) {
@@ -283,7 +287,7 @@ int ProxyScriptDecider::DoQuickCheckComplete(int result) {
UMA_HISTOGRAM_TIMES("Net.WpadQuickCheckSuccess", delta);
else
UMA_HISTOGRAM_TIMES("Net.WpadQuickCheckFailure", delta);
- host_resolver_->Cancel();
+ request_.reset();
quick_check_timer_.Stop();
if (result != OK)
return TryToFallbackPacSource(result);
@@ -301,14 +305,14 @@ int ProxyScriptDecider::DoFetchPacScript() {
GURL effective_pac_url;
DetermineURL(pac_source, &effective_pac_url);
- net_log_.BeginEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT,
- base::Bind(&PacSource::NetLogCallback,
- base::Unretained(&pac_source),
- &effective_pac_url));
+ net_log_.BeginEvent(
+ NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT,
+ base::Bind(&PacSource::NetLogCallback, base::Unretained(&pac_source),
+ &effective_pac_url));
if (pac_source.type == PacSource::WPAD_DHCP) {
if (!dhcp_proxy_script_fetcher_) {
- net_log_.AddEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER_HAS_NO_FETCHER);
+ net_log_.AddEvent(NetLogEventType::PROXY_SCRIPT_DECIDER_HAS_NO_FETCHER);
return ERR_UNEXPECTED;
}
@@ -318,7 +322,7 @@ int ProxyScriptDecider::DoFetchPacScript() {
}
if (!proxy_script_fetcher_) {
- net_log_.AddEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER_HAS_NO_FETCHER);
+ net_log_.AddEvent(NetLogEventType::PROXY_SCRIPT_DECIDER_HAS_NO_FETCHER);
return ERR_UNEXPECTED;
}
@@ -331,7 +335,7 @@ int ProxyScriptDecider::DoFetchPacScriptComplete(int result) {
DCHECK(fetch_pac_bytes_);
net_log_.EndEventWithNetErrorCode(
- NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT, result);
+ NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT, result);
if (result != OK)
return TryToFallbackPacSource(result);
@@ -412,7 +416,7 @@ int ProxyScriptDecider::TryToFallbackPacSource(int error) {
++current_pac_source_index_;
net_log_.AddEvent(
- NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE);
+ NetLogEventType::PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE);
if (quick_check_enabled_ && current_pac_source().type == PacSource::WPAD_DNS)
next_state_ = STATE_QUICK_CHECK;
else
@@ -452,13 +456,13 @@ void ProxyScriptDecider::OnWaitTimerFired() {
}
void ProxyScriptDecider::DidComplete() {
- net_log_.EndEvent(NetLog::TYPE_PROXY_SCRIPT_DECIDER);
+ net_log_.EndEvent(NetLogEventType::PROXY_SCRIPT_DECIDER);
}
void ProxyScriptDecider::Cancel() {
DCHECK_NE(STATE_NONE, next_state_);
- net_log_.AddEvent(NetLog::TYPE_CANCELLED);
+ net_log_.AddEvent(NetLogEventType::CANCELLED);
switch (next_state_) {
case STATE_WAIT_COMPLETE:
diff --git a/chromium/net/proxy/proxy_script_decider.h b/chromium/net/proxy/proxy_script_decider.h
index e405acf460b..7e4177b0f73 100644
--- a/chromium/net/proxy/proxy_script_decider.h
+++ b/chromium/net/proxy/proxy_script_decider.h
@@ -19,15 +19,20 @@
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
#include "net/dns/host_resolver.h"
-#include "net/dns/single_request_host_resolver.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_resolver.h"
#include "url/gurl.h"
+namespace base {
+class Value;
+}
+
namespace net {
class DhcpProxyScriptFetcher;
+class NetLog;
+class NetLogCaptureMode;
class NetLogParameter;
class ProxyResolver;
class ProxyScriptFetcher;
@@ -183,7 +188,7 @@ class NET_EXPORT_PRIVATE ProxyScriptDecider {
PacSourceList pac_sources_;
State next_state_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
bool fetch_pac_bytes_;
@@ -199,7 +204,8 @@ class NET_EXPORT_PRIVATE ProxyScriptDecider {
AddressList wpad_addresses_;
base::OneShotTimer quick_check_timer_;
- std::unique_ptr<SingleRequestHostResolver> host_resolver_;
+ HostResolver* host_resolver_;
+ std::unique_ptr<HostResolver::Request> request_;
base::Time quick_check_start_time_;
DISALLOW_COPY_AND_ASSIGN(ProxyScriptDecider);
diff --git a/chromium/net/proxy/proxy_script_decider_unittest.cc b/chromium/net/proxy/proxy_script_decider_unittest.cc
index 94eb14ab0e0..dfcfeda300a 100644
--- a/chromium/net/proxy/proxy_script_decider_unittest.cc
+++ b/chromium/net/proxy/proxy_script_decider_unittest.cc
@@ -17,7 +17,7 @@
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/dns/mock_host_resolver.h"
-#include "net/log/net_log.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"
@@ -27,9 +27,14 @@
#include "net/proxy/proxy_resolver.h"
#include "net/proxy/proxy_script_decider.h"
#include "net/proxy/proxy_script_fetcher.h"
+#include "net/test/gtest_util.h"
#include "net/url_request/url_request_context.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -204,14 +209,14 @@ TEST(ProxyScriptDeciderTest, CustomPacSucceeds) {
log.GetEntries(&entries);
EXPECT_EQ(4u, entries.size());
+ EXPECT_TRUE(
+ LogContainsBeginEvent(entries, 0, NetLogEventType::PROXY_SCRIPT_DECIDER));
EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
+ entries, 1, NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
+ entries, 2, NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
+ EXPECT_TRUE(
+ LogContainsEndEvent(entries, 3, NetLogEventType::PROXY_SCRIPT_DECIDER));
EXPECT_TRUE(decider.effective_config().has_pac_url());
EXPECT_EQ(config.pac_url(), decider.effective_config().pac_url());
@@ -241,14 +246,14 @@ TEST(ProxyScriptDeciderTest, CustomPacFails1) {
log.GetEntries(&entries);
EXPECT_EQ(4u, entries.size());
+ EXPECT_TRUE(
+ LogContainsBeginEvent(entries, 0, NetLogEventType::PROXY_SCRIPT_DECIDER));
EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
+ entries, 1, NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
+ entries, 2, NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
+ EXPECT_TRUE(
+ LogContainsEndEvent(entries, 3, NetLogEventType::PROXY_SCRIPT_DECIDER));
EXPECT_FALSE(decider.effective_config().has_pac_url());
}
@@ -346,7 +351,7 @@ TEST_F(ProxyScriptDeciderQuickCheckTest, SyncSuccess) {
resolver_.set_synchronous_mode(true);
resolver_.rules()->AddRule("wpad", "1.2.3.4");
- EXPECT_EQ(OK, StartDecider());
+ EXPECT_THAT(StartDecider(), IsOk());
EXPECT_EQ(rule_.text(), decider_->script_data()->utf16());
EXPECT_TRUE(decider_->effective_config().has_pac_url());
@@ -359,7 +364,7 @@ TEST_F(ProxyScriptDeciderQuickCheckTest, AsyncSuccess) {
resolver_.set_ondemand_mode(true);
resolver_.rules()->AddRule("wpad", "1.2.3.4");
- EXPECT_EQ(ERR_IO_PENDING, StartDecider());
+ EXPECT_THAT(StartDecider(), IsError(ERR_IO_PENDING));
ASSERT_TRUE(resolver_.has_pending_requests());
resolver_.ResolveAllPending();
callback_.WaitForResult();
@@ -374,7 +379,7 @@ TEST_F(ProxyScriptDeciderQuickCheckTest, AsyncSuccess) {
TEST_F(ProxyScriptDeciderQuickCheckTest, AsyncFail) {
resolver_.set_ondemand_mode(true);
resolver_.rules()->AddSimulatedFailure("wpad");
- EXPECT_EQ(ERR_IO_PENDING, StartDecider());
+ EXPECT_THAT(StartDecider(), IsError(ERR_IO_PENDING));
ASSERT_TRUE(resolver_.has_pending_requests());
resolver_.ResolveAllPending();
callback_.WaitForResult();
@@ -385,7 +390,7 @@ TEST_F(ProxyScriptDeciderQuickCheckTest, AsyncFail) {
// URL or causes ProxyScriptDecider not to cancel its pending resolution.
TEST_F(ProxyScriptDeciderQuickCheckTest, AsyncTimeout) {
resolver_.set_ondemand_mode(true);
- EXPECT_EQ(ERR_IO_PENDING, StartDecider());
+ EXPECT_THAT(StartDecider(), IsError(ERR_IO_PENDING));
ASSERT_TRUE(resolver_.has_pending_requests());
callback_.WaitForResult();
EXPECT_FALSE(resolver_.has_pending_requests());
@@ -400,7 +405,7 @@ TEST_F(ProxyScriptDeciderQuickCheckTest, QuickCheckInhibitsDhcp) {
GURL url("http://foobar/baz");
dhcp_fetcher.SetPacURL(url);
decider_.reset(new ProxyScriptDecider(&fetcher_, &dhcp_fetcher, NULL));
- EXPECT_EQ(ERR_IO_PENDING, StartDecider());
+ EXPECT_THAT(StartDecider(), IsError(ERR_IO_PENDING));
dhcp_fetcher.CompleteRequests(OK, pac_contents);
EXPECT_TRUE(decider_->effective_config().has_pac_url());
EXPECT_EQ(decider_->effective_config().pac_url(), url);
@@ -416,7 +421,7 @@ TEST_F(ProxyScriptDeciderQuickCheckTest, QuickCheckDisabled) {
resolver_.rules()->AddSimulatedFailure("wpad");
MockProxyScriptFetcher fetcher;
decider_.reset(new ProxyScriptDecider(&fetcher, &dhcp_fetcher_, NULL));
- EXPECT_EQ(ERR_IO_PENDING, StartDecider());
+ EXPECT_THAT(StartDecider(), IsError(ERR_IO_PENDING));
EXPECT_TRUE(fetcher.has_pending_request());
fetcher.NotifyFetchCompletion(OK, kPac);
}
@@ -427,7 +432,7 @@ TEST_F(ProxyScriptDeciderQuickCheckTest, ExplicitPacUrl) {
Rules::Rule rule = rules_.AddSuccessRule(kCustomUrl);
resolver_.rules()->AddSimulatedFailure("wpad");
resolver_.rules()->AddRule("custom", "1.2.3.4");
- EXPECT_EQ(ERR_IO_PENDING, StartDecider());
+ EXPECT_THAT(StartDecider(), IsError(ERR_IO_PENDING));
callback_.WaitForResult();
EXPECT_TRUE(decider_->effective_config().has_pac_url());
EXPECT_EQ(rule.url, decider_->effective_config().pac_url());
@@ -439,7 +444,7 @@ TEST_F(ProxyScriptDeciderQuickCheckTest, ExplicitPacUrl) {
TEST_F(ProxyScriptDeciderQuickCheckTest, CancelPartway) {
resolver_.set_synchronous_mode(false);
resolver_.set_ondemand_mode(true);
- EXPECT_EQ(ERR_IO_PENDING, StartDecider());
+ EXPECT_THAT(StartDecider(), IsError(ERR_IO_PENDING));
decider_.reset(NULL);
}
@@ -501,34 +506,34 @@ TEST(ProxyScriptDeciderTest, AutodetectFailCustomSuccess2) {
log.GetEntries(&entries);
EXPECT_EQ(10u, entries.size());
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
+ EXPECT_TRUE(
+ LogContainsBeginEvent(entries, 0, NetLogEventType::PROXY_SCRIPT_DECIDER));
// This is the DHCP phase, which fails fetching rather than parsing, so
// there is no pair of SET_PAC_SCRIPT events.
EXPECT_TRUE(LogContainsBeginEvent(
- entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
+ entries, 1, NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
+ entries, 2, NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEvent(
entries, 3,
- NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE,
- NetLog::PHASE_NONE));
+ NetLogEventType::PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE,
+ NetLogEventPhase::NONE));
// This is the DNS phase, which attempts a fetch but fails.
EXPECT_TRUE(LogContainsBeginEvent(
- entries, 4, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
+ entries, 4, NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- entries, 5, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
+ entries, 5, NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEvent(
entries, 6,
- NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE,
- NetLog::PHASE_NONE));
+ NetLogEventType::PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE,
+ NetLogEventPhase::NONE));
// Finally, the custom PAC URL phase.
EXPECT_TRUE(LogContainsBeginEvent(
- entries, 7, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
+ entries, 7, NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- entries, 8, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 9, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
+ entries, 8, NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
+ EXPECT_TRUE(
+ LogContainsEndEvent(entries, 9, NetLogEventType::PROXY_SCRIPT_DECIDER));
}
// Fails at WPAD (downloading), and fails at custom PAC (downloading).
@@ -601,18 +606,18 @@ TEST(ProxyScriptDeciderTest, CustomPacFails1_WithPositiveDelay) {
log.GetEntries(&entries);
EXPECT_EQ(6u, entries.size());
+ EXPECT_TRUE(
+ LogContainsBeginEvent(entries, 0, NetLogEventType::PROXY_SCRIPT_DECIDER));
EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT));
+ entries, 1, NetLogEventType::PROXY_SCRIPT_DECIDER_WAIT));
+ EXPECT_TRUE(LogContainsEndEvent(entries, 2,
+ NetLogEventType::PROXY_SCRIPT_DECIDER_WAIT));
EXPECT_TRUE(LogContainsBeginEvent(
- entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
+ entries, 3, NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- entries, 4, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 5, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
+ entries, 4, NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
+ EXPECT_TRUE(
+ LogContainsEndEvent(entries, 5, NetLogEventType::PROXY_SCRIPT_DECIDER));
}
// This is a copy-paste of CustomPacFails1, with the exception that we give it
@@ -641,14 +646,14 @@ TEST(ProxyScriptDeciderTest, CustomPacFails1_WithNegativeDelay) {
log.GetEntries(&entries);
EXPECT_EQ(4u, entries.size());
+ EXPECT_TRUE(
+ LogContainsBeginEvent(entries, 0, NetLogEventType::PROXY_SCRIPT_DECIDER));
EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
+ entries, 1, NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER));
+ entries, 2, NetLogEventType::PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT));
+ EXPECT_TRUE(
+ LogContainsEndEvent(entries, 3, NetLogEventType::PROXY_SCRIPT_DECIDER));
}
class SynchronousSuccessDhcpFetcher : public DhcpProxyScriptFetcher {
diff --git a/chromium/net/proxy/proxy_script_fetcher_impl.cc b/chromium/net/proxy/proxy_script_fetcher_impl.cc
index 150614a55cd..d78c9feb65a 100644
--- a/chromium/net/proxy/proxy_script_fetcher_impl.cc
+++ b/chromium/net/proxy/proxy_script_fetcher_impl.cc
@@ -7,7 +7,7 @@
#include "base/compiler_specific.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -104,13 +104,14 @@ size_t ProxyScriptFetcherImpl::SetSizeConstraint(size_t size_bytes) {
return prev;
}
-void ProxyScriptFetcherImpl::OnResponseCompleted(URLRequest* request) {
+void ProxyScriptFetcherImpl::OnResponseCompleted(URLRequest* request,
+ int net_error) {
DCHECK_EQ(request, cur_request_.get());
// Use |result_code_| as the request's error if we have already set it to
// something specific.
- if (result_code_ == OK && !request->status().is_success())
- result_code_ = request->status().error();
+ if (result_code_ == OK && net_error != OK)
+ result_code_ = net_error;
FetchCompleted();
}
@@ -206,11 +207,13 @@ void ProxyScriptFetcherImpl::OnSSLCertificateError(URLRequest* request,
request->Cancel();
}
-void ProxyScriptFetcherImpl::OnResponseStarted(URLRequest* request) {
+void ProxyScriptFetcherImpl::OnResponseStarted(URLRequest* request,
+ int net_error) {
DCHECK_EQ(request, cur_request_.get());
+ DCHECK_NE(ERR_IO_PENDING, net_error);
- if (!request->status().is_success()) {
- OnResponseCompleted(request);
+ if (net_error != OK) {
+ OnResponseCompleted(request, net_error);
return;
}
@@ -242,6 +245,8 @@ void ProxyScriptFetcherImpl::OnResponseStarted(URLRequest* request) {
void ProxyScriptFetcherImpl::OnReadCompleted(URLRequest* request,
int num_bytes) {
+ DCHECK_NE(ERR_IO_PENDING, num_bytes);
+
DCHECK_EQ(request, cur_request_.get());
if (ConsumeBytesRead(request, num_bytes)) {
// Keep reading.
@@ -252,13 +257,15 @@ void ProxyScriptFetcherImpl::OnReadCompleted(URLRequest* request,
void ProxyScriptFetcherImpl::ReadBody(URLRequest* request) {
// Read as many bytes as are available synchronously.
while (true) {
- int num_bytes;
- if (!request->Read(buf_.get(), kBufSize, &num_bytes)) {
- // Check whether the read failed synchronously.
- if (!request->status().is_io_pending())
- OnResponseCompleted(request);
+ int num_bytes = request->Read(buf_.get(), kBufSize);
+ if (num_bytes == ERR_IO_PENDING)
+ return;
+
+ if (num_bytes < 0) {
+ OnResponseCompleted(request, num_bytes);
return;
}
+
if (!ConsumeBytesRead(request, num_bytes))
return;
}
@@ -268,7 +275,7 @@ bool ProxyScriptFetcherImpl::ConsumeBytesRead(URLRequest* request,
int num_bytes) {
if (num_bytes <= 0) {
// Error while reading, or EOF.
- OnResponseCompleted(request);
+ OnResponseCompleted(request, num_bytes);
return false;
}
diff --git a/chromium/net/proxy/proxy_script_fetcher_impl.h b/chromium/net/proxy/proxy_script_fetcher_impl.h
index 0ece5b8fbae..7a24bf8a2db 100644
--- a/chromium/net/proxy/proxy_script_fetcher_impl.h
+++ b/chromium/net/proxy/proxy_script_fetcher_impl.h
@@ -16,6 +16,7 @@
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
+#include "net/base/net_export.h"
#include "net/proxy/proxy_script_fetcher.h"
#include "net/url_request/url_request.h"
@@ -44,7 +45,7 @@ class NET_EXPORT ProxyScriptFetcherImpl : public ProxyScriptFetcher,
base::TimeDelta SetTimeoutConstraint(base::TimeDelta timeout);
size_t SetSizeConstraint(size_t size_bytes);
- void OnResponseCompleted(URLRequest* request);
+ void OnResponseCompleted(URLRequest* request, int net_error);
// ProxyScriptFetcher methods:
int Fetch(const GURL& url,
@@ -59,7 +60,7 @@ class NET_EXPORT ProxyScriptFetcherImpl : public ProxyScriptFetcher,
void OnSSLCertificateError(URLRequest* request,
const SSLInfo& ssl_info,
bool is_hsts_ok) override;
- void OnResponseStarted(URLRequest* request) override;
+ void OnResponseStarted(URLRequest* request, int net_error) override;
void OnReadCompleted(URLRequest* request, int num_bytes) override;
private:
diff --git a/chromium/net/proxy/proxy_script_fetcher_impl_unittest.cc b/chromium/net/proxy/proxy_script_fetcher_impl_unittest.cc
index f982c1e0b6d..3579ea59573 100644
--- a/chromium/net/proxy/proxy_script_fetcher_impl_unittest.cc
+++ b/chromium/net/proxy/proxy_script_fetcher_impl_unittest.cc
@@ -30,10 +30,12 @@
#include "net/http/transport_security_state.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/url_request/url_request_context_storage.h"
#include "net/url_request/url_request_file_job.h"
#include "net/url_request/url_request_job_factory_impl.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -41,6 +43,9 @@
#include "net/url_request/file_protocol_handler.h"
#endif
+using net::test::IsError;
+using net::test::IsOk;
+
using base::ASCIIToUTF16;
// TODO(eroman):
@@ -88,16 +93,16 @@ class RequestContext : public URLRequestContext {
params.ssl_config_service = ssl_config_service();
params.http_server_properties = http_server_properties();
storage_.set_http_network_session(
- base::WrapUnique(new HttpNetworkSession(params)));
- storage_.set_http_transaction_factory(base::WrapUnique(
- new HttpCache(storage_.http_network_session(),
- HttpCache::DefaultBackend::InMemory(0), false)));
+ base::MakeUnique<HttpNetworkSession>(params));
+ storage_.set_http_transaction_factory(base::MakeUnique<HttpCache>(
+ storage_.http_network_session(), HttpCache::DefaultBackend::InMemory(0),
+ false));
std::unique_ptr<URLRequestJobFactoryImpl> job_factory =
- base::WrapUnique(new URLRequestJobFactoryImpl());
+ base::MakeUnique<URLRequestJobFactoryImpl>();
#if !defined(DISABLE_FILE_SUPPORT)
job_factory->SetProtocolHandler("file",
- base::WrapUnique(new FileProtocolHandler(
- base::ThreadTaskRunnerHandle::Get())));
+ base::MakeUnique<FileProtocolHandler>(
+ base::ThreadTaskRunnerHandle::Get()));
#endif
storage_.set_job_factory(std::move(job_factory));
}
@@ -159,9 +164,9 @@ class BasicNetworkDelegate : public NetworkDelegateImpl {
void OnBeforeRedirect(URLRequest* request,
const GURL& new_location) override {}
- void OnResponseStarted(URLRequest* request) override {}
+ void OnResponseStarted(URLRequest* request, int net_error) override {}
- void OnCompleted(URLRequest* request, bool started) override {}
+ void OnCompleted(URLRequest* request, bool started, int net_error) override {}
void OnURLRequestDestroyed(URLRequest* request) override {}
@@ -217,8 +222,8 @@ TEST_F(ProxyScriptFetcherImplTest, FileUrl) {
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(GetTestFileUrl("does-not-exist"),
&text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(ERR_FILE_NOT_FOUND, callback.WaitForResult());
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_FILE_NOT_FOUND));
EXPECT_TRUE(text.empty());
}
{ // Fetch a file that exists.
@@ -226,8 +231,8 @@ TEST_F(ProxyScriptFetcherImplTest, FileUrl) {
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(GetTestFileUrl("pac.txt"),
&text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(ASCIIToUTF16("-pac.txt-\n"), text);
}
}
@@ -245,8 +250,8 @@ TEST_F(ProxyScriptFetcherImplTest, HttpMimeType) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(ASCIIToUTF16("-pac.txt-\n"), text);
}
{ // Fetch a PAC with mime type "text/html"
@@ -254,8 +259,8 @@ TEST_F(ProxyScriptFetcherImplTest, HttpMimeType) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(ASCIIToUTF16("-pac.html-\n"), text);
}
{ // Fetch a PAC with mime type "application/x-ns-proxy-autoconfig"
@@ -263,8 +268,8 @@ TEST_F(ProxyScriptFetcherImplTest, HttpMimeType) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(ASCIIToUTF16("-pac.nsproxy-\n"), text);
}
}
@@ -279,8 +284,8 @@ TEST_F(ProxyScriptFetcherImplTest, HttpStatusCode) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(ERR_PAC_STATUS_NOT_OK, callback.WaitForResult());
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_PAC_STATUS_NOT_OK));
EXPECT_TRUE(text.empty());
}
{ // Fetch a PAC which gives a 404 -- FAIL
@@ -288,8 +293,8 @@ TEST_F(ProxyScriptFetcherImplTest, HttpStatusCode) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(ERR_PAC_STATUS_NOT_OK, callback.WaitForResult());
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_PAC_STATUS_NOT_OK));
EXPECT_TRUE(text.empty());
}
}
@@ -305,8 +310,8 @@ TEST_F(ProxyScriptFetcherImplTest, ContentDisposition) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(ASCIIToUTF16("-downloadable.pac-\n"), text);
}
@@ -322,8 +327,8 @@ TEST_F(ProxyScriptFetcherImplTest, NoCache) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(ASCIIToUTF16("-cacheable_1hr.pac-\n"), text);
}
@@ -337,7 +342,7 @@ TEST_F(ProxyScriptFetcherImplTest, NoCache) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
// Expect any error. The exact error varies by platform.
EXPECT_NE(OK, callback.WaitForResult());
@@ -367,8 +372,8 @@ TEST_F(ProxyScriptFetcherImplTest, TooLarge) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(ERR_FILE_TOO_BIG, callback.WaitForResult());
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_FILE_TOO_BIG));
EXPECT_TRUE(text.empty());
}
@@ -380,8 +385,8 @@ TEST_F(ProxyScriptFetcherImplTest, TooLarge) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(ASCIIToUTF16("-pac.nsproxy-\n"), text);
}
}
@@ -402,8 +407,8 @@ TEST_F(ProxyScriptFetcherImplTest, Hang) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(ERR_TIMED_OUT, callback.WaitForResult());
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_TIMED_OUT));
EXPECT_TRUE(text.empty());
}
@@ -415,8 +420,8 @@ TEST_F(ProxyScriptFetcherImplTest, Hang) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(ASCIIToUTF16("-pac.nsproxy-\n"), text);
}
}
@@ -435,8 +440,8 @@ TEST_F(ProxyScriptFetcherImplTest, Encodings) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(ASCIIToUTF16("This data was gzipped.\n"), text);
}
@@ -447,8 +452,8 @@ TEST_F(ProxyScriptFetcherImplTest, Encodings) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(ASCIIToUTF16("This was encoded as UTF-16BE.\n"), text);
}
}
@@ -473,7 +478,7 @@ TEST_F(ProxyScriptFetcherImplTest, DataURLs) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
EXPECT_EQ(ASCIIToUTF16(kPacScript), text);
}
@@ -486,7 +491,7 @@ TEST_F(ProxyScriptFetcherImplTest, DataURLs) {
base::string16 text;
TestCompletionCallback callback;
int result = pac_fetcher.Fetch(url, &text, callback.callback());
- EXPECT_EQ(ERR_FAILED, result);
+ EXPECT_THAT(result, IsError(ERR_FAILED));
}
}
diff --git a/chromium/net/proxy/proxy_service.cc b/chromium/net/proxy/proxy_service.cc
index 295bad27802..96f2360f100 100644
--- a/chromium/net/proxy/proxy_service.cc
+++ b/chromium/net/proxy/proxy_service.cc
@@ -24,11 +24,12 @@
#include "base/time/time.h"
#include "base/values.h"
#include "net/base/completion_callback.h"
-#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/base/proxy_delegate.h"
#include "net/base/url_util.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/dhcp_proxy_script_fetcher.h"
#include "net/proxy/multi_threaded_proxy_resolver.h"
#include "net/proxy/proxy_config_service_fixed.h"
@@ -187,7 +188,7 @@ class ProxyResolverNull : public ProxyResolver {
ProxyInfo* results,
const CompletionCallback& callback,
RequestHandle* request,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
return ERR_NOT_IMPLEMENTED;
}
@@ -211,7 +212,7 @@ class ProxyResolverFromPacString : public ProxyResolver {
ProxyInfo* results,
const CompletionCallback& callback,
RequestHandle* request,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
results->UsePacString(pac_string_);
return OK;
}
@@ -236,9 +237,9 @@ class ProxyResolverFactoryForSystem : public MultiThreadedProxyResolverFactory {
std::unique_ptr<ProxyResolverFactory> CreateProxyResolverFactory() override {
#if defined(OS_WIN)
- return base::WrapUnique(new ProxyResolverFactoryWinHttp());
+ return base::MakeUnique<ProxyResolverFactoryWinHttp>();
#elif defined(OS_MACOSX)
- return base::WrapUnique(new ProxyResolverFactoryMac());
+ return base::MakeUnique<ProxyResolverFactoryMac>();
#else
NOTREACHED();
return NULL;
@@ -789,17 +790,15 @@ class ProxyService::PacRequest
PacRequest(ProxyService* service,
const GURL& url,
const std::string& method,
- int load_flags,
ProxyDelegate* proxy_delegate,
ProxyInfo* results,
const CompletionCallback& user_callback,
- const BoundNetLog& net_log)
+ const NetLogWithSource& net_log)
: service_(service),
user_callback_(user_callback),
results_(results),
url_(url),
method_(method),
- load_flags_(load_flags),
proxy_delegate_(proxy_delegate),
resolve_job_(NULL),
config_id_(ProxyConfig::kInvalidConfigID),
@@ -831,8 +830,8 @@ class ProxyService::PacRequest
}
void StartAndCompleteCheckingForSynchronous() {
- int rv = service_->TryToCompleteSynchronously(url_, load_flags_,
- proxy_delegate_, results_);
+ int rv =
+ service_->TryToCompleteSynchronously(url_, proxy_delegate_, results_);
if (rv == ERR_IO_PENDING)
rv = Start();
if (rv != ERR_IO_PENDING)
@@ -848,7 +847,7 @@ class ProxyService::PacRequest
}
void Cancel() {
- net_log_.AddEvent(NetLog::TYPE_CANCELLED);
+ net_log_.AddEvent(NetLogEventType::CANCELLED);
if (is_started())
CancelResolveJob();
@@ -858,7 +857,7 @@ class ProxyService::PacRequest
user_callback_.Reset();
results_ = NULL;
- net_log_.EndEvent(NetLog::TYPE_PROXY_SERVICE);
+ net_log_.EndEvent(NetLogEventType::PROXY_SERVICE);
}
// Returns true if Cancel() has been called.
@@ -879,9 +878,9 @@ class ProxyService::PacRequest
resolve_job_ = nullptr;
// Note that DidFinishResolvingProxy might modify |results_|.
- int rv = service_->DidFinishResolvingProxy(
- url_, method_, load_flags_, proxy_delegate_, results_, result_code,
- net_log_, creation_time_, script_executed);
+ int rv = service_->DidFinishResolvingProxy(url_, method_, proxy_delegate_,
+ results_, result_code, net_log_,
+ creation_time_, script_executed);
// Make a note in the results which configuration was in use at the
// time of the resolve.
@@ -898,7 +897,7 @@ class ProxyService::PacRequest
return rv;
}
- BoundNetLog* net_log() { return &net_log_; }
+ NetLogWithSource* net_log() { return &net_log_; }
LoadState GetLoadState() const {
if (is_started())
@@ -934,12 +933,11 @@ class ProxyService::PacRequest
ProxyInfo* results_;
GURL url_;
std::string method_;
- int load_flags_;
ProxyDelegate* proxy_delegate_;
ProxyResolver::RequestHandle resolve_job_;
ProxyConfig::ID config_id_; // The config id when the resolve was started.
ProxyConfigSource config_source_; // The source of proxy settings.
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
// Time when the request was created. Stored here rather than in |results_|
// because the time in |results_| will be cleared.
TimeTicks creation_time_;
@@ -981,7 +979,7 @@ std::unique_ptr<ProxyService> ProxyService::CreateUsingSystemProxyResolver(
return base::WrapUnique(new ProxyService(
std::move(proxy_config_service),
- base::WrapUnique(new ProxyResolverFactoryForSystem(num_pac_threads)),
+ base::MakeUnique<ProxyResolverFactoryForSystem>(num_pac_threads),
net_log));
}
@@ -999,7 +997,7 @@ std::unique_ptr<ProxyService> ProxyService::CreateFixed(const ProxyConfig& pc) {
// TODO(eroman): This isn't quite right, won't work if |pc| specifies
// a PAC script.
return CreateUsingSystemProxyResolver(
- base::WrapUnique(new ProxyConfigServiceFixed(pc)), 0, NULL);
+ base::MakeUnique<ProxyConfigServiceFixed>(pc), 0, NULL);
}
// static
@@ -1033,34 +1031,31 @@ std::unique_ptr<ProxyService> ProxyService::CreateFixedFromPacResult(
return base::WrapUnique(new ProxyService(
std::move(proxy_config_service),
- base::WrapUnique(new ProxyResolverFactoryForPacResult(pac_string)),
- NULL));
+ base::MakeUnique<ProxyResolverFactoryForPacResult>(pac_string), NULL));
}
int ProxyService::ResolveProxy(const GURL& raw_url,
const std::string& method,
- int load_flags,
ProxyInfo* result,
const CompletionCallback& callback,
PacRequest** pac_request,
ProxyDelegate* proxy_delegate,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
DCHECK(!callback.is_null());
- return ResolveProxyHelper(raw_url, method, load_flags, result, callback,
- pac_request, proxy_delegate, net_log);
+ return ResolveProxyHelper(raw_url, method, result, callback, pac_request,
+ proxy_delegate, net_log);
}
int ProxyService::ResolveProxyHelper(const GURL& raw_url,
const std::string& method,
- int load_flags,
ProxyInfo* result,
const CompletionCallback& callback,
PacRequest** pac_request,
ProxyDelegate* proxy_delegate,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
DCHECK(CalledOnValidThread());
- net_log.BeginEvent(NetLog::TYPE_PROXY_SERVICE);
+ net_log.BeginEvent(NetLogEventType::PROXY_SERVICE);
// Notify our polling-based dependencies that a resolve is taking place.
// This way they can schedule their polls in response to network activity.
@@ -1079,10 +1074,10 @@ int ProxyService::ResolveProxyHelper(const GURL& raw_url,
// Check if the request can be completed right away. (This is the case when
// using a direct connection for example).
- int rv = TryToCompleteSynchronously(url, load_flags, proxy_delegate, result);
+ int rv = TryToCompleteSynchronously(url, proxy_delegate, result);
if (rv != ERR_IO_PENDING) {
rv = DidFinishResolvingProxy(
- url, method, load_flags, proxy_delegate, result, rv, net_log,
+ url, method, proxy_delegate, result, rv, net_log,
callback.is_null() ? TimeTicks() : TimeTicks::Now(), false);
return rv;
}
@@ -1090,9 +1085,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, load_flags,
- proxy_delegate, result, callback,
- net_log));
+ scoped_refptr<PacRequest> req(new PacRequest(
+ this, url, method, proxy_delegate, result, callback, net_log));
if (current_state_ == STATE_READY) {
// Start the resolve request.
@@ -1100,7 +1094,8 @@ int ProxyService::ResolveProxyHelper(const GURL& raw_url,
if (rv != ERR_IO_PENDING)
return req->QueryDidComplete(rv);
} else {
- req->net_log()->BeginEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC);
+ req->net_log()->BeginEvent(
+ NetLogEventType::PROXY_SERVICE_WAITING_FOR_INIT_PAC);
}
DCHECK_EQ(ERR_IO_PENDING, rv);
@@ -1114,20 +1109,19 @@ int ProxyService::ResolveProxyHelper(const GURL& raw_url,
return rv; // ERR_IO_PENDING
}
-bool ProxyService::TryResolveProxySynchronously(const GURL& raw_url,
- const std::string& method,
- int load_flags,
- ProxyInfo* result,
- ProxyDelegate* proxy_delegate,
- const BoundNetLog& net_log) {
+bool ProxyService::TryResolveProxySynchronously(
+ const GURL& raw_url,
+ const std::string& method,
+ ProxyInfo* result,
+ ProxyDelegate* proxy_delegate,
+ const NetLogWithSource& net_log) {
CompletionCallback null_callback;
- return ResolveProxyHelper(raw_url, method, load_flags, result, null_callback,
+ return ResolveProxyHelper(raw_url, method, result, null_callback,
nullptr /* pac_request*/, proxy_delegate,
net_log) == OK;
}
int ProxyService::TryToCompleteSynchronously(const GURL& url,
- int load_flags,
ProxyDelegate* proxy_delegate,
ProxyInfo* result) {
DCHECK_NE(STATE_NONE, current_state_);
@@ -1175,7 +1169,7 @@ void ProxyService::SuspendAllPendingRequests() {
req->CancelResolveJob();
req->net_log()->BeginEvent(
- NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC);
+ NetLogEventType::PROXY_SERVICE_WAITING_FOR_INIT_PAC);
}
}
}
@@ -1194,7 +1188,8 @@ void ProxyService::SetReady() {
++it) {
PacRequest* req = it->get();
if (!req->is_started() && !req->was_cancelled()) {
- req->net_log()->EndEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC);
+ req->net_log()->EndEvent(
+ NetLogEventType::PROXY_SERVICE_WAITING_FOR_INIT_PAC);
// Note that we re-check for synchronous completion, in case we are
// no longer using a ProxyResolver (can happen if we fell-back to manual).
@@ -1282,13 +1277,12 @@ void ProxyService::OnInitProxyResolverComplete(int result) {
int ProxyService::ReconsiderProxyAfterError(const GURL& url,
const std::string& method,
- int load_flags,
int net_error,
ProxyInfo* result,
const CompletionCallback& callback,
PacRequest** pac_request,
ProxyDelegate* proxy_delegate,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
DCHECK(CalledOnValidThread());
// Check to see if we have a new config since ResolveProxy was called. We
@@ -1302,7 +1296,7 @@ int ProxyService::ReconsiderProxyAfterError(const GURL& url,
// If we have a new config or the config was never tried, we delete the
// list of bad proxies and we try again.
proxy_retry_info_.clear();
- return ResolveProxy(url, method, load_flags, result, callback, pac_request,
+ return ResolveProxy(url, method, result, callback, pac_request,
proxy_delegate, net_log);
}
@@ -1322,7 +1316,7 @@ bool ProxyService::MarkProxiesAsBadUntil(
const ProxyInfo& result,
base::TimeDelta retry_delay,
const std::vector<ProxyServer>& additional_bad_proxies,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
result.proxy_list_.UpdateRetryInfoOnFallback(&proxy_retry_info_, retry_delay,
false, additional_bad_proxies,
OK, net_log);
@@ -1354,7 +1348,7 @@ void ProxyService::ReportSuccess(const ProxyInfo& result,
}
if (net_log_) {
net_log_->AddGlobalEntry(
- NetLog::TYPE_BAD_PROXY_LIST_REPORTED,
+ NetLogEventType::BAD_PROXY_LIST_REPORTED,
base::Bind(&NetLogBadProxyListCallback, &new_retry_info));
}
}
@@ -1384,11 +1378,10 @@ void ProxyService::RemovePendingRequest(PacRequest* req) {
int ProxyService::DidFinishResolvingProxy(const GURL& url,
const std::string& method,
- int load_flags,
ProxyDelegate* proxy_delegate,
ProxyInfo* result,
int result_code,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
base::TimeTicks start_time,
bool script_executed) {
// Don't track any metrics if start_time is 0, which will happen when the user
@@ -1419,9 +1412,9 @@ int ProxyService::DidFinishResolvingProxy(const GURL& url,
// Allow the proxy delegate to interpose on the resolution decision,
// possibly modifying the ProxyInfo.
if (proxy_delegate)
- proxy_delegate->OnResolveProxy(url, method, load_flags, *this, result);
+ proxy_delegate->OnResolveProxy(url, method, *this, result);
- net_log.AddEvent(NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
+ net_log.AddEvent(NetLogEventType::PROXY_SERVICE_RESOLVED_PROXY_LIST,
base::Bind(&NetLogFinishedResolvingProxyCallback, result));
// This check is done to only log the NetLog event when necessary, it's
@@ -1429,12 +1422,12 @@ int ProxyService::DidFinishResolvingProxy(const GURL& url,
if (!proxy_retry_info_.empty()) {
result->DeprioritizeBadProxies(proxy_retry_info_);
net_log.AddEvent(
- NetLog::TYPE_PROXY_SERVICE_DEPRIORITIZED_BAD_PROXIES,
+ NetLogEventType::PROXY_SERVICE_DEPRIORITIZED_BAD_PROXIES,
base::Bind(&NetLogFinishedResolvingProxyCallback, result));
}
} else {
net_log.AddEventWithNetErrorCode(
- NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST, result_code);
+ NetLogEventType::PROXY_SERVICE_RESOLVED_PROXY_LIST, result_code);
bool reset_config = result_code == ERR_PAC_SCRIPT_TERMINATED;
if (!config_.pac_mandatory()) {
@@ -1451,7 +1444,7 @@ int ProxyService::DidFinishResolvingProxy(const GURL& url,
// Allow the proxy delegate to interpose on the resolution decision,
// possibly modifying the ProxyInfo.
if (proxy_delegate)
- proxy_delegate->OnResolveProxy(url, method, load_flags, *this, result);
+ proxy_delegate->OnResolveProxy(url, method, *this, result);
} else {
result_code = ERR_MANDATORY_PROXY_CONFIGURATION_FAILED;
}
@@ -1465,7 +1458,7 @@ int ProxyService::DidFinishResolvingProxy(const GURL& url,
}
}
- net_log.EndEvent(NetLog::TYPE_PROXY_SERVICE);
+ net_log.EndEvent(NetLogEventType::PROXY_SERVICE);
return result_code;
}
@@ -1532,11 +1525,11 @@ ProxyService::CreateSystemProxyConfigService(
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner) {
#if defined(OS_WIN)
- return base::WrapUnique(new ProxyConfigServiceWin());
+ return base::MakeUnique<ProxyConfigServiceWin>();
#elif defined(OS_IOS)
- return base::WrapUnique(new ProxyConfigServiceIOS());
+ return base::MakeUnique<ProxyConfigServiceIOS>();
#elif defined(OS_MACOSX)
- return base::WrapUnique(new ProxyConfigServiceMac(io_task_runner));
+ return base::MakeUnique<ProxyConfigServiceMac>(io_task_runner);
#elif defined(OS_CHROMEOS)
LOG(ERROR) << "ProxyConfigService for ChromeOS should be created in "
<< "profile_io_data.cc::CreateProxyConfigService and this should "
@@ -1561,12 +1554,12 @@ ProxyService::CreateSystemProxyConfigService(
return std::move(linux_config_service);
#elif defined(OS_ANDROID)
- return base::WrapUnique(new ProxyConfigServiceAndroid(
- io_task_runner, base::ThreadTaskRunnerHandle::Get()));
+ return base::MakeUnique<ProxyConfigServiceAndroid>(
+ io_task_runner, base::ThreadTaskRunnerHandle::Get());
#else
LOG(WARNING) << "Failed to choose a system proxy settings fetcher "
"for this platform.";
- return base::WrapUnique(new ProxyConfigServiceDirect());
+ return base::MakeUnique<ProxyConfigServiceDirect>();
#endif
}
@@ -1604,7 +1597,7 @@ void ProxyService::OnProxyConfigChanged(
// Emit the proxy settings change to the NetLog stream.
if (net_log_) {
- net_log_->AddGlobalEntry(NetLog::TYPE_PROXY_CONFIG_CHANGED,
+ net_log_->AddGlobalEntry(NetLogEventType::PROXY_CONFIG_CHANGED,
base::Bind(&NetLogProxyConfigChangedCallback,
&fetched_config_, &effective_config));
}
diff --git a/chromium/net/proxy/proxy_service.h b/chromium/net/proxy/proxy_service.h
index c00cada4f7e..c5ae5a54aa4 100644
--- a/chromium/net/proxy/proxy_service.h
+++ b/chromium/net/proxy/proxy_service.h
@@ -21,7 +21,6 @@
#include "net/base/load_states.h"
#include "net/base/net_export.h"
#include "net/base/network_change_notifier.h"
-#include "net/log/net_log.h"
#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_server.h"
@@ -38,6 +37,8 @@ namespace net {
class DhcpProxyScriptFetcher;
class HostResolver;
+class NetLog;
+class NetLogWithSource;
class ProxyDelegate;
class ProxyResolver;
class ProxyResolverFactory;
@@ -152,21 +153,19 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver,
// Profiling information for the request is saved to |net_log| if non-NULL.
int ResolveProxy(const GURL& url,
const std::string& method,
- int load_flags,
ProxyInfo* results,
const CompletionCallback& callback,
PacRequest** pac_request,
ProxyDelegate* proxy_delegate,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Returns true if the proxy information could be determined without spawning
// an asynchronous task. Otherwise, |result| is unmodified.
bool TryResolveProxySynchronously(const GURL& raw_url,
const std::string& method,
- int load_flags,
ProxyInfo* result,
ProxyDelegate* proxy_delegate,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// This method is called after a failure to connect or resolve a host name.
// It gives the proxy service an opportunity to reconsider the proxy to use.
@@ -184,13 +183,12 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver,
// Profiling information for the request is saved to |net_log| if non-NULL.
int ReconsiderProxyAfterError(const GURL& url,
const std::string& method,
- int load_flags,
int net_error,
ProxyInfo* results,
const CompletionCallback& callback,
PacRequest** pac_request,
ProxyDelegate* proxy_delegate,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Explicitly trigger proxy fallback for the given |results| by updating our
// list of bad proxies to include the first entry of |results|, and,
@@ -206,7 +204,7 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver,
const ProxyInfo& results,
base::TimeDelta retry_delay,
const std::vector<ProxyServer>& additional_bad_proxies,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Called to report that the last proxy connection succeeded. If |proxy_info|
// has a non empty proxy_retry_info map, the proxies that have been tried (and
@@ -356,7 +354,6 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver,
// Otherwise it fills |result| with the proxy information for |url|.
// Completing synchronously means we don't need to query ProxyResolver.
int TryToCompleteSynchronously(const GURL& url,
- int load_flags,
ProxyDelegate* proxy_delegate,
ProxyInfo* result);
@@ -365,12 +362,11 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver,
// |TryToCompleteSynchronously|.
int ResolveProxyHelper(const GURL& url,
const std::string& method,
- int load_flags,
ProxyInfo* results,
const CompletionCallback& callback,
PacRequest** pac_request,
ProxyDelegate* proxy_delegate,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Cancels all of the requests sent to the ProxyResolver. These will be
// restarted when calling SetReady().
@@ -391,11 +387,10 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver,
// bad entries from the results list.
int DidFinishResolvingProxy(const GURL& url,
const std::string& method,
- int load_flags,
ProxyDelegate* proxy_delegate,
ProxyInfo* result,
int result_code,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
base::TimeTicks start_time,
bool script_executed);
diff --git a/chromium/net/proxy/proxy_service_mojo.cc b/chromium/net/proxy/proxy_service_mojo.cc
index ad56a988d93..65bdf2c8642 100644
--- a/chromium/net/proxy/proxy_service_mojo.cc
+++ b/chromium/net/proxy/proxy_service_mojo.cc
@@ -38,11 +38,11 @@ std::unique_ptr<ProxyService> CreateProxyServiceUsingMojoFactory(
std::unique_ptr<ProxyService> proxy_service(new ProxyService(
std::move(proxy_config_service),
- base::WrapUnique(new ProxyResolverFactoryMojo(
+ base::MakeUnique<ProxyResolverFactoryMojo>(
mojo_proxy_factory, host_resolver,
base::Bind(&NetworkDelegateErrorObserver::Create, network_delegate,
base::ThreadTaskRunnerHandle::Get()),
- net_log)),
+ net_log),
net_log));
// Configure fetchers to use for PAC script downloads and auto-detect.
diff --git a/chromium/net/proxy/proxy_service_mojo_unittest.cc b/chromium/net/proxy/proxy_service_mojo_unittest.cc
index d49c7d1881c..c6751388f9a 100644
--- a/chromium/net/proxy/proxy_service_mojo_unittest.cc
+++ b/chromium/net/proxy/proxy_service_mojo_unittest.cc
@@ -13,11 +13,11 @@
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
-#include "net/base/load_flags.h"
#include "net/base/network_delegate_impl.h"
#include "net/base/test_completion_callback.h"
#include "net/dns/mock_host_resolver.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
#include "net/log/test_net_log_entry.h"
#include "net/proxy/dhcp_proxy_script_fetcher.h"
@@ -27,10 +27,13 @@
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/proxy/proxy_service.h"
#include "net/test/event_waiter.h"
+#include "net/test/gtest_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -84,7 +87,7 @@ void CheckCapturedNetLogEntries(const TestNetLogEntry::List& entries) {
// ProxyService records its own NetLog entries, so skip forward until the
// expected event type.
while (i < entries.size() &&
- entries[i].type != NetLog::TYPE_PAC_JAVASCRIPT_ALERT) {
+ entries[i].type != NetLogEventType::PAC_JAVASCRIPT_ALERT) {
i++;
}
ASSERT_LT(i, entries.size());
@@ -94,7 +97,7 @@ void CheckCapturedNetLogEntries(const TestNetLogEntry::List& entries) {
ASSERT_FALSE(entries[i].params->HasKey("line_number"));
while (i < entries.size() &&
- entries[i].type != NetLog::TYPE_PAC_JAVASCRIPT_ERROR) {
+ entries[i].type != NetLogEventType::PAC_JAVASCRIPT_ERROR) {
i++;
}
message.clear();
@@ -111,9 +114,9 @@ class LoggingMockHostResolver : public MockHostResolver {
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) override {
- net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB);
+ std::unique_ptr<Request>* out_req,
+ const NetLogWithSource& net_log) override {
+ net_log.AddEvent(NetLogEventType::HOST_RESOLVER_IMPL_JOB);
return MockHostResolver::Resolve(info, priority, addresses, callback,
out_req, net_log);
}
@@ -129,9 +132,9 @@ class ProxyServiceMojoTest : public testing::Test,
fetcher_ = new MockProxyScriptFetcher;
proxy_service_ = CreateProxyServiceUsingMojoFactory(
- this, base::WrapUnique(new ProxyConfigServiceFixed(
- ProxyConfig::CreateFromCustomPacURL(GURL(kPacUrl)))),
- fetcher_, base::WrapUnique(new DoNothingDhcpProxyScriptFetcher()),
+ this, base::MakeUnique<ProxyConfigServiceFixed>(
+ ProxyConfig::CreateFromCustomPacURL(GURL(kPacUrl))),
+ fetcher_, base::MakeUnique<DoNothingDhcpProxyScriptFetcher>(),
&mock_host_resolver_, &net_log_, &network_delegate_);
}
@@ -141,8 +144,8 @@ class ProxyServiceMojoTest : public testing::Test,
interfaces::ProxyResolverFactoryRequestClientPtr client) override {
InProcessMojoProxyResolverFactory::GetInstance()->CreateResolver(
pac_script, std::move(req), std::move(client));
- return base::WrapUnique(
- new base::ScopedClosureRunner(on_delete_closure_.closure()));
+ return base::MakeUnique<base::ScopedClosureRunner>(
+ on_delete_closure_.closure());
}
TestNetworkDelegate network_delegate_;
@@ -157,9 +160,9 @@ TEST_F(ProxyServiceMojoTest, Basic) {
ProxyInfo info;
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
- proxy_service_->ResolveProxy(
- GURL("http://foo"), std::string(), LOAD_NORMAL, &info,
- callback.callback(), nullptr, nullptr, BoundNetLog()));
+ proxy_service_->ResolveProxy(GURL("http://foo"), std::string(),
+ &info, callback.callback(), nullptr,
+ nullptr, NetLogWithSource()));
// Proxy script fetcher should have a fetch triggered by the first
// |ResolveProxy()| request.
@@ -167,7 +170,7 @@ TEST_F(ProxyServiceMojoTest, Basic) {
EXPECT_EQ(GURL(kPacUrl), fetcher_->pending_request_url());
fetcher_->NotifyFetchCompletion(OK, kSimplePacScript);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ("PROXY foo:1234", info.ToPacString());
EXPECT_EQ(0u, mock_host_resolver_.num_resolve());
proxy_service_.reset();
@@ -177,11 +180,11 @@ TEST_F(ProxyServiceMojoTest, Basic) {
TEST_F(ProxyServiceMojoTest, DnsResolution) {
ProxyInfo info;
TestCompletionCallback callback;
- BoundTestNetLog bound_net_log;
+ BoundTestNetLog test_net_log;
EXPECT_EQ(ERR_IO_PENDING,
- proxy_service_->ResolveProxy(
- GURL("http://foo"), std::string(), LOAD_NORMAL, &info,
- callback.callback(), nullptr, nullptr, bound_net_log.bound()));
+ proxy_service_->ResolveProxy(GURL("http://foo"), std::string(),
+ &info, callback.callback(), nullptr,
+ nullptr, test_net_log.bound()));
// Proxy script fetcher should have a fetch triggered by the first
// |ResolveProxy()| request.
@@ -189,30 +192,30 @@ TEST_F(ProxyServiceMojoTest, DnsResolution) {
EXPECT_EQ(GURL(kPacUrl), fetcher_->pending_request_url());
fetcher_->NotifyFetchCompletion(OK, kDnsResolvePacScript);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ("QUIC bar:4321", info.ToPacString());
EXPECT_EQ(1u, mock_host_resolver_.num_resolve());
proxy_service_.reset();
on_delete_closure_.WaitForResult();
TestNetLogEntry::List entries;
- bound_net_log.GetEntries(&entries);
+ test_net_log.GetEntries(&entries);
// There should be one entry with type TYPE_HOST_RESOLVER_IMPL_JOB.
EXPECT_EQ(1, std::count_if(entries.begin(), entries.end(),
[](const TestNetLogEntry& entry) {
return entry.type ==
- NetLog::TYPE_HOST_RESOLVER_IMPL_JOB;
+ NetLogEventType::HOST_RESOLVER_IMPL_JOB;
}));
}
TEST_F(ProxyServiceMojoTest, Error) {
ProxyInfo info;
TestCompletionCallback callback;
- BoundTestNetLog bound_net_log;
+ BoundTestNetLog test_net_log;
EXPECT_EQ(ERR_IO_PENDING,
- proxy_service_->ResolveProxy(
- GURL("http://foo"), std::string(), LOAD_NORMAL, &info,
- callback.callback(), nullptr, nullptr, bound_net_log.bound()));
+ proxy_service_->ResolveProxy(GURL("http://foo"), std::string(),
+ &info, callback.callback(), nullptr,
+ nullptr, test_net_log.bound()));
// Proxy script fetcher should have a fetch triggered by the first
// |ResolveProxy()| request.
@@ -223,12 +226,12 @@ TEST_F(ProxyServiceMojoTest, Error) {
network_delegate_.event_waiter().WaitForEvent(
TestNetworkDelegate::PAC_SCRIPT_ERROR);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ("DIRECT", info.ToPacString());
EXPECT_EQ(0u, mock_host_resolver_.num_resolve());
TestNetLogEntry::List entries;
- bound_net_log.GetEntries(&entries);
+ test_net_log.GetEntries(&entries);
CheckCapturedNetLogEntries(entries);
entries.clear();
net_log_.GetEntries(&entries);
@@ -239,9 +242,9 @@ TEST_F(ProxyServiceMojoTest, ErrorOnInitialization) {
ProxyInfo info;
TestCompletionCallback callback;
EXPECT_EQ(ERR_IO_PENDING,
- proxy_service_->ResolveProxy(
- GURL("http://foo"), std::string(), LOAD_NORMAL, &info,
- callback.callback(), nullptr, nullptr, BoundNetLog()));
+ proxy_service_->ResolveProxy(GURL("http://foo"), std::string(),
+ &info, callback.callback(), nullptr,
+ nullptr, NetLogWithSource()));
// Proxy script fetcher should have a fetch triggered by the first
// |ResolveProxy()| request.
@@ -252,7 +255,7 @@ TEST_F(ProxyServiceMojoTest, ErrorOnInitialization) {
network_delegate_.event_waiter().WaitForEvent(
TestNetworkDelegate::PAC_SCRIPT_ERROR);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ("DIRECT", info.ToPacString());
EXPECT_EQ(0u, mock_host_resolver_.num_resolve());
diff --git a/chromium/net/proxy/proxy_service_unittest.cc b/chromium/net/proxy/proxy_service_unittest.cc
index a1c61793014..c0e4774636b 100644
--- a/chromium/net/proxy/proxy_service_unittest.cc
+++ b/chromium/net/proxy/proxy_service_unittest.cc
@@ -15,11 +15,11 @@
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/base/proxy_delegate.h"
#include "net/base/test_completion_callback.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
#include "net/log/test_net_log_entry.h"
#include "net/log/test_net_log_util.h"
@@ -29,9 +29,15 @@
#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_resolver.h"
#include "net/proxy/proxy_script_fetcher.h"
+#include "net/proxy/proxy_server.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+using net::test::IsError;
+using net::test::IsOk;
+
using base::ASCIIToUTF16;
// TODO(eroman): Write a test which exercises
@@ -175,7 +181,6 @@ class TestResolveProxyDelegate : public ProxyDelegate {
void OnResolveProxy(const GURL& url,
const std::string& method,
- int load_flags,
const ProxyService& proxy_service,
ProxyInfo* result) override {
method_ = method;
@@ -220,6 +225,15 @@ class TestResolveProxyDelegate : public ProxyDelegate {
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 {}
+ ProxyServer GetDefaultAlternativeProxy() const override {
+ return ProxyServer();
+ }
private:
bool on_resolve_proxy_called_;
@@ -238,7 +252,6 @@ class TestProxyFallbackProxyDelegate : public ProxyDelegate {
// ProxyDelegate implementation:
void OnResolveProxy(const GURL& url,
const std::string& method,
- int load_flags,
const ProxyService& proxy_service,
ProxyInfo* result) override {}
void OnTunnelConnectCompleted(const HostPortPair& endpoint,
@@ -258,6 +271,15 @@ class TestProxyFallbackProxyDelegate : public ProxyDelegate {
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 {}
+ ProxyServer GetDefaultAlternativeProxy() const override {
+ return ProxyServer();
+ }
bool on_proxy_fallback_called() const {
return on_proxy_fallback_called_;
@@ -349,7 +371,7 @@ TEST_F(ProxyServiceTest, Direct) {
MockAsyncProxyResolverFactory* factory =
new MockAsyncProxyResolverFactory(false);
ProxyService service(
- base::WrapUnique(new MockProxyConfigService(ProxyConfig::CreateDirect())),
+ base::MakeUnique<MockProxyConfigService>(ProxyConfig::CreateDirect()),
base::WrapUnique(factory), nullptr);
GURL url("http://www.google.com/");
@@ -357,10 +379,9 @@ TEST_F(ProxyServiceTest, Direct) {
ProxyInfo info;
TestCompletionCallback callback;
BoundTestNetLog log;
- int rv =
- service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback.callback(), nullptr, nullptr, log.bound());
- EXPECT_EQ(OK, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
+ nullptr, nullptr, log.bound());
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(factory->pending_requests().empty());
EXPECT_TRUE(info.is_direct());
@@ -372,13 +393,12 @@ TEST_F(ProxyServiceTest, Direct) {
log.GetEntries(&entries);
EXPECT_EQ(3u, entries.size());
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_PROXY_SERVICE));
+ EXPECT_TRUE(
+ LogContainsBeginEvent(entries, 0, NetLogEventType::PROXY_SERVICE));
EXPECT_TRUE(LogContainsEvent(
- entries, 1, NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 2, NetLog::TYPE_PROXY_SERVICE));
+ entries, 1, NetLogEventType::PROXY_SERVICE_RESOLVED_PROXY_LIST,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEndEvent(entries, 2, NetLogEventType::PROXY_SERVICE));
}
TEST_F(ProxyServiceTest, OnResolveProxyCallbackAddProxy) {
@@ -387,7 +407,7 @@ TEST_F(ProxyServiceTest, OnResolveProxyCallbackAddProxy) {
config.set_auto_detect(false);
config.proxy_rules().bypass_rules.ParseFromString("*.org");
- ProxyService service(base::WrapUnique(new MockProxyConfigService(config)),
+ ProxyService service(base::MakeUnique<MockProxyConfigService>(config),
nullptr, nullptr);
GURL url("http://www.google.com/");
@@ -398,15 +418,14 @@ TEST_F(ProxyServiceTest, OnResolveProxyCallbackAddProxy) {
BoundTestNetLog log;
// First, warm up the ProxyService.
- int rv =
- service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback.callback(), nullptr, nullptr, log.bound());
- EXPECT_EQ(OK, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
+ nullptr, nullptr, log.bound());
+ EXPECT_THAT(rv, IsOk());
// Verify that network delegate is invoked.
TestResolveProxyDelegate delegate;
- rv = service.ResolveProxy(url, "GET", LOAD_NORMAL, &info, callback.callback(),
- nullptr, &delegate, log.bound());
+ rv = service.ResolveProxy(url, "GET", &info, callback.callback(), nullptr,
+ &delegate, log.bound());
EXPECT_TRUE(delegate.on_resolve_proxy_called());
EXPECT_EQ(&service, delegate.proxy_service());
EXPECT_EQ(delegate.method(), "GET");
@@ -417,22 +436,21 @@ TEST_F(ProxyServiceTest, OnResolveProxyCallbackAddProxy) {
delegate.set_add_proxy(true);
// Callback should interpose:
- rv = service.ResolveProxy(url, "GET", LOAD_NORMAL, &info, callback.callback(),
- nullptr, &delegate, log.bound());
+ rv = service.ResolveProxy(url, "GET", &info, callback.callback(), nullptr,
+ &delegate, log.bound());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ(info.proxy_server().host_port_pair().host(), "delegate_proxy.com");
delegate.set_add_proxy(false);
// Check non-bypassed URL:
- rv = service.ResolveProxy(url, "GET", LOAD_NORMAL, &info, callback.callback(),
- nullptr, &delegate, log.bound());
+ rv = service.ResolveProxy(url, "GET", &info, callback.callback(), nullptr,
+ &delegate, log.bound());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ(info.proxy_server().host_port_pair().host(), "foopy1");
// Check bypassed URL:
- rv = service.ResolveProxy(bypass_url, "GET", LOAD_NORMAL, &info,
- callback.callback(), nullptr, &delegate,
- log.bound());
+ rv = service.ResolveProxy(bypass_url, "GET", &info, callback.callback(),
+ nullptr, &delegate, log.bound());
EXPECT_TRUE(info.is_direct());
}
@@ -445,7 +463,7 @@ TEST_F(ProxyServiceTest, OnResolveProxyCallbackRemoveProxy) {
config.set_auto_detect(false);
config.proxy_rules().bypass_rules.ParseFromString("*.org");
- ProxyService service(base::WrapUnique(new MockProxyConfigService(config)),
+ ProxyService service(base::MakeUnique<MockProxyConfigService>(config),
nullptr, nullptr);
GURL url("http://www.google.com/");
@@ -456,30 +474,28 @@ TEST_F(ProxyServiceTest, OnResolveProxyCallbackRemoveProxy) {
BoundTestNetLog log;
// First, warm up the ProxyService.
- int rv =
- service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback.callback(), nullptr, nullptr, log.bound());
- EXPECT_EQ(OK, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
+ nullptr, nullptr, log.bound());
+ EXPECT_THAT(rv, IsOk());
TestResolveProxyDelegate delegate;
delegate.set_remove_proxy(true);
// Callback should interpose:
- rv = service.ResolveProxy(url, "GET", LOAD_NORMAL, &info, callback.callback(),
- nullptr, &delegate, log.bound());
+ rv = service.ResolveProxy(url, "GET", &info, callback.callback(), nullptr,
+ &delegate, log.bound());
EXPECT_TRUE(info.is_direct());
delegate.set_remove_proxy(false);
// Check non-bypassed URL:
- rv = service.ResolveProxy(url, "GET", LOAD_NORMAL, &info, callback.callback(),
- nullptr, &delegate, log.bound());
+ rv = service.ResolveProxy(url, "GET", &info, callback.callback(), nullptr,
+ &delegate, log.bound());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ(info.proxy_server().host_port_pair().host(), "foopy1");
// Check bypassed URL:
- rv = service.ResolveProxy(bypass_url, "GET", LOAD_NORMAL, &info,
- callback.callback(), nullptr, &delegate,
- log.bound());
+ rv = service.ResolveProxy(bypass_url, "GET", &info, callback.callback(),
+ nullptr, &delegate, log.bound());
EXPECT_TRUE(info.is_direct());
}
@@ -501,10 +517,9 @@ TEST_F(ProxyServiceTest, PAC) {
ProxyService::PacRequest* request;
BoundTestNetLog log;
- int rv =
- service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback.callback(), &request, nullptr, log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
+ &request, nullptr, log.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, service.GetLoadState(request));
@@ -520,7 +535,7 @@ TEST_F(ProxyServiceTest, PAC) {
resolver.pending_requests()[0]->results()->UseNamedProxy("foopy");
resolver.pending_requests()[0]->CompleteNow(OK);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy:80", info.proxy_server().ToURI());
EXPECT_TRUE(info.did_use_pac_script());
@@ -534,14 +549,13 @@ TEST_F(ProxyServiceTest, PAC) {
log.GetEntries(&entries);
EXPECT_EQ(5u, entries.size());
+ EXPECT_TRUE(
+ LogContainsBeginEvent(entries, 0, NetLogEventType::PROXY_SERVICE));
EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_PROXY_SERVICE));
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 2, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
+ entries, 1, NetLogEventType::PROXY_SERVICE_WAITING_FOR_INIT_PAC));
EXPECT_TRUE(LogContainsEndEvent(
- entries, 4, NetLog::TYPE_PROXY_SERVICE));
+ entries, 2, NetLogEventType::PROXY_SERVICE_WAITING_FOR_INIT_PAC));
+ EXPECT_TRUE(LogContainsEndEvent(entries, 4, NetLogEventType::PROXY_SERVICE));
}
// Test that the proxy resolver does not see the URL's username/password
@@ -561,10 +575,9 @@ TEST_F(ProxyServiceTest, PAC_NoIdentityOrHash) {
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
factory->pending_requests()[0]->script_data()->url());
@@ -593,10 +606,9 @@ TEST_F(ProxyServiceTest, PAC_FailoverWithoutDirect) {
ProxyInfo info;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
factory->pending_requests()[0]->script_data()->url());
@@ -609,7 +621,7 @@ TEST_F(ProxyServiceTest, PAC_FailoverWithoutDirect) {
resolver.pending_requests()[0]->results()->UseNamedProxy("foopy:8080");
resolver.pending_requests()[0]->CompleteNow(OK);
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy:8080", info.proxy_server().ToURI());
EXPECT_TRUE(info.did_use_pac_script());
@@ -625,10 +637,10 @@ TEST_F(ProxyServiceTest, PAC_FailoverWithoutDirect) {
TestCompletionCallback callback2;
ProxyServer expected_proxy_server = info.proxy_server();
rv = service.ReconsiderProxyAfterError(
- url, "GET", LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback2.callback(), nullptr, &proxy_delegate, BoundNetLog());
+ url, "GET", ERR_PROXY_CONNECTION_FAILED, &info, callback2.callback(),
+ nullptr, &proxy_delegate, NetLogWithSource());
// ReconsiderProxyAfterError returns error indicating nothing left.
- EXPECT_EQ(ERR_FAILED, rv);
+ EXPECT_THAT(rv, IsError(ERR_FAILED));
EXPECT_TRUE(info.is_empty());
}
@@ -648,10 +660,9 @@ TEST_F(ProxyServiceTest, PAC_RuntimeError) {
ProxyInfo info;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
factory->pending_requests()[0]->script_data()->url());
@@ -663,7 +674,7 @@ TEST_F(ProxyServiceTest, PAC_RuntimeError) {
// Simulate a failure in the PAC executor.
resolver.pending_requests()[0]->CompleteNow(ERR_PAC_SCRIPT_FAILED);
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
// Since the PAC script was non-mandatory, we should have fallen-back to
// DIRECT.
@@ -707,10 +718,9 @@ TEST_F(ProxyServiceTest, PAC_FailoverAfterDirect) {
ProxyInfo info;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
factory->pending_requests()[0]->script_data()->url());
@@ -724,15 +734,15 @@ TEST_F(ProxyServiceTest, PAC_FailoverAfterDirect) {
"DIRECT ; PROXY foobar:10 ; DIRECT ; PROXY foobar:20");
resolver.pending_requests()[0]->CompleteNow(OK);
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_TRUE(info.is_direct());
// Fallback 1.
TestCompletionCallback callback2;
rv = service.ReconsiderProxyAfterError(
- url, std::string(), LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback2.callback(), nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ url, std::string(), ERR_PROXY_CONNECTION_FAILED, &info,
+ callback2.callback(), nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foobar:10", info.proxy_server().ToURI());
@@ -741,18 +751,18 @@ TEST_F(ProxyServiceTest, PAC_FailoverAfterDirect) {
ProxyServer expected_proxy_server3 = info.proxy_server();
TestCompletionCallback callback3;
rv = service.ReconsiderProxyAfterError(
- url, "GET", LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback3.callback(), nullptr, &proxy_delegate, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ url, "GET", ERR_PROXY_CONNECTION_FAILED, &info, callback3.callback(),
+ nullptr, &proxy_delegate, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(info.is_direct());
// Fallback 3.
ProxyServer expected_proxy_server4 = info.proxy_server();
TestCompletionCallback callback4;
rv = service.ReconsiderProxyAfterError(
- url, "GET", LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback4.callback(), nullptr, &proxy_delegate, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ url, "GET", ERR_PROXY_CONNECTION_FAILED, &info, callback4.callback(),
+ nullptr, &proxy_delegate, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foobar:20", info.proxy_server().ToURI());
@@ -760,9 +770,9 @@ TEST_F(ProxyServiceTest, PAC_FailoverAfterDirect) {
ProxyServer expected_proxy_server5 = info.proxy_server();
TestCompletionCallback callback5;
rv = service.ReconsiderProxyAfterError(
- url, "GET", LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback5.callback(), nullptr, &proxy_delegate, BoundNetLog());
- EXPECT_EQ(ERR_FAILED, rv);
+ url, "GET", ERR_PROXY_CONNECTION_FAILED, &info, callback5.callback(),
+ nullptr, &proxy_delegate, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_FAILED));
EXPECT_TRUE(info.is_empty());
}
@@ -784,10 +794,9 @@ TEST_F(ProxyServiceTest, PAC_ConfigSourcePropagates) {
GURL url("http://www.google.com/");
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback.callback(), nullptr, nullptr,
- BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
factory->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
ASSERT_EQ(1u, resolver.pending_requests().size());
@@ -795,7 +804,7 @@ TEST_F(ProxyServiceTest, PAC_ConfigSourcePropagates) {
resolver.pending_requests()[0]->results()->UseNamedProxy("foopy");
resolver.pending_requests()[0]->CompleteNow(OK);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(PROXY_CONFIG_SOURCE_TEST, info.config_source());
EXPECT_TRUE(info.did_use_pac_script());
@@ -823,10 +832,9 @@ TEST_F(ProxyServiceTest, ProxyResolverFails) {
GURL url("http://www.google.com/");
ProxyInfo info;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
factory->pending_requests()[0]->script_data()->url());
@@ -840,7 +848,7 @@ TEST_F(ProxyServiceTest, ProxyResolverFails) {
// Although the proxy resolver failed the request, ProxyService implicitly
// falls-back to DIRECT.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_TRUE(info.is_direct());
// Failed PAC executions still have proxy resolution times.
@@ -851,10 +859,9 @@ TEST_F(ProxyServiceTest, ProxyResolverFails) {
// The second resolve request will try to run through the proxy resolver,
// regardless of whether the first request failed in it.
TestCompletionCallback callback2;
- rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback2.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(url, std::string(), &info, callback2.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ASSERT_EQ(1u, resolver.pending_requests().size());
EXPECT_EQ(url, resolver.pending_requests()[0]->url());
@@ -864,7 +871,7 @@ TEST_F(ProxyServiceTest, ProxyResolverFails) {
resolver.pending_requests()[0]->results()->UseNamedProxy("foopy_valid:8080");
resolver.pending_requests()[0]->CompleteNow(OK);
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy_valid:8080", info.proxy_server().ToURI());
}
@@ -887,10 +894,9 @@ TEST_F(ProxyServiceTest, ProxyResolverTerminatedDuringRequest) {
GURL url("http://www.google.com/");
ProxyInfo info;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url, std::string(), net::LOAD_NORMAL, &info,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ASSERT_EQ(1u, factory->pending_requests().size());
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -905,7 +911,7 @@ TEST_F(ProxyServiceTest, ProxyResolverTerminatedDuringRequest) {
// Although the proxy resolver failed the request, ProxyService implicitly
// falls-back to DIRECT.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_TRUE(info.is_direct());
// Failed PAC executions still have proxy resolution times.
@@ -918,10 +924,9 @@ TEST_F(ProxyServiceTest, ProxyResolverTerminatedDuringRequest) {
EXPECT_TRUE(factory->pending_requests().empty());
TestCompletionCallback callback2;
- rv = service.ResolveProxy(url, std::string(), net::LOAD_NORMAL, &info,
- callback2.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(url, std::string(), &info, callback2.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ASSERT_EQ(1u, factory->pending_requests().size());
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -935,7 +940,7 @@ TEST_F(ProxyServiceTest, ProxyResolverTerminatedDuringRequest) {
resolver.pending_requests()[0]->results()->UseNamedProxy("foopy_valid:8080");
resolver.pending_requests()[0]->CompleteNow(OK);
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy_valid:8080", info.proxy_server().ToURI());
}
@@ -960,15 +965,14 @@ TEST_F(ProxyServiceTest,
GURL url2("https://www.google.com/");
ProxyInfo info;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url1, std::string(), net::LOAD_NORMAL, &info,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv =
+ service.ResolveProxy(url1, std::string(), &info, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestCompletionCallback callback2;
- rv = service.ResolveProxy(url2, std::string(), net::LOAD_NORMAL, &info,
- callback2.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(url2, std::string(), &info, callback2.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ASSERT_EQ(1u, factory->pending_requests().size());
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -982,7 +986,7 @@ TEST_F(ProxyServiceTest,
// Although the proxy resolver failed the request, ProxyService implicitly
// falls-back to DIRECT.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_TRUE(info.is_direct());
// Failed PAC executions still have proxy resolution times.
@@ -1006,7 +1010,7 @@ TEST_F(ProxyServiceTest,
requests[url2]->results()->UseNamedProxy("foopy_valid:8080");
requests[url2]->CompleteNow(OK);
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy_valid:8080", info.proxy_server().ToURI());
}
@@ -1031,10 +1035,9 @@ TEST_F(ProxyServiceTest, ProxyScriptFetcherFailsDownloadingMandatoryPac) {
GURL url("http://www.google.com/");
ProxyInfo info;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
factory->pending_requests()[0]->script_data()->url());
@@ -1050,10 +1053,9 @@ TEST_F(ProxyServiceTest, ProxyScriptFetcherFailsDownloadingMandatoryPac) {
// As the proxy resolver factory failed the request and is configured for a
// mandatory PAC script, ProxyService must not implicitly fall-back to DIRECT.
TestCompletionCallback callback2;
- rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback2.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED, rv);
+ rv = service.ResolveProxy(url, std::string(), &info, callback2.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED));
EXPECT_FALSE(info.is_direct());
}
@@ -1076,16 +1078,15 @@ TEST_F(ProxyServiceTest, ProxyResolverFailsParsingJavaScriptMandatoryPac) {
MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
service.SetProxyScriptFetchers(
- fetcher, base::WrapUnique(new DoNothingDhcpProxyScriptFetcher()));
+ fetcher, base::MakeUnique<DoNothingDhcpProxyScriptFetcher>());
// Start resolve request.
GURL url("http://www.google.com/");
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Check that nothing has been sent to the proxy resolver factory yet.
ASSERT_EQ(0u, factory->pending_requests().size());
@@ -1129,10 +1130,9 @@ TEST_F(ProxyServiceTest, ProxyResolverFailsInJavaScriptMandatoryPac) {
GURL url("http://www.google.com/");
ProxyInfo info;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
factory->pending_requests()[0]->script_data()->url());
@@ -1153,10 +1153,9 @@ TEST_F(ProxyServiceTest, ProxyResolverFailsInJavaScriptMandatoryPac) {
// The second resolve request will try to run through the proxy resolver,
// regardless of whether the first request failed in it.
TestCompletionCallback callback2;
- rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback2.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(url, std::string(), &info, callback2.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ASSERT_EQ(1u, resolver.pending_requests().size());
EXPECT_EQ(url, resolver.pending_requests()[0]->url());
@@ -1166,7 +1165,7 @@ TEST_F(ProxyServiceTest, ProxyResolverFailsInJavaScriptMandatoryPac) {
resolver.pending_requests()[0]->results()->UseNamedProxy("foopy_valid:8080");
resolver.pending_requests()[0]->CompleteNow(OK);
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy_valid:8080", info.proxy_server().ToURI());
}
@@ -1190,10 +1189,9 @@ TEST_F(ProxyServiceTest, ProxyFallback) {
// Get the proxy information.
ProxyInfo info;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
factory->pending_requests()[0]->script_data()->url());
@@ -1208,7 +1206,7 @@ TEST_F(ProxyServiceTest, ProxyFallback) {
resolver.pending_requests()[0]->CompleteNow(OK);
// The first item is valid.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
@@ -1221,9 +1219,9 @@ TEST_F(ProxyServiceTest, ProxyFallback) {
// Fake an error on the proxy.
TestCompletionCallback callback2;
rv = service.ReconsiderProxyAfterError(
- url, std::string(), LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback2.callback(), nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ url, std::string(), ERR_PROXY_CONNECTION_FAILED, &info,
+ callback2.callback(), nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
// Proxy times should not have been modified by fallback.
EXPECT_EQ(proxy_resolve_start_time, info.proxy_resolve_start_time());
@@ -1240,10 +1238,9 @@ TEST_F(ProxyServiceTest, ProxyFallback) {
test_delegate.proxy_fallback_net_error());
TestCompletionCallback callback3;
- rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback3.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(url, std::string(), &info, callback3.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ASSERT_EQ(1u, resolver.pending_requests().size());
EXPECT_EQ(url, resolver.pending_requests()[0]->url());
@@ -1254,7 +1251,7 @@ TEST_F(ProxyServiceTest, ProxyFallback) {
"foopy3:7070;foopy1:8080;foopy2:9090");
resolver.pending_requests()[0]->CompleteNow(OK);
- EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_THAT(callback3.WaitForResult(), IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy3:7070", info.proxy_server().ToURI());
@@ -1269,9 +1266,9 @@ TEST_F(ProxyServiceTest, ProxyFallback) {
// We fake another error. It should now try the third one.
TestCompletionCallback callback4;
rv = service.ReconsiderProxyAfterError(
- url, std::string(), LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback4.callback(), nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ url, std::string(), ERR_PROXY_CONNECTION_FAILED, &info,
+ callback4.callback(), nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
// We fake another error. At this point we have tried all of the
@@ -1279,18 +1276,18 @@ TEST_F(ProxyServiceTest, ProxyFallback) {
// that was in our bad proxies map (foopy1:8080).
TestCompletionCallback callback5;
rv = service.ReconsiderProxyAfterError(
- url, std::string(), LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback5.callback(), nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ url, std::string(), ERR_PROXY_CONNECTION_FAILED, &info,
+ callback5.callback(), nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
// Fake another error, the last proxy is gone, the list should now be empty,
// so there is nothing left to try.
TestCompletionCallback callback6;
rv = service.ReconsiderProxyAfterError(
- url, std::string(), LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback6.callback(), nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(ERR_FAILED, rv);
+ url, std::string(), ERR_PROXY_CONNECTION_FAILED, &info,
+ callback6.callback(), nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_FAILED));
EXPECT_FALSE(info.is_direct());
EXPECT_TRUE(info.is_empty());
@@ -1300,10 +1297,9 @@ TEST_F(ProxyServiceTest, ProxyFallback) {
// Look up proxies again
TestCompletionCallback callback7;
- rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback7.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(url, std::string(), &info, callback7.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ASSERT_EQ(1u, resolver.pending_requests().size());
EXPECT_EQ(url, resolver.pending_requests()[0]->url());
@@ -1315,7 +1311,7 @@ TEST_F(ProxyServiceTest, ProxyFallback) {
resolver.pending_requests()[0]->CompleteNow(OK);
// ... therefore, we should see the second proxy first.
- EXPECT_EQ(OK, callback7.WaitForResult());
+ EXPECT_THAT(callback7.WaitForResult(), IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy3:7070", info.proxy_server().ToURI());
@@ -1343,10 +1339,9 @@ TEST_F(ProxyServiceTest, ProxyFallbackToDirect) {
// Get the proxy information.
ProxyInfo info;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
factory->pending_requests()[0]->script_data()->url());
@@ -1361,16 +1356,16 @@ TEST_F(ProxyServiceTest, ProxyFallbackToDirect) {
resolver.pending_requests()[0]->CompleteNow(OK);
// Get the first result.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
// Fake an error on the proxy.
TestCompletionCallback callback2;
rv = service.ReconsiderProxyAfterError(
- url, std::string(), LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback2.callback(), nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ url, std::string(), ERR_PROXY_CONNECTION_FAILED, &info,
+ callback2.callback(), nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
// Now we get back the second proxy.
EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
@@ -1378,9 +1373,9 @@ TEST_F(ProxyServiceTest, ProxyFallbackToDirect) {
// Fake an error on this proxy as well.
TestCompletionCallback callback3;
rv = service.ReconsiderProxyAfterError(
- url, std::string(), LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback3.callback(), nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ url, std::string(), ERR_PROXY_CONNECTION_FAILED, &info,
+ callback3.callback(), nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
// Finally, we get back DIRECT.
EXPECT_TRUE(info.is_direct());
@@ -1392,11 +1387,11 @@ TEST_F(ProxyServiceTest, ProxyFallbackToDirect) {
// Now we tell the proxy service that even DIRECT failed.
TestCompletionCallback callback4;
rv = service.ReconsiderProxyAfterError(
- url, std::string(), LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback4.callback(), nullptr, nullptr, BoundNetLog());
+ url, std::string(), ERR_PROXY_CONNECTION_FAILED, &info,
+ callback4.callback(), nullptr, nullptr, NetLogWithSource());
// There was nothing left to try after DIRECT, so we are out of
// choices.
- EXPECT_EQ(ERR_FAILED, rv);
+ EXPECT_THAT(rv, IsError(ERR_FAILED));
}
TEST_F(ProxyServiceTest, ProxyFallback_NewSettings) {
@@ -1417,10 +1412,9 @@ TEST_F(ProxyServiceTest, ProxyFallback_NewSettings) {
// Get the proxy information.
ProxyInfo info;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
factory->pending_requests()[0]->script_data()->url());
@@ -1435,7 +1429,7 @@ TEST_F(ProxyServiceTest, ProxyFallback_NewSettings) {
resolver.pending_requests()[0]->CompleteNow(OK);
// The first item is valid.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
@@ -1445,9 +1439,9 @@ TEST_F(ProxyServiceTest, ProxyFallback_NewSettings) {
TestCompletionCallback callback2;
rv = service.ReconsiderProxyAfterError(
- url, std::string(), LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback2.callback(), nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ url, std::string(), ERR_PROXY_CONNECTION_FAILED, &info,
+ callback2.callback(), nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(GURL("http://foopy-new/proxy.pac"),
factory->pending_requests()[0]->script_data()->url());
@@ -1461,15 +1455,15 @@ TEST_F(ProxyServiceTest, ProxyFallback_NewSettings) {
resolver.pending_requests()[0]->CompleteNow(OK);
// The first proxy is still there since the configuration changed.
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
// We fake another error. It should now ignore the first one.
TestCompletionCallback callback3;
rv = service.ReconsiderProxyAfterError(
- url, std::string(), LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback3.callback(), nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ url, std::string(), ERR_PROXY_CONNECTION_FAILED, &info,
+ callback3.callback(), nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
// We simulate a new configuration.
@@ -1480,9 +1474,9 @@ TEST_F(ProxyServiceTest, ProxyFallback_NewSettings) {
// We fake another error. It should go back to the first proxy.
TestCompletionCallback callback4;
rv = service.ReconsiderProxyAfterError(
- url, std::string(), LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback4.callback(), nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ url, std::string(), ERR_PROXY_CONNECTION_FAILED, &info,
+ callback4.callback(), nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(GURL("http://foopy-new2/proxy.pac"),
factory->pending_requests()[0]->script_data()->url());
@@ -1495,7 +1489,7 @@ TEST_F(ProxyServiceTest, ProxyFallback_NewSettings) {
"foopy1:8080;foopy2:9090");
resolver.pending_requests()[0]->CompleteNow(OK);
- EXPECT_EQ(OK, callback4.WaitForResult());
+ EXPECT_THAT(callback4.WaitForResult(), IsOk());
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
@@ -1521,10 +1515,9 @@ TEST_F(ProxyServiceTest, ProxyFallback_BadConfig) {
// Get the proxy information.
ProxyInfo info;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
factory->pending_requests()[0]->script_data()->url());
@@ -1537,16 +1530,16 @@ TEST_F(ProxyServiceTest, ProxyFallback_BadConfig) {
resolver.pending_requests()[0]->CompleteNow(OK);
// The first item is valid.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
// Fake a proxy error.
TestCompletionCallback callback2;
rv = service.ReconsiderProxyAfterError(
- url, std::string(), LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback2.callback(), nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ url, std::string(), ERR_PROXY_CONNECTION_FAILED, &info,
+ callback2.callback(), nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
// The first proxy is ignored, and the second one is selected.
EXPECT_FALSE(info.is_direct());
@@ -1555,10 +1548,9 @@ TEST_F(ProxyServiceTest, ProxyFallback_BadConfig) {
// Fake a PAC failure.
ProxyInfo info2;
TestCompletionCallback callback3;
- rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info2,
- callback3.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(url, std::string(), &info2, callback3.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ASSERT_EQ(1u, resolver.pending_requests().size());
EXPECT_EQ(url, resolver.pending_requests()[0]->url());
@@ -1568,7 +1560,7 @@ TEST_F(ProxyServiceTest, ProxyFallback_BadConfig) {
// Although the resolver failed, the ProxyService will implicitly fall-back
// to a DIRECT connection.
- EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_THAT(callback3.WaitForResult(), IsOk());
EXPECT_TRUE(info2.is_direct());
EXPECT_FALSE(info2.is_empty());
@@ -1578,9 +1570,9 @@ TEST_F(ProxyServiceTest, ProxyFallback_BadConfig) {
ProxyInfo info3;
TestCompletionCallback callback4;
rv = service.ReconsiderProxyAfterError(
- url, std::string(), LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info3,
- callback4.callback(), nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ url, std::string(), ERR_PROXY_CONNECTION_FAILED, &info3,
+ callback4.callback(), nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ASSERT_EQ(1u, resolver.pending_requests().size());
EXPECT_EQ(url, resolver.pending_requests()[0]->url());
@@ -1591,7 +1583,7 @@ TEST_F(ProxyServiceTest, ProxyFallback_BadConfig) {
// The first proxy is not there since the it was added to the bad proxies
// list by the earlier ReconsiderProxyAfterError().
- EXPECT_EQ(OK, callback4.WaitForResult());
+ EXPECT_THAT(callback4.WaitForResult(), IsOk());
EXPECT_FALSE(info3.is_direct());
EXPECT_EQ("foopy1:8080", info3.proxy_server().ToURI());
@@ -1621,10 +1613,9 @@ TEST_F(ProxyServiceTest, ProxyFallback_BadConfigMandatory) {
// Get the proxy information.
ProxyInfo info;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
factory->pending_requests()[0]->script_data()->url());
@@ -1637,16 +1628,16 @@ TEST_F(ProxyServiceTest, ProxyFallback_BadConfigMandatory) {
resolver.pending_requests()[0]->CompleteNow(OK);
// The first item is valid.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
// Fake a proxy error.
TestCompletionCallback callback2;
rv = service.ReconsiderProxyAfterError(
- url, std::string(), LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info,
- callback2.callback(), nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ url, std::string(), ERR_PROXY_CONNECTION_FAILED, &info,
+ callback2.callback(), nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
// The first proxy is ignored, and the second one is selected.
EXPECT_FALSE(info.is_direct());
@@ -1655,10 +1646,9 @@ TEST_F(ProxyServiceTest, ProxyFallback_BadConfigMandatory) {
// Fake a PAC failure.
ProxyInfo info2;
TestCompletionCallback callback3;
- rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info2,
- callback3.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(url, std::string(), &info2, callback3.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ASSERT_EQ(1u, resolver.pending_requests().size());
EXPECT_EQ(url, resolver.pending_requests()[0]->url());
@@ -1679,9 +1669,9 @@ TEST_F(ProxyServiceTest, ProxyFallback_BadConfigMandatory) {
ProxyInfo info3;
TestCompletionCallback callback4;
rv = service.ReconsiderProxyAfterError(
- url, std::string(), LOAD_NORMAL, ERR_PROXY_CONNECTION_FAILED, &info3,
- callback4.callback(), nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ url, std::string(), ERR_PROXY_CONNECTION_FAILED, &info3,
+ callback4.callback(), nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ASSERT_EQ(1u, resolver.pending_requests().size());
EXPECT_EQ(url, resolver.pending_requests()[0]->url());
@@ -1692,7 +1682,7 @@ TEST_F(ProxyServiceTest, ProxyFallback_BadConfigMandatory) {
// The first proxy is not there since the it was added to the bad proxies
// list by the earlier ReconsiderProxyAfterError().
- EXPECT_EQ(OK, callback4.WaitForResult());
+ EXPECT_THAT(callback4.WaitForResult(), IsOk());
EXPECT_FALSE(info3.is_direct());
EXPECT_EQ("foopy1:8080", info3.proxy_server().ToURI());
}
@@ -1707,7 +1697,7 @@ TEST_F(ProxyServiceTest, ProxyBypassList) {
config.set_auto_detect(false);
config.proxy_rules().bypass_rules.ParseFromString("*.org");
- ProxyService service(base::WrapUnique(new MockProxyConfigService(config)),
+ ProxyService service(base::MakeUnique<MockProxyConfigService>(config),
nullptr, nullptr);
int rv;
@@ -1715,17 +1705,17 @@ TEST_F(ProxyServiceTest, ProxyBypassList) {
GURL url2("http://www.webkit.com");
// Request for a .org domain should bypass proxy.
- rv = service.ResolveProxy(url1, std::string(), LOAD_NORMAL, &info[0],
+ rv = service.ResolveProxy(url1, std::string(), &info[0],
callback[0].callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(OK, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(info[0].is_direct());
// Request for a .com domain hits the proxy.
- rv = service.ResolveProxy(url2, std::string(), LOAD_NORMAL, &info[1],
+ rv = service.ResolveProxy(url2, std::string(), &info[1],
callback[1].callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(OK, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("foopy1:8080", info[1].proxy_server().ToURI());
}
@@ -1748,13 +1738,13 @@ TEST_F(ProxyServiceTest, MarkProxiesAsBadTests) {
EXPECT_EQ(3u, additional_bad_proxies.size());
- ProxyService service(base::WrapUnique(new MockProxyConfigService(config)),
+ ProxyService service(base::MakeUnique<MockProxyConfigService>(config),
nullptr, nullptr);
ProxyInfo proxy_info;
proxy_info.UseProxyList(proxy_list);
const ProxyRetryInfoMap& retry_info = service.proxy_retry_info();
service.MarkProxiesAsBadUntil(proxy_info, base::TimeDelta::FromSeconds(1),
- additional_bad_proxies, BoundNetLog());
+ additional_bad_proxies, NetLogWithSource());
ASSERT_EQ(4u, retry_info.size());
for (const ProxyServer& proxy_server :
config.proxy_rules().proxies_for_http.GetAll()) {
@@ -1769,55 +1759,55 @@ TEST_F(ProxyServiceTest, PerProtocolProxyTests) {
config.proxy_rules().ParseFromString("http=foopy1:8080;https=foopy2:8080");
config.set_auto_detect(false);
{
- ProxyService service(base::WrapUnique(new MockProxyConfigService(config)),
+ ProxyService service(base::MakeUnique<MockProxyConfigService>(config),
nullptr, nullptr);
GURL test_url("http://www.msn.com");
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service.ResolveProxy(test_url, std::string(), LOAD_NORMAL, &info,
+ int rv = service.ResolveProxy(test_url, std::string(), &info,
callback.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(OK, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
}
{
- ProxyService service(base::WrapUnique(new MockProxyConfigService(config)),
+ ProxyService service(base::MakeUnique<MockProxyConfigService>(config),
nullptr, nullptr);
GURL test_url("ftp://ftp.google.com");
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service.ResolveProxy(test_url, std::string(), LOAD_NORMAL, &info,
+ int rv = service.ResolveProxy(test_url, std::string(), &info,
callback.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(OK, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(info.is_direct());
EXPECT_EQ("direct://", info.proxy_server().ToURI());
}
{
- ProxyService service(base::WrapUnique(new MockProxyConfigService(config)),
+ ProxyService service(base::MakeUnique<MockProxyConfigService>(config),
nullptr, nullptr);
GURL test_url("https://webbranch.techcu.com");
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service.ResolveProxy(test_url, std::string(), LOAD_NORMAL, &info,
+ int rv = service.ResolveProxy(test_url, std::string(), &info,
callback.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(OK, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI());
}
{
config.proxy_rules().ParseFromString("foopy1:8080");
- ProxyService service(base::WrapUnique(new MockProxyConfigService(config)),
+ ProxyService service(base::MakeUnique<MockProxyConfigService>(config),
nullptr, nullptr);
GURL test_url("http://www.microsoft.com");
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service.ResolveProxy(test_url, std::string(), LOAD_NORMAL, &info,
+ int rv = service.ResolveProxy(test_url, std::string(), &info,
callback.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(OK, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
}
@@ -1831,15 +1821,15 @@ TEST_F(ProxyServiceTest, ProxyConfigSourcePropagates) {
ProxyConfig config;
config.set_source(PROXY_CONFIG_SOURCE_TEST);
config.proxy_rules().ParseFromString("https=foopy2:8080");
- ProxyService service(base::WrapUnique(new MockProxyConfigService(config)),
+ ProxyService service(base::MakeUnique<MockProxyConfigService>(config),
nullptr, nullptr);
GURL test_url("http://www.google.com");
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service.ResolveProxy(test_url, std::string(), LOAD_NORMAL, &info,
+ int rv = service.ResolveProxy(test_url, std::string(), &info,
callback.callback(), nullptr, nullptr,
- BoundNetLog());
- ASSERT_EQ(OK, rv);
+ NetLogWithSource());
+ ASSERT_THAT(rv, IsOk());
// Should be SOURCE_TEST, even if there are no HTTP proxies configured.
EXPECT_EQ(PROXY_CONFIG_SOURCE_TEST, info.config_source());
}
@@ -1847,30 +1837,30 @@ TEST_F(ProxyServiceTest, ProxyConfigSourcePropagates) {
ProxyConfig config;
config.set_source(PROXY_CONFIG_SOURCE_TEST);
config.proxy_rules().ParseFromString("https=foopy2:8080");
- ProxyService service(base::WrapUnique(new MockProxyConfigService(config)),
+ ProxyService service(base::MakeUnique<MockProxyConfigService>(config),
nullptr, nullptr);
GURL test_url("https://www.google.com");
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service.ResolveProxy(test_url, std::string(), LOAD_NORMAL, &info,
+ int rv = service.ResolveProxy(test_url, std::string(), &info,
callback.callback(), nullptr, nullptr,
- BoundNetLog());
- ASSERT_EQ(OK, rv);
+ NetLogWithSource());
+ ASSERT_THAT(rv, IsOk());
// Used the HTTPS proxy. So source should be TEST.
EXPECT_EQ(PROXY_CONFIG_SOURCE_TEST, info.config_source());
}
{
ProxyConfig config;
config.set_source(PROXY_CONFIG_SOURCE_TEST);
- ProxyService service(base::WrapUnique(new MockProxyConfigService(config)),
+ ProxyService service(base::MakeUnique<MockProxyConfigService>(config),
nullptr, nullptr);
GURL test_url("http://www.google.com");
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service.ResolveProxy(test_url, std::string(), LOAD_NORMAL, &info,
+ int rv = service.ResolveProxy(test_url, std::string(), &info,
callback.callback(), nullptr, nullptr,
- BoundNetLog());
- ASSERT_EQ(OK, rv);
+ NetLogWithSource());
+ ASSERT_THAT(rv, IsOk());
// ProxyConfig is empty. Source should still be TEST.
EXPECT_EQ(PROXY_CONFIG_SOURCE_TEST, info.config_source());
}
@@ -1891,10 +1881,10 @@ TEST_F(ProxyServiceTest, DefaultProxyFallbackToSOCKS) {
GURL test_url("http://www.msn.com");
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service.ResolveProxy(test_url, std::string(), LOAD_NORMAL, &info,
+ int rv = service.ResolveProxy(test_url, std::string(), &info,
callback.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(OK, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
}
@@ -1904,10 +1894,10 @@ TEST_F(ProxyServiceTest, DefaultProxyFallbackToSOCKS) {
GURL test_url("ftp://ftp.google.com");
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service.ResolveProxy(test_url, std::string(), LOAD_NORMAL, &info,
+ int rv = service.ResolveProxy(test_url, std::string(), &info,
callback.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(OK, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI());
}
@@ -1917,10 +1907,10 @@ TEST_F(ProxyServiceTest, DefaultProxyFallbackToSOCKS) {
GURL test_url("https://webbranch.techcu.com");
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service.ResolveProxy(test_url, std::string(), LOAD_NORMAL, &info,
+ int rv = service.ResolveProxy(test_url, std::string(), &info,
callback.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(OK, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI());
}
@@ -1930,10 +1920,10 @@ TEST_F(ProxyServiceTest, DefaultProxyFallbackToSOCKS) {
GURL test_url("unknown://www.microsoft.com");
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service.ResolveProxy(test_url, std::string(), LOAD_NORMAL, &info,
+ int rv = service.ResolveProxy(test_url, std::string(), &info,
callback.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(OK, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI());
}
@@ -1958,10 +1948,10 @@ TEST_F(ProxyServiceTest, CancelInProgressRequest) {
ProxyInfo info1;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url1, std::string(), LOAD_NORMAL, &info1,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv =
+ service.ResolveProxy(url1, std::string(), &info1, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Successfully initialize the PAC script.
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -1973,19 +1963,17 @@ TEST_F(ProxyServiceTest, CancelInProgressRequest) {
ProxyInfo info2;
TestCompletionCallback callback2;
ProxyService::PacRequest* request2;
- rv = service.ResolveProxy(url2, std::string(), LOAD_NORMAL, &info2,
- callback2.callback(), &request2, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(url2, std::string(), &info2, callback2.callback(),
+ &request2, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
GetPendingRequestsForURLs(resolver, url1, url2);
ProxyInfo info3;
TestCompletionCallback callback3;
- rv = service.ResolveProxy(url3, std::string(), LOAD_NORMAL, &info3,
- callback3.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(url3, std::string(), &info3, callback3.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
GetPendingRequestsForURLs(resolver, url1, url2, url3);
// Cancel the second request
@@ -2002,13 +1990,13 @@ TEST_F(ProxyServiceTest, CancelInProgressRequest) {
requests[url1]->CompleteNow(OK);
// Complete and verify that requests ran as expected.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
EXPECT_FALSE(callback2.have_result()); // Cancelled.
GetCancelledRequestsForURLs(resolver, url2);
- EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_THAT(callback3.WaitForResult(), IsOk());
EXPECT_EQ("request3:80", info3.proxy_server().ToURI());
}
@@ -2036,10 +2024,10 @@ TEST_F(ProxyServiceTest, InitialPACScriptDownload) {
ProxyInfo info1;
TestCompletionCallback callback1;
ProxyService::PacRequest* request1;
- int rv = service.ResolveProxy(url1, std::string(), LOAD_NORMAL, &info1,
- callback1.callback(), &request1, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv =
+ service.ResolveProxy(url1, std::string(), &info1, callback1.callback(),
+ &request1, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// The first request should have triggered download of PAC script.
EXPECT_TRUE(fetcher->has_pending_request());
@@ -2048,18 +2036,16 @@ TEST_F(ProxyServiceTest, InitialPACScriptDownload) {
ProxyInfo info2;
TestCompletionCallback callback2;
ProxyService::PacRequest* request2;
- rv = service.ResolveProxy(url2, std::string(), LOAD_NORMAL, &info2,
- callback2.callback(), &request2, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ 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;
- rv = service.ResolveProxy(url3, std::string(), LOAD_NORMAL, &info3,
- callback3.callback(), &request3, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(url3, std::string(), &info3, callback3.callback(),
+ &request3, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Nothing has been sent to the factory yet.
EXPECT_TRUE(factory->pending_requests().empty());
@@ -2100,19 +2086,19 @@ TEST_F(ProxyServiceTest, InitialPACScriptDownload) {
requests[url2]->CompleteNow(OK);
// Complete and verify that requests ran as expected.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
EXPECT_FALSE(info1.proxy_resolve_start_time().is_null());
EXPECT_FALSE(info1.proxy_resolve_end_time().is_null());
EXPECT_LE(info1.proxy_resolve_start_time(), info1.proxy_resolve_end_time());
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
EXPECT_FALSE(info2.proxy_resolve_start_time().is_null());
EXPECT_FALSE(info2.proxy_resolve_end_time().is_null());
EXPECT_LE(info2.proxy_resolve_start_time(), info2.proxy_resolve_end_time());
- EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_THAT(callback3.WaitForResult(), IsOk());
EXPECT_EQ("request3:80", info3.proxy_server().ToURI());
EXPECT_FALSE(info3.proxy_resolve_start_time().is_null());
EXPECT_FALSE(info3.proxy_resolve_end_time().is_null());
@@ -2141,10 +2127,10 @@ TEST_F(ProxyServiceTest, ChangeScriptFetcherWhilePACDownloadInProgress) {
ProxyInfo info1;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url1, std::string(), LOAD_NORMAL, &info1,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv =
+ service.ResolveProxy(url1, std::string(), &info1, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// The first request should have triggered download of PAC script.
EXPECT_TRUE(fetcher->has_pending_request());
@@ -2152,10 +2138,9 @@ TEST_F(ProxyServiceTest, ChangeScriptFetcherWhilePACDownloadInProgress) {
ProxyInfo info2;
TestCompletionCallback callback2;
- rv = service.ResolveProxy(url2, std::string(), LOAD_NORMAL, &info2,
- callback2.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(url2, std::string(), &info2, callback2.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// At this point the ProxyService should be waiting for the
// ProxyScriptFetcher to invoke its completion callback, notifying it of
@@ -2203,10 +2188,10 @@ TEST_F(ProxyServiceTest, CancelWhilePACFetching) {
TestCompletionCallback callback1;
ProxyService::PacRequest* request1;
BoundTestNetLog log1;
- int rv = service.ResolveProxy(GURL("http://request1"), std::string(),
- LOAD_NORMAL, &info1, callback1.callback(),
- &request1, nullptr, log1.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
+ callback1.callback(), &request1, nullptr,
+ log1.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// The first request should have triggered download of PAC script.
EXPECT_TRUE(fetcher->has_pending_request());
@@ -2215,17 +2200,17 @@ TEST_F(ProxyServiceTest, CancelWhilePACFetching) {
ProxyInfo info2;
TestCompletionCallback callback2;
ProxyService::PacRequest* request2;
- rv = service.ResolveProxy(GURL("http://request2"), std::string(), LOAD_NORMAL,
- &info2, callback2.callback(), &request2, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
+ callback2.callback(), &request2, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ProxyInfo info3;
TestCompletionCallback callback3;
- rv = service.ResolveProxy(GURL("http://request3"), std::string(), LOAD_NORMAL,
- &info3, callback3.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(GURL("http://request3"), std::string(), &info3,
+ callback3.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Nothing has been sent to the factory yet.
EXPECT_TRUE(factory->pending_requests().empty());
@@ -2252,7 +2237,7 @@ TEST_F(ProxyServiceTest, CancelWhilePACFetching) {
resolver.pending_requests()[0]->results()->UseNamedProxy("request3:80");
resolver.pending_requests()[0]->CompleteNow(OK);
- EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_THAT(callback3.WaitForResult(), IsOk());
EXPECT_EQ("request3:80", info3.proxy_server().ToURI());
EXPECT_TRUE(resolver.cancelled_requests().empty());
@@ -2265,16 +2250,15 @@ TEST_F(ProxyServiceTest, CancelWhilePACFetching) {
// Check the NetLog for request 1 (which was cancelled) got filled properly.
EXPECT_EQ(4u, entries1.size());
+ EXPECT_TRUE(
+ LogContainsBeginEvent(entries1, 0, NetLogEventType::PROXY_SERVICE));
EXPECT_TRUE(LogContainsBeginEvent(
- entries1, 0, NetLog::TYPE_PROXY_SERVICE));
- EXPECT_TRUE(LogContainsBeginEvent(
- entries1, 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
- // Note that TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC is never completed before
+ entries1, 1, NetLogEventType::PROXY_SERVICE_WAITING_FOR_INIT_PAC));
+ // Note that PROXY_SERVICE_WAITING_FOR_INIT_PAC is never completed before
// the cancellation occured.
- EXPECT_TRUE(LogContainsEvent(
- entries1, 2, NetLog::TYPE_CANCELLED, NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEndEvent(
- entries1, 3, NetLog::TYPE_PROXY_SERVICE));
+ EXPECT_TRUE(LogContainsEvent(entries1, 2, NetLogEventType::CANCELLED,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEndEvent(entries1, 3, NetLogEventType::PROXY_SERVICE));
}
// Test that if auto-detect fails, we fall-back to the custom pac.
@@ -2301,18 +2285,17 @@ TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomPac) {
ProxyInfo info1;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url1, std::string(), LOAD_NORMAL, &info1,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv =
+ service.ResolveProxy(url1, std::string(), &info1, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ProxyInfo info2;
TestCompletionCallback callback2;
ProxyService::PacRequest* request2;
- rv = service.ResolveProxy(url2, std::string(), LOAD_NORMAL, &info2,
- callback2.callback(), &request2, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(url2, std::string(), &info2, callback2.callback(),
+ &request2, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Check that nothing has been sent to the proxy resolver factory yet.
ASSERT_EQ(0u, factory->pending_requests().size());
@@ -2344,13 +2327,13 @@ TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomPac) {
requests[url1]->CompleteNow(OK);
// Verify that requests ran as expected.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
EXPECT_FALSE(info1.proxy_resolve_start_time().is_null());
EXPECT_FALSE(info1.proxy_resolve_end_time().is_null());
EXPECT_LE(info1.proxy_resolve_start_time(), info1.proxy_resolve_end_time());
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
EXPECT_FALSE(info2.proxy_resolve_start_time().is_null());
EXPECT_FALSE(info2.proxy_resolve_end_time().is_null());
@@ -2382,18 +2365,17 @@ TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomPac2) {
ProxyInfo info1;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(url1, std::string(), LOAD_NORMAL, &info1,
- callback1.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv =
+ service.ResolveProxy(url1, std::string(), &info1, callback1.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ProxyInfo info2;
TestCompletionCallback callback2;
ProxyService::PacRequest* request2;
- rv = service.ResolveProxy(url2, std::string(), LOAD_NORMAL, &info2,
- callback2.callback(), &request2, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(url2, std::string(), &info2, callback2.callback(),
+ &request2, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Check that nothing has been sent to the proxy resolver factory yet.
ASSERT_EQ(0u, factory->pending_requests().size());
@@ -2427,10 +2409,10 @@ TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomPac2) {
requests[url1]->CompleteNow(OK);
// Verify that requests ran as expected.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
}
@@ -2456,18 +2438,18 @@ TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomToManual) {
ProxyInfo info1;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(GURL("http://request1"), std::string(),
- LOAD_NORMAL, &info1, callback1.callback(),
- nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
+ callback1.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ProxyInfo info2;
TestCompletionCallback callback2;
ProxyService::PacRequest* request2;
- rv = service.ResolveProxy(GURL("http://request2"), std::string(), LOAD_NORMAL,
- &info2, callback2.callback(), &request2, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
+ callback2.callback(), &request2, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Check that nothing has been sent to the proxy resolver factory yet.
ASSERT_EQ(0u, factory->pending_requests().size());
@@ -2488,10 +2470,10 @@ TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomToManual) {
// Verify that requests ran as expected -- they should have fallen back to
// the manual proxy configuration for HTTP urls.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_EQ("foopy:80", info1.proxy_server().ToURI());
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_EQ("foopy:80", info2.proxy_server().ToURI());
}
@@ -2519,9 +2501,9 @@ TEST_F(ProxyServiceTest, BypassDoesntApplyToPac) {
ProxyInfo info1;
TestCompletionCallback callback1;
int rv = service.ResolveProxy(GURL("http://www.google.com"), std::string(),
- LOAD_NORMAL, &info1, callback1.callback(),
- nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ &info1, callback1.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Check that nothing has been sent to the proxy resolver factory yet.
ASSERT_EQ(0u, factory->pending_requests().size());
@@ -2544,16 +2526,16 @@ TEST_F(ProxyServiceTest, BypassDoesntApplyToPac) {
resolver.pending_requests()[0]->CompleteNow(OK);
// Verify that request ran as expected.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
// Start another request, it should pickup the bypass item.
ProxyInfo info2;
TestCompletionCallback callback2;
rv = service.ResolveProxy(GURL("http://www.google.com"), std::string(),
- LOAD_NORMAL, &info2, callback2.callback(), nullptr,
- nullptr, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ &info2, callback2.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ASSERT_EQ(1u, resolver.pending_requests().size());
EXPECT_EQ(GURL("http://www.google.com"),
@@ -2563,7 +2545,7 @@ TEST_F(ProxyServiceTest, BypassDoesntApplyToPac) {
resolver.pending_requests()[0]->results()->UseNamedProxy("request2:80");
resolver.pending_requests()[0]->CompleteNow(OK);
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
}
@@ -2590,9 +2572,9 @@ TEST_F(ProxyServiceTest, DeleteWhileInitProxyResolverHasOutstandingFetch) {
ProxyInfo info1;
TestCompletionCallback callback1;
int rv = service.ResolveProxy(GURL("http://www.google.com"), std::string(),
- LOAD_NORMAL, &info1, callback1.callback(),
- nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ &info1, callback1.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Check that nothing has been sent to the proxy resolver factory yet.
ASSERT_EQ(0u, factory->pending_requests().size());
@@ -2621,10 +2603,9 @@ TEST_F(ProxyServiceTest, DeleteWhileInitProxyResolverHasOutstandingSet) {
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service.ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
factory->pending_requests()[0]->script_data()->url());
@@ -2634,27 +2615,26 @@ TEST_F(ProxyServiceTest, ResetProxyConfigService) {
ProxyConfig config1;
config1.proxy_rules().ParseFromString("foopy1:8080");
config1.set_auto_detect(false);
- ProxyService service(base::WrapUnique(new MockProxyConfigService(config1)),
+ ProxyService service(base::MakeUnique<MockProxyConfigService>(config1),
nullptr, nullptr);
ProxyInfo info;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(GURL("http://request1"), std::string(),
- LOAD_NORMAL, &info, callback1.callback(),
- nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info,
+ callback1.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
ProxyConfig config2;
config2.proxy_rules().ParseFromString("foopy2:8080");
config2.set_auto_detect(false);
- service.ResetConfigService(
- base::WrapUnique(new MockProxyConfigService(config2)));
+ service.ResetConfigService(base::MakeUnique<MockProxyConfigService>(config2));
TestCompletionCallback callback2;
- rv = service.ResolveProxy(GURL("http://request2"), std::string(), LOAD_NORMAL,
- &info, callback2.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(OK, rv);
+ rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info,
+ callback2.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI());
}
@@ -2675,9 +2655,9 @@ TEST_F(ProxyServiceTest, UpdateConfigFromPACToDirect) {
ProxyInfo info1;
TestCompletionCallback callback1;
int rv = service.ResolveProxy(GURL("http://www.google.com"), std::string(),
- LOAD_NORMAL, &info1, callback1.callback(),
- nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ &info1, callback1.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Successfully set the autodetect script.
EXPECT_EQ(ProxyResolverScriptData::TYPE_AUTO_DETECT,
@@ -2690,7 +2670,7 @@ TEST_F(ProxyServiceTest, UpdateConfigFromPACToDirect) {
resolver.pending_requests()[0]->CompleteNow(OK);
// Verify that request ran as expected.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
// Force the ProxyService to pull down a new proxy configuration.
@@ -2704,9 +2684,9 @@ TEST_F(ProxyServiceTest, UpdateConfigFromPACToDirect) {
ProxyInfo info2;
TestCompletionCallback callback2;
rv = service.ResolveProxy(GURL("http://www.google.com"), std::string(),
- LOAD_NORMAL, &info2, callback2.callback(), nullptr,
- nullptr, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ &info2, callback2.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(info2.is_direct());
}
@@ -2726,7 +2706,7 @@ TEST_F(ProxyServiceTest, NetworkChangeTriggersPacRefetch) {
MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
service.SetProxyScriptFetchers(
- fetcher, base::WrapUnique(new DoNothingDhcpProxyScriptFetcher()));
+ fetcher, base::MakeUnique<DoNothingDhcpProxyScriptFetcher>());
// Disable the "wait after IP address changes" hack, so this unit-test can
// complete quickly.
@@ -2736,10 +2716,10 @@ TEST_F(ProxyServiceTest, NetworkChangeTriggersPacRefetch) {
ProxyInfo info1;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(GURL("http://request1"), std::string(),
- LOAD_NORMAL, &info1, callback1.callback(),
- nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
+ callback1.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// The first request should have triggered initial download of PAC script.
EXPECT_TRUE(fetcher->has_pending_request());
@@ -2767,7 +2747,7 @@ TEST_F(ProxyServiceTest, NetworkChangeTriggersPacRefetch) {
resolver.pending_requests()[0]->CompleteNow(OK);
// Wait for completion callback, and verify that the request ran as expected.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
// Now simluate a change in the network. The ProxyConfigService is still
@@ -2779,10 +2759,10 @@ TEST_F(ProxyServiceTest, NetworkChangeTriggersPacRefetch) {
// Start a second request.
ProxyInfo info2;
TestCompletionCallback callback2;
- rv = service.ResolveProxy(GURL("http://request2"), std::string(), LOAD_NORMAL,
- &info2, callback2.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
+ callback2.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// This second request should have triggered the re-download of the PAC
// script (since we marked the network as having changed).
@@ -2810,7 +2790,7 @@ TEST_F(ProxyServiceTest, NetworkChangeTriggersPacRefetch) {
resolver.pending_requests()[0]->CompleteNow(OK);
// Wait for completion callback, and verify that the request ran as expected.
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
// Check that the expected events were output to the log stream. In particular
@@ -2820,10 +2800,10 @@ TEST_F(ProxyServiceTest, NetworkChangeTriggersPacRefetch) {
log.GetEntries(&entries);
EXPECT_TRUE(LogContainsEntryWithType(entries, 0,
- NetLog::TYPE_PROXY_CONFIG_CHANGED));
+ NetLogEventType::PROXY_CONFIG_CHANGED));
ASSERT_EQ(9u, entries.size());
for (size_t i = 1; i < entries.size(); ++i)
- EXPECT_NE(NetLog::TYPE_PROXY_CONFIG_CHANGED, entries[i].type);
+ EXPECT_NE(NetLogEventType::PROXY_CONFIG_CHANGED, entries[i].type);
}
// This test verifies that the PAC script specified by the settings is
@@ -2854,10 +2834,10 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterFailure) {
ProxyInfo info1;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(GURL("http://request1"), std::string(),
- LOAD_NORMAL, &info1, callback1.callback(),
- nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
+ callback1.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// The first request should have triggered initial download of PAC script.
EXPECT_TRUE(fetcher->has_pending_request());
@@ -2877,7 +2857,7 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterFailure) {
ASSERT_TRUE(factory->pending_requests().empty());
// Wait for completion callback, and verify it used DIRECT.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_TRUE(info1.is_direct());
// At this point we have initialized the proxy service using a PAC script,
@@ -2915,10 +2895,10 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterFailure) {
// Start a second request.
ProxyInfo info2;
TestCompletionCallback callback2;
- rv = service.ResolveProxy(GURL("http://request2"), std::string(), LOAD_NORMAL,
- &info2, callback2.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
+ callback2.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Check that it was sent to the resolver.
ASSERT_EQ(1u, resolver.pending_requests().size());
@@ -2929,7 +2909,7 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterFailure) {
resolver.pending_requests()[0]->CompleteNow(OK);
// Wait for completion callback, and verify that the request ran as expected.
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
}
@@ -2961,10 +2941,10 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentChange) {
ProxyInfo info1;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(GURL("http://request1"), std::string(),
- LOAD_NORMAL, &info1, callback1.callback(),
- nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
+ callback1.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// The first request should have triggered initial download of PAC script.
EXPECT_TRUE(fetcher->has_pending_request());
@@ -2992,7 +2972,7 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentChange) {
resolver.pending_requests()[0]->CompleteNow(OK);
// Wait for completion callback, and verify that the request ran as expected.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
// At this point we have initialized the proxy service using a PAC script.
@@ -3028,10 +3008,10 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentChange) {
// Start a second request.
ProxyInfo info2;
TestCompletionCallback callback2;
- rv = service.ResolveProxy(GURL("http://request2"), std::string(), LOAD_NORMAL,
- &info2, callback2.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
+ callback2.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Check that it was sent to the resolver.
ASSERT_EQ(1u, resolver.pending_requests().size());
@@ -3042,7 +3022,7 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentChange) {
resolver.pending_requests()[0]->CompleteNow(OK);
// Wait for completion callback, and verify that the request ran as expected.
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
}
@@ -3074,10 +3054,10 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentUnchanged) {
ProxyInfo info1;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(GURL("http://request1"), std::string(),
- LOAD_NORMAL, &info1, callback1.callback(),
- nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
+ callback1.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// The first request should have triggered initial download of PAC script.
EXPECT_TRUE(fetcher->has_pending_request());
@@ -3105,7 +3085,7 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentUnchanged) {
resolver.pending_requests()[0]->CompleteNow(OK);
// Wait for completion callback, and verify that the request ran as expected.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
// At this point we have initialized the proxy service using a PAC script.
@@ -3138,10 +3118,10 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentUnchanged) {
// Start a second request.
ProxyInfo info2;
TestCompletionCallback callback2;
- rv = service.ResolveProxy(GURL("http://request2"), std::string(), LOAD_NORMAL,
- &info2, callback2.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
+ callback2.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Check that it was sent to the resolver.
ASSERT_EQ(1u, resolver.pending_requests().size());
@@ -3152,7 +3132,7 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentUnchanged) {
resolver.pending_requests()[0]->CompleteNow(OK);
// Wait for completion callback, and verify that the request ran as expected.
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
}
@@ -3184,10 +3164,10 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterSuccess) {
ProxyInfo info1;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(GURL("http://request1"), std::string(),
- LOAD_NORMAL, &info1, callback1.callback(),
- nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
+ callback1.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// The first request should have triggered initial download of PAC script.
EXPECT_TRUE(fetcher->has_pending_request());
@@ -3215,7 +3195,7 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterSuccess) {
resolver.pending_requests()[0]->CompleteNow(OK);
// Wait for completion callback, and verify that the request ran as expected.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
// At this point we have initialized the proxy service using a PAC script.
@@ -3245,10 +3225,10 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterSuccess) {
// Start a second request.
ProxyInfo info2;
TestCompletionCallback callback2;
- rv = service.ResolveProxy(GURL("http://request2"), std::string(), LOAD_NORMAL,
- &info2, callback2.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(OK, rv);
+ rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
+ callback2.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(info2.is_direct());
}
@@ -3339,10 +3319,10 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterActivity) {
ProxyInfo info1;
TestCompletionCallback callback1;
- int rv = service.ResolveProxy(GURL("http://request1"), std::string(),
- LOAD_NORMAL, &info1, callback1.callback(),
- nullptr, nullptr, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
+ callback1.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// The first request should have triggered initial download of PAC script.
EXPECT_TRUE(fetcher->has_pending_request());
@@ -3370,7 +3350,7 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterActivity) {
resolver.pending_requests()[0]->CompleteNow(OK);
// Wait for completion callback, and verify that the request ran as expected.
- EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
// At this point we have initialized the proxy service using a PAC script.
@@ -3384,10 +3364,10 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterActivity) {
// Start a second request.
ProxyInfo info2;
TestCompletionCallback callback2;
- rv = service.ResolveProxy(GURL("http://request2"), std::string(), LOAD_NORMAL,
- &info2, callback2.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
+ callback2.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// This request should have sent work to the resolver; complete it.
ASSERT_EQ(1u, resolver.pending_requests().size());
@@ -3395,7 +3375,7 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterActivity) {
resolver.pending_requests()[0]->results()->UseNamedProxy("request2:80");
resolver.pending_requests()[0]->CompleteNow(OK);
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
// In response to getting that resolve request, the poller should have
@@ -3415,10 +3395,10 @@ TEST_F(ProxyServiceTest, PACScriptRefetchAfterActivity) {
// since the PAC script poller experienced a failure.
ProxyInfo info3;
TestCompletionCallback callback3;
- rv = service.ResolveProxy(GURL("http://request3"), std::string(), LOAD_NORMAL,
- &info3, callback3.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(OK, rv);
+ rv = service.ResolveProxy(GURL("http://request3"), std::string(), &info3,
+ callback3.callback(), nullptr, nullptr,
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(info3.is_direct());
}
@@ -3440,7 +3420,7 @@ TEST_F(ProxyServiceTest, SynchronousWithPAC) {
BoundTestNetLog log;
bool synchronous_success = service.TryResolveProxySynchronously(
- url, std::string(), LOAD_NORMAL, &info, nullptr, log.bound());
+ url, std::string(), &info, nullptr, log.bound());
EXPECT_FALSE(synchronous_success);
// |info| should not have been modified.
@@ -3466,7 +3446,7 @@ TEST_F(ProxyServiceTest, SynchronousWithFixedConfiguration) {
BoundTestNetLog log;
bool synchronous_success = service.TryResolveProxySynchronously(
- url, std::string(), LOAD_NORMAL, &info, nullptr, log.bound());
+ url, std::string(), &info, nullptr, log.bound());
EXPECT_TRUE(synchronous_success);
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy1", info.proxy_server().host_port_pair().host());
@@ -3496,10 +3476,10 @@ class SanitizeUrlHelper {
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service_->ResolveProxy(url, std::string(), LOAD_NORMAL, &info,
- callback.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv =
+ service_->ResolveProxy(url, std::string(), &info, callback.callback(),
+ nullptr, nullptr, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// First step is to download the PAC script.
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -3512,7 +3492,7 @@ class SanitizeUrlHelper {
// Complete the request.
resolver.pending_requests()[0]->results()->UsePacString("DIRECT");
resolver.pending_requests()[0]->CompleteNow(OK);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(info.is_direct());
}
@@ -3528,10 +3508,10 @@ class SanitizeUrlHelper {
// Issue a request and see what URL is sent to the proxy resolver.
ProxyInfo info;
TestCompletionCallback callback;
- int rv = service_->ResolveProxy(raw_url, std::string(), LOAD_NORMAL, &info,
+ int rv = service_->ResolveProxy(raw_url, std::string(), &info,
callback.callback(), nullptr, nullptr,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(1u, resolver.pending_requests().size());
@@ -3540,7 +3520,7 @@ class SanitizeUrlHelper {
// Complete the request.
resolver.pending_requests()[0]->results()->UsePacString("DIRECT");
resolver.pending_requests()[0]->CompleteNow(OK);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(info.is_direct());
return sanitized_url;
diff --git a/chromium/net/proxy/proxy_service_v8.cc b/chromium/net/proxy/proxy_service_v8.cc
index 8c93b570322..8a71be4405b 100644
--- a/chromium/net/proxy/proxy_service_v8.cc
+++ b/chromium/net/proxy/proxy_service_v8.cc
@@ -34,10 +34,10 @@ std::unique_ptr<ProxyService> CreateProxyServiceUsingV8ProxyResolver(
std::unique_ptr<ProxyService> proxy_service(new ProxyService(
std::move(proxy_config_service),
- base::WrapUnique(new ProxyResolverFactoryV8TracingWrapper(
+ base::MakeUnique<ProxyResolverFactoryV8TracingWrapper>(
host_resolver, net_log,
base::Bind(&NetworkDelegateErrorObserver::Create, network_delegate,
- base::ThreadTaskRunnerHandle::Get()))),
+ base::ThreadTaskRunnerHandle::Get())),
net_log));
// Configure fetchers to use for PAC script downloads and auto-detect.
diff --git a/chromium/net/quic/bidirectional_stream_quic_impl.cc b/chromium/net/quic/bidirectional_stream_quic_impl.cc
deleted file mode 100644
index 205fbd0d1a8..00000000000
--- a/chromium/net/quic/bidirectional_stream_quic_impl.cc
+++ /dev/null
@@ -1,357 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/bidirectional_stream_quic_impl.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/timer/timer.h"
-#include "net/http/bidirectional_stream_request_info.h"
-#include "net/quic/quic_connection.h"
-#include "net/socket/next_proto.h"
-#include "net/spdy/spdy_header_block.h"
-#include "net/spdy/spdy_http_utils.h"
-
-namespace net {
-
-BidirectionalStreamQuicImpl::BidirectionalStreamQuicImpl(
- const base::WeakPtr<QuicChromiumClientSession>& session)
- : session_(session),
- was_handshake_confirmed_(session->IsCryptoHandshakeConfirmed()),
- stream_(nullptr),
- request_info_(nullptr),
- delegate_(nullptr),
- response_status_(OK),
- negotiated_protocol_(kProtoUnknown),
- read_buffer_len_(0),
- headers_bytes_received_(0),
- headers_bytes_sent_(0),
- closed_stream_received_bytes_(0),
- closed_stream_sent_bytes_(0),
- has_sent_headers_(false),
- has_received_headers_(false),
- send_request_headers_automatically_(true),
- waiting_for_confirmation_(false),
- weak_factory_(this) {
- DCHECK(session_);
- session_->AddObserver(this);
-}
-
-BidirectionalStreamQuicImpl::~BidirectionalStreamQuicImpl() {
- Cancel();
- if (session_)
- session_->RemoveObserver(this);
-}
-
-void BidirectionalStreamQuicImpl::Start(
- const BidirectionalStreamRequestInfo* request_info,
- const BoundNetLog& net_log,
- bool send_request_headers_automatically,
- BidirectionalStreamImpl::Delegate* delegate,
- std::unique_ptr<base::Timer> /* timer */) {
- DCHECK(!stream_);
- CHECK(delegate);
-
- send_request_headers_automatically_ = send_request_headers_automatically;
- if (!session_) {
- NotifyError(was_handshake_confirmed_ ? ERR_QUIC_PROTOCOL_ERROR
- : ERR_QUIC_HANDSHAKE_FAILED);
- return;
- }
-
- delegate_ = delegate;
- request_info_ = request_info;
-
- int rv = stream_request_.StartRequest(
- session_, &stream_,
- base::Bind(&BidirectionalStreamQuicImpl::OnStreamReady,
- weak_factory_.GetWeakPtr()));
- if (rv == OK) {
- OnStreamReady(rv);
- } else if (!was_handshake_confirmed_) {
- NotifyError(ERR_QUIC_HANDSHAKE_FAILED);
- }
-}
-
-void BidirectionalStreamQuicImpl::SendRequestHeaders() {
- DCHECK(!has_sent_headers_);
- if (!stream_) {
- LOG(ERROR)
- << "Trying to send request headers after stream has been destroyed.";
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
- weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
- return;
- }
-
- SpdyHeaderBlock headers;
- HttpRequestInfo http_request_info;
- http_request_info.url = request_info_->url;
- http_request_info.method = request_info_->method;
- http_request_info.extra_headers = request_info_->extra_headers;
-
- CreateSpdyHeadersFromHttpRequest(http_request_info,
- http_request_info.extra_headers, HTTP2, true,
- &headers);
- size_t headers_bytes_sent = stream_->WriteHeaders(
- std::move(headers), request_info_->end_stream_on_headers, nullptr);
- headers_bytes_sent_ += headers_bytes_sent;
- has_sent_headers_ = true;
-}
-
-int BidirectionalStreamQuicImpl::ReadData(IOBuffer* buffer, int buffer_len) {
- DCHECK(buffer);
- DCHECK(buffer_len);
-
- if (!stream_) {
- // If the stream is already closed, there is no body to read.
- return response_status_;
- }
- int rv = stream_->Read(buffer, buffer_len);
- if (rv != ERR_IO_PENDING) {
- if (stream_->IsDoneReading()) {
- // If the write side is closed, OnFinRead() will call
- // BidirectionalStreamQuicImpl::OnClose().
- stream_->OnFinRead();
- }
- return rv;
- }
- // Read will complete asynchronously and Delegate::OnReadCompleted will be
- // called upon completion.
- read_buffer_ = buffer;
- read_buffer_len_ = buffer_len;
- return ERR_IO_PENDING;
-}
-
-void BidirectionalStreamQuicImpl::SendData(const scoped_refptr<IOBuffer>& data,
- int length,
- bool end_stream) {
- DCHECK(length > 0 || (length == 0 && end_stream));
- if (!stream_) {
- LOG(ERROR) << "Trying to send data after stream has been destroyed.";
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
- weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
- return;
- }
-
- std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler;
- if (!has_sent_headers_) {
- DCHECK(!send_request_headers_automatically_);
- // Creates a bundler only if there are headers to be sent along with the
- // single data buffer.
- bundler.reset(new QuicConnection::ScopedPacketBundler(
- session_->connection(), QuicConnection::SEND_ACK_IF_PENDING));
- SendRequestHeaders();
- }
-
- base::StringPiece string_data(data->data(), length);
- int rv = stream_->WriteStreamData(
- string_data, end_stream,
- base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
- weak_factory_.GetWeakPtr()));
- DCHECK(rv == OK || rv == ERR_IO_PENDING);
- if (rv == OK) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
- weak_factory_.GetWeakPtr(), OK));
- }
-}
-
-void BidirectionalStreamQuicImpl::SendvData(
- const std::vector<scoped_refptr<IOBuffer>>& buffers,
- const std::vector<int>& lengths,
- bool end_stream) {
- DCHECK_EQ(buffers.size(), lengths.size());
-
- if (!stream_) {
- LOG(ERROR) << "Trying to send data after stream has been destroyed.";
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
- weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
- return;
- }
-
- QuicConnection::ScopedPacketBundler bundler(
- session_->connection(), QuicConnection::SEND_ACK_IF_PENDING);
- if (!has_sent_headers_) {
- DCHECK(!send_request_headers_automatically_);
- SendRequestHeaders();
- }
-
- int rv = stream_->WritevStreamData(
- buffers, lengths, end_stream,
- base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
- weak_factory_.GetWeakPtr()));
-
- DCHECK(rv == OK || rv == ERR_IO_PENDING);
- if (rv == OK) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
- weak_factory_.GetWeakPtr(), OK));
- }
-}
-
-void BidirectionalStreamQuicImpl::Cancel() {
- if (delegate_) {
- delegate_ = nullptr;
- // Cancel any pending callbacks.
- weak_factory_.InvalidateWeakPtrs();
- }
- if (stream_) {
- stream_->Reset(QUIC_STREAM_CANCELLED);
- ResetStream();
- }
-}
-
-NextProto BidirectionalStreamQuicImpl::GetProtocol() const {
- return negotiated_protocol_;
-}
-
-int64_t BidirectionalStreamQuicImpl::GetTotalReceivedBytes() const {
- if (stream_)
- return headers_bytes_received_ + stream_->stream_bytes_read();
- return headers_bytes_received_ + closed_stream_received_bytes_;
-}
-
-int64_t BidirectionalStreamQuicImpl::GetTotalSentBytes() const {
- if (stream_)
- return headers_bytes_sent_ + stream_->stream_bytes_written();
- return headers_bytes_sent_ + closed_stream_sent_bytes_;
-}
-
-void BidirectionalStreamQuicImpl::OnHeadersAvailable(
- const SpdyHeaderBlock& headers,
- size_t frame_len) {
- headers_bytes_received_ += frame_len;
- negotiated_protocol_ = kProtoQUIC1SPDY3;
- if (!has_received_headers_) {
- has_received_headers_ = true;
- if (delegate_)
- delegate_->OnHeadersReceived(headers);
- } else {
- if (stream_->IsDoneReading()) {
- // If the write side is closed, OnFinRead() will call
- // BidirectionalStreamQuicImpl::OnClose().
- stream_->OnFinRead();
- }
- if (delegate_)
- delegate_->OnTrailersReceived(headers);
- }
-}
-
-void BidirectionalStreamQuicImpl::OnDataAvailable() {
- // Return early if ReadData has not been called.
- if (!read_buffer_)
- return;
-
- CHECK(read_buffer_);
- CHECK_NE(0, read_buffer_len_);
- int rv = ReadData(read_buffer_.get(), read_buffer_len_);
- if (rv == ERR_IO_PENDING) {
- // Spurrious notification. Wait for the next one.
- return;
- }
- read_buffer_ = nullptr;
- read_buffer_len_ = 0;
- if (delegate_)
- delegate_->OnDataRead(rv);
-}
-
-void BidirectionalStreamQuicImpl::OnClose() {
- DCHECK(stream_);
-
- if (stream_->connection_error() == QUIC_NO_ERROR &&
- stream_->stream_error() == QUIC_STREAM_NO_ERROR) {
- ResetStream();
- return;
- }
- NotifyError(was_handshake_confirmed_ ? ERR_QUIC_PROTOCOL_ERROR
- : ERR_QUIC_HANDSHAKE_FAILED);
-}
-
-void BidirectionalStreamQuicImpl::OnError(int error) {
- NotifyError(error);
-}
-
-bool BidirectionalStreamQuicImpl::HasSendHeadersComplete() {
- return has_sent_headers_;
-}
-
-void BidirectionalStreamQuicImpl::OnCryptoHandshakeConfirmed() {
- was_handshake_confirmed_ = true;
- if (waiting_for_confirmation_)
- NotifyStreamReady();
-}
-
-void BidirectionalStreamQuicImpl::OnSessionClosed(
- int error,
- bool /*port_migration_detected*/) {
- DCHECK_NE(OK, error);
- session_.reset();
- NotifyError(error);
-}
-
-void BidirectionalStreamQuicImpl::OnStreamReady(int rv) {
- DCHECK_NE(ERR_IO_PENDING, rv);
- DCHECK(rv == OK || !stream_);
- if (rv == OK) {
- stream_->SetDelegate(this);
- if (!was_handshake_confirmed_ && request_info_->method == "POST") {
- waiting_for_confirmation_ = true;
- return;
- }
- NotifyStreamReady();
- } else {
- NotifyError(rv);
- }
-}
-
-void BidirectionalStreamQuicImpl::OnSendDataComplete(int rv) {
- DCHECK(rv == OK || !stream_);
- if (rv == OK) {
- if (delegate_)
- delegate_->OnDataSent();
- } else {
- NotifyError(rv);
- }
-}
-
-void BidirectionalStreamQuicImpl::NotifyError(int error) {
- DCHECK_NE(OK, error);
- DCHECK_NE(ERR_IO_PENDING, error);
-
- ResetStream();
- if (delegate_) {
- response_status_ = error;
- BidirectionalStreamImpl::Delegate* delegate = delegate_;
- delegate_ = nullptr;
- // Cancel any pending callback.
- weak_factory_.InvalidateWeakPtrs();
- delegate->OnFailed(error);
- // |this| might be destroyed at this point.
- }
-}
-
-void BidirectionalStreamQuicImpl::NotifyStreamReady() {
- if (send_request_headers_automatically_) {
- SendRequestHeaders();
- }
- if (delegate_)
- delegate_->OnStreamReady(has_sent_headers_);
-}
-
-void BidirectionalStreamQuicImpl::ResetStream() {
- if (!stream_)
- return;
- closed_stream_received_bytes_ = stream_->stream_bytes_read();
- closed_stream_sent_bytes_ = stream_->stream_bytes_written();
- stream_->SetDelegate(nullptr);
- stream_ = nullptr;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/bidirectional_stream_quic_impl.h b/chromium/net/quic/bidirectional_stream_quic_impl.h
deleted file mode 100644
index 087d692523b..00000000000
--- a/chromium/net/quic/bidirectional_stream_quic_impl.h
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_BIDIRECTIONAL_STREAM_QUIC_IMPL_H_
-#define NET_QUIC_BIDIRECTIONAL_STREAM_QUIC_IMPL_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "net/http/bidirectional_stream_impl.h"
-#include "net/log/net_log.h"
-#include "net/quic/quic_chromium_client_session.h"
-#include "net/quic/quic_chromium_client_stream.h"
-#include "net/spdy/spdy_header_block.h"
-
-namespace base {
-class Timer;
-} // namespace base
-
-namespace net {
-
-struct BidirectionalStreamRequestInfo;
-class IOBuffer;
-
-class NET_EXPORT_PRIVATE BidirectionalStreamQuicImpl
- : public BidirectionalStreamImpl,
- public QuicChromiumClientStream::Delegate,
- public QuicChromiumClientSession::Observer {
- public:
- explicit BidirectionalStreamQuicImpl(
- const base::WeakPtr<QuicChromiumClientSession>& session);
-
- ~BidirectionalStreamQuicImpl() override;
-
- // BidirectionalStreamImpl implementation:
- void Start(const BidirectionalStreamRequestInfo* request_info,
- const BoundNetLog& net_log,
- bool send_request_headers_automatically,
- BidirectionalStreamImpl::Delegate* delegate,
- std::unique_ptr<base::Timer> timer) override;
- void SendRequestHeaders() override;
- int ReadData(IOBuffer* buffer, int buffer_len) override;
- void SendData(const scoped_refptr<IOBuffer>& data,
- int length,
- bool end_stream) override;
- void SendvData(const std::vector<scoped_refptr<IOBuffer>>& buffers,
- const std::vector<int>& lengths,
- bool end_stream) override;
- void Cancel() override;
- NextProto GetProtocol() const override;
- int64_t GetTotalReceivedBytes() const override;
- int64_t GetTotalSentBytes() const override;
-
- private:
- // QuicChromiumClientStream::Delegate implementation:
- void OnHeadersAvailable(const SpdyHeaderBlock& headers,
- size_t frame_len) override;
- void OnDataAvailable() override;
- void OnClose() override;
- void OnError(int error) override;
- bool HasSendHeadersComplete() override;
-
- // QuicChromiumClientSession::Observer implementation:
- void OnCryptoHandshakeConfirmed() override;
- void OnSessionClosed(int error, bool port_migration_detected) override;
-
- void OnStreamReady(int rv);
- void OnSendDataComplete(int rv);
- void OnReadDataComplete(int rv);
-
- // Notifies the delegate of an error.
- void NotifyError(int error);
- // Notifies the delegate that the stream is ready.
- void NotifyStreamReady();
- // Resets the stream and ensures that |delegate_| won't be called back.
- void ResetStream();
-
- base::WeakPtr<QuicChromiumClientSession> session_;
- bool was_handshake_confirmed_; // True if the crypto handshake succeeded.
- QuicChromiumClientSession::StreamRequest stream_request_;
- QuicChromiumClientStream* stream_; // Non-owning.
-
- const BidirectionalStreamRequestInfo* request_info_;
- BidirectionalStreamImpl::Delegate* delegate_;
- // Saves the response status if the stream is explicitly closed via OnError
- // or OnClose with an error. Once all buffered data has been returned, this
- // will be used as the final response.
- int response_status_;
-
- // The protocol that is negotiated.
- NextProto negotiated_protocol_;
- // User provided read buffer for ReadData() response.
- scoped_refptr<IOBuffer> read_buffer_;
- int read_buffer_len_;
-
- // Number of bytes received by the headers stream on behalf of this stream.
- int64_t headers_bytes_received_;
- // Number of bytes sent by the headers stream on behalf of this stream.
- int64_t headers_bytes_sent_;
- // After |stream_| has been closed, this keeps track of the total number of
- // bytes received over the network for |stream_| while it was open.
- int64_t closed_stream_received_bytes_;
- // After |stream_| has been closed, this keeps track of the total number of
- // bytes sent over the network for |stream_| while it was open.
- int64_t closed_stream_sent_bytes_;
- // Indicates whether initial headers have been sent.
- bool has_sent_headers_;
- // Indicates whether initial headers have been received.
- bool has_received_headers_;
-
- // Whether to automatically send request headers when stream is negotiated.
- // If false, headers will not be sent until SendRequestHeaders() is called or
- // until next SendData/SendvData, during which QUIC will try to combine header
- // frame with data frame in the same packet if possible.
- bool send_request_headers_automatically_;
-
- // True of this stream is waiting for the QUIC handshake to be confirmed
- // before sending headers.
- bool waiting_for_confirmation_;
-
- base::WeakPtrFactory<BidirectionalStreamQuicImpl> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(BidirectionalStreamQuicImpl);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_BIDIRECTIONAL_STREAM_QUIC_IMPL_H_
diff --git a/chromium/net/quic/bidirectional_stream_quic_impl_unittest.cc b/chromium/net/quic/bidirectional_stream_quic_impl_unittest.cc
deleted file mode 100644
index abad19b225b..00000000000
--- a/chromium/net/quic/bidirectional_stream_quic_impl_unittest.cc
+++ /dev/null
@@ -1,1675 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/bidirectional_stream_quic_impl.h"
-
-#include <utility>
-
-#include "base/callback_helpers.h"
-#include "base/memory/ptr_util.h"
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "net/base/ip_address.h"
-#include "net/base/net_errors.h"
-#include "net/http/bidirectional_stream_request_info.h"
-#include "net/http/transport_security_state.h"
-#include "net/log/test_net_log.h"
-#include "net/log/test_net_log_util.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/crypto/quic_server_info.h"
-#include "net/quic/quic_chromium_alarm_factory.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_chromium_packet_reader.h"
-#include "net/quic/quic_chromium_packet_writer.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_http_utils.h"
-#include "net/quic/spdy_utils.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
-#include "net/quic/test_tools/mock_random.h"
-#include "net/quic/test_tools/quic_connection_peer.h"
-#include "net/quic/test_tools/quic_test_packet_maker.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/quic/test_tools/test_task_runner.h"
-#include "net/socket/socket_test_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-namespace test {
-
-namespace {
-
-const char kUploadData[] = "Really nifty data!";
-const char kDefaultServerHostName[] = "www.google.com";
-const uint16_t kDefaultServerPort = 80;
-// Size of the buffer to be allocated for each read.
-const size_t kReadBufferSize = 4096;
-
-class TestDelegateBase : public BidirectionalStreamImpl::Delegate {
- public:
- TestDelegateBase(IOBuffer* read_buf, int read_buf_len)
- : TestDelegateBase(read_buf,
- read_buf_len,
- base::WrapUnique(new base::Timer(false, false))) {}
-
- TestDelegateBase(IOBuffer* read_buf,
- int read_buf_len,
- std::unique_ptr<base::Timer> timer)
- : read_buf_(read_buf),
- read_buf_len_(read_buf_len),
- timer_(std::move(timer)),
- loop_(nullptr),
- error_(OK),
- on_data_read_count_(0),
- on_data_sent_count_(0),
- not_expect_callback_(false),
- on_failed_called_(false),
- send_request_headers_automatically_(true),
- is_ready_(false) {
- loop_.reset(new base::RunLoop);
- }
-
- ~TestDelegateBase() override {}
-
- void OnStreamReady(bool request_headers_sent) override {
- CHECK(!is_ready_);
- CHECK(!on_failed_called_);
- EXPECT_EQ(send_request_headers_automatically_, request_headers_sent);
- CHECK(!not_expect_callback_);
- is_ready_ = true;
- loop_->Quit();
- }
-
- void OnHeadersReceived(const SpdyHeaderBlock& response_headers) override {
- CHECK(!on_failed_called_);
- CHECK(!not_expect_callback_);
-
- response_headers_ = response_headers.Clone();
- loop_->Quit();
- }
-
- void OnDataRead(int bytes_read) override {
- CHECK(!on_failed_called_);
- CHECK(!not_expect_callback_);
- CHECK(!callback_.is_null());
-
- ++on_data_read_count_;
- CHECK_GE(bytes_read, OK);
- data_received_.append(read_buf_->data(), bytes_read);
- base::ResetAndReturn(&callback_).Run(bytes_read);
- }
-
- void OnDataSent() override {
- CHECK(!on_failed_called_);
- CHECK(!not_expect_callback_);
-
- ++on_data_sent_count_;
- loop_->Quit();
- }
-
- void OnTrailersReceived(const SpdyHeaderBlock& trailers) override {
- CHECK(!on_failed_called_);
- CHECK(!not_expect_callback_);
-
- trailers_ = trailers.Clone();
- loop_->Quit();
- }
-
- void OnFailed(int error) override {
- CHECK(!on_failed_called_);
- CHECK(!not_expect_callback_);
- CHECK_EQ(OK, error_);
- CHECK_NE(OK, error);
-
- on_failed_called_ = true;
- error_ = error;
- loop_->Quit();
- }
-
- void Start(const BidirectionalStreamRequestInfo* request_info,
- const BoundNetLog& net_log,
- const base::WeakPtr<QuicChromiumClientSession> session) {
- stream_.reset(new BidirectionalStreamQuicImpl(session));
- stream_->Start(request_info, net_log, send_request_headers_automatically_,
- this, nullptr);
- }
-
- void SendRequestHeaders() { stream_->SendRequestHeaders(); }
-
- void SendData(const scoped_refptr<IOBuffer>& data,
- int length,
- bool end_of_stream) {
- not_expect_callback_ = true;
- stream_->SendData(data, length, end_of_stream);
- not_expect_callback_ = false;
- }
-
- void SendvData(const std::vector<scoped_refptr<IOBuffer>>& data,
- const std::vector<int>& lengths,
- bool end_of_stream) {
- not_expect_callback_ = true;
- stream_->SendvData(data, lengths, end_of_stream);
- not_expect_callback_ = false;
- }
-
- // Waits until next Delegate callback.
- void WaitUntilNextCallback() {
- loop_->Run();
- loop_.reset(new base::RunLoop);
- }
-
- // Calls ReadData on the |stream_| and updates |data_received_|.
- int ReadData(const CompletionCallback& callback) {
- not_expect_callback_ = true;
- int rv = stream_->ReadData(read_buf_.get(), read_buf_len_);
- not_expect_callback_ = false;
- if (rv > 0)
- data_received_.append(read_buf_->data(), rv);
- if (rv == ERR_IO_PENDING)
- callback_ = callback;
- return rv;
- }
-
- // Cancels |stream_|.
- void CancelStream() { stream_->Cancel(); }
-
- NextProto GetProtocol() const { return stream_->GetProtocol(); }
-
- int64_t GetTotalReceivedBytes() const {
- return stream_->GetTotalReceivedBytes();
- }
-
- int64_t GetTotalSentBytes() const { return stream_->GetTotalSentBytes(); }
-
- void DoNotSendRequestHeadersAutomatically() {
- send_request_headers_automatically_ = false;
- }
-
- // Const getters for internal states.
- const std::string& data_received() const { return data_received_; }
- int error() const { return error_; }
- const SpdyHeaderBlock& response_headers() const { return response_headers_; }
- const SpdyHeaderBlock& trailers() const { return trailers_; }
- int on_data_read_count() const { return on_data_read_count_; }
- int on_data_sent_count() const { return on_data_sent_count_; }
- bool on_failed_called() const { return on_failed_called_; }
- bool is_ready() const { return is_ready_; }
-
- protected:
- // Quits |loop_|.
- void QuitLoop() { loop_->Quit(); }
-
- // Deletes |stream_|.
- void DeleteStream() { stream_.reset(); }
-
- private:
- std::unique_ptr<BidirectionalStreamQuicImpl> stream_;
- scoped_refptr<IOBuffer> read_buf_;
- int read_buf_len_;
- std::unique_ptr<base::Timer> timer_;
- std::string data_received_;
- std::unique_ptr<base::RunLoop> loop_;
- SpdyHeaderBlock response_headers_;
- SpdyHeaderBlock trailers_;
- int error_;
- int on_data_read_count_;
- int on_data_sent_count_;
- // This is to ensure that delegate callback is not invoked synchronously when
- // calling into |stream_|.
- bool not_expect_callback_;
- bool on_failed_called_;
- CompletionCallback callback_;
- bool send_request_headers_automatically_;
- bool is_ready_;
-
- DISALLOW_COPY_AND_ASSIGN(TestDelegateBase);
-};
-
-// A delegate that deletes the stream in a particular callback.
-class DeleteStreamDelegate : public TestDelegateBase {
- public:
- // Specifies in which callback the stream can be deleted.
- enum Phase {
- ON_HEADERS_RECEIVED,
- ON_DATA_READ,
- ON_TRAILERS_RECEIVED,
- ON_FAILED,
- };
-
- DeleteStreamDelegate(IOBuffer* buf, int buf_len, Phase phase)
- : TestDelegateBase(buf, buf_len), phase_(phase) {}
- ~DeleteStreamDelegate() override {}
-
- void OnHeadersReceived(const SpdyHeaderBlock& response_headers) override {
- if (phase_ == ON_HEADERS_RECEIVED) {
- DeleteStream();
- }
- TestDelegateBase::OnHeadersReceived(response_headers);
- }
-
- void OnDataSent() override { NOTREACHED(); }
-
- void OnDataRead(int bytes_read) override {
- DCHECK_NE(ON_HEADERS_RECEIVED, phase_);
- if (phase_ == ON_DATA_READ)
- DeleteStream();
- TestDelegateBase::OnDataRead(bytes_read);
- }
-
- void OnTrailersReceived(const SpdyHeaderBlock& trailers) override {
- DCHECK_NE(ON_HEADERS_RECEIVED, phase_);
- DCHECK_NE(ON_DATA_READ, phase_);
- if (phase_ == ON_TRAILERS_RECEIVED)
- DeleteStream();
- TestDelegateBase::OnTrailersReceived(trailers);
- }
-
- void OnFailed(int error) override {
- DCHECK_EQ(ON_FAILED, phase_);
- DeleteStream();
- TestDelegateBase::OnFailed(error);
- }
-
- private:
- // Indicates in which callback the delegate should cancel or delete the
- // stream.
- Phase phase_;
-
- DISALLOW_COPY_AND_ASSIGN(DeleteStreamDelegate);
-};
-
-} // namespace
-
-class BidirectionalStreamQuicImplTest
- : public ::testing::TestWithParam<QuicVersion> {
- protected:
- static const bool kFin = true;
- static const bool kIncludeVersion = true;
- static const bool kIncludeCongestionFeedback = true;
-
- // Holds a packet to be written to the wire, and the IO mode that should
- // be used by the mock socket when performing the write.
- struct PacketToWrite {
- PacketToWrite(IoMode mode, QuicReceivedPacket* packet)
- : mode(mode), packet(packet) {}
- PacketToWrite(IoMode mode, int rv) : mode(mode), packet(nullptr), rv(rv) {}
- IoMode mode;
- QuicReceivedPacket* packet;
- int rv;
- };
-
- BidirectionalStreamQuicImplTest()
- : crypto_config_(CryptoTestUtils::ProofVerifierForTesting()),
- read_buffer_(new IOBufferWithSize(4096)),
- connection_id_(2),
- stream_id_(kClientDataStreamId1),
- client_maker_(GetParam(),
- connection_id_,
- &clock_,
- kDefaultServerHostName,
- Perspective::IS_CLIENT),
- server_maker_(GetParam(),
- connection_id_,
- &clock_,
- kDefaultServerHostName,
- Perspective::IS_SERVER),
- random_generator_(0) {
- IPAddress ip(192, 0, 2, 33);
- peer_addr_ = IPEndPoint(ip, 443);
- self_addr_ = IPEndPoint(ip, 8435);
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
- }
-
- ~BidirectionalStreamQuicImplTest() {
- session_->CloseSessionOnError(ERR_ABORTED, QUIC_INTERNAL_ERROR);
- for (size_t i = 0; i < writes_.size(); i++) {
- delete writes_[i].packet;
- }
- }
-
- void TearDown() override {
- EXPECT_TRUE(socket_data_->AllReadDataConsumed());
- EXPECT_TRUE(socket_data_->AllWriteDataConsumed());
- }
-
- // Adds a packet to the list of expected writes.
- void AddWrite(std::unique_ptr<QuicReceivedPacket> packet) {
- writes_.push_back(PacketToWrite(SYNCHRONOUS, packet.release()));
- }
-
- void ProcessPacket(std::unique_ptr<QuicReceivedPacket> packet) {
- connection_->ProcessUdpPacket(self_addr_, peer_addr_, *packet);
- }
-
- // Configures the test fixture to use the list of expected writes.
- void Initialize() {
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::ZERO_RTT);
- mock_writes_.reset(new MockWrite[writes_.size()]);
- for (size_t i = 0; i < writes_.size(); i++) {
- if (writes_[i].packet == nullptr) {
- mock_writes_[i] = MockWrite(writes_[i].mode, writes_[i].rv, i);
- } else {
- mock_writes_[i] = MockWrite(writes_[i].mode, writes_[i].packet->data(),
- writes_[i].packet->length());
- }
- }
-
- socket_data_.reset(new StaticSocketDataProvider(
- nullptr, 0, mock_writes_.get(), writes_.size()));
-
- std::unique_ptr<MockUDPClientSocket> socket(new MockUDPClientSocket(
- socket_data_.get(), net_log().bound().net_log()));
- socket->Connect(peer_addr_);
- runner_ = new TestTaskRunner(&clock_);
- helper_.reset(
- new QuicChromiumConnectionHelper(&clock_, &random_generator_));
- alarm_factory_.reset(new QuicChromiumAlarmFactory(runner_.get(), &clock_));
- connection_ = new QuicConnection(
- connection_id_, peer_addr_, helper_.get(), alarm_factory_.get(),
- new QuicChromiumPacketWriter(socket.get()), true /* owns_writer */,
- Perspective::IS_CLIENT, SupportedVersions(GetParam()));
-
- session_.reset(new QuicChromiumClientSession(
- connection_, std::move(socket),
- /*stream_factory=*/nullptr, &crypto_client_stream_factory_, &clock_,
- &transport_security_state_,
- base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)),
- QuicServerId(kDefaultServerHostName, kDefaultServerPort,
- PRIVACY_MODE_DISABLED),
- kQuicYieldAfterPacketsRead,
- QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds),
- /*cert_verify_flags=*/0, DefaultQuicConfig(), &crypto_config_,
- "CONNECTION_UNKNOWN", base::TimeTicks::Now(), &push_promise_index_,
- base::ThreadTaskRunnerHandle::Get().get(),
- /*socket_performance_watcher=*/nullptr, net_log().bound().net_log()));
- session_->Initialize();
- session_->GetCryptoStream()->CryptoConnect();
- EXPECT_TRUE(session_->IsEncryptionEstablished());
- }
-
- void ConfirmHandshake() {
- crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
- QuicSession::HANDSHAKE_CONFIRMED);
- }
-
- void SetRequest(const std::string& method,
- const std::string& path,
- RequestPriority priority) {
- request_headers_ = client_maker_.GetRequestHeaders(method, "http", path);
- }
-
- SpdyHeaderBlock ConstructResponseHeaders(const std::string& response_code) {
- return server_maker_.GetResponseHeaders(response_code);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructDataPacket(
- QuicPacketNumber packet_number,
- bool should_include_version,
- bool fin,
- QuicStreamOffset offset,
- base::StringPiece data,
- QuicTestPacketMaker* maker) {
- std::unique_ptr<QuicReceivedPacket> packet(maker->MakeDataPacket(
- packet_number, stream_id_, should_include_version, fin, offset, data));
- DVLOG(2) << "packet(" << packet_number << "): " << std::endl
- << QuicUtils::StringToHexASCIIDump(packet->AsStringPiece());
- return packet;
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructServerDataPacket(
- QuicPacketNumber packet_number,
- bool should_include_version,
- bool fin,
- QuicStreamOffset offset,
- base::StringPiece data) {
- return ConstructDataPacket(packet_number, should_include_version, fin,
- offset, data, &server_maker_);
- }
-
- // Construct a data packet with multiple data frames
- std::unique_ptr<QuicReceivedPacket> ConstructClientMultipleDataFramesPacket(
- QuicPacketNumber packet_number,
- bool should_include_version,
- bool fin,
- QuicStreamOffset offset,
- const std::vector<std::string>& data_writes) {
- std::unique_ptr<QuicReceivedPacket> packet(
- client_maker_.MakeMultipleDataFramesPacket(packet_number, stream_id_,
- should_include_version, fin,
- offset, data_writes));
- DVLOG(2) << "packet(" << packet_number << "): " << std::endl
- << QuicUtils::StringToHexASCIIDump(packet->AsStringPiece());
- return packet;
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructRequestHeadersPacket(
- QuicPacketNumber packet_number,
- bool fin,
- RequestPriority request_priority,
- size_t* spdy_headers_frame_length) {
- SpdyPriority priority =
- ConvertRequestPriorityToQuicPriority(request_priority);
- return client_maker_.MakeRequestHeadersPacket(
- packet_number, stream_id_, kIncludeVersion, fin, priority,
- std::move(request_headers_), spdy_headers_frame_length);
- }
-
- std::unique_ptr<QuicReceivedPacket>
- ConstructRequestHeadersAndMultipleDataFramesPacket(
- QuicPacketNumber packet_number,
- bool fin,
- RequestPriority request_priority,
- size_t* spdy_headers_frame_length,
- const std::vector<std::string>& data) {
- SpdyPriority priority =
- ConvertRequestPriorityToQuicPriority(request_priority);
- std::unique_ptr<QuicReceivedPacket> packet(
- client_maker_.MakeRequestHeadersAndMultipleDataFramesPacket(
- packet_number, stream_id_, kIncludeVersion, fin, priority,
- std::move(request_headers_), spdy_headers_frame_length, data));
- DVLOG(2) << "packet(" << packet_number << "): " << std::endl
- << QuicUtils::StringToHexASCIIDump(packet->AsStringPiece());
- return packet;
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructResponseHeadersPacket(
- QuicPacketNumber packet_number,
- bool fin,
- SpdyHeaderBlock response_headers,
- size_t* spdy_headers_frame_length,
- QuicStreamOffset* offset) {
- return server_maker_.MakeResponseHeadersPacket(
- packet_number, stream_id_, !kIncludeVersion, fin,
- std::move(response_headers), spdy_headers_frame_length, offset);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructResponseTrailersPacket(
- QuicPacketNumber packet_number,
- bool fin,
- SpdyHeaderBlock trailers,
- size_t* spdy_headers_frame_length,
- QuicStreamOffset* offset) {
- return server_maker_.MakeResponseHeadersPacket(
- packet_number, stream_id_, !kIncludeVersion, fin, std::move(trailers),
- spdy_headers_frame_length, offset);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructClientRstStreamPacket(
- QuicPacketNumber packet_number) {
- return ConstructRstStreamCancelledPacket(packet_number, 0, &client_maker_);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructServerRstStreamPacket(
- QuicPacketNumber packet_number) {
- return ConstructRstStreamCancelledPacket(packet_number, 0, &server_maker_);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructRstStreamCancelledPacket(
- QuicPacketNumber packet_number,
- size_t bytes_written,
- QuicTestPacketMaker* maker) {
- std::unique_ptr<QuicReceivedPacket> packet(
- maker->MakeRstPacket(packet_number, !kIncludeVersion, stream_id_,
- QUIC_STREAM_CANCELLED, bytes_written));
- DVLOG(2) << "packet(" << packet_number << "): " << std::endl
- << QuicUtils::StringToHexASCIIDump(packet->AsStringPiece());
- return packet;
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructClientAckAndRstStreamPacket(
- QuicPacketNumber packet_number,
- QuicPacketNumber largest_received,
- QuicPacketNumber ack_least_unacked,
- QuicPacketNumber stop_least_unacked) {
- return client_maker_.MakeAckAndRstPacket(
- packet_number, !kIncludeVersion, stream_id_, QUIC_STREAM_CANCELLED,
- largest_received, ack_least_unacked, stop_least_unacked,
- !kIncludeCongestionFeedback);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructAckAndDataPacket(
- QuicPacketNumber packet_number,
- bool should_include_version,
- QuicPacketNumber largest_received,
- QuicPacketNumber least_unacked,
- bool fin,
- QuicStreamOffset offset,
- base::StringPiece data,
- QuicTestPacketMaker* maker) {
- std::unique_ptr<QuicReceivedPacket> packet(maker->MakeAckAndDataPacket(
- packet_number, should_include_version, stream_id_, largest_received,
- least_unacked, fin, offset, data));
- DVLOG(2) << "packet(" << packet_number << "): " << std::endl
- << QuicUtils::StringToHexASCIIDump(packet->AsStringPiece());
- return packet;
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructClientAckPacket(
- QuicPacketNumber packet_number,
- QuicPacketNumber largest_received,
- QuicPacketNumber least_unacked) {
- return client_maker_.MakeAckPacket(packet_number, largest_received,
- least_unacked,
- !kIncludeCongestionFeedback);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructServerAckPacket(
- QuicPacketNumber packet_number,
- QuicPacketNumber largest_received,
- QuicPacketNumber least_unacked) {
- return server_maker_.MakeAckPacket(packet_number, largest_received,
- least_unacked,
- !kIncludeCongestionFeedback);
- }
-
- const BoundTestNetLog& net_log() const { return net_log_; }
-
- QuicChromiumClientSession* session() const { return session_.get(); }
-
- protected:
- BoundTestNetLog net_log_;
- scoped_refptr<TestTaskRunner> runner_;
- std::unique_ptr<MockWrite[]> mock_writes_;
- MockClock clock_;
- QuicConnection* connection_;
- std::unique_ptr<QuicChromiumConnectionHelper> helper_;
- std::unique_ptr<QuicChromiumAlarmFactory> alarm_factory_;
- TransportSecurityState transport_security_state_;
- std::unique_ptr<QuicChromiumClientSession> session_;
- QuicCryptoClientConfig crypto_config_;
- HttpRequestHeaders headers_;
- HttpResponseInfo response_;
- scoped_refptr<IOBufferWithSize> read_buffer_;
- SpdyHeaderBlock request_headers_;
- const QuicConnectionId connection_id_;
- const QuicStreamId stream_id_;
- QuicTestPacketMaker client_maker_;
- QuicTestPacketMaker server_maker_;
- IPEndPoint self_addr_;
- IPEndPoint peer_addr_;
- MockRandom random_generator_;
- MockCryptoClientStreamFactory crypto_client_stream_factory_;
- std::unique_ptr<StaticSocketDataProvider> socket_data_;
- std::vector<PacketToWrite> writes_;
- QuicClientPushPromiseIndex push_promise_index_;
-};
-
-INSTANTIATE_TEST_CASE_P(Version,
- BidirectionalStreamQuicImplTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
-
-TEST_P(BidirectionalStreamQuicImplTest, GetRequest) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
-
- AddWrite(ConstructClientAckPacket(2, 3, 1));
- Initialize();
-
- BidirectionalStreamRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.google.com/");
- request.end_stream_on_headers = true;
- request.priority = DEFAULT_PRIORITY;
-
- 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()->GetWeakPtr());
- delegate->WaitUntilNextCallback(); // OnStreamReady
-
- // Server acks the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Server sends the response headers.
- SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
-
- size_t spdy_response_headers_frame_length;
- QuicStreamOffset offset = 0;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, !kFin, std::move(response_headers),
- &spdy_response_headers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnHeadersReceived
- TestCompletionCallback cb;
- int rv = delegate->ReadData(cb.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
- const char kResponseBody[] = "Hello world!";
- // Server sends data.
- ProcessPacket(
- ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
- EXPECT_EQ(12, cb.WaitForResult());
-
- EXPECT_EQ(std::string(kResponseBody), delegate->data_received());
- TestCompletionCallback cb2;
- EXPECT_EQ(ERR_IO_PENDING, delegate->ReadData(cb2.callback()));
-
- SpdyHeaderBlock trailers;
- size_t spdy_trailers_frame_length;
- trailers["foo"] = "bar";
- trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
- // Server sends trailers.
- ProcessPacket(ConstructResponseTrailersPacket(
- 4, kFin, trailers.Clone(), &spdy_trailers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnTrailersReceived
- EXPECT_EQ(OK, cb2.WaitForResult());
- trailers.erase(kFinalOffsetHeaderKey);
- EXPECT_EQ(trailers, delegate->trailers());
-
- EXPECT_EQ(OK, delegate->ReadData(cb2.callback()));
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(2, delegate->on_data_read_count());
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(
- static_cast<int64_t>(spdy_response_headers_frame_length +
- strlen(kResponseBody) + spdy_trailers_frame_length),
- delegate->GetTotalReceivedBytes());
- // Check that NetLog was filled as expected.
- TestNetLogEntry::List entries;
- net_log().GetEntries(&entries);
- size_t pos = ExpectLogContainsSomewhere(
- entries, /*min_offset=*/0,
- NetLog::TYPE_QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
- NetLog::PHASE_NONE);
- pos = ExpectLogContainsSomewhere(
- entries, /*min_offset=*/pos,
- NetLog::TYPE_QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
- NetLog::PHASE_NONE);
- ExpectLogContainsSomewhere(
- entries, /*min_offset=*/pos,
- NetLog::TYPE_QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
- NetLog::PHASE_NONE);
-}
-
-// Tests that when request headers are not delayed, only data buffers are
-// coalesced.
-TEST_P(BidirectionalStreamQuicImplTest, CoalesceDataBuffersNotHeadersFrame) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
-
- const char kBody1[] = "here are some data";
- const char kBody2[] = "data keep coming";
- std::vector<std::string> two_writes = {kBody1, kBody2};
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructClientMultipleDataFramesPacket(2, kIncludeVersion, !kFin, 0,
- {kBody1, kBody2}));
- // Ack server's data packet.
- AddWrite(ConstructClientAckPacket(3, 3, 1));
- const char kBody3[] = "hello there";
- const char kBody4[] = "another piece of small data";
- const char kBody5[] = "really small";
- QuicStreamOffset data_offset = strlen(kBody1) + strlen(kBody2);
- AddWrite(ConstructClientMultipleDataFramesPacket(
- 4, !kIncludeVersion, kFin, data_offset, {kBody3, kBody4, kBody5}));
-
- Initialize();
-
- BidirectionalStreamRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.google.com/");
- request.end_stream_on_headers = false;
- request.priority = DEFAULT_PRIORITY;
-
- scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
- std::unique_ptr<TestDelegateBase> delegate(
- new TestDelegateBase(read_buffer.get(), kReadBufferSize));
- delegate->DoNotSendRequestHeadersAutomatically();
- delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
- EXPECT_FALSE(delegate->is_ready());
- ConfirmHandshake();
- delegate->WaitUntilNextCallback(); // OnStreamReady
-
- // Sends request headers separately, which causes them to be sent in a
- // separate packet.
- delegate->SendRequestHeaders();
- // Send a Data packet.
- scoped_refptr<StringIOBuffer> buf1(new StringIOBuffer(kBody1));
- scoped_refptr<StringIOBuffer> buf2(new StringIOBuffer(kBody2));
-
- std::vector<int> lengths = {buf1->size(), buf2->size()};
- delegate->SendvData({buf1, buf2}, lengths, !kFin);
- delegate->WaitUntilNextCallback(); // OnDataSent
-
- // Server acks the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Server sends the response headers.
- SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
- size_t spdy_response_headers_frame_length;
- QuicStreamOffset offset = 0;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, !kFin, std::move(response_headers),
- &spdy_response_headers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnHeadersReceived
- TestCompletionCallback cb;
- int rv = delegate->ReadData(cb.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
- const char kResponseBody[] = "Hello world!";
- // Server sends data.
- ProcessPacket(
- ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
-
- EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult());
-
- // Send a second Data packet.
- scoped_refptr<StringIOBuffer> buf3(new StringIOBuffer(kBody3));
- scoped_refptr<StringIOBuffer> buf4(new StringIOBuffer(kBody4));
- scoped_refptr<StringIOBuffer> buf5(new StringIOBuffer(kBody5));
-
- delegate->SendvData({buf3, buf4, buf5},
- {buf3->size(), buf4->size(), buf5->size()}, kFin);
- delegate->WaitUntilNextCallback(); // OnDataSent
-
- size_t spdy_trailers_frame_length;
- SpdyHeaderBlock trailers;
- trailers["foo"] = "bar";
- trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
- // Server sends trailers.
- ProcessPacket(ConstructResponseTrailersPacket(
- 4, kFin, trailers.Clone(), &spdy_trailers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnTrailersReceived
- trailers.erase(kFinalOffsetHeaderKey);
- EXPECT_EQ(trailers, delegate->trailers());
- EXPECT_EQ(OK, delegate->ReadData(cb.callback()));
-
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(2, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
- EXPECT_EQ(
- static_cast<int64_t>(spdy_request_headers_frame_length + strlen(kBody1) +
- strlen(kBody2) + strlen(kBody3) + strlen(kBody4) +
- strlen(kBody5)),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(
- static_cast<int64_t>(spdy_response_headers_frame_length +
- strlen(kResponseBody) + spdy_trailers_frame_length),
- delegate->GetTotalReceivedBytes());
-}
-
-// Tests that when request headers are delayed, SendData triggers coalescing of
-// request headers with data buffers.
-TEST_P(BidirectionalStreamQuicImplTest,
- SendDataCoalesceDataBufferAndHeaderFrame) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
-
- const char kBody1[] = "here are some data";
- AddWrite(ConstructRequestHeadersAndMultipleDataFramesPacket(
- 1, !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length,
- {kBody1}));
- // Ack server's data packet.
- AddWrite(ConstructClientAckPacket(2, 3, 1));
- const char kBody2[] = "really small";
- QuicStreamOffset data_offset = strlen(kBody1);
- AddWrite(ConstructClientMultipleDataFramesPacket(3, !kIncludeVersion, kFin,
- data_offset, {kBody2}));
-
- Initialize();
-
- BidirectionalStreamRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.google.com/");
- request.end_stream_on_headers = false;
- request.priority = DEFAULT_PRIORITY;
-
- scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
- std::unique_ptr<TestDelegateBase> delegate(
- new TestDelegateBase(read_buffer.get(), kReadBufferSize));
- delegate->DoNotSendRequestHeadersAutomatically();
- delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
- ConfirmHandshake();
- delegate->WaitUntilNextCallback(); // OnStreamReady
-
- // Send a Data packet.
- scoped_refptr<StringIOBuffer> buf1(new StringIOBuffer(kBody1));
-
- delegate->SendData(buf1, buf1->size(), false);
- delegate->WaitUntilNextCallback(); // OnDataSent
-
- // Server acks the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Server sends the response headers.
- SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
- size_t spdy_response_headers_frame_length;
- QuicStreamOffset offset = 0;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, !kFin, std::move(response_headers),
- &spdy_response_headers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnHeadersReceived
- TestCompletionCallback cb;
- int rv = delegate->ReadData(cb.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
- const char kResponseBody[] = "Hello world!";
- // Server sends data.
- ProcessPacket(
- ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
-
- EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult());
-
- // Send a second Data packet.
- scoped_refptr<StringIOBuffer> buf2(new StringIOBuffer(kBody2));
-
- delegate->SendData(buf2, buf2->size(), true);
- delegate->WaitUntilNextCallback(); // OnDataSent
-
- size_t spdy_trailers_frame_length;
- SpdyHeaderBlock trailers;
- trailers["foo"] = "bar";
- trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
- // Server sends trailers.
- ProcessPacket(ConstructResponseTrailersPacket(
- 4, kFin, trailers.Clone(), &spdy_trailers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnTrailersReceived
- trailers.erase(kFinalOffsetHeaderKey);
- EXPECT_EQ(trailers, delegate->trailers());
- EXPECT_EQ(OK, delegate->ReadData(cb.callback()));
-
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(2, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
- strlen(kBody1) + strlen(kBody2)),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(
- static_cast<int64_t>(spdy_response_headers_frame_length +
- strlen(kResponseBody) + spdy_trailers_frame_length),
- delegate->GetTotalReceivedBytes());
-}
-
-// Tests that when request headers are delayed, SendvData triggers coalescing of
-// request headers with data buffers.
-TEST_P(BidirectionalStreamQuicImplTest,
- SendvDataCoalesceDataBuffersAndHeaderFrame) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
-
- const char kBody1[] = "here are some data";
- const char kBody2[] = "data keep coming";
- std::vector<std::string> two_writes = {kBody1, kBody2};
- AddWrite(ConstructRequestHeadersAndMultipleDataFramesPacket(
- 1, !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length,
- two_writes));
- // Ack server's data packet.
- AddWrite(ConstructClientAckPacket(2, 3, 1));
- const char kBody3[] = "hello there";
- const char kBody4[] = "another piece of small data";
- const char kBody5[] = "really small";
- QuicStreamOffset data_offset = strlen(kBody1) + strlen(kBody2);
- AddWrite(ConstructClientMultipleDataFramesPacket(
- 3, !kIncludeVersion, kFin, data_offset, {kBody3, kBody4, kBody5}));
-
- Initialize();
-
- BidirectionalStreamRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.google.com/");
- request.end_stream_on_headers = false;
- request.priority = DEFAULT_PRIORITY;
-
- scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
- std::unique_ptr<TestDelegateBase> delegate(
- new TestDelegateBase(read_buffer.get(), kReadBufferSize));
- delegate->DoNotSendRequestHeadersAutomatically();
- delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
- ConfirmHandshake();
- delegate->WaitUntilNextCallback(); // OnStreamReady
-
- // Send a Data packet.
- scoped_refptr<StringIOBuffer> buf1(new StringIOBuffer(kBody1));
- scoped_refptr<StringIOBuffer> buf2(new StringIOBuffer(kBody2));
-
- std::vector<int> lengths = {buf1->size(), buf2->size()};
- delegate->SendvData({buf1, buf2}, lengths, !kFin);
- delegate->WaitUntilNextCallback(); // OnDataSent
-
- // Server acks the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Server sends the response headers.
- SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
- size_t spdy_response_headers_frame_length;
- QuicStreamOffset offset = 0;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, !kFin, std::move(response_headers),
- &spdy_response_headers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnHeadersReceived
- TestCompletionCallback cb;
- int rv = delegate->ReadData(cb.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
- const char kResponseBody[] = "Hello world!";
- // Server sends data.
- ProcessPacket(
- ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
-
- EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult());
-
- // Send a second Data packet.
- scoped_refptr<StringIOBuffer> buf3(new StringIOBuffer(kBody3));
- scoped_refptr<StringIOBuffer> buf4(new StringIOBuffer(kBody4));
- scoped_refptr<StringIOBuffer> buf5(new StringIOBuffer(kBody5));
-
- delegate->SendvData({buf3, buf4, buf5},
- {buf3->size(), buf4->size(), buf5->size()}, kFin);
- delegate->WaitUntilNextCallback(); // OnDataSent
-
- size_t spdy_trailers_frame_length;
- SpdyHeaderBlock trailers;
- trailers["foo"] = "bar";
- trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
- // Server sends trailers.
- ProcessPacket(ConstructResponseTrailersPacket(
- 4, kFin, trailers.Clone(), &spdy_trailers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnTrailersReceived
- trailers.erase(kFinalOffsetHeaderKey);
- EXPECT_EQ(trailers, delegate->trailers());
- EXPECT_EQ(OK, delegate->ReadData(cb.callback()));
-
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(2, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
- EXPECT_EQ(
- static_cast<int64_t>(spdy_request_headers_frame_length + strlen(kBody1) +
- strlen(kBody2) + strlen(kBody3) + strlen(kBody4) +
- strlen(kBody5)),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(
- static_cast<int64_t>(spdy_response_headers_frame_length +
- strlen(kResponseBody) + spdy_trailers_frame_length),
- delegate->GetTotalReceivedBytes());
-}
-
-TEST_P(BidirectionalStreamQuicImplTest, PostRequest) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructDataPacket(2, kIncludeVersion, kFin, 0, kUploadData,
- &client_maker_));
- AddWrite(ConstructClientAckPacket(3, 3, 1));
-
- Initialize();
-
- BidirectionalStreamRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.google.com/");
- request.end_stream_on_headers = false;
- request.priority = DEFAULT_PRIORITY;
-
- 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()->GetWeakPtr());
- ConfirmHandshake();
- delegate->WaitUntilNextCallback(); // OnStreamReady
-
- // Send a DATA frame.
- scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(kUploadData));
-
- delegate->SendData(buf, buf->size(), true);
- delegate->WaitUntilNextCallback(); // OnDataSent
-
- // Server acks the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Server sends the response headers.
- SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
- size_t spdy_response_headers_frame_length;
- QuicStreamOffset offset = 0;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, !kFin, std::move(response_headers),
- &spdy_response_headers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnHeadersReceived
- TestCompletionCallback cb;
- int rv = delegate->ReadData(cb.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
- const char kResponseBody[] = "Hello world!";
- // Server sends data.
- ProcessPacket(
- ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
-
- EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult());
-
- size_t spdy_trailers_frame_length;
- SpdyHeaderBlock trailers;
- trailers["foo"] = "bar";
- trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
- // Server sends trailers.
- ProcessPacket(ConstructResponseTrailersPacket(
- 4, kFin, trailers.Clone(), &spdy_trailers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnTrailersReceived
- trailers.erase(kFinalOffsetHeaderKey);
- EXPECT_EQ(trailers, delegate->trailers());
- EXPECT_EQ(OK, delegate->ReadData(cb.callback()));
-
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(1, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
- strlen(kUploadData)),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(
- static_cast<int64_t>(spdy_response_headers_frame_length +
- strlen(kResponseBody) + spdy_trailers_frame_length),
- delegate->GetTotalReceivedBytes());
-}
-
-TEST_P(BidirectionalStreamQuicImplTest, PutRequest) {
- SetRequest("PUT", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructDataPacket(2, kIncludeVersion, kFin, 0, kUploadData,
- &client_maker_));
- AddWrite(ConstructClientAckPacket(3, 3, 1));
-
- Initialize();
-
- BidirectionalStreamRequestInfo request;
- request.method = "PUT";
- request.url = GURL("http://www.google.com/");
- request.end_stream_on_headers = false;
- request.priority = DEFAULT_PRIORITY;
-
- 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()->GetWeakPtr());
- delegate->WaitUntilNextCallback(); // OnStreamReady
-
- // Send a DATA frame.
- scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(kUploadData));
-
- delegate->SendData(buf, buf->size(), true);
- delegate->WaitUntilNextCallback(); // OnDataSent
-
- // Server acks the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Server sends the response headers.
- SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
- size_t spdy_response_headers_frame_length;
- QuicStreamOffset offset = 0;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, !kFin, std::move(response_headers),
- &spdy_response_headers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnHeadersReceived
- TestCompletionCallback cb;
- int rv = delegate->ReadData(cb.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
- const char kResponseBody[] = "Hello world!";
- // Server sends data.
- ProcessPacket(
- ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
-
- EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult());
-
- size_t spdy_trailers_frame_length;
- SpdyHeaderBlock trailers;
- trailers["foo"] = "bar";
- trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
- // Server sends trailers.
- ProcessPacket(ConstructResponseTrailersPacket(
- 4, kFin, trailers.Clone(), &spdy_trailers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnTrailersReceived
- trailers.erase(kFinalOffsetHeaderKey);
- EXPECT_EQ(trailers, delegate->trailers());
- EXPECT_EQ(OK, delegate->ReadData(cb.callback()));
-
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(1, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
- strlen(kUploadData)),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(
- static_cast<int64_t>(spdy_response_headers_frame_length +
- strlen(kResponseBody) + spdy_trailers_frame_length),
- delegate->GetTotalReceivedBytes());
-}
-
-TEST_P(BidirectionalStreamQuicImplTest, InterleaveReadDataAndSendData) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructAckAndDataPacket(2, !kIncludeVersion, 2, 1, !kFin, 0,
- kUploadData, &client_maker_));
- AddWrite(ConstructAckAndDataPacket(3, !kIncludeVersion, 3, 3, kFin,
- strlen(kUploadData), kUploadData,
- &client_maker_));
- Initialize();
-
- BidirectionalStreamRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.google.com/");
- request.end_stream_on_headers = false;
- request.priority = DEFAULT_PRIORITY;
-
- 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()->GetWeakPtr());
- ConfirmHandshake();
- delegate->WaitUntilNextCallback(); // OnStreamReady
-
- // Server acks the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Server sends the response headers.
- SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
- size_t spdy_response_headers_frame_length;
- ProcessPacket(
- ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
- &spdy_response_headers_frame_length, 0));
-
- delegate->WaitUntilNextCallback(); // OnHeadersReceived
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
-
- // Client sends a data packet.
- scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(kUploadData));
-
- delegate->SendData(buf, buf->size(), false);
- delegate->WaitUntilNextCallback(); // OnDataSent
-
- TestCompletionCallback cb;
- int rv = delegate->ReadData(cb.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- const char kResponseBody[] = "Hello world!";
-
- // Server sends a data packet.
- ProcessPacket(ConstructAckAndDataPacket(3, !kIncludeVersion, 2, 1, !kFin, 0,
- kResponseBody, &server_maker_));
-
- EXPECT_EQ(static_cast<int64_t>(strlen(kResponseBody)), cb.WaitForResult());
- EXPECT_EQ(std::string(kResponseBody), delegate->data_received());
-
- // Client sends a data packet.
- delegate->SendData(buf, buf->size(), true);
- delegate->WaitUntilNextCallback(); // OnDataSent
-
- TestCompletionCallback cb2;
- rv = delegate->ReadData(cb2.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- ProcessPacket(ConstructAckAndDataPacket(4, !kIncludeVersion, 3, 1, kFin,
- strlen(kResponseBody), kResponseBody,
- &server_maker_));
-
- EXPECT_EQ(static_cast<int64_t>(strlen(kResponseBody)), cb2.WaitForResult());
-
- std::string expected_body(kResponseBody);
- expected_body.append(kResponseBody);
- EXPECT_EQ(expected_body, delegate->data_received());
-
- EXPECT_EQ(OK, delegate->ReadData(cb.callback()));
- EXPECT_EQ(2, delegate->on_data_read_count());
- EXPECT_EQ(2, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
- 2 * strlen(kUploadData)),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
- 2 * strlen(kResponseBody)),
- delegate->GetTotalReceivedBytes());
-}
-
-TEST_P(BidirectionalStreamQuicImplTest, ServerSendsRstAfterHeaders) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- Initialize();
-
- BidirectionalStreamRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.google.com/");
- request.end_stream_on_headers = true;
- request.priority = DEFAULT_PRIORITY;
-
- 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()->GetWeakPtr());
- delegate->WaitUntilNextCallback(); // OnStreamReady
- ConfirmHandshake();
-
- // Server sends a Rst.
- ProcessPacket(ConstructServerRstStreamPacket(1));
-
- delegate->WaitUntilNextCallback(); // OnFailed
- TestCompletionCallback cb;
- EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, delegate->ReadData(cb.callback()));
-
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, delegate->error());
- EXPECT_EQ(0, delegate->on_data_read_count());
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
-}
-
-TEST_P(BidirectionalStreamQuicImplTest, ServerSendsRstAfterReadData) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- // Why does QUIC ack Rst? Is this expected?
- AddWrite(ConstructClientAckPacket(2, 3, 1));
-
- Initialize();
-
- BidirectionalStreamRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.google.com/");
- request.end_stream_on_headers = true;
- request.priority = DEFAULT_PRIORITY;
-
- 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()->GetWeakPtr());
- delegate->WaitUntilNextCallback(); // OnStreamReady
- ConfirmHandshake();
-
- // Server acks the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Server sends the response headers.
- SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
-
- size_t spdy_response_headers_frame_length;
- QuicStreamOffset offset = 0;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, !kFin, std::move(response_headers),
- &spdy_response_headers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnHeadersReceived
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
-
- TestCompletionCallback cb;
- int rv = delegate->ReadData(cb.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- // Server sends a Rst.
- ProcessPacket(ConstructServerRstStreamPacket(3));
-
- delegate->WaitUntilNextCallback(); // OnFailed
-
- EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, delegate->ReadData(cb.callback()));
- EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, delegate->error());
- EXPECT_EQ(0, delegate->on_data_read_count());
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length),
- delegate->GetTotalReceivedBytes());
-}
-
-TEST_P(BidirectionalStreamQuicImplTest, CancelStreamAfterSendData) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructAckAndDataPacket(2, !kIncludeVersion, 2, 1, !kFin, 0,
- kUploadData, &client_maker_));
- AddWrite(ConstructRstStreamCancelledPacket(3, strlen(kUploadData),
- &client_maker_));
-
- Initialize();
-
- BidirectionalStreamRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.google.com/");
- request.end_stream_on_headers = false;
- request.priority = DEFAULT_PRIORITY;
-
- 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()->GetWeakPtr());
- ConfirmHandshake();
- delegate->WaitUntilNextCallback(); // OnStreamReady
-
- // Server acks the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Server sends the response headers.
- SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
- size_t spdy_response_headers_frame_length;
- ProcessPacket(
- ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
- &spdy_response_headers_frame_length, 0));
-
- delegate->WaitUntilNextCallback(); // OnHeadersReceived
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
-
- // Send a DATA frame.
- scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(kUploadData));
-
- delegate->SendData(buf, buf->size(), false);
- delegate->WaitUntilNextCallback(); // OnDataSent
-
- delegate->CancelStream();
- base::RunLoop().RunUntilIdle();
-
- // Try to send data after Cancel(), should not get called back.
- delegate->SendData(buf, buf->size(), false);
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(delegate->on_failed_called());
-
- EXPECT_EQ(0, delegate->on_data_read_count());
- EXPECT_EQ(1, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
- strlen(kUploadData)),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length),
- delegate->GetTotalReceivedBytes());
-}
-
-TEST_P(BidirectionalStreamQuicImplTest, SessionClosedBeforeReadData) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- Initialize();
-
- BidirectionalStreamRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.google.com/");
- request.end_stream_on_headers = false;
- request.priority = DEFAULT_PRIORITY;
-
- 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()->GetWeakPtr());
- ConfirmHandshake();
- delegate->WaitUntilNextCallback(); // OnStreamReady
-
- // Server acks the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Server sends the response headers.
- SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
-
- size_t spdy_response_headers_frame_length;
- QuicStreamOffset offset = 0;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, !kFin, std::move(response_headers),
- &spdy_response_headers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnHeadersReceived
- TestCompletionCallback cb;
- int rv = delegate->ReadData(cb.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- session()->connection()->CloseConnection(
- QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
- delegate->WaitUntilNextCallback(); // OnFailed
- EXPECT_TRUE(delegate->on_failed_called());
-
- // Try to send data after OnFailed(), should not get called back.
- scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(kUploadData));
- delegate->SendData(buf, buf->size(), false);
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(ERR_UNEXPECTED, delegate->ReadData(cb.callback()));
- EXPECT_EQ(ERR_UNEXPECTED, delegate->error());
- EXPECT_EQ(0, delegate->on_data_read_count());
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length),
- delegate->GetTotalReceivedBytes());
-}
-
-TEST_P(BidirectionalStreamQuicImplTest, CancelStreamAfterReadData) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructClientAckAndRstStreamPacket(2, 2, 1, 1));
-
- Initialize();
-
- BidirectionalStreamRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.google.com/");
- request.end_stream_on_headers = false;
- request.priority = DEFAULT_PRIORITY;
-
- 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()->GetWeakPtr());
- ConfirmHandshake();
- delegate->WaitUntilNextCallback(); // OnStreamReady
-
- // Server acks the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Server sends the response headers.
- SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
- size_t spdy_response_headers_frame_length;
- ProcessPacket(
- ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
- &spdy_response_headers_frame_length, 0));
-
- delegate->WaitUntilNextCallback(); // OnHeadersReceived
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
-
- // Cancel the stream after ReadData returns ERR_IO_PENDING.
- TestCompletionCallback cb;
- EXPECT_EQ(ERR_IO_PENDING, delegate->ReadData(cb.callback()));
- delegate->CancelStream();
-
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(0, delegate->on_data_read_count());
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length),
- delegate->GetTotalReceivedBytes());
-}
-
-TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnHeadersReceived) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructClientAckAndRstStreamPacket(2, 2, 1, 1));
-
- Initialize();
-
- BidirectionalStreamRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.google.com/");
- request.end_stream_on_headers = false;
- request.priority = DEFAULT_PRIORITY;
-
- scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
- std::unique_ptr<DeleteStreamDelegate> delegate(
- new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize,
- DeleteStreamDelegate::ON_HEADERS_RECEIVED));
- delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
- ConfirmHandshake();
- delegate->WaitUntilNextCallback(); // OnStreamReady
-
- // Server acks the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Server sends the response headers.
- SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
-
- size_t spdy_response_headers_frame_length;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, !kFin, std::move(response_headers),
- &spdy_response_headers_frame_length, nullptr));
-
- delegate->WaitUntilNextCallback(); // OnHeadersReceived
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
-
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(0, delegate->on_data_read_count());
- EXPECT_EQ(0, delegate->on_data_sent_count());
-}
-
-TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnDataRead) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructClientAckPacket(2, 3, 1));
- AddWrite(ConstructClientRstStreamPacket(3));
-
- Initialize();
-
- BidirectionalStreamRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.google.com/");
- request.end_stream_on_headers = false;
- request.priority = DEFAULT_PRIORITY;
-
- 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()->GetWeakPtr());
- ConfirmHandshake();
- delegate->WaitUntilNextCallback(); // OnStreamReady
-
- // Server acks the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Server sends the response headers.
- SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
-
- size_t spdy_response_headers_frame_length;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, !kFin, std::move(response_headers),
- &spdy_response_headers_frame_length, nullptr));
-
- delegate->WaitUntilNextCallback(); // OnHeadersReceived
-
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
-
- TestCompletionCallback cb;
- int rv = delegate->ReadData(cb.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- const char kResponseBody[] = "Hello world!";
- // Server sends data.
- ProcessPacket(
- ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
- EXPECT_EQ(static_cast<int64_t>(strlen(kResponseBody)), cb.WaitForResult());
-
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(0, delegate->on_data_sent_count());
-}
-
-TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnTrailersReceived) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructClientAckPacket(2, 3, 1)); // Ack the data packet
-
- Initialize();
-
- BidirectionalStreamRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.google.com/");
- request.end_stream_on_headers = true;
- request.priority = DEFAULT_PRIORITY;
-
- scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
- std::unique_ptr<DeleteStreamDelegate> delegate(
- new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize,
- DeleteStreamDelegate::ON_TRAILERS_RECEIVED));
- delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
- delegate->WaitUntilNextCallback(); // OnStreamReady
-
- // Server acks the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Server sends the response headers.
- SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
-
- QuicStreamOffset offset = 0;
- size_t spdy_response_headers_frame_length;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, !kFin, std::move(response_headers),
- &spdy_response_headers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnHeadersReceived
-
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
-
- TestCompletionCallback cb;
- int rv = delegate->ReadData(cb.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- const char kResponseBody[] = "Hello world!";
- // Server sends data.
- ProcessPacket(
- ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
-
- EXPECT_EQ(static_cast<int64_t>(strlen(kResponseBody)), cb.WaitForResult());
- EXPECT_EQ(std::string(kResponseBody), delegate->data_received());
-
- size_t spdy_trailers_frame_length;
- SpdyHeaderBlock trailers;
- trailers["foo"] = "bar";
- trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
- // Server sends trailers.
- ProcessPacket(ConstructResponseTrailersPacket(
- 4, kFin, trailers.Clone(), &spdy_trailers_frame_length, &offset));
-
- delegate->WaitUntilNextCallback(); // OnTrailersReceived
- trailers.erase(kFinalOffsetHeaderKey);
- EXPECT_EQ(trailers, delegate->trailers());
-
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(0, delegate->on_data_sent_count());
-}
-
-} // namespace test
-
-} // namespace net
diff --git a/chromium/net/quic/chromium/bidirectional_stream_quic_impl.cc b/chromium/net/quic/chromium/bidirectional_stream_quic_impl.cc
new file mode 100644
index 00000000000..e46675211b4
--- /dev/null
+++ b/chromium/net/quic/chromium/bidirectional_stream_quic_impl.cc
@@ -0,0 +1,359 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/chromium/bidirectional_stream_quic_impl.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/timer/timer.h"
+#include "net/http/bidirectional_stream_request_info.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/socket/next_proto.h"
+#include "net/spdy/spdy_header_block.h"
+#include "net/spdy/spdy_http_utils.h"
+
+namespace net {
+
+BidirectionalStreamQuicImpl::BidirectionalStreamQuicImpl(
+ const base::WeakPtr<QuicChromiumClientSession>& session)
+ : session_(session),
+ was_handshake_confirmed_(session->IsCryptoHandshakeConfirmed()),
+ stream_(nullptr),
+ request_info_(nullptr),
+ delegate_(nullptr),
+ response_status_(OK),
+ negotiated_protocol_(kProtoUnknown),
+ read_buffer_len_(0),
+ headers_bytes_received_(0),
+ headers_bytes_sent_(0),
+ closed_stream_received_bytes_(0),
+ closed_stream_sent_bytes_(0),
+ closed_is_first_stream_(false),
+ has_sent_headers_(false),
+ has_received_headers_(false),
+ send_request_headers_automatically_(true),
+ waiting_for_confirmation_(false),
+ weak_factory_(this) {
+ DCHECK(session_);
+ session_->AddObserver(this);
+}
+
+BidirectionalStreamQuicImpl::~BidirectionalStreamQuicImpl() {
+ if (stream_) {
+ delegate_ = nullptr;
+ stream_->Reset(QUIC_STREAM_CANCELLED);
+ }
+
+ if (session_)
+ session_->RemoveObserver(this);
+}
+
+void BidirectionalStreamQuicImpl::Start(
+ const BidirectionalStreamRequestInfo* request_info,
+ const NetLogWithSource& net_log,
+ bool send_request_headers_automatically,
+ BidirectionalStreamImpl::Delegate* delegate,
+ std::unique_ptr<base::Timer> /* timer */) {
+ DCHECK(!stream_);
+ CHECK(delegate);
+
+ send_request_headers_automatically_ = send_request_headers_automatically;
+ if (!session_) {
+ NotifyError(was_handshake_confirmed_ ? ERR_QUIC_PROTOCOL_ERROR
+ : ERR_QUIC_HANDSHAKE_FAILED);
+ return;
+ }
+
+ delegate_ = delegate;
+ request_info_ = request_info;
+
+ int rv = stream_request_.StartRequest(
+ session_, &stream_,
+ base::Bind(&BidirectionalStreamQuicImpl::OnStreamReady,
+ weak_factory_.GetWeakPtr()));
+ if (rv == OK) {
+ OnStreamReady(rv);
+ } else if (!was_handshake_confirmed_) {
+ NotifyError(ERR_QUIC_HANDSHAKE_FAILED);
+ }
+}
+
+void BidirectionalStreamQuicImpl::SendRequestHeaders() {
+ DCHECK(!has_sent_headers_);
+ if (!stream_) {
+ LOG(ERROR)
+ << "Trying to send request headers after stream has been destroyed.";
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
+ weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
+ return;
+ }
+
+ SpdyHeaderBlock headers;
+ HttpRequestInfo http_request_info;
+ http_request_info.url = request_info_->url;
+ http_request_info.method = request_info_->method;
+ http_request_info.extra_headers = request_info_->extra_headers;
+
+ CreateSpdyHeadersFromHttpRequest(
+ http_request_info, http_request_info.extra_headers, true, &headers);
+ size_t headers_bytes_sent = stream_->WriteHeaders(
+ std::move(headers), request_info_->end_stream_on_headers, nullptr);
+ headers_bytes_sent_ += headers_bytes_sent;
+ has_sent_headers_ = true;
+}
+
+int BidirectionalStreamQuicImpl::ReadData(IOBuffer* buffer, int buffer_len) {
+ DCHECK(buffer);
+ DCHECK(buffer_len);
+
+ if (!stream_) {
+ // If the stream is already closed, there is no body to read.
+ return response_status_;
+ }
+ int rv = stream_->Read(buffer, buffer_len);
+ if (rv != ERR_IO_PENDING) {
+ if (stream_->IsDoneReading()) {
+ // If the write side is closed, OnFinRead() will call
+ // BidirectionalStreamQuicImpl::OnClose().
+ stream_->OnFinRead();
+ }
+ return rv;
+ }
+ // Read will complete asynchronously and Delegate::OnReadCompleted will be
+ // called upon completion.
+ read_buffer_ = buffer;
+ read_buffer_len_ = buffer_len;
+ return ERR_IO_PENDING;
+}
+
+void BidirectionalStreamQuicImpl::SendData(const scoped_refptr<IOBuffer>& data,
+ int length,
+ bool end_stream) {
+ DCHECK(length > 0 || (length == 0 && end_stream));
+ if (!stream_) {
+ LOG(ERROR) << "Trying to send data after stream has been destroyed.";
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
+ weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
+ return;
+ }
+
+ std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler;
+ if (!has_sent_headers_) {
+ DCHECK(!send_request_headers_automatically_);
+ // Creates a bundler only if there are headers to be sent along with the
+ // single data buffer.
+ bundler.reset(new QuicConnection::ScopedPacketBundler(
+ session_->connection(), QuicConnection::SEND_ACK_IF_PENDING));
+ SendRequestHeaders();
+ }
+
+ base::StringPiece string_data(data->data(), length);
+ int rv = stream_->WriteStreamData(
+ string_data, end_stream,
+ base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
+ weak_factory_.GetWeakPtr()));
+ DCHECK(rv == OK || rv == ERR_IO_PENDING);
+ if (rv == OK) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
+ weak_factory_.GetWeakPtr(), OK));
+ }
+}
+
+void BidirectionalStreamQuicImpl::SendvData(
+ const std::vector<scoped_refptr<IOBuffer>>& buffers,
+ const std::vector<int>& lengths,
+ bool end_stream) {
+ DCHECK_EQ(buffers.size(), lengths.size());
+
+ if (!stream_) {
+ LOG(ERROR) << "Trying to send data after stream has been destroyed.";
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
+ weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
+ return;
+ }
+
+ QuicConnection::ScopedPacketBundler bundler(
+ session_->connection(), QuicConnection::SEND_ACK_IF_PENDING);
+ if (!has_sent_headers_) {
+ DCHECK(!send_request_headers_automatically_);
+ SendRequestHeaders();
+ }
+
+ int rv = stream_->WritevStreamData(
+ buffers, lengths, end_stream,
+ base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
+ weak_factory_.GetWeakPtr()));
+
+ DCHECK(rv == OK || rv == ERR_IO_PENDING);
+ if (rv == OK) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
+ weak_factory_.GetWeakPtr(), OK));
+ }
+}
+
+NextProto BidirectionalStreamQuicImpl::GetProtocol() const {
+ return negotiated_protocol_;
+}
+
+int64_t BidirectionalStreamQuicImpl::GetTotalReceivedBytes() const {
+ if (stream_)
+ return headers_bytes_received_ + stream_->stream_bytes_read();
+ return headers_bytes_received_ + closed_stream_received_bytes_;
+}
+
+int64_t BidirectionalStreamQuicImpl::GetTotalSentBytes() const {
+ if (stream_)
+ return headers_bytes_sent_ + stream_->stream_bytes_written();
+ return headers_bytes_sent_ + closed_stream_sent_bytes_;
+}
+
+bool BidirectionalStreamQuicImpl::GetLoadTimingInfo(
+ LoadTimingInfo* load_timing_info) const {
+ bool is_first_stream = closed_is_first_stream_;
+ if (stream_)
+ is_first_stream = stream_->IsFirstStream();
+ if (is_first_stream) {
+ load_timing_info->socket_reused = false;
+ load_timing_info->connect_timing = connect_timing_;
+ } else {
+ load_timing_info->socket_reused = true;
+ }
+ return true;
+}
+
+void BidirectionalStreamQuicImpl::OnHeadersAvailable(
+ const SpdyHeaderBlock& headers,
+ size_t frame_len) {
+ headers_bytes_received_ += frame_len;
+ negotiated_protocol_ = kProtoQUIC1SPDY3;
+ if (!has_received_headers_) {
+ has_received_headers_ = true;
+ connect_timing_ = session_->GetConnectTiming();
+ if (delegate_)
+ delegate_->OnHeadersReceived(headers);
+ } else {
+ if (delegate_)
+ delegate_->OnTrailersReceived(headers);
+ // |this| can be destroyed after this point.
+ }
+}
+
+void BidirectionalStreamQuicImpl::OnDataAvailable() {
+ // Return early if ReadData has not been called.
+ if (!read_buffer_)
+ return;
+
+ int rv = ReadData(read_buffer_.get(), read_buffer_len_);
+ if (rv == ERR_IO_PENDING) {
+ // Spurrious notification. Wait for the next one.
+ return;
+ }
+ read_buffer_ = nullptr;
+ read_buffer_len_ = 0;
+ if (delegate_)
+ delegate_->OnDataRead(rv);
+}
+
+void BidirectionalStreamQuicImpl::OnClose() {
+ DCHECK(stream_);
+
+ if (stream_->connection_error() == QUIC_NO_ERROR &&
+ stream_->stream_error() == QUIC_STREAM_NO_ERROR) {
+ ResetStream();
+ return;
+ }
+ NotifyError(was_handshake_confirmed_ ? ERR_QUIC_PROTOCOL_ERROR
+ : ERR_QUIC_HANDSHAKE_FAILED);
+}
+
+void BidirectionalStreamQuicImpl::OnError(int error) {
+ NotifyError(error);
+}
+
+bool BidirectionalStreamQuicImpl::HasSendHeadersComplete() {
+ return has_sent_headers_;
+}
+
+void BidirectionalStreamQuicImpl::OnCryptoHandshakeConfirmed() {
+ was_handshake_confirmed_ = true;
+ if (waiting_for_confirmation_)
+ NotifyStreamReady();
+}
+
+void BidirectionalStreamQuicImpl::OnSessionClosed(
+ int error,
+ bool /*port_migration_detected*/) {
+ DCHECK_NE(OK, error);
+ session_.reset();
+ NotifyError(error);
+}
+
+void BidirectionalStreamQuicImpl::OnStreamReady(int rv) {
+ DCHECK_NE(ERR_IO_PENDING, rv);
+ DCHECK(rv == OK || !stream_);
+ if (rv == OK) {
+ stream_->SetDelegate(this);
+ if (!was_handshake_confirmed_ && request_info_->method == "POST") {
+ waiting_for_confirmation_ = true;
+ return;
+ }
+ NotifyStreamReady();
+ } else {
+ NotifyError(rv);
+ }
+}
+
+void BidirectionalStreamQuicImpl::OnSendDataComplete(int rv) {
+ DCHECK(rv == OK || !stream_);
+ if (rv == OK) {
+ if (delegate_)
+ delegate_->OnDataSent();
+ } else {
+ NotifyError(rv);
+ }
+}
+
+void BidirectionalStreamQuicImpl::NotifyError(int error) {
+ DCHECK_NE(OK, error);
+ DCHECK_NE(ERR_IO_PENDING, error);
+
+ ResetStream();
+ if (delegate_) {
+ response_status_ = error;
+ BidirectionalStreamImpl::Delegate* delegate = delegate_;
+ delegate_ = nullptr;
+ // Cancel any pending callback.
+ weak_factory_.InvalidateWeakPtrs();
+ delegate->OnFailed(error);
+ // |this| might be destroyed at this point.
+ }
+}
+
+void BidirectionalStreamQuicImpl::NotifyStreamReady() {
+ if (send_request_headers_automatically_) {
+ SendRequestHeaders();
+ }
+ if (delegate_)
+ delegate_->OnStreamReady(has_sent_headers_);
+}
+
+void BidirectionalStreamQuicImpl::ResetStream() {
+ if (!stream_)
+ return;
+ closed_stream_received_bytes_ = stream_->stream_bytes_read();
+ closed_stream_sent_bytes_ = stream_->stream_bytes_written();
+ closed_is_first_stream_ = stream_->IsFirstStream();
+ stream_->SetDelegate(nullptr);
+ stream_ = nullptr;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/chromium/bidirectional_stream_quic_impl.h b/chromium/net/quic/chromium/bidirectional_stream_quic_impl.h
new file mode 100644
index 00000000000..1a15e98d661
--- /dev/null
+++ b/chromium/net/quic/chromium/bidirectional_stream_quic_impl.h
@@ -0,0 +1,142 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_BIDIRECTIONAL_STREAM_QUIC_IMPL_H_
+#define NET_QUIC_BIDIRECTIONAL_STREAM_QUIC_IMPL_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "net/base/load_timing_info.h"
+#include "net/base/net_export.h"
+#include "net/http/bidirectional_stream_impl.h"
+#include "net/quic/chromium/quic_chromium_client_session.h"
+#include "net/quic/chromium/quic_chromium_client_stream.h"
+#include "net/spdy/spdy_header_block.h"
+
+namespace base {
+class Timer;
+} // namespace base
+
+namespace net {
+
+struct BidirectionalStreamRequestInfo;
+class IOBuffer;
+
+class NET_EXPORT_PRIVATE BidirectionalStreamQuicImpl
+ : public BidirectionalStreamImpl,
+ public QuicChromiumClientStream::Delegate,
+ public QuicChromiumClientSession::Observer {
+ public:
+ explicit BidirectionalStreamQuicImpl(
+ const base::WeakPtr<QuicChromiumClientSession>& session);
+
+ ~BidirectionalStreamQuicImpl() override;
+
+ // BidirectionalStreamImpl implementation:
+ void Start(const BidirectionalStreamRequestInfo* request_info,
+ const NetLogWithSource& net_log,
+ bool send_request_headers_automatically,
+ BidirectionalStreamImpl::Delegate* delegate,
+ std::unique_ptr<base::Timer> timer) override;
+ void SendRequestHeaders() override;
+ int ReadData(IOBuffer* buffer, int buffer_len) override;
+ void SendData(const scoped_refptr<IOBuffer>& data,
+ int length,
+ bool end_stream) override;
+ void SendvData(const std::vector<scoped_refptr<IOBuffer>>& buffers,
+ const std::vector<int>& lengths,
+ bool end_stream) override;
+ NextProto GetProtocol() const override;
+ int64_t GetTotalReceivedBytes() const override;
+ int64_t GetTotalSentBytes() const override;
+ bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
+
+ private:
+ // QuicChromiumClientStream::Delegate implementation:
+ void OnHeadersAvailable(const SpdyHeaderBlock& headers,
+ size_t frame_len) override;
+ void OnDataAvailable() override;
+ void OnClose() override;
+ void OnError(int error) override;
+ bool HasSendHeadersComplete() override;
+
+ // QuicChromiumClientSession::Observer implementation:
+ void OnCryptoHandshakeConfirmed() override;
+ void OnSessionClosed(int error, bool port_migration_detected) override;
+
+ void OnStreamReady(int rv);
+ void OnSendDataComplete(int rv);
+ void OnReadDataComplete(int rv);
+
+ // Notifies the delegate of an error.
+ void NotifyError(int error);
+ // Notifies the delegate that the stream is ready.
+ void NotifyStreamReady();
+ // Resets the stream and ensures that |delegate_| won't be called back.
+ void ResetStream();
+
+ base::WeakPtr<QuicChromiumClientSession> session_;
+ bool was_handshake_confirmed_; // True if the crypto handshake succeeded.
+ QuicChromiumClientSession::StreamRequest stream_request_;
+ QuicChromiumClientStream* stream_; // Non-owning.
+
+ const BidirectionalStreamRequestInfo* request_info_;
+ BidirectionalStreamImpl::Delegate* delegate_;
+ // Saves the response status if the stream is explicitly closed via OnError
+ // or OnClose with an error. Once all buffered data has been returned, this
+ // will be used as the final response.
+ int response_status_;
+
+ // The protocol that is negotiated.
+ NextProto negotiated_protocol_;
+ // Connect timing information for this stream. Populated when headers are
+ // received.
+ LoadTimingInfo::ConnectTiming connect_timing_;
+
+ // User provided read buffer for ReadData() response.
+ scoped_refptr<IOBuffer> read_buffer_;
+ int read_buffer_len_;
+
+ // Number of bytes received by the headers stream on behalf of this stream.
+ int64_t headers_bytes_received_;
+ // Number of bytes sent by the headers stream on behalf of this stream.
+ int64_t headers_bytes_sent_;
+ // After |stream_| has been closed, this keeps track of the total number of
+ // bytes received over the network for |stream_| while it was open.
+ int64_t closed_stream_received_bytes_;
+ // After |stream_| has been closed, this keeps track of the total number of
+ // bytes sent over the network for |stream_| while it was open.
+ int64_t closed_stream_sent_bytes_;
+ // True if the stream is the first stream negotiated on the session. Set when
+ // the stream was closed. If |stream_| is failed to be created, this takes on
+ // the default value of false.
+ bool closed_is_first_stream_;
+ // Indicates whether initial headers have been sent.
+ bool has_sent_headers_;
+ // Indicates whether initial headers have been received.
+ bool has_received_headers_;
+
+ // Whether to automatically send request headers when stream is negotiated.
+ // If false, headers will not be sent until SendRequestHeaders() is called or
+ // until next SendData/SendvData, during which QUIC will try to combine header
+ // frame with data frame in the same packet if possible.
+ bool send_request_headers_automatically_;
+
+ // True of this stream is waiting for the QUIC handshake to be confirmed
+ // before sending headers.
+ bool waiting_for_confirmation_;
+
+ base::WeakPtrFactory<BidirectionalStreamQuicImpl> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BidirectionalStreamQuicImpl);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_BIDIRECTIONAL_STREAM_QUIC_IMPL_H_
diff --git a/chromium/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc b/chromium/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc
new file mode 100644
index 00000000000..2a6ee89ee78
--- /dev/null
+++ b/chromium/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc
@@ -0,0 +1,1779 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/chromium/bidirectional_stream_quic_impl.h"
+
+#include <utility>
+
+#include "base/callback_helpers.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "net/base/ip_address.h"
+#include "net/base/load_timing_info.h"
+#include "net/base/load_timing_info_test_util.h"
+#include "net/base/net_errors.h"
+#include "net/http/bidirectional_stream_request_info.h"
+#include "net/http/transport_security_state.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/test_net_log.h"
+#include "net/log/test_net_log_util.h"
+#include "net/quic/chromium/quic_chromium_alarm_factory.h"
+#include "net/quic/chromium/quic_chromium_connection_helper.h"
+#include "net/quic/chromium/quic_chromium_packet_reader.h"
+#include "net/quic/chromium/quic_chromium_packet_writer.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/crypto/quic_server_info.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_http_utils.h"
+#include "net/quic/core/spdy_utils.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
+#include "net/quic/test_tools/mock_random.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_test_packet_maker.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/test_task_runner.h"
+#include "net/socket/socket_test_util.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using net::test::IsError;
+using net::test::IsOk;
+
+namespace net {
+
+namespace test {
+
+namespace {
+
+const char kUploadData[] = "Really nifty data!";
+const char kDefaultServerHostName[] = "www.google.com";
+const uint16_t kDefaultServerPort = 80;
+// Size of the buffer to be allocated for each read.
+const size_t kReadBufferSize = 4096;
+
+class TestDelegateBase : public BidirectionalStreamImpl::Delegate {
+ public:
+ TestDelegateBase(IOBuffer* read_buf, int read_buf_len)
+ : TestDelegateBase(read_buf,
+ read_buf_len,
+ base::MakeUnique<base::Timer>(false, false)) {}
+
+ TestDelegateBase(IOBuffer* read_buf,
+ int read_buf_len,
+ std::unique_ptr<base::Timer> timer)
+ : read_buf_(read_buf),
+ read_buf_len_(read_buf_len),
+ timer_(std::move(timer)),
+ loop_(nullptr),
+ next_proto_(kProtoUnknown),
+ received_bytes_(0),
+ sent_bytes_(0),
+ has_load_timing_info_(false),
+ error_(OK),
+ on_data_read_count_(0),
+ on_data_sent_count_(0),
+ not_expect_callback_(false),
+ on_failed_called_(false),
+ send_request_headers_automatically_(true),
+ is_ready_(false),
+ trailers_expected_(false),
+ trailers_received_(false) {
+ loop_.reset(new base::RunLoop);
+ }
+
+ ~TestDelegateBase() override {}
+
+ void OnStreamReady(bool request_headers_sent) override {
+ CHECK(!is_ready_);
+ CHECK(!on_failed_called_);
+ EXPECT_EQ(send_request_headers_automatically_, request_headers_sent);
+ CHECK(!not_expect_callback_);
+ is_ready_ = true;
+ loop_->Quit();
+ }
+
+ void OnHeadersReceived(const SpdyHeaderBlock& response_headers) override {
+ CHECK(!on_failed_called_);
+ CHECK(!not_expect_callback_);
+
+ response_headers_ = response_headers.Clone();
+ loop_->Quit();
+ }
+
+ void OnDataRead(int bytes_read) override {
+ CHECK(!on_failed_called_);
+ CHECK(!not_expect_callback_);
+ CHECK(!callback_.is_null());
+
+ // If read EOF, make sure this callback is after trailers callback.
+ if (bytes_read == 0)
+ EXPECT_TRUE(!trailers_expected_ || trailers_received_);
+ ++on_data_read_count_;
+ CHECK_GE(bytes_read, OK);
+ data_received_.append(read_buf_->data(), bytes_read);
+ base::ResetAndReturn(&callback_).Run(bytes_read);
+ }
+
+ void OnDataSent() override {
+ CHECK(!on_failed_called_);
+ CHECK(!not_expect_callback_);
+
+ ++on_data_sent_count_;
+ loop_->Quit();
+ }
+
+ void OnTrailersReceived(const SpdyHeaderBlock& trailers) override {
+ CHECK(!on_failed_called_);
+ CHECK(!not_expect_callback_);
+
+ trailers_received_ = true;
+ trailers_ = trailers.Clone();
+ loop_->Quit();
+ }
+
+ void OnFailed(int error) override {
+ CHECK(!on_failed_called_);
+ CHECK(!not_expect_callback_);
+ CHECK_EQ(OK, error_);
+ CHECK_NE(OK, error);
+
+ on_failed_called_ = true;
+ error_ = error;
+ loop_->Quit();
+ }
+
+ void Start(const BidirectionalStreamRequestInfo* request_info,
+ const NetLogWithSource& net_log,
+ const base::WeakPtr<QuicChromiumClientSession> session) {
+ stream_.reset(new BidirectionalStreamQuicImpl(session));
+ stream_->Start(request_info, net_log, send_request_headers_automatically_,
+ this, nullptr);
+ }
+
+ void SendRequestHeaders() { stream_->SendRequestHeaders(); }
+
+ void SendData(const scoped_refptr<IOBuffer>& data,
+ int length,
+ bool end_of_stream) {
+ not_expect_callback_ = true;
+ stream_->SendData(data, length, end_of_stream);
+ not_expect_callback_ = false;
+ }
+
+ void SendvData(const std::vector<scoped_refptr<IOBuffer>>& data,
+ const std::vector<int>& lengths,
+ bool end_of_stream) {
+ not_expect_callback_ = true;
+ stream_->SendvData(data, lengths, end_of_stream);
+ not_expect_callback_ = false;
+ }
+
+ // Waits until next Delegate callback.
+ void WaitUntilNextCallback() {
+ loop_->Run();
+ loop_.reset(new base::RunLoop);
+ }
+
+ // Calls ReadData on the |stream_| and updates |data_received_|.
+ int ReadData(const CompletionCallback& callback) {
+ not_expect_callback_ = true;
+ int rv = stream_->ReadData(read_buf_.get(), read_buf_len_);
+ not_expect_callback_ = false;
+ if (rv > 0)
+ data_received_.append(read_buf_->data(), rv);
+ if (rv == ERR_IO_PENDING)
+ callback_ = callback;
+ return rv;
+ }
+
+ NextProto GetProtocol() const {
+ if (stream_)
+ return stream_->GetProtocol();
+ return next_proto_;
+ }
+
+ int64_t GetTotalReceivedBytes() const {
+ if (stream_)
+ return stream_->GetTotalReceivedBytes();
+ return received_bytes_;
+ }
+
+ int64_t GetTotalSentBytes() const {
+ if (stream_)
+ return stream_->GetTotalSentBytes();
+ return sent_bytes_;
+ }
+
+ bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) {
+ if (stream_)
+ return stream_->GetLoadTimingInfo(load_timing_info);
+ *load_timing_info = load_timing_info_;
+ return has_load_timing_info_;
+ }
+
+ void DoNotSendRequestHeadersAutomatically() {
+ send_request_headers_automatically_ = false;
+ }
+
+ // Deletes |stream_|.
+ void DeleteStream() {
+ next_proto_ = stream_->GetProtocol();
+ received_bytes_ = stream_->GetTotalReceivedBytes();
+ sent_bytes_ = stream_->GetTotalSentBytes();
+ has_load_timing_info_ = stream_->GetLoadTimingInfo(&load_timing_info_);
+ stream_.reset();
+ }
+
+ void set_trailers_expected(bool trailers_expected) {
+ trailers_expected_ = trailers_expected;
+ }
+ // Const getters for internal states.
+ const std::string& data_received() const { return data_received_; }
+ int error() const { return error_; }
+ const SpdyHeaderBlock& response_headers() const { return response_headers_; }
+ const SpdyHeaderBlock& trailers() const { return trailers_; }
+ int on_data_read_count() const { return on_data_read_count_; }
+ int on_data_sent_count() const { return on_data_sent_count_; }
+ bool on_failed_called() const { return on_failed_called_; }
+ bool is_ready() const { return is_ready_; }
+
+ protected:
+ // Quits |loop_|.
+ void QuitLoop() { loop_->Quit(); }
+
+ private:
+ std::unique_ptr<BidirectionalStreamQuicImpl> stream_;
+ scoped_refptr<IOBuffer> read_buf_;
+ int read_buf_len_;
+ std::unique_ptr<base::Timer> timer_;
+ std::string data_received_;
+ std::unique_ptr<base::RunLoop> loop_;
+ SpdyHeaderBlock response_headers_;
+ SpdyHeaderBlock trailers_;
+ NextProto next_proto_;
+ int64_t received_bytes_;
+ int64_t sent_bytes_;
+ bool has_load_timing_info_;
+ LoadTimingInfo load_timing_info_;
+ int error_;
+ int on_data_read_count_;
+ int on_data_sent_count_;
+ // This is to ensure that delegate callback is not invoked synchronously when
+ // calling into |stream_|.
+ bool not_expect_callback_;
+ bool on_failed_called_;
+ CompletionCallback callback_;
+ bool send_request_headers_automatically_;
+ bool is_ready_;
+ bool trailers_expected_;
+ bool trailers_received_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestDelegateBase);
+};
+
+// A delegate that deletes the stream in a particular callback.
+class DeleteStreamDelegate : public TestDelegateBase {
+ public:
+ // Specifies in which callback the stream can be deleted.
+ enum Phase {
+ ON_HEADERS_RECEIVED,
+ ON_DATA_READ,
+ ON_TRAILERS_RECEIVED,
+ ON_FAILED,
+ };
+
+ DeleteStreamDelegate(IOBuffer* buf, int buf_len, Phase phase)
+ : TestDelegateBase(buf, buf_len), phase_(phase) {}
+ ~DeleteStreamDelegate() override {}
+
+ void OnHeadersReceived(const SpdyHeaderBlock& response_headers) override {
+ if (phase_ == ON_HEADERS_RECEIVED) {
+ DeleteStream();
+ }
+ TestDelegateBase::OnHeadersReceived(response_headers);
+ }
+
+ void OnDataSent() override { NOTREACHED(); }
+
+ void OnDataRead(int bytes_read) override {
+ DCHECK_NE(ON_HEADERS_RECEIVED, phase_);
+ if (phase_ == ON_DATA_READ)
+ DeleteStream();
+ TestDelegateBase::OnDataRead(bytes_read);
+ }
+
+ void OnTrailersReceived(const SpdyHeaderBlock& trailers) override {
+ DCHECK_NE(ON_HEADERS_RECEIVED, phase_);
+ DCHECK_NE(ON_DATA_READ, phase_);
+ if (phase_ == ON_TRAILERS_RECEIVED)
+ DeleteStream();
+ TestDelegateBase::OnTrailersReceived(trailers);
+ }
+
+ void OnFailed(int error) override {
+ DCHECK_EQ(ON_FAILED, phase_);
+ DeleteStream();
+ TestDelegateBase::OnFailed(error);
+ }
+
+ private:
+ // Indicates in which callback the delegate should cancel or delete the
+ // stream.
+ Phase phase_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeleteStreamDelegate);
+};
+
+} // namespace
+
+class BidirectionalStreamQuicImplTest
+ : public ::testing::TestWithParam<QuicVersion> {
+ protected:
+ static const bool kFin = true;
+ static const bool kIncludeVersion = true;
+ static const bool kIncludeCongestionFeedback = true;
+
+ // Holds a packet to be written to the wire, and the IO mode that should
+ // be used by the mock socket when performing the write.
+ struct PacketToWrite {
+ PacketToWrite(IoMode mode, QuicReceivedPacket* packet)
+ : mode(mode), packet(packet) {}
+ PacketToWrite(IoMode mode, int rv) : mode(mode), packet(nullptr), rv(rv) {}
+ IoMode mode;
+ QuicReceivedPacket* packet;
+ int rv;
+ };
+
+ BidirectionalStreamQuicImplTest()
+ : crypto_config_(CryptoTestUtils::ProofVerifierForTesting()),
+ read_buffer_(new IOBufferWithSize(4096)),
+ connection_id_(2),
+ stream_id_(kClientDataStreamId1),
+ client_maker_(GetParam(),
+ connection_id_,
+ &clock_,
+ kDefaultServerHostName,
+ Perspective::IS_CLIENT),
+ server_maker_(GetParam(),
+ connection_id_,
+ &clock_,
+ kDefaultServerHostName,
+ Perspective::IS_SERVER),
+ random_generator_(0) {
+ IPAddress ip(192, 0, 2, 33);
+ peer_addr_ = IPEndPoint(ip, 443);
+ self_addr_ = IPEndPoint(ip, 8435);
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
+ }
+
+ ~BidirectionalStreamQuicImplTest() {
+ session_->CloseSessionOnError(ERR_ABORTED, QUIC_INTERNAL_ERROR);
+ for (size_t i = 0; i < writes_.size(); i++) {
+ delete writes_[i].packet;
+ }
+ }
+
+ void TearDown() override {
+ EXPECT_TRUE(socket_data_->AllReadDataConsumed());
+ EXPECT_TRUE(socket_data_->AllWriteDataConsumed());
+ }
+
+ // Adds a packet to the list of expected writes.
+ void AddWrite(std::unique_ptr<QuicReceivedPacket> packet) {
+ writes_.push_back(PacketToWrite(SYNCHRONOUS, packet.release()));
+ }
+
+ void ProcessPacket(std::unique_ptr<QuicReceivedPacket> packet) {
+ connection_->ProcessUdpPacket(self_addr_, peer_addr_, *packet);
+ }
+
+ // Configures the test fixture to use the list of expected writes.
+ void Initialize() {
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::ZERO_RTT);
+ mock_writes_.reset(new MockWrite[writes_.size()]);
+ for (size_t i = 0; i < writes_.size(); i++) {
+ if (writes_[i].packet == nullptr) {
+ mock_writes_[i] = MockWrite(writes_[i].mode, writes_[i].rv, i);
+ } else {
+ mock_writes_[i] = MockWrite(writes_[i].mode, writes_[i].packet->data(),
+ writes_[i].packet->length());
+ }
+ }
+
+ socket_data_.reset(new StaticSocketDataProvider(
+ nullptr, 0, mock_writes_.get(), writes_.size()));
+
+ std::unique_ptr<MockUDPClientSocket> socket(new MockUDPClientSocket(
+ socket_data_.get(), net_log().bound().net_log()));
+ socket->Connect(peer_addr_);
+ runner_ = new TestTaskRunner(&clock_);
+ helper_.reset(
+ new QuicChromiumConnectionHelper(&clock_, &random_generator_));
+ alarm_factory_.reset(new QuicChromiumAlarmFactory(runner_.get(), &clock_));
+ connection_ = new QuicConnection(
+ connection_id_, peer_addr_, helper_.get(), alarm_factory_.get(),
+ new QuicChromiumPacketWriter(socket.get()), true /* owns_writer */,
+ Perspective::IS_CLIENT, SupportedVersions(GetParam()));
+ base::TimeTicks dns_end = base::TimeTicks::Now();
+ base::TimeTicks dns_start = dns_end - base::TimeDelta::FromMilliseconds(1);
+
+ session_.reset(new QuicChromiumClientSession(
+ connection_, std::move(socket),
+ /*stream_factory=*/nullptr, &crypto_client_stream_factory_, &clock_,
+ &transport_security_state_,
+ base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)),
+ QuicServerId(kDefaultServerHostName, kDefaultServerPort,
+ PRIVACY_MODE_DISABLED),
+ kQuicYieldAfterPacketsRead,
+ QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds),
+ /*cert_verify_flags=*/0, DefaultQuicConfig(), &crypto_config_,
+ "CONNECTION_UNKNOWN", dns_start, dns_end, &push_promise_index_,
+ base::ThreadTaskRunnerHandle::Get().get(),
+ /*socket_performance_watcher=*/nullptr, net_log().bound().net_log()));
+ session_->Initialize();
+ TestCompletionCallback callback;
+ session_->CryptoConnect(/*require_confirmation=*/false,
+ callback.callback());
+ EXPECT_TRUE(session_->IsEncryptionEstablished());
+ }
+
+ void ConfirmHandshake() {
+ crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
+ QuicSession::HANDSHAKE_CONFIRMED);
+ }
+
+ void SetRequest(const std::string& method,
+ const std::string& path,
+ RequestPriority priority) {
+ request_headers_ = client_maker_.GetRequestHeaders(method, "http", path);
+ }
+
+ SpdyHeaderBlock ConstructResponseHeaders(const std::string& response_code) {
+ return server_maker_.GetResponseHeaders(response_code);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructDataPacket(
+ QuicPacketNumber packet_number,
+ bool should_include_version,
+ bool fin,
+ QuicStreamOffset offset,
+ base::StringPiece data,
+ QuicTestPacketMaker* maker) {
+ std::unique_ptr<QuicReceivedPacket> packet(maker->MakeDataPacket(
+ packet_number, stream_id_, should_include_version, fin, offset, data));
+ DVLOG(2) << "packet(" << packet_number << "): " << std::endl
+ << QuicUtils::HexDump(packet->AsStringPiece());
+ return packet;
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructServerDataPacket(
+ QuicPacketNumber packet_number,
+ bool should_include_version,
+ bool fin,
+ QuicStreamOffset offset,
+ base::StringPiece data) {
+ return ConstructDataPacket(packet_number, should_include_version, fin,
+ offset, data, &server_maker_);
+ }
+
+ // Construct a data packet with multiple data frames
+ std::unique_ptr<QuicReceivedPacket> ConstructClientMultipleDataFramesPacket(
+ QuicPacketNumber packet_number,
+ bool should_include_version,
+ bool fin,
+ QuicStreamOffset offset,
+ const std::vector<std::string>& data_writes) {
+ std::unique_ptr<QuicReceivedPacket> packet(
+ client_maker_.MakeMultipleDataFramesPacket(packet_number, stream_id_,
+ should_include_version, fin,
+ offset, data_writes));
+ DVLOG(2) << "packet(" << packet_number << "): " << std::endl
+ << QuicUtils::HexDump(packet->AsStringPiece());
+ return packet;
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructRequestHeadersPacket(
+ QuicPacketNumber packet_number,
+ bool fin,
+ RequestPriority request_priority,
+ size_t* spdy_headers_frame_length) {
+ return ConstructRequestHeadersPacketInner(
+ packet_number, stream_id_, fin, request_priority,
+ spdy_headers_frame_length, /*offset=*/nullptr);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructRequestHeadersPacketInner(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool fin,
+ RequestPriority request_priority,
+ 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));
+ DVLOG(2) << "packet(" << packet_number << "): " << std::endl
+ << QuicUtils::HexDump(packet->AsStringPiece());
+ return packet;
+ }
+
+ std::unique_ptr<QuicReceivedPacket>
+ ConstructRequestHeadersAndMultipleDataFramesPacket(
+ QuicPacketNumber packet_number,
+ bool fin,
+ RequestPriority request_priority,
+ size_t* spdy_headers_frame_length,
+ const std::vector<std::string>& data) {
+ SpdyPriority priority =
+ ConvertRequestPriorityToQuicPriority(request_priority);
+ std::unique_ptr<QuicReceivedPacket> packet(
+ client_maker_.MakeRequestHeadersAndMultipleDataFramesPacket(
+ packet_number, stream_id_, kIncludeVersion, fin, priority,
+ std::move(request_headers_), spdy_headers_frame_length, data));
+ DVLOG(2) << "packet(" << packet_number << "): " << std::endl
+ << QuicUtils::HexDump(packet->AsStringPiece());
+ return packet;
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructResponseHeadersPacket(
+ QuicPacketNumber packet_number,
+ bool fin,
+ SpdyHeaderBlock response_headers,
+ size_t* spdy_headers_frame_length,
+ QuicStreamOffset* offset) {
+ return ConstructResponseHeadersPacketInner(
+ packet_number, stream_id_, fin, std::move(response_headers),
+ spdy_headers_frame_length, offset);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructResponseHeadersPacketInner(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool fin,
+ SpdyHeaderBlock response_headers,
+ size_t* spdy_headers_frame_length,
+ QuicStreamOffset* offset) {
+ return server_maker_.MakeResponseHeadersPacket(
+ packet_number, stream_id, !kIncludeVersion, fin,
+ std::move(response_headers), spdy_headers_frame_length, offset);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructResponseTrailersPacket(
+ QuicPacketNumber packet_number,
+ bool fin,
+ SpdyHeaderBlock trailers,
+ size_t* spdy_headers_frame_length,
+ QuicStreamOffset* offset) {
+ return server_maker_.MakeResponseHeadersPacket(
+ packet_number, stream_id_, !kIncludeVersion, fin, std::move(trailers),
+ spdy_headers_frame_length, offset);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructClientRstStreamPacket(
+ QuicPacketNumber packet_number) {
+ return ConstructRstStreamCancelledPacket(packet_number, 0, &client_maker_);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructServerRstStreamPacket(
+ QuicPacketNumber packet_number) {
+ return ConstructRstStreamCancelledPacket(packet_number, 0, &server_maker_);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructRstStreamCancelledPacket(
+ QuicPacketNumber packet_number,
+ size_t bytes_written,
+ QuicTestPacketMaker* maker) {
+ std::unique_ptr<QuicReceivedPacket> packet(
+ maker->MakeRstPacket(packet_number, !kIncludeVersion, stream_id_,
+ QUIC_STREAM_CANCELLED, bytes_written));
+ DVLOG(2) << "packet(" << packet_number << "): " << std::endl
+ << QuicUtils::HexDump(packet->AsStringPiece());
+ return packet;
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructClientAckAndRstStreamPacket(
+ QuicPacketNumber packet_number,
+ QuicPacketNumber largest_received,
+ QuicPacketNumber ack_least_unacked,
+ QuicPacketNumber stop_least_unacked) {
+ return client_maker_.MakeAckAndRstPacket(
+ packet_number, !kIncludeVersion, stream_id_, QUIC_STREAM_CANCELLED,
+ largest_received, ack_least_unacked, stop_least_unacked,
+ !kIncludeCongestionFeedback);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructAckAndDataPacket(
+ QuicPacketNumber packet_number,
+ bool should_include_version,
+ QuicPacketNumber largest_received,
+ QuicPacketNumber least_unacked,
+ bool fin,
+ QuicStreamOffset offset,
+ base::StringPiece data,
+ QuicTestPacketMaker* maker) {
+ std::unique_ptr<QuicReceivedPacket> packet(maker->MakeAckAndDataPacket(
+ packet_number, should_include_version, stream_id_, largest_received,
+ least_unacked, fin, offset, data));
+ DVLOG(2) << "packet(" << packet_number << "): " << std::endl
+ << QuicUtils::HexDump(packet->AsStringPiece());
+ return packet;
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructClientAckPacket(
+ QuicPacketNumber packet_number,
+ QuicPacketNumber largest_received,
+ QuicPacketNumber least_unacked) {
+ return client_maker_.MakeAckPacket(packet_number, largest_received,
+ least_unacked,
+ !kIncludeCongestionFeedback);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructServerAckPacket(
+ QuicPacketNumber packet_number,
+ QuicPacketNumber largest_received,
+ QuicPacketNumber least_unacked) {
+ return server_maker_.MakeAckPacket(packet_number, largest_received,
+ least_unacked,
+ !kIncludeCongestionFeedback);
+ }
+
+ void ExpectLoadTimingValid(const LoadTimingInfo& load_timing_info,
+ bool session_reused) {
+ EXPECT_EQ(session_reused, load_timing_info.socket_reused);
+
+ if (session_reused) {
+ ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
+ } else {
+ ExpectConnectTimingHasTimes(
+ load_timing_info.connect_timing,
+ CONNECT_TIMING_HAS_SSL_TIMES | CONNECT_TIMING_HAS_DNS_TIMES);
+ }
+ ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
+ }
+
+ const BoundTestNetLog& net_log() const { return net_log_; }
+
+ QuicChromiumClientSession* session() const { return session_.get(); }
+
+ protected:
+ BoundTestNetLog net_log_;
+ scoped_refptr<TestTaskRunner> runner_;
+ std::unique_ptr<MockWrite[]> mock_writes_;
+ MockClock clock_;
+ QuicConnection* connection_;
+ std::unique_ptr<QuicChromiumConnectionHelper> helper_;
+ std::unique_ptr<QuicChromiumAlarmFactory> alarm_factory_;
+ TransportSecurityState transport_security_state_;
+ std::unique_ptr<QuicChromiumClientSession> session_;
+ QuicCryptoClientConfig crypto_config_;
+ HttpRequestHeaders headers_;
+ HttpResponseInfo response_;
+ scoped_refptr<IOBufferWithSize> read_buffer_;
+ SpdyHeaderBlock request_headers_;
+ const QuicConnectionId connection_id_;
+ const QuicStreamId stream_id_;
+ QuicTestPacketMaker client_maker_;
+ QuicTestPacketMaker server_maker_;
+ IPEndPoint self_addr_;
+ IPEndPoint peer_addr_;
+ MockRandom random_generator_;
+ MockCryptoClientStreamFactory crypto_client_stream_factory_;
+ std::unique_ptr<StaticSocketDataProvider> socket_data_;
+ std::vector<PacketToWrite> writes_;
+ QuicClientPushPromiseIndex push_promise_index_;
+};
+
+INSTANTIATE_TEST_CASE_P(Version,
+ BidirectionalStreamQuicImplTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
+
+TEST_P(BidirectionalStreamQuicImplTest, GetRequest) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+
+ AddWrite(ConstructClientAckPacket(2, 3, 1));
+ Initialize();
+
+ BidirectionalStreamRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+ request.end_stream_on_headers = true;
+ request.priority = DEFAULT_PRIORITY;
+
+ scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
+ std::unique_ptr<TestDelegateBase> delegate(
+ new TestDelegateBase(read_buffer.get(), kReadBufferSize));
+ delegate->set_trailers_expected(true);
+ delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+ delegate->WaitUntilNextCallback(); // OnStreamReady
+ ConfirmHandshake();
+
+ // Server acks the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Server sends the response headers.
+ SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
+
+ size_t spdy_response_headers_frame_length;
+ QuicStreamOffset offset = 0;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, !kFin, std::move(response_headers),
+ &spdy_response_headers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnHeadersReceived
+ LoadTimingInfo load_timing_info;
+ EXPECT_TRUE(delegate->GetLoadTimingInfo(&load_timing_info));
+ ExpectLoadTimingValid(load_timing_info, /*session_reused=*/false);
+ TestCompletionCallback cb;
+ int rv = delegate->ReadData(cb.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
+ const char kResponseBody[] = "Hello world!";
+ // Server sends data.
+ ProcessPacket(
+ ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
+ EXPECT_EQ(12, cb.WaitForResult());
+
+ EXPECT_EQ(std::string(kResponseBody), delegate->data_received());
+ TestCompletionCallback cb2;
+ EXPECT_THAT(delegate->ReadData(cb2.callback()), IsError(ERR_IO_PENDING));
+
+ SpdyHeaderBlock trailers;
+ size_t spdy_trailers_frame_length;
+ trailers["foo"] = "bar";
+ trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
+ // Server sends trailers.
+ ProcessPacket(ConstructResponseTrailersPacket(
+ 4, kFin, trailers.Clone(), &spdy_trailers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnTrailersReceived
+ EXPECT_THAT(cb2.WaitForResult(), IsOk());
+ trailers.erase(kFinalOffsetHeaderKey);
+ EXPECT_EQ(trailers, delegate->trailers());
+
+ EXPECT_THAT(delegate->ReadData(cb2.callback()), IsOk());
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(2, delegate->on_data_read_count());
+ EXPECT_EQ(0, delegate->on_data_sent_count());
+ EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(
+ static_cast<int64_t>(spdy_response_headers_frame_length +
+ strlen(kResponseBody) + spdy_trailers_frame_length),
+ delegate->GetTotalReceivedBytes());
+ // Check that NetLog was filled as expected.
+ TestNetLogEntry::List entries;
+ net_log().GetEntries(&entries);
+ size_t pos = ExpectLogContainsSomewhere(
+ entries, /*min_offset=*/0,
+ NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
+ NetLogEventPhase::NONE);
+ pos = ExpectLogContainsSomewhere(
+ entries, /*min_offset=*/pos,
+ NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
+ NetLogEventPhase::NONE);
+ ExpectLogContainsSomewhere(
+ entries, /*min_offset=*/pos,
+ NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
+ NetLogEventPhase::NONE);
+}
+
+TEST_P(BidirectionalStreamQuicImplTest, LoadTimingTwoRequests) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ QuicStreamOffset offset = 0;
+ AddWrite(ConstructRequestHeadersPacketInner(
+ 1, kClientDataStreamId1, kFin, DEFAULT_PRIORITY, nullptr, &offset));
+ // SetRequest() again for second request as |request_headers_| was moved.
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ AddWrite(ConstructRequestHeadersPacketInner(
+ 2, kClientDataStreamId2, kFin, DEFAULT_PRIORITY, nullptr, &offset));
+ AddWrite(ConstructClientAckPacket(3, 3, 1));
+ Initialize();
+
+ BidirectionalStreamRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+ request.end_stream_on_headers = true;
+ request.priority = DEFAULT_PRIORITY;
+
+ // Start first request.
+ 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()->GetWeakPtr());
+
+ // 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()->GetWeakPtr());
+
+ delegate->WaitUntilNextCallback(); // OnStreamReady
+ delegate2->WaitUntilNextCallback(); // OnStreamReady
+
+ ConfirmHandshake();
+ // Server acks the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Server sends the response headers.
+ offset = 0;
+ ProcessPacket(ConstructResponseHeadersPacketInner(
+ 2, kClientDataStreamId1, kFin, ConstructResponseHeaders("200"), nullptr,
+ &offset));
+
+ ProcessPacket(ConstructResponseHeadersPacketInner(
+ 3, kClientDataStreamId2, kFin, ConstructResponseHeaders("200"), nullptr,
+ &offset));
+
+ delegate->WaitUntilNextCallback(); // OnHeadersReceived
+ delegate2->WaitUntilNextCallback(); // OnHeadersReceived
+
+ LoadTimingInfo load_timing_info;
+ EXPECT_TRUE(delegate->GetLoadTimingInfo(&load_timing_info));
+ LoadTimingInfo load_timing_info2;
+ EXPECT_TRUE(delegate2->GetLoadTimingInfo(&load_timing_info2));
+ ExpectLoadTimingValid(load_timing_info, /*session_reused=*/false);
+ ExpectLoadTimingValid(load_timing_info2, /*session_reused=*/true);
+ EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
+ EXPECT_EQ("200", delegate2->response_headers().find(":status")->second);
+ // No response body. ReadData() should return OK synchronously.
+ TestCompletionCallback dummy_callback;
+ EXPECT_EQ(OK, delegate->ReadData(dummy_callback.callback()));
+ EXPECT_EQ(OK, delegate2->ReadData(dummy_callback.callback()));
+}
+
+// Tests that when request headers are not delayed, only data buffers are
+// coalesced.
+TEST_P(BidirectionalStreamQuicImplTest, CoalesceDataBuffersNotHeadersFrame) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+
+ const char kBody1[] = "here are some data";
+ const char kBody2[] = "data keep coming";
+ std::vector<std::string> two_writes = {kBody1, kBody2};
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructClientMultipleDataFramesPacket(2, kIncludeVersion, !kFin, 0,
+ {kBody1, kBody2}));
+ // Ack server's data packet.
+ AddWrite(ConstructClientAckPacket(3, 3, 1));
+ const char kBody3[] = "hello there";
+ const char kBody4[] = "another piece of small data";
+ const char kBody5[] = "really small";
+ QuicStreamOffset data_offset = strlen(kBody1) + strlen(kBody2);
+ AddWrite(ConstructClientMultipleDataFramesPacket(
+ 4, !kIncludeVersion, kFin, data_offset, {kBody3, kBody4, kBody5}));
+
+ Initialize();
+
+ BidirectionalStreamRequestInfo request;
+ request.method = "POST";
+ request.url = GURL("http://www.google.com/");
+ request.end_stream_on_headers = false;
+ request.priority = DEFAULT_PRIORITY;
+
+ scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
+ std::unique_ptr<TestDelegateBase> delegate(
+ new TestDelegateBase(read_buffer.get(), kReadBufferSize));
+ delegate->DoNotSendRequestHeadersAutomatically();
+ delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+ EXPECT_FALSE(delegate->is_ready());
+ ConfirmHandshake();
+ delegate->WaitUntilNextCallback(); // OnStreamReady
+
+ // Sends request headers separately, which causes them to be sent in a
+ // separate packet.
+ delegate->SendRequestHeaders();
+ // Send a Data packet.
+ scoped_refptr<StringIOBuffer> buf1(new StringIOBuffer(kBody1));
+ scoped_refptr<StringIOBuffer> buf2(new StringIOBuffer(kBody2));
+
+ std::vector<int> lengths = {buf1->size(), buf2->size()};
+ delegate->SendvData({buf1, buf2}, lengths, !kFin);
+ delegate->WaitUntilNextCallback(); // OnDataSent
+
+ // Server acks the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Server sends the response headers.
+ SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
+ size_t spdy_response_headers_frame_length;
+ QuicStreamOffset offset = 0;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, !kFin, std::move(response_headers),
+ &spdy_response_headers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnHeadersReceived
+ TestCompletionCallback cb;
+ int rv = delegate->ReadData(cb.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
+ const char kResponseBody[] = "Hello world!";
+ // Server sends data.
+ ProcessPacket(
+ ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
+
+ EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult());
+
+ // Send a second Data packet.
+ scoped_refptr<StringIOBuffer> buf3(new StringIOBuffer(kBody3));
+ scoped_refptr<StringIOBuffer> buf4(new StringIOBuffer(kBody4));
+ scoped_refptr<StringIOBuffer> buf5(new StringIOBuffer(kBody5));
+
+ delegate->SendvData({buf3, buf4, buf5},
+ {buf3->size(), buf4->size(), buf5->size()}, kFin);
+ delegate->WaitUntilNextCallback(); // OnDataSent
+
+ size_t spdy_trailers_frame_length;
+ SpdyHeaderBlock trailers;
+ trailers["foo"] = "bar";
+ trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
+ // Server sends trailers.
+ ProcessPacket(ConstructResponseTrailersPacket(
+ 4, kFin, trailers.Clone(), &spdy_trailers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnTrailersReceived
+ trailers.erase(kFinalOffsetHeaderKey);
+ EXPECT_EQ(trailers, delegate->trailers());
+ EXPECT_THAT(delegate->ReadData(cb.callback()), IsOk());
+
+ EXPECT_EQ(1, delegate->on_data_read_count());
+ EXPECT_EQ(2, delegate->on_data_sent_count());
+ EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
+ EXPECT_EQ(
+ static_cast<int64_t>(spdy_request_headers_frame_length + strlen(kBody1) +
+ strlen(kBody2) + strlen(kBody3) + strlen(kBody4) +
+ strlen(kBody5)),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(
+ static_cast<int64_t>(spdy_response_headers_frame_length +
+ strlen(kResponseBody) + spdy_trailers_frame_length),
+ delegate->GetTotalReceivedBytes());
+}
+
+// Tests that when request headers are delayed, SendData triggers coalescing of
+// request headers with data buffers.
+TEST_P(BidirectionalStreamQuicImplTest,
+ SendDataCoalesceDataBufferAndHeaderFrame) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+
+ const char kBody1[] = "here are some data";
+ AddWrite(ConstructRequestHeadersAndMultipleDataFramesPacket(
+ 1, !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length,
+ {kBody1}));
+ // Ack server's data packet.
+ AddWrite(ConstructClientAckPacket(2, 3, 1));
+ const char kBody2[] = "really small";
+ QuicStreamOffset data_offset = strlen(kBody1);
+ AddWrite(ConstructClientMultipleDataFramesPacket(3, !kIncludeVersion, kFin,
+ data_offset, {kBody2}));
+
+ Initialize();
+
+ BidirectionalStreamRequestInfo request;
+ request.method = "POST";
+ request.url = GURL("http://www.google.com/");
+ request.end_stream_on_headers = false;
+ request.priority = DEFAULT_PRIORITY;
+
+ scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
+ std::unique_ptr<TestDelegateBase> delegate(
+ new TestDelegateBase(read_buffer.get(), kReadBufferSize));
+ delegate->DoNotSendRequestHeadersAutomatically();
+ delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+ ConfirmHandshake();
+ delegate->WaitUntilNextCallback(); // OnStreamReady
+
+ // Send a Data packet.
+ scoped_refptr<StringIOBuffer> buf1(new StringIOBuffer(kBody1));
+
+ delegate->SendData(buf1, buf1->size(), false);
+ delegate->WaitUntilNextCallback(); // OnDataSent
+
+ // Server acks the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Server sends the response headers.
+ SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
+ size_t spdy_response_headers_frame_length;
+ QuicStreamOffset offset = 0;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, !kFin, std::move(response_headers),
+ &spdy_response_headers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnHeadersReceived
+ TestCompletionCallback cb;
+ int rv = delegate->ReadData(cb.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
+ const char kResponseBody[] = "Hello world!";
+ // Server sends data.
+ ProcessPacket(
+ ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
+
+ EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult());
+
+ // Send a second Data packet.
+ scoped_refptr<StringIOBuffer> buf2(new StringIOBuffer(kBody2));
+
+ delegate->SendData(buf2, buf2->size(), true);
+ delegate->WaitUntilNextCallback(); // OnDataSent
+
+ size_t spdy_trailers_frame_length;
+ SpdyHeaderBlock trailers;
+ trailers["foo"] = "bar";
+ trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
+ // Server sends trailers.
+ ProcessPacket(ConstructResponseTrailersPacket(
+ 4, kFin, trailers.Clone(), &spdy_trailers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnTrailersReceived
+ trailers.erase(kFinalOffsetHeaderKey);
+ EXPECT_EQ(trailers, delegate->trailers());
+ EXPECT_THAT(delegate->ReadData(cb.callback()), IsOk());
+
+ EXPECT_EQ(1, delegate->on_data_read_count());
+ EXPECT_EQ(2, delegate->on_data_sent_count());
+ EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
+ strlen(kBody1) + strlen(kBody2)),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(
+ static_cast<int64_t>(spdy_response_headers_frame_length +
+ strlen(kResponseBody) + spdy_trailers_frame_length),
+ delegate->GetTotalReceivedBytes());
+}
+
+// Tests that when request headers are delayed, SendvData triggers coalescing of
+// request headers with data buffers.
+TEST_P(BidirectionalStreamQuicImplTest,
+ SendvDataCoalesceDataBuffersAndHeaderFrame) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+
+ const char kBody1[] = "here are some data";
+ const char kBody2[] = "data keep coming";
+ std::vector<std::string> two_writes = {kBody1, kBody2};
+ AddWrite(ConstructRequestHeadersAndMultipleDataFramesPacket(
+ 1, !kFin, DEFAULT_PRIORITY, &spdy_request_headers_frame_length,
+ two_writes));
+ // Ack server's data packet.
+ AddWrite(ConstructClientAckPacket(2, 3, 1));
+ const char kBody3[] = "hello there";
+ const char kBody4[] = "another piece of small data";
+ const char kBody5[] = "really small";
+ QuicStreamOffset data_offset = strlen(kBody1) + strlen(kBody2);
+ AddWrite(ConstructClientMultipleDataFramesPacket(
+ 3, !kIncludeVersion, kFin, data_offset, {kBody3, kBody4, kBody5}));
+
+ Initialize();
+
+ BidirectionalStreamRequestInfo request;
+ request.method = "POST";
+ request.url = GURL("http://www.google.com/");
+ request.end_stream_on_headers = false;
+ request.priority = DEFAULT_PRIORITY;
+
+ scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
+ std::unique_ptr<TestDelegateBase> delegate(
+ new TestDelegateBase(read_buffer.get(), kReadBufferSize));
+ delegate->DoNotSendRequestHeadersAutomatically();
+ delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+ ConfirmHandshake();
+ delegate->WaitUntilNextCallback(); // OnStreamReady
+
+ // Send a Data packet.
+ scoped_refptr<StringIOBuffer> buf1(new StringIOBuffer(kBody1));
+ scoped_refptr<StringIOBuffer> buf2(new StringIOBuffer(kBody2));
+
+ std::vector<int> lengths = {buf1->size(), buf2->size()};
+ delegate->SendvData({buf1, buf2}, lengths, !kFin);
+ delegate->WaitUntilNextCallback(); // OnDataSent
+
+ // Server acks the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Server sends the response headers.
+ SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
+ size_t spdy_response_headers_frame_length;
+ QuicStreamOffset offset = 0;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, !kFin, std::move(response_headers),
+ &spdy_response_headers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnHeadersReceived
+ TestCompletionCallback cb;
+ int rv = delegate->ReadData(cb.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
+ const char kResponseBody[] = "Hello world!";
+ // Server sends data.
+ ProcessPacket(
+ ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
+
+ EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult());
+
+ // Send a second Data packet.
+ scoped_refptr<StringIOBuffer> buf3(new StringIOBuffer(kBody3));
+ scoped_refptr<StringIOBuffer> buf4(new StringIOBuffer(kBody4));
+ scoped_refptr<StringIOBuffer> buf5(new StringIOBuffer(kBody5));
+
+ delegate->SendvData({buf3, buf4, buf5},
+ {buf3->size(), buf4->size(), buf5->size()}, kFin);
+ delegate->WaitUntilNextCallback(); // OnDataSent
+
+ size_t spdy_trailers_frame_length;
+ SpdyHeaderBlock trailers;
+ trailers["foo"] = "bar";
+ trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
+ // Server sends trailers.
+ ProcessPacket(ConstructResponseTrailersPacket(
+ 4, kFin, trailers.Clone(), &spdy_trailers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnTrailersReceived
+ trailers.erase(kFinalOffsetHeaderKey);
+ EXPECT_EQ(trailers, delegate->trailers());
+ EXPECT_THAT(delegate->ReadData(cb.callback()), IsOk());
+
+ EXPECT_EQ(1, delegate->on_data_read_count());
+ EXPECT_EQ(2, delegate->on_data_sent_count());
+ EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
+ EXPECT_EQ(
+ static_cast<int64_t>(spdy_request_headers_frame_length + strlen(kBody1) +
+ strlen(kBody2) + strlen(kBody3) + strlen(kBody4) +
+ strlen(kBody5)),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(
+ static_cast<int64_t>(spdy_response_headers_frame_length +
+ strlen(kResponseBody) + spdy_trailers_frame_length),
+ delegate->GetTotalReceivedBytes());
+}
+
+TEST_P(BidirectionalStreamQuicImplTest, PostRequest) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructDataPacket(2, kIncludeVersion, kFin, 0, kUploadData,
+ &client_maker_));
+ AddWrite(ConstructClientAckPacket(3, 3, 1));
+
+ Initialize();
+
+ BidirectionalStreamRequestInfo request;
+ request.method = "POST";
+ request.url = GURL("http://www.google.com/");
+ request.end_stream_on_headers = false;
+ request.priority = DEFAULT_PRIORITY;
+
+ 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()->GetWeakPtr());
+ ConfirmHandshake();
+ delegate->WaitUntilNextCallback(); // OnStreamReady
+
+ // Send a DATA frame.
+ scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(kUploadData));
+
+ delegate->SendData(buf, buf->size(), true);
+ delegate->WaitUntilNextCallback(); // OnDataSent
+
+ // Server acks the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Server sends the response headers.
+ SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
+ size_t spdy_response_headers_frame_length;
+ QuicStreamOffset offset = 0;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, !kFin, std::move(response_headers),
+ &spdy_response_headers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnHeadersReceived
+ TestCompletionCallback cb;
+ int rv = delegate->ReadData(cb.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
+ const char kResponseBody[] = "Hello world!";
+ // Server sends data.
+ ProcessPacket(
+ ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
+
+ EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult());
+
+ size_t spdy_trailers_frame_length;
+ SpdyHeaderBlock trailers;
+ trailers["foo"] = "bar";
+ trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
+ // Server sends trailers.
+ ProcessPacket(ConstructResponseTrailersPacket(
+ 4, kFin, trailers.Clone(), &spdy_trailers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnTrailersReceived
+ trailers.erase(kFinalOffsetHeaderKey);
+ EXPECT_EQ(trailers, delegate->trailers());
+ EXPECT_THAT(delegate->ReadData(cb.callback()), IsOk());
+
+ EXPECT_EQ(1, delegate->on_data_read_count());
+ EXPECT_EQ(1, delegate->on_data_sent_count());
+ EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
+ strlen(kUploadData)),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(
+ static_cast<int64_t>(spdy_response_headers_frame_length +
+ strlen(kResponseBody) + spdy_trailers_frame_length),
+ delegate->GetTotalReceivedBytes());
+}
+
+TEST_P(BidirectionalStreamQuicImplTest, PutRequest) {
+ SetRequest("PUT", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructDataPacket(2, kIncludeVersion, kFin, 0, kUploadData,
+ &client_maker_));
+ AddWrite(ConstructClientAckPacket(3, 3, 1));
+
+ Initialize();
+
+ BidirectionalStreamRequestInfo request;
+ request.method = "PUT";
+ request.url = GURL("http://www.google.com/");
+ request.end_stream_on_headers = false;
+ request.priority = DEFAULT_PRIORITY;
+
+ 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()->GetWeakPtr());
+ delegate->WaitUntilNextCallback(); // OnStreamReady
+
+ // Send a DATA frame.
+ scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(kUploadData));
+
+ delegate->SendData(buf, buf->size(), true);
+ delegate->WaitUntilNextCallback(); // OnDataSent
+
+ // Server acks the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Server sends the response headers.
+ SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
+ size_t spdy_response_headers_frame_length;
+ QuicStreamOffset offset = 0;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, !kFin, std::move(response_headers),
+ &spdy_response_headers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnHeadersReceived
+ TestCompletionCallback cb;
+ int rv = delegate->ReadData(cb.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
+ const char kResponseBody[] = "Hello world!";
+ // Server sends data.
+ ProcessPacket(
+ ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
+
+ EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult());
+
+ size_t spdy_trailers_frame_length;
+ SpdyHeaderBlock trailers;
+ trailers["foo"] = "bar";
+ trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
+ // Server sends trailers.
+ ProcessPacket(ConstructResponseTrailersPacket(
+ 4, kFin, trailers.Clone(), &spdy_trailers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnTrailersReceived
+ trailers.erase(kFinalOffsetHeaderKey);
+ EXPECT_EQ(trailers, delegate->trailers());
+ EXPECT_THAT(delegate->ReadData(cb.callback()), IsOk());
+
+ EXPECT_EQ(1, delegate->on_data_read_count());
+ EXPECT_EQ(1, delegate->on_data_sent_count());
+ EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
+ strlen(kUploadData)),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(
+ static_cast<int64_t>(spdy_response_headers_frame_length +
+ strlen(kResponseBody) + spdy_trailers_frame_length),
+ delegate->GetTotalReceivedBytes());
+}
+
+TEST_P(BidirectionalStreamQuicImplTest, InterleaveReadDataAndSendData) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructAckAndDataPacket(2, !kIncludeVersion, 2, 1, !kFin, 0,
+ kUploadData, &client_maker_));
+ AddWrite(ConstructAckAndDataPacket(3, !kIncludeVersion, 3, 3, kFin,
+ strlen(kUploadData), kUploadData,
+ &client_maker_));
+ Initialize();
+
+ BidirectionalStreamRequestInfo request;
+ request.method = "POST";
+ request.url = GURL("http://www.google.com/");
+ request.end_stream_on_headers = false;
+ request.priority = DEFAULT_PRIORITY;
+
+ 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()->GetWeakPtr());
+ ConfirmHandshake();
+ delegate->WaitUntilNextCallback(); // OnStreamReady
+
+ // Server acks the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Server sends the response headers.
+ SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(
+ ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
+ &spdy_response_headers_frame_length, 0));
+
+ delegate->WaitUntilNextCallback(); // OnHeadersReceived
+ EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
+
+ // Client sends a data packet.
+ scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(kUploadData));
+
+ delegate->SendData(buf, buf->size(), false);
+ delegate->WaitUntilNextCallback(); // OnDataSent
+
+ TestCompletionCallback cb;
+ int rv = delegate->ReadData(cb.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ const char kResponseBody[] = "Hello world!";
+
+ // Server sends a data packet.
+ ProcessPacket(ConstructAckAndDataPacket(3, !kIncludeVersion, 2, 1, !kFin, 0,
+ kResponseBody, &server_maker_));
+
+ EXPECT_EQ(static_cast<int64_t>(strlen(kResponseBody)), cb.WaitForResult());
+ EXPECT_EQ(std::string(kResponseBody), delegate->data_received());
+
+ // Client sends a data packet.
+ delegate->SendData(buf, buf->size(), true);
+ delegate->WaitUntilNextCallback(); // OnDataSent
+
+ TestCompletionCallback cb2;
+ rv = delegate->ReadData(cb2.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ ProcessPacket(ConstructAckAndDataPacket(4, !kIncludeVersion, 3, 1, kFin,
+ strlen(kResponseBody), kResponseBody,
+ &server_maker_));
+
+ EXPECT_EQ(static_cast<int64_t>(strlen(kResponseBody)), cb2.WaitForResult());
+
+ std::string expected_body(kResponseBody);
+ expected_body.append(kResponseBody);
+ EXPECT_EQ(expected_body, delegate->data_received());
+
+ EXPECT_THAT(delegate->ReadData(cb.callback()), IsOk());
+ EXPECT_EQ(2, delegate->on_data_read_count());
+ EXPECT_EQ(2, delegate->on_data_sent_count());
+ EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
+ 2 * strlen(kUploadData)),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
+ 2 * strlen(kResponseBody)),
+ delegate->GetTotalReceivedBytes());
+}
+
+TEST_P(BidirectionalStreamQuicImplTest, ServerSendsRstAfterHeaders) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ Initialize();
+
+ BidirectionalStreamRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+ request.end_stream_on_headers = true;
+ request.priority = DEFAULT_PRIORITY;
+
+ 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()->GetWeakPtr());
+ delegate->WaitUntilNextCallback(); // OnStreamReady
+ ConfirmHandshake();
+
+ // Server sends a Rst.
+ ProcessPacket(ConstructServerRstStreamPacket(1));
+
+ delegate->WaitUntilNextCallback(); // OnFailed
+ TestCompletionCallback cb;
+ EXPECT_THAT(delegate->ReadData(cb.callback()),
+ IsError(ERR_QUIC_PROTOCOL_ERROR));
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_THAT(delegate->error(), IsError(ERR_QUIC_PROTOCOL_ERROR));
+ EXPECT_EQ(0, delegate->on_data_read_count());
+ EXPECT_EQ(0, delegate->on_data_sent_count());
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
+}
+
+TEST_P(BidirectionalStreamQuicImplTest, ServerSendsRstAfterReadData) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ // Why does QUIC ack Rst? Is this expected?
+ AddWrite(ConstructClientAckPacket(2, 3, 1));
+
+ Initialize();
+
+ BidirectionalStreamRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+ request.end_stream_on_headers = true;
+ request.priority = DEFAULT_PRIORITY;
+
+ 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()->GetWeakPtr());
+ delegate->WaitUntilNextCallback(); // OnStreamReady
+ ConfirmHandshake();
+
+ // Server acks the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Server sends the response headers.
+ SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
+
+ size_t spdy_response_headers_frame_length;
+ QuicStreamOffset offset = 0;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, !kFin, std::move(response_headers),
+ &spdy_response_headers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnHeadersReceived
+ EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
+
+ TestCompletionCallback cb;
+ int rv = delegate->ReadData(cb.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+ // Server sends a Rst.
+ ProcessPacket(ConstructServerRstStreamPacket(3));
+
+ delegate->WaitUntilNextCallback(); // OnFailed
+
+ EXPECT_THAT(delegate->ReadData(cb.callback()),
+ IsError(ERR_QUIC_PROTOCOL_ERROR));
+ EXPECT_THAT(delegate->error(), IsError(ERR_QUIC_PROTOCOL_ERROR));
+ EXPECT_EQ(0, delegate->on_data_read_count());
+ EXPECT_EQ(0, delegate->on_data_sent_count());
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length),
+ delegate->GetTotalReceivedBytes());
+}
+
+TEST_P(BidirectionalStreamQuicImplTest, SessionClosedBeforeReadData) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ Initialize();
+
+ BidirectionalStreamRequestInfo request;
+ request.method = "POST";
+ request.url = GURL("http://www.google.com/");
+ request.end_stream_on_headers = false;
+ request.priority = DEFAULT_PRIORITY;
+
+ 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()->GetWeakPtr());
+ ConfirmHandshake();
+ delegate->WaitUntilNextCallback(); // OnStreamReady
+
+ // Server acks the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Server sends the response headers.
+ SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
+
+ size_t spdy_response_headers_frame_length;
+ QuicStreamOffset offset = 0;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, !kFin, std::move(response_headers),
+ &spdy_response_headers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnHeadersReceived
+ TestCompletionCallback cb;
+ int rv = delegate->ReadData(cb.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ session()->connection()->CloseConnection(
+ QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
+ delegate->WaitUntilNextCallback(); // OnFailed
+ EXPECT_TRUE(delegate->on_failed_called());
+
+ // Try to send data after OnFailed(), should not get called back.
+ scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(kUploadData));
+ delegate->SendData(buf, buf->size(), false);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_THAT(delegate->ReadData(cb.callback()), IsError(ERR_UNEXPECTED));
+ EXPECT_THAT(delegate->error(), IsError(ERR_UNEXPECTED));
+ EXPECT_EQ(0, delegate->on_data_read_count());
+ EXPECT_EQ(0, delegate->on_data_sent_count());
+ EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length),
+ delegate->GetTotalReceivedBytes());
+}
+
+TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamAfterReadData) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructClientAckAndRstStreamPacket(2, 2, 1, 1));
+
+ Initialize();
+
+ BidirectionalStreamRequestInfo request;
+ request.method = "POST";
+ request.url = GURL("http://www.google.com/");
+ request.end_stream_on_headers = false;
+ request.priority = DEFAULT_PRIORITY;
+
+ 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()->GetWeakPtr());
+ ConfirmHandshake();
+ delegate->WaitUntilNextCallback(); // OnStreamReady
+
+ // Server acks the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Server sends the response headers.
+ SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(
+ ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers),
+ &spdy_response_headers_frame_length, 0));
+
+ delegate->WaitUntilNextCallback(); // OnHeadersReceived
+ EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
+
+ // Cancel the stream after ReadData returns ERR_IO_PENDING.
+ TestCompletionCallback cb;
+ EXPECT_THAT(delegate->ReadData(cb.callback()), IsError(ERR_IO_PENDING));
+ delegate->DeleteStream();
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(0, delegate->on_data_read_count());
+ EXPECT_EQ(0, delegate->on_data_sent_count());
+ EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
+ delegate->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length),
+ delegate->GetTotalReceivedBytes());
+}
+
+TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnHeadersReceived) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructClientAckAndRstStreamPacket(2, 2, 1, 1));
+
+ Initialize();
+
+ BidirectionalStreamRequestInfo request;
+ request.method = "POST";
+ request.url = GURL("http://www.google.com/");
+ request.end_stream_on_headers = false;
+ request.priority = DEFAULT_PRIORITY;
+
+ scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
+ std::unique_ptr<DeleteStreamDelegate> delegate(
+ new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize,
+ DeleteStreamDelegate::ON_HEADERS_RECEIVED));
+ delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+ ConfirmHandshake();
+ delegate->WaitUntilNextCallback(); // OnStreamReady
+
+ // Server acks the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Server sends the response headers.
+ SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
+
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, !kFin, std::move(response_headers),
+ &spdy_response_headers_frame_length, nullptr));
+
+ delegate->WaitUntilNextCallback(); // OnHeadersReceived
+ EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(0, delegate->on_data_read_count());
+ EXPECT_EQ(0, delegate->on_data_sent_count());
+}
+
+TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnDataRead) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructClientAckPacket(2, 3, 1));
+ AddWrite(ConstructClientRstStreamPacket(3));
+
+ Initialize();
+
+ BidirectionalStreamRequestInfo request;
+ request.method = "POST";
+ request.url = GURL("http://www.google.com/");
+ request.end_stream_on_headers = false;
+ request.priority = DEFAULT_PRIORITY;
+
+ 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()->GetWeakPtr());
+ ConfirmHandshake();
+ delegate->WaitUntilNextCallback(); // OnStreamReady
+
+ // Server acks the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Server sends the response headers.
+ SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
+
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, !kFin, std::move(response_headers),
+ &spdy_response_headers_frame_length, nullptr));
+
+ delegate->WaitUntilNextCallback(); // OnHeadersReceived
+
+ EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
+
+ TestCompletionCallback cb;
+ int rv = delegate->ReadData(cb.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ const char kResponseBody[] = "Hello world!";
+ // Server sends data.
+ ProcessPacket(
+ ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
+ EXPECT_EQ(static_cast<int64_t>(strlen(kResponseBody)), cb.WaitForResult());
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, delegate->on_data_read_count());
+ EXPECT_EQ(0, delegate->on_data_sent_count());
+}
+
+TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamDuringOnTrailersReceived) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructClientAckPacket(2, 3, 1)); // Ack the data packet
+ AddWrite(ConstructClientAckAndRstStreamPacket(3, 4, 4, 1));
+
+ Initialize();
+
+ BidirectionalStreamRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("http://www.google.com/");
+ request.end_stream_on_headers = true;
+ request.priority = DEFAULT_PRIORITY;
+
+ scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
+ std::unique_ptr<DeleteStreamDelegate> delegate(
+ new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize,
+ DeleteStreamDelegate::ON_TRAILERS_RECEIVED));
+ delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+ delegate->WaitUntilNextCallback(); // OnStreamReady
+
+ // Server acks the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Server sends the response headers.
+ SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
+
+ QuicStreamOffset offset = 0;
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, !kFin, std::move(response_headers),
+ &spdy_response_headers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnHeadersReceived
+
+ EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
+
+ TestCompletionCallback cb;
+ int rv = delegate->ReadData(cb.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ const char kResponseBody[] = "Hello world!";
+ // Server sends data.
+ ProcessPacket(
+ ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
+
+ EXPECT_EQ(static_cast<int64_t>(strlen(kResponseBody)), cb.WaitForResult());
+ EXPECT_EQ(std::string(kResponseBody), delegate->data_received());
+
+ size_t spdy_trailers_frame_length;
+ SpdyHeaderBlock trailers;
+ trailers["foo"] = "bar";
+ trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
+ // Server sends trailers.
+ ProcessPacket(ConstructResponseTrailersPacket(
+ 4, kFin, trailers.Clone(), &spdy_trailers_frame_length, &offset));
+
+ delegate->WaitUntilNextCallback(); // OnTrailersReceived
+ trailers.erase(kFinalOffsetHeaderKey);
+ EXPECT_EQ(trailers, delegate->trailers());
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, delegate->on_data_read_count());
+ EXPECT_EQ(0, delegate->on_data_sent_count());
+}
+
+} // namespace test
+
+} // namespace net
diff --git a/chromium/net/quic/chromium/crypto/channel_id_chromium.cc b/chromium/net/quic/chromium/crypto/channel_id_chromium.cc
new file mode 100644
index 00000000000..cfaf61b0ea1
--- /dev/null
+++ b/chromium/net/quic/chromium/crypto/channel_id_chromium.cc
@@ -0,0 +1,224 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/chromium/crypto/channel_id_chromium.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "crypto/ec_private_key.h"
+#include "crypto/ec_signature_creator.h"
+#include "net/base/net_errors.h"
+#include "net/cert/asn1_util.h"
+#include "net/ssl/channel_id_service.h"
+
+namespace net {
+
+ChannelIDKeyChromium::ChannelIDKeyChromium(
+ std::unique_ptr<crypto::ECPrivateKey> ec_private_key)
+ : ec_private_key_(std::move(ec_private_key)) {}
+
+ChannelIDKeyChromium::~ChannelIDKeyChromium() {}
+
+bool ChannelIDKeyChromium::Sign(base::StringPiece signed_data,
+ std::string* out_signature) const {
+ std::unique_ptr<crypto::ECSignatureCreator> sig_creator(
+ crypto::ECSignatureCreator::Create(ec_private_key_.get()));
+ if (!sig_creator) {
+ return false;
+ }
+ const size_t len1 = strlen(ChannelIDVerifier::kContextStr) + 1;
+ const size_t len2 = strlen(ChannelIDVerifier::kClientToServerStr) + 1;
+ std::vector<uint8_t> data(len1 + len2 + signed_data.size());
+ memcpy(&data[0], ChannelIDVerifier::kContextStr, len1);
+ memcpy(&data[len1], ChannelIDVerifier::kClientToServerStr, len2);
+ memcpy(&data[len1 + len2], signed_data.data(), signed_data.size());
+ std::vector<uint8_t> der_signature;
+ if (!sig_creator->Sign(&data[0], data.size(), &der_signature)) {
+ return false;
+ }
+ std::vector<uint8_t> raw_signature;
+ if (!sig_creator->DecodeSignature(der_signature, &raw_signature)) {
+ return false;
+ }
+ memcpy(base::WriteInto(out_signature, raw_signature.size() + 1),
+ &raw_signature[0], raw_signature.size());
+ return true;
+}
+
+std::string ChannelIDKeyChromium::SerializeKey() const {
+ std::string out_key;
+ if (!ec_private_key_->ExportRawPublicKey(&out_key)) {
+ return std::string();
+ }
+ return out_key;
+}
+
+// A Job handles the lookup of a single channel ID. It is owned by the
+// ChannelIDSource. If the operation can not complete synchronously, it will
+// notify the ChannelIDSource upon completion.
+class ChannelIDSourceChromium::Job {
+ public:
+ Job(ChannelIDSourceChromium* channel_id_source,
+ ChannelIDService* channel_id_service);
+
+ // Starts the channel ID lookup. If |QUIC_PENDING| is returned, then
+ // |callback| will be invoked asynchronously when the operation completes.
+ QuicAsyncStatus GetChannelIDKey(const std::string& hostname,
+ std::unique_ptr<ChannelIDKey>* channel_id_key,
+ ChannelIDSourceCallback* callback);
+
+ private:
+ enum State {
+ STATE_NONE,
+ STATE_GET_CHANNEL_ID_KEY,
+ STATE_GET_CHANNEL_ID_KEY_COMPLETE,
+ };
+
+ int DoLoop(int last_io_result);
+ void OnIOComplete(int result);
+ int DoGetChannelIDKey(int result);
+ int DoGetChannelIDKeyComplete(int result);
+
+ // Channel ID source to notify when this jobs completes.
+ ChannelIDSourceChromium* const channel_id_source_;
+
+ ChannelIDService* const channel_id_service_;
+
+ std::unique_ptr<crypto::ECPrivateKey> channel_id_crypto_key_;
+ ChannelIDService::Request channel_id_request_;
+
+ // |hostname| specifies the hostname for which we need a channel ID.
+ std::string hostname_;
+
+ std::unique_ptr<ChannelIDSourceCallback> callback_;
+
+ std::unique_ptr<ChannelIDKey> channel_id_key_;
+
+ State next_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(Job);
+};
+
+ChannelIDSourceChromium::Job::Job(ChannelIDSourceChromium* channel_id_source,
+ ChannelIDService* channel_id_service)
+ : channel_id_source_(channel_id_source),
+ channel_id_service_(channel_id_service),
+ next_state_(STATE_NONE) {}
+
+QuicAsyncStatus ChannelIDSourceChromium::Job::GetChannelIDKey(
+ const std::string& hostname,
+ std::unique_ptr<ChannelIDKey>* channel_id_key,
+ ChannelIDSourceCallback* callback) {
+ DCHECK(channel_id_key);
+ DCHECK(callback);
+
+ if (STATE_NONE != next_state_) {
+ DLOG(DFATAL) << "GetChannelIDKey has begun";
+ return QUIC_FAILURE;
+ }
+
+ channel_id_key_.reset();
+
+ hostname_ = hostname;
+
+ next_state_ = STATE_GET_CHANNEL_ID_KEY;
+ switch (DoLoop(OK)) {
+ case OK:
+ channel_id_key->reset(channel_id_key_.release());
+ return QUIC_SUCCESS;
+ case ERR_IO_PENDING:
+ callback_.reset(callback);
+ return QUIC_PENDING;
+ default:
+ channel_id_key->reset();
+ return QUIC_FAILURE;
+ }
+}
+
+int ChannelIDSourceChromium::Job::DoLoop(int last_result) {
+ int rv = last_result;
+ do {
+ State state = next_state_;
+ next_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_GET_CHANNEL_ID_KEY:
+ DCHECK(rv == OK);
+ rv = DoGetChannelIDKey(rv);
+ break;
+ case STATE_GET_CHANNEL_ID_KEY_COMPLETE:
+ rv = DoGetChannelIDKeyComplete(rv);
+ break;
+ case STATE_NONE:
+ default:
+ rv = ERR_UNEXPECTED;
+ LOG(DFATAL) << "unexpected state " << state;
+ break;
+ }
+ } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
+ return rv;
+}
+
+void ChannelIDSourceChromium::Job::OnIOComplete(int result) {
+ int rv = DoLoop(result);
+ if (rv != ERR_IO_PENDING) {
+ std::unique_ptr<ChannelIDSourceCallback> callback(callback_.release());
+ callback->Run(&channel_id_key_);
+ // Will delete |this|.
+ channel_id_source_->OnJobComplete(this);
+ }
+}
+
+int ChannelIDSourceChromium::Job::DoGetChannelIDKey(int result) {
+ next_state_ = STATE_GET_CHANNEL_ID_KEY_COMPLETE;
+
+ return channel_id_service_->GetOrCreateChannelID(
+ hostname_, &channel_id_crypto_key_,
+ base::Bind(&ChannelIDSourceChromium::Job::OnIOComplete,
+ base::Unretained(this)),
+ &channel_id_request_);
+}
+
+int ChannelIDSourceChromium::Job::DoGetChannelIDKeyComplete(int result) {
+ DCHECK_EQ(STATE_NONE, next_state_);
+ if (result != OK) {
+ DLOG(WARNING) << "Failed to look up channel ID: " << ErrorToString(result);
+ return result;
+ }
+
+ DCHECK(channel_id_crypto_key_);
+ channel_id_key_.reset(
+ new ChannelIDKeyChromium(std::move(channel_id_crypto_key_)));
+ return result;
+}
+
+ChannelIDSourceChromium::ChannelIDSourceChromium(
+ ChannelIDService* channel_id_service)
+ : channel_id_service_(channel_id_service) {}
+
+ChannelIDSourceChromium::~ChannelIDSourceChromium() {
+ base::STLDeleteElements(&active_jobs_);
+}
+
+QuicAsyncStatus ChannelIDSourceChromium::GetChannelIDKey(
+ const std::string& hostname,
+ std::unique_ptr<ChannelIDKey>* channel_id_key,
+ ChannelIDSourceCallback* callback) {
+ std::unique_ptr<Job> job(new Job(this, channel_id_service_));
+ QuicAsyncStatus status =
+ job->GetChannelIDKey(hostname, channel_id_key, callback);
+ if (status == QUIC_PENDING) {
+ active_jobs_.insert(job.release());
+ }
+ return status;
+}
+
+void ChannelIDSourceChromium::OnJobComplete(Job* job) {
+ active_jobs_.erase(job);
+ delete job;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/chromium/crypto/channel_id_chromium.h b/chromium/net/quic/chromium/crypto/channel_id_chromium.h
new file mode 100644
index 00000000000..2baa587f0a9
--- /dev/null
+++ b/chromium/net/quic/chromium/crypto/channel_id_chromium.h
@@ -0,0 +1,66 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CRYPTO_CHANNEL_ID_CHROMIUM_H_
+#define NET_QUIC_CRYPTO_CHANNEL_ID_CHROMIUM_H_
+
+#include <set>
+#include <string>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/channel_id.h"
+
+namespace crypto {
+class ECPrivateKey;
+} // namespace crypto
+
+namespace net {
+
+class ChannelIDService;
+
+class NET_EXPORT_PRIVATE ChannelIDKeyChromium : public ChannelIDKey {
+ public:
+ explicit ChannelIDKeyChromium(
+ std::unique_ptr<crypto::ECPrivateKey> ec_private_key);
+ ~ChannelIDKeyChromium() override;
+
+ // ChannelIDKey interface
+ bool Sign(base::StringPiece signed_data,
+ std::string* out_signature) const override;
+ std::string SerializeKey() const override;
+
+ private:
+ std::unique_ptr<crypto::ECPrivateKey> ec_private_key_;
+};
+
+// ChannelIDSourceChromium implements the QUIC ChannelIDSource interface.
+class ChannelIDSourceChromium : public ChannelIDSource {
+ public:
+ explicit ChannelIDSourceChromium(ChannelIDService* channel_id_service);
+ ~ChannelIDSourceChromium() override;
+
+ // ChannelIDSource interface
+ QuicAsyncStatus GetChannelIDKey(const std::string& hostname,
+ std::unique_ptr<ChannelIDKey>* channel_id_key,
+ ChannelIDSourceCallback* callback) override;
+
+ private:
+ class Job;
+ typedef std::set<Job*> JobSet;
+
+ void OnJobComplete(Job* job);
+
+ // Set owning pointers to active jobs.
+ JobSet active_jobs_;
+
+ // The service for retrieving Channel ID keys.
+ ChannelIDService* const channel_id_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChannelIDSourceChromium);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CHANNEL_ID_CHROMIUM_H_
diff --git a/chromium/net/quic/chromium/crypto/proof_source_chromium.cc b/chromium/net/quic/chromium/crypto/proof_source_chromium.cc
new file mode 100644
index 00000000000..44b5e825213
--- /dev/null
+++ b/chromium/net/quic/chromium/crypto/proof_source_chromium.cc
@@ -0,0 +1,169 @@
+// Copyright 2013 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/chromium/crypto/proof_source_chromium.h"
+
+#include <openssl/digest.h>
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+
+#include "base/strings/string_number_conversions.h"
+#include "crypto/openssl_util.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/ssl/scoped_openssl_types.h"
+
+using std::string;
+using std::vector;
+
+namespace net {
+
+ProofSourceChromium::ProofSourceChromium() {}
+
+ProofSourceChromium::~ProofSourceChromium() {}
+
+bool ProofSourceChromium::Initialize(const base::FilePath& cert_path,
+ const base::FilePath& key_path,
+ const base::FilePath& sct_path) {
+ crypto::EnsureOpenSSLInit();
+
+ std::string cert_data;
+ if (!base::ReadFileToString(cert_path, &cert_data)) {
+ DLOG(FATAL) << "Unable to read certificates.";
+ return false;
+ }
+
+ CertificateList certs_in_file =
+ X509Certificate::CreateCertificateListFromBytes(
+ cert_data.data(), cert_data.size(), X509Certificate::FORMAT_AUTO);
+
+ if (certs_in_file.empty()) {
+ DLOG(FATAL) << "No certificates.";
+ return false;
+ }
+
+ 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);
+ }
+ chain_ = new ProofSource::Chain(certs);
+
+ std::string key_data;
+ if (!base::ReadFileToString(key_path, &key_data)) {
+ DLOG(FATAL) << "Unable to read key.";
+ return false;
+ }
+
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(key_data.data());
+ std::vector<uint8_t> input(p, p + key_data.size());
+ private_key_ = crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input);
+ if (!private_key_) {
+ DLOG(FATAL) << "Unable to create private key.";
+ return false;
+ }
+
+ // Loading of the signed certificate timestamp is optional.
+ if (sct_path.empty())
+ return true;
+
+ if (!base::ReadFileToString(sct_path, &signed_certificate_timestamp_)) {
+ DLOG(FATAL) << "Unable to read signed certificate timestamp.";
+ return false;
+ }
+
+ return true;
+}
+
+bool ProofSourceChromium::GetProof(const IPAddress& server_ip,
+ const string& hostname,
+ const string& server_config,
+ QuicVersion quic_version,
+ base::StringPiece chlo_hash,
+ scoped_refptr<ProofSource::Chain>* out_chain,
+ string* out_signature,
+ string* out_leaf_cert_sct) {
+ DCHECK(private_key_.get()) << " this: " << this;
+
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ crypto::ScopedEVP_MD_CTX sign_context(EVP_MD_CTX_create());
+ EVP_PKEY_CTX* pkey_ctx;
+
+ if (quic_version > QUIC_VERSION_30) {
+ uint32_t len = chlo_hash.length();
+ if (!EVP_DigestSignInit(sign_context.get(), &pkey_ctx, EVP_sha256(),
+ nullptr, private_key_->key()) ||
+ !EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) ||
+ !EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1) ||
+ !EVP_DigestSignUpdate(
+ sign_context.get(),
+ reinterpret_cast<const uint8_t*>(kProofSignatureLabel),
+ sizeof(kProofSignatureLabel)) ||
+ !EVP_DigestSignUpdate(sign_context.get(),
+ reinterpret_cast<const uint8_t*>(&len),
+ sizeof(len)) ||
+ !EVP_DigestSignUpdate(
+ sign_context.get(),
+ reinterpret_cast<const uint8_t*>(chlo_hash.data()), len) ||
+ !EVP_DigestSignUpdate(
+ sign_context.get(),
+ reinterpret_cast<const uint8_t*>(server_config.data()),
+ server_config.size())) {
+ return false;
+ }
+ } else if (!EVP_DigestSignInit(sign_context.get(), &pkey_ctx, EVP_sha256(),
+ nullptr, private_key_->key()) ||
+ !EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) ||
+ !EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1) ||
+ !EVP_DigestSignUpdate(
+ sign_context.get(),
+ reinterpret_cast<const uint8_t*>(kProofSignatureLabelOld),
+ sizeof(kProofSignatureLabelOld)) ||
+ !EVP_DigestSignUpdate(
+ sign_context.get(),
+ reinterpret_cast<const uint8_t*>(server_config.data()),
+ server_config.size())) {
+ return false;
+ }
+
+ // Determine the maximum length of the signature.
+ size_t len = 0;
+ if (!EVP_DigestSignFinal(sign_context.get(), nullptr, &len)) {
+ return false;
+ }
+ std::vector<uint8_t> signature(len);
+ // Sign it.
+ if (!EVP_DigestSignFinal(sign_context.get(), signature.data(), &len)) {
+ return false;
+ }
+ signature.resize(len);
+ out_signature->assign(reinterpret_cast<const char*>(signature.data()),
+ signature.size());
+ *out_chain = chain_;
+ VLOG(1) << "signature: "
+ << base::HexEncode(out_signature->data(), out_signature->size());
+ *out_leaf_cert_sct = signed_certificate_timestamp_;
+ return true;
+}
+
+void ProofSourceChromium::GetProof(const IPAddress& server_ip,
+ const std::string& hostname,
+ const std::string& server_config,
+ QuicVersion quic_version,
+ base::StringPiece chlo_hash,
+ std::unique_ptr<Callback> callback) {
+ // As a transitional implementation, just call the synchronous version of
+ // GetProof, then invoke the callback with the results and destroy it.
+ scoped_refptr<ProofSource::Chain> chain;
+ string signature;
+ string leaf_cert_sct;
+ const bool ok = GetProof(server_ip, hostname, server_config, quic_version,
+ chlo_hash, &chain, &signature, &leaf_cert_sct);
+ callback->Run(ok, chain, signature, leaf_cert_sct, nullptr /* details */);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/chromium/crypto/proof_source_chromium.h b/chromium/net/quic/chromium/crypto/proof_source_chromium.h
new file mode 100644
index 00000000000..2610258cbfd
--- /dev/null
+++ b/chromium/net/quic/chromium/crypto/proof_source_chromium.h
@@ -0,0 +1,62 @@
+// Copyright 2013 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_CRYPTO_PROOF_SOURCE_CHROMIUM_H_
+#define NET_QUIC_CRYPTO_PROOF_SOURCE_CHROMIUM_H_
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/files/file_util.h"
+#include "base/macros.h"
+#include "crypto/rsa_private_key.h"
+#include "net/base/net_export.h"
+#include "net/cert/x509_certificate.h"
+#include "net/quic/core/crypto/proof_source.h"
+
+namespace net {
+
+// ProofSourceChromium implements the QUIC ProofSource interface.
+// TODO(rtenneti): implement details of this class.
+class NET_EXPORT_PRIVATE ProofSourceChromium : public ProofSource {
+ public:
+ ProofSourceChromium();
+ ~ProofSourceChromium() override;
+
+ // Initializes this object based on the certificate chain in |cert_path|,
+ // and the PKCS#8 RSA private key in |key_path|. Signed certificate
+ // timestamp may be loaded from |sct_path| if it is non-empty.
+ bool Initialize(const base::FilePath& cert_path,
+ const base::FilePath& key_path,
+ const base::FilePath& sct_path);
+
+ // ProofSource interface
+ bool GetProof(const IPAddress& server_ip,
+ const std::string& hostname,
+ const std::string& server_config,
+ QuicVersion quic_version,
+ base::StringPiece chlo_hash,
+ scoped_refptr<ProofSource::Chain>* out_chain,
+ std::string* out_signature,
+ std::string* out_leaf_cert_sct) override;
+
+ void GetProof(const IPAddress& server_ip,
+ const std::string& hostname,
+ const std::string& server_config,
+ QuicVersion quic_version,
+ base::StringPiece chlo_hash,
+ std::unique_ptr<Callback> callback) override;
+
+ private:
+ std::unique_ptr<crypto::RSAPrivateKey> private_key_;
+ scoped_refptr<ProofSource::Chain> chain_;
+ std::string signed_certificate_timestamp_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProofSourceChromium);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_PROOF_SOURCE_CHROMIUM_H_
diff --git a/chromium/net/quic/chromium/crypto/proof_test_chromium.cc b/chromium/net/quic/chromium/crypto/proof_test_chromium.cc
new file mode 100644
index 00000000000..af0a4392740
--- /dev/null
+++ b/chromium/net/quic/chromium/crypto/proof_test_chromium.cc
@@ -0,0 +1,484 @@
+// Copyright (c) 2013 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 <memory>
+
+#include "base/files/file_path.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/cert/cert_status_flags.h"
+#include "net/cert/cert_verify_result.h"
+#include "net/cert/x509_certificate.h"
+#include "net/quic/core/crypto/proof_source.h"
+#include "net/quic/core/crypto/proof_verifier.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+using std::vector;
+
+namespace net {
+namespace test {
+namespace {
+
+// TestProofVerifierCallback is a simple callback for a ProofVerifier that
+// signals a TestCompletionCallback when called and stores the results from the
+// ProofVerifier in pointers passed to the constructor.
+class TestProofVerifierCallback : public ProofVerifierCallback {
+ public:
+ TestProofVerifierCallback(TestCompletionCallback* comp_callback,
+ bool* ok,
+ string* error_details)
+ : comp_callback_(comp_callback), ok_(ok), error_details_(error_details) {}
+
+ void Run(bool ok,
+ const string& error_details,
+ std::unique_ptr<ProofVerifyDetails>* details) override {
+ *ok_ = ok;
+ *error_details_ = error_details;
+
+ comp_callback_->callback().Run(0);
+ }
+
+ private:
+ TestCompletionCallback* const comp_callback_;
+ bool* const ok_;
+ string* const error_details_;
+};
+
+// RunVerification runs |verifier->VerifyProof| and asserts that the result
+// matches |expected_ok|.
+void RunVerification(ProofVerifier* verifier,
+ const string& hostname,
+ const uint16_t port,
+ const string& server_config,
+ QuicVersion quic_version,
+ StringPiece chlo_hash,
+ const vector<string>& certs,
+ const string& proof,
+ bool expected_ok) {
+ std::unique_ptr<ProofVerifyDetails> details;
+ TestCompletionCallback comp_callback;
+ bool ok;
+ string error_details;
+ std::unique_ptr<ProofVerifyContext> verify_context(
+ CryptoTestUtils::ProofVerifyContextForTesting());
+ std::unique_ptr<TestProofVerifierCallback> callback(
+ new TestProofVerifierCallback(&comp_callback, &ok, &error_details));
+
+ QuicAsyncStatus status = verifier->VerifyProof(
+ hostname, port, server_config, quic_version, chlo_hash, certs, "", proof,
+ verify_context.get(), &error_details, &details, std::move(callback));
+
+ switch (status) {
+ case QUIC_FAILURE:
+ ASSERT_FALSE(expected_ok);
+ ASSERT_NE("", error_details);
+ return;
+ case QUIC_SUCCESS:
+ ASSERT_TRUE(expected_ok);
+ ASSERT_EQ("", error_details);
+ return;
+ case QUIC_PENDING:
+ comp_callback.WaitForResult();
+ ASSERT_EQ(expected_ok, ok);
+ break;
+ }
+}
+
+// Reads the certificate named "quic_" + |file_name| in the test data directory.
+// The certificate must be PEM encoded. Returns the DER-encoded certificate.
+string LoadTestCert(const string& file_name) {
+ base::FilePath certs_dir = GetTestCertsDirectory();
+ scoped_refptr<X509Certificate> cert =
+ ImportCertFromFile(certs_dir, "quic_" + file_name);
+ CHECK_NE(static_cast<X509Certificate*>(nullptr), cert.get());
+
+ string der_bytes;
+ CHECK(X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_bytes));
+ return der_bytes;
+}
+
+class TestCallback : public ProofSource::Callback {
+ public:
+ explicit TestCallback(bool* called,
+ bool* ok,
+ scoped_refptr<ProofSource::Chain>* chain,
+ string* signature,
+ string* leaf_cert_sct)
+ : called_(called),
+ ok_(ok),
+ chain_(chain),
+ signature_(signature),
+ leaf_cert_sct_(leaf_cert_sct) {}
+
+ void Run(bool ok,
+ const scoped_refptr<ProofSource::Chain>& chain,
+ const string& signature,
+ const string& leaf_cert_sct,
+ std::unique_ptr<ProofSource::Details> /* details */) override {
+ *ok_ = ok;
+ *chain_ = chain;
+ *signature_ = signature;
+ *leaf_cert_sct_ = leaf_cert_sct;
+ *called_ = true;
+ }
+
+ private:
+ bool* called_;
+ bool* ok_;
+ scoped_refptr<ProofSource::Chain>* chain_;
+ string* signature_;
+ string* leaf_cert_sct_;
+};
+
+class ProofTest : public ::testing::TestWithParam<QuicVersion> {};
+
+} // namespace
+
+INSTANTIATE_TEST_CASE_P(QuicVersion,
+ ProofTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
+
+// TODO(rtenneti): Enable testing of ProofVerifier. See http://crbug.com/514468.
+TEST_P(ProofTest, DISABLED_Verify) {
+ std::unique_ptr<ProofSource> source(CryptoTestUtils::ProofSourceForTesting());
+ std::unique_ptr<ProofVerifier> verifier(
+ CryptoTestUtils::ProofVerifierForTesting());
+
+ const string server_config = "server config bytes";
+ const string hostname = "test.example.com";
+ const uint16_t port = 8443;
+ const string first_chlo_hash = "first chlo hash bytes";
+ const string second_chlo_hash = "first chlo hash bytes";
+ const QuicVersion quic_version = GetParam();
+
+ scoped_refptr<ProofSource::Chain> chain;
+ scoped_refptr<ProofSource::Chain> first_chain;
+ string error_details, signature, first_signature, first_cert_sct, cert_sct;
+ IPAddress server_ip;
+
+ ASSERT_TRUE(source->GetProof(server_ip, hostname, server_config, quic_version,
+ first_chlo_hash, &first_chain, &first_signature,
+ &first_cert_sct));
+ ASSERT_TRUE(source->GetProof(server_ip, hostname, server_config, quic_version,
+ second_chlo_hash, &chain, &signature,
+ &cert_sct));
+
+ // Check that the proof source is caching correctly:
+ ASSERT_EQ(first_chain->certs, chain->certs);
+ if (GetParam() < QUIC_VERSION_31) {
+ ASSERT_EQ(signature, first_signature);
+ } else {
+ // QUIC 31 includes the CHLO hash.
+ ASSERT_NE(signature, first_signature);
+ }
+ ASSERT_EQ(first_cert_sct, cert_sct);
+
+ RunVerification(verifier.get(), hostname, port, server_config, quic_version,
+ first_chlo_hash, chain->certs, signature, true);
+
+ RunVerification(verifier.get(), "foo.com", port, server_config, quic_version,
+ first_chlo_hash, chain->certs, signature, false);
+
+ RunVerification(verifier.get(), server_config.substr(1, string::npos), port,
+ server_config, quic_version, first_chlo_hash, chain->certs,
+ signature, false);
+
+ const string corrupt_signature = "1" + signature;
+ RunVerification(verifier.get(), hostname, port, server_config, quic_version,
+ first_chlo_hash, chain->certs, corrupt_signature, false);
+
+ vector<string> wrong_certs;
+ for (size_t i = 1; i < chain->certs.size(); i++) {
+ wrong_certs.push_back(chain->certs[i]);
+ }
+
+ RunVerification(verifier.get(), "foo.com", port, server_config, quic_version,
+ first_chlo_hash, wrong_certs, corrupt_signature, false);
+}
+
+TEST_P(ProofTest, VerifySourceAsync) {
+ std::unique_ptr<ProofSource> source(CryptoTestUtils::ProofSourceForTesting());
+
+ const string server_config = "server config bytes";
+ const string hostname = "test.example.com";
+ const string first_chlo_hash = "first chlo hash bytes";
+ const string second_chlo_hash = "first chlo hash bytes";
+ const QuicVersion quic_version = GetParam();
+ IPAddress server_ip;
+
+ // Call synchronous version
+ scoped_refptr<ProofSource::Chain> expected_chain;
+ string expected_signature;
+ string expected_leaf_cert_sct;
+ ASSERT_TRUE(source->GetProof(server_ip, hostname, server_config, quic_version,
+ first_chlo_hash, &expected_chain,
+ &expected_signature, &expected_leaf_cert_sct));
+
+ // Call asynchronous version and compare results
+ bool called = false;
+ bool ok;
+ scoped_refptr<ProofSource::Chain> chain;
+ string signature;
+ string leaf_cert_sct;
+ std::unique_ptr<ProofSource::Callback> cb(
+ new TestCallback(&called, &ok, &chain, &signature, &leaf_cert_sct));
+ source->GetProof(server_ip, hostname, server_config, quic_version,
+ first_chlo_hash, std::move(cb));
+ // TODO(gredner): whan GetProof really invokes the callback asynchronously,
+ // figure out what to do here.
+ ASSERT_TRUE(called);
+ ASSERT_TRUE(ok);
+ EXPECT_THAT(chain->certs, ::testing::ContainerEq(expected_chain->certs));
+ EXPECT_EQ(leaf_cert_sct, expected_leaf_cert_sct);
+}
+
+TEST_P(ProofTest, UseAfterFree) {
+ std::unique_ptr<ProofSource> source(CryptoTestUtils::ProofSourceForTesting());
+
+ const string server_config = "server config bytes";
+ const string hostname = "test.example.com";
+ const string chlo_hash = "proof nonce bytes";
+ scoped_refptr<ProofSource::Chain> chain;
+ string error_details, signature, cert_sct;
+ IPAddress server_ip;
+
+ ASSERT_TRUE(source->GetProof(server_ip, hostname, server_config, GetParam(),
+ chlo_hash, &chain, &signature, &cert_sct));
+
+ // Make sure we can safely access results after deleting where they came from.
+ EXPECT_FALSE(chain->HasOneRef());
+ source = nullptr;
+ EXPECT_TRUE(chain->HasOneRef());
+
+ EXPECT_FALSE(chain->certs.empty());
+ for (const string& cert : chain->certs) {
+ EXPECT_FALSE(cert.empty());
+ }
+}
+
+// A known answer test that allows us to test ProofVerifier without a working
+// ProofSource.
+TEST_P(ProofTest, VerifyRSAKnownAnswerTest) {
+ if (GetParam() > QUIC_VERSION_30) {
+ return;
+ }
+ // These sample signatures were generated by running the Proof.Verify test
+ // and dumping the bytes of the |signature| output of ProofSource::GetProof().
+ static const unsigned char signature_data_0[] = {
+ 0x31, 0xd5, 0xfb, 0x40, 0x30, 0x75, 0xd2, 0x7d, 0x61, 0xf9, 0xd7, 0x54,
+ 0x30, 0x06, 0xaf, 0x54, 0x0d, 0xb0, 0x0a, 0xda, 0x63, 0xca, 0x7e, 0x9e,
+ 0xce, 0xba, 0x10, 0x05, 0x1b, 0xa6, 0x7f, 0xef, 0x2b, 0xa3, 0xff, 0x3c,
+ 0xbb, 0x9a, 0xe4, 0xbf, 0xb8, 0x0c, 0xc1, 0xbd, 0xed, 0xc2, 0x90, 0x68,
+ 0xeb, 0x45, 0x48, 0xea, 0x3c, 0x95, 0xf8, 0xa2, 0xb9, 0xe7, 0x62, 0x29,
+ 0x00, 0xc3, 0x18, 0xb4, 0x16, 0x6f, 0x5e, 0xb0, 0xc1, 0x26, 0xc0, 0x4b,
+ 0x84, 0xf5, 0x97, 0xfc, 0x17, 0xf9, 0x1c, 0x43, 0xb8, 0xf2, 0x3f, 0x38,
+ 0x32, 0xad, 0x36, 0x52, 0x2c, 0x26, 0x92, 0x7a, 0xea, 0x2c, 0xa2, 0xf4,
+ 0x28, 0x2f, 0x19, 0x4d, 0x1f, 0x11, 0x46, 0x82, 0xd0, 0xc4, 0x86, 0x56,
+ 0x5c, 0x97, 0x9e, 0xc6, 0x37, 0x8e, 0xaf, 0x9d, 0x69, 0xe9, 0x4f, 0x5a,
+ 0x6d, 0x70, 0x75, 0xc7, 0x41, 0x95, 0x68, 0x53, 0x94, 0xca, 0x31, 0x63,
+ 0x61, 0x9f, 0xb8, 0x8c, 0x3b, 0x75, 0x36, 0x8b, 0x69, 0xa2, 0x35, 0xc0,
+ 0x4b, 0x77, 0x55, 0x08, 0xc2, 0xb4, 0x56, 0xd2, 0x81, 0xce, 0x9e, 0x25,
+ 0xdb, 0x50, 0x74, 0xb3, 0x8a, 0xd9, 0x20, 0x42, 0x3f, 0x85, 0x2d, 0xaa,
+ 0xfd, 0x66, 0xfa, 0xd6, 0x95, 0x55, 0x6b, 0x63, 0x63, 0x04, 0xf8, 0x6c,
+ 0x3e, 0x08, 0x22, 0x39, 0xb9, 0x9a, 0xe0, 0xd7, 0x01, 0xff, 0xeb, 0x8a,
+ 0xb9, 0xe2, 0x34, 0xa5, 0xa0, 0x51, 0xe9, 0xbe, 0x15, 0x12, 0xbf, 0xbe,
+ 0x64, 0x3d, 0x3f, 0x98, 0xce, 0xc1, 0xa6, 0x33, 0x32, 0xd3, 0x5c, 0xa8,
+ 0x39, 0x93, 0xdc, 0x1c, 0xb9, 0xab, 0x3c, 0x80, 0x62, 0xb3, 0x76, 0x21,
+ 0xdf, 0x47, 0x1e, 0xa9, 0x0e, 0x5e, 0x8a, 0xbe, 0x66, 0x5b, 0x7c, 0x21,
+ 0xfa, 0x78, 0x2d, 0xd1, 0x1d, 0x5c, 0x35, 0x8a, 0x34, 0xb2, 0x1a, 0xc2,
+ 0xc4, 0x4b, 0x53, 0x54,
+ };
+ static const unsigned char signature_data_1[] = {
+ 0x01, 0x7b, 0x52, 0x35, 0xe3, 0x51, 0xdd, 0xf1, 0x67, 0x8d, 0x31, 0x5e,
+ 0xa3, 0x75, 0x1f, 0x68, 0x6c, 0xdd, 0x41, 0x7a, 0x18, 0x25, 0xe0, 0x12,
+ 0x6e, 0x84, 0x46, 0x5e, 0xb2, 0x98, 0xd7, 0x84, 0xe1, 0x62, 0xe0, 0xc1,
+ 0xc4, 0xd7, 0x4f, 0x4f, 0x80, 0xc1, 0x92, 0xd6, 0x02, 0xaf, 0xca, 0x28,
+ 0x9f, 0xe0, 0xf3, 0x74, 0xd7, 0xf1, 0x44, 0x67, 0x59, 0x27, 0xc8, 0xc2,
+ 0x8b, 0xd4, 0xe5, 0x4a, 0x07, 0xfd, 0x00, 0xd6, 0x8a, 0xbf, 0x8b, 0xcd,
+ 0x6a, 0xe0, 0x1d, 0xf6, 0x4b, 0x68, 0x0f, 0xcf, 0xb9, 0xd0, 0xa1, 0xbc,
+ 0x2e, 0xcf, 0x7c, 0x03, 0x47, 0x11, 0xe4, 0x4c, 0xbc, 0x1b, 0x6b, 0xa5,
+ 0x2a, 0x82, 0x86, 0xa4, 0x7f, 0x1d, 0x85, 0x64, 0x21, 0x10, 0xd2, 0xb2,
+ 0xa0, 0x31, 0xa2, 0x78, 0xe6, 0xf2, 0xea, 0x96, 0x38, 0x8c, 0x9a, 0xe1,
+ 0x01, 0xab, 0x8e, 0x95, 0x66, 0xc8, 0xe5, 0xcc, 0x80, 0xa3, 0xbd, 0x16,
+ 0xa7, 0x79, 0x19, 0x39, 0x61, 0x3d, 0xff, 0x37, 0xca, 0x9f, 0x97, 0x05,
+ 0xc7, 0xcb, 0xf0, 0xea, 0xaf, 0x64, 0x07, 0xc0, 0xed, 0x2a, 0x98, 0xa4,
+ 0xaf, 0x04, 0x6f, 0xf2, 0xc9, 0xb2, 0x73, 0x9a, 0x56, 0x85, 0x43, 0x64,
+ 0x5f, 0xaa, 0xb7, 0xff, 0x31, 0x4c, 0x2e, 0x6c, 0x17, 0xcf, 0xe5, 0xbe,
+ 0x7f, 0x7e, 0xad, 0xf5, 0x6f, 0x84, 0x50, 0x20, 0x29, 0xb3, 0x57, 0xe7,
+ 0xb1, 0xdc, 0x2c, 0x95, 0x48, 0xfe, 0xb0, 0xc1, 0x92, 0xda, 0xc5, 0x58,
+ 0x95, 0xb0, 0x1a, 0x3a, 0x05, 0x71, 0x3c, 0x6d, 0x20, 0x01, 0x4c, 0xa9,
+ 0xe4, 0x38, 0x08, 0x65, 0xb4, 0xbd, 0x86, 0x76, 0xbd, 0xad, 0x25, 0x06,
+ 0x74, 0x0b, 0xca, 0x95, 0x27, 0x0c, 0x13, 0x08, 0x7e, 0x30, 0xcf, 0xf6,
+ 0xb5, 0xc1, 0x2a, 0x08, 0xfc, 0x4b, 0xc6, 0xb5, 0x2f, 0x23, 0x27, 0x32,
+ 0x89, 0xdb, 0x0e, 0x4a,
+ };
+ static const unsigned char signature_data_2[] = {
+ 0x6d, 0x7d, 0x22, 0x8c, 0x85, 0xc4, 0x8a, 0x80, 0x05, 0xe4, 0x3c, 0xaf,
+ 0x10, 0x3b, 0xe3, 0x51, 0xb1, 0x86, 0x52, 0x63, 0xb6, 0x17, 0x33, 0xbd,
+ 0x1b, 0x1e, 0xc4, 0x50, 0x10, 0xfc, 0xcc, 0xea, 0x6b, 0x11, 0xeb, 0x6d,
+ 0x5e, 0x00, 0xe7, 0xf3, 0x67, 0x99, 0x74, 0x53, 0x12, 0x8f, 0xe4, 0x3e,
+ 0x20, 0x17, 0x8e, 0x83, 0xe6, 0xdc, 0x83, 0x91, 0x0e, 0xf3, 0x69, 0x22,
+ 0x95, 0x14, 0xdf, 0xc1, 0xda, 0xb5, 0xdb, 0x6a, 0x1a, 0xb4, 0x4f, 0x26,
+ 0xd0, 0x32, 0x1d, 0x73, 0x95, 0x1f, 0x39, 0x1d, 0x00, 0xcb, 0xc3, 0x92,
+ 0x49, 0x53, 0xcb, 0x5c, 0x36, 0x70, 0x19, 0xd9, 0x64, 0x36, 0xda, 0xfb,
+ 0x20, 0xe5, 0x47, 0xd9, 0x08, 0xc6, 0x5a, 0x9e, 0x87, 0x1a, 0xdb, 0x11,
+ 0x7b, 0x17, 0xfc, 0x53, 0x7b, 0xc1, 0xa0, 0xc0, 0x33, 0xcf, 0x96, 0xba,
+ 0x03, 0x79, 0x8e, 0xc6, 0x05, 0xd2, 0xb7, 0xa2, 0xe2, 0xc1, 0x67, 0xb7,
+ 0x6a, 0xeb, 0xb1, 0x40, 0xbb, 0x7d, 0x57, 0xcb, 0xc2, 0x60, 0x9f, 0xf1,
+ 0x72, 0xe5, 0xad, 0xce, 0x95, 0x45, 0x7c, 0xbc, 0x75, 0x81, 0x45, 0x19,
+ 0xe1, 0xa7, 0x2f, 0x05, 0x52, 0xeb, 0xed, 0xdd, 0x19, 0xd9, 0x1a, 0xc9,
+ 0x5a, 0x06, 0x8e, 0x29, 0x54, 0xb5, 0x4f, 0x80, 0xaa, 0x36, 0x36, 0xc0,
+ 0xff, 0x64, 0xac, 0xe8, 0x0f, 0x99, 0x35, 0x5e, 0xc6, 0x72, 0x1f, 0x8c,
+ 0xc4, 0x2b, 0x7d, 0xc1, 0xfb, 0xf0, 0x12, 0x61, 0xb1, 0x18, 0x65, 0xdd,
+ 0xc2, 0x38, 0x92, 0xba, 0x84, 0xf8, 0xc8, 0x5e, 0x17, 0x63, 0xe0, 0x9c,
+ 0x2c, 0xe6, 0x70, 0x71, 0xdc, 0xe5, 0xc1, 0xea, 0xb3, 0x9a, 0xb6, 0x91,
+ 0xdc, 0xc5, 0x56, 0x84, 0x8a, 0x31, 0x31, 0x23, 0x61, 0x94, 0x7e, 0x01,
+ 0x22, 0x49, 0xf3, 0xcb, 0x0e, 0x31, 0x03, 0x04, 0x1b, 0x14, 0x43, 0x7c,
+ 0xad, 0x42, 0xe5, 0x55,
+ };
+
+ std::unique_ptr<ProofVerifier> verifier(
+ CryptoTestUtils::RealProofVerifierForTesting());
+
+ const string server_config = "server config bytes";
+ const string hostname = "test.example.com";
+ const uint16_t port = 8443;
+ const string chlo_hash = "proof nonce bytes";
+ const QuicVersion quic_version = GetParam();
+
+ vector<string> certs(2);
+ certs[0] = LoadTestCert("test.example.com.crt");
+ certs[1] = LoadTestCert("intermediate.crt");
+
+ // Signatures are nondeterministic, so we test multiple signatures on the
+ // same server_config.
+ vector<string> signatures(3);
+ signatures[0].assign(reinterpret_cast<const char*>(signature_data_0),
+ sizeof(signature_data_0));
+ signatures[1].assign(reinterpret_cast<const char*>(signature_data_1),
+ sizeof(signature_data_1));
+ signatures[2].assign(reinterpret_cast<const char*>(signature_data_2),
+ sizeof(signature_data_2));
+
+ for (size_t i = 0; i < signatures.size(); i++) {
+ const string& signature = signatures[i];
+
+ RunVerification(verifier.get(), hostname, port, server_config, quic_version,
+ chlo_hash, certs, signature, true);
+ RunVerification(verifier.get(), "foo.com", port, server_config,
+ quic_version, chlo_hash, certs, signature, false);
+ RunVerification(verifier.get(), hostname, port,
+ server_config.substr(1, string::npos), quic_version,
+ chlo_hash, certs, signature, false);
+
+ const string corrupt_signature = "1" + signature;
+ RunVerification(verifier.get(), hostname, port, server_config, quic_version,
+ chlo_hash, certs, corrupt_signature, false);
+
+ vector<string> wrong_certs;
+ for (size_t i = 1; i < certs.size(); i++) {
+ wrong_certs.push_back(certs[i]);
+ }
+ RunVerification(verifier.get(), hostname, port, server_config, quic_version,
+ chlo_hash, wrong_certs, signature, false);
+ }
+}
+
+// A known answer test that allows us to test ProofVerifier without a working
+// ProofSource.
+TEST_P(ProofTest, VerifyECDSAKnownAnswerTest) {
+ if (GetParam() > QUIC_VERSION_30) {
+ return;
+ }
+
+ // These sample signatures were generated by running the Proof.Verify test
+ // (modified to use ECDSA for signing proofs) and dumping the bytes of the
+ // |signature| output of ProofSource::GetProof().
+ static const unsigned char signature_data_0[] = {
+ 0x30, 0x45, 0x02, 0x21, 0x00, 0x89, 0xc4, 0x7d, 0x08, 0xd1, 0x49, 0x19,
+ 0x6c, 0xd1, 0x7c, 0xb9, 0x25, 0xe0, 0xe3, 0xbd, 0x6a, 0x5c, 0xd7, 0xaa,
+ 0x0c, 0xdc, 0x4f, 0x8e, 0xeb, 0xde, 0xbf, 0x32, 0xf8, 0xd1, 0x84, 0x95,
+ 0x97, 0x02, 0x20, 0x29, 0x3d, 0x49, 0x22, 0x73, 0xed, 0x8b, 0xde, 0x3d,
+ 0xc2, 0xa4, 0x20, 0xcc, 0xe7, 0xc8, 0x2a, 0x85, 0x20, 0x9b, 0x5b, 0xda,
+ 0xcd, 0x58, 0x23, 0xbe, 0x89, 0x73, 0x31, 0x87, 0x51, 0xd1, 0x01,
+ };
+ static const unsigned char signature_data_1[] = {
+ 0x30, 0x46, 0x02, 0x21, 0x00, 0xec, 0xdf, 0x69, 0xc8, 0x24, 0x59, 0x93,
+ 0xda, 0x49, 0xee, 0x37, 0x28, 0xaf, 0xeb, 0x0e, 0x2f, 0x80, 0x17, 0x4b,
+ 0x3b, 0xf6, 0x54, 0xcd, 0x3b, 0x86, 0xc5, 0x98, 0x0d, 0xff, 0xc6, 0xb1,
+ 0xe7, 0x02, 0x21, 0x00, 0xe1, 0x36, 0x8c, 0xc0, 0xf4, 0x50, 0x5f, 0xba,
+ 0xfb, 0xe2, 0xff, 0x1d, 0x5d, 0x64, 0xe4, 0x07, 0xbb, 0x5a, 0x4b, 0x19,
+ 0xb6, 0x39, 0x7a, 0xc4, 0x12, 0xc6, 0xe5, 0x42, 0xc8, 0x78, 0x33, 0xcd,
+ };
+ static const unsigned char signature_data_2[] = {
+ 0x30, 0x45, 0x02, 0x20, 0x09, 0x51, 0xe9, 0xde, 0xdb, 0x01, 0xfd, 0xb4,
+ 0xd8, 0x20, 0xbb, 0xad, 0x41, 0xe3, 0xaa, 0xe7, 0xa3, 0xc3, 0x32, 0x10,
+ 0x9d, 0xfa, 0x37, 0xce, 0x17, 0xd1, 0x29, 0xf9, 0xd4, 0x1d, 0x0d, 0x19,
+ 0x02, 0x21, 0x00, 0xc6, 0x20, 0xd4, 0x28, 0xf9, 0x70, 0xb5, 0xb4, 0xff,
+ 0x4a, 0x35, 0xba, 0xa0, 0xf2, 0x8e, 0x00, 0xf7, 0xcb, 0x43, 0xaf, 0x2d,
+ 0x1f, 0xce, 0x92, 0x05, 0xca, 0x29, 0xfe, 0xd2, 0x8f, 0xd9, 0x31,
+ };
+
+ std::unique_ptr<ProofVerifier> verifier(
+ CryptoTestUtils::RealProofVerifierForTesting());
+
+ const string server_config = "server config bytes";
+ const string hostname = "test.example.com";
+ const uint16_t port = 8443;
+ const string chlo_hash = "chlo_hash nonce bytes";
+ const QuicVersion quic_version = GetParam();
+
+ vector<string> certs(2);
+ certs[0] = LoadTestCert("test_ecc.example.com.crt");
+ certs[1] = LoadTestCert("intermediate.crt");
+
+ // Signatures are nondeterministic, so we test multiple signatures on the
+ // same server_config.
+ vector<string> signatures(3);
+ signatures[0].assign(reinterpret_cast<const char*>(signature_data_0),
+ sizeof(signature_data_0));
+ signatures[1].assign(reinterpret_cast<const char*>(signature_data_1),
+ sizeof(signature_data_1));
+ signatures[2].assign(reinterpret_cast<const char*>(signature_data_2),
+ sizeof(signature_data_2));
+
+ for (size_t i = 0; i < signatures.size(); i++) {
+ const string& signature = signatures[i];
+
+ RunVerification(verifier.get(), hostname, port, server_config, quic_version,
+ chlo_hash, certs, signature, true);
+ RunVerification(verifier.get(), "foo.com", port, server_config,
+ quic_version, chlo_hash, certs, signature, false);
+ RunVerification(verifier.get(), hostname, port,
+ server_config.substr(1, string::npos), quic_version,
+ chlo_hash, certs, signature, false);
+
+ // An ECDSA signature is DER-encoded. Corrupt the last byte so that the
+ // signature can still be DER-decoded correctly.
+ string corrupt_signature = signature;
+ corrupt_signature.back()++;
+ RunVerification(verifier.get(), hostname, port, server_config, quic_version,
+ chlo_hash, certs, corrupt_signature, false);
+
+ // Prepending a "1" makes the DER invalid.
+ const string bad_der_signature1 = "1" + signature;
+ RunVerification(verifier.get(), hostname, port, server_config, quic_version,
+ chlo_hash, certs, bad_der_signature1, false);
+
+ vector<string> wrong_certs;
+ for (size_t i = 1; i < certs.size(); i++) {
+ wrong_certs.push_back(certs[i]);
+ }
+ RunVerification(verifier.get(), hostname, port, server_config, quic_version,
+ chlo_hash, wrong_certs, signature, false);
+ }
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/chromium/crypto/proof_verifier_chromium.cc b/chromium/net/quic/chromium/crypto/proof_verifier_chromium.cc
new file mode 100644
index 00000000000..0be468bb491
--- /dev/null
+++ b/chromium/net/quic/chromium/crypto/proof_verifier_chromium.cc
@@ -0,0 +1,625 @@
+// Copyright 2013 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/chromium/crypto/proof_verifier_chromium.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "crypto/signature_verifier.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/net_errors.h"
+#include "net/cert/asn1_util.h"
+#include "net/cert/cert_status_flags.h"
+#include "net/cert/cert_verifier.h"
+#include "net/cert/ct_policy_enforcer.h"
+#include "net/cert/ct_policy_status.h"
+#include "net/cert/ct_verifier.h"
+#include "net/cert/x509_util.h"
+#include "net/http/transport_security_state.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/ssl/ssl_config_service.h"
+
+using base::StringPiece;
+using base::StringPrintf;
+using std::string;
+using std::vector;
+
+namespace net {
+
+ProofVerifyDetailsChromium::ProofVerifyDetailsChromium()
+ : pkp_bypassed(false) {}
+
+ProofVerifyDetailsChromium::~ProofVerifyDetailsChromium() {}
+
+ProofVerifyDetailsChromium::ProofVerifyDetailsChromium(
+ const ProofVerifyDetailsChromium&) = default;
+
+ProofVerifyDetails* ProofVerifyDetailsChromium::Clone() const {
+ ProofVerifyDetailsChromium* other = new ProofVerifyDetailsChromium;
+ other->cert_verify_result = cert_verify_result;
+ other->ct_verify_result = ct_verify_result;
+ return other;
+}
+
+// A Job handles the verification of a single proof. It is owned by the
+// ProofVerifier. If the verification can not complete synchronously, it
+// will notify the ProofVerifier upon completion.
+class ProofVerifierChromium::Job {
+ public:
+ Job(ProofVerifierChromium* proof_verifier,
+ CertVerifier* cert_verifier,
+ CTPolicyEnforcer* ct_policy_enforcer,
+ TransportSecurityState* transport_security_state,
+ CTVerifier* cert_transparency_verifier,
+ int cert_verify_flags,
+ const NetLogWithSource& net_log);
+ ~Job();
+
+ // Starts the proof verification. If |QUIC_PENDING| is returned, then
+ // |callback| will be invoked asynchronously when the verification completes.
+ QuicAsyncStatus VerifyProof(
+ const std::string& hostname,
+ const uint16_t port,
+ const std::string& server_config,
+ QuicVersion quic_version,
+ base::StringPiece chlo_hash,
+ const std::vector<std::string>& certs,
+ const std::string& cert_sct,
+ const std::string& signature,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details,
+ std::unique_ptr<ProofVerifierCallback> callback);
+
+ // Starts the certificate chain verification of |certs|. If |QUIC_PENDING| is
+ // returned, then |callback| will be invoked asynchronously when the
+ // verification completes.
+ QuicAsyncStatus VerifyCertChain(
+ const std::string& hostname,
+ const std::vector<std::string>& certs,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details,
+ std::unique_ptr<ProofVerifierCallback> callback);
+
+ private:
+ enum State {
+ STATE_NONE,
+ STATE_VERIFY_CERT,
+ STATE_VERIFY_CERT_COMPLETE,
+ };
+
+ // Convert |certs| to |cert_|(X509Certificate). Returns true if successful.
+ bool GetX509Certificate(const vector<string>& certs,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details);
+
+ // Start the cert verification.
+ QuicAsyncStatus VerifyCert(
+ const string& hostname,
+ const uint16_t port,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details,
+ std::unique_ptr<ProofVerifierCallback> callback);
+
+ int DoLoop(int last_io_result);
+ void OnIOComplete(int result);
+ int DoVerifyCert(int result);
+ int DoVerifyCertComplete(int result);
+
+ bool VerifySignature(const std::string& signed_data,
+ QuicVersion quic_version,
+ StringPiece chlo_hash,
+ const std::string& signature,
+ const std::string& cert);
+
+ // Proof verifier to notify when this jobs completes.
+ ProofVerifierChromium* proof_verifier_;
+
+ // The underlying verifier used for verifying certificates.
+ CertVerifier* verifier_;
+ std::unique_ptr<CertVerifier::Request> cert_verifier_request_;
+
+ CTPolicyEnforcer* policy_enforcer_;
+
+ TransportSecurityState* transport_security_state_;
+
+ CTVerifier* cert_transparency_verifier_;
+
+ // |hostname| specifies the hostname for which |certs| is a valid chain.
+ std::string hostname_;
+ // |port| specifies the target port for the connection.
+ uint16_t port_;
+
+ std::unique_ptr<ProofVerifierCallback> callback_;
+ std::unique_ptr<ProofVerifyDetailsChromium> verify_details_;
+ std::string error_details_;
+
+ // X509Certificate from a chain of DER encoded certificates.
+ scoped_refptr<X509Certificate> cert_;
+
+ // |cert_verify_flags| is bitwise OR'd of CertVerifier::VerifyFlags and it is
+ // passed to CertVerifier::Verify.
+ int cert_verify_flags_;
+
+ // If set to true, enforces policy checking in DoVerifyCertComplete().
+ bool enforce_policy_checking_;
+
+ State next_state_;
+
+ base::TimeTicks start_time_;
+
+ NetLogWithSource net_log_;
+
+ DISALLOW_COPY_AND_ASSIGN(Job);
+};
+
+ProofVerifierChromium::Job::Job(
+ ProofVerifierChromium* proof_verifier,
+ CertVerifier* cert_verifier,
+ CTPolicyEnforcer* ct_policy_enforcer,
+ TransportSecurityState* transport_security_state,
+ CTVerifier* cert_transparency_verifier,
+ int cert_verify_flags,
+ const NetLogWithSource& net_log)
+ : proof_verifier_(proof_verifier),
+ verifier_(cert_verifier),
+ policy_enforcer_(ct_policy_enforcer),
+ transport_security_state_(transport_security_state),
+ cert_transparency_verifier_(cert_transparency_verifier),
+ cert_verify_flags_(cert_verify_flags),
+ enforce_policy_checking_(true),
+ next_state_(STATE_NONE),
+ start_time_(base::TimeTicks::Now()),
+ net_log_(net_log) {
+ CHECK(proof_verifier_);
+ CHECK(verifier_);
+ CHECK(policy_enforcer_);
+ CHECK(transport_security_state_);
+ CHECK(cert_transparency_verifier_);
+}
+
+ProofVerifierChromium::Job::~Job() {
+ base::TimeTicks end_time = base::TimeTicks::Now();
+ UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime",
+ end_time - start_time_);
+ // |hostname_| will always be canonicalized to lowercase.
+ if (hostname_.compare("www.google.com") == 0) {
+ UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime.google",
+ end_time - start_time_);
+ }
+}
+
+QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof(
+ const string& hostname,
+ const uint16_t port,
+ const string& server_config,
+ QuicVersion quic_version,
+ StringPiece chlo_hash,
+ const vector<string>& certs,
+ const std::string& cert_sct,
+ const string& signature,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details,
+ std::unique_ptr<ProofVerifierCallback> callback) {
+ DCHECK(error_details);
+ DCHECK(verify_details);
+ DCHECK(callback);
+
+ error_details->clear();
+
+ if (STATE_NONE != next_state_) {
+ *error_details = "Certificate is already set and VerifyProof has begun";
+ DLOG(DFATAL) << *error_details;
+ return QUIC_FAILURE;
+ }
+
+ verify_details_.reset(new ProofVerifyDetailsChromium);
+
+ // Converts |certs| to |cert_|.
+ if (!GetX509Certificate(certs, error_details, verify_details))
+ return QUIC_FAILURE;
+
+ if (!cert_sct.empty()) {
+ // 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,
+ net_log_);
+ }
+
+ // We call VerifySignature first to avoid copying of server_config and
+ // signature.
+ if (!signature.empty() &&
+ !VerifySignature(server_config, quic_version, chlo_hash, signature,
+ certs[0])) {
+ *error_details = "Failed to verify signature of server config";
+ DLOG(WARNING) << *error_details;
+ verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
+ *verify_details = std::move(verify_details_);
+ return QUIC_FAILURE;
+ }
+
+ DCHECK(enforce_policy_checking_);
+ return VerifyCert(hostname, port, error_details, verify_details,
+ std::move(callback));
+}
+
+QuicAsyncStatus ProofVerifierChromium::Job::VerifyCertChain(
+ const string& hostname,
+ const vector<string>& certs,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details,
+ std::unique_ptr<ProofVerifierCallback> callback) {
+ DCHECK(error_details);
+ DCHECK(verify_details);
+ DCHECK(callback);
+
+ error_details->clear();
+
+ if (STATE_NONE != next_state_) {
+ *error_details = "Certificate is already set and VerifyCertChain has begun";
+ DLOG(DFATAL) << *error_details;
+ return QUIC_FAILURE;
+ }
+
+ verify_details_.reset(new ProofVerifyDetailsChromium);
+
+ // Converts |certs| to |cert_|.
+ if (!GetX509Certificate(certs, error_details, verify_details))
+ return QUIC_FAILURE;
+
+ enforce_policy_checking_ = false;
+ // |port| is not needed because |enforce_policy_checking_| is false.
+ return VerifyCert(hostname, /*port=*/0, error_details, verify_details,
+ std::move(callback));
+}
+
+bool ProofVerifierChromium::Job::GetX509Certificate(
+ const vector<string>& certs,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details) {
+ if (certs.empty()) {
+ *error_details = "Failed to create certificate chain. Certs are empty.";
+ DLOG(WARNING) << *error_details;
+ verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
+ *verify_details = std::move(verify_details_);
+ return false;
+ }
+
+ // Convert certs to X509Certificate.
+ vector<StringPiece> cert_pieces(certs.size());
+ for (unsigned i = 0; i < certs.size(); i++) {
+ cert_pieces[i] = base::StringPiece(certs[i]);
+ }
+ cert_ = X509Certificate::CreateFromDERCertChain(cert_pieces);
+ if (!cert_.get()) {
+ *error_details = "Failed to create certificate chain";
+ DLOG(WARNING) << *error_details;
+ verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
+ *verify_details = std::move(verify_details_);
+ return false;
+ }
+ return true;
+}
+
+QuicAsyncStatus ProofVerifierChromium::Job::VerifyCert(
+ const string& hostname,
+ const uint16_t port,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details,
+ std::unique_ptr<ProofVerifierCallback> callback) {
+ hostname_ = hostname;
+ port_ = port;
+
+ next_state_ = STATE_VERIFY_CERT;
+ switch (DoLoop(OK)) {
+ case OK:
+ *verify_details = std::move(verify_details_);
+ return QUIC_SUCCESS;
+ case ERR_IO_PENDING:
+ callback_ = std::move(callback);
+ return QUIC_PENDING;
+ default:
+ *error_details = error_details_;
+ *verify_details = std::move(verify_details_);
+ return QUIC_FAILURE;
+ }
+}
+
+int ProofVerifierChromium::Job::DoLoop(int last_result) {
+ int rv = last_result;
+ do {
+ State state = next_state_;
+ next_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_VERIFY_CERT:
+ DCHECK(rv == OK);
+ rv = DoVerifyCert(rv);
+ break;
+ case STATE_VERIFY_CERT_COMPLETE:
+ rv = DoVerifyCertComplete(rv);
+ break;
+ case STATE_NONE:
+ default:
+ rv = ERR_UNEXPECTED;
+ LOG(DFATAL) << "unexpected state " << state;
+ break;
+ }
+ } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
+ return rv;
+}
+
+void ProofVerifierChromium::Job::OnIOComplete(int result) {
+ int rv = DoLoop(result);
+ if (rv != ERR_IO_PENDING) {
+ std::unique_ptr<ProofVerifierCallback> callback(std::move(callback_));
+ // Callback expects ProofVerifyDetails not ProofVerifyDetailsChromium.
+ std::unique_ptr<ProofVerifyDetails> verify_details(
+ std::move(verify_details_));
+ callback->Run(rv == OK, error_details_, &verify_details);
+ // Will delete |this|.
+ proof_verifier_->OnJobComplete(this);
+ }
+}
+
+int ProofVerifierChromium::Job::DoVerifyCert(int result) {
+ next_state_ = STATE_VERIFY_CERT_COMPLETE;
+
+ return verifier_->Verify(
+ CertVerifier::RequestParams(cert_, hostname_, cert_verify_flags_,
+ std::string(), CertificateList()),
+ SSLConfigService::GetCRLSet().get(), &verify_details_->cert_verify_result,
+ base::Bind(&ProofVerifierChromium::Job::OnIOComplete,
+ base::Unretained(this)),
+ &cert_verifier_request_, net_log_);
+}
+
+int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) {
+ cert_verifier_request_.reset();
+
+ const CertVerifyResult& cert_verify_result =
+ verify_details_->cert_verify_result;
+ const CertStatus cert_status = cert_verify_result.cert_status;
+ verify_details_->ct_verify_result.ct_policies_applied = result == OK;
+ verify_details_->ct_verify_result.ev_policy_compliance =
+ ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY;
+
+ // If the connection was good, check HPKP and CT status simultaneously,
+ // but prefer to treat the HPKP error as more serious, if there was one.
+ if (enforce_policy_checking_ &&
+ (result == OK ||
+ (IsCertificateError(result) && IsCertStatusMinorError(cert_status)))) {
+ SCTList verified_scts = ct::SCTsMatchingStatus(
+ verify_details_->ct_verify_result.scts, ct::SCT_STATUS_OK);
+ if ((cert_verify_result.cert_status & CERT_STATUS_IS_EV)) {
+ ct::EVPolicyCompliance ev_policy_compliance =
+ policy_enforcer_->DoesConformToCTEVPolicy(
+ cert_verify_result.verified_cert.get(),
+ SSLConfigService::GetEVCertsWhitelist().get(), verified_scts,
+ net_log_);
+ verify_details_->ct_verify_result.ev_policy_compliance =
+ ev_policy_compliance;
+ if (ev_policy_compliance !=
+ ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY &&
+ ev_policy_compliance !=
+ ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST &&
+ ev_policy_compliance !=
+ ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS) {
+ verify_details_->cert_verify_result.cert_status |=
+ CERT_STATUS_CT_COMPLIANCE_FAILED;
+ verify_details_->cert_verify_result.cert_status &= ~CERT_STATUS_IS_EV;
+ }
+ }
+
+ verify_details_->ct_verify_result.cert_policy_compliance =
+ policy_enforcer_->DoesConformToCertPolicy(
+ cert_verify_result.verified_cert.get(), verified_scts, net_log_);
+
+ int ct_result = OK;
+ if (verify_details_->ct_verify_result.cert_policy_compliance !=
+ ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS &&
+ verify_details_->ct_verify_result.cert_policy_compliance !=
+ ct::CertPolicyCompliance::CERT_POLICY_BUILD_NOT_TIMELY &&
+ transport_security_state_->ShouldRequireCT(
+ hostname_, cert_verify_result.verified_cert.get(),
+ cert_verify_result.public_key_hashes)) {
+ verify_details_->cert_verify_result.cert_status |=
+ CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED;
+ ct_result = ERR_CERTIFICATE_TRANSPARENCY_REQUIRED;
+ }
+
+ TransportSecurityState::PKPStatus pin_validity =
+ transport_security_state_->CheckPublicKeyPins(
+ HostPortPair(hostname_, port_),
+ cert_verify_result.is_issued_by_known_root,
+ cert_verify_result.public_key_hashes, cert_.get(),
+ cert_verify_result.verified_cert.get(),
+ TransportSecurityState::ENABLE_PIN_REPORTS,
+ &verify_details_->pinning_failure_log);
+ switch (pin_validity) {
+ case TransportSecurityState::PKPStatus::VIOLATED:
+ result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
+ verify_details_->cert_verify_result.cert_status |=
+ CERT_STATUS_PINNED_KEY_MISSING;
+ break;
+ case TransportSecurityState::PKPStatus::BYPASSED:
+ verify_details_->pkp_bypassed = true;
+ // Fall through.
+ case TransportSecurityState::PKPStatus::OK:
+ // Do nothing.
+ break;
+ }
+ if (result != ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN && ct_result != OK)
+ result = ct_result;
+ }
+
+ if (result != OK) {
+ std::string error_string = ErrorToString(result);
+ error_details_ = StringPrintf("Failed to verify certificate chain: %s",
+ error_string.c_str());
+ DLOG(WARNING) << error_details_;
+ }
+
+ // Exit DoLoop and return the result to the caller to VerifyProof.
+ DCHECK_EQ(STATE_NONE, next_state_);
+ return result;
+}
+
+bool ProofVerifierChromium::Job::VerifySignature(const string& signed_data,
+ QuicVersion quic_version,
+ StringPiece chlo_hash,
+ const string& signature,
+ const string& cert) {
+ StringPiece spki;
+ if (!asn1::ExtractSPKIFromDERCert(cert, &spki)) {
+ DLOG(WARNING) << "ExtractSPKIFromDERCert failed";
+ return false;
+ }
+
+ crypto::SignatureVerifier verifier;
+
+ size_t size_bits;
+ X509Certificate::PublicKeyType type;
+ X509Certificate::GetPublicKeyInfo(cert_->os_cert_handle(), &size_bits, &type);
+ if (type == X509Certificate::kPublicKeyTypeRSA) {
+ crypto::SignatureVerifier::HashAlgorithm hash_alg =
+ crypto::SignatureVerifier::SHA256;
+ crypto::SignatureVerifier::HashAlgorithm mask_hash_alg = hash_alg;
+ unsigned int hash_len = 32; // 32 is the length of a SHA-256 hash.
+
+ bool ok = verifier.VerifyInitRSAPSS(
+ hash_alg, mask_hash_alg, hash_len,
+ reinterpret_cast<const uint8_t*>(signature.data()), signature.size(),
+ reinterpret_cast<const uint8_t*>(spki.data()), spki.size());
+ if (!ok) {
+ DLOG(WARNING) << "VerifyInitRSAPSS failed";
+ return false;
+ }
+ } else if (type == X509Certificate::kPublicKeyTypeECDSA) {
+ if (!verifier.VerifyInit(crypto::SignatureVerifier::ECDSA_SHA256,
+ reinterpret_cast<const uint8_t*>(signature.data()),
+ signature.size(),
+ reinterpret_cast<const uint8_t*>(spki.data()),
+ spki.size())) {
+ DLOG(WARNING) << "VerifyInit failed";
+ return false;
+ }
+ } else {
+ LOG(ERROR) << "Unsupported public key type " << type;
+ return false;
+ }
+
+ if (quic_version <= QUIC_VERSION_30) {
+ verifier.VerifyUpdate(
+ reinterpret_cast<const uint8_t*>(kProofSignatureLabelOld),
+ sizeof(kProofSignatureLabelOld));
+ } else {
+ verifier.VerifyUpdate(
+ reinterpret_cast<const uint8_t*>(kProofSignatureLabel),
+ sizeof(kProofSignatureLabel));
+ uint32_t len = chlo_hash.length();
+ verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(&len), sizeof(len));
+ verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(chlo_hash.data()),
+ len);
+ }
+
+ verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(signed_data.data()),
+ signed_data.size());
+
+ if (!verifier.VerifyFinal()) {
+ DLOG(WARNING) << "VerifyFinal failed";
+ return false;
+ }
+
+ DVLOG(1) << "VerifyFinal success";
+ return true;
+}
+
+ProofVerifierChromium::ProofVerifierChromium(
+ CertVerifier* cert_verifier,
+ CTPolicyEnforcer* ct_policy_enforcer,
+ TransportSecurityState* transport_security_state,
+ CTVerifier* cert_transparency_verifier)
+ : cert_verifier_(cert_verifier),
+ ct_policy_enforcer_(ct_policy_enforcer),
+ transport_security_state_(transport_security_state),
+ cert_transparency_verifier_(cert_transparency_verifier) {
+ DCHECK(cert_verifier_);
+ DCHECK(ct_policy_enforcer_);
+ DCHECK(transport_security_state_);
+ DCHECK(cert_transparency_verifier_);
+}
+
+ProofVerifierChromium::~ProofVerifierChromium() {
+ base::STLDeleteElements(&active_jobs_);
+}
+
+QuicAsyncStatus ProofVerifierChromium::VerifyProof(
+ const std::string& hostname,
+ const uint16_t port,
+ const std::string& server_config,
+ QuicVersion quic_version,
+ base::StringPiece chlo_hash,
+ const std::vector<std::string>& certs,
+ const std::string& cert_sct,
+ const std::string& signature,
+ const ProofVerifyContext* verify_context,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details,
+ std::unique_ptr<ProofVerifierCallback> callback) {
+ if (!verify_context) {
+ *error_details = "Missing context";
+ return QUIC_FAILURE;
+ }
+ const ProofVerifyContextChromium* chromium_context =
+ reinterpret_cast<const ProofVerifyContextChromium*>(verify_context);
+ std::unique_ptr<Job> job(
+ new Job(this, cert_verifier_, ct_policy_enforcer_,
+ transport_security_state_, cert_transparency_verifier_,
+ chromium_context->cert_verify_flags, chromium_context->net_log));
+ QuicAsyncStatus status = job->VerifyProof(
+ hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct,
+ signature, error_details, verify_details, std::move(callback));
+ if (status == QUIC_PENDING)
+ active_jobs_.insert(job.release());
+ return status;
+}
+
+QuicAsyncStatus ProofVerifierChromium::VerifyCertChain(
+ const std::string& hostname,
+ const std::vector<std::string>& certs,
+ const ProofVerifyContext* verify_context,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details,
+ std::unique_ptr<ProofVerifierCallback> callback) {
+ if (!verify_context) {
+ *error_details = "Missing context";
+ return QUIC_FAILURE;
+ }
+ const ProofVerifyContextChromium* chromium_context =
+ reinterpret_cast<const ProofVerifyContextChromium*>(verify_context);
+ std::unique_ptr<Job> job(
+ new Job(this, cert_verifier_, ct_policy_enforcer_,
+ transport_security_state_, cert_transparency_verifier_,
+ chromium_context->cert_verify_flags, chromium_context->net_log));
+ QuicAsyncStatus status = job->VerifyCertChain(
+ hostname, certs, error_details, verify_details, std::move(callback));
+ if (status == QUIC_PENDING)
+ active_jobs_.insert(job.release());
+ return status;
+}
+
+void ProofVerifierChromium::OnJobComplete(Job* job) {
+ active_jobs_.erase(job);
+ delete job;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/chromium/crypto/proof_verifier_chromium.h b/chromium/net/quic/chromium/crypto/proof_verifier_chromium.h
new file mode 100644
index 00000000000..4eb1bdf0718
--- /dev/null
+++ b/chromium/net/quic/chromium/crypto/proof_verifier_chromium.h
@@ -0,0 +1,118 @@
+// Copyright 2013 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_CRYPTO_PROOF_VERIFIER_CHROMIUM_H_
+#define NET_QUIC_CRYPTO_PROOF_VERIFIER_CHROMIUM_H_
+
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/cert/cert_verify_result.h"
+#include "net/cert/ct_verify_result.h"
+#include "net/cert/x509_certificate.h"
+#include "net/log/net_log_with_source.h"
+#include "net/quic/core/crypto/proof_verifier.h"
+
+namespace net {
+
+class CTPolicyEnforcer;
+class CertVerifier;
+class CTVerifier;
+class TransportSecurityState;
+
+// ProofVerifyDetailsChromium is the implementation-specific information that a
+// ProofVerifierChromium returns about a certificate verification.
+class NET_EXPORT_PRIVATE ProofVerifyDetailsChromium
+ : public ProofVerifyDetails {
+ public:
+ ProofVerifyDetailsChromium();
+ ProofVerifyDetailsChromium(const ProofVerifyDetailsChromium&);
+ ~ProofVerifyDetailsChromium() override;
+
+ // ProofVerifyDetails implementation
+ ProofVerifyDetails* Clone() const override;
+
+ CertVerifyResult cert_verify_result;
+ ct::CTVerifyResult ct_verify_result;
+
+ // pinning_failure_log contains a message produced by
+ // TransportSecurityState::PKPState::CheckPublicKeyPins in the event of a
+ // pinning failure. It is a (somewhat) human-readable string.
+ std::string pinning_failure_log;
+
+ // True if PKP was bypassed due to a local trust anchor.
+ bool pkp_bypassed;
+};
+
+// ProofVerifyContextChromium is the implementation-specific information that a
+// ProofVerifierChromium needs in order to log correctly.
+struct ProofVerifyContextChromium : public ProofVerifyContext {
+ public:
+ ProofVerifyContextChromium(int cert_verify_flags,
+ const NetLogWithSource& net_log)
+ : cert_verify_flags(cert_verify_flags), net_log(net_log) {}
+
+ int cert_verify_flags;
+ NetLogWithSource net_log;
+};
+
+// ProofVerifierChromium implements the QUIC ProofVerifier interface. It is
+// capable of handling multiple simultaneous requests.
+class NET_EXPORT_PRIVATE ProofVerifierChromium : public ProofVerifier {
+ public:
+ ProofVerifierChromium(CertVerifier* cert_verifier,
+ CTPolicyEnforcer* ct_policy_enforcer,
+ TransportSecurityState* transport_security_state,
+ CTVerifier* cert_transparency_verifier);
+ ~ProofVerifierChromium() override;
+
+ // ProofVerifier interface
+ QuicAsyncStatus VerifyProof(
+ const std::string& hostname,
+ const uint16_t port,
+ const std::string& server_config,
+ QuicVersion quic_version,
+ base::StringPiece chlo_hash,
+ const std::vector<std::string>& certs,
+ const std::string& cert_sct,
+ const std::string& signature,
+ const ProofVerifyContext* verify_context,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details,
+ std::unique_ptr<ProofVerifierCallback> callback) override;
+ QuicAsyncStatus VerifyCertChain(
+ const std::string& hostname,
+ const std::vector<std::string>& certs,
+ const ProofVerifyContext* verify_context,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details,
+ std::unique_ptr<ProofVerifierCallback> callback) override;
+
+ private:
+ class Job;
+ typedef std::set<Job*> JobSet;
+
+ void OnJobComplete(Job* job);
+
+ // Set owning pointers to active jobs.
+ JobSet active_jobs_;
+
+ // Underlying verifier used to verify certificates.
+ CertVerifier* const cert_verifier_;
+ CTPolicyEnforcer* const ct_policy_enforcer_;
+
+ TransportSecurityState* const transport_security_state_;
+ CTVerifier* const cert_transparency_verifier_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProofVerifierChromium);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_PROOF_VERIFIER_CHROMIUM_H_
diff --git a/chromium/net/quic/chromium/crypto/proof_verifier_chromium_test.cc b/chromium/net/quic/chromium/crypto/proof_verifier_chromium_test.cc
new file mode 100644
index 00000000000..1488f02cacd
--- /dev/null
+++ b/chromium/net/quic/chromium/crypto/proof_verifier_chromium_test.cc
@@ -0,0 +1,622 @@
+// Copyright 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.
+
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+
+#include "base/memory/ref_counted.h"
+#include "net/base/net_errors.h"
+#include "net/cert/cert_status_flags.h"
+#include "net/cert/cert_verifier.h"
+#include "net/cert/ct_log_verifier.h"
+#include "net/cert/ct_policy_enforcer.h"
+#include "net/cert/ct_policy_status.h"
+#include "net/cert/ct_serialization.h"
+#include "net/cert/mock_cert_verifier.h"
+#include "net/cert/multi_log_ct_verifier.h"
+#include "net/http/transport_security_state.h"
+#include "net/quic/core/crypto/proof_verifier.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/ct_test_util.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace net {
+namespace test {
+
+namespace {
+
+// CertVerifier that will fail the test if it is ever called.
+class FailsTestCertVerifier : public CertVerifier {
+ public:
+ FailsTestCertVerifier() {}
+ ~FailsTestCertVerifier() override {}
+
+ // CertVerifier implementation
+ int Verify(const RequestParams& params,
+ CRLSet* crl_set,
+ CertVerifyResult* verify_result,
+ const CompletionCallback& callback,
+ std::unique_ptr<Request>* out_req,
+ const NetLogWithSource& net_log) override {
+ ADD_FAILURE() << "CertVerifier::Verify() should not be called";
+ return ERR_FAILED;
+ }
+};
+
+// CTPolicyEnforcer that will fail the test if it is ever called.
+class FailsTestCTPolicyEnforcer : public CTPolicyEnforcer {
+ public:
+ FailsTestCTPolicyEnforcer() {}
+ ~FailsTestCTPolicyEnforcer() override {}
+
+ ct::EVPolicyCompliance DoesConformToCTEVPolicy(
+ X509Certificate* cert,
+ const ct::EVCertsWhitelist* ev_whitelist,
+ const ct::SCTList& verified_scts,
+ const NetLogWithSource& net_log) override {
+ ADD_FAILURE() << "CTPolicyEnforcer::DoesConformToCTEVPolicy() should "
+ << "not be called";
+ return ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY;
+ }
+};
+
+// A mock CTPolicyEnforcer that returns a custom verification result.
+class MockCTPolicyEnforcer : public CTPolicyEnforcer {
+ public:
+ MOCK_METHOD3(DoesConformToCertPolicy,
+ ct::CertPolicyCompliance(X509Certificate* cert,
+ const ct::SCTList&,
+ const NetLogWithSource&));
+ MOCK_METHOD4(DoesConformToCTEVPolicy,
+ ct::EVPolicyCompliance(X509Certificate* cert,
+ const ct::EVCertsWhitelist*,
+ const ct::SCTList&,
+ const NetLogWithSource&));
+};
+
+class MockRequireCTDelegate : public TransportSecurityState::RequireCTDelegate {
+ public:
+ MOCK_METHOD1(IsCTRequiredForHost,
+ CTRequirementLevel(const std::string& host));
+};
+
+class DummyProofVerifierCallback : public ProofVerifierCallback {
+ public:
+ DummyProofVerifierCallback() {}
+ ~DummyProofVerifierCallback() override {}
+
+ void Run(bool ok,
+ const std::string& error_details,
+ std::unique_ptr<ProofVerifyDetails>* details) override {
+ // Do nothing
+ }
+};
+
+const char kTestHostname[] = "test.example.com";
+const uint16_t kTestPort = 8443;
+const char kTestConfig[] = "server config bytes";
+const char kLogDescription[] = "somelog";
+
+} // namespace
+
+class ProofVerifierChromiumTest : public ::testing::Test {
+ public:
+ ProofVerifierChromiumTest()
+ : verify_context_(new ProofVerifyContextChromium(0 /*cert_verify_flags*/,
+ NetLogWithSource())) {}
+
+ void SetUp() override {
+ EXPECT_CALL(ct_policy_enforcer_, DoesConformToCertPolicy(_, _, _))
+ .WillRepeatedly(
+ Return(ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS));
+ EXPECT_CALL(ct_policy_enforcer_, DoesConformToCTEVPolicy(_, _, _, _))
+ .WillRepeatedly(
+ Return(ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY));
+
+ scoped_refptr<const CTLogVerifier> log(
+ CTLogVerifier::Create(ct::GetTestPublicKey(), kLogDescription,
+ "https://test.example.com", "dns.example.com"));
+ ASSERT_TRUE(log);
+ log_verifiers_.push_back(log);
+
+ ct_verifier_.reset(new MultiLogCTVerifier());
+ ct_verifier_->AddLogs(log_verifiers_);
+
+ ASSERT_NO_FATAL_FAILURE(GetTestCertificates(&certs_));
+ }
+
+ scoped_refptr<X509Certificate> GetTestServerCertificate() {
+ static const char kTestCert[] = "quic_test.example.com.crt";
+ return ImportCertFromFile(GetTestCertsDirectory(), kTestCert);
+ }
+
+ void GetTestCertificates(std::vector<std::string>* certs) {
+ 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);
+ }
+
+ std::string GetTestSignature() {
+ // Sample known answer test from ProofTest.VerifyRSAKnownAnswerTest.
+ // Generated by dumping the bytes of the |signature| output of
+ // ProofSource::GetProof().
+ static const unsigned char kTestSignature[] = {
+ 0x31, 0xd5, 0xfb, 0x40, 0x30, 0x75, 0xd2, 0x7d, 0x61, 0xf9, 0xd7, 0x54,
+ 0x30, 0x06, 0xaf, 0x54, 0x0d, 0xb0, 0x0a, 0xda, 0x63, 0xca, 0x7e, 0x9e,
+ 0xce, 0xba, 0x10, 0x05, 0x1b, 0xa6, 0x7f, 0xef, 0x2b, 0xa3, 0xff, 0x3c,
+ 0xbb, 0x9a, 0xe4, 0xbf, 0xb8, 0x0c, 0xc1, 0xbd, 0xed, 0xc2, 0x90, 0x68,
+ 0xeb, 0x45, 0x48, 0xea, 0x3c, 0x95, 0xf8, 0xa2, 0xb9, 0xe7, 0x62, 0x29,
+ 0x00, 0xc3, 0x18, 0xb4, 0x16, 0x6f, 0x5e, 0xb0, 0xc1, 0x26, 0xc0, 0x4b,
+ 0x84, 0xf5, 0x97, 0xfc, 0x17, 0xf9, 0x1c, 0x43, 0xb8, 0xf2, 0x3f, 0x38,
+ 0x32, 0xad, 0x36, 0x52, 0x2c, 0x26, 0x92, 0x7a, 0xea, 0x2c, 0xa2, 0xf4,
+ 0x28, 0x2f, 0x19, 0x4d, 0x1f, 0x11, 0x46, 0x82, 0xd0, 0xc4, 0x86, 0x56,
+ 0x5c, 0x97, 0x9e, 0xc6, 0x37, 0x8e, 0xaf, 0x9d, 0x69, 0xe9, 0x4f, 0x5a,
+ 0x6d, 0x70, 0x75, 0xc7, 0x41, 0x95, 0x68, 0x53, 0x94, 0xca, 0x31, 0x63,
+ 0x61, 0x9f, 0xb8, 0x8c, 0x3b, 0x75, 0x36, 0x8b, 0x69, 0xa2, 0x35, 0xc0,
+ 0x4b, 0x77, 0x55, 0x08, 0xc2, 0xb4, 0x56, 0xd2, 0x81, 0xce, 0x9e, 0x25,
+ 0xdb, 0x50, 0x74, 0xb3, 0x8a, 0xd9, 0x20, 0x42, 0x3f, 0x85, 0x2d, 0xaa,
+ 0xfd, 0x66, 0xfa, 0xd6, 0x95, 0x55, 0x6b, 0x63, 0x63, 0x04, 0xf8, 0x6c,
+ 0x3e, 0x08, 0x22, 0x39, 0xb9, 0x9a, 0xe0, 0xd7, 0x01, 0xff, 0xeb, 0x8a,
+ 0xb9, 0xe2, 0x34, 0xa5, 0xa0, 0x51, 0xe9, 0xbe, 0x15, 0x12, 0xbf, 0xbe,
+ 0x64, 0x3d, 0x3f, 0x98, 0xce, 0xc1, 0xa6, 0x33, 0x32, 0xd3, 0x5c, 0xa8,
+ 0x39, 0x93, 0xdc, 0x1c, 0xb9, 0xab, 0x3c, 0x80, 0x62, 0xb3, 0x76, 0x21,
+ 0xdf, 0x47, 0x1e, 0xa9, 0x0e, 0x5e, 0x8a, 0xbe, 0x66, 0x5b, 0x7c, 0x21,
+ 0xfa, 0x78, 0x2d, 0xd1, 0x1d, 0x5c, 0x35, 0x8a, 0x34, 0xb2, 0x1a, 0xc2,
+ 0xc4, 0x4b, 0x53, 0x54,
+ };
+ return std::string(reinterpret_cast<const char*>(kTestSignature),
+ sizeof(kTestSignature));
+ }
+
+ void GetSCTTestCertificates(std::vector<std::string>* certs) {
+ std::string der_test_cert(ct::GetDerEncodedX509Cert());
+ scoped_refptr<X509Certificate> test_cert = X509Certificate::CreateFromBytes(
+ 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);
+ }
+
+ void CheckSCT(bool sct_expected_ok) {
+ ProofVerifyDetailsChromium* proof_details =
+ reinterpret_cast<ProofVerifyDetailsChromium*>(details_.get());
+ const ct::CTVerifyResult& ct_verify_result =
+ proof_details->ct_verify_result;
+ if (sct_expected_ok) {
+ ASSERT_TRUE(ct::CheckForSingleVerifiedSCTInResult(ct_verify_result,
+ kLogDescription));
+ ASSERT_TRUE(ct::CheckForSCTOrigin(
+ ct_verify_result,
+ ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION));
+ } else {
+ EXPECT_EQ(1U, ct_verify_result.scts.size());
+ EXPECT_EQ(ct::SCT_STATUS_LOG_UNKNOWN, ct_verify_result.scts[0].status);
+ }
+ }
+
+ protected:
+ TransportSecurityState transport_security_state_;
+ MockCTPolicyEnforcer ct_policy_enforcer_;
+
+ std::unique_ptr<MultiLogCTVerifier> ct_verifier_;
+ std::vector<scoped_refptr<const CTLogVerifier>> log_verifiers_;
+ std::unique_ptr<ProofVerifyContext> verify_context_;
+ std::unique_ptr<ProofVerifyDetails> details_;
+ std::string error_details_;
+ std::vector<std::string> certs_;
+};
+
+// Tests that the ProofVerifier fails verification if certificate
+// verification fails.
+TEST_F(ProofVerifierChromiumTest, DISABLED_FailsIfCertFails) {
+ MockCertVerifier dummy_verifier;
+ 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, "", certs_, "",
+ GetTestSignature(), verify_context_.get(), &error_details_, &details_,
+ std::move(callback));
+ ASSERT_EQ(QUIC_FAILURE, status);
+}
+
+// Valid SCT, but invalid signature.
+TEST_F(ProofVerifierChromiumTest, DISABLED_ValidSCTList) {
+ // Use different certificates for SCT tests.
+ ASSERT_NO_FATAL_FAILURE(GetSCTTestCertificates(&certs_));
+
+ MockCertVerifier cert_verifier;
+ ProofVerifierChromium proof_verifier(&cert_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, "", certs_,
+ ct::GetSCTListForTesting(), "", verify_context_.get(), &error_details_,
+ &details_, std::move(callback));
+ ASSERT_EQ(QUIC_FAILURE, status);
+ CheckSCT(/*sct_expected_ok=*/true);
+}
+
+// Invalid SCT and signature.
+TEST_F(ProofVerifierChromiumTest, DISABLED_InvalidSCTList) {
+ // Use different certificates for SCT tests.
+ ASSERT_NO_FATAL_FAILURE(GetSCTTestCertificates(&certs_));
+
+ MockCertVerifier cert_verifier;
+ ProofVerifierChromium proof_verifier(&cert_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, "", certs_,
+ ct::GetSCTListWithInvalidSCT(), "", verify_context_.get(),
+ &error_details_, &details_, std::move(callback));
+ ASSERT_EQ(QUIC_FAILURE, status);
+ CheckSCT(/*sct_expected_ok=*/false);
+}
+
+// Tests that the ProofVerifier doesn't verify certificates if the config
+// signature fails.
+TEST_F(ProofVerifierChromiumTest, DISABLED_FailsIfSignatureFails) {
+ FailsTestCertVerifier cert_verifier;
+ ProofVerifierChromium proof_verifier(&cert_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, "", certs_, "",
+ kTestConfig, verify_context_.get(), &error_details_, &details_,
+ std::move(callback));
+ ASSERT_EQ(QUIC_FAILURE, status);
+}
+
+// Tests that the certificate policy enforcer is consulted for EV
+// and the certificate is allowed to be EV.
+TEST_F(ProofVerifierChromiumTest, DISABLED_PreservesEVIfAllowed) {
+ scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate();
+ ASSERT_TRUE(test_cert);
+
+ CertVerifyResult dummy_result;
+ dummy_result.verified_cert = test_cert;
+ dummy_result.cert_status = CERT_STATUS_IS_EV;
+
+ MockCertVerifier dummy_verifier;
+ dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, OK);
+
+ EXPECT_CALL(ct_policy_enforcer_, DoesConformToCTEVPolicy(_, _, _, _))
+ .WillRepeatedly(
+ Return(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS));
+
+ 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, "", certs_, "",
+ GetTestSignature(), verify_context_.get(), &error_details_, &details_,
+ std::move(callback));
+ ASSERT_EQ(QUIC_SUCCESS, status);
+
+ ASSERT_TRUE(details_.get());
+ ProofVerifyDetailsChromium* verify_details =
+ static_cast<ProofVerifyDetailsChromium*>(details_.get());
+ EXPECT_EQ(dummy_result.cert_status,
+ verify_details->cert_verify_result.cert_status);
+}
+
+// Tests that the certificate policy enforcer is consulted for EV
+// and the certificate is not allowed to be EV.
+TEST_F(ProofVerifierChromiumTest, DISABLED_StripsEVIfNotAllowed) {
+ scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate();
+ ASSERT_TRUE(test_cert);
+
+ CertVerifyResult dummy_result;
+ dummy_result.verified_cert = test_cert;
+ dummy_result.cert_status = CERT_STATUS_IS_EV;
+
+ MockCertVerifier dummy_verifier;
+ dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, OK);
+
+ EXPECT_CALL(ct_policy_enforcer_, DoesConformToCTEVPolicy(_, _, _, _))
+ .WillRepeatedly(
+ Return(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS));
+
+ 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, "", certs_, "",
+ GetTestSignature(), verify_context_.get(), &error_details_, &details_,
+ std::move(callback));
+ ASSERT_EQ(QUIC_SUCCESS, status);
+
+ ASSERT_TRUE(details_.get());
+ ProofVerifyDetailsChromium* verify_details =
+ static_cast<ProofVerifyDetailsChromium*>(details_.get());
+ EXPECT_EQ(CERT_STATUS_CT_COMPLIANCE_FAILED,
+ verify_details->cert_verify_result.cert_status &
+ (CERT_STATUS_CT_COMPLIANCE_FAILED | CERT_STATUS_IS_EV));
+}
+
+// Tests that the certificate policy enforcer is not consulted if
+// the certificate is not EV.
+TEST_F(ProofVerifierChromiumTest, DISABLED_IgnoresPolicyEnforcerIfNotEV) {
+ scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate();
+ ASSERT_TRUE(test_cert);
+
+ CertVerifyResult dummy_result;
+ dummy_result.verified_cert = test_cert;
+ dummy_result.cert_status = 0;
+
+ MockCertVerifier dummy_verifier;
+ dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, OK);
+
+ FailsTestCTPolicyEnforcer policy_enforcer;
+
+ ProofVerifierChromium proof_verifier(&dummy_verifier, &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, "", certs_, "",
+ GetTestSignature(), verify_context_.get(), &error_details_, &details_,
+ std::move(callback));
+ ASSERT_EQ(QUIC_SUCCESS, status);
+
+ ASSERT_TRUE(details_.get());
+ ProofVerifyDetailsChromium* verify_details =
+ static_cast<ProofVerifyDetailsChromium*>(details_.get());
+ EXPECT_EQ(0u, verify_details->cert_verify_result.cert_status);
+}
+
+HashValueVector MakeHashValueVector(uint8_t tag) {
+ HashValue hash(HASH_VALUE_SHA256);
+ memset(hash.data(), tag, hash.size());
+ HashValueVector hashes;
+ hashes.push_back(hash);
+ return hashes;
+}
+
+// Test that PKP is enforced for certificates that chain up to known roots.
+TEST_F(ProofVerifierChromiumTest, DISABLED_PKPEnforced) {
+ scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate();
+ ASSERT_TRUE(test_cert);
+
+ CertVerifyResult dummy_result;
+ dummy_result.verified_cert = test_cert;
+ dummy_result.is_issued_by_known_root = true;
+ dummy_result.public_key_hashes = MakeHashValueVector(0x01);
+ dummy_result.cert_status = 0;
+
+ MockCertVerifier dummy_verifier;
+ dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, OK);
+
+ HashValueVector pin_hashes = MakeHashValueVector(0x02);
+ transport_security_state_.AddHPKP(
+ kTestHostname, base::Time::Now() + base::TimeDelta::FromSeconds(10000),
+ true, pin_hashes, GURL());
+
+ 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, "", certs_, "",
+ GetTestSignature(), verify_context_.get(), &error_details_, &details_,
+ std::move(callback));
+ ASSERT_EQ(QUIC_FAILURE, status);
+
+ ASSERT_TRUE(details_.get());
+ ProofVerifyDetailsChromium* verify_details =
+ static_cast<ProofVerifyDetailsChromium*>(details_.get());
+ EXPECT_TRUE(verify_details->cert_verify_result.cert_status &
+ CERT_STATUS_PINNED_KEY_MISSING);
+ EXPECT_FALSE(verify_details->pkp_bypassed);
+ EXPECT_NE("", verify_details->pinning_failure_log);
+}
+
+// Test |pkp_bypassed| is set when PKP is bypassed due to a local
+// trust anchor
+TEST_F(ProofVerifierChromiumTest, DISABLED_PKPBypassFlagSet) {
+ scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate();
+ ASSERT_TRUE(test_cert);
+
+ CertVerifyResult dummy_result;
+ dummy_result.verified_cert = test_cert;
+ dummy_result.is_issued_by_known_root = false;
+ dummy_result.public_key_hashes = MakeHashValueVector(0x01);
+ dummy_result.cert_status = 0;
+
+ MockCertVerifier dummy_verifier;
+ dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, OK);
+
+ HashValueVector expected_hashes = MakeHashValueVector(0x02);
+ transport_security_state_.AddHPKP(
+ kTestHostname, base::Time::Now() + base::TimeDelta::FromSeconds(10000),
+ true, expected_hashes, GURL());
+
+ 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, "", certs_, "",
+ GetTestSignature(), verify_context_.get(), &error_details_, &details_,
+ std::move(callback));
+ ASSERT_EQ(QUIC_SUCCESS, status);
+
+ ASSERT_TRUE(details_.get());
+ ProofVerifyDetailsChromium* verify_details =
+ static_cast<ProofVerifyDetailsChromium*>(details_.get());
+ EXPECT_TRUE(verify_details->pkp_bypassed);
+}
+
+// Test that when CT is required (in this case, by the delegate), the
+// absence of CT information is a socket error.
+TEST_F(ProofVerifierChromiumTest, DISABLED_CTIsRequired) {
+ scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate();
+ ASSERT_TRUE(test_cert);
+
+ CertVerifyResult dummy_result;
+ dummy_result.verified_cert = test_cert;
+ dummy_result.is_issued_by_known_root = true;
+ dummy_result.public_key_hashes = MakeHashValueVector(0x01);
+ dummy_result.cert_status = 0;
+
+ MockCertVerifier dummy_verifier;
+ dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, OK);
+
+ // Set up CT.
+ MockRequireCTDelegate require_ct_delegate;
+ transport_security_state_.SetRequireCTDelegate(&require_ct_delegate);
+ EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_))
+ .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate::
+ CTRequirementLevel::NOT_REQUIRED));
+ EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(kTestHostname))
+ .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate::
+ CTRequirementLevel::REQUIRED));
+ EXPECT_CALL(ct_policy_enforcer_, DoesConformToCertPolicy(_, _, _))
+ .WillRepeatedly(
+ Return(ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS));
+
+ 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, "", certs_, "",
+ GetTestSignature(), verify_context_.get(), &error_details_, &details_,
+ std::move(callback));
+ ASSERT_EQ(QUIC_FAILURE, status);
+
+ ASSERT_TRUE(details_.get());
+ ProofVerifyDetailsChromium* verify_details =
+ static_cast<ProofVerifyDetailsChromium*>(details_.get());
+ EXPECT_TRUE(verify_details->cert_verify_result.cert_status &
+ CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED);
+}
+
+// Test that CT is considered even when HPKP fails.
+TEST_F(ProofVerifierChromiumTest, DISABLED_PKPAndCTBothTested) {
+ scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate();
+ ASSERT_TRUE(test_cert);
+
+ CertVerifyResult dummy_result;
+ dummy_result.verified_cert = test_cert;
+ dummy_result.is_issued_by_known_root = true;
+ dummy_result.public_key_hashes = MakeHashValueVector(0x01);
+ dummy_result.cert_status = 0;
+
+ MockCertVerifier dummy_verifier;
+ dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, OK);
+
+ // Set up HPKP.
+ HashValueVector pin_hashes = MakeHashValueVector(0x02);
+ transport_security_state_.AddHPKP(
+ kTestHostname, base::Time::Now() + base::TimeDelta::FromSeconds(10000),
+ true, pin_hashes, GURL());
+
+ // Set up CT.
+ MockRequireCTDelegate require_ct_delegate;
+ transport_security_state_.SetRequireCTDelegate(&require_ct_delegate);
+ EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_))
+ .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate::
+ CTRequirementLevel::NOT_REQUIRED));
+ EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(kTestHostname))
+ .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate::
+ CTRequirementLevel::REQUIRED));
+ EXPECT_CALL(ct_policy_enforcer_, DoesConformToCertPolicy(_, _, _))
+ .WillRepeatedly(
+ Return(ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS));
+
+ 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, "", certs_, "",
+ GetTestSignature(), verify_context_.get(), &error_details_, &details_,
+ std::move(callback));
+ ASSERT_EQ(QUIC_FAILURE, status);
+
+ ASSERT_TRUE(details_.get());
+ ProofVerifyDetailsChromium* verify_details =
+ static_cast<ProofVerifyDetailsChromium*>(details_.get());
+ EXPECT_TRUE(verify_details->cert_verify_result.cert_status &
+ CERT_STATUS_PINNED_KEY_MISSING);
+ EXPECT_TRUE(verify_details->cert_verify_result.cert_status &
+ CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED);
+}
+
+// Tests that the VerifyCertChain verifies certificates.
+TEST_F(ProofVerifierChromiumTest, VerifyCertChain) {
+ scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate();
+ ASSERT_TRUE(test_cert);
+
+ CertVerifyResult dummy_result;
+ dummy_result.verified_cert = test_cert;
+ dummy_result.cert_status = 0;
+
+ MockCertVerifier dummy_verifier;
+ dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, OK);
+
+ ProofVerifierChromium proof_verifier(&dummy_verifier, &ct_policy_enforcer_,
+ &transport_security_state_,
+ ct_verifier_.get());
+
+ std::unique_ptr<DummyProofVerifierCallback> callback(
+ new DummyProofVerifierCallback);
+ QuicAsyncStatus status = proof_verifier.VerifyCertChain(
+ kTestHostname, certs_, verify_context_.get(), &error_details_, &details_,
+ std::move(callback));
+ ASSERT_EQ(QUIC_SUCCESS, status);
+
+ ASSERT_TRUE(details_.get());
+ ProofVerifyDetailsChromium* verify_details =
+ static_cast<ProofVerifyDetailsChromium*>(details_.get());
+ EXPECT_EQ(0u, verify_details->cert_verify_result.cert_status);
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/chromium/crypto_test_utils_chromium.cc b/chromium/net/quic/chromium/crypto_test_utils_chromium.cc
new file mode 100644
index 00000000000..d1c6db0ec02
--- /dev/null
+++ b/chromium/net/quic/chromium/crypto_test_utils_chromium.cc
@@ -0,0 +1,139 @@
+// Copyright 2013 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 <memory>
+#include <utility>
+
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/cert/cert_status_flags.h"
+#include "net/cert/cert_verifier.h"
+#include "net/cert/cert_verify_result.h"
+#include "net/cert/ct_policy_enforcer.h"
+#include "net/cert/ct_verifier.h"
+#include "net/cert/mock_cert_verifier.h"
+#include "net/cert/multi_log_ct_verifier.h"
+#include "net/cert/test_root_certs.h"
+#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
+#include "net/http/transport_security_state.h"
+#include "net/log/net_log_with_source.h"
+#include "net/quic/chromium/crypto/proof_source_chromium.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/core/crypto/crypto_utils.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/ssl/ssl_config_service.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/test_data_directory.h"
+
+using base::StringPiece;
+using base::StringPrintf;
+using std::string;
+using std::vector;
+
+namespace net {
+
+namespace test {
+
+namespace {
+
+class TestProofVerifierChromium : public ProofVerifierChromium {
+ public:
+ TestProofVerifierChromium(
+ std::unique_ptr<CertVerifier> cert_verifier,
+ std::unique_ptr<TransportSecurityState> transport_security_state,
+ std::unique_ptr<CTVerifier> cert_transparency_verifier,
+ std::unique_ptr<CTPolicyEnforcer> ct_policy_enforcer,
+ const std::string& cert_file)
+ : ProofVerifierChromium(cert_verifier.get(),
+ ct_policy_enforcer.get(),
+ transport_security_state.get(),
+ cert_transparency_verifier.get()),
+ cert_verifier_(std::move(cert_verifier)),
+ transport_security_state_(std::move(transport_security_state)),
+ cert_transparency_verifier_(std::move(cert_transparency_verifier)),
+ ct_policy_enforcer_(std::move(ct_policy_enforcer)) {
+ // Load and install the root for the validated chain.
+ scoped_refptr<X509Certificate> root_cert =
+ ImportCertFromFile(GetTestCertsDirectory(), cert_file);
+ scoped_root_.Reset(root_cert.get());
+ }
+
+ ~TestProofVerifierChromium() override {}
+
+ CertVerifier* cert_verifier() { return cert_verifier_.get(); }
+
+ private:
+ ScopedTestRoot scoped_root_;
+ std::unique_ptr<CertVerifier> cert_verifier_;
+ std::unique_ptr<TransportSecurityState> transport_security_state_;
+ std::unique_ptr<CTVerifier> cert_transparency_verifier_;
+ std::unique_ptr<CTPolicyEnforcer> ct_policy_enforcer_;
+};
+
+} // namespace
+
+// static
+std::unique_ptr<ProofSource> CryptoTestUtils::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")));
+ return std::move(source);
+}
+
+// static
+std::unique_ptr<ProofVerifier> ProofVerifierForTestingInternal(
+ bool use_real_proof_verifier) {
+ // TODO(rch): use a real cert verifier?
+ 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");
+ cert_verifier->AddResultForCertAndHost(verify_result.verified_cert.get(),
+ "test.example.com", verify_result, OK);
+ if (use_real_proof_verifier) {
+ return base::MakeUnique<TestProofVerifierChromium>(
+ std::move(cert_verifier), base::WrapUnique(new TransportSecurityState),
+ base::WrapUnique(new MultiLogCTVerifier),
+ base::WrapUnique(new CTPolicyEnforcer), "quic_root.crt");
+ }
+ return base::MakeUnique<TestProofVerifierChromium>(
+ std::move(cert_verifier), base::WrapUnique(new TransportSecurityState),
+ base::WrapUnique(new MultiLogCTVerifier),
+ base::WrapUnique(new CTPolicyEnforcer), "quic_root.crt");
+}
+
+// static
+std::unique_ptr<ProofVerifier> CryptoTestUtils::ProofVerifierForTesting() {
+ return ProofVerifierForTestingInternal(/*use_real_proof_verifier=*/false);
+}
+
+// static
+std::unique_ptr<ProofVerifier> CryptoTestUtils::RealProofVerifierForTesting() {
+ return ProofVerifierForTestingInternal(/*use_real_proof_verifier=*/true);
+}
+
+// static
+ProofVerifyContext* CryptoTestUtils::ProofVerifyContextForTesting() {
+ return new ProofVerifyContextChromium(/*cert_verify_flags=*/0,
+ NetLogWithSource());
+}
+
+} // namespace test
+
+} // namespace net
diff --git a/chromium/net/quic/chromium/mock_network_change_notifier.cc b/chromium/net/quic/chromium/mock_network_change_notifier.cc
new file mode 100644
index 00000000000..e72ba2501cf
--- /dev/null
+++ b/chromium/net/quic/chromium/mock_network_change_notifier.cc
@@ -0,0 +1,87 @@
+// 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/chromium/mock_network_change_notifier.h"
+
+#include "base/run_loop.h"
+
+namespace net {
+namespace test {
+
+MockNetworkChangeNotifier::MockNetworkChangeNotifier()
+ : force_network_handles_supported_(false) {}
+MockNetworkChangeNotifier::~MockNetworkChangeNotifier() {}
+
+MockNetworkChangeNotifier::ConnectionType
+MockNetworkChangeNotifier::GetCurrentConnectionType() const {
+ return CONNECTION_UNKNOWN;
+}
+
+void MockNetworkChangeNotifier::ForceNetworkHandlesSupported() {
+ force_network_handles_supported_ = true;
+}
+
+bool MockNetworkChangeNotifier::AreNetworkHandlesCurrentlySupported() const {
+ return force_network_handles_supported_;
+}
+
+void MockNetworkChangeNotifier::SetConnectedNetworksList(
+ const NetworkList& network_list) {
+ connected_networks_ = network_list;
+}
+
+void MockNetworkChangeNotifier::GetCurrentConnectedNetworks(
+ NetworkList* network_list) const {
+ network_list->clear();
+ *network_list = connected_networks_;
+}
+
+void MockNetworkChangeNotifier::NotifyNetworkMadeDefault(
+ NetworkChangeNotifier::NetworkHandle network) {
+ QueueNetworkMadeDefault(network);
+ // Spin the message loop so the notification is delivered.
+ base::RunLoop().RunUntilIdle();
+}
+
+void MockNetworkChangeNotifier::QueueNetworkMadeDefault(
+ NetworkChangeNotifier::NetworkHandle network) {
+ NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChange(
+ NetworkChangeNotifier::MADE_DEFAULT, network);
+}
+
+void MockNetworkChangeNotifier::NotifyNetworkDisconnected(
+ NetworkChangeNotifier::NetworkHandle network) {
+ QueueNetworkDisconnected(network);
+ // Spin the message loop so the notification is delivered.
+ base::RunLoop().RunUntilIdle();
+}
+
+void MockNetworkChangeNotifier::QueueNetworkDisconnected(
+ NetworkChangeNotifier::NetworkHandle network) {
+ NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChange(
+ NetworkChangeNotifier::DISCONNECTED, network);
+}
+
+void MockNetworkChangeNotifier::NotifyNetworkConnected(
+ NetworkChangeNotifier::NetworkHandle network) {
+ NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChange(
+ NetworkChangeNotifier::CONNECTED, network);
+ // Spin the message loop so the notification is delivered.
+ base::RunLoop().RunUntilIdle();
+}
+
+ScopedMockNetworkChangeNotifier::ScopedMockNetworkChangeNotifier()
+ : disable_network_change_notifier_for_tests_(
+ new NetworkChangeNotifier::DisableForTest()),
+ mock_network_change_notifier_(new MockNetworkChangeNotifier()) {}
+
+ScopedMockNetworkChangeNotifier::~ScopedMockNetworkChangeNotifier() {}
+
+MockNetworkChangeNotifier*
+ScopedMockNetworkChangeNotifier::mock_network_change_notifier() {
+ return mock_network_change_notifier_.get();
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/chromium/mock_network_change_notifier.h b/chromium/net/quic/chromium/mock_network_change_notifier.h
new file mode 100644
index 00000000000..d81b4efa905
--- /dev/null
+++ b/chromium/net/quic/chromium/mock_network_change_notifier.h
@@ -0,0 +1,69 @@
+// 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.
+
+#ifndef NET_QUIC_CHROMIUM_MOCK_NETWORK_CHANGE_NOTIFIER_H_
+#define NET_QUIC_CHROMIUM_MOCK_NETWORK_CHANGE_NOTIFIER_H_
+
+#include "net/base/network_change_notifier.h"
+
+namespace net {
+namespace test {
+
+class MockNetworkChangeNotifier : public NetworkChangeNotifier {
+ public:
+ MockNetworkChangeNotifier();
+ ~MockNetworkChangeNotifier() override;
+
+ ConnectionType GetCurrentConnectionType() const override;
+
+ void ForceNetworkHandlesSupported();
+
+ bool AreNetworkHandlesCurrentlySupported() const override;
+
+ void SetConnectedNetworksList(const NetworkList& network_list);
+
+ void GetCurrentConnectedNetworks(NetworkList* network_list) const override;
+
+ // Delivers a MADE_DEFAULT notification to observers.
+ void NotifyNetworkMadeDefault(NetworkChangeNotifier::NetworkHandle network);
+
+ // Queues a MADE_DEFAULT notification to be delivered to observers
+ // but does not spin the message loop to actually deliver it.
+ void QueueNetworkMadeDefault(NetworkChangeNotifier::NetworkHandle network);
+
+ // Delivers a DISCONNECTED notification to observers.
+ void NotifyNetworkDisconnected(NetworkChangeNotifier::NetworkHandle network);
+
+ // Queues a DISCONNECTED notification to be delivered to observers
+ // but does not spin the message loop to actually deliver it.
+ void QueueNetworkDisconnected(NetworkChangeNotifier::NetworkHandle network);
+
+ // Delivers a CONNECTED notification to observers.
+ void NotifyNetworkConnected(NetworkChangeNotifier::NetworkHandle network);
+
+ private:
+ bool force_network_handles_supported_;
+ NetworkChangeNotifier::NetworkList connected_networks_;
+};
+
+// Class to replace existing NetworkChangeNotifier singleton with a
+// MockNetworkChangeNotifier for a test. To use, simply create a
+// ScopedMockNetworkChangeNotifier object in the test.
+class ScopedMockNetworkChangeNotifier {
+ public:
+ ScopedMockNetworkChangeNotifier();
+ ~ScopedMockNetworkChangeNotifier();
+
+ MockNetworkChangeNotifier* mock_network_change_notifier();
+
+ private:
+ std::unique_ptr<NetworkChangeNotifier::DisableForTest>
+ disable_network_change_notifier_for_tests_;
+ std::unique_ptr<MockNetworkChangeNotifier> mock_network_change_notifier_;
+};
+
+} // namespace test
+} // namespace net
+
+#endif // NET_QUIC_CHROMIUM_MOCK_NETWORK_CHANGE_NOTIFIER_H_
diff --git a/chromium/net/quic/chromium/mock_quic_data.cc b/chromium/net/quic/chromium/mock_quic_data.cc
new file mode 100644
index 00000000000..f36029b2a4f
--- /dev/null
+++ b/chromium/net/quic/chromium/mock_quic_data.cc
@@ -0,0 +1,68 @@
+// Copyright 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.
+
+#include "net/quic/chromium/mock_quic_data.h"
+
+namespace net {
+namespace test {
+
+MockQuicData::MockQuicData() : sequence_number_(0) {}
+
+MockQuicData::~MockQuicData() {}
+
+void MockQuicData::AddConnect(IoMode mode, int rv) {
+ connect_.reset(new MockConnect(mode, rv));
+}
+
+void MockQuicData::AddSynchronousRead(
+ std::unique_ptr<QuicEncryptedPacket> packet) {
+ reads_.push_back(MockRead(SYNCHRONOUS, packet->data(), packet->length(),
+ sequence_number_++));
+ packets_.push_back(std::move(packet));
+}
+
+void MockQuicData::AddRead(std::unique_ptr<QuicEncryptedPacket> packet) {
+ reads_.push_back(
+ MockRead(ASYNC, packet->data(), packet->length(), sequence_number_++));
+ packets_.push_back(std::move(packet));
+}
+
+void MockQuicData::AddRead(IoMode mode, int rv) {
+ reads_.push_back(MockRead(mode, rv, sequence_number_++));
+}
+
+void MockQuicData::AddWrite(std::unique_ptr<QuicEncryptedPacket> packet) {
+ writes_.push_back(MockWrite(SYNCHRONOUS, packet->data(), packet->length(),
+ sequence_number_++));
+ packets_.push_back(std::move(packet));
+}
+
+void MockQuicData::AddWrite(IoMode mode, int rv) {
+ writes_.push_back(MockWrite(mode, rv, sequence_number_++));
+}
+
+void MockQuicData::AddSocketDataToFactory(MockClientSocketFactory* factory) {
+ MockRead* reads = reads_.empty() ? nullptr : &reads_[0];
+ MockWrite* writes = writes_.empty() ? nullptr : &writes_[0];
+ socket_data_.reset(
+ new SequencedSocketData(reads, reads_.size(), writes, writes_.size()));
+ if (connect_ != nullptr)
+ socket_data_->set_connect_data(*connect_);
+ factory->AddSocketDataProvider(socket_data_.get());
+}
+
+bool MockQuicData::AllReadDataConsumed() {
+ return socket_data_->AllReadDataConsumed();
+}
+
+bool MockQuicData::AllWriteDataConsumed() {
+ return socket_data_->AllWriteDataConsumed();
+}
+
+void MockQuicData::Resume() {
+ socket_data_->Resume();
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/chromium/mock_quic_data.h b/chromium/net/quic/chromium/mock_quic_data.h
new file mode 100644
index 00000000000..8a1e1d27981
--- /dev/null
+++ b/chromium/net/quic/chromium/mock_quic_data.h
@@ -0,0 +1,64 @@
+// Copyright 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.
+
+#include "net/quic/core/quic_protocol.h"
+#include "net/socket/socket_test_util.h"
+
+namespace net {
+namespace test {
+
+// Helper class to encapsulate MockReads and MockWrites for QUIC.
+// Simplify ownership issues and the interaction with the MockSocketFactory.
+class MockQuicData {
+ public:
+ MockQuicData();
+ ~MockQuicData();
+
+ // Makes the Connect() call return |rv| either
+ // synchronusly or asynchronously based on |mode|.
+ void AddConnect(IoMode mode, int rv);
+
+ // Adds a synchronous read at the next sequence number which will read
+ // |packet|.
+ void AddSynchronousRead(std::unique_ptr<QuicEncryptedPacket> packet);
+
+ // Adds an asynchronous read at the next sequence number which will read
+ // |packet|.
+ void AddRead(std::unique_ptr<QuicEncryptedPacket> packet);
+
+ // Adds a read at the next sequence number which will return |rv| either
+ // synchronously or asynchronously based on |mode|.
+ void AddRead(IoMode mode, int rv);
+
+ // Adds a synchronous write at the next sequence number which will write
+ // |packet|.
+ void AddWrite(std::unique_ptr<QuicEncryptedPacket> packet);
+
+ // Adds a write at the next sequence number which will return |rv| either
+ // synchronously or asynchronously based on |mode|.
+ void AddWrite(IoMode mode, int rv);
+
+ // Adds the reads and writes to |factory|.
+ void AddSocketDataToFactory(MockClientSocketFactory* factory);
+
+ // Returns true if all reads have been consumed.
+ bool AllReadDataConsumed();
+
+ // Returns true if all writes have been consumed.
+ bool AllWriteDataConsumed();
+
+ // Resumes I/O after it is paused.
+ void Resume();
+
+ private:
+ std::vector<std::unique_ptr<QuicEncryptedPacket>> packets_;
+ std::unique_ptr<MockConnect> connect_;
+ std::vector<MockWrite> writes_;
+ std::vector<MockRead> reads_;
+ size_t sequence_number_;
+ std::unique_ptr<SequencedSocketData> socket_data_;
+};
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/chromium/network_connection.cc b/chromium/net/quic/chromium/network_connection.cc
new file mode 100644
index 00000000000..6bfed05df54
--- /dev/null
+++ b/chromium/net/quic/chromium/network_connection.cc
@@ -0,0 +1,75 @@
+// 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/chromium/network_connection.h"
+
+#include "net/base/network_interfaces.h"
+
+namespace net {
+
+NetworkConnection::NetworkConnection()
+ : connection_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN),
+ connection_description_(nullptr) {}
+
+const char* NetworkConnection::GetDescription() {
+ NetworkChangeNotifier::ConnectionType type =
+ NetworkChangeNotifier::GetConnectionType();
+ if (connection_description_ != nullptr && type == connection_type_)
+ return connection_description_;
+
+ DVLOG(1) << "Updating NetworkConnection's Cached Data";
+
+ connection_description_ = NetworkChangeNotifier::ConnectionTypeToString(type);
+ connection_type_ = type;
+ if (connection_type_ == NetworkChangeNotifier::CONNECTION_UNKNOWN ||
+ connection_type_ == NetworkChangeNotifier::CONNECTION_WIFI) {
+ // This function only seems usefully defined on Windows currently.
+ WifiPHYLayerProtocol wifi_type = GetWifiPHYLayerProtocol();
+ switch (wifi_type) {
+ case WIFI_PHY_LAYER_PROTOCOL_NONE:
+ // No wifi support or no associated AP.
+ break;
+ case WIFI_PHY_LAYER_PROTOCOL_ANCIENT:
+ // An obsolete modes introduced by the original 802.11, e.g. IR, FHSS.
+ connection_description_ = "CONNECTION_WIFI_ANCIENT";
+ break;
+ case WIFI_PHY_LAYER_PROTOCOL_A:
+ // 802.11a, OFDM-based rates.
+ connection_description_ = "CONNECTION_WIFI_802.11a";
+ break;
+ case WIFI_PHY_LAYER_PROTOCOL_B:
+ // 802.11b, DSSS or HR DSSS.
+ connection_description_ = "CONNECTION_WIFI_802.11b";
+ break;
+ case WIFI_PHY_LAYER_PROTOCOL_G:
+ // 802.11g, same rates as 802.11a but compatible with 802.11b.
+ connection_description_ = "CONNECTION_WIFI_802.11g";
+ break;
+ case WIFI_PHY_LAYER_PROTOCOL_N:
+ // 802.11n, HT rates.
+ connection_description_ = "CONNECTION_WIFI_802.11n";
+ break;
+ case WIFI_PHY_LAYER_PROTOCOL_UNKNOWN:
+ // Unclassified mode or failure to identify.
+ break;
+ }
+ }
+ return connection_description_;
+}
+
+void NetworkConnection::Clear() {
+ connection_type_ = NetworkChangeNotifier::CONNECTION_UNKNOWN;
+ connection_description_ = nullptr;
+}
+
+void NetworkConnection::OnIPAddressChanged() {
+ Clear();
+}
+
+void NetworkConnection::OnConnectionTypeChanged(
+ NetworkChangeNotifier::ConnectionType type) {
+ Clear();
+}
+
+} // namespace net
diff --git a/chromium/net/quic/network_connection.h b/chromium/net/quic/chromium/network_connection.h
index 089fe34ced5..089fe34ced5 100644
--- a/chromium/net/quic/network_connection.h
+++ b/chromium/net/quic/chromium/network_connection.h
diff --git a/chromium/net/quic/chromium/network_connection_unittest.cc b/chromium/net/quic/chromium/network_connection_unittest.cc
new file mode 100644
index 00000000000..6b0ec3a81e4
--- /dev/null
+++ b/chromium/net/quic/chromium/network_connection_unittest.cc
@@ -0,0 +1,80 @@
+// Copyright 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.
+
+#include "net/quic/chromium/network_connection.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+class NetworkConnectionPeer {
+ public:
+ static NetworkChangeNotifier::ConnectionType connection_type(
+ const NetworkConnection& network_connection) {
+ return network_connection.connection_type_;
+ }
+ static void set_connection_type(NetworkConnection* network_connection,
+ NetworkChangeNotifier::ConnectionType type) {
+ network_connection->connection_type_ = type;
+ }
+
+ static const char* connection_description(
+ const NetworkConnection& network_connection) {
+ return network_connection.connection_description_;
+ }
+ static void set_connection_description(NetworkConnection* network_connection,
+ const char* description) {
+ network_connection->connection_description_ = description;
+ }
+};
+
+// Test NetworkConnection().
+class NetworkConnectionTest : public testing::Test {
+ protected:
+ void CheckNetworkConnectionDescription() {
+ NetworkChangeNotifier::ConnectionType type =
+ NetworkChangeNotifier::GetConnectionType();
+ const char* description = network_connection_.GetDescription();
+ // Verify GetDescription() updated the cached data.
+ EXPECT_EQ(NetworkConnectionPeer::connection_type(network_connection_),
+ type);
+ EXPECT_EQ(
+ NetworkConnectionPeer::connection_description(network_connection_),
+ description);
+
+ if (type != NetworkChangeNotifier::CONNECTION_WIFI)
+ EXPECT_EQ(description,
+ NetworkChangeNotifier::ConnectionTypeToString(type));
+ else
+ EXPECT_NE(nullptr, network_connection_.GetDescription());
+ }
+
+ NetworkConnection network_connection_;
+};
+
+TEST_F(NetworkConnectionTest, GetDescription) {
+ const char* description = network_connection_.GetDescription();
+
+ // Set connection description to nullptr.
+ NetworkConnectionPeer::set_connection_description(&network_connection_,
+ nullptr);
+ CheckNetworkConnectionDescription();
+
+ // Set connection type to a junk value.
+ NetworkConnectionPeer::set_connection_type(
+ &network_connection_, NetworkChangeNotifier::CONNECTION_LAST);
+ CheckNetworkConnectionDescription();
+
+ EXPECT_EQ(description, network_connection_.GetDescription());
+}
+
+TEST_F(NetworkConnectionTest, Clear) {
+ CheckNetworkConnectionDescription();
+ network_connection_.Clear();
+ CheckNetworkConnectionDescription();
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/chromium/port_suggester.cc b/chromium/net/quic/chromium/port_suggester.cc
new file mode 100644
index 00000000000..b88ce0d98ca
--- /dev/null
+++ b/chromium/net/quic/chromium/port_suggester.cc
@@ -0,0 +1,47 @@
+// Copyright 2013 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/chromium/port_suggester.h"
+
+#include "base/logging.h"
+
+namespace net {
+
+PortSuggester::PortSuggester(const HostPortPair& server, uint64_t seed)
+ : call_count_(0), previous_suggestion_(-1) {
+ unsigned char hash_bytes[base::kSHA1Length];
+ base::SHA1HashBytes(
+ reinterpret_cast<const unsigned char*>(server.host().data()),
+ server.host().length(), hash_bytes);
+ static_assert(sizeof(seed_) < sizeof(hash_bytes), "seed larger than hash");
+ memcpy(&seed_, hash_bytes, sizeof(seed_));
+ seed_ ^= seed ^ server.port();
+}
+
+int PortSuggester::SuggestPort(int min, int max) {
+ // Sometimes our suggestion can't be used, so we ensure that if additional
+ // calls are made, then each call (probably) provides a new suggestion.
+ if (++call_count_ > 1) {
+ // Evolve the seed.
+ unsigned char hash_bytes[base::kSHA1Length];
+ base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(&seed_),
+ sizeof(seed_), hash_bytes);
+ memcpy(&seed_, hash_bytes, sizeof(seed_));
+ }
+ DCHECK_LE(min, max);
+ DCHECK_GT(min, 0);
+ int range = max - min + 1;
+ // Ports (and hence the extent of the |range|) are generally under 2^16, so
+ // the tiny non-uniformity in the pseudo-random distribution is not
+ // significant.
+ previous_suggestion_ = static_cast<int>(seed_ % range) + min;
+ return previous_suggestion_;
+}
+
+int PortSuggester::previous_suggestion() const {
+ DCHECK_LT(0u, call_count_);
+ return previous_suggestion_;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/port_suggester.h b/chromium/net/quic/chromium/port_suggester.h
index d3f41a316ee..d3f41a316ee 100644
--- a/chromium/net/quic/port_suggester.h
+++ b/chromium/net/quic/chromium/port_suggester.h
diff --git a/chromium/net/quic/chromium/port_suggester_unittest.cc b/chromium/net/quic/chromium/port_suggester_unittest.cc
new file mode 100644
index 00000000000..5bf757bde20
--- /dev/null
+++ b/chromium/net/quic/chromium/port_suggester_unittest.cc
@@ -0,0 +1,108 @@
+// Copyright 2013 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/chromium/port_suggester.h"
+
+#include <set>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+class PortSuggesterTest : public ::testing::Test {
+ protected:
+ PortSuggesterTest()
+ : entropy_(1345689),
+ min_ephemeral_port_(1025),
+ max_ephemeral_port_(65535) {}
+
+ uint64_t entropy_;
+ int min_ephemeral_port_;
+ int max_ephemeral_port_;
+};
+
+TEST_F(PortSuggesterTest, SmallRangeTest) {
+ // When the range is small (one wide), we always get that as our answer.
+ scoped_refptr<PortSuggester> port_suggester =
+ new PortSuggester(HostPortPair("www.example.com", 443), entropy_);
+ // Test this for a few different (small) ranges.
+ for (int port = 2000; port < 2010; ++port) {
+ // Use |port| for both |min| and |max| delimiting the suggestion range.
+ EXPECT_EQ(port, port_suggester->SuggestPort(port, port));
+ EXPECT_EQ(port, port_suggester->previous_suggestion());
+ }
+}
+
+TEST_F(PortSuggesterTest, SuggestAllPorts) {
+ // We should eventually fill out any range, but we'll just ensure that we
+ // fill out a small range of ports.
+ scoped_refptr<PortSuggester> port_suggester =
+ new PortSuggester(HostPortPair("www.example.com", 443), entropy_);
+ std::set<int> ports;
+ const uint32_t port_range = 20;
+ const int insertion_limit = 200; // We should be done by then.
+ for (int i = 0; i < insertion_limit; ++i) {
+ ports.insert(port_suggester->SuggestPort(
+ min_ephemeral_port_, min_ephemeral_port_ + port_range - 1));
+ if (ports.size() == port_range) {
+ break;
+ }
+ }
+ EXPECT_EQ(port_range, ports.size());
+}
+
+TEST_F(PortSuggesterTest, AvoidDuplication) {
+ // When the range is large, duplicates are rare, but we'll ask for a few
+ // suggestions and make sure they are unique.
+ scoped_refptr<PortSuggester> port_suggester =
+ new PortSuggester(HostPortPair("www.example.com", 80), entropy_);
+ std::set<int> ports;
+ const size_t port_count = 200;
+ for (size_t i = 0; i < port_count; ++i) {
+ ports.insert(
+ port_suggester->SuggestPort(min_ephemeral_port_, max_ephemeral_port_));
+ }
+ EXPECT_EQ(port_suggester->call_count(), port_count);
+ EXPECT_EQ(port_count, ports.size());
+}
+
+TEST_F(PortSuggesterTest, ConsistentPorts) {
+ // For given hostname, port, and entropy, we should always get the same
+ // suggestions.
+ scoped_refptr<PortSuggester> port_suggester1 =
+ new PortSuggester(HostPortPair("www.example.com", 443), entropy_);
+ scoped_refptr<PortSuggester> port_suggester2 =
+ new PortSuggester(HostPortPair("www.example.com", 443), entropy_);
+ for (int test_count = 20; test_count > 0; --test_count) {
+ EXPECT_EQ(
+ port_suggester1->SuggestPort(min_ephemeral_port_, min_ephemeral_port_),
+ port_suggester2->SuggestPort(min_ephemeral_port_, min_ephemeral_port_));
+ }
+}
+
+TEST_F(PortSuggesterTest, DifferentHostPortEntropy) {
+ // When we have different hosts, port, or entropy, we probably won't collide.
+ scoped_refptr<PortSuggester> port_suggester[] = {
+ new PortSuggester(HostPortPair("www.example.com", 80), entropy_),
+ new PortSuggester(HostPortPair("www.example.ORG", 80), entropy_),
+ new PortSuggester(HostPortPair("www.example.com", 443), entropy_),
+ new PortSuggester(HostPortPair("www.example.com", 80), entropy_ + 123456),
+ };
+
+ std::set<int> ports;
+ const int port_count = 40;
+ size_t insertion_count = 0;
+ for (size_t j = 0; j < arraysize(port_suggester); ++j) {
+ for (int i = 0; i < port_count; ++i) {
+ ports.insert(port_suggester[j]->SuggestPort(min_ephemeral_port_,
+ max_ephemeral_port_));
+ ++insertion_count;
+ }
+ }
+ EXPECT_EQ(insertion_count, ports.size());
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_chromium_alarm_factory.cc b/chromium/net/quic/chromium/quic_chromium_alarm_factory.cc
new file mode 100644
index 00000000000..1b8315e5c9f
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_alarm_factory.cc
@@ -0,0 +1,117 @@
+// 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/chromium/quic_chromium_alarm_factory.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/task_runner.h"
+#include "base/time/time.h"
+
+namespace net {
+
+namespace {
+
+class QuicChromeAlarm : public QuicAlarm {
+ public:
+ QuicChromeAlarm(const QuicClock* clock,
+ base::TaskRunner* task_runner,
+ QuicArenaScopedPtr<QuicAlarm::Delegate> delegate)
+ : QuicAlarm(std::move(delegate)),
+ clock_(clock),
+ task_runner_(task_runner),
+ task_deadline_(QuicTime::Zero()),
+ weak_factory_(this) {}
+
+ protected:
+ void SetImpl() override {
+ DCHECK(deadline().IsInitialized());
+ if (task_deadline_.IsInitialized()) {
+ if (task_deadline_ <= deadline()) {
+ // Since tasks can not be un-posted, OnAlarm will be invoked which
+ // will notice that deadline has not yet been reached, and will set
+ // the alarm for the new deadline.
+ return;
+ }
+ // The scheduled task is after new deadline. Invalidate the weak ptrs
+ // so that task does not execute when we're not expecting it.
+ weak_factory_.InvalidateWeakPtrs();
+ }
+
+ int64_t delay_us = (deadline() - (clock_->Now())).ToMicroseconds();
+ if (delay_us < 0) {
+ delay_us = 0;
+ }
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&QuicChromeAlarm::OnAlarm, weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMicroseconds(delay_us));
+ task_deadline_ = deadline();
+ }
+
+ void CancelImpl() override {
+ DCHECK(!deadline().IsInitialized());
+ // Since tasks can not be un-posted, OnAlarm will be invoked which
+ // will notice that deadline is not Initialized and will do nothing.
+ }
+
+ private:
+ void OnAlarm() {
+ DCHECK(task_deadline_.IsInitialized());
+ task_deadline_ = QuicTime::Zero();
+ // The alarm may have been cancelled.
+ if (!deadline().IsInitialized()) {
+ return;
+ }
+
+ // The alarm may have been re-set to a later time.
+ if (clock_->Now() < deadline()) {
+ SetImpl();
+ return;
+ }
+
+ Fire();
+ }
+
+ const QuicClock* clock_;
+ base::TaskRunner* task_runner_;
+ // If a task has been posted to the message loop, this is the time it
+ // was scheduled to fire. Tracking this allows us to avoid posting a
+ // new tast if the new deadline is in the future, but permits us to
+ // post a new task when the new deadline now earlier than when
+ // previously posted.
+ QuicTime task_deadline_;
+ base::WeakPtrFactory<QuicChromeAlarm> weak_factory_;
+};
+
+} // namespace
+
+QuicChromiumAlarmFactory::QuicChromiumAlarmFactory(
+ base::TaskRunner* task_runner,
+ const QuicClock* clock)
+ : task_runner_(task_runner), clock_(clock), weak_factory_(this) {}
+
+QuicChromiumAlarmFactory::~QuicChromiumAlarmFactory() {}
+
+QuicArenaScopedPtr<QuicAlarm> QuicChromiumAlarmFactory::CreateAlarm(
+ QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+ QuicConnectionArena* arena) {
+ if (arena != nullptr) {
+ return arena->New<QuicChromeAlarm>(clock_, task_runner_,
+ std::move(delegate));
+ } else {
+ return QuicArenaScopedPtr<QuicAlarm>(
+ new QuicChromeAlarm(clock_, task_runner_, std::move(delegate)));
+ }
+}
+
+QuicAlarm* QuicChromiumAlarmFactory::CreateAlarm(
+ QuicAlarm::Delegate* delegate) {
+ return new QuicChromeAlarm(clock_, task_runner_,
+ QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate));
+}
+
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_chromium_alarm_factory.h b/chromium/net/quic/chromium/quic_chromium_alarm_factory.h
new file mode 100644
index 00000000000..436379c8fee
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_alarm_factory.h
@@ -0,0 +1,49 @@
+// 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.
+//
+// The Chrome-specific helper for QuicConnection which uses
+// a TaskRunner for alarms, and uses a DatagramClientSocket for writing data.
+
+#ifndef NET_QUIC_QUIC_CHROMIUM_ALARM_FACTORY_H_
+#define NET_QUIC_QUIC_CHROMIUM_ALARM_FACTORY_H_
+
+#include <set>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_alarm_factory.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+
+namespace base {
+class TaskRunner;
+} // namespace base
+
+namespace net {
+
+class NET_EXPORT_PRIVATE QuicChromiumAlarmFactory : public QuicAlarmFactory {
+ public:
+ QuicChromiumAlarmFactory(base::TaskRunner* task_runner,
+ const QuicClock* clock);
+ ~QuicChromiumAlarmFactory() override;
+
+ // QuicAlarmFactory
+ QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override;
+ QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
+ QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+ QuicConnectionArena* arena) override;
+
+ private:
+ base::TaskRunner* task_runner_;
+ const QuicClock* clock_;
+ base::WeakPtrFactory<QuicChromiumAlarmFactory> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicChromiumAlarmFactory);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CHROMIUM_ALARM_FACTORY_H_
diff --git a/chromium/net/quic/chromium/quic_chromium_alarm_factory_test.cc b/chromium/net/quic/chromium/quic_chromium_alarm_factory_test.cc
new file mode 100644
index 00000000000..1cfe17558e3
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_alarm_factory_test.cc
@@ -0,0 +1,172 @@
+// 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/chromium/quic_chromium_alarm_factory.h"
+
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/test_task_runner.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+namespace {
+
+class TestDelegate : public QuicAlarm::Delegate {
+ public:
+ TestDelegate() : fired_(false) {}
+
+ void OnAlarm() override { fired_ = true; }
+
+ bool fired() const { return fired_; }
+ void Clear() { fired_ = false; }
+
+ private:
+ bool fired_;
+};
+
+class QuicChromiumAlarmFactoryTest : public ::testing::Test {
+ protected:
+ QuicChromiumAlarmFactoryTest()
+ : runner_(new TestTaskRunner(&clock_)),
+ alarm_factory_(runner_.get(), &clock_) {}
+
+ scoped_refptr<TestTaskRunner> runner_;
+ QuicChromiumAlarmFactory alarm_factory_;
+ MockClock clock_;
+};
+
+TEST_F(QuicChromiumAlarmFactoryTest, CreateAlarm) {
+ TestDelegate* delegate = new TestDelegate();
+ std::unique_ptr<QuicAlarm> alarm(alarm_factory_.CreateAlarm(delegate));
+
+ QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
+ alarm->Set(clock_.Now() + delta);
+
+ // Verify that the alarm task has been posted.
+ ASSERT_EQ(1u, runner_->GetPostedTasks().size());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()),
+ runner_->GetPostedTasks()[0].delay);
+
+ runner_->RunNextTask();
+ EXPECT_EQ(QuicTime::Zero() + delta, clock_.Now());
+ EXPECT_TRUE(delegate->fired());
+}
+
+TEST_F(QuicChromiumAlarmFactoryTest, CreateAlarmAndCancel) {
+ TestDelegate* delegate = new TestDelegate();
+ std::unique_ptr<QuicAlarm> alarm(alarm_factory_.CreateAlarm(delegate));
+
+ QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
+ alarm->Set(clock_.Now() + delta);
+ alarm->Cancel();
+
+ // The alarm task should still be posted.
+ ASSERT_EQ(1u, runner_->GetPostedTasks().size());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()),
+ runner_->GetPostedTasks()[0].delay);
+
+ runner_->RunNextTask();
+ EXPECT_EQ(QuicTime::Zero() + delta, clock_.Now());
+ EXPECT_FALSE(delegate->fired());
+}
+
+TEST_F(QuicChromiumAlarmFactoryTest, CreateAlarmAndReset) {
+ TestDelegate* delegate = new TestDelegate();
+ std::unique_ptr<QuicAlarm> alarm(alarm_factory_.CreateAlarm(delegate));
+
+ QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
+ alarm->Set(clock_.Now() + delta);
+ alarm->Cancel();
+ QuicTime::Delta new_delta = QuicTime::Delta::FromMicroseconds(3);
+ alarm->Set(clock_.Now() + new_delta);
+
+ // The alarm task should still be posted.
+ ASSERT_EQ(1u, runner_->GetPostedTasks().size());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()),
+ runner_->GetPostedTasks()[0].delay);
+
+ runner_->RunNextTask();
+ EXPECT_EQ(QuicTime::Zero() + delta, clock_.Now());
+ EXPECT_FALSE(delegate->fired());
+
+ // The alarm task should be posted again.
+ ASSERT_EQ(1u, runner_->GetPostedTasks().size());
+
+ runner_->RunNextTask();
+ EXPECT_EQ(QuicTime::Zero() + new_delta, clock_.Now());
+ EXPECT_TRUE(delegate->fired());
+}
+
+TEST_F(QuicChromiumAlarmFactoryTest, CreateAlarmAndResetEarlier) {
+ TestDelegate* delegate = new TestDelegate();
+ std::unique_ptr<QuicAlarm> alarm(alarm_factory_.CreateAlarm(delegate));
+
+ QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(3);
+ alarm->Set(clock_.Now() + delta);
+ alarm->Cancel();
+ QuicTime::Delta new_delta = QuicTime::Delta::FromMicroseconds(1);
+ alarm->Set(clock_.Now() + new_delta);
+
+ // Both alarm tasks will be posted.
+ ASSERT_EQ(2u, runner_->GetPostedTasks().size());
+
+ // The earlier task will execute and will fire the alarm->
+ runner_->RunNextTask();
+ EXPECT_EQ(QuicTime::Zero() + new_delta, clock_.Now());
+ EXPECT_TRUE(delegate->fired());
+ delegate->Clear();
+
+ // The latter task is still posted.
+ ASSERT_EQ(1u, runner_->GetPostedTasks().size());
+
+ // When the latter task is executed, the weak ptr will be invalid and
+ // the alarm will not fire.
+ runner_->RunNextTask();
+ EXPECT_EQ(QuicTime::Zero() + delta, clock_.Now());
+ EXPECT_FALSE(delegate->fired());
+}
+
+TEST_F(QuicChromiumAlarmFactoryTest, CreateAlarmAndUpdate) {
+ TestDelegate* delegate = new TestDelegate();
+ std::unique_ptr<QuicAlarm> alarm(alarm_factory_.CreateAlarm(delegate));
+
+ QuicTime start = clock_.Now();
+ QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
+ alarm->Set(clock_.Now() + delta);
+ QuicTime::Delta new_delta = QuicTime::Delta::FromMicroseconds(3);
+ alarm->Update(clock_.Now() + new_delta, QuicTime::Delta::FromMicroseconds(1));
+
+ // The alarm task should still be posted.
+ ASSERT_EQ(1u, runner_->GetPostedTasks().size());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()),
+ runner_->GetPostedTasks()[0].delay);
+
+ runner_->RunNextTask();
+ EXPECT_EQ(QuicTime::Zero() + delta, clock_.Now());
+ EXPECT_FALSE(delegate->fired());
+
+ // Move the alarm forward 1us and ensure it doesn't move forward.
+ alarm->Update(clock_.Now() + new_delta, QuicTime::Delta::FromMicroseconds(2));
+
+ ASSERT_EQ(1u, runner_->GetPostedTasks().size());
+ EXPECT_EQ(
+ base::TimeDelta::FromMicroseconds((new_delta - delta).ToMicroseconds()),
+ runner_->GetPostedTasks()[0].delay);
+ runner_->RunNextTask();
+ EXPECT_EQ(start + new_delta, clock_.Now());
+ EXPECT_TRUE(delegate->fired());
+
+ // Set the alarm via an update call.
+ new_delta = QuicTime::Delta::FromMicroseconds(5);
+ alarm->Update(clock_.Now() + new_delta, QuicTime::Delta::FromMicroseconds(1));
+ EXPECT_TRUE(alarm->IsSet());
+
+ // Update it with an uninitialized time and ensure it's cancelled.
+ alarm->Update(QuicTime::Zero(), QuicTime::Delta::FromMicroseconds(1));
+ EXPECT_FALSE(alarm->IsSet());
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_chromium_client_session.cc b/chromium/net/quic/chromium/quic_chromium_client_session.cc
new file mode 100644
index 00000000000..1fd8318915c
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_client_session.cc
@@ -0,0 +1,1418 @@
+// 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/chromium/quic_chromium_client_session.h"
+
+#include <openssl/ssl.h>
+
+#include <utility>
+
+#include "base/callback_helpers.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.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"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/values.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/network_activity_monitor.h"
+#include "net/http/http_log_util.h"
+#include "net/http/transport_security_state.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source_type.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/chromium/quic_chromium_connection_helper.h"
+#include "net/quic/chromium/quic_chromium_packet_writer.h"
+#include "net/quic/chromium/quic_stream_factory.h"
+#include "net/quic/core/crypto/quic_server_info.h"
+#include "net/quic/core/quic_client_promised_info.h"
+#include "net/quic/core/quic_crypto_client_stream_factory.h"
+#include "net/spdy/spdy_session.h"
+#include "net/ssl/channel_id_service.h"
+#include "net/ssl/ssl_connection_status_flags.h"
+#include "net/ssl/ssl_info.h"
+#include "net/ssl/token_binding.h"
+#include "net/udp/datagram_client_socket.h"
+
+namespace net {
+
+namespace {
+
+// IPv6 packets have an additional 20 bytes of overhead than IPv4 packets.
+const size_t kAdditionalOverheadForIPv6 = 20;
+
+// Maximum number of Readers that are created for any session due to
+// connection migration. A new Reader is created every time this endpoint's
+// IP address changes.
+const size_t kMaxReadersPerQuicSession = 5;
+
+// Size of the MRU cache of Token Binding signatures. Since the material being
+// signed is constant and there aren't many keys being used to sign, a fairly
+// small number was chosen, somewhat arbitrarily, and to match
+// SSLClientSocketImpl.
+const size_t kTokenBindingSignatureMapSize = 10;
+
+// Time to wait (in seconds) when no networks are available and
+// migrating sessions need to wait for a new network to connect.
+const size_t kWaitTimeForNewNetworkSecs = 10;
+
+// Histograms for tracking down the crashes from http://crbug.com/354669
+// Note: these values must be kept in sync with the corresponding values in:
+// tools/metrics/histograms/histograms.xml
+enum Location {
+ DESTRUCTOR = 0,
+ ADD_OBSERVER = 1,
+ TRY_CREATE_STREAM = 2,
+ CREATE_OUTGOING_RELIABLE_STREAM = 3,
+ NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER = 4,
+ NOTIFY_FACTORY_OF_SESSION_CLOSED = 5,
+ NUM_LOCATIONS = 6,
+};
+
+void RecordUnexpectedOpenStreams(Location location) {
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
+ NUM_LOCATIONS);
+}
+
+void RecordUnexpectedObservers(Location location) {
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
+ NUM_LOCATIONS);
+}
+
+void RecordUnexpectedNotGoingAway(Location location) {
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location,
+ NUM_LOCATIONS);
+}
+
+// Histogram for recording the different reasons that a QUIC session is unable
+// to complete the handshake.
+enum HandshakeFailureReason {
+ HANDSHAKE_FAILURE_UNKNOWN = 0,
+ HANDSHAKE_FAILURE_BLACK_HOLE = 1,
+ HANDSHAKE_FAILURE_PUBLIC_RESET = 2,
+ NUM_HANDSHAKE_FAILURE_REASONS = 3,
+};
+
+void RecordHandshakeFailureReason(HandshakeFailureReason reason) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason", reason,
+ NUM_HANDSHAKE_FAILURE_REASONS);
+}
+
+// Note: these values must be kept in sync with the corresponding values in:
+// tools/metrics/histograms/histograms.xml
+enum HandshakeState {
+ STATE_STARTED = 0,
+ STATE_ENCRYPTION_ESTABLISHED = 1,
+ STATE_HANDSHAKE_CONFIRMED = 2,
+ STATE_FAILED = 3,
+ NUM_HANDSHAKE_STATES = 4
+};
+
+void RecordHandshakeState(HandshakeState state) {
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
+ NUM_HANDSHAKE_STATES);
+}
+
+std::unique_ptr<base::Value> NetLogQuicClientSessionCallback(
+ const QuicServerId* server_id,
+ int cert_verify_flags,
+ bool require_confirmation,
+ NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetString("host", server_id->host());
+ dict->SetInteger("port", server_id->port());
+ dict->SetBoolean("privacy_mode",
+ server_id->privacy_mode() == PRIVACY_MODE_ENABLED);
+ dict->SetBoolean("require_confirmation", require_confirmation);
+ dict->SetInteger("cert_verify_flags", cert_verify_flags);
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicPushPromiseReceivedCallback(
+ const SpdyHeaderBlock* headers,
+ SpdyStreamId stream_id,
+ SpdyStreamId promised_stream_id,
+ NetLogCaptureMode capture_mode) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->Set("headers", ElideSpdyHeaderBlockForNetLog(*headers, capture_mode));
+ dict->SetInteger("id", stream_id);
+ dict->SetInteger("promised_stream_id", promised_stream_id);
+ return std::move(dict);
+}
+
+class HpackEncoderDebugVisitor : public QuicHeadersStream::HpackDebugVisitor {
+ void OnUseEntry(QuicTime::Delta elapsed) override {
+ UMA_HISTOGRAM_TIMES(
+ "Net.QuicHpackEncoder.IndexedEntryAge",
+ base::TimeDelta::FromMicroseconds(elapsed.ToMicroseconds()));
+ }
+};
+
+class HpackDecoderDebugVisitor : public QuicHeadersStream::HpackDebugVisitor {
+ void OnUseEntry(QuicTime::Delta elapsed) override {
+ UMA_HISTOGRAM_TIMES(
+ "Net.QuicHpackDecoder.IndexedEntryAge",
+ base::TimeDelta::FromMicroseconds(elapsed.ToMicroseconds()));
+ }
+};
+
+} // namespace
+
+QuicChromiumClientSession::StreamRequest::StreamRequest() : stream_(nullptr) {}
+
+QuicChromiumClientSession::StreamRequest::~StreamRequest() {
+ CancelRequest();
+}
+
+int QuicChromiumClientSession::StreamRequest::StartRequest(
+ const base::WeakPtr<QuicChromiumClientSession>& session,
+ QuicChromiumClientStream** stream,
+ const CompletionCallback& callback) {
+ session_ = session;
+ stream_ = stream;
+ int rv = session_->TryCreateStream(this, stream_);
+ if (rv == ERR_IO_PENDING) {
+ callback_ = callback;
+ }
+
+ return rv;
+}
+
+void QuicChromiumClientSession::StreamRequest::CancelRequest() {
+ if (session_)
+ session_->CancelRequest(this);
+ session_.reset();
+ callback_.Reset();
+}
+
+void QuicChromiumClientSession::StreamRequest::OnRequestCompleteSuccess(
+ QuicChromiumClientStream* stream) {
+ session_.reset();
+ *stream_ = stream;
+ base::ResetAndReturn(&callback_).Run(OK);
+}
+
+void QuicChromiumClientSession::StreamRequest::OnRequestCompleteFailure(
+ int rv) {
+ session_.reset();
+ base::ResetAndReturn(&callback_).Run(rv);
+}
+
+QuicChromiumClientSession::QuicChromiumClientSession(
+ QuicConnection* connection,
+ std::unique_ptr<DatagramClientSocket> socket,
+ QuicStreamFactory* stream_factory,
+ QuicCryptoClientStreamFactory* crypto_client_stream_factory,
+ QuicClock* clock,
+ TransportSecurityState* transport_security_state,
+ std::unique_ptr<QuicServerInfo> server_info,
+ const QuicServerId& server_id,
+ int yield_after_packets,
+ QuicTime::Delta yield_after_duration,
+ int cert_verify_flags,
+ const QuicConfig& config,
+ QuicCryptoClientConfig* crypto_config,
+ const char* const connection_description,
+ base::TimeTicks dns_resolution_start_time,
+ base::TimeTicks dns_resolution_end_time,
+ QuicClientPushPromiseIndex* push_promise_index,
+ base::TaskRunner* task_runner,
+ std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
+ NetLog* net_log)
+ : QuicClientSessionBase(connection, push_promise_index, config),
+ server_id_(server_id),
+ require_confirmation_(false),
+ stream_factory_(stream_factory),
+ transport_security_state_(transport_security_state),
+ server_info_(std::move(server_info)),
+ pkp_bypassed_(false),
+ num_total_streams_(0),
+ task_runner_(task_runner),
+ net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::QUIC_SESSION)),
+ logger_(new QuicConnectionLogger(this,
+ connection_description,
+ std::move(socket_performance_watcher),
+ net_log_)),
+ going_away_(false),
+ port_migration_detected_(false),
+ token_binding_signatures_(kTokenBindingSignatureMapSize),
+ streams_pushed_count_(0),
+ streams_pushed_and_claimed_count_(0),
+ migration_pending_(false),
+ weak_factory_(this) {
+ sockets_.push_back(std::move(socket));
+ packet_readers_.push_back(base::MakeUnique<QuicChromiumPacketReader>(
+ sockets_.back().get(), clock, this, yield_after_packets,
+ yield_after_duration, net_log_));
+ crypto_stream_.reset(
+ crypto_client_stream_factory->CreateQuicCryptoClientStream(
+ server_id, this, base::MakeUnique<ProofVerifyContextChromium>(
+ cert_verify_flags, net_log_),
+ crypto_config));
+ connection->set_debug_visitor(logger_.get());
+ connection->set_creator_debug_delegate(logger_.get());
+ net_log_.BeginEvent(NetLogEventType::QUIC_SESSION,
+ base::Bind(NetLogQuicClientSessionCallback, &server_id,
+ cert_verify_flags, require_confirmation_));
+ IPEndPoint address;
+ if (socket && socket->GetLocalAddress(&address) == OK &&
+ address.GetFamily() == ADDRESS_FAMILY_IPV6) {
+ connection->SetMaxPacketLength(connection->max_packet_length() -
+ kAdditionalOverheadForIPv6);
+ }
+ connect_timing_.dns_start = dns_resolution_start_time;
+ connect_timing_.dns_end = dns_resolution_end_time;
+}
+
+QuicChromiumClientSession::~QuicChromiumClientSession() {
+ if (!dynamic_streams().empty())
+ RecordUnexpectedOpenStreams(DESTRUCTOR);
+ if (!observers_.empty())
+ RecordUnexpectedObservers(DESTRUCTOR);
+ if (!going_away_)
+ RecordUnexpectedNotGoingAway(DESTRUCTOR);
+
+ while (!dynamic_streams().empty() || !observers_.empty() ||
+ !stream_requests_.empty()) {
+ // The session must be closed before it is destroyed.
+ DCHECK(dynamic_streams().empty());
+ CloseAllStreams(ERR_UNEXPECTED);
+ DCHECK(observers_.empty());
+ CloseAllObservers(ERR_UNEXPECTED);
+
+ connection()->set_debug_visitor(nullptr);
+ net_log_.EndEvent(NetLogEventType::QUIC_SESSION);
+
+ while (!stream_requests_.empty()) {
+ StreamRequest* request = stream_requests_.front();
+ stream_requests_.pop_front();
+ request->OnRequestCompleteFailure(ERR_ABORTED);
+ }
+ }
+
+ if (connection()->connected()) {
+ // Ensure that the connection is closed by the time the session is
+ // destroyed.
+ connection()->CloseConnection(QUIC_INTERNAL_ERROR, "session torn down",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+ }
+
+ if (IsEncryptionEstablished())
+ RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
+ if (IsCryptoHandshakeConfirmed())
+ RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
+ else
+ RecordHandshakeState(STATE_FAILED);
+
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
+ UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
+ crypto_stream_->num_sent_client_hellos());
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.Pushed", streams_pushed_count_);
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.PushedAndClaimed",
+ streams_pushed_and_claimed_count_);
+ if (!IsCryptoHandshakeConfirmed())
+ return;
+
+ // Sending one client_hello means we had zero handshake-round-trips.
+ int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
+
+ // Don't bother with these histogram during tests, which mock out
+ // num_sent_client_hellos().
+ if (round_trip_handshakes < 0 || !stream_factory_)
+ return;
+
+ bool port_selected = stream_factory_->enable_port_selection();
+ SSLInfo ssl_info;
+ // QUIC supports only secure urls.
+ if (GetSSLInfo(&ssl_info) && ssl_info.cert.get()) {
+ if (!port_selected) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
+ round_trip_handshakes, 1, 3, 4);
+ if (require_confirmation_) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
+ round_trip_handshakes, 1, 3, 4);
+ }
+ }
+ }
+ const QuicConnectionStats stats = connection()->GetStats();
+ if (server_info_ && stats.min_rtt_us > 0) {
+ base::TimeTicks wait_for_data_start_time =
+ server_info_->wait_for_data_start_time();
+ base::TimeTicks wait_for_data_end_time =
+ server_info_->wait_for_data_end_time();
+ if (!wait_for_data_start_time.is_null() &&
+ !wait_for_data_end_time.is_null()) {
+ base::TimeDelta wait_time =
+ wait_for_data_end_time - wait_for_data_start_time;
+ const base::HistogramBase::Sample kMaxWaitToRtt = 1000;
+ base::HistogramBase::Sample wait_to_rtt =
+ static_cast<base::HistogramBase::Sample>(
+ 100 * wait_time.InMicroseconds() / stats.min_rtt_us);
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicServerInfo.WaitForDataReadyToRtt",
+ wait_to_rtt, 1, kMaxWaitToRtt, 50);
+ }
+ }
+
+ // 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);
+
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.MtuProbesSent",
+ connection()->mtu_probe_count());
+
+ if (stats.packets_sent >= 100) {
+ // Used to monitor for regressions that effect large uploads.
+ UMA_HISTOGRAM_COUNTS_1000(
+ "Net.QuicSession.PacketRetransmitsPerMille",
+ 1000 * stats.packets_retransmitted / stats.packets_sent);
+ }
+
+ if (stats.max_sequence_reordering == 0)
+ return;
+ const base::HistogramBase::Sample kMaxReordering = 100;
+ base::HistogramBase::Sample reordering = kMaxReordering;
+ if (stats.min_rtt_us > 0) {
+ reordering = static_cast<base::HistogramBase::Sample>(
+ 100 * stats.max_time_reordering_us / stats.min_rtt_us);
+ }
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime", reordering,
+ 1, kMaxReordering, 50);
+ if (stats.min_rtt_us > 100 * 1000) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
+ reordering, 1, kMaxReordering, 50);
+ }
+ UMA_HISTOGRAM_COUNTS(
+ "Net.QuicSession.MaxReordering",
+ static_cast<base::HistogramBase::Sample>(stats.max_sequence_reordering));
+}
+
+void QuicChromiumClientSession::Initialize() {
+ QuicClientSessionBase::Initialize();
+ headers_stream()->SetHpackEncoderDebugVisitor(
+ base::MakeUnique<HpackEncoderDebugVisitor>());
+ headers_stream()->SetHpackDecoderDebugVisitor(
+ base::MakeUnique<HpackDecoderDebugVisitor>());
+}
+
+void QuicChromiumClientSession::OnHeadersHeadOfLineBlocking(
+ QuicTime::Delta delta) {
+ UMA_HISTOGRAM_TIMES(
+ "Net.QuicSession.HeadersHOLBlockedTime",
+ base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()));
+}
+
+void QuicChromiumClientSession::OnStreamFrame(const QuicStreamFrame& frame) {
+ // Record total number of stream frames.
+ UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", 1);
+
+ // Record number of frames per stream in packet.
+ UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket", 1);
+
+ return QuicSpdySession::OnStreamFrame(frame);
+}
+
+void QuicChromiumClientSession::AddObserver(Observer* observer) {
+ if (going_away_) {
+ RecordUnexpectedObservers(ADD_OBSERVER);
+ observer->OnSessionClosed(ERR_UNEXPECTED, port_migration_detected_);
+ return;
+ }
+
+ DCHECK(!base::ContainsKey(observers_, observer));
+ observers_.insert(observer);
+}
+
+void QuicChromiumClientSession::RemoveObserver(Observer* observer) {
+ DCHECK(base::ContainsKey(observers_, observer));
+ observers_.erase(observer);
+}
+
+int QuicChromiumClientSession::TryCreateStream(
+ StreamRequest* request,
+ QuicChromiumClientStream** stream) {
+ if (goaway_received()) {
+ DVLOG(1) << "Going away.";
+ return ERR_CONNECTION_CLOSED;
+ }
+
+ if (!connection()->connected()) {
+ DVLOG(1) << "Already closed.";
+ return ERR_CONNECTION_CLOSED;
+ }
+
+ if (going_away_) {
+ RecordUnexpectedOpenStreams(TRY_CREATE_STREAM);
+ return ERR_CONNECTION_CLOSED;
+ }
+
+ if (GetNumOpenOutgoingStreams() < max_open_outgoing_streams()) {
+ *stream = CreateOutgoingReliableStreamImpl();
+ return OK;
+ }
+
+ stream_requests_.push_back(request);
+ return ERR_IO_PENDING;
+}
+
+void QuicChromiumClientSession::CancelRequest(StreamRequest* request) {
+ // Remove |request| from the queue while preserving the order of the
+ // other elements.
+ StreamRequestQueue::iterator it =
+ std::find(stream_requests_.begin(), stream_requests_.end(), request);
+ if (it != stream_requests_.end()) {
+ it = stream_requests_.erase(it);
+ }
+}
+
+bool QuicChromiumClientSession::ShouldCreateOutgoingDynamicStream() {
+ if (!crypto_stream_->encryption_established()) {
+ DVLOG(1) << "Encryption not active so no outgoing stream created.";
+ return false;
+ }
+ if (GetNumOpenOutgoingStreams() >= max_open_outgoing_streams()) {
+ DVLOG(1) << "Failed to create a new outgoing stream. "
+ << "Already " << GetNumOpenOutgoingStreams() << " open.";
+ return false;
+ }
+ if (goaway_received()) {
+ DVLOG(1) << "Failed to create a new outgoing stream. "
+ << "Already received goaway.";
+ return false;
+ }
+ if (going_away_) {
+ RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM);
+ return false;
+ }
+ return true;
+}
+
+QuicChromiumClientStream*
+QuicChromiumClientSession::CreateOutgoingDynamicStream(SpdyPriority priority) {
+ if (!ShouldCreateOutgoingDynamicStream()) {
+ return nullptr;
+ }
+ QuicChromiumClientStream* stream = CreateOutgoingReliableStreamImpl();
+ if (stream != nullptr)
+ stream->SetPriority(priority);
+ return stream;
+}
+
+QuicChromiumClientStream*
+QuicChromiumClientSession::CreateOutgoingReliableStreamImpl() {
+ DCHECK(connection()->connected());
+ QuicChromiumClientStream* stream =
+ new QuicChromiumClientStream(GetNextOutgoingStreamId(), this, net_log_);
+ ActivateStream(stream);
+ ++num_total_streams_;
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams",
+ GetNumOpenOutgoingStreams());
+ // The previous histogram puts 100 in a bucket betweeen 86-113 which does
+ // not shed light on if chrome ever things it has more than 100 streams open.
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.TooManyOpenStreams",
+ GetNumOpenOutgoingStreams() > 100);
+ return stream;
+}
+
+QuicCryptoClientStream* QuicChromiumClientSession::GetCryptoStream() {
+ return crypto_stream_.get();
+}
+
+// TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
+// we learn about SSL info (sync vs async vs cached).
+bool QuicChromiumClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
+ ssl_info->Reset();
+ if (!cert_verify_result_) {
+ return false;
+ }
+
+ ssl_info->cert_status = cert_verify_result_->cert_status;
+ ssl_info->cert = cert_verify_result_->verified_cert;
+
+ // TODO(wtc): Define QUIC "cipher suites".
+ // Report the TLS cipher suite that most closely resembles the crypto
+ // parameters of the QUIC connection.
+ QuicTag aead = crypto_stream_->crypto_negotiated_params().aead;
+ uint16_t cipher_suite;
+ int security_bits;
+ switch (aead) {
+ case kAESG:
+ cipher_suite = 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ security_bits = 128;
+ break;
+ case kCC20:
+ cipher_suite = 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+ security_bits = 256;
+ break;
+ default:
+ NOTREACHED();
+ return false;
+ }
+ int ssl_connection_status = 0;
+ SSLConnectionStatusSetCipherSuite(cipher_suite, &ssl_connection_status);
+ SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_QUIC,
+ &ssl_connection_status);
+
+ // Report the QUIC key exchange as the corresponding TLS curve.
+ switch (crypto_stream_->crypto_negotiated_params().key_exchange) {
+ case kP256:
+ ssl_info->key_exchange_group = SSL_CURVE_SECP256R1;
+ break;
+ case kC255:
+ ssl_info->key_exchange_group = SSL_CURVE_X25519;
+ break;
+ default:
+ NOTREACHED();
+ return false;
+ }
+
+ ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
+ ssl_info->is_issued_by_known_root =
+ cert_verify_result_->is_issued_by_known_root;
+ ssl_info->pkp_bypassed = pkp_bypassed_;
+
+ ssl_info->connection_status = ssl_connection_status;
+ ssl_info->client_cert_sent = false;
+ ssl_info->channel_id_sent = crypto_stream_->WasChannelIDSent();
+ ssl_info->security_bits = security_bits;
+ ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
+ ssl_info->pinning_failure_log = pinning_failure_log_;
+
+ ssl_info->UpdateCertificateTransparencyInfo(*ct_verify_result_);
+
+ if (crypto_stream_->crypto_negotiated_params().token_binding_key_param ==
+ kTB10) {
+ ssl_info->token_binding_negotiated = true;
+ ssl_info->token_binding_key_param = TB_PARAM_ECDSAP256;
+ }
+
+ return true;
+}
+
+Error QuicChromiumClientSession::GetTokenBindingSignature(
+ crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) {
+ // The same key will be used across multiple requests to sign the same value,
+ // so the signature is cached.
+ std::string raw_public_key;
+ if (!key->ExportRawPublicKey(&raw_public_key))
+ return ERR_FAILED;
+ TokenBindingSignatureMap::iterator it =
+ token_binding_signatures_.Get(std::make_pair(tb_type, raw_public_key));
+ if (it != token_binding_signatures_.end()) {
+ *out = it->second;
+ return OK;
+ }
+
+ std::string key_material;
+ if (!crypto_stream_->ExportTokenBindingKeyingMaterial(&key_material))
+ return ERR_FAILED;
+ if (!CreateTokenBindingSignature(key_material, tb_type, key, out))
+ return ERR_FAILED;
+ token_binding_signatures_.Put(std::make_pair(tb_type, raw_public_key), *out);
+ return OK;
+}
+
+int QuicChromiumClientSession::CryptoConnect(
+ bool require_confirmation,
+ const CompletionCallback& callback) {
+ require_confirmation_ = require_confirmation;
+ connect_timing_.connect_start = base::TimeTicks::Now();
+ RecordHandshakeState(STATE_STARTED);
+ DCHECK(flow_controller());
+ crypto_stream_->CryptoConnect();
+
+ if (IsCryptoHandshakeConfirmed()) {
+ connect_timing_.connect_end = base::TimeTicks::Now();
+ return OK;
+ }
+
+ // Unless we require handshake confirmation, activate the session if
+ // we have established initial encryption.
+ if (!require_confirmation_ && IsEncryptionEstablished())
+ return OK;
+
+ callback_ = callback;
+ return ERR_IO_PENDING;
+}
+
+int QuicChromiumClientSession::ResumeCryptoConnect(
+ const CompletionCallback& callback) {
+ if (IsCryptoHandshakeConfirmed()) {
+ connect_timing_.connect_end = base::TimeTicks::Now();
+ return OK;
+ }
+
+ if (!connection()->connected())
+ return ERR_QUIC_HANDSHAKE_FAILED;
+
+ callback_ = callback;
+ return ERR_IO_PENDING;
+}
+
+int QuicChromiumClientSession::GetNumSentClientHellos() const {
+ return crypto_stream_->num_sent_client_hellos();
+}
+
+QuicStreamId QuicChromiumClientSession::GetStreamIdForPush(
+ const GURL& pushed_url) {
+ QuicClientPromisedInfo* promised_info =
+ QuicClientSessionBase::GetPromisedByUrl(pushed_url.spec());
+ if (!promised_info)
+ return 0;
+
+ return promised_info->id();
+}
+
+bool QuicChromiumClientSession::CanPool(const std::string& hostname,
+ PrivacyMode privacy_mode) const {
+ DCHECK(connection()->connected());
+ if (privacy_mode != server_id_.privacy_mode()) {
+ // Privacy mode must always match.
+ return false;
+ }
+ SSLInfo ssl_info;
+ if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
+ NOTREACHED() << "QUIC should always have certificates.";
+ return false;
+ }
+
+ return SpdySession::CanPool(transport_security_state_, ssl_info,
+ server_id_.host(), hostname);
+}
+
+bool QuicChromiumClientSession::ShouldCreateIncomingDynamicStream(
+ QuicStreamId id) {
+ if (!connection()->connected()) {
+ LOG(DFATAL) << "ShouldCreateIncomingDynamicStream called when disconnected";
+ return false;
+ }
+ if (goaway_received()) {
+ DVLOG(1) << "Cannot create a new outgoing stream. "
+ << "Already received goaway.";
+ return false;
+ }
+ if (going_away_) {
+ return false;
+ }
+ if (id % 2 != 0) {
+ LOG(WARNING) << "Received invalid push stream id " << id;
+ connection()->CloseConnection(
+ QUIC_INVALID_STREAM_ID, "Server created odd numbered stream",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+ return true;
+}
+
+QuicChromiumClientStream*
+QuicChromiumClientSession::CreateIncomingDynamicStream(QuicStreamId id) {
+ if (!ShouldCreateIncomingDynamicStream(id)) {
+ return nullptr;
+ }
+ return CreateIncomingReliableStreamImpl(id);
+}
+
+QuicChromiumClientStream*
+QuicChromiumClientSession::CreateIncomingReliableStreamImpl(QuicStreamId id) {
+ DCHECK(connection()->connected());
+ QuicChromiumClientStream* stream =
+ new QuicChromiumClientStream(id, this, net_log_);
+ stream->CloseWriteSide();
+ ActivateStream(stream);
+ ++num_total_streams_;
+ return stream;
+}
+
+void QuicChromiumClientSession::CloseStream(QuicStreamId stream_id) {
+ ReliableQuicStream* stream = GetOrCreateStream(stream_id);
+ if (stream) {
+ logger_->UpdateReceivedFrameCounts(stream_id, stream->num_frames_received(),
+ stream->num_duplicate_frames_received());
+ }
+ QuicSpdySession::CloseStream(stream_id);
+ OnClosedStream();
+}
+
+void QuicChromiumClientSession::SendRstStream(QuicStreamId id,
+ QuicRstStreamErrorCode error,
+ QuicStreamOffset bytes_written) {
+ QuicSpdySession::SendRstStream(id, error, bytes_written);
+ OnClosedStream();
+}
+
+void QuicChromiumClientSession::OnClosedStream() {
+ if (GetNumOpenOutgoingStreams() < max_open_outgoing_streams() &&
+ !stream_requests_.empty() && crypto_stream_->encryption_established() &&
+ !goaway_received() && !going_away_ && connection()->connected()) {
+ StreamRequest* request = stream_requests_.front();
+ stream_requests_.pop_front();
+ request->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
+ }
+
+ if (GetNumOpenOutgoingStreams() == 0 && stream_factory_) {
+ stream_factory_->OnIdleSession(this);
+ }
+}
+
+void QuicChromiumClientSession::OnConfigNegotiated() {
+ QuicClientSessionBase::OnConfigNegotiated();
+ if (!stream_factory_ || !config()->HasReceivedAlternateServerAddress())
+ return;
+
+ // Server has sent an alternate address to connect to.
+ IPEndPoint new_address = config()->ReceivedAlternateServerAddress();
+ IPEndPoint old_address;
+ GetDefaultSocket()->GetPeerAddress(&old_address);
+
+ // Migrate only if address families match, or if new address family is v6,
+ // since a v4 address should be reachable over a v6 network (using a
+ // v4-mapped v6 address).
+ if (old_address.GetFamily() != new_address.GetFamily() &&
+ old_address.GetFamily() == ADDRESS_FAMILY_IPV4) {
+ return;
+ }
+
+ if (old_address.GetFamily() != new_address.GetFamily()) {
+ DCHECK_EQ(old_address.GetFamily(), ADDRESS_FAMILY_IPV6);
+ DCHECK_EQ(new_address.GetFamily(), ADDRESS_FAMILY_IPV4);
+ // Use a v4-mapped v6 address.
+ new_address = IPEndPoint(ConvertIPv4ToIPv4MappedIPv6(new_address.address()),
+ new_address.port());
+ }
+
+ stream_factory_->MigrateSessionToNewPeerAddress(this, new_address, net_log_);
+}
+
+void QuicChromiumClientSession::OnCryptoHandshakeEvent(
+ CryptoHandshakeEvent event) {
+ if (stream_factory_ && event == HANDSHAKE_CONFIRMED &&
+ stream_factory_->OnHandshakeConfirmed(this)) {
+ return;
+ }
+
+ if (!callback_.is_null() &&
+ (!require_confirmation_ || event == HANDSHAKE_CONFIRMED ||
+ event == ENCRYPTION_REESTABLISHED)) {
+ // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
+ // could be called because there are no error events in CryptoHandshakeEvent
+ // enum. If error events are added to CryptoHandshakeEvent, then the
+ // following code needs to changed.
+ base::ResetAndReturn(&callback_).Run(OK);
+ }
+ if (event == HANDSHAKE_CONFIRMED) {
+ // Update |connect_end| only when handshake is confirmed. This should also
+ // take care of any failed 0-RTT request.
+ connect_timing_.connect_end = base::TimeTicks::Now();
+ DCHECK(connect_timing_.connect_start < connect_timing_.connect_end);
+ UMA_HISTOGRAM_TIMES(
+ "Net.QuicSession.HandshakeConfirmedTime",
+ connect_timing_.connect_end - connect_timing_.connect_start);
+
+ if (server_info_) {
+ // TODO(rtenneti): Should we delete this histogram?
+ // Track how long it has taken to finish handshake once we start waiting
+ // for reading of QUIC server information from disk cache. We could use
+ // this data to compare total time taken if we were to cancel the disk
+ // cache read vs waiting for the read to complete.
+ base::TimeTicks wait_for_data_start_time =
+ server_info_->wait_for_data_start_time();
+ if (!wait_for_data_start_time.is_null()) {
+ UMA_HISTOGRAM_TIMES(
+ "Net.QuicServerInfo.WaitForDataReady.HandshakeConfirmedTime",
+ base::TimeTicks::Now() - wait_for_data_start_time);
+ }
+ }
+ // Track how long it has taken to finish handshake after we have finished
+ // DNS host resolution.
+ if (!connect_timing_.dns_end.is_null()) {
+ UMA_HISTOGRAM_TIMES(
+ "Net.QuicSession.HostResolution.HandshakeConfirmedTime",
+ base::TimeTicks::Now() - connect_timing_.dns_end);
+ }
+
+ ObserverSet::iterator it = observers_.begin();
+ while (it != observers_.end()) {
+ Observer* observer = *it;
+ ++it;
+ observer->OnCryptoHandshakeConfirmed();
+ }
+ if (server_info_)
+ server_info_->OnExternalCacheHit();
+ }
+ QuicSpdySession::OnCryptoHandshakeEvent(event);
+}
+
+void QuicChromiumClientSession::OnCryptoHandshakeMessageSent(
+ const CryptoHandshakeMessage& message) {
+ logger_->OnCryptoHandshakeMessageSent(message);
+}
+
+void QuicChromiumClientSession::OnCryptoHandshakeMessageReceived(
+ const CryptoHandshakeMessage& message) {
+ logger_->OnCryptoHandshakeMessageReceived(message);
+ if (message.tag() == kREJ || message.tag() == kSREJ) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.RejectLength",
+ message.GetSerialized().length(), 1000, 10000,
+ 50);
+ base::StringPiece proof;
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.RejectHasProof",
+ message.GetStringPiece(kPROF, &proof));
+ }
+}
+
+void QuicChromiumClientSession::OnGoAway(const QuicGoAwayFrame& frame) {
+ QuicSession::OnGoAway(frame);
+ NotifyFactoryOfSessionGoingAway();
+ port_migration_detected_ = frame.error_code == QUIC_ERROR_MIGRATING_PORT;
+}
+
+void QuicChromiumClientSession::OnRstStream(const QuicRstStreamFrame& frame) {
+ QuicSession::OnRstStream(frame);
+ OnClosedStream();
+}
+
+void QuicChromiumClientSession::OnConnectionClosed(
+ QuicErrorCode error,
+ const std::string& error_details,
+ ConnectionCloseSource source) {
+ DCHECK(!connection()->connected());
+ logger_->OnConnectionClosed(error, error_details, source);
+ if (source == ConnectionCloseSource::FROM_PEER) {
+ if (IsCryptoHandshakeConfirmed()) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "Net.QuicSession.ConnectionCloseErrorCodeServer.HandshakeConfirmed",
+ error);
+ base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
+ "Net.QuicSession.StreamCloseErrorCodeServer.HandshakeConfirmed",
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ size_t num_streams = GetNumActiveStreams();
+ if (num_streams > 0)
+ histogram->AddCount(error, num_streams);
+ }
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
+ } else {
+ if (IsCryptoHandshakeConfirmed()) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "Net.QuicSession.ConnectionCloseErrorCodeClient.HandshakeConfirmed",
+ error);
+ base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
+ "Net.QuicSession.StreamCloseErrorCodeClient.HandshakeConfirmed",
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ size_t num_streams = GetNumActiveStreams();
+ if (num_streams > 0)
+ histogram->AddCount(error, num_streams);
+ }
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "Net.QuicSession.ConnectionCloseErrorCodeClient", error);
+ }
+
+ if (error == QUIC_NETWORK_IDLE_TIMEOUT) {
+ UMA_HISTOGRAM_COUNTS(
+ "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
+ GetNumOpenOutgoingStreams());
+ // Notify the factory the connection timed out with open streams.
+ if (GetNumOpenOutgoingStreams() > 0 && stream_factory_) {
+ stream_factory_->OnTimeoutWithOpenStreams();
+ }
+ if (IsCryptoHandshakeConfirmed()) {
+ if (GetNumOpenOutgoingStreams() > 0) {
+ UMA_HISTOGRAM_BOOLEAN(
+ "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
+ connection()->sent_packet_manager().HasUnackedPackets());
+ UMA_HISTOGRAM_COUNTS(
+ "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveRTOCount",
+ connection()->sent_packet_manager().GetConsecutiveRtoCount());
+ UMA_HISTOGRAM_COUNTS(
+ "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
+ connection()->sent_packet_manager().GetConsecutiveTlpCount());
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "Net.QuicSession.TimedOutWithOpenStreams.LocalPort",
+ connection()->self_address().port());
+ }
+ } else {
+ UMA_HISTOGRAM_COUNTS(
+ "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
+ GetNumOpenOutgoingStreams());
+ UMA_HISTOGRAM_COUNTS(
+ "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
+ num_total_streams_);
+ }
+ }
+
+ if (!IsCryptoHandshakeConfirmed()) {
+ if (error == QUIC_PUBLIC_RESET) {
+ RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
+ } else if (connection()->GetStats().packets_received == 0) {
+ RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
+ error);
+ } else {
+ RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
+ error);
+ }
+ }
+
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
+ connection()->version());
+ NotifyFactoryOfSessionGoingAway();
+ QuicSession::OnConnectionClosed(error, error_details, source);
+
+ if (!callback_.is_null()) {
+ base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
+ }
+
+ for (auto& socket : sockets_) {
+ socket->Close();
+ }
+ DCHECK(dynamic_streams().empty());
+ CloseAllStreams(ERR_UNEXPECTED);
+ CloseAllObservers(ERR_UNEXPECTED);
+ NotifyFactoryOfSessionClosedLater();
+}
+
+void QuicChromiumClientSession::OnSuccessfulVersionNegotiation(
+ const QuicVersion& version) {
+ logger_->OnSuccessfulVersionNegotiation(version);
+ QuicSpdySession::OnSuccessfulVersionNegotiation(version);
+}
+
+int QuicChromiumClientSession::HandleWriteError(
+ int error_code,
+ scoped_refptr<StringIOBuffer> packet) {
+ if (stream_factory_ == nullptr ||
+ !stream_factory_->migrate_sessions_on_network_change()) {
+ return error_code;
+ }
+ DCHECK(packet != nullptr);
+ DCHECK_NE(ERR_IO_PENDING, error_code);
+ DCHECK_GT(0, error_code);
+ DCHECK(!migration_pending_);
+ DCHECK(packet_ == nullptr);
+
+ // Post a task to migrate the session onto a new network.
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&QuicChromiumClientSession::MigrateSessionOnWriteError,
+ weak_factory_.GetWeakPtr()));
+
+ // Store packet in the session since the actual migration and packet rewrite
+ // can happen via this posted task or via an async network notification.
+ packet_ = packet;
+ migration_pending_ = true;
+
+ // Cause the packet writer to return ERR_IO_PENDING and block so
+ // that the actual migration happens from the message loop instead
+ // of under the call stack of QuicConnection::WritePacket.
+ return ERR_IO_PENDING;
+}
+
+void QuicChromiumClientSession::MigrateSessionOnWriteError() {
+ // If migration_pending_ is false, an earlier task completed migration.
+ if (!migration_pending_)
+ return;
+
+ MigrationResult result = MigrationResult::FAILURE;
+ if (stream_factory_ != nullptr)
+ result = stream_factory_->MaybeMigrateSingleSession(this, WRITE_ERROR);
+
+ if (result == MigrationResult::SUCCESS)
+ return;
+
+ if (result == MigrationResult::NO_NEW_NETWORK) {
+ OnNoNewNetwork();
+ return;
+ }
+
+ // Close the connection if migration failed. Do not cause a
+ // connection close packet to be sent since socket may be borked.
+ connection()->CloseConnection(QUIC_PACKET_WRITE_ERROR,
+ "Write and subsequent migration failed",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+}
+
+void QuicChromiumClientSession::OnNoNewNetwork() {
+ migration_pending_ = true;
+
+ // Block the packet writer to avoid any writes while migration is in progress.
+ static_cast<QuicChromiumPacketWriter*>(connection()->writer())
+ ->set_write_blocked(true);
+
+ // Post a task to maybe close the session if the alarm fires.
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&QuicChromiumClientSession::OnMigrationTimeout,
+ weak_factory_.GetWeakPtr(), sockets_.size()),
+ base::TimeDelta::FromSeconds(kWaitTimeForNewNetworkSecs));
+}
+
+void QuicChromiumClientSession::WriteToNewSocket() {
+ // Prevent any pending migration from executing.
+ migration_pending_ = false;
+ static_cast<QuicChromiumPacketWriter*>(connection()->writer())
+ ->set_write_blocked(false);
+ if (packet_ == nullptr) {
+ // Unblock the connection before sending a PING packet, since it
+ // may have been blocked before the migration started.
+ connection()->OnCanWrite();
+ connection()->SendPing();
+ return;
+ }
+
+ // Set packet_ to null first before calling WritePacketToSocket since
+ // that method may set packet_ if there is a write error.
+ scoped_refptr<StringIOBuffer> packet = packet_;
+ packet_ = nullptr;
+
+ // The connection is waiting for the original write to complete
+ // asynchronously. The new writer will notify the connection if the
+ // write below completes asynchronously, but a synchronous competion
+ // must be propagated back to the connection here.
+ WriteResult result =
+ static_cast<QuicChromiumPacketWriter*>(connection()->writer())
+ ->WritePacketToSocket(packet);
+ if (result.error_code == ERR_IO_PENDING)
+ return;
+
+ // All write errors should be mapped into ERR_IO_PENDING by
+ // HandleWriteError.
+ DCHECK_LT(0, result.error_code);
+ connection()->OnCanWrite();
+}
+
+void QuicChromiumClientSession::OnMigrationTimeout(size_t num_sockets) {
+ // If number of sockets has changed, this migration task is stale.
+ if (num_sockets != sockets_.size())
+ return;
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionMigration",
+ MIGRATION_STATUS_NO_ALTERNATE_NETWORK,
+ MIGRATION_STATUS_MAX);
+ CloseSessionOnError(ERR_NETWORK_CHANGED,
+ QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK);
+}
+
+void QuicChromiumClientSession::OnNetworkConnected(
+ NetworkChangeNotifier::NetworkHandle network,
+ const NetLogWithSource& net_log) {
+ // If migration_pending_ is false, there was no migration pending or
+ // an earlier task completed migration.
+ if (!migration_pending_)
+ return;
+
+ // TODO(jri): Ensure that OnSessionGoingAway is called consistently,
+ // and that it's always called at the same time in the whole
+ // migration process. Allows tests to be more uniform.
+ stream_factory_->OnSessionGoingAway(this);
+ stream_factory_->MigrateSessionToNewNetwork(
+ this, network, /*close_session_on_error=*/true, net_log_);
+}
+
+void QuicChromiumClientSession::OnWriteError(int error_code) {
+ DCHECK_NE(ERR_IO_PENDING, error_code);
+ DCHECK_GT(0, error_code);
+ connection()->OnWriteError(error_code);
+}
+
+void QuicChromiumClientSession::OnWriteUnblocked() {
+ connection()->OnCanWrite();
+}
+
+void QuicChromiumClientSession::OnPathDegrading() {
+ if (stream_factory_) {
+ stream_factory_->MaybeMigrateSingleSession(this, EARLY_MIGRATION);
+ }
+}
+
+bool QuicChromiumClientSession::HasOpenDynamicStreams() const {
+ return QuicSession::HasOpenDynamicStreams() ||
+ GetNumDrainingOutgoingStreams() > 0;
+}
+
+void QuicChromiumClientSession::OnProofValid(
+ const QuicCryptoClientConfig::CachedState& cached) {
+ DCHECK(cached.proof_valid());
+
+ if (!server_info_) {
+ return;
+ }
+
+ QuicServerInfo::State* state = server_info_->mutable_state();
+
+ state->server_config = cached.server_config();
+ state->source_address_token = cached.source_address_token();
+ state->cert_sct = cached.cert_sct();
+ state->chlo_hash = cached.chlo_hash();
+ state->server_config_sig = cached.signature();
+ state->certs = cached.certs();
+
+ server_info_->Persist();
+}
+
+void QuicChromiumClientSession::OnProofVerifyDetailsAvailable(
+ const ProofVerifyDetails& verify_details) {
+ const ProofVerifyDetailsChromium* verify_details_chromium =
+ reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
+ cert_verify_result_.reset(
+ new CertVerifyResult(verify_details_chromium->cert_verify_result));
+ pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
+ std::unique_ptr<ct::CTVerifyResult> ct_verify_result_copy(
+ new ct::CTVerifyResult(verify_details_chromium->ct_verify_result));
+ ct_verify_result_ = std::move(ct_verify_result_copy);
+ logger_->OnCertificateVerified(*cert_verify_result_);
+ pkp_bypassed_ = verify_details_chromium->pkp_bypassed;
+}
+
+void QuicChromiumClientSession::StartReading() {
+ for (auto& packet_reader : packet_readers_) {
+ packet_reader->StartReading();
+ }
+}
+
+void QuicChromiumClientSession::CloseSessionOnError(int error,
+ QuicErrorCode quic_error) {
+ RecordAndCloseSessionOnError(error, quic_error);
+ NotifyFactoryOfSessionClosed();
+}
+
+void QuicChromiumClientSession::CloseSessionOnErrorAndNotifyFactoryLater(
+ int error,
+ QuicErrorCode quic_error) {
+ RecordAndCloseSessionOnError(error, quic_error);
+ NotifyFactoryOfSessionClosedLater();
+}
+
+void QuicChromiumClientSession::RecordAndCloseSessionOnError(
+ int error,
+ QuicErrorCode quic_error) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
+ CloseSessionOnErrorInner(error, quic_error);
+}
+
+void QuicChromiumClientSession::CloseSessionOnErrorInner(
+ int net_error,
+ QuicErrorCode quic_error) {
+ if (!callback_.is_null()) {
+ base::ResetAndReturn(&callback_).Run(net_error);
+ }
+ CloseAllStreams(net_error);
+ CloseAllObservers(net_error);
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CLOSE_ON_ERROR,
+ NetLog::IntCallback("net_error", net_error));
+
+ if (connection()->connected())
+ connection()->CloseConnection(quic_error, "net error",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+ DCHECK(!connection()->connected());
+}
+
+void QuicChromiumClientSession::CloseAllStreams(int net_error) {
+ while (!dynamic_streams().empty()) {
+ ReliableQuicStream* stream = dynamic_streams().begin()->second;
+ QuicStreamId id = stream->id();
+ static_cast<QuicChromiumClientStream*>(stream)->OnError(net_error);
+ CloseStream(id);
+ }
+}
+
+void QuicChromiumClientSession::CloseAllObservers(int net_error) {
+ while (!observers_.empty()) {
+ Observer* observer = *observers_.begin();
+ observers_.erase(observer);
+ observer->OnSessionClosed(net_error, port_migration_detected_);
+ }
+}
+
+std::unique_ptr<base::Value> QuicChromiumClientSession::GetInfoAsValue(
+ const std::set<HostPortPair>& aliases) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetString("version", QuicVersionToString(connection()->version()));
+ dict->SetInteger("open_streams", GetNumOpenOutgoingStreams());
+ std::unique_ptr<base::ListValue> stream_list(new base::ListValue());
+ for (DynamicStreamMap::const_iterator it = dynamic_streams().begin();
+ it != dynamic_streams().end(); ++it) {
+ stream_list->AppendString(base::UintToString(it->second->id()));
+ }
+ dict->Set("active_streams", std::move(stream_list));
+
+ dict->SetInteger("total_streams", num_total_streams_);
+ dict->SetString("peer_address", peer_address().ToString());
+ dict->SetString("connection_id", base::Uint64ToString(connection_id()));
+ dict->SetBoolean("connected", connection()->connected());
+ const QuicConnectionStats& stats = connection()->GetStats();
+ dict->SetInteger("packets_sent", stats.packets_sent);
+ dict->SetInteger("packets_received", stats.packets_received);
+ dict->SetInteger("packets_lost", stats.packets_lost);
+ SSLInfo ssl_info;
+ dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert.get());
+
+ std::unique_ptr<base::ListValue> alias_list(new base::ListValue());
+ for (std::set<HostPortPair>::const_iterator it = aliases.begin();
+ it != aliases.end(); it++) {
+ alias_list->AppendString(it->ToString());
+ }
+ dict->Set("aliases", std::move(alias_list));
+
+ return std::move(dict);
+}
+
+base::WeakPtr<QuicChromiumClientSession>
+QuicChromiumClientSession::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
+void QuicChromiumClientSession::OnReadError(
+ int result,
+ const DatagramClientSocket* socket) {
+ DCHECK(socket != nullptr);
+ if (socket != GetDefaultSocket()) {
+ // Ignore read errors from old sockets that are no longer active.
+ // TODO(jri): Maybe clean up old sockets on error.
+ return;
+ }
+ DVLOG(1) << "Closing session on read error: " << result;
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
+ NotifyFactoryOfSessionGoingAway();
+ CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
+ NotifyFactoryOfSessionClosedLater();
+}
+
+bool QuicChromiumClientSession::OnPacket(const QuicReceivedPacket& packet,
+ IPEndPoint local_address,
+ IPEndPoint peer_address) {
+ ProcessUdpPacket(local_address, peer_address, packet);
+ if (!connection()->connected()) {
+ NotifyFactoryOfSessionClosedLater();
+ return false;
+ }
+ return true;
+}
+
+void QuicChromiumClientSession::NotifyFactoryOfSessionGoingAway() {
+ going_away_ = true;
+ if (stream_factory_)
+ stream_factory_->OnSessionGoingAway(this);
+}
+
+void QuicChromiumClientSession::NotifyFactoryOfSessionClosedLater() {
+ if (!dynamic_streams().empty())
+ RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
+
+ if (!going_away_)
+ RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
+
+ going_away_ = true;
+ DCHECK_EQ(0u, GetNumActiveStreams());
+ DCHECK(!connection()->connected());
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&QuicChromiumClientSession::NotifyFactoryOfSessionClosed,
+ weak_factory_.GetWeakPtr()));
+}
+
+void QuicChromiumClientSession::NotifyFactoryOfSessionClosed() {
+ if (!dynamic_streams().empty())
+ RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
+
+ if (!going_away_)
+ RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
+
+ going_away_ = true;
+ DCHECK_EQ(0u, GetNumActiveStreams());
+ // Will delete |this|.
+ if (stream_factory_)
+ stream_factory_->OnSessionClosed(this);
+}
+
+bool QuicChromiumClientSession::MigrateToSocket(
+ std::unique_ptr<DatagramClientSocket> socket,
+ std::unique_ptr<QuicChromiumPacketReader> reader,
+ std::unique_ptr<QuicChromiumPacketWriter> writer) {
+ DCHECK_EQ(sockets_.size(), packet_readers_.size());
+ if (sockets_.size() >= kMaxReadersPerQuicSession)
+ return false;
+
+ // TODO(jri): Make SetQuicPacketWriter take a scoped_ptr.
+ packet_readers_.push_back(std::move(reader));
+ sockets_.push_back(std::move(socket));
+ StartReading();
+ // Block the writer to prevent is being used until WriteToNewSocket
+ // completes.
+ writer->set_write_blocked(true);
+ connection()->SetQuicPacketWriter(writer.release(), /*owns_writer=*/true);
+
+ // Post task to write the pending packet or a PING packet to the new
+ // socket. This avoids reentrancy issues if there is a write error
+ // on the write to the new socket.
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&QuicChromiumClientSession::WriteToNewSocket,
+ weak_factory_.GetWeakPtr()));
+ // Migration completed.
+ migration_pending_ = false;
+ return true;
+}
+
+void QuicChromiumClientSession::PopulateNetErrorDetails(
+ NetErrorDetails* details) {
+ details->quic_port_migration_detected = port_migration_detected_;
+}
+
+const DatagramClientSocket* QuicChromiumClientSession::GetDefaultSocket()
+ const {
+ DCHECK(sockets_.back().get() != nullptr);
+ // The most recently added socket is the currently active one.
+ return sockets_.back().get();
+}
+
+bool QuicChromiumClientSession::IsAuthorized(const std::string& hostname) {
+ bool result = CanPool(hostname, server_id_.privacy_mode());
+ if (result)
+ streams_pushed_count_++;
+ return result;
+}
+
+bool QuicChromiumClientSession::HasNonMigratableStreams() const {
+ for (const auto& stream : dynamic_streams()) {
+ if (!static_cast<QuicChromiumClientStream*>(stream.second)->can_migrate())
+ return true;
+ }
+ return false;
+}
+
+void QuicChromiumClientSession::HandlePromised(QuicStreamId id,
+ QuicStreamId promised_id,
+ const SpdyHeaderBlock& headers) {
+ QuicClientSessionBase::HandlePromised(id, promised_id, headers);
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_PUSH_PROMISE_RECEIVED,
+ base::Bind(&NetLogQuicPushPromiseReceivedCallback, &headers,
+ id, promised_id));
+}
+
+void QuicChromiumClientSession::DeletePromised(
+ QuicClientPromisedInfo* promised) {
+ if (IsOpenStream(promised->id()))
+ streams_pushed_and_claimed_count_++;
+ QuicClientSessionBase::DeletePromised(promised);
+}
+
+const LoadTimingInfo::ConnectTiming&
+QuicChromiumClientSession::GetConnectTiming() {
+ connect_timing_.ssl_start = connect_timing_.connect_start;
+ connect_timing_.ssl_end = connect_timing_.connect_end;
+ return connect_timing_;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_chromium_client_session.h b/chromium/net/quic/chromium/quic_chromium_client_session.h
new file mode 100644
index 00000000000..ba61969218b
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_client_session.h
@@ -0,0 +1,400 @@
+// 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.
+//
+// A client specific QuicSession subclass. This class owns the underlying
+// QuicConnection and QuicConnectionHelper objects. The connection stores
+// a non-owning pointer to the helper so this session needs to ensure that
+// the helper outlives the connection.
+
+#ifndef NET_QUIC_QUIC_CHROMIUM_CLIENT_SESSION_H_
+#define NET_QUIC_QUIC_CHROMIUM_CLIENT_SESSION_H_
+
+#include <stddef.h>
+
+#include <list>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/containers/mru_cache.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "net/base/completion_callback.h"
+#include "net/base/load_timing_info.h"
+#include "net/base/net_error_details.h"
+#include "net/base/net_export.h"
+#include "net/cert/ct_verify_result.h"
+#include "net/log/net_log_with_source.h"
+#include "net/proxy/proxy_server.h"
+#include "net/quic/chromium/quic_chromium_client_stream.h"
+#include "net/quic/chromium/quic_chromium_packet_reader.h"
+#include "net/quic/chromium/quic_chromium_packet_writer.h"
+#include "net/quic/chromium/quic_connection_logger.h"
+#include "net/quic/core/quic_client_session_base.h"
+#include "net/quic/core/quic_crypto_client_stream.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/quic_time.h"
+#include "net/socket/socket_performance_watcher.h"
+
+namespace net {
+
+class CertVerifyResult;
+class DatagramClientSocket;
+class NetLog;
+class QuicCryptoClientStreamFactory;
+class QuicServerInfo;
+class QuicStreamFactory;
+class SSLInfo;
+class TransportSecurityState;
+
+using TokenBindingSignatureMap =
+ base::MRUCache<std::pair<TokenBindingType, std::string>,
+ std::vector<uint8_t>>;
+
+namespace test {
+class QuicChromiumClientSessionPeer;
+} // namespace test
+
+class NET_EXPORT_PRIVATE QuicChromiumClientSession
+ : public QuicClientSessionBase,
+ public QuicChromiumPacketReader::Visitor,
+ public QuicChromiumPacketWriter::Delegate {
+ public:
+ // An interface for observing events on a session.
+ class NET_EXPORT_PRIVATE Observer {
+ public:
+ virtual ~Observer() {}
+ virtual void OnCryptoHandshakeConfirmed() = 0;
+ virtual void OnSessionClosed(int error, bool port_migration_detected) = 0;
+ };
+
+ // A helper class used to manage a request to create a stream.
+ class NET_EXPORT_PRIVATE StreamRequest {
+ public:
+ StreamRequest();
+ ~StreamRequest();
+
+ // Starts a request to create a stream. If OK is returned, then
+ // |stream| will be updated with the newly created stream. If
+ // ERR_IO_PENDING is returned, then when the request is eventuallly
+ // complete |callback| will be called.
+ int StartRequest(const base::WeakPtr<QuicChromiumClientSession>& session,
+ QuicChromiumClientStream** stream,
+ const CompletionCallback& callback);
+
+ // Cancels any pending stream creation request. May be called
+ // repeatedly.
+ void CancelRequest();
+
+ private:
+ friend class QuicChromiumClientSession;
+
+ // Called by |session_| for an asynchronous request when the stream
+ // request has finished successfully.
+ void OnRequestCompleteSuccess(QuicChromiumClientStream* stream);
+
+ // Called by |session_| for an asynchronous request when the stream
+ // request has finished with an error. Also called with ERR_ABORTED
+ // if |session_| is destroyed while the stream request is still pending.
+ void OnRequestCompleteFailure(int rv);
+
+ base::WeakPtr<QuicChromiumClientSession> session_;
+ CompletionCallback callback_;
+ QuicChromiumClientStream** stream_;
+
+ DISALLOW_COPY_AND_ASSIGN(StreamRequest);
+ };
+
+ // Constructs a new session which will own |connection|, but not
+ // |stream_factory|, which must outlive this session.
+ // TODO(rch): decouple the factory from the session via a Delegate interface.
+ QuicChromiumClientSession(
+ QuicConnection* connection,
+ std::unique_ptr<DatagramClientSocket> socket,
+ QuicStreamFactory* stream_factory,
+ QuicCryptoClientStreamFactory* crypto_client_stream_factory,
+ QuicClock* clock,
+ TransportSecurityState* transport_security_state,
+ std::unique_ptr<QuicServerInfo> server_info,
+ const QuicServerId& server_id,
+ int yield_after_packets,
+ QuicTime::Delta yield_after_duration,
+ int cert_verify_flags,
+ const QuicConfig& config,
+ QuicCryptoClientConfig* crypto_config,
+ const char* const connection_description,
+ base::TimeTicks dns_resolution_start_time,
+ base::TimeTicks dns_resolution_end_time,
+ QuicClientPushPromiseIndex* push_promise_index,
+ base::TaskRunner* task_runner,
+ std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
+ NetLog* net_log);
+ ~QuicChromiumClientSession() override;
+
+ void Initialize() override;
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // Attempts to create a new stream. If the stream can be
+ // created immediately, returns OK. If the open stream limit
+ // has been reached, returns ERR_IO_PENDING, and |request|
+ // will be added to the stream requets queue and will
+ // be completed asynchronously.
+ // TODO(rch): remove |stream| from this and use setter on |request|
+ // and fix in spdy too.
+ int TryCreateStream(StreamRequest* request,
+ QuicChromiumClientStream** stream);
+
+ // Cancels the pending stream creation request.
+ void CancelRequest(StreamRequest* request);
+
+ // QuicChromiumPacketWriter::Delegate override.
+ int HandleWriteError(int error_code,
+ scoped_refptr<StringIOBuffer> last_packet) override;
+ void OnWriteError(int error_code) override;
+ void OnWriteUnblocked() override;
+
+ // QuicSpdySession methods:
+ void OnHeadersHeadOfLineBlocking(QuicTime::Delta delta) override;
+
+ // QuicSession methods:
+ void OnStreamFrame(const QuicStreamFrame& frame) override;
+ QuicChromiumClientStream* CreateOutgoingDynamicStream(
+ SpdyPriority priority) override;
+ QuicCryptoClientStream* GetCryptoStream() override;
+ void CloseStream(QuicStreamId stream_id) override;
+ void SendRstStream(QuicStreamId id,
+ QuicRstStreamErrorCode error,
+ QuicStreamOffset bytes_written) override;
+ void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override;
+ void OnCryptoHandshakeMessageSent(
+ const CryptoHandshakeMessage& message) override;
+ void OnCryptoHandshakeMessageReceived(
+ const CryptoHandshakeMessage& message) override;
+ void OnGoAway(const QuicGoAwayFrame& frame) override;
+ void OnRstStream(const QuicRstStreamFrame& frame) override;
+
+ // QuicClientSessionBase methods:
+ void OnConfigNegotiated() override;
+ void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override;
+ void OnProofVerifyDetailsAvailable(
+ const ProofVerifyDetails& verify_details) override;
+
+ // QuicConnectionVisitorInterface methods:
+ void OnConnectionClosed(QuicErrorCode error,
+ const std::string& error_details,
+ ConnectionCloseSource source) override;
+ void OnSuccessfulVersionNegotiation(const QuicVersion& version) override;
+ void OnPathDegrading() override;
+ bool HasOpenDynamicStreams() const override;
+
+ // QuicChromiumPacketReader::Visitor methods:
+ void OnReadError(int result, const DatagramClientSocket* socket) override;
+ bool OnPacket(const QuicReceivedPacket& packet,
+ IPEndPoint local_address,
+ IPEndPoint peer_address) override;
+
+ // Gets the SSL connection information.
+ bool GetSSLInfo(SSLInfo* ssl_info) const;
+
+ // Generates the signature used in Token Binding using key |*key| and for a
+ // Token Binding of type |tb_type|, putting the signature in |*out|. Returns a
+ // net error code.
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out);
+
+ // Performs a crypto handshake with the server.
+ int CryptoConnect(bool require_confirmation,
+ const CompletionCallback& callback);
+
+ // Resumes a crypto handshake with the server after a timeout.
+ int ResumeCryptoConnect(const CompletionCallback& callback);
+
+ // Causes the QuicConnectionHelper to start reading from all sockets
+ // and passing the data along to the QuicConnection.
+ void StartReading();
+
+ // Close the session because of |error| and notifies the factory
+ // that this session has been closed, which will delete the session.
+ void CloseSessionOnError(int error, QuicErrorCode quic_error);
+
+ // Close the session because of |error| and notifies the factory later that
+ // this session has been closed, which will delete the session.
+ void CloseSessionOnErrorAndNotifyFactoryLater(int error,
+ QuicErrorCode quic_error);
+
+ std::unique_ptr<base::Value> GetInfoAsValue(
+ const std::set<HostPortPair>& aliases);
+
+ const NetLogWithSource& net_log() const { return net_log_; }
+
+ base::WeakPtr<QuicChromiumClientSession> GetWeakPtr();
+
+ // 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
+ // than the number of round-trips needed for the handshake.
+ int GetNumSentClientHellos() const;
+
+ // Returns the stream id of the push stream if it is not claimed yet, or 0
+ // otherwise.
+ QuicStreamId GetStreamIdForPush(const GURL& pushed_url);
+
+ // Returns true if |hostname| may be pooled onto this session. If this
+ // is a secure QUIC session, then |hostname| must match the certificate
+ // presented during the handshake.
+ bool CanPool(const std::string& hostname, PrivacyMode privacy_mode) const;
+
+ const QuicServerId& server_id() const { return server_id_; }
+
+ // Attempts to migrate session when a write error is encountered.
+ void MigrateSessionOnWriteError();
+
+ // Helper method that writes a packet on the new socket after
+ // migration completes. If not null, the packet_ member is written,
+ // otherwise a PING packet is written.
+ void WriteToNewSocket();
+
+ // Migrates session onto new socket, i.e., starts reading from
+ // |socket| in addition to any previous sockets, and sets |writer|
+ // to be the new default writer. Returns true if socket was
+ // successfully added to the session and the session was
+ // successfully migrated to using the new socket. Returns true on
+ // successful migration, or false if number of migrations exceeds
+ // kMaxReadersPerQuicSession. Takes ownership of |socket|, |reader|,
+ // and |writer|.
+ bool MigrateToSocket(std::unique_ptr<DatagramClientSocket> socket,
+ std::unique_ptr<QuicChromiumPacketReader> reader,
+ std::unique_ptr<QuicChromiumPacketWriter> writer);
+
+ // Called when NetworkChangeNotifier notifies observers of a newly
+ // connected network. Migrates this session to the newly connected
+ // network if the session has a pending migration.
+ void OnNetworkConnected(NetworkChangeNotifier::NetworkHandle network,
+ const NetLogWithSource& net_log);
+
+ // Schedules a migration alarm to wait for a new network.
+ void OnNoNewNetwork();
+
+ // Called when migration alarm fires. If migration has not occurred
+ // since alarm was set, closes session with error.
+ void OnMigrationTimeout(size_t num_sockets);
+
+ // Populates network error details for this session.
+ void PopulateNetErrorDetails(NetErrorDetails* details);
+
+ // Returns current default socket. This is the socket over which all
+ // QUIC packets are sent. This default socket can change, so do not store the
+ // returned socket.
+ const DatagramClientSocket* GetDefaultSocket() const;
+
+ bool IsAuthorized(const std::string& hostname) override;
+
+ // Returns true if session has one ore more streams marked as non-migratable.
+ bool HasNonMigratableStreams() const;
+
+ void HandlePromised(QuicStreamId associated_id,
+ QuicStreamId promised_id,
+ const SpdyHeaderBlock& headers) override;
+
+ void DeletePromised(QuicClientPromisedInfo* promised) override;
+
+ const LoadTimingInfo::ConnectTiming& GetConnectTiming();
+
+ protected:
+ // QuicSession methods:
+ bool ShouldCreateIncomingDynamicStream(QuicStreamId id) override;
+ bool ShouldCreateOutgoingDynamicStream() override;
+
+ QuicChromiumClientStream* CreateIncomingDynamicStream(
+ QuicStreamId id) override;
+
+ private:
+ friend class test::QuicChromiumClientSessionPeer;
+
+ typedef std::set<Observer*> ObserverSet;
+ typedef std::list<StreamRequest*> StreamRequestQueue;
+
+ QuicChromiumClientStream* CreateOutgoingReliableStreamImpl();
+ QuicChromiumClientStream* CreateIncomingReliableStreamImpl(QuicStreamId id);
+ // A completion callback invoked when a read completes.
+ void OnReadComplete(int result);
+
+ void OnClosedStream();
+
+ // Close the session because of |error| and records it in UMA histogram.
+ void RecordAndCloseSessionOnError(int error, QuicErrorCode quic_error);
+
+ // A Session may be closed via any of three methods:
+ // OnConnectionClosed - called by the connection when the connection has been
+ // closed, perhaps due to a timeout or a protocol error.
+ // CloseSessionOnError - called from the owner of the session,
+ // the QuicStreamFactory, when there is an error.
+ // OnReadComplete - when there is a read error.
+ // This method closes all stream and performs any necessary cleanup.
+ void CloseSessionOnErrorInner(int net_error, QuicErrorCode quic_error);
+
+ void CloseAllStreams(int net_error);
+ void CloseAllObservers(int net_error);
+
+ // Notifies the factory that this session is going away and no more streams
+ // should be created from it. This needs to be called before closing any
+ // streams, because closing a stream may cause a new stream to be created.
+ void NotifyFactoryOfSessionGoingAway();
+
+ // Posts a task to notify the factory that this session has been closed.
+ void NotifyFactoryOfSessionClosedLater();
+
+ // Notifies the factory that this session has been closed which will
+ // delete |this|.
+ void NotifyFactoryOfSessionClosed();
+
+ QuicServerId server_id_;
+ bool require_confirmation_;
+ std::unique_ptr<QuicCryptoClientStream> crypto_stream_;
+ QuicStreamFactory* stream_factory_;
+ std::vector<std::unique_ptr<DatagramClientSocket>> sockets_;
+ TransportSecurityState* transport_security_state_;
+ std::unique_ptr<QuicServerInfo> server_info_;
+ std::unique_ptr<CertVerifyResult> cert_verify_result_;
+ std::unique_ptr<ct::CTVerifyResult> ct_verify_result_;
+ std::string pinning_failure_log_;
+ bool pkp_bypassed_;
+ ObserverSet observers_;
+ StreamRequestQueue stream_requests_;
+ CompletionCallback callback_;
+ size_t num_total_streams_;
+ base::TaskRunner* task_runner_;
+ NetLogWithSource net_log_;
+ std::vector<std::unique_ptr<QuicChromiumPacketReader>> packet_readers_;
+ LoadTimingInfo::ConnectTiming connect_timing_;
+ std::unique_ptr<QuicConnectionLogger> logger_;
+ // True when the session is going away, and streams may no longer be created
+ // on this session. Existing stream will continue to be processed.
+ bool going_away_;
+ // True when the session receives a go away from server due to port migration.
+ bool port_migration_detected_;
+ TokenBindingSignatureMap token_binding_signatures_;
+ // UMA histogram counters for streams pushed to this session.
+ int streams_pushed_count_;
+ int streams_pushed_and_claimed_count_;
+ // Stores packet that witnesses socket write error. This packet is
+ // written to a new socket after migration completes.
+ scoped_refptr<StringIOBuffer> packet_;
+ // TODO(jri): Replace use of migration_pending_ sockets_.size().
+ // When a task is posted for MigrateSessionOnError, pass in
+ // 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.
+ base::WeakPtrFactory<QuicChromiumClientSession> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicChromiumClientSession);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CHROMIUM_CLIENT_SESSION_H_
diff --git a/chromium/net/quic/chromium/quic_chromium_client_session_peer.cc b/chromium/net/quic/chromium/quic_chromium_client_session_peer.cc
new file mode 100644
index 00000000000..8f515abe74b
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_client_session_peer.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2013 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/chromium/quic_chromium_client_session_peer.h"
+
+#include "net/quic/chromium/quic_chromium_client_session.h"
+
+namespace net {
+namespace test {
+
+// static
+void QuicChromiumClientSessionPeer::SetMaxOpenStreams(
+ QuicChromiumClientSession* session,
+ size_t max_streams,
+ size_t default_streams) {
+ session->config()->SetMaxStreamsPerConnection(max_streams, default_streams);
+}
+
+// static
+void QuicChromiumClientSessionPeer::SetChannelIDSent(
+ QuicChromiumClientSession* session,
+ bool channel_id_sent) {
+ session->crypto_stream_->channel_id_sent_ = channel_id_sent;
+}
+
+// static
+void QuicChromiumClientSessionPeer::SetHostname(
+ QuicChromiumClientSession* session,
+ const std::string& hostname) {
+ QuicServerId server_id(hostname, session->server_id_.port(),
+ session->server_id_.privacy_mode());
+ session->server_id_ = server_id;
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_chromium_client_session_peer.h b/chromium/net/quic/chromium/quic_chromium_client_session_peer.h
new file mode 100644
index 00000000000..c4ddee86669
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_client_session_peer.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2013 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_TEST_TOOLS_QUIC_CHROMIUM_CLIENT_SESSION_PEER_H_
+#define NET_QUIC_TEST_TOOLS_QUIC_CHROMIUM_CLIENT_SESSION_PEER_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+class QuicChromiumClientSession;
+
+namespace test {
+
+class QuicChromiumClientSessionPeer {
+ public:
+ static void SetMaxOpenStreams(QuicChromiumClientSession* session,
+ size_t max_streams,
+ size_t default_streams);
+
+ static void SetChannelIDSent(QuicChromiumClientSession* session,
+ bool channel_id_sent);
+
+ static void SetHostname(QuicChromiumClientSession* session,
+ const std::string& hostname);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicChromiumClientSessionPeer);
+};
+
+} // namespace test
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_QUIC_CHROMIUM_CLIENT_SESSION_PEER_H_
diff --git a/chromium/net/quic/chromium/quic_chromium_client_session_test.cc b/chromium/net/quic/chromium/quic_chromium_client_session_test.cc
new file mode 100644
index 00000000000..dbdddde9218
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_client_session_test.cc
@@ -0,0 +1,568 @@
+// 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/chromium/quic_chromium_client_session.h"
+
+#include "base/base64.h"
+#include "base/files/file_path.h"
+#include "base/memory/ptr_util.h"
+#include "base/rand_util.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "net/base/test_completion_callback.h"
+#include "net/cert/cert_verify_result.h"
+#include "net/http/transport_security_state.h"
+#include "net/log/net_log_source.h"
+#include "net/log/test_net_log.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/chromium/quic_chromium_alarm_factory.h"
+#include "net/quic/chromium/quic_chromium_client_session_peer.h"
+#include "net/quic/chromium/quic_chromium_connection_helper.h"
+#include "net/quic/chromium/quic_chromium_packet_reader.h"
+#include "net/quic/chromium/quic_chromium_packet_writer.h"
+#include "net/quic/core/crypto/aes_128_gcm_12_encrypter.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/crypto/quic_server_info.h"
+#include "net/quic/core/quic_crypto_client_stream_factory.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_http_utils.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
+#include "net/quic/test_tools/quic_spdy_session_peer.h"
+#include "net/quic/test_tools/quic_test_packet_maker.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/simple_quic_framer.h"
+#include "net/socket/socket_test_util.h"
+#include "net/spdy/spdy_test_utils.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
+#include "net/test/test_data_directory.h"
+#include "net/udp/datagram_client_socket.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::_;
+
+namespace net {
+namespace test {
+namespace {
+
+const IPEndPoint kIpEndPoint = IPEndPoint(IPAddress::IPv4AllZeros(), 0);
+const char kServerHostname[] = "test.example.com";
+const uint16_t kServerPort = 443;
+const size_t kMaxReadersPerQuicSession = 5;
+
+class MockStreamDelegate : public QuicChromiumClientStream::Delegate {
+ public:
+ MockStreamDelegate() {}
+
+ MOCK_METHOD0(OnSendData, int());
+ MOCK_METHOD2(OnSendDataComplete, int(int, bool*));
+ MOCK_METHOD2(OnHeadersAvailable,
+ void(const SpdyHeaderBlock& headers, size_t frame_len));
+ MOCK_METHOD2(OnHeadersAvailableMock,
+ void(const SpdyHeaderBlock& headers, size_t frame_len));
+ MOCK_METHOD2(OnDataReceived, int(const char*, int));
+ MOCK_METHOD0(OnDataAvailable, void());
+ MOCK_METHOD0(OnClose, void());
+ MOCK_METHOD1(OnError, void(int));
+ MOCK_METHOD0(HasSendHeadersComplete, bool());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockStreamDelegate);
+};
+
+class QuicChromiumClientSessionTest
+ : public ::testing::TestWithParam<QuicVersion> {
+ protected:
+ QuicChromiumClientSessionTest()
+ : crypto_config_(CryptoTestUtils::ProofVerifierForTesting()),
+ default_read_(new MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)),
+ socket_data_(
+ new SequencedSocketData(default_read_.get(), 1, nullptr, 0)),
+ random_(0),
+ helper_(&clock_, &random_),
+ alarm_factory_(base::ThreadTaskRunnerHandle::Get().get(), &clock_),
+ client_maker_(GetParam(),
+ 0,
+ &clock_,
+ kServerHostname,
+ Perspective::IS_CLIENT),
+ server_maker_(GetParam(),
+ 0,
+ &clock_,
+ kServerHostname,
+ Perspective::IS_SERVER) {
+ // Advance the time, because timers do not like uninitialized times.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ }
+
+ void Initialize() {
+ socket_factory_.AddSocketDataProvider(socket_data_.get());
+ std::unique_ptr<DatagramClientSocket> socket =
+ socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND,
+ base::Bind(&base::RandInt),
+ &net_log_, NetLogSource());
+ socket->Connect(kIpEndPoint);
+ QuicChromiumPacketWriter* writer =
+ new net::QuicChromiumPacketWriter(socket.get());
+ QuicConnection* connection = new QuicConnection(
+ 0, kIpEndPoint, &helper_, &alarm_factory_, writer, true,
+ Perspective::IS_CLIENT, SupportedVersions(GetParam()));
+ session_.reset(new QuicChromiumClientSession(
+ connection, std::move(socket),
+ /*stream_factory=*/nullptr, &crypto_client_stream_factory_, &clock_,
+ &transport_security_state_,
+ base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)),
+ QuicServerId(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED),
+ kQuicYieldAfterPacketsRead,
+ QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds),
+ /*cert_verify_flags=*/0, DefaultQuicConfig(), &crypto_config_,
+ "CONNECTION_UNKNOWN", base::TimeTicks::Now(), base::TimeTicks::Now(),
+ &push_promise_index_, base::ThreadTaskRunnerHandle::Get().get(),
+ /*socket_performance_watcher=*/nullptr, &net_log_));
+
+ scoped_refptr<X509Certificate> cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"));
+ verify_details_.cert_verify_result.verified_cert = cert;
+ verify_details_.cert_verify_result.is_issued_by_known_root = true;
+ session_->Initialize();
+ session_->StartReading();
+ writer->set_delegate(session_.get());
+ }
+
+ void TearDown() override {
+ session_->CloseSessionOnError(ERR_ABORTED, QUIC_INTERNAL_ERROR);
+ }
+
+ void CompleteCryptoHandshake() {
+ ASSERT_THAT(session_->CryptoConnect(false, callback_.callback()), IsOk());
+ }
+
+ QuicChromiumPacketWriter* CreateQuicChromiumPacketWriter(
+ DatagramClientSocket* socket,
+ QuicChromiumClientSession* session) const {
+ std::unique_ptr<QuicChromiumPacketWriter> writer(
+ new QuicChromiumPacketWriter(socket));
+ writer->set_delegate(session);
+ return writer.release();
+ }
+
+ QuicCryptoClientConfig crypto_config_;
+ TestNetLog net_log_;
+ BoundTestNetLog bound_test_net_log_;
+ MockClientSocketFactory socket_factory_;
+ std::unique_ptr<MockRead> default_read_;
+ std::unique_ptr<SequencedSocketData> socket_data_;
+ MockClock clock_;
+ MockRandom random_;
+ QuicChromiumConnectionHelper helper_;
+ QuicChromiumAlarmFactory alarm_factory_;
+ TransportSecurityState transport_security_state_;
+ MockCryptoClientStreamFactory crypto_client_stream_factory_;
+ std::unique_ptr<QuicChromiumClientSession> session_;
+ QuicConnectionVisitorInterface* visitor_;
+ TestCompletionCallback callback_;
+ QuicTestPacketMaker client_maker_;
+ QuicTestPacketMaker server_maker_;
+ ProofVerifyDetailsChromium verify_details_;
+ QuicClientPushPromiseIndex push_promise_index_;
+};
+
+INSTANTIATE_TEST_CASE_P(Tests,
+ QuicChromiumClientSessionTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
+
+TEST_P(QuicChromiumClientSessionTest, CryptoConnect) {
+ Initialize();
+ CompleteCryptoHandshake();
+}
+
+TEST_P(QuicChromiumClientSessionTest, MaxNumStreams) {
+ MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
+ std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
+ 1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT));
+ MockWrite writes[] = {
+ MockWrite(ASYNC, client_rst->data(), client_rst->length(), 1)};
+ socket_data_.reset(new SequencedSocketData(reads, arraysize(reads), writes,
+ arraysize(writes)));
+
+ Initialize();
+ CompleteCryptoHandshake();
+ const size_t kMaxOpenStreams = session_->max_open_outgoing_streams();
+
+ std::vector<QuicChromiumClientStream*> streams;
+ for (size_t i = 0; i < kMaxOpenStreams; i++) {
+ QuicChromiumClientStream* stream =
+ session_->CreateOutgoingDynamicStream(kDefaultPriority);
+ EXPECT_TRUE(stream);
+ streams.push_back(stream);
+ }
+ EXPECT_FALSE(session_->CreateOutgoingDynamicStream(kDefaultPriority));
+
+ EXPECT_EQ(kMaxOpenStreams, session_->GetNumOpenOutgoingStreams());
+
+ // Close a stream and ensure I can now open a new one.
+ QuicStreamId stream_id = streams[0]->id();
+ session_->CloseStream(stream_id);
+
+ EXPECT_FALSE(session_->CreateOutgoingDynamicStream(kDefaultPriority));
+ QuicRstStreamFrame rst1(stream_id, QUIC_STREAM_NO_ERROR, 0);
+ session_->OnRstStream(rst1);
+ EXPECT_EQ(kMaxOpenStreams - 1, session_->GetNumOpenOutgoingStreams());
+ EXPECT_TRUE(session_->CreateOutgoingDynamicStream(kDefaultPriority));
+}
+
+TEST_P(QuicChromiumClientSessionTest, Priority) {
+ MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
+ std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
+ 1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT));
+ MockWrite writes[] = {
+ MockWrite(ASYNC, client_rst->data(), client_rst->length(), 1)};
+ socket_data_.reset(new SequencedSocketData(reads, arraysize(reads), writes,
+ arraysize(writes)));
+
+ Initialize();
+ CompleteCryptoHandshake();
+ for (SpdyPriority priority : {kV3HighestPriority, kV3LowestPriority}) {
+ QuicChromiumClientStream* stream =
+ session_->CreateOutgoingDynamicStream(priority);
+ EXPECT_EQ(kV3HighestPriority, stream->priority());
+
+ MockStreamDelegate delegate;
+ EXPECT_CALL(delegate, HasSendHeadersComplete())
+ .WillOnce(testing::Return(true));
+ stream->SetDelegate(&delegate);
+ EXPECT_EQ(priority, stream->priority());
+ stream->SetDelegate(nullptr);
+ session_->CloseStream(stream->id());
+ }
+}
+
+TEST_P(QuicChromiumClientSessionTest, MaxNumStreamsViaRequest) {
+ MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
+ std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
+ 1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT));
+ MockWrite writes[] = {
+ MockWrite(ASYNC, client_rst->data(), client_rst->length(), 1)};
+ socket_data_.reset(new SequencedSocketData(reads, arraysize(reads), writes,
+ arraysize(writes)));
+
+ Initialize();
+ CompleteCryptoHandshake();
+ const size_t kMaxOpenStreams = session_->max_open_outgoing_streams();
+
+ std::vector<QuicChromiumClientStream*> streams;
+ for (size_t i = 0; i < kMaxOpenStreams; i++) {
+ QuicChromiumClientStream* stream =
+ session_->CreateOutgoingDynamicStream(kDefaultPriority);
+ EXPECT_TRUE(stream);
+ streams.push_back(stream);
+ }
+
+ QuicChromiumClientStream* stream;
+ QuicChromiumClientSession::StreamRequest stream_request;
+ TestCompletionCallback callback;
+ ASSERT_EQ(ERR_IO_PENDING,
+ stream_request.StartRequest(session_->GetWeakPtr(), &stream,
+ callback.callback()));
+
+ // Close a stream and ensure I can now open a new one.
+ QuicStreamId stream_id = streams[0]->id();
+ session_->CloseStream(stream_id);
+ QuicRstStreamFrame rst1(stream_id, QUIC_STREAM_NO_ERROR, 0);
+ session_->OnRstStream(rst1);
+ ASSERT_TRUE(callback.have_result());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
+ EXPECT_TRUE(stream != nullptr);
+}
+
+TEST_P(QuicChromiumClientSessionTest, GoAwayReceived) {
+ Initialize();
+ CompleteCryptoHandshake();
+
+ // After receiving a GoAway, I should no longer be able to create outgoing
+ // streams.
+ session_->connection()->OnGoAwayFrame(
+ QuicGoAwayFrame(QUIC_PEER_GOING_AWAY, 1u, "Going away."));
+ EXPECT_EQ(nullptr, session_->CreateOutgoingDynamicStream(kDefaultPriority));
+}
+
+TEST_P(QuicChromiumClientSessionTest, CanPool) {
+ Initialize();
+ // Load a cert that is valid for:
+ // www.example.org
+ // mail.example.org
+ // www.example.com
+
+ ProofVerifyDetailsChromium details;
+ details.cert_verify_result.verified_cert =
+ ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
+ ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
+
+ CompleteCryptoHandshake();
+ session_->OnProofVerifyDetailsAvailable(details);
+
+ EXPECT_TRUE(session_->CanPool("www.example.org", PRIVACY_MODE_DISABLED));
+ EXPECT_FALSE(session_->CanPool("www.example.org", PRIVACY_MODE_ENABLED));
+ EXPECT_TRUE(session_->CanPool("mail.example.org", PRIVACY_MODE_DISABLED));
+ EXPECT_TRUE(session_->CanPool("mail.example.com", PRIVACY_MODE_DISABLED));
+ EXPECT_FALSE(session_->CanPool("mail.google.com", PRIVACY_MODE_DISABLED));
+}
+
+TEST_P(QuicChromiumClientSessionTest, ConnectionPooledWithTlsChannelId) {
+ Initialize();
+ // Load a cert that is valid for:
+ // www.example.org
+ // mail.example.org
+ // www.example.com
+
+ ProofVerifyDetailsChromium details;
+ details.cert_verify_result.verified_cert =
+ ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
+ ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
+
+ CompleteCryptoHandshake();
+ session_->OnProofVerifyDetailsAvailable(details);
+ QuicChromiumClientSessionPeer::SetHostname(session_.get(), "www.example.org");
+ QuicChromiumClientSessionPeer::SetChannelIDSent(session_.get(), true);
+
+ EXPECT_TRUE(session_->CanPool("www.example.org", PRIVACY_MODE_DISABLED));
+ EXPECT_TRUE(session_->CanPool("mail.example.org", PRIVACY_MODE_DISABLED));
+ EXPECT_FALSE(session_->CanPool("mail.example.com", PRIVACY_MODE_DISABLED));
+ EXPECT_FALSE(session_->CanPool("mail.google.com", PRIVACY_MODE_DISABLED));
+}
+
+TEST_P(QuicChromiumClientSessionTest, ConnectionNotPooledWithDifferentPin) {
+ Initialize();
+
+ uint8_t primary_pin = 1;
+ uint8_t backup_pin = 2;
+ uint8_t bad_pin = 3;
+ AddPin(&transport_security_state_, "mail.example.org", primary_pin,
+ backup_pin);
+
+ ProofVerifyDetailsChromium details;
+ details.cert_verify_result.verified_cert =
+ ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
+ details.cert_verify_result.is_issued_by_known_root = true;
+ details.cert_verify_result.public_key_hashes.push_back(
+ GetTestHashValue(bad_pin));
+
+ ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
+
+ CompleteCryptoHandshake();
+ session_->OnProofVerifyDetailsAvailable(details);
+ QuicChromiumClientSessionPeer::SetHostname(session_.get(), "www.example.org");
+ QuicChromiumClientSessionPeer::SetChannelIDSent(session_.get(), true);
+
+ EXPECT_FALSE(session_->CanPool("mail.example.org", PRIVACY_MODE_DISABLED));
+}
+
+TEST_P(QuicChromiumClientSessionTest, ConnectionPooledWithMatchingPin) {
+ Initialize();
+
+ uint8_t primary_pin = 1;
+ uint8_t backup_pin = 2;
+ AddPin(&transport_security_state_, "mail.example.org", primary_pin,
+ backup_pin);
+
+ ProofVerifyDetailsChromium details;
+ details.cert_verify_result.verified_cert =
+ ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
+ details.cert_verify_result.is_issued_by_known_root = true;
+ details.cert_verify_result.public_key_hashes.push_back(
+ GetTestHashValue(primary_pin));
+
+ ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
+
+ CompleteCryptoHandshake();
+ session_->OnProofVerifyDetailsAvailable(details);
+ QuicChromiumClientSessionPeer::SetHostname(session_.get(), "www.example.org");
+ QuicChromiumClientSessionPeer::SetChannelIDSent(session_.get(), true);
+
+ EXPECT_TRUE(session_->CanPool("mail.example.org", PRIVACY_MODE_DISABLED));
+}
+
+TEST_P(QuicChromiumClientSessionTest, MigrateToSocket) {
+ Initialize();
+ CompleteCryptoHandshake();
+
+ char data[] = "ABCD";
+ std::unique_ptr<QuicEncryptedPacket> client_ping(
+ client_maker_.MakePingPacket(1, /*include_version=*/false));
+ std::unique_ptr<QuicEncryptedPacket> server_ping(
+ server_maker_.MakePingPacket(1, /*include_version=*/false));
+ std::unique_ptr<QuicEncryptedPacket> ack_and_data_out(
+ client_maker_.MakeAckAndDataPacket(2, false, 5, 1, 1, false, 0,
+ StringPiece(data)));
+ MockRead reads[] = {
+ MockRead(SYNCHRONOUS, server_ping->data(), server_ping->length(), 0),
+ MockRead(SYNCHRONOUS, ERR_IO_PENDING, 1)};
+ MockWrite writes[] = {
+ MockWrite(SYNCHRONOUS, client_ping->data(), client_ping->length(), 2),
+ MockWrite(SYNCHRONOUS, ack_and_data_out->data(),
+ ack_and_data_out->length(), 3)};
+ StaticSocketDataProvider socket_data(reads, arraysize(reads), writes,
+ arraysize(writes));
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ // Create connected socket.
+ std::unique_ptr<DatagramClientSocket> new_socket =
+ socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND,
+ base::Bind(&base::RandInt),
+ &net_log_, NetLogSource());
+ EXPECT_THAT(new_socket->Connect(kIpEndPoint), IsOk());
+
+ // Create reader and writer.
+ std::unique_ptr<QuicChromiumPacketReader> new_reader(
+ new QuicChromiumPacketReader(new_socket.get(), &clock_, session_.get(),
+ kQuicYieldAfterPacketsRead,
+ QuicTime::Delta::FromMilliseconds(
+ kQuicYieldAfterDurationMilliseconds),
+ bound_test_net_log_.bound()));
+ std::unique_ptr<QuicChromiumPacketWriter> new_writer(
+ CreateQuicChromiumPacketWriter(new_socket.get(), session_.get()));
+
+ // Migrate session.
+ EXPECT_TRUE(session_->MigrateToSocket(
+ std::move(new_socket), std::move(new_reader), std::move(new_writer)));
+ // Spin message loop to complete migration.
+ base::RunLoop().RunUntilIdle();
+
+ // Write data to session.
+ QuicChromiumClientStream* stream =
+ session_->CreateOutgoingDynamicStream(kDefaultPriority);
+ struct iovec iov[1];
+ iov[0].iov_base = data;
+ iov[0].iov_len = 4;
+ session_->WritevData(stream, stream->id(),
+ QuicIOVector(iov, arraysize(iov), 4), 0, false, nullptr);
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicChromiumClientSessionTest, MigrateToSocketMaxReaders) {
+ Initialize();
+ CompleteCryptoHandshake();
+
+ for (size_t i = 0; i < kMaxReadersPerQuicSession; ++i) {
+ MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 1)};
+ std::unique_ptr<QuicEncryptedPacket> ping_out(
+ client_maker_.MakePingPacket(i + 1, /*include_version=*/true));
+ MockWrite writes[] = {
+ MockWrite(SYNCHRONOUS, ping_out->data(), ping_out->length(), i + 2)};
+ StaticSocketDataProvider socket_data(reads, arraysize(reads), writes,
+ arraysize(writes));
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ // Create connected socket.
+ std::unique_ptr<DatagramClientSocket> new_socket =
+ socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND,
+ base::Bind(&base::RandInt),
+ &net_log_, NetLogSource());
+ EXPECT_THAT(new_socket->Connect(kIpEndPoint), IsOk());
+
+ // Create reader and writer.
+ std::unique_ptr<QuicChromiumPacketReader> new_reader(
+ new QuicChromiumPacketReader(new_socket.get(), &clock_, session_.get(),
+ kQuicYieldAfterPacketsRead,
+ QuicTime::Delta::FromMilliseconds(
+ kQuicYieldAfterDurationMilliseconds),
+ bound_test_net_log_.bound()));
+ std::unique_ptr<QuicChromiumPacketWriter> new_writer(
+ CreateQuicChromiumPacketWriter(new_socket.get(), session_.get()));
+
+ // Migrate session.
+ if (i < kMaxReadersPerQuicSession - 1) {
+ EXPECT_TRUE(session_->MigrateToSocket(
+ std::move(new_socket), std::move(new_reader), std::move(new_writer)));
+ // Spin message loop to complete migration.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ } else {
+ // Max readers exceeded.
+ EXPECT_FALSE(session_->MigrateToSocket(
+ std::move(new_socket), std::move(new_reader), std::move(new_writer)));
+ EXPECT_FALSE(socket_data.AllReadDataConsumed());
+ EXPECT_FALSE(socket_data.AllWriteDataConsumed());
+ }
+ }
+}
+
+TEST_P(QuicChromiumClientSessionTest, MigrateToSocketReadError) {
+ std::unique_ptr<QuicEncryptedPacket> client_ping(
+ client_maker_.MakePingPacket(1, /*include_version=*/false));
+ std::unique_ptr<QuicEncryptedPacket> server_ping(
+ server_maker_.MakePingPacket(1, /*include_version=*/false));
+ MockRead old_reads[] = {
+ MockRead(SYNCHRONOUS, client_ping->data(), client_ping->length(), 0),
+ MockRead(ASYNC, ERR_IO_PENDING, 1), // causes reading to pause.
+ MockRead(ASYNC, ERR_NETWORK_CHANGED, 2)};
+ socket_data_.reset(
+ new SequencedSocketData(old_reads, arraysize(old_reads), nullptr, 0));
+ Initialize();
+ CompleteCryptoHandshake();
+
+ MockWrite writes[] = {
+ MockWrite(SYNCHRONOUS, client_ping->data(), client_ping->length(), 1)};
+ MockRead new_reads[] = {
+ MockRead(SYNCHRONOUS, server_ping->data(), server_ping->length(), 0),
+ MockRead(ASYNC, ERR_IO_PENDING, 2), // pause reading.
+ MockRead(ASYNC, server_ping->data(), server_ping->length(), 3),
+ MockRead(ASYNC, ERR_IO_PENDING, 4), // pause reading
+ MockRead(ASYNC, ERR_NETWORK_CHANGED, 5)};
+ SequencedSocketData new_socket_data(new_reads, arraysize(new_reads), writes,
+ arraysize(writes));
+ socket_factory_.AddSocketDataProvider(&new_socket_data);
+
+ // Create connected socket.
+ std::unique_ptr<DatagramClientSocket> new_socket =
+ socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND,
+ base::Bind(&base::RandInt),
+ &net_log_, NetLogSource());
+ EXPECT_THAT(new_socket->Connect(kIpEndPoint), IsOk());
+
+ // Create reader and writer.
+ std::unique_ptr<QuicChromiumPacketReader> new_reader(
+ new QuicChromiumPacketReader(new_socket.get(), &clock_, session_.get(),
+ kQuicYieldAfterPacketsRead,
+ QuicTime::Delta::FromMilliseconds(
+ kQuicYieldAfterDurationMilliseconds),
+ bound_test_net_log_.bound()));
+ std::unique_ptr<QuicChromiumPacketWriter> new_writer(
+ CreateQuicChromiumPacketWriter(new_socket.get(), session_.get()));
+
+ // Store old socket and migrate session.
+ EXPECT_TRUE(session_->MigrateToSocket(
+ std::move(new_socket), std::move(new_reader), std::move(new_writer)));
+ // Spin message loop to complete migration.
+ base::RunLoop().RunUntilIdle();
+
+ // Read error on old socket does not impact session.
+ EXPECT_TRUE(socket_data_->IsPaused());
+ socket_data_->Resume();
+ EXPECT_TRUE(session_->connection()->connected());
+ EXPECT_TRUE(new_socket_data.IsPaused());
+ new_socket_data.Resume();
+
+ // Read error on new socket causes session close.
+ EXPECT_TRUE(new_socket_data.IsPaused());
+ EXPECT_TRUE(session_->connection()->connected());
+ new_socket_data.Resume();
+ EXPECT_FALSE(session_->connection()->connected());
+
+ EXPECT_TRUE(socket_data_->AllReadDataConsumed());
+ EXPECT_TRUE(socket_data_->AllWriteDataConsumed());
+ EXPECT_TRUE(new_socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(new_socket_data.AllWriteDataConsumed());
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_chromium_client_stream.cc b/chromium/net/quic/chromium/quic_chromium_client_stream.cc
new file mode 100644
index 00000000000..5a3d996fb09
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_client_stream.cc
@@ -0,0 +1,338 @@
+// 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/chromium/quic_chromium_client_stream.h"
+
+#include <utility>
+
+#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
+#include "base/location.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/log/net_log_event_type.h"
+#include "net/quic/chromium/quic_chromium_client_session.h"
+#include "net/quic/core/quic_http_utils.h"
+#include "net/quic/core/quic_spdy_session.h"
+#include "net/quic/core/quic_write_blocked_list.h"
+#include "net/quic/core/spdy_utils.h"
+
+namespace net {
+
+QuicChromiumClientStream::QuicChromiumClientStream(
+ QuicStreamId id,
+ QuicClientSessionBase* session,
+ const NetLogWithSource& net_log)
+ : QuicSpdyStream(id, session),
+ net_log_(net_log),
+ delegate_(nullptr),
+ headers_delivered_(false),
+ session_(session),
+ can_migrate_(true),
+ weak_factory_(this) {}
+
+QuicChromiumClientStream::~QuicChromiumClientStream() {
+ if (delegate_)
+ delegate_->OnClose();
+}
+
+void QuicChromiumClientStream::OnStreamHeadersComplete(bool fin,
+ size_t frame_len) {
+ QuicSpdyStream::OnStreamHeadersComplete(fin, frame_len);
+ if (decompressed_headers().empty() && !decompressed_trailers().empty()) {
+ DCHECK(trailers_decompressed());
+ // The delegate will read the trailers via a posted task.
+ NotifyDelegateOfHeadersCompleteLater(received_trailers().Clone(),
+ frame_len);
+ } else {
+ DCHECK(!headers_delivered_);
+ SpdyHeaderBlock headers;
+ SpdyFramer framer(HTTP2);
+ size_t headers_len = decompressed_headers().length();
+ const char* header_data = decompressed_headers().data();
+ if (!framer.ParseHeaderBlockInBuffer(header_data, headers_len, &headers)) {
+ DLOG(WARNING) << "Invalid headers";
+ Reset(QUIC_BAD_APPLICATION_PAYLOAD);
+ return;
+ }
+ MarkHeadersConsumed(headers_len);
+ session_->OnInitialHeadersComplete(id(), headers);
+
+ // The delegate will read the headers via a posted task.
+ NotifyDelegateOfHeadersCompleteLater(std::move(headers), frame_len);
+ }
+}
+
+void QuicChromiumClientStream::OnInitialHeadersComplete(
+ bool fin,
+ size_t frame_len,
+ const QuicHeaderList& header_list) {
+ QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list);
+
+ SpdyHeaderBlock header_block;
+ int64_t length = -1;
+ if (!SpdyUtils::CopyAndValidateHeaders(header_list, &length, &header_block)) {
+ DLOG(ERROR) << "Failed to parse header list: " << header_list.DebugString();
+ ConsumeHeaderList();
+ Reset(QUIC_BAD_APPLICATION_PAYLOAD);
+ return;
+ }
+
+ ConsumeHeaderList();
+ session_->OnInitialHeadersComplete(id(), header_block);
+
+ // The delegate will read the headers via a posted task.
+ NotifyDelegateOfHeadersCompleteLater(std::move(header_block), frame_len);
+}
+
+void QuicChromiumClientStream::OnTrailingHeadersComplete(
+ bool fin,
+ size_t frame_len,
+ const QuicHeaderList& header_list) {
+ QuicSpdyStream::OnTrailingHeadersComplete(fin, frame_len, header_list);
+ NotifyDelegateOfHeadersCompleteLater(received_trailers().Clone(), frame_len);
+}
+
+void QuicChromiumClientStream::OnPromiseHeadersComplete(
+ QuicStreamId promised_id,
+ size_t frame_len) {
+ size_t headers_len = decompressed_headers().length();
+ SpdyHeaderBlock headers;
+ SpdyFramer framer(HTTP2);
+ if (!framer.ParseHeaderBlockInBuffer(decompressed_headers().data(),
+ headers_len, &headers)) {
+ DLOG(WARNING) << "Invalid headers";
+ Reset(QUIC_BAD_APPLICATION_PAYLOAD);
+ return;
+ }
+ MarkHeadersConsumed(headers_len);
+
+ session_->HandlePromised(id(), promised_id, headers);
+}
+
+void QuicChromiumClientStream::OnPromiseHeaderList(
+ QuicStreamId promised_id,
+ size_t frame_len,
+ const QuicHeaderList& header_list) {
+ SpdyHeaderBlock promise_headers;
+ int64_t content_length = -1;
+ if (!SpdyUtils::CopyAndValidateHeaders(header_list, &content_length,
+ &promise_headers)) {
+ DLOG(ERROR) << "Failed to parse header list: " << header_list.DebugString();
+ ConsumeHeaderList();
+ Reset(QUIC_BAD_APPLICATION_PAYLOAD);
+ return;
+ }
+ ConsumeHeaderList();
+
+ session_->HandlePromised(id(), promised_id, promise_headers);
+}
+
+void QuicChromiumClientStream::OnDataAvailable() {
+ if (!FinishedReadingHeaders() || !headers_delivered_) {
+ // Buffer the data in the sequencer until the headers have been read.
+ return;
+ }
+
+ if (!sequencer()->HasBytesToRead() && !FinishedReadingTrailers()) {
+ // If there is no data to read, wait until either FIN is received or
+ // trailers are delivered.
+ return;
+ }
+
+ // The delegate will read the data via a posted task, and
+ // will be able to, potentially, read all data which has queued up.
+ NotifyDelegateOfDataAvailableLater();
+}
+
+void QuicChromiumClientStream::OnClose() {
+ if (delegate_) {
+ delegate_->OnClose();
+ delegate_ = nullptr;
+ delegate_tasks_.clear();
+ }
+ ReliableQuicStream::OnClose();
+}
+
+void QuicChromiumClientStream::OnCanWrite() {
+ ReliableQuicStream::OnCanWrite();
+
+ if (!HasBufferedData() && !callback_.is_null()) {
+ base::ResetAndReturn(&callback_).Run(OK);
+ }
+}
+
+size_t QuicChromiumClientStream::WriteHeaders(
+ SpdyHeaderBlock header_block,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate) {
+ if (!session()->IsCryptoHandshakeConfirmed()) {
+ auto entry = header_block.find(":method");
+ DCHECK(entry != header_block.end());
+ DCHECK_NE("POST", entry->second);
+ }
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
+ base::Bind(&QuicRequestNetLogCallback, id(), &header_block,
+ QuicSpdyStream::priority()));
+ return QuicSpdyStream::WriteHeaders(std::move(header_block), fin,
+ ack_notifier_delegate);
+}
+
+SpdyPriority QuicChromiumClientStream::priority() const {
+ if (delegate_ && delegate_->HasSendHeadersComplete()) {
+ return QuicSpdyStream::priority();
+ }
+ return net::kV3HighestPriority;
+}
+
+int QuicChromiumClientStream::WriteStreamData(
+ base::StringPiece data,
+ bool fin,
+ const CompletionCallback& callback) {
+ // We should not have data buffered.
+ DCHECK(!HasBufferedData());
+ // Writes the data, or buffers it.
+ WriteOrBufferData(data, fin, nullptr);
+ if (!HasBufferedData()) {
+ return OK;
+ }
+
+ callback_ = callback;
+ return ERR_IO_PENDING;
+}
+
+int QuicChromiumClientStream::WritevStreamData(
+ const std::vector<scoped_refptr<IOBuffer>>& buffers,
+ const std::vector<int>& lengths,
+ bool fin,
+ const CompletionCallback& callback) {
+ // Must not be called when data is buffered.
+ DCHECK(!HasBufferedData());
+ // Writes the data, or buffers it.
+ for (size_t i = 0; i < buffers.size(); ++i) {
+ bool is_fin = fin && (i == buffers.size() - 1);
+ base::StringPiece string_data(buffers[i]->data(), lengths[i]);
+ WriteOrBufferData(string_data, is_fin, nullptr);
+ }
+ if (!HasBufferedData()) {
+ return OK;
+ }
+
+ callback_ = callback;
+ return ERR_IO_PENDING;
+}
+
+void QuicChromiumClientStream::SetDelegate(
+ QuicChromiumClientStream::Delegate* delegate) {
+ DCHECK(!(delegate_ && delegate));
+ delegate_ = delegate;
+ while (!delegate_tasks_.empty()) {
+ base::Closure closure = delegate_tasks_.front();
+ delegate_tasks_.pop_front();
+ closure.Run();
+ }
+ if (delegate == nullptr && sequencer()->IsClosed()) {
+ OnFinRead();
+ }
+}
+
+void QuicChromiumClientStream::OnError(int error) {
+ if (delegate_) {
+ QuicChromiumClientStream::Delegate* delegate = delegate_;
+ delegate_ = nullptr;
+ delegate_tasks_.clear();
+ delegate->OnError(error);
+ }
+}
+
+int QuicChromiumClientStream::Read(IOBuffer* buf, int buf_len) {
+ if (IsDoneReading())
+ return 0; // EOF
+
+ if (!HasBytesToRead())
+ return ERR_IO_PENDING;
+
+ iovec iov;
+ iov.iov_base = buf->data();
+ iov.iov_len = buf_len;
+ size_t bytes_read = Readv(&iov, 1);
+ // If no more body bytes and trailers are to be delivered, return
+ // ERR_IO_PENDING now because onDataAvailable() will be called after trailers.
+ if (bytes_read == 0 && !FinishedReadingTrailers())
+ return ERR_IO_PENDING;
+ return bytes_read;
+}
+
+bool QuicChromiumClientStream::CanWrite(const CompletionCallback& callback) {
+ bool can_write = session()->connection()->CanWrite(HAS_RETRANSMITTABLE_DATA);
+ if (!can_write) {
+ session()->MarkConnectionLevelWriteBlocked(id());
+ DCHECK(callback_.is_null());
+ callback_ = callback;
+ }
+ return can_write;
+}
+
+void QuicChromiumClientStream::NotifyDelegateOfHeadersCompleteLater(
+ SpdyHeaderBlock headers,
+ size_t frame_len) {
+ RunOrBuffer(base::Bind(
+ &QuicChromiumClientStream::NotifyDelegateOfHeadersComplete,
+ weak_factory_.GetWeakPtr(), base::Passed(std::move(headers)), frame_len));
+}
+
+void QuicChromiumClientStream::NotifyDelegateOfHeadersComplete(
+ SpdyHeaderBlock headers,
+ size_t frame_len) {
+ if (!delegate_)
+ return;
+ // Only mark trailers consumed when we are about to notify delegate.
+ if (headers_delivered_) {
+ MarkTrailersConsumed(decompressed_trailers().length());
+ MarkTrailersConsumed();
+ // Post an async task to notify delegate of the FIN flag.
+ NotifyDelegateOfDataAvailableLater();
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_TRAILERS,
+ base::Bind(&SpdyHeaderBlockNetLogCallback, &headers));
+ } else {
+ headers_delivered_ = true;
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_HEADERS,
+ base::Bind(&SpdyHeaderBlockNetLogCallback, &headers));
+ }
+
+ delegate_->OnHeadersAvailable(headers, frame_len);
+}
+
+void QuicChromiumClientStream::NotifyDelegateOfDataAvailableLater() {
+ RunOrBuffer(
+ base::Bind(&QuicChromiumClientStream::NotifyDelegateOfDataAvailable,
+ weak_factory_.GetWeakPtr()));
+}
+
+void QuicChromiumClientStream::NotifyDelegateOfDataAvailable() {
+ if (delegate_)
+ delegate_->OnDataAvailable();
+}
+
+void QuicChromiumClientStream::RunOrBuffer(base::Closure closure) {
+ if (delegate_) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure);
+ } else {
+ delegate_tasks_.push_back(closure);
+ }
+}
+
+void QuicChromiumClientStream::DisableConnectionMigration() {
+ can_migrate_ = false;
+}
+
+bool QuicChromiumClientStream::IsFirstStream() {
+ return id() == kHeadersStreamId + 2;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_chromium_client_stream.h b/chromium/net/quic/chromium/quic_chromium_client_stream.h
new file mode 100644
index 00000000000..a24bedf2a42
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_client_stream.h
@@ -0,0 +1,162 @@
+// 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.
+//
+// NOTE: This code is not shared between Google and Chrome.
+
+#ifndef NET_QUIC_QUIC_CHROMIUM_CLIENT_STREAM_H_
+#define NET_QUIC_QUIC_CHROMIUM_CLIENT_STREAM_H_
+
+#include <stddef.h>
+
+#include <deque>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_export.h"
+#include "net/base/upload_data_stream.h"
+#include "net/http/http_request_info.h"
+#include "net/http/http_response_info.h"
+#include "net/http/http_stream.h"
+#include "net/log/net_log_with_source.h"
+#include "net/quic/core/quic_spdy_stream.h"
+
+namespace net {
+
+class QuicClientSessionBase;
+
+// A client-initiated ReliableQuicStream. Instances of this class
+// are owned by the QuicClientSession which created them.
+class NET_EXPORT_PRIVATE QuicChromiumClientStream : public QuicSpdyStream {
+ public:
+ // Delegate handles protocol specific behavior of a quic stream.
+ class NET_EXPORT_PRIVATE Delegate {
+ public:
+ Delegate() {}
+
+ // Called when headers are available.
+ virtual void OnHeadersAvailable(const SpdyHeaderBlock& headers,
+ size_t frame_len) = 0;
+
+ // Called when data is available to be read.
+ virtual void OnDataAvailable() = 0;
+
+ // Called when the stream is closed by the peer.
+ virtual void OnClose() = 0;
+
+ // Called when the stream is closed because of an error.
+ virtual void OnError(int error) = 0;
+
+ // Returns true if sending of headers has completed.
+ virtual bool HasSendHeadersComplete() = 0;
+
+ protected:
+ virtual ~Delegate() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Delegate);
+ };
+
+ QuicChromiumClientStream(QuicStreamId id,
+ QuicClientSessionBase* session,
+ const NetLogWithSource& net_log);
+
+ ~QuicChromiumClientStream() override;
+
+ // QuicSpdyStream
+ void OnStreamHeadersComplete(bool fin, size_t frame_len) override;
+ void OnInitialHeadersComplete(bool fin,
+ size_t frame_len,
+ const QuicHeaderList& header_list) override;
+ void OnTrailingHeadersComplete(bool fin,
+ size_t frame_len,
+ const QuicHeaderList& header_list) override;
+ void OnPromiseHeadersComplete(QuicStreamId promised_stream_id,
+ size_t frame_len) override;
+ void OnPromiseHeaderList(QuicStreamId promised_id,
+ size_t frame_len,
+ const QuicHeaderList& header_list) override;
+ void OnDataAvailable() override;
+ void OnClose() override;
+ void OnCanWrite() override;
+ size_t WriteHeaders(SpdyHeaderBlock header_block,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate) override;
+ SpdyPriority priority() const override;
+
+ // While the server's set_priority shouldn't be called externally, the creator
+ // of client-side streams should be able to set the priority.
+ using QuicSpdyStream::SetPriority;
+
+ int WriteStreamData(base::StringPiece data,
+ bool fin,
+ const CompletionCallback& callback);
+ // Same as WriteStreamData except it writes data from a vector of IOBuffers,
+ // with the length of each buffer at the corresponding index in |lengths|.
+ int WritevStreamData(const std::vector<scoped_refptr<IOBuffer>>& buffers,
+ const std::vector<int>& lengths,
+ bool fin,
+ const CompletionCallback& callback);
+ // Set new |delegate|. |delegate| must not be NULL.
+ // If this stream has already received data, OnDataReceived() will be
+ // called on the delegate.
+ void SetDelegate(Delegate* delegate);
+ Delegate* GetDelegate() { return delegate_; }
+ void OnError(int error);
+
+ // Reads at most |buf_len| bytes into |buf|. Returns the number of bytes read.
+ int Read(IOBuffer* buf, int buf_len);
+
+ // Returns true if the stream can possible write data. (The socket may
+ // turn out to be write blocked, of course). If the stream can not write,
+ // this method returns false, and |callback| will be invoked when
+ // it becomes writable.
+ bool CanWrite(const CompletionCallback& callback);
+
+ const NetLogWithSource& net_log() const { return net_log_; }
+
+ // Prevents this stream from migrating to a new network. May cause other
+ // concurrent streams within the session to also not migrate.
+ void DisableConnectionMigration();
+
+ bool can_migrate() { return can_migrate_; }
+
+ // True if this stream is the first data stream created on this session.
+ bool IsFirstStream();
+
+ using QuicSpdyStream::HasBufferedData;
+
+ private:
+ void NotifyDelegateOfHeadersCompleteLater(SpdyHeaderBlock headers,
+ size_t frame_len);
+ void NotifyDelegateOfHeadersComplete(SpdyHeaderBlock headers,
+ size_t frame_len);
+ void NotifyDelegateOfDataAvailableLater();
+ void NotifyDelegateOfDataAvailable();
+ void RunOrBuffer(base::Closure closure);
+
+ NetLogWithSource net_log_;
+ Delegate* delegate_;
+
+ bool headers_delivered_;
+
+ CompletionCallback callback_;
+
+ QuicClientSessionBase* session_;
+
+ // Set to false if this stream to not be migrated during connection migration.
+ bool can_migrate_;
+
+ // Holds notifications generated before delegate_ is set.
+ std::deque<base::Closure> delegate_tasks_;
+
+ base::WeakPtrFactory<QuicChromiumClientStream> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicChromiumClientStream);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CHROMIUM_CLIENT_STREAM_H_
diff --git a/chromium/net/quic/chromium/quic_chromium_client_stream_test.cc b/chromium/net/quic/chromium/quic_chromium_client_stream_test.cc
new file mode 100644
index 00000000000..41e0ca5e535
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_client_stream_test.cc
@@ -0,0 +1,648 @@
+// 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/chromium/quic_chromium_client_stream.h"
+
+#include <string>
+
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/quic/chromium/quic_chromium_client_session.h"
+#include "net/quic/core/quic_client_session_base.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/core/spdy_utils.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gmock_mutant.h"
+
+using net::test::IsError;
+using net::test::IsOk;
+
+using testing::AnyNumber;
+using testing::CreateFunctor;
+using testing::Invoke;
+using testing::Return;
+using testing::StrEq;
+using testing::_;
+
+namespace net {
+namespace test {
+namespace {
+
+const QuicStreamId kTestStreamId = 5u;
+
+class MockDelegate : public QuicChromiumClientStream::Delegate {
+ public:
+ MockDelegate() {}
+
+ MOCK_METHOD0(OnSendData, int());
+ MOCK_METHOD2(OnSendDataComplete, int(int, bool*));
+ void OnHeadersAvailable(const SpdyHeaderBlock& headers,
+ size_t frame_len) override {
+ headers_ = headers.Clone();
+ OnHeadersAvailableMock(headers, frame_len);
+ }
+ MOCK_METHOD2(OnHeadersAvailableMock,
+ void(const SpdyHeaderBlock& headers, size_t frame_len));
+ MOCK_METHOD2(OnDataReceived, int(const char*, int));
+ MOCK_METHOD0(OnDataAvailable, void());
+ MOCK_METHOD0(OnClose, void());
+ MOCK_METHOD1(OnError, void(int));
+ MOCK_METHOD0(HasSendHeadersComplete, bool());
+
+ SpdyHeaderBlock headers_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockDelegate);
+};
+
+class MockQuicClientSessionBase : public QuicClientSessionBase {
+ public:
+ explicit MockQuicClientSessionBase(QuicConnection* connection,
+ QuicClientPushPromiseIndex* index);
+ ~MockQuicClientSessionBase() override;
+
+ QuicCryptoStream* GetCryptoStream() override { return crypto_stream_.get(); }
+
+ // From QuicSession.
+ MOCK_METHOD3(OnConnectionClosed,
+ void(QuicErrorCode error,
+ const std::string& error_details,
+ ConnectionCloseSource source));
+ MOCK_METHOD1(CreateIncomingDynamicStream, QuicSpdyStream*(QuicStreamId id));
+ MOCK_METHOD1(CreateOutgoingDynamicStream,
+ QuicChromiumClientStream*(SpdyPriority priority));
+ MOCK_METHOD6(WritevData,
+ QuicConsumedData(ReliableQuicStream* stream,
+ QuicStreamId id,
+ QuicIOVector data,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface*));
+ MOCK_METHOD3(SendRstStream,
+ void(QuicStreamId stream_id,
+ QuicRstStreamErrorCode error,
+ QuicStreamOffset bytes_written));
+
+ MOCK_METHOD2(OnStreamHeaders,
+ void(QuicStreamId stream_id, base::StringPiece headers_data));
+ MOCK_METHOD2(OnStreamHeadersPriority,
+ void(QuicStreamId stream_id, SpdyPriority priority));
+ MOCK_METHOD3(OnStreamHeadersComplete,
+ void(QuicStreamId stream_id, bool fin, size_t frame_len));
+ MOCK_METHOD2(OnPromiseHeaders,
+ void(QuicStreamId stream_id, StringPiece headers_data));
+ MOCK_METHOD3(OnPromiseHeadersComplete,
+ void(QuicStreamId stream_id,
+ QuicStreamId promised_stream_id,
+ size_t frame_len));
+ MOCK_METHOD0(IsCryptoHandshakeConfirmed, bool());
+ // Methods taking non-copyable types like SpdyHeaderBlock by value cannot be
+ // mocked directly.
+ size_t WriteHeaders(
+ QuicStreamId id,
+ SpdyHeaderBlock headers,
+ bool fin,
+ SpdyPriority priority,
+ QuicAckListenerInterface* ack_notifier_delegate) override {
+ return WriteHeadersMock(id, headers, fin, priority, ack_notifier_delegate);
+ }
+ MOCK_METHOD5(WriteHeadersMock,
+ size_t(QuicStreamId id,
+ const SpdyHeaderBlock& headers,
+ bool fin,
+ SpdyPriority priority,
+ QuicAckListenerInterface* ack_notifier_delegate));
+ MOCK_METHOD1(OnHeadersHeadOfLineBlocking, void(QuicTime::Delta delta));
+
+ using QuicSession::ActivateStream;
+
+ // Returns a QuicConsumedData that indicates all of |data| (and |fin| if set)
+ // has been consumed.
+ static QuicConsumedData ConsumeAllData(
+ QuicStreamId id,
+ const QuicIOVector& data,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate);
+
+ void OnProofValid(
+ const QuicCryptoClientConfig::CachedState& cached) override {}
+ void OnProofVerifyDetailsAvailable(
+ const ProofVerifyDetails& verify_details) override {}
+ bool IsAuthorized(const std::string& hostname) override { return true; }
+
+ protected:
+ MOCK_METHOD1(ShouldCreateIncomingDynamicStream, bool(QuicStreamId id));
+ MOCK_METHOD0(ShouldCreateOutgoingDynamicStream, bool());
+
+ private:
+ std::unique_ptr<QuicCryptoStream> crypto_stream_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockQuicClientSessionBase);
+};
+
+MockQuicClientSessionBase::MockQuicClientSessionBase(
+ QuicConnection* connection,
+ QuicClientPushPromiseIndex* push_promise_index)
+ : QuicClientSessionBase(connection,
+ push_promise_index,
+ DefaultQuicConfig()) {
+ crypto_stream_.reset(new QuicCryptoStream(this));
+ Initialize();
+ ON_CALL(*this, WritevData(_, _, _, _, _, _))
+ .WillByDefault(testing::Return(QuicConsumedData(0, false)));
+}
+
+MockQuicClientSessionBase::~MockQuicClientSessionBase() {}
+
+class QuicChromiumClientStreamTest
+ : public ::testing::TestWithParam<QuicVersion> {
+ public:
+ QuicChromiumClientStreamTest()
+ : crypto_config_(CryptoTestUtils::ProofVerifierForTesting()),
+ session_(new MockQuicConnection(&helper_,
+ &alarm_factory_,
+ Perspective::IS_CLIENT,
+ SupportedVersions(GetParam())),
+ &push_promise_index_) {
+ stream_ = new QuicChromiumClientStream(kTestStreamId, &session_,
+ NetLogWithSource());
+ session_.ActivateStream(stream_);
+ stream_->SetDelegate(&delegate_);
+ }
+
+ void InitializeHeaders() {
+ headers_[":host"] = "www.google.com";
+ headers_[":path"] = "/index.hml";
+ headers_[":scheme"] = "https";
+ headers_["cookie"] =
+ "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; "
+ "__utmc=160408618; "
+ "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX"
+ "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX"
+ "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT"
+ "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0"
+ "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh"
+ "1zFMi5vzcns38-8_Sns; "
+ "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-"
+ "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339"
+ "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c"
+ "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%"
+ "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4"
+ "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1"
+ "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP"
+ "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6"
+ "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b"
+ "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6"
+ "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG"
+ "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk"
+ "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn"
+ "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
+ "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
+ }
+
+ void ReadData(StringPiece expected_data) {
+ scoped_refptr<IOBuffer> buffer(new IOBuffer(expected_data.length() + 1));
+ EXPECT_EQ(static_cast<int>(expected_data.length()),
+ stream_->Read(buffer.get(), expected_data.length() + 1));
+ EXPECT_EQ(expected_data,
+ StringPiece(buffer->data(), expected_data.length()));
+ }
+
+ QuicCryptoClientConfig crypto_config_;
+ testing::StrictMock<MockDelegate> delegate_;
+ MockQuicConnectionHelper helper_;
+ MockAlarmFactory alarm_factory_;
+ MockQuicClientSessionBase session_;
+ QuicChromiumClientStream* stream_;
+ SpdyHeaderBlock headers_;
+ QuicClientPushPromiseIndex push_promise_index_;
+};
+
+INSTANTIATE_TEST_CASE_P(Version,
+ QuicChromiumClientStreamTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
+
+TEST_P(QuicChromiumClientStreamTest, OnFinRead) {
+ InitializeHeaders();
+ std::string uncompressed_headers =
+ SpdyUtils::SerializeUncompressedHeaders(headers_);
+ QuicStreamOffset offset = 0;
+ stream_->OnStreamHeaders(uncompressed_headers);
+ stream_->OnStreamHeadersComplete(false, uncompressed_headers.length());
+
+ EXPECT_CALL(delegate_,
+ OnHeadersAvailableMock(_, uncompressed_headers.length()));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(headers_, delegate_.headers_);
+ EXPECT_TRUE(stream_->decompressed_headers().empty());
+
+ QuicStreamFrame frame2(kTestStreamId, true, offset, StringPiece());
+ EXPECT_CALL(delegate_, OnClose());
+ stream_->OnStreamFrame(frame2);
+}
+
+TEST_P(QuicChromiumClientStreamTest, OnDataAvailableBeforeHeaders) {
+ EXPECT_CALL(delegate_, OnClose());
+
+ EXPECT_CALL(delegate_, OnDataAvailable()).Times(0);
+ stream_->OnDataAvailable();
+}
+
+TEST_P(QuicChromiumClientStreamTest, OnDataAvailable) {
+ InitializeHeaders();
+ std::string uncompressed_headers =
+ SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(uncompressed_headers);
+ stream_->OnStreamHeadersComplete(false, uncompressed_headers.length());
+
+ EXPECT_CALL(delegate_,
+ OnHeadersAvailableMock(_, uncompressed_headers.length()));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(headers_, delegate_.headers_);
+ EXPECT_TRUE(stream_->decompressed_headers().empty());
+
+ const char data[] = "hello world!";
+ stream_->OnStreamFrame(QuicStreamFrame(kTestStreamId, /*fin=*/false,
+ /*offset=*/0, data));
+
+ EXPECT_CALL(delegate_, OnDataAvailable())
+ .WillOnce(testing::Invoke(
+ CreateFunctor(&QuicChromiumClientStreamTest::ReadData,
+ base::Unretained(this),
+ StringPiece(data, arraysize(data) - 1))));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_CALL(delegate_, OnClose());
+}
+
+TEST_P(QuicChromiumClientStreamTest, ProcessHeadersWithError) {
+ std::string bad_headers = "...";
+ EXPECT_CALL(session_,
+ SendRstStream(kTestStreamId, QUIC_BAD_APPLICATION_PAYLOAD, 0));
+
+ stream_->OnStreamHeaders(StringPiece(bad_headers));
+ stream_->OnStreamHeadersComplete(false, bad_headers.length());
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_CALL(delegate_, OnClose());
+}
+
+TEST_P(QuicChromiumClientStreamTest, OnDataAvailableWithError) {
+ InitializeHeaders();
+ std::string uncompressed_headers =
+ SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(uncompressed_headers);
+ stream_->OnStreamHeadersComplete(false, uncompressed_headers.length());
+
+ EXPECT_CALL(delegate_,
+ OnHeadersAvailableMock(_, uncompressed_headers.length()));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(headers_, delegate_.headers_);
+ EXPECT_TRUE(stream_->decompressed_headers().empty());
+
+ const char data[] = "hello world!";
+ stream_->OnStreamFrame(QuicStreamFrame(kTestStreamId, /*fin=*/false,
+ /*offset=*/0, data));
+ EXPECT_CALL(delegate_, OnDataAvailable())
+ .WillOnce(testing::Invoke(CreateFunctor(
+ &QuicChromiumClientStream::Reset,
+ base::Unretained(stream_), QUIC_STREAM_CANCELLED)));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_CALL(delegate_, OnClose());
+}
+
+TEST_P(QuicChromiumClientStreamTest, OnError) {
+ EXPECT_CALL(delegate_, OnError(ERR_INTERNET_DISCONNECTED));
+
+ stream_->OnError(ERR_INTERNET_DISCONNECTED);
+ EXPECT_FALSE(stream_->GetDelegate());
+}
+
+TEST_P(QuicChromiumClientStreamTest, OnTrailers) {
+ InitializeHeaders();
+ std::string uncompressed_headers =
+ SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(uncompressed_headers);
+ stream_->OnStreamHeadersComplete(false, uncompressed_headers.length());
+
+ EXPECT_CALL(delegate_,
+ OnHeadersAvailableMock(_, uncompressed_headers.length()));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(headers_, delegate_.headers_);
+ EXPECT_TRUE(stream_->decompressed_headers().empty());
+
+ const char data[] = "hello world!";
+ stream_->OnStreamFrame(QuicStreamFrame(kTestStreamId, /*fin=*/false,
+ /*offset=*/0, data));
+
+ EXPECT_CALL(delegate_, OnDataAvailable())
+ .WillOnce(testing::Invoke(CreateFunctor(
+ &QuicChromiumClientStreamTest::ReadData, base::Unretained(this),
+ StringPiece(data, arraysize(data) - 1))));
+
+ SpdyHeaderBlock trailers;
+ trailers["bar"] = "foo";
+ trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(data));
+ std::string uncompressed_trailers =
+ SpdyUtils::SerializeUncompressedHeaders(trailers);
+
+ stream_->OnStreamHeaders(uncompressed_trailers);
+ stream_->OnStreamHeadersComplete(true, uncompressed_trailers.length());
+
+ base::RunLoop run_loop;
+ EXPECT_CALL(delegate_,
+ OnHeadersAvailableMock(_, uncompressed_trailers.length()))
+ .WillOnce(testing::InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); }));
+
+ run_loop.Run();
+
+ // OnDataAvailable callback should follow trailers notification.
+ base::RunLoop run_loop3;
+ EXPECT_CALL(delegate_, OnDataAvailable())
+ .Times(1)
+ .WillOnce(testing::DoAll(
+ testing::Invoke(CreateFunctor(&QuicChromiumClientStreamTest::ReadData,
+ base::Unretained(this), StringPiece())),
+ testing::InvokeWithoutArgs([&run_loop3]() { run_loop3.Quit(); })));
+ run_loop3.Run();
+
+ // Make sure kFinalOffsetHeaderKey is gone from the delivered actual trailers.
+ trailers.erase(kFinalOffsetHeaderKey);
+ EXPECT_EQ(trailers, delegate_.headers_);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_CALL(delegate_, OnClose());
+}
+
+// Tests that trailers are marked as consumed only before delegate is to be
+// immediately notified about trailers.
+TEST_P(QuicChromiumClientStreamTest, MarkTrailersConsumedWhenNotifyDelegate) {
+ InitializeHeaders();
+ std::string uncompressed_headers =
+ SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(uncompressed_headers);
+ stream_->OnStreamHeadersComplete(false, uncompressed_headers.length());
+
+ EXPECT_CALL(delegate_,
+ OnHeadersAvailableMock(_, uncompressed_headers.length()));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(headers_, delegate_.headers_);
+ EXPECT_TRUE(stream_->decompressed_headers().empty());
+
+ const char data[] = "hello world!";
+ stream_->OnStreamFrame(QuicStreamFrame(kTestStreamId, /*fin=*/false,
+ /*offset=*/0, data));
+
+ base::RunLoop run_loop;
+ EXPECT_CALL(delegate_, OnDataAvailable())
+ .Times(1)
+ .WillOnce(testing::DoAll(
+ testing::Invoke(CreateFunctor(
+ &QuicChromiumClientStreamTest::ReadData, base::Unretained(this),
+ StringPiece(data, arraysize(data) - 1))),
+ testing::Invoke([&run_loop]() { run_loop.Quit(); })));
+
+ // Wait for the read to complete.
+ run_loop.Run();
+
+ // Read again, and it will be pending.
+ scoped_refptr<IOBuffer> buffer(new IOBuffer(1));
+ EXPECT_THAT(stream_->Read(buffer.get(), 1), IsError(ERR_IO_PENDING));
+
+ SpdyHeaderBlock trailers;
+ trailers["bar"] = "foo";
+ trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(data));
+ std::string uncompressed_trailers =
+ SpdyUtils::SerializeUncompressedHeaders(trailers);
+
+ stream_->OnStreamHeaders(uncompressed_trailers);
+ stream_->OnStreamHeadersComplete(true, uncompressed_trailers.length());
+ EXPECT_FALSE(stream_->IsDoneReading());
+
+ base::RunLoop run_loop2;
+ EXPECT_CALL(delegate_,
+ OnHeadersAvailableMock(_, uncompressed_trailers.length()))
+ .WillOnce(
+ testing::InvokeWithoutArgs([&run_loop2]() { run_loop2.Quit(); }));
+
+ run_loop2.Run();
+
+ // OnDataAvailable callback should follow trailers notification.
+ base::RunLoop run_loop3;
+ EXPECT_CALL(delegate_, OnDataAvailable())
+ .Times(1)
+ .WillOnce(testing::DoAll(
+ testing::Invoke(CreateFunctor(&QuicChromiumClientStreamTest::ReadData,
+ base::Unretained(this), StringPiece())),
+ testing::InvokeWithoutArgs([&run_loop3]() { run_loop3.Quit(); })));
+ run_loop3.Run();
+
+ // Make sure the stream is properly closed since trailers and data are all
+ // consumed.
+ EXPECT_TRUE(stream_->IsDoneReading());
+ // Make sure kFinalOffsetHeaderKey is gone from the delivered actual trailers.
+ trailers.erase(kFinalOffsetHeaderKey);
+ EXPECT_EQ(trailers, delegate_.headers_);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_CALL(delegate_, OnClose());
+}
+
+// Test that if Read() is called after response body is read and after trailers
+// are received but not yet delivered, Read() will return ERR_IO_PENDING instead
+// of 0 (EOF).
+TEST_P(QuicChromiumClientStreamTest, ReadAfterTrailersReceivedButNotDelivered) {
+ InitializeHeaders();
+ std::string uncompressed_headers =
+ SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(uncompressed_headers);
+ stream_->OnStreamHeadersComplete(false, uncompressed_headers.length());
+
+ EXPECT_CALL(delegate_,
+ OnHeadersAvailableMock(_, uncompressed_headers.length()));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(headers_, delegate_.headers_);
+ EXPECT_TRUE(stream_->decompressed_headers().empty());
+
+ const char data[] = "hello world!";
+ stream_->OnStreamFrame(QuicStreamFrame(kTestStreamId, /*fin=*/false,
+ /*offset=*/0, data));
+
+ base::RunLoop run_loop;
+ EXPECT_CALL(delegate_, OnDataAvailable())
+ .Times(1)
+ .WillOnce(testing::DoAll(
+ testing::Invoke(CreateFunctor(
+ &QuicChromiumClientStreamTest::ReadData, base::Unretained(this),
+ StringPiece(data, arraysize(data) - 1))),
+ testing::Invoke([&run_loop]() { run_loop.Quit(); })));
+
+ // Wait for the read to complete.
+ run_loop.Run();
+
+ // Deliver trailers. Delegate notification is posted asynchronously.
+ SpdyHeaderBlock trailers;
+ trailers["bar"] = "foo";
+ trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(data));
+ std::string uncompressed_trailers =
+ SpdyUtils::SerializeUncompressedHeaders(trailers);
+
+ stream_->OnStreamHeaders(uncompressed_trailers);
+ stream_->OnStreamHeadersComplete(true, uncompressed_trailers.length());
+
+ // Read again, it return ERR_IO_PENDING.
+ scoped_refptr<IOBuffer> buffer(new IOBuffer(1));
+ EXPECT_THAT(stream_->Read(buffer.get(), 1), ERR_IO_PENDING);
+
+ // Trailers are not delivered
+ EXPECT_FALSE(stream_->IsDoneReading());
+
+ base::RunLoop run_loop2;
+ EXPECT_CALL(delegate_,
+ OnHeadersAvailableMock(_, uncompressed_trailers.length()))
+ .WillOnce(
+ testing::InvokeWithoutArgs([&run_loop2]() { run_loop2.Quit(); }));
+
+ run_loop2.Run();
+
+ base::RunLoop run_loop3;
+ // OnDataAvailable() should follow right after and Read() will return 0.
+ EXPECT_CALL(delegate_, OnDataAvailable())
+ .WillOnce(testing::DoAll(
+ testing::Invoke(CreateFunctor(&QuicChromiumClientStreamTest::ReadData,
+ base::Unretained(this), StringPiece())),
+ testing::Invoke([&run_loop3]() { run_loop3.Quit(); })));
+ run_loop3.Run();
+
+ // Make sure the stream is properly closed since trailers and data are all
+ // consumed.
+ EXPECT_TRUE(stream_->IsDoneReading());
+
+ // Make sure kFinalOffsetHeaderKey is gone from the delivered actual trailers.
+ trailers.erase(kFinalOffsetHeaderKey);
+ EXPECT_EQ(trailers, delegate_.headers_);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_CALL(delegate_, OnClose());
+}
+
+TEST_P(QuicChromiumClientStreamTest, WriteStreamData) {
+ EXPECT_CALL(delegate_, OnClose());
+
+ const char kData1[] = "hello world";
+ const size_t kDataLen = arraysize(kData1);
+
+ // All data written.
+ EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(kDataLen, true)));
+ TestCompletionCallback callback;
+ EXPECT_EQ(OK, stream_->WriteStreamData(base::StringPiece(kData1, kDataLen),
+ true, callback.callback()));
+}
+
+TEST_P(QuicChromiumClientStreamTest, WriteStreamDataAsync) {
+ EXPECT_CALL(delegate_, HasSendHeadersComplete()).Times(AnyNumber());
+ EXPECT_CALL(delegate_, OnClose());
+
+ const char kData1[] = "hello world";
+ const size_t kDataLen = arraysize(kData1);
+
+ // No data written.
+ EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(0, false)));
+ TestCompletionCallback callback;
+ EXPECT_EQ(ERR_IO_PENDING,
+ stream_->WriteStreamData(base::StringPiece(kData1, kDataLen), true,
+ callback.callback()));
+ ASSERT_FALSE(callback.have_result());
+
+ // All data written.
+ EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(kDataLen, true)));
+ stream_->OnCanWrite();
+ ASSERT_TRUE(callback.have_result());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
+}
+
+TEST_P(QuicChromiumClientStreamTest, WritevStreamData) {
+ EXPECT_CALL(delegate_, OnClose());
+
+ scoped_refptr<StringIOBuffer> buf1(new StringIOBuffer("hello world!"));
+ scoped_refptr<StringIOBuffer> buf2(
+ new StringIOBuffer("Just a small payload"));
+
+ // All data written.
+ EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(buf1->size(), false)))
+ .WillOnce(Return(QuicConsumedData(buf2->size(), true)));
+ TestCompletionCallback callback;
+ EXPECT_EQ(
+ OK, stream_->WritevStreamData({buf1, buf2}, {buf1->size(), buf2->size()},
+ true, callback.callback()));
+}
+
+TEST_P(QuicChromiumClientStreamTest, WritevStreamDataAsync) {
+ EXPECT_CALL(delegate_, HasSendHeadersComplete()).Times(AnyNumber());
+ EXPECT_CALL(delegate_, OnClose());
+
+ scoped_refptr<StringIOBuffer> buf1(new StringIOBuffer("hello world!"));
+ scoped_refptr<StringIOBuffer> buf2(
+ new StringIOBuffer("Just a small payload"));
+
+ // Only a part of the data is written.
+ EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _, _))
+ // First piece of data is written.
+ .WillOnce(Return(QuicConsumedData(buf1->size(), false)))
+ // Second piece of data is queued.
+ .WillOnce(Return(QuicConsumedData(0, false)));
+ TestCompletionCallback callback;
+ EXPECT_EQ(ERR_IO_PENDING,
+ stream_->WritevStreamData({buf1.get(), buf2.get()},
+ {buf1->size(), buf2->size()}, true,
+ callback.callback()));
+ ASSERT_FALSE(callback.have_result());
+
+ // The second piece of data is written.
+ EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(buf2->size(), true)));
+ stream_->OnCanWrite();
+ ASSERT_TRUE(callback.have_result());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
+}
+
+TEST_P(QuicChromiumClientStreamTest, HeadersBeforeDelegate) {
+ // We don't use stream_ because we want an incoming server push
+ // stream.
+ QuicChromiumClientStream* stream = new QuicChromiumClientStream(
+ kServerDataStreamId1, &session_, NetLogWithSource());
+ session_.ActivateStream(stream);
+
+ InitializeHeaders();
+ std::string uncompressed_headers =
+ SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream->OnStreamHeaders(uncompressed_headers);
+ stream->OnStreamHeadersComplete(false, uncompressed_headers.length());
+ EXPECT_TRUE(stream->decompressed_headers().empty());
+
+ EXPECT_CALL(delegate_,
+ OnHeadersAvailableMock(_, uncompressed_headers.length()));
+ stream->SetDelegate(&delegate_);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(headers_, delegate_.headers_);
+
+ // Times(2) because OnClose will be called for stream and stream_.
+ EXPECT_CALL(delegate_, OnClose()).Times(2);
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_chromium_connection_helper.cc b/chromium/net/quic/chromium/quic_chromium_connection_helper.cc
new file mode 100644
index 00000000000..235cdc21532
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_connection_helper.cc
@@ -0,0 +1,28 @@
+// 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/chromium/quic_chromium_connection_helper.h"
+
+namespace net {
+
+QuicChromiumConnectionHelper::QuicChromiumConnectionHelper(
+ const QuicClock* clock,
+ QuicRandom* random_generator)
+ : clock_(clock), random_generator_(random_generator) {}
+
+QuicChromiumConnectionHelper::~QuicChromiumConnectionHelper() {}
+
+const QuicClock* QuicChromiumConnectionHelper::GetClock() const {
+ return clock_;
+}
+
+QuicRandom* QuicChromiumConnectionHelper::GetRandomGenerator() {
+ return random_generator_;
+}
+
+QuicBufferAllocator* QuicChromiumConnectionHelper::GetBufferAllocator() {
+ return &buffer_allocator_;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_chromium_connection_helper.h b/chromium/net/quic/chromium/quic_chromium_connection_helper.h
new file mode 100644
index 00000000000..6ed4428e5bb
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_connection_helper.h
@@ -0,0 +1,47 @@
+// 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.
+//
+// The Chrome-specific helper for QuicConnection which uses
+// a TaskRunner for alarms, and uses a DatagramClientSocket for writing data.
+
+#ifndef NET_QUIC_QUIC_CHROMIUM_CONNECTION_HELPER_H_
+#define NET_QUIC_QUIC_CHROMIUM_CONNECTION_HELPER_H_
+
+#include "base/macros.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_simple_buffer_allocator.h"
+#include "net/quic/core/quic_time.h"
+#include "net/udp/datagram_client_socket.h"
+
+namespace net {
+
+class QuicClock;
+class QuicRandom;
+
+class NET_EXPORT_PRIVATE QuicChromiumConnectionHelper
+ : public QuicConnectionHelperInterface {
+ public:
+ QuicChromiumConnectionHelper(const QuicClock* clock,
+ QuicRandom* random_generator);
+ ~QuicChromiumConnectionHelper() override;
+
+ // QuicConnectionHelperInterface
+ const QuicClock* GetClock() const override;
+ QuicRandom* GetRandomGenerator() override;
+ QuicBufferAllocator* GetBufferAllocator() override;
+
+ private:
+ const QuicClock* clock_;
+ QuicRandom* random_generator_;
+ SimpleBufferAllocator buffer_allocator_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicChromiumConnectionHelper);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CHROMIUM_CONNECTION_HELPER_H_
diff --git a/chromium/net/quic/chromium/quic_chromium_connection_helper_test.cc b/chromium/net/quic/chromium/quic_chromium_connection_helper_test.cc
new file mode 100644
index 00000000000..11a14766645
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_connection_helper_test.cc
@@ -0,0 +1,34 @@
+// 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/chromium/quic_chromium_connection_helper.h"
+
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/mock_random.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+namespace {
+
+class QuicChromiumConnectionHelperTest : public ::testing::Test {
+ protected:
+ QuicChromiumConnectionHelperTest() : helper_(&clock_, &random_generator_) {}
+
+ QuicChromiumConnectionHelper helper_;
+ MockClock clock_;
+ MockRandom random_generator_;
+};
+
+TEST_F(QuicChromiumConnectionHelperTest, GetClock) {
+ EXPECT_EQ(&clock_, helper_.GetClock());
+}
+
+TEST_F(QuicChromiumConnectionHelperTest, GetRandomGenerator) {
+ EXPECT_EQ(&random_generator_, helper_.GetRandomGenerator());
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_chromium_packet_reader.cc b/chromium/net/quic/chromium/quic_chromium_packet_reader.cc
new file mode 100644
index 00000000000..1c5d660ed0e
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_packet_reader.cc
@@ -0,0 +1,90 @@
+// 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.
+
+#include "net/quic/chromium/quic_chromium_packet_reader.h"
+
+#include "base/location.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "net/base/net_errors.h"
+#include "net/quic/core/quic_clock.h"
+
+namespace net {
+
+QuicChromiumPacketReader::QuicChromiumPacketReader(
+ DatagramClientSocket* socket,
+ QuicClock* clock,
+ Visitor* visitor,
+ int yield_after_packets,
+ QuicTime::Delta yield_after_duration,
+ const NetLogWithSource& net_log)
+ : socket_(socket),
+ visitor_(visitor),
+ read_pending_(false),
+ num_packets_read_(0),
+ clock_(clock),
+ yield_after_packets_(yield_after_packets),
+ yield_after_duration_(yield_after_duration),
+ yield_after_(QuicTime::Infinite()),
+ read_buffer_(new IOBufferWithSize(static_cast<size_t>(kMaxPacketSize))),
+ net_log_(net_log),
+ weak_factory_(this) {}
+
+QuicChromiumPacketReader::~QuicChromiumPacketReader() {}
+
+void QuicChromiumPacketReader::StartReading() {
+ if (read_pending_)
+ return;
+
+ if (num_packets_read_ == 0)
+ yield_after_ = clock_->Now() + yield_after_duration_;
+
+ DCHECK(socket_);
+ read_pending_ = true;
+ int rv = socket_->Read(read_buffer_.get(), read_buffer_->size(),
+ base::Bind(&QuicChromiumPacketReader::OnReadComplete,
+ weak_factory_.GetWeakPtr()));
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.AsyncRead", rv == ERR_IO_PENDING);
+ if (rv == ERR_IO_PENDING) {
+ num_packets_read_ = 0;
+ return;
+ }
+
+ if (++num_packets_read_ > yield_after_packets_ ||
+ clock_->Now() > yield_after_) {
+ num_packets_read_ = 0;
+ // Data was read, process it.
+ // Schedule the work through the message loop to 1) prevent infinite
+ // recursion and 2) avoid blocking the thread for too long.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&QuicChromiumPacketReader::OnReadComplete,
+ weak_factory_.GetWeakPtr(), rv));
+ } else {
+ OnReadComplete(rv);
+ }
+}
+
+void QuicChromiumPacketReader::OnReadComplete(int result) {
+ read_pending_ = false;
+ if (result == 0)
+ result = ERR_CONNECTION_CLOSED;
+
+ if (result < 0) {
+ visitor_->OnReadError(result, socket_);
+ return;
+ }
+
+ QuicReceivedPacket packet(read_buffer_->data(), result, clock_->Now());
+ IPEndPoint local_address;
+ IPEndPoint peer_address;
+ socket_->GetLocalAddress(&local_address);
+ socket_->GetPeerAddress(&peer_address);
+ if (!visitor_->OnPacket(packet, local_address, peer_address))
+ return;
+
+ StartReading();
+}
+
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_chromium_packet_reader.h b/chromium/net/quic/chromium/quic_chromium_packet_reader.h
new file mode 100644
index 00000000000..636741ca39b
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_packet_reader.h
@@ -0,0 +1,74 @@
+// 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.
+//
+
+#ifndef NET_QUIC_QUIC_CHROMIUM_PACKET_READER_H_
+#define NET_QUIC_QUIC_CHROMIUM_PACKET_READER_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_export.h"
+#include "net/log/net_log_with_source.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+#include "net/udp/datagram_client_socket.h"
+
+namespace net {
+
+class QuicClock;
+
+// If more than this many packets have been read or more than that many
+// milliseconds have passed, QuicChromiumPacketReader::StartReading() yields by
+// doing a QuicChromiumPacketReader::PostTask().
+const int kQuicYieldAfterPacketsRead = 32;
+const int kQuicYieldAfterDurationMilliseconds = 20;
+
+class NET_EXPORT_PRIVATE QuicChromiumPacketReader {
+ public:
+ class NET_EXPORT_PRIVATE Visitor {
+ public:
+ virtual ~Visitor() {}
+ virtual void OnReadError(int result,
+ const DatagramClientSocket* socket) = 0;
+ virtual bool OnPacket(const QuicReceivedPacket& packet,
+ IPEndPoint local_address,
+ IPEndPoint peer_address) = 0;
+ };
+
+ QuicChromiumPacketReader(DatagramClientSocket* socket,
+ QuicClock* clock,
+ Visitor* visitor,
+ int yield_after_packets,
+ QuicTime::Delta yield_after_duration,
+ const NetLogWithSource& net_log);
+ virtual ~QuicChromiumPacketReader();
+
+ // Causes the QuicConnectionHelper to start reading from the socket
+ // and passing the data along to the QuicConnection.
+ void StartReading();
+
+ private:
+ // A completion callback invoked when a read completes.
+ void OnReadComplete(int result);
+
+ DatagramClientSocket* socket_;
+ Visitor* visitor_;
+ bool read_pending_;
+ int num_packets_read_;
+ QuicClock* clock_; // Owned by QuicStreamFactory
+ int yield_after_packets_;
+ QuicTime::Delta yield_after_duration_;
+ QuicTime yield_after_;
+ scoped_refptr<IOBufferWithSize> read_buffer_;
+ NetLogWithSource net_log_;
+
+ base::WeakPtrFactory<QuicChromiumPacketReader> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicChromiumPacketReader);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CHROMIUM_PACKET_READER_H_
diff --git a/chromium/net/quic/chromium/quic_chromium_packet_writer.cc b/chromium/net/quic/chromium/quic_chromium_packet_writer.cc
new file mode 100644
index 00000000000..5478d7173c8
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_packet_writer.cc
@@ -0,0 +1,117 @@
+// Copyright 2013 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/chromium/quic_chromium_packet_writer.h"
+
+#include <string>
+
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/quic/chromium/quic_chromium_client_session.h"
+
+namespace net {
+
+QuicChromiumPacketWriter::QuicChromiumPacketWriter() : weak_factory_(this) {}
+
+QuicChromiumPacketWriter::QuicChromiumPacketWriter(Socket* socket)
+ : socket_(socket),
+ delegate_(nullptr),
+ packet_(nullptr),
+ write_blocked_(false),
+ weak_factory_(this) {}
+
+QuicChromiumPacketWriter::~QuicChromiumPacketWriter() {}
+
+WriteResult QuicChromiumPacketWriter::WritePacket(
+ const char* buffer,
+ size_t buf_len,
+ const IPAddress& self_address,
+ const IPEndPoint& peer_address,
+ PerPacketOptions* /*options*/) {
+ scoped_refptr<StringIOBuffer> buf(
+ new StringIOBuffer(std::string(buffer, buf_len)));
+ DCHECK(!IsWriteBlocked());
+ return WritePacketToSocket(buf);
+}
+
+WriteResult QuicChromiumPacketWriter::WritePacketToSocket(
+ scoped_refptr<StringIOBuffer> packet) {
+ base::TimeTicks now = base::TimeTicks::Now();
+ int rv = socket_->Write(packet.get(), packet.get()->size(),
+ base::Bind(&QuicChromiumPacketWriter::OnWriteComplete,
+ weak_factory_.GetWeakPtr()));
+
+ if (rv < 0 && rv != ERR_IO_PENDING && delegate_ != nullptr) {
+ // If write error, then call delegate's HandleWriteError, which
+ // may be able to migrate and rewrite packet on a new socket.
+ // HandleWriteError returns the outcome of that rewrite attempt.
+ rv = delegate_->HandleWriteError(rv, packet);
+ }
+
+ WriteStatus status = WRITE_STATUS_OK;
+ if (rv < 0) {
+ if (rv != ERR_IO_PENDING) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.WriteError", -rv);
+ status = WRITE_STATUS_ERROR;
+ } else {
+ status = WRITE_STATUS_BLOCKED;
+ write_blocked_ = true;
+ packet_ = packet;
+ }
+ }
+
+ base::TimeDelta delta = base::TimeTicks::Now() - now;
+ if (status == WRITE_STATUS_OK) {
+ UMA_HISTOGRAM_TIMES("Net.QuicSession.PacketWriteTime.Synchronous", delta);
+ } else if (status == WRITE_STATUS_BLOCKED) {
+ UMA_HISTOGRAM_TIMES("Net.QuicSession.PacketWriteTime.Asynchronous", delta);
+ }
+
+ return WriteResult(status, rv);
+}
+
+bool QuicChromiumPacketWriter::IsWriteBlockedDataBuffered() const {
+ // Chrome sockets' Write() methods buffer the data until the Write is
+ // permitted.
+ return true;
+}
+
+bool QuicChromiumPacketWriter::IsWriteBlocked() const {
+ return write_blocked_;
+}
+
+void QuicChromiumPacketWriter::SetWritable() {
+ write_blocked_ = false;
+}
+
+void QuicChromiumPacketWriter::OnWriteComplete(int rv) {
+ DCHECK_NE(rv, ERR_IO_PENDING);
+ DCHECK(delegate_) << "Uninitialized delegate.";
+ write_blocked_ = false;
+ if (rv < 0) {
+ // If write error, then call delegate's HandleWriteError, which
+ // may be able to migrate and rewrite packet on a new socket.
+ // HandleWriteError returns the outcome of that rewrite attempt.
+ rv = delegate_->HandleWriteError(rv, packet_);
+ packet_ = nullptr;
+ if (rv == ERR_IO_PENDING)
+ return;
+ }
+
+ if (rv < 0)
+ delegate_->OnWriteError(rv);
+ else
+ delegate_->OnWriteUnblocked();
+}
+
+QuicByteCount QuicChromiumPacketWriter::GetMaxPacketSize(
+ const IPEndPoint& peer_address) const {
+ return kMaxPacketSize;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_chromium_packet_writer.h b/chromium/net/quic/chromium/quic_chromium_packet_writer.h
new file mode 100644
index 00000000000..4e0970807c4
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_chromium_packet_writer.h
@@ -0,0 +1,87 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_CHROMIUM_PACKET_WRITER_H_
+#define NET_QUIC_QUIC_CHROMIUM_PACKET_WRITER_H_
+
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "net/base/io_buffer.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_types.h"
+#include "net/udp/datagram_client_socket.h"
+
+namespace net {
+
+// Chrome specific packet writer which uses a datagram Socket for writing data.
+class NET_EXPORT_PRIVATE QuicChromiumPacketWriter : public QuicPacketWriter {
+ public:
+ // Delegate interface which receives notifications on socket write events.
+ class NET_EXPORT_PRIVATE Delegate {
+ public:
+ // Called when a socket write attempt results in a failure, so
+ // that the delegate may recover from it by perhaps rewriting the
+ // packet to a different socket. An implementation must return the
+ // return value from the rewrite attempt if there is one, and
+ // |error_code| otherwise.
+ virtual int HandleWriteError(int error_code,
+ scoped_refptr<StringIOBuffer> last_packet) = 0;
+
+ // Called to propagate the final write error to the delegate.
+ virtual void OnWriteError(int error_code) = 0;
+
+ // Called when the writer is unblocked due to a write completion.
+ virtual void OnWriteUnblocked() = 0;
+ };
+
+ QuicChromiumPacketWriter();
+ // |socket| must outlive writer.
+ explicit QuicChromiumPacketWriter(Socket* socket);
+ ~QuicChromiumPacketWriter() override;
+
+ // |delegate| must outlive writer.
+ void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+
+ void set_write_blocked(bool write_blocked) { write_blocked_ = write_blocked; }
+
+ // Writes |packet| to the socket and returns the error code from the write.
+ WriteResult WritePacketToSocket(scoped_refptr<StringIOBuffer> packet);
+
+ // QuicPacketWriter
+ WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const IPAddress& self_address,
+ const IPEndPoint& peer_address,
+ PerPacketOptions* options) override;
+ bool IsWriteBlockedDataBuffered() const override;
+ bool IsWriteBlocked() const override;
+ void SetWritable() override;
+ QuicByteCount GetMaxPacketSize(const IPEndPoint& peer_address) const override;
+
+ void OnWriteComplete(int rv);
+
+ private:
+ Socket* socket_; // Unowned.
+ Delegate* delegate_; // Unowned.
+ // When a write returns asynchronously, |packet_| stores the written
+ // packet until OnWriteComplete is called.
+ scoped_refptr<StringIOBuffer> packet_;
+
+ // Whether a write is currently in flight.
+ bool write_blocked_;
+
+ base::WeakPtrFactory<QuicChromiumPacketWriter> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicChromiumPacketWriter);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CHROMIUM_PACKET_WRITER_H_
diff --git a/chromium/net/quic/chromium/quic_connection_logger.cc b/chromium/net/quic/chromium/quic_connection_logger.cc
new file mode 100644
index 00000000000..4f096e1592c
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_connection_logger.cc
@@ -0,0 +1,750 @@
+// Copyright (c) 2013 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/chromium/quic_connection_logger.h"
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+#include "net/base/ip_address.h"
+#include "net/cert/x509_certificate.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/quic_address_mismatch.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_socket_address_coder.h"
+#include "net/quic/core/quic_time.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+namespace {
+
+std::unique_ptr<base::Value> NetLogQuicPacketCallback(
+ const IPEndPoint* self_address,
+ const IPEndPoint* peer_address,
+ size_t packet_size,
+ NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetString("self_address", self_address->ToString());
+ dict->SetString("peer_address", peer_address->ToString());
+ dict->SetInteger("size", packet_size);
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicPacketSentCallback(
+ const SerializedPacket& serialized_packet,
+ TransmissionType transmission_type,
+ QuicTime sent_time,
+ NetLogCaptureMode /* capture_mode */) {
+ 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));
+ dict->SetInteger("size", serialized_packet.encrypted_length);
+ dict->SetString("sent_time_us",
+ base::Int64ToString(sent_time.ToDebuggingValue()));
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicPacketRetransmittedCallback(
+ QuicPacketNumber old_packet_number,
+ 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));
+ return std::move(dict);
+}
+
+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));
+ return std::move(dict);
+}
+
+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->public_header.connection_id));
+ dict->SetInteger("reset_flag", header->public_header.reset_flag);
+ dict->SetInteger("version_flag", header->public_header.version_flag);
+ dict->SetString("packet_number", base::Uint64ToString(header->packet_number));
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicStreamFrameCallback(
+ const QuicStreamFrame* frame,
+ NetLogCaptureMode /* capture_mode */) {
+ 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->SetInteger("length", frame->data_length);
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicAckFrameCallback(
+ const QuicAckFrame* frame,
+ NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetString("largest_observed",
+ base::Uint64ToString(frame->largest_observed));
+ dict->SetString("delta_time_largest_observed_us",
+ base::Int64ToString(frame->ack_delay_time.ToMicroseconds()));
+ if (frame->missing) {
+ // Entropy and Truncated are not present in v34 and above.
+ dict->SetInteger("entropy_hash", frame->entropy_hash);
+ dict->SetBoolean("truncated", frame->is_truncated);
+ }
+
+ base::ListValue* missing = new base::ListValue();
+ dict->Set("missing_packets", missing);
+ if (frame->missing) {
+ for (const Interval<QuicPacketNumber>& interval : frame->packets) {
+ for (QuicPacketNumber packet = interval.min(); packet < interval.max();
+ ++packet) {
+ missing->AppendString(base::Uint64ToString(packet));
+ }
+ }
+ } else if (!frame->packets.Empty()) {
+ // 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->largest_observed; ++packet) {
+ if (!frame->packets.Contains(packet)) {
+ missing->AppendString(base::Uint64ToString(packet));
+ }
+ }
+ }
+
+ base::ListValue* received = new base::ListValue();
+ dict->Set("received_packet_times", received);
+ const PacketTimeVector& received_times = frame->received_packet_times;
+ for (PacketTimeVector::const_iterator it = received_times.begin();
+ it != received_times.end(); ++it) {
+ std::unique_ptr<base::DictionaryValue> info(new base::DictionaryValue());
+ info->SetInteger("packet_number", static_cast<int>(it->first));
+ info->SetString("received",
+ base::Int64ToString(it->second.ToDebuggingValue()));
+ received->Append(std::move(info));
+ }
+
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicRstStreamFrameCallback(
+ const QuicRstStreamFrame* frame,
+ NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetInteger("stream_id", frame->stream_id);
+ dict->SetInteger("quic_rst_stream_error", frame->error_code);
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicConnectionCloseFrameCallback(
+ const QuicConnectionCloseFrame* frame,
+ NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetInteger("quic_error", frame->error_code);
+ dict->SetString("details", frame->error_details);
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicWindowUpdateFrameCallback(
+ const QuicWindowUpdateFrame* frame,
+ 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));
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicBlockedFrameCallback(
+ const QuicBlockedFrame* frame,
+ NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetInteger("stream_id", frame->stream_id);
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicGoAwayFrameCallback(
+ const QuicGoAwayFrame* frame,
+ NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetInteger("quic_error", frame->error_code);
+ dict->SetInteger("last_good_stream_id", frame->last_good_stream_id);
+ dict->SetString("reason_phrase", frame->reason_phrase);
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicStopWaitingFrameCallback(
+ const QuicStopWaitingFrame* frame,
+ NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ base::DictionaryValue* sent_info = new base::DictionaryValue();
+ dict->Set("sent_info", sent_info);
+ sent_info->SetString("least_unacked",
+ base::Uint64ToString(frame->least_unacked));
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicVersionNegotiationPacketCallback(
+ const QuicVersionNegotiationPacket* packet,
+ NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ base::ListValue* versions = new base::ListValue();
+ dict->Set("versions", versions);
+ for (QuicVersionVector::const_iterator it = packet->versions.begin();
+ it != packet->versions.end(); ++it) {
+ versions->AppendString(QuicVersionToString(*it));
+ }
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicCryptoHandshakeMessageCallback(
+ const CryptoHandshakeMessage* message,
+ NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetString("quic_crypto_handshake_message", message->DebugString());
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicOnConnectionClosedCallback(
+ QuicErrorCode error,
+ ConnectionCloseSource source,
+ NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetInteger("quic_error", error);
+ dict->SetBoolean("from_peer",
+ source == ConnectionCloseSource::FROM_PEER ? true : false);
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicCertificateVerifiedCallback(
+ scoped_refptr<X509Certificate> cert,
+ NetLogCaptureMode /* capture_mode */) {
+ // Only the subjects are logged so that we can investigate connection pooling.
+ // More fields could be logged in the future.
+ std::vector<std::string> dns_names;
+ cert->GetDNSNames(&dns_names);
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ base::ListValue* subjects = new base::ListValue();
+ for (std::vector<std::string>::const_iterator it = dns_names.begin();
+ it != dns_names.end(); it++) {
+ subjects->AppendString(*it);
+ }
+ dict->Set("subjects", subjects);
+ return std::move(dict);
+}
+
+void UpdatePacketGapSentHistogram(size_t num_consecutive_missing_packets) {
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.PacketGapSent",
+ num_consecutive_missing_packets);
+}
+
+void UpdatePublicResetAddressMismatchHistogram(
+ const IPEndPoint& server_hello_address,
+ const IPEndPoint& public_reset_address) {
+ int sample = GetAddressMismatch(server_hello_address, public_reset_address);
+ // We are seemingly talking to an older server that does not support the
+ // feature, so we can't report the results in the histogram.
+ if (sample < 0) {
+ return;
+ }
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.PublicResetAddressMismatch2",
+ sample, QUIC_ADDRESS_MISMATCH_MAX);
+}
+
+// If |address| is an IPv4-mapped IPv6 address, returns ADDRESS_FAMILY_IPV4
+// instead of ADDRESS_FAMILY_IPV6. Othewise, behaves like GetAddressFamily().
+AddressFamily GetRealAddressFamily(const IPAddress& address) {
+ return address.IsIPv4MappedIPv6() ? ADDRESS_FAMILY_IPV4
+ : GetAddressFamily(address);
+}
+
+} // namespace
+
+QuicConnectionLogger::QuicConnectionLogger(
+ QuicSpdySession* session,
+ const char* const connection_description,
+ std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
+ const NetLogWithSource& net_log)
+ : net_log_(net_log),
+ session_(session),
+ last_received_packet_number_(0),
+ last_received_packet_size_(0),
+ no_packet_received_after_ping_(false),
+ previous_received_packet_size_(0),
+ largest_received_packet_number_(0),
+ largest_received_missing_packet_number_(0),
+ num_out_of_order_received_packets_(0),
+ num_out_of_order_large_received_packets_(0),
+ num_packets_received_(0),
+ num_frames_received_(0),
+ num_duplicate_frames_received_(0),
+ num_incorrect_connection_ids_(0),
+ num_undecryptable_packets_(0),
+ num_duplicate_packets_(0),
+ num_blocked_frames_received_(0),
+ num_blocked_frames_sent_(0),
+ connection_description_(connection_description),
+ socket_performance_watcher_(std::move(socket_performance_watcher)) {}
+
+QuicConnectionLogger::~QuicConnectionLogger() {
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.OutOfOrderPacketsReceived",
+ num_out_of_order_received_packets_);
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.OutOfOrderLargePacketsReceived",
+ num_out_of_order_large_received_packets_);
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.IncorrectConnectionIDsReceived",
+ num_incorrect_connection_ids_);
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.UndecryptablePacketsReceived",
+ num_undecryptable_packets_);
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.DuplicatePacketsReceived",
+ num_duplicate_packets_);
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.BlockedFrames.Received",
+ num_blocked_frames_received_);
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.BlockedFrames.Sent",
+ num_blocked_frames_sent_);
+
+ const QuicConnectionStats& stats = session_->connection()->GetStats();
+ UMA_HISTOGRAM_TIMES("Net.QuicSession.MinRTT",
+ base::TimeDelta::FromMicroseconds(stats.min_rtt_us));
+ UMA_HISTOGRAM_TIMES("Net.QuicSession.SmoothedRTT",
+ base::TimeDelta::FromMicroseconds(stats.srtt_us));
+
+ if (num_frames_received_ > 0) {
+ int duplicate_stream_frame_per_thousand =
+ num_duplicate_frames_received_ * 1000 / num_frames_received_;
+ if (num_packets_received_ < 100) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Net.QuicSession.StreamFrameDuplicatedShortConnection",
+ duplicate_stream_frame_per_thousand, 1, 1000, 75);
+ } else {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Net.QuicSession.StreamFrameDuplicatedLongConnection",
+ duplicate_stream_frame_per_thousand, 1, 1000, 75);
+ }
+ }
+
+ RecordAggregatePacketLossRate();
+}
+
+void QuicConnectionLogger::OnFrameAddedToPacket(const QuicFrame& frame) {
+ switch (frame.type) {
+ case PADDING_FRAME:
+ break;
+ case STREAM_FRAME:
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_SESSION_STREAM_FRAME_SENT,
+ base::Bind(&NetLogQuicStreamFrameCallback, frame.stream_frame));
+ break;
+ case ACK_FRAME: {
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_SESSION_ACK_FRAME_SENT,
+ base::Bind(&NetLogQuicAckFrameCallback, frame.ack_frame));
+ break;
+ }
+ case RST_STREAM_FRAME:
+ UMA_HISTOGRAM_SPARSE_SLOWLY("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));
+ break;
+ case CONNECTION_CLOSE_FRAME:
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_SESSION_CONNECTION_CLOSE_FRAME_SENT,
+ base::Bind(&NetLogQuicConnectionCloseFrameCallback,
+ frame.connection_close_frame));
+ break;
+ case GOAWAY_FRAME:
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_SESSION_GOAWAY_FRAME_SENT,
+ base::Bind(&NetLogQuicGoAwayFrameCallback, frame.goaway_frame));
+ break;
+ case WINDOW_UPDATE_FRAME:
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_WINDOW_UPDATE_FRAME_SENT,
+ base::Bind(&NetLogQuicWindowUpdateFrameCallback,
+ frame.window_update_frame));
+ break;
+ case BLOCKED_FRAME:
+ ++num_blocked_frames_sent_;
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_SESSION_BLOCKED_FRAME_SENT,
+ base::Bind(&NetLogQuicBlockedFrameCallback, frame.blocked_frame));
+ break;
+ case STOP_WAITING_FRAME:
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_STOP_WAITING_FRAME_SENT,
+ base::Bind(&NetLogQuicStopWaitingFrameCallback,
+ frame.stop_waiting_frame));
+ break;
+ case PING_FRAME:
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ConnectionFlowControlBlocked",
+ session_->IsConnectionFlowControlBlocked());
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.StreamFlowControlBlocked",
+ session_->IsStreamFlowControlBlocked());
+ // PingFrame has no contents to log, so just record that it was sent.
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_PING_FRAME_SENT);
+ break;
+ case MTU_DISCOVERY_FRAME:
+ // MtuDiscoveryFrame is PingFrame on wire, it does not have any payload.
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_MTU_DISCOVERY_FRAME_SENT);
+ break;
+ default:
+ DCHECK(false) << "Illegal frame type: " << frame.type;
+ }
+}
+
+void QuicConnectionLogger::OnPacketSent(
+ const SerializedPacket& serialized_packet,
+ QuicPathId /* original_path_id */,
+ QuicPacketNumber original_packet_number,
+ TransmissionType transmission_type,
+ QuicTime sent_time) {
+ if (original_packet_number == 0) {
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_SESSION_PACKET_SENT,
+ base::Bind(&NetLogQuicPacketSentCallback, serialized_packet,
+ transmission_type, sent_time));
+ } else {
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_SESSION_PACKET_RETRANSMITTED,
+ base::Bind(&NetLogQuicPacketRetransmittedCallback,
+ original_packet_number, serialized_packet.packet_number));
+ }
+}
+
+void QuicConnectionLogger::OnPingSent() {
+ no_packet_received_after_ping_ = true;
+}
+
+void QuicConnectionLogger::OnPacketReceived(const IPEndPoint& self_address,
+ const IPEndPoint& peer_address,
+ const QuicEncryptedPacket& packet) {
+ if (local_address_from_self_.GetFamily() == ADDRESS_FAMILY_UNSPECIFIED) {
+ local_address_from_self_ = self_address;
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionTypeFromSelf",
+ GetRealAddressFamily(self_address.address()),
+ ADDRESS_FAMILY_LAST);
+ }
+
+ previous_received_packet_size_ = last_received_packet_size_;
+ last_received_packet_size_ = packet.length();
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_PACKET_RECEIVED,
+ base::Bind(&NetLogQuicPacketCallback, &self_address,
+ &peer_address, packet.length()));
+}
+
+void QuicConnectionLogger::OnUnauthenticatedHeader(
+ const QuicPacketHeader& header) {
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_SESSION_UNAUTHENTICATED_PACKET_HEADER_RECEIVED,
+ base::Bind(&NetLogQuicPacketHeaderCallback, &header));
+}
+
+void QuicConnectionLogger::OnIncorrectConnectionId(
+ QuicConnectionId connection_id) {
+ ++num_incorrect_connection_ids_;
+}
+
+void QuicConnectionLogger::OnUndecryptablePacket() {
+ ++num_undecryptable_packets_;
+}
+
+void QuicConnectionLogger::OnDuplicatePacket(QuicPacketNumber packet_number) {
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_SESSION_DUPLICATE_PACKET_RECEIVED,
+ base::Bind(&NetLogQuicDuplicatePacketCallback, packet_number));
+ ++num_duplicate_packets_;
+}
+
+void QuicConnectionLogger::OnProtocolVersionMismatch(
+ QuicVersion received_version) {
+ // TODO(rtenneti): Add logging.
+}
+
+void QuicConnectionLogger::OnPacketHeader(const QuicPacketHeader& header) {
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_PACKET_AUTHENTICATED);
+ ++num_packets_received_;
+ if (largest_received_packet_number_ < header.packet_number) {
+ QuicPacketNumber delta =
+ header.packet_number - largest_received_packet_number_;
+ if (delta > 1) {
+ // There is a gap between the largest packet previously received and
+ // the current packet. This indicates either loss, or out-of-order
+ // delivery.
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.PacketGapReceived",
+ static_cast<base::HistogramBase::Sample>(delta - 1));
+ }
+ largest_received_packet_number_ = header.packet_number;
+ }
+ if (header.packet_number < received_packets_.size()) {
+ received_packets_[static_cast<size_t>(header.packet_number)] = true;
+ }
+ if (header.packet_number < last_received_packet_number_) {
+ ++num_out_of_order_received_packets_;
+ if (previous_received_packet_size_ < last_received_packet_size_)
+ ++num_out_of_order_large_received_packets_;
+ UMA_HISTOGRAM_COUNTS(
+ "Net.QuicSession.OutOfOrderGapReceived",
+ static_cast<base::HistogramBase::Sample>(last_received_packet_number_ -
+ header.packet_number));
+ } else if (no_packet_received_after_ping_) {
+ UMA_HISTOGRAM_COUNTS(
+ "Net.QuicSession.PacketGapReceivedNearPing",
+ static_cast<base::HistogramBase::Sample>(header.packet_number -
+ last_received_packet_number_));
+ no_packet_received_after_ping_ = false;
+ }
+ last_received_packet_number_ = header.packet_number;
+}
+
+void QuicConnectionLogger::OnStreamFrame(const QuicStreamFrame& frame) {
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_STREAM_FRAME_RECEIVED,
+ base::Bind(&NetLogQuicStreamFrameCallback, &frame));
+}
+
+void QuicConnectionLogger::OnAckFrame(const QuicAckFrame& frame) {
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_ACK_FRAME_RECEIVED,
+ base::Bind(&NetLogQuicAckFrameCallback, &frame));
+
+ const size_t kApproximateLargestSoloAckBytes = 100;
+ if (last_received_packet_number_ < received_acks_.size() &&
+ last_received_packet_size_ < kApproximateLargestSoloAckBytes) {
+ received_acks_[static_cast<size_t>(last_received_packet_number_)] = true;
+ }
+
+ if (frame.packets.Empty())
+ return;
+
+ // TODO(rch, rtenneti) sort out histograms for QUIC_VERSION_34 and above.
+ if (session_->connection()->version() > QUIC_VERSION_33) {
+ return;
+ }
+ const PacketNumberQueue& missing_packets = frame.packets;
+ PacketNumberQueue::const_iterator it =
+ missing_packets.lower_bound(largest_received_missing_packet_number_);
+ if (it == missing_packets.end() ||
+ largest_received_missing_packet_number_ == missing_packets.Max()) {
+ return;
+ }
+
+ // Scan through the list and log consecutive ranges of missing packets.
+ size_t num_consecutive_missing_packets = 1;
+ QuicPacketNumber previous_missing_packet =
+ largest_received_missing_packet_number_;
+ for (; it != missing_packets.end(); ++it) {
+ // Account for case where first interval starts below
+ // largest_received_missing_packet_number_.
+ QuicPacketNumber interval_min =
+ std::max(previous_missing_packet + 1, it->min());
+ DCHECK_LE(interval_min, it->max());
+
+ size_t interval_len = it->max() - interval_min;
+ if (interval_len == 0) {
+ continue;
+ }
+ if (interval_min == previous_missing_packet + 1) {
+ num_consecutive_missing_packets += interval_len;
+ } else {
+ UpdatePacketGapSentHistogram(num_consecutive_missing_packets);
+ num_consecutive_missing_packets = interval_len;
+ }
+ previous_missing_packet = it->max() - 1;
+ }
+ UpdatePacketGapSentHistogram(num_consecutive_missing_packets);
+ largest_received_missing_packet_number_ = missing_packets.Max();
+}
+
+void QuicConnectionLogger::OnStopWaitingFrame(
+ const QuicStopWaitingFrame& frame) {
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_STOP_WAITING_FRAME_RECEIVED,
+ base::Bind(&NetLogQuicStopWaitingFrameCallback, &frame));
+}
+
+void QuicConnectionLogger::OnRstStreamFrame(const QuicRstStreamFrame& frame) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeServer",
+ frame.error_code);
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_RST_STREAM_FRAME_RECEIVED,
+ base::Bind(&NetLogQuicRstStreamFrameCallback, &frame));
+}
+
+void QuicConnectionLogger::OnConnectionCloseFrame(
+ const QuicConnectionCloseFrame& frame) {
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_SESSION_CONNECTION_CLOSE_FRAME_RECEIVED,
+ base::Bind(&NetLogQuicConnectionCloseFrameCallback, &frame));
+}
+
+void QuicConnectionLogger::OnWindowUpdateFrame(
+ const QuicWindowUpdateFrame& frame) {
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_WINDOW_UPDATE_FRAME_RECEIVED,
+ base::Bind(&NetLogQuicWindowUpdateFrameCallback, &frame));
+}
+
+void QuicConnectionLogger::OnBlockedFrame(const QuicBlockedFrame& frame) {
+ ++num_blocked_frames_received_;
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_BLOCKED_FRAME_RECEIVED,
+ base::Bind(&NetLogQuicBlockedFrameCallback, &frame));
+}
+
+void QuicConnectionLogger::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.GoAwayReceivedForConnectionMigration",
+ frame.error_code == QUIC_ERROR_MIGRATING_PORT);
+
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_GOAWAY_FRAME_RECEIVED,
+ base::Bind(&NetLogQuicGoAwayFrameCallback, &frame));
+}
+
+void QuicConnectionLogger::OnPingFrame(const QuicPingFrame& frame) {
+ // PingFrame has no contents to log, so just record that it was received.
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_PING_FRAME_RECEIVED);
+}
+
+void QuicConnectionLogger::OnPublicResetPacket(
+ const QuicPublicResetPacket& packet) {
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_PUBLIC_RESET_PACKET_RECEIVED);
+ UpdatePublicResetAddressMismatchHistogram(local_address_from_shlo_,
+ packet.client_address);
+}
+
+void QuicConnectionLogger::OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) {
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_SESSION_VERSION_NEGOTIATION_PACKET_RECEIVED,
+ base::Bind(&NetLogQuicVersionNegotiationPacketCallback, &packet));
+}
+
+void QuicConnectionLogger::OnCryptoHandshakeMessageReceived(
+ const CryptoHandshakeMessage& message) {
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_RECEIVED,
+ base::Bind(&NetLogQuicCryptoHandshakeMessageCallback, &message));
+
+ if (message.tag() == kSHLO) {
+ StringPiece address;
+ QuicSocketAddressCoder decoder;
+ if (message.GetStringPiece(kCADR, &address) &&
+ decoder.Decode(address.data(), address.size())) {
+ local_address_from_shlo_ = IPEndPoint(decoder.ip(), decoder.port());
+ UMA_HISTOGRAM_ENUMERATION(
+ "Net.QuicSession.ConnectionTypeFromPeer",
+ GetRealAddressFamily(local_address_from_shlo_.address()),
+ ADDRESS_FAMILY_LAST);
+ }
+ }
+}
+
+void QuicConnectionLogger::OnCryptoHandshakeMessageSent(
+ const CryptoHandshakeMessage& message) {
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_SENT,
+ base::Bind(&NetLogQuicCryptoHandshakeMessageCallback, &message));
+}
+
+void QuicConnectionLogger::OnConnectionClosed(QuicErrorCode error,
+ const string& error_details,
+ ConnectionCloseSource source) {
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_SESSION_CLOSED,
+ base::Bind(&NetLogQuicOnConnectionClosedCallback, error, source));
+}
+
+void QuicConnectionLogger::OnSuccessfulVersionNegotiation(
+ const QuicVersion& version) {
+ string quic_version = QuicVersionToString(version);
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_VERSION_NEGOTIATED,
+ NetLog::StringCallback("version", &quic_version));
+}
+
+void QuicConnectionLogger::UpdateReceivedFrameCounts(
+ QuicStreamId stream_id,
+ int num_frames_received,
+ int num_duplicate_frames_received) {
+ if (stream_id != kCryptoStreamId) {
+ num_frames_received_ += num_frames_received;
+ num_duplicate_frames_received_ += num_duplicate_frames_received;
+ }
+}
+
+void QuicConnectionLogger::OnCertificateVerified(
+ const CertVerifyResult& result) {
+ if (result.cert_status == CERT_STATUS_INVALID) {
+ net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CERTIFICATE_VERIFY_FAILED);
+ return;
+ }
+ net_log_.AddEvent(
+ NetLogEventType::QUIC_SESSION_CERTIFICATE_VERIFIED,
+ base::Bind(&NetLogQuicCertificateVerifiedCallback, result.verified_cert));
+}
+
+base::HistogramBase* QuicConnectionLogger::Get6PacketHistogram(
+ const char* which_6) const {
+ // This histogram takes a binary encoding of the 6 consecutive packets
+ // received. As a result, there are 64 possible sample-patterns.
+ string prefix("Net.QuicSession.6PacketsPatternsReceived_");
+ return base::LinearHistogram::FactoryGet(
+ prefix + which_6 + connection_description_, 1, 64, 65,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+}
+
+float QuicConnectionLogger::ReceivedPacketLossRate() const {
+ if (largest_received_packet_number_ <= num_packets_received_)
+ return 0.0f;
+ float num_received = largest_received_packet_number_ - num_packets_received_;
+ return num_received / largest_received_packet_number_;
+}
+
+void QuicConnectionLogger::OnRttChanged(QuicTime::Delta rtt) const {
+ // Notify socket performance watcher of the updated RTT value.
+ if (!socket_performance_watcher_)
+ return;
+
+ int64_t microseconds = rtt.ToMicroseconds();
+ if (microseconds != 0) {
+ socket_performance_watcher_->OnUpdatedRTTAvailable(
+ base::TimeDelta::FromMicroseconds(rtt.ToMicroseconds()));
+ }
+}
+
+void QuicConnectionLogger::RecordAggregatePacketLossRate() const {
+ // For short connections under 22 packets in length, we'll rely on the
+ // Net.QuicSession.21CumulativePacketsReceived_* histogram to indicate packet
+ // loss rates. This way we avoid tremendously anomalous contributions to our
+ // histogram. (e.g., if we only got 5 packets, but lost 1, we'd otherwise
+ // record a 20% loss in this histogram!). We may still get some strange data
+ // (1 loss in 22 is still high :-/).
+ if (largest_received_packet_number_ <= 21)
+ return;
+
+ string prefix("Net.QuicSession.PacketLossRate_");
+ base::HistogramBase* histogram = base::Histogram::FactoryGet(
+ prefix + connection_description_, 1, 1000, 75,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->Add(static_cast<base::HistogramBase::Sample>(
+ ReceivedPacketLossRate() * 1000));
+}
+
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_connection_logger.h b/chromium/net/quic/chromium/quic_connection_logger.h
new file mode 100644
index 00000000000..98e74ea02aa
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_connection_logger.h
@@ -0,0 +1,168 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_CONNECTION_LOGGER_H_
+#define NET_QUIC_QUIC_CONNECTION_LOGGER_H_
+
+#include <stddef.h>
+
+#include <bitset>
+#include <string>
+
+#include "base/macros.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_export.h"
+#include "net/base/network_change_notifier.h"
+#include "net/cert/cert_verify_result.h"
+#include "net/log/net_log_with_source.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_spdy_session.h"
+#include "net/socket/socket_performance_watcher.h"
+
+namespace base {
+class HistogramBase;
+}
+
+namespace net {
+
+// This class is a debug visitor of a QuicConnection which logs
+// events to |net_log|.
+class NET_EXPORT_PRIVATE QuicConnectionLogger
+ : public QuicConnectionDebugVisitor,
+ public QuicPacketCreator::DebugDelegate {
+ public:
+ QuicConnectionLogger(
+ QuicSpdySession* session,
+ const char* const connection_description,
+ std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
+ const NetLogWithSource& net_log);
+
+ ~QuicConnectionLogger() override;
+
+ // QuicPacketCreator::DebugDelegateInterface
+ void OnFrameAddedToPacket(const QuicFrame& frame) override;
+
+ // QuicConnectionDebugVisitorInterface
+ void OnPacketSent(const SerializedPacket& serialized_packet,
+ QuicPathId original_path_id,
+ QuicPacketNumber original_packet_number,
+ TransmissionType transmission_type,
+ QuicTime sent_time) override;
+ void OnPingSent() override;
+ void OnPacketReceived(const IPEndPoint& self_address,
+ const IPEndPoint& peer_address,
+ const QuicEncryptedPacket& packet) override;
+ void OnUnauthenticatedHeader(const QuicPacketHeader& header) override;
+ void OnIncorrectConnectionId(QuicConnectionId connection_id) override;
+ void OnUndecryptablePacket() override;
+ void OnDuplicatePacket(QuicPacketNumber packet_number) override;
+ void OnProtocolVersionMismatch(QuicVersion version) override;
+ void OnPacketHeader(const QuicPacketHeader& header) override;
+ void OnStreamFrame(const QuicStreamFrame& frame) override;
+ void OnAckFrame(const QuicAckFrame& frame) override;
+ void OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override;
+ void OnRstStreamFrame(const QuicRstStreamFrame& frame) override;
+ void OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override;
+ void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
+ void OnBlockedFrame(const QuicBlockedFrame& frame) override;
+ void OnGoAwayFrame(const QuicGoAwayFrame& frame) override;
+ void OnPingFrame(const QuicPingFrame& frame) override;
+ void OnPublicResetPacket(const QuicPublicResetPacket& packet) override;
+ void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) override;
+ void OnConnectionClosed(QuicErrorCode error,
+ const std::string& error_details,
+ ConnectionCloseSource source) override;
+ void OnSuccessfulVersionNegotiation(const QuicVersion& version) override;
+ void OnRttChanged(QuicTime::Delta rtt) const override;
+
+ void OnCryptoHandshakeMessageReceived(const CryptoHandshakeMessage& message);
+ void OnCryptoHandshakeMessageSent(const CryptoHandshakeMessage& message);
+ void UpdateReceivedFrameCounts(QuicStreamId stream_id,
+ int num_frames_received,
+ int num_duplicate_frames_received);
+ void OnCertificateVerified(const CertVerifyResult& result);
+
+ // Returns connection's overall packet loss rate in fraction.
+ float ReceivedPacketLossRate() const;
+
+ private:
+ // Do a factory get for a histogram to record a 6-packet loss-sequence as a
+ // sample. The histogram will record the 64 distinct possible combinations.
+ // |which_6| is used to adjust the name of the histogram to distinguish the
+ // first 6 packets in a connection, vs. some later 6 packets.
+ base::HistogramBase* Get6PacketHistogram(const char* which_6) const;
+ // For connections longer than 21 received packets, this call will calculate
+ // the overall packet loss rate, and record it into a histogram.
+ void RecordAggregatePacketLossRate() const;
+
+ NetLogWithSource net_log_;
+ QuicSpdySession* session_; // Unowned.
+ // The last packet number received.
+ QuicPacketNumber last_received_packet_number_;
+ // The size of the most recently received packet.
+ size_t last_received_packet_size_;
+ // True if a PING frame has been sent and no packet has been received.
+ bool no_packet_received_after_ping_;
+ // The size of the previously received packet.
+ size_t previous_received_packet_size_;
+ // The largest packet number received. In the case where a packet is
+ // received late (out of order), this value will not be updated.
+ QuicPacketNumber largest_received_packet_number_;
+ // The largest packet number which the peer has failed to
+ // receive, according to the missing packet set in their ack frames.
+ QuicPacketNumber largest_received_missing_packet_number_;
+ // Number of times that the current received packet number is
+ // smaller than the last received packet number.
+ size_t num_out_of_order_received_packets_;
+ // Number of times that the current received packet number is
+ // smaller than the last received packet number and where the
+ // size of the current packet is larger than the size of the previous
+ // packet.
+ size_t num_out_of_order_large_received_packets_;
+ // The number of times that OnPacketHeader was called.
+ // If the network replicates packets, then this number may be slightly
+ // different from the real number of distinct packets received.
+ QuicPacketCount num_packets_received_;
+ // The kCADR value provided by the server in ServerHello.
+ IPEndPoint local_address_from_shlo_;
+ // The first local address from which a packet was received.
+ IPEndPoint local_address_from_self_;
+ // Count of the number of frames received.
+ int num_frames_received_;
+ // Count of the number of duplicate frames received.
+ int num_duplicate_frames_received_;
+ // Count of the number of packets received with incorrect connection IDs.
+ int num_incorrect_connection_ids_;
+ // Count of the number of undecryptable packets received.
+ int num_undecryptable_packets_;
+ // Count of the number of duplicate packets received.
+ int num_duplicate_packets_;
+ // Count of the number of BLOCKED frames received.
+ int num_blocked_frames_received_;
+ // Count of the number of BLOCKED frames sent.
+ int num_blocked_frames_sent_;
+ // Vector of inital packets status' indexed by packet numbers, where
+ // false means never received. Zero is not a valid packet number, so
+ // that offset is never used, and we'll track 150 packets.
+ std::bitset<151> received_packets_;
+ // Vector to indicate which of the initial 150 received packets turned out to
+ // contain solo ACK frames. An element is true iff an ACK frame was in the
+ // corresponding packet, and there was very little else.
+ std::bitset<151> received_acks_;
+ // The available type of connection (WiFi, 3G, etc.) when connection was first
+ // used.
+ const char* const connection_description_;
+ // Receives notifications regarding the performance of the underlying socket
+ // for the QUIC connection. May be null.
+ const std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicConnectionLogger);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CONNECTION_LOGGER_H_
diff --git a/chromium/net/quic/chromium/quic_end_to_end_unittest.cc b/chromium/net/quic/chromium/quic_end_to_end_unittest.cc
new file mode 100644
index 00000000000..d4f0a02aef1
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_end_to_end_unittest.cc
@@ -0,0 +1,374 @@
+// Copyright 2013 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 <memory>
+#include <ostream>
+#include <utility>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/base/elements_upload_data_stream.h"
+#include "net/base/ip_address.h"
+#include "net/base/test_completion_callback.h"
+#include "net/base/upload_bytes_element_reader.h"
+#include "net/base/upload_data_stream.h"
+#include "net/cert/ct_policy_enforcer.h"
+#include "net/cert/mock_cert_verifier.h"
+#include "net/cert/multi_log_ct_verifier.h"
+#include "net/dns/mapped_host_resolver.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_network_transaction.h"
+#include "net/http/http_server_properties_impl.h"
+#include "net/http/http_transaction_test_util.h"
+#include "net/http/transport_security_state.h"
+#include "net/log/net_log_with_source.h"
+#include "net/proxy/proxy_service.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/ssl/default_channel_id_store.h"
+#include "net/ssl/ssl_config_service_defaults.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
+#include "net/test/test_data_directory.h"
+#include "net/tools/quic/quic_in_memory_cache.h"
+#include "net/tools/quic/quic_simple_server.h"
+#include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+using base::StringPiece;
+
+namespace net {
+
+using test::IsOk;
+using test::QuicInMemoryCachePeer;
+
+namespace test {
+
+namespace {
+
+const char kResponseBody[] = "some arbitrary response body";
+
+// Factory for creating HttpTransactions, used by TestTransactionConsumer.
+class TestTransactionFactory : public HttpTransactionFactory {
+ public:
+ explicit TestTransactionFactory(const HttpNetworkSession::Params& params)
+ : session_(new HttpNetworkSession(params)) {}
+
+ ~TestTransactionFactory() override {}
+
+ // HttpTransactionFactory methods
+ int CreateTransaction(RequestPriority priority,
+ std::unique_ptr<HttpTransaction>* trans) override {
+ trans->reset(new HttpNetworkTransaction(priority, session_.get()));
+ return OK;
+ }
+
+ HttpCache* GetCache() override { return nullptr; }
+
+ HttpNetworkSession* GetSession() override { return session_.get(); };
+
+ private:
+ std::unique_ptr<HttpNetworkSession> session_;
+};
+
+struct TestParams {
+ explicit TestParams(bool use_stateless_rejects)
+ : use_stateless_rejects(use_stateless_rejects) {}
+
+ friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
+ os << "{ use_stateless_rejects: " << p.use_stateless_rejects << " }";
+ return os;
+ }
+ bool use_stateless_rejects;
+};
+
+std::vector<TestParams> GetTestParams() {
+ return std::vector<TestParams>{TestParams(true), TestParams(false)};
+}
+
+} // namespace
+
+class QuicEndToEndTest : public ::testing::TestWithParam<TestParams> {
+ protected:
+ QuicEndToEndTest()
+ : host_resolver_impl_(CreateResolverImpl()),
+ host_resolver_(std::move(host_resolver_impl_)),
+ cert_transparency_verifier_(new MultiLogCTVerifier()),
+ ssl_config_service_(new SSLConfigServiceDefaults),
+ proxy_service_(ProxyService::CreateDirect()),
+ auth_handler_factory_(
+ HttpAuthHandlerFactory::CreateDefault(&host_resolver_)),
+ strike_register_no_startup_period_(false) {
+ request_.method = "GET";
+ request_.url = GURL("https://test.example.com/");
+ request_.load_flags = 0;
+
+ params_.enable_quic = true;
+ params_.quic_clock = nullptr;
+ params_.quic_random = nullptr;
+ if (GetParam().use_stateless_rejects) {
+ params_.quic_connection_options.push_back(kSREJ);
+ }
+ params_.host_resolver = &host_resolver_;
+ params_.cert_verifier = &cert_verifier_;
+ params_.transport_security_state = &transport_security_state_;
+ params_.cert_transparency_verifier = cert_transparency_verifier_.get();
+ params_.ct_policy_enforcer = &ct_policy_enforcer_;
+ params_.proxy_service = proxy_service_.get();
+ params_.ssl_config_service = ssl_config_service_.get();
+ params_.http_auth_handler_factory = auth_handler_factory_.get();
+ params_.http_server_properties = &http_server_properties_;
+ channel_id_service_.reset(
+ new ChannelIDService(new DefaultChannelIDStore(nullptr),
+ base::ThreadTaskRunnerHandle::Get()));
+ params_.channel_id_service = channel_id_service_.get();
+
+ 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");
+ cert_verifier_.AddResultForCertAndHost(verify_result.verified_cert.get(),
+ "test.example.com", verify_result,
+ OK);
+ }
+
+ // Creates a mock host resolver in which test.example.com
+ // resolves to localhost.
+ static MockHostResolver* CreateResolverImpl() {
+ MockHostResolver* resolver = new MockHostResolver();
+ resolver->rules()->AddRule("test.example.com", "127.0.0.1");
+ return resolver;
+ }
+
+ void SetUp() override {
+ QuicInMemoryCachePeer::ResetForTests();
+ StartServer();
+
+ // Use a mapped host resolver so that request for test.example.com (port 80)
+ // reach the server running on localhost.
+ std::string map_rule = "MAP test.example.com test.example.com:" +
+ base::IntToString(server_->server_address().port());
+ EXPECT_TRUE(host_resolver_.AddRuleFromString(map_rule));
+
+ // To simplify the test, and avoid the race with the HTTP request, we force
+ // QUIC for these requests.
+ params_.origins_to_force_quic_on.insert(
+ HostPortPair::FromString("test.example.com:443"));
+
+ transaction_factory_.reset(new TestTransactionFactory(params_));
+ }
+
+ void TearDown() override { QuicInMemoryCachePeer::ResetForTests(); }
+
+ // Starts the QUIC server listening on a random port.
+ void StartServer() {
+ server_address_ = IPEndPoint(IPAddress(127, 0, 0, 1), 0);
+ server_config_.SetInitialStreamFlowControlWindowToSend(
+ kInitialStreamFlowControlWindowForTest);
+ server_config_.SetInitialSessionFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+ server_config_options_.token_binding_params = QuicTagVector{kTB10, kP256};
+ server_.reset(new QuicSimpleServer(CryptoTestUtils::ProofSourceForTesting(),
+ server_config_, server_config_options_,
+ AllSupportedVersions()));
+ server_->Listen(server_address_);
+ server_address_ = server_->server_address();
+ server_->StartReading();
+ server_started_ = true;
+ }
+
+ // Adds an entry to the cache used by the QUIC server to serve
+ // responses.
+ void AddToCache(StringPiece path,
+ int response_code,
+ StringPiece response_detail,
+ StringPiece body) {
+ QuicInMemoryCache::GetInstance()->AddSimpleResponse(
+ "test.example.com", path, response_code, body);
+ }
+
+ // Populates |request_body_| with |length_| ASCII bytes.
+ void GenerateBody(size_t length) {
+ request_body_.clear();
+ request_body_.reserve(length);
+ for (size_t i = 0; i < length; ++i) {
+ request_body_.append(1, static_cast<char>(32 + i % (126 - 32)));
+ }
+ }
+
+ // Initializes |request_| for a post of |length| bytes.
+ void InitializePostRequest(size_t length) {
+ GenerateBody(length);
+ std::vector<std::unique_ptr<UploadElementReader>> element_readers;
+ element_readers.push_back(base::MakeUnique<UploadBytesElementReader>(
+ request_body_.data(), request_body_.length()));
+ upload_data_stream_.reset(
+ new ElementsUploadDataStream(std::move(element_readers), 0));
+ request_.method = "POST";
+ request_.url = GURL("https://test.example.com/");
+ request_.upload_data_stream = upload_data_stream_.get();
+ ASSERT_THAT(request_.upload_data_stream->Init(CompletionCallback(),
+ NetLogWithSource()),
+ IsOk());
+ }
+
+ // Checks that |consumer| completed and received |status_line| and |body|.
+ void CheckResponse(const TestTransactionConsumer& consumer,
+ const std::string& status_line,
+ const std::string& body) {
+ ASSERT_TRUE(consumer.is_done());
+ ASSERT_THAT(consumer.error(), IsOk());
+ EXPECT_EQ(status_line, consumer.response_info()->headers->GetStatusLine());
+ EXPECT_EQ(body, consumer.content());
+ }
+
+ std::unique_ptr<MockHostResolver> host_resolver_impl_;
+ MappedHostResolver host_resolver_;
+ MockCertVerifier cert_verifier_;
+ std::unique_ptr<ChannelIDService> channel_id_service_;
+ TransportSecurityState transport_security_state_;
+ std::unique_ptr<CTVerifier> cert_transparency_verifier_;
+ CTPolicyEnforcer ct_policy_enforcer_;
+ scoped_refptr<SSLConfigServiceDefaults> ssl_config_service_;
+ std::unique_ptr<ProxyService> proxy_service_;
+ std::unique_ptr<HttpAuthHandlerFactory> auth_handler_factory_;
+ HttpServerPropertiesImpl http_server_properties_;
+ HttpNetworkSession::Params params_;
+ std::unique_ptr<TestTransactionFactory> transaction_factory_;
+ HttpRequestInfo request_;
+ std::string request_body_;
+ std::unique_ptr<UploadDataStream> upload_data_stream_;
+ std::unique_ptr<QuicSimpleServer> server_;
+ IPEndPoint server_address_;
+ std::string server_hostname_;
+ QuicConfig server_config_;
+ QuicCryptoServerConfig::ConfigOptions server_config_options_;
+ bool server_started_;
+ bool strike_register_no_startup_period_;
+};
+
+INSTANTIATE_TEST_CASE_P(Tests,
+ QuicEndToEndTest,
+ ::testing::ValuesIn(GetTestParams()));
+
+TEST_P(QuicEndToEndTest, LargeGetWithNoPacketLoss) {
+ std::string response(10 * 1024, 'x');
+
+ AddToCache(request_.url.PathForRequest(), 200, "OK", response);
+
+ TestTransactionConsumer consumer(DEFAULT_PRIORITY,
+ transaction_factory_.get());
+ consumer.Start(&request_, NetLogWithSource());
+
+ // Will terminate when the last consumer completes.
+ base::RunLoop().Run();
+
+ CheckResponse(consumer, "HTTP/1.1 200", response);
+}
+
+TEST_P(QuicEndToEndTest, TokenBinding) {
+ // Enable token binding and re-initialize the TestTransactionFactory.
+ params_.enable_token_binding = true;
+ transaction_factory_.reset(new TestTransactionFactory(params_));
+
+ AddToCache(request_.url.PathForRequest(), 200, "OK", kResponseBody);
+
+ TestTransactionConsumer consumer(DEFAULT_PRIORITY,
+ transaction_factory_.get());
+ consumer.Start(&request_, NetLogWithSource());
+
+ // Will terminate when the last consumer completes.
+ base::RunLoop().Run();
+
+ CheckResponse(consumer, "HTTP/1.1 200", kResponseBody);
+ HttpRequestHeaders headers;
+ ASSERT_TRUE(consumer.transaction()->GetFullRequestHeaders(&headers));
+ EXPECT_TRUE(headers.HasHeader(HttpRequestHeaders::kTokenBinding));
+}
+
+// crbug.com/559173
+#if defined(THREAD_SANITIZER)
+TEST_P(QuicEndToEndTest, DISABLED_LargePostWithNoPacketLoss) {
+#else
+TEST_P(QuicEndToEndTest, LargePostWithNoPacketLoss) {
+#endif
+ InitializePostRequest(1024 * 1024);
+
+ AddToCache(request_.url.PathForRequest(), 200, "OK", kResponseBody);
+
+ TestTransactionConsumer consumer(DEFAULT_PRIORITY,
+ transaction_factory_.get());
+ consumer.Start(&request_, NetLogWithSource());
+
+ // Will terminate when the last consumer completes.
+ base::RunLoop().Run();
+
+ CheckResponse(consumer, "HTTP/1.1 200", kResponseBody);
+}
+
+// crbug.com/559173
+#if defined(THREAD_SANITIZER)
+TEST_P(QuicEndToEndTest, DISABLED_LargePostWithPacketLoss) {
+#else
+TEST_P(QuicEndToEndTest, LargePostWithPacketLoss) {
+#endif
+ // FLAGS_fake_packet_loss_percentage = 30;
+ InitializePostRequest(1024 * 1024);
+
+ const char kResponseBody[] = "some really big response body";
+ AddToCache(request_.url.PathForRequest(), 200, "OK", kResponseBody);
+
+ TestTransactionConsumer consumer(DEFAULT_PRIORITY,
+ transaction_factory_.get());
+ consumer.Start(&request_, NetLogWithSource());
+
+ // Will terminate when the last consumer completes.
+ base::RunLoop().Run();
+
+ CheckResponse(consumer, "HTTP/1.1 200", kResponseBody);
+}
+
+// crbug.com/536845
+#if defined(THREAD_SANITIZER)
+TEST_P(QuicEndToEndTest, DISABLED_UberTest) {
+#else
+TEST_P(QuicEndToEndTest, UberTest) {
+#endif
+ // FLAGS_fake_packet_loss_percentage = 30;
+
+ const char kResponseBody[] = "some really big response body";
+ AddToCache(request_.url.PathForRequest(), 200, "OK", kResponseBody);
+
+ std::vector<TestTransactionConsumer*> consumers;
+ size_t num_requests = 100;
+ for (size_t i = 0; i < num_requests; ++i) {
+ TestTransactionConsumer* consumer = new TestTransactionConsumer(
+ DEFAULT_PRIORITY, transaction_factory_.get());
+ consumers.push_back(consumer);
+ consumer->Start(&request_, NetLogWithSource());
+ }
+
+ // Will terminate when the last consumer completes.
+ base::RunLoop().Run();
+
+ for (size_t i = 0; i < num_requests; ++i) {
+ CheckResponse(*consumers[i], "HTTP/1.1 200", kResponseBody);
+ }
+ base::STLDeleteElements(&consumers);
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_http_stream.cc b/chromium/net/quic/chromium/quic_http_stream.cc
new file mode 100644
index 00000000000..059f7dd5632
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_http_stream.cc
@@ -0,0 +1,834 @@
+// 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/chromium/quic_http_stream.h"
+
+#include <utility>
+
+#include "base/auto_reset.h"
+#include "base/callback_helpers.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
+#include "net/base/load_flags.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/quic/core/quic_client_promised_info.h"
+#include "net/quic/core/quic_http_utils.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/core/spdy_utils.h"
+#include "net/spdy/spdy_frame_builder.h"
+#include "net/spdy/spdy_framer.h"
+#include "net/spdy/spdy_http_utils.h"
+#include "net/ssl/ssl_info.h"
+
+namespace net {
+
+namespace {
+
+std::unique_ptr<base::Value> NetLogQuicPushStreamCallback(
+ QuicStreamId stream_id,
+ const GURL* url,
+ NetLogCaptureMode capture_mode) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetInteger("stream_id", stream_id);
+ dict->SetString("url", url->spec());
+ return std::move(dict);
+}
+
+} // namespace
+
+QuicHttpStream::QuicHttpStream(
+ const base::WeakPtr<QuicChromiumClientSession>& session)
+ : next_state_(STATE_NONE),
+ session_(session),
+ session_error_(OK),
+ was_handshake_confirmed_(session->IsCryptoHandshakeConfirmed()),
+ stream_(nullptr),
+ request_info_(nullptr),
+ request_body_stream_(nullptr),
+ priority_(MINIMUM_PRIORITY),
+ response_info_(nullptr),
+ response_status_(OK),
+ response_headers_received_(false),
+ headers_bytes_received_(0),
+ headers_bytes_sent_(0),
+ closed_stream_received_bytes_(0),
+ closed_stream_sent_bytes_(0),
+ closed_is_first_stream_(false),
+ user_buffer_len_(0),
+ quic_connection_error_(QUIC_NO_ERROR),
+ port_migration_detected_(false),
+ found_promise_(false),
+ push_handle_(nullptr),
+ in_loop_(false),
+ weak_factory_(this) {
+ DCHECK(session_);
+ session_->AddObserver(this);
+}
+
+QuicHttpStream::~QuicHttpStream() {
+ CHECK(!in_loop_);
+ Close(false);
+ if (session_)
+ session_->RemoveObserver(this);
+}
+
+bool QuicHttpStream::CheckVary(const SpdyHeaderBlock& client_request,
+ const SpdyHeaderBlock& promise_request,
+ const SpdyHeaderBlock& promise_response) {
+ HttpResponseInfo promise_response_info;
+
+ HttpRequestInfo promise_request_info;
+ ConvertHeaderBlockToHttpRequestHeaders(promise_request,
+ &promise_request_info.extra_headers);
+ HttpRequestInfo client_request_info;
+ ConvertHeaderBlockToHttpRequestHeaders(client_request,
+ &client_request_info.extra_headers);
+
+ if (!SpdyHeadersToHttpResponse(promise_response, &promise_response_info)) {
+ DLOG(WARNING) << "Invalid headers";
+ return false;
+ }
+
+ HttpVaryData vary_data;
+ if (!vary_data.Init(promise_request_info,
+ *promise_response_info.headers.get())) {
+ // Promise didn't contain valid vary info, so URL match was sufficient.
+ return true;
+ }
+ // Now compare the client request for matching.
+ return vary_data.MatchesRequest(client_request_info,
+ *promise_response_info.headers.get());
+}
+
+void QuicHttpStream::OnRendezvousResult(QuicSpdyStream* stream) {
+ push_handle_ = nullptr;
+ if (stream) {
+ stream_ = static_cast<QuicChromiumClientStream*>(stream);
+ stream_->SetDelegate(this);
+ }
+
+ // callback_ should only be non-null in the case of asynchronous
+ // rendezvous; i.e. |Try()| returned QUIC_PENDING.
+ if (callback_.is_null())
+ return;
+
+ DCHECK_EQ(STATE_HANDLE_PROMISE_COMPLETE, next_state_);
+ if (!stream) {
+ // rendezvous has failed so proceed as with a non-push request.
+ next_state_ = STATE_REQUEST_STREAM;
+ }
+
+ OnIOComplete(OK);
+}
+
+int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info,
+ RequestPriority priority,
+ const NetLogWithSource& stream_net_log,
+ const CompletionCallback& callback) {
+ CHECK(callback_.is_null());
+ DCHECK(!stream_);
+ if (!session_)
+ return was_handshake_confirmed_ ? ERR_CONNECTION_CLOSED
+ : ERR_QUIC_HANDSHAKE_FAILED;
+
+ stream_net_log.AddEvent(
+ NetLogEventType::HTTP_STREAM_REQUEST_BOUND_TO_QUIC_SESSION,
+ session_->net_log().source().ToEventParametersCallback());
+
+ stream_net_log_ = stream_net_log;
+ request_info_ = request_info;
+ request_time_ = base::Time::Now();
+ priority_ = priority;
+
+ bool success = session_->GetSSLInfo(&ssl_info_);
+ DCHECK(success);
+ DCHECK(ssl_info_.cert.get());
+
+ std::string url(request_info->url.spec());
+ QuicClientPromisedInfo* promised =
+ session_->push_promise_index()->GetPromised(url);
+ if (promised) {
+ found_promise_ = true;
+ stream_net_log_.AddEvent(
+ NetLogEventType::QUIC_HTTP_STREAM_PUSH_PROMISE_RENDEZVOUS,
+ base::Bind(&NetLogQuicPushStreamCallback, promised->id(),
+ &request_info_->url));
+ session_->net_log().AddEvent(
+ NetLogEventType::QUIC_HTTP_STREAM_PUSH_PROMISE_RENDEZVOUS,
+ base::Bind(&NetLogQuicPushStreamCallback, promised->id(),
+ &request_info_->url));
+ return OK;
+ }
+
+ next_state_ = STATE_REQUEST_STREAM;
+ int rv = DoLoop(OK);
+ if (rv == ERR_IO_PENDING)
+ callback_ = callback;
+
+ return rv;
+}
+
+int QuicHttpStream::DoHandlePromise() {
+ QuicAsyncStatus push_status = session_->push_promise_index()->Try(
+ request_headers_, this, &this->push_handle_);
+
+ switch (push_status) {
+ case QUIC_FAILURE:
+ // Push rendezvous failed.
+ next_state_ = STATE_REQUEST_STREAM;
+ break;
+ case QUIC_SUCCESS:
+ next_state_ = STATE_HANDLE_PROMISE_COMPLETE;
+ break;
+ case QUIC_PENDING:
+ next_state_ = STATE_HANDLE_PROMISE_COMPLETE;
+ return ERR_IO_PENDING;
+ }
+ return OK;
+}
+
+int QuicHttpStream::DoHandlePromiseComplete(int rv) {
+ if (rv != OK)
+ return rv;
+
+ next_state_ = STATE_OPEN;
+ stream_net_log_.AddEvent(
+ NetLogEventType::QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM,
+ base::Bind(&NetLogQuicPushStreamCallback, stream_->id(),
+ &request_info_->url));
+ session_->net_log().AddEvent(
+ NetLogEventType::QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM,
+ base::Bind(&NetLogQuicPushStreamCallback, stream_->id(),
+ &request_info_->url));
+ return OK;
+}
+
+int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
+ HttpResponseInfo* response,
+ const CompletionCallback& callback) {
+ CHECK(!request_body_stream_);
+ CHECK(!response_info_);
+ CHECK(callback_.is_null());
+ CHECK(!callback.is_null());
+ CHECK(response);
+
+ // TODO(rch): remove this once we figure out why channel ID is not being
+ // sent when it should be.
+ HostPortPair origin = HostPortPair::FromURL(request_info_->url);
+ if (origin.Equals(HostPortPair("accounts.google.com", 443)) &&
+ request_headers.HasHeader(HttpRequestHeaders::kCookie)) {
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.CookieSentToAccountsOverChannelId",
+ ssl_info_.channel_id_sent);
+ }
+ if ((!found_promise_ && !stream_) || !session_) {
+ return was_handshake_confirmed_ ? ERR_CONNECTION_CLOSED
+ : ERR_QUIC_HANDSHAKE_FAILED;
+ }
+
+ // Store the serialized request headers.
+ CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers,
+ /*direct=*/true, &request_headers_);
+
+ // Store the request body.
+ request_body_stream_ = request_info_->upload_data_stream;
+ if (request_body_stream_) {
+ // A request with a body is ineligible for push, so reset the
+ // promised stream and request a new stream.
+ if (found_promise_) {
+ found_promise_ = false;
+ std::string url(request_info_->url.spec());
+ QuicClientPromisedInfo* promised =
+ session_->push_promise_index()->GetPromised(url);
+ if (promised != nullptr) {
+ session_->ResetPromised(promised->id(), QUIC_STREAM_CANCELLED);
+ }
+ }
+
+ // TODO(rch): Can we be more precise about when to allocate
+ // raw_request_body_buf_. Removed the following check. DoReadRequestBody()
+ // was being called even if we didn't yet allocate raw_request_body_buf_.
+ // && (request_body_stream_->size() ||
+ // request_body_stream_->is_chunked()))
+ // Use 10 packets as the body buffer size to give enough space to
+ // help ensure we don't often send out partial packets.
+ raw_request_body_buf_ =
+ new IOBufferWithSize(static_cast<size_t>(10 * kMaxPacketSize));
+ // The request body buffer is empty at first.
+ request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_.get(), 0);
+ }
+
+ // Store the response info.
+ response_info_ = response;
+
+ int rv;
+
+ if (found_promise_) {
+ next_state_ = STATE_HANDLE_PROMISE;
+ } else {
+ next_state_ = STATE_SET_REQUEST_PRIORITY;
+ }
+ rv = DoLoop(OK);
+
+ if (rv == ERR_IO_PENDING)
+ callback_ = callback;
+
+ return rv > 0 ? OK : rv;
+}
+
+int QuicHttpStream::ReadResponseHeaders(const CompletionCallback& callback) {
+ CHECK(callback_.is_null());
+ CHECK(!callback.is_null());
+
+ if (stream_ == nullptr)
+ return response_status_;
+
+ // Check if we already have the response headers. If so, return synchronously.
+ if (response_headers_received_)
+ return OK;
+
+ // Still waiting for the response, return IO_PENDING.
+ CHECK(callback_.is_null());
+ callback_ = callback;
+ return ERR_IO_PENDING;
+}
+
+int QuicHttpStream::ReadResponseBody(IOBuffer* buf,
+ int buf_len,
+ const CompletionCallback& callback) {
+ CHECK(callback_.is_null());
+ CHECK(!callback.is_null());
+ CHECK(!user_buffer_.get());
+ CHECK_EQ(0, user_buffer_len_);
+
+ if (!stream_) {
+ // If the stream is already closed, there is no body to read.
+ return response_status_;
+ }
+
+ int rv = ReadAvailableData(buf, buf_len);
+ if (rv != ERR_IO_PENDING)
+ return rv;
+
+ callback_ = callback;
+ user_buffer_ = buf;
+ user_buffer_len_ = buf_len;
+ return ERR_IO_PENDING;
+}
+
+void QuicHttpStream::Close(bool not_reusable) {
+ // Note: the not_reusable flag has no meaning for SPDY streams.
+ if (stream_) {
+ stream_->SetDelegate(nullptr);
+ stream_->Reset(QUIC_STREAM_CANCELLED);
+ response_status_ = was_handshake_confirmed_ ? ERR_CONNECTION_CLOSED
+ : ERR_QUIC_HANDSHAKE_FAILED;
+ }
+ ResetStream();
+}
+
+HttpStream* QuicHttpStream::RenewStreamForAuth() {
+ return nullptr;
+}
+
+bool QuicHttpStream::IsResponseBodyComplete() const {
+ return next_state_ == STATE_OPEN && !stream_;
+}
+
+bool QuicHttpStream::IsConnectionReused() const {
+ // TODO(rch): do something smarter here.
+ return stream_ && stream_->id() > 1;
+}
+
+void QuicHttpStream::SetConnectionReused() {
+ // QUIC doesn't need an indicator here.
+}
+
+bool QuicHttpStream::CanReuseConnection() const {
+ // QUIC streams aren't considered reusable.
+ return false;
+}
+
+int64_t QuicHttpStream::GetTotalReceivedBytes() const {
+ // TODO(sclittle): Currently, this only includes headers and response body
+ // bytes. Change this to include QUIC overhead as well.
+ int64_t total_received_bytes = headers_bytes_received_;
+ if (stream_) {
+ total_received_bytes += stream_->stream_bytes_read();
+ } else {
+ total_received_bytes += closed_stream_received_bytes_;
+ }
+ return total_received_bytes;
+}
+
+int64_t QuicHttpStream::GetTotalSentBytes() const {
+ // TODO(sclittle): Currently, this only includes request headers and body
+ // bytes. Change this to include QUIC overhead as well.
+ int64_t total_sent_bytes = headers_bytes_sent_;
+ if (stream_) {
+ total_sent_bytes += stream_->stream_bytes_written();
+ } else {
+ total_sent_bytes += closed_stream_sent_bytes_;
+ }
+ return total_sent_bytes;
+}
+
+bool QuicHttpStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
+ bool is_first_stream = closed_is_first_stream_;
+ if (stream_)
+ is_first_stream = stream_->IsFirstStream();
+ if (is_first_stream) {
+ load_timing_info->socket_reused = false;
+ load_timing_info->connect_timing = connect_timing_;
+ } else {
+ load_timing_info->socket_reused = true;
+ }
+ return true;
+}
+
+void QuicHttpStream::GetSSLInfo(SSLInfo* ssl_info) {
+ *ssl_info = ssl_info_;
+}
+
+void QuicHttpStream::GetSSLCertRequestInfo(
+ SSLCertRequestInfo* cert_request_info) {
+ DCHECK(stream_);
+ NOTIMPLEMENTED();
+}
+
+bool QuicHttpStream::GetRemoteEndpoint(IPEndPoint* endpoint) {
+ if (!session_)
+ return false;
+
+ *endpoint = session_->peer_address();
+ return true;
+}
+
+Error QuicHttpStream::GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) {
+ return session_->GetTokenBindingSignature(key, tb_type, out);
+}
+
+void QuicHttpStream::Drain(HttpNetworkSession* session) {
+ NOTREACHED();
+ Close(false);
+ delete this;
+}
+
+void QuicHttpStream::PopulateNetErrorDetails(NetErrorDetails* details) {
+ details->connection_info = HttpResponseInfo::CONNECTION_INFO_QUIC1_SPDY3;
+ if (was_handshake_confirmed_)
+ details->quic_connection_error = quic_connection_error_;
+ if (session_) {
+ session_->PopulateNetErrorDetails(details);
+ } else {
+ details->quic_port_migration_detected = port_migration_detected_;
+ }
+}
+
+void QuicHttpStream::SetPriority(RequestPriority priority) {
+ priority_ = priority;
+}
+
+void QuicHttpStream::OnHeadersAvailable(const SpdyHeaderBlock& headers,
+ size_t frame_len) {
+ headers_bytes_received_ += frame_len;
+
+ // QuicHttpStream ignores trailers.
+ if (response_headers_received_) {
+ if (stream_->IsDoneReading()) {
+ // Close the read side. If the write side has been closed, this will
+ // invoke QuicHttpStream::OnClose to reset the stream.
+ stream_->OnFinRead();
+ }
+ return;
+ }
+
+ int rv = ProcessResponseHeaders(headers);
+ if (rv != ERR_IO_PENDING && !callback_.is_null()) {
+ DoCallback(rv);
+ }
+}
+
+void QuicHttpStream::OnDataAvailable() {
+ if (callback_.is_null()) {
+ // Data is available, but can't be delivered
+ return;
+ }
+
+ CHECK(user_buffer_.get());
+ CHECK_NE(0, user_buffer_len_);
+ int rv = ReadAvailableData(user_buffer_.get(), user_buffer_len_);
+ if (rv == ERR_IO_PENDING) {
+ // This was a spurrious notification. Wait for the next one.
+ return;
+ }
+
+ CHECK(!callback_.is_null());
+ user_buffer_ = nullptr;
+ user_buffer_len_ = 0;
+ DoCallback(rv);
+}
+
+void QuicHttpStream::OnClose() {
+ if (stream_->connection_error() != QUIC_NO_ERROR ||
+ stream_->stream_error() != QUIC_STREAM_NO_ERROR) {
+ response_status_ = was_handshake_confirmed_ ? ERR_QUIC_PROTOCOL_ERROR
+ : ERR_QUIC_HANDSHAKE_FAILED;
+ } else if (!response_headers_received_) {
+ response_status_ = ERR_ABORTED;
+ }
+
+ quic_connection_error_ = stream_->connection_error();
+ ResetStream();
+ if (in_loop_) {
+ // If already in DoLoop(), |callback_| will be handled when DoLoop() exits.
+ return;
+ }
+ if (!callback_.is_null()) {
+ DoCallback(response_status_);
+ }
+}
+
+void QuicHttpStream::OnError(int error) {
+ ResetStream();
+ response_status_ =
+ was_handshake_confirmed_ ? error : ERR_QUIC_HANDSHAKE_FAILED;
+ if (in_loop_) {
+ // If already in DoLoop(), |callback_| will be handled when DoLoop() exits.
+ return;
+ }
+ if (!callback_.is_null())
+ DoCallback(response_status_);
+}
+
+bool QuicHttpStream::HasSendHeadersComplete() {
+ return next_state_ > STATE_SEND_HEADERS_COMPLETE;
+}
+
+void QuicHttpStream::OnCryptoHandshakeConfirmed() {
+ was_handshake_confirmed_ = true;
+ if (next_state_ == STATE_WAIT_FOR_CONFIRMATION_COMPLETE) {
+ int rv = DoLoop(OK);
+
+ if (rv != ERR_IO_PENDING && !callback_.is_null()) {
+ DoCallback(rv);
+ }
+ }
+}
+
+void QuicHttpStream::OnSessionClosed(int error, bool port_migration_detected) {
+ Close(false);
+ session_error_ = error;
+ port_migration_detected_ = port_migration_detected;
+ session_.reset();
+}
+
+void QuicHttpStream::OnIOComplete(int rv) {
+ rv = DoLoop(rv);
+
+ if (rv != ERR_IO_PENDING && !callback_.is_null()) {
+ DoCallback(rv);
+ }
+}
+
+void QuicHttpStream::DoCallback(int rv) {
+ CHECK_NE(rv, ERR_IO_PENDING);
+ CHECK(!callback_.is_null());
+ CHECK(!in_loop_);
+
+ // The client callback can do anything, including destroying this class,
+ // so any pending callback must be issued after everything else is done.
+ base::ResetAndReturn(&callback_).Run(rv);
+}
+
+int QuicHttpStream::DoLoop(int rv) {
+ CHECK(!in_loop_);
+ base::AutoReset<bool> auto_reset_in_loop(&in_loop_, true);
+ do {
+ State state = next_state_;
+ next_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_HANDLE_PROMISE:
+ CHECK_EQ(OK, rv);
+ rv = DoHandlePromise();
+ break;
+ case STATE_HANDLE_PROMISE_COMPLETE:
+ CHECK_EQ(OK, rv);
+ rv = DoHandlePromiseComplete(rv);
+ break;
+ case STATE_REQUEST_STREAM:
+ CHECK_EQ(OK, rv);
+ rv = DoRequestStream();
+ break;
+ case STATE_REQUEST_STREAM_COMPLETE:
+ rv = DoRequestStreamComplete(rv);
+ break;
+ case STATE_SET_REQUEST_PRIORITY:
+ CHECK_EQ(OK, rv);
+ rv = DoSetRequestPriority();
+ break;
+ case STATE_WAIT_FOR_CONFIRMATION:
+ CHECK_EQ(OK, rv);
+ rv = DoWaitForConfirmation();
+ break;
+ case STATE_WAIT_FOR_CONFIRMATION_COMPLETE:
+ rv = DoWaitForConfirmationComplete(rv);
+ break;
+ case STATE_SEND_HEADERS:
+ CHECK_EQ(OK, rv);
+ rv = DoSendHeaders();
+ break;
+ case STATE_SEND_HEADERS_COMPLETE:
+ rv = DoSendHeadersComplete(rv);
+ break;
+ case STATE_READ_REQUEST_BODY:
+ CHECK_EQ(OK, rv);
+ rv = DoReadRequestBody();
+ break;
+ case STATE_READ_REQUEST_BODY_COMPLETE:
+ rv = DoReadRequestBodyComplete(rv);
+ break;
+ case STATE_SEND_BODY:
+ CHECK_EQ(OK, rv);
+ rv = DoSendBody();
+ break;
+ case STATE_SEND_BODY_COMPLETE:
+ rv = DoSendBodyComplete(rv);
+ break;
+ case STATE_OPEN:
+ CHECK_EQ(OK, rv);
+ break;
+ default:
+ NOTREACHED() << "next_state_: " << next_state_;
+ break;
+ }
+ } while (next_state_ != STATE_NONE && next_state_ != STATE_OPEN &&
+ rv != ERR_IO_PENDING);
+
+ return rv;
+}
+
+int QuicHttpStream::DoRequestStream() {
+ next_state_ = STATE_REQUEST_STREAM_COMPLETE;
+ return stream_request_.StartRequest(
+ session_, &stream_,
+ base::Bind(&QuicHttpStream::OnIOComplete, weak_factory_.GetWeakPtr()));
+}
+
+int QuicHttpStream::DoRequestStreamComplete(int rv) {
+ DCHECK(rv == OK || !stream_);
+ if (rv != OK)
+ return was_handshake_confirmed_ ? rv : ERR_QUIC_HANDSHAKE_FAILED;
+
+ stream_->SetDelegate(this);
+ if (request_info_->load_flags & LOAD_DISABLE_CONNECTION_MIGRATION) {
+ stream_->DisableConnectionMigration();
+ }
+
+ if (response_info_) {
+ // This happens in the case of a asynchronous push rendezvous
+ // that ultimately fails (e.g. vary failure). |response_info_|
+ // non-null implies that |DoRequestStream()| was called via
+ // |SendRequest()|.
+ next_state_ = STATE_SET_REQUEST_PRIORITY;
+ }
+
+ return OK;
+}
+
+int QuicHttpStream::DoSetRequestPriority() {
+ // Set priority according to request
+ DCHECK(stream_);
+ DCHECK(response_info_);
+ SpdyPriority priority = ConvertRequestPriorityToQuicPriority(priority_);
+ stream_->SetPriority(priority);
+ next_state_ = STATE_WAIT_FOR_CONFIRMATION;
+ return OK;
+}
+
+int QuicHttpStream::DoWaitForConfirmation() {
+ next_state_ = STATE_WAIT_FOR_CONFIRMATION_COMPLETE;
+ if (!session_->IsCryptoHandshakeConfirmed() &&
+ request_info_->method == "POST") {
+ return ERR_IO_PENDING;
+ }
+ return OK;
+}
+
+int QuicHttpStream::DoWaitForConfirmationComplete(int rv) {
+ if (rv < 0)
+ return rv;
+
+ next_state_ = STATE_SEND_HEADERS;
+ return OK;
+}
+
+int QuicHttpStream::DoSendHeaders() {
+ if (!stream_)
+ return ERR_UNEXPECTED;
+
+ // Log the actual request with the URL Request's net log.
+ stream_net_log_.AddEvent(
+ NetLogEventType::HTTP_TRANSACTION_QUIC_SEND_REQUEST_HEADERS,
+ base::Bind(&QuicRequestNetLogCallback, stream_->id(), &request_headers_,
+ priority_));
+ bool has_upload_data = request_body_stream_ != nullptr;
+
+ next_state_ = STATE_SEND_HEADERS_COMPLETE;
+ size_t frame_len = stream_->WriteHeaders(std::move(request_headers_),
+ !has_upload_data, nullptr);
+ headers_bytes_sent_ += frame_len;
+
+ request_headers_ = SpdyHeaderBlock();
+ return static_cast<int>(frame_len);
+}
+
+int QuicHttpStream::DoSendHeadersComplete(int rv) {
+ if (rv < 0)
+ return rv;
+
+ // If the stream is already closed, don't read the request the body.
+ if (!stream_)
+ return response_status_;
+
+ next_state_ = request_body_stream_ ? STATE_READ_REQUEST_BODY : STATE_OPEN;
+
+ return OK;
+}
+
+int QuicHttpStream::DoReadRequestBody() {
+ next_state_ = STATE_READ_REQUEST_BODY_COMPLETE;
+ return request_body_stream_->Read(
+ raw_request_body_buf_.get(), raw_request_body_buf_->size(),
+ base::Bind(&QuicHttpStream::OnIOComplete, weak_factory_.GetWeakPtr()));
+}
+
+int QuicHttpStream::DoReadRequestBodyComplete(int rv) {
+ // If the stream is already closed, don't continue.
+ if (!stream_)
+ return response_status_;
+
+ // |rv| is the result of read from the request body from the last call to
+ // DoSendBody().
+ if (rv < 0) {
+ stream_->SetDelegate(nullptr);
+ stream_->Reset(QUIC_ERROR_PROCESSING_STREAM);
+ ResetStream();
+ return rv;
+ }
+
+ request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_.get(), rv);
+ if (rv == 0) { // Reached the end.
+ DCHECK(request_body_stream_->IsEOF());
+ }
+
+ next_state_ = STATE_SEND_BODY;
+ return OK;
+}
+
+int QuicHttpStream::DoSendBody() {
+ if (!stream_)
+ return ERR_UNEXPECTED;
+
+ CHECK(request_body_stream_);
+ CHECK(request_body_buf_.get());
+ const bool eof = request_body_stream_->IsEOF();
+ int len = request_body_buf_->BytesRemaining();
+ if (len > 0 || eof) {
+ next_state_ = STATE_SEND_BODY_COMPLETE;
+ base::StringPiece data(request_body_buf_->data(), len);
+ return stream_->WriteStreamData(
+ data, eof,
+ base::Bind(&QuicHttpStream::OnIOComplete, weak_factory_.GetWeakPtr()));
+ }
+
+ next_state_ = STATE_OPEN;
+ return OK;
+}
+
+int QuicHttpStream::DoSendBodyComplete(int rv) {
+ if (rv < 0)
+ return rv;
+
+ // If the stream is already closed, don't continue.
+ if (!stream_)
+ return response_status_;
+
+ request_body_buf_->DidConsume(request_body_buf_->BytesRemaining());
+
+ if (!request_body_stream_->IsEOF()) {
+ next_state_ = STATE_READ_REQUEST_BODY;
+ return OK;
+ }
+
+ next_state_ = STATE_OPEN;
+ return OK;
+}
+
+int QuicHttpStream::ProcessResponseHeaders(const SpdyHeaderBlock& headers) {
+ if (!SpdyHeadersToHttpResponse(headers, response_info_)) {
+ DLOG(WARNING) << "Invalid headers";
+ return ERR_QUIC_PROTOCOL_ERROR;
+ }
+ // Put the peer's IP address and port into the response.
+ IPEndPoint address = session_->peer_address();
+ response_info_->socket_address = HostPortPair::FromIPEndPoint(address);
+ response_info_->connection_info =
+ HttpResponseInfo::CONNECTION_INFO_QUIC1_SPDY3;
+ response_info_->vary_data.Init(*request_info_,
+ *response_info_->headers.get());
+ response_info_->was_alpn_negotiated = true;
+ response_info_->alpn_negotiated_protocol = "quic/1+spdy/3";
+ response_info_->response_time = base::Time::Now();
+ response_info_->request_time = request_time_;
+ response_headers_received_ = true;
+
+ // Populate |connect_timing_| when response headers are received. This should
+ // take care of 0-RTT where request is sent before handshake is confirmed.
+ connect_timing_ = session_->GetConnectTiming();
+ return OK;
+}
+
+int QuicHttpStream::ReadAvailableData(IOBuffer* buf, int buf_len) {
+ int rv = stream_->Read(buf, buf_len);
+ // TODO(rtenneti): Temporary fix for crbug.com/585591. Added a check for null
+ // |stream_| to fix crash bug. Delete |stream_| check and histogram after fix
+ // is merged.
+ bool null_stream = stream_ == nullptr;
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicReadAvailableData.NullStream", null_stream);
+ if (null_stream)
+ return rv;
+ if (stream_->IsDoneReading()) {
+ stream_->SetDelegate(nullptr);
+ stream_->OnFinRead();
+ ResetStream();
+ }
+ return rv;
+}
+
+void QuicHttpStream::ResetStream() {
+ if (push_handle_) {
+ push_handle_->Cancel();
+ push_handle_ = nullptr;
+ }
+ if (!stream_)
+ return;
+ closed_stream_received_bytes_ = stream_->stream_bytes_read();
+ closed_stream_sent_bytes_ = stream_->stream_bytes_written();
+ closed_is_first_stream_ = stream_->IsFirstStream();
+ stream_ = nullptr;
+
+ // If |request_body_stream_| is non-NULL, Reset it, to abort any in progress
+ // read.
+ if (request_body_stream_)
+ request_body_stream_->Reset();
+}
+
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_http_stream.h b/chromium/net/quic/chromium/quic_http_stream.h
new file mode 100644
index 00000000000..68bb9165840
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_http_stream.h
@@ -0,0 +1,233 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_HTTP_STREAM_H_
+#define NET_QUIC_QUIC_HTTP_STREAM_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "net/base/io_buffer.h"
+#include "net/base/load_timing_info.h"
+#include "net/base/net_export.h"
+#include "net/http/http_stream.h"
+#include "net/log/net_log_with_source.h"
+#include "net/quic/chromium/quic_chromium_client_session.h"
+#include "net/quic/chromium/quic_chromium_client_stream.h"
+#include "net/quic/core/quic_client_push_promise_index.h"
+
+namespace net {
+
+namespace test {
+class QuicHttpStreamPeer;
+} // namespace test
+
+// The QuicHttpStream is a QUIC-specific HttpStream subclass. It holds a
+// non-owning pointer to a QuicChromiumClientStream which it uses to
+// send and receive data.
+class NET_EXPORT_PRIVATE QuicHttpStream
+ : public QuicChromiumClientSession::Observer,
+ public QuicChromiumClientStream::Delegate,
+ public QuicClientPushPromiseIndex::Delegate,
+ public HttpStream {
+ public:
+ explicit QuicHttpStream(
+ const base::WeakPtr<QuicChromiumClientSession>& session);
+
+ ~QuicHttpStream() override;
+
+ // HttpStream implementation.
+ int InitializeStream(const HttpRequestInfo* request_info,
+ RequestPriority priority,
+ const NetLogWithSource& net_log,
+ const CompletionCallback& callback) override;
+ int SendRequest(const HttpRequestHeaders& request_headers,
+ HttpResponseInfo* response,
+ const CompletionCallback& callback) override;
+ int ReadResponseHeaders(const CompletionCallback& callback) override;
+ int ReadResponseBody(IOBuffer* buf,
+ int buf_len,
+ const CompletionCallback& callback) override;
+ void Close(bool not_reusable) override;
+ HttpStream* RenewStreamForAuth() override;
+ bool IsResponseBodyComplete() const override;
+ bool IsConnectionReused() const override;
+ void SetConnectionReused() override;
+ bool CanReuseConnection() const override;
+ int64_t GetTotalReceivedBytes() const override;
+ int64_t GetTotalSentBytes() const override;
+ bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
+ void GetSSLInfo(SSLInfo* ssl_info) override;
+ void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
+ bool GetRemoteEndpoint(IPEndPoint* endpoint) override;
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) override;
+ void Drain(HttpNetworkSession* session) override;
+ void PopulateNetErrorDetails(NetErrorDetails* details) override;
+ void SetPriority(RequestPriority priority) override;
+
+ // QuicChromiumClientStream::Delegate implementation
+ void OnHeadersAvailable(const SpdyHeaderBlock& headers,
+ size_t frame_len) override;
+ void OnDataAvailable() override;
+ void OnClose() override;
+ void OnError(int error) override;
+ bool HasSendHeadersComplete() override;
+
+ // QuicChromiumClientSession::Observer implementation
+ void OnCryptoHandshakeConfirmed() override;
+ void OnSessionClosed(int error, bool port_migration_detected) override;
+
+ // QuicClientPushPromiseIndex::Delegate implementation
+ bool CheckVary(const SpdyHeaderBlock& client_request,
+ const SpdyHeaderBlock& promise_request,
+ const SpdyHeaderBlock& promise_response) override;
+ void OnRendezvousResult(QuicSpdyStream* stream) override;
+
+ private:
+ friend class test::QuicHttpStreamPeer;
+
+ enum State {
+ STATE_NONE,
+ STATE_HANDLE_PROMISE,
+ STATE_HANDLE_PROMISE_COMPLETE,
+ STATE_REQUEST_STREAM,
+ STATE_REQUEST_STREAM_COMPLETE,
+ STATE_SET_REQUEST_PRIORITY,
+ STATE_WAIT_FOR_CONFIRMATION,
+ STATE_WAIT_FOR_CONFIRMATION_COMPLETE,
+ STATE_SEND_HEADERS,
+ STATE_SEND_HEADERS_COMPLETE,
+ STATE_READ_REQUEST_BODY,
+ STATE_READ_REQUEST_BODY_COMPLETE,
+ STATE_SEND_BODY,
+ STATE_SEND_BODY_COMPLETE,
+ STATE_OPEN,
+ };
+
+ void OnIOComplete(int rv);
+ void DoCallback(int rv);
+
+ int DoLoop(int rv);
+ int DoHandlePromise();
+ int DoHandlePromiseComplete(int rv);
+ int DoRequestStream();
+ int DoRequestStreamComplete(int rv);
+ int DoSetRequestPriority();
+ int DoWaitForConfirmation();
+ int DoWaitForConfirmationComplete(int rv);
+ int DoSendHeaders();
+ int DoSendHeadersComplete(int rv);
+ int DoReadRequestBody();
+ int DoReadRequestBodyComplete(int rv);
+ int DoSendBody();
+ int DoSendBodyComplete(int rv);
+
+ int ProcessResponseHeaders(const SpdyHeaderBlock& headers);
+
+ int ReadAvailableData(IOBuffer* buf, int buf_len);
+ void EnterStateSendHeaders();
+
+ void ResetStream();
+
+ State next_state_;
+
+ base::WeakPtr<QuicChromiumClientSession> session_;
+ int session_error_; // Error code from the connection shutdown.
+ bool was_handshake_confirmed_; // True if the crypto handshake succeeded.
+ QuicChromiumClientSession::StreamRequest stream_request_;
+ QuicChromiumClientStream* stream_; // Non-owning.
+
+ // The following three fields are all owned by the caller and must
+ // outlive this object, according to the HttpStream contract.
+
+ // The request to send.
+ const HttpRequestInfo* request_info_;
+ // The request body to send, if any, owned by the caller.
+ UploadDataStream* request_body_stream_;
+ // Time the request was issued.
+ base::Time request_time_;
+ // The priority of the request.
+ RequestPriority priority_;
+ // |response_info_| is the HTTP response data object which is filled in
+ // when a the response headers are read. It is not owned by this stream.
+ HttpResponseInfo* response_info_;
+ // Because response data is buffered, also buffer the response status if the
+ // stream is explicitly closed via OnError or OnClose with an error.
+ // Once all buffered data has been returned, this will be used as the final
+ // response.
+ int response_status_;
+
+ // Serialized request headers.
+ SpdyHeaderBlock request_headers_;
+
+ bool response_headers_received_;
+
+ // Serialized HTTP request.
+ std::string request_;
+
+ // Number of bytes received by the headers stream on behalf of this stream.
+ int64_t headers_bytes_received_;
+ // Number of bytes sent by the headers stream on behalf of this stream.
+ int64_t headers_bytes_sent_;
+
+ // Number of bytes received when the stream was closed.
+ int64_t closed_stream_received_bytes_;
+ // Number of bytes sent when the stream was closed.
+ int64_t closed_stream_sent_bytes_;
+ // True if the stream is the first stream negotiated on the session. Set when
+ // the stream was closed. If |stream_| is failed to be created, this takes on
+ // the default value of false.
+ bool closed_is_first_stream_;
+
+ // The caller's callback to be used for asynchronous operations.
+ CompletionCallback callback_;
+
+ // Caller provided buffer for the ReadResponseBody() response.
+ scoped_refptr<IOBuffer> user_buffer_;
+ int user_buffer_len_;
+
+ // Temporary buffer used to read the request body from UploadDataStream.
+ scoped_refptr<IOBufferWithSize> raw_request_body_buf_;
+ // Wraps raw_request_body_buf_ to read the remaining data progressively.
+ scoped_refptr<DrainableIOBuffer> request_body_buf_;
+
+ NetLogWithSource stream_net_log_;
+
+ QuicErrorCode quic_connection_error_;
+
+ // SSLInfo from the underlying QuicSession.
+ SSLInfo ssl_info_;
+
+ // True when this stream receives a go away from server due to port migration.
+ bool port_migration_detected_;
+
+ bool found_promise_;
+ // |QuicClientPromisedInfo| owns this. It will be set when |Try()|
+ // is asynchronous, i.e. it returned QUIC_PENDING, and remains valid
+ // until |OnRendezvouResult()| fires or |push_handle_->Cancel()| is
+ // invoked.
+ QuicClientPushPromiseIndex::TryHandle* push_handle_;
+
+ // Set to true when DoLoop() is being executed, false otherwise.
+ bool in_loop_;
+
+ // Session connect timing info.
+ LoadTimingInfo::ConnectTiming connect_timing_;
+
+ base::WeakPtrFactory<QuicHttpStream> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicHttpStream);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_HTTP_STREAM_H_
diff --git a/chromium/net/quic/chromium/quic_http_stream_test.cc b/chromium/net/quic/chromium/quic_http_stream_test.cc
new file mode 100644
index 00000000000..eb672fb4878
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_http_stream_test.cc
@@ -0,0 +1,2069 @@
+// 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/chromium/quic_http_stream.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "net/base/chunked_upload_data_stream.h"
+#include "net/base/elements_upload_data_stream.h"
+#include "net/base/load_timing_info.h"
+#include "net/base/load_timing_info_test_util.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/base/upload_bytes_element_reader.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/transport_security_state.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/test_net_log.h"
+#include "net/log/test_net_log_util.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/chromium/quic_chromium_alarm_factory.h"
+#include "net/quic/chromium/quic_chromium_connection_helper.h"
+#include "net/quic/chromium/quic_chromium_packet_reader.h"
+#include "net/quic/chromium/quic_chromium_packet_writer.h"
+#include "net/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/crypto/quic_server_info.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_http_utils.h"
+#include "net/quic/core/quic_write_blocked_list.h"
+#include "net/quic/core/spdy_utils.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
+#include "net/quic/test_tools/mock_random.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_test_packet_maker.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/test_task_runner.h"
+#include "net/socket/socket_performance_watcher.h"
+#include "net/socket/socket_test_util.h"
+#include "net/spdy/spdy_frame_builder.h"
+#include "net/spdy/spdy_framer.h"
+#include "net/spdy/spdy_http_utils.h"
+#include "net/spdy/spdy_protocol.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using net::test::IsError;
+using net::test::IsOk;
+
+using std::string;
+using testing::_;
+using testing::AnyNumber;
+using testing::Return;
+
+namespace net {
+namespace test {
+namespace {
+
+const char kUploadData[] = "Really nifty data!";
+const char kDefaultServerHostName[] = "www.example.org";
+const uint16_t kDefaultServerPort = 80;
+
+class TestQuicConnection : public QuicConnection {
+ public:
+ TestQuicConnection(const QuicVersionVector& versions,
+ QuicConnectionId connection_id,
+ IPEndPoint address,
+ QuicChromiumConnectionHelper* helper,
+ QuicChromiumAlarmFactory* alarm_factory,
+ QuicPacketWriter* writer)
+ : QuicConnection(connection_id,
+ address,
+ helper,
+ alarm_factory,
+ writer,
+ true /* owns_writer */,
+ Perspective::IS_CLIENT,
+ versions) {}
+
+ void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) {
+ QuicConnectionPeer::SetSendAlgorithm(this, kDefaultPathId, send_algorithm);
+ }
+};
+
+// Subclass of QuicHttpStream that closes itself when the first piece of data
+// is received.
+class AutoClosingStream : public QuicHttpStream {
+ public:
+ explicit AutoClosingStream(
+ const base::WeakPtr<QuicChromiumClientSession>& session)
+ : QuicHttpStream(session) {}
+
+ void OnHeadersAvailable(const SpdyHeaderBlock& headers,
+ size_t frame_len) override {
+ Close(false);
+ }
+
+ void OnDataAvailable() override { Close(false); }
+};
+
+// UploadDataStream that always returns errors on data read.
+class ReadErrorUploadDataStream : public UploadDataStream {
+ public:
+ enum class FailureMode { SYNC, ASYNC };
+
+ explicit ReadErrorUploadDataStream(FailureMode mode)
+ : UploadDataStream(true, 0), async_(mode), weak_factory_(this) {}
+ ~ReadErrorUploadDataStream() override {}
+
+ private:
+ void CompleteRead() { UploadDataStream::OnReadCompleted(ERR_FAILED); }
+
+ // UploadDataStream implementation:
+ int InitInternal(const NetLogWithSource& net_log) override { return OK; }
+
+ int ReadInternal(IOBuffer* buf, int buf_len) override {
+ if (async_ == FailureMode::ASYNC) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&ReadErrorUploadDataStream::CompleteRead,
+ weak_factory_.GetWeakPtr()));
+ return ERR_IO_PENDING;
+ }
+ return ERR_FAILED;
+ }
+
+ void ResetInternal() override {}
+
+ const FailureMode async_;
+
+ base::WeakPtrFactory<ReadErrorUploadDataStream> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReadErrorUploadDataStream);
+};
+
+// A Callback that deletes the QuicHttpStream.
+class DeleteStreamCallback : public TestCompletionCallbackBase {
+ public:
+ DeleteStreamCallback(std::unique_ptr<QuicHttpStream> stream)
+ : stream_(std::move(stream)),
+ callback_(base::Bind(&DeleteStreamCallback::DeleteStream,
+ base::Unretained(this))) {}
+
+ const CompletionCallback& callback() const { return callback_; }
+
+ private:
+ void DeleteStream(int result) {
+ stream_.reset();
+ SetResult(result);
+ }
+
+ std::unique_ptr<QuicHttpStream> stream_;
+ CompletionCallback callback_;
+};
+
+} // namespace
+
+class QuicHttpStreamPeer {
+ public:
+ static QuicChromiumClientStream* GetQuicChromiumClientStream(
+ QuicHttpStream* stream) {
+ return stream->stream_;
+ }
+
+ static bool WasHandshakeConfirmed(QuicHttpStream* stream) {
+ return stream->was_handshake_confirmed_;
+ }
+
+ static void SetHandshakeConfirmed(QuicHttpStream* stream, bool confirmed) {
+ stream->was_handshake_confirmed_ = confirmed;
+ }
+};
+
+class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> {
+ protected:
+ static const bool kFin = true;
+ static const bool kIncludeVersion = true;
+ static const bool kIncludeCongestionFeedback = true;
+
+ // Holds a packet to be written to the wire, and the IO mode that should
+ // be used by the mock socket when performing the write.
+ struct PacketToWrite {
+ PacketToWrite(IoMode mode, QuicReceivedPacket* packet)
+ : mode(mode), packet(packet) {}
+ PacketToWrite(IoMode mode, int rv) : mode(mode), packet(nullptr), rv(rv) {}
+ IoMode mode;
+ QuicReceivedPacket* packet;
+ int rv;
+ };
+
+ QuicHttpStreamTest()
+ : use_closing_stream_(false),
+ crypto_config_(CryptoTestUtils::ProofVerifierForTesting()),
+ read_buffer_(new IOBufferWithSize(4096)),
+ promise_id_(kServerDataStreamId1),
+ stream_id_(kClientDataStreamId1),
+ connection_id_(2),
+ client_maker_(GetParam(),
+ connection_id_,
+ &clock_,
+ kDefaultServerHostName,
+ Perspective::IS_CLIENT),
+ server_maker_(GetParam(),
+ connection_id_,
+ &clock_,
+ kDefaultServerHostName,
+ Perspective::IS_SERVER),
+ random_generator_(0),
+ response_offset_(0) {
+ IPAddress ip(192, 0, 2, 33);
+ peer_addr_ = IPEndPoint(ip, 443);
+ self_addr_ = IPEndPoint(ip, 8435);
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
+ }
+
+ ~QuicHttpStreamTest() {
+ session_->CloseSessionOnError(ERR_ABORTED, QUIC_INTERNAL_ERROR);
+ for (size_t i = 0; i < writes_.size(); i++) {
+ delete writes_[i].packet;
+ }
+ }
+
+ // Adds a packet to the list of expected writes.
+ void AddWrite(std::unique_ptr<QuicReceivedPacket> packet) {
+ writes_.push_back(PacketToWrite(SYNCHRONOUS, packet.release()));
+ }
+
+ void AddWrite(IoMode mode, int rv) {
+ writes_.push_back(PacketToWrite(mode, rv));
+ }
+
+ // Returns the packet to be written at position |pos|.
+ QuicReceivedPacket* GetWrite(size_t pos) { return writes_[pos].packet; }
+
+ bool AtEof() {
+ return socket_data_->AllReadDataConsumed() &&
+ socket_data_->AllWriteDataConsumed();
+ }
+
+ void ProcessPacket(std::unique_ptr<QuicReceivedPacket> packet) {
+ connection_->ProcessUdpPacket(self_addr_, peer_addr_, *packet);
+ }
+
+ // Configures the test fixture to use the list of expected writes.
+ void Initialize() {
+ mock_writes_.reset(new MockWrite[writes_.size()]);
+ for (size_t i = 0; i < writes_.size(); i++) {
+ if (writes_[i].packet == nullptr) {
+ mock_writes_[i] = MockWrite(writes_[i].mode, writes_[i].rv, i);
+ } else {
+ mock_writes_[i] = MockWrite(writes_[i].mode, writes_[i].packet->data(),
+ writes_[i].packet->length());
+ }
+ }
+
+ socket_data_.reset(new StaticSocketDataProvider(
+ nullptr, 0, mock_writes_.get(), writes_.size()));
+
+ std::unique_ptr<MockUDPClientSocket> socket(new MockUDPClientSocket(
+ socket_data_.get(), net_log_.bound().net_log()));
+ socket->Connect(peer_addr_);
+ runner_ = new TestTaskRunner(&clock_);
+ send_algorithm_ = new MockSendAlgorithm();
+ EXPECT_CALL(*send_algorithm_, InRecovery()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*send_algorithm_, InSlowStart()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
+ .WillRepeatedly(Return(kMaxPacketSize));
+ EXPECT_CALL(*send_algorithm_, PacingRate(_))
+ .WillRepeatedly(Return(QuicBandwidth::Zero()));
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ .WillRepeatedly(Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(*send_algorithm_, BandwidthEstimate())
+ .WillRepeatedly(Return(QuicBandwidth::Zero()));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
+ helper_.reset(
+ new QuicChromiumConnectionHelper(&clock_, &random_generator_));
+ alarm_factory_.reset(new QuicChromiumAlarmFactory(runner_.get(), &clock_));
+
+ connection_ =
+ new TestQuicConnection(SupportedVersions(GetParam()), connection_id_,
+ peer_addr_, helper_.get(), alarm_factory_.get(),
+ new QuicChromiumPacketWriter(socket.get()));
+ connection_->set_visitor(&visitor_);
+ connection_->SetSendAlgorithm(send_algorithm_);
+
+ // Load a certificate that is valid for *.example.org
+ scoped_refptr<X509Certificate> test_cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
+ EXPECT_TRUE(test_cert.get());
+
+ verify_details_.cert_verify_result.verified_cert = test_cert;
+ verify_details_.cert_verify_result.is_issued_by_known_root = true;
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details_);
+
+ base::TimeTicks dns_end = base::TimeTicks::Now();
+ base::TimeTicks dns_start = dns_end - base::TimeDelta::FromMilliseconds(1);
+ session_.reset(new QuicChromiumClientSession(
+ connection_, std::move(socket),
+ /*stream_factory=*/nullptr, &crypto_client_stream_factory_, &clock_,
+ &transport_security_state_,
+ base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)),
+ QuicServerId(kDefaultServerHostName, kDefaultServerPort,
+ PRIVACY_MODE_DISABLED),
+ kQuicYieldAfterPacketsRead,
+ QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds),
+ /*cert_verify_flags=*/0, DefaultQuicConfig(), &crypto_config_,
+ "CONNECTION_UNKNOWN", dns_start, dns_end, &push_promise_index_,
+ base::ThreadTaskRunnerHandle::Get().get(),
+ /*socket_performance_watcher=*/nullptr, net_log_.bound().net_log()));
+ session_->Initialize();
+ TestCompletionCallback callback;
+ session_->CryptoConnect(/*require_confirmation=*/false,
+ callback.callback());
+ EXPECT_TRUE(session_->IsCryptoHandshakeConfirmed());
+ stream_.reset(use_closing_stream_
+ ? new AutoClosingStream(session_->GetWeakPtr())
+ : new QuicHttpStream(session_->GetWeakPtr()));
+
+ promised_stream_.reset(use_closing_stream_
+ ? new AutoClosingStream(session_->GetWeakPtr())
+ : new QuicHttpStream(session_->GetWeakPtr()));
+
+ push_promise_[":path"] = "/bar";
+ push_promise_[":authority"] = "www.example.org";
+ push_promise_[":version"] = "HTTP/1.1";
+ push_promise_[":method"] = "GET";
+ push_promise_[":scheme"] = "https";
+
+ promised_response_[":status"] = "200 OK";
+ promised_response_[":version"] = "HTTP/1.1";
+ promised_response_["content-type"] = "text/plain";
+
+ promise_url_ = SpdyUtils::GetUrlFromHeaderBlock(push_promise_);
+
+ serialized_push_promise_ =
+ SpdyUtils::SerializeUncompressedHeaders(push_promise_);
+ }
+
+ void SetRequest(const string& method,
+ const string& path,
+ RequestPriority priority) {
+ request_headers_ = client_maker_.GetRequestHeaders(method, "http", path);
+ }
+
+ void SetResponse(const string& status, const string& body) {
+ response_headers_ = server_maker_.GetResponseHeaders(status);
+ response_data_ = body;
+ }
+
+ std::unique_ptr<QuicReceivedPacket> InnerConstructDataPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool should_include_version,
+ bool fin,
+ QuicStreamOffset offset,
+ base::StringPiece data,
+ QuicTestPacketMaker* maker) {
+ return maker->MakeDataPacket(packet_number, stream_id,
+ should_include_version, fin, offset, data);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructClientDataPacket(
+ QuicPacketNumber packet_number,
+ bool should_include_version,
+ bool fin,
+ QuicStreamOffset offset,
+ base::StringPiece data) {
+ return InnerConstructDataPacket(packet_number, stream_id_,
+ should_include_version, fin, offset, data,
+ &client_maker_);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructServerDataPacket(
+ QuicPacketNumber packet_number,
+ bool should_include_version,
+ bool fin,
+ QuicStreamOffset offset,
+ base::StringPiece data) {
+ return InnerConstructDataPacket(packet_number, stream_id_,
+ should_include_version, fin, offset, data,
+ &server_maker_);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> InnerConstructRequestHeadersPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool should_include_version,
+ bool fin,
+ RequestPriority request_priority,
+ 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::unique_ptr<QuicReceivedPacket> ConstructRequestHeadersPacket(
+ QuicPacketNumber packet_number,
+ bool fin,
+ RequestPriority request_priority,
+ size_t* spdy_headers_frame_length) {
+ return InnerConstructRequestHeadersPacket(
+ packet_number, stream_id_, kIncludeVersion, fin, request_priority,
+ spdy_headers_frame_length, nullptr);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> InnerConstructResponseHeadersPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool fin,
+ size_t* spdy_headers_frame_length) {
+ return server_maker_.MakeResponseHeadersPacket(
+ packet_number, stream_id, !kIncludeVersion, fin,
+ std::move(response_headers_), spdy_headers_frame_length,
+ &response_offset_);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructResponseHeadersPacket(
+ QuicPacketNumber packet_number,
+ bool fin,
+ size_t* spdy_headers_frame_length) {
+ return InnerConstructResponseHeadersPacket(packet_number, stream_id_, fin,
+ spdy_headers_frame_length);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructResponseHeadersPacketWithOffset(
+ QuicPacketNumber packet_number,
+ bool fin,
+ size_t* spdy_headers_frame_length,
+ QuicStreamOffset* offset) {
+ return server_maker_.MakeResponseHeadersPacket(
+ packet_number, stream_id_, !kIncludeVersion, fin,
+ std::move(response_headers_), spdy_headers_frame_length, offset);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructResponseTrailersPacket(
+ QuicPacketNumber packet_number,
+ bool fin,
+ SpdyHeaderBlock trailers,
+ size_t* spdy_headers_frame_length,
+ QuicStreamOffset* offset) {
+ return server_maker_.MakeResponseHeadersPacket(
+ packet_number, stream_id_, !kIncludeVersion, fin, std::move(trailers),
+ spdy_headers_frame_length, offset);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructClientRstStreamPacket(
+ QuicPacketNumber packet_number) {
+ return client_maker_.MakeRstPacket(
+ packet_number, true, stream_id_,
+ AdjustErrorForVersion(QUIC_RST_ACKNOWLEDGEMENT, GetParam()));
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructClientRstStreamCancelledPacket(
+ QuicPacketNumber packet_number) {
+ return client_maker_.MakeRstPacket(packet_number, !kIncludeVersion,
+ stream_id_, QUIC_STREAM_CANCELLED);
+ }
+
+ std::unique_ptr<QuicReceivedPacket>
+ ConstructClientRstStreamVaryMismatchPacket(QuicPacketNumber packet_number) {
+ return client_maker_.MakeRstPacket(packet_number, !kIncludeVersion,
+ promise_id_, QUIC_PROMISE_VARY_MISMATCH);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructAckAndRstStreamPacket(
+ QuicPacketNumber packet_number,
+ QuicPacketNumber largest_received,
+ QuicPacketNumber ack_least_unacked,
+ QuicPacketNumber stop_least_unacked) {
+ return client_maker_.MakeAckAndRstPacket(
+ packet_number, !kIncludeVersion, stream_id_, QUIC_STREAM_CANCELLED,
+ largest_received, ack_least_unacked, stop_least_unacked,
+ !kIncludeCongestionFeedback);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructClientRstStreamErrorPacket(
+ QuicPacketNumber packet_number,
+ bool include_version) {
+ return client_maker_.MakeRstPacket(packet_number, include_version,
+ stream_id_,
+ QUIC_ERROR_PROCESSING_STREAM);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructAckAndRstStreamPacket(
+ QuicPacketNumber packet_number) {
+ return ConstructAckAndRstStreamPacket(packet_number, 2, 1, 1);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructClientAckPacket(
+ QuicPacketNumber packet_number,
+ QuicPacketNumber largest_received,
+ QuicPacketNumber least_unacked) {
+ return client_maker_.MakeAckPacket(packet_number, largest_received,
+ least_unacked,
+ !kIncludeCongestionFeedback);
+ }
+
+ std::unique_ptr<QuicReceivedPacket> ConstructServerAckPacket(
+ QuicPacketNumber packet_number,
+ QuicPacketNumber largest_received,
+ QuicPacketNumber least_unacked) {
+ return server_maker_.MakeAckPacket(packet_number, largest_received,
+ least_unacked,
+ !kIncludeCongestionFeedback);
+ }
+
+ void ReceivePromise(QuicStreamId id) {
+ QuicChromiumClientStream* stream =
+ QuicHttpStreamPeer::GetQuicChromiumClientStream(stream_.get());
+ stream->OnStreamHeaders(serialized_push_promise_);
+
+ stream->OnPromiseHeadersComplete(id, serialized_push_promise_.size());
+ }
+
+ void ExpectLoadTimingValid(const LoadTimingInfo& load_timing_info,
+ bool session_reused) {
+ EXPECT_EQ(session_reused, load_timing_info.socket_reused);
+ if (session_reused) {
+ ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
+ } else {
+ ExpectConnectTimingHasTimes(
+ load_timing_info.connect_timing,
+ CONNECT_TIMING_HAS_SSL_TIMES | CONNECT_TIMING_HAS_DNS_TIMES);
+ }
+ ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
+ }
+
+ BoundTestNetLog net_log_;
+ bool use_closing_stream_;
+ MockSendAlgorithm* send_algorithm_;
+ scoped_refptr<TestTaskRunner> runner_;
+ std::unique_ptr<MockWrite[]> mock_writes_;
+ MockClock clock_;
+ TestQuicConnection* connection_;
+ std::unique_ptr<QuicChromiumConnectionHelper> helper_;
+ std::unique_ptr<QuicChromiumAlarmFactory> alarm_factory_;
+ testing::StrictMock<MockQuicConnectionVisitor> visitor_;
+ std::unique_ptr<QuicHttpStream> stream_;
+ TransportSecurityState transport_security_state_;
+ std::unique_ptr<QuicChromiumClientSession> session_;
+ QuicCryptoClientConfig crypto_config_;
+ TestCompletionCallback callback_;
+ HttpRequestInfo request_;
+ HttpRequestHeaders headers_;
+ HttpResponseInfo response_;
+ scoped_refptr<IOBufferWithSize> read_buffer_;
+ SpdyHeaderBlock request_headers_;
+ SpdyHeaderBlock response_headers_;
+ string request_data_;
+ string response_data_;
+ QuicClientPushPromiseIndex push_promise_index_;
+
+ // For server push testing
+ std::unique_ptr<QuicHttpStream> promised_stream_;
+ SpdyHeaderBlock push_promise_;
+ SpdyHeaderBlock promised_response_;
+ const QuicStreamId promise_id_;
+ string promise_url_;
+ string serialized_push_promise_;
+ const QuicStreamId stream_id_;
+
+ const QuicConnectionId connection_id_;
+ QuicTestPacketMaker client_maker_;
+ QuicTestPacketMaker server_maker_;
+ IPEndPoint self_addr_;
+ IPEndPoint peer_addr_;
+ MockRandom random_generator_;
+ ProofVerifyDetailsChromium verify_details_;
+ MockCryptoClientStreamFactory crypto_client_stream_factory_;
+ std::unique_ptr<StaticSocketDataProvider> socket_data_;
+ std::vector<PacketToWrite> writes_;
+ QuicStreamOffset response_offset_;
+};
+
+INSTANTIATE_TEST_CASE_P(Version,
+ QuicHttpStreamTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
+
+TEST_P(QuicHttpStreamTest, RenewStreamForAuth) {
+ Initialize();
+ EXPECT_EQ(nullptr, stream_->RenewStreamForAuth());
+}
+
+TEST_P(QuicHttpStreamTest, CanReuseConnection) {
+ Initialize();
+ EXPECT_FALSE(stream_->CanReuseConnection());
+}
+
+TEST_P(QuicHttpStreamTest, DisableConnectionMigrationForStream) {
+ request_.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION;
+ Initialize();
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+ QuicChromiumClientStream* client_stream =
+ QuicHttpStreamPeer::GetQuicChromiumClientStream(stream_.get());
+ EXPECT_FALSE(client_stream->can_migrate());
+}
+
+TEST_P(QuicHttpStreamTest, GetRequest) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_header_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
+ &spdy_request_header_frame_length));
+ Initialize();
+
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ // Make sure getting load timing from the stream early does not crash.
+ LoadTimingInfo load_timing_info;
+ EXPECT_TRUE(stream_->GetLoadTimingInfo(&load_timing_info));
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+ EXPECT_EQ(OK,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+
+ // Ack the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()),
+ IsError(ERR_IO_PENDING));
+
+ SetResponse("404 Not Found", string());
+ size_t spdy_response_header_frame_length;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, kFin, &spdy_response_header_frame_length));
+
+ // Now that the headers have been processed, the callback will return.
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ ASSERT_TRUE(response_.headers.get());
+ EXPECT_EQ(404, response_.headers->response_code());
+ EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
+ EXPECT_FALSE(response_.response_time.is_null());
+ EXPECT_FALSE(response_.request_time.is_null());
+
+ // There is no body, so this should return immediately.
+ EXPECT_EQ(0,
+ stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
+ callback_.callback()));
+ EXPECT_TRUE(stream_->IsResponseBodyComplete());
+ EXPECT_TRUE(AtEof());
+
+ EXPECT_TRUE(stream_->GetLoadTimingInfo(&load_timing_info));
+ ExpectLoadTimingValid(load_timing_info, /*session_reused=*/false);
+
+ // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
+ // headers and payload.
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_header_frame_length),
+ stream_->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(spdy_response_header_frame_length),
+ stream_->GetTotalReceivedBytes());
+}
+
+TEST_P(QuicHttpStreamTest, LoadTimingTwoRequests) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_header_frame_length;
+
+ QuicStreamOffset offset = 0;
+ AddWrite(InnerConstructRequestHeadersPacket(
+ 1, kClientDataStreamId1, kIncludeVersion, kFin, DEFAULT_PRIORITY,
+ &spdy_request_header_frame_length, &offset));
+
+ // SetRequest() again for second request as |request_headers_| was moved.
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ AddWrite(InnerConstructRequestHeadersPacket(
+ 2, kClientDataStreamId2, kIncludeVersion, kFin, DEFAULT_PRIORITY,
+ &spdy_request_header_frame_length, &offset));
+ AddWrite(ConstructClientAckPacket(3, 3, 1)); // Ack the responses.
+
+ Initialize();
+
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+ // Start first request.
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+ EXPECT_EQ(OK,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+
+ // Start a second request.
+ QuicHttpStream stream2(session_->GetWeakPtr());
+ TestCompletionCallback callback2;
+ EXPECT_EQ(OK,
+ stream2.InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback2.callback()));
+ EXPECT_EQ(OK,
+ stream2.SendRequest(headers_, &response_, callback2.callback()));
+
+ // Ack both requests.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()),
+ IsError(ERR_IO_PENDING));
+ size_t spdy_response_header_frame_length;
+ SetResponse("200 OK", string());
+ ProcessPacket(InnerConstructResponseHeadersPacket(
+ 2, kClientDataStreamId1, kFin, &spdy_response_header_frame_length));
+
+ // Now that the headers have been processed, the callback will return.
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ EXPECT_EQ(200, response_.headers->response_code());
+
+ // There is no body, so this should return immediately.
+ EXPECT_EQ(0,
+ stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
+ callback_.callback()));
+ EXPECT_TRUE(stream_->IsResponseBodyComplete());
+
+ LoadTimingInfo load_timing_info;
+ EXPECT_TRUE(stream_->GetLoadTimingInfo(&load_timing_info));
+ ExpectLoadTimingValid(load_timing_info, /*session_reused=*/false);
+
+ // SetResponse() again for second request as |response_headers_| was moved.
+ SetResponse("200 OK", string());
+ EXPECT_THAT(stream2.ReadResponseHeaders(callback2.callback()),
+ IsError(ERR_IO_PENDING));
+
+ ProcessPacket(InnerConstructResponseHeadersPacket(
+ 3, kClientDataStreamId2, kFin, &spdy_response_header_frame_length));
+
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
+
+ // There is no body, so this should return immediately.
+ EXPECT_EQ(0,
+ stream2.ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
+ callback2.callback()));
+ EXPECT_TRUE(stream2.IsResponseBodyComplete());
+
+ LoadTimingInfo load_timing_info2;
+ EXPECT_TRUE(stream2.GetLoadTimingInfo(&load_timing_info2));
+ ExpectLoadTimingValid(load_timing_info2, /*session_reused=*/true);
+}
+
+// QuicHttpStream does not currently support trailers. It should ignore
+// trailers upon receiving them.
+TEST_P(QuicHttpStreamTest, GetRequestWithTrailers) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_header_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
+ &spdy_request_header_frame_length));
+ AddWrite(ConstructClientAckPacket(2, 3, 1)); // Ack the data packet.
+
+ Initialize();
+
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+
+ EXPECT_EQ(OK,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+ // Ack the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()),
+ IsError(ERR_IO_PENDING));
+
+ SetResponse("200 OK", string());
+
+ // Send the response headers.
+ size_t spdy_response_header_frame_length;
+ QuicStreamOffset offset = 0;
+ ProcessPacket(ConstructResponseHeadersPacketWithOffset(
+ 2, !kFin, &spdy_response_header_frame_length, &offset));
+ // Now that the headers have been processed, the callback will return.
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ ASSERT_TRUE(response_.headers.get());
+ EXPECT_EQ(200, response_.headers->response_code());
+ EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
+ EXPECT_FALSE(response_.response_time.is_null());
+ EXPECT_FALSE(response_.request_time.is_null());
+
+ // Send the response body.
+ const char kResponseBody[] = "Hello world!";
+ ProcessPacket(
+ ConstructServerDataPacket(3, false, !kFin, /*offset=*/0, kResponseBody));
+ SpdyHeaderBlock trailers;
+ size_t spdy_trailers_frame_length;
+ trailers["foo"] = "bar";
+ trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
+ ProcessPacket(ConstructResponseTrailersPacket(
+ 4, kFin, std::move(trailers), &spdy_trailers_frame_length, &offset));
+
+ // Make sure trailers are processed.
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(static_cast<int>(strlen(kResponseBody)),
+ stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
+ callback_.callback()));
+ EXPECT_TRUE(stream_->IsResponseBodyComplete());
+
+ EXPECT_EQ(OK,
+ stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
+ callback_.callback()));
+
+ EXPECT_TRUE(stream_->IsResponseBodyComplete());
+ EXPECT_TRUE(AtEof());
+
+ // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
+ // headers and payload.
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_header_frame_length),
+ stream_->GetTotalSentBytes());
+ EXPECT_EQ(
+ static_cast<int64_t>(spdy_response_header_frame_length +
+ strlen(kResponseBody) + +spdy_trailers_frame_length),
+ stream_->GetTotalReceivedBytes());
+ // Check that NetLog was filled as expected.
+ TestNetLogEntry::List entries;
+ net_log_.GetEntries(&entries);
+ size_t pos = ExpectLogContainsSomewhere(
+ entries, /*min_offset=*/0,
+ NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
+ NetLogEventPhase::NONE);
+ pos = ExpectLogContainsSomewhere(
+ entries, /*min_offset=*/pos,
+ NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
+ NetLogEventPhase::NONE);
+ ExpectLogContainsSomewhere(
+ entries, /*min_offset=*/pos,
+ NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
+ NetLogEventPhase::NONE);
+}
+
+// Regression test for http://crbug.com/288128
+TEST_P(QuicHttpStreamTest, GetRequestLargeResponse) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ Initialize();
+
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+ EXPECT_EQ(OK,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+
+ // Ack the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()),
+ IsError(ERR_IO_PENDING));
+
+ response_headers_[":status"] = "200 OK";
+ response_headers_[":version"] = "HTTP/1.1";
+ response_headers_["content-type"] = "text/plain";
+ response_headers_["big6"] = string(1000, 'x'); // Lots of x's.
+
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, kFin, &spdy_response_headers_frame_length));
+
+ // Now that the headers have been processed, the callback will return.
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ ASSERT_TRUE(response_.headers.get());
+ EXPECT_EQ(200, response_.headers->response_code());
+ EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
+
+ // There is no body, so this should return immediately.
+ EXPECT_EQ(0,
+ stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
+ callback_.callback()));
+ EXPECT_TRUE(stream_->IsResponseBodyComplete());
+ EXPECT_TRUE(AtEof());
+
+ // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
+ // headers and payload.
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
+ stream_->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length),
+ stream_->GetTotalReceivedBytes());
+}
+
+// Regression test for http://crbug.com/409101
+TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendRequest) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ Initialize();
+
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+
+ session_->connection()->CloseConnection(
+ QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
+
+ EXPECT_EQ(ERR_CONNECTION_CLOSED,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+
+ EXPECT_EQ(0, stream_->GetTotalSentBytes());
+ EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
+}
+
+// Regression test for http://crbug.com/584441
+TEST_P(QuicHttpStreamTest, GetSSLInfoAfterSessionClosed) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ Initialize();
+
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+
+ SSLInfo ssl_info;
+ EXPECT_FALSE(ssl_info.is_valid());
+ stream_->GetSSLInfo(&ssl_info);
+ EXPECT_TRUE(ssl_info.is_valid());
+
+ session_->connection()->CloseConnection(
+ QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
+
+ SSLInfo ssl_info2;
+ stream_->GetSSLInfo(&ssl_info2);
+ EXPECT_TRUE(ssl_info2.is_valid());
+}
+
+TEST_P(QuicHttpStreamTest, LogGranularQuicConnectionError) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructAckAndRstStreamPacket(2));
+ use_closing_stream_ = true;
+ Initialize();
+
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+ EXPECT_EQ(OK,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+
+ // Ack the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+ EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()),
+ IsError(ERR_IO_PENDING));
+
+ EXPECT_TRUE(QuicHttpStreamPeer::WasHandshakeConfirmed(stream_.get()));
+
+ QuicConnectionCloseFrame frame;
+ frame.error_code = QUIC_PEER_GOING_AWAY;
+ session_->connection()->OnConnectionCloseFrame(frame);
+
+ NetErrorDetails details;
+ EXPECT_EQ(QUIC_NO_ERROR, details.quic_connection_error);
+ stream_->PopulateNetErrorDetails(&details);
+ EXPECT_EQ(QUIC_PEER_GOING_AWAY, details.quic_connection_error);
+}
+
+TEST_P(QuicHttpStreamTest, DoNotLogGranularQuicErrorIfHandshakeNotConfirmed) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructAckAndRstStreamPacket(2));
+ use_closing_stream_ = true;
+ Initialize();
+
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+ EXPECT_EQ(OK,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+
+ // Ack the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+ EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()),
+ IsError(ERR_IO_PENDING));
+
+ // The test setup defaults handshake to be confirmed. Manually set
+ // it to be not confirmed.
+ // Granular errors shouldn't be reported if handshake not confirmed.
+ QuicHttpStreamPeer::SetHandshakeConfirmed(stream_.get(), false);
+
+ EXPECT_FALSE(QuicHttpStreamPeer::WasHandshakeConfirmed(stream_.get()));
+ QuicConnectionCloseFrame frame;
+ frame.error_code = QUIC_PEER_GOING_AWAY;
+ session_->connection()->OnConnectionCloseFrame(frame);
+
+ NetErrorDetails details;
+ EXPECT_EQ(QUIC_NO_ERROR, details.quic_connection_error);
+ stream_->PopulateNetErrorDetails(&details);
+ EXPECT_EQ(QUIC_NO_ERROR, details.quic_connection_error);
+}
+
+// Regression test for http://crbug.com/409871
+TEST_P(QuicHttpStreamTest, SessionClosedBeforeReadResponseHeaders) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ Initialize();
+
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+
+ EXPECT_EQ(OK,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+
+ session_->connection()->CloseConnection(
+ QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
+
+ EXPECT_NE(OK, stream_->ReadResponseHeaders(callback_.callback()));
+
+ // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
+ // headers and payload.
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
+ stream_->GetTotalSentBytes());
+ EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
+}
+
+TEST_P(QuicHttpStreamTest, SendPostRequest) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructClientDataPacket(2, kIncludeVersion, kFin, 0, kUploadData));
+ AddWrite(ConstructClientAckPacket(3, 3, 1));
+
+ Initialize();
+
+ std::vector<std::unique_ptr<UploadElementReader>> element_readers;
+ element_readers.push_back(base::MakeUnique<UploadBytesElementReader>(
+ kUploadData, strlen(kUploadData)));
+ ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
+ request_.method = "POST";
+ request_.url = GURL("http://www.example.org/");
+ request_.upload_data_stream = &upload_data_stream;
+ ASSERT_THAT(request_.upload_data_stream->Init(CompletionCallback(),
+ NetLogWithSource()),
+ IsOk());
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+ EXPECT_EQ(OK,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+
+ // Ack both packets in the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Send the response headers (but not the body).
+ SetResponse("200 OK", string());
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, !kFin, &spdy_response_headers_frame_length));
+
+ // The headers have arrived, but they are delivered asynchronously.
+ EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ ASSERT_TRUE(response_.headers.get());
+ EXPECT_EQ(200, response_.headers->response_code());
+ EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
+
+ // Send the response body.
+ const char kResponseBody[] = "Hello world!";
+ ProcessPacket(ConstructServerDataPacket(3, false, kFin, 0, kResponseBody));
+ // Since the body has already arrived, this should return immediately.
+ EXPECT_EQ(static_cast<int>(strlen(kResponseBody)),
+ stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
+ callback_.callback()));
+
+ EXPECT_TRUE(stream_->IsResponseBodyComplete());
+ EXPECT_TRUE(AtEof());
+
+ // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
+ // headers and payload.
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
+ strlen(kUploadData)),
+ stream_->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
+ strlen(kResponseBody)),
+ stream_->GetTotalReceivedBytes());
+}
+
+TEST_P(QuicHttpStreamTest, SendChunkedPostRequest) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t chunk_size = strlen(kUploadData);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(
+ ConstructClientDataPacket(2, kIncludeVersion, !kFin, 0, kUploadData));
+ AddWrite(ConstructClientDataPacket(3, kIncludeVersion, kFin, chunk_size,
+ kUploadData));
+ AddWrite(ConstructClientAckPacket(4, 3, 1));
+ Initialize();
+
+ ChunkedUploadDataStream upload_data_stream(0);
+ upload_data_stream.AppendData(kUploadData, chunk_size, false);
+
+ request_.method = "POST";
+ request_.url = GURL("http://www.example.org/");
+ request_.upload_data_stream = &upload_data_stream;
+ ASSERT_EQ(OK, request_.upload_data_stream->Init(
+ TestCompletionCallback().callback(), NetLogWithSource()));
+
+ ASSERT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+ ASSERT_EQ(ERR_IO_PENDING,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+
+ upload_data_stream.AppendData(kUploadData, chunk_size, true);
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+
+ // Ack both packets in the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Send the response headers (but not the body).
+ SetResponse("200 OK", string());
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, !kFin, &spdy_response_headers_frame_length));
+
+ // The headers have arrived, but they are delivered asynchronously
+ EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ ASSERT_TRUE(response_.headers.get());
+ EXPECT_EQ(200, response_.headers->response_code());
+ EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
+
+ // Send the response body.
+ const char kResponseBody[] = "Hello world!";
+ ProcessPacket(ConstructServerDataPacket(
+ 3, false, kFin, response_data_.length(), kResponseBody));
+
+ // Since the body has already arrived, this should return immediately.
+ ASSERT_EQ(static_cast<int>(strlen(kResponseBody)),
+ stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
+ callback_.callback()));
+
+ EXPECT_TRUE(stream_->IsResponseBodyComplete());
+ EXPECT_TRUE(AtEof());
+
+ // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
+ // headers and payload.
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
+ strlen(kUploadData) * 2),
+ stream_->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
+ strlen(kResponseBody)),
+ stream_->GetTotalReceivedBytes());
+}
+
+TEST_P(QuicHttpStreamTest, SendChunkedPostRequestWithFinalEmptyDataPacket) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t chunk_size = strlen(kUploadData);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(
+ ConstructClientDataPacket(2, kIncludeVersion, !kFin, 0, kUploadData));
+ AddWrite(ConstructClientDataPacket(3, kIncludeVersion, kFin, chunk_size, ""));
+ AddWrite(ConstructClientAckPacket(4, 3, 1));
+ Initialize();
+
+ ChunkedUploadDataStream upload_data_stream(0);
+ upload_data_stream.AppendData(kUploadData, chunk_size, false);
+
+ request_.method = "POST";
+ request_.url = GURL("http://www.example.org/");
+ request_.upload_data_stream = &upload_data_stream;
+ ASSERT_EQ(OK, request_.upload_data_stream->Init(
+ TestCompletionCallback().callback(), NetLogWithSource()));
+
+ ASSERT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+ ASSERT_EQ(ERR_IO_PENDING,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+
+ upload_data_stream.AppendData(nullptr, 0, true);
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Send the response headers (but not the body).
+ SetResponse("200 OK", string());
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, !kFin, &spdy_response_headers_frame_length));
+
+ // The headers have arrived, but they are delivered asynchronously
+ EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ ASSERT_TRUE(response_.headers.get());
+ EXPECT_EQ(200, response_.headers->response_code());
+ EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
+
+ // Send the response body.
+ const char kResponseBody[] = "Hello world!";
+ ProcessPacket(ConstructServerDataPacket(
+ 3, false, kFin, response_data_.length(), kResponseBody));
+
+ // The body has arrived, but it is delivered asynchronously
+ ASSERT_EQ(static_cast<int>(strlen(kResponseBody)),
+ stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
+ callback_.callback()));
+ EXPECT_TRUE(stream_->IsResponseBodyComplete());
+ EXPECT_TRUE(AtEof());
+
+ // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
+ // headers and payload.
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
+ strlen(kUploadData)),
+ stream_->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
+ strlen(kResponseBody)),
+ stream_->GetTotalReceivedBytes());
+}
+
+TEST_P(QuicHttpStreamTest, SendChunkedPostRequestWithOneEmptyDataPacket) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructClientDataPacket(2, kIncludeVersion, kFin, 0, ""));
+ AddWrite(ConstructClientAckPacket(3, 3, 1));
+ Initialize();
+
+ ChunkedUploadDataStream upload_data_stream(0);
+
+ request_.method = "POST";
+ request_.url = GURL("http://www.example.org/");
+ request_.upload_data_stream = &upload_data_stream;
+ ASSERT_EQ(OK, request_.upload_data_stream->Init(
+ TestCompletionCallback().callback(), NetLogWithSource()));
+
+ ASSERT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+ ASSERT_EQ(ERR_IO_PENDING,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+
+ upload_data_stream.AppendData(nullptr, 0, true);
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+ // Send the response headers (but not the body).
+ SetResponse("200 OK", string());
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(ConstructResponseHeadersPacket(
+ 2, !kFin, &spdy_response_headers_frame_length));
+
+ // The headers have arrived, but they are delivered asynchronously
+ EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ ASSERT_TRUE(response_.headers.get());
+ EXPECT_EQ(200, response_.headers->response_code());
+ EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
+
+ // Send the response body.
+ const char kResponseBody[] = "Hello world!";
+ ProcessPacket(ConstructServerDataPacket(
+ 3, false, kFin, response_data_.length(), kResponseBody));
+
+ // The body has arrived, but it is delivered asynchronously
+ ASSERT_EQ(static_cast<int>(strlen(kResponseBody)),
+ stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
+ callback_.callback()));
+
+ EXPECT_TRUE(stream_->IsResponseBodyComplete());
+ EXPECT_TRUE(AtEof());
+
+ // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
+ // headers and payload.
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
+ stream_->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
+ strlen(kResponseBody)),
+ stream_->GetTotalReceivedBytes());
+}
+
+TEST_P(QuicHttpStreamTest, DestroyedEarly) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructAckAndRstStreamPacket(2));
+ use_closing_stream_ = true;
+ Initialize();
+
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+ EXPECT_EQ(OK,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+
+ // Ack the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+ EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()),
+ IsError(ERR_IO_PENDING));
+
+ // Send the response with a body.
+ SetResponse("404 OK", "hello world!");
+ // In the course of processing this packet, the QuicHttpStream close itself.
+ ProcessPacket(ConstructResponseHeadersPacket(2, kFin, nullptr));
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(AtEof());
+
+ // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
+ // headers and payload.
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
+ stream_->GetTotalSentBytes());
+ // Zero since the stream is closed before processing the headers.
+ EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
+}
+
+TEST_P(QuicHttpStreamTest, Priority) {
+ SetRequest("GET", "/", MEDIUM);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, kFin, MEDIUM,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructAckAndRstStreamPacket(2));
+ use_closing_stream_ = true;
+ Initialize();
+
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK, stream_->InitializeStream(&request_, MEDIUM, net_log_.bound(),
+ callback_.callback()));
+
+ // Check that priority is highest.
+ QuicChromiumClientStream* reliable_stream =
+ QuicHttpStreamPeer::GetQuicChromiumClientStream(stream_.get());
+ DCHECK(reliable_stream);
+ DCHECK_EQ(kV3HighestPriority, reliable_stream->priority());
+
+ EXPECT_EQ(OK,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+
+ // Check that priority has now dropped back to MEDIUM.
+ DCHECK_EQ(MEDIUM,
+ ConvertQuicPriorityToRequestPriority(reliable_stream->priority()));
+
+ // Ack the request.
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+ EXPECT_THAT(stream_->ReadResponseHeaders(callback_.callback()),
+ IsError(ERR_IO_PENDING));
+
+ // Send the response with a body.
+ SetResponse("404 OK", "hello world!");
+ // In the course of processing this packet, the QuicHttpStream close itself.
+ ProcessPacket(ConstructResponseHeadersPacket(2, kFin, nullptr));
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(AtEof());
+
+ // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
+ // headers and payload.
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
+ stream_->GetTotalSentBytes());
+ // Zero since the stream is closed before processing the headers.
+ EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
+}
+
+// Regression test for http://crbug.com/294870
+TEST_P(QuicHttpStreamTest, CheckPriorityWithNoDelegate) {
+ SetRequest("GET", "/", MEDIUM);
+ use_closing_stream_ = true;
+
+ AddWrite(ConstructClientRstStreamPacket(1));
+
+ Initialize();
+
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK, stream_->InitializeStream(&request_, MEDIUM, net_log_.bound(),
+ callback_.callback()));
+
+ // Check that priority is highest.
+ QuicChromiumClientStream* reliable_stream =
+ QuicHttpStreamPeer::GetQuicChromiumClientStream(stream_.get());
+ DCHECK(reliable_stream);
+ QuicChromiumClientStream::Delegate* delegate = reliable_stream->GetDelegate();
+ DCHECK(delegate);
+ DCHECK_EQ(kV3HighestPriority, reliable_stream->priority());
+
+ // Set Delegate to nullptr and make sure Priority returns highest
+ // priority.
+ reliable_stream->SetDelegate(nullptr);
+ DCHECK_EQ(kV3HighestPriority, reliable_stream->priority());
+ reliable_stream->SetDelegate(delegate);
+
+ EXPECT_EQ(0, stream_->GetTotalSentBytes());
+ EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
+}
+
+TEST_P(QuicHttpStreamTest, SessionClosedDuringDoLoop) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(
+ ConstructClientDataPacket(2, kIncludeVersion, !kFin, 0, kUploadData));
+ // Second data write will result in a synchronous failure which will close
+ // the session.
+ AddWrite(SYNCHRONOUS, ERR_FAILED);
+ Initialize();
+
+ ChunkedUploadDataStream upload_data_stream(0);
+
+ request_.method = "POST";
+ request_.url = GURL("http://www.example.org/");
+ request_.upload_data_stream = &upload_data_stream;
+ ASSERT_EQ(OK, request_.upload_data_stream->Init(
+ TestCompletionCallback().callback(), NetLogWithSource()));
+
+ size_t chunk_size = strlen(kUploadData);
+ upload_data_stream.AppendData(kUploadData, chunk_size, false);
+ ASSERT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+ QuicHttpStream* stream = stream_.get();
+ DeleteStreamCallback delete_stream_callback(std::move(stream_));
+ // SendRequest() completes asynchronously after the final chunk is added.
+ ASSERT_EQ(ERR_IO_PENDING,
+ stream->SendRequest(headers_, &response_, callback_.callback()));
+ upload_data_stream.AppendData(kUploadData, chunk_size, true);
+ int rv = callback_.WaitForResult();
+ EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, rv);
+}
+
+TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendHeadersComplete) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ AddWrite(SYNCHRONOUS, ERR_FAILED);
+ Initialize();
+
+ ChunkedUploadDataStream upload_data_stream(0);
+
+ request_.method = "POST";
+ request_.url = GURL("http://www.example.org/");
+ request_.upload_data_stream = &upload_data_stream;
+ ASSERT_EQ(OK, request_.upload_data_stream->Init(
+ TestCompletionCallback().callback(), NetLogWithSource()));
+
+ ASSERT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+ ASSERT_EQ(ERR_QUIC_PROTOCOL_ERROR,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+}
+
+TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendBodyComplete) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(SYNCHRONOUS, ERR_FAILED);
+ Initialize();
+
+ ChunkedUploadDataStream upload_data_stream(0);
+ size_t chunk_size = strlen(kUploadData);
+ upload_data_stream.AppendData(kUploadData, chunk_size, false);
+
+ request_.method = "POST";
+ request_.url = GURL("http://www.example.org/");
+ request_.upload_data_stream = &upload_data_stream;
+ ASSERT_EQ(OK, request_.upload_data_stream->Init(
+ TestCompletionCallback().callback(), NetLogWithSource()));
+
+ ASSERT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+ ASSERT_EQ(ERR_QUIC_PROTOCOL_ERROR,
+ stream_->SendRequest(headers_, &response_, callback_.callback()));
+}
+
+TEST_P(QuicHttpStreamTest, ServerPushGetRequest) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ Initialize();
+
+ // Initialize the first stream, for receiving the promise on.
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+
+ // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE
+ // packet, but does it matter?
+ ReceivePromise(promise_id_);
+ EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
+
+ request_.url = GURL(promise_url_);
+
+ // 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()));
+
+ // Receive the promised response headers.
+ response_headers_ = promised_response_.Clone();
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(InnerConstructResponseHeadersPacket(
+ 1, promise_id_, false, &spdy_response_headers_frame_length));
+
+ // Receive the promised response body.
+ const char kResponseBody[] = "Hello world!";
+ ProcessPacket(InnerConstructDataPacket(2, promise_id_, false, kFin, 0,
+ kResponseBody, &server_maker_));
+
+ // Now sending a matching request will have successful rendezvous
+ // with the promised stream.
+ EXPECT_EQ(OK, promised_stream_->SendRequest(headers_, &response_,
+ callback_.callback()));
+
+ EXPECT_EQ(
+ QuicHttpStreamPeer::GetQuicChromiumClientStream(promised_stream_.get())
+ ->id(),
+ promise_id_);
+
+ // The headers will be immediately available.
+ EXPECT_THAT(promised_stream_->ReadResponseHeaders(callback_.callback()),
+ IsOk());
+
+ // As will be the body.
+ EXPECT_EQ(
+ static_cast<int>(strlen(kResponseBody)),
+ promised_stream_->ReadResponseBody(
+ read_buffer_.get(), read_buffer_->size(), callback_.callback()));
+ EXPECT_TRUE(promised_stream_->IsResponseBodyComplete());
+ EXPECT_TRUE(AtEof());
+
+ EXPECT_EQ(0, stream_->GetTotalSentBytes());
+ EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
+ EXPECT_EQ(0, promised_stream_->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
+ strlen(kResponseBody)),
+ promised_stream_->GetTotalReceivedBytes());
+}
+
+TEST_P(QuicHttpStreamTest, ServerPushGetRequestSlowResponse) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ Initialize();
+
+ // Initialize the first stream, for receiving the promise on.
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+
+ // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE
+ // packet, but does it matter?
+ ReceivePromise(promise_id_);
+ EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
+
+ request_.url = GURL(promise_url_);
+
+ // 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()));
+
+ // Now sending a matching request will rendezvous with the promised
+ // stream, but pending secondary validation.
+ EXPECT_EQ(ERR_IO_PENDING, promised_stream_->SendRequest(
+ headers_, &response_, callback_.callback()));
+
+ // Receive the promised response headers.
+ response_headers_ = promised_response_.Clone();
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(InnerConstructResponseHeadersPacket(
+ 1, promise_id_, false, &spdy_response_headers_frame_length));
+
+ // Receive the promised response body.
+ const char kResponseBody[] = "Hello world!";
+ ProcessPacket(InnerConstructDataPacket(2, promise_id_, false, kFin, 0,
+ kResponseBody, &server_maker_));
+
+ base::RunLoop().RunUntilIdle();
+
+ // Rendezvous should have succeeded now, so the promised stream
+ // should point at our push stream, and we should be able read
+ // headers and data from it.
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+
+ EXPECT_EQ(
+ QuicHttpStreamPeer::GetQuicChromiumClientStream(promised_stream_.get())
+ ->id(),
+ promise_id_);
+
+ EXPECT_THAT(promised_stream_->ReadResponseHeaders(callback_.callback()),
+ IsOk());
+
+ EXPECT_EQ(
+ static_cast<int>(strlen(kResponseBody)),
+ promised_stream_->ReadResponseBody(
+ read_buffer_.get(), read_buffer_->size(), callback_.callback()));
+
+ // Callback should return
+ EXPECT_TRUE(promised_stream_->IsResponseBodyComplete());
+ EXPECT_TRUE(AtEof());
+
+ EXPECT_EQ(0, stream_->GetTotalSentBytes());
+ EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
+ EXPECT_EQ(0, promised_stream_->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
+ strlen(kResponseBody)),
+ promised_stream_->GetTotalReceivedBytes());
+}
+
+// Verify fix for crbug.com/637349
+TEST_P(QuicHttpStreamTest, ServerPushCancelHttpStreamBeforeResponse) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ Initialize();
+
+ // Initialize the first stream, for receiving the promise on.
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+
+ // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE
+ // packet, but does it matter?
+ ReceivePromise(promise_id_);
+ EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
+
+ request_.url = GURL(promise_url_);
+
+ // 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()));
+
+ // Now sending a matching request will rendezvous with the promised
+ // stream, but pending secondary validation.
+ EXPECT_EQ(ERR_IO_PENDING, promised_stream_->SendRequest(
+ headers_, &response_, callback_.callback()));
+
+ base::RunLoop().RunUntilIdle();
+
+ // Cause of FinalValidation() crash as per bug.
+ promised_stream_.reset();
+
+ // Receive the promised response headers.
+ response_headers_ = promised_response_.Clone();
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(InnerConstructResponseHeadersPacket(
+ 1, promise_id_, false, &spdy_response_headers_frame_length));
+}
+
+TEST_P(QuicHttpStreamTest, ServerPushCrossOriginOK) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ Initialize();
+
+ // Initialize the first stream, for receiving the promise on.
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+
+ // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE
+ // packet, but does it matter?
+
+ push_promise_[":authority"] = "mail.example.org";
+ promise_url_ = SpdyUtils::GetUrlFromHeaderBlock(push_promise_);
+ serialized_push_promise_ =
+ SpdyUtils::SerializeUncompressedHeaders(push_promise_);
+
+ ReceivePromise(promise_id_);
+ EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
+
+ request_.url = GURL(promise_url_);
+
+ // 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()));
+
+ // Receive the promised response headers.
+ response_headers_ = promised_response_.Clone();
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(InnerConstructResponseHeadersPacket(
+ 1, promise_id_, false, &spdy_response_headers_frame_length));
+
+ // Receive the promised response body.
+ const char kResponseBody[] = "Hello world!";
+ ProcessPacket(InnerConstructDataPacket(2, promise_id_, false, kFin, 0,
+ kResponseBody, &server_maker_));
+
+ // Now sending a matching request will have successful rendezvous
+ // with the promised stream.
+ EXPECT_EQ(OK, promised_stream_->SendRequest(headers_, &response_,
+ callback_.callback()));
+
+ EXPECT_EQ(
+ QuicHttpStreamPeer::GetQuicChromiumClientStream(promised_stream_.get())
+ ->id(),
+ promise_id_);
+
+ // The headers will be immediately available.
+ EXPECT_THAT(promised_stream_->ReadResponseHeaders(callback_.callback()),
+ IsOk());
+
+ // As will be the body.
+ EXPECT_EQ(
+ static_cast<int>(strlen(kResponseBody)),
+ promised_stream_->ReadResponseBody(
+ read_buffer_.get(), read_buffer_->size(), callback_.callback()));
+ EXPECT_TRUE(promised_stream_->IsResponseBodyComplete());
+ EXPECT_TRUE(AtEof());
+
+ EXPECT_EQ(0, stream_->GetTotalSentBytes());
+ EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
+ EXPECT_EQ(0, promised_stream_->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
+ strlen(kResponseBody)),
+ promised_stream_->GetTotalReceivedBytes());
+}
+
+TEST_P(QuicHttpStreamTest, ServerPushCrossOriginFail) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ Initialize();
+
+ // Initialize the first stream, for receiving the promise on.
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+
+ // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE
+ // packet, but does it matter?
+ push_promise_[":authority"] = "www.notexample.org";
+ promise_url_ = SpdyUtils::GetUrlFromHeaderBlock(push_promise_);
+ serialized_push_promise_ =
+ SpdyUtils::SerializeUncompressedHeaders(push_promise_);
+
+ ReceivePromise(promise_id_);
+ // The promise will have been rejected because the cert doesn't
+ // match.
+ EXPECT_EQ(session_->GetPromisedByUrl(promise_url_), nullptr);
+}
+
+TEST_P(QuicHttpStreamTest, ServerPushVaryCheckOK) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ Initialize();
+
+ // Initialize the first stream, for receiving the promise on.
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+
+ push_promise_["accept-encoding"] = "gzip";
+ serialized_push_promise_ =
+ SpdyUtils::SerializeUncompressedHeaders(push_promise_);
+
+ // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE
+ // packet, but does it matter?
+ ReceivePromise(promise_id_);
+ EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
+
+ request_.url = GURL(promise_url_);
+
+ // 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()));
+
+ headers_.SetHeader("accept-encoding", "gzip");
+
+ // Now sending a matching request will rendezvous with the promised
+ // stream, but pending secondary validation.
+ EXPECT_EQ(ERR_IO_PENDING, promised_stream_->SendRequest(
+ headers_, &response_, callback_.callback()));
+
+ // Receive the promised response headers.
+ promised_response_["vary"] = "accept-encoding";
+ response_headers_ = promised_response_.Clone();
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(InnerConstructResponseHeadersPacket(
+ 1, promise_id_, false, &spdy_response_headers_frame_length));
+
+ // Receive the promised response body.
+ const char kResponseBody[] = "Hello world!";
+ ProcessPacket(InnerConstructDataPacket(2, promise_id_, false, kFin, 0,
+ kResponseBody, &server_maker_));
+
+ base::RunLoop().RunUntilIdle();
+
+ // Rendezvous should have succeeded now, so the promised stream
+ // should point at our push stream, and we should be able read
+ // headers and data from it.
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+
+ EXPECT_EQ(
+ QuicHttpStreamPeer::GetQuicChromiumClientStream(promised_stream_.get())
+ ->id(),
+ promise_id_);
+
+ EXPECT_THAT(promised_stream_->ReadResponseHeaders(callback_.callback()),
+ IsOk());
+
+ EXPECT_EQ(
+ static_cast<int>(strlen(kResponseBody)),
+ promised_stream_->ReadResponseBody(
+ read_buffer_.get(), read_buffer_->size(), callback_.callback()));
+
+ // Callback should return
+ EXPECT_TRUE(promised_stream_->IsResponseBodyComplete());
+ EXPECT_TRUE(AtEof());
+
+ EXPECT_EQ(0, stream_->GetTotalSentBytes());
+ EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
+ EXPECT_EQ(0, promised_stream_->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
+ strlen(kResponseBody)),
+ promised_stream_->GetTotalReceivedBytes());
+}
+
+TEST_P(QuicHttpStreamTest, ServerPushVaryCheckFail) {
+ SetRequest("GET", "/", DEFAULT_PRIORITY);
+ request_headers_[":scheme"] = "https";
+ request_headers_[":path"] = "/bar";
+ request_headers_["accept-encoding"] = "sdch";
+
+ size_t spdy_request_header_frame_length;
+ AddWrite(ConstructClientRstStreamVaryMismatchPacket(1));
+ AddWrite(InnerConstructRequestHeadersPacket(
+ 2, stream_id_ + 2, !kIncludeVersion, kFin, DEFAULT_PRIORITY,
+ &spdy_request_header_frame_length, /*offset=*/nullptr));
+ AddWrite(ConstructClientAckPacket(3, 3, 1));
+ AddWrite(ConstructClientRstStreamCancelledPacket(4));
+ Initialize();
+
+ // Initialize the first stream, for receiving the promise on.
+ request_.method = "GET";
+ request_.url = GURL("http://www.example.org/");
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+
+ push_promise_["accept-encoding"] = "gzip";
+ serialized_push_promise_ =
+ SpdyUtils::SerializeUncompressedHeaders(push_promise_);
+
+ // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE
+ // packet, but does it matter?
+ ReceivePromise(promise_id_);
+ EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
+
+ request_.url = GURL(promise_url_);
+
+ // 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()));
+
+ headers_.SetHeader("accept-encoding", "sdch");
+
+ // Now sending a matching request will rendezvous with the promised
+ // stream, but pending secondary validation.
+ EXPECT_EQ(ERR_IO_PENDING, promised_stream_->SendRequest(
+ headers_, &response_, callback_.callback()));
+
+ // Receive the promised response headers.
+ promised_response_["vary"] = "accept-encoding";
+ response_headers_ = promised_response_.Clone();
+ size_t spdy_response_headers_frame_length;
+ ProcessPacket(InnerConstructResponseHeadersPacket(
+ 1, promise_id_, false, &spdy_response_headers_frame_length));
+
+ base::RunLoop().RunUntilIdle();
+
+ // Rendezvous should have failed due to vary mismatch, so the
+ // promised stream should have been aborted, and instead we have a
+ // new, regular client initiated stream.
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+
+ // Not a server-initiated stream.
+ EXPECT_NE(
+ QuicHttpStreamPeer::GetQuicChromiumClientStream(promised_stream_.get())
+ ->id(),
+ promise_id_);
+
+ // Instead, a new client-initiated stream.
+ EXPECT_EQ(
+ QuicHttpStreamPeer::GetQuicChromiumClientStream(promised_stream_.get())
+ ->id(),
+ stream_id_ + 2);
+
+ // After rendezvous failure, the push stream has been cancelled.
+ EXPECT_EQ(session_->GetPromisedByUrl(promise_url_), nullptr);
+
+ // The rest of the test verifies that the retried as
+ // client-initiated version of |promised_stream_| works as intended.
+
+ // Ack the request.
+ ProcessPacket(ConstructServerAckPacket(2, 0, 0));
+
+ SetResponse("404 Not Found", string());
+ size_t spdy_response_header_frame_length;
+ ProcessPacket(InnerConstructResponseHeadersPacket(
+ 3, stream_id_ + 2, kFin, &spdy_response_header_frame_length));
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_THAT(promised_stream_->ReadResponseHeaders(callback_.callback()),
+ IsOk());
+ ASSERT_TRUE(response_.headers.get());
+ EXPECT_EQ(404, response_.headers->response_code());
+ EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
+ EXPECT_FALSE(response_.response_time.is_null());
+ EXPECT_FALSE(response_.request_time.is_null());
+
+ // There is no body, so this should return immediately.
+ EXPECT_EQ(
+ 0, promised_stream_->ReadResponseBody(
+ read_buffer_.get(), read_buffer_->size(), callback_.callback()));
+ EXPECT_TRUE(promised_stream_->IsResponseBodyComplete());
+
+ stream_->Close(true);
+
+ EXPECT_TRUE(AtEof());
+
+ // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
+ // headers and payload.
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_header_frame_length),
+ promised_stream_->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(spdy_response_header_frame_length),
+ promised_stream_->GetTotalReceivedBytes());
+}
+
+TEST_P(QuicHttpStreamTest, DataReadErrorSynchronous) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructClientRstStreamErrorPacket(2, kIncludeVersion));
+
+ Initialize();
+
+ ReadErrorUploadDataStream upload_data_stream(
+ ReadErrorUploadDataStream::FailureMode::SYNC);
+ request_.method = "POST";
+ request_.url = GURL("http://www.example.org/");
+ request_.upload_data_stream = &upload_data_stream;
+ ASSERT_EQ(OK, request_.upload_data_stream->Init(
+ TestCompletionCallback().callback(), NetLogWithSource()));
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+
+ int result = stream_->SendRequest(headers_, &response_, callback_.callback());
+ EXPECT_THAT(result, IsError(ERR_FAILED));
+
+ EXPECT_TRUE(AtEof());
+
+ // QuicHttpStream::GetTotalSent/ReceivedBytes includes only headers.
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
+ stream_->GetTotalSentBytes());
+ EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
+}
+
+TEST_P(QuicHttpStreamTest, DataReadErrorAsynchronous) {
+ SetRequest("POST", "/", DEFAULT_PRIORITY);
+ size_t spdy_request_headers_frame_length;
+ AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+ &spdy_request_headers_frame_length));
+ AddWrite(ConstructClientRstStreamErrorPacket(2, !kIncludeVersion));
+
+ Initialize();
+
+ ReadErrorUploadDataStream upload_data_stream(
+ ReadErrorUploadDataStream::FailureMode::ASYNC);
+ request_.method = "POST";
+ request_.url = GURL("http://www.example.org/");
+ request_.upload_data_stream = &upload_data_stream;
+ ASSERT_EQ(OK, request_.upload_data_stream->Init(
+ TestCompletionCallback().callback(), NetLogWithSource()));
+
+ EXPECT_EQ(OK,
+ stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+ net_log_.bound(), callback_.callback()));
+
+ int result = stream_->SendRequest(headers_, &response_, callback_.callback());
+
+ ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+ SetResponse("200 OK", string());
+
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback_.GetResult(result), IsError(ERR_FAILED));
+
+ EXPECT_TRUE(AtEof());
+
+ // QuicHttpStream::GetTotalSent/ReceivedBytes includes only headers.
+ EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
+ stream_->GetTotalSentBytes());
+ EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_network_transaction_unittest.cc b/chromium/net/quic/chromium/quic_network_transaction_unittest.cc
new file mode 100644
index 00000000000..fa6499b9e65
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_network_transaction_unittest.cc
@@ -0,0 +1,3283 @@
+// 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 <memory>
+#include <ostream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/histogram_tester.h"
+#include "net/base/chunked_upload_data_stream.h"
+#include "net/base/test_completion_callback.h"
+#include "net/base/test_proxy_delegate.h"
+#include "net/cert/ct_policy_enforcer.h"
+#include "net/cert/mock_cert_verifier.h"
+#include "net/cert/multi_log_ct_verifier.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_network_transaction.h"
+#include "net/http/http_server_properties_impl.h"
+#include "net/http/http_stream.h"
+#include "net/http/http_stream_factory.h"
+#include "net/http/http_transaction_test_util.h"
+#include "net/http/transport_security_state.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/proxy/proxy_config_service_fixed.h"
+#include "net/proxy/proxy_resolver.h"
+#include "net/proxy/proxy_service.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/chromium/mock_network_change_notifier.h"
+#include "net/quic/chromium/mock_quic_data.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_http_utils.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
+#include "net/quic/test_tools/mock_random.h"
+#include "net/quic/test_tools/quic_test_packet_maker.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/socket/client_socket_factory.h"
+#include "net/socket/mock_client_socket_pool_manager.h"
+#include "net/socket/socket_performance_watcher.h"
+#include "net/socket/socket_performance_watcher_factory.h"
+#include "net/socket/socket_test_util.h"
+#include "net/socket/ssl_client_socket.h"
+#include "net/spdy/spdy_frame_builder.h"
+#include "net/spdy/spdy_framer.h"
+#include "net/ssl/ssl_config_service_defaults.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
+#include "net/test/test_data_directory.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_job_factory_impl.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#include "url/gurl.h"
+
+using net::test::IsError;
+using net::test::IsOk;
+
+namespace net {
+namespace test {
+
+namespace {
+
+enum DestinationType {
+ // In pooling tests with two requests for different origins to the same
+ // destination, the destination should be
+ SAME_AS_FIRST, // the same as the first origin,
+ SAME_AS_SECOND, // the same as the second origin, or
+ DIFFERENT, // different from both.
+};
+
+static const char kQuicAlternativeServiceHeader[] =
+ "Alt-Svc: quic=\":443\"\r\n\r\n";
+static const char kQuicAlternativeServiceWithProbabilityHeader[] =
+ "Alt-Svc: quic=\":443\";p=\".5\"\r\n\r\n";
+static const char kQuicAlternativeServiceDifferentPortHeader[] =
+ "Alt-Svc: quic=\":137\"\r\n\r\n";
+
+const char kDefaultServerHostName[] = "mail.example.org";
+const char kDifferentHostname[] = "different.example.com";
+
+// Run QuicNetworkTransactionWithDestinationTest instances with all value
+// combinations of version and destination_type.
+struct PoolingTestParams {
+ friend std::ostream& operator<<(std::ostream& os,
+ const PoolingTestParams& p) {
+ os << "{ version: " << QuicVersionToString(p.version)
+ << ", destination_type: ";
+ switch (p.destination_type) {
+ case SAME_AS_FIRST:
+ os << "SAME_AS_FIRST";
+ break;
+ case SAME_AS_SECOND:
+ os << "SAME_AS_SECOND";
+ break;
+ case DIFFERENT:
+ os << "DIFFERENT";
+ break;
+ }
+ os << " }";
+ return os;
+ }
+
+ QuicVersion version;
+ DestinationType destination_type;
+};
+
+std::vector<PoolingTestParams> GetPoolingTestParams() {
+ std::vector<PoolingTestParams> params;
+ QuicVersionVector all_supported_versions = AllSupportedVersions();
+ for (const QuicVersion 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});
+ }
+ return params;
+}
+
+} // namespace
+
+class HeadersHandler {
+ public:
+ HeadersHandler() : was_proxied_(false) {}
+
+ bool was_proxied() { return was_proxied_; }
+
+ void OnBeforeHeadersSent(const ProxyInfo& proxy_info,
+ HttpRequestHeaders* request_headers) {
+ if (!proxy_info.is_http() && !proxy_info.is_https() &&
+ !proxy_info.is_quic()) {
+ return;
+ }
+ was_proxied_ = true;
+ }
+
+ private:
+ bool was_proxied_;
+};
+
+class TestSocketPerformanceWatcher : public SocketPerformanceWatcher {
+ public:
+ explicit TestSocketPerformanceWatcher(bool* rtt_notification_received)
+ : rtt_notification_received_(rtt_notification_received) {}
+ ~TestSocketPerformanceWatcher() override {}
+
+ bool ShouldNotifyUpdatedRTT() const override { return true; }
+
+ void OnUpdatedRTTAvailable(const base::TimeDelta& rtt) override {
+ *rtt_notification_received_ = true;
+ }
+
+ void OnConnectionChanged() override {}
+
+ private:
+ bool* rtt_notification_received_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestSocketPerformanceWatcher);
+};
+
+class TestSocketPerformanceWatcherFactory
+ : public SocketPerformanceWatcherFactory {
+ public:
+ TestSocketPerformanceWatcherFactory()
+ : watcher_count_(0u), rtt_notification_received_(false) {}
+ ~TestSocketPerformanceWatcherFactory() override {}
+
+ // SocketPerformanceWatcherFactory implementation:
+ std::unique_ptr<SocketPerformanceWatcher> CreateSocketPerformanceWatcher(
+ const Protocol protocol) override {
+ if (protocol != PROTOCOL_QUIC) {
+ return nullptr;
+ }
+ ++watcher_count_;
+ return std::unique_ptr<SocketPerformanceWatcher>(
+ new TestSocketPerformanceWatcher(&rtt_notification_received_));
+ }
+
+ size_t watcher_count() const { return watcher_count_; }
+
+ bool rtt_notification_received() const { return rtt_notification_received_; }
+
+ private:
+ size_t watcher_count_;
+ bool rtt_notification_received_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestSocketPerformanceWatcherFactory);
+};
+
+class QuicNetworkTransactionTest
+ : public PlatformTest,
+ public ::testing::WithParamInterface<QuicVersion> {
+ protected:
+ QuicNetworkTransactionTest()
+ : clock_(new MockClock),
+ client_maker_(GetParam(),
+ 0,
+ clock_,
+ kDefaultServerHostName,
+ Perspective::IS_CLIENT),
+ server_maker_(GetParam(),
+ 0,
+ clock_,
+ kDefaultServerHostName,
+ Perspective::IS_SERVER),
+ cert_transparency_verifier_(new MultiLogCTVerifier()),
+ ssl_config_service_(new SSLConfigServiceDefaults),
+ proxy_service_(ProxyService::CreateDirect()),
+ auth_handler_factory_(
+ HttpAuthHandlerFactory::CreateDefault(&host_resolver_)),
+ random_generator_(0),
+ ssl_data_(ASYNC, OK) {
+ request_.method = "GET";
+ std::string url("https://");
+ url.append(kDefaultServerHostName);
+ request_.url = GURL(url);
+ request_.load_flags = 0;
+ clock_->AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
+
+ scoped_refptr<X509Certificate> cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
+ 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_);
+ }
+
+ void SetUp() override {
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void TearDown() override {
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
+ // Empty the current queue.
+ base::RunLoop().RunUntilIdle();
+ PlatformTest::TearDown();
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
+ base::RunLoop().RunUntilIdle();
+ session_.reset();
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructClientConnectionClosePacket(
+ QuicPacketNumber num) {
+ return client_maker_.MakeConnectionClosePacket(num);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructServerConnectionClosePacket(
+ QuicPacketNumber num) {
+ return server_maker_.MakeConnectionClosePacket(num);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructServerGoAwayPacket(
+ QuicPacketNumber num,
+ QuicErrorCode error_code,
+ std::string reason_phrase) {
+ return server_maker_.MakeGoAwayPacket(num, error_code, reason_phrase);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructClientAckPacket(
+ QuicPacketNumber largest_received,
+ QuicPacketNumber least_unacked) {
+ return client_maker_.MakeAckPacket(2, largest_received, least_unacked,
+ least_unacked, true);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructClientAckPacket(
+ QuicPacketNumber packet_number,
+ QuicPacketNumber largest_received,
+ QuicPacketNumber ack_least_unacked,
+ QuicPacketNumber stop_least_unacked) {
+ return client_maker_.MakeAckPacket(packet_number, largest_received,
+ ack_least_unacked, stop_least_unacked,
+ true);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructClientAckAndRstPacket(
+ QuicPacketNumber num,
+ QuicStreamId stream_id,
+ QuicRstStreamErrorCode error_code,
+ QuicPacketNumber largest_received,
+ QuicPacketNumber ack_least_unacked,
+ QuicPacketNumber stop_least_unacked) {
+ return client_maker_.MakeAckAndRstPacket(
+ num, false, stream_id, error_code, largest_received, ack_least_unacked,
+ stop_least_unacked, true);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket>
+ ConstructClientAckAndConnectionClosePacket(
+ QuicPacketNumber packet_number,
+ QuicPacketNumber largest_received,
+ QuicPacketNumber ack_least_unacked,
+ QuicPacketNumber stop_least_unacked) {
+ return client_maker_.MakeAckPacket(packet_number, largest_received,
+ ack_least_unacked, stop_least_unacked,
+ true);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket>
+ ConstructClientAckAndConnectionClosePacket(
+ QuicPacketNumber num,
+ QuicTime::Delta delta_time_largest_observed,
+ QuicPacketNumber largest_received,
+ QuicPacketNumber least_unacked,
+ QuicErrorCode quic_error,
+ const std::string& quic_error_details) {
+ return client_maker_.MakeAckAndConnectionClosePacket(
+ num, false, delta_time_largest_observed, largest_received,
+ least_unacked, quic_error, quic_error_details);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructServerRstPacket(
+ QuicPacketNumber num,
+ bool include_version,
+ QuicStreamId stream_id,
+ QuicRstStreamErrorCode error_code) {
+ return server_maker_.MakeRstPacket(num, include_version, stream_id,
+ error_code);
+ }
+
+ // Uses default QuicTestPacketMaker.
+ SpdyHeaderBlock GetRequestHeaders(const std::string& method,
+ const std::string& scheme,
+ const std::string& path) {
+ return GetRequestHeaders(method, scheme, path, &client_maker_);
+ }
+
+ // Uses customized QuicTestPacketMaker.
+ SpdyHeaderBlock GetRequestHeaders(const std::string& method,
+ const std::string& scheme,
+ const std::string& path,
+ QuicTestPacketMaker* maker) {
+ return maker->GetRequestHeaders(method, scheme, path);
+ }
+
+ SpdyHeaderBlock GetResponseHeaders(const std::string& status) {
+ return server_maker_.GetResponseHeaders(status);
+ }
+
+ // Appends alt_svc headers in the response headers.
+ SpdyHeaderBlock GetResponseHeaders(const std::string& status,
+ const std::string& alt_svc) {
+ return server_maker_.GetResponseHeaders(status, alt_svc);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructServerDataPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool should_include_version,
+ bool fin,
+ QuicStreamOffset offset,
+ base::StringPiece data) {
+ return server_maker_.MakeDataPacket(
+ packet_number, stream_id, should_include_version, fin, offset, data);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructClientDataPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool should_include_version,
+ bool fin,
+ QuicStreamOffset offset,
+ base::StringPiece data) {
+ return client_maker_.MakeDataPacket(
+ packet_number, stream_id, should_include_version, fin, offset, data);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructClientForceHolDataPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool should_include_version,
+ bool fin,
+ QuicStreamOffset* offset,
+ base::StringPiece data) {
+ return client_maker_.MakeForceHolDataPacket(
+ packet_number, stream_id, should_include_version, fin, offset, data);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool should_include_version,
+ bool fin,
+ SpdyHeaderBlock headers,
+ 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::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool should_include_version,
+ bool fin,
+ SpdyHeaderBlock headers) {
+ return ConstructClientRequestHeadersPacket(packet_number, stream_id,
+ should_include_version, fin,
+ std::move(headers), nullptr);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructServerPushPromisePacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ QuicStreamId promised_stream_id,
+ bool should_include_version,
+ SpdyHeaderBlock headers,
+ QuicStreamOffset* offset,
+ QuicTestPacketMaker* maker) {
+ return maker->MakePushPromisePacket(
+ packet_number, stream_id, promised_stream_id, should_include_version,
+ false, std::move(headers), nullptr, offset);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructServerResponseHeadersPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool should_include_version,
+ bool fin,
+ SpdyHeaderBlock headers) {
+ return ConstructServerResponseHeadersPacket(packet_number, stream_id,
+ should_include_version, fin,
+ std::move(headers), nullptr);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructServerResponseHeadersPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool should_include_version,
+ bool fin,
+ SpdyHeaderBlock headers,
+ QuicStreamOffset* offset) {
+ return server_maker_.MakeResponseHeadersPacketWithOffsetTracking(
+ packet_number, stream_id, should_include_version, fin,
+ std::move(headers), offset);
+ }
+
+ void CreateSession() {
+ params_.enable_quic = true;
+ params_.quic_clock = clock_;
+ params_.quic_random = &random_generator_;
+ params_.client_socket_factory = &socket_factory_;
+ params_.quic_crypto_client_stream_factory = &crypto_client_stream_factory_;
+ params_.host_resolver = &host_resolver_;
+ params_.cert_verifier = &cert_verifier_;
+ params_.transport_security_state = &transport_security_state_;
+ params_.cert_transparency_verifier = cert_transparency_verifier_.get();
+ params_.ct_policy_enforcer = &ct_policy_enforcer_;
+ params_.socket_performance_watcher_factory =
+ &test_socket_performance_watcher_factory_;
+ params_.proxy_service = proxy_service_.get();
+ params_.ssl_config_service = ssl_config_service_.get();
+ params_.http_auth_handler_factory = auth_handler_factory_.get();
+ params_.http_server_properties = &http_server_properties_;
+ params_.quic_supported_versions = SupportedVersions(GetParam());
+ for (const char* host :
+ {kDefaultServerHostName, "www.example.org", "news.example.org",
+ "bar.example.org", "foo.example.org", "invalid.example.org",
+ "mail.example.com"}) {
+ params_.quic_host_whitelist.insert(host);
+ }
+
+ session_.reset(new HttpNetworkSession(params_));
+ session_->quic_stream_factory()->set_require_confirmation(false);
+ ASSERT_EQ(params_.quic_socket_receive_buffer_size,
+ session_->quic_stream_factory()->socket_receive_buffer_size());
+ }
+
+ void CheckWasQuicResponse(HttpNetworkTransaction* trans) {
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_TRUE(response != nullptr);
+ ASSERT_TRUE(response->headers.get() != nullptr);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+ EXPECT_TRUE(response->was_fetched_via_spdy);
+ EXPECT_TRUE(response->was_alpn_negotiated);
+ EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_QUIC1_SPDY3,
+ response->connection_info);
+ }
+
+ void CheckResponsePort(HttpNetworkTransaction* trans, uint16_t port) {
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_TRUE(response != nullptr);
+ EXPECT_EQ(port, response->socket_address.port());
+ }
+
+ void CheckWasHttpResponse(HttpNetworkTransaction* trans) {
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_TRUE(response != nullptr);
+ ASSERT_TRUE(response->headers.get() != nullptr);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+ EXPECT_FALSE(response->was_fetched_via_spdy);
+ EXPECT_FALSE(response->was_alpn_negotiated);
+ EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
+ response->connection_info);
+ }
+
+ void CheckResponseData(HttpNetworkTransaction* trans,
+ const std::string& expected) {
+ std::string response_data;
+ ASSERT_THAT(ReadTransaction(trans, &response_data), IsOk());
+ EXPECT_EQ(expected, response_data);
+ }
+
+ void RunTransaction(HttpNetworkTransaction* trans) {
+ TestCompletionCallback callback;
+ int rv = trans->Start(&request_, callback.callback(), net_log_.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
+ }
+
+ void SendRequestAndExpectHttpResponse(const std::string& expected) {
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ RunTransaction(&trans);
+ CheckWasHttpResponse(&trans);
+ CheckResponseData(&trans, expected);
+ }
+
+ void SendRequestAndExpectHttpResponseFromProxy(const std::string& expected,
+ bool used_proxy,
+ uint16_t port) {
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ HeadersHandler headers_handler;
+ trans.SetBeforeHeadersSentCallback(
+ base::Bind(&HeadersHandler::OnBeforeHeadersSent,
+ base::Unretained(&headers_handler)));
+ RunTransaction(&trans);
+ CheckWasHttpResponse(&trans);
+ CheckResponsePort(&trans, port);
+ CheckResponseData(&trans, expected);
+ EXPECT_EQ(used_proxy, headers_handler.was_proxied());
+ if (used_proxy) {
+ EXPECT_TRUE(trans.GetResponseInfo()->proxy_server.is_https());
+ } else {
+ EXPECT_TRUE(trans.GetResponseInfo()->proxy_server.is_direct());
+ }
+ }
+
+ void SendRequestAndExpectQuicResponse(const std::string& expected) {
+ SendRequestAndExpectQuicResponseMaybeFromProxy(expected, false, 443);
+ }
+
+ void SendRequestAndExpectQuicResponseFromProxyOnPort(
+ const std::string& expected,
+ uint16_t port) {
+ SendRequestAndExpectQuicResponseMaybeFromProxy(expected, true, port);
+ }
+
+ void AddQuicAlternateProtocolMapping(
+ MockCryptoClientStream::HandshakeMode handshake_mode) {
+ crypto_client_stream_factory_.set_handshake_mode(handshake_mode);
+ url::SchemeHostPort server(request_.url);
+ AlternativeService alternative_service(QUIC, server.host(), 443);
+ base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
+ http_server_properties_.SetAlternativeService(server, alternative_service,
+ expiration);
+ }
+
+ void AddQuicRemoteAlternativeServiceMapping(
+ MockCryptoClientStream::HandshakeMode handshake_mode,
+ const HostPortPair& alternative) {
+ crypto_client_stream_factory_.set_handshake_mode(handshake_mode);
+ url::SchemeHostPort server(request_.url);
+ AlternativeService alternative_service(QUIC, alternative.host(),
+ alternative.port());
+ base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
+ http_server_properties_.SetAlternativeService(server, alternative_service,
+ expiration);
+ }
+
+ void ExpectBrokenAlternateProtocolMapping() {
+ const url::SchemeHostPort server(request_.url);
+ const AlternativeServiceVector alternative_service_vector =
+ http_server_properties_.GetAlternativeServices(server);
+ EXPECT_EQ(1u, alternative_service_vector.size());
+ EXPECT_TRUE(http_server_properties_.IsAlternativeServiceBroken(
+ alternative_service_vector[0]));
+ }
+
+ void ExpectQuicAlternateProtocolMapping() {
+ const url::SchemeHostPort server(request_.url);
+ const AlternativeServiceVector alternative_service_vector =
+ http_server_properties_.GetAlternativeServices(server);
+ EXPECT_EQ(1u, alternative_service_vector.size());
+ EXPECT_EQ(QUIC, alternative_service_vector[0].protocol);
+ }
+
+ void AddHangingNonAlternateProtocolSocketData() {
+ std::unique_ptr<StaticSocketDataProvider> hanging_data;
+ hanging_data.reset(new StaticSocketDataProvider());
+ MockConnect hanging_connect(SYNCHRONOUS, ERR_IO_PENDING);
+ hanging_data->set_connect_data(hanging_connect);
+ hanging_data_.push_back(std::move(hanging_data));
+ socket_factory_.AddSocketDataProvider(hanging_data_.back().get());
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+ }
+
+ // Fetches two non-cryptographic URL requests via a HTTPS proxy with a QUIC
+ // alternative proxy. Verifies that if the alternative proxy job returns
+ // |error_code|, the request is fetched successfully by the main job.
+ void TestAlternativeProxy(int error_code) {
+ // Use a non-cryptographic scheme for the request URL since this request
+ // will be fetched via proxy with QUIC as the alternative service.
+ request_.url = GURL("http://example.org/");
+ // Data for the alternative proxy server job.
+ MockWrite quic_writes[] = {MockWrite(SYNCHRONOUS, error_code, 1)};
+ MockRead quic_reads[] = {
+ MockRead(SYNCHRONOUS, error_code, 0),
+ };
+
+ SequencedSocketData quic_data(quic_reads, arraysize(quic_reads),
+ quic_writes, arraysize(quic_writes));
+ socket_factory_.AddSocketDataProvider(&quic_data);
+
+ // Main job succeeds and the alternative job fails.
+ // Add data for two requests that will be read by the main job.
+ MockRead http_reads_1[] = {
+ MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello from http"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ MockRead http_reads_2[] = {
+ MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello from http"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data_1(http_reads_1, arraysize(http_reads_1),
+ nullptr, 0);
+ StaticSocketDataProvider http_data_2(http_reads_2, arraysize(http_reads_2),
+ nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&http_data_1);
+ socket_factory_.AddSocketDataProvider(&http_data_2);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ TestProxyDelegate test_proxy_delegate;
+ // Proxy URL is different from the request URL.
+ test_proxy_delegate.set_alternative_proxy_server(
+ ProxyServer::FromPacString("QUIC myproxy.org:443"));
+
+ params_.proxy_delegate = &test_proxy_delegate;
+ proxy_service_ =
+ ProxyService::CreateFixedFromPacResult("HTTPS myproxy.org:443");
+
+ CreateSession();
+ EXPECT_TRUE(test_proxy_delegate.alternative_proxy_server().is_valid());
+
+ // The first request should be fetched via the HTTPS proxy.
+ SendRequestAndExpectHttpResponseFromProxy("hello from http", true, 443);
+
+ // Even through the alternative proxy server job failed, the proxy should
+ // not be marked as bad since the main job succeeded.
+ EXPECT_TRUE(session_->proxy_service()->proxy_retry_info().empty());
+
+ // The alternative proxy server should no longer be in use.
+ EXPECT_FALSE(test_proxy_delegate.alternative_proxy_server().is_valid());
+
+ // Verify that the second request completes successfully, and the
+ // alternative proxy server job is not started.
+ SendRequestAndExpectHttpResponseFromProxy("hello from http", true, 443);
+ }
+
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+ MockClock* clock_; // Owned by QuicStreamFactory after CreateSession.
+ QuicTestPacketMaker client_maker_;
+ QuicTestPacketMaker server_maker_;
+ std::unique_ptr<HttpNetworkSession> session_;
+ MockClientSocketFactory socket_factory_;
+ ProofVerifyDetailsChromium verify_details_;
+ MockCryptoClientStreamFactory crypto_client_stream_factory_;
+ MockHostResolver host_resolver_;
+ MockCertVerifier cert_verifier_;
+ TransportSecurityState transport_security_state_;
+ std::unique_ptr<CTVerifier> cert_transparency_verifier_;
+ CTPolicyEnforcer ct_policy_enforcer_;
+ TestSocketPerformanceWatcherFactory test_socket_performance_watcher_factory_;
+ scoped_refptr<SSLConfigServiceDefaults> ssl_config_service_;
+ std::unique_ptr<ProxyService> proxy_service_;
+ std::unique_ptr<HttpAuthHandlerFactory> auth_handler_factory_;
+ MockRandom random_generator_;
+ HttpServerPropertiesImpl http_server_properties_;
+ HttpNetworkSession::Params params_;
+ HttpRequestInfo request_;
+ BoundTestNetLog net_log_;
+ std::vector<std::unique_ptr<StaticSocketDataProvider>> hanging_data_;
+ SSLSocketDataProvider ssl_data_;
+
+ private:
+ void SendRequestAndExpectQuicResponseMaybeFromProxy(
+ const std::string& expected,
+ bool used_proxy,
+ uint16_t port) {
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ HeadersHandler headers_handler;
+ trans.SetBeforeHeadersSentCallback(
+ base::Bind(&HeadersHandler::OnBeforeHeadersSent,
+ base::Unretained(&headers_handler)));
+ RunTransaction(&trans);
+ CheckWasQuicResponse(&trans);
+ CheckResponsePort(&trans, port);
+ CheckResponseData(&trans, expected);
+ EXPECT_EQ(used_proxy, headers_handler.was_proxied());
+ if (used_proxy) {
+ EXPECT_TRUE(trans.GetResponseInfo()->proxy_server.is_quic());
+ } else {
+ EXPECT_TRUE(trans.GetResponseInfo()->proxy_server.is_direct());
+ }
+ }
+};
+
+INSTANTIATE_TEST_CASE_P(Version,
+ QuicNetworkTransactionTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
+
+TEST_P(QuicNetworkTransactionTest, ForceQuic) {
+ params_.origins_to_force_quic_on.insert(
+ HostPortPair::FromString("mail.example.org:443"));
+
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+ mock_quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // No more data to read
+
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ CreateSession();
+
+ EXPECT_FALSE(
+ test_socket_performance_watcher_factory_.rtt_notification_received());
+ SendRequestAndExpectQuicResponse("hello!");
+ EXPECT_TRUE(
+ test_socket_performance_watcher_factory_.rtt_notification_received());
+
+ // Check that the NetLog was filled reasonably.
+ TestNetLogEntry::List entries;
+ net_log_.GetEntries(&entries);
+ EXPECT_LT(0u, entries.size());
+
+ // Check that we logged a QUIC_SESSION_PACKET_RECEIVED.
+ int pos = ExpectLogContainsSomewhere(
+ entries, 0, NetLogEventType::QUIC_SESSION_PACKET_RECEIVED,
+ NetLogEventPhase::NONE);
+ EXPECT_LT(0, pos);
+
+ // ... and also a TYPE_QUIC_SESSION_UNAUTHENTICATED_PACKET_HEADER_RECEIVED.
+ pos = ExpectLogContainsSomewhere(
+ entries, 0,
+ NetLogEventType::QUIC_SESSION_UNAUTHENTICATED_PACKET_HEADER_RECEIVED,
+ NetLogEventPhase::NONE);
+ EXPECT_LT(0, pos);
+
+ std::string packet_number;
+ ASSERT_TRUE(entries[pos].GetStringValue("packet_number", &packet_number));
+ EXPECT_EQ("1", packet_number);
+
+ // ... and also a TYPE_QUIC_SESSION_PACKET_AUTHENTICATED.
+ pos = ExpectLogContainsSomewhere(
+ entries, 0, NetLogEventType::QUIC_SESSION_PACKET_AUTHENTICATED,
+ NetLogEventPhase::NONE);
+ EXPECT_LT(0, pos);
+
+ // ... and also a QUIC_SESSION_STREAM_FRAME_RECEIVED.
+ pos = ExpectLogContainsSomewhere(
+ entries, 0, NetLogEventType::QUIC_SESSION_STREAM_FRAME_RECEIVED,
+ NetLogEventPhase::NONE);
+ EXPECT_LT(0, pos);
+
+ int log_stream_id;
+ ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &log_stream_id));
+ EXPECT_EQ(3, log_stream_id);
+}
+
+TEST_P(QuicNetworkTransactionTest, ForceQuicForAll) {
+ params_.origins_to_force_quic_on.insert(HostPortPair());
+
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::CONFIRM_HANDSHAKE);
+
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+ mock_quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // No more data to read
+
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ CreateSession();
+
+ SendRequestAndExpectQuicResponse("hello!");
+ EXPECT_TRUE(
+ test_socket_performance_watcher_factory_.rtt_notification_received());
+}
+
+TEST_P(QuicNetworkTransactionTest, QuicProxy) {
+ params_.enable_quic = true;
+ proxy_service_ =
+ ProxyService::CreateFixedFromPacResult("QUIC mail.example.org:70");
+
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "http", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 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_);
+
+ EXPECT_FALSE(
+ test_socket_performance_watcher_factory_.rtt_notification_received());
+ // There is no need to set up an alternate protocol job, because
+ // no attempt will be made to speak to the proxy over TCP.
+
+ request_.url = GURL("http://mail.example.org/");
+ CreateSession();
+
+ SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 70);
+ EXPECT_TRUE(
+ test_socket_performance_watcher_factory_.rtt_notification_received());
+}
+
+// Regression test for https://crbug.com/492458. Test that for an HTTP
+// connection through a QUIC proxy, the certificate exhibited by the proxy is
+// checked against the proxy hostname, not the origin hostname.
+TEST_P(QuicNetworkTransactionTest, QuicProxyWithCert) {
+ const std::string origin_host = "mail.example.com";
+ const std::string proxy_host = "www.example.org";
+
+ params_.enable_quic = true;
+ proxy_service_ =
+ ProxyService::CreateFixedFromPacResult("QUIC " + proxy_host + ":70");
+
+ client_maker_.set_hostname(origin_host);
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "http", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+ mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read
+ mock_quic_data.AddRead(ASYNC, 0);
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ scoped_refptr<X509Certificate> cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
+ ASSERT_TRUE(cert.get());
+ // This certificate is valid for the proxy, but not for the origin.
+ bool common_name_fallback_used;
+ EXPECT_TRUE(cert->VerifyNameMatch(proxy_host, &common_name_fallback_used));
+ EXPECT_FALSE(cert->VerifyNameMatch(origin_host, &common_name_fallback_used));
+ ProofVerifyDetailsChromium verify_details;
+ verify_details.cert_verify_result.verified_cert = cert;
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ ProofVerifyDetailsChromium verify_details2;
+ verify_details2.cert_verify_result.verified_cert = cert;
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2);
+
+ request_.url = GURL("http://" + origin_host);
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSession();
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::CONFIRM_HANDSHAKE);
+ SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 70);
+}
+
+TEST_P(QuicNetworkTransactionTest, AlternativeServicesDifferentHost) {
+ HostPortPair origin("www.example.org", 443);
+ HostPortPair alternative("mail.example.org", 443);
+
+ base::FilePath certs_dir = GetTestCertsDirectory();
+ scoped_refptr<X509Certificate> cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
+ ASSERT_TRUE(cert.get());
+ // TODO(rch): the connection should be "to" the origin, so if the cert is
+ // valid for the origin but not the alternative, that should work too.
+ bool common_name_fallback_used;
+ EXPECT_TRUE(cert->VerifyNameMatch(origin.host(), &common_name_fallback_used));
+ EXPECT_TRUE(
+ cert->VerifyNameMatch(alternative.host(), &common_name_fallback_used));
+ ProofVerifyDetailsChromium verify_details;
+ verify_details.cert_verify_result.verified_cert = cert;
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ client_maker_.set_hostname(origin.host());
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+ mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read
+ mock_quic_data.AddRead(ASYNC, 0);
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ request_.url = GURL("https://" + origin.host());
+ AddQuicRemoteAlternativeServiceMapping(
+ MockCryptoClientStream::CONFIRM_HANDSHAKE, alternative);
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSession();
+
+ SendRequestAndExpectQuicResponse("hello!");
+}
+
+TEST_P(QuicNetworkTransactionTest, ForceQuicWithErrorConnecting) {
+ params_.origins_to_force_quic_on.insert(
+ HostPortPair::FromString("mail.example.org:443"));
+
+ MockQuicData mock_quic_data1;
+ mock_quic_data1.AddRead(ASYNC, ERR_SOCKET_NOT_CONNECTED);
+
+ MockQuicData mock_quic_data2;
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details_);
+ mock_quic_data2.AddRead(ASYNC, ERR_SOCKET_NOT_CONNECTED);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details_);
+
+ mock_quic_data1.AddSocketDataToFactory(&socket_factory_);
+ mock_quic_data2.AddSocketDataToFactory(&socket_factory_);
+
+ CreateSession();
+
+ EXPECT_EQ(0U, test_socket_performance_watcher_factory_.watcher_count());
+ for (size_t i = 0; i < 2; ++i) {
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ TestCompletionCallback callback;
+ int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
+ EXPECT_EQ(1 + i, test_socket_performance_watcher_factory_.watcher_count());
+ }
+}
+
+TEST_P(QuicNetworkTransactionTest, DoNotForceQuicForHttps) {
+ // Attempt to "force" quic on 443, which will not be honored.
+ params_.origins_to_force_quic_on.insert(
+ HostPortPair::FromString("www.google.com:443"));
+
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello world"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider data(http_reads, arraysize(http_reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&data);
+ SSLSocketDataProvider ssl(ASYNC, OK);
+ socket_factory_.AddSSLSocketDataProvider(&ssl);
+
+ CreateSession();
+
+ SendRequestAndExpectHttpResponse("hello world");
+ EXPECT_EQ(0U, test_socket_performance_watcher_factory_.watcher_count());
+}
+
+TEST_P(QuicNetworkTransactionTest, UseAlternativeServiceForQuic) {
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"), MockRead(kQuicAlternativeServiceHeader),
+ MockRead("hello world"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 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_);
+
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSession();
+
+ SendRequestAndExpectHttpResponse("hello world");
+ SendRequestAndExpectQuicResponse("hello!");
+}
+
+TEST_P(QuicNetworkTransactionTest,
+ UseAlternativeServiceWithProbabilityForQuic) {
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead(kQuicAlternativeServiceWithProbabilityHeader),
+ MockRead("hello world"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 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_);
+
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSession();
+
+ SendRequestAndExpectHttpResponse("hello world");
+ SendRequestAndExpectQuicResponse("hello!");
+}
+
+TEST_P(QuicNetworkTransactionTest, SetAlternativeServiceWithScheme) {
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Alt-Svc: quic=\"foo.example.org:443\", quic=\":444\"\r\n\r\n"),
+ MockRead("hello world"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ CreateSession();
+ // Send https request, ignore alternative service advertising if response
+ // header advertises alternative service for mail.example.org.
+ request_.url = GURL("https://mail.example.org:443");
+ SendRequestAndExpectHttpResponse("hello world");
+ HttpServerProperties* http_server_properties =
+ session_->http_server_properties();
+ url::SchemeHostPort http_server("http", "mail.example.org", 443);
+ url::SchemeHostPort https_server("https", "mail.example.org", 443);
+ // Check alternative service is set for the correct origin.
+ EXPECT_EQ(
+ 2u, http_server_properties->GetAlternativeServices(https_server).size());
+ EXPECT_TRUE(
+ http_server_properties->GetAlternativeServices(http_server).empty());
+}
+
+TEST_P(QuicNetworkTransactionTest, DoNotGetAltSvcForDifferentOrigin) {
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Alt-Svc: quic=\"foo.example.org:443\", quic=\":444\"\r\n\r\n"),
+ MockRead("hello world"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ CreateSession();
+
+ // Send https request and set alternative services if response header
+ // advertises alternative service for mail.example.org.
+ SendRequestAndExpectHttpResponse("hello world");
+ HttpServerProperties* http_server_properties =
+ session_->http_server_properties();
+
+ const url::SchemeHostPort https_server(request_.url);
+ // Check alternative service is set.
+ AlternativeServiceVector alternative_service_vector =
+ http_server_properties->GetAlternativeServices(https_server);
+ EXPECT_EQ(2u, alternative_service_vector.size());
+
+ // Send http request to the same origin but with diffrent scheme, should not
+ // use QUIC.
+ request_.url = GURL("http://mail.example.org:443");
+ SendRequestAndExpectHttpResponse("hello world");
+}
+
+TEST_P(QuicNetworkTransactionTest, UseAlternativeServiceAllSupportedVersion) {
+ std::string altsvc_header = base::StringPrintf(
+ "Alt-Svc: quic=\":443\"; v=\"%u\"\r\n\r\n", GetParam());
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"), MockRead(altsvc_header.c_str()),
+ MockRead("hello world"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 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_);
+
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSession();
+
+ SendRequestAndExpectHttpResponse("hello world");
+ SendRequestAndExpectQuicResponse("hello!");
+}
+
+TEST_P(QuicNetworkTransactionTest, GoAwayWithConnectionMigrationOnPortsOnly) {
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ // Read a GoAway packet with
+ // QuicErrorCode: QUIC_ERROR_MIGRATING_PORT from the peer.
+ mock_quic_data.AddRead(ConstructServerGoAwayPacket(
+ 2, QUIC_ERROR_MIGRATING_PORT,
+ "connection migration with port change only"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+ mock_quic_data.AddRead(ConstructServerDataPacket(3, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckAndRstPacket(
+ 3, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 3, 3, 1));
+ mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read
+ mock_quic_data.AddRead(ASYNC, 0); // EOF
+
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ // The non-alternate protocol job needs to hang in order to guarantee that
+ // the alternate-protocol job will "win".
+ AddHangingNonAlternateProtocolSocketData();
+
+ // In order for a new QUIC session to be established via alternate-protocol
+ // without racing an HTTP connection, we need the host resolution to happen
+ // synchronously. Of course, even though QUIC *could* perform a 0-RTT
+ // connection to the the server, in this test we require confirmation
+ // before encrypting so the HTTP job will still start.
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
+ "");
+ HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
+ AddressList address;
+ std::unique_ptr<HostResolver::Request> request;
+ host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
+ &request, net_log_.bound());
+
+ CreateSession();
+ session_->quic_stream_factory()->set_require_confirmation(true);
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
+
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ TestCompletionCallback callback;
+ int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+ crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
+ QuicSession::HANDSHAKE_CONFIRMED);
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
+
+ // Check whether this transaction is correctly marked as received a go-away
+ // because of migrating port.
+ NetErrorDetails details;
+ EXPECT_FALSE(details.quic_port_migration_detected);
+ trans.PopulateNetErrorDetails(&details);
+ EXPECT_TRUE(details.quic_port_migration_detected);
+}
+
+TEST_P(QuicNetworkTransactionTest,
+ DoNotUseAlternativeServiceQuicUnsupportedVersion) {
+ std::string altsvc_header = base::StringPrintf(
+ "Alt-Svc: quic=\":443\"; v=\"%u\"\r\n\r\n", GetParam() - 1);
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"), MockRead(altsvc_header.c_str()),
+ MockRead("hello world"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ CreateSession();
+
+ SendRequestAndExpectHttpResponse("hello world");
+ SendRequestAndExpectHttpResponse("hello world");
+}
+
+// When multiple alternative services are advertised,
+// HttpStreamFactoryImpl::RequestStreamInternal() should select the alternative
+// service which uses existing QUIC session if available. If no existing QUIC
+// session can be used, use the first alternative service from the list.
+TEST_P(QuicNetworkTransactionTest, UseExistingAlternativeServiceForQuic) {
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Alt-Svc: quic=\"foo.example.org:443\", quic=\":444\"\r\n\r\n"),
+ MockRead("hello world"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ QuicStreamOffset request_header_offset = 0;
+ QuicStreamOffset response_header_offset = 0;
+ // First QUIC request data.
+ // Open a session to foo.example.org:443 using the first entry of the
+ // alternative service list.
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/"), &request_header_offset));
+
+ std::string alt_svc_list =
+ "quic=\"mail.example.org:444\", quic=\"foo.example.org:443\", "
+ "quic=\"bar.example.org:445\"";
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false,
+ GetResponseHeaders("200 OK", alt_svc_list), &response_header_offset));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+
+ // Second QUIC request data.
+ // Connection pooling, using existing session, no need to include version
+ // as version negotiation has been completed.
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 3, kClientDataStreamId2, false, true,
+ GetRequestHeaders("GET", "https", "/"), &request_header_offset));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 3, kClientDataStreamId2, false, false, GetResponseHeaders("200 OK"),
+ &response_header_offset));
+ mock_quic_data.AddRead(ConstructServerDataPacket(4, kClientDataStreamId2,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(
+ ConstructClientAckAndConnectionClosePacket(4, 4, 3, 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_);
+
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSession();
+
+ SendRequestAndExpectHttpResponse("hello world");
+
+ SendRequestAndExpectQuicResponse("hello!");
+ SendRequestAndExpectQuicResponse("hello!");
+}
+
+// Check that an existing QUIC connection to an alternative proxy server is
+// used.
+TEST_P(QuicNetworkTransactionTest, UseExistingQUICAlternativeProxy) {
+ base::HistogramTester histogram_tester;
+
+ QuicStreamOffset request_header_offset = 0;
+ QuicStreamOffset response_header_offset = 0;
+ // First QUIC request data.
+ // Open a session to foo.example.org:443 using the first entry of the
+ // alternative service list.
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "http", "/"), &request_header_offset));
+
+ std::string alt_svc_list;
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false,
+ GetResponseHeaders("200 OK", alt_svc_list), &response_header_offset));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+
+ // Second QUIC request data.
+ // Connection pooling, using existing session, no need to include version
+ // as version negotiation has been completed.
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 3, kClientDataStreamId2, false, true,
+ GetRequestHeaders("GET", "http", "/"), &request_header_offset));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 3, kClientDataStreamId2, false, false, GetResponseHeaders("200 OK"),
+ &response_header_offset));
+ mock_quic_data.AddRead(ConstructServerDataPacket(4, kClientDataStreamId2,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(
+ ConstructClientAckAndConnectionClosePacket(4, 4, 3, 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_);
+
+ AddHangingNonAlternateProtocolSocketData();
+
+ TestProxyDelegate test_proxy_delegate;
+
+ proxy_service_ =
+ ProxyService::CreateFixedFromPacResult("HTTPS mail.example.org:443");
+
+ test_proxy_delegate.set_alternative_proxy_server(
+ ProxyServer::FromPacString("QUIC mail.example.org:443"));
+ params_.proxy_delegate = &test_proxy_delegate;
+
+ request_.url = GURL("http://mail.example.org/");
+
+ CreateSession();
+
+ SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 443);
+ histogram_tester.ExpectUniqueSample("Net.QuicAlternativeProxy.Usage",
+ 1 /* ALTERNATIVE_PROXY_USAGE_WON_RACE */,
+ 1);
+
+ SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 443);
+ histogram_tester.ExpectTotalCount("Net.QuicAlternativeProxy.Usage", 2);
+ histogram_tester.ExpectBucketCount("Net.QuicAlternativeProxy.Usage",
+ 0 /* ALTERNATIVE_PROXY_USAGE_NO_RACE */,
+ 1);
+}
+
+// Pool to existing session with matching QuicServerId
+// even if alternative service destination is different.
+TEST_P(QuicNetworkTransactionTest, PoolByOrigin) {
+ MockQuicData mock_quic_data;
+ QuicStreamOffset request_header_offset(0);
+ QuicStreamOffset response_header_offset(0);
+
+ // First request.
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/"), &request_header_offset));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK"),
+ &response_header_offset));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+
+ // Second request.
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 3, kClientDataStreamId2, false, true,
+ GetRequestHeaders("GET", "https", "/"), &request_header_offset));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 3, kClientDataStreamId2, false, false, GetResponseHeaders("200 OK"),
+ &response_header_offset));
+ mock_quic_data.AddRead(ConstructServerDataPacket(4, kClientDataStreamId2,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(
+ ConstructClientAckAndConnectionClosePacket(4, 4, 3, 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_);
+
+ AddHangingNonAlternateProtocolSocketData();
+ AddHangingNonAlternateProtocolSocketData();
+
+ CreateSession();
+
+ const char destination1[] = "first.example.com";
+ const char destination2[] = "second.example.com";
+
+ // Set up alternative service entry to destination1.
+ url::SchemeHostPort server(request_.url);
+ AlternativeService alternative_service(QUIC, destination1, 443);
+ base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
+ http_server_properties_.SetAlternativeService(server, alternative_service,
+ expiration);
+ // First request opens connection to |destination1|
+ // with QuicServerId.host() == kDefaultServerHostName.
+ SendRequestAndExpectQuicResponse("hello!");
+
+ // Set up alternative service entry to a different destination.
+ alternative_service = AlternativeService(QUIC, destination2, 443);
+ http_server_properties_.SetAlternativeService(server, alternative_service,
+ expiration);
+ // Second request pools to existing connection with same QuicServerId,
+ // even though alternative service destination is different.
+ SendRequestAndExpectQuicResponse("hello!");
+}
+
+// Pool to existing session with matching destination and matching certificate
+// even if origin is different, and even if the alternative service with
+// matching destination is not the first one on the list.
+TEST_P(QuicNetworkTransactionTest, PoolByDestination) {
+ GURL origin1 = request_.url;
+ GURL origin2("https://www.example.org/");
+ ASSERT_NE(origin1.host(), origin2.host());
+
+ MockQuicData mock_quic_data;
+ QuicStreamOffset request_header_offset(0);
+ QuicStreamOffset response_header_offset(0);
+
+ // First request.
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/"), &request_header_offset));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK"),
+ &response_header_offset));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+
+ // Second request.
+ QuicTestPacketMaker client_maker2(GetParam(), 0, clock_, origin2.host(),
+ Perspective::IS_CLIENT);
+ QuicTestPacketMaker server_maker2(GetParam(), 0, clock_, origin2.host(),
+ Perspective::IS_SERVER);
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 3, kClientDataStreamId2, false, true,
+ GetRequestHeaders("GET", "https", "/", &client_maker2),
+ &request_header_offset));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 3, kClientDataStreamId2, false, false, GetResponseHeaders("200 OK"),
+ &response_header_offset));
+ mock_quic_data.AddRead(ConstructServerDataPacket(4, kClientDataStreamId2,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(
+ ConstructClientAckAndConnectionClosePacket(4, 4, 3, 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_);
+
+ AddHangingNonAlternateProtocolSocketData();
+ AddHangingNonAlternateProtocolSocketData();
+
+ CreateSession();
+
+ const char destination1[] = "first.example.com";
+ const char destination2[] = "second.example.com";
+
+ // Set up alternative service for |origin1|.
+ AlternativeService alternative_service1(QUIC, destination1, 443);
+ base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
+ http_server_properties_.SetAlternativeService(
+ url::SchemeHostPort(origin1), alternative_service1, expiration);
+
+ // Set up multiple alternative service entries for |origin2|,
+ // the first one with a different destination as for |origin1|,
+ // the second one with the same. The second one should be used,
+ // because the request can be pooled to that one.
+ AlternativeService alternative_service2(QUIC, destination2, 443);
+ AlternativeServiceInfoVector alternative_services;
+ alternative_services.push_back(
+ AlternativeServiceInfo(alternative_service2, expiration));
+ alternative_services.push_back(
+ AlternativeServiceInfo(alternative_service1, expiration));
+ http_server_properties_.SetAlternativeServices(url::SchemeHostPort(origin2),
+ alternative_services);
+ // First request opens connection to |destination1|
+ // with QuicServerId.host() == origin1.host().
+ SendRequestAndExpectQuicResponse("hello!");
+
+ // Second request pools to existing connection with same destination,
+ // because certificate matches, even though QuicServerId is different.
+ request_.url = origin2;
+
+ SendRequestAndExpectQuicResponse("hello!");
+}
+
+// Multiple origins have listed the same alternative services. When there's a
+// existing QUIC session opened by a request to other origin,
+// if the cert is valid, should select this QUIC session to make the request
+// if this is also the first existing QUIC session.
+TEST_P(QuicNetworkTransactionTest,
+ UseSharedExistingAlternativeServiceForQuicWithValidCert) {
+ // Default cert is valid for *.example.org
+
+ // HTTP data for request to www.example.org.
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Alt-Svc: quic=\":443\"\r\n\r\n"),
+ MockRead("hello world from www.example.org"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ // HTTP data for request to mail.example.org.
+ MockRead http_reads2[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead("Alt-Svc: quic=\":444\", quic=\"www.example.org:443\"\r\n\r\n"),
+ MockRead("hello world from mail.example.org"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data2(http_reads2, arraysize(http_reads2),
+ nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&http_data2);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ QuicStreamOffset request_header_offset = 0;
+ QuicStreamOffset response_header_offset = 0;
+
+ QuicTestPacketMaker client_maker(GetParam(), 0, clock_, "mail.example.org",
+ Perspective::IS_CLIENT);
+ server_maker_.set_hostname("www.example.org");
+ client_maker_.set_hostname("www.example.org");
+ MockQuicData mock_quic_data;
+
+ // First QUIC request data.
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/"), &request_header_offset));
+
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK"),
+ &response_header_offset));
+ mock_quic_data.AddRead(ConstructServerDataPacket(
+ 2, kClientDataStreamId1, false, true, 0, "hello from mail QUIC!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+ // Second QUIC request data.
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 3, kClientDataStreamId2, false, true,
+ GetRequestHeaders("GET", "https", "/", &client_maker),
+ &request_header_offset));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 3, kClientDataStreamId2, false, false, GetResponseHeaders("200 OK"),
+ &response_header_offset));
+ mock_quic_data.AddRead(ConstructServerDataPacket(
+ 4, kClientDataStreamId2, false, true, 0, "hello from mail QUIC!"));
+ mock_quic_data.AddWrite(
+ ConstructClientAckAndConnectionClosePacket(4, 4, 3, 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_);
+
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSession();
+
+ // Send two HTTP requests, responses set up alt-svc lists for the origins.
+ request_.url = GURL("https://www.example.org/");
+ SendRequestAndExpectHttpResponse("hello world from www.example.org");
+ request_.url = GURL("https://mail.example.org/");
+ SendRequestAndExpectHttpResponse("hello world from mail.example.org");
+
+ // Open a QUIC session to mail.example.org:443 when making request
+ // to mail.example.org.
+ request_.url = GURL("https://www.example.org/");
+ SendRequestAndExpectQuicResponse("hello from mail QUIC!");
+
+ // Uses the existing QUIC session when making request to www.example.org.
+ request_.url = GURL("https://mail.example.org/");
+ SendRequestAndExpectQuicResponse("hello from mail QUIC!");
+}
+
+TEST_P(QuicNetworkTransactionTest, AlternativeServiceDifferentPort) {
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"),
+ MockRead(kQuicAlternativeServiceDifferentPortHeader),
+ MockRead("hello world"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSession();
+
+ SendRequestAndExpectHttpResponse("hello world");
+
+ url::SchemeHostPort http_server("https", kDefaultServerHostName, 443);
+ AlternativeServiceVector alternative_service_vector =
+ http_server_properties_.GetAlternativeServices(http_server);
+ ASSERT_EQ(1u, alternative_service_vector.size());
+ const AlternativeService alternative_service = alternative_service_vector[0];
+ EXPECT_EQ(QUIC, alternative_service_vector[0].protocol);
+ EXPECT_EQ(kDefaultServerHostName, alternative_service_vector[0].host);
+ EXPECT_EQ(137, alternative_service_vector[0].port);
+}
+
+TEST_P(QuicNetworkTransactionTest, ConfirmAlternativeService) {
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"), MockRead(kQuicAlternativeServiceHeader),
+ MockRead("hello world"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 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_);
+
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSession();
+
+ AlternativeService alternative_service(QUIC,
+ HostPortPair::FromURL(request_.url));
+ http_server_properties_.MarkAlternativeServiceRecentlyBroken(
+ alternative_service);
+ EXPECT_TRUE(http_server_properties_.WasAlternativeServiceRecentlyBroken(
+ alternative_service));
+
+ SendRequestAndExpectHttpResponse("hello world");
+ SendRequestAndExpectQuicResponse("hello!");
+
+ mock_quic_data.Resume();
+
+ EXPECT_FALSE(http_server_properties_.WasAlternativeServiceRecentlyBroken(
+ alternative_service));
+}
+
+TEST_P(QuicNetworkTransactionTest, UseAlternativeServiceForQuicForHttps) {
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"), MockRead(kQuicAlternativeServiceHeader),
+ MockRead("hello world"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+ mock_quic_data.AddRead(SYNCHRONOUS, 0); // EOF
+
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSession();
+
+ // TODO(rtenneti): Test QUIC over HTTPS, GetSSLInfo().
+ SendRequestAndExpectHttpResponse("hello world");
+}
+
+// Tests that the connection to an HTTPS proxy is raced with an available
+// alternative proxy server.
+TEST_P(QuicNetworkTransactionTest, QuicProxyWithRacing) {
+ base::HistogramTester histogram_tester;
+ proxy_service_ =
+ ProxyService::CreateFixedFromPacResult("HTTPS mail.example.org:443");
+
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "http", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 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_);
+
+ // There is no need to set up main job, because no attempt will be made to
+ // speak to the proxy over TCP.
+ request_.url = GURL("http://mail.example.org/");
+ params_.enable_quic_alternative_service_with_different_host = false;
+ TestProxyDelegate test_proxy_delegate;
+ const HostPortPair host_port_pair("mail.example.org", 443);
+
+ test_proxy_delegate.set_alternative_proxy_server(
+ ProxyServer::FromPacString("QUIC mail.example.org:443"));
+ params_.proxy_delegate = &test_proxy_delegate;
+ CreateSession();
+ EXPECT_TRUE(test_proxy_delegate.alternative_proxy_server().is_quic());
+
+ // The main job needs to hang in order to guarantee that the alternative
+ // proxy server job will "win".
+ AddHangingNonAlternateProtocolSocketData();
+
+ SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 443);
+
+ // Verify that the alternative proxy server is not marked as broken.
+ EXPECT_TRUE(test_proxy_delegate.alternative_proxy_server().is_quic());
+
+ // Verify that the proxy server is not marked as broken.
+ EXPECT_TRUE(session_->proxy_service()->proxy_retry_info().empty());
+
+ histogram_tester.ExpectUniqueSample("Net.QuicAlternativeProxy.Usage",
+ 1 /* ALTERNATIVE_PROXY_USAGE_WON_RACE */,
+ 1);
+}
+
+TEST_P(QuicNetworkTransactionTest, HungAlternativeService) {
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::COLD_START);
+
+ MockWrite http_writes[] = {
+ MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n"),
+ MockWrite(SYNCHRONOUS, 1, "Host: mail.example.org\r\n"),
+ MockWrite(SYNCHRONOUS, 2, "Connection: keep-alive\r\n\r\n")};
+
+ MockRead http_reads[] = {
+ MockRead(SYNCHRONOUS, 3, "HTTP/1.1 200 OK\r\n"),
+ MockRead(SYNCHRONOUS, 4, kQuicAlternativeServiceHeader),
+ MockRead(SYNCHRONOUS, 5, "hello world"), MockRead(SYNCHRONOUS, OK, 6)};
+
+ SequencedSocketData http_data(http_reads, arraysize(http_reads), http_writes,
+ arraysize(http_writes));
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ // The QUIC transaction will not be allowed to complete.
+ MockWrite quic_writes[] = {MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 1)};
+ MockRead quic_reads[] = {
+ MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0),
+ };
+ SequencedSocketData quic_data(quic_reads, arraysize(quic_reads), quic_writes,
+ arraysize(quic_writes));
+ socket_factory_.AddSocketDataProvider(&quic_data);
+
+ // The HTTP transaction will complete.
+ SequencedSocketData http_data2(http_reads, arraysize(http_reads), http_writes,
+ arraysize(http_writes));
+ socket_factory_.AddSocketDataProvider(&http_data2);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ CreateSession();
+
+ // Run the first request.
+ SendRequestAndExpectHttpResponse("hello world");
+ ASSERT_TRUE(http_data.AllReadDataConsumed());
+ ASSERT_TRUE(http_data.AllWriteDataConsumed());
+
+ // Now run the second request in which the QUIC socket hangs,
+ // and verify the the transaction continues over HTTP.
+ SendRequestAndExpectHttpResponse("hello world");
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_TRUE(http_data2.AllReadDataConsumed());
+ ASSERT_TRUE(http_data2.AllWriteDataConsumed());
+ ASSERT_TRUE(quic_data.AllReadDataConsumed());
+}
+
+TEST_P(QuicNetworkTransactionTest, ZeroRTTWithHttpRace) {
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+ mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read
+ mock_quic_data.AddRead(ASYNC, 0); // EOF
+
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ // The non-alternate protocol job needs to hang in order to guarantee that
+ // the alternate-protocol job will "win".
+ AddHangingNonAlternateProtocolSocketData();
+
+ CreateSession();
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
+ SendRequestAndExpectQuicResponse("hello!");
+}
+
+TEST_P(QuicNetworkTransactionTest, ZeroRTTWithNoHttpRace) {
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 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_);
+
+ // In order for a new QUIC session to be established via alternate-protocol
+ // without racing an HTTP connection, we need the host resolution to happen
+ // synchronously.
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
+ "");
+ HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
+ AddressList address;
+ std::unique_ptr<HostResolver::Request> request;
+ host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
+ &request, net_log_.bound());
+
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSession();
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
+ SendRequestAndExpectQuicResponse("hello!");
+}
+
+TEST_P(QuicNetworkTransactionTest, ZeroRTTWithProxy) {
+ proxy_service_ = ProxyService::CreateFixedFromPacResult("PROXY myproxy:70");
+
+ // Since we are using a proxy, the QUIC job will not succeed.
+ MockWrite http_writes[] = {
+ MockWrite(SYNCHRONOUS, 0, "GET http://mail.example.org/ HTTP/1.1\r\n"),
+ MockWrite(SYNCHRONOUS, 1, "Host: mail.example.org\r\n"),
+ MockWrite(SYNCHRONOUS, 2, "Proxy-Connection: keep-alive\r\n\r\n")};
+
+ MockRead http_reads[] = {
+ MockRead(SYNCHRONOUS, 3, "HTTP/1.1 200 OK\r\n"),
+ MockRead(SYNCHRONOUS, 4, kQuicAlternativeServiceHeader),
+ MockRead(SYNCHRONOUS, 5, "hello world"), MockRead(SYNCHRONOUS, OK, 6)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads),
+ http_writes, arraysize(http_writes));
+ socket_factory_.AddSocketDataProvider(&http_data);
+
+ // In order for a new QUIC session to be established via alternate-protocol
+ // without racing an HTTP connection, we need the host resolution to happen
+ // synchronously.
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
+ "");
+ HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
+ AddressList address;
+ std::unique_ptr<HostResolver::Request> request;
+ host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
+ &request, net_log_.bound());
+
+ request_.url = GURL("http://mail.example.org/");
+ CreateSession();
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
+ SendRequestAndExpectHttpResponse("hello world");
+}
+
+TEST_P(QuicNetworkTransactionTest, ZeroRTTWithConfirmationRequired) {
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+ mock_quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // No more data to read
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ // The non-alternate protocol job needs to hang in order to guarantee that
+ // the alternate-protocol job will "win".
+ AddHangingNonAlternateProtocolSocketData();
+
+ // In order for a new QUIC session to be established via alternate-protocol
+ // without racing an HTTP connection, we need the host resolution to happen
+ // synchronously. Of course, even though QUIC *could* perform a 0-RTT
+ // connection to the the server, in this test we require confirmation
+ // before encrypting so the HTTP job will still start.
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
+ "");
+ HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
+ AddressList address;
+ std::unique_ptr<HostResolver::Request> request;
+ host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
+ &request, net_log_.bound());
+
+ CreateSession();
+ session_->quic_stream_factory()->set_require_confirmation(true);
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
+
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ TestCompletionCallback callback;
+ int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+ crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
+ QuicSession::HANDSHAKE_CONFIRMED);
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
+
+ CheckWasQuicResponse(&trans);
+ CheckResponseData(&trans, "hello!");
+}
+
+TEST_P(QuicNetworkTransactionTest,
+ LogGranularQuicErrorCodeOnQuicProtocolErrorLocal) {
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ // Read a close connection packet with
+ // QuicErrorCode: QUIC_CRYPTO_VERSION_NOT_SUPPORTED from the peer.
+ mock_quic_data.AddRead(ConstructServerConnectionClosePacket(1));
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ // The non-alternate protocol job needs to hang in order to guarantee that
+ // the alternate-protocol job will "win".
+ AddHangingNonAlternateProtocolSocketData();
+
+ // In order for a new QUIC session to be established via alternate-protocol
+ // without racing an HTTP connection, we need the host resolution to happen
+ // synchronously. Of course, even though QUIC *could* perform a 0-RTT
+ // connection to the the server, in this test we require confirmation
+ // before encrypting so the HTTP job will still start.
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
+ "");
+ HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
+ AddressList address;
+ std::unique_ptr<HostResolver::Request> request;
+ host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
+ &request, net_log_.bound());
+
+ CreateSession();
+ session_->quic_stream_factory()->set_require_confirmation(true);
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
+
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ TestCompletionCallback callback;
+ int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+ crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
+ QuicSession::HANDSHAKE_CONFIRMED);
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_QUIC_PROTOCOL_ERROR));
+
+ NetErrorDetails details;
+ EXPECT_EQ(QUIC_NO_ERROR, details.quic_connection_error);
+
+ trans.PopulateNetErrorDetails(&details);
+ // Verify the error code logged is what sent by the peer.
+ EXPECT_EQ(QUIC_CRYPTO_VERSION_NOT_SUPPORTED, details.quic_connection_error);
+}
+
+TEST_P(QuicNetworkTransactionTest,
+ LogGranularQuicErrorCodeOnQuicProtocolErrorRemote) {
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ // Peer sending data from an non-existing stream causes this end to raise
+ // error and close connection.
+ mock_quic_data.AddRead(
+ ConstructServerRstPacket(1, false, 99, QUIC_STREAM_LAST_ERROR));
+ std::string quic_error_details = "Data for nonexistent stream";
+ mock_quic_data.AddWrite(ConstructClientAckAndConnectionClosePacket(
+ 2, QuicTime::Delta::Infinite(), 0, 1, QUIC_INVALID_STREAM_ID,
+ quic_error_details));
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ // The non-alternate protocol job needs to hang in order to guarantee that
+ // the alternate-protocol job will "win".
+ AddHangingNonAlternateProtocolSocketData();
+
+ // In order for a new QUIC session to be established via alternate-protocol
+ // without racing an HTTP connection, we need the host resolution to happen
+ // synchronously. Of course, even though QUIC *could* perform a 0-RTT
+ // connection to the the server, in this test we require confirmation
+ // before encrypting so the HTTP job will still start.
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
+ "");
+ HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
+ AddressList address;
+ std::unique_ptr<HostResolver::Request> request;
+ host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
+ &request, net_log_.bound());
+
+ CreateSession();
+ session_->quic_stream_factory()->set_require_confirmation(true);
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
+
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ TestCompletionCallback callback;
+ int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+ crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
+ QuicSession::HANDSHAKE_CONFIRMED);
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_QUIC_PROTOCOL_ERROR));
+ NetErrorDetails details;
+ EXPECT_EQ(QUIC_NO_ERROR, details.quic_connection_error);
+
+ trans.PopulateNetErrorDetails(&details);
+ EXPECT_EQ(QUIC_INVALID_STREAM_ID, details.quic_connection_error);
+}
+
+TEST_P(QuicNetworkTransactionTest, RstSteamErrorHandling) {
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ // Read the response headers, then a RST_STREAM frame.
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerRstPacket(
+ 2, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+ mock_quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // No more read data.
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ // The non-alternate protocol job needs to hang in order to guarantee that
+ // the alternate-protocol job will "win".
+ AddHangingNonAlternateProtocolSocketData();
+
+ // In order for a new QUIC session to be established via alternate-protocol
+ // without racing an HTTP connection, we need the host resolution to happen
+ // synchronously. Of course, even though QUIC *could* perform a 0-RTT
+ // connection to the the server, in this test we require confirmation
+ // before encrypting so the HTTP job will still start.
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
+ "");
+ HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
+ AddressList address;
+ std::unique_ptr<HostResolver::Request> request;
+ host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
+ &request, net_log_.bound());
+
+ CreateSession();
+ session_->quic_stream_factory()->set_require_confirmation(true);
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
+
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ TestCompletionCallback callback;
+ int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+ crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
+ QuicSession::HANDSHAKE_CONFIRMED);
+ // Read the headers.
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
+
+ const HttpResponseInfo* response = trans.GetResponseInfo();
+ ASSERT_TRUE(response != nullptr);
+ ASSERT_TRUE(response->headers.get() != nullptr);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+ EXPECT_TRUE(response->was_fetched_via_spdy);
+ EXPECT_TRUE(response->was_alpn_negotiated);
+ EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_QUIC1_SPDY3,
+ response->connection_info);
+
+ std::string response_data;
+ ASSERT_EQ(ERR_QUIC_PROTOCOL_ERROR, ReadTransaction(&trans, &response_data));
+}
+
+TEST_P(QuicNetworkTransactionTest, RstSteamBeforeHeaders) {
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddRead(ConstructServerRstPacket(
+ 1, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
+ mock_quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // No more read data.
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ // The non-alternate protocol job needs to hang in order to guarantee that
+ // the alternate-protocol job will "win".
+ AddHangingNonAlternateProtocolSocketData();
+
+ // In order for a new QUIC session to be established via alternate-protocol
+ // without racing an HTTP connection, we need the host resolution to happen
+ // synchronously. Of course, even though QUIC *could* perform a 0-RTT
+ // connection to the the server, in this test we require confirmation
+ // before encrypting so the HTTP job will still start.
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
+ "");
+ HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
+ AddressList address;
+ std::unique_ptr<HostResolver::Request> request;
+ host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
+ &request, net_log_.bound());
+
+ CreateSession();
+ session_->quic_stream_factory()->set_require_confirmation(true);
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
+
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ TestCompletionCallback callback;
+ int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+ crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
+ QuicSession::HANDSHAKE_CONFIRMED);
+ // Read the headers.
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_QUIC_PROTOCOL_ERROR));
+}
+
+TEST_P(QuicNetworkTransactionTest, BrokenAlternateProtocol) {
+ // Alternate-protocol job
+ std::unique_ptr<QuicEncryptedPacket> close(
+ ConstructServerConnectionClosePacket(1));
+ MockRead quic_reads[] = {
+ MockRead(ASYNC, close->data(), close->length()),
+ MockRead(ASYNC, ERR_IO_PENDING), // No more data to read
+ MockRead(ASYNC, OK), // EOF
+ };
+ StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&quic_data);
+
+ // Main job which will succeed even though the alternate job fails.
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello from http"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ CreateSession();
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START);
+ SendRequestAndExpectHttpResponse("hello from http");
+ ExpectBrokenAlternateProtocolMapping();
+}
+
+TEST_P(QuicNetworkTransactionTest, BrokenAlternateProtocolReadError) {
+ // Alternate-protocol job
+ MockRead quic_reads[] = {
+ MockRead(ASYNC, ERR_SOCKET_NOT_CONNECTED),
+ };
+ StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&quic_data);
+
+ // Main job which will succeed even though the alternate job fails.
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello from http"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ CreateSession();
+
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START);
+ SendRequestAndExpectHttpResponse("hello from http");
+ ExpectBrokenAlternateProtocolMapping();
+}
+
+TEST_P(QuicNetworkTransactionTest, NoBrokenAlternateProtocolIfTcpFails) {
+ // Alternate-protocol job will fail when the session attempts to read.
+ MockRead quic_reads[] = {
+ MockRead(ASYNC, ERR_SOCKET_NOT_CONNECTED),
+ };
+ StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&quic_data);
+
+ // Main job will also fail.
+ MockRead http_reads[] = {
+ MockRead(ASYNC, ERR_SOCKET_NOT_CONNECTED),
+ };
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ http_data.set_connect_data(MockConnect(ASYNC, ERR_SOCKET_NOT_CONNECTED));
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSession();
+
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START);
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ TestCompletionCallback callback;
+ int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_SOCKET_NOT_CONNECTED));
+ ExpectQuicAlternateProtocolMapping();
+}
+
+TEST_P(QuicNetworkTransactionTest, FailedZeroRttBrokenAlternateProtocol) {
+ // Alternate-protocol job
+ MockRead quic_reads[] = {
+ MockRead(ASYNC, ERR_SOCKET_NOT_CONNECTED),
+ };
+ StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&quic_data);
+
+ // Second Alternate-protocol job which will race with the TCP job.
+ StaticSocketDataProvider quic_data2(quic_reads, arraysize(quic_reads),
+ nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&quic_data2);
+
+ // Final job that will proceed when the QUIC job fails.
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello from http"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSession();
+
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
+
+ SendRequestAndExpectHttpResponse("hello from http");
+
+ ExpectBrokenAlternateProtocolMapping();
+
+ EXPECT_TRUE(quic_data.AllReadDataConsumed());
+ EXPECT_TRUE(quic_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicNetworkTransactionTest, DISABLED_HangingZeroRttFallback) {
+ // Alternate-protocol job
+ MockRead quic_reads[] = {
+ MockRead(SYNCHRONOUS, ERR_IO_PENDING),
+ };
+ StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&quic_data);
+
+ // Main job that will proceed when the QUIC job fails.
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello from http"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSession();
+
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
+
+ SendRequestAndExpectHttpResponse("hello from http");
+}
+
+TEST_P(QuicNetworkTransactionTest, BrokenAlternateProtocolOnConnectFailure) {
+ // Alternate-protocol job will fail before creating a QUIC session.
+ StaticSocketDataProvider quic_data(nullptr, 0, nullptr, 0);
+ quic_data.set_connect_data(
+ MockConnect(SYNCHRONOUS, ERR_INTERNET_DISCONNECTED));
+ socket_factory_.AddSocketDataProvider(&quic_data);
+
+ // Main job which will succeed even though the alternate job fails.
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello from http"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ CreateSession();
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START);
+ SendRequestAndExpectHttpResponse("hello from http");
+
+ ExpectBrokenAlternateProtocolMapping();
+}
+
+TEST_P(QuicNetworkTransactionTest, ConnectionCloseDuringConnect) {
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddSynchronousRead(ConstructServerConnectionClosePacket(1));
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ // When the QUIC connection fails, we will try the request again over HTTP.
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"), MockRead(kQuicAlternativeServiceHeader),
+ MockRead("hello world"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ // In order for a new QUIC session to be established via alternate-protocol
+ // without racing an HTTP connection, we need the host resolution to happen
+ // synchronously.
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
+ "");
+ HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
+ AddressList address;
+ std::unique_ptr<HostResolver::Request> request;
+ host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
+ &request, net_log_.bound());
+
+ CreateSession();
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
+ SendRequestAndExpectHttpResponse("hello world");
+}
+
+// For an alternative proxy that supports QUIC, test that the request is
+// successfully fetched by the main job when the alternate proxy job encounters
+// an error.
+TEST_P(QuicNetworkTransactionTest, BrokenAlternativeProxySocketNotConnected) {
+ TestAlternativeProxy(ERR_SOCKET_NOT_CONNECTED);
+}
+TEST_P(QuicNetworkTransactionTest, BrokenAlternativeProxyConnectionFailed) {
+ TestAlternativeProxy(ERR_CONNECTION_FAILED);
+}
+TEST_P(QuicNetworkTransactionTest, BrokenAlternativeProxyConnectionTimedOut) {
+ TestAlternativeProxy(ERR_CONNECTION_TIMED_OUT);
+}
+TEST_P(QuicNetworkTransactionTest, BrokenAlternativeProxyConnectionRefused) {
+ TestAlternativeProxy(ERR_CONNECTION_REFUSED);
+}
+TEST_P(QuicNetworkTransactionTest, BrokenAlternativeProxyQuicHandshakeFailed) {
+ TestAlternativeProxy(ERR_QUIC_HANDSHAKE_FAILED);
+}
+TEST_P(QuicNetworkTransactionTest, BrokenAlternativeProxyQuicProtocolError) {
+ TestAlternativeProxy(ERR_QUIC_PROTOCOL_ERROR);
+}
+TEST_P(QuicNetworkTransactionTest, BrokenAlternativeProxyIOPending) {
+ TestAlternativeProxy(ERR_IO_PENDING);
+}
+TEST_P(QuicNetworkTransactionTest, BrokenAlternativeProxyAddressUnreachable) {
+ TestAlternativeProxy(ERR_ADDRESS_UNREACHABLE);
+}
+
+TEST_P(QuicNetworkTransactionTest, ConnectionCloseDuringConnectProxy) {
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddSynchronousRead(ConstructServerConnectionClosePacket(1));
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ // When the QUIC connection fails, we will try the request again over HTTP.
+ MockRead http_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"), MockRead(kQuicAlternativeServiceHeader),
+ MockRead("hello world"),
+ MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
+ MockRead(ASYNC, OK)};
+
+ StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+ 0);
+ socket_factory_.AddSocketDataProvider(&http_data);
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+
+ TestProxyDelegate test_proxy_delegate;
+ const HostPortPair host_port_pair("myproxy.org", 443);
+ test_proxy_delegate.set_alternative_proxy_server(
+ ProxyServer::FromPacString("QUIC myproxy.org:443"));
+ EXPECT_TRUE(test_proxy_delegate.alternative_proxy_server().is_quic());
+
+ params_.proxy_delegate = &test_proxy_delegate;
+ proxy_service_ =
+ ProxyService::CreateFixedFromPacResult("HTTPS myproxy.org:443");
+ request_.url = GURL("http://mail.example.org/");
+
+ // In order for a new QUIC session to be established via alternate-protocol
+ // without racing an HTTP connection, we need the host resolution to happen
+ // synchronously.
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule("myproxy.org", "192.168.0.1", "");
+ HostResolver::RequestInfo info(HostPortPair("myproxy.org", 443));
+ AddressList address;
+ std::unique_ptr<HostResolver::Request> request;
+ host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
+ &request, net_log_.bound());
+
+ CreateSession();
+ SendRequestAndExpectHttpResponseFromProxy("hello world", true, 443);
+ EXPECT_FALSE(test_proxy_delegate.alternative_proxy_server().is_valid());
+ EXPECT_TRUE(session_->proxy_service()->proxy_retry_info().empty());
+}
+
+TEST_P(QuicNetworkTransactionTest, SecureResourceOverSecureQuic) {
+ client_maker_.set_hostname("www.example.org");
+ EXPECT_FALSE(
+ test_socket_performance_watcher_factory_.rtt_notification_received());
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+ mock_quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // No more read data.
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ request_.url = GURL("https://www.example.org:443");
+ AddHangingNonAlternateProtocolSocketData();
+ CreateSession();
+ AddQuicAlternateProtocolMapping(MockCryptoClientStream::CONFIRM_HANDSHAKE);
+ SendRequestAndExpectQuicResponse("hello!");
+ EXPECT_TRUE(
+ test_socket_performance_watcher_factory_.rtt_notification_received());
+}
+
+TEST_P(QuicNetworkTransactionTest, QuicUploadToAlternativeProxyServer) {
+ base::HistogramTester histogram_tester;
+ proxy_service_ =
+ ProxyService::CreateFixedFromPacResult("HTTPS mail.example.org:443");
+
+ TestProxyDelegate test_proxy_delegate;
+
+ test_proxy_delegate.set_alternative_proxy_server(
+ ProxyServer::FromPacString("QUIC mail.example.org:443"));
+ params_.proxy_delegate = &test_proxy_delegate;
+
+ request_.url = GURL("http://mail.example.org/");
+
+ MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
+ MockWrite writes[] = {MockWrite(SYNCHRONOUS, ERR_FAILED, 1)};
+ SequencedSocketData socket_data(reads, arraysize(reads), writes,
+ arraysize(writes));
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ // The non-alternate protocol job needs to hang in order to guarantee that
+ // the alternate-protocol job will "win".
+ AddHangingNonAlternateProtocolSocketData();
+
+ CreateSession();
+ request_.method = "POST";
+ ChunkedUploadDataStream upload_data(0);
+ upload_data.AppendData("1", 1, true);
+
+ request_.upload_data_stream = &upload_data;
+
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ TestCompletionCallback callback;
+ int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_NE(OK, callback.WaitForResult());
+
+ // Verify that the alternative proxy server is not marked as broken.
+ EXPECT_TRUE(test_proxy_delegate.alternative_proxy_server().is_quic());
+
+ // Verify that the proxy server is not marked as broken.
+ EXPECT_TRUE(session_->proxy_service()->proxy_retry_info().empty());
+
+ histogram_tester.ExpectUniqueSample("Net.QuicAlternativeProxy.Usage",
+ 1 /* ALTERNATIVE_PROXY_USAGE_WON_RACE */,
+ 1);
+}
+
+TEST_P(QuicNetworkTransactionTest, QuicUpload) {
+ params_.origins_to_force_quic_on.insert(
+ HostPortPair::FromString("mail.example.org:443"));
+
+ MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
+ MockWrite writes[] = {MockWrite(SYNCHRONOUS, ERR_FAILED, 1)};
+ SequencedSocketData socket_data(reads, arraysize(reads), writes,
+ arraysize(writes));
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ // The non-alternate protocol job needs to hang in order to guarantee that
+ // the alternate-protocol job will "win".
+ AddHangingNonAlternateProtocolSocketData();
+
+ CreateSession();
+ request_.method = "POST";
+ ChunkedUploadDataStream upload_data(0);
+ upload_data.AppendData("1", 1, true);
+
+ request_.upload_data_stream = &upload_data;
+
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ TestCompletionCallback callback;
+ int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_NE(OK, callback.WaitForResult());
+}
+
+TEST_P(QuicNetworkTransactionTest, QuicUploadWriteError) {
+ ScopedMockNetworkChangeNotifier network_change_notifier;
+ MockNetworkChangeNotifier* mock_ncn =
+ network_change_notifier.mock_network_change_notifier();
+ mock_ncn->ForceNetworkHandlesSupported();
+ mock_ncn->SetConnectedNetworksList(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+
+ params_.origins_to_force_quic_on.insert(
+ HostPortPair::FromString("mail.example.org:443"));
+ params_.quic_migrate_sessions_on_network_change = true;
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ QuicStreamOffset offset = 0;
+ socket_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, false,
+ GetRequestHeaders("POST", "https", "/"), &offset));
+ socket_data.AddWrite(SYNCHRONOUS, ERR_FAILED);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ MockQuicData socket_data2;
+ socket_data2.AddConnect(SYNCHRONOUS, ERR_ADDRESS_INVALID);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ // The non-alternate protocol job needs to hang in order to guarantee that
+ // the alternate-protocol job will "win".
+ AddHangingNonAlternateProtocolSocketData();
+
+ CreateSession();
+ request_.method = "POST";
+ ChunkedUploadDataStream upload_data(0);
+
+ request_.upload_data_stream = &upload_data;
+
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ TestCompletionCallback callback;
+ int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+ base::RunLoop().RunUntilIdle();
+ upload_data.AppendData("1", 1, true);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_NE(OK, callback.WaitForResult());
+ session_.reset();
+}
+
+// Adds coverage to catch regression such as https://crbug.com/622043
+TEST_P(QuicNetworkTransactionTest, QuicServerPush) {
+ params_.origins_to_force_quic_on.insert(
+ HostPortPair::FromString("mail.example.org:443"));
+
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true,
+ GetRequestHeaders("GET", "https", "/")));
+ QuicStreamOffset server_header_offset = 0;
+ mock_quic_data.AddRead(ConstructServerPushPromisePacket(
+ 1, kClientDataStreamId1, kServerDataStreamId1, false,
+ GetRequestHeaders("GET", "https", "/pushed.jpg"), &server_header_offset,
+ &server_maker_));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 2, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK"),
+ &server_header_offset));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 2, 1, 1));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 3, kServerDataStreamId1, false, false, GetResponseHeaders("200 OK"),
+ &server_header_offset));
+ mock_quic_data.AddRead(ConstructServerDataPacket(4, kClientDataStreamId1,
+ false, true, 0, "hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(3, 4, 3, 1));
+ mock_quic_data.AddRead(ConstructServerDataPacket(
+ 5, kServerDataStreamId1, false, true, 0, "and hello!"));
+ mock_quic_data.AddWrite(ConstructClientAckAndRstPacket(
+ 4, kServerDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 5, 5, 1));
+ mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read
+ mock_quic_data.AddRead(ASYNC, 0); // EOF
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ // The non-alternate protocol job needs to hang in order to guarantee that
+ // the alternate-protocol job will "win".
+ AddHangingNonAlternateProtocolSocketData();
+
+ CreateSession();
+
+ // PUSH_PROMISE handling in the http layer gets exercised here.
+ SendRequestAndExpectQuicResponse("hello!");
+
+ request_.url = GURL("https://mail.example.org/pushed.jpg");
+ SendRequestAndExpectQuicResponse("and hello!");
+
+ // Check that the NetLog was filled reasonably.
+ TestNetLogEntry::List entries;
+ net_log_.GetEntries(&entries);
+ EXPECT_LT(0u, entries.size());
+
+ // Check that we logged a QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM
+ int pos = ExpectLogContainsSomewhere(
+ entries, 0, NetLogEventType::QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM,
+ NetLogEventPhase::NONE);
+ EXPECT_LT(0, pos);
+}
+
+TEST_P(QuicNetworkTransactionTest, QuicForceHolBlocking) {
+ FLAGS_quic_enable_version_35 = true;
+ FLAGS_quic_enable_version_36_v2 = true;
+ params_.quic_force_hol_blocking = true;
+ params_.origins_to_force_quic_on.insert(
+ HostPortPair::FromString("mail.example.org:443"));
+
+ MockQuicData mock_quic_data;
+
+ QuicStreamOffset offset = 0;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, false,
+ GetRequestHeaders("POST", "https", "/"), &offset));
+
+ std::unique_ptr<QuicEncryptedPacket> packet;
+ if (GetParam() > QUIC_VERSION_35) {
+ packet = ConstructClientForceHolDataPacket(2, kClientDataStreamId1, true,
+ true, &offset, "1");
+ } else {
+ packet =
+ ConstructClientDataPacket(2, kClientDataStreamId1, true, true, 0, "1");
+ }
+ mock_quic_data.AddWrite(std::move(packet));
+
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+
+ mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
+ 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_);
+
+ // The non-alternate protocol job needs to hang in order to guarantee that
+ // the alternate-protocol job will "win".
+ AddHangingNonAlternateProtocolSocketData();
+
+ CreateSession();
+ request_.method = "POST";
+ ChunkedUploadDataStream upload_data(0);
+ upload_data.AppendData("1", 1, true);
+
+ request_.upload_data_stream = &upload_data;
+
+ SendRequestAndExpectQuicResponse("hello!");
+}
+
+class QuicURLRequestContext : public URLRequestContext {
+ public:
+ QuicURLRequestContext(std::unique_ptr<HttpNetworkSession> session,
+ MockClientSocketFactory* socket_factory)
+ : storage_(this) {
+ socket_factory_ = socket_factory;
+ storage_.set_host_resolver(
+ std::unique_ptr<HostResolver>(new MockHostResolver));
+ storage_.set_cert_verifier(base::WrapUnique(new MockCertVerifier));
+ storage_.set_transport_security_state(
+ base::WrapUnique(new TransportSecurityState));
+ storage_.set_proxy_service(ProxyService::CreateDirect());
+ storage_.set_ssl_config_service(new SSLConfigServiceDefaults);
+ storage_.set_http_auth_handler_factory(
+ HttpAuthHandlerFactory::CreateDefault(host_resolver()));
+ storage_.set_http_server_properties(
+ std::unique_ptr<HttpServerProperties>(new HttpServerPropertiesImpl()));
+ storage_.set_job_factory(base::WrapUnique(new URLRequestJobFactoryImpl()));
+ storage_.set_http_network_session(std::move(session));
+ storage_.set_http_transaction_factory(base::WrapUnique(
+ new HttpCache(storage_.http_network_session(),
+ HttpCache::DefaultBackend::InMemory(0), false)));
+ }
+
+ ~QuicURLRequestContext() override { AssertNoURLRequests(); }
+
+ MockClientSocketFactory& socket_factory() { return *socket_factory_; }
+
+ private:
+ MockClientSocketFactory* socket_factory_;
+ URLRequestContextStorage storage_;
+};
+
+TEST_P(QuicNetworkTransactionTest, RawHeaderSizeSuccessfullRequest) {
+ params_.origins_to_force_quic_on.insert(
+ HostPortPair::FromString("mail.example.org:443"));
+
+ MockQuicData mock_quic_data;
+ SpdyHeaderBlock headers(GetRequestHeaders("GET", "https", "/"));
+ headers["user-agent"] = "";
+ headers["accept-encoding"] = "gzip, deflate";
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true, std::move(headers)));
+
+ QuicStreamOffset expected_raw_header_response_size = 0;
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK"),
+ &expected_raw_header_response_size));
+
+ mock_quic_data.AddRead(ConstructServerDataPacket(
+ 2, kClientDataStreamId1, false, true, 0, "Main Resource Data"));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
+
+ mock_quic_data.AddRead(ASYNC, 0); // EOF
+
+ CreateSession();
+
+ TestDelegate delegate;
+ QuicURLRequestContext quic_url_request_context(std::move(session_),
+ &socket_factory_);
+
+ mock_quic_data.AddSocketDataToFactory(
+ &quic_url_request_context.socket_factory());
+ TestNetworkDelegate network_delegate;
+ quic_url_request_context.set_network_delegate(&network_delegate);
+
+ std::unique_ptr<URLRequest> request(quic_url_request_context.CreateRequest(
+ GURL("https://mail.example.org/"), DEFAULT_PRIORITY, &delegate));
+ quic_url_request_context.socket_factory().AddSSLSocketDataProvider(
+ &ssl_data_);
+
+ request->Start();
+ base::RunLoop().Run();
+
+ EXPECT_LT(0, request->GetTotalSentBytes());
+ EXPECT_LT(0, request->GetTotalReceivedBytes());
+ EXPECT_EQ(network_delegate.total_network_bytes_sent(),
+ request->GetTotalSentBytes());
+ EXPECT_EQ(network_delegate.total_network_bytes_received(),
+ request->GetTotalReceivedBytes());
+ EXPECT_EQ(static_cast<int>(expected_raw_header_response_size),
+ request->raw_header_size());
+ EXPECT_TRUE(mock_quic_data.AllReadDataConsumed());
+ EXPECT_TRUE(mock_quic_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicNetworkTransactionTest, RawHeaderSizeSuccessfullPushHeadersFirst) {
+ params_.origins_to_force_quic_on.insert(
+ HostPortPair::FromString("mail.example.org:443"));
+
+ MockQuicData mock_quic_data;
+ SpdyHeaderBlock headers(GetRequestHeaders("GET", "https", "/"));
+ headers["user-agent"] = "";
+ headers["accept-encoding"] = "gzip, deflate";
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, true, std::move(headers)));
+
+ QuicStreamOffset server_header_offset = 0;
+ QuicStreamOffset expected_raw_header_response_size = 0;
+
+ mock_quic_data.AddRead(ConstructServerPushPromisePacket(
+ 1, kClientDataStreamId1, kServerDataStreamId1, false,
+ GetRequestHeaders("GET", "https", "/pushed.jpg"), &server_header_offset,
+ &server_maker_));
+
+ expected_raw_header_response_size = server_header_offset;
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 2, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK"),
+ &server_header_offset));
+ expected_raw_header_response_size =
+ server_header_offset - expected_raw_header_response_size;
+
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 2, 1, 1));
+
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 3, kServerDataStreamId1, false, false, GetResponseHeaders("200 OK"),
+ &server_header_offset));
+ mock_quic_data.AddRead(ConstructServerDataPacket(
+ 4, kServerDataStreamId1, false, true, 0, "Pushed Resource Data"));
+
+ mock_quic_data.AddWrite(ConstructClientAckPacket(3, 4, 3, 1));
+ mock_quic_data.AddRead(ConstructServerDataPacket(
+ 5, kClientDataStreamId1, false, true, 0, "Main Resource Data"));
+
+ mock_quic_data.AddRead(ConstructServerConnectionClosePacket(6));
+
+ CreateSession();
+
+ TestDelegate delegate;
+ QuicURLRequestContext quic_url_request_context(std::move(session_),
+ &socket_factory_);
+
+ mock_quic_data.AddSocketDataToFactory(
+ &quic_url_request_context.socket_factory());
+ TestNetworkDelegate network_delegate;
+ quic_url_request_context.set_network_delegate(&network_delegate);
+
+ std::unique_ptr<URLRequest> request(quic_url_request_context.CreateRequest(
+ GURL("https://mail.example.org/"), DEFAULT_PRIORITY, &delegate));
+ quic_url_request_context.socket_factory().AddSSLSocketDataProvider(
+ &ssl_data_);
+
+ request->Start();
+ base::RunLoop().Run();
+
+ EXPECT_LT(0, request->GetTotalSentBytes());
+ EXPECT_LT(0, request->GetTotalReceivedBytes());
+ EXPECT_EQ(network_delegate.total_network_bytes_sent(),
+ request->GetTotalSentBytes());
+ EXPECT_EQ(network_delegate.total_network_bytes_received(),
+ request->GetTotalReceivedBytes());
+ EXPECT_EQ(static_cast<int>(expected_raw_header_response_size),
+ request->raw_header_size());
+ EXPECT_TRUE(mock_quic_data.AllReadDataConsumed());
+ EXPECT_TRUE(mock_quic_data.AllWriteDataConsumed());
+}
+
+class QuicNetworkTransactionWithDestinationTest
+ : public PlatformTest,
+ public ::testing::WithParamInterface<PoolingTestParams> {
+ protected:
+ QuicNetworkTransactionWithDestinationTest()
+ : clock_(new MockClock),
+ version_(GetParam().version),
+ destination_type_(GetParam().destination_type),
+ cert_transparency_verifier_(new MultiLogCTVerifier()),
+ ssl_config_service_(new SSLConfigServiceDefaults),
+ proxy_service_(ProxyService::CreateDirect()),
+ auth_handler_factory_(
+ HttpAuthHandlerFactory::CreateDefault(&host_resolver_)),
+ random_generator_(0),
+ ssl_data_(ASYNC, OK) {}
+
+ void SetUp() override {
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
+ base::RunLoop().RunUntilIdle();
+
+ HttpNetworkSession::Params params;
+
+ clock_->AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
+ params.quic_clock = clock_;
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::CONFIRM_HANDSHAKE);
+ params.quic_crypto_client_stream_factory = &crypto_client_stream_factory_;
+
+ params.enable_quic = true;
+ params.quic_random = &random_generator_;
+ params.client_socket_factory = &socket_factory_;
+ params.host_resolver = &host_resolver_;
+ params.cert_verifier = &cert_verifier_;
+ params.transport_security_state = &transport_security_state_;
+ params.cert_transparency_verifier = cert_transparency_verifier_.get();
+ params.ct_policy_enforcer = &ct_policy_enforcer_;
+ params.socket_performance_watcher_factory =
+ &test_socket_performance_watcher_factory_;
+ params.ssl_config_service = ssl_config_service_.get();
+ params.proxy_service = proxy_service_.get();
+ params.http_auth_handler_factory = auth_handler_factory_.get();
+ params.http_server_properties = &http_server_properties_;
+ params.quic_supported_versions = SupportedVersions(version_);
+ params.quic_host_whitelist.insert("news.example.org");
+ params.quic_host_whitelist.insert("mail.example.org");
+ params.quic_host_whitelist.insert("mail.example.com");
+
+ session_.reset(new HttpNetworkSession(params));
+ session_->quic_stream_factory()->set_require_confirmation(true);
+ ASSERT_EQ(params.quic_socket_receive_buffer_size,
+ session_->quic_stream_factory()->socket_receive_buffer_size());
+ }
+
+ void TearDown() override {
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
+ // Empty the current queue.
+ base::RunLoop().RunUntilIdle();
+ PlatformTest::TearDown();
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
+ base::RunLoop().RunUntilIdle();
+ session_.reset();
+ }
+
+ void SetAlternativeService(const std::string& origin) {
+ HostPortPair destination;
+ switch (destination_type_) {
+ case SAME_AS_FIRST:
+ destination = HostPortPair(origin1_, 443);
+ break;
+ case SAME_AS_SECOND:
+ destination = HostPortPair(origin2_, 443);
+ break;
+ case DIFFERENT:
+ destination = HostPortPair(kDifferentHostname, 443);
+ break;
+ }
+ AlternativeService alternative_service(QUIC, destination);
+ base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
+ http_server_properties_.SetAlternativeService(
+ url::SchemeHostPort("https", origin, 443), alternative_service,
+ expiration);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool should_include_version,
+ QuicStreamOffset* offset,
+ QuicTestPacketMaker* maker) {
+ SpdyPriority priority =
+ ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY);
+ SpdyHeaderBlock headers(maker->GetRequestHeaders("GET", "https", "/"));
+ return maker->MakeRequestHeadersPacketWithOffsetTracking(
+ packet_number, stream_id, should_include_version, true, priority,
+ std::move(headers), offset);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool should_include_version,
+ QuicTestPacketMaker* maker) {
+ return ConstructClientRequestHeadersPacket(
+ packet_number, stream_id, should_include_version, nullptr, maker);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructServerResponseHeadersPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ QuicStreamOffset* offset,
+ QuicTestPacketMaker* maker) {
+ SpdyHeaderBlock headers(maker->GetResponseHeaders("200 OK"));
+ return maker->MakeResponseHeadersPacketWithOffsetTracking(
+ packet_number, stream_id, false, false, std::move(headers), offset);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructServerResponseHeadersPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ QuicTestPacketMaker* maker) {
+ return ConstructServerResponseHeadersPacket(packet_number, stream_id,
+ nullptr, maker);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructServerDataPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ QuicTestPacketMaker* maker) {
+ return maker->MakeDataPacket(packet_number, stream_id, false, true, 0,
+ "hello");
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructClientAckPacket(
+ QuicPacketNumber packet_number,
+ QuicPacketNumber largest_received,
+ QuicPacketNumber ack_least_unacked,
+ QuicPacketNumber stop_least_unacked,
+ QuicTestPacketMaker* maker) {
+ return maker->MakeAckPacket(packet_number, largest_received,
+ ack_least_unacked, stop_least_unacked, true);
+ }
+
+ void AddRefusedSocketData() {
+ std::unique_ptr<StaticSocketDataProvider> refused_data(
+ new StaticSocketDataProvider());
+ MockConnect refused_connect(SYNCHRONOUS, ERR_CONNECTION_REFUSED);
+ refused_data->set_connect_data(refused_connect);
+ socket_factory_.AddSocketDataProvider(refused_data.get());
+ static_socket_data_provider_vector_.push_back(std::move(refused_data));
+ }
+
+ void AddHangingSocketData() {
+ std::unique_ptr<StaticSocketDataProvider> hanging_data(
+ new StaticSocketDataProvider());
+ MockConnect hanging_connect(SYNCHRONOUS, ERR_IO_PENDING);
+ hanging_data->set_connect_data(hanging_connect);
+ socket_factory_.AddSocketDataProvider(hanging_data.get());
+ static_socket_data_provider_vector_.push_back(std::move(hanging_data));
+ socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
+ }
+
+ bool AllDataConsumed() {
+ for (const auto& socket_data_ptr : static_socket_data_provider_vector_) {
+ if (!socket_data_ptr->AllReadDataConsumed() ||
+ !socket_data_ptr->AllWriteDataConsumed()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void SendRequestAndExpectQuicResponse(const std::string& host) {
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ HttpRequestInfo request;
+ std::string url("https://");
+ url.append(host);
+ request.url = GURL(url);
+ request.load_flags = 0;
+ request.method = "GET";
+ TestCompletionCallback callback;
+ int rv = trans.Start(&request, callback.callback(), net_log_.bound());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
+
+ std::string response_data;
+ ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
+ EXPECT_EQ("hello", response_data);
+
+ const HttpResponseInfo* response = trans.GetResponseInfo();
+ ASSERT_TRUE(response != nullptr);
+ ASSERT_TRUE(response->headers.get() != nullptr);
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+ EXPECT_TRUE(response->was_fetched_via_spdy);
+ EXPECT_TRUE(response->was_alpn_negotiated);
+ EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_QUIC1_SPDY3,
+ response->connection_info);
+ EXPECT_EQ(443, response->socket_address.port());
+ }
+
+ MockClock* clock_;
+ QuicVersion version_;
+ DestinationType destination_type_;
+ std::string origin1_;
+ std::string origin2_;
+ std::unique_ptr<HttpNetworkSession> session_;
+ MockClientSocketFactory socket_factory_;
+ MockHostResolver host_resolver_;
+ MockCertVerifier cert_verifier_;
+ TransportSecurityState transport_security_state_;
+ std::unique_ptr<CTVerifier> cert_transparency_verifier_;
+ CTPolicyEnforcer ct_policy_enforcer_;
+ TestSocketPerformanceWatcherFactory test_socket_performance_watcher_factory_;
+ scoped_refptr<SSLConfigServiceDefaults> ssl_config_service_;
+ std::unique_ptr<ProxyService> proxy_service_;
+ std::unique_ptr<HttpAuthHandlerFactory> auth_handler_factory_;
+ MockRandom random_generator_;
+ HttpServerPropertiesImpl http_server_properties_;
+ BoundTestNetLog net_log_;
+ MockCryptoClientStreamFactory crypto_client_stream_factory_;
+ std::vector<std::unique_ptr<StaticSocketDataProvider>>
+ static_socket_data_provider_vector_;
+ SSLSocketDataProvider ssl_data_;
+};
+
+INSTANTIATE_TEST_CASE_P(Version,
+ QuicNetworkTransactionWithDestinationTest,
+ ::testing::ValuesIn(GetPoolingTestParams()));
+
+// A single QUIC request fails because the certificate does not match the origin
+// hostname, regardless of whether it matches the alternative service hostname.
+TEST_P(QuicNetworkTransactionWithDestinationTest, InvalidCertificate) {
+ if (destination_type_ == DIFFERENT)
+ return;
+
+ GURL url("https://mail.example.com/");
+ origin1_ = url.host();
+
+ // Not used for requests, but this provides a test case where the certificate
+ // is valid for the hostname of the alternative service.
+ origin2_ = "mail.example.org";
+
+ SetAlternativeService(origin1_);
+
+ scoped_refptr<X509Certificate> cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
+ bool unused;
+ ASSERT_FALSE(cert->VerifyNameMatch(origin1_, &unused));
+ ASSERT_TRUE(cert->VerifyNameMatch(origin2_, &unused));
+
+ 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;
+ mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING);
+ mock_quic_data.AddRead(ASYNC, 0);
+
+ mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+ AddRefusedSocketData();
+
+ HttpRequestInfo request;
+ request.url = url;
+
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+ TestCompletionCallback callback;
+ int rv = trans.Start(&request, callback.callback(), net_log_.bound());
+ EXPECT_THAT(callback.GetResult(rv), IsError(ERR_CONNECTION_REFUSED));
+
+ EXPECT_TRUE(AllDataConsumed());
+}
+
+// First request opens QUIC session to alternative service. Second request
+// pools to it, because destination matches and certificate is valid, even
+// though QuicServerId is different.
+TEST_P(QuicNetworkTransactionWithDestinationTest, PoolIfCertificateValid) {
+ origin1_ = "mail.example.org";
+ origin2_ = "news.example.org";
+
+ SetAlternativeService(origin1_);
+ SetAlternativeService(origin2_);
+
+ scoped_refptr<X509Certificate> cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
+ bool unused;
+ ASSERT_TRUE(cert->VerifyNameMatch(origin1_, &unused));
+ ASSERT_TRUE(cert->VerifyNameMatch(origin2_, &unused));
+ ASSERT_FALSE(cert->VerifyNameMatch(kDifferentHostname, &unused));
+
+ 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);
+
+ QuicTestPacketMaker client_maker1(version_, 0, clock_, origin1_,
+ Perspective::IS_CLIENT);
+ QuicTestPacketMaker server_maker1(version_, 0, clock_, origin1_,
+ Perspective::IS_SERVER);
+
+ QuicStreamOffset request_header_offset(0);
+ QuicStreamOffset response_header_offset(0);
+
+ MockQuicData mock_quic_data;
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, &request_header_offset, &client_maker1));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, &response_header_offset, &server_maker1));
+ mock_quic_data.AddRead(
+ ConstructServerDataPacket(2, kClientDataStreamId1, &server_maker1));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(2, 2, 1, 1, &client_maker1));
+
+ QuicTestPacketMaker client_maker2(version_, 0, clock_, origin2_,
+ Perspective::IS_CLIENT);
+ QuicTestPacketMaker server_maker2(version_, 0, clock_, origin2_,
+ Perspective::IS_SERVER);
+
+ mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+ 3, kClientDataStreamId2, false, &request_header_offset, &client_maker2));
+ mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+ 3, kClientDataStreamId2, &response_header_offset, &server_maker2));
+ mock_quic_data.AddRead(
+ ConstructServerDataPacket(4, kClientDataStreamId2, &server_maker2));
+ mock_quic_data.AddWrite(ConstructClientAckPacket(4, 4, 3, 1, &client_maker2));
+ 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_);
+
+ AddHangingSocketData();
+ AddHangingSocketData();
+
+ SendRequestAndExpectQuicResponse(origin1_);
+ SendRequestAndExpectQuicResponse(origin2_);
+
+ EXPECT_TRUE(AllDataConsumed());
+}
+
+// First request opens QUIC session to alternative service. Second request does
+// not pool to it, even though destination matches, because certificate is not
+// valid. Instead, a new QUIC session is opened to the same destination with a
+// different QuicServerId.
+TEST_P(QuicNetworkTransactionWithDestinationTest,
+ DoNotPoolIfCertificateInvalid) {
+ origin1_ = "news.example.org";
+ origin2_ = "mail.example.com";
+
+ SetAlternativeService(origin1_);
+ SetAlternativeService(origin2_);
+
+ scoped_refptr<X509Certificate> cert1(
+ ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
+ bool unused;
+ ASSERT_TRUE(cert1->VerifyNameMatch(origin1_, &unused));
+ ASSERT_FALSE(cert1->VerifyNameMatch(origin2_, &unused));
+ ASSERT_FALSE(cert1->VerifyNameMatch(kDifferentHostname, &unused));
+
+ scoped_refptr<X509Certificate> cert2(
+ ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"));
+ ASSERT_TRUE(cert2->VerifyNameMatch(origin2_, &unused));
+ ASSERT_FALSE(cert2->VerifyNameMatch(kDifferentHostname, &unused));
+
+ ProofVerifyDetailsChromium verify_details1;
+ verify_details1.cert_verify_result.verified_cert = cert1;
+ verify_details1.cert_verify_result.is_issued_by_known_root = true;
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details1);
+
+ ProofVerifyDetailsChromium verify_details2;
+ verify_details2.cert_verify_result.verified_cert = cert2;
+ 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 server_maker1(version_, 0, clock_, origin1_,
+ Perspective::IS_SERVER);
+
+ MockQuicData mock_quic_data1;
+ mock_quic_data1.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, &client_maker1));
+ mock_quic_data1.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, &server_maker1));
+ mock_quic_data1.AddRead(
+ ConstructServerDataPacket(2, kClientDataStreamId1, &server_maker1));
+ mock_quic_data1.AddWrite(
+ ConstructClientAckPacket(2, 2, 1, 1, &client_maker1));
+ mock_quic_data1.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read
+ mock_quic_data1.AddRead(ASYNC, 0); // EOF
+
+ mock_quic_data1.AddSocketDataToFactory(&socket_factory_);
+
+ AddHangingSocketData();
+
+ QuicTestPacketMaker client_maker2(version_, 0, clock_, origin2_,
+ Perspective::IS_CLIENT);
+ QuicTestPacketMaker server_maker2(version_, 0, clock_, origin2_,
+ Perspective::IS_SERVER);
+
+ MockQuicData mock_quic_data2;
+ mock_quic_data2.AddWrite(ConstructClientRequestHeadersPacket(
+ 1, kClientDataStreamId1, true, &client_maker2));
+ mock_quic_data2.AddRead(ConstructServerResponseHeadersPacket(
+ 1, kClientDataStreamId1, &server_maker2));
+ mock_quic_data2.AddRead(
+ ConstructServerDataPacket(2, kClientDataStreamId1, &server_maker2));
+ mock_quic_data2.AddWrite(
+ ConstructClientAckPacket(2, 2, 1, 1, &client_maker2));
+ 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_);
+
+ AddHangingSocketData();
+
+ SendRequestAndExpectQuicResponse(origin1_);
+ SendRequestAndExpectQuicResponse(origin2_);
+
+ EXPECT_TRUE(AllDataConsumed());
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_stream_factory.cc b/chromium/net/quic/chromium/quic_stream_factory.cc
new file mode 100644
index 00000000000..5bce4ac6ad5
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_stream_factory.cc
@@ -0,0 +1,1929 @@
+// 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/chromium/quic_stream_factory.h"
+
+#include <openssl/aead.h>
+
+#include <algorithm>
+#include <tuple>
+#include <utility>
+
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial.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/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
+#include "base/values.h"
+#include "crypto/openssl_util.h"
+#include "net/base/ip_address.h"
+#include "net/base/net_errors.h"
+#include "net/base/proxy_delegate.h"
+#include "net/cert/cert_verifier.h"
+#include "net/cert/ct_verifier.h"
+#include "net/dns/host_resolver.h"
+#include "net/http/bidirectional_stream_impl.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source_type.h"
+#include "net/quic/chromium/bidirectional_stream_quic_impl.h"
+#include "net/quic/chromium/crypto/channel_id_chromium.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/chromium/port_suggester.h"
+#include "net/quic/chromium/quic_chromium_alarm_factory.h"
+#include "net/quic/chromium/quic_chromium_connection_helper.h"
+#include "net/quic/chromium/quic_chromium_packet_reader.h"
+#include "net/quic/chromium/quic_chromium_packet_writer.h"
+#include "net/quic/core/crypto/proof_verifier.h"
+#include "net/quic/core/crypto/properties_based_quic_server_info.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/crypto/quic_server_info.h"
+#include "net/quic/core/quic_client_promised_info.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_crypto_client_stream_factory.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/socket/client_socket_factory.h"
+#include "net/socket/socket_performance_watcher.h"
+#include "net/socket/socket_performance_watcher_factory.h"
+#include "net/ssl/token_binding.h"
+#include "net/udp/udp_client_socket.h"
+#include "url/gurl.h"
+#include "url/url_constants.h"
+
+using std::min;
+using NetworkHandle = net::NetworkChangeNotifier::NetworkHandle;
+
+namespace net {
+
+namespace {
+
+enum CreateSessionFailure {
+ CREATION_ERROR_CONNECTING_SOCKET,
+ CREATION_ERROR_SETTING_RECEIVE_BUFFER,
+ CREATION_ERROR_SETTING_SEND_BUFFER,
+ CREATION_ERROR_SETTING_DO_NOT_FRAGMENT,
+ CREATION_ERROR_MAX
+};
+
+// The maximum receive window sizes for QUIC sessions and streams.
+const int32_t kQuicSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB
+const int32_t kQuicStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
+
+// Set the maximum number of undecryptable packets the connection will store.
+const int32_t kMaxUndecryptablePackets = 100;
+
+// How long QUIC will be disabled for because of timeouts with open streams.
+const int kDisableQuicTimeoutSecs = 5 * 60;
+
+std::unique_ptr<base::Value> NetLogQuicConnectionMigrationTriggerCallback(
+ std::string trigger,
+ NetLogCaptureMode capture_mode) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetString("trigger", trigger);
+ return std::move(dict);
+}
+
+std::unique_ptr<base::Value> NetLogQuicConnectionMigrationFailureCallback(
+ QuicConnectionId connection_id,
+ 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("reason", reason);
+ return std::move(dict);
+}
+
+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));
+ return std::move(dict);
+}
+
+// Helper class that is used to log a connection migration event.
+class ScopedConnectionMigrationEventLog {
+ public:
+ ScopedConnectionMigrationEventLog(NetLog* net_log, std::string trigger)
+ : net_log_(NetLogWithSource::Make(
+ net_log,
+ NetLogSourceType::QUIC_CONNECTION_MIGRATION)) {
+ net_log_.BeginEvent(
+ NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED,
+ base::Bind(&NetLogQuicConnectionMigrationTriggerCallback, trigger));
+ }
+
+ ~ScopedConnectionMigrationEventLog() {
+ net_log_.EndEvent(NetLogEventType::QUIC_CONNECTION_MIGRATION_TRIGGERED);
+ }
+
+ const NetLogWithSource& net_log() { return net_log_; }
+
+ private:
+ const NetLogWithSource net_log_;
+};
+
+void HistogramCreateSessionFailure(enum CreateSessionFailure error) {
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error,
+ CREATION_ERROR_MAX);
+}
+
+void HistogramAndLogMigrationFailure(const NetLogWithSource& net_log,
+ enum QuicConnectionMigrationStatus status,
+ QuicConnectionId connection_id,
+ std::string reason) {
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionMigration", status,
+ MIGRATION_STATUS_MAX);
+ net_log.AddEvent(NetLogEventType::QUIC_CONNECTION_MIGRATION_FAILURE,
+ base::Bind(&NetLogQuicConnectionMigrationFailureCallback,
+ connection_id, reason));
+}
+
+void HistogramMigrationStatus(enum QuicConnectionMigrationStatus status) {
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionMigration", status,
+ MIGRATION_STATUS_MAX);
+}
+
+QuicConfig InitializeQuicConfig(const QuicTagVector& connection_options,
+ int idle_connection_timeout_seconds) {
+ DCHECK_GT(idle_connection_timeout_seconds, 0);
+ QuicConfig config;
+ config.SetIdleConnectionStateLifetime(
+ QuicTime::Delta::FromSeconds(idle_connection_timeout_seconds),
+ QuicTime::Delta::FromSeconds(idle_connection_timeout_seconds));
+ config.SetConnectionOptionsToSend(connection_options);
+ return config;
+}
+
+// An implementation of QuicCryptoClientConfig::ServerIdFilter that wraps
+// an |origin_filter|.
+class ServerIdOriginFilter : public QuicCryptoClientConfig::ServerIdFilter {
+ public:
+ ServerIdOriginFilter(const base::Callback<bool(const GURL&)> origin_filter)
+ : origin_filter_(origin_filter) {}
+
+ bool Matches(const QuicServerId& server_id) const override {
+ if (origin_filter_.is_null())
+ return true;
+
+ GURL url(base::StringPrintf("%s%s%s:%d", url::kHttpsScheme,
+ url::kStandardSchemeSeparator,
+ server_id.host().c_str(), server_id.port()));
+ DCHECK(url.is_valid());
+ return origin_filter_.Run(url);
+ }
+
+ private:
+ const base::Callback<bool(const GURL&)> origin_filter_;
+};
+
+} // namespace
+
+// Responsible for verifying the certificates saved in
+// QuicCryptoClientConfig, and for notifying any associated requests when
+// complete. Results from cert verification are ignored.
+class QuicStreamFactory::CertVerifierJob {
+ public:
+ // ProofVerifierCallbackImpl is passed as the callback method to
+ // VerifyCertChain. The ProofVerifier calls this class with the result of cert
+ // verification when verification is performed asynchronously.
+ class ProofVerifierCallbackImpl : public ProofVerifierCallback {
+ public:
+ explicit ProofVerifierCallbackImpl(CertVerifierJob* job) : job_(job) {}
+
+ ~ProofVerifierCallbackImpl() override {}
+
+ void Run(bool ok,
+ const std::string& error_details,
+ std::unique_ptr<ProofVerifyDetails>* details) override {
+ if (job_ == nullptr)
+ return;
+ job_->verify_callback_ = nullptr;
+ job_->OnComplete();
+ }
+
+ void Cancel() { job_ = nullptr; }
+
+ private:
+ CertVerifierJob* job_;
+ };
+
+ CertVerifierJob(const QuicServerId& server_id,
+ int cert_verify_flags,
+ const NetLogWithSource& net_log)
+ : server_id_(server_id),
+ verify_callback_(nullptr),
+ verify_context_(base::WrapUnique(
+ new ProofVerifyContextChromium(cert_verify_flags, net_log))),
+ start_time_(base::TimeTicks::Now()),
+ net_log_(net_log),
+ weak_factory_(this) {}
+
+ ~CertVerifierJob() {
+ if (verify_callback_)
+ verify_callback_->Cancel();
+ }
+
+ // Starts verification of certs cached in the |crypto_config|.
+ QuicAsyncStatus Run(QuicCryptoClientConfig* crypto_config,
+ const CompletionCallback& callback) {
+ QuicCryptoClientConfig::CachedState* cached =
+ crypto_config->LookupOrCreate(server_id_);
+ ProofVerifierCallbackImpl* verify_callback =
+ new ProofVerifierCallbackImpl(this);
+ QuicAsyncStatus status = crypto_config->proof_verifier()->VerifyCertChain(
+ server_id_.host(), cached->certs(), verify_context_.get(),
+ &verify_error_details_, &verify_details_,
+ std::unique_ptr<ProofVerifierCallback>(verify_callback));
+ if (status == QUIC_PENDING) {
+ verify_callback_ = verify_callback;
+ callback_ = callback;
+ }
+ return status;
+ }
+
+ void OnComplete() {
+ UMA_HISTOGRAM_TIMES("Net.QuicSession.CertVerifierJob.CompleteTime",
+ base::TimeTicks::Now() - start_time_);
+ if (!callback_.is_null())
+ callback_.Run(OK);
+ }
+
+ const QuicServerId& server_id() const { return server_id_; }
+
+ private:
+ QuicServerId server_id_;
+ ProofVerifierCallbackImpl* verify_callback_;
+ std::unique_ptr<ProofVerifyContext> verify_context_;
+ std::unique_ptr<ProofVerifyDetails> verify_details_;
+ std::string verify_error_details_;
+ base::TimeTicks start_time_;
+ const NetLogWithSource net_log_;
+ CompletionCallback callback_;
+ base::WeakPtrFactory<CertVerifierJob> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(CertVerifierJob);
+};
+
+// Responsible for creating a new QUIC session to the specified server, and
+// for notifying any associated requests when complete.
+class QuicStreamFactory::Job {
+ public:
+ Job(QuicStreamFactory* factory,
+ HostResolver* host_resolver,
+ const QuicSessionKey& key,
+ bool was_alternative_service_recently_broken,
+ int cert_verify_flags,
+ QuicServerInfo* server_info,
+ const NetLogWithSource& net_log);
+
+ // Creates a new job to handle the resumption of for connecting an
+ // existing session.
+ Job(QuicStreamFactory* factory,
+ HostResolver* host_resolver,
+ QuicChromiumClientSession* session,
+ const QuicSessionKey& key);
+
+ ~Job();
+
+ int Run(const CompletionCallback& callback);
+
+ int DoLoop(int rv);
+ int DoResolveHost();
+ int DoResolveHostComplete(int rv);
+ int DoLoadServerInfo();
+ int DoLoadServerInfoComplete(int rv);
+ int DoConnect();
+ int DoResumeConnect();
+ int DoConnectComplete(int rv);
+
+ void OnIOComplete(int rv);
+
+ void RunAuxilaryJob();
+
+ void Cancel();
+
+ void CancelWaitForDataReadyCallback();
+
+ const QuicSessionKey& key() const { return key_; }
+
+ base::WeakPtr<Job> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
+
+ private:
+ enum IoState {
+ STATE_NONE,
+ STATE_RESOLVE_HOST,
+ STATE_RESOLVE_HOST_COMPLETE,
+ STATE_LOAD_SERVER_INFO,
+ STATE_LOAD_SERVER_INFO_COMPLETE,
+ STATE_CONNECT,
+ STATE_RESUME_CONNECT,
+ STATE_CONNECT_COMPLETE,
+ };
+ IoState io_state_;
+
+ QuicStreamFactory* factory_;
+ HostResolver* host_resolver_;
+ std::unique_ptr<HostResolver::Request> request_;
+ QuicSessionKey key_;
+ int cert_verify_flags_;
+ bool was_alternative_service_recently_broken_;
+ std::unique_ptr<QuicServerInfo> server_info_;
+ bool started_another_job_;
+ const NetLogWithSource net_log_;
+ int num_sent_client_hellos_;
+ QuicChromiumClientSession* session_;
+ CompletionCallback callback_;
+ AddressList address_list_;
+ base::TimeTicks dns_resolution_start_time_;
+ base::TimeTicks dns_resolution_end_time_;
+ base::WeakPtrFactory<Job> weak_factory_;
+ DISALLOW_COPY_AND_ASSIGN(Job);
+};
+
+QuicStreamFactory::Job::Job(QuicStreamFactory* factory,
+ HostResolver* host_resolver,
+ const QuicSessionKey& key,
+ bool was_alternative_service_recently_broken,
+ int cert_verify_flags,
+ QuicServerInfo* server_info,
+ const NetLogWithSource& net_log)
+ : io_state_(STATE_RESOLVE_HOST),
+ factory_(factory),
+ host_resolver_(host_resolver),
+ key_(key),
+ cert_verify_flags_(cert_verify_flags),
+ was_alternative_service_recently_broken_(
+ was_alternative_service_recently_broken),
+ server_info_(server_info),
+ started_another_job_(false),
+ net_log_(net_log),
+ num_sent_client_hellos_(0),
+ session_(nullptr),
+ weak_factory_(this) {}
+
+QuicStreamFactory::Job::Job(QuicStreamFactory* factory,
+ HostResolver* host_resolver,
+ QuicChromiumClientSession* session,
+ const QuicSessionKey& key)
+ : io_state_(STATE_RESUME_CONNECT),
+ factory_(factory),
+ host_resolver_(host_resolver), // unused
+ key_(key),
+ cert_verify_flags_(0), // unused
+ was_alternative_service_recently_broken_(false), // unused
+ started_another_job_(false), // unused
+ net_log_(session->net_log()), // unused
+ num_sent_client_hellos_(0),
+ session_(session),
+ weak_factory_(this) {}
+
+QuicStreamFactory::Job::~Job() {
+ // If disk cache has a pending WaitForDataReadyCallback, cancel that callback.
+ if (server_info_)
+ server_info_->ResetWaitForDataReadyCallback();
+}
+
+int QuicStreamFactory::Job::Run(const CompletionCallback& callback) {
+ int rv = DoLoop(OK);
+ if (rv == ERR_IO_PENDING)
+ callback_ = callback;
+
+ return rv > 0 ? OK : rv;
+}
+
+int QuicStreamFactory::Job::DoLoop(int rv) {
+ TRACE_EVENT0("net", "QuicStreamFactory::Job::DoLoop");
+ do {
+ IoState state = io_state_;
+ io_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_RESOLVE_HOST:
+ CHECK_EQ(OK, rv);
+ rv = DoResolveHost();
+ break;
+ case STATE_RESOLVE_HOST_COMPLETE:
+ rv = DoResolveHostComplete(rv);
+ break;
+ case STATE_LOAD_SERVER_INFO:
+ CHECK_EQ(OK, rv);
+ rv = DoLoadServerInfo();
+ break;
+ case STATE_LOAD_SERVER_INFO_COMPLETE:
+ rv = DoLoadServerInfoComplete(rv);
+ break;
+ case STATE_CONNECT:
+ CHECK_EQ(OK, rv);
+ rv = DoConnect();
+ break;
+ case STATE_RESUME_CONNECT:
+ CHECK_EQ(OK, rv);
+ rv = DoResumeConnect();
+ break;
+ case STATE_CONNECT_COMPLETE:
+ rv = DoConnectComplete(rv);
+ break;
+ default:
+ NOTREACHED() << "io_state_: " << io_state_;
+ break;
+ }
+ } while (io_state_ != STATE_NONE && rv != ERR_IO_PENDING);
+ return rv;
+}
+
+void QuicStreamFactory::Job::OnIOComplete(int rv) {
+ rv = DoLoop(rv);
+ if (rv != ERR_IO_PENDING && !callback_.is_null()) {
+ callback_.Run(rv);
+ }
+}
+
+void QuicStreamFactory::Job::RunAuxilaryJob() {
+ int rv = Run(base::Bind(&QuicStreamFactory::OnJobComplete,
+ base::Unretained(factory_), this));
+ if (rv != ERR_IO_PENDING)
+ factory_->OnJobComplete(this, rv);
+}
+
+void QuicStreamFactory::Job::Cancel() {
+ callback_.Reset();
+ if (session_)
+ session_->connection()->CloseConnection(
+ QUIC_CONNECTION_CANCELLED, "New job canceled.",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+}
+
+void QuicStreamFactory::Job::CancelWaitForDataReadyCallback() {
+ // If we are waiting for WaitForDataReadyCallback, then cancel the callback.
+ if (io_state_ != STATE_LOAD_SERVER_INFO_COMPLETE)
+ return;
+ server_info_->CancelWaitForDataReadyCallback();
+ OnIOComplete(OK);
+}
+
+int QuicStreamFactory::Job::DoResolveHost() {
+ dns_resolution_start_time_ = base::TimeTicks::Now();
+ // Start loading the data now, and wait for it after we resolve the host.
+ if (server_info_)
+ server_info_->Start();
+
+ io_state_ = STATE_RESOLVE_HOST_COMPLETE;
+ return host_resolver_->Resolve(
+ HostResolver::RequestInfo(key_.destination()), DEFAULT_PRIORITY,
+ &address_list_,
+ base::Bind(&QuicStreamFactory::Job::OnIOComplete, GetWeakPtr()),
+ &request_, net_log_);
+}
+
+int QuicStreamFactory::Job::DoResolveHostComplete(int rv) {
+ dns_resolution_end_time_ = base::TimeTicks::Now();
+ if (rv != OK)
+ return rv;
+
+ DCHECK(!factory_->HasActiveSession(key_.server_id()));
+
+ // Inform the factory of this resolution, which will set up
+ // a session alias, if possible.
+ if (factory_->OnResolution(key_, address_list_))
+ return OK;
+
+ if (server_info_)
+ io_state_ = STATE_LOAD_SERVER_INFO;
+ else
+ io_state_ = STATE_CONNECT;
+ return OK;
+}
+
+int QuicStreamFactory::Job::DoLoadServerInfo() {
+ io_state_ = STATE_LOAD_SERVER_INFO_COMPLETE;
+
+ DCHECK(server_info_);
+
+ // To mitigate the effects of disk cache taking too long to load QUIC server
+ // information, set up a timer to cancel WaitForDataReady's callback.
+ if (factory_->load_server_info_timeout_srtt_multiplier_ > 0) {
+ const int kMaxLoadServerInfoTimeoutMs = 50;
+ // Wait for DiskCache a maximum of 50ms.
+ int64_t load_server_info_timeout_ms =
+ std::min(static_cast<int>(
+ (factory_->load_server_info_timeout_srtt_multiplier_ *
+ factory_->GetServerNetworkStatsSmoothedRttInMicroseconds(
+ key_.server_id())) /
+ 1000),
+ kMaxLoadServerInfoTimeoutMs);
+ if (load_server_info_timeout_ms > 0) {
+ factory_->task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&QuicStreamFactory::Job::CancelWaitForDataReadyCallback,
+ GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(load_server_info_timeout_ms));
+ }
+ }
+
+ int rv = server_info_->WaitForDataReady(
+ base::Bind(&QuicStreamFactory::Job::OnIOComplete, GetWeakPtr()));
+ if (rv == ERR_IO_PENDING && factory_->enable_connection_racing()) {
+ // If we are waiting to load server config from the disk cache, then start
+ // another job.
+ started_another_job_ = true;
+ factory_->CreateAuxilaryJob(key_, cert_verify_flags_, net_log_);
+ }
+ return rv;
+}
+
+int QuicStreamFactory::Job::DoLoadServerInfoComplete(int rv) {
+ UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheWaitForDataReadyTime",
+ base::TimeTicks::Now() - dns_resolution_end_time_);
+
+ if (rv != OK)
+ server_info_.reset();
+
+ if (started_another_job_ &&
+ (!server_info_ || server_info_->state().server_config.empty() ||
+ !factory_->CryptoConfigCacheIsEmpty(key_.server_id()))) {
+ // If we have started another job and if we didn't load the server config
+ // from the disk cache or if we have received a new server config from the
+ // server, then cancel the current job.
+ io_state_ = STATE_NONE;
+ return ERR_CONNECTION_CLOSED;
+ }
+
+ io_state_ = STATE_CONNECT;
+ return OK;
+}
+
+int QuicStreamFactory::Job::DoConnect() {
+ io_state_ = STATE_CONNECT_COMPLETE;
+
+ int rv =
+ factory_->CreateSession(key_, cert_verify_flags_, std::move(server_info_),
+ address_list_, dns_resolution_start_time_,
+ dns_resolution_end_time_, net_log_, &session_);
+ if (rv != OK) {
+ DCHECK(rv != ERR_IO_PENDING);
+ DCHECK(!session_);
+ return rv;
+ }
+
+ if (!session_->connection()->connected())
+ return ERR_CONNECTION_CLOSED;
+
+ session_->StartReading();
+ if (!session_->connection()->connected())
+ return ERR_QUIC_PROTOCOL_ERROR;
+ bool require_confirmation = factory_->require_confirmation() ||
+ was_alternative_service_recently_broken_;
+
+ rv = session_->CryptoConnect(
+ require_confirmation,
+ base::Bind(&QuicStreamFactory::Job::OnIOComplete, GetWeakPtr()));
+
+ if (!session_->connection()->connected() &&
+ session_->error() == QUIC_PROOF_INVALID) {
+ return ERR_QUIC_HANDSHAKE_FAILED;
+ }
+
+ return rv;
+}
+
+int QuicStreamFactory::Job::DoResumeConnect() {
+ io_state_ = STATE_CONNECT_COMPLETE;
+
+ int rv = session_->ResumeCryptoConnect(
+ base::Bind(&QuicStreamFactory::Job::OnIOComplete, GetWeakPtr()));
+
+ return rv;
+}
+
+int QuicStreamFactory::Job::DoConnectComplete(int rv) {
+ if (session_ && session_->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
+ num_sent_client_hellos_ += session_->GetNumSentClientHellos();
+ if (num_sent_client_hellos_ >= QuicCryptoClientStream::kMaxClientHellos)
+ return ERR_QUIC_HANDSHAKE_FAILED;
+ // The handshake was rejected statelessly, so create another connection
+ // to resume the handshake.
+ io_state_ = STATE_CONNECT;
+ return OK;
+ }
+
+ if (was_alternative_service_recently_broken_)
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ConnectAfterBroken", rv == OK);
+
+ if (rv != OK)
+ return rv;
+
+ DCHECK(!factory_->HasActiveSession(key_.server_id()));
+ // There may well now be an active session for this IP. If so, use the
+ // existing session instead.
+ AddressList address(session_->connection()->peer_address());
+ if (factory_->OnResolution(key_, address)) {
+ session_->connection()->CloseConnection(
+ QUIC_CONNECTION_IP_POOLED, "An active session exists for the given IP.",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ session_ = nullptr;
+ return OK;
+ }
+
+ factory_->ActivateSession(key_, session_);
+
+ return OK;
+}
+
+QuicStreamRequest::QuicStreamRequest(QuicStreamFactory* factory)
+ : factory_(factory) {}
+
+QuicStreamRequest::~QuicStreamRequest() {
+ if (factory_ && !callback_.is_null())
+ factory_->CancelRequest(this);
+}
+
+int QuicStreamRequest::Request(const HostPortPair& destination,
+ PrivacyMode privacy_mode,
+ int cert_verify_flags,
+ const GURL& url,
+ base::StringPiece method,
+ const NetLogWithSource& net_log,
+ const CompletionCallback& callback) {
+ DCHECK(callback_.is_null());
+ DCHECK(factory_);
+ server_id_ = QuicServerId(HostPortPair::FromURL(url), privacy_mode);
+
+ int rv = factory_->Create(server_id_, destination, cert_verify_flags, url,
+ method, net_log, this);
+ if (rv == ERR_IO_PENDING) {
+ net_log_ = net_log;
+ callback_ = callback;
+ } else {
+ factory_ = nullptr;
+ }
+ if (rv == OK)
+ DCHECK(session_);
+ return rv;
+}
+
+void QuicStreamRequest::SetSession(QuicChromiumClientSession* session) {
+ DCHECK(session);
+ session_ = session->GetWeakPtr();
+}
+
+void QuicStreamRequest::OnRequestComplete(int rv) {
+ factory_ = nullptr;
+ callback_.Run(rv);
+}
+
+base::TimeDelta QuicStreamRequest::GetTimeDelayForWaitingJob() const {
+ if (!factory_)
+ return base::TimeDelta();
+ return factory_->GetTimeDelayForWaitingJob(server_id_);
+}
+
+std::unique_ptr<QuicHttpStream> QuicStreamRequest::CreateStream() {
+ if (!session_)
+ return nullptr;
+ return base::MakeUnique<QuicHttpStream>(session_);
+}
+
+std::unique_ptr<BidirectionalStreamImpl>
+QuicStreamRequest::CreateBidirectionalStreamImpl() {
+ if (!session_)
+ return nullptr;
+ return base::MakeUnique<BidirectionalStreamQuicImpl>(session_);
+}
+
+QuicStreamFactory::QuicStreamFactory(
+ NetLog* net_log,
+ HostResolver* host_resolver,
+ SSLConfigService* ssl_config_service,
+ ClientSocketFactory* client_socket_factory,
+ HttpServerProperties* http_server_properties,
+ ProxyDelegate* proxy_delegate,
+ CertVerifier* cert_verifier,
+ CTPolicyEnforcer* ct_policy_enforcer,
+ ChannelIDService* channel_id_service,
+ TransportSecurityState* transport_security_state,
+ CTVerifier* cert_transparency_verifier,
+ SocketPerformanceWatcherFactory* socket_performance_watcher_factory,
+ QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory,
+ QuicRandom* random_generator,
+ QuicClock* clock,
+ size_t max_packet_length,
+ const std::string& user_agent_id,
+ const QuicVersionVector& supported_versions,
+ bool enable_port_selection,
+ bool always_require_handshake_confirmation,
+ bool disable_connection_pooling,
+ float load_server_info_timeout_srtt_multiplier,
+ bool enable_connection_racing,
+ bool enable_non_blocking_io,
+ bool disable_disk_cache,
+ bool prefer_aes,
+ int socket_receive_buffer_size,
+ bool delay_tcp_race,
+ int max_server_configs_stored_in_properties,
+ bool close_sessions_on_ip_change,
+ bool disable_quic_on_timeout_with_open_streams,
+ int idle_connection_timeout_seconds,
+ int reduced_ping_timeout_seconds,
+ int packet_reader_yield_after_duration_milliseconds,
+ bool migrate_sessions_on_network_change,
+ bool migrate_sessions_early,
+ bool allow_server_migration,
+ bool force_hol_blocking,
+ bool race_cert_verification,
+ bool quic_do_not_fragment,
+ const QuicTagVector& connection_options,
+ bool enable_token_binding)
+ : require_confirmation_(true),
+ net_log_(net_log),
+ host_resolver_(host_resolver),
+ client_socket_factory_(client_socket_factory),
+ http_server_properties_(http_server_properties),
+ proxy_delegate_(proxy_delegate),
+ transport_security_state_(transport_security_state),
+ cert_transparency_verifier_(cert_transparency_verifier),
+ quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory),
+ random_generator_(random_generator),
+ clock_(clock),
+ max_packet_length_(max_packet_length),
+ socket_performance_watcher_factory_(socket_performance_watcher_factory),
+ config_(InitializeQuicConfig(connection_options,
+ idle_connection_timeout_seconds)),
+ crypto_config_(base::WrapUnique(
+ new ProofVerifierChromium(cert_verifier,
+ ct_policy_enforcer,
+ transport_security_state,
+ cert_transparency_verifier))),
+ supported_versions_(supported_versions),
+ enable_port_selection_(enable_port_selection),
+ always_require_handshake_confirmation_(
+ always_require_handshake_confirmation),
+ disable_connection_pooling_(disable_connection_pooling),
+ load_server_info_timeout_srtt_multiplier_(
+ load_server_info_timeout_srtt_multiplier),
+ enable_connection_racing_(enable_connection_racing),
+ enable_non_blocking_io_(enable_non_blocking_io),
+ disable_disk_cache_(disable_disk_cache),
+ prefer_aes_(prefer_aes),
+ disable_quic_on_timeout_with_open_streams_(
+ disable_quic_on_timeout_with_open_streams),
+ consecutive_disabled_count_(0),
+ need_to_evaluate_consecutive_disabled_count_(false),
+ socket_receive_buffer_size_(socket_receive_buffer_size),
+ delay_tcp_race_(delay_tcp_race),
+ ping_timeout_(QuicTime::Delta::FromSeconds(kPingTimeoutSecs)),
+ reduced_ping_timeout_(
+ QuicTime::Delta::FromSeconds(reduced_ping_timeout_seconds)),
+ yield_after_packets_(kQuicYieldAfterPacketsRead),
+ yield_after_duration_(QuicTime::Delta::FromMilliseconds(
+ packet_reader_yield_after_duration_milliseconds)),
+ close_sessions_on_ip_change_(close_sessions_on_ip_change),
+ migrate_sessions_on_network_change_(
+ migrate_sessions_on_network_change &&
+ NetworkChangeNotifier::AreNetworkHandlesSupported()),
+ migrate_sessions_early_(migrate_sessions_early &&
+ migrate_sessions_on_network_change_),
+ allow_server_migration_(allow_server_migration),
+ force_hol_blocking_(force_hol_blocking),
+ race_cert_verification_(race_cert_verification),
+ quic_do_not_fragment_(quic_do_not_fragment),
+ port_seed_(random_generator_->RandUint64()),
+ check_persisted_supports_quic_(true),
+ has_initialized_data_(false),
+ num_push_streams_created_(0),
+ status_(OPEN),
+ task_runner_(nullptr),
+ ssl_config_service_(ssl_config_service),
+ weak_factory_(this) {
+ if (ssl_config_service_.get())
+ ssl_config_service_->AddObserver(this);
+ DCHECK(transport_security_state_);
+ DCHECK(http_server_properties_);
+ crypto_config_.set_user_agent_id(user_agent_id);
+ crypto_config_.AddCanonicalSuffix(".c.youtube.com");
+ crypto_config_.AddCanonicalSuffix(".ggpht.com");
+ crypto_config_.AddCanonicalSuffix(".googlevideo.com");
+ crypto_config_.AddCanonicalSuffix(".googleusercontent.com");
+ // TODO(rtenneti): http://crbug.com/487355. Temporary fix for b/20760730 until
+ // channel_id_service is supported in cronet.
+ if (channel_id_service) {
+ crypto_config_.SetChannelIDSource(
+ new ChannelIDSourceChromium(channel_id_service));
+ }
+ if (enable_token_binding && channel_id_service)
+ crypto_config_.tb_key_params.push_back(kTB10);
+ crypto::EnsureOpenSSLInit();
+ bool has_aes_hardware_support = !!EVP_has_aes_hardware();
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.PreferAesGcm",
+ has_aes_hardware_support);
+ if (has_aes_hardware_support || prefer_aes_)
+ crypto_config_.PreferAesGcm();
+ // When disk cache is used to store the server configs, HttpCache code calls
+ // |set_quic_server_info_factory| if |quic_server_info_factory_| wasn't
+ // created.
+ if (max_server_configs_stored_in_properties > 0) {
+ quic_server_info_factory_.reset(
+ new PropertiesBasedQuicServerInfoFactory(http_server_properties_));
+ }
+
+ // migrate_sessions_early should only be set to true if
+ // migrate_sessions_on_network_change is set to true.
+ if (migrate_sessions_early)
+ DCHECK(migrate_sessions_on_network_change);
+ // close_sessions_on_ip_change and migrate_sessions_on_network_change should
+ // never be simultaneously set to true.
+ DCHECK(!(close_sessions_on_ip_change && migrate_sessions_on_network_change));
+
+ if (migrate_sessions_on_network_change_) {
+ NetworkChangeNotifier::AddNetworkObserver(this);
+ } else if (close_sessions_on_ip_change_) {
+ NetworkChangeNotifier::AddIPAddressObserver(this);
+ }
+}
+
+QuicStreamFactory::~QuicStreamFactory() {
+ CloseAllSessions(ERR_ABORTED, QUIC_CONNECTION_CANCELLED);
+ while (!all_sessions_.empty()) {
+ delete all_sessions_.begin()->first;
+ all_sessions_.erase(all_sessions_.begin());
+ }
+ while (!active_jobs_.empty()) {
+ const QuicServerId server_id = active_jobs_.begin()->first;
+ base::STLDeleteElements(&(active_jobs_[server_id]));
+ active_jobs_.erase(server_id);
+ }
+ while (!active_cert_verifier_jobs_.empty())
+ active_cert_verifier_jobs_.erase(active_cert_verifier_jobs_.begin());
+ if (ssl_config_service_.get())
+ ssl_config_service_->RemoveObserver(this);
+ if (migrate_sessions_on_network_change_) {
+ NetworkChangeNotifier::RemoveNetworkObserver(this);
+ } else if (close_sessions_on_ip_change_) {
+ NetworkChangeNotifier::RemoveIPAddressObserver(this);
+ }
+}
+
+void QuicStreamFactory::set_require_confirmation(bool require_confirmation) {
+ require_confirmation_ = require_confirmation;
+ if (!(local_address_ == IPEndPoint())) {
+ http_server_properties_->SetSupportsQuic(!require_confirmation,
+ local_address_.address());
+ }
+}
+
+bool QuicStreamFactory::ZeroRTTEnabledFor(const QuicServerId& quic_server_id) {
+ return !(require_confirmation_ || CryptoConfigCacheIsEmpty(quic_server_id));
+}
+
+base::TimeDelta QuicStreamFactory::GetTimeDelayForWaitingJob(
+ const QuicServerId& server_id) {
+ if (!delay_tcp_race_ || require_confirmation_)
+ return base::TimeDelta();
+ int64_t srtt =
+ 1.5 * GetServerNetworkStatsSmoothedRttInMicroseconds(server_id);
+ // Picked 300ms based on mean time from
+ // Net.QuicSession.HostResolution.HandshakeConfirmedTime histogram.
+ const int kDefaultRTT = 300 * kNumMicrosPerMilli;
+ if (!srtt)
+ srtt = kDefaultRTT;
+ return base::TimeDelta::FromMicroseconds(srtt);
+}
+
+void QuicStreamFactory::set_quic_server_info_factory(
+ QuicServerInfoFactory* quic_server_info_factory) {
+ quic_server_info_factory_.reset(quic_server_info_factory);
+}
+
+bool QuicStreamFactory::CanUseExistingSession(const QuicServerId& server_id,
+ const HostPortPair& destination) {
+ // TODO(zhongyi): delete active_sessions_.empty() checks once the
+ // android crash issue(crbug.com/498823) is resolved.
+ if (active_sessions_.empty())
+ return false;
+
+ if (base::ContainsKey(active_sessions_, server_id))
+ return true;
+
+ for (const auto& key_value : active_sessions_) {
+ QuicChromiumClientSession* session = key_value.second;
+ if (destination.Equals(all_sessions_[session].destination()) &&
+ session->CanPool(server_id.host(), server_id.privacy_mode())) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int QuicStreamFactory::Create(const QuicServerId& server_id,
+ const HostPortPair& destination,
+ int cert_verify_flags,
+ const GURL& url,
+ base::StringPiece method,
+ const NetLogWithSource& net_log,
+ QuicStreamRequest* request) {
+ DCHECK(server_id.host_port_pair().Equals(HostPortPair::FromURL(url)));
+ // Enforce session affinity for promised streams.
+ QuicClientPromisedInfo* promised =
+ push_promise_index_.GetPromised(url.spec());
+ if (promised) {
+ QuicChromiumClientSession* session =
+ static_cast<QuicChromiumClientSession*>(promised->session());
+ DCHECK(session);
+ if (session->server_id().privacy_mode() == server_id.privacy_mode()) {
+ request->SetSession(session);
+ ++num_push_streams_created_;
+ return OK;
+ }
+ // This should happen extremely rarely (if ever), but if somehow a
+ // request comes in with a mismatched privacy mode, consider the
+ // promise borked.
+ promised->Cancel();
+ }
+
+ // Use active session for |server_id| if such exists.
+ // TODO(rtenneti): crbug.com/498823 - delete active_sessions_.empty() checks.
+ if (!active_sessions_.empty()) {
+ SessionMap::iterator it = active_sessions_.find(server_id);
+ if (it != active_sessions_.end()) {
+ QuicChromiumClientSession* session = it->second;
+ request->SetSession(session);
+ return OK;
+ }
+ }
+
+ // Associate with active job to |server_id| if such exists.
+ if (HasActiveJob(server_id)) {
+ active_requests_[request] = server_id;
+ job_requests_map_[server_id].insert(request);
+ return ERR_IO_PENDING;
+ }
+
+ // Pool to active session to |destination| if possible.
+ if (!active_sessions_.empty() && !disable_connection_pooling_) {
+ for (const auto& key_value : active_sessions_) {
+ QuicChromiumClientSession* session = key_value.second;
+ if (destination.Equals(all_sessions_[session].destination()) &&
+ session->CanPool(server_id.host(), server_id.privacy_mode())) {
+ request->SetSession(session);
+ return OK;
+ }
+ }
+ }
+
+ // TODO(rtenneti): |task_runner_| is used by the Job. Initialize task_runner_
+ // in the constructor after WebRequestActionWithThreadsTest.* tests are fixed.
+ if (!task_runner_)
+ task_runner_ = base::ThreadTaskRunnerHandle::Get().get();
+
+ QuicServerInfo* quic_server_info = nullptr;
+ if (quic_server_info_factory_.get()) {
+ bool load_from_disk_cache = !disable_disk_cache_;
+ MaybeInitialize();
+ if (!base::ContainsKey(quic_supported_servers_at_startup_, destination)) {
+ // If there is no entry for QUIC, consider that as a new server and
+ // don't wait for Cache thread to load the data for that server.
+ load_from_disk_cache = false;
+ }
+ if (load_from_disk_cache && CryptoConfigCacheIsEmpty(server_id))
+ quic_server_info = quic_server_info_factory_->GetForServer(server_id);
+ }
+
+ ignore_result(StartCertVerifyJob(server_id, cert_verify_flags, net_log));
+
+ QuicSessionKey key(destination, server_id);
+ std::unique_ptr<Job> job(
+ new Job(this, host_resolver_, key, WasQuicRecentlyBroken(server_id),
+ cert_verify_flags, quic_server_info, net_log));
+ int rv = job->Run(base::Bind(&QuicStreamFactory::OnJobComplete,
+ base::Unretained(this), job.get()));
+ if (rv == ERR_IO_PENDING) {
+ active_requests_[request] = server_id;
+ job_requests_map_[server_id].insert(request);
+ active_jobs_[server_id].insert(job.release());
+ return rv;
+ }
+ if (rv == OK) {
+ // TODO(rtenneti): crbug.com/498823 - revert active_sessions_.empty()
+ // related changes.
+ if (active_sessions_.empty())
+ return ERR_QUIC_PROTOCOL_ERROR;
+ SessionMap::iterator it = active_sessions_.find(server_id);
+ DCHECK(it != active_sessions_.end());
+ if (it == active_sessions_.end())
+ return ERR_QUIC_PROTOCOL_ERROR;
+ QuicChromiumClientSession* session = it->second;
+ request->SetSession(session);
+ }
+ return rv;
+}
+
+QuicStreamFactory::QuicSessionKey::QuicSessionKey(
+ const HostPortPair& destination,
+ const QuicServerId& server_id)
+ : destination_(destination), server_id_(server_id) {}
+
+bool QuicStreamFactory::QuicSessionKey::operator<(
+ const QuicSessionKey& other) const {
+ return std::tie(destination_, server_id_) <
+ std::tie(other.destination_, other.server_id_);
+}
+
+bool QuicStreamFactory::QuicSessionKey::operator==(
+ const QuicSessionKey& other) const {
+ return destination_.Equals(other.destination_) &&
+ server_id_ == other.server_id_;
+}
+
+void QuicStreamFactory::CreateAuxilaryJob(const QuicSessionKey& key,
+ int cert_verify_flags,
+ const NetLogWithSource& net_log) {
+ Job* aux_job =
+ new Job(this, host_resolver_, key, WasQuicRecentlyBroken(key.server_id()),
+ cert_verify_flags, nullptr, net_log);
+ active_jobs_[key.server_id()].insert(aux_job);
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&QuicStreamFactory::Job::RunAuxilaryJob,
+ aux_job->GetWeakPtr()));
+}
+
+bool QuicStreamFactory::OnResolution(const QuicSessionKey& key,
+ const AddressList& address_list) {
+ const QuicServerId& server_id(key.server_id());
+ DCHECK(!HasActiveSession(server_id));
+ if (disable_connection_pooling_)
+ return false;
+ for (const IPEndPoint& address : address_list) {
+ if (!base::ContainsKey(ip_aliases_, address))
+ continue;
+
+ const SessionSet& sessions = ip_aliases_[address];
+ for (QuicChromiumClientSession* session : sessions) {
+ if (!session->CanPool(server_id.host(), server_id.privacy_mode()))
+ continue;
+ active_sessions_[server_id] = session;
+ session_aliases_[session].insert(key);
+ return true;
+ }
+ }
+ return false;
+}
+
+void QuicStreamFactory::OnJobComplete(Job* job, int rv) {
+ // Copy |server_id|, because |job| might be destroyed before this method
+ // returns.
+ const QuicServerId server_id(job->key().server_id());
+ if (rv != OK) {
+ JobSet* jobs = &(active_jobs_[server_id]);
+ if (jobs->size() > 1) {
+ // If there is another pending job, then we can delete this job and let
+ // the other job handle the request.
+ job->Cancel();
+ jobs->erase(job);
+ delete job;
+ return;
+ }
+ }
+
+ if (rv == OK) {
+ if (!always_require_handshake_confirmation_)
+ set_require_confirmation(false);
+
+ if (!job_requests_map_[server_id].empty()) {
+ SessionMap::iterator session_it = active_sessions_.find(server_id);
+ DCHECK(session_it != active_sessions_.end());
+ QuicChromiumClientSession* session = session_it->second;
+ for (QuicStreamRequest* request : job_requests_map_[server_id]) {
+ DCHECK(request->server_id() == server_id);
+ // Do not notify |request| yet.
+ request->SetSession(session);
+ }
+ }
+ }
+
+ while (!job_requests_map_[server_id].empty()) {
+ RequestSet::iterator it = job_requests_map_[server_id].begin();
+ QuicStreamRequest* request = *it;
+ job_requests_map_[server_id].erase(it);
+ active_requests_.erase(request);
+ // Even though we're invoking callbacks here, we don't need to worry
+ // about |this| being deleted, because the factory is owned by the
+ // profile which can not be deleted via callbacks.
+ request->OnRequestComplete(rv);
+ }
+
+ for (Job* other_job : active_jobs_[server_id]) {
+ if (other_job != job)
+ other_job->Cancel();
+ }
+
+ base::STLDeleteElements(&(active_jobs_[server_id]));
+ active_jobs_.erase(server_id);
+ job_requests_map_.erase(server_id);
+}
+
+void QuicStreamFactory::OnCertVerifyJobComplete(CertVerifierJob* job, int rv) {
+ active_cert_verifier_jobs_.erase(job->server_id());
+}
+
+std::unique_ptr<QuicHttpStream> QuicStreamFactory::CreateFromSession(
+ QuicChromiumClientSession* session) {
+ return std::unique_ptr<QuicHttpStream>(
+ new QuicHttpStream(session->GetWeakPtr()));
+}
+
+bool QuicStreamFactory::IsQuicDisabled() const {
+ return status_ != OPEN;
+}
+
+bool QuicStreamFactory::OnHandshakeConfirmed(
+ QuicChromiumClientSession* session) {
+ if (!IsQuicDisabled())
+ return false;
+
+ session->CloseSessionOnErrorAndNotifyFactoryLater(
+ ERR_ABORTED, QUIC_TIMEOUTS_WITH_OPEN_STREAMS);
+
+ return true;
+}
+
+void QuicStreamFactory::OnTcpJobCompleted(bool succeeded) {
+ if (status_ != CLOSED)
+ return;
+
+ // If QUIC connections are failing while TCP connections are working,
+ // then stop using QUIC. On the other hand if both QUIC and TCP are
+ // failing, then attempt to use QUIC again.
+ if (succeeded) {
+ status_ = DISABLED;
+ return;
+ }
+
+ status_ = OPEN;
+}
+
+void QuicStreamFactory::OnIdleSession(QuicChromiumClientSession* session) {}
+
+void QuicStreamFactory::OnSessionGoingAway(QuicChromiumClientSession* session) {
+ const AliasSet& aliases = session_aliases_[session];
+ for (AliasSet::const_iterator it = aliases.begin(); it != aliases.end();
+ ++it) {
+ const QuicServerId& server_id = it->server_id();
+ DCHECK(active_sessions_.count(server_id));
+ DCHECK_EQ(session, active_sessions_[server_id]);
+ // Track sessions which have recently gone away so that we can disable
+ // port suggestions.
+ if (session->goaway_received())
+ gone_away_aliases_.insert(*it);
+
+ active_sessions_.erase(server_id);
+ ProcessGoingAwaySession(session, server_id, true);
+ }
+ ProcessGoingAwaySession(session, all_sessions_[session].server_id(), false);
+ if (!aliases.empty()) {
+ DCHECK(base::ContainsKey(session_peer_ip_, session));
+ const IPEndPoint peer_address = session_peer_ip_[session];
+ ip_aliases_[peer_address].erase(session);
+ if (ip_aliases_[peer_address].empty())
+ ip_aliases_.erase(peer_address);
+ session_peer_ip_.erase(session);
+ }
+ session_aliases_.erase(session);
+}
+
+void QuicStreamFactory::OnSessionClosed(QuicChromiumClientSession* session) {
+ DCHECK_EQ(0u, session->GetNumActiveStreams());
+ OnSessionGoingAway(session);
+ delete session;
+ all_sessions_.erase(session);
+}
+
+void QuicStreamFactory::OnTimeoutWithOpenStreams() {
+ // Reduce PING timeout when connection times out with open stream.
+ if (ping_timeout_ > reduced_ping_timeout_) {
+ ping_timeout_ = reduced_ping_timeout_;
+ }
+ if (disable_quic_on_timeout_with_open_streams_) {
+ if (status_ == OPEN) {
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&QuicStreamFactory::OpenFactory,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromSeconds(kDisableQuicTimeoutSecs *
+ (1 << consecutive_disabled_count_)));
+ consecutive_disabled_count_++;
+ need_to_evaluate_consecutive_disabled_count_ = true;
+ }
+ status_ = CLOSED;
+ }
+}
+
+void QuicStreamFactory::CancelRequest(QuicStreamRequest* request) {
+ RequestMap::iterator request_it = active_requests_.find(request);
+ DCHECK(request_it != active_requests_.end());
+ const QuicServerId& server_id = request_it->second;
+ job_requests_map_[server_id].erase(request);
+ active_requests_.erase(request_it);
+}
+
+void QuicStreamFactory::CloseAllSessions(int error, QuicErrorCode quic_error) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseAllSessionsError", -error);
+ while (!active_sessions_.empty()) {
+ size_t initial_size = active_sessions_.size();
+ active_sessions_.begin()->second->CloseSessionOnError(error, quic_error);
+ DCHECK_NE(initial_size, active_sessions_.size());
+ }
+ while (!all_sessions_.empty()) {
+ size_t initial_size = all_sessions_.size();
+ all_sessions_.begin()->first->CloseSessionOnError(error, quic_error);
+ DCHECK_NE(initial_size, all_sessions_.size());
+ }
+ DCHECK(all_sessions_.empty());
+}
+
+std::unique_ptr<base::Value> QuicStreamFactory::QuicStreamFactoryInfoToValue()
+ const {
+ std::unique_ptr<base::ListValue> list(new base::ListValue());
+
+ for (SessionMap::const_iterator it = active_sessions_.begin();
+ it != active_sessions_.end(); ++it) {
+ const QuicServerId& server_id = it->first;
+ QuicChromiumClientSession* session = it->second;
+ const AliasSet& aliases = session_aliases_.find(session)->second;
+ // Only add a session to the list once.
+ if (server_id == aliases.begin()->server_id()) {
+ std::set<HostPortPair> hosts;
+ for (AliasSet::const_iterator alias_it = aliases.begin();
+ alias_it != aliases.end(); ++alias_it) {
+ hosts.insert(alias_it->server_id().host_port_pair());
+ }
+ list->Append(session->GetInfoAsValue(hosts));
+ }
+ }
+ return std::move(list);
+}
+
+void QuicStreamFactory::ClearCachedStatesInCryptoConfig(
+ const base::Callback<bool(const GURL&)>& origin_filter) {
+ ServerIdOriginFilter filter(origin_filter);
+ crypto_config_.ClearCachedStates(filter);
+}
+
+void QuicStreamFactory::OnIPAddressChanged() {
+ status_ = OPEN;
+ CloseAllSessions(ERR_NETWORK_CHANGED, QUIC_IP_ADDRESS_CHANGED);
+ set_require_confirmation(true);
+}
+
+void QuicStreamFactory::OnNetworkConnected(NetworkHandle network) {
+ status_ = OPEN;
+ ScopedConnectionMigrationEventLog scoped_event_log(net_log_,
+ "OnNetworkConnected");
+ QuicStreamFactory::SessionIdMap::iterator it = all_sessions_.begin();
+ // Sessions may be deleted while iterating through the map.
+ while (it != all_sessions_.end()) {
+ QuicChromiumClientSession* session = it->first;
+ ++it;
+ session->OnNetworkConnected(network, scoped_event_log.net_log());
+ }
+}
+
+void QuicStreamFactory::OnNetworkMadeDefault(NetworkHandle network) {
+ ScopedConnectionMigrationEventLog scoped_event_log(net_log_,
+ "OnNetworkMadeDefault");
+ DCHECK_NE(NetworkChangeNotifier::kInvalidNetworkHandle, network);
+ MaybeMigrateOrCloseSessions(network, /*close_if_cannot_migrate=*/false,
+ scoped_event_log.net_log());
+ set_require_confirmation(true);
+}
+
+void QuicStreamFactory::OnNetworkDisconnected(NetworkHandle network) {
+ ScopedConnectionMigrationEventLog scoped_event_log(net_log_,
+ "OnNetworkDisconnected");
+ NetworkHandle new_network = FindAlternateNetwork(network);
+ MaybeMigrateOrCloseSessions(new_network, /*close_if_cannot_migrate=*/true,
+ scoped_event_log.net_log());
+}
+
+// This method is expected to only be called when migrating from Cellular to
+// WiFi on Android, and should always be preceded by OnNetworkMadeDefault().
+void QuicStreamFactory::OnNetworkSoonToDisconnect(NetworkHandle network) {}
+
+NetworkHandle QuicStreamFactory::FindAlternateNetwork(
+ NetworkHandle old_network) {
+ // Find a new network that sessions bound to |old_network| can be migrated to.
+ NetworkChangeNotifier::NetworkList network_list;
+ NetworkChangeNotifier::GetConnectedNetworks(&network_list);
+ for (NetworkHandle new_network : network_list) {
+ if (new_network != old_network)
+ return new_network;
+ }
+ return NetworkChangeNotifier::kInvalidNetworkHandle;
+}
+
+void QuicStreamFactory::MaybeMigrateOrCloseSessions(
+ NetworkHandle new_network,
+ bool close_if_cannot_migrate,
+ const NetLogWithSource& net_log) {
+ QuicStreamFactory::SessionIdMap::iterator it = all_sessions_.begin();
+ while (it != all_sessions_.end()) {
+ QuicChromiumClientSession* session = it->first;
+ ++it;
+
+ // If session is already bound to |new_network|, move on.
+ if (session->GetDefaultSocket()->GetBoundNetwork() == new_network) {
+ HistogramAndLogMigrationFailure(
+ net_log, MIGRATION_STATUS_ALREADY_MIGRATED, session->connection_id(),
+ "Already bound to new network");
+ continue;
+ }
+
+ // Close idle sessions.
+ if (session->GetNumActiveStreams() == 0) {
+ HistogramAndLogMigrationFailure(
+ net_log, MIGRATION_STATUS_NO_MIGRATABLE_STREAMS,
+ session->connection_id(), "No active sessions");
+ session->CloseSessionOnError(
+ ERR_NETWORK_CHANGED, QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS);
+ continue;
+ }
+
+ // If session has active streams, mark it as going away.
+ OnSessionGoingAway(session);
+
+ // Do not migrate sessions where connection migration is disabled.
+ if (session->config()->DisableConnectionMigration()) {
+ HistogramAndLogMigrationFailure(net_log, MIGRATION_STATUS_DISABLED,
+ session->connection_id(),
+ "Migration disabled");
+ if (close_if_cannot_migrate) {
+ session->CloseSessionOnError(ERR_NETWORK_CHANGED,
+ QUIC_IP_ADDRESS_CHANGED);
+ }
+ continue;
+ }
+
+ // Do not migrate sessions with non-migratable streams.
+ if (session->HasNonMigratableStreams()) {
+ HistogramAndLogMigrationFailure(
+ net_log, MIGRATION_STATUS_NON_MIGRATABLE_STREAM,
+ session->connection_id(), "Non-migratable stream");
+ if (close_if_cannot_migrate) {
+ session->CloseSessionOnError(
+ ERR_NETWORK_CHANGED,
+ QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM);
+ }
+ continue;
+ }
+
+ // No new network was found. Notify session, so it can wait for a
+ // new network.
+ if (new_network == NetworkChangeNotifier::kInvalidNetworkHandle) {
+ session->OnNoNewNetwork();
+ continue;
+ }
+
+ MigrateSessionToNewNetwork(session, new_network,
+ /*close_session_on_error=*/true, net_log);
+ }
+}
+
+MigrationResult QuicStreamFactory::MaybeMigrateSingleSession(
+ QuicChromiumClientSession* session,
+ MigrationCause migration_cause) {
+ ScopedConnectionMigrationEventLog scoped_event_log(
+ net_log_,
+ migration_cause == EARLY_MIGRATION ? "EarlyMigration" : "WriteError");
+ if (!migrate_sessions_on_network_change_ ||
+ (migration_cause == EARLY_MIGRATION && !migrate_sessions_early_) ||
+ session->HasNonMigratableStreams() ||
+ session->config()->DisableConnectionMigration()) {
+ HistogramAndLogMigrationFailure(
+ scoped_event_log.net_log(), MIGRATION_STATUS_DISABLED,
+ session->connection_id(), "Migration disabled");
+ return MigrationResult::FAILURE;
+ }
+ NetworkHandle new_network =
+ FindAlternateNetwork(session->GetDefaultSocket()->GetBoundNetwork());
+ if (new_network == NetworkChangeNotifier::kInvalidNetworkHandle) {
+ // No alternate network found.
+ HistogramAndLogMigrationFailure(
+ scoped_event_log.net_log(), MIGRATION_STATUS_NO_ALTERNATE_NETWORK,
+ session->connection_id(), "No alternate network found");
+ return MigrationResult::NO_NEW_NETWORK;
+ }
+ OnSessionGoingAway(session);
+ return MigrateSessionToNewNetwork(session, new_network,
+ migration_cause != WRITE_ERROR,
+ scoped_event_log.net_log());
+}
+
+void QuicStreamFactory::MigrateSessionToNewPeerAddress(
+ QuicChromiumClientSession* session,
+ IPEndPoint peer_address,
+ const NetLogWithSource& net_log) {
+ if (!allow_server_migration_)
+ return;
+
+ IPEndPoint old_address;
+ session->GetDefaultSocket()->GetPeerAddress(&old_address);
+ DCHECK_EQ(old_address.GetFamily(), peer_address.GetFamily());
+
+ // Specifying kInvalidNetworkHandle for the |network| parameter
+ // causes the session to use the default network for the new socket.
+ MigrateSessionInner(session, peer_address,
+ NetworkChangeNotifier::kInvalidNetworkHandle,
+ /*close_session_on_error=*/true, net_log);
+}
+
+MigrationResult QuicStreamFactory::MigrateSessionToNewNetwork(
+ QuicChromiumClientSession* session,
+ NetworkHandle network,
+ bool close_session_on_error,
+ const NetLogWithSource& net_log) {
+ return MigrateSessionInner(session, session->connection()->peer_address(),
+ network, close_session_on_error, net_log);
+}
+
+MigrationResult QuicStreamFactory::MigrateSessionInner(
+ QuicChromiumClientSession* session,
+ IPEndPoint peer_address,
+ NetworkHandle network,
+ bool close_session_on_error,
+ const NetLogWithSource& net_log) {
+ // Use OS-specified port for socket (DEFAULT_BIND) instead of
+ // using the PortSuggester since the connection is being migrated
+ // and not being newly created.
+ std::unique_ptr<DatagramClientSocket> socket(
+ client_socket_factory_->CreateDatagramClientSocket(
+ DatagramSocket::DEFAULT_BIND, RandIntCallback(),
+ session->net_log().net_log(), session->net_log().source()));
+ if (ConfigureSocket(socket.get(), peer_address, network) != OK) {
+ HistogramAndLogMigrationFailure(net_log, MIGRATION_STATUS_INTERNAL_ERROR,
+ session->connection_id(),
+ "Socket configuration failed");
+ if (close_session_on_error) {
+ session->CloseSessionOnError(ERR_NETWORK_CHANGED, QUIC_INTERNAL_ERROR);
+ }
+ return MigrationResult::FAILURE;
+ }
+ std::unique_ptr<QuicChromiumPacketReader> new_reader(
+ new QuicChromiumPacketReader(socket.get(), clock_.get(), session,
+ yield_after_packets_, yield_after_duration_,
+ session->net_log()));
+ std::unique_ptr<QuicChromiumPacketWriter> new_writer(
+ new QuicChromiumPacketWriter(socket.get()));
+ new_writer->set_delegate(session);
+
+ if (!session->MigrateToSocket(std::move(socket), std::move(new_reader),
+ std::move(new_writer))) {
+ HistogramAndLogMigrationFailure(net_log, MIGRATION_STATUS_TOO_MANY_CHANGES,
+ session->connection_id(),
+ "Too many migrations");
+ if (close_session_on_error) {
+ session->CloseSessionOnError(ERR_NETWORK_CHANGED,
+ QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES);
+ }
+ return MigrationResult::FAILURE;
+ }
+ HistogramMigrationStatus(MIGRATION_STATUS_SUCCESS);
+ net_log.AddEvent(NetLogEventType::QUIC_CONNECTION_MIGRATION_SUCCESS,
+ base::Bind(&NetLogQuicConnectionMigrationSuccessCallback,
+ session->connection_id()));
+ return MigrationResult::SUCCESS;
+}
+
+void QuicStreamFactory::OnSSLConfigChanged() {
+ CloseAllSessions(ERR_CERT_DATABASE_CHANGED, QUIC_CONNECTION_CANCELLED);
+}
+
+void QuicStreamFactory::OnCertAdded(const X509Certificate* cert) {
+ CloseAllSessions(ERR_CERT_DATABASE_CHANGED, QUIC_CONNECTION_CANCELLED);
+}
+
+void QuicStreamFactory::OnCACertChanged(const X509Certificate* cert) {
+ // We should flush the sessions if we removed trust from a
+ // cert, because a previously trusted server may have become
+ // untrusted.
+ //
+ // We should not flush the sessions if we added trust to a cert.
+ //
+ // Since the OnCACertChanged method doesn't tell us what
+ // kind of change it is, we have to flush the socket
+ // pools to be safe.
+ CloseAllSessions(ERR_CERT_DATABASE_CHANGED, QUIC_CONNECTION_CANCELLED);
+}
+
+bool QuicStreamFactory::HasActiveSession(const QuicServerId& server_id) const {
+ // TODO(rtenneti): crbug.com/498823 - delete active_sessions_.empty() check.
+ if (active_sessions_.empty())
+ return false;
+ return base::ContainsKey(active_sessions_, server_id);
+}
+
+bool QuicStreamFactory::HasActiveJob(const QuicServerId& server_id) const {
+ return base::ContainsKey(active_jobs_, server_id);
+}
+
+bool QuicStreamFactory::HasActiveCertVerifierJob(
+ const QuicServerId& server_id) const {
+ return base::ContainsKey(active_cert_verifier_jobs_, server_id);
+}
+
+int QuicStreamFactory::ConfigureSocket(DatagramClientSocket* socket,
+ IPEndPoint addr,
+ NetworkHandle network) {
+ if (enable_non_blocking_io_)
+ socket->UseNonBlockingIO();
+
+ int rv;
+ if (migrate_sessions_on_network_change_) {
+ // If caller leaves network unspecified, use current default network.
+ if (network == NetworkChangeNotifier::kInvalidNetworkHandle) {
+ rv = socket->ConnectUsingDefaultNetwork(addr);
+ } else {
+ rv = socket->ConnectUsingNetwork(network, addr);
+ }
+ } else {
+ rv = socket->Connect(addr);
+ }
+ if (rv != OK) {
+ HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET);
+ return rv;
+ }
+
+ rv = socket->SetReceiveBufferSize(socket_receive_buffer_size_);
+ if (rv != OK) {
+ HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER);
+ return rv;
+ }
+
+ if (quic_do_not_fragment_) {
+ rv = socket->SetDoNotFragment();
+ // SetDoNotFragment is not implemented on all platforms, so ignore errors.
+ if (rv != OK && rv != ERR_NOT_IMPLEMENTED) {
+ HistogramCreateSessionFailure(CREATION_ERROR_SETTING_DO_NOT_FRAGMENT);
+ return rv;
+ }
+ }
+
+ // Set a buffer large enough to contain the initial CWND's worth of packet
+ // to work around the problem with CHLO packets being sent out with the
+ // wrong encryption level, when the send buffer is full.
+ rv = socket->SetSendBufferSize(kMaxPacketSize * 20);
+ if (rv != OK) {
+ HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER);
+ return rv;
+ }
+
+ socket->GetLocalAddress(&local_address_);
+ if (check_persisted_supports_quic_) {
+ check_persisted_supports_quic_ = false;
+ IPAddress last_address;
+ if (http_server_properties_->GetSupportsQuic(&last_address) &&
+ last_address == local_address_.address()) {
+ require_confirmation_ = false;
+ }
+ }
+
+ return OK;
+}
+
+int QuicStreamFactory::CreateSession(
+ const QuicSessionKey& key,
+ int cert_verify_flags,
+ std::unique_ptr<QuicServerInfo> server_info,
+ const AddressList& address_list,
+ base::TimeTicks dns_resolution_start_time,
+ base::TimeTicks dns_resolution_end_time,
+ const NetLogWithSource& net_log,
+ QuicChromiumClientSession** session) {
+ if (need_to_evaluate_consecutive_disabled_count_) {
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&QuicStreamFactory::MaybeClearConsecutiveDisabledCount,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromSeconds(kDisableQuicTimeoutSecs));
+
+ need_to_evaluate_consecutive_disabled_count_ = false;
+ }
+ TRACE_EVENT0("net", "QuicStreamFactory::CreateSession");
+ IPEndPoint addr = *address_list.begin();
+ bool enable_port_selection = enable_port_selection_;
+ if (enable_port_selection && base::ContainsKey(gone_away_aliases_, key)) {
+ // Disable port selection when the server is going away.
+ // There is no point in trying to return to the same server, if
+ // that server is no longer handling requests.
+ enable_port_selection = false;
+ gone_away_aliases_.erase(key);
+ }
+ const QuicServerId& server_id = key.server_id();
+ scoped_refptr<PortSuggester> port_suggester =
+ new PortSuggester(server_id.host_port_pair(), port_seed_);
+ DatagramSocket::BindType bind_type =
+ enable_port_selection ? DatagramSocket::RANDOM_BIND
+ : // Use our callback.
+ DatagramSocket::DEFAULT_BIND; // Use OS to randomize.
+
+ std::unique_ptr<DatagramClientSocket> socket(
+ client_socket_factory_->CreateDatagramClientSocket(
+ bind_type, base::Bind(&PortSuggester::SuggestPort, port_suggester),
+ net_log.net_log(), net_log.source()));
+
+ // Passing in kInvalidNetworkHandle binds socket to default network.
+ int rv = ConfigureSocket(socket.get(), addr,
+ NetworkChangeNotifier::kInvalidNetworkHandle);
+ if (rv != OK)
+ return rv;
+
+ if (enable_port_selection)
+ DCHECK_LE(1u, port_suggester->call_count());
+ else
+ DCHECK_EQ(0u, port_suggester->call_count());
+
+ if (!helper_.get()) {
+ helper_.reset(
+ new QuicChromiumConnectionHelper(clock_.get(), random_generator_));
+ }
+
+ if (!alarm_factory_.get()) {
+ alarm_factory_.reset(new QuicChromiumAlarmFactory(
+ base::ThreadTaskRunnerHandle::Get().get(), clock_.get()));
+ }
+ QuicConnectionId connection_id = random_generator_->RandUint64();
+ InitializeCachedStateInCryptoConfig(server_id, server_info, &connection_id);
+
+ QuicChromiumPacketWriter* writer = new QuicChromiumPacketWriter(socket.get());
+ QuicConnection* connection = new QuicConnection(
+ connection_id, addr, helper_.get(), alarm_factory_.get(), writer,
+ true /* owns_writer */, Perspective::IS_CLIENT, supported_versions_);
+ connection->set_ping_timeout(ping_timeout_);
+ connection->SetMaxPacketLength(max_packet_length_);
+
+ QuicConfig config = config_;
+ config.SetSocketReceiveBufferToSend(socket_receive_buffer_size_);
+ config.set_max_undecryptable_packets(kMaxUndecryptablePackets);
+ config.SetInitialSessionFlowControlWindowToSend(
+ kQuicSessionMaxRecvWindowSize);
+ config.SetInitialStreamFlowControlWindowToSend(kQuicStreamMaxRecvWindowSize);
+ int64_t srtt = GetServerNetworkStatsSmoothedRttInMicroseconds(server_id);
+ if (srtt > 0)
+ config.SetInitialRoundTripTimeUsToSend(static_cast<uint32_t>(srtt));
+ config.SetBytesForConnectionIdToSend(0);
+
+ if (force_hol_blocking_)
+ config.SetForceHolBlocking();
+
+ if (quic_server_info_factory_.get() && !server_info) {
+ // Start the disk cache loading so that we can persist the newer QUIC server
+ // information and/or inform the disk cache that we have reused
+ // |server_info|.
+ server_info.reset(quic_server_info_factory_->GetForServer(server_id));
+ server_info->Start();
+ }
+
+ // Use the factory to create a new socket performance watcher, and pass the
+ // ownership to QuicChromiumClientSession.
+ std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher;
+ if (socket_performance_watcher_factory_) {
+ socket_performance_watcher =
+ socket_performance_watcher_factory_->CreateSocketPerformanceWatcher(
+ SocketPerformanceWatcherFactory::PROTOCOL_QUIC);
+ }
+
+ *session = new QuicChromiumClientSession(
+ connection, std::move(socket), this, quic_crypto_client_stream_factory_,
+ clock_.get(), transport_security_state_, std::move(server_info),
+ server_id, yield_after_packets_, yield_after_duration_, cert_verify_flags,
+ config, &crypto_config_, network_connection_.GetDescription(),
+ dns_resolution_start_time, dns_resolution_end_time, &push_promise_index_,
+ task_runner_, std::move(socket_performance_watcher), net_log.net_log());
+
+ all_sessions_[*session] = key; // owning pointer
+ writer->set_delegate(*session);
+
+ (*session)->Initialize();
+ bool closed_during_initialize = !base::ContainsKey(all_sessions_, *session) ||
+ !(*session)->connection()->connected();
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ClosedDuringInitializeSession",
+ closed_during_initialize);
+ if (closed_during_initialize) {
+ DLOG(DFATAL) << "Session closed during initialize";
+ *session = nullptr;
+ return ERR_CONNECTION_CLOSED;
+ }
+ return OK;
+}
+
+void QuicStreamFactory::ActivateSession(const QuicSessionKey& key,
+ QuicChromiumClientSession* session) {
+ const QuicServerId& server_id(key.server_id());
+ DCHECK(!HasActiveSession(server_id));
+ UMA_HISTOGRAM_COUNTS("Net.QuicActiveSessions", active_sessions_.size());
+ active_sessions_[server_id] = session;
+ session_aliases_[session].insert(key);
+ const IPEndPoint peer_address = session->connection()->peer_address();
+ DCHECK(!base::ContainsKey(ip_aliases_[peer_address], session));
+ ip_aliases_[peer_address].insert(session);
+ DCHECK(!base::ContainsKey(session_peer_ip_, session));
+ session_peer_ip_[session] = peer_address;
+}
+
+int64_t QuicStreamFactory::GetServerNetworkStatsSmoothedRttInMicroseconds(
+ const QuicServerId& server_id) const {
+ url::SchemeHostPort server("https", server_id.host_port_pair().host(),
+ server_id.host_port_pair().port());
+ const ServerNetworkStats* stats =
+ http_server_properties_->GetServerNetworkStats(server);
+ if (stats == nullptr)
+ return 0;
+ return stats->srtt.InMicroseconds();
+}
+
+bool QuicStreamFactory::WasQuicRecentlyBroken(
+ const QuicServerId& server_id) const {
+ const AlternativeService alternative_service(QUIC,
+ server_id.host_port_pair());
+ return http_server_properties_->WasAlternativeServiceRecentlyBroken(
+ alternative_service);
+}
+
+bool QuicStreamFactory::CryptoConfigCacheIsEmpty(
+ const QuicServerId& server_id) {
+ QuicCryptoClientConfig::CachedState* cached =
+ crypto_config_.LookupOrCreate(server_id);
+ return cached->IsEmpty();
+}
+
+QuicAsyncStatus QuicStreamFactory::StartCertVerifyJob(
+ const QuicServerId& server_id,
+ int cert_verify_flags,
+ const NetLogWithSource& net_log) {
+ if (!race_cert_verification_)
+ return QUIC_FAILURE;
+ QuicCryptoClientConfig::CachedState* cached =
+ crypto_config_.LookupOrCreate(server_id);
+ if (!cached || cached->certs().empty() ||
+ HasActiveCertVerifierJob(server_id)) {
+ return QUIC_FAILURE;
+ }
+ std::unique_ptr<CertVerifierJob> cert_verifier_job(
+ new CertVerifierJob(server_id, cert_verify_flags, net_log));
+ QuicAsyncStatus status = cert_verifier_job->Run(
+ &crypto_config_,
+ base::Bind(&QuicStreamFactory::OnCertVerifyJobComplete,
+ base::Unretained(this), cert_verifier_job.get()));
+ if (status == QUIC_PENDING)
+ active_cert_verifier_jobs_[server_id] = std::move(cert_verifier_job);
+ return status;
+}
+
+void QuicStreamFactory::InitializeCachedStateInCryptoConfig(
+ const QuicServerId& server_id,
+ const std::unique_ptr<QuicServerInfo>& server_info,
+ QuicConnectionId* connection_id) {
+ QuicCryptoClientConfig::CachedState* cached =
+ crypto_config_.LookupOrCreate(server_id);
+ if (cached->has_server_designated_connection_id())
+ *connection_id = cached->GetNextServerDesignatedConnectionId();
+
+ if (!cached->IsEmpty())
+ return;
+
+ // |server_info| will be NULL, if a non-empty server config already exists in
+ // the memory cache.
+ if (!server_info)
+ return;
+
+ // TODO(rtenneti): Delete the following histogram after collecting stats.
+ // If the AlternativeServiceMap contained an entry for this host, check if
+ // the disk cache contained an entry for it.
+ if (base::ContainsKey(quic_supported_servers_at_startup_,
+ server_id.host_port_pair())) {
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicServerInfo.ExpectConfigMissingFromDiskCache",
+ server_info->state().server_config.empty());
+ }
+
+ cached->Initialize(server_info->state().server_config,
+ server_info->state().source_address_token,
+ server_info->state().certs, server_info->state().cert_sct,
+ server_info->state().chlo_hash,
+ server_info->state().server_config_sig, clock_->WallNow(),
+ QuicWallTime::Zero());
+}
+
+void QuicStreamFactory::MaybeInitialize() {
+ // We don't initialize data from HttpServerProperties in the constructor
+ // because HttpServerProperties has not yet initialized. We're guaranteed
+ // HttpServerProperties has been initialized by the first time a request is
+ // made.
+ if (has_initialized_data_)
+ return;
+
+ has_initialized_data_ = true;
+
+ // Query the proxy delegate for the default alternative proxy server.
+ ProxyServer default_alternative_proxy_server =
+ proxy_delegate_ ? proxy_delegate_->GetDefaultAlternativeProxy()
+ : ProxyServer();
+ if (default_alternative_proxy_server.is_quic()) {
+ quic_supported_servers_at_startup_.insert(
+ default_alternative_proxy_server.host_port_pair());
+ }
+
+ for (const std::pair<const url::SchemeHostPort, AlternativeServiceInfoVector>&
+ key_value : http_server_properties_->alternative_service_map()) {
+ HostPortPair host_port_pair(key_value.first.host(), key_value.first.port());
+ for (const AlternativeServiceInfo& alternative_service_info :
+ key_value.second) {
+ if (alternative_service_info.alternative_service.protocol == QUIC) {
+ quic_supported_servers_at_startup_.insert(host_port_pair);
+ break;
+ }
+ }
+ }
+
+ if (http_server_properties_->max_server_configs_stored_in_properties() == 0)
+ return;
+ // Create a temporary QuicServerInfo object to deserialize and to populate the
+ // in-memory crypto server config cache in the MRU order.
+ std::unique_ptr<QuicServerInfo> server_info;
+ CompletionCallback callback;
+ // Get the list of servers to be deserialized first because WaitForDataReady
+ // touches quic_server_info_map.
+ const QuicServerInfoMap& quic_server_info_map =
+ http_server_properties_->quic_server_info_map();
+ std::vector<QuicServerId> server_list;
+ for (const auto& key_value : quic_server_info_map)
+ server_list.push_back(key_value.first);
+ for (auto it = server_list.rbegin(); it != server_list.rend(); ++it) {
+ const QuicServerId& server_id = *it;
+ server_info.reset(quic_server_info_factory_->GetForServer(server_id));
+ if (server_info->WaitForDataReady(callback) == OK) {
+ DVLOG(1) << "Initialized server config for: " << server_id.ToString();
+ InitializeCachedStateInCryptoConfig(server_id, server_info, nullptr);
+ }
+ }
+}
+
+void QuicStreamFactory::ProcessGoingAwaySession(
+ QuicChromiumClientSession* session,
+ const QuicServerId& server_id,
+ bool session_was_active) {
+ if (!http_server_properties_)
+ return;
+
+ const QuicConnectionStats& stats = session->connection()->GetStats();
+ const AlternativeService alternative_service(QUIC,
+ server_id.host_port_pair());
+ if (session->IsCryptoHandshakeConfirmed()) {
+ http_server_properties_->ConfirmAlternativeService(alternative_service);
+ ServerNetworkStats network_stats;
+ network_stats.srtt = base::TimeDelta::FromMicroseconds(stats.srtt_us);
+ network_stats.bandwidth_estimate = stats.estimated_bandwidth;
+ url::SchemeHostPort server("https", server_id.host_port_pair().host(),
+ server_id.host_port_pair().port());
+ http_server_properties_->SetServerNetworkStats(server, network_stats);
+ return;
+ }
+
+ UMA_HISTOGRAM_COUNTS("Net.QuicHandshakeNotConfirmedNumPacketsReceived",
+ stats.packets_received);
+
+ if (!session_was_active)
+ return;
+
+ // TODO(rch): In the special case where the session has received no
+ // packets from the peer, we should consider blacklisting this
+ // differently so that we still race TCP but we don't consider the
+ // session connected until the handshake has been confirmed.
+ HistogramBrokenAlternateProtocolLocation(
+ BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_STREAM_FACTORY);
+
+ // Since the session was active, there's no longer an
+ // HttpStreamFactoryImpl::Job running which can mark it broken, unless the TCP
+ // job also fails. So to avoid not using QUIC when we otherwise could, we mark
+ // it as recently broken, which means that 0-RTT will be disabled but we'll
+ // still race.
+ http_server_properties_->MarkAlternativeServiceRecentlyBroken(
+ alternative_service);
+}
+
+void QuicStreamFactory::OpenFactory() {
+ status_ = OPEN;
+}
+
+void QuicStreamFactory::MaybeClearConsecutiveDisabledCount() {
+ if (status_ == OPEN)
+ consecutive_disabled_count_ = 0;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/chromium/quic_stream_factory.h b/chromium/net/quic/chromium/quic_stream_factory.h
new file mode 100644
index 00000000000..bfadfaf6daa
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_stream_factory.h
@@ -0,0 +1,665 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_STREAM_FACTORY_H_
+#define NET_QUIC_QUIC_STREAM_FACTORY_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <deque>
+#include <list>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/gtest_prod_util.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "net/base/address_list.h"
+#include "net/base/completion_callback.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/net_export.h"
+#include "net/base/network_change_notifier.h"
+#include "net/cert/cert_database.h"
+#include "net/http/http_server_properties.h"
+#include "net/http/http_stream_factory.h"
+#include "net/log/net_log_with_source.h"
+#include "net/proxy/proxy_server.h"
+#include "net/quic/chromium/network_connection.h"
+#include "net/quic/chromium/quic_chromium_client_session.h"
+#include "net/quic/chromium/quic_http_stream.h"
+#include "net/quic/core/quic_client_push_promise_index.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_crypto_stream.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/ssl/ssl_config_service.h"
+
+namespace base {
+class Value;
+}
+
+namespace net {
+
+class CTPolicyEnforcer;
+class CertVerifier;
+class ChannelIDService;
+class ClientSocketFactory;
+class CTVerifier;
+class HostResolver;
+class HttpServerProperties;
+class NetLog;
+class ProxyDelegate;
+class QuicClock;
+class QuicChromiumAlarmFactory;
+class QuicChromiumConnectionHelper;
+class QuicCryptoClientStreamFactory;
+class QuicRandom;
+class QuicServerInfo;
+class QuicServerInfoFactory;
+class QuicStreamFactory;
+class SocketPerformanceWatcherFactory;
+class TransportSecurityState;
+class BidirectionalStreamImpl;
+
+namespace test {
+class QuicStreamFactoryPeer;
+} // namespace test
+
+// When a connection is idle for 30 seconds it will be closed.
+const int kIdleConnectionTimeoutSeconds = 30;
+
+// Indicates cause when connection migration is triggered.
+enum MigrationCause {
+ EARLY_MIGRATION, // Migration due to path degradation.
+ WRITE_ERROR // Migration due to socket write error.
+};
+
+// Result of a session migration attempt.
+enum class MigrationResult {
+ SUCCESS, // Migration succeeded.
+ NO_NEW_NETWORK, // Migration failed since no new network was found.
+ FAILURE // Migration failed for other reasons.
+};
+
+enum QuicConnectionMigrationStatus {
+ MIGRATION_STATUS_NO_MIGRATABLE_STREAMS,
+ MIGRATION_STATUS_ALREADY_MIGRATED,
+ MIGRATION_STATUS_INTERNAL_ERROR,
+ MIGRATION_STATUS_TOO_MANY_CHANGES,
+ MIGRATION_STATUS_SUCCESS,
+ MIGRATION_STATUS_NON_MIGRATABLE_STREAM,
+ MIGRATION_STATUS_DISABLED,
+ MIGRATION_STATUS_NO_ALTERNATE_NETWORK,
+ MIGRATION_STATUS_MAX
+};
+
+// Encapsulates a pending request for a QuicHttpStream.
+// If the request is still pending when it is destroyed, it will
+// cancel the request with the factory.
+class NET_EXPORT_PRIVATE QuicStreamRequest {
+ public:
+ explicit QuicStreamRequest(QuicStreamFactory* factory);
+ ~QuicStreamRequest();
+
+ // |cert_verify_flags| is bitwise OR'd of CertVerifier::VerifyFlags and it is
+ // passed to CertVerifier::Verify.
+ // |destination| will be resolved and resulting IPEndPoint used to open a
+ // QuicConnection. This can be different than HostPortPair::FromURL(url).
+ int Request(const HostPortPair& destination,
+ PrivacyMode privacy_mode,
+ int cert_verify_flags,
+ const GURL& url,
+ base::StringPiece method,
+ const NetLogWithSource& net_log,
+ const CompletionCallback& callback);
+
+ void OnRequestComplete(int rv);
+
+ // Helper method that calls |factory_|'s GetTimeDelayForWaitingJob(). It
+ // returns the amount of time waiting job should be delayed.
+ base::TimeDelta GetTimeDelayForWaitingJob() const;
+
+ std::unique_ptr<QuicHttpStream> CreateStream();
+
+ std::unique_ptr<BidirectionalStreamImpl> CreateBidirectionalStreamImpl();
+
+ // Sets |session_|.
+ void SetSession(QuicChromiumClientSession* session);
+
+ const QuicServerId& server_id() const { return server_id_; }
+
+ const NetLogWithSource& net_log() const { return net_log_; }
+
+ private:
+ QuicStreamFactory* factory_;
+ QuicServerId server_id_;
+ NetLogWithSource net_log_;
+ CompletionCallback callback_;
+ base::WeakPtr<QuicChromiumClientSession> session_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicStreamRequest);
+};
+
+// A factory for creating new QuicHttpStreams on top of a pool of
+// QuicChromiumClientSessions.
+class NET_EXPORT_PRIVATE QuicStreamFactory
+ : public NetworkChangeNotifier::IPAddressObserver,
+ public NetworkChangeNotifier::NetworkObserver,
+ public SSLConfigService::Observer,
+ public CertDatabase::Observer {
+ public:
+ // This class encompasses |destination| and |server_id|.
+ // |destination| is a HostPortPair which is resolved
+ // and a QuicConnection is made to the resulting IP address.
+ // |server_id| identifies the origin of the request,
+ // the crypto handshake advertises |server_id.host()| to the server,
+ // and the certificate is also matched against |server_id.host()|.
+ class NET_EXPORT_PRIVATE QuicSessionKey {
+ public:
+ QuicSessionKey() = default;
+ QuicSessionKey(const HostPortPair& destination,
+ const QuicServerId& server_id);
+ ~QuicSessionKey() = default;
+
+ // Needed to be an element of std::set.
+ bool operator<(const QuicSessionKey& other) const;
+ bool operator==(const QuicSessionKey& other) const;
+
+ const HostPortPair& destination() const { return destination_; }
+ const QuicServerId& server_id() const { return server_id_; }
+
+ private:
+ HostPortPair destination_;
+ QuicServerId server_id_;
+ };
+
+ QuicStreamFactory(
+ NetLog* net_log,
+ HostResolver* host_resolver,
+ SSLConfigService* ssl_config_service,
+ ClientSocketFactory* client_socket_factory,
+ HttpServerProperties* http_server_properties,
+ ProxyDelegate* proxy_delegate,
+ CertVerifier* cert_verifier,
+ CTPolicyEnforcer* ct_policy_enforcer,
+ ChannelIDService* channel_id_service,
+ TransportSecurityState* transport_security_state,
+ CTVerifier* cert_transparency_verifier,
+ SocketPerformanceWatcherFactory* socket_performance_watcher_factory,
+ QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory,
+ QuicRandom* random_generator,
+ QuicClock* clock,
+ size_t max_packet_length,
+ const std::string& user_agent_id,
+ const QuicVersionVector& supported_versions,
+ bool enable_port_selection,
+ bool always_require_handshake_confirmation,
+ bool disable_connection_pooling,
+ float load_server_info_timeout_srtt_multiplier,
+ bool enable_connection_racing,
+ bool enable_non_blocking_io,
+ bool disable_disk_cache,
+ bool prefer_aes,
+ int socket_receive_buffer_size,
+ bool delay_tcp_race,
+ int max_server_configs_stored_in_properties,
+ bool close_sessions_on_ip_change,
+ bool disable_quic_on_timeout_with_open_streams,
+ int idle_connection_timeout_seconds,
+ int reduced_ping_timeout_seconds,
+ int packet_reader_yield_after_duration_milliseconds,
+ bool migrate_sessions_on_network_change,
+ bool migrate_sessions_early,
+ bool allow_server_migration,
+ bool force_hol_blocking,
+ bool race_cert_verification,
+ bool quic_do_not_fragment,
+ const QuicTagVector& connection_options,
+ bool enable_token_binding);
+ ~QuicStreamFactory() override;
+
+ // Returns true if there is an existing session for |server_id| or if the
+ // request can be pooled to an existing session to the IP address of
+ // |destination|.
+ bool CanUseExistingSession(const QuicServerId& server_id,
+ const HostPortPair& destination);
+
+ // Creates a new QuicHttpStream to |host_port_pair| which will be
+ // owned by |request|.
+ // If a matching session already exists, this method will return OK. If no
+ // matching session exists, this will return ERR_IO_PENDING and will invoke
+ // OnRequestComplete asynchronously.
+ int Create(const QuicServerId& server_id,
+ const HostPortPair& destination,
+ int cert_verify_flags,
+ const GURL& url,
+ base::StringPiece method,
+ const NetLogWithSource& net_log,
+ QuicStreamRequest* request);
+
+ // Called when the handshake for |session| is confirmed. If QUIC is disabled
+ // currently disabled, then it closes the connection and returns true.
+ bool OnHandshakeConfirmed(QuicChromiumClientSession* session);
+
+ // Called when a TCP job completes for an origin that QUIC potentially
+ // could be used for.
+ void OnTcpJobCompleted(bool succeeded);
+
+ // Returns true if QUIC is disabled.
+ bool IsQuicDisabled() const;
+
+ // Called by a session when it becomes idle.
+ void OnIdleSession(QuicChromiumClientSession* session);
+
+ // Called by a session when it is going away and no more streams should be
+ // created on it.
+ void OnSessionGoingAway(QuicChromiumClientSession* session);
+
+ // Called by a session after it shuts down.
+ void OnSessionClosed(QuicChromiumClientSession* session);
+
+ // Called by a session when it times out with open streams.
+ void OnTimeoutWithOpenStreams();
+
+ // Cancels a pending request.
+ void CancelRequest(QuicStreamRequest* request);
+
+ // Closes all current sessions with specified network and QUIC error codes.
+ void CloseAllSessions(int error, QuicErrorCode quic_error);
+
+ std::unique_ptr<base::Value> QuicStreamFactoryInfoToValue() const;
+
+ // Delete cached state objects in |crypto_config_|. If |origin_filter| is not
+ // null, only objects on matching origins will be deleted.
+ void ClearCachedStatesInCryptoConfig(
+ const base::Callback<bool(const GURL&)>& origin_filter);
+
+ // Helper method that configures a DatagramClientSocket. Socket is
+ // bound to the default network if the |network| param is
+ // NetworkChangeNotifier::kInvalidNetworkHandle.
+ // Returns net_error code.
+ int ConfigureSocket(DatagramClientSocket* socket,
+ IPEndPoint addr,
+ NetworkChangeNotifier::NetworkHandle network);
+
+ // Finds an alternative to |old_network| from the platform's list of connected
+ // networks. Returns NetworkChangeNotifier::kInvalidNetworkHandle if no
+ // alternative is found.
+ NetworkChangeNotifier::NetworkHandle FindAlternateNetwork(
+ NetworkChangeNotifier::NetworkHandle old_network);
+
+ // Method that initiates migration of active sessions to |new_network|.
+ // If |new_network| is a valid network, sessions that can migrate are
+ // migrated to |new_network|, and sessions not bound to |new_network|
+ // are left unchanged. Sessions with non-migratable streams are closed
+ // if |close_if_cannot_migrate| is true, and continue using their current
+ // network otherwise.
+ //
+ // If |new_network| is NetworkChangeNotifier::kInvalidNetworkHandle,
+ // there is no new network to migrate sessions onto, and all sessions are
+ // closed.
+ void MaybeMigrateOrCloseSessions(
+ NetworkChangeNotifier::NetworkHandle new_network,
+ bool close_if_cannot_migrate,
+ const NetLogWithSource& net_log);
+
+ // Method that initiates migration of |session| if |session| is
+ // active and if there is an alternate network than the one to which
+ // |session| is currently bound.
+ MigrationResult MaybeMigrateSingleSession(QuicChromiumClientSession* session,
+ MigrationCause migration_cause);
+
+ // Migrates |session| over to using |network|. If |network| is
+ // kInvalidNetworkHandle, default network is used.
+ MigrationResult MigrateSessionToNewNetwork(
+ QuicChromiumClientSession* session,
+ NetworkChangeNotifier::NetworkHandle network,
+ bool close_session_on_error,
+ const NetLogWithSource& net_log);
+
+ // Migrates |session| over to using |peer_address|. Causes a PING frame
+ // to be sent to the new peer address.
+ void MigrateSessionToNewPeerAddress(QuicChromiumClientSession* session,
+ IPEndPoint peer_address,
+ const NetLogWithSource& net_log);
+
+ // NetworkChangeNotifier::IPAddressObserver methods:
+
+ // Until the servers support roaming, close all connections when the local
+ // IP address changes.
+ void OnIPAddressChanged() override;
+
+ // NetworkChangeNotifier::NetworkObserver methods:
+ void OnNetworkConnected(
+ NetworkChangeNotifier::NetworkHandle network) override;
+ void OnNetworkDisconnected(
+ NetworkChangeNotifier::NetworkHandle network) override;
+ void OnNetworkSoonToDisconnect(
+ NetworkChangeNotifier::NetworkHandle network) override;
+ void OnNetworkMadeDefault(
+ NetworkChangeNotifier::NetworkHandle network) override;
+
+ // SSLConfigService::Observer methods:
+
+ // We perform the same flushing as described above when SSL settings change.
+ void OnSSLConfigChanged() override;
+
+ // CertDatabase::Observer methods:
+
+ // We close all sessions when certificate database is changed.
+ void OnCertAdded(const X509Certificate* cert) override;
+ void OnCACertChanged(const X509Certificate* cert) override;
+
+ bool require_confirmation() const { return require_confirmation_; }
+
+ void set_require_confirmation(bool require_confirmation);
+
+ bool ZeroRTTEnabledFor(const QuicServerId& server_id);
+
+ // It returns the amount of time waiting job should be delayed.
+ base::TimeDelta GetTimeDelayForWaitingJob(const QuicServerId& server_id);
+
+ QuicChromiumConnectionHelper* helper() { return helper_.get(); }
+
+ QuicChromiumAlarmFactory* alarm_factory() { return alarm_factory_.get(); }
+
+ bool enable_port_selection() const { return enable_port_selection_; }
+
+ bool has_quic_server_info_factory() {
+ return quic_server_info_factory_.get() != nullptr;
+ }
+
+ void set_quic_server_info_factory(
+ QuicServerInfoFactory* quic_server_info_factory);
+
+ bool enable_connection_racing() const { return enable_connection_racing_; }
+ void set_enable_connection_racing(bool enable_connection_racing) {
+ enable_connection_racing_ = enable_connection_racing;
+ }
+
+ int socket_receive_buffer_size() const { return socket_receive_buffer_size_; }
+
+ bool delay_tcp_race() const { return delay_tcp_race_; }
+
+ bool migrate_sessions_on_network_change() const {
+ return migrate_sessions_on_network_change_;
+ }
+
+ private:
+ class Job;
+ class CertVerifierJob;
+ friend class test::QuicStreamFactoryPeer;
+
+ typedef std::map<QuicServerId, QuicChromiumClientSession*> SessionMap;
+ typedef std::map<QuicChromiumClientSession*, QuicSessionKey> SessionIdMap;
+ typedef std::set<QuicSessionKey> AliasSet;
+ typedef std::map<QuicChromiumClientSession*, AliasSet> SessionAliasMap;
+ typedef std::set<QuicChromiumClientSession*> SessionSet;
+ typedef std::map<IPEndPoint, SessionSet> IPAliasMap;
+ typedef std::map<QuicChromiumClientSession*, IPEndPoint> SessionPeerIPMap;
+ typedef std::set<Job*> JobSet;
+ typedef std::map<QuicServerId, JobSet> JobMap;
+ typedef std::map<QuicStreamRequest*, QuicServerId> RequestMap;
+ typedef std::set<QuicStreamRequest*> RequestSet;
+ typedef std::map<QuicServerId, RequestSet> ServerIDRequestsMap;
+ typedef std::map<QuicServerId, std::unique_ptr<CertVerifierJob>>
+ CertVerifierJobMap;
+
+ enum FactoryStatus {
+ OPEN, // New streams may be created.
+ CLOSED, // No new streams may be created temporarily.
+ DISABLED // No more streams may be created until the network changes.
+ };
+
+ // Creates a job which doesn't wait for server config to be loaded from the
+ // disk cache. This job is started via a PostTask.
+ void CreateAuxilaryJob(const QuicSessionKey& key,
+ int cert_verify_flags,
+ const NetLogWithSource& net_log);
+
+ // Returns a newly created QuicHttpStream owned by the caller.
+ std::unique_ptr<QuicHttpStream> CreateFromSession(
+ QuicChromiumClientSession* session);
+
+ bool OnResolution(const QuicSessionKey& key, const AddressList& address_list);
+ void OnJobComplete(Job* job, int rv);
+ void OnCertVerifyJobComplete(CertVerifierJob* job, int rv);
+ bool HasActiveSession(const QuicServerId& server_id) const;
+ bool HasActiveJob(const QuicServerId& server_id) const;
+ bool HasActiveCertVerifierJob(const QuicServerId& server_id) const;
+ int CreateSession(const QuicSessionKey& key,
+ int cert_verify_flags,
+ std::unique_ptr<QuicServerInfo> quic_server_info,
+ const AddressList& address_list,
+ base::TimeTicks dns_resolution_start_time,
+ base::TimeTicks dns_resolution_end_time,
+ const NetLogWithSource& net_log,
+ QuicChromiumClientSession** session);
+ void ActivateSession(const QuicSessionKey& key,
+ QuicChromiumClientSession* session);
+
+ // Returns |srtt| in micro seconds from ServerNetworkStats. Returns 0 if there
+ // is no |http_server_properties_| or if |http_server_properties_| doesn't
+ // have ServerNetworkStats for the given |server_id|.
+ int64_t GetServerNetworkStatsSmoothedRttInMicroseconds(
+ const QuicServerId& server_id) const;
+
+ // Helper methods.
+ bool WasQuicRecentlyBroken(const QuicServerId& server_id) const;
+
+ bool CryptoConfigCacheIsEmpty(const QuicServerId& server_id);
+
+ // Starts an asynchronous job for cert verification if
+ // |race_cert_verification_| is enabled and if there are cached certs for the
+ // given |server_id|.
+ QuicAsyncStatus StartCertVerifyJob(const QuicServerId& server_id,
+ int cert_verify_flags,
+ const NetLogWithSource& net_log);
+
+ // Initializes the cached state associated with |server_id| in
+ // |crypto_config_| with the information in |server_info|. Populates
+ // |connection_id| with the next server designated connection id,
+ // if any, and otherwise leaves it unchanged.
+ void InitializeCachedStateInCryptoConfig(
+ const QuicServerId& server_id,
+ const std::unique_ptr<QuicServerInfo>& server_info,
+ QuicConnectionId* connection_id);
+
+ // Initialize |quic_supported_servers_at_startup_| with the list of servers
+ // that supported QUIC at start up and also initialize in-memory cache of
+ // QuicServerInfo objects from HttpServerProperties.
+ void MaybeInitialize();
+
+ void ProcessGoingAwaySession(QuicChromiumClientSession* session,
+ const QuicServerId& server_id,
+ bool was_session_active);
+
+ // Internal method that migrates |session| over to using
+ // |peer_address| and |network|. If |network| is
+ // kInvalidNetworkHandle, default network is used. If the migration
+ // fails and |close_session_on_error| is true, connection is closed.
+ MigrationResult MigrateSessionInner(
+ QuicChromiumClientSession* session,
+ IPEndPoint peer_address,
+ NetworkChangeNotifier::NetworkHandle network,
+ bool close_session_on_error,
+ const NetLogWithSource& net_log);
+
+ // Called to re-enable QUIC when QUIC has been disabled.
+ void OpenFactory();
+ // If QUIC has been working well after having been recently
+ // disabled, clear the |consecutive_disabled_count_|.
+ void MaybeClearConsecutiveDisabledCount();
+
+ bool require_confirmation_;
+ NetLog* net_log_;
+ HostResolver* host_resolver_;
+ ClientSocketFactory* client_socket_factory_;
+ HttpServerProperties* http_server_properties_;
+ ProxyDelegate* proxy_delegate_;
+ TransportSecurityState* transport_security_state_;
+ CTVerifier* cert_transparency_verifier_;
+ std::unique_ptr<QuicServerInfoFactory> quic_server_info_factory_;
+ QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory_;
+ QuicRandom* random_generator_;
+ std::unique_ptr<QuicClock> clock_;
+ const size_t max_packet_length_;
+
+ // Factory which is used to create socket performance watcher. A new watcher
+ // is created for every QUIC connection.
+ // |socket_performance_watcher_factory_| may be null.
+ SocketPerformanceWatcherFactory* socket_performance_watcher_factory_;
+
+ // The helper used for all connections.
+ std::unique_ptr<QuicChromiumConnectionHelper> helper_;
+
+ // The alarm factory used for all connections.
+ std::unique_ptr<QuicChromiumAlarmFactory> alarm_factory_;
+
+ // Contains owning pointers to all sessions that currently exist.
+ SessionIdMap all_sessions_;
+ // Contains non-owning pointers to currently active session
+ // (not going away session, once they're implemented).
+ SessionMap active_sessions_;
+ // Map from session to set of aliases that this session is known by.
+ SessionAliasMap session_aliases_;
+ // Map from IP address to sessions which are connected to this address.
+ IPAliasMap ip_aliases_;
+ // Map from session to its original peer IP address.
+ SessionPeerIPMap session_peer_ip_;
+
+ // Origins which have gone away recently.
+ AliasSet gone_away_aliases_;
+
+ const QuicConfig config_;
+ QuicCryptoClientConfig crypto_config_;
+
+ JobMap active_jobs_;
+ ServerIDRequestsMap job_requests_map_;
+ RequestMap active_requests_;
+
+ CertVerifierJobMap active_cert_verifier_jobs_;
+
+ QuicVersionVector supported_versions_;
+
+ // Determine if we should consistently select a client UDP port. If false,
+ // then we will just let the OS select a random client port for each new
+ // connection.
+ bool enable_port_selection_;
+
+ // Set if we always require handshake confirmation. If true, this will
+ // introduce at least one RTT for the handshake before the client sends data.
+ bool always_require_handshake_confirmation_;
+
+ // Set if we do not want connection pooling.
+ bool disable_connection_pooling_;
+
+ // Specifies the ratio between time to load QUIC server information from disk
+ // cache to 'smoothed RTT'. This ratio is used to calculate the timeout in
+ // milliseconds to wait for loading of QUIC server information. If we don't
+ // want to timeout, set |load_server_info_timeout_srtt_multiplier_| to 0.
+ float load_server_info_timeout_srtt_multiplier_;
+
+ // Set if we want to race connections - one connection that sends
+ // INCHOATE_HELLO and another connection that sends CHLO after loading server
+ // config from the disk cache.
+ bool enable_connection_racing_;
+
+ // Set if experimental non-blocking IO should be used on windows sockets.
+ bool enable_non_blocking_io_;
+
+ // Set if we do not want to load server config from the disk cache.
+ bool disable_disk_cache_;
+
+ // Set if AES-GCM should be preferred, even if there is no hardware support.
+ bool prefer_aes_;
+
+ // True if QUIC should be disabled when there are timeouts with open
+ // streams.
+ bool disable_quic_on_timeout_with_open_streams_;
+
+ // Number of times in a row that QUIC has been disabled.
+ int consecutive_disabled_count_;
+ bool need_to_evaluate_consecutive_disabled_count_;
+
+ // Size of the UDP receive buffer.
+ int socket_receive_buffer_size_;
+
+ // Set if we do want to delay TCP connection when it is racing with QUIC.
+ bool delay_tcp_race_;
+
+ // PING timeout for connections.
+ QuicTime::Delta ping_timeout_;
+ QuicTime::Delta reduced_ping_timeout_;
+
+ // If more than |yield_after_packets_| packets have been read or more than
+ // |yield_after_duration_| time has passed, then
+ // QuicChromiumPacketReader::StartReading() yields by doing a PostTask().
+ int yield_after_packets_;
+ QuicTime::Delta yield_after_duration_;
+
+ // Set if all sessions should be closed when any local IP address changes.
+ const bool close_sessions_on_ip_change_;
+
+ // Set if migration should be attempted on active sessions when primary
+ // interface changes.
+ const bool migrate_sessions_on_network_change_;
+
+ // Set if early migration should be attempted when the connection
+ // experiences poor connectivity.
+ const bool migrate_sessions_early_;
+
+ // If set, allows migration of connection to server-specified alternate
+ // server address.
+ const bool allow_server_migration_;
+
+ // If set, force HOL blocking. For measurement purposes.
+ const bool force_hol_blocking_;
+
+ // Set if cert verification is to be raced with host resolution.
+ bool race_cert_verification_;
+
+ // If set, configure QUIC sockets to not fragment packets.
+ bool quic_do_not_fragment_;
+
+ // Each profile will (probably) have a unique port_seed_ value. This value
+ // is used to help seed a pseudo-random number generator (PortSuggester) so
+ // that we consistently (within this profile) suggest the same ephemeral
+ // port when we re-connect to any given server/port. The differences between
+ // profiles (probablistically) prevent two profiles from colliding in their
+ // ephemeral port requests.
+ uint64_t port_seed_;
+
+ // Local address of socket that was created in CreateSession.
+ IPEndPoint local_address_;
+ bool check_persisted_supports_quic_;
+ bool has_initialized_data_;
+ std::set<HostPortPair> quic_supported_servers_at_startup_;
+
+ NetworkConnection network_connection_;
+
+ int num_push_streams_created_;
+
+ QuicClientPushPromiseIndex push_promise_index_;
+
+ // Current status of the factory's ability to create streams.
+ FactoryStatus status_;
+
+ base::TaskRunner* task_runner_;
+
+ const scoped_refptr<SSLConfigService> ssl_config_service_;
+
+ base::WeakPtrFactory<QuicStreamFactory> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicStreamFactory);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_STREAM_FACTORY_H_
diff --git a/chromium/net/quic/chromium/quic_stream_factory_test.cc b/chromium/net/quic/chromium/quic_stream_factory_test.cc
new file mode 100644
index 00000000000..cf0a6ed0364
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_stream_factory_test.cc
@@ -0,0 +1,5316 @@
+// 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/chromium/quic_stream_factory.h"
+
+#include <ostream>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/run_loop.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "net/base/test_proxy_delegate.h"
+#include "net/cert/cert_verifier.h"
+#include "net/cert/ct_policy_enforcer.h"
+#include "net/cert/multi_log_ct_verifier.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_response_info.h"
+#include "net/http/http_server_properties_impl.h"
+#include "net/http/http_util.h"
+#include "net/http/transport_security_state.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/chromium/mock_network_change_notifier.h"
+#include "net/quic/chromium/mock_quic_data.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/properties_based_quic_server_info.h"
+#include "net/quic/core/crypto/quic_crypto_client_config.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/crypto/quic_server_info.h"
+#include "net/quic/core/quic_client_promised_info.h"
+#include "net/quic/core/quic_http_utils.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
+#include "net/quic/test_tools/mock_random.h"
+#include "net/quic/test_tools/quic_config_peer.h"
+#include "net/quic/test_tools/quic_stream_factory_peer.h"
+#include "net/quic/test_tools/quic_test_packet_maker.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/test_task_runner.h"
+#include "net/socket/socket_test_util.h"
+#include "net/spdy/spdy_session_test_util.h"
+#include "net/spdy/spdy_test_utils.h"
+#include "net/ssl/channel_id_service.h"
+#include "net/ssl/default_channel_id_store.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using net::test::IsError;
+using net::test::IsOk;
+
+using std::string;
+using std::vector;
+
+namespace net {
+
+namespace {
+
+class MockSSLConfigService : public SSLConfigService {
+ public:
+ MockSSLConfigService() {}
+
+ void GetSSLConfig(SSLConfig* config) override { *config = config_; }
+
+ private:
+ ~MockSSLConfigService() override {}
+
+ SSLConfig config_;
+};
+
+} // namespace
+
+namespace test {
+
+namespace {
+
+enum DestinationType {
+ // In pooling tests with two requests for different origins to the same
+ // destination, the destination should be
+ SAME_AS_FIRST, // the same as the first origin,
+ SAME_AS_SECOND, // the same as the second origin, or
+ DIFFERENT, // different from both.
+};
+
+const char kDefaultServerHostName[] = "www.example.org";
+const char kServer2HostName[] = "mail.example.org";
+const char kDifferentHostname[] = "different.example.com";
+const int kDefaultServerPort = 443;
+const char kDefaultUrl[] = "https://www.example.org/";
+const char kServer2Url[] = "https://mail.example.org/";
+const char kServer3Url[] = "https://docs.example.org/";
+const char kServer4Url[] = "https://images.example.org/";
+
+// Run QuicStreamFactoryTest instances with all value combinations of version
+// and enable_connection_racting.
+struct TestParams {
+ friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
+ os << "{ version: " << QuicVersionToString(p.version)
+ << ", enable_connection_racing: "
+ << (p.enable_connection_racing ? "true" : "false") << " }";
+ return os;
+ }
+
+ QuicVersion version;
+ bool enable_connection_racing;
+};
+
+vector<TestParams> GetTestParams() {
+ vector<TestParams> params;
+ QuicVersionVector all_supported_versions = AllSupportedVersions();
+ for (const QuicVersion version : all_supported_versions) {
+ params.push_back(TestParams{version, false});
+ params.push_back(TestParams{version, true});
+ }
+ return params;
+}
+
+// Run QuicStreamFactoryWithDestinationTest instances with all value
+// combinations of version, enable_connection_racting, and destination_type.
+struct PoolingTestParams {
+ friend std::ostream& operator<<(std::ostream& os,
+ const PoolingTestParams& p) {
+ os << "{ version: " << QuicVersionToString(p.version)
+ << ", enable_connection_racing: "
+ << (p.enable_connection_racing ? "true" : "false")
+ << ", destination_type: ";
+ switch (p.destination_type) {
+ case SAME_AS_FIRST:
+ os << "SAME_AS_FIRST";
+ break;
+ case SAME_AS_SECOND:
+ os << "SAME_AS_SECOND";
+ break;
+ case DIFFERENT:
+ os << "DIFFERENT";
+ break;
+ }
+ os << " }";
+ return os;
+ }
+
+ QuicVersion version;
+ bool enable_connection_racing;
+ DestinationType destination_type;
+};
+
+vector<PoolingTestParams> GetPoolingTestParams() {
+ vector<PoolingTestParams> params;
+ QuicVersionVector all_supported_versions = AllSupportedVersions();
+ for (const QuicVersion version : all_supported_versions) {
+ params.push_back(PoolingTestParams{version, false, SAME_AS_FIRST});
+ params.push_back(PoolingTestParams{version, false, SAME_AS_SECOND});
+ params.push_back(PoolingTestParams{version, false, DIFFERENT});
+ params.push_back(PoolingTestParams{version, true, SAME_AS_FIRST});
+ params.push_back(PoolingTestParams{version, true, SAME_AS_SECOND});
+ params.push_back(PoolingTestParams{version, true, DIFFERENT});
+ }
+ return params;
+}
+
+} // namespace
+
+class QuicHttpStreamPeer {
+ public:
+ static QuicChromiumClientSession* GetSession(QuicHttpStream* stream) {
+ return stream->session_.get();
+ }
+};
+
+class MockQuicServerInfo : public QuicServerInfo {
+ public:
+ explicit MockQuicServerInfo(const QuicServerId& server_id)
+ : QuicServerInfo(server_id) {}
+ ~MockQuicServerInfo() override {}
+
+ void Start() override {}
+
+ int WaitForDataReady(const CompletionCallback& callback) override {
+ return ERR_IO_PENDING;
+ }
+
+ void ResetWaitForDataReadyCallback() override {}
+
+ void CancelWaitForDataReadyCallback() override {}
+
+ bool IsDataReady() override { return false; }
+
+ bool IsReadyToPersist() override { return false; }
+
+ void Persist() override {}
+
+ void OnExternalCacheHit() override {}
+};
+
+class MockQuicServerInfoFactory : public QuicServerInfoFactory {
+ public:
+ MockQuicServerInfoFactory() {}
+ ~MockQuicServerInfoFactory() override {}
+
+ QuicServerInfo* GetForServer(const QuicServerId& server_id) override {
+ return new MockQuicServerInfo(server_id);
+ }
+};
+
+class QuicStreamFactoryTestBase {
+ protected:
+ QuicStreamFactoryTestBase(QuicVersion version, bool enable_connection_racing)
+ : ssl_config_service_(new MockSSLConfigService),
+ random_generator_(0),
+ clock_(new MockClock()),
+ runner_(new TestTaskRunner(clock_)),
+ version_(version),
+ client_maker_(version_,
+ 0,
+ clock_,
+ kDefaultServerHostName,
+ Perspective::IS_CLIENT),
+ server_maker_(version_,
+ 0,
+ clock_,
+ kDefaultServerHostName,
+ Perspective::IS_SERVER),
+ cert_verifier_(CertVerifier::CreateDefault()),
+ channel_id_service_(
+ new ChannelIDService(new DefaultChannelIDStore(nullptr),
+ base::ThreadTaskRunnerHandle::Get())),
+ cert_transparency_verifier_(new MultiLogCTVerifier()),
+ scoped_mock_network_change_notifier_(nullptr),
+ factory_(nullptr),
+ host_port_pair_(kDefaultServerHostName, kDefaultServerPort),
+ url_(kDefaultUrl),
+ url2_(kServer2Url),
+ url3_(kServer3Url),
+ url4_(kServer4Url),
+ privacy_mode_(PRIVACY_MODE_DISABLED),
+ enable_port_selection_(true),
+ always_require_handshake_confirmation_(false),
+ disable_connection_pooling_(false),
+ load_server_info_timeout_srtt_multiplier_(0.0f),
+ enable_connection_racing_(enable_connection_racing),
+ enable_non_blocking_io_(true),
+ disable_disk_cache_(false),
+ prefer_aes_(false),
+ receive_buffer_size_(0),
+ delay_tcp_race_(true),
+ close_sessions_on_ip_change_(false),
+ disable_quic_on_timeout_with_open_streams_(false),
+ idle_connection_timeout_seconds_(kIdleConnectionTimeoutSeconds),
+ reduced_ping_timeout_seconds_(kPingTimeoutSecs),
+ packet_reader_yield_after_duration_milliseconds_(
+ kQuicYieldAfterDurationMilliseconds),
+ migrate_sessions_on_network_change_(false),
+ migrate_sessions_early_(false),
+ allow_server_migration_(false),
+ force_hol_blocking_(false),
+ race_cert_verification_(false) {
+ clock_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ }
+
+ ~QuicStreamFactoryTestBase() {
+ // If |factory_| was initialized, then it took over ownership of |clock_|.
+ // If |factory_| was not initialized, then |clock_| needs to be destroyed.
+ if (!factory_)
+ delete clock_;
+ }
+
+ void Initialize() {
+ DCHECK(!factory_);
+ factory_.reset(new QuicStreamFactory(
+ net_log_.net_log(), &host_resolver_, ssl_config_service_.get(),
+ &socket_factory_, &http_server_properties_, &test_proxy_delegate_,
+ cert_verifier_.get(), &ct_policy_enforcer_, channel_id_service_.get(),
+ &transport_security_state_, cert_transparency_verifier_.get(),
+ /*SocketPerformanceWatcherFactory*/ nullptr,
+ &crypto_client_stream_factory_, &random_generator_, clock_,
+ kDefaultMaxPacketSize, string(), SupportedVersions(version_),
+ enable_port_selection_, always_require_handshake_confirmation_,
+ disable_connection_pooling_, load_server_info_timeout_srtt_multiplier_,
+ enable_connection_racing_, enable_non_blocking_io_, disable_disk_cache_,
+ prefer_aes_, receive_buffer_size_, delay_tcp_race_,
+ /*max_server_configs_stored_in_properties*/ 0,
+ close_sessions_on_ip_change_,
+ disable_quic_on_timeout_with_open_streams_,
+ idle_connection_timeout_seconds_, reduced_ping_timeout_seconds_,
+ packet_reader_yield_after_duration_milliseconds_,
+ migrate_sessions_on_network_change_, migrate_sessions_early_,
+ allow_server_migration_, force_hol_blocking_, race_cert_verification_,
+ /*do_not_fragment*/ true, QuicTagVector(),
+ /*enable_token_binding*/ false));
+ factory_->set_require_confirmation(false);
+ EXPECT_FALSE(factory_->has_quic_server_info_factory());
+ factory_->set_quic_server_info_factory(new MockQuicServerInfoFactory());
+ EXPECT_TRUE(factory_->has_quic_server_info_factory());
+ }
+
+ void InitializeConnectionMigrationTest(
+ NetworkChangeNotifier::NetworkList connected_networks) {
+ scoped_mock_network_change_notifier_.reset(
+ new ScopedMockNetworkChangeNotifier());
+ MockNetworkChangeNotifier* mock_ncn =
+ scoped_mock_network_change_notifier_->mock_network_change_notifier();
+ mock_ncn->ForceNetworkHandlesSupported();
+ mock_ncn->SetConnectedNetworksList(connected_networks);
+ migrate_sessions_on_network_change_ = true;
+ migrate_sessions_early_ = true;
+ Initialize();
+ }
+
+ bool HasActiveSession(const HostPortPair& host_port_pair) {
+ QuicServerId server_id(host_port_pair, PRIVACY_MODE_DISABLED);
+ return QuicStreamFactoryPeer::HasActiveSession(factory_.get(), server_id);
+ }
+
+ bool HasActiveCertVerifierJob(const QuicServerId& server_id) {
+ return QuicStreamFactoryPeer::HasActiveCertVerifierJob(factory_.get(),
+ server_id);
+ }
+
+ QuicChromiumClientSession* GetActiveSession(
+ const HostPortPair& host_port_pair) {
+ QuicServerId server_id(host_port_pair, PRIVACY_MODE_DISABLED);
+ return QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server_id);
+ }
+
+ std::unique_ptr<QuicHttpStream> CreateFromSession(
+ const HostPortPair& host_port_pair) {
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair);
+ return QuicStreamFactoryPeer::CreateFromSession(factory_.get(), session);
+ }
+
+ int GetSourcePortForNewSession(const HostPortPair& destination) {
+ return GetSourcePortForNewSessionInner(destination, false);
+ }
+
+ int GetSourcePortForNewSessionAndGoAway(const HostPortPair& destination) {
+ return GetSourcePortForNewSessionInner(destination, true);
+ }
+
+ int GetSourcePortForNewSessionInner(const HostPortPair& destination,
+ bool goaway_received) {
+ // Should only be called if there is no active session for this destination.
+ EXPECT_FALSE(HasActiveSession(destination));
+ size_t socket_count = socket_factory_.udp_client_socket_ports().size();
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request(factory_.get());
+ GURL url("https://" + destination.host() + "/");
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(destination, privacy_mode_,
+ /*cert_verify_flags=*/0, url, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+ stream.reset();
+
+ QuicChromiumClientSession* session = GetActiveSession(destination);
+
+ if (socket_count + 1 != socket_factory_.udp_client_socket_ports().size()) {
+ ADD_FAILURE();
+ return 0;
+ }
+
+ if (goaway_received) {
+ QuicGoAwayFrame goaway(QUIC_NO_ERROR, 1, "");
+ session->connection()->OnGoAwayFrame(goaway);
+ }
+
+ factory_->OnSessionClosed(session);
+ EXPECT_FALSE(HasActiveSession(destination));
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ return socket_factory_.udp_client_socket_ports()[socket_count];
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructClientConnectionClosePacket(
+ QuicPacketNumber num) {
+ return client_maker_.MakeConnectionClosePacket(num);
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructClientRstPacket() {
+ QuicStreamId stream_id = kClientDataStreamId1;
+ return client_maker_.MakeRstPacket(
+ 1, true, stream_id,
+ AdjustErrorForVersion(QUIC_RST_ACKNOWLEDGEMENT, version_));
+ }
+
+ static ProofVerifyDetailsChromium DefaultProofVerifyDetails() {
+ // Load a certificate that is valid for *.example.org
+ scoped_refptr<X509Certificate> test_cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
+ EXPECT_TRUE(test_cert.get());
+ ProofVerifyDetailsChromium verify_details;
+ verify_details.cert_verify_result.verified_cert = test_cert;
+ verify_details.cert_verify_result.is_issued_by_known_root = true;
+ return verify_details;
+ }
+
+ void NotifyIPAddressChanged() {
+ NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
+ // Spin the message loop so the notification is delivered.
+ base::RunLoop().RunUntilIdle();
+ }
+
+ std::unique_ptr<QuicEncryptedPacket> ConstructGetRequestPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool should_include_version,
+ bool fin) {
+ SpdyHeaderBlock headers =
+ client_maker_.GetRequestHeaders("GET", "https", "/");
+ SpdyPriority priority =
+ ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY);
+ 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::unique_ptr<QuicEncryptedPacket> ConstructOkResponsePacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool should_include_version,
+ bool fin) {
+ SpdyHeaderBlock headers = server_maker_.GetResponseHeaders("200 OK");
+ size_t spdy_headers_frame_len;
+ return server_maker_.MakeResponseHeadersPacket(
+ packet_number, stream_id, should_include_version, fin,
+ std::move(headers), &spdy_headers_frame_len);
+ }
+
+ // Helper method for server migration tests.
+ void VerifyServerMigration(QuicConfig& config, IPEndPoint expected_address) {
+ allow_server_migration_ = true;
+ Initialize();
+
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.SetConfig(config);
+
+ // Set up first socket data provider.
+ MockQuicData socket_data1;
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+
+ // Set up second socket data provider that is used after
+ // migration.
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddWrite(
+ client_maker_.MakePingPacket(1, /*include_version=*/true));
+ socket_data2.AddWrite(client_maker_.MakeRstPacket(
+ 2, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_EQ(OK, callback_.WaitForResult());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.example.org/");
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ IPEndPoint actual_address;
+ session->GetDefaultSocket()->GetPeerAddress(&actual_address);
+ EXPECT_EQ(actual_address, expected_address);
+ DVLOG(1) << "Socket connected to: " << actual_address.address().ToString()
+ << " " << actual_address.port();
+ DVLOG(1) << "Expected address: " << expected_address.address().ToString()
+ << " " << expected_address.port();
+
+ stream.reset();
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+ }
+
+ // Verifies that the QUIC stream factory is initialized correctly.
+ // If |proxy_delegate_provides_quic_supported_proxy| is true, then
+ // ProxyDelegate provides a proxy that supports QUIC at startup. Otherwise,
+ // a non proxy server that support alternative services is added to the
+ // HttpServerProperties map.
+ void VerifyInitialization(bool proxy_delegate_provides_quic_supported_proxy) {
+ idle_connection_timeout_seconds_ = 500;
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ const QuicConfig* config = QuicStreamFactoryPeer::GetConfig(factory_.get());
+ EXPECT_EQ(500, config->IdleConnectionStateLifetime().ToSeconds());
+
+ QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
+
+ const AlternativeService alternative_service1(QUIC, host_port_pair_.host(),
+ host_port_pair_.port());
+ AlternativeServiceInfoVector alternative_service_info_vector;
+ base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
+ alternative_service_info_vector.push_back(
+ AlternativeServiceInfo(alternative_service1, expiration));
+ http_server_properties_.SetAlternativeServices(
+ url::SchemeHostPort(url_), alternative_service_info_vector);
+
+ HostPortPair host_port_pair2(kServer2HostName, kDefaultServerPort);
+ url::SchemeHostPort server2("https", kServer2HostName, kDefaultServerPort);
+ const AlternativeService alternative_service2(QUIC, host_port_pair2.host(),
+ host_port_pair2.port());
+ AlternativeServiceInfoVector alternative_service_info_vector2;
+ alternative_service_info_vector2.push_back(
+ AlternativeServiceInfo(alternative_service2, expiration));
+ if (!proxy_delegate_provides_quic_supported_proxy) {
+ http_server_properties_.SetAlternativeServices(
+ server2, alternative_service_info_vector2);
+ // Verify that the properties of both QUIC servers are stored in the
+ // HTTP properties map.
+ EXPECT_EQ(2U, http_server_properties_.alternative_service_map().size());
+ } else {
+ test_proxy_delegate_.set_alternative_proxy_server(net::ProxyServer(
+ net::ProxyServer::SCHEME_QUIC,
+ net::HostPortPair(kServer2HostName, kDefaultServerPort)));
+ // Verify that the properties of only the first QUIC server are stored in
+ // the HTTP properties map.
+ EXPECT_EQ(1U, http_server_properties_.alternative_service_map().size());
+ }
+
+ http_server_properties_.SetMaxServerConfigsStoredInProperties(
+ kMaxQuicServersToPersist);
+
+ QuicServerId quic_server_id(kDefaultServerHostName, 80,
+ PRIVACY_MODE_DISABLED);
+ QuicServerInfoFactory* quic_server_info_factory =
+ new PropertiesBasedQuicServerInfoFactory(&http_server_properties_);
+ factory_->set_quic_server_info_factory(quic_server_info_factory);
+
+ std::unique_ptr<QuicServerInfo> quic_server_info(
+ quic_server_info_factory->GetForServer(quic_server_id));
+
+ // Update quic_server_info's server_config and persist it.
+ QuicServerInfo::State* state = quic_server_info->mutable_state();
+ // Minimum SCFG that passes config validation checks.
+ const char scfg[] = {// SCFG
+ 0x53, 0x43, 0x46, 0x47,
+ // num entries
+ 0x01, 0x00,
+ // padding
+ 0x00, 0x00,
+ // EXPY
+ 0x45, 0x58, 0x50, 0x59,
+ // EXPY end offset
+ 0x08, 0x00, 0x00, 0x00,
+ // Value
+ '1', '2', '3', '4', '5', '6', '7', '8'};
+
+ // Create temporary strings becasue Persist() clears string data in |state|.
+ string server_config(reinterpret_cast<const char*>(&scfg), sizeof(scfg));
+ string source_address_token("test_source_address_token");
+ string cert_sct("test_cert_sct");
+ string chlo_hash("test_chlo_hash");
+ string signature("test_signature");
+ string test_cert("test_cert");
+ vector<string> certs;
+ certs.push_back(test_cert);
+ state->server_config = server_config;
+ state->source_address_token = source_address_token;
+ state->cert_sct = cert_sct;
+ state->chlo_hash = chlo_hash;
+ state->server_config_sig = signature;
+ state->certs = certs;
+
+ quic_server_info->Persist();
+
+ QuicServerId quic_server_id2(kServer2HostName, 80, PRIVACY_MODE_DISABLED);
+ std::unique_ptr<QuicServerInfo> quic_server_info2(
+ quic_server_info_factory->GetForServer(quic_server_id2));
+
+ // Update quic_server_info2's server_config and persist it.
+ QuicServerInfo::State* state2 = quic_server_info2->mutable_state();
+
+ // Minimum SCFG that passes config validation checks.
+ const char scfg2[] = {// SCFG
+ 0x53, 0x43, 0x46, 0x47,
+ // num entries
+ 0x01, 0x00,
+ // padding
+ 0x00, 0x00,
+ // EXPY
+ 0x45, 0x58, 0x50, 0x59,
+ // EXPY end offset
+ 0x08, 0x00, 0x00, 0x00,
+ // Value
+ '8', '7', '3', '4', '5', '6', '2', '1'};
+
+ // Create temporary strings becasue Persist() clears string data in
+ // |state2|.
+ string server_config2(reinterpret_cast<const char*>(&scfg2), sizeof(scfg2));
+ string source_address_token2("test_source_address_token2");
+ string cert_sct2("test_cert_sct2");
+ string chlo_hash2("test_chlo_hash2");
+ string signature2("test_signature2");
+ string test_cert2("test_cert2");
+ vector<string> certs2;
+ certs2.push_back(test_cert2);
+ state2->server_config = server_config2;
+ state2->source_address_token = source_address_token2;
+ state2->cert_sct = cert_sct2;
+ state2->chlo_hash = chlo_hash2;
+ state2->server_config_sig = signature2;
+ state2->certs = certs2;
+
+ quic_server_info2->Persist();
+
+ QuicStreamFactoryPeer::MaybeInitialize(factory_.get());
+ EXPECT_TRUE(QuicStreamFactoryPeer::HasInitializedData(factory_.get()));
+
+ // Verify the MRU order is maintained.
+ const QuicServerInfoMap& quic_server_info_map =
+ http_server_properties_.quic_server_info_map();
+ EXPECT_EQ(2u, quic_server_info_map.size());
+ QuicServerInfoMap::const_iterator quic_server_info_map_it =
+ quic_server_info_map.begin();
+ EXPECT_EQ(quic_server_info_map_it->first, quic_server_id2);
+ ++quic_server_info_map_it;
+ EXPECT_EQ(quic_server_info_map_it->first, quic_server_id);
+
+ EXPECT_TRUE(QuicStreamFactoryPeer::SupportsQuicAtStartUp(factory_.get(),
+ host_port_pair_));
+ EXPECT_FALSE(QuicStreamFactoryPeer::CryptoConfigCacheIsEmpty(
+ factory_.get(), quic_server_id));
+ QuicCryptoClientConfig* crypto_config =
+ QuicStreamFactoryPeer::GetCryptoConfig(factory_.get());
+ QuicCryptoClientConfig::CachedState* cached =
+ crypto_config->LookupOrCreate(quic_server_id);
+ EXPECT_FALSE(cached->server_config().empty());
+ EXPECT_TRUE(cached->GetServerConfig());
+ EXPECT_EQ(server_config, cached->server_config());
+ EXPECT_EQ(source_address_token, cached->source_address_token());
+ EXPECT_EQ(cert_sct, cached->cert_sct());
+ EXPECT_EQ(chlo_hash, cached->chlo_hash());
+ EXPECT_EQ(signature, cached->signature());
+ ASSERT_EQ(1U, cached->certs().size());
+ EXPECT_EQ(test_cert, cached->certs()[0]);
+
+ EXPECT_TRUE(QuicStreamFactoryPeer::SupportsQuicAtStartUp(factory_.get(),
+ host_port_pair2));
+ EXPECT_FALSE(QuicStreamFactoryPeer::CryptoConfigCacheIsEmpty(
+ factory_.get(), quic_server_id2));
+ QuicCryptoClientConfig::CachedState* cached2 =
+ crypto_config->LookupOrCreate(quic_server_id2);
+ EXPECT_FALSE(cached2->server_config().empty());
+ EXPECT_TRUE(cached2->GetServerConfig());
+ EXPECT_EQ(server_config2, cached2->server_config());
+ EXPECT_EQ(source_address_token2, cached2->source_address_token());
+ EXPECT_EQ(cert_sct2, cached2->cert_sct());
+ EXPECT_EQ(chlo_hash2, cached2->chlo_hash());
+ EXPECT_EQ(signature2, cached2->signature());
+ ASSERT_EQ(1U, cached->certs().size());
+ EXPECT_EQ(test_cert2, cached2->certs()[0]);
+ }
+
+ void RunTestLoopUntilIdle() {
+ while (!runner_->GetPostedTasks().empty())
+ runner_->RunNextTask();
+ }
+
+ // Helper methods for tests of connection migration on write error.
+ void TestMigrationOnWriteErrorNonMigratableStream(IoMode write_error_mode);
+ void TestMigrationOnWriteErrorMigrationDisabled(IoMode write_error_mode);
+ void TestMigrationOnWriteError(IoMode write_error_mode);
+ void TestMigrationOnWriteErrorNoNewNetwork(IoMode write_error_mode);
+ void TestMigrationOnMultipleWriteErrors(IoMode first_write_error_mode,
+ IoMode second_write_error_mode);
+ void TestMigrationOnWriteErrorWithNotificationQueued(bool disconnected);
+ void TestMigrationOnNotificationWithWriteErrorQueued(bool disconnected);
+ void OnNetworkDisconnected(bool async_write_before);
+ void OnNetworkMadeDefault(bool async_write_before);
+ void TestMigrationOnWriteErrorPauseBeforeConnected(IoMode write_error_mode);
+ void OnNetworkDisconnectedWithNetworkList(
+ NetworkChangeNotifier::NetworkList network_list);
+ void TestMigrationOnWriteErrorWithNetworkAddedBeforeNotification(
+ IoMode write_error_mode,
+ bool disconnected);
+
+ MockHostResolver host_resolver_;
+ scoped_refptr<SSLConfigService> ssl_config_service_;
+ MockClientSocketFactory socket_factory_;
+ MockCryptoClientStreamFactory crypto_client_stream_factory_;
+ MockRandom random_generator_;
+ MockClock* clock_; // Owned by |factory_| once created.
+ scoped_refptr<TestTaskRunner> runner_;
+ QuicVersion version_;
+ QuicTestPacketMaker client_maker_;
+ QuicTestPacketMaker server_maker_;
+ HttpServerPropertiesImpl http_server_properties_;
+ TestProxyDelegate test_proxy_delegate_;
+ std::unique_ptr<CertVerifier> cert_verifier_;
+ std::unique_ptr<ChannelIDService> channel_id_service_;
+ TransportSecurityState transport_security_state_;
+ std::unique_ptr<CTVerifier> cert_transparency_verifier_;
+ CTPolicyEnforcer ct_policy_enforcer_;
+ std::unique_ptr<ScopedMockNetworkChangeNotifier>
+ scoped_mock_network_change_notifier_;
+ std::unique_ptr<QuicStreamFactory> factory_;
+ HostPortPair host_port_pair_;
+ GURL url_;
+ GURL url2_;
+ GURL url3_;
+ GURL url4_;
+
+ PrivacyMode privacy_mode_;
+ NetLogWithSource net_log_;
+ TestCompletionCallback callback_;
+
+ // Variables to configure QuicStreamFactory.
+ bool enable_port_selection_;
+ bool always_require_handshake_confirmation_;
+ bool disable_connection_pooling_;
+ double load_server_info_timeout_srtt_multiplier_;
+ bool enable_connection_racing_;
+ bool enable_non_blocking_io_;
+ bool disable_disk_cache_;
+ bool prefer_aes_;
+ int receive_buffer_size_;
+ bool delay_tcp_race_;
+ bool close_sessions_on_ip_change_;
+ bool disable_quic_on_timeout_with_open_streams_;
+ int idle_connection_timeout_seconds_;
+ int reduced_ping_timeout_seconds_;
+ int packet_reader_yield_after_duration_milliseconds_;
+ bool migrate_sessions_on_network_change_;
+ bool migrate_sessions_early_;
+ bool allow_server_migration_;
+ bool force_hol_blocking_;
+ bool race_cert_verification_;
+};
+
+class QuicStreamFactoryTest : public QuicStreamFactoryTestBase,
+ public ::testing::TestWithParam<TestParams> {
+ protected:
+ QuicStreamFactoryTest()
+ : QuicStreamFactoryTestBase(GetParam().version,
+ GetParam().enable_connection_racing) {}
+};
+
+INSTANTIATE_TEST_CASE_P(Version,
+ QuicStreamFactoryTest,
+ ::testing::ValuesIn(GetTestParams()));
+
+TEST_P(QuicStreamFactoryTest, Create) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Will reset stream 3.
+ stream = CreateFromSession(host_port_pair_);
+ EXPECT_TRUE(stream.get());
+
+ // TODO(rtenneti): We should probably have a tests that HTTP and HTTPS result
+ // in streams on different sessions.
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ stream = request2.CreateStream(); // Will reset stream 5.
+ stream.reset(); // Will reset stream 7.
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, CreateZeroRtt) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::ZERO_RTT);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, CreateZeroRttPost) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::ZERO_RTT);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "POST", net_log_,
+ callback_.callback()));
+
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, GoAway) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+
+ session->OnGoAway(QuicGoAwayFrame());
+
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, GoAwayForConnectionMigrationWithPortOnly) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+
+ session->OnGoAway(
+ QuicGoAwayFrame(QUIC_ERROR_MIGRATING_PORT, 0,
+ "peer connection migration due to port change only"));
+ NetErrorDetails details;
+ EXPECT_FALSE(details.quic_port_migration_detected);
+ session->PopulateNetErrorDetails(&details);
+ EXPECT_TRUE(details.quic_port_migration_detected);
+ details.quic_port_migration_detected = false;
+ stream->PopulateNetErrorDetails(&details);
+ EXPECT_TRUE(details.quic_port_migration_detected);
+
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, Pooling) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ HostPortPair server2(kServer2HostName, kDefaultServerPort);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ TestCompletionCallback callback;
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
+ /*cert_verify_flags=*/0, url2_, "GET",
+ net_log_, callback.callback()));
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_EQ(GetActiveSession(host_port_pair_), GetActiveSession(server2));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, PoolingWithServerMigration) {
+ // Set up session to migrate.
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+ IPEndPoint alt_address = IPEndPoint(IPAddress(1, 2, 3, 4), 443);
+ QuicConfig config;
+ config.SetAlternateServerAddressToSend(alt_address);
+
+ VerifyServerMigration(config, alt_address);
+
+ // Close server-migrated session.
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+ session->CloseSessionOnError(0u, QUIC_NO_ERROR);
+
+ // Set up server IP, socket, proof, and config for new session.
+ HostPortPair server2(kServer2HostName, kDefaultServerPort);
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+
+ MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
+ SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ QuicConfig config2;
+ crypto_client_stream_factory_.SetConfig(config2);
+
+ // Create new request to cause new session creation.
+ TestCompletionCallback callback;
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(server2, privacy_mode_,
+ /*cert_verify_flags=*/0, url2_, "GET", net_log_,
+ callback.callback()));
+ EXPECT_EQ(OK, callback.WaitForResult());
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ // EXPECT_EQ(GetActiveSession(host_port_pair_), GetActiveSession(server2));
+}
+
+TEST_P(QuicStreamFactoryTest, NoPoolingIfDisabled) {
+ disable_connection_pooling_ = true;
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data1;
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ HostPortPair server2(kServer2HostName, kDefaultServerPort);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ TestCompletionCallback callback;
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
+ /*cert_verify_flags=*/0, url2_, "GET",
+ net_log_, callback.callback()));
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_NE(GetActiveSession(host_port_pair_), GetActiveSession(server2));
+
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, NoPoolingAfterGoAway) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data1;
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ HostPortPair server2(kServer2HostName, kDefaultServerPort);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ TestCompletionCallback callback;
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
+ /*cert_verify_flags=*/0, url2_, "GET",
+ net_log_, callback.callback()));
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ factory_->OnSessionGoingAway(GetActiveSession(host_port_pair_));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_FALSE(HasActiveSession(server2));
+
+ TestCompletionCallback callback3;
+ QuicStreamRequest request3(factory_.get());
+ EXPECT_EQ(OK, request3.Request(server2, privacy_mode_,
+ /*cert_verify_flags=*/0, url2_, "GET",
+ net_log_, callback3.callback()));
+ std::unique_ptr<QuicHttpStream> stream3 = request3.CreateStream();
+ EXPECT_TRUE(stream3.get());
+
+ EXPECT_TRUE(HasActiveSession(server2));
+
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, HttpsPooling) {
+ Initialize();
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ HostPortPair server1(kDefaultServerHostName, 443);
+ HostPortPair server2(kServer2HostName, 443);
+
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(server1, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ TestCompletionCallback callback;
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
+ /*cert_verify_flags=*/0, url2_, "GET",
+ net_log_, callback_.callback()));
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_EQ(GetActiveSession(server1), GetActiveSession(server2));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, NoHttpsPoolingIfDisabled) {
+ disable_connection_pooling_ = true;
+ Initialize();
+
+ MockQuicData socket_data1;
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ HostPortPair server1(kDefaultServerHostName, 443);
+ HostPortPair server2(kServer2HostName, 443);
+
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(server1, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ TestCompletionCallback callback;
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
+ /*cert_verify_flags=*/0, url2_, "GET",
+ net_log_, callback_.callback()));
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_NE(GetActiveSession(server1), GetActiveSession(server2));
+
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, HttpsPoolingWithMatchingPins) {
+ Initialize();
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ HostPortPair server1(kDefaultServerHostName, 443);
+ HostPortPair server2(kServer2HostName, 443);
+ uint8_t primary_pin = 1;
+ uint8_t backup_pin = 2;
+ test::AddPin(&transport_security_state_, kServer2HostName, primary_pin,
+ backup_pin);
+
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ verify_details.cert_verify_result.public_key_hashes.push_back(
+ test::GetTestHashValue(primary_pin));
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(server1, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ TestCompletionCallback callback;
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
+ /*cert_verify_flags=*/0, url2_, "GET",
+ net_log_, callback_.callback()));
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_EQ(GetActiveSession(server1), GetActiveSession(server2));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithMatchingPinsIfDisabled) {
+ disable_connection_pooling_ = true;
+ Initialize();
+
+ MockQuicData socket_data1;
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ HostPortPair server1(kDefaultServerHostName, 443);
+ HostPortPair server2(kServer2HostName, 443);
+ uint8_t primary_pin = 1;
+ uint8_t backup_pin = 2;
+ test::AddPin(&transport_security_state_, kServer2HostName, primary_pin,
+ backup_pin);
+
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ verify_details.cert_verify_result.public_key_hashes.push_back(
+ test::GetTestHashValue(primary_pin));
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(server1, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ TestCompletionCallback callback;
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
+ /*cert_verify_flags=*/0, url2_, "GET",
+ net_log_, callback_.callback()));
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_NE(GetActiveSession(server1), GetActiveSession(server2));
+
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithDifferentPins) {
+ Initialize();
+
+ MockQuicData socket_data1;
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ HostPortPair server1(kDefaultServerHostName, 443);
+ HostPortPair server2(kServer2HostName, 443);
+ uint8_t primary_pin = 1;
+ uint8_t backup_pin = 2;
+ uint8_t bad_pin = 3;
+ test::AddPin(&transport_security_state_, kServer2HostName, primary_pin,
+ backup_pin);
+
+ ProofVerifyDetailsChromium verify_details1 = DefaultProofVerifyDetails();
+ verify_details1.cert_verify_result.public_key_hashes.push_back(
+ test::GetTestHashValue(bad_pin));
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details1);
+
+ ProofVerifyDetailsChromium verify_details2 = DefaultProofVerifyDetails();
+ verify_details2.cert_verify_result.public_key_hashes.push_back(
+ test::GetTestHashValue(primary_pin));
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2);
+
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(server1, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ TestCompletionCallback callback;
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
+ /*cert_verify_flags=*/0, url2_, "GET",
+ net_log_, callback_.callback()));
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_NE(GetActiveSession(server1), GetActiveSession(server2));
+
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, Goaway) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Mark the session as going away. Ensure that while it is still alive
+ // that it is no longer active.
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+ factory_->OnSessionGoingAway(session);
+ EXPECT_EQ(true,
+ QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+
+ // Create a new request for the same destination and verify that a
+ // new session is created.
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ EXPECT_NE(session, GetActiveSession(host_port_pair_));
+ EXPECT_EQ(true,
+ QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+
+ stream2.reset();
+ stream.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, MaxOpenStream) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ QuicStreamId stream_id = kClientDataStreamId1;
+ MockQuicData socket_data;
+ socket_data.AddWrite(
+ client_maker_.MakeRstPacket(1, true, stream_id, QUIC_STREAM_CANCELLED));
+ socket_data.AddRead(
+ server_maker_.MakeRstPacket(1, false, stream_id, QUIC_STREAM_CANCELLED));
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ HttpRequestInfo request_info;
+ vector<QuicHttpStream*> streams;
+ // The MockCryptoClientStream sets max_open_streams to be
+ // kDefaultMaxStreamsPerConnection / 2.
+ for (size_t i = 0; i < kDefaultMaxStreamsPerConnection / 2; i++) {
+ QuicStreamRequest request(factory_.get());
+ int rv = request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback());
+ if (i == 0) {
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ } else {
+ EXPECT_THAT(rv, IsOk());
+ }
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream);
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+ streams.push_back(stream.release());
+ }
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ CompletionCallback()));
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream);
+ EXPECT_EQ(ERR_IO_PENDING,
+ stream->InitializeStream(&request_info, DEFAULT_PRIORITY, net_log_,
+ callback_.callback()));
+
+ // Close the first stream.
+ streams.front()->Close(false);
+ // Trigger exchange of RSTs that in turn allow progress for the last
+ // stream.
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+
+ // Force close of the connection to suppress the generation of RST
+ // packets when streams are torn down, which wouldn't be relevant to
+ // this test anyway.
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+ session->connection()->CloseConnection(QUIC_PUBLIC_RESET, "test",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+
+ base::STLDeleteElements(&streams);
+}
+
+TEST_P(QuicStreamFactoryTest, ResolutionErrorInCreate) {
+ Initialize();
+ MockQuicData socket_data;
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ host_resolver_.rules()->AddSimulatedFailure(kDefaultServerHostName);
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, ConnectErrorInCreate) {
+ Initialize();
+
+ MockQuicData socket_data;
+ socket_data.AddConnect(SYNCHRONOUS, ERR_ADDRESS_IN_USE);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_ADDRESS_IN_USE));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, CancelCreate) {
+ Initialize();
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+ {
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ }
+
+ base::RunLoop().RunUntilIdle();
+
+ std::unique_ptr<QuicHttpStream> stream(CreateFromSession(host_port_pair_));
+ EXPECT_TRUE(stream.get());
+ stream.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, CreateConsistentEphemeralPort) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ // Sequentially connect to the default host, then another host, and then the
+ // default host. Verify that the default host gets a consistent ephemeral
+ // port, that is different from the other host's connection.
+
+ string other_server_name = kServer2HostName;
+ EXPECT_NE(kDefaultServerHostName, other_server_name);
+ HostPortPair host_port_pair2(other_server_name, kDefaultServerPort);
+
+ int original_port = GetSourcePortForNewSession(host_port_pair_);
+ EXPECT_NE(original_port, GetSourcePortForNewSession(host_port_pair2));
+ EXPECT_EQ(original_port, GetSourcePortForNewSession(host_port_pair_));
+}
+
+TEST_P(QuicStreamFactoryTest, GoAwayDisablesConsistentEphemeralPort) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ // Get a session to the host using the port suggester.
+ int original_port = GetSourcePortForNewSessionAndGoAway(host_port_pair_);
+ // Verify that the port is different after the goaway.
+ EXPECT_NE(original_port, GetSourcePortForNewSession(host_port_pair_));
+ // Since the previous session did not goaway we should see the original port.
+ EXPECT_EQ(original_port, GetSourcePortForNewSession(host_port_pair_));
+}
+
+TEST_P(QuicStreamFactoryTest, CloseAllSessions) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(ConstructClientRstPacket());
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ // Close the session and verify that stream saw the error.
+ factory_->CloseAllSessions(ERR_INTERNET_DISCONNECTED, QUIC_INTERNAL_ERROR);
+ EXPECT_EQ(ERR_INTERNET_DISCONNECTED,
+ stream->ReadResponseHeaders(callback_.callback()));
+
+ // Now attempting to request a stream to the same origin should create
+ // a new session.
+
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ stream = request2.CreateStream();
+ stream.reset(); // Will reset stream 3.
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, OnIPAddressChanged) {
+ close_sessions_on_ip_change_ = true;
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(ConstructClientRstPacket());
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ // Change the IP address and verify that stream saw the error.
+ NotifyIPAddressChanged();
+ EXPECT_EQ(ERR_NETWORK_CHANGED,
+ stream->ReadResponseHeaders(callback_.callback()));
+ EXPECT_TRUE(factory_->require_confirmation());
+
+ // Now attempting to request a stream to the same origin should create
+ // a new session.
+
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ stream = request2.CreateStream();
+ stream.reset(); // Will reset stream 3.
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, OnNetworkMadeDefaultWithSynchronousWriteBefore) {
+ OnNetworkMadeDefault(/*async_write_before=*/false);
+}
+
+TEST_P(QuicStreamFactoryTest, OnNetworkMadeDefaultWithAsyncWriteBefore) {
+ OnNetworkMadeDefault(/*async_write_before=*/true);
+}
+
+void QuicStreamFactoryTestBase::OnNetworkMadeDefault(bool async_write_before) {
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ int packet_number = 1;
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(ConstructGetRequestPacket(
+ packet_number++, kClientDataStreamId1, true, true));
+ if (async_write_before) {
+ socket_data.AddWrite(ASYNC, OK);
+ packet_number++;
+ }
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = url_;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Send GET request on stream.
+ HttpResponseInfo response;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+ callback_.callback()));
+
+ // Do an async write to leave writer blocked.
+ if (async_write_before)
+ session->connection()->SendPing();
+
+ // Set up second socket data provider that is used after migration.
+ // The response to the earlier request is read on this new socket.
+ MockQuicData socket_data1;
+ socket_data1.AddWrite(
+ client_maker_.MakePingPacket(packet_number++, /*include_version=*/true));
+ socket_data1.AddRead(
+ ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddWrite(client_maker_.MakeAckAndRstPacket(
+ packet_number++, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1,
+ 1, true));
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+
+ // Trigger connection migration. This should cause a PING frame
+ // to be emitted.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkMadeDefault(kNewNetworkForTests);
+
+ // The session should now be marked as going away. Ensure that
+ // while it is still alive, it is no longer active.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ // Verify that response headers on the migrated socket were delivered to the
+ // stream.
+ EXPECT_THAT(stream->ReadResponseHeaders(callback_.callback()), IsOk());
+ EXPECT_EQ(200, response.headers->response_code());
+
+ // Create a new request for the same destination and verify that a
+ // new session is created.
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ QuicChromiumClientSession* new_session = GetActiveSession(host_port_pair_);
+ EXPECT_NE(session, new_session);
+
+ // On a DISCONNECTED notification, nothing happens to the migrated
+ // session, but the new session is closed since it has no open
+ // streams.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsLiveSession(factory_.get(), new_session));
+ stream.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, OnNetworkDisconnectedWithSynchronousWriteBefore) {
+ OnNetworkDisconnected(/*async_write_before=*/false);
+}
+
+TEST_P(QuicStreamFactoryTest, OnNetworkDisconnectedWithAsyncWriteBefore) {
+ OnNetworkDisconnected(/*async_write_before=*/true);
+}
+
+void QuicStreamFactoryTestBase::OnNetworkDisconnected(bool async_write_before) {
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ int packet_number = 1;
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(ConstructGetRequestPacket(
+ packet_number++, kClientDataStreamId1, true, true));
+ if (async_write_before) {
+ socket_data.AddWrite(ASYNC, OK);
+ packet_number++;
+ }
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = url_;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Send GET request on stream.
+ HttpResponseInfo response_info;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response_info,
+ callback_.callback()));
+
+ // Do an async write to leave writer blocked.
+ if (async_write_before)
+ session->connection()->SendPing();
+
+ // Set up second socket data provider that is used after migration.
+ // The response to the earlier request is read on this new socket.
+ MockQuicData socket_data1;
+ socket_data1.AddWrite(
+ client_maker_.MakePingPacket(packet_number++, /*include_version=*/true));
+ socket_data1.AddRead(
+ ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddWrite(client_maker_.MakeAckAndRstPacket(
+ packet_number++, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1,
+ 1, true));
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+
+ // Trigger connection migration. This should cause a PING frame
+ // to be emitted.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
+
+ // The session should now be marked as going away. Ensure that
+ // while it is still alive, it is no longer active.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ // Create a new request for the same destination and verify that a
+ // new session is created.
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ EXPECT_NE(session, GetActiveSession(host_port_pair_));
+ EXPECT_EQ(true,
+ QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+
+ stream.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, OnNetworkDisconnectedNoNetworks) {
+ NetworkChangeNotifier::NetworkList no_networks(0);
+ OnNetworkDisconnectedWithNetworkList(no_networks);
+}
+
+TEST_P(QuicStreamFactoryTest, OnNetworkDisconnectedNoNewNetwork) {
+ OnNetworkDisconnectedWithNetworkList({kDefaultNetworkForTests});
+}
+
+void QuicStreamFactoryTestBase::OnNetworkDisconnectedWithNetworkList(
+ NetworkChangeNotifier::NetworkList network_list) {
+ InitializeConnectionMigrationTest(network_list);
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ // Use the test task runner, to force the migration alarm timeout later.
+ QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Trigger connection migration. Since there are no networks
+ // to migrate to, this should cause the session to wait for a new network.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
+
+ // The migration will not fail until the migration alarm timeout.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+ EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback()));
+ EXPECT_EQ(true, session->connection()->writer()->IsWriteBlocked());
+
+ // Force the migration alarm timeout to run.
+ RunTestLoopUntilIdle();
+
+ // The connection should now be closed. A request for response
+ // headers should fail.
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(ERR_NETWORK_CHANGED, callback_.WaitForResult());
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, OnNetworkMadeDefaultNonMigratableStream) {
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(client_maker_.MakeRstPacket(
+ 1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // 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,
+ net_log_, CompletionCallback()));
+
+ // Ensure that session is alive and active.
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Trigger connection migration. Since there is a non-migratable stream,
+ // this should cause session to continue but be marked as going away.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkMadeDefault(kNewNetworkForTests);
+
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ stream.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, OnNetworkMadeDefaultConnectionMigrationDisabled) {
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(client_maker_.MakeRstPacket(
+ 1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Set session config to have connection migration disabled.
+ QuicConfigPeer::SetReceivedDisableConnectionMigration(session->config());
+ EXPECT_TRUE(session->config()->DisableConnectionMigration());
+
+ // Trigger connection migration. Since there is a non-migratable stream,
+ // this should cause session to continue but be marked as going away.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkMadeDefault(kNewNetworkForTests);
+
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ stream.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, OnNetworkDisconnectedNonMigratableStream) {
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(client_maker_.MakeRstPacket(
+ 1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT));
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // 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,
+ net_log_, CompletionCallback()));
+
+ // Ensure that session is alive and active.
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Trigger connection migration. Since there is a non-migratable stream,
+ // this should cause a RST_STREAM frame to be emitted with
+ // QUIC_RST_ACKNOWLEDGEMENT error code, and the session will be closed.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
+
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest,
+ OnNetworkDisconnectedConnectionMigrationDisabled) {
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(client_maker_.MakeRstPacket(
+ 1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT));
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Set session config to have connection migration disabled.
+ QuicConfigPeer::SetReceivedDisableConnectionMigration(session->config());
+ EXPECT_TRUE(session->config()->DisableConnectionMigration());
+
+ // Trigger connection migration. Since there is a non-migratable stream,
+ // this should cause a RST_STREAM frame to be emitted with
+ // QUIC_RST_ACKNOWLEDGEMENT error code, and the session will be closed.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
+
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, OnNetworkMadeDefaultNoOpenStreams) {
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Ensure that session is alive and active.
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Trigger connection migration. Since there are no active streams,
+ // the session will be closed.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkMadeDefault(kNewNetworkForTests);
+
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, OnNetworkDisconnectedNoOpenStreams) {
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Ensure that session is alive and active.
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Trigger connection migration. Since there are no active streams,
+ // the session will be closed.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
+
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedPauseBeforeConnected) {
+ InitializeConnectionMigrationTest({kDefaultNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(
+ ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = url_;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Send GET request on stream.
+ HttpResponseInfo response;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+ callback_.callback()));
+
+ // Trigger connection migration. Since there are no networks
+ // to migrate to, this should cause the session to wait for a new network.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
+
+ // The connection should still be alive, but marked as going away.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+ EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback()));
+
+ // Set up second socket data provider that is used after migration.
+ // The response to the earlier request is read on this new socket.
+ MockQuicData socket_data1;
+ socket_data1.AddWrite(
+ client_maker_.MakePingPacket(2, /*include_version=*/true));
+ socket_data1.AddRead(
+ ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddWrite(client_maker_.MakeAckAndRstPacket(
+ 3, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1, 1, true));
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+
+ // Add a new network and notify the stream factory of a new connected network.
+ // This causes a PING packet to be sent over the new network.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->SetConnectedNetworksList({kNewNetworkForTests});
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkConnected(kNewNetworkForTests);
+
+ // Ensure that the session is still alive.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ // Run the message loop so that data queued in the new socket is read by the
+ // packet reader.
+ base::RunLoop().RunUntilIdle();
+
+ // Response headers are received over the new network.
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ EXPECT_EQ(200, response.headers->response_code());
+
+ // Create a new request and verify that a new session is created.
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ EXPECT_NE(session, GetActiveSession(host_port_pair_));
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+
+ stream.reset();
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest,
+ OnNetworkChangeDisconnectedPauseBeforeConnectedMultipleSessions) {
+ InitializeConnectionMigrationTest({kDefaultNetworkForTests});
+
+ MockQuicData socket_data1;
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddWrite(ASYNC, OK);
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+
+ socket_data2.AddWrite(ASYNC, OK);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ HostPortPair server1(kDefaultServerHostName, 443);
+ HostPortPair server2(kServer2HostName, 443);
+
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.2", "");
+
+ // Create request and QuicHttpStream to create session1.
+ QuicStreamRequest request1(factory_.get());
+ EXPECT_EQ(OK, request1.Request(server1, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ std::unique_ptr<QuicHttpStream> stream1 = request1.CreateStream();
+ EXPECT_TRUE(stream1.get());
+
+ // Create request and QuicHttpStream to create session2.
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
+ /*cert_verify_flags=*/0, url2_, "GET",
+ net_log_, callback_.callback()));
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ QuicChromiumClientSession* session1 = GetActiveSession(server1);
+ QuicChromiumClientSession* session2 = GetActiveSession(server2);
+ EXPECT_NE(session1, session2);
+
+ // Cause QUIC stream to be created and send GET so session1 has an open
+ // stream.
+ HttpRequestInfo request_info1;
+ request_info1.method = "GET";
+ request_info1.url = url_;
+ EXPECT_EQ(OK, stream1->InitializeStream(&request_info1, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+ HttpResponseInfo response1;
+ HttpRequestHeaders request_headers1;
+ EXPECT_EQ(OK, stream1->SendRequest(request_headers1, &response1,
+ callback_.callback()));
+
+ // Cause QUIC stream to be created and send GET so session2 has an open
+ // stream.
+ HttpRequestInfo request_info2;
+ request_info2.method = "GET";
+ request_info2.url = url_;
+ EXPECT_EQ(OK, stream2->InitializeStream(&request_info2, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+ HttpResponseInfo response2;
+ HttpRequestHeaders request_headers2;
+ EXPECT_EQ(OK, stream2->SendRequest(request_headers2, &response2,
+ callback_.callback()));
+
+ // Cause both sessions to be paused due to DISCONNECTED.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
+
+ // Ensure that both sessions are paused but alive.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session1));
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session2));
+
+ // Add new sockets to use post migration.
+ MockConnect connect_result =
+ MockConnect(SYNCHRONOUS, ERR_INTERNET_DISCONNECTED);
+ SequencedSocketData socket_data3(connect_result, nullptr, 0, nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data3);
+ SequencedSocketData socket_data4(connect_result, nullptr, 0, nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data4);
+
+ // Add a new network and cause migration to bad sockets, causing sessions to
+ // close.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->SetConnectedNetworksList({kNewNetworkForTests});
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkConnected(kNewNetworkForTests);
+
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session1));
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session2));
+
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, MigrateSessionEarly) {
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(
+ ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = url_;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Send GET request on stream.
+ HttpResponseInfo response;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+ callback_.callback()));
+
+ MockQuicData socket_data1;
+ socket_data1.AddWrite(
+ client_maker_.MakePingPacket(2, /*include_version=*/true));
+ socket_data1.AddRead(
+ ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddWrite(client_maker_.MakeAckAndRstPacket(
+ 3, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1, 1, true));
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+
+ // Trigger early connection migration. This should cause a PING frame
+ // to be emitted.
+ session->OnPathDegrading();
+
+ // Run the message loop so that data queued in the new socket is read by the
+ // packet reader.
+ base::RunLoop().RunUntilIdle();
+
+ // The session should now be marked as going away. Ensure that
+ // while it is still alive, it is no longer active.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ // Verify that response headers on the migrated socket were delivered to the
+ // stream.
+ EXPECT_THAT(stream->ReadResponseHeaders(callback_.callback()), IsOk());
+ EXPECT_EQ(200, response.headers->response_code());
+
+ // Create a new request for the same destination and verify that a
+ // new session is created.
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ QuicChromiumClientSession* new_session = GetActiveSession(host_port_pair_);
+ EXPECT_NE(session, new_session);
+
+ // On a NETWORK_MADE_DEFAULT notification, nothing happens to the
+ // migrated session, but the new session is closed since it has no
+ // open streams.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkMadeDefault(kNewNetworkForTests);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsLiveSession(factory_.get(), new_session));
+
+ // On a DISCONNECTED notification, nothing happens to the migrated session.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ stream.reset();
+ stream2.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyWithAsyncWrites) {
+ // Nearly identical to MigrateSessionEarly except that the write to
+ // the second socket is asynchronous. Ensures that the callback
+ // infrastructure for asynchronous writes is set up correctly for
+ // the old connection on the migrated socket.
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(
+ ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = url_;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Send GET request on stream.
+ HttpResponseInfo response;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+ callback_.callback()));
+
+ // Set up second socket data provider that is used after migration.
+ // The response to the earlier request is read on this new socket.
+ MockQuicData socket_data1;
+ socket_data1.AddWrite(
+ client_maker_.MakePingPacket(2, /*include_version=*/true));
+ socket_data1.AddRead(
+ ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddWrite(client_maker_.MakeAckAndRstPacket(
+ 3, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1, 1, true));
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+
+ // Trigger early connection migration. This should cause a PING frame
+ // to be emitted.
+ session->OnPathDegrading();
+
+ // Run the message loop so that data queued in the new socket is read by the
+ // packet reader.
+ base::RunLoop().RunUntilIdle();
+
+ // The session should now be marked as going away. Ensure that
+ // while it is still alive, it is no longer active.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ // Verify that response headers on the migrated socket were delivered to the
+ // stream.
+ EXPECT_THAT(stream->ReadResponseHeaders(callback_.callback()), IsOk());
+ EXPECT_EQ(200, response.headers->response_code());
+
+ // Create a new request for the same destination and verify that a
+ // new session is created.
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ QuicChromiumClientSession* new_session = GetActiveSession(host_port_pair_);
+ EXPECT_NE(session, new_session);
+
+ // On a NETWORK_MADE_DEFAULT notification, nothing happens to the
+ // migrated session, but the new session is closed since it has no
+ // open streams.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkMadeDefault(kNewNetworkForTests);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+ EXPECT_FALSE(
+ QuicStreamFactoryPeer::IsLiveSession(factory_.get(), new_session));
+
+ // On a DISCONNECTED notification, nothing happens to the migrated session.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ stream.reset();
+ stream2.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyNoNewNetwork) {
+ InitializeConnectionMigrationTest({kDefaultNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(client_maker_.MakeRstPacket(
+ 1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Trigger connection migration. Since there are no networks
+ // to migrate to, this should cause session to be continue but be marked as
+ // going away.
+ session->OnPathDegrading();
+
+ // Run the message loop so that data queued in the new socket is read by the
+ // packet reader.
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ stream.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyNonMigratableStream) {
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(client_maker_.MakeRstPacket(
+ 1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // 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,
+ net_log_, CompletionCallback()));
+
+ // Ensure that session is alive and active.
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Trigger connection migration. Since there is a non-migratable stream,
+ // this should cause session to be continue without migrating.
+ session->OnPathDegrading();
+
+ // Run the message loop so that data queued in the new socket is read by the
+ // packet reader.
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ stream.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyConnectionMigrationDisabled) {
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(client_maker_.MakeRstPacket(
+ 1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Set session config to have connection migration disabled.
+ QuicConfigPeer::SetReceivedDisableConnectionMigration(session->config());
+ EXPECT_TRUE(session->config()->DisableConnectionMigration());
+
+ // Trigger connection migration. Since there is a non-migratable stream,
+ // this should cause session to be continue without migrating.
+ session->OnPathDegrading();
+
+ // Run the message loop so that data queued in the new socket is read by the
+ // packet reader.
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ stream.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+void QuicStreamFactoryTestBase::TestMigrationOnWriteError(
+ IoMode write_error_mode) {
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(write_error_mode, ERR_ADDRESS_UNREACHABLE);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_EQ(OK, callback_.WaitForResult());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.example.org/");
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Set up second socket data provider that is used after
+ // migration. The request is rewritten to this new socket, and the
+ // response to the request is read on this new socket.
+ MockQuicData socket_data1;
+ socket_data1.AddWrite(
+ ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
+ socket_data1.AddRead(
+ ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddWrite(client_maker_.MakeAckAndRstPacket(
+ 2, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1, 1, true));
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+
+ // Send GET request on stream. This should cause a write error, which triggers
+ // a connection migration attempt.
+ HttpResponseInfo response;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+ callback_.callback()));
+
+ // Run the message loop so that the migration attempt is executed and
+ // data queued in the new socket is read by the packet reader.
+ base::RunLoop().RunUntilIdle();
+
+ // The session should now be marked as going away. Ensure that
+ // while it is still alive, it is no longer active.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ // Verify that response headers on the migrated socket were delivered to the
+ // stream.
+ EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback()));
+ EXPECT_EQ(200, response.headers->response_code());
+
+ stream.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteErrorSynchronous) {
+ TestMigrationOnWriteError(SYNCHRONOUS);
+}
+
+TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteErrorAsync) {
+ TestMigrationOnWriteError(ASYNC);
+}
+
+void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorNoNewNetwork(
+ IoMode write_error_mode) {
+ InitializeConnectionMigrationTest({kDefaultNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ // Use the test task runner, to force the migration alarm timeout later.
+ QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(write_error_mode, ERR_ADDRESS_UNREACHABLE);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_EQ(OK, callback_.WaitForResult());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.example.org/");
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Send GET request on stream. This causes a write error, which triggers
+ // a connection migration attempt. Since there are no networks
+ // to migrate to, this causes the session to wait for a new network.
+ HttpResponseInfo response;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+ callback_.callback()));
+
+ // Complete any pending writes. Pending async MockQuicData writes
+ // are run on the message loop, not on the test runner.
+ base::RunLoop().RunUntilIdle();
+
+ // Write error causes migration task to be posted. Spin the loop.
+ if (write_error_mode == ASYNC)
+ runner_->RunNextTask();
+
+ // Migration has not yet failed. The session should be alive and active.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+ EXPECT_TRUE(session->connection()->writer()->IsWriteBlocked());
+
+ // The migration will not fail until the migration alarm timeout.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+ EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback()));
+
+ // Force migration alarm timeout to run.
+ RunTestLoopUntilIdle();
+
+ // The connection should be closed. A request for response headers
+ // should fail.
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(ERR_NETWORK_CHANGED, callback_.WaitForResult());
+ EXPECT_EQ(ERR_NETWORK_CHANGED,
+ stream->ReadResponseHeaders(callback_.callback()));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest,
+ MigrateSessionOnWriteErrorNoNewNetworkSynchronous) {
+ TestMigrationOnWriteErrorNoNewNetwork(SYNCHRONOUS);
+}
+
+TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteErrorNoNewNetworkAsync) {
+ TestMigrationOnWriteErrorNoNewNetwork(ASYNC);
+}
+
+void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorNonMigratableStream(
+ IoMode write_error_mode) {
+ DVLOG(1) << "Mode: "
+ << ((write_error_mode == SYNCHRONOUS) ? "SYNCHRONOUS" : "ASYNC");
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(write_error_mode, ERR_ADDRESS_UNREACHABLE);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_EQ(OK, callback_.WaitForResult());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created, but marked as non-migratable.
+ HttpRequestInfo request_info;
+ 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,
+ net_log_, CompletionCallback()));
+
+ // Ensure that session is alive and active.
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Send GET request on stream. This should cause a write error, which triggers
+ // a connection migration attempt.
+ HttpResponseInfo response;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+ callback_.callback()));
+
+ // Run message loop to execute migration attempt.
+ base::RunLoop().RunUntilIdle();
+
+ // Migration fails, and session is closed and deleted.
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest,
+ MigrateSessionOnWriteErrorNonMigratableStreamSynchronous) {
+ TestMigrationOnWriteErrorNonMigratableStream(SYNCHRONOUS);
+}
+
+TEST_P(QuicStreamFactoryTest,
+ MigrateSessionOnWriteErrorNonMigratableStreamAsync) {
+ TestMigrationOnWriteErrorNonMigratableStream(ASYNC);
+}
+
+void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorMigrationDisabled(
+ IoMode write_error_mode) {
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(write_error_mode, ERR_ADDRESS_UNREACHABLE);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_EQ(OK, callback_.WaitForResult());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.example.org/");
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Set session config to have connection migration disabled.
+ QuicConfigPeer::SetReceivedDisableConnectionMigration(session->config());
+ EXPECT_TRUE(session->config()->DisableConnectionMigration());
+
+ // Send GET request on stream. This should cause a write error, which triggers
+ // a connection migration attempt.
+ HttpResponseInfo response;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+ callback_.callback()));
+ // Run message loop to execute migration attempt.
+ base::RunLoop().RunUntilIdle();
+ // Migration fails, and session is closed and deleted.
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest,
+ MigrateSessionOnWriteErrorMigrationDisabledSynchronous) {
+ TestMigrationOnWriteErrorMigrationDisabled(SYNCHRONOUS);
+}
+
+TEST_P(QuicStreamFactoryTest,
+ MigrateSessionOnWriteErrorMigrationDisabledAsync) {
+ TestMigrationOnWriteErrorMigrationDisabled(ASYNC);
+}
+
+void QuicStreamFactoryTestBase::TestMigrationOnMultipleWriteErrors(
+ IoMode first_write_error_mode,
+ IoMode second_write_error_mode) {
+ const int kMaxReadersPerQuicSession = 5;
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ // Set up kMaxReadersPerQuicSession socket data providers, since
+ // migration will cause kMaxReadersPerQuicSession write failures as
+ // the session hops repeatedly between the two networks.
+ MockQuicData socket_data[kMaxReadersPerQuicSession + 1];
+ for (int i = 0; i <= kMaxReadersPerQuicSession; ++i) {
+ // The last socket is created but never used.
+ if (i < kMaxReadersPerQuicSession) {
+ socket_data[i].AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data[i].AddWrite(
+ (i % 2 == 0) ? first_write_error_mode : second_write_error_mode,
+ ERR_FAILED);
+ }
+ socket_data[i].AddSocketDataToFactory(&socket_factory_);
+ }
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_EQ(OK, callback_.WaitForResult());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.example.org/");
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Send GET request on stream. This should cause a write error, which triggers
+ // a connection migration attempt.
+ HttpResponseInfo response;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+ callback_.callback()));
+ EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback()));
+
+ // Run the message loop so that data queued in the new socket is read by the
+ // packet reader.
+ base::RunLoop().RunUntilIdle();
+
+ // The connection should be closed because of a write error after migration.
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR,
+ stream->ReadResponseHeaders(callback_.callback()));
+
+ stream.reset();
+ for (int i = 0; i <= kMaxReadersPerQuicSession; ++i) {
+ DLOG(INFO) << "Socket number: " << i;
+ EXPECT_TRUE(socket_data[i].AllReadDataConsumed());
+ EXPECT_TRUE(socket_data[i].AllWriteDataConsumed());
+ }
+}
+
+TEST_P(QuicStreamFactoryTest, MigrateSessionOnMultipleWriteErrorsSyncSync) {
+ TestMigrationOnMultipleWriteErrors(SYNCHRONOUS, SYNCHRONOUS);
+}
+
+TEST_P(QuicStreamFactoryTest, MigrateSessionOnMultipleWriteErrorsSyncAsync) {
+ TestMigrationOnMultipleWriteErrors(SYNCHRONOUS, ASYNC);
+}
+
+TEST_P(QuicStreamFactoryTest, MigrateSessionOnMultipleWriteErrorsAsyncSync) {
+ TestMigrationOnMultipleWriteErrors(ASYNC, SYNCHRONOUS);
+}
+
+TEST_P(QuicStreamFactoryTest, MigrateSessionOnMultipleWriteErrorsAsyncAsync) {
+ TestMigrationOnMultipleWriteErrors(ASYNC, ASYNC);
+}
+
+void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorWithNotificationQueued(
+ bool disconnected) {
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_EQ(OK, callback_.WaitForResult());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.example.org/");
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Set up second socket data provider that is used after
+ // migration. The request is rewritten to this new socket, and the
+ // response to the request is read on this new socket.
+ MockQuicData socket_data1;
+ socket_data1.AddWrite(
+ ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
+ socket_data1.AddRead(
+ ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddWrite(client_maker_.MakeAckAndRstPacket(
+ 2, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1, 1, true));
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+
+ // First queue a network change notification in the message loop.
+ if (disconnected) {
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->QueueNetworkDisconnected(kDefaultNetworkForTests);
+ } else {
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->QueueNetworkMadeDefault(kNewNetworkForTests);
+ }
+ // Send GET request on stream. This should cause a write error,
+ // which triggers a connection migration attempt. This will queue a
+ // migration attempt behind the notification in the message loop.
+ HttpResponseInfo response;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+ callback_.callback()));
+
+ base::RunLoop().RunUntilIdle();
+ // The session should now be marked as going away. Ensure that
+ // while it is still alive, it is no longer active.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ // Verify that response headers on the migrated socket were delivered to the
+ // stream.
+ EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback()));
+ EXPECT_EQ(200, response.headers->response_code());
+
+ stream.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest,
+ MigrateSessionOnWriteErrorWithNetworkDisconnectedQueued) {
+ TestMigrationOnWriteErrorWithNotificationQueued(/*disconnected=*/true);
+}
+
+TEST_P(QuicStreamFactoryTest,
+ MigrateSessionOnWriteErrorWithNetworkMadeDefaultQueued) {
+ TestMigrationOnWriteErrorWithNotificationQueued(/*disconnected=*/false);
+}
+
+void QuicStreamFactoryTestBase::TestMigrationOnNotificationWithWriteErrorQueued(
+ bool disconnected) {
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_EQ(OK, callback_.WaitForResult());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.example.org/");
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Set up second socket data provider that is used after
+ // migration. The request is rewritten to this new socket, and the
+ // response to the request is read on this new socket.
+ MockQuicData socket_data1;
+ socket_data1.AddWrite(
+ ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
+ socket_data1.AddRead(
+ ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddWrite(client_maker_.MakeAckAndRstPacket(
+ 2, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1, 1, true));
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+
+ // Send GET request on stream. This should cause a write error,
+ // which triggers a connection migration attempt. This will queue a
+ // migration attempt in the message loop.
+ HttpResponseInfo response;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+ callback_.callback()));
+
+ // Now queue a network change notification in the message loop behind
+ // the migration attempt.
+ if (disconnected) {
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->QueueNetworkDisconnected(kDefaultNetworkForTests);
+ } else {
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->QueueNetworkMadeDefault(kNewNetworkForTests);
+ }
+
+ base::RunLoop().RunUntilIdle();
+ // The session should now be marked as going away. Ensure that
+ // while it is still alive, it is no longer active.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ // Verify that response headers on the migrated socket were delivered to the
+ // stream.
+ EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback()));
+ EXPECT_EQ(200, response.headers->response_code());
+
+ stream.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest,
+ MigrateSessionOnNetworkDisconnectedWithWriteErrorQueued) {
+ TestMigrationOnNotificationWithWriteErrorQueued(/*disconnected=*/true);
+}
+
+TEST_P(QuicStreamFactoryTest,
+ MigrateSessionOnNetworkMadeDefaultWithWriteErrorQueued) {
+ TestMigrationOnNotificationWithWriteErrorQueued(/*disconnected=*/true);
+}
+
+void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorPauseBeforeConnected(
+ IoMode write_error_mode) {
+ InitializeConnectionMigrationTest({kDefaultNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(SYNCHRONOUS, ERR_FAILED);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_EQ(OK, callback_.WaitForResult());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.example.org/");
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Send GET request on stream. This should cause a write error, which triggers
+ // a connection migration attempt.
+ HttpResponseInfo response;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+ callback_.callback()));
+
+ // Run the message loop so that data queued in the new socket is read by the
+ // packet reader.
+ base::RunLoop().RunUntilIdle();
+
+ // In this particular code path, the network will not yet be marked
+ // as going away and the session will still be alive.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+ EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback()));
+
+ // On a DISCONNECTED notification, nothing happens.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
+
+ // Set up second socket data provider that is used after
+ // migration. The request is rewritten to this new socket, and the
+ // response to the request is read on this new socket.
+ MockQuicData socket_data1;
+ socket_data1.AddWrite(
+ ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
+ socket_data1.AddRead(
+ ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddWrite(client_maker_.MakeAckAndRstPacket(
+ 2, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1, 1, true));
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->SetConnectedNetworksList({kNewNetworkForTests});
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkConnected(kNewNetworkForTests);
+
+ // The session should now be marked as going away. Ensure that
+ // while it is still alive, it is no longer active.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ // This is the callback for the response headers that returned
+ // pending previously, because no result was available. Check that
+ // the result is now available due to the successful migration.
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ EXPECT_EQ(200, response.headers->response_code());
+
+ // Create a new request for the same destination and verify that a
+ // new session is created.
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ QuicChromiumClientSession* new_session = GetActiveSession(host_port_pair_);
+ EXPECT_NE(session, new_session);
+
+ stream.reset();
+ stream2.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest,
+ MigrateSessionOnWriteErrorPauseBeforeConnectedSync) {
+ TestMigrationOnWriteErrorPauseBeforeConnected(SYNCHRONOUS);
+}
+
+TEST_P(QuicStreamFactoryTest,
+ MigrateSessionOnWriteErrorPauseBeforeConnectedAsync) {
+ TestMigrationOnWriteErrorPauseBeforeConnected(ASYNC);
+}
+
+void QuicStreamFactoryTestBase::
+ TestMigrationOnWriteErrorWithNetworkAddedBeforeNotification(
+ IoMode write_error_mode,
+ bool disconnected) {
+ InitializeConnectionMigrationTest({kDefaultNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(SYNCHRONOUS, ERR_FAILED);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_EQ(OK, callback_.WaitForResult());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.example.org/");
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Send GET request on stream. This should cause a write error, which triggers
+ // a connection migration attempt.
+ HttpResponseInfo response;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+ callback_.callback()));
+
+ // Run the message loop so that data queued in the new socket is read by the
+ // packet reader.
+ base::RunLoop().RunUntilIdle();
+
+ // In this particular code path, the network will not yet be marked
+ // as going away and the session will still be alive.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+ EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback()));
+
+ // Set up second socket data provider that is used after
+ // migration. The request is rewritten to this new socket, and the
+ // response to the request is read on this new socket.
+ MockQuicData socket_data1;
+ socket_data1.AddWrite(
+ ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
+ socket_data1.AddRead(
+ ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddWrite(client_maker_.MakeAckAndRstPacket(
+ 2, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1, 1, true));
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->SetConnectedNetworksList(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+
+ // A notification triggers and completes migration.
+ if (disconnected) {
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
+ } else {
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkMadeDefault(kNewNetworkForTests);
+ }
+ // The session should now be marked as going away. Ensure that
+ // while it is still alive, it is no longer active.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ // This is the callback for the response headers that returned
+ // pending previously, because no result was available. Check that
+ // the result is now available due to the successful migration.
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ EXPECT_EQ(200, response.headers->response_code());
+
+ // Now deliver a CONNECTED notification. Nothing happens since
+ // migration was already finished earlier.
+ scoped_mock_network_change_notifier_->mock_network_change_notifier()
+ ->NotifyNetworkConnected(kNewNetworkForTests);
+
+ // Create a new request for the same destination and verify that a
+ // new session is created.
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ QuicChromiumClientSession* new_session = GetActiveSession(host_port_pair_);
+ EXPECT_NE(session, new_session);
+
+ stream.reset();
+ stream2.reset();
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest,
+ MigrateSessionOnWriteErrorWithNetworkAddedBeforeDisconnectedSync) {
+ TestMigrationOnWriteErrorWithNetworkAddedBeforeNotification(SYNCHRONOUS,
+ true);
+}
+
+TEST_P(QuicStreamFactoryTest,
+ MigrateSessionOnWriteErrorWithNetworkAddedBeforeDisconnectedAsync) {
+ TestMigrationOnWriteErrorWithNetworkAddedBeforeNotification(ASYNC, true);
+}
+
+TEST_P(QuicStreamFactoryTest,
+ MigrateSessionOnWriteErrorWithNetworkAddedBeforeMadeDefaultSync) {
+ TestMigrationOnWriteErrorWithNetworkAddedBeforeNotification(SYNCHRONOUS,
+ false);
+}
+
+TEST_P(QuicStreamFactoryTest,
+ MigrateSessionOnWriteErrorWithNetworkAddedBeforeMadeDefaultAsync) {
+ TestMigrationOnWriteErrorWithNetworkAddedBeforeNotification(ASYNC, false);
+}
+
+TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyToBadSocket) {
+ // This simulates the case where we attempt to migrate to a new
+ // socket but the socket is unusable, such as an ipv4/ipv6 mismatch.
+ InitializeConnectionMigrationTest(
+ {kDefaultNetworkForTests, kNewNetworkForTests});
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(
+ ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = url_;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Send GET request on stream.
+ HttpResponseInfo response;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+ callback_.callback()));
+
+ // Set up second socket that will immediately return disconnected.
+ // The stream factory will attempt to migrate to the new socket and
+ // immediately fail.
+ MockConnect connect_result =
+ MockConnect(SYNCHRONOUS, ERR_INTERNET_DISCONNECTED);
+ SequencedSocketData socket_data1(connect_result, nullptr, 0, nullptr, 0);
+ socket_factory_.AddSocketDataProvider(&socket_data1);
+
+ // Trigger early connection migration.
+ session->OnPathDegrading();
+
+ // Migration fails, and the session is marked as going away.
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, ServerMigration) {
+ allow_server_migration_ = true;
+ Initialize();
+
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data1;
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddWrite(
+ ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_EQ(OK, callback_.WaitForResult());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.example.org/");
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Send GET request on stream.
+ HttpResponseInfo response;
+ HttpRequestHeaders request_headers;
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
+ callback_.callback()));
+
+ IPEndPoint ip;
+ session->GetDefaultSocket()->GetPeerAddress(&ip);
+ DVLOG(1) << "Socket connected to: " << ip.address().ToString() << " "
+ << ip.port();
+
+ // Set up second socket data provider that is used after
+ // migration. The request is rewritten to this new socket, and the
+ // response to the request is read on this new socket.
+ MockQuicData socket_data2;
+ socket_data2.AddWrite(
+ client_maker_.MakePingPacket(2, /*include_version=*/true));
+ socket_data2.AddRead(
+ ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddWrite(client_maker_.MakeAckAndRstPacket(
+ 3, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1, 1, true));
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ const uint8_t kTestIpAddress[] = {1, 2, 3, 4};
+ const uint16_t kTestPort = 123;
+ factory_->MigrateSessionToNewPeerAddress(
+ session, IPEndPoint(IPAddress(kTestIpAddress), kTestPort), net_log_);
+
+ session->GetDefaultSocket()->GetPeerAddress(&ip);
+ DVLOG(1) << "Socket migrated to: " << ip.address().ToString() << " "
+ << ip.port();
+
+ // The session should be alive and active.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ // Run the message loop so that data queued in the new socket is read by the
+ // packet reader.
+ base::RunLoop().RunUntilIdle();
+
+ // Verify that response headers on the migrated socket were delivered to the
+ // stream.
+ EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback()));
+ EXPECT_EQ(200, response.headers->response_code());
+
+ stream.reset();
+
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, ServerMigrationIPv4ToIPv4) {
+ // Add alternate IPv4 server address to config.
+ IPEndPoint alt_address = IPEndPoint(IPAddress(1, 2, 3, 4), 123);
+ QuicConfig config;
+ config.SetAlternateServerAddressToSend(alt_address);
+ VerifyServerMigration(config, alt_address);
+}
+
+TEST_P(QuicStreamFactoryTest, ServerMigrationIPv6ToIPv6) {
+ // Add a resolver rule to make initial connection to an IPv6 address.
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "fe80::aebc:32ff:febb:1e33", "");
+ // Add alternate IPv6 server address to config.
+ IPEndPoint alt_address = IPEndPoint(
+ IPAddress(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), 123);
+ QuicConfig config;
+ config.SetAlternateServerAddressToSend(alt_address);
+ VerifyServerMigration(config, alt_address);
+}
+
+TEST_P(QuicStreamFactoryTest, ServerMigrationIPv6ToIPv4) {
+ // Add a resolver rule to make initial connection to an IPv6 address.
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "fe80::aebc:32ff:febb:1e33", "");
+ // Add alternate IPv4 server address to config.
+ IPEndPoint alt_address = IPEndPoint(IPAddress(1, 2, 3, 4), 123);
+ QuicConfig config;
+ config.SetAlternateServerAddressToSend(alt_address);
+ IPEndPoint expected_address(
+ ConvertIPv4ToIPv4MappedIPv6(alt_address.address()), alt_address.port());
+ VerifyServerMigration(config, expected_address);
+}
+
+TEST_P(QuicStreamFactoryTest, ServerMigrationIPv4ToIPv6Fails) {
+ allow_server_migration_ = true;
+ Initialize();
+
+ // Add a resolver rule to make initial connection to an IPv4 address.
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(), "1.2.3.4",
+ "");
+ // Add alternate IPv6 server address to config.
+ IPEndPoint alt_address = IPEndPoint(
+ IPAddress(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), 123);
+ QuicConfig config;
+ config.SetAlternateServerAddressToSend(alt_address);
+
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ crypto_client_stream_factory_.SetConfig(config);
+
+ // Set up only socket data provider.
+ MockQuicData socket_data1;
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddWrite(client_maker_.MakeRstPacket(
+ 1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_EQ(OK, callback_.WaitForResult());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.example.org/");
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ IPEndPoint actual_address;
+ session->GetDefaultSocket()->GetPeerAddress(&actual_address);
+ // No migration should have happened.
+ IPEndPoint expected_address =
+ IPEndPoint(IPAddress(1, 2, 3, 4), kDefaultServerPort);
+ EXPECT_EQ(actual_address, expected_address);
+ DVLOG(1) << "Socket connected to: " << actual_address.address().ToString()
+ << " " << actual_address.port();
+ DVLOG(1) << "Expected address: " << expected_address.address().ToString()
+ << " " << expected_address.port();
+
+ stream.reset();
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, OnSSLConfigChanged) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(ConstructClientRstPacket());
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ ssl_config_service_->NotifySSLConfigChange();
+ EXPECT_EQ(ERR_CERT_DATABASE_CHANGED,
+ stream->ReadResponseHeaders(callback_.callback()));
+ EXPECT_FALSE(factory_->require_confirmation());
+
+ // Now attempting to request a stream to the same origin should create
+ // a new session.
+
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ stream = request2.CreateStream();
+ stream.reset(); // Will reset stream 3.
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, OnCertAdded) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(ConstructClientRstPacket());
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ // Add a cert and verify that stream saw the event.
+ factory_->OnCertAdded(nullptr);
+ EXPECT_EQ(ERR_CERT_DATABASE_CHANGED,
+ stream->ReadResponseHeaders(callback_.callback()));
+ EXPECT_FALSE(factory_->require_confirmation());
+
+ // Now attempting to request a stream to the same origin should create
+ // a new session.
+
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ stream = request2.CreateStream();
+ stream.reset(); // Will reset stream 3.
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, OnCACertChanged) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddWrite(ConstructClientRstPacket());
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ // Change the CA cert and verify that stream saw the event.
+ factory_->OnCACertChanged(nullptr);
+ EXPECT_EQ(ERR_CERT_DATABASE_CHANGED,
+ stream->ReadResponseHeaders(callback_.callback()));
+ EXPECT_FALSE(factory_->require_confirmation());
+
+ // Now attempting to request a stream to the same origin should create
+ // a new session.
+
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ stream = request2.CreateStream();
+ stream.reset(); // Will reset stream 3.
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, SharedCryptoConfig) {
+ Initialize();
+
+ vector<string> cannoncial_suffixes;
+ cannoncial_suffixes.push_back(string(".c.youtube.com"));
+ cannoncial_suffixes.push_back(string(".googlevideo.com"));
+
+ for (unsigned i = 0; i < cannoncial_suffixes.size(); ++i) {
+ string r1_host_name("r1");
+ string r2_host_name("r2");
+ r1_host_name.append(cannoncial_suffixes[i]);
+ r2_host_name.append(cannoncial_suffixes[i]);
+
+ HostPortPair host_port_pair1(r1_host_name, 80);
+ QuicCryptoClientConfig* crypto_config =
+ QuicStreamFactoryPeer::GetCryptoConfig(factory_.get());
+ QuicServerId server_id1(host_port_pair1, privacy_mode_);
+ QuicCryptoClientConfig::CachedState* cached1 =
+ crypto_config->LookupOrCreate(server_id1);
+ EXPECT_FALSE(cached1->proof_valid());
+ EXPECT_TRUE(cached1->source_address_token().empty());
+
+ // Mutate the cached1 to have different data.
+ // TODO(rtenneti): mutate other members of CachedState.
+ cached1->set_source_address_token(r1_host_name);
+ cached1->SetProofValid();
+
+ HostPortPair host_port_pair2(r2_host_name, 80);
+ QuicServerId server_id2(host_port_pair2, privacy_mode_);
+ QuicCryptoClientConfig::CachedState* cached2 =
+ crypto_config->LookupOrCreate(server_id2);
+ EXPECT_EQ(cached1->source_address_token(), cached2->source_address_token());
+ EXPECT_TRUE(cached2->proof_valid());
+ }
+}
+
+TEST_P(QuicStreamFactoryTest, CryptoConfigWhenProofIsInvalid) {
+ Initialize();
+ vector<string> cannoncial_suffixes;
+ cannoncial_suffixes.push_back(string(".c.youtube.com"));
+ cannoncial_suffixes.push_back(string(".googlevideo.com"));
+
+ for (unsigned i = 0; i < cannoncial_suffixes.size(); ++i) {
+ string r3_host_name("r3");
+ string r4_host_name("r4");
+ r3_host_name.append(cannoncial_suffixes[i]);
+ r4_host_name.append(cannoncial_suffixes[i]);
+
+ HostPortPair host_port_pair1(r3_host_name, 80);
+ QuicCryptoClientConfig* crypto_config =
+ QuicStreamFactoryPeer::GetCryptoConfig(factory_.get());
+ QuicServerId server_id1(host_port_pair1, privacy_mode_);
+ QuicCryptoClientConfig::CachedState* cached1 =
+ crypto_config->LookupOrCreate(server_id1);
+ EXPECT_FALSE(cached1->proof_valid());
+ EXPECT_TRUE(cached1->source_address_token().empty());
+
+ // Mutate the cached1 to have different data.
+ // TODO(rtenneti): mutate other members of CachedState.
+ cached1->set_source_address_token(r3_host_name);
+ cached1->SetProofInvalid();
+
+ HostPortPair host_port_pair2(r4_host_name, 80);
+ QuicServerId server_id2(host_port_pair2, privacy_mode_);
+ QuicCryptoClientConfig::CachedState* cached2 =
+ crypto_config->LookupOrCreate(server_id2);
+ EXPECT_NE(cached1->source_address_token(), cached2->source_address_token());
+ EXPECT_TRUE(cached2->source_address_token().empty());
+ EXPECT_FALSE(cached2->proof_valid());
+ }
+}
+
+TEST_P(QuicStreamFactoryTest, RacingConnections) {
+ disable_disk_cache_ = false;
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ if (!enable_connection_racing_)
+ return;
+
+ QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ const AlternativeService alternative_service1(QUIC, host_port_pair_.host(),
+ host_port_pair_.port());
+ AlternativeServiceInfoVector alternative_service_info_vector;
+ base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
+ alternative_service_info_vector.push_back(
+ AlternativeServiceInfo(alternative_service1, expiration));
+
+ http_server_properties_.SetAlternativeServices(
+ url::SchemeHostPort(url_), alternative_service_info_vector);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::ZERO_RTT);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+
+ QuicStreamRequest request(factory_.get());
+ QuicServerId server_id(host_port_pair_, privacy_mode_);
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_EQ(2u, QuicStreamFactoryPeer::GetNumberOfActiveJobs(factory_.get(),
+ server_id));
+
+ runner_->RunNextTask();
+
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumberOfActiveJobs(factory_.get(),
+ server_id));
+}
+
+TEST_P(QuicStreamFactoryTest, EnableNotLoadFromDiskCache) {
+ disable_disk_cache_ = true;
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::ZERO_RTT);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ // If we are waiting for disk cache, we would have posted a task. Verify that
+ // the CancelWaitForDataReady task hasn't been posted.
+ ASSERT_EQ(0u, runner_->GetPostedTasks().size());
+
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, ReducePingTimeoutOnConnectionTimeOutOpenStreams) {
+ reduced_ping_timeout_seconds_ = 10;
+ disable_disk_cache_ = true;
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ HostPortPair server2(kServer2HostName, kDefaultServerPort);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::CONFIRM_HANDSHAKE);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+ host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
+
+ // Quic should use default PING timeout when no previous connection times out
+ // with open stream.
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
+ QuicStreamFactoryPeer::GetPingTimeout(factory_.get()));
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(kPingTimeoutSecs),
+ session->connection()->ping_timeout());
+
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ DVLOG(1)
+ << "Created 1st session and initialized a stream. Now trigger timeout";
+ session->connection()->CloseConnection(QUIC_NETWORK_IDLE_TIMEOUT, "test",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ // The first connection times out with open stream, QUIC should reduce initial
+ // PING time for subsequent connections.
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(10),
+ QuicStreamFactoryPeer::GetPingTimeout(factory_.get()));
+
+ // Test two-in-a-row timeouts with open streams.
+ DVLOG(1) << "Create 2nd session and timeout with open stream";
+ TestCompletionCallback callback2;
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
+ /*cert_verify_flags=*/0, url2_, "GET",
+ net_log_, callback2.callback()));
+ QuicChromiumClientSession* session2 = GetActiveSession(server2);
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(10),
+ session2->connection()->ping_timeout());
+
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+ EXPECT_EQ(OK, stream2->InitializeStream(&request_info, 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
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop2;
+ run_loop2.RunUntilIdle();
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, DisableQuicWhenTimeoutsWithOpenStreams) {
+ disable_disk_cache_ = true;
+ disable_quic_on_timeout_with_open_streams_ = true;
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
+
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::CONFIRM_HANDSHAKE);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+
+ // Test first timeouts with open streams will disable QUIC.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ DVLOG(1)
+ << "Created 1st session and initialized a stream. Now trigger timeout."
+ << "Will disable QUIC.";
+ session->connection()->CloseConnection(QUIC_NETWORK_IDLE_TIMEOUT, "test",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ // Verify that QUIC is fully disabled after a TCP job succeeds.
+ factory_->OnTcpJobCompleted(/*succeeded=*/true);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ // Verify that QUIC stays disabled after a TCP job succeeds.
+ factory_->OnTcpJobCompleted(/*succeeded=*/false);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest,
+ DisableQuicWhenTimeoutsWithOpenStreamsExponentialBackoff) {
+ disable_disk_cache_ = true;
+ disable_quic_on_timeout_with_open_streams_ = true;
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
+
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::CONFIRM_HANDSHAKE);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+
+ // Test first timeouts with open streams will disable QUIC.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ DVLOG(1)
+ << "Created 1st session and initialized a stream. Now trigger timeout."
+ << "Will disable QUIC.";
+ session->connection()->CloseConnection(QUIC_NETWORK_IDLE_TIMEOUT, "test",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ ASSERT_EQ(1u, runner_->GetPostedTasks().size());
+ ASSERT_EQ(clock_->NowInTicks() + base::TimeDelta::FromMinutes(5),
+ runner_->GetPostedTasks()[0].GetTimeToRun());
+ runner_->RunNextTask();
+
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ ASSERT_TRUE(runner_->GetPostedTasks().empty());
+
+ // Create a new session which will cause a task to be posted to
+ // clear the exponential backoff.
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ QuicChromiumClientSession* session2 = GetActiveSession(host_port_pair_);
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+ HttpRequestInfo request_info2;
+ EXPECT_EQ(OK, stream2->InitializeStream(&request_info2, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ // Check that the clear task has been posted.
+ ASSERT_EQ(1u, runner_->GetPostedTasks().size());
+ ASSERT_EQ(clock_->NowInTicks() + base::TimeDelta::FromMinutes(5),
+ runner_->GetPostedTasks()[0].GetTimeToRun());
+
+ session2->connection()->CloseConnection(
+ QUIC_NETWORK_IDLE_TIMEOUT, "test", ConnectionCloseBehavior::SILENT_CLOSE);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ ASSERT_EQ(2u, runner_->GetPostedTasks().size());
+ ASSERT_EQ(clock_->NowInTicks() + base::TimeDelta::FromMinutes(10),
+ runner_->GetPostedTasks()[1].GetTimeToRun());
+ runner_->RunNextTask();
+
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest,
+ DisableQuicWhenTimeoutsWithOpenStreamsExponentialBackoffReset) {
+ disable_disk_cache_ = true;
+ disable_quic_on_timeout_with_open_streams_ = true;
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
+
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::CONFIRM_HANDSHAKE);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+
+ // Test first timeouts with open streams will disable QUIC.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ DVLOG(1)
+ << "Created 1st session and initialized a stream. Now trigger timeout."
+ << "Will disable QUIC.";
+ session->connection()->CloseConnection(QUIC_NETWORK_IDLE_TIMEOUT, "test",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ ASSERT_EQ(1u, runner_->GetPostedTasks().size());
+ ASSERT_EQ(clock_->NowInTicks() + base::TimeDelta::FromMinutes(5),
+ runner_->GetPostedTasks()[0].GetTimeToRun());
+ runner_->RunNextTask();
+
+ // Need to spin the loop now to ensure that
+ // QuicStreamFactory::OnSessionClosed() runs.
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ ASSERT_TRUE(runner_->GetPostedTasks().empty());
+
+ // Create a new session which will cause a task to be posted to
+ // clear the exponential backoff.
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ QuicChromiumClientSession* session2 = GetActiveSession(host_port_pair_);
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+ HttpRequestInfo request_info2;
+ EXPECT_EQ(OK, stream2->InitializeStream(&request_info2, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ // Run the clear task and verify that the next disabling is
+ // back to the default timeout.
+ runner_->RunNextTask();
+
+ // QUIC should still be enabled.
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ session2->connection()->CloseConnection(
+ QUIC_NETWORK_IDLE_TIMEOUT, "test", ConnectionCloseBehavior::SILENT_CLOSE);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ ASSERT_EQ(1u, runner_->GetPostedTasks().size());
+ ASSERT_EQ(clock_->NowInTicks() + base::TimeDelta::FromMinutes(5),
+ runner_->GetPostedTasks()[0].GetTimeToRun());
+ runner_->RunNextTask();
+
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get()));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, EnableDelayTcpRace) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ bool delay_tcp_race = QuicStreamFactoryPeer::GetDelayTcpRace(factory_.get());
+ QuicStreamFactoryPeer::SetDelayTcpRace(factory_.get(), false);
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ ServerNetworkStats stats1;
+ stats1.srtt = base::TimeDelta::FromMicroseconds(10);
+ http_server_properties_.SetServerNetworkStats(url::SchemeHostPort(url_),
+ stats1);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::COLD_START);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "POST", net_log_,
+ callback_.callback()));
+
+ // If we don't delay TCP connection, then time delay should be 0.
+ EXPECT_FALSE(factory_->delay_tcp_race());
+ EXPECT_EQ(base::TimeDelta(), request.GetTimeDelayForWaitingJob());
+
+ // Enable |delay_tcp_race_| param and verify delay is one RTT and that
+ // server supports QUIC.
+ QuicStreamFactoryPeer::SetDelayTcpRace(factory_.get(), true);
+ EXPECT_TRUE(factory_->delay_tcp_race());
+ EXPECT_EQ(base::TimeDelta::FromMicroseconds(15),
+ request.GetTimeDelayForWaitingJob());
+
+ // Confirm the handshake and verify that the stream is created.
+ crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
+ QuicSession::HANDSHAKE_CONFIRMED);
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ QuicStreamFactoryPeer::SetDelayTcpRace(factory_.get(), delay_tcp_race);
+}
+
+// Verifies that the QUIC stream factory is initialized correctly.
+TEST_P(QuicStreamFactoryTest, MaybeInitialize) {
+ VerifyInitialization(false);
+}
+
+// Verifies that the alternative proxy server provided by the proxy delegate
+// is added to the list of supported QUIC proxy servers, and the QUIC stream
+// factory is initialized correctly.
+TEST_P(QuicStreamFactoryTest, MaybeInitializeAlternativeProxyServer) {
+ VerifyInitialization(true);
+}
+
+TEST_P(QuicStreamFactoryTest, StartCertVerifyJob) {
+ Initialize();
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ // Save current state of |race_cert_verification|.
+ bool race_cert_verification =
+ QuicStreamFactoryPeer::GetRaceCertVerification(factory_.get());
+
+ // Load server config.
+ HostPortPair host_port_pair(kDefaultServerHostName, kDefaultServerPort);
+ QuicServerId quic_server_id(host_port_pair_, privacy_mode_);
+ QuicStreamFactoryPeer::CacheDummyServerConfig(factory_.get(), quic_server_id);
+
+ QuicStreamFactoryPeer::SetRaceCertVerification(factory_.get(), true);
+ EXPECT_FALSE(HasActiveCertVerifierJob(quic_server_id));
+
+ // Start CertVerifyJob.
+ QuicAsyncStatus status = QuicStreamFactoryPeer::StartCertVerifyJob(
+ factory_.get(), quic_server_id, /*cert_verify_flags=*/0, net_log_);
+ if (status == QUIC_PENDING) {
+ // Verify CertVerifierJob has started.
+ EXPECT_TRUE(HasActiveCertVerifierJob(quic_server_id));
+
+ while (HasActiveCertVerifierJob(quic_server_id)) {
+ base::RunLoop().RunUntilIdle();
+ }
+ }
+ // Verify CertVerifierJob has finished.
+ EXPECT_FALSE(HasActiveCertVerifierJob(quic_server_id));
+
+ // Start a QUIC request.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_EQ(OK, callback_.WaitForResult());
+
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ // Restore |race_cert_verification|.
+ QuicStreamFactoryPeer::SetRaceCertVerification(factory_.get(),
+ race_cert_verification);
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+
+ // Verify there are no outstanding CertVerifierJobs after request has
+ // finished.
+ EXPECT_FALSE(HasActiveCertVerifierJob(quic_server_id));
+}
+
+TEST_P(QuicStreamFactoryTest, QuicDoingZeroRTT) {
+ Initialize();
+
+ factory_->set_require_confirmation(true);
+ QuicServerId quic_server_id(host_port_pair_, PRIVACY_MODE_DISABLED);
+ EXPECT_FALSE(factory_->ZeroRTTEnabledFor(quic_server_id));
+
+ factory_->set_require_confirmation(false);
+ EXPECT_FALSE(factory_->ZeroRTTEnabledFor(quic_server_id));
+
+ // Load server config and verify QUIC will do 0RTT.
+ QuicStreamFactoryPeer::CacheDummyServerConfig(factory_.get(), quic_server_id);
+ EXPECT_TRUE(factory_->ZeroRTTEnabledFor(quic_server_id));
+}
+
+TEST_P(QuicStreamFactoryTest, YieldAfterPackets) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ QuicStreamFactoryPeer::SetYieldAfterPackets(factory_.get(), 0);
+
+ MockQuicData socket_data;
+ socket_data.AddSynchronousRead(ConstructClientConnectionClosePacket(0));
+ socket_data.AddRead(ASYNC, OK);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::ZERO_RTT);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+
+ // Set up the TaskObserver to verify QuicChromiumPacketReader::StartReading
+ // posts a task.
+ // TODO(rtenneti): Change SpdySessionTestTaskObserver to NetTestTaskObserver??
+ SpdySessionTestTaskObserver observer("quic_chromium_packet_reader.cc",
+ "StartReading");
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ // Call run_loop so that QuicChromiumPacketReader::OnReadComplete() gets
+ // called.
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+
+ // Verify task that the observer's executed_count is 1, which indicates
+ // QuicChromiumPacketReader::StartReading() has posted only one task and
+ // yielded the read.
+ EXPECT_EQ(1u, observer.executed_count());
+
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_FALSE(stream.get()); // Session is already closed.
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, YieldAfterDuration) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ QuicStreamFactoryPeer::SetYieldAfterDuration(
+ factory_.get(), QuicTime::Delta::FromMilliseconds(-1));
+
+ MockQuicData socket_data;
+ socket_data.AddSynchronousRead(ConstructClientConnectionClosePacket(0));
+ socket_data.AddRead(ASYNC, OK);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ crypto_client_stream_factory_.set_handshake_mode(
+ MockCryptoClientStream::ZERO_RTT);
+ host_resolver_.set_synchronous_mode(true);
+ host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
+ "192.168.0.1", "");
+
+ // Set up the TaskObserver to verify QuicChromiumPacketReader::StartReading
+ // posts a task.
+ // TODO(rtenneti): Change SpdySessionTestTaskObserver to NetTestTaskObserver??
+ SpdySessionTestTaskObserver observer("quic_chromium_packet_reader.cc",
+ "StartReading");
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ // Call run_loop so that QuicChromiumPacketReader::OnReadComplete() gets
+ // called.
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+
+ // Verify task that the observer's executed_count is 1, which indicates
+ // QuicChromiumPacketReader::StartReading() has posted only one task and
+ // yielded the read.
+ EXPECT_EQ(1u, observer.executed_count());
+
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_FALSE(stream.get()); // Session is already closed.
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, ServerPushSessionAffinity) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumPushStreamsCreated(factory_.get()));
+
+ string url = "https://www.example.org/";
+
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+
+ QuicClientPromisedInfo promised(session, kServerDataStreamId1, kDefaultUrl);
+ (*QuicStreamFactoryPeer::GetPushPromiseIndex(factory_.get())
+ ->promised_by_url())[kDefaultUrl] = &promised;
+
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumPushStreamsCreated(factory_.get()));
+}
+
+TEST_P(QuicStreamFactoryTest, ServerPushPrivacyModeMismatch) {
+ Initialize();
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data1;
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data1.AddWrite(client_maker_.MakeRstPacket(
+ 1, true, kServerDataStreamId1, QUIC_STREAM_CANCELLED));
+ socket_data1.AddSocketDataToFactory(&socket_factory_);
+
+ MockQuicData socket_data2;
+ socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data2.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
+ EXPECT_TRUE(stream.get());
+
+ EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumPushStreamsCreated(factory_.get()));
+
+ string url = "https://www.example.org/";
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+
+ QuicClientPromisedInfo promised(session, kServerDataStreamId1, kDefaultUrl);
+
+ QuicClientPushPromiseIndex* index =
+ QuicStreamFactoryPeer::GetPushPromiseIndex(factory_.get());
+
+ (*index->promised_by_url())[kDefaultUrl] = &promised;
+ EXPECT_EQ(index->GetPromised(kDefaultUrl), &promised);
+
+ // Doing the request should not use the push stream, but rather
+ // cancel it because the privacy modes do not match.
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(host_port_pair_, PRIVACY_MODE_ENABLED,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumPushStreamsCreated(factory_.get()));
+ EXPECT_EQ(index->GetPromised(kDefaultUrl), nullptr);
+
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
+// Pool to existing session with matching QuicServerId
+// even if destination is different.
+TEST_P(QuicStreamFactoryTest, PoolByOrigin) {
+ Initialize();
+
+ HostPortPair destination1("first.example.com", 443);
+ HostPortPair destination2("second.example.com", 443);
+
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request1(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request1.Request(destination1, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream1 = request1.CreateStream();
+ EXPECT_TRUE(stream1.get());
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Second request returns synchronously because it pools to existing session.
+ TestCompletionCallback callback2;
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(destination2, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback2.callback()));
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ QuicChromiumClientSession* session1 =
+ QuicHttpStreamPeer::GetSession(stream1.get());
+ QuicChromiumClientSession* session2 =
+ QuicHttpStreamPeer::GetSession(stream2.get());
+ EXPECT_EQ(session1, session2);
+ EXPECT_EQ(QuicServerId(host_port_pair_, privacy_mode_),
+ session1->server_id());
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+}
+
+TEST_P(QuicStreamFactoryTest, ForceHolBlockingEnabled) {
+ force_hol_blocking_ = true;
+ Initialize();
+
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+ MockQuicData socket_data;
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
+ socket_data.AddSocketDataToFactory(&socket_factory_);
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, url_, "GET", net_log_,
+ callback_.callback()));
+
+ EXPECT_EQ(OK, callback_.WaitForResult());
+
+ QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
+ if (session->connection()->version() > QUIC_VERSION_35) {
+ EXPECT_TRUE(session->force_hol_blocking());
+ } else {
+ EXPECT_FALSE(session->force_hol_blocking());
+ }
+}
+
+class QuicStreamFactoryWithDestinationTest
+ : public QuicStreamFactoryTestBase,
+ public ::testing::TestWithParam<PoolingTestParams> {
+ protected:
+ QuicStreamFactoryWithDestinationTest()
+ : QuicStreamFactoryTestBase(GetParam().version,
+ GetParam().enable_connection_racing),
+ destination_type_(GetParam().destination_type),
+ hanging_read_(SYNCHRONOUS, ERR_IO_PENDING, 0) {}
+
+ HostPortPair GetDestination() {
+ switch (destination_type_) {
+ case SAME_AS_FIRST:
+ return origin1_;
+ case SAME_AS_SECOND:
+ return origin2_;
+ case DIFFERENT:
+ return HostPortPair(kDifferentHostname, 443);
+ default:
+ NOTREACHED();
+ return HostPortPair();
+ }
+ }
+
+ void AddHangingSocketData() {
+ std::unique_ptr<SequencedSocketData> sequenced_socket_data(
+ new SequencedSocketData(&hanging_read_, 1, nullptr, 0));
+ socket_factory_.AddSocketDataProvider(sequenced_socket_data.get());
+ sequenced_socket_data_vector_.push_back(std::move(sequenced_socket_data));
+ }
+
+ bool AllDataConsumed() {
+ for (const auto& socket_data_ptr : sequenced_socket_data_vector_) {
+ if (!socket_data_ptr->AllReadDataConsumed() ||
+ !socket_data_ptr->AllWriteDataConsumed()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ DestinationType destination_type_;
+ HostPortPair origin1_;
+ HostPortPair origin2_;
+ MockRead hanging_read_;
+ vector<std::unique_ptr<SequencedSocketData>> sequenced_socket_data_vector_;
+};
+
+INSTANTIATE_TEST_CASE_P(Version,
+ QuicStreamFactoryWithDestinationTest,
+ ::testing::ValuesIn(GetPoolingTestParams()));
+
+// A single QUIC request fails because the certificate does not match the origin
+// hostname, regardless of whether it matches the alternative service hostname.
+TEST_P(QuicStreamFactoryWithDestinationTest, InvalidCertificate) {
+ if (destination_type_ == DIFFERENT)
+ return;
+
+ Initialize();
+
+ GURL url("https://mail.example.com/");
+ origin1_ = HostPortPair::FromURL(url);
+
+ // Not used for requests, but this provides a test case where the certificate
+ // is valid for the hostname of the alternative service.
+ origin2_ = HostPortPair("mail.example.org", 433);
+
+ HostPortPair destination = GetDestination();
+
+ scoped_refptr<X509Certificate> cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
+ bool unused;
+ ASSERT_FALSE(cert->VerifyNameMatch(origin1_.host(), &unused));
+ ASSERT_TRUE(cert->VerifyNameMatch(origin2_.host(), &unused));
+
+ 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);
+
+ AddHangingSocketData();
+
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING, request.Request(destination, privacy_mode_,
+ /*cert_verify_flags=*/0, url, "GET",
+ net_log_, callback_.callback()));
+
+ EXPECT_THAT(callback_.WaitForResult(), IsError(ERR_QUIC_HANDSHAKE_FAILED));
+
+ EXPECT_TRUE(AllDataConsumed());
+}
+
+// QuicStreamRequest is pooled based on |destination| if certificate matches.
+TEST_P(QuicStreamFactoryWithDestinationTest, SharedCertificate) {
+ Initialize();
+
+ GURL url1("https://www.example.org/");
+ GURL url2("https://mail.example.org/");
+ origin1_ = HostPortPair::FromURL(url1);
+ origin2_ = HostPortPair::FromURL(url2);
+
+ HostPortPair destination = GetDestination();
+
+ scoped_refptr<X509Certificate> cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
+ bool unused;
+ ASSERT_TRUE(cert->VerifyNameMatch(origin1_.host(), &unused));
+ ASSERT_TRUE(cert->VerifyNameMatch(origin2_.host(), &unused));
+ ASSERT_FALSE(cert->VerifyNameMatch(kDifferentHostname, &unused));
+
+ 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);
+
+ AddHangingSocketData();
+
+ QuicStreamRequest request1(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request1.Request(destination, privacy_mode_,
+ /*cert_verify_flags=*/0, url1, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream1 = request1.CreateStream();
+ EXPECT_TRUE(stream1.get());
+ EXPECT_TRUE(HasActiveSession(origin1_));
+
+ // Second request returns synchronously because it pools to existing session.
+ TestCompletionCallback callback2;
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(OK, request2.Request(destination, privacy_mode_,
+ /*cert_verify_flags=*/0, url2, "GET", net_log_,
+ callback2.callback()));
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ QuicChromiumClientSession* session1 =
+ QuicHttpStreamPeer::GetSession(stream1.get());
+ QuicChromiumClientSession* session2 =
+ QuicHttpStreamPeer::GetSession(stream2.get());
+ EXPECT_EQ(session1, session2);
+
+ EXPECT_EQ(QuicServerId(origin1_, privacy_mode_), session1->server_id());
+
+ EXPECT_TRUE(AllDataConsumed());
+}
+
+// QuicStreamRequest is not pooled if PrivacyMode differs.
+TEST_P(QuicStreamFactoryWithDestinationTest, DifferentPrivacyMode) {
+ Initialize();
+
+ GURL url1("https://www.example.org/");
+ GURL url2("https://mail.example.org/");
+ origin1_ = HostPortPair::FromURL(url1);
+ origin2_ = HostPortPair::FromURL(url2);
+
+ HostPortPair destination = GetDestination();
+
+ scoped_refptr<X509Certificate> cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
+ bool unused;
+ ASSERT_TRUE(cert->VerifyNameMatch(origin1_.host(), &unused));
+ ASSERT_TRUE(cert->VerifyNameMatch(origin2_.host(), &unused));
+ ASSERT_FALSE(cert->VerifyNameMatch(kDifferentHostname, &unused));
+
+ ProofVerifyDetailsChromium verify_details1;
+ verify_details1.cert_verify_result.verified_cert = cert;
+ verify_details1.cert_verify_result.is_issued_by_known_root = true;
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details1);
+
+ ProofVerifyDetailsChromium verify_details2;
+ verify_details2.cert_verify_result.verified_cert = cert;
+ verify_details2.cert_verify_result.is_issued_by_known_root = true;
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2);
+
+ AddHangingSocketData();
+ AddHangingSocketData();
+
+ QuicStreamRequest request1(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request1.Request(destination, PRIVACY_MODE_DISABLED,
+ /*cert_verify_flags=*/0, url1, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_EQ(OK, callback_.WaitForResult());
+ std::unique_ptr<QuicHttpStream> stream1 = request1.CreateStream();
+ EXPECT_TRUE(stream1.get());
+ EXPECT_TRUE(HasActiveSession(origin1_));
+
+ TestCompletionCallback callback2;
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(destination, PRIVACY_MODE_ENABLED,
+ /*cert_verify_flags=*/0, url2, "GET", net_log_,
+ callback2.callback()));
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ // |request2| does not pool to the first session, because PrivacyMode does not
+ // match. Instead, another session is opened to the same destination, but
+ // with a different QuicServerId.
+ QuicChromiumClientSession* session1 =
+ QuicHttpStreamPeer::GetSession(stream1.get());
+ QuicChromiumClientSession* session2 =
+ QuicHttpStreamPeer::GetSession(stream2.get());
+ EXPECT_NE(session1, session2);
+
+ EXPECT_EQ(QuicServerId(origin1_, PRIVACY_MODE_DISABLED),
+ session1->server_id());
+ EXPECT_EQ(QuicServerId(origin2_, PRIVACY_MODE_ENABLED),
+ session2->server_id());
+
+ EXPECT_TRUE(AllDataConsumed());
+}
+
+// QuicStreamRequest is not pooled if certificate does not match its origin.
+TEST_P(QuicStreamFactoryWithDestinationTest, DisjointCertificate) {
+ Initialize();
+
+ GURL url1("https://news.example.org/");
+ GURL url2("https://mail.example.com/");
+ origin1_ = HostPortPair::FromURL(url1);
+ origin2_ = HostPortPair::FromURL(url2);
+
+ HostPortPair destination = GetDestination();
+
+ scoped_refptr<X509Certificate> cert1(
+ ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
+ bool unused;
+ ASSERT_TRUE(cert1->VerifyNameMatch(origin1_.host(), &unused));
+ ASSERT_FALSE(cert1->VerifyNameMatch(origin2_.host(), &unused));
+ ASSERT_FALSE(cert1->VerifyNameMatch(kDifferentHostname, &unused));
+
+ ProofVerifyDetailsChromium verify_details1;
+ verify_details1.cert_verify_result.verified_cert = cert1;
+ verify_details1.cert_verify_result.is_issued_by_known_root = true;
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details1);
+
+ scoped_refptr<X509Certificate> cert2(
+ ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"));
+ ASSERT_TRUE(cert2->VerifyNameMatch(origin2_.host(), &unused));
+ ASSERT_FALSE(cert2->VerifyNameMatch(kDifferentHostname, &unused));
+
+ ProofVerifyDetailsChromium verify_details2;
+ verify_details2.cert_verify_result.verified_cert = cert2;
+ verify_details2.cert_verify_result.is_issued_by_known_root = true;
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2);
+
+ AddHangingSocketData();
+ AddHangingSocketData();
+
+ QuicStreamRequest request1(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request1.Request(destination, privacy_mode_,
+ /*cert_verify_flags=*/0, url1, "GET", net_log_,
+ callback_.callback()));
+ EXPECT_THAT(callback_.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream1 = request1.CreateStream();
+ EXPECT_TRUE(stream1.get());
+ EXPECT_TRUE(HasActiveSession(origin1_));
+
+ TestCompletionCallback callback2;
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(destination, privacy_mode_,
+ /*cert_verify_flags=*/0, url2, "GET", net_log_,
+ callback2.callback()));
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
+ std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
+ EXPECT_TRUE(stream2.get());
+
+ // |request2| does not pool to the first session, because the certificate does
+ // not match. Instead, another session is opened to the same destination, but
+ // with a different QuicServerId.
+ QuicChromiumClientSession* session1 =
+ QuicHttpStreamPeer::GetSession(stream1.get());
+ QuicChromiumClientSession* session2 =
+ QuicHttpStreamPeer::GetSession(stream2.get());
+ EXPECT_NE(session1, session2);
+
+ EXPECT_EQ(QuicServerId(origin1_, privacy_mode_), session1->server_id());
+ EXPECT_EQ(QuicServerId(origin2_, privacy_mode_), session2->server_id());
+
+ EXPECT_TRUE(AllDataConsumed());
+}
+
+// This test verifies that QuicStreamFactory::ClearCachedStatesInCryptoConfig
+// correctly transform an origin filter to a ServerIdFilter. Whether the
+// deletion itself works correctly is tested in QuicCryptoClientConfigTest.
+TEST_P(QuicStreamFactoryTest, ClearCachedStatesInCryptoConfig) {
+ Initialize();
+ QuicCryptoClientConfig* crypto_config =
+ QuicStreamFactoryPeer::GetCryptoConfig(factory_.get());
+
+ struct TestCase {
+ TestCase(const std::string& host,
+ int port,
+ PrivacyMode privacy_mode,
+ QuicCryptoClientConfig* crypto_config)
+ : server_id(host, port, privacy_mode),
+ state(crypto_config->LookupOrCreate(server_id)) {
+ vector<string> certs(1);
+ certs[0] = "cert";
+ state->SetProof(certs, "cert_sct", "chlo_hash", "signature");
+ state->set_source_address_token("TOKEN");
+ state->SetProofValid();
+
+ EXPECT_FALSE(state->certs().empty());
+ }
+
+ QuicServerId server_id;
+ QuicCryptoClientConfig::CachedState* state;
+ } test_cases[] = {
+ TestCase("www.google.com", 443, privacy_mode_, crypto_config),
+ TestCase("www.example.com", 443, privacy_mode_, crypto_config),
+ TestCase("www.example.com", 4433, privacy_mode_, crypto_config)};
+
+ // Clear cached states for the origin https://www.example.com:4433.
+ GURL origin("https://www.example.com:4433");
+ factory_->ClearCachedStatesInCryptoConfig(
+ base::Bind(&GURL::operator==, base::Unretained(&origin)));
+ EXPECT_FALSE(test_cases[0].state->certs().empty());
+ EXPECT_FALSE(test_cases[1].state->certs().empty());
+ EXPECT_TRUE(test_cases[2].state->certs().empty());
+
+ // Clear all cached states.
+ factory_->ClearCachedStatesInCryptoConfig(
+ base::Callback<bool(const GURL&)>());
+ EXPECT_TRUE(test_cases[0].state->certs().empty());
+ EXPECT_TRUE(test_cases[1].state->certs().empty());
+ EXPECT_TRUE(test_cases[2].state->certs().empty());
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/quic_utils_chromium.h b/chromium/net/quic/chromium/quic_utils_chromium.h
index daa34dd2a1e..daa34dd2a1e 100644
--- a/chromium/net/quic/quic_utils_chromium.h
+++ b/chromium/net/quic/chromium/quic_utils_chromium.h
diff --git a/chromium/net/quic/chromium/quic_utils_chromium_test.cc b/chromium/net/quic/chromium/quic_utils_chromium_test.cc
new file mode 100644
index 00000000000..b0cdfefb0f4
--- /dev/null
+++ b/chromium/net/quic/chromium/quic_utils_chromium_test.cc
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/chromium/quic_utils_chromium.h"
+
+#include <map>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::map;
+
+namespace net {
+namespace test {
+namespace {
+
+TEST(QuicUtilsChromiumTest, FindOrNullTest) {
+ map<int, int> m;
+ m[0] = 2;
+
+ // Check FindOrNull
+ int* p1 = FindOrNull(m, 0);
+ CHECK_EQ(*p1, 2);
+ ++(*p1);
+ const map<int, int>& const_m = m;
+ const int* p2 = FindOrNull(const_m, 0);
+ CHECK_EQ(*p2, 3);
+ CHECK(FindOrNull(m, 1) == nullptr);
+}
+
+TEST(QuicUtilsChromiumTest, FindOrDieTest) {
+ std::map<int, int> m;
+ m[10] = 15;
+ EXPECT_EQ(15, FindOrDie(m, 10));
+ // TODO(rtenneti): Use the latest DEATH macros after merging with latest rch's
+ // changes.
+ // ASSERT_DEATH(FindOrDie(m, 8), "Map key not found: 8");
+
+ // Make sure the non-const reference returning version works.
+ FindOrDie(m, 10) = 20;
+ EXPECT_EQ(20, FindOrDie(m, 10));
+
+ // Make sure we can lookup values in a const map.
+ const map<int, int>& const_m = m;
+ EXPECT_EQ(20, FindOrDie(const_m, 10));
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/congestion_control/cubic.cc b/chromium/net/quic/congestion_control/cubic.cc
deleted file mode 100644
index 9a924b5b3ca..00000000000
--- a/chromium/net/quic/congestion_control/cubic.cc
+++ /dev/null
@@ -1,197 +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/congestion_control/cubic.h"
-
-#include <stdint.h>
-#include <algorithm>
-#include <cmath>
-
-#include "base/logging.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-using std::max;
-
-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()) {
- Reset();
-}
-
-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_;
-}
-
-void Cubic::Reset() {
- 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;
- estimated_tcp_congestion_window_ = 0;
- origin_point_congestion_window_ = 0;
- time_to_origin_point_ = 0;
- last_target_congestion_window_ = 0;
-}
-
-void Cubic::OnApplicationLimited() {
- if (FLAGS_shift_quic_cubic_epoch_when_app_limited) {
- // When sender is not using the available congestion window, Cubic's epoch
- // should not continue growing. Record the time when sender goes into an
- // app-limited period here, to compensate later when cwnd growth happens.
- if (app_limited_start_time_ == QuicTime::Zero()) {
- app_limited_start_time_ = clock_->ApproximateNow();
- }
- } else {
- // 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();
- }
-}
-
-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>(kBetaLastMax * 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) {
- acked_packets_count_ += 1; // Packets acked.
- QuicTime current_time = clock_->ApproximateNow();
-
- // Cubic is "independent" of RTT, the update is limited by the time elapsed.
- if (last_congestion_window_ == current_congestion_window &&
- (current_time.Subtract(last_update_time_) <= MaxCubicTimeInterval())) {
- return max(last_target_congestion_window_,
- estimated_tcp_congestion_window_);
- }
- last_congestion_window_ = current_congestion_window;
- last_update_time_ = current_time;
-
- if (!epoch_.IsInitialized()) {
- // First ACK after a loss event.
- epoch_ = current_time; // Start of epoch.
- acked_packets_count_ = 1; // Reset count.
- // 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_;
- }
- } else {
- // If sender was app-limited, then freeze congestion window growth during
- // app-limited period. Continue growth now by shifting the epoch-start
- // through the app-limited period.
- if (FLAGS_shift_quic_cubic_epoch_when_app_limited &&
- app_limited_start_time_ != QuicTime::Zero()) {
- QuicTime::Delta shift = current_time.Subtract(app_limited_start_time_);
- DVLOG(1) << "Shifting epoch for quiescence by " << shift.ToMicroseconds();
- epoch_ = epoch_.Add(shift);
- app_limited_start_time_ = QuicTime::Zero();
- }
- }
-
- // 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.
- int64_t elapsed_time =
- (current_time.Add(delay_min).Subtract(epoch_).ToMicroseconds() << 10) /
- kNumMicrosPerSecond;
-
- int64_t offset = time_to_origin_point_ - elapsed_time;
- QuicPacketCount delta_congestion_window =
- (kCubeCongestionWindowScale * offset * offset * offset) >> kCubeScale;
-
- QuicPacketCount target_congestion_window =
- origin_point_congestion_window_ - delta_congestion_window;
-
- 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_++;
- }
-
- // 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_;
- }
-
- DVLOG(1) << "Final target congestion_window: " << target_congestion_window;
- return target_congestion_window;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/cubic.h b/chromium/net/quic/congestion_control/cubic.h
deleted file mode 100644
index 493cc58d6bf..00000000000
--- a/chromium/net/quic/congestion_control/cubic.h
+++ /dev/null
@@ -1,100 +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_CONGESTION_CONTROL_CUBIC_H_
-#define NET_QUIC_CONGESTION_CONTROL_CUBIC_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_connection_stats.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class NET_EXPORT_PRIVATE Cubic {
- public:
- explicit Cubic(const QuicClock* clock);
-
- void SetNumConnections(int num_connections);
-
- // Call after a timeout to reset the cubic state.
- void Reset();
-
- // 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);
-
- // Call on ack arrival when sender is unable to use the available congestion
- // window. Resets Cubic state during quiescence.
- void OnApplicationLimited();
-
- private:
- static const QuicTime::Delta MaxCubicTimeInterval() {
- return QuicTime::Delta::FromMilliseconds(30);
- }
-
- // Compute the TCP Cubic alpha and beta based on the current number of
- // connections.
- float Alpha() const;
- float Beta() const;
-
- 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 since the cycle started (epoch).
- QuicPacketCount acked_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_;
-
- DISALLOW_COPY_AND_ASSIGN(Cubic);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_CUBIC_H_
diff --git a/chromium/net/quic/congestion_control/cubic_bytes.cc b/chromium/net/quic/congestion_control/cubic_bytes.cc
deleted file mode 100644
index e09cc76eac7..00000000000
--- a/chromium/net/quic/congestion_control/cubic_bytes.cc
+++ /dev/null
@@ -1,175 +0,0 @@
-// 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.
-
-#include "net/quic/congestion_control/cubic_bytes.h"
-
-#include <stdint.h>
-#include <algorithm>
-#include <cmath>
-
-#include "base/logging.h"
-#include "net/quic/quic_protocol.h"
-
-using std::max;
-
-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;
-// The cube factor for packets in bytes.
-const uint64_t kCubeFactor =
- (UINT64_C(1) << kCubeScale) / kCubeCongestionWindowScale / kDefaultTCPMSS;
-
-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
-
-CubicBytes::CubicBytes(const QuicClock* clock)
- : clock_(clock),
- num_connections_(kDefaultNumConnections),
- epoch_(QuicTime::Zero()),
- last_update_time_(QuicTime::Zero()) {
- Reset();
-}
-
-void CubicBytes::SetNumConnections(int num_connections) {
- num_connections_ = num_connections;
-}
-
-float CubicBytes::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 CubicBytes::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_;
-}
-
-void CubicBytes::Reset() {
- 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;
- origin_point_congestion_window_ = 0;
- time_to_origin_point_ = 0;
- last_target_congestion_window_ = 0;
-}
-
-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
- // using the entire window during the time since the beginning of the current
- // "epoch" (the end of the last loss recovery period). Since
- // application-limited periods break this assumption, we reset the epoch when
- // in such a period. This reset effectively freezes congestion window growth
- // through application-limited periods and allows Cubic growth to continue
- // when the entire window is being used.
- epoch_ = QuicTime::Zero();
-}
-
-QuicByteCount CubicBytes::CongestionWindowAfterPacketLoss(
- QuicByteCount 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>(kBetaLastMax * current_congestion_window);
- } else {
- last_max_congestion_window_ = current_congestion_window;
- }
- epoch_ = QuicTime::Zero(); // Reset time.
- return static_cast<int>(current_congestion_window * Beta());
-}
-
-QuicByteCount CubicBytes::CongestionWindowAfterAck(
- QuicByteCount acked_bytes,
- QuicByteCount current_congestion_window,
- QuicTime::Delta delay_min) {
- acked_bytes_count_ += acked_bytes;
- QuicTime current_time = clock_->ApproximateNow();
-
- // Cubic is "independent" of RTT, the update is limited by the time elapsed.
- if (last_congestion_window_ == current_congestion_window &&
- (current_time.Subtract(last_update_time_) <= MaxCubicTimeInterval())) {
- return max(last_target_congestion_window_,
- estimated_tcp_congestion_window_);
- }
- last_congestion_window_ = current_congestion_window;
- last_update_time_ = current_time;
-
- if (!epoch_.IsInitialized()) {
- // First ACK after a loss event.
- DVLOG(1) << "Start of epoch";
- epoch_ = current_time; // Start of epoch.
- acked_bytes_count_ = acked_bytes; // Reset count.
- // 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.
- int64_t elapsed_time =
- (current_time.Add(delay_min).Subtract(epoch_).ToMicroseconds() << 10) /
- kNumMicrosPerSecond;
-
- int64_t offset = time_to_origin_point_ - elapsed_time;
- QuicByteCount delta_congestion_window =
- ((kCubeCongestionWindowScale * offset * offset * offset) >> kCubeScale) *
- kDefaultTCPMSS;
-
- QuicByteCount target_congestion_window =
- origin_point_congestion_window_ - delta_congestion_window;
-
- DCHECK_LT(0u, estimated_tcp_congestion_window_);
- // Increase the window by Alpha * 1 MSS of bytes every time we ack an
- // estimated tcp window of bytes.
- estimated_tcp_congestion_window_ += acked_bytes_count_ *
- (Alpha() * kDefaultTCPMSS) /
- estimated_tcp_congestion_window_;
- acked_bytes_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_;
- }
-
- DVLOG(1) << "Final target congestion_window: " << target_congestion_window;
- return target_congestion_window;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/cubic_bytes.h b/chromium/net/quic/congestion_control/cubic_bytes.h
deleted file mode 100644
index b1b4344fd84..00000000000
--- a/chromium/net/quic/congestion_control/cubic_bytes.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// 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.
-
-// 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_CONGESTION_CONTROL_CUBIC_BYTES_H_
-#define NET_QUIC_CONGESTION_CONTROL_CUBIC_BYTES_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_connection_stats.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class NET_EXPORT_PRIVATE CubicBytes {
- public:
- explicit CubicBytes(const QuicClock* clock);
-
- void SetNumConnections(int num_connections);
-
- // Call after a timeout to reset the cubic state.
- void Reset();
-
- // 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.
- QuicByteCount CongestionWindowAfterPacketLoss(QuicPacketCount current);
-
- // Compute a new congestion window to use after a received ACK.
- // Returns the new congestion window in bytes. The new congestion window
- // follows a cubic function that depends on the time passed since last packet
- // loss.
- QuicByteCount CongestionWindowAfterAck(QuicByteCount acked_bytes,
- QuicByteCount current,
- QuicTime::Delta delay_min);
-
- // Call on ack arrival when sender is unable to use the available congestion
- // window. Resets Cubic state during quiescence.
- void OnApplicationLimited();
-
- private:
- static const QuicTime::Delta MaxCubicTimeInterval() {
- return QuicTime::Delta::FromMilliseconds(30);
- }
-
- // Compute the TCP Cubic alpha and beta based on the current number of
- // connections.
- float Alpha() const;
- float Beta() const;
-
- const QuicClock* clock_;
-
- // Number of connections to simulate.
- int num_connections_;
-
- // 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.
- QuicByteCount last_max_congestion_window_;
-
- // Number of acked bytes since the cycle started (epoch).
- QuicByteCount acked_bytes_count_;
-
- // TCP Reno equivalent congestion window in packets.
- QuicByteCount estimated_tcp_congestion_window_;
-
- // Origin point of cubic function.
- QuicByteCount 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.
- QuicByteCount last_target_congestion_window_;
-
- DISALLOW_COPY_AND_ASSIGN(CubicBytes);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_CUBIC_BYTES_H_
diff --git a/chromium/net/quic/congestion_control/cubic_bytes_test.cc b/chromium/net/quic/congestion_control/cubic_bytes_test.cc
deleted file mode 100644
index 02504b3f98e..00000000000
--- a/chromium/net/quic/congestion_control/cubic_bytes_test.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-// 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.
-
-#include "net/quic/congestion_control/cubic_bytes.h"
-
-#include "base/logging.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-const float kBeta = 0.7f; // Default Cubic backoff factor.
-const uint32_t kNumConnections = 2;
-const float kNConnectionBeta = (kNumConnections - 1 + kBeta) / kNumConnections;
-const float kNConnectionAlpha = 3 * kNumConnections * kNumConnections *
- (1 - kNConnectionBeta) / (1 + kNConnectionBeta);
-
-class CubicBytesTest : public ::testing::Test {
- protected:
- CubicBytesTest()
- : one_ms_(QuicTime::Delta::FromMilliseconds(1)),
- hundred_ms_(QuicTime::Delta::FromMilliseconds(100)),
- cubic_(&clock_) {}
- const QuicTime::Delta one_ms_;
- const QuicTime::Delta hundred_ms_;
- MockClock clock_;
- CubicBytes cubic_;
-};
-
-TEST_F(CubicBytesTest, AboveOrigin) {
- // Convex growth.
- const QuicTime::Delta rtt_min = hundred_ms_;
- QuicByteCount current_cwnd = 10 * kDefaultTCPMSS;
- QuicByteCount expected_cwnd = current_cwnd + kDefaultTCPMSS;
- // Initialize the state.
- clock_.AdvanceTime(one_ms_);
- EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck(
- kDefaultTCPMSS, current_cwnd, rtt_min));
- current_cwnd = expected_cwnd;
- // Normal TCP phase.
- for (int i = 0; i < 48; ++i) {
- for (QuicPacketCount n = 1;
- n < current_cwnd / kDefaultTCPMSS / kNConnectionAlpha; ++n) {
- // Call once per ACK.
- EXPECT_NEAR(current_cwnd, cubic_.CongestionWindowAfterAck(
- kDefaultTCPMSS, current_cwnd, rtt_min),
- kDefaultTCPMSS);
- }
- clock_.AdvanceTime(hundred_ms_);
- current_cwnd =
- cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, rtt_min);
- EXPECT_NEAR(expected_cwnd, current_cwnd, kDefaultTCPMSS);
- expected_cwnd += kDefaultTCPMSS;
- }
- // Cubic phase.
- for (int i = 0; i < 52; ++i) {
- for (QuicPacketCount n = 1; n < current_cwnd / kDefaultTCPMSS; ++n) {
- // Call once per ACK.
- EXPECT_NEAR(current_cwnd, cubic_.CongestionWindowAfterAck(
- kDefaultTCPMSS, current_cwnd, rtt_min),
- kDefaultTCPMSS);
- }
- clock_.AdvanceTime(hundred_ms_);
- current_cwnd =
- cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, rtt_min);
- }
- // Total time elapsed so far; add min_rtt (0.1s) here as well.
- float elapsed_time_s = 10.0f + 0.1f;
- // |expected_cwnd| is initial value of cwnd + K * t^3, where K = 0.4.
- expected_cwnd =
- 11 + (elapsed_time_s * elapsed_time_s * elapsed_time_s * 410) / 1024;
- EXPECT_EQ(expected_cwnd, current_cwnd / kDefaultTCPMSS);
-}
-
-TEST_F(CubicBytesTest, LossEvents) {
- const QuicTime::Delta rtt_min = hundred_ms_;
- QuicByteCount current_cwnd = 422 * kDefaultTCPMSS;
- QuicPacketCount expected_cwnd = current_cwnd + kDefaultTCPMSS;
- // Initialize the state.
- clock_.AdvanceTime(one_ms_);
- EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck(
- kDefaultTCPMSS, current_cwnd, rtt_min));
- expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta);
- EXPECT_EQ(expected_cwnd,
- cubic_.CongestionWindowAfterPacketLoss(current_cwnd));
- expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta);
- EXPECT_EQ(expected_cwnd,
- cubic_.CongestionWindowAfterPacketLoss(current_cwnd));
-}
-
-TEST_F(CubicBytesTest, BelowOrigin) {
- // Concave growth.
- const QuicTime::Delta rtt_min = hundred_ms_;
- QuicByteCount current_cwnd = 422 * kDefaultTCPMSS;
- QuicPacketCount expected_cwnd = current_cwnd + kDefaultTCPMSS;
- // Initialize the state.
- clock_.AdvanceTime(one_ms_);
- EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck(
- kDefaultTCPMSS, current_cwnd, rtt_min));
- 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(kDefaultTCPMSS, current_cwnd, rtt_min);
- // Cubic phase.
- for (int i = 0; i < 40; ++i) {
- clock_.AdvanceTime(hundred_ms_);
- current_cwnd =
- cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, rtt_min);
- }
- expected_cwnd = 422 * kDefaultTCPMSS;
- EXPECT_EQ(expected_cwnd, current_cwnd);
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/cubic_test.cc b/chromium/net/quic/congestion_control/cubic_test.cc
deleted file mode 100644
index 2e2c231f814..00000000000
--- a/chromium/net/quic/congestion_control/cubic_test.cc
+++ /dev/null
@@ -1,113 +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/congestion_control/cubic.h"
-
-#include "base/logging.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-const float kBeta = 0.7f; // Default Cubic backoff factor.
-const uint32_t kNumConnections = 2;
-const float kNConnectionBeta = (kNumConnections - 1 + kBeta) / kNumConnections;
-const float kNConnectionAlpha = 3 * kNumConnections * kNumConnections *
- (1 - kNConnectionBeta) / (1 + kNConnectionBeta);
-
-class CubicTest : public ::testing::Test {
- protected:
- CubicTest()
- : one_ms_(QuicTime::Delta::FromMilliseconds(1)),
- hundred_ms_(QuicTime::Delta::FromMilliseconds(100)),
- cubic_(&clock_) {}
- const QuicTime::Delta one_ms_;
- const QuicTime::Delta hundred_ms_;
- MockClock clock_;
- Cubic cubic_;
-};
-
-TEST_F(CubicTest, AboveOrigin) {
- // Convex growth.
- const QuicTime::Delta rtt_min = hundred_ms_;
- QuicPacketCount current_cwnd = 10;
- QuicPacketCount expected_cwnd = current_cwnd + 1;
- // Initialize the state.
- clock_.AdvanceTime(one_ms_);
- EXPECT_EQ(expected_cwnd,
- cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min));
- current_cwnd = expected_cwnd;
- // Normal TCP phase.
- for (int i = 0; i < 48; ++i) {
- for (QuicPacketCount n = 1; n < current_cwnd / kNConnectionAlpha; ++n) {
- // Call once per ACK.
- EXPECT_NEAR(current_cwnd,
- cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min), 1);
- }
- clock_.AdvanceTime(hundred_ms_);
- current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min);
- EXPECT_NEAR(expected_cwnd, current_cwnd, 1);
- expected_cwnd++;
- }
- // Cubic phase.
- for (int i = 0; i < 52; ++i) {
- for (QuicPacketCount n = 1; n < current_cwnd; ++n) {
- // Call once per ACK.
- EXPECT_EQ(current_cwnd,
- cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min));
- }
- clock_.AdvanceTime(hundred_ms_);
- current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min);
- }
- // Total time elapsed so far; add min_rtt (0.1s) here as well.
- float elapsed_time_s = 10.0f + 0.1f;
- // |expected_cwnd| is initial value of cwnd + K * t^3, where K = 0.4.
- expected_cwnd =
- 11 + (elapsed_time_s * elapsed_time_s * elapsed_time_s * 410) / 1024;
- EXPECT_EQ(expected_cwnd, current_cwnd);
-}
-
-TEST_F(CubicTest, LossEvents) {
- const QuicTime::Delta rtt_min = hundred_ms_;
- QuicPacketCount current_cwnd = 422;
- QuicPacketCount expected_cwnd = current_cwnd + 1;
- // Initialize the state.
- clock_.AdvanceTime(one_ms_);
- EXPECT_EQ(expected_cwnd,
- cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min));
- expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta);
- EXPECT_EQ(expected_cwnd,
- cubic_.CongestionWindowAfterPacketLoss(current_cwnd));
- expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta);
- EXPECT_EQ(expected_cwnd,
- cubic_.CongestionWindowAfterPacketLoss(current_cwnd));
-}
-
-TEST_F(CubicTest, BelowOrigin) {
- // Concave growth.
- const QuicTime::Delta rtt_min = hundred_ms_;
- QuicPacketCount current_cwnd = 422;
- QuicPacketCount expected_cwnd = current_cwnd + 1;
- // Initialize the state.
- clock_.AdvanceTime(one_ms_);
- EXPECT_EQ(expected_cwnd,
- cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min));
- 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);
- // Cubic phase.
- for (int i = 0; i < 40; ++i) {
- clock_.AdvanceTime(hundred_ms_);
- current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min);
- }
- expected_cwnd = 422;
- EXPECT_EQ(expected_cwnd, current_cwnd);
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/general_loss_algorithm.cc b/chromium/net/quic/congestion_control/general_loss_algorithm.cc
deleted file mode 100644
index e99a1f57274..00000000000
--- a/chromium/net/quic/congestion_control/general_loss_algorithm.cc
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 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.
-
-#include "net/quic/congestion_control/general_loss_algorithm.h"
-
-#include "net/quic/congestion_control/rtt_stats.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-namespace {
-
-// The minimum delay before a packet will be considered lost,
-// regardless of SRTT. Half of the minimum TLP, since the loss algorithm only
-// triggers when a nack has been receieved for the packet.
-static const size_t kMinLossDelayMs = 5;
-
-// Default fraction of an RTT the algorithm waits before determining a packet is
-// lost due to early retransmission by time based loss detection.
-static const int kDefaultLossDelayShift = 2;
-// Default fraction of an RTT when doing adaptive loss detection.
-static const int kDefaultAdaptiveLossDelayShift = 4;
-
-} // namespace
-
-GeneralLossAlgorithm::GeneralLossAlgorithm()
- : loss_type_(kNack),
- loss_detection_timeout_(QuicTime::Zero()),
- largest_sent_on_spurious_retransmit_(0),
- reordering_shift_(kDefaultLossDelayShift) {}
-
-GeneralLossAlgorithm::GeneralLossAlgorithm(LossDetectionType loss_type)
- : loss_type_(loss_type),
- loss_detection_timeout_(QuicTime::Zero()),
- largest_sent_on_spurious_retransmit_(0),
- reordering_shift_(loss_type == kAdaptiveTime
- ? kDefaultAdaptiveLossDelayShift
- : kDefaultLossDelayShift) {}
-
-LossDetectionType GeneralLossAlgorithm::GetLossDetectionType() const {
- return loss_type_;
-}
-
-void GeneralLossAlgorithm::SetLossDetectionType(LossDetectionType loss_type) {
- loss_type_ = loss_type;
- if (loss_type_ == kAdaptiveTime) {
- reordering_shift_ = kDefaultAdaptiveLossDelayShift;
- }
-}
-
-// Uses nack counts to decide when packets are lost.
-void GeneralLossAlgorithm::DetectLosses(
- const QuicUnackedPacketMap& unacked_packets,
- QuicTime time,
- const RttStats& rtt_stats,
- QuicPacketNumber largest_newly_acked,
- SendAlgorithmInterface::CongestionVector* packets_lost) {
- QuicPacketNumber largest_observed = unacked_packets.largest_observed();
- if (FLAGS_quic_loss_recovery_use_largest_acked) {
- largest_observed = largest_newly_acked;
- }
- loss_detection_timeout_ = QuicTime::Zero();
- QuicTime::Delta max_rtt =
- QuicTime::Delta::Max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt());
- QuicTime::Delta loss_delay =
- QuicTime::Delta::Max(QuicTime::Delta::FromMilliseconds(kMinLossDelayMs),
- max_rtt.Add(max_rtt >> reordering_shift_));
- QuicPacketNumber packet_number = unacked_packets.GetLeastUnacked();
- for (QuicUnackedPacketMap::const_iterator it = unacked_packets.begin();
- it != unacked_packets.end() && packet_number <= largest_observed;
- ++it, ++packet_number) {
- if (!it->in_flight) {
- continue;
- }
-
- if (loss_type_ == kNack) {
- // FACK based loss detection.
- if (largest_observed - packet_number >=
- kNumberOfNacksBeforeRetransmission) {
- packets_lost->push_back(std::make_pair(packet_number, it->bytes_sent));
- continue;
- }
- }
-
- // Only early retransmit(RFC5827) when the last packet gets acked and
- // there are retransmittable packets in flight.
- // This also implements a timer-protected variant of FACK.
- if ((!it->retransmittable_frames.empty() &&
- unacked_packets.largest_sent_packet() == largest_observed) ||
- (loss_type_ == kTime || loss_type_ == kAdaptiveTime)) {
- QuicTime when_lost = it->sent_time.Add(loss_delay);
- if (time < when_lost) {
- loss_detection_timeout_ = when_lost;
- break;
- }
- packets_lost->push_back(std::make_pair(packet_number, it->bytes_sent));
- continue;
- }
-
- // NACK-based loss detection allows for a max reordering window of 1 RTT.
- if (it->sent_time.Add(rtt_stats.smoothed_rtt()) <
- unacked_packets.GetTransmissionInfo(largest_observed).sent_time) {
- packets_lost->push_back(std::make_pair(packet_number, it->bytes_sent));
- continue;
- }
- }
-}
-
-QuicTime GeneralLossAlgorithm::GetLossTimeout() const {
- return loss_detection_timeout_;
-}
-
-void GeneralLossAlgorithm::SpuriousRetransmitDetected(
- const QuicUnackedPacketMap& unacked_packets,
- QuicTime time,
- const RttStats& rtt_stats,
- QuicPacketNumber spurious_retransmission) {
- if (loss_type_ != kAdaptiveTime || reordering_shift_ == 0) {
- return;
- }
- if (spurious_retransmission <= largest_sent_on_spurious_retransmit_) {
- return;
- }
- largest_sent_on_spurious_retransmit_ = unacked_packets.largest_sent_packet();
- // Calculate the extra time needed so this wouldn't have been declared lost.
- // Extra time needed is based on how long it's been since the spurious
- // retransmission was sent, because the SRTT and latest RTT may have changed.
- QuicTime::Delta extra_time_needed = time.Subtract(
- unacked_packets.GetTransmissionInfo(spurious_retransmission).sent_time);
- // Increase the reordering fraction until enough time would be allowed.
- QuicTime::Delta max_rtt =
- QuicTime::Delta::Max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt());
- QuicTime::Delta proposed_extra_time(QuicTime::Delta::Zero());
- do {
- proposed_extra_time = max_rtt >> reordering_shift_;
- --reordering_shift_;
- } while (proposed_extra_time < extra_time_needed && reordering_shift_ > 0);
-}
-
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/general_loss_algorithm.h b/chromium/net/quic/congestion_control/general_loss_algorithm.h
deleted file mode 100644
index 625e7745e44..00000000000
--- a/chromium/net/quic/congestion_control/general_loss_algorithm.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 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.
-
-#ifndef NET_QUIC_CONGESTION_CONTROL_GENERAL_LOSS_ALGORITHM_H_
-#define NET_QUIC_CONGESTION_CONTROL_GENERAL_LOSS_ALGORITHM_H_
-
-#include <algorithm>
-#include <map>
-
-#include "base/macros.h"
-#include "net/quic/congestion_control/loss_detection_interface.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-#include "net/quic/quic_unacked_packet_map.h"
-
-namespace net {
-
-// Class which can be configured to implement's TCP's approach of detecting loss
-// when 3 nacks have been received for a packet or with a time threshold.
-// Also implements TCP's early retransmit(RFC5827).
-class NET_EXPORT_PRIVATE GeneralLossAlgorithm : public LossDetectionInterface {
- public:
- // TCP retransmits after 3 nacks.
- static const QuicPacketCount kNumberOfNacksBeforeRetransmission = 3;
-
- GeneralLossAlgorithm();
- explicit GeneralLossAlgorithm(LossDetectionType loss_type);
- ~GeneralLossAlgorithm() override {}
-
- LossDetectionType GetLossDetectionType() const override;
- void SetLossDetectionType(LossDetectionType loss_type);
-
- // Uses |largest_acked| and time to decide when packets are lost.
- void DetectLosses(
- const QuicUnackedPacketMap& unacked_packets,
- QuicTime time,
- const RttStats& rtt_stats,
- QuicPacketNumber largest_newly_acked,
- SendAlgorithmInterface::CongestionVector* packets_lost) override;
-
- // Returns a non-zero value when the early retransmit timer is active.
- QuicTime GetLossTimeout() const override;
-
- // Increases the loss detection threshold for time loss detection.
- void SpuriousRetransmitDetected(
- const QuicUnackedPacketMap& unacked_packets,
- QuicTime time,
- const RttStats& rtt_stats,
- QuicPacketNumber spurious_retransmission) override;
-
- int reordering_shift() const { return reordering_shift_; }
-
- private:
- LossDetectionType loss_type_;
- QuicTime loss_detection_timeout_;
- // Largest sent packet when a spurious retransmit is detected.
- // Prevents increasing the reordering threshold multiple times per epoch.
- QuicPacketNumber largest_sent_on_spurious_retransmit_;
- // Fraction of a max(SRTT, latest_rtt) to permit reordering before declaring
- // loss. Fraction calculated by shifting max(SRTT, latest_rtt) to the right
- // by reordering_shift.
- int reordering_shift_;
-
- DISALLOW_COPY_AND_ASSIGN(GeneralLossAlgorithm);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_GENERAL_LOSS_ALGORITHM_H_
diff --git a/chromium/net/quic/congestion_control/general_loss_algorithm_test.cc b/chromium/net/quic/congestion_control/general_loss_algorithm_test.cc
deleted file mode 100644
index b0e15192756..00000000000
--- a/chromium/net/quic/congestion_control/general_loss_algorithm_test.cc
+++ /dev/null
@@ -1,359 +0,0 @@
-// Copyright 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.
-
-#include "net/quic/congestion_control/general_loss_algorithm.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "net/quic/congestion_control/rtt_stats.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_unacked_packet_map.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::vector;
-
-namespace net {
-namespace test {
-namespace {
-
-// Default packet length.
-const uint32_t kDefaultLength = 1000;
-
-class GeneralLossAlgorithmTest : public ::testing::Test {
- protected:
- GeneralLossAlgorithmTest() {
- rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
- QuicTime::Delta::Zero(), clock_.Now());
- EXPECT_LT(0, rtt_stats_.smoothed_rtt().ToMicroseconds());
- }
-
- ~GeneralLossAlgorithmTest() override {}
-
- void SendDataPacket(QuicPacketNumber packet_number) {
- QuicStreamFrame* frame = new QuicStreamFrame();
- frame->stream_id = kHeadersStreamId;
- SerializedPacket packet(kDefaultPathId, packet_number,
- PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
- 0, false, false);
- packet.retransmittable_frames.push_back(QuicFrame(frame));
- unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(),
- true);
- }
-
- void VerifyLosses(QuicPacketNumber largest_newly_acked,
- QuicPacketNumber* losses_expected,
- size_t num_losses) {
- if (largest_newly_acked > unacked_packets_.largest_observed()) {
- unacked_packets_.IncreaseLargestObserved(largest_newly_acked);
- }
- SendAlgorithmInterface::CongestionVector lost_packets;
- loss_algorithm_.DetectLosses(unacked_packets_, clock_.Now(), rtt_stats_,
- largest_newly_acked, &lost_packets);
- EXPECT_EQ(num_losses, lost_packets.size());
- for (size_t i = 0; i < num_losses; ++i) {
- EXPECT_EQ(lost_packets[i].first, losses_expected[i]);
- }
- }
-
- QuicUnackedPacketMap unacked_packets_;
- GeneralLossAlgorithm loss_algorithm_;
- RttStats rtt_stats_;
- MockClock clock_;
-};
-
-TEST_F(GeneralLossAlgorithmTest, NackRetransmit1Packet) {
- const size_t kNumSentPackets = 5;
- // Transmit 5 packets.
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
- // No loss on one ack.
- unacked_packets_.RemoveFromInFlight(2);
- VerifyLosses(2, nullptr, 0);
- // No loss on two acks.
- unacked_packets_.RemoveFromInFlight(3);
- VerifyLosses(3, nullptr, 0);
- // Loss on three acks.
- unacked_packets_.RemoveFromInFlight(4);
- QuicPacketNumber lost[] = {1};
- VerifyLosses(4, lost, arraysize(lost));
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
-}
-
-// A stretch ack is an ack that covers more than 1 packet of previously
-// unacknowledged data.
-TEST_F(GeneralLossAlgorithmTest, NackRetransmit1PacketWith1StretchAck) {
- const size_t kNumSentPackets = 10;
- // Transmit 10 packets.
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
-
- // Nack the first packet 3 times in a single StretchAck.
- unacked_packets_.RemoveFromInFlight(2);
- unacked_packets_.RemoveFromInFlight(3);
- unacked_packets_.RemoveFromInFlight(4);
- QuicPacketNumber lost[] = {1};
- VerifyLosses(4, lost, arraysize(lost));
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
-}
-
-// Ack a packet 3 packets ahead, causing a retransmit.
-TEST_F(GeneralLossAlgorithmTest, NackRetransmit1PacketSingleAck) {
- const size_t kNumSentPackets = 10;
- // Transmit 10 packets.
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
-
- // Nack the first packet 3 times in an AckFrame with three missing packets.
- unacked_packets_.RemoveFromInFlight(4);
- QuicPacketNumber lost[] = {1};
- VerifyLosses(4, lost, arraysize(lost));
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
-}
-
-TEST_F(GeneralLossAlgorithmTest, EarlyRetransmit1Packet) {
- const size_t kNumSentPackets = 2;
- // Transmit 2 packets.
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
- // Early retransmit when the final packet gets acked and the first is nacked.
- unacked_packets_.RemoveFromInFlight(2);
- VerifyLosses(2, nullptr, 0);
- EXPECT_EQ(clock_.Now().Add(rtt_stats_.smoothed_rtt().Multiply(1.25)),
- loss_algorithm_.GetLossTimeout());
-
- clock_.AdvanceTime(rtt_stats_.latest_rtt().Multiply(1.25));
- QuicPacketNumber lost[] = {1};
- VerifyLosses(2, lost, arraysize(lost));
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
-}
-
-TEST_F(GeneralLossAlgorithmTest, EarlyRetransmitAllPackets) {
- const size_t kNumSentPackets = 5;
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- // Advance the time 1/4 RTT between 3 and 4.
- if (i == 3) {
- clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.25));
- }
- }
-
- // Early retransmit when the final packet gets acked and 1.25 RTTs have
- // elapsed since the packets were sent.
- unacked_packets_.RemoveFromInFlight(kNumSentPackets);
- // This simulates a single ack following multiple missing packets with FACK.
- QuicPacketNumber lost[] = {1, 2};
- VerifyLosses(kNumSentPackets, lost, arraysize(lost));
- // The time has already advanced 1/4 an RTT, so ensure the timeout is set
- // 1.25 RTTs after the earliest pending packet(3), not the last(4).
- EXPECT_EQ(clock_.Now().Add(rtt_stats_.smoothed_rtt()),
- loss_algorithm_.GetLossTimeout());
-
- clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
- QuicPacketNumber lost2[] = {1, 2, 3};
- VerifyLosses(kNumSentPackets, lost2, arraysize(lost2));
- EXPECT_EQ(clock_.Now().Add(rtt_stats_.smoothed_rtt().Multiply(0.25)),
- loss_algorithm_.GetLossTimeout());
- clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.25));
- QuicPacketNumber lost3[] = {1, 2, 3, 4};
- VerifyLosses(kNumSentPackets, lost3, arraysize(lost3));
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
-}
-
-TEST_F(GeneralLossAlgorithmTest, DontEarlyRetransmitNeuteredPacket) {
- const size_t kNumSentPackets = 2;
- // Transmit 2 packets.
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
- // Neuter packet 1.
- unacked_packets_.RemoveRetransmittability(1);
-
- // Early retransmit when the final packet gets acked and the first is nacked.
- unacked_packets_.IncreaseLargestObserved(2);
- unacked_packets_.RemoveFromInFlight(2);
- VerifyLosses(2, nullptr, 0);
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
-}
-
-TEST_F(GeneralLossAlgorithmTest, AlwaysLosePacketSent1RTTEarlier) {
- // Transmit 1 packet and then wait an rtt plus 1ms.
- SendDataPacket(1);
- clock_.AdvanceTime(
- rtt_stats_.smoothed_rtt().Add(QuicTime::Delta::FromMilliseconds(1)));
-
- // Transmit 2 packets.
- SendDataPacket(2);
- SendDataPacket(3);
-
- // Wait another RTT and ack 2.
- clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
- unacked_packets_.IncreaseLargestObserved(2);
- unacked_packets_.RemoveFromInFlight(2);
- QuicPacketNumber lost[] = {1};
- VerifyLosses(2, lost, arraysize(lost));
-}
-
-// Time-based loss detection tests.
-TEST_F(GeneralLossAlgorithmTest, NoLossFor500Nacks) {
- loss_algorithm_.SetLossDetectionType(kTime);
- const size_t kNumSentPackets = 5;
- // Transmit 5 packets.
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
- unacked_packets_.RemoveFromInFlight(2);
- for (size_t i = 1; i < 500; ++i) {
- VerifyLosses(2, nullptr, 0);
- }
- EXPECT_EQ(rtt_stats_.smoothed_rtt().Multiply(1.25),
- loss_algorithm_.GetLossTimeout().Subtract(clock_.Now()));
-}
-
-TEST_F(GeneralLossAlgorithmTest, NoLossUntilTimeout) {
- loss_algorithm_.SetLossDetectionType(kTime);
- const size_t kNumSentPackets = 10;
- // Transmit 10 packets at 1/10th an RTT interval.
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.1));
- }
- // Expect the timer to not be set.
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
- // The packet should not be lost until 1.25 RTTs pass.
- unacked_packets_.RemoveFromInFlight(2);
- VerifyLosses(2, nullptr, 0);
- // Expect the timer to be set to 0.25 RTT's in the future.
- EXPECT_EQ(rtt_stats_.smoothed_rtt().Multiply(0.25),
- loss_algorithm_.GetLossTimeout().Subtract(clock_.Now()));
- VerifyLosses(2, nullptr, 0);
- clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.25));
- QuicPacketNumber lost[] = {1};
- VerifyLosses(2, lost, arraysize(lost));
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
-}
-
-TEST_F(GeneralLossAlgorithmTest, NoLossWithoutNack) {
- loss_algorithm_.SetLossDetectionType(kTime);
- const size_t kNumSentPackets = 10;
- // Transmit 10 packets at 1/10th an RTT interval.
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.1));
- }
- // Expect the timer to not be set.
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
- // The packet should not be lost without a nack.
- unacked_packets_.RemoveFromInFlight(1);
- VerifyLosses(1, nullptr, 0);
- // The timer should still not be set.
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
- clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.25));
- VerifyLosses(1, nullptr, 0);
- clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
- VerifyLosses(1, nullptr, 0);
-
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
-}
-
-TEST_F(GeneralLossAlgorithmTest, MultipleLossesAtOnce) {
- loss_algorithm_.SetLossDetectionType(kTime);
- const size_t kNumSentPackets = 10;
- // Transmit 10 packets at once and then go forward an RTT.
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
- clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
- // Expect the timer to not be set.
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
- // The packet should not be lost until 1.25 RTTs pass.
- unacked_packets_.RemoveFromInFlight(10);
- VerifyLosses(10, nullptr, 0);
- // Expect the timer to be set to 0.25 RTT's in the future.
- EXPECT_EQ(rtt_stats_.smoothed_rtt().Multiply(0.25),
- loss_algorithm_.GetLossTimeout().Subtract(clock_.Now()));
- clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.25));
- QuicPacketNumber lost[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
- VerifyLosses(10, lost, arraysize(lost));
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
-}
-
-TEST_F(GeneralLossAlgorithmTest, NoSpuriousLossesFromLargeReordering) {
- FLAGS_quic_loss_recovery_use_largest_acked = true;
- loss_algorithm_.SetLossDetectionType(kTime);
- const size_t kNumSentPackets = 10;
- // Transmit 10 packets at once and then go forward an RTT.
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
- clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
- // Expect the timer to not be set.
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
- // The packet should not be lost until 1.25 RTTs pass.
-
- unacked_packets_.RemoveFromInFlight(10);
- VerifyLosses(10, nullptr, 0);
- // Expect the timer to be set to 0.25 RTT's in the future.
- EXPECT_EQ(rtt_stats_.smoothed_rtt().Multiply(0.25),
- loss_algorithm_.GetLossTimeout().Subtract(clock_.Now()));
- clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.25));
- // Now ack packets 1 to 9 and ensure the timer is no longer set and no packets
- // are lost.
- for (QuicPacketNumber i = 1; i <= 9; ++i) {
- unacked_packets_.RemoveFromInFlight(i);
- VerifyLosses(i, nullptr, 0);
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
- }
-}
-
-TEST_F(GeneralLossAlgorithmTest, IncreaseThresholdUponSpuriousLoss) {
- loss_algorithm_.SetLossDetectionType(kAdaptiveTime);
- EXPECT_EQ(4, loss_algorithm_.reordering_shift());
- const size_t kNumSentPackets = 10;
- // Transmit 2 packets at 1/10th an RTT interval.
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.1));
- }
- EXPECT_EQ(QuicTime::Zero().Add(rtt_stats_.smoothed_rtt()), clock_.Now());
-
- // Expect the timer to not be set.
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
- // Packet 1 should not be lost until 1/16 RTTs pass.
- unacked_packets_.RemoveFromInFlight(2);
- VerifyLosses(2, nullptr, 0);
- // Expect the timer to be set to 1/16 RTT's in the future.
- EXPECT_EQ(rtt_stats_.smoothed_rtt().Multiply(1.0f / 16),
- loss_algorithm_.GetLossTimeout().Subtract(clock_.Now()));
- VerifyLosses(2, nullptr, 0);
- clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(1.0f / 16));
- QuicPacketNumber lost[] = {1};
- VerifyLosses(2, lost, arraysize(lost));
- EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
- // Retransmit packet 1 as 11 and 2 as 12.
- SendDataPacket(11);
- SendDataPacket(12);
-
- // 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().Multiply(1.0f / 4));
- loss_algorithm_.SpuriousRetransmitDetected(unacked_packets_, clock_.Now(),
- rtt_stats_, 11);
- EXPECT_EQ(1, loss_algorithm_.reordering_shift());
-
- // Detect another spurious retransmit and ensure the threshold doesn't
- // increase again.
- loss_algorithm_.SpuriousRetransmitDetected(unacked_packets_, clock_.Now(),
- rtt_stats_, 12);
- EXPECT_EQ(1, loss_algorithm_.reordering_shift());
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/hybrid_slow_start.cc b/chromium/net/quic/congestion_control/hybrid_slow_start.cc
deleted file mode 100644
index 5f334c74ed6..00000000000
--- a/chromium/net/quic/congestion_control/hybrid_slow_start.cc
+++ /dev/null
@@ -1,107 +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/congestion_control/hybrid_slow_start.h"
-
-#include <algorithm>
-
-using std::max;
-using std::min;
-
-namespace net {
-
-// Note(pwestin): the magic clamping numbers come from the original code in
-// tcp_cubic.c.
-const int64_t kHybridStartLowWindow = 16;
-// Number of delay samples for detecting the increase of delay.
-const uint32_t kHybridStartMinSamples = 8;
-// Exit slow start if the min rtt has increased by more than 1/8th.
-const int kHybridStartDelayFactorExp = 3; // 2^3 = 8
-// The original paper specifies 2 and 8ms, but those have changed over time.
-const int64_t kHybridStartDelayMinThresholdUs = 4000;
-const int64_t kHybridStartDelayMaxThresholdUs = 16000;
-
-HybridSlowStart::HybridSlowStart()
- : started_(false),
- hystart_found_(NOT_FOUND),
- last_sent_packet_number_(0),
- end_packet_number_(0),
- rtt_sample_count_(0),
- current_min_rtt_(QuicTime::Delta::Zero()) {}
-
-void HybridSlowStart::OnPacketAcked(QuicPacketNumber acked_packet_number) {
- // OnPacketAcked gets invoked after ShouldExitSlowStart, so it's best to end
- // the round when the final packet of the burst is received and start it on
- // the next incoming ack.
- if (IsEndOfRound(acked_packet_number)) {
- started_ = false;
- }
-}
-
-void HybridSlowStart::OnPacketSent(QuicPacketNumber packet_number) {
- last_sent_packet_number_ = packet_number;
-}
-
-void HybridSlowStart::Restart() {
- started_ = false;
- hystart_found_ = NOT_FOUND;
-}
-
-void HybridSlowStart::StartReceiveRound(QuicPacketNumber last_sent) {
- DVLOG(1) << "Reset hybrid slow start @" << last_sent;
- end_packet_number_ = last_sent;
- current_min_rtt_ = QuicTime::Delta::Zero();
- rtt_sample_count_ = 0;
- started_ = true;
-}
-
-bool HybridSlowStart::IsEndOfRound(QuicPacketNumber ack) const {
- return end_packet_number_ <= ack;
-}
-
-bool HybridSlowStart::ShouldExitSlowStart(QuicTime::Delta latest_rtt,
- QuicTime::Delta min_rtt,
- QuicPacketCount congestion_window) {
- if (!started_) {
- // Time to start the hybrid slow start.
- StartReceiveRound(last_sent_packet_number_);
- }
- if (hystart_found_ != NOT_FOUND) {
- return true;
- }
- // Second detection parameter - delay increase detection.
- // Compare the minimum delay (current_min_rtt_) of the current
- // burst of packets relative to the minimum delay during the session.
- // Note: we only look at the first few(8) packets in each burst, since we
- // only want to compare the lowest RTT of the burst relative to previous
- // bursts.
- rtt_sample_count_++;
- if (rtt_sample_count_ <= kHybridStartMinSamples) {
- if (current_min_rtt_.IsZero() || current_min_rtt_ > latest_rtt) {
- current_min_rtt_ = latest_rtt;
- }
- }
- // We only need to check this once per round.
- if (rtt_sample_count_ == kHybridStartMinSamples) {
- // Divide min_rtt by 8 to get a rtt increase threshold for exiting.
- int64_t min_rtt_increase_threshold_us =
- min_rtt.ToMicroseconds() >> kHybridStartDelayFactorExp;
- // Ensure the rtt threshold is never less than 2ms or more than 16ms.
- min_rtt_increase_threshold_us =
- min(min_rtt_increase_threshold_us, kHybridStartDelayMaxThresholdUs);
- QuicTime::Delta min_rtt_increase_threshold =
- QuicTime::Delta::FromMicroseconds(max(min_rtt_increase_threshold_us,
- kHybridStartDelayMinThresholdUs));
-
- if (current_min_rtt_ > min_rtt.Add(min_rtt_increase_threshold)) {
- hystart_found_ = DELAY;
- }
- }
- // Exit from slow start if the cwnd is greater than 16 and
- // increasing delay is found.
- return congestion_window >= kHybridStartLowWindow &&
- hystart_found_ != NOT_FOUND;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/hybrid_slow_start.h b/chromium/net/quic/congestion_control/hybrid_slow_start.h
deleted file mode 100644
index dbd440dffb5..00000000000
--- a/chromium/net/quic/congestion_control/hybrid_slow_start.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// This class is a helper class to TcpCubicSender.
-// Slow start is the initial startup phase of TCP, it lasts until first packet
-// loss. This class implements hybrid slow start of the TCP cubic send side
-// congestion algorithm. The key feaure of hybrid slow start is that it tries to
-// avoid running into the wall too hard during the slow start phase, which
-// the traditional TCP implementation does.
-// This does not implement ack train detection because it interacts poorly with
-// pacing.
-// http://netsrv.csc.ncsu.edu/export/hybridstart_pfldnet08.pdf
-// http://research.csc.ncsu.edu/netsrv/sites/default/files/hystart_techreport_2008.pdf
-
-#ifndef NET_QUIC_CONGESTION_CONTROL_HYBRID_SLOW_START_H_
-#define NET_QUIC_CONGESTION_CONTROL_HYBRID_SLOW_START_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class NET_EXPORT_PRIVATE HybridSlowStart {
- public:
- HybridSlowStart();
-
- void OnPacketAcked(QuicPacketNumber acked_packet_number);
-
- void OnPacketSent(QuicPacketNumber packet_number);
-
- // ShouldExitSlowStart should be called on every new ack frame, since a new
- // RTT measurement can be made then.
- // rtt: the RTT for this ack packet.
- // min_rtt: is the lowest delay (RTT) we have seen during the session.
- // congestion_window: the congestion window in packets.
- bool ShouldExitSlowStart(QuicTime::Delta rtt,
- QuicTime::Delta min_rtt,
- QuicPacketCount congestion_window);
-
- // Start a new slow start phase.
- void Restart();
-
- // TODO(ianswett): The following methods should be private, but that requires
- // a follow up CL to update the unit test.
- // Returns true if this ack the last packet number of our current slow start
- // round.
- // Call Reset if this returns true.
- bool IsEndOfRound(QuicPacketNumber ack) const;
-
- // Call for the start of each receive round (burst) in the slow start phase.
- void StartReceiveRound(QuicPacketNumber last_sent);
-
- // Whether slow start has started.
- bool started() const { return started_; }
-
- private:
- // Whether a condition for exiting slow start has been found.
- enum HystartState {
- NOT_FOUND,
- DELAY, // Too much increase in the round's min_rtt was observed.
- };
-
- // Whether the hybrid slow start has been started.
- bool started_;
- HystartState hystart_found_;
- // Last packet number sent which was CWND limited.
- QuicPacketNumber last_sent_packet_number_;
-
- // Variables for tracking acks received during a slow start round.
- QuicPacketNumber end_packet_number_; // End of the receive round.
- uint32_t rtt_sample_count_; // Number of rtt samples in the current round.
- QuicTime::Delta current_min_rtt_; // The minimum rtt of current round.
-
- DISALLOW_COPY_AND_ASSIGN(HybridSlowStart);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_HYBRID_SLOW_START_H_
diff --git a/chromium/net/quic/congestion_control/hybrid_slow_start_test.cc b/chromium/net/quic/congestion_control/hybrid_slow_start_test.cc
deleted file mode 100644
index 0e8c934a0a0..00000000000
--- a/chromium/net/quic/congestion_control/hybrid_slow_start_test.cc
+++ /dev/null
@@ -1,76 +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/congestion_control/hybrid_slow_start.h"
-
-#include <memory>
-
-#include "base/logging.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-class HybridSlowStartTest : public ::testing::Test {
- protected:
- HybridSlowStartTest()
- : one_ms_(QuicTime::Delta::FromMilliseconds(1)),
- rtt_(QuicTime::Delta::FromMilliseconds(60)) {}
- void SetUp() override { slow_start_.reset(new HybridSlowStart()); }
- const QuicTime::Delta one_ms_;
- const QuicTime::Delta rtt_;
- std::unique_ptr<HybridSlowStart> slow_start_;
-};
-
-TEST_F(HybridSlowStartTest, Simple) {
- QuicPacketNumber packet_number = 1;
- QuicPacketNumber end_packet_number = 3;
- slow_start_->StartReceiveRound(end_packet_number);
-
- EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number++));
-
- // Test duplicates.
- EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number));
-
- EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number++));
- EXPECT_TRUE(slow_start_->IsEndOfRound(packet_number++));
-
- // Test without a new registered end_packet_number;
- EXPECT_TRUE(slow_start_->IsEndOfRound(packet_number++));
-
- end_packet_number = 20;
- slow_start_->StartReceiveRound(end_packet_number);
- while (packet_number < end_packet_number) {
- EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number++));
- }
- EXPECT_TRUE(slow_start_->IsEndOfRound(packet_number++));
-}
-
-TEST_F(HybridSlowStartTest, Delay) {
- // We expect to detect the increase at +1/8 of the RTT; hence at a typical
- // RTT of 60ms the detection will happen at 67.5 ms.
- const int kHybridStartMinSamples = 8; // Number of acks required to trigger.
-
- QuicPacketNumber end_packet_number = 1;
- slow_start_->StartReceiveRound(end_packet_number++);
-
- // Will not trigger since our lowest RTT in our burst is the same as the long
- // term RTT provided.
- for (int n = 0; n < kHybridStartMinSamples; ++n) {
- EXPECT_FALSE(slow_start_->ShouldExitSlowStart(
- rtt_.Add(QuicTime::Delta::FromMilliseconds(n)), rtt_, 100));
- }
- slow_start_->StartReceiveRound(end_packet_number++);
- for (int n = 1; n < kHybridStartMinSamples; ++n) {
- EXPECT_FALSE(slow_start_->ShouldExitSlowStart(
- rtt_.Add(QuicTime::Delta::FromMilliseconds(n + 10)), rtt_, 100));
- }
- // Expect to trigger since all packets in this burst was above the long term
- // RTT provided.
- EXPECT_TRUE(slow_start_->ShouldExitSlowStart(
- rtt_.Add(QuicTime::Delta::FromMilliseconds(10)), rtt_, 100));
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/loss_detection_interface.h b/chromium/net/quic/congestion_control/loss_detection_interface.h
deleted file mode 100644
index 91f882acee5..00000000000
--- a/chromium/net/quic/congestion_control/loss_detection_interface.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// The pure virtual class for send side loss detection algorithm.
-
-#ifndef NET_QUIC_CONGESTION_CONTROL_LOSS_DETECTION_INTERFACE_H_
-#define NET_QUIC_CONGESTION_CONTROL_LOSS_DETECTION_INTERFACE_H_
-
-#include "net/quic/congestion_control/send_algorithm_interface.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class QuicUnackedPacketMap;
-class RttStats;
-
-class NET_EXPORT_PRIVATE LossDetectionInterface {
- public:
- virtual ~LossDetectionInterface() {}
-
- virtual LossDetectionType GetLossDetectionType() const = 0;
-
- // Called when a new ack arrives or the loss alarm fires.
- virtual void DetectLosses(
- const QuicUnackedPacketMap& unacked_packets,
- QuicTime time,
- const RttStats& rtt_stats,
- QuicPacketNumber largest_newly_acked,
- SendAlgorithmInterface::CongestionVector* packets_lost) = 0;
-
- // Get the time the LossDetectionAlgorithm wants to re-evaluate losses.
- // Returns QuicTime::Zero if no alarm needs to be set.
- virtual QuicTime GetLossTimeout() const = 0;
-
- // Called when a |spurious_retransmission| is detected. The original
- // transmission must have been caused by DetectLosses.
- virtual void SpuriousRetransmitDetected(
- const QuicUnackedPacketMap& unacked_packets,
- QuicTime time,
- const RttStats& rtt_stats,
- QuicPacketNumber spurious_retransmission) = 0;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_LOSS_DETECTION_INTERFACE_H_
diff --git a/chromium/net/quic/congestion_control/pacing_sender.cc b/chromium/net/quic/congestion_control/pacing_sender.cc
deleted file mode 100644
index e18183f4dd6..00000000000
--- a/chromium/net/quic/congestion_control/pacing_sender.cc
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright (c) 2013 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/congestion_control/pacing_sender.h"
-
-#include "net/quic/quic_flags.h"
-
-using std::min;
-
-namespace net {
-
-PacingSender::PacingSender(SendAlgorithmInterface* sender,
- QuicTime::Delta alarm_granularity,
- uint32_t initial_packet_burst)
- : sender_(sender),
- alarm_granularity_(alarm_granularity),
- initial_packet_burst_(initial_packet_burst),
- max_pacing_rate_(QuicBandwidth::Zero()),
- burst_tokens_(initial_packet_burst),
- last_delayed_packet_sent_time_(QuicTime::Zero()),
- ideal_next_packet_send_time_(QuicTime::Zero()),
- was_last_send_delayed_(false) {}
-
-PacingSender::~PacingSender() {}
-
-void PacingSender::SetFromConfig(const QuicConfig& config,
- Perspective perspective) {
- sender_->SetFromConfig(config, perspective);
-}
-
-void PacingSender::ResumeConnectionState(
- const CachedNetworkParameters& cached_network_params,
- bool max_bandwidth_resumption) {
- sender_->ResumeConnectionState(cached_network_params,
- max_bandwidth_resumption);
-}
-
-void PacingSender::SetNumEmulatedConnections(int num_connections) {
- sender_->SetNumEmulatedConnections(num_connections);
-}
-
-void PacingSender::SetMaxCongestionWindow(QuicByteCount max_congestion_window) {
- sender_->SetMaxCongestionWindow(max_congestion_window);
-}
-
-void PacingSender::SetMaxPacingRate(QuicBandwidth max_pacing_rate) {
- max_pacing_rate_ = max_pacing_rate;
-}
-
-void PacingSender::OnCongestionEvent(bool rtt_updated,
- QuicByteCount bytes_in_flight,
- const CongestionVector& acked_packets,
- const CongestionVector& lost_packets) {
- if (FLAGS_quic_allow_noprr && !lost_packets.empty()) {
- // Clear any burst tokens when entering recovery.
- burst_tokens_ = 0;
- }
- sender_->OnCongestionEvent(rtt_updated, bytes_in_flight, acked_packets,
- lost_packets);
-}
-
-bool PacingSender::OnPacketSent(
- QuicTime sent_time,
- QuicByteCount bytes_in_flight,
- QuicPacketNumber packet_number,
- QuicByteCount bytes,
- HasRetransmittableData has_retransmittable_data) {
- const bool in_flight =
- sender_->OnPacketSent(sent_time, bytes_in_flight, packet_number, bytes,
- has_retransmittable_data);
- if (has_retransmittable_data != HAS_RETRANSMITTABLE_DATA) {
- return in_flight;
- }
- // If in recovery, the connection is not coming out of quiescence.
- if (bytes_in_flight == 0 && !sender_->InRecovery()) {
- // Add more burst tokens anytime the connection is leaving quiescence, but
- // limit it to the equivalent of a single bulk write, not exceeding the
- // current CWND in packets.
- burst_tokens_ = min(
- initial_packet_burst_,
- static_cast<uint32_t>(sender_->GetCongestionWindow() / kDefaultTCPMSS));
- }
- if (burst_tokens_ > 0) {
- --burst_tokens_;
- was_last_send_delayed_ = false;
- last_delayed_packet_sent_time_ = QuicTime::Zero();
- ideal_next_packet_send_time_ = QuicTime::Zero();
- return in_flight;
- }
- // The next packet should be sent as soon as the current packet has been
- // transferred. PacingRate is based on bytes in flight including this packet.
- QuicTime::Delta delay =
- PacingRate(bytes_in_flight + bytes).TransferTime(bytes);
- // If the last send was delayed, and the alarm took a long time to get
- // invoked, allow the connection to make up for lost time.
- if (was_last_send_delayed_) {
- ideal_next_packet_send_time_ = ideal_next_packet_send_time_.Add(delay);
- // The send was application limited if it takes longer than the
- // pacing delay between sent packets.
- const bool application_limited =
- last_delayed_packet_sent_time_.IsInitialized() &&
- sent_time > last_delayed_packet_sent_time_.Add(delay);
- const bool making_up_for_lost_time =
- ideal_next_packet_send_time_ <= sent_time;
- // As long as we're making up time and not application limited,
- // continue to consider the packets delayed, allowing the packets to be
- // sent immediately.
- if (making_up_for_lost_time && !application_limited) {
- last_delayed_packet_sent_time_ = sent_time;
- } else {
- was_last_send_delayed_ = false;
- last_delayed_packet_sent_time_ = QuicTime::Zero();
- }
- } else {
- ideal_next_packet_send_time_ = QuicTime::Max(
- ideal_next_packet_send_time_.Add(delay), sent_time.Add(delay));
- }
- return in_flight;
-}
-
-void PacingSender::OnRetransmissionTimeout(bool packets_retransmitted) {
- sender_->OnRetransmissionTimeout(packets_retransmitted);
-}
-
-void PacingSender::OnConnectionMigration() {
- sender_->OnConnectionMigration();
-}
-
-QuicTime::Delta PacingSender::TimeUntilSend(
- QuicTime now,
- QuicByteCount bytes_in_flight) const {
- QuicTime::Delta time_until_send =
- sender_->TimeUntilSend(now, bytes_in_flight);
- if (burst_tokens_ > 0 || bytes_in_flight == 0) {
- // Don't pace if we have burst tokens available or leaving quiescence.
- return time_until_send;
- }
-
- if (!time_until_send.IsZero()) {
- DCHECK(time_until_send.IsInfinite());
- // The underlying sender prevents sending.
- return time_until_send;
- }
-
- // If the next send time is within the alarm granularity, send immediately.
- if (ideal_next_packet_send_time_ > now.Add(alarm_granularity_)) {
- DVLOG(1) << "Delaying packet: "
- << ideal_next_packet_send_time_.Subtract(now).ToMicroseconds();
- was_last_send_delayed_ = true;
- return ideal_next_packet_send_time_.Subtract(now);
- }
-
- DVLOG(1) << "Sending packet now";
- return QuicTime::Delta::Zero();
-}
-
-QuicBandwidth PacingSender::PacingRate(QuicByteCount bytes_in_flight) const {
- if (!max_pacing_rate_.IsZero()) {
- return QuicBandwidth::FromBitsPerSecond(
- min(max_pacing_rate_.ToBitsPerSecond(),
- sender_->PacingRate(bytes_in_flight).ToBitsPerSecond()));
- }
- return sender_->PacingRate(bytes_in_flight);
-}
-
-QuicBandwidth PacingSender::BandwidthEstimate() const {
- return sender_->BandwidthEstimate();
-}
-
-QuicTime::Delta PacingSender::RetransmissionDelay() const {
- return sender_->RetransmissionDelay();
-}
-
-QuicByteCount PacingSender::GetCongestionWindow() const {
- return sender_->GetCongestionWindow();
-}
-
-bool PacingSender::InSlowStart() const {
- return sender_->InSlowStart();
-}
-
-bool PacingSender::InRecovery() const {
- return sender_->InRecovery();
-}
-
-QuicByteCount PacingSender::GetSlowStartThreshold() const {
- return sender_->GetSlowStartThreshold();
-}
-
-CongestionControlType PacingSender::GetCongestionControlType() const {
- return sender_->GetCongestionControlType();
-}
-
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/pacing_sender.h b/chromium/net/quic/congestion_control/pacing_sender.h
deleted file mode 100644
index 207901ed0de..00000000000
--- a/chromium/net/quic/congestion_control/pacing_sender.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) 2013 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.
-//
-// A send algorithm that adds pacing on top of an another send algorithm.
-// It uses the underlying sender's pacing rate to schedule packets.
-// It also takes into consideration the expected granularity of the underlying
-// alarm to ensure that alarms are not set too aggressively, and err towards
-// sending packets too early instead of too late.
-
-#ifndef NET_QUIC_CONGESTION_CONTROL_PACING_SENDER_H_
-#define NET_QUIC_CONGESTION_CONTROL_PACING_SENDER_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-
-#include "base/macros.h"
-#include "net/quic/congestion_control/send_algorithm_interface.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class NET_EXPORT_PRIVATE PacingSender : public SendAlgorithmInterface {
- public:
- // Create a PacingSender to wrap the specified sender. |alarm_granularity|
- // indicates to the pacer to send that far into the future, since it should
- // not expect a callback before that time delta. |initial_packet_burst| is
- // the number of packets sent without pacing after quiescence.
- PacingSender(SendAlgorithmInterface* sender,
- QuicTime::Delta alarm_granularity,
- uint32_t initial_packet_burst);
- ~PacingSender() override;
-
- void SetMaxPacingRate(QuicBandwidth max_pacing_rate);
-
- // SendAlgorithmInterface methods.
- void SetFromConfig(const QuicConfig& config,
- Perspective perspective) override;
- void ResumeConnectionState(
- const CachedNetworkParameters& cached_network_params,
- bool max_bandwidth_resumption) override;
- void SetNumEmulatedConnections(int num_connections) override;
- void SetMaxCongestionWindow(QuicByteCount max_congestion_window) override;
- void OnCongestionEvent(bool rtt_updated,
- QuicByteCount bytes_in_flight,
- const CongestionVector& acked_packets,
- const CongestionVector& lost_packets) override;
- bool 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;
- QuicTime::Delta TimeUntilSend(QuicTime now,
- QuicByteCount bytes_in_flight) const override;
- QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const override;
- QuicBandwidth BandwidthEstimate() const override;
- QuicTime::Delta RetransmissionDelay() const override;
- QuicByteCount GetCongestionWindow() const override;
- bool InSlowStart() const override;
- bool InRecovery() const override;
- QuicByteCount GetSlowStartThreshold() const override;
- CongestionControlType GetCongestionControlType() const override;
- // End implementation of SendAlgorithmInterface.
-
- private:
- std::unique_ptr<SendAlgorithmInterface> sender_; // Underlying sender.
- // The estimated system alarm granularity.
- const QuicTime::Delta alarm_granularity_;
- // Configured maximum size of the burst coming out of quiescence. The burst
- // is never larger than the current CWND in packets.
- const uint32_t initial_packet_burst_;
- // If not QuicBandidth::Zero, the maximum rate the PacingSender will use.
- QuicBandwidth max_pacing_rate_;
-
- // Number of unpaced packets to be sent before packets are delayed.
- uint32_t burst_tokens_;
- // Send time of the last packet considered delayed.
- QuicTime last_delayed_packet_sent_time_;
- QuicTime ideal_next_packet_send_time_; // When can the next packet be sent.
- mutable bool was_last_send_delayed_; // True when the last send was delayed.
-
- DISALLOW_COPY_AND_ASSIGN(PacingSender);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_PACING_SENDER_H_
diff --git a/chromium/net/quic/congestion_control/pacing_sender_test.cc b/chromium/net/quic/congestion_control/pacing_sender_test.cc
deleted file mode 100644
index fbcbaa19843..00000000000
--- a/chromium/net/quic/congestion_control/pacing_sender_test.cc
+++ /dev/null
@@ -1,408 +0,0 @@
-// Copyright (c) 2013 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/congestion_control/pacing_sender.h"
-
-#include <memory>
-
-#include "base/logging.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::Return;
-using testing::StrictMock;
-using testing::_;
-
-namespace net {
-namespace test {
-
-const QuicByteCount kBytesInFlight = 1024;
-const int kInitialBurstPackets = 10;
-
-class PacingSenderTest : public ::testing::Test {
- protected:
- PacingSenderTest()
- : zero_time_(QuicTime::Delta::Zero()),
- infinite_time_(QuicTime::Delta::Infinite()),
- packet_number_(1),
- mock_sender_(new StrictMock<MockSendAlgorithm>()),
- pacing_sender_(new PacingSender(mock_sender_,
- QuicTime::Delta::FromMilliseconds(1),
- 0)) {
- // Pick arbitrary time.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(9));
- }
-
- ~PacingSenderTest() override {}
-
- void InitPacingRate(QuicPacketCount burst_size, QuicBandwidth bandwidth) {
- pacing_sender_.reset();
- mock_sender_ = new StrictMock<MockSendAlgorithm>();
- pacing_sender_.reset(new PacingSender(
- mock_sender_, QuicTime::Delta::FromMilliseconds(1), burst_size));
- EXPECT_CALL(*mock_sender_, PacingRate(_)).WillRepeatedly(Return(bandwidth));
- }
-
- void CheckPacketIsSentImmediately(HasRetransmittableData retransmittable_data,
- QuicByteCount bytes_in_flight,
- bool in_recovery) {
- // In order for the packet to be sendable, the underlying sender must
- // permit it to be sent immediately.
- for (int i = 0; i < 2; ++i) {
- EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(), bytes_in_flight))
- .WillOnce(Return(zero_time_));
- // Verify that the packet can be sent immediately.
- EXPECT_EQ(zero_time_,
- pacing_sender_->TimeUntilSend(clock_.Now(), bytes_in_flight));
- }
-
- // Actually send the packet.
- if (bytes_in_flight == 0) {
- EXPECT_CALL(*mock_sender_, InRecovery()).WillOnce(Return(in_recovery));
- }
- EXPECT_CALL(*mock_sender_,
- OnPacketSent(clock_.Now(), bytes_in_flight, packet_number_,
- kMaxPacketSize, retransmittable_data));
- pacing_sender_->OnPacketSent(clock_.Now(), bytes_in_flight,
- packet_number_++, kMaxPacketSize,
- retransmittable_data);
- }
-
- void CheckPacketIsSentImmediately() {
- CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, kBytesInFlight,
- false);
- }
-
- void CheckPacketIsDelayed(QuicTime::Delta delay) {
- // In order for the packet to be sendable, the underlying sender must
- // permit it to be sent immediately.
- for (int i = 0; i < 2; ++i) {
- EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(), kBytesInFlight))
- .WillOnce(Return(zero_time_));
- // Verify that the packet is delayed.
- EXPECT_EQ(delay.ToMicroseconds(),
- pacing_sender_->TimeUntilSend(clock_.Now(), kBytesInFlight)
- .ToMicroseconds());
- }
- }
-
- void UpdateRtt() {
- EXPECT_CALL(*mock_sender_, OnCongestionEvent(true, kBytesInFlight, _, _));
- SendAlgorithmInterface::CongestionVector empty_map;
- pacing_sender_->OnCongestionEvent(true, kBytesInFlight, empty_map,
- empty_map);
- }
-
- const QuicTime::Delta zero_time_;
- const QuicTime::Delta infinite_time_;
- MockClock clock_;
- QuicPacketNumber packet_number_;
- StrictMock<MockSendAlgorithm>* mock_sender_;
- std::unique_ptr<PacingSender> pacing_sender_;
-};
-
-TEST_F(PacingSenderTest, NoSend) {
- for (int i = 0; i < 2; ++i) {
- EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(), kBytesInFlight))
- .WillOnce(Return(infinite_time_));
- EXPECT_EQ(infinite_time_,
- pacing_sender_->TimeUntilSend(clock_.Now(), kBytesInFlight));
- }
-}
-
-TEST_F(PacingSenderTest, SendNow) {
- for (int i = 0; i < 2; ++i) {
- EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(), kBytesInFlight))
- .WillOnce(Return(zero_time_));
- EXPECT_EQ(zero_time_,
- pacing_sender_->TimeUntilSend(clock_.Now(), kBytesInFlight));
- }
-}
-
-TEST_F(PacingSenderTest, VariousSending) {
- // Configure pacing rate of 1 packet per 1 ms, no initial burst.
- InitPacingRate(0, QuicBandwidth::FromBytesAndTimeDelta(
- kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1)));
-
- // Now update the RTT and verify that packets are actually paced.
- UpdateRtt();
-
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
-
- // The first packet was a "make up", then we sent two packets "into the
- // future", so the delay should be 2.
- CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
-
- // Wake up on time.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2));
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
-
- // Wake up late.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(4));
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
-
- // Wake up really late.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8));
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
-
- // Wake up really late again, but application pause partway through.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8));
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100));
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
-
- // Wake up too early.
- CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
-
- // Wake up early, but after enough time has passed to permit a send.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- CheckPacketIsSentImmediately();
- CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
-}
-
-TEST_F(PacingSenderTest, InitialBurst) {
- // Configure pacing rate of 1 packet per 1 ms.
- InitPacingRate(10, QuicBandwidth::FromBytesAndTimeDelta(
- kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1)));
-
- EXPECT_CALL(*mock_sender_, GetCongestionWindow())
- .WillOnce(Return(10 * kDefaultTCPMSS));
- // Update the RTT and verify that the first 10 packets aren't paced.
- UpdateRtt();
-
- // Send 10 packets, and verify that they are not paced.
- for (int i = 0; i < kInitialBurstPackets; ++i) {
- CheckPacketIsSentImmediately();
- }
-
- // The first packet was a "make up", then we sent two packets "into the
- // future", so the delay should be 2ms.
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
-
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- CheckPacketIsSentImmediately();
-
- // Next time TimeUntilSend is called with no bytes in flight, pacing should
- // allow a packet to be sent, and when it's sent, the tokens are refilled.
- CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, 0, false);
- for (int i = 0; i < kInitialBurstPackets - 1; ++i) {
- CheckPacketIsSentImmediately();
- }
-
- // The first packet was a "make up", then we sent two packets "into the
- // future", so the delay should be 2ms.
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
-}
-
-TEST_F(PacingSenderTest, InitialBurstNoRttMeasurement) {
- // Configure pacing rate of 1 packet per 1 ms.
- InitPacingRate(10, QuicBandwidth::FromBytesAndTimeDelta(
- kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1)));
-
- EXPECT_CALL(*mock_sender_, GetCongestionWindow())
- .WillOnce(Return(10 * kDefaultTCPMSS));
- // Send 10 packets, and verify that they are not paced.
- for (int i = 0; i < kInitialBurstPackets; ++i) {
- CheckPacketIsSentImmediately();
- }
-
- // The first packet was a "make up", then we sent two packets "into the
- // future", so the delay should be 2ms.
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
-
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- CheckPacketIsSentImmediately();
-
- // Next time TimeUntilSend is called with no bytes in flight, the tokens
- // should be refilled and there should be no delay.
- CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, 0, false);
- // Send 10 packets, and verify that they are not paced.
- for (int i = 0; i < kInitialBurstPackets - 1; ++i) {
- CheckPacketIsSentImmediately();
- }
-
- // The first packet was a "make up", then we sent two packets "into the
- // future", so the delay should be 2ms.
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
-}
-
-TEST_F(PacingSenderTest, FastSending) {
- // Ensure the pacing sender paces, even when the inter-packet spacing is less
- // than the pacing granularity.
- InitPacingRate(10,
- QuicBandwidth::FromBytesAndTimeDelta(
- 2 * kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1)));
-
- EXPECT_CALL(*mock_sender_, GetCongestionWindow())
- .WillOnce(Return(10 * kDefaultTCPMSS));
- // Update the RTT and verify that the first 10 packets aren't paced.
- UpdateRtt();
-
- // Send 10 packets, and verify that they are not paced.
- for (int i = 0; i < kInitialBurstPackets; ++i) {
- CheckPacketIsSentImmediately();
- }
-
- // The first packet was a "make up", then we sent two packets "into the
- // future", since it's 2 packets/ms, so the delay should be 1.5ms.
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsDelayed(QuicTime::Delta::FromMicroseconds(1500));
-
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- CheckPacketIsSentImmediately();
-
- // Next time TimeUntilSend is called with no bytes in flight, the tokens
- // should be refilled and there should be no delay.
- CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, 0, false);
- for (int i = 0; i < kInitialBurstPackets - 1; ++i) {
- CheckPacketIsSentImmediately();
- }
-
- // The first packet was a "make up", then we sent two packets "into the
- // future", so the delay should be 1.5ms.
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsSentImmediately();
- CheckPacketIsDelayed(QuicTime::Delta::FromMicroseconds(1500));
-}
-
-TEST_F(PacingSenderTest, NoBurstEnteringRecovery) {
- ValueRestore<bool> old_flag(&FLAGS_quic_allow_noprr, true);
- // Configure pacing rate of 1 packet per 1 ms with no burst tokens.
- InitPacingRate(0, QuicBandwidth::FromBytesAndTimeDelta(
- kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1)));
- // Sending a packet will set burst tokens.
- CheckPacketIsSentImmediately();
-
- // Losing a packet will set clear burst tokens.
- SendAlgorithmInterface::CongestionVector lost_packets;
- lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
- SendAlgorithmInterface::CongestionVector empty;
- EXPECT_CALL(*mock_sender_,
- OnCongestionEvent(true, kMaxPacketSize, empty, lost_packets));
- pacing_sender_->OnCongestionEvent(true, kMaxPacketSize, empty, lost_packets);
- // One packet is sent immediately, because of 1ms pacing granularity.
- CheckPacketIsSentImmediately();
- // Ensure packets are immediately paced.
- EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(), kDefaultTCPMSS))
- .WillOnce(Return(zero_time_));
- // Verify the next packet is paced and delayed 2ms due to granularity.
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(2),
- pacing_sender_->TimeUntilSend(clock_.Now(), kDefaultTCPMSS));
- CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
-}
-
-TEST_F(PacingSenderTest, NoBurstInRecovery) {
- // Configure pacing rate of 1 packet per 1 ms with no burst tokens.
- InitPacingRate(0, QuicBandwidth::FromBytesAndTimeDelta(
- kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1)));
-
- UpdateRtt();
-
- // Ensure only one packet is sent immediately and the rest are paced.
- CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, 0, true);
- CheckPacketIsSentImmediately();
- CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
-}
-
-TEST_F(PacingSenderTest, VerifyInnerSenderCalled) {
- QuicBandwidth kBandwidth = QuicBandwidth::FromBitsPerSecond(1000);
- QuicTime kTime = QuicTime::Infinite();
- QuicTime::Delta kTimeDelta = QuicTime::Delta::Infinite();
- QuicByteCount kBytes = 12345u;
-
- EXPECT_CALL(*mock_sender_, SetFromConfig(_, Perspective::IS_SERVER));
- QuicConfig config;
- pacing_sender_->SetFromConfig(config, Perspective::IS_SERVER);
-
- EXPECT_CALL(*mock_sender_, ResumeConnectionState(_, true));
- CachedNetworkParameters cached_network_params;
- pacing_sender_->ResumeConnectionState(cached_network_params, true);
-
- EXPECT_CALL(*mock_sender_, SetNumEmulatedConnections(2));
- pacing_sender_->SetNumEmulatedConnections(2);
-
- EXPECT_CALL(*mock_sender_, SetMaxCongestionWindow(kBytes));
- pacing_sender_->SetMaxCongestionWindow(kBytes);
-
- SendAlgorithmInterface::CongestionVector packets;
- EXPECT_CALL(*mock_sender_, OnCongestionEvent(true, kBytes, packets, packets));
- pacing_sender_->OnCongestionEvent(true, kBytes, packets, packets);
-
- EXPECT_CALL(*mock_sender_, OnPacketSent(kTime, kBytes, 123u, kBytes,
- HAS_RETRANSMITTABLE_DATA));
- EXPECT_CALL(*mock_sender_, PacingRate(_)).WillOnce(Return(kBandwidth));
- pacing_sender_->OnPacketSent(kTime, kBytes, 123u, kBytes,
- HAS_RETRANSMITTABLE_DATA);
-
- EXPECT_CALL(*mock_sender_, OnRetransmissionTimeout(true));
- pacing_sender_->OnRetransmissionTimeout(true);
-
- EXPECT_CALL(*mock_sender_, OnConnectionMigration());
- pacing_sender_->OnConnectionMigration();
-
- EXPECT_CALL(*mock_sender_, TimeUntilSend(kTime, kBytes))
- .WillOnce(Return(kTimeDelta));
- pacing_sender_->TimeUntilSend(kTime, kBytes);
-
- EXPECT_CALL(*mock_sender_, PacingRate(_)).WillOnce(Return(kBandwidth));
- EXPECT_EQ(kBandwidth, pacing_sender_->PacingRate(0));
-
- EXPECT_CALL(*mock_sender_, BandwidthEstimate()).WillOnce(Return(kBandwidth));
- EXPECT_EQ(kBandwidth, pacing_sender_->BandwidthEstimate());
-
- EXPECT_CALL(*mock_sender_, RetransmissionDelay())
- .WillOnce(Return(kTimeDelta));
- EXPECT_EQ(kTimeDelta, pacing_sender_->RetransmissionDelay());
-
- EXPECT_CALL(*mock_sender_, GetCongestionWindow()).WillOnce(Return(kBytes));
- EXPECT_EQ(kBytes, pacing_sender_->GetCongestionWindow());
-
- EXPECT_CALL(*mock_sender_, InSlowStart()).WillOnce(Return(true));
- EXPECT_TRUE(pacing_sender_->InSlowStart());
-
- EXPECT_CALL(*mock_sender_, InRecovery()).WillOnce(Return(true));
- EXPECT_TRUE(pacing_sender_->InRecovery());
-
- EXPECT_CALL(*mock_sender_, GetSlowStartThreshold()).WillOnce(Return(kBytes));
- EXPECT_EQ(kBytes, pacing_sender_->GetSlowStartThreshold());
-
- EXPECT_CALL(*mock_sender_, GetCongestionControlType())
- .WillOnce(Return(kReno));
- EXPECT_EQ(kReno, pacing_sender_->GetCongestionControlType());
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/prr_sender.cc b/chromium/net/quic/congestion_control/prr_sender.cc
deleted file mode 100644
index b3f5f8b0337..00000000000
--- a/chromium/net/quic/congestion_control/prr_sender.cc
+++ /dev/null
@@ -1,71 +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.
-
-#include "net/quic/congestion_control/prr_sender.h"
-
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-namespace {
-// Constant based on TCP defaults.
-const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS;
-} // namespace
-
-PrrSender::PrrSender()
- : bytes_sent_since_loss_(0),
- bytes_delivered_since_loss_(0),
- ack_count_since_loss_(0),
- bytes_in_flight_before_loss_(0) {}
-
-void PrrSender::OnPacketSent(QuicByteCount sent_bytes) {
- bytes_sent_since_loss_ += sent_bytes;
-}
-
-void PrrSender::OnPacketLost(QuicByteCount bytes_in_flight) {
- bytes_sent_since_loss_ = 0;
- bytes_in_flight_before_loss_ = bytes_in_flight;
- bytes_delivered_since_loss_ = 0;
- ack_count_since_loss_ = 0;
-}
-
-void PrrSender::OnPacketAcked(QuicByteCount acked_bytes) {
- bytes_delivered_since_loss_ += acked_bytes;
- ++ack_count_since_loss_;
-}
-
-QuicTime::Delta PrrSender::TimeUntilSend(
- QuicByteCount congestion_window,
- QuicByteCount bytes_in_flight,
- QuicByteCount slowstart_threshold) const {
- // if (FLAGS_?? && bytes_in_flight < congestion_window) {
- // return QuicTime::Delta::Zero();
- // }
- // Return QuicTime::Zero In order to ensure limited transmit always works.
- if (bytes_sent_since_loss_ == 0 || bytes_in_flight < kMaxSegmentSize) {
- return QuicTime::Delta::Zero();
- }
- if (congestion_window > bytes_in_flight) {
- // During PRR-SSRB, limit outgoing packets to 1 extra MSS per ack, instead
- // of sending the entire available window. This prevents burst retransmits
- // when more packets are lost than the CWND reduction.
- // limit = MAX(prr_delivered - prr_out, DeliveredData) + MSS
- if (bytes_delivered_since_loss_ + ack_count_since_loss_ * kMaxSegmentSize <=
- bytes_sent_since_loss_) {
- return QuicTime::Delta::Infinite();
- }
- return QuicTime::Delta::Zero();
- }
- // Implement Proportional Rate Reduction (RFC6937).
- // Checks a simplified version of the PRR formula that doesn't use division:
- // AvailableSendWindow =
- // CEIL(prr_delivered * ssthresh / BytesInFlightAtLoss) - prr_sent
- if (bytes_delivered_since_loss_ * slowstart_threshold >
- bytes_sent_since_loss_ * bytes_in_flight_before_loss_) {
- return QuicTime::Delta::Zero();
- }
- return QuicTime::Delta::Infinite();
-}
-
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/prr_sender.h b/chromium/net/quic/congestion_control/prr_sender.h
deleted file mode 100644
index df73a9fbc6b..00000000000
--- a/chromium/net/quic/congestion_control/prr_sender.h
+++ /dev/null
@@ -1,44 +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.
-//
-// Implements Proportional Rate Reduction (PRR) per RFC 6937.
-
-#ifndef NET_QUIC_CONGESTION_CONTROL_PRR_SENDER_H_
-#define NET_QUIC_CONGESTION_CONTROL_PRR_SENDER_H_
-
-#include <stddef.h>
-
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class NET_EXPORT_PRIVATE PrrSender {
- public:
- PrrSender();
- // OnPacketLost should be called on the first loss that triggers a recovery
- // period and all other methods in this class should only be called when in
- // recovery.
- void OnPacketLost(QuicByteCount bytes_in_flight);
- void OnPacketSent(QuicByteCount sent_bytes);
- void OnPacketAcked(QuicByteCount acked_bytes);
- QuicTime::Delta TimeUntilSend(QuicByteCount congestion_window,
- QuicByteCount bytes_in_flight,
- QuicByteCount slowstart_threshold) const;
-
- private:
- // Bytes sent and acked since the last loss event.
- // |bytes_sent_since_loss_| is the same as "prr_out_" in RFC 6937,
- // and |bytes_delivered_since_loss_| is the same as "prr_delivered_".
- QuicByteCount bytes_sent_since_loss_;
- QuicByteCount bytes_delivered_since_loss_;
- size_t ack_count_since_loss_;
-
- // The congestion window before the last loss event.
- QuicByteCount bytes_in_flight_before_loss_;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_PRR_SENDER_H_
diff --git a/chromium/net/quic/congestion_control/prr_sender_test.cc b/chromium/net/quic/congestion_control/prr_sender_test.cc
deleted file mode 100644
index f7082f2f83c..00000000000
--- a/chromium/net/quic/congestion_control/prr_sender_test.cc
+++ /dev/null
@@ -1,134 +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.
-
-#include "net/quic/congestion_control/prr_sender.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_protocol.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-namespace {
-// Constant based on TCP defaults.
-const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS;
-} // namespace
-
-class PrrSenderTest : public ::testing::Test {};
-
-TEST_F(PrrSenderTest, SingleLossResultsInSendOnEveryOtherAck) {
- PrrSender prr;
- QuicPacketCount num_packets_in_flight = 50;
- QuicByteCount bytes_in_flight = num_packets_in_flight * kMaxSegmentSize;
- const QuicPacketCount ssthresh_after_loss = num_packets_in_flight / 2;
- const QuicByteCount congestion_window = ssthresh_after_loss * kMaxSegmentSize;
-
- prr.OnPacketLost(bytes_in_flight);
- // Ack a packet. PRR allows one packet to leave immediately.
- prr.OnPacketAcked(kMaxSegmentSize);
- bytes_in_flight -= kMaxSegmentSize;
- EXPECT_EQ(QuicTime::Delta::Zero(),
- prr.TimeUntilSend(congestion_window, bytes_in_flight,
- ssthresh_after_loss * kMaxSegmentSize));
- // Send retransmission.
- prr.OnPacketSent(kMaxSegmentSize);
- // PRR shouldn't allow sending any more packets.
- EXPECT_EQ(QuicTime::Delta::Infinite(),
- prr.TimeUntilSend(congestion_window, bytes_in_flight,
- ssthresh_after_loss * kMaxSegmentSize));
-
- // One packet is lost, and one ack was consumed above. PRR now paces
- // transmissions through the remaining 48 acks. PRR will alternatively
- // disallow and allow a packet to be sent in response to an ack.
- for (uint64_t i = 0; i < ssthresh_after_loss - 1; ++i) {
- // Ack a packet. PRR shouldn't allow sending a packet in response.
- prr.OnPacketAcked(kMaxSegmentSize);
- bytes_in_flight -= kMaxSegmentSize;
- EXPECT_EQ(QuicTime::Delta::Infinite(),
- prr.TimeUntilSend(congestion_window, bytes_in_flight,
- ssthresh_after_loss * kMaxSegmentSize));
- // Ack another packet. PRR should now allow sending a packet in response.
- prr.OnPacketAcked(kMaxSegmentSize);
- bytes_in_flight -= kMaxSegmentSize;
- EXPECT_EQ(QuicTime::Delta::Zero(),
- prr.TimeUntilSend(congestion_window, bytes_in_flight,
- ssthresh_after_loss * kMaxSegmentSize));
- // Send a packet in response.
- prr.OnPacketSent(kMaxSegmentSize);
- bytes_in_flight += kMaxSegmentSize;
- }
-
- // Since bytes_in_flight is now equal to congestion_window, PRR now maintains
- // packet conservation, allowing one packet to be sent in response to an ack.
- EXPECT_EQ(congestion_window, bytes_in_flight);
- for (int i = 0; i < 10; ++i) {
- // Ack a packet.
- prr.OnPacketAcked(kMaxSegmentSize);
- bytes_in_flight -= kMaxSegmentSize;
- EXPECT_EQ(QuicTime::Delta::Zero(),
- prr.TimeUntilSend(congestion_window, bytes_in_flight,
- ssthresh_after_loss * kMaxSegmentSize));
- // Send a packet in response, since PRR allows it.
- prr.OnPacketSent(kMaxSegmentSize);
- bytes_in_flight += kMaxSegmentSize;
-
- // Since bytes_in_flight is equal to the congestion_window,
- // PRR disallows sending.
- EXPECT_EQ(congestion_window, bytes_in_flight);
- EXPECT_EQ(QuicTime::Delta::Infinite(),
- prr.TimeUntilSend(congestion_window, bytes_in_flight,
- ssthresh_after_loss * kMaxSegmentSize));
- }
-}
-
-TEST_F(PrrSenderTest, BurstLossResultsInSlowStart) {
- PrrSender prr;
- QuicByteCount bytes_in_flight = 20 * kMaxSegmentSize;
- const QuicPacketCount num_packets_lost = 13;
- const QuicPacketCount ssthresh_after_loss = 10;
- const QuicByteCount congestion_window = ssthresh_after_loss * kMaxSegmentSize;
-
- // Lose 13 packets.
- bytes_in_flight -= num_packets_lost * kMaxSegmentSize;
- prr.OnPacketLost(bytes_in_flight);
-
- // PRR-SSRB will allow the following 3 acks to send up to 2 packets.
- for (int i = 0; i < 3; ++i) {
- prr.OnPacketAcked(kMaxSegmentSize);
- bytes_in_flight -= kMaxSegmentSize;
- // PRR-SSRB should allow two packets to be sent.
- for (int j = 0; j < 2; ++j) {
- EXPECT_EQ(QuicTime::Delta::Zero(),
- prr.TimeUntilSend(congestion_window, bytes_in_flight,
- ssthresh_after_loss * kMaxSegmentSize));
- // Send a packet in response.
- prr.OnPacketSent(kMaxSegmentSize);
- bytes_in_flight += kMaxSegmentSize;
- }
- // PRR should allow no more than 2 packets in response to an ack.
- EXPECT_EQ(QuicTime::Delta::Infinite(),
- prr.TimeUntilSend(congestion_window, bytes_in_flight,
- ssthresh_after_loss * kMaxSegmentSize));
- }
-
- // Out of SSRB mode, PRR allows one send in response to each ack.
- for (int i = 0; i < 10; ++i) {
- prr.OnPacketAcked(kMaxSegmentSize);
- bytes_in_flight -= kMaxSegmentSize;
- EXPECT_EQ(QuicTime::Delta::Zero(),
- prr.TimeUntilSend(congestion_window, bytes_in_flight,
- ssthresh_after_loss * kMaxSegmentSize));
- // Send a packet in response.
- prr.OnPacketSent(kMaxSegmentSize);
- bytes_in_flight += kMaxSegmentSize;
- }
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/rtt_stats.cc b/chromium/net/quic/congestion_control/rtt_stats.cc
deleted file mode 100644
index 4809f1ad510..00000000000
--- a/chromium/net/quic/congestion_control/rtt_stats.cc
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/congestion_control/rtt_stats.h"
-
-#include <cstdlib> // std::abs
-
-#include "net/quic/quic_flags.h"
-
-using std::max;
-
-namespace net {
-
-namespace {
-
-// Default initial rtt used before any samples are received.
-const int kInitialRttMs = 100;
-const float kAlpha = 0.125f;
-const float kOneMinusAlpha = (1 - kAlpha);
-const float kBeta = 0.25f;
-const float kOneMinusBeta = (1 - kBeta);
-// 10-second window length for windowed min RTT.
-const int kMinRttWindowLengthMs = 10000;
-
-} // namespace
-
-RttStats::RttStats()
- : latest_rtt_(QuicTime::Delta::Zero()),
- min_rtt_(QuicTime::Delta::Zero()),
- smoothed_rtt_(QuicTime::Delta::Zero()),
- previous_srtt_(QuicTime::Delta::Zero()),
- mean_deviation_(QuicTime::Delta::Zero()),
- initial_rtt_us_(kInitialRttMs * kNumMicrosPerMilli),
- forced_windowed_min_rtt_(QuicTime::Delta::Zero()),
- forced_windowed_min_rtt_time_(QuicTime::Zero()),
- num_samples_for_forced_min_(0),
- windowed_min_rtt_(
- QuicTime::Delta::FromMilliseconds(kMinRttWindowLengthMs),
- QuicTime::Delta::Zero()) {}
-
-void RttStats::SampleNewWindowedMinRtt(uint32_t num_samples) {
- num_samples_for_forced_min_ = num_samples;
- forced_windowed_min_rtt_ = QuicTime::Delta::Zero();
- forced_windowed_min_rtt_time_ = QuicTime::Zero();
-}
-
-void RttStats::ExpireSmoothedMetrics() {
- mean_deviation_ =
- max(mean_deviation_,
- QuicTime::Delta::FromMicroseconds(
- std::abs(smoothed_rtt_.Subtract(latest_rtt_).ToMicroseconds())));
- smoothed_rtt_ = max(smoothed_rtt_, latest_rtt_);
-}
-
-// Updates the RTT based on a new sample.
-void RttStats::UpdateRtt(QuicTime::Delta send_delta,
- QuicTime::Delta ack_delay,
- QuicTime now) {
- if (send_delta.IsInfinite() || send_delta <= QuicTime::Delta::Zero()) {
- LOG(WARNING) << "Ignoring measured send_delta, because it's is "
- << "either infinite, zero, or negative. send_delta = "
- << send_delta.ToMicroseconds();
- return;
- }
-
- // Update min_rtt_ first. min_rtt_ does not use an rtt_sample corrected for
- // ack_delay but the raw observed send_delta, since poor clock granularity at
- // the client may cause a high ack_delay to result in underestimation of the
- // min_rtt_.
- if (min_rtt_.IsZero() || min_rtt_ > send_delta) {
- min_rtt_ = send_delta;
- }
- UpdateWindowedMinRtt(send_delta, now);
-
- // Correct for ack_delay if information received from the peer results in a
- // positive RTT sample. Otherwise, we use the send_delta as a reasonable
- // measure for smoothed_rtt.
- QuicTime::Delta rtt_sample(send_delta);
- previous_srtt_ = smoothed_rtt_;
-
- if (rtt_sample > ack_delay) {
- rtt_sample = rtt_sample.Subtract(ack_delay);
- }
- latest_rtt_ = rtt_sample;
- // First time call.
- if (smoothed_rtt_.IsZero()) {
- smoothed_rtt_ = rtt_sample;
- mean_deviation_ =
- QuicTime::Delta::FromMicroseconds(rtt_sample.ToMicroseconds() / 2);
- } else {
- mean_deviation_ = QuicTime::Delta::FromMicroseconds(static_cast<int64_t>(
- kOneMinusBeta * mean_deviation_.ToMicroseconds() +
- kBeta * std::abs(smoothed_rtt_.Subtract(rtt_sample).ToMicroseconds())));
- smoothed_rtt_ =
- smoothed_rtt_.Multiply(kOneMinusAlpha).Add(rtt_sample.Multiply(kAlpha));
- DVLOG(1) << " smoothed_rtt(us):" << smoothed_rtt_.ToMicroseconds()
- << " mean_deviation(us):" << mean_deviation_.ToMicroseconds();
- }
-}
-
-void RttStats::UpdateWindowedMinRtt(QuicTime::Delta rtt_sample, QuicTime now) {
- // Update windowed_min_rtt.
- windowed_min_rtt_.Update(rtt_sample, now);
- if (num_samples_for_forced_min_ <= 0) {
- return;
- }
- // Reset windowed_min_rtt to the min of num_samples_for_forced_min_ samples.
- if (forced_windowed_min_rtt_.IsZero() ||
- rtt_sample <= forced_windowed_min_rtt_) {
- forced_windowed_min_rtt_ = rtt_sample;
- forced_windowed_min_rtt_time_ = now;
- }
- if (num_samples_for_forced_min_ == 1) {
- windowed_min_rtt_.Reset(forced_windowed_min_rtt_,
- forced_windowed_min_rtt_time_);
- }
- --num_samples_for_forced_min_;
-}
-
-void RttStats::OnConnectionMigration() {
- latest_rtt_ = QuicTime::Delta::Zero();
- min_rtt_ = QuicTime::Delta::Zero();
- smoothed_rtt_ = QuicTime::Delta::Zero();
- mean_deviation_ = QuicTime::Delta::Zero();
- initial_rtt_us_ = kInitialRttMs * kNumMicrosPerMilli;
- num_samples_for_forced_min_ = 0;
- windowed_min_rtt_.Reset(QuicTime::Delta::Zero(), QuicTime::Zero());
-}
-
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/rtt_stats.h b/chromium/net/quic/congestion_control/rtt_stats.h
deleted file mode 100644
index ac151490b40..00000000000
--- a/chromium/net/quic/congestion_control/rtt_stats.h
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// A convenience class to store rtt samples and calculate smoothed rtt.
-
-#ifndef NET_QUIC_CONGESTION_CONTROL_RTT_STATS_H_
-#define NET_QUIC_CONGESTION_CONTROL_RTT_STATS_H_
-
-#include <stdint.h>
-
-#include <algorithm>
-
-#include "base/macros.h"
-#include "net/quic/congestion_control/windowed_filter.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-namespace test {
-class RttStatsPeer;
-} // namespace test
-
-class NET_EXPORT_PRIVATE RttStats {
- public:
- RttStats();
-
- // Updates the RTT from an incoming ack which is received |send_delta| after
- // the packet is sent and the peer reports the ack being delayed |ack_delay|.
- void UpdateRtt(QuicTime::Delta send_delta,
- QuicTime::Delta ack_delay,
- QuicTime now);
-
- // Causes the smoothed_rtt to be increased to the latest_rtt if the latest_rtt
- // is larger. The mean deviation is increased to the most recent deviation if
- // it's larger.
- void ExpireSmoothedMetrics();
-
- // Forces RttStats to sample a new windowed min rtt within the next
- // |num_samples| UpdateRtt calls.
- void SampleNewWindowedMinRtt(uint32_t num_samples);
-
- // Called when connection migrates and rtt measurement needs to be reset.
- void OnConnectionMigration();
-
- // Returns the EWMA smoothed RTT for the connection.
- // May return Zero if no valid updates have occurred.
- QuicTime::Delta smoothed_rtt() const { return smoothed_rtt_; }
-
- // Returns the EWMA smoothed RTT prior to the most recent RTT sample.
- QuicTime::Delta previous_srtt() const { return previous_srtt_; }
-
- int64_t initial_rtt_us() const { return initial_rtt_us_; }
-
- // Sets an initial RTT to be used for SmoothedRtt before any RTT updates.
- void set_initial_rtt_us(int64_t initial_rtt_us) {
- if (initial_rtt_us <= 0) {
- QUIC_BUG << "Attempt to set initial rtt to <= 0.";
- return;
- }
- initial_rtt_us_ = initial_rtt_us;
- }
-
- // The most recent rtt measurement.
- // May return Zero if no valid updates have occurred.
- QuicTime::Delta latest_rtt() const { return latest_rtt_; }
-
- // Returns the min_rtt for the entire connection.
- // May return Zero if no valid updates have occurred.
- QuicTime::Delta min_rtt() const { return min_rtt_; }
-
- QuicTime::Delta mean_deviation() const { return mean_deviation_; }
-
- QuicTime::Delta WindowedMinRtt() { return windowed_min_rtt_.GetBest(); }
-
- private:
- friend class test::RttStatsPeer;
-
- // Updates the windowed min rtt. Also forces a new windowed_min_rtt sample,
- // if set by a call to SampleNewWindowedMinRtt() above.
- void UpdateWindowedMinRtt(QuicTime::Delta rtt_sample, QuicTime now);
-
- QuicTime::Delta latest_rtt_;
- QuicTime::Delta min_rtt_;
- QuicTime::Delta smoothed_rtt_;
- QuicTime::Delta previous_srtt_;
- // Mean RTT deviation during this session.
- // Approximation of standard deviation, the error is roughly 1.25 times
- // larger than the standard deviation, for a normally distributed signal.
- QuicTime::Delta mean_deviation_;
- int64_t initial_rtt_us_;
-
- // Variables used to force a new windowed_min_rtt measurement within
- // num_samples_for_forced_min_.
- QuicTime::Delta forced_windowed_min_rtt_;
- QuicTime forced_windowed_min_rtt_time_;
- uint32_t num_samples_for_forced_min_;
-
- // Windowed min_rtt.
- WindowedFilter<QuicTime::Delta, MinFilter<QuicTime::Delta>> windowed_min_rtt_;
-
- DISALLOW_COPY_AND_ASSIGN(RttStats);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_RTT_STATS_H_
diff --git a/chromium/net/quic/congestion_control/rtt_stats_test.cc b/chromium/net/quic/congestion_control/rtt_stats_test.cc
deleted file mode 100644
index 9a25946b2d0..00000000000
--- a/chromium/net/quic/congestion_control/rtt_stats_test.cc
+++ /dev/null
@@ -1,202 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/congestion_control/rtt_stats.h"
-
-#include <vector>
-
-#include "base/logging.h"
-#include "base/test/mock_log.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/test_tools/rtt_stats_peer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using logging::LOG_WARNING;
-using std::vector;
-using testing::HasSubstr;
-using testing::Message;
-using testing::_;
-
-namespace net {
-namespace test {
-
-class RttStatsTest : public ::testing::Test {
- protected:
- RttStats rtt_stats_;
-};
-
-TEST_F(RttStatsTest, DefaultsBeforeUpdate) {
- EXPECT_LT(0u, rtt_stats_.initial_rtt_us());
- EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.min_rtt());
- EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.smoothed_rtt());
-}
-
-TEST_F(RttStatsTest, SmoothedRtt) {
- // Verify that ack_delay is corrected for in Smoothed RTT.
- rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300),
- QuicTime::Delta::FromMilliseconds(100),
- QuicTime::Zero());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt());
- // Verify that effective RTT of zero does not change Smoothed RTT.
- rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(200),
- QuicTime::Delta::FromMilliseconds(200),
- QuicTime::Zero());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt());
- // Verify that large erroneous ack_delay does not change Smoothed RTT.
- rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(200),
- QuicTime::Delta::FromMilliseconds(300),
- QuicTime::Zero());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt());
-}
-
-TEST_F(RttStatsTest, PreviousSmoothedRtt) {
- // Verify that ack_delay is corrected for in Smoothed RTT.
- rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300),
- QuicTime::Delta::FromMilliseconds(100),
- QuicTime::Zero());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt());
- EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.previous_srtt());
- // Ensure the previous SRTT is 200ms after a 100ms sample.
- rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats_.latest_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(187500).ToMicroseconds(),
- rtt_stats_.smoothed_rtt().ToMicroseconds());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.previous_srtt());
-}
-
-TEST_F(RttStatsTest, MinRtt) {
- rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(200),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.min_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200),
- rtt_stats_.WindowedMinRtt());
- rtt_stats_.UpdateRtt(
- QuicTime::Delta::FromMilliseconds(10), QuicTime::Delta::Zero(),
- QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(10)));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.WindowedMinRtt());
- rtt_stats_.UpdateRtt(
- QuicTime::Delta::FromMilliseconds(50), QuicTime::Delta::Zero(),
- QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(20)));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.WindowedMinRtt());
- rtt_stats_.UpdateRtt(
- QuicTime::Delta::FromMilliseconds(50), QuicTime::Delta::Zero(),
- QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(30)));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.WindowedMinRtt());
- rtt_stats_.UpdateRtt(
- QuicTime::Delta::FromMilliseconds(50), QuicTime::Delta::Zero(),
- QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(40)));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.WindowedMinRtt());
- // Verify that ack_delay does not go into recording of min_rtt_.
- rtt_stats_.UpdateRtt(
- QuicTime::Delta::FromMilliseconds(7),
- QuicTime::Delta::FromMilliseconds(2),
- QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(50)));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(7), rtt_stats_.min_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(7), rtt_stats_.WindowedMinRtt());
-}
-
-TEST_F(RttStatsTest, WindowedMinRtt) {
- rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(10),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.WindowedMinRtt());
-
- rtt_stats_.SampleNewWindowedMinRtt(4);
- for (int i = 0; i < 3; ++i) {
- rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(50),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
- rtt_stats_.WindowedMinRtt());
- }
- rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(50),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(50), rtt_stats_.WindowedMinRtt());
-}
-
-TEST_F(RttStatsTest, ExpireSmoothedMetrics) {
- QuicTime::Delta initial_rtt = QuicTime::Delta::FromMilliseconds(10);
- rtt_stats_.UpdateRtt(initial_rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
- EXPECT_EQ(initial_rtt, rtt_stats_.min_rtt());
- EXPECT_EQ(initial_rtt, rtt_stats_.WindowedMinRtt());
- EXPECT_EQ(initial_rtt, rtt_stats_.smoothed_rtt());
-
- EXPECT_EQ(initial_rtt.Multiply(0.5), rtt_stats_.mean_deviation());
-
- // Update once with a 20ms RTT.
- QuicTime::Delta doubled_rtt = initial_rtt.Multiply(2);
- rtt_stats_.UpdateRtt(doubled_rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
- EXPECT_EQ(initial_rtt.Multiply(1.125), rtt_stats_.smoothed_rtt());
-
- // Expire the smoothed metrics, increasing smoothed rtt and mean deviation.
- rtt_stats_.ExpireSmoothedMetrics();
- EXPECT_EQ(doubled_rtt, rtt_stats_.smoothed_rtt());
- EXPECT_EQ(initial_rtt.Multiply(0.875), rtt_stats_.mean_deviation());
-
- // Now go back down to 5ms and expire the smoothed metrics, and ensure the
- // mean deviation increases to 15ms.
- QuicTime::Delta half_rtt = initial_rtt.Multiply(0.5);
- rtt_stats_.UpdateRtt(half_rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
- EXPECT_GT(doubled_rtt, rtt_stats_.smoothed_rtt());
- EXPECT_LT(initial_rtt, rtt_stats_.mean_deviation());
-}
-
-TEST_F(RttStatsTest, UpdateRttWithBadSendDeltas) {
- // Make sure we ignore bad RTTs.
- base::test::MockLog log;
-
- QuicTime::Delta initial_rtt = QuicTime::Delta::FromMilliseconds(10);
- rtt_stats_.UpdateRtt(initial_rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
- EXPECT_EQ(initial_rtt, rtt_stats_.min_rtt());
- EXPECT_EQ(initial_rtt, rtt_stats_.WindowedMinRtt());
- EXPECT_EQ(initial_rtt, rtt_stats_.smoothed_rtt());
-
- vector<QuicTime::Delta> bad_send_deltas;
- bad_send_deltas.push_back(QuicTime::Delta::Zero());
- bad_send_deltas.push_back(QuicTime::Delta::Infinite());
- bad_send_deltas.push_back(QuicTime::Delta::FromMicroseconds(-1000));
- log.StartCapturingLogs();
-
- for (QuicTime::Delta bad_send_delta : bad_send_deltas) {
- SCOPED_TRACE(Message() << "bad_send_delta = "
- << bad_send_delta.ToMicroseconds());
- EXPECT_CALL(log, Log(LOG_WARNING, _, _, _, HasSubstr("Ignoring")));
- rtt_stats_.UpdateRtt(bad_send_delta, QuicTime::Delta::Zero(),
- QuicTime::Zero());
- EXPECT_EQ(initial_rtt, rtt_stats_.min_rtt());
- EXPECT_EQ(initial_rtt, rtt_stats_.WindowedMinRtt());
- EXPECT_EQ(initial_rtt, rtt_stats_.smoothed_rtt());
- }
-}
-
-TEST_F(RttStatsTest, ResetAfterConnectionMigrations) {
- rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300),
- QuicTime::Delta::FromMilliseconds(100),
- QuicTime::Zero());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.min_rtt());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300),
- rtt_stats_.WindowedMinRtt());
-
- // Reset rtt stats on connection migrations.
- rtt_stats_.OnConnectionMigration();
- EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.latest_rtt());
- EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.smoothed_rtt());
- EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.min_rtt());
- EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.WindowedMinRtt());
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/send_algorithm_interface.cc b/chromium/net/quic/congestion_control/send_algorithm_interface.cc
deleted file mode 100644
index 821beb755b7..00000000000
--- a/chromium/net/quic/congestion_control/send_algorithm_interface.cc
+++ /dev/null
@@ -1,58 +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/congestion_control/send_algorithm_interface.h"
-
-#include "net/quic/congestion_control/tcp_cubic_sender_bytes.h"
-#include "net/quic/congestion_control/tcp_cubic_sender_packets.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-class RttStats;
-
-// Factory for send side congestion control algorithm.
-SendAlgorithmInterface* SendAlgorithmInterface::Create(
- const QuicClock* clock,
- const RttStats* rtt_stats,
- CongestionControlType congestion_control_type,
- QuicConnectionStats* stats,
- QuicPacketCount initial_congestion_window) {
- QuicPacketCount max_congestion_window =
- (kDefaultSocketReceiveBuffer * kConservativeReceiveBufferFraction) /
- kDefaultTCPMSS;
- if (FLAGS_quic_ignore_srbf) {
- max_congestion_window = kDefaultMaxCongestionWindowPackets;
- }
- switch (congestion_control_type) {
- case kCubic:
- return new TcpCubicSenderPackets(
- clock, rtt_stats, false /* don't use Reno */,
- initial_congestion_window, max_congestion_window, stats);
- case kCubicBytes:
- return new TcpCubicSenderBytes(
- clock, rtt_stats, false /* don't use Reno */,
- initial_congestion_window, max_congestion_window, stats);
- case kReno:
- return new TcpCubicSenderPackets(clock, rtt_stats, true /* use Reno */,
- initial_congestion_window,
- max_congestion_window, stats);
- case kRenoBytes:
- return new TcpCubicSenderBytes(clock, rtt_stats, true /* use Reno */,
- initial_congestion_window,
- max_congestion_window, stats);
- case kBBR:
-// TODO(rtenneti): Enable BbrTcpSender.
-#if 0
- return new BbrTcpSender(clock, rtt_stats, initial_congestion_window,
- max_congestion_window, stats, true);
-#endif
- LOG(DFATAL) << "BbrTcpSender is not supported.";
- return nullptr;
- }
- return nullptr;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/send_algorithm_interface.h b/chromium/net/quic/congestion_control/send_algorithm_interface.h
deleted file mode 100644
index f711e76f920..00000000000
--- a/chromium/net/quic/congestion_control/send_algorithm_interface.h
+++ /dev/null
@@ -1,127 +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.
-//
-// The pure virtual class for send side congestion control algorithm.
-
-#ifndef NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_INTERFACE_H_
-#define NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_INTERFACE_H_
-
-#include <algorithm>
-#include <map>
-
-#include "net/base/net_export.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_connection_stats.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class CachedNetworkParameters;
-class RttStats;
-
-const QuicPacketCount kDefaultMaxCongestionWindowPackets = 2000;
-
-class NET_EXPORT_PRIVATE SendAlgorithmInterface {
- public:
- // A sorted vector of packets.
- typedef std::vector<std::pair<QuicPacketNumber, QuicPacketLength>>
- CongestionVector;
-
- static SendAlgorithmInterface* Create(
- const QuicClock* clock,
- const RttStats* rtt_stats,
- CongestionControlType type,
- QuicConnectionStats* stats,
- QuicPacketCount initial_congestion_window);
-
- virtual ~SendAlgorithmInterface() {}
-
- virtual void SetFromConfig(const QuicConfig& config,
- Perspective perspective) = 0;
-
- // Sets the number of connections to emulate when doing congestion control,
- // particularly for congestion avoidance. Can be set any time.
- virtual void SetNumEmulatedConnections(int num_connections) = 0;
-
- // Sets the maximum congestion window in bytes.
- virtual void SetMaxCongestionWindow(QuicByteCount max_congestion_window) = 0;
-
- // Indicates an update to the congestion state, caused either by an incoming
- // ack or loss event timeout. |rtt_updated| indicates whether a new
- // latest_rtt sample has been taken, |byte_in_flight| the bytes in flight
- // prior to the congestion event. |acked_packets| and |lost_packets| are
- // any packets considered acked or lost as a result of the congestion event.
- virtual void OnCongestionEvent(bool rtt_updated,
- QuicByteCount bytes_in_flight,
- const CongestionVector& acked_packets,
- const CongestionVector& lost_packets) = 0;
-
- // Inform that we sent |bytes| to the wire, and if the packet is
- // retransmittable. Returns true if the packet should be tracked by the
- // congestion manager and included in bytes_in_flight, false otherwise.
- // |bytes_in_flight| is the number of bytes in flight before the packet was
- // sent.
- // Note: this function must be called for every packet sent to the wire.
- virtual bool OnPacketSent(QuicTime sent_time,
- QuicByteCount bytes_in_flight,
- QuicPacketNumber packet_number,
- QuicByteCount bytes,
- HasRetransmittableData is_retransmittable) = 0;
-
- // Called when the retransmission timeout fires. Neither OnPacketAbandoned
- // nor OnPacketLost will be called for these packets.
- virtual void OnRetransmissionTimeout(bool packets_retransmitted) = 0;
-
- // Called when connection migrates and cwnd needs to be reset.
- virtual void OnConnectionMigration() = 0;
-
- // Calculate the time until we can send the next packet.
- virtual QuicTime::Delta TimeUntilSend(
- QuicTime now,
- QuicByteCount bytes_in_flight) const = 0;
-
- // The pacing rate of the send algorithm. May be zero if the rate is unknown.
- virtual QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const = 0;
-
- // What's the current estimated bandwidth in bytes per second.
- // Returns 0 when it does not have an estimate.
- virtual QuicBandwidth BandwidthEstimate() const = 0;
-
- // Get the send algorithm specific retransmission delay, called RTO in TCP,
- // Note 1: the caller is responsible for sanity checking this value.
- // Note 2: this will return zero if we don't have enough data for an estimate.
- virtual QuicTime::Delta RetransmissionDelay() const = 0;
-
- // Returns the size of the current congestion window in bytes. Note, this is
- // not the *available* window. Some send algorithms may not use a congestion
- // window and will return 0.
- virtual QuicByteCount GetCongestionWindow() const = 0;
-
- // Whether the send algorithm is currently in slow start. When true, the
- // BandwidthEstimate is expected to be too low.
- virtual bool InSlowStart() const = 0;
-
- // Whether the send algorithm is currently in recovery.
- virtual bool InRecovery() const = 0;
-
- // Returns the size of the slow start congestion window in bytes,
- // aka ssthresh. Some send algorithms do not define a slow start
- // threshold and will return 0.
- virtual QuicByteCount GetSlowStartThreshold() const = 0;
-
- virtual CongestionControlType GetCongestionControlType() const = 0;
-
- // Called by the Session when we get a bandwidth estimate from the client.
- // Uses the max bandwidth in the params if |max_bandwidth_resumption| is true.
- virtual void ResumeConnectionState(
- const CachedNetworkParameters& cached_network_params,
- bool max_bandwidth_resumption) = 0;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_INTERFACE_H_
diff --git a/chromium/net/quic/congestion_control/send_algorithm_simulator.cc b/chromium/net/quic/congestion_control/send_algorithm_simulator.cc
deleted file mode 100644
index 46f7db364b6..00000000000
--- a/chromium/net/quic/congestion_control/send_algorithm_simulator.cc
+++ /dev/null
@@ -1,394 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/congestion_control/send_algorithm_simulator.h"
-
-#include <stdint.h>
-
-#include <limits>
-
-#include "base/logging.h"
-#include "base/rand_util.h"
-#include "net/quic/crypto/quic_random.h"
-
-using std::list;
-using std::max;
-using std::min;
-using std::string;
-using std::vector;
-
-namespace net {
-
-namespace {
-
-const QuicByteCount kPacketSize = 1200;
-
-} // namespace
-
-SendAlgorithmSimulator::Sender::Sender(SendAlgorithmInterface* send_algorithm,
- RttStats* rtt_stats)
- : Sender(send_algorithm, rtt_stats, QuicTime::Delta::Zero()) {}
-
-SendAlgorithmSimulator::Sender::Sender(SendAlgorithmInterface* send_algorithm,
- RttStats* rtt_stats,
- QuicTime::Delta additional_rtt)
- : send_algorithm(send_algorithm),
- rtt_stats(rtt_stats),
- additional_rtt(additional_rtt),
- last_sent(0),
- last_acked(0),
- next_acked(1),
- max_cwnd(0),
- min_cwnd(100000),
- max_cwnd_drop(0),
- last_cwnd(0),
- last_transfer_bandwidth(QuicBandwidth::Zero()),
- last_transfer_loss_rate(0) {}
-
-SendAlgorithmSimulator::Transfer::Transfer(Sender* sender,
- QuicByteCount num_bytes,
- QuicTime start_time,
- string name)
- : sender(sender),
- num_bytes(num_bytes),
- bytes_acked(0),
- bytes_lost(0),
- bytes_in_flight(0),
- start_time(start_time),
- name(name) {}
-
-SendAlgorithmSimulator::SendAlgorithmSimulator(MockClock* clock,
- QuicBandwidth bandwidth,
- QuicTime::Delta rtt)
- : clock_(clock),
- lose_next_ack_(false),
- forward_loss_rate_(0),
- reverse_loss_rate_(0),
- loss_correlation_(0),
- bandwidth_(bandwidth),
- rtt_(rtt),
- buffer_size_(1000000),
- delayed_ack_timer_(QuicTime::Delta::FromMilliseconds(100)) {
- uint32_t seed = base::RandInt(0, std::numeric_limits<int32_t>::max());
- DVLOG(1) << "Seeding SendAlgorithmSimulator with " << seed;
- simple_random_.set_seed(seed);
-}
-
-SendAlgorithmSimulator::~SendAlgorithmSimulator() {}
-
-void SendAlgorithmSimulator::AddTransfer(Sender* sender, size_t num_bytes) {
- AddTransfer(sender, num_bytes, clock_->Now(),
- StringPrintf("#%zu", pending_transfers_.size()));
-}
-
-void SendAlgorithmSimulator::AddTransfer(Sender* sender,
- size_t num_bytes,
- QuicTime start_time,
- string name) {
- pending_transfers_.push_back(Transfer(sender, num_bytes, start_time, name));
- // Record initial stats from when the transfer begins.
- pending_transfers_.back().sender->RecordStats();
-}
-
-void SendAlgorithmSimulator::TransferBytes() {
- TransferBytes(std::numeric_limits<uint64_t>::max(),
- QuicTime::Delta::Infinite());
-}
-
-void SendAlgorithmSimulator::TransferBytes(QuicByteCount max_bytes,
- QuicTime::Delta max_time) {
- const QuicTime end_time =
- max_time.IsInfinite() ? QuicTime::Zero().Add(QuicTime::Delta::Infinite())
- : clock_->Now().Add(max_time);
- QuicByteCount bytes_sent = 0;
- while (!pending_transfers_.empty() && clock_->Now() < end_time &&
- bytes_sent < max_bytes) {
- // Determine the times of next send and of the next ack arrival.
- PacketEvent send_event = NextSendEvent();
- PacketEvent ack_event = NextAckEvent();
- // If both times are infinite, fire a TLP.
- if (ack_event.time_delta.IsInfinite() &&
- send_event.time_delta.IsInfinite()) {
- DVLOG(1) << "Both times are infinite, simulating a TLP.";
- // TODO(ianswett): Use a more sophisticated TLP timer or never lose
- // the last ack?
- clock_->AdvanceTime(QuicTime::Delta::FromMilliseconds(100));
- SendDataNow(&pending_transfers_.front());
- } else if (ack_event.time_delta < send_event.time_delta) {
- DVLOG(1) << "Handling ack of largest observed:"
- << ack_event.transfer->sender->next_acked
- << ", advancing time:" << ack_event.time_delta.ToMicroseconds()
- << "us";
- // Ack data all the data up to ack time and lose any missing packet
- // numbers.
- clock_->AdvanceTime(ack_event.time_delta);
- HandlePendingAck(ack_event.transfer);
- } else {
- DVLOG(1) << "Sending transfer '" << send_event.transfer->name
- << "', advancing time:" << send_event.time_delta.ToMicroseconds()
- << "us";
- clock_->AdvanceTime(send_event.time_delta);
- SendDataNow(send_event.transfer);
- bytes_sent += kPacketSize;
- }
- }
-}
-
-SendAlgorithmSimulator::PacketEvent SendAlgorithmSimulator::NextSendEvent() {
- QuicTime::Delta next_send_time = QuicTime::Delta::Infinite();
- Transfer* transfer = nullptr;
- for (vector<Transfer>::iterator it = pending_transfers_.begin();
- it != pending_transfers_.end(); ++it) {
- // If we've already sent enough bytes, wait for them to be acked.
- if (it->bytes_acked + it->bytes_in_flight >= it->num_bytes) {
- continue;
- }
- // If the flow hasn't started, use the start time.
- QuicTime::Delta transfer_send_time = it->start_time.Subtract(clock_->Now());
- if (clock_->Now() >= it->start_time) {
- transfer_send_time = it->sender->send_algorithm->TimeUntilSend(
- clock_->Now(), it->bytes_in_flight);
- }
- if (transfer_send_time < next_send_time) {
- next_send_time = transfer_send_time;
- transfer = &(*it);
- }
- }
- DVLOG(1) << "NextSendTime returning delta(ms):"
- << next_send_time.ToMilliseconds() << ", transfer '"
- << transfer->name;
- return PacketEvent(next_send_time, transfer);
-}
-
-// NextAck takes into account packet loss in both forward and reverse
-// direction, as well as correlated losses. And it assumes the receiver acks
-// every other packet when there is no loss.
-SendAlgorithmSimulator::PacketEvent SendAlgorithmSimulator::NextAckEvent() {
- if (sent_packets_.empty()) {
- DVLOG(1) << "No outstanding packets to ack for any transfer.";
- return PacketEvent(QuicTime::Delta::Infinite(), nullptr);
- }
-
- // For each connection, find the next acked packet.
- QuicTime::Delta ack_time = QuicTime::Delta::Infinite();
- Transfer* transfer = nullptr;
- for (vector<Transfer>::iterator it = pending_transfers_.begin();
- it != pending_transfers_.end(); ++it) {
- QuicTime::Delta transfer_ack_time = FindNextAcked(&(*it));
- if (transfer_ack_time < ack_time) {
- ack_time = transfer_ack_time;
- transfer = &(*it);
- }
- }
-
- return PacketEvent(ack_time, transfer);
-}
-
-QuicTime::Delta SendAlgorithmSimulator::FindNextAcked(Transfer* transfer) {
- Sender* sender = transfer->sender;
- if (sender->next_acked == sender->last_acked) {
- // Determine if the next ack is lost only once, to ensure determinism.
- lose_next_ack_ = reverse_loss_rate_ * std::numeric_limits<uint64_t>::max() >
- simple_random_.RandUint64();
- }
-
- QuicPacketNumber next_acked = sender->last_acked;
- QuicTime::Delta next_ack_delay =
- FindNextAck(transfer, sender->last_acked, &next_acked);
- if (lose_next_ack_) {
- next_ack_delay = FindNextAck(transfer, next_acked, &next_acked);
- }
- sender->next_acked = next_acked;
- return next_ack_delay;
-}
-
-QuicTime::Delta SendAlgorithmSimulator::FindNextAck(
- const Transfer* transfer,
- QuicPacketNumber last_acked,
- QuicPacketNumber* next_acked) const {
- *next_acked = last_acked;
- QuicTime::Delta ack_delay = QuicTime::Delta::Infinite();
- // Remove any packets that are simulated as lost.
- for (list<SentPacket>::const_iterator it = sent_packets_.begin();
- it != sent_packets_.end(); ++it) {
- if (transfer != it->transfer) {
- continue;
- }
- // Skip over any packets less than or equal to last_acked.
- if (it->packet_number <= last_acked) {
- continue;
- }
- // Lost packets don't trigger an ack.
- if (it->lost) {
- continue;
- }
- DCHECK_LT(*next_acked, it->packet_number);
- // Consider a delayed ack for the current next_acked.
- if (ack_delay < it->ack_time.Subtract(clock_->Now())) {
- break;
- }
- *next_acked = it->packet_number;
- ack_delay = it->ack_time.Subtract(clock_->Now());
- if (HasRecentLostPackets(transfer, *next_acked) ||
- (*next_acked - last_acked) >= 2) {
- break;
- }
- ack_delay = ack_delay.Add(delayed_ack_timer_);
- }
-
- DVLOG(1) << "FindNextAck found next_acked_:" << transfer->sender->next_acked
- << " last_acked:" << transfer->sender->last_acked
- << " ack_time(ms):" << ack_delay.ToMilliseconds();
- return ack_delay;
-}
-
-bool SendAlgorithmSimulator::HasRecentLostPackets(
- const Transfer* transfer,
- QuicPacketNumber next_acked) const {
- QuicPacketNumber last_packet = transfer->sender->last_acked;
- for (list<SentPacket>::const_iterator it = sent_packets_.begin();
- it != sent_packets_.end() && it->packet_number < next_acked; ++it) {
- if (transfer != it->transfer) {
- continue;
- }
- // Lost packets don't trigger an ack.
- if (it->lost) {
- return true;
- }
- // Buffer dropped packets are skipped automatically, but still end up
- // being lost and cause acks to be sent immediately.
- if (it->packet_number > last_packet + 1) {
- return true;
- }
- last_packet = it->packet_number;
- }
- return false;
-}
-
-void SendAlgorithmSimulator::HandlePendingAck(Transfer* transfer) {
- Sender* sender = transfer->sender;
- DCHECK_LT(sender->last_acked, sender->next_acked);
- SendAlgorithmInterface::CongestionVector acked_packets;
- SendAlgorithmInterface::CongestionVector lost_packets;
- DVLOG(1) << "Acking packets from:" << sender->last_acked << " to "
- << sender->next_acked
- << " bytes_in_flight:" << transfer->bytes_in_flight
- << " Now():" << (clock_->Now().ToDebuggingValue() / 1000) << "ms";
- // Some entries may be missing from the sent_packets_ array, if they were
- // dropped due to buffer overruns.
- SentPacket largest_observed;
- list<SentPacket>::iterator it = sent_packets_.begin();
- while (sender->last_acked < sender->next_acked) {
- ++sender->last_acked;
- // Find the next SentPacket for this transfer.
- while (it->transfer != transfer) {
- DCHECK(it != sent_packets_.end());
- ++it;
- }
- // If it's missing from the array, it's a loss.
- if (it->packet_number > sender->last_acked) {
- DVLOG(1) << "Lost packet:" << sender->last_acked
- << " dropped by buffer overflow.";
- lost_packets.push_back(std::make_pair(sender->last_acked, kPacketSize));
- continue;
- }
- if (it->lost) {
- lost_packets.push_back(std::make_pair(sender->last_acked, kPacketSize));
- } else {
- acked_packets.push_back(std::make_pair(sender->last_acked, kPacketSize));
- }
- // This packet has been acked or lost, remove it from sent_packets_.
- largest_observed = *it;
- sent_packets_.erase(it++);
- }
-
- DCHECK(!largest_observed.lost);
- DVLOG(1) << "Updating RTT from send_time:"
- << largest_observed.send_time.ToDebuggingValue()
- << " to ack_time:" << largest_observed.ack_time.ToDebuggingValue();
- QuicTime::Delta measured_rtt =
- largest_observed.ack_time.Subtract(largest_observed.send_time);
- DCHECK_GE(measured_rtt.ToMicroseconds(), rtt_.ToMicroseconds());
- sender->rtt_stats->UpdateRtt(measured_rtt, QuicTime::Delta::Zero(),
- clock_->Now());
- sender->send_algorithm->OnCongestionEvent(true, transfer->bytes_in_flight,
- acked_packets, lost_packets);
- DCHECK_LE(kPacketSize * (acked_packets.size() + lost_packets.size()),
- transfer->bytes_in_flight);
- transfer->bytes_in_flight -=
- kPacketSize * (acked_packets.size() + lost_packets.size());
-
- sender->RecordStats();
- transfer->bytes_acked += acked_packets.size() * kPacketSize;
- transfer->bytes_lost += lost_packets.size() * kPacketSize;
- if (transfer->bytes_acked >= transfer->num_bytes) {
- // Remove completed transfers and record transfer bandwidth.
- QuicTime::Delta transfer_time =
- clock_->Now().Subtract(transfer->start_time);
- sender->last_transfer_loss_rate =
- static_cast<float>(transfer->bytes_lost) /
- (transfer->bytes_lost + transfer->bytes_acked);
- sender->last_transfer_bandwidth = QuicBandwidth::FromBytesAndTimeDelta(
- transfer->num_bytes, transfer_time);
- DCHECK_GE(bandwidth_.ToBitsPerSecond(),
- sender->last_transfer_bandwidth.ToBitsPerSecond());
- for (vector<Transfer>::iterator it = pending_transfers_.begin();
- it != pending_transfers_.end(); ++it) {
- if (transfer == &(*it)) {
- pending_transfers_.erase(it);
- break;
- }
- }
- }
-}
-
-void SendAlgorithmSimulator::SendDataNow(Transfer* transfer) {
- Sender* sender = transfer->sender;
- ++sender->last_sent;
- DVLOG(1) << "Sending packet:" << sender->last_sent
- << " name:" << transfer->name
- << " bytes_in_flight:" << transfer->bytes_in_flight
- << " cwnd:" << sender->send_algorithm->GetCongestionWindow()
- << " Now():" << (clock_->Now().ToDebuggingValue() / 1000) << "ms";
- sender->send_algorithm->OnPacketSent(clock_->Now(), transfer->bytes_in_flight,
- sender->last_sent, kPacketSize,
- HAS_RETRANSMITTABLE_DATA);
- // Lose the packet immediately if the buffer is full.
- if (sent_packets_.size() * kPacketSize < buffer_size_) {
- // TODO(ianswett): This buffer simulation is an approximation.
- // An ack time of zero means loss.
- bool packet_lost =
- forward_loss_rate_ * std::numeric_limits<uint64_t>::max() >
- simple_random_.RandUint64();
- // Handle correlated loss.
- if (!sent_packets_.empty() && sent_packets_.back().lost &&
- loss_correlation_ * std::numeric_limits<uint64_t>::max() >
- simple_random_.RandUint64()) {
- packet_lost = true;
- }
- DVLOG(1) << "losing packet:" << sender->last_sent
- << " name:" << transfer->name << " due to random loss.";
-
- // If the number of bytes in flight are less than the bdp, there's
- // no buffering delay. Bytes lost from the buffer are not counted.
- QuicByteCount bdp = bandwidth_.ToBytesPerPeriod(rtt_);
- QuicTime ack_time = clock_->Now().Add(rtt_).Add(sender->additional_rtt);
- if (kPacketSize > bdp) {
- ack_time = ack_time.Add(bandwidth_.TransferTime(kPacketSize - bdp));
- }
- QuicTime queue_ack_time = sent_packets_.empty()
- ? QuicTime::Zero()
- : sent_packets_.back().ack_time.Add(
- bandwidth_.TransferTime(kPacketSize));
- ack_time = QuicTime::Max(ack_time, queue_ack_time);
- sent_packets_.push_back(SentPacket(sender->last_sent, clock_->Now(),
- ack_time, packet_lost, transfer));
- } else {
- DVLOG(1) << "losing packet:" << sender->last_sent
- << " name:" << transfer->name << " because the buffer was full.";
- }
- transfer->bytes_in_flight += kPacketSize;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/send_algorithm_simulator.h b/chromium/net/quic/congestion_control/send_algorithm_simulator.h
deleted file mode 100644
index 7fe0f011466..00000000000
--- a/chromium/net/quic/congestion_control/send_algorithm_simulator.h
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// A test only class to enable simulations of send algorithms.
-
-#ifndef NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_SIMULATOR_H_
-#define NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_SIMULATOR_H_
-
-#include <stddef.h>
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include "base/format_macros.h"
-#include "base/macros.h"
-#include "base/strings/stringprintf.h"
-#include "net/quic/congestion_control/send_algorithm_interface.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-
-using base::StringPrintf;
-
-namespace net {
-
-class SendAlgorithmSimulator {
- public:
- struct Sender {
- Sender(SendAlgorithmInterface* send_algorithm, RttStats* rtt_stats);
- Sender(SendAlgorithmInterface* send_algorithm,
- RttStats* rtt_stats,
- QuicTime::Delta additional_rtt);
-
- void RecordStats() {
- QuicByteCount cwnd = send_algorithm->GetCongestionWindow();
- max_cwnd = std::max(max_cwnd, cwnd);
- min_cwnd = std::min(min_cwnd, cwnd);
- if (last_cwnd > cwnd) {
- max_cwnd_drop = std::max(max_cwnd_drop, last_cwnd - cwnd);
- }
- last_cwnd = cwnd;
- }
-
- std::string DebugString() {
- return StringPrintf("observed goodput(bytes/s):%" PRId64
- " loss rate:%f"
- " cwnd:%" PRIu64 " max_cwnd:%" PRIu64
- " min_cwnd:%" PRIu64 " max_cwnd_drop:%" PRIu64,
- last_transfer_bandwidth.ToBytesPerSecond(),
- last_transfer_loss_rate,
- send_algorithm->GetCongestionWindow(), max_cwnd,
- min_cwnd, max_cwnd_drop);
- }
-
- SendAlgorithmInterface* send_algorithm;
- RttStats* rtt_stats;
- QuicTime::Delta additional_rtt;
-
- // Last packet number the sender sent.
- QuicPacketNumber last_sent;
- // Last packet number acked.
- QuicPacketNumber last_acked;
- // packet number to ack up to.
- QuicPacketNumber next_acked;
-
- // Stats collected for understanding the congestion control.
- QuicByteCount max_cwnd;
- QuicByteCount min_cwnd;
- QuicByteCount max_cwnd_drop;
- QuicByteCount last_cwnd;
-
- QuicBandwidth last_transfer_bandwidth;
- float last_transfer_loss_rate;
- };
-
- struct Transfer {
- Transfer(Sender* sender,
- QuicByteCount num_bytes,
- QuicTime start_time,
- std::string name);
-
- Sender* sender;
- QuicByteCount num_bytes;
- QuicByteCount bytes_acked;
- QuicByteCount bytes_lost;
- QuicByteCount bytes_in_flight;
- QuicTime start_time;
- std::string name;
- };
-
- struct SentPacket {
- SentPacket()
- : packet_number(0),
- send_time(QuicTime::Zero()),
- ack_time(QuicTime::Zero()),
- lost(false),
- transfer(nullptr) {}
- SentPacket(QuicPacketNumber packet_number,
- QuicTime send_time,
- QuicTime ack_time,
- bool lost,
- Transfer* transfer)
- : packet_number(packet_number),
- send_time(send_time),
- ack_time(ack_time),
- lost(lost),
- transfer(transfer) {}
-
- QuicPacketNumber packet_number;
- QuicTime send_time;
- QuicTime ack_time;
- bool lost;
- Transfer* transfer;
- };
-
- // |rtt_stats| should be the same RttStats used by the |send_algorithm|.
- SendAlgorithmSimulator(MockClock* clock_,
- QuicBandwidth bandwidth,
- QuicTime::Delta rtt);
- ~SendAlgorithmSimulator();
-
- // For local ad-hoc testing.
- void set_bandwidth(QuicBandwidth bandwidth) { bandwidth_ = bandwidth; }
-
- void set_forward_loss_rate(float loss_rate) {
- DCHECK_LT(loss_rate, 1.0f);
- forward_loss_rate_ = loss_rate;
- }
-
- // For local ad-hoc testing.
- void set_reverse_loss_rate(float loss_rate) {
- DCHECK_LT(loss_rate, 1.0f);
- reverse_loss_rate_ = loss_rate;
- }
-
- // For local ad-hoc testing.
- void set_loss_correlation(float loss_correlation) {
- DCHECK_LT(loss_correlation, 1.0f);
- loss_correlation_ = loss_correlation;
- }
-
- void set_buffer_size(size_t buffer_size_bytes) {
- buffer_size_ = buffer_size_bytes;
- }
-
- void set_delayed_ack_timer(QuicTime::Delta delayed_ack_timer) {
- delayed_ack_timer_ = delayed_ack_timer;
- }
-
- // Advance the time by |delta| without sending anything.
- // For local ad-hoc testing.
- void AdvanceTime(QuicTime::Delta delta);
-
- // Adds a pending sender. The send will run when TransferBytes is called.
- // Adding two transfers with the same sender is unsupported.
- void AddTransfer(Sender* sender, size_t num_bytes);
-
- // Adds a pending sending to start at the specified time.
- void AddTransfer(Sender* sender,
- size_t num_bytes,
- QuicTime start_time,
- std::string name);
-
- // Convenience method to transfer all bytes.
- void TransferBytes();
-
- // Transfers bytes through the connection until |max_bytes| are reached,
- // |max_time| is reached, or all senders have finished sending. If max_bytes
- // is 0, it does not apply, and if |max_time| is Zero, no time limit applies.
- void TransferBytes(QuicByteCount max_bytes, QuicTime::Delta max_time);
-
- private:
- // A pending packet event, either a send or an ack.
- struct PacketEvent {
- PacketEvent(QuicTime::Delta time_delta, Transfer* transfer)
- : time_delta(time_delta), transfer(transfer) {}
-
- QuicTime::Delta time_delta;
- Transfer* transfer;
- };
-
- // NextSendTime returns the next time any of the pending transfers send,
- // and populates transfer if the send time is not infinite.
- PacketEvent NextSendEvent();
-
- // NextAckTime takes into account packet loss in both forward and reverse
- // direction, as well as delayed ack behavior.
- PacketEvent NextAckEvent();
-
- // Sets the next acked.
- QuicTime::Delta FindNextAcked(Transfer* transfer);
-
- // Sets the |next_acked| packet for the |transfer| starting at the specified
- // |last_acked|. Returns QuicTime::Delta::Infinite and doesn't set
- // |next_acked| if there is no ack after |last_acked|.
- QuicTime::Delta FindNextAck(const Transfer* transfer,
- QuicPacketNumber last_acked,
- QuicPacketNumber* next_acked) const;
-
- // Returns true if any of the packets |transfer| is waiting for less than
- // next_acked have been lost.
- bool HasRecentLostPackets(const Transfer* transfer,
- QuicPacketNumber next_acked) const;
-
- // Process all the acks that should have arrived by the current time, and
- // lose any packets that are missing. Returns the number of bytes acked.
- void HandlePendingAck(Transfer* transfer);
-
- void SendDataNow(Transfer* transfer);
-
- // List of all pending transfers waiting to use the connection.
- std::vector<Transfer> pending_transfers_;
-
- MockClock* clock_;
- // Whether the next ack should be lost.
- bool lose_next_ack_;
- // The times acks are expected, assuming acks are not lost and every packet
- // is acked.
- std::list<SentPacket> sent_packets_;
-
- test::SimpleRandom simple_random_;
- float forward_loss_rate_; // Loss rate on the forward path.
- float reverse_loss_rate_; // Loss rate on the reverse path.
- float loss_correlation_; // Likelihood the subsequent packet is lost.
- QuicBandwidth bandwidth_;
- QuicTime::Delta rtt_;
- size_t buffer_size_; // In bytes.
- QuicTime::Delta delayed_ack_timer_;
-
- DISALLOW_COPY_AND_ASSIGN(SendAlgorithmSimulator);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_SIMULATOR_H_
diff --git a/chromium/net/quic/congestion_control/tcp_cubic_sender_base.cc b/chromium/net/quic/congestion_control/tcp_cubic_sender_base.cc
deleted file mode 100644
index 9ab49e92f03..00000000000
--- a/chromium/net/quic/congestion_control/tcp_cubic_sender_base.cc
+++ /dev/null
@@ -1,288 +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/congestion_control/tcp_cubic_sender_packets.h"
-
-#include <algorithm>
-
-#include "base/metrics/histogram_macros.h"
-#include "net/quic/congestion_control/prr_sender.h"
-#include "net/quic/congestion_control/rtt_stats.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
-
-using std::max;
-using std::min;
-
-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.
-const float kRateBasedExtraCwnd = 1.5f; // CWND for rate based sending.
-} // 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),
- rate_based_sending_(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 (FLAGS_quic_allow_noprr && config.HasReceivedConnectionOptions() &&
- ContainsQuicTag(config.ReceivedConnectionOptions(), kNPRR)) {
- // Use unity pacing instead of PRR.
- no_prr_ = true;
- }
- if (FLAGS_quic_rate_based_sending &&
- config.HasReceivedConnectionOptions() &&
- ContainsQuicTag(config.ReceivedConnectionOptions(), kRATE)) {
- // Rate based sending experiment
- rate_based_sending_ = true;
- }
- }
-}
-
-void TcpCubicSenderBase::ResumeConnectionState(
- const CachedNetworkParameters& cached_network_params,
- bool max_bandwidth_resumption) {
- QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond(
- max_bandwidth_resumption
- ? cached_network_params.max_bandwidth_estimate_bytes_per_second()
- : cached_network_params.bandwidth_estimate_bytes_per_second());
- QuicTime::Delta rtt =
- QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms());
-
- SetCongestionWindowFromBandwidthAndRtt(bandwidth, rtt);
-}
-
-void TcpCubicSenderBase::SetNumEmulatedConnections(int num_connections) {
- num_connections_ = 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 bytes_in_flight,
- const CongestionVector& acked_packets,
- const CongestionVector& lost_packets) {
- if (rtt_updated && InSlowStart() &&
- hybrid_slow_start_.ShouldExitSlowStart(
- rtt_stats_->latest_rtt(), rtt_stats_->min_rtt(),
- GetCongestionWindow() / kDefaultTCPMSS)) {
- ExitSlowstart();
- }
- for (CongestionVector::const_iterator it = lost_packets.begin();
- it != lost_packets.end(); ++it) {
- OnPacketLost(it->first, it->second, bytes_in_flight);
- }
- for (CongestionVector::const_iterator it = acked_packets.begin();
- it != acked_packets.end(); ++it) {
- OnPacketAcked(it->first, it->second, bytes_in_flight);
- }
-}
-
-void TcpCubicSenderBase::OnPacketAcked(QuicPacketNumber acked_packet_number,
- QuicByteCount acked_bytes,
- QuicByteCount bytes_in_flight) {
- largest_acked_packet_number_ =
- 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, bytes_in_flight);
- if (InSlowStart()) {
- hybrid_slow_start_.OnPacketAcked(acked_packet_number);
- }
-}
-
-bool TcpCubicSenderBase::OnPacketSent(
- QuicTime /*sent_time*/,
- QuicByteCount /*bytes_in_flight*/,
- QuicPacketNumber packet_number,
- QuicByteCount bytes,
- HasRetransmittableData is_retransmittable) {
- if (InSlowStart()) {
- ++(stats_->slowstart_packets_sent);
- }
-
- // Only update bytes_in_flight_ for data packets.
- if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) {
- return false;
- }
- 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);
- return true;
-}
-
-QuicTime::Delta TcpCubicSenderBase::TimeUntilSend(
- QuicTime /* now */,
- QuicByteCount bytes_in_flight) const {
- if (!no_prr_ && InRecovery()) {
- // PRR is used when in recovery.
- return prr_.TimeUntilSend(GetCongestionWindow(), bytes_in_flight,
- GetSlowStartThreshold());
- }
- if (GetCongestionWindow() > bytes_in_flight) {
- return QuicTime::Delta::Zero();
- }
- if (min4_mode_ && bytes_in_flight < 4 * kDefaultTCPMSS) {
- return QuicTime::Delta::Zero();
- }
- if (rate_based_sending_ &&
- GetCongestionWindow() * kRateBasedExtraCwnd > bytes_in_flight) {
- return QuicTime::Delta::Zero();
- }
- return QuicTime::Delta::Infinite();
-}
-
-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);
- if (rate_based_sending_ && bytes_in_flight > GetCongestionWindow()) {
- // Rate based sending allows sending more than CWND, but reduces the pacing
- // rate when the bytes in flight is more than the CWND to 75% of bandwidth.
- return bandwidth.Scale(0.75);
- }
- return bandwidth.Scale(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);
-}
-
-QuicTime::Delta TcpCubicSenderBase::RetransmissionDelay() const {
- if (rtt_stats_->smoothed_rtt().IsZero()) {
- return QuicTime::Delta::Zero();
- }
- return rtt_stats_->smoothed_rtt().Add(
- rtt_stats_->mean_deviation().Multiply(4));
-}
-
-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;
-}
-
-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;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/tcp_cubic_sender_base.h b/chromium/net/quic/congestion_control/tcp_cubic_sender_base.h
deleted file mode 100644
index 55ac920f289..00000000000
--- a/chromium/net/quic/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_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BASE_H_
-#define NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BASE_H_
-
-#include <stdint.h>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/quic/congestion_control/cubic.h"
-#include "net/quic/congestion_control/hybrid_slow_start.h"
-#include "net/quic/congestion_control/prr_sender.h"
-#include "net/quic/congestion_control/send_algorithm_interface.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_connection_stats.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class RttStats;
-
-// Maximum window to allow when doing bandwidth resumption.
-const QuicPacketCount kMaxResumptionCongestionWindow = 200;
-
-namespace test {
-class TcpCubicSenderBasePeer;
-} // namespace test
-
-class NET_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 ResumeConnectionState(
- const CachedNetworkParameters& cached_network_params,
- bool max_bandwidth_resumption) override;
- void SetNumEmulatedConnections(int num_connections) override;
- void OnCongestionEvent(bool rtt_updated,
- QuicByteCount bytes_in_flight,
- const CongestionVector& acked_packets,
- const CongestionVector& lost_packets) override;
- bool 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;
- QuicTime::Delta TimeUntilSend(QuicTime now,
- QuicByteCount bytes_in_flight) const override;
- QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const override;
- QuicBandwidth BandwidthEstimate() const override;
- QuicTime::Delta RetransmissionDelay() const override;
- bool InSlowStart() const override;
- bool InRecovery() const 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 bytes_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 bytes_in_flight) = 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 bytes_in_flight);
-
- 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 rate based sending instead of only sending if there's CWND.
- bool rate_based_sending_;
-
- // When true, use unity pacing instead of PRR.
- bool no_prr_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TcpCubicSenderBase);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BASE_H_
diff --git a/chromium/net/quic/congestion_control/tcp_cubic_sender_bytes.cc b/chromium/net/quic/congestion_control/tcp_cubic_sender_bytes.cc
deleted file mode 100644
index 012bf043e11..00000000000
--- a/chromium/net/quic/congestion_control/tcp_cubic_sender_bytes.cc
+++ /dev/null
@@ -1,224 +0,0 @@
-// 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.
-
-#include "net/quic/congestion_control/tcp_cubic_sender_bytes.h"
-
-#include <algorithm>
-
-#include "net/quic/congestion_control/prr_sender.h"
-#include "net/quic/congestion_control/rtt_stats.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
-
-using std::max;
-using std::min;
-
-namespace net {
-
-namespace {
-// Constants based on TCP defaults.
-// The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a
-// fast retransmission.
-const QuicByteCount kDefaultMinimumCongestionWindow = 2 * kDefaultTCPMSS;
-} // namespace
-
-TcpCubicSenderBytes::TcpCubicSenderBytes(
- const QuicClock* clock,
- const RttStats* rtt_stats,
- bool reno,
- QuicPacketCount initial_tcp_congestion_window,
- QuicPacketCount max_congestion_window,
- QuicConnectionStats* stats)
- : TcpCubicSenderBase(clock, rtt_stats, reno, stats),
- cubic_(clock),
- num_acked_packets_(0),
- congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS),
- min_congestion_window_(kDefaultMinimumCongestionWindow),
- max_congestion_window_(max_congestion_window * kDefaultTCPMSS),
- slowstart_threshold_(max_congestion_window * kDefaultTCPMSS),
- initial_tcp_congestion_window_(initial_tcp_congestion_window *
- kDefaultTCPMSS),
- initial_max_tcp_congestion_window_(max_congestion_window *
- kDefaultTCPMSS),
- min_slow_start_exit_window_(min_congestion_window_) {}
-
-TcpCubicSenderBytes::~TcpCubicSenderBytes() {}
-
-void TcpCubicSenderBytes::SetCongestionWindowFromBandwidthAndRtt(
- QuicBandwidth bandwidth,
- QuicTime::Delta rtt) {
- QuicByteCount new_congestion_window = bandwidth.ToBytesPerPeriod(rtt);
- if (FLAGS_quic_no_lower_bw_resumption_limit) {
- // Limit new CWND if needed.
- congestion_window_ =
- max(min_congestion_window_,
- min(new_congestion_window,
- kMaxResumptionCongestionWindow * kDefaultTCPMSS));
- } else {
- congestion_window_ =
- max(min(new_congestion_window,
- kMaxResumptionCongestionWindow * kDefaultTCPMSS),
- kMinCongestionWindowForBandwidthResumption * kDefaultTCPMSS);
- }
-}
-
-void TcpCubicSenderBytes::SetCongestionWindowInPackets(
- QuicPacketCount congestion_window) {
- congestion_window_ = congestion_window * kDefaultTCPMSS;
-}
-
-void TcpCubicSenderBytes::SetMinCongestionWindowInPackets(
- QuicPacketCount congestion_window) {
- min_congestion_window_ = congestion_window * kDefaultTCPMSS;
-}
-
-void TcpCubicSenderBytes::SetNumEmulatedConnections(int num_connections) {
- TcpCubicSenderBase::SetNumEmulatedConnections(num_connections);
- cubic_.SetNumConnections(num_connections_);
-}
-
-void TcpCubicSenderBytes::SetMaxCongestionWindow(
- QuicByteCount max_congestion_window) {
- DCHECK(!FLAGS_quic_ignore_srbf);
- max_congestion_window_ = max_congestion_window;
-}
-
-void TcpCubicSenderBytes::ExitSlowstart() {
- slowstart_threshold_ = congestion_window_;
-}
-
-void TcpCubicSenderBytes::OnPacketLost(QuicPacketNumber packet_number,
- QuicByteCount lost_bytes,
- QuicByteCount bytes_in_flight) {
- // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets
- // already sent should be treated as a single loss event, since it's expected.
- if (packet_number <= largest_sent_at_last_cutback_) {
- if (last_cutback_exited_slowstart_) {
- ++stats_->slowstart_packets_lost;
- stats_->slowstart_bytes_lost += lost_bytes;
- if (slow_start_large_reduction_) {
- // Reduce congestion window by lost_bytes for every loss.
- congestion_window_ =
- max(congestion_window_ - lost_bytes, min_slow_start_exit_window_);
- slowstart_threshold_ = congestion_window_;
- }
- }
- DVLOG(1) << "Ignoring loss for largest_missing:" << packet_number
- << " because it was sent prior to the last CWND cutback.";
- return;
- }
- ++stats_->tcp_loss_events;
- last_cutback_exited_slowstart_ = InSlowStart();
- if (InSlowStart()) {
- ++stats_->slowstart_packets_lost;
- }
-
- if (!no_prr_) {
- prr_.OnPacketLost(bytes_in_flight);
- }
-
- // TODO(jri): Separate out all of slow start into a separate class.
- if (slow_start_large_reduction_ && InSlowStart()) {
- DCHECK_LT(kDefaultTCPMSS, congestion_window_);
- if (FLAGS_quic_sslr_limit_reduction &&
- congestion_window_ >= 2 * initial_tcp_congestion_window_) {
- min_slow_start_exit_window_ = congestion_window_ / 2;
- }
- congestion_window_ = congestion_window_ - kDefaultTCPMSS;
- } else if (reno_) {
- congestion_window_ = congestion_window_ * RenoBeta();
- } else {
- congestion_window_ =
- cubic_.CongestionWindowAfterPacketLoss(congestion_window_);
- }
- if (congestion_window_ < min_congestion_window_) {
- congestion_window_ = min_congestion_window_;
- }
- slowstart_threshold_ = congestion_window_;
- largest_sent_at_last_cutback_ = largest_sent_packet_number_;
- // Reset packet count from congestion avoidance mode. We start counting again
- // when we're out of recovery.
- num_acked_packets_ = 0;
- DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_
- << " slowstart threshold: " << slowstart_threshold_;
-}
-
-QuicByteCount TcpCubicSenderBytes::GetCongestionWindow() const {
- return congestion_window_;
-}
-
-QuicByteCount TcpCubicSenderBytes::GetSlowStartThreshold() const {
- return slowstart_threshold_;
-}
-
-// Called when we receive an ack. Normal TCP tracks how many packets one ack
-// represents, but quic has a separate ack for each packet.
-void TcpCubicSenderBytes::MaybeIncreaseCwnd(
- QuicPacketNumber acked_packet_number,
- QuicByteCount acked_bytes,
- QuicByteCount bytes_in_flight) {
- QUIC_BUG_IF(InRecovery()) << "Never increase the CWND during recovery.";
- // Do not increase the congestion window unless the sender is close to using
- // the current window.
- if (!IsCwndLimited(bytes_in_flight)) {
- cubic_.OnApplicationLimited();
- return;
- }
- if (congestion_window_ >= max_congestion_window_) {
- return;
- }
- if (InSlowStart()) {
- // TCP slow start, exponential growth, increase by one for each ACK.
- congestion_window_ += kDefaultTCPMSS;
- DVLOG(1) << "Slow start; congestion window: " << congestion_window_
- << " slowstart threshold: " << slowstart_threshold_;
- return;
- }
- // Congestion avoidance.
- if (reno_) {
- // Classic Reno congestion avoidance.
- ++num_acked_packets_;
- // Divide by num_connections to smoothly increase the CWND at a faster rate
- // than conventional Reno.
- if (num_acked_packets_ * num_connections_ >=
- congestion_window_ / kDefaultTCPMSS) {
- congestion_window_ += kDefaultTCPMSS;
- num_acked_packets_ = 0;
- }
-
- DVLOG(1) << "Reno; congestion window: " << congestion_window_
- << " slowstart threshold: " << slowstart_threshold_
- << " congestion window count: " << num_acked_packets_;
- } else {
- congestion_window_ =
- min(max_congestion_window_,
- cubic_.CongestionWindowAfterAck(acked_bytes, congestion_window_,
- rtt_stats_->min_rtt()));
- DVLOG(1) << "Cubic; congestion window: " << congestion_window_
- << " slowstart threshold: " << slowstart_threshold_;
- }
-}
-
-void TcpCubicSenderBytes::HandleRetransmissionTimeout() {
- cubic_.Reset();
- slowstart_threshold_ = congestion_window_ / 2;
- congestion_window_ = min_congestion_window_;
-}
-
-void TcpCubicSenderBytes::OnConnectionMigration() {
- TcpCubicSenderBase::OnConnectionMigration();
- cubic_.Reset();
- num_acked_packets_ = 0;
- congestion_window_ = initial_tcp_congestion_window_;
- max_congestion_window_ = initial_max_tcp_congestion_window_;
- slowstart_threshold_ = initial_max_tcp_congestion_window_;
-}
-
-CongestionControlType TcpCubicSenderBytes::GetCongestionControlType() const {
- return reno_ ? kRenoBytes : kCubicBytes;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/tcp_cubic_sender_bytes.h b/chromium/net/quic/congestion_control/tcp_cubic_sender_bytes.h
deleted file mode 100644
index e7a0765a0bd..00000000000
--- a/chromium/net/quic/congestion_control/tcp_cubic_sender_bytes.h
+++ /dev/null
@@ -1,104 +0,0 @@
-// 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.
-
-// TCP cubic send side congestion algorithm, emulates the behavior of TCP cubic.
-
-#ifndef NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BYTES_H_
-#define NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BYTES_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/quic/congestion_control/cubic_bytes.h"
-#include "net/quic/congestion_control/hybrid_slow_start.h"
-#include "net/quic/congestion_control/prr_sender.h"
-#include "net/quic/congestion_control/tcp_cubic_sender_base.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_connection_stats.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class RttStats;
-
-namespace test {
-class TcpCubicSenderBytesPeer;
-} // namespace test
-
-class NET_EXPORT_PRIVATE TcpCubicSenderBytes : public TcpCubicSenderBase {
- public:
- TcpCubicSenderBytes(const QuicClock* clock,
- const RttStats* rtt_stats,
- bool reno,
- QuicPacketCount initial_tcp_congestion_window,
- QuicPacketCount max_congestion_window,
- QuicConnectionStats* stats);
- ~TcpCubicSenderBytes() override;
-
- // Start implementation of SendAlgorithmInterface.
- void SetNumEmulatedConnections(int num_connections) override;
- void SetMaxCongestionWindow(QuicByteCount max_congestion_window) override;
- void OnConnectionMigration() override;
- QuicByteCount GetCongestionWindow() const override;
- QuicByteCount GetSlowStartThreshold() const override;
- CongestionControlType GetCongestionControlType() const override;
- // End implementation of SendAlgorithmInterface.
-
- QuicByteCount min_congestion_window() const { return min_congestion_window_; }
-
- protected:
- // TcpCubicSenderBase methods
- void SetCongestionWindowFromBandwidthAndRtt(QuicBandwidth bandwidth,
- QuicTime::Delta rtt) override;
- void SetCongestionWindowInPackets(QuicPacketCount congestion_window) override;
- void SetMinCongestionWindowInPackets(
- QuicPacketCount congestion_window) override;
- void ExitSlowstart() override;
- void OnPacketLost(QuicPacketNumber largest_loss,
- QuicByteCount lost_bytes,
- QuicByteCount bytes_in_flight) override;
- void MaybeIncreaseCwnd(QuicPacketNumber acked_packet_number,
- QuicByteCount acked_bytes,
- QuicByteCount bytes_in_flight) override;
- void HandleRetransmissionTimeout() override;
-
- private:
- friend class test::TcpCubicSenderBytesPeer;
-
- CubicBytes cubic_;
-
- // ACK counter for the Reno implementation.
- uint64_t num_acked_packets_;
-
- // Congestion window in bytes.
- QuicByteCount congestion_window_;
-
- // Minimum congestion window in bytes.
- QuicByteCount min_congestion_window_;
-
- // Maximum congestion window in bytes.
- QuicByteCount max_congestion_window_;
-
- // Slow start congestion window in bytes, aka ssthresh.
- QuicByteCount slowstart_threshold_;
-
- // Initial TCP congestion window in bytes. This variable can only be set when
- // this algorithm is created.
- const QuicByteCount initial_tcp_congestion_window_;
-
- // Initial maximum TCP congestion window in bytes. This variable can only be
- // set when this algorithm is created.
- const QuicByteCount initial_max_tcp_congestion_window_;
-
- // The minimum window when exiting slow start with large reduction.
- QuicByteCount min_slow_start_exit_window_;
-
- DISALLOW_COPY_AND_ASSIGN(TcpCubicSenderBytes);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_BYTES_SENDER_H_
diff --git a/chromium/net/quic/congestion_control/tcp_cubic_sender_bytes_test.cc b/chromium/net/quic/congestion_control/tcp_cubic_sender_bytes_test.cc
deleted file mode 100644
index 9c33e1d4671..00000000000
--- a/chromium/net/quic/congestion_control/tcp_cubic_sender_bytes_test.cc
+++ /dev/null
@@ -1,898 +0,0 @@
-// 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.
-
-#include "net/quic/congestion_control/tcp_cubic_sender_bytes.h"
-
-#include <algorithm>
-#include <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-#include "net/quic/congestion_control/rtt_stats.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/test_tools/quic_config_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-// TODO(ianswett): A number of theses tests were written with the assumption of
-// an initial CWND of 10. They have carefully calculated values which should be
-// updated to be based on kInitialCongestionWindow.
-const uint32_t kInitialCongestionWindowPackets = 10;
-const uint32_t kMaxCongestionWindowPackets = 200;
-const uint32_t kDefaultWindowTCP =
- kInitialCongestionWindowPackets * kDefaultTCPMSS;
-const float kRenoBeta = 0.7f; // Reno backoff factor.
-
-class TcpCubicSenderBytesPeer : public TcpCubicSenderBytes {
- public:
- TcpCubicSenderBytesPeer(const QuicClock* clock, bool reno)
- : TcpCubicSenderBytes(clock,
- &rtt_stats_,
- reno,
- kInitialCongestionWindowPackets,
- kMaxCongestionWindowPackets,
- &stats_) {}
-
- const HybridSlowStart& hybrid_slow_start() const {
- return hybrid_slow_start_;
- }
-
- float GetRenoBeta() const { return RenoBeta(); }
-
- RttStats rtt_stats_;
- QuicConnectionStats stats_;
-};
-
-class TcpCubicSenderBytesTest : public ::testing::Test {
- protected:
- TcpCubicSenderBytesTest()
- : one_ms_(QuicTime::Delta::FromMilliseconds(1)),
- sender_(new TcpCubicSenderBytesPeer(&clock_, true)),
- packet_number_(1),
- acked_packet_number_(0),
- bytes_in_flight_(0) {}
-
- int SendAvailableSendWindow() {
- return SendAvailableSendWindow(kDefaultTCPMSS);
- }
-
- int SendAvailableSendWindow(QuicPacketLength packet_length) {
- // Send as long as TimeUntilSend returns Zero.
- int packets_sent = 0;
- bool can_send =
- sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_).IsZero();
- while (can_send) {
- sender_->OnPacketSent(clock_.Now(), bytes_in_flight_, packet_number_++,
- kDefaultTCPMSS, HAS_RETRANSMITTABLE_DATA);
- ++packets_sent;
- bytes_in_flight_ += kDefaultTCPMSS;
- can_send =
- sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_).IsZero();
- }
- return packets_sent;
- }
-
- // Normal is that TCP acks every other segment.
- void AckNPackets(int n) {
- sender_->rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(60),
- QuicTime::Delta::Zero(), clock_.Now());
- SendAlgorithmInterface::CongestionVector acked_packets;
- SendAlgorithmInterface::CongestionVector lost_packets;
- for (int i = 0; i < n; ++i) {
- ++acked_packet_number_;
- acked_packets.push_back(
- std::make_pair(acked_packet_number_, kDefaultTCPMSS));
- }
- sender_->OnCongestionEvent(true, bytes_in_flight_, acked_packets,
- lost_packets);
- bytes_in_flight_ -= n * kDefaultTCPMSS;
- clock_.AdvanceTime(one_ms_);
- }
-
- void LoseNPackets(int n) { LoseNPackets(n, kDefaultTCPMSS); }
-
- void LoseNPackets(int n, QuicPacketLength packet_length) {
- SendAlgorithmInterface::CongestionVector acked_packets;
- SendAlgorithmInterface::CongestionVector lost_packets;
- for (int i = 0; i < n; ++i) {
- ++acked_packet_number_;
- lost_packets.push_back(
- std::make_pair(acked_packet_number_, packet_length));
- }
- sender_->OnCongestionEvent(false, bytes_in_flight_, acked_packets,
- lost_packets);
- bytes_in_flight_ -= n * packet_length;
- }
-
- // Does not increment acked_packet_number_.
- void LosePacket(QuicPacketNumber packet_number) {
- SendAlgorithmInterface::CongestionVector acked_packets;
- SendAlgorithmInterface::CongestionVector lost_packets;
- lost_packets.push_back(std::make_pair(packet_number, kDefaultTCPMSS));
- sender_->OnCongestionEvent(false, bytes_in_flight_, acked_packets,
- lost_packets);
- bytes_in_flight_ -= kDefaultTCPMSS;
- }
-
- const QuicTime::Delta one_ms_;
- MockClock clock_;
- std::unique_ptr<TcpCubicSenderBytesPeer> sender_;
- QuicPacketNumber packet_number_;
- QuicPacketNumber acked_packet_number_;
- QuicByteCount bytes_in_flight_;
-};
-
-TEST_F(TcpCubicSenderBytesTest, SimpleSender) {
- // At startup make sure we are at the default.
- EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
- // At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
- // Make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
- // And that window is un-affected.
- EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
-
- // Fill the send window with data, then verify that we can't send.
- SendAvailableSendWindow();
- EXPECT_FALSE(
- sender_->TimeUntilSend(clock_.Now(), sender_->GetCongestionWindow())
- .IsZero());
-}
-
-TEST_F(TcpCubicSenderBytesTest, ApplicationLimitedSlowStart) {
- // Send exactly 10 packets and ensure the CWND ends at 14 packets.
- const int kNumberOfAcks = 5;
- // At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
- // Make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
-
- SendAvailableSendWindow();
- for (int i = 0; i < kNumberOfAcks; ++i) {
- AckNPackets(2);
- }
- QuicByteCount bytes_to_send = sender_->GetCongestionWindow();
- // It's expected 2 acks will arrive when the bytes_in_flight are greater than
- // half the CWND.
- EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * 2, bytes_to_send);
-}
-
-TEST_F(TcpCubicSenderBytesTest, ExponentialSlowStart) {
- const int kNumberOfAcks = 20;
- // At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
- EXPECT_EQ(QuicBandwidth::Zero(), sender_->BandwidthEstimate());
- // Make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
-
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- const QuicByteCount cwnd = sender_->GetCongestionWindow();
- EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * kNumberOfAcks, cwnd);
- EXPECT_EQ(QuicBandwidth::FromBytesAndTimeDelta(
- cwnd, sender_->rtt_stats_.smoothed_rtt()),
- sender_->BandwidthEstimate());
-}
-
-TEST_F(TcpCubicSenderBytesTest, SlowStartPacketLoss) {
- sender_->SetNumEmulatedConnections(1);
- const int kNumberOfAcks = 10;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose a packet to exit slow start.
- LoseNPackets(1);
- size_t packets_in_recovery_window = expected_send_window / kDefaultTCPMSS;
-
- // We should now have fallen out of slow start with a reduced window.
- expected_send_window *= kRenoBeta;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Recovery phase. We need to ack every packet in the recovery window before
- // we exit recovery.
- size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
- DVLOG(1) << "number_packets: " << number_of_packets_in_window;
- AckNPackets(packets_in_recovery_window);
- SendAvailableSendWindow();
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // We need to ack an entire window before we increase CWND by 1.
- AckNPackets(number_of_packets_in_window - 2);
- SendAvailableSendWindow();
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Next ack should increase cwnd by 1.
- AckNPackets(1);
- expected_send_window += kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Now RTO and ensure slow start gets reset.
- EXPECT_TRUE(sender_->hybrid_slow_start().started());
- sender_->OnRetransmissionTimeout(true);
- EXPECT_FALSE(sender_->hybrid_slow_start().started());
-}
-
-TEST_F(TcpCubicSenderBytesTest, SlowStartPacketLossWithLargeReduction) {
- FLAGS_quic_sslr_limit_reduction = true;
- QuicConfig config;
- QuicTagVector options;
- options.push_back(kSSLR);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
-
- sender_->SetNumEmulatedConnections(1);
- const int kNumberOfAcks = (kDefaultWindowTCP / (2 * kDefaultTCPMSS)) - 1;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose a packet to exit slow start. We should now have fallen out of
- // slow start with a window reduced by 1.
- LoseNPackets(1);
- expected_send_window -= kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose 5 packets in recovery and verify that congestion window is reduced
- // further.
- LoseNPackets(5);
- expected_send_window -= 5 * kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- // Lose another 10 packets and ensure it reduces below half the peak CWND,
- // because we never acked the full IW.
- LoseNPackets(10);
- expected_send_window -= 10 * kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- size_t packets_in_recovery_window = expected_send_window / kDefaultTCPMSS;
-
- // Recovery phase. We need to ack every packet in the recovery window before
- // we exit recovery.
- size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
- DVLOG(1) << "number_packets: " << number_of_packets_in_window;
- AckNPackets(packets_in_recovery_window);
- SendAvailableSendWindow();
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // We need to ack an entire window before we increase CWND by 1.
- AckNPackets(number_of_packets_in_window - 1);
- SendAvailableSendWindow();
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Next ack should increase cwnd by 1.
- AckNPackets(1);
- expected_send_window += kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Now RTO and ensure slow start gets reset.
- EXPECT_TRUE(sender_->hybrid_slow_start().started());
- sender_->OnRetransmissionTimeout(true);
- EXPECT_FALSE(sender_->hybrid_slow_start().started());
-}
-
-TEST_F(TcpCubicSenderBytesTest, SlowStartHalfPacketLossWithLargeReduction) {
- QuicConfig config;
- QuicTagVector options;
- options.push_back(kSSLR);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
-
- sender_->SetNumEmulatedConnections(1);
- const int kNumberOfAcks = 10;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window in half sized packets.
- SendAvailableSendWindow(kDefaultTCPMSS / 2);
- AckNPackets(2);
- }
- SendAvailableSendWindow(kDefaultTCPMSS / 2);
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose a packet to exit slow start. We should now have fallen out of
- // slow start with a window reduced by 1.
- LoseNPackets(1);
- expected_send_window -= kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose 10 packets in recovery and verify that congestion window is reduced
- // by 5 packets.
- LoseNPackets(10, kDefaultTCPMSS / 2);
- expected_send_window -= 5 * kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderBytesTest, SlowStartPacketLossWithMaxHalfReduction) {
- FLAGS_quic_sslr_limit_reduction = true;
- QuicConfig config;
- QuicTagVector options;
- options.push_back(kSSLR);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
-
- sender_->SetNumEmulatedConnections(1);
- const int kNumberOfAcks = kInitialCongestionWindowPackets / 2;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose a packet to exit slow start. We should now have fallen out of
- // slow start with a window reduced by 1.
- LoseNPackets(1);
- expected_send_window -= kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose half the outstanding packets in recovery and verify the congestion
- // window is only reduced by a max of half.
- LoseNPackets(kNumberOfAcks * 2);
- expected_send_window -= (kNumberOfAcks * 2 - 1) * kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- LoseNPackets(5);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderBytesTest, NoPRRWhenLessThanOnePacketInFlight) {
- SendAvailableSendWindow();
- LoseNPackets(kInitialCongestionWindowPackets - 1);
- AckNPackets(1);
- // PRR will allow 2 packets for every ack during recovery.
- EXPECT_EQ(2, SendAvailableSendWindow());
- // Simulate abandoning all packets by supplying a bytes_in_flight of 0.
- // PRR should now allow a packet to be sent, even though prr's state variables
- // believe it has sent enough packets.
- EXPECT_EQ(QuicTime::Delta::Zero(), sender_->TimeUntilSend(clock_.Now(), 0));
-}
-
-TEST_F(TcpCubicSenderBytesTest, SlowStartPacketLossPRR) {
- sender_->SetNumEmulatedConnections(1);
- // Test based on the first example in RFC6937.
- // Ack 10 packets in 5 acks to raise the CWND to 20, as in the example.
- const int kNumberOfAcks = 5;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- LoseNPackets(1);
-
- // We should now have fallen out of slow start with a reduced window.
- size_t send_window_before_loss = expected_send_window;
- expected_send_window *= kRenoBeta;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Testing TCP proportional rate reduction.
- // We should send packets paced over the received acks for the remaining
- // outstanding packets. The number of packets before we exit recovery is the
- // original CWND minus the packet that has been lost and the one which
- // triggered the loss.
- size_t remaining_packets_in_recovery =
- send_window_before_loss / kDefaultTCPMSS - 2;
-
- for (size_t i = 0; i < remaining_packets_in_recovery; ++i) {
- AckNPackets(1);
- SendAvailableSendWindow();
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- }
-
- // We need to ack another window before we increase CWND by 1.
- size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
- for (size_t i = 0; i < number_of_packets_in_window; ++i) {
- AckNPackets(1);
- EXPECT_EQ(1, SendAvailableSendWindow());
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- }
-
- AckNPackets(1);
- expected_send_window += kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderBytesTest, SlowStartBurstPacketLossPRR) {
- sender_->SetNumEmulatedConnections(1);
- // Test based on the second example in RFC6937, though we also implement
- // forward acknowledgements, so the first two incoming acks will trigger
- // PRR immediately.
- // Ack 20 packets in 10 acks to raise the CWND to 30.
- const int kNumberOfAcks = 10;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose one more than the congestion window reduction, so that after loss,
- // bytes_in_flight is lesser than the congestion window.
- size_t send_window_after_loss = kRenoBeta * expected_send_window;
- size_t num_packets_to_lose =
- (expected_send_window - send_window_after_loss) / kDefaultTCPMSS + 1;
- LoseNPackets(num_packets_to_lose);
- // Immediately after the loss, ensure at least one packet can be sent.
- // Losses without subsequent acks can occur with timer based loss detection.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_).IsZero());
- AckNPackets(1);
-
- // We should now have fallen out of slow start with a reduced window.
- expected_send_window *= kRenoBeta;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Only 2 packets should be allowed to be sent, per PRR-SSRB.
- EXPECT_EQ(2, SendAvailableSendWindow());
-
- // Ack the next packet, which triggers another loss.
- LoseNPackets(1);
- AckNPackets(1);
-
- // Send 2 packets to simulate PRR-SSRB.
- EXPECT_EQ(2, SendAvailableSendWindow());
-
- // Ack the next packet, which triggers another loss.
- LoseNPackets(1);
- AckNPackets(1);
-
- // Send 2 packets to simulate PRR-SSRB.
- EXPECT_EQ(2, SendAvailableSendWindow());
-
- // Exit recovery and return to sending at the new rate.
- for (int i = 0; i < kNumberOfAcks; ++i) {
- AckNPackets(1);
- EXPECT_EQ(1, SendAvailableSendWindow());
- }
-}
-
-TEST_F(TcpCubicSenderBytesTest, RTOCongestionWindow) {
- EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
- // Expect the window to decrease to the minimum once the RTO fires and slow
- // start threshold to be set to 1/2 of the CWND.
- sender_->OnRetransmissionTimeout(true);
- EXPECT_EQ(2 * kDefaultTCPMSS, sender_->GetCongestionWindow());
- EXPECT_EQ(5u * kDefaultTCPMSS, sender_->GetSlowStartThreshold());
-}
-
-TEST_F(TcpCubicSenderBytesTest, RTOCongestionWindowNoRetransmission) {
- EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
-
- // Expect the window to remain unchanged if the RTO fires but no packets are
- // retransmitted.
- sender_->OnRetransmissionTimeout(false);
- EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderBytesTest, RetransmissionDelay) {
- const int64_t kRttMs = 10;
- const int64_t kDeviationMs = 3;
- EXPECT_EQ(QuicTime::Delta::Zero(), sender_->RetransmissionDelay());
-
- sender_->rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(kRttMs),
- QuicTime::Delta::Zero(), clock_.Now());
-
- // Initial value is to set the median deviation to half of the initial rtt,
- // the median in then multiplied by a factor of 4 and finally the smoothed rtt
- // is added which is the initial rtt.
- QuicTime::Delta expected_delay =
- QuicTime::Delta::FromMilliseconds(kRttMs + kRttMs / 2 * 4);
- EXPECT_EQ(expected_delay, sender_->RetransmissionDelay());
-
- for (int i = 0; i < 100; ++i) {
- // Run to make sure that we converge.
- sender_->rtt_stats_.UpdateRtt(
- QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs),
- QuicTime::Delta::Zero(), clock_.Now());
- sender_->rtt_stats_.UpdateRtt(
- QuicTime::Delta::FromMilliseconds(kRttMs - kDeviationMs),
- QuicTime::Delta::Zero(), clock_.Now());
- }
- expected_delay = QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs * 4);
-
- EXPECT_NEAR(kRttMs, sender_->rtt_stats_.smoothed_rtt().ToMilliseconds(), 1);
- EXPECT_NEAR(expected_delay.ToMilliseconds(),
- sender_->RetransmissionDelay().ToMilliseconds(), 1);
- EXPECT_EQ(static_cast<int64_t>(
- sender_->GetCongestionWindow() * kNumMicrosPerSecond /
- sender_->rtt_stats_.smoothed_rtt().ToMicroseconds()),
- sender_->BandwidthEstimate().ToBytesPerSecond());
-}
-
-TEST_F(TcpCubicSenderBytesTest, TcpCubicResetEpochOnQuiescence) {
- const int kMaxCongestionWindow = 50;
- const QuicByteCount kMaxCongestionWindowBytes =
- kMaxCongestionWindow * kDefaultTCPMSS;
- int num_sent = SendAvailableSendWindow();
-
- // Make sure we fall out of slow start.
- QuicByteCount saved_cwnd = sender_->GetCongestionWindow();
- LoseNPackets(1);
- EXPECT_GT(saved_cwnd, sender_->GetCongestionWindow());
-
- // Ack the rest of the outstanding packets to get out of recovery.
- for (int i = 1; i < num_sent; ++i) {
- AckNPackets(1);
- }
- EXPECT_EQ(0u, bytes_in_flight_);
-
- // Send a new window of data and ack all; cubic growth should occur.
- saved_cwnd = sender_->GetCongestionWindow();
- num_sent = SendAvailableSendWindow();
- for (int i = 0; i < num_sent; ++i) {
- AckNPackets(1);
- }
- EXPECT_LT(saved_cwnd, sender_->GetCongestionWindow());
- EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow());
- EXPECT_EQ(0u, bytes_in_flight_);
-
- // Quiescent time of 100 seconds
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100000));
-
- // Send new window of data and ack one packet. Cubic epoch should have
- // been reset; ensure cwnd increase is not dramatic.
- saved_cwnd = sender_->GetCongestionWindow();
- SendAvailableSendWindow();
- AckNPackets(1);
- EXPECT_NEAR(saved_cwnd, sender_->GetCongestionWindow(), kDefaultTCPMSS);
- EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderBytesTest, MultipleLossesInOneWindow) {
- SendAvailableSendWindow();
- const QuicByteCount initial_window = sender_->GetCongestionWindow();
- LosePacket(acked_packet_number_ + 1);
- const QuicByteCount post_loss_window = sender_->GetCongestionWindow();
- EXPECT_GT(initial_window, post_loss_window);
- LosePacket(acked_packet_number_ + 3);
- EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow());
- LosePacket(packet_number_ - 1);
- EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow());
-
- // Lose a later packet and ensure the window decreases.
- LosePacket(packet_number_);
- EXPECT_GT(post_loss_window, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderBytesTest, DontTrackAckPackets) {
- // Send a packet with no retransmittable data, and ensure it's not tracked.
- EXPECT_FALSE(sender_->OnPacketSent(clock_.Now(), bytes_in_flight_,
- packet_number_++, kDefaultTCPMSS,
- NO_RETRANSMITTABLE_DATA));
-
- // Send a data packet with retransmittable data, and ensure it is tracked.
- EXPECT_TRUE(sender_->OnPacketSent(clock_.Now(), bytes_in_flight_,
- packet_number_++, kDefaultTCPMSS,
- HAS_RETRANSMITTABLE_DATA));
-}
-
-TEST_F(TcpCubicSenderBytesTest, ConfigureMaxInitialWindow) {
- QuicConfig config;
-
- // Verify that kCOPT: kIW10 forces the congestion window to the default of 10.
- QuicTagVector options;
- options.push_back(kIW10);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
- EXPECT_EQ(10u * kDefaultTCPMSS, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderBytesTest, 2ConnectionCongestionAvoidanceAtEndOfRecovery) {
- sender_->SetNumEmulatedConnections(2);
- // Ack 10 packets in 5 acks to raise the CWND to 20.
- const int kNumberOfAcks = 5;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- LoseNPackets(1);
-
- // We should now have fallen out of slow start with a reduced window.
- expected_send_window = expected_send_window * sender_->GetRenoBeta();
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // No congestion window growth should occur in recovery phase, i.e., until the
- // currently outstanding 20 packets are acked.
- for (int i = 0; i < 10; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- EXPECT_TRUE(sender_->InRecovery());
- AckNPackets(2);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- }
- EXPECT_FALSE(sender_->InRecovery());
-
- // Out of recovery now. Congestion window should not grow for half an RTT.
- size_t packets_in_send_window = expected_send_window / kDefaultTCPMSS;
- SendAvailableSendWindow();
- AckNPackets(packets_in_send_window / 2 - 2);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Next ack should increase congestion window by 1MSS.
- SendAvailableSendWindow();
- AckNPackets(2);
- expected_send_window += kDefaultTCPMSS;
- packets_in_send_window += 1;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Congestion window should remain steady again for half an RTT.
- SendAvailableSendWindow();
- AckNPackets(packets_in_send_window / 2 - 1);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Next ack should cause congestion window to grow by 1MSS.
- SendAvailableSendWindow();
- AckNPackets(2);
- expected_send_window += kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderBytesTest, 1ConnectionCongestionAvoidanceAtEndOfRecovery) {
- sender_->SetNumEmulatedConnections(1);
- // Ack 10 packets in 5 acks to raise the CWND to 20.
- const int kNumberOfAcks = 5;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- LoseNPackets(1);
-
- // We should now have fallen out of slow start with a reduced window.
- expected_send_window *= kRenoBeta;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // No congestion window growth should occur in recovery phase, i.e., until the
- // currently outstanding 20 packets are acked.
- for (int i = 0; i < 10; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- EXPECT_TRUE(sender_->InRecovery());
- AckNPackets(2);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- }
- EXPECT_FALSE(sender_->InRecovery());
-
- // Out of recovery now. Congestion window should not grow during RTT.
- for (uint64_t i = 0; i < expected_send_window / kDefaultTCPMSS - 2; i += 2) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- }
-
- // Next ack should cause congestion window to grow by 1MSS.
- SendAvailableSendWindow();
- AckNPackets(2);
- expected_send_window += kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderBytesTest, BandwidthResumption) {
- // Test that when provided with CachedNetworkParameters and opted in to the
- // bandwidth resumption experiment, that the TcpCubicSender sets initial CWND
- // appropriately.
-
- // Set some common values.
- CachedNetworkParameters cached_network_params;
- const QuicPacketCount kNumberOfPackets = 123;
- const int kBandwidthEstimateBytesPerSecond =
- kNumberOfPackets * kDefaultTCPMSS;
- cached_network_params.set_bandwidth_estimate_bytes_per_second(
- kBandwidthEstimateBytesPerSecond);
- cached_network_params.set_min_rtt_ms(1000);
-
- // Make sure that a bandwidth estimate results in a changed CWND.
- cached_network_params.set_timestamp(clock_.WallNow().ToUNIXSeconds() -
- (kNumSecondsPerHour - 1));
- sender_->ResumeConnectionState(cached_network_params, false);
- EXPECT_EQ(kNumberOfPackets * kDefaultTCPMSS, sender_->GetCongestionWindow());
-
- // Resumed CWND is limited to be in a sensible range.
- cached_network_params.set_bandwidth_estimate_bytes_per_second(
- (kMaxCongestionWindowPackets + 1) * kDefaultTCPMSS);
- sender_->ResumeConnectionState(cached_network_params, false);
- EXPECT_EQ(kMaxCongestionWindowPackets * kDefaultTCPMSS,
- sender_->GetCongestionWindow());
-
- if (FLAGS_quic_no_lower_bw_resumption_limit) {
- // Resume with an illegal value of 0 and verify the server uses 1 instead.
- cached_network_params.set_bandwidth_estimate_bytes_per_second(0);
- sender_->ResumeConnectionState(cached_network_params, false);
- EXPECT_EQ(sender_->min_congestion_window(), sender_->GetCongestionWindow());
- } else {
- cached_network_params.set_bandwidth_estimate_bytes_per_second(
- (kMinCongestionWindowForBandwidthResumption - 1) * kDefaultTCPMSS);
- sender_->ResumeConnectionState(cached_network_params, false);
- EXPECT_EQ(kMinCongestionWindowForBandwidthResumption * kDefaultTCPMSS,
- sender_->GetCongestionWindow());
- }
-
- // Resume to the max value.
- cached_network_params.set_max_bandwidth_estimate_bytes_per_second(
- kMaxCongestionWindowPackets * kDefaultTCPMSS);
- sender_->ResumeConnectionState(cached_network_params, true);
- EXPECT_EQ(kMaxCongestionWindowPackets * kDefaultTCPMSS,
- sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderBytesTest, PaceBelowCWND) {
- QuicConfig config;
-
- // Verify that kCOPT: kMIN4 forces the min CWND to 1 packet, but allows up
- // to 4 to be sent.
- QuicTagVector options;
- options.push_back(kMIN4);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
- sender_->OnRetransmissionTimeout(true);
- EXPECT_EQ(kDefaultTCPMSS, sender_->GetCongestionWindow());
- EXPECT_TRUE(
- sender_->TimeUntilSend(QuicTime::Zero(), kDefaultTCPMSS).IsZero());
- EXPECT_TRUE(
- sender_->TimeUntilSend(QuicTime::Zero(), 2 * kDefaultTCPMSS).IsZero());
- EXPECT_TRUE(
- sender_->TimeUntilSend(QuicTime::Zero(), 3 * kDefaultTCPMSS).IsZero());
- EXPECT_FALSE(
- sender_->TimeUntilSend(QuicTime::Zero(), 4 * kDefaultTCPMSS).IsZero());
-}
-
-TEST_F(TcpCubicSenderBytesTest, NoPRR) {
- ValueRestore<bool> old_flag(&FLAGS_quic_allow_noprr, true);
- QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(100);
- sender_->rtt_stats_.UpdateRtt(rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
-
- sender_->SetNumEmulatedConnections(1);
- // Verify that kCOPT: kNPRR allows all packets to be sent, even if only one
- // ack has been received.
- QuicTagVector options;
- options.push_back(kNPRR);
- QuicConfig config;
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
- SendAvailableSendWindow();
- LoseNPackets(9);
- AckNPackets(1);
-
- // We should now have fallen out of slow start with a reduced window.
- EXPECT_EQ(kRenoBeta * kDefaultWindowTCP, sender_->GetCongestionWindow());
- const QuicPacketCount window_in_packets =
- kRenoBeta * kDefaultWindowTCP / kDefaultTCPMSS;
- const QuicBandwidth expected_pacing_rate =
- QuicBandwidth::FromBytesAndTimeDelta(kRenoBeta * kDefaultWindowTCP,
- sender_->rtt_stats_.smoothed_rtt());
- EXPECT_EQ(expected_pacing_rate, sender_->PacingRate(0));
- EXPECT_EQ(window_in_packets,
- static_cast<uint64_t>(SendAvailableSendWindow()));
- EXPECT_EQ(expected_pacing_rate,
- sender_->PacingRate(kRenoBeta * kDefaultWindowTCP));
-}
-
-TEST_F(TcpCubicSenderBytesTest, PaceSlowerAboveCwnd) {
- ValueRestore<bool> old_flag(&FLAGS_quic_rate_based_sending, true);
- QuicTime::Delta rtt(QuicTime::Delta::FromMilliseconds(60));
- sender_->rtt_stats_.UpdateRtt(rtt, QuicTime::Delta::Zero(), clock_.Now());
-
- QuicConfig config;
- QuicTagVector options;
- options.push_back(kRATE);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
- EXPECT_EQ(10 * kDefaultTCPMSS, sender_->GetCongestionWindow());
- sender_->SetNumEmulatedConnections(1);
- // Lose a packet to exit slow start.
- LoseNPackets(1);
- const QuicPacketCount cwnd = 7;
- EXPECT_EQ(cwnd * kDefaultTCPMSS, sender_->GetCongestionWindow());
-
- EXPECT_TRUE(
- sender_->TimeUntilSend(QuicTime::Zero(), kDefaultTCPMSS).IsZero());
- EXPECT_EQ(sender_->PacingRate(kDefaultTCPMSS),
- QuicBandwidth::FromBytesAndTimeDelta(7 * kDefaultTCPMSS, rtt)
- .Scale(1.25));
- for (QuicPacketCount i = cwnd + 1; i < 1.5 * cwnd; ++i) {
- EXPECT_TRUE(
- sender_->TimeUntilSend(QuicTime::Zero(), i * kDefaultTCPMSS).IsZero());
- EXPECT_EQ(sender_->PacingRate(i * kDefaultTCPMSS),
- QuicBandwidth::FromBytesAndTimeDelta(cwnd * kDefaultTCPMSS, rtt)
- .Scale(0.75));
- }
- EXPECT_FALSE(
- sender_->TimeUntilSend(QuicTime::Zero(), 11 * kDefaultTCPMSS).IsZero());
-}
-
-TEST_F(TcpCubicSenderBytesTest, ResetAfterConnectionMigration) {
- // Starts from slow start.
- sender_->SetNumEmulatedConnections(1);
- const int kNumberOfAcks = 10;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Loses a packet to exit slow start.
- LoseNPackets(1);
-
- // We should now have fallen out of slow start with a reduced window. Slow
- // start threshold is also updated.
- expected_send_window *= kRenoBeta;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- EXPECT_EQ(expected_send_window, sender_->GetSlowStartThreshold());
-
- // Resets cwnd and slow start threshold on connection migrations.
- sender_->OnConnectionMigration();
- EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
- EXPECT_EQ(kMaxCongestionWindowPackets * kDefaultTCPMSS,
- sender_->GetSlowStartThreshold());
- EXPECT_FALSE(sender_->hybrid_slow_start().started());
-}
-
-TEST_F(TcpCubicSenderBytesTest, DefaultMaxCwnd) {
- ValueRestore<bool> old_flag(&FLAGS_quic_ignore_srbf, true);
- RttStats rtt_stats;
- QuicConnectionStats stats;
- std::unique_ptr<SendAlgorithmInterface> sender(SendAlgorithmInterface::Create(
- &clock_, &rtt_stats, kCubicBytes, &stats, kInitialCongestionWindow));
-
- SendAlgorithmInterface::CongestionVector acked_packets;
- SendAlgorithmInterface::CongestionVector missing_packets;
- for (uint64_t i = 1; i < kDefaultMaxCongestionWindowPackets; ++i) {
- acked_packets.clear();
- acked_packets.push_back(std::make_pair(i, 1350));
- sender->OnCongestionEvent(true, sender->GetCongestionWindow(),
- acked_packets, missing_packets);
- }
- EXPECT_EQ(kDefaultMaxCongestionWindowPackets,
- sender->GetCongestionWindow() / kDefaultTCPMSS);
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/tcp_cubic_sender_packets.cc b/chromium/net/quic/congestion_control/tcp_cubic_sender_packets.cc
deleted file mode 100644
index 33960dff76a..00000000000
--- a/chromium/net/quic/congestion_control/tcp_cubic_sender_packets.cc
+++ /dev/null
@@ -1,225 +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/congestion_control/tcp_cubic_sender_packets.h"
-
-#include <algorithm>
-
-#include "base/metrics/histogram_macros.h"
-#include "net/quic/congestion_control/prr_sender.h"
-#include "net/quic/congestion_control/rtt_stats.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
-
-using std::max;
-using std::min;
-
-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 QuicPacketCount kDefaultMinimumCongestionWindow = 2;
-} // namespace
-
-TcpCubicSenderPackets::TcpCubicSenderPackets(
- const QuicClock* clock,
- const RttStats* rtt_stats,
- bool reno,
- QuicPacketCount initial_tcp_congestion_window,
- QuicPacketCount max_tcp_congestion_window,
- QuicConnectionStats* stats)
- : TcpCubicSenderBase(clock, rtt_stats, reno, stats),
- cubic_(clock),
- congestion_window_count_(0),
- congestion_window_(initial_tcp_congestion_window),
- min_congestion_window_(kDefaultMinimumCongestionWindow),
- slowstart_threshold_(max_tcp_congestion_window),
- max_tcp_congestion_window_(max_tcp_congestion_window),
- initial_tcp_congestion_window_(initial_tcp_congestion_window),
- initial_max_tcp_congestion_window_(max_tcp_congestion_window),
- min_slow_start_exit_window_(min_congestion_window_) {}
-
-TcpCubicSenderPackets::~TcpCubicSenderPackets() {}
-
-void TcpCubicSenderPackets::SetCongestionWindowFromBandwidthAndRtt(
- QuicBandwidth bandwidth,
- QuicTime::Delta rtt) {
- QuicPacketCount new_congestion_window =
- bandwidth.ToBytesPerPeriod(rtt) / kDefaultTCPMSS;
- if (FLAGS_quic_no_lower_bw_resumption_limit) {
- // Limit new CWND to be in the range [1, kMaxCongestionWindow].
- congestion_window_ =
- max(min_congestion_window_,
- min(new_congestion_window, kMaxResumptionCongestionWindow));
- } else {
- congestion_window_ =
- max(min(new_congestion_window, kMaxResumptionCongestionWindow),
- kMinCongestionWindowForBandwidthResumption);
- }
-}
-
-void TcpCubicSenderPackets::SetCongestionWindowInPackets(
- QuicPacketCount congestion_window) {
- congestion_window_ = congestion_window;
-}
-
-void TcpCubicSenderPackets::SetMinCongestionWindowInPackets(
- QuicPacketCount congestion_window) {
- min_congestion_window_ = congestion_window;
-}
-
-void TcpCubicSenderPackets::SetNumEmulatedConnections(int num_connections) {
- TcpCubicSenderBase::SetNumEmulatedConnections(num_connections);
- cubic_.SetNumConnections(num_connections_);
-}
-
-void TcpCubicSenderPackets::SetMaxCongestionWindow(
- QuicByteCount max_congestion_window) {
- DCHECK(!FLAGS_quic_ignore_srbf);
- max_tcp_congestion_window_ = max_congestion_window / kDefaultTCPMSS;
-}
-
-void TcpCubicSenderPackets::ExitSlowstart() {
- slowstart_threshold_ = congestion_window_;
-}
-
-void TcpCubicSenderPackets::OnPacketLost(QuicPacketNumber packet_number,
- QuicByteCount lost_bytes,
- QuicByteCount bytes_in_flight) {
- // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets
- // already sent should be treated as a single loss event, since it's expected.
- if (packet_number <= largest_sent_at_last_cutback_) {
- if (last_cutback_exited_slowstart_) {
- ++stats_->slowstart_packets_lost;
- stats_->slowstart_bytes_lost += lost_bytes;
- if (slow_start_large_reduction_) {
- if (stats_->slowstart_packets_lost == 1 ||
- (stats_->slowstart_bytes_lost / kDefaultTCPMSS) >
- (stats_->slowstart_bytes_lost - lost_bytes) / kDefaultTCPMSS) {
- // Reduce congestion window by 1 for every mss of bytes lost.
- congestion_window_ =
- max(congestion_window_ - 1, min_slow_start_exit_window_);
- }
- slowstart_threshold_ = congestion_window_;
- }
- }
- DVLOG(1) << "Ignoring loss for largest_missing:" << packet_number
- << " because it was sent prior to the last CWND cutback.";
- return;
- }
- ++stats_->tcp_loss_events;
- last_cutback_exited_slowstart_ = InSlowStart();
- if (InSlowStart()) {
- ++stats_->slowstart_packets_lost;
- }
-
- if (!no_prr_) {
- prr_.OnPacketLost(bytes_in_flight);
- }
-
- // TODO(jri): Separate out all of slow start into a separate class.
- if (slow_start_large_reduction_ && InSlowStart()) {
- DCHECK_LT(1u, congestion_window_);
- if (FLAGS_quic_sslr_limit_reduction &&
- congestion_window_ >= 2 * initial_tcp_congestion_window_) {
- min_slow_start_exit_window_ = congestion_window_ / 2;
- }
- congestion_window_ = congestion_window_ - 1;
- } else if (reno_) {
- congestion_window_ = congestion_window_ * RenoBeta();
- } else {
- congestion_window_ =
- cubic_.CongestionWindowAfterPacketLoss(congestion_window_);
- }
- // Enforce a minimum congestion window.
- if (congestion_window_ < min_congestion_window_) {
- congestion_window_ = min_congestion_window_;
- }
- slowstart_threshold_ = congestion_window_;
- largest_sent_at_last_cutback_ = largest_sent_packet_number_;
- // reset packet count from congestion avoidance mode. We start
- // counting again when we're out of recovery.
- congestion_window_count_ = 0;
- DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_
- << " slowstart threshold: " << slowstart_threshold_;
-}
-
-QuicByteCount TcpCubicSenderPackets::GetCongestionWindow() const {
- return congestion_window_ * kDefaultTCPMSS;
-}
-
-QuicByteCount TcpCubicSenderPackets::GetSlowStartThreshold() const {
- return slowstart_threshold_ * kDefaultTCPMSS;
-}
-
-// Called when we receive an ack. Normal TCP tracks how many packets one ack
-// represents, but quic has a separate ack for each packet.
-void TcpCubicSenderPackets::MaybeIncreaseCwnd(
- QuicPacketNumber acked_packet_number,
- QuicByteCount /*acked_bytes*/,
- QuicByteCount bytes_in_flight) {
- QUIC_BUG_IF(InRecovery()) << "Never increase the CWND during recovery.";
- // Do not increase the congestion window unless the sender is close to using
- // the current window.
- if (!IsCwndLimited(bytes_in_flight)) {
- cubic_.OnApplicationLimited();
- return;
- }
- if (congestion_window_ >= max_tcp_congestion_window_) {
- return;
- }
- if (InSlowStart()) {
- // TCP slow start, exponential growth, increase by one for each ACK.
- ++congestion_window_;
- DVLOG(1) << "Slow start; congestion window: " << congestion_window_
- << " slowstart threshold: " << slowstart_threshold_;
- return;
- }
- // Congestion avoidance
- if (reno_) {
- // Classic Reno congestion avoidance.
- ++congestion_window_count_;
- // Divide by num_connections to smoothly increase the CWND at a faster
- // rate than conventional Reno.
- if (congestion_window_count_ * num_connections_ >= congestion_window_) {
- ++congestion_window_;
- congestion_window_count_ = 0;
- }
-
- DVLOG(1) << "Reno; congestion window: " << congestion_window_
- << " slowstart threshold: " << slowstart_threshold_
- << " congestion window count: " << congestion_window_count_;
- } else {
- congestion_window_ = min(max_tcp_congestion_window_,
- cubic_.CongestionWindowAfterAck(
- congestion_window_, rtt_stats_->min_rtt()));
- DVLOG(1) << "Cubic; congestion window: " << congestion_window_
- << " slowstart threshold: " << slowstart_threshold_;
- }
-}
-
-void TcpCubicSenderPackets::HandleRetransmissionTimeout() {
- cubic_.Reset();
- slowstart_threshold_ = congestion_window_ / 2;
- congestion_window_ = min_congestion_window_;
-}
-
-void TcpCubicSenderPackets::OnConnectionMigration() {
- TcpCubicSenderBase::OnConnectionMigration();
- cubic_.Reset();
- congestion_window_count_ = 0;
- congestion_window_ = initial_tcp_congestion_window_;
- slowstart_threshold_ = initial_max_tcp_congestion_window_;
- max_tcp_congestion_window_ = initial_max_tcp_congestion_window_;
-}
-
-CongestionControlType TcpCubicSenderPackets::GetCongestionControlType() const {
- return reno_ ? kReno : kCubic;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/tcp_cubic_sender_packets.h b/chromium/net/quic/congestion_control/tcp_cubic_sender_packets.h
deleted file mode 100644
index 610e75e12b2..00000000000
--- a/chromium/net/quic/congestion_control/tcp_cubic_sender_packets.h
+++ /dev/null
@@ -1,106 +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_CONGESTION_CONTROL_TCP_CUBIC_SENDER_PACKETS_H_
-#define NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_SENDER_PACKETS_H_
-
-#include <stdint.h>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/quic/congestion_control/cubic.h"
-#include "net/quic/congestion_control/hybrid_slow_start.h"
-#include "net/quic/congestion_control/prr_sender.h"
-#include "net/quic/congestion_control/tcp_cubic_sender_base.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_connection_stats.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class RttStats;
-
-namespace test {
-class TcpCubicSenderPacketsPeer;
-} // namespace test
-
-class NET_EXPORT_PRIVATE TcpCubicSenderPackets : public TcpCubicSenderBase {
- public:
- // Reno option and max_tcp_congestion_window are provided for testing.
- TcpCubicSenderPackets(const QuicClock* clock,
- const RttStats* rtt_stats,
- bool reno,
- QuicPacketCount initial_tcp_congestion_window,
- QuicPacketCount max_tcp_congestion_window,
- QuicConnectionStats* stats);
- ~TcpCubicSenderPackets() override;
-
- // Start implementation of SendAlgorithmInterface.
- void SetNumEmulatedConnections(int num_connections) override;
- void SetMaxCongestionWindow(QuicByteCount max_congestion_window) override;
- void OnConnectionMigration() override;
- QuicByteCount GetCongestionWindow() const override;
- QuicByteCount GetSlowStartThreshold() const override;
- CongestionControlType GetCongestionControlType() const override;
- // End implementation of SendAlgorithmInterface.
-
- QuicByteCount min_congestion_window() const { return min_congestion_window_; }
-
- protected:
- // TcpCubicSenderBase methods
- void SetCongestionWindowFromBandwidthAndRtt(QuicBandwidth bandwidth,
- QuicTime::Delta rtt) override;
- void SetCongestionWindowInPackets(QuicPacketCount congestion_window) override;
- void SetMinCongestionWindowInPackets(
- QuicPacketCount congestion_window) override;
- void ExitSlowstart() override;
- void OnPacketLost(QuicPacketNumber largest_loss,
- QuicByteCount lost_bytes,
- QuicByteCount bytes_in_flight) override;
- void MaybeIncreaseCwnd(QuicPacketNumber acked_packet_number,
- QuicByteCount acked_bytes,
- QuicByteCount bytes_in_flight) override;
- void HandleRetransmissionTimeout() override;
-
- private:
- friend class test::TcpCubicSenderPacketsPeer;
-
- Cubic cubic_;
-
- // ACK counter for the Reno implementation.
- uint64_t congestion_window_count_;
-
- // Congestion window in packets.
- QuicPacketCount congestion_window_;
-
- // Minimum congestion window in packets.
- QuicPacketCount min_congestion_window_;
-
- // Slow start congestion window in packets, aka ssthresh.
- QuicPacketCount slowstart_threshold_;
-
- // Maximum number of outstanding packets for tcp.
- QuicPacketCount max_tcp_congestion_window_;
-
- // Initial TCP congestion window. This variable can only be set when this
- // algorithm is created.
- const QuicPacketCount initial_tcp_congestion_window_;
-
- // Initial maximum TCP congestion window. This variable can only be set when
- // this algorithm is created.
- const QuicPacketCount initial_max_tcp_congestion_window_;
-
- // The minimum window when exiting slow start with large reduction.
- QuicPacketCount min_slow_start_exit_window_;
-
- DISALLOW_COPY_AND_ASSIGN(TcpCubicSenderPackets);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_SENDER_H_
diff --git a/chromium/net/quic/congestion_control/tcp_cubic_sender_packets_test.cc b/chromium/net/quic/congestion_control/tcp_cubic_sender_packets_test.cc
deleted file mode 100644
index 91094a69201..00000000000
--- a/chromium/net/quic/congestion_control/tcp_cubic_sender_packets_test.cc
+++ /dev/null
@@ -1,1050 +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/congestion_control/tcp_cubic_sender_packets.h"
-
-#include <algorithm>
-#include <memory>
-
-#include "base/logging.h"
-#include "net/quic/congestion_control/rtt_stats.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/test_tools/quic_config_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::min;
-
-namespace net {
-namespace test {
-
-// TODO(ianswett): A number of theses tests were written with the assumption of
-// an initial CWND of 10. They have carefully calculated values which should be
-// updated to be based on kInitialCongestionWindow.
-const uint32_t kInitialCongestionWindowPackets = 10;
-const uint32_t kMaxCongestionWindowPackets = 200;
-const uint32_t kDefaultWindowTCP =
- kInitialCongestionWindowPackets * kDefaultTCPMSS;
-const float kRenoBeta = 0.7f; // Reno backoff factor.
-
-class TcpCubicSenderPacketsPeer : public TcpCubicSenderPackets {
- public:
- TcpCubicSenderPacketsPeer(const QuicClock* clock,
- bool reno,
- QuicPacketCount max_tcp_congestion_window)
- : TcpCubicSenderPackets(clock,
- &rtt_stats_,
- reno,
- kInitialCongestionWindowPackets,
- max_tcp_congestion_window,
- &stats_) {}
-
- QuicPacketCount congestion_window() { return congestion_window_; }
-
- QuicPacketCount max_congestion_window() { return max_tcp_congestion_window_; }
-
- QuicPacketCount slowstart_threshold() { return slowstart_threshold_; }
-
- const HybridSlowStart& hybrid_slow_start() const {
- return hybrid_slow_start_;
- }
-
- float GetRenoBeta() const { return RenoBeta(); }
-
- RttStats rtt_stats_;
- QuicConnectionStats stats_;
-};
-
-class TcpCubicSenderPacketsTest : public ::testing::Test {
- protected:
- TcpCubicSenderPacketsTest()
- : one_ms_(QuicTime::Delta::FromMilliseconds(1)),
- sender_(new TcpCubicSenderPacketsPeer(&clock_,
- true,
- kMaxCongestionWindowPackets)),
- packet_number_(1),
- acked_packet_number_(0),
- bytes_in_flight_(0) {}
-
- int SendAvailableSendWindow() {
- return SendAvailableSendWindow(kDefaultTCPMSS);
- }
-
- int SendAvailableSendWindow(QuicPacketLength packet_length) {
- // Send as long as TimeUntilSend returns Zero.
- int packets_sent = 0;
- bool can_send =
- sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_).IsZero();
- while (can_send) {
- sender_->OnPacketSent(clock_.Now(), bytes_in_flight_, packet_number_++,
- kDefaultTCPMSS, HAS_RETRANSMITTABLE_DATA);
- ++packets_sent;
- bytes_in_flight_ += kDefaultTCPMSS;
- can_send =
- sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_).IsZero();
- }
- return packets_sent;
- }
-
- // Normal is that TCP acks every other segment.
- void AckNPackets(int n) {
- sender_->rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(60),
- QuicTime::Delta::Zero(), clock_.Now());
- SendAlgorithmInterface::CongestionVector acked_packets;
- SendAlgorithmInterface::CongestionVector lost_packets;
- for (int i = 0; i < n; ++i) {
- ++acked_packet_number_;
- acked_packets.push_back(
- std::make_pair(acked_packet_number_, kDefaultTCPMSS));
- }
- sender_->OnCongestionEvent(true, bytes_in_flight_, acked_packets,
- lost_packets);
- bytes_in_flight_ -= n * kDefaultTCPMSS;
- clock_.AdvanceTime(one_ms_);
- }
-
- void LoseNPackets(int n) { LoseNPackets(n, kDefaultTCPMSS); }
-
- void LoseNPackets(int n, QuicPacketLength packet_length) {
- SendAlgorithmInterface::CongestionVector acked_packets;
- SendAlgorithmInterface::CongestionVector lost_packets;
- for (int i = 0; i < n; ++i) {
- ++acked_packet_number_;
- lost_packets.push_back(
- std::make_pair(acked_packet_number_, packet_length));
- }
- sender_->OnCongestionEvent(false, bytes_in_flight_, acked_packets,
- lost_packets);
- bytes_in_flight_ -= n * packet_length;
- }
-
- // Does not increment acked_packet_number_.
- void LosePacket(QuicPacketNumber packet_number) {
- SendAlgorithmInterface::CongestionVector acked_packets;
- SendAlgorithmInterface::CongestionVector lost_packets;
- lost_packets.push_back(std::make_pair(packet_number, kDefaultTCPMSS));
- sender_->OnCongestionEvent(false, bytes_in_flight_, acked_packets,
- lost_packets);
- bytes_in_flight_ -= kDefaultTCPMSS;
- }
-
- const QuicTime::Delta one_ms_;
- MockClock clock_;
- std::unique_ptr<TcpCubicSenderPacketsPeer> sender_;
- QuicPacketNumber packet_number_;
- QuicPacketNumber acked_packet_number_;
- QuicByteCount bytes_in_flight_;
-};
-
-TEST_F(TcpCubicSenderPacketsTest, SimpleSender) {
- // At startup make sure we are at the default.
- EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
- // At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
- // Make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
- // And that window is un-affected.
- EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
-
- // Fill the send window with data, then verify that we can't send.
- SendAvailableSendWindow();
- EXPECT_FALSE(
- sender_->TimeUntilSend(clock_.Now(), sender_->GetCongestionWindow())
- .IsZero());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, ApplicationLimitedSlowStart) {
- // Send exactly 10 packets and ensure the CWND ends at 14 packets.
- const int kNumberOfAcks = 5;
- // At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
- // Make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
-
- SendAvailableSendWindow();
- for (int i = 0; i < kNumberOfAcks; ++i) {
- AckNPackets(2);
- }
- QuicByteCount bytes_to_send = sender_->GetCongestionWindow();
- // It's expected 2 acks will arrive when the bytes_in_flight are greater than
- // half the CWND.
- EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * 2, bytes_to_send);
-}
-
-TEST_F(TcpCubicSenderPacketsTest, ExponentialSlowStart) {
- const int kNumberOfAcks = 20;
- // At startup make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
- EXPECT_EQ(QuicBandwidth::Zero(), sender_->BandwidthEstimate());
- // Make sure we can send.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
-
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- const QuicByteCount cwnd = sender_->GetCongestionWindow();
- EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * kNumberOfAcks, cwnd);
- EXPECT_EQ(QuicBandwidth::FromBytesAndTimeDelta(
- cwnd, sender_->rtt_stats_.smoothed_rtt()),
- sender_->BandwidthEstimate());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, SlowStartPacketLoss) {
- sender_->SetNumEmulatedConnections(1);
- const int kNumberOfAcks = 10;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose a packet to exit slow start.
- LoseNPackets(1);
- size_t packets_in_recovery_window = expected_send_window / kDefaultTCPMSS;
-
- // We should now have fallen out of slow start with a reduced window.
- expected_send_window *= kRenoBeta;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Recovery phase. We need to ack every packet in the recovery window before
- // we exit recovery.
- size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
- DVLOG(1) << "number_packets: " << number_of_packets_in_window;
- AckNPackets(packets_in_recovery_window);
- SendAvailableSendWindow();
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // We need to ack an entire window before we increase CWND by 1.
- AckNPackets(number_of_packets_in_window - 2);
- SendAvailableSendWindow();
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Next ack should increase cwnd by 1.
- AckNPackets(1);
- expected_send_window += kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Now RTO and ensure slow start gets reset.
- EXPECT_TRUE(sender_->hybrid_slow_start().started());
- sender_->OnRetransmissionTimeout(true);
- EXPECT_FALSE(sender_->hybrid_slow_start().started());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, SlowStartPacketLossWithLargeReduction) {
- FLAGS_quic_sslr_limit_reduction = true;
- QuicConfig config;
- QuicTagVector options;
- options.push_back(kSSLR);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
-
- sender_->SetNumEmulatedConnections(1);
- const int kNumberOfAcks = (kDefaultWindowTCP / (2 * kDefaultTCPMSS)) - 1;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose a packet to exit slow start. We should now have fallen out of
- // slow start with a window reduced by 1.
- LoseNPackets(1);
- expected_send_window -= kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose 5 packets in recovery and verify that congestion window is reduced
- // further.
- LoseNPackets(5);
- expected_send_window -= 5 * kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- // Lose another 10 packets and ensure it reduces below half the peak CWND,
- // because we never acked the full IW.
- LoseNPackets(10);
- expected_send_window -= 10 * kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- size_t packets_in_recovery_window = expected_send_window / kDefaultTCPMSS;
-
- // Recovery phase. We need to ack every packet in the recovery window before
- // we exit recovery.
- size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
- DVLOG(1) << "number_packets: " << number_of_packets_in_window;
- AckNPackets(packets_in_recovery_window);
- SendAvailableSendWindow();
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // We need to ack the rest of the window before cwnd increases by 1.
- AckNPackets(number_of_packets_in_window - 1);
- SendAvailableSendWindow();
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Next ack should increase cwnd by 1.
- AckNPackets(1);
- expected_send_window += kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Now RTO and ensure slow start gets reset.
- EXPECT_TRUE(sender_->hybrid_slow_start().started());
- sender_->OnRetransmissionTimeout(true);
- EXPECT_FALSE(sender_->hybrid_slow_start().started());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, SlowStartHalfPacketLossWithLargeReduction) {
- QuicConfig config;
- QuicTagVector options;
- options.push_back(kSSLR);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
-
- sender_->SetNumEmulatedConnections(1);
- const int kNumberOfAcks = 10;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window in half sized packets.
- SendAvailableSendWindow(kDefaultTCPMSS / 2);
- AckNPackets(2);
- }
- SendAvailableSendWindow(kDefaultTCPMSS / 2);
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose a packet to exit slow start. We should now have fallen out of
- // slow start with a window reduced by 1.
- LoseNPackets(1);
- expected_send_window -= kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose 10 packets in recovery and verify that congestion window is reduced
- // by 5 packets.
- LoseNPackets(10, kDefaultTCPMSS / 2);
- expected_send_window -= 5 * kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, SlowStartPacketLossWithMaxHalfReduction) {
- FLAGS_quic_sslr_limit_reduction = true;
- QuicConfig config;
- QuicTagVector options;
- options.push_back(kSSLR);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
-
- sender_->SetNumEmulatedConnections(1);
- const int kNumberOfAcks = kInitialCongestionWindowPackets / 2;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose a packet to exit slow start. We should now have fallen out of
- // slow start with a window reduced by 1.
- LoseNPackets(1);
- expected_send_window -= kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose half the outstanding packets in recovery and verify the congestion
- // window is only reduced by a max of half.
- LoseNPackets(kNumberOfAcks * 2);
- expected_send_window -= (kNumberOfAcks * 2 - 1) * kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- LoseNPackets(5);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, NoPRRWhenLessThanOnePacketInFlight) {
- SendAvailableSendWindow();
- LoseNPackets(kInitialCongestionWindowPackets - 1);
- AckNPackets(1);
- // PRR will allow 2 packets for every ack during recovery.
- EXPECT_EQ(2, SendAvailableSendWindow());
- // Simulate abandoning all packets by supplying a bytes_in_flight of 0.
- // PRR should now allow a packet to be sent, even though prr's state
- // variables believe it has sent enough packets.
- EXPECT_EQ(QuicTime::Delta::Zero(), sender_->TimeUntilSend(clock_.Now(), 0));
-}
-
-TEST_F(TcpCubicSenderPacketsTest, SlowStartPacketLossPRR) {
- sender_->SetNumEmulatedConnections(1);
- // Test based on the first example in RFC6937.
- // Ack 10 packets in 5 acks to raise the CWND to 20, as in the example.
- const int kNumberOfAcks = 5;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- LoseNPackets(1);
-
- // We should now have fallen out of slow start with a reduced window.
- size_t send_window_before_loss = expected_send_window;
- expected_send_window *= kRenoBeta;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Testing TCP proportional rate reduction.
- // We should send packets paced over the received acks for the remaining
- // outstanding packets. The number of packets before we exit recovery is the
- // original CWND minus the packet that has been lost and the one which
- // triggered the loss.
- size_t remaining_packets_in_recovery =
- send_window_before_loss / kDefaultTCPMSS - 2;
-
- for (size_t i = 0; i < remaining_packets_in_recovery; ++i) {
- AckNPackets(1);
- SendAvailableSendWindow();
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- }
-
- // We need to ack another window before we increase CWND by 1.
- size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
- for (size_t i = 0; i < number_of_packets_in_window; ++i) {
- AckNPackets(1);
- EXPECT_EQ(1, SendAvailableSendWindow());
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- }
-
- AckNPackets(1);
- expected_send_window += kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, SlowStartBurstPacketLossPRR) {
- sender_->SetNumEmulatedConnections(1);
- // Test based on the second example in RFC6937, though we also implement
- // forward acknowledgements, so the first two incoming acks will trigger
- // PRR immediately.
- // Ack 20 packets in 10 acks to raise the CWND to 30.
- const int kNumberOfAcks = 10;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Lose one more than the congestion window reduction, so that after loss,
- // bytes_in_flight is lesser than the congestion window.
- size_t send_window_after_loss = kRenoBeta * expected_send_window;
- size_t num_packets_to_lose =
- (expected_send_window - send_window_after_loss) / kDefaultTCPMSS + 1;
- LoseNPackets(num_packets_to_lose);
- // Immediately after the loss, ensure at least one packet can be sent.
- // Losses without subsequent acks can occur with timer based loss detection.
- EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_).IsZero());
- AckNPackets(1);
-
- // We should now have fallen out of slow start with a reduced window.
- expected_send_window *= kRenoBeta;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Only 2 packets should be allowed to be sent, per PRR-SSRB
- EXPECT_EQ(2, SendAvailableSendWindow());
-
- // Ack the next packet, which triggers another loss.
- LoseNPackets(1);
- AckNPackets(1);
-
- // Send 2 packets to simulate PRR-SSRB.
- EXPECT_EQ(2, SendAvailableSendWindow());
-
- // Ack the next packet, which triggers another loss.
- LoseNPackets(1);
- AckNPackets(1);
-
- // Send 2 packets to simulate PRR-SSRB.
- EXPECT_EQ(2, SendAvailableSendWindow());
-
- // Exit recovery and return to sending at the new rate.
- for (int i = 0; i < kNumberOfAcks; ++i) {
- AckNPackets(1);
- EXPECT_EQ(1, SendAvailableSendWindow());
- }
-}
-
-TEST_F(TcpCubicSenderPacketsTest, RTOCongestionWindow) {
- EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
- EXPECT_EQ(kMaxCongestionWindowPackets, sender_->slowstart_threshold());
-
- // Expect the window to decrease to the minimum once the RTO fires
- // and slow start threshold to be set to 1/2 of the CWND.
- sender_->OnRetransmissionTimeout(true);
- EXPECT_EQ(2 * kDefaultTCPMSS, sender_->GetCongestionWindow());
- EXPECT_EQ(5u, sender_->slowstart_threshold());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, RTOCongestionWindowNoRetransmission) {
- EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
-
- // Expect the window to remain unchanged if the RTO fires but no
- // packets are retransmitted.
- sender_->OnRetransmissionTimeout(false);
- EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, RetransmissionDelay) {
- const int64_t kRttMs = 10;
- const int64_t kDeviationMs = 3;
- EXPECT_EQ(QuicTime::Delta::Zero(), sender_->RetransmissionDelay());
-
- sender_->rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(kRttMs),
- QuicTime::Delta::Zero(), clock_.Now());
-
- // Initial value is to set the median deviation to half of the initial
- // rtt, the median in then multiplied by a factor of 4 and finally the
- // smoothed rtt is added which is the initial rtt.
- QuicTime::Delta expected_delay =
- QuicTime::Delta::FromMilliseconds(kRttMs + kRttMs / 2 * 4);
- EXPECT_EQ(expected_delay, sender_->RetransmissionDelay());
-
- for (int i = 0; i < 100; ++i) {
- // Run to make sure that we converge.
- sender_->rtt_stats_.UpdateRtt(
- QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs),
- QuicTime::Delta::Zero(), clock_.Now());
- sender_->rtt_stats_.UpdateRtt(
- QuicTime::Delta::FromMilliseconds(kRttMs - kDeviationMs),
- QuicTime::Delta::Zero(), clock_.Now());
- }
- expected_delay = QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs * 4);
-
- EXPECT_NEAR(kRttMs, sender_->rtt_stats_.smoothed_rtt().ToMilliseconds(), 1);
- EXPECT_NEAR(expected_delay.ToMilliseconds(),
- sender_->RetransmissionDelay().ToMilliseconds(), 1);
- EXPECT_EQ(static_cast<int64_t>(
- sender_->GetCongestionWindow() * kNumMicrosPerSecond /
- sender_->rtt_stats_.smoothed_rtt().ToMicroseconds()),
- sender_->BandwidthEstimate().ToBytesPerSecond());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, SlowStartMaxSendWindow) {
- const QuicPacketCount kMaxCongestionWindowTCP = 50;
- const int kNumberOfAcks = 100;
- sender_.reset(
- new TcpCubicSenderPacketsPeer(&clock_, false, kMaxCongestionWindowTCP));
-
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- QuicByteCount expected_send_window = kMaxCongestionWindowTCP * kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, TcpRenoMaxCongestionWindow) {
- const QuicPacketCount kMaxCongestionWindowTCP = 50;
- const int kNumberOfAcks = 1000;
- sender_.reset(
- new TcpCubicSenderPacketsPeer(&clock_, true, kMaxCongestionWindowTCP));
-
- SendAvailableSendWindow();
- AckNPackets(2);
- // Make sure we fall out of slow start.
- LoseNPackets(1);
-
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
-
- QuicByteCount expected_send_window = kMaxCongestionWindowTCP * kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, TcpCubicMaxCongestionWindow) {
- const QuicPacketCount kMaxCongestionWindowTCP = 50;
- // Set to 10000 to compensate for small cubic alpha.
- const int kNumberOfAcks = 10000;
-
- sender_.reset(
- new TcpCubicSenderPacketsPeer(&clock_, false, kMaxCongestionWindowTCP));
-
- SendAvailableSendWindow();
- AckNPackets(2);
- // Make sure we fall out of slow start.
- LoseNPackets(1);
-
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
-
- QuicByteCount expected_send_window = kMaxCongestionWindowTCP * kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, TcpCubicResetEpochOnQuiescence) {
- const int kMaxCongestionWindow = 50;
- const QuicByteCount kMaxCongestionWindowBytes =
- kMaxCongestionWindow * kDefaultTCPMSS;
- sender_.reset(
- new TcpCubicSenderPacketsPeer(&clock_, false, kMaxCongestionWindow));
-
- int num_sent = SendAvailableSendWindow();
-
- // Make sure we fall out of slow start.
- QuicByteCount saved_cwnd = sender_->GetCongestionWindow();
- LoseNPackets(1);
- EXPECT_GT(saved_cwnd, sender_->GetCongestionWindow());
-
- // Ack the rest of the outstanding packets to get out of recovery.
- for (int i = 1; i < num_sent; ++i) {
- AckNPackets(1);
- }
- EXPECT_EQ(0u, bytes_in_flight_);
-
- // Send a new window of data and ack all; cubic growth should occur.
- saved_cwnd = sender_->GetCongestionWindow();
- num_sent = SendAvailableSendWindow();
- for (int i = 0; i < num_sent; ++i) {
- AckNPackets(1);
- }
- EXPECT_LT(saved_cwnd, sender_->GetCongestionWindow());
- EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow());
- EXPECT_EQ(0u, bytes_in_flight_);
-
- // Quiescent time of 100 seconds
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100000));
-
- // Send new window of data and ack one packet. Cubic epoch should have
- // been reset; ensure cwnd increase is not dramatic.
- saved_cwnd = sender_->GetCongestionWindow();
- SendAvailableSendWindow();
- AckNPackets(1);
- EXPECT_NEAR(saved_cwnd, sender_->GetCongestionWindow(), kDefaultTCPMSS);
- EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, TcpCubicShiftedEpochOnQuiescence) {
- ValueRestore<bool> old_flag(&FLAGS_shift_quic_cubic_epoch_when_app_limited,
- true);
- const int kMaxCongestionWindow = 50;
- const QuicByteCount kMaxCongestionWindowBytes =
- kMaxCongestionWindow * kDefaultTCPMSS;
- sender_.reset(
- new TcpCubicSenderPacketsPeer(&clock_, false, kMaxCongestionWindow));
-
- int num_sent = SendAvailableSendWindow();
-
- // Make sure we fall out of slow start.
- QuicByteCount saved_cwnd = sender_->GetCongestionWindow();
- LoseNPackets(1);
- EXPECT_GT(saved_cwnd, sender_->GetCongestionWindow());
-
- // Ack the rest of the outstanding packets to get out of recovery.
- for (int i = 1; i < num_sent; ++i) {
- AckNPackets(1);
- }
- EXPECT_EQ(0u, bytes_in_flight_);
-
- // Send a new window of data and ack all; cubic growth should occur.
- saved_cwnd = sender_->GetCongestionWindow();
- num_sent = SendAvailableSendWindow();
- for (int i = 0; i < num_sent; ++i) {
- AckNPackets(1);
- }
- EXPECT_LT(saved_cwnd, sender_->GetCongestionWindow());
- EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow());
- EXPECT_EQ(0u, bytes_in_flight_);
-
- // Quiescent time of 100 seconds
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(100));
-
- // Send new window of data and ack one packet. Cubic epoch should have
- // been reset; ensure cwnd increase is not dramatic.
- saved_cwnd = sender_->GetCongestionWindow();
- SendAvailableSendWindow();
- AckNPackets(1);
- EXPECT_NEAR(saved_cwnd, sender_->GetCongestionWindow(), kDefaultTCPMSS);
- EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, MultipleLossesInOneWindow) {
- SendAvailableSendWindow();
- const QuicByteCount initial_window = sender_->GetCongestionWindow();
- LosePacket(acked_packet_number_ + 1);
- const QuicByteCount post_loss_window = sender_->GetCongestionWindow();
- EXPECT_GT(initial_window, post_loss_window);
- LosePacket(acked_packet_number_ + 3);
- EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow());
- LosePacket(packet_number_ - 1);
- EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow());
-
- // Lose a later packet and ensure the window decreases.
- LosePacket(packet_number_);
- EXPECT_GT(post_loss_window, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, DontTrackAckPackets) {
- // Send a packet with no retransmittable data, and ensure it's not tracked.
- EXPECT_FALSE(sender_->OnPacketSent(clock_.Now(), bytes_in_flight_,
- packet_number_++, kDefaultTCPMSS,
- NO_RETRANSMITTABLE_DATA));
-
- // Send a data packet with retransmittable data, and ensure it is tracked.
- EXPECT_TRUE(sender_->OnPacketSent(clock_.Now(), bytes_in_flight_,
- packet_number_++, kDefaultTCPMSS,
- HAS_RETRANSMITTABLE_DATA));
-}
-
-TEST_F(TcpCubicSenderPacketsTest, ConfigureInitialWindow) {
- QuicConfig config;
-
- QuicTagVector options;
- options.push_back(kIW03);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
- EXPECT_EQ(3u, sender_->congestion_window());
-
- options.clear();
- options.push_back(kIW10);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
- EXPECT_EQ(10u, sender_->congestion_window());
-
- options.clear();
- options.push_back(kIW20);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
- EXPECT_EQ(20u, sender_->congestion_window());
-
- options.clear();
- options.push_back(kIW50);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
- EXPECT_EQ(50u, sender_->congestion_window());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, ConfigureMinimumWindow) {
- QuicConfig config;
-
- // Verify that kCOPT: kMIN1 forces the min CWND to 1 packet.
- QuicTagVector options;
- options.push_back(kMIN1);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
- sender_->OnRetransmissionTimeout(true);
- EXPECT_EQ(1u, sender_->congestion_window());
-}
-
-TEST_F(TcpCubicSenderPacketsTest,
- 2ConnectionCongestionAvoidanceAtEndOfRecovery) {
- sender_->SetNumEmulatedConnections(2);
- // Ack 10 packets in 5 acks to raise the CWND to 20.
- const int kNumberOfAcks = 5;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- LoseNPackets(1);
-
- // We should now have fallen out of slow start with a reduced window.
- expected_send_window = expected_send_window * sender_->GetRenoBeta();
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // No congestion window growth should occur in recovery phase, i.e., until the
- // currently outstanding 20 packets are acked.
- for (int i = 0; i < 10; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- EXPECT_TRUE(sender_->InRecovery());
- AckNPackets(2);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- }
- EXPECT_FALSE(sender_->InRecovery());
-
- // Out of recovery now. Congestion window should not grow for half an RTT.
- size_t packets_in_send_window = expected_send_window / kDefaultTCPMSS;
- SendAvailableSendWindow();
- AckNPackets(packets_in_send_window / 2 - 2);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Next ack should increase congestion window by 1MSS.
- SendAvailableSendWindow();
- AckNPackets(2);
- expected_send_window += kDefaultTCPMSS;
- packets_in_send_window += 1;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Congestion window should remain steady again for half an RTT.
- SendAvailableSendWindow();
- AckNPackets(packets_in_send_window / 2 - 1);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Next ack should cause congestion window to grow by 1MSS.
- SendAvailableSendWindow();
- AckNPackets(2);
- expected_send_window += kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderPacketsTest,
- 1ConnectionCongestionAvoidanceAtEndOfRecovery) {
- sender_->SetNumEmulatedConnections(1);
- // Ack 10 packets in 5 acks to raise the CWND to 20.
- const int kNumberOfAcks = 5;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- LoseNPackets(1);
-
- // We should now have fallen out of slow start with a reduced window.
- expected_send_window *= kRenoBeta;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // No congestion window growth should occur in recovery phase, i.e., until the
- // currently outstanding 20 packets are acked.
- for (int i = 0; i < 10; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- EXPECT_TRUE(sender_->InRecovery());
- AckNPackets(2);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- }
- EXPECT_FALSE(sender_->InRecovery());
-
- // Out of recovery now. Congestion window should not grow during RTT.
- for (uint64_t i = 0; i < expected_send_window / kDefaultTCPMSS - 2; i += 2) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- }
-
- // Next ack should cause congestion window to grow by 1MSS.
- SendAvailableSendWindow();
- AckNPackets(2);
- expected_send_window += kDefaultTCPMSS;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, BandwidthResumption) {
- // Test that when provided with CachedNetworkParameters and opted in to the
- // bandwidth resumption experiment, that the TcpCubicSenderPackets sets
- // initial CWND appropriately.
-
- // Set some common values.
- CachedNetworkParameters cached_network_params;
- const QuicPacketCount kNumberOfPackets = 123;
- const int kBandwidthEstimateBytesPerSecond =
- kNumberOfPackets * kDefaultTCPMSS;
- cached_network_params.set_bandwidth_estimate_bytes_per_second(
- kBandwidthEstimateBytesPerSecond);
- cached_network_params.set_min_rtt_ms(1000);
-
- // Make sure that a bandwidth estimate results in a changed CWND.
- cached_network_params.set_timestamp(clock_.WallNow().ToUNIXSeconds() -
- (kNumSecondsPerHour - 1));
- sender_->ResumeConnectionState(cached_network_params, false);
- EXPECT_EQ(kNumberOfPackets, sender_->congestion_window());
-
- // Resumed CWND is limited to be in a sensible range.
- cached_network_params.set_bandwidth_estimate_bytes_per_second(
- (kMaxCongestionWindowPackets + 1) * kDefaultTCPMSS);
- sender_->ResumeConnectionState(cached_network_params, false);
- EXPECT_EQ(kMaxCongestionWindowPackets, sender_->congestion_window());
-
- if (FLAGS_quic_no_lower_bw_resumption_limit) {
- // Resume with an illegal value of 0 and verify the server uses 1 instead.
- cached_network_params.set_bandwidth_estimate_bytes_per_second(0);
- sender_->ResumeConnectionState(cached_network_params, false);
- EXPECT_EQ(sender_->min_congestion_window(), sender_->congestion_window());
- } else {
- cached_network_params.set_bandwidth_estimate_bytes_per_second(
- (kMinCongestionWindowForBandwidthResumption - 1) * kDefaultTCPMSS);
- sender_->ResumeConnectionState(cached_network_params, false);
- EXPECT_EQ(kMinCongestionWindowForBandwidthResumption,
- sender_->congestion_window());
- }
-
- // Resume to the max value.
- cached_network_params.set_max_bandwidth_estimate_bytes_per_second(
- kMaxCongestionWindowPackets * kDefaultTCPMSS);
- sender_->ResumeConnectionState(cached_network_params, true);
- EXPECT_EQ(kMaxCongestionWindowPackets * kDefaultTCPMSS,
- sender_->GetCongestionWindow());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, PaceBelowCWND) {
- QuicConfig config;
-
- // Verify that kCOPT: kMIN4 forces the min CWND to 1 packet, but allows up
- // to 4 to be sent.
- QuicTagVector options;
- options.push_back(kMIN4);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
- sender_->OnRetransmissionTimeout(true);
- EXPECT_EQ(1u, sender_->congestion_window());
- EXPECT_TRUE(
- sender_->TimeUntilSend(QuicTime::Zero(), kDefaultTCPMSS).IsZero());
- EXPECT_TRUE(
- sender_->TimeUntilSend(QuicTime::Zero(), 2 * kDefaultTCPMSS).IsZero());
- EXPECT_TRUE(
- sender_->TimeUntilSend(QuicTime::Zero(), 3 * kDefaultTCPMSS).IsZero());
- EXPECT_FALSE(
- sender_->TimeUntilSend(QuicTime::Zero(), 4 * kDefaultTCPMSS).IsZero());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, NoPRR) {
- ValueRestore<bool> old_flag(&FLAGS_quic_allow_noprr, true);
- QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(100);
- sender_->rtt_stats_.UpdateRtt(rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
-
- sender_->SetNumEmulatedConnections(1);
- // Verify that kCOPT: kNPRR allows all packets to be sent, even if only one
- // ack has been received.
- QuicTagVector options;
- options.push_back(kNPRR);
- QuicConfig config;
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
- SendAvailableSendWindow();
- LoseNPackets(9);
- AckNPackets(1);
-
- // We should now have fallen out of slow start with a reduced window.
- EXPECT_EQ(kRenoBeta * kDefaultWindowTCP, sender_->GetCongestionWindow());
- const QuicPacketCount window_in_packets =
- kRenoBeta * kDefaultWindowTCP / kDefaultTCPMSS;
- const QuicBandwidth expected_pacing_rate =
- QuicBandwidth::FromBytesAndTimeDelta(kRenoBeta * kDefaultWindowTCP,
- sender_->rtt_stats_.smoothed_rtt());
- EXPECT_EQ(expected_pacing_rate, sender_->PacingRate(0));
- EXPECT_EQ(window_in_packets,
- static_cast<uint64_t>(SendAvailableSendWindow()));
- EXPECT_EQ(expected_pacing_rate,
- sender_->PacingRate(kRenoBeta * kDefaultWindowTCP));
-}
-
-TEST_F(TcpCubicSenderPacketsTest, PaceSlowerAboveCwnd) {
- ValueRestore<bool> old_flag(&FLAGS_quic_rate_based_sending, true);
- QuicTime::Delta rtt(QuicTime::Delta::FromMilliseconds(60));
- sender_->rtt_stats_.UpdateRtt(rtt, QuicTime::Delta::Zero(), clock_.Now());
-
- QuicConfig config;
- QuicTagVector options;
- options.push_back(kRATE);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, Perspective::IS_SERVER);
- EXPECT_EQ(10u, sender_->congestion_window());
- sender_->SetNumEmulatedConnections(1);
- // Lose a packet to exit slow start.
- LoseNPackets(1);
- const QuicPacketCount cwnd = 7;
- EXPECT_EQ(cwnd * kDefaultTCPMSS, sender_->GetCongestionWindow());
-
- EXPECT_TRUE(
- sender_->TimeUntilSend(QuicTime::Zero(), kDefaultTCPMSS).IsZero());
- EXPECT_EQ(sender_->PacingRate(kDefaultTCPMSS),
- QuicBandwidth::FromBytesAndTimeDelta(7 * kDefaultTCPMSS, rtt)
- .Scale(1.25));
- for (QuicPacketCount i = cwnd + 1; i < 1.5 * cwnd; ++i) {
- EXPECT_TRUE(
- sender_->TimeUntilSend(QuicTime::Zero(), i * kDefaultTCPMSS).IsZero());
- EXPECT_EQ(sender_->PacingRate(i * kDefaultTCPMSS),
- QuicBandwidth::FromBytesAndTimeDelta(cwnd * kDefaultTCPMSS, rtt)
- .Scale(0.75));
- }
- EXPECT_FALSE(
- sender_->TimeUntilSend(QuicTime::Zero(), 11 * kDefaultTCPMSS).IsZero());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, ResetAfterConnectionMigration) {
- EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
- EXPECT_EQ(kMaxCongestionWindowPackets, sender_->slowstart_threshold());
-
- // Starts with slow start.
- sender_->SetNumEmulatedConnections(1);
- const int kNumberOfAcks = 10;
- for (int i = 0; i < kNumberOfAcks; ++i) {
- // Send our full send window.
- SendAvailableSendWindow();
- AckNPackets(2);
- }
- SendAvailableSendWindow();
- QuicByteCount expected_send_window =
- kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
-
- // Loses a packet to exit slow start.
- LoseNPackets(1);
-
- // We should now have fallen out of slow start with a reduced window. Slow
- // start threshold is also updated.
- expected_send_window *= kRenoBeta;
- EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
- EXPECT_EQ(expected_send_window / kDefaultTCPMSS,
- sender_->slowstart_threshold());
-
- // Resets cwnd and slow start threshold on connection migrations.
- sender_->OnConnectionMigration();
- EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
- EXPECT_EQ(kMaxCongestionWindowPackets, sender_->slowstart_threshold());
- EXPECT_FALSE(sender_->hybrid_slow_start().started());
-}
-
-TEST_F(TcpCubicSenderPacketsTest, DefaultMaxCwnd) {
- ValueRestore<bool> old_flag(&FLAGS_quic_ignore_srbf, true);
- RttStats rtt_stats;
- QuicConnectionStats stats;
- std::unique_ptr<SendAlgorithmInterface> sender(SendAlgorithmInterface::Create(
- &clock_, &rtt_stats, kCubic, &stats, kInitialCongestionWindow));
-
- SendAlgorithmInterface::CongestionVector acked_packets;
- SendAlgorithmInterface::CongestionVector missing_packets;
- for (uint64_t i = 1; i < kDefaultMaxCongestionWindowPackets; ++i) {
- acked_packets.clear();
- acked_packets.push_back(std::make_pair(i, 1350));
- sender->OnCongestionEvent(true, sender->GetCongestionWindow(),
- acked_packets, missing_packets);
- }
- EXPECT_EQ(kDefaultMaxCongestionWindowPackets,
- sender->GetCongestionWindow() / kDefaultTCPMSS);
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/congestion_control/windowed_filter.h b/chromium/net/quic/congestion_control/windowed_filter.h
deleted file mode 100644
index 9c2ce1a8942..00000000000
--- a/chromium/net/quic/congestion_control/windowed_filter.h
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-#ifndef NET_QUIC_CONGESTION_CONTROL_WINDOWED_FILTER_H_
-#define NET_QUIC_CONGESTION_CONTROL_WINDOWED_FILTER_H_
-
-// Implements Kathleen Nichols' algorithm for tracking the minimum (or maximum)
-// estimate of a stream of samples over some fixed time interval. (E.g.,
-// the minimum RTT over the past five minutes.) The algorithm keeps track of
-// the best, second best, and third best min (or max) estimates, maintaining an
-// invariant that the measurement time of the n'th best >= n-1'th best.
-
-// The algorithm works as follows. On a reset, all three estimates are set to
-// the same sample. The second best estimate is then recorded in the second
-// quarter of the window, and a third best estimate is recorded in the second
-// half of the window, bounding the worst case error when the true min is
-// monotonically increasing (or true max is monotonically decreasing) over the
-// window.
-//
-// A new best sample replaces all three estimates, since the new best is lower
-// (or higher) than everything else in the window and it is the most recent.
-// The window thus effectively gets reset on every new min. The same property
-// holds true for second best and third best estimates. Specifically, when a
-// sample arrives that is better than the second best but not better than the
-// best, it replaces the second and third best estimates but not the best
-// estimate. Similarly, a sample that is better than the third best estimate
-// but not the other estimates replaces only the third best estimate.
-//
-// Finally, when the best expires, it is replaced by the second best, which in
-// turn is replaced by the third best. The newest sample replaces the third
-// best.
-
-#include "base/logging.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-// Compares two values and returns true if the first is less than or equal
-// to the second.
-template <class T>
-struct MinFilter {
- bool operator()(const T& lhs, const T& rhs) const { return lhs <= rhs; }
-};
-
-// Compares two values and returns true if the first is greater than or equal
-// to the second.
-template <class T>
-struct MaxFilter {
- bool operator()(const T& lhs, const T& rhs) const { return lhs >= rhs; }
-};
-
-// Use the following to construct a windowed filter object of type T.
-// For a min filter: WindowedFilter<T, MinFilter<T>> ObjectName;
-// For a max filter: WindowedFilter<T, MaxFilter<T>> ObjectName;
-template <class T, class Compare>
-class WindowedFilter {
- public:
- // |window_length| is the period after which a best estimate expires.
- // |zero_value| is used as the uninitialized value for objects of T.
- // Importantly, |zero_value| should be an invalid value for a true sample.
- WindowedFilter(QuicTime::Delta window_length, T zero_value)
- : window_length_(window_length),
- zero_value_(zero_value),
- estimates_{Sample(zero_value_, QuicTime::Zero()),
- Sample(zero_value_, QuicTime::Zero()),
- Sample(zero_value_, QuicTime::Zero())} {}
-
- // Updates best estimates with |sample|, and expires and updates best
- // estimates as necessary.
- void Update(T new_sample, QuicTime new_time) {
- // Reset all estimates if they have not yet been initialized, if new sample
- // is a new best, or if the newest recorded estimate is too old.
- if (estimates_[0].sample == zero_value_ ||
- Compare()(new_sample, estimates_[0].sample) ||
- new_time.Subtract(estimates_[2].time) > window_length_) {
- Reset(new_sample, new_time);
- return;
- }
-
- if (Compare()(new_sample, estimates_[1].sample)) {
- estimates_[1] = Sample(new_sample, new_time);
- estimates_[2] = estimates_[1];
- } else if (Compare()(new_sample, estimates_[2].sample)) {
- estimates_[2] = Sample(new_sample, new_time);
- }
-
- // Expire and update estimates as necessary.
- if (new_time.Subtract(estimates_[0].time) > window_length_) {
- // The best estimate hasn't been updated for an entire window, so promote
- // second and third best estimates.
- estimates_[0] = estimates_[1];
- estimates_[1] = estimates_[2];
- estimates_[2] = Sample(new_sample, new_time);
- // Need to iterate one more time. Check if the new best estimate is
- // outside the window as well, since it may also have been recorded a
- // long time ago. Don't need to iterate once more since we cover that
- // case at the beginning of the method.
- if (new_time.Subtract(estimates_[0].time) > window_length_) {
- estimates_[0] = estimates_[1];
- estimates_[1] = estimates_[2];
- }
- return;
- }
- if (estimates_[1].sample == estimates_[0].sample &&
- new_time.Subtract(estimates_[1].time) > window_length_ >> 2) {
- // A quarter of the window has passed without a better sample, so the
- // second-best estimate is taken from the second quarter of the window.
- estimates_[2] = estimates_[1] = Sample(new_sample, new_time);
- return;
- }
-
- if (estimates_[2].sample == estimates_[1].sample &&
- new_time.Subtract(estimates_[2].time) > window_length_ >> 1) {
- // We've passed a half of the window without a better estimate, so take
- // a third-best estimate from the second half of the window.
- estimates_[2] = Sample(new_sample, new_time);
- }
- }
-
- // Resets all estimates to new sample.
- void Reset(T new_sample, QuicTime new_time) {
- estimates_[0] = estimates_[1] = estimates_[2] =
- Sample(new_sample, new_time);
- }
-
- T GetBest() const { return estimates_[0].sample; }
- T GetSecondBest() const { return estimates_[1].sample; }
- T GetThirdBest() const { return estimates_[2].sample; }
-
- private:
- struct Sample {
- T sample;
- QuicTime time;
- Sample(T init_sample, QuicTime init_time)
- : sample(init_sample), time(init_time) {}
- };
-
- QuicTime::Delta window_length_; // Time length of window.
- T zero_value_; // Uninitialized value of T.
- Sample estimates_[3]; // Best estimate is element 0.
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_WINDOWED_FILTER_H_
diff --git a/chromium/net/quic/congestion_control/windowed_filter_test.cc b/chromium/net/quic/congestion_control/windowed_filter_test.cc
deleted file mode 100644
index 25870b86458..00000000000
--- a/chromium/net/quic/congestion_control/windowed_filter_test.cc
+++ /dev/null
@@ -1,330 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-#include "net/quic/congestion_control/windowed_filter.h"
-
-#include "base/logging.h"
-#include "net/quic/congestion_control/rtt_stats.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_protocol.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-namespace {
-
-class WindowedFilterTest : public ::testing::Test {
- public:
- // Set the window to 99ms, so 25ms is more than a quarter rtt.
- WindowedFilterTest()
- : windowed_min_rtt_(QuicTime::Delta::FromMilliseconds(99),
- QuicTime::Delta::Zero()),
- windowed_max_bw_(QuicTime::Delta::FromMilliseconds(99),
- QuicBandwidth::Zero()) {}
-
- // Sets up windowed_min_rtt_ to have the following values:
- // Best = 20ms, recorded at 25ms
- // Second best = 40ms, recorded at 75ms
- // Third best = 50ms, recorded at 100ms
- void InitializeMinFilter() {
- QuicTime now = QuicTime::Zero();
- QuicTime::Delta rtt_sample = QuicTime::Delta::FromMilliseconds(10);
- for (int i = 0; i < 5; ++i) {
- windowed_min_rtt_.Update(rtt_sample, now);
- VLOG(1) << "i: " << i << " sample: " << rtt_sample.ToMilliseconds()
- << " mins: "
- << " " << windowed_min_rtt_.GetBest().ToMilliseconds() << " "
- << windowed_min_rtt_.GetSecondBest().ToMilliseconds() << " "
- << windowed_min_rtt_.GetThirdBest().ToMilliseconds();
- now = now.Add(QuicTime::Delta::FromMilliseconds(25));
- rtt_sample = rtt_sample.Add(QuicTime::Delta::FromMilliseconds(10));
- }
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20),
- windowed_min_rtt_.GetBest());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(40),
- windowed_min_rtt_.GetSecondBest());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(50),
- windowed_min_rtt_.GetThirdBest());
- }
-
- // Sets up windowed_max_bw_ to have the following values:
- // Best = 900 bps, recorded at 25ms
- // Second best = 700 bps, recorded at 75ms
- // Third best = 600 bps, recorded at 100ms
- void InitializeMaxFilter() {
- QuicTime now = QuicTime::Zero();
- QuicBandwidth bw_sample = QuicBandwidth::FromBitsPerSecond(1000);
- for (int i = 0; i < 5; ++i) {
- windowed_max_bw_.Update(bw_sample, now);
- VLOG(1) << "i: " << i << " sample: " << bw_sample.ToBitsPerSecond()
- << " maxs: "
- << " " << windowed_max_bw_.GetBest().ToBitsPerSecond() << " "
- << windowed_max_bw_.GetSecondBest().ToBitsPerSecond() << " "
- << windowed_max_bw_.GetThirdBest().ToBitsPerSecond();
- now = now.Add(QuicTime::Delta::FromMilliseconds(25));
- bw_sample = bw_sample.Subtract(QuicBandwidth::FromBitsPerSecond(100));
- }
- EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(900),
- windowed_max_bw_.GetBest());
- EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(700),
- windowed_max_bw_.GetSecondBest());
- EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(600),
- windowed_max_bw_.GetThirdBest());
- }
-
- protected:
- WindowedFilter<QuicTime::Delta, MinFilter<QuicTime::Delta>> windowed_min_rtt_;
- WindowedFilter<QuicBandwidth, MaxFilter<QuicBandwidth>> windowed_max_bw_;
-};
-
-TEST_F(WindowedFilterTest, UninitializedEstimates) {
- EXPECT_EQ(QuicTime::Delta::Zero(), windowed_min_rtt_.GetBest());
- EXPECT_EQ(QuicTime::Delta::Zero(), windowed_min_rtt_.GetSecondBest());
- EXPECT_EQ(QuicTime::Delta::Zero(), windowed_min_rtt_.GetThirdBest());
- EXPECT_EQ(QuicBandwidth::Zero(), windowed_max_bw_.GetBest());
- EXPECT_EQ(QuicBandwidth::Zero(), windowed_max_bw_.GetSecondBest());
- EXPECT_EQ(QuicBandwidth::Zero(), windowed_max_bw_.GetThirdBest());
-}
-
-TEST_F(WindowedFilterTest, MonotonicallyIncreasingMin) {
- QuicTime now = QuicTime::Zero();
- QuicTime::Delta rtt_sample = QuicTime::Delta::FromMilliseconds(10);
- windowed_min_rtt_.Update(rtt_sample, now);
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), windowed_min_rtt_.GetBest());
-
- // Gradually increase the rtt samples and ensure the windowed min rtt starts
- // rising.
- for (int i = 0; i < 6; ++i) {
- now = now.Add(QuicTime::Delta::FromMilliseconds(25));
- rtt_sample = rtt_sample.Add(QuicTime::Delta::FromMilliseconds(10));
- windowed_min_rtt_.Update(rtt_sample, now);
- VLOG(1) << "i: " << i << " sample: " << rtt_sample.ToMilliseconds()
- << " mins: "
- << " " << windowed_min_rtt_.GetBest().ToMilliseconds() << " "
- << windowed_min_rtt_.GetSecondBest().ToMilliseconds() << " "
- << windowed_min_rtt_.GetThirdBest().ToMilliseconds();
- if (i < 3) {
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
- windowed_min_rtt_.GetBest());
- } else if (i == 3) {
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20),
- windowed_min_rtt_.GetBest());
- } else if (i < 6) {
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(40),
- windowed_min_rtt_.GetBest());
- }
- }
-}
-
-TEST_F(WindowedFilterTest, MonotonicallyDecreasingMax) {
- QuicTime now = QuicTime::Zero();
- QuicBandwidth bw_sample = QuicBandwidth::FromBitsPerSecond(1000);
- windowed_max_bw_.Update(bw_sample, now);
- EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(1000), windowed_max_bw_.GetBest());
-
- // Gradually decrease the bw samples and ensure the windowed max bw starts
- // decreasing.
- for (int i = 0; i < 6; ++i) {
- now = now.Add(QuicTime::Delta::FromMilliseconds(25));
- bw_sample = bw_sample.Subtract(QuicBandwidth::FromBitsPerSecond(100));
- windowed_max_bw_.Update(bw_sample, now);
- VLOG(1) << "i: " << i << " sample: " << bw_sample.ToBitsPerSecond()
- << " maxs: "
- << " " << windowed_max_bw_.GetBest().ToBitsPerSecond() << " "
- << windowed_max_bw_.GetSecondBest().ToBitsPerSecond() << " "
- << windowed_max_bw_.GetThirdBest().ToBitsPerSecond();
- if (i < 3) {
- EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(1000),
- windowed_max_bw_.GetBest());
- } else if (i == 3) {
- EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(900),
- windowed_max_bw_.GetBest());
- } else if (i < 6) {
- EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(700),
- windowed_max_bw_.GetBest());
- }
- }
-}
-
-TEST_F(WindowedFilterTest, SampleChangesThirdBestMin) {
- InitializeMinFilter();
- // RTT sample lower than the third-choice min-rtt sets that, but nothing else.
- QuicTime::Delta rtt_sample = windowed_min_rtt_.GetThirdBest().Subtract(
- QuicTime::Delta::FromMilliseconds(5));
- // This assert is necessary to avoid triggering -Wstrict-overflow
- // See crbug/616957
- ASSERT_GT(windowed_min_rtt_.GetThirdBest(),
- QuicTime::Delta::FromMilliseconds(5));
- // Latest sample was recorded at 100ms.
- QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(101));
- windowed_min_rtt_.Update(rtt_sample, now);
- EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(40),
- windowed_min_rtt_.GetSecondBest());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20), windowed_min_rtt_.GetBest());
-}
-
-TEST_F(WindowedFilterTest, SampleChangesThirdBestMax) {
- InitializeMaxFilter();
- // BW sample higher than the third-choice max sets that, but nothing else.
- QuicBandwidth bw_sample =
- windowed_max_bw_.GetThirdBest().Add(QuicBandwidth::FromBitsPerSecond(50));
- // Latest sample was recorded at 100ms.
- QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(101));
- windowed_max_bw_.Update(bw_sample, now);
- EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
- EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(700),
- windowed_max_bw_.GetSecondBest());
- EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(900), windowed_max_bw_.GetBest());
-}
-
-TEST_F(WindowedFilterTest, SampleChangesSecondBestMin) {
- InitializeMinFilter();
- // RTT sample lower than the second-choice min sets that and also
- // the third-choice min.
- QuicTime::Delta rtt_sample = windowed_min_rtt_.GetSecondBest().Subtract(
- QuicTime::Delta::FromMilliseconds(5));
- // This assert is necessary to avoid triggering -Wstrict-overflow
- // See crbug/616957
- ASSERT_GT(windowed_min_rtt_.GetSecondBest(),
- QuicTime::Delta::FromMilliseconds(5));
- // Latest sample was recorded at 100ms.
- QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(101));
- windowed_min_rtt_.Update(rtt_sample, now);
- EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
- EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20), windowed_min_rtt_.GetBest());
-}
-
-TEST_F(WindowedFilterTest, SampleChangesSecondBestMax) {
- InitializeMaxFilter();
- // BW sample higher than the second-choice max sets that and also
- // the third-choice max.
- QuicBandwidth bw_sample = windowed_max_bw_.GetSecondBest().Add(
- QuicBandwidth::FromBitsPerSecond(50));
- // Latest sample was recorded at 100ms.
- QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(101));
- windowed_max_bw_.Update(bw_sample, now);
- EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
- EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest());
- EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(900), windowed_max_bw_.GetBest());
-}
-
-TEST_F(WindowedFilterTest, SampleChangesAllMins) {
- InitializeMinFilter();
- // RTT sample lower than the first-choice min-rtt sets that and also
- // the second and third-choice mins.
- QuicTime::Delta rtt_sample = windowed_min_rtt_.GetBest().Subtract(
- QuicTime::Delta::FromMilliseconds(5));
- // This assert is necessary to avoid triggering -Wstrict-overflow
- // See crbug/616957
- ASSERT_GT(windowed_min_rtt_.GetBest(), QuicTime::Delta::FromMilliseconds(5));
- // Latest sample was recorded at 100ms.
- QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(101));
- windowed_min_rtt_.Update(rtt_sample, now);
- EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
- EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest());
- EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetBest());
-}
-
-TEST_F(WindowedFilterTest, SampleChangesAllMaxs) {
- InitializeMaxFilter();
- // BW sample higher than the first-choice max sets that and also
- // the second and third-choice maxs.
- QuicBandwidth bw_sample =
- windowed_max_bw_.GetBest().Add(QuicBandwidth::FromBitsPerSecond(50));
- // Latest sample was recorded at 100ms.
- QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(101));
- windowed_max_bw_.Update(bw_sample, now);
- EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
- EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest());
- EXPECT_EQ(bw_sample, windowed_max_bw_.GetBest());
-}
-
-TEST_F(WindowedFilterTest, ExpireBestMin) {
- InitializeMinFilter();
- QuicTime::Delta old_third_best = windowed_min_rtt_.GetThirdBest();
- QuicTime::Delta old_second_best = windowed_min_rtt_.GetSecondBest();
- QuicTime::Delta rtt_sample =
- old_third_best.Add(QuicTime::Delta::FromMilliseconds(5));
- // Best min sample was recorded at 25ms, so expiry time is 124ms.
- QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(125));
- windowed_min_rtt_.Update(rtt_sample, now);
- EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
- EXPECT_EQ(old_third_best, windowed_min_rtt_.GetSecondBest());
- EXPECT_EQ(old_second_best, windowed_min_rtt_.GetBest());
-}
-
-TEST_F(WindowedFilterTest, ExpireBestMax) {
- InitializeMaxFilter();
- QuicBandwidth old_third_best = windowed_max_bw_.GetThirdBest();
- QuicBandwidth old_second_best = windowed_max_bw_.GetSecondBest();
- QuicBandwidth bw_sample =
- old_third_best.Subtract(QuicBandwidth::FromBitsPerSecond(50));
- // Best max sample was recorded at 25ms, so expiry time is 124ms.
- QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(125));
- windowed_max_bw_.Update(bw_sample, now);
- EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
- EXPECT_EQ(old_third_best, windowed_max_bw_.GetSecondBest());
- EXPECT_EQ(old_second_best, windowed_max_bw_.GetBest());
-}
-
-TEST_F(WindowedFilterTest, ExpireSecondBestMin) {
- InitializeMinFilter();
- QuicTime::Delta old_third_best = windowed_min_rtt_.GetThirdBest();
- QuicTime::Delta rtt_sample =
- old_third_best.Add(QuicTime::Delta::FromMilliseconds(5));
- // Second best min sample was recorded at 75ms, so expiry time is 174ms.
- QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(175));
- windowed_min_rtt_.Update(rtt_sample, now);
- EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
- EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest());
- EXPECT_EQ(old_third_best, windowed_min_rtt_.GetBest());
-}
-
-TEST_F(WindowedFilterTest, ExpireSecondBestMax) {
- InitializeMaxFilter();
- QuicBandwidth old_third_best = windowed_max_bw_.GetThirdBest();
- QuicBandwidth bw_sample =
- old_third_best.Subtract(QuicBandwidth::FromBitsPerSecond(50));
- // Second best max sample was recorded at 75ms, so expiry time is 174ms.
- QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(175));
- windowed_max_bw_.Update(bw_sample, now);
- EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
- EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest());
- EXPECT_EQ(old_third_best, windowed_max_bw_.GetBest());
-}
-
-TEST_F(WindowedFilterTest, ExpireAllMins) {
- InitializeMinFilter();
- QuicTime::Delta rtt_sample = windowed_min_rtt_.GetThirdBest().Add(
- QuicTime::Delta::FromMilliseconds(5));
- // This assert is necessary to avoid triggering -Wstrict-overflow
- // See crbug/616957
- ASSERT_LT(windowed_min_rtt_.GetThirdBest(),
- QuicTime::Delta::Infinite().Subtract(
- QuicTime::Delta::FromMilliseconds(5)));
- // Third best min sample was recorded at 100ms, so expiry time is 199ms.
- QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(200));
- windowed_min_rtt_.Update(rtt_sample, now);
- EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
- EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest());
- EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetBest());
-}
-
-TEST_F(WindowedFilterTest, ExpireAllMaxs) {
- InitializeMaxFilter();
- QuicBandwidth bw_sample = windowed_max_bw_.GetThirdBest().Subtract(
- QuicBandwidth::FromBitsPerSecond(50));
- // Third best max sample was recorded at 100ms, so expiry time is 199ms.
- QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(200));
- windowed_max_bw_.Update(bw_sample, now);
- EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
- EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest());
- EXPECT_EQ(bw_sample, windowed_max_bw_.GetBest());
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/cubic.cc b/chromium/net/quic/core/congestion_control/cubic.cc
new file mode 100644
index 00000000000..89a347e7e8e
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/cubic.cc
@@ -0,0 +1,190 @@
+// 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 <stdint.h>
+#include <algorithm>
+#include <cmath>
+
+#include "base/logging.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+
+using std::max;
+using std::min;
+
+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()) {
+ Reset();
+}
+
+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_;
+}
+
+void Cubic::Reset() {
+ 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();
+}
+
+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>(kBetaLastMax * 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) {
+ acked_packets_count_ += 1; // Packets acked.
+ epoch_packets_count_ += 1;
+ QuicTime current_time = clock_->ApproximateNow();
+
+ // Cubic is "independent" of RTT, the update is limited by the time elapsed.
+ if (last_congestion_window_ == current_congestion_window &&
+ (current_time - last_update_time_ <= MaxCubicTimeInterval())) {
+ return max(last_target_congestion_window_,
+ estimated_tcp_congestion_window_);
+ }
+ last_congestion_window_ = current_congestion_window;
+ last_update_time_ = current_time;
+
+ if (!epoch_.IsInitialized()) {
+ // First ACK after a loss event.
+ epoch_ = current_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.
+ int64_t elapsed_time =
+ ((current_time + delay_min - epoch_).ToMicroseconds() << 10) /
+ kNumMicrosPerSecond;
+
+ int64_t offset = time_to_origin_point_ - elapsed_time;
+ QuicPacketCount delta_congestion_window =
+ (kCubeCongestionWindowScale * offset * offset * offset) >> kCubeScale;
+
+ QuicPacketCount target_congestion_window =
+ origin_point_congestion_window_ - delta_congestion_window;
+
+ if (FLAGS_quic_limit_cubic_cwnd_increase) {
+ // Limit the CWND increase to half the acked packets rounded up to the
+ // nearest packet.
+ target_congestion_window =
+ 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_;
+ }
+
+ 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
new file mode 100644
index 00000000000..30657e57c9d
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/cubic.h
@@ -0,0 +1,105 @@
+// 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_CONGESTION_CONTROL_CUBIC_H_
+#define NET_QUIC_CONGESTION_CONTROL_CUBIC_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_connection_stats.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE Cubic {
+ public:
+ explicit Cubic(const QuicClock* clock);
+
+ void SetNumConnections(int num_connections);
+
+ // Call after a timeout to reset the cubic state.
+ void Reset();
+
+ // 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);
+
+ // Call on ack arrival when sender is unable to use the available congestion
+ // window. Resets Cubic state during quiescence.
+ void OnApplicationLimited();
+
+ private:
+ static const QuicTime::Delta MaxCubicTimeInterval() {
+ return QuicTime::Delta::FromMilliseconds(30);
+ }
+
+ // Compute the TCP Cubic alpha and beta based on the current number of
+ // connections.
+ float Alpha() const;
+ float Beta() const;
+
+ 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_;
+
+ DISALLOW_COPY_AND_ASSIGN(Cubic);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_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
new file mode 100644
index 00000000000..91924b06e9f
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/cubic_bytes.cc
@@ -0,0 +1,183 @@
+// 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.
+
+#include "net/quic/core/congestion_control/cubic_bytes.h"
+
+#include <stdint.h>
+#include <algorithm>
+#include <cmath>
+
+#include "base/logging.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+
+using std::max;
+using std::min;
+
+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;
+// The cube factor for packets in bytes.
+const uint64_t kCubeFactor =
+ (UINT64_C(1) << kCubeScale) / kCubeCongestionWindowScale / kDefaultTCPMSS;
+
+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
+
+CubicBytes::CubicBytes(const QuicClock* clock)
+ : clock_(clock),
+ num_connections_(kDefaultNumConnections),
+ epoch_(QuicTime::Zero()),
+ last_update_time_(QuicTime::Zero()) {
+ Reset();
+}
+
+void CubicBytes::SetNumConnections(int num_connections) {
+ num_connections_ = num_connections;
+}
+
+float CubicBytes::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 CubicBytes::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_;
+}
+
+void CubicBytes::Reset() {
+ 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;
+ origin_point_congestion_window_ = 0;
+ time_to_origin_point_ = 0;
+ last_target_congestion_window_ = 0;
+}
+
+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
+ // using the entire window during the time since the beginning of the current
+ // "epoch" (the end of the last loss recovery period). Since
+ // application-limited periods break this assumption, we reset the epoch when
+ // in such a period. This reset effectively freezes congestion window growth
+ // through application-limited periods and allows Cubic growth to continue
+ // when the entire window is being used.
+ epoch_ = QuicTime::Zero();
+}
+
+QuicByteCount CubicBytes::CongestionWindowAfterPacketLoss(
+ QuicByteCount 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>(kBetaLastMax * current_congestion_window);
+ } else {
+ last_max_congestion_window_ = current_congestion_window;
+ }
+ epoch_ = QuicTime::Zero(); // Reset time.
+ return static_cast<int>(current_congestion_window * Beta());
+}
+
+QuicByteCount CubicBytes::CongestionWindowAfterAck(
+ QuicByteCount acked_bytes,
+ QuicByteCount current_congestion_window,
+ QuicTime::Delta delay_min) {
+ acked_bytes_count_ += acked_bytes;
+ QuicTime current_time = clock_->ApproximateNow();
+
+ // Cubic is "independent" of RTT, the update is limited by the time elapsed.
+ if (last_congestion_window_ == current_congestion_window &&
+ (current_time - last_update_time_ <= MaxCubicTimeInterval())) {
+ return max(last_target_congestion_window_,
+ estimated_tcp_congestion_window_);
+ }
+ last_congestion_window_ = current_congestion_window;
+ last_update_time_ = current_time;
+
+ if (!epoch_.IsInitialized()) {
+ // First ACK after a loss event.
+ DVLOG(1) << "Start of epoch";
+ epoch_ = current_time; // Start of epoch.
+ acked_bytes_count_ = acked_bytes; // Reset count.
+ // 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.
+ int64_t elapsed_time =
+ ((current_time + delay_min - epoch_).ToMicroseconds() << 10) /
+ kNumMicrosPerSecond;
+
+ int64_t offset = time_to_origin_point_ - elapsed_time;
+ QuicByteCount delta_congestion_window =
+ ((kCubeCongestionWindowScale * offset * offset * offset) >> kCubeScale) *
+ kDefaultTCPMSS;
+
+ QuicByteCount target_congestion_window =
+ origin_point_congestion_window_ - delta_congestion_window;
+ if (FLAGS_quic_limit_cubic_cwnd_increase) {
+ // Limit the CWND increase to half the acked bytes.
+ target_congestion_window =
+ min(target_congestion_window,
+ current_congestion_window + acked_bytes_count_ / 2);
+ }
+
+ DCHECK_LT(0u, estimated_tcp_congestion_window_);
+ // Increase the window by Alpha * 1 MSS of bytes every time we ack an
+ // estimated tcp window of bytes.
+ estimated_tcp_congestion_window_ += acked_bytes_count_ *
+ (Alpha() * kDefaultTCPMSS) /
+ estimated_tcp_congestion_window_;
+ acked_bytes_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_;
+ }
+
+ 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_bytes.h b/chromium/net/quic/core/congestion_control/cubic_bytes.h
new file mode 100644
index 00000000000..73998ad2708
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/cubic_bytes.h
@@ -0,0 +1,97 @@
+// 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.
+
+// 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_CONGESTION_CONTROL_CUBIC_BYTES_H_
+#define NET_QUIC_CONGESTION_CONTROL_CUBIC_BYTES_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_connection_stats.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE CubicBytes {
+ public:
+ explicit CubicBytes(const QuicClock* clock);
+
+ void SetNumConnections(int num_connections);
+
+ // Call after a timeout to reset the cubic state.
+ void Reset();
+
+ // 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.
+ QuicByteCount CongestionWindowAfterPacketLoss(QuicPacketCount current);
+
+ // Compute a new congestion window to use after a received ACK.
+ // Returns the new congestion window in bytes. The new congestion window
+ // follows a cubic function that depends on the time passed since last packet
+ // loss.
+ QuicByteCount CongestionWindowAfterAck(QuicByteCount acked_bytes,
+ QuicByteCount current,
+ QuicTime::Delta delay_min);
+
+ // Call on ack arrival when sender is unable to use the available congestion
+ // window. Resets Cubic state during quiescence.
+ void OnApplicationLimited();
+
+ private:
+ static const QuicTime::Delta MaxCubicTimeInterval() {
+ return QuicTime::Delta::FromMilliseconds(30);
+ }
+
+ // Compute the TCP Cubic alpha and beta based on the current number of
+ // connections.
+ float Alpha() const;
+ float Beta() const;
+
+ const QuicClock* clock_;
+
+ // Number of connections to simulate.
+ int num_connections_;
+
+ // 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.
+ QuicByteCount last_max_congestion_window_;
+
+ // Number of acked bytes since the cycle started (epoch).
+ QuicByteCount acked_bytes_count_;
+
+ // TCP Reno equivalent congestion window in packets.
+ QuicByteCount estimated_tcp_congestion_window_;
+
+ // Origin point of cubic function.
+ QuicByteCount 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.
+ QuicByteCount last_target_congestion_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(CubicBytes);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CONGESTION_CONTROL_CUBIC_BYTES_H_
diff --git a/chromium/net/quic/core/congestion_control/cubic_bytes_test.cc b/chromium/net/quic/core/congestion_control/cubic_bytes_test.cc
new file mode 100644
index 00000000000..8c5f12d48fe
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/cubic_bytes_test.cc
@@ -0,0 +1,128 @@
+// 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.
+
+#include "net/quic/core/congestion_control/cubic_bytes.h"
+
+#include "base/logging.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+const float kBeta = 0.7f; // Default Cubic backoff factor.
+const uint32_t kNumConnections = 2;
+const float kNConnectionBeta = (kNumConnections - 1 + kBeta) / kNumConnections;
+const float kNConnectionAlpha = 3 * kNumConnections * kNumConnections *
+ (1 - kNConnectionBeta) / (1 + kNConnectionBeta);
+
+class CubicBytesTest : public ::testing::Test {
+ protected:
+ CubicBytesTest()
+ : one_ms_(QuicTime::Delta::FromMilliseconds(1)),
+ hundred_ms_(QuicTime::Delta::FromMilliseconds(100)),
+ cubic_(&clock_) {}
+ const QuicTime::Delta one_ms_;
+ const QuicTime::Delta hundred_ms_;
+ MockClock clock_;
+ CubicBytes cubic_;
+};
+
+TEST_F(CubicBytesTest, AboveOrigin) {
+ // Convex growth.
+ const QuicTime::Delta rtt_min = hundred_ms_;
+ QuicByteCount current_cwnd = 10 * kDefaultTCPMSS;
+ QuicByteCount expected_cwnd =
+ current_cwnd + (FLAGS_quic_limit_cubic_cwnd_increase ? kDefaultTCPMSS / 2
+ : kDefaultTCPMSS);
+ // Initialize the state.
+ clock_.AdvanceTime(one_ms_);
+ EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck(
+ kDefaultTCPMSS, current_cwnd, rtt_min));
+ current_cwnd = expected_cwnd;
+ // Normal TCP phase.
+ for (int i = 0; i < 48; ++i) {
+ for (QuicPacketCount n = 1;
+ n < current_cwnd / kDefaultTCPMSS / kNConnectionAlpha; ++n) {
+ // Call once per ACK.
+ EXPECT_NEAR(current_cwnd, cubic_.CongestionWindowAfterAck(
+ kDefaultTCPMSS, current_cwnd, rtt_min),
+ kDefaultTCPMSS);
+ }
+ clock_.AdvanceTime(hundred_ms_);
+ current_cwnd =
+ cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, rtt_min);
+ EXPECT_NEAR(expected_cwnd, current_cwnd, kDefaultTCPMSS);
+ expected_cwnd += kDefaultTCPMSS;
+ }
+ // Cubic phase.
+ for (int i = 0; i < 52; ++i) {
+ for (QuicPacketCount n = 1; n < current_cwnd / kDefaultTCPMSS; ++n) {
+ // Call once per ACK.
+ EXPECT_NEAR(current_cwnd, cubic_.CongestionWindowAfterAck(
+ kDefaultTCPMSS, current_cwnd, rtt_min),
+ kDefaultTCPMSS);
+ }
+ clock_.AdvanceTime(hundred_ms_);
+ current_cwnd =
+ cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, rtt_min);
+ }
+ // Total time elapsed so far; add min_rtt (0.1s) here as well.
+ float elapsed_time_s = 10.0f + 0.1f;
+ // |expected_cwnd| is initial value of cwnd + K * t^3, where K = 0.4.
+ expected_cwnd =
+ 11 + (elapsed_time_s * elapsed_time_s * elapsed_time_s * 410) / 1024;
+ EXPECT_EQ(expected_cwnd, current_cwnd / kDefaultTCPMSS);
+}
+
+TEST_F(CubicBytesTest, LossEvents) {
+ const QuicTime::Delta rtt_min = hundred_ms_;
+ QuicByteCount current_cwnd = 422 * kDefaultTCPMSS;
+ QuicPacketCount expected_cwnd =
+ current_cwnd + (FLAGS_quic_limit_cubic_cwnd_increase ? kDefaultTCPMSS / 2
+ : kDefaultTCPMSS);
+ // Initialize the state.
+ clock_.AdvanceTime(one_ms_);
+ EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck(
+ kDefaultTCPMSS, current_cwnd, rtt_min));
+ expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta);
+ EXPECT_EQ(expected_cwnd,
+ cubic_.CongestionWindowAfterPacketLoss(current_cwnd));
+ expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta);
+ EXPECT_EQ(expected_cwnd,
+ cubic_.CongestionWindowAfterPacketLoss(current_cwnd));
+}
+
+TEST_F(CubicBytesTest, BelowOrigin) {
+ // Concave growth.
+ const QuicTime::Delta rtt_min = hundred_ms_;
+ QuicByteCount current_cwnd = 422 * kDefaultTCPMSS;
+ QuicPacketCount expected_cwnd =
+ current_cwnd + (FLAGS_quic_limit_cubic_cwnd_increase ? kDefaultTCPMSS / 2
+ : kDefaultTCPMSS);
+ // Initialize the state.
+ clock_.AdvanceTime(one_ms_);
+ EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck(
+ kDefaultTCPMSS, current_cwnd, rtt_min));
+ 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(kDefaultTCPMSS, current_cwnd, rtt_min);
+ // Cubic phase.
+ for (int i = 0; i < 40; ++i) {
+ clock_.AdvanceTime(hundred_ms_);
+ current_cwnd =
+ cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, rtt_min);
+ }
+ expected_cwnd =
+ FLAGS_quic_limit_cubic_cwnd_increase ? 553632 : 422 * kDefaultTCPMSS;
+ EXPECT_EQ(expected_cwnd, current_cwnd);
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/cubic_test.cc b/chromium/net/quic/core/congestion_control/cubic_test.cc
new file mode 100644
index 00000000000..ea07888a0eb
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/cubic_test.cc
@@ -0,0 +1,114 @@
+// 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 "base/logging.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+const float kBeta = 0.7f; // Default Cubic backoff factor.
+const uint32_t kNumConnections = 2;
+const float kNConnectionBeta = (kNumConnections - 1 + kBeta) / kNumConnections;
+const float kNConnectionAlpha = 3 * kNumConnections * kNumConnections *
+ (1 - kNConnectionBeta) / (1 + kNConnectionBeta);
+
+class CubicTest : public ::testing::Test {
+ protected:
+ CubicTest()
+ : one_ms_(QuicTime::Delta::FromMilliseconds(1)),
+ hundred_ms_(QuicTime::Delta::FromMilliseconds(100)),
+ cubic_(&clock_) {}
+ const QuicTime::Delta one_ms_;
+ const QuicTime::Delta hundred_ms_;
+ MockClock clock_;
+ Cubic cubic_;
+};
+
+TEST_F(CubicTest, AboveOrigin) {
+ // Convex growth.
+ const QuicTime::Delta rtt_min = hundred_ms_;
+ QuicPacketCount current_cwnd = 10;
+ QuicPacketCount expected_cwnd = current_cwnd + 1;
+ // Initialize the state.
+ clock_.AdvanceTime(one_ms_);
+ EXPECT_EQ(expected_cwnd,
+ cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min));
+ current_cwnd = expected_cwnd;
+ // Normal TCP phase.
+ for (int i = 0; i < 48; ++i) {
+ for (QuicPacketCount n = 1; n < current_cwnd / kNConnectionAlpha; ++n) {
+ // Call once per ACK.
+ EXPECT_NEAR(current_cwnd,
+ cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min), 1);
+ }
+ clock_.AdvanceTime(hundred_ms_);
+ current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min);
+ EXPECT_NEAR(expected_cwnd, current_cwnd, 1);
+ expected_cwnd++;
+ }
+ // Cubic phase.
+ for (int i = 0; i < 52; ++i) {
+ for (QuicPacketCount n = 1; n < current_cwnd; ++n) {
+ // Call once per ACK.
+ EXPECT_EQ(current_cwnd,
+ cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min));
+ }
+ clock_.AdvanceTime(hundred_ms_);
+ current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min);
+ }
+ // Total time elapsed so far; add min_rtt (0.1s) here as well.
+ float elapsed_time_s = 10.0f + 0.1f;
+ // |expected_cwnd| is initial value of cwnd + K * t^3, where K = 0.4.
+ expected_cwnd =
+ 11 + (elapsed_time_s * elapsed_time_s * elapsed_time_s * 410) / 1024;
+ EXPECT_EQ(expected_cwnd, current_cwnd);
+}
+
+TEST_F(CubicTest, LossEvents) {
+ const QuicTime::Delta rtt_min = hundred_ms_;
+ QuicPacketCount current_cwnd = 422;
+ QuicPacketCount expected_cwnd = current_cwnd + 1;
+ // Initialize the state.
+ clock_.AdvanceTime(one_ms_);
+ EXPECT_EQ(expected_cwnd,
+ cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min));
+ expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta);
+ EXPECT_EQ(expected_cwnd,
+ cubic_.CongestionWindowAfterPacketLoss(current_cwnd));
+ expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta);
+ EXPECT_EQ(expected_cwnd,
+ cubic_.CongestionWindowAfterPacketLoss(current_cwnd));
+}
+
+TEST_F(CubicTest, BelowOrigin) {
+ // Concave growth.
+ const QuicTime::Delta rtt_min = hundred_ms_;
+ QuicPacketCount current_cwnd = 422;
+ QuicPacketCount expected_cwnd = current_cwnd + 1;
+ // Initialize the state.
+ clock_.AdvanceTime(one_ms_);
+ EXPECT_EQ(expected_cwnd,
+ cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min));
+ 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);
+ // Cubic phase.
+ for (int i = 0; i < 40; ++i) {
+ clock_.AdvanceTime(hundred_ms_);
+ current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min);
+ }
+ expected_cwnd = FLAGS_quic_limit_cubic_cwnd_increase ? 399 : 422;
+ 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
new file mode 100644
index 00000000000..6c82329ab05
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/general_loss_algorithm.cc
@@ -0,0 +1,145 @@
+// Copyright 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.
+
+#include "net/quic/core/congestion_control/general_loss_algorithm.h"
+
+#include "net/quic/core/congestion_control/rtt_stats.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+namespace {
+
+// The minimum delay before a packet will be considered lost,
+// regardless of SRTT. Half of the minimum TLP, since the loss algorithm only
+// triggers when a nack has been receieved for the packet.
+static const size_t kMinLossDelayMs = 5;
+
+// Default fraction of an RTT the algorithm waits before determining a packet is
+// lost due to early retransmission by time based loss detection.
+static const int kDefaultLossDelayShift = 2;
+// Default fraction of an RTT when doing adaptive loss detection.
+static const int kDefaultAdaptiveLossDelayShift = 4;
+
+} // namespace
+
+GeneralLossAlgorithm::GeneralLossAlgorithm()
+ : loss_detection_timeout_(QuicTime::Zero()),
+ largest_sent_on_spurious_retransmit_(0),
+ loss_type_(kNack),
+ reordering_shift_(kDefaultLossDelayShift) {}
+
+GeneralLossAlgorithm::GeneralLossAlgorithm(LossDetectionType loss_type)
+ : loss_detection_timeout_(QuicTime::Zero()),
+ largest_sent_on_spurious_retransmit_(0),
+ loss_type_(loss_type),
+ reordering_shift_(loss_type == kAdaptiveTime
+ ? kDefaultAdaptiveLossDelayShift
+ : kDefaultLossDelayShift) {}
+
+LossDetectionType GeneralLossAlgorithm::GetLossDetectionType() const {
+ return loss_type_;
+}
+
+void GeneralLossAlgorithm::SetLossDetectionType(LossDetectionType loss_type) {
+ loss_detection_timeout_ = QuicTime::Zero();
+ largest_sent_on_spurious_retransmit_ = 0;
+ loss_type_ = loss_type;
+ reordering_shift_ = loss_type == kAdaptiveTime
+ ? kDefaultAdaptiveLossDelayShift
+ : kDefaultLossDelayShift;
+}
+
+// Uses nack counts to decide when packets are lost.
+void GeneralLossAlgorithm::DetectLosses(
+ const QuicUnackedPacketMap& unacked_packets,
+ QuicTime time,
+ const RttStats& rtt_stats,
+ QuicPacketNumber largest_newly_acked,
+ SendAlgorithmInterface::CongestionVector* packets_lost) {
+ loss_detection_timeout_ = QuicTime::Zero();
+ QuicTime::Delta max_rtt =
+ std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt());
+ QuicTime::Delta loss_delay =
+ std::max(QuicTime::Delta::FromMilliseconds(kMinLossDelayMs),
+ max_rtt + (max_rtt >> reordering_shift_));
+ QuicPacketNumber packet_number = unacked_packets.GetLeastUnacked();
+ for (QuicUnackedPacketMap::const_iterator it = unacked_packets.begin();
+ it != unacked_packets.end() && packet_number <= largest_newly_acked;
+ ++it, ++packet_number) {
+ if (!it->in_flight) {
+ continue;
+ }
+
+ if (loss_type_ == kNack) {
+ // FACK based loss detection.
+ if (largest_newly_acked - packet_number >=
+ kNumberOfNacksBeforeRetransmission) {
+ packets_lost->push_back(std::make_pair(packet_number, it->bytes_sent));
+ continue;
+ }
+ }
+
+ // Only early retransmit(RFC5827) when the last packet gets acked and
+ // there are retransmittable packets in flight.
+ // This also implements a timer-protected variant of FACK.
+ if ((!it->retransmittable_frames.empty() &&
+ (FLAGS_quic_largest_sent_retransmittable
+ ? unacked_packets.largest_sent_retransmittable_packet()
+ : unacked_packets.largest_sent_packet()) <=
+ largest_newly_acked) ||
+ (loss_type_ == kTime || loss_type_ == kAdaptiveTime)) {
+ QuicTime when_lost = it->sent_time + loss_delay;
+ if (time < when_lost) {
+ loss_detection_timeout_ = when_lost;
+ break;
+ }
+ packets_lost->push_back(std::make_pair(packet_number, it->bytes_sent));
+ continue;
+ }
+
+ // NACK-based loss detection allows for a max reordering window of 1 RTT.
+ if (it->sent_time + rtt_stats.smoothed_rtt() <
+ unacked_packets.GetTransmissionInfo(largest_newly_acked).sent_time) {
+ packets_lost->push_back(std::make_pair(packet_number, it->bytes_sent));
+ continue;
+ }
+ }
+}
+
+QuicTime GeneralLossAlgorithm::GetLossTimeout() const {
+ return loss_detection_timeout_;
+}
+
+void GeneralLossAlgorithm::SpuriousRetransmitDetected(
+ const QuicUnackedPacketMap& unacked_packets,
+ QuicTime time,
+ const RttStats& rtt_stats,
+ QuicPacketNumber spurious_retransmission) {
+ if (loss_type_ != kAdaptiveTime || reordering_shift_ == 0) {
+ return;
+ }
+ if (spurious_retransmission <= largest_sent_on_spurious_retransmit_) {
+ return;
+ }
+ largest_sent_on_spurious_retransmit_ = unacked_packets.largest_sent_packet();
+ // Calculate the extra time needed so this wouldn't have been declared lost.
+ // Extra time needed is based on how long it's been since the spurious
+ // retransmission was sent, because the SRTT and latest RTT may have changed.
+ QuicTime::Delta extra_time_needed =
+ time -
+ unacked_packets.GetTransmissionInfo(spurious_retransmission).sent_time;
+ // Increase the reordering fraction until enough time would be allowed.
+ QuicTime::Delta max_rtt =
+ std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt());
+ QuicTime::Delta proposed_extra_time(QuicTime::Delta::Zero());
+ do {
+ proposed_extra_time = max_rtt >> reordering_shift_;
+ --reordering_shift_;
+ } while (proposed_extra_time < extra_time_needed && reordering_shift_ > 0);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/general_loss_algorithm.h b/chromium/net/quic/core/congestion_control/general_loss_algorithm.h
new file mode 100644
index 00000000000..ccfa734c573
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/general_loss_algorithm.h
@@ -0,0 +1,74 @@
+// Copyright 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.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_GENERAL_LOSS_ALGORITHM_H_
+#define NET_QUIC_CONGESTION_CONTROL_GENERAL_LOSS_ALGORITHM_H_
+
+#include <algorithm>
+#include <map>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/congestion_control/loss_detection_interface.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+#include "net/quic/core/quic_unacked_packet_map.h"
+
+namespace net {
+
+// Class which can be configured to implement's TCP's approach of detecting loss
+// when 3 nacks have been received for a packet or with a time threshold.
+// Also implements TCP's early retransmit(RFC5827).
+class NET_EXPORT_PRIVATE GeneralLossAlgorithm : public LossDetectionInterface {
+ public:
+ // TCP retransmits after 3 nacks.
+ static const QuicPacketCount kNumberOfNacksBeforeRetransmission = 3;
+
+ GeneralLossAlgorithm();
+ explicit GeneralLossAlgorithm(LossDetectionType loss_type);
+ ~GeneralLossAlgorithm() override {}
+
+ LossDetectionType GetLossDetectionType() const override;
+
+ // Switches the loss detection type to |loss_type| and resets the loss
+ // algorithm.
+ void SetLossDetectionType(LossDetectionType loss_type);
+
+ // Uses |largest_acked| and time to decide when packets are lost.
+ void DetectLosses(
+ const QuicUnackedPacketMap& unacked_packets,
+ QuicTime time,
+ const RttStats& rtt_stats,
+ QuicPacketNumber largest_newly_acked,
+ SendAlgorithmInterface::CongestionVector* packets_lost) override;
+
+ // Returns a non-zero value when the early retransmit timer is active.
+ QuicTime GetLossTimeout() const override;
+
+ // Increases the loss detection threshold for time loss detection.
+ void SpuriousRetransmitDetected(
+ const QuicUnackedPacketMap& unacked_packets,
+ QuicTime time,
+ const RttStats& rtt_stats,
+ QuicPacketNumber spurious_retransmission) override;
+
+ int reordering_shift() const { return reordering_shift_; }
+
+ private:
+ QuicTime loss_detection_timeout_;
+ // Largest sent packet when a spurious retransmit is detected.
+ // Prevents increasing the reordering threshold multiple times per epoch.
+ QuicPacketNumber largest_sent_on_spurious_retransmit_;
+ LossDetectionType loss_type_;
+ // Fraction of a max(SRTT, latest_rtt) to permit reordering before declaring
+ // loss. Fraction calculated by shifting max(SRTT, latest_rtt) to the right
+ // by reordering_shift.
+ int reordering_shift_;
+
+ DISALLOW_COPY_AND_ASSIGN(GeneralLossAlgorithm);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CONGESTION_CONTROL_GENERAL_LOSS_ALGORITHM_H_
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
new file mode 100644
index 00000000000..107674dbdad
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -0,0 +1,390 @@
+// Copyright 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.
+
+#include "net/quic/core/congestion_control/general_loss_algorithm.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "net/quic/core/congestion_control/rtt_stats.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_unacked_packet_map.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::vector;
+
+namespace net {
+namespace test {
+namespace {
+
+// Default packet length.
+const uint32_t kDefaultLength = 1000;
+
+class GeneralLossAlgorithmTest : public ::testing::Test {
+ protected:
+ GeneralLossAlgorithmTest() {
+ rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
+ QuicTime::Delta::Zero(), clock_.Now());
+ EXPECT_LT(0, rtt_stats_.smoothed_rtt().ToMicroseconds());
+ }
+
+ ~GeneralLossAlgorithmTest() override {}
+
+ void SendDataPacket(QuicPacketNumber packet_number) {
+ QuicStreamFrame* frame = new QuicStreamFrame();
+ frame->stream_id = kHeadersStreamId;
+ SerializedPacket packet(kDefaultPathId, packet_number,
+ PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+ 0, false, false);
+ packet.retransmittable_frames.push_back(QuicFrame(frame));
+ unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(),
+ true);
+ }
+
+ void SendAckPacket(QuicPacketNumber packet_number) {
+ SerializedPacket packet(kDefaultPathId, packet_number,
+ PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+ 0, true, false);
+ unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(),
+ false);
+ }
+
+ void VerifyLosses(QuicPacketNumber largest_newly_acked,
+ QuicPacketNumber* losses_expected,
+ size_t num_losses) {
+ if (largest_newly_acked > unacked_packets_.largest_observed()) {
+ unacked_packets_.IncreaseLargestObserved(largest_newly_acked);
+ }
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ loss_algorithm_.DetectLosses(unacked_packets_, clock_.Now(), rtt_stats_,
+ largest_newly_acked, &lost_packets);
+ EXPECT_EQ(num_losses, lost_packets.size());
+ for (size_t i = 0; i < num_losses; ++i) {
+ EXPECT_EQ(lost_packets[i].first, losses_expected[i]);
+ }
+ }
+
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+ QuicUnackedPacketMap unacked_packets_;
+ GeneralLossAlgorithm loss_algorithm_;
+ RttStats rtt_stats_;
+ MockClock clock_;
+};
+
+TEST_F(GeneralLossAlgorithmTest, NackRetransmit1Packet) {
+ const size_t kNumSentPackets = 5;
+ // Transmit 5 packets.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+ // No loss on one ack.
+ unacked_packets_.RemoveFromInFlight(2);
+ VerifyLosses(2, nullptr, 0);
+ // No loss on two acks.
+ unacked_packets_.RemoveFromInFlight(3);
+ VerifyLosses(3, nullptr, 0);
+ // Loss on three acks.
+ unacked_packets_.RemoveFromInFlight(4);
+ QuicPacketNumber lost[] = {1};
+ VerifyLosses(4, lost, arraysize(lost));
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+}
+
+// A stretch ack is an ack that covers more than 1 packet of previously
+// unacknowledged data.
+TEST_F(GeneralLossAlgorithmTest, NackRetransmit1PacketWith1StretchAck) {
+ const size_t kNumSentPackets = 10;
+ // Transmit 10 packets.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+
+ // Nack the first packet 3 times in a single StretchAck.
+ unacked_packets_.RemoveFromInFlight(2);
+ unacked_packets_.RemoveFromInFlight(3);
+ unacked_packets_.RemoveFromInFlight(4);
+ QuicPacketNumber lost[] = {1};
+ VerifyLosses(4, lost, arraysize(lost));
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+}
+
+// Ack a packet 3 packets ahead, causing a retransmit.
+TEST_F(GeneralLossAlgorithmTest, NackRetransmit1PacketSingleAck) {
+ const size_t kNumSentPackets = 10;
+ // Transmit 10 packets.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+
+ // Nack the first packet 3 times in an AckFrame with three missing packets.
+ unacked_packets_.RemoveFromInFlight(4);
+ QuicPacketNumber lost[] = {1};
+ VerifyLosses(4, lost, arraysize(lost));
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+}
+
+TEST_F(GeneralLossAlgorithmTest, EarlyRetransmit1Packet) {
+ const size_t kNumSentPackets = 2;
+ // Transmit 2 packets.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+ // Early retransmit when the final packet gets acked and the first is nacked.
+ unacked_packets_.RemoveFromInFlight(2);
+ VerifyLosses(2, nullptr, 0);
+ EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
+ loss_algorithm_.GetLossTimeout());
+
+ clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt());
+ QuicPacketNumber lost[] = {1};
+ VerifyLosses(2, lost, arraysize(lost));
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+}
+
+TEST_F(GeneralLossAlgorithmTest, EarlyRetransmitAllPackets) {
+ const size_t kNumSentPackets = 5;
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ // Advance the time 1/4 RTT between 3 and 4.
+ if (i == 3) {
+ clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
+ }
+ }
+
+ // Early retransmit when the final packet gets acked and 1.25 RTTs have
+ // elapsed since the packets were sent.
+ unacked_packets_.RemoveFromInFlight(kNumSentPackets);
+ // This simulates a single ack following multiple missing packets with FACK.
+ QuicPacketNumber lost[] = {1, 2};
+ VerifyLosses(kNumSentPackets, lost, arraysize(lost));
+ // The time has already advanced 1/4 an RTT, so ensure the timeout is set
+ // 1.25 RTTs after the earliest pending packet(3), not the last(4).
+ EXPECT_EQ(clock_.Now() + rtt_stats_.smoothed_rtt(),
+ loss_algorithm_.GetLossTimeout());
+
+ clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
+ QuicPacketNumber lost2[] = {1, 2, 3};
+ VerifyLosses(kNumSentPackets, lost2, arraysize(lost2));
+ EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(),
+ loss_algorithm_.GetLossTimeout());
+ clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
+ QuicPacketNumber lost3[] = {1, 2, 3, 4};
+ VerifyLosses(kNumSentPackets, lost3, arraysize(lost3));
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+}
+
+TEST_F(GeneralLossAlgorithmTest, DontEarlyRetransmitNeuteredPacket) {
+ const size_t kNumSentPackets = 2;
+ // Transmit 2 packets.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+ // Neuter packet 1.
+ unacked_packets_.RemoveRetransmittability(1);
+
+ // Early retransmit when the final packet gets acked and the first is nacked.
+ unacked_packets_.IncreaseLargestObserved(2);
+ unacked_packets_.RemoveFromInFlight(2);
+ VerifyLosses(2, nullptr, 0);
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+}
+
+TEST_F(GeneralLossAlgorithmTest, EarlyRetransmitWithLargerUnackablePackets) {
+ FLAGS_quic_largest_sent_retransmittable = true;
+ // Transmit 2 data packets and one ack.
+ SendDataPacket(1);
+ SendDataPacket(2);
+ SendAckPacket(3);
+ clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
+
+ // Early retransmit when the final packet gets acked and the first is nacked.
+ unacked_packets_.IncreaseLargestObserved(2);
+ unacked_packets_.RemoveFromInFlight(2);
+ VerifyLosses(2, nullptr, 0);
+ EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(),
+ loss_algorithm_.GetLossTimeout());
+
+ // The packet should be lost once the loss timeout is reached.
+ clock_.AdvanceTime(0.25 * rtt_stats_.latest_rtt());
+ QuicPacketNumber lost[] = {1};
+ VerifyLosses(2, lost, arraysize(lost));
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+}
+
+TEST_F(GeneralLossAlgorithmTest, AlwaysLosePacketSent1RTTEarlier) {
+ // Transmit 1 packet and then wait an rtt plus 1ms.
+ SendDataPacket(1);
+ clock_.AdvanceTime(rtt_stats_.smoothed_rtt() +
+ QuicTime::Delta::FromMilliseconds(1));
+
+ // Transmit 2 packets.
+ SendDataPacket(2);
+ SendDataPacket(3);
+
+ // Wait another RTT and ack 2.
+ clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
+ unacked_packets_.IncreaseLargestObserved(2);
+ unacked_packets_.RemoveFromInFlight(2);
+ QuicPacketNumber lost[] = {1};
+ VerifyLosses(2, lost, arraysize(lost));
+}
+
+// Time-based loss detection tests.
+TEST_F(GeneralLossAlgorithmTest, NoLossFor500Nacks) {
+ loss_algorithm_.SetLossDetectionType(kTime);
+ const size_t kNumSentPackets = 5;
+ // Transmit 5 packets.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+ unacked_packets_.RemoveFromInFlight(2);
+ for (size_t i = 1; i < 500; ++i) {
+ VerifyLosses(2, nullptr, 0);
+ }
+ EXPECT_EQ(1.25 * rtt_stats_.smoothed_rtt(),
+ loss_algorithm_.GetLossTimeout() - clock_.Now());
+}
+
+TEST_F(GeneralLossAlgorithmTest, NoLossUntilTimeout) {
+ loss_algorithm_.SetLossDetectionType(kTime);
+ const size_t kNumSentPackets = 10;
+ // Transmit 10 packets at 1/10th an RTT interval.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt());
+ }
+ // Expect the timer to not be set.
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+ // The packet should not be lost until 1.25 RTTs pass.
+ unacked_packets_.RemoveFromInFlight(2);
+ VerifyLosses(2, nullptr, 0);
+ // Expect the timer to be set to 0.25 RTT's in the future.
+ EXPECT_EQ(0.25 * rtt_stats_.smoothed_rtt(),
+ loss_algorithm_.GetLossTimeout() - clock_.Now());
+ VerifyLosses(2, nullptr, 0);
+ clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
+ QuicPacketNumber lost[] = {1};
+ VerifyLosses(2, lost, arraysize(lost));
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+}
+
+TEST_F(GeneralLossAlgorithmTest, NoLossWithoutNack) {
+ loss_algorithm_.SetLossDetectionType(kTime);
+ const size_t kNumSentPackets = 10;
+ // Transmit 10 packets at 1/10th an RTT interval.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt());
+ }
+ // Expect the timer to not be set.
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+ // The packet should not be lost without a nack.
+ unacked_packets_.RemoveFromInFlight(1);
+ VerifyLosses(1, nullptr, 0);
+ // The timer should still not be set.
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+ clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
+ VerifyLosses(1, nullptr, 0);
+ clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
+ VerifyLosses(1, nullptr, 0);
+
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+}
+
+TEST_F(GeneralLossAlgorithmTest, MultipleLossesAtOnce) {
+ loss_algorithm_.SetLossDetectionType(kTime);
+ const size_t kNumSentPackets = 10;
+ // Transmit 10 packets at once and then go forward an RTT.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+ clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
+ // Expect the timer to not be set.
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+ // The packet should not be lost until 1.25 RTTs pass.
+ unacked_packets_.RemoveFromInFlight(10);
+ VerifyLosses(10, nullptr, 0);
+ // Expect the timer to be set to 0.25 RTT's in the future.
+ EXPECT_EQ(0.25 * rtt_stats_.smoothed_rtt(),
+ loss_algorithm_.GetLossTimeout() - clock_.Now());
+ clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
+ QuicPacketNumber lost[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+ VerifyLosses(10, lost, arraysize(lost));
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+}
+
+TEST_F(GeneralLossAlgorithmTest, NoSpuriousLossesFromLargeReordering) {
+ loss_algorithm_.SetLossDetectionType(kTime);
+ const size_t kNumSentPackets = 10;
+ // Transmit 10 packets at once and then go forward an RTT.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+ clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
+ // Expect the timer to not be set.
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+ // The packet should not be lost until 1.25 RTTs pass.
+
+ unacked_packets_.RemoveFromInFlight(10);
+ VerifyLosses(10, nullptr, 0);
+ // Expect the timer to be set to 0.25 RTT's in the future.
+ EXPECT_EQ(0.25 * rtt_stats_.smoothed_rtt(),
+ loss_algorithm_.GetLossTimeout() - clock_.Now());
+ clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
+ // Now ack packets 1 to 9 and ensure the timer is no longer set and no packets
+ // are lost.
+ for (QuicPacketNumber i = 1; i <= 9; ++i) {
+ unacked_packets_.RemoveFromInFlight(i);
+ VerifyLosses(i, nullptr, 0);
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+ }
+}
+
+TEST_F(GeneralLossAlgorithmTest, IncreaseThresholdUponSpuriousLoss) {
+ loss_algorithm_.SetLossDetectionType(kAdaptiveTime);
+ EXPECT_EQ(4, loss_algorithm_.reordering_shift());
+ const size_t kNumSentPackets = 10;
+ // Transmit 2 packets at 1/10th an RTT interval.
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt());
+ }
+ EXPECT_EQ(QuicTime::Zero() + rtt_stats_.smoothed_rtt(), clock_.Now());
+
+ // Expect the timer to not be set.
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+ // Packet 1 should not be lost until 1/16 RTTs pass.
+ unacked_packets_.RemoveFromInFlight(2);
+ VerifyLosses(2, nullptr, 0);
+ // Expect the timer to be set to 1/16 RTT's in the future.
+ EXPECT_EQ(rtt_stats_.smoothed_rtt() * (1.0f / 16),
+ loss_algorithm_.GetLossTimeout() - clock_.Now());
+ VerifyLosses(2, nullptr, 0);
+ clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 16));
+ QuicPacketNumber lost[] = {1};
+ VerifyLosses(2, lost, arraysize(lost));
+ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+ // Retransmit packet 1 as 11 and 2 as 12.
+ SendDataPacket(11);
+ SendDataPacket(12);
+
+ // 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));
+ loss_algorithm_.SpuriousRetransmitDetected(unacked_packets_, clock_.Now(),
+ rtt_stats_, 11);
+ EXPECT_EQ(1, loss_algorithm_.reordering_shift());
+
+ // Detect another spurious retransmit and ensure the threshold doesn't
+ // increase again.
+ loss_algorithm_.SpuriousRetransmitDetected(unacked_packets_, clock_.Now(),
+ rtt_stats_, 12);
+ EXPECT_EQ(1, loss_algorithm_.reordering_shift());
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/hybrid_slow_start.cc b/chromium/net/quic/core/congestion_control/hybrid_slow_start.cc
new file mode 100644
index 00000000000..3224cd67cf6
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/hybrid_slow_start.cc
@@ -0,0 +1,107 @@
+// 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/hybrid_slow_start.h"
+
+#include <algorithm>
+
+using std::max;
+using std::min;
+
+namespace net {
+
+// Note(pwestin): the magic clamping numbers come from the original code in
+// tcp_cubic.c.
+const int64_t kHybridStartLowWindow = 16;
+// Number of delay samples for detecting the increase of delay.
+const uint32_t kHybridStartMinSamples = 8;
+// Exit slow start if the min rtt has increased by more than 1/8th.
+const int kHybridStartDelayFactorExp = 3; // 2^3 = 8
+// The original paper specifies 2 and 8ms, but those have changed over time.
+const int64_t kHybridStartDelayMinThresholdUs = 4000;
+const int64_t kHybridStartDelayMaxThresholdUs = 16000;
+
+HybridSlowStart::HybridSlowStart()
+ : started_(false),
+ hystart_found_(NOT_FOUND),
+ last_sent_packet_number_(0),
+ end_packet_number_(0),
+ rtt_sample_count_(0),
+ current_min_rtt_(QuicTime::Delta::Zero()) {}
+
+void HybridSlowStart::OnPacketAcked(QuicPacketNumber acked_packet_number) {
+ // OnPacketAcked gets invoked after ShouldExitSlowStart, so it's best to end
+ // the round when the final packet of the burst is received and start it on
+ // the next incoming ack.
+ if (IsEndOfRound(acked_packet_number)) {
+ started_ = false;
+ }
+}
+
+void HybridSlowStart::OnPacketSent(QuicPacketNumber packet_number) {
+ last_sent_packet_number_ = packet_number;
+}
+
+void HybridSlowStart::Restart() {
+ started_ = false;
+ hystart_found_ = NOT_FOUND;
+}
+
+void HybridSlowStart::StartReceiveRound(QuicPacketNumber last_sent) {
+ DVLOG(1) << "Reset hybrid slow start @" << last_sent;
+ end_packet_number_ = last_sent;
+ current_min_rtt_ = QuicTime::Delta::Zero();
+ rtt_sample_count_ = 0;
+ started_ = true;
+}
+
+bool HybridSlowStart::IsEndOfRound(QuicPacketNumber ack) const {
+ return end_packet_number_ <= ack;
+}
+
+bool HybridSlowStart::ShouldExitSlowStart(QuicTime::Delta latest_rtt,
+ QuicTime::Delta min_rtt,
+ QuicPacketCount congestion_window) {
+ if (!started_) {
+ // Time to start the hybrid slow start.
+ StartReceiveRound(last_sent_packet_number_);
+ }
+ if (hystart_found_ != NOT_FOUND) {
+ return true;
+ }
+ // Second detection parameter - delay increase detection.
+ // Compare the minimum delay (current_min_rtt_) of the current
+ // burst of packets relative to the minimum delay during the session.
+ // Note: we only look at the first few(8) packets in each burst, since we
+ // only want to compare the lowest RTT of the burst relative to previous
+ // bursts.
+ rtt_sample_count_++;
+ if (rtt_sample_count_ <= kHybridStartMinSamples) {
+ if (current_min_rtt_.IsZero() || current_min_rtt_ > latest_rtt) {
+ current_min_rtt_ = latest_rtt;
+ }
+ }
+ // We only need to check this once per round.
+ if (rtt_sample_count_ == kHybridStartMinSamples) {
+ // Divide min_rtt by 8 to get a rtt increase threshold for exiting.
+ int64_t min_rtt_increase_threshold_us =
+ min_rtt.ToMicroseconds() >> kHybridStartDelayFactorExp;
+ // Ensure the rtt threshold is never less than 2ms or more than 16ms.
+ min_rtt_increase_threshold_us =
+ min(min_rtt_increase_threshold_us, kHybridStartDelayMaxThresholdUs);
+ QuicTime::Delta min_rtt_increase_threshold =
+ QuicTime::Delta::FromMicroseconds(max(min_rtt_increase_threshold_us,
+ kHybridStartDelayMinThresholdUs));
+
+ if (current_min_rtt_ > min_rtt + min_rtt_increase_threshold) {
+ hystart_found_ = DELAY;
+ }
+ }
+ // Exit from slow start if the cwnd is greater than 16 and
+ // increasing delay is found.
+ return congestion_window >= kHybridStartLowWindow &&
+ hystart_found_ != NOT_FOUND;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/hybrid_slow_start.h b/chromium/net/quic/core/congestion_control/hybrid_slow_start.h
new file mode 100644
index 00000000000..1ca14484e14
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/hybrid_slow_start.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This class is a helper class to TcpCubicSender.
+// Slow start is the initial startup phase of TCP, it lasts until first packet
+// loss. This class implements hybrid slow start of the TCP cubic send side
+// congestion algorithm. The key feaure of hybrid slow start is that it tries to
+// avoid running into the wall too hard during the slow start phase, which
+// the traditional TCP implementation does.
+// This does not implement ack train detection because it interacts poorly with
+// pacing.
+// http://netsrv.csc.ncsu.edu/export/hybridstart_pfldnet08.pdf
+// http://research.csc.ncsu.edu/netsrv/sites/default/files/hystart_techreport_2008.pdf
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_HYBRID_SLOW_START_H_
+#define NET_QUIC_CONGESTION_CONTROL_HYBRID_SLOW_START_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE HybridSlowStart {
+ public:
+ HybridSlowStart();
+
+ void OnPacketAcked(QuicPacketNumber acked_packet_number);
+
+ void OnPacketSent(QuicPacketNumber packet_number);
+
+ // ShouldExitSlowStart should be called on every new ack frame, since a new
+ // RTT measurement can be made then.
+ // rtt: the RTT for this ack packet.
+ // min_rtt: is the lowest delay (RTT) we have seen during the session.
+ // congestion_window: the congestion window in packets.
+ bool ShouldExitSlowStart(QuicTime::Delta rtt,
+ QuicTime::Delta min_rtt,
+ QuicPacketCount congestion_window);
+
+ // Start a new slow start phase.
+ void Restart();
+
+ // TODO(ianswett): The following methods should be private, but that requires
+ // a follow up CL to update the unit test.
+ // Returns true if this ack the last packet number of our current slow start
+ // round.
+ // Call Reset if this returns true.
+ bool IsEndOfRound(QuicPacketNumber ack) const;
+
+ // Call for the start of each receive round (burst) in the slow start phase.
+ void StartReceiveRound(QuicPacketNumber last_sent);
+
+ // Whether slow start has started.
+ bool started() const { return started_; }
+
+ private:
+ // Whether a condition for exiting slow start has been found.
+ enum HystartState {
+ NOT_FOUND,
+ DELAY, // Too much increase in the round's min_rtt was observed.
+ };
+
+ // Whether the hybrid slow start has been started.
+ bool started_;
+ HystartState hystart_found_;
+ // Last packet number sent which was CWND limited.
+ QuicPacketNumber last_sent_packet_number_;
+
+ // Variables for tracking acks received during a slow start round.
+ QuicPacketNumber end_packet_number_; // End of the receive round.
+ uint32_t rtt_sample_count_; // Number of rtt samples in the current round.
+ QuicTime::Delta current_min_rtt_; // The minimum rtt of current round.
+
+ DISALLOW_COPY_AND_ASSIGN(HybridSlowStart);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CONGESTION_CONTROL_HYBRID_SLOW_START_H_
diff --git a/chromium/net/quic/core/congestion_control/hybrid_slow_start_test.cc b/chromium/net/quic/core/congestion_control/hybrid_slow_start_test.cc
new file mode 100644
index 00000000000..7a580fac421
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/hybrid_slow_start_test.cc
@@ -0,0 +1,76 @@
+// 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/hybrid_slow_start.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+class HybridSlowStartTest : public ::testing::Test {
+ protected:
+ HybridSlowStartTest()
+ : one_ms_(QuicTime::Delta::FromMilliseconds(1)),
+ rtt_(QuicTime::Delta::FromMilliseconds(60)) {}
+ void SetUp() override { slow_start_.reset(new HybridSlowStart()); }
+ const QuicTime::Delta one_ms_;
+ const QuicTime::Delta rtt_;
+ std::unique_ptr<HybridSlowStart> slow_start_;
+};
+
+TEST_F(HybridSlowStartTest, Simple) {
+ QuicPacketNumber packet_number = 1;
+ QuicPacketNumber end_packet_number = 3;
+ slow_start_->StartReceiveRound(end_packet_number);
+
+ EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number++));
+
+ // Test duplicates.
+ EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number));
+
+ EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number++));
+ EXPECT_TRUE(slow_start_->IsEndOfRound(packet_number++));
+
+ // Test without a new registered end_packet_number;
+ EXPECT_TRUE(slow_start_->IsEndOfRound(packet_number++));
+
+ end_packet_number = 20;
+ slow_start_->StartReceiveRound(end_packet_number);
+ while (packet_number < end_packet_number) {
+ EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number++));
+ }
+ EXPECT_TRUE(slow_start_->IsEndOfRound(packet_number++));
+}
+
+TEST_F(HybridSlowStartTest, Delay) {
+ // We expect to detect the increase at +1/8 of the RTT; hence at a typical
+ // RTT of 60ms the detection will happen at 67.5 ms.
+ const int kHybridStartMinSamples = 8; // Number of acks required to trigger.
+
+ QuicPacketNumber end_packet_number = 1;
+ slow_start_->StartReceiveRound(end_packet_number++);
+
+ // Will not trigger since our lowest RTT in our burst is the same as the long
+ // term RTT provided.
+ for (int n = 0; n < kHybridStartMinSamples; ++n) {
+ EXPECT_FALSE(slow_start_->ShouldExitSlowStart(
+ rtt_ + QuicTime::Delta::FromMilliseconds(n), rtt_, 100));
+ }
+ slow_start_->StartReceiveRound(end_packet_number++);
+ for (int n = 1; n < kHybridStartMinSamples; ++n) {
+ EXPECT_FALSE(slow_start_->ShouldExitSlowStart(
+ rtt_ + QuicTime::Delta::FromMilliseconds(n + 10), rtt_, 100));
+ }
+ // Expect to trigger since all packets in this burst was above the long term
+ // RTT provided.
+ EXPECT_TRUE(slow_start_->ShouldExitSlowStart(
+ rtt_ + QuicTime::Delta::FromMilliseconds(10), rtt_, 100));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/loss_detection_interface.h b/chromium/net/quic/core/congestion_control/loss_detection_interface.h
new file mode 100644
index 00000000000..5fce89f683b
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/loss_detection_interface.h
@@ -0,0 +1,49 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The pure virtual class for send side loss detection algorithm.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_LOSS_DETECTION_INTERFACE_H_
+#define NET_QUIC_CONGESTION_CONTROL_LOSS_DETECTION_INTERFACE_H_
+
+#include "net/base/net_export.h"
+#include "net/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+class QuicUnackedPacketMap;
+class RttStats;
+
+class NET_EXPORT_PRIVATE LossDetectionInterface {
+ public:
+ virtual ~LossDetectionInterface() {}
+
+ virtual LossDetectionType GetLossDetectionType() const = 0;
+
+ // Called when a new ack arrives or the loss alarm fires.
+ virtual void DetectLosses(
+ const QuicUnackedPacketMap& unacked_packets,
+ QuicTime time,
+ const RttStats& rtt_stats,
+ QuicPacketNumber largest_newly_acked,
+ SendAlgorithmInterface::CongestionVector* packets_lost) = 0;
+
+ // Get the time the LossDetectionAlgorithm wants to re-evaluate losses.
+ // Returns QuicTime::Zero if no alarm needs to be set.
+ virtual QuicTime GetLossTimeout() const = 0;
+
+ // Called when a |spurious_retransmission| is detected. The original
+ // transmission must have been caused by DetectLosses.
+ virtual void SpuriousRetransmitDetected(
+ const QuicUnackedPacketMap& unacked_packets,
+ QuicTime time,
+ const RttStats& rtt_stats,
+ QuicPacketNumber spurious_retransmission) = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CONGESTION_CONTROL_LOSS_DETECTION_INTERFACE_H_
diff --git a/chromium/net/quic/core/congestion_control/pacing_sender.cc b/chromium/net/quic/core/congestion_control/pacing_sender.cc
new file mode 100644
index 00000000000..cc2c40b8cb3
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/pacing_sender.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2013 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/pacing_sender.h"
+
+#include <string>
+
+#include "net/quic/core/quic_flags.h"
+
+using std::min;
+
+namespace net {
+namespace {
+
+// The estimated system alarm granularity.
+static const QuicTime::Delta kAlarmGranularity =
+ QuicTime::Delta::FromMilliseconds(1);
+
+// Configured maximum size of the burst coming out of quiescence. The burst
+// is never larger than the current CWND in packets.
+static const uint32_t kInitialUnpacedBurst = 10;
+
+} // namespace
+
+PacingSender::PacingSender()
+ : sender_(nullptr),
+ max_pacing_rate_(QuicBandwidth::Zero()),
+ burst_tokens_(kInitialUnpacedBurst),
+ last_delayed_packet_sent_time_(QuicTime::Zero()),
+ ideal_next_packet_send_time_(QuicTime::Zero()),
+ was_last_send_delayed_(false) {}
+
+PacingSender::~PacingSender() {}
+
+void PacingSender::set_sender(SendAlgorithmInterface* sender) {
+ DCHECK(sender != nullptr);
+ sender_ = sender;
+}
+
+void PacingSender::OnCongestionEvent(
+ bool rtt_updated,
+ QuicByteCount bytes_in_flight,
+ const SendAlgorithmInterface::CongestionVector& acked_packets,
+ const SendAlgorithmInterface::CongestionVector& lost_packets) {
+ DCHECK(sender_ != nullptr);
+ if (!lost_packets.empty()) {
+ // Clear any burst tokens when entering recovery.
+ burst_tokens_ = 0;
+ }
+ sender_->OnCongestionEvent(rtt_updated, bytes_in_flight, acked_packets,
+ lost_packets);
+}
+
+bool PacingSender::OnPacketSent(
+ QuicTime sent_time,
+ QuicByteCount bytes_in_flight,
+ QuicPacketNumber packet_number,
+ QuicByteCount bytes,
+ HasRetransmittableData has_retransmittable_data) {
+ DCHECK(sender_ != nullptr);
+ const bool in_flight =
+ sender_->OnPacketSent(sent_time, bytes_in_flight, packet_number, bytes,
+ has_retransmittable_data);
+ if (has_retransmittable_data != HAS_RETRANSMITTABLE_DATA) {
+ return in_flight;
+ }
+ // If in recovery, the connection is not coming out of quiescence.
+ if (bytes_in_flight == 0 && !sender_->InRecovery()) {
+ // Add more burst tokens anytime the connection is leaving quiescence, but
+ // limit it to the equivalent of a single bulk write, not exceeding the
+ // current CWND in packets.
+ burst_tokens_ = min(
+ kInitialUnpacedBurst,
+ static_cast<uint32_t>(sender_->GetCongestionWindow() / kDefaultTCPMSS));
+ }
+ if (burst_tokens_ > 0) {
+ --burst_tokens_;
+ was_last_send_delayed_ = false;
+ last_delayed_packet_sent_time_ = QuicTime::Zero();
+ ideal_next_packet_send_time_ = QuicTime::Zero();
+ return in_flight;
+ }
+ // The next packet should be sent as soon as the current packet has been
+ // transferred. PacingRate is based on bytes in flight including this packet.
+ QuicTime::Delta delay =
+ PacingRate(bytes_in_flight + bytes).TransferTime(bytes);
+ // If the last send was delayed, and the alarm took a long time to get
+ // invoked, allow the connection to make up for lost time.
+ if (was_last_send_delayed_) {
+ ideal_next_packet_send_time_ = ideal_next_packet_send_time_ + delay;
+ // The send was application limited if it takes longer than the
+ // pacing delay between sent packets.
+ const bool application_limited =
+ last_delayed_packet_sent_time_.IsInitialized() &&
+ sent_time > last_delayed_packet_sent_time_ + delay;
+ const bool making_up_for_lost_time =
+ ideal_next_packet_send_time_ <= sent_time;
+ // As long as we're making up time and not application limited,
+ // continue to consider the packets delayed, allowing the packets to be
+ // sent immediately.
+ if (making_up_for_lost_time && !application_limited) {
+ last_delayed_packet_sent_time_ = sent_time;
+ } else {
+ was_last_send_delayed_ = false;
+ last_delayed_packet_sent_time_ = QuicTime::Zero();
+ }
+ } else {
+ ideal_next_packet_send_time_ =
+ std::max(ideal_next_packet_send_time_ + delay, sent_time + delay);
+ }
+ return in_flight;
+}
+
+QuicTime::Delta PacingSender::TimeUntilSend(
+ QuicTime now,
+ QuicByteCount bytes_in_flight) const {
+ DCHECK(sender_ != nullptr);
+ QuicTime::Delta time_until_send =
+ sender_->TimeUntilSend(now, bytes_in_flight);
+ if (burst_tokens_ > 0 || bytes_in_flight == 0) {
+ // Don't pace if we have burst tokens available or leaving quiescence.
+ return time_until_send;
+ }
+
+ if (!time_until_send.IsZero()) {
+ DCHECK(time_until_send.IsInfinite());
+ // The underlying sender prevents sending.
+ return time_until_send;
+ }
+
+ // If the next send time is within the alarm granularity, send immediately.
+ if (ideal_next_packet_send_time_ > now + kAlarmGranularity) {
+ DVLOG(1) << "Delaying packet: "
+ << (ideal_next_packet_send_time_ - now).ToMicroseconds();
+ was_last_send_delayed_ = true;
+ return ideal_next_packet_send_time_ - now;
+ }
+
+ DVLOG(1) << "Sending packet now";
+ return QuicTime::Delta::Zero();
+}
+
+QuicBandwidth PacingSender::PacingRate(QuicByteCount bytes_in_flight) const {
+ DCHECK(sender_ != nullptr);
+ if (!max_pacing_rate_.IsZero()) {
+ return QuicBandwidth::FromBitsPerSecond(
+ min(max_pacing_rate_.ToBitsPerSecond(),
+ sender_->PacingRate(bytes_in_flight).ToBitsPerSecond()));
+ }
+ return sender_->PacingRate(bytes_in_flight);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/pacing_sender.h b/chromium/net/quic/core/congestion_control/pacing_sender.h
new file mode 100644
index 00000000000..21fbb4c59ef
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/pacing_sender.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2013 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.
+//
+// A send algorithm that adds pacing on top of an another send algorithm.
+// It uses the underlying sender's pacing rate to schedule packets.
+// It also takes into consideration the expected granularity of the underlying
+// alarm to ensure that alarms are not set too aggressively, and err towards
+// sending packets too early instead of too late.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_PACING_SENDER_H_
+#define NET_QUIC_CONGESTION_CONTROL_PACING_SENDER_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE PacingSender {
+ public:
+ PacingSender();
+ ~PacingSender();
+
+ // Sets the underlying sender. Does not take ownership of |sender|. |sender|
+ // must not be null. This must be called before any of the
+ // SendAlgorithmInterface wrapper methods are called.
+ void set_sender(SendAlgorithmInterface* sender);
+
+ void set_max_pacing_rate(QuicBandwidth max_pacing_rate) {
+ max_pacing_rate_ = max_pacing_rate;
+ }
+
+ void OnCongestionEvent(
+ bool rtt_updated,
+ QuicByteCount bytes_in_flight,
+ const SendAlgorithmInterface::CongestionVector& acked_packets,
+ const SendAlgorithmInterface::CongestionVector& lost_packets);
+ bool OnPacketSent(QuicTime sent_time,
+ QuicByteCount bytes_in_flight,
+ QuicPacketNumber packet_number,
+ QuicByteCount bytes,
+ HasRetransmittableData is_retransmittable);
+ QuicTime::Delta TimeUntilSend(QuicTime now,
+ QuicByteCount bytes_in_flight) const;
+ QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const;
+
+ private:
+ // Underlying sender. Not owned.
+ SendAlgorithmInterface* sender_;
+ // If not QuicBandidth::Zero, the maximum rate the PacingSender will use.
+ QuicBandwidth max_pacing_rate_;
+
+ // Number of unpaced packets to be sent before packets are delayed.
+ uint32_t burst_tokens_;
+ // Send time of the last packet considered delayed.
+ QuicTime last_delayed_packet_sent_time_;
+ QuicTime ideal_next_packet_send_time_; // When can the next packet be sent.
+ mutable bool was_last_send_delayed_; // True when the last send was delayed.
+
+ DISALLOW_COPY_AND_ASSIGN(PacingSender);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CONGESTION_CONTROL_PACING_SENDER_H_
diff --git a/chromium/net/quic/core/congestion_control/pacing_sender_test.cc b/chromium/net/quic/core/congestion_control/pacing_sender_test.cc
new file mode 100644
index 00000000000..2a6073f9019
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/pacing_sender_test.cc
@@ -0,0 +1,349 @@
+// Copyright (c) 2013 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/pacing_sender.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Return;
+using testing::StrictMock;
+using testing::_;
+
+namespace net {
+namespace test {
+
+const QuicByteCount kBytesInFlight = 1024;
+const int kInitialBurstPackets = 10;
+
+class PacingSenderTest : public ::testing::Test {
+ protected:
+ PacingSenderTest()
+ : zero_time_(QuicTime::Delta::Zero()),
+ infinite_time_(QuicTime::Delta::Infinite()),
+ packet_number_(1),
+ mock_sender_(new StrictMock<MockSendAlgorithm>()),
+ pacing_sender_(new PacingSender) {
+ pacing_sender_->set_sender(mock_sender_.get());
+ // Pick arbitrary time.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(9));
+ }
+
+ ~PacingSenderTest() override {}
+
+ void InitPacingRate(QuicPacketCount burst_size, QuicBandwidth bandwidth) {
+ mock_sender_.reset(new StrictMock<MockSendAlgorithm>());
+ pacing_sender_.reset(new PacingSender);
+ pacing_sender_->set_sender(mock_sender_.get());
+ EXPECT_CALL(*mock_sender_, PacingRate(_)).WillRepeatedly(Return(bandwidth));
+ if (burst_size == 0) {
+ EXPECT_CALL(*mock_sender_, OnCongestionEvent(_, _, _, _));
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
+ SendAlgorithmInterface::CongestionVector empty;
+ pacing_sender_->OnCongestionEvent(true, 1234, empty, lost_packets);
+ } else if (burst_size != kInitialBurstPackets) {
+ LOG(FATAL) << "Unsupported burst_size " << burst_size
+ << " specificied, only 0 and " << kInitialBurstPackets
+ << " are supported.";
+ }
+ }
+
+ void CheckPacketIsSentImmediately(HasRetransmittableData retransmittable_data,
+ QuicByteCount bytes_in_flight,
+ bool in_recovery) {
+ // In order for the packet to be sendable, the underlying sender must
+ // permit it to be sent immediately.
+ for (int i = 0; i < 2; ++i) {
+ EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(), bytes_in_flight))
+ .WillOnce(Return(zero_time_));
+ // Verify that the packet can be sent immediately.
+ EXPECT_EQ(zero_time_,
+ pacing_sender_->TimeUntilSend(clock_.Now(), bytes_in_flight));
+ }
+
+ // Actually send the packet.
+ if (bytes_in_flight == 0) {
+ EXPECT_CALL(*mock_sender_, InRecovery()).WillOnce(Return(in_recovery));
+ }
+ EXPECT_CALL(*mock_sender_,
+ OnPacketSent(clock_.Now(), bytes_in_flight, packet_number_,
+ kMaxPacketSize, retransmittable_data));
+ pacing_sender_->OnPacketSent(clock_.Now(), bytes_in_flight,
+ packet_number_++, kMaxPacketSize,
+ retransmittable_data);
+ }
+
+ void CheckPacketIsSentImmediately() {
+ CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, kBytesInFlight,
+ false);
+ }
+
+ void CheckPacketIsDelayed(QuicTime::Delta delay) {
+ // In order for the packet to be sendable, the underlying sender must
+ // permit it to be sent immediately.
+ for (int i = 0; i < 2; ++i) {
+ EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(), kBytesInFlight))
+ .WillOnce(Return(zero_time_));
+ // Verify that the packet is delayed.
+ EXPECT_EQ(delay.ToMicroseconds(),
+ pacing_sender_->TimeUntilSend(clock_.Now(), kBytesInFlight)
+ .ToMicroseconds());
+ }
+ }
+
+ void UpdateRtt() {
+ EXPECT_CALL(*mock_sender_, OnCongestionEvent(true, kBytesInFlight, _, _));
+ SendAlgorithmInterface::CongestionVector empty_map;
+ pacing_sender_->OnCongestionEvent(true, kBytesInFlight, empty_map,
+ empty_map);
+ }
+
+ const QuicTime::Delta zero_time_;
+ const QuicTime::Delta infinite_time_;
+ MockClock clock_;
+ QuicPacketNumber packet_number_;
+ std::unique_ptr<StrictMock<MockSendAlgorithm>> mock_sender_;
+ std::unique_ptr<PacingSender> pacing_sender_;
+};
+
+TEST_F(PacingSenderTest, NoSend) {
+ for (int i = 0; i < 2; ++i) {
+ EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(), kBytesInFlight))
+ .WillOnce(Return(infinite_time_));
+ EXPECT_EQ(infinite_time_,
+ pacing_sender_->TimeUntilSend(clock_.Now(), kBytesInFlight));
+ }
+}
+
+TEST_F(PacingSenderTest, SendNow) {
+ for (int i = 0; i < 2; ++i) {
+ EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(), kBytesInFlight))
+ .WillOnce(Return(zero_time_));
+ EXPECT_EQ(zero_time_,
+ pacing_sender_->TimeUntilSend(clock_.Now(), kBytesInFlight));
+ }
+}
+
+TEST_F(PacingSenderTest, VariousSending) {
+ // Configure pacing rate of 1 packet per 1 ms, no initial burst.
+ InitPacingRate(0, QuicBandwidth::FromBytesAndTimeDelta(
+ kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1)));
+
+ // Now update the RTT and verify that packets are actually paced.
+ UpdateRtt();
+
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+
+ // The first packet was a "make up", then we sent two packets "into the
+ // future", so the delay should be 2.
+ CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+
+ // Wake up on time.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2));
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+
+ // Wake up late.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(4));
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+
+ // Wake up really late.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8));
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+
+ // Wake up really late again, but application pause partway through.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8));
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100));
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+
+ // Wake up too early.
+ CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+
+ // Wake up early, but after enough time has passed to permit a send.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+}
+
+TEST_F(PacingSenderTest, InitialBurst) {
+ // Configure pacing rate of 1 packet per 1 ms.
+ InitPacingRate(10, QuicBandwidth::FromBytesAndTimeDelta(
+ kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1)));
+
+ EXPECT_CALL(*mock_sender_, GetCongestionWindow())
+ .WillOnce(Return(10 * kDefaultTCPMSS));
+ // Update the RTT and verify that the first 10 packets aren't paced.
+ UpdateRtt();
+
+ // Send 10 packets, and verify that they are not paced.
+ for (int i = 0; i < kInitialBurstPackets; ++i) {
+ CheckPacketIsSentImmediately();
+ }
+
+ // The first packet was a "make up", then we sent two packets "into the
+ // future", so the delay should be 2ms.
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+ CheckPacketIsSentImmediately();
+
+ // Next time TimeUntilSend is called with no bytes in flight, pacing should
+ // allow a packet to be sent, and when it's sent, the tokens are refilled.
+ CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, 0, false);
+ for (int i = 0; i < kInitialBurstPackets - 1; ++i) {
+ CheckPacketIsSentImmediately();
+ }
+
+ // The first packet was a "make up", then we sent two packets "into the
+ // future", so the delay should be 2ms.
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+}
+
+TEST_F(PacingSenderTest, InitialBurstNoRttMeasurement) {
+ // Configure pacing rate of 1 packet per 1 ms.
+ InitPacingRate(10, QuicBandwidth::FromBytesAndTimeDelta(
+ kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1)));
+
+ EXPECT_CALL(*mock_sender_, GetCongestionWindow())
+ .WillOnce(Return(10 * kDefaultTCPMSS));
+ // Send 10 packets, and verify that they are not paced.
+ for (int i = 0; i < kInitialBurstPackets; ++i) {
+ CheckPacketIsSentImmediately();
+ }
+
+ // The first packet was a "make up", then we sent two packets "into the
+ // future", so the delay should be 2ms.
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+ CheckPacketIsSentImmediately();
+
+ // Next time TimeUntilSend is called with no bytes in flight, the tokens
+ // should be refilled and there should be no delay.
+ CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, 0, false);
+ // Send 10 packets, and verify that they are not paced.
+ for (int i = 0; i < kInitialBurstPackets - 1; ++i) {
+ CheckPacketIsSentImmediately();
+ }
+
+ // The first packet was a "make up", then we sent two packets "into the
+ // future", so the delay should be 2ms.
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+}
+
+TEST_F(PacingSenderTest, FastSending) {
+ // Ensure the pacing sender paces, even when the inter-packet spacing is less
+ // than the pacing granularity.
+ InitPacingRate(10,
+ QuicBandwidth::FromBytesAndTimeDelta(
+ 2 * kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1)));
+
+ EXPECT_CALL(*mock_sender_, GetCongestionWindow())
+ .WillOnce(Return(10 * kDefaultTCPMSS));
+ // Update the RTT and verify that the first 10 packets aren't paced.
+ UpdateRtt();
+
+ // Send 10 packets, and verify that they are not paced.
+ for (int i = 0; i < kInitialBurstPackets; ++i) {
+ CheckPacketIsSentImmediately();
+ }
+
+ // The first packet was a "make up", then we sent two packets "into the
+ // future", since it's 2 packets/ms, so the delay should be 1.5ms.
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMicroseconds(1500));
+
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+ CheckPacketIsSentImmediately();
+
+ // Next time TimeUntilSend is called with no bytes in flight, the tokens
+ // should be refilled and there should be no delay.
+ CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, 0, false);
+ for (int i = 0; i < kInitialBurstPackets - 1; ++i) {
+ CheckPacketIsSentImmediately();
+ }
+
+ // The first packet was a "make up", then we sent two packets "into the
+ // future", so the delay should be 1.5ms.
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMicroseconds(1500));
+}
+
+TEST_F(PacingSenderTest, NoBurstEnteringRecovery) {
+ // Configure pacing rate of 1 packet per 1 ms with no burst tokens.
+ InitPacingRate(0, QuicBandwidth::FromBytesAndTimeDelta(
+ kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1)));
+ // Sending a packet will set burst tokens.
+ CheckPacketIsSentImmediately();
+
+ // Losing a packet will set clear burst tokens.
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
+ SendAlgorithmInterface::CongestionVector empty;
+ EXPECT_CALL(*mock_sender_,
+ OnCongestionEvent(true, kMaxPacketSize, empty, lost_packets));
+ pacing_sender_->OnCongestionEvent(true, kMaxPacketSize, empty, lost_packets);
+ // One packet is sent immediately, because of 1ms pacing granularity.
+ CheckPacketIsSentImmediately();
+ // Ensure packets are immediately paced.
+ EXPECT_CALL(*mock_sender_, TimeUntilSend(clock_.Now(), kDefaultTCPMSS))
+ .WillOnce(Return(zero_time_));
+ // Verify the next packet is paced and delayed 2ms due to granularity.
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(2),
+ pacing_sender_->TimeUntilSend(clock_.Now(), kDefaultTCPMSS));
+ CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+}
+
+TEST_F(PacingSenderTest, NoBurstInRecovery) {
+ // Configure pacing rate of 1 packet per 1 ms with no burst tokens.
+ InitPacingRate(0, QuicBandwidth::FromBytesAndTimeDelta(
+ kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1)));
+
+ UpdateRtt();
+
+ // Ensure only one packet is sent immediately and the rest are paced.
+ CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, 0, true);
+ CheckPacketIsSentImmediately();
+ CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/prr_sender.cc b/chromium/net/quic/core/congestion_control/prr_sender.cc
new file mode 100644
index 00000000000..75ed65b112e
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/prr_sender.cc
@@ -0,0 +1,71 @@
+// 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.
+
+#include "net/quic/core/congestion_control/prr_sender.h"
+
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+namespace {
+// Constant based on TCP defaults.
+const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS;
+} // namespace
+
+PrrSender::PrrSender()
+ : bytes_sent_since_loss_(0),
+ bytes_delivered_since_loss_(0),
+ ack_count_since_loss_(0),
+ bytes_in_flight_before_loss_(0) {}
+
+void PrrSender::OnPacketSent(QuicByteCount sent_bytes) {
+ bytes_sent_since_loss_ += sent_bytes;
+}
+
+void PrrSender::OnPacketLost(QuicByteCount bytes_in_flight) {
+ bytes_sent_since_loss_ = 0;
+ bytes_in_flight_before_loss_ = bytes_in_flight;
+ bytes_delivered_since_loss_ = 0;
+ ack_count_since_loss_ = 0;
+}
+
+void PrrSender::OnPacketAcked(QuicByteCount acked_bytes) {
+ bytes_delivered_since_loss_ += acked_bytes;
+ ++ack_count_since_loss_;
+}
+
+QuicTime::Delta PrrSender::TimeUntilSend(
+ QuicByteCount congestion_window,
+ QuicByteCount bytes_in_flight,
+ QuicByteCount slowstart_threshold) const {
+ // if (FLAGS_?? && bytes_in_flight < congestion_window) {
+ // return QuicTime::Delta::Zero();
+ // }
+ // Return QuicTime::Zero In order to ensure limited transmit always works.
+ if (bytes_sent_since_loss_ == 0 || bytes_in_flight < kMaxSegmentSize) {
+ return QuicTime::Delta::Zero();
+ }
+ if (congestion_window > bytes_in_flight) {
+ // During PRR-SSRB, limit outgoing packets to 1 extra MSS per ack, instead
+ // of sending the entire available window. This prevents burst retransmits
+ // when more packets are lost than the CWND reduction.
+ // limit = MAX(prr_delivered - prr_out, DeliveredData) + MSS
+ if (bytes_delivered_since_loss_ + ack_count_since_loss_ * kMaxSegmentSize <=
+ bytes_sent_since_loss_) {
+ return QuicTime::Delta::Infinite();
+ }
+ return QuicTime::Delta::Zero();
+ }
+ // Implement Proportional Rate Reduction (RFC6937).
+ // Checks a simplified version of the PRR formula that doesn't use division:
+ // AvailableSendWindow =
+ // CEIL(prr_delivered * ssthresh / BytesInFlightAtLoss) - prr_sent
+ if (bytes_delivered_since_loss_ * slowstart_threshold >
+ bytes_sent_since_loss_ * bytes_in_flight_before_loss_) {
+ return QuicTime::Delta::Zero();
+ }
+ return QuicTime::Delta::Infinite();
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/prr_sender.h b/chromium/net/quic/core/congestion_control/prr_sender.h
new file mode 100644
index 00000000000..12e0fd90dfb
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/prr_sender.h
@@ -0,0 +1,45 @@
+// 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.
+//
+// Implements Proportional Rate Reduction (PRR) per RFC 6937.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_PRR_SENDER_H_
+#define NET_QUIC_CONGESTION_CONTROL_PRR_SENDER_H_
+
+#include <stddef.h>
+
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE PrrSender {
+ public:
+ PrrSender();
+ // OnPacketLost should be called on the first loss that triggers a recovery
+ // period and all other methods in this class should only be called when in
+ // recovery.
+ void OnPacketLost(QuicByteCount bytes_in_flight);
+ void OnPacketSent(QuicByteCount sent_bytes);
+ void OnPacketAcked(QuicByteCount acked_bytes);
+ QuicTime::Delta TimeUntilSend(QuicByteCount congestion_window,
+ QuicByteCount bytes_in_flight,
+ QuicByteCount slowstart_threshold) const;
+
+ private:
+ // Bytes sent and acked since the last loss event.
+ // |bytes_sent_since_loss_| is the same as "prr_out_" in RFC 6937,
+ // and |bytes_delivered_since_loss_| is the same as "prr_delivered_".
+ QuicByteCount bytes_sent_since_loss_;
+ QuicByteCount bytes_delivered_since_loss_;
+ size_t ack_count_since_loss_;
+
+ // The congestion window before the last loss event.
+ QuicByteCount bytes_in_flight_before_loss_;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CONGESTION_CONTROL_PRR_SENDER_H_
diff --git a/chromium/net/quic/core/congestion_control/prr_sender_test.cc b/chromium/net/quic/core/congestion_control/prr_sender_test.cc
new file mode 100644
index 00000000000..d132c3307ba
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/prr_sender_test.cc
@@ -0,0 +1,134 @@
+// 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.
+
+#include "net/quic/core/congestion_control/prr_sender.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_protocol.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+namespace {
+// Constant based on TCP defaults.
+const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS;
+} // namespace
+
+class PrrSenderTest : public ::testing::Test {};
+
+TEST_F(PrrSenderTest, SingleLossResultsInSendOnEveryOtherAck) {
+ PrrSender prr;
+ QuicPacketCount num_packets_in_flight = 50;
+ QuicByteCount bytes_in_flight = num_packets_in_flight * kMaxSegmentSize;
+ const QuicPacketCount ssthresh_after_loss = num_packets_in_flight / 2;
+ const QuicByteCount congestion_window = ssthresh_after_loss * kMaxSegmentSize;
+
+ prr.OnPacketLost(bytes_in_flight);
+ // Ack a packet. PRR allows one packet to leave immediately.
+ prr.OnPacketAcked(kMaxSegmentSize);
+ bytes_in_flight -= kMaxSegmentSize;
+ EXPECT_EQ(QuicTime::Delta::Zero(),
+ prr.TimeUntilSend(congestion_window, bytes_in_flight,
+ ssthresh_after_loss * kMaxSegmentSize));
+ // Send retransmission.
+ prr.OnPacketSent(kMaxSegmentSize);
+ // PRR shouldn't allow sending any more packets.
+ EXPECT_EQ(QuicTime::Delta::Infinite(),
+ prr.TimeUntilSend(congestion_window, bytes_in_flight,
+ ssthresh_after_loss * kMaxSegmentSize));
+
+ // One packet is lost, and one ack was consumed above. PRR now paces
+ // transmissions through the remaining 48 acks. PRR will alternatively
+ // disallow and allow a packet to be sent in response to an ack.
+ for (uint64_t i = 0; i < ssthresh_after_loss - 1; ++i) {
+ // Ack a packet. PRR shouldn't allow sending a packet in response.
+ prr.OnPacketAcked(kMaxSegmentSize);
+ bytes_in_flight -= kMaxSegmentSize;
+ EXPECT_EQ(QuicTime::Delta::Infinite(),
+ prr.TimeUntilSend(congestion_window, bytes_in_flight,
+ ssthresh_after_loss * kMaxSegmentSize));
+ // Ack another packet. PRR should now allow sending a packet in response.
+ prr.OnPacketAcked(kMaxSegmentSize);
+ bytes_in_flight -= kMaxSegmentSize;
+ EXPECT_EQ(QuicTime::Delta::Zero(),
+ prr.TimeUntilSend(congestion_window, bytes_in_flight,
+ ssthresh_after_loss * kMaxSegmentSize));
+ // Send a packet in response.
+ prr.OnPacketSent(kMaxSegmentSize);
+ bytes_in_flight += kMaxSegmentSize;
+ }
+
+ // Since bytes_in_flight is now equal to congestion_window, PRR now maintains
+ // packet conservation, allowing one packet to be sent in response to an ack.
+ EXPECT_EQ(congestion_window, bytes_in_flight);
+ for (int i = 0; i < 10; ++i) {
+ // Ack a packet.
+ prr.OnPacketAcked(kMaxSegmentSize);
+ bytes_in_flight -= kMaxSegmentSize;
+ EXPECT_EQ(QuicTime::Delta::Zero(),
+ prr.TimeUntilSend(congestion_window, bytes_in_flight,
+ ssthresh_after_loss * kMaxSegmentSize));
+ // Send a packet in response, since PRR allows it.
+ prr.OnPacketSent(kMaxSegmentSize);
+ bytes_in_flight += kMaxSegmentSize;
+
+ // Since bytes_in_flight is equal to the congestion_window,
+ // PRR disallows sending.
+ EXPECT_EQ(congestion_window, bytes_in_flight);
+ EXPECT_EQ(QuicTime::Delta::Infinite(),
+ prr.TimeUntilSend(congestion_window, bytes_in_flight,
+ ssthresh_after_loss * kMaxSegmentSize));
+ }
+}
+
+TEST_F(PrrSenderTest, BurstLossResultsInSlowStart) {
+ PrrSender prr;
+ QuicByteCount bytes_in_flight = 20 * kMaxSegmentSize;
+ const QuicPacketCount num_packets_lost = 13;
+ const QuicPacketCount ssthresh_after_loss = 10;
+ const QuicByteCount congestion_window = ssthresh_after_loss * kMaxSegmentSize;
+
+ // Lose 13 packets.
+ bytes_in_flight -= num_packets_lost * kMaxSegmentSize;
+ prr.OnPacketLost(bytes_in_flight);
+
+ // PRR-SSRB will allow the following 3 acks to send up to 2 packets.
+ for (int i = 0; i < 3; ++i) {
+ prr.OnPacketAcked(kMaxSegmentSize);
+ bytes_in_flight -= kMaxSegmentSize;
+ // PRR-SSRB should allow two packets to be sent.
+ for (int j = 0; j < 2; ++j) {
+ EXPECT_EQ(QuicTime::Delta::Zero(),
+ prr.TimeUntilSend(congestion_window, bytes_in_flight,
+ ssthresh_after_loss * kMaxSegmentSize));
+ // Send a packet in response.
+ prr.OnPacketSent(kMaxSegmentSize);
+ bytes_in_flight += kMaxSegmentSize;
+ }
+ // PRR should allow no more than 2 packets in response to an ack.
+ EXPECT_EQ(QuicTime::Delta::Infinite(),
+ prr.TimeUntilSend(congestion_window, bytes_in_flight,
+ ssthresh_after_loss * kMaxSegmentSize));
+ }
+
+ // Out of SSRB mode, PRR allows one send in response to each ack.
+ for (int i = 0; i < 10; ++i) {
+ prr.OnPacketAcked(kMaxSegmentSize);
+ bytes_in_flight -= kMaxSegmentSize;
+ EXPECT_EQ(QuicTime::Delta::Zero(),
+ prr.TimeUntilSend(congestion_window, bytes_in_flight,
+ ssthresh_after_loss * kMaxSegmentSize));
+ // Send a packet in response.
+ prr.OnPacketSent(kMaxSegmentSize);
+ bytes_in_flight += kMaxSegmentSize;
+ }
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/rtt_stats.cc b/chromium/net/quic/core/congestion_control/rtt_stats.cc
new file mode 100644
index 00000000000..91d3e2ad3c0
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/rtt_stats.cc
@@ -0,0 +1,130 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/congestion_control/rtt_stats.h"
+
+#include <cstdlib> // std::abs
+
+#include "net/quic/core/quic_flags.h"
+
+using std::max;
+
+namespace net {
+
+namespace {
+
+// Default initial rtt used before any samples are received.
+const int kInitialRttMs = 100;
+const float kAlpha = 0.125f;
+const float kOneMinusAlpha = (1 - kAlpha);
+const float kBeta = 0.25f;
+const float kOneMinusBeta = (1 - kBeta);
+// 10-second window length for windowed min RTT.
+const int kMinRttWindowLengthMs = 10000;
+
+} // namespace
+
+RttStats::RttStats()
+ : latest_rtt_(QuicTime::Delta::Zero()),
+ min_rtt_(QuicTime::Delta::Zero()),
+ smoothed_rtt_(QuicTime::Delta::Zero()),
+ previous_srtt_(QuicTime::Delta::Zero()),
+ mean_deviation_(QuicTime::Delta::Zero()),
+ initial_rtt_us_(kInitialRttMs * kNumMicrosPerMilli),
+ forced_windowed_min_rtt_(QuicTime::Delta::Zero()),
+ forced_windowed_min_rtt_time_(QuicTime::Zero()),
+ num_samples_for_forced_min_(0),
+ windowed_min_rtt_(
+ QuicTime::Delta::FromMilliseconds(kMinRttWindowLengthMs),
+ QuicTime::Delta::Zero(),
+ QuicTime::Zero()) {}
+
+void RttStats::SampleNewWindowedMinRtt(uint32_t num_samples) {
+ num_samples_for_forced_min_ = num_samples;
+ forced_windowed_min_rtt_ = QuicTime::Delta::Zero();
+ forced_windowed_min_rtt_time_ = QuicTime::Zero();
+}
+
+void RttStats::ExpireSmoothedMetrics() {
+ mean_deviation_ = max(mean_deviation_,
+ QuicTime::Delta::FromMicroseconds(std::abs(
+ (smoothed_rtt_ - latest_rtt_).ToMicroseconds())));
+ smoothed_rtt_ = max(smoothed_rtt_, latest_rtt_);
+}
+
+// Updates the RTT based on a new sample.
+void RttStats::UpdateRtt(QuicTime::Delta send_delta,
+ QuicTime::Delta ack_delay,
+ QuicTime now) {
+ if (send_delta.IsInfinite() || send_delta <= QuicTime::Delta::Zero()) {
+ LOG(WARNING) << "Ignoring measured send_delta, because it's is "
+ << "either infinite, zero, or negative. send_delta = "
+ << send_delta.ToMicroseconds();
+ return;
+ }
+
+ // Update min_rtt_ first. min_rtt_ does not use an rtt_sample corrected for
+ // ack_delay but the raw observed send_delta, since poor clock granularity at
+ // the client may cause a high ack_delay to result in underestimation of the
+ // min_rtt_.
+ if (min_rtt_.IsZero() || min_rtt_ > send_delta) {
+ min_rtt_ = send_delta;
+ }
+ UpdateWindowedMinRtt(send_delta, now);
+
+ // Correct for ack_delay if information received from the peer results in a
+ // positive RTT sample. Otherwise, we use the send_delta as a reasonable
+ // measure for smoothed_rtt.
+ QuicTime::Delta rtt_sample(send_delta);
+ previous_srtt_ = smoothed_rtt_;
+
+ if (rtt_sample > ack_delay) {
+ rtt_sample = rtt_sample - ack_delay;
+ }
+ latest_rtt_ = rtt_sample;
+ // First time call.
+ if (smoothed_rtt_.IsZero()) {
+ smoothed_rtt_ = rtt_sample;
+ mean_deviation_ =
+ QuicTime::Delta::FromMicroseconds(rtt_sample.ToMicroseconds() / 2);
+ } else {
+ mean_deviation_ = QuicTime::Delta::FromMicroseconds(static_cast<int64_t>(
+ kOneMinusBeta * mean_deviation_.ToMicroseconds() +
+ kBeta * std::abs((smoothed_rtt_ - rtt_sample).ToMicroseconds())));
+ smoothed_rtt_ = kOneMinusAlpha * smoothed_rtt_ + kAlpha * rtt_sample;
+ DVLOG(1) << " smoothed_rtt(us):" << smoothed_rtt_.ToMicroseconds()
+ << " mean_deviation(us):" << mean_deviation_.ToMicroseconds();
+ }
+}
+
+void RttStats::UpdateWindowedMinRtt(QuicTime::Delta rtt_sample, QuicTime now) {
+ // Update windowed_min_rtt.
+ windowed_min_rtt_.Update(rtt_sample, now);
+ if (num_samples_for_forced_min_ <= 0) {
+ return;
+ }
+ // Reset windowed_min_rtt to the min of num_samples_for_forced_min_ samples.
+ if (forced_windowed_min_rtt_.IsZero() ||
+ rtt_sample <= forced_windowed_min_rtt_) {
+ forced_windowed_min_rtt_ = rtt_sample;
+ forced_windowed_min_rtt_time_ = now;
+ }
+ if (num_samples_for_forced_min_ == 1) {
+ windowed_min_rtt_.Reset(forced_windowed_min_rtt_,
+ forced_windowed_min_rtt_time_);
+ }
+ --num_samples_for_forced_min_;
+}
+
+void RttStats::OnConnectionMigration() {
+ latest_rtt_ = QuicTime::Delta::Zero();
+ min_rtt_ = QuicTime::Delta::Zero();
+ smoothed_rtt_ = QuicTime::Delta::Zero();
+ mean_deviation_ = QuicTime::Delta::Zero();
+ initial_rtt_us_ = kInitialRttMs * kNumMicrosPerMilli;
+ num_samples_for_forced_min_ = 0;
+ windowed_min_rtt_.Reset(QuicTime::Delta::Zero(), QuicTime::Zero());
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/rtt_stats.h b/chromium/net/quic/core/congestion_control/rtt_stats.h
new file mode 100644
index 00000000000..d88bc643768
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/rtt_stats.h
@@ -0,0 +1,114 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A convenience class to store rtt samples and calculate smoothed rtt.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_RTT_STATS_H_
+#define NET_QUIC_CONGESTION_CONTROL_RTT_STATS_H_
+
+#include <stdint.h>
+
+#include <algorithm>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/congestion_control/windowed_filter.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+namespace test {
+class RttStatsPeer;
+} // namespace test
+
+class NET_EXPORT_PRIVATE RttStats {
+ public:
+ RttStats();
+
+ // Updates the RTT from an incoming ack which is received |send_delta| after
+ // the packet is sent and the peer reports the ack being delayed |ack_delay|.
+ void UpdateRtt(QuicTime::Delta send_delta,
+ QuicTime::Delta ack_delay,
+ QuicTime now);
+
+ // Causes the smoothed_rtt to be increased to the latest_rtt if the latest_rtt
+ // is larger. The mean deviation is increased to the most recent deviation if
+ // it's larger.
+ void ExpireSmoothedMetrics();
+
+ // Forces RttStats to sample a new windowed min rtt within the next
+ // |num_samples| UpdateRtt calls.
+ void SampleNewWindowedMinRtt(uint32_t num_samples);
+
+ // Called when connection migrates and rtt measurement needs to be reset.
+ void OnConnectionMigration();
+
+ // Returns the EWMA smoothed RTT for the connection.
+ // May return Zero if no valid updates have occurred.
+ QuicTime::Delta smoothed_rtt() const { return smoothed_rtt_; }
+
+ // Returns the EWMA smoothed RTT prior to the most recent RTT sample.
+ QuicTime::Delta previous_srtt() const { return previous_srtt_; }
+
+ int64_t initial_rtt_us() const { return initial_rtt_us_; }
+
+ // Sets an initial RTT to be used for SmoothedRtt before any RTT updates.
+ void set_initial_rtt_us(int64_t initial_rtt_us) {
+ if (initial_rtt_us <= 0) {
+ QUIC_BUG << "Attempt to set initial rtt to <= 0.";
+ return;
+ }
+ initial_rtt_us_ = initial_rtt_us;
+ }
+
+ // The most recent rtt measurement.
+ // May return Zero if no valid updates have occurred.
+ QuicTime::Delta latest_rtt() const { return latest_rtt_; }
+
+ // Returns the min_rtt for the entire connection.
+ // May return Zero if no valid updates have occurred.
+ QuicTime::Delta min_rtt() const { return min_rtt_; }
+
+ QuicTime::Delta mean_deviation() const { return mean_deviation_; }
+
+ QuicTime::Delta WindowedMinRtt() { return windowed_min_rtt_.GetBest(); }
+
+ private:
+ friend class test::RttStatsPeer;
+
+ // Updates the windowed min rtt. Also forces a new windowed_min_rtt sample,
+ // if set by a call to SampleNewWindowedMinRtt() above.
+ void UpdateWindowedMinRtt(QuicTime::Delta rtt_sample, QuicTime now);
+
+ QuicTime::Delta latest_rtt_;
+ QuicTime::Delta min_rtt_;
+ QuicTime::Delta smoothed_rtt_;
+ QuicTime::Delta previous_srtt_;
+ // Mean RTT deviation during this session.
+ // Approximation of standard deviation, the error is roughly 1.25 times
+ // larger than the standard deviation, for a normally distributed signal.
+ QuicTime::Delta mean_deviation_;
+ int64_t initial_rtt_us_;
+
+ // Variables used to force a new windowed_min_rtt measurement within
+ // num_samples_for_forced_min_.
+ QuicTime::Delta forced_windowed_min_rtt_;
+ QuicTime forced_windowed_min_rtt_time_;
+ uint32_t num_samples_for_forced_min_;
+
+ // Windowed min_rtt.
+ WindowedFilter<QuicTime::Delta,
+ MinFilter<QuicTime::Delta>,
+ QuicTime,
+ QuicTime::Delta>
+ windowed_min_rtt_;
+
+ DISALLOW_COPY_AND_ASSIGN(RttStats);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CONGESTION_CONTROL_RTT_STATS_H_
diff --git a/chromium/net/quic/core/congestion_control/rtt_stats_test.cc b/chromium/net/quic/core/congestion_control/rtt_stats_test.cc
new file mode 100644
index 00000000000..d894bebd0be
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/rtt_stats_test.cc
@@ -0,0 +1,217 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/congestion_control/rtt_stats.h"
+
+#include <cmath>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/test/mock_log.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/test_tools/rtt_stats_peer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using logging::LOG_WARNING;
+using std::vector;
+using testing::HasSubstr;
+using testing::Message;
+using testing::_;
+
+namespace net {
+namespace test {
+
+class RttStatsTest : public ::testing::Test {
+ protected:
+ RttStats rtt_stats_;
+};
+
+TEST_F(RttStatsTest, DefaultsBeforeUpdate) {
+ EXPECT_LT(0u, rtt_stats_.initial_rtt_us());
+ EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.min_rtt());
+ EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.smoothed_rtt());
+}
+
+TEST_F(RttStatsTest, SmoothedRtt) {
+ // Verify that ack_delay is corrected for in Smoothed RTT.
+ rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300),
+ QuicTime::Delta::FromMilliseconds(100),
+ QuicTime::Zero());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt());
+ // Verify that effective RTT of zero does not change Smoothed RTT.
+ rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(200),
+ QuicTime::Delta::FromMilliseconds(200),
+ QuicTime::Zero());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt());
+ // Verify that large erroneous ack_delay does not change Smoothed RTT.
+ rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(200),
+ QuicTime::Delta::FromMilliseconds(300),
+ QuicTime::Zero());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt());
+}
+
+// Ensure that the potential rounding artifacts in EWMA calculation do not cause
+// the SRTT to drift too far from the exact value.
+TEST_F(RttStatsTest, SmoothedRttStability) {
+ for (size_t time = 3; time < 20000; time++) {
+ RttStats stats;
+ for (size_t i = 0; i < 100; i++) {
+ stats.UpdateRtt(QuicTime::Delta::FromMicroseconds(time),
+ QuicTime::Delta::FromMilliseconds(0), QuicTime::Zero());
+ int64_t time_delta_us = stats.smoothed_rtt().ToMicroseconds() - time;
+ ASSERT_LE(std::abs(time_delta_us), 1);
+ }
+ }
+}
+
+TEST_F(RttStatsTest, PreviousSmoothedRtt) {
+ // Verify that ack_delay is corrected for in Smoothed RTT.
+ rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300),
+ QuicTime::Delta::FromMilliseconds(100),
+ QuicTime::Zero());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt());
+ EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.previous_srtt());
+ // Ensure the previous SRTT is 200ms after a 100ms sample.
+ rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats_.latest_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMicroseconds(187500).ToMicroseconds(),
+ rtt_stats_.smoothed_rtt().ToMicroseconds());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.previous_srtt());
+}
+
+TEST_F(RttStatsTest, MinRtt) {
+ rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(200),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.min_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200),
+ rtt_stats_.WindowedMinRtt());
+ rtt_stats_.UpdateRtt(
+ QuicTime::Delta::FromMilliseconds(10), QuicTime::Delta::Zero(),
+ QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(10));
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.WindowedMinRtt());
+ rtt_stats_.UpdateRtt(
+ QuicTime::Delta::FromMilliseconds(50), QuicTime::Delta::Zero(),
+ QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(20));
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.WindowedMinRtt());
+ rtt_stats_.UpdateRtt(
+ QuicTime::Delta::FromMilliseconds(50), QuicTime::Delta::Zero(),
+ QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(30));
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.WindowedMinRtt());
+ rtt_stats_.UpdateRtt(
+ QuicTime::Delta::FromMilliseconds(50), QuicTime::Delta::Zero(),
+ QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(40));
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.WindowedMinRtt());
+ // Verify that ack_delay does not go into recording of min_rtt_.
+ rtt_stats_.UpdateRtt(
+ QuicTime::Delta::FromMilliseconds(7),
+ QuicTime::Delta::FromMilliseconds(2),
+ QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(50));
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(7), rtt_stats_.min_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(7), rtt_stats_.WindowedMinRtt());
+}
+
+TEST_F(RttStatsTest, WindowedMinRtt) {
+ rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(10),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.WindowedMinRtt());
+
+ rtt_stats_.SampleNewWindowedMinRtt(4);
+ for (int i = 0; i < 3; ++i) {
+ rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(50),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
+ rtt_stats_.WindowedMinRtt());
+ }
+ rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(50),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(50), rtt_stats_.WindowedMinRtt());
+}
+
+TEST_F(RttStatsTest, ExpireSmoothedMetrics) {
+ QuicTime::Delta initial_rtt = QuicTime::Delta::FromMilliseconds(10);
+ rtt_stats_.UpdateRtt(initial_rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
+ EXPECT_EQ(initial_rtt, rtt_stats_.min_rtt());
+ EXPECT_EQ(initial_rtt, rtt_stats_.WindowedMinRtt());
+ EXPECT_EQ(initial_rtt, rtt_stats_.smoothed_rtt());
+
+ EXPECT_EQ(0.5 * initial_rtt, rtt_stats_.mean_deviation());
+
+ // Update once with a 20ms RTT.
+ QuicTime::Delta doubled_rtt = 2 * initial_rtt;
+ rtt_stats_.UpdateRtt(doubled_rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
+ EXPECT_EQ(1.125 * initial_rtt, rtt_stats_.smoothed_rtt());
+
+ // Expire the smoothed metrics, increasing smoothed rtt and mean deviation.
+ rtt_stats_.ExpireSmoothedMetrics();
+ EXPECT_EQ(doubled_rtt, rtt_stats_.smoothed_rtt());
+ EXPECT_EQ(0.875 * initial_rtt, rtt_stats_.mean_deviation());
+
+ // Now go back down to 5ms and expire the smoothed metrics, and ensure the
+ // mean deviation increases to 15ms.
+ QuicTime::Delta half_rtt = 0.5 * initial_rtt;
+ rtt_stats_.UpdateRtt(half_rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
+ EXPECT_GT(doubled_rtt, rtt_stats_.smoothed_rtt());
+ EXPECT_LT(initial_rtt, rtt_stats_.mean_deviation());
+}
+
+TEST_F(RttStatsTest, UpdateRttWithBadSendDeltas) {
+ // Make sure we ignore bad RTTs.
+ base::test::MockLog log;
+
+ QuicTime::Delta initial_rtt = QuicTime::Delta::FromMilliseconds(10);
+ rtt_stats_.UpdateRtt(initial_rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
+ EXPECT_EQ(initial_rtt, rtt_stats_.min_rtt());
+ EXPECT_EQ(initial_rtt, rtt_stats_.WindowedMinRtt());
+ EXPECT_EQ(initial_rtt, rtt_stats_.smoothed_rtt());
+
+ vector<QuicTime::Delta> bad_send_deltas;
+ bad_send_deltas.push_back(QuicTime::Delta::Zero());
+ bad_send_deltas.push_back(QuicTime::Delta::Infinite());
+ bad_send_deltas.push_back(QuicTime::Delta::FromMicroseconds(-1000));
+ log.StartCapturingLogs();
+
+ for (QuicTime::Delta bad_send_delta : bad_send_deltas) {
+ SCOPED_TRACE(Message() << "bad_send_delta = "
+ << bad_send_delta.ToMicroseconds());
+ EXPECT_CALL(log, Log(LOG_WARNING, _, _, _, HasSubstr("Ignoring")));
+ rtt_stats_.UpdateRtt(bad_send_delta, QuicTime::Delta::Zero(),
+ QuicTime::Zero());
+ EXPECT_EQ(initial_rtt, rtt_stats_.min_rtt());
+ EXPECT_EQ(initial_rtt, rtt_stats_.WindowedMinRtt());
+ EXPECT_EQ(initial_rtt, rtt_stats_.smoothed_rtt());
+ }
+}
+
+TEST_F(RttStatsTest, ResetAfterConnectionMigrations) {
+ rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300),
+ QuicTime::Delta::FromMilliseconds(100),
+ QuicTime::Zero());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.min_rtt());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300),
+ rtt_stats_.WindowedMinRtt());
+
+ // Reset rtt stats on connection migrations.
+ rtt_stats_.OnConnectionMigration();
+ EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.latest_rtt());
+ EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.smoothed_rtt());
+ EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.min_rtt());
+ EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.WindowedMinRtt());
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/send_algorithm_interface.cc b/chromium/net/quic/core/congestion_control/send_algorithm_interface.cc
new file mode 100644
index 00000000000..2f6f3386d09
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/send_algorithm_interface.cc
@@ -0,0 +1,46 @@
+// 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/send_algorithm_interface.h"
+
+#include "net/quic/core/congestion_control/tcp_cubic_sender_bytes.h"
+#include "net/quic/core/congestion_control/tcp_cubic_sender_packets.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+class RttStats;
+
+// Factory for send side congestion control algorithm.
+SendAlgorithmInterface* SendAlgorithmInterface::Create(
+ const QuicClock* clock,
+ const RttStats* rtt_stats,
+ CongestionControlType congestion_control_type,
+ QuicConnectionStats* stats,
+ QuicPacketCount initial_congestion_window) {
+ QuicPacketCount max_congestion_window = kDefaultMaxCongestionWindowPackets;
+ switch (congestion_control_type) {
+ case kBBR:
+ case kCubic:
+ return new TcpCubicSenderPackets(
+ clock, rtt_stats, false /* don't use Reno */,
+ initial_congestion_window, max_congestion_window, stats);
+ case kCubicBytes:
+ return new TcpCubicSenderBytes(
+ clock, rtt_stats, false /* don't use Reno */,
+ initial_congestion_window, max_congestion_window, stats);
+ case kReno:
+ return new TcpCubicSenderPackets(clock, rtt_stats, true /* use Reno */,
+ initial_congestion_window,
+ max_congestion_window, stats);
+ case kRenoBytes:
+ return new TcpCubicSenderBytes(clock, rtt_stats, true /* use Reno */,
+ initial_congestion_window,
+ max_congestion_window, stats);
+ }
+ return nullptr;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/send_algorithm_interface.h b/chromium/net/quic/core/congestion_control/send_algorithm_interface.h
new file mode 100644
index 00000000000..ad64afad7b8
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/send_algorithm_interface.h
@@ -0,0 +1,137 @@
+// 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.
+//
+// The pure virtual class for send side congestion control algorithm.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_INTERFACE_H_
+#define NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_INTERFACE_H_
+
+#include <algorithm>
+#include <map>
+
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_connection_stats.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+class CachedNetworkParameters;
+class RttStats;
+
+const QuicPacketCount kDefaultMaxCongestionWindowPackets = 2000;
+
+class NET_EXPORT_PRIVATE SendAlgorithmInterface {
+ public:
+ // A sorted vector of packets.
+ typedef std::vector<std::pair<QuicPacketNumber, QuicPacketLength>>
+ CongestionVector;
+
+ static SendAlgorithmInterface* Create(
+ const QuicClock* clock,
+ const RttStats* rtt_stats,
+ CongestionControlType type,
+ QuicConnectionStats* stats,
+ QuicPacketCount initial_congestion_window);
+
+ virtual ~SendAlgorithmInterface() {}
+
+ virtual void SetFromConfig(const QuicConfig& config,
+ Perspective perspective) = 0;
+
+ // Sets the number of connections to emulate when doing congestion control,
+ // particularly for congestion avoidance. Can be set any time.
+ virtual void SetNumEmulatedConnections(int num_connections) = 0;
+
+ // Indicates an update to the congestion state, caused either by an incoming
+ // ack or loss event timeout. |rtt_updated| indicates whether a new
+ // latest_rtt sample has been taken, |byte_in_flight| the bytes in flight
+ // prior to the congestion event. |acked_packets| and |lost_packets| are
+ // any packets considered acked or lost as a result of the congestion event.
+ virtual void OnCongestionEvent(bool rtt_updated,
+ QuicByteCount bytes_in_flight,
+ const CongestionVector& acked_packets,
+ const CongestionVector& lost_packets) = 0;
+
+ // Inform that we sent |bytes| to the wire, and if the packet is
+ // retransmittable. Returns true if the packet should be tracked by the
+ // congestion manager and included in bytes_in_flight, false otherwise.
+ // |bytes_in_flight| is the number of bytes in flight before the packet was
+ // sent.
+ // Note: this function must be called for every packet sent to the wire.
+ virtual bool OnPacketSent(QuicTime sent_time,
+ QuicByteCount bytes_in_flight,
+ QuicPacketNumber packet_number,
+ QuicByteCount bytes,
+ HasRetransmittableData is_retransmittable) = 0;
+
+ // Called when the retransmission timeout fires. Neither OnPacketAbandoned
+ // nor OnPacketLost will be called for these packets.
+ virtual void OnRetransmissionTimeout(bool packets_retransmitted) = 0;
+
+ // Called when connection migrates and cwnd needs to be reset.
+ virtual void OnConnectionMigration() = 0;
+
+ // Calculate the time until we can send the next packet.
+ virtual QuicTime::Delta TimeUntilSend(
+ QuicTime now,
+ QuicByteCount bytes_in_flight) const = 0;
+
+ // The pacing rate of the send algorithm. May be zero if the rate is unknown.
+ virtual QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const = 0;
+
+ // What's the current estimated bandwidth in bytes per second.
+ // Returns 0 when it does not have an estimate.
+ virtual QuicBandwidth BandwidthEstimate() const = 0;
+
+ // Returns the size of the current congestion window in bytes. Note, this is
+ // not the *available* window. Some send algorithms may not use a congestion
+ // window and will return 0.
+ virtual QuicByteCount GetCongestionWindow() const = 0;
+
+ // Whether the send algorithm is currently in slow start. When true, the
+ // BandwidthEstimate is expected to be too low.
+ virtual bool InSlowStart() const = 0;
+
+ // Whether the send algorithm is currently in recovery.
+ virtual bool InRecovery() const = 0;
+
+ // Returns the size of the slow start congestion window in bytes,
+ // aka ssthresh. Some send algorithms do not define a slow start
+ // threshold and will return 0.
+ virtual QuicByteCount GetSlowStartThreshold() const = 0;
+
+ virtual CongestionControlType GetCongestionControlType() const = 0;
+
+ // Called by the Session when we get a bandwidth estimate from the client.
+ // Uses the max bandwidth in the params if |max_bandwidth_resumption| is true.
+ virtual void ResumeConnectionState(
+ const CachedNetworkParameters& cached_network_params,
+ bool max_bandwidth_resumption) = 0;
+
+ // Retrieves debugging information about the current state of the
+ // send algorithm.
+ virtual std::string GetDebugState() const = 0;
+
+ // Called when the connection has no outstanding data to send. Specifically,
+ // this means that none of the data streams are write-blocked, there are no
+ // packets in the connection queue, and there are no pending retransmissins,
+ // i.e. the sender cannot send anything for reasons other than being blocked
+ // by congestion controller. This includes cases when the connection is
+ // blocked by the flow controller.
+ //
+ // The fact that this method is called does not necessarily imply that the
+ // connection would not be blocked by the congestion control if it actually
+ // tried to send data. If the congestion control algorithm needs to exclude
+ // such cases, it should use the internal state it uses for congestion control
+ // for that.
+ virtual void OnApplicationLimited(QuicByteCount bytes_in_flight) = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_INTERFACE_H_
diff --git a/chromium/net/quic/core/congestion_control/send_algorithm_simulator.cc b/chromium/net/quic/core/congestion_control/send_algorithm_simulator.cc
new file mode 100644
index 00000000000..7bc797aeef7
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/send_algorithm_simulator.cc
@@ -0,0 +1,400 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/congestion_control/send_algorithm_simulator.h"
+
+#include <stdint.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/rand_util.h"
+#include "net/quic/core/crypto/quic_random.h"
+
+using std::list;
+using std::max;
+using std::min;
+using std::string;
+using std::vector;
+
+namespace net {
+
+namespace {
+
+const QuicByteCount kPacketSize = 1200;
+
+} // namespace
+
+SendAlgorithmSimulator::Sender::Sender(SendAlgorithmInterface* send_algorithm,
+ RttStats* rtt_stats)
+ : Sender(send_algorithm, rtt_stats, QuicTime::Delta::Zero()) {}
+
+SendAlgorithmSimulator::Sender::Sender(SendAlgorithmInterface* send_algorithm,
+ RttStats* rtt_stats,
+ QuicTime::Delta additional_rtt)
+ : send_algorithm(send_algorithm),
+ rtt_stats(rtt_stats),
+ additional_rtt(additional_rtt),
+ last_sent(0),
+ last_acked(0),
+ next_acked(1),
+ max_cwnd(0),
+ min_cwnd(100000),
+ max_cwnd_drop(0),
+ last_cwnd(0),
+ last_transfer_bandwidth(QuicBandwidth::Zero()),
+ last_transfer_loss_rate(0) {}
+
+SendAlgorithmSimulator::Transfer::Transfer(Sender* sender,
+ QuicByteCount num_bytes,
+ QuicTime start_time,
+ string name)
+ : sender(sender),
+ num_bytes(num_bytes),
+ bytes_acked(0),
+ bytes_lost(0),
+ bytes_in_flight(0),
+ start_time(start_time),
+ name(std::move(name)) {}
+
+SendAlgorithmSimulator::SendAlgorithmSimulator(MockClock* clock,
+ QuicBandwidth bandwidth,
+ QuicTime::Delta rtt)
+ : clock_(clock),
+ lose_next_ack_(false),
+ forward_loss_rate_(0),
+ reverse_loss_rate_(0),
+ loss_correlation_(0),
+ bandwidth_(bandwidth),
+ rtt_(rtt),
+ buffer_size_(1000000),
+ delayed_ack_timer_(QuicTime::Delta::FromMilliseconds(100)) {
+ uint32_t seed = base::RandInt(0, std::numeric_limits<int32_t>::max());
+ DVLOG(1) << "Seeding SendAlgorithmSimulator with " << seed;
+ simple_random_.set_seed(seed);
+}
+
+SendAlgorithmSimulator::~SendAlgorithmSimulator() {}
+
+void SendAlgorithmSimulator::AddTransfer(Sender* sender, size_t num_bytes) {
+ AddTransfer(sender, num_bytes, clock_->Now(),
+ StringPrintf("#%zu", pending_transfers_.size()));
+}
+
+void SendAlgorithmSimulator::AddTransfer(Sender* sender,
+ size_t num_bytes,
+ QuicTime start_time,
+ string name) {
+ pending_transfers_.push_back(Transfer(sender, num_bytes, start_time, name));
+ // Record initial stats from when the transfer begins.
+ pending_transfers_.back().sender->RecordStats();
+}
+
+void SendAlgorithmSimulator::TransferBytes() {
+ TransferBytesUntil([](QuicTime, QuicByteCount) { return false; });
+}
+
+void SendAlgorithmSimulator::TransferBytes(QuicByteCount max_bytes,
+ QuicTime::Delta max_time) {
+ const QuicTime start_time = clock_->Now();
+ TransferBytesUntil([=](QuicTime now, QuicByteCount bytes_sent) {
+ return bytes_sent >= max_bytes || now - start_time > max_time;
+ });
+}
+
+template <class TerminationPredicate>
+bool SendAlgorithmSimulator::TransferBytesUntil(
+ TerminationPredicate termination_predicate) {
+ QuicByteCount bytes_sent = 0;
+ while (!pending_transfers_.empty() &&
+ !termination_predicate(clock_->Now(), bytes_sent)) {
+ // Determine the times of next send and of the next ack arrival.
+ PacketEvent send_event = NextSendEvent();
+ PacketEvent ack_event = NextAckEvent();
+ // If both times are infinite, fire a TLP.
+ if (ack_event.time_delta.IsInfinite() &&
+ send_event.time_delta.IsInfinite()) {
+ DVLOG(1) << "Both times are infinite, simulating a TLP.";
+ // TODO(ianswett): Use a more sophisticated TLP timer or never lose
+ // the last ack?
+ clock_->AdvanceTime(QuicTime::Delta::FromMilliseconds(100));
+ SendDataNow(&pending_transfers_.front());
+ } else if (ack_event.time_delta < send_event.time_delta) {
+ DVLOG(1) << "Handling ack of largest observed:"
+ << ack_event.transfer->sender->next_acked
+ << ", advancing time:" << ack_event.time_delta.ToMicroseconds()
+ << "us";
+ // Ack data all the data up to ack time and lose any missing packet
+ // numbers.
+ clock_->AdvanceTime(ack_event.time_delta);
+ HandlePendingAck(ack_event.transfer);
+ } else {
+ DVLOG(1) << "Sending transfer '" << send_event.transfer->name
+ << "', advancing time:" << send_event.time_delta.ToMicroseconds()
+ << "us";
+ clock_->AdvanceTime(send_event.time_delta);
+ SendDataNow(send_event.transfer);
+ bytes_sent += kPacketSize;
+ }
+ }
+
+ return !pending_transfers_.empty();
+}
+
+SendAlgorithmSimulator::PacketEvent SendAlgorithmSimulator::NextSendEvent() {
+ QuicTime::Delta next_send_time = QuicTime::Delta::Infinite();
+ Transfer* transfer = nullptr;
+ for (vector<Transfer>::iterator it = pending_transfers_.begin();
+ it != pending_transfers_.end(); ++it) {
+ // If we've already sent enough bytes, wait for them to be acked.
+ if (it->bytes_acked + it->bytes_in_flight >= it->num_bytes) {
+ continue;
+ }
+ // If the flow hasn't started, use the start time.
+ QuicTime::Delta transfer_send_time = it->start_time - clock_->Now();
+ if (clock_->Now() >= it->start_time) {
+ transfer_send_time = it->sender->send_algorithm->TimeUntilSend(
+ clock_->Now(), it->bytes_in_flight);
+ }
+ if (transfer_send_time < next_send_time) {
+ next_send_time = transfer_send_time;
+ transfer = &(*it);
+ }
+ }
+ DVLOG(1) << "NextSendTime returning delta(ms):"
+ << next_send_time.ToMilliseconds() << ", transfer '"
+ << transfer->name;
+ return PacketEvent(next_send_time, transfer);
+}
+
+// NextAck takes into account packet loss in both forward and reverse
+// direction, as well as correlated losses. And it assumes the receiver acks
+// every other packet when there is no loss.
+SendAlgorithmSimulator::PacketEvent SendAlgorithmSimulator::NextAckEvent() {
+ if (sent_packets_.empty()) {
+ DVLOG(1) << "No outstanding packets to ack for any transfer.";
+ return PacketEvent(QuicTime::Delta::Infinite(), nullptr);
+ }
+
+ // For each connection, find the next acked packet.
+ QuicTime::Delta ack_time = QuicTime::Delta::Infinite();
+ Transfer* transfer = nullptr;
+ for (vector<Transfer>::iterator it = pending_transfers_.begin();
+ it != pending_transfers_.end(); ++it) {
+ QuicTime::Delta transfer_ack_time = FindNextAcked(&(*it));
+ if (transfer_ack_time < ack_time) {
+ ack_time = transfer_ack_time;
+ transfer = &(*it);
+ }
+ }
+
+ return PacketEvent(ack_time, transfer);
+}
+
+QuicTime::Delta SendAlgorithmSimulator::FindNextAcked(Transfer* transfer) {
+ Sender* sender = transfer->sender;
+ if (sender->next_acked == sender->last_acked) {
+ // Determine if the next ack is lost only once, to ensure determinism.
+ lose_next_ack_ = reverse_loss_rate_ * std::numeric_limits<uint64_t>::max() >
+ simple_random_.RandUint64();
+ }
+
+ QuicPacketNumber next_acked = sender->last_acked;
+ QuicTime::Delta next_ack_delay =
+ FindNextAck(transfer, sender->last_acked, &next_acked);
+ if (lose_next_ack_) {
+ next_ack_delay = FindNextAck(transfer, next_acked, &next_acked);
+ }
+ sender->next_acked = next_acked;
+ return next_ack_delay;
+}
+
+QuicTime::Delta SendAlgorithmSimulator::FindNextAck(
+ const Transfer* transfer,
+ QuicPacketNumber last_acked,
+ QuicPacketNumber* next_acked) const {
+ *next_acked = last_acked;
+ QuicTime::Delta ack_delay = QuicTime::Delta::Infinite();
+ // Remove any packets that are simulated as lost.
+ for (list<SentPacket>::const_iterator it = sent_packets_.begin();
+ it != sent_packets_.end(); ++it) {
+ if (transfer != it->transfer) {
+ continue;
+ }
+ // Skip over any packets less than or equal to last_acked.
+ if (it->packet_number <= last_acked) {
+ continue;
+ }
+ // Lost packets don't trigger an ack.
+ if (it->lost) {
+ continue;
+ }
+ DCHECK_LT(*next_acked, it->packet_number);
+ // Consider a delayed ack for the current next_acked.
+ if (ack_delay < it->ack_time - clock_->Now()) {
+ break;
+ }
+ *next_acked = it->packet_number;
+ ack_delay = it->ack_time - clock_->Now();
+ if (HasRecentLostPackets(transfer, *next_acked) ||
+ (*next_acked - last_acked) >= 2) {
+ break;
+ }
+ ack_delay = ack_delay + delayed_ack_timer_;
+ }
+
+ DVLOG(1) << "FindNextAck found next_acked_:" << transfer->sender->next_acked
+ << " last_acked:" << transfer->sender->last_acked
+ << " ack_time(ms):" << ack_delay.ToMilliseconds();
+ return ack_delay;
+}
+
+bool SendAlgorithmSimulator::HasRecentLostPackets(
+ const Transfer* transfer,
+ QuicPacketNumber next_acked) const {
+ QuicPacketNumber last_packet = transfer->sender->last_acked;
+ for (list<SentPacket>::const_iterator it = sent_packets_.begin();
+ it != sent_packets_.end() && it->packet_number < next_acked; ++it) {
+ if (transfer != it->transfer) {
+ continue;
+ }
+ // Lost packets don't trigger an ack.
+ if (it->lost) {
+ return true;
+ }
+ // Buffer dropped packets are skipped automatically, but still end up
+ // being lost and cause acks to be sent immediately.
+ if (it->packet_number > last_packet + 1) {
+ return true;
+ }
+ last_packet = it->packet_number;
+ }
+ return false;
+}
+
+void SendAlgorithmSimulator::HandlePendingAck(Transfer* transfer) {
+ Sender* sender = transfer->sender;
+ DCHECK_LT(sender->last_acked, sender->next_acked);
+ SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ DVLOG(1) << "Acking packets from:" << sender->last_acked << " to "
+ << sender->next_acked
+ << " bytes_in_flight:" << transfer->bytes_in_flight
+ << " Now():" << (clock_->Now().ToDebuggingValue() / 1000) << "ms";
+ // Some entries may be missing from the sent_packets_ array, if they were
+ // dropped due to buffer overruns.
+ SentPacket largest_observed;
+ list<SentPacket>::iterator it = sent_packets_.begin();
+ while (sender->last_acked < sender->next_acked) {
+ ++sender->last_acked;
+ // Find the next SentPacket for this transfer.
+ while (it->transfer != transfer) {
+ DCHECK(it != sent_packets_.end());
+ ++it;
+ }
+ // If it's missing from the array, it's a loss.
+ if (it->packet_number > sender->last_acked) {
+ DVLOG(1) << "Lost packet:" << sender->last_acked
+ << " dropped by buffer overflow.";
+ lost_packets.push_back(std::make_pair(sender->last_acked, kPacketSize));
+ continue;
+ }
+ if (it->lost) {
+ lost_packets.push_back(std::make_pair(sender->last_acked, kPacketSize));
+ } else {
+ acked_packets.push_back(std::make_pair(sender->last_acked, kPacketSize));
+ }
+ // This packet has been acked or lost, remove it from sent_packets_.
+ largest_observed = *it;
+ sent_packets_.erase(it++);
+ }
+
+ DCHECK(!largest_observed.lost);
+ DVLOG(1) << "Updating RTT from send_time:"
+ << largest_observed.send_time.ToDebuggingValue()
+ << " to ack_time:" << largest_observed.ack_time.ToDebuggingValue();
+ QuicTime::Delta measured_rtt =
+ largest_observed.ack_time - largest_observed.send_time;
+ DCHECK_GE(measured_rtt.ToMicroseconds(), rtt_.ToMicroseconds());
+ sender->rtt_stats->UpdateRtt(measured_rtt, QuicTime::Delta::Zero(),
+ clock_->Now());
+ sender->send_algorithm->OnCongestionEvent(true, transfer->bytes_in_flight,
+ acked_packets, lost_packets);
+ DCHECK_LE(kPacketSize * (acked_packets.size() + lost_packets.size()),
+ transfer->bytes_in_flight);
+ transfer->bytes_in_flight -=
+ kPacketSize * (acked_packets.size() + lost_packets.size());
+
+ sender->RecordStats();
+ transfer->bytes_acked += acked_packets.size() * kPacketSize;
+ transfer->bytes_lost += lost_packets.size() * kPacketSize;
+ if (transfer->bytes_acked >= transfer->num_bytes) {
+ // Remove completed transfers and record transfer bandwidth.
+ QuicTime::Delta transfer_time = clock_->Now() - transfer->start_time;
+ sender->last_transfer_loss_rate =
+ static_cast<float>(transfer->bytes_lost) /
+ (transfer->bytes_lost + transfer->bytes_acked);
+ sender->last_transfer_bandwidth = QuicBandwidth::FromBytesAndTimeDelta(
+ transfer->num_bytes, transfer_time);
+ DCHECK_GE(bandwidth_.ToBitsPerSecond(),
+ sender->last_transfer_bandwidth.ToBitsPerSecond());
+ for (vector<Transfer>::iterator it = pending_transfers_.begin();
+ it != pending_transfers_.end(); ++it) {
+ if (transfer == &(*it)) {
+ pending_transfers_.erase(it);
+ break;
+ }
+ }
+ }
+}
+
+void SendAlgorithmSimulator::SendDataNow(Transfer* transfer) {
+ Sender* sender = transfer->sender;
+ ++sender->last_sent;
+ DVLOG(1) << "Sending packet:" << sender->last_sent
+ << " name:" << transfer->name
+ << " bytes_in_flight:" << transfer->bytes_in_flight
+ << " cwnd:" << sender->send_algorithm->GetCongestionWindow()
+ << " Now():" << (clock_->Now().ToDebuggingValue() / 1000) << "ms";
+ sender->send_algorithm->OnPacketSent(clock_->Now(), transfer->bytes_in_flight,
+ sender->last_sent, kPacketSize,
+ HAS_RETRANSMITTABLE_DATA);
+ // Lose the packet immediately if the buffer is full.
+ if (sent_packets_.size() * kPacketSize < buffer_size_) {
+ // TODO(ianswett): This buffer simulation is an approximation.
+ // An ack time of zero means loss.
+ bool packet_lost =
+ forward_loss_rate_ * std::numeric_limits<uint64_t>::max() >
+ simple_random_.RandUint64();
+ // Handle correlated loss.
+ if (!sent_packets_.empty() && sent_packets_.back().lost &&
+ loss_correlation_ * std::numeric_limits<uint64_t>::max() >
+ simple_random_.RandUint64()) {
+ packet_lost = true;
+ }
+ DVLOG(1) << "losing packet:" << sender->last_sent
+ << " name:" << transfer->name << " due to random loss.";
+
+ // If the number of bytes in flight are less than the bdp, there's
+ // no buffering delay. Bytes lost from the buffer are not counted.
+ QuicByteCount bdp = bandwidth_.ToBytesPerPeriod(rtt_);
+ QuicTime ack_time = clock_->Now() + rtt_ + sender->additional_rtt;
+ if (kPacketSize > bdp) {
+ ack_time = ack_time + bandwidth_.TransferTime(kPacketSize - bdp);
+ }
+ QuicTime queue_ack_time = sent_packets_.empty()
+ ? QuicTime::Zero()
+ : sent_packets_.back().ack_time +
+ bandwidth_.TransferTime(kPacketSize);
+ ack_time = std::max(ack_time, queue_ack_time);
+ sent_packets_.push_back(SentPacket(sender->last_sent, clock_->Now(),
+ ack_time, packet_lost, transfer));
+ } else {
+ DVLOG(1) << "losing packet:" << sender->last_sent
+ << " name:" << transfer->name << " because the buffer was full.";
+ }
+ transfer->bytes_in_flight += kPacketSize;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/send_algorithm_simulator.h b/chromium/net/quic/core/congestion_control/send_algorithm_simulator.h
new file mode 100644
index 00000000000..9b3974bdd2d
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/send_algorithm_simulator.h
@@ -0,0 +1,245 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A test only class to enable simulations of send algorithms.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_SIMULATOR_H_
+#define NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_SIMULATOR_H_
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/format_macros.h"
+#include "base/macros.h"
+#include "base/strings/stringprintf.h"
+#include "net/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+
+using base::StringPrintf;
+
+namespace net {
+
+class SendAlgorithmSimulator {
+ public:
+ struct Sender {
+ Sender(SendAlgorithmInterface* send_algorithm, RttStats* rtt_stats);
+ Sender(SendAlgorithmInterface* send_algorithm,
+ RttStats* rtt_stats,
+ QuicTime::Delta additional_rtt);
+
+ void RecordStats() {
+ QuicByteCount cwnd = send_algorithm->GetCongestionWindow();
+ max_cwnd = std::max(max_cwnd, cwnd);
+ min_cwnd = std::min(min_cwnd, cwnd);
+ if (last_cwnd > cwnd) {
+ max_cwnd_drop = std::max(max_cwnd_drop, last_cwnd - cwnd);
+ }
+ last_cwnd = cwnd;
+ }
+
+ std::string DebugString() {
+ return StringPrintf("observed goodput(bytes/s):%" PRId64
+ " loss rate:%f"
+ " cwnd:%" PRIu64 " max_cwnd:%" PRIu64
+ " min_cwnd:%" PRIu64 " max_cwnd_drop:%" PRIu64,
+ last_transfer_bandwidth.ToBytesPerSecond(),
+ last_transfer_loss_rate,
+ send_algorithm->GetCongestionWindow(), max_cwnd,
+ min_cwnd, max_cwnd_drop);
+ }
+
+ SendAlgorithmInterface* send_algorithm;
+ RttStats* rtt_stats;
+ QuicTime::Delta additional_rtt;
+
+ // Last packet number the sender sent.
+ QuicPacketNumber last_sent;
+ // Last packet number acked.
+ QuicPacketNumber last_acked;
+ // packet number to ack up to.
+ QuicPacketNumber next_acked;
+
+ // Stats collected for understanding the congestion control.
+ QuicByteCount max_cwnd;
+ QuicByteCount min_cwnd;
+ QuicByteCount max_cwnd_drop;
+ QuicByteCount last_cwnd;
+
+ QuicBandwidth last_transfer_bandwidth;
+ float last_transfer_loss_rate;
+ };
+
+ struct Transfer {
+ Transfer(Sender* sender,
+ QuicByteCount num_bytes,
+ QuicTime start_time,
+ std::string name);
+
+ Sender* sender;
+ QuicByteCount num_bytes;
+ QuicByteCount bytes_acked;
+ QuicByteCount bytes_lost;
+ QuicByteCount bytes_in_flight;
+ QuicTime start_time;
+ std::string name;
+ };
+
+ struct SentPacket {
+ SentPacket()
+ : packet_number(0),
+ send_time(QuicTime::Zero()),
+ ack_time(QuicTime::Zero()),
+ lost(false),
+ transfer(nullptr) {}
+ SentPacket(QuicPacketNumber packet_number,
+ QuicTime send_time,
+ QuicTime ack_time,
+ bool lost,
+ Transfer* transfer)
+ : packet_number(packet_number),
+ send_time(send_time),
+ ack_time(ack_time),
+ lost(lost),
+ transfer(transfer) {}
+
+ QuicPacketNumber packet_number;
+ QuicTime send_time;
+ QuicTime ack_time;
+ bool lost;
+ Transfer* transfer;
+ };
+
+ // |rtt_stats| should be the same RttStats used by the |send_algorithm|.
+ SendAlgorithmSimulator(MockClock* clock_,
+ QuicBandwidth bandwidth,
+ QuicTime::Delta rtt);
+ ~SendAlgorithmSimulator();
+
+ // For local ad-hoc testing.
+ void set_bandwidth(QuicBandwidth bandwidth) { bandwidth_ = bandwidth; }
+
+ void set_forward_loss_rate(float loss_rate) {
+ DCHECK_LT(loss_rate, 1.0f);
+ forward_loss_rate_ = loss_rate;
+ }
+
+ // For local ad-hoc testing.
+ void set_reverse_loss_rate(float loss_rate) {
+ DCHECK_LT(loss_rate, 1.0f);
+ reverse_loss_rate_ = loss_rate;
+ }
+
+ // For local ad-hoc testing.
+ void set_loss_correlation(float loss_correlation) {
+ DCHECK_LT(loss_correlation, 1.0f);
+ loss_correlation_ = loss_correlation;
+ }
+
+ void set_buffer_size(size_t buffer_size_bytes) {
+ buffer_size_ = buffer_size_bytes;
+ }
+
+ void set_delayed_ack_timer(QuicTime::Delta delayed_ack_timer) {
+ delayed_ack_timer_ = delayed_ack_timer;
+ }
+
+ // Advance the time by |delta| without sending anything.
+ // For local ad-hoc testing.
+ void AdvanceTime(QuicTime::Delta delta);
+
+ // Adds a pending sender. The send will run when TransferBytes is called.
+ // Adding two transfers with the same sender is unsupported.
+ void AddTransfer(Sender* sender, size_t num_bytes);
+
+ // Adds a pending sending to start at the specified time.
+ void AddTransfer(Sender* sender,
+ size_t num_bytes,
+ QuicTime start_time,
+ std::string name);
+
+ // Convenience method to transfer all bytes.
+ void TransferBytes();
+
+ // Transfers bytes through the connection until |max_bytes| are reached,
+ // |max_time| is reached, or all senders have finished sending. If |max_time|
+ // is Zero, no time limit applies.
+ void TransferBytes(QuicByteCount max_bytes, QuicTime::Delta max_time);
+
+ // Transfers bytes through the connection until the supplied termination
+ // predicate returns true, or until all senders have finished sending.
+ // Returns true if the transfer was terminated due to the predicate, and false
+ // otherwise.
+ template <class TerminationPredicate>
+ bool TransferBytesUntil(TerminationPredicate termination_predicate);
+
+ private:
+ // A pending packet event, either a send or an ack.
+ struct PacketEvent {
+ PacketEvent(QuicTime::Delta time_delta, Transfer* transfer)
+ : time_delta(time_delta), transfer(transfer) {}
+
+ QuicTime::Delta time_delta;
+ Transfer* transfer;
+ };
+
+ // NextSendTime returns the next time any of the pending transfers send,
+ // and populates transfer if the send time is not infinite.
+ PacketEvent NextSendEvent();
+
+ // NextAckTime takes into account packet loss in both forward and reverse
+ // direction, as well as delayed ack behavior.
+ PacketEvent NextAckEvent();
+
+ // Sets the next acked.
+ QuicTime::Delta FindNextAcked(Transfer* transfer);
+
+ // Sets the |next_acked| packet for the |transfer| starting at the specified
+ // |last_acked|. Returns QuicTime::Delta::Infinite and doesn't set
+ // |next_acked| if there is no ack after |last_acked|.
+ QuicTime::Delta FindNextAck(const Transfer* transfer,
+ QuicPacketNumber last_acked,
+ QuicPacketNumber* next_acked) const;
+
+ // Returns true if any of the packets |transfer| is waiting for less than
+ // next_acked have been lost.
+ bool HasRecentLostPackets(const Transfer* transfer,
+ QuicPacketNumber next_acked) const;
+
+ // Process all the acks that should have arrived by the current time, and
+ // lose any packets that are missing. Returns the number of bytes acked.
+ void HandlePendingAck(Transfer* transfer);
+
+ void SendDataNow(Transfer* transfer);
+
+ // List of all pending transfers waiting to use the connection.
+ std::vector<Transfer> pending_transfers_;
+
+ MockClock* clock_;
+ // Whether the next ack should be lost.
+ bool lose_next_ack_;
+ // The times acks are expected, assuming acks are not lost and every packet
+ // is acked.
+ std::list<SentPacket> sent_packets_;
+
+ test::SimpleRandom simple_random_;
+ float forward_loss_rate_; // Loss rate on the forward path.
+ float reverse_loss_rate_; // Loss rate on the reverse path.
+ float loss_correlation_; // Likelihood the subsequent packet is lost.
+ QuicBandwidth bandwidth_;
+ QuicTime::Delta rtt_;
+ size_t buffer_size_; // In bytes.
+ QuicTime::Delta delayed_ack_timer_;
+
+ DISALLOW_COPY_AND_ASSIGN(SendAlgorithmSimulator);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CONGESTION_CONTROL_SEND_ALGORITHM_SIMULATOR_H_
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
new file mode 100644
index 00000000000..7a3641e1159
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.cc
@@ -0,0 +1,285 @@
+// 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 <string>
+
+#include "base/metrics/histogram_macros.h"
+#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/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+
+using std::max;
+using std::min;
+
+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.
+const float kRateBasedExtraCwnd = 1.5f; // CWND for rate based sending.
+} // 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),
+ rate_based_sending_(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;
+ }
+ if (config.HasReceivedConnectionOptions() &&
+ ContainsQuicTag(config.ReceivedConnectionOptions(), kRATE)) {
+ // Rate based sending experiment
+ rate_based_sending_ = true;
+ }
+ }
+}
+
+void TcpCubicSenderBase::ResumeConnectionState(
+ const CachedNetworkParameters& cached_network_params,
+ bool max_bandwidth_resumption) {
+ QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond(
+ max_bandwidth_resumption
+ ? cached_network_params.max_bandwidth_estimate_bytes_per_second()
+ : cached_network_params.bandwidth_estimate_bytes_per_second());
+ QuicTime::Delta rtt =
+ QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms());
+
+ SetCongestionWindowFromBandwidthAndRtt(bandwidth, rtt);
+}
+
+void TcpCubicSenderBase::SetNumEmulatedConnections(int num_connections) {
+ num_connections_ = 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 bytes_in_flight,
+ const CongestionVector& acked_packets,
+ const CongestionVector& lost_packets) {
+ if (rtt_updated && InSlowStart() &&
+ hybrid_slow_start_.ShouldExitSlowStart(
+ rtt_stats_->latest_rtt(), rtt_stats_->min_rtt(),
+ GetCongestionWindow() / kDefaultTCPMSS)) {
+ ExitSlowstart();
+ }
+ for (CongestionVector::const_iterator it = lost_packets.begin();
+ it != lost_packets.end(); ++it) {
+ OnPacketLost(it->first, it->second, bytes_in_flight);
+ }
+ for (CongestionVector::const_iterator it = acked_packets.begin();
+ it != acked_packets.end(); ++it) {
+ OnPacketAcked(it->first, it->second, bytes_in_flight);
+ }
+}
+
+void TcpCubicSenderBase::OnPacketAcked(QuicPacketNumber acked_packet_number,
+ QuicByteCount acked_bytes,
+ QuicByteCount bytes_in_flight) {
+ largest_acked_packet_number_ =
+ 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, bytes_in_flight);
+ if (InSlowStart()) {
+ hybrid_slow_start_.OnPacketAcked(acked_packet_number);
+ }
+}
+
+bool TcpCubicSenderBase::OnPacketSent(
+ QuicTime /*sent_time*/,
+ QuicByteCount /*bytes_in_flight*/,
+ QuicPacketNumber packet_number,
+ QuicByteCount bytes,
+ HasRetransmittableData is_retransmittable) {
+ if (InSlowStart()) {
+ ++(stats_->slowstart_packets_sent);
+ }
+
+ // Only update bytes_in_flight_ for data packets.
+ if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) {
+ return false;
+ }
+ 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);
+ return true;
+}
+
+QuicTime::Delta TcpCubicSenderBase::TimeUntilSend(
+ QuicTime /* now */,
+ QuicByteCount bytes_in_flight) const {
+ if (!no_prr_ && InRecovery()) {
+ // PRR is used when in recovery.
+ return prr_.TimeUntilSend(GetCongestionWindow(), bytes_in_flight,
+ GetSlowStartThreshold());
+ }
+ if (GetCongestionWindow() > bytes_in_flight) {
+ return QuicTime::Delta::Zero();
+ }
+ if (min4_mode_ && bytes_in_flight < 4 * kDefaultTCPMSS) {
+ return QuicTime::Delta::Zero();
+ }
+ if (rate_based_sending_ &&
+ GetCongestionWindow() * kRateBasedExtraCwnd > bytes_in_flight) {
+ return QuicTime::Delta::Zero();
+ }
+ return QuicTime::Delta::Infinite();
+}
+
+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);
+ if (rate_based_sending_ && bytes_in_flight > GetCongestionWindow()) {
+ // Rate based sending allows sending more than CWND, but reduces the pacing
+ // rate when the bytes in flight is more than the CWND to 75% of bandwidth.
+ return 0.75 * bandwidth;
+ }
+ 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;
+}
+
+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
new file mode 100644
index 00000000000..7a892705a7d
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_base.h
@@ -0,0 +1,159 @@
+// 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_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BASE_H_
+#define NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BASE_H_
+
+#include <stdint.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/congestion_control/cubic.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_protocol.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+class RttStats;
+
+// Maximum window to allow when doing bandwidth resumption.
+const QuicPacketCount kMaxResumptionCongestionWindow = 200;
+
+namespace test {
+class TcpCubicSenderBasePeer;
+} // namespace test
+
+class NET_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 ResumeConnectionState(
+ const CachedNetworkParameters& cached_network_params,
+ bool max_bandwidth_resumption) override;
+ void SetNumEmulatedConnections(int num_connections) override;
+ void OnCongestionEvent(bool rtt_updated,
+ QuicByteCount bytes_in_flight,
+ const CongestionVector& acked_packets,
+ const CongestionVector& lost_packets) override;
+ bool 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;
+ QuicTime::Delta TimeUntilSend(QuicTime now,
+ QuicByteCount bytes_in_flight) const override;
+ QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const override;
+ QuicBandwidth BandwidthEstimate() const override;
+ bool InSlowStart() const override;
+ bool InRecovery() 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 bytes_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 bytes_in_flight) = 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 bytes_in_flight);
+
+ 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 rate based sending instead of only sending if there's CWND.
+ bool rate_based_sending_;
+
+ // When true, use unity pacing instead of PRR.
+ bool no_prr_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TcpCubicSenderBase);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_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
new file mode 100644
index 00000000000..a974246f64d
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.cc
@@ -0,0 +1,217 @@
+// 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.
+
+#include "net/quic/core/congestion_control/tcp_cubic_sender_bytes.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/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+
+using std::max;
+using std::min;
+
+namespace net {
+
+namespace {
+// Constants based on TCP defaults.
+// The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a
+// fast retransmission.
+const QuicByteCount kDefaultMinimumCongestionWindow = 2 * kDefaultTCPMSS;
+} // namespace
+
+TcpCubicSenderBytes::TcpCubicSenderBytes(
+ const QuicClock* clock,
+ const RttStats* rtt_stats,
+ bool reno,
+ QuicPacketCount initial_tcp_congestion_window,
+ QuicPacketCount max_congestion_window,
+ QuicConnectionStats* stats)
+ : TcpCubicSenderBase(clock, rtt_stats, reno, stats),
+ cubic_(clock),
+ num_acked_packets_(0),
+ congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS),
+ min_congestion_window_(kDefaultMinimumCongestionWindow),
+ max_congestion_window_(max_congestion_window * kDefaultTCPMSS),
+ slowstart_threshold_(max_congestion_window * kDefaultTCPMSS),
+ initial_tcp_congestion_window_(initial_tcp_congestion_window *
+ kDefaultTCPMSS),
+ initial_max_tcp_congestion_window_(max_congestion_window *
+ kDefaultTCPMSS),
+ min_slow_start_exit_window_(min_congestion_window_) {}
+
+TcpCubicSenderBytes::~TcpCubicSenderBytes() {}
+
+void TcpCubicSenderBytes::SetCongestionWindowFromBandwidthAndRtt(
+ QuicBandwidth bandwidth,
+ QuicTime::Delta rtt) {
+ QuicByteCount new_congestion_window = bandwidth.ToBytesPerPeriod(rtt);
+ if (FLAGS_quic_no_lower_bw_resumption_limit) {
+ // Limit new CWND if needed.
+ congestion_window_ =
+ max(min_congestion_window_,
+ min(new_congestion_window,
+ kMaxResumptionCongestionWindow * kDefaultTCPMSS));
+ } else {
+ congestion_window_ =
+ max(min(new_congestion_window,
+ kMaxResumptionCongestionWindow * kDefaultTCPMSS),
+ kMinCongestionWindowForBandwidthResumption * kDefaultTCPMSS);
+ }
+}
+
+void TcpCubicSenderBytes::SetCongestionWindowInPackets(
+ QuicPacketCount congestion_window) {
+ congestion_window_ = congestion_window * kDefaultTCPMSS;
+}
+
+void TcpCubicSenderBytes::SetMinCongestionWindowInPackets(
+ QuicPacketCount congestion_window) {
+ min_congestion_window_ = congestion_window * kDefaultTCPMSS;
+}
+
+void TcpCubicSenderBytes::SetNumEmulatedConnections(int num_connections) {
+ TcpCubicSenderBase::SetNumEmulatedConnections(num_connections);
+ cubic_.SetNumConnections(num_connections_);
+}
+
+void TcpCubicSenderBytes::ExitSlowstart() {
+ slowstart_threshold_ = congestion_window_;
+}
+
+void TcpCubicSenderBytes::OnPacketLost(QuicPacketNumber packet_number,
+ QuicByteCount lost_bytes,
+ QuicByteCount bytes_in_flight) {
+ // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets
+ // already sent should be treated as a single loss event, since it's expected.
+ if (packet_number <= largest_sent_at_last_cutback_) {
+ if (last_cutback_exited_slowstart_) {
+ ++stats_->slowstart_packets_lost;
+ stats_->slowstart_bytes_lost += lost_bytes;
+ if (slow_start_large_reduction_) {
+ // Reduce congestion window by lost_bytes for every loss.
+ congestion_window_ =
+ max(congestion_window_ - lost_bytes, min_slow_start_exit_window_);
+ slowstart_threshold_ = congestion_window_;
+ }
+ }
+ DVLOG(1) << "Ignoring loss for largest_missing:" << packet_number
+ << " because it was sent prior to the last CWND cutback.";
+ return;
+ }
+ ++stats_->tcp_loss_events;
+ last_cutback_exited_slowstart_ = InSlowStart();
+ if (InSlowStart()) {
+ ++stats_->slowstart_packets_lost;
+ }
+
+ if (!no_prr_) {
+ prr_.OnPacketLost(bytes_in_flight);
+ }
+
+ // TODO(jri): Separate out all of slow start into a separate class.
+ if (slow_start_large_reduction_ && InSlowStart()) {
+ DCHECK_LT(kDefaultTCPMSS, congestion_window_);
+ if (congestion_window_ >= 2 * initial_tcp_congestion_window_) {
+ min_slow_start_exit_window_ = congestion_window_ / 2;
+ }
+ congestion_window_ = congestion_window_ - kDefaultTCPMSS;
+ } else if (reno_) {
+ congestion_window_ = congestion_window_ * RenoBeta();
+ } else {
+ congestion_window_ =
+ cubic_.CongestionWindowAfterPacketLoss(congestion_window_);
+ }
+ if (congestion_window_ < min_congestion_window_) {
+ congestion_window_ = min_congestion_window_;
+ }
+ slowstart_threshold_ = congestion_window_;
+ largest_sent_at_last_cutback_ = largest_sent_packet_number_;
+ // Reset packet count from congestion avoidance mode. We start counting again
+ // when we're out of recovery.
+ num_acked_packets_ = 0;
+ DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_
+ << " slowstart threshold: " << slowstart_threshold_;
+}
+
+QuicByteCount TcpCubicSenderBytes::GetCongestionWindow() const {
+ return congestion_window_;
+}
+
+QuicByteCount TcpCubicSenderBytes::GetSlowStartThreshold() const {
+ return slowstart_threshold_;
+}
+
+// Called when we receive an ack. Normal TCP tracks how many packets one ack
+// represents, but quic has a separate ack for each packet.
+void TcpCubicSenderBytes::MaybeIncreaseCwnd(
+ QuicPacketNumber acked_packet_number,
+ QuicByteCount acked_bytes,
+ QuicByteCount bytes_in_flight) {
+ QUIC_BUG_IF(InRecovery()) << "Never increase the CWND during recovery.";
+ // Do not increase the congestion window unless the sender is close to using
+ // the current window.
+ if (!IsCwndLimited(bytes_in_flight)) {
+ cubic_.OnApplicationLimited();
+ return;
+ }
+ if (congestion_window_ >= max_congestion_window_) {
+ return;
+ }
+ if (InSlowStart()) {
+ // TCP slow start, exponential growth, increase by one for each ACK.
+ congestion_window_ += kDefaultTCPMSS;
+ DVLOG(1) << "Slow start; congestion window: " << congestion_window_
+ << " slowstart threshold: " << slowstart_threshold_;
+ return;
+ }
+ // Congestion avoidance.
+ if (reno_) {
+ // Classic Reno congestion avoidance.
+ ++num_acked_packets_;
+ // Divide by num_connections to smoothly increase the CWND at a faster rate
+ // than conventional Reno.
+ if (num_acked_packets_ * num_connections_ >=
+ congestion_window_ / kDefaultTCPMSS) {
+ congestion_window_ += kDefaultTCPMSS;
+ num_acked_packets_ = 0;
+ }
+
+ DVLOG(1) << "Reno; congestion window: " << congestion_window_
+ << " slowstart threshold: " << slowstart_threshold_
+ << " congestion window count: " << num_acked_packets_;
+ } else {
+ congestion_window_ =
+ min(max_congestion_window_,
+ cubic_.CongestionWindowAfterAck(acked_bytes, congestion_window_,
+ rtt_stats_->min_rtt()));
+ DVLOG(1) << "Cubic; congestion window: " << congestion_window_
+ << " slowstart threshold: " << slowstart_threshold_;
+ }
+}
+
+void TcpCubicSenderBytes::HandleRetransmissionTimeout() {
+ cubic_.Reset();
+ slowstart_threshold_ = congestion_window_ / 2;
+ congestion_window_ = min_congestion_window_;
+}
+
+void TcpCubicSenderBytes::OnConnectionMigration() {
+ TcpCubicSenderBase::OnConnectionMigration();
+ cubic_.Reset();
+ num_acked_packets_ = 0;
+ congestion_window_ = initial_tcp_congestion_window_;
+ max_congestion_window_ = initial_max_tcp_congestion_window_;
+ slowstart_threshold_ = initial_max_tcp_congestion_window_;
+}
+
+CongestionControlType TcpCubicSenderBytes::GetCongestionControlType() const {
+ return reno_ ? kRenoBytes : kCubicBytes;
+}
+
+} // namespace net
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
new file mode 100644
index 00000000000..cf47f7ef3ba
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes.h
@@ -0,0 +1,103 @@
+// 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.
+
+// TCP cubic send side congestion algorithm, emulates the behavior of TCP cubic.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BYTES_H_
+#define NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BYTES_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#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/quic_bandwidth.h"
+#include "net/quic/core/quic_connection_stats.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+class RttStats;
+
+namespace test {
+class TcpCubicSenderBytesPeer;
+} // namespace test
+
+class NET_EXPORT_PRIVATE TcpCubicSenderBytes : public TcpCubicSenderBase {
+ public:
+ TcpCubicSenderBytes(const QuicClock* clock,
+ const RttStats* rtt_stats,
+ bool reno,
+ QuicPacketCount initial_tcp_congestion_window,
+ QuicPacketCount max_congestion_window,
+ QuicConnectionStats* stats);
+ ~TcpCubicSenderBytes() override;
+
+ // Start implementation of SendAlgorithmInterface.
+ void SetNumEmulatedConnections(int num_connections) override;
+ void OnConnectionMigration() override;
+ QuicByteCount GetCongestionWindow() const override;
+ QuicByteCount GetSlowStartThreshold() const override;
+ CongestionControlType GetCongestionControlType() const override;
+ // End implementation of SendAlgorithmInterface.
+
+ QuicByteCount min_congestion_window() const { return min_congestion_window_; }
+
+ protected:
+ // TcpCubicSenderBase methods
+ void SetCongestionWindowFromBandwidthAndRtt(QuicBandwidth bandwidth,
+ QuicTime::Delta rtt) override;
+ void SetCongestionWindowInPackets(QuicPacketCount congestion_window) override;
+ void SetMinCongestionWindowInPackets(
+ QuicPacketCount congestion_window) override;
+ void ExitSlowstart() override;
+ void OnPacketLost(QuicPacketNumber largest_loss,
+ QuicByteCount lost_bytes,
+ QuicByteCount bytes_in_flight) override;
+ void MaybeIncreaseCwnd(QuicPacketNumber acked_packet_number,
+ QuicByteCount acked_bytes,
+ QuicByteCount bytes_in_flight) override;
+ void HandleRetransmissionTimeout() override;
+
+ private:
+ friend class test::TcpCubicSenderBytesPeer;
+
+ CubicBytes cubic_;
+
+ // ACK counter for the Reno implementation.
+ uint64_t num_acked_packets_;
+
+ // Congestion window in bytes.
+ QuicByteCount congestion_window_;
+
+ // Minimum congestion window in bytes.
+ QuicByteCount min_congestion_window_;
+
+ // Maximum congestion window in bytes.
+ QuicByteCount max_congestion_window_;
+
+ // Slow start congestion window in bytes, aka ssthresh.
+ QuicByteCount slowstart_threshold_;
+
+ // Initial TCP congestion window in bytes. This variable can only be set when
+ // this algorithm is created.
+ const QuicByteCount initial_tcp_congestion_window_;
+
+ // Initial maximum TCP congestion window in bytes. This variable can only be
+ // set when this algorithm is created.
+ const QuicByteCount initial_max_tcp_congestion_window_;
+
+ // The minimum window when exiting slow start with large reduction.
+ QuicByteCount min_slow_start_exit_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(TcpCubicSenderBytes);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_BYTES_SENDER_H_
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
new file mode 100644
index 00000000000..bc80426ec76
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
@@ -0,0 +1,895 @@
+// 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.
+
+#include "net/quic/core/congestion_control/tcp_cubic_sender_bytes.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <memory>
+
+#include "base/logging.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/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/quic_config_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+// TODO(ianswett): A number of theses tests were written with the assumption of
+// an initial CWND of 10. They have carefully calculated values which should be
+// updated to be based on kInitialCongestionWindow.
+const uint32_t kInitialCongestionWindowPackets = 10;
+const uint32_t kMaxCongestionWindowPackets = 200;
+const uint32_t kDefaultWindowTCP =
+ kInitialCongestionWindowPackets * kDefaultTCPMSS;
+const float kRenoBeta = 0.7f; // Reno backoff factor.
+
+class TcpCubicSenderBytesPeer : public TcpCubicSenderBytes {
+ public:
+ TcpCubicSenderBytesPeer(const QuicClock* clock, bool reno)
+ : TcpCubicSenderBytes(clock,
+ &rtt_stats_,
+ reno,
+ kInitialCongestionWindowPackets,
+ kMaxCongestionWindowPackets,
+ &stats_) {}
+
+ const HybridSlowStart& hybrid_slow_start() const {
+ return hybrid_slow_start_;
+ }
+
+ float GetRenoBeta() const { return RenoBeta(); }
+
+ RttStats rtt_stats_;
+ QuicConnectionStats stats_;
+};
+
+class TcpCubicSenderBytesTest : public ::testing::Test {
+ protected:
+ TcpCubicSenderBytesTest()
+ : one_ms_(QuicTime::Delta::FromMilliseconds(1)),
+ sender_(new TcpCubicSenderBytesPeer(&clock_, true)),
+ packet_number_(1),
+ acked_packet_number_(0),
+ bytes_in_flight_(0) {}
+
+ int SendAvailableSendWindow() {
+ return SendAvailableSendWindow(kDefaultTCPMSS);
+ }
+
+ int SendAvailableSendWindow(QuicPacketLength packet_length) {
+ // Send as long as TimeUntilSend returns Zero.
+ int packets_sent = 0;
+ bool can_send =
+ sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_).IsZero();
+ while (can_send) {
+ sender_->OnPacketSent(clock_.Now(), bytes_in_flight_, packet_number_++,
+ kDefaultTCPMSS, HAS_RETRANSMITTABLE_DATA);
+ ++packets_sent;
+ bytes_in_flight_ += kDefaultTCPMSS;
+ can_send =
+ sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_).IsZero();
+ }
+ return packets_sent;
+ }
+
+ // Normal is that TCP acks every other segment.
+ void AckNPackets(int n) {
+ sender_->rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(60),
+ QuicTime::Delta::Zero(), clock_.Now());
+ SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ for (int i = 0; i < n; ++i) {
+ ++acked_packet_number_;
+ acked_packets.push_back(
+ std::make_pair(acked_packet_number_, kDefaultTCPMSS));
+ }
+ sender_->OnCongestionEvent(true, bytes_in_flight_, acked_packets,
+ lost_packets);
+ bytes_in_flight_ -= n * kDefaultTCPMSS;
+ clock_.AdvanceTime(one_ms_);
+ }
+
+ void LoseNPackets(int n) { LoseNPackets(n, kDefaultTCPMSS); }
+
+ void LoseNPackets(int n, QuicPacketLength packet_length) {
+ SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ for (int i = 0; i < n; ++i) {
+ ++acked_packet_number_;
+ lost_packets.push_back(
+ std::make_pair(acked_packet_number_, packet_length));
+ }
+ sender_->OnCongestionEvent(false, bytes_in_flight_, acked_packets,
+ lost_packets);
+ bytes_in_flight_ -= n * packet_length;
+ }
+
+ // Does not increment acked_packet_number_.
+ void LosePacket(QuicPacketNumber packet_number) {
+ SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ lost_packets.push_back(std::make_pair(packet_number, kDefaultTCPMSS));
+ sender_->OnCongestionEvent(false, bytes_in_flight_, acked_packets,
+ lost_packets);
+ bytes_in_flight_ -= kDefaultTCPMSS;
+ }
+
+ const QuicTime::Delta one_ms_;
+ MockClock clock_;
+ std::unique_ptr<TcpCubicSenderBytesPeer> sender_;
+ QuicPacketNumber packet_number_;
+ QuicPacketNumber acked_packet_number_;
+ QuicByteCount bytes_in_flight_;
+};
+
+TEST_F(TcpCubicSenderBytesTest, SimpleSender) {
+ // At startup make sure we are at the default.
+ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+ // At startup make sure we can send.
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
+ // Make sure we can send.
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
+ // And that window is un-affected.
+ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+
+ // Fill the send window with data, then verify that we can't send.
+ SendAvailableSendWindow();
+ EXPECT_FALSE(
+ sender_->TimeUntilSend(clock_.Now(), sender_->GetCongestionWindow())
+ .IsZero());
+}
+
+TEST_F(TcpCubicSenderBytesTest, ApplicationLimitedSlowStart) {
+ // Send exactly 10 packets and ensure the CWND ends at 14 packets.
+ const int kNumberOfAcks = 5;
+ // At startup make sure we can send.
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
+ // Make sure we can send.
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
+
+ SendAvailableSendWindow();
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ AckNPackets(2);
+ }
+ QuicByteCount bytes_to_send = sender_->GetCongestionWindow();
+ // It's expected 2 acks will arrive when the bytes_in_flight are greater than
+ // half the CWND.
+ EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * 2, bytes_to_send);
+}
+
+TEST_F(TcpCubicSenderBytesTest, ExponentialSlowStart) {
+ const int kNumberOfAcks = 20;
+ // At startup make sure we can send.
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
+ EXPECT_EQ(QuicBandwidth::Zero(), sender_->BandwidthEstimate());
+ // Make sure we can send.
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
+
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ const QuicByteCount cwnd = sender_->GetCongestionWindow();
+ EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * kNumberOfAcks, cwnd);
+ EXPECT_EQ(QuicBandwidth::FromBytesAndTimeDelta(
+ cwnd, sender_->rtt_stats_.smoothed_rtt()),
+ sender_->BandwidthEstimate());
+}
+
+TEST_F(TcpCubicSenderBytesTest, SlowStartPacketLoss) {
+ sender_->SetNumEmulatedConnections(1);
+ const int kNumberOfAcks = 10;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose a packet to exit slow start.
+ LoseNPackets(1);
+ size_t packets_in_recovery_window = expected_send_window / kDefaultTCPMSS;
+
+ // We should now have fallen out of slow start with a reduced window.
+ expected_send_window *= kRenoBeta;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Recovery phase. We need to ack every packet in the recovery window before
+ // we exit recovery.
+ size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
+ DVLOG(1) << "number_packets: " << number_of_packets_in_window;
+ AckNPackets(packets_in_recovery_window);
+ SendAvailableSendWindow();
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // We need to ack an entire window before we increase CWND by 1.
+ AckNPackets(number_of_packets_in_window - 2);
+ SendAvailableSendWindow();
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Next ack should increase cwnd by 1.
+ AckNPackets(1);
+ expected_send_window += kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Now RTO and ensure slow start gets reset.
+ EXPECT_TRUE(sender_->hybrid_slow_start().started());
+ sender_->OnRetransmissionTimeout(true);
+ EXPECT_FALSE(sender_->hybrid_slow_start().started());
+}
+
+TEST_F(TcpCubicSenderBytesTest, SlowStartPacketLossWithLargeReduction) {
+ QuicConfig config;
+ QuicTagVector options;
+ options.push_back(kSSLR);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+
+ sender_->SetNumEmulatedConnections(1);
+ const int kNumberOfAcks = (kDefaultWindowTCP / (2 * kDefaultTCPMSS)) - 1;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose a packet to exit slow start. We should now have fallen out of
+ // slow start with a window reduced by 1.
+ LoseNPackets(1);
+ expected_send_window -= kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose 5 packets in recovery and verify that congestion window is reduced
+ // further.
+ LoseNPackets(5);
+ expected_send_window -= 5 * kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ // Lose another 10 packets and ensure it reduces below half the peak CWND,
+ // because we never acked the full IW.
+ LoseNPackets(10);
+ expected_send_window -= 10 * kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ size_t packets_in_recovery_window = expected_send_window / kDefaultTCPMSS;
+
+ // Recovery phase. We need to ack every packet in the recovery window before
+ // we exit recovery.
+ size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
+ DVLOG(1) << "number_packets: " << number_of_packets_in_window;
+ AckNPackets(packets_in_recovery_window);
+ SendAvailableSendWindow();
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // We need to ack an entire window before we increase CWND by 1.
+ AckNPackets(number_of_packets_in_window - 1);
+ SendAvailableSendWindow();
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Next ack should increase cwnd by 1.
+ AckNPackets(1);
+ expected_send_window += kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Now RTO and ensure slow start gets reset.
+ EXPECT_TRUE(sender_->hybrid_slow_start().started());
+ sender_->OnRetransmissionTimeout(true);
+ EXPECT_FALSE(sender_->hybrid_slow_start().started());
+}
+
+TEST_F(TcpCubicSenderBytesTest, SlowStartHalfPacketLossWithLargeReduction) {
+ QuicConfig config;
+ QuicTagVector options;
+ options.push_back(kSSLR);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+
+ sender_->SetNumEmulatedConnections(1);
+ const int kNumberOfAcks = 10;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window in half sized packets.
+ SendAvailableSendWindow(kDefaultTCPMSS / 2);
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow(kDefaultTCPMSS / 2);
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose a packet to exit slow start. We should now have fallen out of
+ // slow start with a window reduced by 1.
+ LoseNPackets(1);
+ expected_send_window -= kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose 10 packets in recovery and verify that congestion window is reduced
+ // by 5 packets.
+ LoseNPackets(10, kDefaultTCPMSS / 2);
+ expected_send_window -= 5 * kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderBytesTest, SlowStartPacketLossWithMaxHalfReduction) {
+ QuicConfig config;
+ QuicTagVector options;
+ options.push_back(kSSLR);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+
+ sender_->SetNumEmulatedConnections(1);
+ const int kNumberOfAcks = kInitialCongestionWindowPackets / 2;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose a packet to exit slow start. We should now have fallen out of
+ // slow start with a window reduced by 1.
+ LoseNPackets(1);
+ expected_send_window -= kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose half the outstanding packets in recovery and verify the congestion
+ // window is only reduced by a max of half.
+ LoseNPackets(kNumberOfAcks * 2);
+ expected_send_window -= (kNumberOfAcks * 2 - 1) * kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ LoseNPackets(5);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderBytesTest, NoPRRWhenLessThanOnePacketInFlight) {
+ SendAvailableSendWindow();
+ LoseNPackets(kInitialCongestionWindowPackets - 1);
+ AckNPackets(1);
+ // PRR will allow 2 packets for every ack during recovery.
+ EXPECT_EQ(2, SendAvailableSendWindow());
+ // Simulate abandoning all packets by supplying a bytes_in_flight of 0.
+ // PRR should now allow a packet to be sent, even though prr's state variables
+ // believe it has sent enough packets.
+ EXPECT_EQ(QuicTime::Delta::Zero(), sender_->TimeUntilSend(clock_.Now(), 0));
+}
+
+TEST_F(TcpCubicSenderBytesTest, SlowStartPacketLossPRR) {
+ sender_->SetNumEmulatedConnections(1);
+ // Test based on the first example in RFC6937.
+ // Ack 10 packets in 5 acks to raise the CWND to 20, as in the example.
+ const int kNumberOfAcks = 5;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ LoseNPackets(1);
+
+ // We should now have fallen out of slow start with a reduced window.
+ size_t send_window_before_loss = expected_send_window;
+ expected_send_window *= kRenoBeta;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Testing TCP proportional rate reduction.
+ // We should send packets paced over the received acks for the remaining
+ // outstanding packets. The number of packets before we exit recovery is the
+ // original CWND minus the packet that has been lost and the one which
+ // triggered the loss.
+ size_t remaining_packets_in_recovery =
+ send_window_before_loss / kDefaultTCPMSS - 2;
+
+ for (size_t i = 0; i < remaining_packets_in_recovery; ++i) {
+ AckNPackets(1);
+ SendAvailableSendWindow();
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ }
+
+ // We need to ack another window before we increase CWND by 1.
+ size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
+ for (size_t i = 0; i < number_of_packets_in_window; ++i) {
+ AckNPackets(1);
+ EXPECT_EQ(1, SendAvailableSendWindow());
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ }
+
+ AckNPackets(1);
+ expected_send_window += kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderBytesTest, SlowStartBurstPacketLossPRR) {
+ sender_->SetNumEmulatedConnections(1);
+ // Test based on the second example in RFC6937, though we also implement
+ // forward acknowledgements, so the first two incoming acks will trigger
+ // PRR immediately.
+ // Ack 20 packets in 10 acks to raise the CWND to 30.
+ const int kNumberOfAcks = 10;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose one more than the congestion window reduction, so that after loss,
+ // bytes_in_flight is lesser than the congestion window.
+ size_t send_window_after_loss = kRenoBeta * expected_send_window;
+ size_t num_packets_to_lose =
+ (expected_send_window - send_window_after_loss) / kDefaultTCPMSS + 1;
+ LoseNPackets(num_packets_to_lose);
+ // Immediately after the loss, ensure at least one packet can be sent.
+ // Losses without subsequent acks can occur with timer based loss detection.
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_).IsZero());
+ AckNPackets(1);
+
+ // We should now have fallen out of slow start with a reduced window.
+ expected_send_window *= kRenoBeta;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Only 2 packets should be allowed to be sent, per PRR-SSRB.
+ EXPECT_EQ(2, SendAvailableSendWindow());
+
+ // Ack the next packet, which triggers another loss.
+ LoseNPackets(1);
+ AckNPackets(1);
+
+ // Send 2 packets to simulate PRR-SSRB.
+ EXPECT_EQ(2, SendAvailableSendWindow());
+
+ // Ack the next packet, which triggers another loss.
+ LoseNPackets(1);
+ AckNPackets(1);
+
+ // Send 2 packets to simulate PRR-SSRB.
+ EXPECT_EQ(2, SendAvailableSendWindow());
+
+ // Exit recovery and return to sending at the new rate.
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ AckNPackets(1);
+ EXPECT_EQ(1, SendAvailableSendWindow());
+ }
+}
+
+TEST_F(TcpCubicSenderBytesTest, RTOCongestionWindow) {
+ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+ // Expect the window to decrease to the minimum once the RTO fires and slow
+ // start threshold to be set to 1/2 of the CWND.
+ sender_->OnRetransmissionTimeout(true);
+ EXPECT_EQ(2 * kDefaultTCPMSS, sender_->GetCongestionWindow());
+ EXPECT_EQ(5u * kDefaultTCPMSS, sender_->GetSlowStartThreshold());
+}
+
+TEST_F(TcpCubicSenderBytesTest, RTOCongestionWindowNoRetransmission) {
+ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+
+ // Expect the window to remain unchanged if the RTO fires but no packets are
+ // retransmitted.
+ sender_->OnRetransmissionTimeout(false);
+ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderBytesTest, TcpCubicResetEpochOnQuiescence) {
+ const int kMaxCongestionWindow = 50;
+ const QuicByteCount kMaxCongestionWindowBytes =
+ kMaxCongestionWindow * kDefaultTCPMSS;
+ int num_sent = SendAvailableSendWindow();
+
+ // Make sure we fall out of slow start.
+ QuicByteCount saved_cwnd = sender_->GetCongestionWindow();
+ LoseNPackets(1);
+ EXPECT_GT(saved_cwnd, sender_->GetCongestionWindow());
+
+ // Ack the rest of the outstanding packets to get out of recovery.
+ for (int i = 1; i < num_sent; ++i) {
+ AckNPackets(1);
+ }
+ EXPECT_EQ(0u, bytes_in_flight_);
+
+ // Send a new window of data and ack all; cubic growth should occur.
+ saved_cwnd = sender_->GetCongestionWindow();
+ num_sent = SendAvailableSendWindow();
+ for (int i = 0; i < num_sent; ++i) {
+ AckNPackets(1);
+ }
+ EXPECT_LT(saved_cwnd, sender_->GetCongestionWindow());
+ EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow());
+ EXPECT_EQ(0u, bytes_in_flight_);
+
+ // Quiescent time of 100 seconds
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100000));
+
+ // Send new window of data and ack one packet. Cubic epoch should have
+ // been reset; ensure cwnd increase is not dramatic.
+ saved_cwnd = sender_->GetCongestionWindow();
+ SendAvailableSendWindow();
+ AckNPackets(1);
+ EXPECT_NEAR(saved_cwnd, sender_->GetCongestionWindow(), kDefaultTCPMSS);
+ EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderBytesTest, MultipleLossesInOneWindow) {
+ SendAvailableSendWindow();
+ const QuicByteCount initial_window = sender_->GetCongestionWindow();
+ LosePacket(acked_packet_number_ + 1);
+ const QuicByteCount post_loss_window = sender_->GetCongestionWindow();
+ EXPECT_GT(initial_window, post_loss_window);
+ LosePacket(acked_packet_number_ + 3);
+ EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow());
+ LosePacket(packet_number_ - 1);
+ EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow());
+
+ // Lose a later packet and ensure the window decreases.
+ LosePacket(packet_number_);
+ EXPECT_GT(post_loss_window, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderBytesTest, DontTrackAckPackets) {
+ // Send a packet with no retransmittable data, and ensure it's not tracked.
+ EXPECT_FALSE(sender_->OnPacketSent(clock_.Now(), bytes_in_flight_,
+ packet_number_++, kDefaultTCPMSS,
+ NO_RETRANSMITTABLE_DATA));
+
+ // Send a data packet with retransmittable data, and ensure it is tracked.
+ EXPECT_TRUE(sender_->OnPacketSent(clock_.Now(), bytes_in_flight_,
+ packet_number_++, kDefaultTCPMSS,
+ HAS_RETRANSMITTABLE_DATA));
+}
+
+TEST_F(TcpCubicSenderBytesTest, ConfigureMaxInitialWindow) {
+ QuicConfig config;
+
+ // Verify that kCOPT: kIW10 forces the congestion window to the default of 10.
+ QuicTagVector options;
+ options.push_back(kIW10);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ EXPECT_EQ(10u * kDefaultTCPMSS, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderBytesTest, 2ConnectionCongestionAvoidanceAtEndOfRecovery) {
+ sender_->SetNumEmulatedConnections(2);
+ // Ack 10 packets in 5 acks to raise the CWND to 20.
+ const int kNumberOfAcks = 5;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ LoseNPackets(1);
+
+ // We should now have fallen out of slow start with a reduced window.
+ expected_send_window = expected_send_window * sender_->GetRenoBeta();
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // No congestion window growth should occur in recovery phase, i.e., until the
+ // currently outstanding 20 packets are acked.
+ for (int i = 0; i < 10; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ EXPECT_TRUE(sender_->InRecovery());
+ AckNPackets(2);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ }
+ EXPECT_FALSE(sender_->InRecovery());
+
+ // Out of recovery now. Congestion window should not grow for half an RTT.
+ size_t packets_in_send_window = expected_send_window / kDefaultTCPMSS;
+ SendAvailableSendWindow();
+ AckNPackets(packets_in_send_window / 2 - 2);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Next ack should increase congestion window by 1MSS.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ expected_send_window += kDefaultTCPMSS;
+ packets_in_send_window += 1;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Congestion window should remain steady again for half an RTT.
+ SendAvailableSendWindow();
+ AckNPackets(packets_in_send_window / 2 - 1);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Next ack should cause congestion window to grow by 1MSS.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ expected_send_window += kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderBytesTest, 1ConnectionCongestionAvoidanceAtEndOfRecovery) {
+ sender_->SetNumEmulatedConnections(1);
+ // Ack 10 packets in 5 acks to raise the CWND to 20.
+ const int kNumberOfAcks = 5;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ LoseNPackets(1);
+
+ // We should now have fallen out of slow start with a reduced window.
+ expected_send_window *= kRenoBeta;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // No congestion window growth should occur in recovery phase, i.e., until the
+ // currently outstanding 20 packets are acked.
+ for (int i = 0; i < 10; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ EXPECT_TRUE(sender_->InRecovery());
+ AckNPackets(2);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ }
+ EXPECT_FALSE(sender_->InRecovery());
+
+ // Out of recovery now. Congestion window should not grow during RTT.
+ for (uint64_t i = 0; i < expected_send_window / kDefaultTCPMSS - 2; i += 2) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ }
+
+ // Next ack should cause congestion window to grow by 1MSS.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ expected_send_window += kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderBytesTest, BandwidthResumption) {
+ // Test that when provided with CachedNetworkParameters and opted in to the
+ // bandwidth resumption experiment, that the TcpCubicSender sets initial CWND
+ // appropriately.
+
+ // Set some common values.
+ CachedNetworkParameters cached_network_params;
+ const QuicPacketCount kNumberOfPackets = 123;
+ const int kBandwidthEstimateBytesPerSecond =
+ kNumberOfPackets * kDefaultTCPMSS;
+ cached_network_params.set_bandwidth_estimate_bytes_per_second(
+ kBandwidthEstimateBytesPerSecond);
+ cached_network_params.set_min_rtt_ms(1000);
+
+ // Make sure that a bandwidth estimate results in a changed CWND.
+ cached_network_params.set_timestamp(clock_.WallNow().ToUNIXSeconds() -
+ (kNumSecondsPerHour - 1));
+ sender_->ResumeConnectionState(cached_network_params, false);
+ EXPECT_EQ(kNumberOfPackets * kDefaultTCPMSS, sender_->GetCongestionWindow());
+
+ // Resumed CWND is limited to be in a sensible range.
+ cached_network_params.set_bandwidth_estimate_bytes_per_second(
+ (kMaxCongestionWindowPackets + 1) * kDefaultTCPMSS);
+ sender_->ResumeConnectionState(cached_network_params, false);
+ EXPECT_EQ(kMaxCongestionWindowPackets * kDefaultTCPMSS,
+ sender_->GetCongestionWindow());
+
+ if (FLAGS_quic_no_lower_bw_resumption_limit) {
+ // Resume with an illegal value of 0 and verify the server uses 1 instead.
+ cached_network_params.set_bandwidth_estimate_bytes_per_second(0);
+ sender_->ResumeConnectionState(cached_network_params, false);
+ EXPECT_EQ(sender_->min_congestion_window(), sender_->GetCongestionWindow());
+ } else {
+ cached_network_params.set_bandwidth_estimate_bytes_per_second(
+ (kMinCongestionWindowForBandwidthResumption - 1) * kDefaultTCPMSS);
+ sender_->ResumeConnectionState(cached_network_params, false);
+ EXPECT_EQ(kMinCongestionWindowForBandwidthResumption * kDefaultTCPMSS,
+ sender_->GetCongestionWindow());
+ }
+
+ // Resume to the max value.
+ cached_network_params.set_max_bandwidth_estimate_bytes_per_second(
+ kMaxCongestionWindowPackets * kDefaultTCPMSS);
+ sender_->ResumeConnectionState(cached_network_params, true);
+ EXPECT_EQ(kMaxCongestionWindowPackets * kDefaultTCPMSS,
+ sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderBytesTest, PaceBelowCWND) {
+ QuicConfig config;
+
+ // Verify that kCOPT: kMIN4 forces the min CWND to 1 packet, but allows up
+ // to 4 to be sent.
+ QuicTagVector options;
+ options.push_back(kMIN4);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ sender_->OnRetransmissionTimeout(true);
+ EXPECT_EQ(kDefaultTCPMSS, sender_->GetCongestionWindow());
+ EXPECT_TRUE(
+ sender_->TimeUntilSend(QuicTime::Zero(), kDefaultTCPMSS).IsZero());
+ EXPECT_TRUE(
+ sender_->TimeUntilSend(QuicTime::Zero(), 2 * kDefaultTCPMSS).IsZero());
+ EXPECT_TRUE(
+ sender_->TimeUntilSend(QuicTime::Zero(), 3 * kDefaultTCPMSS).IsZero());
+ EXPECT_FALSE(
+ sender_->TimeUntilSend(QuicTime::Zero(), 4 * kDefaultTCPMSS).IsZero());
+}
+
+TEST_F(TcpCubicSenderBytesTest, NoPRR) {
+ QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(100);
+ sender_->rtt_stats_.UpdateRtt(rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
+
+ sender_->SetNumEmulatedConnections(1);
+ // Verify that kCOPT: kNPRR allows all packets to be sent, even if only one
+ // ack has been received.
+ QuicTagVector options;
+ options.push_back(kNPRR);
+ QuicConfig config;
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ SendAvailableSendWindow();
+ LoseNPackets(9);
+ AckNPackets(1);
+
+ // We should now have fallen out of slow start with a reduced window.
+ EXPECT_EQ(kRenoBeta * kDefaultWindowTCP, sender_->GetCongestionWindow());
+ const QuicPacketCount window_in_packets =
+ kRenoBeta * kDefaultWindowTCP / kDefaultTCPMSS;
+ const QuicBandwidth expected_pacing_rate =
+ QuicBandwidth::FromBytesAndTimeDelta(kRenoBeta * kDefaultWindowTCP,
+ sender_->rtt_stats_.smoothed_rtt());
+ EXPECT_EQ(expected_pacing_rate, sender_->PacingRate(0));
+ EXPECT_EQ(window_in_packets,
+ static_cast<uint64_t>(SendAvailableSendWindow()));
+ EXPECT_EQ(expected_pacing_rate,
+ sender_->PacingRate(kRenoBeta * kDefaultWindowTCP));
+}
+
+TEST_F(TcpCubicSenderBytesTest, PaceSlowerAboveCwnd) {
+ QuicTime::Delta rtt(QuicTime::Delta::FromMilliseconds(60));
+ sender_->rtt_stats_.UpdateRtt(rtt, QuicTime::Delta::Zero(), clock_.Now());
+
+ QuicConfig config;
+ QuicTagVector options;
+ options.push_back(kRATE);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ EXPECT_EQ(10 * kDefaultTCPMSS, sender_->GetCongestionWindow());
+ sender_->SetNumEmulatedConnections(1);
+ // Lose a packet to exit slow start.
+ LoseNPackets(1);
+ const QuicPacketCount cwnd = 7;
+ EXPECT_EQ(cwnd * kDefaultTCPMSS, sender_->GetCongestionWindow());
+
+ EXPECT_TRUE(
+ sender_->TimeUntilSend(QuicTime::Zero(), kDefaultTCPMSS).IsZero());
+ EXPECT_EQ(
+ sender_->PacingRate(kDefaultTCPMSS),
+ QuicBandwidth::FromBytesAndTimeDelta(7 * kDefaultTCPMSS, rtt) * 1.25);
+ for (QuicPacketCount i = cwnd + 1; i < 1.5 * cwnd; ++i) {
+ EXPECT_TRUE(
+ sender_->TimeUntilSend(QuicTime::Zero(), i * kDefaultTCPMSS).IsZero());
+ EXPECT_EQ(sender_->PacingRate(i * kDefaultTCPMSS),
+ QuicBandwidth::FromBytesAndTimeDelta(cwnd * kDefaultTCPMSS, rtt) *
+ 0.75);
+ }
+ EXPECT_FALSE(
+ sender_->TimeUntilSend(QuicTime::Zero(), 11 * kDefaultTCPMSS).IsZero());
+}
+
+TEST_F(TcpCubicSenderBytesTest, ResetAfterConnectionMigration) {
+ // Starts from slow start.
+ sender_->SetNumEmulatedConnections(1);
+ const int kNumberOfAcks = 10;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Loses a packet to exit slow start.
+ LoseNPackets(1);
+
+ // We should now have fallen out of slow start with a reduced window. Slow
+ // start threshold is also updated.
+ expected_send_window *= kRenoBeta;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ EXPECT_EQ(expected_send_window, sender_->GetSlowStartThreshold());
+
+ // Resets cwnd and slow start threshold on connection migrations.
+ sender_->OnConnectionMigration();
+ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+ EXPECT_EQ(kMaxCongestionWindowPackets * kDefaultTCPMSS,
+ sender_->GetSlowStartThreshold());
+ EXPECT_FALSE(sender_->hybrid_slow_start().started());
+}
+
+TEST_F(TcpCubicSenderBytesTest, DefaultMaxCwnd) {
+ RttStats rtt_stats;
+ QuicConnectionStats stats;
+ std::unique_ptr<SendAlgorithmInterface> sender(SendAlgorithmInterface::Create(
+ &clock_, &rtt_stats, kCubicBytes, &stats, kInitialCongestionWindow));
+
+ SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::CongestionVector missing_packets;
+ for (uint64_t i = 1; i < kDefaultMaxCongestionWindowPackets; ++i) {
+ acked_packets.clear();
+ acked_packets.push_back(std::make_pair(i, 1350));
+ sender->OnCongestionEvent(true, sender->GetCongestionWindow(),
+ acked_packets, missing_packets);
+ }
+ EXPECT_EQ(kDefaultMaxCongestionWindowPackets,
+ sender->GetCongestionWindow() / kDefaultTCPMSS);
+}
+
+TEST_F(TcpCubicSenderBytesTest, LimitCwndIncreaseInCongestionAvoidance) {
+ FLAGS_quic_limit_cubic_cwnd_increase = true;
+ // Enable Cubic.
+ sender_.reset(new TcpCubicSenderBytesPeer(&clock_, false));
+
+ int num_sent = SendAvailableSendWindow();
+
+ // Make sure we fall out of slow start.
+ QuicByteCount saved_cwnd = sender_->GetCongestionWindow();
+ LoseNPackets(1);
+ EXPECT_GT(saved_cwnd, sender_->GetCongestionWindow());
+
+ // Ack the rest of the outstanding packets to get out of recovery.
+ for (int i = 1; i < num_sent; ++i) {
+ AckNPackets(1);
+ }
+ EXPECT_EQ(0u, bytes_in_flight_);
+ // Send a new window of data and ack all; cubic growth should occur.
+ saved_cwnd = sender_->GetCongestionWindow();
+ num_sent = SendAvailableSendWindow();
+
+ // Ack packets until the CWND increases.
+ while (sender_->GetCongestionWindow() == saved_cwnd) {
+ AckNPackets(1);
+ SendAvailableSendWindow();
+ }
+ EXPECT_EQ(bytes_in_flight_, sender_->GetCongestionWindow());
+ saved_cwnd = sender_->GetCongestionWindow();
+
+ // Advance time 2 seconds waiting for an ack.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2000));
+
+ // Ack two packets. The CWND should increase by only one packet.
+ AckNPackets(2);
+ EXPECT_EQ(saved_cwnd + kDefaultTCPMSS, sender_->GetCongestionWindow());
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets.cc b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets.cc
new file mode 100644
index 00000000000..c89895a98de
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets.cc
@@ -0,0 +1,218 @@
+// 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_packets.h"
+
+#include <algorithm>
+
+#include "base/metrics/histogram_macros.h"
+#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/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+
+using std::max;
+using std::min;
+
+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 QuicPacketCount kDefaultMinimumCongestionWindow = 2;
+} // namespace
+
+TcpCubicSenderPackets::TcpCubicSenderPackets(
+ const QuicClock* clock,
+ const RttStats* rtt_stats,
+ bool reno,
+ QuicPacketCount initial_tcp_congestion_window,
+ QuicPacketCount max_tcp_congestion_window,
+ QuicConnectionStats* stats)
+ : TcpCubicSenderBase(clock, rtt_stats, reno, stats),
+ cubic_(clock),
+ congestion_window_count_(0),
+ congestion_window_(initial_tcp_congestion_window),
+ min_congestion_window_(kDefaultMinimumCongestionWindow),
+ slowstart_threshold_(max_tcp_congestion_window),
+ max_tcp_congestion_window_(max_tcp_congestion_window),
+ initial_tcp_congestion_window_(initial_tcp_congestion_window),
+ initial_max_tcp_congestion_window_(max_tcp_congestion_window),
+ min_slow_start_exit_window_(min_congestion_window_) {}
+
+TcpCubicSenderPackets::~TcpCubicSenderPackets() {}
+
+void TcpCubicSenderPackets::SetCongestionWindowFromBandwidthAndRtt(
+ QuicBandwidth bandwidth,
+ QuicTime::Delta rtt) {
+ QuicPacketCount new_congestion_window =
+ bandwidth.ToBytesPerPeriod(rtt) / kDefaultTCPMSS;
+ if (FLAGS_quic_no_lower_bw_resumption_limit) {
+ // Limit new CWND to be in the range [1, kMaxCongestionWindow].
+ congestion_window_ =
+ max(min_congestion_window_,
+ min(new_congestion_window, kMaxResumptionCongestionWindow));
+ } else {
+ congestion_window_ =
+ max(min(new_congestion_window, kMaxResumptionCongestionWindow),
+ kMinCongestionWindowForBandwidthResumption);
+ }
+}
+
+void TcpCubicSenderPackets::SetCongestionWindowInPackets(
+ QuicPacketCount congestion_window) {
+ congestion_window_ = congestion_window;
+}
+
+void TcpCubicSenderPackets::SetMinCongestionWindowInPackets(
+ QuicPacketCount congestion_window) {
+ min_congestion_window_ = congestion_window;
+}
+
+void TcpCubicSenderPackets::SetNumEmulatedConnections(int num_connections) {
+ TcpCubicSenderBase::SetNumEmulatedConnections(num_connections);
+ cubic_.SetNumConnections(num_connections_);
+}
+
+void TcpCubicSenderPackets::ExitSlowstart() {
+ slowstart_threshold_ = congestion_window_;
+}
+
+void TcpCubicSenderPackets::OnPacketLost(QuicPacketNumber packet_number,
+ QuicByteCount lost_bytes,
+ QuicByteCount bytes_in_flight) {
+ // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets
+ // already sent should be treated as a single loss event, since it's expected.
+ if (packet_number <= largest_sent_at_last_cutback_) {
+ if (last_cutback_exited_slowstart_) {
+ ++stats_->slowstart_packets_lost;
+ stats_->slowstart_bytes_lost += lost_bytes;
+ if (slow_start_large_reduction_) {
+ if (stats_->slowstart_packets_lost == 1 ||
+ (stats_->slowstart_bytes_lost / kDefaultTCPMSS) >
+ (stats_->slowstart_bytes_lost - lost_bytes) / kDefaultTCPMSS) {
+ // Reduce congestion window by 1 for every mss of bytes lost.
+ congestion_window_ =
+ max(congestion_window_ - 1, min_slow_start_exit_window_);
+ }
+ slowstart_threshold_ = congestion_window_;
+ }
+ }
+ DVLOG(1) << "Ignoring loss for largest_missing:" << packet_number
+ << " because it was sent prior to the last CWND cutback.";
+ return;
+ }
+ ++stats_->tcp_loss_events;
+ last_cutback_exited_slowstart_ = InSlowStart();
+ if (InSlowStart()) {
+ ++stats_->slowstart_packets_lost;
+ }
+
+ if (!no_prr_) {
+ prr_.OnPacketLost(bytes_in_flight);
+ }
+
+ // TODO(jri): Separate out all of slow start into a separate class.
+ if (slow_start_large_reduction_ && InSlowStart()) {
+ DCHECK_LT(1u, congestion_window_);
+ if (congestion_window_ >= 2 * initial_tcp_congestion_window_) {
+ min_slow_start_exit_window_ = congestion_window_ / 2;
+ }
+ congestion_window_ = congestion_window_ - 1;
+ } else if (reno_) {
+ congestion_window_ = congestion_window_ * RenoBeta();
+ } else {
+ congestion_window_ =
+ cubic_.CongestionWindowAfterPacketLoss(congestion_window_);
+ }
+ // Enforce a minimum congestion window.
+ if (congestion_window_ < min_congestion_window_) {
+ congestion_window_ = min_congestion_window_;
+ }
+ slowstart_threshold_ = congestion_window_;
+ largest_sent_at_last_cutback_ = largest_sent_packet_number_;
+ // reset packet count from congestion avoidance mode. We start
+ // counting again when we're out of recovery.
+ congestion_window_count_ = 0;
+ DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_
+ << " slowstart threshold: " << slowstart_threshold_;
+}
+
+QuicByteCount TcpCubicSenderPackets::GetCongestionWindow() const {
+ return congestion_window_ * kDefaultTCPMSS;
+}
+
+QuicByteCount TcpCubicSenderPackets::GetSlowStartThreshold() const {
+ return slowstart_threshold_ * kDefaultTCPMSS;
+}
+
+// Called when we receive an ack. Normal TCP tracks how many packets one ack
+// represents, but quic has a separate ack for each packet.
+void TcpCubicSenderPackets::MaybeIncreaseCwnd(
+ QuicPacketNumber acked_packet_number,
+ QuicByteCount /*acked_bytes*/,
+ QuicByteCount bytes_in_flight) {
+ QUIC_BUG_IF(InRecovery()) << "Never increase the CWND during recovery.";
+ // Do not increase the congestion window unless the sender is close to using
+ // the current window.
+ if (!IsCwndLimited(bytes_in_flight)) {
+ cubic_.OnApplicationLimited();
+ return;
+ }
+ if (congestion_window_ >= max_tcp_congestion_window_) {
+ return;
+ }
+ if (InSlowStart()) {
+ // TCP slow start, exponential growth, increase by one for each ACK.
+ ++congestion_window_;
+ DVLOG(1) << "Slow start; congestion window: " << congestion_window_
+ << " slowstart threshold: " << slowstart_threshold_;
+ return;
+ }
+ // Congestion avoidance
+ if (reno_) {
+ // Classic Reno congestion avoidance.
+ ++congestion_window_count_;
+ // Divide by num_connections to smoothly increase the CWND at a faster
+ // rate than conventional Reno.
+ if (congestion_window_count_ * num_connections_ >= congestion_window_) {
+ ++congestion_window_;
+ congestion_window_count_ = 0;
+ }
+
+ DVLOG(1) << "Reno; congestion window: " << congestion_window_
+ << " slowstart threshold: " << slowstart_threshold_
+ << " congestion window count: " << congestion_window_count_;
+ } else {
+ congestion_window_ = min(max_tcp_congestion_window_,
+ cubic_.CongestionWindowAfterAck(
+ congestion_window_, rtt_stats_->min_rtt()));
+ DVLOG(1) << "Cubic; congestion window: " << congestion_window_
+ << " slowstart threshold: " << slowstart_threshold_;
+ }
+}
+
+void TcpCubicSenderPackets::HandleRetransmissionTimeout() {
+ cubic_.Reset();
+ slowstart_threshold_ = congestion_window_ / 2;
+ congestion_window_ = min_congestion_window_;
+}
+
+void TcpCubicSenderPackets::OnConnectionMigration() {
+ TcpCubicSenderBase::OnConnectionMigration();
+ cubic_.Reset();
+ congestion_window_count_ = 0;
+ congestion_window_ = initial_tcp_congestion_window_;
+ slowstart_threshold_ = initial_max_tcp_congestion_window_;
+ max_tcp_congestion_window_ = initial_max_tcp_congestion_window_;
+}
+
+CongestionControlType TcpCubicSenderPackets::GetCongestionControlType() const {
+ return reno_ ? kReno : kCubic;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets.h b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets.h
new file mode 100644
index 00000000000..76e3ad62ef4
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets.h
@@ -0,0 +1,105 @@
+// 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_CONGESTION_CONTROL_TCP_CUBIC_SENDER_PACKETS_H_
+#define NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_SENDER_PACKETS_H_
+
+#include <stdint.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/congestion_control/cubic.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/quic_bandwidth.h"
+#include "net/quic/core/quic_connection_stats.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+class RttStats;
+
+namespace test {
+class TcpCubicSenderPacketsPeer;
+} // namespace test
+
+class NET_EXPORT_PRIVATE TcpCubicSenderPackets : public TcpCubicSenderBase {
+ public:
+ // Reno option and max_tcp_congestion_window are provided for testing.
+ TcpCubicSenderPackets(const QuicClock* clock,
+ const RttStats* rtt_stats,
+ bool reno,
+ QuicPacketCount initial_tcp_congestion_window,
+ QuicPacketCount max_tcp_congestion_window,
+ QuicConnectionStats* stats);
+ ~TcpCubicSenderPackets() override;
+
+ // Start implementation of SendAlgorithmInterface.
+ void SetNumEmulatedConnections(int num_connections) override;
+ void OnConnectionMigration() override;
+ QuicByteCount GetCongestionWindow() const override;
+ QuicByteCount GetSlowStartThreshold() const override;
+ CongestionControlType GetCongestionControlType() const override;
+ // End implementation of SendAlgorithmInterface.
+
+ QuicByteCount min_congestion_window() const { return min_congestion_window_; }
+
+ protected:
+ // TcpCubicSenderBase methods
+ void SetCongestionWindowFromBandwidthAndRtt(QuicBandwidth bandwidth,
+ QuicTime::Delta rtt) override;
+ void SetCongestionWindowInPackets(QuicPacketCount congestion_window) override;
+ void SetMinCongestionWindowInPackets(
+ QuicPacketCount congestion_window) override;
+ void ExitSlowstart() override;
+ void OnPacketLost(QuicPacketNumber largest_loss,
+ QuicByteCount lost_bytes,
+ QuicByteCount bytes_in_flight) override;
+ void MaybeIncreaseCwnd(QuicPacketNumber acked_packet_number,
+ QuicByteCount acked_bytes,
+ QuicByteCount bytes_in_flight) override;
+ void HandleRetransmissionTimeout() override;
+
+ private:
+ friend class test::TcpCubicSenderPacketsPeer;
+
+ Cubic cubic_;
+
+ // ACK counter for the Reno implementation.
+ uint64_t congestion_window_count_;
+
+ // Congestion window in packets.
+ QuicPacketCount congestion_window_;
+
+ // Minimum congestion window in packets.
+ QuicPacketCount min_congestion_window_;
+
+ // Slow start congestion window in packets, aka ssthresh.
+ QuicPacketCount slowstart_threshold_;
+
+ // Maximum number of outstanding packets for tcp.
+ QuicPacketCount max_tcp_congestion_window_;
+
+ // Initial TCP congestion window. This variable can only be set when this
+ // algorithm is created.
+ const QuicPacketCount initial_tcp_congestion_window_;
+
+ // Initial maximum TCP congestion window. This variable can only be set when
+ // this algorithm is created.
+ const QuicPacketCount initial_max_tcp_congestion_window_;
+
+ // The minimum window when exiting slow start with large reduction.
+ QuicPacketCount min_slow_start_exit_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(TcpCubicSenderPackets);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_SENDER_H_
diff --git a/chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets_test.cc b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets_test.cc
new file mode 100644
index 00000000000..61b7192c864
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/tcp_cubic_sender_packets_test.cc
@@ -0,0 +1,1005 @@
+// 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_packets.h"
+
+#include <algorithm>
+#include <memory>
+
+#include "base/logging.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/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/quic_config_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::min;
+
+namespace net {
+namespace test {
+
+// TODO(ianswett): A number of theses tests were written with the assumption of
+// an initial CWND of 10. They have carefully calculated values which should be
+// updated to be based on kInitialCongestionWindow.
+const uint32_t kInitialCongestionWindowPackets = 10;
+const uint32_t kMaxCongestionWindowPackets = 200;
+const uint32_t kDefaultWindowTCP =
+ kInitialCongestionWindowPackets * kDefaultTCPMSS;
+const float kRenoBeta = 0.7f; // Reno backoff factor.
+
+class TcpCubicSenderPacketsPeer : public TcpCubicSenderPackets {
+ public:
+ TcpCubicSenderPacketsPeer(const QuicClock* clock,
+ bool reno,
+ QuicPacketCount max_tcp_congestion_window)
+ : TcpCubicSenderPackets(clock,
+ &rtt_stats_,
+ reno,
+ kInitialCongestionWindowPackets,
+ max_tcp_congestion_window,
+ &stats_) {}
+
+ QuicPacketCount congestion_window() { return congestion_window_; }
+
+ QuicPacketCount max_congestion_window() { return max_tcp_congestion_window_; }
+
+ QuicPacketCount slowstart_threshold() { return slowstart_threshold_; }
+
+ const HybridSlowStart& hybrid_slow_start() const {
+ return hybrid_slow_start_;
+ }
+
+ float GetRenoBeta() const { return RenoBeta(); }
+
+ RttStats rtt_stats_;
+ QuicConnectionStats stats_;
+};
+
+class TcpCubicSenderPacketsTest : public ::testing::Test {
+ protected:
+ TcpCubicSenderPacketsTest()
+ : one_ms_(QuicTime::Delta::FromMilliseconds(1)),
+ sender_(new TcpCubicSenderPacketsPeer(&clock_,
+ true,
+ kMaxCongestionWindowPackets)),
+ packet_number_(1),
+ acked_packet_number_(0),
+ bytes_in_flight_(0) {}
+
+ int SendAvailableSendWindow() {
+ return SendAvailableSendWindow(kDefaultTCPMSS);
+ }
+
+ int SendAvailableSendWindow(QuicPacketLength packet_length) {
+ // Send as long as TimeUntilSend returns Zero.
+ int packets_sent = 0;
+ bool can_send =
+ sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_).IsZero();
+ while (can_send) {
+ sender_->OnPacketSent(clock_.Now(), bytes_in_flight_, packet_number_++,
+ kDefaultTCPMSS, HAS_RETRANSMITTABLE_DATA);
+ ++packets_sent;
+ bytes_in_flight_ += kDefaultTCPMSS;
+ can_send =
+ sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_).IsZero();
+ }
+ return packets_sent;
+ }
+
+ // Normal is that TCP acks every other segment.
+ void AckNPackets(int n) {
+ sender_->rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(60),
+ QuicTime::Delta::Zero(), clock_.Now());
+ SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ for (int i = 0; i < n; ++i) {
+ ++acked_packet_number_;
+ acked_packets.push_back(
+ std::make_pair(acked_packet_number_, kDefaultTCPMSS));
+ }
+ sender_->OnCongestionEvent(true, bytes_in_flight_, acked_packets,
+ lost_packets);
+ bytes_in_flight_ -= n * kDefaultTCPMSS;
+ clock_.AdvanceTime(one_ms_);
+ }
+
+ void LoseNPackets(int n) { LoseNPackets(n, kDefaultTCPMSS); }
+
+ void LoseNPackets(int n, QuicPacketLength packet_length) {
+ SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ for (int i = 0; i < n; ++i) {
+ ++acked_packet_number_;
+ lost_packets.push_back(
+ std::make_pair(acked_packet_number_, packet_length));
+ }
+ sender_->OnCongestionEvent(false, bytes_in_flight_, acked_packets,
+ lost_packets);
+ bytes_in_flight_ -= n * packet_length;
+ }
+
+ // Does not increment acked_packet_number_.
+ void LosePacket(QuicPacketNumber packet_number) {
+ SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ lost_packets.push_back(std::make_pair(packet_number, kDefaultTCPMSS));
+ sender_->OnCongestionEvent(false, bytes_in_flight_, acked_packets,
+ lost_packets);
+ bytes_in_flight_ -= kDefaultTCPMSS;
+ }
+
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+ const QuicTime::Delta one_ms_;
+ MockClock clock_;
+ std::unique_ptr<TcpCubicSenderPacketsPeer> sender_;
+ QuicPacketNumber packet_number_;
+ QuicPacketNumber acked_packet_number_;
+ QuicByteCount bytes_in_flight_;
+};
+
+TEST_F(TcpCubicSenderPacketsTest, SimpleSender) {
+ // At startup make sure we are at the default.
+ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+ // At startup make sure we can send.
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
+ // Make sure we can send.
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
+ // And that window is un-affected.
+ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+
+ // Fill the send window with data, then verify that we can't send.
+ SendAvailableSendWindow();
+ EXPECT_FALSE(
+ sender_->TimeUntilSend(clock_.Now(), sender_->GetCongestionWindow())
+ .IsZero());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, ApplicationLimitedSlowStart) {
+ // Send exactly 10 packets and ensure the CWND ends at 14 packets.
+ const int kNumberOfAcks = 5;
+ // At startup make sure we can send.
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
+ // Make sure we can send.
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
+
+ SendAvailableSendWindow();
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ AckNPackets(2);
+ }
+ QuicByteCount bytes_to_send = sender_->GetCongestionWindow();
+ // It's expected 2 acks will arrive when the bytes_in_flight are greater than
+ // half the CWND.
+ EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * 2, bytes_to_send);
+}
+
+TEST_F(TcpCubicSenderPacketsTest, ExponentialSlowStart) {
+ const int kNumberOfAcks = 20;
+ // At startup make sure we can send.
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
+ EXPECT_EQ(QuicBandwidth::Zero(), sender_->BandwidthEstimate());
+ // Make sure we can send.
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0).IsZero());
+
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ const QuicByteCount cwnd = sender_->GetCongestionWindow();
+ EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * kNumberOfAcks, cwnd);
+ EXPECT_EQ(QuicBandwidth::FromBytesAndTimeDelta(
+ cwnd, sender_->rtt_stats_.smoothed_rtt()),
+ sender_->BandwidthEstimate());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, SlowStartPacketLoss) {
+ sender_->SetNumEmulatedConnections(1);
+ const int kNumberOfAcks = 10;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose a packet to exit slow start.
+ LoseNPackets(1);
+ size_t packets_in_recovery_window = expected_send_window / kDefaultTCPMSS;
+
+ // We should now have fallen out of slow start with a reduced window.
+ expected_send_window *= kRenoBeta;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Recovery phase. We need to ack every packet in the recovery window before
+ // we exit recovery.
+ size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
+ DVLOG(1) << "number_packets: " << number_of_packets_in_window;
+ AckNPackets(packets_in_recovery_window);
+ SendAvailableSendWindow();
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // We need to ack an entire window before we increase CWND by 1.
+ AckNPackets(number_of_packets_in_window - 2);
+ SendAvailableSendWindow();
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Next ack should increase cwnd by 1.
+ AckNPackets(1);
+ expected_send_window += kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Now RTO and ensure slow start gets reset.
+ EXPECT_TRUE(sender_->hybrid_slow_start().started());
+ sender_->OnRetransmissionTimeout(true);
+ EXPECT_FALSE(sender_->hybrid_slow_start().started());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, SlowStartPacketLossWithLargeReduction) {
+ QuicConfig config;
+ QuicTagVector options;
+ options.push_back(kSSLR);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+
+ sender_->SetNumEmulatedConnections(1);
+ const int kNumberOfAcks = (kDefaultWindowTCP / (2 * kDefaultTCPMSS)) - 1;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose a packet to exit slow start. We should now have fallen out of
+ // slow start with a window reduced by 1.
+ LoseNPackets(1);
+ expected_send_window -= kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose 5 packets in recovery and verify that congestion window is reduced
+ // further.
+ LoseNPackets(5);
+ expected_send_window -= 5 * kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ // Lose another 10 packets and ensure it reduces below half the peak CWND,
+ // because we never acked the full IW.
+ LoseNPackets(10);
+ expected_send_window -= 10 * kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ size_t packets_in_recovery_window = expected_send_window / kDefaultTCPMSS;
+
+ // Recovery phase. We need to ack every packet in the recovery window before
+ // we exit recovery.
+ size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
+ DVLOG(1) << "number_packets: " << number_of_packets_in_window;
+ AckNPackets(packets_in_recovery_window);
+ SendAvailableSendWindow();
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // We need to ack the rest of the window before cwnd increases by 1.
+ AckNPackets(number_of_packets_in_window - 1);
+ SendAvailableSendWindow();
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Next ack should increase cwnd by 1.
+ AckNPackets(1);
+ expected_send_window += kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Now RTO and ensure slow start gets reset.
+ EXPECT_TRUE(sender_->hybrid_slow_start().started());
+ sender_->OnRetransmissionTimeout(true);
+ EXPECT_FALSE(sender_->hybrid_slow_start().started());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, SlowStartHalfPacketLossWithLargeReduction) {
+ QuicConfig config;
+ QuicTagVector options;
+ options.push_back(kSSLR);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+
+ sender_->SetNumEmulatedConnections(1);
+ const int kNumberOfAcks = 10;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window in half sized packets.
+ SendAvailableSendWindow(kDefaultTCPMSS / 2);
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow(kDefaultTCPMSS / 2);
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose a packet to exit slow start. We should now have fallen out of
+ // slow start with a window reduced by 1.
+ LoseNPackets(1);
+ expected_send_window -= kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose 10 packets in recovery and verify that congestion window is reduced
+ // by 5 packets.
+ LoseNPackets(10, kDefaultTCPMSS / 2);
+ expected_send_window -= 5 * kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, SlowStartPacketLossWithMaxHalfReduction) {
+ QuicConfig config;
+ QuicTagVector options;
+ options.push_back(kSSLR);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+
+ sender_->SetNumEmulatedConnections(1);
+ const int kNumberOfAcks = kInitialCongestionWindowPackets / 2;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose a packet to exit slow start. We should now have fallen out of
+ // slow start with a window reduced by 1.
+ LoseNPackets(1);
+ expected_send_window -= kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose half the outstanding packets in recovery and verify the congestion
+ // window is only reduced by a max of half.
+ LoseNPackets(kNumberOfAcks * 2);
+ expected_send_window -= (kNumberOfAcks * 2 - 1) * kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ LoseNPackets(5);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, NoPRRWhenLessThanOnePacketInFlight) {
+ SendAvailableSendWindow();
+ LoseNPackets(kInitialCongestionWindowPackets - 1);
+ AckNPackets(1);
+ // PRR will allow 2 packets for every ack during recovery.
+ EXPECT_EQ(2, SendAvailableSendWindow());
+ // Simulate abandoning all packets by supplying a bytes_in_flight of 0.
+ // PRR should now allow a packet to be sent, even though prr's state
+ // variables believe it has sent enough packets.
+ EXPECT_EQ(QuicTime::Delta::Zero(), sender_->TimeUntilSend(clock_.Now(), 0));
+}
+
+TEST_F(TcpCubicSenderPacketsTest, SlowStartPacketLossPRR) {
+ sender_->SetNumEmulatedConnections(1);
+ // Test based on the first example in RFC6937.
+ // Ack 10 packets in 5 acks to raise the CWND to 20, as in the example.
+ const int kNumberOfAcks = 5;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ LoseNPackets(1);
+
+ // We should now have fallen out of slow start with a reduced window.
+ size_t send_window_before_loss = expected_send_window;
+ expected_send_window *= kRenoBeta;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Testing TCP proportional rate reduction.
+ // We should send packets paced over the received acks for the remaining
+ // outstanding packets. The number of packets before we exit recovery is the
+ // original CWND minus the packet that has been lost and the one which
+ // triggered the loss.
+ size_t remaining_packets_in_recovery =
+ send_window_before_loss / kDefaultTCPMSS - 2;
+
+ for (size_t i = 0; i < remaining_packets_in_recovery; ++i) {
+ AckNPackets(1);
+ SendAvailableSendWindow();
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ }
+
+ // We need to ack another window before we increase CWND by 1.
+ size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
+ for (size_t i = 0; i < number_of_packets_in_window; ++i) {
+ AckNPackets(1);
+ EXPECT_EQ(1, SendAvailableSendWindow());
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ }
+
+ AckNPackets(1);
+ expected_send_window += kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, SlowStartBurstPacketLossPRR) {
+ sender_->SetNumEmulatedConnections(1);
+ // Test based on the second example in RFC6937, though we also implement
+ // forward acknowledgements, so the first two incoming acks will trigger
+ // PRR immediately.
+ // Ack 20 packets in 10 acks to raise the CWND to 30.
+ const int kNumberOfAcks = 10;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Lose one more than the congestion window reduction, so that after loss,
+ // bytes_in_flight is lesser than the congestion window.
+ size_t send_window_after_loss = kRenoBeta * expected_send_window;
+ size_t num_packets_to_lose =
+ (expected_send_window - send_window_after_loss) / kDefaultTCPMSS + 1;
+ LoseNPackets(num_packets_to_lose);
+ // Immediately after the loss, ensure at least one packet can be sent.
+ // Losses without subsequent acks can occur with timer based loss detection.
+ EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_).IsZero());
+ AckNPackets(1);
+
+ // We should now have fallen out of slow start with a reduced window.
+ expected_send_window *= kRenoBeta;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Only 2 packets should be allowed to be sent, per PRR-SSRB
+ EXPECT_EQ(2, SendAvailableSendWindow());
+
+ // Ack the next packet, which triggers another loss.
+ LoseNPackets(1);
+ AckNPackets(1);
+
+ // Send 2 packets to simulate PRR-SSRB.
+ EXPECT_EQ(2, SendAvailableSendWindow());
+
+ // Ack the next packet, which triggers another loss.
+ LoseNPackets(1);
+ AckNPackets(1);
+
+ // Send 2 packets to simulate PRR-SSRB.
+ EXPECT_EQ(2, SendAvailableSendWindow());
+
+ // Exit recovery and return to sending at the new rate.
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ AckNPackets(1);
+ EXPECT_EQ(1, SendAvailableSendWindow());
+ }
+}
+
+TEST_F(TcpCubicSenderPacketsTest, RTOCongestionWindow) {
+ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+ EXPECT_EQ(kMaxCongestionWindowPackets, sender_->slowstart_threshold());
+
+ // Expect the window to decrease to the minimum once the RTO fires
+ // and slow start threshold to be set to 1/2 of the CWND.
+ sender_->OnRetransmissionTimeout(true);
+ EXPECT_EQ(2 * kDefaultTCPMSS, sender_->GetCongestionWindow());
+ EXPECT_EQ(5u, sender_->slowstart_threshold());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, RTOCongestionWindowNoRetransmission) {
+ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+
+ // Expect the window to remain unchanged if the RTO fires but no
+ // packets are retransmitted.
+ sender_->OnRetransmissionTimeout(false);
+ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, SlowStartMaxSendWindow) {
+ const QuicPacketCount kMaxCongestionWindowTCP = 50;
+ const int kNumberOfAcks = 100;
+ sender_.reset(
+ new TcpCubicSenderPacketsPeer(&clock_, false, kMaxCongestionWindowTCP));
+
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ QuicByteCount expected_send_window = kMaxCongestionWindowTCP * kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, TcpRenoMaxCongestionWindow) {
+ const QuicPacketCount kMaxCongestionWindowTCP = 50;
+ const int kNumberOfAcks = 1000;
+ sender_.reset(
+ new TcpCubicSenderPacketsPeer(&clock_, true, kMaxCongestionWindowTCP));
+
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ // Make sure we fall out of slow start.
+ LoseNPackets(1);
+
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+
+ QuicByteCount expected_send_window = kMaxCongestionWindowTCP * kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, TcpCubicMaxCongestionWindow) {
+ const QuicPacketCount kMaxCongestionWindowTCP = 50;
+ // Set to 10000 to compensate for small cubic alpha.
+ const int kNumberOfAcks = 10000;
+
+ sender_.reset(
+ new TcpCubicSenderPacketsPeer(&clock_, false, kMaxCongestionWindowTCP));
+
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ // Make sure we fall out of slow start.
+ LoseNPackets(1);
+
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+
+ QuicByteCount expected_send_window = kMaxCongestionWindowTCP * kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, TcpCubicResetEpochOnQuiescence) {
+ const int kMaxCongestionWindow = 50;
+ const QuicByteCount kMaxCongestionWindowBytes =
+ kMaxCongestionWindow * kDefaultTCPMSS;
+ sender_.reset(
+ new TcpCubicSenderPacketsPeer(&clock_, false, kMaxCongestionWindow));
+
+ int num_sent = SendAvailableSendWindow();
+
+ // Make sure we fall out of slow start.
+ QuicByteCount saved_cwnd = sender_->GetCongestionWindow();
+ LoseNPackets(1);
+ EXPECT_GT(saved_cwnd, sender_->GetCongestionWindow());
+
+ // Ack the rest of the outstanding packets to get out of recovery.
+ for (int i = 1; i < num_sent; ++i) {
+ AckNPackets(1);
+ }
+ EXPECT_EQ(0u, bytes_in_flight_);
+
+ // Send a new window of data and ack all; cubic growth should occur.
+ saved_cwnd = sender_->GetCongestionWindow();
+ num_sent = SendAvailableSendWindow();
+ for (int i = 0; i < num_sent; ++i) {
+ AckNPackets(1);
+ }
+ EXPECT_LT(saved_cwnd, sender_->GetCongestionWindow());
+ EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow());
+ EXPECT_EQ(0u, bytes_in_flight_);
+
+ // Quiescent time of 100 seconds
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100000));
+
+ // Send new window of data and ack one packet. Cubic epoch should have
+ // been reset; ensure cwnd increase is not dramatic.
+ saved_cwnd = sender_->GetCongestionWindow();
+ SendAvailableSendWindow();
+ AckNPackets(1);
+ EXPECT_NEAR(saved_cwnd, sender_->GetCongestionWindow(), kDefaultTCPMSS);
+ EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, MultipleLossesInOneWindow) {
+ SendAvailableSendWindow();
+ const QuicByteCount initial_window = sender_->GetCongestionWindow();
+ LosePacket(acked_packet_number_ + 1);
+ const QuicByteCount post_loss_window = sender_->GetCongestionWindow();
+ EXPECT_GT(initial_window, post_loss_window);
+ LosePacket(acked_packet_number_ + 3);
+ EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow());
+ LosePacket(packet_number_ - 1);
+ EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow());
+
+ // Lose a later packet and ensure the window decreases.
+ LosePacket(packet_number_);
+ EXPECT_GT(post_loss_window, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, DontTrackAckPackets) {
+ // Send a packet with no retransmittable data, and ensure it's not tracked.
+ EXPECT_FALSE(sender_->OnPacketSent(clock_.Now(), bytes_in_flight_,
+ packet_number_++, kDefaultTCPMSS,
+ NO_RETRANSMITTABLE_DATA));
+
+ // Send a data packet with retransmittable data, and ensure it is tracked.
+ EXPECT_TRUE(sender_->OnPacketSent(clock_.Now(), bytes_in_flight_,
+ packet_number_++, kDefaultTCPMSS,
+ HAS_RETRANSMITTABLE_DATA));
+}
+
+TEST_F(TcpCubicSenderPacketsTest, ConfigureInitialWindow) {
+ QuicConfig config;
+
+ QuicTagVector options;
+ options.push_back(kIW03);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ EXPECT_EQ(3u, sender_->congestion_window());
+
+ options.clear();
+ options.push_back(kIW10);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ EXPECT_EQ(10u, sender_->congestion_window());
+
+ options.clear();
+ options.push_back(kIW20);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ EXPECT_EQ(20u, sender_->congestion_window());
+
+ options.clear();
+ options.push_back(kIW50);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ EXPECT_EQ(50u, sender_->congestion_window());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, ConfigureMinimumWindow) {
+ QuicConfig config;
+
+ // Verify that kCOPT: kMIN1 forces the min CWND to 1 packet.
+ QuicTagVector options;
+ options.push_back(kMIN1);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ sender_->OnRetransmissionTimeout(true);
+ EXPECT_EQ(1u, sender_->congestion_window());
+}
+
+TEST_F(TcpCubicSenderPacketsTest,
+ 2ConnectionCongestionAvoidanceAtEndOfRecovery) {
+ sender_->SetNumEmulatedConnections(2);
+ // Ack 10 packets in 5 acks to raise the CWND to 20.
+ const int kNumberOfAcks = 5;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ LoseNPackets(1);
+
+ // We should now have fallen out of slow start with a reduced window.
+ expected_send_window = expected_send_window * sender_->GetRenoBeta();
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // No congestion window growth should occur in recovery phase, i.e., until the
+ // currently outstanding 20 packets are acked.
+ for (int i = 0; i < 10; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ EXPECT_TRUE(sender_->InRecovery());
+ AckNPackets(2);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ }
+ EXPECT_FALSE(sender_->InRecovery());
+
+ // Out of recovery now. Congestion window should not grow for half an RTT.
+ size_t packets_in_send_window = expected_send_window / kDefaultTCPMSS;
+ SendAvailableSendWindow();
+ AckNPackets(packets_in_send_window / 2 - 2);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Next ack should increase congestion window by 1MSS.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ expected_send_window += kDefaultTCPMSS;
+ packets_in_send_window += 1;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Congestion window should remain steady again for half an RTT.
+ SendAvailableSendWindow();
+ AckNPackets(packets_in_send_window / 2 - 1);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Next ack should cause congestion window to grow by 1MSS.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ expected_send_window += kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderPacketsTest,
+ 1ConnectionCongestionAvoidanceAtEndOfRecovery) {
+ sender_->SetNumEmulatedConnections(1);
+ // Ack 10 packets in 5 acks to raise the CWND to 20.
+ const int kNumberOfAcks = 5;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ LoseNPackets(1);
+
+ // We should now have fallen out of slow start with a reduced window.
+ expected_send_window *= kRenoBeta;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // No congestion window growth should occur in recovery phase, i.e., until the
+ // currently outstanding 20 packets are acked.
+ for (int i = 0; i < 10; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ EXPECT_TRUE(sender_->InRecovery());
+ AckNPackets(2);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ }
+ EXPECT_FALSE(sender_->InRecovery());
+
+ // Out of recovery now. Congestion window should not grow during RTT.
+ for (uint64_t i = 0; i < expected_send_window / kDefaultTCPMSS - 2; i += 2) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ }
+
+ // Next ack should cause congestion window to grow by 1MSS.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ expected_send_window += kDefaultTCPMSS;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, BandwidthResumption) {
+ // Test that when provided with CachedNetworkParameters and opted in to the
+ // bandwidth resumption experiment, that the TcpCubicSenderPackets sets
+ // initial CWND appropriately.
+
+ // Set some common values.
+ CachedNetworkParameters cached_network_params;
+ const QuicPacketCount kNumberOfPackets = 123;
+ const int kBandwidthEstimateBytesPerSecond =
+ kNumberOfPackets * kDefaultTCPMSS;
+ cached_network_params.set_bandwidth_estimate_bytes_per_second(
+ kBandwidthEstimateBytesPerSecond);
+ cached_network_params.set_min_rtt_ms(1000);
+
+ // Make sure that a bandwidth estimate results in a changed CWND.
+ cached_network_params.set_timestamp(clock_.WallNow().ToUNIXSeconds() -
+ (kNumSecondsPerHour - 1));
+ sender_->ResumeConnectionState(cached_network_params, false);
+ EXPECT_EQ(kNumberOfPackets, sender_->congestion_window());
+
+ // Resumed CWND is limited to be in a sensible range.
+ cached_network_params.set_bandwidth_estimate_bytes_per_second(
+ (kMaxCongestionWindowPackets + 1) * kDefaultTCPMSS);
+ sender_->ResumeConnectionState(cached_network_params, false);
+ EXPECT_EQ(kMaxCongestionWindowPackets, sender_->congestion_window());
+
+ if (FLAGS_quic_no_lower_bw_resumption_limit) {
+ // Resume with an illegal value of 0 and verify the server uses 1 instead.
+ cached_network_params.set_bandwidth_estimate_bytes_per_second(0);
+ sender_->ResumeConnectionState(cached_network_params, false);
+ EXPECT_EQ(sender_->min_congestion_window(), sender_->congestion_window());
+ } else {
+ cached_network_params.set_bandwidth_estimate_bytes_per_second(
+ (kMinCongestionWindowForBandwidthResumption - 1) * kDefaultTCPMSS);
+ sender_->ResumeConnectionState(cached_network_params, false);
+ EXPECT_EQ(kMinCongestionWindowForBandwidthResumption,
+ sender_->congestion_window());
+ }
+
+ // Resume to the max value.
+ cached_network_params.set_max_bandwidth_estimate_bytes_per_second(
+ kMaxCongestionWindowPackets * kDefaultTCPMSS);
+ sender_->ResumeConnectionState(cached_network_params, true);
+ EXPECT_EQ(kMaxCongestionWindowPackets * kDefaultTCPMSS,
+ sender_->GetCongestionWindow());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, PaceBelowCWND) {
+ QuicConfig config;
+
+ // Verify that kCOPT: kMIN4 forces the min CWND to 1 packet, but allows up
+ // to 4 to be sent.
+ QuicTagVector options;
+ options.push_back(kMIN4);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ sender_->OnRetransmissionTimeout(true);
+ EXPECT_EQ(1u, sender_->congestion_window());
+ EXPECT_TRUE(
+ sender_->TimeUntilSend(QuicTime::Zero(), kDefaultTCPMSS).IsZero());
+ EXPECT_TRUE(
+ sender_->TimeUntilSend(QuicTime::Zero(), 2 * kDefaultTCPMSS).IsZero());
+ EXPECT_TRUE(
+ sender_->TimeUntilSend(QuicTime::Zero(), 3 * kDefaultTCPMSS).IsZero());
+ EXPECT_FALSE(
+ sender_->TimeUntilSend(QuicTime::Zero(), 4 * kDefaultTCPMSS).IsZero());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, NoPRR) {
+ QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(100);
+ sender_->rtt_stats_.UpdateRtt(rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
+
+ sender_->SetNumEmulatedConnections(1);
+ // Verify that kCOPT: kNPRR allows all packets to be sent, even if only one
+ // ack has been received.
+ QuicTagVector options;
+ options.push_back(kNPRR);
+ QuicConfig config;
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ SendAvailableSendWindow();
+ LoseNPackets(9);
+ AckNPackets(1);
+
+ // We should now have fallen out of slow start with a reduced window.
+ EXPECT_EQ(kRenoBeta * kDefaultWindowTCP, sender_->GetCongestionWindow());
+ const QuicPacketCount window_in_packets =
+ kRenoBeta * kDefaultWindowTCP / kDefaultTCPMSS;
+ const QuicBandwidth expected_pacing_rate =
+ QuicBandwidth::FromBytesAndTimeDelta(kRenoBeta * kDefaultWindowTCP,
+ sender_->rtt_stats_.smoothed_rtt());
+ EXPECT_EQ(expected_pacing_rate, sender_->PacingRate(0));
+ EXPECT_EQ(window_in_packets,
+ static_cast<uint64_t>(SendAvailableSendWindow()));
+ EXPECT_EQ(expected_pacing_rate,
+ sender_->PacingRate(kRenoBeta * kDefaultWindowTCP));
+}
+
+TEST_F(TcpCubicSenderPacketsTest, PaceSlowerAboveCwnd) {
+ QuicTime::Delta rtt(QuicTime::Delta::FromMilliseconds(60));
+ sender_->rtt_stats_.UpdateRtt(rtt, QuicTime::Delta::Zero(), clock_.Now());
+
+ QuicConfig config;
+ QuicTagVector options;
+ options.push_back(kRATE);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ sender_->SetFromConfig(config, Perspective::IS_SERVER);
+ EXPECT_EQ(10u, sender_->congestion_window());
+ sender_->SetNumEmulatedConnections(1);
+ // Lose a packet to exit slow start.
+ LoseNPackets(1);
+ const QuicPacketCount cwnd = 7;
+ EXPECT_EQ(cwnd * kDefaultTCPMSS, sender_->GetCongestionWindow());
+
+ EXPECT_TRUE(
+ sender_->TimeUntilSend(QuicTime::Zero(), kDefaultTCPMSS).IsZero());
+ EXPECT_EQ(
+ sender_->PacingRate(kDefaultTCPMSS),
+ QuicBandwidth::FromBytesAndTimeDelta(7 * kDefaultTCPMSS, rtt) * 1.25);
+ for (QuicPacketCount i = cwnd + 1; i < 1.5 * cwnd; ++i) {
+ EXPECT_TRUE(
+ sender_->TimeUntilSend(QuicTime::Zero(), i * kDefaultTCPMSS).IsZero());
+ EXPECT_EQ(sender_->PacingRate(i * kDefaultTCPMSS),
+ QuicBandwidth::FromBytesAndTimeDelta(cwnd * kDefaultTCPMSS, rtt) *
+ 0.75);
+ }
+ EXPECT_FALSE(
+ sender_->TimeUntilSend(QuicTime::Zero(), 11 * kDefaultTCPMSS).IsZero());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, ResetAfterConnectionMigration) {
+ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+ EXPECT_EQ(kMaxCongestionWindowPackets, sender_->slowstart_threshold());
+
+ // Starts with slow start.
+ sender_->SetNumEmulatedConnections(1);
+ const int kNumberOfAcks = 10;
+ for (int i = 0; i < kNumberOfAcks; ++i) {
+ // Send our full send window.
+ SendAvailableSendWindow();
+ AckNPackets(2);
+ }
+ SendAvailableSendWindow();
+ QuicByteCount expected_send_window =
+ kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks);
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+
+ // Loses a packet to exit slow start.
+ LoseNPackets(1);
+
+ // We should now have fallen out of slow start with a reduced window. Slow
+ // start threshold is also updated.
+ expected_send_window *= kRenoBeta;
+ EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
+ EXPECT_EQ(expected_send_window / kDefaultTCPMSS,
+ sender_->slowstart_threshold());
+
+ // Resets cwnd and slow start threshold on connection migrations.
+ sender_->OnConnectionMigration();
+ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
+ EXPECT_EQ(kMaxCongestionWindowPackets, sender_->slowstart_threshold());
+ EXPECT_FALSE(sender_->hybrid_slow_start().started());
+}
+
+TEST_F(TcpCubicSenderPacketsTest, DefaultMaxCwnd) {
+ RttStats rtt_stats;
+ QuicConnectionStats stats;
+ std::unique_ptr<SendAlgorithmInterface> sender(SendAlgorithmInterface::Create(
+ &clock_, &rtt_stats, kCubic, &stats, kInitialCongestionWindow));
+
+ SendAlgorithmInterface::CongestionVector acked_packets;
+ SendAlgorithmInterface::CongestionVector missing_packets;
+ for (uint64_t i = 1; i < kDefaultMaxCongestionWindowPackets; ++i) {
+ acked_packets.clear();
+ acked_packets.push_back(std::make_pair(i, 1350));
+ sender->OnCongestionEvent(true, sender->GetCongestionWindow(),
+ acked_packets, missing_packets);
+ }
+ EXPECT_EQ(kDefaultMaxCongestionWindowPackets,
+ sender->GetCongestionWindow() / kDefaultTCPMSS);
+}
+
+TEST_F(TcpCubicSenderPacketsTest, LimitCwndIncreaseInCongestionAvoidance) {
+ FLAGS_quic_limit_cubic_cwnd_increase = true;
+ // Enable Cubic.
+ sender_.reset(new TcpCubicSenderPacketsPeer(
+ &clock_, false, kDefaultMaxCongestionWindowPackets));
+
+ int num_sent = SendAvailableSendWindow();
+
+ // Make sure we fall out of slow start.
+ QuicByteCount saved_cwnd = sender_->GetCongestionWindow();
+ LoseNPackets(1);
+ EXPECT_GT(saved_cwnd, sender_->GetCongestionWindow());
+
+ // Ack the rest of the outstanding packets to get out of recovery.
+ for (int i = 1; i < num_sent; ++i) {
+ AckNPackets(1);
+ }
+ EXPECT_EQ(0u, bytes_in_flight_);
+ // Send a new window of data and ack all; cubic growth should occur.
+ saved_cwnd = sender_->GetCongestionWindow();
+ num_sent = SendAvailableSendWindow();
+
+ // Ack packets until the CWND increases.
+ while (sender_->GetCongestionWindow() == saved_cwnd) {
+ AckNPackets(1);
+ SendAvailableSendWindow();
+ }
+ EXPECT_EQ(bytes_in_flight_, sender_->GetCongestionWindow());
+ saved_cwnd = sender_->GetCongestionWindow();
+
+ // Advance time 2 seconds waiting for an ack.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2000));
+
+ // Ack one packet. The CWND should increase by only one packet.
+ AckNPackets(1);
+ EXPECT_EQ(saved_cwnd + kDefaultTCPMSS, sender_->GetCongestionWindow());
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/congestion_control/windowed_filter.h b/chromium/net/quic/core/congestion_control/windowed_filter.h
new file mode 100644
index 00000000000..4012cb2b5c5
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/windowed_filter.h
@@ -0,0 +1,156 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#ifndef NET_QUIC_CONGESTION_CONTROL_WINDOWED_FILTER_H_
+#define NET_QUIC_CONGESTION_CONTROL_WINDOWED_FILTER_H_
+
+// Implements Kathleen Nichols' algorithm for tracking the minimum (or maximum)
+// estimate of a stream of samples over some fixed time interval. (E.g.,
+// the minimum RTT over the past five minutes.) The algorithm keeps track of
+// the best, second best, and third best min (or max) estimates, maintaining an
+// invariant that the measurement time of the n'th best >= n-1'th best.
+
+// The algorithm works as follows. On a reset, all three estimates are set to
+// the same sample. The second best estimate is then recorded in the second
+// quarter of the window, and a third best estimate is recorded in the second
+// half of the window, bounding the worst case error when the true min is
+// monotonically increasing (or true max is monotonically decreasing) over the
+// window.
+//
+// A new best sample replaces all three estimates, since the new best is lower
+// (or higher) than everything else in the window and it is the most recent.
+// The window thus effectively gets reset on every new min. The same property
+// holds true for second best and third best estimates. Specifically, when a
+// sample arrives that is better than the second best but not better than the
+// best, it replaces the second and third best estimates but not the best
+// estimate. Similarly, a sample that is better than the third best estimate
+// but not the other estimates replaces only the third best estimate.
+//
+// Finally, when the best expires, it is replaced by the second best, which in
+// turn is replaced by the third best. The newest sample replaces the third
+// best.
+
+#include "base/logging.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+// Compares two values and returns true if the first is less than or equal
+// to the second.
+template <class T>
+struct MinFilter {
+ bool operator()(const T& lhs, const T& rhs) const { return lhs <= rhs; }
+};
+
+// Compares two values and returns true if the first is greater than or equal
+// to the second.
+template <class T>
+struct MaxFilter {
+ bool operator()(const T& lhs, const T& rhs) const { return lhs >= rhs; }
+};
+
+// Use the following to construct a windowed filter object of type T.
+// For example, a min filter using QuicTime as the time type:
+// WindowedFilter<T, MinFilter<T>, QuicTime, QuicTime::Delta> ObjectName;
+// A max filter using 64-bit integers as the time type:
+// WindowedFilter<T, MaxFilter<T>, uint64_t, int64_t> ObjectName;
+// Specifically, this template takes four arguments:
+// 1. T -- type of the measurement that is being filtered.
+// 2. Compare -- MinFilter<T> or MaxFilter<T>, depending on the type of filter
+// desired.
+// 3. TimeT -- the type used to represent timestamps.
+// 4. TimeDeltaT -- the type used to represent continuous time intervals between
+// two timestamps. Has to be the type of (a - b) if both |a| and |b| are
+// of type TimeT.
+template <class T, class Compare, typename TimeT, typename TimeDeltaT>
+class WindowedFilter {
+ public:
+ // |window_length| is the period after which a best estimate expires.
+ // |zero_value| is used as the uninitialized value for objects of T.
+ // Importantly, |zero_value| should be an invalid value for a true sample.
+ WindowedFilter(TimeDeltaT window_length, T zero_value, TimeT zero_time)
+ : window_length_(window_length),
+ zero_value_(zero_value),
+ estimates_{Sample(zero_value_, zero_time),
+ Sample(zero_value_, zero_time),
+ Sample(zero_value_, zero_time)} {}
+
+ // Updates best estimates with |sample|, and expires and updates best
+ // estimates as necessary.
+ void Update(T new_sample, TimeT new_time) {
+ // Reset all estimates if they have not yet been initialized, if new sample
+ // is a new best, or if the newest recorded estimate is too old.
+ if (estimates_[0].sample == zero_value_ ||
+ Compare()(new_sample, estimates_[0].sample) ||
+ new_time - estimates_[2].time > window_length_) {
+ Reset(new_sample, new_time);
+ return;
+ }
+
+ if (Compare()(new_sample, estimates_[1].sample)) {
+ estimates_[1] = Sample(new_sample, new_time);
+ estimates_[2] = estimates_[1];
+ } else if (Compare()(new_sample, estimates_[2].sample)) {
+ estimates_[2] = Sample(new_sample, new_time);
+ }
+
+ // Expire and update estimates as necessary.
+ if (new_time - estimates_[0].time > window_length_) {
+ // The best estimate hasn't been updated for an entire window, so promote
+ // second and third best estimates.
+ estimates_[0] = estimates_[1];
+ estimates_[1] = estimates_[2];
+ estimates_[2] = Sample(new_sample, new_time);
+ // Need to iterate one more time. Check if the new best estimate is
+ // outside the window as well, since it may also have been recorded a
+ // long time ago. Don't need to iterate once more since we cover that
+ // case at the beginning of the method.
+ if (new_time - estimates_[0].time > window_length_) {
+ estimates_[0] = estimates_[1];
+ estimates_[1] = estimates_[2];
+ }
+ return;
+ }
+ if (estimates_[1].sample == estimates_[0].sample &&
+ new_time - estimates_[1].time > window_length_ >> 2) {
+ // A quarter of the window has passed without a better sample, so the
+ // second-best estimate is taken from the second quarter of the window.
+ estimates_[2] = estimates_[1] = Sample(new_sample, new_time);
+ return;
+ }
+
+ if (estimates_[2].sample == estimates_[1].sample &&
+ new_time - estimates_[2].time > window_length_ >> 1) {
+ // We've passed a half of the window without a better estimate, so take
+ // a third-best estimate from the second half of the window.
+ estimates_[2] = Sample(new_sample, new_time);
+ }
+ }
+
+ // Resets all estimates to new sample.
+ void Reset(T new_sample, TimeT new_time) {
+ estimates_[0] = estimates_[1] = estimates_[2] =
+ Sample(new_sample, new_time);
+ }
+
+ T GetBest() const { return estimates_[0].sample; }
+ T GetSecondBest() const { return estimates_[1].sample; }
+ T GetThirdBest() const { return estimates_[2].sample; }
+
+ private:
+ struct Sample {
+ T sample;
+ TimeT time;
+ Sample(T init_sample, TimeT init_time)
+ : sample(init_sample), time(init_time) {}
+ };
+
+ TimeDeltaT window_length_; // Time length of window.
+ T zero_value_; // Uninitialized value of T.
+ Sample estimates_[3]; // Best estimate is element 0.
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CONGESTION_CONTROL_WINDOWED_FILTER_H_
diff --git a/chromium/net/quic/core/congestion_control/windowed_filter_test.cc b/chromium/net/quic/core/congestion_control/windowed_filter_test.cc
new file mode 100644
index 00000000000..92a8f60708a
--- /dev/null
+++ b/chromium/net/quic/core/congestion_control/windowed_filter_test.cc
@@ -0,0 +1,392 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#include "net/quic/core/congestion_control/windowed_filter.h"
+
+#include "base/logging.h"
+#include "net/quic/core/congestion_control/rtt_stats.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_protocol.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+namespace {
+
+class WindowedFilterTest : public ::testing::Test {
+ public:
+ // Set the window to 99ms, so 25ms is more than a quarter rtt.
+ WindowedFilterTest()
+ : windowed_min_rtt_(QuicTime::Delta::FromMilliseconds(99),
+ QuicTime::Delta::Zero(),
+ QuicTime::Zero()),
+ windowed_max_bw_(QuicTime::Delta::FromMilliseconds(99),
+ QuicBandwidth::Zero(),
+ QuicTime::Zero()) {}
+
+ // Sets up windowed_min_rtt_ to have the following values:
+ // Best = 20ms, recorded at 25ms
+ // Second best = 40ms, recorded at 75ms
+ // Third best = 50ms, recorded at 100ms
+ void InitializeMinFilter() {
+ QuicTime now = QuicTime::Zero();
+ QuicTime::Delta rtt_sample = QuicTime::Delta::FromMilliseconds(10);
+ for (int i = 0; i < 5; ++i) {
+ windowed_min_rtt_.Update(rtt_sample, now);
+ VLOG(1) << "i: " << i << " sample: " << rtt_sample.ToMilliseconds()
+ << " mins: "
+ << " " << windowed_min_rtt_.GetBest().ToMilliseconds() << " "
+ << windowed_min_rtt_.GetSecondBest().ToMilliseconds() << " "
+ << windowed_min_rtt_.GetThirdBest().ToMilliseconds();
+ now = now + QuicTime::Delta::FromMilliseconds(25);
+ rtt_sample = rtt_sample + QuicTime::Delta::FromMilliseconds(10);
+ }
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20),
+ windowed_min_rtt_.GetBest());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(40),
+ windowed_min_rtt_.GetSecondBest());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(50),
+ windowed_min_rtt_.GetThirdBest());
+ }
+
+ // Sets up windowed_max_bw_ to have the following values:
+ // Best = 900 bps, recorded at 25ms
+ // Second best = 700 bps, recorded at 75ms
+ // Third best = 600 bps, recorded at 100ms
+ void InitializeMaxFilter() {
+ QuicTime now = QuicTime::Zero();
+ QuicBandwidth bw_sample = QuicBandwidth::FromBitsPerSecond(1000);
+ for (int i = 0; i < 5; ++i) {
+ windowed_max_bw_.Update(bw_sample, now);
+ VLOG(1) << "i: " << i << " sample: " << bw_sample.ToBitsPerSecond()
+ << " maxs: "
+ << " " << windowed_max_bw_.GetBest().ToBitsPerSecond() << " "
+ << windowed_max_bw_.GetSecondBest().ToBitsPerSecond() << " "
+ << windowed_max_bw_.GetThirdBest().ToBitsPerSecond();
+ now = now + QuicTime::Delta::FromMilliseconds(25);
+ bw_sample = bw_sample - QuicBandwidth::FromBitsPerSecond(100);
+ }
+ EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(900),
+ windowed_max_bw_.GetBest());
+ EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(700),
+ windowed_max_bw_.GetSecondBest());
+ EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(600),
+ windowed_max_bw_.GetThirdBest());
+ }
+
+ protected:
+ WindowedFilter<QuicTime::Delta,
+ MinFilter<QuicTime::Delta>,
+ QuicTime,
+ QuicTime::Delta>
+ windowed_min_rtt_;
+ WindowedFilter<QuicBandwidth,
+ MaxFilter<QuicBandwidth>,
+ QuicTime,
+ QuicTime::Delta>
+ windowed_max_bw_;
+};
+
+namespace {
+// Test helper function: updates the filter with a lot of small values in order
+// to ensure that it is not susceptible to noise.
+void UpdateWithIrrelevantSamples(
+ WindowedFilter<uint64_t, MaxFilter<uint64_t>, uint64_t, uint64_t>* filter,
+ uint64_t max_value,
+ uint64_t time) {
+ for (uint64_t i = 0; i < 1000; i++) {
+ filter->Update(i % max_value, time);
+ }
+}
+} // namespace
+
+TEST_F(WindowedFilterTest, UninitializedEstimates) {
+ EXPECT_EQ(QuicTime::Delta::Zero(), windowed_min_rtt_.GetBest());
+ EXPECT_EQ(QuicTime::Delta::Zero(), windowed_min_rtt_.GetSecondBest());
+ EXPECT_EQ(QuicTime::Delta::Zero(), windowed_min_rtt_.GetThirdBest());
+ EXPECT_EQ(QuicBandwidth::Zero(), windowed_max_bw_.GetBest());
+ EXPECT_EQ(QuicBandwidth::Zero(), windowed_max_bw_.GetSecondBest());
+ EXPECT_EQ(QuicBandwidth::Zero(), windowed_max_bw_.GetThirdBest());
+}
+
+TEST_F(WindowedFilterTest, MonotonicallyIncreasingMin) {
+ QuicTime now = QuicTime::Zero();
+ QuicTime::Delta rtt_sample = QuicTime::Delta::FromMilliseconds(10);
+ windowed_min_rtt_.Update(rtt_sample, now);
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), windowed_min_rtt_.GetBest());
+
+ // Gradually increase the rtt samples and ensure the windowed min rtt starts
+ // rising.
+ for (int i = 0; i < 6; ++i) {
+ now = now + QuicTime::Delta::FromMilliseconds(25);
+ rtt_sample = rtt_sample + QuicTime::Delta::FromMilliseconds(10);
+ windowed_min_rtt_.Update(rtt_sample, now);
+ VLOG(1) << "i: " << i << " sample: " << rtt_sample.ToMilliseconds()
+ << " mins: "
+ << " " << windowed_min_rtt_.GetBest().ToMilliseconds() << " "
+ << windowed_min_rtt_.GetSecondBest().ToMilliseconds() << " "
+ << windowed_min_rtt_.GetThirdBest().ToMilliseconds();
+ if (i < 3) {
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
+ windowed_min_rtt_.GetBest());
+ } else if (i == 3) {
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20),
+ windowed_min_rtt_.GetBest());
+ } else if (i < 6) {
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(40),
+ windowed_min_rtt_.GetBest());
+ }
+ }
+}
+
+TEST_F(WindowedFilterTest, MonotonicallyDecreasingMax) {
+ QuicTime now = QuicTime::Zero();
+ QuicBandwidth bw_sample = QuicBandwidth::FromBitsPerSecond(1000);
+ windowed_max_bw_.Update(bw_sample, now);
+ EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(1000), windowed_max_bw_.GetBest());
+
+ // Gradually decrease the bw samples and ensure the windowed max bw starts
+ // decreasing.
+ for (int i = 0; i < 6; ++i) {
+ now = now + QuicTime::Delta::FromMilliseconds(25);
+ bw_sample = bw_sample - QuicBandwidth::FromBitsPerSecond(100);
+ windowed_max_bw_.Update(bw_sample, now);
+ VLOG(1) << "i: " << i << " sample: " << bw_sample.ToBitsPerSecond()
+ << " maxs: "
+ << " " << windowed_max_bw_.GetBest().ToBitsPerSecond() << " "
+ << windowed_max_bw_.GetSecondBest().ToBitsPerSecond() << " "
+ << windowed_max_bw_.GetThirdBest().ToBitsPerSecond();
+ if (i < 3) {
+ EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(1000),
+ windowed_max_bw_.GetBest());
+ } else if (i == 3) {
+ EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(900),
+ windowed_max_bw_.GetBest());
+ } else if (i < 6) {
+ EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(700),
+ windowed_max_bw_.GetBest());
+ }
+ }
+}
+
+TEST_F(WindowedFilterTest, SampleChangesThirdBestMin) {
+ InitializeMinFilter();
+ // RTT sample lower than the third-choice min-rtt sets that, but nothing else.
+ QuicTime::Delta rtt_sample =
+ windowed_min_rtt_.GetThirdBest() - QuicTime::Delta::FromMilliseconds(5);
+ // This assert is necessary to avoid triggering -Wstrict-overflow
+ // See crbug/616957
+ ASSERT_GT(windowed_min_rtt_.GetThirdBest(),
+ QuicTime::Delta::FromMilliseconds(5));
+ // Latest sample was recorded at 100ms.
+ QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101);
+ windowed_min_rtt_.Update(rtt_sample, now);
+ windowed_min_rtt_.Update(rtt_sample, now);
+ EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(40),
+ windowed_min_rtt_.GetSecondBest());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20), windowed_min_rtt_.GetBest());
+}
+
+TEST_F(WindowedFilterTest, SampleChangesThirdBestMax) {
+ InitializeMaxFilter();
+ // BW sample higher than the third-choice max sets that, but nothing else.
+ QuicBandwidth bw_sample =
+ windowed_max_bw_.GetThirdBest() + QuicBandwidth::FromBitsPerSecond(50);
+ // Latest sample was recorded at 100ms.
+ QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101);
+ windowed_max_bw_.Update(bw_sample, now);
+ EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
+ EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(700),
+ windowed_max_bw_.GetSecondBest());
+ EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(900), windowed_max_bw_.GetBest());
+}
+
+TEST_F(WindowedFilterTest, SampleChangesSecondBestMin) {
+ InitializeMinFilter();
+ // RTT sample lower than the second-choice min sets that and also
+ // the third-choice min.
+ QuicTime::Delta rtt_sample =
+ windowed_min_rtt_.GetSecondBest() - QuicTime::Delta::FromMilliseconds(5);
+ // This assert is necessary to avoid triggering -Wstrict-overflow
+ // See crbug/616957
+ ASSERT_GT(windowed_min_rtt_.GetSecondBest(),
+ QuicTime::Delta::FromMilliseconds(5));
+ // Latest sample was recorded at 100ms.
+ QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101);
+ windowed_min_rtt_.Update(rtt_sample, now);
+ EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
+ EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20), windowed_min_rtt_.GetBest());
+}
+
+TEST_F(WindowedFilterTest, SampleChangesSecondBestMax) {
+ InitializeMaxFilter();
+ // BW sample higher than the second-choice max sets that and also
+ // the third-choice max.
+ QuicBandwidth bw_sample =
+ windowed_max_bw_.GetSecondBest() + QuicBandwidth::FromBitsPerSecond(50);
+ // Latest sample was recorded at 100ms.
+ QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101);
+ windowed_max_bw_.Update(bw_sample, now);
+ EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
+ EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest());
+ EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(900), windowed_max_bw_.GetBest());
+}
+
+TEST_F(WindowedFilterTest, SampleChangesAllMins) {
+ InitializeMinFilter();
+ // RTT sample lower than the first-choice min-rtt sets that and also
+ // the second and third-choice mins.
+ QuicTime::Delta rtt_sample =
+ windowed_min_rtt_.GetBest() - QuicTime::Delta::FromMilliseconds(5);
+ // This assert is necessary to avoid triggering -Wstrict-overflow
+ // See crbug/616957
+ ASSERT_GT(windowed_min_rtt_.GetBest(), QuicTime::Delta::FromMilliseconds(5));
+ // Latest sample was recorded at 100ms.
+ QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101);
+ windowed_min_rtt_.Update(rtt_sample, now);
+ EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
+ EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest());
+ EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetBest());
+}
+
+TEST_F(WindowedFilterTest, SampleChangesAllMaxs) {
+ InitializeMaxFilter();
+ // BW sample higher than the first-choice max sets that and also
+ // the second and third-choice maxs.
+ QuicBandwidth bw_sample =
+ windowed_max_bw_.GetBest() + QuicBandwidth::FromBitsPerSecond(50);
+ // Latest sample was recorded at 100ms.
+ QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101);
+ windowed_max_bw_.Update(bw_sample, now);
+ EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
+ EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest());
+ EXPECT_EQ(bw_sample, windowed_max_bw_.GetBest());
+}
+
+TEST_F(WindowedFilterTest, ExpireBestMin) {
+ InitializeMinFilter();
+ QuicTime::Delta old_third_best = windowed_min_rtt_.GetThirdBest();
+ QuicTime::Delta old_second_best = windowed_min_rtt_.GetSecondBest();
+ QuicTime::Delta rtt_sample =
+ old_third_best + QuicTime::Delta::FromMilliseconds(5);
+ // Best min sample was recorded at 25ms, so expiry time is 124ms.
+ QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(125);
+ windowed_min_rtt_.Update(rtt_sample, now);
+ EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
+ EXPECT_EQ(old_third_best, windowed_min_rtt_.GetSecondBest());
+ EXPECT_EQ(old_second_best, windowed_min_rtt_.GetBest());
+}
+
+TEST_F(WindowedFilterTest, ExpireBestMax) {
+ InitializeMaxFilter();
+ QuicBandwidth old_third_best = windowed_max_bw_.GetThirdBest();
+ QuicBandwidth old_second_best = windowed_max_bw_.GetSecondBest();
+ QuicBandwidth bw_sample =
+ old_third_best - QuicBandwidth::FromBitsPerSecond(50);
+ // Best max sample was recorded at 25ms, so expiry time is 124ms.
+ QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(125);
+ windowed_max_bw_.Update(bw_sample, now);
+ EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
+ EXPECT_EQ(old_third_best, windowed_max_bw_.GetSecondBest());
+ EXPECT_EQ(old_second_best, windowed_max_bw_.GetBest());
+}
+
+TEST_F(WindowedFilterTest, ExpireSecondBestMin) {
+ InitializeMinFilter();
+ QuicTime::Delta old_third_best = windowed_min_rtt_.GetThirdBest();
+ QuicTime::Delta rtt_sample =
+ old_third_best + QuicTime::Delta::FromMilliseconds(5);
+ // Second best min sample was recorded at 75ms, so expiry time is 174ms.
+ QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(175);
+ windowed_min_rtt_.Update(rtt_sample, now);
+ EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
+ EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest());
+ EXPECT_EQ(old_third_best, windowed_min_rtt_.GetBest());
+}
+
+TEST_F(WindowedFilterTest, ExpireSecondBestMax) {
+ InitializeMaxFilter();
+ QuicBandwidth old_third_best = windowed_max_bw_.GetThirdBest();
+ QuicBandwidth bw_sample =
+ old_third_best - QuicBandwidth::FromBitsPerSecond(50);
+ // Second best max sample was recorded at 75ms, so expiry time is 174ms.
+ QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(175);
+ windowed_max_bw_.Update(bw_sample, now);
+ EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
+ EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest());
+ EXPECT_EQ(old_third_best, windowed_max_bw_.GetBest());
+}
+
+TEST_F(WindowedFilterTest, ExpireAllMins) {
+ InitializeMinFilter();
+ QuicTime::Delta rtt_sample =
+ windowed_min_rtt_.GetThirdBest() + QuicTime::Delta::FromMilliseconds(5);
+ // This assert is necessary to avoid triggering -Wstrict-overflow
+ // See crbug/616957
+ ASSERT_LT(windowed_min_rtt_.GetThirdBest(),
+ QuicTime::Delta::Infinite() - QuicTime::Delta::FromMilliseconds(5));
+
+ // Third best min sample was recorded at 100ms, so expiry time is 199ms.
+ QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(200);
+ windowed_min_rtt_.Update(rtt_sample, now);
+ EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
+ EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest());
+ EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetBest());
+}
+
+TEST_F(WindowedFilterTest, ExpireAllMaxs) {
+ InitializeMaxFilter();
+ QuicBandwidth bw_sample =
+ windowed_max_bw_.GetThirdBest() - QuicBandwidth::FromBitsPerSecond(50);
+ // Third best max sample was recorded at 100ms, so expiry time is 199ms.
+ QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(200);
+ windowed_max_bw_.Update(bw_sample, now);
+ EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
+ EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest());
+ EXPECT_EQ(bw_sample, windowed_max_bw_.GetBest());
+}
+
+// Test the windowed filter where the time used is an exact counter instead of a
+// timestamp. This is useful if, for example, the time is measured in round
+// trips.
+TEST_F(WindowedFilterTest, ExpireCounterBasedMax) {
+ // Create a window which starts at t = 0 and expires after two cycles.
+ WindowedFilter<uint64_t, MaxFilter<uint64_t>, uint64_t, uint64_t> max_filter(
+ 2, 0, 0);
+
+ // Insert 50000 at t = 1.
+ const uint64_t kBest = 50000;
+ max_filter.Update(50000, 1);
+ EXPECT_EQ(kBest, max_filter.GetBest());
+ UpdateWithIrrelevantSamples(&max_filter, 20, 1);
+ EXPECT_EQ(kBest, max_filter.GetBest());
+
+ // Insert 40000 at t = 2. Nothing is expected to expire.
+ max_filter.Update(40000, 2);
+ EXPECT_EQ(kBest, max_filter.GetBest());
+ UpdateWithIrrelevantSamples(&max_filter, 20, 2);
+ EXPECT_EQ(kBest, max_filter.GetBest());
+
+ // Insert 30000 at t = 3. Nothing is expected to expire yet.
+ max_filter.Update(30000, 3);
+ EXPECT_EQ(kBest, max_filter.GetBest());
+ UpdateWithIrrelevantSamples(&max_filter, 20, 3);
+ EXPECT_EQ(kBest, max_filter.GetBest());
+ VLOG(0) << max_filter.GetSecondBest();
+ VLOG(0) << max_filter.GetThirdBest();
+
+ // Insert 20000 at t = 4. 50000 at t = 1 expires, so 40000 becomes the new
+ // maximum.
+ const uint64_t kNewBest = 40000;
+ max_filter.Update(20000, 4);
+ EXPECT_EQ(kNewBest, max_filter.GetBest());
+ UpdateWithIrrelevantSamples(&max_filter, 20, 4);
+ EXPECT_EQ(kNewBest, max_filter.GetBest());
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/aead_base_decrypter.cc b/chromium/net/quic/core/crypto/aead_base_decrypter.cc
new file mode 100644
index 00000000000..721fe5ba566
--- /dev/null
+++ b/chromium/net/quic/core/crypto/aead_base_decrypter.cc
@@ -0,0 +1,168 @@
+// Copyright (c) 2013 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 <openssl/err.h>
+#include <openssl/evp.h>
+
+#include <memory>
+
+#include "net/quic/core/crypto/aead_base_decrypter.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+namespace {
+
+// Clear OpenSSL error stack.
+void ClearOpenSslErrors() {
+ while (ERR_get_error()) {
+ }
+}
+
+// In debug builds only, log OpenSSL error stack. Then clear OpenSSL error
+// stack.
+void DLogOpenSslErrors() {
+#ifdef NDEBUG
+ ClearOpenSslErrors();
+#else
+ while (uint32_t error = ERR_get_error()) {
+ char buf[120];
+ ERR_error_string_n(error, buf, arraysize(buf));
+ DLOG(ERROR) << "OpenSSL error: " << buf;
+ }
+#endif
+}
+
+} // namespace
+
+AeadBaseDecrypter::AeadBaseDecrypter(const EVP_AEAD* aead_alg,
+ size_t key_size,
+ size_t auth_tag_size,
+ size_t nonce_prefix_size)
+ : aead_alg_(aead_alg),
+ key_size_(key_size),
+ auth_tag_size_(auth_tag_size),
+ nonce_prefix_size_(nonce_prefix_size),
+ have_preliminary_key_(false) {
+ DCHECK_GT(256u, key_size);
+ DCHECK_GT(256u, auth_tag_size);
+ DCHECK_GT(256u, nonce_prefix_size);
+ DCHECK_LE(key_size_, sizeof(key_));
+ DCHECK_LE(nonce_prefix_size_, sizeof(nonce_prefix_));
+}
+
+AeadBaseDecrypter::~AeadBaseDecrypter() {}
+
+bool AeadBaseDecrypter::SetKey(StringPiece key) {
+ DCHECK_EQ(key.size(), key_size_);
+ if (key.size() != key_size_) {
+ return false;
+ }
+ memcpy(key_, key.data(), key.size());
+
+ EVP_AEAD_CTX_cleanup(ctx_.get());
+ if (!EVP_AEAD_CTX_init(ctx_.get(), aead_alg_, key_, key_size_, auth_tag_size_,
+ nullptr)) {
+ DLogOpenSslErrors();
+ return false;
+ }
+
+ return true;
+}
+
+bool AeadBaseDecrypter::SetNoncePrefix(StringPiece nonce_prefix) {
+ DCHECK_EQ(nonce_prefix.size(), nonce_prefix_size_);
+ if (nonce_prefix.size() != nonce_prefix_size_) {
+ return false;
+ }
+ memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size());
+ return true;
+}
+
+bool AeadBaseDecrypter::SetPreliminaryKey(StringPiece key) {
+ DCHECK(!have_preliminary_key_);
+ SetKey(key);
+ have_preliminary_key_ = true;
+
+ return true;
+}
+
+bool AeadBaseDecrypter::SetDiversificationNonce(
+ const DiversificationNonce& nonce) {
+ if (!have_preliminary_key_) {
+ return true;
+ }
+
+ string key, nonce_prefix;
+ DiversifyPreliminaryKey(
+ StringPiece(reinterpret_cast<const char*>(key_), key_size_),
+ StringPiece(reinterpret_cast<const char*>(nonce_prefix_),
+ nonce_prefix_size_),
+ nonce, key_size_, nonce_prefix_size_, &key, &nonce_prefix);
+
+ if (!SetKey(key) || !SetNoncePrefix(nonce_prefix)) {
+ DCHECK(false);
+ return false;
+ }
+
+ have_preliminary_key_ = false;
+ return true;
+}
+
+bool AeadBaseDecrypter::DecryptPacket(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ StringPiece associated_data,
+ StringPiece ciphertext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) {
+ if (ciphertext.length() < auth_tag_size_) {
+ return false;
+ }
+
+ if (have_preliminary_key_) {
+ QUIC_BUG << "Unable to decrypt while key diversification is pending";
+ return false;
+ }
+
+ uint8_t nonce[sizeof(nonce_prefix_) + sizeof(packet_number)];
+ const size_t nonce_size = nonce_prefix_size_ + sizeof(packet_number);
+ memcpy(nonce, nonce_prefix_, nonce_prefix_size_);
+ uint64_t path_id_packet_number =
+ QuicUtils::PackPathIdAndPacketNumber(path_id, packet_number);
+ memcpy(nonce + nonce_prefix_size_, &path_id_packet_number,
+ sizeof(path_id_packet_number));
+ if (!EVP_AEAD_CTX_open(
+ ctx_.get(), reinterpret_cast<uint8_t*>(output), output_length,
+ max_output_length, reinterpret_cast<const uint8_t*>(nonce),
+ nonce_size, reinterpret_cast<const uint8_t*>(ciphertext.data()),
+ ciphertext.size(),
+ reinterpret_cast<const uint8_t*>(associated_data.data()),
+ associated_data.size())) {
+ // Because QuicFramer does trial decryption, decryption errors are expected
+ // when encryption level changes. So we don't log decryption errors.
+ ClearOpenSslErrors();
+ return false;
+ }
+ return true;
+}
+
+StringPiece AeadBaseDecrypter::GetKey() const {
+ return StringPiece(reinterpret_cast<const char*>(key_), key_size_);
+}
+
+StringPiece AeadBaseDecrypter::GetNoncePrefix() const {
+ if (nonce_prefix_size_ == 0) {
+ return StringPiece();
+ }
+ return StringPiece(reinterpret_cast<const char*>(nonce_prefix_),
+ nonce_prefix_size_);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/aead_base_decrypter.h b/chromium/net/quic/core/crypto/aead_base_decrypter.h
new file mode 100644
index 00000000000..f6da359b806
--- /dev/null
+++ b/chromium/net/quic/core/crypto/aead_base_decrypter.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2013 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_CRYPTO_AEAD_BASE_DECRYPTER_H_
+#define NET_QUIC_CRYPTO_AEAD_BASE_DECRYPTER_H_
+
+#include <stddef.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/scoped_evp_aead_ctx.h"
+
+namespace net {
+
+// AeadBaseDecrypter is the base class of AEAD QuicDecrypter subclasses.
+class NET_EXPORT_PRIVATE AeadBaseDecrypter : public QuicDecrypter {
+ public:
+ AeadBaseDecrypter(const EVP_AEAD* aead_alg,
+ size_t key_size,
+ size_t auth_tag_size,
+ size_t nonce_prefix_size);
+ ~AeadBaseDecrypter() override;
+
+ // QuicDecrypter implementation
+ bool SetKey(base::StringPiece key) override;
+ bool SetNoncePrefix(base::StringPiece nonce_prefix) override;
+ bool SetPreliminaryKey(base::StringPiece key) override;
+ bool SetDiversificationNonce(const DiversificationNonce& nonce) override;
+ bool DecryptPacket(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ base::StringPiece associated_data,
+ base::StringPiece ciphertext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) override;
+ base::StringPiece GetKey() const override;
+ base::StringPiece GetNoncePrefix() const override;
+
+ protected:
+ // Make these constants available to the subclasses so that the subclasses
+ // can assert at compile time their key_size_ and nonce_prefix_size_ do not
+ // exceed the maximum.
+ static const size_t kMaxKeySize = 32;
+ static const size_t kMaxNoncePrefixSize = 4;
+
+ private:
+ const EVP_AEAD* const aead_alg_;
+ const size_t key_size_;
+ const size_t auth_tag_size_;
+ const size_t nonce_prefix_size_;
+ bool have_preliminary_key_;
+
+ // The key.
+ unsigned char key_[kMaxKeySize];
+ // The nonce prefix.
+ unsigned char nonce_prefix_[kMaxNoncePrefixSize];
+
+ ScopedEVPAEADCtx ctx_;
+
+ DISALLOW_COPY_AND_ASSIGN(AeadBaseDecrypter);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_AEAD_BASE_DECRYPTER_H_
diff --git a/chromium/net/quic/core/crypto/aead_base_encrypter.cc b/chromium/net/quic/core/crypto/aead_base_encrypter.cc
new file mode 100644
index 00000000000..195aba79402
--- /dev/null
+++ b/chromium/net/quic/core/crypto/aead_base_encrypter.cc
@@ -0,0 +1,164 @@
+// Copyright (c) 2013 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 <openssl/err.h>
+#include <openssl/evp.h>
+#include <string.h>
+
+#include <memory>
+
+#include "net/quic/core/crypto/aead_base_encrypter.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+
+using base::StringPiece;
+
+namespace net {
+
+namespace {
+
+// The maximum size in bytes of the nonce, including 8 bytes of sequence number.
+// ChaCha20 uses only the 8 byte sequence number and AES-GCM uses 12 bytes.
+const size_t kMaxNonceSize = 12;
+
+// In debug builds only, log OpenSSL error stack. Then clear OpenSSL error
+// stack.
+void DLogOpenSslErrors() {
+#ifdef NDEBUG
+ while (ERR_get_error()) {
+ }
+#else
+ while (unsigned long error = ERR_get_error()) {
+ char buf[120];
+ ERR_error_string_n(error, buf, arraysize(buf));
+ DLOG(ERROR) << "OpenSSL error: " << buf;
+ }
+#endif
+}
+
+} // namespace
+
+AeadBaseEncrypter::AeadBaseEncrypter(const EVP_AEAD* aead_alg,
+ size_t key_size,
+ size_t auth_tag_size,
+ size_t nonce_prefix_size)
+ : aead_alg_(aead_alg),
+ key_size_(key_size),
+ auth_tag_size_(auth_tag_size),
+ nonce_prefix_size_(nonce_prefix_size) {
+ DCHECK_LE(key_size_, sizeof(key_));
+ DCHECK_LE(nonce_prefix_size_, sizeof(nonce_prefix_));
+ DCHECK_GE(kMaxNonceSize, nonce_prefix_size_);
+}
+
+AeadBaseEncrypter::~AeadBaseEncrypter() {}
+
+bool AeadBaseEncrypter::SetKey(StringPiece key) {
+ DCHECK_EQ(key.size(), key_size_);
+ if (key.size() != key_size_) {
+ return false;
+ }
+ memcpy(key_, key.data(), key.size());
+
+ EVP_AEAD_CTX_cleanup(ctx_.get());
+
+ if (!EVP_AEAD_CTX_init(ctx_.get(), aead_alg_, key_, key_size_, auth_tag_size_,
+ nullptr)) {
+ DLogOpenSslErrors();
+ return false;
+ }
+
+ return true;
+}
+
+bool AeadBaseEncrypter::SetNoncePrefix(StringPiece nonce_prefix) {
+ DCHECK_EQ(nonce_prefix.size(), nonce_prefix_size_);
+ if (nonce_prefix.size() != nonce_prefix_size_) {
+ return false;
+ }
+ memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size());
+ return true;
+}
+
+bool AeadBaseEncrypter::Encrypt(StringPiece nonce,
+ StringPiece associated_data,
+ StringPiece plaintext,
+ unsigned char* output) {
+ if (nonce.size() != nonce_prefix_size_ + sizeof(QuicPacketNumber)) {
+ return false;
+ }
+
+ size_t ciphertext_len;
+ if (!EVP_AEAD_CTX_seal(
+ ctx_.get(), output, &ciphertext_len,
+ plaintext.size() + auth_tag_size_,
+ reinterpret_cast<const uint8_t*>(nonce.data()), nonce.size(),
+ reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size(),
+ reinterpret_cast<const uint8_t*>(associated_data.data()),
+ associated_data.size())) {
+ DLogOpenSslErrors();
+ return false;
+ }
+
+ return true;
+}
+
+bool AeadBaseEncrypter::EncryptPacket(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ StringPiece associated_data,
+ StringPiece plaintext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) {
+ size_t ciphertext_size = GetCiphertextSize(plaintext.length());
+ if (max_output_length < ciphertext_size) {
+ return false;
+ }
+ // TODO(ianswett): Introduce a check to ensure that we don't encrypt with the
+ // same packet number twice.
+ const size_t nonce_size = nonce_prefix_size_ + sizeof(packet_number);
+ ALIGNAS(4) char nonce_buffer[kMaxNonceSize];
+ memcpy(nonce_buffer, nonce_prefix_, nonce_prefix_size_);
+ uint64_t path_id_packet_number =
+ QuicUtils::PackPathIdAndPacketNumber(path_id, packet_number);
+ memcpy(nonce_buffer + nonce_prefix_size_, &path_id_packet_number,
+ sizeof(path_id_packet_number));
+
+ if (!Encrypt(StringPiece(nonce_buffer, nonce_size), associated_data,
+ plaintext, reinterpret_cast<unsigned char*>(output))) {
+ return false;
+ }
+ *output_length = ciphertext_size;
+ return true;
+}
+
+size_t AeadBaseEncrypter::GetKeySize() const {
+ return key_size_;
+}
+
+size_t AeadBaseEncrypter::GetNoncePrefixSize() const {
+ return nonce_prefix_size_;
+}
+
+size_t AeadBaseEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const {
+ return ciphertext_size - auth_tag_size_;
+}
+
+size_t AeadBaseEncrypter::GetCiphertextSize(size_t plaintext_size) const {
+ return plaintext_size + auth_tag_size_;
+}
+
+StringPiece AeadBaseEncrypter::GetKey() const {
+ return StringPiece(reinterpret_cast<const char*>(key_), key_size_);
+}
+
+StringPiece AeadBaseEncrypter::GetNoncePrefix() const {
+ if (nonce_prefix_size_ == 0) {
+ return StringPiece();
+ }
+ return StringPiece(reinterpret_cast<const char*>(nonce_prefix_),
+ nonce_prefix_size_);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/aead_base_encrypter.h b/chromium/net/quic/core/crypto/aead_base_encrypter.h
new file mode 100644
index 00000000000..4e2c68ad139
--- /dev/null
+++ b/chromium/net/quic/core/crypto/aead_base_encrypter.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2013 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_CRYPTO_AEAD_BASE_ENCRYPTER_H_
+#define NET_QUIC_CRYPTO_AEAD_BASE_ENCRYPTER_H_
+
+#include <stddef.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/crypto/scoped_evp_aead_ctx.h"
+
+namespace net {
+
+// AeadBaseEncrypter is the base class of AEAD QuicEncrypter subclasses.
+class NET_EXPORT_PRIVATE AeadBaseEncrypter : public QuicEncrypter {
+ public:
+ AeadBaseEncrypter(const EVP_AEAD* aead_alg,
+ size_t key_size,
+ size_t auth_tag_size,
+ size_t nonce_prefix_size);
+ ~AeadBaseEncrypter() override;
+
+ // QuicEncrypter implementation
+ bool SetKey(base::StringPiece key) override;
+ bool SetNoncePrefix(base::StringPiece nonce_prefix) override;
+ bool EncryptPacket(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ base::StringPiece associated_data,
+ base::StringPiece plaintext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) override;
+ size_t GetKeySize() const override;
+ size_t GetNoncePrefixSize() const override;
+ size_t GetMaxPlaintextSize(size_t ciphertext_size) const override;
+ size_t GetCiphertextSize(size_t plaintext_size) const override;
+ base::StringPiece GetKey() const override;
+ base::StringPiece GetNoncePrefix() const override;
+
+ // Necessary so unit tests can explicitly specify a nonce, instead of a
+ // nonce prefix and packet number.
+ bool Encrypt(base::StringPiece nonce,
+ base::StringPiece associated_data,
+ base::StringPiece plaintext,
+ unsigned char* output);
+
+ protected:
+ // Make these constants available to the subclasses so that the subclasses
+ // can assert at compile time their key_size_ and nonce_prefix_size_ do not
+ // exceed the maximum.
+ static const size_t kMaxKeySize = 32;
+ static const size_t kMaxNoncePrefixSize = 4;
+
+ private:
+ const EVP_AEAD* const aead_alg_;
+ const size_t key_size_;
+ const size_t auth_tag_size_;
+ const size_t nonce_prefix_size_;
+
+ // The key.
+ unsigned char key_[kMaxKeySize];
+ // The nonce prefix.
+ unsigned char nonce_prefix_[kMaxNoncePrefixSize];
+
+ ScopedEVPAEADCtx ctx_;
+
+ DISALLOW_COPY_AND_ASSIGN(AeadBaseEncrypter);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_AEAD_BASE_ENCRYPTER_H_
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
new file mode 100644
index 00000000000..a9eb9cb1730
--- /dev/null
+++ b/chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2013 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/crypto/aes_128_gcm_12_decrypter.h"
+
+#include <openssl/evp.h>
+#include <openssl/tls1.h>
+
+namespace net {
+
+namespace {
+
+const size_t kKeySize = 16;
+const size_t kNoncePrefixSize = 4;
+
+} // namespace
+
+Aes128Gcm12Decrypter::Aes128Gcm12Decrypter()
+ : AeadBaseDecrypter(EVP_aead_aes_128_gcm(),
+ kKeySize,
+ kAuthTagSize,
+ kNoncePrefixSize) {
+ static_assert(kKeySize <= kMaxKeySize, "key size too big");
+ static_assert(kNoncePrefixSize <= kMaxNoncePrefixSize,
+ "nonce prefix size too big");
+}
+
+Aes128Gcm12Decrypter::~Aes128Gcm12Decrypter() {}
+
+const char* Aes128Gcm12Decrypter::cipher_name() const {
+ return TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
+}
+
+uint32_t Aes128Gcm12Decrypter::cipher_id() const {
+ // This OpenSSL macro has the value 0x0300C02F. The two most significant bytes
+ // 0x0300 are OpenSSL specific and are NOT part of the TLS CipherSuite value
+ // for TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256.
+ return TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter.h b/chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter.h
new file mode 100644
index 00000000000..58d992b5508
--- /dev/null
+++ b/chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2013 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_CRYPTO_AES_128_GCM_12_DECRYPTER_H_
+#define NET_QUIC_CRYPTO_AES_128_GCM_12_DECRYPTER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/aead_base_decrypter.h"
+
+namespace net {
+
+// An Aes128Gcm12Decrypter is a QuicDecrypter that implements the
+// AEAD_AES_128_GCM_12 algorithm specified in RFC 5282. Create an instance by
+// calling QuicDecrypter::Create(kAESG).
+//
+// It uses an authentication tag of 12 bytes (96 bits). The fixed prefix
+// of the nonce is four bytes.
+class NET_EXPORT_PRIVATE Aes128Gcm12Decrypter : public AeadBaseDecrypter {
+ public:
+ enum {
+ // Authentication tags are truncated to 96 bits.
+ kAuthTagSize = 12,
+ };
+
+ Aes128Gcm12Decrypter();
+ ~Aes128Gcm12Decrypter() override;
+
+ const char* cipher_name() const override;
+ uint32_t cipher_id() const override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Aes128Gcm12Decrypter);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_AES_128_GCM_12_DECRYPTER_H_
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
new file mode 100644
index 00000000000..64e8f30bc10
--- /dev/null
+++ b/chromium/net/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
@@ -0,0 +1,287 @@
+// Copyright (c) 2013 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/crypto/aes_128_gcm_12_decrypter.h"
+
+#include <memory>
+
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace {
+
+// The AES GCM test vectors come from the file gcmDecrypt128.rsp
+// downloaded from http://csrc.nist.gov/groups/STM/cavp/index.html on
+// 2013-02-01. The test vectors in that file look like this:
+//
+// [Keylen = 128]
+// [IVlen = 96]
+// [PTlen = 0]
+// [AADlen = 0]
+// [Taglen = 128]
+//
+// Count = 0
+// Key = cf063a34d4a9a76c2c86787d3f96db71
+// IV = 113b9785971864c83b01c787
+// CT =
+// AAD =
+// Tag = 72ac8493e3a5228b5d130a69d2510e42
+// PT =
+//
+// Count = 1
+// Key = a49a5e26a2f8cb63d05546c2a62f5343
+// IV = 907763b19b9b4ab6bd4f0281
+// CT =
+// AAD =
+// Tag = a2be08210d8c470a8df6e8fbd79ec5cf
+// FAIL
+//
+// ...
+//
+// The gcmDecrypt128.rsp file is huge (2.6 MB), so I selected just a
+// few test vectors for this unit test.
+
+// Describes a group of test vectors that all have a given key length, IV
+// length, plaintext length, AAD length, and tag length.
+struct TestGroupInfo {
+ size_t key_len;
+ size_t iv_len;
+ size_t pt_len;
+ size_t aad_len;
+ size_t tag_len;
+};
+
+// Each test vector consists of six strings of lowercase hexadecimal digits.
+// The strings may be empty (zero length). A test vector with a nullptr |key|
+// marks the end of an array of test vectors.
+struct TestVector {
+ // Input:
+ const char* key;
+ const char* iv;
+ const char* ct;
+ const char* aad;
+ const char* tag;
+
+ // Expected output:
+ const char* pt; // An empty string "" means decryption succeeded and
+ // the plaintext is zero-length. nullptr means decryption
+ // failed.
+};
+
+const TestGroupInfo test_group_info[] = {
+ {128, 96, 0, 0, 128}, {128, 96, 0, 128, 128}, {128, 96, 128, 0, 128},
+ {128, 96, 408, 160, 128}, {128, 96, 408, 720, 128}, {128, 96, 104, 0, 128},
+};
+
+const TestVector test_group_0[] = {
+ {"cf063a34d4a9a76c2c86787d3f96db71", "113b9785971864c83b01c787", "", "",
+ "72ac8493e3a5228b5d130a69d2510e42", ""},
+ {
+ "a49a5e26a2f8cb63d05546c2a62f5343", "907763b19b9b4ab6bd4f0281", "", "",
+ "a2be08210d8c470a8df6e8fbd79ec5cf",
+ nullptr // FAIL
+ },
+ {nullptr}};
+
+const TestVector test_group_1[] = {
+ {
+ "d1f6af919cde85661208bdce0c27cb22", "898c6929b435017bf031c3c5", "",
+ "7c5faa40e636bbc91107e68010c92b9f", "ae45f11777540a2caeb128be8092468a",
+ nullptr // FAIL
+ },
+ {"2370e320d4344208e0ff5683f243b213", "04dbb82f044d30831c441228", "",
+ "d43a8e5089eea0d026c03a85178b27da", "2a049c049d25aa95969b451d93c31c6e",
+ ""},
+ {nullptr}};
+
+const TestVector test_group_2[] = {
+ {"e98b72a9881a84ca6b76e0f43e68647a", "8b23299fde174053f3d652ba",
+ "5a3c1cf1985dbb8bed818036fdd5ab42", "", "23c7ab0f952b7091cd324835043b5eb5",
+ "28286a321293253c3e0aa2704a278032"},
+ {"33240636cd3236165f1a553b773e728e", "17c4d61493ecdc8f31700b12",
+ "47bb7e23f7bdfe05a8091ac90e4f8b2e", "", "b723c70e931d9785f40fd4ab1d612dc9",
+ "95695a5b12f2870b9cc5fdc8f218a97d"},
+ {
+ "5164df856f1e9cac04a79b808dc5be39", "e76925d5355e0584ce871b2b",
+ "0216c899c88d6e32c958c7e553daa5bc", "",
+ "a145319896329c96df291f64efbe0e3a",
+ nullptr // FAIL
+ },
+ {nullptr}};
+
+const TestVector test_group_3[] = {
+ {"af57f42c60c0fc5a09adb81ab86ca1c3", "a2dc01871f37025dc0fc9a79",
+ "b9a535864f48ea7b6b1367914978f9bfa087d854bb0e269bed8d279d2eea1210e48947"
+ "338b22f9bad09093276a331e9c79c7f4",
+ "41dc38988945fcb44faf2ef72d0061289ef8efd8",
+ "4f71e72bde0018f555c5adcce062e005",
+ "3803a0727eeb0ade441e0ec107161ded2d425ec0d102f21f51bf2cf9947c7ec4aa7279"
+ "5b2f69b041596e8817d0a3c16f8fadeb"},
+ {"ebc753e5422b377d3cb64b58ffa41b61", "2e1821efaced9acf1f241c9b",
+ "069567190554e9ab2b50a4e1fbf9c147340a5025fdbd201929834eaf6532325899ccb9"
+ "f401823e04b05817243d2142a3589878",
+ "b9673412fd4f88ba0e920f46dd6438ff791d8eef",
+ "534d9234d2351cf30e565de47baece0b",
+ "39077edb35e9c5a4b1e4c2a6b9bb1fce77f00f5023af40333d6d699014c2bcf4209c18"
+ "353a18017f5b36bfc00b1f6dcb7ed485"},
+ {
+ "52bdbbf9cf477f187ec010589cb39d58", "d3be36d3393134951d324b31",
+ "700188da144fa692cf46e4a8499510a53d90903c967f7f13e8a1bd8151a74adc4fe63e"
+ "32b992760b3a5f99e9a47838867000a9",
+ "93c4fc6a4135f54d640b0c976bf755a06a292c33",
+ "8ca4e38aa3dfa6b1d0297021ccf3ea5f",
+ nullptr // FAIL
+ },
+ {nullptr}};
+
+const TestVector test_group_4[] = {
+ {"da2bb7d581493d692380c77105590201", "44aa3e7856ca279d2eb020c6",
+ "9290d430c9e89c37f0446dbd620c9a6b34b1274aeb6f911f75867efcf95b6feda69f1a"
+ "f4ee16c761b3c9aeac3da03aa9889c88",
+ "4cd171b23bddb3a53cdf959d5c1710b481eb3785a90eb20a2345ee00d0bb7868c367ab"
+ "12e6f4dd1dee72af4eee1d197777d1d6499cc541f34edbf45cda6ef90b3c024f9272d7"
+ "2ec1909fb8fba7db88a4d6f7d3d925980f9f9f72",
+ "9e3ac938d3eb0cadd6f5c9e35d22ba38",
+ "9bbf4c1a2742f6ac80cb4e8a052e4a8f4f07c43602361355b717381edf9fabd4cb7e3a"
+ "d65dbd1378b196ac270588dd0621f642"},
+ {"d74e4958717a9d5c0e235b76a926cae8", "0b7471141e0c70b1995fd7b1",
+ "e701c57d2330bf066f9ff8cf3ca4343cafe4894651cd199bdaaa681ba486b4a65c5a22"
+ "b0f1420be29ea547d42c713bc6af66aa",
+ "4a42b7aae8c245c6f1598a395316e4b8484dbd6e64648d5e302021b1d3fa0a38f46e22"
+ "bd9c8080b863dc0016482538a8562a4bd0ba84edbe2697c76fd039527ac179ec5506cf"
+ "34a6039312774cedebf4961f3978b14a26509f96",
+ "e192c23cb036f0b31592989119eed55d",
+ "840d9fb95e32559fb3602e48590280a172ca36d9b49ab69510f5bd552bfab7a306f85f"
+ "f0a34bc305b88b804c60b90add594a17"},
+ {
+ "1986310c725ac94ecfe6422e75fc3ee7", "93ec4214fa8e6dc4e3afc775",
+ "b178ec72f85a311ac4168f42a4b2c23113fbea4b85f4b9dabb74e143eb1b8b0a361e02"
+ "43edfd365b90d5b325950df0ada058f9",
+ "e80b88e62c49c958b5e0b8b54f532d9ff6aa84c8a40132e93e55b59fc24e8decf28463"
+ "139f155d1e8ce4ee76aaeefcd245baa0fc519f83a5fb9ad9aa40c4b21126013f576c42"
+ "72c2cb136c8fd091cc4539877a5d1e72d607f960",
+ "8b347853f11d75e81e8a95010be81f17",
+ nullptr // FAIL
+ },
+ {nullptr}};
+
+const TestVector test_group_5[] = {
+ {"387218b246c1a8257748b56980e50c94", "dd7e014198672be39f95b69d",
+ "cdba9e73eaf3d38eceb2b04a8d", "", "ecf90f4a47c9c626d6fb2c765d201556",
+ "48f5b426baca03064554cc2b30"},
+ {"294de463721e359863887c820524b3d4", "3338b35c9d57a5d28190e8c9",
+ "2f46634e74b8e4c89812ac83b9", "", "dabd506764e68b82a7e720aa18da0abe",
+ "46a2e55c8e264df211bd112685"},
+ {"28ead7fd2179e0d12aa6d5d88c58c2dc", "5055347f18b4d5add0ae5c41",
+ "142d8210c3fb84774cdbd0447a", "", "5fd321d9cdb01952dc85f034736c2a7d",
+ "3b95b981086ee73cc4d0cc1422"},
+ {
+ "7d7b6c988137b8d470c57bf674a09c87", "9edf2aa970d016ac962e1fd8",
+ "a85b66c3cb5eab91d5bdc8bc0e", "", "dc054efc01f3afd21d9c2484819f569a",
+ nullptr // FAIL
+ },
+ {nullptr}};
+
+const TestVector* const test_group_array[] = {
+ test_group_0, test_group_1, test_group_2,
+ test_group_3, test_group_4, test_group_5,
+};
+
+} // namespace
+
+namespace net {
+namespace test {
+
+// DecryptWithNonce wraps the |Decrypt| method of |decrypter| to allow passing
+// in an nonce and also to allocate the buffer needed for the plaintext.
+QuicData* DecryptWithNonce(Aes128Gcm12Decrypter* decrypter,
+ StringPiece nonce,
+ StringPiece associated_data,
+ StringPiece ciphertext) {
+ QuicPathId path_id = kDefaultPathId;
+ QuicPacketNumber packet_number;
+ StringPiece nonce_prefix(nonce.data(), nonce.size() - sizeof(packet_number));
+ decrypter->SetNoncePrefix(nonce_prefix);
+ memcpy(&packet_number, nonce.data() + nonce_prefix.size(),
+ sizeof(packet_number));
+ path_id = static_cast<QuicPathId>(
+ packet_number >> 8 * (sizeof(packet_number) - sizeof(path_id)));
+ packet_number &= UINT64_C(0x00FFFFFFFFFFFFFF);
+ std::unique_ptr<char[]> output(new char[ciphertext.length()]);
+ size_t output_length = 0;
+ const bool success = decrypter->DecryptPacket(
+ path_id, packet_number, associated_data, ciphertext, output.get(),
+ &output_length, ciphertext.length());
+ if (!success) {
+ return nullptr;
+ }
+ return new QuicData(output.release(), output_length, true);
+}
+
+TEST(Aes128Gcm12DecrypterTest, Decrypt) {
+ for (size_t i = 0; i < arraysize(test_group_array); i++) {
+ SCOPED_TRACE(i);
+ const TestVector* test_vectors = test_group_array[i];
+ const TestGroupInfo& test_info = test_group_info[i];
+ for (size_t j = 0; test_vectors[j].key != nullptr; j++) {
+ // If not present then decryption is expected to fail.
+ bool has_pt = test_vectors[j].pt;
+
+ // Decode the test vector.
+ string key = QuicUtils::HexDecode(test_vectors[j].key);
+ string iv = QuicUtils::HexDecode(test_vectors[j].iv);
+ string ct = QuicUtils::HexDecode(test_vectors[j].ct);
+ string aad = QuicUtils::HexDecode(test_vectors[j].aad);
+ string tag = QuicUtils::HexDecode(test_vectors[j].tag);
+ string pt;
+ if (has_pt) {
+ pt = QuicUtils::HexDecode(test_vectors[j].pt);
+ }
+
+ // The test vector's lengths should look sane. Note that the lengths
+ // in |test_info| are in bits.
+ EXPECT_EQ(test_info.key_len, key.length() * 8);
+ EXPECT_EQ(test_info.iv_len, iv.length() * 8);
+ EXPECT_EQ(test_info.pt_len, ct.length() * 8);
+ EXPECT_EQ(test_info.aad_len, aad.length() * 8);
+ EXPECT_EQ(test_info.tag_len, tag.length() * 8);
+ if (has_pt) {
+ EXPECT_EQ(test_info.pt_len, pt.length() * 8);
+ }
+
+ // The test vectors have 16 byte authenticators but this code only uses
+ // the first 12.
+ ASSERT_LE(static_cast<size_t>(Aes128Gcm12Decrypter::kAuthTagSize),
+ tag.length());
+ tag.resize(Aes128Gcm12Decrypter::kAuthTagSize);
+ string ciphertext = ct + tag;
+
+ Aes128Gcm12Decrypter decrypter;
+ ASSERT_TRUE(decrypter.SetKey(key));
+
+ std::unique_ptr<QuicData> decrypted(DecryptWithNonce(
+ &decrypter, iv,
+ // This deliberately tests that the decrypter can handle an AAD that
+ // is set to nullptr, as opposed to a zero-length, non-nullptr
+ // pointer.
+ aad.length() ? aad : StringPiece(), ciphertext));
+ if (!decrypted.get()) {
+ EXPECT_FALSE(has_pt);
+ continue;
+ }
+ EXPECT_TRUE(has_pt);
+
+ ASSERT_EQ(pt.length(), decrypted->length());
+ test::CompareCharArraysWithHexError("plaintext", decrypted->data(),
+ pt.length(), pt.data(), pt.length());
+ }
+ }
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/aes_128_gcm_12_encrypter.cc b/chromium/net/quic/core/crypto/aes_128_gcm_12_encrypter.cc
new file mode 100644
index 00000000000..50c24cbbc7f
--- /dev/null
+++ b/chromium/net/quic/core/crypto/aes_128_gcm_12_encrypter.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2013 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/crypto/aes_128_gcm_12_encrypter.h"
+
+#include <openssl/evp.h>
+
+namespace net {
+
+namespace {
+
+const size_t kKeySize = 16;
+const size_t kNoncePrefixSize = 4;
+
+} // namespace
+
+Aes128Gcm12Encrypter::Aes128Gcm12Encrypter()
+ : AeadBaseEncrypter(EVP_aead_aes_128_gcm(),
+ kKeySize,
+ kAuthTagSize,
+ kNoncePrefixSize) {
+ static_assert(kKeySize <= kMaxKeySize, "key size too big");
+ static_assert(kNoncePrefixSize <= kMaxNoncePrefixSize,
+ "nonce prefix size too big");
+}
+
+Aes128Gcm12Encrypter::~Aes128Gcm12Encrypter() {}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/aes_128_gcm_12_encrypter.h b/chromium/net/quic/core/crypto/aes_128_gcm_12_encrypter.h
new file mode 100644
index 00000000000..70b86237f5a
--- /dev/null
+++ b/chromium/net/quic/core/crypto/aes_128_gcm_12_encrypter.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2013 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_CRYPTO_AES_128_GCM_12_ENCRYPTER_H_
+#define NET_QUIC_CRYPTO_AES_128_GCM_12_ENCRYPTER_H_
+
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/aead_base_encrypter.h"
+
+namespace net {
+
+// An Aes128Gcm12Encrypter is a QuicEncrypter that implements the
+// AEAD_AES_128_GCM_12 algorithm specified in RFC 5282. Create an instance by
+// calling QuicEncrypter::Create(kAESG).
+//
+// It uses an authentication tag of 12 bytes (96 bits). The fixed prefix
+// of the nonce is four bytes.
+class NET_EXPORT_PRIVATE Aes128Gcm12Encrypter : public AeadBaseEncrypter {
+ public:
+ enum {
+ // Authentication tags are truncated to 96 bits.
+ kAuthTagSize = 12,
+ };
+
+ Aes128Gcm12Encrypter();
+ ~Aes128Gcm12Encrypter() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Aes128Gcm12Encrypter);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_AES_128_GCM_12_ENCRYPTER_H_
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
new file mode 100644
index 00000000000..037d90f77e0
--- /dev/null
+++ b/chromium/net/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc
@@ -0,0 +1,238 @@
+// Copyright (c) 2013 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/crypto/aes_128_gcm_12_encrypter.h"
+
+#include <memory>
+
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace {
+
+// The AES GCM test vectors come from the file gcmEncryptExtIV128.rsp
+// downloaded from http://csrc.nist.gov/groups/STM/cavp/index.html on
+// 2013-02-01. The test vectors in that file look like this:
+//
+// [Keylen = 128]
+// [IVlen = 96]
+// [PTlen = 0]
+// [AADlen = 0]
+// [Taglen = 128]
+//
+// Count = 0
+// Key = 11754cd72aec309bf52f7687212e8957
+// IV = 3c819d9a9bed087615030b65
+// PT =
+// AAD =
+// CT =
+// Tag = 250327c674aaf477aef2675748cf6971
+//
+// Count = 1
+// Key = ca47248ac0b6f8372a97ac43508308ed
+// IV = ffd2b598feabc9019262d2be
+// PT =
+// AAD =
+// CT =
+// Tag = 60d20404af527d248d893ae495707d1a
+//
+// ...
+//
+// The gcmEncryptExtIV128.rsp file is huge (2.8 MB), so I selected just a
+// few test vectors for this unit test.
+
+// Describes a group of test vectors that all have a given key length, IV
+// length, plaintext length, AAD length, and tag length.
+struct TestGroupInfo {
+ size_t key_len;
+ size_t iv_len;
+ size_t pt_len;
+ size_t aad_len;
+ size_t tag_len;
+};
+
+// Each test vector consists of six strings of lowercase hexadecimal digits.
+// The strings may be empty (zero length). A test vector with a nullptr |key|
+// marks the end of an array of test vectors.
+struct TestVector {
+ const char* key;
+ const char* iv;
+ const char* pt;
+ const char* aad;
+ const char* ct;
+ const char* tag;
+};
+
+const TestGroupInfo test_group_info[] = {
+ {128, 96, 0, 0, 128}, {128, 96, 0, 128, 128}, {128, 96, 128, 0, 128},
+ {128, 96, 408, 160, 128}, {128, 96, 408, 720, 128}, {128, 96, 104, 0, 128},
+};
+
+const TestVector test_group_0[] = {
+ {"11754cd72aec309bf52f7687212e8957", "3c819d9a9bed087615030b65", "", "", "",
+ "250327c674aaf477aef2675748cf6971"},
+ {"ca47248ac0b6f8372a97ac43508308ed", "ffd2b598feabc9019262d2be", "", "", "",
+ "60d20404af527d248d893ae495707d1a"},
+ {nullptr}};
+
+const TestVector test_group_1[] = {
+ {"77be63708971c4e240d1cb79e8d77feb", "e0e00f19fed7ba0136a797f3", "",
+ "7a43ec1d9c0a5a78a0b16533a6213cab", "",
+ "209fcc8d3675ed938e9c7166709dd946"},
+ {"7680c5d3ca6154758e510f4d25b98820", "f8f105f9c3df4965780321f8", "",
+ "c94c410194c765e3dcc7964379758ed3", "",
+ "94dca8edfcf90bb74b153c8d48a17930"},
+ {nullptr}};
+
+const TestVector test_group_2[] = {
+ {"7fddb57453c241d03efbed3ac44e371c", "ee283a3fc75575e33efd4887",
+ "d5de42b461646c255c87bd2962d3b9a2", "", "2ccda4a5415cb91e135c2a0f78c9b2fd",
+ "b36d1df9b9d5e596f83e8b7f52971cb3"},
+ {"ab72c77b97cb5fe9a382d9fe81ffdbed", "54cc7dc2c37ec006bcc6d1da",
+ "007c5e5b3e59df24a7c355584fc1518d", "", "0e1bde206a07a9c2c1b65300f8c64997",
+ "2b4401346697138c7a4891ee59867d0c"},
+ {nullptr}};
+
+const TestVector test_group_3[] = {
+ {"fe47fcce5fc32665d2ae399e4eec72ba", "5adb9609dbaeb58cbd6e7275",
+ "7c0e88c88899a779228465074797cd4c2e1498d259b54390b85e3eef1c02df60e743f1"
+ "b840382c4bccaf3bafb4ca8429bea063",
+ "88319d6e1d3ffa5f987199166c8a9b56c2aeba5a",
+ "98f4826f05a265e6dd2be82db241c0fbbbf9ffb1c173aa83964b7cf539304373636525"
+ "3ddbc5db8778371495da76d269e5db3e",
+ "291ef1982e4defedaa2249f898556b47"},
+ {"ec0c2ba17aa95cd6afffe949da9cc3a8", "296bce5b50b7d66096d627ef",
+ "b85b3753535b825cbe5f632c0b843c741351f18aa484281aebec2f45bb9eea2d79d987"
+ "b764b9611f6c0f8641843d5d58f3a242",
+ "f8d00f05d22bf68599bcdeb131292ad6e2df5d14",
+ "a7443d31c26bdf2a1c945e29ee4bd344a99cfaf3aa71f8b3f191f83c2adfc7a0716299"
+ "5506fde6309ffc19e716eddf1a828c5a",
+ "890147971946b627c40016da1ecf3e77"},
+ {nullptr}};
+
+const TestVector test_group_4[] = {
+ {"2c1f21cf0f6fb3661943155c3e3d8492", "23cb5ff362e22426984d1907",
+ "42f758836986954db44bf37c6ef5e4ac0adaf38f27252a1b82d02ea949c8a1a2dbc0d6"
+ "8b5615ba7c1220ff6510e259f06655d8",
+ "5d3624879d35e46849953e45a32a624d6a6c536ed9857c613b572b0333e701557a713e"
+ "3f010ecdf9a6bd6c9e3e44b065208645aff4aabee611b391528514170084ccf587177f"
+ "4488f33cfb5e979e42b6e1cfc0a60238982a7aec",
+ "81824f0e0d523db30d3da369fdc0d60894c7a0a20646dd015073ad2732bd989b14a222"
+ "b6ad57af43e1895df9dca2a5344a62cc",
+ "57a3ee28136e94c74838997ae9823f3a"},
+ {"d9f7d2411091f947b4d6f1e2d1f0fb2e", "e1934f5db57cc983e6b180e7",
+ "73ed042327f70fe9c572a61545eda8b2a0c6e1d6c291ef19248e973aee6c312012f490"
+ "c2c6f6166f4a59431e182663fcaea05a",
+ "0a8a18a7150e940c3d87b38e73baee9a5c049ee21795663e264b694a949822b639092d"
+ "0e67015e86363583fcf0ca645af9f43375f05fdb4ce84f411dcbca73c2220dea03a201"
+ "15d2e51398344b16bee1ed7c499b353d6c597af8",
+ "aaadbd5c92e9151ce3db7210b8714126b73e43436d242677afa50384f2149b831f1d57"
+ "3c7891c2a91fbc48db29967ec9542b23",
+ "21b51ca862cb637cdd03b99a0f93b134"},
+ {nullptr}};
+
+const TestVector test_group_5[] = {
+ {"fe9bb47deb3a61e423c2231841cfd1fb", "4d328eb776f500a2f7fb47aa",
+ "f1cc3818e421876bb6b8bbd6c9", "", "b88c5c1977b35b517b0aeae967",
+ "43fd4727fe5cdb4b5b42818dea7ef8c9"},
+ {"6703df3701a7f54911ca72e24dca046a", "12823ab601c350ea4bc2488c",
+ "793cd125b0b84a043e3ac67717", "", "b2051c80014f42f08735a7b0cd",
+ "38e6bcd29962e5f2c13626b85a877101"},
+ {nullptr}};
+
+const TestVector* const test_group_array[] = {
+ test_group_0, test_group_1, test_group_2,
+ test_group_3, test_group_4, test_group_5,
+};
+
+} // namespace
+
+namespace net {
+namespace test {
+
+// EncryptWithNonce wraps the |Encrypt| method of |encrypter| to allow passing
+// in an nonce and also to allocate the buffer needed for the ciphertext.
+QuicData* EncryptWithNonce(Aes128Gcm12Encrypter* encrypter,
+ StringPiece nonce,
+ StringPiece associated_data,
+ StringPiece plaintext) {
+ size_t ciphertext_size = encrypter->GetCiphertextSize(plaintext.length());
+ std::unique_ptr<char[]> ciphertext(new char[ciphertext_size]);
+
+ if (!encrypter->Encrypt(nonce, associated_data, plaintext,
+ reinterpret_cast<unsigned char*>(ciphertext.get()))) {
+ return nullptr;
+ }
+
+ return new QuicData(ciphertext.release(), ciphertext_size, true);
+}
+
+TEST(Aes128Gcm12EncrypterTest, Encrypt) {
+ for (size_t i = 0; i < arraysize(test_group_array); i++) {
+ SCOPED_TRACE(i);
+ const TestVector* test_vectors = test_group_array[i];
+ const TestGroupInfo& test_info = test_group_info[i];
+ for (size_t j = 0; test_vectors[j].key != nullptr; j++) {
+ // Decode the test vector.
+ string key = QuicUtils::HexDecode(test_vectors[j].key);
+ string iv = QuicUtils::HexDecode(test_vectors[j].iv);
+ string pt = QuicUtils::HexDecode(test_vectors[j].pt);
+ string aad = QuicUtils::HexDecode(test_vectors[j].aad);
+ string ct = QuicUtils::HexDecode(test_vectors[j].ct);
+ string tag = QuicUtils::HexDecode(test_vectors[j].tag);
+
+ // The test vector's lengths should look sane. Note that the lengths
+ // in |test_info| are in bits.
+ EXPECT_EQ(test_info.key_len, key.length() * 8);
+ EXPECT_EQ(test_info.iv_len, iv.length() * 8);
+ EXPECT_EQ(test_info.pt_len, pt.length() * 8);
+ EXPECT_EQ(test_info.aad_len, aad.length() * 8);
+ EXPECT_EQ(test_info.pt_len, ct.length() * 8);
+ EXPECT_EQ(test_info.tag_len, tag.length() * 8);
+
+ Aes128Gcm12Encrypter encrypter;
+ ASSERT_TRUE(encrypter.SetKey(key));
+ std::unique_ptr<QuicData> encrypted(EncryptWithNonce(
+ &encrypter, iv,
+ // This deliberately tests that the encrypter can handle an AAD that
+ // is set to nullptr, as opposed to a zero-length, non-nullptr
+ // pointer.
+ aad.length() ? aad : StringPiece(), pt));
+ ASSERT_TRUE(encrypted.get());
+
+ // The test vectors have 16 byte authenticators but this code only uses
+ // the first 12.
+ ASSERT_LE(static_cast<size_t>(Aes128Gcm12Encrypter::kAuthTagSize),
+ tag.length());
+ tag.resize(Aes128Gcm12Encrypter::kAuthTagSize);
+
+ ASSERT_EQ(ct.length() + tag.length(), encrypted->length());
+ test::CompareCharArraysWithHexError("ciphertext", encrypted->data(),
+ ct.length(), ct.data(), ct.length());
+ test::CompareCharArraysWithHexError(
+ "authentication tag", encrypted->data() + ct.length(), tag.length(),
+ tag.data(), tag.length());
+ }
+ }
+}
+
+TEST(Aes128Gcm12EncrypterTest, GetMaxPlaintextSize) {
+ Aes128Gcm12Encrypter encrypter;
+ EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1012));
+ EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(112));
+ EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(22));
+}
+
+TEST(Aes128Gcm12EncrypterTest, GetCiphertextSize) {
+ Aes128Gcm12Encrypter encrypter;
+ EXPECT_EQ(1012u, encrypter.GetCiphertextSize(1000));
+ EXPECT_EQ(112u, encrypter.GetCiphertextSize(100));
+ EXPECT_EQ(22u, encrypter.GetCiphertextSize(10));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/cert_compressor.cc b/chromium/net/quic/core/crypto/cert_compressor.cc
new file mode 100644
index 00000000000..40108267c31
--- /dev/null
+++ b/chromium/net/quic/core/crypto/cert_compressor.cc
@@ -0,0 +1,647 @@
+// Copyright (c) 2013 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/crypto/cert_compressor.h"
+
+#include <cstdint>
+#include <memory>
+
+#include "base/logging.h"
+#include "net/quic/core/quic_utils.h"
+#include "third_party/zlib/zlib.h"
+
+using base::StringPiece;
+using std::string;
+using std::vector;
+
+namespace net {
+
+namespace {
+
+// kCommonCertSubstrings contains ~1500 bytes of common certificate substrings
+// in order to help zlib. This was generated via a fairly dumb algorithm from
+// the Alexa Top 5000 set - we could probably do better.
+static const unsigned char kCommonCertSubstrings[] = {
+ 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04,
+ 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
+ 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30,
+ 0x5f, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01,
+ 0x06, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd, 0x6d, 0x01, 0x07,
+ 0x17, 0x01, 0x30, 0x33, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65,
+ 0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x20, 0x53, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x34,
+ 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+ 0x32, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72,
+ 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x30, 0x2d, 0x61, 0x69, 0x61, 0x2e,
+ 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x45, 0x2d, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73,
+ 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x45, 0x2e, 0x63, 0x65,
+ 0x72, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+ 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x4a, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73,
+ 0x2f, 0x63, 0x70, 0x73, 0x20, 0x28, 0x63, 0x29, 0x30, 0x30, 0x09, 0x06,
+ 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
+ 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x7b, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
+ 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd2,
+ 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x2e,
+ 0x63, 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
+ 0x04, 0x14, 0xb4, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69,
+ 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x30, 0x0b, 0x06, 0x03,
+ 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
+ 0x81, 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08,
+ 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30,
+ 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74,
+ 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03,
+ 0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x33,
+ 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x68, 0x74, 0x74,
+ 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+ 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74,
+ 0x6f, 0x72, 0x79, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x13, 0x27, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x53,
+ 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+ 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
+ 0x04, 0x05, 0x13, 0x08, 0x30, 0x37, 0x39, 0x36, 0x39, 0x32, 0x38, 0x37,
+ 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
+ 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0c,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00,
+ 0x30, 0x1d, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
+ 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
+ 0x03, 0x02, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
+ 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x33, 0x06, 0x03, 0x55, 0x1d,
+ 0x1f, 0x04, 0x2c, 0x30, 0x2a, 0x30, 0x28, 0xa0, 0x26, 0xa0, 0x24, 0x86,
+ 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e,
+ 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x67, 0x64, 0x73, 0x31, 0x2d, 0x32, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08,
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74,
+ 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65,
+ 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,
+ 0x70, 0x73, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17,
+ 0x0d, 0x31, 0x33, 0x30, 0x35, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01,
+ 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a,
+ 0x2f, 0x2f, 0x73, 0x30, 0x39, 0x30, 0x37, 0x06, 0x08, 0x2b, 0x06, 0x01,
+ 0x05, 0x05, 0x07, 0x02, 0x30, 0x44, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04,
+ 0x3d, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86,
+ 0xf8, 0x45, 0x01, 0x07, 0x17, 0x06, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x1b, 0x53, 0x31, 0x17,
+ 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72,
+ 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31,
+ 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, 0x65,
+ 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74,
+ 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3b, 0x30, 0x39,
+ 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x32, 0x54, 0x65, 0x72, 0x6d, 0x73,
+ 0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x65, 0x20, 0x61, 0x74, 0x20, 0x68,
+ 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76,
+ 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x72, 0x70, 0x61, 0x20, 0x28, 0x63, 0x29, 0x30, 0x31, 0x10, 0x30, 0x0e,
+ 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x53, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x47, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x3c, 0x02, 0x01,
+ 0x03, 0x13, 0x02, 0x55, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x14, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+ 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0f, 0x13, 0x14, 0x50,
+ 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x20, 0x4f, 0x72, 0x67, 0x61, 0x6e,
+ 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x12, 0x31, 0x21, 0x30,
+ 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x44, 0x6f, 0x6d, 0x61,
+ 0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, 0x56,
+ 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x31, 0x14, 0x31, 0x31,
+ 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x28, 0x53, 0x65, 0x65,
+ 0x20, 0x77, 0x77, 0x77, 0x2e, 0x72, 0x3a, 0x2f, 0x2f, 0x73, 0x65, 0x63,
+ 0x75, 0x72, 0x65, 0x2e, 0x67, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53,
+ 0x69, 0x67, 0x6e, 0x31, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x41,
+ 0x2e, 0x63, 0x72, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e,
+ 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x45, 0x63, 0x72,
+ 0x6c, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x73, 0x64, 0x31, 0x1a,
+ 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x3a,
+ 0x2f, 0x2f, 0x45, 0x56, 0x49, 0x6e, 0x74, 0x6c, 0x2d, 0x63, 0x63, 0x72,
+ 0x74, 0x2e, 0x67, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x69, 0x63, 0x65, 0x72,
+ 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x31, 0x6f, 0x63, 0x73, 0x70, 0x2e,
+ 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x30, 0x39, 0x72, 0x61, 0x70, 0x69, 0x64, 0x73, 0x73, 0x6c, 0x2e, 0x63,
+ 0x6f, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72,
+ 0x79, 0x2f, 0x30, 0x81, 0x80, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
+ 0x07, 0x01, 0x01, 0x04, 0x74, 0x30, 0x72, 0x30, 0x24, 0x06, 0x08, 0x2b,
+ 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74,
+ 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64,
+ 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x4a, 0x06,
+ 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x3e, 0x68,
+ 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64,
+ 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73,
+ 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x67, 0x64, 0x5f, 0x69, 0x6e, 0x74,
+ 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72,
+ 0x74, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0xfd, 0xac, 0x61, 0x32, 0x93, 0x6c, 0x45, 0xd6, 0xe2, 0xee,
+ 0x85, 0x5f, 0x9a, 0xba, 0xe7, 0x76, 0x99, 0x68, 0xcc, 0xe7, 0x30, 0x27,
+ 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x86, 0x30,
+ 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73,
+};
+
+// CertEntry represents a certificate in compressed form. Each entry is one of
+// the three types enumerated in |Type|.
+struct CertEntry {
+ public:
+ enum Type {
+ // Type 0 is reserved to mean "end of list" in the wire format.
+
+ // COMPRESSED means that the certificate is included in the trailing zlib
+ // data.
+ COMPRESSED = 1,
+ // CACHED means that the certificate is already known to the peer and will
+ // be replaced by its 64-bit hash (in |hash|).
+ CACHED = 2,
+ // COMMON means that the certificate is in a common certificate set known
+ // to the peer with hash |set_hash| and certificate index |index|.
+ COMMON = 3,
+ };
+
+ Type type;
+ uint64_t hash;
+ uint64_t set_hash;
+ uint32_t index;
+};
+
+// MatchCerts returns a vector of CertEntries describing how to most
+// efficiently represent |certs| to a peer who has the common sets identified
+// by |client_common_set_hashes| and who has cached the certificates with the
+// 64-bit, FNV-1a hashes in |client_cached_cert_hashes|.
+vector<CertEntry> MatchCerts(const vector<string>& certs,
+ StringPiece client_common_set_hashes,
+ StringPiece client_cached_cert_hashes,
+ const CommonCertSets* common_sets) {
+ vector<CertEntry> entries;
+ entries.reserve(certs.size());
+
+ const bool cached_valid =
+ client_cached_cert_hashes.size() % sizeof(uint64_t) == 0 &&
+ !client_cached_cert_hashes.empty();
+
+ for (vector<string>::const_iterator i = certs.begin(); i != certs.end();
+ ++i) {
+ CertEntry entry;
+
+ if (cached_valid) {
+ bool cached = false;
+
+ uint64_t hash = QuicUtils::FNV1a_64_Hash(i->data(), i->size());
+ // This assumes that the machine is little-endian.
+ for (size_t j = 0; j < client_cached_cert_hashes.size();
+ j += sizeof(uint64_t)) {
+ uint64_t cached_hash;
+ memcpy(&cached_hash, client_cached_cert_hashes.data() + j,
+ sizeof(uint64_t));
+ if (hash != cached_hash) {
+ continue;
+ }
+
+ entry.type = CertEntry::CACHED;
+ entry.hash = hash;
+ entries.push_back(entry);
+ cached = true;
+ break;
+ }
+
+ if (cached) {
+ continue;
+ }
+ }
+
+ if (common_sets &&
+ common_sets->MatchCert(*i, client_common_set_hashes, &entry.set_hash,
+ &entry.index)) {
+ entry.type = CertEntry::COMMON;
+ entries.push_back(entry);
+ continue;
+ }
+
+ entry.type = CertEntry::COMPRESSED;
+ entries.push_back(entry);
+ }
+
+ return entries;
+}
+
+// CertEntriesSize returns the size, in bytes, of the serialised form of
+// |entries|.
+size_t CertEntriesSize(const vector<CertEntry>& entries) {
+ size_t entries_size = 0;
+
+ for (vector<CertEntry>::const_iterator i = entries.begin();
+ i != entries.end(); ++i) {
+ entries_size++;
+ switch (i->type) {
+ case CertEntry::COMPRESSED:
+ break;
+ case CertEntry::CACHED:
+ entries_size += sizeof(uint64_t);
+ break;
+ case CertEntry::COMMON:
+ entries_size += sizeof(uint64_t) + sizeof(uint32_t);
+ break;
+ }
+ }
+
+ entries_size++; // for end marker
+
+ return entries_size;
+}
+
+// SerializeCertEntries serialises |entries| to |out|, which must have enough
+// space to contain them.
+void SerializeCertEntries(uint8_t* out, const vector<CertEntry>& entries) {
+ for (vector<CertEntry>::const_iterator i = entries.begin();
+ i != entries.end(); ++i) {
+ *out++ = static_cast<uint8_t>(i->type);
+ switch (i->type) {
+ case CertEntry::COMPRESSED:
+ break;
+ case CertEntry::CACHED:
+ memcpy(out, &i->hash, sizeof(i->hash));
+ out += sizeof(uint64_t);
+ break;
+ case CertEntry::COMMON:
+ // Assumes a little-endian machine.
+ memcpy(out, &i->set_hash, sizeof(i->set_hash));
+ out += sizeof(i->set_hash);
+ memcpy(out, &i->index, sizeof(uint32_t));
+ out += sizeof(uint32_t);
+ break;
+ }
+ }
+
+ *out++ = 0; // end marker
+}
+
+// ZlibDictForEntries returns a string that contains the zlib pre-shared
+// dictionary to use in order to decompress a zlib block following |entries|.
+// |certs| is one-to-one with |entries| and contains the certificates for those
+// entries that are CACHED or COMMON.
+string ZlibDictForEntries(const vector<CertEntry>& entries,
+ const vector<string>& certs) {
+ string zlib_dict;
+
+ // The dictionary starts with the common and cached certs in reverse order.
+ size_t zlib_dict_size = 0;
+ for (size_t i = certs.size() - 1; i < certs.size(); i--) {
+ if (entries[i].type != CertEntry::COMPRESSED) {
+ zlib_dict_size += certs[i].size();
+ }
+ }
+
+ // At the end of the dictionary is a block of common certificate substrings.
+ zlib_dict_size += sizeof(kCommonCertSubstrings);
+
+ zlib_dict.reserve(zlib_dict_size);
+
+ for (size_t i = certs.size() - 1; i < certs.size(); i--) {
+ if (entries[i].type != CertEntry::COMPRESSED) {
+ zlib_dict += certs[i];
+ }
+ }
+
+ zlib_dict += string(reinterpret_cast<const char*>(kCommonCertSubstrings),
+ sizeof(kCommonCertSubstrings));
+
+ DCHECK_EQ(zlib_dict.size(), zlib_dict_size);
+
+ return zlib_dict;
+}
+
+// HashCerts returns the FNV-1a hashes of |certs|.
+vector<uint64_t> HashCerts(const vector<string>& certs) {
+ vector<uint64_t> ret;
+ ret.reserve(certs.size());
+
+ for (vector<string>::const_iterator i = certs.begin(); i != certs.end();
+ ++i) {
+ ret.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size()));
+ }
+
+ return ret;
+}
+
+// ParseEntries parses the serialised form of a vector of CertEntries from
+// |in_out| and writes them to |out_entries|. CACHED and COMMON entries are
+// resolved using |cached_certs| and |common_sets| and written to |out_certs|.
+// |in_out| is updated to contain the trailing data.
+bool ParseEntries(StringPiece* in_out,
+ const vector<string>& cached_certs,
+ const CommonCertSets* common_sets,
+ vector<CertEntry>* out_entries,
+ vector<string>* out_certs) {
+ StringPiece in = *in_out;
+ vector<uint64_t> cached_hashes;
+
+ out_entries->clear();
+ out_certs->clear();
+
+ for (;;) {
+ if (in.empty()) {
+ return false;
+ }
+ CertEntry entry;
+ const uint8_t type_byte = in[0];
+ in.remove_prefix(1);
+
+ if (type_byte == 0) {
+ break;
+ }
+
+ entry.type = static_cast<CertEntry::Type>(type_byte);
+
+ switch (entry.type) {
+ case CertEntry::COMPRESSED:
+ out_certs->push_back(string());
+ break;
+ case CertEntry::CACHED: {
+ if (in.size() < sizeof(uint64_t)) {
+ return false;
+ }
+ memcpy(&entry.hash, in.data(), sizeof(uint64_t));
+ in.remove_prefix(sizeof(uint64_t));
+
+ if (cached_hashes.size() != cached_certs.size()) {
+ cached_hashes = HashCerts(cached_certs);
+ }
+ bool found = false;
+ for (size_t i = 0; i < cached_hashes.size(); i++) {
+ if (cached_hashes[i] == entry.hash) {
+ out_certs->push_back(cached_certs[i]);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return false;
+ }
+ break;
+ }
+ case CertEntry::COMMON: {
+ if (!common_sets) {
+ return false;
+ }
+ if (in.size() < sizeof(uint64_t) + sizeof(uint32_t)) {
+ return false;
+ }
+ memcpy(&entry.set_hash, in.data(), sizeof(uint64_t));
+ in.remove_prefix(sizeof(uint64_t));
+ memcpy(&entry.index, in.data(), sizeof(uint32_t));
+ in.remove_prefix(sizeof(uint32_t));
+
+ StringPiece cert = common_sets->GetCert(entry.set_hash, entry.index);
+ if (cert.empty()) {
+ return false;
+ }
+ out_certs->push_back(cert.as_string());
+ break;
+ }
+ default:
+ return false;
+ }
+ out_entries->push_back(entry);
+ }
+
+ *in_out = in;
+ return true;
+}
+
+// ScopedZLib deals with the automatic destruction of a zlib context.
+class ScopedZLib {
+ public:
+ enum Type {
+ INFLATE,
+ DEFLATE,
+ };
+
+ explicit ScopedZLib(Type type) : z_(nullptr), type_(type) {}
+
+ void reset(z_stream* z) {
+ Clear();
+ z_ = z;
+ }
+
+ ~ScopedZLib() { Clear(); }
+
+ private:
+ void Clear() {
+ if (!z_) {
+ return;
+ }
+
+ if (type_ == DEFLATE) {
+ deflateEnd(z_);
+ } else {
+ inflateEnd(z_);
+ }
+ z_ = nullptr;
+ }
+
+ z_stream* z_;
+ const Type type_;
+};
+
+} // anonymous namespace
+
+// static
+string CertCompressor::CompressChain(const vector<string>& certs,
+ StringPiece client_common_set_hashes,
+ StringPiece client_cached_cert_hashes,
+ const CommonCertSets* common_sets) {
+ const vector<CertEntry> entries = MatchCerts(
+ certs, client_common_set_hashes, client_cached_cert_hashes, common_sets);
+ DCHECK_EQ(entries.size(), certs.size());
+
+ size_t uncompressed_size = 0;
+ for (size_t i = 0; i < entries.size(); i++) {
+ if (entries[i].type == CertEntry::COMPRESSED) {
+ uncompressed_size += 4 /* uint32_t length */ + certs[i].size();
+ }
+ }
+
+ size_t compressed_size = 0;
+ z_stream z;
+ ScopedZLib scoped_z(ScopedZLib::DEFLATE);
+
+ if (uncompressed_size > 0) {
+ memset(&z, 0, sizeof(z));
+ int rv = deflateInit(&z, Z_DEFAULT_COMPRESSION);
+ DCHECK_EQ(Z_OK, rv);
+ if (rv != Z_OK) {
+ return "";
+ }
+ scoped_z.reset(&z);
+
+ string zlib_dict = ZlibDictForEntries(entries, certs);
+
+ rv = deflateSetDictionary(
+ &z, reinterpret_cast<const uint8_t*>(&zlib_dict[0]), zlib_dict.size());
+ DCHECK_EQ(Z_OK, rv);
+ if (rv != Z_OK) {
+ return "";
+ }
+
+ compressed_size = deflateBound(&z, uncompressed_size);
+ }
+
+ const size_t entries_size = CertEntriesSize(entries);
+
+ string result;
+ result.resize(entries_size + (uncompressed_size > 0 ? 4 : 0) +
+ compressed_size);
+
+ uint8_t* j = reinterpret_cast<uint8_t*>(&result[0]);
+ SerializeCertEntries(j, entries);
+ j += entries_size;
+
+ if (uncompressed_size == 0) {
+ return result;
+ }
+
+ uint32_t uncompressed_size_32 = uncompressed_size;
+ memcpy(j, &uncompressed_size_32, sizeof(uint32_t));
+ j += sizeof(uint32_t);
+
+ int rv;
+
+ z.next_out = j;
+ z.avail_out = compressed_size;
+
+ for (size_t i = 0; i < certs.size(); i++) {
+ if (entries[i].type != CertEntry::COMPRESSED) {
+ continue;
+ }
+
+ uint32_t length32 = certs[i].size();
+ z.next_in = reinterpret_cast<uint8_t*>(&length32);
+ z.avail_in = sizeof(length32);
+ rv = deflate(&z, Z_NO_FLUSH);
+ DCHECK_EQ(Z_OK, rv);
+ DCHECK_EQ(0u, z.avail_in);
+ if (rv != Z_OK || z.avail_in) {
+ return "";
+ }
+
+ z.next_in =
+ const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(certs[i].data()));
+ z.avail_in = certs[i].size();
+ rv = deflate(&z, Z_NO_FLUSH);
+ DCHECK_EQ(Z_OK, rv);
+ DCHECK_EQ(0u, z.avail_in);
+ if (rv != Z_OK || z.avail_in) {
+ return "";
+ }
+ }
+
+ z.avail_in = 0;
+ rv = deflate(&z, Z_FINISH);
+ DCHECK_EQ(Z_STREAM_END, rv);
+ if (rv != Z_STREAM_END) {
+ return "";
+ }
+
+ result.resize(result.size() - z.avail_out);
+ return result;
+}
+
+// static
+bool CertCompressor::DecompressChain(StringPiece in,
+ const vector<string>& cached_certs,
+ const CommonCertSets* common_sets,
+ vector<string>* out_certs) {
+ vector<CertEntry> entries;
+ if (!ParseEntries(&in, cached_certs, common_sets, &entries, out_certs)) {
+ return false;
+ }
+ DCHECK_EQ(entries.size(), out_certs->size());
+
+ std::unique_ptr<uint8_t[]> uncompressed_data;
+ StringPiece uncompressed;
+
+ if (!in.empty()) {
+ if (in.size() < sizeof(uint32_t)) {
+ return false;
+ }
+
+ uint32_t uncompressed_size;
+ memcpy(&uncompressed_size, in.data(), sizeof(uncompressed_size));
+ in.remove_prefix(sizeof(uint32_t));
+
+ if (uncompressed_size > 128 * 1024) {
+ return false;
+ }
+
+ uncompressed_data.reset(new uint8_t[uncompressed_size]);
+ z_stream z;
+ ScopedZLib scoped_z(ScopedZLib::INFLATE);
+
+ memset(&z, 0, sizeof(z));
+ z.next_out = uncompressed_data.get();
+ z.avail_out = uncompressed_size;
+ z.next_in =
+ const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(in.data()));
+ z.avail_in = in.size();
+
+ if (Z_OK != inflateInit(&z)) {
+ return false;
+ }
+ scoped_z.reset(&z);
+
+ int rv = inflate(&z, Z_FINISH);
+ if (rv == Z_NEED_DICT) {
+ string zlib_dict = ZlibDictForEntries(entries, *out_certs);
+ const uint8_t* dict = reinterpret_cast<const uint8_t*>(zlib_dict.data());
+ if (Z_OK != inflateSetDictionary(&z, dict, zlib_dict.size())) {
+ return false;
+ }
+ rv = inflate(&z, Z_FINISH);
+ }
+
+ if (Z_STREAM_END != rv || z.avail_out > 0 || z.avail_in > 0) {
+ return false;
+ }
+
+ uncompressed = StringPiece(reinterpret_cast<char*>(uncompressed_data.get()),
+ uncompressed_size);
+ }
+
+ for (size_t i = 0; i < entries.size(); i++) {
+ switch (entries[i].type) {
+ case CertEntry::COMPRESSED:
+ if (uncompressed.size() < sizeof(uint32_t)) {
+ return false;
+ }
+ uint32_t cert_len;
+ memcpy(&cert_len, uncompressed.data(), sizeof(cert_len));
+ uncompressed.remove_prefix(sizeof(uint32_t));
+ if (uncompressed.size() < cert_len) {
+ return false;
+ }
+ (*out_certs)[i] = uncompressed.substr(0, cert_len).as_string();
+ uncompressed.remove_prefix(cert_len);
+ break;
+ case CertEntry::CACHED:
+ case CertEntry::COMMON:
+ break;
+ }
+ }
+
+ if (!uncompressed.empty()) {
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/cert_compressor.h b/chromium/net/quic/core/crypto/cert_compressor.h
new file mode 100644
index 00000000000..f43df1a67ec
--- /dev/null
+++ b/chromium/net/quic/core/crypto/cert_compressor.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2013 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_CRYPTO_CERT_COMPRESSOR_H_
+#define NET_QUIC_CRYPTO_CERT_COMPRESSOR_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/common_cert_set.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+
+namespace net {
+
+// CertCompressor provides functions for compressing and decompressing
+// certificate chains using three techniquies:
+// 1) The peer may provide a list of a 64-bit, FNV-1a hashes of certificates
+// that they already have. In the event that one of them is to be
+// compressed, it can be replaced with just the hash.
+// 2) The peer may provide a number of hashes that represent sets of
+// pre-shared certificates (CommonCertSets). If one of those certificates
+// is to be compressed, and it's known to the given CommonCertSets, then it
+// can be replaced with a set hash and certificate index.
+// 3) Otherwise the certificates are compressed with zlib using a pre-shared
+// dictionary that consists of the certificates handled with the above
+// methods and a small chunk of common substrings.
+class NET_EXPORT_PRIVATE CertCompressor {
+ public:
+ // CompressChain compresses the certificates in |certs| and returns a
+ // compressed representation. |common_sets| contains the common certificate
+ // sets known locally and |client_common_set_hashes| contains the hashes of
+ // the common sets known to the peer. |client_cached_cert_hashes| contains
+ // 64-bit, FNV-1a hashes of certificates that the peer already possesses.
+ static std::string CompressChain(const std::vector<std::string>& certs,
+ base::StringPiece client_common_set_hashes,
+ base::StringPiece client_cached_cert_hashes,
+ const CommonCertSets* common_sets);
+
+ // DecompressChain decompresses the result of |CompressChain|, given in |in|,
+ // into a series of certificates that are written to |out_certs|.
+ // |cached_certs| contains certificates that the peer may have omitted and
+ // |common_sets| contains the common certificate sets known locally.
+ static bool DecompressChain(base::StringPiece in,
+ const std::vector<std::string>& cached_certs,
+ const CommonCertSets* common_sets,
+ std::vector<std::string>* out_certs);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CertCompressor);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CERT_COMPRESSOR_H_
diff --git a/chromium/net/quic/core/crypto/cert_compressor_test.cc b/chromium/net/quic/core/crypto/cert_compressor_test.cc
new file mode 100644
index 00000000000..dff6f10c48c
--- /dev/null
+++ b/chromium/net/quic/core/crypto/cert_compressor_test.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2013 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/crypto/cert_compressor.h"
+
+#include <memory>
+
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringPiece;
+using std::string;
+using std::vector;
+
+namespace net {
+namespace test {
+
+TEST(CertCompressor, EmptyChain) {
+ vector<string> chain;
+ const string compressed = CertCompressor::CompressChain(
+ chain, StringPiece(), StringPiece(), nullptr);
+ EXPECT_EQ("00", QuicUtils::HexEncode(compressed));
+
+ vector<string> chain2, cached_certs;
+ ASSERT_TRUE(CertCompressor::DecompressChain(compressed, cached_certs, nullptr,
+ &chain2));
+ EXPECT_EQ(chain.size(), chain2.size());
+}
+
+TEST(CertCompressor, Compressed) {
+ vector<string> chain;
+ chain.push_back("testcert");
+ const string compressed = CertCompressor::CompressChain(
+ chain, StringPiece(), StringPiece(), nullptr);
+ ASSERT_GE(compressed.size(), 2u);
+ EXPECT_EQ("0100", QuicUtils::HexEncode(compressed.substr(0, 2)));
+
+ vector<string> chain2, cached_certs;
+ ASSERT_TRUE(CertCompressor::DecompressChain(compressed, cached_certs, nullptr,
+ &chain2));
+ EXPECT_EQ(chain.size(), chain2.size());
+ EXPECT_EQ(chain[0], chain2[0]);
+}
+
+TEST(CertCompressor, Common) {
+ vector<string> chain;
+ chain.push_back("testcert");
+ static const uint64_t set_hash = 42;
+ std::unique_ptr<CommonCertSets> common_sets(
+ CryptoTestUtils::MockCommonCertSets(chain[0], set_hash, 1));
+ const string compressed = CertCompressor::CompressChain(
+ chain,
+ StringPiece(reinterpret_cast<const char*>(&set_hash), sizeof(set_hash)),
+ StringPiece(), common_sets.get());
+ EXPECT_EQ(
+ "03" /* common */
+ "2A00000000000000" /* set hash 42 */
+ "01000000" /* index 1 */
+ "00" /* end of list */,
+ QuicUtils::HexEncode(compressed));
+
+ vector<string> chain2, cached_certs;
+ ASSERT_TRUE(CertCompressor::DecompressChain(compressed, cached_certs,
+ common_sets.get(), &chain2));
+ EXPECT_EQ(chain.size(), chain2.size());
+ EXPECT_EQ(chain[0], chain2[0]);
+}
+
+TEST(CertCompressor, Cached) {
+ vector<string> chain;
+ chain.push_back("testcert");
+ uint64_t hash = QuicUtils::FNV1a_64_Hash(chain[0].data(), chain[0].size());
+ StringPiece hash_bytes(reinterpret_cast<char*>(&hash), sizeof(hash));
+ const string compressed =
+ CertCompressor::CompressChain(chain, StringPiece(), hash_bytes, nullptr);
+
+ EXPECT_EQ("02" /* cached */ + QuicUtils::HexEncode(hash_bytes) +
+ "00" /* end of list */,
+ QuicUtils::HexEncode(compressed));
+
+ vector<string> cached_certs, chain2;
+ cached_certs.push_back(chain[0]);
+ ASSERT_TRUE(CertCompressor::DecompressChain(compressed, cached_certs, nullptr,
+ &chain2));
+ EXPECT_EQ(chain.size(), chain2.size());
+ EXPECT_EQ(chain[0], chain2[0]);
+}
+
+TEST(CertCompressor, BadInputs) {
+ vector<string> cached_certs, chain;
+
+ EXPECT_FALSE(CertCompressor::DecompressChain(
+ QuicUtils::HexEncode("04") /* bad entry type */, cached_certs, nullptr,
+ &chain));
+
+ EXPECT_FALSE(CertCompressor::DecompressChain(
+ QuicUtils::HexEncode("01") /* no terminator */, cached_certs, nullptr,
+ &chain));
+
+ EXPECT_FALSE(CertCompressor::DecompressChain(
+ QuicUtils::HexEncode("0200") /* hash truncated */, cached_certs, nullptr,
+ &chain));
+
+ EXPECT_FALSE(CertCompressor::DecompressChain(
+ QuicUtils::HexEncode("0300") /* hash and index truncated */, cached_certs,
+ nullptr, &chain));
+
+ /* without a CommonCertSets */
+ EXPECT_FALSE(
+ CertCompressor::DecompressChain(QuicUtils::HexEncode("03"
+ "0000000000000000"
+ "00000000"),
+ cached_certs, nullptr, &chain));
+
+ std::unique_ptr<CommonCertSets> common_sets(
+ CryptoTestUtils::MockCommonCertSets("foo", 42, 1));
+
+ /* incorrect hash and index */
+ EXPECT_FALSE(
+ CertCompressor::DecompressChain(QuicUtils::HexEncode("03"
+ "a200000000000000"
+ "00000000"),
+ cached_certs, nullptr, &chain));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter.cc b/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter.cc
new file mode 100644
index 00000000000..302d105b50d
--- /dev/null
+++ b/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter.cc
@@ -0,0 +1,39 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/crypto/chacha20_poly1305_decrypter.h"
+
+#include <openssl/evp.h>
+#include <openssl/tls1.h>
+
+namespace net {
+
+namespace {
+
+const size_t kKeySize = 32;
+const size_t kNoncePrefixSize = 4;
+
+} // namespace
+
+ChaCha20Poly1305Decrypter::ChaCha20Poly1305Decrypter()
+ : AeadBaseDecrypter(EVP_aead_chacha20_poly1305(),
+ kKeySize,
+ kAuthTagSize,
+ kNoncePrefixSize) {
+ static_assert(kKeySize <= kMaxKeySize, "key size too big");
+ static_assert(kNoncePrefixSize <= kMaxNoncePrefixSize,
+ "nonce prefix size too big");
+}
+
+ChaCha20Poly1305Decrypter::~ChaCha20Poly1305Decrypter() {}
+
+const char* ChaCha20Poly1305Decrypter::cipher_name() const {
+ return TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305;
+}
+
+uint32_t ChaCha20Poly1305Decrypter::cipher_id() const {
+ return TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter.h b/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter.h
new file mode 100644
index 00000000000..0aa3568af88
--- /dev/null
+++ b/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter.h
@@ -0,0 +1,43 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CRYPTO_CHACHA20_POLY1305_DECRYPTER_H_
+#define NET_QUIC_CRYPTO_CHACHA20_POLY1305_DECRYPTER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/aead_base_decrypter.h"
+
+namespace net {
+
+// A ChaCha20Poly1305Decrypter is a QuicDecrypter that implements the
+// AEAD_CHACHA20_POLY1305 algorithm specified in
+// draft-agl-tls-chacha20poly1305-04, except that it truncates the Poly1305
+// authenticator to 12 bytes. Create an instance by calling
+// QuicDecrypter::Create(kCC12).
+//
+// It uses an authentication tag of 16 bytes (128 bits). There is no
+// fixed nonce prefix.
+class NET_EXPORT_PRIVATE ChaCha20Poly1305Decrypter : public AeadBaseDecrypter {
+ public:
+ enum {
+ kAuthTagSize = 12,
+ };
+
+ ChaCha20Poly1305Decrypter();
+ ~ChaCha20Poly1305Decrypter() override;
+
+ const char* cipher_name() const override;
+ uint32_t cipher_id() const override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ChaCha20Poly1305Decrypter);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CHACHA20_POLY1305_DECRYPTER_H_
diff --git a/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter_test.cc b/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
new file mode 100644
index 00000000000..a0ca47c72b1
--- /dev/null
+++ b/chromium/net/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
@@ -0,0 +1,177 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/crypto/chacha20_poly1305_decrypter.h"
+
+#include <memory>
+
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace {
+
+// The test vectors come from RFC 7539 Section 2.8.2.
+
+// Each test vector consists of six strings of lowercase hexadecimal digits.
+// The strings may be empty (zero length). A test vector with a nullptr |key|
+// marks the end of an array of test vectors.
+struct TestVector {
+ // Input:
+ const char* key;
+ const char* iv;
+ const char* fixed;
+ const char* aad;
+ const char* ct;
+
+ // Expected output:
+ const char* pt; // An empty string "" means decryption succeeded and
+ // the plaintext is zero-length. nullptr means decryption
+ // failed.
+};
+
+const TestVector test_vectors[] = {
+ {"808182838485868788898a8b8c8d8e8f"
+ "909192939495969798999a9b9c9d9e9f",
+
+ "4041424344454647",
+
+ "07000000",
+
+ "50515253c0c1c2c3c4c5c6c7",
+
+ "d31a8d34648e60db7b86afbc53ef7ec2"
+ "a4aded51296e08fea9e2b5a736ee62d6"
+ "3dbea45e8ca9671282fafb69da92728b"
+ "1a71de0a9e060b2905d6a5b67ecd3b36"
+ "92ddbd7f2d778b8c9803aee328091b58"
+ "fab324e4fad675945585808b4831d7bc"
+ "3ff4def08e4b7a9de576d26586cec64b"
+ "6116"
+ "1ae10b594f09e26a7e902ecb", // "d0600691" truncated
+
+ "4c616469657320616e642047656e746c"
+ "656d656e206f662074686520636c6173"
+ "73206f66202739393a20496620492063"
+ "6f756c64206f6666657220796f75206f"
+ "6e6c79206f6e652074697020666f7220"
+ "746865206675747572652c2073756e73"
+ "637265656e20776f756c642062652069"
+ "742e"},
+ // Modify the ciphertext (Poly1305 authenticator).
+ {"808182838485868788898a8b8c8d8e8f"
+ "909192939495969798999a9b9c9d9e9f",
+
+ "4041424344454647",
+
+ "07000000",
+
+ "50515253c0c1c2c3c4c5c6c7",
+
+ "d31a8d34648e60db7b86afbc53ef7ec2"
+ "a4aded51296e08fea9e2b5a736ee62d6"
+ "3dbea45e8ca9671282fafb69da92728b"
+ "1a71de0a9e060b2905d6a5b67ecd3b36"
+ "92ddbd7f2d778b8c9803aee328091b58"
+ "fab324e4fad675945585808b4831d7bc"
+ "3ff4def08e4b7a9de576d26586cec64b"
+ "6116"
+ "1ae10b594f09e26a7e902ecc", // "d0600691" truncated
+
+ nullptr},
+ // Modify the associated data.
+ {"808182838485868788898a8b8c8d8e8f"
+ "909192939495969798999a9b9c9d9e9f",
+
+ "4041424344454647",
+
+ "07000000",
+
+ "60515253c0c1c2c3c4c5c6c7",
+
+ "d31a8d34648e60db7b86afbc53ef7ec2"
+ "a4aded51296e08fea9e2b5a736ee62d6"
+ "3dbea45e8ca9671282fafb69da92728b"
+ "1a71de0a9e060b2905d6a5b67ecd3b36"
+ "92ddbd7f2d778b8c9803aee328091b58"
+ "fab324e4fad675945585808b4831d7bc"
+ "3ff4def08e4b7a9de576d26586cec64b"
+ "6116"
+ "1ae10b594f09e26a7e902ecb", // "d0600691" truncated
+
+ nullptr},
+ {nullptr}};
+
+} // namespace
+
+namespace net {
+namespace test {
+
+// DecryptWithNonce wraps the |Decrypt| method of |decrypter| to allow passing
+// in an nonce and also to allocate the buffer needed for the plaintext.
+QuicData* DecryptWithNonce(ChaCha20Poly1305Decrypter* decrypter,
+ StringPiece nonce,
+ StringPiece associated_data,
+ StringPiece ciphertext) {
+ QuicPathId path_id = kDefaultPathId;
+ QuicPacketNumber packet_number;
+ StringPiece nonce_prefix(nonce.data(), nonce.size() - sizeof(packet_number));
+ decrypter->SetNoncePrefix(nonce_prefix);
+ memcpy(&packet_number, nonce.data() + nonce_prefix.size(),
+ sizeof(packet_number));
+ path_id = static_cast<QuicPathId>(
+ packet_number >> 8 * (sizeof(packet_number) - sizeof(path_id)));
+ packet_number &= UINT64_C(0x00FFFFFFFFFFFFFF);
+ std::unique_ptr<char[]> output(new char[ciphertext.length()]);
+ size_t output_length = 0;
+ const bool success = decrypter->DecryptPacket(
+ path_id, packet_number, associated_data, ciphertext, output.get(),
+ &output_length, ciphertext.length());
+ if (!success) {
+ return nullptr;
+ }
+ return new QuicData(output.release(), output_length, true);
+}
+
+TEST(ChaCha20Poly1305DecrypterTest, Decrypt) {
+ for (size_t i = 0; test_vectors[i].key != nullptr; i++) {
+ // If not present then decryption is expected to fail.
+ bool has_pt = test_vectors[i].pt;
+
+ // Decode the test vector.
+ string key = QuicUtils::HexDecode(test_vectors[i].key);
+ string iv = QuicUtils::HexDecode(test_vectors[i].iv);
+ string fixed = QuicUtils::HexDecode(test_vectors[i].fixed);
+ string aad = QuicUtils::HexDecode(test_vectors[i].aad);
+ string ct = QuicUtils::HexDecode(test_vectors[i].ct);
+ string pt;
+ if (has_pt) {
+ pt = QuicUtils::HexDecode(test_vectors[i].pt);
+ }
+
+ ChaCha20Poly1305Decrypter decrypter;
+ ASSERT_TRUE(decrypter.SetKey(key));
+ std::unique_ptr<QuicData> decrypted(DecryptWithNonce(
+ &decrypter, fixed + iv,
+ // This deliberately tests that the decrypter can handle an AAD that
+ // is set to nullptr, as opposed to a zero-length, non-nullptr pointer.
+ StringPiece(aad.length() ? aad.data() : nullptr, aad.length()), ct));
+ if (!decrypted.get()) {
+ EXPECT_FALSE(has_pt);
+ continue;
+ }
+ EXPECT_TRUE(has_pt);
+
+ EXPECT_EQ(12u, ct.size() - decrypted->length());
+ ASSERT_EQ(pt.length(), decrypted->length());
+ test::CompareCharArraysWithHexError("plaintext", decrypted->data(),
+ pt.length(), pt.data(), pt.length());
+ }
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/chacha20_poly1305_encrypter.cc b/chromium/net/quic/core/crypto/chacha20_poly1305_encrypter.cc
new file mode 100644
index 00000000000..3a796226aea
--- /dev/null
+++ b/chromium/net/quic/core/crypto/chacha20_poly1305_encrypter.cc
@@ -0,0 +1,30 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/crypto/chacha20_poly1305_encrypter.h"
+
+#include <openssl/evp.h>
+
+namespace net {
+
+namespace {
+
+const size_t kKeySize = 32;
+const size_t kNoncePrefixSize = 4;
+
+} // namespace
+
+ChaCha20Poly1305Encrypter::ChaCha20Poly1305Encrypter()
+ : AeadBaseEncrypter(EVP_aead_chacha20_poly1305(),
+ kKeySize,
+ kAuthTagSize,
+ kNoncePrefixSize) {
+ static_assert(kKeySize <= kMaxKeySize, "key size too big");
+ static_assert(kNoncePrefixSize <= kMaxNoncePrefixSize,
+ "nonce prefix size too big");
+}
+
+ChaCha20Poly1305Encrypter::~ChaCha20Poly1305Encrypter() {}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/chacha20_poly1305_encrypter.h b/chromium/net/quic/core/crypto/chacha20_poly1305_encrypter.h
new file mode 100644
index 00000000000..8f3eaa7dc3b
--- /dev/null
+++ b/chromium/net/quic/core/crypto/chacha20_poly1305_encrypter.h
@@ -0,0 +1,39 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CRYPTO_CHACHA20_POLY1305_ENCRYPTER_H_
+#define NET_QUIC_CRYPTO_CHACHA20_POLY1305_ENCRYPTER_H_
+
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/aead_base_encrypter.h"
+
+namespace net {
+
+// A ChaCha20Poly1305Encrypter is a QuicEncrypter that implements the
+// AEAD_CHACHA20_POLY1305 algorithm specified in
+// draft-agl-tls-chacha20poly1305-04, except that it truncates the Poly1305
+// authenticator to 12 bytes. Create an instance by calling
+// QuicEncrypter::Create(kCC12).
+//
+// It uses an authentication tag of 16 bytes (128 bits). There is no
+// fixed nonce prefix.
+class NET_EXPORT_PRIVATE ChaCha20Poly1305Encrypter : public AeadBaseEncrypter {
+ public:
+ enum {
+ kAuthTagSize = 12,
+ };
+
+ ChaCha20Poly1305Encrypter();
+ ~ChaCha20Poly1305Encrypter() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ChaCha20Poly1305Encrypter);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CHACHA20_POLY1305_ENCRYPTER_H_
diff --git a/chromium/net/quic/core/crypto/chacha20_poly1305_encrypter_test.cc b/chromium/net/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
new file mode 100644
index 00000000000..863be3111d6
--- /dev/null
+++ b/chromium/net/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
@@ -0,0 +1,154 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/crypto/chacha20_poly1305_encrypter.h"
+
+#include <memory>
+
+#include "net/quic/core/crypto/chacha20_poly1305_decrypter.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace {
+
+// The test vectors come from RFC 7539 Section 2.8.2.
+
+// Each test vector consists of five strings of lowercase hexadecimal digits.
+// The strings may be empty (zero length). A test vector with a nullptr |key|
+// marks the end of an array of test vectors.
+struct TestVector {
+ const char* key;
+ const char* pt;
+ const char* iv;
+ const char* fixed;
+ const char* aad;
+ const char* ct;
+};
+
+const TestVector test_vectors[] = {
+ {
+ "808182838485868788898a8b8c8d8e8f"
+ "909192939495969798999a9b9c9d9e9f",
+
+ "4c616469657320616e642047656e746c"
+ "656d656e206f662074686520636c6173"
+ "73206f66202739393a20496620492063"
+ "6f756c64206f6666657220796f75206f"
+ "6e6c79206f6e652074697020666f7220"
+ "746865206675747572652c2073756e73"
+ "637265656e20776f756c642062652069"
+ "742e",
+
+ "4041424344454647",
+
+ "07000000",
+
+ "50515253c0c1c2c3c4c5c6c7",
+
+ "d31a8d34648e60db7b86afbc53ef7ec2"
+ "a4aded51296e08fea9e2b5a736ee62d6"
+ "3dbea45e8ca9671282fafb69da92728b"
+ "1a71de0a9e060b2905d6a5b67ecd3b36"
+ "92ddbd7f2d778b8c9803aee328091b58"
+ "fab324e4fad675945585808b4831d7bc"
+ "3ff4def08e4b7a9de576d26586cec64b"
+ "6116"
+ "1ae10b594f09e26a7e902ecb", // "d0600691" truncated
+ },
+ {nullptr}};
+
+} // namespace
+
+namespace net {
+namespace test {
+
+// EncryptWithNonce wraps the |Encrypt| method of |encrypter| to allow passing
+// in an nonce and also to allocate the buffer needed for the ciphertext.
+QuicData* EncryptWithNonce(ChaCha20Poly1305Encrypter* encrypter,
+ StringPiece nonce,
+ StringPiece associated_data,
+ StringPiece plaintext) {
+ size_t ciphertext_size = encrypter->GetCiphertextSize(plaintext.length());
+ std::unique_ptr<char[]> ciphertext(new char[ciphertext_size]);
+
+ if (!encrypter->Encrypt(nonce, associated_data, plaintext,
+ reinterpret_cast<unsigned char*>(ciphertext.get()))) {
+ return nullptr;
+ }
+
+ return new QuicData(ciphertext.release(), ciphertext_size, true);
+}
+
+TEST(ChaCha20Poly1305EncrypterTest, EncryptThenDecrypt) {
+ ChaCha20Poly1305Encrypter encrypter;
+ ChaCha20Poly1305Decrypter decrypter;
+
+ string key = QuicUtils::HexDecode(test_vectors[0].key);
+ ASSERT_TRUE(encrypter.SetKey(key));
+ ASSERT_TRUE(decrypter.SetKey(key));
+ ASSERT_TRUE(encrypter.SetNoncePrefix("abcd"));
+ ASSERT_TRUE(decrypter.SetNoncePrefix("abcd"));
+
+ QuicPathId path_id = 0x42;
+ QuicPacketNumber packet_number = UINT64_C(0x123456789ABC);
+ string associated_data = "associated_data";
+ string plaintext = "plaintext";
+ char encrypted[1024];
+ size_t len;
+ ASSERT_TRUE(encrypter.EncryptPacket(path_id, packet_number, associated_data,
+ plaintext, encrypted, &len,
+ arraysize(encrypted)));
+ StringPiece ciphertext(encrypted, len);
+ char decrypted[1024];
+ ASSERT_TRUE(decrypter.DecryptPacket(path_id, packet_number, associated_data,
+ ciphertext, decrypted, &len,
+ arraysize(decrypted)));
+}
+
+TEST(ChaCha20Poly1305EncrypterTest, Encrypt) {
+ for (size_t i = 0; test_vectors[i].key != nullptr; i++) {
+ // Decode the test vector.
+ string key = QuicUtils::HexDecode(test_vectors[i].key);
+ string pt = QuicUtils::HexDecode(test_vectors[i].pt);
+ string iv = QuicUtils::HexDecode(test_vectors[i].iv);
+ string fixed = QuicUtils::HexDecode(test_vectors[i].fixed);
+ string aad = QuicUtils::HexDecode(test_vectors[i].aad);
+ string ct = QuicUtils::HexDecode(test_vectors[i].ct);
+
+ ChaCha20Poly1305Encrypter encrypter;
+ ASSERT_TRUE(encrypter.SetKey(key));
+ std::unique_ptr<QuicData> encrypted(EncryptWithNonce(
+ &encrypter, fixed + iv,
+ // This deliberately tests that the encrypter can handle an AAD that
+ // is set to nullptr, as opposed to a zero-length, non-nullptr pointer.
+ StringPiece(aad.length() ? aad.data() : nullptr, aad.length()), pt));
+ ASSERT_TRUE(encrypted.get());
+ EXPECT_EQ(12u, ct.size() - pt.size());
+ EXPECT_EQ(12u, encrypted->length() - pt.size());
+
+ test::CompareCharArraysWithHexError("ciphertext", encrypted->data(),
+ encrypted->length(), ct.data(),
+ ct.length());
+ }
+}
+
+TEST(ChaCha20Poly1305EncrypterTest, GetMaxPlaintextSize) {
+ ChaCha20Poly1305Encrypter encrypter;
+ EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1012));
+ EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(112));
+ EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(22));
+}
+
+TEST(ChaCha20Poly1305EncrypterTest, GetCiphertextSize) {
+ ChaCha20Poly1305Encrypter encrypter;
+ EXPECT_EQ(1012u, encrypter.GetCiphertextSize(1000));
+ EXPECT_EQ(112u, encrypter.GetCiphertextSize(100));
+ EXPECT_EQ(22u, encrypter.GetCiphertextSize(10));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/channel_id.cc b/chromium/net/quic/core/crypto/channel_id.cc
new file mode 100644
index 00000000000..0d989c84e5f
--- /dev/null
+++ b/chromium/net/quic/core/crypto/channel_id.cc
@@ -0,0 +1,91 @@
+// Copyright 2013 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/crypto/channel_id.h"
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+#include <openssl/obj_mac.h>
+#include <openssl/sha.h>
+
+#include "crypto/openssl_util.h"
+#include "crypto/scoped_openssl_types.h"
+
+using base::StringPiece;
+
+namespace net {
+
+// static
+const char ChannelIDVerifier::kContextStr[] = "QUIC ChannelID";
+// static
+const char ChannelIDVerifier::kClientToServerStr[] = "client -> server";
+
+// static
+bool ChannelIDVerifier::Verify(StringPiece key,
+ StringPiece signed_data,
+ StringPiece signature) {
+ return VerifyRaw(key, signed_data, signature, true);
+}
+
+// static
+bool ChannelIDVerifier::VerifyRaw(StringPiece key,
+ StringPiece signed_data,
+ StringPiece signature,
+ bool is_channel_id_signature) {
+ if (key.size() != 32 * 2 || signature.size() != 32 * 2) {
+ return false;
+ }
+
+ crypto::ScopedEC_GROUP p256(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+ if (!p256) {
+ return false;
+ }
+
+ crypto::ScopedBIGNUM x(BN_new()), y(BN_new()), r(BN_new()), s(BN_new());
+
+ ECDSA_SIG sig;
+ sig.r = r.get();
+ sig.s = s.get();
+
+ const uint8_t* key_bytes = reinterpret_cast<const uint8_t*>(key.data());
+ const uint8_t* signature_bytes =
+ reinterpret_cast<const uint8_t*>(signature.data());
+
+ if (BN_bin2bn(key_bytes + 0, 32, x.get()) == nullptr ||
+ BN_bin2bn(key_bytes + 32, 32, y.get()) == nullptr ||
+ BN_bin2bn(signature_bytes + 0, 32, sig.r) == nullptr ||
+ BN_bin2bn(signature_bytes + 32, 32, sig.s) == nullptr) {
+ return false;
+ }
+
+ crypto::ScopedEC_POINT point(EC_POINT_new(p256.get()));
+ if (!point ||
+ !EC_POINT_set_affine_coordinates_GFp(p256.get(), point.get(), x.get(),
+ y.get(), nullptr)) {
+ return false;
+ }
+
+ crypto::ScopedEC_KEY ecdsa_key(EC_KEY_new());
+ if (ecdsa_key.get() == nullptr ||
+ !EC_KEY_set_group(ecdsa_key.get(), p256.get()) ||
+ !EC_KEY_set_public_key(ecdsa_key.get(), point.get())) {
+ return false;
+ }
+
+ SHA256_CTX sha256;
+ SHA256_Init(&sha256);
+ if (is_channel_id_signature) {
+ SHA256_Update(&sha256, kContextStr, strlen(kContextStr) + 1);
+ SHA256_Update(&sha256, kClientToServerStr, strlen(kClientToServerStr) + 1);
+ }
+ SHA256_Update(&sha256, signed_data.data(), signed_data.size());
+
+ unsigned char digest[SHA256_DIGEST_LENGTH];
+ SHA256_Final(digest, &sha256);
+
+ return ECDSA_do_verify(digest, sizeof(digest), &sig, ecdsa_key.get()) == 1;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/channel_id.h b/chromium/net/quic/core/crypto/channel_id.h
new file mode 100644
index 00000000000..571f7410c90
--- /dev/null
+++ b/chromium/net/quic/core/crypto/channel_id.h
@@ -0,0 +1,99 @@
+// Copyright 2013 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_CRYPTO_CHANNEL_ID_H_
+#define NET_QUIC_CRYPTO_CHANNEL_ID_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_types.h"
+
+namespace net {
+
+// ChannelIDKey is an interface that supports signing with and serializing a
+// ChannelID key.
+class NET_EXPORT_PRIVATE ChannelIDKey {
+ public:
+ virtual ~ChannelIDKey() {}
+
+ // Sign signs |signed_data| using the ChannelID private key and puts the
+ // signature into |out_signature|. It returns true on success.
+ virtual bool Sign(base::StringPiece signed_data,
+ std::string* out_signature) const = 0;
+
+ // SerializeKey returns the serialized ChannelID public key.
+ virtual std::string SerializeKey() const = 0;
+};
+
+// ChannelIDSourceCallback provides a generic mechanism for a ChannelIDSource
+// to call back after an asynchronous GetChannelIDKey operation.
+class ChannelIDSourceCallback {
+ public:
+ virtual ~ChannelIDSourceCallback() {}
+
+ // Run is called on the original thread to mark the completion of an
+ // asynchonous GetChannelIDKey operation. If |*channel_id_key| is not nullptr
+ // then the channel ID lookup is successful. |Run| may take ownership of
+ // |*channel_id_key| by calling |release| on it.
+ virtual void Run(std::unique_ptr<ChannelIDKey>* channel_id_key) = 0;
+};
+
+// ChannelIDSource is an abstract interface by which a QUIC client can obtain
+// a ChannelIDKey for a given hostname.
+class NET_EXPORT_PRIVATE ChannelIDSource {
+ public:
+ virtual ~ChannelIDSource() {}
+
+ // GetChannelIDKey looks up the ChannelIDKey for |hostname|. On success it
+ // returns QUIC_SUCCESS and stores the ChannelIDKey in |*channel_id_key|,
+ // which the caller takes ownership of. On failure, it returns QUIC_FAILURE.
+ //
+ // This function may also return QUIC_PENDING, in which case the
+ // ChannelIDSource will call back, on the original thread, via |callback|
+ // when complete. In this case, the ChannelIDSource will take ownership of
+ // |callback|.
+ virtual QuicAsyncStatus GetChannelIDKey(
+ const std::string& hostname,
+ std::unique_ptr<ChannelIDKey>* channel_id_key,
+ ChannelIDSourceCallback* callback) = 0;
+};
+
+// ChannelIDVerifier verifies ChannelID signatures.
+class NET_EXPORT_PRIVATE ChannelIDVerifier {
+ public:
+ // kContextStr is prepended to the data to be signed in order to ensure that
+ // a ChannelID signature cannot be used in a different context. (The
+ // terminating NUL byte is inclued.)
+ static const char kContextStr[];
+ // kClientToServerStr follows kContextStr to specify that the ChannelID is
+ // being used in the client to server direction. (The terminating NUL byte is
+ // included.)
+ static const char kClientToServerStr[];
+
+ // Verify returns true iff |signature| is a valid signature of |signed_data|
+ // by |key|.
+ static bool Verify(base::StringPiece key,
+ base::StringPiece signed_data,
+ base::StringPiece signature);
+
+ // FOR TESTING ONLY: VerifyRaw returns true iff |signature| is a valid
+ // signature of |signed_data| by |key|. |is_channel_id_signature| indicates
+ // whether |signature| is a ChannelID signature (with kContextStr prepended
+ // to the data to be signed).
+ static bool VerifyRaw(base::StringPiece key,
+ base::StringPiece signed_data,
+ base::StringPiece signature,
+ bool is_channel_id_signature);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ChannelIDVerifier);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CHANNEL_ID_H_
diff --git a/chromium/net/quic/core/crypto/channel_id_test.cc b/chromium/net/quic/core/crypto/channel_id_test.cc
new file mode 100644
index 00000000000..2b364d460b4
--- /dev/null
+++ b/chromium/net/quic/core/crypto/channel_id_test.cc
@@ -0,0 +1,274 @@
+// Copyright 2013 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/crypto/channel_id.h"
+
+#include <memory>
+
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+namespace test {
+
+namespace {
+
+// The following ECDSA signature verification test vectors for P-256,SHA-256
+// come from the SigVer.rsp file in
+// http://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip
+// downloaded on 2013-06-11.
+struct TestVector {
+ // Input:
+ const char* msg;
+ const char* qx;
+ const char* qy;
+ const char* r;
+ const char* s;
+
+ // Expected output:
+ bool result; // true means "P", false means "F"
+};
+
+const TestVector test_vector[] = {
+ {
+ "e4796db5f785f207aa30d311693b3702821dff1168fd2e04c0836825aefd850d"
+ "9aa60326d88cde1a23c7745351392ca2288d632c264f197d05cd424a30336c19"
+ "fd09bb229654f0222fcb881a4b35c290a093ac159ce13409111ff0358411133c"
+ "24f5b8e2090d6db6558afc36f06ca1f6ef779785adba68db27a409859fc4c4a0",
+ "87f8f2b218f49845f6f10eec3877136269f5c1a54736dbdf69f89940cad41555",
+ "e15f369036f49842fac7a86c8a2b0557609776814448b8f5e84aa9f4395205e9",
+ "d19ff48b324915576416097d2544f7cbdf8768b1454ad20e0baac50e211f23b0",
+ "a3e81e59311cdfff2d4784949f7a2cb50ba6c3a91fa54710568e61aca3e847c6",
+ false // F (3 - S changed)
+ },
+ {
+ "069a6e6b93dfee6df6ef6997cd80dd2182c36653cef10c655d524585655462d6"
+ "83877f95ecc6d6c81623d8fac4e900ed0019964094e7de91f1481989ae187300"
+ "4565789cbf5dc56c62aedc63f62f3b894c9c6f7788c8ecaadc9bd0e81ad91b2b"
+ "3569ea12260e93924fdddd3972af5273198f5efda0746219475017557616170e",
+ "5cf02a00d205bdfee2016f7421807fc38ae69e6b7ccd064ee689fc1a94a9f7d2",
+ "ec530ce3cc5c9d1af463f264d685afe2b4db4b5828d7e61b748930f3ce622a85",
+ "dc23d130c6117fb5751201455e99f36f59aba1a6a21cf2d0e7481a97451d6693",
+ "d6ce7708c18dbf35d4f8aa7240922dc6823f2e7058cbc1484fcad1599db5018c",
+ false // F (2 - R changed)
+ },
+ {
+ "df04a346cf4d0e331a6db78cca2d456d31b0a000aa51441defdb97bbeb20b94d"
+ "8d746429a393ba88840d661615e07def615a342abedfa4ce912e562af7149598"
+ "96858af817317a840dcff85a057bb91a3c2bf90105500362754a6dd321cdd861"
+ "28cfc5f04667b57aa78c112411e42da304f1012d48cd6a7052d7de44ebcc01de",
+ "2ddfd145767883ffbb0ac003ab4a44346d08fa2570b3120dcce94562422244cb",
+ "5f70c7d11ac2b7a435ccfbbae02c3df1ea6b532cc0e9db74f93fffca7c6f9a64",
+ "9913111cff6f20c5bf453a99cd2c2019a4e749a49724a08774d14e4c113edda8",
+ "9467cd4cd21ecb56b0cab0a9a453b43386845459127a952421f5c6382866c5cc",
+ false // F (4 - Q changed)
+ },
+ {
+ "e1130af6a38ccb412a9c8d13e15dbfc9e69a16385af3c3f1e5da954fd5e7c45f"
+ "d75e2b8c36699228e92840c0562fbf3772f07e17f1add56588dd45f7450e1217"
+ "ad239922dd9c32695dc71ff2424ca0dec1321aa47064a044b7fe3c2b97d03ce4"
+ "70a592304c5ef21eed9f93da56bb232d1eeb0035f9bf0dfafdcc4606272b20a3",
+ "e424dc61d4bb3cb7ef4344a7f8957a0c5134e16f7a67c074f82e6e12f49abf3c",
+ "970eed7aa2bc48651545949de1dddaf0127e5965ac85d1243d6f60e7dfaee927",
+ "bf96b99aa49c705c910be33142017c642ff540c76349b9dab72f981fd9347f4f",
+ "17c55095819089c2e03b9cd415abdf12444e323075d98f31920b9e0f57ec871c",
+ true // P (0 )
+ },
+ {
+ "73c5f6a67456ae48209b5f85d1e7de7758bf235300c6ae2bdceb1dcb27a7730f"
+ "b68c950b7fcada0ecc4661d3578230f225a875e69aaa17f1e71c6be5c831f226"
+ "63bac63d0c7a9635edb0043ff8c6f26470f02a7bc56556f1437f06dfa27b487a"
+ "6c4290d8bad38d4879b334e341ba092dde4e4ae694a9c09302e2dbf443581c08",
+ "e0fc6a6f50e1c57475673ee54e3a57f9a49f3328e743bf52f335e3eeaa3d2864",
+ "7f59d689c91e463607d9194d99faf316e25432870816dde63f5d4b373f12f22a",
+ "1d75830cd36f4c9aa181b2c4221e87f176b7f05b7c87824e82e396c88315c407",
+ "cb2acb01dac96efc53a32d4a0d85d0c2e48955214783ecf50a4f0414a319c05a",
+ true // P (0 )
+ },
+ {
+ "666036d9b4a2426ed6585a4e0fd931a8761451d29ab04bd7dc6d0c5b9e38e6c2"
+ "b263ff6cb837bd04399de3d757c6c7005f6d7a987063cf6d7e8cb38a4bf0d74a"
+ "282572bd01d0f41e3fd066e3021575f0fa04f27b700d5b7ddddf50965993c3f9"
+ "c7118ed78888da7cb221849b3260592b8e632d7c51e935a0ceae15207bedd548",
+ "a849bef575cac3c6920fbce675c3b787136209f855de19ffe2e8d29b31a5ad86",
+ "bf5fe4f7858f9b805bd8dcc05ad5e7fb889de2f822f3d8b41694e6c55c16b471",
+ "25acc3aa9d9e84c7abf08f73fa4195acc506491d6fc37cb9074528a7db87b9d6",
+ "9b21d5b5259ed3f2ef07dfec6cc90d3a37855d1ce122a85ba6a333f307d31537",
+ false // F (2 - R changed)
+ },
+ {
+ "7e80436bce57339ce8da1b5660149a20240b146d108deef3ec5da4ae256f8f89"
+ "4edcbbc57b34ce37089c0daa17f0c46cd82b5a1599314fd79d2fd2f446bd5a25"
+ "b8e32fcf05b76d644573a6df4ad1dfea707b479d97237a346f1ec632ea5660ef"
+ "b57e8717a8628d7f82af50a4e84b11f21bdff6839196a880ae20b2a0918d58cd",
+ "3dfb6f40f2471b29b77fdccba72d37c21bba019efa40c1c8f91ec405d7dcc5df",
+ "f22f953f1e395a52ead7f3ae3fc47451b438117b1e04d613bc8555b7d6e6d1bb",
+ "548886278e5ec26bed811dbb72db1e154b6f17be70deb1b210107decb1ec2a5a",
+ "e93bfebd2f14f3d827ca32b464be6e69187f5edbd52def4f96599c37d58eee75",
+ false // F (4 - Q changed)
+ },
+ {
+ "1669bfb657fdc62c3ddd63269787fc1c969f1850fb04c933dda063ef74a56ce1"
+ "3e3a649700820f0061efabf849a85d474326c8a541d99830eea8131eaea584f2"
+ "2d88c353965dabcdc4bf6b55949fd529507dfb803ab6b480cd73ca0ba00ca19c"
+ "438849e2cea262a1c57d8f81cd257fb58e19dec7904da97d8386e87b84948169",
+ "69b7667056e1e11d6caf6e45643f8b21e7a4bebda463c7fdbc13bc98efbd0214",
+ "d3f9b12eb46c7c6fda0da3fc85bc1fd831557f9abc902a3be3cb3e8be7d1aa2f",
+ "288f7a1cd391842cce21f00e6f15471c04dc182fe4b14d92dc18910879799790",
+ "247b3c4e89a3bcadfea73c7bfd361def43715fa382b8c3edf4ae15d6e55e9979",
+ false // F (1 - Message changed)
+ },
+ {
+ "3fe60dd9ad6caccf5a6f583b3ae65953563446c4510b70da115ffaa0ba04c076"
+ "115c7043ab8733403cd69c7d14c212c655c07b43a7c71b9a4cffe22c2684788e"
+ "c6870dc2013f269172c822256f9e7cc674791bf2d8486c0f5684283e1649576e"
+ "fc982ede17c7b74b214754d70402fb4bb45ad086cf2cf76b3d63f7fce39ac970",
+ "bf02cbcf6d8cc26e91766d8af0b164fc5968535e84c158eb3bc4e2d79c3cc682",
+ "069ba6cb06b49d60812066afa16ecf7b51352f2c03bd93ec220822b1f3dfba03",
+ "f5acb06c59c2b4927fb852faa07faf4b1852bbb5d06840935e849c4d293d1bad",
+ "049dab79c89cc02f1484c437f523e080a75f134917fda752f2d5ca397addfe5d",
+ false // F (3 - S changed)
+ },
+ {
+ "983a71b9994d95e876d84d28946a041f8f0a3f544cfcc055496580f1dfd4e312"
+ "a2ad418fe69dbc61db230cc0c0ed97e360abab7d6ff4b81ee970a7e97466acfd"
+ "9644f828ffec538abc383d0e92326d1c88c55e1f46a668a039beaa1be631a891"
+ "29938c00a81a3ae46d4aecbf9707f764dbaccea3ef7665e4c4307fa0b0a3075c",
+ "224a4d65b958f6d6afb2904863efd2a734b31798884801fcab5a590f4d6da9de",
+ "178d51fddada62806f097aa615d33b8f2404e6b1479f5fd4859d595734d6d2b9",
+ "87b93ee2fecfda54deb8dff8e426f3c72c8864991f8ec2b3205bb3b416de93d2",
+ "4044a24df85be0cc76f21a4430b75b8e77b932a87f51e4eccbc45c263ebf8f66",
+ false // F (2 - R changed)
+ },
+ {
+ "4a8c071ac4fd0d52faa407b0fe5dab759f7394a5832127f2a3498f34aac28733"
+ "9e043b4ffa79528faf199dc917f7b066ad65505dab0e11e6948515052ce20cfd"
+ "b892ffb8aa9bf3f1aa5be30a5bbe85823bddf70b39fd7ebd4a93a2f75472c1d4"
+ "f606247a9821f1a8c45a6cb80545de2e0c6c0174e2392088c754e9c8443eb5af",
+ "43691c7795a57ead8c5c68536fe934538d46f12889680a9cb6d055a066228369",
+ "f8790110b3c3b281aa1eae037d4f1234aff587d903d93ba3af225c27ddc9ccac",
+ "8acd62e8c262fa50dd9840480969f4ef70f218ebf8ef9584f199031132c6b1ce",
+ "cfca7ed3d4347fb2a29e526b43c348ae1ce6c60d44f3191b6d8ea3a2d9c92154",
+ false // F (3 - S changed)
+ },
+ {
+ "0a3a12c3084c865daf1d302c78215d39bfe0b8bf28272b3c0b74beb4b7409db0"
+ "718239de700785581514321c6440a4bbaea4c76fa47401e151e68cb6c29017f0"
+ "bce4631290af5ea5e2bf3ed742ae110b04ade83a5dbd7358f29a85938e23d87a"
+ "c8233072b79c94670ff0959f9c7f4517862ff829452096c78f5f2e9a7e4e9216",
+ "9157dbfcf8cf385f5bb1568ad5c6e2a8652ba6dfc63bc1753edf5268cb7eb596",
+ "972570f4313d47fc96f7c02d5594d77d46f91e949808825b3d31f029e8296405",
+ "dfaea6f297fa320b707866125c2a7d5d515b51a503bee817de9faa343cc48eeb",
+ "8f780ad713f9c3e5a4f7fa4c519833dfefc6a7432389b1e4af463961f09764f2",
+ false // F (1 - Message changed)
+ },
+ {
+ "785d07a3c54f63dca11f5d1a5f496ee2c2f9288e55007e666c78b007d95cc285"
+ "81dce51f490b30fa73dc9e2d45d075d7e3a95fb8a9e1465ad191904124160b7c"
+ "60fa720ef4ef1c5d2998f40570ae2a870ef3e894c2bc617d8a1dc85c3c557749"
+ "28c38789b4e661349d3f84d2441a3b856a76949b9f1f80bc161648a1cad5588e",
+ "072b10c081a4c1713a294f248aef850e297991aca47fa96a7470abe3b8acfdda",
+ "9581145cca04a0fb94cedce752c8f0370861916d2a94e7c647c5373ce6a4c8f5",
+ "09f5483eccec80f9d104815a1be9cc1a8e5b12b6eb482a65c6907b7480cf4f19",
+ "a4f90e560c5e4eb8696cb276e5165b6a9d486345dedfb094a76e8442d026378d",
+ false // F (4 - Q changed)
+ },
+ {
+ "76f987ec5448dd72219bd30bf6b66b0775c80b394851a43ff1f537f140a6e722"
+ "9ef8cd72ad58b1d2d20298539d6347dd5598812bc65323aceaf05228f738b5ad"
+ "3e8d9fe4100fd767c2f098c77cb99c2992843ba3eed91d32444f3b6db6cd212d"
+ "d4e5609548f4bb62812a920f6e2bf1581be1ebeebdd06ec4e971862cc42055ca",
+ "09308ea5bfad6e5adf408634b3d5ce9240d35442f7fe116452aaec0d25be8c24",
+ "f40c93e023ef494b1c3079b2d10ef67f3170740495ce2cc57f8ee4b0618b8ee5",
+ "5cc8aa7c35743ec0c23dde88dabd5e4fcd0192d2116f6926fef788cddb754e73",
+ "9c9c045ebaa1b828c32f82ace0d18daebf5e156eb7cbfdc1eff4399a8a900ae7",
+ false // F (1 - Message changed)
+ },
+ {
+ "60cd64b2cd2be6c33859b94875120361a24085f3765cb8b2bf11e026fa9d8855"
+ "dbe435acf7882e84f3c7857f96e2baab4d9afe4588e4a82e17a78827bfdb5ddb"
+ "d1c211fbc2e6d884cddd7cb9d90d5bf4a7311b83f352508033812c776a0e00c0"
+ "03c7e0d628e50736c7512df0acfa9f2320bd102229f46495ae6d0857cc452a84",
+ "2d98ea01f754d34bbc3003df5050200abf445ec728556d7ed7d5c54c55552b6d",
+ "9b52672742d637a32add056dfd6d8792f2a33c2e69dafabea09b960bc61e230a",
+ "06108e525f845d0155bf60193222b3219c98e3d49424c2fb2a0987f825c17959",
+ "62b5cdd591e5b507e560167ba8f6f7cda74673eb315680cb89ccbc4eec477dce",
+ true // P (0 )
+ },
+ {nullptr}};
+
+} // namespace
+
+// A known answer test for ChannelIDVerifier.
+TEST(ChannelIDTest, VerifyKnownAnswerTest) {
+ string msg;
+ string qx;
+ string qy;
+ string r;
+ string s;
+
+ for (size_t i = 0; test_vector[i].msg != nullptr; i++) {
+ SCOPED_TRACE(i);
+ // Decode the test vector.
+ ASSERT_TRUE(DecodeHexString(test_vector[i].msg, &msg));
+ ASSERT_TRUE(DecodeHexString(test_vector[i].qx, &qx));
+ ASSERT_TRUE(DecodeHexString(test_vector[i].qy, &qy));
+ ASSERT_TRUE(DecodeHexString(test_vector[i].r, &r));
+ ASSERT_TRUE(DecodeHexString(test_vector[i].s, &s));
+
+ string key = qx + qy;
+ string signature = r + s;
+
+ // The test vector's lengths should look sane.
+ EXPECT_EQ(32u, qx.size());
+ EXPECT_EQ(32u, qy.size());
+ EXPECT_EQ(32u, r.size());
+ EXPECT_EQ(32u, s.size());
+
+ EXPECT_EQ(test_vector[i].result,
+ ChannelIDVerifier::VerifyRaw(key, msg, signature, false));
+ }
+}
+
+TEST(ChannelIDTest, SignAndVerify) {
+ std::unique_ptr<ChannelIDSource> source(
+ CryptoTestUtils::ChannelIDSourceForTesting());
+
+ const string signed_data = "signed data";
+ const string hostname = "foo.example.com";
+ std::unique_ptr<ChannelIDKey> channel_id_key;
+ QuicAsyncStatus status =
+ source->GetChannelIDKey(hostname, &channel_id_key, nullptr);
+ ASSERT_EQ(QUIC_SUCCESS, status);
+
+ string signature;
+ ASSERT_TRUE(channel_id_key->Sign(signed_data, &signature));
+
+ string key = channel_id_key->SerializeKey();
+ EXPECT_TRUE(ChannelIDVerifier::Verify(key, signed_data, signature));
+
+ EXPECT_FALSE(ChannelIDVerifier::Verify("a" + key, signed_data, signature));
+ EXPECT_FALSE(ChannelIDVerifier::Verify(key, "a" + signed_data, signature));
+
+ std::unique_ptr<char[]> bad_key(new char[key.size()]);
+ memcpy(bad_key.get(), key.data(), key.size());
+ bad_key[1] ^= 0x80;
+ EXPECT_FALSE(ChannelIDVerifier::Verify(string(bad_key.get(), key.size()),
+ signed_data, signature));
+
+ std::unique_ptr<char[]> bad_signature(new char[signature.size()]);
+ memcpy(bad_signature.get(), signature.data(), signature.size());
+ bad_signature[1] ^= 0x80;
+ EXPECT_FALSE(ChannelIDVerifier::Verify(
+ key, signed_data, string(bad_signature.get(), signature.size())));
+
+ EXPECT_FALSE(ChannelIDVerifier::Verify(key, "wrong signed data", signature));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/common_cert_set.cc b/chromium/net/quic/core/crypto/common_cert_set.cc
new file mode 100644
index 00000000000..5b68b63a5fe
--- /dev/null
+++ b/chromium/net/quic/core/crypto/common_cert_set.cc
@@ -0,0 +1,168 @@
+// Copyright (c) 2013 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/crypto/common_cert_set.h"
+
+#include <cstddef>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/singleton.h"
+#include "net/quic/core/quic_utils.h"
+
+using base::StringPiece;
+
+namespace net {
+
+namespace common_cert_set_2 {
+#include "net/quic/core/crypto/common_cert_set_2.c"
+}
+
+namespace common_cert_set_3 {
+#include "net/quic/core/crypto/common_cert_set_3.c"
+}
+
+namespace {
+
+struct CertSet {
+ // num_certs contains the number of certificates in this set.
+ size_t num_certs;
+ // certs is an array of |num_certs| pointers to the DER encoded certificates.
+ const unsigned char* const* certs;
+ // lens is an array of |num_certs| integers describing the length, in bytes,
+ // of each certificate.
+ const size_t* lens;
+ // hash contains the 64-bit, FNV-1a hash of this set.
+ uint64_t hash;
+};
+
+const CertSet kSets[] = {
+ {
+ common_cert_set_2::kNumCerts, common_cert_set_2::kCerts,
+ common_cert_set_2::kLens, common_cert_set_2::kHash,
+ },
+ {
+ common_cert_set_3::kNumCerts, common_cert_set_3::kCerts,
+ common_cert_set_3::kLens, common_cert_set_3::kHash,
+ },
+};
+
+const uint64_t kSetHashes[] = {
+ common_cert_set_2::kHash, common_cert_set_3::kHash,
+};
+
+// Compare returns a value less than, equal to or greater than zero if |a| is
+// lexicographically less than, equal to or greater than |b|, respectively.
+int Compare(StringPiece a, const unsigned char* b, size_t b_len) {
+ size_t len = a.size();
+ if (len > b_len) {
+ len = b_len;
+ }
+ int n = memcmp(a.data(), b, len);
+ if (n != 0) {
+ return n;
+ }
+
+ if (a.size() < b_len) {
+ return -1;
+ } else if (a.size() > b_len) {
+ return 1;
+ }
+ return 0;
+}
+
+// CommonCertSetsQUIC implements the CommonCertSets interface using the default
+// certificate sets.
+class CommonCertSetsQUIC : public CommonCertSets {
+ public:
+ // CommonCertSets interface.
+ StringPiece GetCommonHashes() const override {
+ return StringPiece(reinterpret_cast<const char*>(kSetHashes),
+ sizeof(uint64_t) * arraysize(kSetHashes));
+ }
+
+ StringPiece GetCert(uint64_t hash, uint32_t index) const override {
+ for (size_t i = 0; i < arraysize(kSets); i++) {
+ if (kSets[i].hash == hash) {
+ if (index < kSets[i].num_certs) {
+ return StringPiece(
+ reinterpret_cast<const char*>(kSets[i].certs[index]),
+ kSets[i].lens[index]);
+ }
+ break;
+ }
+ }
+
+ return StringPiece();
+ }
+
+ bool MatchCert(StringPiece cert,
+ StringPiece common_set_hashes,
+ uint64_t* out_hash,
+ uint32_t* out_index) const override {
+ if (common_set_hashes.size() % sizeof(uint64_t) != 0) {
+ return false;
+ }
+
+ for (size_t i = 0; i < common_set_hashes.size() / sizeof(uint64_t); i++) {
+ uint64_t hash;
+ memcpy(&hash, common_set_hashes.data() + i * sizeof(uint64_t),
+ sizeof(uint64_t));
+
+ for (size_t j = 0; j < arraysize(kSets); j++) {
+ if (kSets[j].hash != hash) {
+ continue;
+ }
+
+ if (kSets[j].num_certs == 0) {
+ continue;
+ }
+
+ // Binary search for a matching certificate.
+ size_t min = 0;
+ size_t max = kSets[j].num_certs - 1;
+ while (max >= min) {
+ size_t mid = min + ((max - min) / 2);
+ int n = Compare(cert, kSets[j].certs[mid], kSets[j].lens[mid]);
+ if (n < 0) {
+ if (mid == 0) {
+ break;
+ }
+ max = mid - 1;
+ } else if (n > 0) {
+ min = mid + 1;
+ } else {
+ *out_hash = hash;
+ *out_index = mid;
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ static CommonCertSetsQUIC* GetInstance() {
+ return base::Singleton<CommonCertSetsQUIC>::get();
+ }
+
+ private:
+ CommonCertSetsQUIC() {}
+ ~CommonCertSetsQUIC() override {}
+
+ friend struct base::DefaultSingletonTraits<CommonCertSetsQUIC>;
+ DISALLOW_COPY_AND_ASSIGN(CommonCertSetsQUIC);
+};
+
+} // anonymous namespace
+
+CommonCertSets::~CommonCertSets() {}
+
+// static
+const CommonCertSets* CommonCertSets::GetInstanceQUIC() {
+ return CommonCertSetsQUIC::GetInstance();
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/common_cert_set.h b/chromium/net/quic/core/crypto/common_cert_set.h
new file mode 100644
index 00000000000..9ff622bd221
--- /dev/null
+++ b/chromium/net/quic/core/crypto/common_cert_set.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2013 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_CRYPTO_COMMON_CERT_SET_H_
+#define NET_QUIC_CRYPTO_COMMON_CERT_SET_H_
+
+#include <cstdint>
+
+#include "base/compiler_specific.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+
+namespace net {
+
+// CommonCertSets is an interface to an object that contains a number of common
+// certificate sets and can match against them.
+class NET_EXPORT_PRIVATE CommonCertSets {
+ public:
+ virtual ~CommonCertSets();
+
+ // GetInstanceQUIC returns the standard QUIC common certificate sets.
+ static const CommonCertSets* GetInstanceQUIC();
+
+ // GetCommonHashes returns a StringPiece containing the hashes of common sets
+ // supported by this object. The 64-bit hashes are concatenated in the
+ // StringPiece.
+ virtual base::StringPiece GetCommonHashes() const = 0;
+
+ // GetCert returns a specific certificate (at index |index|) in the common
+ // set identified by |hash|. If no such certificate is known, an empty
+ // StringPiece is returned.
+ virtual base::StringPiece GetCert(uint64_t hash, uint32_t index) const = 0;
+
+ // MatchCert tries to find |cert| in one of the common certificate sets
+ // identified by |common_set_hashes|. On success it puts the hash of the
+ // set in |out_hash|, the index of |cert| in the set in |out_index| and
+ // returns true. Otherwise it returns false.
+ virtual bool MatchCert(base::StringPiece cert,
+ base::StringPiece common_set_hashes,
+ uint64_t* out_hash,
+ uint32_t* out_index) const = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_COMMON_CERT_SET_H_
diff --git a/chromium/net/quic/core/crypto/common_cert_set_2.c b/chromium/net/quic/core/crypto/common_cert_set_2.c
new file mode 100644
index 00000000000..08ac82eee21
--- /dev/null
+++ b/chromium/net/quic/core/crypto/common_cert_set_2.c
@@ -0,0 +1,129 @@
+/* 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 common certificates. It's designed to be #included in
+ * another file, in a namespace. */
+
+#include <stdint.h>
+
+#include "net/quic/core/crypto/common_cert_set_2a.inc"
+#include "net/quic/core/crypto/common_cert_set_2b.inc"
+
+static const size_t kNumCerts = 54;
+static const unsigned char* const kCerts[] = {
+ kDERCert0,
+ kDERCert1,
+ kDERCert2,
+ kDERCert3,
+ kDERCert4,
+ kDERCert5,
+ kDERCert6,
+ kDERCert7,
+ kDERCert8,
+ kDERCert9,
+ kDERCert10,
+ kDERCert11,
+ kDERCert12,
+ kDERCert13,
+ kDERCert14,
+ kDERCert15,
+ kDERCert16,
+ kDERCert17,
+ kDERCert18,
+ kDERCert19,
+ kDERCert20,
+ kDERCert21,
+ kDERCert22,
+ kDERCert23,
+ kDERCert24,
+ kDERCert25,
+ kDERCert26,
+ kDERCert27,
+ kDERCert28,
+ kDERCert29,
+ kDERCert30,
+ kDERCert31,
+ kDERCert32,
+ kDERCert33,
+ kDERCert34,
+ kDERCert35,
+ kDERCert36,
+ kDERCert37,
+ kDERCert38,
+ kDERCert39,
+ kDERCert40,
+ kDERCert41,
+ kDERCert42,
+ kDERCert43,
+ kDERCert44,
+ kDERCert45,
+ kDERCert46,
+ kDERCert47,
+ kDERCert48,
+ kDERCert49,
+ kDERCert50,
+ kDERCert51,
+ kDERCert52,
+ kDERCert53,
+};
+
+static const size_t kLens[] = {
+ 897,
+ 911,
+ 985,
+ 1012,
+ 1049,
+ 1062,
+ 1065,
+ 1071,
+ 1084,
+ 1096,
+ 1097,
+ 1105,
+ 1107,
+ 1117,
+ 1127,
+ 1133,
+ 1136,
+ 1138,
+ 1153,
+ 1171,
+ 1172,
+ 1176,
+ 1182,
+ 1188,
+ 1194,
+ 1203,
+ 1205,
+ 1206,
+ 1210,
+ 1222,
+ 1226,
+ 1236,
+ 1236,
+ 1236,
+ 1238,
+ 1256,
+ 1270,
+ 1280,
+ 1283,
+ 1284,
+ 1287,
+ 1315,
+ 1327,
+ 1340,
+ 1418,
+ 1447,
+ 1509,
+ 1520,
+ 1570,
+ 1581,
+ 1592,
+ 1628,
+ 1632,
+ 1770,
+};
+
+static const uint64_t kHash = UINT64_C(0xe81a92926081e801);
diff --git a/chromium/net/quic/crypto/common_cert_set_2a.inc b/chromium/net/quic/core/crypto/common_cert_set_2a.inc
index f71001f5a3a..f71001f5a3a 100644
--- a/chromium/net/quic/crypto/common_cert_set_2a.inc
+++ b/chromium/net/quic/core/crypto/common_cert_set_2a.inc
diff --git a/chromium/net/quic/crypto/common_cert_set_2b.inc b/chromium/net/quic/core/crypto/common_cert_set_2b.inc
index 55f120d3ae5..55f120d3ae5 100644
--- a/chromium/net/quic/crypto/common_cert_set_2b.inc
+++ b/chromium/net/quic/core/crypto/common_cert_set_2b.inc
diff --git a/chromium/net/quic/core/crypto/common_cert_set_3.c b/chromium/net/quic/core/crypto/common_cert_set_3.c
new file mode 100644
index 00000000000..3d16aae3eb9
--- /dev/null
+++ b/chromium/net/quic/core/crypto/common_cert_set_3.c
@@ -0,0 +1,123 @@
+/* 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 common certificates. It's designed to be #included in
+ * another file, in a namespace. */
+
+#include "net/quic/core/crypto/common_cert_set_3a.inc"
+#include "net/quic/core/crypto/common_cert_set_3b.inc"
+
+static const size_t kNumCerts = 52;
+static const unsigned char* const kCerts[] = {
+ kDERCert0,
+ kDERCert1,
+ kDERCert2,
+ kDERCert3,
+ kDERCert4,
+ kDERCert5,
+ kDERCert6,
+ kDERCert7,
+ kDERCert8,
+ kDERCert9,
+ kDERCert10,
+ kDERCert11,
+ kDERCert12,
+ kDERCert13,
+ kDERCert14,
+ kDERCert15,
+ kDERCert16,
+ kDERCert17,
+ kDERCert18,
+ kDERCert19,
+ kDERCert20,
+ kDERCert21,
+ kDERCert22,
+ kDERCert23,
+ kDERCert24,
+ kDERCert25,
+ kDERCert26,
+ kDERCert27,
+ kDERCert28,
+ kDERCert29,
+ kDERCert30,
+ kDERCert31,
+ kDERCert32,
+ kDERCert33,
+ kDERCert34,
+ kDERCert35,
+ kDERCert36,
+ kDERCert37,
+ kDERCert38,
+ kDERCert39,
+ kDERCert40,
+ kDERCert41,
+ kDERCert42,
+ kDERCert43,
+ kDERCert44,
+ kDERCert45,
+ kDERCert46,
+ kDERCert47,
+ kDERCert48,
+ kDERCert49,
+ kDERCert50,
+ kDERCert51,
+};
+
+static const size_t kLens[] = {
+ 897,
+ 911,
+ 1012,
+ 1049,
+ 1065,
+ 1096,
+ 1097,
+ 1101,
+ 1105,
+ 1105,
+ 1107,
+ 1117,
+ 1127,
+ 1133,
+ 1136,
+ 1138,
+ 1139,
+ 1145,
+ 1149,
+ 1153,
+ 1167,
+ 1172,
+ 1174,
+ 1174,
+ 1176,
+ 1188,
+ 1194,
+ 1196,
+ 1203,
+ 1205,
+ 1206,
+ 1208,
+ 1209,
+ 1210,
+ 1222,
+ 1227,
+ 1236,
+ 1236,
+ 1238,
+ 1283,
+ 1284,
+ 1287,
+ 1298,
+ 1315,
+ 1327,
+ 1340,
+ 1357,
+ 1418,
+ 1447,
+ 1509,
+ 1513,
+ 1632,
+};
+
+static const uint64_t kHash = UINT64_C(0x918215a28680ed7e);
diff --git a/chromium/net/quic/crypto/common_cert_set_3a.inc b/chromium/net/quic/core/crypto/common_cert_set_3a.inc
index a500cb01bd7..a500cb01bd7 100644
--- a/chromium/net/quic/crypto/common_cert_set_3a.inc
+++ b/chromium/net/quic/core/crypto/common_cert_set_3a.inc
diff --git a/chromium/net/quic/crypto/common_cert_set_3b.inc b/chromium/net/quic/core/crypto/common_cert_set_3b.inc
index 7ba882c9eb7..7ba882c9eb7 100644
--- a/chromium/net/quic/crypto/common_cert_set_3b.inc
+++ b/chromium/net/quic/core/crypto/common_cert_set_3b.inc
diff --git a/chromium/net/quic/core/crypto/common_cert_set_test.cc b/chromium/net/quic/core/crypto/common_cert_set_test.cc
new file mode 100644
index 00000000000..3eea6eebbe7
--- /dev/null
+++ b/chromium/net/quic/core/crypto/common_cert_set_test.cc
@@ -0,0 +1,249 @@
+// Copyright (c) 2013 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/crypto/common_cert_set.h"
+
+#include <stdint.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringPiece;
+
+namespace net {
+namespace test {
+
+// Google Internet Authority cert from v2 of the cert set.
+static const unsigned char kGIACertificate2[] = {
+ 0x30, 0x82, 0x03, 0xf0, 0x30, 0x82, 0x02, 0xd8, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x03, 0x02, 0x3a, 0x83, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
+ 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47,
+ 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+ 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47,
+ 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62,
+ 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30,
+ 0x34, 0x30, 0x35, 0x31, 0x35, 0x31, 0x35, 0x35, 0x36, 0x5a, 0x17, 0x0d,
+ 0x31, 0x36, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39,
+ 0x5a, 0x30, 0x49, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x13, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e,
+ 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c,
+ 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72,
+ 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+ 0x79, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+ 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
+ 0x00, 0x9c, 0x2a, 0x04, 0x77, 0x5c, 0xd8, 0x50, 0x91, 0x3a, 0x06, 0xa3,
+ 0x82, 0xe0, 0xd8, 0x50, 0x48, 0xbc, 0x89, 0x3f, 0xf1, 0x19, 0x70, 0x1a,
+ 0x88, 0x46, 0x7e, 0xe0, 0x8f, 0xc5, 0xf1, 0x89, 0xce, 0x21, 0xee, 0x5a,
+ 0xfe, 0x61, 0x0d, 0xb7, 0x32, 0x44, 0x89, 0xa0, 0x74, 0x0b, 0x53, 0x4f,
+ 0x55, 0xa4, 0xce, 0x82, 0x62, 0x95, 0xee, 0xeb, 0x59, 0x5f, 0xc6, 0xe1,
+ 0x05, 0x80, 0x12, 0xc4, 0x5e, 0x94, 0x3f, 0xbc, 0x5b, 0x48, 0x38, 0xf4,
+ 0x53, 0xf7, 0x24, 0xe6, 0xfb, 0x91, 0xe9, 0x15, 0xc4, 0xcf, 0xf4, 0x53,
+ 0x0d, 0xf4, 0x4a, 0xfc, 0x9f, 0x54, 0xde, 0x7d, 0xbe, 0xa0, 0x6b, 0x6f,
+ 0x87, 0xc0, 0xd0, 0x50, 0x1f, 0x28, 0x30, 0x03, 0x40, 0xda, 0x08, 0x73,
+ 0x51, 0x6c, 0x7f, 0xff, 0x3a, 0x3c, 0xa7, 0x37, 0x06, 0x8e, 0xbd, 0x4b,
+ 0x11, 0x04, 0xeb, 0x7d, 0x24, 0xde, 0xe6, 0xf9, 0xfc, 0x31, 0x71, 0xfb,
+ 0x94, 0xd5, 0x60, 0xf3, 0x2e, 0x4a, 0xaf, 0x42, 0xd2, 0xcb, 0xea, 0xc4,
+ 0x6a, 0x1a, 0xb2, 0xcc, 0x53, 0xdd, 0x15, 0x4b, 0x8b, 0x1f, 0xc8, 0x19,
+ 0x61, 0x1f, 0xcd, 0x9d, 0xa8, 0x3e, 0x63, 0x2b, 0x84, 0x35, 0x69, 0x65,
+ 0x84, 0xc8, 0x19, 0xc5, 0x46, 0x22, 0xf8, 0x53, 0x95, 0xbe, 0xe3, 0x80,
+ 0x4a, 0x10, 0xc6, 0x2a, 0xec, 0xba, 0x97, 0x20, 0x11, 0xc7, 0x39, 0x99,
+ 0x10, 0x04, 0xa0, 0xf0, 0x61, 0x7a, 0x95, 0x25, 0x8c, 0x4e, 0x52, 0x75,
+ 0xe2, 0xb6, 0xed, 0x08, 0xca, 0x14, 0xfc, 0xce, 0x22, 0x6a, 0xb3, 0x4e,
+ 0xcf, 0x46, 0x03, 0x97, 0x97, 0x03, 0x7e, 0xc0, 0xb1, 0xde, 0x7b, 0xaf,
+ 0x45, 0x33, 0xcf, 0xba, 0x3e, 0x71, 0xb7, 0xde, 0xf4, 0x25, 0x25, 0xc2,
+ 0x0d, 0x35, 0x89, 0x9d, 0x9d, 0xfb, 0x0e, 0x11, 0x79, 0x89, 0x1e, 0x37,
+ 0xc5, 0xaf, 0x8e, 0x72, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81,
+ 0xe7, 0x30, 0x81, 0xe4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
+ 0x18, 0x30, 0x16, 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb,
+ 0xab, 0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc,
+ 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
+ 0x4a, 0xdd, 0x06, 0x16, 0x1b, 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81,
+ 0xb6, 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, 0x0e, 0x06, 0x03,
+ 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06,
+ 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01,
+ 0x04, 0x22, 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
+ 0x05, 0x07, 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08,
+ 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x35, 0x06, 0x03,
+ 0x55, 0x1d, 0x1f, 0x04, 0x2e, 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0,
+ 0x26, 0x86, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e,
+ 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72,
+ 0x6c, 0x73, 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e,
+ 0x63, 0x72, 0x6c, 0x30, 0x17, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x10,
+ 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6,
+ 0x79, 0x02, 0x05, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
+ 0xaa, 0xfa, 0xa9, 0x20, 0xcd, 0x6a, 0x67, 0x83, 0xed, 0x5e, 0xd4, 0x7e,
+ 0xde, 0x1d, 0xc4, 0x7f, 0xe0, 0x25, 0x06, 0x00, 0xc5, 0x24, 0xfb, 0xa9,
+ 0xc8, 0x2d, 0x6d, 0x7e, 0xde, 0x9d, 0x82, 0x65, 0x2c, 0x81, 0x63, 0x34,
+ 0x66, 0x3e, 0xe9, 0x52, 0xc2, 0x08, 0xb4, 0xcb, 0x2f, 0xf7, 0x5f, 0x99,
+ 0x3a, 0x6a, 0x9c, 0x50, 0x7a, 0x85, 0x05, 0x8c, 0x7d, 0xd1, 0x2a, 0x48,
+ 0x84, 0xd3, 0x09, 0x6c, 0x7c, 0xc2, 0xcd, 0x35, 0x9f, 0xf3, 0x82, 0xee,
+ 0x52, 0xde, 0x68, 0x5f, 0xe4, 0x00, 0x8a, 0x17, 0x20, 0x96, 0xf7, 0x29,
+ 0x8d, 0x9a, 0x4d, 0xcb, 0xa8, 0xde, 0x86, 0xc8, 0x0d, 0x6f, 0x56, 0x87,
+ 0x03, 0x7d, 0x03, 0x3f, 0xdc, 0xfa, 0x79, 0x7d, 0x21, 0x19, 0xf9, 0xc8,
+ 0x3a, 0x2f, 0x51, 0x76, 0x8c, 0xc7, 0x41, 0x92, 0x71, 0x8f, 0x25, 0xce,
+ 0x37, 0xf8, 0x4a, 0x4c, 0x00, 0x23, 0xef, 0xc4, 0x35, 0x10, 0xae, 0xe0,
+ 0x23, 0x80, 0x73, 0x7c, 0x4d, 0x34, 0x2e, 0xc8, 0x6e, 0x90, 0xd6, 0x10,
+ 0x1e, 0x99, 0x84, 0x73, 0x1a, 0x70, 0xf2, 0xed, 0x55, 0x0e, 0xee, 0x17,
+ 0x06, 0xea, 0x67, 0xee, 0x32, 0xeb, 0x2c, 0xdd, 0x67, 0x07, 0x3f, 0xf6,
+ 0x8b, 0xc2, 0x70, 0xde, 0x5b, 0x00, 0xe6, 0xbb, 0x1b, 0xd3, 0x36, 0x1a,
+ 0x22, 0x6c, 0x6c, 0xb0, 0x35, 0x42, 0x6c, 0x90, 0x09, 0x3d, 0x93, 0xe9,
+ 0x64, 0x09, 0x22, 0x0e, 0x85, 0x06, 0x9f, 0xc2, 0x73, 0x21, 0xd3, 0xe6,
+ 0x5f, 0x80, 0xe4, 0x8d, 0x85, 0x22, 0x3a, 0x73, 0x03, 0xb1, 0x60, 0x8e,
+ 0xae, 0x68, 0xe2, 0xf4, 0x3e, 0x97, 0xe7, 0x60, 0x12, 0x09, 0x68, 0x36,
+ 0xde, 0x3a, 0xd6, 0xe2, 0x43, 0x95, 0x5b, 0x37, 0x81, 0x92, 0x81, 0x1f,
+ 0xbb, 0x8d, 0xd7, 0xad, 0x52, 0x64, 0x16, 0x57, 0x96, 0xd9, 0x5e, 0x34,
+ 0x7e, 0xc8, 0x35, 0xd8,
+};
+
+// Google Internet Authority cert from v3 of the cert set.
+static const unsigned char kGIACertificate3[] = {
+ 0x30, 0x82, 0x03, 0xf0, 0x30, 0x82, 0x02, 0xd8, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x03, 0x02, 0x3a, 0x92, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
+ 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47,
+ 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+ 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47,
+ 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62,
+ 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30,
+ 0x34, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d,
+ 0x31, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39,
+ 0x5a, 0x30, 0x49, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x13, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e,
+ 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c,
+ 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72,
+ 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+ 0x79, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+ 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
+ 0x00, 0x9c, 0x2a, 0x04, 0x77, 0x5c, 0xd8, 0x50, 0x91, 0x3a, 0x06, 0xa3,
+ 0x82, 0xe0, 0xd8, 0x50, 0x48, 0xbc, 0x89, 0x3f, 0xf1, 0x19, 0x70, 0x1a,
+ 0x88, 0x46, 0x7e, 0xe0, 0x8f, 0xc5, 0xf1, 0x89, 0xce, 0x21, 0xee, 0x5a,
+ 0xfe, 0x61, 0x0d, 0xb7, 0x32, 0x44, 0x89, 0xa0, 0x74, 0x0b, 0x53, 0x4f,
+ 0x55, 0xa4, 0xce, 0x82, 0x62, 0x95, 0xee, 0xeb, 0x59, 0x5f, 0xc6, 0xe1,
+ 0x05, 0x80, 0x12, 0xc4, 0x5e, 0x94, 0x3f, 0xbc, 0x5b, 0x48, 0x38, 0xf4,
+ 0x53, 0xf7, 0x24, 0xe6, 0xfb, 0x91, 0xe9, 0x15, 0xc4, 0xcf, 0xf4, 0x53,
+ 0x0d, 0xf4, 0x4a, 0xfc, 0x9f, 0x54, 0xde, 0x7d, 0xbe, 0xa0, 0x6b, 0x6f,
+ 0x87, 0xc0, 0xd0, 0x50, 0x1f, 0x28, 0x30, 0x03, 0x40, 0xda, 0x08, 0x73,
+ 0x51, 0x6c, 0x7f, 0xff, 0x3a, 0x3c, 0xa7, 0x37, 0x06, 0x8e, 0xbd, 0x4b,
+ 0x11, 0x04, 0xeb, 0x7d, 0x24, 0xde, 0xe6, 0xf9, 0xfc, 0x31, 0x71, 0xfb,
+ 0x94, 0xd5, 0x60, 0xf3, 0x2e, 0x4a, 0xaf, 0x42, 0xd2, 0xcb, 0xea, 0xc4,
+ 0x6a, 0x1a, 0xb2, 0xcc, 0x53, 0xdd, 0x15, 0x4b, 0x8b, 0x1f, 0xc8, 0x19,
+ 0x61, 0x1f, 0xcd, 0x9d, 0xa8, 0x3e, 0x63, 0x2b, 0x84, 0x35, 0x69, 0x65,
+ 0x84, 0xc8, 0x19, 0xc5, 0x46, 0x22, 0xf8, 0x53, 0x95, 0xbe, 0xe3, 0x80,
+ 0x4a, 0x10, 0xc6, 0x2a, 0xec, 0xba, 0x97, 0x20, 0x11, 0xc7, 0x39, 0x99,
+ 0x10, 0x04, 0xa0, 0xf0, 0x61, 0x7a, 0x95, 0x25, 0x8c, 0x4e, 0x52, 0x75,
+ 0xe2, 0xb6, 0xed, 0x08, 0xca, 0x14, 0xfc, 0xce, 0x22, 0x6a, 0xb3, 0x4e,
+ 0xcf, 0x46, 0x03, 0x97, 0x97, 0x03, 0x7e, 0xc0, 0xb1, 0xde, 0x7b, 0xaf,
+ 0x45, 0x33, 0xcf, 0xba, 0x3e, 0x71, 0xb7, 0xde, 0xf4, 0x25, 0x25, 0xc2,
+ 0x0d, 0x35, 0x89, 0x9d, 0x9d, 0xfb, 0x0e, 0x11, 0x79, 0x89, 0x1e, 0x37,
+ 0xc5, 0xaf, 0x8e, 0x72, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81,
+ 0xe7, 0x30, 0x81, 0xe4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
+ 0x18, 0x30, 0x16, 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb,
+ 0xab, 0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc,
+ 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
+ 0x4a, 0xdd, 0x06, 0x16, 0x1b, 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81,
+ 0xb6, 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, 0x0e, 0x06, 0x03,
+ 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06,
+ 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01,
+ 0x04, 0x22, 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
+ 0x05, 0x07, 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+ 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08,
+ 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x35, 0x06, 0x03,
+ 0x55, 0x1d, 0x1f, 0x04, 0x2e, 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0,
+ 0x26, 0x86, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e,
+ 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72,
+ 0x6c, 0x73, 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e,
+ 0x63, 0x72, 0x6c, 0x30, 0x17, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x10,
+ 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6,
+ 0x79, 0x02, 0x05, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
+ 0x08, 0x4e, 0x04, 0xa7, 0x80, 0x7f, 0x10, 0x16, 0x43, 0x5e, 0x02, 0xad,
+ 0xd7, 0x42, 0x80, 0xf4, 0xb0, 0x8e, 0xd2, 0xae, 0xb3, 0xeb, 0x11, 0x7d,
+ 0x90, 0x84, 0x18, 0x7d, 0xe7, 0x90, 0x15, 0xfb, 0x49, 0x7f, 0xa8, 0x99,
+ 0x05, 0x91, 0xbb, 0x7a, 0xc9, 0xd6, 0x3c, 0x37, 0x18, 0x09, 0x9a, 0xb6,
+ 0xc7, 0x92, 0x20, 0x07, 0x35, 0x33, 0x09, 0xe4, 0x28, 0x63, 0x72, 0x0d,
+ 0xb4, 0xe0, 0x32, 0x9c, 0x87, 0x98, 0xc4, 0x1b, 0x76, 0x89, 0x67, 0xc1,
+ 0x50, 0x58, 0xb0, 0x13, 0xaa, 0x13, 0x1a, 0x1b, 0x32, 0xa5, 0xbe, 0xea,
+ 0x11, 0x95, 0x4c, 0x48, 0x63, 0x49, 0xe9, 0x99, 0x5d, 0x20, 0x37, 0xcc,
+ 0xfe, 0x2a, 0x69, 0x51, 0x16, 0x95, 0x4b, 0xa9, 0xde, 0x49, 0x82, 0xc0,
+ 0x10, 0x70, 0xf4, 0x2c, 0xf3, 0xec, 0xbc, 0x24, 0x24, 0xd0, 0x4e, 0xac,
+ 0xa5, 0xd9, 0x5e, 0x1e, 0x6d, 0x92, 0xc1, 0xa7, 0xac, 0x48, 0x35, 0x81,
+ 0xf9, 0xe5, 0xe4, 0x9c, 0x65, 0x69, 0xcd, 0x87, 0xa4, 0x41, 0x50, 0x3f,
+ 0x2e, 0x57, 0xa5, 0x91, 0x51, 0x12, 0x58, 0x0e, 0x8c, 0x09, 0xa1, 0xac,
+ 0x7a, 0xa4, 0x12, 0xa5, 0x27, 0xf3, 0x9a, 0x10, 0x97, 0x7d, 0x55, 0x03,
+ 0x06, 0xf7, 0x66, 0x58, 0x5f, 0x5f, 0x64, 0xe1, 0xab, 0x5d, 0x6d, 0xa5,
+ 0x39, 0x48, 0x75, 0x98, 0x4c, 0x29, 0x5a, 0x3a, 0x8d, 0xd3, 0x2b, 0xca,
+ 0x9c, 0x55, 0x04, 0xbf, 0xf4, 0xe6, 0x14, 0xd5, 0x80, 0xac, 0x26, 0xed,
+ 0x17, 0x89, 0xa6, 0x93, 0x6c, 0x5c, 0xa4, 0xcc, 0xb8, 0xf0, 0x66, 0x8e,
+ 0x64, 0xe3, 0x7d, 0x9a, 0xe2, 0x00, 0xb3, 0x49, 0xc7, 0xe4, 0x0a, 0xaa,
+ 0xdd, 0x5b, 0x83, 0xc7, 0x70, 0x90, 0x46, 0x4e, 0xbe, 0xd0, 0xdb, 0x59,
+ 0x96, 0x6c, 0x2e, 0xf5, 0x16, 0x36, 0xde, 0x71, 0xcc, 0x01, 0xc2, 0x12,
+ 0xc1, 0x21, 0xc6, 0x16,
+};
+
+TEST(CommonCertSets, FindGIA_2) {
+ StringPiece gia(reinterpret_cast<const char*>(kGIACertificate2),
+ sizeof(kGIACertificate2));
+
+ const CommonCertSets* sets(CommonCertSets::GetInstanceQUIC());
+ // Common Cert Set 2's hash.
+ const uint64_t in_hash = UINT64_C(0xe81a92926081e801);
+ uint64_t hash;
+ uint32_t index;
+ ASSERT_TRUE(sets->MatchCert(
+ gia,
+ StringPiece(reinterpret_cast<const char*>(&in_hash), sizeof(in_hash)),
+ &hash, &index));
+ EXPECT_EQ(in_hash, hash);
+
+ StringPiece gia_copy = sets->GetCert(hash, index);
+ EXPECT_FALSE(gia_copy.empty());
+ ASSERT_EQ(gia.size(), gia_copy.size());
+ EXPECT_EQ(0, memcmp(gia.data(), gia_copy.data(), gia.size()));
+}
+
+TEST(CommonCertSets, FindGIA_3) {
+ StringPiece gia(reinterpret_cast<const char*>(kGIACertificate3),
+ sizeof(kGIACertificate3));
+
+ const CommonCertSets* sets(CommonCertSets::GetInstanceQUIC());
+ // Common Cert Set 3's hash.
+ const uint64_t in_hash = UINT64_C(0x918215a28680ed7e);
+ uint64_t hash;
+ uint32_t index;
+ ASSERT_TRUE(sets->MatchCert(
+ gia,
+ StringPiece(reinterpret_cast<const char*>(&in_hash), sizeof(in_hash)),
+ &hash, &index));
+ EXPECT_EQ(in_hash, hash);
+
+ StringPiece gia_copy = sets->GetCert(hash, index);
+ EXPECT_FALSE(gia_copy.empty());
+ ASSERT_EQ(gia.size(), gia_copy.size());
+ EXPECT_EQ(0, memcmp(gia.data(), gia_copy.data(), gia.size()));
+}
+
+TEST(CommonCertSets, NonMatch) {
+ const CommonCertSets* sets(CommonCertSets::GetInstanceQUIC());
+ StringPiece not_a_cert("hello");
+ const uint64_t in_hash = UINT64_C(0xc9fef74053f99f39);
+ uint64_t hash;
+ uint32_t index;
+ EXPECT_FALSE(sets->MatchCert(
+ not_a_cert,
+ StringPiece(reinterpret_cast<const char*>(&in_hash), sizeof(in_hash)),
+ &hash, &index));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/crypto_framer.cc b/chromium/net/quic/core/crypto/crypto_framer.cc
new file mode 100644
index 00000000000..2dd8f6329e3
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_framer.cc
@@ -0,0 +1,294 @@
+// 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/crypto/crypto_framer.h"
+
+#include <memory>
+
+#include "base/strings/stringprintf.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/quic_data_reader.h"
+#include "net/quic/core/quic_data_writer.h"
+
+using base::StringPiece;
+using std::pair;
+using std::vector;
+
+namespace net {
+
+namespace {
+
+const size_t kQuicTagSize = sizeof(uint32_t);
+const size_t kCryptoEndOffsetSize = sizeof(uint32_t);
+const size_t kNumEntriesSize = sizeof(uint16_t);
+
+// OneShotVisitor is a framer visitor that records a single handshake message.
+class OneShotVisitor : public CryptoFramerVisitorInterface {
+ public:
+ OneShotVisitor() : error_(false) {}
+
+ void OnError(CryptoFramer* framer) override { error_ = true; }
+
+ void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
+ out_.reset(new CryptoHandshakeMessage(message));
+ }
+
+ bool error() const { return error_; }
+
+ CryptoHandshakeMessage* release() { return out_.release(); }
+
+ private:
+ std::unique_ptr<CryptoHandshakeMessage> out_;
+ bool error_;
+};
+
+} // namespace
+
+CryptoFramer::CryptoFramer()
+ : visitor_(nullptr), error_detail_(""), num_entries_(0), values_len_(0) {
+ Clear();
+}
+
+CryptoFramer::~CryptoFramer() {}
+
+// static
+CryptoHandshakeMessage* CryptoFramer::ParseMessage(StringPiece in) {
+ OneShotVisitor visitor;
+ CryptoFramer framer;
+
+ framer.set_visitor(&visitor);
+ if (!framer.ProcessInput(in) || visitor.error() ||
+ framer.InputBytesRemaining()) {
+ return nullptr;
+ }
+
+ return visitor.release();
+}
+
+bool CryptoFramer::ProcessInput(StringPiece input) {
+ DCHECK_EQ(QUIC_NO_ERROR, error_);
+ if (error_ != QUIC_NO_ERROR) {
+ return false;
+ }
+ error_ = Process(input);
+ if (error_ != QUIC_NO_ERROR) {
+ DCHECK(!error_detail_.empty());
+ visitor_->OnError(this);
+ return false;
+ }
+
+ return true;
+}
+
+// static
+QuicData* CryptoFramer::ConstructHandshakeMessage(
+ const CryptoHandshakeMessage& message) {
+ size_t num_entries = message.tag_value_map().size();
+ size_t pad_length = 0;
+ bool need_pad_tag = false;
+ bool need_pad_value = false;
+
+ size_t len = message.size();
+ if (len < message.minimum_size()) {
+ need_pad_tag = true;
+ need_pad_value = true;
+ num_entries++;
+
+ size_t delta = message.minimum_size() - len;
+ const size_t overhead = kQuicTagSize + kCryptoEndOffsetSize;
+ if (delta > overhead) {
+ pad_length = delta - overhead;
+ }
+ len += overhead + pad_length;
+ }
+
+ if (num_entries > kMaxEntries) {
+ return nullptr;
+ }
+
+ std::unique_ptr<char[]> buffer(new char[len]);
+ QuicDataWriter writer(len, buffer.get());
+ if (!writer.WriteUInt32(message.tag())) {
+ DCHECK(false) << "Failed to write message tag.";
+ return nullptr;
+ }
+ if (!writer.WriteUInt16(static_cast<uint16_t>(num_entries))) {
+ DCHECK(false) << "Failed to write size.";
+ return nullptr;
+ }
+ if (!writer.WriteUInt16(0)) {
+ DCHECK(false) << "Failed to write padding.";
+ return nullptr;
+ }
+
+ uint32_t end_offset = 0;
+ // Tags and offsets
+ for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin();
+ it != message.tag_value_map().end(); ++it) {
+ if (it->first == kPAD && need_pad_tag) {
+ // Existing PAD tags are only checked when padding needs to be added
+ // because parts of the code may need to reserialize received messages
+ // and those messages may, legitimately include padding.
+ DCHECK(false) << "Message needed padding but already contained a PAD tag";
+ return nullptr;
+ }
+
+ if (it->first > kPAD && need_pad_tag) {
+ need_pad_tag = false;
+ if (!WritePadTag(&writer, pad_length, &end_offset)) {
+ return nullptr;
+ }
+ }
+
+ if (!writer.WriteUInt32(it->first)) {
+ DCHECK(false) << "Failed to write tag.";
+ return nullptr;
+ }
+ end_offset += it->second.length();
+ if (!writer.WriteUInt32(end_offset)) {
+ DCHECK(false) << "Failed to write end offset.";
+ return nullptr;
+ }
+ }
+
+ if (need_pad_tag) {
+ if (!WritePadTag(&writer, pad_length, &end_offset)) {
+ return nullptr;
+ }
+ }
+
+ // Values
+ for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin();
+ it != message.tag_value_map().end(); ++it) {
+ if (it->first > kPAD && need_pad_value) {
+ need_pad_value = false;
+ if (!writer.WriteRepeatedByte('-', pad_length)) {
+ DCHECK(false) << "Failed to write padding.";
+ return nullptr;
+ }
+ }
+
+ if (!writer.WriteBytes(it->second.data(), it->second.length())) {
+ DCHECK(false) << "Failed to write value.";
+ return nullptr;
+ }
+ }
+
+ if (need_pad_value) {
+ if (!writer.WriteRepeatedByte('-', pad_length)) {
+ DCHECK(false) << "Failed to write padding.";
+ return nullptr;
+ }
+ }
+
+ return new QuicData(buffer.release(), len, true);
+}
+
+void CryptoFramer::Clear() {
+ message_.Clear();
+ tags_and_lengths_.clear();
+ error_ = QUIC_NO_ERROR;
+ error_detail_ = "";
+ state_ = STATE_READING_TAG;
+}
+
+QuicErrorCode CryptoFramer::Process(StringPiece input) {
+ // Add this data to the buffer.
+ buffer_.append(input.data(), input.length());
+ QuicDataReader reader(buffer_.data(), buffer_.length());
+
+ switch (state_) {
+ case STATE_READING_TAG:
+ if (reader.BytesRemaining() < kQuicTagSize) {
+ break;
+ }
+ QuicTag message_tag;
+ reader.ReadUInt32(&message_tag);
+ message_.set_tag(message_tag);
+ state_ = STATE_READING_NUM_ENTRIES;
+ case STATE_READING_NUM_ENTRIES:
+ if (reader.BytesRemaining() < kNumEntriesSize + sizeof(uint16_t)) {
+ break;
+ }
+ reader.ReadUInt16(&num_entries_);
+ if (num_entries_ > kMaxEntries) {
+ error_detail_ = base::StringPrintf("%u entries", num_entries_);
+ return QUIC_CRYPTO_TOO_MANY_ENTRIES;
+ }
+ uint16_t padding;
+ reader.ReadUInt16(&padding);
+
+ tags_and_lengths_.reserve(num_entries_);
+ state_ = STATE_READING_TAGS_AND_LENGTHS;
+ values_len_ = 0;
+ case STATE_READING_TAGS_AND_LENGTHS: {
+ if (reader.BytesRemaining() <
+ num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) {
+ break;
+ }
+
+ uint32_t last_end_offset = 0;
+ for (unsigned i = 0; i < num_entries_; ++i) {
+ QuicTag tag;
+ reader.ReadUInt32(&tag);
+ if (i > 0 && tag <= tags_and_lengths_[i - 1].first) {
+ if (tag == tags_and_lengths_[i - 1].first) {
+ error_detail_ = base::StringPrintf("Duplicate tag:%u", tag);
+ return QUIC_CRYPTO_DUPLICATE_TAG;
+ }
+ error_detail_ = base::StringPrintf("Tag %u out of order", tag);
+ return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
+ }
+
+ uint32_t end_offset;
+ reader.ReadUInt32(&end_offset);
+
+ if (end_offset < last_end_offset) {
+ error_detail_ = base::StringPrintf("End offset: %u vs %u", end_offset,
+ last_end_offset);
+ return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
+ }
+ tags_and_lengths_.push_back(std::make_pair(
+ tag, static_cast<size_t>(end_offset - last_end_offset)));
+ last_end_offset = end_offset;
+ }
+ values_len_ = last_end_offset;
+ state_ = STATE_READING_VALUES;
+ }
+ case STATE_READING_VALUES:
+ if (reader.BytesRemaining() < values_len_) {
+ break;
+ }
+ for (const pair<QuicTag, size_t>& item : tags_and_lengths_) {
+ StringPiece value;
+ reader.ReadStringPiece(&value, item.second);
+ message_.SetStringPiece(item.first, value);
+ }
+ visitor_->OnHandshakeMessage(message_);
+ Clear();
+ state_ = STATE_READING_TAG;
+ break;
+ }
+ // Save any remaining data.
+ buffer_ = reader.PeekRemainingPayload().as_string();
+ return QUIC_NO_ERROR;
+}
+
+// static
+bool CryptoFramer::WritePadTag(QuicDataWriter* writer,
+ size_t pad_length,
+ uint32_t* end_offset) {
+ if (!writer->WriteUInt32(kPAD)) {
+ DCHECK(false) << "Failed to write tag.";
+ return false;
+ }
+ *end_offset += pad_length;
+ if (!writer->WriteUInt32(*end_offset)) {
+ DCHECK(false) << "Failed to write end offset.";
+ return false;
+ }
+ return true;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/crypto_framer.h b/chromium/net/quic/core/crypto/crypto_framer.h
new file mode 100644
index 00000000000..c581a625e4f
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_framer.h
@@ -0,0 +1,118 @@
+// 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.
+
+#ifndef NET_QUIC_CRYPTO_CRYPTO_FRAMER_H_
+#define NET_QUIC_CRYPTO_CRYPTO_FRAMER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+class CryptoFramer;
+class QuicData;
+class QuicDataReader;
+class QuicDataWriter;
+
+class NET_EXPORT_PRIVATE CryptoFramerVisitorInterface {
+ public:
+ virtual ~CryptoFramerVisitorInterface() {}
+
+ // Called if an error is detected.
+ virtual void OnError(CryptoFramer* framer) = 0;
+
+ // Called when a complete handshake message has been parsed.
+ virtual void OnHandshakeMessage(const CryptoHandshakeMessage& message) = 0;
+};
+
+// A class for framing the crypto messages that are exchanged in a QUIC
+// session.
+class NET_EXPORT_PRIVATE CryptoFramer {
+ public:
+ CryptoFramer();
+
+ virtual ~CryptoFramer();
+
+ // ParseMessage parses exactly one message from the given StringPiece. If
+ // there is an error, the message is truncated, or the message has trailing
+ // garbage then nullptr will be returned.
+ static CryptoHandshakeMessage* ParseMessage(base::StringPiece in);
+
+ // Set callbacks to be called from the framer. A visitor must be set, or
+ // else the framer will crash. It is acceptable for the visitor to do
+ // nothing. If this is called multiple times, only the last visitor
+ // will be used. |visitor| will be owned by the framer.
+ void set_visitor(CryptoFramerVisitorInterface* visitor) {
+ visitor_ = visitor;
+ }
+
+ QuicErrorCode error() const { return error_; }
+ const std::string& error_detail() const { return error_detail_; }
+
+ // Processes input data, which must be delivered in order. Returns
+ // false if there was an error, and true otherwise.
+ bool ProcessInput(base::StringPiece input);
+
+ // Returns the number of bytes of buffered input data remaining to be
+ // parsed.
+ size_t InputBytesRemaining() const { return buffer_.length(); }
+
+ // Returns a new QuicData owned by the caller that contains a serialized
+ // |message|, or nullptr if there was an error.
+ static QuicData* ConstructHandshakeMessage(
+ const CryptoHandshakeMessage& message);
+
+ private:
+ // Clears per-message state. Does not clear the visitor.
+ void Clear();
+
+ // Process does does the work of |ProcessInput|, but returns an error code,
+ // doesn't set error_ and doesn't call |visitor_->OnError()|.
+ QuicErrorCode Process(base::StringPiece input);
+
+ static bool WritePadTag(QuicDataWriter* writer,
+ size_t pad_length,
+ uint32_t* end_offset);
+
+ // Represents the current state of the parsing state machine.
+ enum CryptoFramerState {
+ STATE_READING_TAG,
+ STATE_READING_NUM_ENTRIES,
+ STATE_READING_TAGS_AND_LENGTHS,
+ STATE_READING_VALUES
+ };
+
+ // Visitor to invoke when messages are parsed.
+ CryptoFramerVisitorInterface* visitor_;
+ // Last error.
+ QuicErrorCode error_;
+ // Remaining unparsed data.
+ std::string buffer_;
+ // Current state of the parsing.
+ CryptoFramerState state_;
+ // The message currently being parsed.
+ CryptoHandshakeMessage message_;
+ // The issue which caused |error_|
+ std::string error_detail_;
+ // Number of entires in the message currently being parsed.
+ uint16_t num_entries_;
+ // tags_and_lengths_ contains the tags that are currently being parsed and
+ // their lengths.
+ std::vector<std::pair<QuicTag, size_t>> tags_and_lengths_;
+ // Cumulative length of all values in the message currently being parsed.
+ size_t values_len_;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CRYPTO_FRAMER_H_
diff --git a/chromium/net/quic/core/crypto/crypto_framer_test.cc b/chromium/net/quic/core/crypto/crypto_framer_test.cc
new file mode 100644
index 00000000000..bfe2d5af78b
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_framer_test.cc
@@ -0,0 +1,471 @@
+// 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/crypto/crypto_framer.h"
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/logging.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+
+using base::StringPiece;
+using std::map;
+using std::string;
+using std::vector;
+
+namespace net {
+
+namespace {
+
+char* AsChars(unsigned char* data) {
+ return reinterpret_cast<char*>(data);
+}
+
+} // namespace
+
+namespace test {
+
+class TestCryptoVisitor : public CryptoFramerVisitorInterface {
+ public:
+ TestCryptoVisitor() : error_count_(0) {}
+
+ void OnError(CryptoFramer* framer) override {
+ DLOG(ERROR) << "CryptoFramer Error: " << framer->error();
+ ++error_count_;
+ }
+
+ void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
+ messages_.push_back(message);
+ }
+
+ // Counters from the visitor callbacks.
+ int error_count_;
+
+ vector<CryptoHandshakeMessage> messages_;
+};
+
+TEST(CryptoFramerTest, ConstructHandshakeMessage) {
+ CryptoHandshakeMessage message;
+ message.set_tag(0xFFAA7733);
+ message.SetStringPiece(0x12345678, "abcdef");
+ message.SetStringPiece(0x12345679, "ghijk");
+ message.SetStringPiece(0x1234567A, "lmnopqr");
+
+ unsigned char packet[] = {
+ // tag
+ 0x33, 0x77, 0xAA, 0xFF,
+ // num entries
+ 0x03, 0x00,
+ // padding
+ 0x00, 0x00,
+ // tag 1
+ 0x78, 0x56, 0x34, 0x12,
+ // end offset 1
+ 0x06, 0x00, 0x00, 0x00,
+ // tag 2
+ 0x79, 0x56, 0x34, 0x12,
+ // end offset 2
+ 0x0b, 0x00, 0x00, 0x00,
+ // tag 3
+ 0x7A, 0x56, 0x34, 0x12,
+ // end offset 3
+ 0x12, 0x00, 0x00, 0x00,
+ // value 1
+ 'a', 'b', 'c', 'd', 'e', 'f',
+ // value 2
+ 'g', 'h', 'i', 'j', 'k',
+ // value 3
+ 'l', 'm', 'n', 'o', 'p', 'q', 'r',
+ };
+
+ CryptoFramer framer;
+ std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
+ ASSERT_TRUE(data.get() != nullptr);
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST(CryptoFramerTest, ConstructHandshakeMessageWithTwoKeys) {
+ CryptoHandshakeMessage message;
+ message.set_tag(0xFFAA7733);
+ message.SetStringPiece(0x12345678, "abcdef");
+ message.SetStringPiece(0x12345679, "ghijk");
+
+ unsigned char packet[] = {
+ // tag
+ 0x33, 0x77, 0xAA, 0xFF,
+ // num entries
+ 0x02, 0x00,
+ // padding
+ 0x00, 0x00,
+ // tag 1
+ 0x78, 0x56, 0x34, 0x12,
+ // end offset 1
+ 0x06, 0x00, 0x00, 0x00,
+ // tag 2
+ 0x79, 0x56, 0x34, 0x12,
+ // end offset 2
+ 0x0b, 0x00, 0x00, 0x00,
+ // value 1
+ 'a', 'b', 'c', 'd', 'e', 'f',
+ // value 2
+ 'g', 'h', 'i', 'j', 'k',
+ };
+
+ CryptoFramer framer;
+ std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
+ ASSERT_TRUE(data.get() != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST(CryptoFramerTest, ConstructHandshakeMessageZeroLength) {
+ CryptoHandshakeMessage message;
+ message.set_tag(0xFFAA7733);
+ message.SetStringPiece(0x12345678, "");
+
+ unsigned char packet[] = {
+ // tag
+ 0x33, 0x77, 0xAA, 0xFF,
+ // num entries
+ 0x01, 0x00,
+ // padding
+ 0x00, 0x00,
+ // tag 1
+ 0x78, 0x56, 0x34, 0x12,
+ // end offset 1
+ 0x00, 0x00, 0x00, 0x00,
+ };
+
+ CryptoFramer framer;
+ std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
+ ASSERT_TRUE(data.get() != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST(CryptoFramerTest, ConstructHandshakeMessageTooManyEntries) {
+ CryptoHandshakeMessage message;
+ message.set_tag(0xFFAA7733);
+ for (uint32_t key = 1; key <= kMaxEntries + 1; ++key) {
+ message.SetStringPiece(key, "abcdef");
+ }
+
+ CryptoFramer framer;
+ std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
+ EXPECT_TRUE(data.get() == nullptr);
+}
+
+TEST(CryptoFramerTest, ConstructHandshakeMessageMinimumSize) {
+ CryptoHandshakeMessage message;
+ message.set_tag(0xFFAA7733);
+ message.SetStringPiece(0x01020304, "test");
+ message.set_minimum_size(64);
+
+ unsigned char packet[] = {
+ // tag
+ 0x33, 0x77, 0xAA, 0xFF,
+ // num entries
+ 0x02, 0x00,
+ // padding
+ 0x00, 0x00,
+ // tag 1
+ 'P', 'A', 'D', 0,
+ // end offset 1
+ 0x24, 0x00, 0x00, 0x00,
+ // tag 2
+ 0x04, 0x03, 0x02, 0x01,
+ // end offset 2
+ 0x28, 0x00, 0x00, 0x00,
+ // 36 bytes of padding.
+ '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
+ '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
+ '-', '-', '-', '-', '-', '-',
+ // value 2
+ 't', 'e', 's', 't',
+ };
+
+ CryptoFramer framer;
+ std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
+ ASSERT_TRUE(data.get() != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST(CryptoFramerTest, ConstructHandshakeMessageMinimumSizePadLast) {
+ CryptoHandshakeMessage message;
+ message.set_tag(0xFFAA7733);
+ message.SetStringPiece(1, "");
+ message.set_minimum_size(64);
+
+ unsigned char packet[] = {
+ // tag
+ 0x33, 0x77, 0xAA, 0xFF,
+ // num entries
+ 0x02, 0x00,
+ // padding
+ 0x00, 0x00,
+ // tag 1
+ 0x01, 0x00, 0x00, 0x00,
+ // end offset 1
+ 0x00, 0x00, 0x00, 0x00,
+ // tag 2
+ 'P', 'A', 'D', 0,
+ // end offset 2
+ 0x28, 0x00, 0x00, 0x00,
+ // 40 bytes of padding.
+ '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
+ '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
+ '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
+ };
+
+ CryptoFramer framer;
+ std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
+ ASSERT_TRUE(data.get() != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST(CryptoFramerTest, ProcessInput) {
+ test::TestCryptoVisitor visitor;
+ CryptoFramer framer;
+ framer.set_visitor(&visitor);
+
+ unsigned char input[] = {
+ // tag
+ 0x33, 0x77, 0xAA, 0xFF,
+ // num entries
+ 0x02, 0x00,
+ // padding
+ 0x00, 0x00,
+ // tag 1
+ 0x78, 0x56, 0x34, 0x12,
+ // end offset 1
+ 0x06, 0x00, 0x00, 0x00,
+ // tag 2
+ 0x79, 0x56, 0x34, 0x12,
+ // end offset 2
+ 0x0b, 0x00, 0x00, 0x00,
+ // value 1
+ 'a', 'b', 'c', 'd', 'e', 'f',
+ // value 2
+ 'g', 'h', 'i', 'j', 'k',
+ };
+
+ EXPECT_TRUE(
+ framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
+ EXPECT_EQ(0u, framer.InputBytesRemaining());
+ EXPECT_EQ(0, visitor.error_count_);
+ ASSERT_EQ(1u, visitor.messages_.size());
+ const CryptoHandshakeMessage& message = visitor.messages_[0];
+ EXPECT_EQ(0xFFAA7733, message.tag());
+ EXPECT_EQ(2u, message.tag_value_map().size());
+ EXPECT_EQ("abcdef", CryptoTestUtils::GetValueForTag(message, 0x12345678));
+ EXPECT_EQ("ghijk", CryptoTestUtils::GetValueForTag(message, 0x12345679));
+}
+
+TEST(CryptoFramerTest, ProcessInputWithThreeKeys) {
+ test::TestCryptoVisitor visitor;
+ CryptoFramer framer;
+ framer.set_visitor(&visitor);
+
+ unsigned char input[] = {
+ // tag
+ 0x33, 0x77, 0xAA, 0xFF,
+ // num entries
+ 0x03, 0x00,
+ // padding
+ 0x00, 0x00,
+ // tag 1
+ 0x78, 0x56, 0x34, 0x12,
+ // end offset 1
+ 0x06, 0x00, 0x00, 0x00,
+ // tag 2
+ 0x79, 0x56, 0x34, 0x12,
+ // end offset 2
+ 0x0b, 0x00, 0x00, 0x00,
+ // tag 3
+ 0x7A, 0x56, 0x34, 0x12,
+ // end offset 3
+ 0x12, 0x00, 0x00, 0x00,
+ // value 1
+ 'a', 'b', 'c', 'd', 'e', 'f',
+ // value 2
+ 'g', 'h', 'i', 'j', 'k',
+ // value 3
+ 'l', 'm', 'n', 'o', 'p', 'q', 'r',
+ };
+
+ EXPECT_TRUE(
+ framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
+ EXPECT_EQ(0u, framer.InputBytesRemaining());
+ EXPECT_EQ(0, visitor.error_count_);
+ ASSERT_EQ(1u, visitor.messages_.size());
+ const CryptoHandshakeMessage& message = visitor.messages_[0];
+ EXPECT_EQ(0xFFAA7733, message.tag());
+ EXPECT_EQ(3u, message.tag_value_map().size());
+ EXPECT_EQ("abcdef", CryptoTestUtils::GetValueForTag(message, 0x12345678));
+ EXPECT_EQ("ghijk", CryptoTestUtils::GetValueForTag(message, 0x12345679));
+ EXPECT_EQ("lmnopqr", CryptoTestUtils::GetValueForTag(message, 0x1234567A));
+}
+
+TEST(CryptoFramerTest, ProcessInputIncrementally) {
+ test::TestCryptoVisitor visitor;
+ CryptoFramer framer;
+ framer.set_visitor(&visitor);
+
+ unsigned char input[] = {
+ // tag
+ 0x33, 0x77, 0xAA, 0xFF,
+ // num entries
+ 0x02, 0x00,
+ // padding
+ 0x00, 0x00,
+ // tag 1
+ 0x78, 0x56, 0x34, 0x12,
+ // end offset 1
+ 0x06, 0x00, 0x00, 0x00,
+ // tag 2
+ 0x79, 0x56, 0x34, 0x12,
+ // end offset 2
+ 0x0b, 0x00, 0x00, 0x00,
+ // value 1
+ 'a', 'b', 'c', 'd', 'e', 'f',
+ // value 2
+ 'g', 'h', 'i', 'j', 'k',
+ };
+
+ for (size_t i = 0; i < arraysize(input); i++) {
+ EXPECT_TRUE(framer.ProcessInput(StringPiece(AsChars(input) + i, 1)));
+ }
+ EXPECT_EQ(0u, framer.InputBytesRemaining());
+ ASSERT_EQ(1u, visitor.messages_.size());
+ const CryptoHandshakeMessage& message = visitor.messages_[0];
+ EXPECT_EQ(0xFFAA7733, message.tag());
+ EXPECT_EQ(2u, message.tag_value_map().size());
+ EXPECT_EQ("abcdef", CryptoTestUtils::GetValueForTag(message, 0x12345678));
+ EXPECT_EQ("ghijk", CryptoTestUtils::GetValueForTag(message, 0x12345679));
+}
+
+TEST(CryptoFramerTest, ProcessInputTagsOutOfOrder) {
+ test::TestCryptoVisitor visitor;
+ CryptoFramer framer;
+ framer.set_visitor(&visitor);
+
+ unsigned char input[] = {
+ // tag
+ 0x33, 0x77, 0xAA, 0xFF,
+ // num entries
+ 0x02, 0x00,
+ // padding
+ 0x00, 0x00,
+ // tag 1
+ 0x78, 0x56, 0x34, 0x13,
+ // end offset 1
+ 0x01, 0x00, 0x00, 0x00,
+ // tag 2
+ 0x79, 0x56, 0x34, 0x12,
+ // end offset 2
+ 0x02, 0x00, 0x00, 0x00,
+ };
+
+ EXPECT_FALSE(
+ framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
+ EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error());
+ EXPECT_EQ(1, visitor.error_count_);
+}
+
+TEST(CryptoFramerTest, ProcessEndOffsetsOutOfOrder) {
+ test::TestCryptoVisitor visitor;
+ CryptoFramer framer;
+ framer.set_visitor(&visitor);
+
+ unsigned char input[] = {
+ // tag
+ 0x33, 0x77, 0xAA, 0xFF,
+ // num entries
+ 0x02, 0x00,
+ // padding
+ 0x00, 0x00,
+ // tag 1
+ 0x79, 0x56, 0x34, 0x12,
+ // end offset 1
+ 0x01, 0x00, 0x00, 0x00,
+ // tag 2
+ 0x78, 0x56, 0x34, 0x13,
+ // end offset 2
+ 0x00, 0x00, 0x00, 0x00,
+ };
+
+ EXPECT_FALSE(
+ framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
+ EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error());
+ EXPECT_EQ(1, visitor.error_count_);
+}
+
+TEST(CryptoFramerTest, ProcessInputTooManyEntries) {
+ test::TestCryptoVisitor visitor;
+ CryptoFramer framer;
+ framer.set_visitor(&visitor);
+
+ unsigned char input[] = {
+ // tag
+ 0x33, 0x77, 0xAA, 0xFF,
+ // num entries
+ 0xA0, 0x00,
+ // padding
+ 0x00, 0x00,
+ };
+
+ EXPECT_FALSE(
+ framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
+ EXPECT_EQ(QUIC_CRYPTO_TOO_MANY_ENTRIES, framer.error());
+ EXPECT_EQ(1, visitor.error_count_);
+}
+
+TEST(CryptoFramerTest, ProcessInputZeroLength) {
+ test::TestCryptoVisitor visitor;
+ CryptoFramer framer;
+ framer.set_visitor(&visitor);
+
+ unsigned char input[] = {
+ // tag
+ 0x33, 0x77, 0xAA, 0xFF,
+ // num entries
+ 0x02, 0x00,
+ // padding
+ 0x00, 0x00,
+ // tag 1
+ 0x78, 0x56, 0x34, 0x12,
+ // end offset 1
+ 0x00, 0x00, 0x00, 0x00,
+ // tag 2
+ 0x79, 0x56, 0x34, 0x12,
+ // end offset 2
+ 0x05, 0x00, 0x00, 0x00,
+ };
+
+ EXPECT_TRUE(
+ framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
+ EXPECT_EQ(0, visitor.error_count_);
+}
+
+} // namespace test
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/crypto_handshake.cc b/chromium/net/quic/core/crypto/crypto_handshake.cc
new file mode 100644
index 00000000000..f1d8998ca06
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_handshake.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2013 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/crypto/crypto_handshake.h"
+
+#include "net/quic/core/crypto/common_cert_set.h"
+#include "net/quic/core/crypto/key_exchange.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+
+namespace net {
+
+QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters()
+ : key_exchange(0),
+ aead(0),
+ token_binding_key_param(0),
+ x509_ecdsa_supported(false),
+ x509_supported(false),
+ sct_supported_by_client(false) {}
+
+QuicCryptoNegotiatedParameters::~QuicCryptoNegotiatedParameters() {}
+
+CrypterPair::CrypterPair() {}
+
+CrypterPair::~CrypterPair() {}
+
+// static
+const char QuicCryptoConfig::kInitialLabel[] = "QUIC key expansion";
+
+// static
+const char QuicCryptoConfig::kCETVLabel[] = "QUIC CETV block";
+
+// static
+const char QuicCryptoConfig::kForwardSecureLabel[] =
+ "QUIC forward secure key expansion";
+
+QuicCryptoConfig::QuicCryptoConfig()
+ : common_cert_sets(CommonCertSets::GetInstanceQUIC()) {}
+
+QuicCryptoConfig::~QuicCryptoConfig() {}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/crypto_handshake.h b/chromium/net/quic/core/crypto/crypto_handshake.h
new file mode 100644
index 00000000000..017fa056f29
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_handshake.h
@@ -0,0 +1,192 @@
+// Copyright (c) 2013 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_CRYPTO_CRYPTO_HANDSHAKE_H_
+#define NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+class CommonCertSets;
+class KeyExchange;
+class QuicDecrypter;
+class QuicEncrypter;
+
+// HandshakeFailureReason enum values are uploaded to UMA, they cannot be
+// changed.
+enum HandshakeFailureReason {
+ HANDSHAKE_OK = 0,
+
+ // Failure reasons for an invalid client nonce in CHLO.
+ //
+ // The default error value for nonce verification failures from strike
+ // register (covers old strike registers and unknown failures).
+ CLIENT_NONCE_UNKNOWN_FAILURE = 1,
+ // Client nonce had incorrect length.
+ CLIENT_NONCE_INVALID_FAILURE = 2,
+ // Client nonce is not unique.
+ CLIENT_NONCE_NOT_UNIQUE_FAILURE = 3,
+ // Client orbit is invalid or incorrect.
+ CLIENT_NONCE_INVALID_ORBIT_FAILURE = 4,
+ // Client nonce's timestamp is not in the strike register's valid time range.
+ CLIENT_NONCE_INVALID_TIME_FAILURE = 5,
+ // Strike register's RPC call timed out, client nonce couldn't be verified.
+ CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT = 6,
+ // Strike register is down, client nonce couldn't be verified.
+ CLIENT_NONCE_STRIKE_REGISTER_FAILURE = 7,
+
+ // Failure reasons for an invalid server nonce in CHLO.
+ //
+ // Unbox of server nonce failed.
+ SERVER_NONCE_DECRYPTION_FAILURE = 8,
+ // Decrypted server nonce had incorrect length.
+ SERVER_NONCE_INVALID_FAILURE = 9,
+ // Server nonce is not unique.
+ SERVER_NONCE_NOT_UNIQUE_FAILURE = 10,
+ // Server nonce's timestamp is not in the strike register's valid time range.
+ SERVER_NONCE_INVALID_TIME_FAILURE = 11,
+ // The server requires handshake confirmation.
+ SERVER_NONCE_REQUIRED_FAILURE = 20,
+
+ // Failure reasons for an invalid server config in CHLO.
+ //
+ // Missing Server config id (kSCID) tag.
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE = 12,
+ // Couldn't find the Server config id (kSCID).
+ SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE = 13,
+
+ // Failure reasons for an invalid source-address token.
+ //
+ // Missing Source-address token (kSourceAddressTokenTag) tag.
+ SOURCE_ADDRESS_TOKEN_INVALID_FAILURE = 14,
+ // Unbox of Source-address token failed.
+ SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE = 15,
+ // Couldn't parse the unbox'ed Source-address token.
+ SOURCE_ADDRESS_TOKEN_PARSE_FAILURE = 16,
+ // Source-address token is for a different IP address.
+ SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE = 17,
+ // The source-address token has a timestamp in the future.
+ SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE = 18,
+ // The source-address token has expired.
+ SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE = 19,
+
+ // The expected leaf certificate hash could not be validated.
+ INVALID_EXPECTED_LEAF_CERTIFICATE = 21,
+
+ MAX_FAILURE_REASON = 22,
+};
+
+// These errors will be packed into an uint32_t and we don't want to set the
+// most significant bit, which may be misinterpreted as the sign bit.
+static_assert(MAX_FAILURE_REASON <= 32, "failure reason out of sync");
+
+// A CrypterPair contains the encrypter and decrypter for an encryption level.
+struct NET_EXPORT_PRIVATE CrypterPair {
+ CrypterPair();
+ ~CrypterPair();
+ std::unique_ptr<QuicEncrypter> encrypter;
+ std::unique_ptr<QuicDecrypter> decrypter;
+};
+
+// Parameters negotiated by the crypto handshake.
+struct NET_EXPORT_PRIVATE QuicCryptoNegotiatedParameters {
+ // Initializes the members to 0 or empty values.
+ QuicCryptoNegotiatedParameters();
+ ~QuicCryptoNegotiatedParameters();
+
+ QuicTag key_exchange;
+ QuicTag aead;
+ std::string initial_premaster_secret;
+ std::string forward_secure_premaster_secret;
+ // initial_subkey_secret is used as the PRK input to the HKDF used when
+ // performing key extraction that needs to happen before forward-secure keys
+ // are available.
+ std::string initial_subkey_secret;
+ // subkey_secret is used as the PRK input to the HKDF used for key extraction.
+ std::string subkey_secret;
+ CrypterPair initial_crypters;
+ CrypterPair forward_secure_crypters;
+ // Normalized SNI: converted to lower case and trailing '.' removed.
+ std::string sni;
+ std::string client_nonce;
+ std::string server_nonce;
+ // hkdf_input_suffix contains the HKDF input following the label: the
+ // ConnectionId, client hello and server config. This is only populated in the
+ // client because only the client needs to derive the forward secure keys at a
+ // later time from the initial keys.
+ std::string hkdf_input_suffix;
+ // cached_certs contains the cached certificates that a client used when
+ // sending a client hello.
+ std::vector<std::string> cached_certs;
+ // client_key_exchange is used by clients to store the ephemeral KeyExchange
+ // for the connection.
+ std::unique_ptr<KeyExchange> client_key_exchange;
+ // channel_id is set by servers to a ChannelID key when the client correctly
+ // proves possession of the corresponding private key. It consists of 32
+ // bytes of x coordinate, followed by 32 bytes of y coordinate. Both values
+ // are big-endian and the pair is a P-256 public key.
+ std::string channel_id;
+ QuicTag token_binding_key_param;
+
+ // Used when generating proof signature when sending server config updates.
+ bool x509_ecdsa_supported;
+ bool x509_supported;
+
+ // Used to generate cert chain when sending server config updates.
+ std::string client_common_set_hashes;
+ std::string client_cached_cert_hashes;
+
+ // Default to false; set to true if the client indicates that it supports sct
+ // by sending CSCT tag with an empty value in client hello.
+ bool sct_supported_by_client;
+};
+
+// QuicCryptoConfig contains common configuration between clients and servers.
+class NET_EXPORT_PRIVATE QuicCryptoConfig {
+ public:
+ // kInitialLabel is a constant that is used when deriving the initial
+ // (non-forward secure) keys for the connection in order to tie the resulting
+ // key to this protocol.
+ static const char kInitialLabel[];
+
+ // kCETVLabel is a constant that is used when deriving the keys for the
+ // encrypted tag/value block in the client hello.
+ static const char kCETVLabel[];
+
+ // kForwardSecureLabel is a constant that is used when deriving the forward
+ // secure keys for the connection in order to tie the resulting key to this
+ // protocol.
+ static const char kForwardSecureLabel[];
+
+ QuicCryptoConfig();
+ ~QuicCryptoConfig();
+
+ // Key exchange methods. The following two members' values correspond by
+ // index.
+ QuicTagVector kexs;
+ // Authenticated encryption with associated data (AEAD) algorithms.
+ QuicTagVector aead;
+
+ // Supported Token Binding key parameters that can be negotiated in the client
+ // hello.
+ QuicTagVector tb_key_params;
+
+ const CommonCertSets* common_cert_sets;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicCryptoConfig);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_H_
diff --git a/chromium/net/quic/core/crypto/crypto_handshake_message.cc b/chromium/net/quic/core/crypto/crypto_handshake_message.cc
new file mode 100644
index 00000000000..9fcf6ff0d64
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_handshake_message.cc
@@ -0,0 +1,328 @@
+// Copyright (c) 2013 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/crypto/crypto_handshake_message.h"
+
+#include <memory>
+
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "net/quic/core/crypto/crypto_framer.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/crypto_utils.h"
+#include "net/quic/core/quic_socket_address_coder.h"
+#include "net/quic/core/quic_utils.h"
+
+using base::StringPiece;
+using base::StringPrintf;
+using std::string;
+using std::vector;
+
+namespace net {
+
+CryptoHandshakeMessage::CryptoHandshakeMessage() : tag_(0), minimum_size_(0) {}
+
+CryptoHandshakeMessage::CryptoHandshakeMessage(
+ const CryptoHandshakeMessage& other)
+ : tag_(other.tag_),
+ tag_value_map_(other.tag_value_map_),
+ minimum_size_(other.minimum_size_) {
+ // Don't copy serialized_. unique_ptr doesn't have a copy constructor.
+ // The new object can lazily reconstruct serialized_.
+}
+
+CryptoHandshakeMessage::CryptoHandshakeMessage(CryptoHandshakeMessage&& other) =
+ default;
+
+CryptoHandshakeMessage::~CryptoHandshakeMessage() {}
+
+CryptoHandshakeMessage& CryptoHandshakeMessage::operator=(
+ const CryptoHandshakeMessage& other) {
+ tag_ = other.tag_;
+ tag_value_map_ = other.tag_value_map_;
+ // Don't copy serialized_. unique_ptr doesn't have an assignment operator.
+ // However, invalidate serialized_.
+ serialized_.reset();
+ minimum_size_ = other.minimum_size_;
+ return *this;
+}
+
+CryptoHandshakeMessage& CryptoHandshakeMessage::operator=(
+ CryptoHandshakeMessage&& other) = default;
+
+void CryptoHandshakeMessage::Clear() {
+ tag_ = 0;
+ tag_value_map_.clear();
+ minimum_size_ = 0;
+ serialized_.reset();
+}
+
+const QuicData& CryptoHandshakeMessage::GetSerialized() const {
+ if (!serialized_.get()) {
+ serialized_.reset(CryptoFramer::ConstructHandshakeMessage(*this));
+ }
+ return *serialized_;
+}
+
+void CryptoHandshakeMessage::MarkDirty() {
+ serialized_.reset();
+}
+
+void CryptoHandshakeMessage::SetStringPiece(QuicTag tag, StringPiece value) {
+ tag_value_map_[tag] = value.as_string();
+}
+
+void CryptoHandshakeMessage::Erase(QuicTag tag) {
+ tag_value_map_.erase(tag);
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetTaglist(QuicTag tag,
+ const QuicTag** out_tags,
+ size_t* out_len) const {
+ QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
+ QuicErrorCode ret = QUIC_NO_ERROR;
+
+ if (it == tag_value_map_.end()) {
+ ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ } else if (it->second.size() % sizeof(QuicTag) != 0) {
+ ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ if (ret != QUIC_NO_ERROR) {
+ *out_tags = nullptr;
+ *out_len = 0;
+ return ret;
+ }
+
+ *out_tags = reinterpret_cast<const QuicTag*>(it->second.data());
+ *out_len = it->second.size() / sizeof(QuicTag);
+ return ret;
+}
+
+bool CryptoHandshakeMessage::GetStringPiece(QuicTag tag,
+ StringPiece* out) const {
+ QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
+ if (it == tag_value_map_.end()) {
+ return false;
+ }
+ *out = it->second;
+ return true;
+}
+
+bool CryptoHandshakeMessage::HasStringPiece(QuicTag tag) const {
+ return base::ContainsKey(tag_value_map_, tag);
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetNthValue24(QuicTag tag,
+ unsigned index,
+ StringPiece* out) const {
+ StringPiece value;
+ if (!GetStringPiece(tag, &value)) {
+ return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ }
+
+ for (unsigned i = 0;; i++) {
+ if (value.empty()) {
+ return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND;
+ }
+ if (value.size() < 3) {
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ const unsigned char* data =
+ reinterpret_cast<const unsigned char*>(value.data());
+ size_t size = static_cast<size_t>(data[0]) |
+ (static_cast<size_t>(data[1]) << 8) |
+ (static_cast<size_t>(data[2]) << 16);
+ value.remove_prefix(3);
+
+ if (value.size() < size) {
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ if (i == index) {
+ *out = StringPiece(value.data(), size);
+ return QUIC_NO_ERROR;
+ }
+
+ value.remove_prefix(size);
+ }
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetUint32(QuicTag tag,
+ uint32_t* out) const {
+ return GetPOD(tag, out, sizeof(uint32_t));
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag,
+ uint64_t* out) const {
+ return GetPOD(tag, out, sizeof(uint64_t));
+}
+
+size_t CryptoHandshakeMessage::size() const {
+ size_t ret = sizeof(QuicTag) + sizeof(uint16_t) /* number of entries */ +
+ sizeof(uint16_t) /* padding */;
+ ret += (sizeof(QuicTag) + sizeof(uint32_t) /* end offset */) *
+ tag_value_map_.size();
+ for (QuicTagValueMap::const_iterator i = tag_value_map_.begin();
+ i != tag_value_map_.end(); ++i) {
+ ret += i->second.size();
+ }
+
+ return ret;
+}
+
+void CryptoHandshakeMessage::set_minimum_size(size_t min_bytes) {
+ if (min_bytes == minimum_size_) {
+ return;
+ }
+ serialized_.reset();
+ minimum_size_ = min_bytes;
+}
+
+size_t CryptoHandshakeMessage::minimum_size() const {
+ return minimum_size_;
+}
+
+string CryptoHandshakeMessage::DebugString() const {
+ return DebugStringInternal(0);
+}
+
+QuicErrorCode CryptoHandshakeMessage::GetPOD(QuicTag tag,
+ void* out,
+ size_t len) const {
+ QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
+ QuicErrorCode ret = QUIC_NO_ERROR;
+
+ if (it == tag_value_map_.end()) {
+ ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ } else if (it->second.size() != len) {
+ ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ if (ret != QUIC_NO_ERROR) {
+ memset(out, 0, len);
+ return ret;
+ }
+
+ memcpy(out, it->second.data(), len);
+ return ret;
+}
+
+string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
+ string ret = string(2 * indent, ' ') + QuicUtils::TagToString(tag_) + "<\n";
+ ++indent;
+ for (QuicTagValueMap::const_iterator it = tag_value_map_.begin();
+ it != tag_value_map_.end(); ++it) {
+ ret += string(2 * indent, ' ') + QuicUtils::TagToString(it->first) + ": ";
+
+ bool done = false;
+ switch (it->first) {
+ case kICSL:
+ case kCFCW:
+ case kSFCW:
+ case kIRTT:
+ case kMSPC:
+ case kSRBF:
+ case kSWND:
+ // uint32_t value
+ if (it->second.size() == 4) {
+ uint32_t value;
+ memcpy(&value, it->second.data(), sizeof(value));
+ ret += base::UintToString(value);
+ done = true;
+ }
+ break;
+ case kRCID:
+ // uint64_t value
+ if (it->second.size() == 8) {
+ uint64_t value;
+ memcpy(&value, it->second.data(), sizeof(value));
+ ret += base::Uint64ToString(value);
+ done = true;
+ }
+ break;
+ case kTBKP:
+ case kKEXS:
+ case kAEAD:
+ case kCOPT:
+ case kPDMD:
+ case kVER:
+ // tag lists
+ if (it->second.size() % sizeof(QuicTag) == 0) {
+ for (size_t j = 0; j < it->second.size(); j += sizeof(QuicTag)) {
+ QuicTag tag;
+ memcpy(&tag, it->second.data() + j, sizeof(tag));
+ if (j > 0) {
+ ret += ",";
+ }
+ ret += "'" + QuicUtils::TagToString(tag) + "'";
+ }
+ done = true;
+ }
+ break;
+ case kRREJ:
+ // uint32_t lists
+ if (it->second.size() % sizeof(uint32_t) == 0) {
+ for (size_t j = 0; j < it->second.size(); j += sizeof(uint32_t)) {
+ uint32_t value;
+ memcpy(&value, it->second.data() + j, sizeof(value));
+ if (j > 0) {
+ ret += ",";
+ }
+ ret += CryptoUtils::HandshakeFailureReasonToString(
+ static_cast<HandshakeFailureReason>(value));
+ }
+ done = true;
+ }
+ break;
+ case kCADR:
+ // IP address and port
+ if (!it->second.empty()) {
+ QuicSocketAddressCoder decoder;
+ if (decoder.Decode(it->second.data(), it->second.size())) {
+ ret += IPAddressToStringWithPort(decoder.ip(), decoder.port());
+ done = true;
+ }
+ }
+ break;
+ case kSCFG:
+ // nested messages.
+ if (!it->second.empty()) {
+ std::unique_ptr<CryptoHandshakeMessage> msg(
+ CryptoFramer::ParseMessage(it->second));
+ if (msg.get()) {
+ ret += "\n";
+ ret += msg->DebugStringInternal(indent + 1);
+
+ done = true;
+ }
+ }
+ break;
+ case kPAD:
+ ret += StringPrintf("(%d bytes of padding)",
+ static_cast<int>(it->second.size()));
+ done = true;
+ break;
+ case kSNI:
+ case kUAID:
+ ret += "\"" + it->second + "\"";
+ done = true;
+ break;
+ }
+
+ if (!done) {
+ // If there's no specific format for this tag, or the value is invalid,
+ // then just use hex.
+ ret += "0x" + QuicUtils::HexEncode(it->second);
+ }
+ ret += "\n";
+ }
+ --indent;
+ ret += string(2 * indent, ' ') + ">";
+ return ret;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/crypto_handshake_message.h b/chromium/net/quic/core/crypto/crypto_handshake_message.h
new file mode 100644
index 00000000000..e4dccc3b5a8
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_handshake_message.h
@@ -0,0 +1,140 @@
+// Copyright (c) 2013 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_CRYPTO_CRYPTO_HANDSHAKE_MESSAGE_H_
+#define NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_MESSAGE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+// An intermediate format of a handshake message that's convenient for a
+// CryptoFramer to serialize from or parse into.
+class NET_EXPORT_PRIVATE CryptoHandshakeMessage {
+ public:
+ CryptoHandshakeMessage();
+ CryptoHandshakeMessage(const CryptoHandshakeMessage& other);
+ CryptoHandshakeMessage(CryptoHandshakeMessage&& other);
+ ~CryptoHandshakeMessage();
+
+ CryptoHandshakeMessage& operator=(const CryptoHandshakeMessage& other);
+ CryptoHandshakeMessage& operator=(CryptoHandshakeMessage&& other);
+
+ // Clears state.
+ void Clear();
+
+ // GetSerialized returns the serialized form of this message and caches the
+ // result. Subsequently altering the message does not invalidate the cache.
+ const QuicData& GetSerialized() const;
+
+ // MarkDirty invalidates the cache created by |GetSerialized|.
+ void MarkDirty();
+
+ // SetValue sets an element with the given tag to the raw, memory contents of
+ // |v|.
+ template <class T>
+ void SetValue(QuicTag tag, const T& v) {
+ tag_value_map_[tag] =
+ std::string(reinterpret_cast<const char*>(&v), sizeof(v));
+ }
+
+ // SetVector sets an element with the given tag to the raw contents of an
+ // array of elements in |v|.
+ template <class T>
+ void SetVector(QuicTag tag, const std::vector<T>& v) {
+ if (v.empty()) {
+ tag_value_map_[tag] = std::string();
+ } else {
+ tag_value_map_[tag] = std::string(reinterpret_cast<const char*>(&v[0]),
+ v.size() * sizeof(T));
+ }
+ }
+
+ // Returns the message tag.
+ QuicTag tag() const { return tag_; }
+ // Sets the message tag.
+ void set_tag(QuicTag tag) { tag_ = tag; }
+
+ const QuicTagValueMap& tag_value_map() const { return tag_value_map_; }
+
+ void SetStringPiece(QuicTag tag, base::StringPiece value);
+
+ // Erase removes a tag/value, if present, from the message.
+ void Erase(QuicTag tag);
+
+ // GetTaglist finds an element with the given tag containing zero or more
+ // tags. If such a tag doesn't exist, it returns false. Otherwise it sets
+ // |out_tags| and |out_len| to point to the array of tags and returns true.
+ // The array points into the CryptoHandshakeMessage and is valid only for as
+ // long as the CryptoHandshakeMessage exists and is not modified.
+ QuicErrorCode GetTaglist(QuicTag tag,
+ const QuicTag** out_tags,
+ size_t* out_len) const;
+
+ bool GetStringPiece(QuicTag tag, base::StringPiece* out) const;
+ bool HasStringPiece(QuicTag tag) const;
+
+ // GetNthValue24 interprets the value with the given tag to be a series of
+ // 24-bit, length prefixed values and it returns the subvalue with the given
+ // index.
+ QuicErrorCode GetNthValue24(QuicTag tag,
+ unsigned index,
+ base::StringPiece* out) const;
+ QuicErrorCode GetUint32(QuicTag tag, uint32_t* out) const;
+ QuicErrorCode GetUint64(QuicTag tag, uint64_t* out) const;
+
+ // size returns 4 (message tag) + 2 (uint16_t, number of entries) +
+ // (4 (tag) + 4 (end offset))*tag_value_map_.size() + ∑ value sizes.
+ size_t size() const;
+
+ // set_minimum_size sets the minimum number of bytes that the message should
+ // consume. The CryptoFramer will add a PAD tag as needed when serializing in
+ // order to ensure this. Setting a value of 0 disables padding.
+ //
+ // Padding is useful in order to ensure that messages are a minimum size. A
+ // QUIC server can require a minimum size in order to reduce the
+ // amplification factor of any mirror DoS attack.
+ void set_minimum_size(size_t min_bytes);
+
+ size_t minimum_size() const;
+
+ // DebugString returns a multi-line, string representation of the message
+ // suitable for including in debug output.
+ std::string DebugString() const;
+
+ private:
+ // GetPOD is a utility function for extracting a plain-old-data value. If
+ // |tag| exists in the message, and has a value of exactly |len| bytes then
+ // it copies |len| bytes of data into |out|. Otherwise |len| bytes at |out|
+ // are zeroed out.
+ //
+ // If used to copy integers then this assumes that the machine is
+ // little-endian.
+ QuicErrorCode GetPOD(QuicTag tag, void* out, size_t len) const;
+
+ std::string DebugStringInternal(size_t indent) const;
+
+ QuicTag tag_;
+ QuicTagValueMap tag_value_map_;
+
+ size_t minimum_size_;
+
+ // The serialized form of the handshake message. This member is constructed
+ // lasily.
+ mutable std::unique_ptr<QuicData> serialized_;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_MESSAGE_H_
diff --git a/chromium/net/quic/core/crypto/crypto_handshake_message_test.cc b/chromium/net/quic/core/crypto/crypto_handshake_message_test.cc
new file mode 100644
index 00000000000..7032a23969d
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_handshake_message_test.cc
@@ -0,0 +1,129 @@
+// 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.
+
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/test/gtest_util.h"
+
+namespace net {
+namespace test {
+namespace {
+
+TEST(CryptoHandshakeMessageTest, DebugString) {
+ const char* str = "SHLO<\n>";
+
+ CryptoHandshakeMessage message;
+ message.set_tag(kSHLO);
+ EXPECT_EQ(str, message.DebugString());
+
+ // Test copy
+ CryptoHandshakeMessage message2(message);
+ EXPECT_EQ(str, message2.DebugString());
+
+ // Test move
+ CryptoHandshakeMessage message3(std::move(message));
+ EXPECT_EQ(str, message3.DebugString());
+
+ // Test assign
+ CryptoHandshakeMessage message4 = message3;
+ EXPECT_EQ(str, message4.DebugString());
+
+ // Test move-assign
+ CryptoHandshakeMessage message5 = std::move(message3);
+ EXPECT_EQ(str, message5.DebugString());
+}
+
+TEST(CryptoHandshakeMessageTest, DebugStringWithUintVector) {
+ const char* str =
+ "REJ <\n RREJ: "
+ "SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,"
+ "CLIENT_NONCE_NOT_UNIQUE_FAILURE\n>";
+
+ CryptoHandshakeMessage message;
+ message.set_tag(kREJ);
+ std::vector<uint32_t> reasons = {
+ SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
+ CLIENT_NONCE_NOT_UNIQUE_FAILURE};
+ message.SetVector(kRREJ, reasons);
+ EXPECT_EQ(str, message.DebugString());
+
+ // Test copy
+ CryptoHandshakeMessage message2(message);
+ EXPECT_EQ(str, message2.DebugString());
+
+ // Test move
+ CryptoHandshakeMessage message3(std::move(message));
+ EXPECT_EQ(str, message3.DebugString());
+
+ // Test assign
+ CryptoHandshakeMessage message4 = message3;
+ EXPECT_EQ(str, message4.DebugString());
+
+ // Test move-assign
+ CryptoHandshakeMessage message5 = std::move(message3);
+ EXPECT_EQ(str, message5.DebugString());
+}
+
+TEST(CryptoHandshakeMessageTest, DebugStringWithTagVector) {
+ const char* str = "CHLO<\n COPT: 'TBBR','PAD ','BYTE'\n>";
+
+ CryptoHandshakeMessage message;
+ message.set_tag(kCHLO);
+ message.SetVector(kCOPT, QuicTagVector{kTBBR, kPAD, kBYTE});
+ EXPECT_EQ(str, message.DebugString());
+
+ // Test copy
+ CryptoHandshakeMessage message2(message);
+ EXPECT_EQ(str, message2.DebugString());
+
+ // Test move
+ CryptoHandshakeMessage message3(std::move(message));
+ EXPECT_EQ(str, message3.DebugString());
+
+ // Test assign
+ CryptoHandshakeMessage message4 = message3;
+ EXPECT_EQ(str, message4.DebugString());
+
+ // Test move-assign
+ CryptoHandshakeMessage message5 = std::move(message3);
+ EXPECT_EQ(str, message5.DebugString());
+}
+
+TEST(CryptoHandshakeMessageTest, ServerDesignatedConnectionId) {
+ const char* str = "SREJ<\n RCID: 18364758544493064720\n>";
+
+ CryptoHandshakeMessage message;
+ message.set_tag(kSREJ);
+ message.SetValue(kRCID, UINT64_C(18364758544493064720));
+ EXPECT_EQ(str, message.DebugString());
+
+ // Test copy
+ CryptoHandshakeMessage message2(message);
+ EXPECT_EQ(str, message2.DebugString());
+
+ // Test move
+ CryptoHandshakeMessage message3(std::move(message));
+ EXPECT_EQ(str, message3.DebugString());
+
+ // Test assign
+ CryptoHandshakeMessage message4 = message3;
+ EXPECT_EQ(str, message4.DebugString());
+
+ // Test move-assign
+ CryptoHandshakeMessage message5 = std::move(message3);
+ EXPECT_EQ(str, message5.DebugString());
+}
+
+TEST(CryptoHandshakeMessageTest, HasStringPiece) {
+ CryptoHandshakeMessage message;
+ EXPECT_FALSE(message.HasStringPiece(kRCID));
+ message.SetStringPiece(kRCID, "foo");
+ EXPECT_TRUE(message.HasStringPiece(kRCID));
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/crypto_protocol.h b/chromium/net/quic/core/crypto/crypto_protocol.h
new file mode 100644
index 00000000000..288106622c9
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_protocol.h
@@ -0,0 +1,258 @@
+// 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.
+
+#ifndef NET_QUIC_CRYPTO_CRYPTO_PROTOCOL_H_
+#define NET_QUIC_CRYPTO_CRYPTO_PROTOCOL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "net/quic/core/quic_protocol.h"
+
+// Version and Crypto tags are written to the wire with a big-endian
+// representation of the name of the tag. For example
+// the client hello tag (CHLO) will be written as the
+// following 4 bytes: 'C' 'H' 'L' 'O'. Since it is
+// stored in memory as a little endian uint32_t, we need
+// to reverse the order of the bytes.
+//
+// We use a macro to ensure that no static initialisers are created. Use the
+// MakeQuicTag function in normal code.
+#define TAG(a, b, c, d) \
+ static_cast<QuicTag>((d << 24) + (c << 16) + (b << 8) + a)
+
+namespace net {
+
+typedef std::string ServerConfigID;
+
+// clang-format off
+const QuicTag kCHLO = TAG('C', 'H', 'L', 'O'); // Client hello
+const QuicTag kSHLO = TAG('S', 'H', 'L', 'O'); // Server hello
+const QuicTag kSCFG = TAG('S', 'C', 'F', 'G'); // Server config
+const QuicTag kREJ = TAG('R', 'E', 'J', '\0'); // Reject
+const QuicTag kSREJ = TAG('S', 'R', 'E', 'J'); // Stateless reject
+const QuicTag kCETV = TAG('C', 'E', 'T', 'V'); // Client encrypted tag-value
+ // pairs
+const QuicTag kPRST = TAG('P', 'R', 'S', 'T'); // Public reset
+const QuicTag kSCUP = TAG('S', 'C', 'U', 'P'); // Server config update.
+
+// Key exchange methods
+const QuicTag kP256 = TAG('P', '2', '5', '6'); // ECDH, Curve P-256
+const QuicTag kC255 = TAG('C', '2', '5', '5'); // ECDH, Curve25519
+
+// AEAD algorithms
+const QuicTag kNULL = TAG('N', 'U', 'L', 'N'); // null algorithm
+const QuicTag kAESG = TAG('A', 'E', 'S', 'G'); // AES128 + GCM-12
+const QuicTag kCC20 = TAG('C', 'C', '2', '0'); // ChaCha20 + Poly1305 RFC7539
+
+// Socket receive buffer
+const QuicTag kSRBF = TAG('S', 'R', 'B', 'F'); // Socket receive buffer
+
+// Congestion control feedback types
+const QuicTag kQBIC = TAG('Q', 'B', 'I', 'C'); // TCP cubic
+
+// Connection options (COPT) values
+const QuicTag kAFCW = TAG('A', 'F', 'C', 'W'); // Auto-tune flow control
+ // receive windows.
+const QuicTag kIFW5 = TAG('I', 'F', 'W', '5'); // Set initial size
+ // of stream flow control
+ // receive window to
+ // 32KB. (2^5 KB).
+const QuicTag kIFW6 = TAG('I', 'F', 'W', '6'); // Set initial size
+ // of stream flow control
+ // receive window to
+ // 64KB. (2^6 KB).
+const QuicTag kIFW7 = TAG('I', 'F', 'W', '7'); // Set initial size
+ // of stream flow control
+ // receive window to
+ // 128KB. (2^7 KB).
+const QuicTag kTBBR = TAG('T', 'B', 'B', 'R'); // Reduced Buffer Bloat TCP
+const QuicTag kRENO = TAG('R', 'E', 'N', 'O'); // Reno Congestion Control
+const QuicTag kBYTE = TAG('B', 'Y', 'T', 'E'); // TCP cubic or reno in bytes
+const QuicTag kRATE = TAG('R', 'A', 'T', 'E'); // TCP cubic rate based sending
+const QuicTag kIW03 = TAG('I', 'W', '0', '3'); // Force ICWND to 3
+const QuicTag kIW10 = TAG('I', 'W', '1', '0'); // Force ICWND to 10
+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 kNCON = TAG('N', 'C', 'O', 'N'); // N Connection Congestion Ctrl
+const QuicTag kNRTO = TAG('N', 'R', 'T', 'O'); // CWND reduction on loss
+const QuicTag kUNDO = TAG('U', 'N', 'D', 'O'); // Undo any pending retransmits
+ // if they're likely spurious.
+const QuicTag kTIME = TAG('T', 'I', 'M', 'E'); // Time based loss detection
+const QuicTag kATIM = TAG('A', 'T', 'I', 'M'); // Adaptive time loss detection
+const QuicTag kMIN1 = TAG('M', 'I', 'N', '1'); // Min CWND of 1 packet
+const QuicTag kMIN4 = TAG('M', 'I', 'N', '4'); // Min CWND of 4 packets,
+ // with a min rate of 1 BDP.
+const QuicTag kTLPR = TAG('T', 'L', 'P', 'R'); // Tail loss probe delay of
+ // 0.5RTT.
+const QuicTag kACKD = TAG('A', 'C', 'K', 'D'); // Ack decimation style acking.
+const QuicTag kAKD2 = TAG('A', 'K', 'D', '2'); // Ack decimation tolerating
+ // out of order packets.
+const QuicTag kAKD3 = TAG('A', 'K', 'D', '3'); // Ack decimation style acking
+ // with 1/8 RTT acks.
+const QuicTag kAKD4 = TAG('A', 'K', 'D', '4'); // Ack decimation with 1/8 RTT
+ // tolerating out of order.
+const QuicTag kSSLR = TAG('S', 'S', 'L', 'R'); // Slow Start Large Reduction.
+const QuicTag kNPRR = TAG('N', 'P', 'R', 'R'); // Pace at unity instead of PRR
+const QuicTag k5RTO = TAG('5', 'R', 'T', 'O'); // Close connection on 5 RTOs
+const QuicTag kCTIM = TAG('C', 'T', 'I', 'M'); // Client timestamp in seconds
+ // since UNIX epoch.
+const QuicTag kDHDT = TAG('D', 'H', 'D', 'T'); // Disable HPACK dynamic table.
+const QuicTag kIPFS = TAG('I', 'P', 'F', 'S'); // No Immediate Forward Secrecy
+const QuicTag kCONH = TAG('C', 'O', 'N', 'H'); // Conservative Handshake
+ // Retransmissions.
+
+// Optional support of truncated Connection IDs. If sent by a peer, the value
+// is the minimum number of bytes allowed for the connection ID sent to the
+// peer.
+const QuicTag kTCID = TAG('T', 'C', 'I', 'D'); // Connection ID truncation.
+
+// Multipath option.
+const QuicTag kMPTH = TAG('M', 'P', 'T', 'H'); // Enable multipath.
+
+const QuicTag kNCMR = TAG('N', 'C', 'M', 'R'); // Do not attempt connection
+ // migration.
+
+// Enable bandwidth resumption experiment.
+const QuicTag kBWRE = TAG('B', 'W', 'R', 'E'); // Bandwidth resumption.
+const QuicTag kBWMX = TAG('B', 'W', 'M', 'X'); // Max bandwidth resumption.
+const QuicTag kBWRS = TAG('B', 'W', 'R', 'S'); // Server bandwidth resumption.
+const QuicTag kBWS2 = TAG('B', 'W', 'S', '2'); // Server bw resumption v2.
+
+// Enable path MTU discovery experiment.
+const QuicTag kMTUH = TAG('M', 'T', 'U', 'H'); // High-target MTU discovery.
+const QuicTag kMTUL = TAG('M', 'T', 'U', 'L'); // Low-target MTU discovery.
+
+const QuicTag kFHOL = TAG('F', 'H', 'O', 'L'); // Force head of line blocking.
+
+// Proof types (i.e. certificate types)
+// NOTE: although it would be silly to do so, specifying both kX509 and kX59R
+// is allowed and is equivalent to specifying only kX509.
+const QuicTag kX509 = TAG('X', '5', '0', '9'); // X.509 certificate, all key
+ // types
+const QuicTag kX59R = TAG('X', '5', '9', 'R'); // X.509 certificate, RSA keys
+ // only
+const QuicTag kCHID = TAG('C', 'H', 'I', 'D'); // Channel ID.
+
+// Client hello tags
+const QuicTag kVER = TAG('V', 'E', 'R', '\0'); // Version
+const QuicTag kNONC = TAG('N', 'O', 'N', 'C'); // The client's nonce
+const QuicTag kNONP = TAG('N', 'O', 'N', 'P'); // The client's proof nonce
+const QuicTag kKEXS = TAG('K', 'E', 'X', 'S'); // Key exchange methods
+const QuicTag kAEAD = TAG('A', 'E', 'A', 'D'); // Authenticated
+ // encryption algorithms
+const QuicTag kCOPT = TAG('C', 'O', 'P', 'T'); // Connection options
+const QuicTag kICSL = TAG('I', 'C', 'S', 'L'); // Idle connection state
+ // lifetime
+const QuicTag kSCLS = TAG('S', 'C', 'L', 'S'); // Silently close on timeout
+const QuicTag kMSPC = TAG('M', 'S', 'P', 'C'); // Max streams per connection.
+const QuicTag kMIDS = TAG('M', 'I', 'D', 'S'); // Max incoming dynamic streams
+const QuicTag kIRTT = TAG('I', 'R', 'T', 'T'); // Estimated initial RTT in us.
+const QuicTag kSWND = TAG('S', 'W', 'N', 'D'); // Server's Initial congestion
+ // window.
+const QuicTag kSNI = TAG('S', 'N', 'I', '\0'); // Server name
+ // indication
+const QuicTag kPUBS = TAG('P', 'U', 'B', 'S'); // Public key values
+const QuicTag kSCID = TAG('S', 'C', 'I', 'D'); // Server config id
+const QuicTag kORBT = TAG('O', 'B', 'I', 'T'); // Server orbit.
+const QuicTag kPDMD = TAG('P', 'D', 'M', 'D'); // Proof demand.
+const QuicTag kPROF = TAG('P', 'R', 'O', 'F'); // Proof (signature).
+const QuicTag kCCS = TAG('C', 'C', 'S', 0); // Common certificate set
+const QuicTag kCCRT = TAG('C', 'C', 'R', 'T'); // Cached certificate
+const QuicTag kEXPY = TAG('E', 'X', 'P', 'Y'); // Expiry
+const QuicTag kSTTL = TAG('S', 'T', 'T', 'L'); // Server Config TTL
+const QuicTag kSFCW = TAG('S', 'F', 'C', 'W'); // Initial stream flow control
+ // receive window.
+const QuicTag kCFCW = TAG('C', 'F', 'C', 'W'); // Initial session/connection
+ // flow control receive window.
+const QuicTag kUAID = TAG('U', 'A', 'I', 'D'); // Client's User Agent ID.
+const QuicTag kXLCT = TAG('X', 'L', 'C', 'T'); // Expected leaf certificate.
+const QuicTag kTBKP = TAG('T', 'B', 'K', 'P'); // Token Binding key params.
+
+// Token Binding tags
+const QuicTag kTB10 = TAG('T', 'B', '1', '0'); // TB draft 10 with P256.
+
+// Rejection tags
+const QuicTag kRREJ = TAG('R', 'R', 'E', 'J'); // Reasons for server sending
+// Stateless Reject tags
+const QuicTag kRCID = TAG('R', 'C', 'I', 'D'); // Server-designated
+ // connection ID
+// Server hello tags
+const QuicTag kCADR = TAG('C', 'A', 'D', 'R'); // Client IP address and port
+const QuicTag kASAD = TAG('A', 'S', 'A', 'D'); // Alternate Server IP address
+ // and port.
+
+// CETV tags
+const QuicTag kCIDK = TAG('C', 'I', 'D', 'K'); // ChannelID key
+const QuicTag kCIDS = TAG('C', 'I', 'D', 'S'); // ChannelID signature
+
+// Public reset tags
+const QuicTag kRNON = TAG('R', 'N', 'O', 'N'); // Public reset nonce proof
+const QuicTag kRSEQ = TAG('R', 'S', 'E', 'Q'); // Rejected packet number
+
+// Universal tags
+const QuicTag kPAD = TAG('P', 'A', 'D', '\0'); // Padding
+
+// Server push tags
+const QuicTag kSPSH = TAG('S', 'P', 'S', 'H'); // Support server push.
+
+// Sent by clients with the fix to crbug/566156
+const QuicTag kFIXD = TAG('F', 'I', 'X', 'D'); // Client hello
+// clang-format on
+
+// These tags have a special form so that they appear either at the beginning
+// or the end of a handshake message. Since handshake messages are sorted by
+// tag value, the tags with 0 at the end will sort first and those with 255 at
+// the end will sort last.
+//
+// The certificate chain should have a tag that will cause it to be sorted at
+// the end of any handshake messages because it's likely to be large and the
+// client might be able to get everything that it needs from the small values at
+// the beginning.
+//
+// Likewise tags with random values should be towards the beginning of the
+// message because the server mightn't hold state for a rejected client hello
+// and therefore the client may have issues reassembling the rejection message
+// in the event that it sent two client hellos.
+const QuicTag kServerNonceTag = TAG('S', 'N', 'O', 0); // The server's nonce
+const QuicTag kSourceAddressTokenTag =
+ TAG('S', 'T', 'K', 0); // Source-address token
+const QuicTag kCertificateTag = TAG('C', 'R', 'T', 255); // Certificate chain
+const QuicTag kCertificateSCTTag =
+ TAG('C', 'S', 'C', 'T'); // Signed cert timestamp (RFC6962) of leaf cert.
+
+#undef TAG
+
+const size_t kMaxEntries = 128; // Max number of entries in a message.
+
+const size_t kNonceSize = 32; // Size in bytes of the connection nonce.
+
+const size_t kOrbitSize = 8; // Number of bytes in an orbit value.
+
+// kProofSignatureLabel is prepended to server configs before signing to avoid
+// any cross-protocol attacks on the signature.
+// TODO(rch): Remove this when QUIC_VERSION_30 is removed.
+const char kProofSignatureLabelOld[] = "QUIC server config signature";
+
+// kProofSignatureLabel is prepended to the CHLO hash and server configs before
+// signing to avoid any cross-protocol attacks on the signature.
+const char kProofSignatureLabel[] = "QUIC CHLO and server config signature";
+
+// kClientHelloMinimumSize is the minimum size of a client hello. Client hellos
+// will have PAD tags added in order to ensure this minimum is met and client
+// hellos smaller than this will be an error. This minimum size reduces the
+// amplification factor of any mirror DoS attack.
+//
+// A client may pad an inchoate client hello to a size larger than
+// kClientHelloMinimumSize to make it more likely to receive a complete
+// rejection message.
+const size_t kClientHelloMinimumSize = 1024;
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CRYPTO_PROTOCOL_H_
diff --git a/chromium/net/quic/core/crypto/crypto_secret_boxer.cc b/chromium/net/quic/core/crypto/crypto_secret_boxer.cc
new file mode 100644
index 00000000000..37f48b5e312
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_secret_boxer.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2013 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/crypto/crypto_secret_boxer.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "net/quic/core/crypto/aes_128_gcm_12_decrypter.h"
+#include "net/quic/core/crypto/aes_128_gcm_12_encrypter.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/crypto/quic_random.h"
+
+using base::StringPiece;
+using std::string;
+using std::vector;
+
+namespace net {
+
+// Defined kKeySize for GetKeySize() and SetKey().
+static const size_t kKeySize = 16;
+
+// kBoxNonceSize contains the number of bytes of nonce that we use in each box.
+// TODO(rtenneti): Add support for kBoxNonceSize to be 16 bytes.
+//
+// From agl@:
+// 96-bit nonces are on the edge. An attacker who can collect 2^41
+// source-address tokens has a 1% chance of finding a duplicate.
+//
+// The "average" DDoS is now 32.4M PPS. That's 2^25 source-address tokens
+// per second. So one day of that DDoS botnot would reach the 1% mark.
+//
+// It's not terrible, but it's not a "forget about it" margin.
+static const size_t kBoxNonceSize = 12;
+
+CryptoSecretBoxer::CryptoSecretBoxer() {}
+
+CryptoSecretBoxer::~CryptoSecretBoxer() {}
+
+// static
+size_t CryptoSecretBoxer::GetKeySize() {
+ return kKeySize;
+}
+
+void CryptoSecretBoxer::SetKeys(const vector<string>& keys) {
+ DCHECK(!keys.empty());
+ vector<string> copy = keys;
+ for (const string& key : keys) {
+ DCHECK_EQ(kKeySize, key.size());
+ }
+ base::AutoLock l(lock_);
+ keys_.swap(copy);
+}
+
+string CryptoSecretBoxer::Box(QuicRandom* rand, StringPiece plaintext) const {
+ std::unique_ptr<Aes128Gcm12Encrypter> encrypter(new Aes128Gcm12Encrypter());
+ {
+ base::AutoLock l(lock_);
+ DCHECK_EQ(kKeySize, keys_[0].size());
+ if (!encrypter->SetKey(keys_[0])) {
+ DLOG(DFATAL) << "CryptoSecretBoxer's encrypter->SetKey failed.";
+ return string();
+ }
+ }
+ size_t ciphertext_size = encrypter->GetCiphertextSize(plaintext.length());
+
+ string ret;
+ const size_t len = kBoxNonceSize + ciphertext_size;
+ ret.resize(len);
+ char* data = &ret[0];
+
+ // Generate nonce.
+ rand->RandBytes(data, kBoxNonceSize);
+ memcpy(data + kBoxNonceSize, plaintext.data(), plaintext.size());
+
+ if (!encrypter->Encrypt(
+ StringPiece(data, kBoxNonceSize), StringPiece(), plaintext,
+ reinterpret_cast<unsigned char*>(data + kBoxNonceSize))) {
+ DLOG(DFATAL) << "CryptoSecretBoxer's Encrypt failed.";
+ return string();
+ }
+
+ return ret;
+}
+
+bool CryptoSecretBoxer::Unbox(StringPiece ciphertext,
+ string* out_storage,
+ StringPiece* out) const {
+ if (ciphertext.size() < kBoxNonceSize) {
+ return false;
+ }
+
+ StringPiece nonce(ciphertext.data(), kBoxNonceSize);
+ ciphertext.remove_prefix(kBoxNonceSize);
+ QuicPacketNumber packet_number;
+ StringPiece nonce_prefix(nonce.data(), nonce.size() - sizeof(packet_number));
+ memcpy(&packet_number, nonce.data() + nonce_prefix.size(),
+ sizeof(packet_number));
+
+ std::unique_ptr<Aes128Gcm12Decrypter> decrypter(new Aes128Gcm12Decrypter());
+ char plaintext[kMaxPacketSize];
+ size_t plaintext_length = 0;
+ bool ok = false;
+ {
+ base::AutoLock l(lock_);
+ for (const string& key : keys_) {
+ if (decrypter->SetKey(key)) {
+ decrypter->SetNoncePrefix(nonce_prefix);
+ if (decrypter->DecryptPacket(
+ /*path_id=*/0u, packet_number,
+ /*associated data=*/StringPiece(), ciphertext, plaintext,
+ &plaintext_length, kMaxPacketSize)) {
+ ok = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!ok) {
+ return false;
+ }
+
+ out_storage->resize(plaintext_length);
+ out_storage->assign(plaintext, plaintext_length);
+ out->set(out_storage->data(), plaintext_length);
+ return true;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/crypto/crypto_secret_boxer.h b/chromium/net/quic/core/crypto/crypto_secret_boxer.h
index 09ec23c3613..09ec23c3613 100644
--- a/chromium/net/quic/crypto/crypto_secret_boxer.h
+++ b/chromium/net/quic/core/crypto/crypto_secret_boxer.h
diff --git a/chromium/net/quic/core/crypto/crypto_secret_boxer_test.cc b/chromium/net/quic/core/crypto/crypto_secret_boxer_test.cc
new file mode 100644
index 00000000000..c7712f40b65
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_secret_boxer_test.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2013 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/crypto/crypto_secret_boxer.h"
+
+#include <memory>
+
+#include "net/quic/core/crypto/quic_random.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+namespace test {
+
+TEST(CryptoSecretBoxerTest, BoxAndUnbox) {
+ StringPiece message("hello world");
+
+ CryptoSecretBoxer boxer;
+ boxer.SetKeys({string(CryptoSecretBoxer::GetKeySize(), 0x11)});
+
+ const string box = boxer.Box(QuicRandom::GetInstance(), message);
+
+ string storage;
+ StringPiece result;
+ EXPECT_TRUE(boxer.Unbox(box, &storage, &result));
+ EXPECT_EQ(result, message);
+
+ EXPECT_FALSE(boxer.Unbox(string(1, 'X') + box, &storage, &result));
+ EXPECT_FALSE(boxer.Unbox(box.substr(1, string::npos), &storage, &result));
+ EXPECT_FALSE(boxer.Unbox(string(), &storage, &result));
+ EXPECT_FALSE(
+ boxer.Unbox(string(1, box[0] ^ 0x80) + box.substr(1, string::npos),
+ &storage, &result));
+}
+
+// Helper function to test whether one boxer can decode the output of another.
+static bool CanDecode(const CryptoSecretBoxer& decoder,
+ const CryptoSecretBoxer& encoder) {
+ StringPiece message("hello world");
+ const string boxed = encoder.Box(QuicRandom::GetInstance(), message);
+ string storage;
+ StringPiece result;
+ bool ok = decoder.Unbox(boxed, &storage, &result);
+ if (ok) {
+ EXPECT_EQ(result, message);
+ }
+ return ok;
+}
+
+TEST(CryptoSecretBoxerTest, MultipleKeys) {
+ string key_11(CryptoSecretBoxer::GetKeySize(), 0x11);
+ string key_12(CryptoSecretBoxer::GetKeySize(), 0x12);
+
+ CryptoSecretBoxer boxer_11, boxer_12, boxer;
+ boxer_11.SetKeys({key_11});
+ boxer_12.SetKeys({key_12});
+ boxer.SetKeys({key_12, key_11});
+
+ // Neither single-key boxer can decode the other's tokens.
+ EXPECT_FALSE(CanDecode(boxer_11, boxer_12));
+ EXPECT_FALSE(CanDecode(boxer_12, boxer_11));
+
+ // |boxer| encodes with the first key, which is key_12.
+ EXPECT_TRUE(CanDecode(boxer_12, boxer));
+ EXPECT_FALSE(CanDecode(boxer_11, boxer));
+
+ // The boxer with both keys can decode tokens from either single-key boxer.
+ EXPECT_TRUE(CanDecode(boxer, boxer_11));
+ EXPECT_TRUE(CanDecode(boxer, boxer_12));
+
+ // After we flush key_11 from |boxer|, it can no longer decode tokens from
+ // |boxer_11|.
+ boxer.SetKeys({key_12});
+ EXPECT_FALSE(CanDecode(boxer, boxer_11));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/crypto_server_config_protobuf.cc b/chromium/net/quic/core/crypto/crypto_server_config_protobuf.cc
new file mode 100644
index 00000000000..c8e70ed9a24
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_server_config_protobuf.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2013 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/crypto/crypto_server_config_protobuf.h"
+
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+QuicServerConfigProtobuf::QuicServerConfigProtobuf()
+ : primary_time_(QuicWallTime::Zero().ToUNIXSeconds()), priority_(0) {}
+
+QuicServerConfigProtobuf::~QuicServerConfigProtobuf() {
+ base::STLDeleteElements(&keys_);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/crypto_server_config_protobuf.h b/chromium/net/quic/core/crypto/crypto_server_config_protobuf.h
new file mode 100644
index 00000000000..28c2eb94b12
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_server_config_protobuf.h
@@ -0,0 +1,115 @@
+// Copyright (c) 2013 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_CRYPTO_CRYPTO_SERVER_CONFIG_PROTOBUF_H_
+#define NET_QUIC_CRYPTO_CRYPTO_SERVER_CONFIG_PROTOBUF_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+
+namespace net {
+
+// QuicServerConfigProtobuf contains QUIC server config block and the private
+// keys needed to prove ownership.
+// TODO(rch): sync with server more rationally.
+class NET_EXPORT_PRIVATE QuicServerConfigProtobuf {
+ public:
+ // PrivateKey contains a QUIC tag of a key exchange algorithm and a
+ // serialised private key for that algorithm. The format of the serialised
+ // private key is specific to the algorithm in question.
+ class NET_EXPORT_PRIVATE PrivateKey {
+ public:
+ QuicTag tag() const { return tag_; }
+ void set_tag(QuicTag tag) { tag_ = tag; }
+ std::string private_key() const { return private_key_; }
+ void set_private_key(const std::string& key) { private_key_ = key; }
+
+ private:
+ QuicTag tag_;
+ std::string private_key_;
+ };
+
+ QuicServerConfigProtobuf();
+ ~QuicServerConfigProtobuf();
+
+ size_t key_size() const { return keys_.size(); }
+
+ const PrivateKey& key(size_t i) const {
+ DCHECK_GT(keys_.size(), i);
+ return *keys_[i];
+ }
+
+ std::string config() const { return config_; }
+
+ void set_config(base::StringPiece config) { config.CopyToString(&config_); }
+
+ QuicServerConfigProtobuf::PrivateKey* add_key() {
+ keys_.push_back(new PrivateKey);
+ return keys_.back();
+ }
+
+ void clear_key() { base::STLDeleteElements(&keys_); }
+
+ bool has_primary_time() const { return primary_time_ > 0; }
+
+ int64_t primary_time() const { return primary_time_; }
+
+ void set_primary_time(int64_t primary_time) { primary_time_ = primary_time; }
+
+ bool has_priority() const { return priority_ > 0; }
+
+ uint64_t priority() const { return priority_; }
+
+ void set_priority(int64_t priority) { priority_ = priority; }
+
+ bool has_source_address_token_secret_override() const {
+ return !source_address_token_secret_override_.empty();
+ }
+
+ std::string source_address_token_secret_override() const {
+ return source_address_token_secret_override_;
+ }
+
+ void set_source_address_token_secret_override(
+ base::StringPiece source_address_token_secret_override) {
+ source_address_token_secret_override.CopyToString(
+ &source_address_token_secret_override_);
+ }
+
+ private:
+ std::vector<PrivateKey*> keys_;
+
+ // config_ is a serialised config in QUIC wire format.
+ std::string config_;
+
+ // primary_time_ contains a UNIX epoch seconds value that indicates when this
+ // config should become primary.
+ int64_t primary_time_;
+
+ // Relative priority of this config vs other configs with the same
+ // primary time. For use as a secondary sort key when selecting the
+ // primary config.
+ uint64_t priority_;
+
+ // Optional override to the secret used to box/unbox source address
+ // tokens when talking to clients that select this server config.
+ // It can be of any length as it is fed into a KDF before use.
+ std::string source_address_token_secret_override_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicServerConfigProtobuf);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CRYPTO_SERVER_CONFIG_PROTOBUF_H_
diff --git a/chromium/net/quic/core/crypto/crypto_server_test.cc b/chromium/net/quic/core/crypto/crypto_server_test.cc
new file mode 100644
index 00000000000..39305c1147f
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_server_test.cc
@@ -0,0 +1,1288 @@
+// Copyright (c) 2013 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 <algorithm>
+#include <cstdint>
+#include <memory>
+#include <ostream>
+#include <vector>
+
+#include "base/strings/string_number_conversions.h"
+#include "crypto/secure_hash.h"
+#include "net/quic/core/crypto/cert_compressor.h"
+#include "net/quic/core/crypto/common_cert_set.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/crypto_server_config_protobuf.h"
+#include "net/quic/core/crypto/crypto_utils.h"
+#include "net/quic/core/crypto/proof_source.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_socket_address_coder.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/delayed_verify_strike_register_client.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/mock_random.h"
+#include "net/quic/test_tools/quic_crypto_server_config_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringPiece;
+using std::endl;
+using std::ostream;
+using std::string;
+using std::vector;
+
+namespace net {
+namespace test {
+
+namespace {
+
+class DummyProofVerifierCallback : public ProofVerifierCallback {
+ public:
+ DummyProofVerifierCallback() {}
+ ~DummyProofVerifierCallback() override {}
+
+ void Run(bool ok,
+ const std::string& error_details,
+ std::unique_ptr<ProofVerifyDetails>* details) override {
+ // Do nothing
+ }
+};
+
+const char kOldConfigId[] = "old-config-id";
+
+} // namespace
+
+struct TestParams {
+ TestParams(bool enable_stateless_rejects,
+ bool use_stateless_rejects,
+ QuicVersionVector supported_versions)
+ : enable_stateless_rejects(enable_stateless_rejects),
+ use_stateless_rejects(use_stateless_rejects),
+ supported_versions(std::move(supported_versions)) {}
+
+ friend ostream& operator<<(ostream& os, const TestParams& p) {
+ os << " enable_stateless_rejects: " << p.enable_stateless_rejects
+ << std::endl;
+ os << " use_stateless_rejects: " << p.use_stateless_rejects << std::endl;
+ os << " versions: " << QuicVersionVectorToString(p.supported_versions)
+ << " }";
+ return os;
+ }
+
+ // This only enables the stateless reject feature via the feature-flag.
+ // It does not force the crypto server to emit stateless rejects.
+ bool enable_stateless_rejects;
+ // If true, this forces the server to send a stateless reject when
+ // rejecting messages. This should be a no-op if
+ // enable_stateless_rejects is false.
+ bool use_stateless_rejects;
+ // Versions supported by client and server.
+ QuicVersionVector supported_versions;
+};
+
+// Constructs various test permutations.
+vector<TestParams> GetTestParams() {
+ vector<TestParams> params;
+ static const bool kTrueFalse[] = {true, false};
+ for (bool enable_stateless_rejects : kTrueFalse) {
+ for (bool use_stateless_rejects : kTrueFalse) {
+ // Start with all versions, remove highest on each iteration.
+ QuicVersionVector supported_versions = AllSupportedVersions();
+ while (!supported_versions.empty()) {
+ params.push_back(TestParams(enable_stateless_rejects,
+ use_stateless_rejects, supported_versions));
+ supported_versions.erase(supported_versions.begin());
+ }
+ }
+ }
+ return params;
+}
+
+class CryptoServerTest : public ::testing::TestWithParam<TestParams> {
+ public:
+ CryptoServerTest()
+ : rand_(QuicRandom::GetInstance()),
+ client_address_(Loopback4(), 1234),
+ config_(QuicCryptoServerConfig::TESTING,
+ rand_,
+ CryptoTestUtils::ProofSourceForTesting()),
+ compressed_certs_cache_(
+ QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
+ chlo_packet_size_(kDefaultMaxPacketSize) {
+ supported_versions_ = GetParam().supported_versions;
+ config_.set_enable_serving_sct(true);
+
+ client_version_ = supported_versions_.front();
+ client_version_string_ =
+ QuicUtils::TagToString(QuicVersionToQuicTag(client_version_));
+
+ FLAGS_quic_require_handshake_confirmation_pre33 = false;
+ FLAGS_enable_quic_stateless_reject_support =
+ GetParam().enable_stateless_rejects;
+ use_stateless_rejects_ = GetParam().use_stateless_rejects;
+ }
+
+ void SetUp() override {
+ QuicCryptoServerConfig::ConfigOptions old_config_options;
+ old_config_options.id = kOldConfigId;
+ delete config_.AddDefaultConfig(rand_, &clock_, old_config_options);
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000));
+ std::unique_ptr<QuicServerConfigProtobuf> primary_config(
+ config_.GenerateConfig(rand_, &clock_, config_options_));
+ primary_config->set_primary_time(clock_.WallNow().ToUNIXSeconds());
+ std::unique_ptr<CryptoHandshakeMessage> msg(
+ config_.AddConfig(primary_config.get(), clock_.WallNow()));
+
+ StringPiece orbit;
+ CHECK(msg->GetStringPiece(kORBT, &orbit));
+ CHECK_EQ(sizeof(orbit_), orbit.size());
+ memcpy(orbit_, orbit.data(), orbit.size());
+
+ char public_value[32];
+ memset(public_value, 42, sizeof(public_value));
+
+ nonce_hex_ = "#" + QuicUtils::HexEncode(GenerateNonce());
+ pub_hex_ = "#" + QuicUtils::HexEncode(public_value, sizeof(public_value));
+
+ // clang-format off
+ CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "CSCT", "",
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+ ShouldSucceed(client_hello);
+ // The message should be rejected because the source-address token is
+ // missing.
+ CheckRejectTag();
+ const HandshakeFailureReason kRejectReasons[] = {
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+ CheckForServerDesignatedConnectionId();
+
+ StringPiece srct;
+ ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct));
+ srct_hex_ = "#" + QuicUtils::HexEncode(srct);
+
+ StringPiece scfg;
+ ASSERT_TRUE(out_.GetStringPiece(kSCFG, &scfg));
+ server_config_.reset(CryptoFramer::ParseMessage(scfg));
+
+ StringPiece scid;
+ ASSERT_TRUE(server_config_->GetStringPiece(kSCID, &scid));
+ scid_hex_ = "#" + QuicUtils::HexEncode(scid);
+
+ crypto_proof_ = QuicCryptoProof();
+ DCHECK(crypto_proof_.chain.get() == nullptr);
+ }
+
+ // Helper used to accept the result of ValidateClientHello and pass
+ // it on to ProcessClientHello.
+ class ValidateCallback : public ValidateClientHelloResultCallback {
+ public:
+ ValidateCallback(CryptoServerTest* test,
+ bool should_succeed,
+ const char* error_substr,
+ bool* called)
+ : test_(test),
+ should_succeed_(should_succeed),
+ error_substr_(error_substr),
+ called_(called) {
+ *called_ = false;
+ }
+
+ void Run(scoped_refptr<Result> result,
+ std::unique_ptr<ProofSource::Details> /* details */) override {
+ {
+ // Ensure that the strike register client lock is not held.
+ QuicCryptoServerConfigPeer peer(&test_->config_);
+ base::Lock* m = peer.GetStrikeRegisterClientLock();
+ // In Chromium, we will dead lock if the lock is held by the current
+ // thread. Chromium doesn't have AssertNotHeld API call.
+ // m->AssertNotHeld();
+ base::AutoLock lock(*m);
+ }
+ ASSERT_FALSE(*called_);
+ test_->ProcessValidationResult(std::move(result), should_succeed_,
+ error_substr_);
+ *called_ = true;
+ }
+
+ private:
+ CryptoServerTest* test_;
+ const bool should_succeed_;
+ const char* const error_substr_;
+ bool* called_;
+ };
+
+ void CheckServerHello(const CryptoHandshakeMessage& server_hello) {
+ const QuicTag* versions;
+ size_t num_versions;
+ server_hello.GetTaglist(kVER, &versions, &num_versions);
+ ASSERT_EQ(supported_versions_.size(), num_versions);
+ for (size_t i = 0; i < num_versions; ++i) {
+ EXPECT_EQ(QuicVersionToQuicTag(supported_versions_[i]), versions[i]);
+ }
+
+ StringPiece address;
+ ASSERT_TRUE(server_hello.GetStringPiece(kCADR, &address));
+ QuicSocketAddressCoder decoder;
+ ASSERT_TRUE(decoder.Decode(address.data(), address.size()));
+ EXPECT_EQ(client_address_.address(), decoder.ip());
+ EXPECT_EQ(client_address_.port(), decoder.port());
+ }
+
+ void ShouldSucceed(const CryptoHandshakeMessage& message) {
+ bool called = false;
+ IPAddress server_ip;
+ config_.ValidateClientHello(
+ message, client_address_.address(), server_ip,
+ supported_versions_.front(), &clock_, &crypto_proof_,
+ std::unique_ptr<ValidateCallback>(
+ new ValidateCallback(this, true, "", &called)));
+ EXPECT_TRUE(called);
+ }
+
+ void ShouldFailMentioning(const char* error_substr,
+ const CryptoHandshakeMessage& message) {
+ bool called = false;
+ ShouldFailMentioning(error_substr, message, &called);
+ EXPECT_TRUE(called);
+ }
+
+ void ShouldFailMentioning(const char* error_substr,
+ const CryptoHandshakeMessage& message,
+ bool* called) {
+ IPAddress server_ip;
+ config_.ValidateClientHello(
+ message, client_address_.address(), server_ip,
+ supported_versions_.front(), &clock_, &crypto_proof_,
+ std::unique_ptr<ValidateCallback>(
+ new ValidateCallback(this, false, error_substr, called)));
+ }
+
+ class ProcessCallback : public ProcessClientHelloResultCallback {
+ public:
+ ProcessCallback(scoped_refptr<ValidateCallback::Result> result,
+ bool should_succeed,
+ const char* error_substr,
+ bool* called,
+ CryptoHandshakeMessage* out)
+ : result_(std::move(result)),
+ should_succeed_(should_succeed),
+ error_substr_(error_substr),
+ called_(called),
+ out_(out) {
+ *called_ = false;
+ }
+
+ void Run(
+ QuicErrorCode error,
+ const string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> message,
+ std::unique_ptr<DiversificationNonce> diversification_nonce) override {
+ if (should_succeed_) {
+ ASSERT_EQ(error, QUIC_NO_ERROR) << "Message failed with error "
+ << error_details << ": "
+ << result_->client_hello.DebugString();
+ } else {
+ ASSERT_NE(error, QUIC_NO_ERROR) << "Message didn't fail: "
+ << result_->client_hello.DebugString();
+
+ EXPECT_TRUE(error_details.find(error_substr_) != string::npos)
+ << error_substr_ << " not in " << error_details;
+ }
+ if (message != nullptr) {
+ *out_ = *message;
+ }
+ *called_ = true;
+ }
+
+ private:
+ const scoped_refptr<ValidateCallback::Result> result_;
+ const bool should_succeed_;
+ const char* const error_substr_;
+ bool* called_;
+ CryptoHandshakeMessage* out_;
+ };
+
+ void ProcessValidationResult(scoped_refptr<ValidateCallback::Result> result,
+ bool should_succeed,
+ const char* error_substr) {
+ IPAddress server_ip;
+ QuicConnectionId server_designated_connection_id =
+ rand_for_id_generation_.RandUint64();
+ bool called;
+ config_.ProcessClientHello(
+ result, /*reject_only=*/false, /*connection_id=*/1, server_ip,
+ client_address_, supported_versions_.front(), supported_versions_,
+ use_stateless_rejects_, server_designated_connection_id, &clock_, rand_,
+ &compressed_certs_cache_, &params_, &crypto_proof_,
+ /*total_framing_overhead=*/50, chlo_packet_size_,
+ std::unique_ptr<ProcessCallback>(new ProcessCallback(
+ result, should_succeed, error_substr, &called, &out_)));
+ EXPECT_TRUE(called);
+ }
+
+ string GenerateNonce() {
+ string nonce;
+ CryptoUtils::GenerateNonce(
+ clock_.WallNow(), rand_,
+ StringPiece(reinterpret_cast<const char*>(orbit_), sizeof(orbit_)),
+ &nonce);
+ return nonce;
+ }
+
+ void CheckRejectReasons(
+ const HandshakeFailureReason* expected_handshake_failures,
+ size_t expected_count) {
+ const uint32_t* reject_reasons;
+ size_t num_reject_reasons;
+ static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync");
+ QuicErrorCode error_code =
+ out_.GetTaglist(kRREJ, &reject_reasons, &num_reject_reasons);
+ ASSERT_EQ(QUIC_NO_ERROR, error_code);
+
+ EXPECT_EQ(expected_count, num_reject_reasons);
+ for (size_t i = 0; i < num_reject_reasons; ++i) {
+ EXPECT_EQ(expected_handshake_failures[i], reject_reasons[i]);
+ }
+ }
+
+ // If the server is rejecting statelessly, make sure it contains a
+ // server-designated connection id. Once the check is complete,
+ // allow the random id-generator to move to the next value.
+ void CheckForServerDesignatedConnectionId() {
+ QuicConnectionId server_designated_connection_id;
+ if (!RejectsAreStateless()) {
+ EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
+ out_.GetUint64(kRCID, &server_designated_connection_id));
+ } else {
+ ASSERT_EQ(QUIC_NO_ERROR,
+ out_.GetUint64(kRCID, &server_designated_connection_id));
+ EXPECT_EQ(rand_for_id_generation_.RandUint64(),
+ server_designated_connection_id);
+ }
+ rand_for_id_generation_.ChangeValue();
+ }
+
+ void CheckRejectTag() {
+ if (RejectsAreStateless()) {
+ ASSERT_EQ(kSREJ, out_.tag()) << QuicUtils::TagToString(out_.tag());
+ } else {
+ ASSERT_EQ(kREJ, out_.tag()) << QuicUtils::TagToString(out_.tag());
+ }
+ }
+
+ bool RejectsAreStateless() {
+ return GetParam().enable_stateless_rejects &&
+ GetParam().use_stateless_rejects;
+ }
+
+ string XlctHexString() {
+ uint64_t xlct = CryptoTestUtils::LeafCertHashForTesting();
+ return "#" +
+ QuicUtils::HexEncode(reinterpret_cast<char*>(&xlct), sizeof(xlct));
+ }
+
+ protected:
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+ QuicRandom* const rand_;
+ MockRandom rand_for_id_generation_;
+ MockClock clock_;
+ IPEndPoint client_address_;
+ QuicVersionVector supported_versions_;
+ QuicVersion client_version_;
+ string client_version_string_;
+ QuicCryptoServerConfig config_;
+ QuicCompressedCertsCache compressed_certs_cache_;
+ QuicCryptoServerConfig::ConfigOptions config_options_;
+ QuicCryptoNegotiatedParameters params_;
+ QuicCryptoProof crypto_proof_;
+ CryptoHandshakeMessage out_;
+ uint8_t orbit_[kOrbitSize];
+ bool use_stateless_rejects_;
+ size_t chlo_packet_size_;
+
+ // These strings contain hex escaped values from the server suitable for using
+ // when constructing client hello messages.
+ string nonce_hex_, pub_hex_, srct_hex_, scid_hex_;
+ std::unique_ptr<CryptoHandshakeMessage> server_config_;
+};
+
+INSTANTIATE_TEST_CASE_P(CryptoServerTests,
+ CryptoServerTest,
+ ::testing::ValuesIn(GetTestParams()));
+
+TEST_P(CryptoServerTest, BadSNI) {
+ // clang-format off
+ static const char* const kBadSNIs[] = {
+ "",
+ "foo",
+ "#00",
+ "#ff00",
+ "127.0.0.1",
+ "ffee::1",
+ };
+ // clang-format on
+
+ for (size_t i = 0; i < arraysize(kBadSNIs); i++) {
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "SNI", kBadSNIs[i],
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+ ShouldFailMentioning("SNI", msg);
+ const HandshakeFailureReason kRejectReasons[] = {
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+ }
+}
+
+TEST_P(CryptoServerTest, DefaultCert) {
+ // Check that the server replies with a default certificate when no SNI is
+ // specified. The CHLO is constructed to generate a REJ with certs, so must
+ // not contain a valid STK, and must include PDMD.
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "PDMD", "X509",
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+
+ ShouldSucceed(msg);
+ StringPiece cert, proof, cert_sct;
+ EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert));
+ EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof));
+ EXPECT_TRUE(out_.GetStringPiece(kCertificateSCTTag, &cert_sct));
+ EXPECT_NE(0u, cert.size());
+ EXPECT_NE(0u, proof.size());
+ const HandshakeFailureReason kRejectReasons[] = {
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+ EXPECT_LT(0u, cert_sct.size());
+}
+
+TEST_P(CryptoServerTest, RejectTooLarge) {
+ // Check that the server replies with no certificate when a CHLO is
+ // constructed with a PDMD but no SKT when the REJ would be too large.
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "PDMD", "X509",
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+
+ // The REJ will be larger than the CHLO so no PROF or CRT will be sent.
+ config_.set_chlo_multiplier(1);
+
+ ShouldSucceed(msg);
+ StringPiece cert, proof, cert_sct;
+ EXPECT_FALSE(out_.GetStringPiece(kCertificateTag, &cert));
+ EXPECT_FALSE(out_.GetStringPiece(kPROF, &proof));
+ EXPECT_FALSE(out_.GetStringPiece(kCertificateSCTTag, &cert_sct));
+ const HandshakeFailureReason kRejectReasons[] = {
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+}
+
+TEST_P(CryptoServerTest, RejectNotTooLarge) {
+ // When the CHLO packet is large enough, ensure that a full REJ is sent.
+ chlo_packet_size_ *= 2;
+
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "PDMD", "X509",
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+
+ // The REJ will be larger than the CHLO so no PROF or CRT will be sent.
+ config_.set_chlo_multiplier(1);
+
+ ShouldSucceed(msg);
+ StringPiece cert, proof, cert_sct;
+ EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert));
+ EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof));
+ EXPECT_TRUE(out_.GetStringPiece(kCertificateSCTTag, &cert_sct));
+ const HandshakeFailureReason kRejectReasons[] = {
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+}
+
+TEST_P(CryptoServerTest, RejectTooLargeButValidSTK) {
+ // Check that the server replies with no certificate when a CHLO is
+ // constructed with a PDMD but no SKT when the REJ would be too large.
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "#004b5453", srct_hex_.c_str(),
+ "PDMD", "X509",
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+
+ // The REJ will be larger than the CHLO so no PROF or CRT will be sent.
+ config_.set_chlo_multiplier(1);
+
+ ShouldSucceed(msg);
+ StringPiece cert, proof, cert_sct;
+ EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert));
+ EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof));
+ EXPECT_TRUE(out_.GetStringPiece(kCertificateSCTTag, &cert_sct));
+ EXPECT_NE(0u, cert.size());
+ EXPECT_NE(0u, proof.size());
+ const HandshakeFailureReason kRejectReasons[] = {
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+}
+
+TEST_P(CryptoServerTest, TooSmall) {
+ // clang-format off
+ ShouldFailMentioning("too small", CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "VER\0", client_version_string_.c_str(),
+ nullptr));
+ // clang-format on
+ const HandshakeFailureReason kRejectReasons[] = {
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+}
+
+TEST_P(CryptoServerTest, BadSourceAddressToken) {
+ // Invalid source-address tokens should be ignored.
+ // clang-format off
+ static const char* const kBadSourceAddressTokens[] = {
+ "",
+ "foo",
+ "#0000",
+ "#0000000000000000000000000000000000000000",
+ };
+ // clang-format on
+
+ for (size_t i = 0; i < arraysize(kBadSourceAddressTokens); i++) {
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "STK", kBadSourceAddressTokens[i],
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize), nullptr);
+ // clang-format on
+ ShouldSucceed(msg);
+ const HandshakeFailureReason kRejectReasons[] = {
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+ }
+}
+
+TEST_P(CryptoServerTest, BadClientNonce) {
+ // clang-format off
+ static const char* const kBadNonces[] = {
+ "",
+ "#0000",
+ "#0000000000000000000000000000000000000000",
+ };
+ // clang-format on
+
+ for (size_t i = 0; i < arraysize(kBadNonces); i++) {
+ // Invalid nonces should be ignored, in an inchoate CHLO.
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "NONC", kBadNonces[i],
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+ ShouldSucceed(msg);
+ const HandshakeFailureReason kRejectReasons[] = {
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+
+ // Invalid nonces should result in CLIENT_NONCE_INVALID_FAILURE.
+ // clang-format off
+ CryptoHandshakeMessage msg1 = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", srct_hex_.c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", kBadNonces[i],
+ "NONP", kBadNonces[i],
+ "XLCT", XlctHexString().c_str(),
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+
+ ShouldSucceed(msg1);
+
+ CheckRejectTag();
+ const HandshakeFailureReason kRejectReasons1[] = {
+ CLIENT_NONCE_INVALID_FAILURE};
+ CheckRejectReasons(kRejectReasons1, arraysize(kRejectReasons1));
+ }
+}
+
+TEST_P(CryptoServerTest, NoClientNonce) {
+ // No client nonces should result in INCHOATE_HELLO_FAILURE.
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+
+ ShouldSucceed(msg);
+ const HandshakeFailureReason kRejectReasons[] = {
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+
+ // clang-format off
+ CryptoHandshakeMessage msg1 = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", srct_hex_.c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "XLCT", XlctHexString().c_str(),
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+
+ ShouldSucceed(msg1);
+ CheckRejectTag();
+ const HandshakeFailureReason kRejectReasons1[] = {
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
+ CheckRejectReasons(kRejectReasons1, arraysize(kRejectReasons1));
+}
+
+TEST_P(CryptoServerTest, DowngradeAttack) {
+ if (supported_versions_.size() == 1) {
+ // No downgrade attack is possible if the server only supports one version.
+ return;
+ }
+ // Set the client's preferred version to a supported version that
+ // is not the "current" version (supported_versions_.front()).
+ string bad_version =
+ QuicUtils::TagToString(QuicVersionToQuicTag(supported_versions_.back()));
+
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "VER\0", bad_version.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+ ShouldFailMentioning("Downgrade", msg);
+ const HandshakeFailureReason kRejectReasons[] = {
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+}
+
+TEST_P(CryptoServerTest, CorruptServerConfig) {
+ // This tests corrupted server config.
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SCID", (string(1, 'X') + scid_hex_).c_str(),
+ "#004b5453", srct_hex_.c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+ ShouldSucceed(msg);
+ CheckRejectTag();
+ const HandshakeFailureReason kRejectReasons[] = {
+ SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+}
+
+TEST_P(CryptoServerTest, CorruptSourceAddressToken) {
+ // This tests corrupted source address token.
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", (string(1, 'X') + srct_hex_).c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "XLCT", XlctHexString().c_str(),
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+ ShouldSucceed(msg);
+ CheckRejectTag();
+ const HandshakeFailureReason kRejectReasons[] = {
+ SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+}
+
+TEST_P(CryptoServerTest, CorruptClientNonceAndSourceAddressToken) {
+ // This test corrupts client nonce and source address token.
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", (string(1, 'X') + srct_hex_).c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", (string(1, 'X') + nonce_hex_).c_str(),
+ "XLCT", XlctHexString().c_str(),
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+ ShouldSucceed(msg);
+ CheckRejectTag();
+ const HandshakeFailureReason kRejectReasons[] = {
+ SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+}
+
+TEST_P(CryptoServerTest, CorruptMultipleTags) {
+ // This test corrupts client nonce, server nonce and source address token.
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", (string(1, 'X') + srct_hex_).c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", (string(1, 'X') + nonce_hex_).c_str(),
+ "NONP", (string(1, 'X') + nonce_hex_).c_str(),
+ "SNO\0", (string(1, 'X') + nonce_hex_).c_str(),
+ "XLCT", XlctHexString().c_str(),
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+ ShouldSucceed(msg);
+ CheckRejectTag();
+
+ if (client_version_ <= QUIC_VERSION_32) {
+ const HandshakeFailureReason kRejectReasons[] = {
+ SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE,
+ SERVER_NONCE_DECRYPTION_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+ } else {
+ const HandshakeFailureReason kRejectReasons[] = {
+ SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+ };
+}
+
+TEST_P(CryptoServerTest, NoServerNonce) {
+ // When no server nonce is present and no strike register is configured,
+ // the CHLO should be rejected.
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", srct_hex_.c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "NONP", nonce_hex_.c_str(),
+ "XLCT", XlctHexString().c_str(),
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+
+ ShouldSucceed(msg);
+
+ if (client_version_ <= QUIC_VERSION_32) {
+ CheckRejectTag();
+ const HandshakeFailureReason kRejectReasons[] = {
+ SERVER_NONCE_REQUIRED_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+ } else {
+ // Even without a server nonce, this ClientHello should be accepted in
+ // version 33.
+ ASSERT_EQ(kSHLO, out_.tag());
+ CheckServerHello(out_);
+ }
+}
+
+TEST_P(CryptoServerTest, ProofForSuppliedServerConfig) {
+ client_address_ = IPEndPoint(Loopback6(), 1234);
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "PDMD", "X509",
+ "SCID", kOldConfigId,
+ "#004b5453", srct_hex_.c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "VER\0", client_version_string_.c_str(),
+ "XLCT", XlctHexString().c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+ ShouldSucceed(msg);
+ // The message should be rejected because the source-address token is no
+ // longer valid.
+ CheckRejectTag();
+ const HandshakeFailureReason kRejectReasons[] = {
+ SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+
+ StringPiece cert, proof, scfg_str;
+ EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert));
+ EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof));
+ EXPECT_TRUE(out_.GetStringPiece(kSCFG, &scfg_str));
+ std::unique_ptr<CryptoHandshakeMessage> scfg(
+ CryptoFramer::ParseMessage(scfg_str));
+ StringPiece scid;
+ EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid));
+ EXPECT_NE(scid, kOldConfigId);
+
+ // Get certs from compressed certs.
+ const CommonCertSets* common_cert_sets(CommonCertSets::GetInstanceQUIC());
+ vector<string> cached_certs;
+
+ vector<string> certs;
+ ASSERT_TRUE(CertCompressor::DecompressChain(cert, cached_certs,
+ common_cert_sets, &certs));
+
+ // Check that the proof in the REJ message is valid.
+ std::unique_ptr<ProofVerifier> proof_verifier(
+ CryptoTestUtils::ProofVerifierForTesting());
+ std::unique_ptr<ProofVerifyContext> verify_context(
+ CryptoTestUtils::ProofVerifyContextForTesting());
+ std::unique_ptr<ProofVerifyDetails> details;
+ string error_details;
+ std::unique_ptr<ProofVerifierCallback> callback(
+ new DummyProofVerifierCallback());
+ string chlo_hash;
+ CryptoUtils::HashHandshakeMessage(msg, &chlo_hash);
+ EXPECT_EQ(QUIC_SUCCESS,
+ proof_verifier->VerifyProof(
+ "test.example.com", 443, scfg_str.as_string(), client_version_,
+ chlo_hash, certs, "", proof.as_string(), verify_context.get(),
+ &error_details, &details, std::move(callback)));
+}
+
+TEST_P(CryptoServerTest, RejectInvalidXlct) {
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", srct_hex_.c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "VER\0", client_version_string_.c_str(),
+ "XLCT", "#0102030405060708",
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+ // If replay protection isn't disabled, then
+ // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false
+ // and cause ProcessClientHello to exit early (and generate a REJ message).
+ config_.set_replay_protection(false);
+
+ ShouldSucceed(msg);
+ // clang-format off
+ const HandshakeFailureReason kRejectReasons[] = {
+ INVALID_EXPECTED_LEAF_CERTIFICATE
+ };
+ // clang-format on
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+}
+
+TEST_P(CryptoServerTest, ValidXlct) {
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", srct_hex_.c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "NONP", "123456789012345678901234567890",
+ "VER\0", client_version_string_.c_str(),
+ "XLCT", XlctHexString().c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+ // If replay protection isn't disabled, then
+ // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false
+ // and cause ProcessClientHello to exit early (and generate a REJ message).
+ config_.set_replay_protection(false);
+
+ ShouldSucceed(msg);
+ EXPECT_EQ(kSHLO, out_.tag());
+}
+
+TEST_P(CryptoServerTest, NonceInSHLO) {
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", srct_hex_.c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "VER\0", client_version_string_.c_str(),
+ "XLCT", XlctHexString().c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+ // If replay protection isn't disabled, then
+ // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false
+ // and cause ProcessClientHello to exit early (and generate a REJ message).
+ config_.set_replay_protection(false);
+
+ ShouldSucceed(msg);
+ EXPECT_EQ(kSHLO, out_.tag());
+
+ StringPiece nonce;
+ EXPECT_TRUE(out_.GetStringPiece(kServerNonceTag, &nonce));
+}
+
+TEST(CryptoServerConfigGenerationTest, Determinism) {
+ // Test that using a deterministic PRNG causes the server-config to be
+ // deterministic.
+
+ MockRandom rand_a, rand_b;
+ const QuicCryptoServerConfig::ConfigOptions options;
+ MockClock clock;
+
+ QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a,
+ CryptoTestUtils::ProofSourceForTesting());
+ QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b,
+ CryptoTestUtils::ProofSourceForTesting());
+ std::unique_ptr<CryptoHandshakeMessage> scfg_a(
+ a.AddDefaultConfig(&rand_a, &clock, options));
+ std::unique_ptr<CryptoHandshakeMessage> scfg_b(
+ b.AddDefaultConfig(&rand_b, &clock, options));
+
+ ASSERT_EQ(scfg_a->DebugString(), scfg_b->DebugString());
+}
+
+TEST(CryptoServerConfigGenerationTest, SCIDVaries) {
+ // This test ensures that the server config ID varies for different server
+ // configs.
+
+ MockRandom rand_a, rand_b;
+ const QuicCryptoServerConfig::ConfigOptions options;
+ MockClock clock;
+
+ QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a,
+ CryptoTestUtils::ProofSourceForTesting());
+ rand_b.ChangeValue();
+ QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b,
+ CryptoTestUtils::ProofSourceForTesting());
+ std::unique_ptr<CryptoHandshakeMessage> scfg_a(
+ a.AddDefaultConfig(&rand_a, &clock, options));
+ std::unique_ptr<CryptoHandshakeMessage> scfg_b(
+ b.AddDefaultConfig(&rand_b, &clock, options));
+
+ StringPiece scid_a, scid_b;
+ EXPECT_TRUE(scfg_a->GetStringPiece(kSCID, &scid_a));
+ EXPECT_TRUE(scfg_b->GetStringPiece(kSCID, &scid_b));
+
+ EXPECT_NE(scid_a, scid_b);
+}
+
+TEST(CryptoServerConfigGenerationTest, SCIDIsHashOfServerConfig) {
+ MockRandom rand_a;
+ const QuicCryptoServerConfig::ConfigOptions options;
+ MockClock clock;
+
+ QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a,
+ CryptoTestUtils::ProofSourceForTesting());
+ std::unique_ptr<CryptoHandshakeMessage> scfg(
+ a.AddDefaultConfig(&rand_a, &clock, options));
+
+ StringPiece scid;
+ EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid));
+ // Need to take a copy of |scid| has we're about to call |Erase|.
+ const string scid_str(scid.as_string());
+
+ scfg->Erase(kSCID);
+ scfg->MarkDirty();
+ const QuicData& serialized(scfg->GetSerialized());
+
+ std::unique_ptr<crypto::SecureHash> hash(
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+ hash->Update(serialized.data(), serialized.length());
+ uint8_t digest[16];
+ hash->Finish(digest, sizeof(digest));
+
+ ASSERT_EQ(scid.size(), sizeof(digest));
+ EXPECT_EQ(0, memcmp(digest, scid_str.c_str(), sizeof(digest)));
+}
+
+class CryptoServerTestNoConfig : public CryptoServerTest {
+ public:
+ void SetUp() override {
+ // Deliberately don't add a config so that we can test this situation.
+ }
+};
+
+TEST_P(CryptoServerTestNoConfig, DontCrash) {
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+ ShouldFailMentioning("No config", msg);
+
+ const HandshakeFailureReason kRejectReasons[] = {
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+}
+
+class CryptoServerTestOldVersion : public CryptoServerTest {
+ public:
+ void SetUp() override {
+ client_version_ = supported_versions_.back();
+ client_version_string_ =
+ QuicUtils::TagToString(QuicVersionToQuicTag(client_version_));
+ CryptoServerTest::SetUp();
+ }
+};
+
+TEST_P(CryptoServerTestOldVersion, ServerIgnoresXlct) {
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", srct_hex_.c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "VER\0", client_version_string_.c_str(),
+ "XLCT", "#0100000000000000",
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+ // If replay protection isn't disabled, then
+ // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false
+ // and cause ProcessClientHello to exit early (and generate a REJ message).
+ config_.set_replay_protection(false);
+
+ ShouldSucceed(msg);
+ EXPECT_EQ(kSHLO, out_.tag());
+}
+
+TEST_P(CryptoServerTestOldVersion, XlctNotRequired) {
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", srct_hex_.c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+ // If replay protection isn't disabled, then
+ // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false
+ // and cause ProcessClientHello to exit early (and generate a REJ message).
+ config_.set_replay_protection(false);
+
+ ShouldSucceed(msg);
+ EXPECT_EQ(kSHLO, out_.tag());
+}
+
+class AsyncStrikeServerVerificationTest : public CryptoServerTest {
+ protected:
+ AsyncStrikeServerVerificationTest() {}
+
+ void SetUp() override {
+ const string kOrbit = "12345678";
+ config_options_.orbit = kOrbit;
+ strike_register_client_ = new DelayedVerifyStrikeRegisterClient(
+ 10000, // strike_register_max_entries
+ static_cast<uint32_t>(clock_.WallNow().ToUNIXSeconds()),
+ 60, // strike_register_window_secs
+ reinterpret_cast<const uint8_t*>(kOrbit.c_str()),
+ StrikeRegister::NO_STARTUP_PERIOD_NEEDED);
+ config_.SetStrikeRegisterClient(strike_register_client_);
+ ASSERT_NO_FATAL_FAILURE(CryptoServerTest::SetUp());
+ strike_register_client_->StartDelayingVerification();
+ }
+
+ DelayedVerifyStrikeRegisterClient* strike_register_client_;
+};
+
+TEST_P(AsyncStrikeServerVerificationTest, AsyncReplayProtection) {
+ // This tests async validation with a strike register works.
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", srct_hex_.c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "VER\0", client_version_string_.c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+
+ // Clear the message tag.
+ out_.set_tag(0);
+
+ bool called = false;
+ IPAddress server_ip;
+ config_.ValidateClientHello(
+ msg, client_address_.address(), server_ip, client_version_, &clock_,
+ &crypto_proof_, std::unique_ptr<ValidateCallback>(
+ new ValidateCallback(this, true, "", &called)));
+ // The verification request was queued.
+ ASSERT_FALSE(called);
+ EXPECT_EQ(0u, out_.tag());
+ EXPECT_EQ(1, strike_register_client_->PendingVerifications());
+
+ // Continue processing the verification request.
+ strike_register_client_->RunPendingVerifications();
+ ASSERT_TRUE(called);
+ EXPECT_EQ(0, strike_register_client_->PendingVerifications());
+ // The message should be accepted now.
+ EXPECT_EQ(kSHLO, out_.tag());
+
+ // Rejected if replayed.
+ config_.ValidateClientHello(
+ msg, client_address_.address(), server_ip, client_version_, &clock_,
+ &crypto_proof_, std::unique_ptr<ValidateCallback>(
+ new ValidateCallback(this, true, "", &called)));
+ // The verification request was queued.
+ ASSERT_FALSE(called);
+ EXPECT_EQ(1, strike_register_client_->PendingVerifications());
+
+ strike_register_client_->RunPendingVerifications();
+ ASSERT_TRUE(called);
+ EXPECT_EQ(0, strike_register_client_->PendingVerifications());
+ // The message should be rejected now.
+ CheckRejectTag();
+}
+
+TEST_P(AsyncStrikeServerVerificationTest, RequireHandshakeCofirmationPre33) {
+ FLAGS_quic_require_handshake_confirmation = false;
+ FLAGS_quic_require_handshake_confirmation_pre33 = true;
+ // clang-format off
+ CryptoHandshakeMessage msg = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "SNI", "foobar1.example.com",
+ "SCID", scid_hex_.c_str(),
+ "#004b5453", srct_hex_.c_str(),
+ "PUBS", pub_hex_.c_str(),
+ "NONC", nonce_hex_.c_str(),
+ "VER\0", client_version_string_.c_str(),
+ "XLCT", XlctHexString().c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+
+ ShouldSucceed(msg);
+
+ if (client_version_ <= QUIC_VERSION_32) {
+ // clang-format off
+ const HandshakeFailureReason kRejectReasons[] = {
+ SERVER_NONCE_REQUIRED_FAILURE
+ };
+ // clang-format on
+ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
+ EXPECT_EQ(0, strike_register_client_->PendingVerifications());
+ } else {
+ // version 33.
+ ASSERT_EQ(kSHLO, out_.tag());
+ CheckServerHello(out_);
+ }
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/crypto_utils.cc b/chromium/net/quic/core/crypto/crypto_utils.cc
new file mode 100644
index 00000000000..b382339f47e
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_utils.cc
@@ -0,0 +1,340 @@
+// Copyright (c) 2013 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/crypto/crypto_utils.h"
+
+#include <memory>
+
+#include "crypto/hkdf.h"
+#include "crypto/secure_hash.h"
+#include "net/base/url_util.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_time.h"
+#include "net/quic/core/quic_utils.h"
+#include "url/url_canon.h"
+
+using base::StringPiece;
+using std::numeric_limits;
+using std::string;
+
+namespace net {
+
+// static
+void CryptoUtils::GenerateNonce(QuicWallTime now,
+ QuicRandom* random_generator,
+ StringPiece orbit,
+ string* nonce) {
+ // a 4-byte timestamp + 28 random bytes.
+ nonce->reserve(kNonceSize);
+ nonce->resize(kNonceSize);
+
+ uint32_t gmt_unix_time = static_cast<uint32_t>(now.ToUNIXSeconds());
+ // The time in the nonce must be encoded in big-endian because the
+ // strike-register depends on the nonces being ordered by time.
+ (*nonce)[0] = static_cast<char>(gmt_unix_time >> 24);
+ (*nonce)[1] = static_cast<char>(gmt_unix_time >> 16);
+ (*nonce)[2] = static_cast<char>(gmt_unix_time >> 8);
+ (*nonce)[3] = static_cast<char>(gmt_unix_time);
+ size_t bytes_written = 4;
+
+ if (orbit.size() == 8) {
+ memcpy(&(*nonce)[bytes_written], orbit.data(), orbit.size());
+ bytes_written += orbit.size();
+ }
+
+ random_generator->RandBytes(&(*nonce)[bytes_written],
+ kNonceSize - bytes_written);
+}
+
+// static
+bool CryptoUtils::IsValidSNI(StringPiece sni) {
+ // TODO(rtenneti): Support RFC2396 hostname.
+ // NOTE: Microsoft does NOT enforce this spec, so if we throw away hostnames
+ // based on the above spec, we may be losing some hostnames that windows
+ // would consider valid. By far the most common hostname character NOT
+ // accepted by the above spec is '_'.
+ url::CanonHostInfo host_info;
+ string canonicalized_host(CanonicalizeHost(sni.as_string(), &host_info));
+ return !host_info.IsIPAddress() &&
+ IsCanonicalizedHostCompliant(canonicalized_host) &&
+ sni.find_last_of('.') != string::npos;
+}
+
+// static
+string CryptoUtils::NormalizeHostname(const char* hostname) {
+ url::CanonHostInfo host_info;
+ string host(CanonicalizeHost(hostname, &host_info));
+
+ // Walk backwards over the string, stopping at the first trailing dot.
+ size_t host_end = host.length();
+ while (host_end != 0 && host[host_end - 1] == '.') {
+ host_end--;
+ }
+
+ // Erase the trailing dots.
+ if (host_end != host.length()) {
+ host.erase(host_end, host.length() - host_end);
+ }
+ return host;
+}
+
+// static
+bool CryptoUtils::DeriveKeys(StringPiece premaster_secret,
+ QuicTag aead,
+ StringPiece client_nonce,
+ StringPiece server_nonce,
+ const string& hkdf_input,
+ Perspective perspective,
+ Diversification diversification,
+ CrypterPair* crypters,
+ string* subkey_secret) {
+ crypters->encrypter.reset(QuicEncrypter::Create(aead));
+ crypters->decrypter.reset(QuicDecrypter::Create(aead));
+ size_t key_bytes = crypters->encrypter->GetKeySize();
+ size_t nonce_prefix_bytes = crypters->encrypter->GetNoncePrefixSize();
+ size_t subkey_secret_bytes =
+ subkey_secret == nullptr ? 0 : premaster_secret.length();
+
+ StringPiece nonce = client_nonce;
+ string nonce_storage;
+ if (!server_nonce.empty()) {
+ nonce_storage = client_nonce.as_string() + server_nonce.as_string();
+ nonce = nonce_storage;
+ }
+
+ crypto::HKDF hkdf(premaster_secret, nonce, hkdf_input, key_bytes,
+ nonce_prefix_bytes, subkey_secret_bytes);
+
+ // Key derivation depends on the key diversification method being employed.
+ // both the client and the server support never doing key diversification.
+ // The server also supports immediate diversification, and the client
+ // supports pending diversification.
+ switch (diversification.mode()) {
+ case Diversification::NEVER: {
+ if (perspective == Perspective::IS_SERVER) {
+ if (!crypters->encrypter->SetKey(hkdf.server_write_key()) ||
+ !crypters->encrypter->SetNoncePrefix(hkdf.server_write_iv()) ||
+ !crypters->decrypter->SetKey(hkdf.client_write_key()) ||
+ !crypters->decrypter->SetNoncePrefix(hkdf.client_write_iv())) {
+ return false;
+ }
+ } else {
+ if (!crypters->encrypter->SetKey(hkdf.client_write_key()) ||
+ !crypters->encrypter->SetNoncePrefix(hkdf.client_write_iv()) ||
+ !crypters->decrypter->SetKey(hkdf.server_write_key()) ||
+ !crypters->decrypter->SetNoncePrefix(hkdf.server_write_iv())) {
+ return false;
+ }
+ }
+ break;
+ }
+ case Diversification::PENDING: {
+ if (perspective == Perspective::IS_SERVER) {
+ QUIC_BUG << "Pending diversification is only for clients.";
+ return false;
+ }
+
+ if (!crypters->encrypter->SetKey(hkdf.client_write_key()) ||
+ !crypters->encrypter->SetNoncePrefix(hkdf.client_write_iv()) ||
+ !crypters->decrypter->SetPreliminaryKey(hkdf.server_write_key()) ||
+ !crypters->decrypter->SetNoncePrefix(hkdf.server_write_iv())) {
+ return false;
+ }
+ break;
+ }
+ case Diversification::NOW: {
+ if (perspective == Perspective::IS_CLIENT) {
+ QUIC_BUG << "Immediate diversification is only for servers.";
+ return false;
+ }
+
+ string key, nonce_prefix;
+ QuicDecrypter::DiversifyPreliminaryKey(
+ hkdf.server_write_key(), hkdf.server_write_iv(),
+ *diversification.nonce(), key_bytes, nonce_prefix_bytes, &key,
+ &nonce_prefix);
+ if (!crypters->decrypter->SetKey(hkdf.client_write_key()) ||
+ !crypters->decrypter->SetNoncePrefix(hkdf.client_write_iv()) ||
+ !crypters->encrypter->SetKey(key) ||
+ !crypters->encrypter->SetNoncePrefix(nonce_prefix)) {
+ return false;
+ }
+ break;
+ }
+ default:
+ DCHECK(false);
+ }
+
+ if (subkey_secret != nullptr) {
+ hkdf.subkey_secret().CopyToString(subkey_secret);
+ }
+
+ return true;
+}
+
+// static
+bool CryptoUtils::ExportKeyingMaterial(StringPiece subkey_secret,
+ StringPiece label,
+ StringPiece context,
+ size_t result_len,
+ string* result) {
+ for (size_t i = 0; i < label.length(); i++) {
+ if (label[i] == '\0') {
+ LOG(ERROR) << "ExportKeyingMaterial label may not contain NULs";
+ return false;
+ }
+ }
+ // Create HKDF info input: null-terminated label + length-prefixed context
+ if (context.length() >= numeric_limits<uint32_t>::max()) {
+ LOG(ERROR) << "Context value longer than 2^32";
+ return false;
+ }
+ uint32_t context_length = static_cast<uint32_t>(context.length());
+ string info = label.as_string();
+ info.push_back('\0');
+ info.append(reinterpret_cast<char*>(&context_length), sizeof(context_length));
+ info.append(context.data(), context.length());
+
+ crypto::HKDF hkdf(subkey_secret, StringPiece() /* no salt */, info,
+ result_len, 0 /* no fixed IV */, 0 /* no subkey secret */);
+ hkdf.client_write_key().CopyToString(result);
+ return true;
+}
+
+// static
+uint64_t CryptoUtils::ComputeLeafCertHash(const std::string& cert) {
+ return QuicUtils::FNV1a_64_Hash(cert.data(), cert.size());
+}
+
+QuicErrorCode CryptoUtils::ValidateServerHello(
+ const CryptoHandshakeMessage& server_hello,
+ const QuicVersionVector& negotiated_versions,
+ string* error_details) {
+ DCHECK(error_details != nullptr);
+
+ if (server_hello.tag() != kSHLO) {
+ *error_details = "Bad tag";
+ return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
+ }
+
+ const QuicTag* supported_version_tags;
+ size_t num_supported_versions;
+
+ if (server_hello.GetTaglist(kVER, &supported_version_tags,
+ &num_supported_versions) != QUIC_NO_ERROR) {
+ *error_details = "server hello missing version list";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+ if (!negotiated_versions.empty()) {
+ bool mismatch = num_supported_versions != negotiated_versions.size();
+ for (size_t i = 0; i < num_supported_versions && !mismatch; ++i) {
+ mismatch = QuicTagToQuicVersion(supported_version_tags[i]) !=
+ negotiated_versions[i];
+ }
+ // The server sent a list of supported versions, and the connection
+ // reports that there was a version negotiation during the handshake.
+ // Ensure that these two lists are identical.
+ if (mismatch) {
+ *error_details = "Downgrade attack detected";
+ return QUIC_VERSION_NEGOTIATION_MISMATCH;
+ }
+ }
+ return QUIC_NO_ERROR;
+}
+
+QuicErrorCode CryptoUtils::ValidateClientHello(
+ const CryptoHandshakeMessage& client_hello,
+ QuicVersion version,
+ const QuicVersionVector& supported_versions,
+ string* error_details) {
+ if (client_hello.tag() != kCHLO) {
+ *error_details = "Bad tag";
+ return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
+ }
+
+ // If the client's preferred version is not the version we are currently
+ // speaking, then the client went through a version negotiation. In this
+ // case, we need to make sure that we actually do not support this version
+ // and that it wasn't a downgrade attack.
+ QuicTag client_version_tag;
+ if (client_hello.GetUint32(kVER, &client_version_tag) != QUIC_NO_ERROR) {
+ *error_details = "client hello missing version list";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+ QuicVersion client_version = QuicTagToQuicVersion(client_version_tag);
+ if (client_version != version) {
+ // Just because client_version is a valid version enum doesn't mean that
+ // this server actually supports that version, so we check to see if
+ // it's actually in the supported versions list.
+ for (size_t i = 0; i < supported_versions.size(); ++i) {
+ if (client_version == supported_versions[i]) {
+ *error_details = "Downgrade attack detected";
+ return QUIC_VERSION_NEGOTIATION_MISMATCH;
+ }
+ }
+ }
+ return QUIC_NO_ERROR;
+}
+
+#define RETURN_STRING_LITERAL(x) \
+ case x: \
+ return #x
+
+// Returns the name of the HandshakeFailureReason as a char*
+// static
+const char* CryptoUtils::HandshakeFailureReasonToString(
+ HandshakeFailureReason reason) {
+ switch (reason) {
+ RETURN_STRING_LITERAL(HANDSHAKE_OK);
+ RETURN_STRING_LITERAL(CLIENT_NONCE_UNKNOWN_FAILURE);
+ RETURN_STRING_LITERAL(CLIENT_NONCE_INVALID_FAILURE);
+ RETURN_STRING_LITERAL(CLIENT_NONCE_NOT_UNIQUE_FAILURE);
+ RETURN_STRING_LITERAL(CLIENT_NONCE_INVALID_ORBIT_FAILURE);
+ RETURN_STRING_LITERAL(CLIENT_NONCE_INVALID_TIME_FAILURE);
+ RETURN_STRING_LITERAL(CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT);
+ RETURN_STRING_LITERAL(CLIENT_NONCE_STRIKE_REGISTER_FAILURE);
+
+ RETURN_STRING_LITERAL(SERVER_NONCE_DECRYPTION_FAILURE);
+ RETURN_STRING_LITERAL(SERVER_NONCE_INVALID_FAILURE);
+ RETURN_STRING_LITERAL(SERVER_NONCE_NOT_UNIQUE_FAILURE);
+ RETURN_STRING_LITERAL(SERVER_NONCE_INVALID_TIME_FAILURE);
+ RETURN_STRING_LITERAL(SERVER_NONCE_REQUIRED_FAILURE);
+
+ RETURN_STRING_LITERAL(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
+ RETURN_STRING_LITERAL(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
+
+ RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_INVALID_FAILURE);
+ RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE);
+ RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_PARSE_FAILURE);
+ RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE);
+ RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE);
+ RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE);
+
+ RETURN_STRING_LITERAL(INVALID_EXPECTED_LEAF_CERTIFICATE);
+ RETURN_STRING_LITERAL(MAX_FAILURE_REASON);
+ }
+ // Return a default value so that we return this when |reason| doesn't match
+ // any HandshakeFailureReason.. This can happen when the message by the peer
+ // (attacker) has invalid reason.
+ return "INVALID_HANDSHAKE_FAILURE_REASON";
+}
+
+// static
+void CryptoUtils::HashHandshakeMessage(const CryptoHandshakeMessage& message,
+ string* output) {
+ const QuicData& serialized = message.GetSerialized();
+ std::unique_ptr<crypto::SecureHash> hash(
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+ hash->Update(serialized.data(), serialized.length());
+ uint8_t digest[32];
+ hash->Finish(digest, sizeof(digest));
+ output->assign(reinterpret_cast<const char*>(&digest), sizeof(digest));
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/crypto_utils.h b/chromium/net/quic/core/crypto/crypto_utils.h
new file mode 100644
index 00000000000..60a4f0634bb
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_utils.h
@@ -0,0 +1,170 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Some helpers for quic crypto
+
+#ifndef NET_QUIC_CRYPTO_CRYPTO_UTILS_H_
+#define NET_QUIC_CRYPTO_CRYPTO_UTILS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+class QuicTime;
+class QuicRandom;
+struct QuicCryptoNegotiatedParameters;
+
+class NET_EXPORT_PRIVATE CryptoUtils {
+ public:
+ // Diversification is a utility class that's used to act like a union type.
+ // Values can be created by calling the functions like |NoDiversification|,
+ // below.
+ class Diversification {
+ public:
+ enum Mode {
+ NEVER, // Key diversification will never be used. Forward secure
+ // crypters will always use this mode.
+
+ PENDING, // Key diversification will happen when a nonce is later
+ // received. This should only be used by clients initial
+ // decrypters which are waiting on the divesification nonce
+ // from the server.
+
+ NOW, // Key diversification will happen immediate based on the nonce.
+ // This should only be used by servers initial encrypters.
+ };
+
+ Diversification(const Diversification& diversification) = default;
+
+ static Diversification Never() { return Diversification(NEVER, nullptr); }
+ static Diversification Pending() {
+ return Diversification(PENDING, nullptr);
+ }
+ static Diversification Now(DiversificationNonce* nonce) {
+ return Diversification(NOW, nonce);
+ }
+
+ Mode mode() const { return mode_; }
+ DiversificationNonce* nonce() const {
+ DCHECK_EQ(mode_, NOW);
+ return nonce_;
+ }
+
+ private:
+ Diversification(Mode mode, DiversificationNonce* nonce)
+ : mode_(mode), nonce_(nonce) {}
+
+ Mode mode_;
+ DiversificationNonce* nonce_;
+ };
+
+ // Generates the connection nonce. The nonce is formed as:
+ // <4 bytes> current time
+ // <8 bytes> |orbit| (or random if |orbit| is empty)
+ // <20 bytes> random
+ static void GenerateNonce(QuicWallTime now,
+ QuicRandom* random_generator,
+ base::StringPiece orbit,
+ std::string* nonce);
+
+ // Returns true if the sni is valid, false otherwise.
+ // (1) disallow IP addresses;
+ // (2) check that the hostname contains valid characters only; and
+ // (3) contains at least one dot.
+ static bool IsValidSNI(base::StringPiece sni);
+
+ // Convert hostname to lowercase and remove the trailing '.'.
+ // Returns |hostname|. NormalizeHostname() doesn't support IP address
+ // literals. IsValidSNI() should be called before calling NormalizeHostname().
+ static std::string NormalizeHostname(const char* hostname);
+
+ // DeriveKeys populates |crypters->encrypter|, |crypters->decrypter|, and
+ // |subkey_secret| (optional -- may be null) given the contents of
+ // |premaster_secret|, |client_nonce|, |server_nonce| and |hkdf_input|. |aead|
+ // determines which cipher will be used. |perspective| controls whether the
+ // server's keys are assigned to |encrypter| or |decrypter|. |server_nonce| is
+ // optional and, if non-empty, is mixed into the key derivation.
+ // |subkey_secret| will have the same length as |premaster_secret|.
+ //
+ // If the mode of |diversification| is NEVER, the the crypters will be
+ // configured to never perform key diversification. If the mode is
+ // NOW (which is only for servers, then the encrypter will be keyed via a
+ // two-step process that uses the nonce from |diversification|.
+ // If the mode is PENDING (which is only for servres), then the
+ // decrypter will only be keyed to a preliminary state: a call to
+ // |SetDiversificationNonce| with a diversification nonce will be needed to
+ // complete keying.
+ static bool DeriveKeys(base::StringPiece premaster_secret,
+ QuicTag aead,
+ base::StringPiece client_nonce,
+ base::StringPiece server_nonce,
+ const std::string& hkdf_input,
+ Perspective perspective,
+ Diversification diversification,
+ CrypterPair* crypters,
+ std::string* subkey_secret);
+
+ // Performs key extraction to derive a new secret of |result_len| bytes
+ // dependent on |subkey_secret|, |label|, and |context|. Returns false if the
+ // parameters are invalid (e.g. |label| contains null bytes); returns true on
+ // success.
+ static bool ExportKeyingMaterial(base::StringPiece subkey_secret,
+ base::StringPiece label,
+ base::StringPiece context,
+ size_t result_len,
+ std::string* result);
+
+ // Computes the FNV-1a hash of the provided DER-encoded cert for use in the
+ // XLCT tag.
+ static uint64_t ComputeLeafCertHash(const std::string& cert);
+
+ // Validates that |server_hello| is actually an SHLO message and that it is
+ // not part of a downgrade attack.
+ //
+ // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error
+ // code and sets |error_details|.
+ static QuicErrorCode ValidateServerHello(
+ const CryptoHandshakeMessage& server_hello,
+ const QuicVersionVector& negotiated_versions,
+ std::string* error_details);
+
+ // Validates that |client_hello| is actually a CHLO and that this is not part
+ // of a downgrade attack.
+ // This includes verifiying versions and detecting downgrade attacks.
+ //
+ // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error
+ // code and sets |error_details|.
+ static QuicErrorCode ValidateClientHello(
+ const CryptoHandshakeMessage& client_hello,
+ QuicVersion version,
+ const QuicVersionVector& supported_versions,
+ std::string* error_details);
+
+ // Returns the name of the HandshakeFailureReason as a char*
+ static const char* HandshakeFailureReasonToString(
+ HandshakeFailureReason reason);
+
+ // Writes a hash of the serialized |message| into |output|.
+ static void HashHandshakeMessage(const CryptoHandshakeMessage& message,
+ std::string* output);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CryptoUtils);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CRYPTO_UTILS_H_
diff --git a/chromium/net/quic/core/crypto/crypto_utils_test.cc b/chromium/net/quic/core/crypto/crypto_utils_test.cc
new file mode 100644
index 00000000000..34035233799
--- /dev/null
+++ b/chromium/net/quic/core/crypto/crypto_utils_test.cc
@@ -0,0 +1,195 @@
+// Copyright (c) 2013 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/crypto/crypto_utils.h"
+
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+
+namespace net {
+namespace test {
+namespace {
+
+TEST(CryptoUtilsTest, IsValidSNI) {
+ // IP as SNI.
+ EXPECT_FALSE(CryptoUtils::IsValidSNI("192.168.0.1"));
+ // SNI without any dot.
+ EXPECT_FALSE(CryptoUtils::IsValidSNI("somedomain"));
+ // Invalid RFC2396 hostname
+ // TODO(rtenneti): Support RFC2396 hostname.
+ // EXPECT_FALSE(CryptoUtils::IsValidSNI("some_domain.com"));
+ // An empty string must be invalid otherwise the QUIC client will try sending
+ // it.
+ EXPECT_FALSE(CryptoUtils::IsValidSNI(""));
+
+ // Valid SNI
+ EXPECT_TRUE(CryptoUtils::IsValidSNI("test.google.com"));
+}
+
+TEST(CryptoUtilsTest, NormalizeHostname) {
+ struct {
+ const char *input, *expected;
+ } tests[] = {
+ {
+ "www.google.com", "www.google.com",
+ },
+ {
+ "WWW.GOOGLE.COM", "www.google.com",
+ },
+ {
+ "www.google.com.", "www.google.com",
+ },
+ {
+ "www.google.COM.", "www.google.com",
+ },
+ {
+ "www.google.com..", "www.google.com",
+ },
+ {
+ "www.google.com........", "www.google.com",
+ },
+ };
+
+ for (size_t i = 0; i < arraysize(tests); ++i) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "%s", tests[i].input);
+ EXPECT_EQ(string(tests[i].expected), CryptoUtils::NormalizeHostname(buf));
+ }
+}
+
+TEST(CryptoUtilsTest, TestExportKeyingMaterial) {
+ const struct TestVector {
+ // Input (strings of hexadecimal digits):
+ const char* subkey_secret;
+ const char* label;
+ const char* context;
+ size_t result_len;
+
+ // Expected output (string of hexadecimal digits):
+ const char* expected; // Null if it should fail.
+ } test_vector[] = {
+ // Try a typical input
+ {"4823c1189ecc40fce888fbb4cf9ae6254f19ba12e6d9af54788f195a6f509ca3",
+ "e934f78d7a71dd85420fceeb8cea0317",
+ "b8d766b5d3c8aba0009c7ed3de553eba53b4de1030ea91383dcdf724cd8b7217", 32,
+ "a9979da0d5f1c1387d7cbe68f5c4163ddb445a03c4ad6ee72cb49d56726d679e"},
+ // Don't let the label contain nulls
+ {"14fe51e082ffee7d1b4d8d4ab41f8c55", "3132333435363700",
+ "58585858585858585858585858585858", 16, nullptr},
+ // Make sure nulls in the context are fine
+ {"d862c2e36b0a42f7827c67ebc8d44df7", "7a5b95e4e8378123",
+ "4142434445464700", 16, "12d418c6d0738a2e4d85b2d0170f76e1"},
+ // ... and give a different result than without
+ {"d862c2e36b0a42f7827c67ebc8d44df7", "7a5b95e4e8378123", "41424344454647",
+ 16, "abfa1c479a6e3ffb98a11dee7d196408"},
+ // Try weird lengths
+ {"d0ec8a34f6cc9a8c96", "49711798cc6251",
+ "933d4a2f30d22f089cfba842791116adc121e0", 23,
+ "c9a46ed0757bd1812f1f21b4d41e62125fec8364a21db7"},
+ };
+
+ for (size_t i = 0; i < arraysize(test_vector); i++) {
+ // Decode the test vector.
+ string subkey_secret = QuicUtils::HexDecode(test_vector[i].subkey_secret);
+ string label = QuicUtils::HexDecode(test_vector[i].label);
+ string context = QuicUtils::HexDecode(test_vector[i].context);
+ size_t result_len = test_vector[i].result_len;
+ bool expect_ok = test_vector[i].expected != nullptr;
+ string expected;
+ if (expect_ok) {
+ expected = QuicUtils::HexDecode(test_vector[i].expected);
+ }
+
+ string result;
+ bool ok = CryptoUtils::ExportKeyingMaterial(subkey_secret, label, context,
+ result_len, &result);
+ EXPECT_EQ(expect_ok, ok);
+ if (expect_ok) {
+ EXPECT_EQ(result_len, result.length());
+ test::CompareCharArraysWithHexError("HKDF output", result.data(),
+ result.length(), expected.data(),
+ expected.length());
+ }
+ }
+}
+
+TEST(CryptoUtilsTest, HandshakeFailureReasonToString) {
+ EXPECT_STREQ("HANDSHAKE_OK",
+ CryptoUtils::HandshakeFailureReasonToString(HANDSHAKE_OK));
+ EXPECT_STREQ("CLIENT_NONCE_UNKNOWN_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ CLIENT_NONCE_UNKNOWN_FAILURE));
+ EXPECT_STREQ("CLIENT_NONCE_INVALID_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ CLIENT_NONCE_INVALID_FAILURE));
+ EXPECT_STREQ("CLIENT_NONCE_NOT_UNIQUE_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ CLIENT_NONCE_NOT_UNIQUE_FAILURE));
+ EXPECT_STREQ("CLIENT_NONCE_INVALID_ORBIT_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ CLIENT_NONCE_INVALID_ORBIT_FAILURE));
+ EXPECT_STREQ("CLIENT_NONCE_INVALID_TIME_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ CLIENT_NONCE_INVALID_TIME_FAILURE));
+ EXPECT_STREQ("CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT",
+ CryptoUtils::HandshakeFailureReasonToString(
+ CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT));
+ EXPECT_STREQ("CLIENT_NONCE_STRIKE_REGISTER_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ CLIENT_NONCE_STRIKE_REGISTER_FAILURE));
+ EXPECT_STREQ("SERVER_NONCE_DECRYPTION_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ SERVER_NONCE_DECRYPTION_FAILURE));
+ EXPECT_STREQ("SERVER_NONCE_INVALID_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ SERVER_NONCE_INVALID_FAILURE));
+ EXPECT_STREQ("SERVER_NONCE_NOT_UNIQUE_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ SERVER_NONCE_NOT_UNIQUE_FAILURE));
+ EXPECT_STREQ("SERVER_NONCE_INVALID_TIME_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ SERVER_NONCE_INVALID_TIME_FAILURE));
+ EXPECT_STREQ("SERVER_NONCE_REQUIRED_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ SERVER_NONCE_REQUIRED_FAILURE));
+ EXPECT_STREQ("SERVER_CONFIG_INCHOATE_HELLO_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ SERVER_CONFIG_INCHOATE_HELLO_FAILURE));
+ EXPECT_STREQ("SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE));
+ EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_INVALID_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ SOURCE_ADDRESS_TOKEN_INVALID_FAILURE));
+ EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE));
+ EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_PARSE_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ SOURCE_ADDRESS_TOKEN_PARSE_FAILURE));
+ EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE));
+ EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE));
+ EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE));
+ EXPECT_STREQ("INVALID_EXPECTED_LEAF_CERTIFICATE",
+ CryptoUtils::HandshakeFailureReasonToString(
+ INVALID_EXPECTED_LEAF_CERTIFICATE));
+ EXPECT_STREQ("MAX_FAILURE_REASON",
+ CryptoUtils::HandshakeFailureReasonToString(MAX_FAILURE_REASON));
+ EXPECT_STREQ(
+ "INVALID_HANDSHAKE_FAILURE_REASON",
+ CryptoUtils::HandshakeFailureReasonToString(
+ static_cast<HandshakeFailureReason>(MAX_FAILURE_REASON + 1)));
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/curve25519_key_exchange.cc b/chromium/net/quic/core/crypto/curve25519_key_exchange.cc
new file mode 100644
index 00000000000..7bb7e30569f
--- /dev/null
+++ b/chromium/net/quic/core/crypto/curve25519_key_exchange.cc
@@ -0,0 +1,86 @@
+// Copyright (c) 2013 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/crypto/curve25519_key_exchange.h"
+
+#include "base/logging.h"
+#include "crypto/curve25519.h"
+#include "net/quic/core/crypto/quic_random.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+Curve25519KeyExchange::Curve25519KeyExchange() {}
+
+Curve25519KeyExchange::~Curve25519KeyExchange() {}
+
+// static
+Curve25519KeyExchange* Curve25519KeyExchange::New(StringPiece private_key) {
+ Curve25519KeyExchange* ka;
+ // We don't want to #include the NaCl headers in the public header file, so
+ // we use literals for the sizes of private_key_ and public_key_. Here we
+ // assert that those values are equal to the values from the NaCl header.
+ static_assert(sizeof(ka->private_key_) == crypto::curve25519::kScalarBytes,
+ "header out of sync");
+ static_assert(sizeof(ka->public_key_) == crypto::curve25519::kBytes,
+ "header out of sync");
+
+ if (private_key.size() != crypto::curve25519::kScalarBytes) {
+ return nullptr;
+ }
+
+ ka = new Curve25519KeyExchange();
+ memcpy(ka->private_key_, private_key.data(),
+ crypto::curve25519::kScalarBytes);
+ crypto::curve25519::ScalarBaseMult(ka->private_key_, ka->public_key_);
+ return ka;
+}
+
+// static
+string Curve25519KeyExchange::NewPrivateKey(QuicRandom* rand) {
+ uint8_t private_key[crypto::curve25519::kScalarBytes];
+ rand->RandBytes(private_key, sizeof(private_key));
+
+ // This makes |private_key| a valid scalar, as specified on
+ // http://cr.yp.to/ecdh.html
+ private_key[0] &= 248;
+ private_key[31] &= 127;
+ private_key[31] |= 64;
+ return string(reinterpret_cast<char*>(private_key), sizeof(private_key));
+}
+
+KeyExchange* Curve25519KeyExchange::NewKeyPair(QuicRandom* rand) const {
+ const string private_value = NewPrivateKey(rand);
+ return Curve25519KeyExchange::New(private_value);
+}
+
+bool Curve25519KeyExchange::CalculateSharedKey(StringPiece peer_public_value,
+ string* out_result) const {
+ if (peer_public_value.size() != crypto::curve25519::kBytes) {
+ return false;
+ }
+
+ uint8_t result[crypto::curve25519::kBytes];
+ if (!crypto::curve25519::ScalarMult(
+ private_key_,
+ reinterpret_cast<const uint8_t*>(peer_public_value.data()), result)) {
+ return false;
+ }
+ out_result->assign(reinterpret_cast<char*>(result), sizeof(result));
+
+ return true;
+}
+
+StringPiece Curve25519KeyExchange::public_value() const {
+ return StringPiece(reinterpret_cast<const char*>(public_key_),
+ sizeof(public_key_));
+}
+
+QuicTag Curve25519KeyExchange::tag() const {
+ return kC255;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/curve25519_key_exchange.h b/chromium/net/quic/core/crypto/curve25519_key_exchange.h
new file mode 100644
index 00000000000..6f1bfe45db0
--- /dev/null
+++ b/chromium/net/quic/core/crypto/curve25519_key_exchange.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2013 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_CRYPTO_CURVE25519_KEY_EXCHANGE_H_
+#define NET_QUIC_CRYPTO_CURVE25519_KEY_EXCHANGE_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/key_exchange.h"
+
+namespace net {
+
+class QuicRandom;
+
+// Curve25519KeyExchange implements a KeyExchange using elliptic-curve
+// Diffie-Hellman on curve25519. See http://cr.yp.to/ecdh.html
+class NET_EXPORT_PRIVATE Curve25519KeyExchange : public KeyExchange {
+ public:
+ ~Curve25519KeyExchange() override;
+
+ // New creates a new object from a private key. If the private key is
+ // invalid, nullptr is returned.
+ static Curve25519KeyExchange* New(base::StringPiece private_key);
+
+ // NewPrivateKey returns a private key, generated from |rand|, suitable for
+ // passing to |New|.
+ static std::string NewPrivateKey(QuicRandom* rand);
+
+ // KeyExchange interface.
+ KeyExchange* NewKeyPair(QuicRandom* rand) const override;
+ bool CalculateSharedKey(base::StringPiece peer_public_value,
+ std::string* shared_key) const override;
+ base::StringPiece public_value() const override;
+ QuicTag tag() const override;
+
+ private:
+ Curve25519KeyExchange();
+
+ uint8_t private_key_[32];
+ uint8_t public_key_[32];
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CURVE25519_KEY_EXCHANGE_H_
diff --git a/chromium/net/quic/core/crypto/curve25519_key_exchange_test.cc b/chromium/net/quic/core/crypto/curve25519_key_exchange_test.cc
new file mode 100644
index 00000000000..dcd33527c1b
--- /dev/null
+++ b/chromium/net/quic/core/crypto/curve25519_key_exchange_test.cc
@@ -0,0 +1,44 @@
+// Copyright (c) 2013 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/crypto/curve25519_key_exchange.h"
+
+#include <memory>
+
+#include "base/strings/string_piece.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+namespace test {
+
+// SharedKey just tests that the basic key exchange identity holds: that both
+// parties end up with the same key.
+TEST(Curve25519KeyExchange, SharedKey) {
+ QuicRandom* const rand = QuicRandom::GetInstance();
+
+ for (int i = 0; i < 5; i++) {
+ const string alice_key(Curve25519KeyExchange::NewPrivateKey(rand));
+ const string bob_key(Curve25519KeyExchange::NewPrivateKey(rand));
+
+ std::unique_ptr<Curve25519KeyExchange> alice(
+ Curve25519KeyExchange::New(alice_key));
+ std::unique_ptr<Curve25519KeyExchange> bob(
+ Curve25519KeyExchange::New(bob_key));
+
+ const StringPiece alice_public(alice->public_value());
+ const StringPiece bob_public(bob->public_value());
+
+ string alice_shared, bob_shared;
+ ASSERT_TRUE(alice->CalculateSharedKey(bob_public, &alice_shared));
+ ASSERT_TRUE(bob->CalculateSharedKey(alice_public, &bob_shared));
+ ASSERT_EQ(alice_shared, bob_shared);
+ }
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/ephemeral_key_source.h b/chromium/net/quic/core/crypto/ephemeral_key_source.h
new file mode 100644
index 00000000000..e99b687ed98
--- /dev/null
+++ b/chromium/net/quic/core/crypto/ephemeral_key_source.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2013 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_CRYPTO_EPHEMERAL_KEY_SOURCE_H_
+#define NET_QUIC_CRYPTO_EPHEMERAL_KEY_SOURCE_H_
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+class KeyExchange;
+class QuicRandom;
+
+// EphemeralKeySource manages and rotates ephemeral keys as they can be reused
+// for several connections in a short space of time. Since the implementation
+// of this may involve locking or thread-local data, this interface abstracts
+// that away.
+class NET_EXPORT_PRIVATE EphemeralKeySource {
+ public:
+ virtual ~EphemeralKeySource() {}
+
+ // CalculateForwardSecureKey generates an ephemeral public/private key pair
+ // using the algorithm |key_exchange|, sets |*public_value| to the public key
+ // and returns the shared key between |peer_public_value| and the private
+ // key. |*public_value| will be sent to the peer to be used with the peer's
+ // private key.
+ virtual std::string CalculateForwardSecureKey(
+ const KeyExchange* key_exchange,
+ QuicRandom* rand,
+ QuicTime now,
+ base::StringPiece peer_public_value,
+ std::string* public_value) = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_EPHEMERAL_KEY_SOURCE_H_
diff --git a/chromium/net/quic/core/crypto/key_exchange.h b/chromium/net/quic/core/crypto/key_exchange.h
new file mode 100644
index 00000000000..7e4c6f0889b
--- /dev/null
+++ b/chromium/net/quic/core/crypto/key_exchange.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2013 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_CRYPTO_KEY_EXCHANGE_H_
+#define NET_QUIC_CRYPTO_KEY_EXCHANGE_H_
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+
+namespace net {
+
+class QuicRandom;
+
+// KeyExchange is an abstract class that provides an interface to a
+// key-exchange primitive.
+class NET_EXPORT_PRIVATE KeyExchange {
+ public:
+ virtual ~KeyExchange() {}
+
+ // NewKeyPair generates a new public, private key pair. The caller takes
+ // ownership of the return value. (This is intended for servers that need to
+ // generate forward-secure keys.)
+ virtual KeyExchange* NewKeyPair(QuicRandom* rand) const = 0;
+
+ // CalculateSharedKey computes the shared key between the local private key
+ // (which is implicitly known by a KeyExchange object) and a public value
+ // from the peer.
+ virtual bool CalculateSharedKey(base::StringPiece peer_public_value,
+ std::string* shared_key) const = 0;
+
+ // public_value returns the local public key which can be sent to a peer in
+ // order to complete a key exchange. The returned StringPiece is a reference
+ // to a member of the KeyExchange and is only valid for as long as the
+ // KeyExchange exists.
+ virtual base::StringPiece public_value() const = 0;
+
+ // tag returns the tag value that identifies this key exchange function.
+ virtual QuicTag tag() const = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_KEY_EXCHANGE_H_
diff --git a/chromium/net/quic/core/crypto/local_strike_register_client.cc b/chromium/net/quic/core/crypto/local_strike_register_client.cc
new file mode 100644
index 00000000000..bd70e0b320f
--- /dev/null
+++ b/chromium/net/quic/core/crypto/local_strike_register_client.cc
@@ -0,0 +1,52 @@
+// Copyright 2013 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/crypto/local_strike_register_client.h"
+
+#include "net/quic/core/crypto/crypto_protocol.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+LocalStrikeRegisterClient::LocalStrikeRegisterClient(
+ unsigned max_entries,
+ uint32_t current_time_external,
+ uint32_t window_secs,
+ const uint8_t orbit[8],
+ StrikeRegister::StartupType startup)
+ : strike_register_(max_entries,
+ current_time_external,
+ window_secs,
+ orbit,
+ startup) {}
+
+bool LocalStrikeRegisterClient::IsKnownOrbit(StringPiece orbit) const {
+ base::AutoLock lock(m_);
+ if (orbit.length() != kOrbitSize) {
+ return false;
+ }
+ return memcmp(orbit.data(), strike_register_.orbit(), kOrbitSize) == 0;
+}
+
+void LocalStrikeRegisterClient::VerifyNonceIsValidAndUnique(
+ StringPiece nonce,
+ QuicWallTime now,
+ ResultCallback* cb) {
+ InsertStatus nonce_error;
+ if (nonce.length() != kNonceSize) {
+ nonce_error = NONCE_INVALID_FAILURE;
+ } else {
+ base::AutoLock lock(m_);
+ nonce_error =
+ strike_register_.Insert(reinterpret_cast<const uint8_t*>(nonce.data()),
+ static_cast<uint32_t>(now.ToUNIXSeconds()));
+ }
+
+ // m_ must not be held when the ResultCallback runs.
+ cb->Run((nonce_error == NONCE_OK), nonce_error);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/local_strike_register_client.h b/chromium/net/quic/core/crypto/local_strike_register_client.h
new file mode 100644
index 00000000000..f1d043c599e
--- /dev/null
+++ b/chromium/net/quic/core/crypto/local_strike_register_client.h
@@ -0,0 +1,45 @@
+// Copyright 2013 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_CRYPTO_LOCAL_STRIKE_REGISTER_CLIENT_H_
+#define NET_QUIC_CRYPTO_LOCAL_STRIKE_REGISTER_CLIENT_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "base/synchronization/lock.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/strike_register.h"
+#include "net/quic/core/crypto/strike_register_client.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+// StrikeRegisterClient implementation that wraps a local in-memory
+// strike register.
+class NET_EXPORT_PRIVATE LocalStrikeRegisterClient
+ : public StrikeRegisterClient {
+ public:
+ LocalStrikeRegisterClient(unsigned max_entries,
+ uint32_t current_time_external,
+ uint32_t window_secs,
+ const uint8_t orbit[8],
+ StrikeRegister::StartupType startup);
+
+ bool IsKnownOrbit(base::StringPiece orbit) const override;
+ void VerifyNonceIsValidAndUnique(base::StringPiece nonce,
+ QuicWallTime now,
+ ResultCallback* cb) override;
+
+ private:
+ mutable base::Lock m_;
+ StrikeRegister strike_register_;
+
+ DISALLOW_COPY_AND_ASSIGN(LocalStrikeRegisterClient);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_LOCAL_STRIKE_REGISTER_CLIENT_H_
diff --git a/chromium/net/quic/core/crypto/local_strike_register_client_test.cc b/chromium/net/quic/core/crypto/local_strike_register_client_test.cc
new file mode 100644
index 00000000000..e28e627ed44
--- /dev/null
+++ b/chromium/net/quic/core/crypto/local_strike_register_client_test.cc
@@ -0,0 +1,134 @@
+// Copyright 2013 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/crypto/local_strike_register_client.h"
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "base/sys_byteorder.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/quic_time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+namespace test {
+namespace {
+
+class RecordResultCallback : public StrikeRegisterClient::ResultCallback {
+ public:
+ // RecordResultCallback stores the argument to RunImpl in
+ // |*saved_value| and sets |*called| to true. The callback is self
+ // deleting.
+ RecordResultCallback(bool* called,
+ bool* saved_value,
+ InsertStatus* saved_nonce_error)
+ : called_(called),
+ saved_value_(saved_value),
+ saved_nonce_error_(saved_nonce_error) {
+ *called_ = false;
+ }
+
+ protected:
+ void RunImpl(bool nonce_is_valid_and_unique,
+ InsertStatus nonce_error) override {
+ *called_ = true;
+ *saved_value_ = nonce_is_valid_and_unique;
+ *saved_nonce_error_ = nonce_error;
+ }
+
+ private:
+ bool* called_;
+ bool* saved_value_;
+ InsertStatus* saved_nonce_error_;
+
+ DISALLOW_COPY_AND_ASSIGN(RecordResultCallback);
+};
+
+const uint8_t kOrbit[] = "\x12\x34\x56\x78\x9A\xBC\xDE\xF0";
+const uint32_t kCurrentTimeExternalSecs = 12345678;
+size_t kMaxEntries = 100;
+uint32_t kWindowSecs = 60;
+
+class LocalStrikeRegisterClientTest : public ::testing::Test {
+ protected:
+ LocalStrikeRegisterClientTest() {}
+
+ void SetUp() override {
+ strike_register_.reset(new LocalStrikeRegisterClient(
+ kMaxEntries, kCurrentTimeExternalSecs, kWindowSecs, kOrbit,
+ StrikeRegister::NO_STARTUP_PERIOD_NEEDED));
+ }
+
+ std::unique_ptr<LocalStrikeRegisterClient> strike_register_;
+};
+
+TEST_F(LocalStrikeRegisterClientTest, CheckOrbit) {
+ EXPECT_TRUE(strike_register_->IsKnownOrbit(
+ StringPiece(reinterpret_cast<const char*>(kOrbit), kOrbitSize)));
+ EXPECT_FALSE(strike_register_->IsKnownOrbit(
+ StringPiece(reinterpret_cast<const char*>(kOrbit), kOrbitSize - 1)));
+ EXPECT_FALSE(strike_register_->IsKnownOrbit(
+ StringPiece(reinterpret_cast<const char*>(kOrbit), kOrbitSize + 1)));
+ EXPECT_FALSE(strike_register_->IsKnownOrbit(
+ StringPiece(reinterpret_cast<const char*>(kOrbit) + 1, kOrbitSize)));
+}
+
+TEST_F(LocalStrikeRegisterClientTest, IncorrectNonceLength) {
+ string valid_nonce;
+ uint32_t norder = htonl(kCurrentTimeExternalSecs);
+ valid_nonce.assign(reinterpret_cast<const char*>(&norder), sizeof(norder));
+ valid_nonce.append(string(reinterpret_cast<const char*>(kOrbit), kOrbitSize));
+ valid_nonce.append(string(20, '\x17')); // 20 'random' bytes.
+
+ {
+ // Validation fails if you remove a byte from the nonce.
+ bool called = false;
+ bool is_valid = false;
+ InsertStatus nonce_error = NONCE_UNKNOWN_FAILURE;
+ string short_nonce = valid_nonce.substr(0, valid_nonce.length() - 1);
+ strike_register_->VerifyNonceIsValidAndUnique(
+ short_nonce, QuicWallTime::FromUNIXSeconds(kCurrentTimeExternalSecs),
+ new RecordResultCallback(&called, &is_valid, &nonce_error));
+ EXPECT_TRUE(called);
+ EXPECT_FALSE(is_valid);
+ EXPECT_EQ(NONCE_INVALID_FAILURE, nonce_error);
+ }
+
+ {
+ // Validation fails if you add a byte to the nonce.
+ bool called = false;
+ bool is_valid = false;
+ InsertStatus nonce_error = NONCE_UNKNOWN_FAILURE;
+ string long_nonce(valid_nonce);
+ long_nonce.append("a");
+ strike_register_->VerifyNonceIsValidAndUnique(
+ long_nonce, QuicWallTime::FromUNIXSeconds(kCurrentTimeExternalSecs),
+ new RecordResultCallback(&called, &is_valid, &nonce_error));
+ EXPECT_TRUE(called);
+ EXPECT_FALSE(is_valid);
+ EXPECT_EQ(NONCE_INVALID_FAILURE, nonce_error);
+ }
+
+ {
+ // Verify that the base nonce validates was valid.
+ bool called = false;
+ bool is_valid = false;
+ InsertStatus nonce_error = NONCE_UNKNOWN_FAILURE;
+ strike_register_->VerifyNonceIsValidAndUnique(
+ valid_nonce, QuicWallTime::FromUNIXSeconds(kCurrentTimeExternalSecs),
+ new RecordResultCallback(&called, &is_valid, &nonce_error));
+ EXPECT_TRUE(called);
+ EXPECT_TRUE(is_valid);
+ EXPECT_EQ(NONCE_OK, nonce_error);
+ }
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/null_decrypter.cc b/chromium/net/quic/core/crypto/null_decrypter.cc
new file mode 100644
index 00000000000..dabbff59b46
--- /dev/null
+++ b/chromium/net/quic/core/crypto/null_decrypter.cc
@@ -0,0 +1,104 @@
+// 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/crypto/null_decrypter.h"
+
+#include <stdint.h>
+
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_data_reader.h"
+#include "net/quic/core/quic_utils.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+NullDecrypter::NullDecrypter() {}
+
+bool NullDecrypter::SetKey(StringPiece key) {
+ return key.empty();
+}
+
+bool NullDecrypter::SetNoncePrefix(StringPiece nonce_prefix) {
+ return nonce_prefix.empty();
+}
+
+bool NullDecrypter::SetPreliminaryKey(StringPiece key) {
+ QUIC_BUG << "Should not be called";
+ return false;
+}
+
+bool NullDecrypter::SetDiversificationNonce(const DiversificationNonce& nonce) {
+ QUIC_BUG << "Should not be called";
+ return true;
+}
+
+bool NullDecrypter::DecryptPacket(QuicPathId /*path_id*/,
+ QuicPacketNumber /*packet_number*/,
+ StringPiece associated_data,
+ StringPiece ciphertext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) {
+ QuicDataReader reader(ciphertext.data(), ciphertext.length());
+ uint128 hash;
+
+ if (!ReadHash(&reader, &hash)) {
+ return false;
+ }
+
+ StringPiece plaintext = reader.ReadRemainingPayload();
+ if (plaintext.length() > max_output_length) {
+ QUIC_BUG << "Output buffer must be larger than the plaintext.";
+ return false;
+ }
+ if (hash != ComputeHash(associated_data, plaintext)) {
+ return false;
+ }
+ // Copy the plaintext to output.
+ memcpy(output, plaintext.data(), plaintext.length());
+ *output_length = plaintext.length();
+ return true;
+}
+
+StringPiece NullDecrypter::GetKey() const {
+ return StringPiece();
+}
+
+StringPiece NullDecrypter::GetNoncePrefix() const {
+ return StringPiece();
+}
+
+const char* NullDecrypter::cipher_name() const {
+ return "NULL";
+}
+
+uint32_t NullDecrypter::cipher_id() const {
+ return 0;
+}
+
+bool NullDecrypter::ReadHash(QuicDataReader* reader, uint128* hash) {
+ uint64_t lo;
+ uint32_t hi;
+ if (!reader->ReadUInt64(&lo) || !reader->ReadUInt32(&hi)) {
+ return false;
+ }
+ *hash = hi;
+ *hash <<= 64;
+ *hash += lo;
+ return true;
+}
+
+uint128 NullDecrypter::ComputeHash(const StringPiece data1,
+ const StringPiece data2) const {
+ uint128 correct_hash = QuicUtils::FNV1a_128_Hash_Two(
+ data1.data(), data1.length(), data2.data(), data2.length());
+ uint128 mask(UINT64_C(0x0), UINT64_C(0xffffffff));
+ mask <<= 96;
+ correct_hash &= ~mask;
+ return correct_hash;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/null_decrypter.h b/chromium/net/quic/core/crypto/null_decrypter.h
new file mode 100644
index 00000000000..0e5a2202ad9
--- /dev/null
+++ b/chromium/net/quic/core/crypto/null_decrypter.h
@@ -0,0 +1,55 @@
+// 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.
+
+#ifndef NET_QUIC_CRYPTO_NULL_DECRYPTER_H_
+#define NET_QUIC_CRYPTO_NULL_DECRYPTER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+
+namespace net {
+
+class QuicDataReader;
+
+// A NullDecrypter is a QuicDecrypter used before a crypto negotiation
+// has occurred. It does not actually decrypt the payload, but does
+// verify a hash (fnv128) over both the payload and associated data.
+class NET_EXPORT_PRIVATE NullDecrypter : public QuicDecrypter {
+ public:
+ NullDecrypter();
+ ~NullDecrypter() override {}
+
+ // QuicDecrypter implementation
+ bool SetKey(base::StringPiece key) override;
+ bool SetNoncePrefix(base::StringPiece nonce_prefix) override;
+ bool SetPreliminaryKey(base::StringPiece key) override;
+ bool SetDiversificationNonce(const DiversificationNonce& nonce) override;
+ bool DecryptPacket(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ base::StringPiece associated_data,
+ base::StringPiece ciphertext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) override;
+ base::StringPiece GetKey() const override;
+ base::StringPiece GetNoncePrefix() const override;
+
+ const char* cipher_name() const override;
+ uint32_t cipher_id() const override;
+
+ private:
+ bool ReadHash(QuicDataReader* reader, uint128* hash);
+ uint128 ComputeHash(base::StringPiece data1, base::StringPiece data2) const;
+
+ DISALLOW_COPY_AND_ASSIGN(NullDecrypter);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_NULL_DECRYPTER_H_
diff --git a/chromium/net/quic/core/crypto/null_decrypter_test.cc b/chromium/net/quic/core/crypto/null_decrypter_test.cc
new file mode 100644
index 00000000000..d615f344602
--- /dev/null
+++ b/chromium/net/quic/core/crypto/null_decrypter_test.cc
@@ -0,0 +1,67 @@
+// 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/crypto/null_decrypter.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+
+using base::StringPiece;
+
+namespace net {
+namespace test {
+
+class NullDecrypterTest : public ::testing::TestWithParam<bool> {};
+
+TEST_F(NullDecrypterTest, Decrypt) {
+ unsigned char expected[] = {
+ // fnv hash
+ 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13,
+ // payload
+ 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!',
+ };
+ const char* data = reinterpret_cast<const char*>(expected);
+ size_t len = arraysize(expected);
+ NullDecrypter decrypter;
+ char buffer[256];
+ size_t length = 0;
+ ASSERT_TRUE(decrypter.DecryptPacket(kDefaultPathId, 0, "hello world!",
+ StringPiece(data, len), buffer, &length,
+ 256));
+ EXPECT_LT(0u, length);
+ EXPECT_EQ("goodbye!", StringPiece(buffer, length));
+}
+
+TEST_F(NullDecrypterTest, BadHash) {
+ unsigned char expected[] = {
+ // fnv hash
+ 0x46, 0x11, 0xea, 0x5f, 0xcf, 0x1d, 0x66, 0x5b, 0xba, 0xf0, 0xbc, 0xfd,
+ // payload
+ 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!',
+ };
+ const char* data = reinterpret_cast<const char*>(expected);
+ size_t len = arraysize(expected);
+ NullDecrypter decrypter;
+ char buffer[256];
+ size_t length = 0;
+ ASSERT_FALSE(decrypter.DecryptPacket(kDefaultPathId, 0, "hello world!",
+ StringPiece(data, len), buffer, &length,
+ 256));
+}
+
+TEST_F(NullDecrypterTest, ShortInput) {
+ unsigned char expected[] = {
+ // fnv hash (truncated)
+ 0x46, 0x11, 0xea, 0x5f, 0xcf, 0x1d, 0x66, 0x5b, 0xba, 0xf0, 0xbc,
+ };
+ const char* data = reinterpret_cast<const char*>(expected);
+ size_t len = arraysize(expected);
+ NullDecrypter decrypter;
+ char buffer[256];
+ size_t length = 0;
+ ASSERT_FALSE(decrypter.DecryptPacket(kDefaultPathId, 0, "hello world!",
+ StringPiece(data, len), buffer, &length,
+ 256));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/null_encrypter.cc b/chromium/net/quic/core/crypto/null_encrypter.cc
new file mode 100644
index 00000000000..6fbe53fa784
--- /dev/null
+++ b/chromium/net/quic/core/crypto/null_encrypter.cc
@@ -0,0 +1,78 @@
+// 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/crypto/null_encrypter.h"
+
+#include "net/quic/core/quic_data_writer.h"
+#include "net/quic/core/quic_utils.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+const size_t kHashSizeShort = 12; // size of uint128 serialized short
+
+NullEncrypter::NullEncrypter() {}
+
+bool NullEncrypter::SetKey(StringPiece key) {
+ return key.empty();
+}
+
+bool NullEncrypter::SetNoncePrefix(StringPiece nonce_prefix) {
+ return nonce_prefix.empty();
+}
+
+bool NullEncrypter::EncryptPacket(QuicPathId /*path_id*/,
+ QuicPacketNumber /*packet_number*/,
+ StringPiece associated_data,
+ StringPiece plaintext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) {
+ const size_t len = plaintext.size() + GetHashLength();
+ if (max_output_length < len) {
+ return false;
+ }
+ uint128 hash = QuicUtils::FNV1a_128_Hash_Two(
+ associated_data.data(), associated_data.size(), plaintext.data(),
+ plaintext.size());
+ // TODO(ianswett): memmove required for in place encryption. Placing the
+ // hash at the end would allow use of memcpy, doing nothing for in place.
+ memmove(output + GetHashLength(), plaintext.data(), plaintext.length());
+ QuicUtils::SerializeUint128Short(hash,
+ reinterpret_cast<unsigned char*>(output));
+ *output_length = len;
+ return true;
+}
+
+size_t NullEncrypter::GetKeySize() const {
+ return 0;
+}
+
+size_t NullEncrypter::GetNoncePrefixSize() const {
+ return 0;
+}
+
+size_t NullEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const {
+ return ciphertext_size - GetHashLength();
+}
+
+size_t NullEncrypter::GetCiphertextSize(size_t plaintext_size) const {
+ return plaintext_size + GetHashLength();
+}
+
+StringPiece NullEncrypter::GetKey() const {
+ return StringPiece();
+}
+
+StringPiece NullEncrypter::GetNoncePrefix() const {
+ return StringPiece();
+}
+
+size_t NullEncrypter::GetHashLength() const {
+ return kHashSizeShort;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/null_encrypter.h b/chromium/net/quic/core/crypto/null_encrypter.h
new file mode 100644
index 00000000000..5ea31eb67cf
--- /dev/null
+++ b/chromium/net/quic/core/crypto/null_encrypter.h
@@ -0,0 +1,50 @@
+// 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.
+
+#ifndef NET_QUIC_CRYPTO_NULL_ENCRYPTER_H_
+#define NET_QUIC_CRYPTO_NULL_ENCRYPTER_H_
+
+#include <stddef.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+
+namespace net {
+
+// A NullEncrypter is a QuicEncrypter used before a crypto negotiation
+// has occurred. It does not actually encrypt the payload, but does
+// generate a MAC (fnv128) over both the payload and associated data.
+class NET_EXPORT_PRIVATE NullEncrypter : public QuicEncrypter {
+ public:
+ NullEncrypter();
+ ~NullEncrypter() override {}
+
+ // QuicEncrypter implementation
+ bool SetKey(base::StringPiece key) override;
+ bool SetNoncePrefix(base::StringPiece nonce_prefix) override;
+ bool EncryptPacket(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ base::StringPiece associated_data,
+ base::StringPiece plaintext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) override;
+ size_t GetKeySize() const override;
+ size_t GetNoncePrefixSize() const override;
+ size_t GetMaxPlaintextSize(size_t ciphertext_size) const override;
+ size_t GetCiphertextSize(size_t plaintext_size) const override;
+ base::StringPiece GetKey() const override;
+ base::StringPiece GetNoncePrefix() const override;
+
+ private:
+ size_t GetHashLength() const;
+
+ DISALLOW_COPY_AND_ASSIGN(NullEncrypter);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_NULL_ENCRYPTER_H_
diff --git a/chromium/net/quic/core/crypto/null_encrypter_test.cc b/chromium/net/quic/core/crypto/null_encrypter_test.cc
new file mode 100644
index 00000000000..8987807c66b
--- /dev/null
+++ b/chromium/net/quic/core/crypto/null_encrypter_test.cc
@@ -0,0 +1,48 @@
+// 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/crypto/null_encrypter.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+
+using base::StringPiece;
+
+namespace net {
+namespace test {
+
+class NullEncrypterTest : public ::testing::TestWithParam<bool> {};
+
+TEST_F(NullEncrypterTest, Encrypt) {
+ unsigned char expected[] = {
+ // fnv hash
+ 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13,
+ // payload
+ 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!',
+ };
+ NullEncrypter encrypter;
+ char encrypted[256];
+ size_t encrypted_len = 0;
+ ASSERT_TRUE(encrypter.EncryptPacket(kDefaultPathId, 0, "hello world!",
+ "goodbye!", encrypted, &encrypted_len,
+ 256));
+ test::CompareCharArraysWithHexError(
+ "encrypted data", encrypted, encrypted_len,
+ reinterpret_cast<const char*>(expected), arraysize(expected));
+}
+
+TEST_F(NullEncrypterTest, GetMaxPlaintextSize) {
+ NullEncrypter encrypter;
+ EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1012));
+ EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(112));
+ EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(22));
+}
+
+TEST_F(NullEncrypterTest, GetCiphertextSize) {
+ NullEncrypter encrypter;
+ EXPECT_EQ(1012u, encrypter.GetCiphertextSize(1000));
+ EXPECT_EQ(112u, encrypter.GetCiphertextSize(100));
+ EXPECT_EQ(22u, encrypter.GetCiphertextSize(10));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/p256_key_exchange.cc b/chromium/net/quic/core/crypto/p256_key_exchange.cc
new file mode 100644
index 00000000000..6e401a6ace0
--- /dev/null
+++ b/chromium/net/quic/core/crypto/p256_key_exchange.cc
@@ -0,0 +1,119 @@
+// Copyright (c) 2013 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/crypto/p256_key_exchange.h"
+
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/evp.h>
+
+#include "base/logging.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+P256KeyExchange::P256KeyExchange(EC_KEY* private_key, const uint8_t* public_key)
+ : private_key_(private_key) {
+ memcpy(public_key_, public_key, sizeof(public_key_));
+}
+
+P256KeyExchange::~P256KeyExchange() {}
+
+// static
+P256KeyExchange* P256KeyExchange::New(StringPiece key) {
+ if (key.empty()) {
+ DVLOG(1) << "Private key is empty";
+ return nullptr;
+ }
+
+ const uint8_t* keyp = reinterpret_cast<const uint8_t*>(key.data());
+ crypto::ScopedEC_KEY private_key(
+ d2i_ECPrivateKey(nullptr, &keyp, key.size()));
+ if (!private_key.get() || !EC_KEY_check_key(private_key.get())) {
+ DVLOG(1) << "Private key is invalid.";
+ return nullptr;
+ }
+
+ uint8_t public_key[kUncompressedP256PointBytes];
+ if (EC_POINT_point2oct(EC_KEY_get0_group(private_key.get()),
+ EC_KEY_get0_public_key(private_key.get()),
+ POINT_CONVERSION_UNCOMPRESSED, public_key,
+ sizeof(public_key), nullptr) != sizeof(public_key)) {
+ DVLOG(1) << "Can't get public key.";
+ return nullptr;
+ }
+
+ return new P256KeyExchange(private_key.release(), public_key);
+}
+
+// static
+string P256KeyExchange::NewPrivateKey() {
+ crypto::ScopedEC_KEY key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+ if (!key.get() || !EC_KEY_generate_key(key.get())) {
+ DVLOG(1) << "Can't generate a new private key.";
+ return string();
+ }
+
+ int key_len = i2d_ECPrivateKey(key.get(), nullptr);
+ if (key_len <= 0) {
+ DVLOG(1) << "Can't convert private key to string";
+ return string();
+ }
+ std::unique_ptr<uint8_t[]> private_key(new uint8_t[key_len]);
+ uint8_t* keyp = private_key.get();
+ if (!i2d_ECPrivateKey(key.get(), &keyp)) {
+ DVLOG(1) << "Can't convert private key to string.";
+ return string();
+ }
+ return string(reinterpret_cast<char*>(private_key.get()), key_len);
+}
+
+KeyExchange* P256KeyExchange::NewKeyPair(QuicRandom* /*rand*/) const {
+ // TODO(agl): avoid the serialisation/deserialisation in this function.
+ const string private_value = NewPrivateKey();
+ return P256KeyExchange::New(private_value);
+}
+
+bool P256KeyExchange::CalculateSharedKey(StringPiece peer_public_value,
+ string* out_result) const {
+ if (peer_public_value.size() != kUncompressedP256PointBytes) {
+ DVLOG(1) << "Peer public value is invalid";
+ return false;
+ }
+
+ crypto::ScopedEC_POINT point(
+ EC_POINT_new(EC_KEY_get0_group(private_key_.get())));
+ if (!point ||
+ !EC_POINT_oct2point(/* also test if point is on curve */
+ EC_KEY_get0_group(private_key_.get()), point.get(),
+ reinterpret_cast<const uint8_t*>(
+ peer_public_value.data()),
+ peer_public_value.size(), nullptr)) {
+ DVLOG(1) << "Can't convert peer public value to curve point.";
+ return false;
+ }
+
+ uint8_t result[kP256FieldBytes];
+ if (ECDH_compute_key(result, sizeof(result), point.get(), private_key_.get(),
+ nullptr) != sizeof(result)) {
+ DVLOG(1) << "Can't compute ECDH shared key.";
+ return false;
+ }
+
+ out_result->assign(reinterpret_cast<char*>(result), sizeof(result));
+ return true;
+}
+
+StringPiece P256KeyExchange::public_value() const {
+ return StringPiece(reinterpret_cast<const char*>(public_key_),
+ sizeof(public_key_));
+}
+
+QuicTag P256KeyExchange::tag() const {
+ return kP256;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/p256_key_exchange.h b/chromium/net/quic/core/crypto/p256_key_exchange.h
new file mode 100644
index 00000000000..e6b32a2b771
--- /dev/null
+++ b/chromium/net/quic/core/crypto/p256_key_exchange.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2013 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_CRYPTO_P256_KEY_EXCHANGE_H_
+#define NET_QUIC_CRYPTO_P256_KEY_EXCHANGE_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "crypto/openssl_util.h"
+#include "crypto/scoped_openssl_types.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/key_exchange.h"
+
+
+namespace net {
+
+// P256KeyExchange implements a KeyExchange using elliptic-curve
+// Diffie-Hellman on NIST P-256.
+class NET_EXPORT_PRIVATE P256KeyExchange : public KeyExchange {
+ public:
+ ~P256KeyExchange() override;
+
+ // New creates a new key exchange object from a private key. If
+ // |private_key| is invalid, nullptr is returned.
+ static P256KeyExchange* New(base::StringPiece private_key);
+
+ // |NewPrivateKey| returns a private key, suitable for passing to |New|.
+ // If |NewPrivateKey| can't generate a private key, it returns an empty
+ // string.
+ static std::string NewPrivateKey();
+
+ // KeyExchange interface.
+ KeyExchange* NewKeyPair(QuicRandom* rand) const override;
+ bool CalculateSharedKey(base::StringPiece peer_public_value,
+ std::string* shared_key) const override;
+ base::StringPiece public_value() const override;
+ QuicTag tag() const override;
+
+ private:
+ enum {
+ // A P-256 field element consists of 32 bytes.
+ kP256FieldBytes = 32,
+ // A P-256 point in uncompressed form consists of 0x04 (to denote
+ // that the point is uncompressed) followed by two, 32-byte field
+ // elements.
+ kUncompressedP256PointBytes = 1 + 2 * kP256FieldBytes,
+ // The first byte in an uncompressed P-256 point.
+ kUncompressedECPointForm = 0x04,
+ };
+
+ // P256KeyExchange takes ownership of |private_key|, and expects
+ // |public_key| consists of |kUncompressedP256PointBytes| bytes.
+ P256KeyExchange(EC_KEY* private_key, const uint8_t* public_key);
+
+ crypto::ScopedEC_KEY private_key_;
+ // The public key stored as an uncompressed P-256 point.
+ uint8_t public_key_[kUncompressedP256PointBytes];
+
+ DISALLOW_COPY_AND_ASSIGN(P256KeyExchange);
+};
+
+} // namespace net
+#endif // NET_QUIC_CRYPTO_P256_KEY_EXCHANGE_H_
diff --git a/chromium/net/quic/core/crypto/p256_key_exchange_test.cc b/chromium/net/quic/core/crypto/p256_key_exchange_test.cc
new file mode 100644
index 00000000000..7f6812288f1
--- /dev/null
+++ b/chromium/net/quic/core/crypto/p256_key_exchange_test.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2013 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/crypto/p256_key_exchange.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+
+namespace net {
+namespace test {
+
+// SharedKey just tests that the basic key exchange identity holds: that both
+// parties end up with the same key.
+TEST(P256KeyExchange, SharedKey) {
+ for (int i = 0; i < 5; i++) {
+ string alice_private(P256KeyExchange::NewPrivateKey());
+ string bob_private(P256KeyExchange::NewPrivateKey());
+
+ ASSERT_FALSE(alice_private.empty());
+ ASSERT_FALSE(bob_private.empty());
+ ASSERT_NE(alice_private, bob_private);
+
+ std::unique_ptr<P256KeyExchange> alice(P256KeyExchange::New(alice_private));
+ std::unique_ptr<P256KeyExchange> bob(P256KeyExchange::New(bob_private));
+
+ ASSERT_TRUE(alice.get() != nullptr);
+ ASSERT_TRUE(bob.get() != nullptr);
+
+ const base::StringPiece alice_public(alice->public_value());
+ const base::StringPiece bob_public(bob->public_value());
+
+ std::string alice_shared, bob_shared;
+ ASSERT_TRUE(alice->CalculateSharedKey(bob_public, &alice_shared));
+ ASSERT_TRUE(bob->CalculateSharedKey(alice_public, &bob_shared));
+ ASSERT_EQ(alice_shared, bob_shared);
+ }
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/proof_source.cc b/chromium/net/quic/core/crypto/proof_source.cc
new file mode 100644
index 00000000000..9a72345f090
--- /dev/null
+++ b/chromium/net/quic/core/crypto/proof_source.cc
@@ -0,0 +1,14 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/crypto/proof_source.h"
+
+namespace net {
+
+ProofSource::Chain::Chain(const std::vector<std::string>& certs)
+ : certs(certs) {}
+
+ProofSource::Chain::~Chain() {}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/proof_source.h b/chromium/net/quic/core/crypto/proof_source.h
new file mode 100644
index 00000000000..b97f3856f5f
--- /dev/null
+++ b/chromium/net/quic/core/crypto/proof_source.h
@@ -0,0 +1,136 @@
+// Copyright (c) 2013 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_CRYPTO_PROOF_SOURCE_H_
+#define NET_QUIC_CRYPTO_PROOF_SOURCE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+class IPAddress;
+
+// ProofSource is an interface by which a QUIC server can obtain certificate
+// chains and signatures that prove its identity.
+class NET_EXPORT_PRIVATE ProofSource {
+ public:
+ // Chain is a reference-counted wrapper for a std::vector of std::stringified
+ // certificates.
+ struct NET_EXPORT_PRIVATE Chain : public base::RefCounted<Chain> {
+ explicit Chain(const std::vector<std::string>& certs);
+
+ const std::vector<std::string> certs;
+
+ private:
+ friend class base::RefCounted<Chain>;
+
+ virtual ~Chain();
+
+ DISALLOW_COPY_AND_ASSIGN(Chain);
+ };
+
+ // Details is an abstract class which acts as a container for any
+ // implementation-specific details that a ProofSource wants to return.
+ class Details {
+ public:
+ virtual ~Details() {}
+ };
+
+ // Callback base class for receiving the results of an async call to GetProof.
+ class Callback {
+ public:
+ Callback() {}
+ virtual ~Callback() {}
+
+ // Invoked upon completion of GetProof.
+ //
+ // |ok| indicates whether the operation completed successfully. If false,
+ // the values of the remaining three arguments are undefined.
+ //
+ // |chain| is a reference-counted pointer to an object representing the
+ // certificate chain.
+ //
+ // |signature| contains the signature of the server config.
+ //
+ // |leaf_cert_sct| holds the signed timestamp (RFC6962) of the leaf cert.
+ //
+ // |details| holds a pointer to an object representing the statistics, if
+ // any, gathered during the operation of GetProof. If no stats are
+ // available, this will be nullptr.
+ virtual void Run(bool ok,
+ const scoped_refptr<Chain>& chain,
+ const std::string& signature,
+ const std::string& leaf_cert_sct,
+ std::unique_ptr<Details> details) = 0;
+
+ private:
+ Callback(const Callback&) = delete;
+ Callback& operator=(const Callback&) = delete;
+ };
+
+ virtual ~ProofSource() {}
+
+ // GetProof finds a certificate chain for |hostname|, sets |out_chain| to
+ // point to it (in leaf-first order), calculates a signature of
+ // |server_config| using that chain and puts the result in |out_signature|.
+ //
+ // The signature uses SHA-256 as the hash function and PSS padding when the
+ // key is RSA.
+ //
+ // The signature uses SHA-256 as the hash function when the key is ECDSA.
+ // The signature may use an ECDSA key.
+ //
+ // |out_chain| is reference counted to avoid the (assumed) expense of copying
+ // out the certificates.
+ //
+ // The number of certificate chains is expected to be small and fixed, thus
+ // the ProofSource retains ownership of the contents of |out_chain|. The
+ // expectation is that they will be cached forever.
+ //
+ // For version before QUIC_VERSION_30, the signature values should be cached
+ // because |server_config| will be somewhat static. However, since they aren't
+ // bounded, the ProofSource may wish to evict entries from that cache, thus
+ // the caller takes ownership of |*out_signature|.
+ //
+ // For QUIC_VERSION_30 and later, the signature depends on |chlo_hash|
+ // which means that the signature can not be cached. The caller takes
+ // ownership of |*out_signature|.
+ //
+ // |hostname| may be empty to signify that a default certificate should be
+ // used.
+ //
+ // |out_leaf_cert_sct| points to the signed timestamp (RFC6962) of the leaf
+ // cert.
+ //
+ // This function may be called concurrently.
+ virtual bool GetProof(const IPAddress& server_ip,
+ const std::string& hostname,
+ const std::string& server_config,
+ QuicVersion quic_version,
+ base::StringPiece chlo_hash,
+ scoped_refptr<Chain>* out_chain,
+ std::string* out_signature,
+ std::string* out_leaf_cert_sct) = 0;
+
+ // Async version of GetProof with identical semantics, except that the results
+ // are delivered to |callback|. Callers should expect that |callback| might
+ // be invoked synchronously. The ProofSource takes ownership of |callback| in
+ // any case.
+ virtual void GetProof(const IPAddress& server_ip,
+ const std::string& hostname,
+ const std::string& server_config,
+ QuicVersion quic_version,
+ base::StringPiece chlo_hash,
+ std::unique_ptr<Callback> callback) = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_PROOF_SOURCE_H_
diff --git a/chromium/net/quic/core/crypto/proof_verifier.h b/chromium/net/quic/core/crypto/proof_verifier.h
new file mode 100644
index 00000000000..c87b5c8ccfe
--- /dev/null
+++ b/chromium/net/quic/core/crypto/proof_verifier.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2013 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_CRYPTO_PROOF_VERIFIER_H_
+#define NET_QUIC_CRYPTO_PROOF_VERIFIER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_types.h"
+
+namespace net {
+
+// ProofVerifyDetails is an abstract class that acts as a container for any
+// implementation specific details that a ProofVerifier wishes to return. These
+// details are saved in the CachedState for the origin in question.
+class NET_EXPORT_PRIVATE ProofVerifyDetails {
+ public:
+ virtual ~ProofVerifyDetails() {}
+
+ // Returns an new ProofVerifyDetails object with the same contents
+ // as this one.
+ virtual ProofVerifyDetails* Clone() const = 0;
+};
+
+// ProofVerifyContext is an abstract class that acts as a container for any
+// implementation specific context that a ProofVerifier needs.
+class NET_EXPORT_PRIVATE ProofVerifyContext {
+ public:
+ virtual ~ProofVerifyContext() {}
+};
+
+// ProofVerifierCallback provides a generic mechanism for a ProofVerifier to
+// call back after an asynchronous verification.
+class NET_EXPORT_PRIVATE ProofVerifierCallback {
+ public:
+ virtual ~ProofVerifierCallback() {}
+
+ // Run is called on the original thread to mark the completion of an
+ // asynchonous verification. If |ok| is true then the certificate is valid
+ // and |error_details| is unused. Otherwise, |error_details| contains a
+ // description of the error. |details| contains implementation-specific
+ // details of the verification. |Run| may take ownership of |details| by
+ // calling |release| on it.
+ virtual void Run(bool ok,
+ const std::string& error_details,
+ std::unique_ptr<ProofVerifyDetails>* details) = 0;
+};
+
+// A ProofVerifier checks the signature on a server config, and the certificate
+// chain that backs the public key.
+class NET_EXPORT_PRIVATE ProofVerifier {
+ public:
+ virtual ~ProofVerifier() {}
+
+ // VerifyProof checks that |signature| is a valid signature of
+ // |server_config| by the public key in the leaf certificate of |certs|, and
+ // that |certs| is a valid chain for |hostname|. On success, it returns
+ // QUIC_SUCCESS. On failure, it returns QUIC_FAILURE and sets |*error_details|
+ // to a description of the problem. In either case it may set |*details|,
+ // which the caller takes ownership of.
+ //
+ // |context| specifies an implementation specific struct (which may be nullptr
+ // for some implementations) that provides useful information for the
+ // verifier, e.g. logging handles.
+ //
+ // This function may also return QUIC_PENDING, in which case the ProofVerifier
+ // will call back, on the original thread, via |callback| when complete.
+ //
+ // The signature uses SHA-256 as the hash function and PSS padding in the
+ // case of RSA.
+ virtual QuicAsyncStatus VerifyProof(
+ const std::string& hostname,
+ const uint16_t port,
+ const std::string& server_config,
+ QuicVersion quic_version,
+ base::StringPiece chlo_hash,
+ const std::vector<std::string>& certs,
+ const std::string& cert_sct,
+ const std::string& signature,
+ const ProofVerifyContext* context,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* details,
+ std::unique_ptr<ProofVerifierCallback> callback) = 0;
+
+ // VerifyCertChain checks that |certs| is a valid chain for |hostname|. On
+ // success, it returns QUIC_SUCCESS. On failure, it returns QUIC_FAILURE and
+ // sets |*error_details| to a description of the problem. In either case it
+ // may set |*details|, which the caller takes ownership of.
+ //
+ // |context| specifies an implementation specific struct (which may be nullptr
+ // for some implementations) that provides useful information for the
+ // verifier, e.g. logging handles.
+ //
+ // This function may also return QUIC_PENDING, in which case the ProofVerifier
+ // will call back, on the original thread, via |callback| when complete.
+ // In this case, the ProofVerifier will take ownership of |callback|.
+ virtual QuicAsyncStatus VerifyCertChain(
+ const std::string& hostname,
+ const std::vector<std::string>& certs,
+ const ProofVerifyContext* context,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* details,
+ std::unique_ptr<ProofVerifierCallback> callback) = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_PROOF_VERIFIER_H_
diff --git a/chromium/net/quic/core/crypto/properties_based_quic_server_info.cc b/chromium/net/quic/core/crypto/properties_based_quic_server_info.cc
new file mode 100644
index 00000000000..0ab4f6cef1a
--- /dev/null
+++ b/chromium/net/quic/core/crypto/properties_based_quic_server_info.cc
@@ -0,0 +1,107 @@
+// Copyright 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.
+
+#include "net/quic/core/crypto/properties_based_quic_server_info.h"
+
+#include "base/base64.h"
+#include "base/metrics/histogram_macros.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_server_properties.h"
+
+using std::string;
+
+namespace {
+
+void RecordQuicServerInfoStatus(
+ net::QuicServerInfo::QuicServerInfoAPICall call) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Net.QuicDiskCache.APICall.PropertiesBasedCache", call,
+ net::QuicServerInfo::QUIC_SERVER_INFO_NUM_OF_API_CALLS);
+}
+
+void RecordQuicServerInfoFailure(net::QuicServerInfo::FailureReason failure) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Net.QuicDiskCache.FailureReason.PropertiesBasedCache", failure,
+ net::QuicServerInfo::NUM_OF_FAILURES);
+}
+
+} // namespace
+
+namespace net {
+
+PropertiesBasedQuicServerInfo::PropertiesBasedQuicServerInfo(
+ const QuicServerId& server_id,
+ HttpServerProperties* http_server_properties)
+ : QuicServerInfo(server_id),
+ http_server_properties_(http_server_properties) {
+ DCHECK(http_server_properties_);
+}
+
+PropertiesBasedQuicServerInfo::~PropertiesBasedQuicServerInfo() {}
+
+void PropertiesBasedQuicServerInfo::Start() {
+ RecordQuicServerInfoStatus(QUIC_SERVER_INFO_START);
+}
+
+int PropertiesBasedQuicServerInfo::WaitForDataReady(
+ const CompletionCallback& callback) {
+ RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY);
+ const string* data = http_server_properties_->GetQuicServerInfo(server_id_);
+ string decoded;
+ if (!data) {
+ RecordQuicServerInfoFailure(PARSE_NO_DATA_FAILURE);
+ return ERR_FAILED;
+ }
+ if (!base::Base64Decode(*data, &decoded)) {
+ RecordQuicServerInfoFailure(PARSE_DATA_DECODE_FAILURE);
+ return ERR_FAILED;
+ }
+ RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PARSE);
+ if (!Parse(decoded)) {
+ RecordQuicServerInfoFailure(PARSE_FAILURE);
+ return ERR_FAILED;
+ }
+ return OK;
+}
+
+void PropertiesBasedQuicServerInfo::ResetWaitForDataReadyCallback() {
+ RecordQuicServerInfoStatus(QUIC_SERVER_INFO_RESET_WAIT_FOR_DATA_READY);
+}
+
+void PropertiesBasedQuicServerInfo::CancelWaitForDataReadyCallback() {
+ RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL);
+}
+
+bool PropertiesBasedQuicServerInfo::IsDataReady() {
+ return true;
+}
+
+bool PropertiesBasedQuicServerInfo::IsReadyToPersist() {
+ RecordQuicServerInfoStatus(QUIC_SERVER_INFO_READY_TO_PERSIST);
+ return true;
+}
+
+void PropertiesBasedQuicServerInfo::Persist() {
+ RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PERSIST);
+ string encoded;
+ base::Base64Encode(Serialize(), &encoded);
+ http_server_properties_->SetQuicServerInfo(server_id_, encoded);
+}
+
+void PropertiesBasedQuicServerInfo::OnExternalCacheHit() {
+ RecordQuicServerInfoStatus(QUIC_SERVER_INFO_EXTERNAL_CACHE_HIT);
+}
+
+PropertiesBasedQuicServerInfoFactory::PropertiesBasedQuicServerInfoFactory(
+ HttpServerProperties* http_server_properties)
+ : http_server_properties_(http_server_properties) {}
+
+PropertiesBasedQuicServerInfoFactory::~PropertiesBasedQuicServerInfoFactory() {}
+
+QuicServerInfo* PropertiesBasedQuicServerInfoFactory::GetForServer(
+ const QuicServerId& server_id) {
+ return new PropertiesBasedQuicServerInfo(server_id, http_server_properties_);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/properties_based_quic_server_info.h b/chromium/net/quic/core/crypto/properties_based_quic_server_info.h
new file mode 100644
index 00000000000..276c8ef6c4a
--- /dev/null
+++ b/chromium/net/quic/core/crypto/properties_based_quic_server_info.h
@@ -0,0 +1,63 @@
+// Copyright 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.
+
+#ifndef NET_QUIC_CRYPTO_PROPERTIES_BASED_QUIC_SERVER_INFO_H_
+#define NET_QUIC_CRYPTO_PROPERTIES_BASED_QUIC_SERVER_INFO_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/quic_server_info.h"
+
+namespace net {
+
+class HttpServerProperties;
+
+// PropertiesBasedQuicServerInfo fetches information about a QUIC server from
+// HttpServerProperties. Since the information is defined to be non-sensitive,
+// it's ok for us to keep it on disk.
+class NET_EXPORT_PRIVATE PropertiesBasedQuicServerInfo : public QuicServerInfo {
+ public:
+ PropertiesBasedQuicServerInfo(const QuicServerId& server_id,
+ HttpServerProperties* http_server_properties);
+ ~PropertiesBasedQuicServerInfo() override;
+
+ // QuicServerInfo implementation.
+ void Start() override;
+ int WaitForDataReady(const CompletionCallback& callback) override;
+ void ResetWaitForDataReadyCallback() override;
+ void CancelWaitForDataReadyCallback() override;
+ bool IsDataReady() override;
+ bool IsReadyToPersist() override;
+ void Persist() override;
+ void OnExternalCacheHit() override;
+
+ private:
+ HttpServerProperties* http_server_properties_;
+
+ DISALLOW_COPY_AND_ASSIGN(PropertiesBasedQuicServerInfo);
+};
+
+class NET_EXPORT_PRIVATE PropertiesBasedQuicServerInfoFactory
+ : public QuicServerInfoFactory {
+ public:
+ explicit PropertiesBasedQuicServerInfoFactory(
+ HttpServerProperties* http_server_properties);
+ ~PropertiesBasedQuicServerInfoFactory() override;
+
+ QuicServerInfo* GetForServer(const QuicServerId& server_id) override;
+
+ private:
+ HttpServerProperties* http_server_properties_;
+
+ DISALLOW_COPY_AND_ASSIGN(PropertiesBasedQuicServerInfoFactory);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_PROPERTIES_BASED_QUIC_SERVER_INFO_H_
diff --git a/chromium/net/quic/core/crypto/properties_based_quic_server_info_test.cc b/chromium/net/quic/core/crypto/properties_based_quic_server_info_test.cc
new file mode 100644
index 00000000000..747905f122e
--- /dev/null
+++ b/chromium/net/quic/core/crypto/properties_based_quic_server_info_test.cc
@@ -0,0 +1,110 @@
+// Copyright 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.
+
+#include "net/quic/core/crypto/properties_based_quic_server_info.h"
+
+#include <string>
+
+#include "net/base/net_errors.h"
+#include "net/http/http_server_properties_impl.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+namespace {
+const char kServerConfigA[] = "server_config_a";
+const char kSourceAddressTokenA[] = "source_address_token_a";
+const char kCertSCTA[] = "cert_sct_a";
+const char kChloHashA[] = "chlo_hash_a";
+const char kServerConfigSigA[] = "server_config_sig_a";
+const char kCertA[] = "cert_a";
+const char kCertB[] = "cert_b";
+} // namespace
+
+class PropertiesBasedQuicServerInfoTest : public ::testing::Test {
+ protected:
+ PropertiesBasedQuicServerInfoTest()
+ : server_id_("www.google.com", 443, PRIVACY_MODE_DISABLED),
+ server_info_(server_id_, &http_server_properties_) {}
+
+ // Initialize |server_info_| object and persist it.
+ void InitializeAndPersist() {
+ server_info_.Start();
+ EXPECT_TRUE(server_info_.IsDataReady());
+ QuicServerInfo::State* state = server_info_.mutable_state();
+ EXPECT_TRUE(state->certs.empty());
+
+ state->server_config = kServerConfigA;
+ state->source_address_token = kSourceAddressTokenA;
+ state->server_config_sig = kServerConfigSigA;
+ state->cert_sct = kCertSCTA;
+ state->chlo_hash = kChloHashA;
+ state->certs.push_back(kCertA);
+ EXPECT_TRUE(server_info_.IsReadyToPersist());
+ server_info_.Persist();
+ EXPECT_TRUE(server_info_.IsReadyToPersist());
+ EXPECT_TRUE(server_info_.IsDataReady());
+ server_info_.OnExternalCacheHit();
+ }
+
+ // Verify the data that is persisted in InitializeAndPersist().
+ void VerifyInitialData(const QuicServerInfo::State& state) {
+ EXPECT_EQ(kServerConfigA, state.server_config);
+ EXPECT_EQ(kSourceAddressTokenA, state.source_address_token);
+ EXPECT_EQ(kCertSCTA, state.cert_sct);
+ EXPECT_EQ(kChloHashA, state.chlo_hash);
+ EXPECT_EQ(kServerConfigSigA, state.server_config_sig);
+ EXPECT_EQ(kCertA, state.certs[0]);
+ }
+
+ HttpServerPropertiesImpl http_server_properties_;
+ QuicServerId server_id_;
+ PropertiesBasedQuicServerInfo server_info_;
+ CompletionCallback callback_;
+};
+
+// Test persisting, reading and verifying and then updating and verifing.
+TEST_F(PropertiesBasedQuicServerInfoTest, Update) {
+ InitializeAndPersist();
+
+ // Read the persisted data and verify we have read the data correctly.
+ PropertiesBasedQuicServerInfo server_info1(server_id_,
+ &http_server_properties_);
+ server_info1.Start();
+ EXPECT_THAT(server_info1.WaitForDataReady(callback_),
+ IsOk()); // Read the data.
+ EXPECT_TRUE(server_info1.IsDataReady());
+
+ // Verify the data.
+ const QuicServerInfo::State& state1 = server_info1.state();
+ EXPECT_EQ(1U, state1.certs.size());
+ VerifyInitialData(state1);
+
+ // Update the data, by adding another cert.
+ QuicServerInfo::State* state2 = server_info1.mutable_state();
+ state2->certs.push_back(kCertB);
+ EXPECT_TRUE(server_info_.IsReadyToPersist());
+ server_info1.Persist();
+
+ // Read the persisted data and verify we have read the data correctly.
+ PropertiesBasedQuicServerInfo server_info2(server_id_,
+ &http_server_properties_);
+ server_info2.Start();
+ EXPECT_THAT(server_info2.WaitForDataReady(callback_),
+ IsOk()); // Read the data.
+ EXPECT_TRUE(server_info1.IsDataReady());
+
+ // Verify updated data.
+ const QuicServerInfo::State& state3 = server_info2.state();
+ VerifyInitialData(state3);
+ EXPECT_EQ(2U, state3.certs.size());
+ EXPECT_EQ(kCertB, state3.certs[1]);
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/quic_compressed_certs_cache.cc b/chromium/net/quic/core/crypto/quic_compressed_certs_cache.cc
new file mode 100644
index 00000000000..a18f021fa8f
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_compressed_certs_cache.cc
@@ -0,0 +1,124 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/crypto/quic_compressed_certs_cache.h"
+
+using std::string;
+
+namespace net {
+
+namespace {
+
+// Inline helper function for extending a 64-bit |seed| in-place with a 64-bit
+// |value|. Based on Boost's hash_combine function.
+inline void hash_combine(uint64_t* seed, const uint64_t& val) {
+ (*seed) ^= val + 0x9e3779b9 + ((*seed) << 6) + ((*seed) >> 2);
+}
+
+} // namespace
+
+QuicCompressedCertsCache::UncompressedCerts::UncompressedCerts() {}
+
+QuicCompressedCertsCache::UncompressedCerts::UncompressedCerts(
+ const scoped_refptr<ProofSource::Chain>& chain,
+ const string* client_common_set_hashes,
+ const string* client_cached_cert_hashes)
+ : chain(chain),
+ client_common_set_hashes(client_common_set_hashes),
+ client_cached_cert_hashes(client_cached_cert_hashes) {}
+
+QuicCompressedCertsCache::UncompressedCerts::~UncompressedCerts() {}
+
+QuicCompressedCertsCache::CachedCerts::CachedCerts() {}
+
+QuicCompressedCertsCache::CachedCerts::CachedCerts(
+ const UncompressedCerts& uncompressed_certs,
+ const string& compressed_cert)
+ : chain_(uncompressed_certs.chain),
+ client_common_set_hashes_(*uncompressed_certs.client_common_set_hashes),
+ client_cached_cert_hashes_(*uncompressed_certs.client_cached_cert_hashes),
+ compressed_cert_(compressed_cert) {}
+
+QuicCompressedCertsCache::CachedCerts::CachedCerts(const CachedCerts& other) =
+ default;
+
+QuicCompressedCertsCache::CachedCerts::~CachedCerts() {}
+
+bool QuicCompressedCertsCache::CachedCerts::MatchesUncompressedCerts(
+ const UncompressedCerts& uncompressed_certs) const {
+ return (client_common_set_hashes_ ==
+ *uncompressed_certs.client_common_set_hashes &&
+ client_cached_cert_hashes_ ==
+ *uncompressed_certs.client_cached_cert_hashes &&
+ chain_ == uncompressed_certs.chain);
+}
+
+const string* QuicCompressedCertsCache::CachedCerts::compressed_cert() const {
+ return &compressed_cert_;
+}
+
+QuicCompressedCertsCache::QuicCompressedCertsCache(int64_t max_num_certs)
+ : certs_cache_(max_num_certs) {}
+
+QuicCompressedCertsCache::~QuicCompressedCertsCache() {
+ // Underlying cache must be cleared before destruction.
+ certs_cache_.Clear();
+}
+
+const string* QuicCompressedCertsCache::GetCompressedCert(
+ const scoped_refptr<ProofSource::Chain>& chain,
+ const string& client_common_set_hashes,
+ const string& client_cached_cert_hashes) {
+ UncompressedCerts uncompressed_certs(chain, &client_common_set_hashes,
+ &client_cached_cert_hashes);
+
+ uint64_t key = ComputeUncompressedCertsHash(uncompressed_certs);
+
+ auto cached_it = certs_cache_.Get(key);
+
+ if (cached_it != certs_cache_.end()) {
+ const CachedCerts& cached_value = cached_it->second;
+ if (cached_value.MatchesUncompressedCerts(uncompressed_certs)) {
+ return cached_value.compressed_cert();
+ }
+ }
+ return nullptr;
+}
+
+void QuicCompressedCertsCache::Insert(
+ const scoped_refptr<ProofSource::Chain>& chain,
+ const string& client_common_set_hashes,
+ const string& client_cached_cert_hashes,
+ const string& compressed_cert) {
+ UncompressedCerts uncompressed_certs(chain, &client_common_set_hashes,
+ &client_cached_cert_hashes);
+
+ uint64_t key = ComputeUncompressedCertsHash(uncompressed_certs);
+
+ // Insert one unit to the cache.
+ certs_cache_.Put(key, CachedCerts(uncompressed_certs, compressed_cert));
+}
+
+size_t QuicCompressedCertsCache::MaxSize() {
+ return certs_cache_.max_size();
+}
+
+size_t QuicCompressedCertsCache::Size() {
+ return certs_cache_.size();
+}
+
+uint64_t QuicCompressedCertsCache::ComputeUncompressedCertsHash(
+ const UncompressedCerts& uncompressed_certs) {
+ uint64_t hash =
+ std::hash<string>()(*uncompressed_certs.client_common_set_hashes);
+ uint64_t h =
+ std::hash<string>()(*uncompressed_certs.client_cached_cert_hashes);
+ hash_combine(&hash, h);
+
+ hash_combine(&hash,
+ reinterpret_cast<uint64_t>(uncompressed_certs.chain.get()));
+ return hash;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/quic_compressed_certs_cache.h b/chromium/net/quic/core/crypto/quic_compressed_certs_cache.h
new file mode 100644
index 00000000000..84989f77052
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_compressed_certs_cache.h
@@ -0,0 +1,109 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CRYPTO_QUIC_COMPRESSED_CERTS_CACHE_H_
+#define NET_QUIC_CRYPTO_QUIC_COMPRESSED_CERTS_CACHE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/containers/mru_cache.h"
+#include "base/memory/ref_counted.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/proof_source.h"
+
+namespace net {
+
+// QuicCompressedCertsCache is a cache to track most recently compressed certs.
+class NET_EXPORT_PRIVATE QuicCompressedCertsCache {
+ public:
+ explicit QuicCompressedCertsCache(int64_t max_num_certs);
+ ~QuicCompressedCertsCache();
+
+ // Returns the pointer to the cached compressed cert if
+ // |chain, client_common_set_hashes, client_cached_cert_hashes| hits cache.
+ // Otherwise, return nullptr.
+ // Returned pointer might become invalid on the next call to Insert().
+ const std::string* GetCompressedCert(
+ const scoped_refptr<ProofSource::Chain>& chain,
+ const std::string& client_common_set_hashes,
+ const std::string& client_cached_cert_hashes);
+
+ // Inserts the specified
+ // |chain, client_common_set_hashes,
+ // client_cached_cert_hashes, compressed_cert| tuple to the cache.
+ // If the insertion causes the cache to become overfull, entries will
+ // be deleted in an LRU order to make room.
+ void Insert(const scoped_refptr<ProofSource::Chain>& chain,
+ const std::string& client_common_set_hashes,
+ const std::string& client_cached_cert_hashes,
+ const std::string& compressed_cert);
+
+ // Returns max number of cache entries the cache can carry.
+ size_t MaxSize();
+
+ // Returns current number of cache entries in the cache.
+ size_t Size();
+
+ // Default size of the QuicCompressedCertsCache per server side investigation.
+ static const size_t kQuicCompressedCertsCacheSize = 225;
+
+ private:
+ // A wrapper of the tuple:
+ // |chain, client_common_set_hashes, client_cached_cert_hashes|
+ // to identify uncompressed representation of certs.
+ struct UncompressedCerts {
+ UncompressedCerts();
+ UncompressedCerts(const scoped_refptr<ProofSource::Chain>& chain,
+ const std::string* client_common_set_hashes,
+ const std::string* client_cached_cert_hashes);
+ ~UncompressedCerts();
+
+ const scoped_refptr<ProofSource::Chain> chain;
+ const std::string* client_common_set_hashes;
+ const std::string* client_cached_cert_hashes;
+ };
+
+ // Certs stored by QuicCompressedCertsCache where uncompressed certs data is
+ // used to identify the uncompressed representation of certs and
+ // |compressed_cert| is the cached compressed representation.
+ class CachedCerts {
+ public:
+ CachedCerts();
+ CachedCerts(const UncompressedCerts& uncompressed_certs,
+ const std::string& compressed_cert);
+ CachedCerts(const CachedCerts& other);
+
+ ~CachedCerts();
+
+ // Returns true if the |uncompressed_certs| matches uncompressed
+ // representation of this cert.
+ bool MatchesUncompressedCerts(
+ const UncompressedCerts& uncompressed_certs) const;
+
+ const std::string* compressed_cert() const;
+
+ private:
+ // Uncompressed certs data.
+ scoped_refptr<ProofSource::Chain> chain_;
+ const std::string client_common_set_hashes_;
+ const std::string client_cached_cert_hashes_;
+
+ // Cached compressed representation derived from uncompressed certs.
+ const std::string compressed_cert_;
+ };
+
+ // Computes a uint64_t hash for |uncompressed_certs|.
+ uint64_t ComputeUncompressedCertsHash(
+ const UncompressedCerts& uncompressed_certs);
+
+ // Key is a unit64_t hash for UncompressedCerts. Stored associated value is
+ // CachedCerts which has both original uncompressed certs data and the
+ // compressed representation of the certs.
+ base::MRUCache<uint64_t, CachedCerts> certs_cache_;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_QUIC_COMPRESSED_CERTS_CACHE_H_
diff --git a/chromium/net/quic/core/crypto/quic_compressed_certs_cache_test.cc b/chromium/net/quic/core/crypto/quic_compressed_certs_cache_test.cc
new file mode 100644
index 00000000000..c446a09cab3
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_compressed_certs_cache_test.cc
@@ -0,0 +1,91 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/crypto/quic_compressed_certs_cache.h"
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/quic/core/crypto/cert_compressor.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+using std::vector;
+
+namespace net {
+
+namespace test {
+
+namespace {
+
+class QuicCompressedCertsCacheTest : public testing::Test {
+ public:
+ QuicCompressedCertsCacheTest()
+ : certs_cache_(QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) {}
+
+ protected:
+ QuicCompressedCertsCache certs_cache_;
+};
+
+TEST_F(QuicCompressedCertsCacheTest, CacheHit) {
+ vector<string> certs = {"leaf cert", "intermediate cert", "root cert"};
+ scoped_refptr<ProofSource::Chain> chain(new ProofSource::Chain(certs));
+ string common_certs = "common certs";
+ string cached_certs = "cached certs";
+ string compressed = "compressed cert";
+
+ certs_cache_.Insert(chain, common_certs, cached_certs, compressed);
+
+ const string* cached_value =
+ certs_cache_.GetCompressedCert(chain, common_certs, cached_certs);
+ ASSERT_NE(nullptr, cached_value);
+ EXPECT_EQ(*cached_value, compressed);
+}
+
+TEST_F(QuicCompressedCertsCacheTest, CacheMiss) {
+ vector<string> certs = {"leaf cert", "intermediate cert", "root cert"};
+ scoped_refptr<ProofSource::Chain> chain(new ProofSource::Chain(certs));
+ string common_certs = "common certs";
+ string cached_certs = "cached certs";
+ string compressed = "compressed cert";
+
+ certs_cache_.Insert(chain, common_certs, cached_certs, compressed);
+
+ EXPECT_EQ(nullptr, certs_cache_.GetCompressedCert(
+ chain, "mismatched common certs", cached_certs));
+ EXPECT_EQ(nullptr, certs_cache_.GetCompressedCert(chain, common_certs,
+ "mismatched cached certs"));
+ scoped_refptr<ProofSource::Chain> chain2(new ProofSource::Chain(certs));
+ EXPECT_EQ(nullptr,
+ certs_cache_.GetCompressedCert(chain2, common_certs, cached_certs));
+}
+
+TEST_F(QuicCompressedCertsCacheTest, CacheMissDueToEviction) {
+ // Test cache returns a miss when a queried uncompressed certs was cached but
+ // then evicted.
+ vector<string> certs = {"leaf cert", "intermediate cert", "root cert"};
+ scoped_refptr<ProofSource::Chain> chain(new ProofSource::Chain(certs));
+
+ string common_certs = "common certs";
+ string cached_certs = "cached certs";
+ string compressed = "compressed cert";
+ certs_cache_.Insert(chain, common_certs, cached_certs, compressed);
+
+ // Insert another kQuicCompressedCertsCacheSize certs to evict the first
+ // cached cert.
+ for (unsigned int i = 0;
+ i < QuicCompressedCertsCache::kQuicCompressedCertsCacheSize; i++) {
+ EXPECT_EQ(certs_cache_.Size(), i + 1);
+ certs_cache_.Insert(chain, base::IntToString(i), "", base::IntToString(i));
+ }
+ EXPECT_EQ(certs_cache_.MaxSize(), certs_cache_.Size());
+
+ EXPECT_EQ(nullptr,
+ certs_cache_.GetCompressedCert(chain, common_certs, cached_certs));
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/quic_crypto_client_config.cc b/chromium/net/quic/core/crypto/quic_crypto_client_config.cc
new file mode 100644
index 00000000000..e1fd5f4c26b
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_crypto_client_config.cc
@@ -0,0 +1,997 @@
+// Copyright 2013 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/crypto/quic_crypto_client_config.h"
+
+#include <memory>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "net/quic/core/crypto/cert_compressor.h"
+#include "net/quic/core/crypto/chacha20_poly1305_encrypter.h"
+#include "net/quic/core/crypto/channel_id.h"
+#include "net/quic/core/crypto/common_cert_set.h"
+#include "net/quic/core/crypto/crypto_framer.h"
+#include "net/quic/core/crypto/crypto_utils.h"
+#include "net/quic/core/crypto/curve25519_key_exchange.h"
+#include "net/quic/core/crypto/key_exchange.h"
+#include "net/quic/core/crypto/p256_key_exchange.h"
+#include "net/quic/core/crypto/proof_verifier.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+
+using base::StringPiece;
+using std::map;
+using std::string;
+using std::queue;
+using std::vector;
+
+namespace net {
+
+namespace {
+
+// Tracks the reason (the state of the server config) for sending inchoate
+// ClientHello to the server.
+void RecordInchoateClientHelloReason(
+ QuicCryptoClientConfig::CachedState::ServerConfigState state) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Net.QuicInchoateClientHelloReason", state,
+ QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT);
+}
+
+// Tracks the state of the QUIC server information loaded from the disk cache.
+void RecordDiskCacheServerConfigState(
+ QuicCryptoClientConfig::CachedState::ServerConfigState state) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Net.QuicServerInfo.DiskCacheState", state,
+ QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT);
+}
+
+} // namespace
+
+QuicCryptoClientConfig::QuicCryptoClientConfig(
+ std::unique_ptr<ProofVerifier> proof_verifier)
+ : proof_verifier_(std::move(proof_verifier)) {
+ DCHECK(proof_verifier_.get());
+ SetDefaults();
+}
+
+QuicCryptoClientConfig::~QuicCryptoClientConfig() {
+ base::STLDeleteValues(&cached_states_);
+}
+
+QuicCryptoClientConfig::CachedState::CachedState()
+ : server_config_valid_(false),
+ expiration_time_(QuicWallTime::Zero()),
+ generation_counter_(0) {}
+
+QuicCryptoClientConfig::CachedState::~CachedState() {}
+
+bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const {
+ if (server_config_.empty()) {
+ RecordInchoateClientHelloReason(SERVER_CONFIG_EMPTY);
+ return false;
+ }
+
+ if (!server_config_valid_) {
+ RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID);
+ return false;
+ }
+
+ const CryptoHandshakeMessage* scfg = GetServerConfig();
+ if (!scfg) {
+ // Should be impossible short of cache corruption.
+ DCHECK(false);
+ RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED);
+ return false;
+ }
+
+ if (now.IsAfter(expiration_time_)) {
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "Net.QuicClientHelloServerConfig.InvalidDuration",
+ base::TimeDelta::FromSeconds(now.ToUNIXSeconds() -
+ expiration_time_.ToUNIXSeconds()),
+ base::TimeDelta::FromMinutes(1), base::TimeDelta::FromDays(20), 50);
+ RecordInchoateClientHelloReason(SERVER_CONFIG_EXPIRED);
+ return false;
+ }
+
+ return true;
+}
+
+bool QuicCryptoClientConfig::CachedState::IsEmpty() const {
+ return server_config_.empty();
+}
+
+const CryptoHandshakeMessage*
+QuicCryptoClientConfig::CachedState::GetServerConfig() const {
+ if (server_config_.empty()) {
+ return nullptr;
+ }
+
+ if (!scfg_.get()) {
+ scfg_.reset(CryptoFramer::ParseMessage(server_config_));
+ DCHECK(scfg_.get());
+ }
+ return scfg_.get();
+}
+
+void QuicCryptoClientConfig::CachedState::add_server_designated_connection_id(
+ QuicConnectionId connection_id) {
+ server_designated_connection_ids_.push(connection_id);
+}
+
+bool QuicCryptoClientConfig::CachedState::has_server_designated_connection_id()
+ const {
+ return !server_designated_connection_ids_.empty();
+}
+
+void QuicCryptoClientConfig::CachedState::add_server_nonce(
+ const string& server_nonce) {
+ server_nonces_.push(server_nonce);
+}
+
+bool QuicCryptoClientConfig::CachedState::has_server_nonce() const {
+ return !server_nonces_.empty();
+}
+
+QuicCryptoClientConfig::CachedState::ServerConfigState
+QuicCryptoClientConfig::CachedState::SetServerConfig(StringPiece server_config,
+ QuicWallTime now,
+ QuicWallTime expiry_time,
+ string* error_details) {
+ const bool matches_existing = server_config == server_config_;
+
+ // Even if the new server config matches the existing one, we still wish to
+ // reject it if it has expired.
+ std::unique_ptr<CryptoHandshakeMessage> new_scfg_storage;
+ const CryptoHandshakeMessage* new_scfg;
+
+ if (!matches_existing) {
+ new_scfg_storage.reset(CryptoFramer::ParseMessage(server_config));
+ new_scfg = new_scfg_storage.get();
+ } else {
+ new_scfg = GetServerConfig();
+ }
+
+ if (!new_scfg) {
+ *error_details = "SCFG invalid";
+ return SERVER_CONFIG_INVALID;
+ }
+
+ if (expiry_time.IsZero()) {
+ uint64_t expiry_seconds;
+ if (new_scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
+ *error_details = "SCFG missing EXPY";
+ return SERVER_CONFIG_INVALID_EXPIRY;
+ }
+ expiration_time_ = QuicWallTime::FromUNIXSeconds(expiry_seconds);
+ } else {
+ expiration_time_ = expiry_time;
+ }
+
+ if (now.IsAfter(expiration_time_)) {
+ *error_details = "SCFG has expired";
+ return SERVER_CONFIG_EXPIRED;
+ }
+
+ if (!matches_existing) {
+ server_config_ = server_config.as_string();
+ SetProofInvalid();
+ scfg_.reset(new_scfg_storage.release());
+ }
+ return SERVER_CONFIG_VALID;
+}
+
+void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
+ server_config_.clear();
+ scfg_.reset();
+ SetProofInvalid();
+ queue<QuicConnectionId> empty_queue;
+ swap(server_designated_connection_ids_, empty_queue);
+}
+
+void QuicCryptoClientConfig::CachedState::SetProof(const vector<string>& certs,
+ StringPiece cert_sct,
+ StringPiece chlo_hash,
+ StringPiece signature) {
+ bool has_changed = signature != server_config_sig_ ||
+ chlo_hash != chlo_hash_ || certs_.size() != certs.size();
+
+ if (!has_changed) {
+ for (size_t i = 0; i < certs_.size(); i++) {
+ if (certs_[i] != certs[i]) {
+ has_changed = true;
+ break;
+ }
+ }
+ }
+
+ if (!has_changed) {
+ return;
+ }
+
+ // If the proof has changed then it needs to be revalidated.
+ SetProofInvalid();
+ certs_ = certs;
+ cert_sct_ = cert_sct.as_string();
+ chlo_hash_ = chlo_hash.as_string();
+ server_config_sig_ = signature.as_string();
+}
+
+void QuicCryptoClientConfig::CachedState::Clear() {
+ server_config_.clear();
+ source_address_token_.clear();
+ certs_.clear();
+ cert_sct_.clear();
+ chlo_hash_.clear();
+ server_config_sig_.clear();
+ server_config_valid_ = false;
+ proof_verify_details_.reset();
+ scfg_.reset();
+ ++generation_counter_;
+ queue<QuicConnectionId> empty_queue;
+ swap(server_designated_connection_ids_, empty_queue);
+}
+
+void QuicCryptoClientConfig::CachedState::ClearProof() {
+ SetProofInvalid();
+ certs_.clear();
+ cert_sct_.clear();
+ chlo_hash_.clear();
+ server_config_sig_.clear();
+}
+
+void QuicCryptoClientConfig::CachedState::SetProofValid() {
+ server_config_valid_ = true;
+}
+
+void QuicCryptoClientConfig::CachedState::SetProofInvalid() {
+ server_config_valid_ = false;
+ ++generation_counter_;
+}
+
+bool QuicCryptoClientConfig::CachedState::Initialize(
+ StringPiece server_config,
+ StringPiece source_address_token,
+ const vector<string>& certs,
+ StringPiece cert_sct,
+ StringPiece chlo_hash,
+ StringPiece signature,
+ QuicWallTime now,
+ QuicWallTime expiration_time) {
+ DCHECK(server_config_.empty());
+
+ if (server_config.empty()) {
+ RecordDiskCacheServerConfigState(SERVER_CONFIG_EMPTY);
+ return false;
+ }
+
+ string error_details;
+ ServerConfigState state =
+ SetServerConfig(server_config, now, expiration_time, &error_details);
+ RecordDiskCacheServerConfigState(state);
+ if (state != SERVER_CONFIG_VALID) {
+ DVLOG(1) << "SetServerConfig failed with " << error_details;
+ return false;
+ }
+
+ signature.CopyToString(&server_config_sig_);
+ source_address_token.CopyToString(&source_address_token_);
+ cert_sct.CopyToString(&cert_sct_);
+ chlo_hash.CopyToString(&chlo_hash_);
+ certs_ = certs;
+ return true;
+}
+
+const string& QuicCryptoClientConfig::CachedState::server_config() const {
+ return server_config_;
+}
+
+const string& QuicCryptoClientConfig::CachedState::source_address_token()
+ const {
+ return source_address_token_;
+}
+
+const vector<string>& QuicCryptoClientConfig::CachedState::certs() const {
+ return certs_;
+}
+
+const string& QuicCryptoClientConfig::CachedState::cert_sct() const {
+ return cert_sct_;
+}
+
+const string& QuicCryptoClientConfig::CachedState::chlo_hash() const {
+ return chlo_hash_;
+}
+
+const string& QuicCryptoClientConfig::CachedState::signature() const {
+ return server_config_sig_;
+}
+
+bool QuicCryptoClientConfig::CachedState::proof_valid() const {
+ return server_config_valid_;
+}
+
+uint64_t QuicCryptoClientConfig::CachedState::generation_counter() const {
+ return generation_counter_;
+}
+
+const ProofVerifyDetails*
+QuicCryptoClientConfig::CachedState::proof_verify_details() const {
+ return proof_verify_details_.get();
+}
+
+void QuicCryptoClientConfig::CachedState::set_source_address_token(
+ StringPiece token) {
+ source_address_token_ = token.as_string();
+}
+
+void QuicCryptoClientConfig::CachedState::set_cert_sct(StringPiece cert_sct) {
+ cert_sct_ = cert_sct.as_string();
+}
+
+void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails(
+ ProofVerifyDetails* details) {
+ proof_verify_details_.reset(details);
+}
+
+void QuicCryptoClientConfig::CachedState::InitializeFrom(
+ const QuicCryptoClientConfig::CachedState& other) {
+ DCHECK(server_config_.empty());
+ DCHECK(!server_config_valid_);
+ server_config_ = other.server_config_;
+ source_address_token_ = other.source_address_token_;
+ certs_ = other.certs_;
+ cert_sct_ = other.cert_sct_;
+ chlo_hash_ = other.chlo_hash_;
+ server_config_sig_ = other.server_config_sig_;
+ server_config_valid_ = other.server_config_valid_;
+ server_designated_connection_ids_ = other.server_designated_connection_ids_;
+ expiration_time_ = other.expiration_time_;
+ if (other.proof_verify_details_.get() != nullptr) {
+ proof_verify_details_.reset(other.proof_verify_details_->Clone());
+ }
+ ++generation_counter_;
+}
+
+QuicConnectionId
+QuicCryptoClientConfig::CachedState::GetNextServerDesignatedConnectionId() {
+ if (server_designated_connection_ids_.empty()) {
+ QUIC_BUG
+ << "Attempting to consume a connection id that was never designated.";
+ return 0;
+ }
+ const QuicConnectionId next_id = server_designated_connection_ids_.front();
+ server_designated_connection_ids_.pop();
+ return next_id;
+}
+
+string QuicCryptoClientConfig::CachedState::GetNextServerNonce() {
+ if (server_nonces_.empty()) {
+ QUIC_BUG
+ << "Attempting to consume a server nonce that was never designated.";
+ return "";
+ }
+ const string server_nonce = server_nonces_.front();
+ server_nonces_.pop();
+ return server_nonce;
+}
+
+void QuicCryptoClientConfig::SetDefaults() {
+ // Key exchange methods.
+ kexs = {kC255, kP256};
+
+ // Authenticated encryption algorithms. Prefer RFC 7539 ChaCha20 by default.
+ aead = {kCC20, kAESG};
+}
+
+QuicCryptoClientConfig::CachedState* QuicCryptoClientConfig::LookupOrCreate(
+ const QuicServerId& server_id) {
+ CachedStateMap::const_iterator it = cached_states_.find(server_id);
+ if (it != cached_states_.end()) {
+ return it->second;
+ }
+
+ CachedState* cached = new CachedState;
+ cached_states_.insert(std::make_pair(server_id, cached));
+ bool cache_populated = PopulateFromCanonicalConfig(server_id, cached);
+ UMA_HISTOGRAM_BOOLEAN(
+ "Net.QuicCryptoClientConfig.PopulatedFromCanonicalConfig",
+ cache_populated);
+ return cached;
+}
+
+void QuicCryptoClientConfig::ClearCachedStates(const ServerIdFilter& filter) {
+ for (CachedStateMap::const_iterator it = cached_states_.begin();
+ it != cached_states_.end(); ++it) {
+ if (filter.Matches(it->first))
+ it->second->Clear();
+ }
+}
+
+void QuicCryptoClientConfig::FillInchoateClientHello(
+ const QuicServerId& server_id,
+ const QuicVersion preferred_version,
+ const CachedState* cached,
+ QuicRandom* rand,
+ bool demand_x509_proof,
+ QuicCryptoNegotiatedParameters* out_params,
+ CryptoHandshakeMessage* out) const {
+ out->set_tag(kCHLO);
+ // TODO(rch): Remove this when we remove:
+ // FLAGS_quic_use_chlo_packet_size
+ out->set_minimum_size(kClientHelloMinimumSize);
+
+ // Server name indication. We only send SNI if it's a valid domain name, as
+ // per the spec.
+ if (CryptoUtils::IsValidSNI(server_id.host())) {
+ out->SetStringPiece(kSNI, server_id.host());
+ }
+ out->SetValue(kVER, QuicVersionToQuicTag(preferred_version));
+
+ if (!user_agent_id_.empty()) {
+ out->SetStringPiece(kUAID, user_agent_id_);
+ }
+
+ // Even though this is an inchoate CHLO, send the SCID so that
+ // the STK can be validated by the server.
+ const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
+ if (scfg != nullptr) {
+ StringPiece scid;
+ if (scfg->GetStringPiece(kSCID, &scid)) {
+ out->SetStringPiece(kSCID, scid);
+ }
+ }
+
+ if (!cached->source_address_token().empty()) {
+ out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token());
+ }
+
+ if (!demand_x509_proof) {
+ return;
+ }
+
+ char proof_nonce[32];
+ rand->RandBytes(proof_nonce, arraysize(proof_nonce));
+ out->SetStringPiece(kNONP, StringPiece(proof_nonce, arraysize(proof_nonce)));
+
+ out->SetVector(kPDMD, QuicTagVector{kX509});
+
+ if (common_cert_sets) {
+ out->SetStringPiece(kCCS, common_cert_sets->GetCommonHashes());
+ }
+
+ out->SetStringPiece(kCertificateSCTTag, "");
+
+ const vector<string>& certs = cached->certs();
+ // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
+ // client config is being used for multiple connections, another connection
+ // doesn't update the cached certificates and cause us to be unable to
+ // process the server's compressed certificate chain.
+ out_params->cached_certs = certs;
+ if (!certs.empty()) {
+ vector<uint64_t> hashes;
+ hashes.reserve(certs.size());
+ for (vector<string>::const_iterator i = certs.begin(); i != certs.end();
+ ++i) {
+ hashes.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size()));
+ }
+ out->SetVector(kCCRT, hashes);
+ }
+}
+
+QuicErrorCode QuicCryptoClientConfig::FillClientHello(
+ const QuicServerId& server_id,
+ QuicConnectionId connection_id,
+ const QuicVersion actual_version,
+ const QuicVersion preferred_version,
+ const CachedState* cached,
+ QuicWallTime now,
+ QuicRandom* rand,
+ const ChannelIDKey* channel_id_key,
+ QuicCryptoNegotiatedParameters* out_params,
+ CryptoHandshakeMessage* out,
+ string* error_details) const {
+ DCHECK(error_details != nullptr);
+
+ FillInchoateClientHello(server_id, preferred_version, cached, rand,
+ /* demand_x509_proof= */ true, out_params, out);
+
+ const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
+ if (!scfg) {
+ // This should never happen as our caller should have checked
+ // cached->IsComplete() before calling this function.
+ *error_details = "Handshake not ready";
+ return QUIC_CRYPTO_INTERNAL_ERROR;
+ }
+
+ StringPiece scid;
+ if (!scfg->GetStringPiece(kSCID, &scid)) {
+ *error_details = "SCFG missing SCID";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+ out->SetStringPiece(kSCID, scid);
+
+ out->SetStringPiece(kCertificateSCTTag, "");
+
+ const QuicTag* their_aeads;
+ const QuicTag* their_key_exchanges;
+ size_t num_their_aeads, num_their_key_exchanges;
+ if (scfg->GetTaglist(kAEAD, &their_aeads, &num_their_aeads) !=
+ QUIC_NO_ERROR ||
+ scfg->GetTaglist(kKEXS, &their_key_exchanges, &num_their_key_exchanges) !=
+ QUIC_NO_ERROR) {
+ *error_details = "Missing AEAD or KEXS";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ // AEAD: the work loads on the client and server are symmetric. Since the
+ // client is more likely to be CPU-constrained, break the tie by favoring
+ // the client's preference.
+ // Key exchange: the client does more work than the server, so favor the
+ // client's preference.
+ size_t key_exchange_index;
+ if (!QuicUtils::FindMutualTag(aead, their_aeads, num_their_aeads,
+ QuicUtils::LOCAL_PRIORITY, &out_params->aead,
+ nullptr) ||
+ !QuicUtils::FindMutualTag(
+ kexs, their_key_exchanges, num_their_key_exchanges,
+ QuicUtils::LOCAL_PRIORITY, &out_params->key_exchange,
+ &key_exchange_index)) {
+ *error_details = "Unsupported AEAD or KEXS";
+ return QUIC_CRYPTO_NO_SUPPORT;
+ }
+ out->SetVector(kAEAD, QuicTagVector{out_params->aead});
+ out->SetVector(kKEXS, QuicTagVector{out_params->key_exchange});
+
+ if (!tb_key_params.empty()) {
+ const QuicTag* their_tbkps;
+ size_t num_their_tbkps;
+ switch (scfg->GetTaglist(kTBKP, &their_tbkps, &num_their_tbkps)) {
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+ break;
+ case QUIC_NO_ERROR:
+ if (QuicUtils::FindMutualTag(tb_key_params, their_tbkps,
+ num_their_tbkps, QuicUtils::LOCAL_PRIORITY,
+ &out_params->token_binding_key_param,
+ nullptr)) {
+ out->SetVector(kTBKP,
+ QuicTagVector{out_params->token_binding_key_param});
+ }
+ break;
+ default:
+ *error_details = "Invalid TBKP";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+ }
+
+ StringPiece public_value;
+ if (scfg->GetNthValue24(kPUBS, key_exchange_index, &public_value) !=
+ QUIC_NO_ERROR) {
+ *error_details = "Missing public value";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ StringPiece orbit;
+ if (!scfg->GetStringPiece(kORBT, &orbit) || orbit.size() != kOrbitSize) {
+ *error_details = "SCFG missing OBIT";
+ return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ }
+
+ CryptoUtils::GenerateNonce(now, rand, orbit, &out_params->client_nonce);
+ out->SetStringPiece(kNONC, out_params->client_nonce);
+ if (!out_params->server_nonce.empty()) {
+ out->SetStringPiece(kServerNonceTag, out_params->server_nonce);
+ }
+
+ switch (out_params->key_exchange) {
+ case kC255:
+ out_params->client_key_exchange.reset(Curve25519KeyExchange::New(
+ Curve25519KeyExchange::NewPrivateKey(rand)));
+ break;
+ case kP256:
+ out_params->client_key_exchange.reset(
+ P256KeyExchange::New(P256KeyExchange::NewPrivateKey()));
+ break;
+ default:
+ DCHECK(false);
+ *error_details = "Configured to support an unknown key exchange";
+ return QUIC_CRYPTO_INTERNAL_ERROR;
+ }
+
+ if (!out_params->client_key_exchange->CalculateSharedKey(
+ public_value, &out_params->initial_premaster_secret)) {
+ *error_details = "Key exchange failure";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+ out->SetStringPiece(kPUBS, out_params->client_key_exchange->public_value());
+
+ const vector<string>& certs = cached->certs();
+ if (certs.empty()) {
+ *error_details = "No certs to calculate XLCT";
+ return QUIC_CRYPTO_INTERNAL_ERROR;
+ }
+ out->SetValue(kXLCT, CryptoUtils::ComputeLeafCertHash(certs[0]));
+
+ if (channel_id_key) {
+ // In order to calculate the encryption key for the CETV block we need to
+ // serialise the client hello as it currently is (i.e. without the CETV
+ // block). For this, the client hello is serialized without padding.
+ const size_t orig_min_size = out->minimum_size();
+ out->set_minimum_size(0);
+
+ CryptoHandshakeMessage cetv;
+ cetv.set_tag(kCETV);
+
+ string hkdf_input;
+ const QuicData& client_hello_serialized = out->GetSerialized();
+ hkdf_input.append(QuicCryptoConfig::kCETVLabel,
+ strlen(QuicCryptoConfig::kCETVLabel) + 1);
+ hkdf_input.append(reinterpret_cast<char*>(&connection_id),
+ sizeof(connection_id));
+ hkdf_input.append(client_hello_serialized.data(),
+ client_hello_serialized.length());
+ hkdf_input.append(cached->server_config());
+
+ string key = channel_id_key->SerializeKey();
+ string signature;
+ if (!channel_id_key->Sign(hkdf_input, &signature)) {
+ *error_details = "Channel ID signature failed";
+ return QUIC_INVALID_CHANNEL_ID_SIGNATURE;
+ }
+
+ cetv.SetStringPiece(kCIDK, key);
+ cetv.SetStringPiece(kCIDS, signature);
+
+ CrypterPair crypters;
+ if (!CryptoUtils::DeriveKeys(
+ out_params->initial_premaster_secret, out_params->aead,
+ out_params->client_nonce, out_params->server_nonce, hkdf_input,
+ Perspective::IS_CLIENT, CryptoUtils::Diversification::Never(),
+ &crypters, nullptr /* subkey secret */)) {
+ *error_details = "Symmetric key setup failed";
+ return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
+ }
+
+ const QuicData& cetv_plaintext = cetv.GetSerialized();
+ const size_t encrypted_len =
+ crypters.encrypter->GetCiphertextSize(cetv_plaintext.length());
+ std::unique_ptr<char[]> output(new char[encrypted_len]);
+ size_t output_size = 0;
+ if (!crypters.encrypter->EncryptPacket(
+ kDefaultPathId /* path id */, 0 /* packet number */,
+ StringPiece() /* associated data */, cetv_plaintext.AsStringPiece(),
+ output.get(), &output_size, encrypted_len)) {
+ *error_details = "Packet encryption failed";
+ return QUIC_ENCRYPTION_FAILURE;
+ }
+
+ out->SetStringPiece(kCETV, StringPiece(output.get(), output_size));
+ out->MarkDirty();
+
+ out->set_minimum_size(orig_min_size);
+ }
+
+ // Derive the symmetric keys and set up the encrypters and decrypters.
+ // Set the following members of out_params:
+ // out_params->hkdf_input_suffix
+ // out_params->initial_crypters
+ out_params->hkdf_input_suffix.clear();
+ out_params->hkdf_input_suffix.append(reinterpret_cast<char*>(&connection_id),
+ sizeof(connection_id));
+ const QuicData& client_hello_serialized = out->GetSerialized();
+ out_params->hkdf_input_suffix.append(client_hello_serialized.data(),
+ client_hello_serialized.length());
+ out_params->hkdf_input_suffix.append(cached->server_config());
+ if (certs.empty()) {
+ *error_details = "No certs found to include in KDF";
+ return QUIC_CRYPTO_INTERNAL_ERROR;
+ }
+ out_params->hkdf_input_suffix.append(certs[0]);
+
+ string hkdf_input;
+ const size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
+ hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
+ hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
+ hkdf_input.append(out_params->hkdf_input_suffix);
+
+ string* subkey_secret = &out_params->initial_subkey_secret;
+
+ // Only perform key diversification for QUIC versions 33 and later.
+ // TODO(rch): remove the |actual_version| argument to this method when
+ // QUIC_VERSION_32 is removed.
+ CryptoUtils::Diversification diversification =
+ actual_version > QUIC_VERSION_32 ? CryptoUtils::Diversification::Pending()
+ : CryptoUtils::Diversification::Never();
+ if (!CryptoUtils::DeriveKeys(out_params->initial_premaster_secret,
+ out_params->aead, out_params->client_nonce,
+ out_params->server_nonce, hkdf_input,
+ Perspective::IS_CLIENT, diversification,
+ &out_params->initial_crypters, subkey_secret)) {
+ *error_details = "Symmetric key setup failed";
+ return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
+ }
+
+ return QUIC_NO_ERROR;
+}
+
+QuicErrorCode QuicCryptoClientConfig::CacheNewServerConfig(
+ const CryptoHandshakeMessage& message,
+ QuicWallTime now,
+ QuicVersion version,
+ StringPiece chlo_hash,
+ const vector<string>& cached_certs,
+ CachedState* cached,
+ string* error_details) {
+ DCHECK(error_details != nullptr);
+
+ StringPiece scfg;
+ if (!message.GetStringPiece(kSCFG, &scfg)) {
+ *error_details = "Missing SCFG";
+ return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ }
+
+ QuicWallTime expiration_time = QuicWallTime::Zero();
+ uint64_t expiry_seconds;
+ if (message.GetUint64(kSTTL, &expiry_seconds) == QUIC_NO_ERROR) {
+ expiration_time = now.Add(QuicTime::Delta::FromSeconds(expiry_seconds));
+ }
+
+ CachedState::ServerConfigState state =
+ cached->SetServerConfig(scfg, now, expiration_time, error_details);
+ if (state == CachedState::SERVER_CONFIG_EXPIRED) {
+ return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED;
+ }
+ // TODO(rtenneti): Return more specific error code than returning
+ // QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER.
+ if (state != CachedState::SERVER_CONFIG_VALID) {
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ StringPiece token;
+ if (message.GetStringPiece(kSourceAddressTokenTag, &token)) {
+ cached->set_source_address_token(token);
+ }
+
+ StringPiece proof, cert_bytes, cert_sct;
+ bool has_proof = message.GetStringPiece(kPROF, &proof);
+ bool has_cert = message.GetStringPiece(kCertificateTag, &cert_bytes);
+ if (has_proof && has_cert) {
+ vector<string> certs;
+ if (!CertCompressor::DecompressChain(cert_bytes, cached_certs,
+ common_cert_sets, &certs)) {
+ *error_details = "Certificate data invalid";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ message.GetStringPiece(kCertificateSCTTag, &cert_sct);
+ cached->SetProof(certs, cert_sct, chlo_hash, proof);
+ } else {
+ // Secure QUIC: clear existing proof as we have been sent a new SCFG
+ // without matching proof/certs.
+ cached->ClearProof();
+
+ if (has_proof && !has_cert) {
+ *error_details = "Certificate missing";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ if (!has_proof && has_cert) {
+ *error_details = "Proof missing";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+ }
+
+ return QUIC_NO_ERROR;
+}
+
+QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
+ const CryptoHandshakeMessage& rej,
+ QuicWallTime now,
+ const QuicVersion version,
+ StringPiece chlo_hash,
+ CachedState* cached,
+ QuicCryptoNegotiatedParameters* out_params,
+ string* error_details) {
+ DCHECK(error_details != nullptr);
+
+ if ((rej.tag() != kREJ) && (rej.tag() != kSREJ)) {
+ *error_details = "Message is not REJ or SREJ";
+ return QUIC_CRYPTO_INTERNAL_ERROR;
+ }
+
+ QuicErrorCode error =
+ CacheNewServerConfig(rej, now, version, chlo_hash,
+ out_params->cached_certs, cached, error_details);
+ if (error != QUIC_NO_ERROR) {
+ return error;
+ }
+
+ StringPiece nonce;
+ if (rej.GetStringPiece(kServerNonceTag, &nonce)) {
+ out_params->server_nonce = nonce.as_string();
+ }
+
+ if (rej.tag() == kSREJ) {
+ QuicConnectionId connection_id;
+ if (rej.GetUint64(kRCID, &connection_id) != QUIC_NO_ERROR) {
+ *error_details = "Missing kRCID";
+ return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ }
+ cached->add_server_designated_connection_id(connection_id);
+ if (!nonce.empty()) {
+ cached->add_server_nonce(nonce.as_string());
+ }
+ return QUIC_NO_ERROR;
+ }
+
+ return QUIC_NO_ERROR;
+}
+
+QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
+ const CryptoHandshakeMessage& server_hello,
+ QuicConnectionId connection_id,
+ QuicVersion version,
+ const QuicVersionVector& negotiated_versions,
+ CachedState* cached,
+ QuicCryptoNegotiatedParameters* out_params,
+ string* error_details) {
+ DCHECK(error_details != nullptr);
+
+ QuicErrorCode valid = CryptoUtils::ValidateServerHello(
+ server_hello, negotiated_versions, error_details);
+ if (valid != QUIC_NO_ERROR) {
+ return valid;
+ }
+
+ // Learn about updated source address tokens.
+ StringPiece token;
+ if (server_hello.GetStringPiece(kSourceAddressTokenTag, &token)) {
+ cached->set_source_address_token(token);
+ }
+
+ StringPiece shlo_nonce;
+ if (!server_hello.GetStringPiece(kServerNonceTag, &shlo_nonce)) {
+ *error_details = "server hello missing server nonce";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ // TODO(agl):
+ // learn about updated SCFGs.
+
+ StringPiece public_value;
+ if (!server_hello.GetStringPiece(kPUBS, &public_value)) {
+ *error_details = "server hello missing forward secure public value";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ if (!out_params->client_key_exchange->CalculateSharedKey(
+ public_value, &out_params->forward_secure_premaster_secret)) {
+ *error_details = "Key exchange failure";
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ }
+
+ string hkdf_input;
+ const size_t label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
+ hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
+ hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, label_len);
+ hkdf_input.append(out_params->hkdf_input_suffix);
+
+ if (!CryptoUtils::DeriveKeys(
+ out_params->forward_secure_premaster_secret, out_params->aead,
+ out_params->client_nonce,
+ shlo_nonce.empty() ? out_params->server_nonce : shlo_nonce,
+ hkdf_input, Perspective::IS_CLIENT,
+ CryptoUtils::Diversification::Never(),
+ &out_params->forward_secure_crypters, &out_params->subkey_secret)) {
+ *error_details = "Symmetric key setup failed";
+ return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
+ }
+
+ return QUIC_NO_ERROR;
+}
+
+QuicErrorCode QuicCryptoClientConfig::ProcessServerConfigUpdate(
+ const CryptoHandshakeMessage& server_config_update,
+ QuicWallTime now,
+ const QuicVersion version,
+ StringPiece chlo_hash,
+ CachedState* cached,
+ QuicCryptoNegotiatedParameters* out_params,
+ string* error_details) {
+ DCHECK(error_details != nullptr);
+
+ if (server_config_update.tag() != kSCUP) {
+ *error_details = "ServerConfigUpdate must have kSCUP tag.";
+ return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
+ }
+ return CacheNewServerConfig(server_config_update, now, version, chlo_hash,
+ out_params->cached_certs, cached, error_details);
+}
+
+ProofVerifier* QuicCryptoClientConfig::proof_verifier() const {
+ return proof_verifier_.get();
+}
+
+ChannelIDSource* QuicCryptoClientConfig::channel_id_source() const {
+ return channel_id_source_.get();
+}
+
+void QuicCryptoClientConfig::SetChannelIDSource(ChannelIDSource* source) {
+ channel_id_source_.reset(source);
+}
+
+void QuicCryptoClientConfig::InitializeFrom(
+ const QuicServerId& server_id,
+ const QuicServerId& canonical_server_id,
+ QuicCryptoClientConfig* canonical_crypto_config) {
+ CachedState* canonical_cached =
+ canonical_crypto_config->LookupOrCreate(canonical_server_id);
+ if (!canonical_cached->proof_valid()) {
+ return;
+ }
+ CachedState* cached = LookupOrCreate(server_id);
+ cached->InitializeFrom(*canonical_cached);
+}
+
+void QuicCryptoClientConfig::AddCanonicalSuffix(const string& suffix) {
+ canonical_suffixes_.push_back(suffix);
+}
+
+void QuicCryptoClientConfig::PreferAesGcm() {
+ DCHECK(!aead.empty());
+ if (aead.size() <= 1) {
+ return;
+ }
+ QuicTagVector::iterator pos = std::find(aead.begin(), aead.end(), kAESG);
+ if (pos != aead.end()) {
+ aead.erase(pos);
+ aead.insert(aead.begin(), kAESG);
+ }
+}
+
+bool QuicCryptoClientConfig::PopulateFromCanonicalConfig(
+ const QuicServerId& server_id,
+ CachedState* server_state) {
+ DCHECK(server_state->IsEmpty());
+ size_t i = 0;
+ for (; i < canonical_suffixes_.size(); ++i) {
+ if (base::EndsWith(server_id.host(), canonical_suffixes_[i],
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ break;
+ }
+ }
+ if (i == canonical_suffixes_.size()) {
+ return false;
+ }
+
+ QuicServerId suffix_server_id(canonical_suffixes_[i], server_id.port(),
+ server_id.privacy_mode());
+ if (!base::ContainsKey(canonical_server_map_, suffix_server_id)) {
+ // This is the first host we've seen which matches the suffix, so make it
+ // canonical.
+ canonical_server_map_[suffix_server_id] = server_id;
+ return false;
+ }
+
+ const QuicServerId& canonical_server_id =
+ canonical_server_map_[suffix_server_id];
+ CachedState* canonical_state = cached_states_[canonical_server_id];
+ if (!canonical_state->proof_valid()) {
+ return false;
+ }
+
+ // Update canonical version to point at the "most recent" entry.
+ canonical_server_map_[suffix_server_id] = server_id;
+
+ server_state->InitializeFrom(*canonical_state);
+ return true;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/quic_crypto_client_config.h b/chromium/net/quic/core/crypto/quic_crypto_client_config.h
new file mode 100644
index 00000000000..36437c63141
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_crypto_client_config.h
@@ -0,0 +1,392 @@
+// Copyright 2013 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_CRYPTO_QUIC_CRYPTO_CLIENT_CONFIG_H_
+#define NET_QUIC_CRYPTO_QUIC_CRYPTO_CLIENT_CONFIG_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_id.h"
+
+namespace net {
+
+class ChannelIDKey;
+class ChannelIDSource;
+class CryptoHandshakeMessage;
+class ProofVerifier;
+class ProofVerifyDetails;
+class QuicRandom;
+
+// QuicCryptoClientConfig contains crypto-related configuration settings for a
+// client. Note that this object isn't thread-safe. It's designed to be used on
+// a single thread at a time.
+class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
+ public:
+ // A CachedState contains the information that the client needs in order to
+ // perform a 0-RTT handshake with a server. This information can be reused
+ // over several connections to the same server.
+ class NET_EXPORT_PRIVATE CachedState {
+ public:
+ // Enum to track if the server config is valid or not. If it is not valid,
+ // it specifies why it is invalid.
+ enum ServerConfigState {
+ // WARNING: Do not change the numerical values of any of server config
+ // state. Do not remove deprecated server config states - just comment
+ // them as deprecated.
+ SERVER_CONFIG_EMPTY = 0,
+ SERVER_CONFIG_INVALID = 1,
+ SERVER_CONFIG_CORRUPTED = 2,
+ SERVER_CONFIG_EXPIRED = 3,
+ SERVER_CONFIG_INVALID_EXPIRY = 4,
+ SERVER_CONFIG_VALID = 5,
+ // NOTE: Add new server config states only immediately above this line.
+ // Make sure to update the QuicServerConfigState enum in
+ // tools/metrics/histograms/histograms.xml accordingly.
+ SERVER_CONFIG_COUNT
+ };
+
+ CachedState();
+ ~CachedState();
+
+ // IsComplete returns true if this object contains enough information to
+ // perform a handshake with the server. |now| is used to judge whether any
+ // cached server config has expired.
+ bool IsComplete(QuicWallTime now) const;
+
+ // IsEmpty returns true if |server_config_| is empty.
+ bool IsEmpty() const;
+
+ // GetServerConfig returns the parsed contents of |server_config|, or
+ // nullptr if |server_config| is empty. The return value is owned by this
+ // object and is destroyed when this object is.
+ const CryptoHandshakeMessage* GetServerConfig() const;
+
+ // SetServerConfig checks that |server_config| parses correctly and stores
+ // it in |server_config_|. |now| is used to judge whether |server_config|
+ // has expired.
+ ServerConfigState SetServerConfig(base::StringPiece server_config,
+ QuicWallTime now,
+ QuicWallTime expiry_time,
+ std::string* error_details);
+
+ // InvalidateServerConfig clears the cached server config (if any).
+ void InvalidateServerConfig();
+
+ // SetProof stores a certificate chain and signature.
+ void SetProof(const std::vector<std::string>& certs,
+ base::StringPiece cert_sct,
+ base::StringPiece chlo_hash,
+ base::StringPiece signature);
+
+ // Clears all the data.
+ void Clear();
+
+ // Clears the certificate chain and signature and invalidates the proof.
+ void ClearProof();
+
+ // SetProofValid records that the certificate chain and signature have been
+ // validated and that it's safe to assume that the server is legitimate.
+ // (Note: this does not check the chain or signature.)
+ void SetProofValid();
+
+ // If the server config or the proof has changed then it needs to be
+ // revalidated. Helper function to keep server_config_valid_ and
+ // generation_counter_ in sync.
+ void SetProofInvalid();
+
+ const std::string& server_config() const;
+ const std::string& source_address_token() const;
+ const std::vector<std::string>& certs() const;
+ const std::string& cert_sct() const;
+ const std::string& chlo_hash() const;
+ const std::string& signature() const;
+ bool proof_valid() const;
+ uint64_t generation_counter() const;
+ const ProofVerifyDetails* proof_verify_details() const;
+
+ void set_source_address_token(base::StringPiece token);
+
+ void set_cert_sct(base::StringPiece cert_sct);
+
+ // Adds the connection ID to the queue of server-designated connection-ids.
+ void add_server_designated_connection_id(QuicConnectionId connection_id);
+
+ // If true, the crypto config contains at least one connection ID specified
+ // by the server, and the client should use one of these IDs when initiating
+ // the next connection.
+ bool has_server_designated_connection_id() const;
+
+ // This function should only be called when
+ // has_server_designated_connection_id is true. Returns the next
+ // connection_id specified by the server and removes it from the
+ // queue of ids.
+ QuicConnectionId GetNextServerDesignatedConnectionId();
+
+ // Adds the servernonce to the queue of server nonces.
+ void add_server_nonce(const std::string& server_nonce);
+
+ // If true, the crypto config contains at least one server nonce, and the
+ // client should use one of these nonces.
+ bool has_server_nonce() const;
+
+ // This function should only be called when has_server_nonce is true.
+ // Returns the next server_nonce specified by the server and removes it
+ // from the queue of nonces.
+ std::string GetNextServerNonce();
+
+ // SetProofVerifyDetails takes ownership of |details|.
+ void SetProofVerifyDetails(ProofVerifyDetails* details);
+
+ // Copy the |server_config_|, |source_address_token_|, |certs_|,
+ // |expiration_time_|, |cert_sct_|, |chlo_hash_| and |server_config_sig_|
+ // from the |other|. The remaining fields, |generation_counter_|,
+ // |proof_verify_details_|, and |scfg_| remain unchanged.
+ void InitializeFrom(const CachedState& other);
+
+ // Initializes this cached state based on the arguments provided.
+ // Returns false if there is a problem parsing the server config.
+ bool Initialize(base::StringPiece server_config,
+ base::StringPiece source_address_token,
+ const std::vector<std::string>& certs,
+ base::StringPiece cert_sct,
+ base::StringPiece chlo_hash,
+ base::StringPiece signature,
+ QuicWallTime now,
+ QuicWallTime expiration_time);
+
+ private:
+ std::string server_config_; // A serialized handshake message.
+ std::string source_address_token_; // An opaque proof of IP ownership.
+ std::vector<std::string> certs_; // A list of certificates in leaf-first
+ // order.
+ std::string cert_sct_; // Signed timestamp of the leaf cert.
+ std::string chlo_hash_; // Hash of the CHLO message.
+ std::string server_config_sig_; // A signature of |server_config_|.
+ bool server_config_valid_; // True if |server_config_| is correctly
+ // signed and |certs_| has been
+ // validated.
+ QuicWallTime expiration_time_; // Time when the config is no longer
+ // valid.
+ // Generation counter associated with the |server_config_|, |certs_| and
+ // |server_config_sig_| combination. It is incremented whenever we set
+ // server_config_valid_ to false.
+ uint64_t generation_counter_;
+
+ std::unique_ptr<ProofVerifyDetails> proof_verify_details_;
+
+ // scfg contains the cached, parsed value of |server_config|.
+ mutable std::unique_ptr<CryptoHandshakeMessage> scfg_;
+
+ // TODO(jokulik): Consider using a hash-set as extra book-keeping to ensure
+ // that no connection-id is added twice. Also, consider keeping the server
+ // nonces and connection_ids together in one queue.
+ std::queue<QuicConnectionId> server_designated_connection_ids_;
+ std::queue<std::string> server_nonces_;
+
+ DISALLOW_COPY_AND_ASSIGN(CachedState);
+ };
+
+ // Used to filter server ids for partial config deletion.
+ class ServerIdFilter {
+ public:
+ // Returns true if |server_id| matches the filter.
+ virtual bool Matches(const QuicServerId& server_id) const = 0;
+ };
+
+ explicit QuicCryptoClientConfig(
+ std::unique_ptr<ProofVerifier> proof_verifier);
+ ~QuicCryptoClientConfig();
+
+ // LookupOrCreate returns a CachedState for the given |server_id|. If no such
+ // CachedState currently exists, it will be created and cached.
+ CachedState* LookupOrCreate(const QuicServerId& server_id);
+
+ // Delete CachedState objects whose server ids match |filter| from
+ // cached_states.
+ void ClearCachedStates(const ServerIdFilter& filter);
+
+ // FillInchoateClientHello sets |out| to be a CHLO message that elicits a
+ // source-address token or SCFG from a server. If |cached| is non-nullptr, the
+ // source-address token will be taken from it. |out_params| is used in order
+ // to store the cached certs that were sent as hints to the server in
+ // |out_params->cached_certs|. |preferred_version| is the version of the
+ // QUIC protocol that this client chose to use initially. This allows the
+ // server to detect downgrade attacks. If |demand_x509_proof| is true,
+ // then |out| will include an X509 proof demand, and the associated
+ // certificate related fields.
+ void FillInchoateClientHello(const QuicServerId& server_id,
+ const QuicVersion preferred_version,
+ const CachedState* cached,
+ QuicRandom* rand,
+ bool demand_x509_proof,
+ QuicCryptoNegotiatedParameters* out_params,
+ CryptoHandshakeMessage* out) const;
+
+ // FillClientHello sets |out| to be a CHLO message based on the configuration
+ // of this object. This object must have cached enough information about
+ // the server's hostname in order to perform a handshake. This can be checked
+ // with the |IsComplete| member of |CachedState|.
+ //
+ // |now| and |rand| are used to generate the nonce and |out_params| is
+ // filled with the results of the handshake that the server is expected to
+ // accept. |preferred_version| is the version of the QUIC protocol that this
+ // client chose to use initially. This allows the server to detect downgrade
+ // attacks.
+ //
+ // If |channel_id_key| is not null, it is used to sign a secret value derived
+ // from the client and server's keys, and the Channel ID public key and the
+ // signature are placed in the CETV value of the CHLO.
+ QuicErrorCode FillClientHello(const QuicServerId& server_id,
+ QuicConnectionId connection_id,
+ const QuicVersion actual_version,
+ const QuicVersion preferred_version,
+ const CachedState* cached,
+ QuicWallTime now,
+ QuicRandom* rand,
+ const ChannelIDKey* channel_id_key,
+ QuicCryptoNegotiatedParameters* out_params,
+ CryptoHandshakeMessage* out,
+ std::string* error_details) const;
+
+ // ProcessRejection processes a REJ message from a server and updates the
+ // cached information about that server. After this, |IsComplete| may return
+ // true for that server's CachedState. If the rejection message contains state
+ // about a future handshake (i.e. an nonce value from the server), then it
+ // will be saved in |out_params|. |now| is used to judge whether the server
+ // config in the rejection message has expired.
+ QuicErrorCode ProcessRejection(const CryptoHandshakeMessage& rej,
+ QuicWallTime now,
+ QuicVersion version,
+ base::StringPiece chlo_hash,
+ CachedState* cached,
+ QuicCryptoNegotiatedParameters* out_params,
+ std::string* error_details);
+
+ // ProcessServerHello processes the message in |server_hello|, updates the
+ // cached information about that server, writes the negotiated parameters to
+ // |out_params| and returns QUIC_NO_ERROR. If |server_hello| is unacceptable
+ // then it puts an error message in |error_details| and returns an error
+ // code. |version| is the QUIC version for the current connection.
+ // |negotiated_versions| contains the list of version, if any, that were
+ // present in a version negotiation packet previously recevied from the
+ // server. The contents of this list will be compared against the list of
+ // versions provided in the VER tag of the server hello.
+ QuicErrorCode ProcessServerHello(const CryptoHandshakeMessage& server_hello,
+ QuicConnectionId connection_id,
+ QuicVersion version,
+ const QuicVersionVector& negotiated_versions,
+ CachedState* cached,
+ QuicCryptoNegotiatedParameters* out_params,
+ std::string* error_details);
+
+ // Processes the message in |server_update|, updating the cached source
+ // address token, and server config.
+ // If |server_update| is invalid then |error_details| will contain an error
+ // message, and an error code will be returned. If all has gone well
+ // QUIC_NO_ERROR is returned.
+ QuicErrorCode ProcessServerConfigUpdate(
+ const CryptoHandshakeMessage& server_update,
+ QuicWallTime now,
+ const QuicVersion version,
+ base::StringPiece chlo_hash,
+ CachedState* cached,
+ QuicCryptoNegotiatedParameters* out_params,
+ std::string* error_details);
+
+ ProofVerifier* proof_verifier() const;
+
+ ChannelIDSource* channel_id_source() 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
+ // |source|.
+ void SetChannelIDSource(ChannelIDSource* source);
+
+ // Initialize the CachedState from |canonical_crypto_config| for the
+ // |canonical_server_id| as the initial CachedState for |server_id|. We will
+ // copy config data only if |canonical_crypto_config| has valid proof.
+ void InitializeFrom(const QuicServerId& server_id,
+ const QuicServerId& canonical_server_id,
+ QuicCryptoClientConfig* canonical_crypto_config);
+
+ // Adds |suffix| as a domain suffix for which the server's crypto config
+ // is expected to be shared among servers with the domain suffix. If a server
+ // matches this suffix, then the server config from another server with the
+ // suffix will be used to initialize the cached state for this server.
+ void AddCanonicalSuffix(const std::string& suffix);
+
+ // Prefers AES-GCM (kAESG) over other AEAD algorithms. Call this method if
+ // the CPU has hardware acceleration for AES-GCM. This method can only be
+ // called after SetDefaults().
+ void PreferAesGcm();
+
+ // Saves the |user_agent_id| that will be passed in QUIC's CHLO message.
+ void set_user_agent_id(const std::string& user_agent_id) {
+ user_agent_id_ = user_agent_id;
+ }
+
+ private:
+ typedef std::map<QuicServerId, CachedState*> CachedStateMap;
+
+ // Sets the members to reasonable, default values.
+ void SetDefaults();
+
+ // CacheNewServerConfig checks for SCFG, STK, PROF, and CRT tags in |message|,
+ // verifies them, and stores them in the cached state if they validate.
+ // This is used on receipt of a REJ from a server, or when a server sends
+ // updated server config during a connection.
+ QuicErrorCode CacheNewServerConfig(
+ const CryptoHandshakeMessage& message,
+ QuicWallTime now,
+ const QuicVersion version,
+ base::StringPiece chlo_hash,
+ const std::vector<std::string>& cached_certs,
+ CachedState* cached,
+ std::string* error_details);
+
+ // If the suffix of the hostname in |server_id| is in |canonical_suffixes_|,
+ // then populate |cached| with the canonical cached state from
+ // |canonical_server_map_| for that suffix. Returns true if |cached| is
+ // initialized with canonical cached state.
+ bool PopulateFromCanonicalConfig(const QuicServerId& server_id,
+ CachedState* cached);
+
+ // cached_states_ maps from the server_id to the cached information about
+ // that server.
+ CachedStateMap cached_states_;
+
+ // Contains a map of servers which could share the same server config. Map
+ // from a canonical host suffix/port/scheme to a representative server with
+ // the canonical suffix, which has a plausible set of initial certificates
+ // (or at least server public key).
+ std::map<QuicServerId, QuicServerId> canonical_server_map_;
+
+ // Contains list of suffixes (for exmaple ".c.youtube.com",
+ // ".googlevideo.com") of canonical hostnames.
+ std::vector<std::string> canonical_suffixes_;
+
+ std::unique_ptr<ProofVerifier> proof_verifier_;
+ std::unique_ptr<ChannelIDSource> channel_id_source_;
+
+ // The |user_agent_id_| passed in QUIC's CHLO message.
+ std::string user_agent_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientConfig);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_QUIC_CRYPTO_CLIENT_CONFIG_H_
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
new file mode 100644
index 00000000000..072f8657abe
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_crypto_client_config_test.cc
@@ -0,0 +1,539 @@
+// Copyright 2013 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/crypto/quic_crypto_client_config.h"
+
+#include "net/quic/core/crypto/proof_verifier.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/mock_random.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+using std::vector;
+
+namespace net {
+namespace test {
+namespace {
+
+class TestProofVerifyDetails : public ProofVerifyDetails {
+ ~TestProofVerifyDetails() override {}
+
+ // ProofVerifyDetails implementation
+ ProofVerifyDetails* Clone() const override {
+ return new TestProofVerifyDetails;
+ }
+};
+
+class OneServerIdFilter : public QuicCryptoClientConfig::ServerIdFilter {
+ public:
+ OneServerIdFilter(const QuicServerId* server_id) : server_id_(*server_id) {}
+
+ bool Matches(const QuicServerId& server_id) const override {
+ return server_id == server_id_;
+ }
+
+ private:
+ const QuicServerId server_id_;
+};
+
+class AllServerIdsFilter : public QuicCryptoClientConfig::ServerIdFilter {
+ public:
+ bool Matches(const QuicServerId& server_id) const override { return true; }
+};
+
+} // namespace
+
+TEST(QuicCryptoClientConfigTest, CachedState_IsEmpty) {
+ QuicCryptoClientConfig::CachedState state;
+ EXPECT_TRUE(state.IsEmpty());
+}
+
+TEST(QuicCryptoClientConfigTest, CachedState_IsComplete) {
+ QuicCryptoClientConfig::CachedState state;
+ EXPECT_FALSE(state.IsComplete(QuicWallTime::FromUNIXSeconds(0)));
+}
+
+TEST(QuicCryptoClientConfigTest, CachedState_GenerationCounter) {
+ QuicCryptoClientConfig::CachedState state;
+ EXPECT_EQ(0u, state.generation_counter());
+ state.SetProofInvalid();
+ EXPECT_EQ(1u, state.generation_counter());
+}
+
+TEST(QuicCryptoClientConfigTest, CachedState_SetProofVerifyDetails) {
+ QuicCryptoClientConfig::CachedState state;
+ EXPECT_TRUE(state.proof_verify_details() == nullptr);
+ ProofVerifyDetails* details = new TestProofVerifyDetails;
+ state.SetProofVerifyDetails(details);
+ EXPECT_EQ(details, state.proof_verify_details());
+}
+
+TEST(QuicCryptoClientConfigTest, CachedState_ServerDesignatedConnectionId) {
+ QuicCryptoClientConfig::CachedState state;
+ EXPECT_FALSE(state.has_server_designated_connection_id());
+
+ QuicConnectionId connection_id = 1234;
+ state.add_server_designated_connection_id(connection_id);
+ EXPECT_TRUE(state.has_server_designated_connection_id());
+ EXPECT_EQ(connection_id, state.GetNextServerDesignatedConnectionId());
+ EXPECT_FALSE(state.has_server_designated_connection_id());
+
+ // Allow the ID to be set multiple times. It's unusual that this would
+ // happen, but not impossible.
+ ++connection_id;
+ state.add_server_designated_connection_id(connection_id);
+ EXPECT_TRUE(state.has_server_designated_connection_id());
+ EXPECT_EQ(connection_id, state.GetNextServerDesignatedConnectionId());
+ ++connection_id;
+ state.add_server_designated_connection_id(connection_id);
+ EXPECT_EQ(connection_id, state.GetNextServerDesignatedConnectionId());
+ EXPECT_FALSE(state.has_server_designated_connection_id());
+
+ // Test FIFO behavior.
+ const QuicConnectionId first_cid = 0xdeadbeef;
+ const QuicConnectionId second_cid = 0xfeedbead;
+ state.add_server_designated_connection_id(first_cid);
+ state.add_server_designated_connection_id(second_cid);
+ EXPECT_TRUE(state.has_server_designated_connection_id());
+ EXPECT_EQ(first_cid, state.GetNextServerDesignatedConnectionId());
+ EXPECT_EQ(second_cid, state.GetNextServerDesignatedConnectionId());
+}
+
+TEST(QuicCryptoClientConfigTest, CachedState_ServerIdConsumedBeforeSet) {
+ QuicCryptoClientConfig::CachedState state;
+ EXPECT_FALSE(state.has_server_designated_connection_id());
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+ EXPECT_DEBUG_DEATH(state.GetNextServerDesignatedConnectionId(),
+ "Attempting to consume a connection id "
+ "that was never designated.");
+#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+}
+
+TEST(QuicCryptoClientConfigTest, CachedState_ServerNonce) {
+ QuicCryptoClientConfig::CachedState state;
+ EXPECT_FALSE(state.has_server_nonce());
+
+ string server_nonce = "nonce_1";
+ state.add_server_nonce(server_nonce);
+ EXPECT_TRUE(state.has_server_nonce());
+ EXPECT_EQ(server_nonce, state.GetNextServerNonce());
+ EXPECT_FALSE(state.has_server_nonce());
+
+ // Allow the ID to be set multiple times. It's unusual that this would
+ // happen, but not impossible.
+ server_nonce = "nonce_2";
+ state.add_server_nonce(server_nonce);
+ EXPECT_TRUE(state.has_server_nonce());
+ EXPECT_EQ(server_nonce, state.GetNextServerNonce());
+ server_nonce = "nonce_3";
+ state.add_server_nonce(server_nonce);
+ EXPECT_EQ(server_nonce, state.GetNextServerNonce());
+ EXPECT_FALSE(state.has_server_nonce());
+
+ // Test FIFO behavior.
+ const string first_nonce = "first_nonce";
+ const string second_nonce = "second_nonce";
+ state.add_server_nonce(first_nonce);
+ state.add_server_nonce(second_nonce);
+ EXPECT_TRUE(state.has_server_nonce());
+ EXPECT_EQ(first_nonce, state.GetNextServerNonce());
+ EXPECT_EQ(second_nonce, state.GetNextServerNonce());
+}
+
+TEST(QuicCryptoClientConfigTest, CachedState_ServerNonceConsumedBeforeSet) {
+ QuicCryptoClientConfig::CachedState state;
+ EXPECT_FALSE(state.has_server_nonce());
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+ EXPECT_DEBUG_DEATH(state.GetNextServerNonce(),
+ "Attempting to consume a server nonce "
+ "that was never designated.");
+#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+}
+
+TEST(QuicCryptoClientConfigTest, CachedState_InitializeFrom) {
+ QuicCryptoClientConfig::CachedState state;
+ QuicCryptoClientConfig::CachedState other;
+ state.set_source_address_token("TOKEN");
+ // TODO(rch): Populate other fields of |state|.
+ other.InitializeFrom(state);
+ EXPECT_EQ(state.server_config(), other.server_config());
+ EXPECT_EQ(state.source_address_token(), other.source_address_token());
+ EXPECT_EQ(state.certs(), other.certs());
+ EXPECT_EQ(1u, other.generation_counter());
+ EXPECT_FALSE(state.has_server_designated_connection_id());
+ EXPECT_FALSE(state.has_server_nonce());
+}
+
+TEST(QuicCryptoClientConfigTest, InchoateChlo) {
+ QuicCryptoClientConfig::CachedState state;
+ QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
+ QuicCryptoNegotiatedParameters params;
+ CryptoHandshakeMessage msg;
+ QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
+ MockRandom rand;
+ config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
+ /* demand_x509_proof= */ true, &params, &msg);
+
+ QuicTag cver;
+ EXPECT_EQ(QUIC_NO_ERROR, msg.GetUint32(kVER, &cver));
+ EXPECT_EQ(QuicVersionToQuicTag(QuicVersionMax()), cver);
+ StringPiece proof_nonce;
+ EXPECT_TRUE(msg.GetStringPiece(kNONP, &proof_nonce));
+ EXPECT_EQ(string(32, 'r'), proof_nonce);
+}
+
+TEST(QuicCryptoClientConfigTest, PreferAesGcm) {
+ QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
+ if (config.aead.size() > 1)
+ EXPECT_NE(kAESG, config.aead[0]);
+ config.PreferAesGcm();
+ EXPECT_EQ(kAESG, config.aead[0]);
+}
+
+TEST(QuicCryptoClientConfigTest, InchoateChloSecure) {
+ QuicCryptoClientConfig::CachedState state;
+ QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
+ QuicCryptoNegotiatedParameters params;
+ CryptoHandshakeMessage msg;
+ QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
+ MockRandom rand;
+ config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
+ /* demand_x509_proof= */ true, &params, &msg);
+
+ QuicTag pdmd;
+ EXPECT_EQ(QUIC_NO_ERROR, msg.GetUint32(kPDMD, &pdmd));
+ EXPECT_EQ(kX509, pdmd);
+ StringPiece scid;
+ EXPECT_FALSE(msg.GetStringPiece(kSCID, &scid));
+}
+
+TEST(QuicCryptoClientConfigTest, InchoateChloSecureWithSCIDNoEXPY) {
+ // Test that a config with no EXPY is still valid when a non-zero
+ // expiry time is passed in.
+ QuicCryptoClientConfig::CachedState state;
+ CryptoHandshakeMessage scfg;
+ scfg.set_tag(kSCFG);
+ scfg.SetStringPiece(kSCID, "12345678");
+ string details;
+ QuicWallTime now = QuicWallTime::FromUNIXSeconds(1);
+ QuicWallTime expiry = QuicWallTime::FromUNIXSeconds(2);
+ state.SetServerConfig(scfg.GetSerialized().AsStringPiece(), now, expiry,
+ &details);
+
+ QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
+ QuicCryptoNegotiatedParameters params;
+ CryptoHandshakeMessage msg;
+ QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
+ MockRandom rand;
+ config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
+ /* demand_x509_proof= */ true, &params, &msg);
+
+ StringPiece scid;
+ EXPECT_TRUE(msg.GetStringPiece(kSCID, &scid));
+ EXPECT_EQ("12345678", scid);
+}
+
+TEST(QuicCryptoClientConfigTest, InchoateChloSecureWithSCID) {
+ QuicCryptoClientConfig::CachedState state;
+ CryptoHandshakeMessage scfg;
+ scfg.set_tag(kSCFG);
+ uint64_t future = 1;
+ scfg.SetValue(kEXPY, future);
+ scfg.SetStringPiece(kSCID, "12345678");
+ string details;
+ state.SetServerConfig(scfg.GetSerialized().AsStringPiece(),
+ QuicWallTime::FromUNIXSeconds(1),
+ QuicWallTime::FromUNIXSeconds(0), &details);
+
+ QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
+ QuicCryptoNegotiatedParameters params;
+ CryptoHandshakeMessage msg;
+ QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
+ MockRandom rand;
+ config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
+ /* demand_x509_proof= */ true, &params, &msg);
+
+ StringPiece scid;
+ EXPECT_TRUE(msg.GetStringPiece(kSCID, &scid));
+ EXPECT_EQ("12345678", scid);
+}
+
+TEST(QuicCryptoClientConfigTest, FillClientHello) {
+ QuicCryptoClientConfig::CachedState state;
+ QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
+ QuicCryptoNegotiatedParameters params;
+ QuicConnectionId kConnectionId = 1234;
+ string error_details;
+ MockRandom rand;
+ CryptoHandshakeMessage chlo;
+ QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
+ config.FillClientHello(server_id, kConnectionId, QuicVersionMax(),
+ QuicVersionMax(), &state, QuicWallTime::Zero(), &rand,
+ nullptr, // channel_id_key
+ &params, &chlo, &error_details);
+
+ // Verify that certain QuicTags have been set correctly in the CHLO.
+ QuicTag cver;
+ EXPECT_EQ(QUIC_NO_ERROR, chlo.GetUint32(kVER, &cver));
+ EXPECT_EQ(QuicVersionToQuicTag(QuicVersionMax()), cver);
+}
+
+TEST(QuicCryptoClientConfigTest, ProcessServerDowngradeAttack) {
+ QuicVersionVector supported_versions = AllSupportedVersions();
+ if (supported_versions.size() == 1) {
+ // No downgrade attack is possible if the client only supports one version.
+ return;
+ }
+ QuicTagVector supported_version_tags;
+ for (size_t i = supported_versions.size(); i > 0; --i) {
+ supported_version_tags.push_back(
+ QuicVersionToQuicTag(supported_versions[i - 1]));
+ }
+ CryptoHandshakeMessage msg;
+ msg.set_tag(kSHLO);
+ msg.SetVector(kVER, supported_version_tags);
+
+ QuicCryptoClientConfig::CachedState cached;
+ QuicCryptoNegotiatedParameters out_params;
+ string error;
+ QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
+ EXPECT_EQ(QUIC_VERSION_NEGOTIATION_MISMATCH,
+ config.ProcessServerHello(msg, 0, supported_versions.front(),
+ supported_versions, &cached, &out_params,
+ &error));
+ EXPECT_EQ("Downgrade attack detected", error);
+}
+
+TEST(QuicCryptoClientConfigTest, InitializeFrom) {
+ QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
+ QuicServerId canonical_server_id("www.google.com", 443,
+ PRIVACY_MODE_DISABLED);
+ QuicCryptoClientConfig::CachedState* state =
+ config.LookupOrCreate(canonical_server_id);
+ // TODO(rch): Populate other fields of |state|.
+ state->set_source_address_token("TOKEN");
+ state->SetProofValid();
+
+ QuicServerId other_server_id("mail.google.com", 443, PRIVACY_MODE_DISABLED);
+ config.InitializeFrom(other_server_id, canonical_server_id, &config);
+ QuicCryptoClientConfig::CachedState* other =
+ config.LookupOrCreate(other_server_id);
+
+ EXPECT_EQ(state->server_config(), other->server_config());
+ EXPECT_EQ(state->source_address_token(), other->source_address_token());
+ EXPECT_EQ(state->certs(), other->certs());
+ EXPECT_EQ(1u, other->generation_counter());
+}
+
+TEST(QuicCryptoClientConfigTest, Canonical) {
+ QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
+ config.AddCanonicalSuffix(".google.com");
+ QuicServerId canonical_id1("www.google.com", 443, PRIVACY_MODE_DISABLED);
+ QuicServerId canonical_id2("mail.google.com", 443, PRIVACY_MODE_DISABLED);
+ QuicCryptoClientConfig::CachedState* state =
+ config.LookupOrCreate(canonical_id1);
+ // TODO(rch): Populate other fields of |state|.
+ state->set_source_address_token("TOKEN");
+ state->SetProofValid();
+
+ QuicCryptoClientConfig::CachedState* other =
+ config.LookupOrCreate(canonical_id2);
+
+ EXPECT_TRUE(state->IsEmpty());
+ EXPECT_EQ(state->server_config(), other->server_config());
+ EXPECT_EQ(state->source_address_token(), other->source_address_token());
+ EXPECT_EQ(state->certs(), other->certs());
+ EXPECT_EQ(1u, other->generation_counter());
+
+ QuicServerId different_id("mail.google.org", 443, PRIVACY_MODE_DISABLED);
+ EXPECT_TRUE(config.LookupOrCreate(different_id)->IsEmpty());
+}
+
+TEST(QuicCryptoClientConfigTest, CanonicalNotUsedIfNotValid) {
+ QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
+ config.AddCanonicalSuffix(".google.com");
+ QuicServerId canonical_id1("www.google.com", 443, PRIVACY_MODE_DISABLED);
+ QuicServerId canonical_id2("mail.google.com", 443, PRIVACY_MODE_DISABLED);
+ QuicCryptoClientConfig::CachedState* state =
+ config.LookupOrCreate(canonical_id1);
+ // TODO(rch): Populate other fields of |state|.
+ state->set_source_address_token("TOKEN");
+
+ // Do not set the proof as valid, and check that it is not used
+ // as a canonical entry.
+ EXPECT_TRUE(config.LookupOrCreate(canonical_id2)->IsEmpty());
+}
+
+TEST(QuicCryptoClientConfigTest, ClearCachedStates) {
+ QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
+
+ // Create two states on different origins.
+ struct TestCase {
+ TestCase(const std::string& host, QuicCryptoClientConfig* config)
+ : server_id(host, 443, PRIVACY_MODE_DISABLED),
+ state(config->LookupOrCreate(server_id)) {
+ // TODO(rch): Populate other fields of |state|.
+ CryptoHandshakeMessage scfg;
+ scfg.set_tag(kSCFG);
+ uint64_t future = 1;
+ scfg.SetValue(kEXPY, future);
+ scfg.SetStringPiece(kSCID, "12345678");
+ string details;
+ state->SetServerConfig(scfg.GetSerialized().AsStringPiece(),
+ QuicWallTime::FromUNIXSeconds(0),
+ QuicWallTime::FromUNIXSeconds(future), &details);
+
+ vector<string> certs(1);
+ certs[0] = "Hello Cert for " + host;
+ state->SetProof(certs, "cert_sct", "chlo_hash", "signature");
+ state->set_source_address_token("TOKEN");
+ state->SetProofValid();
+
+ // The generation counter starts at 2, because proof has been once
+ // invalidated in SetServerConfig().
+ EXPECT_EQ(2u, state->generation_counter());
+ }
+
+ QuicServerId server_id;
+ QuicCryptoClientConfig::CachedState* state;
+ } test_cases[] = {TestCase("www.google.com", &config),
+ TestCase("www.example.com", &config)};
+
+ // Verify LookupOrCreate returns the same data.
+ for (const TestCase& test_case : test_cases) {
+ QuicCryptoClientConfig::CachedState* other =
+ config.LookupOrCreate(test_case.server_id);
+ EXPECT_EQ(test_case.state, other);
+ EXPECT_EQ(2u, other->generation_counter());
+ }
+
+ // Clear the cached state for www.google.com.
+ OneServerIdFilter google_com_filter(&test_cases[0].server_id);
+ config.ClearCachedStates(google_com_filter);
+
+ // Verify LookupOrCreate doesn't have any data for google.com.
+ QuicCryptoClientConfig::CachedState* cleared_cache =
+ config.LookupOrCreate(test_cases[0].server_id);
+
+ EXPECT_EQ(test_cases[0].state, cleared_cache);
+ EXPECT_FALSE(cleared_cache->proof_valid());
+ EXPECT_TRUE(cleared_cache->server_config().empty());
+ EXPECT_TRUE(cleared_cache->certs().empty());
+ EXPECT_TRUE(cleared_cache->cert_sct().empty());
+ EXPECT_TRUE(cleared_cache->signature().empty());
+ EXPECT_EQ(3u, cleared_cache->generation_counter());
+
+ // But it still does for www.example.com.
+ QuicCryptoClientConfig::CachedState* existing_cache =
+ config.LookupOrCreate(test_cases[1].server_id);
+
+ EXPECT_EQ(test_cases[1].state, existing_cache);
+ EXPECT_TRUE(existing_cache->proof_valid());
+ EXPECT_FALSE(existing_cache->server_config().empty());
+ EXPECT_FALSE(existing_cache->certs().empty());
+ EXPECT_FALSE(existing_cache->cert_sct().empty());
+ EXPECT_FALSE(existing_cache->signature().empty());
+ EXPECT_EQ(2u, existing_cache->generation_counter());
+
+ // Clear all cached states.
+ AllServerIdsFilter all_server_ids;
+ config.ClearCachedStates(all_server_ids);
+
+ // The data for www.example.com should now be cleared as well.
+ cleared_cache = config.LookupOrCreate(test_cases[1].server_id);
+
+ EXPECT_EQ(test_cases[1].state, cleared_cache);
+ EXPECT_FALSE(cleared_cache->proof_valid());
+ EXPECT_TRUE(cleared_cache->server_config().empty());
+ EXPECT_TRUE(cleared_cache->certs().empty());
+ EXPECT_TRUE(cleared_cache->cert_sct().empty());
+ EXPECT_TRUE(cleared_cache->signature().empty());
+ EXPECT_EQ(3u, cleared_cache->generation_counter());
+}
+
+TEST(QuicCryptoClientConfigTest, ProcessReject) {
+ CryptoHandshakeMessage rej;
+ CryptoTestUtils::FillInDummyReject(&rej, /* stateless */ false);
+
+ // Now process the rejection.
+ QuicCryptoClientConfig::CachedState cached;
+ QuicCryptoNegotiatedParameters out_params;
+ string error;
+ QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
+ EXPECT_EQ(QUIC_NO_ERROR,
+ config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0),
+ AllSupportedVersions().front(), "", &cached,
+ &out_params, &error));
+ EXPECT_FALSE(cached.has_server_designated_connection_id());
+ EXPECT_FALSE(cached.has_server_nonce());
+}
+
+TEST(QuicCryptoClientConfigTest, ProcessStatelessReject) {
+ // Create a dummy reject message and mark it as stateless.
+ CryptoHandshakeMessage rej;
+ CryptoTestUtils::FillInDummyReject(&rej, /* stateless */ true);
+ const QuicConnectionId kConnectionId = 0xdeadbeef;
+ const string server_nonce = "SERVER_NONCE";
+ rej.SetValue(kRCID, kConnectionId);
+ rej.SetStringPiece(kServerNonceTag, server_nonce);
+
+ // Now process the rejection.
+ QuicCryptoClientConfig::CachedState cached;
+ QuicCryptoNegotiatedParameters out_params;
+ string error;
+ QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
+ EXPECT_EQ(QUIC_NO_ERROR,
+ config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0),
+ AllSupportedVersions().front(), "", &cached,
+ &out_params, &error));
+ EXPECT_TRUE(cached.has_server_designated_connection_id());
+ EXPECT_EQ(kConnectionId, cached.GetNextServerDesignatedConnectionId());
+ EXPECT_EQ(server_nonce, cached.GetNextServerNonce());
+}
+
+TEST(QuicCryptoClientConfigTest, BadlyFormattedStatelessReject) {
+ // Create a dummy reject message and mark it as stateless. Do not
+ // add an server-designated connection-id.
+ CryptoHandshakeMessage rej;
+ CryptoTestUtils::FillInDummyReject(&rej, /* stateless */ true);
+
+ // Now process the rejection.
+ QuicCryptoClientConfig::CachedState cached;
+ QuicCryptoNegotiatedParameters out_params;
+ string error;
+ QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
+ EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
+ config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0),
+ AllSupportedVersions().front(), "", &cached,
+ &out_params, &error));
+ EXPECT_FALSE(cached.has_server_designated_connection_id());
+ EXPECT_EQ("Missing kRCID", error);
+}
+
+TEST(QuicCryptoClientConfigTest, ServerNonceinSHLO) {
+ // Test that the server must include a nonce in the SHLO.
+ CryptoHandshakeMessage msg;
+ msg.set_tag(kSHLO);
+ // Choose the latest version.
+ QuicVersionVector supported_versions;
+ QuicVersion version = AllSupportedVersions().front();
+ supported_versions.push_back(version);
+ QuicTagVector versions;
+ versions.push_back(QuicVersionToQuicTag(version));
+ msg.SetVector(kVER, versions);
+
+ QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
+ QuicCryptoClientConfig::CachedState cached;
+ QuicCryptoNegotiatedParameters out_params;
+ string error_details;
+ EXPECT_EQ(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
+ config.ProcessServerHello(msg, 0, version, supported_versions,
+ &cached, &out_params, &error_details));
+ EXPECT_EQ("server hello missing server nonce", error_details);
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/quic_crypto_server_config.cc b/chromium/net/quic/core/crypto/quic_crypto_server_config.cc
new file mode 100644
index 00000000000..fbfc92cf27a
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_crypto_server_config.cc
@@ -0,0 +1,2164 @@
+// Copyright 2013 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/crypto/quic_crypto_server_config.h"
+
+#include <stdlib.h>
+
+#include <algorithm>
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/stl_util.h"
+#include "crypto/hkdf.h"
+#include "crypto/secure_hash.h"
+#include "net/base/ip_address.h"
+#include "net/quic/core/crypto/aes_128_gcm_12_decrypter.h"
+#include "net/quic/core/crypto/aes_128_gcm_12_encrypter.h"
+#include "net/quic/core/crypto/cert_compressor.h"
+#include "net/quic/core/crypto/chacha20_poly1305_encrypter.h"
+#include "net/quic/core/crypto/channel_id.h"
+#include "net/quic/core/crypto/crypto_framer.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/crypto/crypto_server_config_protobuf.h"
+#include "net/quic/core/crypto/crypto_utils.h"
+#include "net/quic/core/crypto/curve25519_key_exchange.h"
+#include "net/quic/core/crypto/ephemeral_key_source.h"
+#include "net/quic/core/crypto/key_exchange.h"
+#include "net/quic/core/crypto/local_strike_register_client.h"
+#include "net/quic/core/crypto/p256_key_exchange.h"
+#include "net/quic/core/crypto/proof_source.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/crypto/strike_register.h"
+#include "net/quic/core/crypto/strike_register_client.h"
+#include "net/quic/core/proto/source_address_token.pb.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_socket_address_coder.h"
+#include "net/quic/core/quic_utils.h"
+
+using base::StringPiece;
+using crypto::SecureHash;
+using std::map;
+using std::sort;
+using std::string;
+using std::vector;
+
+namespace net {
+
+namespace {
+
+// kMultiplier is the multiple of the CHLO message size that a REJ message
+// must stay under when the client doesn't present a valid source-address
+// token. This is used to protect QUIC from amplification attacks.
+// TODO(rch): Reduce this to 2 again once b/25933682 is fixed.
+const size_t kMultiplier = 3;
+
+const int kMaxTokenAddresses = 4;
+
+string DeriveSourceAddressTokenKey(StringPiece source_address_token_secret) {
+ crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */,
+ "QUIC source address token key",
+ CryptoSecretBoxer::GetKeySize(), 0 /* no fixed IV needed */,
+ 0 /* no subkey secret */);
+ return hkdf.server_write_key().as_string();
+}
+
+IPAddress DualstackIPAddress(const IPAddress& ip) {
+ if (ip.IsIPv4()) {
+ return ConvertIPv4ToIPv4MappedIPv6(ip);
+ }
+ return ip;
+}
+
+} // namespace
+
+class ValidateClientHelloHelper {
+ public:
+ // Note: stores a pointer to a unique_ptr, and std::moves the unique_ptr when
+ // ValidationComplete is called.
+ ValidateClientHelloHelper(
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result,
+ std::unique_ptr<ValidateClientHelloResultCallback>* done_cb)
+ : result_(std::move(result)), done_cb_(done_cb) {}
+
+ ~ValidateClientHelloHelper() {
+ QUIC_BUG_IF(done_cb_ != nullptr)
+ << "Deleting ValidateClientHelloHelper with a pending callback.";
+ }
+
+ void ValidationComplete(
+ QuicErrorCode error_code,
+ const char* error_details,
+ std::unique_ptr<ProofSource::Details> proof_source_details) {
+ result_->error_code = error_code;
+ result_->error_details = error_details;
+ (*done_cb_)->Run(std::move(result_), std::move(proof_source_details));
+ DetachCallback();
+ }
+
+ void DetachCallback() {
+ QUIC_BUG_IF(done_cb_ == nullptr) << "Callback already detached.";
+ done_cb_ = nullptr;
+ }
+
+ private:
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result_;
+ std::unique_ptr<ValidateClientHelloResultCallback>* done_cb_;
+
+ DISALLOW_COPY_AND_ASSIGN(ValidateClientHelloHelper);
+};
+
+class VerifyNonceIsValidAndUniqueCallback
+ : public StrikeRegisterClient::ResultCallback {
+ public:
+ VerifyNonceIsValidAndUniqueCallback(
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result,
+ std::unique_ptr<ProofSource::Details> proof_source_details,
+ std::unique_ptr<ValidateClientHelloResultCallback> done_cb)
+ : result_(std::move(result)),
+ proof_source_details_(std::move(proof_source_details)),
+ done_cb_(std::move(done_cb)) {}
+
+ protected:
+ void RunImpl(bool nonce_is_valid_and_unique,
+ InsertStatus nonce_error) override {
+ DVLOG(1) << "Using client nonce, unique: " << nonce_is_valid_and_unique
+ << " nonce_error: " << nonce_error;
+ if (!nonce_is_valid_and_unique) {
+ HandshakeFailureReason client_nonce_error;
+ switch (nonce_error) {
+ case NONCE_INVALID_FAILURE:
+ client_nonce_error = CLIENT_NONCE_INVALID_FAILURE;
+ break;
+ case NONCE_NOT_UNIQUE_FAILURE:
+ client_nonce_error = CLIENT_NONCE_NOT_UNIQUE_FAILURE;
+ break;
+ case NONCE_INVALID_ORBIT_FAILURE:
+ client_nonce_error = CLIENT_NONCE_INVALID_ORBIT_FAILURE;
+ break;
+ case NONCE_INVALID_TIME_FAILURE:
+ client_nonce_error = CLIENT_NONCE_INVALID_TIME_FAILURE;
+ break;
+ case STRIKE_REGISTER_TIMEOUT:
+ client_nonce_error = CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT;
+ break;
+ case STRIKE_REGISTER_FAILURE:
+ client_nonce_error = CLIENT_NONCE_STRIKE_REGISTER_FAILURE;
+ break;
+ case NONCE_UNKNOWN_FAILURE:
+ client_nonce_error = CLIENT_NONCE_UNKNOWN_FAILURE;
+ break;
+ case NONCE_OK:
+ default:
+ QUIC_BUG << "Unexpected client nonce error: " << nonce_error;
+ client_nonce_error = CLIENT_NONCE_UNKNOWN_FAILURE;
+ break;
+ }
+ result_->info.reject_reasons.push_back(client_nonce_error);
+ }
+ done_cb_->Run(result_, std::move(proof_source_details_));
+ }
+
+ private:
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result_;
+ std::unique_ptr<ProofSource::Details> proof_source_details_;
+ std::unique_ptr<ValidateClientHelloResultCallback> done_cb_;
+
+ DISALLOW_COPY_AND_ASSIGN(VerifyNonceIsValidAndUniqueCallback);
+};
+
+// static
+const char QuicCryptoServerConfig::TESTING[] = "secret string for testing";
+
+ClientHelloInfo::ClientHelloInfo(const IPAddress& in_client_ip,
+ QuicWallTime in_now)
+ : client_ip(in_client_ip), now(in_now), valid_source_address_token(false) {}
+
+ClientHelloInfo::ClientHelloInfo(const ClientHelloInfo& other) = default;
+
+ClientHelloInfo::~ClientHelloInfo() {}
+
+PrimaryConfigChangedCallback::PrimaryConfigChangedCallback() {}
+
+PrimaryConfigChangedCallback::~PrimaryConfigChangedCallback() {}
+
+ValidateClientHelloResultCallback::Result::Result(
+ const CryptoHandshakeMessage& in_client_hello,
+ IPAddress in_client_ip,
+ QuicWallTime in_now)
+ : client_hello(in_client_hello),
+ info(in_client_ip, in_now),
+ error_code(QUIC_NO_ERROR) {}
+
+ValidateClientHelloResultCallback::Result::~Result() {}
+
+ValidateClientHelloResultCallback::ValidateClientHelloResultCallback() {}
+
+ValidateClientHelloResultCallback::~ValidateClientHelloResultCallback() {}
+
+ProcessClientHelloResultCallback::ProcessClientHelloResultCallback() {}
+
+ProcessClientHelloResultCallback::~ProcessClientHelloResultCallback() {}
+
+QuicCryptoServerConfig::ConfigOptions::ConfigOptions()
+ : expiry_time(QuicWallTime::Zero()),
+ channel_id_enabled(false),
+ p256(false) {}
+
+QuicCryptoServerConfig::ConfigOptions::ConfigOptions(
+ const ConfigOptions& other) = default;
+
+QuicCryptoServerConfig::ConfigOptions::~ConfigOptions() {}
+
+QuicCryptoServerConfig::QuicCryptoServerConfig(
+ StringPiece source_address_token_secret,
+ QuicRandom* server_nonce_entropy,
+ std::unique_ptr<ProofSource> proof_source)
+ : replay_protection_(true),
+ chlo_multiplier_(kMultiplier),
+ configs_lock_(),
+ primary_config_(nullptr),
+ next_config_promotion_time_(QuicWallTime::Zero()),
+ server_nonce_strike_register_lock_(),
+ proof_source_(std::move(proof_source)),
+ strike_register_no_startup_period_(false),
+ strike_register_max_entries_(1 << 10),
+ strike_register_window_secs_(600),
+ source_address_token_future_secs_(3600),
+ source_address_token_lifetime_secs_(86400),
+ server_nonce_strike_register_max_entries_(1 << 10),
+ server_nonce_strike_register_window_secs_(120),
+ enable_serving_sct_(false),
+ rejection_observer_(nullptr) {
+ DCHECK(proof_source_.get());
+ source_address_token_boxer_.SetKeys(
+ {DeriveSourceAddressTokenKey(source_address_token_secret)});
+
+ // Generate a random key and orbit for server nonces.
+ server_nonce_entropy->RandBytes(server_nonce_orbit_,
+ sizeof(server_nonce_orbit_));
+ const size_t key_size = server_nonce_boxer_.GetKeySize();
+ std::unique_ptr<uint8_t[]> key_bytes(new uint8_t[key_size]);
+ server_nonce_entropy->RandBytes(key_bytes.get(), key_size);
+
+ server_nonce_boxer_.SetKeys(
+ {string(reinterpret_cast<char*>(key_bytes.get()), key_size)});
+}
+
+QuicCryptoServerConfig::~QuicCryptoServerConfig() {
+ primary_config_ = nullptr;
+}
+
+// static
+QuicServerConfigProtobuf* QuicCryptoServerConfig::GenerateConfig(
+ QuicRandom* rand,
+ const QuicClock* clock,
+ const ConfigOptions& options) {
+ CryptoHandshakeMessage msg;
+
+ const string curve25519_private_key =
+ Curve25519KeyExchange::NewPrivateKey(rand);
+ std::unique_ptr<Curve25519KeyExchange> curve25519(
+ Curve25519KeyExchange::New(curve25519_private_key));
+ StringPiece curve25519_public_value = curve25519->public_value();
+
+ string encoded_public_values;
+ // First three bytes encode the length of the public value.
+ DCHECK_LT(curve25519_public_value.size(), (1U << 24));
+ encoded_public_values.push_back(
+ static_cast<char>(curve25519_public_value.size()));
+ encoded_public_values.push_back(
+ static_cast<char>(curve25519_public_value.size() >> 8));
+ encoded_public_values.push_back(
+ static_cast<char>(curve25519_public_value.size() >> 16));
+ encoded_public_values.append(curve25519_public_value.data(),
+ curve25519_public_value.size());
+
+ string p256_private_key;
+ if (options.p256) {
+ p256_private_key = P256KeyExchange::NewPrivateKey();
+ std::unique_ptr<P256KeyExchange> p256(
+ P256KeyExchange::New(p256_private_key));
+ StringPiece p256_public_value = p256->public_value();
+
+ DCHECK_LT(p256_public_value.size(), (1U << 24));
+ encoded_public_values.push_back(
+ static_cast<char>(p256_public_value.size()));
+ encoded_public_values.push_back(
+ static_cast<char>(p256_public_value.size() >> 8));
+ encoded_public_values.push_back(
+ static_cast<char>(p256_public_value.size() >> 16));
+ encoded_public_values.append(p256_public_value.data(),
+ p256_public_value.size());
+ }
+
+ msg.set_tag(kSCFG);
+ if (options.p256) {
+ msg.SetVector(kKEXS, QuicTagVector{kC255, kP256});
+ } else {
+ msg.SetVector(kKEXS, QuicTagVector{kC255});
+ }
+ msg.SetVector(kAEAD, QuicTagVector{kAESG, kCC20});
+ msg.SetStringPiece(kPUBS, encoded_public_values);
+
+ if (options.expiry_time.IsZero()) {
+ const QuicWallTime now = clock->WallNow();
+ const QuicWallTime expiry = now.Add(QuicTime::Delta::FromSeconds(
+ 60 * 60 * 24 * 180 /* 180 days, ~six months */));
+ const uint64_t expiry_seconds = expiry.ToUNIXSeconds();
+ msg.SetValue(kEXPY, expiry_seconds);
+ } else {
+ msg.SetValue(kEXPY, options.expiry_time.ToUNIXSeconds());
+ }
+
+ char orbit_bytes[kOrbitSize];
+ if (options.orbit.size() == sizeof(orbit_bytes)) {
+ memcpy(orbit_bytes, options.orbit.data(), sizeof(orbit_bytes));
+ } else {
+ DCHECK(options.orbit.empty());
+ rand->RandBytes(orbit_bytes, sizeof(orbit_bytes));
+ }
+ msg.SetStringPiece(kORBT, StringPiece(orbit_bytes, sizeof(orbit_bytes)));
+
+ if (options.channel_id_enabled) {
+ msg.SetVector(kPDMD, QuicTagVector{kCHID});
+ }
+
+ if (!options.token_binding_params.empty()) {
+ msg.SetVector(kTBKP, options.token_binding_params);
+ }
+
+ if (options.id.empty()) {
+ // We need to ensure that the SCID changes whenever the server config does
+ // thus we make it a hash of the rest of the server config.
+ std::unique_ptr<QuicData> serialized(
+ CryptoFramer::ConstructHandshakeMessage(msg));
+ std::unique_ptr<SecureHash> hash(SecureHash::Create(SecureHash::SHA256));
+ hash->Update(serialized->data(), serialized->length());
+
+ char scid_bytes[16];
+ hash->Finish(scid_bytes, sizeof(scid_bytes));
+ msg.SetStringPiece(kSCID, StringPiece(scid_bytes, sizeof(scid_bytes)));
+ } else {
+ msg.SetStringPiece(kSCID, options.id);
+ }
+ // Don't put new tags below this point. The SCID generation should hash over
+ // everything but itself and so extra tags should be added prior to the
+ // preceeding if block.
+
+ std::unique_ptr<QuicData> serialized(
+ CryptoFramer::ConstructHandshakeMessage(msg));
+
+ std::unique_ptr<QuicServerConfigProtobuf> config(
+ new QuicServerConfigProtobuf);
+ config->set_config(serialized->AsStringPiece());
+ QuicServerConfigProtobuf::PrivateKey* curve25519_key = config->add_key();
+ curve25519_key->set_tag(kC255);
+ curve25519_key->set_private_key(curve25519_private_key);
+
+ if (options.p256) {
+ QuicServerConfigProtobuf::PrivateKey* p256_key = config->add_key();
+ p256_key->set_tag(kP256);
+ p256_key->set_private_key(p256_private_key);
+ }
+
+ return config.release();
+}
+
+CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig(
+ QuicServerConfigProtobuf* protobuf,
+ const QuicWallTime now) {
+ std::unique_ptr<CryptoHandshakeMessage> msg(
+ CryptoFramer::ParseMessage(protobuf->config()));
+
+ if (!msg.get()) {
+ LOG(WARNING) << "Failed to parse server config message";
+ return nullptr;
+ }
+
+ scoped_refptr<Config> config(ParseConfigProtobuf(protobuf));
+ if (!config.get()) {
+ LOG(WARNING) << "Failed to parse server config message";
+ return nullptr;
+ }
+
+ {
+ base::AutoLock locked(configs_lock_);
+ if (configs_.find(config->id) != configs_.end()) {
+ LOG(WARNING) << "Failed to add config because another with the same "
+ "server config id already exists: "
+ << QuicUtils::HexEncode(config->id);
+ return nullptr;
+ }
+
+ configs_[config->id] = config;
+ SelectNewPrimaryConfig(now);
+ DCHECK(primary_config_.get());
+ DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
+ }
+
+ return msg.release();
+}
+
+CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig(
+ QuicRandom* rand,
+ const QuicClock* clock,
+ const ConfigOptions& options) {
+ std::unique_ptr<QuicServerConfigProtobuf> config(
+ GenerateConfig(rand, clock, options));
+ return AddConfig(config.get(), clock->WallNow());
+}
+
+bool QuicCryptoServerConfig::SetConfigs(
+ const vector<QuicServerConfigProtobuf*>& protobufs,
+ const QuicWallTime now) {
+ vector<scoped_refptr<Config>> parsed_configs;
+ bool ok = true;
+
+ for (vector<QuicServerConfigProtobuf*>::const_iterator i = protobufs.begin();
+ i != protobufs.end(); ++i) {
+ scoped_refptr<Config> config(ParseConfigProtobuf(*i));
+ if (!config.get()) {
+ ok = false;
+ break;
+ }
+
+ parsed_configs.push_back(config);
+ }
+
+ if (parsed_configs.empty()) {
+ LOG(WARNING) << "New config list is empty.";
+ ok = false;
+ }
+
+ if (!ok) {
+ LOG(WARNING) << "Rejecting QUIC configs because of above errors";
+ } else {
+ VLOG(1) << "Updating configs:";
+
+ base::AutoLock locked(configs_lock_);
+ ConfigMap new_configs;
+
+ for (vector<scoped_refptr<Config>>::const_iterator i =
+ parsed_configs.begin();
+ i != parsed_configs.end(); ++i) {
+ scoped_refptr<Config> config = *i;
+
+ ConfigMap::iterator it = configs_.find(config->id);
+ if (it != configs_.end()) {
+ VLOG(1) << "Keeping scid: " << QuicUtils::HexEncode(config->id)
+ << " orbit: "
+ << QuicUtils::HexEncode(
+ reinterpret_cast<const char*>(config->orbit), kOrbitSize)
+ << " new primary_time " << config->primary_time.ToUNIXSeconds()
+ << " old primary_time "
+ << it->second->primary_time.ToUNIXSeconds() << " new priority "
+ << config->priority << " old priority " << it->second->priority;
+ // Update primary_time and priority.
+ it->second->primary_time = config->primary_time;
+ it->second->priority = config->priority;
+ new_configs.insert(*it);
+ } else {
+ VLOG(1) << "Adding scid: " << QuicUtils::HexEncode(config->id)
+ << " orbit: "
+ << QuicUtils::HexEncode(
+ reinterpret_cast<const char*>(config->orbit), kOrbitSize)
+ << " primary_time " << config->primary_time.ToUNIXSeconds()
+ << " priority " << config->priority;
+ new_configs.insert(std::make_pair(config->id, config));
+ }
+ }
+
+ configs_.swap(new_configs);
+ SelectNewPrimaryConfig(now);
+ DCHECK(primary_config_.get());
+ DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
+ }
+
+ return ok;
+}
+
+void QuicCryptoServerConfig::SetSourceAddressTokenKeys(
+ const vector<string>& keys) {
+ source_address_token_boxer_.SetKeys(keys);
+}
+
+void QuicCryptoServerConfig::GetConfigIds(vector<string>* scids) const {
+ base::AutoLock locked(configs_lock_);
+ for (ConfigMap::const_iterator it = configs_.begin(); it != configs_.end();
+ ++it) {
+ scids->push_back(it->first);
+ }
+}
+
+void QuicCryptoServerConfig::ValidateClientHello(
+ const CryptoHandshakeMessage& client_hello,
+ const IPAddress& client_ip,
+ const IPAddress& server_ip,
+ QuicVersion version,
+ const QuicClock* clock,
+ QuicCryptoProof* crypto_proof,
+ std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const {
+ const QuicWallTime now(clock->WallNow());
+
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result(
+ new ValidateClientHelloResultCallback::Result(client_hello, client_ip,
+ now));
+
+ StringPiece requested_scid;
+ client_hello.GetStringPiece(kSCID, &requested_scid);
+
+ uint8_t primary_orbit[kOrbitSize];
+ scoped_refptr<Config> requested_config;
+ scoped_refptr<Config> primary_config;
+ {
+ base::AutoLock locked(configs_lock_);
+
+ if (!primary_config_.get()) {
+ result->error_code = QUIC_CRYPTO_INTERNAL_ERROR;
+ result->error_details = "No configurations loaded";
+ } else {
+ if (!next_config_promotion_time_.IsZero() &&
+ next_config_promotion_time_.IsAfter(now)) {
+ SelectNewPrimaryConfig(now);
+ DCHECK(primary_config_.get());
+ DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
+ }
+
+ memcpy(primary_orbit, primary_config_->orbit, sizeof(primary_orbit));
+ }
+
+ requested_config = GetConfigWithScid(requested_scid);
+ primary_config = primary_config_;
+ crypto_proof->config = primary_config_;
+ }
+
+ if (result->error_code == QUIC_NO_ERROR) {
+ if (version > QUIC_VERSION_30) {
+ // QUIC v31 and above require a new proof for each CHLO so clear the
+ // existing proof, if any.
+ crypto_proof->chain = nullptr;
+ crypto_proof->signature = "";
+ crypto_proof->cert_sct = "";
+ }
+ EvaluateClientHello(server_ip, version, primary_orbit, requested_config,
+ primary_config, crypto_proof, result,
+ std::move(done_cb));
+ } else {
+ done_cb->Run(result, /* details = */ nullptr);
+ }
+}
+
+class ProcessClientHelloHelper {
+ public:
+ explicit ProcessClientHelloHelper(
+ std::unique_ptr<ProcessClientHelloResultCallback>* done_cb)
+ : done_cb_(done_cb) {}
+
+ ~ProcessClientHelloHelper() {
+ QUIC_BUG_IF(done_cb_ != nullptr)
+ << "Deleting ProcessClientHelloHelper with a pending callback.";
+ }
+
+ void Fail(QuicErrorCode error, const string& error_details) {
+ (*done_cb_)->Run(error, error_details, nullptr, nullptr);
+ DetachCallback();
+ }
+
+ void Succeed(std::unique_ptr<CryptoHandshakeMessage> message,
+ std::unique_ptr<DiversificationNonce> diversification_nonce) {
+ (*done_cb_)->Run(QUIC_NO_ERROR, string(), std::move(message),
+ std::move(diversification_nonce));
+ DetachCallback();
+ }
+
+ void DetachCallback() {
+ QUIC_BUG_IF(done_cb_ == nullptr) << "Callback already detached.";
+ done_cb_ = nullptr;
+ }
+
+ private:
+ std::unique_ptr<ProcessClientHelloResultCallback>* done_cb_;
+};
+
+void QuicCryptoServerConfig::ProcessClientHello(
+ scoped_refptr<ValidateClientHelloResultCallback::Result>
+ validate_chlo_result,
+ bool reject_only,
+ QuicConnectionId connection_id,
+ const IPAddress& server_ip,
+ const IPEndPoint& client_address,
+ QuicVersion version,
+ const QuicVersionVector& supported_versions,
+ bool use_stateless_rejects,
+ QuicConnectionId server_designated_connection_id,
+ const QuicClock* clock,
+ QuicRandom* rand,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ QuicCryptoNegotiatedParameters* params,
+ QuicCryptoProof* crypto_proof,
+ QuicByteCount total_framing_overhead,
+ QuicByteCount chlo_packet_size,
+ std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const {
+ DCHECK(done_cb);
+
+ ProcessClientHelloHelper helper(&done_cb);
+
+ const CryptoHandshakeMessage& client_hello =
+ validate_chlo_result->client_hello;
+ const ClientHelloInfo& info = validate_chlo_result->info;
+
+ string error_details;
+ QuicErrorCode valid = CryptoUtils::ValidateClientHello(
+ client_hello, version, supported_versions, &error_details);
+ if (valid != QUIC_NO_ERROR) {
+ helper.Fail(valid, error_details);
+ return;
+ }
+
+ StringPiece requested_scid;
+ client_hello.GetStringPiece(kSCID, &requested_scid);
+ const QuicWallTime now(clock->WallNow());
+
+ scoped_refptr<Config> requested_config;
+ scoped_refptr<Config> primary_config;
+ bool no_primary_config = false;
+ {
+ base::AutoLock locked(configs_lock_);
+
+ if (!primary_config_) {
+ no_primary_config = true;
+ } else {
+ if (!next_config_promotion_time_.IsZero() &&
+ next_config_promotion_time_.IsAfter(now)) {
+ SelectNewPrimaryConfig(now);
+ DCHECK(primary_config_.get());
+ DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
+ }
+
+ // Use the config that the client requested in order to do key-agreement.
+ // Otherwise give it a copy of |primary_config_| to use.
+ primary_config = crypto_proof->config;
+ requested_config = GetConfigWithScid(requested_scid);
+ }
+ }
+ if (no_primary_config) {
+ helper.Fail(QUIC_CRYPTO_INTERNAL_ERROR, "No configurations loaded");
+ return;
+ }
+
+ if (validate_chlo_result->error_code != QUIC_NO_ERROR) {
+ helper.Fail(validate_chlo_result->error_code,
+ validate_chlo_result->error_details);
+ return;
+ }
+
+ if (!ClientDemandsX509Proof(client_hello)) {
+ helper.Fail(QUIC_UNSUPPORTED_PROOF_DEMAND, "Missing or invalid PDMD");
+ return;
+ }
+ DCHECK(proof_source_.get());
+ string chlo_hash;
+ CryptoUtils::HashHandshakeMessage(client_hello, &chlo_hash);
+ // No need to get a new proof if one was already generated.
+ if (!crypto_proof->chain) {
+ if (!proof_source_->GetProof(server_ip, info.sni.as_string(),
+ primary_config->serialized, version, chlo_hash,
+ &crypto_proof->chain, &crypto_proof->signature,
+ &crypto_proof->cert_sct)) {
+ helper.Fail(QUIC_HANDSHAKE_FAILED, "Failed to get proof");
+ return;
+ }
+ }
+
+ // Note: this split exists to facilitate a future change in which the async
+ // version of GetProof will be called.
+ helper.DetachCallback();
+ ProcessClientHelloAfterGetProof(
+ *validate_chlo_result, reject_only, connection_id, client_address,
+ version, supported_versions, use_stateless_rejects,
+ server_designated_connection_id, clock, rand, compressed_certs_cache,
+ params, crypto_proof, total_framing_overhead, chlo_packet_size,
+ requested_config, primary_config, std::move(done_cb));
+}
+
+void QuicCryptoServerConfig::ProcessClientHelloAfterGetProof(
+ const ValidateClientHelloResultCallback::Result& validate_chlo_result,
+ bool reject_only,
+ QuicConnectionId connection_id,
+ const IPEndPoint& client_address,
+ QuicVersion version,
+ const QuicVersionVector& supported_versions,
+ bool use_stateless_rejects,
+ QuicConnectionId server_designated_connection_id,
+ const QuicClock* clock,
+ QuicRandom* rand,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ QuicCryptoNegotiatedParameters* params,
+ QuicCryptoProof* crypto_proof,
+ QuicByteCount total_framing_overhead,
+ QuicByteCount chlo_packet_size,
+ const scoped_refptr<Config>& requested_config,
+ const scoped_refptr<Config>& primary_config,
+ std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const {
+ ProcessClientHelloHelper helper(&done_cb);
+
+ const CryptoHandshakeMessage& client_hello =
+ validate_chlo_result.client_hello;
+ const ClientHelloInfo& info = validate_chlo_result.info;
+ std::unique_ptr<DiversificationNonce> out_diversification_nonce(
+ new DiversificationNonce);
+
+ StringPiece cert_sct;
+ if (client_hello.GetStringPiece(kCertificateSCTTag, &cert_sct) &&
+ cert_sct.empty()) {
+ params->sct_supported_by_client = true;
+ }
+
+ std::unique_ptr<CryptoHandshakeMessage> out(new CryptoHandshakeMessage);
+ if (!info.reject_reasons.empty() || !requested_config.get()) {
+ BuildRejection(version, clock->WallNow(), *primary_config, client_hello,
+ info, validate_chlo_result.cached_network_params,
+ use_stateless_rejects, server_designated_connection_id, rand,
+ compressed_certs_cache, params, *crypto_proof,
+ total_framing_overhead, chlo_packet_size, out.get());
+ if (FLAGS_quic_export_rej_for_all_rejects &&
+ rejection_observer_ != nullptr) {
+ rejection_observer_->OnRejectionBuilt(info.reject_reasons, out.get());
+ }
+ helper.Succeed(std::move(out), std::move(out_diversification_nonce));
+ return;
+ }
+
+ if (reject_only) {
+ helper.Succeed(std::move(out), std::move(out_diversification_nonce));
+ return;
+ }
+
+ const QuicTag* their_aeads;
+ const QuicTag* their_key_exchanges;
+ size_t num_their_aeads, num_their_key_exchanges;
+ if (client_hello.GetTaglist(kAEAD, &their_aeads, &num_their_aeads) !=
+ QUIC_NO_ERROR ||
+ client_hello.GetTaglist(kKEXS, &their_key_exchanges,
+ &num_their_key_exchanges) != QUIC_NO_ERROR ||
+ num_their_aeads != 1 || num_their_key_exchanges != 1) {
+ helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
+ "Missing or invalid AEAD or KEXS");
+ return;
+ }
+
+ size_t key_exchange_index;
+ if (!QuicUtils::FindMutualTag(requested_config->aead, their_aeads,
+ num_their_aeads, QuicUtils::LOCAL_PRIORITY,
+ &params->aead, nullptr) ||
+ !QuicUtils::FindMutualTag(requested_config->kexs, their_key_exchanges,
+ num_their_key_exchanges,
+ QuicUtils::LOCAL_PRIORITY,
+ &params->key_exchange, &key_exchange_index)) {
+ helper.Fail(QUIC_CRYPTO_NO_SUPPORT, "Unsupported AEAD or KEXS");
+ return;
+ }
+
+ if (!requested_config->tb_key_params.empty()) {
+ const QuicTag* their_tbkps;
+ size_t num_their_tbkps;
+ switch (client_hello.GetTaglist(kTBKP, &their_tbkps, &num_their_tbkps)) {
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+ break;
+ case QUIC_NO_ERROR:
+ if (QuicUtils::FindMutualTag(
+ requested_config->tb_key_params, their_tbkps, num_their_tbkps,
+ QuicUtils::LOCAL_PRIORITY, &params->token_binding_key_param,
+ nullptr)) {
+ break;
+ }
+ default:
+ helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
+ "Invalid Token Binding key parameter");
+ return;
+ }
+ }
+
+ StringPiece public_value;
+ if (!client_hello.GetStringPiece(kPUBS, &public_value)) {
+ helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "Missing public value");
+ return;
+ }
+
+ const KeyExchange* key_exchange =
+ requested_config->key_exchanges[key_exchange_index];
+ if (!key_exchange->CalculateSharedKey(public_value,
+ &params->initial_premaster_secret)) {
+ helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "Invalid public value");
+ return;
+ }
+
+ if (!info.sni.empty()) {
+ std::unique_ptr<char[]> sni_tmp(new char[info.sni.length() + 1]);
+ memcpy(sni_tmp.get(), info.sni.data(), info.sni.length());
+ sni_tmp[info.sni.length()] = 0;
+ params->sni = CryptoUtils::NormalizeHostname(sni_tmp.get());
+ }
+
+ string hkdf_suffix;
+ const QuicData& client_hello_serialized = client_hello.GetSerialized();
+ hkdf_suffix.reserve(sizeof(connection_id) + client_hello_serialized.length() +
+ requested_config->serialized.size());
+ hkdf_suffix.append(reinterpret_cast<char*>(&connection_id),
+ sizeof(connection_id));
+ hkdf_suffix.append(client_hello_serialized.data(),
+ client_hello_serialized.length());
+ hkdf_suffix.append(requested_config->serialized);
+ DCHECK(proof_source_.get());
+ if (crypto_proof->chain->certs.empty()) {
+ helper.Fail(QUIC_CRYPTO_INTERNAL_ERROR, "Failed to get certs");
+ return;
+ }
+ hkdf_suffix.append(crypto_proof->chain->certs.at(0));
+
+ StringPiece cetv_ciphertext;
+ if (requested_config->channel_id_enabled &&
+ client_hello.GetStringPiece(kCETV, &cetv_ciphertext)) {
+ CryptoHandshakeMessage client_hello_copy(client_hello);
+ client_hello_copy.Erase(kCETV);
+ client_hello_copy.Erase(kPAD);
+
+ const QuicData& client_hello_copy_serialized =
+ client_hello_copy.GetSerialized();
+ string hkdf_input;
+ hkdf_input.append(QuicCryptoConfig::kCETVLabel,
+ strlen(QuicCryptoConfig::kCETVLabel) + 1);
+ hkdf_input.append(reinterpret_cast<char*>(&connection_id),
+ sizeof(connection_id));
+ hkdf_input.append(client_hello_copy_serialized.data(),
+ client_hello_copy_serialized.length());
+ hkdf_input.append(requested_config->serialized);
+
+ CrypterPair crypters;
+ if (!CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead,
+ info.client_nonce, info.server_nonce,
+ hkdf_input, Perspective::IS_SERVER,
+ CryptoUtils::Diversification::Never(),
+ &crypters, nullptr /* subkey secret */)) {
+ helper.Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
+ "Symmetric key setup failed");
+ return;
+ }
+
+ char plaintext[kMaxPacketSize];
+ size_t plaintext_length = 0;
+ const bool success = crypters.decrypter->DecryptPacket(
+ kDefaultPathId, 0 /* packet number */,
+ StringPiece() /* associated data */, cetv_ciphertext, plaintext,
+ &plaintext_length, kMaxPacketSize);
+ if (!success) {
+ helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
+ "CETV decryption failure");
+ return;
+ }
+ std::unique_ptr<CryptoHandshakeMessage> cetv(
+ CryptoFramer::ParseMessage(StringPiece(plaintext, plaintext_length)));
+ if (!cetv.get()) {
+ helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "CETV parse error");
+ return;
+ }
+
+ StringPiece key, signature;
+ if (cetv->GetStringPiece(kCIDK, &key) &&
+ cetv->GetStringPiece(kCIDS, &signature)) {
+ if (!ChannelIDVerifier::Verify(key, hkdf_input, signature)) {
+ helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
+ "ChannelID signature failure");
+ return;
+ }
+
+ params->channel_id = key.as_string();
+ }
+ }
+
+ string hkdf_input;
+ size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
+ hkdf_input.reserve(label_len + hkdf_suffix.size());
+ hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
+ hkdf_input.append(hkdf_suffix);
+
+ CryptoUtils::Diversification diversification =
+ CryptoUtils::Diversification::Never();
+ if (version > QUIC_VERSION_32) {
+ rand->RandBytes(out_diversification_nonce->data(),
+ out_diversification_nonce->size());
+ diversification =
+ CryptoUtils::Diversification::Now(out_diversification_nonce.get());
+ }
+
+ if (!CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead,
+ info.client_nonce, info.server_nonce, hkdf_input,
+ Perspective::IS_SERVER, diversification,
+ &params->initial_crypters,
+ &params->initial_subkey_secret)) {
+ helper.Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
+ "Symmetric key setup failed");
+ return;
+ }
+
+ string forward_secure_public_value;
+ if (ephemeral_key_source_.get()) {
+ params->forward_secure_premaster_secret =
+ ephemeral_key_source_->CalculateForwardSecureKey(
+ key_exchange, rand, clock->ApproximateNow(), public_value,
+ &forward_secure_public_value);
+ } else {
+ std::unique_ptr<KeyExchange> forward_secure_key_exchange(
+ key_exchange->NewKeyPair(rand));
+ forward_secure_public_value =
+ forward_secure_key_exchange->public_value().as_string();
+ if (!forward_secure_key_exchange->CalculateSharedKey(
+ public_value, &params->forward_secure_premaster_secret)) {
+ helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
+ "Invalid public value");
+ return;
+ }
+ }
+
+ string forward_secure_hkdf_input;
+ label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
+ forward_secure_hkdf_input.reserve(label_len + hkdf_suffix.size());
+ forward_secure_hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel,
+ label_len);
+ forward_secure_hkdf_input.append(hkdf_suffix);
+
+ string shlo_nonce;
+ shlo_nonce = NewServerNonce(rand, info.now);
+ out->SetStringPiece(kServerNonceTag, shlo_nonce);
+
+ if (!CryptoUtils::DeriveKeys(
+ params->forward_secure_premaster_secret, params->aead,
+ info.client_nonce,
+ shlo_nonce.empty() ? info.server_nonce : shlo_nonce,
+ forward_secure_hkdf_input, Perspective::IS_SERVER,
+ CryptoUtils::Diversification::Never(),
+ &params->forward_secure_crypters, &params->subkey_secret)) {
+ helper.Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED,
+ "Symmetric key setup failed");
+ return;
+ }
+
+ out->set_tag(kSHLO);
+ QuicTagVector supported_version_tags;
+ for (size_t i = 0; i < supported_versions.size(); ++i) {
+ supported_version_tags.push_back(
+ QuicVersionToQuicTag(supported_versions[i]));
+ }
+ out->SetVector(kVER, supported_version_tags);
+ out->SetStringPiece(
+ kSourceAddressTokenTag,
+ NewSourceAddressToken(*requested_config.get(), info.source_address_tokens,
+ client_address.address(), rand, info.now, nullptr));
+ QuicSocketAddressCoder address_coder(client_address);
+ out->SetStringPiece(kCADR, address_coder.Encode());
+ out->SetStringPiece(kPUBS, forward_secure_public_value);
+
+ helper.Succeed(std::move(out), std::move(out_diversification_nonce));
+}
+
+scoped_refptr<QuicCryptoServerConfig::Config>
+QuicCryptoServerConfig::GetConfigWithScid(StringPiece requested_scid) const {
+ // In Chromium, we will dead lock if the lock is held by the current thread.
+ // Chromium doesn't have AssertReaderHeld API call.
+ // configs_lock_.AssertReaderHeld();
+
+ if (!requested_scid.empty()) {
+ ConfigMap::const_iterator it = configs_.find(requested_scid.as_string());
+ if (it != configs_.end()) {
+ // We'll use the config that the client requested in order to do
+ // key-agreement.
+ return scoped_refptr<Config>(it->second);
+ }
+ }
+
+ return scoped_refptr<Config>();
+}
+
+// ConfigPrimaryTimeLessThan is a comparator that implements "less than" for
+// Config's based on their primary_time.
+// static
+bool QuicCryptoServerConfig::ConfigPrimaryTimeLessThan(
+ const scoped_refptr<Config>& a,
+ const scoped_refptr<Config>& b) {
+ if (a->primary_time.IsBefore(b->primary_time) ||
+ b->primary_time.IsBefore(a->primary_time)) {
+ // Primary times differ.
+ return a->primary_time.IsBefore(b->primary_time);
+ } else if (a->priority != b->priority) {
+ // Primary times are equal, sort backwards by priority.
+ return a->priority < b->priority;
+ } else {
+ // Primary times and priorities are equal, sort by config id.
+ return a->id < b->id;
+ }
+}
+
+void QuicCryptoServerConfig::SelectNewPrimaryConfig(
+ const QuicWallTime now) const {
+ vector<scoped_refptr<Config>> configs;
+ configs.reserve(configs_.size());
+
+ for (ConfigMap::const_iterator it = configs_.begin(); it != configs_.end();
+ ++it) {
+ // TODO(avd) Exclude expired configs?
+ configs.push_back(it->second);
+ }
+
+ if (configs.empty()) {
+ if (primary_config_.get()) {
+ QUIC_BUG << "No valid QUIC server config. Keeping the current config.";
+ } else {
+ QUIC_BUG << "No valid QUIC server config.";
+ }
+ return;
+ }
+
+ std::sort(configs.begin(), configs.end(), ConfigPrimaryTimeLessThan);
+
+ Config* best_candidate = configs[0].get();
+
+ for (size_t i = 0; i < configs.size(); ++i) {
+ const scoped_refptr<Config> config(configs[i]);
+ if (!config->primary_time.IsAfter(now)) {
+ if (config->primary_time.IsAfter(best_candidate->primary_time)) {
+ best_candidate = config.get();
+ }
+ continue;
+ }
+
+ // This is the first config with a primary_time in the future. Thus the
+ // previous Config should be the primary and this one should determine the
+ // next_config_promotion_time_.
+ scoped_refptr<Config> new_primary(best_candidate);
+ if (i == 0) {
+ // We need the primary_time of the next config.
+ if (configs.size() > 1) {
+ next_config_promotion_time_ = configs[1]->primary_time;
+ } else {
+ next_config_promotion_time_ = QuicWallTime::Zero();
+ }
+ } else {
+ next_config_promotion_time_ = config->primary_time;
+ }
+
+ if (primary_config_.get()) {
+ primary_config_->is_primary = false;
+ }
+ primary_config_ = new_primary;
+ new_primary->is_primary = true;
+ DVLOG(1) << "New primary config. orbit: "
+ << QuicUtils::HexEncode(
+ reinterpret_cast<const char*>(primary_config_->orbit),
+ kOrbitSize);
+ if (primary_config_changed_cb_.get() != nullptr) {
+ primary_config_changed_cb_->Run(primary_config_->id);
+ }
+
+ return;
+ }
+
+ // All config's primary times are in the past. We should make the most recent
+ // and highest priority candidate primary.
+ scoped_refptr<Config> new_primary(best_candidate);
+ if (primary_config_.get()) {
+ primary_config_->is_primary = false;
+ }
+ primary_config_ = new_primary;
+ new_primary->is_primary = true;
+ DVLOG(1) << "New primary config. orbit: "
+ << QuicUtils::HexEncode(
+ reinterpret_cast<const char*>(primary_config_->orbit),
+ kOrbitSize)
+ << " scid: " << QuicUtils::HexEncode(primary_config_->id);
+ next_config_promotion_time_ = QuicWallTime::Zero();
+ if (primary_config_changed_cb_.get() != nullptr) {
+ primary_config_changed_cb_->Run(primary_config_->id);
+ }
+}
+
+class QuicCryptoServerConfig::EvaluateClientHelloCallback
+ : public ProofSource::Callback {
+ public:
+ EvaluateClientHelloCallback(
+ const QuicCryptoServerConfig& config,
+ bool found_error,
+ const IPAddress& server_ip,
+ QuicVersion version,
+ const uint8_t* primary_orbit,
+ scoped_refptr<QuicCryptoServerConfig::Config> requested_config,
+ scoped_refptr<QuicCryptoServerConfig::Config> primary_config,
+ QuicCryptoProof* crypto_proof,
+ scoped_refptr<ValidateClientHelloResultCallback::Result>
+ client_hello_state,
+ std::unique_ptr<ValidateClientHelloResultCallback> done_cb)
+ : config_(config),
+ found_error_(found_error),
+ server_ip_(server_ip),
+ version_(version),
+ primary_orbit_(primary_orbit),
+ requested_config_(std::move(requested_config)),
+ primary_config_(std::move(primary_config)),
+ crypto_proof_(crypto_proof),
+ client_hello_state_(std::move(client_hello_state)),
+ done_cb_(std::move(done_cb)) {}
+
+ void Run(bool ok,
+ const scoped_refptr<ProofSource::Chain>& chain,
+ const string& signature,
+ const string& leaf_cert_sct,
+ std::unique_ptr<ProofSource::Details> details) override {
+ if (ok) {
+ crypto_proof_->chain = chain;
+ crypto_proof_->signature = signature;
+ crypto_proof_->cert_sct = leaf_cert_sct;
+ }
+ config_.EvaluateClientHelloAfterGetProof(
+ found_error_, server_ip_, version_, primary_orbit_, requested_config_,
+ primary_config_, crypto_proof_, std::move(details), !ok,
+ client_hello_state_, std::move(done_cb_));
+ }
+
+ private:
+ const QuicCryptoServerConfig& config_;
+ const bool found_error_;
+ const IPAddress& server_ip_;
+ const QuicVersion version_;
+ const uint8_t* primary_orbit_;
+ const scoped_refptr<QuicCryptoServerConfig::Config> requested_config_;
+ const scoped_refptr<QuicCryptoServerConfig::Config> primary_config_;
+ QuicCryptoProof* crypto_proof_;
+ scoped_refptr<ValidateClientHelloResultCallback::Result> client_hello_state_;
+ std::unique_ptr<ValidateClientHelloResultCallback> done_cb_;
+};
+
+void QuicCryptoServerConfig::EvaluateClientHello(
+ const IPAddress& server_ip,
+ QuicVersion version,
+ const uint8_t* primary_orbit,
+ scoped_refptr<Config> requested_config,
+ scoped_refptr<Config> primary_config,
+ QuicCryptoProof* crypto_proof,
+ scoped_refptr<ValidateClientHelloResultCallback::Result> client_hello_state,
+ std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const {
+ ValidateClientHelloHelper helper(client_hello_state, &done_cb);
+
+ const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello;
+ ClientHelloInfo* info = &(client_hello_state->info);
+
+ if (client_hello.size() < kClientHelloMinimumSize) {
+ helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH,
+ "Client hello too small", nullptr);
+ return;
+ }
+
+ if (client_hello.GetStringPiece(kSNI, &info->sni) &&
+ !CryptoUtils::IsValidSNI(info->sni)) {
+ helper.ValidationComplete(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
+ "Invalid SNI name", nullptr);
+ return;
+ }
+
+ client_hello.GetStringPiece(kUAID, &info->user_agent_id);
+
+ HandshakeFailureReason source_address_token_error = MAX_FAILURE_REASON;
+ StringPiece srct;
+ if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) {
+ Config& config = requested_config ? *requested_config : *primary_config;
+ source_address_token_error =
+ ParseSourceAddressToken(config, srct, &info->source_address_tokens);
+
+ if (source_address_token_error == HANDSHAKE_OK) {
+ source_address_token_error = ValidateSourceAddressTokens(
+ info->source_address_tokens, info->client_ip, info->now,
+ &client_hello_state->cached_network_params);
+ }
+ info->valid_source_address_token =
+ (source_address_token_error == HANDSHAKE_OK);
+ } else {
+ source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE;
+ }
+
+ if (!requested_config.get()) {
+ StringPiece requested_scid;
+ if (client_hello.GetStringPiece(kSCID, &requested_scid)) {
+ info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
+ } else {
+ info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
+ }
+ // No server config with the requested ID.
+ helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr);
+ return;
+ }
+
+ if (!client_hello.GetStringPiece(kNONC, &info->client_nonce)) {
+ info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
+ // Report no client nonce as INCHOATE_HELLO_FAILURE.
+ helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr);
+ return;
+ }
+
+ bool found_error = false;
+ if (source_address_token_error != HANDSHAKE_OK) {
+ info->reject_reasons.push_back(source_address_token_error);
+ // No valid source address token.
+ found_error = true;
+ }
+
+ bool get_proof_failed = false;
+ string serialized_config = primary_config->serialized;
+ string chlo_hash;
+ CryptoUtils::HashHandshakeMessage(client_hello, &chlo_hash);
+ bool need_proof = true;
+ need_proof = !crypto_proof->chain;
+ if (FLAGS_enable_async_get_proof) {
+ if (need_proof) {
+ // Make an async call to GetProof and setup the callback to trampoline
+ // back into EvaluateClientHelloAfterGetProof
+ std::unique_ptr<EvaluateClientHelloCallback> cb(
+ new EvaluateClientHelloCallback(
+ *this, found_error, server_ip, version, primary_orbit,
+ requested_config, primary_config, crypto_proof,
+ client_hello_state, std::move(done_cb)));
+ proof_source_->GetProof(server_ip, info->sni.as_string(),
+ serialized_config, version, chlo_hash,
+ std::move(cb));
+ helper.DetachCallback();
+ return;
+ }
+ }
+
+ // No need to get a new proof if one was already generated.
+ if (need_proof &&
+ !proof_source_->GetProof(server_ip, info->sni.as_string(),
+ serialized_config, version, chlo_hash,
+ &crypto_proof->chain, &crypto_proof->signature,
+ &crypto_proof->cert_sct)) {
+ get_proof_failed = true;
+ }
+
+ // Details are null because the synchronous version of GetProof does not
+ // return any stats. Eventually the synchronous codepath will be eliminated.
+ EvaluateClientHelloAfterGetProof(
+ found_error, server_ip, version, primary_orbit, requested_config,
+ primary_config, crypto_proof, nullptr /* proof_source_details */,
+ get_proof_failed, client_hello_state, std::move(done_cb));
+ helper.DetachCallback();
+}
+
+void QuicCryptoServerConfig::EvaluateClientHelloAfterGetProof(
+ bool found_error,
+ const IPAddress& server_ip,
+ QuicVersion version,
+ const uint8_t* primary_orbit,
+ scoped_refptr<Config> requested_config,
+ scoped_refptr<Config> primary_config,
+ QuicCryptoProof* crypto_proof,
+ std::unique_ptr<ProofSource::Details> proof_source_details,
+ bool get_proof_failed,
+ scoped_refptr<ValidateClientHelloResultCallback::Result> client_hello_state,
+ std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const {
+ ValidateClientHelloHelper helper(client_hello_state, &done_cb);
+ const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello;
+ ClientHelloInfo* info = &(client_hello_state->info);
+
+ if (get_proof_failed) {
+ found_error = true;
+ info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
+ }
+
+ if (!ValidateExpectedLeafCertificate(client_hello, *crypto_proof)) {
+ found_error = true;
+ info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE);
+ }
+
+ if (info->client_nonce.size() != kNonceSize) {
+ info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
+ // Invalid client nonce.
+ LOG(ERROR) << "Invalid client nonce: " << client_hello.DebugString();
+ DVLOG(1) << "Invalid client nonce.";
+ found_error = true;
+ }
+
+ // Server nonce is optional, and used for key derivation if present.
+ client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce);
+
+ if (version > QUIC_VERSION_32) {
+ 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_require_handshake_confirmation &&
+ info->server_nonce.empty()) {
+ info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE);
+ }
+ helper.ValidationComplete(QUIC_NO_ERROR, "",
+ std::move(proof_source_details));
+ return;
+ }
+
+ if (!replay_protection_) {
+ DVLOG(1) << "No replay protection.";
+ helper.ValidationComplete(QUIC_NO_ERROR, "",
+ std::move(proof_source_details));
+ return;
+ }
+
+ if (!info->server_nonce.empty()) {
+ // If the server nonce is present, use it to establish uniqueness.
+ HandshakeFailureReason server_nonce_error =
+ ValidateServerNonce(info->server_nonce, info->now);
+ bool is_unique = server_nonce_error == HANDSHAKE_OK;
+ if (!is_unique) {
+ info->reject_reasons.push_back(server_nonce_error);
+ }
+ DVLOG(1) << "Using server nonce, unique: " << is_unique;
+ helper.ValidationComplete(QUIC_NO_ERROR, "",
+ std::move(proof_source_details));
+ return;
+ }
+ // If we hit this block, the server nonce was empty. If we're requiring
+ // handshake confirmation for DoS reasons and there's no server nonce present,
+ // reject the CHLO.
+ if (FLAGS_quic_require_handshake_confirmation ||
+ FLAGS_quic_require_handshake_confirmation_pre33) {
+ info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE);
+ helper.ValidationComplete(QUIC_NO_ERROR, "",
+ std::move(proof_source_details));
+ return;
+ }
+
+ // We want to contact strike register only if there are no errors because it
+ // is a RPC call and is expensive.
+ if (found_error) {
+ helper.ValidationComplete(QUIC_NO_ERROR, "",
+ std::move(proof_source_details));
+ return;
+ }
+
+ // Use the client nonce to establish uniqueness.
+ StrikeRegisterClient* strike_register_client;
+ {
+ base::AutoLock locked(strike_register_client_lock_);
+ strike_register_client = strike_register_client_.get();
+ }
+
+ if (!strike_register_client) {
+ // Either a valid server nonces or a strike register is required.
+ // Since neither are present, reject the handshake which will send a
+ // server nonce to the client.
+ info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE);
+ helper.ValidationComplete(QUIC_NO_ERROR, "",
+ std::move(proof_source_details));
+ return;
+ }
+
+ strike_register_client->VerifyNonceIsValidAndUnique(
+ info->client_nonce, info->now,
+ new VerifyNonceIsValidAndUniqueCallback(client_hello_state,
+ std::move(proof_source_details),
+ std::move(done_cb)));
+ helper.DetachCallback();
+}
+
+bool QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
+ QuicVersion version,
+ StringPiece chlo_hash,
+ const SourceAddressTokens& previous_source_address_tokens,
+ const IPAddress& server_ip,
+ const IPAddress& client_ip,
+ const QuicClock* clock,
+ QuicRandom* rand,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ const QuicCryptoNegotiatedParameters& params,
+ const CachedNetworkParameters* cached_network_params,
+ CryptoHandshakeMessage* out) const {
+ string serialized;
+ string source_address_token;
+ QuicWallTime expiry_time = QuicWallTime::Zero();
+ const CommonCertSets* common_cert_sets;
+ {
+ base::AutoLock locked(configs_lock_);
+ serialized = primary_config_->serialized;
+ common_cert_sets = primary_config_->common_cert_sets;
+ expiry_time = primary_config_->expiry_time;
+ source_address_token = NewSourceAddressToken(
+ *primary_config_, previous_source_address_tokens, client_ip, rand,
+ clock->WallNow(), cached_network_params);
+ }
+
+ out->set_tag(kSCUP);
+ out->SetStringPiece(kSCFG, serialized);
+ out->SetStringPiece(kSourceAddressTokenTag, source_address_token);
+ out->SetValue(kSTTL,
+ expiry_time.AbsoluteDifference(clock->WallNow()).ToSeconds());
+
+ scoped_refptr<ProofSource::Chain> chain;
+ string signature;
+ string cert_sct;
+ if (!proof_source_->GetProof(server_ip, params.sni, serialized, version,
+ chlo_hash, &chain, &signature, &cert_sct)) {
+ DVLOG(1) << "Server: failed to get proof.";
+ return false;
+ }
+
+ const string compressed = CompressChain(
+ compressed_certs_cache, chain, params.client_common_set_hashes,
+ params.client_cached_cert_hashes, common_cert_sets);
+
+ out->SetStringPiece(kCertificateTag, compressed);
+ out->SetStringPiece(kPROF, signature);
+ if (params.sct_supported_by_client && enable_serving_sct_) {
+ if (cert_sct.empty()) {
+ DLOG(WARNING) << "SCT is expected but it is empty. sni: " << params.sni
+ << " server_ip: " << server_ip.ToString();
+ } else {
+ out->SetStringPiece(kCertificateSCTTag, cert_sct);
+ }
+ }
+ return true;
+}
+
+void QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
+ QuicVersion version,
+ StringPiece chlo_hash,
+ const SourceAddressTokens& previous_source_address_tokens,
+ const IPAddress& server_ip,
+ const IPAddress& client_ip,
+ const QuicClock* clock,
+ QuicRandom* rand,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ const QuicCryptoNegotiatedParameters& params,
+ const CachedNetworkParameters* cached_network_params,
+ std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const {
+ string serialized;
+ string source_address_token;
+ const CommonCertSets* common_cert_sets;
+ {
+ base::AutoLock locked(configs_lock_);
+ serialized = primary_config_->serialized;
+ common_cert_sets = primary_config_->common_cert_sets;
+ source_address_token = NewSourceAddressToken(
+ *primary_config_, previous_source_address_tokens, client_ip, rand,
+ clock->WallNow(), cached_network_params);
+ }
+
+ CryptoHandshakeMessage message;
+ message.set_tag(kSCUP);
+ message.SetStringPiece(kSCFG, serialized);
+ message.SetStringPiece(kSourceAddressTokenTag, source_address_token);
+
+ std::unique_ptr<BuildServerConfigUpdateMessageProofSourceCallback>
+ proof_source_cb(new BuildServerConfigUpdateMessageProofSourceCallback(
+ this, version, compressed_certs_cache, common_cert_sets, params,
+ std::move(message), std::move(cb)));
+
+ proof_source_->GetProof(server_ip, params.sni, serialized, version, chlo_hash,
+ std::move(proof_source_cb));
+}
+
+QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
+ ~BuildServerConfigUpdateMessageProofSourceCallback() {}
+
+QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
+ BuildServerConfigUpdateMessageProofSourceCallback(
+ const QuicCryptoServerConfig* config,
+ QuicVersion version,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ const CommonCertSets* common_cert_sets,
+ const QuicCryptoNegotiatedParameters& params,
+ CryptoHandshakeMessage message,
+ std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb)
+ : config_(config),
+ version_(version),
+ compressed_certs_cache_(compressed_certs_cache),
+ common_cert_sets_(common_cert_sets),
+ client_common_set_hashes_(params.client_common_set_hashes),
+ client_cached_cert_hashes_(params.client_cached_cert_hashes),
+ sct_supported_by_client_(params.sct_supported_by_client),
+ message_(std::move(message)),
+ cb_(std::move(cb)) {}
+
+void QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
+ Run(bool ok,
+ const scoped_refptr<ProofSource::Chain>& chain,
+ const string& signature,
+ const string& leaf_cert_sct,
+ std::unique_ptr<ProofSource::Details> details) {
+ config_->FinishBuildServerConfigUpdateMessage(
+ version_, compressed_certs_cache_, common_cert_sets_,
+ client_common_set_hashes_, client_cached_cert_hashes_,
+ sct_supported_by_client_, ok, chain, signature, leaf_cert_sct,
+ std::move(details), std::move(message_), std::move(cb_));
+}
+
+void QuicCryptoServerConfig::FinishBuildServerConfigUpdateMessage(
+ QuicVersion version,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ const CommonCertSets* common_cert_sets,
+ const string& client_common_set_hashes,
+ const string& client_cached_cert_hashes,
+ bool sct_supported_by_client,
+ bool ok,
+ const scoped_refptr<ProofSource::Chain>& chain,
+ const string& signature,
+ const string& leaf_cert_sct,
+ std::unique_ptr<ProofSource::Details> details,
+ CryptoHandshakeMessage message,
+ std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const {
+ if (!ok) {
+ cb->Run(false, message);
+ return;
+ }
+
+ const string compressed =
+ CompressChain(compressed_certs_cache, chain, client_common_set_hashes,
+ client_cached_cert_hashes, common_cert_sets);
+
+ message.SetStringPiece(kCertificateTag, compressed);
+ message.SetStringPiece(kPROF, signature);
+ if (sct_supported_by_client && enable_serving_sct_) {
+ if (leaf_cert_sct.empty()) {
+ DLOG(WARNING) << "SCT is expected but it is empty.";
+ } else {
+ message.SetStringPiece(kCertificateSCTTag, leaf_cert_sct);
+ }
+ }
+
+ cb->Run(true, message);
+}
+
+void QuicCryptoServerConfig::BuildRejection(
+ QuicVersion version,
+ QuicWallTime now,
+ const Config& config,
+ const CryptoHandshakeMessage& client_hello,
+ const ClientHelloInfo& info,
+ const CachedNetworkParameters& cached_network_params,
+ bool use_stateless_rejects,
+ QuicConnectionId server_designated_connection_id,
+ QuicRandom* rand,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ QuicCryptoNegotiatedParameters* params,
+ const QuicCryptoProof& crypto_proof,
+ QuicByteCount total_framing_overhead,
+ QuicByteCount chlo_packet_size,
+ CryptoHandshakeMessage* out) const {
+ if (FLAGS_enable_quic_stateless_reject_support && use_stateless_rejects) {
+ DVLOG(1) << "QUIC Crypto server config returning stateless reject "
+ << "with server-designated connection ID "
+ << server_designated_connection_id;
+ out->set_tag(kSREJ);
+ out->SetValue(kRCID, server_designated_connection_id);
+ } else {
+ out->set_tag(kREJ);
+ }
+ out->SetStringPiece(kSCFG, config.serialized);
+ out->SetStringPiece(
+ kSourceAddressTokenTag,
+ NewSourceAddressToken(config, info.source_address_tokens, info.client_ip,
+ rand, info.now, &cached_network_params));
+ out->SetValue(kSTTL, config.expiry_time.AbsoluteDifference(now).ToSeconds());
+ if (replay_protection_) {
+ out->SetStringPiece(kServerNonceTag, NewServerNonce(rand, info.now));
+ }
+
+ // Send client the reject reason for debugging purposes.
+ DCHECK_LT(0u, info.reject_reasons.size());
+ out->SetVector(kRREJ, info.reject_reasons);
+
+ // The client may have requested a certificate chain.
+ if (!ClientDemandsX509Proof(client_hello)) {
+ QUIC_BUG << "x509 certificates not supported in proof demand";
+ return;
+ }
+
+ StringPiece client_common_set_hashes;
+ if (client_hello.GetStringPiece(kCCS, &client_common_set_hashes)) {
+ params->client_common_set_hashes = client_common_set_hashes.as_string();
+ }
+
+ StringPiece client_cached_cert_hashes;
+ if (client_hello.GetStringPiece(kCCRT, &client_cached_cert_hashes)) {
+ params->client_cached_cert_hashes = client_cached_cert_hashes.as_string();
+ }
+
+ const string compressed =
+ CompressChain(compressed_certs_cache, crypto_proof.chain,
+ params->client_common_set_hashes,
+ params->client_cached_cert_hashes, config.common_cert_sets);
+
+ DCHECK_GT(chlo_packet_size, client_hello.size());
+ // kREJOverheadBytes is a very rough estimate of how much of a REJ
+ // message is taken up by things other than the certificates.
+ // STK: 56 bytes
+ // SNO: 56 bytes
+ // SCFG
+ // SCID: 16 bytes
+ // PUBS: 38 bytes
+ const size_t kREJOverheadBytes = 166;
+ // max_unverified_size is the number of bytes that the certificate chain,
+ // signature, and (optionally) signed certificate timestamp can consume before
+ // we will demand a valid source-address token.
+ const size_t max_unverified_size =
+ chlo_multiplier_ * (chlo_packet_size - total_framing_overhead) -
+ kREJOverheadBytes;
+ static_assert(kClientHelloMinimumSize * kMultiplier >= kREJOverheadBytes,
+ "overhead calculation may underflow");
+ bool should_return_sct =
+ params->sct_supported_by_client && enable_serving_sct_;
+ const size_t sct_size = should_return_sct ? crypto_proof.cert_sct.size() : 0;
+ const size_t total_size =
+ crypto_proof.signature.size() + compressed.size() + sct_size;
+ if (info.valid_source_address_token || total_size < max_unverified_size) {
+ out->SetStringPiece(kCertificateTag, compressed);
+ out->SetStringPiece(kPROF, crypto_proof.signature);
+ if (should_return_sct) {
+ if (crypto_proof.cert_sct.empty()) {
+ DLOG(WARNING) << "SCT is expected but it is empty.";
+ } else {
+ out->SetStringPiece(kCertificateSCTTag, crypto_proof.cert_sct);
+ }
+ }
+ } else {
+ DLOG(WARNING) << "Sending inchoate REJ for hostname: " << info.sni
+ << " signature: " << crypto_proof.signature.size()
+ << " cert: " << compressed.size() << " sct:" << sct_size
+ << " total: " << total_size
+ << " max: " << max_unverified_size;
+ }
+}
+
+string QuicCryptoServerConfig::CompressChain(
+ QuicCompressedCertsCache* compressed_certs_cache,
+ const scoped_refptr<ProofSource::Chain>& chain,
+ const string& client_common_set_hashes,
+ const string& client_cached_cert_hashes,
+ const CommonCertSets* common_sets) {
+ // Check whether the compressed certs is available in the cache.
+ DCHECK(compressed_certs_cache);
+ const string* cached_value = compressed_certs_cache->GetCompressedCert(
+ chain, client_common_set_hashes, client_cached_cert_hashes);
+ if (cached_value) {
+ return *cached_value;
+ }
+
+ const string 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,
+ client_cached_cert_hashes, compressed);
+ return compressed;
+}
+
+scoped_refptr<QuicCryptoServerConfig::Config>
+QuicCryptoServerConfig::ParseConfigProtobuf(
+ QuicServerConfigProtobuf* protobuf) {
+ std::unique_ptr<CryptoHandshakeMessage> msg(
+ CryptoFramer::ParseMessage(protobuf->config()));
+
+ if (msg->tag() != kSCFG) {
+ LOG(WARNING) << "Server config message has tag " << msg->tag()
+ << " expected " << kSCFG;
+ return nullptr;
+ }
+
+ scoped_refptr<Config> config(new Config);
+ config->serialized = protobuf->config();
+ config->source_address_token_boxer = &source_address_token_boxer_;
+
+ if (protobuf->has_primary_time()) {
+ config->primary_time =
+ QuicWallTime::FromUNIXSeconds(protobuf->primary_time());
+ }
+
+ config->priority = protobuf->priority();
+
+ StringPiece scid;
+ if (!msg->GetStringPiece(kSCID, &scid)) {
+ LOG(WARNING) << "Server config message is missing SCID";
+ return nullptr;
+ }
+ config->id = scid.as_string();
+
+ const QuicTag* aead_tags;
+ size_t aead_len;
+ if (msg->GetTaglist(kAEAD, &aead_tags, &aead_len) != QUIC_NO_ERROR) {
+ LOG(WARNING) << "Server config message is missing AEAD";
+ return nullptr;
+ }
+ config->aead = vector<QuicTag>(aead_tags, aead_tags + aead_len);
+
+ const QuicTag* kexs_tags;
+ size_t kexs_len;
+ if (msg->GetTaglist(kKEXS, &kexs_tags, &kexs_len) != QUIC_NO_ERROR) {
+ LOG(WARNING) << "Server config message is missing KEXS";
+ return nullptr;
+ }
+
+ const QuicTag* tbkp_tags;
+ size_t tbkp_len;
+ QuicErrorCode err;
+ if ((err = msg->GetTaglist(kTBKP, &tbkp_tags, &tbkp_len)) !=
+ QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND &&
+ err != QUIC_NO_ERROR) {
+ LOG(WARNING) << "Server config message is missing or has invalid TBKP";
+ return nullptr;
+ }
+ config->tb_key_params = vector<QuicTag>(tbkp_tags, tbkp_tags + tbkp_len);
+
+ StringPiece orbit;
+ if (!msg->GetStringPiece(kORBT, &orbit)) {
+ LOG(WARNING) << "Server config message is missing ORBT";
+ return nullptr;
+ }
+
+ if (orbit.size() != kOrbitSize) {
+ LOG(WARNING) << "Orbit value in server config is the wrong length."
+ " Got "
+ << orbit.size() << " want " << kOrbitSize;
+ return nullptr;
+ }
+ static_assert(sizeof(config->orbit) == kOrbitSize,
+ "orbit has incorrect size");
+ memcpy(config->orbit, orbit.data(), sizeof(config->orbit));
+
+ {
+ StrikeRegisterClient* strike_register_client;
+ {
+ base::AutoLock locked(strike_register_client_lock_);
+ strike_register_client = strike_register_client_.get();
+ }
+
+ if (strike_register_client != nullptr &&
+ !strike_register_client->IsKnownOrbit(orbit)) {
+ LOG(WARNING)
+ << "Rejecting server config with orbit that the strike register "
+ "client doesn't know about.";
+ return nullptr;
+ }
+ }
+
+ if (kexs_len != protobuf->key_size()) {
+ LOG(WARNING) << "Server config has " << kexs_len
+ << " key exchange methods configured, but "
+ << protobuf->key_size() << " private keys";
+ return nullptr;
+ }
+
+ const QuicTag* proof_demand_tags;
+ size_t num_proof_demand_tags;
+ if (msg->GetTaglist(kPDMD, &proof_demand_tags, &num_proof_demand_tags) ==
+ QUIC_NO_ERROR) {
+ for (size_t i = 0; i < num_proof_demand_tags; i++) {
+ if (proof_demand_tags[i] == kCHID) {
+ config->channel_id_enabled = true;
+ break;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < kexs_len; i++) {
+ const QuicTag tag = kexs_tags[i];
+ string private_key;
+
+ config->kexs.push_back(tag);
+
+ for (size_t j = 0; j < protobuf->key_size(); j++) {
+ const QuicServerConfigProtobuf::PrivateKey& key = protobuf->key(i);
+ if (key.tag() == tag) {
+ private_key = key.private_key();
+ break;
+ }
+ }
+
+ if (private_key.empty()) {
+ LOG(WARNING) << "Server config contains key exchange method without "
+ "corresponding private key: "
+ << tag;
+ return nullptr;
+ }
+
+ std::unique_ptr<KeyExchange> ka;
+ switch (tag) {
+ case kC255:
+ ka.reset(Curve25519KeyExchange::New(private_key));
+ if (!ka.get()) {
+ LOG(WARNING) << "Server config contained an invalid curve25519"
+ " private key.";
+ return nullptr;
+ }
+ break;
+ case kP256:
+ ka.reset(P256KeyExchange::New(private_key));
+ if (!ka.get()) {
+ LOG(WARNING) << "Server config contained an invalid P-256"
+ " private key.";
+ return nullptr;
+ }
+ break;
+ default:
+ LOG(WARNING) << "Server config message contains unknown key exchange "
+ "method: "
+ << tag;
+ return nullptr;
+ }
+
+ for (const KeyExchange* key_exchange : config->key_exchanges) {
+ if (key_exchange->tag() == tag) {
+ LOG(WARNING) << "Duplicate key exchange in config: " << tag;
+ return nullptr;
+ }
+ }
+
+ config->key_exchanges.push_back(ka.release());
+ }
+
+ uint64_t expiry_seconds;
+ if (msg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
+ LOG(WARNING) << "Server config message is missing EXPY";
+ return nullptr;
+ }
+ config->expiry_time = QuicWallTime::FromUNIXSeconds(expiry_seconds);
+
+ return config;
+}
+
+void QuicCryptoServerConfig::SetEphemeralKeySource(
+ EphemeralKeySource* ephemeral_key_source) {
+ ephemeral_key_source_.reset(ephemeral_key_source);
+}
+
+void QuicCryptoServerConfig::SetStrikeRegisterClient(
+ StrikeRegisterClient* strike_register_client) {
+ base::AutoLock locker(strike_register_client_lock_);
+ DCHECK(!strike_register_client_.get());
+ strike_register_client_.reset(strike_register_client);
+}
+
+void QuicCryptoServerConfig::set_replay_protection(bool on) {
+ replay_protection_ = on;
+}
+
+void QuicCryptoServerConfig::set_chlo_multiplier(size_t multiplier) {
+ chlo_multiplier_ = multiplier;
+}
+
+void QuicCryptoServerConfig::set_strike_register_no_startup_period() {
+ base::AutoLock locker(strike_register_client_lock_);
+ DCHECK(!strike_register_client_.get());
+ strike_register_no_startup_period_ = true;
+}
+
+void QuicCryptoServerConfig::set_strike_register_max_entries(
+ uint32_t max_entries) {
+ base::AutoLock locker(strike_register_client_lock_);
+ DCHECK(!strike_register_client_.get());
+ strike_register_max_entries_ = max_entries;
+}
+
+void QuicCryptoServerConfig::set_strike_register_window_secs(
+ uint32_t window_secs) {
+ base::AutoLock locker(strike_register_client_lock_);
+ DCHECK(!strike_register_client_.get());
+ strike_register_window_secs_ = window_secs;
+}
+
+void QuicCryptoServerConfig::set_source_address_token_future_secs(
+ uint32_t future_secs) {
+ source_address_token_future_secs_ = future_secs;
+}
+
+void QuicCryptoServerConfig::set_source_address_token_lifetime_secs(
+ uint32_t lifetime_secs) {
+ source_address_token_lifetime_secs_ = lifetime_secs;
+}
+
+void QuicCryptoServerConfig::set_server_nonce_strike_register_max_entries(
+ uint32_t max_entries) {
+ DCHECK(!server_nonce_strike_register_.get());
+ server_nonce_strike_register_max_entries_ = max_entries;
+}
+
+void QuicCryptoServerConfig::set_server_nonce_strike_register_window_secs(
+ uint32_t window_secs) {
+ DCHECK(!server_nonce_strike_register_.get());
+ server_nonce_strike_register_window_secs_ = window_secs;
+}
+
+void QuicCryptoServerConfig::set_enable_serving_sct(bool enable_serving_sct) {
+ enable_serving_sct_ = enable_serving_sct;
+}
+
+void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb(
+ std::unique_ptr<PrimaryConfigChangedCallback> cb) {
+ base::AutoLock locked(configs_lock_);
+ primary_config_changed_cb_ = std::move(cb);
+}
+
+string QuicCryptoServerConfig::NewSourceAddressToken(
+ const Config& config,
+ const SourceAddressTokens& previous_tokens,
+ const IPAddress& ip,
+ QuicRandom* rand,
+ QuicWallTime now,
+ const CachedNetworkParameters* cached_network_params) const {
+ SourceAddressTokens source_address_tokens;
+ SourceAddressToken* source_address_token = source_address_tokens.add_tokens();
+ source_address_token->set_ip(IPAddressToPackedString(DualstackIPAddress(ip)));
+ source_address_token->set_timestamp(now.ToUNIXSeconds());
+ if (cached_network_params != nullptr) {
+ *(source_address_token->mutable_cached_network_parameters()) =
+ *cached_network_params;
+ }
+
+ // Append previous tokens.
+ for (const SourceAddressToken& token : previous_tokens.tokens()) {
+ if (source_address_tokens.tokens_size() > kMaxTokenAddresses) {
+ break;
+ }
+
+ if (token.ip() == source_address_token->ip()) {
+ // It's for the same IP address.
+ continue;
+ }
+
+ if (ValidateSourceAddressTokenTimestamp(token, now) != HANDSHAKE_OK) {
+ continue;
+ }
+
+ *(source_address_tokens.add_tokens()) = token;
+ }
+
+ return config.source_address_token_boxer->Box(
+ rand, source_address_tokens.SerializeAsString());
+}
+
+int QuicCryptoServerConfig::NumberOfConfigs() const {
+ base::AutoLock locked(configs_lock_);
+ return configs_.size();
+}
+
+HandshakeFailureReason QuicCryptoServerConfig::ParseSourceAddressToken(
+ const Config& config,
+ StringPiece token,
+ SourceAddressTokens* tokens) const {
+ string storage;
+ StringPiece plaintext;
+ if (!config.source_address_token_boxer->Unbox(token, &storage, &plaintext)) {
+ return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE;
+ }
+
+ if (!tokens->ParseFromArray(plaintext.data(), plaintext.size())) {
+ // Some clients might still be using the old source token format so
+ // attempt to parse that format.
+ // TODO(rch): remove this code once the new format is ubiquitous.
+ SourceAddressToken source_address_token;
+ if (!source_address_token.ParseFromArray(plaintext.data(),
+ plaintext.size())) {
+ return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE;
+ }
+ *tokens->add_tokens() = source_address_token;
+ }
+
+ return HANDSHAKE_OK;
+}
+
+HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressTokens(
+ const SourceAddressTokens& source_address_tokens,
+ const IPAddress& ip,
+ QuicWallTime now,
+ CachedNetworkParameters* cached_network_params) const {
+ HandshakeFailureReason reason =
+ SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
+ for (const SourceAddressToken& token : source_address_tokens.tokens()) {
+ reason = ValidateSingleSourceAddressToken(token, ip, now);
+ if (reason == HANDSHAKE_OK) {
+ if (token.has_cached_network_parameters()) {
+ *cached_network_params = token.cached_network_parameters();
+ }
+ break;
+ }
+ }
+ return reason;
+}
+
+HandshakeFailureReason QuicCryptoServerConfig::ValidateSingleSourceAddressToken(
+ const SourceAddressToken& source_address_token,
+ const IPAddress& ip,
+ QuicWallTime now) const {
+ if (source_address_token.ip() !=
+ IPAddressToPackedString(DualstackIPAddress(ip))) {
+ // It's for a different IP address.
+ return SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
+ }
+
+ return ValidateSourceAddressTokenTimestamp(source_address_token, now);
+}
+
+HandshakeFailureReason
+QuicCryptoServerConfig::ValidateSourceAddressTokenTimestamp(
+ const SourceAddressToken& source_address_token,
+ QuicWallTime now) const {
+ const QuicWallTime timestamp(
+ QuicWallTime::FromUNIXSeconds(source_address_token.timestamp()));
+ const QuicTime::Delta delta(now.AbsoluteDifference(timestamp));
+
+ if (now.IsBefore(timestamp) &&
+ delta.ToSeconds() > source_address_token_future_secs_) {
+ return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE;
+ }
+
+ if (now.IsAfter(timestamp) &&
+ delta.ToSeconds() > source_address_token_lifetime_secs_) {
+ return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE;
+ }
+
+ return HANDSHAKE_OK;
+}
+
+// kServerNoncePlaintextSize is the number of bytes in an unencrypted server
+// nonce.
+static const size_t kServerNoncePlaintextSize =
+ 4 /* timestamp */ + 20 /* random bytes */;
+
+string QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand,
+ QuicWallTime now) const {
+ const uint32_t timestamp = static_cast<uint32_t>(now.ToUNIXSeconds());
+
+ uint8_t server_nonce[kServerNoncePlaintextSize];
+ static_assert(sizeof(server_nonce) > sizeof(timestamp), "nonce too small");
+ server_nonce[0] = static_cast<uint8_t>(timestamp >> 24);
+ server_nonce[1] = static_cast<uint8_t>(timestamp >> 16);
+ server_nonce[2] = static_cast<uint8_t>(timestamp >> 8);
+ server_nonce[3] = static_cast<uint8_t>(timestamp);
+ rand->RandBytes(&server_nonce[sizeof(timestamp)],
+ sizeof(server_nonce) - sizeof(timestamp));
+
+ return server_nonce_boxer_.Box(
+ rand,
+ StringPiece(reinterpret_cast<char*>(server_nonce), sizeof(server_nonce)));
+}
+
+HandshakeFailureReason QuicCryptoServerConfig::ValidateServerNonce(
+ StringPiece token,
+ QuicWallTime now) const {
+ string storage;
+ StringPiece plaintext;
+ if (!server_nonce_boxer_.Unbox(token, &storage, &plaintext)) {
+ return SERVER_NONCE_DECRYPTION_FAILURE;
+ }
+
+ // plaintext contains:
+ // uint32_t timestamp
+ // uint8_t[20] random bytes
+
+ if (plaintext.size() != kServerNoncePlaintextSize) {
+ // This should never happen because the value decrypted correctly.
+ QUIC_BUG << "Seemingly valid server nonce had incorrect length.";
+ return SERVER_NONCE_INVALID_FAILURE;
+ }
+
+ uint8_t server_nonce[32];
+ memcpy(server_nonce, plaintext.data(), 4);
+ memcpy(server_nonce + 4, server_nonce_orbit_, sizeof(server_nonce_orbit_));
+ memcpy(server_nonce + 4 + sizeof(server_nonce_orbit_), plaintext.data() + 4,
+ 20);
+ static_assert(4 + sizeof(server_nonce_orbit_) + 20 == sizeof(server_nonce),
+ "bad nonce buffer length");
+
+ InsertStatus nonce_error;
+ {
+ base::AutoLock auto_lock(server_nonce_strike_register_lock_);
+ if (server_nonce_strike_register_.get() == nullptr) {
+ server_nonce_strike_register_.reset(new StrikeRegister(
+ server_nonce_strike_register_max_entries_,
+ static_cast<uint32_t>(now.ToUNIXSeconds()),
+ server_nonce_strike_register_window_secs_, server_nonce_orbit_,
+ StrikeRegister::NO_STARTUP_PERIOD_NEEDED));
+ }
+ nonce_error = server_nonce_strike_register_->Insert(
+ server_nonce, static_cast<uint32_t>(now.ToUNIXSeconds()));
+ }
+
+ switch (nonce_error) {
+ case NONCE_OK:
+ return HANDSHAKE_OK;
+ case NONCE_INVALID_FAILURE:
+ case NONCE_INVALID_ORBIT_FAILURE:
+ return SERVER_NONCE_INVALID_FAILURE;
+ case NONCE_NOT_UNIQUE_FAILURE:
+ return SERVER_NONCE_NOT_UNIQUE_FAILURE;
+ case NONCE_INVALID_TIME_FAILURE:
+ return SERVER_NONCE_INVALID_TIME_FAILURE;
+ case NONCE_UNKNOWN_FAILURE:
+ case STRIKE_REGISTER_TIMEOUT:
+ case STRIKE_REGISTER_FAILURE:
+ default:
+ QUIC_BUG << "Unexpected server nonce error: " << nonce_error;
+ return SERVER_NONCE_NOT_UNIQUE_FAILURE;
+ }
+}
+
+bool QuicCryptoServerConfig::ValidateExpectedLeafCertificate(
+ const CryptoHandshakeMessage& client_hello,
+ const QuicCryptoProof& crypto_proof) const {
+ if (crypto_proof.chain->certs.empty()) {
+ return false;
+ }
+
+ uint64_t hash_from_client;
+ if (client_hello.GetUint64(kXLCT, &hash_from_client) != QUIC_NO_ERROR) {
+ return false;
+ }
+ return CryptoUtils::ComputeLeafCertHash(crypto_proof.chain->certs.at(0)) ==
+ hash_from_client;
+}
+
+bool QuicCryptoServerConfig::ClientDemandsX509Proof(
+ const CryptoHandshakeMessage& client_hello) const {
+ const QuicTag* their_proof_demands;
+ size_t num_their_proof_demands;
+
+ if (client_hello.GetTaglist(kPDMD, &their_proof_demands,
+ &num_their_proof_demands) != QUIC_NO_ERROR) {
+ return false;
+ }
+
+ for (size_t i = 0; i < num_their_proof_demands; i++) {
+ switch (their_proof_demands[i]) {
+ case kX509:
+ return true;
+ }
+ }
+ return false;
+}
+
+QuicCryptoServerConfig::Config::Config()
+ : channel_id_enabled(false),
+ is_primary(false),
+ primary_time(QuicWallTime::Zero()),
+ expiry_time(QuicWallTime::Zero()),
+ priority(0),
+ source_address_token_boxer(nullptr) {}
+
+QuicCryptoServerConfig::Config::~Config() {
+ base::STLDeleteElements(&key_exchanges);
+}
+
+QuicCryptoProof::QuicCryptoProof() {}
+QuicCryptoProof::~QuicCryptoProof() {}
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/quic_crypto_server_config.h b/chromium/net/quic/core/crypto/quic_crypto_server_config.h
new file mode 100644
index 00000000000..e01bb3afc9a
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_crypto_server_config.h
@@ -0,0 +1,856 @@
+// Copyright 2013 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_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_
+#define NET_QUIC_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
+#include "base/synchronization/lock.h"
+#include "net/base/ip_address.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/crypto_secret_boxer.h"
+#include "net/quic/core/crypto/proof_source.h"
+#include "net/quic/core/crypto/quic_compressed_certs_cache.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_time.h"
+
+namespace net {
+
+class CryptoHandshakeMessage;
+class EphemeralKeySource;
+class KeyExchange;
+class ProofSource;
+class QuicClock;
+class QuicDecrypter;
+class QuicEncrypter;
+class QuicRandom;
+class QuicServerConfigProtobuf;
+class StrikeRegister;
+class StrikeRegisterClient;
+struct QuicCryptoProof;
+
+// ClientHelloInfo contains information about a client hello message that is
+// only kept for as long as it's being processed.
+struct ClientHelloInfo {
+ ClientHelloInfo(const IPAddress& in_client_ip, QuicWallTime in_now);
+ ClientHelloInfo(const ClientHelloInfo& other);
+ ~ClientHelloInfo();
+
+ // Inputs to EvaluateClientHello.
+ const IPAddress client_ip;
+ const QuicWallTime now;
+
+ // Outputs from EvaluateClientHello.
+ bool valid_source_address_token;
+ base::StringPiece sni;
+ base::StringPiece client_nonce;
+ base::StringPiece server_nonce;
+ base::StringPiece user_agent_id;
+ SourceAddressTokens source_address_tokens;
+
+ // Errors from EvaluateClientHello.
+ std::vector<uint32_t> reject_reasons;
+ static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync");
+};
+
+namespace test {
+class QuicCryptoServerConfigPeer;
+} // namespace test
+
+// Hook that allows application code to subscribe to primary config changes.
+class PrimaryConfigChangedCallback {
+ public:
+ PrimaryConfigChangedCallback();
+ virtual ~PrimaryConfigChangedCallback();
+ virtual void Run(const std::string& scid) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PrimaryConfigChangedCallback);
+};
+
+// Callback used to accept the result of the |client_hello| validation step.
+class NET_EXPORT_PRIVATE ValidateClientHelloResultCallback {
+ public:
+ // Opaque token that holds information about the client_hello and
+ // its validity. Can be interpreted by calling ProcessClientHello.
+ struct NET_EXPORT_PRIVATE Result : public base::RefCountedThreadSafe<Result> {
+ Result(const CryptoHandshakeMessage& in_client_hello,
+ IPAddress in_client_ip,
+ QuicWallTime in_now);
+
+ CryptoHandshakeMessage client_hello;
+ ClientHelloInfo info;
+ QuicErrorCode error_code;
+ std::string error_details;
+
+ // Populated if the CHLO STK contained a CachedNetworkParameters proto.
+ CachedNetworkParameters cached_network_params;
+
+ private:
+ friend class base::RefCountedThreadSafe<Result>;
+ ~Result();
+ };
+
+ ValidateClientHelloResultCallback();
+ virtual void Run(scoped_refptr<Result> result,
+ std::unique_ptr<ProofSource::Details> details) = 0;
+ virtual ~ValidateClientHelloResultCallback();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ValidateClientHelloResultCallback);
+};
+
+// Callback used to accept the result of the ProcessClientHello method.
+class NET_EXPORT_PRIVATE ProcessClientHelloResultCallback {
+ public:
+ ProcessClientHelloResultCallback();
+ virtual ~ProcessClientHelloResultCallback();
+ virtual void Run(
+ QuicErrorCode error,
+ const std::string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> message,
+ std::unique_ptr<DiversificationNonce> diversification_nonce) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProcessClientHelloResultCallback);
+};
+
+// Callback used to receive the results of a call to
+// BuildServerConfigUpdateMessage.
+class BuildServerConfigUpdateMessageResultCallback {
+ public:
+ BuildServerConfigUpdateMessageResultCallback() = default;
+ virtual ~BuildServerConfigUpdateMessageResultCallback() {}
+ virtual void Run(bool ok, const CryptoHandshakeMessage& message) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BuildServerConfigUpdateMessageResultCallback);
+};
+
+// Object that is interested in built rejections (which include REJ, SREJ and
+// cheap SREJ).
+class RejectionObserver {
+ public:
+ RejectionObserver() = default;
+ virtual ~RejectionObserver() {}
+ // Called after a rejection is built.
+ virtual void OnRejectionBuilt(const std::vector<uint32_t>& reasons,
+ CryptoHandshakeMessage* out) const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RejectionObserver);
+};
+
+// QuicCryptoServerConfig contains the crypto configuration of a QUIC server.
+// Unlike a client, a QUIC server can have multiple configurations active in
+// order to support clients resuming with a previous configuration.
+// TODO(agl): when adding configurations at runtime is added, this object will
+// need to consider locking.
+class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
+ public:
+ // ConfigOptions contains options for generating server configs.
+ struct NET_EXPORT_PRIVATE ConfigOptions {
+ ConfigOptions();
+ ConfigOptions(const ConfigOptions& other);
+ ~ConfigOptions();
+
+ // expiry_time is the time, in UNIX seconds, when the server config will
+ // expire. If unset, it defaults to the current time plus six months.
+ QuicWallTime expiry_time;
+ // channel_id_enabled controls whether the server config will indicate
+ // support for ChannelIDs.
+ bool channel_id_enabled;
+ // token_binding_params contains the list of Token Binding params (e.g.
+ // P256, TB10) that the server config will include.
+ QuicTagVector token_binding_params;
+ // id contains the server config id for the resulting config. If empty, a
+ // random id is generated.
+ std::string id;
+ // orbit contains the kOrbitSize bytes of the orbit value for the server
+ // config. If |orbit| is empty then a random orbit is generated.
+ std::string orbit;
+ // p256 determines whether a P-256 public key will be included in the
+ // server config. Note that this breaks deterministic server-config
+ // generation since P-256 key generation doesn't use the QuicRandom given
+ // to DefaultConfig().
+ bool p256;
+ };
+
+ // |source_address_token_secret|: secret key material used for encrypting and
+ // decrypting source address tokens. It can be of any length as it is fed
+ // into a KDF before use. In tests, use TESTING.
+ // |server_nonce_entropy|: an entropy source used to generate the orbit and
+ // key for server nonces, which are always local to a given instance of a
+ // server. Not owned.
+ // |proof_source|: provides certificate chains and signatures. This class
+ // takes ownership of |proof_source|.
+ QuicCryptoServerConfig(base::StringPiece source_address_token_secret,
+ QuicRandom* server_nonce_entropy,
+ std::unique_ptr<ProofSource> proof_source);
+ ~QuicCryptoServerConfig();
+
+ // TESTING is a magic parameter for passing to the constructor in tests.
+ static const char TESTING[];
+
+ // Generates a QuicServerConfigProtobuf protobuf suitable for
+ // AddConfig and SetConfigs.
+ static QuicServerConfigProtobuf* GenerateConfig(QuicRandom* rand,
+ const QuicClock* clock,
+ const ConfigOptions& options);
+
+ // AddConfig adds a QuicServerConfigProtobuf to the availible configurations.
+ // It returns the SCFG message from the config if successful. The caller
+ // takes ownership of the CryptoHandshakeMessage. |now| is used in
+ // conjunction with |protobuf->primary_time()| to determine whether the
+ // config should be made primary.
+ CryptoHandshakeMessage* AddConfig(QuicServerConfigProtobuf* protobuf,
+ QuicWallTime now);
+
+ // AddDefaultConfig calls DefaultConfig to create a config and then calls
+ // AddConfig to add it. See the comment for |DefaultConfig| for details of
+ // the arguments.
+ CryptoHandshakeMessage* AddDefaultConfig(QuicRandom* rand,
+ const QuicClock* clock,
+ const ConfigOptions& options);
+
+ // SetConfigs takes a vector of config protobufs and the current time.
+ // Configs are assumed to be uniquely identified by their server config ID.
+ // Previously unknown configs are added and possibly made the primary config
+ // depending on their |primary_time| and the value of |now|. Configs that are
+ // known, but are missing from the protobufs are deleted, unless they are
+ // currently the primary config. SetConfigs returns false if any errors were
+ // encountered and no changes to the QuicCryptoServerConfig will occur.
+ bool SetConfigs(const std::vector<QuicServerConfigProtobuf*>& protobufs,
+ QuicWallTime now);
+
+ // SetSourceAddressTokenKeys sets the keys to be tried, in order, when
+ // decrypting a source address token. Note that these keys are used *without*
+ // passing them through a KDF, in contradistinction to the
+ // |source_address_token_secret| argument to the constructor.
+ void SetSourceAddressTokenKeys(const std::vector<std::string>& keys);
+
+ // Get the server config ids for all known configs.
+ void GetConfigIds(std::vector<std::string>* scids) const;
+
+ // Checks |client_hello| for gross errors and determines whether it can be
+ // shown to be fresh (i.e. not a replay). The result of the validation step
+ // must be interpreted by calling QuicCryptoServerConfig::ProcessClientHello
+ // from the done_cb.
+ //
+ // ValidateClientHello may invoke the done_cb before unrolling the
+ // stack if it is able to assess the validity of the client_nonce
+ // without asynchronous operations.
+ //
+ // client_hello: the incoming client hello message.
+ // client_ip: the IP address of the client, which is used to generate and
+ // validate source-address tokens.
+ // server_ip: the IP address of the server. The IP address may be used for
+ // certificate selection.
+ // version: protocol version used for this connection.
+ // clock: used to validate client nonces and ephemeral keys.
+ // crypto_proof: in/out parameter to which will be written the crypto proof
+ // used in reply to a proof demand. The pointed-to-object must
+ // live until the callback is invoked.
+ // done_cb: single-use callback that accepts an opaque
+ // ValidatedClientHelloMsg token that holds information about
+ // the client hello. The callback will always be called exactly
+ // once, either under the current call stack, or after the
+ // completion of an asynchronous operation.
+ void ValidateClientHello(
+ const CryptoHandshakeMessage& client_hello,
+ const IPAddress& client_ip,
+ const IPAddress& server_ip,
+ QuicVersion version,
+ const QuicClock* clock,
+ QuicCryptoProof* crypto_proof,
+ std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const;
+
+ // ProcessClientHello processes |client_hello| and decides whether to accept
+ // or reject the connection. If the connection is to be accepted, |done_cb| is
+ // invoked with the contents of the ServerHello and QUIC_NO_ERROR. Otherwise
+ // |done_cb| is called with a REJ or SREJ message and QUIC_NO_ERROR.
+ //
+ // validate_chlo_result: Output from the asynchronous call to
+ // ValidateClientHello. Contains the client hello message and
+ // information about it.
+ // reject_only: Only generate rejections, not server hello messages.
+ // connection_id: the ConnectionId for the connection, which is used in key
+ // derivation.
+ // server_ip: the IP address of the server. The IP address may be used for
+ // certificate selection.
+ // client_address: the IP address and port of the client. The IP address is
+ // used to generate and validate source-address tokens.
+ // version: version of the QUIC protocol in use for this connection
+ // supported_versions: versions of the QUIC protocol that this server
+ // supports.
+ // clock: used to validate client nonces and ephemeral keys.
+ // rand: an entropy source
+ // compressed_certs_cache: the cache that caches a set of most recently used
+ // certs. Owned by QuicDispatcher.
+ // params: the state of the handshake. This may be updated with a server
+ // nonce when we send a rejection.
+ // crypto_proof: output structure containing the crypto proof used in reply to
+ // a proof demand.
+ // total_framing_overhead: the total per-packet overhead for a stream frame
+ // chlo_packet_size: the size, in bytes, of the CHLO packet
+ // done_cb: the callback invoked on completion
+ void ProcessClientHello(
+ scoped_refptr<ValidateClientHelloResultCallback::Result>
+ validate_chlo_result,
+ bool reject_only,
+ QuicConnectionId connection_id,
+ const IPAddress& server_ip,
+ const IPEndPoint& client_address,
+ QuicVersion version,
+ const QuicVersionVector& supported_versions,
+ bool use_stateless_rejects,
+ QuicConnectionId server_designated_connection_id,
+ const QuicClock* clock,
+ QuicRandom* rand,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ QuicCryptoNegotiatedParameters* params,
+ QuicCryptoProof* crypto_proof,
+ QuicByteCount total_framing_overhead,
+ QuicByteCount chlo_packet_size,
+ std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const;
+
+ // BuildServerConfigUpdateMessage sets |out| to be a SCUP message containing
+ // the current primary config, an up to date source-address token, and cert
+ // chain and proof in the case of secure QUIC. Returns true if successfully
+ // filled |out|.
+ //
+ // |cached_network_params| is optional, and can be nullptr.
+ //
+ // TODO(gredner): remove this when --FLAGS_enable_async_get_proof is removed.
+ bool BuildServerConfigUpdateMessage(
+ QuicVersion version,
+ base::StringPiece chlo_hash,
+ const SourceAddressTokens& previous_source_address_tokens,
+ const IPAddress& server_ip,
+ const IPAddress& client_ip,
+ const QuicClock* clock,
+ QuicRandom* rand,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ const QuicCryptoNegotiatedParameters& params,
+ const CachedNetworkParameters* cached_network_params,
+ CryptoHandshakeMessage* out) const;
+
+ // BuildServerConfigUpdateMessage invokes |cb| with a SCUP message containing
+ // the current primary config, an up to date source-address token, and cert
+ // chain and proof in the case of secure QUIC. Passes true to |cb| if the
+ // message was generated successfully, and false otherwise. This method
+ // assumes ownership of |cb|.
+ //
+ // |cached_network_params| is optional, and can be nullptr.
+ //
+ // TODO(gredner): This method is an async version of the above. The
+ // synchronous version will eventually be removed.
+ void BuildServerConfigUpdateMessage(
+ QuicVersion version,
+ base::StringPiece chlo_hash,
+ const SourceAddressTokens& previous_source_address_tokens,
+ const IPAddress& server_ip,
+ const IPAddress& client_ip,
+ const QuicClock* clock,
+ QuicRandom* rand,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ const QuicCryptoNegotiatedParameters& params,
+ const CachedNetworkParameters* cached_network_params,
+ std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const;
+
+ // SetEphemeralKeySource installs an object that can cache ephemeral keys for
+ // a short period of time. This object takes ownership of
+ // |ephemeral_key_source|. If not set then ephemeral keys will be generated
+ // per-connection.
+ void SetEphemeralKeySource(EphemeralKeySource* ephemeral_key_source);
+
+ // Install an externall created StrikeRegisterClient for use to
+ // interact with the strike register. This object takes ownership
+ // of the |strike_register_client|.
+ void SetStrikeRegisterClient(StrikeRegisterClient* strike_register_client);
+
+ // set_replay_protection controls whether replay protection is enabled. If
+ // replay protection is disabled then no strike registers are needed and
+ // frontends can share an orbit value without a shared strike-register.
+ // However, an attacker can duplicate a handshake and cause a client's
+ // request to be processed twice.
+ void set_replay_protection(bool on);
+
+ // set_chlo_multiplier specifies the multiple of the CHLO message size
+ // that a REJ message must stay under when the client doesn't present a
+ // valid source-address token.
+ void set_chlo_multiplier(size_t multiplier);
+
+ // set_strike_register_no_startup_period configures the strike register to
+ // not have a startup period.
+ void set_strike_register_no_startup_period();
+
+ // set_strike_register_max_entries sets the maximum number of entries that
+ // the internal strike register will hold. If the strike register fills up
+ // then the oldest entries (by the client's clock) will be dropped.
+ void set_strike_register_max_entries(uint32_t max_entries);
+
+ // set_strike_register_window_secs sets the number of seconds around the
+ // current time that the strike register will attempt to be authoritative
+ // for. Setting a larger value allows for greater client clock-skew, but
+ // means that the quiescent startup period must be longer.
+ void set_strike_register_window_secs(uint32_t window_secs);
+
+ // set_source_address_token_future_secs sets the number of seconds into the
+ // future that source-address tokens will be accepted from. Since
+ // source-address tokens are authenticated, this should only happen if
+ // another, valid server has clock-skew.
+ void set_source_address_token_future_secs(uint32_t future_secs);
+
+ // set_source_address_token_lifetime_secs sets the number of seconds that a
+ // source-address token will be valid for.
+ void set_source_address_token_lifetime_secs(uint32_t lifetime_secs);
+
+ // set_server_nonce_strike_register_max_entries sets the number of entries in
+ // the server-nonce strike-register. This is used to record that server nonce
+ // values have been used. If the number of entries is too small then clients
+ // which are depending on server nonces may fail to handshake because their
+ // nonce has expired in the amount of time it took to go from the server to
+ // the client and back.
+ void set_server_nonce_strike_register_max_entries(uint32_t max_entries);
+
+ // set_server_nonce_strike_register_window_secs sets the number of seconds
+ // around the current time that the server-nonce strike-register will accept
+ // nonces from. Setting a larger value allows for clients to delay follow-up
+ // client hellos for longer and still use server nonces as proofs of
+ // uniqueness.
+ void set_server_nonce_strike_register_window_secs(uint32_t window_secs);
+
+ // set_enable_serving_sct enables or disables serving signed cert timestamp
+ // (RFC6962) in server hello.
+ void set_enable_serving_sct(bool enable_serving_sct);
+
+ // Set and take ownership of the callback to invoke on primary config changes.
+ void AcquirePrimaryConfigChangedCb(
+ std::unique_ptr<PrimaryConfigChangedCallback> cb);
+
+ // Returns the number of configs this object owns.
+ int NumberOfConfigs() const;
+
+ // Callers retain the ownership of |rejection_observer| which must outlive the
+ // config.
+ void set_rejection_observer(RejectionObserver* rejection_observer) {
+ rejection_observer_ = rejection_observer;
+ }
+
+ private:
+ friend class test::QuicCryptoServerConfigPeer;
+ friend struct QuicCryptoProof;
+
+ // Config represents a server config: a collection of preferences and
+ // Diffie-Hellman public values.
+ class NET_EXPORT_PRIVATE Config : public QuicCryptoConfig,
+ public base::RefCounted<Config> {
+ public:
+ Config();
+
+ // TODO(rtenneti): since this is a class, we should probably do
+ // getters/setters here.
+ // |serialized| contains the bytes of this server config, suitable for
+ // sending on the wire.
+ std::string serialized;
+ // id contains the SCID of this server config.
+ std::string id;
+ // orbit contains the orbit value for this config: an opaque identifier
+ // used to identify clusters of server frontends.
+ unsigned char orbit[kOrbitSize];
+
+ // key_exchanges contains key exchange objects with the private keys
+ // already loaded. The values correspond, one-to-one, with the tags in
+ // |kexs| from the parent class.
+ std::vector<KeyExchange*> key_exchanges;
+
+ // tag_value_map contains the raw key/value pairs for the config.
+ QuicTagValueMap tag_value_map;
+
+ // channel_id_enabled is true if the config in |serialized| specifies that
+ // ChannelIDs are supported.
+ bool channel_id_enabled;
+
+ // is_primary is true if this config is the one that we'll give out to
+ // clients as the current one.
+ bool is_primary;
+
+ // primary_time contains the timestamp when this config should become the
+ // primary config. A value of QuicWallTime::Zero() means that this config
+ // will not be promoted at a specific time.
+ QuicWallTime primary_time;
+
+ // expiry_time contains the timestamp when this config expires.
+ QuicWallTime expiry_time;
+
+ // Secondary sort key for use when selecting primary configs and
+ // there are multiple configs with the same primary time.
+ // Smaller numbers mean higher priority.
+ uint64_t priority;
+
+ // source_address_token_boxer_ is used to protect the
+ // source-address tokens that are given to clients.
+ // Points to either source_address_token_boxer_storage or the
+ // default boxer provided by QuicCryptoServerConfig.
+ const CryptoSecretBoxer* source_address_token_boxer;
+
+ // Holds the override source_address_token_boxer instance if the
+ // Config is not using the default source address token boxer
+ // instance provided by QuicCryptoServerConfig.
+ std::unique_ptr<CryptoSecretBoxer> source_address_token_boxer_storage;
+
+ private:
+ friend class base::RefCounted<Config>;
+
+ virtual ~Config();
+
+ DISALLOW_COPY_AND_ASSIGN(Config);
+ };
+
+ typedef std::map<ServerConfigID, scoped_refptr<Config>> ConfigMap;
+
+ // Get a ref to the config with a given server config id.
+ scoped_refptr<Config> GetConfigWithScid(
+ base::StringPiece requested_scid) const;
+
+ // ConfigPrimaryTimeLessThan returns true if a->primary_time <
+ // b->primary_time.
+ static bool ConfigPrimaryTimeLessThan(const scoped_refptr<Config>& a,
+ const scoped_refptr<Config>& b);
+
+ // SelectNewPrimaryConfig reevaluates the primary config based on the
+ // "primary_time" deadlines contained in each.
+ void SelectNewPrimaryConfig(QuicWallTime now) const;
+
+ // EvaluateClientHello checks |client_hello| for gross errors and determines
+ // whether it can be shown to be fresh (i.e. not a replay). The results are
+ // written to |info|.
+ void EvaluateClientHello(
+ const IPAddress& server_ip,
+ QuicVersion version,
+ const uint8_t* primary_orbit,
+ scoped_refptr<Config> requested_config,
+ scoped_refptr<Config> primary_config,
+ QuicCryptoProof* crypto_proof,
+ scoped_refptr<ValidateClientHelloResultCallback::Result>
+ client_hello_state,
+ std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const;
+
+ // Callback class for bridging between EvaluateClientHello and
+ // EvaluateClientHelloAfterGetProof.
+ class EvaluateClientHelloCallback;
+ friend class EvaluateClientHelloCallback;
+
+ // Continuation of EvaluateClientHello after the call to
+ // ProofSource::GetProof. |found_error| indicates whether an error was
+ // detected in EvaluateClientHello, and |get_proof_failed| indicates whether
+ // GetProof failed. If GetProof was not run, then |get_proof_failed| will be
+ // set to false.
+ void EvaluateClientHelloAfterGetProof(
+ bool found_error,
+ const IPAddress& server_ip,
+ QuicVersion version,
+ const uint8_t* primary_orbit,
+ scoped_refptr<Config> requested_config,
+ scoped_refptr<Config> primary_config,
+ QuicCryptoProof* crypto_proof,
+ std::unique_ptr<ProofSource::Details> proof_source_details,
+ bool get_proof_failed,
+ scoped_refptr<ValidateClientHelloResultCallback::Result>
+ client_hello_state,
+ std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const;
+
+ // Portion of ProcessClientHello which executes after GetProof.
+ void ProcessClientHelloAfterGetProof(
+ const ValidateClientHelloResultCallback::Result& validate_chlo_result,
+ bool reject_only,
+ QuicConnectionId connection_id,
+ const IPEndPoint& client_address,
+ QuicVersion version,
+ const QuicVersionVector& supported_versions,
+ bool use_stateless_rejects,
+ QuicConnectionId server_designated_connection_id,
+ const QuicClock* clock,
+ QuicRandom* rand,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ QuicCryptoNegotiatedParameters* params,
+ QuicCryptoProof* crypto_proof,
+ QuicByteCount total_framing_overhead,
+ QuicByteCount chlo_packet_size,
+ const scoped_refptr<Config>& requested_config,
+ const scoped_refptr<Config>& primary_config,
+ std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const;
+
+ // BuildRejection sets |out| to be a REJ message in reply to |client_hello|.
+ void BuildRejection(QuicVersion version,
+ QuicWallTime now,
+ const Config& config,
+ const CryptoHandshakeMessage& client_hello,
+ const ClientHelloInfo& info,
+ const CachedNetworkParameters& cached_network_params,
+ bool use_stateless_rejects,
+ QuicConnectionId server_designated_connection_id,
+ QuicRandom* rand,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ QuicCryptoNegotiatedParameters* params,
+ const QuicCryptoProof& crypto_proof,
+ QuicByteCount total_framing_overhead,
+ QuicByteCount chlo_packet_size,
+ CryptoHandshakeMessage* out) const;
+
+ // CompressChain compresses the certificates in |chain->certs| and returns a
+ // compressed representation. |common_sets| contains the common certificate
+ // sets known locally and |client_common_set_hashes| contains the hashes of
+ // the common sets known to the peer. |client_cached_cert_hashes| contains
+ // 64-bit, FNV-1a hashes of certificates that the peer already possesses.
+ static std::string CompressChain(
+ QuicCompressedCertsCache* compressed_certs_cache,
+ const scoped_refptr<ProofSource::Chain>& chain,
+ const std::string& client_common_set_hashes,
+ const std::string& client_cached_cert_hashes,
+ const CommonCertSets* common_sets);
+
+ // ParseConfigProtobuf parses the given config protobuf and returns a
+ // scoped_refptr<Config> if successful. The caller adopts the reference to the
+ // Config. On error, ParseConfigProtobuf returns nullptr.
+ scoped_refptr<Config> ParseConfigProtobuf(QuicServerConfigProtobuf* protobuf);
+
+ // NewSourceAddressToken returns a fresh source address token for the given
+ // IP address. |cached_network_params| is optional, and can be nullptr.
+ std::string NewSourceAddressToken(
+ const Config& config,
+ const SourceAddressTokens& previous_tokens,
+ const IPAddress& ip,
+ QuicRandom* rand,
+ QuicWallTime now,
+ const CachedNetworkParameters* cached_network_params) const;
+
+ // ParseSourceAddressToken parses the source address tokens contained in
+ // the encrypted |token|, and populates |tokens| with the parsed tokens.
+ // Returns HANDSHAKE_OK if |token| could be parsed, or the reason for the
+ // failure.
+ HandshakeFailureReason ParseSourceAddressToken(
+ const Config& config,
+ base::StringPiece token,
+ SourceAddressTokens* tokens) const;
+
+ // ValidateSourceAddressTokens returns HANDSHAKE_OK if the source address
+ // tokens in |tokens| contain a valid and timely token for the IP address
+ // |ip| given that the current time is |now|. Otherwise it returns the
+ // reason for failure. |cached_network_params| is populated if the valid
+ // token contains a CachedNetworkParameters proto.
+ HandshakeFailureReason ValidateSourceAddressTokens(
+ const SourceAddressTokens& tokens,
+ const IPAddress& ip,
+ QuicWallTime now,
+ CachedNetworkParameters* cached_network_params) const;
+
+ // ValidateSingleSourceAddressToken returns HANDSHAKE_OK if the source
+ // address token in |token| is a timely token for the IP address |ip|
+ // given that the current time is |now|. Otherwise it returns the reason
+ // for failure.
+ HandshakeFailureReason ValidateSingleSourceAddressToken(
+ const SourceAddressToken& token,
+ const IPAddress& ip,
+ QuicWallTime now) const;
+
+ // Returns HANDSHAKE_OK if the source address token in |token| is a timely
+ // token given that the current time is |now|. Otherwise it returns the
+ // reason for failure.
+ HandshakeFailureReason ValidateSourceAddressTokenTimestamp(
+ const SourceAddressToken& token,
+ QuicWallTime now) const;
+
+ // NewServerNonce generates and encrypts a random nonce.
+ std::string NewServerNonce(QuicRandom* rand, QuicWallTime now) const;
+
+ // ValidateServerNonce decrypts |token| and verifies that it hasn't been
+ // previously used and is recent enough that it is plausible that it was part
+ // of a very recently provided rejection ("recent" will be on the order of
+ // 10-30 seconds). If so, it records that it has been used and returns
+ // HANDSHAKE_OK. Otherwise it returns the reason for failure.
+ HandshakeFailureReason ValidateServerNonce(
+ base::StringPiece echoed_server_nonce,
+ QuicWallTime now) const;
+
+ // ValidateExpectedLeafCertificate checks the |client_hello| to see if it has
+ // an XLCT tag, and if so, verifies that its value matches the hash of the
+ // server's leaf certificate. The certs field of |crypto_proof| is used to
+ // compare against the XLCT value. This method returns true if the XLCT tag
+ // is not present, or if the XLCT tag is present and valid. It returns false
+ // otherwise.
+ bool ValidateExpectedLeafCertificate(
+ const CryptoHandshakeMessage& client_hello,
+ const QuicCryptoProof& crypto_proof) const;
+
+ // Returns true if the PDMD field from the client hello demands an X509
+ // certificate.
+ bool ClientDemandsX509Proof(const CryptoHandshakeMessage& client_hello) const;
+
+ // Callback to receive the results of ProofSource::GetProof. Note: this
+ // callback has no cancellation support, since the lifetime of the ProofSource
+ // is controlled by this object via unique ownership. If that ownership
+ // stricture changes, this decision may need to be revisited.
+ class BuildServerConfigUpdateMessageProofSourceCallback
+ : public ProofSource::Callback {
+ public:
+ BuildServerConfigUpdateMessageProofSourceCallback(
+ const BuildServerConfigUpdateMessageProofSourceCallback&) = delete;
+ ~BuildServerConfigUpdateMessageProofSourceCallback() override;
+ void operator=(const BuildServerConfigUpdateMessageProofSourceCallback&) =
+ delete;
+ BuildServerConfigUpdateMessageProofSourceCallback(
+ const QuicCryptoServerConfig* config,
+ QuicVersion version,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ const CommonCertSets* common_cert_sets,
+ const QuicCryptoNegotiatedParameters& params,
+ CryptoHandshakeMessage message,
+ std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb);
+
+ void Run(bool ok,
+ const scoped_refptr<ProofSource::Chain>& chain,
+ const std::string& signature,
+ const std::string& leaf_cert_sct,
+ std::unique_ptr<ProofSource::Details> details) override;
+
+ private:
+ const QuicCryptoServerConfig* config_;
+ const QuicVersion version_;
+ QuicCompressedCertsCache* compressed_certs_cache_;
+ const CommonCertSets* common_cert_sets_;
+ const std::string client_common_set_hashes_;
+ const std::string client_cached_cert_hashes_;
+ const bool sct_supported_by_client_;
+ CryptoHandshakeMessage message_;
+ std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb_;
+ };
+
+ // Invoked by BuildServerConfigUpdateMessageProofSourceCallback::Run once
+ // the proof has been acquired. Finishes building the server config update
+ // message and invokes |cb|.
+ void FinishBuildServerConfigUpdateMessage(
+ QuicVersion version,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ const CommonCertSets* common_cert_sets,
+ const std::string& client_common_set_hashes,
+ const std::string& client_cached_cert_hashes,
+ bool sct_supported_by_client,
+ bool ok,
+ const scoped_refptr<ProofSource::Chain>& chain,
+ const std::string& signature,
+ const std::string& leaf_cert_sct,
+ std::unique_ptr<ProofSource::Details> details,
+ CryptoHandshakeMessage message,
+ std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const;
+
+ // replay_protection_ controls whether the server enforces that handshakes
+ // aren't replays.
+ bool replay_protection_;
+
+ // The multiple of the CHLO message size that a REJ message must stay under
+ // when the client doesn't present a valid source-address token. This is
+ // used to protect QUIC from amplification attacks.
+ size_t chlo_multiplier_;
+
+ // configs_ satisfies the following invariants:
+ // 1) configs_.empty() <-> primary_config_ == nullptr
+ // 2) primary_config_ != nullptr -> primary_config_->is_primary
+ // 3) ∀ c∈configs_, c->is_primary <-> c == primary_config_
+ mutable base::Lock configs_lock_;
+ // configs_ contains all active server configs. It's expected that there are
+ // about half-a-dozen configs active at any one time.
+ ConfigMap configs_;
+ // primary_config_ points to a Config (which is also in |configs_|) which is
+ // the primary config - i.e. the one that we'll give out to new clients.
+ mutable scoped_refptr<Config> primary_config_;
+ // next_config_promotion_time_ contains the nearest, future time when an
+ // active config will be promoted to primary.
+ mutable QuicWallTime next_config_promotion_time_;
+ // Callback to invoke when the primary config changes.
+ std::unique_ptr<PrimaryConfigChangedCallback> primary_config_changed_cb_;
+
+ // Protects access to the pointer held by strike_register_client_.
+ mutable base::Lock strike_register_client_lock_;
+ // strike_register_ contains a data structure that keeps track of previously
+ // observed client nonces in order to prevent replay attacks.
+ mutable std::unique_ptr<StrikeRegisterClient> strike_register_client_;
+
+ // Used to protect the source-address tokens that are given to clients.
+ CryptoSecretBoxer source_address_token_boxer_;
+
+ // server_nonce_boxer_ is used to encrypt and validate suggested server
+ // nonces.
+ CryptoSecretBoxer server_nonce_boxer_;
+
+ // server_nonce_orbit_ contains the random, per-server orbit values that this
+ // server will use to generate server nonces (the moral equivalent of a SYN
+ // cookies).
+ uint8_t server_nonce_orbit_[8];
+
+ mutable base::Lock server_nonce_strike_register_lock_;
+ // server_nonce_strike_register_ contains a data structure that keeps track of
+ // previously observed server nonces from this server, in order to prevent
+ // replay attacks.
+ mutable std::unique_ptr<StrikeRegister> server_nonce_strike_register_;
+
+ // proof_source_ contains an object that can provide certificate chains and
+ // signatures.
+ std::unique_ptr<ProofSource> proof_source_;
+
+ // ephemeral_key_source_ contains an object that caches ephemeral keys for a
+ // short period of time.
+ std::unique_ptr<EphemeralKeySource> ephemeral_key_source_;
+
+ // These fields store configuration values. See the comments for their
+ // respective setter functions.
+ bool strike_register_no_startup_period_;
+ uint32_t strike_register_max_entries_;
+ uint32_t strike_register_window_secs_;
+ uint32_t source_address_token_future_secs_;
+ uint32_t source_address_token_lifetime_secs_;
+ uint32_t server_nonce_strike_register_max_entries_;
+ uint32_t server_nonce_strike_register_window_secs_;
+
+ // Enable serving SCT or not.
+ bool enable_serving_sct_;
+
+ // Does not own this observer.
+ RejectionObserver* rejection_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicCryptoServerConfig);
+};
+
+struct NET_EXPORT_PRIVATE QuicCryptoProof {
+ QuicCryptoProof();
+ ~QuicCryptoProof();
+
+ std::string signature;
+ scoped_refptr<ProofSource::Chain> chain;
+ std::string cert_sct;
+ // The server config that is used for this proof (and the rest of the
+ // request).
+ scoped_refptr<QuicCryptoServerConfig::Config> config;
+ std::string primary_scid;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_
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
new file mode 100644
index 00000000000..902adeca43d
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_crypto_server_config_test.cc
@@ -0,0 +1,549 @@
+// Copyright 2013 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/crypto/quic_crypto_server_config.h"
+
+#include <stdarg.h>
+
+#include <memory>
+
+#include "base/stl_util.h"
+#include "net/quic/core/crypto/aes_128_gcm_12_encrypter.h"
+#include "net/quic/core/crypto/cert_compressor.h"
+#include "net/quic/core/crypto/chacha20_poly1305_encrypter.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/crypto/crypto_secret_boxer.h"
+#include "net/quic/core/crypto/crypto_server_config_protobuf.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/crypto/strike_register_client.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_time.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/quic_crypto_server_config_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringPiece;
+using std::map;
+using std::pair;
+using std::string;
+using std::vector;
+
+namespace net {
+namespace test {
+
+class TestStrikeRegisterClient : public StrikeRegisterClient {
+ public:
+ explicit TestStrikeRegisterClient(QuicCryptoServerConfig* config)
+ : config_(config), is_known_orbit_called_(false) {}
+
+ bool IsKnownOrbit(StringPiece orbit) const override {
+ // Ensure that the strike register client lock is not held.
+ QuicCryptoServerConfigPeer peer(config_);
+ base::Lock* m = peer.GetStrikeRegisterClientLock();
+ // In Chromium, we will dead lock if the lock is held by the current thread.
+ // Chromium doesn't have AssertNotHeld API call.
+ // m->AssertNotHeld();
+ base::AutoLock lock(*m);
+
+ is_known_orbit_called_ = true;
+ return true;
+ }
+
+ void VerifyNonceIsValidAndUnique(StringPiece nonce,
+ QuicWallTime now,
+ ResultCallback* cb) override {
+ LOG(FATAL) << "Not implemented";
+ }
+
+ bool is_known_orbit_called() { return is_known_orbit_called_; }
+
+ private:
+ QuicCryptoServerConfig* config_;
+ mutable bool is_known_orbit_called_;
+};
+
+TEST(QuicCryptoServerConfigTest, ServerConfig) {
+ QuicRandom* rand = QuicRandom::GetInstance();
+ QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
+ CryptoTestUtils::ProofSourceForTesting());
+ MockClock clock;
+
+ std::unique_ptr<CryptoHandshakeMessage> message(server.AddDefaultConfig(
+ rand, &clock, QuicCryptoServerConfig::ConfigOptions()));
+
+ // The default configuration should have AES-GCM and at least one ChaCha20
+ // cipher.
+ const QuicTag* aead_tags;
+ size_t aead_len;
+ ASSERT_EQ(QUIC_NO_ERROR, message->GetTaglist(kAEAD, &aead_tags, &aead_len));
+ vector<QuicTag> aead(aead_tags, aead_tags + aead_len);
+ EXPECT_THAT(aead, ::testing::Contains(kAESG));
+ EXPECT_LE(1u, aead.size());
+}
+
+TEST(QuicCryptoServerConfigTest, GetOrbitIsCalledWithoutTheStrikeRegisterLock) {
+ QuicRandom* rand = QuicRandom::GetInstance();
+ QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
+ CryptoTestUtils::ProofSourceForTesting());
+ MockClock clock;
+
+ TestStrikeRegisterClient* strike_register =
+ new TestStrikeRegisterClient(&server);
+ server.SetStrikeRegisterClient(strike_register);
+
+ QuicCryptoServerConfig::ConfigOptions options;
+ std::unique_ptr<CryptoHandshakeMessage> message(
+ server.AddDefaultConfig(rand, &clock, options));
+ EXPECT_TRUE(strike_register->is_known_orbit_called());
+}
+
+TEST(QuicCryptoServerConfigTest, CompressCerts) {
+ QuicCompressedCertsCache compressed_certs_cache(
+ QuicCompressedCertsCache::kQuicCompressedCertsCacheSize);
+
+ QuicRandom* rand = QuicRandom::GetInstance();
+ QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
+ CryptoTestUtils::ProofSourceForTesting());
+ QuicCryptoServerConfigPeer peer(&server);
+
+ vector<string> certs = {"testcert"};
+ scoped_refptr<ProofSource::Chain> chain(new ProofSource::Chain(certs));
+
+ string compressed = QuicCryptoServerConfigPeer::CompressChain(
+ &compressed_certs_cache, chain, "", "", nullptr);
+
+ EXPECT_EQ(compressed_certs_cache.Size(), 1u);
+}
+
+TEST(QuicCryptoServerConfigTest, CompressSameCertsTwice) {
+ QuicCompressedCertsCache compressed_certs_cache(
+ QuicCompressedCertsCache::kQuicCompressedCertsCacheSize);
+
+ QuicRandom* rand = QuicRandom::GetInstance();
+ QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
+ CryptoTestUtils::ProofSourceForTesting());
+ QuicCryptoServerConfigPeer peer(&server);
+
+ // Compress the certs for the first time.
+ vector<string> certs = {"testcert"};
+ scoped_refptr<ProofSource::Chain> chain(new ProofSource::Chain(certs));
+ string common_certs = "";
+ string cached_certs = "";
+
+ string compressed = QuicCryptoServerConfigPeer::CompressChain(
+ &compressed_certs_cache, chain, common_certs, cached_certs, nullptr);
+ EXPECT_EQ(compressed_certs_cache.Size(), 1u);
+
+ // Compress the same certs, should use cache if available.
+ string compressed2 = QuicCryptoServerConfigPeer::CompressChain(
+ &compressed_certs_cache, chain, common_certs, cached_certs, nullptr);
+ EXPECT_EQ(compressed, compressed2);
+ EXPECT_EQ(compressed_certs_cache.Size(), 1u);
+}
+
+TEST(QuicCryptoServerConfigTest, CompressDifferentCerts) {
+ // This test compresses a set of similar but not identical certs. Cache if
+ // used should return cache miss and add all the compressed certs.
+ QuicCompressedCertsCache compressed_certs_cache(
+ QuicCompressedCertsCache::kQuicCompressedCertsCacheSize);
+
+ QuicRandom* rand = QuicRandom::GetInstance();
+ QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
+ CryptoTestUtils::ProofSourceForTesting());
+ QuicCryptoServerConfigPeer peer(&server);
+
+ vector<string> certs = {"testcert"};
+ scoped_refptr<ProofSource::Chain> chain(new ProofSource::Chain(certs));
+ string common_certs = "";
+ string cached_certs = "";
+
+ string compressed = QuicCryptoServerConfigPeer::CompressChain(
+ &compressed_certs_cache, chain, common_certs, cached_certs, nullptr);
+ EXPECT_EQ(compressed_certs_cache.Size(), 1u);
+
+ // Compress a similar certs which only differs in the chain.
+ scoped_refptr<ProofSource::Chain> chain2(new ProofSource::Chain(certs));
+
+ string compressed2 = QuicCryptoServerConfigPeer::CompressChain(
+ &compressed_certs_cache, chain2, common_certs, cached_certs, nullptr);
+ EXPECT_EQ(compressed_certs_cache.Size(), 2u);
+
+ // Compress a similar certs which only differs in common certs field.
+ static const uint64_t set_hash = 42;
+ std::unique_ptr<CommonCertSets> common_sets(
+ CryptoTestUtils::MockCommonCertSets(certs[0], set_hash, 1));
+ StringPiece different_common_certs(reinterpret_cast<const char*>(&set_hash),
+ sizeof(set_hash));
+ string compressed3 = QuicCryptoServerConfigPeer::CompressChain(
+ &compressed_certs_cache, chain, different_common_certs.as_string(),
+ cached_certs, common_sets.get());
+ EXPECT_EQ(compressed_certs_cache.Size(), 3u);
+}
+
+class SourceAddressTokenTest : public ::testing::Test {
+ public:
+ SourceAddressTokenTest()
+ : ip4_(Loopback4()),
+ ip4_dual_(ConvertIPv4ToIPv4MappedIPv6(ip4_)),
+ ip6_(Loopback6()),
+ original_time_(QuicWallTime::Zero()),
+ rand_(QuicRandom::GetInstance()),
+ server_(QuicCryptoServerConfig::TESTING,
+ rand_,
+ CryptoTestUtils::ProofSourceForTesting()),
+ peer_(&server_) {
+ // Advance the clock to some non-zero time.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000000));
+ original_time_ = clock_.WallNow();
+
+ primary_config_.reset(server_.AddDefaultConfig(
+ rand_, &clock_, QuicCryptoServerConfig::ConfigOptions()));
+ }
+
+ string NewSourceAddressToken(string config_id, const IPAddress& ip) {
+ return NewSourceAddressToken(config_id, ip, nullptr);
+ }
+
+ string NewSourceAddressToken(string config_id,
+ const IPAddress& ip,
+ const SourceAddressTokens& previous_tokens) {
+ return peer_.NewSourceAddressToken(config_id, previous_tokens, ip, rand_,
+ clock_.WallNow(), nullptr);
+ }
+
+ string NewSourceAddressToken(string config_id,
+ const IPAddress& ip,
+ CachedNetworkParameters* cached_network_params) {
+ SourceAddressTokens previous_tokens;
+ return peer_.NewSourceAddressToken(config_id, previous_tokens, ip, rand_,
+ clock_.WallNow(), cached_network_params);
+ }
+
+ HandshakeFailureReason ValidateSourceAddressTokens(string config_id,
+ StringPiece srct,
+ const IPAddress& ip) {
+ return ValidateSourceAddressTokens(config_id, srct, ip, nullptr);
+ }
+
+ HandshakeFailureReason ValidateSourceAddressTokens(
+ string config_id,
+ StringPiece srct,
+ const IPAddress& ip,
+ CachedNetworkParameters* cached_network_params) {
+ return peer_.ValidateSourceAddressTokens(
+ config_id, srct, ip, clock_.WallNow(), cached_network_params);
+ }
+
+ const string kPrimary = "<primary>";
+ const string kOverride = "Config with custom source address token key";
+
+ IPAddress ip4_;
+ IPAddress ip4_dual_;
+ IPAddress ip6_;
+
+ MockClock clock_;
+ QuicWallTime original_time_;
+ QuicRandom* rand_ = QuicRandom::GetInstance();
+ QuicCryptoServerConfig server_;
+ QuicCryptoServerConfigPeer peer_;
+ // Stores the primary config.
+ std::unique_ptr<CryptoHandshakeMessage> primary_config_;
+ std::unique_ptr<QuicServerConfigProtobuf> override_config_protobuf_;
+};
+
+// Test basic behavior of source address tokens including being specific
+// to a single IP address and server config.
+TEST_F(SourceAddressTokenTest, NewSourceAddressToken) {
+ // Primary config generates configs that validate successfully.
+ const string token4 = NewSourceAddressToken(kPrimary, ip4_);
+ const string token4d = NewSourceAddressToken(kPrimary, ip4_dual_);
+ const string token6 = NewSourceAddressToken(kPrimary, ip6_);
+ EXPECT_EQ(HANDSHAKE_OK, ValidateSourceAddressTokens(kPrimary, token4, ip4_));
+ ASSERT_EQ(HANDSHAKE_OK,
+ ValidateSourceAddressTokens(kPrimary, token4, ip4_dual_));
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
+ ValidateSourceAddressTokens(kPrimary, token4, ip6_));
+ ASSERT_EQ(HANDSHAKE_OK, ValidateSourceAddressTokens(kPrimary, token4d, ip4_));
+ ASSERT_EQ(HANDSHAKE_OK,
+ ValidateSourceAddressTokens(kPrimary, token4d, ip4_dual_));
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
+ ValidateSourceAddressTokens(kPrimary, token4d, ip6_));
+ ASSERT_EQ(HANDSHAKE_OK, ValidateSourceAddressTokens(kPrimary, token6, ip6_));
+}
+
+TEST_F(SourceAddressTokenTest, NewSourceAddressTokenExpiration) {
+ const string token = NewSourceAddressToken(kPrimary, ip4_);
+
+ // Validation fails if the token is from the future.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(-3600 * 2));
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE,
+ ValidateSourceAddressTokens(kPrimary, token, ip4_));
+
+ // Validation fails after tokens expire.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(86400 * 7));
+ ASSERT_EQ(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE,
+ ValidateSourceAddressTokens(kPrimary, token, ip4_));
+}
+
+TEST_F(SourceAddressTokenTest, NewSourceAddressTokenWithNetworkParams) {
+ // Make sure that if the source address token contains CachedNetworkParameters
+ // that this gets written to ValidateSourceAddressToken output argument.
+ CachedNetworkParameters cached_network_params_input;
+ cached_network_params_input.set_bandwidth_estimate_bytes_per_second(1234);
+ const string token4_with_cached_network_params =
+ NewSourceAddressToken(kPrimary, ip4_, &cached_network_params_input);
+
+ CachedNetworkParameters cached_network_params_output;
+ EXPECT_NE(cached_network_params_output.SerializeAsString(),
+ cached_network_params_input.SerializeAsString());
+ ValidateSourceAddressTokens(kPrimary, token4_with_cached_network_params, ip4_,
+ &cached_network_params_output);
+ EXPECT_EQ(cached_network_params_output.SerializeAsString(),
+ cached_network_params_input.SerializeAsString());
+}
+
+// Test the ability for a source address token to be valid for multiple
+// addresses.
+TEST_F(SourceAddressTokenTest, SourceAddressTokenMultipleAddresses) {
+ QuicWallTime now = clock_.WallNow();
+
+ // Now create a token which is usable for both addresses.
+ SourceAddressToken previous_token;
+ IPAddress ip_address = ip6_;
+ if (ip6_.IsIPv4()) {
+ ip_address = ConvertIPv4ToIPv4MappedIPv6(ip_address);
+ }
+ previous_token.set_ip(IPAddressToPackedString(ip_address));
+ previous_token.set_timestamp(now.ToUNIXSeconds());
+ SourceAddressTokens previous_tokens;
+ (*previous_tokens.add_tokens()) = previous_token;
+ const string token4or6 =
+ NewSourceAddressToken(kPrimary, ip4_, previous_tokens);
+
+ EXPECT_EQ(HANDSHAKE_OK,
+ ValidateSourceAddressTokens(kPrimary, token4or6, ip4_));
+ ASSERT_EQ(HANDSHAKE_OK,
+ ValidateSourceAddressTokens(kPrimary, token4or6, ip6_));
+}
+
+TEST(QuicCryptoServerConfigTest, ValidateServerNonce) {
+ QuicRandom* rand = QuicRandom::GetInstance();
+ QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
+ CryptoTestUtils::ProofSourceForTesting());
+ QuicCryptoServerConfigPeer peer(&server);
+
+ StringPiece message("hello world");
+ const size_t key_size = CryptoSecretBoxer::GetKeySize();
+ std::unique_ptr<uint8_t[]> key(new uint8_t[key_size]);
+ memset(key.get(), 0x11, key_size);
+
+ CryptoSecretBoxer boxer;
+ boxer.SetKeys({string(reinterpret_cast<char*>(key.get()), key_size)});
+ const string box = boxer.Box(rand, message);
+ MockClock clock;
+ QuicWallTime now = clock.WallNow();
+ const QuicWallTime original_time = now;
+ EXPECT_EQ(SERVER_NONCE_DECRYPTION_FAILURE,
+ peer.ValidateServerNonce(box, now));
+
+ string server_nonce = peer.NewServerNonce(rand, now);
+ EXPECT_EQ(HANDSHAKE_OK, peer.ValidateServerNonce(server_nonce, now));
+ EXPECT_EQ(SERVER_NONCE_NOT_UNIQUE_FAILURE,
+ peer.ValidateServerNonce(server_nonce, now));
+
+ now = original_time.Add(QuicTime::Delta::FromSeconds(1000 * 7));
+ server_nonce = peer.NewServerNonce(rand, now);
+ EXPECT_EQ(HANDSHAKE_OK, peer.ValidateServerNonce(server_nonce, now));
+}
+
+class CryptoServerConfigsTest : public ::testing::Test {
+ public:
+ CryptoServerConfigsTest()
+ : rand_(QuicRandom::GetInstance()),
+ config_(QuicCryptoServerConfig::TESTING,
+ rand_,
+ CryptoTestUtils::ProofSourceForTesting()),
+ test_peer_(&config_) {}
+
+ void SetUp() override {
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000));
+ }
+
+ // SetConfigs constructs suitable config protobufs and calls SetConfigs on
+ // |config_|. The arguments are given as nullptr-terminated pairs. The first
+ // of each pair is the server config ID of a Config. The second is the
+ // |primary_time| of that Config, given in epoch seconds. (Although note that,
+ // in these tests, time is set to 1000 seconds since the epoch.) For example:
+ // SetConfigs(nullptr); // calls |config_.SetConfigs| with no protobufs.
+ //
+ // // Calls |config_.SetConfigs| with two protobufs: one for a Config with
+ // // a |primary_time| of 900 and priority 1, and another with
+ // // a |primary_time| of 1000 and priority 2.
+
+ // CheckConfigs(
+ // "id1", 900, 1,
+ // "id2", 1000, 2,
+ // nullptr);
+ //
+ // If the server config id starts with "INVALID" then the generated protobuf
+ // will be invalid.
+ void SetConfigs(const char* server_config_id1, ...) {
+ const char kOrbit[] = "12345678";
+
+ va_list ap;
+ va_start(ap, server_config_id1);
+ bool has_invalid = false;
+ bool is_empty = true;
+
+ vector<QuicServerConfigProtobuf*> protobufs;
+ bool first = true;
+ for (;;) {
+ const char* server_config_id;
+ if (first) {
+ server_config_id = server_config_id1;
+ first = false;
+ } else {
+ server_config_id = va_arg(ap, const char*);
+ }
+
+ if (!server_config_id) {
+ break;
+ }
+
+ is_empty = false;
+ int primary_time = va_arg(ap, int);
+ int priority = va_arg(ap, int);
+
+ QuicCryptoServerConfig::ConfigOptions options;
+ options.id = server_config_id;
+ options.orbit = kOrbit;
+ QuicServerConfigProtobuf* protobuf(
+ QuicCryptoServerConfig::GenerateConfig(rand_, &clock_, options));
+ protobuf->set_primary_time(primary_time);
+ protobuf->set_priority(priority);
+ if (string(server_config_id).find("INVALID") == 0) {
+ protobuf->clear_key();
+ has_invalid = true;
+ }
+ protobufs.push_back(protobuf);
+ }
+
+ ASSERT_EQ(!has_invalid && !is_empty,
+ config_.SetConfigs(protobufs, clock_.WallNow()));
+ base::STLDeleteElements(&protobufs);
+ }
+
+ protected:
+ QuicRandom* const rand_;
+ MockClock clock_;
+ QuicCryptoServerConfig config_;
+ QuicCryptoServerConfigPeer test_peer_;
+};
+
+TEST_F(CryptoServerConfigsTest, NoConfigs) {
+ test_peer_.CheckConfigs(nullptr);
+}
+
+TEST_F(CryptoServerConfigsTest, MakePrimaryFirst) {
+ // Make sure that "b" is primary even though "a" comes first.
+ SetConfigs("a", 1100, 1, "b", 900, 1, nullptr);
+ test_peer_.CheckConfigs("a", false, "b", true, nullptr);
+}
+
+TEST_F(CryptoServerConfigsTest, MakePrimarySecond) {
+ // Make sure that a remains primary after b is added.
+ SetConfigs("a", 900, 1, "b", 1100, 1, nullptr);
+ test_peer_.CheckConfigs("a", true, "b", false, nullptr);
+}
+
+TEST_F(CryptoServerConfigsTest, Delete) {
+ // Ensure that configs get deleted when removed.
+ SetConfigs("a", 800, 1, "b", 900, 1, "c", 1100, 1, nullptr);
+ test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr);
+ SetConfigs("b", 900, 1, "c", 1100, 1, nullptr);
+ test_peer_.CheckConfigs("b", true, "c", false, nullptr);
+}
+
+TEST_F(CryptoServerConfigsTest, DeletePrimary) {
+ // Ensure that deleting the primary config works.
+ SetConfigs("a", 800, 1, "b", 900, 1, "c", 1100, 1, nullptr);
+ test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr);
+ SetConfigs("a", 800, 1, "c", 1100, 1, nullptr);
+ test_peer_.CheckConfigs("a", true, "c", false, nullptr);
+}
+
+TEST_F(CryptoServerConfigsTest, FailIfDeletingAllConfigs) {
+ // Ensure that configs get deleted when removed.
+ SetConfigs("a", 800, 1, "b", 900, 1, nullptr);
+ test_peer_.CheckConfigs("a", false, "b", true, nullptr);
+ SetConfigs(nullptr);
+ // Config change is rejected, still using old configs.
+ test_peer_.CheckConfigs("a", false, "b", true, nullptr);
+}
+
+TEST_F(CryptoServerConfigsTest, ChangePrimaryTime) {
+ // Check that updates to primary time get picked up.
+ SetConfigs("a", 400, 1, "b", 800, 1, "c", 1200, 1, nullptr);
+ test_peer_.SelectNewPrimaryConfig(500);
+ test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr);
+ SetConfigs("a", 1200, 1, "b", 800, 1, "c", 400, 1, nullptr);
+ test_peer_.SelectNewPrimaryConfig(500);
+ test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr);
+}
+
+TEST_F(CryptoServerConfigsTest, AllConfigsInThePast) {
+ // Check that the most recent config is selected.
+ SetConfigs("a", 400, 1, "b", 800, 1, "c", 1200, 1, nullptr);
+ test_peer_.SelectNewPrimaryConfig(1500);
+ test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr);
+}
+
+TEST_F(CryptoServerConfigsTest, AllConfigsInTheFuture) {
+ // Check that the first config is selected.
+ SetConfigs("a", 400, 1, "b", 800, 1, "c", 1200, 1, nullptr);
+ test_peer_.SelectNewPrimaryConfig(100);
+ test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr);
+}
+
+TEST_F(CryptoServerConfigsTest, SortByPriority) {
+ // Check that priority is used to decide on a primary config when
+ // configs have the same primary time.
+ SetConfigs("a", 900, 1, "b", 900, 2, "c", 900, 3, nullptr);
+ test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr);
+ test_peer_.SelectNewPrimaryConfig(800);
+ test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr);
+ test_peer_.SelectNewPrimaryConfig(1000);
+ test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr);
+
+ // Change priorities and expect sort order to change.
+ SetConfigs("a", 900, 2, "b", 900, 1, "c", 900, 0, nullptr);
+ test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr);
+ test_peer_.SelectNewPrimaryConfig(800);
+ test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr);
+ test_peer_.SelectNewPrimaryConfig(1000);
+ test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr);
+}
+
+TEST_F(CryptoServerConfigsTest, AdvancePrimary) {
+ // Check that a new primary config is enabled at the right time.
+ SetConfigs("a", 900, 1, "b", 1100, 1, nullptr);
+ test_peer_.SelectNewPrimaryConfig(1000);
+ test_peer_.CheckConfigs("a", true, "b", false, nullptr);
+ test_peer_.SelectNewPrimaryConfig(1101);
+ test_peer_.CheckConfigs("a", false, "b", true, nullptr);
+}
+
+TEST_F(CryptoServerConfigsTest, InvalidConfigs) {
+ // Ensure that invalid configs don't change anything.
+ SetConfigs("a", 800, 1, "b", 900, 1, "c", 1100, 1, nullptr);
+ test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr);
+ SetConfigs("a", 800, 1, "c", 1100, 1, "INVALID1", 1000, 1, nullptr);
+ test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr);
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/quic_decrypter.cc b/chromium/net/quic/core/crypto/quic_decrypter.cc
new file mode 100644
index 00000000000..5d8f3d32945
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_decrypter.cc
@@ -0,0 +1,49 @@
+// 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/crypto/quic_decrypter.h"
+
+#include "crypto/hkdf.h"
+#include "net/quic/core/crypto/aes_128_gcm_12_decrypter.h"
+#include "net/quic/core/crypto/chacha20_poly1305_decrypter.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/null_decrypter.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+// static
+QuicDecrypter* QuicDecrypter::Create(QuicTag algorithm) {
+ switch (algorithm) {
+ case kAESG:
+ return new Aes128Gcm12Decrypter();
+ case kCC20:
+ return new ChaCha20Poly1305Decrypter();
+ case kNULL:
+ return new NullDecrypter();
+ default:
+ LOG(FATAL) << "Unsupported algorithm: " << algorithm;
+ return nullptr;
+ }
+}
+
+// static
+void QuicDecrypter::DiversifyPreliminaryKey(StringPiece preliminary_key,
+ StringPiece nonce_prefix,
+ const DiversificationNonce& nonce,
+ size_t key_size,
+ size_t nonce_prefix_size,
+ string* out_key,
+ string* out_nonce_prefix) {
+ crypto::HKDF hkdf(preliminary_key.as_string() + nonce_prefix.as_string(),
+ StringPiece(nonce.data(), nonce.size()),
+ "QUIC key diversification", 0, key_size, 0,
+ nonce_prefix_size, 0);
+ *out_key = hkdf.server_write_key().as_string();
+ *out_nonce_prefix = hkdf.server_write_iv().as_string();
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/quic_decrypter.h b/chromium/net/quic/core/crypto/quic_decrypter.h
new file mode 100644
index 00000000000..0a5eea3d388
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_decrypter.h
@@ -0,0 +1,98 @@
+// 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.
+
+#ifndef NET_QUIC_CRYPTO_QUIC_DECRYPTER_H_
+#define NET_QUIC_CRYPTO_QUIC_DECRYPTER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE QuicDecrypter {
+ public:
+ virtual ~QuicDecrypter() {}
+
+ static QuicDecrypter* Create(QuicTag algorithm);
+
+ // Sets the encryption key. Returns true on success, false on failure.
+ //
+ // NOTE: The key is the client_write_key or server_write_key derived from
+ // the master secret.
+ virtual bool SetKey(base::StringPiece key) = 0;
+
+ // Sets the fixed initial bytes of the nonce. Returns true on success,
+ // false on failure.
+ //
+ // NOTE: The nonce prefix is the client_write_iv or server_write_iv
+ // derived from the master secret. A 64-bit packet number will
+ // be appended to form the nonce.
+ //
+ // <------------ 64 bits ----------->
+ // +---------------------+----------------------------------+
+ // | Fixed prefix | packet number |
+ // +---------------------+----------------------------------+
+ // Nonce format
+ //
+ // The security of the nonce format requires that QUIC never reuse a
+ // packet number, even when retransmitting a lost packet.
+ virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) = 0;
+
+ // Sets the encryption key. Returns true on success, false on failure.
+ // |DecryptPacket| may not be called until |SetDiversificationNonce| is
+ // called and the preliminary keying material will be combined with that
+ // nonce in order to create the actual key and nonce-prefix.
+ //
+ // If this function is called, neither |SetKey| nor |SetNoncePrefix| may be
+ // called.
+ virtual bool SetPreliminaryKey(base::StringPiece key) = 0;
+
+ // SetDiversificationNonce uses |nonce| to derive final keys based on the
+ // input keying material given by calling |SetPreliminaryKey|.
+ //
+ // Calling this function is a no-op if |SetPreliminaryKey| hasn't been
+ // called.
+ virtual bool SetDiversificationNonce(const DiversificationNonce& nonce) = 0;
+
+ // Populates |output| with the decrypted |ciphertext| and populates
+ // |output_length| with the length. Returns 0 if there is an error.
+ // |output| size is specified by |max_output_length| and must be
+ // at least as large as the ciphertext. |packet_number| is
+ // appended to the |nonce_prefix| value provided in SetNoncePrefix()
+ // to form the nonce.
+ // TODO(wtc): add a way for DecryptPacket to report decryption failure due
+ // to non-authentic inputs, as opposed to other reasons for failure.
+ virtual bool DecryptPacket(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ base::StringPiece associated_data,
+ base::StringPiece ciphertext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) = 0;
+
+ // The name of the cipher.
+ virtual const char* cipher_name() const = 0;
+ // The ID of the cipher. Return 0x03000000 ORed with the 'cryptographic suite
+ // selector'.
+ virtual uint32_t cipher_id() const = 0;
+
+ // For use by unit tests only.
+ virtual base::StringPiece GetKey() const = 0;
+ virtual base::StringPiece GetNoncePrefix() const = 0;
+
+ static void DiversifyPreliminaryKey(base::StringPiece preliminary_key,
+ base::StringPiece nonce_prefix,
+ const DiversificationNonce& nonce,
+ size_t key_size,
+ size_t nonce_prefix_size,
+ std::string* out_key,
+ std::string* out_nonce_prefix);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_QUIC_DECRYPTER_H_
diff --git a/chromium/net/quic/core/crypto/quic_encrypter.cc b/chromium/net/quic/core/crypto/quic_encrypter.cc
new file mode 100644
index 00000000000..2c19078d2a9
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_encrypter.cc
@@ -0,0 +1,29 @@
+// 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/crypto/quic_encrypter.h"
+
+#include "net/quic/core/crypto/aes_128_gcm_12_encrypter.h"
+#include "net/quic/core/crypto/chacha20_poly1305_encrypter.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/null_encrypter.h"
+
+namespace net {
+
+// static
+QuicEncrypter* QuicEncrypter::Create(QuicTag algorithm) {
+ switch (algorithm) {
+ case kAESG:
+ return new Aes128Gcm12Encrypter();
+ case kCC20:
+ return new ChaCha20Poly1305Encrypter();
+ case kNULL:
+ return new NullEncrypter();
+ default:
+ LOG(FATAL) << "Unsupported algorithm: " << algorithm;
+ return nullptr;
+ }
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/quic_encrypter.h b/chromium/net/quic/core/crypto/quic_encrypter.h
new file mode 100644
index 00000000000..fefd7773edb
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_encrypter.h
@@ -0,0 +1,85 @@
+// 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.
+
+#ifndef NET_QUIC_CRYPTO_QUIC_ENCRYPTER_H_
+#define NET_QUIC_CRYPTO_QUIC_ENCRYPTER_H_
+
+#include <stddef.h>
+
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE QuicEncrypter {
+ public:
+ virtual ~QuicEncrypter() {}
+
+ static QuicEncrypter* Create(QuicTag algorithm);
+
+ // Sets the encryption key. Returns true on success, false on failure.
+ //
+ // NOTE: The key is the client_write_key or server_write_key derived from
+ // the master secret.
+ virtual bool SetKey(base::StringPiece key) = 0;
+
+ // Sets the fixed initial bytes of the nonce. Returns true on success,
+ // false on failure.
+ //
+ // NOTE: The nonce prefix is the client_write_iv or server_write_iv
+ // derived from the master secret. A 64-bit packet number will
+ // be appended to form the nonce.
+ //
+ // <------------ 64 bits ----------->
+ // +---------------------+----------------------------------+
+ // | Fixed prefix | packet number |
+ // +---------------------+----------------------------------+
+ // Nonce format
+ //
+ // The security of the nonce format requires that QUIC never reuse a
+ // packet number, even when retransmitting a lost packet.
+ virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) = 0;
+
+ // Writes encrypted |plaintext| and a MAC over |plaintext| and
+ // |associated_data| into output. Sets |output_length| to the number of
+ // bytes written. Returns true on success or false if there was an error.
+ // |packet_number| is appended to the |nonce_prefix| value provided in
+ // SetNoncePrefix() to form the nonce. |output| must not overlap with
+ // |associated_data|. If |output| overlaps with |plaintext| then
+ // |plaintext| must be <= |output|.
+ virtual bool EncryptPacket(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ base::StringPiece associated_data,
+ base::StringPiece plaintext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) = 0;
+
+ // GetKeySize() and GetNoncePrefixSize() tell the HKDF class how many bytes
+ // of key material needs to be derived from the master secret.
+ // NOTE: the sizes returned by GetKeySize() and GetNoncePrefixSize() are
+ // also correct for the QuicDecrypter of the same algorithm. So only
+ // QuicEncrypter has these two methods.
+
+ // Returns the size in bytes of a key for the algorithm.
+ virtual size_t GetKeySize() const = 0;
+ // Returns the size in bytes of the fixed initial part of the nonce.
+ virtual size_t GetNoncePrefixSize() 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;
+
+ // Returns the length of the ciphertext that would be generated by encrypting
+ // to plaintext of size |plaintext_size|.
+ virtual size_t GetCiphertextSize(size_t plaintext_size) const = 0;
+
+ // For use by unit tests only.
+ virtual base::StringPiece GetKey() const = 0;
+ virtual base::StringPiece GetNoncePrefix() const = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_QUIC_ENCRYPTER_H_
diff --git a/chromium/net/quic/core/crypto/quic_random.cc b/chromium/net/quic/core/crypto/quic_random.cc
new file mode 100644
index 00000000000..35d1bdd326c
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_random.cc
@@ -0,0 +1,59 @@
+// 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/crypto/quic_random.h"
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/singleton.h"
+#include "crypto/random.h"
+#include "net/quic/core/quic_bug_tracker.h"
+
+namespace net {
+
+namespace {
+
+class DefaultRandom : public QuicRandom {
+ public:
+ static DefaultRandom* GetInstance();
+
+ // QuicRandom implementation
+ void RandBytes(void* data, size_t len) override;
+ uint64_t RandUint64() override;
+ void Reseed(const void* additional_entropy, size_t entropy_len) override;
+
+ private:
+ DefaultRandom() {}
+ ~DefaultRandom() override {}
+
+ friend struct base::DefaultSingletonTraits<DefaultRandom>;
+ DISALLOW_COPY_AND_ASSIGN(DefaultRandom);
+};
+
+DefaultRandom* DefaultRandom::GetInstance() {
+ return base::Singleton<DefaultRandom>::get();
+}
+
+void DefaultRandom::RandBytes(void* data, size_t len) {
+ crypto::RandBytes(data, len);
+}
+
+uint64_t DefaultRandom::RandUint64() {
+ uint64_t value;
+ RandBytes(&value, sizeof(value));
+ return value;
+}
+
+void DefaultRandom::Reseed(const void* additional_entropy, size_t entropy_len) {
+ // No such function exists in crypto/random.h.
+}
+
+} // namespace
+
+// static
+QuicRandom* QuicRandom::GetInstance() {
+ return DefaultRandom::GetInstance();
+}
+
+} // namespace net
diff --git a/chromium/net/quic/crypto/quic_random.h b/chromium/net/quic/core/crypto/quic_random.h
index e723241bd4f..e723241bd4f 100644
--- a/chromium/net/quic/crypto/quic_random.h
+++ b/chromium/net/quic/core/crypto/quic_random.h
diff --git a/chromium/net/quic/core/crypto/quic_random_test.cc b/chromium/net/quic/core/crypto/quic_random_test.cc
new file mode 100644
index 00000000000..d4f8a7bbd9b
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_random_test.cc
@@ -0,0 +1,40 @@
+// 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/crypto/quic_random.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+TEST(QuicRandomTest, RandBytes) {
+ unsigned char buf1[16];
+ unsigned char buf2[16];
+ memset(buf1, 0xaf, sizeof(buf1));
+ memset(buf2, 0xaf, sizeof(buf2));
+ ASSERT_EQ(0, memcmp(buf1, buf2, sizeof(buf1)));
+
+ QuicRandom* rng = QuicRandom::GetInstance();
+ rng->RandBytes(buf1, sizeof(buf1));
+ EXPECT_NE(0, memcmp(buf1, buf2, sizeof(buf1)));
+}
+
+TEST(QuicRandomTest, RandUint64) {
+ QuicRandom* rng = QuicRandom::GetInstance();
+ uint64_t value1 = rng->RandUint64();
+ uint64_t value2 = rng->RandUint64();
+ EXPECT_NE(value1, value2);
+}
+
+TEST(QuicRandomTest, Reseed) {
+ char buf[1024];
+ memset(buf, 0xaf, sizeof(buf));
+
+ QuicRandom* rng = QuicRandom::GetInstance();
+ rng->Reseed(buf, sizeof(buf));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/quic_server_info.cc b/chromium/net/quic/core/crypto/quic_server_info.cc
new file mode 100644
index 00000000000..cb3a66fd34c
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_server_info.cc
@@ -0,0 +1,163 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/crypto/quic_server_info.h"
+
+#include <limits>
+
+#include "base/pickle.h"
+
+using std::string;
+
+namespace {
+
+// TODO(rtenneti): Delete kQuicCryptoConfigVersionNoChloHash after
+// QUIC_VERSION_31 becomes the default.
+const int kQuicCryptoConfigVersionNoChloHash = 1;
+const int kQuicCryptoConfigVersion = 2;
+
+} // namespace
+
+namespace net {
+
+QuicServerInfo::State::State() {}
+
+QuicServerInfo::State::~State() {}
+
+void QuicServerInfo::State::Clear() {
+ server_config.clear();
+ source_address_token.clear();
+ cert_sct.clear();
+ chlo_hash.clear();
+ server_config_sig.clear();
+ certs.clear();
+}
+
+QuicServerInfo::QuicServerInfo(const QuicServerId& server_id)
+ : server_id_(server_id) {}
+
+QuicServerInfo::~QuicServerInfo() {}
+
+const QuicServerInfo::State& QuicServerInfo::state() const {
+ return state_;
+}
+
+QuicServerInfo::State* QuicServerInfo::mutable_state() {
+ return &state_;
+}
+
+bool QuicServerInfo::Parse(const string& data) {
+ State* state = mutable_state();
+
+ state->Clear();
+
+ bool r = ParseInner(data);
+ if (!r)
+ state->Clear();
+ return r;
+}
+
+bool QuicServerInfo::ParseInner(const string& data) {
+ State* state = mutable_state();
+
+ // No data was read from the disk cache.
+ if (data.empty()) {
+ return false;
+ }
+
+ base::Pickle p(data.data(), data.size());
+ base::PickleIterator iter(p);
+
+ int version = -1;
+ if (!iter.ReadInt(&version)) {
+ DVLOG(1) << "Missing version";
+ return false;
+ }
+
+ // TODO(rtenneti): Delete kQuicCryptoConfigVersionNoChloHash after
+ // QUIC_VERSION_31 becomes the default.
+ if (!(version == kQuicCryptoConfigVersionNoChloHash ||
+ version == kQuicCryptoConfigVersion)) {
+ DVLOG(1) << "Unsupported version";
+ return false;
+ }
+
+ if (!iter.ReadString(&state->server_config)) {
+ DVLOG(1) << "Malformed server_config";
+ return false;
+ }
+ if (!iter.ReadString(&state->source_address_token)) {
+ DVLOG(1) << "Malformed source_address_token";
+ return false;
+ }
+ // TODO(rtenneti): Delete kQuicCryptoConfigVersionNoChloHash after
+ // QUIC_VERSION_31 becomes the default.
+ if (version == kQuicCryptoConfigVersionNoChloHash) {
+ state->cert_sct.clear();
+ state->chlo_hash.clear();
+ } else {
+ if (!iter.ReadString(&state->cert_sct)) {
+ DVLOG(1) << "Malformed cert_sct";
+ return false;
+ }
+ if (!iter.ReadString(&state->chlo_hash)) {
+ DVLOG(1) << "Malformed chlo_hash";
+ return false;
+ }
+ }
+ if (!iter.ReadString(&state->server_config_sig)) {
+ DVLOG(1) << "Malformed server_config_sig";
+ return false;
+ }
+
+ // Read certs.
+ uint32_t num_certs;
+ if (!iter.ReadUInt32(&num_certs)) {
+ DVLOG(1) << "Malformed num_certs";
+ return false;
+ }
+
+ for (uint32_t i = 0; i < num_certs; i++) {
+ string cert;
+ if (!iter.ReadString(&cert)) {
+ DVLOG(1) << "Malformed cert";
+ return false;
+ }
+ state->certs.push_back(cert);
+ }
+
+ return true;
+}
+
+string QuicServerInfo::Serialize() {
+ string pickled_data = SerializeInner();
+ state_.Clear();
+ return pickled_data;
+}
+
+string QuicServerInfo::SerializeInner() const {
+ base::Pickle p(sizeof(base::Pickle::Header));
+
+ if (!p.WriteInt(kQuicCryptoConfigVersion) ||
+ !p.WriteString(state_.server_config) ||
+ !p.WriteString(state_.source_address_token) ||
+ !p.WriteString(state_.cert_sct) || !p.WriteString(state_.chlo_hash) ||
+ !p.WriteString(state_.server_config_sig) ||
+ state_.certs.size() > std::numeric_limits<uint32_t>::max() ||
+ !p.WriteUInt32(state_.certs.size())) {
+ return string();
+ }
+
+ for (size_t i = 0; i < state_.certs.size(); i++) {
+ if (!p.WriteString(state_.certs[i])) {
+ return string();
+ }
+ }
+
+ return string(reinterpret_cast<const char*>(p.data()), p.size());
+}
+
+QuicServerInfoFactory::~QuicServerInfoFactory() {}
+
+} // namespace net
diff --git a/chromium/net/quic/core/crypto/quic_server_info.h b/chromium/net/quic/core/crypto/quic_server_info.h
new file mode 100644
index 00000000000..12c807ee37f
--- /dev/null
+++ b/chromium/net/quic/core/crypto/quic_server_info.h
@@ -0,0 +1,181 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CRYPTO_QUIC_SERVER_INFO_H_
+#define NET_QUIC_CRYPTO_QUIC_SERVER_INFO_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_server_id.h"
+
+namespace net {
+
+class X509Certificate;
+
+// QuicServerInfo is an interface for fetching information about a QUIC server.
+// This information may be stored on disk so does not include keys or other
+// sensitive information. Primarily it's intended for caching the QUIC server's
+// crypto config.
+class NET_EXPORT_PRIVATE QuicServerInfo {
+ public:
+ // Enum to track number of times data read/parse/write API calls of
+ // QuicServerInfo to and from disk cache is called.
+ enum QuicServerInfoAPICall {
+ QUIC_SERVER_INFO_START = 0,
+ QUIC_SERVER_INFO_WAIT_FOR_DATA_READY = 1,
+ QUIC_SERVER_INFO_PARSE = 2,
+ QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL = 3,
+ QUIC_SERVER_INFO_READY_TO_PERSIST = 4,
+ QUIC_SERVER_INFO_PERSIST = 5,
+ QUIC_SERVER_INFO_EXTERNAL_CACHE_HIT = 6,
+ QUIC_SERVER_INFO_RESET_WAIT_FOR_DATA_READY = 7,
+ QUIC_SERVER_INFO_NUM_OF_API_CALLS = 8,
+ };
+
+ // Enum to track failure reasons to read/load/write of QuicServerInfo to
+ // and from disk cache.
+ enum FailureReason {
+ WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE = 0,
+ GET_BACKEND_FAILURE = 1,
+ OPEN_FAILURE = 2,
+ CREATE_OR_OPEN_FAILURE = 3,
+ PARSE_NO_DATA_FAILURE = 4,
+ PARSE_FAILURE = 5,
+ READ_FAILURE = 6,
+ READY_TO_PERSIST_FAILURE = 7,
+ PERSIST_NO_BACKEND_FAILURE = 8,
+ WRITE_FAILURE = 9,
+ NO_FAILURE = 10,
+ PARSE_DATA_DECODE_FAILURE = 11,
+ NUM_OF_FAILURES = 12,
+ };
+
+ explicit QuicServerInfo(const QuicServerId& server_id);
+ virtual ~QuicServerInfo();
+
+ // Start will commence the lookup. This must be called before any other
+ // methods. By opportunistically calling this early, it may be possible to
+ // overlap this object's lookup and reduce latency.
+ virtual void Start() = 0;
+
+ // WaitForDataReady returns OK if the fetch of the requested data has
+ // completed. Otherwise it returns ERR_IO_PENDING and will call |callback| on
+ // the current thread when ready.
+ //
+ // Only a single callback can be outstanding at a given time and, in the
+ // event that WaitForDataReady returns OK, it's the caller's responsibility
+ // to delete |callback|.
+ //
+ // |callback| may be NULL, in which case ERR_IO_PENDING may still be returned
+ // but, obviously, a callback will never be made.
+ virtual int WaitForDataReady(const CompletionCallback& callback) = 0;
+
+ // Reset's WaitForDataReady callback. This method shouldn't have any side
+ // effects (could be called even if HttpCache doesn't exist).
+ virtual void ResetWaitForDataReadyCallback() = 0;
+
+ // Cancel's WaitForDataReady callback. |callback| passed in WaitForDataReady
+ // will not be called.
+ virtual void CancelWaitForDataReadyCallback() = 0;
+
+ // Returns true if data is loaded from disk cache and ready (WaitForDataReady
+ // doesn't have a pending callback).
+ virtual bool IsDataReady() = 0;
+
+ // Returns true if the object is ready to persist data, in other words, if
+ // data is loaded from disk cache and ready and there are no pending writes.
+ virtual bool IsReadyToPersist() = 0;
+
+ // Persist allows for the server information to be updated for future users.
+ // This is a fire and forget operation: the caller may drop its reference
+ // from this object and the store operation will still complete. This can
+ // only be called once WaitForDataReady has returned OK or called its
+ // callback.
+ virtual void Persist() = 0;
+
+ // Called whenever an external cache reuses quic server config.
+ virtual void OnExternalCacheHit() = 0;
+
+ struct State {
+ State();
+ ~State();
+
+ void Clear();
+
+ // This class matches QuicClientCryptoConfig::CachedState.
+ std::string server_config; // A serialized handshake message.
+ std::string source_address_token; // An opaque proof of IP ownership.
+ std::string cert_sct; // Signed timestamp of the leaf cert.
+ std::string chlo_hash; // Hash of the CHLO message.
+ std::vector<std::string> certs; // A list of certificates in leaf-first
+ // order.
+ std::string server_config_sig; // A signature of |server_config_|.
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(State);
+ };
+
+ // Once the data is ready, it can be read using the following members. These
+ // members can then be updated before calling |Persist|.
+ const State& state() const;
+ State* mutable_state();
+
+ base::TimeTicks wait_for_data_start_time() const {
+ return wait_for_data_start_time_;
+ }
+
+ base::TimeTicks wait_for_data_end_time() const {
+ return wait_for_data_end_time_;
+ }
+
+ protected:
+ // Parse parses pickled data and fills out the public member fields of this
+ // object. It returns true iff the parse was successful. The public member
+ // fields will be set to something sane in any case.
+ bool Parse(const std::string& data);
+ std::string Serialize();
+
+ State state_;
+
+ // Time when WaitForDataReady was called and when it has finished.
+ base::TimeTicks wait_for_data_start_time_;
+ base::TimeTicks wait_for_data_end_time_;
+
+ // This is the QUIC server (hostname, port, is_https, privacy_mode) tuple for
+ // which we restore the crypto_config.
+ const QuicServerId server_id_;
+
+ private:
+ // ParseInner is a helper function for Parse.
+ bool ParseInner(const std::string& data);
+
+ // SerializeInner is a helper function for Serialize.
+ std::string SerializeInner() const;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicServerInfo);
+};
+
+class NET_EXPORT_PRIVATE QuicServerInfoFactory {
+ public:
+ QuicServerInfoFactory() {}
+ virtual ~QuicServerInfoFactory();
+
+ // GetForServer returns a fresh, allocated QuicServerInfo for the given
+ // |server_id| or NULL on failure.
+ virtual QuicServerInfo* GetForServer(const QuicServerId& server_id) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicServerInfoFactory);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_QUIC_SERVER_INFO_H_
diff --git a/chromium/net/quic/core/crypto/scoped_evp_aead_ctx.cc b/chromium/net/quic/core/crypto/scoped_evp_aead_ctx.cc
new file mode 100644
index 00000000000..447235833e4
--- /dev/null
+++ b/chromium/net/quic/core/crypto/scoped_evp_aead_ctx.cc
@@ -0,0 +1,23 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/crypto/scoped_evp_aead_ctx.h"
+
+namespace net {
+
+ScopedEVPAEADCtx::ScopedEVPAEADCtx() {
+ ctx_.aead = nullptr;
+}
+
+ScopedEVPAEADCtx::~ScopedEVPAEADCtx() {
+ if (ctx_.aead != nullptr) {
+ EVP_AEAD_CTX_cleanup(&ctx_);
+ }
+}
+
+EVP_AEAD_CTX* ScopedEVPAEADCtx::get() {
+ return &ctx_;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/crypto/scoped_evp_aead_ctx.h b/chromium/net/quic/core/crypto/scoped_evp_aead_ctx.h
index d8067fc0d9e..d8067fc0d9e 100644
--- a/chromium/net/quic/crypto/scoped_evp_aead_ctx.h
+++ b/chromium/net/quic/core/crypto/scoped_evp_aead_ctx.h
diff --git a/chromium/net/quic/core/crypto/strike_register.cc b/chromium/net/quic/core/crypto/strike_register.cc
new file mode 100644
index 00000000000..5bfb07cba3c
--- /dev/null
+++ b/chromium/net/quic/core/crypto/strike_register.cc
@@ -0,0 +1,519 @@
+// Copyright (c) 2013 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/crypto/strike_register.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "base/logging.h"
+
+using std::pair;
+using std::set;
+using std::vector;
+
+namespace net {
+
+namespace {
+
+uint32_t GetInitialHorizon(uint32_t current_time_internal,
+ uint32_t window_secs,
+ StrikeRegister::StartupType startup) {
+ if (startup == StrikeRegister::DENY_REQUESTS_AT_STARTUP) {
+ // The horizon is initially set |window_secs| into the future because, if
+ // we just crashed, then we may have accepted nonces in the span
+ // [current_time...current_time+window_secs] and so we conservatively
+ // reject the whole timespan unless |startup| tells us otherwise.
+ return current_time_internal + window_secs + 1;
+ } else { // startup == StrikeRegister::NO_STARTUP_PERIOD_NEEDED
+ // The orbit can be assumed to be globally unique. Use a horizon
+ // in the past.
+ return 0;
+ }
+}
+
+} // namespace
+
+// static
+const uint32_t StrikeRegister::kExternalNodeSize = 24;
+// static
+const uint32_t StrikeRegister::kNil = (1u << 31) | 1;
+// static
+const uint32_t StrikeRegister::kExternalFlag = 1 << 23;
+
+// InternalNode represents a non-leaf node in the critbit tree. See the comment
+// in the .h file for details.
+class StrikeRegister::InternalNode {
+ public:
+ void SetChild(unsigned direction, uint32_t child) {
+ data_[direction] = (data_[direction] & 0xff) | (child << 8);
+ }
+
+ void SetCritByte(uint8_t critbyte) {
+ data_[0] = (data_[0] & 0xffffff00) | critbyte;
+ }
+
+ void SetOtherBits(uint8_t otherbits) {
+ data_[1] = (data_[1] & 0xffffff00) | otherbits;
+ }
+
+ void SetNextPtr(uint32_t next) { data_[0] = next; }
+
+ uint32_t next() const { return data_[0]; }
+
+ uint32_t child(unsigned n) const { return data_[n] >> 8; }
+
+ uint8_t critbyte() const { return static_cast<uint8_t>(data_[0]); }
+
+ uint8_t otherbits() const { return static_cast<uint8_t>(data_[1]); }
+
+ // These bytes are organised thus:
+ // <24 bits> left child
+ // <8 bits> crit-byte
+ // <24 bits> right child
+ // <8 bits> other-bits
+ uint32_t data_[2];
+};
+
+// kCreationTimeFromInternalEpoch contains the number of seconds between the
+// start of the internal epoch and the creation time. This allows us
+// to consider times that are before the creation time.
+static const uint32_t kCreationTimeFromInternalEpoch = 63115200; // 2 years.
+
+void StrikeRegister::ValidateStrikeRegisterConfig(unsigned max_entries) {
+ // We only have 23 bits of index available.
+ CHECK_LT(max_entries, 1u << 23);
+ CHECK_GT(max_entries, 1u); // There must be at least two entries.
+ CHECK_EQ(sizeof(InternalNode), 8u); // in case of compiler changes.
+}
+
+StrikeRegister::StrikeRegister(unsigned max_entries,
+ uint32_t current_time,
+ uint32_t window_secs,
+ const uint8_t orbit[8],
+ StartupType startup)
+ : max_entries_(max_entries),
+ window_secs_(window_secs),
+ internal_epoch_(current_time > kCreationTimeFromInternalEpoch
+ ? current_time - kCreationTimeFromInternalEpoch
+ : 0),
+ horizon_(GetInitialHorizon(ExternalTimeToInternal(current_time),
+ window_secs,
+ startup)) {
+ memcpy(orbit_, orbit, sizeof(orbit_));
+
+ ValidateStrikeRegisterConfig(max_entries);
+ internal_nodes_ = new InternalNode[max_entries];
+ external_nodes_.reset(new uint8_t[kExternalNodeSize * max_entries]);
+
+ Reset();
+}
+
+StrikeRegister::~StrikeRegister() {
+ delete[] internal_nodes_;
+}
+
+void StrikeRegister::Reset() {
+ // Thread a free list through all of the internal nodes.
+ internal_node_free_head_ = 0;
+ for (unsigned i = 0; i < max_entries_ - 1; i++) {
+ internal_nodes_[i].SetNextPtr(i + 1);
+ }
+ internal_nodes_[max_entries_ - 1].SetNextPtr(kNil);
+
+ // Also thread a free list through the external nodes.
+ external_node_free_head_ = 0;
+ for (unsigned i = 0; i < max_entries_ - 1; i++) {
+ external_node_next_ptr(i) = i + 1;
+ }
+ external_node_next_ptr(max_entries_ - 1) = kNil;
+
+ // This is the root of the tree.
+ internal_node_head_ = kNil;
+}
+
+InsertStatus StrikeRegister::Insert(const uint8_t nonce[32],
+ uint32_t current_time_external) {
+ // Make space for the insertion if the strike register is full.
+ while (external_node_free_head_ == kNil || internal_node_free_head_ == kNil) {
+ DropOldestNode();
+ }
+
+ const uint32_t current_time = ExternalTimeToInternal(current_time_external);
+
+ // Check to see if the orbit is correct.
+ if (memcmp(nonce + sizeof(current_time), orbit_, sizeof(orbit_))) {
+ return NONCE_INVALID_ORBIT_FAILURE;
+ }
+
+ const uint32_t nonce_time = ExternalTimeToInternal(TimeFromBytes(nonce));
+
+ // Check that the timestamp is in the valid range.
+ pair<uint32_t, uint32_t> valid_range =
+ StrikeRegister::GetValidRange(current_time);
+ if (nonce_time < valid_range.first || nonce_time > valid_range.second) {
+ return NONCE_INVALID_TIME_FAILURE;
+ }
+
+ // We strip the orbit out of the nonce.
+ uint8_t value[24];
+ memcpy(value, nonce, sizeof(nonce_time));
+ memcpy(value + sizeof(nonce_time),
+ nonce + sizeof(nonce_time) + sizeof(orbit_),
+ sizeof(value) - sizeof(nonce_time));
+
+ // Find the best match to |value| in the crit-bit tree. The best match is
+ // simply the value which /could/ match |value|, if any does, so we still
+ // need a memcmp to check.
+ uint32_t best_match_index = BestMatch(value);
+ if (best_match_index == kNil) {
+ // Empty tree. Just insert the new value at the root.
+ uint32_t index = GetFreeExternalNode();
+ memcpy(external_node(index), value, sizeof(value));
+ internal_node_head_ = (index | kExternalFlag) << 8;
+ DCHECK_LE(horizon_, nonce_time);
+ return NONCE_OK;
+ }
+
+ const uint8_t* best_match = external_node(best_match_index);
+ if (memcmp(best_match, value, sizeof(value)) == 0) {
+ // We found the value in the tree.
+ return NONCE_NOT_UNIQUE_FAILURE;
+ }
+
+ // We are going to insert a new entry into the tree, so get the nodes now.
+ uint32_t internal_node_index = GetFreeInternalNode();
+ uint32_t external_node_index = GetFreeExternalNode();
+
+ // If we just evicted the best match, then we have to try and match again.
+ // We know that we didn't just empty the tree because we require that
+ // max_entries_ >= 2. Also, we know that it doesn't match because, if it
+ // did, it would have been returned previously.
+ if (external_node_index == best_match_index) {
+ best_match_index = BestMatch(value);
+ best_match = external_node(best_match_index);
+ }
+
+ // Now we need to find the first bit where we differ from |best_match|.
+ uint8_t differing_byte;
+ uint8_t new_other_bits;
+ for (differing_byte = 0; differing_byte < arraysize(value);
+ differing_byte++) {
+ new_other_bits = value[differing_byte] ^ best_match[differing_byte];
+ if (new_other_bits) {
+ break;
+ }
+ }
+
+ // Once we have the XOR the of first differing byte in new_other_bits we need
+ // to find the most significant differing bit. We could do this with a simple
+ // for loop, testing bits 7..0. Instead we fold the bits so that we end up
+ // with a byte where all the bits below the most significant one, are set.
+ new_other_bits |= new_other_bits >> 1;
+ new_other_bits |= new_other_bits >> 2;
+ new_other_bits |= new_other_bits >> 4;
+ // Now this bit trick results in all the bits set, except the original
+ // most-significant one.
+ new_other_bits = (new_other_bits & ~(new_other_bits >> 1)) ^ 255;
+
+ // Consider the effect of ORing against |new_other_bits|. If |value| did not
+ // have the critical bit set, the result is the same as |new_other_bits|. If
+ // it did, the result is all ones.
+
+ unsigned newdirection;
+ if ((new_other_bits | value[differing_byte]) == 0xff) {
+ newdirection = 1;
+ } else {
+ newdirection = 0;
+ }
+
+ memcpy(external_node(external_node_index), value, sizeof(value));
+ InternalNode* inode = &internal_nodes_[internal_node_index];
+
+ inode->SetChild(newdirection, external_node_index | kExternalFlag);
+ inode->SetCritByte(differing_byte);
+ inode->SetOtherBits(new_other_bits);
+
+ // |where_index| is a pointer to the uint32_t which needs to be updated in
+ // order to insert the new internal node into the tree. The internal nodes
+ // store the child indexes in the top 24-bits of a 32-bit word and, to keep
+ // the code simple, we define that |internal_node_head_| is organised the
+ // same way.
+ DCHECK_EQ(internal_node_head_ & 0xff, 0u);
+ uint32_t* where_index = &internal_node_head_;
+ while (((*where_index >> 8) & kExternalFlag) == 0) {
+ InternalNode* node = &internal_nodes_[*where_index >> 8];
+ if (node->critbyte() > differing_byte) {
+ break;
+ }
+ if (node->critbyte() == differing_byte &&
+ node->otherbits() > new_other_bits) {
+ break;
+ }
+ if (node->critbyte() == differing_byte &&
+ node->otherbits() == new_other_bits) {
+ CHECK(false);
+ }
+
+ uint8_t c = value[node->critbyte()];
+ const int direction =
+ (1 + static_cast<unsigned>(node->otherbits() | c)) >> 8;
+ where_index = &node->data_[direction];
+ }
+
+ inode->SetChild(newdirection ^ 1, *where_index >> 8);
+ *where_index = (*where_index & 0xff) | (internal_node_index << 8);
+
+ DCHECK_LE(horizon_, nonce_time);
+ return NONCE_OK;
+}
+
+const uint8_t* StrikeRegister::orbit() const {
+ return orbit_;
+}
+
+uint32_t StrikeRegister::GetCurrentValidWindowSecs(
+ uint32_t current_time_external) const {
+ uint32_t current_time = ExternalTimeToInternal(current_time_external);
+ pair<uint32_t, uint32_t> valid_range =
+ StrikeRegister::GetValidRange(current_time);
+ if (valid_range.second >= valid_range.first) {
+ return valid_range.second - current_time + 1;
+ } else {
+ return 0;
+ }
+}
+
+void StrikeRegister::Validate() {
+ set<uint32_t> free_internal_nodes;
+ for (uint32_t i = internal_node_free_head_; i != kNil;
+ i = internal_nodes_[i].next()) {
+ CHECK_LT(i, max_entries_);
+ CHECK_EQ(free_internal_nodes.count(i), 0u);
+ free_internal_nodes.insert(i);
+ }
+
+ set<uint32_t> free_external_nodes;
+ for (uint32_t i = external_node_free_head_; i != kNil;
+ i = external_node_next_ptr(i)) {
+ CHECK_LT(i, max_entries_);
+ CHECK_EQ(free_external_nodes.count(i), 0u);
+ free_external_nodes.insert(i);
+ }
+
+ set<uint32_t> used_external_nodes;
+ set<uint32_t> used_internal_nodes;
+
+ if (internal_node_head_ != kNil &&
+ ((internal_node_head_ >> 8) & kExternalFlag) == 0) {
+ vector<pair<unsigned, bool>> bits;
+ ValidateTree(internal_node_head_ >> 8, -1, bits, free_internal_nodes,
+ free_external_nodes, &used_internal_nodes,
+ &used_external_nodes);
+ }
+}
+
+// static
+uint32_t StrikeRegister::TimeFromBytes(const uint8_t d[4]) {
+ return static_cast<uint32_t>(d[0]) << 24 | static_cast<uint32_t>(d[1]) << 16 |
+ static_cast<uint32_t>(d[2]) << 8 | static_cast<uint32_t>(d[3]);
+}
+
+pair<uint32_t, uint32_t> StrikeRegister::GetValidRange(
+ uint32_t current_time_internal) const {
+ if (current_time_internal < horizon_) {
+ // Empty valid range.
+ return std::make_pair(std::numeric_limits<uint32_t>::max(), 0);
+ }
+
+ uint32_t lower_bound;
+ if (current_time_internal >= window_secs_) {
+ lower_bound = std::max(horizon_, current_time_internal - window_secs_);
+ } else {
+ lower_bound = horizon_;
+ }
+
+ // Also limit the upper range based on horizon_. This makes the
+ // strike register reject inserts that are far in the future and
+ // would consume strike register resources for a long time. This
+ // allows the strike server to degrade optimally in cases where the
+ // insert rate exceeds |max_entries_ / (2 * window_secs_)| entries
+ // per second.
+ uint32_t upper_bound =
+ current_time_internal +
+ std::min(current_time_internal - horizon_, window_secs_);
+
+ return std::make_pair(lower_bound, upper_bound);
+}
+
+uint32_t StrikeRegister::ExternalTimeToInternal(uint32_t external_time) const {
+ return external_time - internal_epoch_;
+}
+
+uint32_t StrikeRegister::BestMatch(const uint8_t v[24]) const {
+ if (internal_node_head_ == kNil) {
+ return kNil;
+ }
+
+ uint32_t next = internal_node_head_ >> 8;
+ while ((next & kExternalFlag) == 0) {
+ InternalNode* node = &internal_nodes_[next];
+ uint8_t b = v[node->critbyte()];
+ unsigned direction =
+ (1 + static_cast<unsigned>(node->otherbits() | b)) >> 8;
+ next = node->child(direction);
+ }
+
+ return next & ~kExternalFlag;
+}
+
+uint32_t& StrikeRegister::external_node_next_ptr(unsigned i) {
+ return *reinterpret_cast<uint32_t*>(&external_nodes_[i * kExternalNodeSize]);
+}
+
+uint8_t* StrikeRegister::external_node(unsigned i) {
+ return &external_nodes_[i * kExternalNodeSize];
+}
+
+uint32_t StrikeRegister::GetFreeExternalNode() {
+ uint32_t index = external_node_free_head_;
+ DCHECK(index != kNil);
+ external_node_free_head_ = external_node_next_ptr(index);
+ return index;
+}
+
+uint32_t StrikeRegister::GetFreeInternalNode() {
+ uint32_t index = internal_node_free_head_;
+ DCHECK(index != kNil);
+ internal_node_free_head_ = internal_nodes_[index].next();
+ return index;
+}
+
+void StrikeRegister::DropOldestNode() {
+ // DropOldestNode should never be called on an empty tree.
+ DCHECK(internal_node_head_ != kNil);
+
+ // An internal node in a crit-bit tree always has exactly two children.
+ // This means that, if we are removing an external node (which is one of
+ // those children), then we also need to remove an internal node. In order
+ // to do that we keep pointers to the parent (wherep) and grandparent
+ // (whereq) when walking down the tree.
+
+ uint32_t p = internal_node_head_ >> 8, *wherep = &internal_node_head_,
+ *whereq = nullptr;
+ while ((p & kExternalFlag) == 0) {
+ whereq = wherep;
+ InternalNode* inode = &internal_nodes_[p];
+ // We always go left, towards the smallest element, exploiting the fact
+ // that the timestamp is big-endian and at the start of the value.
+ wherep = &inode->data_[0];
+ p = (*wherep) >> 8;
+ }
+
+ const uint32_t ext_index = p & ~kExternalFlag;
+ const uint8_t* ext_node = external_node(ext_index);
+ uint32_t new_horizon = ExternalTimeToInternal(TimeFromBytes(ext_node)) + 1;
+ DCHECK_LE(horizon_, new_horizon);
+ horizon_ = new_horizon;
+
+ if (!whereq) {
+ // We are removing the last element in a tree.
+ internal_node_head_ = kNil;
+ FreeExternalNode(ext_index);
+ return;
+ }
+
+ // |wherep| points to the left child pointer in the parent so we can add
+ // one and dereference to get the right child.
+ const uint32_t other_child = wherep[1];
+ FreeInternalNode((*whereq) >> 8);
+ *whereq = (*whereq & 0xff) | (other_child & 0xffffff00);
+ FreeExternalNode(ext_index);
+}
+
+void StrikeRegister::FreeExternalNode(uint32_t index) {
+ external_node_next_ptr(index) = external_node_free_head_;
+ external_node_free_head_ = index;
+}
+
+void StrikeRegister::FreeInternalNode(uint32_t index) {
+ internal_nodes_[index].SetNextPtr(internal_node_free_head_);
+ internal_node_free_head_ = index;
+}
+
+void StrikeRegister::ValidateTree(uint32_t internal_node,
+ int last_bit,
+ const vector<pair<unsigned, bool>>& bits,
+ const set<uint32_t>& free_internal_nodes,
+ const set<uint32_t>& free_external_nodes,
+ set<uint32_t>* used_internal_nodes,
+ set<uint32_t>* used_external_nodes) {
+ CHECK_LT(internal_node, max_entries_);
+ const InternalNode* i = &internal_nodes_[internal_node];
+ unsigned bit = 0;
+ switch (i->otherbits()) {
+ case 0xff & ~(1 << 7):
+ bit = 0;
+ break;
+ case 0xff & ~(1 << 6):
+ bit = 1;
+ break;
+ case 0xff & ~(1 << 5):
+ bit = 2;
+ break;
+ case 0xff & ~(1 << 4):
+ bit = 3;
+ break;
+ case 0xff & ~(1 << 3):
+ bit = 4;
+ break;
+ case 0xff & ~(1 << 2):
+ bit = 5;
+ break;
+ case 0xff & ~(1 << 1):
+ bit = 6;
+ break;
+ case 0xff & ~1:
+ bit = 7;
+ break;
+ default:
+ CHECK(false);
+ }
+
+ bit += 8 * i->critbyte();
+ if (last_bit > -1) {
+ CHECK_GT(bit, static_cast<unsigned>(last_bit));
+ }
+
+ CHECK_EQ(free_internal_nodes.count(internal_node), 0u);
+
+ for (unsigned child = 0; child < 2; child++) {
+ if (i->child(child) & kExternalFlag) {
+ uint32_t ext = i->child(child) & ~kExternalFlag;
+ CHECK_EQ(free_external_nodes.count(ext), 0u);
+ CHECK_EQ(used_external_nodes->count(ext), 0u);
+ used_external_nodes->insert(ext);
+ const uint8_t* bytes = external_node(ext);
+ for (const pair<unsigned, bool>& pair : bits) {
+ unsigned byte = pair.first / 8;
+ DCHECK_LE(byte, 0xffu);
+ unsigned bit_new = pair.first % 8;
+ static const uint8_t kMasks[8] = {0x80, 0x40, 0x20, 0x10,
+ 0x08, 0x04, 0x02, 0x01};
+ CHECK_EQ((bytes[byte] & kMasks[bit_new]) != 0, pair.second);
+ }
+ } else {
+ uint32_t inter = i->child(child);
+ vector<pair<unsigned, bool>> new_bits(bits);
+ new_bits.push_back(pair<unsigned, bool>(bit, child != 0));
+ CHECK_EQ(free_internal_nodes.count(inter), 0u);
+ CHECK_EQ(used_internal_nodes->count(inter), 0u);
+ used_internal_nodes->insert(inter);
+ ValidateTree(inter, bit, bits, free_internal_nodes, free_external_nodes,
+ used_internal_nodes, used_external_nodes);
+ }
+ }
+}
+
+} // namespace net
diff --git a/chromium/net/quic/crypto/strike_register.h b/chromium/net/quic/core/crypto/strike_register.h
index 9d7431bfd05..9d7431bfd05 100644
--- a/chromium/net/quic/crypto/strike_register.h
+++ b/chromium/net/quic/core/crypto/strike_register.h
diff --git a/chromium/net/quic/core/crypto/strike_register_client.h b/chromium/net/quic/core/crypto/strike_register_client.h
new file mode 100644
index 00000000000..2126d6fc4be
--- /dev/null
+++ b/chromium/net/quic/core/crypto/strike_register_client.h
@@ -0,0 +1,60 @@
+// Copyright 2013 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_CRYPTO_STRIKE_REGISTER_CLIENT_H_
+#define NET_QUIC_CRYPTO_STRIKE_REGISTER_CLIENT_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/strike_register.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+// Interface implemented by clients that talk to strike registers
+// implemented as local or remote services.
+class NET_EXPORT_PRIVATE StrikeRegisterClient {
+ public:
+ // Single use callback that will be invoked once the validation
+ // operation is complete.
+ class NET_EXPORT_PRIVATE ResultCallback {
+ public:
+ ResultCallback() {}
+ virtual ~ResultCallback() {}
+ void Run(bool nonce_is_valid_and_unique, InsertStatus nonce_error) {
+ RunImpl(nonce_is_valid_and_unique, nonce_error);
+ delete this;
+ }
+
+ protected:
+ virtual void RunImpl(bool nonce_is_valid_and_unique,
+ InsertStatus nonce_error) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ResultCallback);
+ };
+
+ StrikeRegisterClient() {}
+ virtual ~StrikeRegisterClient() {}
+
+ // Returns true iff the strike register knows about the given orbit.
+ virtual bool IsKnownOrbit(base::StringPiece orbit) const = 0;
+ // Validate a nonce for freshness and uniqueness.
+ // Will invoke cb->Run(ValidateResponse::nonce_is_valid_and_unique(),
+ // ValidateResponse::nonce_error())
+ // once the asynchronous operation is complete.
+ virtual void VerifyNonceIsValidAndUnique(base::StringPiece nonce,
+ QuicWallTime now,
+ ResultCallback* cb) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StrikeRegisterClient);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_STRIKE_REGISTER_CLIENT_H_
diff --git a/chromium/net/quic/core/crypto/strike_register_test.cc b/chromium/net/quic/core/crypto/strike_register_test.cc
new file mode 100644
index 00000000000..1de07355eef
--- /dev/null
+++ b/chromium/net/quic/core/crypto/strike_register_test.cc
@@ -0,0 +1,407 @@
+// Copyright (c) 2013 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/crypto/strike_register.h"
+
+#include <cstdint>
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/rand_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+using std::min;
+using std::pair;
+using std::set;
+using std::string;
+
+const uint8_t kOrbit[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+// StrikeRegisterTests don't look at the random bytes so this function can
+// simply set the random bytes to 0.
+void SetNonce(uint8_t nonce[32], unsigned time, const uint8_t orbit[8]) {
+ nonce[0] = time >> 24;
+ nonce[1] = time >> 16;
+ nonce[2] = time >> 8;
+ nonce[3] = time;
+ memcpy(nonce + 4, orbit, 8);
+ memset(nonce + 12, 0, 20);
+}
+
+TEST(StrikeRegisterTest, SimpleHorizon) {
+ // The set must reject values created on or before its own creation time.
+ StrikeRegister set(10 /* max size */, 1000 /* current time */,
+ 100 /* window secs */, kOrbit,
+ StrikeRegister::DENY_REQUESTS_AT_STARTUP);
+ uint8_t nonce[32];
+ SetNonce(nonce, 999, kOrbit);
+ EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce, 1000));
+ SetNonce(nonce, 1000, kOrbit);
+ EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce, 1000));
+
+ EXPECT_EQ(0u, set.GetCurrentValidWindowSecs(1000 /* current time */));
+ EXPECT_EQ(0u, set.GetCurrentValidWindowSecs(1100 /* current time */));
+ EXPECT_EQ(1u, set.GetCurrentValidWindowSecs(1101 /* current time */));
+ EXPECT_EQ(50u, set.GetCurrentValidWindowSecs(1150 /* current time */));
+ EXPECT_EQ(100u, set.GetCurrentValidWindowSecs(1200 /* current time */));
+ EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1300 /* current time */));
+}
+
+TEST(StrikeRegisterTest, NoStartupMode) {
+ // Check that a strike register works immediately if NO_STARTUP_PERIOD_NEEDED
+ // is specified.
+ StrikeRegister set(10 /* max size */, 1000 /* current time */,
+ 100 /* window secs */, kOrbit,
+ StrikeRegister::NO_STARTUP_PERIOD_NEEDED);
+ uint8_t nonce[32];
+ SetNonce(nonce, 1000, kOrbit);
+ EXPECT_EQ(NONCE_OK, set.Insert(nonce, 1000));
+ EXPECT_EQ(NONCE_NOT_UNIQUE_FAILURE, set.Insert(nonce, 1000));
+
+ EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1000 /* current time */));
+ EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1050 /* current time */));
+ EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1100 /* current time */));
+ EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1200 /* current time */));
+ EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1300 /* current time */));
+}
+
+TEST(StrikeRegisterTest, WindowFuture) {
+ // The set must reject values outside the window.
+ StrikeRegister set(10 /* max size */, 1000 /* current time */,
+ 100 /* window secs */, kOrbit,
+ StrikeRegister::DENY_REQUESTS_AT_STARTUP);
+ uint8_t nonce[32];
+ SetNonce(nonce, 1101, kOrbit);
+ EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce, 1000));
+ SetNonce(nonce, 999, kOrbit);
+ EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce, 1100));
+}
+
+TEST(StrikeRegisterTest, BadOrbit) {
+ // The set must reject values with the wrong orbit
+ StrikeRegister set(10 /* max size */, 1000 /* current time */,
+ 100 /* window secs */, kOrbit,
+ StrikeRegister::DENY_REQUESTS_AT_STARTUP);
+ uint8_t nonce[32];
+ static const uint8_t kBadOrbit[8] = {0, 0, 0, 0, 1, 1, 1, 1};
+ SetNonce(nonce, 1101, kBadOrbit);
+ EXPECT_EQ(NONCE_INVALID_ORBIT_FAILURE, set.Insert(nonce, 1100));
+}
+
+TEST(StrikeRegisterTest, OneValue) {
+ StrikeRegister set(10 /* max size */, 1000 /* current time */,
+ 100 /* window secs */, kOrbit,
+ StrikeRegister::DENY_REQUESTS_AT_STARTUP);
+ uint8_t nonce[32];
+ SetNonce(nonce, 1101, kOrbit);
+ EXPECT_EQ(NONCE_OK, set.Insert(nonce, 1101));
+}
+
+TEST(StrikeRegisterTest, RejectDuplicate) {
+ // The set must reject values with the wrong orbit
+ StrikeRegister set(10 /* max size */, 1000 /* current time */,
+ 100 /* window secs */, kOrbit,
+ StrikeRegister::DENY_REQUESTS_AT_STARTUP);
+ uint8_t nonce[32];
+ SetNonce(nonce, 1101, kOrbit);
+ EXPECT_EQ(NONCE_OK, set.Insert(nonce, 1101));
+ EXPECT_EQ(NONCE_NOT_UNIQUE_FAILURE, set.Insert(nonce, 1101));
+}
+
+TEST(StrikeRegisterTest, HorizonUpdating) {
+ StrikeRegister::StartupType startup_types[] = {
+ StrikeRegister::DENY_REQUESTS_AT_STARTUP,
+ StrikeRegister::NO_STARTUP_PERIOD_NEEDED};
+
+ for (size_t type_idx = 0; type_idx < arraysize(startup_types); ++type_idx) {
+ StrikeRegister set(5 /* max size */, 500 /* current time */,
+ 100 /* window secs */, kOrbit, startup_types[type_idx]);
+ uint8_t nonce[6][32];
+ for (unsigned i = 0; i < 5; i++) {
+ SetNonce(nonce[i], 1101 + i, kOrbit);
+ nonce[i][31] = i;
+ EXPECT_EQ(NONCE_OK, set.Insert(nonce[i], 1100));
+ }
+
+ // Valid window is still equal to |window_secs + 1|.
+ EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1100));
+
+ // This should push the oldest value out and force the horizon to
+ // be updated.
+ SetNonce(nonce[5], 1110, kOrbit);
+ EXPECT_EQ(NONCE_OK, set.Insert(nonce[5], 1110));
+ // Effective horizon is computed based on the timestamp of the
+ // value that was pushed out.
+ EXPECT_EQ(9u, set.GetCurrentValidWindowSecs(1110));
+
+ SetNonce(nonce[5], 1111, kOrbit);
+ EXPECT_EQ(NONCE_OK, set.Insert(nonce[5], 1110));
+ EXPECT_EQ(8u, set.GetCurrentValidWindowSecs(1110));
+
+ // This should be behind the horizon now:
+ SetNonce(nonce[5], 1101, kOrbit);
+ nonce[5][31] = 10;
+ EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce[5], 1110));
+
+ // Insert beyond the valid range.
+ SetNonce(nonce[5], 1117, kOrbit);
+ nonce[5][31] = 2;
+ EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce[5], 1110));
+
+ // Insert at the upper valid range.
+ SetNonce(nonce[5], 1116, kOrbit);
+ nonce[5][31] = 1;
+ EXPECT_EQ(NONCE_OK, set.Insert(nonce[5], 1110));
+
+ // This should be beyond the upper valid range now:
+ SetNonce(nonce[5], 1116, kOrbit);
+ nonce[5][31] = 2;
+ EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce[5], 1110));
+ }
+}
+
+TEST(StrikeRegisterTest, InsertMany) {
+ StrikeRegister set(5000 /* max size */, 1000 /* current time */,
+ 500 /* window secs */, kOrbit,
+ StrikeRegister::DENY_REQUESTS_AT_STARTUP);
+
+ uint8_t nonce[32];
+ SetNonce(nonce, 1101, kOrbit);
+ for (unsigned i = 0; i < 100000; i++) {
+ SetNonce(nonce, 1101 + i / 500, kOrbit);
+ memcpy(nonce + 12, &i, sizeof(i));
+ EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce, 1100));
+ }
+}
+
+// For the following test we create a slow, but simple, version of a
+// StrikeRegister. The behaviour of this object is much easier to understand
+// than the fully fledged version. We then create a test to show, empirically,
+// that the two objects have identical behaviour.
+
+// A SlowStrikeRegister has the same public interface as a StrikeRegister, but
+// is much slower. Hopefully it is also more obviously correct and we can
+// empirically test that their behaviours are identical.
+class SlowStrikeRegister {
+ public:
+ SlowStrikeRegister(unsigned max_entries,
+ uint32_t current_time,
+ uint32_t window_secs,
+ const uint8_t orbit[8])
+ : max_entries_(max_entries),
+ window_secs_(window_secs),
+ creation_time_(current_time),
+ horizon_(ExternalTimeToInternal(current_time + window_secs) + 1) {
+ memcpy(orbit_, orbit, sizeof(orbit_));
+ }
+
+ InsertStatus Insert(const uint8_t nonce_bytes[32],
+ const uint32_t nonce_time_external,
+ const uint32_t current_time_external) {
+ if (nonces_.size() == max_entries_) {
+ DropOldestEntry();
+ }
+
+ const uint32_t current_time = ExternalTimeToInternal(current_time_external);
+
+ // Check to see if the orbit is correct.
+ if (memcmp(nonce_bytes + 4, orbit_, sizeof(orbit_))) {
+ return NONCE_INVALID_ORBIT_FAILURE;
+ }
+ const uint32_t nonce_time =
+ ExternalTimeToInternal(TimeFromBytes(nonce_bytes));
+ EXPECT_EQ(ExternalTimeToInternal(nonce_time_external), nonce_time);
+ // We have dropped one or more nonces with a time value of |horizon_ - 1|,
+ // so we have to reject anything with a timestamp less than or
+ // equal to that.
+ if (nonce_time < horizon_) {
+ return NONCE_INVALID_TIME_FAILURE;
+ }
+
+ // Check that the timestamp is in the current window.
+ if ((current_time > window_secs_ &&
+ nonce_time < (current_time - window_secs_)) ||
+ nonce_time > (current_time + window_secs_)) {
+ return NONCE_INVALID_TIME_FAILURE;
+ }
+
+ pair<uint32_t, string> nonce = std::make_pair(
+ nonce_time, string(reinterpret_cast<const char*>(nonce_bytes), 32));
+
+ set<pair<uint32_t, string>>::const_iterator it = nonces_.find(nonce);
+ if (it != nonces_.end()) {
+ return NONCE_NOT_UNIQUE_FAILURE;
+ }
+
+ nonces_.insert(nonce);
+ return NONCE_OK;
+ }
+
+ uint32_t GetCurrentValidWindowSecs(
+ const uint32_t current_time_external) const {
+ const uint32_t current_time = ExternalTimeToInternal(current_time_external);
+ if (horizon_ > current_time) {
+ return 0;
+ }
+ return 1 + min(current_time - horizon_, window_secs_);
+ }
+
+ private:
+ // TimeFromBytes returns a big-endian uint32_t from |d|.
+ static uint32_t TimeFromBytes(const uint8_t d[4]) {
+ return static_cast<uint32_t>(d[0]) << 24 |
+ static_cast<uint32_t>(d[1]) << 16 |
+ static_cast<uint32_t>(d[2]) << 8 | static_cast<uint32_t>(d[3]);
+ }
+
+ uint32_t ExternalTimeToInternal(uint32_t external_time) const {
+ static const uint32_t kCreationTimeFromInternalEpoch = 63115200.0;
+ uint32_t internal_epoch = 0;
+ if (creation_time_ > kCreationTimeFromInternalEpoch) {
+ internal_epoch = creation_time_ - kCreationTimeFromInternalEpoch;
+ }
+
+ return external_time - internal_epoch;
+ }
+
+ void DropOldestEntry() {
+ set<pair<uint32_t, string>>::iterator oldest = nonces_.begin();
+ horizon_ = oldest->first + 1;
+ nonces_.erase(oldest);
+ }
+
+ const unsigned max_entries_;
+ const unsigned window_secs_;
+ const uint32_t creation_time_;
+ uint8_t orbit_[8];
+ uint32_t horizon_;
+
+ set<pair<uint32_t, string>> nonces_;
+};
+
+class StrikeRegisterStressTest : public ::testing::Test {};
+
+TEST_F(StrikeRegisterStressTest, InOrderInsertion) {
+ // Fixed seed gives reproducibility for this test.
+ srand(42);
+
+ unsigned max_entries = 64;
+ uint32_t current_time = 10000, window = 200;
+ std::unique_ptr<StrikeRegister> s1(
+ new StrikeRegister(max_entries, current_time, window, kOrbit,
+ StrikeRegister::DENY_REQUESTS_AT_STARTUP));
+ std::unique_ptr<SlowStrikeRegister> s2(
+ new SlowStrikeRegister(max_entries, current_time, window, kOrbit));
+
+ uint64_t i;
+ const uint64_t kMaxIterations = 10000;
+ for (i = 0; i < kMaxIterations; i++) {
+ const uint32_t time = current_time + i;
+
+ uint8_t nonce[32];
+ SetNonce(nonce, time, kOrbit);
+
+ // There are 2048 possible nonce values:
+ const uint32_t v = rand() % 2048;
+ nonce[30] = v >> 8;
+ nonce[31] = v;
+
+ const InsertStatus nonce_error2 = s2->Insert(nonce, time, time);
+ const InsertStatus nonce_error1 = s1->Insert(nonce, time);
+ EXPECT_EQ(nonce_error1, nonce_error2);
+
+ // Inserts succeed after the startup period.
+ if (time > current_time + window) {
+ EXPECT_EQ(NONCE_OK, nonce_error1);
+ } else {
+ EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, nonce_error1);
+ }
+ EXPECT_EQ(s1->GetCurrentValidWindowSecs(time),
+ s2->GetCurrentValidWindowSecs(time));
+
+ if (i % 10 == 0) {
+ s1->Validate();
+ }
+
+ if (HasFailure()) {
+ break;
+ }
+ }
+
+ if (i != kMaxIterations) {
+ FAIL() << "Failed after " << i << " iterations";
+ }
+}
+
+TEST_F(StrikeRegisterStressTest, Stress) {
+ // Fixed seed gives reproducibility for this test.
+ srand(42);
+ unsigned max_entries = 64;
+ uint32_t current_time = 10000, window = 200;
+ std::unique_ptr<StrikeRegister> s1(
+ new StrikeRegister(max_entries, current_time, window, kOrbit,
+ StrikeRegister::DENY_REQUESTS_AT_STARTUP));
+ std::unique_ptr<SlowStrikeRegister> s2(
+ new SlowStrikeRegister(max_entries, current_time, window, kOrbit));
+ uint64_t i;
+
+ // When making changes it's worth removing the limit on this test and running
+ // it for a while. For the initial development an opt binary was left running
+ // for 10 minutes.
+ const uint64_t kMaxIterations = 10000;
+ for (i = 0; i < kMaxIterations; i++) {
+ if (rand() % 1000 == 0) {
+ // 0.1% chance of resetting the sets.
+ max_entries = rand() % 300 + 2;
+ current_time = rand() % 10000;
+ window = rand() % 500;
+ s1.reset(new StrikeRegister(max_entries, current_time, window, kOrbit,
+ StrikeRegister::DENY_REQUESTS_AT_STARTUP));
+ s2.reset(
+ new SlowStrikeRegister(max_entries, current_time, window, kOrbit));
+ }
+
+ int32_t time_delta = rand() % (window * 4);
+ time_delta -= window * 2;
+ const uint32_t time = current_time + time_delta;
+ if (time_delta < 0 && time > current_time) {
+ continue; // overflow
+ }
+
+ uint8_t nonce[32];
+ SetNonce(nonce, time, kOrbit);
+
+ // There are 2048 possible nonce values:
+ const uint32_t v = rand() % 2048;
+ nonce[30] = v >> 8;
+ nonce[31] = v;
+
+ const InsertStatus nonce_error2 = s2->Insert(nonce, time, time);
+ const InsertStatus nonce_error1 = s1->Insert(nonce, time);
+ EXPECT_EQ(nonce_error1, nonce_error2);
+ EXPECT_EQ(s1->GetCurrentValidWindowSecs(time),
+ s2->GetCurrentValidWindowSecs(time));
+
+ if (i % 10 == 0) {
+ s1->Validate();
+ }
+
+ if (HasFailure()) {
+ break;
+ }
+ }
+
+ if (i != kMaxIterations) {
+ FAIL() << "Failed after " << i << " iterations";
+ }
+}
+
+} // namespace
+
+} // namespace net
diff --git a/chromium/net/quic/core/interval.h b/chromium/net/quic/core/interval.h
new file mode 100644
index 00000000000..d29694e598b
--- /dev/null
+++ b/chromium/net/quic/core/interval.h
@@ -0,0 +1,302 @@
+// Copyright 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.
+//
+// An Interval<T> is a data structure used to represent a contiguous, mutable
+// range over an ordered type T. Supported operations include testing a value to
+// see whether it is included in the interval, comparing two intervals, and
+// performing their union, intersection, and difference. For the purposes of
+// this library, an "ordered type" is any type that induces a total order on its
+// values via its less-than operator (operator<()). Examples of such types are
+// basic arithmetic types like int and double as well as class types like
+// string.
+//
+// An Interval<T> is represented using the usual C++ STL convention, namely as
+// the half-open interval [min, max). A point p is considered to be contained in
+// the interval iff p >= min && p < max. One consequence of this definition is
+// that for any non-empty interval, min is contained in the interval but max is
+// not. There is no canonical representation for the empty interval; rather, any
+// interval where max <= min is regarded as empty. As a consequence, two empty
+// intervals will still compare as equal despite possibly having different
+// underlying min() or max() values. Also beware of the terminology used here:
+// the library uses the terms "min" and "max" rather than "begin" and "end" as
+// is conventional for the STL.
+//
+// T is required to be default- and copy-constructable, to have an assignment
+// operator, and the full complement of comparison operators (<, <=, ==, !=, >=,
+// >). A difference operator (operator-()) is required if Interval<T>::Length
+// is used.
+//
+// For equality comparisons, Interval<T> supports an Equals() method and an
+// operator==() which delegates to it. Two intervals are considered equal if
+// either they are both empty or if their corresponding min and max fields
+// compare equal. For ordered comparisons, Interval<T> also provides the
+// comparator Interval<T>::Less and an operator<() which delegates to it.
+// Unfortunately this comparator is currently buggy because its behavior is
+// inconsistent with Equals(): two empty ranges with different representations
+// may be regarded as equivalent by Equals() but regarded as different by
+// the comparator. Bug 9240050 has been created to address this.
+//
+// This class is thread-compatible if T is thread-compatible. (See
+// go/thread-compatible).
+//
+// Examples:
+// Interval<int> r1(0, 100); // The interval [0, 100).
+// EXPECT_TRUE(r1.Contains(0));
+// EXPECT_TRUE(r1.Contains(50));
+// EXPECT_FALSE(r1.Contains(100)); // 100 is just outside the interval.
+//
+// Interval<int> r2(50, 150); // The interval [50, 150).
+// EXPECT_TRUE(r1.Intersects(r2));
+// EXPECT_FALSE(r1.Contains(r2));
+// EXPECT_TRUE(r1.IntersectWith(r2)); // Mutates r1.
+// EXPECT_EQ(Interval<int>(50, 100), r1); // r1 is now [50, 100).
+//
+// Interval<int> r3(1000, 2000); // The interval [1000, 2000).
+// EXPECT_TRUE(r1.IntersectWith(r3)); // Mutates r1.
+// EXPECT_TRUE(r1.Empty()); // Now r1 is empty.
+// EXPECT_FALSE(r1.Contains(r1.min())); // e.g. doesn't contain its own min.
+
+#ifndef NET_QUIC_INTERVAL_H_
+#define NET_QUIC_INTERVAL_H_
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <functional>
+#include <ostream>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace net {
+
+template <typename T>
+class Interval {
+ private:
+// TODO(rtenneti): Implement after suupport for std::decay.
+#if 0
+ // Type trait for deriving the return type for Interval::Length. If
+ // operator-() is not defined for T, then the return type is void. This makes
+ // the signature for Length compile so that the class can be used for such T,
+ // but code that calls Length would still generate a compilation error.
+ template <typename U>
+ class DiffTypeOrVoid {
+ private:
+ template <typename V>
+ static auto f(const V* v) -> decltype(*v - *v);
+ template <typename V>
+ static void f(...);
+
+ public:
+ using type = typename std::decay<decltype(f<U>(0))>::type;
+ };
+#endif
+
+ public:
+ // Compatibility alias.
+ using Less = std::less<Interval>;
+
+ // Construct an Interval representing an empty interval.
+ Interval() : min_(), max_() {}
+
+ // Construct an Interval representing the interval [min, max). If min < max,
+ // the constructed object will represent the non-empty interval containing all
+ // values from min up to (but not including) max. On the other hand, if min >=
+ // max, the constructed object will represent the empty interval.
+ Interval(const T& min, const T& max) : min_(min), max_(max) {}
+
+ const T& min() const { return min_; }
+ const T& max() const { return max_; }
+ void SetMin(const T& t) { min_ = t; }
+ void SetMax(const T& t) { max_ = t; }
+
+ void Set(const T& min, const T& max) {
+ SetMin(min);
+ SetMax(max);
+ }
+
+ void Clear() { *this = {}; }
+ void CopyFrom(const Interval& i) { *this = i; }
+ bool Equals(const Interval& i) const { return *this == i; }
+ bool Empty() const { return min() >= max(); }
+
+ // Returns the length of this interval. The value returned is zero if
+ // IsEmpty() is true; otherwise the value returned is max() - min().
+ const T Length() const { return (min_ >= max_ ? min_ : max_) - min_; }
+
+ // Returns true iff t >= min() && t < max().
+ bool Contains(const T& t) const { return min() <= t && max() > t; }
+
+ // Returns true iff *this and i are non-empty, and *this includes i. "*this
+ // includes i" means that for all t, if i.Contains(t) then this->Contains(t).
+ // Note the unintuitive consequence of this definition: this method always
+ // returns false when i is the empty interval.
+ bool Contains(const Interval& i) const {
+ return !Empty() && !i.Empty() && min() <= i.min() && max() >= i.max();
+ }
+
+ // Returns true iff there exists some point t for which this->Contains(t) &&
+ // i.Contains(t) evaluates to true, i.e. if the intersection is non-empty.
+ bool Intersects(const Interval& i) const {
+ return !Empty() && !i.Empty() && min() < i.max() && max() > i.min();
+ }
+
+ // Returns true iff there exists some point t for which this->Contains(t) &&
+ // i.Contains(t) evaluates to true, i.e. if the intersection is non-empty.
+ // Furthermore, if the intersection is non-empty and the intersection pointer
+ // is not null, this method stores the calculated intersection in
+ // *intersection.
+ bool Intersects(const Interval& i, Interval* out) const;
+
+ // Sets *this to be the intersection of itself with i. Returns true iff
+ // *this was modified.
+ bool IntersectWith(const Interval& i);
+
+ // Calculates the smallest interval containing both *this i, and updates *this
+ // to represent that interval, and returns true iff *this was modified.
+ bool SpanningUnion(const Interval& i);
+
+ // Determines the difference between two intervals as in
+ // Difference(Interval&, vector*), but stores the results directly in out
+ // parameters rather than dynamically allocating an Interval* and appending
+ // it to a vector. If two results are generated, the one with the smaller
+ // value of min() will be stored in *lo and the other in *hi. Otherwise (if
+ // fewer than two results are generated), unused arguments will be set to the
+ // empty interval (it is possible that *lo will be empty and *hi non-empty).
+ // The method returns true iff the intersection of *this and i is non-empty.
+ bool Difference(const Interval& i, Interval* lo, Interval* hi) const;
+
+ friend bool operator==(const Interval& a, const Interval& b) {
+ bool ae = a.Empty();
+ bool be = b.Empty();
+ if (ae && be)
+ return true; // All empties are equal.
+ if (ae != be)
+ return false; // Empty cannot equal nonempty.
+ return a.min() == b.min() && a.max() == b.max();
+ }
+
+ friend bool operator!=(const Interval& a, const Interval& b) {
+ return !(a == b);
+ }
+
+ // Defines a comparator which can be used to induce an order on Intervals, so
+ // that, for example, they can be stored in an ordered container such as
+ // std::set. The ordering is arbitrary, but does provide the guarantee that,
+ // for non-empty intervals X and Y, if X contains Y, then X <= Y.
+ // TODO(kosak): The current implementation of this comparator has a problem
+ // because the ordering it induces is inconsistent with that of Equals(). In
+ // particular, this comparator does not properly consider all empty intervals
+ // equivalent. Bug b/9240050 has been created to track this.
+ friend bool operator<(const Interval& a, const Interval& b) {
+ return a.min() < b.min() || (a.min() == b.min() && a.max() > b.max());
+ }
+
+ friend std::ostream& operator<<(std::ostream& out, const Interval& i) {
+ return out << "[" << i.min() << ", " << i.max() << ")";
+ }
+
+ private:
+ T min_; // Inclusive lower bound.
+ T max_; // Exclusive upper bound.
+};
+
+//==============================================================================
+// Implementation details: Clients can stop reading here.
+
+template <typename T>
+bool Interval<T>::Intersects(const Interval& i, Interval* out) const {
+ if (!Intersects(i))
+ return false;
+ if (out != nullptr) {
+ *out = Interval(std::max(min(), i.min()), std::min(max(), i.max()));
+ }
+ return true;
+}
+
+template <typename T>
+bool Interval<T>::IntersectWith(const Interval& i) {
+ if (Empty())
+ return false;
+ bool modified = false;
+ if (i.min() > min()) {
+ SetMin(i.min());
+ modified = true;
+ }
+ if (i.max() < max()) {
+ SetMax(i.max());
+ modified = true;
+ }
+ return modified;
+}
+
+template <typename T>
+bool Interval<T>::SpanningUnion(const Interval& i) {
+ if (i.Empty())
+ return false;
+ if (Empty()) {
+ *this = i;
+ return true;
+ }
+ bool modified = false;
+ if (i.min() < min()) {
+ SetMin(i.min());
+ modified = true;
+ }
+ if (i.max() > max()) {
+ SetMax(i.max());
+ modified = true;
+ }
+ return modified;
+}
+
+template <typename T>
+bool Interval<T>::Difference(const Interval& i,
+ Interval* lo,
+ Interval* hi) const {
+ // Initialize *lo and *hi to empty
+ *lo = {};
+ *hi = {};
+ if (Empty())
+ return false;
+ if (i.Empty()) {
+ *lo = *this;
+ return false;
+ }
+ if (min() < i.max() && min() >= i.min() && max() > i.max()) {
+ // [------ this ------)
+ // [------ i ------)
+ // [-- result ---)
+ *hi = Interval(i.max(), max());
+ return true;
+ }
+ if (max() > i.min() && max() <= i.max() && min() < i.min()) {
+ // [------ this ------)
+ // [------ i ------)
+ // [- result -)
+ *lo = Interval(min(), i.min());
+ return true;
+ }
+ if (min() < i.min() && max() > i.max()) {
+ // [------- this --------)
+ // [---- i ----)
+ // [ R1 ) [ R2 )
+ // There are two results: R1 and R2.
+ *lo = Interval(min(), i.min());
+ *hi = Interval(i.max(), max());
+ return true;
+ }
+ if (min() >= i.min() && max() <= i.max()) {
+ // [--- this ---)
+ // [------ i --------)
+ // Intersection is <this>, so difference yields the empty interval.
+ return true;
+ }
+ *lo = *this; // No intersection.
+ return false;
+}
+
+} // namespace net
+
+#endif // NET_QUIC_INTERVAL_H_
diff --git a/chromium/net/quic/core/interval_set.h b/chromium/net/quic/core/interval_set.h
new file mode 100644
index 00000000000..9bb763a4e91
--- /dev/null
+++ b/chromium/net/quic/core/interval_set.h
@@ -0,0 +1,857 @@
+// Copyright 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.
+//
+// IntervalSet<T> is a data structure used to represent a sorted set of
+// non-empty, non-adjacent, and mutually disjoint intervals. Mutations to an
+// interval set preserve these properties, altering the set as needed. For
+// example, adding [2, 3) to a set containing only [1, 2) would result in the
+// set containing the single interval [1, 3).
+//
+// Supported operations include testing whether an Interval is contained in the
+// IntervalSet, comparing two IntervalSets, and performing IntervalSet union,
+// intersection, and difference.
+//
+// IntervalSet maintains the minimum number of entries needed to represent the
+// set of underlying intervals. When the IntervalSet is modified (e.g. due to an
+// Add operation), other interval entries may be coalesced, removed, or
+// otherwise modified in order to maintain this invariant. The intervals are
+// maintained in sorted order, by ascending min() value.
+//
+// The reader is cautioned to beware of the terminology used here: this library
+// uses the terms "min" and "max" rather than "begin" and "end" as is
+// conventional for the STL. The terminology [min, max) refers to the half-open
+// interval which (if the interval is not empty) contains min but does not
+// contain max. An interval is considered empty if min >= max.
+//
+// T is required to be default- and copy-constructible, to have an assignment
+// operator, a difference operator (operator-()), and the full complement of
+// comparison operators (<, <=, ==, !=, >=, >). These requirements are inherited
+// from Interval<T>.
+//
+// IntervalSet has constant-time move operations.
+//
+// This class is thread-compatible if T is thread-compatible. (See
+// go/thread-compatible).
+//
+// Examples:
+// IntervalSet<int> intervals;
+// intervals.Add(Interval<int>(10, 20));
+// intervals.Add(Interval<int>(30, 40));
+// // intervals contains [10,20) and [30,40).
+// intervals.Add(Interval<int>(15, 35));
+// // intervals has been coalesced. It now contains the single range [10,40).
+// EXPECT_EQ(1, intervals.Size());
+// EXPECT_TRUE(intervals.Contains(Interval<int>(10, 40)));
+//
+// intervals.Difference(Interval<int>(10, 20));
+// // intervals should now contain the single range [20, 40).
+// EXPECT_EQ(1, intervals.Size());
+// EXPECT_TRUE(intervals.Contains(Interval<int>(20, 40)));
+
+#ifndef NET_QUIC_INTERVAL_SET_H_
+#define NET_QUIC_INTERVAL_SET_H_
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "net/quic/core/interval.h"
+
+namespace net {
+
+template <typename T>
+class IntervalSet {
+ private:
+ struct IntervalComparator {
+ bool operator()(const Interval<T>& a, const Interval<T>& b) const;
+ };
+ typedef std::set<Interval<T>, IntervalComparator> Set;
+
+ public:
+ typedef typename Set::value_type value_type;
+ typedef typename Set::const_iterator const_iterator;
+ typedef typename Set::const_reverse_iterator const_reverse_iterator;
+
+ // Instantiates an empty IntervalSet.
+ IntervalSet() {}
+
+ // Instantiates an IntervalSet containing exactly one initial half-open
+ // interval [min, max), unless the given interval is empty, in which case the
+ // IntervalSet will be empty.
+ explicit IntervalSet(const Interval<T>& interval) { Add(interval); }
+
+ // Instantiates an IntervalSet containing the half-open interval [min, max).
+ IntervalSet(const T& min, const T& max) { Add(min, max); }
+
+// TODO(rtenneti): Implement after suupport for std::initializer_list.
+#if 0
+ IntervalSet(std::initializer_list<value_type> il) { assign(il); }
+#endif
+
+ // Clears this IntervalSet.
+ void Clear() { intervals_.clear(); }
+
+ // Returns the number of disjoint intervals contained in this IntervalSet.
+ size_t Size() const { return intervals_.size(); }
+
+ // Returns the smallest interval that contains all intervals in this
+ // IntervalSet, or the empty interval if the set is empty.
+ Interval<T> SpanningInterval() const;
+
+ // Adds "interval" to this IntervalSet. Adding the empty interval has no
+ // effect.
+ void Add(const Interval<T>& interval);
+
+ // Adds the interval [min, max) to this IntervalSet. Adding the empty interval
+ // has no effect.
+ void Add(const T& min, const T& max) { Add(Interval<T>(min, max)); }
+
+ // DEPRECATED(kosak). Use Union() instead. This method merges all of the
+ // values contained in "other" into this IntervalSet.
+ void Add(const IntervalSet& other);
+
+ // Returns true if this IntervalSet represents exactly the same set of
+ // intervals as the ones represented by "other".
+ bool Equals(const IntervalSet& other) const;
+
+ // Returns true if this IntervalSet is empty.
+ bool Empty() const { return intervals_.empty(); }
+
+ // Returns true if any interval in this IntervalSet contains the indicated
+ // value.
+ bool Contains(const T& value) const;
+
+ // Returns true if there is some interval in this IntervalSet that wholly
+ // contains the given interval. An interval O "wholly contains" a non-empty
+ // interval I if O.Contains(p) is true for every p in I. This is the same
+ // definition used by Interval<T>::Contains(). This method returns false on
+ // the empty interval, due to a (perhaps unintuitive) convention inherited
+ // from Interval<T>.
+ // Example:
+ // Assume an IntervalSet containing the entries { [10,20), [30,40) }.
+ // Contains(Interval(15, 16)) returns true, because [10,20) contains
+ // [15,16). However, Contains(Interval(15, 35)) returns false.
+ bool Contains(const Interval<T>& interval) const;
+
+ // Returns true if for each interval in "other", there is some (possibly
+ // different) interval in this IntervalSet which wholly contains it. See
+ // Contains(const Interval<T>& interval) for the meaning of "wholly contains".
+ // Perhaps unintuitively, this method returns false if "other" is the empty
+ // set. The algorithmic complexity of this method is O(other.Size() *
+ // log(this->Size())), which is not efficient. The method could be rewritten
+ // to run in O(other.Size() + this->Size()).
+ bool Contains(const IntervalSet<T>& other) const;
+
+ // Returns true if there is some interval in this IntervalSet that wholly
+ // contains the interval [min, max). See Contains(const Interval<T>&).
+ bool Contains(const T& min, const T& max) const {
+ return Contains(Interval<T>(min, max));
+ }
+
+ // Returns true if for some interval in "other", there is some interval in
+ // this IntervalSet that intersects with it. See Interval<T>::Intersects()
+ // for the definition of interval intersection.
+ bool Intersects(const IntervalSet& other) const;
+
+ // Returns an iterator to the Interval<T> in the IntervalSet that contains the
+ // given value. In other words, returns an iterator to the unique interval
+ // [min, max) in the IntervalSet that has the property min <= value < max. If
+ // there is no such interval, this method returns end().
+ const_iterator Find(const T& value) const;
+
+ // Returns an iterator to the Interval<T> in the IntervalSet that wholly
+ // contains the given interval. In other words, returns an iterator to the
+ // unique interval outer in the IntervalSet that has the property that
+ // outer.Contains(interval). If there is no such interval, or if interval is
+ // empty, returns end().
+ const_iterator Find(const Interval<T>& interval) const;
+
+ // Returns an iterator to the Interval<T> in the IntervalSet that wholly
+ // contains [min, max). In other words, returns an iterator to the unique
+ // interval outer in the IntervalSet that has the property that
+ // outer.Contains(Interval<T>(min, max)). If there is no such interval, or if
+ // interval is empty, returns end().
+ const_iterator Find(const T& min, const T& max) const {
+ return Find(Interval<T>(min, max));
+ }
+
+ // Returns true if every value within the passed interval is not Contained
+ // within the IntervalSet.
+ bool IsDisjoint(const Interval<T>& interval) const;
+
+ // Merges all the values contained in "other" into this IntervalSet.
+ void Union(const IntervalSet& other);
+
+ // Modifies this IntervalSet so that it contains only those values that are
+ // currently present both in *this and in the IntervalSet "other".
+ void Intersection(const IntervalSet& other);
+
+ // Mutates this IntervalSet so that it contains only those values that are
+ // currently in *this but not in "interval".
+ void Difference(const Interval<T>& interval);
+
+ // Mutates this IntervalSet so that it contains only those values that are
+ // currently in *this but not in the interval [min, max).
+ void Difference(const T& min, const T& max);
+
+ // Mutates this IntervalSet so that it contains only those values that are
+ // currently in *this but not in the IntervalSet "other".
+ void Difference(const IntervalSet& other);
+
+ // Mutates this IntervalSet so that it contains only those values that are
+ // in [min, max) but not currently in *this.
+ void Complement(const T& min, const T& max);
+
+ // IntervalSet's begin() iterator. The invariants of IntervalSet guarantee
+ // that for each entry e in the set, e.min() < e.max() (because the entries
+ // are non-empty) and for each entry f that appears later in the set,
+ // e.max() < f.min() (because the entries are ordered, pairwise-disjoint, and
+ // non-adjacent). Modifications to this IntervalSet invalidate these
+ // iterators.
+ const_iterator begin() const { return intervals_.begin(); }
+
+ // IntervalSet's end() iterator.
+ const_iterator end() const { return intervals_.end(); }
+
+ // IntervalSet's rbegin() and rend() iterators. Iterator invalidation
+ // semantics are the same as those for begin() / end().
+ const_reverse_iterator rbegin() const { return intervals_.rbegin(); }
+
+ const_reverse_iterator rend() const { return intervals_.rend(); }
+
+ // Appends the intervals in this IntervalSet to the end of *out.
+ void Get(std::vector<Interval<T>>* out) const {
+ out->insert(out->end(), begin(), end());
+ }
+
+ // Copies the intervals in this IntervalSet to the given output iterator.
+ template <typename Iter>
+ Iter Get(Iter out_iter) const {
+ return std::copy(begin(), end(), out_iter);
+ }
+
+ template <typename Iter>
+ void assign(Iter first, Iter last) {
+ Clear();
+ for (; first != last; ++first)
+ Add(*first);
+ }
+
+// TODO(rtenneti): Implement after suupport for std::initializer_list.
+#if 0
+ void assign(std::initializer_list<value_type> il) {
+ assign(il.begin(), il.end());
+ }
+#endif
+
+ // Returns a human-readable representation of this set. This will typically be
+ // (though is not guaranteed to be) of the form
+ // "[a1, b1) [a2, b2) ... [an, bn)"
+ // where the intervals are in the same order as given by traversal from
+ // begin() to end(). This representation is intended for human consumption;
+ // computer programs should not rely on the output being in exactly this form.
+ std::string ToString() const;
+
+ // Equality for IntervalSet<T>. Delegates to Equals().
+ bool operator==(const IntervalSet& other) const { return Equals(other); }
+
+ // Inequality for IntervalSet<T>. Delegates to Equals() (and returns its
+ // negation).
+ bool operator!=(const IntervalSet& other) const { return !Equals(other); }
+
+// TODO(rtenneti): Implement after suupport for std::initializer_list.
+#if 0
+ IntervalSet& operator=(std::initializer_list<value_type> il) {
+ assign(il.begin(), il.end());
+ return *this;
+ }
+#endif
+
+ // Swap this IntervalSet with *other. This is a constant-time operation.
+ void Swap(IntervalSet<T>* other) { intervals_.swap(other->intervals_); }
+
+ private:
+ // Removes overlapping ranges and coalesces adjacent intervals as needed.
+ void Compact(const typename Set::iterator& begin,
+ const typename Set::iterator& end);
+
+ // Returns true if this set is valid (i.e. all intervals in it are non-empty,
+ // non-adjacent, and mutually disjoint). Currently this is used as an
+ // integrity check by the Intersection() and Difference() methods, but is only
+ // invoked for debug builds (via DCHECK).
+ bool Valid() const;
+
+ // Finds the first interval that potentially intersects 'other'.
+ const_iterator FindIntersectionCandidate(const IntervalSet& other) const;
+
+ // Finds the first interval that potentially intersects 'interval'.
+ const_iterator FindIntersectionCandidate(const Interval<T>& interval) const;
+
+ // Helper for Intersection() and Difference(): Finds the next pair of
+ // intervals from 'x' and 'y' that intersect. 'mine' is an iterator
+ // over x->intervals_. 'theirs' is an iterator over y.intervals_. 'mine'
+ // and 'theirs' are advanced until an intersecting pair is found.
+ // Non-intersecting intervals (aka "holes") from x->intervals_ can be
+ // optionally erased by "on_hole".
+ template <typename X, typename Func>
+ static bool FindNextIntersectingPairImpl(X* x,
+ const IntervalSet& y,
+ const_iterator* mine,
+ const_iterator* theirs,
+ Func on_hole);
+
+ // The variant of the above method that doesn't mutate this IntervalSet.
+ bool FindNextIntersectingPair(const IntervalSet& other,
+ const_iterator* mine,
+ const_iterator* theirs) const {
+ return FindNextIntersectingPairImpl(
+ this, other, mine, theirs,
+ [](const IntervalSet*, const_iterator, const_iterator) {});
+ }
+
+ // The variant of the above method that mutates this IntervalSet by erasing
+ // holes.
+ bool FindNextIntersectingPairAndEraseHoles(const IntervalSet& other,
+ const_iterator* mine,
+ const_iterator* theirs) {
+ return FindNextIntersectingPairImpl(
+ this, other, mine, theirs,
+ [](IntervalSet* x, const_iterator from, const_iterator to) {
+ x->intervals_.erase(from, to);
+ });
+ }
+
+ // The representation for the intervals. The intervals in this set are
+ // non-empty, pairwise-disjoint, non-adjacent and ordered in ascending order
+ // by min().
+ Set intervals_;
+};
+
+template <typename T>
+std::ostream& operator<<(std::ostream& out, const IntervalSet<T>& seq);
+
+template <typename T>
+void swap(IntervalSet<T>& x, IntervalSet<T>& y);
+
+//==============================================================================
+// Implementation details: Clients can stop reading here.
+
+template <typename T>
+Interval<T> IntervalSet<T>::SpanningInterval() const {
+ Interval<T> result;
+ if (!intervals_.empty()) {
+ result.SetMin(intervals_.begin()->min());
+ result.SetMax(intervals_.rbegin()->max());
+ }
+ return result;
+}
+
+template <typename T>
+void IntervalSet<T>::Add(const Interval<T>& interval) {
+ if (interval.Empty())
+ return;
+ std::pair<typename Set::iterator, bool> ins = intervals_.insert(interval);
+ if (!ins.second) {
+ // This interval already exists.
+ return;
+ }
+ // Determine the minimal range that will have to be compacted. We know that
+ // the IntervalSet was valid before the addition of the interval, so only
+ // need to start with the interval itself (although Compact takes an open
+ // range so begin needs to be the interval to the left). We don't know how
+ // many ranges this interval may cover, so we need to find the appropriate
+ // interval to end with on the right.
+ typename Set::iterator begin = ins.first;
+ if (begin != intervals_.begin())
+ --begin;
+ const Interval<T> target_end(interval.max(), interval.max());
+ const typename Set::iterator end = intervals_.upper_bound(target_end);
+ Compact(begin, end);
+}
+
+template <typename T>
+void IntervalSet<T>::Add(const IntervalSet& other) {
+ for (const_iterator it = other.begin(); it != other.end(); ++it) {
+ Add(*it);
+ }
+}
+
+template <typename T>
+bool IntervalSet<T>::Equals(const IntervalSet& other) const {
+ if (intervals_.size() != other.intervals_.size())
+ return false;
+ for (typename Set::iterator i = intervals_.begin(),
+ j = other.intervals_.begin();
+ i != intervals_.end(); ++i, ++j) {
+ // Simple member-wise equality, since all intervals are non-empty.
+ if (i->min() != j->min() || i->max() != j->max())
+ return false;
+ }
+ return true;
+}
+
+template <typename T>
+bool IntervalSet<T>::Contains(const T& value) const {
+ Interval<T> tmp(value, value);
+ // Find the first interval with min() > value, then move back one step
+ const_iterator it = intervals_.upper_bound(tmp);
+ if (it == intervals_.begin())
+ return false;
+ --it;
+ return it->Contains(value);
+}
+
+template <typename T>
+bool IntervalSet<T>::Contains(const Interval<T>& interval) const {
+ // Find the first interval with min() > value, then move back one step.
+ const_iterator it = intervals_.upper_bound(interval);
+ if (it == intervals_.begin())
+ return false;
+ --it;
+ return it->Contains(interval);
+}
+
+template <typename T>
+bool IntervalSet<T>::Contains(const IntervalSet<T>& other) const {
+ if (!SpanningInterval().Contains(other.SpanningInterval())) {
+ return false;
+ }
+
+ for (const_iterator i = other.begin(); i != other.end(); ++i) {
+ // If we don't contain the interval, can return false now.
+ if (!Contains(*i)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// This method finds the interval that Contains() "value", if such an interval
+// exists in the IntervalSet. The way this is done is to locate the "candidate
+// interval", the only interval that could *possibly* contain value, and test it
+// using Contains(). The candidate interval is the interval with the largest
+// min() having min() <= value.
+//
+// Determining the candidate interval takes a couple of steps. First, since the
+// underlying std::set stores intervals, not values, we need to create a "probe
+// interval" suitable for use as a search key. The probe interval used is
+// [value, value). Now we can restate the problem as finding the largest
+// interval in the IntervalSet that is <= the probe interval.
+//
+// This restatement only works if the set's comparator behaves in a certain way.
+// In particular it needs to order first by ascending min(), and then by
+// descending max(). The comparator used by this library is defined in exactly
+// this way. To see why descending max() is required, consider the following
+// example. Assume an IntervalSet containing these intervals:
+//
+// [0, 5) [10, 20) [50, 60)
+//
+// Consider searching for the value 15. The probe interval [15, 15) is created,
+// and [10, 20) is identified as the largest interval in the set <= the probe
+// interval. This is the correct interval needed for the Contains() test, which
+// will then return true.
+//
+// Now consider searching for the value 30. The probe interval [30, 30) is
+// created, and again [10, 20] is identified as the largest interval <= the
+// probe interval. This is again the correct interval needed for the Contains()
+// test, which in this case returns false.
+//
+// Finally, consider searching for the value 10. The probe interval [10, 10) is
+// created. Here the ordering relationship between [10, 10) and [10, 20) becomes
+// vitally important. If [10, 10) were to come before [10, 20), then [0, 5)
+// would be the largest interval <= the probe, leading to the wrong choice of
+// interval for the Contains() test. Therefore [10, 10) needs to come after
+// [10, 20). The simplest way to make this work in the general case is to order
+// by ascending min() but descending max(). In this ordering, the empty interval
+// is larger than any non-empty interval with the same min(). The comparator
+// used by this library is careful to induce this ordering.
+//
+// Another detail involves the choice of which std::set method to use to try to
+// find the candidate interval. The most appropriate entry point is
+// set::upper_bound(), which finds the smallest interval which is > the probe
+// interval. The semantics of upper_bound() are slightly different from what we
+// want (namely, to find the largest interval which is <= the probe interval)
+// but they are close enough; the interval found by upper_bound() will always be
+// one step past the interval we are looking for (if it exists) or at begin()
+// (if it does not). Getting to the proper interval is a simple matter of
+// decrementing the iterator.
+template <typename T>
+typename IntervalSet<T>::const_iterator IntervalSet<T>::Find(
+ const T& value) const {
+ Interval<T> tmp(value, value);
+ const_iterator it = intervals_.upper_bound(tmp);
+ if (it == intervals_.begin())
+ return intervals_.end();
+ --it;
+ if (it->Contains(value))
+ return it;
+ else
+ return intervals_.end();
+}
+
+// This method finds the interval that Contains() the interval "probe", if such
+// an interval exists in the IntervalSet. The way this is done is to locate the
+// "candidate interval", the only interval that could *possibly* contain
+// "probe", and test it using Contains(). The candidate interval is the largest
+// interval that is <= the probe interval.
+//
+// The search for the candidate interval only works if the comparator used
+// behaves in a certain way. In particular it needs to order first by ascending
+// min(), and then by descending max(). The comparator used by this library is
+// defined in exactly this way. To see why descending max() is required,
+// consider the following example. Assume an IntervalSet containing these
+// intervals:
+//
+// [0, 5) [10, 20) [50, 60)
+//
+// Consider searching for the probe [15, 17). [10, 20) is the largest interval
+// in the set which is <= the probe interval. This is the correct interval
+// needed for the Contains() test, which will then return true, because [10, 20)
+// contains [15, 17).
+//
+// Now consider searching for the probe [30, 32). Again [10, 20] is the largest
+// interval <= the probe interval. This is again the correct interval needed for
+// the Contains() test, which in this case returns false, because [10, 20) does
+// not contain [30, 32).
+//
+// Finally, consider searching for the probe [10, 12). Here the ordering
+// relationship between [10, 12) and [10, 20) becomes vitally important. If
+// [10, 12) were to come before [10, 20), then [0, 5) would be the largest
+// interval <= the probe, leading to the wrong choice of interval for the
+// Contains() test. Therefore [10, 12) needs to come after [10, 20). The
+// simplest way to make this work in the general case is to order by ascending
+// min() but descending max(). In this ordering, given two intervals with the
+// same min(), the wider one goes before the narrower one. The comparator used
+// by this library is careful to induce this ordering.
+//
+// Another detail involves the choice of which std::set method to use to try to
+// find the candidate interval. The most appropriate entry point is
+// set::upper_bound(), which finds the smallest interval which is > the probe
+// interval. The semantics of upper_bound() are slightly different from what we
+// want (namely, to find the largest interval which is <= the probe interval)
+// but they are close enough; the interval found by upper_bound() will always be
+// one step past the interval we are looking for (if it exists) or at begin()
+// (if it does not). Getting to the proper interval is a simple matter of
+// decrementing the iterator.
+template <typename T>
+typename IntervalSet<T>::const_iterator IntervalSet<T>::Find(
+ const Interval<T>& probe) const {
+ const_iterator it = intervals_.upper_bound(probe);
+ if (it == intervals_.begin())
+ return intervals_.end();
+ --it;
+ if (it->Contains(probe))
+ return it;
+ else
+ return intervals_.end();
+}
+
+template <typename T>
+bool IntervalSet<T>::IsDisjoint(const Interval<T>& interval) const {
+ Interval<T> tmp(interval.min(), interval.min());
+ // Find the first interval with min() > interval.min()
+ const_iterator it = intervals_.upper_bound(tmp);
+ if (it != intervals_.end() && interval.max() > it->min())
+ return false;
+ if (it == intervals_.begin())
+ return true;
+ --it;
+ return it->max() <= interval.min();
+}
+
+template <typename T>
+void IntervalSet<T>::Union(const IntervalSet& other) {
+ intervals_.insert(other.begin(), other.end());
+ Compact(intervals_.begin(), intervals_.end());
+}
+
+template <typename T>
+typename IntervalSet<T>::const_iterator
+IntervalSet<T>::FindIntersectionCandidate(const IntervalSet& other) const {
+ return FindIntersectionCandidate(*other.intervals_.begin());
+}
+
+template <typename T>
+typename IntervalSet<T>::const_iterator
+IntervalSet<T>::FindIntersectionCandidate(const Interval<T>& interval) const {
+ // Use upper_bound to efficiently find the first interval in intervals_
+ // where min() is greater than interval.min(). If the result
+ // isn't the beginning of intervals_ then move backwards one interval since
+ // the interval before it is the first candidate where max() may be
+ // greater than interval.min().
+ // In other words, no interval before that can possibly intersect with any
+ // of other.intervals_.
+ const_iterator mine = intervals_.upper_bound(interval);
+ if (mine != intervals_.begin()) {
+ --mine;
+ }
+ return mine;
+}
+
+template <typename T>
+template <typename X, typename Func>
+bool IntervalSet<T>::FindNextIntersectingPairImpl(X* x,
+ const IntervalSet& y,
+ const_iterator* mine,
+ const_iterator* theirs,
+ Func on_hole) {
+ CHECK(x != nullptr);
+ if ((*mine == x->intervals_.end()) || (*theirs == y.intervals_.end())) {
+ return false;
+ }
+ while (!(**mine).Intersects(**theirs)) {
+ const_iterator erase_first = *mine;
+ // Skip over intervals in 'mine' that don't reach 'theirs'.
+ while (*mine != x->intervals_.end() && (**mine).max() <= (**theirs).min()) {
+ ++(*mine);
+ }
+ on_hole(x, erase_first, *mine);
+ // We're done if the end of intervals_ is reached.
+ if (*mine == x->intervals_.end()) {
+ return false;
+ }
+ // Skip over intervals 'theirs' that don't reach 'mine'.
+ while (*theirs != y.intervals_.end() &&
+ (**theirs).max() <= (**mine).min()) {
+ ++(*theirs);
+ }
+ // If the end of other.intervals_ is reached, we're done.
+ if (*theirs == y.intervals_.end()) {
+ on_hole(x, *mine, x->intervals_.end());
+ return false;
+ }
+ }
+ return true;
+}
+
+template <typename T>
+void IntervalSet<T>::Intersection(const IntervalSet& other) {
+ if (!SpanningInterval().Intersects(other.SpanningInterval())) {
+ intervals_.clear();
+ return;
+ }
+
+ const_iterator mine = FindIntersectionCandidate(other);
+ // Remove any intervals that cannot possibly intersect with other.intervals_.
+ intervals_.erase(intervals_.begin(), mine);
+ const_iterator theirs = other.FindIntersectionCandidate(*this);
+
+ while (FindNextIntersectingPairAndEraseHoles(other, &mine, &theirs)) {
+ // OK, *mine and *theirs intersect. Now, we find the largest
+ // span of intervals in other (starting at theirs) - say [a..b]
+ // - that intersect *mine, and we replace *mine with (*mine
+ // intersect x) for all x in [a..b] Note that subsequent
+ // intervals in this can't intersect any intervals in [a..b) --
+ // they may only intersect b or subsequent intervals in other.
+ Interval<T> i(*mine);
+ intervals_.erase(mine);
+ mine = intervals_.end();
+ Interval<T> intersection;
+ while (theirs != other.intervals_.end() &&
+ i.Intersects(*theirs, &intersection)) {
+ std::pair<typename Set::iterator, bool> ins =
+ intervals_.insert(intersection);
+ DCHECK(ins.second);
+ mine = ins.first;
+ ++theirs;
+ }
+ DCHECK(mine != intervals_.end());
+ --theirs;
+ ++mine;
+ }
+ DCHECK(Valid());
+}
+
+template <typename T>
+bool IntervalSet<T>::Intersects(const IntervalSet& other) const {
+ if (!SpanningInterval().Intersects(other.SpanningInterval())) {
+ return false;
+ }
+
+ const_iterator mine = FindIntersectionCandidate(other);
+ if (mine == intervals_.end()) {
+ return false;
+ }
+ const_iterator theirs = other.FindIntersectionCandidate(*mine);
+
+ return FindNextIntersectingPair(other, &mine, &theirs);
+}
+
+template <typename T>
+void IntervalSet<T>::Difference(const Interval<T>& interval) {
+ if (!SpanningInterval().Intersects(interval)) {
+ return;
+ }
+ Difference(IntervalSet<T>(interval));
+}
+
+template <typename T>
+void IntervalSet<T>::Difference(const T& min, const T& max) {
+ Difference(Interval<T>(min, max));
+}
+
+template <typename T>
+void IntervalSet<T>::Difference(const IntervalSet& other) {
+ if (!SpanningInterval().Intersects(other.SpanningInterval())) {
+ return;
+ }
+
+ const_iterator mine = FindIntersectionCandidate(other);
+ // If no interval in mine reaches the first interval of theirs then we're
+ // done.
+ if (mine == intervals_.end()) {
+ return;
+ }
+ const_iterator theirs = other.FindIntersectionCandidate(*this);
+
+ while (FindNextIntersectingPair(other, &mine, &theirs)) {
+ // At this point *mine and *theirs overlap. Remove mine from
+ // intervals_ and replace it with the possibly two intervals that are
+ // the difference between mine and theirs.
+ Interval<T> i(*mine);
+ intervals_.erase(mine++);
+ Interval<T> lo;
+ Interval<T> hi;
+ i.Difference(*theirs, &lo, &hi);
+
+ if (!lo.Empty()) {
+ // We have a low end. This can't intersect anything else.
+ std::pair<typename Set::iterator, bool> ins = intervals_.insert(lo);
+ DCHECK(ins.second);
+ }
+
+ if (!hi.Empty()) {
+ std::pair<typename Set::iterator, bool> ins = intervals_.insert(hi);
+ DCHECK(ins.second);
+ mine = ins.first;
+ }
+ }
+ DCHECK(Valid());
+}
+
+template <typename T>
+void IntervalSet<T>::Complement(const T& min, const T& max) {
+ IntervalSet<T> span(min, max);
+ span.Difference(*this);
+ intervals_.swap(span.intervals_);
+}
+
+template <typename T>
+std::string IntervalSet<T>::ToString() const {
+ std::ostringstream os;
+ os << *this;
+ return os.str();
+}
+
+// This method compacts the IntervalSet, merging pairs of overlapping intervals
+// into a single interval. In the steady state, the IntervalSet does not contain
+// any such pairs. However, the way the Union() and Add() methods work is to
+// temporarily put the IntervalSet into such a state and then to call Compact()
+// to "fix it up" so that it is no longer in that state.
+//
+// Compact() needs the interval set to allow two intervals [a,b) and [a,c)
+// (having the same min() but different max()) to briefly coexist in the set at
+// the same time, and be adjacent to each other, so that they can be efficiently
+// located and merged into a single interval. This state would be impossible
+// with a comparator which only looked at min(), as such a comparator would
+// consider such pairs equal. Fortunately, the comparator used by IntervalSet
+// does exactly what is needed, ordering first by ascending min(), then by
+// descending max().
+template <typename T>
+void IntervalSet<T>::Compact(const typename Set::iterator& begin,
+ const typename Set::iterator& end) {
+ if (begin == end)
+ return;
+ typename Set::iterator next = begin;
+ typename Set::iterator prev = begin;
+ typename Set::iterator it = begin;
+ ++it;
+ ++next;
+ while (it != end) {
+ ++next;
+ if (prev->max() >= it->min()) {
+ // Overlapping / coalesced range; merge the two intervals.
+ T min = prev->min();
+ T max = std::max(prev->max(), it->max());
+ Interval<T> i(min, max);
+ intervals_.erase(prev);
+ intervals_.erase(it);
+ std::pair<typename Set::iterator, bool> ins = intervals_.insert(i);
+ DCHECK(ins.second);
+ prev = ins.first;
+ } else {
+ prev = it;
+ }
+ it = next;
+ }
+}
+
+template <typename T>
+bool IntervalSet<T>::Valid() const {
+ const_iterator prev = end();
+ for (const_iterator it = begin(); it != end(); ++it) {
+ // invalid or empty interval.
+ if (it->min() >= it->max())
+ return false;
+ // Not sorted, not disjoint, or adjacent.
+ if (prev != end() && prev->max() >= it->min())
+ return false;
+ prev = it;
+ }
+ return true;
+}
+
+template <typename T>
+inline std::ostream& operator<<(std::ostream& out, const IntervalSet<T>& seq) {
+// TODO(rtenneti): Implement << method of IntervalSet.
+#if 0
+ util::gtl::LogRangeToStream(out, seq.begin(), seq.end(),
+ util::gtl::LogLegacy());
+#endif // 0
+ return out;
+}
+
+template <typename T>
+void swap(IntervalSet<T>& x, IntervalSet<T>& y) {
+ x.Swap(&y);
+}
+
+// This comparator orders intervals first by ascending min() and then by
+// descending max(). Readers who are satisified with that explanation can stop
+// reading here. The remainder of this comment is for the benefit of future
+// maintainers of this library.
+//
+// The reason for this ordering is that this comparator has to serve two
+// masters. First, it has to maintain the intervals in its internal set in the
+// order that clients expect to see them. Clients see these intervals via the
+// iterators provided by begin()/end() or as a result of invoking Get(). For
+// this reason, the comparator orders intervals by ascending min().
+//
+// If client iteration were the only consideration, then ordering by ascending
+// min() would be good enough. This is because the intervals in the IntervalSet
+// are non-empty, non-adjacent, and mutually disjoint; such intervals happen to
+// always have disjoint min() values, so such a comparator would never even have
+// to look at max() in order to work correctly for this class.
+//
+// However, in addition to ordering by ascending min(), this comparator also has
+// a second responsibility: satisfying the special needs of this library's
+// peculiar internal implementation. These needs require the comparator to order
+// first by ascending min() and then by descending max(). The best way to
+// understand why this is so is to check out the comments associated with the
+// Find() and Compact() methods.
+template <typename T>
+inline bool IntervalSet<T>::IntervalComparator::operator()(
+ const Interval<T>& a,
+ const Interval<T>& b) const {
+ return (a.min() < b.min() || (a.min() == b.min() && a.max() > b.max()));
+}
+
+} // namespace net
+
+#endif // NET_QUIC_INTERVAL_SET_H_
diff --git a/chromium/net/quic/core/interval_set_test.cc b/chromium/net/quic/core/interval_set_test.cc
new file mode 100644
index 00000000000..cbcda2a325e
--- /dev/null
+++ b/chromium/net/quic/core/interval_set_test.cc
@@ -0,0 +1,981 @@
+// Copyright 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.
+
+#include "net/quic/core/interval_set.h"
+
+#include <stdarg.h>
+
+#include <iostream>
+#include <iterator>
+#include <limits>
+
+#include "net/test/gtest_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::pair;
+using std::string;
+using std::vector;
+
+namespace net {
+namespace test {
+namespace {
+
+using ::testing::ElementsAreArray;
+
+class IntervalSetTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ // Initialize two IntervalSets for union, intersection, and difference
+ // tests
+ is.Add(100, 200);
+ is.Add(300, 400);
+ is.Add(500, 600);
+ is.Add(700, 800);
+ is.Add(900, 1000);
+ is.Add(1100, 1200);
+ is.Add(1300, 1400);
+ is.Add(1500, 1600);
+ is.Add(1700, 1800);
+ is.Add(1900, 2000);
+ is.Add(2100, 2200);
+
+ // Lots of different cases:
+ other.Add(50, 70); // disjoint, at the beginning
+ other.Add(2250, 2270); // disjoint, at the end
+ other.Add(650, 670); // disjoint, in the middle
+ other.Add(350, 360); // included
+ other.Add(370, 380); // also included (two at once)
+ other.Add(470, 530); // overlaps low end
+ other.Add(770, 830); // overlaps high end
+ other.Add(870, 900); // meets at low end
+ other.Add(1200, 1230); // meets at high end
+ other.Add(1270, 1830); // overlaps multiple ranges
+ }
+
+ void TearDown() override {
+ is.Clear();
+ EXPECT_TRUE(is.Empty());
+ other.Clear();
+ EXPECT_TRUE(other.Empty());
+ }
+ IntervalSet<int> is;
+ IntervalSet<int> other;
+};
+
+TEST_F(IntervalSetTest, IsDisjoint) {
+ EXPECT_TRUE(is.IsDisjoint(Interval<int>(0, 99)));
+ EXPECT_TRUE(is.IsDisjoint(Interval<int>(0, 100)));
+ EXPECT_TRUE(is.IsDisjoint(Interval<int>(200, 200)));
+ EXPECT_TRUE(is.IsDisjoint(Interval<int>(200, 299)));
+ EXPECT_TRUE(is.IsDisjoint(Interval<int>(400, 407)));
+ EXPECT_TRUE(is.IsDisjoint(Interval<int>(405, 499)));
+ EXPECT_TRUE(is.IsDisjoint(Interval<int>(2300, 2300)));
+ EXPECT_TRUE(
+ is.IsDisjoint(Interval<int>(2300, std::numeric_limits<int>::max())));
+ EXPECT_FALSE(is.IsDisjoint(Interval<int>(100, 100)));
+ EXPECT_FALSE(is.IsDisjoint(Interval<int>(100, 105)));
+ EXPECT_FALSE(is.IsDisjoint(Interval<int>(199, 300)));
+ EXPECT_FALSE(is.IsDisjoint(Interval<int>(250, 450)));
+ EXPECT_FALSE(is.IsDisjoint(Interval<int>(299, 400)));
+ EXPECT_FALSE(is.IsDisjoint(Interval<int>(250, 2000)));
+ EXPECT_FALSE(
+ is.IsDisjoint(Interval<int>(2199, std::numeric_limits<int>::max())));
+}
+
+// Base helper method for verifying the contents of an interval set.
+// Returns true iff <is> contains <count> intervals whose successive
+// endpoints match the sequence of args in <ap>:
+static bool VA_Check(const IntervalSet<int>& is, size_t count, va_list ap) {
+ vector<Interval<int>> intervals;
+ is.Get(&intervals);
+ if (count != intervals.size()) {
+ LOG(ERROR) << "Expected " << count << " intervals, got " << intervals.size()
+ << ": " << is.ToString();
+ return false;
+ }
+ if (count != is.Size()) {
+ LOG(ERROR) << "Expected " << count << " intervals, got Size " << is.Size()
+ << ": " << is.ToString();
+ return false;
+ }
+ bool result = true;
+ for (size_t i = 0; i < count; i++) {
+ int min = va_arg(ap, int);
+ int max = va_arg(ap, int);
+ if (min != intervals[i].min() || max != intervals[i].max()) {
+ LOG(ERROR) << "Expected: [" << min << ", " << max << ") got "
+ << intervals[i] << " in " << is.ToString();
+ result = false;
+ }
+ }
+ return result;
+}
+
+static bool Check(const IntervalSet<int>& is, int count, ...) {
+ va_list ap;
+ va_start(ap, count);
+ const bool result = VA_Check(is, count, ap);
+ va_end(ap);
+ return result;
+}
+
+// Some helper functions for testing Contains and Find, which are logically the
+// same.
+static void TestContainsAndFind(const IntervalSet<int>& is, int value) {
+ EXPECT_TRUE(is.Contains(value)) << "Set does not contain " << value;
+ auto it = is.Find(value);
+ EXPECT_NE(it, is.end()) << "No iterator to interval containing " << value;
+ EXPECT_TRUE(it->Contains(value)) << "Iterator does not contain " << value;
+}
+
+static void TestContainsAndFind(const IntervalSet<int>& is, int min, int max) {
+ EXPECT_TRUE(is.Contains(min, max))
+ << "Set does not contain interval with min " << min << "and max " << max;
+ auto it = is.Find(min, max);
+ EXPECT_NE(it, is.end()) << "No iterator to interval with min " << min
+ << "and max " << max;
+ EXPECT_TRUE(it->Contains(Interval<int>(min, max)))
+ << "Iterator does not contain interval with min " << min << "and max "
+ << max;
+}
+
+static void TestNotContainsAndFind(const IntervalSet<int>& is, int value) {
+ EXPECT_FALSE(is.Contains(value)) << "Set contains " << value;
+ auto it = is.Find(value);
+ EXPECT_EQ(it, is.end()) << "There is iterator to interval containing "
+ << value;
+}
+
+static void TestNotContainsAndFind(const IntervalSet<int>& is,
+ int min,
+ int max) {
+ EXPECT_FALSE(is.Contains(min, max)) << "Set contains interval with min "
+ << min << "and max " << max;
+ auto it = is.Find(min, max);
+ EXPECT_EQ(it, is.end()) << "There is iterator to interval with min " << min
+ << "and max " << max;
+}
+
+TEST_F(IntervalSetTest, IntervalSetBasic) {
+ // Test Add, Get, Contains and Find
+ IntervalSet<int> iset;
+ EXPECT_TRUE(iset.Empty());
+ EXPECT_EQ(0u, iset.Size());
+ iset.Add(100, 200);
+ EXPECT_FALSE(iset.Empty());
+ EXPECT_EQ(1u, iset.Size());
+ iset.Add(100, 150);
+ iset.Add(150, 200);
+ iset.Add(130, 170);
+ iset.Add(90, 150);
+ iset.Add(170, 220);
+ iset.Add(300, 400);
+ iset.Add(250, 450);
+ EXPECT_FALSE(iset.Empty());
+ EXPECT_EQ(2u, iset.Size());
+ EXPECT_TRUE(Check(iset, 2, 90, 220, 250, 450));
+
+ // Test two intervals with a.max == b.min, that will just join up.
+ iset.Clear();
+ iset.Add(100, 200);
+ iset.Add(200, 300);
+ EXPECT_FALSE(iset.Empty());
+ EXPECT_EQ(1u, iset.Size());
+ EXPECT_TRUE(Check(iset, 1, 100, 300));
+
+ // Test adding two sets together.
+ iset.Clear();
+ IntervalSet<int> iset_add;
+ iset.Add(100, 200);
+ iset.Add(100, 150);
+ iset.Add(150, 200);
+ iset.Add(130, 170);
+ iset_add.Add(90, 150);
+ iset_add.Add(170, 220);
+ iset_add.Add(300, 400);
+ iset_add.Add(250, 450);
+
+ iset.Add(iset_add);
+ EXPECT_FALSE(iset.Empty());
+ EXPECT_EQ(2u, iset.Size());
+ EXPECT_TRUE(Check(iset, 2, 90, 220, 250, 450));
+
+ // Test Get() (using an output iterator), begin()/end(), and rbegin()/rend()
+ // to iterate over intervals.
+ {
+ vector<Interval<int>> expected;
+ iset.Get(&expected);
+
+ vector<Interval<int>> actual1;
+ iset.Get(back_inserter(actual1));
+ ASSERT_EQ(expected.size(), actual1.size());
+
+ vector<Interval<int>> actual2;
+ std::copy(iset.begin(), iset.end(), back_inserter(actual2));
+ ASSERT_EQ(expected.size(), actual2.size());
+
+ for (size_t i = 0; i < expected.size(); i++) {
+ EXPECT_EQ(expected[i].min(), actual1[i].min());
+ EXPECT_EQ(expected[i].max(), actual1[i].max());
+
+ EXPECT_EQ(expected[i].min(), actual2[i].min());
+ EXPECT_EQ(expected[i].max(), actual2[i].max());
+ }
+
+ // Ensure that the rbegin()/rend() iterators correctly yield the intervals
+ // in reverse order.
+ EXPECT_THAT(vector<Interval<int>>(iset.rbegin(), iset.rend()),
+ ElementsAreArray(expected.rbegin(), expected.rend()));
+ }
+
+ TestNotContainsAndFind(iset, 89);
+ TestContainsAndFind(iset, 90);
+ TestContainsAndFind(iset, 120);
+ TestContainsAndFind(iset, 219);
+ TestNotContainsAndFind(iset, 220);
+ TestNotContainsAndFind(iset, 235);
+ TestNotContainsAndFind(iset, 249);
+ TestContainsAndFind(iset, 250);
+ TestContainsAndFind(iset, 300);
+ TestContainsAndFind(iset, 449);
+ TestNotContainsAndFind(iset, 450);
+ TestNotContainsAndFind(iset, 451);
+
+ TestNotContainsAndFind(iset, 50, 60);
+ TestNotContainsAndFind(iset, 50, 90);
+ TestNotContainsAndFind(iset, 50, 200);
+ TestNotContainsAndFind(iset, 90, 90);
+ TestContainsAndFind(iset, 90, 200);
+ TestContainsAndFind(iset, 100, 200);
+ TestContainsAndFind(iset, 100, 220);
+ TestNotContainsAndFind(iset, 100, 221);
+ TestNotContainsAndFind(iset, 220, 220);
+ TestNotContainsAndFind(iset, 240, 300);
+ TestContainsAndFind(iset, 250, 300);
+ TestContainsAndFind(iset, 260, 300);
+ TestContainsAndFind(iset, 300, 450);
+ TestNotContainsAndFind(iset, 300, 451);
+
+ IntervalSet<int> iset_contains;
+ iset_contains.Add(50, 90);
+ EXPECT_FALSE(iset.Contains(iset_contains));
+ iset_contains.Clear();
+
+ iset_contains.Add(90, 200);
+ EXPECT_TRUE(iset.Contains(iset_contains));
+ iset_contains.Add(100, 200);
+ EXPECT_TRUE(iset.Contains(iset_contains));
+ iset_contains.Add(100, 220);
+ EXPECT_TRUE(iset.Contains(iset_contains));
+ iset_contains.Add(250, 300);
+ EXPECT_TRUE(iset.Contains(iset_contains));
+ iset_contains.Add(300, 450);
+ EXPECT_TRUE(iset.Contains(iset_contains));
+ iset_contains.Add(300, 451);
+ EXPECT_FALSE(iset.Contains(iset_contains));
+ EXPECT_FALSE(iset.Contains(Interval<int>()));
+ EXPECT_FALSE(iset.Contains(IntervalSet<int>()));
+}
+
+TEST_F(IntervalSetTest, IntervalSetContainsEmpty) {
+ const IntervalSet<int> empty;
+ const IntervalSet<int> other_empty;
+ EXPECT_FALSE(empty.Contains(empty));
+ EXPECT_FALSE(empty.Contains(other_empty));
+// TODO(rtenneti): Implement after suupport for std::initializer_list.
+#if 0
+ const IntervalSet<int> non_empty({{10, 20}, {40, 50}});
+ EXPECT_FALSE(empty.Contains(non_empty));
+ EXPECT_FALSE(non_empty.Contains(empty));
+#endif
+}
+
+TEST_F(IntervalSetTest, Equality) {
+ IntervalSet<int> is_copy = is;
+ EXPECT_TRUE(is.Equals(is));
+ EXPECT_EQ(is, is);
+ EXPECT_TRUE(is.Equals(is_copy));
+ EXPECT_EQ(is, is_copy);
+ EXPECT_FALSE(is.Equals(other));
+ EXPECT_NE(is, other);
+ EXPECT_FALSE(is.Equals(IntervalSet<int>()));
+ EXPECT_NE(is, IntervalSet<int>());
+ EXPECT_TRUE(IntervalSet<int>().Equals(IntervalSet<int>()));
+ EXPECT_EQ(IntervalSet<int>(), IntervalSet<int>());
+}
+
+TEST_F(IntervalSetTest, SpanningInterval) {
+ // Spanning interval of an empty set is empty:
+ {
+ IntervalSet<int> iset;
+ const Interval<int>& ival = iset.SpanningInterval();
+ EXPECT_TRUE(ival.Empty());
+ }
+
+ // Spanning interval of a set with one interval is that interval:
+ {
+ IntervalSet<int> iset;
+ iset.Add(100, 200);
+ const Interval<int>& ival = iset.SpanningInterval();
+ EXPECT_EQ(100, ival.min());
+ EXPECT_EQ(200, ival.max());
+ }
+
+ // Spanning interval of a set with multiple elements is determined
+ // by the endpoints of the first and last element:
+ {
+ const Interval<int>& ival = is.SpanningInterval();
+ EXPECT_EQ(100, ival.min());
+ EXPECT_EQ(2200, ival.max());
+ }
+ {
+ const Interval<int>& ival = other.SpanningInterval();
+ EXPECT_EQ(50, ival.min());
+ EXPECT_EQ(2270, ival.max());
+ }
+}
+
+TEST_F(IntervalSetTest, IntervalSetUnion) {
+ is.Union(other);
+ EXPECT_TRUE(Check(is, 12, 50, 70, 100, 200, 300, 400, 470, 600, 650, 670, 700,
+ 830, 870, 1000, 1100, 1230, 1270, 1830, 1900, 2000, 2100,
+ 2200, 2250, 2270));
+}
+
+TEST_F(IntervalSetTest, IntervalSetIntersection) {
+ EXPECT_TRUE(is.Intersects(other));
+ EXPECT_TRUE(other.Intersects(is));
+ is.Intersection(other);
+ EXPECT_TRUE(Check(is, 7, 350, 360, 370, 380, 500, 530, 770, 800, 1300, 1400,
+ 1500, 1600, 1700, 1800));
+ EXPECT_TRUE(is.Intersects(other));
+ EXPECT_TRUE(other.Intersects(is));
+}
+
+TEST_F(IntervalSetTest, IntervalSetIntersectionBothEmpty) {
+ IntervalSet<string> mine, theirs;
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(IntervalSetTest, IntervalSetIntersectionEmptyMine) {
+ IntervalSet<string> mine;
+ IntervalSet<string> theirs("a", "b");
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(IntervalSetTest, IntervalSetIntersectionEmptyTheirs) {
+ IntervalSet<string> mine("a", "b");
+ IntervalSet<string> theirs;
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(IntervalSetTest, IntervalSetIntersectionTheirsBeforeMine) {
+ IntervalSet<string> mine("y", "z");
+ IntervalSet<string> theirs;
+ theirs.Add("a", "b");
+ theirs.Add("c", "d");
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(IntervalSetTest, IntervalSetIntersectionMineBeforeTheirs) {
+ IntervalSet<string> mine;
+ mine.Add("a", "b");
+ mine.Add("c", "d");
+ IntervalSet<string> theirs("y", "z");
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+// TODO(rtenneti): Implement after suupport for std::initializer_list.
+#if 0
+TEST_F(IntervalSetTest,
+ IntervalSetIntersectionTheirsBeforeMineInt64Singletons) {
+ IntervalSet<int64_t> mine({{10, 15}});
+ IntervalSet<int64_t> theirs({{-20, -5}});
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(IntervalSetTest, IntervalSetIntersectionMineBeforeTheirsIntSingletons) {
+ IntervalSet<int> mine({{10, 15}});
+ IntervalSet<int> theirs({{90, 95}});
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(IntervalSetTest, IntervalSetIntersectionTheirsBetweenMine) {
+ IntervalSet<int64_t> mine({{0, 5}, {40, 50}});
+ IntervalSet<int64_t> theirs({{10, 15}});
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+TEST_F(IntervalSetTest, IntervalSetIntersectionMineBetweenTheirs) {
+ IntervalSet<int> mine({{20, 25}});
+ IntervalSet<int> theirs({{10, 15}, {30, 32}});
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+#endif // 0
+
+TEST_F(IntervalSetTest, IntervalSetIntersectionAlternatingIntervals) {
+ IntervalSet<int> mine, theirs;
+ mine.Add(10, 20);
+ mine.Add(40, 50);
+ mine.Add(60, 70);
+ theirs.Add(25, 39);
+ theirs.Add(55, 59);
+ theirs.Add(75, 79);
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(mine.Empty());
+ EXPECT_FALSE(mine.Intersects(theirs));
+ EXPECT_FALSE(theirs.Intersects(mine));
+}
+
+// TODO(rtenneti): Implement after suupport for std::initializer_list.
+#if 0
+TEST_F(IntervalSetTest,
+ IntervalSetIntersectionAdjacentAlternatingNonIntersectingIntervals) {
+ // Make sure that intersection with adjacent interval set is empty.
+ const IntervalSet<int> x1({{0, 10}});
+ const IntervalSet<int> y1({{-50, 0}, {10, 95}});
+
+ IntervalSet<int> result1 = x1;
+ result1.Intersection(y1);
+ EXPECT_TRUE(result1.Empty()) << result1;
+
+ const IntervalSet<int16_t> x2({{0, 10}, {20, 30}, {40, 90}});
+ const IntervalSet<int16_t> y2(
+ {{-50, -40}, {-2, 0}, {10, 20}, {32, 40}, {90, 95}});
+
+ IntervalSet<int16_t> result2 = x2;
+ result2.Intersection(y2);
+ EXPECT_TRUE(result2.Empty()) << result2;
+
+ const IntervalSet<int64_t> x3({{-1, 5}, {5, 10}});
+ const IntervalSet<int64_t> y3({{-10, -1}, {10, 95}});
+
+ IntervalSet<int64_t> result3 = x3;
+ result3.Intersection(y3);
+ EXPECT_TRUE(result3.Empty()) << result3;
+}
+
+TEST_F(IntervalSetTest,
+ IntervalSetIntersectionAlternatingIntersectingIntervals) {
+ const IntervalSet<int> x1({{0, 10}});
+ const IntervalSet<int> y1({{-50, 1}, {9, 95}});
+ const IntervalSet<int> expected_result1({{0, 1}, {9, 10}});
+
+ IntervalSet<int> result1 = x1;
+ result1.Intersection(y1);
+ EXPECT_EQ(result1, expected_result1);
+
+ const IntervalSet<int16_t> x2({{0, 10}, {20, 30}, {40, 90}});
+ const IntervalSet<int16_t> y2(
+ {{-50, -40}, {-2, 2}, {9, 21}, {32, 41}, {85, 95}});
+ const IntervalSet<int16_t> expected_result2(
+ {{0, 2}, {9, 10}, {20, 21}, {40, 41}, {85, 90}});
+
+ IntervalSet<int16_t> result2 = x2;
+ result2.Intersection(y2);
+ EXPECT_EQ(result2, expected_result2);
+
+ const IntervalSet<int64_t> x3({{-1, 5}, {5, 10}});
+ const IntervalSet<int64_t> y3({{-10, 3}, {4, 95}});
+ const IntervalSet<int64_t> expected_result3({{-1, 3}, {4, 10}});
+
+ IntervalSet<int64_t> result3 = x3;
+ result3.Intersection(y3);
+ EXPECT_EQ(result3, expected_result3);
+}
+
+#endif // 0
+
+TEST_F(IntervalSetTest, IntervalSetIntersectionIdentical) {
+ IntervalSet<int> copy(is);
+ EXPECT_TRUE(copy.Intersects(is));
+ EXPECT_TRUE(is.Intersects(copy));
+ is.Intersection(copy);
+ EXPECT_EQ(copy, is);
+}
+
+TEST_F(IntervalSetTest, IntervalSetIntersectionSuperset) {
+ IntervalSet<int> mine(-1, 10000);
+ EXPECT_TRUE(mine.Intersects(is));
+ EXPECT_TRUE(is.Intersects(mine));
+ mine.Intersection(is);
+ EXPECT_EQ(is, mine);
+}
+
+TEST_F(IntervalSetTest, IntervalSetIntersectionSubset) {
+ IntervalSet<int> copy(is);
+ IntervalSet<int> theirs(-1, 10000);
+ EXPECT_TRUE(copy.Intersects(theirs));
+ EXPECT_TRUE(theirs.Intersects(copy));
+ is.Intersection(theirs);
+ EXPECT_EQ(copy, is);
+}
+
+TEST_F(IntervalSetTest, IntervalSetIntersectionLargeSet) {
+ IntervalSet<int> mine, theirs;
+ // mine: [0, 9), [10, 19), ..., [990, 999)
+ for (int i = 0; i < 1000; i += 10) {
+ mine.Add(i, i + 9);
+ }
+
+ theirs.Add(500, 520);
+ theirs.Add(535, 545);
+ theirs.Add(801, 809);
+ EXPECT_TRUE(mine.Intersects(theirs));
+ EXPECT_TRUE(theirs.Intersects(mine));
+ mine.Intersection(theirs);
+ EXPECT_TRUE(Check(mine, 5, 500, 509, 510, 519, 535, 539, 540, 545, 801, 809));
+ EXPECT_TRUE(mine.Intersects(theirs));
+ EXPECT_TRUE(theirs.Intersects(mine));
+}
+
+TEST_F(IntervalSetTest, IntervalSetDifference) {
+ is.Difference(other);
+ EXPECT_TRUE(Check(is, 10, 100, 200, 300, 350, 360, 370, 380, 400, 530, 600,
+ 700, 770, 900, 1000, 1100, 1200, 1900, 2000, 2100, 2200));
+ IntervalSet<int> copy = is;
+ is.Difference(copy);
+ EXPECT_TRUE(is.Empty());
+}
+
+TEST_F(IntervalSetTest, IntervalSetDifferenceSingleBounds) {
+ vector<Interval<int>> ivals;
+ other.Get(&ivals);
+ for (size_t i = 0; i < ivals.size(); ++i) {
+ is.Difference(ivals[i].min(), ivals[i].max());
+ }
+ EXPECT_TRUE(Check(is, 10, 100, 200, 300, 350, 360, 370, 380, 400, 530, 600,
+ 700, 770, 900, 1000, 1100, 1200, 1900, 2000, 2100, 2200));
+}
+
+TEST_F(IntervalSetTest, IntervalSetDifferenceSingleInterval) {
+ vector<Interval<int>> ivals;
+ other.Get(&ivals);
+ for (size_t i = 0; i < ivals.size(); ++i) {
+ is.Difference(ivals[i]);
+ }
+ EXPECT_TRUE(Check(is, 10, 100, 200, 300, 350, 360, 370, 380, 400, 530, 600,
+ 700, 770, 900, 1000, 1100, 1200, 1900, 2000, 2100, 2200));
+}
+
+TEST_F(IntervalSetTest, IntervalSetDifferenceAlternatingIntervals) {
+ IntervalSet<int> mine, theirs;
+ mine.Add(10, 20);
+ mine.Add(40, 50);
+ mine.Add(60, 70);
+ theirs.Add(25, 39);
+ theirs.Add(55, 59);
+ theirs.Add(75, 79);
+
+ mine.Difference(theirs);
+ EXPECT_TRUE(Check(mine, 3, 10, 20, 40, 50, 60, 70));
+}
+
+TEST_F(IntervalSetTest, IntervalSetDifferenceEmptyMine) {
+ IntervalSet<string> mine, theirs;
+ theirs.Add("a", "b");
+
+ mine.Difference(theirs);
+ EXPECT_TRUE(mine.Empty());
+}
+
+TEST_F(IntervalSetTest, IntervalSetDifferenceEmptyTheirs) {
+ IntervalSet<string> mine, theirs;
+ mine.Add("a", "b");
+
+ mine.Difference(theirs);
+ EXPECT_EQ(1u, mine.Size());
+ EXPECT_EQ("a", mine.begin()->min());
+ EXPECT_EQ("b", mine.begin()->max());
+}
+
+TEST_F(IntervalSetTest, IntervalSetDifferenceTheirsBeforeMine) {
+ IntervalSet<string> mine, theirs;
+ mine.Add("y", "z");
+ theirs.Add("a", "b");
+
+ mine.Difference(theirs);
+ EXPECT_EQ(1u, mine.Size());
+ EXPECT_EQ("y", mine.begin()->min());
+ EXPECT_EQ("z", mine.begin()->max());
+}
+
+TEST_F(IntervalSetTest, IntervalSetDifferenceMineBeforeTheirs) {
+ IntervalSet<string> mine, theirs;
+ mine.Add("a", "b");
+ theirs.Add("y", "z");
+
+ mine.Difference(theirs);
+ EXPECT_EQ(1u, mine.Size());
+ EXPECT_EQ("a", mine.begin()->min());
+ EXPECT_EQ("b", mine.begin()->max());
+}
+
+TEST_F(IntervalSetTest, IntervalSetDifferenceIdentical) {
+ IntervalSet<string> mine;
+ mine.Add("a", "b");
+ mine.Add("c", "d");
+ IntervalSet<string> theirs(mine);
+
+ mine.Difference(theirs);
+ EXPECT_TRUE(mine.Empty());
+}
+
+TEST_F(IntervalSetTest, EmptyComplement) {
+ // The complement of an empty set is the input interval:
+ IntervalSet<int> iset;
+ iset.Complement(100, 200);
+ EXPECT_TRUE(Check(iset, 1, 100, 200));
+}
+
+TEST(IntervalSetMultipleCompactionTest, OuterCovering) {
+ IntervalSet<int> iset;
+ // First add a bunch of disjoint ranges
+ iset.Add(100, 150);
+ iset.Add(200, 250);
+ iset.Add(300, 350);
+ iset.Add(400, 450);
+ EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450));
+ // Now add a big range that covers all of these ranges
+ iset.Add(0, 500);
+ EXPECT_TRUE(Check(iset, 1, 0, 500));
+}
+
+TEST(IntervalSetMultipleCompactionTest, InnerCovering) {
+ IntervalSet<int> iset;
+ // First add a bunch of disjoint ranges
+ iset.Add(100, 150);
+ iset.Add(200, 250);
+ iset.Add(300, 350);
+ iset.Add(400, 450);
+ EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450));
+ // Now add a big range that partially covers the left and right most ranges.
+ iset.Add(125, 425);
+ EXPECT_TRUE(Check(iset, 1, 100, 450));
+}
+
+TEST(IntervalSetMultipleCompactionTest, LeftCovering) {
+ IntervalSet<int> iset;
+ // First add a bunch of disjoint ranges
+ iset.Add(100, 150);
+ iset.Add(200, 250);
+ iset.Add(300, 350);
+ iset.Add(400, 450);
+ EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450));
+ // Now add a big range that partially covers the left most range.
+ iset.Add(125, 500);
+ EXPECT_TRUE(Check(iset, 1, 100, 500));
+}
+
+TEST(IntervalSetMultipleCompactionTest, RightCovering) {
+ IntervalSet<int> iset;
+ // First add a bunch of disjoint ranges
+ iset.Add(100, 150);
+ iset.Add(200, 250);
+ iset.Add(300, 350);
+ iset.Add(400, 450);
+ EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450));
+ // Now add a big range that partially covers the right most range.
+ iset.Add(0, 425);
+ EXPECT_TRUE(Check(iset, 1, 0, 450));
+}
+
+// Helper method for testing and verifying the results of a one-interval
+// completement case.
+static bool CheckOneComplement(int add_min,
+ int add_max,
+ int comp_min,
+ int comp_max,
+ int count,
+ ...) {
+ IntervalSet<int> iset;
+ iset.Add(add_min, add_max);
+ iset.Complement(comp_min, comp_max);
+ bool result = true;
+ va_list ap;
+ va_start(ap, count);
+ if (!VA_Check(iset, count, ap)) {
+ result = false;
+ }
+ va_end(ap);
+ return result;
+}
+
+TEST_F(IntervalSetTest, SingleIntervalComplement) {
+ // Verify the complement of a set with one interval (i):
+ // |----- i -----|
+ // |----- args -----|
+ EXPECT_TRUE(CheckOneComplement(0, 10, 50, 150, 1, 50, 150));
+
+ // |----- i -----|
+ // |----- args -----|
+ EXPECT_TRUE(CheckOneComplement(50, 150, 0, 100, 1, 0, 50));
+
+ // |----- i -----|
+ // |----- args -----|
+ EXPECT_TRUE(CheckOneComplement(50, 150, 50, 150, 0));
+
+ // |---------- i ----------|
+ // |----- args -----|
+ EXPECT_TRUE(CheckOneComplement(50, 500, 100, 300, 0));
+
+ // |----- i -----|
+ // |---------- args ----------|
+ EXPECT_TRUE(CheckOneComplement(50, 500, 0, 800, 2, 0, 50, 500, 800));
+
+ // |----- i -----|
+ // |----- args -----|
+ EXPECT_TRUE(CheckOneComplement(50, 150, 100, 300, 1, 150, 300));
+
+ // |----- i -----|
+ // |----- args -----|
+ EXPECT_TRUE(CheckOneComplement(50, 150, 200, 300, 1, 200, 300));
+}
+
+// Helper method that copies <iset> and takes its complement,
+// returning false if Check succeeds.
+static bool CheckComplement(const IntervalSet<int>& iset,
+ int comp_min,
+ int comp_max,
+ int count,
+ ...) {
+ IntervalSet<int> iset_copy = iset;
+ iset_copy.Complement(comp_min, comp_max);
+ bool result = true;
+ va_list ap;
+ va_start(ap, count);
+ if (!VA_Check(iset_copy, count, ap)) {
+ result = false;
+ }
+ va_end(ap);
+ return result;
+}
+
+TEST_F(IntervalSetTest, MultiIntervalComplement) {
+ // Initialize a small test set:
+ IntervalSet<int> iset;
+ iset.Add(100, 200);
+ iset.Add(300, 400);
+ iset.Add(500, 600);
+
+ // |----- i -----|
+ // |----- comp -----|
+ EXPECT_TRUE(CheckComplement(iset, 0, 50, 1, 0, 50));
+
+ // |----- i -----|
+ // |----- comp -----|
+ EXPECT_TRUE(CheckComplement(iset, 0, 200, 1, 0, 100));
+ EXPECT_TRUE(CheckComplement(iset, 0, 220, 2, 0, 100, 200, 220));
+
+ // |----- i -----|
+ // |----- comp -----|
+ EXPECT_TRUE(CheckComplement(iset, 100, 600, 2, 200, 300, 400, 500));
+
+ // |---------- i ----------|
+ // |----- comp -----|
+ EXPECT_TRUE(CheckComplement(iset, 300, 400, 0));
+ EXPECT_TRUE(CheckComplement(iset, 250, 400, 1, 250, 300));
+ EXPECT_TRUE(CheckComplement(iset, 300, 450, 1, 400, 450));
+ EXPECT_TRUE(CheckComplement(iset, 250, 450, 2, 250, 300, 400, 450));
+
+ // |----- i -----|
+ // |---------- comp ----------|
+ EXPECT_TRUE(
+ CheckComplement(iset, 0, 700, 4, 0, 100, 200, 300, 400, 500, 600, 700));
+
+ // |----- i -----|
+ // |----- comp -----|
+ EXPECT_TRUE(CheckComplement(iset, 400, 700, 2, 400, 500, 600, 700));
+ EXPECT_TRUE(CheckComplement(iset, 350, 700, 2, 400, 500, 600, 700));
+
+ // |----- i -----|
+ // |----- comp -----|
+ EXPECT_TRUE(CheckComplement(iset, 700, 800, 1, 700, 800));
+}
+
+// Verifies ToString, operator<< don't assert.
+// TODO(rtenneti): Implement ToString() method of IntervalSet.
+TEST_F(IntervalSetTest, DISABLED_ToString) {
+ IntervalSet<int> iset;
+ iset.Add(300, 400);
+ iset.Add(100, 200);
+ iset.Add(500, 600);
+ EXPECT_TRUE(!iset.ToString().empty());
+ VLOG(2) << iset.ToString();
+ // Order and format of ToString() output is guaranteed.
+ EXPECT_EQ("[100, 200) [300, 400) [500, 600)", iset.ToString());
+ EXPECT_EQ("[1, 2)", IntervalSet<int>(1, 2).ToString());
+ EXPECT_EQ("", IntervalSet<int>().ToString());
+}
+
+TEST_F(IntervalSetTest, ConstructionDiscardsEmptyInterval) {
+ EXPECT_TRUE(IntervalSet<int>(Interval<int>(2, 2)).Empty());
+ EXPECT_TRUE(IntervalSet<int>(2, 2).Empty());
+ EXPECT_FALSE(IntervalSet<int>(Interval<int>(2, 3)).Empty());
+ EXPECT_FALSE(IntervalSet<int>(2, 3).Empty());
+}
+
+TEST_F(IntervalSetTest, Swap) {
+ IntervalSet<int> a, b;
+ a.Add(300, 400);
+ b.Add(100, 200);
+ b.Add(500, 600);
+ a.Swap(&b);
+ EXPECT_TRUE(Check(a, 2, 100, 200, 500, 600));
+ EXPECT_TRUE(Check(b, 1, 300, 400));
+ swap(a, b);
+ EXPECT_TRUE(Check(a, 1, 300, 400));
+ EXPECT_TRUE(Check(b, 2, 100, 200, 500, 600));
+}
+
+// TODO(rtenneti): Enabled these tests.
+#if 0
+static void BM_Difference(int iters) {
+ // StopBenchmarkTiming();
+ IntervalSet<int> difference_set;
+ int start = 10;
+ for (int i = 0; i < 1000000; ++i) {
+ difference_set.Add(start, start+5);
+ start += 7;
+ }
+
+ // Create an interval somewhere in the middle of the difference set.
+ // StartBenchmarkTiming();
+ for (int i = 0; i < iters; ++i) {
+ IntervalSet<int> initial(1000000, 1000020);
+ initial.Difference(difference_set);
+ }
+}
+
+BENCHMARK(BM_Difference);
+
+static void BM_IntersectionSmallAndLarge(int iters, int size) {
+ // Intersects constant size 'mine' with large 'theirs'.
+ StopBenchmarkTiming();
+ IntervalSet<int> theirs;
+ for (int i = 0; i < size; ++i) {
+ theirs.Add(2 * i, 2 * i + 1);
+ }
+
+ StartBenchmarkTiming();
+ for (int i = 0; i < iters; ++i) {
+ // 'mine' starts in the middle of 'theirs'.
+ IntervalSet<int> mine(size, size + 10);
+ mine.Intersection(theirs);
+ }
+}
+
+BENCHMARK_RANGE(BM_IntersectionSmallAndLarge, 0, 1 << 23);
+
+static void BM_IntersectionIdentical(int iters, int size) {
+ // Intersects identical 'mine' and 'theirs'.
+ StopBenchmarkTiming();
+ IntervalSet<int> mine;
+ for (int i = 0; i < size; ++i) {
+ mine.Add(2 * i, 2 * i + 1);
+ }
+ IntervalSet<int> theirs(mine);
+
+ StartBenchmarkTiming();
+ for (int i = 0; i < iters; ++i) {
+ mine.Intersection(theirs);
+ }
+}
+
+BENCHMARK_RANGE(BM_IntersectionIdentical, 0, 1 << 23);
+
+class IntervalSetInitTest : public testing::Test {
+ protected:
+ const std::vector<Interval<int>> intervals_{{0, 1}, {2, 4}};
+};
+
+TEST_F(IntervalSetInitTest, DirectInit) {
+ std::initializer_list<Interval<int>> il = {{0, 1}, {2, 3}, {3, 4}};
+ IntervalSet<int> s(il);
+ EXPECT_THAT(s, ElementsAreArray(intervals_));
+}
+
+TEST_F(IntervalSetInitTest, CopyInit) {
+ std::initializer_list<Interval<int>> il = {{0, 1}, {2, 3}, {3, 4}};
+ IntervalSet<int> s = il;
+ EXPECT_THAT(s, ElementsAreArray(intervals_));
+}
+
+TEST_F(IntervalSetInitTest, AssignIterPair) {
+ IntervalSet<int> s(0, 1000); // Make sure assign clears.
+ s.assign(intervals_.begin(), intervals_.end());
+ EXPECT_THAT(s, ElementsAreArray(intervals_));
+}
+
+TEST_F(IntervalSetInitTest, AssignInitList) {
+ IntervalSet<int> s(0, 1000); // Make sure assign clears.
+ s.assign({{0, 1}, {2, 3}, {3, 4}});
+ EXPECT_THAT(s, ElementsAreArray(intervals_));
+}
+
+TEST_F(IntervalSetInitTest, AssignmentInitList) {
+ std::initializer_list<Interval<int>> il = {{0, 1}, {2, 3}, {3, 4}};
+ IntervalSet<int> s;
+ s = il;
+ EXPECT_THAT(s, ElementsAreArray(intervals_));
+}
+
+TEST_F(IntervalSetInitTest, BracedInitThenBracedAssign) {
+ IntervalSet<int> s{{0, 1}, {2, 3}, {3, 4}};
+ s = {{0, 1}, {2, 4}};
+ EXPECT_THAT(s, ElementsAreArray(intervals_));
+}
+
+#endif // 0
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/interval_test.cc b/chromium/net/quic/core/interval_test.cc
new file mode 100644
index 00000000000..2e52c5b8c21
--- /dev/null
+++ b/chromium/net/quic/core/interval_test.cc
@@ -0,0 +1,283 @@
+// Copyright 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.
+//
+// ----------------------------------------------------------------------
+//
+// Unittest for the Interval class.
+//
+// Author: Will Neveitt (wneveitt@google.com)
+// ----------------------------------------------------------------------
+
+#include "net/quic/core/interval.h"
+
+#include "base/logging.h"
+#include "net/test/gtest_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::pair;
+using std::string;
+using std::vector;
+
+namespace net {
+namespace test {
+namespace {
+
+class IntervalTest : public ::testing::Test {
+ protected:
+ // Test intersection between the two intervals i1 and i2. Tries
+ // i1.IntersectWith(i2) and vice versa. The intersection should change i1 iff
+ // changes_i1 is true, and the same for changes_i2. The resulting
+ // intersection should be result.
+ void TestIntersect(const Interval<int64_t>& i1,
+ const Interval<int64_t>& i2,
+ bool changes_i1,
+ bool changes_i2,
+ const Interval<int64_t>& result) {
+ Interval<int64_t> i;
+ i.CopyFrom(i1);
+ EXPECT_TRUE(i.IntersectWith(i2) == changes_i1 && i.Equals(result));
+ i.CopyFrom(i2);
+ EXPECT_TRUE(i.IntersectWith(i1) == changes_i2 && i.Equals(result));
+ }
+};
+
+TEST_F(IntervalTest, ConstructorsCopyAndClear) {
+ Interval<int32_t> empty;
+ EXPECT_TRUE(empty.Empty());
+
+ Interval<int32_t> d2(0, 100);
+ EXPECT_EQ(0, d2.min());
+ EXPECT_EQ(100, d2.max());
+ EXPECT_EQ(Interval<int32_t>(0, 100), d2);
+ EXPECT_NE(Interval<int32_t>(0, 99), d2);
+
+ empty.CopyFrom(d2);
+ EXPECT_EQ(0, d2.min());
+ EXPECT_EQ(100, d2.max());
+ EXPECT_TRUE(empty.Equals(d2));
+ EXPECT_EQ(empty, d2);
+ EXPECT_TRUE(d2.Equals(empty));
+ EXPECT_EQ(d2, empty);
+
+ Interval<int32_t> max_less_than_min(40, 20);
+ EXPECT_TRUE(max_less_than_min.Empty());
+ EXPECT_EQ(40, max_less_than_min.min());
+ EXPECT_EQ(20, max_less_than_min.max());
+
+ Interval<int> d3(10, 20);
+ d3.Clear();
+ EXPECT_TRUE(d3.Empty());
+}
+
+TEST_F(IntervalTest, GettersSetters) {
+ Interval<int32_t> d1(100, 200);
+
+ // SetMin:
+ d1.SetMin(30);
+ EXPECT_EQ(30, d1.min());
+ EXPECT_EQ(200, d1.max());
+
+ // SetMax:
+ d1.SetMax(220);
+ EXPECT_EQ(30, d1.min());
+ EXPECT_EQ(220, d1.max());
+
+ // Set:
+ d1.Clear();
+ d1.Set(30, 220);
+ EXPECT_EQ(30, d1.min());
+ EXPECT_EQ(220, d1.max());
+
+ // SpanningUnion:
+ Interval<int32_t> d2;
+ EXPECT_TRUE(!d1.SpanningUnion(d2));
+ EXPECT_EQ(30, d1.min());
+ EXPECT_EQ(220, d1.max());
+
+ EXPECT_TRUE(d2.SpanningUnion(d1));
+ EXPECT_EQ(30, d2.min());
+ EXPECT_EQ(220, d2.max());
+
+ d2.SetMin(40);
+ d2.SetMax(100);
+ EXPECT_TRUE(!d1.SpanningUnion(d2));
+ EXPECT_EQ(30, d1.min());
+ EXPECT_EQ(220, d1.max());
+
+ d2.SetMin(20);
+ d2.SetMax(100);
+ EXPECT_TRUE(d1.SpanningUnion(d2));
+ EXPECT_EQ(20, d1.min());
+ EXPECT_EQ(220, d1.max());
+
+ d2.SetMin(50);
+ d2.SetMax(300);
+ EXPECT_TRUE(d1.SpanningUnion(d2));
+ EXPECT_EQ(20, d1.min());
+ EXPECT_EQ(300, d1.max());
+
+ d2.SetMin(0);
+ d2.SetMax(500);
+ EXPECT_TRUE(d1.SpanningUnion(d2));
+ EXPECT_EQ(0, d1.min());
+ EXPECT_EQ(500, d1.max());
+
+ d2.SetMin(100);
+ d2.SetMax(0);
+ EXPECT_TRUE(!d1.SpanningUnion(d2));
+ EXPECT_EQ(0, d1.min());
+ EXPECT_EQ(500, d1.max());
+ EXPECT_TRUE(d2.SpanningUnion(d1));
+ EXPECT_EQ(0, d2.min());
+ EXPECT_EQ(500, d2.max());
+}
+
+TEST_F(IntervalTest, CoveringOps) {
+ const Interval<int64_t> empty;
+ const Interval<int64_t> d(100, 200);
+ const Interval<int64_t> d1(0, 50);
+ const Interval<int64_t> d2(50, 110);
+ const Interval<int64_t> d3(110, 180);
+ const Interval<int64_t> d4(180, 220);
+ const Interval<int64_t> d5(220, 300);
+ const Interval<int64_t> d6(100, 150);
+ const Interval<int64_t> d7(150, 200);
+ const Interval<int64_t> d8(0, 300);
+
+ // Intersection:
+ EXPECT_TRUE(d.Intersects(d));
+ EXPECT_TRUE(!empty.Intersects(d) && !d.Intersects(empty));
+ EXPECT_TRUE(!d.Intersects(d1) && !d1.Intersects(d));
+ EXPECT_TRUE(d.Intersects(d2) && d2.Intersects(d));
+ EXPECT_TRUE(d.Intersects(d3) && d3.Intersects(d));
+ EXPECT_TRUE(d.Intersects(d4) && d4.Intersects(d));
+ EXPECT_TRUE(!d.Intersects(d5) && !d5.Intersects(d));
+ EXPECT_TRUE(d.Intersects(d6) && d6.Intersects(d));
+ EXPECT_TRUE(d.Intersects(d7) && d7.Intersects(d));
+ EXPECT_TRUE(d.Intersects(d8) && d8.Intersects(d));
+
+ Interval<int64_t> i;
+ EXPECT_TRUE(d.Intersects(d, &i) && d.Equals(i));
+ EXPECT_TRUE(!empty.Intersects(d, NULL) && !d.Intersects(empty, NULL));
+ EXPECT_TRUE(!d.Intersects(d1, NULL) && !d1.Intersects(d, NULL));
+ EXPECT_TRUE(d.Intersects(d2, &i) && i.Equals(Interval<int64_t>(100, 110)));
+ EXPECT_TRUE(d2.Intersects(d, &i) && i.Equals(Interval<int64_t>(100, 110)));
+ EXPECT_TRUE(d.Intersects(d3, &i) && i.Equals(d3));
+ EXPECT_TRUE(d3.Intersects(d, &i) && i.Equals(d3));
+ EXPECT_TRUE(d.Intersects(d4, &i) && i.Equals(Interval<int64_t>(180, 200)));
+ EXPECT_TRUE(d4.Intersects(d, &i) && i.Equals(Interval<int64_t>(180, 200)));
+ EXPECT_TRUE(!d.Intersects(d5, NULL) && !d5.Intersects(d, NULL));
+ EXPECT_TRUE(d.Intersects(d6, &i) && i.Equals(d6));
+ EXPECT_TRUE(d6.Intersects(d, &i) && i.Equals(d6));
+ EXPECT_TRUE(d.Intersects(d7, &i) && i.Equals(d7));
+ EXPECT_TRUE(d7.Intersects(d, &i) && i.Equals(d7));
+ EXPECT_TRUE(d.Intersects(d8, &i) && i.Equals(d));
+ EXPECT_TRUE(d8.Intersects(d, &i) && i.Equals(d));
+
+ // Test IntersectsWith().
+ // Arguments are TestIntersect(i1, i2, changes_i1, changes_i2, result).
+ TestIntersect(empty, d, false, true, empty);
+ TestIntersect(d, d1, true, true, empty);
+ TestIntersect(d1, d2, true, true, empty);
+ TestIntersect(d, d2, true, true, Interval<int64_t>(100, 110));
+ TestIntersect(d8, d, true, false, d);
+ TestIntersect(d8, d1, true, false, d1);
+ TestIntersect(d8, d5, true, false, d5);
+
+ // Contains:
+ EXPECT_TRUE(!empty.Contains(d) && !d.Contains(empty));
+ EXPECT_TRUE(d.Contains(d));
+ EXPECT_TRUE(!d.Contains(d1) && !d1.Contains(d));
+ EXPECT_TRUE(!d.Contains(d2) && !d2.Contains(d));
+ EXPECT_TRUE(d.Contains(d3) && !d3.Contains(d));
+ EXPECT_TRUE(!d.Contains(d4) && !d4.Contains(d));
+ EXPECT_TRUE(!d.Contains(d5) && !d5.Contains(d));
+ EXPECT_TRUE(d.Contains(d6) && !d6.Contains(d));
+ EXPECT_TRUE(d.Contains(d7) && !d7.Contains(d));
+ EXPECT_TRUE(!d.Contains(d8) && d8.Contains(d));
+
+ EXPECT_TRUE(d.Contains(100));
+ EXPECT_TRUE(!d.Contains(200));
+ EXPECT_TRUE(d.Contains(150));
+ EXPECT_TRUE(!d.Contains(99));
+ EXPECT_TRUE(!d.Contains(201));
+
+ // Difference:
+ Interval<int64_t> lo;
+ Interval<int64_t> hi;
+
+ EXPECT_TRUE(d.Difference(d2, &lo, &hi));
+ EXPECT_TRUE(lo.Empty());
+ EXPECT_EQ(110u, hi.min());
+ EXPECT_EQ(200u, hi.max());
+
+ EXPECT_TRUE(d.Difference(d3, &lo, &hi));
+ EXPECT_EQ(100u, lo.min());
+ EXPECT_EQ(110u, lo.max());
+ EXPECT_EQ(180u, hi.min());
+ EXPECT_EQ(200u, hi.max());
+
+ EXPECT_TRUE(d.Difference(d4, &lo, &hi));
+ EXPECT_EQ(100u, lo.min());
+ EXPECT_EQ(180u, lo.max());
+ EXPECT_TRUE(hi.Empty());
+
+ EXPECT_FALSE(d.Difference(d5, &lo, &hi));
+ EXPECT_EQ(100u, lo.min());
+ EXPECT_EQ(200u, lo.max());
+ EXPECT_TRUE(hi.Empty());
+
+ EXPECT_TRUE(d.Difference(d6, &lo, &hi));
+ EXPECT_TRUE(lo.Empty());
+ EXPECT_EQ(150u, hi.min());
+ EXPECT_EQ(200u, hi.max());
+
+ EXPECT_TRUE(d.Difference(d7, &lo, &hi));
+ EXPECT_EQ(100u, lo.min());
+ EXPECT_EQ(150u, lo.max());
+ EXPECT_TRUE(hi.Empty());
+
+ EXPECT_TRUE(d.Difference(d8, &lo, &hi));
+ EXPECT_TRUE(lo.Empty());
+ EXPECT_TRUE(hi.Empty());
+}
+
+TEST_F(IntervalTest, Length) {
+ const Interval<int> empty1;
+ const Interval<int> empty2(1, 1);
+ const Interval<int> empty3(1, 0);
+ const Interval<base::TimeDelta> empty4(
+ base::TimeDelta() + base::TimeDelta::FromSeconds(1), base::TimeDelta());
+ const Interval<int> d1(1, 2);
+ const Interval<int> d2(0, 50);
+ const Interval<base::TimeDelta> d3(
+ base::TimeDelta(), base::TimeDelta() + base::TimeDelta::FromSeconds(1));
+ const Interval<base::TimeDelta> d4(
+ base::TimeDelta() + base::TimeDelta::FromHours(1),
+ base::TimeDelta() + base::TimeDelta::FromMinutes(90));
+
+ EXPECT_EQ(0, empty1.Length());
+ EXPECT_EQ(0, empty2.Length());
+ EXPECT_EQ(0, empty3.Length());
+ EXPECT_EQ(base::TimeDelta(), empty4.Length());
+ EXPECT_EQ(1, d1.Length());
+ EXPECT_EQ(50, d2.Length());
+ EXPECT_EQ(base::TimeDelta::FromSeconds(1), d3.Length());
+ EXPECT_EQ(base::TimeDelta::FromMinutes(30), d4.Length());
+}
+
+TEST_F(IntervalTest, IntervalOfTypeWithNoOperatorMinus) {
+ // Interval<T> should work even if T does not support operator-(). We just
+ // can't call Interval<T>::Length() for such types.
+ const Interval<string> d1("a", "b");
+ const Interval<pair<int, int>> d2({1, 2}, {4, 3});
+ EXPECT_EQ("a", d1.min());
+ EXPECT_EQ("b", d1.max());
+ EXPECT_EQ(std::make_pair(1, 2), d2.min());
+ EXPECT_EQ(std::make_pair(4, 3), d2.max());
+}
+
+} // unnamed namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/iovector.cc b/chromium/net/quic/core/iovector.cc
new file mode 100644
index 00000000000..d7c919c9475
--- /dev/null
+++ b/chromium/net/quic/core/iovector.cc
@@ -0,0 +1,15 @@
+// Copyright 2013 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/iovector.h"
+
+namespace net {
+
+IOVector::IOVector() {}
+
+IOVector::IOVector(const IOVector& other) = default;
+
+IOVector::~IOVector() {}
+
+} // namespace net
diff --git a/chromium/net/quic/iovector.h b/chromium/net/quic/core/iovector.h
index cf77a9acc26..cf77a9acc26 100644
--- a/chromium/net/quic/iovector.h
+++ b/chromium/net/quic/core/iovector.h
diff --git a/chromium/net/quic/core/iovector_test.cc b/chromium/net/quic/core/iovector_test.cc
new file mode 100644
index 00000000000..06b40bdf9a0
--- /dev/null
+++ b/chromium/net/quic/core/iovector_test.cc
@@ -0,0 +1,373 @@
+// Copyright 2013 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/iovector.h"
+
+#include <string.h>
+
+#include <memory>
+#include <string>
+
+#include "net/test/gtest_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+
+namespace net {
+namespace test {
+namespace {
+
+const char* const test_data[] = {
+ "test string 1, a medium size one.", "test string2",
+ "test string 3, a looooooooooooong loooooooooooooooong string"};
+
+TEST(IOVectorTest, CopyConstructor) {
+ IOVector iov1;
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ iov1.Append(const_cast<char*>(test_data[i]), strlen(test_data[i]));
+ }
+ IOVector iov2 = iov1;
+ EXPECT_EQ(iov2.Size(), iov1.Size());
+ for (size_t i = 0; i < iov2.Size(); ++i) {
+ EXPECT_TRUE(iov2.iovec()[i].iov_base == iov1.iovec()[i].iov_base);
+ EXPECT_EQ(iov2.iovec()[i].iov_len, iov1.iovec()[i].iov_len);
+ }
+ EXPECT_EQ(iov2.TotalBufferSize(), iov1.TotalBufferSize());
+}
+
+TEST(IOVectorTest, AssignmentOperator) {
+ IOVector iov1;
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ iov1.Append(const_cast<char*>(test_data[i]), strlen(test_data[i]));
+ }
+ IOVector iov2;
+ iov2.Append(const_cast<char*>("ephemeral string"), 16);
+ // The following assignment results in a shallow copy;
+ // both IOVectors point to the same underlying data.
+ iov2 = iov1;
+ EXPECT_EQ(iov2.Size(), iov1.Size());
+ for (size_t i = 0; i < iov2.Size(); ++i) {
+ EXPECT_TRUE(iov2.iovec()[i].iov_base == iov1.iovec()[i].iov_base);
+ EXPECT_EQ(iov2.iovec()[i].iov_len, iov1.iovec()[i].iov_len);
+ }
+ EXPECT_EQ(iov2.TotalBufferSize(), iov1.TotalBufferSize());
+}
+
+TEST(IOVectorTest, Append) {
+ IOVector iov;
+ int length = 0;
+ const struct iovec* iov2 = iov.iovec();
+
+ ASSERT_EQ(0u, iov.Size());
+ ASSERT_TRUE(iov2 == nullptr);
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ const int str_len = strlen(test_data[i]);
+ const int append_len = str_len / 2;
+ // This should append a new block.
+ iov.Append(const_cast<char*>(test_data[i]), append_len);
+ length += append_len;
+ ASSERT_EQ(i + 1, static_cast<size_t>(iov.Size()));
+ ASSERT_TRUE(iov.LastBlockEnd() == test_data[i] + append_len);
+ // This should just lengthen the existing block.
+ iov.Append(const_cast<char*>(test_data[i] + append_len),
+ str_len - append_len);
+ length += (str_len - append_len);
+ ASSERT_EQ(i + 1, static_cast<size_t>(iov.Size()));
+ ASSERT_TRUE(iov.LastBlockEnd() == test_data[i] + str_len);
+ }
+
+ iov2 = iov.iovec();
+ ASSERT_TRUE(iov2 != nullptr);
+ for (size_t i = 0; i < iov.Size(); ++i) {
+ ASSERT_TRUE(test_data[i] == iov2[i].iov_base);
+ ASSERT_EQ(strlen(test_data[i]), iov2[i].iov_len);
+ }
+}
+
+TEST(IOVectorTest, AppendIovec) {
+ IOVector iov;
+ const struct iovec test_iov[] = {{const_cast<char*>("foo"), 3},
+ {const_cast<char*>("bar"), 3},
+ {const_cast<char*>("buzzzz"), 6}};
+ iov.AppendIovec(test_iov, arraysize(test_iov));
+ for (size_t i = 0; i < arraysize(test_iov); ++i) {
+ EXPECT_EQ(test_iov[i].iov_base, iov.iovec()[i].iov_base);
+ EXPECT_EQ(test_iov[i].iov_len, iov.iovec()[i].iov_len);
+ }
+
+ // Test AppendIovecAtMostBytes.
+ iov.Clear();
+ // Stop in the middle of a block.
+ EXPECT_EQ(5u, iov.AppendIovecAtMostBytes(test_iov, arraysize(test_iov), 5));
+ EXPECT_EQ(5u, iov.TotalBufferSize());
+ iov.Append(static_cast<char*>(test_iov[1].iov_base) + 2, 1);
+ // Make sure the boundary case, where max_bytes == size of block also works.
+ EXPECT_EQ(6u, iov.AppendIovecAtMostBytes(&test_iov[2], 1, 6));
+ ASSERT_LE(arraysize(test_iov), static_cast<size_t>(iov.Size()));
+ for (size_t i = 0; i < arraysize(test_iov); ++i) {
+ EXPECT_EQ(test_iov[i].iov_base, iov.iovec()[i].iov_base);
+ EXPECT_EQ(test_iov[i].iov_len, iov.iovec()[i].iov_len);
+ }
+}
+
+TEST(IOVectorTest, ConsumeHalfBlocks) {
+ IOVector iov;
+ int length = 0;
+
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ const int str_len = strlen(test_data[i]);
+ iov.Append(const_cast<char*>(test_data[i]), str_len);
+ length += str_len;
+ }
+ const char* endp = iov.LastBlockEnd();
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ const struct iovec* iov2 = iov.iovec();
+ const size_t str_len = strlen(test_data[i]);
+ size_t tmp = str_len / 2;
+
+ ASSERT_TRUE(iov2 != nullptr);
+ ASSERT_TRUE(iov2[0].iov_base == test_data[i]);
+ ASSERT_EQ(str_len, iov2[0].iov_len);
+
+ // Consume half of the first block.
+ size_t consumed = iov.Consume(tmp);
+ ASSERT_EQ(tmp, consumed);
+ ASSERT_EQ(arraysize(test_data) - i, static_cast<size_t>(iov.Size()));
+ iov2 = iov.iovec();
+ ASSERT_TRUE(iov2 != nullptr);
+ ASSERT_TRUE(iov2[0].iov_base == test_data[i] + tmp);
+ ASSERT_EQ(iov2[0].iov_len, str_len - tmp);
+
+ // Consume the rest of the first block.
+ consumed = iov.Consume(str_len - tmp);
+ ASSERT_EQ(str_len - tmp, consumed);
+ ASSERT_EQ(arraysize(test_data) - i - 1, static_cast<size_t>(iov.Size()));
+ iov2 = iov.iovec();
+ if (iov.Size() > 0) {
+ ASSERT_TRUE(iov2 != nullptr);
+ ASSERT_TRUE(iov.LastBlockEnd() == endp);
+ } else {
+ ASSERT_TRUE(iov2 == nullptr);
+ ASSERT_TRUE(iov.LastBlockEnd() == nullptr);
+ }
+ }
+}
+
+TEST(IOVectorTest, ConsumeTwoAndHalfBlocks) {
+ IOVector iov;
+ int length = 0;
+
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ const int str_len = strlen(test_data[i]);
+ iov.Append(const_cast<char*>(test_data[i]), str_len);
+ length += str_len;
+ }
+ const size_t last_len = strlen(test_data[arraysize(test_data) - 1]);
+ const size_t half_len = last_len / 2;
+
+ const char* endp = iov.LastBlockEnd();
+ size_t consumed = iov.Consume(length - half_len);
+ ASSERT_EQ(length - half_len, consumed);
+ const struct iovec* iov2 = iov.iovec();
+ ASSERT_TRUE(iov2 != nullptr);
+ ASSERT_EQ(1u, iov.Size());
+ ASSERT_TRUE(iov2[0].iov_base ==
+ test_data[arraysize(test_data) - 1] + last_len - half_len);
+ ASSERT_EQ(half_len, iov2[0].iov_len);
+ ASSERT_TRUE(iov.LastBlockEnd() == endp);
+
+ consumed = iov.Consume(half_len);
+ ASSERT_EQ(half_len, consumed);
+ iov2 = iov.iovec();
+ ASSERT_EQ(0u, iov.Size());
+ ASSERT_TRUE(iov2 == nullptr);
+ ASSERT_TRUE(iov.LastBlockEnd() == nullptr);
+}
+
+TEST(IOVectorTest, ConsumeTooMuch) {
+ IOVector iov;
+ int length = 0;
+
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ const int str_len = strlen(test_data[i]);
+ iov.Append(const_cast<char*>(test_data[i]), str_len);
+ length += str_len;
+ }
+
+ int consumed = 0;
+ EXPECT_DFATAL({ consumed = iov.Consume(length + 1); },
+ "Attempting to consume 1 non-existent bytes.");
+ ASSERT_EQ(length, consumed);
+ const struct iovec* iov2 = iov.iovec();
+ ASSERT_EQ(0u, iov.Size());
+ ASSERT_TRUE(iov2 == nullptr);
+ ASSERT_TRUE(iov.LastBlockEnd() == nullptr);
+}
+
+TEST(IOVectorTest, ConsumeAndCopyHalfBlocks) {
+ IOVector iov;
+ int length = 0;
+
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ const int str_len = strlen(test_data[i]);
+ iov.Append(const_cast<char*>(test_data[i]), str_len);
+ length += str_len;
+ }
+ const char* endp = iov.LastBlockEnd();
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ const struct iovec* iov2 = iov.iovec();
+ const size_t str_len = strlen(test_data[i]);
+ size_t tmp = str_len / 2;
+
+ ASSERT_TRUE(iov2 != nullptr);
+ ASSERT_TRUE(iov2[0].iov_base == test_data[i]);
+ ASSERT_EQ(str_len, iov2[0].iov_len);
+
+ // Consume half of the first block.
+ std::unique_ptr<char[]> buffer(new char[str_len]);
+ size_t consumed = iov.ConsumeAndCopy(tmp, buffer.get());
+ EXPECT_EQ(0, memcmp(test_data[i], buffer.get(), tmp));
+ ASSERT_EQ(tmp, consumed);
+ ASSERT_EQ(arraysize(test_data) - i, static_cast<size_t>(iov.Size()));
+ iov2 = iov.iovec();
+ ASSERT_TRUE(iov2 != nullptr);
+ ASSERT_TRUE(iov2[0].iov_base == test_data[i] + tmp);
+ ASSERT_EQ(iov2[0].iov_len, str_len - tmp);
+
+ // Consume the rest of the first block.
+ consumed = iov.ConsumeAndCopy(str_len - tmp, buffer.get());
+ ASSERT_EQ(str_len - tmp, consumed);
+ ASSERT_EQ(arraysize(test_data) - i - 1, static_cast<size_t>(iov.Size()));
+ iov2 = iov.iovec();
+ if (iov.Size() > 0) {
+ ASSERT_TRUE(iov2 != nullptr);
+ ASSERT_TRUE(iov.LastBlockEnd() == endp);
+ } else {
+ ASSERT_TRUE(iov2 == nullptr);
+ ASSERT_TRUE(iov.LastBlockEnd() == nullptr);
+ }
+ }
+}
+
+TEST(IOVectorTest, ConsumeAndCopyTwoAndHalfBlocks) {
+ IOVector iov;
+ size_t length = 0;
+
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ const int str_len = strlen(test_data[i]);
+ iov.Append(const_cast<char*>(test_data[i]), str_len);
+ length += str_len;
+ }
+ const size_t last_len = strlen(test_data[arraysize(test_data) - 1]);
+ const size_t half_len = last_len / 2;
+
+ const char* endp = iov.LastBlockEnd();
+ std::unique_ptr<char[]> buffer(new char[length]);
+ size_t consumed = iov.ConsumeAndCopy(length - half_len, buffer.get());
+ ASSERT_EQ(length - half_len, consumed);
+ const struct iovec* iov2 = iov.iovec();
+ ASSERT_TRUE(iov2 != nullptr);
+ ASSERT_EQ(1u, iov.Size());
+ ASSERT_TRUE(iov2[0].iov_base ==
+ test_data[arraysize(test_data) - 1] + last_len - half_len);
+ ASSERT_EQ(half_len, iov2[0].iov_len);
+ ASSERT_TRUE(iov.LastBlockEnd() == endp);
+
+ consumed = iov.Consume(half_len);
+ ASSERT_EQ(half_len, consumed);
+ iov2 = iov.iovec();
+ ASSERT_EQ(0u, iov.Size());
+ ASSERT_TRUE(iov2 == nullptr);
+ ASSERT_TRUE(iov.LastBlockEnd() == nullptr);
+}
+
+TEST(IOVectorTest, ConsumeAndCopyTooMuch) {
+ IOVector iov;
+ int length = 0;
+
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ const int str_len = strlen(test_data[i]);
+ iov.Append(const_cast<char*>(test_data[i]), str_len);
+ length += str_len;
+ }
+
+ int consumed = 0;
+ std::unique_ptr<char[]> buffer(new char[length + 1]);
+ EXPECT_DFATAL({ consumed = iov.ConsumeAndCopy(length + 1, buffer.get()); },
+ "Attempting to consume 1 non-existent bytes.");
+ ASSERT_EQ(length, consumed);
+ const struct iovec* iov2 = iov.iovec();
+ ASSERT_EQ(0u, iov.Size());
+ ASSERT_TRUE(iov2 == nullptr);
+ ASSERT_TRUE(iov.LastBlockEnd() == nullptr);
+}
+
+TEST(IOVectorTest, Clear) {
+ IOVector iov;
+ int length = 0;
+
+ for (size_t i = 0; i < arraysize(test_data); ++i) {
+ const int str_len = strlen(test_data[i]);
+ iov.Append(const_cast<char*>(test_data[i]), str_len);
+ length += str_len;
+ }
+ const struct iovec* iov2 = iov.iovec();
+ ASSERT_TRUE(iov2 != nullptr);
+ ASSERT_EQ(arraysize(test_data), static_cast<size_t>(iov.Size()));
+
+ iov.Clear();
+ iov2 = iov.iovec();
+ ASSERT_EQ(0u, iov.Size());
+ ASSERT_TRUE(iov2 == nullptr);
+}
+
+TEST(IOVectorTest, Capacity) {
+ IOVector iov;
+ // Note: IOVector merges adjacent Appends() into a single iov.
+ // Therefore, if we expect final size of iov to be 3, we must insure
+ // that the items we are appending are not adjacent. To achieve that
+ // we use use an array (a[1] provides a buffer between a[0] and b[0],
+ // and makes them non-adjacent).
+ char a[2], b[2], c[2];
+ iov.Append(&a[0], 1);
+ iov.Append(&b[0], 1);
+ iov.Append(&c[0], 1);
+ ASSERT_EQ(3u, iov.Size());
+ size_t capacity = iov.Capacity();
+ EXPECT_LE(iov.Size(), capacity);
+ iov.Consume(2);
+ // The capacity should not have changed.
+ EXPECT_EQ(capacity, iov.Capacity());
+}
+
+TEST(IOVectorTest, Swap) {
+ IOVector iov1, iov2;
+ // See IOVector merge comment above.
+ char a[2], b[2], c[2], d[2], e[2];
+ iov1.Append(&a[0], 1);
+ iov1.Append(&b[0], 1);
+
+ iov2.Append(&c[0], 1);
+ iov2.Append(&d[0], 1);
+ iov2.Append(&e[0], 1);
+ iov1.Swap(&iov2);
+
+ ASSERT_EQ(3u, iov1.Size());
+ EXPECT_EQ(&c[0], iov1.iovec()[0].iov_base);
+ EXPECT_EQ(1u, iov1.iovec()[0].iov_len);
+ EXPECT_EQ(&d[0], iov1.iovec()[1].iov_base);
+ EXPECT_EQ(1u, iov1.iovec()[1].iov_len);
+ EXPECT_EQ(&e[0], iov1.iovec()[2].iov_base);
+ EXPECT_EQ(1u, iov1.iovec()[2].iov_len);
+
+ ASSERT_EQ(2u, iov2.Size());
+ EXPECT_EQ(&a[0], iov2.iovec()[0].iov_base);
+ EXPECT_EQ(1u, iov2.iovec()[0].iov_len);
+ EXPECT_EQ(&b[0], iov2.iovec()[1].iov_base);
+ EXPECT_EQ(1u, iov2.iovec()[1].iov_len);
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/proto/cached_network_parameters.proto b/chromium/net/quic/core/proto/cached_network_parameters.proto
index 2a3f3e5a595..2a3f3e5a595 100644
--- a/chromium/net/quic/proto/cached_network_parameters.proto
+++ b/chromium/net/quic/core/proto/cached_network_parameters.proto
diff --git a/chromium/net/quic/proto/source_address_token.proto b/chromium/net/quic/core/proto/source_address_token.proto
index 8d833de97f8..8d833de97f8 100644
--- a/chromium/net/quic/proto/source_address_token.proto
+++ b/chromium/net/quic/core/proto/source_address_token.proto
diff --git a/chromium/net/quic/core/quic_address_mismatch.cc b/chromium/net/quic/core/quic_address_mismatch.cc
new file mode 100644
index 00000000000..b37fb096f7d
--- /dev/null
+++ b/chromium/net/quic/core/quic_address_mismatch.cc
@@ -0,0 +1,51 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_address_mismatch.h"
+
+#include "base/logging.h"
+#include "net/base/ip_address.h"
+
+namespace net {
+
+int GetAddressMismatch(const IPEndPoint& first_address,
+ const IPEndPoint& second_address) {
+ if (first_address.address().empty() || second_address.address().empty()) {
+ return -1;
+ }
+ IPAddress first_ip_address = first_address.address();
+ if (first_ip_address.IsIPv4MappedIPv6()) {
+ first_ip_address = ConvertIPv4MappedIPv6ToIPv4(first_ip_address);
+ }
+ IPAddress second_ip_address = second_address.address();
+ if (second_ip_address.IsIPv4MappedIPv6()) {
+ second_ip_address = ConvertIPv4MappedIPv6ToIPv4(second_ip_address);
+ }
+
+ int sample;
+ if (first_ip_address != second_ip_address) {
+ sample = QUIC_ADDRESS_MISMATCH_BASE;
+ } else if (first_address.port() != second_address.port()) {
+ sample = QUIC_PORT_MISMATCH_BASE;
+ } else {
+ sample = QUIC_ADDRESS_AND_PORT_MATCH_BASE;
+ }
+
+ // Add an offset to |sample|:
+ // V4_V4: add 0
+ // V6_V6: add 1
+ // V4_V6: add 2
+ // V6_V4: add 3
+ bool first_ipv4 = first_ip_address.IsIPv4();
+ if (first_ipv4 != second_ip_address.IsIPv4()) {
+ CHECK_EQ(sample, QUIC_ADDRESS_MISMATCH_BASE);
+ sample += 2;
+ }
+ if (!first_ipv4) {
+ sample += 1;
+ }
+ return sample;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/quic_address_mismatch.h b/chromium/net/quic/core/quic_address_mismatch.h
index 0ac09a261db..0ac09a261db 100644
--- a/chromium/net/quic/quic_address_mismatch.h
+++ b/chromium/net/quic/core/quic_address_mismatch.h
diff --git a/chromium/net/quic/core/quic_address_mismatch_test.cc b/chromium/net/quic/core/quic_address_mismatch_test.cc
new file mode 100644
index 00000000000..63aa627ccf2
--- /dev/null
+++ b/chromium/net/quic/core/quic_address_mismatch_test.cc
@@ -0,0 +1,99 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_address_mismatch.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+// Test all cases of the GetAddressMismatch function.
+TEST(QuicAddressMismatchTest, GetAddressMismatch) {
+ IPAddress ip4_1;
+ IPAddress ip4_2;
+ IPAddress ip6_1;
+ IPAddress ip6_2;
+ IPAddress ip4_mapped_1;
+ IPAddress ip4_mapped_2;
+ ASSERT_TRUE(ip4_1.AssignFromIPLiteral("1.2.3.4"));
+ ASSERT_TRUE(ip4_2.AssignFromIPLiteral("5.6.7.8"));
+ ASSERT_TRUE(ip6_1.AssignFromIPLiteral("1234::1"));
+ ASSERT_TRUE(ip6_2.AssignFromIPLiteral("1234::2"));
+ ip4_mapped_1 = ConvertIPv4ToIPv4MappedIPv6(ip4_1);
+ ip4_mapped_2 = ConvertIPv4ToIPv4MappedIPv6(ip4_2);
+ ASSERT_NE(ip4_1, ip4_2);
+ ASSERT_NE(ip6_1, ip6_2);
+ ASSERT_NE(ip4_mapped_1, ip4_mapped_2);
+
+ EXPECT_EQ(-1, GetAddressMismatch(IPEndPoint(), IPEndPoint()));
+ EXPECT_EQ(-1, GetAddressMismatch(IPEndPoint(), IPEndPoint(ip4_1, 443)));
+ EXPECT_EQ(-1, GetAddressMismatch(IPEndPoint(ip4_1, 443), IPEndPoint()));
+
+ EXPECT_EQ(QUIC_ADDRESS_AND_PORT_MATCH_V4_V4,
+ GetAddressMismatch(IPEndPoint(ip4_1, 443), IPEndPoint(ip4_1, 443)));
+ EXPECT_EQ(QUIC_ADDRESS_AND_PORT_MATCH_V4_V4,
+ GetAddressMismatch(IPEndPoint(ip4_1, 443),
+ IPEndPoint(ip4_mapped_1, 443)));
+ EXPECT_EQ(QUIC_ADDRESS_AND_PORT_MATCH_V4_V4,
+ GetAddressMismatch(IPEndPoint(ip4_mapped_1, 443),
+ IPEndPoint(ip4_mapped_1, 443)));
+ EXPECT_EQ(QUIC_ADDRESS_AND_PORT_MATCH_V6_V6,
+ GetAddressMismatch(IPEndPoint(ip6_1, 443), IPEndPoint(ip6_1, 443)));
+
+ EXPECT_EQ(QUIC_PORT_MISMATCH_V4_V4,
+ GetAddressMismatch(IPEndPoint(ip4_1, 80), IPEndPoint(ip4_1, 443)));
+ EXPECT_EQ(
+ QUIC_PORT_MISMATCH_V4_V4,
+ GetAddressMismatch(IPEndPoint(ip4_1, 80), IPEndPoint(ip4_mapped_1, 443)));
+ EXPECT_EQ(QUIC_PORT_MISMATCH_V4_V4,
+ GetAddressMismatch(IPEndPoint(ip4_mapped_1, 80),
+ IPEndPoint(ip4_mapped_1, 443)));
+ EXPECT_EQ(QUIC_PORT_MISMATCH_V6_V6,
+ GetAddressMismatch(IPEndPoint(ip6_1, 80), IPEndPoint(ip6_1, 443)));
+
+ EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V4,
+ GetAddressMismatch(IPEndPoint(ip4_1, 443), IPEndPoint(ip4_2, 443)));
+ EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V4,
+ GetAddressMismatch(IPEndPoint(ip4_1, 443),
+ IPEndPoint(ip4_mapped_2, 443)));
+ EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V4,
+ GetAddressMismatch(IPEndPoint(ip4_mapped_1, 443),
+ IPEndPoint(ip4_mapped_2, 443)));
+ EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V4,
+ GetAddressMismatch(IPEndPoint(ip4_1, 80), IPEndPoint(ip4_2, 443)));
+ EXPECT_EQ(
+ QUIC_ADDRESS_MISMATCH_V4_V4,
+ GetAddressMismatch(IPEndPoint(ip4_1, 80), IPEndPoint(ip4_mapped_2, 443)));
+ EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V4,
+ GetAddressMismatch(IPEndPoint(ip4_mapped_1, 80),
+ IPEndPoint(ip4_mapped_2, 443)));
+ EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V6_V6,
+ GetAddressMismatch(IPEndPoint(ip6_1, 443), IPEndPoint(ip6_2, 443)));
+ EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V6_V6,
+ GetAddressMismatch(IPEndPoint(ip6_1, 80), IPEndPoint(ip6_2, 443)));
+ EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V6,
+ GetAddressMismatch(IPEndPoint(ip4_1, 443), IPEndPoint(ip6_1, 443)));
+ EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V6,
+ GetAddressMismatch(IPEndPoint(ip4_mapped_1, 443),
+ IPEndPoint(ip6_1, 443)));
+ EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V6,
+ GetAddressMismatch(IPEndPoint(ip4_1, 80), IPEndPoint(ip6_1, 443)));
+ EXPECT_EQ(
+ QUIC_ADDRESS_MISMATCH_V4_V6,
+ GetAddressMismatch(IPEndPoint(ip4_mapped_1, 80), IPEndPoint(ip6_1, 443)));
+ EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V6_V4,
+ GetAddressMismatch(IPEndPoint(ip6_1, 443), IPEndPoint(ip4_1, 443)));
+ EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V6_V4,
+ GetAddressMismatch(IPEndPoint(ip6_1, 443),
+ IPEndPoint(ip4_mapped_1, 443)));
+ EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V6_V4,
+ GetAddressMismatch(IPEndPoint(ip6_1, 80), IPEndPoint(ip4_1, 443)));
+ EXPECT_EQ(
+ QUIC_ADDRESS_MISMATCH_V6_V4,
+ GetAddressMismatch(IPEndPoint(ip6_1, 80), IPEndPoint(ip4_mapped_1, 443)));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_alarm.cc b/chromium/net/quic/core/quic_alarm.cc
new file mode 100644
index 00000000000..985be648f66
--- /dev/null
+++ b/chromium/net/quic/core/quic_alarm.cc
@@ -0,0 +1,76 @@
+// Copyright 2013 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/quic_alarm.h"
+
+#include "base/logging.h"
+#include "net/quic/core/quic_flags.h"
+
+namespace net {
+
+QuicAlarm::QuicAlarm(QuicArenaScopedPtr<Delegate> delegate)
+ : delegate_(std::move(delegate)), deadline_(QuicTime::Zero()) {}
+
+QuicAlarm::~QuicAlarm() {}
+
+void QuicAlarm::Set(QuicTime new_deadline) {
+ DCHECK(!IsSet());
+ DCHECK(new_deadline.IsInitialized());
+ deadline_ = new_deadline;
+ SetImpl();
+}
+
+void QuicAlarm::Cancel() {
+ if (!IsSet()) {
+ // Don't try to cancel an alarm that hasn't been set.
+ return;
+ }
+ deadline_ = QuicTime::Zero();
+ CancelImpl();
+}
+
+void QuicAlarm::Update(QuicTime new_deadline, QuicTime::Delta granularity) {
+ if (!new_deadline.IsInitialized()) {
+ Cancel();
+ return;
+ }
+ if (std::abs((new_deadline - deadline_).ToMicroseconds()) <
+ granularity.ToMicroseconds()) {
+ return;
+ }
+ const bool was_set = IsSet();
+ deadline_ = new_deadline;
+ if (was_set) {
+ UpdateImpl();
+ } else {
+ SetImpl();
+ }
+}
+
+bool QuicAlarm::IsSet() const {
+ return deadline_.IsInitialized();
+}
+
+void QuicAlarm::Fire() {
+ if (!IsSet()) {
+ return;
+ }
+
+ deadline_ = QuicTime::Zero();
+ delegate_->OnAlarm();
+}
+
+void QuicAlarm::UpdateImpl() {
+ // CancelImpl and SetImpl take the new deadline by way of the deadline_
+ // member, so save and restore deadline_ before canceling.
+ const QuicTime new_deadline = deadline_;
+
+ deadline_ = QuicTime::Zero();
+ CancelImpl();
+
+ deadline_ = new_deadline;
+ SetImpl();
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_alarm.h b/chromium/net/quic/core/quic_alarm.h
new file mode 100644
index 00000000000..7ad8af427be
--- /dev/null
+++ b/chromium/net/quic/core/quic_alarm.h
@@ -0,0 +1,89 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_ALARM_H_
+#define NET_QUIC_QUIC_ALARM_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_arena_scoped_ptr.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+// Abstract class which represents an alarm which will go off at a
+// scheduled time, and execute the |OnAlarm| method of the delegate.
+// An alarm may be cancelled, in which case it may or may not be
+// removed from the underlying scheduling system, but in either case
+// the task will not be executed.
+class NET_EXPORT_PRIVATE QuicAlarm {
+ public:
+ class NET_EXPORT_PRIVATE Delegate {
+ public:
+ virtual ~Delegate() {}
+
+ // Invoked when the alarm fires.
+ virtual void OnAlarm() = 0;
+ };
+
+ explicit QuicAlarm(QuicArenaScopedPtr<Delegate> delegate);
+ virtual ~QuicAlarm();
+
+ // Sets the alarm to fire at |deadline|. Must not be called while
+ // the alarm is set. To reschedule an alarm, call Cancel() first,
+ // then Set().
+ void Set(QuicTime new_deadline);
+
+ // Cancels the alarm. May be called repeatedly. Does not
+ // guarantee that the underlying scheduling system will remove
+ // the alarm's associated task, but guarantees that the
+ // delegates OnAlarm method will not be called.
+ void Cancel();
+
+ // Cancels and sets the alarm if the |deadline| is farther from the current
+ // deadline than |granularity|, and otherwise does nothing. If |deadline| is
+ // not initialized, the alarm is cancelled.
+ void Update(QuicTime new_deadline, QuicTime::Delta granularity);
+
+ // Returns true if |deadline_| has been set to a non-zero time.
+ bool IsSet() const;
+
+ QuicTime deadline() const { return deadline_; }
+
+ protected:
+ // Subclasses implement this method to perform the platform-specific
+ // scheduling of the alarm. Is called from Set() or Fire(), after the
+ // deadline has been updated.
+ virtual void SetImpl() = 0;
+
+ // Subclasses implement this method to perform the platform-specific
+ // cancelation of the alarm.
+ virtual void CancelImpl() = 0;
+
+ // Subclasses implement this method to perform the platform-specific update of
+ // the alarm if there exists a more optimal implementation than calling
+ // CancelImpl() and SetImpl().
+ virtual void UpdateImpl();
+
+ // Called by subclasses when the alarm fires. Invokes the
+ // delegates |OnAlarm| if a delegate is set, and if the deadline
+ // has been exceeded. Implementations which do not remove the
+ // alarm from the underlying scheduler on Cancel() may need to handle
+ // the situation where the task executes before the deadline has been
+ // reached, in which case they need to reschedule the task and must not
+ // call invoke this method.
+ void Fire();
+
+ private:
+ QuicArenaScopedPtr<Delegate> delegate_;
+ QuicTime deadline_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicAlarm);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_ALARM_H_
diff --git a/chromium/net/quic/core/quic_alarm_factory.h b/chromium/net/quic/core/quic_alarm_factory.h
new file mode 100644
index 00000000000..77e6ab7fb42
--- /dev/null
+++ b/chromium/net/quic/core/quic_alarm_factory.h
@@ -0,0 +1,40 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_ALARM_FACTORY_H_
+#define NET_QUIC_QUIC_ALARM_FACTORY_H_
+
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_alarm.h"
+#include "net/quic/core/quic_one_block_arena.h"
+
+namespace net {
+
+// QuicConnections currently use around 1KB of polymorphic types which would
+// ordinarily be on the heap. Instead, store them inline in an arena.
+using QuicConnectionArena = QuicOneBlockArena<1024>;
+
+// Creates platform-specific alarms used throughout QUIC.
+class NET_EXPORT_PRIVATE QuicAlarmFactory {
+ public:
+ virtual ~QuicAlarmFactory() {}
+
+ // Creates a new platform-specific alarm which will be configured to notify
+ // |delegate| when the alarm fires. Returns an alarm allocated on the heap.
+ // Caller takes ownership of the new alarm, which will not yet be "set" to
+ // fire.
+ virtual QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) = 0;
+
+ // Creates a new platform-specific alarm which will be configured to notify
+ // |delegate| when the alarm fires. Caller takes ownership of the new alarm,
+ // which will not yet be "set" to fire. If |arena| is null, then the alarm
+ // will be created on the heap. Otherwise, it will be created in |arena|.
+ virtual QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
+ QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+ QuicConnectionArena* arena) = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_ALARM_FACTORY_H_
diff --git a/chromium/net/quic/core/quic_alarm_test.cc b/chromium/net/quic/core/quic_alarm_test.cc
new file mode 100644
index 00000000000..a0cafd66a46
--- /dev/null
+++ b/chromium/net/quic/core/quic_alarm_test.cc
@@ -0,0 +1,168 @@
+// Copyright 2013 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/quic_alarm.h"
+
+#include "base/logging.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Return;
+using testing::Invoke;
+
+namespace net {
+namespace test {
+namespace {
+
+class MockDelegate : public QuicAlarm::Delegate {
+ public:
+ MOCK_METHOD0(OnAlarm, void());
+};
+
+class DestructiveDelegate : public QuicAlarm::Delegate {
+ public:
+ DestructiveDelegate() : alarm_(nullptr) {}
+
+ void set_alarm(QuicAlarm* alarm) { alarm_ = alarm; }
+
+ void OnAlarm() override {
+ DCHECK(alarm_);
+ delete alarm_;
+ }
+
+ private:
+ QuicAlarm* alarm_;
+};
+
+class TestAlarm : public QuicAlarm {
+ public:
+ explicit TestAlarm(QuicAlarm::Delegate* delegate)
+ : QuicAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate)) {}
+
+ bool scheduled() const { return scheduled_; }
+
+ void FireAlarm() {
+ scheduled_ = false;
+ Fire();
+ }
+
+ protected:
+ void SetImpl() override {
+ DCHECK(deadline().IsInitialized());
+ scheduled_ = true;
+ }
+
+ void CancelImpl() override {
+ DCHECK(!deadline().IsInitialized());
+ scheduled_ = false;
+ }
+
+ private:
+ bool scheduled_;
+};
+
+class DestructiveAlarm : public QuicAlarm {
+ public:
+ explicit DestructiveAlarm(DestructiveDelegate* delegate)
+ : QuicAlarm(QuicArenaScopedPtr<DestructiveDelegate>(delegate)) {}
+
+ void FireAlarm() { Fire(); }
+
+ protected:
+ void SetImpl() override {}
+
+ void CancelImpl() override {}
+};
+
+class QuicAlarmTest : public ::testing::Test {
+ public:
+ QuicAlarmTest()
+ : delegate_(new MockDelegate()),
+ alarm_(delegate_),
+ deadline_(QuicTime::Zero() + QuicTime::Delta::FromSeconds(7)),
+ deadline2_(QuicTime::Zero() + QuicTime::Delta::FromSeconds(14)),
+ new_deadline_(QuicTime::Zero()) {}
+
+ void ResetAlarm() { alarm_.Set(new_deadline_); }
+
+ MockDelegate* delegate_; // not owned
+ TestAlarm alarm_;
+ QuicTime deadline_;
+ QuicTime deadline2_;
+ QuicTime new_deadline_;
+};
+
+TEST_F(QuicAlarmTest, IsSet) {
+ EXPECT_FALSE(alarm_.IsSet());
+}
+
+TEST_F(QuicAlarmTest, Set) {
+ QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
+ alarm_.Set(deadline);
+ EXPECT_TRUE(alarm_.IsSet());
+ EXPECT_TRUE(alarm_.scheduled());
+ EXPECT_EQ(deadline, alarm_.deadline());
+}
+
+TEST_F(QuicAlarmTest, Cancel) {
+ QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
+ alarm_.Set(deadline);
+ alarm_.Cancel();
+ EXPECT_FALSE(alarm_.IsSet());
+ EXPECT_FALSE(alarm_.scheduled());
+ EXPECT_EQ(QuicTime::Zero(), alarm_.deadline());
+}
+
+TEST_F(QuicAlarmTest, Update) {
+ QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
+ alarm_.Set(deadline);
+ QuicTime new_deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(8);
+ alarm_.Update(new_deadline, QuicTime::Delta::Zero());
+ EXPECT_TRUE(alarm_.IsSet());
+ EXPECT_TRUE(alarm_.scheduled());
+ EXPECT_EQ(new_deadline, alarm_.deadline());
+}
+
+TEST_F(QuicAlarmTest, UpdateWithZero) {
+ QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
+ alarm_.Set(deadline);
+ alarm_.Update(QuicTime::Zero(), QuicTime::Delta::Zero());
+ EXPECT_FALSE(alarm_.IsSet());
+ EXPECT_FALSE(alarm_.scheduled());
+ EXPECT_EQ(QuicTime::Zero(), alarm_.deadline());
+}
+
+TEST_F(QuicAlarmTest, Fire) {
+ QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
+ alarm_.Set(deadline);
+ alarm_.FireAlarm();
+ EXPECT_FALSE(alarm_.IsSet());
+ EXPECT_FALSE(alarm_.scheduled());
+ EXPECT_EQ(QuicTime::Zero(), alarm_.deadline());
+}
+
+TEST_F(QuicAlarmTest, FireAndResetViaSet) {
+ alarm_.Set(deadline_);
+ new_deadline_ = deadline2_;
+ EXPECT_CALL(*delegate_, OnAlarm())
+ .WillOnce(Invoke(this, &QuicAlarmTest::ResetAlarm));
+ alarm_.FireAlarm();
+ EXPECT_TRUE(alarm_.IsSet());
+ EXPECT_TRUE(alarm_.scheduled());
+ EXPECT_EQ(deadline2_, alarm_.deadline());
+}
+
+TEST_F(QuicAlarmTest, FireDestroysAlarm) {
+ DestructiveDelegate* delegate(new DestructiveDelegate);
+ DestructiveAlarm* alarm = new DestructiveAlarm(delegate);
+ delegate->set_alarm(alarm);
+ QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
+ alarm->Set(deadline);
+ // This should not crash, even though it will destroy alarm.
+ alarm->FireAlarm();
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_arena_scoped_ptr.h b/chromium/net/quic/core/quic_arena_scoped_ptr.h
new file mode 100644
index 00000000000..d9ca24282bf
--- /dev/null
+++ b/chromium/net/quic/core/quic_arena_scoped_ptr.h
@@ -0,0 +1,210 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// unique_ptr-style pointer that stores values that may be from an arena. Takes
+// up the same storage as the platform's native pointer type. Takes ownership
+// of the value it's constructed with; if holding a value in an arena, and the
+// type has a non-trivial destructor, the arena must outlive the
+// QuicArenaScopedPtr. Does not support array overloads.
+
+#ifndef NET_QUIC_QUIC_ARENA_SCOPED_PTR_H_
+#define NET_QUIC_QUIC_ARENA_SCOPED_PTR_H_
+
+#include <cstdint> // for uintptr_t
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "net/quic/core/quic_utils.h"
+
+namespace net {
+
+template <typename T>
+class QuicArenaScopedPtr {
+ static_assert(QUIC_ALIGN_OF(T*) > 1,
+ "QuicArenaScopedPtr can only store objects that are aligned to "
+ "greater than 1 byte.");
+
+ public:
+ // Constructs an empty QuicArenaScopedPtr.
+ QuicArenaScopedPtr();
+
+ // Constructs a QuicArenaScopedPtr referencing the heap-allocated memory
+ // provided.
+ explicit QuicArenaScopedPtr(T* value);
+
+ template <typename U>
+ QuicArenaScopedPtr(QuicArenaScopedPtr<U>&& other); // NOLINT
+ template <typename U>
+ QuicArenaScopedPtr& operator=(QuicArenaScopedPtr<U>&& other);
+ ~QuicArenaScopedPtr();
+
+ // Returns a pointer to the value.
+ T* get() const;
+
+ // Returns a reference to the value.
+ T& operator*() const;
+
+ // Returns a pointer to the value.
+ T* operator->() const;
+
+ // Swaps the value of this pointer with |other|.
+ void swap(QuicArenaScopedPtr& other);
+
+ // Resets the held value to |value|.
+ void reset(T* value = nullptr);
+
+ // Returns true if |this| came from an arena. Primarily exposed for testing
+ // and assertions.
+ bool is_from_arena();
+
+ private:
+ // Friends with other derived types of QuicArenaScopedPtr, to support the
+ // derived-types case.
+ template <typename U>
+ friend class QuicArenaScopedPtr;
+ // Also befriend all known arenas, only to prevent misuse.
+ template <uint32_t ArenaSize>
+ friend class QuicOneBlockArena;
+
+ // Tag to denote that a QuicArenaScopedPtr is being explicitly created by an
+ // arena.
+ enum class ConstructFrom { kHeap, kArena };
+
+ // Constructs a QuicArenaScopedPtr with the given representation.
+ QuicArenaScopedPtr(void* value, ConstructFrom from);
+
+ // Low-order bits of value_ that determine if the pointer came from an arena.
+ static const uintptr_t kFromArenaMask = 0x1;
+
+ // Every platform we care about has at least 4B aligned integers, so store the
+ // is_from_arena bit in the least significant bit.
+ void* value_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicArenaScopedPtr);
+};
+
+template <typename T>
+bool operator==(const QuicArenaScopedPtr<T>& left,
+ const QuicArenaScopedPtr<T>& right) {
+ return left.get() == right.get();
+}
+
+template <typename T>
+bool operator!=(const QuicArenaScopedPtr<T>& left,
+ const QuicArenaScopedPtr<T>& right) {
+ return left.get() != right.get();
+}
+
+template <typename T>
+bool operator==(std::nullptr_t, const QuicArenaScopedPtr<T>& right) {
+ return nullptr == right.get();
+}
+
+template <typename T>
+bool operator!=(std::nullptr_t, const QuicArenaScopedPtr<T>& right) {
+ return nullptr != right.get();
+}
+
+template <typename T>
+bool operator==(const QuicArenaScopedPtr<T>& left, std::nullptr_t) {
+ return left.get() == nullptr;
+}
+
+template <typename T>
+bool operator!=(const QuicArenaScopedPtr<T>& left, std::nullptr_t) {
+ return left.get() != nullptr;
+}
+
+template <typename T>
+QuicArenaScopedPtr<T>::QuicArenaScopedPtr()
+ : value_(nullptr) {}
+
+template <typename T>
+QuicArenaScopedPtr<T>::QuicArenaScopedPtr(T* value)
+ : QuicArenaScopedPtr(value, ConstructFrom::kHeap) {}
+
+template <typename T>
+template <typename U>
+QuicArenaScopedPtr<T>::QuicArenaScopedPtr(QuicArenaScopedPtr<U>&& other)
+ : value_(other.value_) {
+ static_assert(
+ std::is_base_of<T, U>::value || std::is_same<T, U>::value,
+ "Cannot construct QuicArenaScopedPtr; type is not derived or same.");
+ other.value_ = nullptr;
+}
+
+template <typename T>
+template <typename U>
+QuicArenaScopedPtr<T>& QuicArenaScopedPtr<T>::operator=(
+ QuicArenaScopedPtr<U>&& other) {
+ static_assert(
+ std::is_base_of<T, U>::value || std::is_same<T, U>::value,
+ "Cannot assign QuicArenaScopedPtr; type is not derived or same.");
+ swap(other);
+ return *this;
+}
+
+template <typename T>
+QuicArenaScopedPtr<T>::~QuicArenaScopedPtr() {
+ reset();
+}
+
+template <typename T>
+T* QuicArenaScopedPtr<T>::get() const {
+ return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(value_) &
+ ~kFromArenaMask);
+}
+
+template <typename T>
+T& QuicArenaScopedPtr<T>::operator*() const {
+ return *get();
+}
+
+template <typename T>
+T* QuicArenaScopedPtr<T>::operator->() const {
+ return get();
+}
+
+template <typename T>
+void QuicArenaScopedPtr<T>::swap(QuicArenaScopedPtr& other) {
+ using std::swap;
+ swap(value_, other.value_);
+}
+
+template <typename T>
+bool QuicArenaScopedPtr<T>::is_from_arena() {
+ return (reinterpret_cast<uintptr_t>(value_) & kFromArenaMask) != 0;
+}
+
+template <typename T>
+void QuicArenaScopedPtr<T>::reset(T* value) {
+ if (value_ != nullptr) {
+ if (is_from_arena()) {
+ // Manually invoke the destructor.
+ get()->~T();
+ } else {
+ delete get();
+ }
+ }
+ DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(value) & kFromArenaMask);
+ value_ = value;
+}
+
+template <typename T>
+QuicArenaScopedPtr<T>::QuicArenaScopedPtr(void* value, ConstructFrom from_arena)
+ : value_(value) {
+ DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(value_) & kFromArenaMask);
+ switch (from_arena) {
+ case ConstructFrom::kHeap:
+ break;
+ case ConstructFrom::kArena:
+ value_ = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(value_) |
+ QuicArenaScopedPtr<T>::kFromArenaMask);
+ break;
+ }
+}
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_ARENA_SCOPED_PTR_H_
diff --git a/chromium/net/quic/core/quic_arena_scoped_ptr_test.cc b/chromium/net/quic/core/quic_arena_scoped_ptr_test.cc
new file mode 100644
index 00000000000..9c4a0a2501f
--- /dev/null
+++ b/chromium/net/quic/core/quic_arena_scoped_ptr_test.cc
@@ -0,0 +1,102 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "net/quic/core/quic_arena_scoped_ptr.h"
+
+#include "net/quic/core/quic_one_block_arena.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace {
+
+enum class TestParam { kFromHeap, kFromArena };
+
+struct TestObject {
+ explicit TestObject(uintptr_t value) : value(value) { buffer.resize(1024); }
+ uintptr_t value;
+
+ // Ensure that we have a non-trivial destructor that will leak memory if it's
+ // not called.
+ std::vector<char> buffer;
+};
+
+class QuicArenaScopedPtrParamTest : public ::testing::TestWithParam<TestParam> {
+ protected:
+ QuicArenaScopedPtr<TestObject> CreateObject(uintptr_t value) {
+ QuicArenaScopedPtr<TestObject> ptr;
+ switch (GetParam()) {
+ case TestParam::kFromHeap:
+ ptr = QuicArenaScopedPtr<TestObject>(new TestObject(value));
+ CHECK(!ptr.is_from_arena());
+ break;
+ case TestParam::kFromArena:
+ ptr = arena_.New<TestObject>(value);
+ CHECK(ptr.is_from_arena());
+ break;
+ }
+ return ptr;
+ }
+
+ private:
+ QuicOneBlockArena<1024> arena_;
+};
+
+INSTANTIATE_TEST_CASE_P(QuicArenaScopedPtrParamTest,
+ QuicArenaScopedPtrParamTest,
+ testing::Values(TestParam::kFromHeap,
+ TestParam::kFromArena));
+
+TEST(QuicArenaScopedPtrTest, NullObjects) {
+ QuicArenaScopedPtr<TestObject> def;
+ QuicArenaScopedPtr<TestObject> null(nullptr);
+ EXPECT_EQ(def, null);
+ EXPECT_EQ(def, nullptr);
+ EXPECT_EQ(null, nullptr);
+}
+
+TEST(QuicArenaScopedPtrTest, FromArena) {
+ QuicOneBlockArena<1024> arena_;
+ EXPECT_TRUE(arena_.New<TestObject>(0).is_from_arena());
+ EXPECT_FALSE(
+ QuicArenaScopedPtr<TestObject>(new TestObject(0)).is_from_arena());
+}
+
+TEST_P(QuicArenaScopedPtrParamTest, Assign) {
+ QuicArenaScopedPtr<TestObject> ptr = CreateObject(12345);
+ ptr = CreateObject(54321);
+ EXPECT_EQ(54321u, ptr->value);
+}
+
+TEST_P(QuicArenaScopedPtrParamTest, MoveConstruct) {
+ QuicArenaScopedPtr<TestObject> ptr1 = CreateObject(12345);
+ QuicArenaScopedPtr<TestObject> ptr2(std::move(ptr1));
+ EXPECT_EQ(nullptr, ptr1);
+ EXPECT_EQ(12345u, ptr2->value);
+}
+
+TEST_P(QuicArenaScopedPtrParamTest, Accessors) {
+ QuicArenaScopedPtr<TestObject> ptr = CreateObject(12345);
+ EXPECT_EQ(12345u, (*ptr).value);
+ EXPECT_EQ(12345u, ptr->value);
+ // We explicitly want to test that get() returns a valid pointer to the data,
+ // but the call looks redundant.
+ EXPECT_EQ(12345u, ptr.get()->value); // NOLINT
+}
+
+TEST_P(QuicArenaScopedPtrParamTest, Reset) {
+ QuicArenaScopedPtr<TestObject> ptr = CreateObject(12345);
+ ptr.reset(new TestObject(54321));
+ EXPECT_EQ(54321u, ptr->value);
+}
+
+TEST_P(QuicArenaScopedPtrParamTest, Swap) {
+ QuicArenaScopedPtr<TestObject> ptr1 = CreateObject(12345);
+ QuicArenaScopedPtr<TestObject> ptr2 = CreateObject(54321);
+ ptr1.swap(ptr2);
+ EXPECT_EQ(12345u, ptr2->value);
+ EXPECT_EQ(54321u, ptr1->value);
+}
+
+} // namespace
+} // namespace net
diff --git a/chromium/net/quic/core/quic_bandwidth.cc b/chromium/net/quic/core/quic_bandwidth.cc
new file mode 100644
index 00000000000..9ba96f3817e
--- /dev/null
+++ b/chromium/net/quic/core/quic_bandwidth.cc
@@ -0,0 +1,143 @@
+// 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/quic_bandwidth.h"
+
+#include <stdint.h>
+
+#include <limits>
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_time.h"
+#include "net/quic/core/quic_types.h"
+
+using base::StringPrintf;
+
+namespace net {
+
+// Highest number that QuicBandwidth can hold.
+const int64_t kQuicInfiniteBandwidth = INT64_C(0x7fffffffffffffff);
+
+// static
+QuicBandwidth QuicBandwidth::Zero() {
+ return QuicBandwidth(0);
+}
+
+// static
+QuicBandwidth QuicBandwidth::Infinite() {
+ return QuicBandwidth(std::numeric_limits<int64_t>::max());
+}
+
+// static
+QuicBandwidth QuicBandwidth::FromBitsPerSecond(int64_t bits_per_second) {
+ return QuicBandwidth(bits_per_second);
+}
+
+// static
+QuicBandwidth QuicBandwidth::FromKBitsPerSecond(int64_t k_bits_per_second) {
+ DCHECK(k_bits_per_second < kQuicInfiniteBandwidth / 1000);
+ return QuicBandwidth(k_bits_per_second * 1000);
+}
+
+// static
+QuicBandwidth QuicBandwidth::FromBytesPerSecond(int64_t bytes_per_second) {
+ DCHECK(bytes_per_second < kQuicInfiniteBandwidth / 8);
+ return QuicBandwidth(bytes_per_second * 8);
+}
+
+// static
+QuicBandwidth QuicBandwidth::FromKBytesPerSecond(int64_t k_bytes_per_second) {
+ DCHECK(k_bytes_per_second < kQuicInfiniteBandwidth / 8000);
+ return QuicBandwidth(k_bytes_per_second * 8000);
+}
+
+// static
+QuicBandwidth QuicBandwidth::FromBytesAndTimeDelta(QuicByteCount bytes,
+ QuicTime::Delta delta) {
+ DCHECK_LT(bytes, static_cast<uint64_t>(kQuicInfiniteBandwidth /
+ (8 * kNumMicrosPerSecond)));
+ int64_t bytes_per_second =
+ (bytes * kNumMicrosPerSecond) / delta.ToMicroseconds();
+ return QuicBandwidth(bytes_per_second * 8);
+}
+
+QuicBandwidth::QuicBandwidth(int64_t bits_per_second)
+ : bits_per_second_(bits_per_second) {
+ if (bits_per_second < 0) {
+ QUIC_BUG << "Can't set negative bandwidth " << bits_per_second;
+ bits_per_second_ = 0;
+ return;
+ }
+ bits_per_second_ = bits_per_second;
+}
+
+int64_t QuicBandwidth::ToBitsPerSecond() const {
+ return bits_per_second_;
+}
+
+int64_t QuicBandwidth::ToKBitsPerSecond() const {
+ return bits_per_second_ / 1000;
+}
+
+int64_t QuicBandwidth::ToBytesPerSecond() const {
+ return bits_per_second_ / 8;
+}
+
+int64_t QuicBandwidth::ToKBytesPerSecond() const {
+ return bits_per_second_ / 8000;
+}
+
+QuicByteCount QuicBandwidth::ToBytesPerPeriod(
+ QuicTime::Delta time_period) const {
+ return ToBytesPerSecond() * time_period.ToMicroseconds() /
+ kNumMicrosPerSecond;
+}
+
+int64_t QuicBandwidth::ToKBytesPerPeriod(QuicTime::Delta time_period) const {
+ return ToKBytesPerSecond() * time_period.ToMicroseconds() /
+ kNumMicrosPerSecond;
+}
+
+bool QuicBandwidth::IsZero() const {
+ return (bits_per_second_ == 0);
+}
+
+QuicTime::Delta QuicBandwidth::TransferTime(QuicByteCount bytes) const {
+ if (bits_per_second_ == 0) {
+ return QuicTime::Delta::Zero();
+ }
+ return QuicTime::Delta::FromMicroseconds(bytes * 8 * kNumMicrosPerSecond /
+ bits_per_second_);
+}
+
+std::string QuicBandwidth::ToDebugValue() const {
+ if (bits_per_second_ < 80000) {
+ return StringPrintf("%" PRId64 " bits/s (%" PRId64 " bytes/s)",
+ bits_per_second_, bits_per_second_ / 8);
+ }
+
+ double divisor;
+ char unit;
+ if (bits_per_second_ < 8 * 1000 * 1000) {
+ divisor = 1e3;
+ unit = 'k';
+ } else if (bits_per_second_ < INT64_C(8) * 1000 * 1000 * 1000) {
+ divisor = 1e6;
+ unit = 'M';
+ } else {
+ divisor = 1e9;
+ unit = 'G';
+ }
+
+ double bits_per_second_with_unit = bits_per_second_ / divisor;
+ double bytes_per_second_with_unit = bits_per_second_with_unit / 8;
+ return StringPrintf("%.2f %cbits/s (%.2f %cbytes/s)",
+ bits_per_second_with_unit, unit,
+ bytes_per_second_with_unit, unit);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_bandwidth.h b/chromium/net/quic/core/quic_bandwidth.h
new file mode 100644
index 00000000000..20d32be8b5d
--- /dev/null
+++ b/chromium/net/quic/core/quic_bandwidth.h
@@ -0,0 +1,124 @@
+// 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.
+//
+// QuicBandwidth represents a bandwidth, stored in bits per second resolution.
+
+#ifndef NET_QUIC_QUIC_BANDWIDTH_H_
+#define NET_QUIC_QUIC_BANDWIDTH_H_
+
+#include <stdint.h>
+
+#include <cmath>
+#include <ostream>
+
+#include "base/compiler_specific.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+typedef uint64_t QuicByteCount;
+typedef uint64_t QuicPacketCount;
+
+class NET_EXPORT_PRIVATE QuicBandwidth {
+ public:
+ // Creates a new QuicBandwidth with an internal value of 0.
+ static QuicBandwidth Zero();
+
+ // Creates a new QuicBandwidth with an internal value of INT64_MAX.
+ static QuicBandwidth Infinite();
+
+ // Create a new QuicBandwidth holding the bits per second.
+ static QuicBandwidth FromBitsPerSecond(int64_t bits_per_second);
+
+ // Create a new QuicBandwidth holding the kilo bits per second.
+ static QuicBandwidth FromKBitsPerSecond(int64_t k_bits_per_second);
+
+ // Create a new QuicBandwidth holding the bytes per second.
+ static QuicBandwidth FromBytesPerSecond(int64_t bytes_per_second);
+
+ // Create a new QuicBandwidth holding the kilo bytes per second.
+ static QuicBandwidth FromKBytesPerSecond(int64_t k_bytes_per_second);
+
+ // Create a new QuicBandwidth based on the bytes per the elapsed delta.
+ static QuicBandwidth FromBytesAndTimeDelta(QuicByteCount bytes,
+ QuicTime::Delta delta);
+
+ int64_t ToBitsPerSecond() const;
+
+ int64_t ToKBitsPerSecond() const;
+
+ int64_t ToBytesPerSecond() const;
+
+ int64_t ToKBytesPerSecond() const;
+
+ QuicByteCount ToBytesPerPeriod(QuicTime::Delta time_period) const;
+
+ int64_t ToKBytesPerPeriod(QuicTime::Delta time_period) const;
+
+ bool IsZero() const;
+
+ QuicTime::Delta TransferTime(QuicByteCount bytes) const;
+
+ std::string ToDebugValue() const;
+
+ private:
+ explicit QuicBandwidth(int64_t bits_per_second);
+ int64_t bits_per_second_;
+
+ friend QuicBandwidth operator+(QuicBandwidth lhs, QuicBandwidth rhs);
+ friend QuicBandwidth operator-(QuicBandwidth lhs, QuicBandwidth rhs);
+ friend QuicBandwidth operator*(QuicBandwidth lhs, float factor);
+};
+
+// Non-member relational operators for QuicBandwidth.
+inline bool operator==(QuicBandwidth lhs, QuicBandwidth rhs) {
+ return lhs.ToBitsPerSecond() == rhs.ToBitsPerSecond();
+}
+inline bool operator!=(QuicBandwidth lhs, QuicBandwidth rhs) {
+ return !(lhs == rhs);
+}
+inline bool operator<(QuicBandwidth lhs, QuicBandwidth rhs) {
+ return lhs.ToBitsPerSecond() < rhs.ToBitsPerSecond();
+}
+inline bool operator>(QuicBandwidth lhs, QuicBandwidth rhs) {
+ return rhs < lhs;
+}
+inline bool operator<=(QuicBandwidth lhs, QuicBandwidth rhs) {
+ return !(rhs < lhs);
+}
+inline bool operator>=(QuicBandwidth lhs, QuicBandwidth rhs) {
+ return !(lhs < rhs);
+}
+
+// Non-member arithmetic operators for QuicBandwidth.
+inline QuicBandwidth operator+(QuicBandwidth lhs, QuicBandwidth rhs) {
+ return QuicBandwidth(lhs.bits_per_second_ + rhs.bits_per_second_);
+}
+inline QuicBandwidth operator-(QuicBandwidth lhs, QuicBandwidth rhs) {
+ return QuicBandwidth(lhs.bits_per_second_ - rhs.bits_per_second_);
+}
+inline QuicBandwidth operator*(QuicBandwidth lhs, float rhs) {
+ return QuicBandwidth(
+ static_cast<int64_t>(std::llround(lhs.bits_per_second_ * rhs)));
+}
+inline QuicBandwidth operator*(float lhs, QuicBandwidth rhs) {
+ return rhs * lhs;
+}
+inline QuicByteCount operator*(QuicBandwidth lhs, QuicTime::Delta rhs) {
+ return lhs.ToBytesPerPeriod(rhs);
+}
+inline QuicByteCount operator*(QuicTime::Delta lhs, QuicBandwidth rhs) {
+ return rhs * lhs;
+}
+
+// Override stream output operator for gtest.
+inline std::ostream& operator<<(std::ostream& output,
+ const QuicBandwidth bandwidth) {
+ output << bandwidth.ToDebugValue();
+ return output;
+}
+
+} // namespace net
+#endif // NET_QUIC_QUIC_BANDWIDTH_H_
diff --git a/chromium/net/quic/core/quic_bandwidth_test.cc b/chromium/net/quic/core/quic_bandwidth_test.cc
new file mode 100644
index 00000000000..d249768eb8a
--- /dev/null
+++ b/chromium/net/quic/core/quic_bandwidth_test.cc
@@ -0,0 +1,121 @@
+// 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/quic_bandwidth.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+class QuicBandwidthTest : public ::testing::Test {};
+
+TEST_F(QuicBandwidthTest, FromTo) {
+ EXPECT_EQ(QuicBandwidth::FromKBitsPerSecond(1),
+ QuicBandwidth::FromBitsPerSecond(1000));
+ EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(1),
+ QuicBandwidth::FromBytesPerSecond(1000));
+ EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(8000),
+ QuicBandwidth::FromBytesPerSecond(1000));
+ EXPECT_EQ(QuicBandwidth::FromKBitsPerSecond(8),
+ QuicBandwidth::FromKBytesPerSecond(1));
+
+ EXPECT_EQ(0, QuicBandwidth::Zero().ToBitsPerSecond());
+ EXPECT_EQ(0, QuicBandwidth::Zero().ToKBitsPerSecond());
+ EXPECT_EQ(0, QuicBandwidth::Zero().ToBytesPerSecond());
+ EXPECT_EQ(0, QuicBandwidth::Zero().ToKBytesPerSecond());
+
+ EXPECT_EQ(1, QuicBandwidth::FromBitsPerSecond(1000).ToKBitsPerSecond());
+ EXPECT_EQ(1000, QuicBandwidth::FromKBitsPerSecond(1).ToBitsPerSecond());
+ EXPECT_EQ(1, QuicBandwidth::FromBytesPerSecond(1000).ToKBytesPerSecond());
+ EXPECT_EQ(1000, QuicBandwidth::FromKBytesPerSecond(1).ToBytesPerSecond());
+}
+
+TEST_F(QuicBandwidthTest, Add) {
+ QuicBandwidth bandwidht_1 = QuicBandwidth::FromKBitsPerSecond(1);
+ QuicBandwidth bandwidht_2 = QuicBandwidth::FromKBytesPerSecond(1);
+
+ EXPECT_EQ(9000, (bandwidht_1 + bandwidht_2).ToBitsPerSecond());
+ EXPECT_EQ(9000, (bandwidht_2 + bandwidht_1).ToBitsPerSecond());
+}
+
+TEST_F(QuicBandwidthTest, Subtract) {
+ QuicBandwidth bandwidht_1 = QuicBandwidth::FromKBitsPerSecond(1);
+ QuicBandwidth bandwidht_2 = QuicBandwidth::FromKBytesPerSecond(1);
+
+ EXPECT_EQ(7000, (bandwidht_2 - bandwidht_1).ToBitsPerSecond());
+}
+
+TEST_F(QuicBandwidthTest, TimeDelta) {
+ EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(1000),
+ QuicBandwidth::FromBytesAndTimeDelta(
+ 1000, QuicTime::Delta::FromMilliseconds(1)));
+
+ EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(10),
+ QuicBandwidth::FromBytesAndTimeDelta(
+ 1000, QuicTime::Delta::FromMilliseconds(100)));
+}
+
+TEST_F(QuicBandwidthTest, Scale) {
+ EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(500),
+ QuicBandwidth::FromKBytesPerSecond(1000) * 0.5f);
+ EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(750),
+ 0.75f * QuicBandwidth::FromKBytesPerSecond(1000));
+ EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(1250),
+ QuicBandwidth::FromKBytesPerSecond(1000) * 1.25f);
+
+ // Ensure we are rounding correctly within a 1bps level of precision.
+ EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(5),
+ QuicBandwidth::FromBitsPerSecond(9) * 0.5f);
+ EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(2),
+ QuicBandwidth::FromBitsPerSecond(12) * 0.2f);
+}
+
+TEST_F(QuicBandwidthTest, BytesPerPeriod) {
+ EXPECT_EQ(2000u, QuicBandwidth::FromKBytesPerSecond(2000)
+ .ToBytesPerPeriod(QuicTime::Delta::FromMilliseconds(1)));
+ EXPECT_EQ(2u, QuicBandwidth::FromKBytesPerSecond(2000)
+ .ToKBytesPerPeriod(QuicTime::Delta::FromMilliseconds(1)));
+ EXPECT_EQ(200000u, QuicBandwidth::FromKBytesPerSecond(2000).ToBytesPerPeriod(
+ QuicTime::Delta::FromMilliseconds(100)));
+ EXPECT_EQ(200u, QuicBandwidth::FromKBytesPerSecond(2000).ToKBytesPerPeriod(
+ QuicTime::Delta::FromMilliseconds(100)));
+}
+
+TEST_F(QuicBandwidthTest, TransferTime) {
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(1),
+ QuicBandwidth::FromKBytesPerSecond(1).TransferTime(1000));
+ EXPECT_EQ(QuicTime::Delta::Zero(), QuicBandwidth::Zero().TransferTime(1000));
+}
+
+TEST_F(QuicBandwidthTest, RelOps) {
+ const QuicBandwidth b1 = QuicBandwidth::FromKBitsPerSecond(1);
+ const QuicBandwidth b2 = QuicBandwidth::FromKBytesPerSecond(2);
+ EXPECT_EQ(b1, b1);
+ EXPECT_NE(b1, b2);
+ EXPECT_LT(b1, b2);
+ EXPECT_GT(b2, b1);
+ EXPECT_LE(b1, b1);
+ EXPECT_LE(b1, b2);
+ EXPECT_GE(b1, b1);
+ EXPECT_GE(b2, b1);
+}
+
+TEST_F(QuicBandwidthTest, DebugValue) {
+ EXPECT_EQ("128 bits/s (16 bytes/s)",
+ QuicBandwidth::FromBytesPerSecond(16).ToDebugValue());
+ EXPECT_EQ("4096 bits/s (512 bytes/s)",
+ QuicBandwidth::FromBytesPerSecond(512).ToDebugValue());
+
+ QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond(1000 * 50);
+ EXPECT_EQ("400.00 kbits/s (50.00 kbytes/s)", bandwidth.ToDebugValue());
+
+ bandwidth = bandwidth * 1000;
+ EXPECT_EQ("400.00 Mbits/s (50.00 Mbytes/s)", bandwidth.ToDebugValue());
+
+ bandwidth = bandwidth * 1000;
+ EXPECT_EQ("400.00 Gbits/s (50.00 Gbytes/s)", bandwidth.ToDebugValue());
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/quic_blocked_writer_interface.h b/chromium/net/quic/core/quic_blocked_writer_interface.h
index a3a2622a599..a3a2622a599 100644
--- a/chromium/net/quic/quic_blocked_writer_interface.h
+++ b/chromium/net/quic/core/quic_blocked_writer_interface.h
diff --git a/chromium/net/quic/core/quic_buffered_packet_store.cc b/chromium/net/quic/core/quic_buffered_packet_store.cc
new file mode 100644
index 00000000000..00daa68d68f
--- /dev/null
+++ b/chromium/net/quic/core/quic_buffered_packet_store.cc
@@ -0,0 +1,223 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_buffered_packet_store.h"
+
+#include <list>
+
+#include "base/stl_util.h"
+#include "net/quic/core/quic_bug_tracker.h"
+
+using std::list;
+
+namespace net {
+
+typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket;
+typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult;
+typedef QuicBufferedPacketStore::BufferedPacketList BufferedPacketList;
+
+// Max number of connections this store can keep track.
+static const size_t kDefaultMaxConnectionsInStore = 100;
+// Up to half of the capacity can be used for storing non-CHLO packets.
+static const size_t kMaxConnectionsWithoutCHLO =
+ kDefaultMaxConnectionsInStore / 2;
+
+namespace {
+
+// This alarm removes expired entries in map each time this alarm fires.
+class ConnectionExpireAlarm : public QuicAlarm::Delegate {
+ public:
+ explicit ConnectionExpireAlarm(QuicBufferedPacketStore* store)
+ : connection_store_(store) {}
+
+ void OnAlarm() override { connection_store_->OnExpirationTimeout(); }
+
+ // Disallow copy and asign.
+ ConnectionExpireAlarm(const ConnectionExpireAlarm&) = delete;
+ ConnectionExpireAlarm& operator=(const ConnectionExpireAlarm&) = delete;
+
+ private:
+ QuicBufferedPacketStore* connection_store_;
+};
+
+} // namespace
+
+BufferedPacket::BufferedPacket(std::unique_ptr<QuicReceivedPacket> packet,
+ IPEndPoint server_address,
+ IPEndPoint client_address)
+ : packet(std::move(packet)),
+ server_address(server_address),
+ client_address(client_address) {}
+
+BufferedPacket::BufferedPacket(BufferedPacket&& other) = default;
+
+BufferedPacket& BufferedPacket::operator=(BufferedPacket&& other) = default;
+
+BufferedPacket::~BufferedPacket() {}
+
+BufferedPacketList::BufferedPacketList() : creation_time(QuicTime::Zero()) {}
+
+BufferedPacketList::BufferedPacketList(BufferedPacketList&& other) = default;
+
+BufferedPacketList& BufferedPacketList::operator=(BufferedPacketList&& other) =
+ default;
+
+BufferedPacketList::~BufferedPacketList() {}
+
+QuicBufferedPacketStore::QuicBufferedPacketStore(
+ VisitorInterface* visitor,
+ const QuicClock* clock,
+ QuicAlarmFactory* alarm_factory)
+ : connection_life_span_(
+ QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs)),
+ visitor_(visitor),
+ clock_(clock),
+ expiration_alarm_(
+ alarm_factory->CreateAlarm(new ConnectionExpireAlarm(this))) {}
+
+QuicBufferedPacketStore::~QuicBufferedPacketStore() {}
+
+EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket(
+ QuicConnectionId connection_id,
+ const QuicReceivedPacket& packet,
+ IPEndPoint server_address,
+ IPEndPoint client_address,
+ bool is_chlo) {
+ QUIC_BUG_IF(is_chlo &&
+ base::ContainsKey(connections_with_chlo_, connection_id))
+ << "Shouldn't buffer duplicated CHLO on connection " << connection_id;
+
+ if (!base::ContainsKey(undecryptable_packets_, connection_id) &&
+ ShouldBufferPacket(is_chlo)) {
+ // Drop the packet if the upper limit of undecryptable packets has been
+ // reached or the whole capacity of the store has been reached.
+ return TOO_MANY_CONNECTIONS;
+ } else if (!base::ContainsKey(undecryptable_packets_, connection_id)) {
+ undecryptable_packets_.emplace(
+ std::make_pair(connection_id, BufferedPacketList()));
+ }
+ CHECK(base::ContainsKey(undecryptable_packets_, connection_id));
+ BufferedPacketList& queue =
+ undecryptable_packets_.find(connection_id)->second;
+
+ if (!is_chlo) {
+ // If current packet is not CHLO, it might not be buffered because store
+ // only buffers certain number of undecryptable packets per connection.
+ size_t num_non_chlo_packets =
+ base::ContainsKey(connections_with_chlo_, connection_id)
+ ? (queue.buffered_packets.size() - 1)
+ : queue.buffered_packets.size();
+ if (num_non_chlo_packets >= kDefaultMaxUndecryptablePackets) {
+ // If there are kMaxBufferedPacketsPerConnection packets buffered up for
+ // this connection, drop the current packet.
+ return TOO_MANY_PACKETS;
+ }
+ }
+
+ if (queue.buffered_packets.empty()) {
+ // If this is the first packet arrived on a new connection, initialize the
+ // creation time.
+ queue.creation_time = clock_->ApproximateNow();
+ }
+
+ BufferedPacket new_entry(std::unique_ptr<QuicReceivedPacket>(packet.Clone()),
+ server_address, client_address);
+ if (is_chlo) {
+ // Add CHLO to the beginning of buffered packets so that it can be delivered
+ // first later.
+ queue.buffered_packets.push_front(std::move(new_entry));
+ connections_with_chlo_[connection_id] = false; // Dummy value.
+ } else {
+ // Buffer non-CHLO packets in arrival order.
+ queue.buffered_packets.push_back(std::move(new_entry));
+ }
+ MaybeSetExpirationAlarm();
+ return SUCCESS;
+}
+
+bool QuicBufferedPacketStore::HasBufferedPackets(
+ QuicConnectionId connection_id) const {
+ return base::ContainsKey(undecryptable_packets_, connection_id);
+}
+
+bool QuicBufferedPacketStore::HasChlosBuffered() const {
+ return !connections_with_chlo_.empty();
+}
+
+list<BufferedPacket> QuicBufferedPacketStore::DeliverPackets(
+ QuicConnectionId connection_id) {
+ list<BufferedPacket> packets_to_deliver;
+ auto it = undecryptable_packets_.find(connection_id);
+ if (it != undecryptable_packets_.end()) {
+ packets_to_deliver = std::move(it->second.buffered_packets);
+ undecryptable_packets_.erase(connection_id);
+ }
+ return packets_to_deliver;
+}
+
+void QuicBufferedPacketStore::DiscardPackets(QuicConnectionId connection_id) {
+ undecryptable_packets_.erase(connection_id);
+ connections_with_chlo_.erase(connection_id);
+}
+
+void QuicBufferedPacketStore::OnExpirationTimeout() {
+ QuicTime expiration_time = clock_->ApproximateNow() - connection_life_span_;
+ while (!undecryptable_packets_.empty()) {
+ auto& entry = undecryptable_packets_.front();
+ if (entry.second.creation_time > expiration_time) {
+ break;
+ }
+ QuicConnectionId connection_id = entry.first;
+ visitor_->OnExpiredPackets(connection_id, std::move(entry.second));
+ undecryptable_packets_.erase(undecryptable_packets_.begin());
+ connections_with_chlo_.erase(connection_id);
+ }
+ if (!undecryptable_packets_.empty()) {
+ expiration_alarm_->Set(clock_->ApproximateNow() + connection_life_span_);
+ }
+}
+
+void QuicBufferedPacketStore::MaybeSetExpirationAlarm() {
+ if (!expiration_alarm_->IsSet()) {
+ expiration_alarm_->Set(clock_->ApproximateNow() + connection_life_span_);
+ }
+}
+
+bool QuicBufferedPacketStore::ShouldBufferPacket(bool is_chlo) {
+ bool is_store_full =
+ undecryptable_packets_.size() >= kDefaultMaxConnectionsInStore;
+
+ if (is_chlo) {
+ return is_store_full;
+ }
+
+ size_t num_connections_without_chlo =
+ undecryptable_packets_.size() - connections_with_chlo_.size();
+ bool reach_non_chlo_limit =
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop &&
+ num_connections_without_chlo >= kMaxConnectionsWithoutCHLO;
+
+ return is_store_full || reach_non_chlo_limit;
+}
+
+list<BufferedPacket> QuicBufferedPacketStore::DeliverPacketsForNextConnection(
+ QuicConnectionId* connection_id) {
+ if (connections_with_chlo_.empty()) {
+ // Returns empty list if no CHLO has been buffered.
+ return list<BufferedPacket>();
+ }
+ *connection_id = connections_with_chlo_.front().first;
+ connections_with_chlo_.erase(connections_with_chlo_.begin());
+
+ list<BufferedPacket> packets = DeliverPackets(*connection_id);
+ DCHECK(!packets.empty()) << "Try to deliver connectons without CHLO";
+ return packets;
+}
+
+bool QuicBufferedPacketStore::HasChloForConnection(
+ QuicConnectionId connection_id) {
+ return base::ContainsKey(connections_with_chlo_, connection_id);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_buffered_packet_store.h b/chromium/net/quic/core/quic_buffered_packet_store.h
new file mode 100644
index 00000000000..364ea669570
--- /dev/null
+++ b/chromium/net/quic/core/quic_buffered_packet_store.h
@@ -0,0 +1,161 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_BUFFERED_PACKET_STORE_H_
+#define NET_QUIC_QUIC_BUFFERED_PACKET_STORE_H_
+
+#include "net/base/ip_address.h"
+#include "net/base/linked_hash_map.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_alarm.h"
+#include "net/quic/core/quic_alarm_factory.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+namespace test {
+class QuicBufferedPacketStorePeer;
+} // namespace test
+
+// This class buffers packets for each connection until either
+// 1) They are requested to be delivered via
+// DeliverPacket()/DeliverPacketsForNextConnection(), or
+// 2) They expire after exceeding their lifetime in the store.
+//
+// It can only buffer packets on certain number of connections. It has two pools
+// of connections: connections with CHLO buffered and those without CHLO. The
+// latter has its own upper limit along with the max number of connections this
+// store can hold. The former pool can grow till this store is full.
+class NET_EXPORT_PRIVATE QuicBufferedPacketStore {
+ public:
+ enum EnqueuePacketResult {
+ SUCCESS = 0,
+ TOO_MANY_PACKETS, // Too many packets stored up for a certain connection.
+ TOO_MANY_CONNECTIONS // Too many connections stored up in the store.
+ };
+
+ // A packets with client/server address.
+ struct NET_EXPORT_PRIVATE BufferedPacket {
+ BufferedPacket(std::unique_ptr<QuicReceivedPacket> packet,
+ IPEndPoint server_address,
+ IPEndPoint client_address);
+ BufferedPacket(BufferedPacket&& other);
+
+ BufferedPacket& operator=(BufferedPacket&& other);
+
+ ~BufferedPacket();
+
+ std::unique_ptr<QuicReceivedPacket> packet;
+ IPEndPoint server_address;
+ IPEndPoint client_address;
+ };
+
+ // A queue of BufferedPackets for a connection.
+ struct NET_EXPORT_PRIVATE BufferedPacketList {
+ BufferedPacketList();
+ BufferedPacketList(BufferedPacketList&& other);
+
+ BufferedPacketList& operator=(BufferedPacketList&& other);
+
+ ~BufferedPacketList();
+
+ std::list<BufferedPacket> buffered_packets;
+ QuicTime creation_time;
+ };
+
+ typedef linked_hash_map<QuicConnectionId, BufferedPacketList>
+ BufferedPacketMap;
+
+ class NET_EXPORT_PRIVATE VisitorInterface {
+ public:
+ virtual ~VisitorInterface() {}
+
+ // Called for each expired connection when alarm fires.
+ virtual void OnExpiredPackets(QuicConnectionId connection_id,
+ BufferedPacketList early_arrived_packets) = 0;
+ };
+
+ QuicBufferedPacketStore(VisitorInterface* vistor,
+ const QuicClock* clock,
+ QuicAlarmFactory* alarm_factory);
+
+ QuicBufferedPacketStore(const QuicBufferedPacketStore&) = delete;
+
+ ~QuicBufferedPacketStore();
+
+ QuicBufferedPacketStore& operator=(const QuicBufferedPacketStore&) = delete;
+
+ // Adds a copy of packet into packet queue for given connection.
+ EnqueuePacketResult EnqueuePacket(QuicConnectionId connection_id,
+ const QuicReceivedPacket& packet,
+ IPEndPoint server_address,
+ IPEndPoint client_address,
+ bool is_chlo);
+
+ // Returns true if there are any packets buffered for |connection_id|.
+ bool HasBufferedPackets(QuicConnectionId connection_id) const;
+
+ // Returns the list of buffered packets for |connection_id| and removes them
+ // from the store. Returns an empty list if no early arrived packets for this
+ // connection are present.
+ std::list<BufferedPacket> DeliverPackets(QuicConnectionId connection_id);
+
+ // Discards packets buffered for |connection_id|, if any.
+ void DiscardPackets(QuicConnectionId connection_id);
+
+ // Examines how long packets have been buffered in the store for each
+ // connection. If they stay too long, removes them for new coming packets and
+ // calls |visitor_|'s OnPotentialConnectionExpire().
+ // Resets the alarm at the end.
+ void OnExpirationTimeout();
+
+ // Delivers buffered packets for next connection with CHLO to open.
+ // Return connection id for next connection in |connection_id|
+ // and all buffered packets including CHLO.
+ // The returned std::list should at least has one packet(CHLO) if
+ // store does have any connection to open. If no connection in the store has
+ // received CHLO yet, empty std::list will be returned.
+ std::list<BufferedPacket> DeliverPacketsForNextConnection(
+ QuicConnectionId* connection_id);
+
+ // Is given connection already buffered in the store?
+ bool HasChloForConnection(QuicConnectionId connection_id);
+
+ // Is there any CHLO buffered in the store?
+ bool HasChlosBuffered() const;
+
+ private:
+ friend class test::QuicBufferedPacketStorePeer;
+
+ // Set expiration alarm if it hasn't been set.
+ void MaybeSetExpirationAlarm();
+
+ // Return true if add an extra packet will go beyond allowed max connection
+ // limit. The limit for non-CHLO packet and CHLO packet is different.
+ bool ShouldBufferPacket(bool is_chlo);
+
+ // A map to store packet queues with creation time for each connection.
+ BufferedPacketMap undecryptable_packets_;
+
+ // The max time the packets of a connection can be buffer in the store.
+ QuicTime::Delta connection_life_span_;
+
+ VisitorInterface* visitor_; // Unowned.
+
+ const QuicClock* clock_; // Unowned.
+
+ // This alarm fires every |connection_life_span_| to clean up
+ // packets staying in the store for too long.
+ std::unique_ptr<QuicAlarm> expiration_alarm_;
+
+ // Keeps track of connection with CHLO buffered up already and the order they
+ // arrive.
+ linked_hash_map<QuicConnectionId, bool> connections_with_chlo_;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_BUFFERED_PACKET_STORE_H_
diff --git a/chromium/net/quic/core/quic_buffered_packet_store_test.cc b/chromium/net/quic/core/quic_buffered_packet_store_test.cc
new file mode 100644
index 00000000000..cf9e6087117
--- /dev/null
+++ b/chromium/net/quic/core/quic_buffered_packet_store_test.cc
@@ -0,0 +1,482 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_buffered_packet_store.h"
+
+#include <list>
+#include <string>
+
+#include "base/stl_util.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/quic_buffered_packet_store_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::list;
+using std::string;
+
+namespace net {
+
+typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket;
+typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult;
+
+static const size_t kDefaultMaxConnectionsInStore = 100;
+static const size_t kMaxConnectionsWithoutCHLO =
+ kDefaultMaxConnectionsInStore / 2;
+
+namespace test {
+namespace {
+
+typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket;
+typedef QuicBufferedPacketStore::BufferedPacketList BufferedPacketList;
+
+class QuicBufferedPacketStoreVisitor
+ : public QuicBufferedPacketStore::VisitorInterface {
+ public:
+ QuicBufferedPacketStoreVisitor() {}
+
+ ~QuicBufferedPacketStoreVisitor() override {}
+
+ void OnExpiredPackets(QuicConnectionId connection_id,
+ BufferedPacketList early_arrived_packets) override {
+ last_expired_packet_queue_ = std::move(early_arrived_packets);
+ }
+
+ // The packets queue for most recently expirect connection.
+ BufferedPacketList last_expired_packet_queue_;
+};
+
+class QuicBufferedPacketStoreTest : public ::testing::Test {
+ public:
+ QuicBufferedPacketStoreTest()
+ : store_(&visitor_, &clock_, &alarm_factory_),
+ server_address_(Loopback6(), 65535),
+ client_address_(Loopback6(), 65535),
+ packet_content_("some encrypted content"),
+ packet_time_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(42)),
+ packet_(packet_content_.data(), packet_content_.size(), packet_time_) {}
+
+ protected:
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+ QuicBufferedPacketStoreVisitor visitor_;
+ MockClock clock_;
+ MockAlarmFactory alarm_factory_;
+ QuicBufferedPacketStore store_;
+ IPEndPoint server_address_;
+ IPEndPoint client_address_;
+ string packet_content_;
+ QuicTime packet_time_;
+ QuicReceivedPacket packet_;
+};
+
+TEST_F(QuicBufferedPacketStoreTest, SimpleEnqueueAndDeliverPacket) {
+ QuicConnectionId connection_id = 1;
+ store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_,
+ false);
+ EXPECT_TRUE(store_.HasBufferedPackets(connection_id));
+ list<BufferedPacket> queue = store_.DeliverPackets(connection_id);
+ ASSERT_EQ(1u, queue.size());
+ // Check content of the only packet in the queue.
+ EXPECT_EQ(packet_content_, queue.front().packet->AsStringPiece());
+ EXPECT_EQ(packet_time_, queue.front().packet->receipt_time());
+ EXPECT_EQ(client_address_, queue.front().client_address);
+ EXPECT_EQ(server_address_, queue.front().server_address);
+ // No more packets on connection 1 should remain in the store.
+ EXPECT_TRUE(store_.DeliverPackets(connection_id).empty());
+ EXPECT_FALSE(store_.HasBufferedPackets(connection_id));
+}
+
+TEST_F(QuicBufferedPacketStoreTest, DifferentPacketAddressOnOneConnection) {
+ IPEndPoint addr_with_new_port(Loopback4(), 256);
+ QuicConnectionId connection_id = 1;
+ store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_,
+ false);
+ store_.EnqueuePacket(connection_id, packet_, server_address_,
+ addr_with_new_port, false);
+ list<BufferedPacket> queue = store_.DeliverPackets(connection_id);
+ ASSERT_EQ(2u, queue.size());
+ // The address migration path should be preserved.
+ EXPECT_EQ(client_address_, queue.front().client_address);
+ EXPECT_EQ(addr_with_new_port, queue.back().client_address);
+}
+
+TEST_F(QuicBufferedPacketStoreTest,
+ EnqueueAndDeliverMultiplePacketsOnMultipleConnections) {
+ size_t num_connections = 10;
+ for (QuicConnectionId connection_id = 1; connection_id <= num_connections;
+ ++connection_id) {
+ store_.EnqueuePacket(connection_id, packet_, server_address_,
+ client_address_, false);
+ store_.EnqueuePacket(connection_id, packet_, server_address_,
+ client_address_, false);
+ }
+
+ // Deliver packets in reversed order.
+ for (QuicConnectionId connection_id = num_connections; connection_id > 0;
+ --connection_id) {
+ list<BufferedPacket> queue = store_.DeliverPackets(connection_id);
+ ASSERT_EQ(2u, queue.size());
+ }
+}
+
+TEST_F(QuicBufferedPacketStoreTest,
+ FailToBufferTooManyPacketsOnExistingConnection) {
+ // Tests that for one connection, only limited number of packets can be
+ // buffered.
+ size_t num_packets = kDefaultMaxUndecryptablePackets + 1;
+ QuicConnectionId connection_id = 1;
+ if (FLAGS_quic_limit_num_new_sessions_per_epoll_loop) {
+ // Arrived CHLO packet shouldn't affect how many non-CHLO pacekts store can
+ // keep.
+ EXPECT_EQ(QuicBufferedPacketStore::SUCCESS,
+ store_.EnqueuePacket(connection_id, packet_, server_address_,
+ client_address_, true));
+ }
+ for (size_t i = 1; i <= num_packets; ++i) {
+ // Only first |kDefaultMaxUndecryptablePackets packets| will be buffered.
+ EnqueuePacketResult result = store_.EnqueuePacket(
+ connection_id, packet_, server_address_, client_address_, false);
+ if (i <= kDefaultMaxUndecryptablePackets) {
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS, result);
+ } else {
+ EXPECT_EQ(EnqueuePacketResult::TOO_MANY_PACKETS, result);
+ }
+ }
+
+ // Only first |kDefaultMaxUndecryptablePackets| non-CHLO packets and CHLO are
+ // buffered.
+ EXPECT_EQ(kDefaultMaxUndecryptablePackets +
+ (FLAGS_quic_limit_num_new_sessions_per_epoll_loop ? 1 : 0),
+ store_.DeliverPackets(connection_id).size());
+}
+
+TEST_F(QuicBufferedPacketStoreTest, ReachNonChloConnectionUpperLimit) {
+ // Tests that store can only keep early arrived packets for limited number of
+ // connections.
+ const size_t kNumConnections =
+ (FLAGS_quic_limit_num_new_sessions_per_epoll_loop
+ ? kMaxConnectionsWithoutCHLO
+ : kDefaultMaxConnectionsInStore) +
+ 1;
+ for (size_t connection_id = 1; connection_id <= kNumConnections;
+ ++connection_id) {
+ EnqueuePacketResult result = store_.EnqueuePacket(
+ connection_id, packet_, server_address_, client_address_, false);
+ if (connection_id <= (FLAGS_quic_limit_num_new_sessions_per_epoll_loop
+ ? kMaxConnectionsWithoutCHLO
+ : kDefaultMaxConnectionsInStore)) {
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS, result);
+ } else {
+ EXPECT_EQ(EnqueuePacketResult::TOO_MANY_CONNECTIONS, result);
+ }
+ }
+ // Store only keeps early arrived packets upto |kNumConnections| connections.
+ for (size_t connection_id = 1; connection_id <= kNumConnections;
+ ++connection_id) {
+ list<BufferedPacket> queue = store_.DeliverPackets(connection_id);
+ if (connection_id <= (FLAGS_quic_limit_num_new_sessions_per_epoll_loop
+ ? kMaxConnectionsWithoutCHLO
+ : kDefaultMaxConnectionsInStore)) {
+ EXPECT_EQ(1u, queue.size());
+ } else {
+ EXPECT_EQ(0u, queue.size());
+ }
+ }
+}
+
+TEST_F(QuicBufferedPacketStoreTest,
+ FullStoreFailToBufferDataPacketOnNewConnection) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
+ // Send enough CHLOs so that store gets full before number of connections
+ // without CHLO reaches its upper limit.
+ size_t num_chlos =
+ kDefaultMaxConnectionsInStore - kMaxConnectionsWithoutCHLO + 1;
+ for (size_t connection_id = 1; connection_id <= num_chlos; ++connection_id) {
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS,
+ store_.EnqueuePacket(connection_id, packet_, server_address_,
+ client_address_, true));
+ }
+
+ // Send data packets on another |kMaxConnectionsWithoutCHLO| connections.
+ // Store should only be able to buffer till it's full.
+ for (size_t conn_id = num_chlos + 1;
+ conn_id <= (kDefaultMaxConnectionsInStore + 1); ++conn_id) {
+ EnqueuePacketResult result = store_.EnqueuePacket(
+ conn_id, packet_, server_address_, client_address_, true);
+ if (conn_id <= kDefaultMaxConnectionsInStore) {
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS, result);
+ } else {
+ EXPECT_EQ(EnqueuePacketResult::TOO_MANY_CONNECTIONS, result);
+ }
+ }
+}
+
+TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
+ // Buffer data packets on different connections upto limit.
+ for (QuicConnectionId conn_id = 1; conn_id <= kMaxConnectionsWithoutCHLO;
+ ++conn_id) {
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS,
+ store_.EnqueuePacket(conn_id, packet_, server_address_,
+ client_address_, false));
+ }
+
+ // Buffer CHLOs on other connections till store is full.
+ for (size_t i = kMaxConnectionsWithoutCHLO + 1;
+ i <= kDefaultMaxConnectionsInStore + 1; ++i) {
+ EnqueuePacketResult rs = store_.EnqueuePacket(
+ /*connection_id=*/i, packet_, server_address_, client_address_, true);
+ if (i <= kDefaultMaxConnectionsInStore) {
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS, rs);
+ EXPECT_TRUE(store_.HasChloForConnection(/*connection_id=*/i));
+ } else {
+ // Last CHLO can't be buffered because store is full.
+ EXPECT_EQ(EnqueuePacketResult::TOO_MANY_CONNECTIONS, rs);
+ EXPECT_FALSE(store_.HasChloForConnection(/*connection_id=*/i));
+ }
+ }
+
+ // But buffering a CHLO belonging to a connection already has data packet
+ // buffered in the store should success. This is the connection should be
+ // delivered at last.
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS,
+ store_.EnqueuePacket(/*connection_id=*/1, packet_, server_address_,
+ client_address_, true));
+ EXPECT_TRUE(store_.HasChloForConnection(/*connection_id=*/1));
+
+ QuicConnectionId delivered_conn_id;
+ for (size_t i = 0;
+ i < kDefaultMaxConnectionsInStore - kMaxConnectionsWithoutCHLO + 1;
+ ++i) {
+ if (i < kDefaultMaxConnectionsInStore - kMaxConnectionsWithoutCHLO) {
+ // Only CHLO is buffered.
+ EXPECT_EQ(
+ 1u,
+ store_.DeliverPacketsForNextConnection(&delivered_conn_id).size());
+ EXPECT_EQ(i + kMaxConnectionsWithoutCHLO + 1, delivered_conn_id);
+ } else {
+ EXPECT_EQ(
+ 2u,
+ store_.DeliverPacketsForNextConnection(&delivered_conn_id).size());
+ EXPECT_EQ(1u, delivered_conn_id);
+ }
+ }
+ EXPECT_FALSE(store_.HasChlosBuffered());
+}
+
+TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery1) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = false;
+ QuicConnectionId connection_id = 1;
+ store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_,
+ false);
+ // Packet for another connection arrive 1ms later.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+ QuicConnectionId connection_id2 = 2;
+ // Use different client address to differetiate packets from different
+ // connections.
+ IPEndPoint another_client_address(Loopback4(), 255);
+ store_.EnqueuePacket(connection_id2, packet_, server_address_,
+ another_client_address, false);
+ // Advance clock to the time when connection 1 expires.
+ clock_.AdvanceTime(
+ QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() -
+ clock_.ApproximateNow());
+ ASSERT_GE(clock_.ApproximateNow(),
+ QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline());
+ // Fire alarm to remove long-staying connection 1 packets.
+ alarm_factory_.FireAlarm(
+ QuicBufferedPacketStorePeer::expiration_alarm(&store_));
+ EXPECT_EQ(1u, visitor_.last_expired_packet_queue_.buffered_packets.size());
+ // Try to deliver packets, but packet queue has been removed so no
+ // packets can be returned.
+ ASSERT_EQ(0u, store_.DeliverPackets(connection_id).size());
+
+ // Deliver packets on connection 2. And the queue for connection 2 should be
+ // returned.
+ list<BufferedPacket> queue = store_.DeliverPackets(connection_id2);
+ ASSERT_EQ(1u, queue.size());
+ // Packets in connection 2 should use another client address.
+ EXPECT_EQ(another_client_address, queue.front().client_address);
+
+ // Test the alarm is reset by enqueueing 2 packets for 3rd connection and wait
+ // for them to expire.
+ QuicConnectionId connection_id3 = 3;
+ store_.EnqueuePacket(connection_id3, packet_, server_address_,
+ client_address_, false);
+ store_.EnqueuePacket(connection_id3, packet_, server_address_,
+ client_address_, false);
+ clock_.AdvanceTime(
+ QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() -
+ clock_.ApproximateNow());
+ alarm_factory_.FireAlarm(
+ QuicBufferedPacketStorePeer::expiration_alarm(&store_));
+ // |last_expired_packet_queue_| should be updated.
+ EXPECT_EQ(2u, visitor_.last_expired_packet_queue_.buffered_packets.size());
+}
+
+// Tests that store expires long-staying connections appropriately for
+// connections both with and without CHLOs.
+TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery2) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
+ QuicConnectionId connection_id = 1;
+ store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_,
+ false);
+ if (FLAGS_quic_limit_num_new_sessions_per_epoll_loop) {
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS,
+ store_.EnqueuePacket(connection_id, packet_, server_address_,
+ client_address_, true));
+ }
+ QuicConnectionId connection_id2 = 2;
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS,
+ store_.EnqueuePacket(connection_id2, packet_, server_address_,
+ client_address_, false));
+
+ // CHLO on connection 3 arrives 1ms later.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+ QuicConnectionId connection_id3 = 3;
+ // Use different client address to differetiate packets from different
+ // connections.
+ IPEndPoint another_client_address(Any4(), 255);
+ store_.EnqueuePacket(connection_id3, packet_, server_address_,
+ another_client_address, true);
+
+ // Advance clock to the time when connection 1 and 2 expires.
+ clock_.AdvanceTime(
+ QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() -
+ clock_.ApproximateNow());
+ ASSERT_GE(clock_.ApproximateNow(),
+ QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline());
+ // Fire alarm to remove long-staying connection 1 and 2 packets.
+ alarm_factory_.FireAlarm(
+ QuicBufferedPacketStorePeer::expiration_alarm(&store_));
+ EXPECT_EQ(1u, visitor_.last_expired_packet_queue_.buffered_packets.size());
+ EXPECT_FALSE(store_.HasBufferedPackets(connection_id));
+ EXPECT_FALSE(store_.HasBufferedPackets(connection_id2));
+
+ // Try to deliver packets, but packet queue has been removed so no
+ // packets can be returned.
+ ASSERT_EQ(0u, store_.DeliverPackets(connection_id).size());
+ ASSERT_EQ(0u, store_.DeliverPackets(connection_id2).size());
+ QuicConnectionId delivered_conn_id;
+ auto queue = store_.DeliverPacketsForNextConnection(&delivered_conn_id);
+ // Connection 3 is the next to be delivered as connection 1 already expired.
+ EXPECT_EQ(connection_id3, delivered_conn_id);
+ ASSERT_EQ(1u, queue.size());
+ // Packets in connection 3 should use another client address.
+ EXPECT_EQ(another_client_address, queue.front().client_address);
+
+ // Test the alarm is reset by enqueueing 2 packets for 4th connection and wait
+ // for them to expire.
+ QuicConnectionId connection_id4 = 4;
+ store_.EnqueuePacket(connection_id4, packet_, server_address_,
+ client_address_, false);
+ store_.EnqueuePacket(connection_id4, packet_, server_address_,
+ client_address_, false);
+ clock_.AdvanceTime(
+ QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() -
+ clock_.ApproximateNow());
+ alarm_factory_.FireAlarm(
+ QuicBufferedPacketStorePeer::expiration_alarm(&store_));
+ // |last_expired_packet_queue_| should be updated.
+ EXPECT_EQ(2u, visitor_.last_expired_packet_queue_.buffered_packets.size());
+}
+
+TEST_F(QuicBufferedPacketStoreTest, SimpleDiscardPackets) {
+ QuicConnectionId connection_id = 1;
+
+ // Enqueue some packets
+ store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_,
+ false);
+ store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_,
+ false);
+ EXPECT_TRUE(store_.HasBufferedPackets(connection_id));
+ EXPECT_FALSE(store_.HasChlosBuffered());
+
+ // Dicard the packets
+ store_.DiscardPackets(connection_id);
+
+ // No packets on connection 1 should remain in the store
+ EXPECT_TRUE(store_.DeliverPackets(connection_id).empty());
+ EXPECT_FALSE(store_.HasBufferedPackets(connection_id));
+ EXPECT_FALSE(store_.HasChlosBuffered());
+
+ // Check idempotency
+ store_.DiscardPackets(connection_id);
+ EXPECT_TRUE(store_.DeliverPackets(connection_id).empty());
+ EXPECT_FALSE(store_.HasBufferedPackets(connection_id));
+ EXPECT_FALSE(store_.HasChlosBuffered());
+}
+
+TEST_F(QuicBufferedPacketStoreTest, DiscardWithCHLOs) {
+ QuicConnectionId connection_id = 1;
+
+ // Enqueue some packets, which include a CHLO
+ store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_,
+ false);
+ store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_,
+ true);
+ store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_,
+ false);
+ EXPECT_TRUE(store_.HasBufferedPackets(connection_id));
+ EXPECT_TRUE(store_.HasChlosBuffered());
+
+ // Dicard the packets
+ store_.DiscardPackets(connection_id);
+
+ // No packets on connection 1 should remain in the store
+ EXPECT_TRUE(store_.DeliverPackets(connection_id).empty());
+ EXPECT_FALSE(store_.HasBufferedPackets(connection_id));
+ EXPECT_FALSE(store_.HasChlosBuffered());
+
+ // Check idempotency
+ store_.DiscardPackets(connection_id);
+ EXPECT_TRUE(store_.DeliverPackets(connection_id).empty());
+ EXPECT_FALSE(store_.HasBufferedPackets(connection_id));
+ EXPECT_FALSE(store_.HasChlosBuffered());
+}
+
+TEST_F(QuicBufferedPacketStoreTest, MultipleDiscardPackets) {
+ QuicConnectionId connection_id_1 = 1;
+ QuicConnectionId connection_id_2 = 2;
+
+ // Enqueue some packets for two connection IDs
+ store_.EnqueuePacket(connection_id_1, packet_, server_address_,
+ client_address_, false);
+ store_.EnqueuePacket(connection_id_1, packet_, server_address_,
+ client_address_, false);
+ store_.EnqueuePacket(connection_id_2, packet_, server_address_,
+ client_address_, false);
+ EXPECT_TRUE(store_.HasBufferedPackets(connection_id_1));
+ EXPECT_TRUE(store_.HasBufferedPackets(connection_id_2));
+ EXPECT_FALSE(store_.HasChlosBuffered());
+
+ // Discard the packets for connection 1
+ store_.DiscardPackets(connection_id_1);
+
+ // No packets on connection 1 should remain in the store
+ EXPECT_TRUE(store_.DeliverPackets(connection_id_1).empty());
+ EXPECT_FALSE(store_.HasBufferedPackets(connection_id_1));
+ EXPECT_FALSE(store_.HasChlosBuffered());
+
+ // Packets on connection 2 should remain
+ EXPECT_TRUE(store_.HasBufferedPackets(connection_id_2));
+ EXPECT_EQ(1u, store_.DeliverPackets(connection_id_2).size());
+ EXPECT_FALSE(store_.HasChlosBuffered());
+}
+
+TEST_F(QuicBufferedPacketStoreTest, DiscardPacketsEmpty) {
+ // Check that DiscardPackets on an unknown connection ID is safe and does
+ // nothing.
+ QuicConnectionId connection_id = 11235;
+ EXPECT_FALSE(store_.HasBufferedPackets(connection_id));
+ EXPECT_FALSE(store_.HasChlosBuffered());
+ store_.DiscardPackets(connection_id);
+ EXPECT_FALSE(store_.HasBufferedPackets(connection_id));
+ EXPECT_FALSE(store_.HasChlosBuffered());
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/quic_bug_tracker.h b/chromium/net/quic/core/quic_bug_tracker.h
index 280a537d0e7..280a537d0e7 100644
--- a/chromium/net/quic/quic_bug_tracker.h
+++ b/chromium/net/quic/core/quic_bug_tracker.h
diff --git a/chromium/net/quic/core/quic_client_promised_info.cc b/chromium/net/quic/core/quic_client_promised_info.cc
new file mode 100644
index 00000000000..8c6703884b3
--- /dev/null
+++ b/chromium/net/quic/core/quic_client_promised_info.cc
@@ -0,0 +1,123 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_client_promised_info.h"
+
+#include "base/logging.h"
+#include "net/quic/core/spdy_utils.h"
+
+using net::SpdyHeaderBlock;
+using net::kPushPromiseTimeoutSecs;
+using std::string;
+
+namespace net {
+
+QuicClientPromisedInfo::QuicClientPromisedInfo(QuicClientSessionBase* session,
+ QuicStreamId id,
+ string url)
+ : session_(session),
+ id_(id),
+ url_(std::move(url)),
+ client_request_delegate_(nullptr) {}
+
+QuicClientPromisedInfo::~QuicClientPromisedInfo() {}
+
+void QuicClientPromisedInfo::CleanupAlarm::OnAlarm() {
+ DVLOG(1) << "self GC alarm for stream " << promised_->id_;
+ promised_->Reset(QUIC_STREAM_CANCELLED);
+}
+
+void QuicClientPromisedInfo::Init() {
+ cleanup_alarm_.reset(session_->connection()->alarm_factory()->CreateAlarm(
+ new QuicClientPromisedInfo::CleanupAlarm(this)));
+ cleanup_alarm_->Set(
+ session_->connection()->helper()->GetClock()->ApproximateNow() +
+ QuicTime::Delta::FromSeconds(kPushPromiseTimeoutSecs));
+}
+
+void QuicClientPromisedInfo::OnPromiseHeaders(const SpdyHeaderBlock& headers) {
+ // RFC7540, Section 8.2, requests MUST be safe [RFC7231], Section
+ // 4.2.1. GET and HEAD are the methods that are safe and required.
+ SpdyHeaderBlock::const_iterator it = headers.find(":method");
+ DCHECK(it != headers.end());
+ if (!(it->second == "GET" || it->second == "HEAD")) {
+ DVLOG(1) << "Promise for stream " << id_ << " has invalid method "
+ << it->second;
+ Reset(QUIC_INVALID_PROMISE_METHOD);
+ return;
+ }
+ if (!SpdyUtils::UrlIsValid(headers)) {
+ DVLOG(1) << "Promise for stream " << id_ << " has invalid URL " << url_;
+ Reset(QUIC_INVALID_PROMISE_URL);
+ return;
+ }
+ if (!session_->IsAuthorized(SpdyUtils::GetHostNameFromHeaderBlock(headers))) {
+ Reset(QUIC_UNAUTHORIZED_PROMISE_URL);
+ return;
+ }
+ request_headers_.reset(new SpdyHeaderBlock(headers.Clone()));
+}
+
+void QuicClientPromisedInfo::OnResponseHeaders(const SpdyHeaderBlock& headers) {
+ response_headers_.reset(new SpdyHeaderBlock(headers.Clone()));
+ if (client_request_delegate_) {
+ // We already have a client request waiting.
+ FinalValidation();
+ }
+}
+
+void QuicClientPromisedInfo::Reset(QuicRstStreamErrorCode error_code) {
+ QuicClientPushPromiseIndex::Delegate* delegate = client_request_delegate_;
+ session_->ResetPromised(id_, error_code);
+ session_->DeletePromised(this);
+ if (delegate) {
+ delegate->OnRendezvousResult(nullptr);
+ }
+}
+
+QuicAsyncStatus QuicClientPromisedInfo::FinalValidation() {
+ if (!client_request_delegate_->CheckVary(
+ *client_request_headers_, *request_headers_, *response_headers_)) {
+ Reset(QUIC_PROMISE_VARY_MISMATCH);
+ return QUIC_FAILURE;
+ }
+ QuicSpdyStream* stream = session_->GetPromisedStream(id_);
+ if (!stream) {
+ // This shouldn't be possible, as |ClientRequest| guards against
+ // closed stream for the synchronous case. And in the
+ // asynchronous case, a RST can only be caught by |OnAlarm()|.
+ QUIC_BUG << "missing promised stream" << id_;
+ }
+ QuicClientPushPromiseIndex::Delegate* delegate = client_request_delegate_;
+ session_->DeletePromised(this);
+ // Stream can start draining now
+ if (delegate) {
+ delegate->OnRendezvousResult(stream);
+ }
+ return QUIC_SUCCESS;
+}
+
+QuicAsyncStatus QuicClientPromisedInfo::HandleClientRequest(
+ const SpdyHeaderBlock& request_headers,
+ QuicClientPushPromiseIndex::Delegate* delegate) {
+ if (session_->IsClosedStream(id_)) {
+ // There was a RST on the response stream.
+ session_->DeletePromised(this);
+ return QUIC_FAILURE;
+ }
+ client_request_delegate_ = delegate;
+ client_request_headers_.reset(new SpdyHeaderBlock(request_headers.Clone()));
+ if (!response_headers_) {
+ return QUIC_PENDING;
+ }
+ return FinalValidation();
+}
+
+void QuicClientPromisedInfo::Cancel() {
+ // Don't fire OnRendezvousResult() for client initiated cancel.
+ client_request_delegate_ = nullptr;
+ Reset(QUIC_STREAM_CANCELLED);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_client_promised_info.h b/chromium/net/quic/core/quic_client_promised_info.h
new file mode 100644
index 00000000000..449812c4292
--- /dev/null
+++ b/chromium/net/quic/core/quic_client_promised_info.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_CLIENT_PROMISED_INFO_H_
+#define NET_QUIC_QUIC_CLIENT_PROMISED_INFO_H_
+
+#include <sys/types.h>
+#include <string>
+
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_alarm.h"
+#include "net/quic/core/quic_client_push_promise_index.h"
+#include "net/quic/core/quic_client_session_base.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_spdy_stream.h"
+#include "net/spdy/spdy_framer.h"
+
+namespace net {
+
+class QuicClientSessionBase;
+class QuicDataToResend;
+class QuicConnectionHelperInterface;
+
+namespace test {
+class QuicClientPromisedInfoPeer;
+} // namespace test
+
+// QuicClientPromisedInfo tracks the client state of a server push
+// stream from the time a PUSH_PROMISE is received until rendezvous
+// between the promised response and the corresponding client request
+// is complete.
+class NET_EXPORT_PRIVATE QuicClientPromisedInfo
+ : public QuicClientPushPromiseIndex::TryHandle {
+ public:
+ // Interface to QuicSpdyClientStream
+ QuicClientPromisedInfo(QuicClientSessionBase* session,
+ QuicStreamId id,
+ std::string url);
+ virtual ~QuicClientPromisedInfo();
+
+ void Init();
+
+ // Validate promise headers etc.
+ void OnPromiseHeaders(const SpdyHeaderBlock& request_headers);
+
+ // Store response, possibly proceed with final validation.
+ void OnResponseHeaders(const SpdyHeaderBlock& response_headers);
+
+ // Rendezvous between this promised stream and a client request that
+ // has a matching URL.
+ virtual QuicAsyncStatus HandleClientRequest(
+ const SpdyHeaderBlock& headers,
+ QuicClientPushPromiseIndex::Delegate* delegate);
+
+ void Cancel() override;
+
+ void Reset(QuicRstStreamErrorCode error_code);
+
+ // Client requests are initially associated to promises by matching
+ // URL in the client request against the URL in the promise headers,
+ // uing the |promised_by_url| map. The push can be cross-origin, so
+ // the client should validate that the session is authoritative for
+ // the promised URL. If not, it should call |RejectUnauthorized|.
+ QuicClientSessionBase* session() { return session_; }
+
+ // If the promised response contains Vary header, then the fields
+ // specified by Vary must match between the client request header
+ // and the promise headers (see https://crbug.com//554220). Vary
+ // validation requires the response headers (for the actual Vary
+ // field list), the promise headers (taking the role of the "cached"
+ // request), and the client request headers.
+ SpdyHeaderBlock* request_headers() { return request_headers_.get(); }
+
+ SpdyHeaderBlock* response_headers() { return response_headers_.get(); }
+
+ QuicStreamId id() const { return id_; }
+
+ const std::string url() const { return url_; }
+
+ private:
+ friend class test::QuicClientPromisedInfoPeer;
+
+ class CleanupAlarm : public QuicAlarm::Delegate {
+ public:
+ explicit CleanupAlarm(QuicClientPromisedInfo* promised)
+ : promised_(promised) {}
+
+ void OnAlarm() override;
+
+ QuicClientPromisedInfo* promised_;
+ };
+
+ QuicAsyncStatus FinalValidation();
+
+ QuicClientSessionBase* session_;
+ QuicStreamId id_;
+ std::string url_;
+ std::unique_ptr<SpdyHeaderBlock> request_headers_;
+ std::unique_ptr<SpdyHeaderBlock> response_headers_;
+ std::unique_ptr<SpdyHeaderBlock> client_request_headers_;
+ QuicClientPushPromiseIndex::Delegate* client_request_delegate_;
+
+ // The promise will commit suicide eventually if it is not claimed
+ // by a GET first.
+ std::unique_ptr<QuicAlarm> cleanup_alarm_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicClientPromisedInfo);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CLIENT_PROMISED_INFO_H_
diff --git a/chromium/net/quic/core/quic_client_promised_info_test.cc b/chromium/net/quic/core/quic_client_promised_info_test.cc
new file mode 100644
index 00000000000..9e38372128e
--- /dev/null
+++ b/chromium/net/quic/core/quic_client_promised_info_test.cc
@@ -0,0 +1,377 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_client_promised_info.h"
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/scoped_ptr.h"
+#include "net/gfe2/balsa_headers.h"
+#include "net/quic/core/quic_client.h"
+#include "net/quic/core/quic_client_session.h"
+#include "net/quic/core/quic_spdy_client_stream.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/core/spdy_balsa_utils.h"
+#include "net/quic/core/spdy_utils.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/util/ipaddress.h"
+#include "testing/base/public/gunit.h"
+
+using SpdyHeaderBlock;
+using BalsaHeaders;
+using testing::StrictMock;
+
+namespace net {
+namespace test {
+
+class QuicClientPromisedInfoPeer {
+ public:
+ static QuicAlarm* GetAlarm(QuicClientPromisedInfo* promised_stream) {
+ return promised_stream->cleanup_alarm_.get();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicClientPromisedInfoPeer);
+};
+
+namespace {
+
+class MockQuicClientSession : public QuicClientSession {
+ public:
+ explicit MockQuicClientSession(QuicConnection* connection,
+ QuicClientPushPromiseIndex* push_promise_index)
+ : QuicClientSession(
+ DefaultQuicConfig(),
+ connection,
+ QuicServerId("example.com", 443, PRIVACY_MODE_DISABLED),
+ &crypto_config_,
+ push_promise_index),
+ crypto_config_(CryptoTestUtils::ProofVerifierForTesting()),
+ authorized_(true) {}
+ ~MockQuicClientSession() override {}
+
+ bool IsAuthorized(const string& authority) override { return authorized_; }
+
+ void set_authorized(bool authorized) { authorized_ = authorized; }
+
+ MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id));
+
+ private:
+ QuicCryptoClientConfig crypto_config_;
+
+ bool authorized_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockQuicClientSession);
+};
+
+class QuicClientPromisedInfoTest : public ::testing::Test {
+ public:
+ class StreamVisitor;
+
+ QuicClientPromisedInfoTest()
+ : connection_(new StrictMock<MockQuicConnection>(&helper_,
+ &alarm_factory_,
+ Perspective::IS_CLIENT)),
+ session_(connection_, &push_promise_index_),
+ body_("hello world"),
+ promise_id_(gfe_quic::test::kServerDataStreamId1) {
+ session_.Initialize();
+
+ headers_.SetResponseFirstline("HTTP/1.1", 200, "Ok");
+ headers_.ReplaceOrAppendHeader("content-length", "11");
+ headers_string_ = SpdyBalsaUtils::SerializeResponseHeaders(headers_);
+
+ stream_.reset(new QuicSpdyClientStream(gfe_quic::test::kClientDataStreamId1,
+ &session_));
+ stream_visitor_.reset(new StreamVisitor());
+ stream_->set_visitor(stream_visitor_.get());
+
+ push_promise_[":path"] = "/bar";
+ push_promise_[":authority"] = "www.google.com";
+ push_promise_[":version"] = "HTTP/1.1";
+ push_promise_[":method"] = "GET";
+ push_promise_[":scheme"] = "https";
+
+ promise_url_ = SpdyUtils::GetUrlFromHeaderBlock(push_promise_);
+ serialized_push_promise_ =
+ SpdyUtils::SerializeUncompressedHeaders(push_promise_);
+
+ client_request_ = push_promise_.Clone();
+ }
+
+ class StreamVisitor : public QuicSpdyClientStream::Visitor {
+ void OnClose(QuicSpdyStream* stream) override {
+ DVLOG(1) << "stream " << stream->id();
+ }
+ };
+
+ class PushPromiseDelegate : public QuicClientPushPromiseIndex::Delegate {
+ public:
+ explicit PushPromiseDelegate(bool match)
+ : match_(match),
+ rendezvous_fired_(false),
+ rendezvous_stream_(nullptr) {}
+
+ bool CheckVary(const SpdyHeaderBlock& client_request,
+ const SpdyHeaderBlock& promise_request,
+ const SpdyHeaderBlock& promise_response) override {
+ DVLOG(1) << "match " << match_;
+ return match_;
+ }
+
+ void OnRendezvousResult(QuicSpdyClientStream* stream) override {
+ rendezvous_fired_ = true;
+ rendezvous_stream_ = stream;
+ }
+
+ QuicSpdyClientStream* rendezvous_stream() { return rendezvous_stream_; }
+ bool rendezvous_fired() { return rendezvous_fired_; }
+
+ private:
+ bool match_;
+ bool rendezvous_fired_;
+ QuicSpdyClientStream* rendezvous_stream_;
+ };
+
+ void ReceivePromise(QuicStreamId id) {
+ stream_->OnStreamHeaders(serialized_push_promise_);
+
+ stream_->OnPromiseHeadersComplete(id, serialized_push_promise_.size());
+ }
+
+ MockQuicConnectionHelper helper_;
+ MockAlarmFactory alarm_factory_;
+ StrictMock<MockQuicConnection>* connection_;
+ QuicClientPushPromiseIndex push_promise_index_;
+
+ MockQuicClientSession session_;
+ std::unique_ptr<QuicSpdyClientStream> stream_;
+ std::unique_ptr<StreamVisitor> stream_visitor_;
+ std::unique_ptr<QuicSpdyClientStream> promised_stream_;
+ BalsaHeaders headers_;
+ string headers_string_;
+ string body_;
+ SpdyHeaderBlock push_promise_;
+ QuicStreamId promise_id_;
+ string promise_url_;
+ string serialized_push_promise_;
+ SpdyHeaderBlock client_request_;
+};
+
+TEST_F(QuicClientPromisedInfoTest, PushPromise) {
+ ReceivePromise(promise_id_);
+
+ // Verify that the promise is in the unclaimed streams map.
+ EXPECT_NE(session_.GetPromisedById(promise_id_), nullptr);
+}
+
+TEST_F(QuicClientPromisedInfoTest, PushPromiseCleanupAlarm) {
+ ReceivePromise(promise_id_);
+
+ // Verify that the promise is in the unclaimed streams map.
+ QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_);
+ ASSERT_NE(promised, nullptr);
+
+ // Fire the alarm that will cancel the promised stream.
+ EXPECT_CALL(*connection_,
+ SendRstStream(promise_id_, QUIC_STREAM_CANCELLED, 0));
+ alarm_factory_.FireAlarm(QuicClientPromisedInfoPeer::GetAlarm(promised));
+
+ // Verify that the promise is gone after the alarm fires.
+ EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
+ EXPECT_EQ(session_.GetPromisedByUrl(promise_url_), nullptr);
+}
+
+TEST_F(QuicClientPromisedInfoTest, PushPromiseInvalidMethod) {
+ // Promise with an unsafe method
+ push_promise_[":method"] = "PUT";
+ serialized_push_promise_ =
+ SpdyUtils::SerializeUncompressedHeaders(push_promise_);
+
+ EXPECT_CALL(*connection_,
+ SendRstStream(promise_id_, QUIC_INVALID_PROMISE_METHOD, 0));
+ ReceivePromise(promise_id_);
+
+ // Verify that the promise headers were ignored
+ EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
+ EXPECT_EQ(session_.GetPromisedByUrl(promise_url_), nullptr);
+}
+
+TEST_F(QuicClientPromisedInfoTest, PushPromiseInvalidUrl) {
+ // Remove required header field to make URL invalid
+ push_promise_.erase(":authority");
+ serialized_push_promise_ =
+ SpdyUtils::SerializeUncompressedHeaders(push_promise_);
+
+ EXPECT_CALL(*connection_,
+ SendRstStream(promise_id_, QUIC_INVALID_PROMISE_URL, 0));
+ ReceivePromise(promise_id_);
+
+ // Verify that the promise headers were ignored
+ EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
+ EXPECT_EQ(session_.GetPromisedByUrl(promise_url_), nullptr);
+}
+
+TEST_F(QuicClientPromisedInfoTest, PushPromiseInvalidUrl) {
+ // Promise with an unsafe method
+ push_promise_[":method"] = "PUT";
+ serialized_push_promise_ =
+ SpdyUtils::SerializeUncompressedHeaders(push_promise_);
+
+ EXPECT_CALL(*connection_,
+ SendRstStream(promise_id_, QUIC_INVALID_PROMISE_METHOD, 0));
+ ReceivePromise(promise_id_);
+
+ // Verify that the promise headers were ignored
+ EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
+ EXPECT_EQ(session_.GetPromisedByUrl(promise_url_), nullptr);
+}
+
+TEST_F(QuicClientPromisedInfoTest, PushPromiseUnauthorizedUrl) {
+ session_.set_authorized(false);
+
+ EXPECT_CALL(*connection_,
+ SendRstStream(promise_id_, QUIC_UNAUTHORIZED_PROMISE_URL, 0));
+
+ ReceivePromise(promise_id_);
+
+ QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_);
+ ASSERT_EQ(promised, nullptr);
+}
+
+TEST_F(QuicClientPromisedInfoTest, PushPromiseMismatch) {
+ ReceivePromise(promise_id_);
+
+ QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_);
+ ASSERT_NE(promised, nullptr);
+
+ // Need to send the promised response headers and initiate the
+ // rendezvous for secondary validation to proceed.
+ QuicSpdyClientStream* promise_stream = static_cast<QuicSpdyClientStream*>(
+ session_.GetOrCreateStream(promise_id_));
+ promise_stream->OnStreamHeaders(headers_string_);
+ promise_stream->OnStreamHeadersComplete(false, headers_string_.size());
+
+ PushPromiseDelegate delegate(/*match=*/false);
+ EXPECT_CALL(*connection_,
+ SendRstStream(promise_id_, QUIC_PROMISE_VARY_MISMATCH, 0));
+ EXPECT_CALL(session_, CloseStream(promise_id_));
+
+ promised->HandleClientRequest(client_request_, &delegate);
+}
+
+TEST_F(QuicClientPromisedInfoTest, PushPromiseVaryWaits) {
+ ReceivePromise(promise_id_);
+
+ QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_);
+ ASSERT_NE(promised, nullptr);
+
+ // Now initiate rendezvous.
+ PushPromiseDelegate delegate(/*match=*/true);
+ promised->HandleClientRequest(client_request_, &delegate);
+
+ // Promise is still there, waiting for response.
+ EXPECT_NE(session_.GetPromisedById(promise_id_), nullptr);
+
+ // Send Response, should trigger promise validation and complete rendezvous
+ QuicSpdyClientStream* promise_stream = static_cast<QuicSpdyClientStream*>(
+ session_.GetOrCreateStream(promise_id_));
+ ASSERT_NE(promise_stream, nullptr);
+ promise_stream->OnStreamHeaders(headers_string_);
+ promise_stream->OnStreamHeadersComplete(false, headers_string_.size());
+
+ // Promise is gone
+ EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
+}
+
+TEST_F(QuicClientPromisedInfoTest, PushPromiseVaryNoWait) {
+ ReceivePromise(promise_id_);
+
+ QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_);
+ ASSERT_NE(promised, nullptr);
+
+ QuicSpdyClientStream* promise_stream = static_cast<QuicSpdyClientStream*>(
+ session_.GetOrCreateStream(promise_id_));
+ ASSERT_NE(promise_stream, nullptr);
+
+ // Send Response, should trigger promise validation and complete rendezvous
+ promise_stream->OnStreamHeaders(headers_string_);
+ promise_stream->OnStreamHeadersComplete(false, headers_string_.size());
+
+ // Now initiate rendezvous.
+ PushPromiseDelegate delegate(/*match=*/true);
+ promised->HandleClientRequest(client_request_, &delegate);
+
+ // Promise is gone
+ EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
+ // Have a push stream
+ EXPECT_TRUE(delegate.rendezvous_fired());
+
+ EXPECT_NE(delegate.rendezvous_stream(), nullptr);
+}
+
+TEST_F(QuicClientPromisedInfoTest, PushPromiseWaitCancels) {
+ ReceivePromise(promise_id_);
+
+ QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_);
+ ASSERT_NE(promised, nullptr);
+
+ // Now initiate rendezvous.
+ PushPromiseDelegate delegate(/*match=*/true);
+ promised->HandleClientRequest(client_request_, &delegate);
+
+ // Promise is still there, waiting for response.
+ EXPECT_NE(session_.GetPromisedById(promise_id_), nullptr);
+
+ // Create response stream, but no data yet.
+ session_.GetOrCreateStream(promise_id_);
+
+ // Fire the alarm that will cancel the promised stream.
+ EXPECT_CALL(session_, CloseStream(promise_id_));
+ EXPECT_CALL(*connection_,
+ SendRstStream(promise_id_, QUIC_STREAM_CANCELLED, 0));
+ promised->Cancel();
+
+ // Promise is gone
+ EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
+}
+
+TEST_F(QuicClientPromisedInfoTest, PushPromiseDataClosed) {
+ ReceivePromise(promise_id_);
+
+ QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_);
+ ASSERT_NE(promised, nullptr);
+
+ QuicSpdyClientStream* promise_stream = static_cast<QuicSpdyClientStream*>(
+ session_.GetOrCreateStream(promise_id_));
+ ASSERT_NE(promise_stream, nullptr);
+
+ // Send response, rendezvous will be able to finish synchronously.
+ promise_stream->OnStreamHeaders(headers_string_);
+ promise_stream->OnStreamHeadersComplete(false, headers_string_.size());
+
+ EXPECT_CALL(session_, CloseStream(promise_id_));
+ EXPECT_CALL(*connection_,
+ SendRstStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0));
+ session_.SendRstStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0);
+
+ // Now initiate rendezvous.
+ PushPromiseDelegate delegate(/*match=*/true);
+ EXPECT_EQ(promised->HandleClientRequest(client_request_, &delegate),
+ QUIC_FAILURE);
+
+ // Got an indication of the stream failure, client should retry
+ // request.
+ EXPECT_FALSE(delegate.rendezvous_fired());
+ EXPECT_EQ(delegate.rendezvous_stream(), nullptr);
+
+ // Promise is gone
+ EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_client_push_promise_index.cc b/chromium/net/quic/core/quic_client_push_promise_index.cc
new file mode 100644
index 00000000000..a88c5e6075e
--- /dev/null
+++ b/chromium/net/quic/core/quic_client_push_promise_index.cc
@@ -0,0 +1,49 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_client_push_promise_index.h"
+
+#include <string>
+
+#include "net/quic/core/quic_client_promised_info.h"
+#include "net/quic/core/spdy_utils.h"
+
+using net::SpdyHeaderBlock;
+using std::string;
+
+namespace net {
+
+QuicClientPushPromiseIndex::QuicClientPushPromiseIndex() {}
+
+QuicClientPushPromiseIndex::~QuicClientPushPromiseIndex() {}
+
+QuicClientPushPromiseIndex::TryHandle::~TryHandle() {}
+
+QuicClientPromisedInfo* QuicClientPushPromiseIndex::GetPromised(
+ const string& url) {
+ QuicPromisedByUrlMap::iterator it = promised_by_url_.find(url);
+ if (it == promised_by_url_.end()) {
+ return nullptr;
+ }
+ return it->second;
+}
+
+QuicAsyncStatus QuicClientPushPromiseIndex::Try(
+ const SpdyHeaderBlock& request,
+ QuicClientPushPromiseIndex::Delegate* delegate,
+ TryHandle** handle) {
+ string url(SpdyUtils::GetUrlFromHeaderBlock(request));
+ QuicPromisedByUrlMap::iterator it = promised_by_url_.find(url);
+ if (it != promised_by_url_.end()) {
+ QuicClientPromisedInfo* promised = it->second;
+ QuicAsyncStatus rv = promised->HandleClientRequest(request, delegate);
+ if (rv == QUIC_PENDING) {
+ *handle = promised;
+ }
+ return rv;
+ }
+ return QUIC_FAILURE;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_client_push_promise_index.h b/chromium/net/quic/core/quic_client_push_promise_index.h
new file mode 100644
index 00000000000..2049aac843d
--- /dev/null
+++ b/chromium/net/quic/core/quic_client_push_promise_index.h
@@ -0,0 +1,99 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_CLIENT_PUSH_PROMISE_INDEX_H_
+#define NET_QUIC_QUIC_CLIENT_PUSH_PROMISE_INDEX_H_
+
+#include <string>
+
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_client_session_base.h"
+#include "net/quic/core/quic_types.h"
+
+namespace net {
+
+// QuicClientPushPromiseIndex is the interface to support rendezvous
+// between client requests and resources delivered via server push.
+// The same index can be shared across multiple sessions (e.g. for the
+// same browser users profile), since cross-origin pushes are allowed
+// (subject to authority constraints).
+
+class NET_EXPORT_PRIVATE QuicClientPushPromiseIndex {
+ public:
+ // Delegate is used to complete the rendezvous that began with
+ // |Try()|.
+ class NET_EXPORT_PRIVATE Delegate {
+ public:
+ virtual ~Delegate() {}
+
+ // The primary lookup matched request with push promise by URL. A
+ // secondary match is necessary to ensure Vary (RFC 2616, 14.14)
+ // is honored. If Vary is not present, return true. If Vary is
+ // present, return whether designated header fields of
+ // |promise_request| and |client_request| match.
+ virtual bool CheckVary(const SpdyHeaderBlock& client_request,
+ const SpdyHeaderBlock& promise_request,
+ const SpdyHeaderBlock& promise_response) = 0;
+
+ // On rendezvous success, provides the promised |stream|. Callee
+ // does not inherit ownership of |stream|. On rendezvous failure,
+ // |stream| is |nullptr| and the client should retry the request.
+ // Rendezvous can fail due to promise validation failure or RST on
+ // promised stream. |url| will have been removed from the index
+ // before |OnRendezvousResult()| is invoked, so a recursive call to
+ // |Try()| will return |QUIC_FAILURE|, which may be convenient for
+ // retry purposes.
+ virtual void OnRendezvousResult(QuicSpdyStream* stream) = 0;
+ };
+
+ class NET_EXPORT_PRIVATE TryHandle {
+ public:
+ // Cancel the request.
+ virtual void Cancel() = 0;
+
+ protected:
+ TryHandle() {}
+ ~TryHandle();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TryHandle);
+ };
+
+ QuicClientPushPromiseIndex();
+ virtual ~QuicClientPushPromiseIndex();
+
+ // Called by client code, used to enforce affinity between requests
+ // for promised streams and the session the promise came from.
+ QuicClientPromisedInfo* GetPromised(const std::string& url);
+
+ // Called by client code, to initiate rendezvous between a request
+ // and a server push stream. If |request|'s url is in the index,
+ // rendezvous will be attempted and may complete immediately or
+ // asynchronously. If the matching promise and response headers
+ // have already arrived, the delegate's methods will fire
+ // recursively from within |Try()|. Returns |QUIC_SUCCESS| if the
+ // rendezvous was a success. Returns |QUIC_FAILURE| if there was no
+ // matching promise, or if there was but the rendezvous has failed.
+ // Returns QUIC_PENDING if a matching promise was found, but the
+ // rendezvous needs to complete asynchronously because the promised
+ // response headers are not yet available. If result is
+ // QUIC_PENDING, then |*handle| will set so that the caller may
+ // cancel the request if need be. The caller does not inherit
+ // ownership of |*handle|, and it ceases to be valid if the caller
+ // invokes |handle->Cancel()| or if |delegate->OnReponse()| fires.
+ QuicAsyncStatus Try(const SpdyHeaderBlock& request,
+ Delegate* delegate,
+ TryHandle** handle);
+
+ QuicPromisedByUrlMap* promised_by_url() { return &promised_by_url_; }
+
+ private:
+ QuicPromisedByUrlMap promised_by_url_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicClientPushPromiseIndex);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CLIENT_PUSH_PROMISE_INDEX_H_
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
new file mode 100644
index 00000000000..73407c54e2b
--- /dev/null
+++ b/chromium/net/quic/core/quic_client_push_promise_index_test.cc
@@ -0,0 +1,108 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_client_push_promise_index.h"
+
+#include <string>
+
+#include "net/quic/core/spdy_utils.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/mock_quic_client_promised_info.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/tools/quic/quic_client_session.h"
+
+using testing::_;
+using testing::Return;
+using testing::StrictMock;
+using std::string;
+
+namespace net {
+namespace test {
+namespace {
+
+class MockQuicClientSession : public QuicClientSession {
+ public:
+ explicit MockQuicClientSession(QuicConnection* connection,
+ QuicClientPushPromiseIndex* push_promise_index)
+ : QuicClientSession(
+ DefaultQuicConfig(),
+ connection,
+ QuicServerId("example.com", 443, PRIVACY_MODE_DISABLED),
+ &crypto_config_,
+ push_promise_index),
+ crypto_config_(CryptoTestUtils::ProofVerifierForTesting()) {}
+ ~MockQuicClientSession() override {}
+
+ MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id));
+
+ private:
+ QuicCryptoClientConfig crypto_config_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockQuicClientSession);
+};
+
+class QuicClientPushPromiseIndexTest : public ::testing::Test {
+ public:
+ QuicClientPushPromiseIndexTest()
+ : connection_(new StrictMock<MockQuicConnection>(&helper_,
+ &alarm_factory_,
+ Perspective::IS_CLIENT)),
+ session_(connection_, &index_),
+ promised_(&session_, kServerDataStreamId1, url_) {
+ request_[":path"] = "/bar";
+ request_[":authority"] = "www.google.com";
+ request_[":version"] = "HTTP/1.1";
+ request_[":method"] = "GET";
+ request_[":scheme"] = "https";
+ url_ = SpdyUtils::GetUrlFromHeaderBlock(request_);
+ }
+
+ MockQuicConnectionHelper helper_;
+ MockAlarmFactory alarm_factory_;
+ StrictMock<MockQuicConnection>* connection_;
+ MockQuicClientSession session_;
+ QuicClientPushPromiseIndex index_;
+ SpdyHeaderBlock request_;
+ string url_;
+ MockQuicClientPromisedInfo promised_;
+ QuicClientPushPromiseIndex::TryHandle* handle_;
+};
+
+TEST_F(QuicClientPushPromiseIndexTest, TryRequestSuccess) {
+ (*index_.promised_by_url())[url_] = &promised_;
+ EXPECT_CALL(promised_, HandleClientRequest(_, _))
+ .WillOnce(Return(QUIC_SUCCESS));
+ EXPECT_EQ(index_.Try(request_, nullptr, &handle_), QUIC_SUCCESS);
+}
+
+TEST_F(QuicClientPushPromiseIndexTest, TryRequestPending) {
+ (*index_.promised_by_url())[url_] = &promised_;
+ EXPECT_CALL(promised_, HandleClientRequest(_, _))
+ .WillOnce(Return(QUIC_PENDING));
+ EXPECT_EQ(index_.Try(request_, nullptr, &handle_), QUIC_PENDING);
+}
+
+TEST_F(QuicClientPushPromiseIndexTest, TryRequestFailure) {
+ (*index_.promised_by_url())[url_] = &promised_;
+ EXPECT_CALL(promised_, HandleClientRequest(_, _))
+ .WillOnce(Return(QUIC_FAILURE));
+ EXPECT_EQ(index_.Try(request_, nullptr, &handle_), QUIC_FAILURE);
+}
+
+TEST_F(QuicClientPushPromiseIndexTest, TryNoPromise) {
+ EXPECT_EQ(index_.Try(request_, nullptr, &handle_), QUIC_FAILURE);
+}
+
+TEST_F(QuicClientPushPromiseIndexTest, GetNoPromise) {
+ EXPECT_EQ(index_.GetPromised(url_), nullptr);
+}
+
+TEST_F(QuicClientPushPromiseIndexTest, GetPromise) {
+ (*index_.promised_by_url())[url_] = &promised_;
+ EXPECT_EQ(index_.GetPromised(url_), &promised_);
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_client_session_base.cc b/chromium/net/quic/core/quic_client_session_base.cc
new file mode 100644
index 00000000000..31101071622
--- /dev/null
+++ b/chromium/net/quic/core/quic_client_session_base.cc
@@ -0,0 +1,208 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_client_session_base.h"
+
+#include "net/quic/core/quic_client_promised_info.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/spdy_utils.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+QuicClientSessionBase::QuicClientSessionBase(
+ QuicConnection* connection,
+ QuicClientPushPromiseIndex* push_promise_index,
+ const QuicConfig& config)
+ : QuicSpdySession(connection, config),
+ push_promise_index_(push_promise_index),
+ largest_promised_stream_id_(kInvalidStreamId) {}
+
+QuicClientSessionBase::~QuicClientSessionBase() {
+ // all promised streams for this session
+ for (auto& it : promised_by_id_) {
+ DVLOG(1) << "erase stream " << it.first << " url " << it.second->url();
+ push_promise_index_->promised_by_url()->erase(it.second->url());
+ }
+ delete connection();
+}
+
+void QuicClientSessionBase::OnConfigNegotiated() {
+ QuicSpdySession::OnConfigNegotiated();
+}
+
+void QuicClientSessionBase::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
+ QuicSession::OnCryptoHandshakeEvent(event);
+}
+
+void QuicClientSessionBase::OnPromiseHeaders(QuicStreamId stream_id,
+ StringPiece headers_data) {
+ QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
+ if (!stream) {
+ // It's quite possible to receive headers after a stream has been reset.
+ return;
+ }
+ stream->OnPromiseHeaders(headers_data);
+}
+
+void QuicClientSessionBase::OnInitialHeadersComplete(
+ QuicStreamId stream_id,
+ const SpdyHeaderBlock& response_headers) {
+ // Note that the strong ordering of the headers stream means that
+ // QuicSpdyClientStream::OnPromiseHeadersComplete must have already
+ // been called (on the associated stream) if this is a promised
+ // stream. However, this stream may not have existed at this time,
+ // hence the need to query the session.
+ QuicClientPromisedInfo* promised = GetPromisedById(stream_id);
+ if (!promised)
+ return;
+
+ promised->OnResponseHeaders(response_headers);
+}
+
+void QuicClientSessionBase::OnPromiseHeadersComplete(
+ QuicStreamId stream_id,
+ QuicStreamId promised_stream_id,
+ size_t frame_len) {
+ if (promised_stream_id != kInvalidStreamId &&
+ promised_stream_id <= largest_promised_stream_id_) {
+ connection()->CloseConnection(
+ QUIC_INVALID_STREAM_ID,
+ "Received push stream id lesser or equal to the"
+ " last accepted before",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+ largest_promised_stream_id_ = promised_stream_id;
+
+ QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
+ if (!stream) {
+ // It's quite possible to receive headers after a stream has been reset.
+ return;
+ }
+ stream->OnPromiseHeadersComplete(promised_stream_id, frame_len);
+}
+
+void QuicClientSessionBase::OnPromiseHeaderList(
+ QuicStreamId stream_id,
+ QuicStreamId promised_stream_id,
+ size_t frame_len,
+ const QuicHeaderList& header_list) {
+ if (promised_stream_id != kInvalidStreamId &&
+ promised_stream_id <= largest_promised_stream_id_) {
+ connection()->CloseConnection(
+ QUIC_INVALID_STREAM_ID,
+ "Received push stream id lesser or equal to the"
+ " last accepted before",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+ largest_promised_stream_id_ = promised_stream_id;
+
+ QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
+ if (!stream) {
+ // It's quite possible to receive headers after a stream has been reset.
+ return;
+ }
+ stream->OnPromiseHeaderList(promised_stream_id, frame_len, header_list);
+}
+
+void QuicClientSessionBase::HandlePromised(QuicStreamId /* associated_id */,
+ QuicStreamId id,
+ const SpdyHeaderBlock& headers) {
+ // Due to pathalogical packet re-ordering, it is possible that
+ // frames for the promised stream have already arrived, and the
+ // promised stream could be active or closed.
+ if (IsClosedStream(id)) {
+ // There was a RST on the data stream already, perhaps
+ // QUIC_REFUSED_STREAM?
+ DVLOG(1) << "Promise ignored for stream " << id
+ << " that is already closed";
+ return;
+ }
+
+ if (push_promise_index_->promised_by_url()->size() >= get_max_promises()) {
+ DVLOG(1) << "Too many promises, rejecting promise for stream " << id;
+ ResetPromised(id, QUIC_REFUSED_STREAM);
+ return;
+ }
+
+ const string url = SpdyUtils::GetUrlFromHeaderBlock(headers);
+ QuicClientPromisedInfo* old_promised = GetPromisedByUrl(url);
+ if (old_promised) {
+ DVLOG(1) << "Promise for stream " << id << " is duplicate URL " << url
+ << " of previous promise for stream " << old_promised->id();
+ ResetPromised(id, QUIC_DUPLICATE_PROMISE_URL);
+ return;
+ }
+
+ if (GetPromisedById(id)) {
+ // OnPromiseHeadersComplete() would have closed the connection if
+ // promised id is a duplicate.
+ QUIC_BUG << "Duplicate promise for id " << id;
+ return;
+ }
+
+ QuicClientPromisedInfo* promised = new QuicClientPromisedInfo(this, id, url);
+ std::unique_ptr<QuicClientPromisedInfo> promised_owner(promised);
+ promised->Init();
+ DVLOG(1) << "stream " << id << " emplace url " << url;
+ (*push_promise_index_->promised_by_url())[url] = promised;
+ promised_by_id_[id] = std::move(promised_owner);
+ promised->OnPromiseHeaders(headers);
+}
+
+QuicClientPromisedInfo* QuicClientSessionBase::GetPromisedByUrl(
+ const string& url) {
+ QuicPromisedByUrlMap::iterator it =
+ push_promise_index_->promised_by_url()->find(url);
+ if (it != push_promise_index_->promised_by_url()->end()) {
+ return it->second;
+ }
+ return nullptr;
+}
+
+QuicClientPromisedInfo* QuicClientSessionBase::GetPromisedById(
+ const QuicStreamId id) {
+ QuicPromisedByIdMap::iterator it = promised_by_id_.find(id);
+ if (it != promised_by_id_.end()) {
+ return it->second.get();
+ }
+ return nullptr;
+}
+
+QuicSpdyStream* QuicClientSessionBase::GetPromisedStream(
+ const QuicStreamId id) {
+ if (IsClosedStream(id)) {
+ return nullptr;
+ }
+ DynamicStreamMap::iterator it = dynamic_streams().find(id);
+ if (it != dynamic_streams().end()) {
+ return static_cast<QuicSpdyStream*>(it->second);
+ }
+ QUIC_BUG << "Open promised stream " << id << " is missing!";
+ return nullptr;
+}
+
+void QuicClientSessionBase::DeletePromised(QuicClientPromisedInfo* promised) {
+ push_promise_index_->promised_by_url()->erase(promised->url());
+ // Since promised_by_id_ contains the unique_ptr, this will destroy
+ // promised.
+ promised_by_id_.erase(promised->id());
+}
+
+void QuicClientSessionBase::ResetPromised(QuicStreamId id,
+ QuicRstStreamErrorCode error_code) {
+ SendRstStream(id, error_code, 0);
+ if (!IsOpenStream(id)) {
+ MaybeIncreaseLargestPeerStreamId(id);
+ if (!FLAGS_quic_bugfix_reset_promised) {
+ InsertLocallyClosedStreamsHighestOffset(id, 0);
+ }
+ }
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_client_session_base.h b/chromium/net/quic/core/quic_client_session_base.h
new file mode 100644
index 00000000000..0233b0c3529
--- /dev/null
+++ b/chromium/net/quic/core/quic_client_session_base.h
@@ -0,0 +1,140 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_CLIENT_SESSION_BASE_H_
+#define NET_QUIC_QUIC_CLIENT_SESSION_BASE_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_crypto_client_stream.h"
+#include "net/quic/core/quic_spdy_session.h"
+
+namespace net {
+
+class QuicClientPromisedInfo;
+class QuicClientPushPromiseIndex;
+class QuicSpdyClientStream;
+
+// For client/http layer code. Lookup promised streams based on
+// matching promised request url. The same map can be shared across
+// multiple sessions, since cross-origin pushes are allowed (subject
+// to authority constraints). Clients should use this map to enforce
+// session affinity for requests corresponding to cross-origin push
+// promised streams.
+using QuicPromisedByUrlMap =
+ std::unordered_map<std::string, QuicClientPromisedInfo*>;
+
+// The maximum time a promises stream can be reserved without being
+// claimed by a client request.
+const int64_t kPushPromiseTimeoutSecs = 60;
+
+// Base class for all client-specific QuicSession subclasses.
+class NET_EXPORT_PRIVATE QuicClientSessionBase
+ : public QuicSpdySession,
+ public QuicCryptoClientStream::ProofHandler {
+ public:
+ // Takes ownership of |connection|. Caller retains ownership of
+ // |promised_by_url|.
+ QuicClientSessionBase(QuicConnection* connection,
+ QuicClientPushPromiseIndex* push_promise_index,
+ const QuicConfig& config);
+
+ ~QuicClientSessionBase() override;
+
+ void OnConfigNegotiated() override;
+
+ // Override base class to set FEC policy before any data is sent by client.
+ void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override;
+
+ // Called by |headers_stream_| when push promise headers have been
+ // received for a stream.
+ void OnPromiseHeaders(QuicStreamId stream_id,
+ base::StringPiece headers_data) override;
+
+ // Called by |headers_stream_| when push promise headers have been
+ // completely received.
+ void OnPromiseHeadersComplete(QuicStreamId stream_id,
+ QuicStreamId promised_stream_id,
+ size_t frame_len) override;
+
+ // Called by |headers_stream_| when push promise headers have been
+ // completely received.
+ void OnPromiseHeaderList(QuicStreamId stream_id,
+ QuicStreamId promised_stream_id,
+ size_t frame_len,
+ const QuicHeaderList& header_list) override;
+
+ // Called by |QuicSpdyClientStream| on receipt of response headers,
+ // needed to detect promised server push streams, as part of
+ // client-request to push-stream rendezvous.
+ void OnInitialHeadersComplete(QuicStreamId stream_id,
+ const SpdyHeaderBlock& response_headers);
+
+ // Called by |QuicSpdyClientStream| on receipt of PUSH_PROMISE, does
+ // some session level validation and creates the
+ // |QuicClientPromisedInfo| inserting into maps by (promised) id and
+ // url.
+ virtual void HandlePromised(QuicStreamId associated_id,
+ QuicStreamId promised_id,
+ const SpdyHeaderBlock& headers);
+
+ // For cross-origin server push, this should verify the server is
+ // authoritative per [RFC2818], Section 3. Roughly, subjectAltName
+ // std::list in the certificate should contain a matching DNS name, or IP
+ // address. |hostname| is derived from the ":authority" header field of
+ // the PUSH_PROMISE frame, port if present there will be dropped.
+ virtual bool IsAuthorized(const std::string& hostname) = 0;
+
+ // Session retains ownership.
+ QuicClientPromisedInfo* GetPromisedByUrl(const std::string& url);
+ // Session retains ownership.
+ QuicClientPromisedInfo* GetPromisedById(const QuicStreamId id);
+
+ //
+ QuicSpdyStream* GetPromisedStream(const QuicStreamId id);
+
+ // Removes |promised| from the maps by url.
+ void ErasePromisedByUrl(QuicClientPromisedInfo* promised);
+
+ // Removes |promised| from the maps by url and id and destroys
+ // promised.
+ virtual void DeletePromised(QuicClientPromisedInfo* promised);
+
+ // Sends Rst for the stream, and makes sure that future calls to
+ // IsClosedStream(id) return true, which ensures that any subsequent
+ // frames related to this stream will be ignored (modulo flow
+ // control accounting).
+ void ResetPromised(QuicStreamId id, QuicRstStreamErrorCode error_code);
+
+ size_t get_max_promises() const {
+ return max_open_incoming_streams() * kMaxPromisedStreamsMultiplier;
+ }
+
+ QuicClientPushPromiseIndex* push_promise_index() {
+ return push_promise_index_;
+ }
+
+ private:
+ // For QuicSpdyClientStream to detect that a response corresponds to a
+ // promise.
+ using QuicPromisedByIdMap =
+ std::unordered_map<QuicStreamId, std::unique_ptr<QuicClientPromisedInfo>>;
+
+ // As per rfc7540, section 10.5: track promise streams in "reserved
+ // (remote)". The primary key is URL from he promise request
+ // headers. The promised stream id is a secondary key used to get
+ // promise info when the response headers of the promised stream
+ // arrive.
+ QuicClientPushPromiseIndex* push_promise_index_;
+ QuicPromisedByIdMap promised_by_id_;
+ QuicStreamId largest_promised_stream_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicClientSessionBase);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CLIENT_SESSION_BASE_H_
diff --git a/chromium/net/quic/core/quic_clock.cc b/chromium/net/quic/core/quic_clock.cc
new file mode 100644
index 00000000000..9eb4f71760e
--- /dev/null
+++ b/chromium/net/quic/core/quic_clock.cc
@@ -0,0 +1,48 @@
+// 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/quic_clock.h"
+
+#include "base/time/time.h"
+
+namespace net {
+
+QuicClock::QuicClock() {}
+
+QuicClock::~QuicClock() {}
+
+QuicTime QuicClock::ApproximateNow() const {
+ // At the moment, Chrome does not have a distinct notion of ApproximateNow().
+ // We should consider implementing this using MessageLoop::recent_time_.
+ return Now();
+}
+
+QuicTime QuicClock::Now() const {
+ return QuicTime(base::TimeTicks::Now());
+}
+
+QuicWallTime QuicClock::WallNow() const {
+ return QuicWallTime::FromUNIXMicroseconds(base::Time::Now().ToJavaTime() *
+ 1000);
+}
+
+QuicTime QuicClock::ConvertWallTimeToQuicTime(
+ const QuicWallTime& walltime) const {
+ // ..........................
+ // | | |
+ // unix epoch |walltime| WallNow()
+ // ..........................
+ // | | |
+ // clock epoch | Now()
+ // result
+ //
+ // result = Now() - (WallNow() - walltime)
+ return Now() - QuicTime::Delta::FromMicroseconds(
+ WallNow()
+ .Subtract(QuicTime::Delta::FromMicroseconds(
+ walltime.ToUNIXMicroseconds()))
+ .ToUNIXMicroseconds());
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_clock.h b/chromium/net/quic/core/quic_clock.h
new file mode 100644
index 00000000000..7c6878b063a
--- /dev/null
+++ b/chromium/net/quic/core/quic_clock.h
@@ -0,0 +1,44 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_CLOCK_H_
+#define NET_QUIC_QUIC_CLOCK_H_
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+typedef double WallTime;
+
+// Clock to efficiently retrieve an approximately accurate time from an
+// EpollServer.
+class NET_EXPORT_PRIVATE QuicClock {
+ public:
+ QuicClock();
+ virtual ~QuicClock();
+
+ // Returns the approximate current time as a QuicTime object.
+ virtual QuicTime ApproximateNow() const;
+
+ // Returns the current time as a QuicTime object.
+ // Note: this use significant resources please use only if needed.
+ virtual QuicTime Now() const;
+
+ // WallNow returns the current wall-time - a time that is consistent across
+ // different clocks.
+ virtual QuicWallTime WallNow() const;
+
+ // Converts |walltime| to a QuicTime relative to this clock's epoch.
+ virtual QuicTime ConvertWallTimeToQuicTime(
+ const QuicWallTime& walltime) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicClock);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CLOCK_H_
diff --git a/chromium/net/quic/core/quic_clock_test.cc b/chromium/net/quic/core/quic_clock_test.cc
new file mode 100644
index 00000000000..f9d1f634e32
--- /dev/null
+++ b/chromium/net/quic/core/quic_clock_test.cc
@@ -0,0 +1,38 @@
+// 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/quic_clock.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+TEST(QuicClockTest, Now) {
+ QuicClock clock;
+
+ QuicTime start(base::TimeTicks::Now());
+ QuicTime now = clock.ApproximateNow();
+ QuicTime end(base::TimeTicks::Now());
+
+ EXPECT_LE(start, now);
+ EXPECT_LE(now, end);
+}
+
+TEST(QuicClockTest, WallNow) {
+ QuicClock clock;
+
+ base::Time start = base::Time::Now();
+ QuicWallTime now = clock.WallNow();
+ base::Time end = base::Time::Now();
+
+ // If end > start, then we can check now is between start and end.
+ if (end > start) {
+ EXPECT_LE(static_cast<uint64_t>(start.ToTimeT()), now.ToUNIXSeconds());
+ EXPECT_LE(now.ToUNIXSeconds(), static_cast<uint64_t>(end.ToTimeT()));
+ }
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_config.cc b/chromium/net/quic/core/quic_config.cc
new file mode 100644
index 00000000000..3697a97d77c
--- /dev/null
+++ b/chromium/net/quic/core/quic_config.cc
@@ -0,0 +1,762 @@
+// Copyright (c) 2013 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/quic_config.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_socket_address_coder.h"
+#include "net/quic/core/quic_utils.h"
+
+using std::min;
+using std::string;
+
+namespace net {
+
+// Reads the value corresponding to |name_| from |msg| into |out|. If the
+// |name_| is absent in |msg| and |presence| is set to OPTIONAL |out| is set
+// to |default_value|.
+QuicErrorCode ReadUint32(const CryptoHandshakeMessage& msg,
+ QuicTag tag,
+ QuicConfigPresence presence,
+ uint32_t default_value,
+ uint32_t* out,
+ string* error_details) {
+ DCHECK(error_details != nullptr);
+ QuicErrorCode error = msg.GetUint32(tag, out);
+ switch (error) {
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+ if (presence == PRESENCE_REQUIRED) {
+ *error_details = "Missing " + QuicUtils::TagToString(tag);
+ break;
+ }
+ error = QUIC_NO_ERROR;
+ *out = default_value;
+ break;
+ case QUIC_NO_ERROR:
+ break;
+ default:
+ *error_details = "Bad " + QuicUtils::TagToString(tag);
+ break;
+ }
+ return error;
+}
+
+QuicConfigValue::QuicConfigValue(QuicTag tag, QuicConfigPresence presence)
+ : tag_(tag), presence_(presence) {}
+QuicConfigValue::~QuicConfigValue() {}
+
+QuicNegotiableValue::QuicNegotiableValue(QuicTag tag,
+ QuicConfigPresence presence)
+ : QuicConfigValue(tag, presence), negotiated_(false) {}
+QuicNegotiableValue::~QuicNegotiableValue() {}
+
+QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag,
+ QuicConfigPresence presence)
+ : QuicNegotiableValue(tag, presence),
+ max_value_(0),
+ default_value_(0),
+ negotiated_value_(0) {}
+QuicNegotiableUint32::~QuicNegotiableUint32() {}
+
+void QuicNegotiableUint32::set(uint32_t max, uint32_t default_value) {
+ DCHECK_LE(default_value, max);
+ max_value_ = max;
+ default_value_ = default_value;
+}
+
+uint32_t QuicNegotiableUint32::GetUint32() const {
+ if (negotiated()) {
+ return negotiated_value_;
+ }
+ return default_value_;
+}
+
+void QuicNegotiableUint32::ToHandshakeMessage(
+ CryptoHandshakeMessage* out) const {
+ if (negotiated()) {
+ out->SetValue(tag_, negotiated_value_);
+ } else {
+ out->SetValue(tag_, max_value_);
+ }
+}
+
+QuicErrorCode QuicNegotiableUint32::ProcessPeerHello(
+ const CryptoHandshakeMessage& peer_hello,
+ HelloType hello_type,
+ string* error_details) {
+ DCHECK(!negotiated());
+ DCHECK(error_details != nullptr);
+ uint32_t value;
+ QuicErrorCode error = ReadUint32(peer_hello, tag_, presence_, default_value_,
+ &value, error_details);
+ if (error != QUIC_NO_ERROR) {
+ return error;
+ }
+ if (hello_type == SERVER && value > max_value_) {
+ *error_details =
+ "Invalid value received for " + QuicUtils::TagToString(tag_);
+ return QUIC_INVALID_NEGOTIATED_VALUE;
+ }
+
+ set_negotiated(true);
+ negotiated_value_ = min(value, max_value_);
+ return QUIC_NO_ERROR;
+}
+
+QuicNegotiableTag::QuicNegotiableTag(QuicTag tag, QuicConfigPresence presence)
+ : QuicNegotiableValue(tag, presence),
+ negotiated_tag_(0),
+ default_value_(0) {}
+
+QuicNegotiableTag::~QuicNegotiableTag() {}
+
+void QuicNegotiableTag::set(const QuicTagVector& possible,
+ QuicTag default_value) {
+ DCHECK(ContainsQuicTag(possible, default_value));
+ possible_values_ = possible;
+ default_value_ = default_value;
+}
+
+void QuicNegotiableTag::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
+ if (negotiated()) {
+ // Because of the way we serialize and parse handshake messages we can
+ // serialize this as value and still parse it as a vector.
+ out->SetValue(tag_, negotiated_tag_);
+ } else {
+ out->SetVector(tag_, possible_values_);
+ }
+}
+
+QuicErrorCode QuicNegotiableTag::ReadVector(const CryptoHandshakeMessage& msg,
+ const QuicTag** out,
+ size_t* out_length,
+ string* error_details) const {
+ DCHECK(error_details != nullptr);
+ QuicErrorCode error = msg.GetTaglist(tag_, out, out_length);
+ switch (error) {
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+ if (presence_ == PRESENCE_REQUIRED) {
+ *error_details = "Missing " + QuicUtils::TagToString(tag_);
+ break;
+ }
+ error = QUIC_NO_ERROR;
+ *out_length = 1;
+ *out = &default_value_;
+
+ case QUIC_NO_ERROR:
+ break;
+ default:
+ *error_details = "Bad " + QuicUtils::TagToString(tag_);
+ break;
+ }
+ return error;
+}
+
+QuicErrorCode QuicNegotiableTag::ProcessPeerHello(
+ const CryptoHandshakeMessage& peer_hello,
+ HelloType hello_type,
+ string* error_details) {
+ DCHECK(!negotiated());
+ DCHECK(error_details != nullptr);
+ const QuicTag* received_tags;
+ size_t received_tags_length;
+ QuicErrorCode error = ReadVector(peer_hello, &received_tags,
+ &received_tags_length, error_details);
+ if (error != QUIC_NO_ERROR) {
+ return error;
+ }
+
+ if (hello_type == SERVER) {
+ if (received_tags_length != 1 ||
+ !ContainsQuicTag(possible_values_, *received_tags)) {
+ *error_details = "Invalid " + QuicUtils::TagToString(tag_);
+ return QUIC_INVALID_NEGOTIATED_VALUE;
+ }
+ negotiated_tag_ = *received_tags;
+ } else {
+ QuicTag negotiated_tag;
+ if (!QuicUtils::FindMutualTag(
+ possible_values_, received_tags, received_tags_length,
+ QuicUtils::LOCAL_PRIORITY, &negotiated_tag, nullptr)) {
+ *error_details = "Unsupported " + QuicUtils::TagToString(tag_);
+ return QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP;
+ }
+ negotiated_tag_ = negotiated_tag;
+ }
+
+ set_negotiated(true);
+ return QUIC_NO_ERROR;
+}
+
+QuicFixedUint32::QuicFixedUint32(QuicTag tag, QuicConfigPresence presence)
+ : QuicConfigValue(tag, presence),
+ has_send_value_(false),
+ has_receive_value_(false) {}
+QuicFixedUint32::~QuicFixedUint32() {}
+
+bool QuicFixedUint32::HasSendValue() const {
+ return has_send_value_;
+}
+
+uint32_t QuicFixedUint32::GetSendValue() const {
+ QUIC_BUG_IF(!has_send_value_) << "No send value to get for tag:"
+ << QuicUtils::TagToString(tag_);
+ return send_value_;
+}
+
+void QuicFixedUint32::SetSendValue(uint32_t value) {
+ has_send_value_ = true;
+ send_value_ = value;
+}
+
+bool QuicFixedUint32::HasReceivedValue() const {
+ return has_receive_value_;
+}
+
+uint32_t QuicFixedUint32::GetReceivedValue() const {
+ QUIC_BUG_IF(!has_receive_value_) << "No receive value to get for tag:"
+ << QuicUtils::TagToString(tag_);
+ return receive_value_;
+}
+
+void QuicFixedUint32::SetReceivedValue(uint32_t value) {
+ has_receive_value_ = true;
+ receive_value_ = value;
+}
+
+void QuicFixedUint32::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
+ if (has_send_value_) {
+ out->SetValue(tag_, send_value_);
+ }
+}
+
+QuicErrorCode QuicFixedUint32::ProcessPeerHello(
+ const CryptoHandshakeMessage& peer_hello,
+ HelloType hello_type,
+ string* error_details) {
+ DCHECK(error_details != nullptr);
+ QuicErrorCode error = peer_hello.GetUint32(tag_, &receive_value_);
+ switch (error) {
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+ if (presence_ == PRESENCE_OPTIONAL) {
+ return QUIC_NO_ERROR;
+ }
+ *error_details = "Missing " + QuicUtils::TagToString(tag_);
+ break;
+ case QUIC_NO_ERROR:
+ has_receive_value_ = true;
+ break;
+ default:
+ *error_details = "Bad " + QuicUtils::TagToString(tag_);
+ break;
+ }
+ return error;
+}
+
+QuicFixedTagVector::QuicFixedTagVector(QuicTag name,
+ QuicConfigPresence presence)
+ : QuicConfigValue(name, presence),
+ has_send_values_(false),
+ has_receive_values_(false) {}
+
+QuicFixedTagVector::QuicFixedTagVector(const QuicFixedTagVector& other) =
+ default;
+
+QuicFixedTagVector::~QuicFixedTagVector() {}
+
+bool QuicFixedTagVector::HasSendValues() const {
+ return has_send_values_;
+}
+
+QuicTagVector QuicFixedTagVector::GetSendValues() const {
+ QUIC_BUG_IF(!has_send_values_) << "No send values to get for tag:"
+ << QuicUtils::TagToString(tag_);
+ return send_values_;
+}
+
+void QuicFixedTagVector::SetSendValues(const QuicTagVector& values) {
+ has_send_values_ = true;
+ send_values_ = values;
+}
+
+bool QuicFixedTagVector::HasReceivedValues() const {
+ return has_receive_values_;
+}
+
+QuicTagVector QuicFixedTagVector::GetReceivedValues() const {
+ QUIC_BUG_IF(!has_receive_values_) << "No receive value to get for tag:"
+ << QuicUtils::TagToString(tag_);
+ return receive_values_;
+}
+
+void QuicFixedTagVector::SetReceivedValues(const QuicTagVector& values) {
+ has_receive_values_ = true;
+ receive_values_ = values;
+}
+
+void QuicFixedTagVector::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
+ if (has_send_values_) {
+ out->SetVector(tag_, send_values_);
+ }
+}
+
+QuicErrorCode QuicFixedTagVector::ProcessPeerHello(
+ const CryptoHandshakeMessage& peer_hello,
+ HelloType hello_type,
+ string* error_details) {
+ DCHECK(error_details != nullptr);
+ const QuicTag* received_tags;
+ size_t received_tags_length;
+ QuicErrorCode error =
+ peer_hello.GetTaglist(tag_, &received_tags, &received_tags_length);
+ switch (error) {
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+ if (presence_ == PRESENCE_OPTIONAL) {
+ return QUIC_NO_ERROR;
+ }
+ *error_details = "Missing " + QuicUtils::TagToString(tag_);
+ break;
+ case QUIC_NO_ERROR:
+ DVLOG(1) << "Received Connection Option tags from receiver.";
+ has_receive_values_ = true;
+ for (size_t i = 0; i < received_tags_length; ++i) {
+ receive_values_.push_back(received_tags[i]);
+ }
+ break;
+ default:
+ *error_details = "Bad " + QuicUtils::TagToString(tag_);
+ break;
+ }
+ return error;
+}
+
+QuicFixedIPEndPoint::QuicFixedIPEndPoint(QuicTag tag,
+ QuicConfigPresence presence)
+ : QuicConfigValue(tag, presence),
+ has_send_value_(false),
+ has_receive_value_(false) {}
+
+QuicFixedIPEndPoint::~QuicFixedIPEndPoint() {}
+
+bool QuicFixedIPEndPoint::HasSendValue() const {
+ return has_send_value_;
+}
+
+const IPEndPoint& QuicFixedIPEndPoint::GetSendValue() const {
+ QUIC_BUG_IF(!has_send_value_) << "No send value to get for tag:"
+ << QuicUtils::TagToString(tag_);
+ return send_value_;
+}
+
+void QuicFixedIPEndPoint::SetSendValue(const IPEndPoint& value) {
+ has_send_value_ = true;
+ send_value_ = value;
+}
+
+bool QuicFixedIPEndPoint::HasReceivedValue() const {
+ return has_receive_value_;
+}
+
+const IPEndPoint& QuicFixedIPEndPoint::GetReceivedValue() const {
+ QUIC_BUG_IF(!has_receive_value_) << "No receive value to get for tag:"
+ << QuicUtils::TagToString(tag_);
+ return receive_value_;
+}
+
+void QuicFixedIPEndPoint::SetReceivedValue(const IPEndPoint& value) {
+ has_receive_value_ = true;
+ receive_value_ = value;
+}
+
+void QuicFixedIPEndPoint::ToHandshakeMessage(
+ CryptoHandshakeMessage* out) const {
+ if (has_send_value_) {
+ QuicSocketAddressCoder address_coder(send_value_);
+ out->SetStringPiece(tag_, address_coder.Encode());
+ }
+}
+
+QuicErrorCode QuicFixedIPEndPoint::ProcessPeerHello(
+ const CryptoHandshakeMessage& peer_hello,
+ HelloType hello_type,
+ string* error_details) {
+ base::StringPiece address;
+ if (!peer_hello.GetStringPiece(tag_, &address)) {
+ if (presence_ == PRESENCE_REQUIRED) {
+ *error_details = "Missing " + QuicUtils::TagToString(tag_);
+ return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
+ }
+ } else {
+ QuicSocketAddressCoder address_coder;
+ if (address_coder.Decode(address.data(), address.length())) {
+ SetReceivedValue(IPEndPoint(address_coder.ip(), address_coder.port()));
+ }
+ }
+ return QUIC_NO_ERROR;
+}
+
+QuicConfig::QuicConfig()
+ : max_time_before_crypto_handshake_(QuicTime::Delta::Zero()),
+ max_idle_time_before_crypto_handshake_(QuicTime::Delta::Zero()),
+ max_undecryptable_packets_(0),
+ connection_options_(kCOPT, PRESENCE_OPTIONAL),
+ idle_connection_state_lifetime_seconds_(kICSL, PRESENCE_REQUIRED),
+ silent_close_(kSCLS, PRESENCE_OPTIONAL),
+ max_streams_per_connection_(kMSPC, PRESENCE_OPTIONAL),
+ max_incoming_dynamic_streams_(kMIDS, PRESENCE_OPTIONAL),
+ bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL),
+ initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL),
+ initial_stream_flow_control_window_bytes_(kSFCW, PRESENCE_OPTIONAL),
+ initial_session_flow_control_window_bytes_(kCFCW, PRESENCE_OPTIONAL),
+ socket_receive_buffer_(kSRBF, PRESENCE_OPTIONAL),
+ multipath_enabled_(kMPTH, PRESENCE_OPTIONAL),
+ connection_migration_disabled_(kNCMR, PRESENCE_OPTIONAL),
+ alternate_server_address_(kASAD, PRESENCE_OPTIONAL),
+ force_hol_blocking_(kFHOL, PRESENCE_OPTIONAL) {
+ SetDefaults();
+}
+
+QuicConfig::QuicConfig(const QuicConfig& other) = default;
+
+QuicConfig::~QuicConfig() {}
+
+bool QuicConfig::SetInitialReceivedConnectionOptions(
+ const QuicTagVector& tags) {
+ if (HasReceivedConnectionOptions()) {
+ // If we have already received connection options (via handshake or due to a
+ // previous call), don't re-initialize.
+ return false;
+ }
+ connection_options_.SetReceivedValues(tags);
+ return true;
+}
+
+void QuicConfig::SetConnectionOptionsToSend(
+ const QuicTagVector& connection_options) {
+ connection_options_.SetSendValues(connection_options);
+}
+
+bool QuicConfig::HasReceivedConnectionOptions() const {
+ return connection_options_.HasReceivedValues();
+}
+
+QuicTagVector QuicConfig::ReceivedConnectionOptions() const {
+ return connection_options_.GetReceivedValues();
+}
+
+bool QuicConfig::HasSendConnectionOptions() const {
+ return connection_options_.HasSendValues();
+}
+
+QuicTagVector QuicConfig::SendConnectionOptions() const {
+ return connection_options_.GetSendValues();
+}
+
+bool QuicConfig::HasClientSentConnectionOption(QuicTag tag,
+ Perspective perspective) const {
+ if (perspective == Perspective::IS_SERVER) {
+ if (HasReceivedConnectionOptions() &&
+ ContainsQuicTag(ReceivedConnectionOptions(), tag)) {
+ return true;
+ }
+ } else if (HasSendConnectionOptions() &&
+ ContainsQuicTag(SendConnectionOptions(), tag)) {
+ return true;
+ }
+ return false;
+}
+
+void QuicConfig::SetIdleConnectionStateLifetime(
+ QuicTime::Delta max_idle_connection_state_lifetime,
+ QuicTime::Delta default_idle_conection_state_lifetime) {
+ idle_connection_state_lifetime_seconds_.set(
+ static_cast<uint32_t>(max_idle_connection_state_lifetime.ToSeconds()),
+ static_cast<uint32_t>(default_idle_conection_state_lifetime.ToSeconds()));
+}
+
+QuicTime::Delta QuicConfig::IdleConnectionStateLifetime() const {
+ return QuicTime::Delta::FromSeconds(
+ idle_connection_state_lifetime_seconds_.GetUint32());
+}
+
+// TODO(ianswett) Use this for silent close on mobile, or delete.
+void QuicConfig::SetSilentClose(bool silent_close) {
+ silent_close_.set(silent_close ? 1 : 0, silent_close ? 1 : 0);
+}
+
+bool QuicConfig::SilentClose() const {
+ return silent_close_.GetUint32() > 0;
+}
+
+void QuicConfig::SetMaxStreamsPerConnection(size_t max_streams,
+ size_t default_streams) {
+ max_streams_per_connection_.set(max_streams, default_streams);
+}
+
+uint32_t QuicConfig::MaxStreamsPerConnection() const {
+ return max_streams_per_connection_.GetUint32();
+}
+
+void QuicConfig::SetMaxIncomingDynamicStreamsToSend(
+ uint32_t max_incoming_dynamic_streams) {
+ max_incoming_dynamic_streams_.SetSendValue(max_incoming_dynamic_streams);
+}
+
+uint32_t QuicConfig::GetMaxIncomingDynamicStreamsToSend() {
+ return max_incoming_dynamic_streams_.GetSendValue();
+}
+
+bool QuicConfig::HasReceivedMaxIncomingDynamicStreams() {
+ return max_incoming_dynamic_streams_.HasReceivedValue();
+}
+
+uint32_t QuicConfig::ReceivedMaxIncomingDynamicStreams() {
+ return max_incoming_dynamic_streams_.GetReceivedValue();
+}
+
+bool QuicConfig::HasSetBytesForConnectionIdToSend() const {
+ return bytes_for_connection_id_.HasSendValue();
+}
+
+void QuicConfig::SetBytesForConnectionIdToSend(uint32_t bytes) {
+ bytes_for_connection_id_.SetSendValue(bytes);
+}
+
+bool QuicConfig::HasReceivedBytesForConnectionId() const {
+ return bytes_for_connection_id_.HasReceivedValue();
+}
+
+uint32_t QuicConfig::ReceivedBytesForConnectionId() const {
+ return bytes_for_connection_id_.GetReceivedValue();
+}
+
+void QuicConfig::SetInitialRoundTripTimeUsToSend(uint32_t rtt) {
+ initial_round_trip_time_us_.SetSendValue(rtt);
+}
+
+bool QuicConfig::HasReceivedInitialRoundTripTimeUs() const {
+ return initial_round_trip_time_us_.HasReceivedValue();
+}
+
+uint32_t QuicConfig::ReceivedInitialRoundTripTimeUs() const {
+ return initial_round_trip_time_us_.GetReceivedValue();
+}
+
+bool QuicConfig::HasInitialRoundTripTimeUsToSend() const {
+ return initial_round_trip_time_us_.HasSendValue();
+}
+
+uint32_t QuicConfig::GetInitialRoundTripTimeUsToSend() const {
+ return initial_round_trip_time_us_.GetSendValue();
+}
+
+void QuicConfig::SetInitialStreamFlowControlWindowToSend(
+ uint32_t window_bytes) {
+ if (window_bytes < kMinimumFlowControlSendWindow) {
+ QUIC_BUG << "Initial stream flow control receive window (" << window_bytes
+ << ") cannot be set lower than default ("
+ << kMinimumFlowControlSendWindow << ").";
+ window_bytes = kMinimumFlowControlSendWindow;
+ }
+ initial_stream_flow_control_window_bytes_.SetSendValue(window_bytes);
+}
+
+uint32_t QuicConfig::GetInitialStreamFlowControlWindowToSend() const {
+ return initial_stream_flow_control_window_bytes_.GetSendValue();
+}
+
+bool QuicConfig::HasReceivedInitialStreamFlowControlWindowBytes() const {
+ return initial_stream_flow_control_window_bytes_.HasReceivedValue();
+}
+
+uint32_t QuicConfig::ReceivedInitialStreamFlowControlWindowBytes() const {
+ return initial_stream_flow_control_window_bytes_.GetReceivedValue();
+}
+
+void QuicConfig::SetInitialSessionFlowControlWindowToSend(
+ uint32_t window_bytes) {
+ if (window_bytes < kMinimumFlowControlSendWindow) {
+ QUIC_BUG << "Initial session flow control receive window (" << window_bytes
+ << ") cannot be set lower than default ("
+ << kMinimumFlowControlSendWindow << ").";
+ window_bytes = kMinimumFlowControlSendWindow;
+ }
+ initial_session_flow_control_window_bytes_.SetSendValue(window_bytes);
+}
+
+uint32_t QuicConfig::GetInitialSessionFlowControlWindowToSend() const {
+ return initial_session_flow_control_window_bytes_.GetSendValue();
+}
+
+bool QuicConfig::HasReceivedInitialSessionFlowControlWindowBytes() const {
+ return initial_session_flow_control_window_bytes_.HasReceivedValue();
+}
+
+uint32_t QuicConfig::ReceivedInitialSessionFlowControlWindowBytes() const {
+ return initial_session_flow_control_window_bytes_.GetReceivedValue();
+}
+
+void QuicConfig::SetSocketReceiveBufferToSend(uint32_t tcp_receive_window) {
+ socket_receive_buffer_.SetSendValue(tcp_receive_window);
+}
+
+bool QuicConfig::HasReceivedSocketReceiveBuffer() const {
+ return socket_receive_buffer_.HasReceivedValue();
+}
+
+uint32_t QuicConfig::ReceivedSocketReceiveBuffer() const {
+ return socket_receive_buffer_.GetReceivedValue();
+}
+
+void QuicConfig::SetMultipathEnabled(bool multipath_enabled) {
+ uint32_t value = multipath_enabled ? 1 : 0;
+ multipath_enabled_.set(value, value);
+}
+
+bool QuicConfig::MultipathEnabled() const {
+ return multipath_enabled_.GetUint32() > 0;
+}
+
+void QuicConfig::SetDisableConnectionMigration() {
+ connection_migration_disabled_.SetSendValue(1);
+}
+
+bool QuicConfig::DisableConnectionMigration() const {
+ return connection_migration_disabled_.HasReceivedValue();
+}
+
+void QuicConfig::SetAlternateServerAddressToSend(
+ const IPEndPoint& alternate_server_address) {
+ alternate_server_address_.SetSendValue(alternate_server_address);
+}
+
+bool QuicConfig::HasReceivedAlternateServerAddress() const {
+ return alternate_server_address_.HasReceivedValue();
+}
+
+const IPEndPoint& QuicConfig::ReceivedAlternateServerAddress() const {
+ return alternate_server_address_.GetReceivedValue();
+}
+
+void QuicConfig::SetForceHolBlocking() {
+ force_hol_blocking_.SetSendValue(1);
+}
+
+bool QuicConfig::ForceHolBlocking(Perspective perspective) const {
+ if (perspective == Perspective::IS_SERVER) {
+ return force_hol_blocking_.HasReceivedValue();
+ } else {
+ return force_hol_blocking_.HasSendValue();
+ }
+}
+
+bool QuicConfig::negotiated() const {
+ // TODO(ianswett): Add the negotiated parameters once and iterate over all
+ // of them in negotiated, ToHandshakeMessage, ProcessClientHello, and
+ // ProcessServerHello.
+ return idle_connection_state_lifetime_seconds_.negotiated() &&
+ max_streams_per_connection_.negotiated();
+}
+
+void QuicConfig::SetDefaults() {
+ idle_connection_state_lifetime_seconds_.set(kMaximumIdleTimeoutSecs,
+ kDefaultIdleTimeoutSecs);
+ silent_close_.set(1, 0);
+ SetMaxStreamsPerConnection(kDefaultMaxStreamsPerConnection,
+ kDefaultMaxStreamsPerConnection);
+ SetMaxIncomingDynamicStreamsToSend(kDefaultMaxStreamsPerConnection);
+ max_time_before_crypto_handshake_ =
+ QuicTime::Delta::FromSeconds(kMaxTimeForCryptoHandshakeSecs);
+ max_idle_time_before_crypto_handshake_ =
+ QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs);
+ max_undecryptable_packets_ = kDefaultMaxUndecryptablePackets;
+
+ SetInitialStreamFlowControlWindowToSend(kMinimumFlowControlSendWindow);
+ SetInitialSessionFlowControlWindowToSend(kMinimumFlowControlSendWindow);
+}
+
+void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
+ idle_connection_state_lifetime_seconds_.ToHandshakeMessage(out);
+ silent_close_.ToHandshakeMessage(out);
+ max_streams_per_connection_.ToHandshakeMessage(out);
+ max_incoming_dynamic_streams_.ToHandshakeMessage(out);
+ bytes_for_connection_id_.ToHandshakeMessage(out);
+ initial_round_trip_time_us_.ToHandshakeMessage(out);
+ initial_stream_flow_control_window_bytes_.ToHandshakeMessage(out);
+ initial_session_flow_control_window_bytes_.ToHandshakeMessage(out);
+ socket_receive_buffer_.ToHandshakeMessage(out);
+ connection_migration_disabled_.ToHandshakeMessage(out);
+ connection_options_.ToHandshakeMessage(out);
+ alternate_server_address_.ToHandshakeMessage(out);
+ force_hol_blocking_.ToHandshakeMessage(out);
+}
+
+QuicErrorCode QuicConfig::ProcessPeerHello(
+ const CryptoHandshakeMessage& peer_hello,
+ HelloType hello_type,
+ string* error_details) {
+ DCHECK(error_details != nullptr);
+
+ QuicErrorCode error = QUIC_NO_ERROR;
+ if (error == QUIC_NO_ERROR) {
+ error = idle_connection_state_lifetime_seconds_.ProcessPeerHello(
+ peer_hello, hello_type, error_details);
+ }
+ if (error == QUIC_NO_ERROR) {
+ error =
+ silent_close_.ProcessPeerHello(peer_hello, hello_type, error_details);
+ }
+ if (error == QUIC_NO_ERROR) {
+ error = max_streams_per_connection_.ProcessPeerHello(peer_hello, hello_type,
+ error_details);
+ }
+ if (error == QUIC_NO_ERROR) {
+ error = max_incoming_dynamic_streams_.ProcessPeerHello(
+ peer_hello, hello_type, error_details);
+ }
+ if (error == QUIC_NO_ERROR) {
+ error = bytes_for_connection_id_.ProcessPeerHello(peer_hello, hello_type,
+ error_details);
+ }
+ if (error == QUIC_NO_ERROR) {
+ error = initial_round_trip_time_us_.ProcessPeerHello(peer_hello, hello_type,
+ error_details);
+ }
+ if (error == QUIC_NO_ERROR) {
+ error = initial_stream_flow_control_window_bytes_.ProcessPeerHello(
+ peer_hello, hello_type, error_details);
+ }
+ if (error == QUIC_NO_ERROR) {
+ error = initial_session_flow_control_window_bytes_.ProcessPeerHello(
+ peer_hello, hello_type, error_details);
+ }
+ if (error == QUIC_NO_ERROR) {
+ error = socket_receive_buffer_.ProcessPeerHello(peer_hello, hello_type,
+ error_details);
+ }
+ if (error == QUIC_NO_ERROR) {
+ error = connection_migration_disabled_.ProcessPeerHello(
+ peer_hello, hello_type, error_details);
+ }
+ if (error == QUIC_NO_ERROR) {
+ error = connection_options_.ProcessPeerHello(peer_hello, hello_type,
+ error_details);
+ }
+ if (error == QUIC_NO_ERROR) {
+ error = alternate_server_address_.ProcessPeerHello(peer_hello, hello_type,
+ error_details);
+ }
+ if (error == QUIC_NO_ERROR) {
+ error = force_hol_blocking_.ProcessPeerHello(peer_hello, hello_type,
+ error_details);
+ }
+ return error;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_config.h b/chromium/net/quic/core/quic_config.h
new file mode 100644
index 00000000000..6d552426fd1
--- /dev/null
+++ b/chromium/net/quic/core/quic_config.h
@@ -0,0 +1,460 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_CONFIG_H_
+#define NET_QUIC_QUIC_CONFIG_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+namespace test {
+class QuicConfigPeer;
+} // namespace test
+
+class CryptoHandshakeMessage;
+
+// Describes whether or not a given QuicTag is required or optional in the
+// handshake message.
+enum QuicConfigPresence {
+ // This negotiable value can be absent from the handshake message. Default
+ // value is selected as the negotiated value in such a case.
+ PRESENCE_OPTIONAL,
+ // This negotiable value is required in the handshake message otherwise the
+ // Process*Hello function returns an error.
+ PRESENCE_REQUIRED,
+};
+
+// Whether the CryptoHandshakeMessage is from the client or server.
+enum HelloType {
+ CLIENT,
+ SERVER,
+};
+
+// An abstract base class that stores a value that can be sent in CHLO/SHLO
+// message. These values can be OPTIONAL or REQUIRED, depending on |presence_|.
+class NET_EXPORT_PRIVATE QuicConfigValue {
+ public:
+ QuicConfigValue(QuicTag tag, QuicConfigPresence presence);
+ virtual ~QuicConfigValue();
+
+ // Serialises tag name and value(s) to |out|.
+ virtual void ToHandshakeMessage(CryptoHandshakeMessage* out) const = 0;
+
+ // Selects a mutually acceptable value from those offered in |peer_hello|
+ // and those defined in the subclass.
+ virtual QuicErrorCode ProcessPeerHello(
+ const CryptoHandshakeMessage& peer_hello,
+ HelloType hello_type,
+ std::string* error_details) = 0;
+
+ protected:
+ const QuicTag tag_;
+ const QuicConfigPresence presence_;
+};
+
+class NET_EXPORT_PRIVATE QuicNegotiableValue : public QuicConfigValue {
+ public:
+ QuicNegotiableValue(QuicTag tag, QuicConfigPresence presence);
+ ~QuicNegotiableValue() override;
+
+ bool negotiated() const { return negotiated_; }
+
+ protected:
+ void set_negotiated(bool negotiated) { negotiated_ = negotiated; }
+
+ private:
+ bool negotiated_;
+};
+
+class NET_EXPORT_PRIVATE QuicNegotiableUint32 : public QuicNegotiableValue {
+ // TODO(fayang): some negotiated values use uint32 as bool (e.g., silent
+ // close). Consider adding a QuicNegotiableBool type.
+ public:
+ // Default and max values default to 0.
+ QuicNegotiableUint32(QuicTag name, QuicConfigPresence presence);
+ ~QuicNegotiableUint32() override;
+
+ // Sets the maximum possible value that can be achieved after negotiation and
+ // also the default values to be assumed if PRESENCE_OPTIONAL and the *HLO msg
+ // doesn't contain a value corresponding to |name_|. |max| is serialised via
+ // ToHandshakeMessage call if |negotiated_| is false.
+ void set(uint32_t max, uint32_t default_value);
+
+ // Returns the value negotiated if |negotiated_| is true, otherwise returns
+ // default_value_ (used to set default values before negotiation finishes).
+ uint32_t GetUint32() const;
+
+ // Serialises |name_| and value to |out|. If |negotiated_| is true then
+ // |negotiated_value_| is serialised, otherwise |max_value_| is serialised.
+ void ToHandshakeMessage(CryptoHandshakeMessage* out) const override;
+
+ // Sets |negotiated_value_| to the minimum of |max_value_| and the
+ // corresponding value from |peer_hello|. If the corresponding value is
+ // missing and PRESENCE_OPTIONAL then |negotiated_value_| is set to
+ // |default_value_|.
+ QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello,
+ HelloType hello_type,
+ std::string* error_details) override;
+
+ private:
+ uint32_t max_value_;
+ uint32_t default_value_;
+ uint32_t negotiated_value_;
+};
+
+class NET_EXPORT_PRIVATE QuicNegotiableTag : public QuicNegotiableValue {
+ public:
+ QuicNegotiableTag(QuicTag name, QuicConfigPresence presence);
+ ~QuicNegotiableTag() override;
+
+ // Sets the possible values that |negotiated_tag_| can take after negotiation
+ // and the default value that |negotiated_tag_| takes if OPTIONAL and *HLO
+ // msg doesn't contain tag |name_|.
+ void set(const QuicTagVector& possible_values, QuicTag default_value);
+
+ // Serialises |name_| and vector (either possible or negotiated) to |out|. If
+ // |negotiated_| is true then |negotiated_tag_| is serialised, otherwise
+ // |possible_values_| is serialised.
+ void ToHandshakeMessage(CryptoHandshakeMessage* out) const override;
+
+ // Selects the tag common to both tags in |client_hello| for |name_| and
+ // |possible_values_| with preference to tag in |possible_values_|. The
+ // selected tag is set as |negotiated_tag_|.
+ QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello,
+ HelloType hello_type,
+ std::string* error_details) override;
+
+ private:
+ // Reads the vector corresponding to |name_| from |msg| into |out|. If the
+ // |name_| is absent in |msg| and |presence_| is set to OPTIONAL |out| is set
+ // to |possible_values_|.
+ QuicErrorCode ReadVector(const CryptoHandshakeMessage& msg,
+ const QuicTag** out,
+ size_t* out_length,
+ std::string* error_details) const;
+
+ QuicTag negotiated_tag_;
+ QuicTagVector possible_values_;
+ QuicTag default_value_;
+};
+
+// Stores uint32_t from CHLO or SHLO messages that are not negotiated.
+class NET_EXPORT_PRIVATE QuicFixedUint32 : public QuicConfigValue {
+ public:
+ QuicFixedUint32(QuicTag name, QuicConfigPresence presence);
+ ~QuicFixedUint32() override;
+
+ bool HasSendValue() const;
+
+ uint32_t GetSendValue() const;
+
+ void SetSendValue(uint32_t value);
+
+ bool HasReceivedValue() const;
+
+ uint32_t GetReceivedValue() const;
+
+ void SetReceivedValue(uint32_t value);
+
+ // If has_send_value is true, serialises |tag_| and |send_value_| to |out|.
+ void ToHandshakeMessage(CryptoHandshakeMessage* out) const override;
+
+ // Sets |value_| to the corresponding value from |peer_hello_| if it exists.
+ QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello,
+ HelloType hello_type,
+ std::string* error_details) override;
+
+ private:
+ uint32_t send_value_;
+ bool has_send_value_;
+ uint32_t receive_value_;
+ bool has_receive_value_;
+};
+
+// Stores tag from CHLO or SHLO messages that are not negotiated.
+class NET_EXPORT_PRIVATE QuicFixedTagVector : public QuicConfigValue {
+ public:
+ QuicFixedTagVector(QuicTag name, QuicConfigPresence presence);
+ QuicFixedTagVector(const QuicFixedTagVector& other);
+ ~QuicFixedTagVector() override;
+
+ bool HasSendValues() const;
+
+ QuicTagVector GetSendValues() const;
+
+ void SetSendValues(const QuicTagVector& values);
+
+ bool HasReceivedValues() const;
+
+ QuicTagVector GetReceivedValues() const;
+
+ void SetReceivedValues(const QuicTagVector& values);
+
+ // If has_send_value is true, serialises |tag_vector_| and |send_value_| to
+ // |out|.
+ void ToHandshakeMessage(CryptoHandshakeMessage* out) const override;
+
+ // Sets |receive_values_| to the corresponding value from |client_hello_| if
+ // it exists.
+ QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello,
+ HelloType hello_type,
+ std::string* error_details) override;
+
+ private:
+ QuicTagVector send_values_;
+ bool has_send_values_;
+ QuicTagVector receive_values_;
+ bool has_receive_values_;
+};
+
+// Stores IPEndPoint from CHLO or SHLO messages that are not negotiated.
+class NET_EXPORT_PRIVATE QuicFixedIPEndPoint : public QuicConfigValue {
+ public:
+ QuicFixedIPEndPoint(QuicTag tag, QuicConfigPresence presence);
+ ~QuicFixedIPEndPoint() override;
+
+ bool HasSendValue() const;
+
+ const IPEndPoint& GetSendValue() const;
+
+ void SetSendValue(const IPEndPoint& value);
+
+ bool HasReceivedValue() const;
+
+ const IPEndPoint& GetReceivedValue() const;
+
+ void SetReceivedValue(const IPEndPoint& value);
+
+ void ToHandshakeMessage(CryptoHandshakeMessage* out) const override;
+
+ QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello,
+ HelloType hello_type,
+ std::string* error_details) override;
+
+ private:
+ IPEndPoint send_value_;
+ bool has_send_value_;
+ IPEndPoint receive_value_;
+ bool has_receive_value_;
+};
+
+// QuicConfig contains non-crypto configuration options that are negotiated in
+// the crypto handshake.
+class NET_EXPORT_PRIVATE QuicConfig {
+ public:
+ QuicConfig();
+ QuicConfig(const QuicConfig& other);
+ ~QuicConfig();
+
+ void SetConnectionOptionsToSend(const QuicTagVector& connection_options);
+
+ bool HasReceivedConnectionOptions() const;
+
+ // Sets initial received connection options. All received connection options
+ // will be initialized with these fields. Initial received options may only be
+ // set once per config, prior to the setting of any other options. If options
+ // have already been set (either by previous calls or via handshake), this
+ // function does nothing and returns false.
+ bool SetInitialReceivedConnectionOptions(const QuicTagVector& tags);
+
+ QuicTagVector ReceivedConnectionOptions() const;
+
+ bool HasSendConnectionOptions() const;
+
+ QuicTagVector SendConnectionOptions() const;
+
+ // Returns true if the client is sending or the server has received a
+ // connection option.
+ bool HasClientSentConnectionOption(QuicTag tag,
+ Perspective perspective) const;
+
+ void SetIdleConnectionStateLifetime(
+ QuicTime::Delta max_idle_connection_state_lifetime,
+ QuicTime::Delta default_idle_conection_state_lifetime);
+
+ QuicTime::Delta IdleConnectionStateLifetime() const;
+
+ void SetSilentClose(bool silent_close);
+
+ bool SilentClose() const;
+
+ void SetMaxStreamsPerConnection(size_t max_streams, size_t default_streams);
+
+ uint32_t MaxStreamsPerConnection() const;
+
+ void SetMaxIncomingDynamicStreamsToSend(
+ uint32_t max_incoming_dynamic_streams);
+
+ uint32_t GetMaxIncomingDynamicStreamsToSend();
+
+ bool HasReceivedMaxIncomingDynamicStreams();
+
+ uint32_t ReceivedMaxIncomingDynamicStreams();
+
+ void set_max_time_before_crypto_handshake(
+ QuicTime::Delta max_time_before_crypto_handshake) {
+ max_time_before_crypto_handshake_ = max_time_before_crypto_handshake;
+ }
+
+ QuicTime::Delta max_time_before_crypto_handshake() const {
+ return max_time_before_crypto_handshake_;
+ }
+
+ void set_max_idle_time_before_crypto_handshake(
+ QuicTime::Delta max_idle_time_before_crypto_handshake) {
+ max_idle_time_before_crypto_handshake_ =
+ max_idle_time_before_crypto_handshake;
+ }
+
+ QuicTime::Delta max_idle_time_before_crypto_handshake() const {
+ return max_idle_time_before_crypto_handshake_;
+ }
+
+ void set_max_undecryptable_packets(size_t max_undecryptable_packets) {
+ max_undecryptable_packets_ = max_undecryptable_packets;
+ }
+
+ size_t max_undecryptable_packets() const {
+ return max_undecryptable_packets_;
+ }
+
+ bool HasSetBytesForConnectionIdToSend() const;
+
+ // Sets the peer's connection id length, in bytes.
+ void SetBytesForConnectionIdToSend(uint32_t bytes);
+
+ bool HasReceivedBytesForConnectionId() const;
+
+ uint32_t ReceivedBytesForConnectionId() const;
+
+ // Sets an estimated initial round trip time in us.
+ void SetInitialRoundTripTimeUsToSend(uint32_t rtt_us);
+
+ bool HasReceivedInitialRoundTripTimeUs() const;
+
+ uint32_t ReceivedInitialRoundTripTimeUs() const;
+
+ bool HasInitialRoundTripTimeUsToSend() const;
+
+ uint32_t GetInitialRoundTripTimeUsToSend() const;
+
+ // Sets an initial stream flow control window size to transmit to the peer.
+ void SetInitialStreamFlowControlWindowToSend(uint32_t window_bytes);
+
+ uint32_t GetInitialStreamFlowControlWindowToSend() const;
+
+ bool HasReceivedInitialStreamFlowControlWindowBytes() const;
+
+ uint32_t ReceivedInitialStreamFlowControlWindowBytes() const;
+
+ // Sets an initial session flow control window size to transmit to the peer.
+ void SetInitialSessionFlowControlWindowToSend(uint32_t window_bytes);
+
+ uint32_t GetInitialSessionFlowControlWindowToSend() const;
+
+ bool HasReceivedInitialSessionFlowControlWindowBytes() const;
+
+ uint32_t ReceivedInitialSessionFlowControlWindowBytes() const;
+
+ // Sets socket receive buffer to transmit to the peer.
+ void SetSocketReceiveBufferToSend(uint32_t window_bytes);
+
+ bool HasReceivedSocketReceiveBuffer() const;
+
+ uint32_t ReceivedSocketReceiveBuffer() const;
+
+ void SetMultipathEnabled(bool multipath_enabled);
+
+ bool MultipathEnabled() const;
+
+ void SetDisableConnectionMigration();
+
+ bool DisableConnectionMigration() const;
+
+ void SetAlternateServerAddressToSend(
+ const IPEndPoint& alternate_server_address);
+
+ bool HasReceivedAlternateServerAddress() const;
+
+ const IPEndPoint& ReceivedAlternateServerAddress() const;
+
+ void SetForceHolBlocking();
+
+ bool ForceHolBlocking(Perspective perspective) const;
+
+ bool negotiated() const;
+
+ // ToHandshakeMessage serialises the settings in this object as a series of
+ // tags /value pairs and adds them to |out|.
+ void ToHandshakeMessage(CryptoHandshakeMessage* out) const;
+
+ // Calls ProcessPeerHello on each negotiable parameter. On failure returns
+ // the corresponding QuicErrorCode and sets detailed error in |error_details|.
+ QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello,
+ HelloType hello_type,
+ std::string* error_details);
+
+ private:
+ friend class test::QuicConfigPeer;
+
+ // SetDefaults sets the members to sensible, default values.
+ void SetDefaults();
+
+ // Configurations options that are not negotiated.
+ // Maximum time the session can be alive before crypto handshake is finished.
+ QuicTime::Delta max_time_before_crypto_handshake_;
+ // Maximum idle time before the crypto handshake has completed.
+ QuicTime::Delta max_idle_time_before_crypto_handshake_;
+ // Maximum number of undecryptable packets stored before CHLO/SHLO.
+ size_t max_undecryptable_packets_;
+
+ // Connection options.
+ QuicFixedTagVector connection_options_;
+ // Idle connection state lifetime
+ QuicNegotiableUint32 idle_connection_state_lifetime_seconds_;
+ // Whether to use silent close. Defaults to 0 (false) and is otherwise true.
+ QuicNegotiableUint32 silent_close_;
+ // Maximum number of streams that the connection can support.
+ // TODO(rjshade): Remove when removing QUIC_VERSION_34
+ QuicNegotiableUint32 max_streams_per_connection_;
+ // Maximum number of incoming dynamic streams that the connection can support.
+ QuicFixedUint32 max_incoming_dynamic_streams_;
+ // The number of bytes required for the connection ID.
+ QuicFixedUint32 bytes_for_connection_id_;
+ // Initial round trip time estimate in microseconds.
+ QuicFixedUint32 initial_round_trip_time_us_;
+
+ // Initial stream flow control receive window in bytes.
+ QuicFixedUint32 initial_stream_flow_control_window_bytes_;
+ // Initial session flow control receive window in bytes.
+ QuicFixedUint32 initial_session_flow_control_window_bytes_;
+
+ // Socket receive buffer in bytes.
+ // TODO(ianswett): Deprecate once QUIC_VERSION_34 is deprecated.
+ QuicFixedUint32 socket_receive_buffer_;
+
+ // Whether to support multipath for this connection.
+ QuicNegotiableUint32 multipath_enabled_;
+
+ // Whether tell peer not to attempt connection migration.
+ QuicFixedUint32 connection_migration_disabled_;
+
+ // An alternate server address the client could connect to.
+ QuicFixedIPEndPoint alternate_server_address_;
+
+ // Force HOL blocking for measurement purposes.
+ QuicFixedUint32 force_hol_blocking_;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CONFIG_H_
diff --git a/chromium/net/quic/core/quic_config_test.cc b/chromium/net/quic/core/quic_config_test.cc
new file mode 100644
index 00000000000..d89ade55be5
--- /dev/null
+++ b/chromium/net/quic/core/quic_config_test.cc
@@ -0,0 +1,255 @@
+// Copyright (c) 2013 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/quic_config.h"
+
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/quic_config_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/test/gtest_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+
+namespace net {
+namespace test {
+namespace {
+
+class QuicConfigTest : public ::testing::Test {
+ protected:
+ QuicConfig config_;
+};
+
+TEST_F(QuicConfigTest, ToHandshakeMessage) {
+ config_.SetInitialStreamFlowControlWindowToSend(
+ kInitialStreamFlowControlWindowForTest);
+ config_.SetInitialSessionFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+ config_.SetIdleConnectionStateLifetime(QuicTime::Delta::FromSeconds(5),
+ QuicTime::Delta::FromSeconds(2));
+ config_.SetMaxStreamsPerConnection(4, 2);
+ config_.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer);
+ CryptoHandshakeMessage msg;
+ config_.ToHandshakeMessage(&msg);
+
+ uint32_t value;
+ QuicErrorCode error = msg.GetUint32(kICSL, &value);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_EQ(5u, value);
+
+ error = msg.GetUint32(kMSPC, &value);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_EQ(4u, value);
+
+ error = msg.GetUint32(kSFCW, &value);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_EQ(kInitialStreamFlowControlWindowForTest, value);
+
+ error = msg.GetUint32(kCFCW, &value);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest, value);
+
+ error = msg.GetUint32(kSRBF, &value);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_EQ(kDefaultSocketReceiveBuffer, value);
+}
+
+TEST_F(QuicConfigTest, ProcessClientHello) {
+ QuicConfig client_config;
+ QuicTagVector cgst;
+ cgst.push_back(kQBIC);
+ client_config.SetIdleConnectionStateLifetime(
+ QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs),
+ QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs));
+ client_config.SetMaxStreamsPerConnection(2 * kDefaultMaxStreamsPerConnection,
+ kDefaultMaxStreamsPerConnection);
+ client_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli);
+ client_config.SetInitialStreamFlowControlWindowToSend(
+ 2 * kInitialStreamFlowControlWindowForTest);
+ client_config.SetInitialSessionFlowControlWindowToSend(
+ 2 * kInitialSessionFlowControlWindowForTest);
+ client_config.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer);
+ client_config.SetForceHolBlocking();
+ QuicTagVector copt;
+ copt.push_back(kTBBR);
+ client_config.SetConnectionOptionsToSend(copt);
+ CryptoHandshakeMessage msg;
+ client_config.ToHandshakeMessage(&msg);
+
+ string error_details;
+ QuicTagVector initial_received_options;
+ initial_received_options.push_back(kIW50);
+ EXPECT_TRUE(
+ config_.SetInitialReceivedConnectionOptions(initial_received_options));
+ EXPECT_FALSE(
+ config_.SetInitialReceivedConnectionOptions(initial_received_options))
+ << "You can only set initial options once.";
+ const QuicErrorCode error =
+ config_.ProcessPeerHello(msg, CLIENT, &error_details);
+ EXPECT_FALSE(
+ config_.SetInitialReceivedConnectionOptions(initial_received_options))
+ << "You cannot set initial options after the hello.";
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_TRUE(config_.negotiated());
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs),
+ config_.IdleConnectionStateLifetime());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection, config_.MaxStreamsPerConnection());
+ EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs());
+ EXPECT_TRUE(config_.ForceHolBlocking(Perspective::IS_SERVER));
+ EXPECT_TRUE(config_.HasReceivedConnectionOptions());
+ EXPECT_EQ(2u, config_.ReceivedConnectionOptions().size());
+ EXPECT_EQ(config_.ReceivedConnectionOptions()[0], kIW50);
+ EXPECT_EQ(config_.ReceivedConnectionOptions()[1], kTBBR);
+ EXPECT_EQ(config_.ReceivedInitialStreamFlowControlWindowBytes(),
+ 2 * kInitialStreamFlowControlWindowForTest);
+ EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(),
+ 2 * kInitialSessionFlowControlWindowForTest);
+ EXPECT_EQ(config_.ReceivedSocketReceiveBuffer(), kDefaultSocketReceiveBuffer);
+}
+
+TEST_F(QuicConfigTest, ProcessServerHello) {
+ const IPEndPoint kTestServerAddress(IPAddress(127, 0, 3, 1), 1234);
+ QuicConfig server_config;
+ QuicTagVector cgst;
+ cgst.push_back(kQBIC);
+ server_config.SetIdleConnectionStateLifetime(
+ QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2),
+ QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2));
+ server_config.SetMaxStreamsPerConnection(kDefaultMaxStreamsPerConnection / 2,
+ kDefaultMaxStreamsPerConnection / 2);
+ server_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli);
+ server_config.SetInitialStreamFlowControlWindowToSend(
+ 2 * kInitialStreamFlowControlWindowForTest);
+ server_config.SetInitialSessionFlowControlWindowToSend(
+ 2 * kInitialSessionFlowControlWindowForTest);
+ server_config.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer);
+ server_config.SetAlternateServerAddressToSend(kTestServerAddress);
+ CryptoHandshakeMessage msg;
+ server_config.ToHandshakeMessage(&msg);
+ string error_details;
+ const QuicErrorCode error =
+ config_.ProcessPeerHello(msg, SERVER, &error_details);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_TRUE(config_.negotiated());
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2),
+ config_.IdleConnectionStateLifetime());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection / 2,
+ config_.MaxStreamsPerConnection());
+ EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs());
+ EXPECT_EQ(config_.ReceivedInitialStreamFlowControlWindowBytes(),
+ 2 * kInitialStreamFlowControlWindowForTest);
+ EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(),
+ 2 * kInitialSessionFlowControlWindowForTest);
+ EXPECT_EQ(config_.ReceivedSocketReceiveBuffer(), kDefaultSocketReceiveBuffer);
+ EXPECT_TRUE(config_.HasReceivedAlternateServerAddress());
+ EXPECT_EQ(kTestServerAddress, config_.ReceivedAlternateServerAddress());
+}
+
+TEST_F(QuicConfigTest, MissingOptionalValuesInCHLO) {
+ CryptoHandshakeMessage msg;
+ msg.SetValue(kICSL, 1);
+
+ // Set all REQUIRED tags.
+ msg.SetValue(kICSL, 1);
+ msg.SetValue(kMSPC, 1);
+
+ // No error, as rest are optional.
+ string error_details;
+ const QuicErrorCode error =
+ config_.ProcessPeerHello(msg, CLIENT, &error_details);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_TRUE(config_.negotiated());
+}
+
+TEST_F(QuicConfigTest, MissingOptionalValuesInSHLO) {
+ CryptoHandshakeMessage msg;
+
+ // Set all REQUIRED tags.
+ msg.SetValue(kICSL, 1);
+ msg.SetValue(kMSPC, 1);
+
+ // No error, as rest are optional.
+ string error_details;
+ const QuicErrorCode error =
+ config_.ProcessPeerHello(msg, SERVER, &error_details);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_TRUE(config_.negotiated());
+}
+
+TEST_F(QuicConfigTest, MissingValueInCHLO) {
+ // Server receives CHLO with missing kICSL.
+ CryptoHandshakeMessage msg;
+ string error_details;
+ const QuicErrorCode error =
+ config_.ProcessPeerHello(msg, CLIENT, &error_details);
+ EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, error);
+}
+
+TEST_F(QuicConfigTest, MissingValueInSHLO) {
+ // Client receives SHLO with missing kICSL.
+ CryptoHandshakeMessage msg;
+ string error_details;
+ const QuicErrorCode error =
+ config_.ProcessPeerHello(msg, SERVER, &error_details);
+ EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, error);
+}
+
+TEST_F(QuicConfigTest, OutOfBoundSHLO) {
+ QuicConfig server_config;
+ server_config.SetIdleConnectionStateLifetime(
+ QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs),
+ QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs));
+
+ CryptoHandshakeMessage msg;
+ server_config.ToHandshakeMessage(&msg);
+ string error_details;
+ const QuicErrorCode error =
+ config_.ProcessPeerHello(msg, SERVER, &error_details);
+ EXPECT_EQ(QUIC_INVALID_NEGOTIATED_VALUE, error);
+}
+
+TEST_F(QuicConfigTest, InvalidFlowControlWindow) {
+ // QuicConfig should not accept an invalid flow control window to send to the
+ // peer: the receive window must be at least the default of 16 Kb.
+ QuicConfig config;
+ const uint64_t kInvalidWindow = kMinimumFlowControlSendWindow - 1;
+ EXPECT_QUIC_BUG(
+ config.SetInitialStreamFlowControlWindowToSend(kInvalidWindow),
+ "Initial stream flow control receive window");
+
+ EXPECT_EQ(kMinimumFlowControlSendWindow,
+ config.GetInitialStreamFlowControlWindowToSend());
+}
+
+TEST_F(QuicConfigTest, HasClientSentConnectionOption) {
+ QuicConfig client_config;
+ QuicTagVector copt;
+ copt.push_back(kTBBR);
+ client_config.SetConnectionOptionsToSend(copt);
+ EXPECT_TRUE(client_config.HasClientSentConnectionOption(
+ kTBBR, Perspective::IS_CLIENT));
+
+ CryptoHandshakeMessage msg;
+ client_config.ToHandshakeMessage(&msg);
+
+ string error_details;
+ const QuicErrorCode error =
+ config_.ProcessPeerHello(msg, CLIENT, &error_details);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_TRUE(config_.negotiated());
+
+ EXPECT_TRUE(config_.HasReceivedConnectionOptions());
+ EXPECT_EQ(1u, config_.ReceivedConnectionOptions().size());
+ EXPECT_TRUE(
+ config_.HasClientSentConnectionOption(kTBBR, Perspective::IS_SERVER));
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_connection.cc b/chromium/net/quic/core/quic_connection.cc
new file mode 100644
index 00000000000..dadba8c67c7
--- /dev/null
+++ b/chromium/net/quic/core/quic_connection.cc
@@ -0,0 +1,2599 @@
+// 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/quic_connection.h"
+
+#include <string.h>
+#include <sys/types.h>
+
+#include <algorithm>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <set>
+#include <utility>
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "net/base/address_family.h"
+#include "net/base/ip_address.h"
+#include "net/base/net_errors.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/proto/cached_network_parameters.pb.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_packet_generator.h"
+#include "net/quic/core/quic_sent_packet_manager.h"
+#include "net/quic/core/quic_utils.h"
+
+using base::StringPiece;
+using base::StringPrintf;
+using std::list;
+using std::make_pair;
+using std::max;
+using std::min;
+using std::numeric_limits;
+using std::set;
+using std::string;
+using std::vector;
+
+namespace net {
+
+class QuicDecrypter;
+class QuicEncrypter;
+
+namespace {
+
+// The largest gap in packets we'll accept without closing the connection.
+// This will likely have to be tuned.
+const QuicPacketNumber kMaxPacketGap = 5000;
+
+// Maximum number of acks received before sending an ack in response.
+const QuicPacketCount kMaxPacketsReceivedBeforeAckSend = 20;
+
+// Maximum number of retransmittable packets received before sending an ack.
+const QuicPacketCount kDefaultRetransmittablePacketsBeforeAck = 2;
+// Minimum number of packets received before ack decimation is enabled.
+// This intends to avoid the beginning of slow start, when CWNDs may be
+// rapidly increasing.
+const QuicPacketCount kMinReceivedBeforeAckDecimation = 100;
+// Wait for up to 10 retransmittable packets before sending an ack.
+const QuicPacketCount kMaxRetransmittablePacketsBeforeAck = 10;
+// One quarter RTT delay when doing ack decimation.
+const float kAckDecimationDelay = 0.25;
+// One eighth RTT delay when doing ack decimation.
+const float kShortAckDecimationDelay = 0.125;
+
+// Error code used in WriteResult to indicate that the packet writer rejected
+// the message as being too big.
+const int kMessageTooBigErrorCode = ERR_MSG_TOO_BIG;
+
+bool Near(QuicPacketNumber a, QuicPacketNumber b) {
+ QuicPacketNumber delta = (a > b) ? a - b : b - a;
+ return delta <= kMaxPacketGap;
+}
+
+bool IsInitializedIPEndPoint(const IPEndPoint& address) {
+ return net::GetAddressFamily(address.address()) !=
+ net::ADDRESS_FAMILY_UNSPECIFIED;
+}
+
+// An alarm that is scheduled to send an ack if a timeout occurs.
+class AckAlarmDelegate : public QuicAlarm::Delegate {
+ public:
+ explicit AckAlarmDelegate(QuicConnection* connection)
+ : connection_(connection) {}
+
+ void OnAlarm() override {
+ DCHECK(connection_->ack_frame_updated());
+ QuicConnection::ScopedPacketBundler bundler(connection_,
+ QuicConnection::SEND_ACK);
+ }
+
+ private:
+ QuicConnection* connection_;
+
+ DISALLOW_COPY_AND_ASSIGN(AckAlarmDelegate);
+};
+
+// This alarm will be scheduled any time a data-bearing packet is sent out.
+// When the alarm goes off, the connection checks to see if the oldest packets
+// have been acked, and retransmit them if they have not.
+class RetransmissionAlarmDelegate : public QuicAlarm::Delegate {
+ public:
+ explicit RetransmissionAlarmDelegate(QuicConnection* connection)
+ : connection_(connection) {}
+
+ void OnAlarm() override { connection_->OnRetransmissionTimeout(); }
+
+ private:
+ QuicConnection* connection_;
+
+ DISALLOW_COPY_AND_ASSIGN(RetransmissionAlarmDelegate);
+};
+
+// An alarm that is scheduled when the SentPacketManager requires a delay
+// before sending packets and fires when the packet may be sent.
+class SendAlarmDelegate : public QuicAlarm::Delegate {
+ public:
+ explicit SendAlarmDelegate(QuicConnection* connection)
+ : connection_(connection) {}
+
+ void OnAlarm() override { connection_->WriteAndBundleAcksIfNotBlocked(); }
+
+ private:
+ QuicConnection* connection_;
+
+ DISALLOW_COPY_AND_ASSIGN(SendAlarmDelegate);
+};
+
+class TimeoutAlarmDelegate : public QuicAlarm::Delegate {
+ public:
+ explicit TimeoutAlarmDelegate(QuicConnection* connection)
+ : connection_(connection) {}
+
+ void OnAlarm() override { connection_->CheckForTimeout(); }
+
+ private:
+ QuicConnection* connection_;
+
+ DISALLOW_COPY_AND_ASSIGN(TimeoutAlarmDelegate);
+};
+
+class PingAlarmDelegate : public QuicAlarm::Delegate {
+ public:
+ explicit PingAlarmDelegate(QuicConnection* connection)
+ : connection_(connection) {}
+
+ void OnAlarm() override { connection_->OnPingTimeout(); }
+
+ private:
+ QuicConnection* connection_;
+
+ DISALLOW_COPY_AND_ASSIGN(PingAlarmDelegate);
+};
+
+class MtuDiscoveryAlarmDelegate : public QuicAlarm::Delegate {
+ public:
+ explicit MtuDiscoveryAlarmDelegate(QuicConnection* connection)
+ : connection_(connection) {}
+
+ void OnAlarm() override { connection_->DiscoverMtu(); }
+
+ private:
+ QuicConnection* connection_;
+
+ DISALLOW_COPY_AND_ASSIGN(MtuDiscoveryAlarmDelegate);
+};
+
+} // namespace
+
+#define ENDPOINT \
+ (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ")
+
+QuicConnection::QuicConnection(QuicConnectionId connection_id,
+ IPEndPoint address,
+ QuicConnectionHelperInterface* helper,
+ QuicAlarmFactory* alarm_factory,
+ QuicPacketWriter* writer,
+ bool owns_writer,
+ Perspective perspective,
+ const QuicVersionVector& supported_versions)
+ : framer_(supported_versions,
+ helper->GetClock()->ApproximateNow(),
+ perspective),
+ helper_(helper),
+ alarm_factory_(alarm_factory),
+ per_packet_options_(nullptr),
+ writer_(writer),
+ owns_writer_(owns_writer),
+ encryption_level_(ENCRYPTION_NONE),
+ clock_(helper->GetClock()),
+ random_generator_(helper->GetRandomGenerator()),
+ connection_id_(connection_id),
+ peer_address_(address),
+ active_peer_migration_type_(NO_CHANGE),
+ highest_packet_sent_before_peer_migration_(0),
+ last_packet_decrypted_(false),
+ last_size_(0),
+ current_packet_data_(nullptr),
+ last_decrypted_packet_level_(ENCRYPTION_NONE),
+ should_last_packet_instigate_acks_(false),
+ was_last_packet_missing_(false),
+ largest_seen_packet_with_ack_(0),
+ largest_seen_packet_with_stop_waiting_(0),
+ max_undecryptable_packets_(0),
+ pending_version_negotiation_packet_(false),
+ save_crypto_packets_as_termination_packets_(false),
+ idle_timeout_connection_close_behavior_(
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET),
+ close_connection_after_five_rtos_(false),
+ received_packet_manager_(&stats_),
+ ack_queued_(false),
+ num_retransmittable_packets_received_since_last_ack_sent_(0),
+ last_ack_had_missing_packets_(false),
+ num_packets_received_since_last_ack_sent_(0),
+ stop_waiting_count_(0),
+ ack_mode_(TCP_ACKING),
+ ack_decimation_delay_(kAckDecimationDelay),
+ delay_setting_retransmission_alarm_(false),
+ pending_retransmission_alarm_(false),
+ defer_send_in_response_to_packets_(false),
+ ping_timeout_(QuicTime::Delta::FromSeconds(kPingTimeoutSecs)),
+ arena_(),
+ ack_alarm_(alarm_factory_->CreateAlarm(arena_.New<AckAlarmDelegate>(this),
+ &arena_)),
+ retransmission_alarm_(alarm_factory_->CreateAlarm(
+ arena_.New<RetransmissionAlarmDelegate>(this),
+ &arena_)),
+ send_alarm_(
+ alarm_factory_->CreateAlarm(arena_.New<SendAlarmDelegate>(this),
+ &arena_)),
+ resume_writes_alarm_(
+ alarm_factory_->CreateAlarm(arena_.New<SendAlarmDelegate>(this),
+ &arena_)),
+ timeout_alarm_(
+ alarm_factory_->CreateAlarm(arena_.New<TimeoutAlarmDelegate>(this),
+ &arena_)),
+ ping_alarm_(
+ alarm_factory_->CreateAlarm(arena_.New<PingAlarmDelegate>(this),
+ &arena_)),
+ mtu_discovery_alarm_(alarm_factory_->CreateAlarm(
+ arena_.New<MtuDiscoveryAlarmDelegate>(this),
+ &arena_)),
+ visitor_(nullptr),
+ debug_visitor_(nullptr),
+ packet_generator_(connection_id_,
+ &framer_,
+ random_generator_,
+ helper->GetBufferAllocator(),
+ this),
+ idle_network_timeout_(QuicTime::Delta::Infinite()),
+ handshake_timeout_(QuicTime::Delta::Infinite()),
+ time_of_last_received_packet_(clock_->ApproximateNow()),
+ time_of_last_sent_new_packet_(clock_->ApproximateNow()),
+ last_send_for_timeout_(clock_->ApproximateNow()),
+ packet_number_of_last_sent_packet_(0),
+ sent_packet_manager_(new QuicSentPacketManager(perspective,
+ kDefaultPathId,
+ clock_,
+ &stats_,
+ kCubic,
+ kNack,
+ /*delegate=*/nullptr)),
+ version_negotiation_state_(START_NEGOTIATION),
+ perspective_(perspective),
+ connected_(true),
+ can_truncate_connection_ids_(true),
+ mtu_discovery_target_(0),
+ mtu_probe_count_(0),
+ packets_between_mtu_probes_(kPacketsBetweenMtuProbesBase),
+ next_mtu_probe_at_(kPacketsBetweenMtuProbesBase),
+ largest_received_packet_size_(0),
+ largest_packet_size_supported_(std::numeric_limits<QuicByteCount>::max()),
+ goaway_sent_(false),
+ goaway_received_(false),
+ multipath_enabled_(false),
+ write_error_occured_(false) {
+ DVLOG(1) << ENDPOINT
+ << "Created connection with connection_id: " << connection_id;
+ framer_.set_visitor(this);
+ framer_.set_received_entropy_calculator(&received_packet_manager_);
+ if (!FLAGS_quic_receive_packet_once_decrypted) {
+ last_stop_waiting_frame_.least_unacked = 0;
+ }
+ stats_.connection_creation_time = clock_->ApproximateNow();
+ if (FLAGS_quic_enable_multipath) {
+ sent_packet_manager_.reset(new QuicMultipathSentPacketManager(
+ sent_packet_manager_.release(), this));
+ }
+ // TODO(ianswett): Supply the NetworkChangeVisitor as a constructor argument
+ // and make it required non-null, because it's always used.
+ sent_packet_manager_->SetNetworkChangeVisitor(this);
+ // Allow the packet writer to potentially reduce the packet size to a value
+ // even smaller than kDefaultMaxPacketSize.
+ SetMaxPacketLength(perspective_ == Perspective::IS_SERVER
+ ? kDefaultServerMaxPacketSize
+ : kDefaultMaxPacketSize);
+ received_packet_manager_.SetVersion(version());
+}
+
+QuicConnection::~QuicConnection() {
+ if (owns_writer_) {
+ delete writer_;
+ }
+ base::STLDeleteElements(&undecryptable_packets_);
+ ClearQueuedPackets();
+}
+
+void QuicConnection::ClearQueuedPackets() {
+ for (QueuedPacketList::iterator it = queued_packets_.begin();
+ it != queued_packets_.end(); ++it) {
+ // Delete the buffer before calling ClearSerializedPacket, which sets
+ // encrypted_buffer to nullptr.
+ delete[] it->encrypted_buffer;
+ QuicUtils::ClearSerializedPacket(&(*it));
+ }
+ queued_packets_.clear();
+}
+
+void QuicConnection::SetFromConfig(const QuicConfig& config) {
+ if (config.negotiated()) {
+ // Handshake complete, set handshake timeout to Infinite.
+ SetNetworkTimeouts(QuicTime::Delta::Infinite(),
+ config.IdleConnectionStateLifetime());
+ if (config.SilentClose()) {
+ idle_timeout_connection_close_behavior_ =
+ ConnectionCloseBehavior::SILENT_CLOSE;
+ }
+ if (FLAGS_quic_enable_multipath && config.MultipathEnabled()) {
+ multipath_enabled_ = true;
+ }
+ } else {
+ SetNetworkTimeouts(config.max_time_before_crypto_handshake(),
+ config.max_idle_time_before_crypto_handshake());
+ }
+
+ sent_packet_manager_->SetFromConfig(config);
+ if (config.HasReceivedBytesForConnectionId() &&
+ can_truncate_connection_ids_) {
+ packet_generator_.SetConnectionIdLength(
+ config.ReceivedBytesForConnectionId());
+ }
+ max_undecryptable_packets_ = config.max_undecryptable_packets();
+
+ if (config.HasClientSentConnectionOption(kMTUH, perspective_)) {
+ SetMtuDiscoveryTarget(kMtuDiscoveryTargetPacketSizeHigh);
+ }
+ if (config.HasClientSentConnectionOption(kMTUL, perspective_)) {
+ SetMtuDiscoveryTarget(kMtuDiscoveryTargetPacketSizeLow);
+ }
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnSetFromConfig(config);
+ }
+ if (config.HasClientSentConnectionOption(kACKD, perspective_)) {
+ ack_mode_ = ACK_DECIMATION;
+ }
+ if (config.HasClientSentConnectionOption(kAKD2, perspective_)) {
+ ack_mode_ = ACK_DECIMATION_WITH_REORDERING;
+ }
+ if (config.HasClientSentConnectionOption(kAKD3, perspective_)) {
+ ack_mode_ = ACK_DECIMATION;
+ ack_decimation_delay_ = kShortAckDecimationDelay;
+ }
+ if (config.HasClientSentConnectionOption(kAKD4, perspective_)) {
+ ack_mode_ = ACK_DECIMATION_WITH_REORDERING;
+ ack_decimation_delay_ = kShortAckDecimationDelay;
+ }
+ if (config.HasClientSentConnectionOption(k5RTO, perspective_)) {
+ if (perspective_ == Perspective::IS_CLIENT ||
+ !FLAGS_quic_only_5rto_client_side) {
+ close_connection_after_five_rtos_ = true;
+ }
+ }
+}
+
+void QuicConnection::OnSendConnectionState(
+ const CachedNetworkParameters& cached_network_params) {
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnSendConnectionState(cached_network_params);
+ }
+}
+
+void QuicConnection::OnReceiveConnectionState(
+ const CachedNetworkParameters& cached_network_params) {
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnReceiveConnectionState(cached_network_params);
+ }
+}
+
+void QuicConnection::ResumeConnectionState(
+ const CachedNetworkParameters& cached_network_params,
+ bool max_bandwidth_resumption) {
+ sent_packet_manager_->ResumeConnectionState(cached_network_params,
+ max_bandwidth_resumption);
+}
+
+void QuicConnection::SetMaxPacingRate(QuicBandwidth max_pacing_rate) {
+ sent_packet_manager_->SetMaxPacingRate(max_pacing_rate);
+}
+
+void QuicConnection::SetNumOpenStreams(size_t num_streams) {
+ sent_packet_manager_->SetNumOpenStreams(num_streams);
+}
+
+bool QuicConnection::SelectMutualVersion(
+ const QuicVersionVector& 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 QuicVersionVector& supported_versions = framer_.supported_versions();
+ for (size_t i = 0; i < supported_versions.size(); ++i) {
+ const QuicVersion& version = supported_versions[i];
+ if (base::ContainsValue(available_versions, version)) {
+ framer_.set_version(version);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void QuicConnection::OnError(QuicFramer* framer) {
+ // Packets that we can not or have not decrypted are dropped.
+ // TODO(rch): add stats to measure this.
+ if (!connected_ || last_packet_decrypted_ == false) {
+ return;
+ }
+ CloseConnection(framer->error(), framer->detailed_error(),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+}
+
+void QuicConnection::OnPacket() {
+ last_packet_decrypted_ = false;
+}
+
+void QuicConnection::OnPublicResetPacket(const QuicPublicResetPacket& packet) {
+ // Check that any public reset packet with a different connection ID that was
+ // routed to this QuicConnection has been redirected before control reaches
+ // here. (Check for a bug regression.)
+ DCHECK_EQ(connection_id_, packet.public_header.connection_id);
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnPublicResetPacket(packet);
+ }
+ const string error_details = "Received public reset.";
+ DVLOG(1) << ENDPOINT << error_details;
+ TearDownLocalConnectionState(QUIC_PUBLIC_RESET, error_details,
+ ConnectionCloseSource::FROM_PEER);
+}
+
+bool QuicConnection::OnProtocolVersionMismatch(QuicVersion received_version) {
+ DVLOG(1) << ENDPOINT << "Received packet with mismatched version "
+ << received_version;
+ // TODO(satyamshekhar): Implement no server state in this mode.
+ if (perspective_ == Perspective::IS_CLIENT) {
+ const string error_details = "Protocol version mismatch.";
+ QUIC_BUG << ENDPOINT << error_details;
+ TearDownLocalConnectionState(QUIC_INTERNAL_ERROR, error_details,
+ ConnectionCloseSource::FROM_SELF);
+ return false;
+ }
+ DCHECK_NE(version(), received_version);
+
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnProtocolVersionMismatch(received_version);
+ }
+
+ switch (version_negotiation_state_) {
+ case START_NEGOTIATION:
+ if (!framer_.IsSupportedVersion(received_version)) {
+ SendVersionNegotiationPacket();
+ version_negotiation_state_ = NEGOTIATION_IN_PROGRESS;
+ return false;
+ }
+ break;
+
+ case NEGOTIATION_IN_PROGRESS:
+ if (!framer_.IsSupportedVersion(received_version)) {
+ SendVersionNegotiationPacket();
+ return false;
+ }
+ break;
+
+ case NEGOTIATED_VERSION:
+ // Might be old packets that were sent by the client before the version
+ // was negotiated. Drop these.
+ return false;
+
+ default:
+ DCHECK(false);
+ }
+
+ version_negotiation_state_ = NEGOTIATED_VERSION;
+ received_packet_manager_.SetVersion(received_version);
+ visitor_->OnSuccessfulVersionNegotiation(received_version);
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnSuccessfulVersionNegotiation(received_version);
+ }
+ DVLOG(1) << ENDPOINT << "version negotiated " << received_version;
+
+ // Store the new version.
+ framer_.set_version(received_version);
+
+ // TODO(satyamshekhar): Store the packet number of this packet and close the
+ // connection if we ever received a packet with incorrect version and whose
+ // packet number is greater.
+ return true;
+}
+
+// Handles version negotiation for client connection.
+void QuicConnection::OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) {
+ // Check that any public reset packet with a different connection ID that was
+ // routed to this QuicConnection has been redirected before control reaches
+ // here. (Check for a bug regression.)
+ DCHECK_EQ(connection_id_, packet.connection_id);
+ if (perspective_ == Perspective::IS_SERVER) {
+ const string error_details = "Server receieved version negotiation packet.";
+ QUIC_BUG << error_details;
+ TearDownLocalConnectionState(QUIC_INTERNAL_ERROR, error_details,
+ ConnectionCloseSource::FROM_SELF);
+ return;
+ }
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnVersionNegotiationPacket(packet);
+ }
+
+ if (version_negotiation_state_ != START_NEGOTIATION) {
+ // Possibly a duplicate version negotiation packet.
+ return;
+ }
+
+ if (base::ContainsValue(packet.versions, version())) {
+ const string error_details =
+ "Server already supports client's version and should have accepted the "
+ "connection.";
+ DLOG(WARNING) << error_details;
+ TearDownLocalConnectionState(QUIC_INVALID_VERSION_NEGOTIATION_PACKET,
+ error_details,
+ ConnectionCloseSource::FROM_SELF);
+ return;
+ }
+
+ if (!SelectMutualVersion(packet.versions)) {
+ CloseConnection(
+ QUIC_INVALID_VERSION,
+ "No common version found. Supported versions: {" +
+ QuicVersionVectorToString(framer_.supported_versions()) +
+ "}, peer supported versions: {" +
+ QuicVersionVectorToString(packet.versions) + "}",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+
+ DVLOG(1) << ENDPOINT
+ << "Negotiated version: " << QuicVersionToString(version());
+ received_packet_manager_.SetVersion(version());
+ server_supported_versions_ = packet.versions;
+ version_negotiation_state_ = NEGOTIATION_IN_PROGRESS;
+ RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION);
+}
+
+bool QuicConnection::OnUnauthenticatedPublicHeader(
+ const QuicPacketPublicHeader& header) {
+ if (header.connection_id == connection_id_) {
+ return true;
+ }
+
+ ++stats_.packets_dropped;
+ DVLOG(1) << ENDPOINT << "Ignoring packet from unexpected ConnectionId: "
+ << header.connection_id << " instead of " << connection_id_;
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnIncorrectConnectionId(header.connection_id);
+ }
+ // If this is a server, the dispatcher routes each packet to the
+ // QuicConnection responsible for the packet's connection ID. So if control
+ // arrives here and this is a server, the dispatcher must be malfunctioning.
+ DCHECK_NE(Perspective::IS_SERVER, perspective_);
+ return false;
+}
+
+bool QuicConnection::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnUnauthenticatedHeader(header);
+ }
+
+ // Check that any public reset packet with a different connection ID that was
+ // routed to this QuicConnection has been redirected before control reaches
+ // here.
+ DCHECK_EQ(connection_id_, header.public_header.connection_id);
+
+ if (!packet_generator_.IsPendingPacketEmpty()) {
+ // Incoming packets may change a queued ACK frame.
+ const string error_details =
+ "Pending frames must be serialized before incoming packets are "
+ "processed.";
+ QUIC_BUG << error_details;
+ CloseConnection(QUIC_INTERNAL_ERROR, error_details,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+
+ // If this packet has already been seen, or the sender has told us that it
+ // will not be retransmitted, then stop processing the packet.
+ if (!received_packet_manager_.IsAwaitingPacket(header.packet_number)) {
+ DVLOG(1) << ENDPOINT << "Packet " << header.packet_number
+ << " no longer being waited for. Discarding.";
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnDuplicatePacket(header.packet_number);
+ }
+ ++stats_.packets_dropped;
+ return false;
+ }
+
+ return true;
+}
+
+void QuicConnection::OnDecryptedPacket(EncryptionLevel level) {
+ last_decrypted_packet_level_ = level;
+ last_packet_decrypted_ = true;
+
+ // Once the server receives a forward secure packet, the handshake is
+ // confirmed.
+ if (level == ENCRYPTION_FORWARD_SECURE &&
+ perspective_ == Perspective::IS_SERVER) {
+ sent_packet_manager_->SetHandshakeConfirmed();
+ }
+}
+
+bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnPacketHeader(header);
+ }
+
+ // Will be decremented below if we fall through to return true.
+ ++stats_.packets_dropped;
+
+ if (!ProcessValidatedPacket(header)) {
+ return false;
+ }
+
+ // Only migrate connection to a new peer address if a change is not underway.
+ PeerAddressChangeType peer_migration_type =
+ QuicUtils::DetermineAddressChangeType(peer_address_,
+ last_packet_source_address_);
+ // Do not migrate connection if the changed address packet is a reordered
+ // packet.
+ if (active_peer_migration_type_ == NO_CHANGE &&
+ peer_migration_type != NO_CHANGE &&
+ header.packet_number > received_packet_manager_.GetLargestObserved()) {
+ StartPeerMigration(header.path_id, peer_migration_type);
+ }
+
+ --stats_.packets_dropped;
+ DVLOG(1) << ENDPOINT << "Received packet header: " << header;
+ last_header_ = header;
+ if (FLAGS_quic_receive_packet_once_decrypted) {
+ // An ack will be sent if a missing retransmittable packet was received;
+ was_last_packet_missing_ =
+ received_packet_manager_.IsMissing(last_header_.packet_number);
+
+ // Record received to populate ack info correctly before processing stream
+ // frames, since the processing may result in a response packet with a
+ // bundled ack.
+ received_packet_manager_.RecordPacketReceived(
+ last_header_, time_of_last_received_packet_);
+ }
+ DCHECK(connected_);
+ return true;
+}
+
+bool QuicConnection::OnStreamFrame(const QuicStreamFrame& frame) {
+ DCHECK(connected_);
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnStreamFrame(frame);
+ }
+ if (frame.stream_id != kCryptoStreamId &&
+ last_decrypted_packet_level_ == ENCRYPTION_NONE) {
+ if (MaybeConsiderAsMemoryCorruption(frame)) {
+ CloseConnection(QUIC_MAYBE_CORRUPTED_MEMORY,
+ "Received crypto frame on non crypto stream.",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+
+ QUIC_BUG << ENDPOINT
+ << "Received an unencrypted data frame: closing connection"
+ << " packet_number:" << last_header_.packet_number
+ << " stream_id:" << frame.stream_id
+ << " received_packets:" << received_packet_manager_.ack_frame();
+ CloseConnection(QUIC_UNENCRYPTED_STREAM_DATA,
+ "Unencrypted stream data seen.",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+ visitor_->OnStreamFrame(frame);
+ visitor_->PostProcessAfterData();
+ stats_.stream_bytes_received += frame.data_length;
+ should_last_packet_instigate_acks_ = true;
+ return connected_;
+}
+
+bool QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) {
+ DCHECK(connected_);
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnAckFrame(incoming_ack);
+ }
+ DVLOG(1) << ENDPOINT << "OnAckFrame: " << incoming_ack;
+
+ if (last_header_.packet_number <= largest_seen_packet_with_ack_) {
+ DVLOG(1) << ENDPOINT << "Received an old ack frame: ignoring";
+ return true;
+ }
+
+ const char* error = ValidateAckFrame(incoming_ack);
+ if (error != nullptr) {
+ CloseConnection(QUIC_INVALID_ACK_DATA, error,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+
+ if (send_alarm_->IsSet()) {
+ send_alarm_->Cancel();
+ }
+ ProcessAckFrame(incoming_ack);
+ if (incoming_ack.is_truncated) {
+ should_last_packet_instigate_acks_ = true;
+ }
+ // If the incoming ack's packets set expresses missing packets: peer is still
+ // waiting for a packet lower than a packet that we are no longer planning to
+ // send.
+ // If the incoming ack's packets set expresses received packets: peer is still
+ // acking packets which we never care about.
+ // Send an ack to raise the high water mark.
+ if (!incoming_ack.packets.Empty() &&
+ GetLeastUnacked(incoming_ack.path_id) > incoming_ack.packets.Min()) {
+ ++stop_waiting_count_;
+ } else {
+ stop_waiting_count_ = 0;
+ }
+
+ return connected_;
+}
+
+void QuicConnection::ProcessAckFrame(const QuicAckFrame& incoming_ack) {
+ largest_seen_packet_with_ack_ = last_header_.packet_number;
+ sent_packet_manager_->OnIncomingAck(incoming_ack,
+ time_of_last_received_packet_);
+ if (version() <= QUIC_VERSION_33) {
+ sent_entropy_manager_.ClearEntropyBefore(
+ sent_packet_manager_->GetLeastPacketAwaitedByPeer(
+ incoming_ack.path_id) -
+ 1);
+ }
+ // Always reset the retransmission alarm when an ack comes in, since we now
+ // have a better estimate of the current rtt than when it was set.
+ SetRetransmissionAlarm();
+}
+
+void QuicConnection::ProcessStopWaitingFrame(
+ const QuicStopWaitingFrame& stop_waiting) {
+ largest_seen_packet_with_stop_waiting_ = last_header_.packet_number;
+ received_packet_manager_.UpdatePacketInformationSentByPeer(stop_waiting);
+}
+
+bool QuicConnection::OnStopWaitingFrame(const QuicStopWaitingFrame& frame) {
+ DCHECK(connected_);
+
+ if (last_header_.packet_number <= largest_seen_packet_with_stop_waiting_) {
+ DVLOG(1) << ENDPOINT << "Received an old stop waiting frame: ignoring";
+ return true;
+ }
+
+ const char* error = ValidateStopWaitingFrame(frame);
+ if (error != nullptr) {
+ CloseConnection(QUIC_INVALID_STOP_WAITING_DATA, error,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnStopWaitingFrame(frame);
+ }
+
+ if (FLAGS_quic_receive_packet_once_decrypted) {
+ ProcessStopWaitingFrame(frame);
+ } else {
+ last_stop_waiting_frame_ = frame;
+ }
+ return connected_;
+}
+
+bool QuicConnection::OnPaddingFrame(const QuicPaddingFrame& frame) {
+ DCHECK(connected_);
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnPaddingFrame(frame);
+ }
+ return true;
+}
+
+bool QuicConnection::OnPingFrame(const QuicPingFrame& frame) {
+ DCHECK(connected_);
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnPingFrame(frame);
+ }
+ should_last_packet_instigate_acks_ = true;
+ return true;
+}
+
+const char* QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
+ if (incoming_ack.largest_observed > packet_generator_.packet_number()) {
+ DLOG(WARNING) << ENDPOINT << "Peer's observed unsent packet:"
+ << incoming_ack.largest_observed << " vs "
+ << packet_generator_.packet_number();
+ // We got an error for data we have not sent. Error out.
+ return "Largest observed too high.";
+ }
+
+ if (incoming_ack.largest_observed <
+ sent_packet_manager_->GetLargestObserved(incoming_ack.path_id)) {
+ VLOG(1) << ENDPOINT << "Peer's largest_observed packet decreased:"
+ << incoming_ack.largest_observed << " vs "
+ << sent_packet_manager_->GetLargestObserved(incoming_ack.path_id)
+ << " packet_number:" << last_header_.packet_number
+ << " largest seen with ack:" << largest_seen_packet_with_ack_
+ << " connection_id: " << connection_id_;
+ // A new ack has a diminished largest_observed value. Error out.
+ // If this was an old packet, we wouldn't even have checked.
+ return "Largest observed too low.";
+ }
+
+ if (version() <= QUIC_VERSION_33) {
+ if (!incoming_ack.packets.Empty() &&
+ incoming_ack.packets.Max() > incoming_ack.largest_observed) {
+ LOG(WARNING) << ENDPOINT
+ << "Peer sent missing packet: " << incoming_ack.packets.Max()
+ << " which is greater than largest observed: "
+ << incoming_ack.largest_observed;
+ return "Missing packet higher than largest observed.";
+ }
+
+ if (!incoming_ack.packets.Empty() &&
+ incoming_ack.packets.Min() <
+ sent_packet_manager_->GetLeastPacketAwaitedByPeer(
+ incoming_ack.path_id)) {
+ LOG(WARNING) << ENDPOINT
+ << "Peer sent missing packet: " << incoming_ack.packets.Min()
+ << " which is smaller than least_packet_awaited_by_peer_: "
+ << sent_packet_manager_->GetLeastPacketAwaitedByPeer(
+ incoming_ack.path_id);
+ return "Missing packet smaller than least awaited.";
+ }
+ if (!sent_entropy_manager_.IsValidEntropy(incoming_ack.largest_observed,
+ incoming_ack.packets,
+ incoming_ack.entropy_hash)) {
+ DLOG(WARNING) << ENDPOINT << "Peer sent invalid entropy."
+ << " largest_observed:" << incoming_ack.largest_observed
+ << " last_received:" << last_header_.packet_number;
+ return "Invalid entropy.";
+ }
+ } else {
+ if (!incoming_ack.packets.Empty() &&
+ incoming_ack.packets.Max() != incoming_ack.largest_observed) {
+ QUIC_BUG << ENDPOINT
+ << "Peer last received packet: " << incoming_ack.packets.Max()
+ << " which is not equal to largest observed: "
+ << incoming_ack.largest_observed;
+ return "Last received packet not equal to largest observed.";
+ }
+ }
+
+ return nullptr;
+}
+
+const char* QuicConnection::ValidateStopWaitingFrame(
+ const QuicStopWaitingFrame& stop_waiting) {
+ if (stop_waiting.least_unacked <
+ received_packet_manager_.peer_least_packet_awaiting_ack()) {
+ DLOG(ERROR) << ENDPOINT << "Peer's sent low least_unacked: "
+ << stop_waiting.least_unacked << " vs "
+ << received_packet_manager_.peer_least_packet_awaiting_ack();
+ // We never process old ack frames, so this number should only increase.
+ return "Least unacked too small.";
+ }
+
+ if (stop_waiting.least_unacked > last_header_.packet_number) {
+ DLOG(ERROR) << ENDPOINT
+ << "Peer sent least_unacked:" << stop_waiting.least_unacked
+ << " greater than the enclosing packet number:"
+ << last_header_.packet_number;
+ return "Least unacked too large.";
+ }
+
+ return nullptr;
+}
+
+bool QuicConnection::OnRstStreamFrame(const QuicRstStreamFrame& frame) {
+ DCHECK(connected_);
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnRstStreamFrame(frame);
+ }
+ DVLOG(1) << ENDPOINT
+ << "RST_STREAM_FRAME received for stream: " << frame.stream_id
+ << " with error: "
+ << QuicUtils::StreamErrorToString(frame.error_code);
+ visitor_->OnRstStream(frame);
+ visitor_->PostProcessAfterData();
+ should_last_packet_instigate_acks_ = true;
+ return connected_;
+}
+
+bool QuicConnection::OnConnectionCloseFrame(
+ const QuicConnectionCloseFrame& frame) {
+ DCHECK(connected_);
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnConnectionCloseFrame(frame);
+ }
+ DVLOG(1) << ENDPOINT
+ << "Received ConnectionClose for connection: " << connection_id()
+ << ", with error: " << QuicUtils::ErrorToString(frame.error_code)
+ << " (" << frame.error_details << ")";
+ if (frame.error_code == QUIC_BAD_MULTIPATH_FLAG) {
+ LOG(ERROR) << " quic_version: " << version()
+ << " last_received_header: " << last_header_
+ << " encryption_level: " << encryption_level_;
+ }
+ TearDownLocalConnectionState(frame.error_code, frame.error_details,
+ ConnectionCloseSource::FROM_PEER);
+ return connected_;
+}
+
+bool QuicConnection::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
+ DCHECK(connected_);
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnGoAwayFrame(frame);
+ }
+ DVLOG(1) << ENDPOINT << "GOAWAY_FRAME received with last good stream: "
+ << frame.last_good_stream_id
+ << " and error: " << QuicUtils::ErrorToString(frame.error_code)
+ << " and reason: " << frame.reason_phrase;
+
+ goaway_received_ = true;
+ visitor_->OnGoAway(frame);
+ visitor_->PostProcessAfterData();
+ should_last_packet_instigate_acks_ = true;
+ return connected_;
+}
+
+bool QuicConnection::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
+ DCHECK(connected_);
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnWindowUpdateFrame(frame);
+ }
+ DVLOG(1) << ENDPOINT
+ << "WINDOW_UPDATE_FRAME received for stream: " << frame.stream_id
+ << " with byte offset: " << frame.byte_offset;
+ visitor_->OnWindowUpdateFrame(frame);
+ visitor_->PostProcessAfterData();
+ should_last_packet_instigate_acks_ = true;
+ return connected_;
+}
+
+bool QuicConnection::OnBlockedFrame(const QuicBlockedFrame& frame) {
+ DCHECK(connected_);
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnBlockedFrame(frame);
+ }
+ DVLOG(1) << ENDPOINT
+ << "BLOCKED_FRAME received for stream: " << frame.stream_id;
+ visitor_->OnBlockedFrame(frame);
+ visitor_->PostProcessAfterData();
+ should_last_packet_instigate_acks_ = true;
+ return connected_;
+}
+
+bool QuicConnection::OnPathCloseFrame(const QuicPathCloseFrame& frame) {
+ DCHECK(connected_);
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnPathCloseFrame(frame);
+ }
+ DVLOG(1) << ENDPOINT
+ << "PATH_CLOSE_FRAME received for path: " << frame.path_id;
+ OnPathClosed(frame.path_id);
+ return connected_;
+}
+
+void QuicConnection::OnPacketComplete() {
+ // Don't do anything if this packet closed the connection.
+ if (!connected_) {
+ ClearLastFrames();
+ return;
+ }
+
+ DVLOG(1) << ENDPOINT << "Got packet " << last_header_.packet_number << " for "
+ << last_header_.public_header.connection_id;
+
+ if (FLAGS_quic_receive_packet_once_decrypted) {
+ // An ack will be sent if a missing retransmittable packet was received;
+ const bool was_missing =
+ should_last_packet_instigate_acks_ && was_last_packet_missing_;
+
+ // It's possible the ack frame was sent along with response data, so it
+ // no longer needs to be sent.
+ if (ack_frame_updated()) {
+ MaybeQueueAck(was_missing);
+ }
+ } else {
+ // An ack will be sent if a missing retransmittable packet was received;
+ const bool was_missing =
+ should_last_packet_instigate_acks_ &&
+ received_packet_manager_.IsMissing(last_header_.packet_number);
+
+ // Record received to populate ack info correctly before processing stream
+ // frames, since the processing may result in a response packet with a
+ // bundled ack.
+ received_packet_manager_.RecordPacketReceived(
+ last_header_, time_of_last_received_packet_);
+
+ // Process stop waiting frames here, instead of inline, because the packet
+ // needs to be considered 'received' before the entropy can be updated.
+ if (last_stop_waiting_frame_.least_unacked > 0) {
+ ProcessStopWaitingFrame(last_stop_waiting_frame_);
+ if (!connected_) {
+ return;
+ }
+ }
+
+ MaybeQueueAck(was_missing);
+ }
+
+ ClearLastFrames();
+ MaybeCloseIfTooManyOutstandingPackets();
+}
+
+void QuicConnection::MaybeQueueAck(bool was_missing) {
+ ++num_packets_received_since_last_ack_sent_;
+ // Always send an ack every 20 packets in order to allow the peer to discard
+ // information from the SentPacketManager and provide an RTT measurement.
+ if (num_packets_received_since_last_ack_sent_ >=
+ kMaxPacketsReceivedBeforeAckSend) {
+ ack_queued_ = true;
+ }
+
+ // Determine whether the newly received packet was missing before recording
+ // the received packet.
+ // Ack decimation with reordering relies on the timer to send an ack, but if
+ // missing packets we reported in the previous ack, send an ack immediately.
+ if (was_missing && (ack_mode_ != ACK_DECIMATION_WITH_REORDERING ||
+ last_ack_had_missing_packets_)) {
+ ack_queued_ = true;
+ }
+
+ if (should_last_packet_instigate_acks_ && !ack_queued_) {
+ ++num_retransmittable_packets_received_since_last_ack_sent_;
+ if (ack_mode_ != TCP_ACKING &&
+ last_header_.packet_number > kMinReceivedBeforeAckDecimation) {
+ // Ack up to 10 packets at once.
+ if (num_retransmittable_packets_received_since_last_ack_sent_ >=
+ kMaxRetransmittablePacketsBeforeAck) {
+ ack_queued_ = true;
+ } else if (!ack_alarm_->IsSet()) {
+ // Wait the minimum of a quarter min_rtt and the delayed ack time.
+ QuicTime::Delta ack_delay = std::min(
+ DelayedAckTime(), sent_packet_manager_->GetRttStats()->min_rtt() *
+ ack_decimation_delay_);
+ ack_alarm_->Set(clock_->ApproximateNow() + ack_delay);
+ }
+ } else {
+ // Ack with a timer or every 2 packets by default.
+ if (num_retransmittable_packets_received_since_last_ack_sent_ >=
+ kDefaultRetransmittablePacketsBeforeAck) {
+ ack_queued_ = true;
+ } else if (!ack_alarm_->IsSet()) {
+ ack_alarm_->Set(clock_->ApproximateNow() + DelayedAckTime());
+ }
+ }
+
+ // If there are new missing packets to report, send an ack immediately.
+ if (received_packet_manager_.HasNewMissingPackets()) {
+ if (ack_mode_ == ACK_DECIMATION_WITH_REORDERING) {
+ // Wait the minimum of an eighth min_rtt and the existing ack time.
+ QuicTime ack_time =
+ clock_->ApproximateNow() +
+ 0.125 * sent_packet_manager_->GetRttStats()->min_rtt();
+ if (!ack_alarm_->IsSet() || ack_alarm_->deadline() > ack_time) {
+ ack_alarm_->Update(ack_time, QuicTime::Delta::Zero());
+ }
+ } else {
+ ack_queued_ = true;
+ }
+ }
+ }
+
+ if (ack_queued_) {
+ ack_alarm_->Cancel();
+ }
+}
+
+void QuicConnection::ClearLastFrames() {
+ should_last_packet_instigate_acks_ = false;
+ if (!FLAGS_quic_receive_packet_once_decrypted) {
+ last_stop_waiting_frame_.least_unacked = 0;
+ }
+}
+
+void QuicConnection::MaybeCloseIfTooManyOutstandingPackets() {
+ if (version() > QUIC_VERSION_33) {
+ return;
+ }
+ // This occurs if we don't discard old packets we've sent fast enough.
+ // It's possible largest observed is less than least unacked.
+ if (sent_packet_manager_->GetLargestObserved(last_header_.path_id) >
+ (sent_packet_manager_->GetLeastUnacked(last_header_.path_id) +
+ kMaxTrackedPackets)) {
+ CloseConnection(
+ QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS,
+ StringPrintf("More than %" PRIu64 " outstanding.", kMaxTrackedPackets),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ }
+ // This occurs if there are received packet gaps and the peer does not raise
+ // the least unacked fast enough.
+ if (received_packet_manager_.NumTrackedPackets() > kMaxTrackedPackets) {
+ CloseConnection(
+ QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS,
+ StringPrintf("More than %" PRIu64 " outstanding.", kMaxTrackedPackets),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ }
+}
+
+const QuicFrame QuicConnection::GetUpdatedAckFrame() {
+ return received_packet_manager_.GetUpdatedAckFrame(clock_->ApproximateNow());
+}
+
+void QuicConnection::PopulateStopWaitingFrame(
+ QuicStopWaitingFrame* stop_waiting) {
+ stop_waiting->least_unacked = GetLeastUnacked(stop_waiting->path_id);
+ if (version() <= QUIC_VERSION_33) {
+ stop_waiting->entropy_hash = sent_entropy_manager_.GetCumulativeEntropy(
+ stop_waiting->least_unacked - 1);
+ }
+}
+
+QuicPacketNumber QuicConnection::GetLeastUnacked(QuicPathId path_id) const {
+ return sent_packet_manager_->GetLeastUnacked(path_id);
+}
+
+void QuicConnection::MaybeSendInResponseToPacket() {
+ if (!connected_) {
+ return;
+ }
+ // Now that we have received an ack, we might be able to send packets which
+ // are queued locally, or drain streams which are blocked.
+ if (defer_send_in_response_to_packets_) {
+ send_alarm_->Update(clock_->ApproximateNow(), QuicTime::Delta::Zero());
+ } else {
+ WriteAndBundleAcksIfNotBlocked();
+ }
+}
+
+void QuicConnection::SendVersionNegotiationPacket() {
+ pending_version_negotiation_packet_ = true;
+ if (writer_->IsWriteBlocked()) {
+ visitor_->OnWriteBlocked();
+ return;
+ }
+ DVLOG(1) << ENDPOINT << "Sending version negotiation packet: {"
+ << QuicVersionVectorToString(framer_.supported_versions()) << "}";
+ std::unique_ptr<QuicEncryptedPacket> version_packet(
+ packet_generator_.SerializeVersionNegotiationPacket(
+ framer_.supported_versions()));
+ WriteResult result = writer_->WritePacket(
+ version_packet->data(), version_packet->length(),
+ self_address().address(), peer_address(), per_packet_options_);
+
+ if (result.status == WRITE_STATUS_ERROR) {
+ OnWriteError(result.error_code);
+ return;
+ }
+ if (result.status == WRITE_STATUS_BLOCKED) {
+ visitor_->OnWriteBlocked();
+ if (writer_->IsWriteBlockedDataBuffered()) {
+ pending_version_negotiation_packet_ = false;
+ }
+ return;
+ }
+
+ pending_version_negotiation_packet_ = false;
+}
+
+QuicConsumedData QuicConnection::SendStreamData(
+ QuicStreamId id,
+ QuicIOVector iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* listener) {
+ if (!fin && iov.total_length == 0) {
+ QUIC_BUG << "Attempt to send empty stream frame";
+ return QuicConsumedData(0, false);
+ }
+
+ // Opportunistically bundle an ack with every outgoing packet.
+ // Particularly, we want to bundle with handshake packets since we don't know
+ // which decrypter will be used on an ack packet following a handshake
+ // packet (a handshake packet from client to server could result in a REJ or a
+ // SHLO from the server, leading to two different decrypters at the server.)
+ ScopedRetransmissionScheduler alarm_delayer(this);
+ ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
+ // The optimized path may be used for data only packets which fit into a
+ // standard buffer and don't need padding.
+ if (id != kCryptoStreamId && !packet_generator_.HasQueuedFrames() &&
+ iov.total_length > kMaxPacketSize) {
+ // Use the fast path to send full data packets.
+ return packet_generator_.ConsumeDataFastPath(id, iov, offset, fin,
+ listener);
+ }
+ return packet_generator_.ConsumeData(id, iov, offset, fin, listener);
+}
+
+void QuicConnection::SendRstStream(QuicStreamId id,
+ QuicRstStreamErrorCode error,
+ QuicStreamOffset bytes_written) {
+ // Opportunistically bundle an ack with this outgoing packet.
+ ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
+ packet_generator_.AddControlFrame(QuicFrame(new QuicRstStreamFrame(
+ id, AdjustErrorForVersion(error, version()), bytes_written)));
+
+ if (error == QUIC_STREAM_NO_ERROR) {
+ // All data for streams which are reset with QUIC_STREAM_NO_ERROR must
+ // be received by the peer.
+ return;
+ }
+
+ sent_packet_manager_->CancelRetransmissionsForStream(id);
+ // Remove all queued packets which only contain data for the reset stream.
+ QueuedPacketList::iterator packet_iterator = queued_packets_.begin();
+ while (packet_iterator != queued_packets_.end()) {
+ QuicFrames* retransmittable_frames =
+ &packet_iterator->retransmittable_frames;
+ if (retransmittable_frames->empty()) {
+ ++packet_iterator;
+ continue;
+ }
+ QuicUtils::RemoveFramesForStream(retransmittable_frames, id);
+ if (!retransmittable_frames->empty()) {
+ ++packet_iterator;
+ continue;
+ }
+ delete[] packet_iterator->encrypted_buffer;
+ QuicUtils::ClearSerializedPacket(&(*packet_iterator));
+ packet_iterator = queued_packets_.erase(packet_iterator);
+ }
+}
+
+void QuicConnection::SendWindowUpdate(QuicStreamId id,
+ QuicStreamOffset byte_offset) {
+ // Opportunistically bundle an ack with this outgoing packet.
+ ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
+ packet_generator_.AddControlFrame(
+ QuicFrame(new QuicWindowUpdateFrame(id, byte_offset)));
+}
+
+void QuicConnection::SendBlocked(QuicStreamId id) {
+ // Opportunistically bundle an ack with this outgoing packet.
+ ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
+ packet_generator_.AddControlFrame(QuicFrame(new QuicBlockedFrame(id)));
+}
+
+void QuicConnection::SendPathClose(QuicPathId path_id) {
+ // Opportunistically bundle an ack with this outgoing packet.
+ ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
+ packet_generator_.AddControlFrame(QuicFrame(new QuicPathCloseFrame(path_id)));
+ OnPathClosed(path_id);
+}
+
+const QuicConnectionStats& QuicConnection::GetStats() {
+ const RttStats* rtt_stats = sent_packet_manager_->GetRttStats();
+
+ // Update rtt and estimated bandwidth.
+ QuicTime::Delta min_rtt = rtt_stats->min_rtt();
+ if (min_rtt.IsZero()) {
+ // If min RTT has not been set, use initial RTT instead.
+ min_rtt = QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
+ }
+ stats_.min_rtt_us = min_rtt.ToMicroseconds();
+
+ QuicTime::Delta srtt = rtt_stats->smoothed_rtt();
+ if (srtt.IsZero()) {
+ // If SRTT has not been set, use initial RTT instead.
+ srtt = QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
+ }
+ stats_.srtt_us = srtt.ToMicroseconds();
+
+ stats_.estimated_bandwidth = sent_packet_manager_->BandwidthEstimate();
+ stats_.max_packet_size = packet_generator_.GetCurrentMaxPacketLength();
+ stats_.max_received_packet_size = largest_received_packet_size_;
+ return stats_;
+}
+
+void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address,
+ const IPEndPoint& peer_address,
+ const QuicReceivedPacket& packet) {
+ if (!connected_) {
+ return;
+ }
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnPacketReceived(self_address, peer_address, packet);
+ }
+ last_size_ = packet.length();
+ current_packet_data_ = packet.data();
+
+ last_packet_destination_address_ = self_address;
+ last_packet_source_address_ = peer_address;
+ if (!IsInitializedIPEndPoint(self_address_)) {
+ self_address_ = last_packet_destination_address_;
+ }
+ if (!IsInitializedIPEndPoint(peer_address_)) {
+ peer_address_ = last_packet_source_address_;
+ }
+
+ stats_.bytes_received += packet.length();
+ ++stats_.packets_received;
+
+ // Ensure the time coming from the packet reader is within a minute of now.
+ if (FLAGS_quic_allow_large_send_deltas &&
+ std::abs((packet.receipt_time() - clock_->ApproximateNow()).ToSeconds()) >
+ 60) {
+ QUIC_BUG << "Packet receipt time:"
+ << packet.receipt_time().ToDebuggingValue()
+ << " too far from current time:"
+ << clock_->ApproximateNow().ToDebuggingValue();
+ }
+ time_of_last_received_packet_ = packet.receipt_time();
+ DVLOG(1) << ENDPOINT << "time of last received packet: "
+ << time_of_last_received_packet_.ToDebuggingValue();
+
+ ScopedRetransmissionScheduler alarm_delayer(this);
+ if (!framer_.ProcessPacket(packet)) {
+ // If we are unable to decrypt this packet, it might be
+ // because the CHLO or SHLO packet was lost.
+ if (framer_.error() == QUIC_DECRYPTION_FAILURE) {
+ if (encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
+ undecryptable_packets_.size() < max_undecryptable_packets_) {
+ QueueUndecryptablePacket(packet);
+ } else if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnUndecryptablePacket();
+ }
+ }
+ DVLOG(1) << ENDPOINT << "Unable to process packet. Last packet processed: "
+ << last_header_.packet_number;
+ current_packet_data_ = nullptr;
+ return;
+ }
+
+ ++stats_.packets_processed;
+ if (active_peer_migration_type_ != NO_CHANGE &&
+ sent_packet_manager_->GetLargestObserved(last_header_.path_id) >
+ highest_packet_sent_before_peer_migration_) {
+ OnPeerMigrationValidated(last_header_.path_id);
+ }
+ MaybeProcessUndecryptablePackets();
+ MaybeSendInResponseToPacket();
+ SetPingAlarm();
+ current_packet_data_ = nullptr;
+}
+
+void QuicConnection::OnCanWrite() {
+ DCHECK(!writer_->IsWriteBlocked());
+
+ WriteQueuedPackets();
+ WritePendingRetransmissions();
+
+ // Sending queued packets may have caused the socket to become write blocked,
+ // or the congestion manager to prohibit sending. If we've sent everything
+ // we had queued and we're still not blocked, let the visitor know it can
+ // write more.
+ if (!CanWrite(HAS_RETRANSMITTABLE_DATA)) {
+ return;
+ }
+
+ {
+ ScopedPacketBundler bundler(this, SEND_ACK_IF_QUEUED);
+ visitor_->OnCanWrite();
+ visitor_->PostProcessAfterData();
+ }
+
+ // After the visitor writes, it may have caused the socket to become write
+ // blocked or the congestion manager to prohibit sending, so check again.
+ if (visitor_->WillingAndAbleToWrite() && !resume_writes_alarm_->IsSet() &&
+ CanWrite(HAS_RETRANSMITTABLE_DATA)) {
+ // We're not write blocked, but some stream didn't write out all of its
+ // bytes. Register for 'immediate' resumption so we'll keep writing after
+ // other connections and events have had a chance to use the thread.
+ resume_writes_alarm_->Set(clock_->ApproximateNow());
+ }
+}
+
+void QuicConnection::WriteIfNotBlocked() {
+ if (!writer_->IsWriteBlocked()) {
+ OnCanWrite();
+ }
+}
+
+void QuicConnection::WriteAndBundleAcksIfNotBlocked() {
+ if (!writer_->IsWriteBlocked()) {
+ ScopedPacketBundler bundler(this, SEND_ACK_IF_QUEUED);
+ OnCanWrite();
+ }
+}
+
+bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) {
+ if (header.fec_flag) {
+ // Drop any FEC packet.
+ return false;
+ }
+
+ if (perspective_ == Perspective::IS_SERVER &&
+ IsInitializedIPEndPoint(self_address_) &&
+ IsInitializedIPEndPoint(last_packet_destination_address_) &&
+ (!(self_address_ == last_packet_destination_address_))) {
+ if (!FLAGS_quic_allow_server_address_change_for_mapped_ipv4) {
+ CloseConnection(QUIC_ERROR_MIGRATING_ADDRESS,
+ "Self address migration is not supported at the server.",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+ // Allow change between pure IPv4 and equivalent mapped IPv4 address.
+ IPAddress self_ip = self_address_.address();
+ if (self_ip.IsIPv4MappedIPv6()) {
+ self_ip = ConvertIPv4MappedIPv6ToIPv4(self_ip);
+ }
+ IPAddress last_packet_destination_ip =
+ last_packet_destination_address_.address();
+ if (last_packet_destination_ip.IsIPv4MappedIPv6()) {
+ last_packet_destination_ip =
+ ConvertIPv4MappedIPv6ToIPv4(last_packet_destination_ip);
+ }
+ if (self_address_.port() != last_packet_destination_address_.port() ||
+ self_ip != last_packet_destination_ip) {
+ CloseConnection(QUIC_ERROR_MIGRATING_ADDRESS,
+ "Self address migration is not supported at the server.",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+ self_address_ = last_packet_destination_address_;
+ }
+
+ if (!Near(header.packet_number, last_header_.packet_number)) {
+ DVLOG(1) << ENDPOINT << "Packet " << header.packet_number
+ << " out of bounds. Discarding";
+ CloseConnection(QUIC_INVALID_PACKET_HEADER, "packet number out of bounds.",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+
+ // Multipath is not enabled, but a packet with multipath flag on is
+ // received.
+ if (!multipath_enabled_ && header.public_header.multipath_flag) {
+ const string error_details =
+ "Received a packet with multipath flag but multipath is not enabled.";
+ QUIC_BUG << error_details;
+ CloseConnection(QUIC_BAD_MULTIPATH_FLAG, error_details,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+
+ if (version_negotiation_state_ != NEGOTIATED_VERSION) {
+ if (perspective_ == Perspective::IS_SERVER) {
+ if (!header.public_header.version_flag) {
+ // Packets should have the version flag till version negotiation is
+ // done.
+ string error_details =
+ StringPrintf("%s Packet %" PRIu64
+ " without version flag before version negotiated.",
+ ENDPOINT, header.packet_number);
+ DLOG(WARNING) << error_details;
+ CloseConnection(QUIC_INVALID_VERSION, error_details,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ } else {
+ DCHECK_EQ(1u, header.public_header.versions.size());
+ DCHECK_EQ(header.public_header.versions[0], version());
+ version_negotiation_state_ = NEGOTIATED_VERSION;
+ received_packet_manager_.SetVersion(version());
+ visitor_->OnSuccessfulVersionNegotiation(version());
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnSuccessfulVersionNegotiation(version());
+ }
+ }
+ } else {
+ DCHECK(!header.public_header.version_flag);
+ // If the client gets a packet without the version flag from the server
+ // it should stop sending version since the version negotiation is done.
+ packet_generator_.StopSendingVersion();
+ version_negotiation_state_ = NEGOTIATED_VERSION;
+ received_packet_manager_.SetVersion(version());
+ visitor_->OnSuccessfulVersionNegotiation(version());
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnSuccessfulVersionNegotiation(version());
+ }
+ }
+ }
+
+ DCHECK_EQ(NEGOTIATED_VERSION, version_negotiation_state_);
+
+ if (last_size_ > largest_received_packet_size_) {
+ largest_received_packet_size_ = last_size_;
+ }
+
+ if (perspective_ == Perspective::IS_SERVER &&
+ encryption_level_ == ENCRYPTION_NONE &&
+ last_size_ > packet_generator_.GetCurrentMaxPacketLength()) {
+ SetMaxPacketLength(last_size_);
+ }
+ return true;
+}
+
+void QuicConnection::WriteQueuedPackets() {
+ DCHECK(!writer_->IsWriteBlocked());
+
+ if (pending_version_negotiation_packet_) {
+ SendVersionNegotiationPacket();
+ }
+
+ QueuedPacketList::iterator packet_iterator = queued_packets_.begin();
+ while (packet_iterator != queued_packets_.end() &&
+ WritePacket(&(*packet_iterator))) {
+ delete[] packet_iterator->encrypted_buffer;
+ QuicUtils::ClearSerializedPacket(&(*packet_iterator));
+ packet_iterator = queued_packets_.erase(packet_iterator);
+ }
+}
+
+void QuicConnection::WritePendingRetransmissions() {
+ // Keep writing as long as there's a pending retransmission which can be
+ // written.
+ while (sent_packet_manager_->HasPendingRetransmissions()) {
+ const PendingRetransmission pending =
+ sent_packet_manager_->NextPendingRetransmission();
+ if (!CanWrite(HAS_RETRANSMITTABLE_DATA)) {
+ break;
+ }
+
+ // Re-packetize the frames with a new packet number for retransmission.
+ // Retransmitted packets use the same packet number length as the
+ // original.
+ // Flush the packet generator before making a new packet.
+ // TODO(ianswett): Implement ReserializeAllFrames as a separate path that
+ // does not require the creator to be flushed.
+ packet_generator_.FlushAllQueuedFrames();
+ char buffer[kMaxPacketSize];
+ packet_generator_.ReserializeAllFrames(pending, buffer, kMaxPacketSize);
+ }
+}
+
+void QuicConnection::RetransmitUnackedPackets(
+ TransmissionType retransmission_type) {
+ sent_packet_manager_->RetransmitUnackedPackets(retransmission_type);
+
+ WriteIfNotBlocked();
+}
+
+void QuicConnection::NeuterUnencryptedPackets() {
+ sent_packet_manager_->NeuterUnencryptedPackets();
+ // This may have changed the retransmission timer, so re-arm it.
+ SetRetransmissionAlarm();
+}
+
+bool QuicConnection::ShouldGeneratePacket(
+ HasRetransmittableData retransmittable,
+ IsHandshake handshake) {
+ // We should serialize handshake packets immediately to ensure that they
+ // end up sent at the right encryption level.
+ if (handshake == IS_HANDSHAKE) {
+ return true;
+ }
+
+ return CanWrite(retransmittable);
+}
+
+bool QuicConnection::CanWrite(HasRetransmittableData retransmittable) {
+ if (!connected_) {
+ return false;
+ }
+
+ if (writer_->IsWriteBlocked()) {
+ visitor_->OnWriteBlocked();
+ return false;
+ }
+
+ // Allow acks to be sent immediately.
+ if (retransmittable == NO_RETRANSMITTABLE_DATA) {
+ return true;
+ }
+ // If the send alarm is set, wait for it to fire.
+ if (send_alarm_->IsSet()) {
+ return false;
+ }
+
+ // TODO(fayang): If delay is not infinite, the next packet will be created and
+ // sent on path_id.
+ QuicPathId path_id = kInvalidPathId;
+ QuicTime now = clock_->Now();
+ QuicTime::Delta delay = sent_packet_manager_->TimeUntilSend(now, &path_id);
+ if (delay.IsInfinite()) {
+ DCHECK_EQ(kInvalidPathId, path_id);
+ send_alarm_->Cancel();
+ return false;
+ }
+
+ DCHECK_NE(kInvalidPathId, path_id);
+ // If the scheduler requires a delay, then we can not send this packet now.
+ if (!delay.IsZero()) {
+ send_alarm_->Update(now + delay, QuicTime::Delta::FromMilliseconds(1));
+ DVLOG(1) << ENDPOINT << "Delaying sending " << delay.ToMilliseconds()
+ << "ms";
+ return false;
+ }
+ return true;
+}
+
+bool QuicConnection::WritePacket(SerializedPacket* packet) {
+ if (packet->packet_number <
+ sent_packet_manager_->GetLargestSentPacket(packet->path_id)) {
+ QUIC_BUG << "Attempt to write packet:" << packet->packet_number << " after:"
+ << sent_packet_manager_->GetLargestSentPacket(packet->path_id);
+ CloseConnection(QUIC_INTERNAL_ERROR, "Packet written out of order.",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return true;
+ }
+ if (ShouldDiscardPacket(*packet)) {
+ ++stats_.packets_discarded;
+ return true;
+ }
+ // Termination packets are encrypted and saved, so don't exit early.
+ const bool is_termination_packet = IsTerminationPacket(*packet);
+ if (writer_->IsWriteBlocked() && !is_termination_packet) {
+ return false;
+ }
+
+ QuicPacketNumber packet_number = packet->packet_number;
+ // TODO(ianswett): Remove packet_number_of_last_sent_packet_ because it's
+ // redundant to SentPacketManager_->GetLargestPacket in most cases, and wrong
+ // for multipath.
+ DCHECK_LE(packet_number_of_last_sent_packet_, packet_number);
+ packet_number_of_last_sent_packet_ = packet_number;
+
+ QuicPacketLength encrypted_length = packet->encrypted_length;
+ // Termination packets are eventually owned by TimeWaitListManager.
+ // Others are deleted at the end of this call.
+ if (is_termination_packet) {
+ if (termination_packets_.get() == nullptr) {
+ termination_packets_.reset(
+ new std::vector<std::unique_ptr<QuicEncryptedPacket>>);
+ }
+ // Copy the buffer so it's owned in the future.
+ char* buffer_copy = QuicUtils::CopyBuffer(*packet);
+ termination_packets_->push_back(std::unique_ptr<QuicEncryptedPacket>(
+ new QuicEncryptedPacket(buffer_copy, encrypted_length, true)));
+ // This assures we won't try to write *forced* packets when blocked.
+ // Return true to stop processing.
+ if (writer_->IsWriteBlocked()) {
+ visitor_->OnWriteBlocked();
+ return true;
+ }
+ }
+
+ DCHECK_LE(encrypted_length, kMaxPacketSize);
+ DCHECK_LE(encrypted_length, packet_generator_.GetCurrentMaxPacketLength());
+ DVLOG(1) << ENDPOINT << "Sending packet " << packet_number << " : "
+ << (IsRetransmittable(*packet) == HAS_RETRANSMITTABLE_DATA
+ ? "data bearing "
+ : " ack only ")
+ << ", encryption level: "
+ << QuicUtils::EncryptionLevelToString(packet->encryption_level)
+ << ", encrypted length:" << encrypted_length;
+ DVLOG(2) << ENDPOINT << "packet(" << packet_number << "): " << std::endl
+ << QuicUtils::HexDump(
+ StringPiece(packet->encrypted_buffer, encrypted_length));
+
+ // Measure the RTT from before the write begins to avoid underestimating the
+ // min_rtt_, especially in cases where the thread blocks or gets swapped out
+ // during the WritePacket below.
+ QuicTime packet_send_time = clock_->Now();
+ WriteResult result = writer_->WritePacket(
+ packet->encrypted_buffer, encrypted_length, self_address().address(),
+ peer_address(), per_packet_options_);
+ if (result.error_code == ERR_IO_PENDING) {
+ DCHECK_EQ(WRITE_STATUS_BLOCKED, result.status);
+ }
+
+ if (result.status == WRITE_STATUS_BLOCKED) {
+ visitor_->OnWriteBlocked();
+ // If the socket buffers the the data, then the packet should not
+ // be queued and sent again, which would result in an unnecessary
+ // duplicate packet being sent. The helper must call OnCanWrite
+ // when the write completes, and OnWriteError if an error occurs.
+ if (!writer_->IsWriteBlockedDataBuffered()) {
+ return false;
+ }
+ }
+
+ if (FLAGS_quic_only_track_sent_packets) {
+ // In some cases, an MTU probe can cause EMSGSIZE. This indicates that the
+ // MTU discovery is permanently unsuccessful.
+ if (FLAGS_graceful_emsgsize_on_mtu_probe &&
+ result.status == WRITE_STATUS_ERROR &&
+ result.error_code == kMessageTooBigErrorCode &&
+ packet->retransmittable_frames.empty() &&
+ packet->encrypted_length > long_term_mtu_) {
+ mtu_discovery_target_ = 0;
+ mtu_discovery_alarm_->Cancel();
+ // The write failed, but the writer is not blocked, so return true.
+ return true;
+ }
+
+ if (result.status == WRITE_STATUS_ERROR) {
+ OnWriteError(result.error_code);
+ DLOG(ERROR) << ENDPOINT << "failed writing " << encrypted_length
+ << " from host "
+ << (self_address().address().empty()
+ ? " empty address "
+ : self_address().ToStringWithoutPort())
+ << " to address " << peer_address().ToString()
+ << " with error code " << result.error_code;
+ return false;
+ }
+ }
+
+ if (result.status != WRITE_STATUS_ERROR && debug_visitor_ != nullptr) {
+ // Pass the write result to the visitor.
+ debug_visitor_->OnPacketSent(*packet, packet->original_path_id,
+ packet->original_packet_number,
+ packet->transmission_type, packet_send_time);
+ }
+ if (packet->transmission_type == NOT_RETRANSMISSION) {
+ time_of_last_sent_new_packet_ = packet_send_time;
+ }
+ // Only adjust the last sent time (for the purpose of tracking the idle
+ // timeout) if this is the first retransmittable packet sent after a
+ // packet is received. If it were updated on every sent packet, then
+ // sending into a black hole might never timeout.
+ if (IsRetransmittable(*packet) == HAS_RETRANSMITTABLE_DATA &&
+ last_send_for_timeout_ <= time_of_last_received_packet_) {
+ last_send_for_timeout_ = packet_send_time;
+ }
+ SetPingAlarm();
+ MaybeSetMtuAlarm();
+ DVLOG(1) << ENDPOINT << "time we began writing last sent packet: "
+ << packet_send_time.ToDebuggingValue();
+
+ bool reset_retransmission_alarm = sent_packet_manager_->OnPacketSent(
+ packet, packet->original_path_id, packet->original_packet_number,
+ packet_send_time, packet->transmission_type, IsRetransmittable(*packet));
+
+ if (reset_retransmission_alarm || !retransmission_alarm_->IsSet()) {
+ SetRetransmissionAlarm();
+ }
+
+ // The packet number length must be updated after OnPacketSent, because it
+ // may change the packet number length in packet.
+ packet_generator_.UpdateSequenceNumberLength(
+ sent_packet_manager_->GetLeastUnacked(packet->path_id),
+ sent_packet_manager_->EstimateMaxPacketsInFlight(max_packet_length()));
+
+ stats_.bytes_sent += result.bytes_written;
+ ++stats_.packets_sent;
+ if (packet->transmission_type != NOT_RETRANSMISSION) {
+ stats_.bytes_retransmitted += result.bytes_written;
+ ++stats_.packets_retransmitted;
+ }
+
+ if (!FLAGS_quic_only_track_sent_packets) {
+ // In some cases, an MTU probe can cause EMSGSIZE. This indicates that the
+ // MTU discovery is permanently unsuccessful.
+ if (FLAGS_graceful_emsgsize_on_mtu_probe &&
+ result.status == WRITE_STATUS_ERROR &&
+ result.error_code == kMessageTooBigErrorCode &&
+ packet->retransmittable_frames.empty() &&
+ packet->encrypted_length > long_term_mtu_) {
+ mtu_discovery_target_ = 0;
+ mtu_discovery_alarm_->Cancel();
+ return true;
+ }
+
+ if (result.status == WRITE_STATUS_ERROR) {
+ OnWriteError(result.error_code);
+ DLOG(ERROR) << ENDPOINT << "failed writing " << encrypted_length
+ << " from host "
+ << (self_address().address().empty()
+ ? " empty address "
+ : self_address().ToStringWithoutPort())
+ << " to address " << peer_address().ToString()
+ << " with error code " << result.error_code;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool QuicConnection::ShouldDiscardPacket(const SerializedPacket& packet) {
+ if (!connected_) {
+ DVLOG(1) << ENDPOINT << "Not sending packet as connection is disconnected.";
+ return true;
+ }
+
+ QuicPacketNumber packet_number = packet.packet_number;
+ if (encryption_level_ == ENCRYPTION_FORWARD_SECURE &&
+ packet.encryption_level == ENCRYPTION_NONE) {
+ // Drop packets that are NULL encrypted since the peer won't accept them
+ // anymore.
+ DVLOG(1) << ENDPOINT << "Dropping NULL encrypted packet: " << packet_number
+ << " since the connection is forward secure.";
+ return true;
+ }
+
+ return false;
+}
+
+void QuicConnection::OnWriteError(int error_code) {
+ if (write_error_occured_) {
+ // A write error already occurred. The connection is being closed.
+ return;
+ }
+ write_error_occured_ = true;
+
+ const string error_details = "Write failed with error: " +
+ base::IntToString(error_code) + " (" +
+ ErrorToString(error_code) + ")";
+ DVLOG(1) << ENDPOINT << error_details;
+ // We can't send an error as the socket is presumably borked.
+ switch (error_code) {
+ case kMessageTooBigErrorCode:
+ CloseConnection(
+ QUIC_PACKET_WRITE_ERROR, error_details,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET_WITH_NO_ACK);
+ break;
+ default:
+ // We can't send an error as the socket is presumably borked.
+ TearDownLocalConnectionState(QUIC_PACKET_WRITE_ERROR, error_details,
+ ConnectionCloseSource::FROM_SELF);
+ }
+}
+
+void QuicConnection::OnSerializedPacket(SerializedPacket* serialized_packet) {
+ DCHECK_NE(kInvalidPathId, serialized_packet->path_id);
+ if (serialized_packet->encrypted_buffer == nullptr) {
+ // We failed to serialize the packet, so close the connection.
+ // TearDownLocalConnectionState does not send close packet, so no infinite
+ // loop here.
+ // TODO(ianswett): This is actually an internal error, not an
+ // encryption failure.
+ TearDownLocalConnectionState(
+ QUIC_ENCRYPTION_FAILURE,
+ "Serialized packet does not have an encrypted buffer.",
+ ConnectionCloseSource::FROM_SELF);
+ return;
+ }
+ SendOrQueuePacket(serialized_packet);
+}
+
+void QuicConnection::OnUnrecoverableError(QuicErrorCode error,
+ const string& error_details,
+ ConnectionCloseSource source) {
+ // The packet creator or generator encountered an unrecoverable error: tear
+ // down local connection state immediately.
+ TearDownLocalConnectionState(error, error_details, source);
+}
+
+void QuicConnection::OnCongestionChange() {
+ visitor_->OnCongestionWindowChange(clock_->ApproximateNow());
+
+ // Uses the connection's smoothed RTT. If zero, uses initial_rtt.
+ QuicTime::Delta rtt = sent_packet_manager_->GetRttStats()->smoothed_rtt();
+ if (rtt.IsZero()) {
+ rtt = QuicTime::Delta::FromMicroseconds(
+ sent_packet_manager_->GetRttStats()->initial_rtt_us());
+ }
+
+ if (debug_visitor_)
+ debug_visitor_->OnRttChanged(rtt);
+}
+
+void QuicConnection::OnPathDegrading() {
+ visitor_->OnPathDegrading();
+}
+
+void QuicConnection::OnPathMtuIncreased(QuicPacketLength packet_size) {
+ if (packet_size > max_packet_length()) {
+ SetMaxPacketLength(packet_size);
+ }
+}
+
+void QuicConnection::OnHandshakeComplete() {
+ sent_packet_manager_->SetHandshakeConfirmed();
+ // The client should immediately ack the SHLO to confirm the handshake is
+ // complete with the server.
+ if (perspective_ == Perspective::IS_CLIENT && !ack_queued_ &&
+ ack_frame_updated()) {
+ ack_alarm_->Update(clock_->ApproximateNow(), QuicTime::Delta::Zero());
+ }
+}
+
+void QuicConnection::SendOrQueuePacket(SerializedPacket* packet) {
+ // The caller of this function is responsible for checking CanWrite().
+ if (packet->encrypted_buffer == nullptr) {
+ QUIC_BUG << "packet.encrypted_buffer == nullptr in to SendOrQueuePacket";
+ return;
+ }
+ if (version() <= QUIC_VERSION_33) {
+ sent_entropy_manager_.RecordPacketEntropyHash(packet->packet_number,
+ packet->entropy_hash);
+ }
+ // If there are already queued packets, queue this one immediately to ensure
+ // it's written in sequence number order.
+ if (!queued_packets_.empty() || !WritePacket(packet)) {
+ // Take ownership of the underlying encrypted packet.
+ packet->encrypted_buffer = QuicUtils::CopyBuffer(*packet);
+ queued_packets_.push_back(*packet);
+ packet->retransmittable_frames.clear();
+ }
+
+ QuicUtils::ClearSerializedPacket(packet);
+}
+
+void QuicConnection::OnPingTimeout() {
+ if (!retransmission_alarm_->IsSet()) {
+ SendPing();
+ }
+}
+
+void QuicConnection::SendPing() {
+ ScopedPacketBundler bundler(this, SEND_ACK_IF_QUEUED);
+ packet_generator_.AddControlFrame(QuicFrame(QuicPingFrame()));
+ // Send PING frame immediately, without checking for congestion window bounds.
+ packet_generator_.FlushAllQueuedFrames();
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnPingSent();
+ }
+}
+
+void QuicConnection::SendAck() {
+ ack_alarm_->Cancel();
+ ack_queued_ = false;
+ stop_waiting_count_ = 0;
+ num_retransmittable_packets_received_since_last_ack_sent_ = 0;
+ last_ack_had_missing_packets_ = received_packet_manager_.HasMissingPackets();
+ num_packets_received_since_last_ack_sent_ = 0;
+
+ packet_generator_.SetShouldSendAck(true);
+}
+
+void QuicConnection::OnRetransmissionTimeout() {
+ DCHECK(sent_packet_manager_->HasUnackedPackets());
+
+ if (close_connection_after_five_rtos_ &&
+ sent_packet_manager_->GetConsecutiveRtoCount() >= 4) {
+ // Close on the 5th consecutive RTO, so after 4 previous RTOs have occurred.
+ CloseConnection(QUIC_TOO_MANY_RTOS, "5 consecutive retransmission timeouts",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+
+ sent_packet_manager_->OnRetransmissionTimeout();
+ WriteIfNotBlocked();
+
+ // A write failure can result in the connection being closed, don't attempt to
+ // write further packets, or to set alarms.
+ if (!connected_) {
+ return;
+ }
+
+ // In the TLP case, the SentPacketManager gives the connection the opportunity
+ // to send new data before retransmitting.
+ if (sent_packet_manager_->MaybeRetransmitTailLossProbe()) {
+ // Send the pending retransmission now that it's been queued.
+ WriteIfNotBlocked();
+ }
+
+ // Ensure the retransmission alarm is always set if there are unacked packets
+ // and nothing waiting to be sent.
+ // This happens if the loss algorithm invokes a timer based loss, but the
+ // packet doesn't need to be retransmitted.
+ if (!HasQueuedData() && !retransmission_alarm_->IsSet()) {
+ SetRetransmissionAlarm();
+ }
+}
+
+void QuicConnection::SetEncrypter(EncryptionLevel level,
+ QuicEncrypter* encrypter) {
+ packet_generator_.SetEncrypter(level, encrypter);
+}
+
+void QuicConnection::SetDiversificationNonce(
+ const DiversificationNonce& nonce) {
+ DCHECK_EQ(Perspective::IS_SERVER, perspective_);
+ packet_generator_.SetDiversificationNonce(nonce);
+}
+
+void QuicConnection::SetDefaultEncryptionLevel(EncryptionLevel level) {
+ encryption_level_ = level;
+ packet_generator_.set_encryption_level(level);
+}
+
+void QuicConnection::SetDecrypter(EncryptionLevel level,
+ QuicDecrypter* decrypter) {
+ framer_.SetDecrypter(level, decrypter);
+}
+
+void QuicConnection::SetAlternativeDecrypter(EncryptionLevel level,
+ QuicDecrypter* decrypter,
+ bool latch_once_used) {
+ framer_.SetAlternativeDecrypter(level, decrypter, latch_once_used);
+}
+
+const QuicDecrypter* QuicConnection::decrypter() const {
+ return framer_.decrypter();
+}
+
+const QuicDecrypter* QuicConnection::alternative_decrypter() const {
+ return framer_.alternative_decrypter();
+}
+
+void QuicConnection::QueueUndecryptablePacket(
+ const QuicEncryptedPacket& packet) {
+ DVLOG(1) << ENDPOINT << "Queueing undecryptable packet.";
+ undecryptable_packets_.push_back(packet.Clone());
+}
+
+void QuicConnection::MaybeProcessUndecryptablePackets() {
+ if (undecryptable_packets_.empty() || encryption_level_ == ENCRYPTION_NONE) {
+ return;
+ }
+
+ while (connected_ && !undecryptable_packets_.empty()) {
+ DVLOG(1) << ENDPOINT << "Attempting to process undecryptable packet";
+ QuicEncryptedPacket* packet = undecryptable_packets_.front();
+ if (!framer_.ProcessPacket(*packet) &&
+ framer_.error() == QUIC_DECRYPTION_FAILURE) {
+ DVLOG(1) << ENDPOINT << "Unable to process undecryptable packet...";
+ break;
+ }
+ DVLOG(1) << ENDPOINT << "Processed undecryptable packet!";
+ ++stats_.packets_processed;
+ delete packet;
+ undecryptable_packets_.pop_front();
+ }
+
+ // Once forward secure encryption is in use, there will be no
+ // new keys installed and hence any undecryptable packets will
+ // never be able to be decrypted.
+ if (encryption_level_ == ENCRYPTION_FORWARD_SECURE) {
+ if (debug_visitor_ != nullptr) {
+ // TODO(rtenneti): perhaps more efficient to pass the number of
+ // undecryptable packets as the argument to OnUndecryptablePacket so that
+ // we just need to call OnUndecryptablePacket once?
+ for (size_t i = 0; i < undecryptable_packets_.size(); ++i) {
+ debug_visitor_->OnUndecryptablePacket();
+ }
+ }
+ base::STLDeleteElements(&undecryptable_packets_);
+ }
+}
+
+void QuicConnection::CloseConnection(
+ QuicErrorCode error,
+ const string& error_details,
+ ConnectionCloseBehavior connection_close_behavior) {
+ DCHECK(!error_details.empty());
+ if (!connected_) {
+ DVLOG(1) << "Connection is already closed.";
+ return;
+ }
+
+ DVLOG(1) << ENDPOINT << "Closing connection: " << connection_id()
+ << ", with error: " << QuicUtils::ErrorToString(error) << " ("
+ << error << "), and details: " << error_details;
+
+ if (connection_close_behavior ==
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET) {
+ SendConnectionClosePacket(error, error_details, SEND_ACK);
+ } else if (connection_close_behavior ==
+ ConnectionCloseBehavior::
+ SEND_CONNECTION_CLOSE_PACKET_WITH_NO_ACK) {
+ SendConnectionClosePacket(error, error_details, NO_ACK);
+ }
+
+ TearDownLocalConnectionState(error, error_details,
+ ConnectionCloseSource::FROM_SELF);
+}
+
+void QuicConnection::SendConnectionClosePacket(QuicErrorCode error,
+ const string& details,
+ AckBundling ack_mode) {
+ DVLOG(1) << ENDPOINT << "Sending connection close packet.";
+ ClearQueuedPackets();
+ ScopedPacketBundler ack_bundler(this, ack_mode);
+ QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame();
+ frame->error_code = error;
+ frame->error_details = details;
+ packet_generator_.AddControlFrame(QuicFrame(frame));
+ packet_generator_.FlushAllQueuedFrames();
+}
+
+void QuicConnection::TearDownLocalConnectionState(
+ QuicErrorCode error,
+ const string& error_details,
+ ConnectionCloseSource source) {
+ if (!connected_) {
+ DVLOG(1) << "Connection is already closed.";
+ return;
+ }
+ connected_ = false;
+ DCHECK(visitor_ != nullptr);
+ // TODO(rtenneti): crbug.com/546668. A temporary fix. Added a check for null
+ // |visitor_| to fix crash bug. Delete |visitor_| check and histogram after
+ // fix is merged.
+ if (visitor_ != nullptr) {
+ visitor_->OnConnectionClosed(error, error_details, source);
+ } else {
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicCloseConnection.NullVisitor", true);
+ }
+ if (debug_visitor_ != nullptr) {
+ debug_visitor_->OnConnectionClosed(error, error_details, source);
+ }
+ // Cancel the alarms so they don't trigger any action now that the
+ // connection is closed.
+ CancelAllAlarms();
+}
+
+void QuicConnection::CancelAllAlarms() {
+ ack_alarm_->Cancel();
+ ping_alarm_->Cancel();
+ resume_writes_alarm_->Cancel();
+ retransmission_alarm_->Cancel();
+ send_alarm_->Cancel();
+ timeout_alarm_->Cancel();
+ mtu_discovery_alarm_->Cancel();
+}
+
+void QuicConnection::SendGoAway(QuicErrorCode error,
+ QuicStreamId last_good_stream_id,
+ const string& reason) {
+ if (goaway_sent_) {
+ return;
+ }
+ goaway_sent_ = true;
+
+ DVLOG(1) << ENDPOINT << "Going away with error "
+ << QuicUtils::ErrorToString(error) << " (" << error << ")";
+
+ // Opportunistically bundle an ack with this outgoing packet.
+ ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
+ packet_generator_.AddControlFrame(
+ QuicFrame(new QuicGoAwayFrame(error, last_good_stream_id, reason)));
+}
+
+QuicByteCount QuicConnection::max_packet_length() const {
+ return packet_generator_.GetCurrentMaxPacketLength();
+}
+
+void QuicConnection::SetMaxPacketLength(QuicByteCount length) {
+ long_term_mtu_ = length;
+ packet_generator_.SetMaxPacketLength(GetLimitedMaxPacketSize(length));
+}
+
+bool QuicConnection::HasQueuedData() const {
+ return pending_version_negotiation_packet_ || !queued_packets_.empty() ||
+ packet_generator_.HasQueuedFrames();
+}
+
+void QuicConnection::EnableSavingCryptoPackets() {
+ save_crypto_packets_as_termination_packets_ = true;
+}
+
+bool QuicConnection::CanWriteStreamData() {
+ // Don't write stream data if there are negotiation or queued data packets
+ // to send. Otherwise, continue and bundle as many frames as possible.
+ if (pending_version_negotiation_packet_ || !queued_packets_.empty()) {
+ return false;
+ }
+
+ IsHandshake pending_handshake =
+ visitor_->HasPendingHandshake() ? IS_HANDSHAKE : NOT_HANDSHAKE;
+ // Sending queued packets may have caused the socket to become write blocked,
+ // or the congestion manager to prohibit sending. If we've sent everything
+ // we had queued and we're still not blocked, let the visitor know it can
+ // write more.
+ return ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, pending_handshake);
+}
+
+void QuicConnection::SetNetworkTimeouts(QuicTime::Delta handshake_timeout,
+ QuicTime::Delta idle_timeout) {
+ QUIC_BUG_IF(idle_timeout > handshake_timeout)
+ << "idle_timeout:" << idle_timeout.ToMilliseconds()
+ << " handshake_timeout:" << handshake_timeout.ToMilliseconds();
+ // Adjust the idle timeout on client and server to prevent clients from
+ // sending requests to servers which have already closed the connection.
+ if (perspective_ == Perspective::IS_SERVER) {
+ idle_timeout = idle_timeout + QuicTime::Delta::FromSeconds(3);
+ } else if (idle_timeout > QuicTime::Delta::FromSeconds(1)) {
+ idle_timeout = idle_timeout - QuicTime::Delta::FromSeconds(1);
+ }
+ handshake_timeout_ = handshake_timeout;
+ idle_network_timeout_ = idle_timeout;
+
+ SetTimeoutAlarm();
+}
+
+void QuicConnection::CheckForTimeout() {
+ QuicTime now = clock_->ApproximateNow();
+ QuicTime time_of_last_packet =
+ max(time_of_last_received_packet_, last_send_for_timeout_);
+
+ // |delta| can be < 0 as |now| is approximate time but |time_of_last_packet|
+ // is accurate time. However, this should not change the behavior of
+ // timeout handling.
+ QuicTime::Delta idle_duration = now - time_of_last_packet;
+ DVLOG(1) << ENDPOINT << "last packet "
+ << time_of_last_packet.ToDebuggingValue()
+ << " now:" << now.ToDebuggingValue()
+ << " idle_duration:" << idle_duration.ToMicroseconds()
+ << " idle_network_timeout: "
+ << idle_network_timeout_.ToMicroseconds();
+ if (idle_duration >= idle_network_timeout_) {
+ const string error_details = "No recent network activity.";
+ DVLOG(1) << ENDPOINT << error_details;
+ CloseConnection(QUIC_NETWORK_IDLE_TIMEOUT, error_details,
+ idle_timeout_connection_close_behavior_);
+ return;
+ }
+
+ if (!handshake_timeout_.IsInfinite()) {
+ QuicTime::Delta connected_duration = now - stats_.connection_creation_time;
+ DVLOG(1) << ENDPOINT
+ << "connection time: " << connected_duration.ToMicroseconds()
+ << " handshake timeout: " << handshake_timeout_.ToMicroseconds();
+ if (connected_duration >= handshake_timeout_) {
+ const string error_details = "Handshake timeout expired.";
+ DVLOG(1) << ENDPOINT << error_details;
+ CloseConnection(QUIC_HANDSHAKE_TIMEOUT, error_details,
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+ }
+
+ SetTimeoutAlarm();
+}
+
+void QuicConnection::SetTimeoutAlarm() {
+ QuicTime time_of_last_packet =
+ max(time_of_last_received_packet_, time_of_last_sent_new_packet_);
+ time_of_last_packet =
+ max(time_of_last_received_packet_, last_send_for_timeout_);
+
+ QuicTime deadline = time_of_last_packet + idle_network_timeout_;
+ if (!handshake_timeout_.IsInfinite()) {
+ deadline =
+ min(deadline, stats_.connection_creation_time + handshake_timeout_);
+ }
+
+ timeout_alarm_->Update(deadline, QuicTime::Delta::Zero());
+}
+
+void QuicConnection::SetPingAlarm() {
+ if (perspective_ == Perspective::IS_SERVER) {
+ // Only clients send pings.
+ return;
+ }
+ if (!visitor_->HasOpenDynamicStreams()) {
+ ping_alarm_->Cancel();
+ // Don't send a ping unless there are open streams.
+ return;
+ }
+ ping_alarm_->Update(clock_->ApproximateNow() + ping_timeout_,
+ QuicTime::Delta::FromSeconds(1));
+}
+
+void QuicConnection::SetRetransmissionAlarm() {
+ if (delay_setting_retransmission_alarm_) {
+ pending_retransmission_alarm_ = true;
+ return;
+ }
+ QuicTime retransmission_time = sent_packet_manager_->GetRetransmissionTime();
+ retransmission_alarm_->Update(retransmission_time,
+ QuicTime::Delta::FromMilliseconds(1));
+}
+
+void QuicConnection::MaybeSetMtuAlarm() {
+ // Do not set the alarm if the target size is less than the current size.
+ // This covers the case when |mtu_discovery_target_| is at its default value,
+ // zero.
+ if (mtu_discovery_target_ <= max_packet_length()) {
+ return;
+ }
+
+ if (mtu_probe_count_ >= kMtuDiscoveryAttempts) {
+ return;
+ }
+
+ if (mtu_discovery_alarm_->IsSet()) {
+ return;
+ }
+
+ if (packet_number_of_last_sent_packet_ >= next_mtu_probe_at_) {
+ // Use an alarm to send the MTU probe to ensure that no ScopedPacketBundlers
+ // are active.
+ mtu_discovery_alarm_->Set(clock_->ApproximateNow());
+ }
+}
+
+QuicConnection::ScopedPacketBundler::ScopedPacketBundler(
+ QuicConnection* connection,
+ AckBundling ack_mode)
+ : connection_(connection),
+ already_in_batch_mode_(connection != nullptr &&
+ connection->packet_generator_.InBatchMode()) {
+ if (connection_ == nullptr) {
+ return;
+ }
+ // Move generator into batch mode. If caller wants us to include an ack,
+ // check the delayed-ack timer to see if there's ack info to be sent.
+ if (!already_in_batch_mode_) {
+ DVLOG(2) << "Entering Batch Mode.";
+ connection_->packet_generator_.StartBatchOperations();
+ }
+ if (ShouldSendAck(ack_mode)) {
+ DVLOG(1) << "Bundling ack with outgoing packet.";
+ DCHECK(ack_mode == SEND_ACK || connection_->ack_frame_updated() ||
+ connection_->stop_waiting_count_ > 1);
+ connection_->SendAck();
+ }
+}
+
+bool QuicConnection::ScopedPacketBundler::ShouldSendAck(
+ AckBundling ack_mode) const {
+ switch (ack_mode) {
+ case SEND_ACK:
+ return true;
+ case SEND_ACK_IF_QUEUED:
+ return connection_->ack_queued();
+ case SEND_ACK_IF_PENDING:
+ return connection_->ack_alarm_->IsSet() ||
+ connection_->stop_waiting_count_ > 1;
+ case NO_ACK:
+ return false;
+ default:
+ QUIC_BUG << "Unsupported ack_mode.";
+ return true;
+ }
+}
+
+QuicConnection::ScopedPacketBundler::~ScopedPacketBundler() {
+ if (connection_ == nullptr) {
+ return;
+ }
+ // If we changed the generator's batch state, restore original batch state.
+ if (!already_in_batch_mode_) {
+ DVLOG(2) << "Leaving Batch Mode.";
+ connection_->packet_generator_.FinishBatchOperations();
+
+ // Once all transmissions are done, check if there is any outstanding data
+ // to send and notify the congestion controller if not.
+ //
+ // Note that this means that the application limited check will happen as
+ // soon as the last bundler gets destroyed, which is typically after a
+ // single stream write is finished. This means that if all the data from a
+ // single write goes through the connection, the application-limited signal
+ // will fire even if the caller does a write operation immediately after.
+ // There are two important approaches to remedy this situation:
+ // (1) Instantiate ScopedPacketBundler before performing multiple subsequent
+ // writes, thus deferring this check until all writes are done.
+ // (2) Write data in chunks sufficiently large so that they cause the
+ // connection to be limited by the congestion control. Typically, this
+ // would mean writing chunks larger than the product of the current
+ // pacing rate and the pacer granularity. So, for instance, if the
+ // pacing rate of the connection is 1 Gbps, and the pacer granularity is
+ // 1 ms, the caller should send at least 125k bytes in order to not
+ // be marked as application-limited.
+ connection_->CheckIfApplicationLimited();
+ }
+ DCHECK_EQ(already_in_batch_mode_,
+ connection_->packet_generator_.InBatchMode());
+}
+
+QuicConnection::ScopedRetransmissionScheduler::ScopedRetransmissionScheduler(
+ QuicConnection* connection)
+ : connection_(connection),
+ already_delayed_(connection_->delay_setting_retransmission_alarm_) {
+ connection_->delay_setting_retransmission_alarm_ = true;
+}
+
+QuicConnection::ScopedRetransmissionScheduler::
+ ~ScopedRetransmissionScheduler() {
+ if (already_delayed_) {
+ return;
+ }
+ connection_->delay_setting_retransmission_alarm_ = false;
+ if (connection_->pending_retransmission_alarm_) {
+ connection_->SetRetransmissionAlarm();
+ connection_->pending_retransmission_alarm_ = false;
+ }
+}
+
+HasRetransmittableData QuicConnection::IsRetransmittable(
+ const SerializedPacket& packet) {
+ // Retransmitted packets retransmittable frames are owned by the unacked
+ // packet map, but are not present in the serialized packet.
+ if (packet.transmission_type != NOT_RETRANSMISSION ||
+ !packet.retransmittable_frames.empty()) {
+ return HAS_RETRANSMITTABLE_DATA;
+ } else {
+ return NO_RETRANSMITTABLE_DATA;
+ }
+}
+
+bool QuicConnection::IsTerminationPacket(const SerializedPacket& packet) {
+ if (packet.retransmittable_frames.empty()) {
+ return false;
+ }
+ for (const QuicFrame& frame : packet.retransmittable_frames) {
+ if (frame.type == CONNECTION_CLOSE_FRAME) {
+ return true;
+ }
+ if (save_crypto_packets_as_termination_packets_ &&
+ frame.type == STREAM_FRAME &&
+ frame.stream_frame->stream_id == kCryptoStreamId) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void QuicConnection::SetMtuDiscoveryTarget(QuicByteCount target) {
+ mtu_discovery_target_ = GetLimitedMaxPacketSize(target);
+}
+
+QuicByteCount QuicConnection::GetLimitedMaxPacketSize(
+ QuicByteCount suggested_max_packet_size) {
+ if (peer_address_.address().empty()) {
+ QUIC_BUG << "Attempted to use a connection without a valid peer address";
+ return suggested_max_packet_size;
+ }
+
+ const QuicByteCount writer_limit = writer_->GetMaxPacketSize(peer_address());
+
+ return std::min({suggested_max_packet_size, writer_limit, kMaxPacketSize,
+ largest_packet_size_supported_});
+}
+
+void QuicConnection::SendMtuDiscoveryPacket(QuicByteCount target_mtu) {
+ // Currently, this limit is ensured by the caller.
+ DCHECK_EQ(target_mtu, GetLimitedMaxPacketSize(target_mtu));
+
+ // Send the probe.
+ packet_generator_.GenerateMtuDiscoveryPacket(target_mtu, nullptr);
+}
+
+void QuicConnection::DiscoverMtu() {
+ DCHECK(!mtu_discovery_alarm_->IsSet());
+
+ // Check if the MTU has been already increased.
+ if (mtu_discovery_target_ <= max_packet_length()) {
+ return;
+ }
+
+ // Calculate the packet number of the next probe *before* sending the current
+ // one. Otherwise, when SendMtuDiscoveryPacket() is called,
+ // MaybeSetMtuAlarm() will not realize that the probe has been just sent, and
+ // will reschedule this probe again.
+ packets_between_mtu_probes_ *= 2;
+ next_mtu_probe_at_ =
+ packet_number_of_last_sent_packet_ + packets_between_mtu_probes_ + 1;
+ ++mtu_probe_count_;
+
+ DVLOG(2) << "Sending a path MTU discovery packet #" << mtu_probe_count_;
+ SendMtuDiscoveryPacket(mtu_discovery_target_);
+
+ DCHECK(!mtu_discovery_alarm_->IsSet());
+}
+
+void QuicConnection::OnPeerMigrationValidated(QuicPathId path_id) {
+ if (active_peer_migration_type_ == NO_CHANGE) {
+ QUIC_BUG << "No migration underway.";
+ return;
+ }
+ highest_packet_sent_before_peer_migration_ = 0;
+ active_peer_migration_type_ = NO_CHANGE;
+}
+
+// TODO(jri): Modify method to start migration whenever a new IP address is seen
+// from a packet with sequence number > the one that triggered the previous
+// migration. This should happen even if a migration is underway, since the
+// most recent migration is the one that we should pay attention to.
+void QuicConnection::StartPeerMigration(
+ QuicPathId path_id,
+ PeerAddressChangeType peer_migration_type) {
+ // TODO(fayang): Currently, all peer address change type are allowed. Need to
+ // add a method ShouldAllowPeerAddressChange(PeerAddressChangeType type) to
+ // determine whether |type| is allowed.
+ if (active_peer_migration_type_ != NO_CHANGE ||
+ peer_migration_type == NO_CHANGE) {
+ QUIC_BUG << "Migration underway or no new migration started.";
+ return;
+ }
+ DVLOG(1) << ENDPOINT << "Peer's ip:port changed from "
+ << peer_address_.ToString() << " to "
+ << last_packet_source_address_.ToString()
+ << ", migrating connection.";
+
+ highest_packet_sent_before_peer_migration_ =
+ packet_number_of_last_sent_packet_;
+ peer_address_ = last_packet_source_address_;
+ active_peer_migration_type_ = peer_migration_type;
+
+ // TODO(jri): Move these calls to OnPeerMigrationValidated. Rename
+ // OnConnectionMigration methods to OnPeerMigration.
+ visitor_->OnConnectionMigration(peer_migration_type);
+ sent_packet_manager_->OnConnectionMigration(path_id, peer_migration_type);
+}
+
+void QuicConnection::OnPathClosed(QuicPathId path_id) {
+ // Stop receiving packets on this path.
+ framer_.OnPathClosed(path_id);
+}
+
+bool QuicConnection::ack_frame_updated() const {
+ return received_packet_manager_.ack_frame_updated();
+}
+
+StringPiece QuicConnection::GetCurrentPacket() {
+ if (current_packet_data_ == nullptr) {
+ return StringPiece();
+ }
+ return StringPiece(current_packet_data_, last_size_);
+}
+
+bool QuicConnection::MaybeConsiderAsMemoryCorruption(
+ const QuicStreamFrame& frame) {
+ if (frame.stream_id == kCryptoStreamId ||
+ last_decrypted_packet_level_ != ENCRYPTION_NONE) {
+ return false;
+ }
+
+ if (perspective_ == Perspective::IS_SERVER &&
+ frame.data_length >= sizeof(kCHLO) &&
+ strncmp(frame.data_buffer, reinterpret_cast<const char*>(&kCHLO),
+ sizeof(kCHLO)) == 0) {
+ return true;
+ }
+
+ if (perspective_ == Perspective::IS_CLIENT &&
+ frame.data_length >= sizeof(kREJ) &&
+ strncmp(frame.data_buffer, reinterpret_cast<const char*>(&kREJ),
+ sizeof(kREJ)) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+// Uses a 25ms delayed ack timer. Also helps with better signaling
+// in low-bandwidth (< ~384 kbps), where an ack is sent per packet.
+// Ensures that the Delayed Ack timer is always set to a value lesser
+// than the retransmission timer's minimum value (MinRTO). We want the
+// delayed ack to get back to the QUIC peer before the sender's
+// retransmission timer triggers. Since we do not know the
+// reverse-path one-way delay, we assume equal delays for forward and
+// reverse paths, and ensure that the timer is set to less than half
+// of the MinRTO.
+// There may be a value in making this delay adaptive with the help of
+// the sender and a signaling mechanism -- if the sender uses a
+// different MinRTO, we may get spurious retransmissions. May not have
+// any benefits, but if the delayed ack becomes a significant source
+// of (likely, tail) latency, then consider such a mechanism.
+const QuicTime::Delta QuicConnection::DelayedAckTime() {
+ return QuicTime::Delta::FromMilliseconds(
+ min(kMaxDelayedAckTimeMs, kMinRetransmissionTimeMs / 2));
+}
+
+void QuicConnection::CheckIfApplicationLimited() {
+ if (queued_packets_.empty() &&
+ !sent_packet_manager_->HasPendingRetransmissions() &&
+ !visitor_->WillingAndAbleToWrite()) {
+ sent_packet_manager_->OnApplicationLimited();
+ }
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_connection.h b/chromium/net/quic/core/quic_connection.h
new file mode 100644
index 00000000000..5143c05b053
--- /dev/null
+++ b/chromium/net/quic/core/quic_connection.h
@@ -0,0 +1,1121 @@
+// 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.
+//
+// The entity that handles framing writes for a Quic client or server.
+// Each QuicSession will have a connection associated with it.
+//
+// On the server side, the Dispatcher handles the raw reads, and hands off
+// packets via ProcessUdpPacket for framing and processing.
+//
+// On the client side, the Connection handles the raw reads, as well as the
+// processing.
+//
+// Note: this class is not thread-safe.
+
+#ifndef NET_QUIC_QUIC_CONNECTION_H_
+#define NET_QUIC_QUIC_CONNECTION_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <deque>
+#include <list>
+#include <map>
+#include <memory>
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/ip_address.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/quic_decrypter.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"
+#include "net/quic/core/quic_connection_stats.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_multipath_sent_packet_manager.h"
+#include "net/quic/core/quic_one_block_arena.h"
+#include "net/quic/core/quic_packet_creator.h"
+#include "net/quic/core/quic_packet_generator.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_received_packet_manager.h"
+#include "net/quic/core/quic_sent_entropy_manager.h"
+#include "net/quic/core/quic_sent_packet_manager_interface.h"
+#include "net/quic/core/quic_time.h"
+#include "net/quic/core/quic_types.h"
+
+namespace net {
+
+class QuicClock;
+class QuicConfig;
+class QuicConnection;
+class QuicEncrypter;
+class QuicRandom;
+
+namespace test {
+class PacketSavingConnection;
+class QuicConnectionPeer;
+} // namespace test
+
+// The initial number of packets between MTU probes. After each attempt the
+// number is doubled.
+const QuicPacketCount kPacketsBetweenMtuProbesBase = 100;
+
+// The number of MTU probes that get sent before giving up.
+const size_t kMtuDiscoveryAttempts = 3;
+
+// Ensure that exponential back-off does not result in an integer overflow.
+// The number of packets can be potentially capped, but that is not useful at
+// current kMtuDiscoveryAttempts value, and hence is not implemented at present.
+static_assert(kMtuDiscoveryAttempts + 8 < 8 * sizeof(QuicPacketNumber),
+ "The number of MTU discovery attempts is too high");
+static_assert(kPacketsBetweenMtuProbesBase < (1 << 8),
+ "The initial number of packets between MTU probes is too high");
+
+// The incresed packet size targeted when doing path MTU discovery.
+const QuicByteCount kMtuDiscoveryTargetPacketSizeHigh = 1450;
+const QuicByteCount kMtuDiscoveryTargetPacketSizeLow = 1430;
+
+static_assert(kMtuDiscoveryTargetPacketSizeLow <= kMaxPacketSize,
+ "MTU discovery target is too large");
+static_assert(kMtuDiscoveryTargetPacketSizeHigh <= kMaxPacketSize,
+ "MTU discovery target is too large");
+
+static_assert(kMtuDiscoveryTargetPacketSizeLow > kDefaultMaxPacketSize,
+ "MTU discovery target does not exceed the default packet size");
+static_assert(kMtuDiscoveryTargetPacketSizeHigh > kDefaultMaxPacketSize,
+ "MTU discovery target does not exceed the default packet size");
+
+// Class that receives callbacks from the connection when frames are received
+// and when other interesting events happen.
+class NET_EXPORT_PRIVATE QuicConnectionVisitorInterface {
+ public:
+ virtual ~QuicConnectionVisitorInterface() {}
+
+ // A simple visitor interface for dealing with a data frame.
+ virtual void OnStreamFrame(const QuicStreamFrame& frame) = 0;
+
+ // The session should process the WINDOW_UPDATE frame, adjusting both stream
+ // and connection level flow control windows.
+ virtual void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) = 0;
+
+ // A BLOCKED frame indicates the peer is flow control blocked
+ // on a specified stream.
+ virtual void OnBlockedFrame(const QuicBlockedFrame& frame) = 0;
+
+ // Called when the stream is reset by the peer.
+ virtual void OnRstStream(const QuicRstStreamFrame& frame) = 0;
+
+ // Called when the connection is going away according to the peer.
+ virtual void OnGoAway(const QuicGoAwayFrame& frame) = 0;
+
+ // Called when the connection is closed either locally by the framer, or
+ // remotely by the peer.
+ virtual void OnConnectionClosed(QuicErrorCode error,
+ const std::string& error_details,
+ ConnectionCloseSource source) = 0;
+
+ // Called when the connection failed to write because the socket was blocked.
+ virtual void OnWriteBlocked() = 0;
+
+ // Called once a specific QUIC version is agreed by both endpoints.
+ virtual void OnSuccessfulVersionNegotiation(const QuicVersion& version) = 0;
+
+ // Called when a blocked socket becomes writable.
+ virtual void OnCanWrite() = 0;
+
+ // Called when the connection experiences a change in congestion window.
+ virtual void OnCongestionWindowChange(QuicTime now) = 0;
+
+ // Called when the connection receives a packet from a migrated client.
+ virtual void OnConnectionMigration(PeerAddressChangeType type) = 0;
+
+ // Called when the peer seems unreachable over the current path.
+ virtual void OnPathDegrading() = 0;
+
+ // Called after OnStreamFrame, OnRstStream, OnGoAway, OnWindowUpdateFrame,
+ // OnBlockedFrame, and OnCanWrite to allow post-processing once the work has
+ // been done.
+ virtual void PostProcessAfterData() = 0;
+
+ // Called to ask if the visitor wants to schedule write resumption as it both
+ // has pending data to write, and is able to write (e.g. based on flow control
+ // limits).
+ // Writes may be pending because they were write-blocked, congestion-throttled
+ // or yielded to other connections.
+ virtual bool WillingAndAbleToWrite() const = 0;
+
+ // Called to ask if any handshake messages are pending in this visitor.
+ virtual bool HasPendingHandshake() const = 0;
+
+ // Called to ask if any streams are open in this visitor, excluding the
+ // reserved crypto and headers stream.
+ virtual bool HasOpenDynamicStreams() const = 0;
+};
+
+// Interface which gets callbacks from the QuicConnection at interesting
+// points. Implementations must not mutate the state of the connection
+// as a result of these callbacks.
+class NET_EXPORT_PRIVATE QuicConnectionDebugVisitor
+ : public QuicSentPacketManagerInterface::DebugDelegate {
+ public:
+ ~QuicConnectionDebugVisitor() override {}
+
+ // Called when a packet has been sent.
+ virtual void OnPacketSent(const SerializedPacket& serialized_packet,
+ QuicPathId original_path_id,
+ QuicPacketNumber original_packet_number,
+ TransmissionType transmission_type,
+ QuicTime sent_time) {}
+
+ // Called when an PING frame has been sent.
+ virtual void OnPingSent() {}
+
+ // Called when a packet has been received, but before it is
+ // validated or parsed.
+ virtual void OnPacketReceived(const IPEndPoint& self_address,
+ const IPEndPoint& peer_address,
+ const QuicEncryptedPacket& packet) {}
+
+ // Called when the unauthenticated portion of the header has been parsed.
+ virtual void OnUnauthenticatedHeader(const QuicPacketHeader& header) {}
+
+ // Called when a packet is received with a connection id that does not
+ // match the ID of this connection.
+ virtual void OnIncorrectConnectionId(QuicConnectionId connection_id) {}
+
+ // Called when an undecryptable packet has been received.
+ virtual void OnUndecryptablePacket() {}
+
+ // Called when a duplicate packet has been received.
+ virtual void OnDuplicatePacket(QuicPacketNumber packet_number) {}
+
+ // Called when the protocol version on the received packet doensn't match
+ // current protocol version of the connection.
+ virtual void OnProtocolVersionMismatch(QuicVersion version) {}
+
+ // Called when the complete header of a packet has been parsed.
+ virtual void OnPacketHeader(const QuicPacketHeader& header) {}
+
+ // Called when a StreamFrame has been parsed.
+ virtual void OnStreamFrame(const QuicStreamFrame& frame) {}
+
+ // Called when a AckFrame has been parsed.
+ virtual void OnAckFrame(const QuicAckFrame& frame) {}
+
+ // Called when a StopWaitingFrame has been parsed.
+ virtual void OnStopWaitingFrame(const QuicStopWaitingFrame& frame) {}
+
+ // Called when a QuicPaddingFrame has been parsed.
+ virtual void OnPaddingFrame(const QuicPaddingFrame& frame) {}
+
+ // Called when a Ping has been parsed.
+ virtual void OnPingFrame(const QuicPingFrame& frame) {}
+
+ // Called when a GoAway has been parsed.
+ virtual void OnGoAwayFrame(const QuicGoAwayFrame& frame) {}
+
+ // Called when a RstStreamFrame has been parsed.
+ virtual void OnRstStreamFrame(const QuicRstStreamFrame& frame) {}
+
+ // Called when a ConnectionCloseFrame has been parsed.
+ virtual void OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) {}
+
+ // Called when a WindowUpdate has been parsed.
+ virtual void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {}
+
+ // Called when a BlockedFrame has been parsed.
+ virtual void OnBlockedFrame(const QuicBlockedFrame& frame) {}
+
+ // Called when a PathCloseFrame has been parsed.
+ virtual void OnPathCloseFrame(const QuicPathCloseFrame& frame) {}
+
+ // Called when a public reset packet has been received.
+ virtual void OnPublicResetPacket(const QuicPublicResetPacket& packet) {}
+
+ // Called when a version negotiation packet has been received.
+ virtual void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) {}
+
+ // Called when the connection is closed.
+ virtual void OnConnectionClosed(QuicErrorCode error,
+ const std::string& error_details,
+ ConnectionCloseSource source) {}
+
+ // Called when the version negotiation is successful.
+ virtual void OnSuccessfulVersionNegotiation(const QuicVersion& version) {}
+
+ // Called when a CachedNetworkParameters is sent to the client.
+ virtual void OnSendConnectionState(
+ const CachedNetworkParameters& cached_network_params) {}
+
+ // Called when a CachedNetworkParameters are recieved from the client.
+ virtual void OnReceiveConnectionState(
+ const CachedNetworkParameters& cached_network_params) {}
+
+ // Called when the connection parameters are set from the supplied
+ // |config|.
+ virtual void OnSetFromConfig(const QuicConfig& config) {}
+
+ // Called when RTT may have changed, including when an RTT is read from
+ // the config.
+ virtual void OnRttChanged(QuicTime::Delta rtt) const {}
+};
+
+// QuicConnections currently use around 1KB of polymorphic types which would
+// ordinarily be on the heap. Instead, store them inline in an arena.
+using QuicConnectionArena = QuicOneBlockArena<1024>;
+
+class NET_EXPORT_PRIVATE QuicConnectionHelperInterface {
+ public:
+ virtual ~QuicConnectionHelperInterface() {}
+
+ // Returns a QuicClock to be used for all time related functions.
+ virtual const QuicClock* GetClock() const = 0;
+
+ // Returns a QuicRandom to be used for all random number related functions.
+ virtual QuicRandom* GetRandomGenerator() = 0;
+
+ // Returns a QuicBufferAllocator to be used for all stream frame buffers.
+ virtual QuicBufferAllocator* GetBufferAllocator() = 0;
+};
+
+class NET_EXPORT_PRIVATE QuicConnection
+ : public QuicFramerVisitorInterface,
+ public QuicBlockedWriterInterface,
+ public QuicPacketGenerator::DelegateInterface,
+ public QuicSentPacketManagerInterface::NetworkChangeVisitor {
+ public:
+ enum AckBundling {
+ // Send an ack if it's already queued in the connection.
+ SEND_ACK_IF_QUEUED,
+ // Always send an ack.
+ SEND_ACK,
+ // Bundle an ack with outgoing data.
+ SEND_ACK_IF_PENDING,
+ // Do not send ack.
+ NO_ACK,
+ };
+
+ enum AckMode { TCP_ACKING, ACK_DECIMATION, ACK_DECIMATION_WITH_REORDERING };
+
+ // Constructs a new QuicConnection for |connection_id| and |address| using
+ // |writer| to write packets. |owns_writer| specifies whether the connection
+ // takes ownership of |writer|. |helper| must outlive this connection.
+ QuicConnection(QuicConnectionId connection_id,
+ IPEndPoint address,
+ QuicConnectionHelperInterface* helper,
+ QuicAlarmFactory* alarm_factory,
+ QuicPacketWriter* writer,
+ bool owns_writer,
+ Perspective perspective,
+ const QuicVersionVector& supported_versions);
+ ~QuicConnection() override;
+
+ // Sets connection parameters from the supplied |config|.
+ void SetFromConfig(const QuicConfig& config);
+
+ // Called by the session when sending connection state to the client.
+ virtual void OnSendConnectionState(
+ const CachedNetworkParameters& cached_network_params);
+
+ // Called by the session when receiving connection state from the client.
+ virtual void OnReceiveConnectionState(
+ const CachedNetworkParameters& cached_network_params);
+
+ // Called by the Session when the client has provided CachedNetworkParameters.
+ virtual void ResumeConnectionState(
+ const CachedNetworkParameters& cached_network_params,
+ bool max_bandwidth_resumption);
+
+ // Called by the Session when a max pacing rate for the connection is needed.
+ virtual void SetMaxPacingRate(QuicBandwidth max_pacing_rate);
+
+ // Sets the number of active streams on the connection for congestion control.
+ void SetNumOpenStreams(size_t num_streams);
+
+ // Send the data in |data| to the peer in as few packets as possible.
+ // Returns a pair with the number of bytes consumed from data, and a boolean
+ // indicating if the fin bit was consumed. This does not indicate the data
+ // has been sent on the wire: it may have been turned into a packet and queued
+ // if the socket was unexpectedly blocked.
+ // If |listener| is provided, then it will be informed once ACKs have been
+ // received for all the packets written in this call.
+ // The |listener| is not owned by the QuicConnection and must outlive it.
+ virtual QuicConsumedData SendStreamData(QuicStreamId id,
+ QuicIOVector iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* listener);
+
+ // Send a RST_STREAM frame to the peer.
+ virtual void SendRstStream(QuicStreamId id,
+ QuicRstStreamErrorCode error,
+ QuicStreamOffset bytes_written);
+
+ // Send a BLOCKED frame to the peer.
+ virtual void SendBlocked(QuicStreamId id);
+
+ // Send a WINDOW_UPDATE frame to the peer.
+ virtual void SendWindowUpdate(QuicStreamId id, QuicStreamOffset byte_offset);
+
+ // Send a PATH_CLOSE frame to the peer.
+ virtual void SendPathClose(QuicPathId path_id);
+
+ // Closes the connection.
+ // |connection_close_behavior| determines whether or not a connection close
+ // packet is sent to the peer.
+ virtual void CloseConnection(
+ QuicErrorCode error,
+ const std::string& details,
+ ConnectionCloseBehavior connection_close_behavior);
+
+ // Sends a GOAWAY frame. Does nothing if a GOAWAY frame has already been sent.
+ virtual void SendGoAway(QuicErrorCode error,
+ QuicStreamId last_good_stream_id,
+ const std::string& reason);
+
+ // Returns statistics tracked for this connection.
+ const QuicConnectionStats& GetStats();
+
+ // Processes an incoming UDP packet (consisting of a QuicEncryptedPacket) from
+ // the peer.
+ // In a client, the packet may be "stray" and have a different connection ID
+ // than that of this connection.
+ virtual void ProcessUdpPacket(const IPEndPoint& self_address,
+ const IPEndPoint& peer_address,
+ const QuicReceivedPacket& packet);
+
+ // QuicBlockedWriterInterface
+ // Called when the underlying connection becomes writable to allow queued
+ // writes to happen.
+ void OnCanWrite() override;
+
+ // Called when an error occurs while attempting to write a packet to the
+ // network.
+ void OnWriteError(int error_code);
+
+ // If the socket is not blocked, writes queued packets.
+ void WriteIfNotBlocked();
+
+ // If the socket is not blocked, writes queued packets and bundles any pending
+ // ACKs.
+ void WriteAndBundleAcksIfNotBlocked();
+
+ // Set the packet writer.
+ void SetQuicPacketWriter(QuicPacketWriter* writer, bool owns_writer) {
+ DCHECK(writer != nullptr);
+ if (writer_ != nullptr && owns_writer_) {
+ delete writer_;
+ }
+ writer_ = writer;
+ owns_writer_ = owns_writer;
+ }
+
+ // Set self address.
+ void SetSelfAddress(IPEndPoint address) { self_address_ = address; }
+
+ // The version of the protocol this connection is using.
+ QuicVersion version() const { return framer_.version(); }
+
+ // The versions of the protocol that this connection supports.
+ const QuicVersionVector& supported_versions() const {
+ return framer_.supported_versions();
+ }
+
+ // From QuicFramerVisitorInterface
+ void OnError(QuicFramer* framer) override;
+ bool OnProtocolVersionMismatch(QuicVersion received_version) override;
+ void OnPacket() override;
+ void OnPublicResetPacket(const QuicPublicResetPacket& packet) override;
+ void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) override;
+ bool OnUnauthenticatedPublicHeader(
+ const QuicPacketPublicHeader& header) override;
+ bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override;
+ void OnDecryptedPacket(EncryptionLevel level) override;
+ bool OnPacketHeader(const QuicPacketHeader& header) override;
+ bool OnStreamFrame(const QuicStreamFrame& frame) override;
+ bool OnAckFrame(const QuicAckFrame& frame) override;
+ bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override;
+ bool OnPaddingFrame(const QuicPaddingFrame& frame) override;
+ bool OnPingFrame(const QuicPingFrame& frame) override;
+ bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override;
+ bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override;
+ bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override;
+ bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
+ bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
+ bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override;
+ void OnPacketComplete() override;
+
+ // QuicConnectionCloseDelegateInterface
+ void OnUnrecoverableError(QuicErrorCode error,
+ const std::string& error_details,
+ ConnectionCloseSource source) override;
+
+ // QuicPacketGenerator::DelegateInterface
+ bool ShouldGeneratePacket(HasRetransmittableData retransmittable,
+ IsHandshake handshake) override;
+ const QuicFrame GetUpdatedAckFrame() override;
+ void PopulateStopWaitingFrame(QuicStopWaitingFrame* stop_waiting) override;
+
+ // QuicPacketCreator::DelegateInterface
+ void OnSerializedPacket(SerializedPacket* packet) override;
+
+ // QuicSentPacketManager::NetworkChangeVisitor
+ void OnCongestionChange() override;
+ void OnPathDegrading() override;
+ void OnPathMtuIncreased(QuicPacketLength packet_size) override;
+
+ // Called by the crypto stream when the handshake completes. In the server's
+ // case this is when the SHLO has been ACKed. Clients call this on receipt of
+ // the SHLO.
+ void OnHandshakeComplete();
+
+ // Accessors
+ void set_visitor(QuicConnectionVisitorInterface* visitor) {
+ visitor_ = visitor;
+ }
+ void set_debug_visitor(QuicConnectionDebugVisitor* debug_visitor) {
+ debug_visitor_ = debug_visitor;
+ sent_packet_manager_->SetDebugDelegate(debug_visitor);
+ }
+ void set_ping_timeout(QuicTime::Delta ping_timeout) {
+ ping_timeout_ = ping_timeout;
+ }
+ const QuicTime::Delta ping_timeout() { return ping_timeout_; }
+ // Used in Chromium, but not internally.
+ void set_creator_debug_delegate(QuicPacketCreator::DebugDelegate* visitor) {
+ packet_generator_.set_debug_delegate(visitor);
+ }
+ const IPEndPoint& self_address() const { return self_address_; }
+ const IPEndPoint& peer_address() const { return peer_address_; }
+ QuicConnectionId connection_id() const { return connection_id_; }
+ const QuicClock* clock() const { return clock_; }
+ QuicRandom* random_generator() const { return random_generator_; }
+ QuicByteCount max_packet_length() const;
+ void SetMaxPacketLength(QuicByteCount length);
+
+ size_t mtu_probe_count() const { return mtu_probe_count_; }
+
+ bool connected() const { return connected_; }
+
+ bool goaway_sent() const { return goaway_sent_; }
+
+ bool goaway_received() const { return goaway_received_; }
+
+ // Must only be called on client connections.
+ const QuicVersionVector& server_supported_versions() const {
+ DCHECK_EQ(Perspective::IS_CLIENT, perspective_);
+ return server_supported_versions_;
+ }
+
+ // Testing only.
+ size_t NumQueuedPackets() const { return queued_packets_.size(); }
+
+ // Once called, any sent crypto packets to be saved as the
+ // termination packet, for use with stateless rejections.
+ void EnableSavingCryptoPackets();
+
+ // Returns true if the underlying UDP socket is writable, there is
+ // no queued data and the connection is not congestion-control
+ // blocked.
+ bool CanWriteStreamData();
+
+ // Returns true if the connection has queued packets or frames.
+ bool HasQueuedData() const;
+
+ // Sets the handshake and idle state connection timeouts.
+ void SetNetworkTimeouts(QuicTime::Delta handshake_timeout,
+ QuicTime::Delta idle_timeout);
+
+ // If the connection has timed out, this will close the connection.
+ // Otherwise, it will reschedule the timeout alarm.
+ void CheckForTimeout();
+
+ // Called when the ping alarm fires. Causes a ping frame to be sent only
+ // if the retransmission alarm is not running.
+ void OnPingTimeout();
+
+ // Sends a ping frame.
+ void SendPing();
+
+ // Sets up a packet with an QuicAckFrame and sends it out.
+ void SendAck();
+
+ // Called when an RTO fires. Resets the retransmission alarm if there are
+ // remaining unacked packets.
+ void OnRetransmissionTimeout();
+
+ // Retransmits all unacked packets with retransmittable frames if
+ // |retransmission_type| is ALL_UNACKED_PACKETS, otherwise retransmits only
+ // initially encrypted packets. Used when the negotiated protocol version is
+ // different from what was initially assumed and when the initial encryption
+ // changes.
+ void RetransmitUnackedPackets(TransmissionType retransmission_type);
+
+ // Calls |sent_packet_manager_|'s NeuterUnencryptedPackets. Used when the
+ // connection becomes forward secure and hasn't received acks for all packets.
+ void NeuterUnencryptedPackets();
+
+ // Changes the encrypter used for level |level| to |encrypter|. The function
+ // takes ownership of |encrypter|.
+ void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter);
+
+ // SetNonceForPublicHeader sets the nonce that will be transmitted in the
+ // public header of each packet encrypted at the initial encryption level
+ // decrypted. This should only be called on the server side.
+ void SetDiversificationNonce(const DiversificationNonce& nonce);
+
+ // SetDefaultEncryptionLevel sets the encryption level that will be applied
+ // to new packets.
+ void SetDefaultEncryptionLevel(EncryptionLevel level);
+
+ // SetDecrypter sets the primary decrypter, replacing any that already exists,
+ // and takes ownership. If an alternative decrypter is in place then the
+ // function DCHECKs. This is intended for cases where one knows that future
+ // packets will be using the new decrypter and the previous decrypter is now
+ // obsolete. |level| indicates the encryption level of the new decrypter.
+ void SetDecrypter(EncryptionLevel level, QuicDecrypter* decrypter);
+
+ // SetAlternativeDecrypter sets a decrypter that may be used to decrypt
+ // future packets and takes ownership of it. |level| indicates the encryption
+ // level of the decrypter. If |latch_once_used| is true, then the first time
+ // that the decrypter is successful it will replace the primary decrypter.
+ // Otherwise both decrypters will remain active and the primary decrypter
+ // will be the one last used.
+ void SetAlternativeDecrypter(EncryptionLevel level,
+ QuicDecrypter* decrypter,
+ bool latch_once_used);
+
+ const QuicDecrypter* decrypter() const;
+ const QuicDecrypter* alternative_decrypter() const;
+
+ Perspective perspective() const { return perspective_; }
+
+ // Allow easy overriding of truncated connection IDs.
+ void set_can_truncate_connection_ids(bool can) {
+ can_truncate_connection_ids_ = can;
+ }
+
+ // Returns the underlying sent packet manager.
+ const QuicSentPacketManagerInterface& sent_packet_manager() const {
+ return *sent_packet_manager_;
+ }
+
+ bool CanWrite(HasRetransmittableData retransmittable);
+
+ // Stores current batch state for connection, puts the connection
+ // into batch mode, and destruction restores the stored batch state.
+ // While the bundler is in scope, any generated frames are bundled
+ // as densely as possible into packets. In addition, this bundler
+ // can be configured to ensure that an ACK frame is included in the
+ // first packet created, if there's new ack information to be sent.
+ class NET_EXPORT_PRIVATE ScopedPacketBundler {
+ public:
+ // In addition to all outgoing frames being bundled when the
+ // bundler is in scope, setting |include_ack| to true ensures that
+ // an ACK frame is opportunistically bundled with the first
+ // outgoing packet.
+ ScopedPacketBundler(QuicConnection* connection, AckBundling send_ack);
+ ~ScopedPacketBundler();
+
+ private:
+ bool ShouldSendAck(AckBundling ack_mode) const;
+
+ QuicConnection* connection_;
+ bool already_in_batch_mode_;
+ };
+
+ // Delays setting the retransmission alarm until the scope is exited.
+ // When nested, only the outermost scheduler will set the alarm, and inner
+ // ones have no effect.
+ class NET_EXPORT_PRIVATE ScopedRetransmissionScheduler {
+ public:
+ explicit ScopedRetransmissionScheduler(QuicConnection* connection);
+ ~ScopedRetransmissionScheduler();
+
+ private:
+ QuicConnection* connection_;
+ // Set to the connection's delay_setting_retransmission_alarm_ value in the
+ // constructor and when true, causes this class to do nothing.
+ const bool already_delayed_;
+ };
+
+ QuicPacketNumber packet_number_of_last_sent_packet() const {
+ return packet_number_of_last_sent_packet_;
+ }
+
+ QuicPacketWriter* writer() { return writer_; }
+ const QuicPacketWriter* writer() const { return writer_; }
+
+ // Sends an MTU discovery packet of size |target_mtu|. If the packet is
+ // acknowledged by the peer, the maximum packet size will be increased to
+ // |target_mtu|.
+ void SendMtuDiscoveryPacket(QuicByteCount target_mtu);
+
+ // Sends an MTU discovery packet of size |mtu_discovery_target_| and updates
+ // the MTU discovery alarm.
+ void DiscoverMtu();
+
+ // Return the name of the cipher of the primary decrypter of the framer.
+ const char* cipher_name() const { return framer_.decrypter()->cipher_name(); }
+ // Return the id of the cipher of the primary decrypter of the framer.
+ uint32_t cipher_id() const { return framer_.decrypter()->cipher_id(); }
+
+ std::vector<std::unique_ptr<QuicEncryptedPacket>>* termination_packets() {
+ return termination_packets_.get();
+ }
+
+ bool ack_queued() const { return ack_queued_; }
+
+ bool ack_frame_updated() const;
+
+ QuicConnectionHelperInterface* helper() { return helper_; }
+ QuicAlarmFactory* alarm_factory() { return alarm_factory_; }
+
+ base::StringPiece GetCurrentPacket();
+
+ const QuicPacketGenerator& packet_generator() const {
+ return packet_generator_;
+ }
+
+ const QuicReceivedPacketManager& received_packet_manager() const {
+ return received_packet_manager_;
+ }
+
+ EncryptionLevel encryption_level() const { return encryption_level_; }
+
+ const IPEndPoint& last_packet_source_address() const {
+ return last_packet_source_address_;
+ }
+
+ void set_largest_packet_size_supported(QuicByteCount size) {
+ largest_packet_size_supported_ = size;
+ }
+
+ protected:
+ // Calls cancel() on all the alarms owned by this connection.
+ void CancelAllAlarms();
+
+ // Send a packet to the peer, and takes ownership of the packet if the packet
+ // cannot be written immediately.
+ virtual void SendOrQueuePacket(SerializedPacket* packet);
+
+ // Called after a packet is received from a new peer address on existing
+ // |path_id| and is decrypted. Starts validation of peer's address change.
+ virtual void StartPeerMigration(QuicPathId path_id,
+ PeerAddressChangeType peer_migration_type);
+
+ // Called when a peer address migration is validated on |path_id|.
+ virtual void OnPeerMigrationValidated(QuicPathId path_id);
+
+ // 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 QuicVersionVector& available_versions);
+
+ // Returns the current per-packet options for the connection.
+ PerPacketOptions* per_packet_options() { return per_packet_options_; }
+ // Sets the current per-packet options for the connection. The QuicConnection
+ // does not take ownership of |options|; |options| must live for as long as
+ // the QuicConnection is in use.
+ void set_per_packet_options(PerPacketOptions* options) {
+ per_packet_options_ = options;
+ }
+
+ // If |defer| is true, configures the connection to defer sending packets in
+ // response to an ACK to the SendAlarm. If |defer| is false, packets may be
+ // sent immediately after receiving an ACK.
+ void set_defer_send_in_response_to_packets(bool defer) {
+ defer_send_in_response_to_packets_ = defer;
+ }
+
+ PeerAddressChangeType active_peer_migration_type() {
+ return active_peer_migration_type_;
+ }
+
+ // Sends the connection close packet to the peer. |ack_mode| determines
+ // whether ack frame will be bundled with the connection close packet.
+ virtual void SendConnectionClosePacket(QuicErrorCode error,
+ const std::string& details,
+ AckBundling ack_mode);
+
+ private:
+ friend class test::QuicConnectionPeer;
+ friend class test::PacketSavingConnection;
+
+ typedef std::list<SerializedPacket> QueuedPacketList;
+
+ // Notifies the visitor of the close and marks the connection as disconnected.
+ // Does not send a connection close frame to the peer.
+ void TearDownLocalConnectionState(QuicErrorCode error,
+ const std::string& details,
+ ConnectionCloseSource source);
+
+ // Writes the given packet to socket, encrypted with packet's
+ // encryption_level. Returns true on successful write, and false if the writer
+ // was blocked and the write needs to be tried again. Notifies the
+ // SentPacketManager when the write is successful and sets
+ // retransmittable frames to nullptr.
+ // Saves the connection close packet for later transmission, even if the
+ // writer is write blocked.
+ bool WritePacket(SerializedPacket* packet);
+
+ // Make sure an ack we got from our peer is sane.
+ // Returns nullptr for valid acks or an error std::string if it was invalid.
+ const char* ValidateAckFrame(const QuicAckFrame& incoming_ack);
+
+ // Make sure a stop waiting we got from our peer is sane.
+ // Returns nullptr if the frame is valid or an error std::string if it was
+ // invalid.
+ const char* ValidateStopWaitingFrame(
+ const QuicStopWaitingFrame& stop_waiting);
+
+ // Sends a version negotiation packet to the peer.
+ void SendVersionNegotiationPacket();
+
+ // Clears any accumulated frames from the last received packet.
+ void ClearLastFrames();
+
+ // Deletes and clears any queued packets.
+ void ClearQueuedPackets();
+
+ // Closes the connection if the sent or received packet manager are tracking
+ // too many outstanding packets.
+ void MaybeCloseIfTooManyOutstandingPackets();
+
+ // Writes as many queued packets as possible. The connection must not be
+ // blocked when this is called.
+ void WriteQueuedPackets();
+
+ // Writes as many pending retransmissions as possible.
+ void WritePendingRetransmissions();
+
+ // Returns true if the packet should be discarded and not sent.
+ bool ShouldDiscardPacket(const SerializedPacket& packet);
+
+ // Queues |packet| in the hopes that it can be decrypted in the
+ // future, when a new key is installed.
+ void QueueUndecryptablePacket(const QuicEncryptedPacket& packet);
+
+ // Attempts to process any queued undecryptable packets.
+ void MaybeProcessUndecryptablePackets();
+
+ void ProcessAckFrame(const QuicAckFrame& incoming_ack);
+
+ void ProcessStopWaitingFrame(const QuicStopWaitingFrame& stop_waiting);
+
+ // Sends any packets which are a response to the last packet, including both
+ // acks and pending writes if an ack opened the congestion window.
+ void MaybeSendInResponseToPacket();
+
+ // Queue an ack or set the ack alarm if needed. |was_missing| is true if
+ // the most recently received packet was formerly missing.
+ void MaybeQueueAck(bool was_missing);
+
+ // Gets the least unacked packet number of |path_id|, which is the next packet
+ // number to be sent if there are no outstanding packets.
+ QuicPacketNumber GetLeastUnacked(QuicPathId path_id) const;
+
+ // Sets the timeout alarm to the appropriate value, if any.
+ void SetTimeoutAlarm();
+
+ // Sets the ping alarm to the appropriate value, if any.
+ void SetPingAlarm();
+
+ // Sets the retransmission alarm based on SentPacketManager.
+ void SetRetransmissionAlarm();
+
+ // Sets the MTU discovery alarm if necessary.
+ void MaybeSetMtuAlarm();
+
+ // On arrival of a new packet, checks to see if the socket addresses have
+ // changed since the last packet we saw on this connection.
+ void CheckForAddressMigration(const IPEndPoint& self_address,
+ const IPEndPoint& peer_address);
+
+ HasRetransmittableData IsRetransmittable(const SerializedPacket& packet);
+ bool IsTerminationPacket(const SerializedPacket& packet);
+
+ // Set the size of the packet we are targeting while doing path MTU discovery.
+ void SetMtuDiscoveryTarget(QuicByteCount target);
+
+ // Returns |suggested_max_packet_size| clamped to any limits set by the
+ // underlying writer, connection, or protocol.
+ QuicByteCount GetLimitedMaxPacketSize(
+ QuicByteCount suggested_max_packet_size);
+
+ // Called when |path_id| is considered as closed because either a PATH_CLOSE
+ // frame is sent or received. Stops receiving packets on closed path. Drops
+ // receive side of a closed path, and packets with retransmittable frames on a
+ // closed path are marked as retransmissions which will be transmitted on
+ // other paths.
+ // TODO(fayang): complete OnPathClosed once QuicMultipathSentPacketManager and
+ // QuicMultipathReceivedPacketManager are landed in QuicConnection.
+ void OnPathClosed(QuicPathId path_id);
+
+ // Do any work which logically would be done in OnPacket but can not be
+ // safely done until the packet is validated. Returns true if packet can be
+ // handled, false otherwise.
+ bool ProcessValidatedPacket(const QuicPacketHeader& header);
+
+ // Consider receiving crypto frame on non crypto stream as memory corruption.
+ bool MaybeConsiderAsMemoryCorruption(const QuicStreamFrame& frame);
+
+ const QuicTime::Delta DelayedAckTime();
+
+ // Check if the connection has no outstanding data to send and notify
+ // congestion controller if it is the case.
+ void CheckIfApplicationLimited();
+
+ QuicFramer framer_;
+ QuicConnectionHelperInterface* helper_; // Not owned.
+ QuicAlarmFactory* alarm_factory_; // Not owned.
+ PerPacketOptions* per_packet_options_; // Not owned.
+ QuicPacketWriter* writer_; // Owned or not depending on |owns_writer_|.
+ bool owns_writer_;
+ // Encryption level for new packets. Should only be changed via
+ // SetDefaultEncryptionLevel().
+ EncryptionLevel encryption_level_;
+ const QuicClock* clock_;
+ QuicRandom* random_generator_;
+
+ const QuicConnectionId connection_id_;
+ // Address on the last successfully processed packet received from the
+ // client.
+ IPEndPoint self_address_;
+ IPEndPoint peer_address_;
+
+ // Records change type when the peer initiates migration to a new peer
+ // address. Reset to NO_CHANGE after peer migration is validated.
+ PeerAddressChangeType active_peer_migration_type_;
+
+ // Records highest sent packet number when peer migration is started.
+ QuicPacketNumber highest_packet_sent_before_peer_migration_;
+
+ // True if the last packet has gotten far enough in the framer to be
+ // decrypted.
+ bool last_packet_decrypted_;
+ QuicByteCount last_size_; // Size of the last received packet.
+ // TODO(rch): remove this when b/27221014 is fixed.
+ const char* current_packet_data_; // UDP payload of packet currently being
+ // parsed or nullptr.
+ EncryptionLevel last_decrypted_packet_level_;
+ QuicPacketHeader last_header_;
+ // TODO(ianswett): Remove last_stop_waiting_frame_ once
+ // FLAGS_quic_receive_packet_once_decrypted is deprecated.
+ QuicStopWaitingFrame last_stop_waiting_frame_;
+ bool should_last_packet_instigate_acks_;
+ // Whether the most recent packet was missing before it was received.
+ bool was_last_packet_missing_;
+
+ // Track some peer state so we can do less bookkeeping
+ // Largest sequence sent by the peer which had an ack frame (latest ack info).
+ QuicPacketNumber largest_seen_packet_with_ack_;
+
+ // Largest packet number sent by the peer which had a stop waiting frame.
+ QuicPacketNumber largest_seen_packet_with_stop_waiting_;
+
+ // Collection of packets which were received before encryption was
+ // established, but which could not be decrypted. We buffer these on
+ // the assumption that they could not be processed because they were
+ // sent with the INITIAL encryption and the CHLO message was lost.
+ std::deque<QuicEncryptedPacket*> undecryptable_packets_;
+
+ // Maximum number of undecryptable packets the connection will store.
+ size_t max_undecryptable_packets_;
+
+ // When the version negotiation packet could not be sent because the socket
+ // was not writable, this is set to true.
+ bool pending_version_negotiation_packet_;
+
+ // When packets could not be sent because the socket was not writable,
+ // they are added to this std::list. All corresponding frames are in
+ // unacked_packets_ if they are to be retransmitted. Packets encrypted_buffer
+ // fields are owned by the QueuedPacketList, in order to ensure they outlast
+ // the original scope of the SerializedPacket.
+ QueuedPacketList queued_packets_;
+
+ // If true, then crypto packets will be saved as termination packets.
+ bool save_crypto_packets_as_termination_packets_;
+
+ // Contains the connection close packets if the connection has been closed.
+ std::unique_ptr<std::vector<std::unique_ptr<QuicEncryptedPacket>>>
+ termination_packets_;
+
+ // Determines whether or not a connection close packet is sent to the peer
+ // after idle timeout due to lack of network activity.
+ // This is particularly important on mobile, where waking up the radio is
+ // undesirable.
+ ConnectionCloseBehavior idle_timeout_connection_close_behavior_;
+
+ // When true, close the QUIC connection after 5 RTOs. Due to the min rto of
+ // 200ms, this is over 5 seconds.
+ bool close_connection_after_five_rtos_;
+
+ QuicReceivedPacketManager received_packet_manager_;
+ QuicSentEntropyManager sent_entropy_manager_;
+
+ // Indicates whether an ack should be sent the next time we try to write.
+ bool ack_queued_;
+ // How many retransmittable packets have arrived without sending an ack.
+ QuicPacketCount num_retransmittable_packets_received_since_last_ack_sent_;
+ // Whether there were missing packets in the last sent ack.
+ bool last_ack_had_missing_packets_;
+ // How many consecutive packets have arrived without sending an ack.
+ QuicPacketCount num_packets_received_since_last_ack_sent_;
+ // Indicates how many consecutive times an ack has arrived which indicates
+ // the peer needs to stop waiting for some packets.
+ int stop_waiting_count_;
+ // Indicates the current ack mode, defaults to acking every 2 packets.
+ AckMode ack_mode_;
+ // The max delay in fraction of min_rtt to use when sending decimated acks.
+ float ack_decimation_delay_;
+
+ // Indicates the retransmit alarm is going to be set by the
+ // ScopedRetransmitAlarmDelayer
+ bool delay_setting_retransmission_alarm_;
+ // Indicates the retransmission alarm needs to be set.
+ bool pending_retransmission_alarm_;
+
+ // If true, defer sending data in response to received packets to the
+ // SendAlarm.
+ bool defer_send_in_response_to_packets_;
+
+ // The timeout for PING.
+ QuicTime::Delta ping_timeout_;
+
+ // Arena to store class implementations within the QuicConnection.
+ QuicConnectionArena arena_;
+
+ // An alarm that fires when an ACK should be sent to the peer.
+ QuicArenaScopedPtr<QuicAlarm> ack_alarm_;
+ // An alarm that fires when a packet needs to be retransmitted.
+ QuicArenaScopedPtr<QuicAlarm> retransmission_alarm_;
+ // An alarm that is scheduled when the SentPacketManager requires a delay
+ // before sending packets and fires when the packet may be sent.
+ QuicArenaScopedPtr<QuicAlarm> send_alarm_;
+ // An alarm that is scheduled when the connection can still write and there
+ // may be more data to send.
+ // TODO(ianswett): Remove resume_writes_alarm when deprecating
+ // FLAGS_quic_only_one_sending_alarm
+ QuicArenaScopedPtr<QuicAlarm> resume_writes_alarm_;
+ // An alarm that fires when the connection may have timed out.
+ QuicArenaScopedPtr<QuicAlarm> timeout_alarm_;
+ // An alarm that fires when a ping should be sent.
+ QuicArenaScopedPtr<QuicAlarm> ping_alarm_;
+ // An alarm that fires when an MTU probe should be sent.
+ QuicArenaScopedPtr<QuicAlarm> mtu_discovery_alarm_;
+
+ // Neither visitor is owned by this class.
+ QuicConnectionVisitorInterface* visitor_;
+ QuicConnectionDebugVisitor* debug_visitor_;
+
+ QuicPacketGenerator packet_generator_;
+
+ // Network idle time before this connection is closed.
+ QuicTime::Delta idle_network_timeout_;
+ // The connection will wait this long for the handshake to complete.
+ QuicTime::Delta handshake_timeout_;
+
+ // Statistics for this session.
+ QuicConnectionStats stats_;
+
+ // The time that we got a packet for this connection.
+ // This is used for timeouts, and does not indicate the packet was processed.
+ QuicTime time_of_last_received_packet_;
+
+ // The last time this connection began sending a new (non-retransmitted)
+ // packet.
+ QuicTime time_of_last_sent_new_packet_;
+
+ // The the send time of the first retransmittable packet sent after
+ // |time_of_last_received_packet_|.
+ QuicTime last_send_for_timeout_;
+
+ // packet number of the last sent packet. Packets are guaranteed to be sent
+ // in packet number order.
+ QuicPacketNumber packet_number_of_last_sent_packet_;
+
+ // Sent packet manager which tracks the status of packets sent by this
+ // connection and contains the send and receive algorithms to determine when
+ // to send packets.
+ std::unique_ptr<QuicSentPacketManagerInterface> sent_packet_manager_;
+
+ // The state of connection in version negotiation finite state machine.
+ QuicVersionNegotiationState version_negotiation_state_;
+
+ // Tracks if the connection was created by the server or the client.
+ Perspective perspective_;
+
+ // True by default. False if we've received or sent an explicit connection
+ // close.
+ bool connected_;
+
+ // Destination address of the last received packet.
+ IPEndPoint last_packet_destination_address_;
+
+ // Source address of the last received packet.
+ IPEndPoint last_packet_source_address_;
+
+ // Set to false if the connection should not send truncated connection IDs to
+ // the peer, even if the peer supports it.
+ bool can_truncate_connection_ids_;
+
+ // If non-empty this contains the set of versions received in a
+ // version negotiation packet.
+ QuicVersionVector server_supported_versions_;
+
+ // The size of the packet we are targeting while doing path MTU discovery.
+ QuicByteCount mtu_discovery_target_;
+
+ // The number of MTU probes already sent.
+ size_t mtu_probe_count_;
+
+ // The number of packets between MTU probes.
+ QuicPacketCount packets_between_mtu_probes_;
+
+ // The packet number of the packet after which the next MTU probe will be
+ // sent.
+ QuicPacketNumber next_mtu_probe_at_;
+
+ // The value of the MTU regularly used by the connection. This is different
+ // from the value returned by max_packet_size(), as max_packet_size() returns
+ // the value of the MTU as currently used by the serializer, so if
+ // serialization of an MTU probe is in progress, those two values will be
+ // different.
+ QuicByteCount long_term_mtu_;
+
+ // The size of the largest packet received from peer.
+ QuicByteCount largest_received_packet_size_;
+
+ // The maximum allowed packet size.
+ QuicByteCount largest_packet_size_supported_;
+
+ // Whether a GoAway has been sent.
+ bool goaway_sent_;
+
+ // Whether a GoAway has been received.
+ bool goaway_received_;
+
+ // If true, multipath is enabled for this connection.
+ bool multipath_enabled_;
+
+ // Indicates whether a write error is encountered currently. This is used to
+ // avoid infinite write errors.
+ bool write_error_occured_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicConnection);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CONNECTION_H_
diff --git a/chromium/net/quic/core/quic_connection_stats.cc b/chromium/net/quic/core/quic_connection_stats.cc
new file mode 100644
index 00000000000..5b231c67112
--- /dev/null
+++ b/chromium/net/quic/core/quic_connection_stats.cc
@@ -0,0 +1,49 @@
+// Copyright 2013 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/quic_connection_stats.h"
+
+using std::ostream;
+
+namespace net {
+
+QuicConnectionStats::QuicConnectionStats()
+ : bytes_sent(0),
+ packets_sent(0),
+ stream_bytes_sent(0),
+ packets_discarded(0),
+ bytes_received(0),
+ packets_received(0),
+ packets_processed(0),
+ stream_bytes_received(0),
+ bytes_retransmitted(0),
+ packets_retransmitted(0),
+ bytes_spuriously_retransmitted(0),
+ packets_spuriously_retransmitted(0),
+ packets_lost(0),
+ slowstart_packets_sent(0),
+ slowstart_packets_lost(0),
+ slowstart_bytes_lost(0),
+ packets_dropped(0),
+ crypto_retransmit_count(0),
+ loss_timeout_count(0),
+ tlp_count(0),
+ rto_count(0),
+ min_rtt_us(0),
+ srtt_us(0),
+ max_packet_size(0),
+ max_received_packet_size(0),
+ estimated_bandwidth(QuicBandwidth::Zero()),
+ packets_reordered(0),
+ max_sequence_reordering(0),
+ max_time_reordering_us(0),
+ tcp_loss_events(0),
+ connection_creation_time(QuicTime::Zero()) {}
+
+QuicConnectionStats::QuicConnectionStats(const QuicConnectionStats& other) =
+ default;
+
+QuicConnectionStats::~QuicConnectionStats() {}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_connection_stats.h b/chromium/net/quic/core/quic_connection_stats.h
new file mode 100644
index 00000000000..1d0aaa3e81f
--- /dev/null
+++ b/chromium/net/quic/core/quic_connection_stats.h
@@ -0,0 +1,93 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_CONNECTION_STATS_H_
+#define NET_QUIC_QUIC_CONNECTION_STATS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <ostream>
+
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+// Structure to hold stats for a QuicConnection.
+struct NET_EXPORT_PRIVATE QuicConnectionStats {
+ QuicConnectionStats();
+ QuicConnectionStats(const QuicConnectionStats& other);
+ ~QuicConnectionStats();
+
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os,
+ const QuicConnectionStats& s);
+
+ QuicByteCount bytes_sent; // Includes retransmissions.
+ QuicPacketCount packets_sent;
+ // Non-retransmitted bytes sent in a stream frame.
+ QuicByteCount stream_bytes_sent;
+ // Packets serialized and discarded before sending.
+ QuicPacketCount packets_discarded;
+
+ // These include version negotiation and public reset packets, which do not
+ // have packet numbers or frame data.
+ QuicByteCount bytes_received; // Includes duplicate data for a stream.
+ // Includes packets which were not processable.
+ QuicPacketCount packets_received;
+ // Excludes packets which were not processable.
+ QuicPacketCount packets_processed;
+ QuicByteCount stream_bytes_received; // Bytes received in a stream frame.
+
+ QuicByteCount bytes_retransmitted;
+ QuicPacketCount packets_retransmitted;
+
+ QuicByteCount bytes_spuriously_retransmitted;
+ QuicPacketCount packets_spuriously_retransmitted;
+ // Number of packets abandoned as lost by the loss detection algorithm.
+ QuicPacketCount packets_lost;
+
+ // Number of packets sent in slow start.
+ QuicPacketCount slowstart_packets_sent;
+ // Number of packets lost exiting slow start.
+ QuicPacketCount slowstart_packets_lost;
+ // Number of bytes lost exiting slow start.
+ QuicByteCount slowstart_bytes_lost;
+
+ QuicPacketCount packets_dropped; // Duplicate or less than least unacked.
+ size_t crypto_retransmit_count;
+ // Count of times the loss detection alarm fired. At least one packet should
+ // be lost when the alarm fires.
+ size_t loss_timeout_count;
+ size_t tlp_count;
+ size_t rto_count; // Count of times the rto timer fired.
+
+ int64_t min_rtt_us; // Minimum RTT in microseconds.
+ int64_t srtt_us; // Smoothed RTT in microseconds.
+ QuicByteCount max_packet_size;
+ QuicByteCount max_received_packet_size;
+ QuicBandwidth estimated_bandwidth;
+
+ // Reordering stats for received packets.
+ // Number of packets received out of packet number order.
+ QuicPacketCount packets_reordered;
+ // Maximum reordering observed in packet number space.
+ QuicPacketNumber max_sequence_reordering;
+ // Maximum reordering observed in microseconds
+ int64_t max_time_reordering_us;
+
+ // The following stats are used only in TcpCubicSender.
+ // The number of loss events from TCP's perspective. Each loss event includes
+ // one or more lost packets.
+ uint32_t tcp_loss_events;
+
+ // Creation time, as reported by the QuicClock.
+ QuicTime connection_creation_time;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CONNECTION_STATS_H_
diff --git a/chromium/net/quic/core/quic_connection_test.cc b/chromium/net/quic/core/quic_connection_test.cc
new file mode 100644
index 00000000000..1e99229e9c6
--- /dev/null
+++ b/chromium/net/quic/core/quic_connection_test.cc
@@ -0,0 +1,5265 @@
+// 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/quic_connection.h"
+
+#include <errno.h>
+#include <memory>
+#include <ostream>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "net/base/ip_address.h"
+#include "net/base/net_errors.h"
+#include "net/quic/core/congestion_control/loss_detection_interface.h"
+#include "net/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/quic/core/crypto/null_encrypter.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_simple_buffer_allocator.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/mock_random.h"
+#include "net/quic/test_tools/quic_config_peer.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_framer_peer.h"
+#include "net/quic/test_tools/quic_packet_creator_peer.h"
+#include "net/quic/test_tools/quic_packet_generator_peer.h"
+#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/simple_quic_framer.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringPiece;
+using std::map;
+using std::ostream;
+using std::string;
+using std::vector;
+using testing::AnyNumber;
+using testing::AtLeast;
+using testing::Contains;
+using testing::DoAll;
+using testing::InSequence;
+using testing::InvokeWithoutArgs;
+using testing::NiceMock;
+using testing::Ref;
+using testing::Return;
+using testing::SaveArg;
+using testing::SetArgPointee;
+using testing::StrictMock;
+using testing::_;
+
+namespace net {
+namespace test {
+namespace {
+
+const char data1[] = "foo";
+const char data2[] = "bar";
+
+const bool kFin = true;
+const bool kEntropyFlag = true;
+const bool kHasStopWaiting = true;
+
+const QuicPacketEntropyHash kTestEntropyHash = 76;
+
+const int kDefaultRetransmissionTimeMs = 500;
+
+const IPEndPoint kPeerAddress = IPEndPoint(Loopback6(), /*port=*/12345);
+const IPEndPoint kSelfAddress = IPEndPoint(Loopback6(), /*port=*/443);
+
+Perspective InvertPerspective(Perspective perspective) {
+ return perspective == Perspective::IS_CLIENT ? Perspective::IS_SERVER
+ : Perspective::IS_CLIENT;
+}
+
+// TaggingEncrypter appends kTagSize bytes of |tag| to the end of each message.
+class TaggingEncrypter : public QuicEncrypter {
+ public:
+ explicit TaggingEncrypter(uint8_t tag) : tag_(tag) {}
+
+ ~TaggingEncrypter() override {}
+
+ // QuicEncrypter interface.
+ bool SetKey(StringPiece key) override { return true; }
+
+ bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
+
+ bool EncryptPacket(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ StringPiece associated_data,
+ StringPiece plaintext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) override {
+ const size_t len = plaintext.size() + kTagSize;
+ if (max_output_length < len) {
+ return false;
+ }
+ // Memmove is safe for inplace encryption.
+ memmove(output, plaintext.data(), plaintext.size());
+ output += plaintext.size();
+ memset(output, tag_, kTagSize);
+ *output_length = len;
+ return true;
+ }
+
+ size_t GetKeySize() const override { return 0; }
+ size_t GetNoncePrefixSize() const override { return 0; }
+
+ size_t GetMaxPlaintextSize(size_t ciphertext_size) const override {
+ return ciphertext_size - kTagSize;
+ }
+
+ size_t GetCiphertextSize(size_t plaintext_size) const override {
+ return plaintext_size + kTagSize;
+ }
+
+ StringPiece GetKey() const override { return StringPiece(); }
+
+ StringPiece GetNoncePrefix() const override { return StringPiece(); }
+
+ private:
+ enum {
+ kTagSize = 12,
+ };
+
+ const uint8_t tag_;
+
+ DISALLOW_COPY_AND_ASSIGN(TaggingEncrypter);
+};
+
+// TaggingDecrypter ensures that the final kTagSize bytes of the message all
+// have the same value and then removes them.
+class TaggingDecrypter : public QuicDecrypter {
+ public:
+ ~TaggingDecrypter() override {}
+
+ // QuicDecrypter interface
+ bool SetKey(StringPiece key) override { return true; }
+
+ bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
+
+ bool SetPreliminaryKey(StringPiece key) override {
+ QUIC_BUG << "should not be called";
+ return false;
+ }
+
+ bool SetDiversificationNonce(const DiversificationNonce& key) override {
+ return true;
+ }
+
+ bool DecryptPacket(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ StringPiece associated_data,
+ StringPiece ciphertext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) override {
+ if (ciphertext.size() < kTagSize) {
+ return false;
+ }
+ if (!CheckTag(ciphertext, GetTag(ciphertext))) {
+ return false;
+ }
+ *output_length = ciphertext.size() - kTagSize;
+ memcpy(output, ciphertext.data(), *output_length);
+ return true;
+ }
+
+ StringPiece GetKey() const override { return StringPiece(); }
+ StringPiece GetNoncePrefix() const override { return StringPiece(); }
+ const char* cipher_name() const override { return "Tagging"; }
+ // Use a distinct value starting with 0xFFFFFF, which is never used by TLS.
+ uint32_t cipher_id() const override { return 0xFFFFFFF0; }
+
+ protected:
+ virtual uint8_t GetTag(StringPiece ciphertext) {
+ return ciphertext.data()[ciphertext.size() - 1];
+ }
+
+ private:
+ enum {
+ kTagSize = 12,
+ };
+
+ bool CheckTag(StringPiece ciphertext, uint8_t tag) {
+ for (size_t i = ciphertext.size() - kTagSize; i < ciphertext.size(); i++) {
+ if (ciphertext.data()[i] != tag) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+};
+
+// StringTaggingDecrypter ensures that the final kTagSize bytes of the message
+// match the expected value.
+class StrictTaggingDecrypter : public TaggingDecrypter {
+ public:
+ explicit StrictTaggingDecrypter(uint8_t tag) : tag_(tag) {}
+ ~StrictTaggingDecrypter() override {}
+
+ // TaggingQuicDecrypter
+ uint8_t GetTag(StringPiece ciphertext) override { return tag_; }
+
+ const char* cipher_name() const override { return "StrictTagging"; }
+ // Use a distinct value starting with 0xFFFFFF, which is never used by TLS.
+ uint32_t cipher_id() const override { return 0xFFFFFFF1; }
+
+ private:
+ const uint8_t tag_;
+};
+
+class TestConnectionHelper : public QuicConnectionHelperInterface {
+ public:
+ TestConnectionHelper(MockClock* clock, MockRandom* random_generator)
+ : clock_(clock), random_generator_(random_generator) {
+ clock_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ }
+
+ // QuicConnectionHelperInterface
+ const QuicClock* GetClock() const override { return clock_; }
+
+ QuicRandom* GetRandomGenerator() override { return random_generator_; }
+
+ QuicBufferAllocator* GetBufferAllocator() override {
+ return &buffer_allocator_;
+ }
+
+ private:
+ MockClock* clock_;
+ MockRandom* random_generator_;
+ SimpleBufferAllocator buffer_allocator_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestConnectionHelper);
+};
+
+class TestAlarmFactory : public QuicAlarmFactory {
+ public:
+ class TestAlarm : public QuicAlarm {
+ public:
+ explicit TestAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate> delegate)
+ : QuicAlarm(std::move(delegate)) {}
+
+ void SetImpl() override {}
+ void CancelImpl() override {}
+ using QuicAlarm::Fire;
+ };
+
+ TestAlarmFactory() {}
+
+ QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override {
+ return new TestAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate));
+ }
+
+ QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
+ QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+ QuicConnectionArena* arena) override {
+ return arena->New<TestAlarm>(std::move(delegate));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestAlarmFactory);
+};
+
+class TestPacketWriter : public QuicPacketWriter {
+ public:
+ TestPacketWriter(QuicVersion version, MockClock* clock)
+ : version_(version),
+ framer_(SupportedVersions(version_)),
+ last_packet_size_(0),
+ write_blocked_(false),
+ write_should_fail_(false),
+ block_on_next_write_(false),
+ next_packet_too_large_(false),
+ always_get_packet_too_large_(false),
+ is_write_blocked_data_buffered_(false),
+ final_bytes_of_last_packet_(0),
+ final_bytes_of_previous_packet_(0),
+ use_tagging_decrypter_(false),
+ packets_write_attempts_(0),
+ clock_(clock),
+ write_pause_time_delta_(QuicTime::Delta::Zero()),
+ max_packet_size_(kMaxPacketSize) {}
+
+ // QuicPacketWriter interface
+ WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const IPAddress& self_address,
+ const IPEndPoint& peer_address,
+ PerPacketOptions* options) override {
+ QuicEncryptedPacket packet(buffer, buf_len);
+ ++packets_write_attempts_;
+
+ if (packet.length() >= sizeof(final_bytes_of_last_packet_)) {
+ final_bytes_of_previous_packet_ = final_bytes_of_last_packet_;
+ memcpy(&final_bytes_of_last_packet_, packet.data() + packet.length() - 4,
+ sizeof(final_bytes_of_last_packet_));
+ }
+
+ if (use_tagging_decrypter_) {
+ framer_.framer()->SetDecrypter(ENCRYPTION_NONE, new TaggingDecrypter);
+ }
+ EXPECT_TRUE(framer_.ProcessPacket(packet));
+ if (block_on_next_write_) {
+ write_blocked_ = true;
+ block_on_next_write_ = false;
+ }
+ if (next_packet_too_large_) {
+ next_packet_too_large_ = false;
+ return WriteResult(WRITE_STATUS_ERROR, ERR_MSG_TOO_BIG);
+ }
+ if (always_get_packet_too_large_) {
+ LOG(ERROR) << "RETURNING TOO BIG";
+ return WriteResult(WRITE_STATUS_ERROR, ERR_MSG_TOO_BIG);
+ }
+ if (IsWriteBlocked()) {
+ return WriteResult(WRITE_STATUS_BLOCKED, -1);
+ }
+
+ if (ShouldWriteFail()) {
+ return WriteResult(WRITE_STATUS_ERROR, 0);
+ }
+
+ last_packet_size_ = packet.length();
+
+ if (!write_pause_time_delta_.IsZero()) {
+ clock_->AdvanceTime(write_pause_time_delta_);
+ }
+ return WriteResult(WRITE_STATUS_OK, last_packet_size_);
+ }
+
+ bool IsWriteBlockedDataBuffered() const override {
+ return is_write_blocked_data_buffered_;
+ }
+
+ bool ShouldWriteFail() { return write_should_fail_; }
+
+ bool IsWriteBlocked() const override { return write_blocked_; }
+
+ void SetWritable() override { write_blocked_ = false; }
+
+ void SetShouldWriteFail() { write_should_fail_ = true; }
+
+ QuicByteCount GetMaxPacketSize(
+ const IPEndPoint& /*peer_address*/) const override {
+ return max_packet_size_;
+ }
+
+ void BlockOnNextWrite() { block_on_next_write_ = true; }
+
+ void SimulateNextPacketTooLarge() { next_packet_too_large_ = true; }
+
+ void AlwaysGetPacketTooLarge() { always_get_packet_too_large_ = true; }
+
+ // Sets the amount of time that the writer should before the actual write.
+ void SetWritePauseTimeDelta(QuicTime::Delta delta) {
+ write_pause_time_delta_ = delta;
+ }
+
+ const QuicPacketHeader& header() { return framer_.header(); }
+
+ size_t frame_count() const { return framer_.num_frames(); }
+
+ const vector<QuicAckFrame>& ack_frames() const {
+ return framer_.ack_frames();
+ }
+
+ const vector<QuicStopWaitingFrame>& stop_waiting_frames() const {
+ return framer_.stop_waiting_frames();
+ }
+
+ const vector<QuicConnectionCloseFrame>& connection_close_frames() const {
+ return framer_.connection_close_frames();
+ }
+
+ const vector<QuicRstStreamFrame>& rst_stream_frames() const {
+ return framer_.rst_stream_frames();
+ }
+
+ const vector<QuicStreamFrame*>& stream_frames() const {
+ return framer_.stream_frames();
+ }
+
+ const vector<QuicPingFrame>& ping_frames() const {
+ return framer_.ping_frames();
+ }
+
+ size_t last_packet_size() { return last_packet_size_; }
+
+ const QuicVersionNegotiationPacket* version_negotiation_packet() {
+ return framer_.version_negotiation_packet();
+ }
+
+ void set_is_write_blocked_data_buffered(bool buffered) {
+ is_write_blocked_data_buffered_ = buffered;
+ }
+
+ void set_perspective(Perspective perspective) {
+ // We invert perspective here, because the framer needs to parse packets
+ // we send.
+ QuicFramerPeer::SetPerspective(framer_.framer(),
+ InvertPerspective(perspective));
+ }
+
+ // final_bytes_of_last_packet_ returns the last four bytes of the previous
+ // packet as a little-endian, uint32_t. This is intended to be used with a
+ // TaggingEncrypter so that tests can determine which encrypter was used for
+ // a given packet.
+ uint32_t final_bytes_of_last_packet() { return final_bytes_of_last_packet_; }
+
+ // Returns the final bytes of the second to last packet.
+ uint32_t final_bytes_of_previous_packet() {
+ return final_bytes_of_previous_packet_;
+ }
+
+ void use_tagging_decrypter() { use_tagging_decrypter_ = true; }
+
+ uint32_t packets_write_attempts() { return packets_write_attempts_; }
+
+ void Reset() { framer_.Reset(); }
+
+ void SetSupportedVersions(const QuicVersionVector& versions) {
+ framer_.SetSupportedVersions(versions);
+ }
+
+ void set_max_packet_size(QuicByteCount max_packet_size) {
+ max_packet_size_ = max_packet_size;
+ }
+
+ private:
+ QuicVersion version_;
+ SimpleQuicFramer framer_;
+ size_t last_packet_size_;
+ bool write_blocked_;
+ bool write_should_fail_;
+ bool block_on_next_write_;
+ bool next_packet_too_large_;
+ bool always_get_packet_too_large_;
+ bool is_write_blocked_data_buffered_;
+ uint32_t final_bytes_of_last_packet_;
+ uint32_t final_bytes_of_previous_packet_;
+ bool use_tagging_decrypter_;
+ uint32_t packets_write_attempts_;
+ MockClock* clock_;
+ // If non-zero, the clock will pause during WritePacket for this amount of
+ // time.
+ QuicTime::Delta write_pause_time_delta_;
+ QuicByteCount max_packet_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestPacketWriter);
+};
+
+class TestConnection : public QuicConnection {
+ public:
+ TestConnection(QuicConnectionId connection_id,
+ IPEndPoint address,
+ TestConnectionHelper* helper,
+ TestAlarmFactory* alarm_factory,
+ TestPacketWriter* writer,
+ Perspective perspective,
+ QuicVersion version)
+ : QuicConnection(connection_id,
+ address,
+ helper,
+ alarm_factory,
+ writer,
+ /* owns_writer= */ false,
+ perspective,
+ SupportedVersions(version)) {
+ writer->set_perspective(perspective);
+ SetEncrypter(ENCRYPTION_FORWARD_SECURE, new NullEncrypter());
+ }
+
+ void SendAck() { QuicConnectionPeer::SendAck(this); }
+
+ void SetSendAlgorithm(QuicPathId path_id,
+ SendAlgorithmInterface* send_algorithm) {
+ QuicConnectionPeer::SetSendAlgorithm(this, path_id, send_algorithm);
+ }
+
+ void SetLossAlgorithm(QuicPathId path_id,
+ LossDetectionInterface* loss_algorithm) {
+ QuicConnectionPeer::SetLossAlgorithm(this, path_id, loss_algorithm);
+ }
+
+ void SendPacket(EncryptionLevel level,
+ QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ QuicPacket* packet,
+ QuicPacketEntropyHash entropy_hash,
+ HasRetransmittableData retransmittable,
+ bool has_ack,
+ bool has_pending_frames) {
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length =
+ QuicConnectionPeer::GetFramer(this)->EncryptPayload(
+ ENCRYPTION_NONE, path_id, packet_number, *packet, buffer,
+ kMaxPacketSize);
+ delete packet;
+ SerializedPacket serialized_packet(
+ kDefaultPathId, packet_number, PACKET_6BYTE_PACKET_NUMBER, buffer,
+ encrypted_length, entropy_hash, has_ack, has_pending_frames);
+ if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
+ serialized_packet.retransmittable_frames.push_back(
+ QuicFrame(new QuicStreamFrame()));
+ }
+ OnSerializedPacket(&serialized_packet);
+ }
+
+ QuicConsumedData SendStreamDataWithString(
+ QuicStreamId id,
+ StringPiece data,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* listener) {
+ if (id != kCryptoStreamId && this->encryption_level() == ENCRYPTION_NONE) {
+ this->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ }
+ struct iovec iov;
+ QuicIOVector data_iov(MakeIOVector(data, &iov));
+ return QuicConnection::SendStreamData(id, data_iov, offset, fin, listener);
+ }
+
+ QuicConsumedData SendStreamData3() {
+ return SendStreamDataWithString(kClientDataStreamId1, "food", 0, !kFin,
+ nullptr);
+ }
+
+ QuicConsumedData SendStreamData5() {
+ return SendStreamDataWithString(kClientDataStreamId2, "food2", 0, !kFin,
+ nullptr);
+ }
+
+ // Ensures the connection can write stream data before writing.
+ QuicConsumedData EnsureWritableAndSendStreamData5() {
+ EXPECT_TRUE(CanWriteStreamData());
+ return SendStreamData5();
+ }
+
+ // The crypto stream has special semantics so that it is not blocked by a
+ // congestion window limitation, and also so that it gets put into a separate
+ // packet (so that it is easier to reason about a crypto frame not being
+ // split needlessly across packet boundaries). As a result, we have separate
+ // tests for some cases for this stream.
+ QuicConsumedData SendCryptoStreamData() {
+ return SendStreamDataWithString(kCryptoStreamId, "chlo", 0, !kFin, nullptr);
+ }
+
+ void set_version(QuicVersion version) {
+ QuicConnectionPeer::GetFramer(this)->set_version(version);
+ }
+
+ void SetSupportedVersions(const QuicVersionVector& versions) {
+ QuicConnectionPeer::GetFramer(this)->SetSupportedVersions(versions);
+ writer()->SetSupportedVersions(versions);
+ }
+
+ void set_perspective(Perspective perspective) {
+ writer()->set_perspective(perspective);
+ QuicConnectionPeer::SetPerspective(this, perspective);
+ }
+
+ // Enable path MTU discovery. Assumes that the test is performed from the
+ // client perspective and the higher value of MTU target is used.
+ void EnablePathMtuDiscovery(MockSendAlgorithm* send_algorithm) {
+ ASSERT_EQ(Perspective::IS_CLIENT, perspective());
+
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(kMTUH);
+ config.SetConnectionOptionsToSend(connection_options);
+ EXPECT_CALL(*send_algorithm, SetFromConfig(_, _));
+ SetFromConfig(config);
+
+ // Normally, the pacing would be disabled in the test, but calling
+ // SetFromConfig enables it. Set nearly-infinite bandwidth to make the
+ // pacing algorithm work.
+ EXPECT_CALL(*send_algorithm, PacingRate(_))
+ .WillRepeatedly(Return(QuicBandwidth::Infinite()));
+ }
+
+ TestAlarmFactory::TestAlarm* GetAckAlarm() {
+ return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
+ QuicConnectionPeer::GetAckAlarm(this));
+ }
+
+ TestAlarmFactory::TestAlarm* GetPingAlarm() {
+ return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
+ QuicConnectionPeer::GetPingAlarm(this));
+ }
+
+ TestAlarmFactory::TestAlarm* GetResumeWritesAlarm() {
+ return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
+ QuicConnectionPeer::GetResumeWritesAlarm(this));
+ }
+
+ TestAlarmFactory::TestAlarm* GetRetransmissionAlarm() {
+ return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
+ QuicConnectionPeer::GetRetransmissionAlarm(this));
+ }
+
+ TestAlarmFactory::TestAlarm* GetSendAlarm() {
+ return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
+ QuicConnectionPeer::GetSendAlarm(this));
+ }
+
+ TestAlarmFactory::TestAlarm* GetTimeoutAlarm() {
+ return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
+ QuicConnectionPeer::GetTimeoutAlarm(this));
+ }
+
+ TestAlarmFactory::TestAlarm* GetMtuDiscoveryAlarm() {
+ return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
+ QuicConnectionPeer::GetMtuDiscoveryAlarm(this));
+ }
+
+ void SetMaxTailLossProbes(QuicPathId path_id, size_t max_tail_loss_probes) {
+ QuicSentPacketManagerPeer::SetMaxTailLossProbes(
+ QuicConnectionPeer::GetSentPacketManager(this, path_id),
+ max_tail_loss_probes);
+ }
+
+ QuicByteCount GetBytesInFlight(QuicPathId path_id) {
+ return QuicSentPacketManagerPeer::GetBytesInFlight(
+ QuicConnectionPeer::GetSentPacketManager(this, path_id));
+ }
+
+ using QuicConnection::SelectMutualVersion;
+ using QuicConnection::set_defer_send_in_response_to_packets;
+
+ private:
+ TestPacketWriter* writer() {
+ return static_cast<TestPacketWriter*>(QuicConnection::writer());
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(TestConnection);
+};
+
+enum class AckResponse { kDefer, kImmediate };
+
+// Run tests with combinations of {QuicVersion, AckResponse}.
+struct TestParams {
+ TestParams(QuicVersion version, AckResponse ack_response)
+ : version(version), ack_response(ack_response) {}
+
+ friend ostream& operator<<(ostream& os, const TestParams& p) {
+ os << "{ client_version: " << QuicVersionToString(p.version)
+ << " ack_response: "
+ << (p.ack_response == AckResponse::kDefer ? "defer" : "immediate")
+ << " }";
+ return os;
+ }
+
+ QuicVersion version;
+ AckResponse ack_response;
+};
+
+// Constructs various test permutations.
+vector<TestParams> GetTestParams() {
+ vector<TestParams> params;
+ QuicVersionVector all_supported_versions = AllSupportedVersions();
+ for (size_t i = 0; i < all_supported_versions.size(); ++i) {
+ for (AckResponse ack_response :
+ {AckResponse::kDefer, AckResponse::kImmediate}) {
+ params.push_back(TestParams(all_supported_versions[i], ack_response));
+ }
+ }
+ return params;
+}
+
+class QuicConnectionTest : public ::testing::TestWithParam<TestParams> {
+ protected:
+ QuicConnectionTest()
+ : connection_id_(42),
+ 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_(SupportedVersions(version()),
+ QuicTime::Zero(),
+ Perspective::IS_SERVER),
+ peer_creator_(connection_id_,
+ &peer_framer_,
+ &random_generator_,
+ &buffer_allocator_,
+ /*delegate=*/nullptr),
+ writer_(new TestPacketWriter(version(), &clock_)),
+ connection_(connection_id_,
+ kPeerAddress,
+ helper_.get(),
+ alarm_factory_.get(),
+ writer_.get(),
+ Perspective::IS_CLIENT,
+ version()),
+ creator_(QuicConnectionPeer::GetPacketCreator(&connection_)),
+ generator_(QuicConnectionPeer::GetPacketGenerator(&connection_)),
+ manager_(QuicConnectionPeer::GetSentPacketManager(&connection_,
+ kDefaultPathId)),
+ frame1_(1, false, 0, StringPiece(data1)),
+ frame2_(1, false, 3, StringPiece(data2)),
+ packet_number_length_(PACKET_6BYTE_PACKET_NUMBER),
+ connection_id_length_(PACKET_8BYTE_CONNECTION_ID) {
+ connection_.set_defer_send_in_response_to_packets(GetParam().ack_response ==
+ AckResponse::kDefer);
+ connection_.set_visitor(&visitor_);
+ connection_.SetSendAlgorithm(kDefaultPathId, send_algorithm_);
+ connection_.SetLossAlgorithm(kDefaultPathId, loss_algorithm_.get());
+ framer_.set_received_entropy_calculator(&entropy_calculator_);
+ peer_framer_.set_received_entropy_calculator(&peer_entropy_calculator_);
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ .WillRepeatedly(Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
+ .WillRepeatedly(Return(kDefaultTCPMSS));
+ EXPECT_CALL(*send_algorithm_, PacingRate(_))
+ .WillRepeatedly(Return(QuicBandwidth::Zero()));
+ ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillByDefault(Return(true));
+ EXPECT_CALL(*send_algorithm_, HasReliableBandwidthEstimate())
+ .Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, BandwidthEstimate())
+ .Times(AnyNumber())
+ .WillRepeatedly(Return(QuicBandwidth::Zero()));
+ EXPECT_CALL(*send_algorithm_, InSlowStart()).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, InRecovery()).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(AnyNumber());
+ EXPECT_CALL(visitor_, WillingAndAbleToWrite()).Times(AnyNumber());
+ EXPECT_CALL(visitor_, HasPendingHandshake()).Times(AnyNumber());
+ EXPECT_CALL(visitor_, OnCanWrite()).Times(AnyNumber());
+ EXPECT_CALL(visitor_, PostProcessAfterData()).Times(AnyNumber());
+ EXPECT_CALL(visitor_, HasOpenDynamicStreams())
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(visitor_, OnCongestionWindowChange(_)).Times(AnyNumber());
+
+ EXPECT_CALL(*loss_algorithm_, GetLossTimeout())
+ .WillRepeatedly(Return(QuicTime::Zero()));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
+ .Times(AnyNumber());
+ }
+
+ QuicVersion version() { return GetParam().version; }
+
+ QuicAckFrame* outgoing_ack() {
+ QuicFrame ack_frame = QuicConnectionPeer::GetUpdatedAckFrame(&connection_);
+ ack_ = *ack_frame.ack_frame;
+ return &ack_;
+ }
+
+ QuicStopWaitingFrame* stop_waiting() {
+ QuicConnectionPeer::PopulateStopWaitingFrame(&connection_, &stop_waiting_);
+ return &stop_waiting_;
+ }
+
+ QuicPacketNumber least_unacked() {
+ if (writer_->stop_waiting_frames().empty()) {
+ return 0;
+ }
+ return writer_->stop_waiting_frames()[0].least_unacked;
+ }
+
+ void use_tagging_decrypter() { writer_->use_tagging_decrypter(); }
+
+ void ProcessPacket(QuicPathId path_id, QuicPacketNumber number) {
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacket(path_id, number, !kEntropyFlag);
+ if (connection_.GetSendAlarm()->IsSet()) {
+ connection_.GetSendAlarm()->Fire();
+ }
+ }
+
+ QuicPacketEntropyHash ProcessFramePacket(QuicFrame frame) {
+ return ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
+ }
+
+ QuicPacketEntropyHash ProcessFramePacketWithAddresses(
+ QuicFrame frame,
+ IPEndPoint self_address,
+ IPEndPoint peer_address) {
+ QuicFrames frames;
+ frames.push_back(QuicFrame(frame));
+ QuicPacketCreatorPeer::SetSendVersionInPacket(
+ &peer_creator_, connection_.perspective() == Perspective::IS_SERVER);
+
+ char buffer[kMaxPacketSize];
+ SerializedPacket serialized_packet =
+ QuicPacketCreatorPeer::SerializeAllFrames(&peer_creator_, frames,
+ buffer, kMaxPacketSize);
+ connection_.ProcessUdpPacket(
+ self_address, peer_address,
+ QuicReceivedPacket(serialized_packet.encrypted_buffer,
+ serialized_packet.encrypted_length, clock_.Now()));
+ if (connection_.GetSendAlarm()->IsSet()) {
+ connection_.GetSendAlarm()->Fire();
+ }
+ return serialized_packet.entropy_hash;
+ }
+
+ // Bypassing the packet creator is unrealistic, but allows us to process
+ // packets the QuicPacketCreator won't allow us to create.
+ void ForceProcessFramePacket(QuicFrame frame) {
+ QuicFrames frames;
+ frames.push_back(QuicFrame(frame));
+ QuicPacketCreatorPeer::SetSendVersionInPacket(
+ &peer_creator_, connection_.perspective() == Perspective::IS_SERVER);
+ QuicPacketHeader header;
+ QuicPacketCreatorPeer::FillPacketHeader(&peer_creator_, &header);
+ char encrypted_buffer[kMaxPacketSize];
+ size_t length = peer_framer_.BuildDataPacket(
+ header, frames, encrypted_buffer, kMaxPacketSize);
+ DCHECK_GT(length, 0u);
+
+ const size_t encrypted_length = peer_framer_.EncryptInPlace(
+ ENCRYPTION_NONE, kDefaultPathId, header.packet_number,
+ GetStartOfEncryptedData(peer_framer_.version(), header), length,
+ kMaxPacketSize, encrypted_buffer);
+ DCHECK_GT(encrypted_length, 0u);
+
+ connection_.ProcessUdpPacket(
+ kSelfAddress, kPeerAddress,
+ QuicReceivedPacket(encrypted_buffer, encrypted_length, clock_.Now()));
+ }
+
+ QuicPacketEntropyHash ProcessFramePacketAtLevel(QuicPathId path_id,
+ QuicPacketNumber number,
+ QuicFrame frame,
+ EncryptionLevel level) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = connection_id_;
+ header.public_header.packet_number_length = packet_number_length_;
+ header.public_header.connection_id_length = connection_id_length_;
+ header.public_header.multipath_flag = path_id != kDefaultPathId;
+ header.path_id = path_id;
+ header.packet_number = number;
+ QuicFrames frames;
+ frames.push_back(frame);
+ std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
+
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length = framer_.EncryptPayload(
+ level, path_id, number, *packet, buffer, kMaxPacketSize);
+ connection_.ProcessUdpPacket(
+ kSelfAddress, kPeerAddress,
+ QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
+ return base::checked_cast<QuicPacketEntropyHash>(encrypted_length);
+ }
+
+ size_t ProcessDataPacket(QuicPathId path_id,
+ QuicPacketNumber number,
+ bool entropy_flag) {
+ return ProcessDataPacketAtLevel(path_id, number, entropy_flag, false,
+ ENCRYPTION_NONE);
+ }
+
+ size_t ProcessDataPacketAtLevel(QuicPathId path_id,
+ QuicPacketNumber number,
+ bool entropy_flag,
+ bool has_stop_waiting,
+ EncryptionLevel level) {
+ std::unique_ptr<QuicPacket> packet(
+ ConstructDataPacket(path_id, number, entropy_flag, has_stop_waiting));
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length = framer_.EncryptPayload(
+ level, path_id, number, *packet, buffer, kMaxPacketSize);
+ connection_.ProcessUdpPacket(
+ kSelfAddress, kPeerAddress,
+ QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false));
+ if (connection_.GetSendAlarm()->IsSet()) {
+ connection_.GetSendAlarm()->Fire();
+ }
+ return encrypted_length;
+ }
+
+ void ProcessClosePacket(QuicPathId path_id, QuicPacketNumber number) {
+ std::unique_ptr<QuicPacket> packet(ConstructClosePacket(number));
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length = framer_.EncryptPayload(
+ ENCRYPTION_NONE, path_id, number, *packet, buffer, kMaxPacketSize);
+ connection_.ProcessUdpPacket(
+ kSelfAddress, kPeerAddress,
+ QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
+ }
+
+ QuicByteCount SendStreamDataToPeer(QuicStreamId id,
+ StringPiece data,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicPacketNumber* last_packet) {
+ QuicByteCount packet_size;
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<3>(&packet_size), Return(true)));
+ connection_.SendStreamDataWithString(id, data, offset, fin, nullptr);
+ if (last_packet != nullptr) {
+ *last_packet = creator_->packet_number();
+ }
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .Times(AnyNumber());
+ return packet_size;
+ }
+
+ void SendAckPacketToPeer() {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendAck();
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .Times(AnyNumber());
+ }
+
+ void ProcessAckPacket(QuicPacketNumber packet_number, QuicAckFrame* frame) {
+ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, packet_number - 1);
+ ProcessFramePacket(QuicFrame(frame));
+ }
+
+ QuicPacketEntropyHash ProcessAckPacket(QuicAckFrame* frame) {
+ return ProcessFramePacket(QuicFrame(frame));
+ }
+
+ QuicPacketEntropyHash ProcessStopWaitingPacket(QuicStopWaitingFrame* frame) {
+ return ProcessFramePacket(QuicFrame(frame));
+ }
+
+ QuicPacketEntropyHash ProcessStopWaitingPacketAtLevel(
+ QuicPathId path_id,
+ QuicPacketNumber number,
+ QuicStopWaitingFrame* frame,
+ EncryptionLevel level) {
+ return ProcessFramePacketAtLevel(path_id, number, QuicFrame(frame),
+ ENCRYPTION_INITIAL);
+ }
+
+ QuicPacketEntropyHash ProcessGoAwayPacket(QuicGoAwayFrame* frame) {
+ return ProcessFramePacket(QuicFrame(frame));
+ }
+
+ QuicPacketEntropyHash ProcessPathClosePacket(QuicPathCloseFrame* frame) {
+ return ProcessFramePacket(QuicFrame(frame));
+ }
+
+ bool IsMissing(QuicPacketNumber number) {
+ return IsAwaitingPacket(*outgoing_ack(), number, 0);
+ }
+
+ QuicPacket* ConstructPacket(QuicPacketHeader header, QuicFrames frames) {
+ QuicPacket* packet = BuildUnsizedDataPacket(&peer_framer_, header, frames);
+ EXPECT_NE(nullptr, packet);
+ return packet;
+ }
+
+ QuicPacket* ConstructDataPacket(QuicPathId path_id,
+ QuicPacketNumber number,
+ bool entropy_flag,
+ bool has_stop_waiting) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = connection_id_;
+ header.public_header.packet_number_length = packet_number_length_;
+ header.public_header.connection_id_length = connection_id_length_;
+ header.public_header.multipath_flag = path_id != kDefaultPathId;
+ header.entropy_flag = entropy_flag;
+ header.path_id = path_id;
+ header.packet_number = number;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&frame1_));
+ if (has_stop_waiting) {
+ frames.push_back(QuicFrame(&stop_waiting_));
+ }
+ return ConstructPacket(header, frames);
+ }
+
+ QuicPacket* ConstructClosePacket(QuicPacketNumber number) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = connection_id_;
+ header.packet_number = number;
+
+ QuicConnectionCloseFrame qccf;
+ qccf.error_code = QUIC_PEER_GOING_AWAY;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&qccf));
+ return ConstructPacket(header, frames);
+ }
+
+ QuicTime::Delta DefaultRetransmissionTime() {
+ return QuicTime::Delta::FromMilliseconds(kDefaultRetransmissionTimeMs);
+ }
+
+ QuicTime::Delta DefaultDelayedAckTime() {
+ return QuicTime::Delta::FromMilliseconds(kMaxDelayedAckTimeMs);
+ }
+
+ // Initialize a frame acknowledging all packets up to largest_observed.
+ const QuicAckFrame InitAckFrame(QuicPacketNumber largest_observed) {
+ QuicAckFrame frame(MakeAckFrame(largest_observed));
+ if (GetParam().version <= QUIC_VERSION_33) {
+ if (largest_observed > 0) {
+ frame.entropy_hash = QuicConnectionPeer::GetSentEntropyHash(
+ &connection_, largest_observed);
+ }
+ } else {
+ frame.missing = false;
+ if (largest_observed > 0) {
+ frame.packets.Add(1, largest_observed + 1);
+ }
+ }
+ return frame;
+ }
+
+ const QuicStopWaitingFrame InitStopWaitingFrame(
+ QuicPacketNumber least_unacked) {
+ QuicStopWaitingFrame frame;
+ frame.least_unacked = least_unacked;
+ return frame;
+ }
+
+ // Explicitly nack a packet.
+ void NackPacket(QuicPacketNumber missing, QuicAckFrame* frame) {
+ if (frame->missing) {
+ frame->packets.Add(missing);
+ frame->entropy_hash ^=
+ QuicConnectionPeer::PacketEntropy(&connection_, missing);
+ } else {
+ frame->packets.Remove(missing);
+ }
+ }
+
+ // Undo nacking a packet within the frame.
+ void AckPacket(QuicPacketNumber arrived, QuicAckFrame* frame) {
+ if (frame->missing) {
+ EXPECT_TRUE(frame->packets.Contains(arrived));
+ frame->packets.Remove(arrived);
+ frame->entropy_hash ^=
+ QuicConnectionPeer::PacketEntropy(&connection_, arrived);
+ } else {
+ EXPECT_FALSE(frame->packets.Contains(arrived));
+ frame->packets.Add(arrived);
+ }
+ }
+
+ void TriggerConnectionClose() {
+ // Send an erroneous packet to close the connection.
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, _,
+ ConnectionCloseSource::FROM_SELF));
+ // Call ProcessDataPacket rather than ProcessPacket, as we should not get a
+ // packet call to the visitor.
+ ProcessDataPacket(kDefaultPathId, 6000, !kEntropyFlag);
+ EXPECT_FALSE(QuicConnectionPeer::GetConnectionClosePacket(&connection_) ==
+ nullptr);
+ }
+
+ void BlockOnNextWrite() {
+ writer_->BlockOnNextWrite();
+ EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1));
+ }
+
+ void SimulateNextPacketTooLarge() { writer_->SimulateNextPacketTooLarge(); }
+
+ void AlwaysGetPacketTooLarge() { writer_->AlwaysGetPacketTooLarge(); }
+
+ void SetWritePauseTimeDelta(QuicTime::Delta delta) {
+ writer_->SetWritePauseTimeDelta(delta);
+ }
+
+ void CongestionBlockWrites() {
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ .WillRepeatedly(testing::Return(QuicTime::Delta::FromSeconds(1)));
+ }
+
+ void CongestionUnblockWrites() {
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ .WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
+ }
+
+ void set_perspective(Perspective perspective) {
+ connection_.set_perspective(perspective);
+ QuicFramerPeer::SetPerspective(&peer_framer_,
+ InvertPerspective(perspective));
+ }
+
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+
+ QuicConnectionId connection_id_;
+ QuicFramer framer_;
+ MockEntropyCalculator entropy_calculator_;
+ MockEntropyCalculator peer_entropy_calculator_;
+
+ MockSendAlgorithm* send_algorithm_;
+ std::unique_ptr<MockLossAlgorithm> loss_algorithm_;
+ MockClock clock_;
+ MockRandom random_generator_;
+ SimpleBufferAllocator buffer_allocator_;
+ std::unique_ptr<TestConnectionHelper> helper_;
+ std::unique_ptr<TestAlarmFactory> alarm_factory_;
+ QuicFramer peer_framer_;
+ QuicPacketCreator peer_creator_;
+ std::unique_ptr<TestPacketWriter> writer_;
+ TestConnection connection_;
+ QuicPacketCreator* creator_;
+ QuicPacketGenerator* generator_;
+ QuicSentPacketManagerInterface* manager_;
+ StrictMock<MockQuicConnectionVisitor> visitor_;
+
+ QuicStreamFrame frame1_;
+ QuicStreamFrame frame2_;
+ QuicAckFrame ack_;
+ QuicStopWaitingFrame stop_waiting_;
+ QuicPacketNumberLength packet_number_length_;
+ QuicConnectionIdLength connection_id_length_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicConnectionTest);
+};
+
+// Run all end to end tests with all supported versions.
+INSTANTIATE_TEST_CASE_P(SupportedVersion,
+ QuicConnectionTest,
+ ::testing::ValuesIn(GetTestParams()));
+
+TEST_P(QuicConnectionTest, SelfAddressChangeAtClient) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective());
+ EXPECT_TRUE(connection_.connected());
+
+ QuicStreamFrame stream_frame(1u, false, 0u, StringPiece());
+ EXPECT_CALL(visitor_, OnStreamFrame(_));
+ ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress,
+ kPeerAddress);
+ // Cause change in self_address.
+ IPEndPoint self_address(IPAddress(1, 1, 1, 1), 123);
+ EXPECT_CALL(visitor_, OnStreamFrame(_));
+ ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), self_address,
+ kPeerAddress);
+ EXPECT_TRUE(connection_.connected());
+}
+
+TEST_P(QuicConnectionTest, SelfAddressChangeAtServer) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ set_perspective(Perspective::IS_SERVER);
+ QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+
+ EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
+ EXPECT_TRUE(connection_.connected());
+
+ QuicStreamFrame stream_frame(1u, false, 0u, StringPiece());
+ EXPECT_CALL(visitor_, OnStreamFrame(_));
+ ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress,
+ kPeerAddress);
+ // Cause change in self_address.
+ IPEndPoint self_address(IPAddress(1, 1, 1, 1), 123);
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_ERROR_MIGRATING_ADDRESS, _, _));
+ ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), self_address,
+ kPeerAddress);
+ EXPECT_FALSE(connection_.connected());
+}
+
+TEST_P(QuicConnectionTest, AllowSelfAddressChangeToMappedIpv4AddressAtServer) {
+ FLAGS_quic_allow_server_address_change_for_mapped_ipv4 = true;
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ set_perspective(Perspective::IS_SERVER);
+ QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+
+ EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
+ EXPECT_TRUE(connection_.connected());
+
+ QuicStreamFrame stream_frame(1u, false, 0u, StringPiece());
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(3);
+ IPEndPoint self_address1(IPAddress(1, 1, 1, 1), 443);
+ ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), self_address1,
+ kPeerAddress);
+ // Cause self_address change to mapped Ipv4 address.
+ IPEndPoint self_address2(ConvertIPv4ToIPv4MappedIPv6(self_address1.address()),
+ 443);
+ ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), self_address2,
+ kPeerAddress);
+ EXPECT_TRUE(connection_.connected());
+ // self_address change back to Ipv4 address.
+ ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), self_address1,
+ kPeerAddress);
+ EXPECT_TRUE(connection_.connected());
+}
+
+TEST_P(QuicConnectionTest, ClientAddressChangeAndPacketReordered) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ set_perspective(Perspective::IS_SERVER);
+ QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+ // Clear peer address.
+ QuicConnectionPeer::SetPeerAddress(&connection_, IPEndPoint());
+
+ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 5);
+ QuicStreamFrame stream_frame(1u, false, 0u, StringPiece());
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+ const IPEndPoint kNewPeerAddress = IPEndPoint(Loopback6(),
+ /*port=*/23456);
+ ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress,
+ kNewPeerAddress);
+
+ // Decrease packet number to simulate out-of-order packets.
+ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 4);
+ // This is an old packet, do not migrate.
+ EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
+ ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress,
+ kPeerAddress);
+}
+
+TEST_P(QuicConnectionTest, MaxPacketSize) {
+ EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective());
+ EXPECT_EQ(1350u, connection_.max_packet_length());
+}
+
+TEST_P(QuicConnectionTest, SmallerServerMaxPacketSize) {
+ QuicConnectionId connection_id = 42;
+ TestConnection connection(connection_id, kPeerAddress, helper_.get(),
+ alarm_factory_.get(), writer_.get(),
+ Perspective::IS_SERVER, version());
+ EXPECT_EQ(Perspective::IS_SERVER, connection.perspective());
+ EXPECT_EQ(1000u, connection.max_packet_length());
+}
+
+TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSize) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ set_perspective(Perspective::IS_SERVER);
+ connection_.SetMaxPacketLength(1000);
+
+ QuicPacketHeader header;
+ header.public_header.connection_id = connection_id_;
+ header.public_header.version_flag = true;
+ header.path_id = kDefaultPathId;
+ header.packet_number = 1;
+
+ QuicFrames frames;
+ QuicPaddingFrame padding;
+ frames.push_back(QuicFrame(&frame1_));
+ frames.push_back(QuicFrame(padding));
+ std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length = framer_.EncryptPayload(
+ ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize);
+ EXPECT_EQ(kMaxPacketSize, encrypted_length);
+
+ framer_.set_version(version());
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ connection_.ProcessUdpPacket(
+ kSelfAddress, kPeerAddress,
+ QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
+
+ EXPECT_EQ(kMaxPacketSize, connection_.max_packet_length());
+}
+
+TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSizeWhileWriterLimited) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ const QuicByteCount lower_max_packet_size = 1240;
+ writer_->set_max_packet_size(lower_max_packet_size);
+ set_perspective(Perspective::IS_SERVER);
+ connection_.SetMaxPacketLength(1000);
+ EXPECT_EQ(1000u, connection_.max_packet_length());
+
+ QuicPacketHeader header;
+ header.public_header.connection_id = connection_id_;
+ header.public_header.version_flag = true;
+ header.path_id = kDefaultPathId;
+ header.packet_number = 1;
+
+ QuicFrames frames;
+ QuicPaddingFrame padding;
+ frames.push_back(QuicFrame(&frame1_));
+ frames.push_back(QuicFrame(padding));
+ std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length = framer_.EncryptPayload(
+ ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize);
+ EXPECT_EQ(kMaxPacketSize, encrypted_length);
+
+ framer_.set_version(version());
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ connection_.ProcessUdpPacket(
+ kSelfAddress, kPeerAddress,
+ QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
+
+ // Here, the limit imposed by the writer is lower than the size of the packet
+ // received, so the writer max packet size is used.
+ EXPECT_EQ(lower_max_packet_size, connection_.max_packet_length());
+}
+
+TEST_P(QuicConnectionTest, LimitMaxPacketSizeByWriter) {
+ const QuicByteCount lower_max_packet_size = 1240;
+ writer_->set_max_packet_size(lower_max_packet_size);
+
+ static_assert(lower_max_packet_size < kDefaultMaxPacketSize,
+ "Default maximum packet size is too low");
+ connection_.SetMaxPacketLength(kDefaultMaxPacketSize);
+
+ EXPECT_EQ(lower_max_packet_size, connection_.max_packet_length());
+}
+
+TEST_P(QuicConnectionTest, LimitMaxPacketSizeByWriterForNewConnection) {
+ const QuicConnectionId connection_id = 17;
+ const QuicByteCount lower_max_packet_size = 1240;
+ writer_->set_max_packet_size(lower_max_packet_size);
+ TestConnection connection(connection_id, kPeerAddress, helper_.get(),
+ alarm_factory_.get(), writer_.get(),
+ Perspective::IS_CLIENT, version());
+ EXPECT_EQ(Perspective::IS_CLIENT, connection.perspective());
+ EXPECT_EQ(lower_max_packet_size, connection.max_packet_length());
+}
+
+TEST_P(QuicConnectionTest, PacketsInOrder) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ ProcessPacket(kDefaultPathId, 1);
+ EXPECT_EQ(1u, outgoing_ack()->largest_observed);
+ if (outgoing_ack()->missing) {
+ EXPECT_TRUE(outgoing_ack()->packets.Empty());
+ } else {
+ EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
+ }
+
+ ProcessPacket(kDefaultPathId, 2);
+ EXPECT_EQ(2u, outgoing_ack()->largest_observed);
+ if (outgoing_ack()->missing) {
+ EXPECT_TRUE(outgoing_ack()->packets.Empty());
+ } else {
+ EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
+ }
+
+ ProcessPacket(kDefaultPathId, 3);
+ EXPECT_EQ(3u, outgoing_ack()->largest_observed);
+ if (outgoing_ack()->missing) {
+ EXPECT_TRUE(outgoing_ack()->packets.Empty());
+ } else {
+ EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
+ }
+}
+
+TEST_P(QuicConnectionTest, PacketsOutOfOrder) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ ProcessPacket(kDefaultPathId, 3);
+ EXPECT_EQ(3u, outgoing_ack()->largest_observed);
+ EXPECT_TRUE(IsMissing(2));
+ EXPECT_TRUE(IsMissing(1));
+
+ ProcessPacket(kDefaultPathId, 2);
+ EXPECT_EQ(3u, outgoing_ack()->largest_observed);
+ EXPECT_FALSE(IsMissing(2));
+ EXPECT_TRUE(IsMissing(1));
+
+ ProcessPacket(kDefaultPathId, 1);
+ EXPECT_EQ(3u, outgoing_ack()->largest_observed);
+ EXPECT_FALSE(IsMissing(2));
+ EXPECT_FALSE(IsMissing(1));
+}
+
+TEST_P(QuicConnectionTest, DuplicatePacket) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ ProcessPacket(kDefaultPathId, 3);
+ EXPECT_EQ(3u, outgoing_ack()->largest_observed);
+ EXPECT_TRUE(IsMissing(2));
+ EXPECT_TRUE(IsMissing(1));
+
+ // Send packet 3 again, but do not set the expectation that
+ // the visitor OnStreamFrame() will be called.
+ ProcessDataPacket(kDefaultPathId, 3, !kEntropyFlag);
+ EXPECT_EQ(3u, outgoing_ack()->largest_observed);
+ EXPECT_TRUE(IsMissing(2));
+ EXPECT_TRUE(IsMissing(1));
+}
+
+TEST_P(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ ProcessPacket(kDefaultPathId, 3);
+ EXPECT_EQ(3u, outgoing_ack()->largest_observed);
+ EXPECT_TRUE(IsMissing(2));
+ EXPECT_TRUE(IsMissing(1));
+
+ ProcessPacket(kDefaultPathId, 2);
+ EXPECT_EQ(3u, outgoing_ack()->largest_observed);
+ EXPECT_TRUE(IsMissing(1));
+
+ ProcessPacket(kDefaultPathId, 5);
+ EXPECT_EQ(5u, outgoing_ack()->largest_observed);
+ EXPECT_TRUE(IsMissing(1));
+ EXPECT_TRUE(IsMissing(4));
+
+ // Pretend at this point the client has gotten acks for 2 and 3 and 1 is a
+ // packet the peer will not retransmit. It indicates this by sending 'least
+ // awaiting' is 4. The connection should then realize 1 will not be
+ // retransmitted, and will remove it from the missing list.
+ QuicAckFrame frame = InitAckFrame(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _));
+ ProcessAckPacket(6, &frame);
+
+ // Force an ack to be sent.
+ SendAckPacketToPeer();
+ EXPECT_TRUE(IsMissing(4));
+}
+
+TEST_P(QuicConnectionTest, RejectPacketTooFarOut) {
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, _,
+ ConnectionCloseSource::FROM_SELF));
+ // Call ProcessDataPacket rather than ProcessPacket, as we should not get a
+ // packet call to the visitor.
+ ProcessDataPacket(kDefaultPathId, 6000, !kEntropyFlag);
+ EXPECT_FALSE(QuicConnectionPeer::GetConnectionClosePacket(&connection_) ==
+ nullptr);
+}
+
+TEST_P(QuicConnectionTest, RejectUnencryptedStreamData) {
+ // Process an unencrypted packet from the non-crypto stream.
+ frame1_.stream_id = 3;
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_UNENCRYPTED_STREAM_DATA, _,
+ ConnectionCloseSource::FROM_SELF));
+ EXPECT_QUIC_BUG(ProcessDataPacket(kDefaultPathId, 1, !kEntropyFlag), "");
+ EXPECT_FALSE(QuicConnectionPeer::GetConnectionClosePacket(&connection_) ==
+ nullptr);
+ const vector<QuicConnectionCloseFrame>& connection_close_frames =
+ writer_->connection_close_frames();
+ EXPECT_EQ(1u, connection_close_frames.size());
+ EXPECT_EQ(QUIC_UNENCRYPTED_STREAM_DATA,
+ connection_close_frames[0].error_code);
+}
+
+TEST_P(QuicConnectionTest, TruncatedAck) {
+ if (GetParam().version > QUIC_VERSION_33) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ QuicPacketNumber num_packets = 256 * 2 + 1;
+ for (QuicPacketNumber i = 0; i < num_packets; ++i) {
+ SendStreamDataToPeer(3, "foo", i * 3, !kFin, nullptr);
+ }
+
+ QuicAckFrame frame = InitAckFrame(num_packets);
+ // Create an ack with 256 nacks, none adjacent to one another.
+ for (QuicPacketNumber i = 1; i <= 256; ++i) {
+ NackPacket(i * 2, &frame);
+ }
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+ EXPECT_CALL(peer_entropy_calculator_, EntropyHash(511))
+ .WillOnce(Return(static_cast<QuicPacketEntropyHash>(0)));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&frame);
+
+ // A truncated ack will not have the true largest observed.
+ EXPECT_GT(num_packets, manager_->GetLargestObserved(frame.path_id));
+
+ AckPacket(192, &frame);
+
+ // Removing one missing packet allows us to ack 192 and one more range, but
+ // 192 has already been declared lost, so it doesn't register as an ack.
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&frame);
+ EXPECT_EQ(num_packets, manager_->GetLargestObserved(frame.path_id));
+}
+
+TEST_P(QuicConnectionTest, AckReceiptCausesAckSendBadEntropy) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ ProcessPacket(kDefaultPathId, 1);
+ // Delay sending, then queue up an ack.
+ QuicConnectionPeer::SendAck(&connection_);
+
+ // Process an ack with a least unacked of the received ack.
+ // This causes an ack to be sent when TimeUntilSend returns 0.
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ .WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
+ // Skip a packet and then record an ack.
+ QuicAckFrame frame = InitAckFrame(0);
+ ProcessAckPacket(3, &frame);
+}
+
+TEST_P(QuicConnectionTest, OutOfOrderReceiptCausesAckSend) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ ProcessPacket(kDefaultPathId, 3);
+ // Should ack immediately since we have missing packets.
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+
+ ProcessPacket(kDefaultPathId, 2);
+ // Should ack immediately since we have missing packets.
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+
+ ProcessPacket(kDefaultPathId, 1);
+ // Should ack immediately, since this fills the last hole.
+ EXPECT_EQ(3u, writer_->packets_write_attempts());
+
+ ProcessPacket(kDefaultPathId, 4);
+ // Should not cause an ack.
+ EXPECT_EQ(3u, writer_->packets_write_attempts());
+}
+
+TEST_P(QuicConnectionTest, OutOfOrderAckReceiptCausesNoAck) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ SendStreamDataToPeer(1, "foo", 0, !kFin, nullptr);
+ SendStreamDataToPeer(1, "bar", 3, !kFin, nullptr);
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+
+ QuicAckFrame ack1 = InitAckFrame(1);
+ QuicAckFrame ack2 = InitAckFrame(2);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(2, &ack2);
+ // Should ack immediately since we have missing packets.
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+
+ ProcessAckPacket(1, &ack1);
+ // Should not ack an ack filling a missing packet.
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+}
+
+TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ QuicPacketNumber original;
+ QuicByteCount packet_size;
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(
+ DoAll(SaveArg<2>(&original), SaveArg<3>(&packet_size), Return(true)));
+ connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
+ QuicAckFrame frame = InitAckFrame(original);
+ NackPacket(original, &frame);
+ // First nack triggers early retransmit.
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
+ .WillOnce(SetArgPointee<4>(lost_packets));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ QuicPacketNumber retransmission;
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, _, _, packet_size - kQuicVersionSize, _))
+ .WillOnce(DoAll(SaveArg<2>(&retransmission), Return(true)));
+
+ ProcessAckPacket(&frame);
+
+ QuicAckFrame frame2 = InitAckFrame(retransmission);
+ NackPacket(original, &frame2);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+ ProcessAckPacket(&frame2);
+
+ // Now if the peer sends an ack which still reports the retransmitted packet
+ // as missing, that will bundle an ack with data after two acks in a row
+ // indicate the high water mark needs to be raised.
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA));
+ connection_.SendStreamDataWithString(3, "foo", 3, !kFin, nullptr);
+ // No ack sent.
+ EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+
+ // No more packet loss for the rest of the test.
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _)).Times(AnyNumber());
+ ProcessAckPacket(&frame2);
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA));
+ connection_.SendStreamDataWithString(3, "foo", 3, !kFin, nullptr);
+ // Ack bundled.
+ EXPECT_EQ(3u, writer_->frame_count());
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+
+ // But an ack with no missing packets will not send an ack.
+ AckPacket(original, &frame2);
+ ProcessAckPacket(&frame2);
+ ProcessAckPacket(&frame2);
+}
+
+TEST_P(QuicConnectionTest, 20AcksCausesAckSend) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ SendStreamDataToPeer(1, "foo", 0, !kFin, nullptr);
+
+ QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
+ // But an ack with no missing packets will not send an ack.
+ QuicAckFrame frame = InitAckFrame(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ for (int i = 0; i < 19; ++i) {
+ ProcessAckPacket(&frame);
+ EXPECT_FALSE(ack_alarm->IsSet());
+ }
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+ // The 20th ack packet will cause an ack to be sent.
+ ProcessAckPacket(&frame);
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+}
+
+TEST_P(QuicConnectionTest, LeastUnackedLower) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ SendStreamDataToPeer(1, "foo", 0, !kFin, nullptr);
+ SendStreamDataToPeer(1, "bar", 3, !kFin, nullptr);
+ SendStreamDataToPeer(1, "eep", 6, !kFin, nullptr);
+
+ // Start out saying the least unacked is 2.
+ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 5);
+ QuicStopWaitingFrame frame = InitStopWaitingFrame(2);
+ ProcessStopWaitingPacket(&frame);
+
+ // Change it to 1, but lower the packet number to fake out-of-order packets.
+ // This should be fine.
+ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 1);
+ // The scheduler will not process out of order acks, but all packet processing
+ // causes the connection to try to write.
+ EXPECT_CALL(visitor_, OnCanWrite());
+ QuicStopWaitingFrame frame2 = InitStopWaitingFrame(1);
+ ProcessStopWaitingPacket(&frame2);
+
+ // Now claim it's one, but set the ordering so it was sent "after" the first
+ // one. This should cause a connection error.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 7);
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_STOP_WAITING_DATA, _,
+ ConnectionCloseSource::FROM_SELF));
+ QuicStopWaitingFrame frame3 = InitStopWaitingFrame(1);
+ ProcessStopWaitingPacket(&frame3);
+}
+
+TEST_P(QuicConnectionTest, TooManySentPackets) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ const int num_packets = kMaxTrackedPackets + 100;
+ for (int i = 0; i < num_packets; ++i) {
+ SendStreamDataToPeer(1, "foo", 3 * i, !kFin, nullptr);
+ }
+
+ // Ack packet 1, which leaves more than the limit outstanding.
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ if (GetParam().version <= QUIC_VERSION_33) {
+ EXPECT_CALL(visitor_,
+ OnConnectionClosed(QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS, _,
+ ConnectionCloseSource::FROM_SELF));
+ // We're receive buffer limited, so the connection won't try to write more.
+ EXPECT_CALL(visitor_, OnCanWrite()).Times(0);
+ }
+
+ // Nack the first packet and ack the rest, leaving a huge gap.
+ QuicAckFrame frame1 = InitAckFrame(num_packets);
+ NackPacket(1, &frame1);
+ ProcessAckPacket(&frame1);
+}
+
+TEST_P(QuicConnectionTest, TooManyReceivedPackets) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ if (GetParam().version <= QUIC_VERSION_33) {
+ EXPECT_CALL(visitor_,
+ OnConnectionClosed(QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS,
+ _, ConnectionCloseSource::FROM_SELF));
+ }
+ // Miss 99 of every 100 packets for 5500 packets.
+ for (QuicPacketNumber i = 1; i < kMaxTrackedPackets + 500; i += 100) {
+ ProcessPacket(kDefaultPathId, i);
+ if (!connection_.connected()) {
+ break;
+ }
+ }
+}
+
+TEST_P(QuicConnectionTest, LargestObservedLower) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ SendStreamDataToPeer(1, "foo", 0, !kFin, nullptr);
+ SendStreamDataToPeer(1, "bar", 3, !kFin, nullptr);
+ SendStreamDataToPeer(1, "eep", 6, !kFin, nullptr);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+
+ // Start out saying the largest observed is 2.
+ QuicAckFrame frame1 = InitAckFrame(1);
+ QuicAckFrame frame2 = InitAckFrame(2);
+ ProcessAckPacket(&frame2);
+
+ // Now change it to 1, and it should cause a connection error.
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, _,
+ ConnectionCloseSource::FROM_SELF));
+ EXPECT_CALL(visitor_, OnCanWrite()).Times(0);
+ ProcessAckPacket(&frame1);
+}
+
+TEST_P(QuicConnectionTest, AckUnsentData) {
+ // Ack a packet which has not been sent.
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, _,
+ ConnectionCloseSource::FROM_SELF));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ QuicAckFrame frame(MakeAckFrame(1));
+ EXPECT_CALL(visitor_, OnCanWrite()).Times(0);
+ ProcessAckPacket(&frame);
+}
+
+TEST_P(QuicConnectionTest, AckAll) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ ProcessPacket(kDefaultPathId, 1);
+
+ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 1);
+ QuicAckFrame frame1 = InitAckFrame(0);
+ ProcessAckPacket(&frame1);
+}
+
+TEST_P(QuicConnectionTest, BasicSending) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ QuicPacketNumber last_packet;
+ SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1
+ EXPECT_EQ(1u, last_packet);
+ SendAckPacketToPeer(); // Packet 2
+
+ EXPECT_EQ(1u, least_unacked());
+
+ SendAckPacketToPeer(); // Packet 3
+ EXPECT_EQ(1u, least_unacked());
+
+ SendStreamDataToPeer(1, "bar", 3, !kFin, &last_packet); // Packet 4
+ EXPECT_EQ(4u, last_packet);
+ SendAckPacketToPeer(); // Packet 5
+ EXPECT_EQ(1u, least_unacked());
+
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+
+ // Peer acks up to packet 3.
+ QuicAckFrame frame = InitAckFrame(3);
+ ProcessAckPacket(&frame);
+ SendAckPacketToPeer(); // Packet 6
+
+ // As soon as we've acked one, we skip ack packets 2 and 3 and note lack of
+ // ack for 4.
+ EXPECT_EQ(4u, least_unacked());
+
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+
+ // Peer acks up to packet 4, the last packet.
+ QuicAckFrame frame2 = InitAckFrame(6);
+ ProcessAckPacket(&frame2); // Acks don't instigate acks.
+
+ // Verify that we did not send an ack.
+ EXPECT_EQ(6u, writer_->header().packet_number);
+
+ // So the last ack has not changed.
+ EXPECT_EQ(4u, least_unacked());
+
+ // If we force an ack, we shouldn't change our retransmit state.
+ SendAckPacketToPeer(); // Packet 7
+ EXPECT_EQ(7u, least_unacked());
+
+ // But if we send more data it should.
+ SendStreamDataToPeer(1, "eep", 6, !kFin, &last_packet); // Packet 8
+ EXPECT_EQ(8u, last_packet);
+ SendAckPacketToPeer(); // Packet 9
+ EXPECT_EQ(7u, least_unacked());
+}
+
+// QuicConnection should record the the packet sent-time prior to sending the
+// packet.
+TEST_P(QuicConnectionTest, RecordSentTimeBeforePacketSent) {
+ // We're using a MockClock for the tests, so we have complete control over the
+ // time.
+ // Our recorded timestamp for the last packet sent time will be passed in to
+ // the send_algorithm. Make sure that it is set to the correct value.
+ QuicTime actual_recorded_send_time = QuicTime::Zero();
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true)));
+
+ // First send without any pause and check the result.
+ QuicTime expected_recorded_send_time = clock_.Now();
+ connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
+ EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time)
+ << "Expected time = " << expected_recorded_send_time.ToDebuggingValue()
+ << ". Actual time = " << actual_recorded_send_time.ToDebuggingValue();
+
+ // Now pause during the write, and check the results.
+ actual_recorded_send_time = QuicTime::Zero();
+ const QuicTime::Delta write_pause_time_delta =
+ QuicTime::Delta::FromMilliseconds(5000);
+ SetWritePauseTimeDelta(write_pause_time_delta);
+ expected_recorded_send_time = clock_.Now();
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true)));
+ connection_.SendStreamDataWithString(2, "baz", 0, !kFin, nullptr);
+ EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time)
+ << "Expected time = " << expected_recorded_send_time.ToDebuggingValue()
+ << ". Actual time = " << actual_recorded_send_time.ToDebuggingValue();
+}
+
+TEST_P(QuicConnectionTest, FramePacking) {
+ // Send an ack and two stream frames in 1 packet by queueing them.
+ {
+ QuicConnection::ScopedPacketBundler bundler(&connection_,
+ QuicConnection::SEND_ACK);
+ connection_.SendStreamData3();
+ connection_.SendStreamData5();
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ }
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+ EXPECT_FALSE(connection_.HasQueuedData());
+
+ // Parse the last packet and ensure it's an ack and two stream frames from
+ // two different streams.
+ EXPECT_EQ(4u, writer_->frame_count());
+ EXPECT_FALSE(writer_->stop_waiting_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.
+ {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ QuicConnection::ScopedPacketBundler bundler(&connection_,
+ QuicConnection::SEND_ACK);
+ connection_.SendStreamData3();
+ connection_.SendCryptoStreamData();
+ }
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+ EXPECT_FALSE(connection_.HasQueuedData());
+
+ // Parse the last packet and ensure it's the crypto stream frame.
+ EXPECT_EQ(1u, writer_->frame_count());
+ ASSERT_EQ(1u, writer_->stream_frames().size());
+ EXPECT_EQ(kCryptoStreamId, writer_->stream_frames()[0]->stream_id);
+}
+
+TEST_P(QuicConnectionTest, FramePackingCryptoThenNonCrypto) {
+ // Send an ack and two stream frames (one crypto, then one non-crypto) in 2
+ // packets by queueing them.
+ {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ QuicConnection::ScopedPacketBundler bundler(&connection_,
+ QuicConnection::SEND_ACK);
+ connection_.SendCryptoStreamData();
+ connection_.SendStreamData3();
+ }
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+ EXPECT_FALSE(connection_.HasQueuedData());
+
+ // Parse the last packet and ensure it's the stream frame from stream 3.
+ EXPECT_EQ(1u, writer_->frame_count());
+ ASSERT_EQ(1u, writer_->stream_frames().size());
+ EXPECT_EQ(kClientDataStreamId1, writer_->stream_frames()[0]->stream_id);
+}
+
+TEST_P(QuicConnectionTest, FramePackingAckResponse) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ // Process a data packet to queue up a pending ack.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacket(kDefaultPathId, 1, kEntropyFlag);
+
+ EXPECT_CALL(visitor_, OnCanWrite())
+ .WillOnce(DoAll(IgnoreResult(InvokeWithoutArgs(
+ &connection_, &TestConnection::SendStreamData3)),
+ IgnoreResult(InvokeWithoutArgs(
+ &connection_, &TestConnection::SendStreamData5))));
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+
+ // Process an ack to cause the visitor's OnCanWrite to be invoked.
+ QuicAckFrame ack_one = InitAckFrame(0);
+ ProcessAckPacket(3, &ack_one);
+
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+ EXPECT_FALSE(connection_.HasQueuedData());
+
+ // Parse the last packet and ensure it's an ack and two stream frames from
+ // two different streams.
+ EXPECT_EQ(4u, writer_->frame_count());
+ EXPECT_FALSE(writer_->stop_waiting_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, FramePackingSendv) {
+ // Send data in 1 packet by writing multiple blocks in a single iovector
+ // using writev.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+
+ char data[] = "ABCD";
+ struct iovec iov[2];
+ iov[0].iov_base = data;
+ iov[0].iov_len = 2;
+ iov[1].iov_base = data + 2;
+ iov[1].iov_len = 2;
+ connection_.SendStreamData(1, QuicIOVector(iov, 2, 4), 0, !kFin, nullptr);
+
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+ EXPECT_FALSE(connection_.HasQueuedData());
+
+ // Parse the last packet and ensure multiple iovector blocks have
+ // been packed into a single stream frame from one stream.
+ EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ QuicStreamFrame* frame = writer_->stream_frames()[0];
+ EXPECT_EQ(1u, frame->stream_id);
+ EXPECT_EQ("ABCD", StringPiece(frame->data_buffer, frame->data_length));
+}
+
+TEST_P(QuicConnectionTest, FramePackingSendvQueued) {
+ // Try to send two stream frames in 1 packet by using writev.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+
+ BlockOnNextWrite();
+ char data[] = "ABCD";
+ struct iovec iov[2];
+ iov[0].iov_base = data;
+ iov[0].iov_len = 2;
+ iov[1].iov_base = data + 2;
+ iov[1].iov_len = 2;
+ connection_.SendStreamData(1, QuicIOVector(iov, 2, 4), 0, !kFin, nullptr);
+
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
+ EXPECT_TRUE(connection_.HasQueuedData());
+
+ // Unblock the writes and actually send.
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+
+ // Parse the last packet and ensure it's one stream frame from one stream.
+ EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ EXPECT_EQ(1u, writer_->stream_frames()[0]->stream_id);
+}
+
+TEST_P(QuicConnectionTest, SendingZeroBytes) {
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ // Send a zero byte write with a fin using writev.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ QuicIOVector empty_iov(nullptr, 0, 0);
+ connection_.SendStreamData(kHeadersStreamId, empty_iov, 0, kFin, nullptr);
+
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+ EXPECT_FALSE(connection_.HasQueuedData());
+
+ // Parse the last packet and ensure it's one stream frame from one stream.
+ EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ EXPECT_EQ(kHeadersStreamId, writer_->stream_frames()[0]->stream_id);
+ EXPECT_TRUE(writer_->stream_frames()[0]->fin);
+}
+
+TEST_P(QuicConnectionTest, LargeSendWithPendingAck) {
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ // Set the ack alarm by processing a ping frame.
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ // Processs a PING frame.
+ ProcessFramePacket(QuicFrame(QuicPingFrame()));
+ // Ensure that this has caused the ACK alarm to be set.
+ QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
+ EXPECT_TRUE(ack_alarm->IsSet());
+
+ // Send data and ensure the ack is bundled.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(8);
+ size_t len = 10000;
+ std::unique_ptr<char[]> data_array(new char[len]);
+ memset(data_array.get(), '?', len);
+ struct iovec iov;
+ iov.iov_base = data_array.get();
+ iov.iov_len = len;
+ QuicIOVector iovector(&iov, 1, len);
+ QuicConsumedData consumed =
+ connection_.SendStreamData(kHeadersStreamId, iovector, 0, true, nullptr);
+ EXPECT_EQ(len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+ EXPECT_FALSE(connection_.HasQueuedData());
+
+ // Parse the last packet and ensure it's one stream frame with a fin.
+ EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ EXPECT_EQ(kHeadersStreamId, writer_->stream_frames()[0]->stream_id);
+ EXPECT_TRUE(writer_->stream_frames()[0]->fin);
+ // Ensure the ack alarm was cancelled when the ack was sent.
+ EXPECT_FALSE(ack_alarm->IsSet());
+}
+
+TEST_P(QuicConnectionTest, OnCanWrite) {
+ // Visitor's OnCanWrite will send data, but will have more pending writes.
+ EXPECT_CALL(visitor_, OnCanWrite())
+ .WillOnce(DoAll(IgnoreResult(InvokeWithoutArgs(
+ &connection_, &TestConnection::SendStreamData3)),
+ IgnoreResult(InvokeWithoutArgs(
+ &connection_, &TestConnection::SendStreamData5))));
+ {
+ InSequence seq;
+ EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillOnce(Return(true));
+ EXPECT_CALL(visitor_, WillingAndAbleToWrite())
+ .WillRepeatedly(Return(false));
+ }
+
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ .WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
+
+ connection_.OnCanWrite();
+
+ // Parse the last packet and ensure it's the two stream frames from
+ // two different streams.
+ EXPECT_EQ(2u, writer_->frame_count());
+ EXPECT_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, RetransmitOnNack) {
+ QuicPacketNumber last_packet;
+ QuicByteCount second_packet_size;
+ SendStreamDataToPeer(3, "foo", 0, !kFin, &last_packet); // Packet 1
+ second_packet_size =
+ SendStreamDataToPeer(3, "foos", 3, !kFin, &last_packet); // Packet 2
+ SendStreamDataToPeer(3, "fooos", 7, !kFin, &last_packet); // Packet 3
+
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ // Don't lose a packet on an ack, and nothing is retransmitted.
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ QuicAckFrame ack_one = InitAckFrame(1);
+ ProcessAckPacket(&ack_one);
+
+ // Lose a packet and ensure it triggers retransmission.
+ QuicAckFrame nack_two = InitAckFrame(3);
+ NackPacket(2, &nack_two);
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ lost_packets.push_back(std::make_pair(2, kMaxPacketSize));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
+ .WillOnce(SetArgPointee<4>(lost_packets));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, _, _, second_packet_size - kQuicVersionSize, _))
+ .Times(1);
+ ProcessAckPacket(&nack_two);
+}
+
+TEST_P(QuicConnectionTest, DoNotSendQueuedPacketForResetStream) {
+ // Block the connection to queue the packet.
+ BlockOnNextWrite();
+
+ QuicStreamId stream_id = 2;
+ connection_.SendStreamDataWithString(stream_id, "foo", 0, !kFin, nullptr);
+
+ // Now that there is a queued packet, reset the stream.
+ connection_.SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 14);
+
+ // Unblock the connection and verify that only the RST_STREAM is sent.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+ EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(1u, writer_->rst_stream_frames().size());
+}
+
+TEST_P(QuicConnectionTest, SendQueuedPacketForQuicRstStreamNoError) {
+ // Block the connection to queue the packet.
+ BlockOnNextWrite();
+
+ QuicStreamId stream_id = 2;
+ connection_.SendStreamDataWithString(stream_id, "foo", 0, !kFin, nullptr);
+
+ // Now that there is a queued packet, reset the stream.
+ connection_.SendRstStream(stream_id, QUIC_STREAM_NO_ERROR, 14);
+
+ // Unblock the connection and verify that the RST_STREAM is sent and the data
+ // packet is sent.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(2));
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+ EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(1u, writer_->rst_stream_frames().size());
+}
+
+TEST_P(QuicConnectionTest, DoNotRetransmitForResetStreamOnNack) {
+ QuicStreamId stream_id = 2;
+ QuicPacketNumber last_packet;
+ SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
+ SendStreamDataToPeer(stream_id, "foos", 3, !kFin, &last_packet);
+ SendStreamDataToPeer(stream_id, "fooos", 7, !kFin, &last_packet);
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 14);
+
+ // Lose a packet and ensure it does not trigger retransmission.
+ QuicAckFrame nack_two = InitAckFrame(last_packet);
+ NackPacket(last_packet - 1, &nack_two);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ ProcessAckPacket(&nack_two);
+}
+
+TEST_P(QuicConnectionTest, RetransmitForQuicRstStreamNoErrorOnNack) {
+ QuicStreamId stream_id = 2;
+ QuicPacketNumber last_packet;
+ SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
+ SendStreamDataToPeer(stream_id, "foos", 3, !kFin, &last_packet);
+ SendStreamDataToPeer(stream_id, "fooos", 7, !kFin, &last_packet);
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendRstStream(stream_id, QUIC_STREAM_NO_ERROR, 14);
+
+ // Lose a packet, ensure it triggers retransmission.
+ QuicAckFrame nack_two = InitAckFrame(last_packet);
+ NackPacket(last_packet - 1, &nack_two);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ lost_packets.push_back(std::make_pair(last_packet - 1, kMaxPacketSize));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
+ .WillOnce(SetArgPointee<4>(lost_packets));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
+ ProcessAckPacket(&nack_two);
+}
+
+TEST_P(QuicConnectionTest, DoNotRetransmitForResetStreamOnRTO) {
+ QuicStreamId stream_id = 2;
+ QuicPacketNumber last_packet;
+ SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 14);
+
+ // Fire the RTO and verify that the RST_STREAM is resent, not stream data.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ clock_.AdvanceTime(DefaultRetransmissionTime());
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(1u, writer_->rst_stream_frames().size());
+ EXPECT_EQ(stream_id, writer_->rst_stream_frames().front().stream_id);
+}
+
+TEST_P(QuicConnectionTest, RetransmitForQuicRstStreamNoErrorOnRTO) {
+ connection_.SetMaxTailLossProbes(kDefaultPathId, 0);
+
+ QuicStreamId stream_id = 2;
+ QuicPacketNumber last_packet;
+ SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendRstStream(stream_id, QUIC_STREAM_NO_ERROR, 14);
+
+ // Fire the RTO and verify that the RST_STREAM is resent, the stream data
+ // is sent.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(2));
+ clock_.AdvanceTime(DefaultRetransmissionTime());
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_EQ(1u, writer_->frame_count());
+ ASSERT_EQ(1u, writer_->rst_stream_frames().size());
+ EXPECT_EQ(stream_id, writer_->rst_stream_frames().front().stream_id);
+}
+
+TEST_P(QuicConnectionTest, DoNotSendPendingRetransmissionForResetStream) {
+ QuicStreamId stream_id = 2;
+ QuicPacketNumber last_packet;
+ SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
+ SendStreamDataToPeer(stream_id, "foos", 3, !kFin, &last_packet);
+ BlockOnNextWrite();
+ connection_.SendStreamDataWithString(stream_id, "fooos", 7, !kFin, nullptr);
+
+ // Lose a packet which will trigger a pending retransmission.
+ QuicAckFrame ack = InitAckFrame(last_packet);
+ NackPacket(last_packet - 1, &ack);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ ProcessAckPacket(&ack);
+
+ connection_.SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 14);
+
+ // Unblock the connection and verify that the RST_STREAM is sent but not the
+ // second data packet nor a retransmit.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+ EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(1u, writer_->rst_stream_frames().size());
+ EXPECT_EQ(stream_id, writer_->rst_stream_frames().front().stream_id);
+}
+
+TEST_P(QuicConnectionTest, SendPendingRetransmissionForQuicRstStreamNoError) {
+ QuicStreamId stream_id = 2;
+ QuicPacketNumber last_packet;
+ SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
+ SendStreamDataToPeer(stream_id, "foos", 3, !kFin, &last_packet);
+ BlockOnNextWrite();
+ connection_.SendStreamDataWithString(stream_id, "fooos", 7, !kFin, nullptr);
+
+ // Lose a packet which will trigger a pending retransmission.
+ QuicAckFrame ack = InitAckFrame(last_packet);
+ NackPacket(last_packet - 1, &ack);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ lost_packets.push_back(std::make_pair(last_packet - 1, kMaxPacketSize));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
+ .WillOnce(SetArgPointee<4>(lost_packets));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ ProcessAckPacket(&ack);
+
+ connection_.SendRstStream(stream_id, QUIC_STREAM_NO_ERROR, 14);
+
+ // Unblock the connection and verify that the RST_STREAM is sent and the
+ // second data packet or a retransmit is sent.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(2));
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+ EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(0u, writer_->rst_stream_frames().size());
+}
+
+TEST_P(QuicConnectionTest, RetransmitAckedPacket) {
+ QuicPacketNumber last_packet;
+ SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1
+ SendStreamDataToPeer(1, "foos", 3, !kFin, &last_packet); // Packet 2
+ SendStreamDataToPeer(1, "fooos", 7, !kFin, &last_packet); // Packet 3
+
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ // Instigate a loss with an ack.
+ QuicAckFrame nack_two = InitAckFrame(3);
+ NackPacket(2, &nack_two);
+ // The first nack should trigger a fast retransmission, but we'll be
+ // write blocked, so the packet will be queued.
+ BlockOnNextWrite();
+
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ lost_packets.push_back(std::make_pair(2, kMaxPacketSize));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
+ .WillOnce(SetArgPointee<4>(lost_packets));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&nack_two);
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
+
+ // Now, ack the previous transmission.
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+ QuicAckFrame ack_all = InitAckFrame(3);
+ ProcessAckPacket(&ack_all);
+
+ // Unblock the socket and attempt to send the queued packets. We will always
+ // send the retransmission.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 4, _, _)).Times(1);
+
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+ // We do not store retransmittable frames of this retransmission.
+ EXPECT_FALSE(QuicConnectionPeer::HasRetransmittableFrames(&connection_,
+ kDefaultPathId, 4));
+}
+
+TEST_P(QuicConnectionTest, RetransmitNackedLargestObserved) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ QuicPacketNumber largest_observed;
+ QuicByteCount packet_size;
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<2>(&largest_observed), SaveArg<3>(&packet_size),
+ Return(true)));
+ connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
+
+ QuicAckFrame frame = InitAckFrame(1);
+ NackPacket(largest_observed, &frame);
+ // The first nack should retransmit the largest observed packet.
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
+ .WillOnce(SetArgPointee<4>(lost_packets));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, _, _, packet_size - kQuicVersionSize, _));
+ ProcessAckPacket(&frame);
+}
+
+TEST_P(QuicConnectionTest, QueueAfterTwoRTOs) {
+ connection_.SetMaxTailLossProbes(kDefaultPathId, 0);
+
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendStreamDataWithString(3, "foo", i * 3, !kFin, nullptr);
+ }
+
+ // Block the writer and ensure they're queued.
+ BlockOnNextWrite();
+ clock_.AdvanceTime(DefaultRetransmissionTime());
+ // Only one packet should be retransmitted.
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_TRUE(connection_.HasQueuedData());
+
+ // Unblock the writer.
+ writer_->SetWritable();
+ clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(
+ 2 * DefaultRetransmissionTime().ToMicroseconds()));
+ // Retransmit already retransmitted packets event though the packet number
+ // greater than the largest observed.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ connection_.GetRetransmissionAlarm()->Fire();
+ connection_.OnCanWrite();
+}
+
+TEST_P(QuicConnectionTest, WriteBlockedBufferedThenSent) {
+ BlockOnNextWrite();
+ writer_->set_is_write_blocked_data_buffered(true);
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, WriteBlockedThenSent) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ BlockOnNextWrite();
+ connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
+
+ // The second packet should also be queued, in order to ensure packets are
+ // never sent out of order.
+ writer_->SetWritable();
+ connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
+ EXPECT_EQ(2u, connection_.NumQueuedPackets());
+
+ // Now both are sent in order when we unblock.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ connection_.OnCanWrite();
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ BlockOnNextWrite();
+ writer_->set_is_write_blocked_data_buffered(true);
+ // Simulate the retransmission alarm firing.
+ clock_.AdvanceTime(DefaultRetransmissionTime());
+ connection_.GetRetransmissionAlarm()->Fire();
+
+ // Ack the sent packet before the callback returns, which happens in
+ // rare circumstances with write blocked sockets.
+ QuicAckFrame ack = InitAckFrame(1);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&ack);
+
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+ // There is now a pending packet, but with no retransmittable frames.
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+ EXPECT_FALSE(QuicConnectionPeer::HasRetransmittableFrames(&connection_,
+ ack.path_id, 2));
+}
+
+TEST_P(QuicConnectionTest, AlarmsWhenWriteBlocked) {
+ // Block the connection.
+ BlockOnNextWrite();
+ connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+ EXPECT_TRUE(writer_->IsWriteBlocked());
+
+ // Set the send and resumption alarms. Fire the alarms and ensure they don't
+ // attempt to write.
+ connection_.GetResumeWritesAlarm()->Set(clock_.ApproximateNow());
+ connection_.GetSendAlarm()->Set(clock_.ApproximateNow());
+ connection_.GetResumeWritesAlarm()->Fire();
+ connection_.GetSendAlarm()->Fire();
+ EXPECT_TRUE(writer_->IsWriteBlocked());
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+}
+
+TEST_P(QuicConnectionTest, NoLimitPacketsPerNack) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ int offset = 0;
+ // Send packets 1 to 15.
+ for (int i = 0; i < 15; ++i) {
+ SendStreamDataToPeer(1, "foo", offset, !kFin, nullptr);
+ offset += 3;
+ }
+
+ // Ack 15, nack 1-14.
+
+ QuicAckFrame nack = InitAckFrame(15);
+ for (int i = 1; i < 15; ++i) {
+ NackPacket(i, &nack);
+ }
+
+ // 14 packets have been NACK'd and lost.
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ for (int i = 1; i < 15; ++i) {
+ lost_packets.push_back(std::make_pair(i, kMaxPacketSize));
+ }
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
+ .WillOnce(SetArgPointee<4>(lost_packets));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(14);
+ ProcessAckPacket(&nack);
+}
+
+// Test sending multiple acks from the connection to the session.
+TEST_P(QuicConnectionTest, MultipleAcks) {
+ QuicPacketNumber last_packet;
+ SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1
+ EXPECT_EQ(1u, last_packet);
+ SendStreamDataToPeer(3, "foo", 0, !kFin, &last_packet); // Packet 2
+ EXPECT_EQ(2u, last_packet);
+ SendAckPacketToPeer(); // Packet 3
+ SendStreamDataToPeer(5, "foo", 0, !kFin, &last_packet); // Packet 4
+ EXPECT_EQ(4u, last_packet);
+ SendStreamDataToPeer(1, "foo", 3, !kFin, &last_packet); // Packet 5
+ EXPECT_EQ(5u, last_packet);
+ SendStreamDataToPeer(3, "foo", 3, !kFin, &last_packet); // Packet 6
+ EXPECT_EQ(6u, last_packet);
+
+ // Client will ack packets 1, 2, [!3], 4, 5.
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ QuicAckFrame frame1 = InitAckFrame(5);
+ NackPacket(3, &frame1);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ ProcessAckPacket(&frame1);
+
+ // Now the client implicitly acks 3, and explicitly acks 6.
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ QuicAckFrame frame2 = InitAckFrame(6);
+ ProcessAckPacket(&frame2);
+}
+
+TEST_P(QuicConnectionTest, DontLatchUnackedPacket) {
+ SendStreamDataToPeer(1, "foo", 0, !kFin, nullptr); // Packet 1;
+ // From now on, we send acks, so the send algorithm won't mark them pending.
+ ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillByDefault(Return(false));
+ SendAckPacketToPeer(); // Packet 2
+
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ QuicAckFrame frame = InitAckFrame(1);
+ ProcessAckPacket(&frame);
+
+ // Verify that our internal state has least-unacked as 2, because we're still
+ // waiting for a potential ack for 2.
+
+ EXPECT_EQ(2u, stop_waiting()->least_unacked);
+
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ frame = InitAckFrame(2);
+ ProcessAckPacket(&frame);
+ EXPECT_EQ(3u, stop_waiting()->least_unacked);
+
+ // When we send an ack, we make sure our least-unacked makes sense. In this
+ // case since we're not waiting on an ack for 2 and all packets are acked, we
+ // set it to 3.
+ SendAckPacketToPeer(); // Packet 3
+ // Least_unacked remains at 3 until another ack is received.
+ EXPECT_EQ(3u, stop_waiting()->least_unacked);
+ // Check that the outgoing ack had its packet number as least_unacked.
+ EXPECT_EQ(3u, least_unacked());
+
+ // Ack the ack, which updates the rtt and raises the least unacked.
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ frame = InitAckFrame(3);
+ ProcessAckPacket(&frame);
+
+ ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillByDefault(Return(true));
+ SendStreamDataToPeer(1, "bar", 3, false, nullptr); // Packet 4
+ EXPECT_EQ(4u, stop_waiting()->least_unacked);
+ ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillByDefault(Return(false));
+ SendAckPacketToPeer(); // Packet 5
+ EXPECT_EQ(4u, least_unacked());
+
+ // Send two data packets at the end, and ensure if the last one is acked,
+ // the least unacked is raised above the ack packets.
+ ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillByDefault(Return(true));
+ SendStreamDataToPeer(1, "bar", 6, false, nullptr); // Packet 6
+ SendStreamDataToPeer(1, "bar", 9, false, nullptr); // Packet 7
+
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ frame = InitAckFrame(7);
+ NackPacket(5, &frame);
+ NackPacket(6, &frame);
+ ProcessAckPacket(&frame);
+
+ EXPECT_EQ(6u, stop_waiting()->least_unacked);
+}
+
+TEST_P(QuicConnectionTest, TLP) {
+ connection_.SetMaxTailLossProbes(kDefaultPathId, 1);
+
+ SendStreamDataToPeer(3, "foo", 0, !kFin, nullptr);
+ EXPECT_EQ(1u, stop_waiting()->least_unacked);
+ QuicTime retransmission_time =
+ connection_.GetRetransmissionAlarm()->deadline();
+ EXPECT_NE(QuicTime::Zero(), retransmission_time);
+
+ EXPECT_EQ(1u, writer_->header().packet_number);
+ // Simulate the retransmission alarm firing and sending a tlp,
+ // so send algorithm's OnRetransmissionTimeout is not called.
+ clock_.AdvanceTime(retransmission_time - clock_.Now());
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_EQ(2u, writer_->header().packet_number);
+ // We do not raise the high water mark yet.
+ EXPECT_EQ(1u, stop_waiting()->least_unacked);
+}
+
+TEST_P(QuicConnectionTest, RTO) {
+ connection_.SetMaxTailLossProbes(kDefaultPathId, 0);
+
+ QuicTime default_retransmission_time =
+ clock_.ApproximateNow() + DefaultRetransmissionTime();
+ SendStreamDataToPeer(3, "foo", 0, !kFin, nullptr);
+ EXPECT_EQ(1u, stop_waiting()->least_unacked);
+
+ EXPECT_EQ(1u, writer_->header().packet_number);
+ EXPECT_EQ(default_retransmission_time,
+ connection_.GetRetransmissionAlarm()->deadline());
+ // Simulate the retransmission alarm firing.
+ clock_.AdvanceTime(DefaultRetransmissionTime());
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_EQ(2u, writer_->header().packet_number);
+ // We do not raise the high water mark yet.
+ EXPECT_EQ(1u, stop_waiting()->least_unacked);
+}
+
+TEST_P(QuicConnectionTest, RetransmitWithSameEncryptionLevel) {
+ use_tagging_decrypter();
+
+ // A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at
+ // the end of the packet. We can test this to check which encrypter was used.
+ connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01));
+ SendStreamDataToPeer(kCryptoStreamId, "foo", 0, !kFin, nullptr);
+ EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet());
+
+ connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ SendStreamDataToPeer(3, "foo", 0, !kFin, nullptr);
+ EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+
+ {
+ InSequence s;
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 3, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 4, _, _));
+ }
+
+ // Manually mark both packets for retransmission.
+ connection_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION);
+
+ // Packet should have been sent with ENCRYPTION_NONE.
+ EXPECT_EQ(0x01010101u, writer_->final_bytes_of_previous_packet());
+
+ // Packet should have been sent with ENCRYPTION_INITIAL.
+ EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
+}
+
+TEST_P(QuicConnectionTest, SendHandshakeMessages) {
+ use_tagging_decrypter();
+ // A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at
+ // the end of the packet. We can test this to check which encrypter was used.
+ connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01));
+
+ // Attempt to send a handshake message and have the socket block.
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ .WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
+ BlockOnNextWrite();
+ connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
+ // The packet should be serialized, but not queued.
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
+
+ // Switch to the new encrypter.
+ connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+
+ // Now become writeable and flush the packets.
+ writer_->SetWritable();
+ EXPECT_CALL(visitor_, OnCanWrite());
+ connection_.OnCanWrite();
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+
+ // Verify that the handshake packet went out at the null encryption.
+ EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet());
+}
+
+TEST_P(QuicConnectionTest,
+ DropRetransmitsForNullEncryptedPacketAfterForwardSecure) {
+ use_tagging_decrypter();
+ connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01));
+ QuicPacketNumber packet_number;
+ SendStreamDataToPeer(kCryptoStreamId, "foo", 0, !kFin, &packet_number);
+
+ // Simulate the retransmission alarm firing and the socket blocking.
+ BlockOnNextWrite();
+ clock_.AdvanceTime(DefaultRetransmissionTime());
+ connection_.GetRetransmissionAlarm()->Fire();
+
+ // Go forward secure.
+ connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+ new TaggingEncrypter(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ connection_.NeuterUnencryptedPackets();
+
+ EXPECT_EQ(QuicTime::Zero(), connection_.GetRetransmissionAlarm()->deadline());
+ // Unblock the socket and ensure that no packets are sent.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+}
+
+TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) {
+ use_tagging_decrypter();
+ connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_NONE);
+
+ SendStreamDataToPeer(1, "foo", 0, !kFin, nullptr);
+
+ connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(0x02));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+
+ SendStreamDataToPeer(2, "bar", 0, !kFin, nullptr);
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+
+ connection_.RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
+}
+
+TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) {
+ // SetFromConfig is always called after construction from InitializeSession.
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ connection_.SetFromConfig(config);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ use_tagging_decrypter();
+
+ const uint8_t tag = 0x07;
+ framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
+
+ // Process an encrypted packet which can not yet be decrypted which should
+ // result in the packet being buffered.
+ ProcessDataPacketAtLevel(kDefaultPathId, 1, kEntropyFlag, !kHasStopWaiting,
+ ENCRYPTION_INITIAL);
+
+ // Transition to the new encryption state and process another encrypted packet
+ // which should result in the original packet being processed.
+ connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(2);
+ ProcessDataPacketAtLevel(kDefaultPathId, 2, kEntropyFlag, !kHasStopWaiting,
+ ENCRYPTION_INITIAL);
+
+ // Finally, process a third packet and note that we do not reprocess the
+ // buffered packet.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, 3, kEntropyFlag, !kHasStopWaiting,
+ ENCRYPTION_INITIAL);
+}
+
+TEST_P(QuicConnectionTest, Buffer100NonDecryptablePackets) {
+ // SetFromConfig is always called after construction from InitializeSession.
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ config.set_max_undecryptable_packets(100);
+ connection_.SetFromConfig(config);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ use_tagging_decrypter();
+
+ const uint8_t tag = 0x07;
+ framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
+
+ // Process an encrypted packet which can not yet be decrypted which should
+ // result in the packet being buffered.
+ for (QuicPacketNumber i = 1; i <= 100; ++i) {
+ ProcessDataPacketAtLevel(kDefaultPathId, i, kEntropyFlag, !kHasStopWaiting,
+ ENCRYPTION_INITIAL);
+ }
+
+ // Transition to the new encryption state and process another encrypted packet
+ // which should result in the original packets being processed.
+ connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(101);
+ ProcessDataPacketAtLevel(kDefaultPathId, 101, kEntropyFlag, !kHasStopWaiting,
+ ENCRYPTION_INITIAL);
+
+ // Finally, process a third packet and note that we do not reprocess the
+ // buffered packet.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, 102, kEntropyFlag, !kHasStopWaiting,
+ ENCRYPTION_INITIAL);
+}
+
+TEST_P(QuicConnectionTest, TestRetransmitOrder) {
+ connection_.SetMaxTailLossProbes(kDefaultPathId, 0);
+
+ QuicByteCount first_packet_size;
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<3>(&first_packet_size), Return(true)));
+
+ connection_.SendStreamDataWithString(3, "first_packet", 0, !kFin, nullptr);
+ QuicByteCount second_packet_size;
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<3>(&second_packet_size), Return(true)));
+ connection_.SendStreamDataWithString(3, "second_packet", 12, !kFin, nullptr);
+ EXPECT_NE(first_packet_size, second_packet_size);
+ // Advance the clock by huge time to make sure packets will be retransmitted.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
+ {
+ InSequence s;
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, first_packet_size, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, second_packet_size, _));
+ }
+ connection_.GetRetransmissionAlarm()->Fire();
+
+ // Advance again and expect the packets to be sent again in the same order.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(20));
+ {
+ InSequence s;
+ EXPECT_CALL(visitor_, OnPathDegrading());
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, first_packet_size, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, second_packet_size, _));
+ }
+ connection_.GetRetransmissionAlarm()->Fire();
+}
+
+TEST_P(QuicConnectionTest, SetRTOAfterWritingToSocket) {
+ BlockOnNextWrite();
+ connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
+ // Make sure that RTO is not started when the packet is queued.
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+
+ // Test that RTO is started once we write to the socket.
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+ EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, DelayRTOWithAckReceipt) {
+ connection_.SetMaxTailLossProbes(kDefaultPathId, 0);
+
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ connection_.SendStreamDataWithString(2, "foo", 0, !kFin, nullptr);
+ connection_.SendStreamDataWithString(3, "bar", 0, !kFin, nullptr);
+ QuicAlarm* retransmission_alarm = connection_.GetRetransmissionAlarm();
+ EXPECT_TRUE(retransmission_alarm->IsSet());
+ EXPECT_EQ(clock_.Now() + DefaultRetransmissionTime(),
+ retransmission_alarm->deadline());
+
+ // Advance the time right before the RTO, then receive an ack for the first
+ // packet to delay the RTO.
+ clock_.AdvanceTime(DefaultRetransmissionTime());
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ QuicAckFrame ack = InitAckFrame(1);
+ ProcessAckPacket(&ack);
+ // Now we have an RTT sample of DefaultRetransmissionTime(500ms),
+ // so the RTO has increased to 2 * SRTT.
+ EXPECT_TRUE(retransmission_alarm->IsSet());
+ EXPECT_EQ(retransmission_alarm->deadline(),
+ clock_.Now() + 2 * DefaultRetransmissionTime());
+
+ // Move forward past the original RTO and ensure the RTO is still pending.
+ clock_.AdvanceTime(2 * DefaultRetransmissionTime());
+
+ // Ensure the second packet gets retransmitted when it finally fires.
+ EXPECT_TRUE(retransmission_alarm->IsSet());
+ EXPECT_EQ(retransmission_alarm->deadline(), clock_.ApproximateNow());
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ // Manually cancel the alarm to simulate a real test.
+ connection_.GetRetransmissionAlarm()->Fire();
+
+ // The new retransmitted packet number should set the RTO to a larger value
+ // than previously.
+ EXPECT_TRUE(retransmission_alarm->IsSet());
+ QuicTime next_rto_time = retransmission_alarm->deadline();
+ QuicTime expected_rto_time =
+ connection_.sent_packet_manager().GetRetransmissionTime();
+ EXPECT_EQ(next_rto_time, expected_rto_time);
+}
+
+TEST_P(QuicConnectionTest, TestQueued) {
+ connection_.SetMaxTailLossProbes(kDefaultPathId, 0);
+
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+ BlockOnNextWrite();
+ connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
+
+ // Unblock the writes and actually send.
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+}
+
+TEST_P(QuicConnectionTest, InitialTimeout) {
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
+ EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
+
+ // SetFromConfig sets the initial timeouts before negotiation.
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ connection_.SetFromConfig(config);
+ // Subtract a second from the idle timeout on the client side.
+ QuicTime default_timeout =
+ clock_.ApproximateNow() +
+ QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
+ EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
+
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NETWORK_IDLE_TIMEOUT, _,
+ ConnectionCloseSource::FROM_SELF));
+ // Simulate the timeout alarm firing.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1));
+ connection_.GetTimeoutAlarm()->Fire();
+
+ EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_FALSE(connection_.connected());
+
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
+ EXPECT_FALSE(connection_.GetResumeWritesAlarm()->IsSet());
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ EXPECT_FALSE(connection_.GetSendAlarm()->IsSet());
+ EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, HandshakeTimeout) {
+ // Use a shorter handshake timeout than idle timeout for this test.
+ const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(5);
+ connection_.SetNetworkTimeouts(timeout, timeout);
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
+
+ QuicTime handshake_timeout =
+ clock_.ApproximateNow() + timeout - QuicTime::Delta::FromSeconds(1);
+ EXPECT_EQ(handshake_timeout, connection_.GetTimeoutAlarm()->deadline());
+ EXPECT_TRUE(connection_.connected());
+
+ // Send and ack new data 3 seconds later to lengthen the idle timeout.
+ SendStreamDataToPeer(kHeadersStreamId, "GET /", 0, kFin, nullptr);
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(3));
+ QuicAckFrame frame = InitAckFrame(1);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&frame);
+
+ // Fire early to verify it wouldn't timeout yet.
+ connection_.GetTimeoutAlarm()->Fire();
+ EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_TRUE(connection_.connected());
+
+ clock_.AdvanceTime(timeout - QuicTime::Delta::FromSeconds(2));
+
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_HANDSHAKE_TIMEOUT, _,
+ ConnectionCloseSource::FROM_SELF));
+ // Simulate the timeout alarm firing.
+ connection_.GetTimeoutAlarm()->Fire();
+
+ EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_FALSE(connection_.connected());
+
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
+ EXPECT_FALSE(connection_.GetResumeWritesAlarm()->IsSet());
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ EXPECT_FALSE(connection_.GetSendAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, PingAfterSend) {
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(visitor_, HasOpenDynamicStreams()).WillRepeatedly(Return(true));
+ EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
+
+ // Advance to 5ms, and send a packet to the peer, which will set
+ // the ping alarm.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ SendStreamDataToPeer(kHeadersStreamId, "GET /", 0, kFin, nullptr);
+ EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
+ EXPECT_EQ(clock_.ApproximateNow() + QuicTime::Delta::FromSeconds(15),
+ connection_.GetPingAlarm()->deadline());
+
+ // Now recevie and ACK of the previous packet, which will move the
+ // ping alarm forward.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+ QuicAckFrame frame = InitAckFrame(1);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&frame);
+ EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
+ // The ping timer is set slightly less than 15 seconds in the future, because
+ // of the 1s ping timer alarm granularity.
+ EXPECT_EQ(clock_.ApproximateNow() + QuicTime::Delta::FromSeconds(15) -
+ QuicTime::Delta::FromMilliseconds(5),
+ connection_.GetPingAlarm()->deadline());
+
+ writer_->Reset();
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(15));
+ connection_.GetPingAlarm()->Fire();
+ EXPECT_EQ(1u, writer_->frame_count());
+ ASSERT_EQ(1u, writer_->ping_frames().size());
+ writer_->Reset();
+
+ EXPECT_CALL(visitor_, HasOpenDynamicStreams()).WillRepeatedly(Return(false));
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+ SendAckPacketToPeer();
+
+ EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, ReducedPingTimeout) {
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(visitor_, HasOpenDynamicStreams()).WillRepeatedly(Return(true));
+ EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
+
+ // Use a reduced ping timeout for this connection.
+ connection_.set_ping_timeout(QuicTime::Delta::FromSeconds(10));
+
+ // Advance to 5ms, and send a packet to the peer, which will set
+ // the ping alarm.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+ EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+ SendStreamDataToPeer(kHeadersStreamId, "GET /", 0, kFin, nullptr);
+ EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
+ EXPECT_EQ(clock_.ApproximateNow() + QuicTime::Delta::FromSeconds(10),
+ connection_.GetPingAlarm()->deadline());
+
+ // Now recevie and ACK of the previous packet, which will move the
+ // ping alarm forward.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+ QuicAckFrame frame = InitAckFrame(1);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&frame);
+ EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
+ // The ping timer is set slightly less than 10 seconds in the future, because
+ // of the 1s ping timer alarm granularity.
+ EXPECT_EQ(clock_.ApproximateNow() + QuicTime::Delta::FromSeconds(10) -
+ QuicTime::Delta::FromMilliseconds(5),
+ connection_.GetPingAlarm()->deadline());
+
+ writer_->Reset();
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
+ connection_.GetPingAlarm()->Fire();
+ EXPECT_EQ(1u, writer_->frame_count());
+ ASSERT_EQ(1u, writer_->ping_frames().size());
+ writer_->Reset();
+
+ EXPECT_CALL(visitor_, HasOpenDynamicStreams()).WillRepeatedly(Return(false));
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+ SendAckPacketToPeer();
+
+ EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
+}
+
+// Tests whether sending an MTU discovery packet to peer successfully causes the
+// maximum packet size to increase.
+TEST_P(QuicConnectionTest, SendMtuDiscoveryPacket) {
+ EXPECT_TRUE(connection_.connected());
+
+ // Send an MTU probe.
+ const size_t new_mtu = kDefaultMaxPacketSize + 100;
+ QuicByteCount mtu_probe_size;
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<3>(&mtu_probe_size), Return(true)));
+ connection_.SendMtuDiscoveryPacket(new_mtu);
+ EXPECT_EQ(new_mtu, mtu_probe_size);
+ EXPECT_EQ(1u, creator_->packet_number());
+
+ // Send more than MTU worth of data. No acknowledgement was received so far,
+ // so the MTU should be at its old value.
+ const string data(kDefaultMaxPacketSize + 1, '.');
+ QuicByteCount size_before_mtu_change;
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<3>(&size_before_mtu_change), Return(true)))
+ .WillOnce(Return(true));
+ connection_.SendStreamDataWithString(3, data, 0, kFin, nullptr);
+ EXPECT_EQ(3u, creator_->packet_number());
+ EXPECT_EQ(kDefaultMaxPacketSize, size_before_mtu_change);
+
+ // Acknowledge all packets so far.
+ QuicAckFrame probe_ack = InitAckFrame(3);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&probe_ack);
+ EXPECT_EQ(new_mtu, connection_.max_packet_length());
+
+ // Send the same data again. Check that it fits into a single packet now.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendStreamDataWithString(3, data, 0, kFin, nullptr);
+ EXPECT_EQ(4u, creator_->packet_number());
+}
+
+// Tests whether MTU discovery does not happen when it is not explicitly enabled
+// by the connection options.
+TEST_P(QuicConnectionTest, MtuDiscoveryDisabled) {
+ EXPECT_TRUE(connection_.connected());
+
+ const QuicPacketCount number_of_packets = kPacketsBetweenMtuProbesBase * 2;
+ for (QuicPacketCount i = 0; i < number_of_packets; i++) {
+ SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
+ EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ EXPECT_EQ(0u, connection_.mtu_probe_count());
+ }
+}
+
+// Tests whether MTU discovery works when the probe gets acknowledged on the
+// first try.
+TEST_P(QuicConnectionTest, MtuDiscoveryEnabled) {
+ EXPECT_TRUE(connection_.connected());
+
+ connection_.EnablePathMtuDiscovery(send_algorithm_);
+
+ // Send enough packets so that the next one triggers path MTU discovery.
+ for (QuicPacketCount i = 0; i < kPacketsBetweenMtuProbesBase - 1; i++) {
+ SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
+ ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ }
+
+ // Trigger the probe.
+ SendStreamDataToPeer(3, "!", kPacketsBetweenMtuProbesBase,
+ /*fin=*/false, nullptr);
+ ASSERT_TRUE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ QuicByteCount probe_size;
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<3>(&probe_size), Return(true)));
+ connection_.GetMtuDiscoveryAlarm()->Fire();
+ EXPECT_EQ(kMtuDiscoveryTargetPacketSizeHigh, probe_size);
+
+ const QuicPacketCount probe_packet_number = kPacketsBetweenMtuProbesBase + 1;
+ ASSERT_EQ(probe_packet_number, creator_->packet_number());
+
+ // Acknowledge all packets sent so far.
+ QuicAckFrame probe_ack = InitAckFrame(probe_packet_number);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&probe_ack);
+ EXPECT_EQ(kMtuDiscoveryTargetPacketSizeHigh, connection_.max_packet_length());
+ EXPECT_EQ(0u, connection_.GetBytesInFlight(kDefaultPathId));
+
+ // Send more packets, and ensure that none of them sets the alarm.
+ for (QuicPacketCount i = 0; i < 4 * kPacketsBetweenMtuProbesBase; i++) {
+ SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
+ ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ }
+
+ EXPECT_EQ(1u, connection_.mtu_probe_count());
+}
+
+// Tests whether MTU discovery works correctly when the probes never get
+// acknowledged.
+TEST_P(QuicConnectionTest, MtuDiscoveryFailed) {
+ EXPECT_TRUE(connection_.connected());
+
+ connection_.EnablePathMtuDiscovery(send_algorithm_);
+
+ const QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(100);
+
+ EXPECT_EQ(kPacketsBetweenMtuProbesBase,
+ QuicConnectionPeer::GetPacketsBetweenMtuProbes(&connection_));
+ // Lower the number of probes between packets in order to make the test go
+ // much faster.
+ const QuicPacketCount packets_between_probes_base = 10;
+ QuicConnectionPeer::SetPacketsBetweenMtuProbes(&connection_,
+ packets_between_probes_base);
+ QuicConnectionPeer::SetNextMtuProbeAt(&connection_,
+ packets_between_probes_base);
+
+ // This tests sends more packets than strictly necessary to make sure that if
+ // the connection was to send more discovery packets than needed, those would
+ // get caught as well.
+ const QuicPacketCount number_of_packets =
+ packets_between_probes_base * (1 << (kMtuDiscoveryAttempts + 1));
+ vector<QuicPacketNumber> mtu_discovery_packets;
+ // Called by the first ack.
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ // Called on many acks.
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _))
+ .Times(AnyNumber());
+ for (QuicPacketCount i = 0; i < number_of_packets; i++) {
+ SendStreamDataToPeer(3, "!", i, /*fin=*/false, nullptr);
+ clock_.AdvanceTime(rtt);
+
+ // Receive an ACK, which marks all data packets as received, and all MTU
+ // discovery packets as missing.
+ QuicAckFrame ack = InitAckFrame(creator_->packet_number());
+ for (QuicPacketNumber& packet : mtu_discovery_packets) {
+ NackPacket(packet, &ack);
+ }
+ ProcessAckPacket(&ack);
+
+ // Trigger MTU probe if it would be scheduled now.
+ if (!connection_.GetMtuDiscoveryAlarm()->IsSet()) {
+ continue;
+ }
+
+ // Fire the alarm. The alarm should cause a packet to be sent.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(Return(true));
+ connection_.GetMtuDiscoveryAlarm()->Fire();
+ // Record the packet number of the MTU discovery packet in order to
+ // mark it as NACK'd.
+ mtu_discovery_packets.push_back(creator_->packet_number());
+ }
+
+ // Ensure the number of packets between probes grows exponentially by checking
+ // it against the closed-form expression for the packet number.
+ ASSERT_EQ(kMtuDiscoveryAttempts, mtu_discovery_packets.size());
+ for (QuicPacketNumber i = 0; i < kMtuDiscoveryAttempts; i++) {
+ // 2^0 + 2^1 + 2^2 + ... + 2^n = 2^(n + 1) - 1
+ const QuicPacketCount packets_between_probes =
+ packets_between_probes_base * ((1 << (i + 1)) - 1);
+ EXPECT_EQ(packets_between_probes + (i + 1), mtu_discovery_packets[i]);
+ }
+
+ EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ EXPECT_EQ(kDefaultMaxPacketSize, connection_.max_packet_length());
+ EXPECT_EQ(kMtuDiscoveryAttempts, connection_.mtu_probe_count());
+}
+
+// Tests whether MTU discovery works when the writer has a limit on how large a
+// packet can be.
+TEST_P(QuicConnectionTest, MtuDiscoveryWriterLimited) {
+ EXPECT_TRUE(connection_.connected());
+
+ const QuicByteCount mtu_limit = kMtuDiscoveryTargetPacketSizeHigh - 1;
+ writer_->set_max_packet_size(mtu_limit);
+ connection_.EnablePathMtuDiscovery(send_algorithm_);
+
+ // Send enough packets so that the next one triggers path MTU discovery.
+ for (QuicPacketCount i = 0; i < kPacketsBetweenMtuProbesBase - 1; i++) {
+ SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
+ ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ }
+
+ // Trigger the probe.
+ SendStreamDataToPeer(3, "!", kPacketsBetweenMtuProbesBase,
+ /*fin=*/false, nullptr);
+ ASSERT_TRUE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ QuicByteCount probe_size;
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<3>(&probe_size), Return(true)));
+ connection_.GetMtuDiscoveryAlarm()->Fire();
+ EXPECT_EQ(mtu_limit, probe_size);
+
+ const QuicPacketCount probe_sequence_number =
+ kPacketsBetweenMtuProbesBase + 1;
+ ASSERT_EQ(probe_sequence_number, creator_->packet_number());
+
+ // Acknowledge all packets sent so far.
+ QuicAckFrame probe_ack = InitAckFrame(probe_sequence_number);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&probe_ack);
+ EXPECT_EQ(mtu_limit, connection_.max_packet_length());
+ EXPECT_EQ(0u, connection_.GetBytesInFlight(kDefaultPathId));
+
+ // Send more packets, and ensure that none of them sets the alarm.
+ for (QuicPacketCount i = 0; i < 4 * kPacketsBetweenMtuProbesBase; i++) {
+ SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
+ ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ }
+
+ EXPECT_EQ(1u, connection_.mtu_probe_count());
+}
+
+// Tests whether MTU discovery works when the writer returns an error despite
+// advertising higher packet length.
+TEST_P(QuicConnectionTest, MtuDiscoveryWriterFailed) {
+ FLAGS_graceful_emsgsize_on_mtu_probe = true;
+ EXPECT_TRUE(connection_.connected());
+
+ const QuicByteCount mtu_limit = kMtuDiscoveryTargetPacketSizeHigh - 1;
+ const QuicByteCount initial_mtu = connection_.max_packet_length();
+ EXPECT_LT(initial_mtu, mtu_limit);
+ writer_->set_max_packet_size(mtu_limit);
+ connection_.EnablePathMtuDiscovery(send_algorithm_);
+
+ // Send enough packets so that the next one triggers path MTU discovery.
+ for (QuicPacketCount i = 0; i < kPacketsBetweenMtuProbesBase - 1; i++) {
+ SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
+ ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ }
+
+ // Trigger the probe.
+ SendStreamDataToPeer(3, "!", kPacketsBetweenMtuProbesBase,
+ /*fin=*/false, nullptr);
+ ASSERT_TRUE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ writer_->SimulateNextPacketTooLarge();
+ connection_.GetMtuDiscoveryAlarm()->Fire();
+ ASSERT_TRUE(connection_.connected());
+
+ // Send more data.
+ QuicPacketNumber probe_number = creator_->packet_number();
+ QuicPacketCount extra_packets = kPacketsBetweenMtuProbesBase * 3;
+ for (QuicPacketCount i = 0; i < extra_packets; i++) {
+ connection_.EnsureWritableAndSendStreamData5();
+ ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ }
+
+ // Acknowledge all packets sent so far, except for the lost probe.
+ QuicAckFrame probe_ack = InitAckFrame(creator_->packet_number());
+ NackPacket(probe_number, &probe_ack);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&probe_ack);
+ EXPECT_EQ(initial_mtu, connection_.max_packet_length());
+
+ // Send more packets, and ensure that none of them sets the alarm.
+ for (QuicPacketCount i = 0; i < 4 * kPacketsBetweenMtuProbesBase; i++) {
+ connection_.EnsureWritableAndSendStreamData5();
+ ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ }
+
+ EXPECT_EQ(initial_mtu, connection_.max_packet_length());
+ EXPECT_EQ(1u, connection_.mtu_probe_count());
+}
+
+TEST_P(QuicConnectionTest, NoMtuDiscoveryAfterConnectionClosed) {
+ EXPECT_TRUE(connection_.connected());
+
+ connection_.EnablePathMtuDiscovery(send_algorithm_);
+
+ // Send enough packets so that the next one triggers path MTU discovery.
+ for (QuicPacketCount i = 0; i < kPacketsBetweenMtuProbesBase - 1; i++) {
+ SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
+ ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+ }
+
+ SendStreamDataToPeer(3, "!", kPacketsBetweenMtuProbesBase,
+ /*fin=*/false, nullptr);
+ EXPECT_TRUE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _));
+ connection_.CloseConnection(QUIC_PEER_GOING_AWAY, "no reason",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+ EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, TimeoutAfterSend) {
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ connection_.SetFromConfig(config);
+ EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
+
+ const QuicTime::Delta initial_idle_timeout =
+ QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
+ const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
+ QuicTime default_timeout = clock_.ApproximateNow() + initial_idle_timeout;
+
+ // When we send a packet, the timeout will change to 5ms +
+ // kInitialIdleTimeoutSecs.
+ clock_.AdvanceTime(five_ms);
+ SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, kFin, nullptr);
+ EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
+
+ // Now send more data. This will not move the timeout becase
+ // no data has been recieved since the previous write.
+ clock_.AdvanceTime(five_ms);
+ SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, kFin, nullptr);
+ EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
+
+ // The original alarm will fire. We should not time out because we had a
+ // network event at t=5ms. The alarm will reregister.
+ clock_.AdvanceTime(initial_idle_timeout - five_ms - five_ms);
+ EXPECT_EQ(default_timeout, clock_.ApproximateNow());
+ connection_.GetTimeoutAlarm()->Fire();
+ EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_EQ(default_timeout + five_ms,
+ connection_.GetTimeoutAlarm()->deadline());
+
+ // This time, we should time out.
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NETWORK_IDLE_TIMEOUT, _,
+ ConnectionCloseSource::FROM_SELF));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ clock_.AdvanceTime(five_ms);
+ EXPECT_EQ(default_timeout + five_ms, clock_.ApproximateNow());
+ connection_.GetTimeoutAlarm()->Fire();
+ EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_FALSE(connection_.connected());
+}
+
+TEST_P(QuicConnectionTest, TimeoutAfterRetransmission) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ connection_.SetFromConfig(config);
+ EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
+
+ const QuicTime start_time = clock_.Now();
+ const QuicTime::Delta initial_idle_timeout =
+ QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
+ QuicTime default_timeout = clock_.Now() + initial_idle_timeout;
+
+ connection_.SetMaxTailLossProbes(kDefaultPathId, 0);
+ const QuicTime default_retransmission_time =
+ start_time + DefaultRetransmissionTime();
+
+ ASSERT_LT(default_retransmission_time, default_timeout);
+
+ // When we send a packet, the timeout will change to 5 ms +
+ // kInitialIdleTimeoutSecs (but it will not reschedule the alarm).
+ const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
+ const QuicTime send_time = start_time + five_ms;
+ clock_.AdvanceTime(five_ms);
+ ASSERT_EQ(send_time, clock_.Now());
+ SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, kFin, nullptr);
+ EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
+
+ // Move forward 5 ms and receive a packet, which will move the timeout
+ // forward 5 ms more (but will not reschedule the alarm).
+ const QuicTime receive_time = send_time + five_ms;
+ clock_.AdvanceTime(receive_time - clock_.Now());
+ ASSERT_EQ(receive_time, clock_.Now());
+ ProcessPacket(kDefaultPathId, 1);
+
+ // Now move forward to the retransmission time and retransmit the
+ // packet, which should move the timeout forward again (but will not
+ // reschedule the alarm).
+ EXPECT_EQ(default_retransmission_time + five_ms,
+ connection_.GetRetransmissionAlarm()->deadline());
+ // Simulate the retransmission alarm firing.
+ const QuicTime rto_time = send_time + DefaultRetransmissionTime();
+ const QuicTime final_timeout = rto_time + initial_idle_timeout;
+ clock_.AdvanceTime(rto_time - clock_.Now());
+ ASSERT_EQ(rto_time, clock_.Now());
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
+ connection_.GetRetransmissionAlarm()->Fire();
+
+ // Advance to the original timeout and fire the alarm. The connection should
+ // timeout, and the alarm should be registered based on the time of the
+ // retransmission.
+ clock_.AdvanceTime(default_timeout - clock_.Now());
+ ASSERT_EQ(default_timeout.ToDebuggingValue(),
+ clock_.Now().ToDebuggingValue());
+ EXPECT_EQ(default_timeout, clock_.Now());
+ connection_.GetTimeoutAlarm()->Fire();
+ EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_TRUE(connection_.connected());
+ ASSERT_EQ(final_timeout.ToDebuggingValue(),
+ connection_.GetTimeoutAlarm()->deadline().ToDebuggingValue());
+
+ // This time, we should time out.
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NETWORK_IDLE_TIMEOUT, _,
+ ConnectionCloseSource::FROM_SELF));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ clock_.AdvanceTime(final_timeout - clock_.Now());
+ EXPECT_EQ(connection_.GetTimeoutAlarm()->deadline(), clock_.Now());
+ EXPECT_EQ(final_timeout, clock_.Now());
+ connection_.GetTimeoutAlarm()->Fire();
+ EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_FALSE(connection_.connected());
+}
+
+TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) {
+ // Same test as above, but complete a handshake which enables silent close,
+ // causing no connection close packet to be sent.
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+
+ // Create a handshake message that also enables silent close.
+ CryptoHandshakeMessage msg;
+ string error_details;
+ QuicConfig client_config;
+ client_config.SetInitialStreamFlowControlWindowToSend(
+ kInitialStreamFlowControlWindowForTest);
+ client_config.SetInitialSessionFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+ client_config.SetIdleConnectionStateLifetime(
+ QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs),
+ QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs));
+ client_config.ToHandshakeMessage(&msg);
+ const QuicErrorCode error =
+ config.ProcessPeerHello(msg, CLIENT, &error_details);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+
+ connection_.SetFromConfig(config);
+ EXPECT_TRUE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
+
+ const QuicTime::Delta default_idle_timeout =
+ QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs - 1);
+ const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
+ QuicTime default_timeout = clock_.ApproximateNow() + default_idle_timeout;
+
+ // When we send a packet, the timeout will change to 5ms +
+ // kInitialIdleTimeoutSecs.
+ clock_.AdvanceTime(five_ms);
+ SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, kFin, nullptr);
+ EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
+
+ // Now send more data. This will not move the timeout becase
+ // no data has been recieved since the previous write.
+ clock_.AdvanceTime(five_ms);
+ SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, kFin, nullptr);
+ EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
+
+ // The original alarm will fire. We should not time out because we had a
+ // network event at t=5ms. The alarm will reregister.
+ clock_.AdvanceTime(default_idle_timeout - five_ms - five_ms);
+ EXPECT_EQ(default_timeout, clock_.ApproximateNow());
+ connection_.GetTimeoutAlarm()->Fire();
+ EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_EQ(default_timeout + five_ms,
+ connection_.GetTimeoutAlarm()->deadline());
+
+ // This time, we should time out.
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NETWORK_IDLE_TIMEOUT, _,
+ ConnectionCloseSource::FROM_SELF));
+ clock_.AdvanceTime(five_ms);
+ EXPECT_EQ(default_timeout + five_ms, clock_.ApproximateNow());
+ connection_.GetTimeoutAlarm()->Fire();
+ EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_FALSE(connection_.connected());
+}
+
+TEST_P(QuicConnectionTest, TimeoutAfterReceive) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ connection_.SetFromConfig(config);
+ EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
+
+ const QuicTime::Delta initial_idle_timeout =
+ QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
+ const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
+ QuicTime default_timeout = clock_.ApproximateNow() + initial_idle_timeout;
+
+ connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0, !kFin,
+ nullptr);
+ connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 3, !kFin,
+ nullptr);
+
+ EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
+ clock_.AdvanceTime(five_ms);
+
+ // When we receive a packet, the timeout will change to 5ms +
+ // kInitialIdleTimeoutSecs.
+ QuicAckFrame ack = InitAckFrame(2);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&ack);
+
+ // The original alarm will fire. We should not time out because we had a
+ // network event at t=5ms. The alarm will reregister.
+ clock_.AdvanceTime(initial_idle_timeout - five_ms);
+ EXPECT_EQ(default_timeout, clock_.ApproximateNow());
+ connection_.GetTimeoutAlarm()->Fire();
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_EQ(default_timeout + five_ms,
+ connection_.GetTimeoutAlarm()->deadline());
+
+ // This time, we should time out.
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NETWORK_IDLE_TIMEOUT, _,
+ ConnectionCloseSource::FROM_SELF));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ clock_.AdvanceTime(five_ms);
+ EXPECT_EQ(default_timeout + five_ms, clock_.ApproximateNow());
+ connection_.GetTimeoutAlarm()->Fire();
+ EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_FALSE(connection_.connected());
+}
+
+TEST_P(QuicConnectionTest, TimeoutAfterReceiveNotSendWhenUnacked) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ connection_.SetFromConfig(config);
+ EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
+
+ const QuicTime::Delta initial_idle_timeout =
+ QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
+ connection_.SetNetworkTimeouts(
+ QuicTime::Delta::Infinite(),
+ initial_idle_timeout + QuicTime::Delta::FromSeconds(1));
+ const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
+ QuicTime default_timeout = clock_.ApproximateNow() + initial_idle_timeout;
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0, !kFin,
+ nullptr);
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 3, !kFin,
+ nullptr);
+
+ EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
+
+ clock_.AdvanceTime(five_ms);
+
+ // When we receive a packet, the timeout will change to 5ms +
+ // kInitialIdleTimeoutSecs.
+ QuicAckFrame ack = InitAckFrame(2);
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&ack);
+
+ // The original alarm will fire. We should not time out because we had a
+ // network event at t=5ms. The alarm will reregister.
+ clock_.AdvanceTime(initial_idle_timeout - five_ms);
+ EXPECT_EQ(default_timeout, clock_.ApproximateNow());
+ connection_.GetTimeoutAlarm()->Fire();
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_EQ(default_timeout + five_ms,
+ connection_.GetTimeoutAlarm()->deadline());
+
+ // Now, send packets while advancing the time and verify that the connection
+ // eventually times out.
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NETWORK_IDLE_TIMEOUT, _,
+ ConnectionCloseSource::FROM_SELF));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
+ for (int i = 0; i < 100 && connection_.connected(); ++i) {
+ VLOG(1) << "sending data packet";
+ connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0, !kFin,
+ nullptr);
+ connection_.GetTimeoutAlarm()->Fire();
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ }
+ EXPECT_FALSE(connection_.connected());
+ EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, TimeoutAfter5ClientRTOs) {
+ connection_.SetMaxTailLossProbes(kDefaultPathId, 2);
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(k5RTO);
+ config.SetConnectionOptionsToSend(connection_options);
+ connection_.SetFromConfig(config);
+
+ // Send stream data.
+ SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, kFin, nullptr);
+
+ EXPECT_CALL(visitor_, OnPathDegrading());
+ // Fire the retransmission alarm 6 times, twice for TLP and 4 times for RTO.
+ for (int i = 0; i < 6; ++i) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_TRUE(connection_.connected());
+ }
+
+ EXPECT_EQ(2u, connection_.sent_packet_manager().GetConsecutiveTlpCount());
+ EXPECT_EQ(4u, connection_.sent_packet_manager().GetConsecutiveRtoCount());
+ // This time, we should time out.
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_TOO_MANY_RTOS, _,
+ ConnectionCloseSource::FROM_SELF));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_FALSE(connection_.connected());
+}
+
+TEST_P(QuicConnectionTest, TimeoutAfter5ServerRTOs) {
+ FLAGS_quic_only_5rto_client_side = true;
+ connection_.SetMaxTailLossProbes(kDefaultPathId, 2);
+ QuicConnectionPeer::SetPerspective(&connection_, Perspective::IS_SERVER);
+ QuicFramerPeer::SetPerspective(QuicConnectionPeer::GetFramer(&connection_),
+ Perspective::IS_SERVER);
+ creator_->StopSendingVersion();
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ QuicTagVector connection_options;
+ connection_options.push_back(k5RTO);
+ config.SetConnectionOptionsToSend(connection_options);
+ connection_.SetFromConfig(config);
+
+ // Send stream data.
+ SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, kFin, nullptr);
+
+ EXPECT_CALL(visitor_, OnPathDegrading());
+ // Fire the retransmission alarm 6 times, twice for TLP and 4 times for RTO.
+ for (int i = 0; i < 6; ++i) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_TRUE(connection_.connected());
+ }
+
+ EXPECT_EQ(2u, connection_.sent_packet_manager().GetConsecutiveTlpCount());
+ EXPECT_EQ(4u, connection_.sent_packet_manager().GetConsecutiveRtoCount());
+ // The 5th RTO should not time out server side.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
+ EXPECT_TRUE(connection_.connected());
+}
+
+TEST_P(QuicConnectionTest, SendScheduler) {
+ // Test that if we send a packet without delay, it is not queued.
+ QuicPacket* packet =
+ ConstructDataPacket(kDefaultPathId, 1, !kEntropyFlag, !kHasStopWaiting);
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet,
+ kTestEntropyHash, HAS_RETRANSMITTABLE_DATA, false,
+ false);
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+}
+
+TEST_P(QuicConnectionTest, FailToSendFirstPacket) {
+ // Test that the connection does not crash when it fails to send the first
+ // packet at which point self_address_ might be uninitialized.
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(1);
+ QuicPacket* packet =
+ ConstructDataPacket(kDefaultPathId, 1, !kEntropyFlag, !kHasStopWaiting);
+ writer_->SetShouldWriteFail();
+ connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet,
+ kTestEntropyHash, HAS_RETRANSMITTABLE_DATA, false,
+ false);
+}
+
+TEST_P(QuicConnectionTest, SendSchedulerEAGAIN) {
+ QuicPacket* packet =
+ ConstructDataPacket(kDefaultPathId, 1, !kEntropyFlag, !kHasStopWaiting);
+ BlockOnNextWrite();
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0);
+ connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet,
+ kTestEntropyHash, HAS_RETRANSMITTABLE_DATA, false,
+ false);
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
+}
+
+TEST_P(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
+ // All packets carry version info till version is negotiated.
+ size_t payload_length;
+ size_t length = GetPacketLengthForOneStream(
+ connection_.version(), kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID,
+ PACKET_1BYTE_PACKET_NUMBER, &payload_length);
+ connection_.SetMaxPacketLength(length);
+
+ // Queue the first packet.
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ .WillOnce(testing::Return(QuicTime::Delta::FromMicroseconds(10)));
+ const string payload(payload_length, 'a');
+ EXPECT_EQ(0u,
+ connection_.SendStreamDataWithString(3, payload, 0, !kFin, nullptr)
+ .bytes_consumed);
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+}
+
+TEST_P(QuicConnectionTest, LoopThroughSendingPackets) {
+ // All packets carry version info till version is negotiated.
+ size_t payload_length;
+ // GetPacketLengthForOneStream() assumes a stream offset of 0 in determining
+ // packet length. The size of the offset field in a stream frame is 0 for
+ // offset 0, and 2 for non-zero offsets up through 16K. Increase
+ // max_packet_length by 2 so that subsequent packets containing subsequent
+ // stream frames with non-zero offets will fit within the packet length.
+ size_t length =
+ 2 + GetPacketLengthForOneStream(
+ connection_.version(), kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID,
+ PACKET_1BYTE_PACKET_NUMBER, &payload_length);
+ connection_.SetMaxPacketLength(length);
+
+ // Queue the first packet.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(7);
+ // The first stream frame will have 2 fewer overhead bytes than the other six.
+ const string payload(payload_length * 7 + 2, 'a');
+ EXPECT_EQ(payload.size(),
+ connection_.SendStreamDataWithString(1, payload, 0, !kFin, nullptr)
+ .bytes_consumed);
+}
+
+TEST_P(QuicConnectionTest, LoopThroughSendingPacketsWithTruncation) {
+ // Set up a larger payload than will fit in one packet.
+ const string payload(connection_.max_packet_length(), 'a');
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
+
+ // Now send some packets with no truncation.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ EXPECT_EQ(payload.size(),
+ connection_.SendStreamDataWithString(3, payload, 0, !kFin, nullptr)
+ .bytes_consumed);
+ // Track the size of the second packet here. The overhead will be the largest
+ // we see in this test, due to the non-truncated connection id.
+ size_t non_truncated_packet_size = writer_->last_packet_size();
+
+ // Change to a 0 byte connection id.
+ QuicConfig config;
+ QuicConfigPeer::SetReceivedBytesForConnectionId(&config, 0);
+ connection_.SetFromConfig(config);
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ EXPECT_EQ(payload.size(),
+ connection_.SendStreamDataWithString(3, payload, 0, !kFin, nullptr)
+ .bytes_consumed);
+ // Just like above, we save 8 bytes on payload, and 8 on truncation.
+ EXPECT_EQ(non_truncated_packet_size, writer_->last_packet_size() + 8 * 2);
+}
+
+TEST_P(QuicConnectionTest, SendDelayedAck) {
+ QuicTime ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime();
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ const uint8_t tag = 0x07;
+ connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
+ framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
+ // Process a packet from the non-crypto stream.
+ frame1_.stream_id = 3;
+
+ // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // instead of ENCRYPTION_NONE.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, 1, !kEntropyFlag, !kHasStopWaiting,
+ ENCRYPTION_INITIAL);
+
+ // Check if delayed ack timer is running for the expected interval.
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+ // Simulate delayed ack alarm firing.
+ connection_.GetAckAlarm()->Fire();
+ // Check that ack is sent and that delayed ack alarm is reset.
+ EXPECT_EQ(2u, writer_->frame_count());
+ EXPECT_FALSE(writer_->stop_waiting_frames().empty());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, SendDelayedAckDecimation) {
+ QuicConnectionPeer::SetAckMode(&connection_, QuicConnection::ACK_DECIMATION);
+
+ const size_t kMinRttMs = 40;
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ // The ack time should be based on min_rtt/4, since it's less than the
+ // default delayed ack time.
+ QuicTime ack_time = clock_.ApproximateNow() +
+ QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ const uint8_t tag = 0x07;
+ connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
+ framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
+ // Process a packet from the non-crypto stream.
+ frame1_.stream_id = 3;
+
+ // Process all the initial packets in order so there aren't missing packets.
+ QuicPacketNumber kFirstDecimatedPacket = 101;
+ for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kEntropyFlag,
+ !kHasStopWaiting, ENCRYPTION_INITIAL);
+ }
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // instead of ENCRYPTION_NONE.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, !kEntropyFlag,
+ !kHasStopWaiting, ENCRYPTION_INITIAL);
+
+ // Check if delayed ack timer is running for the expected interval.
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+
+ // The 10th received packet causes an ack to be sent.
+ for (int i = 0; i < 9; ++i) {
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i,
+ !kEntropyFlag, !kHasStopWaiting,
+ ENCRYPTION_INITIAL);
+ }
+ // Check that ack is sent and that delayed ack alarm is reset.
+ EXPECT_EQ(2u, writer_->frame_count());
+ EXPECT_FALSE(writer_->stop_waiting_frames().empty());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) {
+ QuicConnectionPeer::SetAckMode(&connection_, QuicConnection::ACK_DECIMATION);
+ QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125);
+
+ const size_t kMinRttMs = 40;
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ // The ack time should be based on min_rtt/8, since it's less than the
+ // default delayed ack time.
+ QuicTime ack_time = clock_.ApproximateNow() +
+ QuicTime::Delta::FromMilliseconds(kMinRttMs / 8);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ const uint8_t tag = 0x07;
+ connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
+ framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
+ // Process a packet from the non-crypto stream.
+ frame1_.stream_id = 3;
+
+ // Process all the initial packets in order so there aren't missing packets.
+ QuicPacketNumber kFirstDecimatedPacket = 101;
+ for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kEntropyFlag,
+ !kHasStopWaiting, ENCRYPTION_INITIAL);
+ }
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // instead of ENCRYPTION_NONE.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, !kEntropyFlag,
+ !kHasStopWaiting, ENCRYPTION_INITIAL);
+
+ // Check if delayed ack timer is running for the expected interval.
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+
+ // The 10th received packet causes an ack to be sent.
+ for (int i = 0; i < 9; ++i) {
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i,
+ !kEntropyFlag, !kHasStopWaiting,
+ ENCRYPTION_INITIAL);
+ }
+ // Check that ack is sent and that delayed ack alarm is reset.
+ EXPECT_EQ(2u, writer_->frame_count());
+ EXPECT_FALSE(writer_->stop_waiting_frames().empty());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) {
+ QuicConnectionPeer::SetAckMode(
+ &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING);
+
+ const size_t kMinRttMs = 40;
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ // The ack time should be based on min_rtt/4, since it's less than the
+ // default delayed ack time.
+ QuicTime ack_time = clock_.ApproximateNow() +
+ QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ const uint8_t tag = 0x07;
+ connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
+ framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
+ // Process a packet from the non-crypto stream.
+ frame1_.stream_id = 3;
+
+ // Process all the initial packets in order so there aren't missing packets.
+ QuicPacketNumber kFirstDecimatedPacket = 101;
+ for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kEntropyFlag,
+ !kHasStopWaiting, ENCRYPTION_INITIAL);
+ }
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // instead of ENCRYPTION_NONE.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, !kEntropyFlag,
+ !kHasStopWaiting, ENCRYPTION_INITIAL);
+
+ // Check if delayed ack timer is running for the expected interval.
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+
+ // Process packet 10 first and ensure the alarm is one eighth min_rtt.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 9,
+ !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+
+ // The 10th received packet causes an ack to be sent.
+ for (int i = 0; i < 8; ++i) {
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i,
+ !kEntropyFlag, !kHasStopWaiting,
+ ENCRYPTION_INITIAL);
+ }
+ // Check that ack is sent and that delayed ack alarm is reset.
+ EXPECT_EQ(2u, writer_->frame_count());
+ EXPECT_FALSE(writer_->stop_waiting_frames().empty());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) {
+ QuicConnectionPeer::SetAckMode(
+ &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING);
+
+ const size_t kMinRttMs = 40;
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ // The ack time should be based on min_rtt/4, since it's less than the
+ // default delayed ack time.
+ QuicTime ack_time = clock_.ApproximateNow() +
+ QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ const uint8_t tag = 0x07;
+ connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
+ framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
+ // Process a packet from the non-crypto stream.
+ frame1_.stream_id = 3;
+
+ // Process all the initial packets in order so there aren't missing packets.
+ QuicPacketNumber kFirstDecimatedPacket = 101;
+ for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kEntropyFlag,
+ !kHasStopWaiting, ENCRYPTION_INITIAL);
+ }
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // instead of ENCRYPTION_NONE.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, !kEntropyFlag,
+ !kHasStopWaiting, ENCRYPTION_INITIAL);
+
+ // Check if delayed ack timer is running for the expected interval.
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+
+ // Process packet 10 first and ensure the alarm is one eighth min_rtt.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 19,
+ !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+
+ // The 10th received packet causes an ack to be sent.
+ for (int i = 0; i < 8; ++i) {
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i,
+ !kEntropyFlag, !kHasStopWaiting,
+ ENCRYPTION_INITIAL);
+ }
+ // Check that ack is sent and that delayed ack alarm is reset.
+ EXPECT_EQ(2u, writer_->frame_count());
+ EXPECT_FALSE(writer_->stop_waiting_frames().empty());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+
+ // The next packet received in order will cause an immediate ack,
+ // because it fills a hole.
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 10,
+ !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ // Check that ack is sent and that delayed ack alarm is reset.
+ EXPECT_EQ(2u, writer_->frame_count());
+ EXPECT_FALSE(writer_->stop_waiting_frames().empty());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) {
+ QuicConnectionPeer::SetAckMode(
+ &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING);
+ QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125);
+
+ const size_t kMinRttMs = 40;
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ // The ack time should be based on min_rtt/8, since it's less than the
+ // default delayed ack time.
+ QuicTime ack_time = clock_.ApproximateNow() +
+ QuicTime::Delta::FromMilliseconds(kMinRttMs / 8);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ const uint8_t tag = 0x07;
+ connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
+ framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
+ // Process a packet from the non-crypto stream.
+ frame1_.stream_id = 3;
+
+ // Process all the initial packets in order so there aren't missing packets.
+ QuicPacketNumber kFirstDecimatedPacket = 101;
+ for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kEntropyFlag,
+ !kHasStopWaiting, ENCRYPTION_INITIAL);
+ }
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // instead of ENCRYPTION_NONE.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, !kEntropyFlag,
+ !kHasStopWaiting, ENCRYPTION_INITIAL);
+
+ // Check if delayed ack timer is running for the expected interval.
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+
+ // Process packet 10 first and ensure the alarm is one eighth min_rtt.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 9,
+ !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+
+ // The 10th received packet causes an ack to be sent.
+ for (int i = 0; i < 8; ++i) {
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i,
+ !kEntropyFlag, !kHasStopWaiting,
+ ENCRYPTION_INITIAL);
+ }
+ // Check that ack is sent and that delayed ack alarm is reset.
+ EXPECT_EQ(2u, writer_->frame_count());
+ EXPECT_FALSE(writer_->stop_waiting_frames().empty());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest,
+ SendDelayedAckDecimationWithLargeReorderingEighthRtt) {
+ QuicConnectionPeer::SetAckMode(
+ &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING);
+ QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125);
+
+ const size_t kMinRttMs = 40;
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ // The ack time should be based on min_rtt/8, since it's less than the
+ // default delayed ack time.
+ QuicTime ack_time = clock_.ApproximateNow() +
+ QuicTime::Delta::FromMilliseconds(kMinRttMs / 8);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ const uint8_t tag = 0x07;
+ connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
+ framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
+ // Process a packet from the non-crypto stream.
+ frame1_.stream_id = 3;
+
+ // Process all the initial packets in order so there aren't missing packets.
+ QuicPacketNumber kFirstDecimatedPacket = 101;
+ for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kEntropyFlag,
+ !kHasStopWaiting, ENCRYPTION_INITIAL);
+ }
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
+ // instead of ENCRYPTION_NONE.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, !kEntropyFlag,
+ !kHasStopWaiting, ENCRYPTION_INITIAL);
+
+ // Check if delayed ack timer is running for the expected interval.
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+
+ // Process packet 10 first and ensure the alarm is one eighth min_rtt.
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 19,
+ !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+
+ // The 10th received packet causes an ack to be sent.
+ for (int i = 0; i < 8; ++i) {
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i,
+ !kEntropyFlag, !kHasStopWaiting,
+ ENCRYPTION_INITIAL);
+ }
+ // Check that ack is sent and that delayed ack alarm is reset.
+ EXPECT_EQ(2u, writer_->frame_count());
+ EXPECT_FALSE(writer_->stop_waiting_frames().empty());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+
+ // The next packet received in order will cause an immediate ack,
+ // because it fills a hole.
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 10,
+ !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
+ // Check that ack is sent and that delayed ack alarm is reset.
+ EXPECT_EQ(2u, writer_->frame_count());
+ EXPECT_FALSE(writer_->stop_waiting_frames().empty());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, SendDelayedAckOnHandshakeConfirmed) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ ProcessPacket(kDefaultPathId, 1);
+ // Check that ack is sent and that delayed ack alarm is set.
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ QuicTime ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime();
+ EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+
+ // Completing the handshake as the server does nothing.
+ QuicConnectionPeer::SetPerspective(&connection_, Perspective::IS_SERVER);
+ connection_.OnHandshakeComplete();
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+
+ // Complete the handshake as the client decreases the delayed ack time to 0ms.
+ QuicConnectionPeer::SetPerspective(&connection_, Perspective::IS_CLIENT);
+ connection_.OnHandshakeComplete();
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_EQ(clock_.ApproximateNow(), connection_.GetAckAlarm()->deadline());
+}
+
+TEST_P(QuicConnectionTest, SendDelayedAckOnSecondPacket) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ ProcessPacket(kDefaultPathId, 1);
+ ProcessPacket(kDefaultPathId, 2);
+ // Check that ack is sent and that delayed ack alarm is reset.
+ EXPECT_EQ(2u, writer_->frame_count());
+ EXPECT_FALSE(writer_->stop_waiting_frames().empty());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, NoAckOnOldNacks) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ // Drop one packet, triggering a sequence of acks.
+ ProcessPacket(kDefaultPathId, 2);
+ size_t frames_per_ack = 2;
+ EXPECT_EQ(frames_per_ack, writer_->frame_count());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ writer_->Reset();
+ ProcessPacket(kDefaultPathId, 3);
+ EXPECT_EQ(frames_per_ack, writer_->frame_count());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ writer_->Reset();
+ ProcessPacket(kDefaultPathId, 4);
+ EXPECT_EQ(frames_per_ack, writer_->frame_count());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ writer_->Reset();
+ ProcessPacket(kDefaultPathId, 5);
+ EXPECT_EQ(frames_per_ack, writer_->frame_count());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ writer_->Reset();
+ // Now only set the timer on the 6th packet, instead of sending another ack.
+ ProcessPacket(kDefaultPathId, 6);
+ EXPECT_EQ(0u, writer_->frame_count());
+ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingPacket) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ ProcessPacket(kDefaultPathId, 1);
+ connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0, !kFin,
+ nullptr);
+ // Check that ack is bundled with outgoing data and that delayed ack
+ // alarm is reset.
+ EXPECT_EQ(3u, writer_->frame_count());
+ EXPECT_FALSE(writer_->stop_waiting_frames().empty());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingCryptoPacket) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ ProcessPacket(kDefaultPathId, 1);
+ connection_.SendStreamDataWithString(kCryptoStreamId, "foo", 0, !kFin,
+ nullptr);
+ // Check that ack is bundled with outgoing crypto data.
+ EXPECT_EQ(3u, writer_->frame_count());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, BlockAndBufferOnFirstCHLOPacketOfTwo) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ ProcessPacket(kDefaultPathId, 1);
+ BlockOnNextWrite();
+ writer_->set_is_write_blocked_data_buffered(true);
+ connection_.SendStreamDataWithString(kCryptoStreamId, "foo", 0, !kFin,
+ nullptr);
+ EXPECT_TRUE(writer_->IsWriteBlocked());
+ EXPECT_FALSE(connection_.HasQueuedData());
+ connection_.SendStreamDataWithString(kCryptoStreamId, "bar", 3, !kFin,
+ nullptr);
+ EXPECT_TRUE(writer_->IsWriteBlocked());
+ EXPECT_TRUE(connection_.HasQueuedData());
+}
+
+TEST_P(QuicConnectionTest, BundleAckForSecondCHLO) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ EXPECT_CALL(visitor_, OnCanWrite())
+ .WillOnce(IgnoreResult(InvokeWithoutArgs(
+ &connection_, &TestConnection::SendCryptoStreamData)));
+ // Process a packet from the crypto stream, which is frame1_'s default.
+ // Receiving the CHLO as packet 2 first will cause the connection to
+ // immediately send an ack, due to the packet gap.
+ ProcessPacket(kDefaultPathId, 2);
+ // Check that ack is sent and that delayed ack alarm is reset.
+ EXPECT_EQ(3u, writer_->frame_count());
+ EXPECT_FALSE(writer_->stop_waiting_frames().empty());
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_EQ(2u, writer_->ack_frames().front().largest_observed);
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0, !kFin,
+ nullptr);
+ connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 3, !kFin,
+ nullptr);
+ // Ack the second packet, which will retransmit the first packet.
+ QuicAckFrame ack = InitAckFrame(2);
+ NackPacket(1, &ack);
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
+ .WillOnce(SetArgPointee<4>(lost_packets));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&ack);
+ EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ writer_->Reset();
+
+ // Now ack the retransmission, which will both raise the high water mark
+ // and see if there is more data to send.
+ ack = InitAckFrame(3);
+ NackPacket(1, &ack);
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&ack);
+
+ // Check that no packet is sent and the ack alarm isn't set.
+ EXPECT_EQ(0u, writer_->frame_count());
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+ writer_->Reset();
+
+ // Send the same ack, but send both data and an ack together.
+ ack = InitAckFrame(3);
+ NackPacket(1, &ack);
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+ EXPECT_CALL(visitor_, OnCanWrite())
+ .WillOnce(IgnoreResult(InvokeWithoutArgs(
+ &connection_, &TestConnection::EnsureWritableAndSendStreamData5)));
+ ProcessAckPacket(&ack);
+
+ // Check that ack is bundled with outgoing data and the delayed ack
+ // alarm is reset.
+ EXPECT_EQ(3u, writer_->frame_count());
+ EXPECT_FALSE(writer_->stop_waiting_frames().empty());
+ EXPECT_FALSE(writer_->ack_frames().empty());
+ EXPECT_EQ(3u, writer_->ack_frames().front().largest_observed);
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+}
+
+TEST_P(QuicConnectionTest, NoAckSentForClose) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ ProcessPacket(kDefaultPathId, 1);
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, _,
+ ConnectionCloseSource::FROM_PEER));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ ProcessClosePacket(kDefaultPathId, 2);
+}
+
+TEST_P(QuicConnectionTest, SendWhenDisconnected) {
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, _,
+ ConnectionCloseSource::FROM_SELF));
+ connection_.CloseConnection(QUIC_PEER_GOING_AWAY, "no reason",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+ EXPECT_FALSE(connection_.connected());
+ EXPECT_FALSE(connection_.CanWriteStreamData());
+ QuicPacket* packet =
+ ConstructDataPacket(kDefaultPathId, 1, !kEntropyFlag, !kHasStopWaiting);
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0);
+ connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet,
+ kTestEntropyHash, HAS_RETRANSMITTABLE_DATA, false,
+ false);
+}
+
+TEST_P(QuicConnectionTest, PublicReset) {
+ QuicPublicResetPacket header;
+ header.public_header.connection_id = connection_id_;
+ header.public_header.reset_flag = true;
+ header.public_header.version_flag = false;
+ header.rejected_packet_number = 10101;
+ std::unique_ptr<QuicEncryptedPacket> packet(
+ framer_.BuildPublicResetPacket(header));
+ std::unique_ptr<QuicReceivedPacket> received(
+ ConstructReceivedPacket(*packet, QuicTime::Zero()));
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PUBLIC_RESET, _,
+ ConnectionCloseSource::FROM_PEER));
+ connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received);
+}
+
+TEST_P(QuicConnectionTest, GoAway) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ QuicGoAwayFrame goaway;
+ goaway.last_good_stream_id = 1;
+ goaway.error_code = QUIC_PEER_GOING_AWAY;
+ goaway.reason_phrase = "Going away.";
+ EXPECT_CALL(visitor_, OnGoAway(_));
+ ProcessGoAwayPacket(&goaway);
+}
+
+TEST_P(QuicConnectionTest, WindowUpdate) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ QuicWindowUpdateFrame window_update;
+ window_update.stream_id = 3;
+ window_update.byte_offset = 1234;
+ EXPECT_CALL(visitor_, OnWindowUpdateFrame(_));
+ ProcessFramePacket(QuicFrame(&window_update));
+}
+
+TEST_P(QuicConnectionTest, Blocked) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ QuicBlockedFrame blocked;
+ blocked.stream_id = 3;
+ EXPECT_CALL(visitor_, OnBlockedFrame(_));
+ ProcessFramePacket(QuicFrame(&blocked));
+}
+
+TEST_P(QuicConnectionTest, PathClose) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ QuicPathCloseFrame path_close = QuicPathCloseFrame(1);
+ ProcessPathClosePacket(&path_close);
+ EXPECT_TRUE(QuicFramerPeer::IsPathClosed(
+ QuicConnectionPeer::GetFramer(&connection_), 1));
+}
+
+TEST_P(QuicConnectionTest, ZeroBytePacket) {
+ // Don't close the connection for zero byte packets.
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(0);
+ QuicReceivedPacket encrypted(nullptr, 0, QuicTime::Zero());
+ connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, encrypted);
+}
+
+TEST_P(QuicConnectionTest, MissingPacketsBeforeLeastUnacked) {
+ // Set the packet number of the ack packet to be least unacked (4).
+ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 3);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ QuicStopWaitingFrame frame = InitStopWaitingFrame(4);
+ ProcessStopWaitingPacket(&frame);
+ if (outgoing_ack()->missing) {
+ EXPECT_TRUE(outgoing_ack()->packets.Empty());
+ } else {
+ EXPECT_FALSE(outgoing_ack()->packets.Empty());
+ }
+}
+
+TEST_P(QuicConnectionTest, ReceivedEntropyHashCalculation) {
+ if (GetParam().version > QUIC_VERSION_33) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AtLeast(1));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ ProcessDataPacket(kDefaultPathId, 1, kEntropyFlag);
+ ProcessDataPacket(kDefaultPathId, 4, kEntropyFlag);
+ ProcessDataPacket(kDefaultPathId, 3, !kEntropyFlag);
+ ProcessDataPacket(kDefaultPathId, 7, kEntropyFlag);
+ EXPECT_EQ(146u, outgoing_ack()->entropy_hash);
+}
+
+TEST_P(QuicConnectionTest, UpdateEntropyForReceivedPackets) {
+ if (GetParam().version > QUIC_VERSION_33) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AtLeast(1));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ ProcessDataPacket(kDefaultPathId, 1, kEntropyFlag);
+ ProcessDataPacket(kDefaultPathId, 5, kEntropyFlag);
+ ProcessDataPacket(kDefaultPathId, 4, !kEntropyFlag);
+ EXPECT_EQ(34u, outgoing_ack()->entropy_hash);
+ // Make 4th packet my least unacked, and update entropy for 2, 3 packets.
+ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 5);
+ QuicPacketEntropyHash six_packet_entropy_hash = 0;
+ QuicPacketEntropyHash random_entropy_hash = 129u;
+ QuicStopWaitingFrame frame = InitStopWaitingFrame(4);
+ frame.entropy_hash = random_entropy_hash;
+ if (ProcessStopWaitingPacket(&frame)) {
+ six_packet_entropy_hash = 1 << 6;
+ }
+
+ EXPECT_EQ((random_entropy_hash + (1 << 5) + six_packet_entropy_hash),
+ outgoing_ack()->entropy_hash);
+}
+
+TEST_P(QuicConnectionTest, UpdateEntropyHashUptoCurrentPacket) {
+ if (GetParam().version > QUIC_VERSION_33) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AtLeast(1));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ ProcessDataPacket(kDefaultPathId, 1, kEntropyFlag);
+ ProcessDataPacket(kDefaultPathId, 5, !kEntropyFlag);
+ ProcessDataPacket(kDefaultPathId, 22, kEntropyFlag);
+ EXPECT_EQ(66u, outgoing_ack()->entropy_hash);
+ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 22);
+ QuicPacketEntropyHash random_entropy_hash = 85u;
+ // Current packet is the least unacked packet.
+ QuicPacketEntropyHash ack_entropy_hash;
+ QuicStopWaitingFrame frame = InitStopWaitingFrame(23);
+ frame.entropy_hash = random_entropy_hash;
+ ack_entropy_hash = ProcessStopWaitingPacket(&frame);
+ EXPECT_EQ((random_entropy_hash + ack_entropy_hash),
+ outgoing_ack()->entropy_hash);
+ ProcessDataPacket(kDefaultPathId, 25, kEntropyFlag);
+ EXPECT_EQ((random_entropy_hash + ack_entropy_hash + (1 << (25 % 8))),
+ outgoing_ack()->entropy_hash);
+}
+
+TEST_P(QuicConnectionTest, EntropyCalculationForTruncatedAck) {
+ if (GetParam().version > QUIC_VERSION_33) {
+ return;
+ }
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AtLeast(1));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ QuicPacketEntropyHash entropy[51];
+ entropy[0] = 0;
+ for (int i = 1; i < 51; ++i) {
+ bool should_send = i % 10 != 1;
+ bool entropy_flag = (i & (i - 1)) != 0;
+ if (!should_send) {
+ entropy[i] = entropy[i - 1];
+ continue;
+ }
+ if (entropy_flag) {
+ entropy[i] = entropy[i - 1] ^ (1 << (i % 8));
+ } else {
+ entropy[i] = entropy[i - 1];
+ }
+ ProcessDataPacket(kDefaultPathId, i, entropy_flag);
+ }
+ for (int i = 1; i < 50; ++i) {
+ EXPECT_EQ(entropy[i],
+ QuicConnectionPeer::ReceivedEntropyHash(&connection_, i));
+ }
+}
+
+TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacket) {
+ connection_.SetSupportedVersions(AllSupportedVersions());
+ set_perspective(Perspective::IS_SERVER);
+ peer_framer_.set_version_for_tests(QUIC_VERSION_UNSUPPORTED);
+
+ QuicPacketHeader header;
+ header.public_header.connection_id = connection_id_;
+ header.public_header.version_flag = true;
+ header.path_id = kDefaultPathId;
+ header.packet_number = 12;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&frame1_));
+ std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length = framer_.EncryptPayload(
+ ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize);
+
+ 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(kSupportedQuicVersions);
+ ASSERT_EQ(num_versions,
+ writer_->version_negotiation_packet()->versions.size());
+
+ // We expect all versions in kSupportedQuicVersions to be
+ // included in the packet.
+ for (size_t i = 0; i < num_versions; ++i) {
+ EXPECT_EQ(kSupportedQuicVersions[i],
+ writer_->version_negotiation_packet()->versions[i]);
+ }
+}
+
+TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlocked) {
+ connection_.SetSupportedVersions(AllSupportedVersions());
+ set_perspective(Perspective::IS_SERVER);
+ peer_framer_.set_version_for_tests(QUIC_VERSION_UNSUPPORTED);
+
+ QuicPacketHeader header;
+ header.public_header.connection_id = connection_id_;
+ header.public_header.version_flag = true;
+ header.packet_number = 12;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&frame1_));
+ std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length = framer_.EncryptPayload(
+ ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize);
+
+ framer_.set_version(version());
+ BlockOnNextWrite();
+ connection_.ProcessUdpPacket(
+ kSelfAddress, kPeerAddress,
+ QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
+ EXPECT_EQ(0u, writer_->last_packet_size());
+ EXPECT_TRUE(connection_.HasQueuedData());
+
+ writer_->SetWritable();
+ connection_.OnCanWrite();
+ EXPECT_TRUE(writer_->version_negotiation_packet() != nullptr);
+
+ size_t num_versions = arraysize(kSupportedQuicVersions);
+ ASSERT_EQ(num_versions,
+ writer_->version_negotiation_packet()->versions.size());
+
+ // We expect all versions in kSupportedQuicVersions to be
+ // included in the packet.
+ for (size_t i = 0; i < num_versions; ++i) {
+ EXPECT_EQ(kSupportedQuicVersions[i],
+ writer_->version_negotiation_packet()->versions[i]);
+ }
+}
+
+TEST_P(QuicConnectionTest,
+ ServerSendsVersionNegotiationPacketSocketBlockedDataBuffered) {
+ connection_.SetSupportedVersions(AllSupportedVersions());
+ set_perspective(Perspective::IS_SERVER);
+ peer_framer_.set_version_for_tests(QUIC_VERSION_UNSUPPORTED);
+
+ QuicPacketHeader header;
+ header.public_header.connection_id = connection_id_;
+ header.public_header.version_flag = true;
+ header.packet_number = 12;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&frame1_));
+ std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
+ char buffer[kMaxPacketSize];
+ size_t encryped_length = framer_.EncryptPayload(
+ ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize);
+
+ framer_.set_version(version());
+ set_perspective(Perspective::IS_SERVER);
+ BlockOnNextWrite();
+ writer_->set_is_write_blocked_data_buffered(true);
+ connection_.ProcessUdpPacket(
+ kSelfAddress, kPeerAddress,
+ QuicReceivedPacket(buffer, encryped_length, QuicTime::Zero(), false));
+ EXPECT_EQ(0u, writer_->last_packet_size());
+ EXPECT_FALSE(connection_.HasQueuedData());
+}
+
+TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) {
+ // Start out with some unsupported version.
+ QuicConnectionPeer::GetFramer(&connection_)
+ ->set_version_for_tests(QUIC_VERSION_UNSUPPORTED);
+
+ // Send a version negotiation packet.
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ framer_.BuildVersionNegotiationPacket(connection_id_,
+ AllSupportedVersions()));
+ std::unique_ptr<QuicReceivedPacket> received(
+ ConstructReceivedPacket(*encrypted, QuicTime::Zero()));
+ connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received);
+
+ // Now force another packet. The connection should transition into
+ // NEGOTIATED_VERSION state and tell the packet creator to StopSendingVersion.
+ QuicPacketHeader header;
+ header.public_header.connection_id = connection_id_;
+ header.path_id = kDefaultPathId;
+ header.packet_number = 12;
+ header.public_header.version_flag = false;
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&frame1_));
+ std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length = framer_.EncryptPayload(
+ ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize);
+ ASSERT_NE(0u, encrypted_length);
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ connection_.ProcessUdpPacket(
+ kSelfAddress, kPeerAddress,
+ QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
+
+ ASSERT_FALSE(QuicPacketCreatorPeer::SendVersionInPacket(creator_));
+}
+
+TEST_P(QuicConnectionTest, BadVersionNegotiation) {
+ // Send a version negotiation packet with the version the client started with.
+ // It should be rejected.
+ EXPECT_CALL(visitor_,
+ OnConnectionClosed(QUIC_INVALID_VERSION_NEGOTIATION_PACKET, _,
+ ConnectionCloseSource::FROM_SELF));
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ framer_.BuildVersionNegotiationPacket(connection_id_,
+ AllSupportedVersions()));
+ std::unique_ptr<QuicReceivedPacket> received(
+ ConstructReceivedPacket(*encrypted, QuicTime::Zero()));
+ connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received);
+}
+
+TEST_P(QuicConnectionTest, CheckSendStats) {
+ connection_.SetMaxTailLossProbes(kDefaultPathId, 0);
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ connection_.SendStreamDataWithString(3, "first", 0, !kFin, nullptr);
+ size_t first_packet_size = writer_->last_packet_size();
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ connection_.SendStreamDataWithString(5, "second", 0, !kFin, nullptr);
+ size_t second_packet_size = writer_->last_packet_size();
+
+ // 2 retransmissions due to rto, 1 due to explicit nack.
+ EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(3);
+
+ // Retransmit due to RTO.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
+ connection_.GetRetransmissionAlarm()->Fire();
+
+ // Retransmit due to explicit nacks.
+ QuicAckFrame nack_three = InitAckFrame(4);
+ NackPacket(3, &nack_three);
+ NackPacket(1, &nack_three);
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
+ lost_packets.push_back(std::make_pair(3, kMaxPacketSize));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
+ .WillOnce(SetArgPointee<4>(lost_packets));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ EXPECT_CALL(visitor_, OnCanWrite());
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ ProcessAckPacket(&nack_three);
+
+ EXPECT_CALL(*send_algorithm_, BandwidthEstimate())
+ .WillOnce(Return(QuicBandwidth::Zero()));
+
+ const QuicConnectionStats& stats = connection_.GetStats();
+ EXPECT_EQ(3 * first_packet_size + 2 * second_packet_size - kQuicVersionSize,
+ stats.bytes_sent);
+ EXPECT_EQ(5u, stats.packets_sent);
+ EXPECT_EQ(2 * first_packet_size + second_packet_size - kQuicVersionSize,
+ stats.bytes_retransmitted);
+ EXPECT_EQ(3u, stats.packets_retransmitted);
+ EXPECT_EQ(1u, stats.rto_count);
+ EXPECT_EQ(kDefaultMaxPacketSize, stats.max_packet_size);
+}
+
+TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) {
+ // Construct a packet with stream frame and connection close frame.
+ QuicPacketHeader header;
+ header.public_header.connection_id = connection_id_;
+ header.packet_number = 1;
+ header.public_header.version_flag = false;
+
+ QuicConnectionCloseFrame qccf;
+ qccf.error_code = QUIC_PEER_GOING_AWAY;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&frame1_));
+ frames.push_back(QuicFrame(&qccf));
+ std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
+ EXPECT_TRUE(nullptr != packet.get());
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length = framer_.EncryptPayload(
+ ENCRYPTION_NONE, kDefaultPathId, 1, *packet, buffer, kMaxPacketSize);
+
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, _,
+ ConnectionCloseSource::FROM_PEER));
+ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ connection_.ProcessUdpPacket(
+ kSelfAddress, kPeerAddress,
+ QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
+}
+
+TEST_P(QuicConnectionTest, SelectMutualVersion) {
+ connection_.SetSupportedVersions(AllSupportedVersions());
+ // Set the connection to speak the lowest quic version.
+ connection_.set_version(QuicVersionMin());
+ EXPECT_EQ(QuicVersionMin(), connection_.version());
+
+ // Pass in available versions which includes a higher mutually supported
+ // version. The higher mutually supported version should be selected.
+ QuicVersionVector supported_versions;
+ for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
+ supported_versions.push_back(kSupportedQuicVersions[i]);
+ }
+ EXPECT_TRUE(connection_.SelectMutualVersion(supported_versions));
+ 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());
+ QuicVersionVector lowest_version_vector;
+ lowest_version_vector.push_back(QuicVersionMin());
+ EXPECT_TRUE(connection_.SelectMutualVersion(lowest_version_vector));
+ EXPECT_EQ(QuicVersionMin(), connection_.version());
+
+ // Shouldn't be able to find a mutually supported version.
+ QuicVersionVector unsupported_version;
+ unsupported_version.push_back(QUIC_VERSION_UNSUPPORTED);
+ EXPECT_FALSE(connection_.SelectMutualVersion(unsupported_version));
+}
+
+TEST_P(QuicConnectionTest, ConnectionCloseWhenWritable) {
+ EXPECT_FALSE(writer_->IsWriteBlocked());
+
+ // Send a packet.
+ connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
+ EXPECT_EQ(0u, connection_.NumQueuedPackets());
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+
+ TriggerConnectionClose();
+ EXPECT_EQ(2u, writer_->packets_write_attempts());
+}
+
+TEST_P(QuicConnectionTest, ConnectionCloseGettingWriteBlocked) {
+ BlockOnNextWrite();
+ TriggerConnectionClose();
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+ EXPECT_TRUE(writer_->IsWriteBlocked());
+}
+
+TEST_P(QuicConnectionTest, ConnectionCloseWhenWriteBlocked) {
+ BlockOnNextWrite();
+ connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
+ EXPECT_EQ(1u, connection_.NumQueuedPackets());
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+ EXPECT_TRUE(writer_->IsWriteBlocked());
+ TriggerConnectionClose();
+ EXPECT_EQ(1u, writer_->packets_write_attempts());
+}
+
+TEST_P(QuicConnectionTest, AckNotifierTriggerCallback) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ // Create a listener which we expect to be called.
+ scoped_refptr<MockAckListener> listener(new MockAckListener);
+ EXPECT_CALL(*listener, OnPacketAcked(_, _)).Times(1);
+
+ // Send some data, which will register the listener to be notified.
+ connection_.SendStreamDataWithString(1, "foo", 0, !kFin, listener.get());
+
+ // Process an ACK from the server which should trigger the callback.
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ QuicAckFrame frame = InitAckFrame(1);
+ ProcessAckPacket(&frame);
+}
+
+TEST_P(QuicConnectionTest, AckNotifierFailToTriggerCallback) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ // Create a listener which we don't expect to be called.
+ scoped_refptr<MockAckListener> listener(new MockAckListener);
+ EXPECT_CALL(*listener, OnPacketAcked(_, _)).Times(0);
+
+ // Send some data, which will register the listener to be notified. This will
+ // not be ACKed and so the listener should never be called.
+ connection_.SendStreamDataWithString(1, "foo", 0, !kFin, listener.get());
+
+ // Send some other data which we will ACK.
+ connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
+ connection_.SendStreamDataWithString(1, "bar", 0, !kFin, nullptr);
+
+ // Now we receive ACK for packets 2 and 3, but importantly missing packet 1
+ // which we registered to be notified about.
+ QuicAckFrame frame = InitAckFrame(3);
+ NackPacket(1, &frame);
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
+ .WillOnce(SetArgPointee<4>(lost_packets));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ ProcessAckPacket(&frame);
+}
+
+TEST_P(QuicConnectionTest, AckNotifierCallbackAfterRetransmission) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ // Create a listener which we expect to be called.
+ scoped_refptr<MockAckListener> listener(new MockAckListener);
+ EXPECT_CALL(*listener, OnPacketRetransmitted(3)).Times(1);
+ EXPECT_CALL(*listener, OnPacketAcked(3, _)).Times(1);
+
+ // Send four packets, and register to be notified on ACK of packet 2.
+ connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
+ connection_.SendStreamDataWithString(3, "bar", 0, !kFin, listener.get());
+ connection_.SendStreamDataWithString(3, "baz", 0, !kFin, nullptr);
+ connection_.SendStreamDataWithString(3, "qux", 0, !kFin, nullptr);
+
+ // Now we receive ACK for packets 1, 3, and 4 and lose 2.
+ QuicAckFrame frame = InitAckFrame(4);
+ NackPacket(2, &frame);
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ lost_packets.push_back(std::make_pair(2, kMaxPacketSize));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
+ .WillOnce(SetArgPointee<4>(lost_packets));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ ProcessAckPacket(&frame);
+
+ // Now we get an ACK for packet 5 (retransmitted packet 2), which should
+ // trigger the callback.
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ QuicAckFrame second_ack_frame = InitAckFrame(5);
+ ProcessAckPacket(&second_ack_frame);
+}
+
+// AckNotifierCallback is triggered by the ack of a packet that timed
+// out and was retransmitted, even though the retransmission has a
+// different packet number.
+TEST_P(QuicConnectionTest, AckNotifierCallbackForAckAfterRTO) {
+ connection_.SetMaxTailLossProbes(kDefaultPathId, 0);
+
+ // Create a listener which we expect to be called.
+ scoped_refptr<MockAckListener> listener(new StrictMock<MockAckListener>);
+
+ QuicTime default_retransmission_time =
+ clock_.ApproximateNow() + DefaultRetransmissionTime();
+ connection_.SendStreamDataWithString(3, "foo", 0, !kFin, listener.get());
+ EXPECT_EQ(1u, stop_waiting()->least_unacked);
+
+ EXPECT_EQ(1u, writer_->header().packet_number);
+ EXPECT_EQ(default_retransmission_time,
+ connection_.GetRetransmissionAlarm()->deadline());
+ // Simulate the retransmission alarm firing.
+ clock_.AdvanceTime(DefaultRetransmissionTime());
+ EXPECT_CALL(*listener, OnPacketRetransmitted(3));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
+ connection_.GetRetransmissionAlarm()->Fire();
+ EXPECT_EQ(2u, writer_->header().packet_number);
+ // We do not raise the high water mark yet.
+ EXPECT_EQ(1u, stop_waiting()->least_unacked);
+
+ // Ack the original packet, which will revert the RTO.
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ EXPECT_CALL(*listener, OnPacketAcked(3, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ QuicAckFrame ack_frame = InitAckFrame(1);
+ ProcessAckPacket(&ack_frame);
+
+ // listener is not notified again when the retransmit is acked.
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ QuicAckFrame second_ack_frame = InitAckFrame(2);
+ ProcessAckPacket(&second_ack_frame);
+}
+
+// AckNotifierCallback is triggered by the ack of a packet that was
+// previously nacked, even though the retransmission has a different
+// packet number.
+TEST_P(QuicConnectionTest, AckNotifierCallbackForAckOfNackedPacket) {
+ // Create a listener which we expect to be called.
+ scoped_refptr<MockAckListener> listener(new StrictMock<MockAckListener>);
+
+ // Send four packets, and register to be notified on ACK of packet 2.
+ connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
+ connection_.SendStreamDataWithString(3, "bar", 0, !kFin, listener.get());
+ connection_.SendStreamDataWithString(3, "baz", 0, !kFin, nullptr);
+ connection_.SendStreamDataWithString(3, "qux", 0, !kFin, nullptr);
+
+ // Now we receive ACK for packets 1, 3, and 4 and lose 2.
+ QuicAckFrame frame = InitAckFrame(4);
+ NackPacket(2, &frame);
+ EXPECT_CALL(*listener, OnPacketRetransmitted(_));
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ lost_packets.push_back(std::make_pair(2, kMaxPacketSize));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
+ .WillOnce(SetArgPointee<4>(lost_packets));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ ProcessAckPacket(&frame);
+
+ // Now we get an ACK for packet 2, which was previously nacked.
+ EXPECT_CALL(*listener, OnPacketAcked(3, _));
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+ QuicAckFrame second_ack_frame = InitAckFrame(4);
+ ProcessAckPacket(&second_ack_frame);
+
+ // Verify that the listener is not notified again when the
+ // retransmit is acked.
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ QuicAckFrame third_ack_frame = InitAckFrame(5);
+ ProcessAckPacket(&third_ack_frame);
+}
+
+TEST_P(QuicConnectionTest, OnPacketHeaderDebugVisitor) {
+ QuicPacketHeader header;
+ header.packet_number = 1;
+
+ MockQuicConnectionDebugVisitor debug_visitor;
+ connection_.set_debug_visitor(&debug_visitor);
+ EXPECT_CALL(debug_visitor, OnPacketHeader(Ref(header))).Times(1);
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)).Times(1);
+ EXPECT_CALL(debug_visitor, OnSuccessfulVersionNegotiation(_)).Times(1);
+ connection_.OnPacketHeader(header);
+}
+
+TEST_P(QuicConnectionTest, Pacing) {
+ // static_cast here does not work if using multipath_sent_packet_manager.
+ FLAGS_quic_enable_multipath = false;
+ TestConnection server(connection_id_, kSelfAddress, helper_.get(),
+ alarm_factory_.get(), writer_.get(),
+ Perspective::IS_SERVER, version());
+ TestConnection client(connection_id_, kPeerAddress, helper_.get(),
+ alarm_factory_.get(), writer_.get(),
+ Perspective::IS_CLIENT, version());
+ EXPECT_FALSE(QuicSentPacketManagerPeer::UsingPacing(
+ static_cast<const QuicSentPacketManager*>(
+ &client.sent_packet_manager())));
+ EXPECT_FALSE(QuicSentPacketManagerPeer::UsingPacing(
+ static_cast<const QuicSentPacketManager*>(
+ &server.sent_packet_manager())));
+}
+
+TEST_P(QuicConnectionTest, WindowUpdateInstigateAcks) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ // Send a WINDOW_UPDATE frame.
+ QuicWindowUpdateFrame window_update;
+ window_update.stream_id = 3;
+ window_update.byte_offset = 1234;
+ EXPECT_CALL(visitor_, OnWindowUpdateFrame(_));
+ ProcessFramePacket(QuicFrame(&window_update));
+
+ // Ensure that this has caused the ACK alarm to be set.
+ QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
+ EXPECT_TRUE(ack_alarm->IsSet());
+}
+
+TEST_P(QuicConnectionTest, BlockedFrameInstigateAcks) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ // Send a BLOCKED frame.
+ QuicBlockedFrame blocked;
+ blocked.stream_id = 3;
+ EXPECT_CALL(visitor_, OnBlockedFrame(_));
+ ProcessFramePacket(QuicFrame(&blocked));
+
+ // Ensure that this has caused the ACK alarm to be set.
+ QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
+ EXPECT_TRUE(ack_alarm->IsSet());
+}
+
+TEST_P(QuicConnectionTest, NoDataNoFin) {
+ // Make sure that a call to SendStreamWithData, with no data and no FIN, does
+ // not result in a QuicAckNotifier being used-after-free (fail under ASAN).
+ // Regression test for b/18594622
+ scoped_refptr<MockAckListener> listener(new MockAckListener);
+ EXPECT_QUIC_BUG(
+ connection_.SendStreamDataWithString(3, "", 0, !kFin, listener.get()),
+ "Attempt to send empty stream frame");
+}
+
+TEST_P(QuicConnectionTest, DoNotSendGoAwayTwice) {
+ EXPECT_FALSE(connection_.goaway_sent());
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ connection_.SendGoAway(QUIC_PEER_GOING_AWAY, kHeadersStreamId, "Going Away.");
+ EXPECT_TRUE(connection_.goaway_sent());
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+ connection_.SendGoAway(QUIC_PEER_GOING_AWAY, kHeadersStreamId, "Going Away.");
+}
+
+TEST_P(QuicConnectionTest, ReevaluateTimeUntilSendOnAck) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0, !kFin,
+ nullptr);
+
+ // Evaluate CanWrite, and have it return a non-Zero value.
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ .WillRepeatedly(Return(QuicTime::Delta::FromMilliseconds(1)));
+ connection_.OnCanWrite();
+ EXPECT_TRUE(connection_.GetSendAlarm()->IsSet());
+ EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromMilliseconds(1),
+ connection_.GetSendAlarm()->deadline());
+
+ // Process an ack and the send alarm will be set to the new 2ms delay.
+ QuicAckFrame ack = InitAckFrame(1);
+ EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ .WillRepeatedly(Return(QuicTime::Delta::FromMilliseconds(2)));
+ ProcessAckPacket(&ack);
+ EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_EQ(1u, writer_->stream_frames().size());
+ EXPECT_TRUE(connection_.GetSendAlarm()->IsSet());
+ EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromMilliseconds(2),
+ connection_.GetSendAlarm()->deadline());
+ writer_->Reset();
+}
+
+TEST_P(QuicConnectionTest, SendAcksImmediately) {
+ CongestionBlockWrites();
+ SendAckPacketToPeer();
+}
+
+TEST_P(QuicConnectionTest, SendPingImmediately) {
+ MockQuicConnectionDebugVisitor debug_visitor;
+ connection_.set_debug_visitor(&debug_visitor);
+
+ CongestionBlockWrites();
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+ EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _)).Times(1);
+ EXPECT_CALL(debug_visitor, OnPingSent()).Times(1);
+ connection_.SendPing();
+ EXPECT_FALSE(connection_.HasQueuedData());
+}
+
+TEST_P(QuicConnectionTest, SendingUnencryptedStreamDataFails) {
+ EXPECT_CALL(visitor_,
+ OnConnectionClosed(QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA,
+ _, ConnectionCloseSource::FROM_SELF));
+ struct iovec iov;
+ QuicIOVector data_iov(MakeIOVector("", &iov));
+ EXPECT_QUIC_BUG(connection_.SendStreamData(3, data_iov, 0, kFin, nullptr),
+ "Cannot send stream data without encryption.");
+ EXPECT_FALSE(connection_.connected());
+}
+
+TEST_P(QuicConnectionTest, EnableMultipathNegotiation) {
+ // Test multipath negotiation during crypto handshake. Multipath is enabled
+ // when both endpoints enable multipath.
+ FLAGS_quic_enable_multipath = true;
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_FALSE(QuicConnectionPeer::IsMultipathEnabled(&connection_));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ QuicConfig config;
+ // Enable multipath on server side.
+ config.SetMultipathEnabled(true);
+
+ // Create a handshake message enables multipath.
+ CryptoHandshakeMessage msg;
+ string error_details;
+ QuicConfig client_config;
+ // Enable multipath on client side.
+ client_config.SetMultipathEnabled(true);
+ client_config.ToHandshakeMessage(&msg);
+ const QuicErrorCode error =
+ config.ProcessPeerHello(msg, CLIENT, &error_details);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+
+ connection_.SetFromConfig(config);
+ EXPECT_TRUE(QuicConnectionPeer::IsMultipathEnabled(&connection_));
+}
+
+TEST_P(QuicConnectionTest, ClosePath) {
+ QuicPathId kTestPathId = 1;
+ connection_.SendPathClose(kTestPathId);
+ EXPECT_TRUE(QuicFramerPeer::IsPathClosed(
+ QuicConnectionPeer::GetFramer(&connection_), kTestPathId));
+}
+
+TEST_P(QuicConnectionTest, BadMultipathFlag) {
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_BAD_MULTIPATH_FLAG, _,
+ ConnectionCloseSource::FROM_SELF));
+
+ // Receieve a packet with multipath flag on when multipath is not enabled.
+ EXPECT_TRUE(connection_.connected());
+ EXPECT_FALSE(QuicConnectionPeer::IsMultipathEnabled(&connection_));
+ peer_creator_.SetCurrentPath(/*path_id=*/1u, 1u, 10u);
+ QuicStreamFrame stream_frame(1u, false, 0u, StringPiece());
+ EXPECT_QUIC_BUG(
+ ProcessFramePacket(QuicFrame(&stream_frame)),
+ "Received a packet with multipath flag but multipath is not enabled.");
+ EXPECT_FALSE(connection_.connected());
+}
+
+TEST_P(QuicConnectionTest, OnPathDegrading) {
+ QuicByteCount packet_size;
+ const size_t kMinTimeoutsBeforePathDegrading = 2;
+
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(DoAll(SaveArg<3>(&packet_size), Return(true)));
+ connection_.SendStreamDataWithString(3, "packet", 0, !kFin, nullptr);
+ size_t num_timeouts = kMinTimeoutsBeforePathDegrading +
+ QuicSentPacketManagerPeer::GetMaxTailLossProbes(
+ QuicConnectionPeer::GetSentPacketManager(
+ &connection_, kDefaultPathId));
+ for (size_t i = 1; i < num_timeouts; ++i) {
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10 * i));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, packet_size, _));
+ connection_.GetRetransmissionAlarm()->Fire();
+ }
+ // Next RTO should cause OnPathDegrading to be called before the
+ // retransmission is sent out.
+ clock_.AdvanceTime(
+ QuicTime::Delta::FromSeconds(kMinTimeoutsBeforePathDegrading * 10));
+ {
+ InSequence s;
+ EXPECT_CALL(visitor_, OnPathDegrading());
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, packet_size, _));
+ }
+ connection_.GetRetransmissionAlarm()->Fire();
+}
+
+TEST_P(QuicConnectionTest, MultipleCallsToCloseConnection) {
+ // Verifies that multiple calls to CloseConnection do not
+ // result in multiple attempts to close the connection - it will be marked as
+ // disconnected after the first call.
+ EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(1);
+ connection_.CloseConnection(QUIC_NO_ERROR, "no reason",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+ connection_.CloseConnection(QUIC_NO_ERROR, "no reason",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+}
+
+TEST_P(QuicConnectionTest, ServerReceivesChloOnNonCryptoStream) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ set_perspective(Perspective::IS_SERVER);
+ QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+
+ CryptoHandshakeMessage message;
+ CryptoFramer framer;
+ message.set_tag(kCHLO);
+ std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
+ frame1_.stream_id = 10;
+ frame1_.data_buffer = data->data();
+ frame1_.data_length = data->length();
+
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_MAYBE_CORRUPTED_MEMORY, _,
+ ConnectionCloseSource::FROM_SELF));
+ ForceProcessFramePacket(QuicFrame(&frame1_));
+}
+
+TEST_P(QuicConnectionTest, ClientReceivesRejOnNonCryptoStream) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+
+ CryptoHandshakeMessage message;
+ CryptoFramer framer;
+ message.set_tag(kREJ);
+ std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
+ frame1_.stream_id = 10;
+ frame1_.data_buffer = data->data();
+ frame1_.data_length = data->length();
+
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_MAYBE_CORRUPTED_MEMORY, _,
+ ConnectionCloseSource::FROM_SELF));
+ ForceProcessFramePacket(QuicFrame(&frame1_));
+}
+
+TEST_P(QuicConnectionTest, CloseConnectionOnPacketTooLarge) {
+ SimulateNextPacketTooLarge();
+ if (!FLAGS_quic_only_track_sent_packets) {
+ // Although the data packet cannot be written, the send packet manager is
+ // informed.
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ }
+ // A connection close packet is sent
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PACKET_WRITE_ERROR, _,
+ ConnectionCloseSource::FROM_SELF))
+ .Times(1);
+ connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
+}
+
+TEST_P(QuicConnectionTest, AlwaysGetPacketTooLarge) {
+ // Test even we always get packet too large, we do not infinitely try to send
+ // close packet.
+ AlwaysGetPacketTooLarge();
+ if (!FLAGS_quic_only_track_sent_packets) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+ }
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PACKET_WRITE_ERROR, _,
+ ConnectionCloseSource::FROM_SELF))
+ .Times(1);
+ connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
+}
+
+// Verify that if connection has no outstanding data, it notifies the send
+// algorithm after the write.
+TEST_P(QuicConnectionTest, SendDataAndBecomeApplicationLimited) {
+ EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(1);
+ {
+ InSequence seq;
+ EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(visitor_, WillingAndAbleToWrite())
+ .WillRepeatedly(Return(false));
+ }
+
+ connection_.SendStreamData3();
+}
+
+// Verify that the connection does not become app-limited if there is
+// outstanding data to send after the write.
+TEST_P(QuicConnectionTest, NotBecomeApplicationLimitedIfMoreDataAvailable) {
+ EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(0);
+ {
+ InSequence seq;
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillRepeatedly(Return(true));
+ }
+
+ connection_.SendStreamData3();
+}
+
+// Verify that the connection does not become app-limited after blocked write
+// even if there is outstanding data to send after the write.
+TEST_P(QuicConnectionTest, NotBecomeApplicationLimitedDueToWriteBlock) {
+ EXPECT_CALL(*send_algorithm_, OnApplicationLimited(_)).Times(0);
+ EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillRepeatedly(Return(true));
+ BlockOnNextWrite();
+
+ connection_.SendStreamData3();
+}
+
+TEST_P(QuicConnectionTest, DonotForceSendingAckOnPacketTooLarge) {
+ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+ // Send an ack by simulating delayed ack alarm firing.
+ ProcessPacket(kDefaultPathId, 1);
+ QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
+ EXPECT_TRUE(ack_alarm->IsSet());
+ connection_.GetAckAlarm()->Fire();
+ // Simulate data packet causes write error.
+ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PACKET_WRITE_ERROR, _, _));
+ SimulateNextPacketTooLarge();
+ connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
+ EXPECT_EQ(1u, writer_->frame_count());
+ EXPECT_FALSE(writer_->connection_close_frames().empty());
+ // Ack frame is not bundled in connection close packet.
+ EXPECT_TRUE(writer_->ack_frames().empty());
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_crypto_client_stream.cc b/chromium/net/quic/core/quic_crypto_client_stream.cc
new file mode 100644
index 00000000000..89fa59016bd
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_client_stream.cc
@@ -0,0 +1,678 @@
+// 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/quic_crypto_client_stream.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/strings/stringprintf.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/crypto_utils.h"
+#include "net/quic/core/crypto/null_encrypter.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_session.h"
+#include "net/quic/core/quic_utils.h"
+
+using std::string;
+using std::vector;
+
+namespace net {
+
+QuicCryptoClientStreamBase::QuicCryptoClientStreamBase(QuicSession* session)
+ : QuicCryptoStream(session) {}
+
+QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
+ ChannelIDSourceCallbackImpl(QuicCryptoClientStream* stream)
+ : stream_(stream) {}
+
+QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
+ ~ChannelIDSourceCallbackImpl() {}
+
+void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Run(
+ std::unique_ptr<ChannelIDKey>* channel_id_key) {
+ if (stream_ == nullptr) {
+ return;
+ }
+
+ stream_->channel_id_key_.reset(channel_id_key->release());
+ stream_->channel_id_source_callback_run_ = true;
+ stream_->channel_id_source_callback_ = nullptr;
+ stream_->DoHandshakeLoop(nullptr);
+
+ // The ChannelIDSource owns this object and will delete it when this method
+ // returns.
+}
+
+void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Cancel() {
+ stream_ = nullptr;
+}
+
+QuicCryptoClientStream::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl(
+ QuicCryptoClientStream* stream)
+ : stream_(stream) {}
+
+QuicCryptoClientStream::ProofVerifierCallbackImpl::
+ ~ProofVerifierCallbackImpl() {}
+
+void QuicCryptoClientStream::ProofVerifierCallbackImpl::Run(
+ bool ok,
+ const string& error_details,
+ std::unique_ptr<ProofVerifyDetails>* details) {
+ if (stream_ == nullptr) {
+ return;
+ }
+
+ stream_->verify_ok_ = ok;
+ stream_->verify_error_details_ = error_details;
+ stream_->verify_details_.reset(details->release());
+ stream_->proof_verify_callback_ = nullptr;
+ stream_->DoHandshakeLoop(nullptr);
+
+ // The ProofVerifier owns this object and will delete it when this method
+ // returns.
+}
+
+void QuicCryptoClientStream::ProofVerifierCallbackImpl::Cancel() {
+ stream_ = nullptr;
+}
+
+QuicCryptoClientStream::QuicCryptoClientStream(
+ const QuicServerId& server_id,
+ QuicSession* session,
+ ProofVerifyContext* verify_context,
+ QuicCryptoClientConfig* crypto_config,
+ ProofHandler* proof_handler)
+ : QuicCryptoClientStreamBase(session),
+ next_state_(STATE_IDLE),
+ num_client_hellos_(0),
+ crypto_config_(crypto_config),
+ server_id_(server_id),
+ generation_counter_(0),
+ channel_id_sent_(false),
+ channel_id_source_callback_run_(false),
+ channel_id_source_callback_(nullptr),
+ verify_context_(verify_context),
+ proof_verify_callback_(nullptr),
+ proof_handler_(proof_handler),
+ stateless_reject_received_(false),
+ num_scup_messages_received_(0) {
+ DCHECK_EQ(Perspective::IS_CLIENT, session->connection()->perspective());
+}
+
+QuicCryptoClientStream::~QuicCryptoClientStream() {
+ if (channel_id_source_callback_) {
+ channel_id_source_callback_->Cancel();
+ }
+ if (proof_verify_callback_) {
+ proof_verify_callback_->Cancel();
+ }
+}
+
+void QuicCryptoClientStream::OnHandshakeMessage(
+ const CryptoHandshakeMessage& message) {
+ QuicCryptoClientStreamBase::OnHandshakeMessage(message);
+
+ if (message.tag() == kSCUP) {
+ if (!handshake_confirmed()) {
+ CloseConnectionWithDetails(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE,
+ "Early SCUP disallowed");
+ return;
+ }
+
+ // |message| is an update from the server, so we treat it differently from a
+ // handshake message.
+ HandleServerConfigUpdateMessage(message);
+ num_scup_messages_received_++;
+ return;
+ }
+
+ // Do not process handshake messages after the handshake is confirmed.
+ if (handshake_confirmed()) {
+ CloseConnectionWithDetails(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
+ "Unexpected handshake message");
+ return;
+ }
+
+ DoHandshakeLoop(&message);
+}
+
+void QuicCryptoClientStream::CryptoConnect() {
+ next_state_ = STATE_INITIALIZE;
+ DoHandshakeLoop(nullptr);
+}
+
+int QuicCryptoClientStream::num_sent_client_hellos() const {
+ return num_client_hellos_;
+}
+
+int QuicCryptoClientStream::num_scup_messages_received() const {
+ return num_scup_messages_received_;
+}
+
+// Used in Chromium, but not in the server.
+bool QuicCryptoClientStream::WasChannelIDSent() const {
+ return channel_id_sent_;
+}
+
+bool QuicCryptoClientStream::WasChannelIDSourceCallbackRun() const {
+ return channel_id_source_callback_run_;
+}
+
+void QuicCryptoClientStream::HandleServerConfigUpdateMessage(
+ const CryptoHandshakeMessage& server_config_update) {
+ DCHECK(server_config_update.tag() == kSCUP);
+ string error_details;
+ QuicCryptoClientConfig::CachedState* cached =
+ crypto_config_->LookupOrCreate(server_id_);
+ QuicErrorCode error = crypto_config_->ProcessServerConfigUpdate(
+ server_config_update, session()->connection()->clock()->WallNow(),
+ session()->connection()->version(), cached->chlo_hash(), cached,
+ &crypto_negotiated_params_, &error_details);
+
+ if (error != QUIC_NO_ERROR) {
+ CloseConnectionWithDetails(
+ error, "Server config update invalid: " + error_details);
+ return;
+ }
+
+ DCHECK(handshake_confirmed());
+ if (proof_verify_callback_) {
+ proof_verify_callback_->Cancel();
+ }
+ next_state_ = STATE_INITIALIZE_SCUP;
+ DoHandshakeLoop(nullptr);
+}
+
+void QuicCryptoClientStream::DoHandshakeLoop(const CryptoHandshakeMessage* in) {
+ QuicCryptoClientConfig::CachedState* cached =
+ crypto_config_->LookupOrCreate(server_id_);
+
+ QuicAsyncStatus rv = QUIC_SUCCESS;
+ do {
+ CHECK_NE(STATE_NONE, next_state_);
+ const State state = next_state_;
+ next_state_ = STATE_IDLE;
+ rv = QUIC_SUCCESS;
+ switch (state) {
+ case STATE_INITIALIZE:
+ DoInitialize(cached);
+ break;
+ case STATE_SEND_CHLO:
+ DoSendCHLO(cached);
+ return; // return waiting to hear from server.
+ case STATE_RECV_REJ:
+ DoReceiveREJ(in, cached);
+ break;
+ case STATE_VERIFY_PROOF:
+ rv = DoVerifyProof(cached);
+ break;
+ case STATE_VERIFY_PROOF_COMPLETE:
+ DoVerifyProofComplete(cached);
+ break;
+ case STATE_GET_CHANNEL_ID:
+ rv = DoGetChannelID(cached);
+ break;
+ case STATE_GET_CHANNEL_ID_COMPLETE:
+ DoGetChannelIDComplete();
+ break;
+ case STATE_RECV_SHLO:
+ DoReceiveSHLO(in, cached);
+ break;
+ case STATE_IDLE:
+ // This means that the peer sent us a message that we weren't expecting.
+ CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
+ "Handshake in idle state");
+ return;
+ case STATE_INITIALIZE_SCUP:
+ DoInitializeServerConfigUpdate(cached);
+ break;
+ case STATE_NONE:
+ NOTREACHED();
+ return; // We are done.
+ }
+ } while (rv != QUIC_PENDING && next_state_ != STATE_NONE);
+}
+
+void QuicCryptoClientStream::DoInitialize(
+ QuicCryptoClientConfig::CachedState* cached) {
+ if (!cached->IsEmpty() && !cached->signature().empty()) {
+ // Note that we verify the proof even if the cached proof is valid.
+ // This allows us to respond to CA trust changes or certificate
+ // expiration because it may have been a while since we last verified
+ // the proof.
+ DCHECK(crypto_config_->proof_verifier());
+ // Track proof verification time when cached server config is used.
+ proof_verify_start_time_ = base::TimeTicks::Now();
+ chlo_hash_ = cached->chlo_hash();
+ // If the cached state needs to be verified, do it now.
+ next_state_ = STATE_VERIFY_PROOF;
+ } else {
+ next_state_ = STATE_GET_CHANNEL_ID;
+ }
+}
+
+void QuicCryptoClientStream::DoSendCHLO(
+ QuicCryptoClientConfig::CachedState* cached) {
+ if (stateless_reject_received_) {
+ // If we've gotten to this point, we've sent at least one hello
+ // and received a stateless reject in response. We cannot
+ // continue to send hellos because the server has abandoned state
+ // for this connection. Abandon further handshakes.
+ next_state_ = STATE_NONE;
+ if (session()->connection()->connected()) {
+ session()->connection()->CloseConnection(
+ QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject received",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+ }
+ return;
+ }
+
+ // Send the client hello in plaintext.
+ session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
+ encryption_established_ = false;
+ if (num_client_hellos_ > kMaxClientHellos) {
+ CloseConnectionWithDetails(
+ QUIC_CRYPTO_TOO_MANY_REJECTS,
+ base::StringPrintf("More than %u rejects", kMaxClientHellos).c_str());
+ return;
+ }
+ num_client_hellos_++;
+
+ CryptoHandshakeMessage out;
+ DCHECK(session() != nullptr);
+ DCHECK(session()->config() != nullptr);
+ // Send all the options, regardless of whether we're sending an
+ // inchoate or subsequent hello.
+ session()->config()->ToHandshakeMessage(&out);
+
+ // Send a local timestamp to the server.
+ out.SetValue(kCTIM,
+ session()->connection()->clock()->WallNow().ToUNIXSeconds());
+
+ if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
+ crypto_config_->FillInchoateClientHello(
+ server_id_, session()->connection()->supported_versions().front(),
+ cached, session()->connection()->random_generator(),
+ /* demand_x509_proof= */ true, &crypto_negotiated_params_, &out);
+ // Pad the inchoate client hello to fill up a packet.
+ const QuicByteCount kFramingOverhead = 50; // A rough estimate.
+ const QuicByteCount max_packet_size =
+ session()->connection()->max_packet_length();
+ if (max_packet_size <= kFramingOverhead) {
+ DLOG(DFATAL) << "max_packet_length (" << max_packet_size
+ << ") has no room for framing overhead.";
+ CloseConnectionWithDetails(QUIC_INTERNAL_ERROR,
+ "max_packet_size too smalll");
+ return;
+ }
+ if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
+ DLOG(DFATAL) << "Client hello won't fit in a single packet.";
+ CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, "CHLO too large");
+ return;
+ }
+ // TODO(rch): Remove this when we remove:
+ // FLAGS_quic_use_chlo_packet_size
+ out.set_minimum_size(
+ static_cast<size_t>(max_packet_size - kFramingOverhead));
+ next_state_ = STATE_RECV_REJ;
+ CryptoUtils::HashHandshakeMessage(out, &chlo_hash_);
+ SendHandshakeMessage(out);
+ return;
+ }
+
+ // If the server nonce is empty, copy over the server nonce from a previous
+ // SREJ, if there is one.
+ if (FLAGS_enable_quic_stateless_reject_support &&
+ crypto_negotiated_params_.server_nonce.empty() &&
+ cached->has_server_nonce()) {
+ crypto_negotiated_params_.server_nonce = cached->GetNextServerNonce();
+ DCHECK(!crypto_negotiated_params_.server_nonce.empty());
+ }
+
+ string error_details;
+ QuicErrorCode error = crypto_config_->FillClientHello(
+ server_id_, session()->connection()->connection_id(),
+ session()->connection()->version(),
+ session()->connection()->supported_versions().front(), cached,
+ session()->connection()->clock()->WallNow(),
+ session()->connection()->random_generator(), channel_id_key_.get(),
+ &crypto_negotiated_params_, &out, &error_details);
+ if (error != QUIC_NO_ERROR) {
+ // Flush the cached config so that, if it's bad, the server has a
+ // chance to send us another in the future.
+ cached->InvalidateServerConfig();
+ CloseConnectionWithDetails(error, error_details);
+ return;
+ }
+ CryptoUtils::HashHandshakeMessage(out, &chlo_hash_);
+ channel_id_sent_ = (channel_id_key_.get() != nullptr);
+ if (cached->proof_verify_details()) {
+ proof_handler_->OnProofVerifyDetailsAvailable(
+ *cached->proof_verify_details());
+ }
+ next_state_ = STATE_RECV_SHLO;
+ SendHandshakeMessage(out);
+ // Be prepared to decrypt with the new server write key.
+ session()->connection()->SetAlternativeDecrypter(
+ ENCRYPTION_INITIAL,
+ crypto_negotiated_params_.initial_crypters.decrypter.release(),
+ true /* latch once used */);
+ // Send subsequent packets under encryption on the assumption that the
+ // server will accept the handshake.
+ session()->connection()->SetEncrypter(
+ ENCRYPTION_INITIAL,
+ crypto_negotiated_params_.initial_crypters.encrypter.release());
+ session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+
+ // TODO(ianswett): Merge ENCRYPTION_REESTABLISHED and
+ // ENCRYPTION_FIRST_ESTABLSIHED
+ encryption_established_ = true;
+ session()->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_REESTABLISHED);
+}
+
+void QuicCryptoClientStream::DoReceiveREJ(
+ const CryptoHandshakeMessage* in,
+ QuicCryptoClientConfig::CachedState* cached) {
+ // We sent a dummy CHLO because we didn't have enough information to
+ // perform a handshake, or we sent a full hello that the server
+ // rejected. Here we hope to have a REJ that contains the information
+ // that we need.
+ if ((in->tag() != kREJ) && (in->tag() != kSREJ)) {
+ next_state_ = STATE_NONE;
+ CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
+ "Expected REJ");
+ return;
+ }
+
+ const uint32_t* reject_reasons;
+ size_t num_reject_reasons;
+ static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync");
+ if (in->GetTaglist(kRREJ, &reject_reasons, &num_reject_reasons) ==
+ QUIC_NO_ERROR) {
+ uint32_t packed_error = 0;
+ for (size_t i = 0; i < num_reject_reasons; ++i) {
+ // HANDSHAKE_OK is 0 and don't report that as error.
+ if (reject_reasons[i] == HANDSHAKE_OK || reject_reasons[i] >= 32) {
+ continue;
+ }
+ HandshakeFailureReason reason =
+ static_cast<HandshakeFailureReason>(reject_reasons[i]);
+ packed_error |= 1 << (reason - 1);
+ }
+ DVLOG(1) << "Reasons for rejection: " << packed_error;
+ if (num_client_hellos_ == kMaxClientHellos) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.TooMany",
+ packed_error);
+ }
+ UMA_HISTOGRAM_SPARSE_SLOWLY("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();
+
+ stateless_reject_received_ = in->tag() == kSREJ;
+ string error_details;
+ QuicErrorCode error = crypto_config_->ProcessRejection(
+ *in, session()->connection()->clock()->WallNow(),
+ session()->connection()->version(), chlo_hash_, cached,
+ &crypto_negotiated_params_, &error_details);
+
+ if (error != QUIC_NO_ERROR) {
+ next_state_ = STATE_NONE;
+ CloseConnectionWithDetails(error, error_details);
+ return;
+ }
+ if (!cached->proof_valid()) {
+ if (!cached->signature().empty()) {
+ // Note that we only verify the proof if the cached proof is not
+ // valid. If the cached proof is valid here, someone else must have
+ // just added the server config to the cache and verified the proof,
+ // so we can assume no CA trust changes or certificate expiration
+ // has happened since then.
+ next_state_ = STATE_VERIFY_PROOF;
+ return;
+ }
+ }
+ next_state_ = STATE_GET_CHANNEL_ID;
+}
+
+QuicAsyncStatus QuicCryptoClientStream::DoVerifyProof(
+ QuicCryptoClientConfig::CachedState* cached) {
+ ProofVerifier* verifier = crypto_config_->proof_verifier();
+ DCHECK(verifier);
+ next_state_ = STATE_VERIFY_PROOF_COMPLETE;
+ generation_counter_ = cached->generation_counter();
+
+ ProofVerifierCallbackImpl* proof_verify_callback =
+ new ProofVerifierCallbackImpl(this);
+
+ verify_ok_ = false;
+
+ QuicAsyncStatus status = verifier->VerifyProof(
+ server_id_.host(), server_id_.port(), cached->server_config(),
+ session()->connection()->version(), chlo_hash_, cached->certs(),
+ cached->cert_sct(), cached->signature(), verify_context_.get(),
+ &verify_error_details_, &verify_details_,
+ std::unique_ptr<ProofVerifierCallback>(proof_verify_callback));
+
+ switch (status) {
+ case QUIC_PENDING:
+ proof_verify_callback_ = proof_verify_callback;
+ DVLOG(1) << "Doing VerifyProof";
+ break;
+ case QUIC_FAILURE:
+ break;
+ case QUIC_SUCCESS:
+ verify_ok_ = true;
+ break;
+ }
+ return status;
+}
+
+void QuicCryptoClientStream::DoVerifyProofComplete(
+ QuicCryptoClientConfig::CachedState* cached) {
+ if (!proof_verify_start_time_.is_null()) {
+ UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime.CachedServerConfig",
+ base::TimeTicks::Now() - proof_verify_start_time_);
+ }
+ if (!verify_ok_) {
+ if (verify_details_.get()) {
+ proof_handler_->OnProofVerifyDetailsAvailable(*verify_details_);
+ }
+ if (num_client_hellos_ == 0) {
+ cached->Clear();
+ next_state_ = STATE_INITIALIZE;
+ return;
+ }
+ next_state_ = STATE_NONE;
+ UMA_HISTOGRAM_BOOLEAN("Net.QuicVerifyProofFailed.HandshakeConfirmed",
+ handshake_confirmed());
+ CloseConnectionWithDetails(QUIC_PROOF_INVALID,
+ "Proof invalid: " + verify_error_details_);
+ return;
+ }
+
+ // Check if generation_counter has changed between STATE_VERIFY_PROOF and
+ // STATE_VERIFY_PROOF_COMPLETE state changes.
+ if (generation_counter_ != cached->generation_counter()) {
+ next_state_ = STATE_VERIFY_PROOF;
+ } else {
+ SetCachedProofValid(cached);
+ cached->SetProofVerifyDetails(verify_details_.release());
+ if (!handshake_confirmed()) {
+ next_state_ = STATE_GET_CHANNEL_ID;
+ } else {
+ // TODO: Enable Expect-Staple. https://crbug.com/631101
+ next_state_ = STATE_NONE;
+ }
+ }
+}
+
+QuicAsyncStatus QuicCryptoClientStream::DoGetChannelID(
+ QuicCryptoClientConfig::CachedState* cached) {
+ next_state_ = STATE_GET_CHANNEL_ID_COMPLETE;
+ channel_id_key_.reset();
+ if (!RequiresChannelID(cached)) {
+ next_state_ = STATE_SEND_CHLO;
+ return QUIC_SUCCESS;
+ }
+
+ ChannelIDSourceCallbackImpl* channel_id_source_callback =
+ new ChannelIDSourceCallbackImpl(this);
+ QuicAsyncStatus status = crypto_config_->channel_id_source()->GetChannelIDKey(
+ server_id_.host(), &channel_id_key_, channel_id_source_callback);
+
+ switch (status) {
+ case QUIC_PENDING:
+ channel_id_source_callback_ = channel_id_source_callback;
+ DVLOG(1) << "Looking up channel ID";
+ break;
+ case QUIC_FAILURE:
+ next_state_ = STATE_NONE;
+ delete channel_id_source_callback;
+ CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
+ "Channel ID lookup failed");
+ break;
+ case QUIC_SUCCESS:
+ delete channel_id_source_callback;
+ break;
+ }
+ return status;
+}
+
+void QuicCryptoClientStream::DoGetChannelIDComplete() {
+ if (!channel_id_key_.get()) {
+ next_state_ = STATE_NONE;
+ CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
+ "Channel ID lookup failed");
+ return;
+ }
+ next_state_ = STATE_SEND_CHLO;
+}
+
+void QuicCryptoClientStream::DoReceiveSHLO(
+ const CryptoHandshakeMessage* in,
+ QuicCryptoClientConfig::CachedState* cached) {
+ next_state_ = STATE_NONE;
+ // We sent a CHLO that we expected to be accepted and now we're
+ // hoping for a SHLO from the server to confirm that. First check
+ // to see whether the response was a reject, and if so, move on to
+ // the reject-processing state.
+ if ((in->tag() == kREJ) || (in->tag() == kSREJ)) {
+ // alternative_decrypter will be nullptr if the original alternative
+ // decrypter latched and became the primary decrypter. That happens
+ // if we received a message encrypted with the INITIAL key.
+ if (session()->connection()->alternative_decrypter() == nullptr) {
+ // The rejection was sent encrypted!
+ CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
+ "encrypted REJ message");
+ return;
+ }
+ next_state_ = STATE_RECV_REJ;
+ return;
+ }
+
+ if (in->tag() != kSHLO) {
+ CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
+ "Expected SHLO or REJ");
+ return;
+ }
+
+ // alternative_decrypter will be nullptr if the original alternative
+ // decrypter latched and became the primary decrypter. That happens
+ // if we received a message encrypted with the INITIAL key.
+ if (session()->connection()->alternative_decrypter() != nullptr) {
+ // The server hello was sent without encryption.
+ CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
+ "unencrypted SHLO message");
+ return;
+ }
+
+ string error_details;
+ QuicErrorCode error = crypto_config_->ProcessServerHello(
+ *in, session()->connection()->connection_id(),
+ session()->connection()->version(),
+ session()->connection()->server_supported_versions(), cached,
+ &crypto_negotiated_params_, &error_details);
+
+ if (error != QUIC_NO_ERROR) {
+ CloseConnectionWithDetails(error, "Server hello invalid: " + error_details);
+ return;
+ }
+ error = session()->config()->ProcessPeerHello(*in, SERVER, &error_details);
+ if (error != QUIC_NO_ERROR) {
+ CloseConnectionWithDetails(error, "Server hello invalid: " + error_details);
+ return;
+ }
+ session()->OnConfigNegotiated();
+
+ CrypterPair* crypters = &crypto_negotiated_params_.forward_secure_crypters;
+ // TODO(agl): we don't currently latch this decrypter because the idea
+ // has been floated that the server shouldn't send packets encrypted
+ // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
+ // packet from the client.
+ session()->connection()->SetAlternativeDecrypter(
+ ENCRYPTION_FORWARD_SECURE, crypters->decrypter.release(),
+ false /* don't latch */);
+ session()->connection()->SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+ crypters->encrypter.release());
+ session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+
+ handshake_confirmed_ = true;
+ session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
+ session()->connection()->OnHandshakeComplete();
+}
+
+void QuicCryptoClientStream::DoInitializeServerConfigUpdate(
+ QuicCryptoClientConfig::CachedState* cached) {
+ bool update_ignored = false;
+ if (!cached->IsEmpty() && !cached->signature().empty()) {
+ // Note that we verify the proof even if the cached proof is valid.
+ DCHECK(crypto_config_->proof_verifier());
+ next_state_ = STATE_VERIFY_PROOF;
+ } else {
+ update_ignored = true;
+ next_state_ = STATE_NONE;
+ }
+ UMA_HISTOGRAM_COUNTS("Net.QuicNumServerConfig.UpdateMessagesIgnored",
+ update_ignored);
+}
+
+void QuicCryptoClientStream::SetCachedProofValid(
+ QuicCryptoClientConfig::CachedState* cached) {
+ cached->SetProofValid();
+ proof_handler_->OnProofValid(*cached);
+}
+
+bool QuicCryptoClientStream::RequiresChannelID(
+ QuicCryptoClientConfig::CachedState* cached) {
+ if (server_id_.privacy_mode() == PRIVACY_MODE_ENABLED ||
+ !crypto_config_->channel_id_source()) {
+ return false;
+ }
+ const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
+ if (!scfg) { // scfg may be null then we send an inchoate CHLO.
+ return false;
+ }
+ const QuicTag* their_proof_demands;
+ size_t num_their_proof_demands;
+ if (scfg->GetTaglist(kPDMD, &their_proof_demands, &num_their_proof_demands) !=
+ QUIC_NO_ERROR) {
+ return false;
+ }
+ for (size_t i = 0; i < num_their_proof_demands; i++) {
+ if (their_proof_demands[i] == kCHID) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_crypto_client_stream.h b/chromium/net/quic/core/quic_crypto_client_stream.h
new file mode 100644
index 00000000000..94e3fdae44d
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_client_stream.h
@@ -0,0 +1,277 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_CRYPTO_CLIENT_STREAM_H_
+#define NET_QUIC_QUIC_CRYPTO_CLIENT_STREAM_H_
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/channel_id.h"
+#include "net/quic/core/crypto/proof_verifier.h"
+#include "net/quic/core/crypto/quic_crypto_client_config.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_crypto_stream.h"
+#include "net/quic/core/quic_server_id.h"
+
+namespace net {
+
+namespace test {
+class CryptoTestUtils;
+class QuicChromiumClientSessionPeer;
+} // namespace test
+
+class NET_EXPORT_PRIVATE QuicCryptoClientStreamBase : public QuicCryptoStream {
+ public:
+ explicit QuicCryptoClientStreamBase(QuicSession* session);
+
+ ~QuicCryptoClientStreamBase() override{};
+
+ // Performs a crypto handshake with the server.
+ virtual void CryptoConnect() = 0;
+
+ // num_sent_client_hellos returns the number of client hello messages that
+ // have been sent. If the handshake has completed then this is one greater
+ // than the number of round-trips needed for the handshake.
+ virtual int num_sent_client_hellos() const = 0;
+
+ // The number of server config update messages received by the
+ // client. Does not count update messages that were received prior
+ // to handshake confirmation.
+ virtual int num_scup_messages_received() const = 0;
+};
+
+class NET_EXPORT_PRIVATE QuicCryptoClientStream
+ : public QuicCryptoClientStreamBase {
+ public:
+ // kMaxClientHellos is the maximum number of times that we'll send a client
+ // hello. The value 3 accounts for:
+ // * One failure due to an incorrect or missing source-address token.
+ // * One failure due the server's certificate chain being unavailible and
+ // the server being unwilling to send it without a valid source-address
+ // token.
+ static const int kMaxClientHellos = 3;
+
+ // ProofHandler is an interface that handles callbacks from the crypto
+ // stream when the client has proof verification details of the server.
+ class NET_EXPORT_PRIVATE ProofHandler {
+ public:
+ virtual ~ProofHandler() {}
+
+ // Called when the proof in |cached| is marked valid. If this is a secure
+ // QUIC session, then this will happen only after the proof verifier
+ // completes.
+ virtual void OnProofValid(
+ const QuicCryptoClientConfig::CachedState& cached) = 0;
+
+ // Called when proof verification details become available, either because
+ // proof verification is complete, or when cached details are used. This
+ // will only be called for secure QUIC connections.
+ virtual void OnProofVerifyDetailsAvailable(
+ const ProofVerifyDetails& verify_details) = 0;
+ };
+
+ QuicCryptoClientStream(const QuicServerId& server_id,
+ QuicSession* session,
+ ProofVerifyContext* verify_context,
+ QuicCryptoClientConfig* crypto_config,
+ ProofHandler* proof_handler);
+
+ ~QuicCryptoClientStream() override;
+
+ // From QuicCryptoClientStreamBase
+ void CryptoConnect() override;
+ int num_sent_client_hellos() const override;
+
+ int num_scup_messages_received() const override;
+
+ // CryptoFramerVisitorInterface implementation
+ void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
+
+ // Returns true if a channel ID was sent on this connection.
+ bool WasChannelIDSent() const;
+
+ // Returns true if our ChannelIDSourceCallback was run, which implies the
+ // ChannelIDSource operated asynchronously. Intended for testing.
+ bool WasChannelIDSourceCallbackRun() const;
+
+ private:
+ // ChannelIDSourceCallbackImpl is passed as the callback method to
+ // GetChannelIDKey. The ChannelIDSource calls this class with the result of
+ // channel ID lookup when lookup is performed asynchronously.
+ class ChannelIDSourceCallbackImpl : public ChannelIDSourceCallback {
+ public:
+ explicit ChannelIDSourceCallbackImpl(QuicCryptoClientStream* stream);
+ ~ChannelIDSourceCallbackImpl() override;
+
+ // ChannelIDSourceCallback interface.
+ void Run(std::unique_ptr<ChannelIDKey>* channel_id_key) override;
+
+ // Cancel causes any future callbacks to be ignored. It must be called on
+ // the same thread as the callback will be made on.
+ void Cancel();
+
+ private:
+ QuicCryptoClientStream* stream_;
+ };
+
+ // ProofVerifierCallbackImpl is passed as the callback method to VerifyProof.
+ // The ProofVerifier calls this class with the result of proof verification
+ // when verification is performed asynchronously.
+ class ProofVerifierCallbackImpl : public ProofVerifierCallback {
+ public:
+ explicit ProofVerifierCallbackImpl(QuicCryptoClientStream* stream);
+ ~ProofVerifierCallbackImpl() override;
+
+ // ProofVerifierCallback interface.
+ void Run(bool ok,
+ const std::string& error_details,
+ std::unique_ptr<ProofVerifyDetails>* details) override;
+
+ // Cancel causes any future callbacks to be ignored. It must be called on
+ // the same thread as the callback will be made on.
+ void Cancel();
+
+ private:
+ QuicCryptoClientStream* stream_;
+ };
+
+ friend class test::CryptoTestUtils;
+ friend class test::QuicChromiumClientSessionPeer;
+
+ enum State {
+ STATE_IDLE,
+ STATE_INITIALIZE,
+ STATE_SEND_CHLO,
+ STATE_RECV_REJ,
+ STATE_VERIFY_PROOF,
+ STATE_VERIFY_PROOF_COMPLETE,
+ STATE_GET_CHANNEL_ID,
+ STATE_GET_CHANNEL_ID_COMPLETE,
+ STATE_RECV_SHLO,
+ STATE_INITIALIZE_SCUP,
+ STATE_NONE,
+ };
+
+ // Handles new server config and optional source-address token provided by the
+ // server during a connection.
+ void HandleServerConfigUpdateMessage(
+ const CryptoHandshakeMessage& server_config_update);
+
+ // DoHandshakeLoop performs a step of the handshake state machine. Note that
+ // |in| may be nullptr if the call did not result from a received message.
+ void DoHandshakeLoop(const CryptoHandshakeMessage* in);
+
+ // Start the handshake process.
+ void DoInitialize(QuicCryptoClientConfig::CachedState* cached);
+
+ // Send either InchoateClientHello or ClientHello message to the server.
+ void DoSendCHLO(QuicCryptoClientConfig::CachedState* cached);
+
+ // Process REJ message from the server.
+ void DoReceiveREJ(const CryptoHandshakeMessage* in,
+ QuicCryptoClientConfig::CachedState* cached);
+
+ // Start the proof verification process. Returns the QuicAsyncStatus returned
+ // by the ProofVerifier's VerifyProof.
+ QuicAsyncStatus DoVerifyProof(QuicCryptoClientConfig::CachedState* cached);
+
+ // If proof is valid then it sets the proof as valid (which persists the
+ // server config). If not, it closes the connection.
+ void DoVerifyProofComplete(QuicCryptoClientConfig::CachedState* cached);
+
+ // Start the look up of Channel ID process. Returns either QUIC_SUCCESS if
+ // RequiresChannelID returns false or QuicAsyncStatus returned by
+ // GetChannelIDKey.
+ QuicAsyncStatus DoGetChannelID(QuicCryptoClientConfig::CachedState* cached);
+
+ // If there is no channel ID, then close the connection otherwise transtion to
+ // STATE_SEND_CHLO state.
+ void DoGetChannelIDComplete();
+
+ // Process SHLO message from the server.
+ void DoReceiveSHLO(const CryptoHandshakeMessage* in,
+ QuicCryptoClientConfig::CachedState* cached);
+
+ // Start the proof verification if |server_id_| is https and |cached| has
+ // signature.
+ void DoInitializeServerConfigUpdate(
+ QuicCryptoClientConfig::CachedState* cached);
+
+ // Called to set the proof of |cached| valid. Also invokes the session's
+ // OnProofValid() method.
+ void SetCachedProofValid(QuicCryptoClientConfig::CachedState* cached);
+
+ // Returns true if the server crypto config in |cached| requires a ChannelID
+ // and the client config settings also allow sending a ChannelID.
+ bool RequiresChannelID(QuicCryptoClientConfig::CachedState* cached);
+
+ State next_state_;
+ // num_client_hellos_ contains the number of client hello messages that this
+ // connection has sent.
+ int num_client_hellos_;
+
+ QuicCryptoClientConfig* const crypto_config_;
+
+ // SHA-256 hash of the most recently sent CHLO.
+ std::string chlo_hash_;
+
+ // Server's (hostname, port, is_https, privacy_mode) tuple.
+ const QuicServerId server_id_;
+
+ // Generation counter from QuicCryptoClientConfig's CachedState.
+ uint64_t generation_counter_;
+
+ // True if a channel ID was sent.
+ bool channel_id_sent_;
+
+ // True if channel_id_source_callback_ was run.
+ bool channel_id_source_callback_run_;
+
+ // channel_id_source_callback_ contains the callback object that we passed
+ // to an asynchronous channel ID lookup. The ChannelIDSource owns this
+ // object.
+ ChannelIDSourceCallbackImpl* channel_id_source_callback_;
+
+ // These members are used to store the result of an asynchronous channel ID
+ // lookup. These members must not be used after
+ // STATE_GET_CHANNEL_ID_COMPLETE.
+ std::unique_ptr<ChannelIDKey> channel_id_key_;
+
+ // verify_context_ contains the context object that we pass to asynchronous
+ // proof verifications.
+ std::unique_ptr<ProofVerifyContext> verify_context_;
+
+ // proof_verify_callback_ contains the callback object that we passed to an
+ // asynchronous proof verification. The ProofVerifier owns this object.
+ ProofVerifierCallbackImpl* proof_verify_callback_;
+ // proof_handler_ contains the callback object used by a quic client
+ // for proof verification. It is not owned by this class.
+ ProofHandler* proof_handler_;
+
+ // These members are used to store the result of an asynchronous proof
+ // verification. These members must not be used after
+ // STATE_VERIFY_PROOF_COMPLETE.
+ bool verify_ok_;
+ std::string verify_error_details_;
+ std::unique_ptr<ProofVerifyDetails> verify_details_;
+
+ // True if the server responded to a previous CHLO with a stateless
+ // reject. Used for book-keeping between the STATE_RECV_REJ,
+ // STATE_VERIFY_PROOF*, and subsequent STATE_SEND_CHLO state.
+ bool stateless_reject_received_;
+
+ base::TimeTicks proof_verify_start_time_;
+
+ int num_scup_messages_received_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientStream);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CRYPTO_CLIENT_STREAM_H_
diff --git a/chromium/net/quic/core/quic_crypto_client_stream_factory.cc b/chromium/net/quic/core/quic_crypto_client_stream_factory.cc
new file mode 100644
index 00000000000..af6e00340d5
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_client_stream_factory.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_crypto_client_stream_factory.h"
+
+#include "base/lazy_instance.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/chromium/quic_chromium_client_session.h"
+#include "net/quic/core/quic_crypto_client_stream.h"
+
+namespace net {
+
+namespace {
+
+class DefaultCryptoStreamFactory : public QuicCryptoClientStreamFactory {
+ public:
+ QuicCryptoClientStream* CreateQuicCryptoClientStream(
+ const QuicServerId& server_id,
+ QuicChromiumClientSession* session,
+ std::unique_ptr<ProofVerifyContext> proof_verify_context,
+ QuicCryptoClientConfig* crypto_config) override {
+ return new QuicCryptoClientStream(server_id, session,
+ proof_verify_context.release(),
+ crypto_config, session);
+ }
+};
+
+static base::LazyInstance<DefaultCryptoStreamFactory>::Leaky
+ g_default_crypto_stream_factory = LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+// static
+QuicCryptoClientStreamFactory*
+QuicCryptoClientStreamFactory::GetDefaultFactory() {
+ return g_default_crypto_stream_factory.Pointer();
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_crypto_client_stream_factory.h b/chromium/net/quic/core/quic_crypto_client_stream_factory.h
new file mode 100644
index 00000000000..319d7d57855
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_client_stream_factory.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_CRYPTO_CLIENT_STREAM_FACTORY_H_
+#define NET_QUIC_QUIC_CRYPTO_CLIENT_STREAM_FACTORY_H_
+
+#include <memory>
+#include <string>
+
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_server_id.h"
+
+namespace net {
+
+class ProofVerifyContext;
+class QuicChromiumClientSession;
+class QuicCryptoClientConfig;
+class QuicCryptoClientStream;
+
+// An interface used to instantiate QuicCryptoClientStream objects. Used to
+// facilitate testing code with mock implementations.
+class NET_EXPORT QuicCryptoClientStreamFactory {
+ public:
+ virtual ~QuicCryptoClientStreamFactory() {}
+
+ virtual QuicCryptoClientStream* CreateQuicCryptoClientStream(
+ const QuicServerId& server_id,
+ QuicChromiumClientSession* session,
+ std::unique_ptr<ProofVerifyContext> proof_verify_context,
+ QuicCryptoClientConfig* crypto_config) = 0;
+
+ static QuicCryptoClientStreamFactory* GetDefaultFactory();
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CRYPTO_CLIENT_STREAM_FACTORY_H_
diff --git a/chromium/net/quic/core/quic_crypto_client_stream_test.cc b/chromium/net/quic/core/quic_crypto_client_stream_test.cc
new file mode 100644
index 00000000000..19773ec0a0d
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_client_stream_test.cc
@@ -0,0 +1,388 @@
+// 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/quic_crypto_client_stream.h"
+
+#include <memory>
+
+#include "net/quic/core/crypto/aes_128_gcm_12_encrypter.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/quic_stream_sequencer_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/reliable_quic_stream_peer.h"
+#include "net/quic/test_tools/simple_quic_framer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+using std::vector;
+
+using testing::_;
+
+namespace net {
+namespace test {
+namespace {
+
+const char kServerHostname[] = "test.example.com";
+const uint16_t kServerPort = 443;
+
+class QuicCryptoClientStreamTest : public ::testing::Test {
+ public:
+ QuicCryptoClientStreamTest()
+ : server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED),
+ crypto_config_(CryptoTestUtils::ProofVerifierForTesting()) {
+ CreateConnection();
+ }
+
+ void CreateConnection() {
+ connection_ = new PacketSavingConnection(&client_helper_, &alarm_factory_,
+ Perspective::IS_CLIENT);
+ // Advance the time, because timers do not like uninitialized times.
+ connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
+
+ session_.reset(new TestQuicSpdyClientSession(
+ connection_, DefaultQuicConfig(), server_id_, &crypto_config_));
+ }
+
+ void CompleteCryptoHandshake() {
+ stream()->CryptoConnect();
+ QuicConfig config;
+ CryptoTestUtils::HandshakeWithFakeServer(&config, &server_helper_,
+ &alarm_factory_, connection_,
+ stream(), server_options_);
+ }
+
+ void ConstructHandshakeMessage() {
+ CryptoFramer framer;
+ message_data_.reset(framer.ConstructHandshakeMessage(message_));
+ }
+
+ QuicCryptoClientStream* stream() { return session_->GetCryptoStream(); }
+
+ MockQuicConnectionHelper server_helper_;
+ MockQuicConnectionHelper client_helper_;
+ MockAlarmFactory alarm_factory_;
+ PacketSavingConnection* connection_;
+ std::unique_ptr<TestQuicSpdyClientSession> session_;
+ QuicServerId server_id_;
+ CryptoHandshakeMessage message_;
+ std::unique_ptr<QuicData> message_data_;
+ QuicCryptoClientConfig crypto_config_;
+ CryptoTestUtils::FakeServerOptions server_options_;
+};
+
+TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) {
+ EXPECT_FALSE(stream()->encryption_established());
+ EXPECT_FALSE(stream()->handshake_confirmed());
+}
+
+TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) {
+ CompleteCryptoHandshake();
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->handshake_confirmed());
+}
+
+TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
+ CompleteCryptoHandshake();
+
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE, _, _));
+ message_.set_tag(kCHLO);
+ ConstructHandshakeMessage();
+ stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false,
+ /*offset=*/0,
+ message_data_->AsStringPiece()));
+}
+
+TEST_F(QuicCryptoClientStreamTest, BadMessageType) {
+ stream()->CryptoConnect();
+
+ message_.set_tag(kCHLO);
+ ConstructHandshakeMessage();
+
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
+ "Expected REJ", _));
+ stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false,
+ /*offset=*/0,
+ message_data_->AsStringPiece()));
+}
+
+TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) {
+ CompleteCryptoHandshake();
+
+ const QuicConfig* config = session_->config();
+ EXPECT_EQ(kMaximumIdleTimeoutSecs,
+ config->IdleConnectionStateLifetime().ToSeconds());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection, config->MaxStreamsPerConnection());
+
+ const QuicCryptoNegotiatedParameters& crypto_params(
+ stream()->crypto_negotiated_params());
+ EXPECT_EQ(crypto_config_.aead[0], crypto_params.aead);
+ EXPECT_EQ(crypto_config_.kexs[0], crypto_params.key_exchange);
+}
+
+TEST_F(QuicCryptoClientStreamTest, ExpiredServerConfig) {
+ // Seed the config with a cached server config.
+ CompleteCryptoHandshake();
+
+ // Recreate connection with the new config.
+ CreateConnection();
+
+ // Advance time 5 years to ensure that we pass the expiry time of the cached
+ // server config.
+ connection_->AdvanceTime(
+ QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
+
+ stream()->CryptoConnect();
+ // Check that a client hello was sent.
+ ASSERT_EQ(1u, connection_->encrypted_packets_.size());
+ EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level());
+}
+
+TEST_F(QuicCryptoClientStreamTest, ClockSkew) {
+ // Test that if the client's clock is skewed with respect to the server,
+ // the handshake succeeds. In the past, the client would get the server
+ // config, notice that it had already expired and then close the connection.
+
+ // Advance time 5 years to ensure that we pass the expiry time in the server
+ // config, but the TTL is used instead.
+ connection_->AdvanceTime(
+ QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
+
+ // The handshakes completes!
+ CompleteCryptoHandshake();
+}
+
+TEST_F(QuicCryptoClientStreamTest, InvalidCachedServerConfig) {
+ // Seed the config with a cached server config.
+ CompleteCryptoHandshake();
+
+ // Recreate connection with the new config.
+ CreateConnection();
+
+ QuicCryptoClientConfig::CachedState* state =
+ crypto_config_.LookupOrCreate(server_id_);
+
+ vector<string> certs = state->certs();
+ string cert_sct = state->cert_sct();
+ string signature = state->signature();
+ string chlo_hash = state->chlo_hash();
+ state->SetProof(certs, cert_sct, chlo_hash, signature + signature);
+
+ stream()->CryptoConnect();
+ // Check that a client hello was sent.
+ ASSERT_EQ(1u, connection_->encrypted_packets_.size());
+}
+
+TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdate) {
+ // Test that the crypto client stream can receive server config updates after
+ // the connection has been established.
+ CompleteCryptoHandshake();
+
+ QuicCryptoClientConfig::CachedState* state =
+ crypto_config_.LookupOrCreate(server_id_);
+
+ // Ensure cached STK is different to what we send in the handshake.
+ EXPECT_NE("xstk", state->source_address_token());
+
+ // Initialize using {...} syntax to avoid trailing \0 if converting from
+ // string.
+ unsigned char stk[] = {'x', 's', 't', 'k'};
+
+ // Minimum SCFG that passes config validation checks.
+ unsigned char scfg[] = {// SCFG
+ 0x53, 0x43, 0x46, 0x47,
+ // num entries
+ 0x01, 0x00,
+ // padding
+ 0x00, 0x00,
+ // EXPY
+ 0x45, 0x58, 0x50, 0x59,
+ // EXPY end offset
+ 0x08, 0x00, 0x00, 0x00,
+ // Value
+ '1', '2', '3', '4', '5', '6', '7', '8'};
+
+ CryptoHandshakeMessage server_config_update;
+ server_config_update.set_tag(kSCUP);
+ server_config_update.SetValue(kSourceAddressTokenTag, stk);
+ server_config_update.SetValue(kSCFG, scfg);
+ const uint64_t expiry_seconds = 60 * 60 * 24 * 2;
+ server_config_update.SetValue(kSTTL, expiry_seconds);
+
+ std::unique_ptr<QuicData> data(
+ CryptoFramer::ConstructHandshakeMessage(server_config_update));
+ stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false,
+ /*offset=*/0, data->AsStringPiece()));
+
+ // Make sure that the STK and SCFG are cached correctly.
+ EXPECT_EQ("xstk", state->source_address_token());
+
+ const string& cached_scfg = state->server_config();
+ test::CompareCharArraysWithHexError(
+ "scfg", cached_scfg.data(), cached_scfg.length(),
+ QuicUtils::AsChars(scfg), arraysize(scfg));
+ QuicStreamSequencer* sequencer = ReliableQuicStreamPeer::sequencer(stream());
+ EXPECT_NE(FLAGS_quic_release_crypto_stream_buffer &&
+ FLAGS_quic_reduce_sequencer_buffer_memory_life_time,
+ QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
+}
+
+TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateBeforeHandshake) {
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE, _, _));
+ CryptoHandshakeMessage server_config_update;
+ server_config_update.set_tag(kSCUP);
+ std::unique_ptr<QuicData> data(
+ CryptoFramer::ConstructHandshakeMessage(server_config_update));
+ stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false,
+ /*offset=*/0, data->AsStringPiece()));
+}
+
+TEST_F(QuicCryptoClientStreamTest, TokenBindingNegotiation) {
+ server_options_.token_binding_params = QuicTagVector{kTB10, kP256};
+ crypto_config_.tb_key_params = QuicTagVector{kTB10};
+
+ CompleteCryptoHandshake();
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->handshake_confirmed());
+ EXPECT_EQ(kTB10,
+ stream()->crypto_negotiated_params().token_binding_key_param);
+}
+
+TEST_F(QuicCryptoClientStreamTest, NoTokenBindingWithoutServerSupport) {
+ crypto_config_.tb_key_params = QuicTagVector{kTB10, kP256};
+
+ CompleteCryptoHandshake();
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->handshake_confirmed());
+ EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
+}
+
+TEST_F(QuicCryptoClientStreamTest, NoTokenBindingWithoutClientSupport) {
+ server_options_.token_binding_params = QuicTagVector{kTB10, kP256};
+
+ CompleteCryptoHandshake();
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->handshake_confirmed());
+ EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
+}
+
+TEST_F(QuicCryptoClientStreamTest, TokenBindingNotNegotiated) {
+ CompleteCryptoHandshake();
+ EXPECT_TRUE(stream()->encryption_established());
+ EXPECT_TRUE(stream()->handshake_confirmed());
+ EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
+}
+
+class QuicCryptoClientStreamStatelessTest : public ::testing::Test {
+ public:
+ QuicCryptoClientStreamStatelessTest()
+ : client_crypto_config_(CryptoTestUtils::ProofVerifierForTesting()),
+ server_crypto_config_(QuicCryptoServerConfig::TESTING,
+ QuicRandom::GetInstance(),
+ CryptoTestUtils::ProofSourceForTesting()),
+ server_compressed_certs_cache_(
+ QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
+ server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED) {
+ TestQuicSpdyClientSession* client_session = nullptr;
+ CreateClientSessionForTest(server_id_,
+ /* supports_stateless_rejects= */ true,
+ QuicTime::Delta::FromSeconds(100000),
+ AllSupportedVersions(), &helper_,
+ &alarm_factory_, &client_crypto_config_,
+ &client_connection_, &client_session);
+ CHECK(client_session);
+ client_session_.reset(client_session);
+ }
+
+ QuicCryptoServerStream* server_stream() {
+ return server_session_->GetCryptoStream();
+ }
+
+ void AdvanceHandshakeWithFakeServer() {
+ client_session_->GetCryptoStream()->CryptoConnect();
+ CryptoTestUtils::AdvanceHandshake(client_connection_,
+ client_session_->GetCryptoStream(), 0,
+ server_connection_, server_stream(), 0);
+ }
+
+ // Initializes the server_stream_ for stateless rejects.
+ void InitializeFakeStatelessRejectServer() {
+ TestQuicSpdyServerSession* server_session = nullptr;
+ CreateServerSessionForTest(server_id_, QuicTime::Delta::FromSeconds(100000),
+ AllSupportedVersions(), &helper_,
+ &alarm_factory_, &server_crypto_config_,
+ &server_compressed_certs_cache_,
+ &server_connection_, &server_session);
+ CHECK(server_session);
+ server_session_.reset(server_session);
+ CryptoTestUtils::FakeServerOptions options;
+ CryptoTestUtils::SetupCryptoServerConfigForTest(
+ server_connection_->clock(), server_connection_->random_generator(),
+ server_session_->config(), &server_crypto_config_, options);
+ FLAGS_enable_quic_stateless_reject_support = true;
+ }
+
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+
+ MockQuicConnectionHelper helper_;
+ MockAlarmFactory alarm_factory_;
+
+ // Client crypto stream state
+ PacketSavingConnection* client_connection_;
+ std::unique_ptr<TestQuicSpdyClientSession> client_session_;
+ QuicCryptoClientConfig client_crypto_config_;
+
+ // Server crypto stream state
+ PacketSavingConnection* server_connection_;
+ std::unique_ptr<TestQuicSpdyServerSession> server_session_;
+ QuicCryptoServerConfig server_crypto_config_;
+ QuicCompressedCertsCache server_compressed_certs_cache_;
+ QuicServerId server_id_;
+};
+
+TEST_F(QuicCryptoClientStreamStatelessTest, StatelessReject) {
+ FLAGS_enable_quic_stateless_reject_support = true;
+
+ QuicCryptoClientConfig::CachedState* client_state =
+ client_crypto_config_.LookupOrCreate(server_id_);
+
+ EXPECT_FALSE(client_state->has_server_designated_connection_id());
+ EXPECT_CALL(*client_session_, OnProofValid(testing::_));
+
+ InitializeFakeStatelessRejectServer();
+ AdvanceHandshakeWithFakeServer();
+
+ EXPECT_EQ(1, server_stream()->NumHandshakeMessages());
+ EXPECT_EQ(0, server_stream()->NumHandshakeMessagesWithServerNonces());
+
+ EXPECT_FALSE(client_session_->GetCryptoStream()->encryption_established());
+ EXPECT_FALSE(client_session_->GetCryptoStream()->handshake_confirmed());
+ // Even though the handshake was not complete, the cached client_state is
+ // complete, and can be used for a subsequent successful handshake.
+ EXPECT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
+
+ ASSERT_TRUE(client_state->has_server_nonce());
+ ASSERT_FALSE(client_state->GetNextServerNonce().empty());
+ ASSERT_TRUE(client_state->has_server_designated_connection_id());
+ QuicConnectionId server_designated_id =
+ client_state->GetNextServerDesignatedConnectionId();
+ QuicConnectionId expected_id =
+ server_session_->connection()->random_generator()->RandUint64();
+ EXPECT_EQ(expected_id, server_designated_id);
+ EXPECT_FALSE(client_state->has_server_designated_connection_id());
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_crypto_framer_parse_message_fuzzer.cc b/chromium/net/quic/core/quic_crypto_framer_parse_message_fuzzer.cc
new file mode 100644
index 00000000000..811c0598cc4
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_framer_parse_message_fuzzer.cc
@@ -0,0 +1,18 @@
+// Copyright 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.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/strings/string_piece.h"
+#include "net/quic/core/crypto/crypto_framer.h"
+
+// Entry point for LibFuzzer.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ base::StringPiece crypto_input(reinterpret_cast<const char*>(data), size);
+ std::unique_ptr<net::CryptoHandshakeMessage> handshake_message(
+ net::CryptoFramer::ParseMessage(crypto_input));
+
+ return 0;
+}
diff --git a/chromium/net/quic/core/quic_crypto_server_stream.cc b/chromium/net/quic/core/quic_crypto_server_stream.cc
new file mode 100644
index 00000000000..665bd622bf9
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_server_stream.cc
@@ -0,0 +1,514 @@
+// 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/quic_crypto_server_stream.h"
+
+#include <memory>
+
+#include "base/base64.h"
+#include "crypto/secure_hash.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/crypto_utils.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/proto/cached_network_parameters.pb.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_session_base.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+QuicCryptoServerStreamBase::QuicCryptoServerStreamBase(QuicSession* session)
+ : QuicCryptoStream(session) {}
+
+// TODO(jokulik): Once stateless rejects support is inherent in the version
+// number, this function will likely go away entirely.
+// static
+bool QuicCryptoServerStreamBase::DoesPeerSupportStatelessRejects(
+ const CryptoHandshakeMessage& message) {
+ const QuicTag* received_tags;
+ size_t received_tags_length;
+ QuicErrorCode error =
+ message.GetTaglist(kCOPT, &received_tags, &received_tags_length);
+ if (error != QUIC_NO_ERROR) {
+ return false;
+ }
+ for (size_t i = 0; i < received_tags_length; ++i) {
+ if (received_tags[i] == kSREJ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+QuicCryptoServerStream::QuicCryptoServerStream(
+ const QuicCryptoServerConfig* crypto_config,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ bool use_stateless_rejects_if_peer_supported,
+ QuicSession* session,
+ Helper* helper)
+ : QuicCryptoServerStreamBase(session),
+ crypto_config_(crypto_config),
+ compressed_certs_cache_(compressed_certs_cache),
+ validate_client_hello_cb_(nullptr),
+ helper_(helper),
+ num_handshake_messages_(0),
+ num_handshake_messages_with_server_nonces_(0),
+ send_server_config_update_cb_(nullptr),
+ num_server_config_update_messages_sent_(0),
+ use_stateless_rejects_if_peer_supported_(
+ use_stateless_rejects_if_peer_supported),
+ peer_supports_stateless_rejects_(false),
+ chlo_packet_size_(0) {
+ DCHECK_EQ(Perspective::IS_SERVER, session->connection()->perspective());
+}
+
+QuicCryptoServerStream::~QuicCryptoServerStream() {
+ CancelOutstandingCallbacks();
+}
+
+void QuicCryptoServerStream::CancelOutstandingCallbacks() {
+ // Detach from the validation callback. Calling this multiple times is safe.
+ if (validate_client_hello_cb_ != nullptr) {
+ validate_client_hello_cb_->Cancel();
+ validate_client_hello_cb_ = nullptr;
+ }
+ if (send_server_config_update_cb_ != nullptr) {
+ send_server_config_update_cb_->Cancel();
+ send_server_config_update_cb_ = nullptr;
+ }
+}
+
+void QuicCryptoServerStream::OnHandshakeMessage(
+ const CryptoHandshakeMessage& message) {
+ QuicCryptoServerStreamBase::OnHandshakeMessage(message);
+ ++num_handshake_messages_;
+ chlo_packet_size_ = session()->connection()->GetCurrentPacket().length();
+
+ // Do not process handshake messages after the handshake is confirmed.
+ if (handshake_confirmed_) {
+ CloseConnectionWithDetails(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
+ "Unexpected handshake message from client");
+ return;
+ }
+
+ if (message.tag() != kCHLO) {
+ CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
+ "Handshake packet not CHLO");
+ return;
+ }
+
+ if (validate_client_hello_cb_ != nullptr) {
+ // Already processing some other handshake message. The protocol
+ // does not allow for clients to send multiple handshake messages
+ // before the server has a chance to respond.
+ CloseConnectionWithDetails(
+ QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO,
+ "Unexpected handshake message while processing CHLO");
+ return;
+ }
+
+ CryptoUtils::HashHandshakeMessage(message, &chlo_hash_);
+
+ std::unique_ptr<ValidateCallback> cb(new ValidateCallback(this));
+ validate_client_hello_cb_ = cb.get();
+ crypto_config_->ValidateClientHello(
+ message, session()->connection()->peer_address().address(),
+ session()->connection()->self_address().address(), version(),
+ session()->connection()->clock(), &crypto_proof_, std::move(cb));
+}
+
+void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result,
+ std::unique_ptr<ProofSource::Details> details) {
+ const CryptoHandshakeMessage& message = result->client_hello;
+
+ // Clear the callback that got us here.
+ DCHECK(validate_client_hello_cb_ != nullptr);
+ validate_client_hello_cb_ = nullptr;
+
+ if (use_stateless_rejects_if_peer_supported_) {
+ peer_supports_stateless_rejects_ = DoesPeerSupportStatelessRejects(message);
+ }
+
+ string error_details;
+ std::unique_ptr<CryptoHandshakeMessage> reply(new CryptoHandshakeMessage);
+ std::unique_ptr<DiversificationNonce> diversification_nonce(
+ new DiversificationNonce);
+ QuicErrorCode error =
+ ProcessClientHello(result, std::move(details), reply.get(),
+ diversification_nonce.get(), &error_details);
+
+ // Note: this split exists to facilitate a future conversion of
+ // ProcessClientHello to an async signature.
+ FinishProcessingHandshakeMessageAfterProcessClientHello(
+ *result, error, error_details, std::move(reply),
+ std::move(diversification_nonce));
+}
+
+void QuicCryptoServerStream::
+ FinishProcessingHandshakeMessageAfterProcessClientHello(
+ const ValidateClientHelloResultCallback::Result& result,
+ QuicErrorCode error,
+ const string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> reply,
+ std::unique_ptr<DiversificationNonce> diversification_nonce) {
+ const CryptoHandshakeMessage& message = result.client_hello;
+ if (error != QUIC_NO_ERROR) {
+ CloseConnectionWithDetails(error, error_details);
+ return;
+ }
+
+ if (reply->tag() != kSHLO) {
+ if (reply->tag() == kSREJ) {
+ DCHECK(use_stateless_rejects_if_peer_supported_);
+ DCHECK(peer_supports_stateless_rejects_);
+ // Before sending the SREJ, cause the connection to save crypto packets
+ // so that they can be added to the time wait list manager and
+ // retransmitted.
+ session()->connection()->EnableSavingCryptoPackets();
+ }
+ SendHandshakeMessage(*reply);
+
+ if (reply->tag() == kSREJ) {
+ DCHECK(use_stateless_rejects_if_peer_supported_);
+ DCHECK(peer_supports_stateless_rejects_);
+ DCHECK(!handshake_confirmed());
+ DVLOG(1) << "Closing connection "
+ << session()->connection()->connection_id()
+ << " because of a stateless reject.";
+ session()->connection()->CloseConnection(
+ QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+ }
+ return;
+ }
+
+ // If we are returning a SHLO then we accepted the handshake. Now
+ // process the negotiated configuration options as part of the
+ // session config.
+ QuicConfig* config = session()->config();
+ OverrideQuicConfigDefaults(config);
+ string process_error_details;
+ const QuicErrorCode process_error =
+ config->ProcessPeerHello(message, CLIENT, &process_error_details);
+ if (process_error != QUIC_NO_ERROR) {
+ CloseConnectionWithDetails(process_error, process_error_details);
+ return;
+ }
+
+ session()->OnConfigNegotiated();
+
+ config->ToHandshakeMessage(reply.get());
+
+ // Receiving a full CHLO implies the client is prepared to decrypt with
+ // the new server write key. We can start to encrypt with the new server
+ // write key.
+ //
+ // NOTE: the SHLO will be encrypted with the new server write key.
+ session()->connection()->SetEncrypter(
+ ENCRYPTION_INITIAL,
+ crypto_negotiated_params_.initial_crypters.encrypter.release());
+ session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+ // Set the decrypter immediately so that we no longer accept unencrypted
+ // packets.
+ session()->connection()->SetDecrypter(
+ ENCRYPTION_INITIAL,
+ crypto_negotiated_params_.initial_crypters.decrypter.release());
+ if (version() > QUIC_VERSION_32) {
+ session()->connection()->SetDiversificationNonce(*diversification_nonce);
+ }
+
+ SendHandshakeMessage(*reply);
+
+ session()->connection()->SetEncrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ crypto_negotiated_params_.forward_secure_crypters.encrypter.release());
+ session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+
+ session()->connection()->SetAlternativeDecrypter(
+ ENCRYPTION_FORWARD_SECURE,
+ crypto_negotiated_params_.forward_secure_crypters.decrypter.release(),
+ false /* don't latch */);
+
+ encryption_established_ = true;
+ handshake_confirmed_ = true;
+ session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
+}
+
+void QuicCryptoServerStream::SendServerConfigUpdate(
+ const CachedNetworkParameters* cached_network_params) {
+ if (!handshake_confirmed_) {
+ return;
+ }
+
+ if (FLAGS_enable_async_get_proof) {
+ if (send_server_config_update_cb_ != nullptr) {
+ DVLOG(1)
+ << "Skipped server config update since one is already in progress";
+ return;
+ }
+
+ std::unique_ptr<SendServerConfigUpdateCallback> cb(
+ new SendServerConfigUpdateCallback(this));
+ send_server_config_update_cb_ = cb.get();
+ crypto_config_->BuildServerConfigUpdateMessage(
+ session()->connection()->version(), chlo_hash_,
+ previous_source_address_tokens_,
+ session()->connection()->self_address().address(),
+ session()->connection()->peer_address().address(),
+ session()->connection()->clock(),
+ session()->connection()->random_generator(), compressed_certs_cache_,
+ crypto_negotiated_params_, cached_network_params, std::move(cb));
+ return;
+ }
+
+ CryptoHandshakeMessage server_config_update_message;
+ if (!crypto_config_->BuildServerConfigUpdateMessage(
+ session()->connection()->version(), chlo_hash_,
+ previous_source_address_tokens_,
+ session()->connection()->self_address().address(),
+ session()->connection()->peer_address().address(),
+ session()->connection()->clock(),
+ session()->connection()->random_generator(), compressed_certs_cache_,
+ crypto_negotiated_params_, cached_network_params,
+ &server_config_update_message)) {
+ DVLOG(1) << "Server: Failed to build server config update (SCUP)!";
+ return;
+ }
+
+ DVLOG(1) << "Server: Sending server config update: "
+ << server_config_update_message.DebugString();
+ const QuicData& data = server_config_update_message.GetSerialized();
+ WriteOrBufferData(StringPiece(data.data(), data.length()), false, nullptr);
+
+ ++num_server_config_update_messages_sent_;
+}
+
+QuicCryptoServerStream::SendServerConfigUpdateCallback::
+ SendServerConfigUpdateCallback(QuicCryptoServerStream* parent)
+ : parent_(parent) {}
+
+void QuicCryptoServerStream::SendServerConfigUpdateCallback::Cancel() {
+ parent_ = nullptr;
+}
+
+// From BuildServerConfigUpdateMessageResultCallback
+void QuicCryptoServerStream::SendServerConfigUpdateCallback::Run(
+ bool ok,
+ const CryptoHandshakeMessage& message) {
+ if (parent_ == nullptr) {
+ return;
+ }
+ parent_->FinishSendServerConfigUpdate(ok, message);
+}
+
+void QuicCryptoServerStream::FinishSendServerConfigUpdate(
+ bool ok,
+ const CryptoHandshakeMessage& message) {
+ // Clear the callback that got us here.
+ DCHECK(send_server_config_update_cb_ != nullptr);
+ send_server_config_update_cb_ = nullptr;
+
+ if (!ok) {
+ DVLOG(1) << "Server: Failed to build server config update (SCUP)!";
+ return;
+ }
+
+ DVLOG(1) << "Server: Sending server config update: " << message.DebugString();
+ const QuicData& data = message.GetSerialized();
+ WriteOrBufferData(StringPiece(data.data(), data.length()), false, nullptr);
+
+ ++num_server_config_update_messages_sent_;
+}
+
+void QuicCryptoServerStream::OnServerHelloAcked() {
+ session()->connection()->OnHandshakeComplete();
+}
+
+uint8_t QuicCryptoServerStream::NumHandshakeMessages() const {
+ return num_handshake_messages_;
+}
+
+uint8_t QuicCryptoServerStream::NumHandshakeMessagesWithServerNonces() const {
+ return num_handshake_messages_with_server_nonces_;
+}
+
+int QuicCryptoServerStream::NumServerConfigUpdateMessagesSent() const {
+ return num_server_config_update_messages_sent_;
+}
+
+const CachedNetworkParameters*
+QuicCryptoServerStream::PreviousCachedNetworkParams() const {
+ return previous_cached_network_params_.get();
+}
+
+bool QuicCryptoServerStream::UseStatelessRejectsIfPeerSupported() const {
+ return use_stateless_rejects_if_peer_supported_;
+}
+
+bool QuicCryptoServerStream::PeerSupportsStatelessRejects() const {
+ return peer_supports_stateless_rejects_;
+}
+
+void QuicCryptoServerStream::SetPeerSupportsStatelessRejects(
+ bool peer_supports_stateless_rejects) {
+ peer_supports_stateless_rejects_ = peer_supports_stateless_rejects;
+}
+
+void QuicCryptoServerStream::SetPreviousCachedNetworkParams(
+ CachedNetworkParameters cached_network_params) {
+ previous_cached_network_params_.reset(
+ new CachedNetworkParameters(cached_network_params));
+}
+
+bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID(
+ string* output) const {
+ if (!encryption_established_ ||
+ crypto_negotiated_params_.channel_id.empty()) {
+ return false;
+ }
+
+ const string& channel_id(crypto_negotiated_params_.channel_id);
+ std::unique_ptr<crypto::SecureHash> hash(
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+ hash->Update(channel_id.data(), channel_id.size());
+ uint8_t digest[32];
+ hash->Finish(digest, sizeof(digest));
+
+ base::Base64Encode(
+ string(reinterpret_cast<const char*>(digest), sizeof(digest)), output);
+ // Remove padding.
+ size_t len = output->size();
+ if (len >= 2) {
+ if ((*output)[len - 1] == '=') {
+ len--;
+ if ((*output)[len - 1] == '=') {
+ len--;
+ }
+ output->resize(len);
+ }
+ }
+ return true;
+}
+
+class QuicCryptoServerStream::ProcessClientHelloCallback
+ : public ProcessClientHelloResultCallback {
+ public:
+ ProcessClientHelloCallback(QuicErrorCode* error,
+ string* error_details,
+ CryptoHandshakeMessage* message,
+ DiversificationNonce* diversification_nonce)
+ : error_(error),
+ error_details_(error_details),
+ message_(message),
+ diversification_nonce_(diversification_nonce) {}
+
+ void Run(
+ QuicErrorCode error,
+ const string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> message,
+ std::unique_ptr<DiversificationNonce> diversification_nonce) override {
+ *error_ = error;
+ *error_details_ = error_details;
+ if (message != nullptr) {
+ *message_ = *message;
+ }
+ if (diversification_nonce != nullptr) {
+ *diversification_nonce_ = *diversification_nonce;
+ }
+ // NOTE: copies the message, nonce, and error details. This is a temporary
+ // condition until this codepath is fully asynchronized.
+ // TODO(gredner): Fix this.
+ }
+
+ private:
+ QuicErrorCode* error_;
+ string* error_details_;
+ CryptoHandshakeMessage* message_;
+ DiversificationNonce* diversification_nonce_;
+};
+
+QuicErrorCode QuicCryptoServerStream::ProcessClientHello(
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result,
+ std::unique_ptr<ProofSource::Details> proof_source_details,
+ CryptoHandshakeMessage* reply,
+ DiversificationNonce* out_diversification_nonce,
+ string* error_details) {
+ const CryptoHandshakeMessage& message = result->client_hello;
+ if (!helper_->CanAcceptClientHello(
+ message, session()->connection()->self_address(), error_details)) {
+ return QUIC_HANDSHAKE_FAILED;
+ }
+
+ if (!result->info.server_nonce.empty()) {
+ ++num_handshake_messages_with_server_nonces_;
+ }
+ // Store the bandwidth estimate from the client.
+ if (result->cached_network_params.bandwidth_estimate_bytes_per_second() > 0) {
+ previous_cached_network_params_.reset(
+ new CachedNetworkParameters(result->cached_network_params));
+ }
+ previous_source_address_tokens_ = result->info.source_address_tokens;
+
+ const bool use_stateless_rejects_in_crypto_config =
+ use_stateless_rejects_if_peer_supported_ &&
+ peer_supports_stateless_rejects_;
+ QuicConnection* connection = session()->connection();
+ const QuicConnectionId server_designated_connection_id =
+ GenerateConnectionIdForReject(use_stateless_rejects_in_crypto_config);
+
+ QuicErrorCode error = QUIC_NO_ERROR;
+ std::unique_ptr<ProcessClientHelloCallback> cb(new ProcessClientHelloCallback(
+ &error, error_details, reply, out_diversification_nonce));
+ crypto_config_->ProcessClientHello(
+ result, /*reject_only=*/false, connection->connection_id(),
+ connection->self_address().address(), connection->peer_address(),
+ 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_, &crypto_proof_,
+ QuicCryptoStream::CryptoMessageFramingOverhead(version()),
+ chlo_packet_size_, std::move(cb));
+ // NOTE: assumes that ProcessClientHello invokes the callback synchronously.
+ // This is a temporary condition until these codepaths are fully
+ // asynchronized.
+ // TODO(gredner): fix this.
+
+ return error;
+}
+
+void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {}
+
+QuicCryptoServerStream::ValidateCallback::ValidateCallback(
+ QuicCryptoServerStream* parent)
+ : parent_(parent) {}
+
+void QuicCryptoServerStream::ValidateCallback::Cancel() {
+ parent_ = nullptr;
+}
+
+void QuicCryptoServerStream::ValidateCallback::Run(
+ scoped_refptr<Result> result,
+ std::unique_ptr<ProofSource::Details> details) {
+ if (parent_ != nullptr) {
+ parent_->FinishProcessingHandshakeMessage(std::move(result),
+ std::move(details));
+ }
+}
+
+QuicConnectionId QuicCryptoServerStream::GenerateConnectionIdForReject(
+ bool use_stateless_rejects) {
+ if (!use_stateless_rejects) {
+ return 0;
+ }
+ return helper_->GenerateConnectionIdForReject(
+ session()->connection()->connection_id());
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_crypto_server_stream.h b/chromium/net/quic/core/quic_crypto_server_stream.h
new file mode 100644
index 00000000000..4ce02b5cd24
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_server_stream.h
@@ -0,0 +1,275 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_CRYPTO_SERVER_STREAM_H_
+#define NET_QUIC_QUIC_CRYPTO_SERVER_STREAM_H_
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#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_stream.h"
+
+namespace net {
+
+class CachedNetworkParameters;
+class CryptoHandshakeMessage;
+class QuicCryptoServerConfig;
+class QuicCryptoServerStreamBase;
+class QuicServerSessionBase;
+
+namespace test {
+class CryptoTestUtils;
+class QuicCryptoServerStreamPeer;
+} // namespace test
+
+// TODO(alyssar) see what can be moved out of QuicCryptoServerStream with
+// various code and test refactoring.
+class NET_EXPORT_PRIVATE QuicCryptoServerStreamBase : public QuicCryptoStream {
+ public:
+ explicit QuicCryptoServerStreamBase(QuicSession* session);
+
+ ~QuicCryptoServerStreamBase() override {}
+
+ // Cancel any outstanding callbacks, such as asynchronous validation of client
+ // hello.
+ virtual void CancelOutstandingCallbacks() = 0;
+
+ // GetBase64SHA256ClientChannelID sets |*output| to the base64 encoded,
+ // SHA-256 hash of the client's ChannelID key and returns true, if the client
+ // presented a ChannelID. Otherwise it returns false.
+ virtual bool GetBase64SHA256ClientChannelID(std::string* output) const = 0;
+
+ virtual int NumServerConfigUpdateMessagesSent() const = 0;
+
+ // Sends the latest server config and source-address token to the client.
+ virtual void SendServerConfigUpdate(
+ const CachedNetworkParameters* cached_network_params) = 0;
+
+ // Called by the ServerHello AckNotifier once the SHLO has been ACKed by the
+ // client.
+ virtual void OnServerHelloAcked() = 0;
+
+ // These are all accessors and setters to their respective counters.
+ virtual uint8_t NumHandshakeMessages() const = 0;
+ virtual uint8_t NumHandshakeMessagesWithServerNonces() const = 0;
+ virtual bool UseStatelessRejectsIfPeerSupported() const = 0;
+ virtual bool PeerSupportsStatelessRejects() const = 0;
+ virtual void SetPeerSupportsStatelessRejects(bool set) = 0;
+ virtual const CachedNetworkParameters* PreviousCachedNetworkParams()
+ const = 0;
+ virtual void SetPreviousCachedNetworkParams(
+ CachedNetworkParameters cached_network_params) = 0;
+
+ // Checks the options on the handshake-message to see whether the
+ // peer supports stateless-rejects.
+ static bool DoesPeerSupportStatelessRejects(
+ const CryptoHandshakeMessage& message);
+};
+
+class NET_EXPORT_PRIVATE QuicCryptoServerStream
+ : public QuicCryptoServerStreamBase {
+ public:
+ class Helper {
+ public:
+ virtual ~Helper() {}
+
+ // Given the current connection_id, generates a new ConnectionId to
+ // be returned with a stateless reject.
+ virtual QuicConnectionId GenerateConnectionIdForReject(
+ QuicConnectionId connection_id) const = 0;
+
+ // Returns true if |message|, which was received on |self_address| is
+ // acceptable according to the visitor's policy. Otherwise, returns false
+ // and populates |error_details|.
+ virtual bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
+ const IPEndPoint& self_address,
+ std::string* error_details) const = 0;
+ };
+
+ // |crypto_config| must outlive the stream.
+ // |session| must outlive the stream.
+ // |helper| must outlive the stream.
+ QuicCryptoServerStream(const QuicCryptoServerConfig* crypto_config,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ bool use_stateless_rejects_if_peer_supported,
+ QuicSession* session,
+ Helper* helper);
+
+ ~QuicCryptoServerStream() override;
+
+ // From QuicCryptoServerStreamBase
+ void CancelOutstandingCallbacks() override;
+ void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
+ bool GetBase64SHA256ClientChannelID(std::string* output) const override;
+ void SendServerConfigUpdate(
+ const CachedNetworkParameters* cached_network_params) override;
+ void OnServerHelloAcked() override;
+ uint8_t NumHandshakeMessages() const override;
+ uint8_t NumHandshakeMessagesWithServerNonces() const override;
+ int NumServerConfigUpdateMessagesSent() const override;
+ const CachedNetworkParameters* PreviousCachedNetworkParams() const override;
+ bool UseStatelessRejectsIfPeerSupported() const override;
+ bool PeerSupportsStatelessRejects() const override;
+ void SetPeerSupportsStatelessRejects(
+ bool peer_supports_stateless_rejects) override;
+ void SetPreviousCachedNetworkParams(
+ CachedNetworkParameters cached_network_params) override;
+
+ protected:
+ virtual QuicErrorCode ProcessClientHello(
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result,
+ std::unique_ptr<ProofSource::Details> proof_source_details,
+ CryptoHandshakeMessage* reply,
+ DiversificationNonce* out_diversification_nonce,
+ std::string* error_details);
+
+ // Hook that allows the server to set QuicConfig defaults just
+ // before going through the parameter negotiation step.
+ virtual void OverrideQuicConfigDefaults(QuicConfig* config);
+
+ private:
+ friend class test::CryptoTestUtils;
+ friend class test::QuicCryptoServerStreamPeer;
+
+ class ValidateCallback : public ValidateClientHelloResultCallback {
+ public:
+ explicit ValidateCallback(QuicCryptoServerStream* parent);
+ // To allow the parent to detach itself from the callback before deletion.
+ void Cancel();
+
+ // From ValidateClientHelloResultCallback
+ void Run(scoped_refptr<Result> result,
+ std::unique_ptr<ProofSource::Details> details) override;
+
+ private:
+ QuicCryptoServerStream* parent_;
+
+ DISALLOW_COPY_AND_ASSIGN(ValidateCallback);
+ };
+
+ class SendServerConfigUpdateCallback
+ : public BuildServerConfigUpdateMessageResultCallback {
+ public:
+ explicit SendServerConfigUpdateCallback(QuicCryptoServerStream* parent);
+ SendServerConfigUpdateCallback(const SendServerConfigUpdateCallback&) =
+ delete;
+ void operator=(const SendServerConfigUpdateCallback&) = delete;
+
+ // To allow the parent to detach itself from the callback before deletion.
+ void Cancel();
+
+ // From BuildServerConfigUpdateMessageResultCallback
+ void Run(bool ok, const CryptoHandshakeMessage& message) override;
+
+ private:
+ QuicCryptoServerStream* parent_;
+ };
+
+ // Invoked by ValidateCallback::RunImpl once initial validation of
+ // the client hello is complete. Finishes processing of the client
+ // hello message and handles handshake success/failure.
+ void FinishProcessingHandshakeMessage(
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result,
+ std::unique_ptr<ProofSource::Details> details);
+
+ class ProcessClientHelloCallback;
+ friend class ProcessClientHelloCallback;
+
+ // Portion of FinishProcessingHandshakeMessage which executes after
+ // ProcessClientHello has been called.
+ void FinishProcessingHandshakeMessageAfterProcessClientHello(
+ const ValidateClientHelloResultCallback::Result& result,
+ QuicErrorCode error,
+ const std::string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> reply,
+ std::unique_ptr<DiversificationNonce> diversification_nonce);
+
+ // Invoked by SendServerConfigUpdateCallback::RunImpl once the proof has been
+ // received. |ok| indicates whether or not the proof was successfully
+ // acquired, and |message| holds the partially-constructed message from
+ // SendServerConfigUpdate.
+ void FinishSendServerConfigUpdate(bool ok,
+ const CryptoHandshakeMessage& message);
+
+ // Returns a new ConnectionId to be used for statelessly rejected connections
+ // if |use_stateless_rejects| is true. Returns 0 otherwise.
+ QuicConnectionId GenerateConnectionIdForReject(bool use_stateless_rejects);
+
+ // crypto_config_ contains crypto parameters for the handshake.
+ const QuicCryptoServerConfig* crypto_config_;
+
+ // compressed_certs_cache_ contains a set of most recently compressed certs.
+ // Owned by QuicDispatcher.
+ QuicCompressedCertsCache* compressed_certs_cache_;
+
+ // Server's certificate chain and signature of the server config, as provided
+ // by ProofSource::GetProof.
+ QuicCryptoProof crypto_proof_;
+
+ // Hash of the last received CHLO message which can be used for generating
+ // server config update messages.
+ std::string chlo_hash_;
+
+ // Pointer to the active callback that will receive the result of
+ // the client hello validation request and forward it to
+ // FinishProcessingHandshakeMessage for processing. nullptr if no
+ // handshake message is being validated.
+ ValidateCallback* validate_client_hello_cb_;
+
+ // Pointer to the helper for this crypto stream. Must outlive this stream.
+ Helper* helper_;
+
+ // Number of handshake messages received by this stream.
+ uint8_t num_handshake_messages_;
+
+ // Number of handshake messages received by this stream that contain
+ // server nonces (indicating that this is a non-zero-RTT handshake
+ // attempt).
+ uint8_t num_handshake_messages_with_server_nonces_;
+
+ // Pointer to the active callback that will receive the result of
+ // BuildServerConfigUpdateMessage and forward it to
+ // FinishSendServerConfigUpdate. nullptr if no update message is currently
+ // being built.
+ SendServerConfigUpdateCallback* send_server_config_update_cb_;
+
+ // Number of server config update (SCUP) messages sent by this stream.
+ int num_server_config_update_messages_sent_;
+
+ // If the client provides CachedNetworkParameters in the STK in the CHLO, then
+ // store here, and send back in future STKs if we have no better bandwidth
+ // estimate to send.
+ std::unique_ptr<CachedNetworkParameters> previous_cached_network_params_;
+
+ // Contains any source address tokens which were present in the CHLO.
+ SourceAddressTokens previous_source_address_tokens_;
+
+ // If true, the server should use stateless rejects, so long as the
+ // client supports them, as indicated by
+ // peer_supports_stateless_rejects_.
+ bool use_stateless_rejects_if_peer_supported_;
+
+ // Set to true, once the server has received information from the
+ // client that it supports stateless reject.
+ // TODO(jokulik): Remove once client stateless reject support
+ // becomes the default.
+ bool peer_supports_stateless_rejects_;
+
+ // Size of the packet containing the most recently received CHLO.
+ QuicByteCount chlo_packet_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicCryptoServerStream);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CRYPTO_SERVER_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
new file mode 100644
index 00000000000..dadcaee3d01
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_server_stream_test.cc
@@ -0,0 +1,629 @@
+// 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/quic_crypto_server_stream.h"
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/stl_util.h"
+#include "net/quic/core/crypto/aes_128_gcm_12_encrypter.h"
+#include "net/quic/core/crypto/crypto_framer.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/crypto_utils.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_crypto_client_stream.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_session.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/delayed_verify_strike_register_client.h"
+#include "net/quic/test_tools/quic_crypto_server_config_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+class QuicConnection;
+class ReliableQuicStream;
+} // namespace net
+
+using std::pair;
+using std::string;
+using testing::_;
+
+namespace net {
+namespace test {
+
+class QuicCryptoServerStreamPeer {
+ public:
+ static bool DoesPeerSupportStatelessRejects(
+ const CryptoHandshakeMessage& message) {
+ return net::QuicCryptoServerStream::DoesPeerSupportStatelessRejects(
+ message);
+ }
+};
+
+namespace {
+
+const char kServerHostname[] = "test.example.com";
+const uint16_t kServerPort = 443;
+
+class QuicCryptoServerStreamTest : public ::testing::TestWithParam<bool> {
+ public:
+ QuicCryptoServerStreamTest()
+ : QuicCryptoServerStreamTest(CryptoTestUtils::ProofSourceForTesting()) {}
+
+ explicit QuicCryptoServerStreamTest(std::unique_ptr<ProofSource> proof_source)
+ : server_crypto_config_(QuicCryptoServerConfig::TESTING,
+ QuicRandom::GetInstance(),
+ std::move(proof_source)),
+ server_compressed_certs_cache_(
+ QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
+ server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED),
+ client_crypto_config_(CryptoTestUtils::ProofVerifierForTesting()) {
+ FLAGS_enable_quic_stateless_reject_support = false;
+ server_crypto_config_.set_strike_register_no_startup_period();
+ }
+
+ void Initialize() {
+ InitializeServer();
+
+ if (AsyncStrikeRegisterVerification()) {
+ QuicCryptoServerConfigPeer peer(&server_crypto_config_);
+ strike_register_client_ = new DelayedVerifyStrikeRegisterClient(
+ 10000, // strike_register_max_entries
+ static_cast<uint32_t>(
+ server_connection_->clock()->WallNow().ToUNIXSeconds()),
+ 60, // strike_register_window_secs
+ peer.GetPrimaryConfig()->orbit,
+ StrikeRegister::NO_STARTUP_PERIOD_NEEDED);
+ strike_register_client_->StartDelayingVerification();
+ server_crypto_config_.SetStrikeRegisterClient(strike_register_client_);
+ }
+ }
+
+ ~QuicCryptoServerStreamTest() override {
+ // Ensure that anything that might reference |helpers_| is destroyed before
+ // |helpers_| is destroyed.
+ server_session_.reset();
+ client_session_.reset();
+ base::STLDeleteElements(&helpers_);
+ base::STLDeleteElements(&alarm_factories_);
+ }
+
+ // Initializes the crypto server stream state for testing. May be
+ // called multiple times.
+ void InitializeServer() {
+ TestQuicSpdyServerSession* server_session = nullptr;
+ helpers_.push_back(new MockQuicConnectionHelper);
+ alarm_factories_.push_back(new MockAlarmFactory);
+ CreateServerSessionForTest(
+ server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_,
+ helpers_.back(), alarm_factories_.back(), &server_crypto_config_,
+ &server_compressed_certs_cache_, &server_connection_, &server_session);
+ CHECK(server_session);
+ server_session_.reset(server_session);
+ CryptoTestUtils::FakeServerOptions options;
+ options.token_binding_params = QuicTagVector{kTB10};
+ CryptoTestUtils::SetupCryptoServerConfigForTest(
+ server_connection_->clock(), server_connection_->random_generator(),
+ server_session_->config(), &server_crypto_config_, options);
+ }
+
+ QuicCryptoServerStream* server_stream() {
+ return server_session_->GetCryptoStream();
+ }
+
+ QuicCryptoClientStream* client_stream() {
+ return client_session_->GetCryptoStream();
+ }
+
+ // Initializes a fake client, and all its associated state, for
+ // testing. May be called multiple times.
+ void InitializeFakeClient(bool supports_stateless_rejects) {
+ TestQuicSpdyClientSession* client_session = nullptr;
+ helpers_.push_back(new MockQuicConnectionHelper);
+ alarm_factories_.push_back(new MockAlarmFactory);
+ CreateClientSessionForTest(
+ server_id_, supports_stateless_rejects,
+ QuicTime::Delta::FromSeconds(100000), supported_versions_,
+
+ helpers_.back(), alarm_factories_.back(), &client_crypto_config_,
+ &client_connection_, &client_session);
+ CHECK(client_session);
+ client_session_.reset(client_session);
+ }
+
+ bool AsyncStrikeRegisterVerification() {
+ if (server_connection_->version() > QUIC_VERSION_32) {
+ return false;
+ }
+ return GetParam();
+ }
+
+ void ConstructHandshakeMessage() {
+ CryptoFramer framer;
+ message_data_.reset(framer.ConstructHandshakeMessage(message_));
+ }
+
+ int CompleteCryptoHandshake() {
+ CHECK(server_connection_);
+ CHECK(server_session_ != nullptr);
+ return CryptoTestUtils::HandshakeWithFakeClient(
+ helpers_.back(), alarm_factories_.back(), server_connection_,
+ server_stream(), server_id_, client_options_);
+ }
+
+ // Performs a single round of handshake message-exchange between the
+ // client and server.
+ void AdvanceHandshakeWithFakeClient() {
+ CHECK(server_connection_);
+ CHECK(client_session_ != nullptr);
+
+ EXPECT_CALL(*client_session_, OnProofValid(_)).Times(testing::AnyNumber());
+ client_stream()->CryptoConnect();
+ CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream(), 0,
+ server_connection_, server_stream(), 0);
+ }
+
+ protected:
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+
+ // Every connection gets its own MockQuicConnectionHelper and
+ // MockAlarmFactory,
+ // tracked separately from
+ // the server and client state so their lifetimes persist through the whole
+ // test.
+ std::vector<MockQuicConnectionHelper*> helpers_;
+ std::vector<MockAlarmFactory*> alarm_factories_;
+
+ // Server state
+ PacketSavingConnection* server_connection_;
+ std::unique_ptr<TestQuicSpdyServerSession> server_session_;
+ QuicCryptoServerConfig server_crypto_config_;
+ QuicCompressedCertsCache server_compressed_certs_cache_;
+ QuicServerId server_id_;
+
+ // Client state
+ PacketSavingConnection* client_connection_;
+ QuicCryptoClientConfig client_crypto_config_;
+ std::unique_ptr<TestQuicSpdyClientSession> client_session_;
+
+ CryptoHandshakeMessage message_;
+ std::unique_ptr<QuicData> message_data_;
+ CryptoTestUtils::FakeClientOptions client_options_;
+ DelayedVerifyStrikeRegisterClient* strike_register_client_;
+
+ // Which QUIC versions the client and server support.
+ QuicVersionVector supported_versions_ = AllSupportedVersions();
+};
+
+INSTANTIATE_TEST_CASE_P(Tests, QuicCryptoServerStreamTest, testing::Bool());
+
+TEST_P(QuicCryptoServerStreamTest, NotInitiallyConected) {
+ Initialize();
+ EXPECT_FALSE(server_stream()->encryption_established());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
+}
+
+TEST_P(QuicCryptoServerStreamTest, NotInitiallySendingStatelessRejects) {
+ Initialize();
+ EXPECT_FALSE(server_stream()->UseStatelessRejectsIfPeerSupported());
+ EXPECT_FALSE(server_stream()->PeerSupportsStatelessRejects());
+}
+
+TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) {
+ // CompleteCryptoHandshake returns the number of client hellos sent. This
+ // test should send:
+ // * One to get a source-address token and certificates.
+ // * One to complete the handshake.
+ Initialize();
+ EXPECT_EQ(2, CompleteCryptoHandshake());
+ EXPECT_TRUE(server_stream()->encryption_established());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
+}
+
+TEST_P(QuicCryptoServerStreamTest, ForwardSecureAfterCHLO) {
+ Initialize();
+ InitializeFakeClient(/* supports_stateless_rejects= */ false);
+
+ // Do a first handshake in order to prime the client config with the server's
+ // information.
+ AdvanceHandshakeWithFakeClient();
+ EXPECT_FALSE(server_stream()->encryption_established());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
+
+ // Now do another handshake, with the blocking SHLO connection option.
+ InitializeServer();
+ InitializeFakeClient(/* supports_stateless_rejects= */ false);
+
+ AdvanceHandshakeWithFakeClient();
+ EXPECT_TRUE(server_stream()->encryption_established());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
+ EXPECT_EQ(ENCRYPTION_FORWARD_SECURE,
+ server_session_->connection()->encryption_level());
+}
+
+TEST_P(QuicCryptoServerStreamTest, StatelessRejectAfterCHLO) {
+ FLAGS_enable_quic_stateless_reject_support = true;
+
+ Initialize();
+
+ EXPECT_CALL(*server_connection_,
+ CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _));
+
+ InitializeFakeClient(/* supports_stateless_rejects= */ true);
+ AdvanceHandshakeWithFakeClient();
+
+ // Check the server to make the sure the handshake did not succeed.
+ EXPECT_FALSE(server_stream()->encryption_established());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
+
+ // Check the client state to make sure that it received a server-designated
+ // connection id.
+ QuicCryptoClientConfig::CachedState* client_state =
+ client_crypto_config_.LookupOrCreate(server_id_);
+
+ ASSERT_TRUE(client_state->has_server_nonce());
+ ASSERT_FALSE(client_state->GetNextServerNonce().empty());
+ ASSERT_FALSE(client_state->has_server_nonce());
+
+ ASSERT_TRUE(client_state->has_server_designated_connection_id());
+ const QuicConnectionId server_designated_connection_id =
+ client_state->GetNextServerDesignatedConnectionId();
+ const QuicConnectionId expected_id =
+ server_connection_->random_generator()->RandUint64();
+ EXPECT_EQ(expected_id, server_designated_connection_id);
+ EXPECT_FALSE(client_state->has_server_designated_connection_id());
+ ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
+}
+
+TEST_P(QuicCryptoServerStreamTest, ConnectedAfterStatelessHandshake) {
+ FLAGS_enable_quic_stateless_reject_support = true;
+
+ Initialize();
+
+ InitializeFakeClient(/* supports_stateless_rejects= */ true);
+ AdvanceHandshakeWithFakeClient();
+
+ // On the first round, encryption will not be established.
+ EXPECT_FALSE(server_stream()->encryption_established());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
+ EXPECT_EQ(1, server_stream()->NumHandshakeMessages());
+ EXPECT_EQ(0, server_stream()->NumHandshakeMessagesWithServerNonces());
+
+ // Now check the client state.
+ QuicCryptoClientConfig::CachedState* client_state =
+ client_crypto_config_.LookupOrCreate(server_id_);
+
+ ASSERT_TRUE(client_state->has_server_designated_connection_id());
+ const QuicConnectionId server_designated_connection_id =
+ client_state->GetNextServerDesignatedConnectionId();
+ const QuicConnectionId expected_id =
+ server_connection_->random_generator()->RandUint64();
+ EXPECT_EQ(expected_id, server_designated_connection_id);
+ EXPECT_FALSE(client_state->has_server_designated_connection_id());
+ ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
+
+ // Now create new client and server streams with the existing config
+ // and try the handshake again (0-RTT handshake).
+ InitializeServer();
+
+ InitializeFakeClient(/* supports_stateless_rejects= */ true);
+
+ // In the stateless case, the second handshake contains a server-nonce, so the
+ // AsyncStrikeRegisterVerification() case will still succeed (unlike a 0-RTT
+ // handshake).
+ AdvanceHandshakeWithFakeClient();
+
+ // On the second round, encryption will be established.
+ EXPECT_TRUE(server_stream()->encryption_established());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
+ EXPECT_EQ(1, server_stream()->NumHandshakeMessages());
+ EXPECT_EQ(1, server_stream()->NumHandshakeMessagesWithServerNonces());
+}
+
+TEST_P(QuicCryptoServerStreamTest, NoStatelessRejectIfNoClientSupport) {
+ FLAGS_enable_quic_stateless_reject_support = true;
+
+ Initialize();
+
+ // The server is configured to use stateless rejects, but the client does not
+ // support it.
+ InitializeFakeClient(/* supports_stateless_rejects= */ false);
+ AdvanceHandshakeWithFakeClient();
+
+ // Check the server to make the sure the handshake did not succeed.
+ EXPECT_FALSE(server_stream()->encryption_established());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
+
+ // Check the client state to make sure that it did not receive a
+ // server-designated connection id.
+ QuicCryptoClientConfig::CachedState* client_state =
+ client_crypto_config_.LookupOrCreate(server_id_);
+
+ ASSERT_FALSE(client_state->has_server_designated_connection_id());
+ ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
+}
+
+TEST_P(QuicCryptoServerStreamTest, ZeroRTT) {
+ Initialize();
+ InitializeFakeClient(/* supports_stateless_rejects= */ false);
+
+ // Do a first handshake in order to prime the client config with the server's
+ // information.
+ AdvanceHandshakeWithFakeClient();
+
+ // Now do another handshake, hopefully in 0-RTT.
+ DVLOG(1) << "Resetting for 0-RTT handshake attempt";
+ InitializeFakeClient(/* supports_stateless_rejects= */ false);
+ InitializeServer();
+
+ client_stream()->CryptoConnect();
+
+ if (AsyncStrikeRegisterVerification()) {
+ EXPECT_FALSE(client_stream()->handshake_confirmed());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
+
+ // Advance the handshake. Expect that the server will be stuck waiting for
+ // client nonce verification to complete.
+ pair<size_t, size_t> messages_moved = CryptoTestUtils::AdvanceHandshake(
+ client_connection_, client_stream(), 0, server_connection_,
+ server_stream(), 0);
+ EXPECT_EQ(1u, messages_moved.first);
+ EXPECT_EQ(0u, messages_moved.second);
+ EXPECT_EQ(1, strike_register_client_->PendingVerifications());
+ EXPECT_FALSE(client_stream()->handshake_confirmed());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
+
+ // The server handshake completes once the nonce verification completes.
+ strike_register_client_->RunPendingVerifications();
+ EXPECT_FALSE(client_stream()->handshake_confirmed());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
+
+ messages_moved = CryptoTestUtils::AdvanceHandshake(
+ client_connection_, client_stream(), messages_moved.first,
+ server_connection_, server_stream(), messages_moved.second);
+ EXPECT_EQ(1u, messages_moved.first);
+ EXPECT_EQ(1u, messages_moved.second);
+ EXPECT_TRUE(client_stream()->handshake_confirmed());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
+ } else {
+ CryptoTestUtils::CommunicateHandshakeMessages(
+ client_connection_, client_stream(), server_connection_,
+ server_stream());
+ }
+
+ EXPECT_EQ(1, client_stream()->num_sent_client_hellos());
+}
+
+TEST_P(QuicCryptoServerStreamTest, FailByPolicy) {
+ Initialize();
+ InitializeFakeClient(/* supports_stateless_rejects= */ false);
+
+ EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _))
+ .WillOnce(testing::Return(false));
+ EXPECT_CALL(*server_connection_,
+ CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
+
+ AdvanceHandshakeWithFakeClient();
+}
+
+TEST_P(QuicCryptoServerStreamTest, MessageAfterHandshake) {
+ Initialize();
+ CompleteCryptoHandshake();
+ EXPECT_CALL(
+ *server_connection_,
+ CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE, _, _));
+ message_.set_tag(kCHLO);
+ ConstructHandshakeMessage();
+ server_stream()->OnStreamFrame(
+ QuicStreamFrame(kCryptoStreamId, /*fin=*/false, /*offset=*/0,
+ message_data_->AsStringPiece()));
+}
+
+TEST_P(QuicCryptoServerStreamTest, BadMessageType) {
+ Initialize();
+
+ message_.set_tag(kSHLO);
+ ConstructHandshakeMessage();
+ EXPECT_CALL(*server_connection_,
+ CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, _, _));
+ server_stream()->OnStreamFrame(
+ QuicStreamFrame(kCryptoStreamId, /*fin=*/false, /*offset=*/0,
+ message_data_->AsStringPiece()));
+}
+
+TEST_P(QuicCryptoServerStreamTest, ChannelID) {
+ Initialize();
+
+ client_options_.channel_id_enabled = true;
+ client_options_.channel_id_source_async = false;
+ // CompleteCryptoHandshake verifies
+ // server_stream()->crypto_negotiated_params().channel_id is correct.
+ EXPECT_EQ(2, CompleteCryptoHandshake());
+ EXPECT_TRUE(server_stream()->encryption_established());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
+}
+
+TEST_P(QuicCryptoServerStreamTest, ChannelIDAsync) {
+ Initialize();
+
+ client_options_.channel_id_enabled = true;
+ client_options_.channel_id_source_async = true;
+ // CompleteCryptoHandshake verifies
+ // server_stream()->crypto_negotiated_params().channel_id is correct.
+ EXPECT_EQ(2, CompleteCryptoHandshake());
+ EXPECT_TRUE(server_stream()->encryption_established());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
+}
+
+TEST_P(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) {
+ // An attempt to send a SCUP before completing handshake should fail.
+ Initialize();
+
+ server_stream()->SendServerConfigUpdate(nullptr);
+ EXPECT_EQ(0, server_stream()->NumServerConfigUpdateMessagesSent());
+}
+
+TEST_P(QuicCryptoServerStreamTest, SendSCUPAfterHandshakeComplete) {
+ Initialize();
+
+ InitializeFakeClient(/* supports_stateless_rejects= */ false);
+
+ // Do a first handshake in order to prime the client config with the server's
+ // information.
+ AdvanceHandshakeWithFakeClient();
+
+ // Now do another handshake, with the blocking SHLO connection option.
+ InitializeServer();
+ InitializeFakeClient(/* supports_stateless_rejects= */ false);
+ AdvanceHandshakeWithFakeClient();
+
+ // Send a SCUP message and ensure that the client was able to verify it.
+ EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0);
+ server_stream()->SendServerConfigUpdate(nullptr);
+ CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream(), 1,
+ server_connection_, server_stream(), 1);
+
+ EXPECT_EQ(1, server_stream()->NumServerConfigUpdateMessagesSent());
+ EXPECT_EQ(1, client_stream()->num_scup_messages_received());
+}
+
+TEST_P(QuicCryptoServerStreamTest, DoesPeerSupportStatelessRejects) {
+ Initialize();
+
+ ConstructHandshakeMessage();
+ QuicConfig stateless_reject_config = DefaultQuicConfigStatelessRejects();
+ stateless_reject_config.ToHandshakeMessage(&message_);
+ EXPECT_TRUE(
+ QuicCryptoServerStreamPeer::DoesPeerSupportStatelessRejects(message_));
+
+ message_.Clear();
+ QuicConfig stateful_reject_config = DefaultQuicConfig();
+ stateful_reject_config.ToHandshakeMessage(&message_);
+ EXPECT_FALSE(
+ QuicCryptoServerStreamPeer::DoesPeerSupportStatelessRejects(message_));
+}
+
+TEST_P(QuicCryptoServerStreamTest, TokenBindingNegotiated) {
+ Initialize();
+
+ client_options_.token_binding_params = QuicTagVector{kTB10, kP256};
+ CompleteCryptoHandshake();
+ EXPECT_EQ(
+ kTB10,
+ server_stream()->crypto_negotiated_params().token_binding_key_param);
+ EXPECT_TRUE(server_stream()->encryption_established());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
+}
+
+TEST_P(QuicCryptoServerStreamTest, NoTokenBindingWithoutClientSupport) {
+ Initialize();
+
+ CompleteCryptoHandshake();
+ EXPECT_EQ(
+ 0u, server_stream()->crypto_negotiated_params().token_binding_key_param);
+ EXPECT_TRUE(server_stream()->encryption_established());
+ EXPECT_TRUE(server_stream()->handshake_confirmed());
+}
+
+TEST_P(QuicCryptoServerStreamTest, CancelRPCBeforeVerificationCompletes) {
+ FLAGS_quic_require_handshake_confirmation_pre33 = false;
+ // Tests that the client can close the connection while the remote strike
+ // register verification RPC is still pending.
+
+ // Set version to QUIC_VERSION_32 as QUIC_VERSION_33 and later don't support
+ // asynchronous strike register RPCs.
+ supported_versions_ = {QUIC_VERSION_32};
+ Initialize();
+ if (!AsyncStrikeRegisterVerification()) {
+ return;
+ }
+ InitializeFakeClient(/* supports_stateless_rejects= */ false);
+
+ // Do a first handshake in order to prime the client config with the server's
+ // information.
+ AdvanceHandshakeWithFakeClient();
+
+ // Now start another handshake, this time the server will attempt to verify
+ // the client's nonce with the strike registers.
+ InitializeFakeClient(/* supports_stateless_rejects= */ false);
+ InitializeServer();
+ client_stream()->CryptoConnect();
+ EXPECT_FALSE(client_stream()->handshake_confirmed());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
+
+ // Advance the handshake. Expect that the server will be stuck waiting for
+ // client nonce verification to complete.
+ CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream(), 0,
+ server_connection_, server_stream(), 0);
+ EXPECT_EQ(1, strike_register_client_->PendingVerifications());
+ EXPECT_FALSE(client_stream()->handshake_confirmed());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
+
+ // While waiting for the asynchronous verification to complete, the client
+ // decides to close the connection.
+ server_session_->connection()->CloseConnection(
+ QUIC_NO_ERROR, "", ConnectionCloseBehavior::SILENT_CLOSE);
+
+ // The outstanding nonce verification RPC now completes.
+ strike_register_client_->RunPendingVerifications();
+}
+
+class FailingProofSource : public ProofSource {
+ public:
+ bool GetProof(const IPAddress& server_ip,
+ const string& hostname,
+ const string& server_config,
+ QuicVersion quic_version,
+ StringPiece chlo_hash,
+ scoped_refptr<ProofSource::Chain>* out_chain,
+ string* out_signature,
+ string* out_leaf_cert_sct) override {
+ return false;
+ }
+
+ void GetProof(const IPAddress& server_ip,
+ const string& hostname,
+ const string& server_config,
+ QuicVersion quic_version,
+ StringPiece chlo_hash,
+ std::unique_ptr<Callback> callback) override {
+ callback->Run(false, nullptr, "", "", nullptr);
+ }
+};
+
+class QuicCryptoServerStreamTestWithFailingProofSource
+ : public QuicCryptoServerStreamTest {
+ public:
+ QuicCryptoServerStreamTestWithFailingProofSource()
+ : QuicCryptoServerStreamTest(
+ std::unique_ptr<FailingProofSource>(new FailingProofSource)) {}
+};
+
+INSTANTIATE_TEST_CASE_P(MoreTests,
+ QuicCryptoServerStreamTestWithFailingProofSource,
+ testing::Bool());
+
+TEST_P(QuicCryptoServerStreamTestWithFailingProofSource, Test) {
+ Initialize();
+ InitializeFakeClient(/* supports_stateless_rejects= */ false);
+
+ // Regression test for b/31521252, in which a crash would happen here.
+ AdvanceHandshakeWithFakeClient();
+ EXPECT_FALSE(server_stream()->encryption_established());
+ EXPECT_FALSE(server_stream()->handshake_confirmed());
+}
+
+} // namespace
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_crypto_stream.cc b/chromium/net/quic/core/quic_crypto_stream.cc
new file mode 100644
index 00000000000..be7271c519f
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_stream.cc
@@ -0,0 +1,120 @@
+// 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/quic_crypto_stream.h"
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/crypto_utils.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_session.h"
+#include "net/quic/core/quic_utils.h"
+
+using std::string;
+using base::StringPiece;
+using net::SpdyPriority;
+
+namespace net {
+
+#define ENDPOINT \
+ (session()->perspective() == Perspective::IS_SERVER ? "Server: " : "Client:" \
+ " ")
+
+QuicCryptoStream::QuicCryptoStream(QuicSession* session)
+ : ReliableQuicStream(kCryptoStreamId, session),
+ encryption_established_(false),
+ handshake_confirmed_(false) {
+ crypto_framer_.set_visitor(this);
+ // The crypto stream is exempt from connection level flow control.
+ DisableConnectionFlowControlForThisStream();
+}
+
+// static
+QuicByteCount QuicCryptoStream::CryptoMessageFramingOverhead(
+ QuicVersion version) {
+ return QuicPacketCreator::StreamFramePacketOverhead(
+ version, PACKET_8BYTE_CONNECTION_ID,
+ /*include_version=*/true,
+ /*include_path_id=*/true,
+ /*include_diversification_nonce=*/true, PACKET_1BYTE_PACKET_NUMBER,
+ /*offset=*/0);
+}
+
+void QuicCryptoStream::OnError(CryptoFramer* framer) {
+ DLOG(WARNING) << "Error processing crypto data: "
+ << QuicUtils::ErrorToString(framer->error());
+}
+
+void QuicCryptoStream::OnHandshakeMessage(
+ const CryptoHandshakeMessage& message) {
+ DVLOG(1) << ENDPOINT << "Received " << message.DebugString();
+ session()->OnCryptoHandshakeMessageReceived(message);
+}
+
+void QuicCryptoStream::OnDataAvailable() {
+ struct iovec iov;
+ while (true) {
+ if (sequencer()->GetReadableRegions(&iov, 1) != 1) {
+ // No more data to read.
+ break;
+ }
+ StringPiece data(static_cast<char*>(iov.iov_base), iov.iov_len);
+ if (!crypto_framer_.ProcessInput(data)) {
+ CloseConnectionWithDetails(crypto_framer_.error(),
+ crypto_framer_.error_detail());
+ return;
+ }
+ sequencer()->MarkConsumed(iov.iov_len);
+ if (handshake_confirmed_ && crypto_framer_.InputBytesRemaining() == 0) {
+ // If the handshake is complete and the current message has been fully
+ // processed then no more handshake messages are likely to arrive soon
+ // so release the memory in the stream sequencer.
+ sequencer()->ReleaseBufferIfEmpty();
+ }
+ }
+}
+
+void QuicCryptoStream::SendHandshakeMessage(
+ const CryptoHandshakeMessage& message) {
+ DVLOG(1) << ENDPOINT << "Sending " << message.DebugString();
+ session()->connection()->NeuterUnencryptedPackets();
+ session()->OnCryptoHandshakeMessageSent(message);
+ const QuicData& data = message.GetSerialized();
+ WriteOrBufferData(StringPiece(data.data(), data.length()), false, nullptr);
+}
+
+bool QuicCryptoStream::ExportKeyingMaterial(StringPiece label,
+ StringPiece context,
+ size_t result_len,
+ string* result) const {
+ if (!handshake_confirmed()) {
+ DLOG(ERROR) << "ExportKeyingMaterial was called before forward-secure"
+ << "encryption was established.";
+ return false;
+ }
+ return CryptoUtils::ExportKeyingMaterial(
+ crypto_negotiated_params_.subkey_secret, label, context, result_len,
+ result);
+}
+
+bool QuicCryptoStream::ExportTokenBindingKeyingMaterial(string* result) const {
+ if (!encryption_established()) {
+ QUIC_BUG << "ExportTokenBindingKeyingMaterial was called before initial"
+ << "encryption was established.";
+ return false;
+ }
+ return CryptoUtils::ExportKeyingMaterial(
+ crypto_negotiated_params_.initial_subkey_secret, "EXPORTER-Token-Binding",
+ /* context= */ "", 32, result);
+}
+
+const QuicCryptoNegotiatedParameters&
+QuicCryptoStream::crypto_negotiated_params() const {
+ return crypto_negotiated_params_;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_crypto_stream.h b/chromium/net/quic/core/quic_crypto_stream.h
new file mode 100644
index 00000000000..494ecd7f1c5
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_stream.h
@@ -0,0 +1,92 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_CRYPTO_STREAM_H_
+#define NET_QUIC_QUIC_CRYPTO_STREAM_H_
+
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/crypto_framer.h"
+#include "net/quic/core/crypto/crypto_utils.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/reliable_quic_stream.h"
+
+namespace net {
+
+class CryptoHandshakeMessage;
+class QuicSession;
+
+// Crypto handshake messages in QUIC take place over a reserved
+// reliable stream with the id 1. Each endpoint (client and server)
+// will allocate an instance of a subclass of QuicCryptoStream
+// to send and receive handshake messages. (In the normal 1-RTT
+// handshake, the client will send a client hello, CHLO, message.
+// The server will receive this message and respond with a server
+// hello message, SHLO. At this point both sides will have established
+// a crypto context they can use to send encrypted messages.
+//
+// For more details: http://goto.google.com/quic-crypto
+class NET_EXPORT_PRIVATE QuicCryptoStream
+ : public ReliableQuicStream,
+ public CryptoFramerVisitorInterface {
+ public:
+ explicit QuicCryptoStream(QuicSession* session);
+
+ // Returns the per-packet framing overhead associated with sending a
+ // handshake message for |version|.
+ static QuicByteCount CryptoMessageFramingOverhead(QuicVersion version);
+
+ // CryptoFramerVisitorInterface implementation
+ void OnError(CryptoFramer* framer) override;
+ void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
+
+ // ReliableQuicStream implementation
+ void OnDataAvailable() override;
+
+ // Sends |message| to the peer.
+ // TODO(wtc): return a success/failure status.
+ void SendHandshakeMessage(const CryptoHandshakeMessage& message);
+
+ // Performs key extraction to derive a new secret of |result_len| bytes
+ // dependent on |label|, |context|, and the stream's negotiated subkey secret.
+ // Returns false if the handshake has not been confirmed or the parameters are
+ // invalid (e.g. |label| contains null bytes); returns true on success.
+ bool ExportKeyingMaterial(base::StringPiece label,
+ base::StringPiece context,
+ size_t result_len,
+ std::string* result) const;
+
+ // Performs key extraction for Token Binding. Unlike ExportKeyingMaterial,
+ // this function can be called before forward-secure encryption is
+ // established. Returns false if initial encryption has not been established,
+ // and true on success.
+ //
+ // Since this depends only on the initial keys, a signature over it can be
+ // repurposed by an attacker who obtains the client's or server's DH private
+ // value.
+ bool ExportTokenBindingKeyingMaterial(std::string* result) const;
+
+ bool encryption_established() const { return encryption_established_; }
+ bool handshake_confirmed() const { return handshake_confirmed_; }
+
+ const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const;
+
+ protected:
+ bool encryption_established_;
+ bool handshake_confirmed_;
+
+ QuicCryptoNegotiatedParameters crypto_negotiated_params_;
+
+ private:
+ CryptoFramer crypto_framer_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicCryptoStream);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_CRYPTO_STREAM_H_
diff --git a/chromium/net/quic/core/quic_crypto_stream_test.cc b/chromium/net/quic/core/quic_crypto_stream_test.cc
new file mode 100644
index 00000000000..4485ee881dc
--- /dev/null
+++ b/chromium/net/quic/core/quic_crypto_stream_test.cc
@@ -0,0 +1,115 @@
+// 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/quic_crypto_stream.h"
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/reliable_quic_stream_peer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+using std::vector;
+
+namespace net {
+namespace test {
+namespace {
+
+class MockQuicCryptoStream : public QuicCryptoStream {
+ public:
+ explicit MockQuicCryptoStream(QuicSession* session)
+ : QuicCryptoStream(session) {}
+
+ void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
+ messages_.push_back(message);
+ }
+
+ vector<CryptoHandshakeMessage>* messages() { return &messages_; }
+
+ private:
+ vector<CryptoHandshakeMessage> messages_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockQuicCryptoStream);
+};
+
+class QuicCryptoStreamTest : public ::testing::Test {
+ public:
+ QuicCryptoStreamTest()
+ : connection_(new MockQuicConnection(&helper_,
+ &alarm_factory_,
+ Perspective::IS_CLIENT)),
+ session_(connection_),
+ stream_(&session_) {
+ message_.set_tag(kSHLO);
+ message_.SetStringPiece(1, "abc");
+ message_.SetStringPiece(2, "def");
+ ConstructHandshakeMessage();
+ }
+
+ void ConstructHandshakeMessage() {
+ CryptoFramer framer;
+ message_data_.reset(framer.ConstructHandshakeMessage(message_));
+ }
+
+ protected:
+ MockQuicConnectionHelper helper_;
+ MockAlarmFactory alarm_factory_;
+ MockQuicConnection* connection_;
+ MockQuicSpdySession session_;
+ MockQuicCryptoStream stream_;
+ CryptoHandshakeMessage message_;
+ std::unique_ptr<QuicData> message_data_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicCryptoStreamTest);
+};
+
+TEST_F(QuicCryptoStreamTest, NotInitiallyConected) {
+ EXPECT_FALSE(stream_.encryption_established());
+ EXPECT_FALSE(stream_.handshake_confirmed());
+}
+
+TEST_F(QuicCryptoStreamTest, ProcessRawData) {
+ stream_.OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false,
+ /*offset=*/0,
+ message_data_->AsStringPiece()));
+ ASSERT_EQ(1u, stream_.messages()->size());
+ const CryptoHandshakeMessage& message = (*stream_.messages())[0];
+ EXPECT_EQ(kSHLO, message.tag());
+ EXPECT_EQ(2u, message.tag_value_map().size());
+ EXPECT_EQ("abc", CryptoTestUtils::GetValueForTag(message, 1));
+ EXPECT_EQ("def", CryptoTestUtils::GetValueForTag(message, 2));
+}
+
+TEST_F(QuicCryptoStreamTest, ProcessBadData) {
+ string bad(message_data_->data(), message_data_->length());
+ const int kFirstTagIndex = sizeof(uint32_t) + // message tag
+ sizeof(uint16_t) + // number of tag-value pairs
+ sizeof(uint16_t); // padding
+ EXPECT_EQ(1, bad[kFirstTagIndex]);
+ bad[kFirstTagIndex] = 0x7F; // out of order tag
+
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_CRYPTO_TAGS_OUT_OF_ORDER,
+ testing::_, testing::_));
+ stream_.OnStreamFrame(
+ QuicStreamFrame(kCryptoStreamId, /*fin=*/false, /*offset=*/0, bad));
+}
+
+TEST_F(QuicCryptoStreamTest, NoConnectionLevelFlowControl) {
+ EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl(
+ &stream_));
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_data_reader.cc b/chromium/net/quic/core/quic_data_reader.cc
new file mode 100644
index 00000000000..72185cdeb41
--- /dev/null
+++ b/chromium/net/quic/core/quic_data_reader.cc
@@ -0,0 +1,133 @@
+// 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/quic_data_reader.h"
+
+#include "net/base/int128.h"
+#include "net/quic/core/quic_protocol.h"
+
+using base::StringPiece;
+
+namespace net {
+
+QuicDataReader::QuicDataReader(const char* data, const size_t len)
+ : data_(data), len_(len), pos_(0) {}
+
+bool QuicDataReader::ReadUInt16(uint16_t* result) {
+ return ReadBytes(result, sizeof(*result));
+}
+
+bool QuicDataReader::ReadUInt32(uint32_t* result) {
+ return ReadBytes(result, sizeof(*result));
+}
+
+bool QuicDataReader::ReadUInt64(uint64_t* result) {
+ return ReadBytes(result, sizeof(*result));
+}
+
+bool QuicDataReader::ReadUFloat16(uint64_t* result) {
+ uint16_t value;
+ if (!ReadUInt16(&value)) {
+ return false;
+ }
+
+ *result = value;
+ if (*result < (1 << kUFloat16MantissaEffectiveBits)) {
+ // Fast path: either the value is denormalized (no hidden bit), or
+ // normalized (hidden bit set, exponent offset by one) with exponent zero.
+ // Zero exponent offset by one sets the bit exactly where the hidden bit is.
+ // So in both cases the value encodes itself.
+ return true;
+ }
+
+ uint16_t exponent =
+ value >> kUFloat16MantissaBits; // No sign extend on uint!
+ // After the fast pass, the exponent is at least one (offset by one).
+ // Un-offset the exponent.
+ --exponent;
+ DCHECK_GE(exponent, 1);
+ DCHECK_LE(exponent, kUFloat16MaxExponent);
+ // Here we need to clear the exponent and set the hidden bit. We have already
+ // decremented the exponent, so when we subtract it, it leaves behind the
+ // hidden bit.
+ *result -= exponent << kUFloat16MantissaBits;
+ *result <<= exponent;
+ DCHECK_GE(*result,
+ static_cast<uint64_t>(1 << kUFloat16MantissaEffectiveBits));
+ DCHECK_LE(*result, kUFloat16MaxValue);
+ return true;
+}
+
+bool QuicDataReader::ReadStringPiece16(StringPiece* result) {
+ // Read resultant length.
+ uint16_t result_len;
+ if (!ReadUInt16(&result_len)) {
+ // OnFailure() already called.
+ return false;
+ }
+
+ return ReadStringPiece(result, result_len);
+}
+
+bool QuicDataReader::ReadStringPiece(StringPiece* result, size_t size) {
+ // Make sure that we have enough data to read.
+ if (!CanRead(size)) {
+ OnFailure();
+ return false;
+ }
+
+ // Set result.
+ result->set(data_ + pos_, size);
+
+ // Iterate.
+ pos_ += size;
+
+ return true;
+}
+
+StringPiece QuicDataReader::ReadRemainingPayload() {
+ StringPiece payload = PeekRemainingPayload();
+ pos_ = len_;
+ return payload;
+}
+
+StringPiece QuicDataReader::PeekRemainingPayload() {
+ return StringPiece(data_ + pos_, len_ - pos_);
+}
+
+bool QuicDataReader::ReadBytes(void* result, size_t size) {
+ // Make sure that we have enough data to read.
+ if (!CanRead(size)) {
+ OnFailure();
+ return false;
+ }
+
+ // Read into result.
+ memcpy(result, data_ + pos_, size);
+
+ // Iterate.
+ pos_ += size;
+
+ return true;
+}
+
+bool QuicDataReader::IsDoneReading() const {
+ return len_ == pos_;
+}
+
+size_t QuicDataReader::BytesRemaining() const {
+ return len_ - pos_;
+}
+
+bool QuicDataReader::CanRead(size_t bytes) const {
+ return bytes <= (len_ - pos_);
+}
+
+void QuicDataReader::OnFailure() {
+ // Set our iterator to the end of the buffer so that further reads fail
+ // immediately.
+ pos_ = len_;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/quic_data_reader.h b/chromium/net/quic/core/quic_data_reader.h
index 970e5b208f3..970e5b208f3 100644
--- a/chromium/net/quic/quic_data_reader.h
+++ b/chromium/net/quic/core/quic_data_reader.h
diff --git a/chromium/net/quic/core/quic_data_writer.cc b/chromium/net/quic/core/quic_data_writer.cc
new file mode 100644
index 00000000000..f56145887a2
--- /dev/null
+++ b/chromium/net/quic/core/quic_data_writer.cc
@@ -0,0 +1,145 @@
+// 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/quic_data_writer.h"
+
+#include <stdint.h>
+#include <algorithm>
+#include <limits>
+
+using base::StringPiece;
+using std::numeric_limits;
+
+namespace net {
+
+QuicDataWriter::QuicDataWriter(size_t size, char* buffer)
+ : buffer_(buffer), capacity_(size), length_(0) {}
+
+QuicDataWriter::~QuicDataWriter() {}
+
+char* QuicDataWriter::data() {
+ return buffer_;
+}
+
+bool QuicDataWriter::WriteUInt8(uint8_t value) {
+ return WriteBytes(&value, sizeof(value));
+}
+
+bool QuicDataWriter::WriteUInt16(uint16_t value) {
+ return WriteBytes(&value, sizeof(value));
+}
+
+bool QuicDataWriter::WriteUInt32(uint32_t value) {
+ return WriteBytes(&value, sizeof(value));
+}
+
+bool QuicDataWriter::WriteUInt48(uint64_t value) {
+ uint16_t hi = static_cast<uint16_t>(value >> 32);
+ uint32_t lo = static_cast<uint32_t>(value);
+ return WriteUInt32(lo) && WriteUInt16(hi);
+}
+
+bool QuicDataWriter::WriteUInt64(uint64_t value) {
+ return WriteBytes(&value, sizeof(value));
+}
+
+bool QuicDataWriter::WriteUFloat16(uint64_t value) {
+ uint16_t result;
+ if (value < (UINT64_C(1) << kUFloat16MantissaEffectiveBits)) {
+ // Fast path: either the value is denormalized, or has exponent zero.
+ // Both cases are represented by the value itself.
+ result = static_cast<uint16_t>(value);
+ } else if (value >= kUFloat16MaxValue) {
+ // Value is out of range; clamp it to the maximum representable.
+ result = numeric_limits<uint16_t>::max();
+ } else {
+ // The highest bit is between position 13 and 42 (zero-based), which
+ // corresponds to exponent 1-30. In the output, mantissa is from 0 to 10,
+ // hidden bit is 11 and exponent is 11 to 15. Shift the highest bit to 11
+ // and count the shifts.
+ uint16_t exponent = 0;
+ for (uint16_t offset = 16; offset > 0; offset /= 2) {
+ // Right-shift the value until the highest bit is in position 11.
+ // For offset of 16, 8, 4, 2 and 1 (binary search over 1-30),
+ // shift if the bit is at or above 11 + offset.
+ if (value >= (UINT64_C(1) << (kUFloat16MantissaBits + offset))) {
+ exponent += offset;
+ value >>= offset;
+ }
+ }
+
+ DCHECK_GE(exponent, 1);
+ DCHECK_LE(exponent, kUFloat16MaxExponent);
+ DCHECK_GE(value, UINT64_C(1) << kUFloat16MantissaBits);
+ DCHECK_LT(value, UINT64_C(1) << kUFloat16MantissaEffectiveBits);
+
+ // Hidden bit (position 11) is set. We should remove it and increment the
+ // exponent. Equivalently, we just add it to the exponent.
+ // This hides the bit.
+ result = static_cast<uint16_t>(value + (exponent << kUFloat16MantissaBits));
+ }
+
+ return WriteBytes(&result, sizeof(result));
+}
+
+bool QuicDataWriter::WriteStringPiece16(StringPiece val) {
+ if (val.size() > numeric_limits<uint16_t>::max()) {
+ return false;
+ }
+ if (!WriteUInt16(static_cast<uint16_t>(val.size()))) {
+ return false;
+ }
+ return WriteBytes(val.data(), val.size());
+}
+
+char* QuicDataWriter::BeginWrite(size_t length) {
+ if (length_ > capacity_) {
+ return nullptr;
+ }
+
+ if (capacity_ - length_ < length) {
+ return nullptr;
+ }
+
+#ifdef ARCH_CPU_64_BITS
+ DCHECK_LE(length, std::numeric_limits<uint32_t>::max());
+#endif
+
+ return buffer_ + length_;
+}
+
+bool QuicDataWriter::WriteBytes(const void* data, size_t data_len) {
+ char* dest = BeginWrite(data_len);
+ if (!dest) {
+ return false;
+ }
+
+ memcpy(dest, data, data_len);
+
+ length_ += data_len;
+ return true;
+}
+
+bool QuicDataWriter::WriteRepeatedByte(uint8_t byte, size_t count) {
+ char* dest = BeginWrite(count);
+ if (!dest) {
+ return false;
+ }
+
+ memset(dest, byte, count);
+
+ length_ += count;
+ return true;
+}
+
+void QuicDataWriter::WritePadding() {
+ DCHECK_LE(length_, capacity_);
+ if (length_ > capacity_) {
+ return;
+ }
+ memset(buffer_ + length_, 0x00, capacity_ - length_);
+ length_ = capacity_;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_data_writer.h b/chromium/net/quic/core/quic_data_writer.h
new file mode 100644
index 00000000000..8dcc74a0e9f
--- /dev/null
+++ b/chromium/net/quic/core/quic_data_writer.h
@@ -0,0 +1,76 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_DATA_WRITER_H_
+#define NET_QUIC_QUIC_DATA_WRITER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cstddef>
+#include <string>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/int128.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+// This class provides facilities for packing QUIC data.
+//
+// The QuicDataWriter supports appending primitive values (int, string, etc)
+// to a frame instance. The internal memory buffer is exposed as the "data"
+// of the QuicDataWriter.
+class NET_EXPORT_PRIVATE QuicDataWriter {
+ public:
+ // Creates a QuicDataWriter where |buffer| is not owned.
+ QuicDataWriter(size_t size, char* buffer);
+
+ ~QuicDataWriter();
+
+ // Returns the size of the QuicDataWriter's data.
+ size_t length() const { return length_; }
+
+ // Retrieves the buffer from the QuicDataWriter without changing ownership.
+ char* data();
+
+ // Methods for adding to the payload. These values are appended to the end
+ // of the QuicDataWriter payload. Note - binary integers are written in
+ // host byte order (little endian) not network byte order (big endian).
+ bool WriteUInt8(uint8_t value);
+ bool WriteUInt16(uint16_t value);
+ bool WriteUInt32(uint32_t value);
+ bool WriteUInt48(uint64_t value);
+ bool WriteUInt64(uint64_t value);
+ // Write unsigned floating point corresponding to the value. Large values are
+ // clamped to the maximum representable (kUFloat16MaxValue). Values that can
+ // not be represented directly are rounded down.
+ bool WriteUFloat16(uint64_t value);
+ bool WriteStringPiece16(base::StringPiece val);
+ bool WriteBytes(const void* data, size_t data_len);
+ bool WriteRepeatedByte(uint8_t byte, size_t count);
+ // Fills the remaining buffer with null characters.
+ void WritePadding();
+
+ size_t capacity() const { return capacity_; }
+
+ private:
+ // Returns the location that the data should be written at, or nullptr if
+ // there is not enough room. Call EndWrite with the returned offset and the
+ // given length to pad out for the next write.
+ char* BeginWrite(size_t length);
+
+ char* buffer_;
+ size_t capacity_; // Allocation size of payload (or -1 if buffer is const).
+ size_t length_; // Current length of the buffer.
+
+ DISALLOW_COPY_AND_ASSIGN(QuicDataWriter);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_DATA_WRITER_H_
diff --git a/chromium/net/quic/core/quic_data_writer_test.cc b/chromium/net/quic/core/quic_data_writer_test.cc
new file mode 100644
index 00000000000..bb3cfaf5e14
--- /dev/null
+++ b/chromium/net/quic/core/quic_data_writer_test.cc
@@ -0,0 +1,204 @@
+// 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/quic_data_writer.h"
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "net/quic/core/quic_data_reader.h"
+#include "net/test/gtest_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+namespace {
+
+TEST(QuicDataWriterTest, SanityCheckUFloat16Consts) {
+ // Check the arithmetic on the constants - otherwise the values below make
+ // no sense.
+ EXPECT_EQ(30, kUFloat16MaxExponent);
+ EXPECT_EQ(11, kUFloat16MantissaBits);
+ EXPECT_EQ(12, kUFloat16MantissaEffectiveBits);
+ EXPECT_EQ(UINT64_C(0x3FFC0000000), kUFloat16MaxValue);
+}
+
+TEST(QuicDataWriterTest, WriteUFloat16) {
+ struct TestCase {
+ uint64_t decoded;
+ uint16_t encoded;
+ };
+ TestCase test_cases[] = {
+ // Small numbers represent themselves.
+ {0, 0},
+ {1, 1},
+ {2, 2},
+ {3, 3},
+ {4, 4},
+ {5, 5},
+ {6, 6},
+ {7, 7},
+ {15, 15},
+ {31, 31},
+ {42, 42},
+ {123, 123},
+ {1234, 1234},
+ // Check transition through 2^11.
+ {2046, 2046},
+ {2047, 2047},
+ {2048, 2048},
+ {2049, 2049},
+ // Running out of mantissa at 2^12.
+ {4094, 4094},
+ {4095, 4095},
+ {4096, 4096},
+ {4097, 4096},
+ {4098, 4097},
+ {4099, 4097},
+ {4100, 4098},
+ {4101, 4098},
+ // Check transition through 2^13.
+ {8190, 6143},
+ {8191, 6143},
+ {8192, 6144},
+ {8193, 6144},
+ {8194, 6144},
+ {8195, 6144},
+ {8196, 6145},
+ {8197, 6145},
+ // Half-way through the exponents.
+ {0x7FF8000, 0x87FF},
+ {0x7FFFFFF, 0x87FF},
+ {0x8000000, 0x8800},
+ {0xFFF0000, 0x8FFF},
+ {0xFFFFFFF, 0x8FFF},
+ {0x10000000, 0x9000},
+ // Transition into the largest exponent.
+ {0x1FFFFFFFFFE, 0xF7FF},
+ {0x1FFFFFFFFFF, 0xF7FF},
+ {0x20000000000, 0xF800},
+ {0x20000000001, 0xF800},
+ {0x2003FFFFFFE, 0xF800},
+ {0x2003FFFFFFF, 0xF800},
+ {0x20040000000, 0xF801},
+ {0x20040000001, 0xF801},
+ // Transition into the max value and clamping.
+ {0x3FF80000000, 0xFFFE},
+ {0x3FFBFFFFFFF, 0xFFFE},
+ {0x3FFC0000000, 0xFFFF},
+ {0x3FFC0000001, 0xFFFF},
+ {0x3FFFFFFFFFF, 0xFFFF},
+ {0x40000000000, 0xFFFF},
+ {0xFFFFFFFFFFFFFFFF, 0xFFFF},
+ };
+ int num_test_cases = sizeof(test_cases) / sizeof(test_cases[0]);
+
+ for (int i = 0; i < num_test_cases; ++i) {
+ char buffer[2];
+ QuicDataWriter writer(2, buffer);
+ EXPECT_TRUE(writer.WriteUFloat16(test_cases[i].decoded));
+ EXPECT_EQ(test_cases[i].encoded,
+ *reinterpret_cast<uint16_t*>(writer.data()));
+ }
+}
+
+TEST(QuicDataWriterTest, ReadUFloat16) {
+ struct TestCase {
+ uint64_t decoded;
+ uint16_t encoded;
+ };
+ TestCase test_cases[] = {
+ // There are fewer decoding test cases because encoding truncates, and
+ // decoding returns the smallest expansion.
+ // Small numbers represent themselves.
+ {0, 0},
+ {1, 1},
+ {2, 2},
+ {3, 3},
+ {4, 4},
+ {5, 5},
+ {6, 6},
+ {7, 7},
+ {15, 15},
+ {31, 31},
+ {42, 42},
+ {123, 123},
+ {1234, 1234},
+ // Check transition through 2^11.
+ {2046, 2046},
+ {2047, 2047},
+ {2048, 2048},
+ {2049, 2049},
+ // Running out of mantissa at 2^12.
+ {4094, 4094},
+ {4095, 4095},
+ {4096, 4096},
+ {4098, 4097},
+ {4100, 4098},
+ // Check transition through 2^13.
+ {8190, 6143},
+ {8192, 6144},
+ {8196, 6145},
+ // Half-way through the exponents.
+ {0x7FF8000, 0x87FF},
+ {0x8000000, 0x8800},
+ {0xFFF0000, 0x8FFF},
+ {0x10000000, 0x9000},
+ // Transition into the largest exponent.
+ {0x1FFE0000000, 0xF7FF},
+ {0x20000000000, 0xF800},
+ {0x20040000000, 0xF801},
+ // Transition into the max value.
+ {0x3FF80000000, 0xFFFE},
+ {0x3FFC0000000, 0xFFFF},
+ };
+ int num_test_cases = sizeof(test_cases) / sizeof(test_cases[0]);
+
+ for (int i = 0; i < num_test_cases; ++i) {
+ QuicDataReader reader(reinterpret_cast<char*>(&test_cases[i].encoded), 2);
+ uint64_t value;
+ EXPECT_TRUE(reader.ReadUFloat16(&value));
+ EXPECT_EQ(test_cases[i].decoded, value);
+ }
+}
+
+TEST(QuicDataWriterTest, RoundTripUFloat16) {
+ // Just test all 16-bit encoded values. 0 and max already tested above.
+ uint64_t previous_value = 0;
+ for (uint16_t i = 1; i < 0xFFFF; ++i) {
+ // Read the two bytes.
+ QuicDataReader reader(reinterpret_cast<char*>(&i), 2);
+ uint64_t value;
+ // All values must be decodable.
+ EXPECT_TRUE(reader.ReadUFloat16(&value));
+ // Check that small numbers represent themselves
+ if (i < 4097)
+ EXPECT_EQ(i, value);
+ // Check there's monotonic growth.
+ EXPECT_LT(previous_value, value);
+ // Check that precision is within 0.5% away from the denormals.
+ if (i > 2000)
+ EXPECT_GT(previous_value * 1005, value * 1000);
+ // Check we're always within the promised range.
+ EXPECT_LT(value, UINT64_C(0x3FFC0000000));
+ previous_value = value;
+ char buffer[6];
+ QuicDataWriter writer(6, buffer);
+ EXPECT_TRUE(writer.WriteUFloat16(value - 1));
+ EXPECT_TRUE(writer.WriteUFloat16(value));
+ EXPECT_TRUE(writer.WriteUFloat16(value + 1));
+ // Check minimal decoding (previous decoding has previous encoding).
+ EXPECT_EQ(i - 1, *reinterpret_cast<uint16_t*>(writer.data()));
+ // Check roundtrip.
+ EXPECT_EQ(i, *reinterpret_cast<uint16_t*>(writer.data() + 2));
+ // Check next decoding.
+ EXPECT_EQ(i < 4096 ? i + 1 : i,
+ *reinterpret_cast<uint16_t*>(writer.data() + 4));
+ }
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_flags.cc b/chromium/net/quic/core/quic_flags.cc
new file mode 100644
index 00000000000..f53537db090
--- /dev/null
+++ b/chromium/net/quic/core/quic_flags.cc
@@ -0,0 +1,9 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_flags.h"
+
+#define QUIC_FLAG(type, flag, value) type flag = value;
+#include "net/quic/core/quic_flags_list.h"
+#undef QUIC_FLAG
diff --git a/chromium/net/quic/core/quic_flags.h b/chromium/net/quic/core/quic_flags.h
new file mode 100644
index 00000000000..70c9d2e9ad2
--- /dev/null
+++ b/chromium/net/quic/core/quic_flags.h
@@ -0,0 +1,16 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_FLAGS_H_
+#define NET_QUIC_QUIC_FLAGS_H_
+
+#include <stdint.h>
+
+#include "net/base/net_export.h"
+
+#define QUIC_FLAG(type, flag, value) NET_EXPORT_PRIVATE extern type flag;
+#include "net/quic/core/quic_flags_list.h"
+#undef QUIC_FLAG
+
+#endif // NET_QUIC_QUIC_FLAGS_H_
diff --git a/chromium/net/quic/core/quic_flags_list.h b/chromium/net/quic/core/quic_flags_list.h
new file mode 100644
index 00000000000..8cf06c821cc
--- /dev/null
+++ b/chromium/net/quic/core/quic_flags_list.h
@@ -0,0 +1,164 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file intentionally does not have header guards, it's included
+// inside a macro to generate values.
+
+// This file contains the list of QUIC protocol flags.
+
+// If true, QUIC BBR congestion control may be enabled via Finch and/or via QUIC
+// connection options.
+QUIC_FLAG(bool, FLAGS_quic_allow_bbr, false)
+
+// Time period for which a given connection_id should live in the time-wait
+// state.
+QUIC_FLAG(int64_t, FLAGS_quic_time_wait_list_seconds, 200)
+
+// Currently, this number is quite conservative. The max QPS limit for an
+// individual server silo is currently set to 1000 qps, though the actual max
+// that we see in the wild is closer to 450 qps. Regardless, this means that
+// the longest time-wait list we should see is 200 seconds * 1000 qps, 200000.
+// Of course, there are usually many queries per QUIC connection, so we allow a
+// factor of 3 leeway.
+//
+// Maximum number of connections on the time-wait list. A negative value implies
+// no configured limit.
+QUIC_FLAG(int64_t, FLAGS_quic_time_wait_list_max_connections, 600000)
+
+// Enables server-side support for QUIC stateless rejects.
+QUIC_FLAG(bool, FLAGS_enable_quic_stateless_reject_support, true)
+
+// This flag is not in use, just to keep consistency for shared code.
+QUIC_FLAG(bool, FLAGS_quic_always_log_bugs_for_tests, true)
+
+// If true, multipath is enabled for the connection.
+QUIC_FLAG(bool, FLAGS_quic_enable_multipath, false)
+
+// If true, require handshake confirmation for QUIC connections, functionally
+// disabling 0-rtt handshakes.
+// TODO(rtenneti): Enable this flag after CryptoServerTest's are fixed.
+QUIC_FLAG(bool, FLAGS_quic_require_handshake_confirmation, false)
+
+// If true, disable pacing in QUIC.
+QUIC_FLAG(bool, FLAGS_quic_disable_pacing_for_perf_tests, false)
+
+// If true, QUIC connections can do bandwidth resumption with an initial window
+// of < 10 packets.
+QUIC_FLAG(bool, FLAGS_quic_no_lower_bw_resumption_limit, true)
+
+// If true, QUIC public reset packets will have the \"pre-v33\" public header
+// flags.
+QUIC_FLAG(bool, FLAGS_quic_use_old_public_reset_packets, true)
+
+// If true, QUIC will use cheap stateless rejects without creating a full
+// connection.
+QUIC_FLAG(bool, FLAGS_quic_use_cheap_stateless_rejects, true)
+
+// If true, QUIC respect HTTP2 SETTINGS frame rather than always close the
+// connection.
+QUIC_FLAG(bool, FLAGS_quic_respect_http2_settings_frame, true)
+
+// If true, enables QUIC_VERSION_35.
+QUIC_FLAG(bool, FLAGS_quic_enable_version_35, true)
+
+// If true, re-enables QUIC_VERSION_36.
+QUIC_FLAG(bool, FLAGS_quic_enable_version_36_v2, true)
+
+// If true, use async codepaths to invoke ProofSource::GetProof.
+QUIC_FLAG(bool, FLAGS_enable_async_get_proof, false)
+
+// If true, requires handshake confirmations for all QUIC handshakes with
+// versions less than 33.
+QUIC_FLAG(bool, FLAGS_quic_require_handshake_confirmation_pre33, false)
+
+// If true, defer creation of new connection till its CHLO arrives.
+QUIC_FLAG(bool, FLAGS_quic_buffer_packet_till_chlo, true)
+
+// If true, disables QUIC version less than 32.
+QUIC_FLAG(bool, FLAGS_quic_disable_pre_32, true)
+
+// If true, QUIC will enforce the MTU limit for connections that may require a
+// small MTU.
+QUIC_FLAG(bool, FLAGS_quic_enforce_mtu_limit, false)
+
+// Disable MTU probing if MTU probe causes ERR_MSG_TOO_BIG instead of aborting
+// the connection.
+QUIC_FLAG(bool, FLAGS_graceful_emsgsize_on_mtu_probe, true)
+
+// If true, only open limited number of quic sessions per epoll event. Leave the
+// rest to next event. This flag can be turned on only if
+// --quic_buffer_packet_till_chlo is true.
+QUIC_FLAG(bool, FLAGS_quic_limit_num_new_sessions_per_epoll_loop, true)
+
+// If true, lazy allocate and early release memeory used in
+// QuicStreamSequencerBuffer to buffer incoming data.
+QUIC_FLAG(bool, FLAGS_quic_reduce_sequencer_buffer_memory_life_time, true)
+
+// If true, allow server address change if it is because of mapped ipv4 address.
+QUIC_FLAG(bool, FLAGS_quic_allow_server_address_change_for_mapped_ipv4, true)
+
+// If true, disables QUIC version less than 34.
+QUIC_FLAG(bool, FLAGS_quic_disable_pre_34, false)
+
+// When true, decode the packet number from the largest received packet, rather
+// than the most recent.
+QUIC_FLAG(bool, FLAGS_quic_packet_numbers_largest_received, true)
+
+// Only close the connection on the 5th RTO client side when the 5RTO option
+// is enabled.
+QUIC_FLAG(bool, FLAGS_quic_only_5rto_client_side, true)
+
+// If true, QUIC server push will enabled by default.
+QUIC_FLAG(bool, FLAGS_quic_enable_server_push_by_default, false)
+
+// Only inform the QuicSentPacketManager of packets that were sent,
+// not those that we tried to send.
+QUIC_FLAG(bool, FLAGS_quic_only_track_sent_packets, false)
+
+// If true, connection is closed when packet generator is trying to
+// add a frame which alone cannot fit into a packet.
+QUIC_FLAG(bool, FLAGS_quic_close_connection_on_huge_frames, true)
+
+// As the Linux kernel does, limit QUIC's Cubic congestion control to
+// only increase the CWND 1 packet for every two packets acked.
+QUIC_FLAG(bool, FLAGS_quic_limit_cubic_cwnd_increase, true)
+
+// If true, export reject reasons for all rejects, i.e., rejects,
+// stateless rejects and cheap stateless rejects.
+QUIC_FLAG(bool, FLAGS_quic_export_rej_for_all_rejects, true)
+
+// Allow large send deltas to be used as RTT samples.
+QUIC_FLAG(bool, FLAGS_quic_allow_large_send_deltas, true)
+
+// Engage early retransmit anytime the largest acked is greater than
+// or equal to the largest retransmittable packet.
+QUIC_FLAG(bool, FLAGS_quic_largest_sent_retransmittable, true)
+
+// If true, close connection when sequencer buffer enter into unexpected state.
+QUIC_FLAG(bool, FLAGS_quic_stream_sequencer_buffer_debug, true)
+
+// If true, release QuicCryptoStream\'s read buffer when stream are less
+// frequently used.
+QUIC_FLAG(bool, FLAGS_quic_release_crypto_stream_buffer, false)
+
+// Use a more conservative backoff of 2x instead of 1.5x for handshake
+// retransmissions, as well as a larger minimum.
+QUIC_FLAG(bool, FLAGS_quic_conservative_handshake_retransmits, true)
+
+// If true, buffer packets while parsing public headers instead of parsing down
+// if CHLO is already buffered.
+QUIC_FLAG(bool, FLAGS_quic_buffer_packets_after_chlo, false)
+
+// Previously QUIC didn't register a packet as received until it was fully
+// processed, but now that flow control is implemented, it can be received once
+// decrypted.
+QUIC_FLAG(bool, FLAGS_quic_receive_packet_once_decrypted, false)
+
+// If true, v33 QUIC client uses 1 bit to specify 8-byte connection id in
+// public flag.
+QUIC_FLAG(bool, FLAGS_quic_remove_v33_hacks2, false)
+
+// If enabled, fix double call of
+// InsertLocallyClosedStreamsHighestOffset in ResetPromised.
+QUIC_FLAG(bool, FLAGS_quic_bugfix_reset_promised, true)
diff --git a/chromium/net/quic/core/quic_flow_controller.cc b/chromium/net/quic/core/quic_flow_controller.cc
new file mode 100644
index 00000000000..3c556f3488f
--- /dev/null
+++ b/chromium/net/quic/core/quic_flow_controller.cc
@@ -0,0 +1,254 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_flow_controller.h"
+
+#include "base/strings/stringprintf.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+#define ENDPOINT \
+ (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ")
+
+QuicFlowController::QuicFlowController(QuicConnection* connection,
+ QuicStreamId id,
+ Perspective perspective,
+ QuicStreamOffset send_window_offset,
+ QuicStreamOffset receive_window_offset,
+ bool should_auto_tune_receive_window)
+ : connection_(connection),
+ id_(id),
+ perspective_(perspective),
+ bytes_sent_(0),
+ send_window_offset_(send_window_offset),
+ bytes_consumed_(0),
+ highest_received_byte_offset_(0),
+ receive_window_offset_(receive_window_offset),
+ receive_window_size_(receive_window_offset),
+ auto_tune_receive_window_(should_auto_tune_receive_window),
+ last_blocked_send_window_offset_(0),
+ prev_window_update_time_(QuicTime::Zero()) {
+ receive_window_size_limit_ = (id_ == kConnectionLevelId)
+ ? kSessionReceiveWindowLimit
+ : kStreamReceiveWindowLimit;
+
+ DVLOG(1) << ENDPOINT << "Created flow controller for stream " << id_
+ << ", setting initial receive window offset to: "
+ << receive_window_offset_
+ << ", max receive window to: " << receive_window_size_
+ << ", max receive window limit to: " << receive_window_size_limit_
+ << ", setting send window offset to: " << send_window_offset_;
+}
+
+void QuicFlowController::AddBytesConsumed(QuicByteCount bytes_consumed) {
+ bytes_consumed_ += bytes_consumed;
+ DVLOG(1) << ENDPOINT << "Stream " << id_ << " consumed: " << bytes_consumed_;
+
+ MaybeSendWindowUpdate();
+}
+
+bool QuicFlowController::UpdateHighestReceivedOffset(
+ QuicStreamOffset new_offset) {
+ // Only update if offset has increased.
+ if (new_offset <= highest_received_byte_offset_) {
+ return false;
+ }
+
+ DVLOG(1) << ENDPOINT << "Stream " << id_
+ << " highest byte offset increased from: "
+ << highest_received_byte_offset_ << " to " << new_offset;
+ highest_received_byte_offset_ = new_offset;
+ return true;
+}
+
+void QuicFlowController::AddBytesSent(QuicByteCount bytes_sent) {
+ if (bytes_sent_ + bytes_sent > send_window_offset_) {
+ QUIC_BUG << ENDPOINT << "Stream " << id_ << " Trying to send an extra "
+ << bytes_sent << " bytes, when bytes_sent = " << bytes_sent_
+ << ", and send_window_offset_ = " << send_window_offset_;
+ bytes_sent_ = send_window_offset_;
+
+ // This is an error on our side, close the connection as soon as possible.
+ connection_->CloseConnection(
+ QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA,
+ base::StringPrintf(
+ "%llu bytes over send window offset",
+ static_cast<unsigned long long>(send_window_offset_ -
+ (bytes_sent_ + bytes_sent)))
+ .c_str(),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+
+ bytes_sent_ += bytes_sent;
+ DVLOG(1) << ENDPOINT << "Stream " << id_ << " sent: " << bytes_sent_;
+}
+
+bool QuicFlowController::FlowControlViolation() {
+ if (highest_received_byte_offset_ > receive_window_offset_) {
+ DVLOG(1) << ENDPOINT << "Flow control violation on stream " << id_
+ << ", receive window offset: " << receive_window_offset_
+ << ", highest received byte offset: "
+ << highest_received_byte_offset_;
+ return true;
+ }
+ return false;
+}
+
+void QuicFlowController::MaybeIncreaseMaxWindowSize() {
+ // Core of receive window auto tuning. This method should be called before a
+ // WINDOW_UPDATE frame is sent. Ideally, window updates should occur close to
+ // once per RTT. If a window update happens much faster than RTT, it implies
+ // that the flow control window is imposing a bottleneck. To prevent this,
+ // this method will increase the receive window size (subject to a reasonable
+ // upper bound). For simplicity this algorithm is deliberately asymmetric, in
+ // that it may increase window size but never decreases.
+
+ // Keep track of timing between successive window updates.
+ QuicTime now = connection_->clock()->ApproximateNow();
+ QuicTime prev = prev_window_update_time_;
+ prev_window_update_time_ = now;
+ if (!prev.IsInitialized()) {
+ DVLOG(1) << ENDPOINT << "first window update for stream " << id_;
+ return;
+ }
+
+ if (!auto_tune_receive_window_) {
+ return;
+ }
+
+ // Get outbound RTT.
+ QuicTime::Delta rtt =
+ connection_->sent_packet_manager().GetRttStats()->smoothed_rtt();
+ if (rtt.IsZero()) {
+ DVLOG(1) << ENDPOINT << "rtt zero for stream " << id_;
+ return;
+ }
+
+ // Now we can compare timing of window updates with RTT.
+ QuicTime::Delta since_last = now - prev;
+ QuicTime::Delta two_rtt = 2 * rtt;
+
+ if (since_last >= two_rtt) {
+ // If interval between window updates is sufficiently large, there
+ // is no need to increase receive_window_size_.
+ return;
+ }
+
+ QuicByteCount old_window = receive_window_size_;
+ receive_window_size_ *= 2;
+ receive_window_size_ =
+ std::min(receive_window_size_, receive_window_size_limit_);
+
+ if (receive_window_size_ > old_window) {
+ DVLOG(1) << ENDPOINT << "New max window increase for stream " << id_
+ << " after " << since_last.ToMicroseconds() << " us, and RTT is "
+ << rtt.ToMicroseconds()
+ << "us. max wndw: " << receive_window_size_;
+ } else {
+ // TODO(ckrasic) - add a varz to track this (?).
+ DVLOG(1) << ENDPOINT << "Max window at limit for stream " << id_
+ << " after " << since_last.ToMicroseconds() << " us, and RTT is "
+ << rtt.ToMicroseconds()
+ << "us. Limit size: " << receive_window_size_;
+ }
+}
+
+QuicByteCount QuicFlowController::WindowUpdateThreshold() {
+ return receive_window_size_ / 2;
+}
+
+void QuicFlowController::MaybeSendWindowUpdate() {
+ // Send WindowUpdate to increase receive window if
+ // (receive window offset - consumed bytes) < (max window / 2).
+ // This is behaviour copied from SPDY.
+ DCHECK_LE(bytes_consumed_, receive_window_offset_);
+ QuicStreamOffset available_window = receive_window_offset_ - bytes_consumed_;
+ QuicByteCount threshold = WindowUpdateThreshold();
+
+ if (available_window >= threshold) {
+ DVLOG(1) << ENDPOINT << "Not sending WindowUpdate for stream " << id_
+ << ", available window: " << available_window
+ << " >= threshold: " << threshold;
+ return;
+ }
+
+ MaybeIncreaseMaxWindowSize();
+
+ // Update our receive window.
+ receive_window_offset_ += (receive_window_size_ - available_window);
+
+ DVLOG(1) << ENDPOINT << "Sending WindowUpdate frame for stream " << id_
+ << ", consumed bytes: " << bytes_consumed_
+ << ", available window: " << available_window
+ << ", and threshold: " << threshold
+ << ", and receive window size: " << receive_window_size_
+ << ". New receive window offset is: " << receive_window_offset_;
+
+ // Inform the peer of our new receive window.
+ connection_->SendWindowUpdate(id_, receive_window_offset_);
+}
+
+void QuicFlowController::MaybeSendBlocked() {
+ if (SendWindowSize() == 0 &&
+ last_blocked_send_window_offset_ < send_window_offset_) {
+ DVLOG(1) << ENDPOINT << "Stream " << id_ << " is flow control blocked. "
+ << "Send window: " << SendWindowSize()
+ << ", bytes sent: " << bytes_sent_
+ << ", send limit: " << send_window_offset_;
+ // The entire send_window has been consumed, we are now flow control
+ // blocked.
+ connection_->SendBlocked(id_);
+
+ // Keep track of when we last sent a BLOCKED frame so that we only send one
+ // at a given send offset.
+ last_blocked_send_window_offset_ = send_window_offset_;
+ }
+}
+
+bool QuicFlowController::UpdateSendWindowOffset(
+ QuicStreamOffset new_send_window_offset) {
+ // Only update if send window has increased.
+ if (new_send_window_offset <= send_window_offset_) {
+ return false;
+ }
+
+ DVLOG(1) << ENDPOINT << "UpdateSendWindowOffset for stream " << id_
+ << " with new offset " << new_send_window_offset
+ << " current offset: " << send_window_offset_
+ << " bytes_sent: " << bytes_sent_;
+
+ const bool blocked = IsBlocked();
+ send_window_offset_ = new_send_window_offset;
+ return blocked;
+}
+
+bool QuicFlowController::IsBlocked() const {
+ return SendWindowSize() == 0;
+}
+
+uint64_t QuicFlowController::SendWindowSize() const {
+ if (bytes_sent_ > send_window_offset_) {
+ return 0;
+ }
+ return send_window_offset_ - bytes_sent_;
+}
+
+void QuicFlowController::UpdateReceiveWindowSize(QuicStreamOffset size) {
+ DVLOG(1) << ENDPOINT << "UpdateReceiveWindowSize for stream " << id_ << ": "
+ << size;
+ if (receive_window_size_ != receive_window_offset_) {
+ QUIC_BUG << "receive_window_size_:" << receive_window_size_
+ << " != receive_window_offset:" << receive_window_offset_;
+ return;
+ }
+ receive_window_size_ = size;
+ receive_window_offset_ = size;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_flow_controller.h b/chromium/net/quic/core/quic_flow_controller.h
new file mode 100644
index 00000000000..238b9b49c3b
--- /dev/null
+++ b/chromium/net/quic/core/quic_flow_controller.h
@@ -0,0 +1,171 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_FLOW_CONTROLLER_H_
+#define NET_QUIC_QUIC_FLOW_CONTROLLER_H_
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+namespace test {
+class QuicFlowControllerPeer;
+} // namespace test
+
+class QuicConnection;
+
+const QuicStreamId kConnectionLevelId = 0;
+
+// QuicFlowController allows a QUIC stream or connection to perform flow
+// control. The stream/connection owns a QuicFlowController which keeps track of
+// bytes sent/received, can tell the owner if it is flow control blocked, and
+// can send WINDOW_UPDATE or BLOCKED frames when needed.
+class NET_EXPORT_PRIVATE QuicFlowController {
+ public:
+ QuicFlowController(QuicConnection* connection,
+ QuicStreamId id,
+ Perspective perspective,
+ QuicStreamOffset send_window_offset,
+ QuicStreamOffset receive_window_offset,
+ bool should_auto_tune_receive_window);
+
+ ~QuicFlowController() {}
+
+ // Called when we see a new highest received byte offset from the peer, either
+ // via a data frame or a RST.
+ // Returns true if this call changes highest_received_byte_offset_, and false
+ // in the case where |new_offset| is <= highest_received_byte_offset_.
+ bool UpdateHighestReceivedOffset(QuicStreamOffset new_offset);
+
+ // Called when bytes received from the peer are consumed locally. This may
+ // trigger the sending of a WINDOW_UPDATE frame using |connection|.
+ void AddBytesConsumed(QuicByteCount bytes_consumed);
+
+ // Called when bytes are sent to the peer.
+ void AddBytesSent(QuicByteCount bytes_sent);
+
+ // Set a new send window offset.
+ // Returns true if this increases send_window_offset_ and is now blocked.
+ bool UpdateSendWindowOffset(QuicStreamOffset new_send_window_offset);
+
+ // Returns the current available send window.
+ QuicByteCount SendWindowSize() const;
+
+ // Send a BLOCKED frame if appropriate.
+ void MaybeSendBlocked();
+
+ // Returns true if flow control send limits have been reached.
+ bool IsBlocked() const;
+
+ // Returns true if flow control receive limits have been violated by the peer.
+ bool FlowControlViolation();
+
+ QuicByteCount bytes_consumed() const { return bytes_consumed_; }
+
+ QuicStreamOffset highest_received_byte_offset() const {
+ return highest_received_byte_offset_;
+ }
+
+ void set_receive_window_size_limit(QuicByteCount receive_window_size_limit) {
+ DCHECK_GE(receive_window_size_limit, receive_window_size_limit_);
+ receive_window_size_limit_ = receive_window_size_limit;
+ }
+
+ void set_auto_tune_receive_window(bool enable) {
+ auto_tune_receive_window_ = enable;
+ }
+
+ // Should only be called before any data is received.
+ void UpdateReceiveWindowSize(QuicStreamOffset size);
+
+ bool auto_tune_receive_window() { return auto_tune_receive_window_; }
+
+ private:
+ friend class test::QuicFlowControllerPeer;
+
+ // Send a WINDOW_UPDATE frame if appropriate.
+ void MaybeSendWindowUpdate();
+
+ // Auto-tune the max receive window size.
+ void MaybeIncreaseMaxWindowSize();
+
+ // The parent connection, used to send connection close on flow control
+ // violation, and WINDOW_UPDATE and BLOCKED frames when appropriate.
+ // Not owned.
+ QuicConnection* connection_;
+
+ // ID of stream this flow controller belongs to. This can be 0 if this is a
+ // connection level flow controller.
+ QuicStreamId id_;
+
+ // Tracks if this is owned by a server or a client.
+ Perspective perspective_;
+
+ // Tracks number of bytes sent to the peer.
+ QuicByteCount bytes_sent_;
+
+ // The absolute offset in the outgoing byte stream. If this offset is reached
+ // then we become flow control blocked until we receive a WINDOW_UPDATE.
+ QuicStreamOffset send_window_offset_;
+
+ // Overview of receive flow controller.
+ //
+ // 0=...===1=======2-------3 ...... FIN
+ // |<--- <= 4 --->|
+ //
+
+ // 1) bytes_consumed_ - moves forward when data is read out of the
+ // stream.
+ //
+ // 2) highest_received_byte_offset_ - moves when data is received
+ // from the peer.
+ //
+ // 3) receive_window_offset_ - moves when WINDOW_UPDATE is sent.
+ //
+ // 4) receive_window_size_ - maximum allowed unread data (3 - 1).
+ // This value may be increased by auto-tuning.
+ //
+ // 5) receive_window_size_limit_ - limit on receive_window_size_;
+ // auto-tuning will not increase window size beyond this limit.
+
+ // Track number of bytes received from the peer, which have been consumed
+ // locally.
+ QuicByteCount bytes_consumed_;
+
+ // The highest byte offset we have seen from the peer. This could be the
+ // highest offset in a data frame, or a final value in a RST.
+ QuicStreamOffset highest_received_byte_offset_;
+
+ // The absolute offset in the incoming byte stream. The peer should never send
+ // us bytes which are beyond this offset.
+ QuicStreamOffset receive_window_offset_;
+
+ // Largest size the receive window can grow to.
+ QuicByteCount receive_window_size_;
+
+ // Upper limit on receive_window_size_;
+ QuicByteCount receive_window_size_limit_;
+
+ // Used to dynamically enable receive window auto-tuning.
+ bool auto_tune_receive_window_;
+
+ // Send window update when receive window size drops below this.
+ QuicByteCount WindowUpdateThreshold();
+
+ // Keep track of the last time we sent a BLOCKED frame. We should only send
+ // another when the number of bytes we have sent has changed.
+ QuicStreamOffset last_blocked_send_window_offset_;
+
+ // Keep time of the last time a window update was sent. We use this
+ // as part of the receive window auto tuning.
+ QuicTime prev_window_update_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicFlowController);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_FLOW_CONTROLLER_H_
diff --git a/chromium/net/quic/core/quic_flow_controller_test.cc b/chromium/net/quic/core/quic_flow_controller_test.cc
new file mode 100644
index 00000000000..5b7981f1858
--- /dev/null
+++ b/chromium/net/quic/core/quic_flow_controller_test.cc
@@ -0,0 +1,376 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_flow_controller.h"
+
+#include <memory>
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_flow_controller_peer.h"
+#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::_;
+
+namespace net {
+namespace test {
+
+// Receive window auto-tuning uses RTT in its logic.
+const int64_t kRtt = 100;
+
+class QuicFlowControllerTest : public ::testing::Test {
+ public:
+ QuicFlowControllerTest()
+ : stream_id_(1234),
+ send_window_(kInitialSessionFlowControlWindowForTest),
+ receive_window_(kInitialSessionFlowControlWindowForTest),
+ connection_(&helper_, &alarm_factory_, Perspective::IS_CLIENT) {}
+
+ void Initialize() {
+ flow_controller_.reset(
+ new QuicFlowController(&connection_, stream_id_, Perspective::IS_CLIENT,
+ send_window_, receive_window_, false));
+ }
+
+ protected:
+ QuicStreamId stream_id_;
+ QuicByteCount send_window_;
+ QuicByteCount receive_window_;
+ std::unique_ptr<QuicFlowController> flow_controller_;
+ MockQuicConnectionHelper helper_;
+ MockAlarmFactory alarm_factory_;
+ MockQuicConnection connection_;
+};
+
+TEST_F(QuicFlowControllerTest, SendingBytes) {
+ Initialize();
+
+ EXPECT_FALSE(flow_controller_->IsBlocked());
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(send_window_, flow_controller_->SendWindowSize());
+
+ // Send some bytes, but not enough to block.
+ flow_controller_->AddBytesSent(send_window_ / 2);
+ EXPECT_FALSE(flow_controller_->IsBlocked());
+ EXPECT_EQ(send_window_ / 2, flow_controller_->SendWindowSize());
+
+ // Send enough bytes to block.
+ flow_controller_->AddBytesSent(send_window_ / 2);
+ EXPECT_TRUE(flow_controller_->IsBlocked());
+ EXPECT_EQ(0u, flow_controller_->SendWindowSize());
+
+ // BLOCKED frame should get sent.
+ EXPECT_CALL(connection_, SendBlocked(stream_id_)).Times(1);
+ flow_controller_->MaybeSendBlocked();
+
+ // Update the send window, and verify this has unblocked.
+ EXPECT_TRUE(flow_controller_->UpdateSendWindowOffset(2 * send_window_));
+ EXPECT_FALSE(flow_controller_->IsBlocked());
+ EXPECT_EQ(send_window_, flow_controller_->SendWindowSize());
+
+ // Updating with a smaller offset doesn't change anything.
+ EXPECT_FALSE(flow_controller_->UpdateSendWindowOffset(send_window_ / 10));
+ EXPECT_EQ(send_window_, flow_controller_->SendWindowSize());
+
+ // Try to send more bytes, violating flow control.
+ EXPECT_CALL(connection_,
+ CloseConnection(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA, _, _));
+ EXPECT_QUIC_BUG(
+ flow_controller_->AddBytesSent(send_window_ * 10),
+ base::StringPrintf("Trying to send an extra %" PRIu64 " bytes",
+ send_window_ * 10));
+ EXPECT_TRUE(flow_controller_->IsBlocked());
+ EXPECT_EQ(0u, flow_controller_->SendWindowSize());
+}
+
+TEST_F(QuicFlowControllerTest, ReceivingBytes) {
+ Initialize();
+
+ EXPECT_FALSE(flow_controller_->IsBlocked());
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ // Receive some bytes, updating highest received offset, but not enough to
+ // fill flow control receive window.
+ EXPECT_TRUE(
+ flow_controller_->UpdateHighestReceivedOffset(1 + receive_window_ / 2));
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ((receive_window_ / 2) - 1,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ // Consume enough bytes to send a WINDOW_UPDATE frame.
+ EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(1);
+
+ flow_controller_->AddBytesConsumed(1 + receive_window_ / 2);
+
+ // Result is that once again we have a fully open receive window.
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+}
+
+TEST_F(QuicFlowControllerTest, OnlySendBlockedFrameOncePerOffset) {
+ Initialize();
+
+ // Test that we don't send duplicate BLOCKED frames. We should only send one
+ // BLOCKED frame at a given send window offset.
+ EXPECT_FALSE(flow_controller_->IsBlocked());
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(send_window_, flow_controller_->SendWindowSize());
+
+ // Send enough bytes to block.
+ flow_controller_->AddBytesSent(send_window_);
+ EXPECT_TRUE(flow_controller_->IsBlocked());
+ EXPECT_EQ(0u, flow_controller_->SendWindowSize());
+
+ // Expect that 2 BLOCKED frames should get sent in total.
+ EXPECT_CALL(connection_, SendBlocked(stream_id_)).Times(2);
+
+ // BLOCKED frame should get sent.
+ flow_controller_->MaybeSendBlocked();
+
+ // BLOCKED frame should not get sent again until our send offset changes.
+ flow_controller_->MaybeSendBlocked();
+ flow_controller_->MaybeSendBlocked();
+ flow_controller_->MaybeSendBlocked();
+ flow_controller_->MaybeSendBlocked();
+ flow_controller_->MaybeSendBlocked();
+
+ // Update the send window, then send enough bytes to block again.
+ EXPECT_TRUE(flow_controller_->UpdateSendWindowOffset(2 * send_window_));
+ EXPECT_FALSE(flow_controller_->IsBlocked());
+ EXPECT_EQ(send_window_, flow_controller_->SendWindowSize());
+ flow_controller_->AddBytesSent(send_window_);
+ EXPECT_TRUE(flow_controller_->IsBlocked());
+ EXPECT_EQ(0u, flow_controller_->SendWindowSize());
+
+ // BLOCKED frame should get sent as send offset has changed.
+ flow_controller_->MaybeSendBlocked();
+}
+
+TEST_F(QuicFlowControllerTest, ReceivingBytesFastIncreasesFlowWindow) {
+ // This test will generate two WINDOW_UPDATE frames.
+ EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
+
+ Initialize();
+ flow_controller_->set_auto_tune_receive_window(true);
+
+ // Make sure clock is inititialized.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+
+ QuicSentPacketManagerInterface* manager =
+ QuicConnectionPeer::GetSentPacketManager(&connection_, kDefaultPathId);
+
+ RttStats* rtt_stats = const_cast<RttStats*>(manager->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+
+ EXPECT_FALSE(flow_controller_->IsBlocked());
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ QuicByteCount threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+ QuicStreamOffset receive_offset = threshold + 1;
+ // Receive some bytes, updating highest received offset, but not enough to
+ // fill flow control receive window.
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ // Consume enough bytes to send a WINDOW_UPDATE frame.
+ flow_controller_->AddBytesConsumed(threshold + 1);
+ // Result is that once again we have a fully open receive window.
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ // Move time forward, but by less than two RTTs. Then receive and consume
+ // some more, forcing a second WINDOW_UPDATE with an increased max window
+ // size.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt - 1));
+ receive_offset += threshold + 1;
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+ flow_controller_->AddBytesConsumed(threshold + 1);
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ QuicByteCount new_threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+ EXPECT_GT(new_threshold, threshold);
+}
+
+TEST_F(QuicFlowControllerTest, ReceivingBytesFastNoAutoTune) {
+ // This test will generate two WINDOW_UPDATE frames.
+ EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
+
+ Initialize();
+ flow_controller_->set_auto_tune_receive_window(false);
+
+ // Make sure clock is inititialized.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+
+ QuicSentPacketManagerInterface* manager =
+ QuicConnectionPeer::GetSentPacketManager(&connection_, kDefaultPathId);
+
+ RttStats* rtt_stats = const_cast<RttStats*>(manager->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+
+ EXPECT_FALSE(flow_controller_->IsBlocked());
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ QuicByteCount threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+ QuicStreamOffset receive_offset = threshold + 1;
+ // Receive some bytes, updating highest received offset, but not enough to
+ // fill flow control receive window.
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ // Consume enough bytes to send a WINDOW_UPDATE frame.
+ flow_controller_->AddBytesConsumed(threshold + 1);
+ // Result is that once again we have a fully open receive window.
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ // Move time forward, but by less than two RTTs. Then receive and consume
+ // some more, forcing a second WINDOW_UPDATE with an increased max window
+ // size.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt - 1));
+ receive_offset += threshold + 1;
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+ flow_controller_->AddBytesConsumed(threshold + 1);
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ QuicByteCount new_threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+ EXPECT_EQ(new_threshold, threshold);
+}
+
+TEST_F(QuicFlowControllerTest, ReceivingBytesNormalStableFlowWindow) {
+ // This test will generate two WINDOW_UPDATE frames.
+ EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
+
+ Initialize();
+ flow_controller_->set_auto_tune_receive_window(true);
+
+ // Make sure clock is inititialized.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+
+ QuicSentPacketManagerInterface* manager =
+ QuicConnectionPeer::GetSentPacketManager(&connection_, kDefaultPathId);
+ RttStats* rtt_stats = const_cast<RttStats*>(manager->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+
+ EXPECT_FALSE(flow_controller_->IsBlocked());
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ QuicByteCount threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+ QuicStreamOffset receive_offset = threshold + 1;
+ // Receive some bytes, updating highest received offset, but not enough to
+ // fill flow control receive window.
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ flow_controller_->AddBytesConsumed(threshold + 1);
+
+ // Result is that once again we have a fully open receive window.
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ // Move time forward, but by more than two RTTs. Then receive and consume
+ // some more, forcing a second WINDOW_UPDATE with unchanged max window size.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt + 1));
+
+ receive_offset += threshold + 1;
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+
+ flow_controller_->AddBytesConsumed(threshold + 1);
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+
+ QuicByteCount new_threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+ EXPECT_EQ(new_threshold, threshold);
+}
+
+TEST_F(QuicFlowControllerTest, ReceivingBytesNormalNoAutoTune) {
+ // This test will generate two WINDOW_UPDATE frames.
+ EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
+
+ Initialize();
+ flow_controller_->set_auto_tune_receive_window(false);
+
+ // Make sure clock is inititialized.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+
+ QuicSentPacketManagerInterface* manager =
+ QuicConnectionPeer::GetSentPacketManager(&connection_, kDefaultPathId);
+ RttStats* rtt_stats = const_cast<RttStats*>(manager->GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+
+ EXPECT_FALSE(flow_controller_->IsBlocked());
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ QuicByteCount threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+ QuicStreamOffset receive_offset = threshold + 1;
+ // Receive some bytes, updating highest received offset, but not enough to
+ // fill flow control receive window.
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ flow_controller_->AddBytesConsumed(threshold + 1);
+
+ // Result is that once again we have a fully open receive window.
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+ EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+ // Move time forward, but by more than two RTTs. Then receive and consume
+ // some more, forcing a second WINDOW_UPDATE with unchanged max window size.
+ connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt + 1));
+
+ receive_offset += threshold + 1;
+ EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+
+ flow_controller_->AddBytesConsumed(threshold + 1);
+ EXPECT_FALSE(flow_controller_->FlowControlViolation());
+
+ QuicByteCount new_threshold =
+ QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+ EXPECT_EQ(new_threshold, threshold);
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_frame_list.cc b/chromium/net/quic/core/quic_frame_list.cc
new file mode 100644
index 00000000000..f4890f14e7e
--- /dev/null
+++ b/chromium/net/quic/core/quic_frame_list.cc
@@ -0,0 +1,254 @@
+// 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.
+
+#include "net/quic/core/quic_frame_list.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+
+using std::list;
+using std::string;
+
+namespace net {
+
+QuicFrameList::FrameData::FrameData(QuicStreamOffset offset,
+ string segment,
+ const QuicTime timestamp)
+ : offset(offset), segment(segment), timestamp(timestamp) {}
+
+QuicFrameList::QuicFrameList() {}
+
+QuicFrameList::~QuicFrameList() {
+ Clear();
+}
+
+void QuicFrameList::Clear() {
+ frame_list_.clear();
+ num_bytes_buffered_ = 0;
+}
+
+bool QuicFrameList::Empty() const {
+ return frame_list_.empty();
+}
+
+QuicErrorCode QuicFrameList::OnStreamData(QuicStreamOffset offset,
+ base::StringPiece data,
+ QuicTime timestamp,
+ size_t* const bytes_buffered) {
+ *bytes_buffered = 0;
+ const size_t data_len = data.size();
+ auto insertion_point = FindInsertionPoint(offset, data_len);
+ if (IsDuplicate(offset, data_len, insertion_point)) {
+ return QUIC_NO_ERROR;
+ }
+
+ if (FrameOverlapsBufferedData(offset, data_len, insertion_point)) {
+ return QUIC_INVALID_STREAM_DATA;
+ }
+
+ DVLOG(1) << "Buffering stream data at offset " << offset;
+ // Inserting an empty string and then copying to avoid the extra copy.
+ insertion_point =
+ frame_list_.insert(insertion_point, FrameData(offset, "", timestamp));
+ data.CopyToString(&insertion_point->segment);
+ *bytes_buffered = data_len;
+ num_bytes_buffered_ += data_len;
+ return QUIC_NO_ERROR;
+}
+
+// Finds the place the frame should be inserted. If an identical frame is
+// present, stops on the identical frame.
+list<QuicFrameList::FrameData>::iterator QuicFrameList::FindInsertionPoint(
+ QuicStreamOffset offset,
+ size_t len) {
+ if (frame_list_.empty()) {
+ return frame_list_.begin();
+ }
+ // If it's after all buffered_frames, return the end.
+ if (offset >=
+ (frame_list_.rbegin()->offset + frame_list_.rbegin()->segment.length())) {
+ return frame_list_.end();
+ }
+ auto iter = frame_list_.begin();
+ // Only advance the iterator if the data begins after the already received
+ // frame. If the new frame overlaps with an existing frame, the iterator will
+ // still point to the frame it overlaps with.
+ while (iter != frame_list_.end() &&
+ offset >= iter->offset + iter->segment.length()) {
+ ++iter;
+ }
+ return iter;
+}
+
+// Returns true if |frame| contains data which overlaps buffered data
+// (indicating an invalid stream frame has been received).
+bool QuicFrameList::FrameOverlapsBufferedData(
+ QuicStreamOffset offset,
+ size_t data_len,
+ list<FrameData>::const_iterator insertion_point) const {
+ if (frame_list_.empty() || insertion_point == frame_list_.end()) {
+ return false;
+ }
+ // If there is a buffered frame with a higher starting offset, then check to
+ // see if the new frame overlaps the beginning of the higher frame.
+ if (offset < insertion_point->offset &&
+ offset + data_len > insertion_point->offset) {
+ DVLOG(1) << "New frame overlaps next frame: " << offset << " + " << data_len
+ << " > " << insertion_point->offset;
+ return true;
+ }
+ // If there is a buffered frame with a lower starting offset, then check to
+ // see if the buffered frame runs into the new frame.
+ if (offset >= insertion_point->offset &&
+ offset < insertion_point->offset + insertion_point->segment.length()) {
+ DVLOG(1) << "Preceeding frame overlaps new frame: "
+ << insertion_point->offset << " + "
+ << insertion_point->segment.length() << " > " << offset;
+ return true;
+ }
+
+ return false;
+}
+
+// Returns true if the sequencer has received this frame before.
+bool QuicFrameList::IsDuplicate(
+ QuicStreamOffset offset,
+ size_t data_len,
+ list<FrameData>::const_iterator insertion_point) const {
+ // A frame is duplicate if the frame offset is smaller than the bytes consumed
+ // or identical to an already received frame.
+ return offset < total_bytes_read_ || (insertion_point != frame_list_.end() &&
+ offset == insertion_point->offset);
+}
+
+int QuicFrameList::GetReadableRegions(struct iovec* iov, int iov_len) const {
+ list<FrameData>::const_iterator it = frame_list_.begin();
+ int index = 0;
+ QuicStreamOffset offset = total_bytes_read_;
+ while (it != frame_list_.end() && index < iov_len) {
+ if (it->offset != offset) {
+ return index;
+ }
+
+ iov[index].iov_base =
+ static_cast<void*>(const_cast<char*>(it->segment.data()));
+ iov[index].iov_len = it->segment.size();
+ offset += it->segment.size();
+
+ ++index;
+ ++it;
+ }
+ return index;
+}
+
+bool QuicFrameList::GetReadableRegion(iovec* iov, QuicTime* timestamp) const {
+ list<FrameData>::const_iterator it = frame_list_.begin();
+ if (it == frame_list_.end() || it->offset != total_bytes_read_) {
+ return false;
+ }
+ iov->iov_base = static_cast<void*>(const_cast<char*>(it->segment.data()));
+ iov->iov_len = it->segment.size();
+ *timestamp = it->timestamp;
+ return true;
+}
+
+bool QuicFrameList::MarkConsumed(size_t bytes_used) {
+ size_t end_offset = total_bytes_read_ + bytes_used;
+ while (!frame_list_.empty() && end_offset != total_bytes_read_) {
+ list<FrameData>::iterator it = frame_list_.begin();
+ if (it->offset != total_bytes_read_) {
+ return false;
+ }
+
+ if (it->offset + it->segment.length() <= end_offset) {
+ total_bytes_read_ += it->segment.length();
+ num_bytes_buffered_ -= it->segment.length();
+ // This chunk is entirely consumed.
+ frame_list_.erase(it);
+ continue;
+ }
+
+ // Partially consume this frame.
+ size_t delta = end_offset - it->offset;
+ total_bytes_read_ += delta;
+ num_bytes_buffered_ -= delta;
+ string new_data = it->segment.substr(delta);
+ const QuicTime timestamp = it->timestamp;
+ frame_list_.erase(it);
+ frame_list_.push_front(FrameData(total_bytes_read_, new_data, timestamp));
+ break;
+ }
+ return true;
+}
+
+size_t QuicFrameList::Readv(const struct iovec* iov, size_t iov_len) {
+ list<FrameData>::iterator it = frame_list_.begin();
+ size_t iov_index = 0;
+ size_t iov_offset = 0;
+ size_t frame_offset = 0;
+ QuicStreamOffset initial_bytes_consumed = total_bytes_read_;
+
+ while (iov_index < iov_len && it != frame_list_.end() &&
+ it->offset == total_bytes_read_) {
+ int bytes_to_read = std::min(iov[iov_index].iov_len - iov_offset,
+ it->segment.size() - frame_offset);
+
+ char* iov_ptr = static_cast<char*>(iov[iov_index].iov_base) + iov_offset;
+ memcpy(iov_ptr, it->segment.data() + frame_offset, bytes_to_read);
+ frame_offset += bytes_to_read;
+ iov_offset += bytes_to_read;
+
+ if (iov[iov_index].iov_len == iov_offset) {
+ // We've filled this buffer.
+ iov_offset = 0;
+ ++iov_index;
+ }
+ if (it->segment.size() == frame_offset) {
+ // We've copied this whole frame
+ total_bytes_read_ += it->segment.size();
+ num_bytes_buffered_ -= it->segment.size();
+ frame_list_.erase(it);
+ it = frame_list_.begin();
+ frame_offset = 0;
+ }
+ }
+ // Done copying. If there is a partial frame, update it.
+ if (frame_offset != 0) {
+ frame_list_.push_front(FrameData(it->offset + frame_offset,
+ it->segment.substr(frame_offset),
+ it->timestamp));
+ frame_list_.erase(it);
+ total_bytes_read_ += frame_offset;
+ num_bytes_buffered_ -= frame_offset;
+ }
+ return total_bytes_read_ - initial_bytes_consumed;
+}
+
+size_t QuicFrameList::FlushBufferedFrames() {
+ QuicStreamOffset initial_bytes_consumed = total_bytes_read_;
+ if (!frame_list_.empty()) {
+ // Consume all of the bytes up to the last byte yet seen, including the
+ // ones that haven't arrived yet.
+ auto it = frame_list_.back();
+ total_bytes_read_ = it.offset + it.segment.length();
+ frame_list_.clear();
+ }
+ return total_bytes_read_ - initial_bytes_consumed;
+}
+
+bool QuicFrameList::HasBytesToRead() const {
+ return !frame_list_.empty() &&
+ frame_list_.begin()->offset == total_bytes_read_;
+}
+
+QuicStreamOffset QuicFrameList::BytesConsumed() const {
+ return total_bytes_read_;
+}
+
+size_t QuicFrameList::BytesBuffered() const {
+ return num_bytes_buffered_;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_frame_list.h b/chromium/net/quic/core/quic_frame_list.h
new file mode 100644
index 00000000000..2e95455d2d7
--- /dev/null
+++ b/chromium/net/quic/core/quic_frame_list.h
@@ -0,0 +1,82 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_FRAME_LIST_H_
+#define NET_QUIC_QUIC_FRAME_LIST_H_
+
+#include <stddef.h>
+#include <list>
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_stream_sequencer_buffer_interface.h"
+
+namespace net {
+
+namespace test {
+class QuicStreamSequencerPeer;
+}
+
+class NET_EXPORT_PRIVATE QuicFrameList
+ : public QuicStreamSequencerBufferInterface {
+ public:
+ // A contiguous segment received by a QUIC stream.
+ struct FrameData {
+ FrameData(QuicStreamOffset offset,
+ std::string segment,
+ const QuicTime timestamp);
+
+ const QuicStreamOffset offset;
+ std::string segment;
+ const QuicTime timestamp;
+ };
+
+ QuicFrameList();
+
+ ~QuicFrameList() override;
+
+ // QuicStreamSequencerBufferInterface implementation
+ void Clear() override;
+ bool Empty() const override;
+ QuicErrorCode OnStreamData(QuicStreamOffset offset,
+ base::StringPiece data,
+ QuicTime timestamp,
+ size_t* bytes_buffered) override;
+ size_t Readv(const struct iovec* iov, size_t iov_len) override;
+ int GetReadableRegions(struct iovec* iov, int iov_len) const override;
+ bool GetReadableRegion(iovec* iov, QuicTime* timestamp) const override;
+ bool MarkConsumed(size_t bytes_used) override;
+ size_t FlushBufferedFrames() override;
+ bool HasBytesToRead() const override;
+ QuicStreamOffset BytesConsumed() const override;
+ size_t BytesBuffered() const override;
+
+ private:
+ friend class test::QuicStreamSequencerPeer;
+
+ std::list<FrameData>::iterator FindInsertionPoint(QuicStreamOffset offset,
+ size_t len);
+
+ bool FrameOverlapsBufferedData(
+ QuicStreamOffset offset,
+ size_t data_len,
+ std::list<FrameData>::const_iterator insertion_point) const;
+
+ bool IsDuplicate(QuicStreamOffset offset,
+ size_t data_len,
+ std::list<FrameData>::const_iterator insertion_point) const;
+
+ std::list<FrameData> frame_list_;
+
+ // Number of bytes in buffer.
+ size_t num_bytes_buffered_ = 0;
+
+ QuicStreamOffset total_bytes_read_ = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_FRAME_LIST_H_
diff --git a/chromium/net/quic/core/quic_framer.cc b/chromium/net/quic/core/quic_framer.cc
new file mode 100644
index 00000000000..bec9020c167
--- /dev/null
+++ b/chromium/net/quic/core/quic_framer.cc
@@ -0,0 +1,2650 @@
+// 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/quic_framer.h"
+
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "net/quic/core/crypto/crypto_framer.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_data_reader.h"
+#include "net/quic/core/quic_data_writer.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_socket_address_coder.h"
+#include "net/quic/core/quic_utils.h"
+
+using base::ContainsKey;
+using base::StringPiece;
+using std::map;
+using std::max;
+using std::min;
+using std::numeric_limits;
+using std::string;
+using std::vector;
+#define PREDICT_FALSE(x) (x)
+
+namespace net {
+
+namespace {
+
+// Mask to select the lowest 48 bits of a packet number.
+const QuicPacketNumber k6ByteSequenceNumberMask = UINT64_C(0x0000FFFFFFFFFFFF);
+const QuicPacketNumber k4ByteSequenceNumberMask = UINT64_C(0x00000000FFFFFFFF);
+const QuicPacketNumber k2ByteSequenceNumberMask = UINT64_C(0x000000000000FFFF);
+const QuicPacketNumber k1ByteSequenceNumberMask = UINT64_C(0x00000000000000FF);
+
+// Number of bits the packet number length bits are shifted from the right
+// edge of the public header.
+const uint8_t kPublicHeaderSequenceNumberShift = 4;
+
+// New Frame Types, QUIC v. >= 10:
+// There are two interpretations for the Frame Type byte in the QUIC protocol,
+// resulting in two Frame Types: Special Frame Types and Regular Frame Types.
+//
+// Regular Frame Types use the Frame Type byte simply. Currently defined
+// Regular Frame Types are:
+// Padding : 0b 00000000 (0x00)
+// ResetStream : 0b 00000001 (0x01)
+// ConnectionClose : 0b 00000010 (0x02)
+// GoAway : 0b 00000011 (0x03)
+// WindowUpdate : 0b 00000100 (0x04)
+// Blocked : 0b 00000101 (0x05)
+//
+// Special Frame Types encode both a Frame Type and corresponding flags
+// all in the Frame Type byte. Currently defined Special Frame Types are:
+// Stream : 0b 1xxxxxxx
+// Ack : 0b 01xxxxxx
+//
+// Semantics of the flag bits above (the x bits) depends on the frame type.
+
+// Masks to determine if the frame type is a special use
+// and for specific special frame types.
+const uint8_t kQuicFrameTypeSpecialMask = 0xE0; // 0b 11100000
+const uint8_t kQuicFrameTypeStreamMask = 0x80;
+const uint8_t kQuicFrameTypeAckMask = 0x40;
+
+// Stream frame relative shifts and masks for interpreting the stream flags.
+// StreamID may be 1, 2, 3, or 4 bytes.
+const uint8_t kQuicStreamIdShift = 2;
+const uint8_t kQuicStreamIDLengthMask = 0x03;
+
+// Offset may be 0, 2, 3, 4, 5, 6, 7, 8 bytes.
+const uint8_t kQuicStreamOffsetShift = 3;
+const uint8_t kQuicStreamOffsetMask = 0x07;
+
+// Data length may be 0 or 2 bytes.
+const uint8_t kQuicStreamDataLengthShift = 1;
+const uint8_t kQuicStreamDataLengthMask = 0x01;
+
+// Fin bit may be set or not.
+const uint8_t kQuicStreamFinShift = 1;
+const uint8_t kQuicStreamFinMask = 0x01;
+
+// packet number size shift used in AckFrames.
+const uint8_t kQuicSequenceNumberLengthShift = 2;
+
+// Acks may be truncated.
+const uint8_t kQuicAckTruncatedShift = 1;
+const uint8_t kQuicAckTruncatedMask = 0x01;
+
+// Acks may not have any nacks.
+const uint8_t kQuicHasNacksMask = 0x01;
+// Acks may have only one ack block.
+const uint8_t kQuicHasMultipleAckBlocksMask = 0x01;
+const uint8_t kQuicHasMultipleAckBlocksShift = 1;
+
+// Returns the absolute value of the difference between |a| and |b|.
+QuicPacketNumber Delta(QuicPacketNumber a, QuicPacketNumber b) {
+ // Since these are unsigned numbers, we can't just return abs(a - b)
+ if (a < b) {
+ return b - a;
+ }
+ return a - b;
+}
+
+QuicPacketNumber ClosestTo(QuicPacketNumber target,
+ QuicPacketNumber a,
+ QuicPacketNumber b) {
+ return (Delta(target, a) < Delta(target, b)) ? a : b;
+}
+
+QuicPacketNumberLength ReadSequenceNumberLength(uint8_t flags) {
+ switch (flags & PACKET_FLAGS_6BYTE_PACKET) {
+ case PACKET_FLAGS_6BYTE_PACKET:
+ return PACKET_6BYTE_PACKET_NUMBER;
+ case PACKET_FLAGS_4BYTE_PACKET:
+ return PACKET_4BYTE_PACKET_NUMBER;
+ case PACKET_FLAGS_2BYTE_PACKET:
+ return PACKET_2BYTE_PACKET_NUMBER;
+ case PACKET_FLAGS_1BYTE_PACKET:
+ return PACKET_1BYTE_PACKET_NUMBER;
+ default:
+ QUIC_BUG << "Unreachable case statement.";
+ return PACKET_6BYTE_PACKET_NUMBER;
+ }
+}
+
+} // namespace
+
+QuicFramer::QuicFramer(const QuicVersionVector& supported_versions,
+ QuicTime creation_time,
+ Perspective perspective)
+ : visitor_(nullptr),
+ entropy_calculator_(nullptr),
+ error_(QUIC_NO_ERROR),
+ last_packet_number_(0),
+ largest_packet_number_(0),
+ last_path_id_(kInvalidPathId),
+ last_serialized_connection_id_(0),
+ supported_versions_(supported_versions),
+ decrypter_level_(ENCRYPTION_NONE),
+ alternative_decrypter_level_(ENCRYPTION_NONE),
+ alternative_decrypter_latch_(false),
+ perspective_(perspective),
+ validate_flags_(true),
+ creation_time_(creation_time),
+ last_timestamp_(QuicTime::Delta::Zero()) {
+ DCHECK(!supported_versions.empty());
+ quic_version_ = supported_versions_[0];
+ decrypter_.reset(QuicDecrypter::Create(kNULL));
+ encrypter_[ENCRYPTION_NONE].reset(QuicEncrypter::Create(kNULL));
+}
+
+QuicFramer::~QuicFramer() {}
+
+// static
+size_t QuicFramer::GetMinStreamFrameSize(QuicStreamId stream_id,
+ QuicStreamOffset offset,
+ bool last_frame_in_packet) {
+ return kQuicFrameTypeSize + GetStreamIdSize(stream_id) +
+ GetStreamOffsetSize(offset) +
+ (last_frame_in_packet ? 0 : kQuicStreamPayloadLengthSize);
+}
+
+// static
+size_t QuicFramer::GetMinAckFrameSize(
+ QuicVersion version,
+ QuicPacketNumberLength largest_observed_length) {
+ size_t min_size = kQuicFrameTypeSize + largest_observed_length +
+ kQuicDeltaTimeLargestObservedSize;
+ if (version <= QUIC_VERSION_33) {
+ return min_size + kQuicEntropyHashSize;
+ }
+ return min_size + kQuicNumTimestampsSize;
+}
+
+// static
+size_t QuicFramer::GetStopWaitingFrameSize(
+ QuicVersion version,
+ QuicPacketNumberLength packet_number_length) {
+ size_t min_size = kQuicFrameTypeSize + packet_number_length;
+ if (version <= QUIC_VERSION_33) {
+ return min_size + kQuicEntropyHashSize;
+ }
+ return min_size;
+}
+
+// static
+size_t QuicFramer::GetRstStreamFrameSize() {
+ return kQuicFrameTypeSize + kQuicMaxStreamIdSize + kQuicMaxStreamOffsetSize +
+ kQuicErrorCodeSize;
+}
+
+// static
+size_t QuicFramer::GetMinConnectionCloseFrameSize() {
+ return kQuicFrameTypeSize + kQuicErrorCodeSize + kQuicErrorDetailsLengthSize;
+}
+
+// static
+size_t QuicFramer::GetMinGoAwayFrameSize() {
+ return kQuicFrameTypeSize + kQuicErrorCodeSize + kQuicErrorDetailsLengthSize +
+ kQuicMaxStreamIdSize;
+}
+
+// static
+size_t QuicFramer::GetWindowUpdateFrameSize() {
+ return kQuicFrameTypeSize + kQuicMaxStreamIdSize + kQuicMaxStreamOffsetSize;
+}
+
+// static
+size_t QuicFramer::GetBlockedFrameSize() {
+ return kQuicFrameTypeSize + kQuicMaxStreamIdSize;
+}
+
+// static
+size_t QuicFramer::GetPathCloseFrameSize() {
+ return kQuicFrameTypeSize + kQuicPathIdSize;
+}
+
+// static
+size_t QuicFramer::GetStreamIdSize(QuicStreamId stream_id) {
+ // Sizes are 1 through 4 bytes.
+ for (int i = 1; i <= 4; ++i) {
+ stream_id >>= 8;
+ if (stream_id == 0) {
+ return i;
+ }
+ }
+ QUIC_BUG << "Failed to determine StreamIDSize.";
+ return 4;
+}
+
+// static
+size_t QuicFramer::GetStreamOffsetSize(QuicStreamOffset offset) {
+ // 0 is a special case.
+ if (offset == 0) {
+ return 0;
+ }
+ // 2 through 8 are the remaining sizes.
+ offset >>= 8;
+ for (int i = 2; i <= 8; ++i) {
+ offset >>= 8;
+ if (offset == 0) {
+ return i;
+ }
+ }
+ QUIC_BUG << "Failed to determine StreamOffsetSize.";
+ return 8;
+}
+
+// static
+size_t QuicFramer::GetVersionNegotiationPacketSize(size_t number_versions) {
+ return kPublicFlagsSize + PACKET_8BYTE_CONNECTION_ID +
+ number_versions * kQuicVersionSize;
+}
+
+bool QuicFramer::IsSupportedVersion(const QuicVersion version) const {
+ for (size_t i = 0; i < supported_versions_.size(); ++i) {
+ if (version == supported_versions_[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+size_t QuicFramer::GetSerializedFrameLength(
+ const QuicFrame& frame,
+ size_t free_bytes,
+ bool first_frame,
+ bool last_frame,
+ QuicPacketNumberLength packet_number_length) {
+ // Prevent a rare crash reported in b/19458523.
+ if ((frame.type == STREAM_FRAME || frame.type == ACK_FRAME) &&
+ frame.stream_frame == nullptr) {
+ QUIC_BUG << "Cannot compute the length of a null frame. "
+ << "type:" << frame.type << "free_bytes:" << free_bytes
+ << " first_frame:" << first_frame << " last_frame:" << last_frame
+ << " seq num length:" << packet_number_length;
+ set_error(QUIC_INTERNAL_ERROR);
+ visitor_->OnError(this);
+ return 0;
+ }
+ if (frame.type == PADDING_FRAME) {
+ if (frame.padding_frame.num_padding_bytes == -1) {
+ // Full padding to the end of the packet.
+ return free_bytes;
+ } else {
+ // Lite padding.
+ return free_bytes <
+ static_cast<size_t>(frame.padding_frame.num_padding_bytes)
+ ? free_bytes
+ : frame.padding_frame.num_padding_bytes;
+ }
+ }
+
+ size_t frame_len =
+ ComputeFrameLength(frame, last_frame, packet_number_length);
+ if (frame_len <= free_bytes) {
+ // Frame fits within packet. Note that acks may be truncated.
+ return frame_len;
+ }
+ // Only truncate the first frame in a packet, so if subsequent ones go
+ // over, stop including more frames.
+ if (!first_frame) {
+ return 0;
+ }
+ bool can_truncate =
+ frame.type == ACK_FRAME &&
+ free_bytes >=
+ GetMinAckFrameSize(quic_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.
+ DVLOG(1) << "Truncating large frame, free bytes: " << free_bytes;
+ return free_bytes;
+ }
+ return 0;
+}
+
+QuicFramer::AckFrameInfo::AckFrameInfo() : max_delta(0) {}
+
+QuicFramer::AckFrameInfo::AckFrameInfo(const AckFrameInfo& other) = default;
+
+QuicFramer::AckFrameInfo::~AckFrameInfo() {}
+
+QuicFramer::AckBlock::AckBlock(uint8_t gap, QuicPacketNumber length)
+ : gap(gap), length(length) {}
+
+QuicFramer::AckBlock::AckBlock(const AckBlock& other) = default;
+
+QuicFramer::AckBlock::~AckBlock() {}
+
+QuicFramer::NewAckFrameInfo::NewAckFrameInfo()
+ : max_block_length(0), first_block_length(0), num_ack_blocks(0) {}
+
+QuicFramer::NewAckFrameInfo::NewAckFrameInfo(const NewAckFrameInfo& other) =
+ default;
+
+QuicFramer::NewAckFrameInfo::~NewAckFrameInfo() {}
+
+// static
+QuicPacketEntropyHash QuicFramer::GetPacketEntropyHash(
+ const QuicPacketHeader& header) {
+ return header.entropy_flag << (header.packet_number % 8);
+}
+
+size_t QuicFramer::BuildDataPacket(const QuicPacketHeader& header,
+ const QuicFrames& frames,
+ char* buffer,
+ size_t packet_length) {
+ QuicDataWriter writer(packet_length, buffer);
+ if (!AppendPacketHeader(header, &writer)) {
+ QUIC_BUG << "AppendPacketHeader failed";
+ return 0;
+ }
+
+ size_t i = 0;
+ for (const QuicFrame& frame : frames) {
+ // Determine if we should write stream frame length in header.
+ const bool no_stream_frame_length = i == frames.size() - 1;
+ if (!AppendTypeByte(frame, no_stream_frame_length, &writer)) {
+ QUIC_BUG << "AppendTypeByte failed";
+ return 0;
+ }
+
+ switch (frame.type) {
+ case PADDING_FRAME:
+ writer.WritePadding();
+ break;
+ case STREAM_FRAME:
+ if (!AppendStreamFrame(*frame.stream_frame, no_stream_frame_length,
+ &writer)) {
+ QUIC_BUG << "AppendStreamFrame failed";
+ return 0;
+ }
+ break;
+ case ACK_FRAME:
+ if (quic_version_ <= QUIC_VERSION_33) {
+ if (!AppendAckFrameAndTypeByte(header, *frame.ack_frame, &writer)) {
+ QUIC_BUG << "AppendAckFrameAndTypeByte failed"
+ << " header: " << header
+ << " ack_fame: " << *frame.ack_frame;
+ return 0;
+ }
+ } else {
+ if (!AppendNewAckFrameAndTypeByte(*frame.ack_frame, &writer)) {
+ QUIC_BUG << "AppendNewAckFrameAndTypeByte failed";
+ return 0;
+ }
+ }
+ break;
+ case STOP_WAITING_FRAME:
+ if (!AppendStopWaitingFrame(header, *frame.stop_waiting_frame,
+ &writer)) {
+ QUIC_BUG << "AppendStopWaitingFrame failed";
+ return 0;
+ }
+ break;
+ case MTU_DISCOVERY_FRAME:
+ // MTU discovery frames are serialized as ping frames.
+ case PING_FRAME:
+ // Ping has no payload.
+ break;
+ case RST_STREAM_FRAME:
+ if (!AppendRstStreamFrame(*frame.rst_stream_frame, &writer)) {
+ QUIC_BUG << "AppendRstStreamFrame failed";
+ return 0;
+ }
+ break;
+ case CONNECTION_CLOSE_FRAME:
+ if (!AppendConnectionCloseFrame(*frame.connection_close_frame,
+ &writer)) {
+ QUIC_BUG << "AppendConnectionCloseFrame failed";
+ return 0;
+ }
+ break;
+ case GOAWAY_FRAME:
+ if (!AppendGoAwayFrame(*frame.goaway_frame, &writer)) {
+ QUIC_BUG << "AppendGoAwayFrame failed";
+ return 0;
+ }
+ break;
+ case WINDOW_UPDATE_FRAME:
+ if (!AppendWindowUpdateFrame(*frame.window_update_frame, &writer)) {
+ QUIC_BUG << "AppendWindowUpdateFrame failed";
+ return 0;
+ }
+ break;
+ case BLOCKED_FRAME:
+ if (!AppendBlockedFrame(*frame.blocked_frame, &writer)) {
+ QUIC_BUG << "AppendBlockedFrame failed";
+ return 0;
+ }
+ break;
+ case PATH_CLOSE_FRAME:
+ if (!AppendPathCloseFrame(*frame.path_close_frame, &writer)) {
+ QUIC_BUG << "AppendPathCloseFrame failed";
+ return 0;
+ }
+ break;
+ default:
+ RaiseError(QUIC_INVALID_FRAME_DATA);
+ QUIC_BUG << "QUIC_INVALID_FRAME_DATA";
+ return 0;
+ }
+ ++i;
+ }
+
+ return writer.length();
+}
+
+// static
+QuicEncryptedPacket* QuicFramer::BuildPublicResetPacket(
+ const QuicPublicResetPacket& packet) {
+ DCHECK(packet.public_header.reset_flag);
+
+ CryptoHandshakeMessage reset;
+ reset.set_tag(kPRST);
+ reset.SetValue(kRNON, packet.nonce_proof);
+ reset.SetValue(kRSEQ, packet.rejected_packet_number);
+ if (!packet.client_address.address().empty()) {
+ // packet.client_address is non-empty.
+ QuicSocketAddressCoder address_coder(packet.client_address);
+ string serialized_address = address_coder.Encode();
+ if (serialized_address.empty()) {
+ return nullptr;
+ }
+ reset.SetStringPiece(kCADR, serialized_address);
+ }
+ const QuicData& reset_serialized = reset.GetSerialized();
+
+ size_t len =
+ kPublicFlagsSize + PACKET_8BYTE_CONNECTION_ID + reset_serialized.length();
+ std::unique_ptr<char[]> buffer(new char[len]);
+ QuicDataWriter writer(len, buffer.get());
+
+ uint8_t flags = static_cast<uint8_t>(PACKET_PUBLIC_FLAGS_RST |
+ PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID);
+ if (FLAGS_quic_use_old_public_reset_packets) {
+ // TODO(rch): Remove this QUIC_VERSION_32 is retired.
+ flags |= static_cast<uint8_t>(PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD);
+ }
+ if (!writer.WriteUInt8(flags)) {
+ return nullptr;
+ }
+
+ if (!writer.WriteUInt64(packet.public_header.connection_id)) {
+ return nullptr;
+ }
+
+ if (!writer.WriteBytes(reset_serialized.data(), reset_serialized.length())) {
+ return nullptr;
+ }
+
+ return new QuicEncryptedPacket(buffer.release(), len, true);
+}
+
+// static
+QuicEncryptedPacket* QuicFramer::BuildVersionNegotiationPacket(
+ QuicConnectionId connection_id,
+ const QuicVersionVector& versions) {
+ DCHECK(!versions.empty());
+ size_t len = GetVersionNegotiationPacketSize(versions.size());
+ std::unique_ptr<char[]> buffer(new char[len]);
+ QuicDataWriter writer(len, buffer.get());
+
+ uint8_t flags = static_cast<uint8_t>(
+ PACKET_PUBLIC_FLAGS_VERSION | PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID |
+ // TODO(rch): Remove this QUIC_VERSION_32 is retired.
+ PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD);
+ if (!writer.WriteUInt8(flags)) {
+ return nullptr;
+ }
+
+ if (!writer.WriteUInt64(connection_id)) {
+ return nullptr;
+ }
+
+ for (QuicVersion version : versions) {
+ if (!writer.WriteUInt32(QuicVersionToQuicTag(version))) {
+ return nullptr;
+ }
+ }
+
+ return new QuicEncryptedPacket(buffer.release(), len, true);
+}
+
+bool QuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) {
+ QuicDataReader reader(packet.data(), packet.length());
+
+ visitor_->OnPacket();
+
+ // First parse the public header.
+ QuicPacketPublicHeader public_header;
+ if (!ProcessPublicHeader(&reader, &public_header)) {
+ DLOG(WARNING) << "Unable to process public header.";
+ DCHECK_NE("", detailed_error_);
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
+
+ if (!visitor_->OnUnauthenticatedPublicHeader(public_header)) {
+ // The visitor suppresses further processing of the packet.
+ return true;
+ }
+
+ if (perspective_ == Perspective::IS_SERVER && public_header.version_flag &&
+ public_header.versions[0] != quic_version_) {
+ if (!visitor_->OnProtocolVersionMismatch(public_header.versions[0])) {
+ return true;
+ }
+ }
+
+ bool rv;
+ if (perspective_ == Perspective::IS_CLIENT && public_header.version_flag) {
+ rv = ProcessVersionNegotiationPacket(&reader, &public_header);
+ } else if (public_header.reset_flag) {
+ rv = ProcessPublicResetPacket(&reader, public_header);
+ } else if (packet.length() <= kMaxPacketSize) {
+ // The optimized decryption algorithm implementations run faster when
+ // operating on aligned memory.
+ //
+ // TODO(rtenneti): Change the default 64 alignas value (used the default
+ // value from CACHELINE_SIZE).
+ ALIGNAS(64) char buffer[kMaxPacketSize];
+ rv = ProcessDataPacket(&reader, public_header, packet, buffer,
+ kMaxPacketSize);
+ } else {
+ std::unique_ptr<char[]> large_buffer(new char[packet.length()]);
+ rv = ProcessDataPacket(&reader, public_header, packet, large_buffer.get(),
+ packet.length());
+ QUIC_BUG_IF(rv) << "QUIC should never successfully process packets larger"
+ << "than kMaxPacketSize. packet size:" << packet.length();
+ }
+
+ return rv;
+}
+
+bool QuicFramer::ProcessVersionNegotiationPacket(
+ QuicDataReader* reader,
+ QuicPacketPublicHeader* public_header) {
+ DCHECK_EQ(Perspective::IS_CLIENT, perspective_);
+ // Try reading at least once to raise error if the packet is invalid.
+ do {
+ QuicTag version;
+ if (!reader->ReadBytes(&version, kQuicVersionSize)) {
+ set_detailed_error("Unable to read supported version in negotiation.");
+ return RaiseError(QUIC_INVALID_VERSION_NEGOTIATION_PACKET);
+ }
+ public_header->versions.push_back(QuicTagToQuicVersion(version));
+ } while (!reader->IsDoneReading());
+
+ visitor_->OnVersionNegotiationPacket(*public_header);
+ return true;
+}
+
+bool QuicFramer::ProcessDataPacket(QuicDataReader* encrypted_reader,
+ const QuicPacketPublicHeader& public_header,
+ const QuicEncryptedPacket& packet,
+ char* decrypted_buffer,
+ size_t buffer_length) {
+ QuicPacketHeader header(public_header);
+ if (!ProcessUnauthenticatedHeader(encrypted_reader, &header)) {
+ DLOG(WARNING) << "Unable to process packet header. Stopping parsing.";
+ return false;
+ }
+
+ size_t decrypted_length = 0;
+ if (!DecryptPayload(encrypted_reader, header, packet, decrypted_buffer,
+ buffer_length, &decrypted_length)) {
+ set_detailed_error("Unable to decrypt payload.");
+ return RaiseError(QUIC_DECRYPTION_FAILURE);
+ }
+
+ QuicDataReader reader(decrypted_buffer, decrypted_length);
+ if (quic_version_ <= QUIC_VERSION_33) {
+ if (!ProcessAuthenticatedHeader(&reader, &header)) {
+ DLOG(WARNING) << "Unable to process packet header. Stopping parsing.";
+ return false;
+ }
+ }
+
+ // Set the last packet number after we have decrypted the packet
+ // so we are confident is not attacker controlled.
+ SetLastPacketNumber(header);
+
+ if (!visitor_->OnPacketHeader(header)) {
+ // The visitor suppresses further processing of the packet.
+ return true;
+ }
+
+ if (packet.length() > kMaxPacketSize) {
+ // If the packet has gotten this far, it should not be too large.
+ QUIC_BUG << "Packet too large:" << packet.length();
+ return RaiseError(QUIC_PACKET_TOO_LARGE);
+ }
+
+ DCHECK(!header.fec_flag);
+ // Handle the payload.
+ if (!ProcessFrameData(&reader, header)) {
+ DCHECK_NE(QUIC_NO_ERROR, error_); // ProcessFrameData sets the error.
+ DLOG(WARNING) << "Unable to process frame data.";
+ return false;
+ }
+
+ visitor_->OnPacketComplete();
+ return true;
+}
+
+bool QuicFramer::ProcessPublicResetPacket(
+ QuicDataReader* reader,
+ const QuicPacketPublicHeader& public_header) {
+ QuicPublicResetPacket packet(public_header);
+
+ std::unique_ptr<CryptoHandshakeMessage> reset(
+ CryptoFramer::ParseMessage(reader->ReadRemainingPayload()));
+ if (!reset.get()) {
+ set_detailed_error("Unable to read reset message.");
+ return RaiseError(QUIC_INVALID_PUBLIC_RST_PACKET);
+ }
+ if (reset->tag() != kPRST) {
+ set_detailed_error("Incorrect message tag.");
+ return RaiseError(QUIC_INVALID_PUBLIC_RST_PACKET);
+ }
+
+ if (reset->GetUint64(kRNON, &packet.nonce_proof) != QUIC_NO_ERROR) {
+ set_detailed_error("Unable to read nonce proof.");
+ return RaiseError(QUIC_INVALID_PUBLIC_RST_PACKET);
+ }
+ // TODO(satyamshekhar): validate nonce to protect against DoS.
+
+ StringPiece address;
+ if (reset->GetStringPiece(kCADR, &address)) {
+ QuicSocketAddressCoder address_coder;
+ if (address_coder.Decode(address.data(), address.length())) {
+ packet.client_address =
+ IPEndPoint(address_coder.ip(), address_coder.port());
+ }
+ }
+
+ visitor_->OnPublicResetPacket(packet);
+ return true;
+}
+
+bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header,
+ QuicDataWriter* writer) {
+ DVLOG(1) << "Appending header: " << header;
+ uint8_t public_flags = 0;
+ if (header.public_header.reset_flag) {
+ public_flags |= PACKET_PUBLIC_FLAGS_RST;
+ }
+ if (header.public_header.version_flag) {
+ public_flags |= PACKET_PUBLIC_FLAGS_VERSION;
+ }
+ if (header.public_header.multipath_flag) {
+ public_flags |= PACKET_PUBLIC_FLAGS_MULTIPATH;
+ }
+
+ public_flags |=
+ GetSequenceNumberFlags(header.public_header.packet_number_length)
+ << kPublicHeaderSequenceNumberShift;
+
+ if (header.public_header.nonce != nullptr) {
+ DCHECK_EQ(Perspective::IS_SERVER, perspective_);
+ public_flags |= PACKET_PUBLIC_FLAGS_NONCE;
+ }
+
+ switch (header.public_header.connection_id_length) {
+ case PACKET_0BYTE_CONNECTION_ID:
+ if (!writer->WriteUInt8(public_flags |
+ PACKET_PUBLIC_FLAGS_0BYTE_CONNECTION_ID)) {
+ return false;
+ }
+ break;
+ case PACKET_8BYTE_CONNECTION_ID:
+ if (quic_version_ > QUIC_VERSION_32) {
+ public_flags |= PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID;
+ if (!FLAGS_quic_remove_v33_hacks2 &&
+ perspective_ == Perspective::IS_CLIENT) {
+ public_flags |= PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD;
+ }
+
+ } else {
+ public_flags |= PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD;
+ }
+ if (!writer->WriteUInt8(public_flags) ||
+ !writer->WriteUInt64(header.public_header.connection_id)) {
+ return false;
+ }
+ break;
+ }
+ last_serialized_connection_id_ = header.public_header.connection_id;
+
+ if (header.public_header.version_flag) {
+ DCHECK_EQ(Perspective::IS_CLIENT, perspective_);
+ QuicTag tag = QuicVersionToQuicTag(quic_version_);
+ writer->WriteUInt32(tag);
+ DVLOG(1) << "version = " << quic_version_ << ", tag = '"
+ << QuicUtils::TagToString(tag) << "'";
+ }
+
+ if (header.public_header.multipath_flag &&
+ !writer->WriteUInt8(header.path_id)) {
+ return false;
+ }
+
+ if (header.public_header.nonce != nullptr &&
+ !writer->WriteBytes(header.public_header.nonce,
+ kDiversificationNonceSize)) {
+ return false;
+ }
+
+ if (!AppendPacketSequenceNumber(header.public_header.packet_number_length,
+ header.packet_number, writer)) {
+ return false;
+ }
+ if (quic_version_ > QUIC_VERSION_33) {
+ return true;
+ }
+
+ uint8_t private_flags = 0;
+ if (header.entropy_flag) {
+ private_flags |= PACKET_PRIVATE_FLAGS_ENTROPY;
+ }
+ if (!writer->WriteUInt8(private_flags)) {
+ return false;
+ }
+
+ return true;
+}
+
+const QuicTime::Delta QuicFramer::CalculateTimestampFromWire(
+ uint32_t time_delta_us) {
+ // The new time_delta might have wrapped to the next epoch, or it
+ // might have reverse wrapped to the previous epoch, or it might
+ // remain in the same epoch. Select the time closest to the previous
+ // time.
+ //
+ // epoch_delta is the delta between epochs. A delta is 4 bytes of
+ // microseconds.
+ const uint64_t epoch_delta = UINT64_C(1) << 32;
+ uint64_t epoch = last_timestamp_.ToMicroseconds() & ~(epoch_delta - 1);
+ // Wrapping is safe here because a wrapped value will not be ClosestTo below.
+ uint64_t prev_epoch = epoch - epoch_delta;
+ uint64_t next_epoch = epoch + epoch_delta;
+
+ uint64_t time = ClosestTo(
+ last_timestamp_.ToMicroseconds(), epoch + time_delta_us,
+ ClosestTo(last_timestamp_.ToMicroseconds(), prev_epoch + time_delta_us,
+ next_epoch + time_delta_us));
+
+ return QuicTime::Delta::FromMicroseconds(time);
+}
+
+bool QuicFramer::IsValidPath(QuicPathId path_id,
+ QuicPacketNumber* base_packet_number) {
+ if (ContainsKey(closed_paths_, path_id)) {
+ // Path is closed.
+ return false;
+ }
+
+ if (FLAGS_quic_packet_numbers_largest_received) {
+ if (path_id == last_path_id_) {
+ *base_packet_number = largest_packet_number_;
+ return true;
+ }
+
+ if (ContainsKey(largest_packet_numbers_, path_id)) {
+ *base_packet_number = largest_packet_numbers_[path_id];
+ } else {
+ *base_packet_number = 0;
+ }
+ } else {
+ if (path_id == last_path_id_) {
+ *base_packet_number = last_packet_number_;
+ return true;
+ }
+
+ if (ContainsKey(last_packet_numbers_, path_id)) {
+ *base_packet_number = last_packet_numbers_[path_id];
+ } else {
+ *base_packet_number = 0;
+ }
+ }
+
+ return true;
+}
+
+void QuicFramer::SetLastPacketNumber(const QuicPacketHeader& header) {
+ if (header.public_header.multipath_flag && header.path_id != last_path_id_) {
+ if (last_path_id_ != kInvalidPathId) {
+ // Save current last packet number before changing path.
+ last_packet_numbers_[last_path_id_] = last_packet_number_;
+ if (FLAGS_quic_packet_numbers_largest_received) {
+ largest_packet_numbers_[last_path_id_] = largest_packet_number_;
+ }
+ }
+ // Change path.
+ last_path_id_ = header.path_id;
+ }
+ last_packet_number_ = header.packet_number;
+ if (FLAGS_quic_packet_numbers_largest_received) {
+ largest_packet_number_ = max(header.packet_number, largest_packet_number_);
+ }
+}
+
+void QuicFramer::OnPathClosed(QuicPathId path_id) {
+ closed_paths_.insert(path_id);
+ last_packet_numbers_.erase(path_id);
+}
+
+QuicPacketNumber QuicFramer::CalculatePacketNumberFromWire(
+ QuicPacketNumberLength packet_number_length,
+ QuicPacketNumber base_packet_number,
+ QuicPacketNumber packet_number) const {
+ // The new packet number might have wrapped to the next epoch, or
+ // it might have reverse wrapped to the previous epoch, or it might
+ // remain in the same epoch. Select the packet number closest to the
+ // next expected packet number, the previous packet number plus 1.
+
+ // epoch_delta is the delta between epochs the packet number was serialized
+ // with, so the correct value is likely the same epoch as the last sequence
+ // number or an adjacent epoch.
+ const QuicPacketNumber epoch_delta = UINT64_C(1)
+ << (8 * packet_number_length);
+ QuicPacketNumber next_packet_number = base_packet_number + 1;
+ QuicPacketNumber epoch = base_packet_number & ~(epoch_delta - 1);
+ QuicPacketNumber prev_epoch = epoch - epoch_delta;
+ QuicPacketNumber next_epoch = epoch + epoch_delta;
+
+ return ClosestTo(next_packet_number, epoch + packet_number,
+ ClosestTo(next_packet_number, prev_epoch + packet_number,
+ next_epoch + packet_number));
+}
+
+bool QuicFramer::ProcessPublicHeader(QuicDataReader* reader,
+ QuicPacketPublicHeader* public_header) {
+ uint8_t public_flags;
+ if (!reader->ReadBytes(&public_flags, 1)) {
+ set_detailed_error("Unable to read public flags.");
+ return false;
+ }
+
+ public_header->multipath_flag =
+ (public_flags & PACKET_PUBLIC_FLAGS_MULTIPATH) != 0;
+ public_header->reset_flag = (public_flags & PACKET_PUBLIC_FLAGS_RST) != 0;
+ public_header->version_flag =
+ (public_flags & PACKET_PUBLIC_FLAGS_VERSION) != 0;
+
+ if (validate_flags_ && !public_header->version_flag &&
+ public_flags > PACKET_PUBLIC_FLAGS_MAX) {
+ set_detailed_error("Illegal public flags value.");
+ return false;
+ }
+
+ if (public_header->reset_flag && public_header->version_flag) {
+ set_detailed_error("Got version flag in reset packet");
+ return false;
+ }
+
+ switch (public_flags & PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID) {
+ case PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID:
+ if (!reader->ReadUInt64(&public_header->connection_id)) {
+ set_detailed_error("Unable to read ConnectionId.");
+ return false;
+ }
+ public_header->connection_id_length = PACKET_8BYTE_CONNECTION_ID;
+ break;
+ case PACKET_PUBLIC_FLAGS_0BYTE_CONNECTION_ID:
+ public_header->connection_id_length = PACKET_0BYTE_CONNECTION_ID;
+ public_header->connection_id = last_serialized_connection_id_;
+ break;
+ }
+
+ public_header->packet_number_length = ReadSequenceNumberLength(
+ public_flags >> kPublicHeaderSequenceNumberShift);
+
+ // Read the version only if the packet is from the client.
+ // version flag from the server means version negotiation packet.
+ if (public_header->version_flag && perspective_ == Perspective::IS_SERVER) {
+ QuicTag version_tag;
+ if (!reader->ReadUInt32(&version_tag)) {
+ set_detailed_error("Unable to read protocol version.");
+ return false;
+ }
+
+ // 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_tag_ = version_tag;
+ QuicVersion version = QuicTagToQuicVersion(version_tag);
+ if (version == quic_version_ && public_flags > PACKET_PUBLIC_FLAGS_MAX) {
+ set_detailed_error("Illegal public flags value.");
+ return false;
+ }
+ public_header->versions.push_back(version);
+ }
+
+ // A nonce should only be present in packets from the server to the client,
+ // which are neither version negotiation nor public reset packets
+ // and only for versions after QUIC_VERSION_32. Earlier versions will
+ // set this bit when indicating an 8-byte connection ID, which should
+ // not be interpreted as indicating a nonce is present.
+ if (quic_version_ > QUIC_VERSION_32 &&
+ public_flags & PACKET_PUBLIC_FLAGS_NONCE &&
+ !(public_flags & PACKET_PUBLIC_FLAGS_VERSION) &&
+ !(public_flags & PACKET_PUBLIC_FLAGS_RST) &&
+ // The nonce flag from a client is ignored and is assumed to be an older
+ // client indicating an eight-byte connection ID.
+ perspective_ == Perspective::IS_CLIENT) {
+ if (!reader->ReadBytes(reinterpret_cast<uint8_t*>(last_nonce_.data()),
+ last_nonce_.size())) {
+ set_detailed_error("Unable to read nonce.");
+ return false;
+ }
+ public_header->nonce = &last_nonce_;
+ } else {
+ public_header->nonce = nullptr;
+ }
+
+ return true;
+}
+
+// static
+QuicPacketNumberLength QuicFramer::GetMinSequenceNumberLength(
+ QuicPacketNumber packet_number) {
+ if (packet_number < 1 << (PACKET_1BYTE_PACKET_NUMBER * 8)) {
+ return PACKET_1BYTE_PACKET_NUMBER;
+ } else if (packet_number < 1 << (PACKET_2BYTE_PACKET_NUMBER * 8)) {
+ return PACKET_2BYTE_PACKET_NUMBER;
+ } else if (packet_number < UINT64_C(1) << (PACKET_4BYTE_PACKET_NUMBER * 8)) {
+ return PACKET_4BYTE_PACKET_NUMBER;
+ } else {
+ return PACKET_6BYTE_PACKET_NUMBER;
+ }
+}
+
+// static
+uint8_t QuicFramer::GetSequenceNumberFlags(
+ QuicPacketNumberLength packet_number_length) {
+ switch (packet_number_length) {
+ case PACKET_1BYTE_PACKET_NUMBER:
+ return PACKET_FLAGS_1BYTE_PACKET;
+ case PACKET_2BYTE_PACKET_NUMBER:
+ return PACKET_FLAGS_2BYTE_PACKET;
+ case PACKET_4BYTE_PACKET_NUMBER:
+ return PACKET_FLAGS_4BYTE_PACKET;
+ case PACKET_6BYTE_PACKET_NUMBER:
+ return PACKET_FLAGS_6BYTE_PACKET;
+ default:
+ QUIC_BUG << "Unreachable case statement.";
+ return PACKET_FLAGS_6BYTE_PACKET;
+ }
+}
+
+// static
+QuicFramer::AckFrameInfo QuicFramer::GetAckFrameInfo(
+ const QuicAckFrame& frame) {
+ AckFrameInfo ack_info;
+ if (frame.packets.Empty()) {
+ return ack_info;
+ }
+ DCHECK_GE(frame.largest_observed, frame.packets.Max());
+ QuicPacketNumber last_largest_missing = 0;
+ for (const Interval<QuicPacketNumber>& interval : frame.packets) {
+ for (QuicPacketNumber interval_start = interval.min();
+ interval_start < interval.max();
+ interval_start += (1ull + numeric_limits<uint8_t>::max())) {
+ uint8_t cur_range_length =
+ interval.max() - interval_start > numeric_limits<uint8_t>::max()
+ ? numeric_limits<uint8_t>::max()
+ : (interval.max() - interval_start) - 1;
+ ack_info.nack_ranges[interval_start] = cur_range_length;
+ }
+ ack_info.max_delta =
+ max(ack_info.max_delta, last_largest_missing == 0
+ ? QuicPacketNumber{0}
+ : (interval.min() - last_largest_missing));
+ last_largest_missing = interval.max() - 1;
+ }
+ // Include the range to the largest observed.
+ ack_info.max_delta =
+ max(ack_info.max_delta, frame.largest_observed - last_largest_missing);
+ return ack_info;
+}
+
+// static
+QuicFramer::NewAckFrameInfo QuicFramer::GetNewAckFrameInfo(
+ const QuicAckFrame& frame) {
+ NewAckFrameInfo new_ack_info;
+ if (frame.packets.Empty()) {
+ return new_ack_info;
+ }
+ // The first block is the last interval. It isn't encoded with the gap-length
+ // encoding, so skip it.
+ new_ack_info.first_block_length = frame.packets.LastIntervalLength();
+ auto itr = frame.packets.rbegin();
+ QuicPacketNumber previous_start = itr->min();
+ new_ack_info.max_block_length = itr->Length();
+ ++itr;
+
+ // Don't do any more work after getting information for 256 ACK blocks; any
+ // more can't be encoded anyway.
+ for (; itr != frame.packets.rend() &&
+ new_ack_info.num_ack_blocks < numeric_limits<uint8_t>::max();
+ previous_start = itr->min(), ++itr) {
+ const auto& interval = *itr;
+ const QuicPacketNumber total_gap = previous_start - interval.max();
+ new_ack_info.num_ack_blocks +=
+ (total_gap + numeric_limits<uint8_t>::max() - 1) /
+ numeric_limits<uint8_t>::max();
+ new_ack_info.max_block_length =
+ max(new_ack_info.max_block_length, interval.Length());
+ }
+ return new_ack_info;
+}
+
+bool QuicFramer::ProcessUnauthenticatedHeader(QuicDataReader* encrypted_reader,
+ QuicPacketHeader* header) {
+ header->path_id = kDefaultPathId;
+ if (header->public_header.multipath_flag &&
+ !ProcessPathId(encrypted_reader, &header->path_id)) {
+ set_detailed_error("Unable to read path id.");
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
+
+ QuicPacketNumber base_packet_number =
+ FLAGS_quic_packet_numbers_largest_received ? largest_packet_number_
+ : last_packet_number_;
+ if (header->public_header.multipath_flag &&
+ !IsValidPath(header->path_id, &base_packet_number)) {
+ // Stop processing because path is closed.
+ return false;
+ }
+
+ if (!ProcessPacketSequenceNumber(
+ encrypted_reader, header->public_header.packet_number_length,
+ base_packet_number, &header->packet_number)) {
+ set_detailed_error("Unable to read packet number.");
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
+
+ if (header->packet_number == 0u) {
+ set_detailed_error("packet numbers cannot be 0.");
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
+
+ if (!visitor_->OnUnauthenticatedHeader(*header)) {
+ return false;
+ }
+ return true;
+}
+
+bool QuicFramer::ProcessAuthenticatedHeader(QuicDataReader* reader,
+ QuicPacketHeader* header) {
+ uint8_t private_flags;
+ if (!reader->ReadBytes(&private_flags, 1)) {
+ set_detailed_error("Unable to read private flags.");
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
+
+ if (quic_version_ > QUIC_VERSION_31) {
+ if (private_flags > PACKET_PRIVATE_FLAGS_MAX_VERSION_32) {
+ set_detailed_error("Illegal private flags value.");
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
+ } else {
+ if (private_flags > PACKET_PRIVATE_FLAGS_MAX) {
+ set_detailed_error("Illegal private flags value.");
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
+ }
+
+ header->entropy_flag = (private_flags & PACKET_PRIVATE_FLAGS_ENTROPY) != 0;
+ header->fec_flag = (private_flags & PACKET_PRIVATE_FLAGS_FEC) != 0;
+
+ if ((private_flags & PACKET_PRIVATE_FLAGS_FEC_GROUP) != 0) {
+ uint8_t first_fec_protected_packet_offset;
+ if (!reader->ReadBytes(&first_fec_protected_packet_offset, 1)) {
+ set_detailed_error("Unable to read first fec protected packet offset.");
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
+ if (first_fec_protected_packet_offset >= header->packet_number) {
+ set_detailed_error(
+ "First fec protected packet offset must be less "
+ "than the packet number.");
+ return RaiseError(QUIC_INVALID_PACKET_HEADER);
+ }
+ }
+
+ header->entropy_hash = GetPacketEntropyHash(*header);
+ return true;
+}
+
+bool QuicFramer::ProcessPathId(QuicDataReader* reader, QuicPathId* path_id) {
+ if (!reader->ReadBytes(path_id, 1)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool QuicFramer::ProcessPacketSequenceNumber(
+ QuicDataReader* reader,
+ QuicPacketNumberLength packet_number_length,
+ QuicPacketNumber base_packet_number,
+ QuicPacketNumber* packet_number) {
+ QuicPacketNumber wire_packet_number = 0u;
+ if (!reader->ReadBytes(&wire_packet_number, packet_number_length)) {
+ return false;
+ }
+
+ // TODO(ianswett): Explore the usefulness of trying multiple packet numbers
+ // in case the first guess is incorrect.
+ *packet_number = CalculatePacketNumberFromWire(
+ packet_number_length, base_packet_number, wire_packet_number);
+ return true;
+}
+
+bool QuicFramer::ProcessFrameData(QuicDataReader* reader,
+ const QuicPacketHeader& header) {
+ if (reader->IsDoneReading()) {
+ set_detailed_error("Packet has no frames.");
+ return RaiseError(QUIC_MISSING_PAYLOAD);
+ }
+ while (!reader->IsDoneReading()) {
+ uint8_t frame_type;
+ if (!reader->ReadBytes(&frame_type, 1)) {
+ set_detailed_error("Unable to read frame type.");
+ return RaiseError(QUIC_INVALID_FRAME_DATA);
+ }
+
+ if (frame_type & kQuicFrameTypeSpecialMask) {
+ // Stream Frame
+ if (frame_type & kQuicFrameTypeStreamMask) {
+ QuicStreamFrame frame;
+ if (!ProcessStreamFrame(reader, frame_type, &frame)) {
+ return RaiseError(QUIC_INVALID_STREAM_DATA);
+ }
+ if (!visitor_->OnStreamFrame(frame)) {
+ DVLOG(1) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ continue;
+ }
+
+ // Ack Frame
+ if (frame_type & kQuicFrameTypeAckMask) {
+ QuicAckFrame frame;
+ if (quic_version_ <= QUIC_VERSION_33) {
+ if (!ProcessAckFrame(reader, frame_type, &frame)) {
+ return RaiseError(QUIC_INVALID_ACK_DATA);
+ }
+ } else {
+ if (!ProcessNewAckFrame(reader, frame_type, &frame)) {
+ return RaiseError(QUIC_INVALID_ACK_DATA);
+ }
+ }
+ if (!visitor_->OnAckFrame(frame)) {
+ DVLOG(1) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ continue;
+ }
+
+ // This was a special frame type that did not match any
+ // of the known ones. Error.
+ set_detailed_error("Illegal frame type.");
+ DLOG(WARNING) << "Illegal frame type: " << static_cast<int>(frame_type);
+ return RaiseError(QUIC_INVALID_FRAME_DATA);
+ }
+
+ switch (frame_type) {
+ case PADDING_FRAME: {
+ QuicPaddingFrame frame(reader->BytesRemaining());
+ if (!visitor_->OnPaddingFrame(frame)) {
+ DVLOG(1) << "Visitor asked to stop further processing.";
+ }
+ // We're done with the packet.
+ return true;
+ }
+
+ case RST_STREAM_FRAME: {
+ QuicRstStreamFrame frame;
+ if (!ProcessRstStreamFrame(reader, &frame)) {
+ return RaiseError(QUIC_INVALID_RST_STREAM_DATA);
+ }
+ if (!visitor_->OnRstStreamFrame(frame)) {
+ DVLOG(1) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ continue;
+ }
+
+ case CONNECTION_CLOSE_FRAME: {
+ QuicConnectionCloseFrame frame;
+ if (!ProcessConnectionCloseFrame(reader, &frame)) {
+ return RaiseError(QUIC_INVALID_CONNECTION_CLOSE_DATA);
+ }
+
+ if (!visitor_->OnConnectionCloseFrame(frame)) {
+ DVLOG(1) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ continue;
+ }
+
+ case GOAWAY_FRAME: {
+ QuicGoAwayFrame goaway_frame;
+ if (!ProcessGoAwayFrame(reader, &goaway_frame)) {
+ return RaiseError(QUIC_INVALID_GOAWAY_DATA);
+ }
+ if (!visitor_->OnGoAwayFrame(goaway_frame)) {
+ DVLOG(1) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ continue;
+ }
+
+ case WINDOW_UPDATE_FRAME: {
+ QuicWindowUpdateFrame window_update_frame;
+ if (!ProcessWindowUpdateFrame(reader, &window_update_frame)) {
+ return RaiseError(QUIC_INVALID_WINDOW_UPDATE_DATA);
+ }
+ if (!visitor_->OnWindowUpdateFrame(window_update_frame)) {
+ DVLOG(1) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ continue;
+ }
+
+ case BLOCKED_FRAME: {
+ QuicBlockedFrame blocked_frame;
+ if (!ProcessBlockedFrame(reader, &blocked_frame)) {
+ return RaiseError(QUIC_INVALID_BLOCKED_DATA);
+ }
+ if (!visitor_->OnBlockedFrame(blocked_frame)) {
+ DVLOG(1) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ continue;
+ }
+
+ case STOP_WAITING_FRAME: {
+ QuicStopWaitingFrame stop_waiting_frame;
+ if (!ProcessStopWaitingFrame(reader, header, &stop_waiting_frame)) {
+ return RaiseError(QUIC_INVALID_STOP_WAITING_DATA);
+ }
+ if (!visitor_->OnStopWaitingFrame(stop_waiting_frame)) {
+ DVLOG(1) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ continue;
+ }
+ case PING_FRAME: {
+ // Ping has no payload.
+ QuicPingFrame ping_frame;
+ if (!visitor_->OnPingFrame(ping_frame)) {
+ DVLOG(1) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ continue;
+ }
+ case PATH_CLOSE_FRAME: {
+ QuicPathCloseFrame path_close_frame;
+ if (!ProcessPathCloseFrame(reader, &path_close_frame)) {
+ return RaiseError(QUIC_INVALID_PATH_CLOSE_DATA);
+ }
+ if (!visitor_->OnPathCloseFrame(path_close_frame)) {
+ DVLOG(1) << "Visitor asked to stop further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+ continue;
+ }
+
+ default:
+ set_detailed_error("Illegal frame type.");
+ DLOG(WARNING) << "Illegal frame type: " << static_cast<int>(frame_type);
+ return RaiseError(QUIC_INVALID_FRAME_DATA);
+ }
+ }
+
+ return true;
+}
+
+bool QuicFramer::ProcessStreamFrame(QuicDataReader* reader,
+ uint8_t frame_type,
+ QuicStreamFrame* frame) {
+ uint8_t stream_flags = frame_type;
+
+ stream_flags &= ~kQuicFrameTypeStreamMask;
+
+ // Read from right to left: StreamID, Offset, Data Length, Fin.
+ const uint8_t stream_id_length = (stream_flags & kQuicStreamIDLengthMask) + 1;
+ stream_flags >>= kQuicStreamIdShift;
+
+ uint8_t offset_length = (stream_flags & kQuicStreamOffsetMask);
+ // There is no encoding for 1 byte, only 0 and 2 through 8.
+ if (offset_length > 0) {
+ offset_length += 1;
+ }
+ stream_flags >>= kQuicStreamOffsetShift;
+
+ bool has_data_length =
+ (stream_flags & kQuicStreamDataLengthMask) == kQuicStreamDataLengthMask;
+ stream_flags >>= kQuicStreamDataLengthShift;
+
+ frame->fin = (stream_flags & kQuicStreamFinMask) == kQuicStreamFinShift;
+
+ frame->stream_id = 0;
+ if (!reader->ReadBytes(&frame->stream_id, stream_id_length)) {
+ set_detailed_error("Unable to read stream_id.");
+ return false;
+ }
+
+ frame->offset = 0;
+ if (!reader->ReadBytes(&frame->offset, offset_length)) {
+ set_detailed_error("Unable to read offset.");
+ return false;
+ }
+
+ // TODO(ianswett): Don't use StringPiece as an intermediary.
+ StringPiece data;
+ if (has_data_length) {
+ if (!reader->ReadStringPiece16(&data)) {
+ set_detailed_error("Unable to read frame data.");
+ return false;
+ }
+ } else {
+ if (!reader->ReadStringPiece(&data, reader->BytesRemaining())) {
+ set_detailed_error("Unable to read frame data.");
+ return false;
+ }
+ }
+ frame->data_buffer = data.data();
+ frame->data_length = static_cast<uint16_t>(data.length());
+
+ return true;
+}
+
+bool QuicFramer::ProcessAckFrame(QuicDataReader* reader,
+ uint8_t frame_type,
+ QuicAckFrame* ack_frame) {
+ // Determine the three lengths from the frame type: largest observed length,
+ // missing packet number length, and missing range length.
+ const QuicPacketNumberLength missing_packet_number_length =
+ ReadSequenceNumberLength(frame_type);
+ frame_type >>= kQuicSequenceNumberLengthShift;
+ const QuicPacketNumberLength largest_observed_packet_number_length =
+ ReadSequenceNumberLength(frame_type);
+ frame_type >>= kQuicSequenceNumberLengthShift;
+ ack_frame->is_truncated = frame_type & kQuicAckTruncatedMask;
+ frame_type >>= kQuicAckTruncatedShift;
+ bool has_nacks = frame_type & kQuicHasNacksMask;
+
+ if (!reader->ReadBytes(&ack_frame->entropy_hash, 1)) {
+ set_detailed_error("Unable to read entropy hash for received packets.");
+ return false;
+ }
+
+ if (!reader->ReadBytes(&ack_frame->largest_observed,
+ largest_observed_packet_number_length)) {
+ set_detailed_error("Unable to read largest observed.");
+ return false;
+ }
+
+ uint64_t ack_delay_time_us;
+ if (!reader->ReadUFloat16(&ack_delay_time_us)) {
+ set_detailed_error("Unable to read ack delay time.");
+ return false;
+ }
+
+ if (ack_delay_time_us == kUFloat16MaxValue) {
+ ack_frame->ack_delay_time = QuicTime::Delta::Infinite();
+ } else {
+ ack_frame->ack_delay_time =
+ QuicTime::Delta::FromMicroseconds(ack_delay_time_us);
+ }
+
+ if (!ProcessTimestampsInAckFrame(reader, ack_frame)) {
+ return false;
+ }
+
+ if (!has_nacks) {
+ return true;
+ }
+
+ uint8_t num_missing_ranges;
+ if (!reader->ReadBytes(&num_missing_ranges, 1)) {
+ set_detailed_error("Unable to read num missing packet ranges.");
+ return false;
+ }
+
+ QuicPacketNumber last_packet_number = ack_frame->largest_observed;
+ for (size_t i = 0; i < num_missing_ranges; ++i) {
+ QuicPacketNumber missing_delta = 0;
+ if (!reader->ReadBytes(&missing_delta, missing_packet_number_length)) {
+ set_detailed_error("Unable to read missing packet number delta.");
+ return false;
+ }
+ last_packet_number -= missing_delta;
+ QuicPacketNumber range_length = 0;
+ if (!reader->ReadBytes(&range_length, PACKET_1BYTE_PACKET_NUMBER)) {
+ set_detailed_error("Unable to read missing packet number range.");
+ return false;
+ }
+ ack_frame->packets.Add(last_packet_number - range_length,
+ last_packet_number + 1);
+ // Subtract an extra 1 to ensure ranges are represented efficiently and
+ // can't overlap by 1 packet number. This allows a missing_delta of 0
+ // to represent an adjacent nack range.
+ last_packet_number -= (range_length + 1);
+ }
+
+ if (quic_version_ > QUIC_VERSION_31) {
+ return true;
+ }
+
+ // Parse the revived packets list.
+ // TODO(ianswett): Change the ack frame so it only expresses one revived.
+ uint8_t num_revived_packets;
+ if (!reader->ReadBytes(&num_revived_packets, 1)) {
+ set_detailed_error("Unable to read num revived packets.");
+ return false;
+ }
+
+ for (size_t i = 0; i < num_revived_packets; ++i) {
+ QuicPacketNumber revived_packet = 0;
+ if (!reader->ReadBytes(&revived_packet,
+ largest_observed_packet_number_length)) {
+ set_detailed_error("Unable to read revived packet.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool QuicFramer::ProcessNewAckFrame(QuicDataReader* reader,
+ uint8_t frame_type,
+ QuicAckFrame* ack_frame) {
+ // Determine the two lengths from the frame type: largest acked length,
+ // ack block length.
+ const QuicPacketNumberLength ack_block_length =
+ ReadSequenceNumberLength(frame_type);
+ frame_type >>= kQuicSequenceNumberLengthShift;
+ const QuicPacketNumberLength largest_acked_length =
+ ReadSequenceNumberLength(frame_type);
+ frame_type >>= kQuicSequenceNumberLengthShift;
+ frame_type >>= kQuicHasMultipleAckBlocksShift;
+ bool has_ack_blocks = frame_type & kQuicHasMultipleAckBlocksMask;
+ ack_frame->missing = false;
+
+ if (!reader->ReadBytes(&ack_frame->largest_observed, largest_acked_length)) {
+ set_detailed_error("Unable to read largest acked.");
+ return false;
+ }
+
+ uint64_t ack_delay_time_us;
+ if (!reader->ReadUFloat16(&ack_delay_time_us)) {
+ set_detailed_error("Unable to read ack delay time.");
+ return false;
+ }
+
+ if (ack_delay_time_us == kUFloat16MaxValue) {
+ ack_frame->ack_delay_time = QuicTime::Delta::Infinite();
+ } else {
+ ack_frame->ack_delay_time =
+ QuicTime::Delta::FromMicroseconds(ack_delay_time_us);
+ }
+
+ uint8_t num_ack_blocks = 0;
+ if (has_ack_blocks) {
+ if (!reader->ReadBytes(&num_ack_blocks, 1)) {
+ set_detailed_error("Unable to read num of ack blocks.");
+ return false;
+ }
+ }
+
+ size_t first_block_length = 0;
+ if (!reader->ReadBytes(&first_block_length, ack_block_length)) {
+ set_detailed_error("Unable to read first ack block length.");
+ return false;
+ }
+ QuicPacketNumber first_received =
+ ack_frame->largest_observed + 1 - first_block_length;
+ ack_frame->packets.Add(first_received, ack_frame->largest_observed + 1);
+
+ if (num_ack_blocks > 0) {
+ for (size_t i = 0; i < num_ack_blocks; ++i) {
+ size_t gap = 0;
+ if (!reader->ReadBytes(&gap, PACKET_1BYTE_PACKET_NUMBER)) {
+ set_detailed_error("Unable to read gap to next ack block.");
+ return false;
+ }
+ size_t current_block_length = 0;
+ if (!reader->ReadBytes(&current_block_length, ack_block_length)) {
+ set_detailed_error("Unable to ack block length.");
+ return false;
+ }
+ first_received -= (gap + current_block_length);
+ if (current_block_length > 0) {
+ ack_frame->packets.Add(first_received,
+ first_received + current_block_length);
+ }
+ }
+ }
+
+ if (!ProcessTimestampsInAckFrame(reader, ack_frame)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool QuicFramer::ProcessTimestampsInAckFrame(QuicDataReader* reader,
+ QuicAckFrame* ack_frame) {
+ if (ack_frame->is_truncated) {
+ return true;
+ }
+ uint8_t num_received_packets;
+ if (!reader->ReadBytes(&num_received_packets, 1)) {
+ set_detailed_error("Unable to read num received packets.");
+ return false;
+ }
+
+ if (num_received_packets > 0) {
+ uint8_t delta_from_largest_observed;
+ if (!reader->ReadBytes(&delta_from_largest_observed,
+ PACKET_1BYTE_PACKET_NUMBER)) {
+ set_detailed_error("Unable to read sequence delta in received packets.");
+ return false;
+ }
+ QuicPacketNumber seq_num =
+ ack_frame->largest_observed - delta_from_largest_observed;
+
+ // Time delta from the framer creation.
+ uint32_t time_delta_us;
+ if (!reader->ReadBytes(&time_delta_us, sizeof(time_delta_us))) {
+ set_detailed_error("Unable to read time delta in received packets.");
+ return false;
+ }
+
+ last_timestamp_ = CalculateTimestampFromWire(time_delta_us);
+
+ ack_frame->received_packet_times.reserve(num_received_packets);
+ ack_frame->received_packet_times.push_back(
+ std::make_pair(seq_num, creation_time_ + last_timestamp_));
+
+ for (uint8_t i = 1; i < num_received_packets; ++i) {
+ if (!reader->ReadBytes(&delta_from_largest_observed,
+ PACKET_1BYTE_PACKET_NUMBER)) {
+ set_detailed_error(
+ "Unable to read sequence delta in received packets.");
+ return false;
+ }
+ seq_num = ack_frame->largest_observed - delta_from_largest_observed;
+
+ // Time delta from the previous timestamp.
+ uint64_t incremental_time_delta_us;
+ if (!reader->ReadUFloat16(&incremental_time_delta_us)) {
+ set_detailed_error(
+ "Unable to read incremental time delta in received packets.");
+ return false;
+ }
+
+ last_timestamp_ = last_timestamp_ + QuicTime::Delta::FromMicroseconds(
+ incremental_time_delta_us);
+ ack_frame->received_packet_times.push_back(
+ std::make_pair(seq_num, creation_time_ + last_timestamp_));
+ }
+ }
+ return true;
+}
+
+bool QuicFramer::ProcessStopWaitingFrame(QuicDataReader* reader,
+ const QuicPacketHeader& header,
+ QuicStopWaitingFrame* stop_waiting) {
+ if (quic_version_ <= QUIC_VERSION_33) {
+ if (!reader->ReadBytes(&stop_waiting->entropy_hash, 1)) {
+ set_detailed_error("Unable to read entropy hash for sent packets.");
+ return false;
+ }
+ }
+
+ QuicPacketNumber least_unacked_delta = 0;
+ if (!reader->ReadBytes(&least_unacked_delta,
+ header.public_header.packet_number_length)) {
+ set_detailed_error("Unable to read least unacked delta.");
+ return false;
+ }
+ DCHECK_GE(header.packet_number, least_unacked_delta);
+ stop_waiting->least_unacked = header.packet_number - least_unacked_delta;
+
+ return true;
+}
+
+bool QuicFramer::ProcessRstStreamFrame(QuicDataReader* reader,
+ QuicRstStreamFrame* frame) {
+ if (!reader->ReadUInt32(&frame->stream_id)) {
+ set_detailed_error("Unable to read stream_id.");
+ return false;
+ }
+
+ if (!reader->ReadUInt64(&frame->byte_offset)) {
+ set_detailed_error("Unable to read rst stream sent byte offset.");
+ return false;
+ }
+
+ uint32_t error_code;
+ if (!reader->ReadUInt32(&error_code)) {
+ set_detailed_error("Unable to read rst stream error code.");
+ return false;
+ }
+
+ if (error_code >= QUIC_STREAM_LAST_ERROR) {
+ // Ignore invalid stream error code if any.
+ error_code = QUIC_STREAM_LAST_ERROR;
+ }
+
+ frame->error_code = static_cast<QuicRstStreamErrorCode>(error_code);
+ return true;
+}
+
+bool QuicFramer::ProcessConnectionCloseFrame(QuicDataReader* reader,
+ QuicConnectionCloseFrame* frame) {
+ uint32_t error_code;
+ if (!reader->ReadUInt32(&error_code)) {
+ set_detailed_error("Unable to read connection close error code.");
+ return false;
+ }
+
+ if (error_code >= QUIC_LAST_ERROR) {
+ // Ignore invalid QUIC error code if any.
+ error_code = QUIC_LAST_ERROR;
+ }
+
+ frame->error_code = static_cast<QuicErrorCode>(error_code);
+
+ StringPiece error_details;
+ if (!reader->ReadStringPiece16(&error_details)) {
+ set_detailed_error("Unable to read connection close error details.");
+ return false;
+ }
+ frame->error_details = error_details.as_string();
+
+ return true;
+}
+
+bool QuicFramer::ProcessGoAwayFrame(QuicDataReader* reader,
+ QuicGoAwayFrame* frame) {
+ uint32_t error_code;
+ if (!reader->ReadUInt32(&error_code)) {
+ set_detailed_error("Unable to read go away error code.");
+ return false;
+ }
+
+ if (error_code >= QUIC_LAST_ERROR) {
+ // Ignore invalid QUIC error code if any.
+ error_code = QUIC_LAST_ERROR;
+ }
+ frame->error_code = static_cast<QuicErrorCode>(error_code);
+
+ uint32_t stream_id;
+ if (!reader->ReadUInt32(&stream_id)) {
+ set_detailed_error("Unable to read last good stream id.");
+ return false;
+ }
+ frame->last_good_stream_id = static_cast<QuicStreamId>(stream_id);
+
+ StringPiece reason_phrase;
+ if (!reader->ReadStringPiece16(&reason_phrase)) {
+ set_detailed_error("Unable to read goaway reason.");
+ return false;
+ }
+ frame->reason_phrase = reason_phrase.as_string();
+
+ return true;
+}
+
+bool QuicFramer::ProcessWindowUpdateFrame(QuicDataReader* reader,
+ QuicWindowUpdateFrame* frame) {
+ if (!reader->ReadUInt32(&frame->stream_id)) {
+ set_detailed_error("Unable to read stream_id.");
+ return false;
+ }
+
+ if (!reader->ReadUInt64(&frame->byte_offset)) {
+ set_detailed_error("Unable to read window byte_offset.");
+ return false;
+ }
+
+ return true;
+}
+
+bool QuicFramer::ProcessBlockedFrame(QuicDataReader* reader,
+ QuicBlockedFrame* frame) {
+ if (!reader->ReadUInt32(&frame->stream_id)) {
+ set_detailed_error("Unable to read stream_id.");
+ return false;
+ }
+
+ return true;
+}
+
+bool QuicFramer::ProcessPathCloseFrame(QuicDataReader* reader,
+ QuicPathCloseFrame* frame) {
+ if (!reader->ReadBytes(&frame->path_id, 1)) {
+ set_detailed_error("Unable to read path_id.");
+ return false;
+ }
+
+ return true;
+}
+
+// static
+StringPiece QuicFramer::GetAssociatedDataFromEncryptedPacket(
+ QuicVersion version,
+ const QuicEncryptedPacket& encrypted,
+ QuicConnectionIdLength connection_id_length,
+ bool includes_version,
+ bool includes_path_id,
+ bool includes_diversification_nonce,
+ QuicPacketNumberLength packet_number_length) {
+ // TODO(ianswett): This is identical to QuicData::AssociatedData.
+ return StringPiece(
+ encrypted.data(),
+ GetStartOfEncryptedData(version, connection_id_length, includes_version,
+ includes_path_id, includes_diversification_nonce,
+ packet_number_length));
+}
+
+void QuicFramer::SetDecrypter(EncryptionLevel level, QuicDecrypter* decrypter) {
+ DCHECK(alternative_decrypter_.get() == nullptr);
+ DCHECK_GE(level, decrypter_level_);
+ decrypter_.reset(decrypter);
+ decrypter_level_ = level;
+}
+
+void QuicFramer::SetAlternativeDecrypter(EncryptionLevel level,
+ QuicDecrypter* decrypter,
+ bool latch_once_used) {
+ alternative_decrypter_.reset(decrypter);
+ alternative_decrypter_level_ = level;
+ alternative_decrypter_latch_ = latch_once_used;
+}
+
+const QuicDecrypter* QuicFramer::decrypter() const {
+ return decrypter_.get();
+}
+
+const QuicDecrypter* QuicFramer::alternative_decrypter() const {
+ return alternative_decrypter_.get();
+}
+
+void QuicFramer::SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter) {
+ DCHECK_GE(level, 0);
+ DCHECK_LT(level, NUM_ENCRYPTION_LEVELS);
+ encrypter_[level].reset(encrypter);
+}
+
+size_t QuicFramer::EncryptInPlace(EncryptionLevel level,
+ QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ size_t ad_len,
+ size_t total_len,
+ size_t buffer_len,
+ char* buffer) {
+ size_t output_length = 0;
+ if (!encrypter_[level]->EncryptPacket(
+ path_id, packet_number,
+ StringPiece(buffer, ad_len), // Associated data
+ StringPiece(buffer + ad_len, total_len - ad_len), // Plaintext
+ buffer + ad_len, // Destination buffer
+ &output_length, buffer_len - ad_len)) {
+ RaiseError(QUIC_ENCRYPTION_FAILURE);
+ return 0;
+ }
+
+ return ad_len + output_length;
+}
+
+size_t QuicFramer::EncryptPayload(EncryptionLevel level,
+ QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ const QuicPacket& packet,
+ char* buffer,
+ size_t buffer_len) {
+ DCHECK(encrypter_[level].get() != nullptr);
+
+ StringPiece associated_data = packet.AssociatedData(quic_version_);
+ // Copy in the header, because the encrypter only populates the encrypted
+ // plaintext content.
+ const size_t ad_len = associated_data.length();
+ memmove(buffer, associated_data.data(), ad_len);
+ // Encrypt the plaintext into the buffer.
+ size_t output_length = 0;
+ if (!encrypter_[level]->EncryptPacket(path_id, packet_number, associated_data,
+ packet.Plaintext(quic_version_),
+ buffer + ad_len, &output_length,
+ buffer_len - ad_len)) {
+ RaiseError(QUIC_ENCRYPTION_FAILURE);
+ return 0;
+ }
+
+ return ad_len + output_length;
+}
+
+size_t QuicFramer::GetMaxPlaintextSize(size_t ciphertext_size) {
+ // In order to keep the code simple, we don't have the current encryption
+ // level to hand. Both the NullEncrypter and AES-GCM have a tag length of 12.
+ size_t min_plaintext_size = ciphertext_size;
+
+ for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; i++) {
+ if (encrypter_[i].get() != nullptr) {
+ size_t size = encrypter_[i]->GetMaxPlaintextSize(ciphertext_size);
+ if (size < min_plaintext_size) {
+ min_plaintext_size = size;
+ }
+ }
+ }
+
+ return min_plaintext_size;
+}
+
+bool QuicFramer::DecryptPayload(QuicDataReader* encrypted_reader,
+ const QuicPacketHeader& header,
+ const QuicEncryptedPacket& packet,
+ char* decrypted_buffer,
+ size_t buffer_length,
+ size_t* decrypted_length) {
+ StringPiece encrypted = encrypted_reader->ReadRemainingPayload();
+ DCHECK(decrypter_.get() != nullptr);
+ StringPiece associated_data = GetAssociatedDataFromEncryptedPacket(
+ quic_version_, packet, header.public_header.connection_id_length,
+ header.public_header.version_flag, header.public_header.multipath_flag,
+ header.public_header.nonce != nullptr,
+ header.public_header.packet_number_length);
+
+ bool success = decrypter_->DecryptPacket(
+ header.path_id, header.packet_number, associated_data, encrypted,
+ decrypted_buffer, decrypted_length, buffer_length);
+ if (success) {
+ visitor_->OnDecryptedPacket(decrypter_level_);
+ } else if (alternative_decrypter_.get() != nullptr) {
+ if (header.public_header.nonce != nullptr) {
+ DCHECK_EQ(perspective_, Perspective::IS_CLIENT);
+ alternative_decrypter_->SetDiversificationNonce(
+ *header.public_header.nonce);
+ }
+ bool try_alternative_decryption = true;
+ if (alternative_decrypter_level_ == ENCRYPTION_INITIAL) {
+ if (perspective_ == Perspective::IS_CLIENT &&
+ quic_version_ > QUIC_VERSION_32) {
+ if (header.public_header.nonce == nullptr) {
+ // Can not use INITIAL decryption without a diversification nonce.
+ try_alternative_decryption = false;
+ }
+ } else {
+ DCHECK(header.public_header.nonce == nullptr);
+ }
+ }
+
+ if (try_alternative_decryption) {
+ success = alternative_decrypter_->DecryptPacket(
+ header.path_id, header.packet_number, associated_data, encrypted,
+ decrypted_buffer, decrypted_length, buffer_length);
+ }
+ if (success) {
+ visitor_->OnDecryptedPacket(alternative_decrypter_level_);
+ if (alternative_decrypter_latch_) {
+ // Switch to the alternative decrypter and latch so that we cannot
+ // switch back.
+ decrypter_.reset(alternative_decrypter_.release());
+ decrypter_level_ = alternative_decrypter_level_;
+ alternative_decrypter_level_ = ENCRYPTION_NONE;
+ } else {
+ // Switch the alternative decrypter so that we use it first next time.
+ decrypter_.swap(alternative_decrypter_);
+ EncryptionLevel level = alternative_decrypter_level_;
+ alternative_decrypter_level_ = decrypter_level_;
+ decrypter_level_ = level;
+ }
+ }
+ }
+
+ if (!success) {
+ DLOG(WARNING) << "DecryptPacket failed for packet_number:"
+ << header.packet_number;
+ return false;
+ }
+
+ return true;
+}
+
+size_t QuicFramer::GetAckFrameTimeStampSize(const QuicAckFrame& ack) {
+ if (ack.received_packet_times.empty()) {
+ return 0;
+ }
+
+ return 5 + 3 * (ack.received_packet_times.size() - 1);
+}
+
+size_t QuicFramer::GetAckFrameSize(
+ const QuicAckFrame& ack,
+ QuicPacketNumberLength packet_number_length) {
+ size_t ack_size = 0;
+ if (quic_version_ <= QUIC_VERSION_33) {
+ AckFrameInfo ack_info = GetAckFrameInfo(ack);
+ QuicPacketNumberLength largest_observed_length =
+ GetMinSequenceNumberLength(ack.largest_observed);
+ QuicPacketNumberLength missing_packet_number_length =
+ GetMinSequenceNumberLength(ack_info.max_delta);
+
+ ack_size = GetMinAckFrameSize(quic_version_, largest_observed_length);
+ if (!ack_info.nack_ranges.empty()) {
+ ack_size += kNumberOfNackRangesSize;
+ if (quic_version_ <= QUIC_VERSION_31) {
+ ack_size += kNumberOfRevivedPacketsSize;
+ }
+ ack_size += min(ack_info.nack_ranges.size(), kMaxNackRanges) *
+ (missing_packet_number_length + PACKET_1BYTE_PACKET_NUMBER);
+ }
+
+ // In version 23, if the ack will be truncated due to too many nack ranges,
+ // then do not include the number of timestamps (1 byte).
+ if (ack_info.nack_ranges.size() <= kMaxNackRanges) {
+ // 1 byte for the number of timestamps.
+ ack_size += 1;
+ ack_size += GetAckFrameTimeStampSize(ack);
+ }
+
+ return ack_size;
+ }
+
+ NewAckFrameInfo ack_info = GetNewAckFrameInfo(ack);
+ QuicPacketNumberLength largest_acked_length =
+ GetMinSequenceNumberLength(ack.largest_observed);
+ QuicPacketNumberLength ack_block_length =
+ GetMinSequenceNumberLength(ack_info.max_block_length);
+
+ ack_size = GetMinAckFrameSize(quic_version_, largest_acked_length);
+ // First ack block length.
+ ack_size += ack_block_length;
+ if (ack_info.num_ack_blocks != 0) {
+ ack_size += kNumberOfAckBlocksSize;
+ ack_size += min(ack_info.num_ack_blocks, kMaxAckBlocks) *
+ (ack_block_length + PACKET_1BYTE_PACKET_NUMBER);
+ }
+
+ // Include timestamps.
+ ack_size += GetAckFrameTimeStampSize(ack);
+
+ return ack_size;
+}
+
+size_t QuicFramer::ComputeFrameLength(
+ const QuicFrame& frame,
+ bool last_frame_in_packet,
+ QuicPacketNumberLength packet_number_length) {
+ switch (frame.type) {
+ case STREAM_FRAME:
+ return GetMinStreamFrameSize(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(quic_version_, packet_number_length);
+ case MTU_DISCOVERY_FRAME:
+ // MTU discovery frames are serialized as ping frames.
+ case PING_FRAME:
+ // Ping has no payload.
+ return kQuicFrameTypeSize;
+ case RST_STREAM_FRAME:
+ return GetRstStreamFrameSize();
+ case CONNECTION_CLOSE_FRAME:
+ return GetMinConnectionCloseFrameSize() +
+ frame.connection_close_frame->error_details.size();
+ case GOAWAY_FRAME:
+ return GetMinGoAwayFrameSize() + frame.goaway_frame->reason_phrase.size();
+ case WINDOW_UPDATE_FRAME:
+ return GetWindowUpdateFrameSize();
+ case BLOCKED_FRAME:
+ return GetBlockedFrameSize();
+ case PATH_CLOSE_FRAME:
+ return GetPathCloseFrameSize();
+ case PADDING_FRAME:
+ DCHECK(false);
+ return 0;
+ case NUM_FRAME_TYPES:
+ DCHECK(false);
+ return 0;
+ }
+
+ // Not reachable, but some Chrome compilers can't figure that out. *sigh*
+ DCHECK(false);
+ return 0;
+}
+
+bool QuicFramer::AppendTypeByte(const QuicFrame& frame,
+ bool no_stream_frame_length,
+ QuicDataWriter* writer) {
+ uint8_t type_byte = 0;
+ switch (frame.type) {
+ case STREAM_FRAME: {
+ if (frame.stream_frame == nullptr) {
+ QUIC_BUG << "Failed to append STREAM frame with no stream_frame.";
+ }
+ // Fin bit.
+ type_byte |= frame.stream_frame->fin ? kQuicStreamFinMask : 0;
+
+ // Data Length bit.
+ type_byte <<= kQuicStreamDataLengthShift;
+ type_byte |= no_stream_frame_length ? 0 : kQuicStreamDataLengthMask;
+
+ // Offset 3 bits.
+ type_byte <<= kQuicStreamOffsetShift;
+ const size_t offset_len = GetStreamOffsetSize(frame.stream_frame->offset);
+ if (offset_len > 0) {
+ type_byte |= offset_len - 1;
+ }
+
+ // stream id 2 bits.
+ type_byte <<= kQuicStreamIdShift;
+ type_byte |= GetStreamIdSize(frame.stream_frame->stream_id) - 1;
+ type_byte |= kQuicFrameTypeStreamMask; // Set Stream Frame Type to 1.
+ break;
+ }
+ case ACK_FRAME:
+ return true;
+ case MTU_DISCOVERY_FRAME:
+ type_byte = static_cast<uint8_t>(PING_FRAME);
+ break;
+ default:
+ type_byte = static_cast<uint8_t>(frame.type);
+ break;
+ }
+
+ return writer->WriteUInt8(type_byte);
+}
+
+// static
+bool QuicFramer::AppendPacketSequenceNumber(
+ QuicPacketNumberLength packet_number_length,
+ QuicPacketNumber packet_number,
+ QuicDataWriter* writer) {
+ // Ensure the entire packet number can be written.
+ if (writer->capacity() - writer->length() <
+ static_cast<size_t>(packet_number_length)) {
+ return false;
+ }
+ switch (packet_number_length) {
+ case PACKET_1BYTE_PACKET_NUMBER:
+ return writer->WriteUInt8(packet_number & k1ByteSequenceNumberMask);
+ break;
+ case PACKET_2BYTE_PACKET_NUMBER:
+ return writer->WriteUInt16(packet_number & k2ByteSequenceNumberMask);
+ break;
+ case PACKET_4BYTE_PACKET_NUMBER:
+ return writer->WriteUInt32(packet_number & k4ByteSequenceNumberMask);
+ break;
+ case PACKET_6BYTE_PACKET_NUMBER:
+ return writer->WriteUInt48(packet_number & k6ByteSequenceNumberMask);
+ break;
+ default:
+ DCHECK(false) << "packet_number_length: " << packet_number_length;
+ return false;
+ }
+}
+
+// static
+bool QuicFramer::AppendAckBlock(uint8_t gap,
+ QuicPacketNumberLength length_length,
+ QuicPacketNumber length,
+ QuicDataWriter* writer) {
+ return AppendPacketSequenceNumber(PACKET_1BYTE_PACKET_NUMBER, gap, writer) &&
+ AppendPacketSequenceNumber(length_length, length, writer);
+}
+
+bool QuicFramer::AppendStreamFrame(const QuicStreamFrame& frame,
+ bool no_stream_frame_length,
+ QuicDataWriter* writer) {
+ if (!writer->WriteBytes(&frame.stream_id, GetStreamIdSize(frame.stream_id))) {
+ QUIC_BUG << "Writing stream id size failed.";
+ return false;
+ }
+ if (!writer->WriteBytes(&frame.offset, GetStreamOffsetSize(frame.offset))) {
+ QUIC_BUG << "Writing offset size failed.";
+ return false;
+ }
+ if (!no_stream_frame_length) {
+ if ((frame.data_length > numeric_limits<uint16_t>::max()) ||
+ !writer->WriteUInt16(static_cast<uint16_t>(frame.data_length))) {
+ QUIC_BUG << "Writing stream frame length failed";
+ return false;
+ }
+ }
+
+ if (!writer->WriteBytes(frame.data_buffer, frame.data_length)) {
+ QUIC_BUG << "Writing frame data failed.";
+ return false;
+ }
+ return true;
+}
+
+void QuicFramer::set_version(const QuicVersion version) {
+ DCHECK(IsSupportedVersion(version)) << QuicVersionToString(version);
+ quic_version_ = version;
+}
+
+bool QuicFramer::AppendAckFrameAndTypeByte(const QuicPacketHeader& header,
+ const QuicAckFrame& frame,
+ QuicDataWriter* writer) {
+ AckFrameInfo ack_info = GetAckFrameInfo(frame);
+ QuicPacketNumber ack_largest_observed = frame.largest_observed;
+ QuicPacketNumberLength largest_observed_length =
+ GetMinSequenceNumberLength(ack_largest_observed);
+ QuicPacketNumberLength missing_packet_number_length =
+ GetMinSequenceNumberLength(ack_info.max_delta);
+ // Determine whether we need to truncate ranges.
+ size_t available_range_bytes =
+ writer->capacity() - writer->length() - kNumberOfNackRangesSize -
+ GetMinAckFrameSize(quic_version_, largest_observed_length);
+ if (quic_version_ <= QUIC_VERSION_31) {
+ available_range_bytes -= kNumberOfRevivedPacketsSize;
+ }
+ size_t max_num_ranges =
+ available_range_bytes /
+ (missing_packet_number_length + PACKET_1BYTE_PACKET_NUMBER);
+ max_num_ranges = min(kMaxNackRanges, max_num_ranges);
+ bool truncated = ack_info.nack_ranges.size() > max_num_ranges;
+ DVLOG_IF(1, truncated) << "Truncating ack from "
+ << ack_info.nack_ranges.size() << " ranges to "
+ << max_num_ranges;
+ // Write out the type byte by setting the low order bits and doing shifts
+ // to make room for the next bit flags to be set.
+ // Whether there are any nacks.
+ uint8_t type_byte = ack_info.nack_ranges.empty() ? 0 : kQuicHasNacksMask;
+
+ // truncating bit.
+ type_byte <<= kQuicAckTruncatedShift;
+ type_byte |= truncated ? kQuicAckTruncatedMask : 0;
+
+ // Largest observed packet number length.
+ type_byte <<= kQuicSequenceNumberLengthShift;
+ type_byte |= GetSequenceNumberFlags(largest_observed_length);
+
+ // Missing packet number length.
+ type_byte <<= kQuicSequenceNumberLengthShift;
+ type_byte |= GetSequenceNumberFlags(missing_packet_number_length);
+
+ type_byte |= kQuicFrameTypeAckMask;
+
+ if (!writer->WriteUInt8(type_byte)) {
+ QUIC_BUG << "type byte failed";
+ return false;
+ }
+
+ QuicPacketEntropyHash ack_entropy_hash = frame.entropy_hash;
+ NackRangeMap::reverse_iterator ack_iter = ack_info.nack_ranges.rbegin();
+ if (truncated) {
+ // Skip the nack ranges which the truncated ack won't include and set
+ // a correct largest observed for the truncated ack.
+ for (size_t i = 1; i < (ack_info.nack_ranges.size() - max_num_ranges);
+ ++i) {
+ ++ack_iter;
+ }
+ // If the last range is followed by acks, include them.
+ // If the last range is followed by another range, specify the end of the
+ // range as the largest_observed.
+ ack_largest_observed = ack_iter->first - 1;
+ // Also update the entropy so it matches the largest observed.
+ ack_entropy_hash = entropy_calculator_->EntropyHash(ack_largest_observed);
+ ++ack_iter;
+ }
+
+ if (!writer->WriteUInt8(ack_entropy_hash)) {
+ QUIC_BUG << "hash failed.";
+ return false;
+ }
+
+ if (!AppendPacketSequenceNumber(largest_observed_length, ack_largest_observed,
+ writer)) {
+ QUIC_BUG << "AppendPacketSequenceNumber failed. "
+ << "largest_observed_length: " << largest_observed_length
+ << " ack_largest_observed: " << ack_largest_observed;
+ return false;
+ }
+
+ uint64_t ack_delay_time_us = kUFloat16MaxValue;
+ if (!frame.ack_delay_time.IsInfinite()) {
+ DCHECK_LE(0u, frame.ack_delay_time.ToMicroseconds());
+ ack_delay_time_us = frame.ack_delay_time.ToMicroseconds();
+ }
+
+ if (!writer->WriteUFloat16(ack_delay_time_us)) {
+ QUIC_BUG << "ack delay time failed.";
+ return false;
+ }
+
+ // Timestamp goes at the end of the required fields.
+ if (!truncated) {
+ if (!AppendTimestampToAckFrame(frame, writer)) {
+ QUIC_BUG << "AppendTimestampToAckFrame failed";
+ return false;
+ }
+ }
+
+ if (ack_info.nack_ranges.empty()) {
+ return true;
+ }
+
+ const uint8_t num_missing_ranges =
+ static_cast<uint8_t>(min(ack_info.nack_ranges.size(), max_num_ranges));
+ if (!writer->WriteBytes(&num_missing_ranges, 1)) {
+ QUIC_BUG << "num_missing_ranges failed: "
+ << static_cast<uint32_t>(num_missing_ranges);
+ return false;
+ }
+
+ int num_ranges_written = 0;
+ QuicPacketNumber last_sequence_written = ack_largest_observed;
+ for (; ack_iter != ack_info.nack_ranges.rend(); ++ack_iter) {
+ // Calculate the delta to the last number in the range.
+ QuicPacketNumber missing_delta =
+ last_sequence_written - (ack_iter->first + ack_iter->second);
+ if (!AppendPacketSequenceNumber(missing_packet_number_length, missing_delta,
+ writer)) {
+ QUIC_BUG << "AppendPacketSequenceNumber failed: "
+ << "missing_packet_number_length: "
+ << missing_packet_number_length << " missing_delta "
+ << missing_delta;
+ return false;
+ }
+ if (!AppendPacketSequenceNumber(PACKET_1BYTE_PACKET_NUMBER,
+ ack_iter->second, writer)) {
+ QUIC_BUG << "AppendPacketSequenceNumber failed";
+ return false;
+ }
+ // Subtract 1 so a missing_delta of 0 means an adjacent range.
+ last_sequence_written = ack_iter->first - 1;
+ ++num_ranges_written;
+ }
+ DCHECK_EQ(num_missing_ranges, num_ranges_written);
+
+ if (quic_version_ > QUIC_VERSION_31) {
+ return true;
+ }
+
+ // Append revived packets.
+ // FEC is not supported.
+ uint8_t num_revived_packets = 0;
+ if (!writer->WriteBytes(&num_revived_packets, 1)) {
+ QUIC_BUG << "num_revived_packets failed: " << num_revived_packets;
+ return false;
+ }
+
+ return true;
+}
+
+bool QuicFramer::AppendNewAckFrameAndTypeByte(const QuicAckFrame& frame,
+ QuicDataWriter* writer) {
+ const NewAckFrameInfo new_ack_info = GetNewAckFrameInfo(frame);
+ QuicPacketNumber largest_acked = frame.largest_observed;
+ QuicPacketNumberLength largest_acked_length =
+ GetMinSequenceNumberLength(largest_acked);
+ QuicPacketNumberLength ack_block_length =
+ GetMinSequenceNumberLength(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(quic_version_, largest_acked_length) -
+ (new_ack_info.num_ack_blocks != 0 ? kNumberOfAckBlocksSize : 0);
+ DCHECK_LE(0, available_timestamp_and_ack_block_bytes);
+
+ // Write out the type byte by setting the low order bits and doing shifts
+ // to make room for the next bit flags to be set.
+ // Whether there are multiple ack blocks.
+ uint8_t type_byte =
+ new_ack_info.num_ack_blocks == 0 ? 0 : kQuicHasMultipleAckBlocksMask;
+ type_byte <<= kQuicHasMultipleAckBlocksShift;
+
+ // Largest acked length.
+ type_byte <<= kQuicSequenceNumberLengthShift;
+ type_byte |= GetSequenceNumberFlags(largest_acked_length);
+
+ // Ack block length.
+ type_byte <<= kQuicSequenceNumberLengthShift;
+ type_byte |= GetSequenceNumberFlags(ack_block_length);
+
+ type_byte |= kQuicFrameTypeAckMask;
+
+ if (!writer->WriteUInt8(type_byte)) {
+ return false;
+ }
+
+ // Largest acked.
+ if (!AppendPacketSequenceNumber(largest_acked_length, largest_acked,
+ writer)) {
+ return false;
+ }
+
+ // Largest acked delta time.
+ uint64_t ack_delay_time_us = kUFloat16MaxValue;
+ if (!frame.ack_delay_time.IsInfinite()) {
+ DCHECK_LE(0u, frame.ack_delay_time.ToMicroseconds());
+ ack_delay_time_us = frame.ack_delay_time.ToMicroseconds();
+ }
+ if (!writer->WriteUFloat16(ack_delay_time_us)) {
+ return false;
+ }
+
+ size_t max_num_ack_blocks = available_timestamp_and_ack_block_bytes /
+ (ack_block_length + PACKET_1BYTE_PACKET_NUMBER);
+
+ // Number of ack blocks.
+ size_t num_ack_blocks = min(new_ack_info.num_ack_blocks, max_num_ack_blocks);
+ if (num_ack_blocks > numeric_limits<uint8_t>::max()) {
+ num_ack_blocks = numeric_limits<uint8_t>::max();
+ }
+
+ if (num_ack_blocks > 0) {
+ if (!writer->WriteBytes(&num_ack_blocks, 1)) {
+ return false;
+ }
+ }
+
+ // First ack block length.
+ if (!AppendPacketSequenceNumber(ack_block_length,
+ new_ack_info.first_block_length, writer)) {
+ return false;
+ }
+
+ // Ack blocks.
+ if (num_ack_blocks > 0) {
+ size_t num_ack_blocks_written = 0;
+ // Append, in descending order from the largest ACKed packet, a series of
+ // ACK blocks that represents the successfully acknoweldged packets. Each
+ // appended gap/block length represents a descending delta from the previous
+ // block. i.e.:
+ // |--- length ---|--- gap ---|--- length ---|--- gap ---|--- largest ---|
+ // For gaps larger than can be represented by a single encoded gap, a 0
+ // length gap of the maximum is used, i.e.:
+ // |--- length ---|--- gap ---|- 0 -|--- gap ---|--- largest ---|
+ auto itr = frame.packets.rbegin();
+ QuicPacketNumber previous_start = itr->min();
+ ++itr;
+
+ for (;
+ itr != frame.packets.rend() && num_ack_blocks_written < num_ack_blocks;
+ previous_start = itr->min(), ++itr) {
+ const auto& interval = *itr;
+ const QuicPacketNumber total_gap = previous_start - interval.max();
+ const size_t num_encoded_gaps =
+ (total_gap + numeric_limits<uint8_t>::max() - 1) /
+ numeric_limits<uint8_t>::max();
+ DCHECK_GT(num_encoded_gaps, 0u);
+
+ // Append empty ACK blocks because the gap is longer than a single gap.
+ for (size_t i = 1;
+ i < num_encoded_gaps && num_ack_blocks_written < num_ack_blocks;
+ ++i) {
+ if (!AppendAckBlock(numeric_limits<uint8_t>::max(), ack_block_length, 0,
+ writer)) {
+ return false;
+ }
+ ++num_ack_blocks_written;
+ }
+ if (num_ack_blocks_written >= num_ack_blocks) {
+ if (PREDICT_FALSE(num_ack_blocks_written != num_ack_blocks)) {
+ QUIC_BUG << "Wrote " << num_ack_blocks_written
+ << ", expected to write " << num_ack_blocks;
+ }
+ break;
+ }
+
+ const uint8_t last_gap =
+ total_gap - (num_encoded_gaps - 1) * numeric_limits<uint8_t>::max();
+ // Append the final ACK block with a non-empty size.
+ if (!AppendAckBlock(last_gap, ack_block_length, interval.Length(),
+ writer)) {
+ return false;
+ }
+ ++num_ack_blocks_written;
+ }
+ DCHECK_EQ(num_ack_blocks, num_ack_blocks_written);
+ }
+
+ // Timestamps.
+ // If we don't have enough available space to append all the timestamps, don't
+ // append any of them.
+ if (writer->capacity() - writer->length() >=
+ GetAckFrameTimeStampSize(frame)) {
+ if (!AppendTimestampToAckFrame(frame, writer)) {
+ return false;
+ }
+ } else {
+ uint8_t num_received_packets = 0;
+ if (!writer->WriteBytes(&num_received_packets, 1)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool QuicFramer::AppendTimestampToAckFrame(const QuicAckFrame& frame,
+ QuicDataWriter* writer) {
+ DCHECK_GE(numeric_limits<uint8_t>::max(), frame.received_packet_times.size());
+ // num_received_packets is only 1 byte.
+ if (frame.received_packet_times.size() > numeric_limits<uint8_t>::max()) {
+ return false;
+ }
+
+ uint8_t num_received_packets = frame.received_packet_times.size();
+ if (!writer->WriteBytes(&num_received_packets, 1)) {
+ return false;
+ }
+ if (num_received_packets == 0) {
+ return true;
+ }
+
+ PacketTimeVector::const_iterator it = frame.received_packet_times.begin();
+ QuicPacketNumber packet_number = it->first;
+ QuicPacketNumber delta_from_largest_observed =
+ frame.largest_observed - packet_number;
+
+ DCHECK_GE(numeric_limits<uint8_t>::max(), delta_from_largest_observed);
+ if (delta_from_largest_observed > numeric_limits<uint8_t>::max()) {
+ return false;
+ }
+
+ if (!writer->WriteUInt8(delta_from_largest_observed &
+ k1ByteSequenceNumberMask)) {
+ return false;
+ }
+
+ // Use the lowest 4 bytes of the time delta from the creation_time_.
+ const uint64_t time_epoch_delta_us = UINT64_C(1) << 32;
+ uint32_t time_delta_us =
+ static_cast<uint32_t>((it->second - creation_time_).ToMicroseconds() &
+ (time_epoch_delta_us - 1));
+ if (!writer->WriteBytes(&time_delta_us, sizeof(time_delta_us))) {
+ return false;
+ }
+
+ QuicTime prev_time = it->second;
+
+ for (++it; it != frame.received_packet_times.end(); ++it) {
+ packet_number = it->first;
+ delta_from_largest_observed = frame.largest_observed - packet_number;
+
+ if (delta_from_largest_observed > numeric_limits<uint8_t>::max()) {
+ return false;
+ }
+
+ if (!writer->WriteUInt8(delta_from_largest_observed &
+ k1ByteSequenceNumberMask)) {
+ return false;
+ }
+
+ uint64_t frame_time_delta_us = (it->second - prev_time).ToMicroseconds();
+ prev_time = it->second;
+ if (!writer->WriteUFloat16(frame_time_delta_us)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool QuicFramer::AppendStopWaitingFrame(const QuicPacketHeader& header,
+ const QuicStopWaitingFrame& frame,
+ QuicDataWriter* writer) {
+ DCHECK_GE(header.packet_number, frame.least_unacked);
+ const QuicPacketNumber least_unacked_delta =
+ header.packet_number - frame.least_unacked;
+ const QuicPacketNumber length_shift =
+ header.public_header.packet_number_length * 8;
+ if (quic_version_ <= QUIC_VERSION_33) {
+ if (!writer->WriteUInt8(frame.entropy_hash)) {
+ QUIC_BUG << " hash failed";
+ return false;
+ }
+ }
+
+ if (least_unacked_delta >> length_shift > 0) {
+ QUIC_BUG << "packet_number_length "
+ << header.public_header.packet_number_length
+ << " is too small for least_unacked_delta: " << least_unacked_delta
+ << " packet_number:" << header.packet_number
+ << " least_unacked:" << frame.least_unacked
+ << " version:" << quic_version_;
+ return false;
+ }
+ if (!AppendPacketSequenceNumber(header.public_header.packet_number_length,
+ least_unacked_delta, writer)) {
+ QUIC_BUG << " seq failed: " << header.public_header.packet_number_length;
+ return false;
+ }
+
+ return true;
+}
+
+bool QuicFramer::AppendRstStreamFrame(const QuicRstStreamFrame& frame,
+ QuicDataWriter* writer) {
+ if (!writer->WriteUInt32(frame.stream_id)) {
+ return false;
+ }
+
+ if (!writer->WriteUInt64(frame.byte_offset)) {
+ return false;
+ }
+
+ uint32_t error_code = static_cast<uint32_t>(frame.error_code);
+ if (!writer->WriteUInt32(error_code)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool QuicFramer::AppendConnectionCloseFrame(
+ const QuicConnectionCloseFrame& frame,
+ QuicDataWriter* writer) {
+ uint32_t error_code = static_cast<uint32_t>(frame.error_code);
+ if (!writer->WriteUInt32(error_code)) {
+ return false;
+ }
+ if (!writer->WriteStringPiece16(frame.error_details)) {
+ return false;
+ }
+ return true;
+}
+
+bool QuicFramer::AppendGoAwayFrame(const QuicGoAwayFrame& frame,
+ QuicDataWriter* writer) {
+ uint32_t error_code = static_cast<uint32_t>(frame.error_code);
+ if (!writer->WriteUInt32(error_code)) {
+ return false;
+ }
+ uint32_t stream_id = static_cast<uint32_t>(frame.last_good_stream_id);
+ if (!writer->WriteUInt32(stream_id)) {
+ return false;
+ }
+ if (!writer->WriteStringPiece16(frame.reason_phrase)) {
+ return false;
+ }
+ return true;
+}
+
+bool QuicFramer::AppendWindowUpdateFrame(const QuicWindowUpdateFrame& frame,
+ QuicDataWriter* writer) {
+ uint32_t stream_id = static_cast<uint32_t>(frame.stream_id);
+ if (!writer->WriteUInt32(stream_id)) {
+ return false;
+ }
+ if (!writer->WriteUInt64(frame.byte_offset)) {
+ return false;
+ }
+ return true;
+}
+
+bool QuicFramer::AppendBlockedFrame(const QuicBlockedFrame& frame,
+ QuicDataWriter* writer) {
+ uint32_t stream_id = static_cast<uint32_t>(frame.stream_id);
+ if (!writer->WriteUInt32(stream_id)) {
+ return false;
+ }
+ return true;
+}
+
+bool QuicFramer::AppendPathCloseFrame(const QuicPathCloseFrame& frame,
+ QuicDataWriter* writer) {
+ uint8_t path_id = static_cast<uint8_t>(frame.path_id);
+ if (!writer->WriteUInt8(path_id)) {
+ return false;
+ }
+ return true;
+}
+
+bool QuicFramer::RaiseError(QuicErrorCode error) {
+ DVLOG(1) << "Error: " << QuicUtils::ErrorToString(error)
+ << " detail: " << detailed_error_;
+ set_error(error);
+ visitor_->OnError(this);
+ return false;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_framer.h b/chromium/net/quic/core/quic_framer.h
new file mode 100644
index 00000000000..55d32262fa7
--- /dev/null
+++ b/chromium/net/quic/core/quic_framer.h
@@ -0,0 +1,629 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_FRAMER_H_
+#define NET_QUIC_QUIC_FRAMER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+namespace test {
+class QuicFramerPeer;
+} // namespace test
+
+class QuicDataReader;
+class QuicDataWriter;
+class QuicDecrypter;
+class QuicEncrypter;
+class QuicFramer;
+
+// Number of bytes reserved for the frame type preceding each frame.
+const size_t kQuicFrameTypeSize = 1;
+// Number of bytes reserved for error code.
+const size_t kQuicErrorCodeSize = 4;
+// Number of bytes reserved to denote the length of error details field.
+const size_t kQuicErrorDetailsLengthSize = 2;
+
+// Maximum number of bytes reserved for stream id.
+const size_t kQuicMaxStreamIdSize = 4;
+// Maximum number of bytes reserved for byte offset in stream frame.
+const size_t kQuicMaxStreamOffsetSize = 8;
+// Number of bytes reserved to store payload length in stream frame.
+const size_t kQuicStreamPayloadLengthSize = 2;
+
+// Size in bytes of the entropy hash sent in ack frames.
+const size_t kQuicEntropyHashSize = 1;
+// Size in bytes reserved for the delta time of the largest observed
+// packet number in ack frames.
+const size_t kQuicDeltaTimeLargestObservedSize = 2;
+// Size in bytes reserved for the number of received packets with timestamps.
+const size_t kQuicNumTimestampsSize = 1;
+// Size in bytes reserved for the number of missing packets in ack frames.
+const size_t kNumberOfNackRangesSize = 1;
+// Size in bytes reserved for the number of ack blocks in ack frames.
+const size_t kNumberOfAckBlocksSize = 1;
+// Maximum number of missing packet ranges that can fit within an ack frame.
+const size_t kMaxNackRanges = (1 << (kNumberOfNackRangesSize * 8)) - 1;
+// Maximum number of ack blocks that can fit within an ack frame.
+const size_t kMaxAckBlocks = (1 << (kNumberOfAckBlocksSize * 8)) - 1;
+// Size in bytes reserved for the number of revived packets in ack frames.
+const size_t kNumberOfRevivedPacketsSize = 1;
+
+// This class receives callbacks from the framer when packets
+// are processed.
+class NET_EXPORT_PRIVATE QuicFramerVisitorInterface {
+ public:
+ virtual ~QuicFramerVisitorInterface() {}
+
+ // Called if an error is detected in the QUIC protocol.
+ virtual void OnError(QuicFramer* framer) = 0;
+
+ // Called only when |perspective_| is IS_SERVER and the the framer gets a
+ // packet with version flag true and the version on the packet doesn't match
+ // |quic_version_|. The visitor should return true after it updates the
+ // version of the |framer_| to |received_version| or false to stop processing
+ // this packet.
+ virtual bool OnProtocolVersionMismatch(QuicVersion received_version) = 0;
+
+ // Called when a new packet has been received, before it
+ // has been validated or processed.
+ virtual void OnPacket() = 0;
+
+ // Called when a public reset packet has been parsed but has not yet
+ // been validated.
+ virtual void OnPublicResetPacket(const QuicPublicResetPacket& packet) = 0;
+
+ // Called only when |perspective_| is IS_CLIENT and a version negotiation
+ // packet has been parsed.
+ virtual void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) = 0;
+
+ // Called when the public header has been parsed, but has not been
+ // authenticated. If it returns false, framing for this packet will cease.
+ virtual bool OnUnauthenticatedPublicHeader(
+ const QuicPacketPublicHeader& header) = 0;
+
+ // Called when the unauthenticated portion of the header has been parsed.
+ // If OnUnauthenticatedHeader returns false, framing for this packet will
+ // cease.
+ virtual bool OnUnauthenticatedHeader(const QuicPacketHeader& header) = 0;
+
+ // Called when a packet has been decrypted. |level| is the encryption level
+ // of the packet.
+ virtual void OnDecryptedPacket(EncryptionLevel level) = 0;
+
+ // Called when the complete header of a packet had been parsed.
+ // If OnPacketHeader returns false, framing for this packet will cease.
+ virtual bool OnPacketHeader(const QuicPacketHeader& header) = 0;
+
+ // Called when a StreamFrame has been parsed.
+ virtual bool OnStreamFrame(const QuicStreamFrame& frame) = 0;
+
+ // Called when a AckFrame has been parsed. If OnAckFrame returns false,
+ // the framer will stop parsing the current packet.
+ virtual bool OnAckFrame(const QuicAckFrame& frame) = 0;
+
+ // Called when a StopWaitingFrame has been parsed.
+ virtual bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) = 0;
+
+ // Called when a QuicPaddingFrame has been parsed.
+ virtual bool OnPaddingFrame(const QuicPaddingFrame& frame) = 0;
+
+ // Called when a PingFrame has been parsed.
+ virtual bool OnPingFrame(const QuicPingFrame& frame) = 0;
+
+ // Called when a RstStreamFrame has been parsed.
+ virtual bool OnRstStreamFrame(const QuicRstStreamFrame& frame) = 0;
+
+ // Called when a ConnectionCloseFrame has been parsed.
+ virtual bool OnConnectionCloseFrame(
+ const QuicConnectionCloseFrame& frame) = 0;
+
+ // Called when a GoAwayFrame has been parsed.
+ virtual bool OnGoAwayFrame(const QuicGoAwayFrame& frame) = 0;
+
+ // Called when a WindowUpdateFrame has been parsed.
+ virtual bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) = 0;
+
+ // Called when a BlockedFrame has been parsed.
+ virtual bool OnBlockedFrame(const QuicBlockedFrame& frame) = 0;
+
+ // Called when a PathCloseFrame has been parsed.
+ virtual bool OnPathCloseFrame(const QuicPathCloseFrame& frame) = 0;
+
+ // Called when a packet has been completely processed.
+ virtual void OnPacketComplete() = 0;
+};
+
+// This class calculates the received entropy of the ack packet being
+// framed, should it get truncated.
+class NET_EXPORT_PRIVATE QuicReceivedEntropyHashCalculatorInterface {
+ public:
+ virtual ~QuicReceivedEntropyHashCalculatorInterface() {}
+
+ // When an ack frame gets truncated while being framed the received
+ // entropy of the ack frame needs to be calculated since the some of the
+ // missing packets are not added and the largest observed might be lowered.
+ // This should return the received entropy hash of the packets received up to
+ // and including |packet_number|.
+ virtual QuicPacketEntropyHash EntropyHash(
+ QuicPacketNumber packet_number) const = 0;
+};
+
+// Class for parsing and constructing QUIC packets. It has a
+// QuicFramerVisitorInterface that is called when packets are parsed.
+class NET_EXPORT_PRIVATE QuicFramer {
+ public:
+ // Constructs a new framer that installs a kNULL QuicEncrypter and
+ // 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 QuicVersionVector& supported_versions,
+ QuicTime creation_time,
+ Perspective perspective);
+
+ virtual ~QuicFramer();
+
+ // Returns true if |version| is a supported protocol version.
+ bool IsSupportedVersion(const QuicVersion 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
+ // to do nothing. If this is called multiple times, only the last visitor
+ // will be used.
+ void set_visitor(QuicFramerVisitorInterface* visitor) { visitor_ = visitor; }
+
+ const QuicVersionVector& supported_versions() const {
+ return supported_versions_;
+ }
+
+ QuicVersion version() const { return quic_version_; }
+
+ void set_version(const QuicVersion version);
+
+ // Does not DCHECK for supported version. Used by tests to set unsupported
+ // version to trigger version negotiation.
+ void set_version_for_tests(const QuicVersion version) {
+ quic_version_ = version;
+ }
+
+ // Set entropy calculator to be called from the framer when it needs the
+ // entropy of a truncated ack frame. An entropy calculator must be set or else
+ // the framer will likely crash. If this is called multiple times, only the
+ // last calculator will be used.
+ void set_received_entropy_calculator(
+ QuicReceivedEntropyHashCalculatorInterface* entropy_calculator) {
+ entropy_calculator_ = entropy_calculator;
+ }
+
+ QuicErrorCode error() const { return error_; }
+
+ // Pass a UDP packet into the framer for parsing.
+ // Return true if the packet was processed succesfully. |packet| must be a
+ // single, complete UDP packet (not a frame of a packet). This packet
+ // might be null padded past the end of the payload, which will be correctly
+ // ignored.
+ bool ProcessPacket(const QuicEncryptedPacket& packet);
+
+ // Largest size in bytes of all stream frame fields without the payload.
+ static size_t GetMinStreamFrameSize(QuicStreamId stream_id,
+ QuicStreamOffset offset,
+ bool last_frame_in_packet);
+ // Size in bytes of all ack frame fields without the missing packets or ack
+ // blocks.
+ static size_t GetMinAckFrameSize(
+ QuicVersion version,
+ QuicPacketNumberLength largest_observed_length);
+ // Size in bytes of a stop waiting frame.
+ static size_t GetStopWaitingFrameSize(
+ QuicVersion version,
+ QuicPacketNumberLength packet_number_length);
+ // Size in bytes of all reset stream frame fields.
+ static size_t GetRstStreamFrameSize();
+ // Size in bytes of all connection close frame fields without the error
+ // details and the missing packets from the enclosed ack frame.
+ static size_t GetMinConnectionCloseFrameSize();
+ // Size in bytes of all GoAway frame fields without the reason phrase.
+ static size_t GetMinGoAwayFrameSize();
+ // Size in bytes of all WindowUpdate frame fields.
+ static size_t GetWindowUpdateFrameSize();
+ // Size in bytes of all Blocked frame fields.
+ static size_t GetBlockedFrameSize();
+ // Size in bytes of all PathClose frame fields.
+ static size_t GetPathCloseFrameSize();
+ // Size in bytes required to serialize the stream id.
+ static size_t GetStreamIdSize(QuicStreamId stream_id);
+ // Size in bytes required to serialize the stream offset.
+ static size_t GetStreamOffsetSize(QuicStreamOffset offset);
+ // Size in bytes required for a serialized version negotiation packet
+ static size_t GetVersionNegotiationPacketSize(size_t number_versions);
+
+ // Returns the number of bytes added to the packet for the specified frame,
+ // and 0 if the frame doesn't fit. Includes the header size for the first
+ // frame.
+ size_t GetSerializedFrameLength(const QuicFrame& frame,
+ size_t free_bytes,
+ bool first_frame_in_packet,
+ bool last_frame_in_packet,
+ QuicPacketNumberLength packet_number_length);
+
+ // Returns the associated data from the encrypted packet |encrypted| as a
+ // stringpiece.
+ static base::StringPiece GetAssociatedDataFromEncryptedPacket(
+ QuicVersion version,
+ const QuicEncryptedPacket& encrypted,
+ QuicConnectionIdLength connection_id_length,
+ bool includes_version,
+ bool includes_path_id,
+ bool includes_diversification_nonce,
+ QuicPacketNumberLength packet_number_length);
+
+ // Serializes a packet containing |frames| into |buffer|.
+ // Returns the length of the packet, which must not be longer than
+ // |packet_length|. Returns 0 if it fails to serialize.
+ size_t BuildDataPacket(const QuicPacketHeader& header,
+ const QuicFrames& frames,
+ char* buffer,
+ size_t packet_length);
+
+ // Returns a new public reset packet, owned by the caller.
+ static QuicEncryptedPacket* BuildPublicResetPacket(
+ const QuicPublicResetPacket& packet);
+
+ // Returns a new version negotiation packet, owned by the caller.
+ static QuicEncryptedPacket* BuildVersionNegotiationPacket(
+ QuicConnectionId connection_id,
+ const QuicVersionVector& versions);
+
+ // If header.public_header.version_flag is set, the version in the
+ // packet will be set -- but it will be set from quic_version_ not
+ // header.public_header.versions.
+ bool AppendPacketHeader(const QuicPacketHeader& header,
+ QuicDataWriter* writer);
+ bool AppendTypeByte(const QuicFrame& frame,
+ bool last_frame_in_packet,
+ QuicDataWriter* writer);
+ bool AppendStreamFrame(const QuicStreamFrame& frame,
+ bool last_frame_in_packet,
+ QuicDataWriter* builder);
+
+ // SetDecrypter sets the primary decrypter, replacing any that already exists,
+ // and takes ownership. If an alternative decrypter is in place then the
+ // function DCHECKs. This is intended for cases where one knows that future
+ // packets will be using the new decrypter and the previous decrypter is now
+ // obsolete. |level| indicates the encryption level of the new decrypter.
+ void SetDecrypter(EncryptionLevel level, QuicDecrypter* decrypter);
+
+ // SetAlternativeDecrypter sets a decrypter that may be used to decrypt
+ // future packets and takes ownership of it. |level| indicates the encryption
+ // level of the decrypter. If |latch_once_used| is true, then the first time
+ // that the decrypter is successful it will replace the primary decrypter.
+ // Otherwise both decrypters will remain active and the primary decrypter
+ // will be the one last used.
+ void SetAlternativeDecrypter(EncryptionLevel level,
+ QuicDecrypter* decrypter,
+ bool latch_once_used);
+
+ const QuicDecrypter* decrypter() const;
+ const QuicDecrypter* alternative_decrypter() const;
+
+ // Changes the encrypter used for level |level| to |encrypter|. The function
+ // takes ownership of |encrypter|.
+ void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter);
+
+ // Encrypts a payload in |buffer|. |ad_len| is the length of the associated
+ // data. |total_len| is the length of the associated data plus plaintext.
+ // |buffer_len| is the full length of the allocated buffer.
+ size_t EncryptInPlace(EncryptionLevel level,
+ QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ size_t ad_len,
+ size_t total_len,
+ size_t buffer_len,
+ char* buffer);
+
+ // Returns the length of the data encrypted into |buffer| if |buffer_len| is
+ // long enough, and otherwise 0.
+ size_t EncryptPayload(EncryptionLevel level,
+ QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ const QuicPacket& packet,
+ char* buffer,
+ size_t buffer_len);
+
+ // Returns the maximum length of plaintext that can be encrypted
+ // to ciphertext no larger than |ciphertext_size|.
+ size_t GetMaxPlaintextSize(size_t ciphertext_size);
+
+ const std::string& detailed_error() { return detailed_error_; }
+
+ // The minimum packet number length required to represent |packet_number|.
+ static QuicPacketNumberLength GetMinSequenceNumberLength(
+ QuicPacketNumber packet_number);
+
+ void SetSupportedVersions(const QuicVersionVector& versions) {
+ supported_versions_ = versions;
+ quic_version_ = versions[0];
+ }
+
+ void set_validate_flags(bool value) { validate_flags_ = value; }
+
+ Perspective perspective() const { return perspective_; }
+
+ static QuicPacketEntropyHash GetPacketEntropyHash(
+ const QuicPacketHeader& header);
+
+ // Called when a PATH_CLOSED frame has been sent/received on |path_id|.
+ void OnPathClosed(QuicPathId path_id);
+
+ QuicTag last_version_tag() { return last_version_tag_; }
+
+ private:
+ friend class test::QuicFramerPeer;
+
+ typedef std::map<QuicPacketNumber, uint8_t> NackRangeMap;
+
+ struct AckFrameInfo {
+ AckFrameInfo();
+ AckFrameInfo(const AckFrameInfo& other);
+ ~AckFrameInfo();
+
+ // The maximum delta between ranges.
+ QuicPacketNumber max_delta;
+ // Nack ranges starting with start packet numbers and lengths.
+ NackRangeMap nack_ranges;
+ };
+
+ struct AckBlock {
+ AckBlock(uint8_t gap, QuicPacketNumber length);
+ AckBlock(const AckBlock& other);
+ ~AckBlock();
+
+ // Gap to the next ack block.
+ uint8_t gap;
+ // Length of this ack block.
+ QuicPacketNumber length;
+ };
+
+ struct NewAckFrameInfo {
+ NewAckFrameInfo();
+ NewAckFrameInfo(const NewAckFrameInfo& other);
+ ~NewAckFrameInfo();
+
+ // The maximum ack block length.
+ QuicPacketNumber max_block_length;
+ // Length of first ack block.
+ QuicPacketNumber first_block_length;
+ // Number of ACK blocks needed for the ACK frame.
+ size_t num_ack_blocks;
+ };
+
+ bool ProcessDataPacket(QuicDataReader* reader,
+ const QuicPacketPublicHeader& public_header,
+ const QuicEncryptedPacket& packet,
+ char* decrypted_buffer,
+ size_t buffer_length);
+
+ bool ProcessPublicResetPacket(QuicDataReader* reader,
+ const QuicPacketPublicHeader& public_header);
+
+ bool ProcessVersionNegotiationPacket(QuicDataReader* reader,
+ QuicPacketPublicHeader* public_header);
+
+ bool ProcessPublicHeader(QuicDataReader* reader,
+ QuicPacketPublicHeader* header);
+
+ // Processes the unauthenticated portion of the header into |header| from
+ // the current QuicDataReader. Returns true on success, false on failure.
+ bool ProcessUnauthenticatedHeader(QuicDataReader* encrypted_reader,
+ QuicPacketHeader* header);
+
+ // Processes the authenticated portion of the header into |header| from
+ // the current QuicDataReader. Returns true on success, false on failure.
+ bool ProcessAuthenticatedHeader(QuicDataReader* reader,
+ QuicPacketHeader* header);
+
+ bool ProcessPathId(QuicDataReader* reader, QuicPathId* path_id);
+ bool ProcessPacketSequenceNumber(QuicDataReader* reader,
+ QuicPacketNumberLength packet_number_length,
+ QuicPacketNumber base_packet_number,
+ QuicPacketNumber* packet_number);
+ bool ProcessFrameData(QuicDataReader* reader, const QuicPacketHeader& header);
+ bool ProcessStreamFrame(QuicDataReader* reader,
+ uint8_t frame_type,
+ QuicStreamFrame* frame);
+ bool ProcessAckFrame(QuicDataReader* reader,
+ uint8_t frame_type,
+ QuicAckFrame* frame);
+ bool ProcessNewAckFrame(QuicDataReader* reader,
+ uint8_t frame_type,
+ QuicAckFrame* frame);
+ bool ProcessTimestampsInAckFrame(QuicDataReader* reader, QuicAckFrame* frame);
+ bool ProcessStopWaitingFrame(QuicDataReader* reader,
+ const QuicPacketHeader& public_header,
+ QuicStopWaitingFrame* stop_waiting);
+ bool ProcessRstStreamFrame(QuicDataReader* reader, QuicRstStreamFrame* frame);
+ bool ProcessConnectionCloseFrame(QuicDataReader* reader,
+ QuicConnectionCloseFrame* frame);
+ bool ProcessGoAwayFrame(QuicDataReader* reader, QuicGoAwayFrame* frame);
+ bool ProcessWindowUpdateFrame(QuicDataReader* reader,
+ QuicWindowUpdateFrame* frame);
+ bool ProcessBlockedFrame(QuicDataReader* reader, QuicBlockedFrame* frame);
+ bool ProcessPathCloseFrame(QuicDataReader* reader, QuicPathCloseFrame* frame);
+
+ bool DecryptPayload(QuicDataReader* encrypted_reader,
+ const QuicPacketHeader& header,
+ const QuicEncryptedPacket& packet,
+ char* decrypted_buffer,
+ size_t buffer_length,
+ size_t* decrypted_length);
+
+ // Checks if |path_id| is a viable path to receive packets on. Returns true
+ // and sets |base_packet_number| to the packet number to calculate the
+ // incoming packet number from if the path is not closed. Returns false
+ // otherwise.
+ bool IsValidPath(QuicPathId path_id, QuicPacketNumber* base_packet_number);
+
+ // Sets last_packet_number_. This can only be called after the packet is
+ // successfully decrypted.
+ void SetLastPacketNumber(const QuicPacketHeader& header);
+
+ // Returns the full packet number from the truncated
+ // wire format version and the last seen packet number.
+ QuicPacketNumber CalculatePacketNumberFromWire(
+ QuicPacketNumberLength packet_number_length,
+ QuicPacketNumber base_packet_number,
+ QuicPacketNumber packet_number) const;
+
+ // Returns the QuicTime::Delta corresponding to the time from when the framer
+ // was created.
+ const QuicTime::Delta CalculateTimestampFromWire(uint32_t time_delta_us);
+
+ // Computes the wire size in bytes of time stamps in |ack|.
+ size_t GetAckFrameTimeStampSize(const QuicAckFrame& ack);
+
+ // Computes the wire size in bytes of the |ack| frame, assuming no truncation.
+ size_t GetAckFrameSize(const QuicAckFrame& ack,
+ QuicPacketNumberLength packet_number_length);
+
+ // Computes the wire size in bytes of the |ack| frame.
+ size_t GetNewAckFrameSize(const QuicAckFrame& ack);
+
+ // Computes the wire size in bytes of the payload of |frame|.
+ size_t ComputeFrameLength(const QuicFrame& frame,
+ bool last_frame_in_packet,
+ QuicPacketNumberLength packet_number_length);
+
+ static bool AppendPacketSequenceNumber(
+ QuicPacketNumberLength packet_number_length,
+ QuicPacketNumber packet_number,
+ QuicDataWriter* writer);
+
+ // Appends a single ACK block to |writer| and returns true if the block was
+ // successfully appended.
+ static bool AppendAckBlock(uint8_t gap,
+ QuicPacketNumberLength length_length,
+ QuicPacketNumber length,
+ QuicDataWriter* writer);
+
+ static uint8_t GetSequenceNumberFlags(
+ QuicPacketNumberLength packet_number_length);
+
+ static AckFrameInfo GetAckFrameInfo(const QuicAckFrame& frame);
+
+ static NewAckFrameInfo GetNewAckFrameInfo(const QuicAckFrame& frame);
+
+ // The Append* methods attempt to write the provided header or frame using the
+ // |writer|, and return true if successful.
+
+ bool AppendAckFrameAndTypeByte(const QuicPacketHeader& header,
+ const QuicAckFrame& frame,
+ QuicDataWriter* builder);
+ bool AppendNewAckFrameAndTypeByte(const QuicAckFrame& frame,
+ QuicDataWriter* builder);
+ bool AppendTimestampToAckFrame(const QuicAckFrame& frame,
+ QuicDataWriter* builder);
+ bool AppendStopWaitingFrame(const QuicPacketHeader& header,
+ const QuicStopWaitingFrame& frame,
+ QuicDataWriter* builder);
+ bool AppendRstStreamFrame(const QuicRstStreamFrame& frame,
+ QuicDataWriter* builder);
+ bool AppendConnectionCloseFrame(const QuicConnectionCloseFrame& frame,
+ QuicDataWriter* builder);
+ bool AppendGoAwayFrame(const QuicGoAwayFrame& frame, QuicDataWriter* writer);
+ bool AppendWindowUpdateFrame(const QuicWindowUpdateFrame& frame,
+ QuicDataWriter* writer);
+ bool AppendBlockedFrame(const QuicBlockedFrame& frame,
+ QuicDataWriter* writer);
+ bool AppendPathCloseFrame(const QuicPathCloseFrame& frame,
+ QuicDataWriter* writer);
+
+ bool RaiseError(QuicErrorCode error);
+
+ void set_error(QuicErrorCode error) { error_ = error; }
+
+ void set_detailed_error(const char* error) { detailed_error_ = error; }
+
+ std::string detailed_error_;
+ QuicFramerVisitorInterface* visitor_;
+ QuicReceivedEntropyHashCalculatorInterface* entropy_calculator_;
+ QuicErrorCode error_;
+ // Set of closed paths. A path is considered as closed if a PATH_CLOSED frame
+ // has been sent/received.
+ // TODO(fayang): this set is never cleaned up. A possible improvement is to
+ // use intervals.
+ std::unordered_set<QuicPathId> closed_paths_;
+ // Map mapping path id to packet number of last successfully decrypted
+ // received packet.
+ // TODO(ianswett): Remove when
+ // gfe2_reloadable_flag_quic_packet_numbers_largest_received is deprecated.
+ std::unordered_map<QuicPathId, QuicPacketNumber> last_packet_numbers_;
+ // Updated by ProcessPacketHeader when it succeeds.
+ QuicPacketNumber last_packet_number_;
+ // Map mapping path id to packet number of largest successfully decrypted
+ // received packet.
+ std::unordered_map<QuicPathId, QuicPacketNumber> largest_packet_numbers_;
+ // Updated by ProcessPacketHeader when it succeeds decrypting a larger packet.
+ QuicPacketNumber largest_packet_number_;
+ // The path on which last successfully decrypted packet was received.
+ QuicPathId last_path_id_;
+ // Updated by WritePacketHeader.
+ QuicConnectionId last_serialized_connection_id_;
+ // The last QUIC version tag received.
+ QuicTag last_version_tag_;
+ // Version of the protocol being used.
+ QuicVersion quic_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).
+ QuicVersionVector 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.
+ std::unique_ptr<QuicDecrypter> alternative_decrypter_;
+ // The encryption level of |decrypter_|.
+ EncryptionLevel decrypter_level_;
+ // The encryption level of |alternative_decrypter_|.
+ EncryptionLevel alternative_decrypter_level_;
+ // |alternative_decrypter_latch_| is true if, when |alternative_decrypter_|
+ // successfully decrypts a packet, we should install it as the only
+ // decrypter.
+ bool alternative_decrypter_latch_;
+ // Encrypters used to encrypt packets via EncryptPayload().
+ std::unique_ptr<QuicEncrypter> encrypter_[NUM_ENCRYPTION_LEVELS];
+ // Tracks if the framer is being used by the entity that received the
+ // connection or the entity that initiated it.
+ Perspective perspective_;
+ // If false, skip validation that the public flags are set to legal values.
+ bool validate_flags_;
+ // The time this framer was created. Time written to the wire will be
+ // written as a delta from this value.
+ QuicTime creation_time_;
+ // The time delta computed for the last timestamp frame. This is relative to
+ // the creation_time.
+ QuicTime::Delta last_timestamp_;
+ // The diversification nonce from the last received packet.
+ DiversificationNonce last_nonce_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicFramer);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_FRAMER_H_
diff --git a/chromium/net/quic/core/quic_framer_test.cc b/chromium/net/quic/core/quic_framer_test.cc
new file mode 100644
index 00000000000..927b97d2352
--- /dev/null
+++ b/chromium/net/quic/core/quic_framer_test.cc
@@ -0,0 +1,7276 @@
+// 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/quic_framer.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "net/quic/core/crypto/null_decrypter.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/quic_framer_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/test/gtest_util.h"
+
+using base::StringPiece;
+using std::make_pair;
+using std::map;
+using std::numeric_limits;
+using std::pair;
+using std::string;
+using std::vector;
+using testing::Return;
+using testing::Truly;
+using testing::_;
+
+namespace net {
+namespace test {
+
+const QuicPacketNumber kEpoch = UINT64_C(1) << 48;
+const QuicPacketNumber kMask = kEpoch - 1;
+
+// Use fields in which each byte is distinct to ensure that every byte is
+// framed correctly. The values are otherwise arbitrary.
+const QuicConnectionId kConnectionId = UINT64_C(0xFEDCBA9876543210);
+const QuicPathId kPathId = 0x42;
+const QuicPacketNumber kPacketNumber = UINT64_C(0x123456789ABC);
+const QuicPacketNumber kLargestObserved = UINT64_C(0x0123456789ABF);
+const QuicPacketNumber kSmallLargestObserved = UINT16_C(0x1234);
+const QuicPacketNumber kMissingPacket = UINT64_C(0x0123456789ABE);
+const QuicPacketNumber kSmallMissingPacket = UINT16_C(0x1233);
+const QuicPacketNumber kLeastUnacked = UINT64_C(0x0123456789AA0);
+const QuicStreamId kStreamId = UINT64_C(0x01020304);
+const QuicStreamOffset kStreamOffset = UINT64_C(0xBA98FEDC32107654);
+const QuicPublicResetNonceProof kNonceProof = UINT64_C(0xABCDEF0123456789);
+
+// Index into the connection_id offset in the header.
+const size_t kConnectionIdOffset = kPublicFlagsSize;
+// Index into the version string in the header. (if present).
+const size_t kVersionOffset = kConnectionIdOffset + PACKET_8BYTE_CONNECTION_ID;
+
+// Size in bytes of the stream frame fields for an arbitrary StreamID and
+// offset and the last frame in a packet.
+size_t GetMinStreamFrameSize() {
+ return kQuicFrameTypeSize + kQuicMaxStreamIdSize + kQuicMaxStreamOffsetSize;
+}
+
+// Index into the path id offset in the header (if present).
+size_t GetPathIdOffset(QuicConnectionIdLength connection_id_length,
+ bool include_version) {
+ return kConnectionIdOffset + connection_id_length +
+ (include_version ? kQuicVersionSize : 0);
+}
+
+// Index into the packet number offset in the header.
+size_t GetPacketNumberOffset(QuicConnectionIdLength connection_id_length,
+ bool include_version,
+ bool include_path_id) {
+ return kConnectionIdOffset + connection_id_length +
+ (include_version ? kQuicVersionSize : 0) +
+ (include_path_id ? kQuicPathIdSize : 0);
+}
+
+size_t GetPacketNumberOffset(bool include_version, bool include_path_id) {
+ return GetPacketNumberOffset(PACKET_8BYTE_CONNECTION_ID, include_version,
+ include_path_id);
+}
+
+// Index into the private flags offset in the data packet header.
+size_t GetPrivateFlagsOffset(QuicConnectionIdLength connection_id_length,
+ bool include_version,
+ bool include_path_id) {
+ return GetPacketNumberOffset(connection_id_length, include_version,
+ include_path_id) +
+ PACKET_6BYTE_PACKET_NUMBER;
+}
+
+size_t GetPrivateFlagsOffset(bool include_version, bool include_path_id) {
+ return GetPrivateFlagsOffset(PACKET_8BYTE_CONNECTION_ID, include_version,
+ include_path_id);
+}
+
+size_t GetPrivateFlagsOffset(bool include_version,
+ bool include_path_id,
+ QuicPacketNumberLength packet_number_length) {
+ return GetPacketNumberOffset(PACKET_8BYTE_CONNECTION_ID, include_version,
+ include_path_id) +
+ packet_number_length;
+}
+
+// Index into the message tag of the public reset packet.
+// Public resets always have full connection_ids.
+const size_t kPublicResetPacketMessageTagOffset =
+ kConnectionIdOffset + PACKET_8BYTE_CONNECTION_ID;
+
+class TestEncrypter : public QuicEncrypter {
+ public:
+ ~TestEncrypter() override {}
+ bool SetKey(StringPiece key) override { return true; }
+ bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
+ bool EncryptPacket(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ StringPiece associated_data,
+ StringPiece plaintext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) override {
+ path_id_ = path_id;
+ packet_number_ = packet_number;
+ associated_data_ = associated_data.as_string();
+ plaintext_ = plaintext.as_string();
+ memcpy(output, plaintext.data(), plaintext.length());
+ *output_length = plaintext.length();
+ return true;
+ }
+ size_t GetKeySize() const override { return 0; }
+ size_t GetNoncePrefixSize() const override { return 0; }
+ size_t GetMaxPlaintextSize(size_t ciphertext_size) const override {
+ return ciphertext_size;
+ }
+ size_t GetCiphertextSize(size_t plaintext_size) const override {
+ return plaintext_size;
+ }
+ StringPiece GetKey() const override { return StringPiece(); }
+ StringPiece GetNoncePrefix() const override { return StringPiece(); }
+ QuicPathId path_id_;
+ QuicPacketNumber packet_number_;
+ string associated_data_;
+ string plaintext_;
+};
+
+class TestDecrypter : public QuicDecrypter {
+ public:
+ ~TestDecrypter() override {}
+ bool SetKey(StringPiece key) override { return true; }
+ bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
+ bool SetPreliminaryKey(StringPiece key) override {
+ QUIC_BUG << "should not be called";
+ return false;
+ }
+ bool SetDiversificationNonce(const DiversificationNonce& key) override {
+ return true;
+ }
+ bool DecryptPacket(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ StringPiece associated_data,
+ StringPiece ciphertext,
+ char* output,
+ size_t* output_length,
+ size_t max_output_length) override {
+ path_id_ = path_id;
+ packet_number_ = packet_number;
+ associated_data_ = associated_data.as_string();
+ ciphertext_ = ciphertext.as_string();
+ memcpy(output, ciphertext.data(), ciphertext.length());
+ *output_length = ciphertext.length();
+ return true;
+ }
+ StringPiece GetKey() const override { return StringPiece(); }
+ StringPiece GetNoncePrefix() const override { return StringPiece(); }
+ const char* cipher_name() const override { return "Test"; }
+ // Use a distinct value starting with 0xFFFFFF, which is never used by TLS.
+ uint32_t cipher_id() const override { return 0xFFFFFFF2; }
+ QuicPathId path_id_;
+ QuicPacketNumber packet_number_;
+ string associated_data_;
+ string ciphertext_;
+};
+
+class TestQuicVisitor : public QuicFramerVisitorInterface {
+ public:
+ TestQuicVisitor()
+ : error_count_(0),
+ version_mismatch_(0),
+ packet_count_(0),
+ frame_count_(0),
+ complete_packets_(0),
+ accept_packet_(true),
+ accept_public_header_(true) {}
+
+ ~TestQuicVisitor() override {
+ base::STLDeleteElements(&stream_frames_);
+ base::STLDeleteElements(&ack_frames_);
+ base::STLDeleteElements(&stop_waiting_frames_);
+ base::STLDeleteElements(&padding_frames_);
+ base::STLDeleteElements(&ping_frames_);
+ base::STLDeleteElements(&stream_data_);
+ }
+
+ void OnError(QuicFramer* f) override {
+ DVLOG(1) << "QuicFramer Error: " << QuicUtils::ErrorToString(f->error())
+ << " (" << f->error() << ")";
+ ++error_count_;
+ }
+
+ void OnPacket() override {}
+
+ void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {
+ public_reset_packet_.reset(new QuicPublicResetPacket(packet));
+ }
+
+ void OnVersionNegotiationPacket(
+ const QuicVersionNegotiationPacket& packet) override {
+ version_negotiation_packet_.reset(new QuicVersionNegotiationPacket(packet));
+ }
+
+ bool OnProtocolVersionMismatch(QuicVersion version) override {
+ DVLOG(1) << "QuicFramer Version Mismatch, version: " << version;
+ ++version_mismatch_;
+ return true;
+ }
+
+ bool OnUnauthenticatedPublicHeader(
+ const QuicPacketPublicHeader& header) override {
+ public_header_.reset(new QuicPacketPublicHeader(header));
+ return accept_public_header_;
+ }
+
+ bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override {
+ return true;
+ }
+
+ void OnDecryptedPacket(EncryptionLevel level) override {}
+
+ bool OnPacketHeader(const QuicPacketHeader& header) override {
+ if (header.fec_flag) {
+ // Drop any FEC packet.
+ return false;
+ }
+ ++packet_count_;
+ header_.reset(new QuicPacketHeader(header));
+ return accept_packet_;
+ }
+
+ bool OnStreamFrame(const QuicStreamFrame& frame) override {
+ ++frame_count_;
+ // Save a copy of the data so it is valid after the packet is processed.
+ string* string_data = new string();
+ StringPiece(frame.data_buffer, frame.data_length)
+ .AppendToString(string_data);
+ stream_data_.push_back(string_data);
+ stream_frames_.push_back(new QuicStreamFrame(frame.stream_id, frame.fin,
+ frame.offset, *string_data));
+ return true;
+ }
+
+ bool OnAckFrame(const QuicAckFrame& frame) override {
+ ++frame_count_;
+ ack_frames_.push_back(new QuicAckFrame(frame));
+ return true;
+ }
+
+ bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override {
+ ++frame_count_;
+ stop_waiting_frames_.push_back(new QuicStopWaitingFrame(frame));
+ return true;
+ }
+
+ bool OnPaddingFrame(const QuicPaddingFrame& frame) override {
+ padding_frames_.push_back(new QuicPaddingFrame(frame));
+ return true;
+ }
+
+ bool OnPingFrame(const QuicPingFrame& frame) override {
+ ++frame_count_;
+ ping_frames_.push_back(new QuicPingFrame(frame));
+ return true;
+ }
+
+ void OnPacketComplete() override { ++complete_packets_; }
+
+ bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override {
+ rst_stream_frame_ = frame;
+ return true;
+ }
+
+ bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override {
+ connection_close_frame_ = frame;
+ return true;
+ }
+
+ bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override {
+ goaway_frame_ = frame;
+ return true;
+ }
+
+ bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override {
+ window_update_frame_ = frame;
+ return true;
+ }
+
+ bool OnBlockedFrame(const QuicBlockedFrame& frame) override {
+ blocked_frame_ = frame;
+ return true;
+ }
+
+ bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override {
+ path_close_frame_ = frame;
+ return true;
+ }
+
+ // Counters from the visitor_ callbacks.
+ int error_count_;
+ int version_mismatch_;
+ int packet_count_;
+ int frame_count_;
+ int complete_packets_;
+ bool accept_packet_;
+ bool accept_public_header_;
+
+ std::unique_ptr<QuicPacketHeader> header_;
+ std::unique_ptr<QuicPacketPublicHeader> public_header_;
+ std::unique_ptr<QuicPublicResetPacket> public_reset_packet_;
+ std::unique_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_;
+ vector<QuicStreamFrame*> stream_frames_;
+ vector<QuicAckFrame*> ack_frames_;
+ vector<QuicStopWaitingFrame*> stop_waiting_frames_;
+ vector<QuicPaddingFrame*> padding_frames_;
+ vector<QuicPingFrame*> ping_frames_;
+ QuicRstStreamFrame rst_stream_frame_;
+ QuicConnectionCloseFrame connection_close_frame_;
+ QuicGoAwayFrame goaway_frame_;
+ QuicWindowUpdateFrame window_update_frame_;
+ QuicBlockedFrame blocked_frame_;
+ QuicPathCloseFrame path_close_frame_;
+ vector<string*> stream_data_;
+};
+
+class QuicFramerTest : public ::testing::TestWithParam<QuicVersion> {
+ public:
+ QuicFramerTest()
+ : encrypter_(new test::TestEncrypter()),
+ decrypter_(new test::TestDecrypter()),
+ start_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(0x10)),
+ framer_(AllSupportedVersions(), start_, Perspective::IS_SERVER) {
+ version_ = GetParam();
+ framer_.set_version(version_);
+ framer_.SetDecrypter(ENCRYPTION_NONE, decrypter_);
+ framer_.SetEncrypter(ENCRYPTION_NONE, encrypter_);
+ framer_.set_visitor(&visitor_);
+ framer_.set_received_entropy_calculator(&entropy_calculator_);
+ }
+
+ // 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);
+ }
+
+ // 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);
+ }
+
+ bool CheckEncryption(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ QuicPacket* packet) {
+ if (packet_number != encrypter_->packet_number_) {
+ LOG(ERROR) << "Encrypted incorrect packet number. expected "
+ << packet_number << " actual: " << encrypter_->packet_number_;
+ return false;
+ }
+ if (packet->AssociatedData(framer_.version()) !=
+ encrypter_->associated_data_) {
+ LOG(ERROR) << "Encrypted incorrect associated data. expected "
+ << packet->AssociatedData(framer_.version())
+ << " actual: " << encrypter_->associated_data_;
+ return false;
+ }
+ if (packet->Plaintext(framer_.version()) != encrypter_->plaintext_) {
+ LOG(ERROR) << "Encrypted incorrect plaintext data. expected "
+ << packet->Plaintext(framer_.version())
+ << " actual: " << encrypter_->plaintext_;
+ return false;
+ }
+ return true;
+ }
+
+ bool CheckDecryption(const QuicEncryptedPacket& encrypted,
+ bool includes_version,
+ bool includes_path_id,
+ bool includes_diversification_nonce) {
+ if (visitor_.header_->packet_number != decrypter_->packet_number_) {
+ LOG(ERROR) << "Decrypted incorrect packet number. expected "
+ << visitor_.header_->packet_number
+ << " actual: " << decrypter_->packet_number_;
+ return false;
+ }
+ if (QuicFramer::GetAssociatedDataFromEncryptedPacket(
+ framer_.version(), encrypted, PACKET_8BYTE_CONNECTION_ID,
+ includes_version, includes_path_id, includes_diversification_nonce,
+ PACKET_6BYTE_PACKET_NUMBER) != decrypter_->associated_data_) {
+ LOG(ERROR) << "Decrypted incorrect associated data. expected "
+ << QuicFramer::GetAssociatedDataFromEncryptedPacket(
+ framer_.version(), encrypted,
+ PACKET_8BYTE_CONNECTION_ID, includes_version,
+ includes_path_id, includes_diversification_nonce,
+ PACKET_6BYTE_PACKET_NUMBER)
+ << " actual: " << decrypter_->associated_data_;
+ return false;
+ }
+ StringPiece ciphertext(
+ encrypted.AsStringPiece().substr(GetStartOfEncryptedData(
+ framer_.version(), PACKET_8BYTE_CONNECTION_ID, includes_version,
+ includes_path_id, includes_diversification_nonce,
+ PACKET_6BYTE_PACKET_NUMBER)));
+ if (ciphertext != decrypter_->ciphertext_) {
+ LOG(ERROR) << "Decrypted incorrect ciphertext data. expected "
+ << ciphertext << " actual: " << decrypter_->ciphertext_;
+ return false;
+ }
+ return true;
+ }
+
+ char* AsChars(unsigned char* data) { return reinterpret_cast<char*>(data); }
+
+ void CheckProcessingFails(unsigned char* packet,
+ size_t len,
+ string expected_error,
+ QuicErrorCode error_code) {
+ QuicEncryptedPacket encrypted(AsChars(packet), len, false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted)) << "len: " << len;
+ EXPECT_EQ(expected_error, framer_.detailed_error()) << "len: " << len;
+ EXPECT_EQ(error_code, framer_.error()) << "len: " << len;
+ }
+
+ // Checks if the supplied string matches data in the supplied StreamFrame.
+ void CheckStreamFrameData(string str, QuicStreamFrame* frame) {
+ EXPECT_EQ(str, string(frame->data_buffer, frame->data_length));
+ }
+
+ void CheckStreamFrameBoundaries(unsigned char* packet,
+ size_t stream_id_size,
+ bool include_version) {
+ // Now test framing boundaries.
+ for (size_t i = kQuicFrameTypeSize; i < GetMinStreamFrameSize(); ++i) {
+ string expected_error;
+ if (i < kQuicFrameTypeSize + stream_id_size) {
+ expected_error = "Unable to read stream_id.";
+ } else if (i < kQuicFrameTypeSize + stream_id_size +
+ kQuicMaxStreamOffsetSize) {
+ expected_error = "Unable to read offset.";
+ } else {
+ expected_error = "Unable to read frame data.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ include_version, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_STREAM_DATA);
+ }
+ }
+
+ void CheckCalculatePacketNumber(QuicPacketNumber expected_packet_number,
+ QuicPacketNumber last_packet_number) {
+ QuicPacketNumber wire_packet_number = expected_packet_number & kMask;
+ QuicFramerPeer::SetLastPacketNumber(&framer_, last_packet_number);
+ EXPECT_EQ(
+ expected_packet_number,
+ QuicFramerPeer::CalculatePacketNumberFromWire(
+ &framer_, PACKET_6BYTE_PACKET_NUMBER,
+ QuicFramerPeer::GetLastPacketNumber(&framer_), wire_packet_number))
+ << "last_packet_number: " << last_packet_number
+ << " wire_packet_number: " << wire_packet_number;
+ }
+
+ QuicPacket* BuildDataPacket(const QuicPacketHeader& header,
+ const QuicFrames& frames) {
+ return BuildUnsizedDataPacket(&framer_, header, frames);
+ }
+
+ QuicPacket* BuildDataPacket(const QuicPacketHeader& header,
+ const QuicFrames& frames,
+ size_t packet_size) {
+ return BuildUnsizedDataPacket(&framer_, header, frames, packet_size);
+ }
+
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+ test::TestEncrypter* encrypter_;
+ test::TestDecrypter* decrypter_;
+ QuicVersion version_;
+ QuicTime start_;
+ QuicFramer framer_;
+ test::TestQuicVisitor visitor_;
+ test::TestEntropyCalculator entropy_calculator_;
+};
+
+// Run all framer tests with all supported versions of QUIC.
+INSTANTIATE_TEST_CASE_P(QuicFramerTests,
+ QuicFramerTest,
+ ::testing::ValuesIn(kSupportedQuicVersions));
+
+TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochStart) {
+ // A few quick manual sanity checks.
+ CheckCalculatePacketNumber(UINT64_C(1), UINT64_C(0));
+ CheckCalculatePacketNumber(kEpoch + 1, kMask);
+ CheckCalculatePacketNumber(kEpoch, kMask);
+
+ // Cases where the last number was close to the start of the range.
+ for (uint64_t last = 0; last < 10; last++) {
+ // Small numbers should not wrap (even if they're out of order).
+ for (uint64_t j = 0; j < 10; j++) {
+ CheckCalculatePacketNumber(j, last);
+ }
+
+ // Large numbers should not wrap either (because we're near 0 already).
+ for (uint64_t j = 0; j < 10; j++) {
+ CheckCalculatePacketNumber(kEpoch - 1 - j, last);
+ }
+ }
+}
+
+TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochEnd) {
+ // Cases where the last number was close to the end of the range
+ for (uint64_t i = 0; i < 10; i++) {
+ QuicPacketNumber last = kEpoch - i;
+
+ // Small numbers should wrap.
+ for (uint64_t j = 0; j < 10; j++) {
+ CheckCalculatePacketNumber(kEpoch + j, last);
+ }
+
+ // Large numbers should not (even if they're out of order).
+ for (uint64_t j = 0; j < 10; j++) {
+ CheckCalculatePacketNumber(kEpoch - 1 - j, last);
+ }
+ }
+}
+
+// Next check where we're in a non-zero epoch to verify we handle
+// reverse wrapping, too.
+TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearPrevEpoch) {
+ const uint64_t prev_epoch = 1 * kEpoch;
+ const uint64_t cur_epoch = 2 * kEpoch;
+ // Cases where the last number was close to the start of the range
+ for (uint64_t i = 0; i < 10; i++) {
+ uint64_t last = cur_epoch + i;
+ // Small number should not wrap (even if they're out of order).
+ for (uint64_t j = 0; j < 10; j++) {
+ CheckCalculatePacketNumber(cur_epoch + j, last);
+ }
+
+ // But large numbers should reverse wrap.
+ for (uint64_t j = 0; j < 10; j++) {
+ uint64_t num = kEpoch - 1 - j;
+ CheckCalculatePacketNumber(prev_epoch + num, last);
+ }
+ }
+}
+
+TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearNextEpoch) {
+ const uint64_t cur_epoch = 2 * kEpoch;
+ const uint64_t next_epoch = 3 * kEpoch;
+ // Cases where the last number was close to the end of the range
+ for (uint64_t i = 0; i < 10; i++) {
+ QuicPacketNumber last = next_epoch - 1 - i;
+
+ // Small numbers should wrap.
+ for (uint64_t j = 0; j < 10; j++) {
+ CheckCalculatePacketNumber(next_epoch + j, last);
+ }
+
+ // but large numbers should not (even if they're out of order).
+ for (uint64_t j = 0; j < 10; j++) {
+ uint64_t num = kEpoch - 1 - j;
+ CheckCalculatePacketNumber(cur_epoch + num, last);
+ }
+ }
+}
+
+TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearNextMax) {
+ const uint64_t max_number = numeric_limits<uint64_t>::max();
+ const uint64_t max_epoch = max_number & ~kMask;
+
+ // Cases where the last number was close to the end of the range
+ for (uint64_t i = 0; i < 10; i++) {
+ // Subtract 1, because the expected next packet number is 1 more than the
+ // last packet number.
+ QuicPacketNumber last = max_number - i - 1;
+
+ // Small numbers should not wrap, because they have nowhere to go.
+ for (uint64_t j = 0; j < 10; j++) {
+ CheckCalculatePacketNumber(max_epoch + j, last);
+ }
+
+ // Large numbers should not wrap either.
+ for (uint64_t j = 0; j < 10; j++) {
+ uint64_t num = kEpoch - 1 - j;
+ CheckCalculatePacketNumber(max_epoch + num, last);
+ }
+ }
+}
+
+TEST_P(QuicFramerTest, EmptyPacket) {
+ char packet[] = {0x00};
+ QuicEncryptedPacket encrypted(packet, 0, false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
+}
+
+TEST_P(QuicFramerTest, LargePacket) {
+ // clang-format off
+ unsigned char packet[kMaxPacketSize + 1] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags
+ 0x00,
+ };
+ // clang-format on
+
+ const size_t header_size = GetPacketHeaderSize(
+ framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+ !kIncludePathId, !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER);
+
+ memset(packet + header_size, 0, kMaxPacketSize - header_size);
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_QUIC_BUG(framer_.ProcessPacket(encrypted), "Packet too large:1");
+
+ ASSERT_TRUE(visitor_.header_.get());
+ // Make sure we've parsed the packet header, so we can send an error.
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ // Make sure the correct error is propagated.
+ EXPECT_EQ(QUIC_PACKET_TOO_LARGE, framer_.error());
+}
+
+TEST_P(QuicFramerTest, PacketHeader) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags
+ 0x00,
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
+ EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
+ EXPECT_FALSE(visitor_.header_->public_header.version_flag);
+ EXPECT_FALSE(visitor_.header_->fec_flag);
+ EXPECT_FALSE(visitor_.header_->entropy_flag);
+ EXPECT_EQ(0, visitor_.header_->entropy_hash);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
+
+ // Now test framing boundaries.
+ for (size_t i = 0;
+ i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER);
+ ++i) {
+ string expected_error;
+ if (i < kConnectionIdOffset) {
+ expected_error = "Unable to read public flags.";
+ } else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) {
+ expected_error = "Unable to read ConnectionId.";
+ } else {
+ if (framer_.version() <= QUIC_VERSION_33) {
+ if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId)) {
+ expected_error = "Unable to read packet number.";
+ } else {
+ expected_error = "Unable to read private flags.";
+ }
+ } else {
+ expected_error = "Unable to read packet number.";
+ }
+ }
+ CheckProcessingFails(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
+ expected_error, QUIC_INVALID_PACKET_HEADER);
+ }
+}
+
+TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
+ QuicFramerPeer::SetLastSerializedConnectionId(&framer_, kConnectionId);
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (0 byte connection_id)
+ 0x30,
+ // connection_id
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+ };
+ unsigned char packet_34[] = {
+ // public flags (0 byte connection_id)
+ 0x30,
+ // connection_id
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
+ EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
+ EXPECT_FALSE(visitor_.header_->public_header.version_flag);
+ EXPECT_FALSE(visitor_.header_->fec_flag);
+ EXPECT_FALSE(visitor_.header_->entropy_flag);
+ EXPECT_EQ(0, visitor_.header_->entropy_hash);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
+
+ // Now test framing boundaries.
+ for (size_t i = 0;
+ i < GetPacketHeaderSize(framer_.version(), PACKET_0BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER);
+ ++i) {
+ string expected_error;
+ if (i < kConnectionIdOffset) {
+ expected_error = "Unable to read public flags.";
+ } else if (i < GetPacketNumberOffset(PACKET_0BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId)) {
+ expected_error = "Unable to read ConnectionId.";
+ } else {
+ if (framer_.version() <= QUIC_VERSION_33) {
+ if (i < GetPrivateFlagsOffset(PACKET_0BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId)) {
+ expected_error = "Unable to read packet number.";
+ } else {
+ expected_error = "Unable to read private flags.";
+ }
+ } else {
+ expected_error = "Unable to read packet number.";
+ }
+ }
+ CheckProcessingFails(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
+ expected_error, QUIC_INVALID_PACKET_HEADER);
+ }
+}
+
+TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version)
+ 0x39,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags
+ 0x00,
+ };
+ unsigned char packet_34[] = {
+ // public flags (version)
+ 0x39,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
+ EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
+ EXPECT_TRUE(visitor_.header_->public_header.version_flag);
+ EXPECT_EQ(GetParam(), visitor_.header_->public_header.versions[0]);
+ EXPECT_FALSE(visitor_.header_->fec_flag);
+ EXPECT_FALSE(visitor_.header_->entropy_flag);
+ EXPECT_EQ(0, visitor_.header_->entropy_hash);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
+
+ // Now test framing boundaries.
+ for (size_t i = 0;
+ i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER);
+ ++i) {
+ string expected_error;
+ if (i < kConnectionIdOffset) {
+ expected_error = "Unable to read public flags.";
+ } else if (i < kVersionOffset) {
+ expected_error = "Unable to read ConnectionId.";
+ } else if (i < GetPacketNumberOffset(kIncludeVersion, !kIncludePathId)) {
+ expected_error = "Unable to read protocol version.";
+ } else {
+ if (framer_.version() <= QUIC_VERSION_33) {
+ if (i < GetPrivateFlagsOffset(kIncludeVersion, !kIncludePathId)) {
+ expected_error = "Unable to read packet number.";
+ } else {
+ expected_error = "Unable to read private flags.";
+ }
+ } else {
+ expected_error = "Unable to read packet number.";
+ }
+ }
+ CheckProcessingFails(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
+ expected_error, QUIC_INVALID_PACKET_HEADER);
+ }
+}
+
+TEST_P(QuicFramerTest, PacketHeaderWithMultipathFlag) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version)
+ 0x78,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags
+ 0x00,
+ };
+ unsigned char packet_34[] = {
+ // public flags (version)
+ 0x78,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, kIncludePathId,
+ !kIncludeDiversificationNonce));
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ EXPECT_TRUE(visitor_.header_->public_header.multipath_flag);
+ EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
+ EXPECT_FALSE(visitor_.header_->public_header.version_flag);
+ EXPECT_FALSE(visitor_.header_->fec_flag);
+ EXPECT_FALSE(visitor_.header_->entropy_flag);
+ EXPECT_EQ(0, visitor_.header_->entropy_hash);
+ EXPECT_EQ(kPathId, visitor_.header_->path_id);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
+
+ // Now test framing boundaries.
+ for (size_t i = 0;
+ i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER);
+ ++i) {
+ string expected_error;
+ if (i < kConnectionIdOffset) {
+ expected_error = "Unable to read public flags.";
+ } else if (i <
+ GetPathIdOffset(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion)) {
+ expected_error = "Unable to read ConnectionId.";
+ } else if (i < GetPacketNumberOffset(!kIncludeVersion, kIncludePathId)) {
+ expected_error = "Unable to read path id.";
+ } else {
+ if (framer_.version() <= QUIC_VERSION_33) {
+ if (i < GetPrivateFlagsOffset(!kIncludeVersion, kIncludePathId)) {
+ expected_error = "Unable to read packet number.";
+ } else {
+ expected_error = "Unable to read private flags.";
+ }
+ } else {
+ expected_error = "Unable to read packet number.";
+ }
+ }
+ CheckProcessingFails(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
+ expected_error, QUIC_INVALID_PACKET_HEADER);
+ }
+}
+
+TEST_P(QuicFramerTest, PacketHeaderWithBothVersionFlagAndMultipathFlag) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version)
+ 0x79,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags
+ 0x00,
+ };
+ unsigned char packet_34[] = {
+ // public flags (version)
+ 0x79,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, kIncludeVersion, kIncludePathId,
+ !kIncludeDiversificationNonce));
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ EXPECT_TRUE(visitor_.header_->public_header.multipath_flag);
+ EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
+ EXPECT_TRUE(visitor_.header_->public_header.version_flag);
+ EXPECT_EQ(GetParam(), visitor_.header_->public_header.versions[0]);
+ EXPECT_FALSE(visitor_.header_->fec_flag);
+ EXPECT_FALSE(visitor_.header_->entropy_flag);
+ EXPECT_EQ(0, visitor_.header_->entropy_hash);
+ EXPECT_EQ(kPathId, visitor_.header_->path_id);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
+
+ // Now test framing boundaries.
+ for (size_t i = 0;
+ i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER);
+ ++i) {
+ string expected_error;
+ if (i < kConnectionIdOffset) {
+ expected_error = "Unable to read public flags.";
+ } else if (i < kVersionOffset) {
+ expected_error = "Unable to read ConnectionId.";
+ } else if (i <
+ GetPathIdOffset(PACKET_8BYTE_CONNECTION_ID, kIncludeVersion)) {
+ expected_error = "Unable to read protocol version.";
+ } else if (i < GetPacketNumberOffset(kIncludeVersion, kIncludePathId)) {
+ expected_error = "Unable to read path id.";
+ } else {
+ if (framer_.version() <= QUIC_VERSION_33) {
+ if (i < GetPrivateFlagsOffset(kIncludeVersion, kIncludePathId)) {
+ expected_error = "Unable to read packet number.";
+ } else {
+ expected_error = "Unable to read private flags.";
+ }
+ } else {
+ expected_error = "Unable to read packet number.";
+ }
+ }
+ CheckProcessingFails(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
+ expected_error, QUIC_INVALID_PACKET_HEADER);
+ }
+}
+
+TEST_P(QuicFramerTest, PacketHeaderWithPathChange) {
+ // Packet 1 from path 0x42.
+ // clang-format off
+ unsigned char packet1[] = {
+ // public flags (version)
+ 0x78,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags
+ 0x00,
+ };
+ unsigned char packet1_34[] = {
+ // public flags (version)
+ 0x78,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ };
+ // clang-format on
+
+ EXPECT_EQ(0u, QuicFramerPeer::GetLastPacketNumber(&framer_));
+ EXPECT_EQ(kInvalidPathId, QuicFramerPeer::GetLastPathId(&framer_));
+ QuicEncryptedPacket encrypted1(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet1 : packet1_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet1)
+ : arraysize(packet1_34),
+ false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted1));
+ EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(kPathId, visitor_.header_->path_id);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
+ EXPECT_EQ(kPacketNumber, QuicFramerPeer::GetLastPacketNumber(&framer_));
+ EXPECT_EQ(kPathId, QuicFramerPeer::GetLastPathId(&framer_));
+
+ // Packet 2 from default path.
+ // clang-format off
+ unsigned char packet2[] = {
+ // public flags (version)
+ 0x78,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x00,
+ // packet number
+ 0xCC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags
+ 0x00,
+ };
+ unsigned char packet2_34[] = {
+ // public flags (version)
+ 0x78,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x00,
+ // packet number
+ 0xCC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted2(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet2 : packet2_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet2)
+ : arraysize(packet2_34),
+ false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted2));
+ EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(kDefaultPathId, visitor_.header_->path_id);
+ EXPECT_EQ(kPacketNumber + 16, visitor_.header_->packet_number);
+ EXPECT_EQ(kPacketNumber + 16, QuicFramerPeer::GetLastPacketNumber(&framer_));
+ EXPECT_EQ(kDefaultPathId, QuicFramerPeer::GetLastPathId(&framer_));
+
+ // Packet 3 from path 0x42.
+ // clang-format off
+ unsigned char packet3[] = {
+ // public flags (version)
+ 0x78,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x42,
+ // packet number
+ 0xBD, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags
+ 0x00,
+ };
+ unsigned char packet3_34[] = {
+ // public flags (version)
+ 0x78,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x42,
+ // packet number
+ 0xBD, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted3(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet3 : packet3_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet3)
+ : arraysize(packet3_34),
+ false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted3));
+ EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(kPathId, visitor_.header_->path_id);
+ EXPECT_EQ(kPacketNumber + 1, visitor_.header_->packet_number);
+ EXPECT_EQ(kPacketNumber + 1, QuicFramerPeer::GetLastPacketNumber(&framer_));
+ EXPECT_EQ(kPathId, QuicFramerPeer::GetLastPathId(&framer_));
+}
+
+TEST_P(QuicFramerTest, ReceivedPacketOnClosedPath) {
+ // Packet 1 from path 0x42.
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version)
+ 0x78,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags
+ 0x00,
+ };
+ unsigned char packet_34[] = {
+ // public flags (version)
+ 0x78,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags
+ 0x00,
+ };
+ // clang-format on
+
+ framer_.OnPathClosed(kPathId);
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ EXPECT_EQ(0u, QuicFramerPeer::GetLastPacketNumber(&framer_));
+ EXPECT_EQ(kInvalidPathId, QuicFramerPeer::GetLastPathId(&framer_));
+}
+
+TEST_P(QuicFramerTest, PacketHeaderWith4BytePacketNumber) {
+ if (FLAGS_quic_packet_numbers_largest_received) {
+ QuicFramerPeer::SetLargestPacketNumber(&framer_, kPacketNumber - 2);
+ } else {
+ QuicFramerPeer::SetLastPacketNumber(&framer_, kPacketNumber - 2);
+ }
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id and 4 byte packet number)
+ 0x28,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ // private flags
+ 0x00,
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id and 4 byte packet number)
+ 0x28,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
+ EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
+ EXPECT_FALSE(visitor_.header_->public_header.version_flag);
+ EXPECT_FALSE(visitor_.header_->fec_flag);
+ EXPECT_FALSE(visitor_.header_->entropy_flag);
+ EXPECT_EQ(0, visitor_.header_->entropy_hash);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
+
+ // Now test framing boundaries.
+ for (size_t i = 0;
+ i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_4BYTE_PACKET_NUMBER);
+ ++i) {
+ string expected_error;
+ if (i < kConnectionIdOffset) {
+ expected_error = "Unable to read public flags.";
+ } else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) {
+ expected_error = "Unable to read ConnectionId.";
+ } else {
+ if (framer_.version() <= QUIC_VERSION_33) {
+ if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId,
+ PACKET_4BYTE_PACKET_NUMBER)) {
+ expected_error = "Unable to read packet number.";
+ } else {
+ expected_error = "Unable to read private flags.";
+ }
+ } else {
+ expected_error = "Unable to read packet number.";
+ }
+ }
+ CheckProcessingFails(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
+ expected_error, QUIC_INVALID_PACKET_HEADER);
+ }
+}
+
+TEST_P(QuicFramerTest, PacketHeaderWith2BytePacketNumber) {
+ if (FLAGS_quic_packet_numbers_largest_received) {
+ QuicFramerPeer::SetLargestPacketNumber(&framer_, kPacketNumber - 2);
+ } else {
+ QuicFramerPeer::SetLastPacketNumber(&framer_, kPacketNumber - 2);
+ }
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id and 2 byte packet number)
+ 0x18,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A,
+ // private flags
+ 0x00,
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id and 2 byte packet number)
+ 0x18,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
+ EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
+ EXPECT_FALSE(visitor_.header_->public_header.version_flag);
+ EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER,
+ visitor_.header_->public_header.packet_number_length);
+ EXPECT_FALSE(visitor_.header_->fec_flag);
+ EXPECT_FALSE(visitor_.header_->entropy_flag);
+ EXPECT_EQ(0, visitor_.header_->entropy_hash);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
+
+ // Now test framing boundaries.
+ for (size_t i = 0;
+ i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_2BYTE_PACKET_NUMBER);
+ ++i) {
+ string expected_error;
+ if (i < kConnectionIdOffset) {
+ expected_error = "Unable to read public flags.";
+ } else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) {
+ expected_error = "Unable to read ConnectionId.";
+ } else {
+ if (framer_.version() <= QUIC_VERSION_33) {
+ if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId,
+ PACKET_2BYTE_PACKET_NUMBER)) {
+ expected_error = "Unable to read packet number.";
+ } else {
+ expected_error = "Unable to read private flags.";
+ }
+ } else {
+ expected_error = "Unable to read packet number.";
+ }
+ }
+ CheckProcessingFails(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
+ expected_error, QUIC_INVALID_PACKET_HEADER);
+ }
+}
+
+TEST_P(QuicFramerTest, PacketHeaderWith1BytePacketNumber) {
+ if (FLAGS_quic_packet_numbers_largest_received) {
+ QuicFramerPeer::SetLargestPacketNumber(&framer_, kPacketNumber - 2);
+ } else {
+ QuicFramerPeer::SetLastPacketNumber(&framer_, kPacketNumber - 2);
+ }
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id and 1 byte packet number)
+ 0x08,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC,
+ // private flags
+ 0x00,
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id and 1 byte packet number)
+ 0x08,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
+ EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
+ EXPECT_FALSE(visitor_.header_->public_header.version_flag);
+ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
+ visitor_.header_->public_header.packet_number_length);
+ EXPECT_FALSE(visitor_.header_->fec_flag);
+ EXPECT_FALSE(visitor_.header_->entropy_flag);
+ EXPECT_EQ(0, visitor_.header_->entropy_hash);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
+
+ // Now test framing boundaries.
+ for (size_t i = 0;
+ i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_1BYTE_PACKET_NUMBER);
+ ++i) {
+ string expected_error;
+ if (i < kConnectionIdOffset) {
+ expected_error = "Unable to read public flags.";
+ } else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) {
+ expected_error = "Unable to read ConnectionId.";
+ } else {
+ if (framer_.version() <= QUIC_VERSION_33) {
+ if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId,
+ PACKET_1BYTE_PACKET_NUMBER)) {
+ expected_error = "Unable to read packet number.";
+ } else {
+ expected_error = "Unable to read private flags.";
+ }
+ } else {
+ expected_error = "Unable to read packet number.";
+ }
+ }
+ CheckProcessingFails(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
+ expected_error, QUIC_INVALID_PACKET_HEADER);
+ }
+}
+
+TEST_P(QuicFramerTest, PacketNumberDecreasesThenIncreases) {
+ FLAGS_quic_packet_numbers_largest_received = true;
+ // Test the case when a packet is received from the past and future packet
+ // numbers are still calculated relative to the largest received packet.
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = false;
+ header.packet_number = kPacketNumber - 2;
+
+ QuicPaddingFrame padding_frame;
+ QuicFrames frames;
+ frames.push_back(QuicFrame(padding_frame));
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ QuicEncryptedPacket encrypted(data->data(), data->length(), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER,
+ visitor_.header_->public_header.packet_number_length);
+ EXPECT_EQ(kPacketNumber - 2, visitor_.header_->packet_number);
+
+ // Receive a 1 byte packet number.
+ header.packet_number = kPacketNumber;
+ header.public_header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER;
+ data.reset(BuildDataPacket(header, frames));
+ QuicEncryptedPacket encrypted1(data->data(), data->length(), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted1));
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
+ visitor_.header_->public_header.packet_number_length);
+ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
+
+ // Process a 2 byte packet number 256 packets ago.
+ header.packet_number = kPacketNumber - 256;
+ header.public_header.packet_number_length = PACKET_2BYTE_PACKET_NUMBER;
+ data.reset(BuildDataPacket(header, frames));
+ QuicEncryptedPacket encrypted2(data->data(), data->length(), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted2));
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER,
+ visitor_.header_->public_header.packet_number_length);
+ EXPECT_EQ(kPacketNumber - 256, visitor_.header_->packet_number);
+
+ // Process another 1 byte packet number and ensure it works.
+ header.packet_number = kPacketNumber - 1;
+ header.public_header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER;
+ data.reset(BuildDataPacket(header, frames));
+ QuicEncryptedPacket encrypted3(data->data(), data->length(), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted3));
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
+ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
+ visitor_.header_->public_header.packet_number_length);
+ EXPECT_EQ(kPacketNumber - 1, visitor_.header_->packet_number);
+}
+
+TEST_P(QuicFramerTest, InvalidPublicFlag) {
+ if (framer_.version() > QUIC_VERSION_33) {
+ return;
+ }
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags: all flags set but the public reset flag and version flag.
+ 0xF8,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (padding)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ // clang-format on
+
+ CheckProcessingFails(packet, arraysize(packet), "Illegal public flags value.",
+ QUIC_INVALID_PACKET_HEADER);
+
+ // Now turn off validation.
+ framer_.set_validate_flags(false);
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+};
+
+TEST_P(QuicFramerTest, PacketWithDiversificationNonce) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags: includes nonce flag
+ 0x7C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // nonce
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (padding)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ unsigned char packet_34[] = {
+ // public flags: includes nonce flag
+ 0x7C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // nonce
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+
+ // frame type (padding)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+ if (framer_.version() > QUIC_VERSION_32) {
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ ASSERT_TRUE(visitor_.public_header_->nonce != nullptr);
+ for (char i = 0; i < 32; ++i) {
+ EXPECT_EQ(i, (*visitor_.public_header_->nonce)[static_cast<int>(i)]);
+ }
+ } else if (framer_.version() < QUIC_VERSION_32) {
+ // Packet is successfully parsed by accident.
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ ASSERT_TRUE(visitor_.public_header_ != nullptr);
+ } else {
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
+ EXPECT_EQ("Illegal private flags value.", framer_.detailed_error());
+ }
+};
+
+TEST_P(QuicFramerTest, InvalidPublicFlagWithMatchingVersions) {
+ if (framer_.version() > QUIC_VERSION_33) {
+ return;
+ }
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id and version flag and an unknown flag)
+ 0x8D,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (padding)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ // clang-format on
+ CheckProcessingFails(packet, arraysize(packet), "Illegal public flags value.",
+ QUIC_INVALID_PACKET_HEADER);
+};
+
+TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id, version flag and an unknown flag)
+ 0x79,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', '0', '0',
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (padding frame)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id, version flag and an unknown flag)
+ 0x79,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', '0', '0',
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (padding frame)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ // clang-format on
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_EQ(0, visitor_.frame_count_);
+ EXPECT_EQ(1, visitor_.version_mismatch_);
+};
+
+TEST_P(QuicFramerTest, InvalidPrivateFlag) {
+ if (framer_.version() > QUIC_VERSION_33) {
+ return;
+ }
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x10,
+
+ // frame type (padding)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ // clang-format on
+ CheckProcessingFails(packet, arraysize(packet),
+ "Illegal private flags value.",
+ QUIC_INVALID_PACKET_HEADER);
+};
+
+TEST_P(QuicFramerTest, InvalidFECGroupOffset) {
+ if (framer_.version() > QUIC_VERSION_33) {
+ return;
+ }
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ // private flags (fec group)
+ 0x02,
+ // first fec protected packet offset
+ 0x10
+ };
+ // clang-format on
+ if (framer_.version() > QUIC_VERSION_31) {
+ CheckProcessingFails(packet, arraysize(packet),
+ "Illegal private flags value.",
+ QUIC_INVALID_PACKET_HEADER);
+ } else {
+ CheckProcessingFails(packet, arraysize(packet),
+ "First fec protected packet offset must be less "
+ "than the packet number.",
+ QUIC_INVALID_PACKET_HEADER);
+ }
+};
+
+TEST_P(QuicFramerTest, PaddingFrame) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (padding frame)
+ 0x00,
+ // Ignored data (which in this case is a stream frame)
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (padding frame)
+ 0x00,
+ // Ignored data (which in this case is a stream frame)
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ ASSERT_EQ(0u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+ // A packet with no frames is not acceptable.
+ CheckProcessingFails(
+ packet, GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ "Packet has no frames.", QUIC_MISSING_PAYLOAD);
+}
+
+TEST_P(QuicFramerTest, StreamFrame) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ ASSERT_EQ(1u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+ EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
+ CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
+
+ // Now test framing boundaries.
+ CheckStreamFrameBoundaries(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
+ kQuicMaxStreamIdSize, !kIncludeVersion);
+}
+
+TEST_P(QuicFramerTest, MissingDiversificationNonce) {
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+ framer_.SetDecrypter(ENCRYPTION_NONE, new NullDecrypter());
+ decrypter_ = new test::TestDecrypter();
+ framer_.SetAlternativeDecrypter(ENCRYPTION_INITIAL, decrypter_, false);
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ if (framer_.version() > QUIC_VERSION_32) {
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error());
+
+ } else {
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+ }
+}
+
+TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (stream frame with fin)
+ 0xFE,
+ // stream id
+ 0x04, 0x03, 0x02,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (stream frame with fin)
+ 0xFE,
+ // stream id
+ 0x04, 0x03, 0x02,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ ASSERT_EQ(1u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+ // Stream ID should be the last 3 bytes of kStreamId.
+ EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
+ CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
+
+ // Now test framing boundaries.
+ const size_t stream_id_size = 3;
+ CheckStreamFrameBoundaries(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, stream_id_size,
+ !kIncludeVersion);
+}
+
+TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (stream frame with fin)
+ 0xFD,
+ // stream id
+ 0x04, 0x03,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (stream frame with fin)
+ 0xFD,
+ // stream id
+ 0x04, 0x03,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ ASSERT_EQ(1u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+ // Stream ID should be the last 2 bytes of kStreamId.
+ EXPECT_EQ(0x0000FFFF & kStreamId, visitor_.stream_frames_[0]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
+ CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
+
+ // Now test framing boundaries.
+ const size_t stream_id_size = 2;
+ CheckStreamFrameBoundaries(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, stream_id_size,
+ !kIncludeVersion);
+}
+
+TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (stream frame with fin)
+ 0xFC,
+ // stream id
+ 0x04,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (stream frame with fin)
+ 0xFC,
+ // stream id
+ 0x04,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ ASSERT_EQ(1u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+ // Stream ID should be the last byte of kStreamId.
+ EXPECT_EQ(0x000000FF & kStreamId, visitor_.stream_frames_[0]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
+ CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
+
+ // Now test framing boundaries.
+ const size_t stream_id_size = 1;
+ CheckStreamFrameBoundaries(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, stream_id_size,
+ !kIncludeVersion);
+}
+
+TEST_P(QuicFramerTest, StreamFrameWithVersion) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version, 8 byte connection_id)
+ 0x39,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ unsigned char packet_34[] = {
+ // public flags (version, 8 byte connection_id)
+ 0x39,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(visitor_.header_->public_header.version_flag);
+ EXPECT_EQ(GetParam(), visitor_.header_->public_header.versions[0]);
+ EXPECT_TRUE(CheckDecryption(encrypted, kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ ASSERT_EQ(1u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+ EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id);
+ EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
+ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
+ CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
+
+ // Now test framing boundaries.
+ CheckStreamFrameBoundaries(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
+ kQuicMaxStreamIdSize, kIncludeVersion);
+}
+
+TEST_P(QuicFramerTest, RejectPacket) {
+ visitor_.accept_packet_ = false;
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ ASSERT_EQ(0u, visitor_.stream_frames_.size());
+ EXPECT_EQ(0u, visitor_.ack_frames_.size());
+}
+
+TEST_P(QuicFramerTest, RejectPublicHeader) {
+ visitor_.accept_public_header_ = false;
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.public_header_.get());
+ ASSERT_FALSE(visitor_.header_.get());
+}
+
+TEST_P(QuicFramerTest, AckFrameTwoTimestamp) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet number
+ 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // Number of timestamps.
+ 0x02,
+ // Delta from largest observed.
+ 0x01,
+ // Delta time.
+ 0x10, 0x32, 0x54, 0x76,
+ // Delta from largest observed.
+ 0x02,
+ // Delta time.
+ 0x10, 0x32,
+ // num missing packets
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // Number of revived packets.
+ 0x00,
+ };
+ // clang-format on
+
+ if (framer_.version() > QUIC_VERSION_31) {
+ return;
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame.entropy_hash);
+ EXPECT_EQ(kLargestObserved, frame.largest_observed);
+ ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
+ ASSERT_EQ(2u, frame.received_packet_times.size());
+ EXPECT_EQ(kMissingPacket, frame.packets.Min());
+
+ const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLargestObservedOffset =
+ kReceivedEntropyOffset + kQuicEntropyHashSize;
+ const size_t kMissingDeltaTimeOffset =
+ kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
+ const size_t kNumTimestampsOffset =
+ kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
+ const size_t kTimestampDeltaLargestObserved1 =
+ kNumTimestampsOffset + kQuicNumTimestampsSize;
+ const size_t kTimestampTimeDeltaLargestObserved1 =
+ kTimestampDeltaLargestObserved1 + 1;
+ const size_t kTimestampDeltaLargestObserved2 =
+ kTimestampTimeDeltaLargestObserved1 + 4;
+ const size_t kTimestampTimeDeltaLargestObserved2 =
+ kTimestampDeltaLargestObserved2 + 1;
+ const size_t kNumMissingPacketOffset =
+ kTimestampTimeDeltaLargestObserved2 + 2;
+ const size_t kMissingPacketsOffset =
+ kNumMissingPacketOffset + kNumberOfNackRangesSize;
+ const size_t kMissingPacketsRange =
+ kMissingPacketsOffset + PACKET_1BYTE_PACKET_NUMBER;
+ const size_t kRevivedPacketsLength =
+ kMissingPacketsRange + PACKET_1BYTE_PACKET_NUMBER;
+ // Now test framing boundaries.
+ const size_t ack_frame_size =
+ kRevivedPacketsLength + PACKET_1BYTE_PACKET_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kLargestObservedOffset) {
+ expected_error = "Unable to read entropy hash for received packets.";
+ } else if (i < kMissingDeltaTimeOffset) {
+ expected_error = "Unable to read largest observed.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to read ack delay time.";
+ } else if (i < kTimestampDeltaLargestObserved1) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < kTimestampTimeDeltaLargestObserved1) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else if (i < kTimestampDeltaLargestObserved2) {
+ expected_error = "Unable to read time delta in received packets.";
+ } else if (i < kTimestampTimeDeltaLargestObserved2) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else if (i < kNumMissingPacketOffset) {
+ expected_error =
+ "Unable to read incremental time delta in received packets.";
+ } else if (i < kMissingPacketsOffset) {
+ expected_error = "Unable to read num missing packet ranges.";
+ } else if (i < kMissingPacketsRange) {
+ expected_error = "Unable to read missing packet number delta.";
+ } else if (i < kRevivedPacketsLength) {
+ expected_error = "Unable to read missing packet number range.";
+ } else {
+ expected_error = "Unable to read num revived packets.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, AckFrameTwoTimestampVersion32) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet number
+ 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // Number of timestamps.
+ 0x02,
+ // Delta from largest observed.
+ 0x01,
+ // Delta time.
+ 0x10, 0x32, 0x54, 0x76,
+ // Delta from largest observed.
+ 0x02,
+ // Delta time.
+ 0x10, 0x32,
+ // num missing packets
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ };
+ // clang-format on
+
+ if (framer_.version() <= QUIC_VERSION_31 ||
+ framer_.version() > QUIC_VERSION_33) {
+ return;
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame.entropy_hash);
+ EXPECT_EQ(kLargestObserved, frame.largest_observed);
+ ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
+ ASSERT_EQ(2u, frame.received_packet_times.size());
+ EXPECT_EQ(kMissingPacket, frame.packets.Min());
+
+ const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLargestObservedOffset =
+ kReceivedEntropyOffset + kQuicEntropyHashSize;
+ const size_t kMissingDeltaTimeOffset =
+ kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
+ const size_t kNumTimestampsOffset =
+ kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
+ const size_t kTimestampDeltaLargestObserved1 =
+ kNumTimestampsOffset + kQuicNumTimestampsSize;
+ const size_t kTimestampTimeDeltaLargestObserved1 =
+ kTimestampDeltaLargestObserved1 + 1;
+ const size_t kTimestampDeltaLargestObserved2 =
+ kTimestampTimeDeltaLargestObserved1 + 4;
+ const size_t kTimestampTimeDeltaLargestObserved2 =
+ kTimestampDeltaLargestObserved2 + 1;
+ const size_t kNumMissingPacketOffset =
+ kTimestampTimeDeltaLargestObserved2 + 2;
+ const size_t kMissingPacketsOffset =
+ kNumMissingPacketOffset + kNumberOfNackRangesSize;
+ // Now test framing boundaries.
+ const size_t ack_frame_size = PACKET_1BYTE_PACKET_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kLargestObservedOffset) {
+ expected_error = "Unable to read entropy hash for received packets.";
+ } else if (i < kMissingDeltaTimeOffset) {
+ expected_error = "Unable to read largest observed.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to read ack delay time.";
+ } else if (i < kTimestampDeltaLargestObserved1) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < kTimestampTimeDeltaLargestObserved1) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else if (i < kTimestampDeltaLargestObserved2) {
+ expected_error = "Unable to read time delta in received packets.";
+ } else if (i < kTimestampTimeDeltaLargestObserved2) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else if (i < kNumMissingPacketOffset) {
+ expected_error =
+ "Unable to read incremental time delta in received packets.";
+ } else if (i < kMissingPacketsOffset) {
+ expected_error = "Unable to read num missing packet ranges.";
+ } else {
+ expected_error = "Unable to read missing packet number delta.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, AckFrameOneTimestamp) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet number
+ 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // Number of timestamps.
+ 0x01,
+ // Delta from largest observed.
+ 0x01,
+ // Delta time.
+ 0x10, 0x32, 0x54, 0x76,
+ // num missing packets
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // Number of revived packets.
+ 0x00,
+ };
+ // clang-format on
+
+ if (framer_.version() > QUIC_VERSION_31) {
+ return;
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame.entropy_hash);
+ EXPECT_EQ(kLargestObserved, frame.largest_observed);
+ ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
+ ASSERT_EQ(1u, frame.received_packet_times.size());
+ EXPECT_EQ(kMissingPacket, frame.packets.Min());
+
+ const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLargestObservedOffset =
+ kReceivedEntropyOffset + kQuicEntropyHashSize;
+ const size_t kMissingDeltaTimeOffset =
+ kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
+ const size_t kNumTimestampsOffset =
+ kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
+ const size_t kTimestampDeltaLargestObserved =
+ kNumTimestampsOffset + kQuicNumTimestampsSize;
+ const size_t kTimestampTimeDeltaLargestObserved =
+ kTimestampDeltaLargestObserved + 1;
+ const size_t kNumMissingPacketOffset = kTimestampTimeDeltaLargestObserved + 4;
+ const size_t kMissingPacketsOffset =
+ kNumMissingPacketOffset + kNumberOfNackRangesSize;
+ const size_t kMissingPacketsRange =
+ kMissingPacketsOffset + PACKET_1BYTE_PACKET_NUMBER;
+ const size_t kRevivedPacketsLength =
+ kMissingPacketsRange + PACKET_1BYTE_PACKET_NUMBER;
+ // Now test framing boundaries.
+ const size_t ack_frame_size =
+ kRevivedPacketsLength + PACKET_1BYTE_PACKET_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kLargestObservedOffset) {
+ expected_error = "Unable to read entropy hash for received packets.";
+ } else if (i < kMissingDeltaTimeOffset) {
+ expected_error = "Unable to read largest observed.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to read ack delay time.";
+ } else if (i < kTimestampDeltaLargestObserved) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < kTimestampTimeDeltaLargestObserved) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else if (i < kNumMissingPacketOffset) {
+ expected_error = "Unable to read time delta in received packets.";
+ } else if (i < kMissingPacketsOffset) {
+ expected_error = "Unable to read num missing packet ranges.";
+ } else if (i < kMissingPacketsRange) {
+ expected_error = "Unable to read missing packet number delta.";
+ } else if (i < kRevivedPacketsLength) {
+ expected_error = "Unable to read missing packet number range.";
+ } else {
+ expected_error = "Unable to read num revived packets.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, AckFrameOneTimestampVersion32) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet number
+ 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // Number of timestamps.
+ 0x01,
+ // Delta from largest observed.
+ 0x01,
+ // Delta time.
+ 0x10, 0x32, 0x54, 0x76,
+ // num missing packets
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ };
+ // clang-format on
+
+ if (framer_.version() <= QUIC_VERSION_31 ||
+ framer_.version() > QUIC_VERSION_33) {
+ return;
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame.entropy_hash);
+ EXPECT_EQ(kLargestObserved, frame.largest_observed);
+ ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
+ ASSERT_EQ(1u, frame.received_packet_times.size());
+ EXPECT_EQ(kMissingPacket, frame.packets.Min());
+
+ const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLargestObservedOffset =
+ kReceivedEntropyOffset + kQuicEntropyHashSize;
+ const size_t kMissingDeltaTimeOffset =
+ kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
+ const size_t kNumTimestampsOffset =
+ kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
+ const size_t kTimestampDeltaLargestObserved =
+ kNumTimestampsOffset + kQuicNumTimestampsSize;
+ const size_t kTimestampTimeDeltaLargestObserved =
+ kTimestampDeltaLargestObserved + 1;
+ const size_t kNumMissingPacketOffset = kTimestampTimeDeltaLargestObserved + 4;
+ const size_t kMissingPacketsOffset =
+ kNumMissingPacketOffset + kNumberOfNackRangesSize;
+ // Now test framing boundaries.
+ const size_t ack_frame_size = PACKET_1BYTE_PACKET_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kLargestObservedOffset) {
+ expected_error = "Unable to read entropy hash for received packets.";
+ } else if (i < kMissingDeltaTimeOffset) {
+ expected_error = "Unable to read largest observed.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to read ack delay time.";
+ } else if (i < kTimestampDeltaLargestObserved) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < kTimestampTimeDeltaLargestObserved) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else if (i < kNumMissingPacketOffset) {
+ expected_error = "Unable to read time delta in received packets.";
+ } else if (i < kMissingPacketsOffset) {
+ expected_error = "Unable to read num missing packet ranges.";
+ } else {
+ expected_error = "Unable to read missing packet number delta.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, AckFrame) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet number
+ 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // Number of timestamps.
+ 0x00,
+ // num missing packets
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // Number of revived packets.
+ 0x00,
+ };
+ // clang-format on
+
+ if (framer_.version() > QUIC_VERSION_31) {
+ return;
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame.entropy_hash);
+ EXPECT_EQ(kLargestObserved, frame.largest_observed);
+ ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
+ EXPECT_EQ(kMissingPacket, frame.packets.Min());
+
+ const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLargestObservedOffset =
+ kReceivedEntropyOffset + kQuicEntropyHashSize;
+ const size_t kMissingDeltaTimeOffset =
+ kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
+ const size_t kNumTimestampsOffset =
+ kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
+ const size_t kNumMissingPacketOffset =
+ kNumTimestampsOffset + kQuicNumTimestampsSize;
+ const size_t kMissingPacketsOffset =
+ kNumMissingPacketOffset + kNumberOfNackRangesSize;
+ const size_t kMissingPacketsRange =
+ kMissingPacketsOffset + PACKET_1BYTE_PACKET_NUMBER;
+ const size_t kRevivedPacketsLength =
+ kMissingPacketsRange + PACKET_1BYTE_PACKET_NUMBER;
+ // Now test framing boundaries.
+ const size_t ack_frame_size =
+ kRevivedPacketsLength + PACKET_1BYTE_PACKET_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kLargestObservedOffset) {
+ expected_error = "Unable to read entropy hash for received packets.";
+ } else if (i < kMissingDeltaTimeOffset) {
+ expected_error = "Unable to read largest observed.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to read ack delay time.";
+ } else if (i < kNumMissingPacketOffset) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < kMissingPacketsOffset) {
+ expected_error = "Unable to read num missing packet ranges.";
+ } else if (i < kMissingPacketsRange) {
+ expected_error = "Unable to read missing packet number delta.";
+ } else if (i < kRevivedPacketsLength) {
+ expected_error = "Unable to read missing packet number range.";
+ } else {
+ expected_error = "Unable to read num revived packets.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, NewAckFrameOneAckBlock) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+
+ // frame type (ack frame)
+ // (one ack block, 2 byte largest observed, 2 byte block length)
+ 0x45,
+ // largest acked
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x34, 0x12,
+ // num timestamps.
+ 0x00,
+ };
+ // clang-format on
+
+ if (framer_.version() <= QUIC_VERSION_33) {
+ return;
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(kSmallLargestObserved, frame.largest_observed);
+ EXPECT_FALSE(frame.missing);
+ ASSERT_EQ(4660u, frame.packets.NumPacketsSlow());
+
+ const size_t kLargestAckedOffset = kQuicFrameTypeSize;
+ const size_t kLargestAckedDeltaTimeOffset =
+ kLargestAckedOffset + PACKET_2BYTE_PACKET_NUMBER;
+ const size_t kFirstAckBlockLengthOffset =
+ kLargestAckedDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
+ const size_t kNumTimestampsOffset =
+ kFirstAckBlockLengthOffset + PACKET_2BYTE_PACKET_NUMBER;
+ // Now test framing boundaries.
+ const size_t ack_frame_size =
+ kFirstAckBlockLengthOffset + PACKET_2BYTE_PACKET_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kLargestAckedDeltaTimeOffset) {
+ expected_error = "Unable to read largest acked.";
+ } else if (i < kFirstAckBlockLengthOffset) {
+ expected_error = "Unable to read ack delay time.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to read first ack block length.";
+ } else {
+ expected_error = "Unable to read num received packets.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, NewAckFrameTwoTimeStampsMultipleAckBlocks) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // 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
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // num ack blocks ranges.
+ 0x04,
+ // first ack block length.
+ 0x01, 0x00,
+ // gap to next block.
+ 0x01,
+ // ack block length.
+ 0xaf, 0x0e,
+ // gap to next block.
+ 0xff,
+ // ack block length.
+ 0x00, 0x00,
+ // gap to next block.
+ 0x91,
+ // ack block length.
+ 0xea, 0x01,
+ // gap to next block.
+ 0x05,
+ // ack block length.
+ 0x04, 0x00,
+ // Number of timestamps.
+ 0x02,
+ // Delta from largest observed.
+ 0x01,
+ // Delta time.
+ 0x10, 0x32, 0x54, 0x76,
+ // Delta from largest observed.
+ 0x02,
+ // Delta time.
+ 0x10, 0x32,
+ };
+ // clang-format on
+
+ if (framer_.version() <= QUIC_VERSION_33) {
+ return;
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(kSmallLargestObserved, frame.largest_observed);
+ EXPECT_FALSE(frame.missing);
+ ASSERT_EQ(4254u, frame.packets.NumPacketsSlow());
+
+ const size_t kLargestAckedOffset = kQuicFrameTypeSize;
+ const size_t kLargestAckedDeltaTimeOffset =
+ kLargestAckedOffset + PACKET_2BYTE_PACKET_NUMBER;
+ const size_t kNumberOfAckBlocksOffset =
+ kLargestAckedDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
+ const size_t kFirstAckBlockLengthOffset =
+ kNumberOfAckBlocksOffset + kNumberOfAckBlocksSize;
+ const size_t kGapToNextBlockOffset1 =
+ kFirstAckBlockLengthOffset + PACKET_2BYTE_PACKET_NUMBER;
+ const size_t kAckBlockLengthOffset1 = kGapToNextBlockOffset1 + 1;
+ const size_t kGapToNextBlockOffset2 =
+ kAckBlockLengthOffset1 + PACKET_2BYTE_PACKET_NUMBER;
+ const size_t kAckBlockLengthOffset2 = kGapToNextBlockOffset2 + 1;
+ const size_t kGapToNextBlockOffset3 =
+ kAckBlockLengthOffset2 + PACKET_2BYTE_PACKET_NUMBER;
+ const size_t kAckBlockLengthOffset3 = kGapToNextBlockOffset3 + 1;
+ const size_t kGapToNextBlockOffset4 =
+ kAckBlockLengthOffset3 + PACKET_2BYTE_PACKET_NUMBER;
+ const size_t kAckBlockLengthOffset4 = kGapToNextBlockOffset3 + 1;
+ const size_t kNumTimestampsOffset =
+ kAckBlockLengthOffset4 + PACKET_2BYTE_PACKET_NUMBER;
+ const size_t kTimestampDeltaLargestObserved1 =
+ kNumTimestampsOffset + kQuicNumTimestampsSize;
+ const size_t kTimestampTimeDeltaLargestObserved1 =
+ kTimestampDeltaLargestObserved1 + 1;
+ const size_t kTimestampDeltaLargestObserved2 =
+ kTimestampTimeDeltaLargestObserved1 + 4;
+ const size_t kTimestampTimeDeltaLargestObserved2 =
+ kTimestampDeltaLargestObserved2 + 1;
+
+ // Now test framing boundaries.
+ const size_t ack_frame_size =
+ kAckBlockLengthOffset4 + PACKET_2BYTE_PACKET_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kLargestAckedDeltaTimeOffset) {
+ expected_error = "Unable to read largest acked.";
+ } else if (i < kNumberOfAckBlocksOffset) {
+ expected_error = "Unable to read ack delay time.";
+ } else if (i < kFirstAckBlockLengthOffset) {
+ expected_error = "Unable to read num of ack blocks.";
+ } else if (i < kGapToNextBlockOffset1) {
+ expected_error = "Unable to read first ack block length.";
+ } else if (i < kAckBlockLengthOffset1) {
+ expected_error = "Unable to read gap to next ack block.";
+ } else if (i < kGapToNextBlockOffset2) {
+ expected_error = "Unable to ack block length.";
+ } else if (i < kAckBlockLengthOffset2) {
+ expected_error = "Unable to read gap to next ack block.";
+ } else if (i < kGapToNextBlockOffset3) {
+ expected_error = "Unable to ack block length.";
+ } else if (i < kAckBlockLengthOffset3) {
+ expected_error = "Unable to read gap to next ack block.";
+ } else if (i < kGapToNextBlockOffset4) {
+ expected_error = "Unable to ack block length.";
+ } else if (i < kAckBlockLengthOffset4) {
+ expected_error = "Unable to read gap to next ack block.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to ack block length.";
+ } else if (i < kTimestampDeltaLargestObserved1) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < kTimestampTimeDeltaLargestObserved1) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else if (i < kTimestampDeltaLargestObserved2) {
+ expected_error = "Unable to read time delta in received packets.";
+ } else if (i < kTimestampTimeDeltaLargestObserved2) {
+ expected_error = "Unable to read sequence delta in received packets.";
+ } else {
+ expected_error =
+ "Unable to read incremental time delta in received packets.";
+ }
+
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, AckFrameVersion32) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet number
+ 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // Number of timestamps.
+ 0x00,
+ // num missing packets
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ };
+ // clang-format on
+
+ if (framer_.version() <= QUIC_VERSION_31 ||
+ framer_.version() > QUIC_VERSION_33) {
+ return;
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame.entropy_hash);
+ EXPECT_EQ(kLargestObserved, frame.largest_observed);
+ ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
+ EXPECT_EQ(kMissingPacket, frame.packets.Min());
+
+ const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLargestObservedOffset =
+ kReceivedEntropyOffset + kQuicEntropyHashSize;
+ const size_t kMissingDeltaTimeOffset =
+ kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
+ const size_t kNumTimestampsOffset =
+ kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
+ const size_t kNumMissingPacketOffset =
+ kNumTimestampsOffset + kQuicNumTimestampsSize;
+ const size_t kMissingPacketsOffset =
+ kNumMissingPacketOffset + kNumberOfNackRangesSize;
+ // Now test framing boundaries.
+ const size_t ack_frame_size = PACKET_1BYTE_PACKET_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kLargestObservedOffset) {
+ expected_error = "Unable to read entropy hash for received packets.";
+ } else if (i < kMissingDeltaTimeOffset) {
+ expected_error = "Unable to read largest observed.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to read ack delay time.";
+ } else if (i < kNumMissingPacketOffset) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < kMissingPacketsOffset) {
+ expected_error = "Unable to read num missing packet ranges.";
+ } else {
+ expected_error = "Unable to read missing packet number delta.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet number
+ 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // num received packets.
+ 0x00,
+ // num missing packets
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // Number of revived packets.
+ 0x01,
+ // Revived packet number.
+ 0xBE, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // Number of revived packets.
+ 0x00,
+ };
+ // clang-format on
+
+ if (framer_.version() > QUIC_VERSION_31) {
+ return;
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ const QuicAckFrame& frame = *visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame.entropy_hash);
+ EXPECT_EQ(kLargestObserved, frame.largest_observed);
+ ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
+ EXPECT_EQ(kMissingPacket, frame.packets.Min());
+
+ const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLargestObservedOffset =
+ kReceivedEntropyOffset + kQuicEntropyHashSize;
+ const size_t kMissingDeltaTimeOffset =
+ kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
+ const size_t kNumTimestampsOffset =
+ kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
+ const size_t kNumMissingPacketOffset =
+ kNumTimestampsOffset + kQuicNumTimestampsSize;
+ const size_t kMissingPacketsOffset =
+ kNumMissingPacketOffset + kNumberOfNackRangesSize;
+ const size_t kMissingPacketsRange =
+ kMissingPacketsOffset + PACKET_1BYTE_PACKET_NUMBER;
+ const size_t kRevivedPacketsLength =
+ kMissingPacketsRange + PACKET_1BYTE_PACKET_NUMBER;
+ const size_t kRevivedPacketSequenceNumberLength =
+ kRevivedPacketsLength + PACKET_1BYTE_PACKET_NUMBER;
+ // Now test framing boundaries.
+ const size_t ack_frame_size =
+ kRevivedPacketSequenceNumberLength + PACKET_6BYTE_PACKET_NUMBER;
+ for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
+ string expected_error;
+ if (i < kReceivedEntropyOffset) {
+ expected_error = "Unable to read least unacked delta.";
+ } else if (i < kLargestObservedOffset) {
+ expected_error = "Unable to read entropy hash for received packets.";
+ } else if (i < kMissingDeltaTimeOffset) {
+ expected_error = "Unable to read largest observed.";
+ } else if (i < kNumTimestampsOffset) {
+ expected_error = "Unable to read ack delay time.";
+ } else if (i < kNumMissingPacketOffset) {
+ expected_error = "Unable to read num received packets.";
+ } else if (i < kMissingPacketsOffset) {
+ expected_error = "Unable to read num missing packet ranges.";
+ } else if (i < kMissingPacketsRange) {
+ expected_error = "Unable to read missing packet number delta.";
+ } else if (i < kRevivedPacketsLength) {
+ expected_error = "Unable to read missing packet number range.";
+ } else if (i < kRevivedPacketSequenceNumberLength) {
+ expected_error = "Unable to read num revived packets.";
+ } else {
+ expected_error = "Unable to read revived packet.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_ACK_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, AckFrameNoNacks) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (no nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x4C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet number
+ 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // Number of received packets.
+ 0x00,
+ };
+ // clang-format on
+ if (framer_.version() >= QUIC_VERSION_31) {
+ return;
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ QuicAckFrame* frame = visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame->entropy_hash);
+ EXPECT_EQ(kLargestObserved, frame->largest_observed);
+ ASSERT_TRUE(frame->packets.Empty());
+
+ // Verify that the packet re-serializes identically.
+ QuicFrames frames;
+ frames.push_back(QuicFrame(frame));
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, AckFrame500Nacks) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet number
+ 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // No received packets.
+ 0x00,
+ // num missing packet ranges
+ 0x02,
+ // missing packet delta
+ 0x01,
+ // 243 more missing packets in range.
+ // The ranges are listed in this order so the re-constructed packet
+ // matches.
+ 0xF3,
+ // No gap between ranges
+ 0x00,
+ // 255 more missing packets in range.
+ 0xFF,
+ // No revived packets.
+ 0x00,
+ };
+ // clang-format on
+
+ if (framer_.version() > QUIC_VERSION_31) {
+ return;
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ QuicAckFrame* frame = visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame->entropy_hash);
+ EXPECT_EQ(kLargestObserved, frame->largest_observed);
+ ASSERT_EQ(500u, frame->packets.NumPacketsSlow());
+ EXPECT_EQ(kMissingPacket - 499, frame->packets.Min());
+ EXPECT_EQ(kMissingPacket, frame->packets.Max());
+
+ // Verify that the packet re-serializes identically.
+ QuicFrames frames;
+ frames.push_back(QuicFrame(frame));
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, AckFrame500NacksVersion32) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0xBA,
+ // largest observed packet number
+ 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // No received packets.
+ 0x00,
+ // num missing packet ranges
+ 0x02,
+ // missing packet delta
+ 0x01,
+ // 243 more missing packets in range.
+ // The ranges are listed in this order so the re-constructed packet
+ // matches.
+ 0xF3,
+ // No gap between ranges
+ 0x00,
+ // 255 more missing packets in range.
+ 0xFF,
+ };
+ // clang-format on
+
+ if (framer_.version() <= QUIC_VERSION_31 ||
+ framer_.version() > QUIC_VERSION_33) {
+ return;
+ }
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ QuicAckFrame* frame = visitor_.ack_frames_[0];
+ EXPECT_EQ(0xBA, frame->entropy_hash);
+ EXPECT_EQ(kLargestObserved, frame->largest_observed);
+ ASSERT_EQ(500u, frame->packets.NumPacketsSlow());
+ EXPECT_EQ(kMissingPacket - 499, frame->packets.Min());
+ EXPECT_EQ(kMissingPacket, frame->packets.Max());
+
+ // Verify that the packet re-serializes identically.
+ QuicFrames frames;
+ frames.push_back(QuicFrame(frame));
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, StopWaitingFrame) {
+ if (framer_.version() > QUIC_VERSION_33) {
+ return;
+ }
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x06,
+ // entropy hash of sent packets till least awaiting - 1.
+ 0xAB,
+ // least packet number awaiting an ack, delta from packet number.
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.stop_waiting_frames_.size());
+ const QuicStopWaitingFrame& frame = *visitor_.stop_waiting_frames_[0];
+ EXPECT_EQ(0xAB, frame.entropy_hash);
+ EXPECT_EQ(kLeastUnacked, frame.least_unacked);
+
+ const size_t kSentEntropyOffset = kQuicFrameTypeSize;
+ const size_t kLeastUnackedOffset = kSentEntropyOffset + kQuicEntropyHashSize;
+ const size_t frame_size = 7;
+ for (size_t i = kQuicFrameTypeSize; i < frame_size; ++i) {
+ string expected_error;
+ if (i < kLeastUnackedOffset) {
+ expected_error = "Unable to read entropy hash for sent packets.";
+ } else {
+ expected_error = "Unable to read least unacked delta.";
+ }
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_STOP_WAITING_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, NewStopWaitingFrame) {
+ if (framer_.version() <= QUIC_VERSION_33) {
+ return;
+ }
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xA8, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // frame type (stop waiting frame)
+ 0x06,
+ // least packet number awaiting an ack, delta from packet number.
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+ ASSERT_EQ(1u, visitor_.stop_waiting_frames_.size());
+ const QuicStopWaitingFrame& frame = *visitor_.stop_waiting_frames_[0];
+ EXPECT_EQ(kLeastUnacked, frame.least_unacked);
+
+ const size_t frame_size = 7;
+ for (size_t i = kQuicFrameTypeSize; i < frame_size; ++i) {
+ string expected_error;
+ expected_error = "Unable to read least unacked delta.";
+ CheckProcessingFails(
+ packet,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_STOP_WAITING_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, RstStreamFrameQuic) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (rst stream frame)
+ 0x01,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+
+ // sent byte offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+
+ // error code
+ 0x01, 0x00, 0x00, 0x00,
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (rst stream frame)
+ 0x01,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+
+ // sent byte offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+
+ // error code
+ 0x01, 0x00, 0x00, 0x00,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(kStreamId, visitor_.rst_stream_frame_.stream_id);
+ EXPECT_EQ(0x01, visitor_.rst_stream_frame_.error_code);
+ EXPECT_EQ(kStreamOffset, visitor_.rst_stream_frame_.byte_offset);
+
+ // Now test framing boundaries.
+ for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetRstStreamFrameSize();
+ ++i) {
+ string expected_error;
+ if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
+ expected_error = "Unable to read stream_id.";
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
+ kQuicMaxStreamOffsetSize) {
+ expected_error = "Unable to read rst stream sent byte offset.";
+ } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
+ kQuicMaxStreamOffsetSize + kQuicErrorCodeSize) {
+ expected_error = "Unable to read rst stream error code.";
+ }
+ CheckProcessingFails(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_RST_STREAM_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, ConnectionCloseFrame) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (connection close frame)
+ 0x02,
+ // error code
+ 0x11, 0x00, 0x00, 0x00,
+
+ // error details length
+ 0x0d, 0x00,
+ // error details
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n',
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (connection close frame)
+ 0x02,
+ // error code
+ 0x11, 0x00, 0x00, 0x00,
+
+ // error details length
+ 0x0d, 0x00,
+ // error details
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n',
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(0u, visitor_.stream_frames_.size());
+
+ EXPECT_EQ(0x11, visitor_.connection_close_frame_.error_code);
+ EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details);
+
+ ASSERT_EQ(0u, visitor_.ack_frames_.size());
+
+ // Now test framing boundaries.
+ for (size_t i = kQuicFrameTypeSize;
+ i < QuicFramer::GetMinConnectionCloseFrameSize(); ++i) {
+ string expected_error;
+ if (i < kQuicFrameTypeSize + kQuicErrorCodeSize) {
+ expected_error = "Unable to read connection close error code.";
+ } else {
+ expected_error = "Unable to read connection close error details.";
+ }
+ CheckProcessingFails(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_CONNECTION_CLOSE_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, GoAwayFrame) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (go away frame)
+ 0x03,
+ // error code
+ 0x09, 0x00, 0x00, 0x00,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // error details length
+ 0x0d, 0x00,
+ // error details
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n',
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (go away frame)
+ 0x03,
+ // error code
+ 0x09, 0x00, 0x00, 0x00,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // error details length
+ 0x0d, 0x00,
+ // error details
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n',
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(kStreamId, visitor_.goaway_frame_.last_good_stream_id);
+ EXPECT_EQ(0x9, visitor_.goaway_frame_.error_code);
+ EXPECT_EQ("because I can", visitor_.goaway_frame_.reason_phrase);
+
+ const size_t reason_size = arraysize("because I can") - 1;
+ // Now test framing boundaries.
+ for (size_t i = kQuicFrameTypeSize;
+ i < QuicFramer::GetMinGoAwayFrameSize() + reason_size; ++i) {
+ string expected_error;
+ if (i < kQuicFrameTypeSize + kQuicErrorCodeSize) {
+ expected_error = "Unable to read go away error code.";
+ } else if (i <
+ kQuicFrameTypeSize + kQuicErrorCodeSize + kQuicMaxStreamIdSize) {
+ expected_error = "Unable to read last good stream id.";
+ } else {
+ expected_error = "Unable to read goaway reason.";
+ }
+ CheckProcessingFails(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_GOAWAY_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, WindowUpdateFrame) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (window update frame)
+ 0x04,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // byte offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (window update frame)
+ 0x04,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // byte offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(kStreamId, visitor_.window_update_frame_.stream_id);
+ EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.byte_offset);
+
+ // Now test framing boundaries.
+ for (size_t i = kQuicFrameTypeSize;
+ i < QuicFramer::GetWindowUpdateFrameSize(); ++i) {
+ string expected_error;
+ if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
+ expected_error = "Unable to read stream_id.";
+ } else {
+ expected_error = "Unable to read window byte_offset.";
+ }
+ CheckProcessingFails(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_WINDOW_UPDATE_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, BlockedFrame) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (blocked frame)
+ 0x05,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (blocked frame)
+ 0x05,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(kStreamId, visitor_.blocked_frame_.stream_id);
+
+ // Now test framing boundaries.
+ for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetBlockedFrameSize();
+ ++i) {
+ string expected_error = "Unable to read stream_id.";
+ CheckProcessingFails(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_BLOCKED_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, PingFrame) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (ping frame)
+ 0x07,
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (ping frame)
+ 0x07,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce));
+
+ EXPECT_EQ(1u, visitor_.ping_frames_.size());
+
+ // No need to check the PING frame boundaries because it has no payload.
+}
+
+TEST_P(QuicFramerTest, PathCloseFrame) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version)
+ 0x78,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x00,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (path_close_frame)
+ 0x08,
+ // path id
+ 0x42,
+ };
+ unsigned char packet_34[] = {
+ // public flags (version)
+ 0x78,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x00,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+
+ // frame type (path_close_frame)
+ 0x08,
+ // path id
+ 0x42,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ // TODO(fayang): CheckDecryption after cl/110553865 is landed.
+ EXPECT_EQ(kPathId, visitor_.path_close_frame_.path_id);
+
+ // Now test framing boundaries.
+ for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetPathCloseFrameSize();
+ ++i) {
+ string expected_error;
+ if (i < kQuicFrameTypeSize + kQuicPathIdSize) {
+ expected_error = "Unable to read path_id.";
+ }
+ CheckProcessingFails(
+ framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
+ i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, kIncludePathId,
+ !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER),
+ expected_error, QUIC_INVALID_PATH_CLOSE_DATA);
+ }
+}
+
+TEST_P(QuicFramerTest, PublicResetPacketV33) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (public reset, 8 byte connection_id)
+ 0x0A,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // message tag (kPRST)
+ 'P', 'R', 'S', 'T',
+ // num_entries (2) + padding
+ 0x02, 0x00, 0x00, 0x00,
+ // tag kRNON
+ 'R', 'N', 'O', 'N',
+ // end offset 8
+ 0x08, 0x00, 0x00, 0x00,
+ // tag kRSEQ
+ 'R', 'S', 'E', 'Q',
+ // end offset 16
+ 0x10, 0x00, 0x00, 0x00,
+ // nonce proof
+ 0x89, 0x67, 0x45, 0x23,
+ 0x01, 0xEF, 0xCD, 0xAB,
+ // rejected packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12, 0x00, 0x00,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.public_reset_packet_.get());
+ EXPECT_EQ(kConnectionId,
+ visitor_.public_reset_packet_->public_header.connection_id);
+ EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag);
+ EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag);
+ EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof);
+ EXPECT_EQ(0u, visitor_.public_reset_packet_->rejected_packet_number);
+ EXPECT_EQ(ADDRESS_FAMILY_UNSPECIFIED,
+ visitor_.public_reset_packet_->client_address.GetFamily());
+
+ // Now test framing boundaries.
+ for (size_t i = 0; i < arraysize(packet); ++i) {
+ string expected_error;
+ DVLOG(1) << "iteration: " << i;
+ if (i < kConnectionIdOffset) {
+ expected_error = "Unable to read public flags.";
+ CheckProcessingFails(packet, i, expected_error,
+ QUIC_INVALID_PACKET_HEADER);
+ } else if (i < kPublicResetPacketMessageTagOffset) {
+ expected_error = "Unable to read ConnectionId.";
+ CheckProcessingFails(packet, i, expected_error,
+ QUIC_INVALID_PACKET_HEADER);
+ } else {
+ expected_error = "Unable to read reset message.";
+ CheckProcessingFails(packet, i, expected_error,
+ QUIC_INVALID_PUBLIC_RST_PACKET);
+ }
+ }
+}
+
+TEST_P(QuicFramerTest, PublicResetPacket) {
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (public reset, 8 byte connection_id)
+ 0x0E,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // message tag (kPRST)
+ 'P', 'R', 'S', 'T',
+ // num_entries (2) + padding
+ 0x02, 0x00, 0x00, 0x00,
+ // tag kRNON
+ 'R', 'N', 'O', 'N',
+ // end offset 8
+ 0x08, 0x00, 0x00, 0x00,
+ // tag kRSEQ
+ 'R', 'S', 'E', 'Q',
+ // end offset 16
+ 0x10, 0x00, 0x00, 0x00,
+ // nonce proof
+ 0x89, 0x67, 0x45, 0x23,
+ 0x01, 0xEF, 0xCD, 0xAB,
+ // rejected packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12, 0x00, 0x00,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.public_reset_packet_.get());
+ EXPECT_EQ(kConnectionId,
+ visitor_.public_reset_packet_->public_header.connection_id);
+ EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag);
+ EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag);
+ EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof);
+ EXPECT_EQ(0u, visitor_.public_reset_packet_->rejected_packet_number);
+ EXPECT_EQ(ADDRESS_FAMILY_UNSPECIFIED,
+ visitor_.public_reset_packet_->client_address.GetFamily());
+
+ // Now test framing boundaries.
+ for (size_t i = 0; i < arraysize(packet); ++i) {
+ string expected_error;
+ DVLOG(1) << "iteration: " << i;
+ if (i < kConnectionIdOffset) {
+ expected_error = "Unable to read public flags.";
+ CheckProcessingFails(packet, i, expected_error,
+ QUIC_INVALID_PACKET_HEADER);
+ } else if (i < kPublicResetPacketMessageTagOffset) {
+ expected_error = "Unable to read ConnectionId.";
+ CheckProcessingFails(packet, i, expected_error,
+ QUIC_INVALID_PACKET_HEADER);
+ } else {
+ expected_error = "Unable to read reset message.";
+ CheckProcessingFails(packet, i, expected_error,
+ QUIC_INVALID_PUBLIC_RST_PACKET);
+ }
+ }
+}
+
+TEST_P(QuicFramerTest, PublicResetPacketWithTrailingJunk) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (public reset, 8 byte connection_id)
+ 0x0A,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // message tag (kPRST)
+ 'P', 'R', 'S', 'T',
+ // num_entries (2) + padding
+ 0x02, 0x00, 0x00, 0x00,
+ // tag kRNON
+ 'R', 'N', 'O', 'N',
+ // end offset 8
+ 0x08, 0x00, 0x00, 0x00,
+ // tag kRSEQ
+ 'R', 'S', 'E', 'Q',
+ // end offset 16
+ 0x10, 0x00, 0x00, 0x00,
+ // nonce proof
+ 0x89, 0x67, 0x45, 0x23,
+ 0x01, 0xEF, 0xCD, 0xAB,
+ // rejected packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12, 0x00, 0x00,
+ // trailing junk
+ 'j', 'u', 'n', 'k',
+ };
+ // clang-format on
+
+ string expected_error = "Unable to read reset message.";
+ CheckProcessingFails(packet, arraysize(packet), expected_error,
+ QUIC_INVALID_PUBLIC_RST_PACKET);
+}
+
+TEST_P(QuicFramerTest, PublicResetPacketWithClientAddress) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (public reset, 8 byte connection_id)
+ 0x0A,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // message tag (kPRST)
+ 'P', 'R', 'S', 'T',
+ // num_entries (3) + padding
+ 0x03, 0x00, 0x00, 0x00,
+ // tag kRNON
+ 'R', 'N', 'O', 'N',
+ // end offset 8
+ 0x08, 0x00, 0x00, 0x00,
+ // tag kRSEQ
+ 'R', 'S', 'E', 'Q',
+ // end offset 16
+ 0x10, 0x00, 0x00, 0x00,
+ // tag kCADR
+ 'C', 'A', 'D', 'R',
+ // end offset 24
+ 0x18, 0x00, 0x00, 0x00,
+ // nonce proof
+ 0x89, 0x67, 0x45, 0x23,
+ 0x01, 0xEF, 0xCD, 0xAB,
+ // rejected packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12, 0x00, 0x00,
+ // client address: 4.31.198.44:443
+ 0x02, 0x00,
+ 0x04, 0x1F, 0xC6, 0x2C,
+ 0xBB, 0x01,
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.public_reset_packet_.get());
+ EXPECT_EQ(kConnectionId,
+ visitor_.public_reset_packet_->public_header.connection_id);
+ EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag);
+ EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag);
+ EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof);
+ EXPECT_EQ(0u, visitor_.public_reset_packet_->rejected_packet_number);
+ EXPECT_EQ("4.31.198.44",
+ visitor_.public_reset_packet_->client_address.address().ToString());
+ EXPECT_EQ(443, visitor_.public_reset_packet_->client_address.port());
+
+ // Now test framing boundaries.
+ for (size_t i = 0; i < arraysize(packet); ++i) {
+ string expected_error;
+ DVLOG(1) << "iteration: " << i;
+ if (i < kConnectionIdOffset) {
+ expected_error = "Unable to read public flags.";
+ CheckProcessingFails(packet, i, expected_error,
+ QUIC_INVALID_PACKET_HEADER);
+ } else if (i < kPublicResetPacketMessageTagOffset) {
+ expected_error = "Unable to read ConnectionId.";
+ CheckProcessingFails(packet, i, expected_error,
+ QUIC_INVALID_PACKET_HEADER);
+ } else {
+ expected_error = "Unable to read reset message.";
+ CheckProcessingFails(packet, i, expected_error,
+ QUIC_INVALID_PUBLIC_RST_PACKET);
+ }
+ }
+}
+
+TEST_P(QuicFramerTest, VersionNegotiationPacket) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version, 8 byte connection_id)
+ 0x39,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ 'Q', '2', '.', '0',
+ };
+ // clang-format on
+
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.version_negotiation_packet_.get());
+ EXPECT_EQ(2u, visitor_.version_negotiation_packet_->versions.size());
+ EXPECT_EQ(GetParam(), visitor_.version_negotiation_packet_->versions[0]);
+
+ for (size_t i = 0; i <= kPublicFlagsSize + PACKET_8BYTE_CONNECTION_ID; ++i) {
+ string expected_error;
+ QuicErrorCode error_code = QUIC_INVALID_PACKET_HEADER;
+ if (i < kConnectionIdOffset) {
+ expected_error = "Unable to read public flags.";
+ } else if (i < kVersionOffset) {
+ expected_error = "Unable to read ConnectionId.";
+ } else {
+ expected_error = "Unable to read supported version in negotiation.";
+ error_code = QUIC_INVALID_VERSION_NEGOTIATION_PACKET;
+ }
+ CheckProcessingFails(packet, i, expected_error, error_code);
+ }
+}
+
+TEST_P(QuicFramerTest, OldVersionNegotiationPacket) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version, 8 byte connection_id)
+ 0x3D,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ 'Q', '2', '.', '0',
+ };
+ // clang-format on
+
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.version_negotiation_packet_.get());
+ EXPECT_EQ(2u, visitor_.version_negotiation_packet_->versions.size());
+ EXPECT_EQ(GetParam(), visitor_.version_negotiation_packet_->versions[0]);
+
+ for (size_t i = 0; i <= kPublicFlagsSize + PACKET_8BYTE_CONNECTION_ID; ++i) {
+ string expected_error;
+ QuicErrorCode error_code = QUIC_INVALID_PACKET_HEADER;
+ if (i < kConnectionIdOffset) {
+ expected_error = "Unable to read public flags.";
+ } else if (i < kVersionOffset) {
+ expected_error = "Unable to read ConnectionId.";
+ } else {
+ expected_error = "Unable to read supported version in negotiation.";
+ error_code = QUIC_INVALID_VERSION_NEGOTIATION_PACKET;
+ }
+ CheckProcessingFails(packet, i, expected_error, error_code);
+ }
+}
+
+TEST_P(QuicFramerTest, DropFecPacket) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (fec group & FEC)
+ 0x06,
+ // first fec protected packet offset
+ 0x01,
+
+ // redundancy
+ 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h',
+ 'i', 'j', 'k', 'l',
+ 'm', 'n', 'o', 'p',
+ };
+ if (framer_.version() > QUIC_VERSION_33) {
+ return;
+ }
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ if (framer_.version() <= QUIC_VERSION_31) {
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ } else {
+ EXPECT_FALSE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
+ }
+ EXPECT_FALSE(visitor_.header_.get());
+}
+
+TEST_P(QuicFramerTest, BuildPaddingFramePacket) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = false;
+ header.packet_number = kPacketNumber;
+
+ QuicPaddingFrame padding_frame;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(padding_frame));
+
+ // clang-format off
+ unsigned char packet[kMaxPacketSize] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (padding frame)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ unsigned char packet_34[kMaxPacketSize] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (padding frame)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ // clang-format on
+
+ uint64_t header_size = GetPacketHeaderSize(
+ framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+ !kIncludePathId, !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER);
+ memset((framer_.version() <= QUIC_VERSION_33 ? packet : packet_34) +
+ header_size + 1,
+ 0x00, kMaxPacketSize - header_size - 1);
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = false;
+ header.public_header.packet_number_length = PACKET_4BYTE_PACKET_NUMBER;
+ header.packet_number = kPacketNumber;
+
+ QuicPaddingFrame padding_frame;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(padding_frame));
+
+ // clang-format off
+ unsigned char packet[kMaxPacketSize] = {
+ // public flags (8 byte connection_id and 4 byte packet number)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x28 : 0x2C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ // private flags
+ 0x00,
+
+ // frame type (padding frame)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ unsigned char packet_34[kMaxPacketSize] = {
+ // public flags (8 byte connection_id and 4 byte packet number)
+ 0x28,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+
+ // frame type (padding frame)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ // clang-format on
+
+ uint64_t header_size = GetPacketHeaderSize(
+ framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+ !kIncludePathId, !kIncludeDiversificationNonce,
+ PACKET_4BYTE_PACKET_NUMBER);
+ memset((framer_.version() <= QUIC_VERSION_33 ? packet : packet_34) +
+ header_size + 1,
+ 0x00, kMaxPacketSize - header_size - 1);
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = false;
+ header.public_header.packet_number_length = PACKET_2BYTE_PACKET_NUMBER;
+ header.packet_number = kPacketNumber;
+
+ QuicPaddingFrame padding_frame;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(padding_frame));
+
+ // clang-format off
+ unsigned char packet[kMaxPacketSize] = {
+ // public flags (8 byte connection_id and 2 byte packet number)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x18 : 0x1C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A,
+ // private flags
+ 0x00,
+
+ // frame type (padding frame)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ unsigned char packet_34[kMaxPacketSize] = {
+ // public flags (8 byte connection_id and 2 byte packet number)
+ 0x18,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A,
+
+ // frame type (padding frame)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ // clang-format on
+
+ uint64_t header_size = GetPacketHeaderSize(
+ framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+ !kIncludePathId, !kIncludeDiversificationNonce,
+ PACKET_2BYTE_PACKET_NUMBER);
+ memset((framer_.version() <= QUIC_VERSION_33 ? packet : packet_34) +
+ header_size + 1,
+ 0x00, kMaxPacketSize - header_size - 1);
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = false;
+ header.public_header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER;
+ header.packet_number = kPacketNumber;
+
+ QuicPaddingFrame padding_frame;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(padding_frame));
+
+ // clang-format off
+ unsigned char packet[kMaxPacketSize] = {
+ // public flags (8 byte connection_id and 1 byte packet number)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x08 : 0x0C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC,
+ // private flags
+ 0x00,
+
+ // frame type (padding frame)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ unsigned char packet_34[kMaxPacketSize] = {
+ // public flags (8 byte connection_id and 1 byte packet number)
+ 0x08,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC,
+
+ // frame type (padding frame)
+ 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+ // clang-format on
+
+ uint64_t header_size = GetPacketHeaderSize(
+ framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
+ !kIncludePathId, !kIncludeDiversificationNonce,
+ PACKET_1BYTE_PACKET_NUMBER);
+ memset((framer_.version() <= QUIC_VERSION_33 ? packet : packet_34) +
+ header_size + 1,
+ 0x00, kMaxPacketSize - header_size - 1);
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+TEST_P(QuicFramerTest, BuildStreamFramePacket) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_number = kPacketNumber;
+
+ QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
+ StringPiece("hello world!"));
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&stream_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (stream frame with fin and no length)
+ 0xDF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (stream frame with fin and no length)
+ 0xDF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = true;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_number = kPacketNumber;
+
+ QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
+ StringPiece("hello world!"));
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&stream_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version, 8 byte connection_id)
+ static_cast<unsigned char>(
+ (FLAGS_quic_remove_v33_hacks2 &&
+ framer_.version() > QUIC_VERSION_32) ? 0x39 : 0x3D),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (stream frame with fin and no length)
+ 0xDF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32, 0xDC, 0xFE, 0x98, 0xBA,
+ // data
+ 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
+ };
+ unsigned char packet_34[] = {
+ // public flags (version, 8 byte connection_id)
+ static_cast<unsigned char>(
+ FLAGS_quic_remove_v33_hacks2 ? 0x39 : 0x3D),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+
+ // frame type (stream frame with fin and no length)
+ 0xDF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32, 0xDC, 0xFE, 0x98, 0xBA,
+ // data
+ 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
+ };
+ // clang-format on
+
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+TEST_P(QuicFramerTest, BuildStreamFramePacketWithMultipathFlag) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.multipath_flag = true;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.path_id = kPathId;
+ header.packet_number = kPacketNumber;
+
+ QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
+ StringPiece("hello world!"));
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&stream_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x78 : 0x7C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (stream frame with fin and no length)
+ 0xDF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x78,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (stream frame with fin and no length)
+ 0xDF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+TEST_P(QuicFramerTest, BuildStreamFramePacketWithBothVersionAndMultipathFlag) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.multipath_flag = true;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = true;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.path_id = kPathId;
+ header.packet_number = kPacketNumber;
+
+ QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
+ StringPiece("hello world!"));
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&stream_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ (FLAGS_quic_remove_v33_hacks2 &&
+ framer_.version() > QUIC_VERSION_32) ? 0x79 : 0x7D),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (stream frame with fin and no length)
+ 0xDF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ FLAGS_quic_remove_v33_hacks2 ? 0x79 : 0x7D),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (stream frame with fin and no length)
+ 0xDF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ // clang-format on
+
+ QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version, 8 byte connection_id)
+ 0x0D,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
+ };
+ // clang-format on
+
+ QuicConnectionId connection_id = kConnectionId;
+ std::unique_ptr<QuicEncryptedPacket> data(
+ framer_.BuildVersionNegotiationPacket(connection_id,
+ SupportedVersions(GetParam())));
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, BuildAckFramePacket) {
+ if (framer_.version() > QUIC_VERSION_33) {
+ return;
+ }
+
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_number = kPacketNumber;
+
+ QuicAckFrame ack_frame;
+ ack_frame.entropy_hash = 0x43;
+ ack_frame.largest_observed = kLargestObserved;
+ ack_frame.ack_delay_time = QuicTime::Delta::Zero();
+ ack_frame.packets.Add(kMissingPacket);
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&ack_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0x43,
+ // largest observed packet number
+ 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // num received packets.
+ 0x00,
+ // num missing packet ranges
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ // 0 revived packets.
+ 0x00,
+ };
+ // clang-format on
+
+ // clang-format off
+ unsigned char packet_version32[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
+ 0x6C,
+ // entropy hash of all received packets.
+ 0x43,
+ // largest observed packet number
+ 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // num received packets.
+ 0x00,
+ // num missing packet ranges
+ 0x01,
+ // missing packet delta
+ 0x01,
+ // 0 more missing packets in range.
+ 0x00,
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ if (framer_.version() <= QUIC_VERSION_31) {
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+ } else {
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(packet_version32), arraysize(packet_version32));
+ }
+}
+
+// TODO(jri): Add test for tuncated packets in which the original ack frame had
+// revived packets. (In both the large and small packet cases below).
+
+TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacket) {
+ if (framer_.version() > QUIC_VERSION_33) {
+ return;
+ }
+
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_number = kPacketNumber;
+
+ QuicAckFrame ack_frame;
+ // This entropy hash is different from what shows up in the packet below,
+ // since entropy is recomputed by the framer on ack truncation (by
+ // TestEntropyCalculator for this test.)
+ ack_frame.entropy_hash = 0x43;
+ ack_frame.largest_observed = 2 * 300;
+ ack_frame.ack_delay_time = QuicTime::Delta::Zero();
+ for (size_t i = 1; i < 2 * 300; i += 2) {
+ ack_frame.packets.Add(i);
+ }
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&ack_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
+ 0x74,
+ // entropy hash of all received packets, set to 1 by TestEntropyCalculator
+ // since ack is truncated.
+ 0x01,
+ // 2-byte largest observed packet number.
+ // Expected to be 510 (0x1FE), since only 255 nack ranges can fit.
+ 0xFE, 0x01,
+ // Zero delta time.
+ 0x00, 0x00,
+ // num missing packet ranges (limited to 255 by size of this field).
+ 0xFF,
+ // {missing packet delta, further missing packets in range}
+ // 6 nack ranges x 42 + 3 nack ranges
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ // 0 revived packets.
+ 0x00,
+ };
+ // clang-format on
+
+ // clang-format off
+ unsigned char packet_version32[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
+ 0x74,
+ // entropy hash of all received packets, set to 1 by TestEntropyCalculator
+ // since ack is truncated.
+ 0x01,
+ // 2-byte largest observed packet number.
+ // Expected to be 510 (0x1FE), since only 255 nack ranges can fit.
+ 0xFE, 0x01,
+ // Zero delta time.
+ 0x00, 0x00,
+ // num missing packet ranges (limited to 255 by size of this field).
+ 0xFF,
+ // {missing packet delta, further missing packets in range}
+ // 6 nack ranges x 42 + 3 nack ranges
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ if (framer_.version() <= QUIC_VERSION_31) {
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+ } else {
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(packet_version32), arraysize(packet_version32));
+ }
+}
+
+TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacket) {
+ if (framer_.version() > QUIC_VERSION_33) {
+ return;
+ }
+
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_number = kPacketNumber;
+
+ QuicAckFrame ack_frame;
+ // This entropy hash is different from what shows up in the packet below,
+ // since entropy is recomputed by the framer on ack truncation (by
+ // TestEntropyCalculator for this test.)
+ ack_frame.entropy_hash = 0x43;
+ ack_frame.largest_observed = 2 * 300;
+ ack_frame.ack_delay_time = QuicTime::Delta::Zero();
+ for (size_t i = 1; i < 2 * 300; i += 2) {
+ ack_frame.packets.Add(i);
+ }
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&ack_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
+ 0x74,
+ // entropy hash of all received packets, set to 1 by TestEntropyCalculator
+ // since ack is truncated.
+ 0x01,
+ // 2-byte largest observed packet number.
+ // Expected to be 12 (0x0C), since only 6 nack ranges can fit.
+ 0x0C, 0x00,
+ // Zero delta time.
+ 0x00, 0x00,
+ // num missing packet ranges (limited to 6 by packet size of 37).
+ 0x06,
+ // {missing packet delta, further missing packets in range}
+ // 6 nack ranges
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ // 0 revived packets.
+ 0x00,
+ };
+ // clang-format on
+
+ // clang-format off
+ unsigned char packet_version32[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (ack frame)
+ // (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
+ 0x74,
+ // entropy hash of all received packets, set to 1 by TestEntropyCalculator
+ // since ack is truncated.
+ 0x01,
+ // 2-byte largest observed packet number.
+ // Expected to be 12 (0x0C), since only 6 nack ranges can fit.
+ 0x0C, 0x00,
+ // Zero delta time.
+ 0x00, 0x00,
+ // num missing packet ranges (limited to 6 by packet size of 37).
+ 0x06,
+ // {missing packet delta, further missing packets in range}
+ // 6 nack ranges
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ };
+ // clang-format on
+
+ if (framer_.version() <= QUIC_VERSION_31) {
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames, 37u));
+ ASSERT_TRUE(data != nullptr);
+ // Expect 1 byte unused since at least 2 bytes are needed to fit more nacks.
+ EXPECT_EQ(36u, data->length());
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+ } else {
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames, 36u));
+ ASSERT_TRUE(data != nullptr);
+ // Expect 1 byte unused since at least 2 bytes are needed to fit more nacks.
+ EXPECT_EQ(35u, data->length());
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(packet_version32), arraysize(packet_version32));
+ }
+}
+
+TEST_P(QuicFramerTest, BuildNewAckFramePacketOneAckBlock) {
+ if (framer_.version() <= QUIC_VERSION_33) {
+ return;
+ }
+
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.packet_number = kPacketNumber;
+
+ // Use kSmallLargestObserved to make this test finished in a short time.
+ QuicAckFrame ack_frame;
+ ack_frame.largest_observed = kSmallLargestObserved;
+ ack_frame.ack_delay_time = QuicTime::Delta::Zero();
+ ack_frame.missing = false;
+ ack_frame.packets.Add(1, kSmallLargestObserved + 1);
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&ack_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+
+ // frame type (ack frame)
+ // (no ack blocks, 2 byte largest observed, 2 byte block length)
+ 0x45,
+ // largest acked
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // first ack block length.
+ 0x34, 0x12,
+ // num timestamps.
+ 0x00,
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, BuildNewAckFramePacketMultipleAckBlocks) {
+ if (framer_.version() <= QUIC_VERSION_33) {
+ return;
+ }
+
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.packet_number = kPacketNumber;
+
+ // Use kSmallLargestObserved to make this test finished in a short time.
+ QuicAckFrame ack_frame;
+ ack_frame.largest_observed = kSmallLargestObserved;
+ ack_frame.ack_delay_time = QuicTime::Delta::Zero();
+ ack_frame.missing = false;
+ ack_frame.packets.Add(1, 5);
+ ack_frame.packets.Add(10, 500);
+ ack_frame.packets.Add(900, kSmallMissingPacket);
+ ack_frame.packets.Add(kSmallMissingPacket + 1, kSmallLargestObserved + 1);
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&ack_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+
+ // frame type (ack frame)
+ // (has ack blocks, 2 byte largest observed, 2 byte block length)
+ 0x65,
+ // largest acked
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // num ack blocks ranges.
+ 0x04,
+ // first ack block length.
+ 0x01, 0x00,
+ // gap to next block.
+ 0x01,
+ // ack block length.
+ 0xaf, 0x0e,
+ // gap to next block.
+ 0xff,
+ // ack block length.
+ 0x00, 0x00,
+ // gap to next block.
+ 0x91,
+ // ack block length.
+ 0xea, 0x01,
+ // gap to next block.
+ 0x05,
+ // ack block length.
+ 0x04, 0x00,
+ // num timestamps.
+ 0x00,
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, BuildNewAckFramePacketMaxAckBlocks) {
+ if (framer_.version() <= QUIC_VERSION_33) {
+ return;
+ }
+
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.packet_number = kPacketNumber;
+
+ // Use kSmallLargestObservedto make this test finished in a short time.
+ QuicAckFrame ack_frame;
+ ack_frame.largest_observed = kSmallLargestObserved;
+ ack_frame.ack_delay_time = QuicTime::Delta::Zero();
+ ack_frame.missing = false;
+ // 300 ack blocks.
+ for (size_t i = 2; i < 2 * 300; i += 2) {
+ ack_frame.packets.Add(i);
+ }
+ ack_frame.packets.Add(600, kSmallLargestObserved + 1);
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&ack_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // frame type (ack frame)
+ // (has ack blocks, 2 byte largest observed, 2 byte block length)
+ 0x65,
+ // largest acked
+ 0x34, 0x12,
+ // Zero delta time.
+ 0x00, 0x00,
+ // num ack blocks ranges.
+ 0xff,
+ // first ack block length.
+ 0xdd, 0x0f,
+ // 255 = 4 * 63 + 3
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
+ // num timestamps.
+ 0x00,
+ };
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, BuildStopWaitingPacket) {
+ if (framer_.version() > QUIC_VERSION_33) {
+ return;
+ }
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_number = kPacketNumber;
+
+ QuicStopWaitingFrame stop_waiting_frame;
+ stop_waiting_frame.entropy_hash = 0x14;
+ stop_waiting_frame.least_unacked = kLeastUnacked;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&stop_waiting_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (stop waiting frame)
+ 0x06,
+ // entropy hash of sent packets till least awaiting - 1.
+ 0x14,
+ // least packet number awaiting an ack, delta from packet number.
+ 0x1C, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, BuildNewStopWaitingPacket) {
+ if (framer_.version() <= QUIC_VERSION_33) {
+ return;
+ }
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = false;
+ header.packet_number = kPacketNumber;
+
+ QuicStopWaitingFrame stop_waiting_frame;
+ stop_waiting_frame.least_unacked = kLeastUnacked;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&stop_waiting_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+
+ // frame type (stop waiting frame)
+ 0x06,
+ // least packet number awaiting an ack, delta from packet number.
+ 0x1C, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, BuildRstFramePacketQuic) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = false;
+ header.packet_number = kPacketNumber;
+
+ QuicRstStreamFrame rst_frame;
+ rst_frame.stream_id = kStreamId;
+ rst_frame.error_code = static_cast<QuicRstStreamErrorCode>(0x05060708);
+ rst_frame.byte_offset = 0x0807060504030201;
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (rst stream frame)
+ 0x01,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // sent byte offset
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,
+ // error code
+ 0x08, 0x07, 0x06, 0x05,
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (rst stream frame)
+ 0x01,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // sent byte offset
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,
+ // error code
+ 0x08, 0x07, 0x06, 0x05,
+ };
+ // clang-format on
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&rst_frame));
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+TEST_P(QuicFramerTest, BuildCloseFramePacket) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_number = kPacketNumber;
+
+ QuicConnectionCloseFrame close_frame;
+ close_frame.error_code = static_cast<QuicErrorCode>(0x05060708);
+ close_frame.error_details = "because I can";
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&close_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (connection close frame)
+ 0x02,
+ // error code
+ 0x08, 0x07, 0x06, 0x05,
+ // error details length
+ 0x0d, 0x00,
+ // error details
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n',
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (connection close frame)
+ 0x02,
+ // error code
+ 0x08, 0x07, 0x06, 0x05,
+ // error details length
+ 0x0d, 0x00,
+ // error details
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n',
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+TEST_P(QuicFramerTest, BuildGoAwayPacket) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_number = kPacketNumber;
+
+ QuicGoAwayFrame goaway_frame;
+ goaway_frame.error_code = static_cast<QuicErrorCode>(0x05060708);
+ goaway_frame.last_good_stream_id = kStreamId;
+ goaway_frame.reason_phrase = "because I can";
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&goaway_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags(entropy)
+ 0x01,
+
+ // frame type (go away frame)
+ 0x03,
+ // error code
+ 0x08, 0x07, 0x06, 0x05,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // error details length
+ 0x0d, 0x00,
+ // error details
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n',
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (go away frame)
+ 0x03,
+ // error code
+ 0x08, 0x07, 0x06, 0x05,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // error details length
+ 0x0d, 0x00,
+ // error details
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n',
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+TEST_P(QuicFramerTest, BuildWindowUpdatePacket) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_number = kPacketNumber;
+
+ QuicWindowUpdateFrame window_update_frame;
+ window_update_frame.stream_id = kStreamId;
+ window_update_frame.byte_offset = 0x1122334455667788;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&window_update_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags(entropy)
+ 0x01,
+
+ // frame type (window update frame)
+ 0x04,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // byte offset
+ 0x88, 0x77, 0x66, 0x55,
+ 0x44, 0x33, 0x22, 0x11,
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (window update frame)
+ 0x04,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // byte offset
+ 0x88, 0x77, 0x66, 0x55,
+ 0x44, 0x33, 0x22, 0x11,
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+TEST_P(QuicFramerTest, BuildBlockedPacket) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_number = kPacketNumber;
+
+ QuicBlockedFrame blocked_frame;
+ blocked_frame.stream_id = kStreamId;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&blocked_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags(entropy)
+ 0x01,
+
+ // frame type (blocked frame)
+ 0x05,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ 0x38,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (blocked frame)
+ 0x05,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+TEST_P(QuicFramerTest, BuildPingPacket) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_number = kPacketNumber;
+
+ QuicPingFrame ping_frame;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(ping_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags(entropy)
+ 0x01,
+
+ // frame type (ping frame)
+ 0x07,
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (ping frame)
+ 0x07,
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+TEST_P(QuicFramerTest, BuildPathClosePacket) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.multipath_flag = true;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.path_id = kDefaultPathId;
+ header.packet_number = kPacketNumber;
+
+ QuicPathCloseFrame path_close;
+ path_close.path_id = kPathId;
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&path_close));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x78 : 0X7C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x00,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+ // private flags (entropy)
+ 0x01,
+
+ // frame type (path_close_frame)
+ 0x08,
+ // path id
+ 0x42,
+ };
+ unsigned char packet_34[] = {
+ // public flags (version)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x78 : 0X7C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x00,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
+
+ // frame type (path_close_frame)
+ 0x08,
+ // path id
+ 0x42,
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+// Test that the MTU discovery packet is serialized correctly as a PING packet.
+TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_number = kPacketNumber;
+
+ QuicMtuDiscoveryFrame mtu_discovery_frame;
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(mtu_discovery_frame));
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags(entropy)
+ 0x01,
+
+ // frame type (ping frame)
+ 0x07,
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (ping frame)
+ 0x07,
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError(
+ "constructed packet", data->data(), data->length(),
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34));
+}
+
+TEST_P(QuicFramerTest, BuildPublicResetPacketOld) {
+ FLAGS_quic_use_old_public_reset_packets = true;
+ QuicPublicResetPacket reset_packet;
+ reset_packet.public_header.connection_id = kConnectionId;
+ reset_packet.public_header.reset_flag = true;
+ reset_packet.public_header.version_flag = false;
+ reset_packet.rejected_packet_number = kPacketNumber;
+ reset_packet.nonce_proof = kNonceProof;
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (public reset, 8 byte ConnectionId)
+ 0x0E,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // message tag (kPRST)
+ 'P', 'R', 'S', 'T',
+ // num_entries (2) + padding
+ 0x02, 0x00, 0x00, 0x00,
+ // tag kRNON
+ 'R', 'N', 'O', 'N',
+ // end offset 8
+ 0x08, 0x00, 0x00, 0x00,
+ // tag kRSEQ
+ 'R', 'S', 'E', 'Q',
+ // end offset 16
+ 0x10, 0x00, 0x00, 0x00,
+ // nonce proof
+ 0x89, 0x67, 0x45, 0x23,
+ 0x01, 0xEF, 0xCD, 0xAB,
+ // rejected packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12, 0x00, 0x00,
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicEncryptedPacket> data(
+ framer_.BuildPublicResetPacket(reset_packet));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, BuildPublicResetPacket) {
+ FLAGS_quic_use_old_public_reset_packets = false;
+ QuicPublicResetPacket reset_packet;
+ reset_packet.public_header.connection_id = kConnectionId;
+ reset_packet.public_header.reset_flag = true;
+ reset_packet.public_header.version_flag = false;
+ reset_packet.rejected_packet_number = kPacketNumber;
+ reset_packet.nonce_proof = kNonceProof;
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (public reset, 8 byte ConnectionId)
+ 0x0A,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // message tag (kPRST)
+ 'P', 'R', 'S', 'T',
+ // num_entries (2) + padding
+ 0x02, 0x00, 0x00, 0x00,
+ // tag kRNON
+ 'R', 'N', 'O', 'N',
+ // end offset 8
+ 0x08, 0x00, 0x00, 0x00,
+ // tag kRSEQ
+ 'R', 'S', 'E', 'Q',
+ // end offset 16
+ 0x10, 0x00, 0x00, 0x00,
+ // nonce proof
+ 0x89, 0x67, 0x45, 0x23,
+ 0x01, 0xEF, 0xCD, 0xAB,
+ // rejected packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12, 0x00, 0x00,
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicEncryptedPacket> data(
+ framer_.BuildPublicResetPacket(reset_packet));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, BuildPublicResetPacketWithClientAddress) {
+ FLAGS_quic_use_old_public_reset_packets = false;
+ QuicPublicResetPacket reset_packet;
+ reset_packet.public_header.connection_id = kConnectionId;
+ reset_packet.public_header.reset_flag = true;
+ reset_packet.public_header.version_flag = false;
+ reset_packet.rejected_packet_number = kPacketNumber;
+ reset_packet.nonce_proof = kNonceProof;
+ reset_packet.client_address = IPEndPoint(Loopback4(), 0x1234);
+
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (public reset, 8 byte ConnectionId)
+ 0x0A,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // message tag (kPRST)
+ 'P', 'R', 'S', 'T',
+ // num_entries (3) + padding
+ 0x03, 0x00, 0x00, 0x00,
+ // tag kRNON
+ 'R', 'N', 'O', 'N',
+ // end offset 8
+ 0x08, 0x00, 0x00, 0x00,
+ // tag kRSEQ
+ 'R', 'S', 'E', 'Q',
+ // end offset 16
+ 0x10, 0x00, 0x00, 0x00,
+ // tag kCADR
+ 'C', 'A', 'D', 'R',
+ // end offset 24
+ 0x18, 0x00, 0x00, 0x00,
+ // nonce proof
+ 0x89, 0x67, 0x45, 0x23,
+ 0x01, 0xEF, 0xCD, 0xAB,
+ // rejected packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12, 0x00, 0x00,
+ // client address
+ 0x02, 0x00,
+ 0x7F, 0x00, 0x00, 0x01,
+ 0x34, 0x12,
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicEncryptedPacket> data(
+ framer_.BuildPublicResetPacket(reset_packet));
+ ASSERT_TRUE(data != nullptr);
+
+ test::CompareCharArraysWithHexError("constructed packet", data->data(),
+ data->length(), AsChars(packet),
+ arraysize(packet));
+}
+
+TEST_P(QuicFramerTest, EncryptPacket) {
+ QuicPacketNumber packet_number = kPacketNumber;
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // redundancy
+ 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h',
+ 'i', 'j', 'k', 'l',
+ 'm', 'n', 'o', 'p',
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // redundancy
+ 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h',
+ 'i', 'j', 'k', 'l',
+ 'm', 'n', 'o', 'p',
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> raw(new QuicPacket(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false, PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER));
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length =
+ framer_.EncryptPayload(ENCRYPTION_NONE, kDefaultPathId, packet_number,
+ *raw, buffer, kMaxPacketSize);
+
+ ASSERT_NE(0u, encrypted_length);
+ EXPECT_TRUE(CheckEncryption(kDefaultPathId, packet_number, raw.get()));
+}
+
+TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) {
+ QuicPacketNumber packet_number = kPacketNumber;
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version, 8 byte connection_id)
+ 0x39,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '.', '1', '0',
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // redundancy
+ 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h',
+ 'i', 'j', 'k', 'l',
+ 'm', 'n', 'o', 'p',
+ };
+ unsigned char packet_34[] = {
+ // public flags (version, 8 byte connection_id)
+ 0x39,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '.', '1', '0',
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // redundancy
+ 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h',
+ 'i', 'j', 'k', 'l',
+ 'm', 'n', 'o', 'p',
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> raw(new QuicPacket(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false, PACKET_8BYTE_CONNECTION_ID, kIncludeVersion, !kIncludePathId,
+ !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER));
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length =
+ framer_.EncryptPayload(ENCRYPTION_NONE, kDefaultPathId, packet_number,
+ *raw, buffer, kMaxPacketSize);
+
+ ASSERT_NE(0u, encrypted_length);
+ EXPECT_TRUE(CheckEncryption(kDefaultPathId, packet_number, raw.get()));
+}
+
+TEST_P(QuicFramerTest, EncryptPacketWithMultipathFlag) {
+ QuicPacketNumber packet_number = kPacketNumber;
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version, 8 byte connection_id)
+ 0x78,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // redundancy
+ 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h',
+ 'i', 'j', 'k', 'l',
+ 'm', 'n', 'o', 'p',
+ };
+ unsigned char packet_34[] = {
+ // public flags (version, 8 byte connection_id)
+ 0x78,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // redundancy
+ 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h',
+ 'i', 'j', 'k', 'l',
+ 'm', 'n', 'o', 'p',
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> raw(new QuicPacket(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false, PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, kIncludePathId,
+ !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER));
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length = framer_.EncryptPayload(
+ ENCRYPTION_NONE, kPathId, packet_number, *raw, buffer, kMaxPacketSize);
+
+ ASSERT_NE(0u, encrypted_length);
+ EXPECT_TRUE(CheckEncryption(kPathId, packet_number, raw.get()));
+}
+
+TEST_P(QuicFramerTest, EncryptPacketWithBothVersionFlagAndMultipathFlag) {
+ QuicPacketNumber packet_number = kPacketNumber;
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (version, 8 byte connection_id)
+ 0x79,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '.', '1', '0',
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // redundancy
+ 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h',
+ 'i', 'j', 'k', 'l',
+ 'm', 'n', 'o', 'p',
+ };
+ unsigned char packet_34[] = {
+ // public flags (version, 8 byte connection_id)
+ 0x79,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // version tag
+ 'Q', '.', '1', '0',
+ // path_id
+ 0x42,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // redundancy
+ 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h',
+ 'i', 'j', 'k', 'l',
+ 'm', 'n', 'o', 'p',
+ };
+ // clang-format on
+
+ std::unique_ptr<QuicPacket> raw(new QuicPacket(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false, PACKET_8BYTE_CONNECTION_ID, kIncludeVersion, kIncludePathId,
+ !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER));
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length = framer_.EncryptPayload(
+ ENCRYPTION_NONE, kPathId, packet_number, *raw, buffer, kMaxPacketSize);
+
+ ASSERT_NE(0u, encrypted_length);
+ EXPECT_TRUE(CheckEncryption(kPathId, packet_number, raw.get()));
+}
+
+TEST_P(QuicFramerTest, AckTruncationLargePacket) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = false;
+ header.packet_number = kPacketNumber;
+
+ QuicAckFrame ack_frame;
+ // Create a packet with just the ack.
+ if (framer_.version() <= QUIC_VERSION_33) {
+ ack_frame = MakeAckFrameWithNackRanges(300, 0u);
+ } else {
+ ack_frame = MakeAckFrameWithAckBlocks(300, 0u);
+ }
+ QuicFrame frame;
+ frame.type = ACK_FRAME;
+ frame.ack_frame = &ack_frame;
+ QuicFrames frames;
+ frames.push_back(frame);
+
+ // Build an ack packet with truncation due to limit in number of nack ranges.
+ std::unique_ptr<QuicPacket> raw_ack_packet(BuildDataPacket(header, frames));
+ ASSERT_TRUE(raw_ack_packet != nullptr);
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length = framer_.EncryptPayload(
+ ENCRYPTION_NONE, kDefaultPathId, header.packet_number, *raw_ack_packet,
+ buffer, kMaxPacketSize);
+ ASSERT_NE(0u, encrypted_length);
+ // Now make sure we can turn our ack packet back into an ack frame.
+ ASSERT_TRUE(framer_.ProcessPacket(
+ QuicEncryptedPacket(buffer, encrypted_length, false)));
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
+ if (framer_.version() <= QUIC_VERSION_33) {
+ EXPECT_TRUE(processed_ack_frame.is_truncated);
+ EXPECT_EQ(510u, processed_ack_frame.largest_observed);
+ EXPECT_TRUE(processed_ack_frame.missing);
+ ASSERT_EQ(255u, processed_ack_frame.packets.NumPacketsSlow());
+ EXPECT_EQ(1u, processed_ack_frame.packets.Min());
+ EXPECT_EQ(509u, processed_ack_frame.packets.Max());
+ } else {
+ EXPECT_FALSE(processed_ack_frame.is_truncated);
+ EXPECT_FALSE(processed_ack_frame.missing);
+ EXPECT_EQ(600u, processed_ack_frame.largest_observed);
+ ASSERT_EQ(256u, processed_ack_frame.packets.NumPacketsSlow());
+ EXPECT_EQ(90u, processed_ack_frame.packets.Min());
+ EXPECT_EQ(600u, processed_ack_frame.packets.Max());
+ }
+}
+
+TEST_P(QuicFramerTest, AckTruncationSmallPacket) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = false;
+ header.packet_number = kPacketNumber;
+
+ // Create a packet with just the ack.
+ QuicAckFrame ack_frame;
+ if (framer_.version() <= QUIC_VERSION_33) {
+ ack_frame = MakeAckFrameWithNackRanges(300, 0u);
+ } else {
+ ack_frame = MakeAckFrameWithAckBlocks(300, 0u);
+ }
+ QuicFrame frame;
+ frame.type = ACK_FRAME;
+ frame.ack_frame = &ack_frame;
+ QuicFrames frames;
+ frames.push_back(frame);
+
+ // Build an ack packet with truncation due to limit in number of nack ranges.
+ std::unique_ptr<QuicPacket> raw_ack_packet(
+ BuildDataPacket(header, frames, 500));
+ ASSERT_TRUE(raw_ack_packet != nullptr);
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length = framer_.EncryptPayload(
+ ENCRYPTION_NONE, kDefaultPathId, header.packet_number, *raw_ack_packet,
+ buffer, kMaxPacketSize);
+ ASSERT_NE(0u, encrypted_length);
+ // Now make sure we can turn our ack packet back into an ack frame.
+ ASSERT_TRUE(framer_.ProcessPacket(
+ QuicEncryptedPacket(buffer, encrypted_length, false)));
+ ASSERT_EQ(1u, visitor_.ack_frames_.size());
+ QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
+ if (framer_.version() <= QUIC_VERSION_33) {
+ EXPECT_TRUE(processed_ack_frame.is_truncated);
+ EXPECT_EQ(476u, processed_ack_frame.largest_observed);
+ EXPECT_TRUE(processed_ack_frame.missing);
+ ASSERT_EQ(238u, processed_ack_frame.packets.NumPacketsSlow());
+ EXPECT_EQ(1u, processed_ack_frame.packets.Min());
+ EXPECT_EQ(475u, processed_ack_frame.packets.Max());
+ } else {
+ EXPECT_FALSE(processed_ack_frame.is_truncated);
+ EXPECT_EQ(600u, processed_ack_frame.largest_observed);
+ EXPECT_FALSE(processed_ack_frame.missing);
+ ASSERT_EQ(239u, processed_ack_frame.packets.NumPacketsSlow());
+ EXPECT_EQ(124u, processed_ack_frame.packets.Min());
+ EXPECT_EQ(600u, processed_ack_frame.packets.Max());
+ }
+}
+
+TEST_P(QuicFramerTest, CleanTruncation) {
+ QuicPacketHeader header;
+ header.public_header.connection_id = kConnectionId;
+ header.public_header.reset_flag = false;
+ header.public_header.version_flag = false;
+ header.fec_flag = false;
+ header.entropy_flag = true;
+ header.packet_number = kPacketNumber;
+
+ QuicAckFrame ack_frame;
+ ack_frame.largest_observed = 201;
+ ack_frame.packets.Add(1, ack_frame.largest_observed);
+
+ // Create a packet with just the ack.
+ QuicFrame frame;
+ frame.type = ACK_FRAME;
+ frame.ack_frame = &ack_frame;
+ QuicFrames frames;
+ frames.push_back(frame);
+
+ std::unique_ptr<QuicPacket> raw_ack_packet(BuildDataPacket(header, frames));
+ ASSERT_TRUE(raw_ack_packet != nullptr);
+
+ char buffer[kMaxPacketSize];
+ size_t encrypted_length = framer_.EncryptPayload(
+ ENCRYPTION_NONE, kDefaultPathId, header.packet_number, *raw_ack_packet,
+ buffer, kMaxPacketSize);
+ ASSERT_NE(0u, encrypted_length);
+
+ // Now make sure we can turn our ack packet back into an ack frame.
+ ASSERT_TRUE(framer_.ProcessPacket(
+ QuicEncryptedPacket(buffer, encrypted_length, false)));
+
+ // Test for clean truncation of the ack by comparing the length of the
+ // original packets to the re-serialized packets.
+ frames.clear();
+ frame.type = ACK_FRAME;
+ frame.ack_frame = visitor_.ack_frames_[0];
+ frames.push_back(frame);
+
+ size_t original_raw_length = raw_ack_packet->length();
+ raw_ack_packet.reset(BuildDataPacket(header, frames));
+ ASSERT_TRUE(raw_ack_packet != nullptr);
+ EXPECT_EQ(original_raw_length, raw_ack_packet->length());
+ ASSERT_TRUE(raw_ack_packet != nullptr);
+}
+
+TEST_P(QuicFramerTest, EntropyFlagTest) {
+ if (framer_.version() > QUIC_VERSION_33) {
+ return;
+ }
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags (Entropy)
+ 0x01,
+
+ // frame type (stream frame with fin and no length)
+ 0xDF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+ ASSERT_TRUE(visitor_.header_.get());
+ EXPECT_TRUE(visitor_.header_->entropy_flag);
+ EXPECT_EQ(1 << 4, visitor_.header_->entropy_hash);
+ EXPECT_FALSE(visitor_.header_->fec_flag);
+};
+
+TEST_P(QuicFramerTest, StopPacketProcessing) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Entropy
+ 0x01,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+
+ // frame type (ack frame)
+ 0x40,
+ // entropy hash of sent packets till least awaiting - 1.
+ 0x14,
+ // least packet number awaiting an ack
+ 0xA0, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // entropy hash of all received packets.
+ 0x43,
+ // largest observed packet number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // num missing packets
+ 0x01,
+ // missing packet
+ 0xBE, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ };
+ unsigned char packet_34[] = {
+ // public flags (8 byte connection_id)
+ static_cast<unsigned char>(
+ framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+
+ // frame type (ack frame)
+ 0x40,
+ // entropy hash of sent packets till least awaiting - 1.
+ 0x14,
+ // least packet number awaiting an ack
+ 0xA0, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // entropy hash of all received packets.
+ 0x43,
+ // largest observed packet number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // num missing packets
+ 0x01,
+ // missing packet
+ 0xBE, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ };
+ // clang-format on
+
+ MockFramerVisitor visitor;
+ framer_.set_visitor(&visitor);
+ EXPECT_CALL(visitor, OnPacket());
+ EXPECT_CALL(visitor, OnPacketHeader(_));
+ EXPECT_CALL(visitor, OnStreamFrame(_)).WillOnce(Return(false));
+ EXPECT_CALL(visitor, OnAckFrame(_)).Times(0);
+ EXPECT_CALL(visitor, OnPacketComplete());
+ EXPECT_CALL(visitor, OnUnauthenticatedPublicHeader(_)).WillOnce(Return(true));
+ EXPECT_CALL(visitor, OnUnauthenticatedHeader(_)).WillOnce(Return(true));
+ EXPECT_CALL(visitor, OnDecryptedPacket(_));
+
+ QuicEncryptedPacket encrypted(
+ AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
+ framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
+ : arraysize(packet_34),
+ false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+}
+
+static char kTestString[] = "At least 20 characters.";
+static QuicStreamId kTestQuicStreamId = 1;
+static bool ExpectedStreamFrame(const QuicStreamFrame& frame) {
+ return frame.stream_id == kTestQuicStreamId && !frame.fin &&
+ frame.offset == 0 &&
+ string(frame.data_buffer, frame.data_length) == kTestString;
+ // FIN is hard-coded false in ConstructEncryptedPacket.
+ // Offset 0 is hard-coded in ConstructEncryptedPacket.
+}
+
+// Verify that the packet returned by ConstructEncryptedPacket() can be properly
+// parsed by the framer.
+TEST_P(QuicFramerTest, ConstructEncryptedPacket) {
+ // Since we are using ConstructEncryptedPacket, we have to set the framer's
+ // crypto to be Null.
+ framer_.SetDecrypter(ENCRYPTION_NONE, QuicDecrypter::Create(kNULL));
+ framer_.SetEncrypter(ENCRYPTION_NONE, QuicEncrypter::Create(kNULL));
+ QuicVersionVector versions;
+ versions.push_back(framer_.version());
+ std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
+ 42, false, false, false, kDefaultPathId, kTestQuicStreamId, kTestString,
+ PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, &versions));
+
+ MockFramerVisitor visitor;
+ framer_.set_visitor(&visitor);
+ EXPECT_CALL(visitor, OnPacket()).Times(1);
+ EXPECT_CALL(visitor, OnUnauthenticatedPublicHeader(_))
+ .Times(1)
+ .WillOnce(Return(true));
+ EXPECT_CALL(visitor, OnUnauthenticatedHeader(_))
+ .Times(1)
+ .WillOnce(Return(true));
+ EXPECT_CALL(visitor, OnPacketHeader(_)).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(visitor, OnDecryptedPacket(_)).Times(1);
+ EXPECT_CALL(visitor, OnError(_)).Times(0);
+ EXPECT_CALL(visitor, OnStreamFrame(_)).Times(0);
+ EXPECT_CALL(visitor, OnStreamFrame(Truly(ExpectedStreamFrame))).Times(1);
+ EXPECT_CALL(visitor, OnAckFrame(_)).Times(0);
+ EXPECT_CALL(visitor, OnPacketComplete()).Times(1);
+
+ EXPECT_TRUE(framer_.ProcessPacket(*packet));
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+}
+
+// Verify that the packet returned by ConstructMisFramedEncryptedPacket()
+// does cause the framer to return an error.
+TEST_P(QuicFramerTest, ConstructMisFramedEncryptedPacket) {
+ // Since we are using ConstructEncryptedPacket, we have to set the framer's
+ // crypto to be Null.
+ framer_.SetDecrypter(ENCRYPTION_NONE, QuicDecrypter::Create(kNULL));
+ framer_.SetEncrypter(ENCRYPTION_NONE, QuicEncrypter::Create(kNULL));
+ QuicVersionVector versions;
+ versions.push_back(framer_.version());
+ std::unique_ptr<QuicEncryptedPacket> packet(ConstructMisFramedEncryptedPacket(
+ 42, false, false, false, kDefaultPathId, kTestQuicStreamId, kTestString,
+ PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, &versions,
+ Perspective::IS_SERVER));
+
+ MockFramerVisitor visitor;
+ framer_.set_visitor(&visitor);
+ EXPECT_CALL(visitor, OnPacket()).Times(1);
+ EXPECT_CALL(visitor, OnUnauthenticatedPublicHeader(_))
+ .Times(1)
+ .WillOnce(Return(true));
+ EXPECT_CALL(visitor, OnUnauthenticatedHeader(_))
+ .Times(1)
+ .WillOnce(Return(true));
+ if (framer_.version() <= QUIC_VERSION_33) {
+ EXPECT_CALL(visitor, OnPacketHeader(_)).Times(0);
+ } else {
+ EXPECT_CALL(visitor, OnPacketHeader(_)).Times(1);
+ }
+ EXPECT_CALL(visitor, OnDecryptedPacket(_)).Times(1);
+ EXPECT_CALL(visitor, OnError(_)).Times(1);
+ EXPECT_CALL(visitor, OnStreamFrame(_)).Times(0);
+ EXPECT_CALL(visitor, OnAckFrame(_)).Times(0);
+ EXPECT_CALL(visitor, OnPacketComplete()).Times(0);
+
+ EXPECT_FALSE(framer_.ProcessPacket(*packet));
+ if (framer_.version() <= QUIC_VERSION_33) {
+ EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
+ } else {
+ EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error());
+ }
+}
+
+// Tests for fuzzing with Dr. Fuzz
+// Xref http://www.chromium.org/developers/testing/dr-fuzz for more details.
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// target function to be fuzzed by Dr. Fuzz
+void QuicFramerFuzzFunc(unsigned char* data, size_t size) {
+ QuicFramer framer(AllSupportedVersions(), QuicTime::Zero(),
+ Perspective::IS_SERVER);
+ const char* const packet_bytes = reinterpret_cast<const char*>(data);
+
+ // Test the CryptoFramer.
+ StringPiece crypto_input(packet_bytes, size);
+ std::unique_ptr<CryptoHandshakeMessage> handshake_message(
+ CryptoFramer::ParseMessage(crypto_input));
+
+ // Test the regular QuicFramer with the same input.
+ NoOpFramerVisitor visitor;
+ framer.set_visitor(&visitor);
+ QuicEncryptedPacket packet(packet_bytes, size);
+ framer.ProcessPacket(packet);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+TEST_P(QuicFramerTest, FramerFuzzTest) {
+ // clang-format off
+ unsigned char packet[] = {
+ // public flags (8 byte connection_id)
+ 0x3C,
+ // connection_id
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // packet number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+
+ // frame type (stream frame with fin)
+ 0xFF,
+ // stream id
+ 0x04, 0x03, 0x02, 0x01,
+ // offset
+ 0x54, 0x76, 0x10, 0x32,
+ 0xDC, 0xFE, 0x98, 0xBA,
+ // data length
+ 0x0c, 0x00,
+ // data
+ 'h', 'e', 'l', 'l',
+ 'o', ' ', 'w', 'o',
+ 'r', 'l', 'd', '!',
+ };
+ // clang-format on
+
+ QuicFramerFuzzFunc(packet, arraysize(packet));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_header_list.cc b/chromium/net/quic/core/quic_header_list.cc
new file mode 100644
index 00000000000..df8ecac4521
--- /dev/null
+++ b/chromium/net/quic/core/quic_header_list.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_header_list.h"
+
+using std::string;
+
+namespace net {
+
+QuicHeaderList::QuicHeaderList() : uncompressed_header_bytes_(0) {}
+
+QuicHeaderList::QuicHeaderList(QuicHeaderList&& other) = default;
+
+QuicHeaderList::QuicHeaderList(const QuicHeaderList& other) = default;
+
+QuicHeaderList& QuicHeaderList::operator=(const QuicHeaderList& other) =
+ default;
+
+QuicHeaderList& QuicHeaderList::operator=(QuicHeaderList&& other) = default;
+
+QuicHeaderList::~QuicHeaderList() {}
+
+void QuicHeaderList::OnHeaderBlockStart() {
+ QUIC_BUG_IF(uncompressed_header_bytes_ != 0)
+ << "OnHeaderBlockStart called more than once!";
+}
+
+void QuicHeaderList::OnHeader(base::StringPiece name, base::StringPiece value) {
+ header_list_.emplace_back(name.as_string(), value.as_string());
+}
+
+void QuicHeaderList::OnHeaderBlockEnd(size_t uncompressed_header_bytes) {
+ uncompressed_header_bytes_ = uncompressed_header_bytes;
+ compressed_header_bytes_ = uncompressed_header_bytes;
+}
+
+void QuicHeaderList::OnHeaderBlockEnd(size_t uncompressed_header_bytes,
+ size_t compressed_header_bytes) {
+ uncompressed_header_bytes_ = uncompressed_header_bytes;
+ compressed_header_bytes_ = compressed_header_bytes;
+}
+
+void QuicHeaderList::Clear() {
+ header_list_.clear();
+ uncompressed_header_bytes_ = 0;
+}
+
+string QuicHeaderList::DebugString() const {
+ string s = "{ ";
+ for (const auto& p : *this) {
+ s.append(p.first + "=" + p.second + ", ");
+ }
+ s.append("}");
+ return s;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_header_list.h b/chromium/net/quic/core/quic_header_list.h
new file mode 100644
index 00000000000..6bff6ce057b
--- /dev/null
+++ b/chromium/net/quic/core/quic_header_list.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_HEADER_LIST_H_
+#define NET_QUIC_QUIC_HEADER_LIST_H_
+
+#include <deque>
+#include <functional>
+
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/spdy/spdy_header_block.h"
+#include "net/spdy/spdy_headers_handler_interface.h"
+
+namespace net {
+
+// A simple class that accumulates header pairs
+class NET_EXPORT_PRIVATE QuicHeaderList : public SpdyHeadersHandlerInterface {
+ public:
+ typedef std::deque<std::pair<std::string, std::string>> ListType;
+ typedef ListType::const_iterator const_iterator;
+
+ QuicHeaderList();
+ QuicHeaderList(QuicHeaderList&& other);
+ QuicHeaderList(const QuicHeaderList& other);
+ QuicHeaderList& operator=(QuicHeaderList&& other);
+ QuicHeaderList& operator=(const QuicHeaderList& other);
+ ~QuicHeaderList() override;
+
+ // From SpdyHeadersHandlerInteface.
+ void OnHeaderBlockStart() override;
+ void OnHeader(base::StringPiece name, base::StringPiece value) override;
+ void OnHeaderBlockEnd(size_t uncompressed_header_bytes) override;
+ void OnHeaderBlockEnd(size_t uncompressed_header_bytes,
+ size_t compressed_header_bytes) override;
+
+ void Clear();
+
+ const_iterator begin() const { return header_list_.begin(); }
+ const_iterator end() const { return header_list_.end(); }
+
+ bool empty() const { return header_list_.empty(); }
+ size_t uncompressed_header_bytes() const {
+ return uncompressed_header_bytes_;
+ }
+
+ size_t compressed_header_bytes() const { return compressed_header_bytes_; }
+
+ std::string DebugString() const;
+
+ private:
+ std::deque<std::pair<std::string, std::string>> header_list_;
+ size_t uncompressed_header_bytes_;
+ size_t compressed_header_bytes_;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_HEADER_LIST_H_
diff --git a/chromium/net/quic/core/quic_header_list_test.cc b/chromium/net/quic/core/quic_header_list_test.cc
new file mode 100644
index 00000000000..4c91c418b2c
--- /dev/null
+++ b/chromium/net/quic/core/quic_header_list_test.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_header_list.h"
+
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace net {
+
+// This test verifies that QuicHeaderList accumulates header pairs in order.
+TEST(QuicHeaderListTest, OnHeader) {
+ QuicHeaderList headers;
+ headers.OnHeader("foo", "bar");
+ headers.OnHeader("april", "fools");
+ headers.OnHeader("beep", "");
+
+ EXPECT_EQ("{ foo=bar, april=fools, beep=, }", headers.DebugString());
+}
+
+// This test verifies that QuicHeaderList is copyable and assignable.
+TEST(QuicHeaderListTest, IsCopyableAndAssignable) {
+ QuicHeaderList headers;
+ headers.OnHeader("foo", "bar");
+ headers.OnHeader("april", "fools");
+ headers.OnHeader("beep", "");
+
+ QuicHeaderList headers2(headers);
+ QuicHeaderList headers3 = headers;
+
+ EXPECT_EQ("{ foo=bar, april=fools, beep=, }", headers2.DebugString());
+ EXPECT_EQ("{ foo=bar, april=fools, beep=, }", headers3.DebugString());
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_headers_stream.cc b/chromium/net/quic/core/quic_headers_stream.cc
new file mode 100644
index 00000000000..b6e8a5ecff8
--- /dev/null
+++ b/chromium/net/quic/core/quic_headers_stream.cc
@@ -0,0 +1,652 @@
+// Copyright 2013 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/quic_headers_stream.h"
+
+#include <utility>
+
+#include "base/macros.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_header_list.h"
+#include "net/quic/core/quic_server_session_base.h"
+#include "net/quic/core/quic_spdy_session.h"
+#include "net/quic/core/quic_time.h"
+#include "net/spdy/spdy_protocol.h"
+
+using base::StringPiece;
+using net::HTTP2;
+using net::SpdyFrameType;
+using std::string;
+
+namespace net {
+
+namespace {
+
+class HeaderTableDebugVisitor : public HpackHeaderTable::DebugVisitorInterface {
+ public:
+ HeaderTableDebugVisitor(
+ const QuicClock* clock,
+ std::unique_ptr<QuicHeadersStream::HpackDebugVisitor> visitor)
+ : clock_(clock), headers_stream_hpack_visitor_(std::move(visitor)) {}
+
+ int64_t OnNewEntry(const HpackEntry& entry) override {
+ DVLOG(1) << entry.GetDebugString();
+ return (clock_->ApproximateNow() - QuicTime::Zero()).ToMicroseconds();
+ }
+
+ void OnUseEntry(const HpackEntry& entry) override {
+ const QuicTime::Delta elapsed(
+ clock_->ApproximateNow() -
+ QuicTime::Delta::FromMicroseconds(entry.time_added()) -
+ QuicTime::Zero());
+ DVLOG(1) << entry.GetDebugString() << " " << elapsed.ToMilliseconds()
+ << " ms";
+ headers_stream_hpack_visitor_->OnUseEntry(elapsed);
+ }
+
+ private:
+ const QuicClock* clock_;
+ std::unique_ptr<QuicHeadersStream::HpackDebugVisitor>
+ headers_stream_hpack_visitor_;
+
+ DISALLOW_COPY_AND_ASSIGN(HeaderTableDebugVisitor);
+};
+
+// When forced HOL blocking is enabled, extra bytes in the form of
+// HTTP/2 DATA frame headers are inserted on the way down to the
+// session layer. |ForceAckListener| filters the |OnPacketAcked()|
+// notifications generated by the session layer to not count the extra
+// bytes. Otherwise, code that is using ack listener on streams might
+// consider it an error if more bytes are acked than were written to
+// the stream, it is the case with some internal stats gathering code.
+class ForceHolAckListener : public QuicAckListenerInterface {
+ public:
+ // |extra_bytes| should be initialized to the size of the HTTP/2
+ // DATA frame header inserted when forced HOL blocking is enabled.
+ ForceHolAckListener(QuicAckListenerInterface* stream_ack_listener,
+ int extra_bytes)
+ : stream_ack_listener_(stream_ack_listener), extra_bytes_(extra_bytes) {
+ DCHECK_GE(extra_bytes, 0);
+ }
+
+ void OnPacketAcked(int acked_bytes, QuicTime::Delta ack_delay_time) override {
+ if (extra_bytes_ > 0) {
+ // Don't count the added HTTP/2 DATA frame header bytes
+ int delta = std::min(extra_bytes_, acked_bytes);
+ extra_bytes_ -= delta;
+ acked_bytes -= delta;
+ }
+ stream_ack_listener_->OnPacketAcked(acked_bytes, ack_delay_time);
+ }
+
+ void OnPacketRetransmitted(int retransmitted_bytes) override {
+ stream_ack_listener_->OnPacketRetransmitted(retransmitted_bytes);
+ }
+
+ private:
+ ~ForceHolAckListener() override {}
+
+ scoped_refptr<QuicAckListenerInterface> stream_ack_listener_;
+ int extra_bytes_;
+
+ DISALLOW_COPY_AND_ASSIGN(ForceHolAckListener);
+};
+
+} // namespace
+
+QuicHeadersStream::HpackDebugVisitor::HpackDebugVisitor() {}
+
+QuicHeadersStream::HpackDebugVisitor::~HpackDebugVisitor() {}
+
+// A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to
+// the QuicSpdyStream, and closes the connection if any unexpected frames
+// are received.
+class QuicHeadersStream::SpdyFramerVisitor
+ : public SpdyFramerVisitorInterface,
+ public SpdyFramerDebugVisitorInterface {
+ public:
+ explicit SpdyFramerVisitor(QuicHeadersStream* stream) : stream_(stream) {}
+
+ // SpdyFramerVisitorInterface implementation
+ void OnSynStream(SpdyStreamId stream_id,
+ SpdyStreamId associated_stream_id,
+ SpdyPriority priority,
+ bool fin,
+ bool unidirectional) override {
+ CloseConnection("SPDY SYN_STREAM frame received.");
+ }
+
+ void OnSynReply(SpdyStreamId stream_id, bool fin) override {
+ CloseConnection("SPDY SYN_REPLY frame received.");
+ }
+
+ bool OnControlFrameHeaderData(SpdyStreamId stream_id,
+ const char* header_data,
+ size_t len) override {
+ if (!stream_->IsConnected()) {
+ return false;
+ }
+ stream_->OnControlFrameHeaderData(stream_id, header_data, len);
+ return true;
+ }
+
+ void OnStreamFrameData(SpdyStreamId stream_id,
+ const char* data,
+ size_t len) override {
+ if (stream_->OnStreamFrameData(stream_id, data, len)) {
+ return;
+ }
+ CloseConnection("SPDY DATA frame received.");
+ }
+
+ void OnStreamEnd(SpdyStreamId stream_id) override {
+ // The framer invokes OnStreamEnd after processing a SYN_STREAM
+ // or SYN_REPLY frame that had the fin bit set.
+ }
+
+ void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {
+ CloseConnection("SPDY frame padding received.");
+ }
+
+ SpdyHeadersHandlerInterface* OnHeaderFrameStart(
+ SpdyStreamId /* stream_id */) override {
+ return &header_list_;
+ }
+
+ void OnHeaderFrameEnd(SpdyStreamId /* stream_id */,
+ bool end_headers) override {
+ if (end_headers) {
+ if (stream_->IsConnected()) {
+ stream_->OnHeaderList(header_list_);
+ }
+ header_list_.Clear();
+ }
+ }
+
+ void OnError(SpdyFramer* framer) override {
+ CloseConnection(base::StringPrintf(
+ "SPDY framing error: %s",
+ SpdyFramer::ErrorCodeToString(framer->error_code())));
+ }
+
+ void OnDataFrameHeader(SpdyStreamId stream_id,
+ size_t length,
+ bool fin) override {
+ if (stream_->OnDataFrameHeader(stream_id, length, fin)) {
+ return;
+ }
+ CloseConnection("SPDY DATA frame received.");
+ }
+
+ void OnRstStream(SpdyStreamId stream_id,
+ SpdyRstStreamStatus status) override {
+ CloseConnection("SPDY RST_STREAM frame received.");
+ }
+
+ void OnSetting(SpdySettingsIds id, uint8_t flags, uint32_t value) override {
+ if (!FLAGS_quic_respect_http2_settings_frame) {
+ CloseConnection("SPDY SETTINGS frame received.");
+ return;
+ }
+ switch (id) {
+ case SETTINGS_HEADER_TABLE_SIZE:
+ stream_->UpdateHeaderEncoderTableSize(value);
+ break;
+ case SETTINGS_ENABLE_PUSH:
+ if (FLAGS_quic_enable_server_push_by_default &&
+ stream_->session()->perspective() == Perspective::IS_SERVER) {
+ // See rfc7540, Section 6.5.2.
+ if (value > 1) {
+ CloseConnection("Invalid value for SETTINGS_ENABLE_PUSH: " +
+ base::IntToString(value));
+ return;
+ }
+ stream_->UpdateEnableServerPush(value > 0);
+ break;
+ } else {
+ CloseConnection("Unsupported field of HTTP/2 SETTINGS frame: " +
+ base::IntToString(id));
+ }
+ break;
+ // TODO(fayang): Need to support SETTINGS_MAX_HEADER_LIST_SIZE when
+ // clients are actually sending it.
+ default:
+ CloseConnection("Unsupported field of HTTP/2 SETTINGS frame: " +
+ base::IntToString(id));
+ }
+ }
+
+ void OnSettingsAck() override {
+ if (!FLAGS_quic_respect_http2_settings_frame) {
+ CloseConnection("SPDY SETTINGS frame received.");
+ }
+ }
+
+ void OnSettingsEnd() override {
+ if (!FLAGS_quic_respect_http2_settings_frame) {
+ CloseConnection("SPDY SETTINGS frame received.");
+ }
+ }
+
+ void OnPing(SpdyPingId unique_id, bool is_ack) override {
+ CloseConnection("SPDY PING frame received.");
+ }
+
+ void OnGoAway(SpdyStreamId last_accepted_stream_id,
+ SpdyGoAwayStatus status) override {
+ CloseConnection("SPDY GOAWAY frame received.");
+ }
+
+ void OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ int weight,
+ SpdyStreamId parent_stream_id,
+ bool exclusive,
+ bool fin,
+ bool end) override {
+ if (!stream_->IsConnected()) {
+ return;
+ }
+
+ // TODO(mpw): avoid down-conversion and plumb SpdyStreamPrecedence through
+ // QuicHeadersStream.
+ SpdyPriority priority =
+ has_priority ? Http2WeightToSpdy3Priority(weight) : 0;
+ stream_->OnHeaders(stream_id, has_priority, priority, fin);
+ }
+
+ void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override {
+ CloseConnection("SPDY WINDOW_UPDATE frame received.");
+ }
+
+ void OnPushPromise(SpdyStreamId stream_id,
+ SpdyStreamId promised_stream_id,
+ bool end) override {
+ if (!stream_->supports_push_promise()) {
+ CloseConnection("PUSH_PROMISE not supported.");
+ return;
+ }
+ if (!stream_->IsConnected()) {
+ return;
+ }
+ stream_->OnPushPromise(stream_id, promised_stream_id, end);
+ }
+
+ void OnContinuation(SpdyStreamId stream_id, bool end) override {}
+
+ void OnPriority(SpdyStreamId stream_id,
+ SpdyStreamId parent_id,
+ int weight,
+ bool exclusive) override {
+ CloseConnection("SPDY PRIORITY frame received.");
+ }
+
+ bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override {
+ CloseConnection("Unknown frame type received.");
+ return false;
+ }
+
+ // SpdyFramerDebugVisitorInterface implementation
+ void OnSendCompressedFrame(SpdyStreamId stream_id,
+ SpdyFrameType type,
+ size_t payload_len,
+ size_t frame_len) override {
+ if (payload_len == 0) {
+ QUIC_BUG << "Zero payload length.";
+ return;
+ }
+ int compression_pct = 100 - (100 * frame_len) / payload_len;
+ DVLOG(1) << "Net.QuicHpackCompressionPercentage: " << compression_pct;
+ UMA_HISTOGRAM_PERCENTAGE("Net.QuicHpackCompressionPercentage",
+ compression_pct);
+ }
+
+ void OnReceiveCompressedFrame(SpdyStreamId stream_id,
+ SpdyFrameType type,
+ size_t frame_len) override {
+ if (stream_->IsConnected()) {
+ stream_->OnCompressedFrameSize(frame_len);
+ }
+ }
+
+ private:
+ void CloseConnection(const string& details) {
+ if (stream_->IsConnected()) {
+ stream_->CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
+ details);
+ }
+ }
+
+ private:
+ QuicHeadersStream* stream_;
+ QuicHeaderList header_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor);
+};
+
+QuicHeadersStream::QuicHeadersStream(QuicSpdySession* session)
+ : ReliableQuicStream(kHeadersStreamId, session),
+ spdy_session_(session),
+ stream_id_(kInvalidStreamId),
+ promised_stream_id_(kInvalidStreamId),
+ fin_(false),
+ frame_len_(0),
+ uncompressed_frame_len_(0),
+ supports_push_promise_(session->perspective() == Perspective::IS_CLIENT),
+ cur_max_timestamp_(QuicTime::Zero()),
+ prev_max_timestamp_(QuicTime::Zero()),
+ spdy_framer_(HTTP2),
+ spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
+ spdy_framer_.set_visitor(spdy_framer_visitor_.get());
+ spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
+ // The headers stream is exempt from connection level flow control.
+ DisableConnectionFlowControlForThisStream();
+}
+
+QuicHeadersStream::~QuicHeadersStream() {}
+
+size_t QuicHeadersStream::WriteHeaders(QuicStreamId stream_id,
+ SpdyHeaderBlock headers,
+ bool fin,
+ SpdyPriority priority,
+ QuicAckListenerInterface* ack_listener) {
+ SpdyHeadersIR headers_frame(stream_id, std::move(headers));
+ headers_frame.set_fin(fin);
+ if (session()->perspective() == Perspective::IS_CLIENT) {
+ headers_frame.set_has_priority(true);
+ headers_frame.set_weight(Spdy3PriorityToHttp2Weight(priority));
+ }
+ SpdySerializedFrame frame(spdy_framer_.SerializeFrame(headers_frame));
+ WriteOrBufferData(StringPiece(frame.data(), frame.size()), false,
+ ack_listener);
+ return frame.size();
+}
+
+size_t QuicHeadersStream::WritePushPromise(QuicStreamId original_stream_id,
+ QuicStreamId promised_stream_id,
+ SpdyHeaderBlock headers) {
+ if (session()->perspective() == Perspective::IS_CLIENT) {
+ QUIC_BUG << "Client shouldn't send PUSH_PROMISE";
+ return 0;
+ }
+
+ SpdyPushPromiseIR push_promise(original_stream_id, promised_stream_id,
+ std::move(headers));
+
+ // PUSH_PROMISE must not be the last frame sent out, at least followed by
+ // response headers.
+ push_promise.set_fin(false);
+
+ SpdySerializedFrame frame(spdy_framer_.SerializeFrame(push_promise));
+ WriteOrBufferData(StringPiece(frame.data(), frame.size()), false, nullptr);
+ return frame.size();
+}
+
+QuicConsumedData QuicHeadersStream::WritevStreamData(
+ QuicStreamId id,
+ QuicIOVector iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate) {
+ const size_t max_len = kSpdyInitialFrameSizeLimit -
+ SpdyConstants::GetDataFrameMinimumSize(HTTP2);
+
+ QuicConsumedData result(0, false);
+ size_t total_length = iov.total_length;
+
+ // Encapsulate the data into HTTP/2 DATA frames. The outer loop
+ // handles each element of the source iov, the inner loop handles
+ // the possibility of fragmenting eacho of those into multiple DATA
+ // frames, as the DATA frames have a max size of 16KB.
+ for (int i = 0; i < iov.iov_count; i++) {
+ size_t offset = 0;
+ const struct iovec* src_iov = &iov.iov[i];
+ do {
+ size_t len =
+ std::min(std::min(src_iov->iov_len - offset, max_len), total_length);
+ char* data = static_cast<char*>(src_iov->iov_base) + offset;
+ SpdyDataIR spdy_data(id, StringPiece(data, len));
+ offset += len;
+ // fin handling, set it only it only very last generated HTTP/2
+ // DATA frame.
+ bool last_iov = i == iov.iov_count - 1;
+ bool last_fragment_within_iov = offset >= src_iov->iov_len;
+ bool frame_fin = (last_iov && last_fragment_within_iov) ? fin : false;
+ spdy_data.set_fin(frame_fin);
+ if (frame_fin) {
+ result.fin_consumed = true;
+ }
+ SpdySerializedFrame frame(spdy_framer_.SerializeFrame(spdy_data));
+ DVLOG(1) << "Encapsulating in DATA frame for stream " << id << " len "
+ << len << " fin " << spdy_data.fin() << " remaining "
+ << src_iov->iov_len - offset;
+
+ scoped_refptr<ForceHolAckListener> ack_listener;
+ if (ack_notifier_delegate != nullptr) {
+ ack_listener =
+ new ForceHolAckListener(ack_notifier_delegate, frame.size() - len);
+ }
+
+ WriteOrBufferData(StringPiece(frame.data(), frame.size()), false,
+ ack_listener.get());
+ result.bytes_consumed += len;
+ total_length -= len;
+ if (total_length <= 0) {
+ return result;
+ }
+ } while (offset < src_iov->iov_len);
+ }
+ return result;
+}
+
+void QuicHeadersStream::OnDataAvailable() {
+ char buffer[1024];
+ struct iovec iov;
+ QuicTime timestamp(QuicTime::Zero());
+ while (true) {
+ iov.iov_base = buffer;
+ iov.iov_len = arraysize(buffer);
+ if (!sequencer()->GetReadableRegion(&iov, &timestamp)) {
+ // No more data to read.
+ break;
+ }
+ DCHECK(timestamp.IsInitialized());
+ cur_max_timestamp_ = std::max(timestamp, cur_max_timestamp_);
+ if (spdy_framer_.ProcessInput(static_cast<char*>(iov.iov_base),
+ iov.iov_len) != iov.iov_len) {
+ // Error processing data.
+ return;
+ }
+ sequencer()->MarkConsumed(iov.iov_len);
+ }
+}
+
+void QuicHeadersStream::OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ SpdyPriority priority,
+ bool fin) {
+ if (has_priority) {
+ if (session()->perspective() == Perspective::IS_CLIENT) {
+ CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "Server must not send priorities.");
+ return;
+ }
+ spdy_session_->OnStreamHeadersPriority(stream_id, priority);
+ } else {
+ if (session()->perspective() == Perspective::IS_SERVER) {
+ CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "Client must send priorities.");
+ return;
+ }
+ }
+ DCHECK_EQ(kInvalidStreamId, stream_id_);
+ DCHECK_EQ(kInvalidStreamId, promised_stream_id_);
+ stream_id_ = stream_id;
+ fin_ = fin;
+}
+
+void QuicHeadersStream::OnPushPromise(SpdyStreamId stream_id,
+ SpdyStreamId promised_stream_id,
+ bool end) {
+ DCHECK_EQ(kInvalidStreamId, stream_id_);
+ DCHECK_EQ(kInvalidStreamId, promised_stream_id_);
+ stream_id_ = stream_id;
+ promised_stream_id_ = promised_stream_id;
+}
+
+void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id,
+ const char* header_data,
+ size_t len) {
+ DCHECK_EQ(stream_id_, stream_id);
+ if (len == 0) {
+ DCHECK_NE(0u, stream_id_);
+ DCHECK_NE(0u, frame_len_);
+ if (prev_max_timestamp_ > cur_max_timestamp_) {
+ // prev_max_timestamp_ > cur_max_timestamp_ implies that
+ // headers from lower numbered streams actually came off the
+ // wire after headers for the current stream, hence there was
+ // HOL blocking.
+ QuicTime::Delta delta = prev_max_timestamp_ - cur_max_timestamp_;
+ DVLOG(1) << "stream " << stream_id
+ << ": Net.QuicSession.HeadersHOLBlockedTime "
+ << delta.ToMilliseconds();
+ spdy_session_->OnHeadersHeadOfLineBlocking(delta);
+ }
+ prev_max_timestamp_ = std::max(prev_max_timestamp_, cur_max_timestamp_);
+ cur_max_timestamp_ = QuicTime::Zero();
+ if (promised_stream_id_ == kInvalidStreamId) {
+ spdy_session_->OnStreamHeadersComplete(stream_id_, fin_, frame_len_);
+ } else {
+ spdy_session_->OnPromiseHeadersComplete(stream_id_, promised_stream_id_,
+ frame_len_);
+ }
+ if (uncompressed_frame_len_ != 0) {
+ int compression_pct = 100 - (100 * frame_len_) / uncompressed_frame_len_;
+ DVLOG(1) << "Net.QuicHpackDecompressionPercentage: " << compression_pct;
+ UMA_HISTOGRAM_PERCENTAGE("Net.QuicHpackDecompressionPercentage",
+ compression_pct);
+ }
+ // Reset state for the next frame.
+ promised_stream_id_ = kInvalidStreamId;
+ stream_id_ = kInvalidStreamId;
+ fin_ = false;
+ frame_len_ = 0;
+ uncompressed_frame_len_ = 0;
+ } else {
+ uncompressed_frame_len_ += len;
+ if (promised_stream_id_ == kInvalidStreamId) {
+ spdy_session_->OnStreamHeaders(stream_id_, StringPiece(header_data, len));
+ } else {
+ spdy_session_->OnPromiseHeaders(stream_id_,
+ StringPiece(header_data, len));
+ }
+ }
+}
+
+void QuicHeadersStream::OnHeaderList(const QuicHeaderList& header_list) {
+ DVLOG(1) << "Received header list for stream " << stream_id_ << ": "
+ << header_list.DebugString();
+ if (prev_max_timestamp_ > cur_max_timestamp_) {
+ // prev_max_timestamp_ > cur_max_timestamp_ implies that
+ // headers from lower numbered streams actually came off the
+ // wire after headers for the current stream, hence there was
+ // HOL blocking.
+ QuicTime::Delta delta = prev_max_timestamp_ - cur_max_timestamp_;
+ DVLOG(1) << "stream " << stream_id_
+ << ": Net.QuicSession.HeadersHOLBlockedTime "
+ << delta.ToMilliseconds();
+ spdy_session_->OnHeadersHeadOfLineBlocking(delta);
+ }
+
+ prev_max_timestamp_ = std::max(prev_max_timestamp_, cur_max_timestamp_);
+ cur_max_timestamp_ = QuicTime::Zero();
+ if (promised_stream_id_ == kInvalidStreamId) {
+ spdy_session_->OnStreamHeaderList(stream_id_, fin_, frame_len_,
+ header_list);
+ } else {
+ spdy_session_->OnPromiseHeaderList(stream_id_, promised_stream_id_,
+ frame_len_, header_list);
+ }
+ // Reset state for the next frame.
+ promised_stream_id_ = kInvalidStreamId;
+ stream_id_ = kInvalidStreamId;
+ fin_ = false;
+ frame_len_ = 0;
+ uncompressed_frame_len_ = 0;
+}
+
+void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len) {
+ frame_len_ += frame_len;
+}
+
+bool QuicHeadersStream::IsConnected() {
+ return session()->connection()->connected();
+}
+
+void QuicHeadersStream::DisableHpackDynamicTable() {
+ spdy_framer_.UpdateHeaderEncoderTableSize(0);
+}
+
+void QuicHeadersStream::SetHpackEncoderDebugVisitor(
+ std::unique_ptr<HpackDebugVisitor> visitor) {
+ spdy_framer_.SetEncoderHeaderTableDebugVisitor(
+ std::unique_ptr<HeaderTableDebugVisitor>(new HeaderTableDebugVisitor(
+ session()->connection()->helper()->GetClock(), std::move(visitor))));
+}
+
+void QuicHeadersStream::SetHpackDecoderDebugVisitor(
+ std::unique_ptr<HpackDebugVisitor> visitor) {
+ spdy_framer_.SetDecoderHeaderTableDebugVisitor(
+ std::unique_ptr<HeaderTableDebugVisitor>(new HeaderTableDebugVisitor(
+ session()->connection()->helper()->GetClock(), std::move(visitor))));
+}
+
+void QuicHeadersStream::UpdateHeaderEncoderTableSize(uint32_t value) {
+ spdy_framer_.UpdateHeaderEncoderTableSize(value);
+}
+
+void QuicHeadersStream::UpdateEnableServerPush(bool value) {
+ spdy_session_->set_server_push_enabled(value);
+}
+
+bool QuicHeadersStream::OnDataFrameHeader(QuicStreamId stream_id,
+ size_t length,
+ bool fin) {
+ if (!spdy_session_->force_hol_blocking()) {
+ return false;
+ }
+ if (!IsConnected()) {
+ return true;
+ }
+ DVLOG(1) << "DATA frame header for stream " << stream_id << " length "
+ << length << " fin " << fin;
+ fin_ = fin;
+ frame_len_ = length;
+ if (fin && length == 0) {
+ OnStreamFrameData(stream_id, "", 0);
+ }
+ return true;
+}
+
+bool QuicHeadersStream::OnStreamFrameData(QuicStreamId stream_id,
+ const char* data,
+ size_t len) {
+ if (!spdy_session_->force_hol_blocking()) {
+ return false;
+ }
+ if (!IsConnected()) {
+ return true;
+ }
+ frame_len_ -= len;
+ // Ignore fin_ while there is more data coming, if frame_len_ > 0.
+ spdy_session_->OnStreamFrameData(stream_id, data, len,
+ frame_len_ > 0 ? false : fin_);
+ return true;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_headers_stream.h b/chromium/net/quic/core/quic_headers_stream.h
new file mode 100644
index 00000000000..603dd45677b
--- /dev/null
+++ b/chromium/net/quic/core/quic_headers_stream.h
@@ -0,0 +1,175 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_HEADERS_STREAM_H_
+#define NET_QUIC_QUIC_HEADERS_STREAM_H_
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_header_list.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/reliable_quic_stream.h"
+#include "net/spdy/spdy_framer.h"
+
+namespace net {
+
+class QuicSpdySession;
+
+namespace test {
+class QuicHeadersStreamPeer;
+} // namespace test
+
+// Headers in QUIC are sent as HTTP/2 HEADERS or PUSH_PROMISE frames
+// over a reserved reliable stream with the id 3. Each endpoint
+// (client and server) will allocate an instance of QuicHeadersStream
+// to send and receive headers.
+class NET_EXPORT_PRIVATE QuicHeadersStream : public ReliableQuicStream {
+ public:
+ class NET_EXPORT_PRIVATE HpackDebugVisitor {
+ public:
+ HpackDebugVisitor();
+
+ virtual ~HpackDebugVisitor();
+
+ // For each HPACK indexed representation processed, |elapsed| is
+ // the time since the corresponding entry was added to the dynamic
+ // table.
+ virtual void OnUseEntry(QuicTime::Delta elapsed) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HpackDebugVisitor);
+ };
+
+ explicit QuicHeadersStream(QuicSpdySession* session);
+ ~QuicHeadersStream() override;
+
+ // Writes |headers| for |stream_id| in an HTTP/2 HEADERS frame to the peer.
+ // If |fin| is true, the fin flag will be set on the HEADERS frame. Returns
+ // the size, in bytes, of the resulting HEADERS frame.
+ virtual size_t WriteHeaders(QuicStreamId stream_id,
+ SpdyHeaderBlock headers,
+ bool fin,
+ SpdyPriority priority,
+ QuicAckListenerInterface* ack_listener);
+
+ // 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.
+ virtual size_t WritePushPromise(QuicStreamId original_stream_id,
+ QuicStreamId promised_stream_id,
+ SpdyHeaderBlock headers);
+
+ // For forcing HOL blocking. This encapsulates data from other
+ // streams into HTTP/2 data frames on the headers stream.
+ QuicConsumedData WritevStreamData(
+ QuicStreamId id,
+ QuicIOVector iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate);
+
+ // ReliableQuicStream implementation
+ void OnDataAvailable() override;
+
+ bool supports_push_promise() { return supports_push_promise_; }
+
+ // Experimental: force HPACK to use static table and huffman coding
+ // only. Part of exploring improvements related to headers stream
+ // induced HOL blocking in QUIC.
+ void DisableHpackDynamicTable();
+
+ // Optional, enables instrumentation related to go/quic-hpack.
+ void SetHpackEncoderDebugVisitor(std::unique_ptr<HpackDebugVisitor> visitor);
+ void SetHpackDecoderDebugVisitor(std::unique_ptr<HpackDebugVisitor> visitor);
+
+ // Sets the maximum size of the header compression table spdy_framer_ is
+ // willing to use to decode header blocks.
+ void UpdateHeaderEncoderTableSize(uint32_t value);
+
+ // Called when SETTINGS_ENABLE_PUSH is received, only supported on
+ // server side.
+ void UpdateEnableServerPush(bool value);
+
+ // Sets how much encoded data the hpack decoder of spdy_framer_ is willing to
+ // buffer.
+ void set_max_decode_buffer_size_bytes(size_t max_decode_buffer_size_bytes) {
+ spdy_framer_.set_max_decode_buffer_size_bytes(max_decode_buffer_size_bytes);
+ }
+
+ private:
+ friend class test::QuicHeadersStreamPeer;
+
+ class SpdyFramerVisitor;
+
+ // The following methods are called by the SimpleVisitor.
+
+ // Called when a HEADERS frame has been received.
+ void OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ SpdyPriority priority,
+ bool fin);
+
+ // Called when a PUSH_PROMISE frame has been received.
+ void OnPushPromise(SpdyStreamId stream_id,
+ SpdyStreamId promised_stream_id,
+ bool end);
+
+ // Called when a chunk of header data is available. This is called
+ // after OnHeaders.
+ // |stream_id| The stream receiving the header data.
+ // |header_data| A buffer containing the header data chunk received.
+ // |len| The length of the header data buffer. A length of zero indicates
+ // that the header data block has been completely sent.
+ void OnControlFrameHeaderData(SpdyStreamId stream_id,
+ const char* header_data,
+ size_t len);
+
+ // Called when the complete list of headers is available.
+ void OnHeaderList(const QuicHeaderList& header_list);
+
+ // Called when the size of the compressed frame payload is available.
+ void OnCompressedFrameSize(size_t frame_len);
+
+ // For force HOL blocking, where stream frames from all streams are
+ // plumbed through headers stream as HTTP/2 data frames. Return false
+ // if force_hol_blocking_ is false;
+ bool OnDataFrameHeader(QuicStreamId stream_id, size_t length, bool fin);
+ bool OnStreamFrameData(QuicStreamId stream_id, const char* data, size_t len);
+
+ // Returns true if the session is still connected.
+ bool IsConnected();
+
+ QuicSpdySession* spdy_session_;
+
+ // Data about the stream whose headers are being processed.
+ QuicStreamId stream_id_;
+ QuicStreamId promised_stream_id_;
+ bool fin_;
+ size_t frame_len_;
+ size_t uncompressed_frame_len_;
+
+ bool supports_push_promise_;
+
+ // Timestamps used to measure HOL blocking, these are recorded by
+ // the sequencer approximate to the time of arrival off the wire.
+ // |cur_max_timestamp_| tracks the most recent arrival time of
+ // frames for current (at the headers stream level) processed
+ // stream's headers, and |prev_max_timestamp_| tracks the most
+ // recent arrival time of lower numbered streams.
+ QuicTime cur_max_timestamp_;
+ QuicTime prev_max_timestamp_;
+
+ SpdyFramer spdy_framer_;
+ std::unique_ptr<SpdyFramerVisitor> spdy_framer_visitor_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicHeadersStream);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_HEADERS_STREAM_H_
diff --git a/chromium/net/quic/core/quic_headers_stream_test.cc b/chromium/net/quic/core/quic_headers_stream_test.cc
new file mode 100644
index 00000000000..c1ca9fbb00f
--- /dev/null
+++ b/chromium/net/quic/core/quic_headers_stream_test.cc
@@ -0,0 +1,997 @@
+// Copyright 2013 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/quic_headers_stream.h"
+
+#include <string>
+
+#include "base/strings/string_number_conversions.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/core/spdy_utils.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_headers_stream_peer.h"
+#include "net/quic/test_tools/quic_spdy_session_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/reliable_quic_stream_peer.h"
+#include "net/spdy/spdy_alt_svc_wire_format.h"
+#include "net/spdy/spdy_flags.h"
+#include "net/spdy/spdy_protocol.h"
+#include "net/spdy/spdy_test_utils.h"
+#include "net/test/gtest_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringPiece;
+using std::ostream;
+using std::string;
+using std::vector;
+using testing::ElementsAre;
+using testing::_;
+using testing::AtLeast;
+using testing::HasSubstr;
+using testing::InSequence;
+using testing::Invoke;
+using testing::Return;
+using testing::StrictMock;
+using testing::WithArgs;
+using testing::_;
+
+// TODO(bnc): Merge these correctly.
+bool FLAGS_use_http2_frame_decoder_adapter;
+bool FLAGS_spdy_use_hpack_decoder2;
+bool FLAGS_spdy_framer_use_new_methods4;
+
+namespace net {
+namespace test {
+
+class MockHpackDebugVisitor : public QuicHeadersStream::HpackDebugVisitor {
+ public:
+ explicit MockHpackDebugVisitor() : HpackDebugVisitor() {}
+
+ MOCK_METHOD1(OnUseEntry, void(QuicTime::Delta elapsed));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockHpackDebugVisitor);
+};
+
+namespace {
+
+// TODO(ckrasic): this workaround is due to absence of std::initializer_list
+const bool kFins[] = {false, true};
+
+class MockVisitor : public SpdyFramerVisitorInterface {
+ public:
+ MOCK_METHOD1(OnError, void(SpdyFramer* framer));
+ MOCK_METHOD3(OnDataFrameHeader,
+ void(SpdyStreamId stream_id, size_t length, bool fin));
+ MOCK_METHOD3(OnStreamFrameData,
+ void(SpdyStreamId stream_id, const char* data, size_t len));
+ MOCK_METHOD1(OnStreamEnd, void(SpdyStreamId stream_id));
+ MOCK_METHOD2(OnStreamPadding, void(SpdyStreamId stream_id, size_t len));
+ MOCK_METHOD1(OnHeaderFrameStart,
+ SpdyHeadersHandlerInterface*(SpdyStreamId stream_id));
+ MOCK_METHOD2(OnHeaderFrameEnd, void(SpdyStreamId stream_id, bool end));
+ MOCK_METHOD3(OnControlFrameHeaderData,
+ bool(SpdyStreamId stream_id,
+ const char* header_data,
+ size_t len));
+ MOCK_METHOD5(OnSynStream,
+ void(SpdyStreamId stream_id,
+ SpdyStreamId associated_stream_id,
+ SpdyPriority priority,
+ bool fin,
+ bool unidirectional));
+ MOCK_METHOD2(OnSynReply, void(SpdyStreamId stream_id, bool fin));
+ MOCK_METHOD2(OnRstStream,
+ void(SpdyStreamId stream_id, SpdyRstStreamStatus status));
+ MOCK_METHOD1(OnSettings, void(bool clear_persisted));
+ MOCK_METHOD3(OnSetting,
+ void(SpdySettingsIds id, uint8_t flags, uint32_t value));
+ MOCK_METHOD0(OnSettingsAck, void());
+ MOCK_METHOD0(OnSettingsEnd, void());
+ MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack));
+ MOCK_METHOD2(OnGoAway,
+ void(SpdyStreamId last_accepted_stream_id,
+ SpdyGoAwayStatus status));
+ MOCK_METHOD7(OnHeaders,
+ void(SpdyStreamId stream_id,
+ bool has_priority,
+ int weight,
+ SpdyStreamId parent_stream_id,
+ bool exclusive,
+ bool fin,
+ bool end));
+ MOCK_METHOD2(OnWindowUpdate,
+ void(SpdyStreamId stream_id, int delta_window_size));
+ MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id));
+ MOCK_METHOD3(OnPushPromise,
+ void(SpdyStreamId stream_id,
+ SpdyStreamId promised_stream_id,
+ bool end));
+ MOCK_METHOD2(OnContinuation, void(SpdyStreamId stream_id, bool end));
+ MOCK_METHOD3(OnAltSvc,
+ void(SpdyStreamId stream_id,
+ StringPiece origin,
+ const SpdyAltSvcWireFormat::AlternativeServiceVector&
+ altsvc_vector));
+ MOCK_METHOD4(OnPriority,
+ void(SpdyStreamId stream_id,
+ SpdyStreamId parent_stream_id,
+ int weight,
+ bool exclusive));
+ MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type));
+};
+
+class ForceHolAckListener : public QuicAckListenerInterface {
+ public:
+ ForceHolAckListener() : total_acked_bytes_(0) {}
+
+ void OnPacketAcked(int acked_bytes, QuicTime::Delta ack_delay_time) override {
+ total_acked_bytes_ += acked_bytes;
+ }
+
+ void OnPacketRetransmitted(int retransmitted_bytes) override {}
+
+ size_t total_acked_bytes() { return total_acked_bytes_; }
+
+ private:
+ ~ForceHolAckListener() override {}
+
+ size_t total_acked_bytes_;
+
+ DISALLOW_COPY_AND_ASSIGN(ForceHolAckListener);
+};
+
+enum Http2DecoderChoice {
+ HTTP2_DECODER_SPDY,
+ HTTP2_DECODER_NESTED_SPDY,
+ HTTP2_DECODER_NEW
+};
+ostream& operator<<(ostream& os, Http2DecoderChoice v) {
+ switch (v) {
+ case HTTP2_DECODER_SPDY:
+ return os << "SPDY";
+ case HTTP2_DECODER_NESTED_SPDY:
+ return os << "NESTED_SPDY";
+ case HTTP2_DECODER_NEW:
+ return os << "NEW";
+ }
+ return os;
+}
+
+enum HpackDecoderChoice { HPACK_DECODER_SPDY, HPACK_DECODER_NEW };
+ostream& operator<<(ostream& os, HpackDecoderChoice v) {
+ switch (v) {
+ case HPACK_DECODER_SPDY:
+ return os << "SPDY";
+ case HPACK_DECODER_NEW:
+ return os << "NEW";
+ }
+ return os;
+}
+
+typedef testing::
+ tuple<QuicVersion, Perspective, Http2DecoderChoice, HpackDecoderChoice>
+ TestParamsTuple;
+
+struct TestParams {
+ explicit TestParams(TestParamsTuple params)
+ : version(testing::get<0>(params)),
+ perspective(testing::get<1>(params)),
+ http2_decoder(testing::get<2>(params)),
+ hpack_decoder(testing::get<3>(params)) {
+ switch (http2_decoder) {
+ case HTTP2_DECODER_SPDY:
+ FLAGS_use_nested_spdy_framer_decoder = false;
+ FLAGS_use_http2_frame_decoder_adapter = false;
+ break;
+ case HTTP2_DECODER_NESTED_SPDY:
+ FLAGS_use_nested_spdy_framer_decoder = true;
+ FLAGS_use_http2_frame_decoder_adapter = false;
+ break;
+ case HTTP2_DECODER_NEW:
+ FLAGS_use_nested_spdy_framer_decoder = false;
+ FLAGS_use_http2_frame_decoder_adapter = true;
+ // Http2FrameDecoderAdapter needs the new header methods, else
+ // --use_http2_frame_decoder_adapter=true will be ignored.
+ FLAGS_spdy_framer_use_new_methods4 = true;
+ break;
+ }
+ switch (hpack_decoder) {
+ case HPACK_DECODER_SPDY:
+ FLAGS_spdy_use_hpack_decoder2 = false;
+ break;
+ case HPACK_DECODER_NEW:
+ FLAGS_spdy_use_hpack_decoder2 = true;
+ // Needs new header methods to be used.
+ FLAGS_spdy_framer_use_new_methods4 = true;
+ break;
+ }
+ VLOG(1) << "TestParams: version: " << QuicVersionToString(version)
+ << ", perspective: " << perspective
+ << ", http2_decoder: " << http2_decoder
+ << ", hpack_decoder: " << hpack_decoder;
+ }
+
+ QuicVersion version;
+ Perspective perspective;
+ Http2DecoderChoice http2_decoder;
+ HpackDecoderChoice hpack_decoder;
+};
+
+class QuicHeadersStreamTest : public ::testing::TestWithParam<TestParamsTuple> {
+ 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_,
+ &alarm_factory_,
+ perspective(),
+ GetVersion())),
+ session_(connection_),
+ headers_stream_(QuicSpdySessionPeer::GetHeadersStream(&session_)),
+ body_("hello world"),
+ hpack_encoder_visitor_(new StrictMock<MockHpackDebugVisitor>),
+ hpack_decoder_visitor_(new StrictMock<MockHpackDebugVisitor>),
+ stream_frame_(kHeadersStreamId, /*fin=*/false, /*offset=*/0, ""),
+ next_promised_stream_id_(2) {
+ headers_[":version"] = "HTTP/1.1";
+ headers_[":status"] = "200 Ok";
+ headers_["content-length"] = "11";
+ framer_ = std::unique_ptr<SpdyFramer>(new SpdyFramer(HTTP2));
+ framer_->set_visitor(&visitor_);
+ EXPECT_EQ(version(), session_.connection()->version());
+ EXPECT_TRUE(headers_stream_ != nullptr);
+ connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+ }
+
+ QuicConsumedData SaveIov(const QuicIOVector& data) {
+ const iovec* iov = data.iov;
+ int count = data.iov_count;
+ int consumed = 0;
+ for (int i = 0; i < count; ++i) {
+ saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
+ consumed += iov[i].iov_len;
+ }
+ return QuicConsumedData(consumed, false);
+ }
+
+ QuicConsumedData SaveIovAndNotifyAckListener(
+ const QuicIOVector& data,
+ QuicAckListenerInterface* ack_listener) {
+ QuicConsumedData result = SaveIov(data);
+ if (ack_listener) {
+ ack_listener->OnPacketAcked(result.bytes_consumed,
+ QuicTime::Delta::Zero());
+ }
+ return result;
+ }
+
+ void SavePayload(const char* data, size_t len) {
+ saved_payloads_.append(data, len);
+ }
+
+ bool SaveHeaderData(const char* data, int len) {
+ saved_header_data_.append(data, len);
+ return true;
+ }
+
+ void SaveHeaderDataStringPiece(StringPiece data) {
+ saved_header_data_.append(data.data(), data.length());
+ }
+
+ void SavePromiseHeaderList(QuicStreamId /* stream_id */,
+ QuicStreamId /* promised_stream_id */,
+ size_t size,
+ const QuicHeaderList& header_list) {
+ SaveToHandler(size, header_list);
+ }
+
+ void SaveHeaderList(QuicStreamId /* stream_id */,
+ bool /* fin */,
+ size_t size,
+ const QuicHeaderList& header_list) {
+ SaveToHandler(size, header_list);
+ }
+
+ void SaveToHandler(size_t size, const QuicHeaderList& header_list) {
+ headers_handler_.reset(new TestHeadersHandler);
+ headers_handler_->OnHeaderBlockStart();
+ for (const auto& p : header_list) {
+ headers_handler_->OnHeader(p.first, p.second);
+ }
+ headers_handler_->OnHeaderBlockEnd(size);
+ }
+
+ void WriteHeadersAndExpectSynStream(QuicStreamId stream_id,
+ bool fin,
+ SpdyPriority priority) {
+ WriteHeadersAndCheckData(stream_id, fin, priority, SYN_STREAM);
+ }
+
+ void WriteHeadersAndExpectSynReply(QuicStreamId stream_id, bool fin) {
+ WriteHeadersAndCheckData(stream_id, fin, 0, SYN_REPLY);
+ }
+
+ void WriteHeadersAndCheckData(QuicStreamId stream_id,
+ bool fin,
+ SpdyPriority priority,
+ SpdyFrameType type) {
+ // Write the headers and capture the outgoing data
+ EXPECT_CALL(session_, WritevData(headers_stream_, kHeadersStreamId, _, _,
+ false, nullptr))
+ .WillOnce(WithArgs<2>(Invoke(this, &QuicHeadersStreamTest::SaveIov)));
+ headers_stream_->WriteHeaders(stream_id, headers_.Clone(), fin, priority,
+ nullptr);
+
+ // Parse the outgoing data and check that it matches was was written.
+ if (type == SYN_STREAM) {
+ EXPECT_CALL(visitor_,
+ OnHeaders(stream_id, kHasPriority,
+ Spdy3PriorityToHttp2Weight(priority),
+ /*parent_stream_id=*/0,
+ /*exclusive=*/false, fin, kFrameComplete));
+ } else {
+ EXPECT_CALL(visitor_,
+ OnHeaders(stream_id, !kHasPriority,
+ /*priority=*/0,
+ /*parent_stream_id=*/0,
+ /*exclusive=*/false, fin, kFrameComplete));
+ }
+ headers_handler_.reset(new TestHeadersHandler);
+ EXPECT_CALL(visitor_, OnHeaderFrameStart(stream_id))
+ .WillOnce(Return(headers_handler_.get()));
+ EXPECT_CALL(visitor_, OnHeaderFrameEnd(stream_id, true)).Times(1);
+ if (fin) {
+ EXPECT_CALL(visitor_, OnStreamEnd(stream_id));
+ }
+ framer_->ProcessInput(saved_data_.data(), saved_data_.length());
+ EXPECT_FALSE(framer_->HasError())
+ << SpdyFramer::ErrorCodeToString(framer_->error_code());
+
+ CheckHeaders();
+ saved_data_.clear();
+ }
+
+ void CheckHeaders() {
+ EXPECT_EQ(headers_, headers_handler_->decoded_block());
+ headers_handler_.reset();
+ }
+
+ Perspective perspective() const { return test_params_.perspective; }
+
+ QuicVersion version() const { return test_params_.version; }
+
+ QuicVersionVector GetVersion() {
+ QuicVersionVector versions;
+ versions.push_back(version());
+ return versions;
+ }
+
+ void TearDownLocalConnectionState() {
+ QuicConnectionPeer::TearDownLocalConnectionState(connection_);
+ }
+
+ QuicStreamId NextPromisedStreamId() { return next_promised_stream_id_ += 2; }
+
+ static const bool kFrameComplete = true;
+ static const bool kHasPriority = true;
+
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+ const TestParams test_params_;
+ MockQuicConnectionHelper helper_;
+ MockAlarmFactory alarm_factory_;
+ StrictMock<MockQuicConnection>* connection_;
+ StrictMock<MockQuicSpdySession> session_;
+ QuicHeadersStream* headers_stream_;
+ SpdyHeaderBlock headers_;
+ std::unique_ptr<TestHeadersHandler> headers_handler_;
+ string body_;
+ string saved_data_;
+ string saved_header_data_;
+ string saved_payloads_;
+ std::unique_ptr<SpdyFramer> framer_;
+ StrictMock<MockVisitor> visitor_;
+ std::unique_ptr<StrictMock<MockHpackDebugVisitor>> hpack_encoder_visitor_;
+ std::unique_ptr<StrictMock<MockHpackDebugVisitor>> hpack_decoder_visitor_;
+ QuicStreamFrame stream_frame_;
+ QuicStreamId next_promised_stream_id_;
+};
+
+// Run all tests with each version, perspective (client or server),
+// HTTP/2 and HPACK decoder.
+INSTANTIATE_TEST_CASE_P(
+ Tests,
+ QuicHeadersStreamTest,
+ ::testing::Combine(
+ ::testing::ValuesIn(AllSupportedVersions()),
+ ::testing::Values(Perspective::IS_CLIENT, Perspective::IS_SERVER),
+ ::testing::Values(HTTP2_DECODER_SPDY,
+ HTTP2_DECODER_NESTED_SPDY,
+ HTTP2_DECODER_NEW),
+ ::testing::Values(HPACK_DECODER_SPDY, HPACK_DECODER_NEW)));
+
+TEST_P(QuicHeadersStreamTest, StreamId) {
+ EXPECT_EQ(3u, headers_stream_->id());
+}
+
+TEST_P(QuicHeadersStreamTest, WriteHeaders) {
+ for (QuicStreamId stream_id = kClientDataStreamId1;
+ stream_id < kClientDataStreamId3; stream_id += 2) {
+ for (bool fin : kFins) {
+ if (perspective() == Perspective::IS_SERVER) {
+ WriteHeadersAndExpectSynReply(stream_id, fin);
+ } else {
+ for (SpdyPriority priority = 0; priority < 7; ++priority) {
+ // TODO(rch): implement priorities correctly.
+ WriteHeadersAndExpectSynStream(stream_id, fin, 0);
+ }
+ }
+ }
+ }
+}
+
+TEST_P(QuicHeadersStreamTest, WritePushPromises) {
+ for (QuicStreamId stream_id = kClientDataStreamId1;
+ stream_id < kClientDataStreamId3; stream_id += 2) {
+ QuicStreamId promised_stream_id = NextPromisedStreamId();
+ if (perspective() == Perspective::IS_SERVER) {
+ // Write the headers and capture the outgoing data
+ EXPECT_CALL(session_, WritevData(headers_stream_, kHeadersStreamId, _, _,
+ false, nullptr))
+ .WillOnce(WithArgs<2>(Invoke(this, &QuicHeadersStreamTest::SaveIov)));
+ headers_stream_->WritePushPromise(stream_id, promised_stream_id,
+ headers_.Clone());
+
+ // Parse the outgoing data and check that it matches was was written.
+ EXPECT_CALL(visitor_,
+ OnPushPromise(stream_id, promised_stream_id, kFrameComplete));
+ headers_handler_.reset(new TestHeadersHandler);
+ EXPECT_CALL(visitor_, OnHeaderFrameStart(stream_id))
+ .WillOnce(Return(headers_handler_.get()));
+ EXPECT_CALL(visitor_, OnHeaderFrameEnd(stream_id, true)).Times(1);
+ framer_->ProcessInput(saved_data_.data(), saved_data_.length());
+ EXPECT_FALSE(framer_->HasError())
+ << SpdyFramer::ErrorCodeToString(framer_->error_code());
+ CheckHeaders();
+ saved_data_.clear();
+ } else {
+ EXPECT_QUIC_BUG(headers_stream_->WritePushPromise(
+ stream_id, promised_stream_id, headers_.Clone()),
+ "Client shouldn't send PUSH_PROMISE");
+ }
+ }
+}
+
+TEST_P(QuicHeadersStreamTest, ProcessRawData) {
+ for (QuicStreamId stream_id = kClientDataStreamId1;
+ stream_id < kClientDataStreamId3; stream_id += 2) {
+ for (bool fin : {false, true}) {
+ for (SpdyPriority priority = 0; priority < 7; ++priority) {
+ // Replace with "WriteHeadersAndSaveData"
+ SpdySerializedFrame frame;
+ if (perspective() == Perspective::IS_SERVER) {
+ SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
+ headers_frame.set_fin(fin);
+ headers_frame.set_has_priority(true);
+ headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0));
+ frame = framer_->SerializeFrame(headers_frame);
+ EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
+ } else {
+ SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
+ headers_frame.set_fin(fin);
+ frame = framer_->SerializeFrame(headers_frame);
+ }
+ EXPECT_CALL(session_,
+ OnStreamHeaderList(stream_id, fin, frame.size(), _))
+ .WillOnce(Invoke(this, &QuicHeadersStreamTest::SaveHeaderList));
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ headers_stream_->OnStreamFrame(stream_frame_);
+ stream_frame_.offset += frame.size();
+ CheckHeaders();
+ }
+ }
+ }
+}
+
+TEST_P(QuicHeadersStreamTest, ProcessPushPromise) {
+ if (perspective() == Perspective::IS_SERVER)
+ return;
+ for (QuicStreamId stream_id = kClientDataStreamId1;
+ stream_id < kClientDataStreamId3; stream_id += 2) {
+ QuicStreamId promised_stream_id = NextPromisedStreamId();
+ SpdyPushPromiseIR push_promise(stream_id, promised_stream_id,
+ headers_.Clone());
+ SpdySerializedFrame frame(framer_->SerializeFrame(push_promise));
+ if (perspective() == Perspective::IS_SERVER) {
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "PUSH_PROMISE not supported.", _))
+ .WillRepeatedly(InvokeWithoutArgs(
+ this, &QuicHeadersStreamTest::TearDownLocalConnectionState));
+ } else {
+ EXPECT_CALL(session_, OnPromiseHeaderList(stream_id, promised_stream_id,
+ frame.size(), _))
+ .WillOnce(
+ Invoke(this, &QuicHeadersStreamTest::SavePromiseHeaderList));
+ }
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ headers_stream_->OnStreamFrame(stream_frame_);
+ if (perspective() == Perspective::IS_CLIENT) {
+ stream_frame_.offset += frame.size();
+ CheckHeaders();
+ }
+ }
+}
+
+TEST_P(QuicHeadersStreamTest, ProcessPushPromiseDisabledSetting) {
+ FLAGS_quic_respect_http2_settings_frame = true;
+ FLAGS_quic_enable_server_push_by_default = true;
+ session_.OnConfigNegotiated();
+ SpdySettingsIR data;
+ // Respect supported settings frames SETTINGS_ENABLE_PUSH.
+ data.AddSetting(SETTINGS_ENABLE_PUSH, true, true, 0);
+ SpdySerializedFrame frame(framer_->SerializeFrame(data));
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ if (perspective() == Perspective::IS_CLIENT) {
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "Unsupported field of HTTP/2 SETTINGS frame: 9", _));
+ }
+ headers_stream_->OnStreamFrame(stream_frame_);
+ EXPECT_EQ(
+ session_.server_push_enabled(),
+ (perspective() == Perspective::IS_CLIENT && version() > QUIC_VERSION_34));
+}
+
+TEST_P(QuicHeadersStreamTest, EmptyHeaderHOLBlockedTime) {
+ EXPECT_CALL(session_, OnHeadersHeadOfLineBlocking(_)).Times(0);
+ testing::InSequence seq;
+ bool fin = true;
+ for (int stream_num = 0; stream_num < 10; stream_num++) {
+ QuicStreamId stream_id = QuicClientDataStreamId(stream_num);
+ // Replace with "WriteHeadersAndSaveData"
+ SpdySerializedFrame frame;
+ if (perspective() == Perspective::IS_SERVER) {
+ SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
+ headers_frame.set_fin(fin);
+ headers_frame.set_has_priority(true);
+ headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0));
+ frame = framer_->SerializeFrame(headers_frame);
+ EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
+ } else {
+ SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
+ headers_frame.set_fin(fin);
+ frame = framer_->SerializeFrame(headers_frame);
+ }
+ EXPECT_CALL(session_, OnStreamHeaderList(stream_id, fin, frame.size(), _))
+ .Times(1);
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ headers_stream_->OnStreamFrame(stream_frame_);
+ connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+ stream_frame_.offset += frame.size();
+ }
+}
+
+TEST_P(QuicHeadersStreamTest, NonEmptyHeaderHOLBlockedTime) {
+ QuicStreamId stream_id;
+ bool fin = true;
+ QuicStreamFrame stream_frames[10];
+ SpdySerializedFrame frames[10];
+ // First create all the frames in order
+ {
+ InSequence seq;
+ for (int stream_num = 0; stream_num < 10; ++stream_num) {
+ stream_id = QuicClientDataStreamId(stream_num);
+ if (perspective() == Perspective::IS_SERVER) {
+ SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
+ headers_frame.set_fin(fin);
+ headers_frame.set_has_priority(true);
+ headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0));
+ frames[stream_num] = framer_->SerializeFrame(headers_frame);
+ EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)).Times(1);
+ } else {
+ SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
+ headers_frame.set_fin(fin);
+ frames[stream_num] = framer_->SerializeFrame(headers_frame);
+ }
+ stream_frames[stream_num].stream_id = stream_frame_.stream_id;
+ stream_frames[stream_num].offset = stream_frame_.offset;
+ stream_frames[stream_num].data_buffer = frames[stream_num].data();
+ stream_frames[stream_num].data_length = frames[stream_num].size();
+ DVLOG(1) << "make frame for stream " << stream_num << " offset "
+ << stream_frames[stream_num].offset;
+ stream_frame_.offset += frames[stream_num].size();
+ EXPECT_CALL(session_, OnStreamHeaderList(stream_id, fin, _, _)).Times(1);
+ }
+ }
+
+ // Actually writing the frames in reverse order will cause HOL blocking.
+ EXPECT_CALL(session_, OnHeadersHeadOfLineBlocking(_)).Times(9);
+
+ for (int stream_num = 9; stream_num >= 0; --stream_num) {
+ DVLOG(1) << "OnStreamFrame for stream " << stream_num << " offset "
+ << stream_frames[stream_num].offset;
+ headers_stream_->OnStreamFrame(stream_frames[stream_num]);
+ connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+ }
+}
+
+TEST_P(QuicHeadersStreamTest, ProcessLargeRawData) {
+ // We want to create a frame that is more than the SPDY Framer's max control
+ // frame size, which is 16K, but less than the HPACK decoders max decode
+ // buffer size, which is 32K.
+ headers_["key0"] = string(1 << 13, '.');
+ headers_["key1"] = string(1 << 13, '.');
+ headers_["key2"] = string(1 << 13, '.');
+ for (QuicStreamId stream_id = kClientDataStreamId1;
+ stream_id < kClientDataStreamId3; stream_id += 2) {
+ for (bool fin : {false, true}) {
+ for (SpdyPriority priority = 0; priority < 7; ++priority) {
+ // Replace with "WriteHeadersAndSaveData"
+ SpdySerializedFrame frame;
+ if (perspective() == Perspective::IS_SERVER) {
+ SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
+ headers_frame.set_fin(fin);
+ headers_frame.set_has_priority(true);
+ headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0));
+ frame = framer_->SerializeFrame(headers_frame);
+ EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
+ } else {
+ SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
+ headers_frame.set_fin(fin);
+ frame = framer_->SerializeFrame(headers_frame);
+ }
+ EXPECT_CALL(session_,
+ OnStreamHeaderList(stream_id, fin, frame.size(), _))
+ .WillOnce(Invoke(this, &QuicHeadersStreamTest::SaveHeaderList));
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ headers_stream_->OnStreamFrame(stream_frame_);
+ stream_frame_.offset += frame.size();
+ CheckHeaders();
+ }
+ }
+ }
+}
+
+TEST_P(QuicHeadersStreamTest, ProcessBadData) {
+ const char kBadData[] = "blah blah blah";
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _))
+ .Times(::testing::AnyNumber());
+ stream_frame_.data_buffer = kBadData;
+ stream_frame_.data_length = strlen(kBadData);
+ headers_stream_->OnStreamFrame(stream_frame_);
+}
+
+TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrame) {
+ SpdyDataIR data(2, "ping");
+ SpdySerializedFrame frame(framer_->SerializeFrame(data));
+
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "SPDY DATA frame received.", _))
+ .WillOnce(InvokeWithoutArgs(
+ this, &QuicHeadersStreamTest::TearDownLocalConnectionState));
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ headers_stream_->OnStreamFrame(stream_frame_);
+}
+
+TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrameForceHolBlocking) {
+ if (version() <= QUIC_VERSION_35) {
+ return;
+ }
+ QuicSpdySessionPeer::SetForceHolBlocking(&session_, true);
+ SpdyDataIR data(2, "ping");
+ SpdySerializedFrame frame(framer_->SerializeFrame(data));
+ EXPECT_CALL(session_, OnStreamFrameData(2, _, 4, false));
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ headers_stream_->OnStreamFrame(stream_frame_);
+}
+
+TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrameEmptyWithFin) {
+ if (version() <= QUIC_VERSION_35) {
+ return;
+ }
+ QuicSpdySessionPeer::SetForceHolBlocking(&session_, true);
+ SpdyDataIR data(2, "");
+ data.set_fin(true);
+ SpdySerializedFrame frame(framer_->SerializeFrame(data));
+ EXPECT_CALL(session_, OnStreamFrameData(2, _, 0, true));
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ headers_stream_->OnStreamFrame(stream_frame_);
+}
+
+TEST_P(QuicHeadersStreamTest, ProcessSpdyRstStreamFrame) {
+ SpdyRstStreamIR data(2, RST_STREAM_PROTOCOL_ERROR);
+ SpdySerializedFrame frame(framer_->SerializeFrame(data));
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "SPDY RST_STREAM frame received.", _))
+ .WillOnce(InvokeWithoutArgs(
+ this, &QuicHeadersStreamTest::TearDownLocalConnectionState));
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ headers_stream_->OnStreamFrame(stream_frame_);
+}
+
+TEST_P(QuicHeadersStreamTest, ProcessSpdySettingsFrame) {
+ FLAGS_quic_respect_http2_settings_frame = false;
+ SpdySettingsIR data;
+ data.AddSetting(SETTINGS_HEADER_TABLE_SIZE, true, true, 0);
+ SpdySerializedFrame frame(framer_->SerializeFrame(data));
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "SPDY SETTINGS frame received.", _))
+ .WillOnce(InvokeWithoutArgs(
+ this, &QuicHeadersStreamTest::TearDownLocalConnectionState));
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ headers_stream_->OnStreamFrame(stream_frame_);
+}
+
+TEST_P(QuicHeadersStreamTest, RespectHttp2SettingsFrameSupportedFields) {
+ FLAGS_quic_respect_http2_settings_frame = true;
+ const uint32_t kTestHeaderTableSize = 1000;
+ SpdySettingsIR data;
+ // Respect supported settings frames SETTINGS_HEADER_TABLE_SIZE.
+ data.AddSetting(SETTINGS_HEADER_TABLE_SIZE, true, true, kTestHeaderTableSize);
+ SpdySerializedFrame frame(framer_->SerializeFrame(data));
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ headers_stream_->OnStreamFrame(stream_frame_);
+ EXPECT_EQ(kTestHeaderTableSize,
+ QuicHeadersStreamPeer::GetSpdyFramer(headers_stream_)
+ .header_encoder_table_size());
+}
+
+TEST_P(QuicHeadersStreamTest, RespectHttp2SettingsFrameUnsupportedFields) {
+ FLAGS_quic_respect_http2_settings_frame = true;
+ SpdySettingsIR data;
+ // Does not support SETTINGS_MAX_HEADER_LIST_SIZE,
+ // SETTINGS_MAX_CONCURRENT_STREAMS, SETTINGS_INITIAL_WINDOW_SIZE,
+ // SETTINGS_ENABLE_PUSH and SETTINGS_MAX_FRAME_SIZE.
+ data.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, true, true, 2000);
+ data.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, true, true, 100);
+ data.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, true, true, 100);
+ data.AddSetting(SETTINGS_ENABLE_PUSH, true, true, 1);
+ data.AddSetting(SETTINGS_MAX_FRAME_SIZE, true, true, 1250);
+ SpdySerializedFrame frame(framer_->SerializeFrame(data));
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "Unsupported field of HTTP/2 SETTINGS frame: " +
+ base::IntToString(SETTINGS_MAX_HEADER_LIST_SIZE),
+ _));
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "Unsupported field of HTTP/2 SETTINGS frame: " +
+ base::IntToString(SETTINGS_MAX_CONCURRENT_STREAMS),
+ _));
+ EXPECT_CALL(
+ *connection_,
+ CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "Unsupported field of HTTP/2 SETTINGS frame: " +
+ base::IntToString(SETTINGS_INITIAL_WINDOW_SIZE),
+ _));
+ if (!FLAGS_quic_enable_server_push_by_default ||
+ session_.perspective() == Perspective::IS_CLIENT) {
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "Unsupported field of HTTP/2 SETTINGS frame: " +
+ base::IntToString(SETTINGS_ENABLE_PUSH),
+ _));
+ }
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "Unsupported field of HTTP/2 SETTINGS frame: " +
+ base::IntToString(SETTINGS_MAX_FRAME_SIZE),
+ _));
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ headers_stream_->OnStreamFrame(stream_frame_);
+}
+
+TEST_P(QuicHeadersStreamTest, ProcessSpdyPingFrame) {
+ SpdyPingIR data(1);
+ SpdySerializedFrame frame(framer_->SerializeFrame(data));
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "SPDY PING frame received.", _))
+ .WillOnce(InvokeWithoutArgs(
+ this, &QuicHeadersStreamTest::TearDownLocalConnectionState));
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ headers_stream_->OnStreamFrame(stream_frame_);
+}
+
+TEST_P(QuicHeadersStreamTest, ProcessSpdyGoAwayFrame) {
+ SpdyGoAwayIR data(1, GOAWAY_PROTOCOL_ERROR, "go away");
+ SpdySerializedFrame frame(framer_->SerializeFrame(data));
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "SPDY GOAWAY frame received.", _))
+ .WillOnce(InvokeWithoutArgs(
+ this, &QuicHeadersStreamTest::TearDownLocalConnectionState));
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ headers_stream_->OnStreamFrame(stream_frame_);
+}
+
+TEST_P(QuicHeadersStreamTest, ProcessSpdyWindowUpdateFrame) {
+ SpdyWindowUpdateIR data(1, 1);
+ SpdySerializedFrame frame(framer_->SerializeFrame(data));
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
+ "SPDY WINDOW_UPDATE frame received.", _))
+ .WillOnce(InvokeWithoutArgs(
+ this, &QuicHeadersStreamTest::TearDownLocalConnectionState));
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ headers_stream_->OnStreamFrame(stream_frame_);
+}
+
+TEST_P(QuicHeadersStreamTest, NoConnectionLevelFlowControl) {
+ EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl(
+ headers_stream_));
+}
+
+TEST_P(QuicHeadersStreamTest, HpackDecoderDebugVisitor) {
+ if (FLAGS_use_nested_spdy_framer_decoder)
+ return;
+
+ StrictMock<MockHpackDebugVisitor>* hpack_decoder_visitor =
+ hpack_decoder_visitor_.get();
+ headers_stream_->SetHpackDecoderDebugVisitor(
+ std::move(hpack_decoder_visitor_));
+
+ // Create some headers we expect to generate entries in HPACK's
+ // dynamic table, in addition to content-length.
+ headers_["key0"] = string(1 << 1, '.');
+ headers_["key1"] = string(1 << 2, '.');
+ headers_["key2"] = string(1 << 3, '.');
+ {
+ testing::InSequence seq;
+ // Number of indexed representations generated in headers below.
+ for (int i = 1; i < 28; i++) {
+ EXPECT_CALL(*hpack_decoder_visitor,
+ OnUseEntry(QuicTime::Delta::FromMilliseconds(i)))
+ .Times(4);
+ }
+ }
+ for (QuicStreamId stream_id = kClientDataStreamId1;
+ stream_id < kClientDataStreamId3; stream_id += 2) {
+ for (bool fin : {false, true}) {
+ for (SpdyPriority priority = 0; priority < 7; ++priority) {
+ // Replace with "WriteHeadersAndSaveData"
+ SpdySerializedFrame frame;
+ if (perspective() == Perspective::IS_SERVER) {
+ SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
+ headers_frame.set_fin(fin);
+ headers_frame.set_has_priority(true);
+ headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0));
+ frame = framer_->SerializeFrame(headers_frame);
+ EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
+ } else {
+ SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
+ headers_frame.set_fin(fin);
+ frame = framer_->SerializeFrame(headers_frame);
+ }
+ EXPECT_CALL(session_,
+ OnStreamHeaderList(stream_id, fin, frame.size(), _))
+ .WillOnce(Invoke(this, &QuicHeadersStreamTest::SaveHeaderList));
+ stream_frame_.data_buffer = frame.data();
+ stream_frame_.data_length = frame.size();
+ connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+ headers_stream_->OnStreamFrame(stream_frame_);
+ stream_frame_.offset += frame.size();
+ CheckHeaders();
+ }
+ }
+ }
+}
+
+TEST_P(QuicHeadersStreamTest, HpackEncoderDebugVisitor) {
+ StrictMock<MockHpackDebugVisitor>* hpack_encoder_visitor =
+ hpack_encoder_visitor_.get();
+ headers_stream_->SetHpackEncoderDebugVisitor(
+ std::move(hpack_encoder_visitor_));
+
+ if (perspective() == Perspective::IS_SERVER) {
+ testing::InSequence seq;
+ for (int i = 1; i < 4; i++) {
+ EXPECT_CALL(*hpack_encoder_visitor,
+ OnUseEntry(QuicTime::Delta::FromMilliseconds(i)));
+ }
+ } else {
+ testing::InSequence seq;
+ for (int i = 1; i < 28; i++) {
+ EXPECT_CALL(*hpack_encoder_visitor,
+ OnUseEntry(QuicTime::Delta::FromMilliseconds(i)));
+ }
+ }
+ for (QuicStreamId stream_id = kClientDataStreamId1;
+ stream_id < kClientDataStreamId3; stream_id += 2) {
+ for (bool fin : {false, true}) {
+ if (perspective() == Perspective::IS_SERVER) {
+ WriteHeadersAndExpectSynReply(stream_id, fin);
+ connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+ } else {
+ for (SpdyPriority priority = 0; priority < 7; ++priority) {
+ // TODO(rch): implement priorities correctly.
+ WriteHeadersAndExpectSynStream(stream_id, fin, 0);
+ connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+ }
+ }
+ }
+ }
+}
+
+TEST_P(QuicHeadersStreamTest, WritevStreamData) {
+ QuicStreamId id = kClientDataStreamId1;
+ QuicStreamOffset offset = 0;
+ struct iovec iov;
+ string data;
+
+ // This test will issue a write that will require fragmenting into
+ // multiple HTTP/2 DATA frames.
+ const int kMinDataFrames = 4;
+ const size_t data_len =
+ kSpdyInitialFrameSizeLimit * kMinDataFrames + 1024;
+ // Set headers stream send window large enough for data written below.
+ headers_stream_->flow_controller()->UpdateSendWindowOffset(data_len * 2 * 4);
+ test::GenerateBody(&data, data_len);
+
+ for (bool fin : {true, false}) {
+ for (bool use_ack_listener : {true, false}) {
+ scoped_refptr<ForceHolAckListener> ack_listener;
+ if (use_ack_listener) {
+ ack_listener = new ForceHolAckListener();
+ }
+ EXPECT_CALL(session_,
+ WritevData(headers_stream_, kHeadersStreamId, _, _, false, _))
+ .WillRepeatedly(WithArgs<2, 5>(Invoke(
+ this, &QuicHeadersStreamTest::SaveIovAndNotifyAckListener)));
+
+ QuicConsumedData consumed_data = headers_stream_->WritevStreamData(
+ id, MakeIOVector(data, &iov), offset, fin, ack_listener.get());
+
+ EXPECT_EQ(consumed_data.bytes_consumed, data_len);
+ EXPECT_EQ(consumed_data.fin_consumed, fin);
+ // Now process the written data with the SPDY framer, and verify
+ // that the original data is unchanged.
+ EXPECT_CALL(visitor_, OnDataFrameHeader(id, _, _))
+ .Times(AtLeast(kMinDataFrames));
+ EXPECT_CALL(visitor_, OnStreamFrameData(id, _, _))
+ .WillRepeatedly(WithArgs<1, 2>(
+ Invoke(this, &QuicHeadersStreamTest::SavePayload)));
+ if (fin) {
+ EXPECT_CALL(visitor_, OnStreamEnd(id));
+ }
+ framer_->ProcessInput(saved_data_.data(), saved_data_.length());
+ EXPECT_EQ(saved_payloads_, data);
+
+ if (use_ack_listener) {
+ // Notice, acked bytes doesn't include extra bytes used by
+ // HTTP/2 DATA frame headers.
+ EXPECT_EQ(ack_listener->total_acked_bytes(), data_len);
+ }
+ saved_data_.clear();
+ saved_payloads_.clear();
+ }
+ }
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_http_utils.cc b/chromium/net/quic/core/quic_http_utils.cc
new file mode 100644
index 00000000000..f9e953da1e9
--- /dev/null
+++ b/chromium/net/quic/core/quic_http_utils.cc
@@ -0,0 +1,38 @@
+// Copyright 2013 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/quic_http_utils.h"
+
+#include <utility>
+
+namespace net {
+
+SpdyPriority ConvertRequestPriorityToQuicPriority(
+ const RequestPriority priority) {
+ DCHECK_GE(priority, MINIMUM_PRIORITY);
+ DCHECK_LE(priority, MAXIMUM_PRIORITY);
+ return static_cast<SpdyPriority>(HIGHEST - priority);
+}
+
+NET_EXPORT_PRIVATE RequestPriority
+ConvertQuicPriorityToRequestPriority(SpdyPriority priority) {
+ // Handle invalid values gracefully.
+ return (priority >= 5) ? IDLE
+ : static_cast<RequestPriority>(HIGHEST - priority);
+}
+
+std::unique_ptr<base::Value> QuicRequestNetLogCallback(
+ QuicStreamId stream_id,
+ const SpdyHeaderBlock* headers,
+ SpdyPriority priority,
+ NetLogCaptureMode capture_mode) {
+ std::unique_ptr<base::DictionaryValue> dict(
+ static_cast<base::DictionaryValue*>(
+ SpdyHeaderBlockNetLogCallback(headers, capture_mode).release()));
+ dict->SetInteger("quic_priority", static_cast<int>(priority));
+ dict->SetInteger("quic_stream_id", static_cast<int>(stream_id));
+ return std::move(dict);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_http_utils.h b/chromium/net/quic/core/quic_http_utils.h
new file mode 100644
index 00000000000..6b3e38f19ed
--- /dev/null
+++ b/chromium/net/quic/core/quic_http_utils.h
@@ -0,0 +1,32 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_HTTP_UTILS_H_
+#define NET_QUIC_QUIC_HTTP_UTILS_H_
+
+#include "base/values.h"
+#include "net/base/net_export.h"
+#include "net/base/request_priority.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/spdy/spdy_header_block.h"
+#include "net/spdy/spdy_protocol.h"
+
+namespace net {
+
+NET_EXPORT_PRIVATE SpdyPriority
+ConvertRequestPriorityToQuicPriority(RequestPriority priority);
+
+NET_EXPORT_PRIVATE RequestPriority
+ConvertQuicPriorityToRequestPriority(SpdyPriority priority);
+
+// Converts a SpdyHeaderBlock and priority into NetLog event parameters.
+NET_EXPORT std::unique_ptr<base::Value> QuicRequestNetLogCallback(
+ QuicStreamId stream_id,
+ const SpdyHeaderBlock* headers,
+ SpdyPriority priority,
+ NetLogCaptureMode capture_mode);
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_HTTP_UTILS_H_
diff --git a/chromium/net/quic/core/quic_http_utils_test.cc b/chromium/net/quic/core/quic_http_utils_test.cc
new file mode 100644
index 00000000000..330e8e8cdc4
--- /dev/null
+++ b/chromium/net/quic/core/quic_http_utils_test.cc
@@ -0,0 +1,39 @@
+// Copyright 2013 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/quic_http_utils.h"
+
+#include <stdint.h>
+
+#include <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+TEST(QuicHttpUtilsTest, ConvertRequestPriorityToQuicPriority) {
+ EXPECT_EQ(0u, ConvertRequestPriorityToQuicPriority(HIGHEST));
+ EXPECT_EQ(1u, ConvertRequestPriorityToQuicPriority(MEDIUM));
+ EXPECT_EQ(2u, ConvertRequestPriorityToQuicPriority(LOW));
+ EXPECT_EQ(3u, ConvertRequestPriorityToQuicPriority(LOWEST));
+ EXPECT_EQ(4u, ConvertRequestPriorityToQuicPriority(IDLE));
+}
+
+TEST(QuicHttpUtilsTest, ConvertQuicPriorityToRequestPriority) {
+ EXPECT_EQ(HIGHEST, ConvertQuicPriorityToRequestPriority(0));
+ EXPECT_EQ(MEDIUM, ConvertQuicPriorityToRequestPriority(1));
+ EXPECT_EQ(LOW, ConvertQuicPriorityToRequestPriority(2));
+ EXPECT_EQ(LOWEST, ConvertQuicPriorityToRequestPriority(3));
+ EXPECT_EQ(IDLE, ConvertQuicPriorityToRequestPriority(4));
+ // These are invalid values, but we should still handle them
+ // gracefully. TODO(rtenneti): should we test for all possible values of
+ // uint32_t?
+ for (int i = 5; i < std::numeric_limits<uint8_t>::max(); ++i) {
+ EXPECT_EQ(IDLE, ConvertQuicPriorityToRequestPriority(i));
+ }
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_multipath_received_packet_manager.cc b/chromium/net/quic/core/quic_multipath_received_packet_manager.cc
new file mode 100644
index 00000000000..3440495c5df
--- /dev/null
+++ b/chromium/net/quic/core/quic_multipath_received_packet_manager.cc
@@ -0,0 +1,118 @@
+// 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.
+
+#include "net/quic/core/quic_multipath_received_packet_manager.h"
+
+#include "base/stl_util.h"
+
+#include "net/quic/core/quic_bug_tracker.h"
+
+namespace net {
+
+QuicMultipathReceivedPacketManager::QuicMultipathReceivedPacketManager(
+ QuicConnectionStats* stats) {
+ path_managers_[kDefaultPathId] = new QuicReceivedPacketManager(stats);
+}
+
+QuicMultipathReceivedPacketManager::~QuicMultipathReceivedPacketManager() {
+ base::STLDeleteValues(&path_managers_);
+}
+
+void QuicMultipathReceivedPacketManager::OnPathCreated(
+ QuicPathId path_id,
+ QuicConnectionStats* stats) {
+ if (path_managers_[path_id] != nullptr) {
+ QUIC_BUG << "Received packet manager of path already exists: "
+ << static_cast<uint32_t>(path_id);
+ return;
+ }
+
+ path_managers_[path_id] = new QuicReceivedPacketManager(stats);
+}
+
+void QuicMultipathReceivedPacketManager::OnPathClosed(QuicPathId path_id) {
+ QuicReceivedPacketManager* manager = path_managers_[path_id];
+ if (manager == nullptr) {
+ QUIC_BUG << "Received packet manager of path does not exist: "
+ << static_cast<uint32_t>(path_id);
+ return;
+ }
+
+ delete manager;
+ path_managers_.erase(path_id);
+}
+
+void QuicMultipathReceivedPacketManager::RecordPacketReceived(
+ QuicPathId path_id,
+ const QuicPacketHeader& header,
+ QuicTime receipt_time) {
+ QuicReceivedPacketManager* manager = path_managers_[path_id];
+ if (manager == nullptr) {
+ QUIC_BUG << "Received a packet on a non-existent path.";
+ return;
+ }
+
+ manager->RecordPacketReceived(header, receipt_time);
+}
+
+bool QuicMultipathReceivedPacketManager::IsMissing(
+ QuicPathId path_id,
+ QuicPacketNumber packet_number) {
+ QuicReceivedPacketManager* manager = path_managers_[path_id];
+ if (manager == nullptr) {
+ QUIC_BUG << "Check whether a packet is missing on a non-existent path.";
+ return true;
+ }
+
+ return manager->IsMissing(packet_number);
+}
+
+bool QuicMultipathReceivedPacketManager::IsAwaitingPacket(
+ QuicPathId path_id,
+ QuicPacketNumber packet_number) {
+ QuicReceivedPacketManager* manager = path_managers_[path_id];
+ if (manager == nullptr) {
+ QUIC_BUG << "Check whether a packet is awaited on a non-existent path.";
+ return false;
+ }
+
+ return manager->IsAwaitingPacket(packet_number);
+}
+
+void QuicMultipathReceivedPacketManager::UpdatePacketInformationSentByPeer(
+ const std::vector<QuicStopWaitingFrame>& stop_waitings) {
+ for (QuicStopWaitingFrame stop_waiting : stop_waitings) {
+ QuicReceivedPacketManager* manager = path_managers_[stop_waiting.path_id];
+ if (manager != nullptr) {
+ manager->UpdatePacketInformationSentByPeer(stop_waiting);
+ }
+ }
+}
+
+bool QuicMultipathReceivedPacketManager::HasNewMissingPackets(
+ QuicPathId path_id) const {
+ MultipathReceivedPacketManagerMap::const_iterator it =
+ path_managers_.find(path_id);
+ if (it == path_managers_.end()) {
+ QUIC_BUG << "Check whether has new missing packets on a non-existent path.";
+ return false;
+ }
+
+ return it->second->HasNewMissingPackets();
+}
+
+QuicPacketNumber
+QuicMultipathReceivedPacketManager::GetPeerLeastPacketAwaitingAck(
+ QuicPathId path_id) {
+ QuicReceivedPacketManager* manager = path_managers_[path_id];
+ if (manager == nullptr) {
+ QUIC_BUG
+ << "Try to get peer_least_packet_awaiting_ack of a non-existent path.";
+ return false;
+ }
+
+ return manager->peer_least_packet_awaiting_ack();
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_multipath_received_packet_manager.h b/chromium/net/quic/core/quic_multipath_received_packet_manager.h
new file mode 100644
index 00000000000..98ae2f5b45c
--- /dev/null
+++ b/chromium/net/quic/core/quic_multipath_received_packet_manager.h
@@ -0,0 +1,76 @@
+// 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.
+
+// A connection level received packet manager which manages multiple per path
+// received packet managers.
+
+#ifndef NET_QUIC_QUIC_MULTIPATH_RECEIVED_PACKET_MANAGER_H_
+#define NET_QUIC_QUIC_MULTIPATH_RECEIVED_PACKET_MANAGER_H_
+
+#include <unordered_map>
+#include <vector>
+
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_received_packet_manager.h"
+
+namespace net {
+
+namespace test {
+class QuicMultipathReceivedPacketManagerPeer;
+} // namespace test
+
+class NET_EXPORT_PRIVATE QuicMultipathReceivedPacketManager {
+ public:
+ typedef std::unordered_map<QuicPathId, QuicReceivedPacketManager*>
+ MultipathReceivedPacketManagerMap;
+
+ explicit QuicMultipathReceivedPacketManager(QuicConnectionStats* stats);
+ ~QuicMultipathReceivedPacketManager();
+
+ // Called when a new path with |path_id| is created.
+ void OnPathCreated(QuicPathId path_id, QuicConnectionStats* stats);
+
+ // Called when path with |path_id| is closed.
+ void OnPathClosed(QuicPathId path_id);
+
+ // Records packet receipt information on path with |path_id|.
+ void RecordPacketReceived(QuicPathId path_id,
+ const QuicPacketHeader& header,
+ QuicTime receipt_time);
+
+ // Checks whether |packet_number| is missing on path with |path_id|.
+ bool IsMissing(QuicPathId path_id, QuicPacketNumber packet_number);
+
+ // Checks if we're still waiting for the packet with |packet_number| on path
+ // with |path_id|.
+ bool IsAwaitingPacket(QuicPathId path_id, QuicPacketNumber packet_number);
+
+ // If |force_all_paths| is false, populates ack information for paths whose
+ // ack has been updated since UpdateReceivedPacketInfo was called last time.
+ // Otherwise, populates ack for all paths.
+ void UpdateReceivedPacketInfo(std::vector<QuicAckFrame>* ack_frames,
+ QuicTime approximate_now,
+ bool force_all_paths);
+
+ // Updates internal state based on stop_waiting frames for corresponding path.
+ void UpdatePacketInformationSentByPeer(
+ const std::vector<QuicStopWaitingFrame>& stop_waitings);
+
+ // Returns true when there are new missing packets to be reported within 3
+ // packets of the largest observed on path with |path_id|.
+ bool HasNewMissingPackets(QuicPathId path_id) const;
+
+ QuicPacketNumber GetPeerLeastPacketAwaitingAck(QuicPathId path_id);
+
+ private:
+ friend class test::QuicMultipathReceivedPacketManagerPeer;
+
+ // Map mapping path id to path received packet manager.
+ MultipathReceivedPacketManagerMap path_managers_;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_MULTIPATH_RECEIVED_PACKET_MANAGER_H_
diff --git a/chromium/net/quic/core/quic_multipath_received_packet_manager_test.cc b/chromium/net/quic/core/quic_multipath_received_packet_manager_test.cc
new file mode 100644
index 00000000000..0dc2e2195d2
--- /dev/null
+++ b/chromium/net/quic/core/quic_multipath_received_packet_manager_test.cc
@@ -0,0 +1,158 @@
+// 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.
+
+#include "net/quic/core/quic_multipath_received_packet_manager.h"
+
+#include "net/quic/core/quic_connection_stats.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Return;
+using testing::_;
+
+namespace net {
+namespace test {
+
+class QuicMultipathReceivedPacketManagerPeer {
+ public:
+ static bool PathReceivedPacketManagerExists(
+ QuicMultipathReceivedPacketManager* multipath_manager,
+ QuicPathId path_id) {
+ return multipath_manager->path_managers_.count(path_id);
+ }
+
+ static void SetPathReceivedPacketManager(
+ QuicMultipathReceivedPacketManager* multipath_manager,
+ QuicPathId path_id,
+ QuicReceivedPacketManager* manager) {
+ delete multipath_manager->path_managers_[path_id];
+ multipath_manager->path_managers_[path_id] = manager;
+ }
+};
+
+namespace {
+
+const QuicPathId kPathId1 = 1;
+const QuicPathId kPathId2 = 2;
+const QuicPathId kPathId3 = 3;
+
+class QuicMultipathReceivedPacketManagerTest : public testing::Test {
+ public:
+ QuicMultipathReceivedPacketManagerTest()
+ : multipath_manager_(&stats_),
+ manager_0_(new MockReceivedPacketManager(&stats_)),
+ manager_1_(new MockReceivedPacketManager(&stats_)) {
+ QuicMultipathReceivedPacketManagerPeer::SetPathReceivedPacketManager(
+ &multipath_manager_, kDefaultPathId, manager_0_);
+ QuicMultipathReceivedPacketManagerPeer::SetPathReceivedPacketManager(
+ &multipath_manager_, kPathId1, manager_1_);
+ }
+
+ QuicConnectionStats stats_;
+ QuicMultipathReceivedPacketManager multipath_manager_;
+ MockReceivedPacketManager* manager_0_;
+ MockReceivedPacketManager* manager_1_;
+ QuicPacketHeader header_;
+};
+
+TEST_F(QuicMultipathReceivedPacketManagerTest, OnPathCreatedAndClosed) {
+ EXPECT_TRUE(
+ QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists(
+ &multipath_manager_, kDefaultPathId));
+ EXPECT_TRUE(
+ QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists(
+ &multipath_manager_, kPathId1));
+ EXPECT_QUIC_BUG(multipath_manager_.OnPathCreated(kDefaultPathId, &stats_),
+ "Received packet manager of path already exists");
+ // Path 2 created.
+ multipath_manager_.OnPathCreated(kPathId2, &stats_);
+ EXPECT_TRUE(
+ QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists(
+ &multipath_manager_, kPathId2));
+ EXPECT_FALSE(
+ QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists(
+ &multipath_manager_, kPathId3));
+ // Path 3 created.
+ multipath_manager_.OnPathCreated(kPathId3, &stats_);
+ EXPECT_TRUE(
+ QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists(
+ &multipath_manager_, kPathId3));
+
+ // Path 0 closed.
+ multipath_manager_.OnPathClosed(kDefaultPathId);
+ EXPECT_FALSE(
+ QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists(
+ &multipath_manager_, kDefaultPathId));
+ EXPECT_QUIC_BUG(multipath_manager_.OnPathClosed(kDefaultPathId),
+ "Received packet manager of path does not exist");
+}
+
+TEST_F(QuicMultipathReceivedPacketManagerTest, RecordPacketReceived) {
+ EXPECT_CALL(*manager_0_, RecordPacketReceived(_, _)).Times(1);
+ multipath_manager_.RecordPacketReceived(kDefaultPathId, header_,
+ QuicTime::Zero());
+ EXPECT_QUIC_BUG(multipath_manager_.RecordPacketReceived(kPathId2, header_,
+ QuicTime::Zero()),
+ "Received a packet on a non-existent path");
+}
+
+TEST_F(QuicMultipathReceivedPacketManagerTest, IsMissing) {
+ EXPECT_CALL(*manager_0_, IsMissing(header_.packet_number))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*manager_1_, IsMissing(header_.packet_number))
+ .WillOnce(Return(false));
+ EXPECT_TRUE(
+ multipath_manager_.IsMissing(kDefaultPathId, header_.packet_number));
+ EXPECT_FALSE(multipath_manager_.IsMissing(kPathId1, header_.packet_number));
+ EXPECT_QUIC_BUG(multipath_manager_.IsMissing(kPathId2, header_.packet_number),
+ "Check whether a packet is missing on a non-existent path");
+}
+
+TEST_F(QuicMultipathReceivedPacketManagerTest, IsAwaitingPacket) {
+ EXPECT_CALL(*manager_0_, IsAwaitingPacket(header_.packet_number))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*manager_1_, IsAwaitingPacket(header_.packet_number))
+ .WillOnce(Return(false));
+ EXPECT_TRUE(multipath_manager_.IsAwaitingPacket(kDefaultPathId,
+ header_.packet_number));
+ EXPECT_FALSE(
+ multipath_manager_.IsAwaitingPacket(kPathId1, header_.packet_number));
+ EXPECT_QUIC_BUG(
+ multipath_manager_.IsAwaitingPacket(kPathId2, header_.packet_number),
+ "Check whether a packet is awaited on a non-existent path");
+}
+
+TEST_F(QuicMultipathReceivedPacketManagerTest,
+ UpdatePacketInformationSentByPeer) {
+ std::vector<QuicStopWaitingFrame> stop_waitings;
+ QuicStopWaitingFrame stop_waiting_0;
+ QuicStopWaitingFrame stop_waiting_1;
+ QuicStopWaitingFrame stop_waiting_2;
+ stop_waiting_0.path_id = kDefaultPathId;
+ stop_waiting_1.path_id = kPathId1;
+ stop_waiting_2.path_id = kPathId2;
+ stop_waitings.push_back(stop_waiting_0);
+ stop_waitings.push_back(stop_waiting_1);
+ stop_waitings.push_back(stop_waiting_2);
+ EXPECT_CALL(*manager_0_, UpdatePacketInformationSentByPeer(_)).Times(1);
+ EXPECT_CALL(*manager_1_, UpdatePacketInformationSentByPeer(_)).Times(1);
+ multipath_manager_.UpdatePacketInformationSentByPeer(stop_waitings);
+}
+
+TEST_F(QuicMultipathReceivedPacketManagerTest, HasNewMissingPackets) {
+ EXPECT_CALL(*manager_0_, HasNewMissingPackets()).WillOnce(Return(true));
+ EXPECT_CALL(*manager_1_, HasNewMissingPackets()).WillOnce(Return(false));
+ EXPECT_TRUE(multipath_manager_.HasNewMissingPackets(kDefaultPathId));
+ EXPECT_FALSE(multipath_manager_.HasNewMissingPackets(kPathId1));
+ EXPECT_QUIC_BUG(
+ multipath_manager_.HasNewMissingPackets(kPathId2),
+ "Check whether has new missing packets on a non-existent path");
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_multipath_sent_packet_manager.cc b/chromium/net/quic/core/quic_multipath_sent_packet_manager.cc
new file mode 100644
index 00000000000..5d46ec10f06
--- /dev/null
+++ b/chromium/net/quic/core/quic_multipath_sent_packet_manager.cc
@@ -0,0 +1,524 @@
+// 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/quic_multipath_sent_packet_manager.h"
+
+#include <cstdint>
+
+#include "base/strings/string_number_conversions.h"
+#include "net/quic/core/quic_bug_tracker.h"
+
+using std::string;
+using std::max;
+
+namespace net {
+
+QuicMultipathSentPacketManager::QuicMultipathSentPacketManager(
+ QuicSentPacketManagerInterface* manager,
+ QuicConnectionCloseDelegateInterface* delegate)
+ : delegate_(delegate) {
+ path_managers_info_.push_back(PathSentPacketManagerInfo(manager, ACTIVE));
+}
+
+QuicMultipathSentPacketManager::~QuicMultipathSentPacketManager() {
+ for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
+ delete path_manager_info.manager;
+ }
+}
+
+void QuicMultipathSentPacketManager::SetFromConfig(const QuicConfig& config) {
+ for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
+ if (path_manager_info.manager != nullptr) {
+ path_manager_info.manager->SetFromConfig(config);
+ }
+ }
+}
+
+void QuicMultipathSentPacketManager::ResumeConnectionState(
+ const CachedNetworkParameters& cached_network_params,
+ bool max_bandwidth_resumption) {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ if (path_manager == nullptr) {
+ OnUnrecoverablePathError(kDefaultPathId);
+ return;
+ }
+ path_manager->ResumeConnectionState(cached_network_params,
+ max_bandwidth_resumption);
+}
+
+void QuicMultipathSentPacketManager::SetNumOpenStreams(size_t num_streams) {
+ for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
+ if (path_manager_info.manager != nullptr) {
+ path_manager_info.manager->SetNumOpenStreams(num_streams);
+ }
+ }
+}
+
+void QuicMultipathSentPacketManager::SetMaxPacingRate(
+ QuicBandwidth max_pacing_rate) {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ if (path_manager == nullptr) {
+ OnUnrecoverablePathError(kDefaultPathId);
+ return;
+ }
+ path_manager->SetMaxPacingRate(max_pacing_rate);
+}
+
+void QuicMultipathSentPacketManager::SetHandshakeConfirmed() {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ if (path_manager == nullptr) {
+ OnUnrecoverablePathError(kDefaultPathId);
+ return;
+ }
+ path_manager->SetHandshakeConfirmed();
+}
+
+void QuicMultipathSentPacketManager::OnIncomingAck(
+ const QuicAckFrame& ack_frame,
+ QuicTime ack_receive_time) {
+ if (ack_frame.path_id >= path_managers_info_.size() ||
+ path_managers_info_[ack_frame.path_id].state != ACTIVE) {
+ return;
+ }
+ path_managers_info_[ack_frame.path_id].manager->OnIncomingAck(
+ ack_frame, ack_receive_time);
+}
+
+void QuicMultipathSentPacketManager::RetransmitUnackedPackets(
+ TransmissionType retransmission_type) {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ if (path_manager == nullptr) {
+ OnUnrecoverablePathError(kDefaultPathId);
+ return;
+ }
+ path_manager->RetransmitUnackedPackets(retransmission_type);
+}
+
+bool QuicMultipathSentPacketManager::MaybeRetransmitTailLossProbe() {
+ for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
+ if (path_manager_info.manager != nullptr &&
+ path_manager_info.state == ACTIVE) {
+ if (path_manager_info.manager->MaybeRetransmitTailLossProbe()) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void QuicMultipathSentPacketManager::NeuterUnencryptedPackets() {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ if (path_manager == nullptr) {
+ OnUnrecoverablePathError(kDefaultPathId);
+ return;
+ }
+ path_manager->NeuterUnencryptedPackets();
+}
+
+bool QuicMultipathSentPacketManager::HasPendingRetransmissions() const {
+ // TODO(fayang): Move pending_retransmissions_ from path sent packet manager
+ // to multipath sent packet manager.
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ return path_manager != nullptr && path_manager->HasPendingRetransmissions();
+}
+
+PendingRetransmission
+QuicMultipathSentPacketManager::NextPendingRetransmission() {
+ // TODO(fayang): Move pending_retransmissions_ from path sent packet manager
+ // to multipath sent packet manager.
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ if (path_manager == nullptr) {
+ OnUnrecoverablePathError(kDefaultPathId);
+ QuicFrames retransmittable_frames;
+ return PendingRetransmission(kInvalidPathId, 0u, NOT_RETRANSMISSION,
+ retransmittable_frames, false, 0,
+ ENCRYPTION_NONE, PACKET_1BYTE_PACKET_NUMBER);
+ }
+ return path_manager->NextPendingRetransmission();
+}
+
+bool QuicMultipathSentPacketManager::HasUnackedPackets() const {
+ for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
+ if (path_manager_info.manager != nullptr &&
+ path_manager_info.state == ACTIVE &&
+ path_manager_info.manager->HasUnackedPackets()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+QuicPacketNumber QuicMultipathSentPacketManager::GetLeastUnacked(
+ QuicPathId path_id) const {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForPath(path_id);
+ if (path_manager == nullptr) {
+ return 0;
+ }
+ return path_manager->GetLeastUnacked(path_id);
+}
+
+bool QuicMultipathSentPacketManager::OnPacketSent(
+ SerializedPacket* serialized_packet,
+ QuicPathId original_path_id,
+ QuicPacketNumber original_packet_number,
+ QuicTime sent_time,
+ TransmissionType transmission_type,
+ HasRetransmittableData has_retransmittable_data) {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(serialized_packet->path_id);
+ // TODO(fayang): Handle packets retransmitted on different path.
+ DCHECK(original_packet_number == 0 ||
+ original_path_id == serialized_packet->path_id);
+ if (path_manager == nullptr) {
+ OnUnrecoverablePathError(serialized_packet->path_id);
+ return false;
+ }
+
+ return path_manager->OnPacketSent(
+ serialized_packet, original_path_id, original_packet_number, sent_time,
+ transmission_type, has_retransmittable_data);
+}
+
+void QuicMultipathSentPacketManager::OnRetransmissionTimeout() {
+ QuicPathId rto_path = DetermineRetransmissionTimeoutPath();
+ DCHECK_NE(kInvalidPathId, rto_path);
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(rto_path);
+ if (path_manager == nullptr) {
+ OnUnrecoverablePathError(rto_path);
+ return;
+ }
+ path_manager->OnRetransmissionTimeout();
+}
+
+QuicTime::Delta QuicMultipathSentPacketManager::TimeUntilSend(
+ QuicTime now,
+ QuicPathId* path_id) {
+ QuicTime::Delta delay = QuicTime::Delta::Infinite();
+ *path_id = kInvalidPathId;
+ for (size_t i = 0; i < path_managers_info_.size(); ++i) {
+ if (path_managers_info_[i].manager == nullptr ||
+ path_managers_info_[i].state != ACTIVE) {
+ continue;
+ }
+
+ QuicTime::Delta path_delay =
+ path_managers_info_[i].manager->TimeUntilSend(now, path_id);
+ if (!path_delay.IsInfinite() && path_delay < delay) {
+ delay = path_delay;
+ *path_id = i;
+ }
+ }
+ DCHECK(*path_id == kInvalidPathId || !delay.IsInfinite());
+ return delay;
+}
+
+const QuicTime QuicMultipathSentPacketManager::GetRetransmissionTime() const {
+ QuicTime retransmission_time = QuicTime::Zero();
+ for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
+ if (path_manager_info.manager == nullptr ||
+ path_manager_info.state != ACTIVE) {
+ continue;
+ }
+ QuicTime path_retransmission_time =
+ path_manager_info.manager->GetRetransmissionTime();
+ if (!path_retransmission_time.IsInitialized()) {
+ continue;
+ }
+ if (!retransmission_time.IsInitialized() ||
+ path_retransmission_time < retransmission_time) {
+ retransmission_time = path_retransmission_time;
+ }
+ }
+
+ return retransmission_time;
+}
+
+const RttStats* QuicMultipathSentPacketManager::GetRttStats() const {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ if (path_manager == nullptr) {
+ return nullptr;
+ }
+ return path_manager->GetRttStats();
+}
+
+QuicBandwidth QuicMultipathSentPacketManager::BandwidthEstimate() const {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ if (path_manager == nullptr) {
+ return QuicBandwidth::Zero();
+ }
+ return path_manager->BandwidthEstimate();
+}
+
+const QuicSustainedBandwidthRecorder*
+QuicMultipathSentPacketManager::SustainedBandwidthRecorder() const {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ if (path_manager == nullptr) {
+ return nullptr;
+ }
+ return path_manager->SustainedBandwidthRecorder();
+}
+
+QuicPacketCount QuicMultipathSentPacketManager::GetCongestionWindowInTcpMss()
+ const {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ if (path_manager == nullptr) {
+ return 0;
+ }
+ return path_manager->GetCongestionWindowInTcpMss();
+}
+
+QuicPacketCount QuicMultipathSentPacketManager::EstimateMaxPacketsInFlight(
+ QuicByteCount max_packet_length) const {
+ QuicPacketCount max_packets_in_flight = 0;
+ for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
+ if (path_manager_info.manager != nullptr) {
+ max_packets_in_flight =
+ max(max_packets_in_flight,
+ path_manager_info.manager->EstimateMaxPacketsInFlight(
+ max_packet_length));
+ }
+ }
+ DCHECK_LT(0u, max_packets_in_flight);
+ return max_packets_in_flight;
+}
+
+QuicByteCount QuicMultipathSentPacketManager::GetCongestionWindowInBytes()
+ const {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ if (path_manager == nullptr) {
+ return 0;
+ }
+ return path_manager->GetCongestionWindowInBytes();
+}
+
+QuicPacketCount QuicMultipathSentPacketManager::GetSlowStartThresholdInTcpMss()
+ const {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ if (path_manager == nullptr) {
+ return 0;
+ }
+ return path_manager->GetSlowStartThresholdInTcpMss();
+}
+
+string QuicMultipathSentPacketManager::GetDebugState() const {
+ string debug_state_by_path;
+ for (size_t i = 0; i < path_managers_info_.size(); ++i) {
+ if (path_managers_info_[i].manager == nullptr ||
+ path_managers_info_[i].state != ACTIVE) {
+ continue;
+ }
+ const string& debug_state = path_managers_info_[i].manager->GetDebugState();
+ if (debug_state.empty()) {
+ continue;
+ }
+ debug_state_by_path =
+ debug_state_by_path + "[" + base::IntToString(i) + "]:" + debug_state;
+ }
+ return debug_state_by_path;
+}
+
+void QuicMultipathSentPacketManager::CancelRetransmissionsForStream(
+ QuicStreamId stream_id) {
+ for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
+ if (path_manager_info.manager != nullptr) {
+ path_manager_info.manager->CancelRetransmissionsForStream(stream_id);
+ }
+ }
+}
+
+void QuicMultipathSentPacketManager::OnConnectionMigration(
+ QuicPathId path_id,
+ PeerAddressChangeType type) {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(path_id);
+ if (path_manager == nullptr) {
+ OnUnrecoverablePathError(path_id);
+ return;
+ }
+ path_manager->OnConnectionMigration(path_id, type);
+}
+
+void QuicMultipathSentPacketManager::SetDebugDelegate(
+ DebugDelegate* debug_delegate) {
+ for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
+ if (path_manager_info.manager == nullptr) {
+ continue;
+ }
+ path_manager_info.manager->SetDebugDelegate(debug_delegate);
+ }
+}
+
+QuicPacketNumber QuicMultipathSentPacketManager::GetLargestObserved(
+ QuicPathId path_id) const {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForPath(path_id);
+ if (path_manager == nullptr) {
+ return 0;
+ }
+ return path_manager->GetLargestObserved(path_id);
+}
+
+QuicPacketNumber QuicMultipathSentPacketManager::GetLargestSentPacket(
+ QuicPathId path_id) const {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForPath(path_id);
+ if (path_manager == nullptr) {
+ return 0;
+ }
+ return path_manager->GetLargestSentPacket(path_id);
+}
+
+QuicPacketNumber QuicMultipathSentPacketManager::GetLeastPacketAwaitedByPeer(
+ QuicPathId path_id) const {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForPath(path_id);
+ if (path_manager == nullptr) {
+ return 0;
+ }
+ return path_manager->GetLeastPacketAwaitedByPeer(path_id);
+}
+
+void QuicMultipathSentPacketManager::SetNetworkChangeVisitor(
+ NetworkChangeVisitor* visitor) {
+ for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
+ if (path_manager_info.manager == nullptr ||
+ path_manager_info.state != ACTIVE) {
+ continue;
+ }
+ path_manager_info.manager->SetNetworkChangeVisitor(visitor);
+ }
+}
+
+bool QuicMultipathSentPacketManager::InSlowStart() const {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ return path_manager != nullptr && path_manager->InSlowStart();
+}
+
+size_t QuicMultipathSentPacketManager::GetConsecutiveRtoCount() const {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ if (path_manager == nullptr) {
+ return 0;
+ }
+ return path_manager->GetConsecutiveRtoCount();
+}
+size_t QuicMultipathSentPacketManager::GetConsecutiveTlpCount() const {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
+ if (path_manager == nullptr) {
+ return 0;
+ }
+ return path_manager->GetConsecutiveTlpCount();
+}
+
+QuicMultipathSentPacketManager::PathSentPacketManagerInfo::
+ PathSentPacketManagerInfo()
+ : manager(nullptr), state(CLOSING) {}
+
+QuicMultipathSentPacketManager::PathSentPacketManagerInfo::
+ PathSentPacketManagerInfo(QuicSentPacketManagerInterface* manager,
+ PathSentPacketManagerState state)
+ : manager(manager), state(state) {}
+
+QuicMultipathSentPacketManager::PathSentPacketManagerInfo::
+ PathSentPacketManagerInfo(const PathSentPacketManagerInfo& other) = default;
+
+QuicSentPacketManagerInterface*
+QuicMultipathSentPacketManager::MaybeGetSentPacketManagerForPath(
+ QuicPathId path_id) const {
+ if (path_id >= path_managers_info_.size() ||
+ path_managers_info_[path_id].manager == nullptr) {
+ QUIC_BUG << "Sent packet manager of path: (" + base::IntToString(path_id) +
+ ") must exist but does not.";
+ return nullptr;
+ }
+
+ return path_managers_info_[path_id].manager;
+}
+
+QuicSentPacketManagerInterface*
+QuicMultipathSentPacketManager::MaybeGetSentPacketManagerForActivePath(
+ QuicPathId path_id) const {
+ QuicSentPacketManagerInterface* path_manager =
+ MaybeGetSentPacketManagerForPath(path_id);
+ if (path_manager == nullptr) {
+ return nullptr;
+ }
+ if (path_managers_info_[path_id].state != ACTIVE) {
+ QUIC_BUG << "Sent packet manager of path: (" + base::IntToString(path_id) +
+ ") must be active but is not.";
+ return nullptr;
+ }
+
+ return path_manager;
+}
+
+QuicPathId QuicMultipathSentPacketManager::DetermineRetransmissionTimeoutPath()
+ const {
+ QuicTime retransmission_time = QuicTime::Zero();
+ QuicPathId rto_path = kInvalidPathId;
+ for (size_t i = 0; i < path_managers_info_.size(); ++i) {
+ if (path_managers_info_[i].manager == nullptr ||
+ path_managers_info_[i].state != ACTIVE) {
+ continue;
+ }
+ QuicTime path_retransmission_time =
+ path_managers_info_[i].manager->GetRetransmissionTime();
+ if (!path_retransmission_time.IsInitialized()) {
+ continue;
+ }
+ if (!retransmission_time.IsInitialized() ||
+ path_retransmission_time < retransmission_time) {
+ retransmission_time = path_retransmission_time;
+ rto_path = i;
+ }
+ }
+ return rto_path;
+}
+
+void QuicMultipathSentPacketManager::OnUnrecoverablePathError(
+ QuicPathId path_id) {
+ if (MaybeGetSentPacketManagerForPath(path_id) == nullptr) {
+ const string error_details = "Sent packet manager of path: (" +
+ base::IntToString(path_id) +
+ ") must exist but does not.";
+ delegate_->OnUnrecoverableError(QUIC_MULTIPATH_PATH_DOES_NOT_EXIST,
+ error_details,
+ ConnectionCloseSource::FROM_SELF);
+ return;
+ }
+ const string error_details = "Sent packet manager of path: (" +
+ base::IntToString(path_id) +
+ ") must be active but is not.";
+ delegate_->OnUnrecoverableError(QUIC_MULTIPATH_PATH_NOT_ACTIVE, error_details,
+ ConnectionCloseSource::FROM_SELF);
+}
+
+void QuicMultipathSentPacketManager::OnApplicationLimited() {
+ for (PathSentPacketManagerInfo& path_manager_info : path_managers_info_) {
+ if (path_manager_info.manager == nullptr ||
+ path_manager_info.state != ACTIVE) {
+ continue;
+ }
+ path_manager_info.manager->OnApplicationLimited();
+ }
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_multipath_sent_packet_manager.h b/chromium/net/quic/core/quic_multipath_sent_packet_manager.h
new file mode 100644
index 00000000000..75b35ddf237
--- /dev/null
+++ b/chromium/net/quic/core/quic_multipath_sent_packet_manager.h
@@ -0,0 +1,220 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_MULTIPATH_SENT_PACKET_MANAGER_H_
+#define NET_QUIC_QUIC_MULTIPATH_SENT_PACKET_MANAGER_H_
+
+#include <vector>
+
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_sent_packet_manager.h"
+#include "net/quic/core/quic_sent_packet_manager_interface.h"
+
+namespace net {
+
+namespace test {
+class QuicConnectionPeer;
+class QuicMultipathSentPacketManagerPeer;
+} // namespace test
+
+// A connection level sent packet manager which manages a sent packet manager
+// per path. The main duties of multipath sent packet manager comprise:
+// (1) manages a pending retransmission queue shared among all paths;
+// (2) records mapping of packets transmitted on different paths;
+// (3) consults paths which should timeout on a retransmission timeout.
+// TODO(fayang): Currently above duties are not fully implemented, need to
+// finish them.
+class NET_EXPORT_PRIVATE QuicMultipathSentPacketManager
+ : public QuicSentPacketManagerInterface {
+ public:
+ // Multipath sent packet manager takes ownership of |manager|.
+ explicit QuicMultipathSentPacketManager(
+ QuicSentPacketManagerInterface* manager,
+ QuicConnectionCloseDelegateInterface* delegate);
+ ~QuicMultipathSentPacketManager() override;
+
+ // Start implementation of QuicSentPacketManagerInterface.
+ // Sets all paths from |config|.
+ void SetFromConfig(const QuicConfig& config) override;
+
+ // Resumes connection state on the default path.
+ void ResumeConnectionState(
+ const CachedNetworkParameters& cached_network_params,
+ bool max_bandwidth_resumption) override;
+
+ // Sets number of active streams of all paths.
+ void SetNumOpenStreams(size_t num_streams) override;
+
+ // Sets max pacing rate of the default path.
+ void SetMaxPacingRate(QuicBandwidth max_pacing_rate) override;
+
+ void SetHandshakeConfirmed() override;
+
+ // Directs |ack_frame| to the appropriate path sent packet manager.
+ void OnIncomingAck(const QuicAckFrame& ack_frame,
+ QuicTime ack_receive_time) override;
+
+ // Requests retransmission of all unacked packets of |retransmission_type| on
+ // the default path.
+ void RetransmitUnackedPackets(TransmissionType retransmission_type) override;
+
+ // Tries to retransmit the oldest pending packet across all paths. The
+ // retransmission is sent on the path that has a TLP timer pending.
+ bool MaybeRetransmitTailLossProbe() override;
+
+ // Removes the retransmittable frames from all unencrypted packets on the
+ // default path to ensure they don't get retransmitted.
+ void NeuterUnencryptedPackets() override;
+
+ // Returns true if there are pending retransmissions.
+ bool HasPendingRetransmissions() const override;
+
+ // Retrieves the next pending retransmission. Caller must ensure that
+ // there are pending retransmissions prior to calling this function.
+ PendingRetransmission NextPendingRetransmission() override;
+
+ // Returns true if the any path has unacked packets.
+ bool HasUnackedPackets() const override;
+
+ // Returns the smallest packet number of a serialized packet which has not
+ // been acked on |path_id|.
+ QuicPacketNumber GetLeastUnacked(QuicPathId path_id) const override;
+
+ // Called when a packet has been sent to the peer. If this packet is a
+ // retransmission on a different path than the original packet, records the
+ // mapping in |transmissions_map_|. Retransmittable frames are transfered from
+ // original packet to the sent packet.
+ bool OnPacketSent(SerializedPacket* serialized_packet,
+ QuicPathId original_path_id,
+ QuicPacketNumber original_packet_number,
+ QuicTime sent_time,
+ TransmissionType transmission_type,
+ HasRetransmittableData has_retransmittable_data) override;
+
+ // Called when the retransmission timer expires.
+ void OnRetransmissionTimeout() override;
+
+ // Returns the earliest time the next packet can be sent. Sets |path_id| to be
+ // the path on which the next packet should be sent.
+ QuicTime::Delta TimeUntilSend(QuicTime now, QuicPathId* path_id) override;
+
+ // Returns the earliest retransmission time of all paths.
+ const QuicTime GetRetransmissionTime() const override;
+
+ // Returns the rtt stats of the default path.
+ const RttStats* GetRttStats() const override;
+
+ // Returns the estimated bandwidth on default path calculated by the
+ // congestion algorithm.
+ QuicBandwidth BandwidthEstimate() const override;
+
+ // Returns the sustained bandwidth recorder on the default path.
+ const QuicSustainedBandwidthRecorder* SustainedBandwidthRecorder()
+ const override;
+
+ // Returns the size of the current congestion window on default path in number
+ // of kDefaultTCPMSS-sized segments.
+ QuicPacketCount GetCongestionWindowInTcpMss() const override;
+
+ // Determines the number of packets of length |max_packet_length| which fit in
+ // the congestion windows for all paths, and returns the max number of packets
+ // across all paths.
+ QuicPacketCount EstimateMaxPacketsInFlight(
+ QuicByteCount max_packet_length) const override;
+
+ // Returns the size of the current congestion window size on the default path
+ // in bytes.
+ QuicByteCount GetCongestionWindowInBytes() const override;
+
+ // Returns the size of the slow start congestion window in number of 1460 byte
+ // TCP segments on the default path.
+ QuicPacketCount GetSlowStartThresholdInTcpMss() const override;
+
+ // Returns debugging information about the state of the congestion
+ // controller for all paths.
+ std::string GetDebugState() const override;
+
+ // No longer retransmit data for |stream_id| on all paths and any pending
+ // retransmissions in pending_retransmissions_.
+ void CancelRetransmissionsForStream(QuicStreamId stream_id) override;
+
+ void OnConnectionMigration(QuicPathId path_id,
+ PeerAddressChangeType type) override;
+
+ // Sets debug delegate for all active paths.
+ void SetDebugDelegate(DebugDelegate* debug_delegate) override;
+
+ QuicPacketNumber GetLargestObserved(QuicPathId path_id) const override;
+
+ QuicPacketNumber GetLargestSentPacket(QuicPathId path_id) const override;
+
+ QuicPacketNumber GetLeastPacketAwaitedByPeer(
+ QuicPathId path_id) const override;
+
+ // Sets network change visitor for all active paths.
+ void SetNetworkChangeVisitor(NetworkChangeVisitor* visitor) override;
+
+ // Returns true if the default path is in slow start.
+ bool InSlowStart() const override;
+
+ // These two methods return the consecutive RTO or TLP count of the default
+ // path.
+ size_t GetConsecutiveRtoCount() const override;
+ size_t GetConsecutiveTlpCount() const override;
+
+ void OnApplicationLimited() override;
+
+ private:
+ friend class test::QuicConnectionPeer;
+ friend class test::QuicMultipathSentPacketManagerPeer;
+
+ // State of per path sent packet manager.
+ // TODO(fayang): Need to add a state that path can receive acks but cannot
+ // send data.
+ enum PathSentPacketManagerState {
+ ACTIVE, // We both send packets and receiving acks on this path.
+ CLOSING, // We stop sending packets and receiving acks on this path. There
+ // are retransmittable frames in the unacked packets map.
+ };
+
+ // PathSentPacketManagerInfo contains sent packet manager and its state.
+ struct NET_EXPORT_PRIVATE PathSentPacketManagerInfo {
+ PathSentPacketManagerInfo();
+ PathSentPacketManagerInfo(QuicSentPacketManagerInterface* manager,
+ PathSentPacketManagerState state);
+ PathSentPacketManagerInfo(const PathSentPacketManagerInfo& other);
+
+ QuicSentPacketManagerInterface* manager;
+ PathSentPacketManagerState state;
+ };
+
+ // Returns path sent packet manager if it exists for |path_id|, returns
+ // nullptr otherwise.
+ QuicSentPacketManagerInterface* MaybeGetSentPacketManagerForPath(
+ QuicPathId path_id) const;
+
+ // Returns path sent packet manager if it exists and |path_id| is ACTIVE,
+ // returns nullptr otherwise.
+ QuicSentPacketManagerInterface* MaybeGetSentPacketManagerForActivePath(
+ QuicPathId path_id) const;
+
+ // Returns the path which has the earliest retransmission time.
+ QuicPathId DetermineRetransmissionTimeoutPath() const;
+
+ // Close the connection on unrecoverable path errors.
+ void OnUnrecoverablePathError(QuicPathId path_id);
+
+ // Current path sent packet managers info, index is path id.
+ std::vector<PathSentPacketManagerInfo> path_managers_info_;
+
+ // Does not own this delegate.
+ QuicConnectionCloseDelegateInterface* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicMultipathSentPacketManager);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_MULTIPATH_SENT_PACKET_MANAGER_H_
diff --git a/chromium/net/quic/core/quic_multipath_sent_packet_manager_test.cc b/chromium/net/quic/core/quic_multipath_sent_packet_manager_test.cc
new file mode 100644
index 00000000000..bcff44da01b
--- /dev/null
+++ b/chromium/net/quic/core/quic_multipath_sent_packet_manager_test.cc
@@ -0,0 +1,356 @@
+// 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/quic_multipath_sent_packet_manager.h"
+
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/test_tools/quic_multipath_sent_packet_manager_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Return;
+using testing::StrictMock;
+using testing::_;
+
+namespace net {
+namespace test {
+
+namespace {
+
+const QuicPathId kTestPathId1 = 1;
+const QuicPathId kTestPathId2 = 2;
+const QuicPathId kTestPathId3 = 3;
+
+class QuicMultipathSentPacketManagerTest : public testing::Test {
+ public:
+ QuicMultipathSentPacketManagerTest()
+ : manager_0_(new StrictMock<MockSentPacketManager>),
+ manager_1_(new StrictMock<MockSentPacketManager>),
+ manager_2_(new StrictMock<MockSentPacketManager>),
+ multipath_manager_(manager_0_, &delegate_) {
+ // Paths 0 and 1 are active, and path 2 is closing.
+ QuicMultipathSentPacketManagerPeer::AddPathWithActiveState(
+ &multipath_manager_, manager_1_);
+ QuicMultipathSentPacketManagerPeer::AddPathWithCloseState(
+ &multipath_manager_, manager_2_);
+ }
+
+ ~QuicMultipathSentPacketManagerTest() override {}
+
+ MockSentPacketManager* manager_0_;
+ MockSentPacketManager* manager_1_;
+ MockSentPacketManager* manager_2_;
+ QuicMultipathSentPacketManager multipath_manager_;
+ MockClock clock_;
+ StrictMock<MockConnectionCloseDelegate> delegate_;
+};
+
+TEST_F(QuicMultipathSentPacketManagerTest, SetFromConfig) {
+ EXPECT_CALL(*manager_0_, SetFromConfig(_)).Times(1);
+ EXPECT_CALL(*manager_1_, SetFromConfig(_)).Times(1);
+ EXPECT_CALL(*manager_2_, SetFromConfig(_)).Times(1);
+ QuicConfig config;
+ multipath_manager_.SetFromConfig(config);
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, ResumeConnectionState) {
+ EXPECT_CALL(*manager_0_, ResumeConnectionState(_, true));
+ multipath_manager_.ResumeConnectionState(CachedNetworkParameters(), true);
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, SetNumOpenStreams) {
+ size_t kNumStreams = 10;
+ EXPECT_CALL(*manager_0_, SetNumOpenStreams(kNumStreams));
+ EXPECT_CALL(*manager_1_, SetNumOpenStreams(kNumStreams));
+ EXPECT_CALL(*manager_2_, SetNumOpenStreams(kNumStreams));
+ multipath_manager_.SetNumOpenStreams(kNumStreams);
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, SetMaxPacingRate) {
+ QuicBandwidth kBandwidth = QuicBandwidth::FromBitsPerSecond(1000);
+ EXPECT_CALL(*manager_0_, SetMaxPacingRate(kBandwidth));
+ multipath_manager_.SetMaxPacingRate(kBandwidth);
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, SetHandshakeConfirmed) {
+ EXPECT_CALL(*manager_0_, SetHandshakeConfirmed());
+ multipath_manager_.SetHandshakeConfirmed();
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, OnIncomingAck) {
+ QuicAckFrame frame0;
+ QuicAckFrame frame1;
+ frame1.path_id = kTestPathId1;
+ QuicAckFrame frame2;
+ frame2.path_id = kTestPathId2;
+ QuicAckFrame frame3;
+ frame3.path_id = kTestPathId3;
+ EXPECT_CALL(*manager_0_, OnIncomingAck(_, QuicTime::Zero()));
+ EXPECT_CALL(*manager_1_, OnIncomingAck(_, QuicTime::Zero()));
+ EXPECT_CALL(*manager_2_, OnIncomingAck(_, QuicTime::Zero())).Times(0);
+ multipath_manager_.OnIncomingAck(frame0, QuicTime::Zero());
+ multipath_manager_.OnIncomingAck(frame1, QuicTime::Zero());
+ multipath_manager_.OnIncomingAck(frame2, QuicTime::Zero());
+ multipath_manager_.OnIncomingAck(frame3, QuicTime::Zero());
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, RetransmitUnackedPackets) {
+ EXPECT_CALL(*manager_0_, RetransmitUnackedPackets(HANDSHAKE_RETRANSMISSION));
+ multipath_manager_.RetransmitUnackedPackets(HANDSHAKE_RETRANSMISSION);
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, MaybeRetransmitTailLossProbe) {
+ EXPECT_CALL(*manager_0_, MaybeRetransmitTailLossProbe())
+ .WillOnce(Return(false));
+ EXPECT_CALL(*manager_1_, MaybeRetransmitTailLossProbe())
+ .WillOnce(Return(false));
+ EXPECT_FALSE(multipath_manager_.MaybeRetransmitTailLossProbe());
+ EXPECT_CALL(*manager_0_, MaybeRetransmitTailLossProbe())
+ .WillOnce(Return(false));
+ EXPECT_CALL(*manager_1_, MaybeRetransmitTailLossProbe())
+ .WillOnce(Return(true));
+ EXPECT_TRUE(multipath_manager_.MaybeRetransmitTailLossProbe());
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, NeuterUnencryptedPackets) {
+ EXPECT_CALL(*manager_0_, NeuterUnencryptedPackets());
+ multipath_manager_.NeuterUnencryptedPackets();
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, HasPendingRetransmissions) {
+ EXPECT_CALL(*manager_0_, HasPendingRetransmissions()).WillOnce(Return(true));
+ EXPECT_TRUE(multipath_manager_.HasPendingRetransmissions());
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, NextPendingRetransmission) {
+ SerializedPacket packet(kDefaultPathId, 1, PACKET_6BYTE_PACKET_NUMBER,
+ nullptr, 1250, 0u, false, false);
+ PendingRetransmission retransmission(
+ packet.path_id, packet.packet_number, LOSS_RETRANSMISSION,
+ packet.retransmittable_frames, packet.has_crypto_handshake,
+ packet.num_padding_bytes, packet.encryption_level,
+ packet.packet_number_length);
+ EXPECT_CALL(*manager_0_, NextPendingRetransmission())
+ .WillOnce(Return(retransmission));
+ multipath_manager_.NextPendingRetransmission();
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, HasUnackedPackets) {
+ EXPECT_CALL(*manager_0_, HasUnackedPackets()).WillOnce(Return(false));
+ EXPECT_CALL(*manager_1_, HasUnackedPackets()).WillOnce(Return(false));
+ EXPECT_CALL(*manager_2_, HasUnackedPackets()).Times(0);
+ EXPECT_FALSE(multipath_manager_.HasUnackedPackets());
+ EXPECT_CALL(*manager_0_, HasUnackedPackets()).WillOnce(Return(false));
+ EXPECT_CALL(*manager_1_, HasUnackedPackets()).WillOnce(Return(true));
+ EXPECT_TRUE(multipath_manager_.HasUnackedPackets());
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, GetLeastUnacked) {
+ EXPECT_CALL(*manager_0_, GetLeastUnacked(kDefaultPathId)).WillOnce(Return(2));
+ EXPECT_CALL(*manager_1_, GetLeastUnacked(kTestPathId1)).WillOnce(Return(3));
+ EXPECT_CALL(*manager_2_, GetLeastUnacked(kTestPathId2)).WillOnce(Return(4));
+ EXPECT_EQ(2u, multipath_manager_.GetLeastUnacked(kDefaultPathId));
+ EXPECT_EQ(3u, multipath_manager_.GetLeastUnacked(kTestPathId1));
+ EXPECT_EQ(4u, multipath_manager_.GetLeastUnacked(kTestPathId2));
+ EXPECT_QUIC_BUG(multipath_manager_.GetLeastUnacked(kTestPathId3), "");
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, OnPacketSent) {
+ SerializedPacket packet0(kDefaultPathId, 1, PACKET_6BYTE_PACKET_NUMBER,
+ nullptr, 1250, 0u, false, false);
+ SerializedPacket packet1(kTestPathId1, 1, PACKET_6BYTE_PACKET_NUMBER, nullptr,
+ 1250, 0u, false, false);
+ SerializedPacket packet2(kTestPathId2, 1, PACKET_6BYTE_PACKET_NUMBER, nullptr,
+ 1250, 0u, false, false);
+ SerializedPacket packet3(kTestPathId3, 1, PACKET_6BYTE_PACKET_NUMBER, nullptr,
+ 1250, 0u, false, false);
+ EXPECT_CALL(*manager_0_,
+ OnPacketSent(&packet0, kInvalidPathId, 0, clock_.Now(),
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+ multipath_manager_.OnPacketSent(&packet0, kInvalidPathId, 0, clock_.Now(),
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+ EXPECT_CALL(*manager_1_,
+ OnPacketSent(&packet1, kInvalidPathId, 0, clock_.Now(),
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+ multipath_manager_.OnPacketSent(&packet1, kInvalidPathId, 0, clock_.Now(),
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+ EXPECT_CALL(*manager_2_, OnPacketSent(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(delegate_,
+ OnUnrecoverableError(QUIC_MULTIPATH_PATH_NOT_ACTIVE, _, _));
+ EXPECT_QUIC_BUG(multipath_manager_.OnPacketSent(
+ &packet2, kInvalidPathId, 0, clock_.Now(),
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA),
+ "");
+ EXPECT_CALL(delegate_,
+ OnUnrecoverableError(QUIC_MULTIPATH_PATH_DOES_NOT_EXIST, _, _));
+ EXPECT_QUIC_BUG(multipath_manager_.OnPacketSent(
+ &packet3, kInvalidPathId, 0, clock_.Now(),
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA),
+ "");
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, OnRetransmissionTimeout) {
+ QuicTime time0 = clock_.Now() + QuicTime::Delta::FromMilliseconds(50);
+ QuicTime time1 = clock_.Now() + QuicTime::Delta::FromMilliseconds(100);
+ EXPECT_CALL(*manager_0_, GetRetransmissionTime()).WillOnce(Return(time0));
+ EXPECT_CALL(*manager_1_, GetRetransmissionTime()).WillOnce(Return(time1));
+ EXPECT_CALL(*manager_0_, OnRetransmissionTimeout());
+ multipath_manager_.OnRetransmissionTimeout();
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, TimeUntilSend) {
+ QuicPathId path_id = kInvalidPathId;
+ EXPECT_CALL(*manager_0_, TimeUntilSend(clock_.Now(), &path_id))
+ .WillOnce(Return(QuicTime::Delta::FromMilliseconds(200)));
+ EXPECT_CALL(*manager_1_, TimeUntilSend(clock_.Now(), &path_id))
+ .WillOnce(Return(QuicTime::Delta::FromMilliseconds(100)));
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100),
+ multipath_manager_.TimeUntilSend(clock_.Now(), &path_id));
+ EXPECT_EQ(kTestPathId1, path_id);
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, GetRetransmissionTime) {
+ QuicTime time0 = clock_.Now() + QuicTime::Delta::FromMilliseconds(200);
+ QuicTime time1 = clock_.Now() + QuicTime::Delta::FromMilliseconds(100);
+ EXPECT_CALL(*manager_0_, GetRetransmissionTime()).WillOnce(Return(time0));
+ EXPECT_CALL(*manager_1_, GetRetransmissionTime()).WillOnce(Return(time1));
+ EXPECT_EQ(time1, multipath_manager_.GetRetransmissionTime());
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, GetRttStats) {
+ EXPECT_CALL(*manager_0_, GetRttStats());
+ multipath_manager_.GetRttStats();
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, BandwidthEstimate) {
+ QuicBandwidth bandwidth = QuicBandwidth::FromKBitsPerSecond(100);
+ EXPECT_CALL(*manager_0_, BandwidthEstimate()).WillOnce(Return(bandwidth));
+ EXPECT_EQ(bandwidth, multipath_manager_.BandwidthEstimate());
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, GetCongestionWindowInTcpMss) {
+ EXPECT_CALL(*manager_0_, GetCongestionWindowInTcpMss()).WillOnce(Return(100));
+ EXPECT_EQ(100u, multipath_manager_.GetCongestionWindowInTcpMss());
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, EstimateMaxPacketsInFlight) {
+ QuicByteCount max_packet_length = 1250;
+ EXPECT_CALL(*manager_0_, EstimateMaxPacketsInFlight(max_packet_length))
+ .WillOnce(Return(100));
+ EXPECT_CALL(*manager_1_, EstimateMaxPacketsInFlight(max_packet_length))
+ .WillOnce(Return(200));
+ EXPECT_CALL(*manager_2_, EstimateMaxPacketsInFlight(max_packet_length))
+ .WillOnce(Return(300));
+ EXPECT_EQ(300u,
+ multipath_manager_.EstimateMaxPacketsInFlight(max_packet_length));
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, GetSlowStartThresholdInTcpMss) {
+ EXPECT_CALL(*manager_0_, GetSlowStartThresholdInTcpMss())
+ .WillOnce(Return(100));
+ EXPECT_EQ(100u, multipath_manager_.GetSlowStartThresholdInTcpMss());
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, CancelRetransmissionsForStream) {
+ EXPECT_CALL(*manager_0_, CancelRetransmissionsForStream(1));
+ EXPECT_CALL(*manager_1_, CancelRetransmissionsForStream(1));
+ EXPECT_CALL(*manager_2_, CancelRetransmissionsForStream(1));
+ multipath_manager_.CancelRetransmissionsForStream(1);
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, OnConnectionMigration) {
+ EXPECT_CALL(*manager_0_, OnConnectionMigration(kDefaultPathId, PORT_CHANGE));
+ EXPECT_CALL(*manager_2_, OnConnectionMigration(_, _)).Times(0);
+ multipath_manager_.OnConnectionMigration(kDefaultPathId, PORT_CHANGE);
+ EXPECT_CALL(delegate_,
+ OnUnrecoverableError(QUIC_MULTIPATH_PATH_NOT_ACTIVE, _, _));
+ EXPECT_QUIC_BUG(
+ multipath_manager_.OnConnectionMigration(kTestPathId2, PORT_CHANGE), "");
+ EXPECT_CALL(delegate_,
+ OnUnrecoverableError(QUIC_MULTIPATH_PATH_DOES_NOT_EXIST, _, _));
+ EXPECT_QUIC_BUG(
+ multipath_manager_.OnConnectionMigration(kTestPathId3, PORT_CHANGE), "");
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, SetDebugDelegate) {
+ EXPECT_CALL(*manager_0_, SetDebugDelegate(nullptr));
+ EXPECT_CALL(*manager_1_, SetDebugDelegate(nullptr));
+ EXPECT_CALL(*manager_2_, SetDebugDelegate(nullptr));
+ multipath_manager_.SetDebugDelegate(nullptr);
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, GetLargestObserved) {
+ EXPECT_CALL(*manager_0_, GetLargestObserved(kDefaultPathId))
+ .WillOnce(Return(10));
+ EXPECT_CALL(*manager_1_, GetLargestObserved(kTestPathId1))
+ .WillOnce(Return(11));
+ EXPECT_CALL(*manager_2_, GetLargestObserved(kTestPathId2))
+ .WillOnce(Return(12));
+ EXPECT_EQ(10u, multipath_manager_.GetLargestObserved(kDefaultPathId));
+ EXPECT_EQ(11u, multipath_manager_.GetLargestObserved(kTestPathId1));
+ EXPECT_EQ(12u, multipath_manager_.GetLargestObserved(kTestPathId2));
+ EXPECT_QUIC_BUG(multipath_manager_.GetLargestObserved(kTestPathId3), "");
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, GetLargestSentPacket) {
+ EXPECT_CALL(*manager_0_, GetLargestSentPacket(kDefaultPathId))
+ .WillOnce(Return(10));
+ EXPECT_CALL(*manager_1_, GetLargestSentPacket(kTestPathId1))
+ .WillOnce(Return(11));
+ EXPECT_CALL(*manager_2_, GetLargestSentPacket(kTestPathId2))
+ .WillOnce(Return(12));
+ EXPECT_EQ(10u, multipath_manager_.GetLargestSentPacket(kDefaultPathId));
+ EXPECT_EQ(11u, multipath_manager_.GetLargestSentPacket(kTestPathId1));
+ EXPECT_EQ(12u, multipath_manager_.GetLargestSentPacket(kTestPathId2));
+ EXPECT_QUIC_BUG(multipath_manager_.GetLargestSentPacket(kTestPathId3), "");
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, GetLeastPacketAwaitedByPeer) {
+ EXPECT_CALL(*manager_0_, GetLeastPacketAwaitedByPeer(kDefaultPathId))
+ .WillOnce(Return(10));
+ EXPECT_CALL(*manager_1_, GetLeastPacketAwaitedByPeer(kTestPathId1))
+ .WillOnce(Return(11));
+ EXPECT_CALL(*manager_2_, GetLeastPacketAwaitedByPeer(kTestPathId2))
+ .WillOnce(Return(12));
+ EXPECT_EQ(10u,
+ multipath_manager_.GetLeastPacketAwaitedByPeer(kDefaultPathId));
+ EXPECT_EQ(11u, multipath_manager_.GetLeastPacketAwaitedByPeer(kTestPathId1));
+ EXPECT_EQ(12u, multipath_manager_.GetLeastPacketAwaitedByPeer(kTestPathId2));
+ EXPECT_QUIC_BUG(multipath_manager_.GetLeastPacketAwaitedByPeer(kTestPathId3),
+ "");
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, SetNetworkChangeVisitor) {
+ EXPECT_CALL(*manager_0_, SetNetworkChangeVisitor(nullptr));
+ EXPECT_CALL(*manager_1_, SetNetworkChangeVisitor(nullptr));
+ multipath_manager_.SetNetworkChangeVisitor(nullptr);
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, InSlowStart) {
+ EXPECT_CALL(*manager_0_, InSlowStart()).WillOnce(Return(true));
+ EXPECT_TRUE(multipath_manager_.InSlowStart());
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, GetConsecutiveRtoCount) {
+ EXPECT_CALL(*manager_0_, GetConsecutiveRtoCount()).WillOnce(Return(4));
+ EXPECT_EQ(4u, multipath_manager_.GetConsecutiveRtoCount());
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, GetConsecutiveTlpCount) {
+ EXPECT_CALL(*manager_0_, GetConsecutiveTlpCount()).WillOnce(Return(3));
+ EXPECT_EQ(3u, multipath_manager_.GetConsecutiveTlpCount());
+}
+
+TEST_F(QuicMultipathSentPacketManagerTest, OnApplicationLimited) {
+ EXPECT_CALL(*manager_0_, OnApplicationLimited()).Times(1);
+ EXPECT_CALL(*manager_1_, OnApplicationLimited()).Times(1);
+ EXPECT_CALL(*manager_2_, OnApplicationLimited()).Times(0);
+ multipath_manager_.OnApplicationLimited();
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_multipath_transmissions_map.cc b/chromium/net/quic/core/quic_multipath_transmissions_map.cc
new file mode 100644
index 00000000000..100bf0869ae
--- /dev/null
+++ b/chromium/net/quic/core/quic_multipath_transmissions_map.cc
@@ -0,0 +1,70 @@
+// 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.
+
+#include "net/quic/core/quic_multipath_transmissions_map.h"
+
+namespace net {
+
+QuicMultipathTransmissionsMap::QuicMultipathTransmissionsMap() {}
+
+QuicMultipathTransmissionsMap::~QuicMultipathTransmissionsMap() {
+ for (std::pair<QuicPathIdPacketNumber, MultipathTransmissionsList*>
+ packet_transmissions : transmission_map_) {
+ packet_transmissions.second->pop_front();
+ if (packet_transmissions.second->empty()) {
+ delete packet_transmissions.second;
+ }
+ }
+}
+
+void QuicMultipathTransmissionsMap::OnPacketRetransmittedOnDifferentPath(
+ QuicPathIdPacketNumber original_path_id_packet_number,
+ QuicPathIdPacketNumber path_id_packet_number) {
+ MultipathTransmissionsList* across_paths_transmission_list = nullptr;
+ MultipathTransmissionsMap::iterator it =
+ transmission_map_.find(original_path_id_packet_number);
+ if (it != transmission_map_.end()) {
+ across_paths_transmission_list = it->second;
+ } else {
+ across_paths_transmission_list = new MultipathTransmissionsList();
+ across_paths_transmission_list->push_back(original_path_id_packet_number);
+ transmission_map_[original_path_id_packet_number] =
+ across_paths_transmission_list;
+ }
+
+ across_paths_transmission_list->push_back(path_id_packet_number);
+ transmission_map_[path_id_packet_number] = across_paths_transmission_list;
+}
+
+const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
+QuicMultipathTransmissionsMap::MaybeGetTransmissionsOnOtherPaths(
+ QuicPathIdPacketNumber path_id_packet_number) const {
+ MultipathTransmissionsMap::const_iterator it =
+ transmission_map_.find(path_id_packet_number);
+ if (it == transmission_map_.end()) {
+ return nullptr;
+ }
+
+ return it->second;
+}
+
+void QuicMultipathTransmissionsMap::OnPacketHandled(
+ QuicPathIdPacketNumber path_id_packet_number) {
+ MultipathTransmissionsMap::iterator it =
+ transmission_map_.find(path_id_packet_number);
+ if (it == transmission_map_.end()) {
+ return;
+ }
+
+ MultipathTransmissionsList* transmission_list = it->second;
+ MultipathTransmissionsList::iterator transmission_it;
+ // Remove all across paths transmissions of this packet from the map.
+ for (QuicPathIdPacketNumber path_id_packet_number : *transmission_list) {
+ transmission_map_.erase(path_id_packet_number);
+ }
+ // Remove the multipath transmissions list.
+ delete transmission_list;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_multipath_transmissions_map.h b/chromium/net/quic/core/quic_multipath_transmissions_map.h
new file mode 100644
index 00000000000..8802e4d59ee
--- /dev/null
+++ b/chromium/net/quic/core/quic_multipath_transmissions_map.h
@@ -0,0 +1,74 @@
+// 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.
+
+// A map manages packets which are transmitted across multiple paths.
+// For example, a packet is originally transmitted on path 1 with packet number
+// 1. Then this packet is retransmitted on path 2 with packet number 1. (1, 1)
+// and (2, 1) are inserted into this map. Suppose (2, 1) is detected lost and
+// gets retransmitted on path 2 with packet 2. (2, 2) will not be inserted
+// because this transmission does not "across" path compared to (2, 1).
+
+#ifndef NET_QUIC_QUIC_MULTIPATH_TRANSMISSIONS_MAP_H_
+#define NET_QUIC_QUIC_MULTIPATH_TRANSMISSIONS_MAP_H_
+
+#include <deque>
+#include <unordered_map>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_utils.h"
+
+namespace net {
+
+typedef std::pair<QuicPathId, QuicPacketNumber> QuicPathIdPacketNumber;
+
+class NET_EXPORT_PRIVATE QuicMultipathTransmissionsMap {
+ public:
+ struct QuicPathIdPacketNumberHash {
+ size_t operator()(std::pair<QuicPathId, QuicPacketNumber> value) const {
+ return QuicUtils::PackPathIdAndPacketNumber(value.first, value.second);
+ }
+ };
+
+ typedef std::deque<QuicPathIdPacketNumber> MultipathTransmissionsList;
+ typedef std::unordered_map<QuicPathIdPacketNumber,
+ MultipathTransmissionsList*,
+ QuicPathIdPacketNumberHash>
+ MultipathTransmissionsMap;
+
+ QuicMultipathTransmissionsMap();
+ ~QuicMultipathTransmissionsMap();
+
+ // Called when a packet is retransmitted on a different path. Adds both
+ // |original_path_id_packet_number| (if not exists) and
+ // |path_id_packet_number| to |transmission_map_|.
+ void OnPacketRetransmittedOnDifferentPath(
+ QuicPathIdPacketNumber original_path_id_packet_number,
+ QuicPathIdPacketNumber path_id_packet_number);
+
+ // Returns all multipath transmissions list if |path_id_packet_number| has
+ // been transmitted across multiple paths, nullptr otherwise.
+ const MultipathTransmissionsList* MaybeGetTransmissionsOnOtherPaths(
+ QuicPathIdPacketNumber path_id_packet_number) const;
+
+ // Called after packet |path_id_packet_number| is received.
+ // If |path_id_packet_number| has been transmitted across multiple paths,
+ // clears all multipath transmissions list and removes each transmission from
+ // |transmission_map_|, does nothing otherwise.
+ void OnPacketHandled(QuicPathIdPacketNumber path_id_packet_number);
+
+ private:
+ // Keys of the map are QuicPathIdPacketNumber, and values are pointers to
+ // lists of multipath transmissions of the same packet. For example, if a
+ // packet has been transmitted as (1, 1) and (2, 1), two entries are added
+ // to this map and both values point to the same list: {(1, 1), (2, 1)}.
+ // The MultipathTransmissionsList is owned by the transmission which is
+ // received first (on any path).
+ MultipathTransmissionsMap transmission_map_;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_MULTIPATH_TRANSMISSIONS_MAP_H_
diff --git a/chromium/net/quic/core/quic_multipath_transmissions_map_test.cc b/chromium/net/quic/core/quic_multipath_transmissions_map_test.cc
new file mode 100644
index 00000000000..a264b0d75c9
--- /dev/null
+++ b/chromium/net/quic/core/quic_multipath_transmissions_map_test.cc
@@ -0,0 +1,114 @@
+// 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.
+
+#include "net/quic/core/quic_multipath_transmissions_map.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+namespace {
+
+TEST(QuicAcrossPathsTransmissionMapTest, OnPacketRetransmittedOnDifferentPath) {
+ QuicMultipathTransmissionsMap transmission_map;
+ // Packet0's original transmission sent on path 1 with packet number 1.
+ QuicPathIdPacketNumber packet0_0(1, 1);
+ // Packet0's retransmission sent on path 2 with packet number 1.
+ QuicPathIdPacketNumber packet0_1(2, 1);
+ // packet0's 2nd retransmission sent on path 3 with packet number 1.
+ QuicPathIdPacketNumber packet0_2(3, 1);
+
+ transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_0, packet0_1);
+ const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
+ transmission_list1 =
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0);
+ EXPECT_EQ(packet0_0, (*transmission_list1)[0]);
+ EXPECT_EQ(packet0_1, (*transmission_list1)[1]);
+
+ transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_1, packet0_2);
+ const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
+ transmission_list2 =
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0);
+ EXPECT_EQ(packet0_0, (*transmission_list2)[0]);
+ EXPECT_EQ(packet0_1, (*transmission_list2)[1]);
+ EXPECT_EQ(packet0_2, (*transmission_list2)[2]);
+ // Make sure there is no memory leakage.
+}
+
+TEST(QuicAcrossPathsTransmissionMapTest, MaybeGetTransmissionsOnOtherPaths) {
+ QuicMultipathTransmissionsMap transmission_map;
+ // Packet0's original transmission sent on path 1 with packet number 1.
+ QuicPathIdPacketNumber packet0_0(1, 1);
+ // Packet0's retransmission sent on path 2 with packet number 1.
+ QuicPathIdPacketNumber packet0_1(2, 1);
+ // packet0's 2nd retransmission sent on path 3 with packet number 1.
+ QuicPathIdPacketNumber packet0_2(3, 1);
+
+ transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_0, packet0_1);
+ transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_1, packet0_2);
+
+ const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
+ transmission_list1 =
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0);
+ const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
+ transmission_list2 =
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_1);
+ const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
+ transmission_list3 =
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_2);
+ // Make sure all three pointers point to the same list.
+ EXPECT_EQ(transmission_list1, transmission_list2);
+ EXPECT_EQ(transmission_list2, transmission_list3);
+ EXPECT_EQ(packet0_0, (*transmission_list1)[0]);
+ EXPECT_EQ(packet0_1, (*transmission_list1)[1]);
+ EXPECT_EQ(packet0_2, (*transmission_list1)[2]);
+
+ // Packet1 which is not transmitted across path.
+ QuicPathIdPacketNumber packet1_0(1, 2);
+ EXPECT_EQ(nullptr,
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_0));
+ // Make sure there is no memory leakage.
+}
+
+TEST(QuicAcrossPathsTransmissionMapTest, OnPacketHandled) {
+ QuicMultipathTransmissionsMap transmission_map;
+
+ // Packet's original transmission sent on path 1 with packet number 1.
+ QuicPathIdPacketNumber packet0_0(1, 1);
+ // Packet's retransmission sent on path 2 with packet number 1.
+ QuicPathIdPacketNumber packet0_1(2, 1);
+ // packet's 2nd retransmission sent on path 3 with packet number 1.
+ QuicPathIdPacketNumber packet0_2(3, 1);
+ transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_0, packet0_1);
+ transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_1, packet0_2);
+
+ // Packet1's original transmission sent on path 1 with packet number 2.
+ QuicPathIdPacketNumber packet1_0(1, 2);
+ // Packet1's retransmission sent on path 2 with packet number 2.
+ QuicPathIdPacketNumber packet1_1(2, 2);
+ transmission_map.OnPacketRetransmittedOnDifferentPath(packet1_0, packet1_1);
+
+ transmission_map.OnPacketHandled(packet0_0);
+ EXPECT_EQ(nullptr,
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0));
+ EXPECT_EQ(nullptr,
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_1));
+ EXPECT_EQ(nullptr,
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_2));
+ const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
+ transmission_list =
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_0);
+ EXPECT_EQ(packet1_0, (*transmission_list)[0]);
+ EXPECT_EQ(packet1_1, (*transmission_list)[1]);
+ // Packet 1 is received on path 2.
+ transmission_map.OnPacketHandled(packet1_1);
+ EXPECT_EQ(nullptr,
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_0));
+ EXPECT_EQ(nullptr,
+ transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_1));
+ // Make sure there is no memory leakage.
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_one_block_arena.h b/chromium/net/quic/core/quic_one_block_arena.h
new file mode 100644
index 00000000000..37893747ec6
--- /dev/null
+++ b/chromium/net/quic/core/quic_one_block_arena.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// An arena that consists of a single inlined block of |ArenaSize|. Useful to
+// avoid repeated calls to malloc/new and to improve memory locality. DCHECK's
+// if an allocation out of the arena ever fails in debug builds; falls back to
+// heap allocation in release builds.
+
+#ifndef NET_QUIC_QUIC_ONE_BLOCK_ARENA_H_
+#define NET_QUIC_QUIC_ONE_BLOCK_ARENA_H_
+
+#include "net/quic/core/quic_arena_scoped_ptr.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+
+#define PREDICT_FALSE(x) x
+
+namespace net {
+
+template <uint32_t ArenaSize>
+class QuicOneBlockArena {
+ static const uint32_t kMaxAlign = 8;
+
+ public:
+ QuicOneBlockArena();
+
+ // Instantiates an object of type |T| with |args|. |args| are perfectly
+ // forwarded to |T|'s constructor. The returned pointer's lifetime is
+ // controlled by QuicArenaScopedPtr.
+ template <typename T, typename... Args>
+ QuicArenaScopedPtr<T> New(Args&&... args);
+
+ private:
+ // Returns the size of |T| aligned up to |kMaxAlign|.
+ template <typename T>
+ static inline uint32_t AlignedSize() {
+ return ((sizeof(T) + (kMaxAlign - 1)) / kMaxAlign) * kMaxAlign;
+ }
+
+ // Actual storage.
+ // Subtle/annoying: the value '8' must be coded explicitly into the alignment
+ // declaration for MSVC.
+ QUIC_ALIGNED(8) char storage_[ArenaSize];
+ // Current offset into the storage.
+ uint32_t offset_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicOneBlockArena);
+};
+
+template <uint32_t ArenaSize>
+QuicOneBlockArena<ArenaSize>::QuicOneBlockArena() : offset_(0) {}
+
+template <uint32_t ArenaSize>
+template <typename T, typename... Args>
+QuicArenaScopedPtr<T> QuicOneBlockArena<ArenaSize>::New(Args&&... args) {
+ DCHECK_LT(AlignedSize<T>(), ArenaSize)
+ << "Object is too large for the arena.";
+ static_assert(QUIC_ALIGN_OF(T) > 1,
+ "Objects added to the arena must be at least 2B aligned.");
+ if (PREDICT_FALSE(offset_ > ArenaSize - AlignedSize<T>())) {
+ LOG(DFATAL) << "Ran out of space in QuicOneBlockArena at " << this
+ << ", max size was " << ArenaSize << ", failing request was "
+ << AlignedSize<T>() << ", end of arena was " << offset_;
+ return QuicArenaScopedPtr<T>(new T(std::forward<Args>(args)...));
+ }
+
+ void* buf = &storage_[offset_];
+ new (buf) T(std::forward<Args>(args)...);
+ offset_ += AlignedSize<T>();
+ return QuicArenaScopedPtr<T>(buf,
+ QuicArenaScopedPtr<T>::ConstructFrom::kArena);
+}
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_ONE_BLOCK_ARENA_H_
diff --git a/chromium/net/quic/core/quic_one_block_arena_test.cc b/chromium/net/quic/core/quic_one_block_arena_test.cc
new file mode 100644
index 00000000000..15ff0c67211
--- /dev/null
+++ b/chromium/net/quic/core/quic_one_block_arena_test.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_one_block_arena.h"
+
+#include "net/quic/core/interval_set.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace {
+
+static const uint32_t kMaxAlign = 8;
+
+struct TestObject {
+ uint32_t value;
+};
+
+TEST(QuicOneBlockArenaTest, AllocateSuccess) {
+ QuicOneBlockArena<1024> arena;
+ QuicArenaScopedPtr<TestObject> ptr = arena.New<TestObject>();
+ EXPECT_TRUE(ptr.is_from_arena());
+}
+
+TEST(QuicOneBlockArenaTest, Exhaust) {
+ QuicOneBlockArena<1024> arena;
+ for (size_t i = 0; i < 1024 / kMaxAlign; ++i) {
+ QuicArenaScopedPtr<TestObject> ptr = arena.New<TestObject>();
+ EXPECT_TRUE(ptr.is_from_arena());
+ }
+ QuicArenaScopedPtr<TestObject> ptr;
+ EXPECT_QUIC_BUG(ptr = arena.New<TestObject>(),
+ "Ran out of space in QuicOneBlockArena");
+ EXPECT_FALSE(ptr.is_from_arena());
+}
+
+TEST(QuicOneBlockArenaTest, NoOverlaps) {
+ QuicOneBlockArena<1024> arena;
+ std::vector<QuicArenaScopedPtr<TestObject>> objects;
+ IntervalSet<uintptr_t> used;
+ for (size_t i = 0; i < 1024 / kMaxAlign; ++i) {
+ QuicArenaScopedPtr<TestObject> ptr = arena.New<TestObject>();
+ EXPECT_TRUE(ptr.is_from_arena());
+
+ uintptr_t begin = reinterpret_cast<uintptr_t>(ptr.get());
+ uintptr_t end = begin + sizeof(TestObject);
+ EXPECT_FALSE(used.Contains(begin));
+ EXPECT_FALSE(used.Contains(end - 1));
+ used.Add(begin, end);
+ }
+}
+
+} // namespace
+} // namespace net
diff --git a/chromium/net/quic/core/quic_packet_creator.cc b/chromium/net/quic/core/quic_packet_creator.cc
new file mode 100644
index 00000000000..2b2a8c141d7
--- /dev/null
+++ b/chromium/net/quic/core/quic_packet_creator.cc
@@ -0,0 +1,690 @@
+// 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/quic_packet_creator.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_data_writer.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+
+using base::StringPiece;
+using std::make_pair;
+using std::max;
+using std::min;
+using std::pair;
+using std::string;
+using std::vector;
+
+namespace net {
+
+QuicPacketCreator::QuicPacketCreator(QuicConnectionId connection_id,
+ QuicFramer* framer,
+ QuicRandom* random_generator,
+ QuicBufferAllocator* buffer_allocator,
+ DelegateInterface* delegate)
+ : delegate_(delegate),
+ debug_delegate_(nullptr),
+ framer_(framer),
+ random_bool_source_(random_generator),
+ buffer_allocator_(buffer_allocator),
+ send_version_in_packet_(framer->perspective() == Perspective::IS_CLIENT),
+ send_path_id_in_packet_(false),
+ next_packet_number_length_(PACKET_1BYTE_PACKET_NUMBER),
+ have_diversification_nonce_(false),
+ max_packet_length_(0),
+ connection_id_length_(PACKET_8BYTE_CONNECTION_ID),
+ packet_size_(0),
+ connection_id_(connection_id),
+ packet_(kDefaultPathId,
+ 0,
+ PACKET_1BYTE_PACKET_NUMBER,
+ nullptr,
+ 0,
+ 0,
+ false,
+ false) {
+ SetMaxPacketLength(kDefaultMaxPacketSize);
+}
+
+QuicPacketCreator::~QuicPacketCreator() {
+ QuicUtils::DeleteFrames(&packet_.retransmittable_frames);
+}
+
+void QuicPacketCreator::SetEncrypter(EncryptionLevel level,
+ QuicEncrypter* encrypter) {
+ framer_->SetEncrypter(level, encrypter);
+ max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_);
+}
+
+bool QuicPacketCreator::CanSetMaxPacketLength() const {
+ // |max_packet_length_| should not be changed mid-packet.
+ return queued_frames_.empty();
+}
+
+void QuicPacketCreator::SetMaxPacketLength(QuicByteCount length) {
+ DCHECK(CanSetMaxPacketLength());
+
+ // Avoid recomputing |max_plaintext_size_| if the length does not actually
+ // change.
+ if (length == max_packet_length_) {
+ return;
+ }
+
+ max_packet_length_ = length;
+ max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_);
+}
+
+// Stops serializing version of the protocol in packets sent after this call.
+// A packet that is already open might send kQuicVersionSize bytes less than the
+// maximum packet size if we stop sending version before it is serialized.
+void QuicPacketCreator::StopSendingVersion() {
+ DCHECK(send_version_in_packet_);
+ send_version_in_packet_ = false;
+ if (packet_size_ > 0) {
+ DCHECK_LT(kQuicVersionSize, packet_size_);
+ packet_size_ -= kQuicVersionSize;
+ }
+}
+
+void QuicPacketCreator::SetDiversificationNonce(
+ const DiversificationNonce& nonce) {
+ DCHECK(!have_diversification_nonce_);
+ have_diversification_nonce_ = true;
+ diversification_nonce_ = nonce;
+}
+
+void QuicPacketCreator::UpdatePacketNumberLength(
+ QuicPacketNumber least_packet_awaited_by_peer,
+ QuicPacketCount max_packets_in_flight) {
+ if (!queued_frames_.empty()) {
+ // Don't change creator state if there are frames queued.
+ QUIC_BUG << "Called UpdatePacketNumberLength with " << queued_frames_.size()
+ << " queued_frames. First frame type:"
+ << queued_frames_.front().type
+ << " last frame type:" << queued_frames_.back().type;
+ return;
+ }
+
+ DCHECK_LE(least_packet_awaited_by_peer, packet_.packet_number + 1);
+ const QuicPacketNumber current_delta =
+ packet_.packet_number + 1 - least_packet_awaited_by_peer;
+ const uint64_t delta = max(current_delta, max_packets_in_flight);
+ packet_.packet_number_length =
+ QuicFramer::GetMinSequenceNumberLength(delta * 4);
+}
+
+bool QuicPacketCreator::ConsumeData(QuicStreamId id,
+ QuicIOVector iov,
+ size_t iov_offset,
+ QuicStreamOffset offset,
+ bool fin,
+ bool needs_full_padding,
+ QuicFrame* frame) {
+ if (!HasRoomForStreamFrame(id, offset)) {
+ return false;
+ }
+ CreateStreamFrame(id, iov, iov_offset, offset, fin, frame);
+ // Explicitly disallow multi-packet CHLOs.
+ if (id == kCryptoStreamId &&
+ frame->stream_frame->data_length >= sizeof(kCHLO) &&
+ strncmp(frame->stream_frame->data_buffer,
+ reinterpret_cast<const char*>(&kCHLO), sizeof(kCHLO)) == 0) {
+ DCHECK_EQ(static_cast<size_t>(0), iov_offset);
+ if (frame->stream_frame->data_length < iov.iov->iov_len) {
+ const string error_details = "Client hello won't fit in a single packet.";
+ QUIC_BUG << error_details << " Constructed stream frame length: "
+ << frame->stream_frame->data_length
+ << " CHLO length: " << iov.iov->iov_len;
+ delegate_->OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, error_details,
+ ConnectionCloseSource::FROM_SELF);
+ delete frame->stream_frame;
+ return false;
+ }
+ }
+ if (!AddFrame(*frame, /*save_retransmittable_frames=*/true)) {
+ // Fails if we try to write unencrypted stream data.
+ delete frame->stream_frame;
+ return false;
+ }
+ if (needs_full_padding) {
+ packet_.num_padding_bytes = -1;
+ }
+ return true;
+}
+
+bool QuicPacketCreator::HasRoomForStreamFrame(QuicStreamId id,
+ QuicStreamOffset offset) {
+ return BytesFree() > QuicFramer::GetMinStreamFrameSize(id, offset, true);
+}
+
+// static
+size_t QuicPacketCreator::StreamFramePacketOverhead(
+ QuicVersion version,
+ QuicConnectionIdLength connection_id_length,
+ bool include_version,
+ bool include_path_id,
+ bool include_diversification_nonce,
+ QuicPacketNumberLength packet_number_length,
+ QuicStreamOffset offset) {
+ return GetPacketHeaderSize(version, connection_id_length, include_version,
+ include_path_id, include_diversification_nonce,
+ packet_number_length) +
+ // Assumes this is a stream with a single lone packet.
+ QuicFramer::GetMinStreamFrameSize(1u, offset, true);
+}
+
+void QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
+ QuicIOVector iov,
+ size_t iov_offset,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicFrame* frame) {
+ DCHECK_GT(max_packet_length_,
+ StreamFramePacketOverhead(framer_->version(), connection_id_length_,
+ kIncludeVersion, kIncludePathId,
+ IncludeNonceInPublicHeader(),
+ PACKET_6BYTE_PACKET_NUMBER, offset));
+
+ QUIC_BUG_IF(!HasRoomForStreamFrame(id, offset))
+ << "No room for Stream frame, BytesFree: " << BytesFree()
+ << " MinStreamFrameSize: "
+ << QuicFramer::GetMinStreamFrameSize(id, offset, true);
+
+ if (iov_offset == iov.total_length) {
+ QUIC_BUG_IF(!fin) << "Creating a stream frame with no data or fin.";
+ // Create a new packet for the fin, if necessary.
+ *frame = QuicFrame(new QuicStreamFrame(id, true, offset, StringPiece()));
+ return;
+ }
+
+ const size_t data_size = iov.total_length - iov_offset;
+ size_t min_frame_size = QuicFramer::GetMinStreamFrameSize(
+ id, offset, /* last_frame_in_packet= */ true);
+ size_t bytes_consumed = min<size_t>(BytesFree() - min_frame_size, data_size);
+
+ bool set_fin = fin && bytes_consumed == data_size; // Last frame.
+ UniqueStreamBuffer buffer =
+ NewStreamBuffer(buffer_allocator_, bytes_consumed);
+ CopyToBuffer(iov, iov_offset, bytes_consumed, buffer.get());
+ *frame = QuicFrame(new QuicStreamFrame(id, set_fin, offset, bytes_consumed,
+ std::move(buffer)));
+}
+
+// static
+void QuicPacketCreator::CopyToBuffer(QuicIOVector iov,
+ size_t iov_offset,
+ size_t length,
+ char* buffer) {
+ int iovnum = 0;
+ while (iovnum < iov.iov_count && iov_offset >= iov.iov[iovnum].iov_len) {
+ iov_offset -= iov.iov[iovnum].iov_len;
+ ++iovnum;
+ }
+ DCHECK_LE(iovnum, iov.iov_count);
+ DCHECK_LE(iov_offset, iov.iov[iovnum].iov_len);
+ if (iovnum >= iov.iov_count || length == 0) {
+ return;
+ }
+
+ // Unroll the first iteration that handles iov_offset.
+ const size_t iov_available = iov.iov[iovnum].iov_len - iov_offset;
+ size_t copy_len = min(length, iov_available);
+
+ // Try to prefetch the next iov if there is at least one more after the
+ // current. Otherwise, it looks like an irregular access that the hardware
+ // prefetcher won't speculatively prefetch. Only prefetch one iov because
+ // 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.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);
+ // 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.
+ // prefetch(next_base, PREFETCH_HINT_T0);
+ if (iov.iov[iovnum + 1].iov_len >= 64) {
+ // TODO(ckrasic) - investigate what to do about prefetch directives.
+ // prefetch(next_base + CACHELINE_SIZE, PREFETCH_HINT_T0);
+ }
+ }
+
+ const char* src = static_cast<char*>(iov.iov[iovnum].iov_base) + iov_offset;
+ while (true) {
+ memcpy(buffer, src, copy_len);
+ length -= copy_len;
+ buffer += copy_len;
+ if (length == 0 || ++iovnum >= iov.iov_count) {
+ break;
+ }
+ src = static_cast<char*>(iov.iov[iovnum].iov_base);
+ copy_len = min(length, iov.iov[iovnum].iov_len);
+ }
+ QUIC_BUG_IF(length > 0) << "Failed to copy entire length to buffer.";
+}
+
+void QuicPacketCreator::ReserializeAllFrames(
+ const PendingRetransmission& retransmission,
+ char* buffer,
+ size_t buffer_len) {
+ DCHECK(queued_frames_.empty());
+ DCHECK_EQ(0, packet_.num_padding_bytes);
+ QUIC_BUG_IF(retransmission.retransmittable_frames.empty())
+ << "Attempt to serialize empty packet";
+ const EncryptionLevel default_encryption_level = packet_.encryption_level;
+
+ // Temporarily set the packet number length and change the encryption level.
+ packet_.packet_number_length = retransmission.packet_number_length;
+ packet_.num_padding_bytes = retransmission.num_padding_bytes;
+ // Only preserve the original encryption level if it's a handshake packet or
+ // if we haven't gone forward secure.
+ if (retransmission.has_crypto_handshake ||
+ packet_.encryption_level != ENCRYPTION_FORWARD_SECURE) {
+ packet_.encryption_level = retransmission.encryption_level;
+ }
+
+ // Serialize the packet and restore packet number length state.
+ for (const QuicFrame& frame : retransmission.retransmittable_frames) {
+ bool success = AddFrame(frame, false);
+ QUIC_BUG_IF(!success) << " Failed to add frame of type:" << frame.type
+ << " num_frames:"
+ << retransmission.retransmittable_frames.size()
+ << " retransmission.packet_number_length:"
+ << retransmission.packet_number_length
+ << " packet_.packet_number_length:"
+ << packet_.packet_number_length;
+ }
+ SerializePacket(buffer, buffer_len);
+ packet_.original_path_id = retransmission.path_id;
+ packet_.original_packet_number = retransmission.packet_number;
+ packet_.transmission_type = retransmission.transmission_type;
+ OnSerializedPacket();
+ // Restore old values.
+ packet_.encryption_level = default_encryption_level;
+}
+
+void QuicPacketCreator::Flush() {
+ if (!HasPendingFrames()) {
+ return;
+ }
+
+ // TODO(rtenneti): Change the default 64 alignas value (used the default
+ // value from CACHELINE_SIZE).
+ ALIGNAS(64) char seralized_packet_buffer[kMaxPacketSize];
+ SerializePacket(seralized_packet_buffer, kMaxPacketSize);
+ OnSerializedPacket();
+}
+
+void QuicPacketCreator::OnSerializedPacket() {
+ if (packet_.encrypted_buffer == nullptr) {
+ const string error_details = "Failed to SerializePacket.";
+ QUIC_BUG << error_details;
+ delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET,
+ error_details,
+ ConnectionCloseSource::FROM_SELF);
+ return;
+ }
+
+ delegate_->OnSerializedPacket(&packet_);
+ ClearPacket();
+ // Maximum packet size may be only enacted while no packet is currently being
+ // constructed, so here we have a good opportunity to actually change it.
+ if (CanSetMaxPacketLength()) {
+ SetMaxPacketLength(max_packet_length_);
+ }
+}
+
+void QuicPacketCreator::ClearPacket() {
+ packet_.has_ack = false;
+ packet_.has_stop_waiting = false;
+ packet_.has_crypto_handshake = NOT_HANDSHAKE;
+ packet_.num_padding_bytes = 0;
+ packet_.original_path_id = kInvalidPathId;
+ packet_.original_packet_number = 0;
+ packet_.transmission_type = NOT_RETRANSMISSION;
+ packet_.encrypted_buffer = nullptr;
+ packet_.encrypted_length = 0;
+ DCHECK(packet_.retransmittable_frames.empty());
+ packet_.listeners.clear();
+}
+
+void QuicPacketCreator::CreateAndSerializeStreamFrame(
+ QuicStreamId id,
+ const QuicIOVector& iov,
+ QuicStreamOffset iov_offset,
+ QuicStreamOffset stream_offset,
+ bool fin,
+ QuicAckListenerInterface* listener,
+ size_t* num_bytes_consumed) {
+ DCHECK(queued_frames_.empty());
+ // Write out the packet header
+ QuicPacketHeader header;
+ FillPacketHeader(&header);
+ ALIGNAS(64) char encrypted_buffer[kMaxPacketSize];
+ QuicDataWriter writer(arraysize(encrypted_buffer), encrypted_buffer);
+ if (!framer_->AppendPacketHeader(header, &writer)) {
+ QUIC_BUG << "AppendPacketHeader failed";
+ return;
+ }
+
+ // Create a Stream frame with the remaining space.
+ QUIC_BUG_IF(iov_offset == iov.total_length && !fin)
+ << "Creating a stream frame with no data or fin.";
+ const size_t remaining_data_size = iov.total_length - iov_offset;
+ const size_t min_frame_size = QuicFramer::GetMinStreamFrameSize(
+ id, stream_offset, /* last_frame_in_packet= */ true);
+ const size_t available_size =
+ max_plaintext_size_ - writer.length() - min_frame_size;
+ const size_t bytes_consumed =
+ min<size_t>(available_size, remaining_data_size);
+
+ const bool set_fin = fin && (bytes_consumed == remaining_data_size);
+ UniqueStreamBuffer stream_buffer =
+ NewStreamBuffer(buffer_allocator_, bytes_consumed);
+ CopyToBuffer(iov, iov_offset, bytes_consumed, stream_buffer.get());
+ std::unique_ptr<QuicStreamFrame> frame(new QuicStreamFrame(
+ id, set_fin, stream_offset, bytes_consumed, std::move(stream_buffer)));
+ DVLOG(1) << "Adding frame: " << *frame;
+
+ // TODO(ianswett): AppendTypeByte and AppendStreamFrame could be optimized
+ // into one method that takes a QuicStreamFrame, if warranted.
+ if (!framer_->AppendTypeByte(QuicFrame(frame.get()),
+ /* no stream frame length */ true, &writer)) {
+ QUIC_BUG << "AppendTypeByte failed";
+ return;
+ }
+ if (!framer_->AppendStreamFrame(*frame, /* no stream frame length */ true,
+ &writer)) {
+ QUIC_BUG << "AppendStreamFrame failed";
+ return;
+ }
+
+ size_t encrypted_length = framer_->EncryptInPlace(
+ packet_.encryption_level, packet_.path_id, packet_.packet_number,
+ GetStartOfEncryptedData(framer_->version(), header), writer.length(),
+ arraysize(encrypted_buffer), encrypted_buffer);
+ if (encrypted_length == 0) {
+ QUIC_BUG << "Failed to encrypt packet number " << header.packet_number;
+ return;
+ }
+ // TODO(ianswett): Optimize the storage so RetransmitableFrames can be
+ // unioned with a QuicStreamFrame and a UniqueStreamBuffer.
+ *num_bytes_consumed = bytes_consumed;
+ packet_size_ = 0;
+ packet_.entropy_hash = QuicFramer::GetPacketEntropyHash(header);
+ packet_.encrypted_buffer = encrypted_buffer;
+ packet_.encrypted_length = encrypted_length;
+ if (listener != nullptr) {
+ packet_.listeners.emplace_back(listener, bytes_consumed);
+ }
+ packet_.retransmittable_frames.push_back(QuicFrame(frame.release()));
+ OnSerializedPacket();
+}
+
+bool QuicPacketCreator::HasPendingFrames() const {
+ return !queued_frames_.empty();
+}
+
+bool QuicPacketCreator::HasPendingRetransmittableFrames() const {
+ return !packet_.retransmittable_frames.empty();
+}
+
+size_t QuicPacketCreator::ExpansionOnNewFrame() const {
+ // If the last frame in the packet is a stream frame, then it will expand to
+ // include the stream_length field when a new frame is added.
+ bool has_trailing_stream_frame =
+ !queued_frames_.empty() && queued_frames_.back().type == STREAM_FRAME;
+ return has_trailing_stream_frame ? kQuicStreamPayloadLengthSize : 0;
+}
+
+size_t QuicPacketCreator::BytesFree() {
+ DCHECK_GE(max_plaintext_size_, PacketSize());
+ return max_plaintext_size_ -
+ min(max_plaintext_size_, PacketSize() + ExpansionOnNewFrame());
+}
+
+size_t QuicPacketCreator::PacketSize() {
+ if (!queued_frames_.empty()) {
+ return packet_size_;
+ }
+ packet_size_ = GetPacketHeaderSize(
+ framer_->version(), connection_id_length_, send_version_in_packet_,
+ send_path_id_in_packet_, IncludeNonceInPublicHeader(),
+ packet_.packet_number_length);
+ return packet_size_;
+}
+
+bool QuicPacketCreator::AddSavedFrame(const QuicFrame& frame) {
+ return AddFrame(frame, /*save_retransmittable_frames=*/true);
+}
+
+bool QuicPacketCreator::AddPaddedSavedFrame(const QuicFrame& frame) {
+ if (AddFrame(frame, /*save_retransmittable_frames=*/true)) {
+ packet_.num_padding_bytes = -1;
+ return true;
+ }
+ return false;
+}
+
+void QuicPacketCreator::AddAckListener(QuicAckListenerInterface* listener,
+ QuicPacketLength length) {
+ DCHECK(!queued_frames_.empty());
+ packet_.listeners.emplace_back(listener, length);
+}
+
+void QuicPacketCreator::SerializePacket(char* encrypted_buffer,
+ size_t encrypted_buffer_len) {
+ DCHECK_LT(0u, encrypted_buffer_len);
+ QUIC_BUG_IF(queued_frames_.empty()) << "Attempt to serialize empty packet";
+ QuicPacketHeader header;
+ // FillPacketHeader increments packet_number_.
+ FillPacketHeader(&header);
+
+ MaybeAddPadding();
+
+ DCHECK_GE(max_plaintext_size_, packet_size_);
+ // Use the packet_size_ instead of the buffer size to ensure smaller
+ // packet sizes are properly used.
+ size_t length = framer_->BuildDataPacket(header, queued_frames_,
+ encrypted_buffer, packet_size_);
+ if (length == 0) {
+ QUIC_BUG << "Failed to serialize " << queued_frames_.size() << " frames.";
+ return;
+ }
+
+ // ACK Frames will be truncated due to length only if they're the only frame
+ // in the packet, and if packet_size_ was set to max_plaintext_size_. If
+ // truncation due to length occurred, then GetSerializedFrameLength will have
+ // returned all bytes free.
+ bool possibly_truncated_by_length = packet_size_ == max_plaintext_size_ &&
+ queued_frames_.size() == 1 &&
+ queued_frames_.back().type == ACK_FRAME;
+ // Because of possible truncation, we can't be confident that our
+ // packet size calculation worked correctly.
+ if (!possibly_truncated_by_length) {
+ DCHECK_EQ(packet_size_, length);
+ }
+ const size_t encrypted_length = framer_->EncryptInPlace(
+ packet_.encryption_level, packet_.path_id, packet_.packet_number,
+ GetStartOfEncryptedData(framer_->version(), header), length,
+ encrypted_buffer_len, encrypted_buffer);
+ if (encrypted_length == 0) {
+ QUIC_BUG << "Failed to encrypt packet number " << packet_.packet_number;
+ return;
+ }
+
+ packet_size_ = 0;
+ queued_frames_.clear();
+ packet_.entropy_hash = QuicFramer::GetPacketEntropyHash(header);
+ packet_.encrypted_buffer = encrypted_buffer;
+ packet_.encrypted_length = encrypted_length;
+}
+
+QuicEncryptedPacket* QuicPacketCreator::SerializeVersionNegotiationPacket(
+ const QuicVersionVector& supported_versions) {
+ DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective());
+ QuicEncryptedPacket* encrypted = QuicFramer::BuildVersionNegotiationPacket(
+ connection_id_, supported_versions);
+ DCHECK(encrypted);
+ DCHECK_GE(max_packet_length_, encrypted->length());
+ return encrypted;
+}
+
+// TODO(jri): Make this a public method of framer?
+SerializedPacket QuicPacketCreator::NoPacket() {
+ return SerializedPacket(kInvalidPathId, 0, PACKET_1BYTE_PACKET_NUMBER,
+ nullptr, 0, 0, false, false);
+}
+
+void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) {
+ header->public_header.connection_id = connection_id_;
+ header->public_header.connection_id_length = connection_id_length_;
+ header->public_header.multipath_flag = send_path_id_in_packet_;
+ header->public_header.reset_flag = false;
+ header->public_header.version_flag = send_version_in_packet_;
+ if (IncludeNonceInPublicHeader()) {
+ DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective());
+ header->public_header.nonce = &diversification_nonce_;
+ } else {
+ header->public_header.nonce = nullptr;
+ }
+ header->path_id = packet_.path_id;
+ header->packet_number = ++packet_.packet_number;
+ header->public_header.packet_number_length = packet_.packet_number_length;
+ header->entropy_flag = random_bool_source_.RandBool();
+}
+
+bool QuicPacketCreator::ShouldRetransmit(const QuicFrame& frame) {
+ switch (frame.type) {
+ case ACK_FRAME:
+ case PADDING_FRAME:
+ case STOP_WAITING_FRAME:
+ case MTU_DISCOVERY_FRAME:
+ return false;
+ default:
+ return true;
+ }
+}
+
+bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
+ bool save_retransmittable_frames) {
+ DVLOG(1) << "Adding frame: " << frame;
+ if (frame.type == STREAM_FRAME &&
+ frame.stream_frame->stream_id != kCryptoStreamId &&
+ packet_.encryption_level == ENCRYPTION_NONE) {
+ const string error_details = "Cannot send stream data without encryption.";
+ QUIC_BUG << error_details;
+ delegate_->OnUnrecoverableError(
+ QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA, error_details,
+ ConnectionCloseSource::FROM_SELF);
+ return false;
+ }
+ size_t frame_len = framer_->GetSerializedFrameLength(
+ frame, BytesFree(), queued_frames_.empty(), true,
+ packet_.packet_number_length);
+ if (frame_len == 0) {
+ // Current open packet is full.
+ Flush();
+ return false;
+ }
+ DCHECK_LT(0u, packet_size_);
+ packet_size_ += ExpansionOnNewFrame() + frame_len;
+
+ if (save_retransmittable_frames && ShouldRetransmit(frame)) {
+ if (packet_.retransmittable_frames.empty()) {
+ packet_.retransmittable_frames.reserve(2);
+ }
+ packet_.retransmittable_frames.push_back(frame);
+ queued_frames_.push_back(frame);
+ if (frame.type == STREAM_FRAME &&
+ frame.stream_frame->stream_id == kCryptoStreamId) {
+ packet_.has_crypto_handshake = IS_HANDSHAKE;
+ }
+ } else {
+ queued_frames_.push_back(frame);
+ }
+
+ if (frame.type == ACK_FRAME) {
+ packet_.has_ack = true;
+ }
+ if (frame.type == STOP_WAITING_FRAME) {
+ packet_.has_stop_waiting = true;
+ }
+ if (debug_delegate_ != nullptr) {
+ debug_delegate_->OnFrameAddedToPacket(frame);
+ }
+
+ return true;
+}
+
+void QuicPacketCreator::MaybeAddPadding() {
+ if (packet_.num_padding_bytes == 0) {
+ return;
+ }
+
+ if (BytesFree() == 0) {
+ // Don't pad full packets.
+ return;
+ }
+
+ bool success =
+ AddFrame(QuicFrame(QuicPaddingFrame(packet_.num_padding_bytes)), false);
+ DCHECK(success);
+}
+
+void QuicPacketCreator::SetCurrentPath(
+ QuicPathId path_id,
+ QuicPacketNumber least_packet_awaited_by_peer,
+ QuicPacketCount max_packets_in_flight) {
+ if (packet_.path_id == path_id) {
+ return;
+ }
+
+ if (HasPendingFrames()) {
+ QUIC_BUG << "Unable to change paths when a packet is under construction.";
+ return;
+ }
+ // Save current packet number and load switching path's packet number.
+ multipath_packet_number_[packet_.path_id] = packet_.packet_number;
+ std::unordered_map<QuicPathId, QuicPacketNumber>::iterator it =
+ multipath_packet_number_.find(path_id);
+ // If path_id is not in the map, it's a new path. Set packet_number to 0.
+ packet_.packet_number = it == multipath_packet_number_.end() ? 0 : it->second;
+ packet_.path_id = path_id;
+ DCHECK(packet_.path_id != kInvalidPathId);
+ // Send path in packet if current path is not the default path.
+ send_path_id_in_packet_ = packet_.path_id != kDefaultPathId ? true : false;
+ // Switching path needs to update packet number length.
+ UpdatePacketNumberLength(least_packet_awaited_by_peer, max_packets_in_flight);
+}
+
+bool QuicPacketCreator::IncludeNonceInPublicHeader() {
+ return have_diversification_nonce_ &&
+ packet_.encryption_level == ENCRYPTION_INITIAL;
+}
+
+QuicPacketCreator::QuicRandomBoolSource::QuicRandomBoolSource(
+ QuicRandom* random)
+ : random_(random), bit_bucket_(0), bit_mask_(0) {}
+
+QuicPacketCreator::QuicRandomBoolSource::~QuicRandomBoolSource() {}
+
+bool QuicPacketCreator::QuicRandomBoolSource::RandBool() {
+ if (bit_mask_ == 0) {
+ bit_bucket_ = random_->RandUint64();
+ bit_mask_ = 1;
+ }
+ bool result = ((bit_bucket_ & bit_mask_) != 0);
+ bit_mask_ <<= 1;
+ return result;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_packet_creator.h b/chromium/net/quic/core/quic_packet_creator.h
new file mode 100644
index 00000000000..55ab53524be
--- /dev/null
+++ b/chromium/net/quic/core/quic_packet_creator.h
@@ -0,0 +1,350 @@
+// 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.
+//
+// Accumulates frames for the next packet until more frames no longer fit or
+// it's time to create a packet from them. If multipath enabled, only creates
+// packets on one path at the same time. Currently, next packet number is
+// tracked per-path.
+
+#ifndef NET_QUIC_QUIC_PACKET_CREATOR_H_
+#define NET_QUIC_QUIC_PACKET_CREATOR_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+namespace test {
+class QuicPacketCreatorPeer;
+}
+
+class QuicRandom;
+
+class NET_EXPORT_PRIVATE QuicPacketCreator {
+ public:
+ // A delegate interface for further processing serialized packet.
+ class NET_EXPORT_PRIVATE DelegateInterface
+ : public QuicConnectionCloseDelegateInterface {
+ public:
+ ~DelegateInterface() override {}
+ // Called when a packet is serialized. Delegate does not take the ownership
+ // of |serialized_packet|, but takes ownership of any frames it removes
+ // from |packet.retransmittable_frames|.
+ virtual void OnSerializedPacket(SerializedPacket* serialized_packet) = 0;
+ };
+
+ // Interface which gets callbacks from the QuicPacketCreator at interesting
+ // points. Implementations must not mutate the state of the creator
+ // as a result of these callbacks.
+ class NET_EXPORT_PRIVATE DebugDelegate {
+ public:
+ virtual ~DebugDelegate() {}
+
+ // Called when a frame has been added to the current packet.
+ virtual void OnFrameAddedToPacket(const QuicFrame& frame) {}
+ };
+
+ // QuicRandom* required for packet entropy.
+ QuicPacketCreator(QuicConnectionId connection_id,
+ QuicFramer* framer,
+ QuicRandom* random_generator,
+ QuicBufferAllocator* buffer_allocator,
+ DelegateInterface* delegate);
+
+ ~QuicPacketCreator();
+
+ // Makes the framer not serialize the protocol version in sent packets.
+ void StopSendingVersion();
+
+ // SetDiversificationNonce sets the nonce that will be sent in each public
+ // header of packets encrypted at the initial encryption level. Should only
+ // be called by servers.
+ void SetDiversificationNonce(const DiversificationNonce& nonce);
+
+ // Update the packet number length to use in future packets as soon as it
+ // can be safely changed.
+ // TODO(fayang): Directly set packet number length instead of compute it in
+ // creator.
+ void UpdatePacketNumberLength(QuicPacketNumber least_packet_awaited_by_peer,
+ QuicPacketCount max_packets_in_flight);
+
+ // The overhead the framing will add for a packet with one frame.
+ static size_t StreamFramePacketOverhead(
+ QuicVersion version,
+ QuicConnectionIdLength connection_id_length,
+ bool include_version,
+ bool include_path_id,
+ bool include_diversification_nonce,
+ QuicPacketNumberLength packet_number_length,
+ QuicStreamOffset offset);
+
+ // Returns false and flushes all pending frames if current open packet is
+ // full.
+ // If current packet is not full, converts a raw payload into a stream frame
+ // that fits into the open packet and adds it to the packet.
+ // The payload begins at |iov_offset| into the |iov|.
+ bool ConsumeData(QuicStreamId id,
+ QuicIOVector iov,
+ size_t iov_offset,
+ QuicStreamOffset offset,
+ bool fin,
+ bool needs_full_padding,
+ QuicFrame* frame);
+
+ // Returns true if current open packet can accommodate more stream frames of
+ // stream |id| at |offset|, false otherwise.
+ bool HasRoomForStreamFrame(QuicStreamId id, QuicStreamOffset offset);
+
+ // Re-serializes frames with the original packet's packet number length.
+ // Used for retransmitting packets to ensure they aren't too long.
+ void ReserializeAllFrames(const PendingRetransmission& retransmission,
+ char* buffer,
+ size_t buffer_len);
+
+ // Serializes all added frames into a single packet and invokes the delegate_
+ // to further process the SerializedPacket.
+ void Flush();
+
+ // Optimized method to create a QuicStreamFrame and serialize it. Adds the
+ // QuicStreamFrame to the returned SerializedPacket. Sets
+ // |num_bytes_consumed| to the number of bytes consumed to create the
+ // QuicStreamFrame.
+ void CreateAndSerializeStreamFrame(QuicStreamId id,
+ const QuicIOVector& iov,
+ QuicStreamOffset iov_offset,
+ QuicStreamOffset stream_offset,
+ bool fin,
+ QuicAckListenerInterface* listener,
+ size_t* num_bytes_consumed);
+
+ // Returns true if there are frames pending to be serialized.
+ bool HasPendingFrames() const;
+
+ // Returns true if there are retransmittable frames pending to be serialized.
+ bool HasPendingRetransmittableFrames() const;
+
+ // Returns the number of bytes which are available to be used by additional
+ // frames in the packet. Since stream frames are slightly smaller when they
+ // are the last frame in a packet, this method will return a different
+ // value than max_packet_size - PacketSize(), in this case.
+ size_t BytesFree();
+
+ // Returns the number of bytes that the packet will expand by if a new frame
+ // is added to the packet. If the last frame was a stream frame, it will
+ // expand slightly when a new frame is added, and this method returns the
+ // amount of expected expansion.
+ size_t ExpansionOnNewFrame() const;
+
+ // Returns the number of bytes in the current packet, including the header,
+ // if serialized with the current frames. Adding a frame to the packet
+ // may change the serialized length of existing frames, as per the comment
+ // in BytesFree.
+ size_t PacketSize();
+
+ // Tries to add |frame| to the packet creator's list of frames to be
+ // serialized. If the frame does not fit into the current packet, flushes the
+ // packet and returns false.
+ bool AddSavedFrame(const QuicFrame& frame);
+
+ // Identical to AddSavedFrame, but allows the frame to be padded.
+ bool AddPaddedSavedFrame(const QuicFrame& frame);
+
+ // Adds |listener| to the next serialized packet and notifies the
+ // std::listener with |length| as the number of acked bytes.
+ void AddAckListener(QuicAckListenerInterface* listener,
+ QuicPacketLength length);
+
+ // Creates a version negotiation packet which supports |supported_versions|.
+ // Caller owns the created packet. Also, sets the entropy hash of the
+ // serialized packet to a random bool and returns that value as a member of
+ // SerializedPacket.
+ QuicEncryptedPacket* SerializeVersionNegotiationPacket(
+ const QuicVersionVector& supported_versions);
+
+ // Returns a dummy packet that is valid but contains no useful information.
+ static SerializedPacket NoPacket();
+
+ // Sets the encryption level that will be applied to new packets.
+ void set_encryption_level(EncryptionLevel level) {
+ packet_.encryption_level = level;
+ }
+
+ // packet number of the last created packet, or 0 if no packets have been
+ // created.
+ QuicPacketNumber packet_number() const { return packet_.packet_number; }
+
+ QuicConnectionIdLength connection_id_length() const {
+ return connection_id_length_;
+ }
+
+ void set_connection_id_length(QuicConnectionIdLength length) {
+ connection_id_length_ = length;
+ }
+
+ QuicByteCount max_packet_length() const { return max_packet_length_; }
+
+ bool has_ack() const { return packet_.has_ack; }
+
+ bool has_stop_waiting() const { return packet_.has_stop_waiting; }
+
+ // Sets the encrypter to use for the encryption level and updates the max
+ // plaintext size.
+ void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter);
+
+ // Indicates whether the packet creator is in a state where it can change
+ // current maximum packet length.
+ bool CanSetMaxPacketLength() const;
+
+ // Sets the maximum packet length.
+ void SetMaxPacketLength(QuicByteCount length);
+
+ // Sets the path on which subsequent packets will be created. It is the
+ // caller's responsibility to guarantee no packet is under construction before
+ // calling this function. If |path_id| is different from current_path_,
+ // next_packet_number_length_ is recalculated.
+ void SetCurrentPath(QuicPathId path_id,
+ QuicPacketNumber least_packet_awaited_by_peer,
+ QuicPacketCount max_packets_in_flight);
+
+ void set_debug_delegate(DebugDelegate* debug_delegate) {
+ debug_delegate_ = debug_delegate;
+ }
+
+ private:
+ friend class test::QuicPacketCreatorPeer;
+
+ // A QuicRandom wrapper that gets a bucket of entropy and distributes it
+ // bit-by-bit. Replenishes the bucket as needed. Not thread-safe. Expose this
+ // class if single bit randomness is needed elsewhere.
+ class QuicRandomBoolSource {
+ public:
+ // random: Source of entropy. Not owned.
+ explicit QuicRandomBoolSource(QuicRandom* random);
+
+ ~QuicRandomBoolSource();
+
+ // Returns the next random bit from the bucket.
+ bool RandBool();
+
+ private:
+ // Source of entropy.
+ QuicRandom* random_;
+ // Stored random bits.
+ uint64_t bit_bucket_;
+ // The next available bit has "1" in the mask. Zero means empty bucket.
+ uint64_t bit_mask_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicRandomBoolSource);
+ };
+
+ static bool ShouldRetransmit(const QuicFrame& frame);
+
+ // Converts a raw payload to a frame which fits into the current open
+ // packet. The payload begins at |iov_offset| into the |iov|.
+ // If data is empty and fin is true, the expected behavior is to consume the
+ // fin but return 0. If any data is consumed, it will be copied into a
+ // new buffer that |frame| will point to and own.
+ void CreateStreamFrame(QuicStreamId id,
+ QuicIOVector iov,
+ size_t iov_offset,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicFrame* frame);
+
+ // Copies |length| bytes from iov starting at offset |iov_offset| into buffer.
+ // |iov| must be at least iov_offset+length total length and buffer must be
+ // at least |length| long.
+ static void CopyToBuffer(QuicIOVector iov,
+ size_t iov_offset,
+ size_t length,
+ char* buffer);
+
+ void FillPacketHeader(QuicPacketHeader* header);
+
+ // Adds a |frame| if there is space and returns false and flushes all pending
+ // frames if there isn't room. If |save_retransmittable_frames| is true,
+ // saves the |frame| in the next SerializedPacket.
+ bool AddFrame(const QuicFrame& frame, bool save_retransmittable_frames);
+
+ // Adds a padding frame to the current packet only if the current packet
+ // contains a handshake message, and there is sufficient room to fit a
+ // padding frame.
+ void MaybeAddPadding();
+
+ // Serializes all frames which have been added and adds any which should be
+ // retransmitted to packet_.retransmittable_frames. All frames must fit into
+ // a single packet. Sets the entropy hash of the serialized packet to a
+ // random bool.
+ // Fails if |buffer_len| isn't long enough for the encrypted packet.
+ void SerializePacket(char* encrypted_buffer, size_t buffer_len);
+
+ // Called after a new SerialiedPacket is created to call the delegate's
+ // OnSerializedPacket and reset state.
+ void OnSerializedPacket();
+
+ // Clears all fields of packet_ that should be cleared between serializations.
+ void ClearPacket();
+
+ // Returns true if a diversification nonce should be included in the current
+ // packet's public header.
+ bool IncludeNonceInPublicHeader();
+
+ // Does not own these delegates or the framer.
+ DelegateInterface* delegate_;
+ DebugDelegate* debug_delegate_;
+ QuicFramer* framer_;
+
+ QuicRandomBoolSource random_bool_source_;
+ QuicBufferAllocator* const buffer_allocator_;
+
+ // Controls whether version should be included while serializing the packet.
+ bool send_version_in_packet_;
+ // Controls whether path id should be included while serializing the packet.
+ bool send_path_id_in_packet_;
+ // Staging variable to hold next packet number length. When sequence
+ // number length is to be changed, this variable holds the new length until
+ // a packet boundary, when the creator's packet_number_length_ can be changed
+ // to this new value.
+ QuicPacketNumberLength next_packet_number_length_;
+ // If true, then |nonce_for_public_header_| will be included in the public
+ // header of all packets created at the initial encryption level.
+ bool have_diversification_nonce_;
+ DiversificationNonce diversification_nonce_;
+ // Maximum length including headers and encryption (UDP payload length.)
+ QuicByteCount max_packet_length_;
+ size_t max_plaintext_size_;
+ // Length of connection_id to send over the wire.
+ QuicConnectionIdLength connection_id_length_;
+
+ // Frames to be added to the next SerializedPacket
+ QuicFrames queued_frames_;
+
+ // packet_size should never be read directly, use PacketSize() instead.
+ // TODO(ianswett): Move packet_size_ into SerializedPacket once
+ // QuicEncryptedPacket has been flattened into SerializedPacket.
+ size_t packet_size_;
+ QuicConnectionId connection_id_;
+
+ // Packet used to invoke OnSerializedPacket.
+ SerializedPacket packet_;
+
+ // Map mapping path_id to last sent packet number on the path.
+ std::unordered_map<QuicPathId, QuicPacketNumber> multipath_packet_number_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicPacketCreator);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_PACKET_CREATOR_H_
diff --git a/chromium/net/quic/core/quic_packet_creator_test.cc b/chromium/net/quic/core/quic_packet_creator_test.cc
new file mode 100644
index 00000000000..d8565170b33
--- /dev/null
+++ b/chromium/net/quic/core/quic_packet_creator_test.cc
@@ -0,0 +1,1075 @@
+// 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/quic_packet_creator.h"
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "net/quic/core/crypto/null_encrypter.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_simple_buffer_allocator.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/mock_random.h"
+#include "net/quic/test_tools/quic_framer_peer.h"
+#include "net/quic/test_tools/quic_packet_creator_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using base::StringPiece;
+using std::ostream;
+using std::string;
+using std::vector;
+using testing::DoAll;
+using testing::InSequence;
+using testing::Return;
+using testing::SaveArg;
+using testing::StrictMock;
+using testing::_;
+
+namespace net {
+namespace test {
+namespace {
+
+// Run tests with combinations of {QuicVersion, ToggleVersionSerialization}.
+struct TestParams {
+ TestParams(QuicVersion version,
+ bool version_serialization,
+ QuicConnectionIdLength length)
+ : version(version),
+ connection_id_length(length),
+ version_serialization(version_serialization) {}
+
+ friend ostream& operator<<(ostream& os, const TestParams& p) {
+ os << "{ client_version: " << QuicVersionToString(p.version)
+ << " connection id length: " << p.connection_id_length
+ << " include version: " << p.version_serialization << " }";
+ return os;
+ }
+
+ QuicVersion version;
+ QuicConnectionIdLength connection_id_length;
+ bool version_serialization;
+};
+
+// Constructs various test permutations.
+vector<TestParams> GetTestParams() {
+ vector<TestParams> params;
+ constexpr QuicConnectionIdLength kMax = PACKET_8BYTE_CONNECTION_ID;
+ QuicVersionVector all_supported_versions = AllSupportedVersions();
+ for (size_t i = 0; i < all_supported_versions.size(); ++i) {
+ params.push_back(TestParams(all_supported_versions[i], true, kMax));
+ params.push_back(TestParams(all_supported_versions[i], false, kMax));
+ }
+ params.push_back(
+ TestParams(all_supported_versions[0], true, PACKET_0BYTE_CONNECTION_ID));
+ params.push_back(TestParams(all_supported_versions[0], true, kMax));
+ return params;
+}
+
+class MockDelegate : public QuicPacketCreator::DelegateInterface {
+ public:
+ MockDelegate() {}
+ ~MockDelegate() override {}
+
+ MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet));
+ MOCK_METHOD3(OnUnrecoverableError,
+ void(QuicErrorCode,
+ const string&,
+ ConnectionCloseSource source));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockDelegate);
+};
+
+class QuicPacketCreatorTest : public ::testing::TestWithParam<TestParams> {
+ public:
+ void ClearSerializedPacket(SerializedPacket* serialized_packet) {
+ if (serialized_packet == nullptr) {
+ return;
+ }
+ QuicUtils::ClearSerializedPacket(serialized_packet);
+ }
+
+ void SaveSerializedPacket(SerializedPacket* serialized_packet) {
+ if (serialized_packet == nullptr) {
+ return;
+ }
+ delete[] serialized_packet_.encrypted_buffer;
+ serialized_packet_ = *serialized_packet;
+ serialized_packet_.encrypted_buffer =
+ QuicUtils::CopyBuffer(*serialized_packet);
+ serialized_packet->retransmittable_frames.clear();
+ }
+
+ void DeleteSerializedPacket() {
+ delete[] serialized_packet_.encrypted_buffer;
+ serialized_packet_.encrypted_buffer = nullptr;
+ ClearSerializedPacket(&serialized_packet_);
+ }
+
+ protected:
+ QuicPacketCreatorTest()
+ : server_framer_(SupportedVersions(GetParam().version),
+ QuicTime::Zero(),
+ Perspective::IS_SERVER),
+ client_framer_(SupportedVersions(GetParam().version),
+ QuicTime::Zero(),
+ Perspective::IS_CLIENT),
+ connection_id_(2),
+ data_("foo"),
+ creator_(connection_id_,
+ &client_framer_,
+ &mock_random_,
+ &buffer_allocator_,
+ &delegate_),
+ serialized_packet_(creator_.NoPacket()) {
+ creator_.set_connection_id_length(GetParam().connection_id_length);
+
+ creator_.SetEncrypter(ENCRYPTION_INITIAL, new NullEncrypter());
+ creator_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, new NullEncrypter());
+ client_framer_.set_visitor(&framer_visitor_);
+ client_framer_.set_received_entropy_calculator(&entropy_calculator_);
+ server_framer_.set_visitor(&framer_visitor_);
+ }
+
+ ~QuicPacketCreatorTest() override {
+ delete[] serialized_packet_.encrypted_buffer;
+ ClearSerializedPacket(&serialized_packet_);
+ }
+
+ SerializedPacket SerializeAllFrames(const QuicFrames& frames) {
+ SerializedPacket packet = QuicPacketCreatorPeer::SerializeAllFrames(
+ &creator_, frames, buffer_, kMaxPacketSize);
+ EXPECT_EQ(QuicPacketCreatorPeer::GetEncryptionLevel(&creator_),
+ packet.encryption_level);
+ return packet;
+ }
+
+ void ProcessPacket(const SerializedPacket& packet) {
+ QuicEncryptedPacket encrypted_packet(packet.encrypted_buffer,
+ packet.encrypted_length);
+ server_framer_.ProcessPacket(encrypted_packet);
+ }
+
+ void CheckStreamFrame(const QuicFrame& frame,
+ QuicStreamId stream_id,
+ const string& data,
+ QuicStreamOffset offset,
+ bool fin) {
+ EXPECT_EQ(STREAM_FRAME, frame.type);
+ ASSERT_TRUE(frame.stream_frame);
+ EXPECT_EQ(stream_id, frame.stream_frame->stream_id);
+ EXPECT_EQ(data, StringPiece(frame.stream_frame->data_buffer,
+ frame.stream_frame->data_length));
+ EXPECT_EQ(offset, frame.stream_frame->offset);
+ EXPECT_EQ(fin, frame.stream_frame->fin);
+ }
+
+ // Returns the number of bytes consumed by the header of packet, including
+ // the version.
+ size_t GetPacketHeaderOverhead(QuicVersion version) {
+ return GetPacketHeaderSize(
+ version, creator_.connection_id_length(), kIncludeVersion,
+ !kIncludePathId, !kIncludeDiversificationNonce,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+ }
+
+ // Returns the number of bytes of overhead that will be added to a packet
+ // of maximum length.
+ size_t GetEncryptionOverhead() {
+ return creator_.max_packet_length() -
+ client_framer_.GetMaxPlaintextSize(creator_.max_packet_length());
+ }
+
+ // Returns the number of bytes consumed by the non-data fields of a stream
+ // frame, assuming it is the last frame in the packet
+ size_t GetStreamFrameOverhead() {
+ return QuicFramer::GetMinStreamFrameSize(kClientDataStreamId1, kOffset,
+ true);
+ }
+
+ QuicIOVector MakeIOVector(StringPiece s) {
+ return ::net::MakeIOVector(s, &iov_);
+ }
+
+ PendingRetransmission CreateRetransmission(
+ const QuicFrames& retransmittable_frames,
+ bool has_crypto_handshake,
+ int num_padding_bytes,
+ EncryptionLevel encryption_level,
+ QuicPacketNumberLength packet_number_length) {
+ return PendingRetransmission(1u, 1u, NOT_RETRANSMISSION,
+ retransmittable_frames, has_crypto_handshake,
+ num_padding_bytes, encryption_level,
+ packet_number_length);
+ }
+
+ static const QuicStreamOffset kOffset = 1u;
+
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+ char buffer_[kMaxPacketSize];
+ QuicFrames frames_;
+ QuicFramer server_framer_;
+ QuicFramer client_framer_;
+ StrictMock<MockFramerVisitor> framer_visitor_;
+ StrictMock<MockDelegate> delegate_;
+ QuicConnectionId connection_id_;
+ string data_;
+ struct iovec iov_;
+ MockRandom mock_random_;
+ SimpleBufferAllocator buffer_allocator_;
+ QuicPacketCreator creator_;
+ MockEntropyCalculator entropy_calculator_;
+ SerializedPacket serialized_packet_;
+};
+
+// Run all packet creator tests with all supported versions of QUIC, and with
+// and without version in the packet header, as well as doing a run for each
+// length of truncated connection id.
+INSTANTIATE_TEST_CASE_P(QuicPacketCreatorTests,
+ QuicPacketCreatorTest,
+ ::testing::ValuesIn(GetTestParams()));
+
+TEST_P(QuicPacketCreatorTest, SerializeFrames) {
+ for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; ++i) {
+ EncryptionLevel level = static_cast<EncryptionLevel>(i);
+ creator_.set_encryption_level(level);
+ frames_.push_back(QuicFrame(new QuicAckFrame(MakeAckFrame(0u))));
+ frames_.push_back(QuicFrame(
+ new QuicStreamFrame(kCryptoStreamId, false, 0u, StringPiece())));
+ frames_.push_back(QuicFrame(
+ new QuicStreamFrame(kCryptoStreamId, true, 0u, StringPiece())));
+ SerializedPacket serialized = SerializeAllFrames(frames_);
+ EXPECT_EQ(level, serialized.encryption_level);
+ delete frames_[0].ack_frame;
+ delete frames_[1].stream_frame;
+ delete frames_[2].stream_frame;
+ frames_.clear();
+
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+ EXPECT_CALL(framer_visitor_, OnAckFrame(_));
+ EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
+ EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
+ }
+ ProcessPacket(serialized);
+ }
+}
+
+TEST_P(QuicPacketCreatorTest, ReserializeFramesWithSequenceNumberLength) {
+ // If the original packet number length, the current packet number
+ // length, and the configured send packet number length are different, the
+ // retransmit must sent with the original length and the others do not change.
+ QuicPacketCreatorPeer::SetPacketNumberLength(&creator_,
+ PACKET_2BYTE_PACKET_NUMBER);
+ QuicStreamFrame* stream_frame =
+ new QuicStreamFrame(kCryptoStreamId, /*fin=*/false, 0u, StringPiece());
+ QuicFrames frames;
+ frames.push_back(QuicFrame(stream_frame));
+ char buffer[kMaxPacketSize];
+ PendingRetransmission retransmission(CreateRetransmission(
+ frames, true /* has_crypto_handshake */, -1 /* needs full padding */,
+ ENCRYPTION_NONE, PACKET_1BYTE_PACKET_NUMBER));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ creator_.ReserializeAllFrames(retransmission, buffer, kMaxPacketSize);
+ // The packet number length is updated after every packet is sent,
+ // so there is no need to restore the old length after sending.
+ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
+ serialized_packet_.packet_number_length);
+
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+ EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
+ }
+ ProcessPacket(serialized_packet_);
+ delete stream_frame;
+}
+
+TEST_P(QuicPacketCreatorTest, ReserializeCryptoFrameWithForwardSecurity) {
+ QuicStreamFrame* stream_frame =
+ new QuicStreamFrame(kCryptoStreamId, /*fin=*/false, 0u, StringPiece());
+ QuicFrames frames;
+ frames.push_back(QuicFrame(stream_frame));
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+ char buffer[kMaxPacketSize];
+ PendingRetransmission retransmission(CreateRetransmission(
+ frames, true /* has_crypto_handshake */, -1 /* needs full padding */,
+ ENCRYPTION_NONE,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ creator_.ReserializeAllFrames(retransmission, buffer, kMaxPacketSize);
+ EXPECT_EQ(ENCRYPTION_NONE, serialized_packet_.encryption_level);
+ delete stream_frame;
+}
+
+TEST_P(QuicPacketCreatorTest, ReserializeFrameWithForwardSecurity) {
+ QuicStreamFrame* stream_frame =
+ new QuicStreamFrame(0u, /*fin=*/false, 0u, StringPiece());
+ QuicFrames frames;
+ frames.push_back(QuicFrame(stream_frame));
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+ char buffer[kMaxPacketSize];
+ PendingRetransmission retransmission(CreateRetransmission(
+ frames, false /* has_crypto_handshake */, 0 /* no padding */,
+ ENCRYPTION_NONE,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ creator_.ReserializeAllFrames(retransmission, buffer, kMaxPacketSize);
+ EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, serialized_packet_.encryption_level);
+ delete stream_frame;
+}
+
+TEST_P(QuicPacketCreatorTest, ReserializeFramesWithFullPadding) {
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector("fake handshake message data"));
+ QuicPacketCreatorPeer::CreateStreamFrame(&creator_, kCryptoStreamId,
+ io_vector, 0u, 0u, false, &frame);
+ QuicFrames frames;
+ frames.push_back(frame);
+ char buffer[kMaxPacketSize];
+ PendingRetransmission retransmission(CreateRetransmission(
+ frames, true /* has_crypto_handshake */, -1 /* needs full padding */,
+ ENCRYPTION_NONE,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ creator_.ReserializeAllFrames(retransmission, buffer, kMaxPacketSize);
+ EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_.encrypted_length);
+ delete frame.stream_frame;
+}
+
+TEST_P(QuicPacketCreatorTest, ReserializeFramesWithSpecifiedPadding) {
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector("fake message data"));
+ QuicPacketCreatorPeer::CreateStreamFrame(&creator_, kCryptoStreamId,
+ io_vector, 0u, 0u, false, &frame);
+
+ const int kNumPaddingBytes1 = 4;
+ int packet_size = 0;
+ {
+ QuicFrames frames;
+ frames.push_back(frame);
+ char buffer[kMaxPacketSize];
+ PendingRetransmission retransmission(CreateRetransmission(
+ frames, false /* has_crypto_handshake */,
+ kNumPaddingBytes1 /* padding bytes */, ENCRYPTION_NONE,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ creator_.ReserializeAllFrames(retransmission, buffer, kMaxPacketSize);
+ packet_size = serialized_packet_.encrypted_length;
+ }
+
+ const int kNumPaddingBytes2 = 44;
+ QuicFrames frames;
+ frames.push_back(frame);
+ char buffer[kMaxPacketSize];
+ PendingRetransmission retransmission(CreateRetransmission(
+ frames, false /* has_crypto_handshake */,
+ kNumPaddingBytes2 /* padding bytes */, ENCRYPTION_NONE,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ creator_.ReserializeAllFrames(retransmission, buffer, kMaxPacketSize);
+
+ EXPECT_EQ(packet_size + kNumPaddingBytes2 - kNumPaddingBytes1,
+ serialized_packet_.encrypted_length);
+ delete frame.stream_frame;
+}
+
+TEST_P(QuicPacketCreatorTest, ReserializeFramesWithFullPacketAndPadding) {
+ const size_t overhead = GetPacketHeaderOverhead(client_framer_.version()) +
+ GetEncryptionOverhead() + GetStreamFrameOverhead();
+ size_t capacity = kDefaultMaxPacketSize - overhead;
+ for (int delta = -5; delta <= 0; ++delta) {
+ string data(capacity + delta, 'A');
+ size_t bytes_free = 0 - delta;
+
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector(data));
+ QuicPacketCreatorPeer::CreateStreamFrame(
+ &creator_, kCryptoStreamId, io_vector, 0, kOffset, false, &frame);
+ QuicFrames frames;
+ frames.push_back(frame);
+ char buffer[kMaxPacketSize];
+ PendingRetransmission retransmission(CreateRetransmission(
+ frames, true /* has_crypto_handshake */, -1 /* needs full padding */,
+ ENCRYPTION_NONE,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ creator_.ReserializeAllFrames(retransmission, buffer, kMaxPacketSize);
+
+ // If there is not enough space in the packet to fit a padding frame
+ // (1 byte) and to expand the stream frame (another 2 bytes) the packet
+ // will not be padded.
+ if (bytes_free < 3) {
+ EXPECT_EQ(kDefaultMaxPacketSize - bytes_free,
+ serialized_packet_.encrypted_length);
+ } else {
+ EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_.encrypted_length);
+ }
+
+ delete frame.stream_frame;
+ frames_.clear();
+ }
+}
+
+TEST_P(QuicPacketCreatorTest, SerializeConnectionClose) {
+ QuicConnectionCloseFrame frame;
+ frame.error_code = QUIC_NO_ERROR;
+ frame.error_details = "error";
+
+ QuicFrames frames;
+ frames.push_back(QuicFrame(&frame));
+ SerializedPacket serialized = SerializeAllFrames(frames);
+ EXPECT_EQ(ENCRYPTION_NONE, serialized.encryption_level);
+ ASSERT_EQ(1u, serialized.packet_number);
+ ASSERT_EQ(1u, creator_.packet_number());
+
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+ EXPECT_CALL(framer_visitor_, OnConnectionCloseFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
+
+ ProcessPacket(serialized);
+}
+
+TEST_P(QuicPacketCreatorTest, ConsumeData) {
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector("test"));
+ ASSERT_TRUE(creator_.ConsumeData(kCryptoStreamId, io_vector, 0u, 0u, false,
+ false, &frame));
+ ASSERT_TRUE(frame.stream_frame);
+ size_t consumed = frame.stream_frame->data_length;
+ EXPECT_EQ(4u, consumed);
+ CheckStreamFrame(frame, 1u, "test", 0u, false);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+}
+
+TEST_P(QuicPacketCreatorTest, ConsumeDataFin) {
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector("test"));
+ ASSERT_TRUE(creator_.ConsumeData(kCryptoStreamId, io_vector, 0u, 10u, true,
+ false, &frame));
+ ASSERT_TRUE(frame.stream_frame);
+ size_t consumed = frame.stream_frame->data_length;
+ EXPECT_EQ(4u, consumed);
+ CheckStreamFrame(frame, 1u, "test", 10u, true);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+}
+
+TEST_P(QuicPacketCreatorTest, ConsumeDataFinOnly) {
+ QuicFrame frame;
+ QuicIOVector io_vector(nullptr, 0, 0);
+ ASSERT_TRUE(creator_.ConsumeData(kCryptoStreamId, io_vector, 0u, 0u, true,
+ false, &frame));
+ ASSERT_TRUE(frame.stream_frame);
+ size_t consumed = frame.stream_frame->data_length;
+ EXPECT_EQ(0u, consumed);
+ CheckStreamFrame(frame, 1u, string(), 0u, true);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+}
+
+TEST_P(QuicPacketCreatorTest, CreateAllFreeBytesForStreamFrames) {
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+ const size_t overhead = GetPacketHeaderOverhead(client_framer_.version()) +
+ GetEncryptionOverhead();
+ for (size_t i = overhead; i < overhead + 100; ++i) {
+ creator_.SetMaxPacketLength(i);
+ const bool should_have_room = i > overhead + GetStreamFrameOverhead();
+ ASSERT_EQ(should_have_room,
+ creator_.HasRoomForStreamFrame(kClientDataStreamId1, kOffset));
+ if (should_have_room) {
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector("testdata"));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillRepeatedly(
+ Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket));
+ ASSERT_TRUE(creator_.ConsumeData(kClientDataStreamId1, io_vector, 0u,
+ kOffset, false, false, &frame));
+ ASSERT_TRUE(frame.stream_frame);
+ size_t bytes_consumed = frame.stream_frame->data_length;
+ EXPECT_LT(0u, bytes_consumed);
+ creator_.Flush();
+ }
+ }
+}
+
+TEST_P(QuicPacketCreatorTest, StreamFrameConsumption) {
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+ // Compute the total overhead for a single frame in packet.
+ const size_t overhead = GetPacketHeaderOverhead(client_framer_.version()) +
+ GetEncryptionOverhead() + GetStreamFrameOverhead();
+ size_t capacity = kDefaultMaxPacketSize - overhead;
+ // Now, test various sizes around this size.
+ for (int delta = -5; delta <= 5; ++delta) {
+ string data(capacity + delta, 'A');
+ size_t bytes_free = delta > 0 ? 0 : 0 - delta;
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector(data));
+ ASSERT_TRUE(creator_.ConsumeData(kClientDataStreamId1, io_vector, 0u,
+ kOffset, false, false, &frame));
+ ASSERT_TRUE(frame.stream_frame);
+
+ // BytesFree() returns bytes available for the next frame, which will
+ // be two bytes smaller since the stream frame would need to be grown.
+ EXPECT_EQ(2u, creator_.ExpansionOnNewFrame());
+ size_t expected_bytes_free = bytes_free < 3 ? 0 : bytes_free - 2;
+ EXPECT_EQ(expected_bytes_free, creator_.BytesFree()) << "delta: " << delta;
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ creator_.Flush();
+ ASSERT_TRUE(serialized_packet_.encrypted_buffer);
+ DeleteSerializedPacket();
+ }
+}
+
+TEST_P(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) {
+ // Compute the total overhead for a single frame in packet.
+ const size_t overhead = GetPacketHeaderOverhead(client_framer_.version()) +
+ GetEncryptionOverhead() + GetStreamFrameOverhead();
+ ASSERT_GT(kMaxPacketSize, overhead);
+ size_t capacity = kDefaultMaxPacketSize - overhead;
+ // Now, test various sizes around this size.
+ for (int delta = -5; delta <= 5; ++delta) {
+ string data(capacity + delta, 'A');
+ size_t bytes_free = delta > 0 ? 0 : 0 - delta;
+
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector(data));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillRepeatedly(
+ Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ ASSERT_TRUE(creator_.ConsumeData(kCryptoStreamId, io_vector, 0u, kOffset,
+ false, true, &frame));
+ ASSERT_TRUE(frame.stream_frame);
+ size_t bytes_consumed = frame.stream_frame->data_length;
+ EXPECT_LT(0u, bytes_consumed);
+ creator_.Flush();
+ ASSERT_TRUE(serialized_packet_.encrypted_buffer);
+ // If there is not enough space in the packet to fit a padding frame
+ // (1 byte) and to expand the stream frame (another 2 bytes) the packet
+ // will not be padded.
+ if (bytes_free < 3) {
+ EXPECT_EQ(kDefaultMaxPacketSize - bytes_free,
+ serialized_packet_.encrypted_length);
+ } else {
+ EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_.encrypted_length);
+ }
+ DeleteSerializedPacket();
+ }
+}
+
+TEST_P(QuicPacketCreatorTest, NonCryptoStreamFramePacketNonPadding) {
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+ // Compute the total overhead for a single frame in packet.
+ const size_t overhead = GetPacketHeaderOverhead(client_framer_.version()) +
+ GetEncryptionOverhead() + GetStreamFrameOverhead();
+ ASSERT_GT(kDefaultMaxPacketSize, overhead);
+ size_t capacity = kDefaultMaxPacketSize - overhead;
+ // Now, test various sizes around this size.
+ for (int delta = -5; delta <= 5; ++delta) {
+ string data(capacity + delta, 'A');
+ size_t bytes_free = delta > 0 ? 0 : 0 - delta;
+
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector(data));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ ASSERT_TRUE(creator_.ConsumeData(kClientDataStreamId1, io_vector, 0u,
+ kOffset, false, false, &frame));
+ ASSERT_TRUE(frame.stream_frame);
+ size_t bytes_consumed = frame.stream_frame->data_length;
+ EXPECT_LT(0u, bytes_consumed);
+ creator_.Flush();
+ ASSERT_TRUE(serialized_packet_.encrypted_buffer);
+ if (bytes_free > 0) {
+ EXPECT_EQ(kDefaultMaxPacketSize - bytes_free,
+ serialized_packet_.encrypted_length);
+ } else {
+ EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_.encrypted_length);
+ }
+ DeleteSerializedPacket();
+ }
+}
+
+TEST_P(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) {
+ QuicFramerPeer::SetPerspective(&client_framer_, Perspective::IS_SERVER);
+ QuicVersionVector versions;
+ versions.push_back(test::QuicVersionMax());
+ std::unique_ptr<QuicEncryptedPacket> encrypted(
+ creator_.SerializeVersionNegotiationPacket(versions));
+
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnVersionNegotiationPacket(_));
+ }
+ QuicFramerPeer::SetPerspective(&client_framer_, Perspective::IS_CLIENT);
+ client_framer_.ProcessPacket(*encrypted);
+}
+
+TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthLeastAwaiting) {
+ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+
+ QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64);
+ creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
+ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+
+ QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64 * 256);
+ creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
+ EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+
+ QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64 * 256 * 256);
+ creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
+ EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+
+ QuicPacketCreatorPeer::SetPacketNumber(&creator_,
+ UINT64_C(64) * 256 * 256 * 256 * 256);
+ creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
+ EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+}
+
+TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthCwnd) {
+ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+
+ creator_.UpdatePacketNumberLength(1, 10000 / kDefaultMaxPacketSize);
+ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+
+ creator_.UpdatePacketNumberLength(1, 10000 * 256 / kDefaultMaxPacketSize);
+ EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+
+ creator_.UpdatePacketNumberLength(1,
+ 10000 * 256 * 256 / kDefaultMaxPacketSize);
+ EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+
+ creator_.UpdatePacketNumberLength(
+ 1, UINT64_C(1000) * 256 * 256 * 256 * 256 / kDefaultMaxPacketSize);
+ EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+}
+
+TEST_P(QuicPacketCreatorTest, SerializeFrame) {
+ if (!GetParam().version_serialization) {
+ creator_.StopSendingVersion();
+ }
+ frames_.push_back(QuicFrame(
+ new QuicStreamFrame(kCryptoStreamId, false, 0u, StringPiece())));
+ SerializedPacket serialized = SerializeAllFrames(frames_);
+ delete frames_[0].stream_frame;
+
+ QuicPacketHeader header;
+ {
+ InSequence s;
+ EXPECT_CALL(framer_visitor_, OnPacket());
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
+ EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
+ EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
+ EXPECT_CALL(framer_visitor_, OnPacketHeader(_))
+ .WillOnce(DoAll(SaveArg<0>(&header), Return(true)));
+ EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
+ EXPECT_CALL(framer_visitor_, OnPacketComplete());
+ }
+ ProcessPacket(serialized);
+ EXPECT_EQ(GetParam().version_serialization,
+ header.public_header.version_flag);
+}
+
+TEST_P(QuicPacketCreatorTest, ConsumeDataLargerThanOneStreamFrame) {
+ if (!GetParam().version_serialization) {
+ creator_.StopSendingVersion();
+ }
+ // A string larger than fits into a frame.
+ size_t payload_length;
+ creator_.SetMaxPacketLength(GetPacketLengthForOneStream(
+ client_framer_.version(),
+ QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
+ QuicPacketCreatorPeer::SendPathIdInPacket(&creator_),
+ !kIncludeDiversificationNonce, creator_.connection_id_length(),
+ PACKET_1BYTE_PACKET_NUMBER, &payload_length));
+ QuicFrame frame;
+ const string too_long_payload(payload_length * 2, 'a');
+ QuicIOVector io_vector(MakeIOVector(too_long_payload));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ ASSERT_TRUE(creator_.ConsumeData(kCryptoStreamId, io_vector, 0u, 0u, true,
+ false, &frame));
+ ASSERT_TRUE(frame.stream_frame);
+ size_t consumed = frame.stream_frame->data_length;
+ EXPECT_EQ(payload_length, consumed);
+ const string payload(payload_length, 'a');
+ CheckStreamFrame(frame, 1u, payload, 0u, false);
+ creator_.Flush();
+ DeleteSerializedPacket();
+}
+
+TEST_P(QuicPacketCreatorTest, AddFrameAndFlush) {
+ if (!GetParam().version_serialization) {
+ creator_.StopSendingVersion();
+ }
+ const size_t max_plaintext_size =
+ client_framer_.GetMaxPlaintextSize(creator_.max_packet_length());
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_EQ(max_plaintext_size -
+ GetPacketHeaderSize(
+ client_framer_.version(), creator_.connection_id_length(),
+ QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
+ QuicPacketCreatorPeer::SendPathIdInPacket(&creator_),
+ !kIncludeDiversificationNonce, PACKET_1BYTE_PACKET_NUMBER),
+ creator_.BytesFree());
+
+ // Add a variety of frame types and then a padding frame.
+ QuicAckFrame ack_frame(MakeAckFrame(0u));
+ EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&ack_frame)));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector("test"));
+ ASSERT_TRUE(creator_.ConsumeData(kCryptoStreamId, io_vector, 0u, 0u, false,
+ false, &frame));
+ ASSERT_TRUE(frame.stream_frame);
+ size_t consumed = frame.stream_frame->data_length;
+ EXPECT_EQ(4u, consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+
+ QuicPaddingFrame padding_frame;
+ EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(padding_frame)));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_EQ(0u, creator_.BytesFree());
+
+ // Packet is full. Creator will flush.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ EXPECT_FALSE(creator_.AddSavedFrame(QuicFrame(&ack_frame)));
+
+ // Ensure the packet is successfully created.
+ ASSERT_TRUE(serialized_packet_.encrypted_buffer);
+ ASSERT_FALSE(serialized_packet_.retransmittable_frames.empty());
+ const QuicFrames& retransmittable = serialized_packet_.retransmittable_frames;
+ ASSERT_EQ(1u, retransmittable.size());
+ EXPECT_EQ(STREAM_FRAME, retransmittable[0].type);
+ ASSERT_TRUE(retransmittable[0].stream_frame);
+ DeleteSerializedPacket();
+
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_EQ(max_plaintext_size -
+ GetPacketHeaderSize(
+ client_framer_.version(), creator_.connection_id_length(),
+ QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
+ /*include_path_id=*/false, !kIncludeDiversificationNonce,
+ PACKET_1BYTE_PACKET_NUMBER),
+ creator_.BytesFree());
+}
+
+TEST_P(QuicPacketCreatorTest, SerializeAndSendStreamFrame) {
+ if (!GetParam().version_serialization) {
+ creator_.StopSendingVersion();
+ }
+ EXPECT_FALSE(creator_.HasPendingFrames());
+
+ QuicIOVector iov(MakeIOVector("test"));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ size_t num_bytes_consumed;
+ creator_.CreateAndSerializeStreamFrame(kHeadersStreamId, iov, 0, 0, true,
+ nullptr, &num_bytes_consumed);
+ EXPECT_EQ(static_cast<size_t>(4), num_bytes_consumed);
+
+ // Ensure the packet is successfully created.
+ ASSERT_TRUE(serialized_packet_.encrypted_buffer);
+ ASSERT_FALSE(serialized_packet_.retransmittable_frames.empty());
+ const QuicFrames& retransmittable = serialized_packet_.retransmittable_frames;
+ ASSERT_EQ(1u, retransmittable.size());
+ EXPECT_EQ(STREAM_FRAME, retransmittable[0].type);
+ ASSERT_TRUE(retransmittable[0].stream_frame);
+ DeleteSerializedPacket();
+
+ EXPECT_FALSE(creator_.HasPendingFrames());
+}
+
+TEST_P(QuicPacketCreatorTest, SerializeTruncatedAckFrameWithLargePacketSize) {
+ creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+ if (!GetParam().version_serialization) {
+ creator_.StopSendingVersion();
+ }
+ creator_.SetMaxPacketLength(kMaxPacketSize);
+
+ // Serialized length of ack frame with 2000 nack ranges should be limited by
+ // the number of nack ranges that can be fit in an ack frame.
+ QuicAckFrame ack_frame = MakeAckFrameWithNackRanges(2000u, 0u);
+ size_t frame_len = client_framer_.GetSerializedFrameLength(
+ QuicFrame(&ack_frame), creator_.BytesFree(), true, true,
+ PACKET_1BYTE_PACKET_NUMBER);
+ EXPECT_GT(creator_.BytesFree(), frame_len);
+ EXPECT_GT(creator_.max_packet_length(), creator_.PacketSize());
+
+ // Add ack frame to creator.
+ EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&ack_frame)));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_GT(creator_.max_packet_length(), creator_.PacketSize());
+ EXPECT_LT(0u, creator_.BytesFree());
+
+ // Make sure that an additional stream frame can be added to the packet.
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector("test"));
+ ASSERT_TRUE(
+ creator_.ConsumeData(2u, io_vector, 0u, 0u, false, false, &frame));
+ ASSERT_TRUE(frame.stream_frame);
+ size_t consumed = frame.stream_frame->data_length;
+ EXPECT_EQ(4u, consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+
+ // Ensure the packet is successfully created, and the packet size estimate
+ // matches the serialized packet length.
+ if (GetParam().version <= QUIC_VERSION_33) {
+ EXPECT_CALL(entropy_calculator_, EntropyHash(_))
+ .WillOnce(testing::Return(0));
+ }
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ size_t est_packet_size = creator_.PacketSize();
+ creator_.Flush();
+ ASSERT_TRUE(serialized_packet_.encrypted_buffer);
+ EXPECT_EQ(est_packet_size, client_framer_.GetMaxPlaintextSize(
+ serialized_packet_.encrypted_length));
+ DeleteSerializedPacket();
+}
+
+TEST_P(QuicPacketCreatorTest, SerializeTruncatedAckFrameWithSmallPacketSize) {
+ if (!GetParam().version_serialization) {
+ creator_.StopSendingVersion();
+ }
+ creator_.SetMaxPacketLength(500u);
+
+ const size_t max_plaintext_size =
+ client_framer_.GetMaxPlaintextSize(creator_.max_packet_length());
+ EXPECT_EQ(max_plaintext_size - creator_.PacketSize(), creator_.BytesFree());
+
+ // Serialized length of ack frame with 2000 nack ranges should be limited by
+ // the packet size.
+ QuicAckFrame ack_frame = MakeAckFrameWithNackRanges(2000u, 0u);
+ size_t frame_len = client_framer_.GetSerializedFrameLength(
+ QuicFrame(&ack_frame), creator_.BytesFree(), true, true,
+ PACKET_1BYTE_PACKET_NUMBER);
+ EXPECT_EQ(creator_.BytesFree(), frame_len);
+
+ // Add ack frame to creator.
+ EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&ack_frame)));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_EQ(client_framer_.GetMaxPlaintextSize(creator_.max_packet_length()),
+ creator_.PacketSize());
+ EXPECT_EQ(0u, creator_.BytesFree());
+
+ // Ensure the packet is successfully created, and the packet size estimate
+ // may not match the serialized packet length.
+ if (GetParam().version <= QUIC_VERSION_33) {
+ EXPECT_CALL(entropy_calculator_, EntropyHash(_)).WillOnce(Return(0));
+ }
+ size_t est_packet_size = creator_.PacketSize();
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ creator_.Flush();
+ ASSERT_TRUE(serialized_packet_.encrypted_buffer);
+ EXPECT_GE(est_packet_size, client_framer_.GetMaxPlaintextSize(
+ serialized_packet_.encrypted_length));
+ DeleteSerializedPacket();
+}
+
+TEST_P(QuicPacketCreatorTest, EntropyFlag) {
+ frames_.push_back(QuicFrame(
+ new QuicStreamFrame(kCryptoStreamId, false, 0u, StringPiece())));
+
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 64; ++j) {
+ SerializedPacket serialized = SerializeAllFrames(frames_);
+ // Verify both BoolSource and hash algorithm.
+ bool expected_rand_bool =
+ (mock_random_.RandUint64() & (UINT64_C(1) << j)) != 0;
+ bool observed_rand_bool =
+ (serialized.entropy_hash & (1 << ((j + 1) % 8))) != 0;
+ uint8_t rest_of_hash = serialized.entropy_hash & ~(1 << ((j + 1) % 8));
+ EXPECT_EQ(expected_rand_bool, observed_rand_bool);
+ EXPECT_EQ(0, rest_of_hash);
+ }
+ // After 64 calls, BoolSource will refresh the bucket - make sure it does.
+ mock_random_.ChangeValue();
+ }
+
+ delete frames_[0].stream_frame;
+}
+
+TEST_P(QuicPacketCreatorTest, SetCurrentPath) {
+ // Current path is the default path.
+ EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(&creator_));
+ EXPECT_EQ(0u, creator_.packet_number());
+ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+ // Add a stream frame to the creator.
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector("test"));
+ ASSERT_TRUE(creator_.ConsumeData(kCryptoStreamId, io_vector, 0u, 0u, false,
+ false, &frame));
+ ASSERT_TRUE(frame.stream_frame);
+ size_t consumed = frame.stream_frame->data_length;
+ EXPECT_EQ(4u, consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_EQ(0u, creator_.packet_number());
+
+ // Change current path.
+ QuicPathId kPathId1 = 1;
+ EXPECT_QUIC_BUG(creator_.SetCurrentPath(kPathId1, 1, 0),
+ "Unable to change paths when a packet is under construction");
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .Times(1)
+ .WillRepeatedly(
+ Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket));
+ creator_.Flush();
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ creator_.SetCurrentPath(kPathId1, 1, 0);
+ EXPECT_EQ(kPathId1, QuicPacketCreatorPeer::GetCurrentPath(&creator_));
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_EQ(0u, creator_.packet_number());
+ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+
+ // Change current path back.
+ creator_.SetCurrentPath(kDefaultPathId, 2, 1);
+ EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(&creator_));
+ EXPECT_EQ(1u, creator_.packet_number());
+ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+ // Add a stream frame to the creator.
+ ASSERT_TRUE(creator_.ConsumeData(kCryptoStreamId, io_vector, 0u, 0u, false,
+ false, &frame));
+ ASSERT_TRUE(frame.stream_frame);
+ consumed = frame.stream_frame->data_length;
+ EXPECT_EQ(4u, consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+
+ // Does not change current path.
+ creator_.SetCurrentPath(kDefaultPathId, 2, 0);
+ EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(&creator_));
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_EQ(1u, creator_.packet_number());
+ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+}
+
+TEST_P(QuicPacketCreatorTest, SerializePacketOnDifferentPath) {
+ // Current path is the default path.
+ EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(&creator_));
+ EXPECT_EQ(0u, creator_.packet_number());
+ // Add a stream frame to the creator and flush the packet.
+ QuicFrame frame;
+ QuicIOVector io_vector(MakeIOVector("test"));
+ ASSERT_TRUE(creator_.ConsumeData(kCryptoStreamId, io_vector, 0u, 0u, false,
+ false, &frame));
+ ASSERT_TRUE(frame.stream_frame);
+ size_t consumed = frame.stream_frame->data_length;
+ EXPECT_EQ(4u, consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ EXPECT_EQ(0u, creator_.packet_number());
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillRepeatedly(
+ Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
+ creator_.Flush();
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_EQ(1u, creator_.packet_number());
+ // Verify serialized data packet's path id.
+ EXPECT_EQ(kDefaultPathId, serialized_packet_.path_id);
+ DeleteSerializedPacket();
+
+ // Change to path 1.
+ QuicPathId kPathId1 = 1;
+ creator_.SetCurrentPath(kPathId1, 1, 0);
+ EXPECT_EQ(kPathId1, QuicPacketCreatorPeer::GetCurrentPath(&creator_));
+ EXPECT_FALSE(creator_.HasPendingFrames());
+ EXPECT_EQ(0u, creator_.packet_number());
+ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
+ QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
+
+ // Add a stream frame to the creator and flush the packet.
+ ASSERT_TRUE(creator_.ConsumeData(kCryptoStreamId, io_vector, 0u, 0u, false,
+ false, &frame));
+ ASSERT_TRUE(frame.stream_frame);
+ consumed = frame.stream_frame->data_length;
+ EXPECT_EQ(4u, consumed);
+ EXPECT_TRUE(creator_.HasPendingFrames());
+ creator_.Flush();
+ // Verify serialized data packet's path id.
+ EXPECT_EQ(kPathId1, serialized_packet_.path_id);
+ DeleteSerializedPacket();
+}
+
+TEST_P(QuicPacketCreatorTest, AddUnencryptedStreamDataClosesConnection) {
+ creator_.set_encryption_level(ENCRYPTION_NONE);
+ EXPECT_CALL(delegate_, OnUnrecoverableError(_, _, _));
+ QuicStreamFrame stream_frame(kHeadersStreamId, /*fin=*/false, 0u,
+ StringPiece());
+ EXPECT_QUIC_BUG(creator_.AddSavedFrame(QuicFrame(&stream_frame)),
+ "Cannot send stream data without encryption.");
+}
+
+TEST_P(QuicPacketCreatorTest, ChloTooLarge) {
+ CryptoHandshakeMessage message;
+ message.set_tag(kCHLO);
+ message.set_minimum_size(kMaxPacketSize);
+ CryptoFramer framer;
+ std::unique_ptr<QuicData> message_data;
+ message_data.reset(framer.ConstructHandshakeMessage(message));
+
+ struct iovec iov;
+ QuicIOVector data_iovec(::net::MakeIOVector(
+ StringPiece(message_data->data(), message_data->length()), &iov));
+ QuicFrame frame;
+ EXPECT_CALL(delegate_,
+ OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, _, _));
+ EXPECT_QUIC_BUG(creator_.ConsumeData(kCryptoStreamId, data_iovec, 0u, 0u,
+ false, false, &frame),
+ "Client hello won't fit in a single packet.");
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_packet_generator.cc b/chromium/net/quic/core/quic_packet_generator.cc
new file mode 100644
index 00000000000..cb66f1d249d
--- /dev/null
+++ b/chromium/net/quic/core/quic_packet_generator.cc
@@ -0,0 +1,347 @@
+// 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/quic_packet_generator.h"
+
+#include "base/logging.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+
+using base::StringPiece;
+
+namespace net {
+
+QuicPacketGenerator::QuicPacketGenerator(QuicConnectionId connection_id,
+ QuicFramer* framer,
+ QuicRandom* random_generator,
+ QuicBufferAllocator* buffer_allocator,
+ DelegateInterface* delegate)
+ : delegate_(delegate),
+ packet_creator_(connection_id,
+ framer,
+ random_generator,
+ buffer_allocator,
+ delegate),
+ batch_mode_(false),
+ should_send_ack_(false),
+ should_send_stop_waiting_(false) {}
+
+QuicPacketGenerator::~QuicPacketGenerator() {
+ QuicUtils::DeleteFrames(&queued_control_frames_);
+}
+
+void QuicPacketGenerator::SetShouldSendAck(bool also_send_stop_waiting) {
+ if (packet_creator_.has_ack()) {
+ // Ack already queued, nothing to do.
+ return;
+ }
+
+ if (also_send_stop_waiting && packet_creator_.has_stop_waiting()) {
+ QUIC_BUG << "Should only ever be one pending stop waiting frame.";
+ return;
+ }
+
+ should_send_ack_ = true;
+ should_send_stop_waiting_ = also_send_stop_waiting;
+ SendQueuedFrames(/*flush=*/false);
+}
+
+void QuicPacketGenerator::AddControlFrame(const QuicFrame& frame) {
+ queued_control_frames_.push_back(frame);
+ SendQueuedFrames(/*flush=*/false);
+}
+
+QuicConsumedData QuicPacketGenerator::ConsumeData(
+ QuicStreamId id,
+ QuicIOVector iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* listener) {
+ bool has_handshake = (id == kCryptoStreamId);
+ QUIC_BUG_IF(has_handshake && fin)
+ << "Handshake packets should never send a fin";
+ // To make reasoning about crypto frames easier, we don't combine them with
+ // other retransmittable frames in a single packet.
+ const bool flush =
+ has_handshake && packet_creator_.HasPendingRetransmittableFrames();
+ SendQueuedFrames(flush);
+
+ size_t total_bytes_consumed = 0;
+ bool fin_consumed = false;
+
+ if (!packet_creator_.HasRoomForStreamFrame(id, offset)) {
+ packet_creator_.Flush();
+ }
+
+ if (!fin && (iov.total_length == 0)) {
+ QUIC_BUG << "Attempt to consume empty data without FIN.";
+ return QuicConsumedData(0, false);
+ }
+
+ while (delegate_->ShouldGeneratePacket(
+ HAS_RETRANSMITTABLE_DATA, has_handshake ? IS_HANDSHAKE : NOT_HANDSHAKE)) {
+ QuicFrame frame;
+ if (!packet_creator_.ConsumeData(id, iov, total_bytes_consumed,
+ offset + total_bytes_consumed, fin,
+ has_handshake, &frame)) {
+ // The creator is always flushed if there's not enough room for a new
+ // stream frame before ConsumeData, so ConsumeData should always succeed.
+ QUIC_BUG << "Failed to ConsumeData, stream:" << id;
+ return QuicConsumedData(0, false);
+ }
+
+ // A stream frame is created and added.
+ size_t bytes_consumed = frame.stream_frame->data_length;
+ if (listener != nullptr) {
+ packet_creator_.AddAckListener(listener, bytes_consumed);
+ }
+ total_bytes_consumed += bytes_consumed;
+ fin_consumed = fin && total_bytes_consumed == iov.total_length;
+ DCHECK(total_bytes_consumed == iov.total_length ||
+ (bytes_consumed > 0 && packet_creator_.HasPendingFrames()));
+
+ if (!InBatchMode()) {
+ packet_creator_.Flush();
+ }
+
+ if (total_bytes_consumed == iov.total_length) {
+ // We're done writing the data. Exit the loop.
+ // We don't make this a precondition because we could have 0 bytes of data
+ // if we're simply writing a fin.
+ break;
+ }
+ // TODO(ianswett): Move to having the creator flush itself when it's full.
+ packet_creator_.Flush();
+ }
+
+ // Don't allow the handshake to be bundled with other retransmittable frames.
+ if (has_handshake) {
+ SendQueuedFrames(/*flush=*/true);
+ }
+
+ DCHECK(InBatchMode() || !packet_creator_.HasPendingFrames());
+ return QuicConsumedData(total_bytes_consumed, fin_consumed);
+}
+
+QuicConsumedData QuicPacketGenerator::ConsumeDataFastPath(
+ QuicStreamId id,
+ const QuicIOVector& iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* listener) {
+ DCHECK_NE(id, kCryptoStreamId);
+ size_t total_bytes_consumed = 0;
+ while (total_bytes_consumed < iov.total_length &&
+ delegate_->ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA,
+ NOT_HANDSHAKE)) {
+ // Serialize and encrypt the packet.
+ size_t bytes_consumed = 0;
+ packet_creator_.CreateAndSerializeStreamFrame(
+ id, iov, total_bytes_consumed, offset + total_bytes_consumed, fin,
+ listener, &bytes_consumed);
+ total_bytes_consumed += bytes_consumed;
+ }
+
+ return QuicConsumedData(total_bytes_consumed,
+ fin && (total_bytes_consumed == iov.total_length));
+}
+
+void QuicPacketGenerator::GenerateMtuDiscoveryPacket(
+ QuicByteCount target_mtu,
+ QuicAckListenerInterface* listener) {
+ // MTU discovery frames must be sent by themselves.
+ if (!packet_creator_.CanSetMaxPacketLength()) {
+ QUIC_BUG << "MTU discovery packets should only be sent when no other "
+ << "frames needs to be sent.";
+ return;
+ }
+ const QuicByteCount current_mtu = GetCurrentMaxPacketLength();
+
+ // The MTU discovery frame is allocated on the stack, since it is going to be
+ // serialized within this function.
+ QuicMtuDiscoveryFrame mtu_discovery_frame;
+ QuicFrame frame(mtu_discovery_frame);
+
+ // Send the probe packet with the new length.
+ SetMaxPacketLength(target_mtu);
+ const bool success = packet_creator_.AddPaddedSavedFrame(frame);
+ if (listener != nullptr) {
+ packet_creator_.AddAckListener(listener, 0);
+ }
+ packet_creator_.Flush();
+ // The only reason AddFrame can fail is that the packet is too full to fit in
+ // a ping. This is not possible for any sane MTU.
+ DCHECK(success);
+
+ // Reset the packet length back.
+ SetMaxPacketLength(current_mtu);
+}
+
+bool QuicPacketGenerator::CanSendWithNextPendingFrameAddition() const {
+ DCHECK(HasPendingFrames());
+ HasRetransmittableData retransmittable =
+ (should_send_ack_ || should_send_stop_waiting_)
+ ? NO_RETRANSMITTABLE_DATA
+ : HAS_RETRANSMITTABLE_DATA;
+ if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
+ DCHECK(!queued_control_frames_.empty()); // These are retransmittable.
+ }
+ return delegate_->ShouldGeneratePacket(retransmittable, NOT_HANDSHAKE);
+}
+
+void QuicPacketGenerator::SendQueuedFrames(bool flush) {
+ // Only add pending frames if we are SURE we can then send the whole packet.
+ while (HasPendingFrames() &&
+ (flush || CanSendWithNextPendingFrameAddition())) {
+ if (FLAGS_quic_close_connection_on_huge_frames) {
+ bool first_frame = packet_creator_.CanSetMaxPacketLength();
+ if (!AddNextPendingFrame() && first_frame) {
+ // A single frame cannot fit into the packet, tear down the connection.
+ QUIC_BUG << "A single frame cannot fit into packet."
+ << " should_send_ack: " << should_send_ack_
+ << " should_send_stop_waiting: " << should_send_stop_waiting_
+ << " number of queued_control_frames: "
+ << queued_control_frames_.size();
+ if (!queued_control_frames_.empty()) {
+ DVLOG(1) << queued_control_frames_[0];
+ }
+ delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET,
+ "Single frame cannot fit into a packet",
+ ConnectionCloseSource::FROM_SELF);
+ return;
+ }
+ } else {
+ AddNextPendingFrame();
+ }
+ }
+ if (flush || !InBatchMode()) {
+ packet_creator_.Flush();
+ }
+}
+
+bool QuicPacketGenerator::InBatchMode() {
+ return batch_mode_;
+}
+
+void QuicPacketGenerator::StartBatchOperations() {
+ batch_mode_ = true;
+}
+
+void QuicPacketGenerator::FinishBatchOperations() {
+ batch_mode_ = false;
+ SendQueuedFrames(/*flush=*/false);
+}
+
+void QuicPacketGenerator::FlushAllQueuedFrames() {
+ SendQueuedFrames(/*flush=*/true);
+}
+
+bool QuicPacketGenerator::HasQueuedFrames() const {
+ return packet_creator_.HasPendingFrames() || HasPendingFrames();
+}
+
+bool QuicPacketGenerator::IsPendingPacketEmpty() const {
+ return !packet_creator_.HasPendingFrames();
+}
+
+bool QuicPacketGenerator::HasPendingFrames() const {
+ return should_send_ack_ || should_send_stop_waiting_ ||
+ !queued_control_frames_.empty();
+}
+
+bool QuicPacketGenerator::AddNextPendingFrame() {
+ if (should_send_ack_) {
+ should_send_ack_ =
+ !packet_creator_.AddSavedFrame(delegate_->GetUpdatedAckFrame());
+ return !should_send_ack_;
+ }
+
+ if (should_send_stop_waiting_) {
+ delegate_->PopulateStopWaitingFrame(&pending_stop_waiting_frame_);
+ // If we can't this add the frame now, then we still need to do so later.
+ should_send_stop_waiting_ =
+ !packet_creator_.AddSavedFrame(QuicFrame(&pending_stop_waiting_frame_));
+ // Return success if we have cleared out this flag (i.e., added the frame).
+ // If we still need to send, then the frame is full, and we have failed.
+ return !should_send_stop_waiting_;
+ }
+
+ QUIC_BUG_IF(queued_control_frames_.empty())
+ << "AddNextPendingFrame called with no queued control frames.";
+ if (!packet_creator_.AddSavedFrame(queued_control_frames_.back())) {
+ // Packet was full.
+ return false;
+ }
+ queued_control_frames_.pop_back();
+ return true;
+}
+
+void QuicPacketGenerator::StopSendingVersion() {
+ packet_creator_.StopSendingVersion();
+}
+
+void QuicPacketGenerator::SetDiversificationNonce(
+ const DiversificationNonce& nonce) {
+ packet_creator_.SetDiversificationNonce(nonce);
+}
+
+QuicPacketNumber QuicPacketGenerator::packet_number() const {
+ return packet_creator_.packet_number();
+}
+
+QuicByteCount QuicPacketGenerator::GetCurrentMaxPacketLength() const {
+ return packet_creator_.max_packet_length();
+}
+
+void QuicPacketGenerator::SetMaxPacketLength(QuicByteCount length) {
+ DCHECK(packet_creator_.CanSetMaxPacketLength());
+ packet_creator_.SetMaxPacketLength(length);
+}
+
+QuicEncryptedPacket* QuicPacketGenerator::SerializeVersionNegotiationPacket(
+ const QuicVersionVector& supported_versions) {
+ return packet_creator_.SerializeVersionNegotiationPacket(supported_versions);
+}
+
+void QuicPacketGenerator::ReserializeAllFrames(
+ const PendingRetransmission& retransmission,
+ char* buffer,
+ size_t buffer_len) {
+ packet_creator_.ReserializeAllFrames(retransmission, buffer, buffer_len);
+}
+
+void QuicPacketGenerator::UpdateSequenceNumberLength(
+ QuicPacketNumber least_packet_awaited_by_peer,
+ QuicPacketCount max_packets_in_flight) {
+ return packet_creator_.UpdatePacketNumberLength(least_packet_awaited_by_peer,
+ max_packets_in_flight);
+}
+
+void QuicPacketGenerator::SetConnectionIdLength(uint32_t length) {
+ if (length == 0) {
+ packet_creator_.set_connection_id_length(PACKET_0BYTE_CONNECTION_ID);
+ } else {
+ packet_creator_.set_connection_id_length(PACKET_8BYTE_CONNECTION_ID);
+ }
+}
+
+void QuicPacketGenerator::set_encryption_level(EncryptionLevel level) {
+ packet_creator_.set_encryption_level(level);
+}
+
+void QuicPacketGenerator::SetEncrypter(EncryptionLevel level,
+ QuicEncrypter* encrypter) {
+ packet_creator_.SetEncrypter(level, encrypter);
+}
+
+void QuicPacketGenerator::SetCurrentPath(
+ QuicPathId path_id,
+ QuicPacketNumber least_packet_awaited_by_peer,
+ QuicPacketCount max_packets_in_flight) {
+ packet_creator_.SetCurrentPath(path_id, least_packet_awaited_by_peer,
+ max_packets_in_flight);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_packet_generator.h b/chromium/net/quic/core/quic_packet_generator.h
new file mode 100644
index 00000000000..2a87979eaa0
--- /dev/null
+++ b/chromium/net/quic/core/quic_packet_generator.h
@@ -0,0 +1,223 @@
+// 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.
+//
+// Responsible for generating packets on behalf of a QuicConnection.
+// Packets are serialized just-in-time. Control frames are queued.
+// Ack and Feedback frames will be requested from the Connection
+// just-in-time. When a packet needs to be sent, the Generator
+// will serialize a packet and pass it to QuicConnection::SendOrQueuePacket()
+//
+// The Generator's mode of operation is controlled by two conditions:
+//
+// 1) Is the Delegate writable?
+//
+// If the Delegate is not writable, then no operations will cause
+// a packet to be serialized. In particular:
+// * SetShouldSendAck will simply record that an ack is to be sent.
+// * AddControlFrame will enqueue the control frame.
+// * ConsumeData will do nothing.
+//
+// If the Delegate is writable, then the behavior depends on the second
+// condition:
+//
+// 2) Is the Generator in batch mode?
+//
+// If the Generator is NOT in batch mode, then each call to a write
+// operation will serialize one or more packets. The contents will
+// include any previous queued frames. If an ack should be sent
+// but has not been sent, then the Delegate will be asked to create
+// an Ack frame which will then be included in the packet. When
+// the write call completes, the current packet will be serialized
+// and sent to the Delegate, even if it is not full.
+//
+// If the Generator is in batch mode, then each write operation will
+// add data to the "current" packet. When the current packet becomes
+// full, it will be serialized and sent to the packet. When batch
+// mode is ended via |FinishBatchOperations|, the current packet
+// will be serialzied, even if it is not full.
+
+#ifndef NET_QUIC_QUIC_PACKET_GENERATOR_H_
+#define NET_QUIC_QUIC_PACKET_GENERATOR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <list>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_packet_creator.h"
+#include "net/quic/core/quic_sent_packet_manager.h"
+#include "net/quic/core/quic_types.h"
+
+namespace net {
+
+namespace test {
+class QuicPacketGeneratorPeer;
+} // namespace test
+
+class NET_EXPORT_PRIVATE QuicPacketGenerator {
+ public:
+ class NET_EXPORT_PRIVATE DelegateInterface
+ : public QuicPacketCreator::DelegateInterface {
+ public:
+ ~DelegateInterface() override {}
+ // Consults delegate whether a packet should be generated.
+ virtual bool ShouldGeneratePacket(HasRetransmittableData retransmittable,
+ IsHandshake handshake) = 0;
+ virtual const QuicFrame GetUpdatedAckFrame() = 0;
+ virtual void PopulateStopWaitingFrame(
+ QuicStopWaitingFrame* stop_waiting) = 0;
+ };
+
+ QuicPacketGenerator(QuicConnectionId connection_id,
+ QuicFramer* framer,
+ QuicRandom* random_generator,
+ QuicBufferAllocator* buffer_allocator,
+ DelegateInterface* delegate);
+
+ ~QuicPacketGenerator();
+
+ // Indicates that an ACK frame should be sent.
+ // If |also_send_stop_waiting| is true, then it also indicates that a
+ // STOP_WAITING frame should be sent as well.
+ // The contents of the frame(s) will be generated via a call to the delegate
+ // CreateAckFrame() when the packet is serialized.
+ void SetShouldSendAck(bool also_send_stop_waiting);
+
+ void AddControlFrame(const QuicFrame& frame);
+
+ // Given some data, may consume part or all of it and pass it to the
+ // packet creator to be serialized into packets. If not in batch
+ // mode, these packets will also be sent during this call.
+ // |delegate| (if not nullptr) will be informed once all packets sent as a
+ // result of this call are ACKed by the peer.
+ QuicConsumedData ConsumeData(QuicStreamId id,
+ QuicIOVector iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* listener);
+
+ // Sends as many data only packets as allowed by the send algorithm and the
+ // available iov.
+ // This path does not support FEC, padding, or bundling pending frames.
+ QuicConsumedData ConsumeDataFastPath(QuicStreamId id,
+ const QuicIOVector& iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* listener);
+
+ // Generates an MTU discovery packet of specified size.
+ void GenerateMtuDiscoveryPacket(QuicByteCount target_mtu,
+ QuicAckListenerInterface* listener);
+
+ // Indicates whether batch mode is currently enabled.
+ bool InBatchMode();
+ // Disables flushing.
+ void StartBatchOperations();
+ // Enables flushing and flushes queued data which can be sent.
+ void FinishBatchOperations();
+
+ // Flushes all queued frames, even frames which are not sendable.
+ void FlushAllQueuedFrames();
+
+ bool HasQueuedFrames() const;
+
+ // Whether the pending packet has no frames in it at the moment.
+ bool IsPendingPacketEmpty() const;
+
+ // Makes the framer not serialize the protocol version in sent packets.
+ void StopSendingVersion();
+
+ // SetDiversificationNonce sets the nonce that will be sent in each public
+ // header of packets encrypted at the initial encryption level. Should only
+ // be called by servers.
+ void SetDiversificationNonce(const DiversificationNonce& nonce);
+
+ // Creates a version negotiation packet which supports |supported_versions|.
+ // Caller owns the created packet. Also, sets the entropy hash of the
+ // serialized packet to a random bool and returns that value as a member of
+ // SerializedPacket.
+ QuicEncryptedPacket* SerializeVersionNegotiationPacket(
+ const QuicVersionVector& supported_versions);
+
+ // Re-serializes frames with the original packet's packet number length.
+ // Used for retransmitting packets to ensure they aren't too long.
+ void ReserializeAllFrames(const PendingRetransmission& retransmission,
+ char* buffer,
+ size_t buffer_len);
+
+ // Update the packet number length to use in future packets as soon as it
+ // can be safely changed.
+ void UpdateSequenceNumberLength(QuicPacketNumber least_packet_awaited_by_peer,
+ QuicPacketCount max_packets_in_flight);
+
+ // Set the minimum number of bytes for the connection id length;
+ void SetConnectionIdLength(uint32_t length);
+
+ // Sets the encrypter to use for the encryption level.
+ void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter);
+
+ // Sets the encryption level that will be applied to new packets.
+ void set_encryption_level(EncryptionLevel level);
+
+ // packet number of the last created packet, or 0 if no packets have been
+ // created.
+ QuicPacketNumber packet_number() const;
+
+ // Returns the maximum length a current packet can actually have.
+ QuicByteCount GetCurrentMaxPacketLength() const;
+
+ // Set maximum packet length in the creator immediately. May not be called
+ // when there are frames queued in the creator.
+ void SetMaxPacketLength(QuicByteCount length);
+
+ // Sets |path_id| to be the path on which next packet is generated.
+ void SetCurrentPath(QuicPathId path_id,
+ QuicPacketNumber least_packet_awaited_by_peer,
+ QuicPacketCount max_packets_in_flight);
+
+ void set_debug_delegate(QuicPacketCreator::DebugDelegate* debug_delegate) {
+ packet_creator_.set_debug_delegate(debug_delegate);
+ }
+
+ private:
+ friend class test::QuicPacketGeneratorPeer;
+
+ void SendQueuedFrames(bool flush);
+
+ // Test to see if we have pending ack, or control frames.
+ bool HasPendingFrames() const;
+ // Returns true if addition of a pending frame (which might be
+ // retransmittable) would still allow the resulting packet to be sent now.
+ bool CanSendWithNextPendingFrameAddition() const;
+ // Add exactly one pending frame, preferring ack frames over control frames.
+ // Returns true if a pending frame is successfully added.
+ // Returns false and flushes current open packet if the pending frame cannot
+ // fit into current open packet.
+ bool AddNextPendingFrame();
+
+ DelegateInterface* delegate_;
+
+ QuicPacketCreator packet_creator_;
+ QuicFrames queued_control_frames_;
+
+ // True if batch mode is currently enabled.
+ bool batch_mode_;
+
+ // Flags to indicate the need for just-in-time construction of a frame.
+ bool should_send_ack_;
+ bool should_send_stop_waiting_;
+ // If we put a non-retransmittable frame in this packet, then we have to hold
+ // a reference to it until we flush (and serialize it). Retransmittable frames
+ // are referenced elsewhere so that they can later be (optionally)
+ // retransmitted.
+ QuicStopWaitingFrame pending_stop_waiting_frame_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicPacketGenerator);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_PACKET_GENERATOR_H_
diff --git a/chromium/net/quic/core/quic_packet_generator_test.cc b/chromium/net/quic/core/quic_packet_generator_test.cc
new file mode 100644
index 00000000000..782d28ea26a
--- /dev/null
+++ b/chromium/net/quic/core/quic_packet_generator_test.cc
@@ -0,0 +1,897 @@
+// 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/quic_packet_generator.h"
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/null_encrypter.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_simple_buffer_allocator.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/quic_packet_creator_peer.h"
+#include "net/quic/test_tools/quic_packet_generator_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/simple_quic_framer.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringPiece;
+using std::string;
+using std::vector;
+using testing::InSequence;
+using testing::Return;
+using testing::StrictMock;
+using testing::_;
+
+namespace net {
+namespace test {
+namespace {
+
+class MockDelegate : public QuicPacketGenerator::DelegateInterface {
+ public:
+ MockDelegate() {}
+ ~MockDelegate() override {}
+
+ MOCK_METHOD2(ShouldGeneratePacket,
+ bool(HasRetransmittableData retransmittable,
+ IsHandshake handshake));
+ MOCK_METHOD0(GetUpdatedAckFrame, const QuicFrame());
+ MOCK_METHOD1(PopulateStopWaitingFrame, void(QuicStopWaitingFrame*));
+ MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet));
+ MOCK_METHOD3(OnUnrecoverableError,
+ void(QuicErrorCode, const string&, ConnectionCloseSource));
+
+ void SetCanWriteAnything() {
+ EXPECT_CALL(*this, ShouldGeneratePacket(_, _)).WillRepeatedly(Return(true));
+ EXPECT_CALL(*this, ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, _))
+ .WillRepeatedly(Return(true));
+ }
+
+ void SetCanNotWrite() {
+ EXPECT_CALL(*this, ShouldGeneratePacket(_, _))
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*this, ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, _))
+ .WillRepeatedly(Return(false));
+ }
+
+ // Use this when only ack frames should be allowed to be written.
+ void SetCanWriteOnlyNonRetransmittable() {
+ EXPECT_CALL(*this, ShouldGeneratePacket(_, _))
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*this, ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, _))
+ .WillRepeatedly(Return(true));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockDelegate);
+};
+
+// Simple struct for describing the contents of a packet.
+// Useful in conjunction with a SimpleQuicFrame for validating that a packet
+// contains the expected frames.
+struct PacketContents {
+ PacketContents()
+ : num_ack_frames(0),
+ num_connection_close_frames(0),
+ num_goaway_frames(0),
+ num_rst_stream_frames(0),
+ num_stop_waiting_frames(0),
+ num_stream_frames(0),
+ num_ping_frames(0),
+ num_mtu_discovery_frames(0) {}
+
+ size_t num_ack_frames;
+ size_t num_connection_close_frames;
+ size_t num_goaway_frames;
+ size_t num_rst_stream_frames;
+ size_t num_stop_waiting_frames;
+ size_t num_stream_frames;
+ size_t num_ping_frames;
+ size_t num_mtu_discovery_frames;
+};
+
+} // namespace
+
+class QuicPacketGeneratorTest : public ::testing::Test {
+ public:
+ QuicPacketGeneratorTest()
+ : framer_(AllSupportedVersions(),
+ QuicTime::Zero(),
+ Perspective::IS_CLIENT),
+ generator_(42, &framer_, &random_, &buffer_allocator_, &delegate_),
+ creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)) {
+ creator_->SetEncrypter(ENCRYPTION_FORWARD_SECURE, new NullEncrypter());
+ creator_->set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+ }
+
+ ~QuicPacketGeneratorTest() override {
+ for (SerializedPacket& packet : packets_) {
+ delete[] packet.encrypted_buffer;
+ QuicUtils::ClearSerializedPacket(&packet);
+ }
+ }
+
+ void SavePacket(SerializedPacket* packet) {
+ packet->encrypted_buffer = QuicUtils::CopyBuffer(*packet);
+ packets_.push_back(*packet);
+ packet->encrypted_buffer = nullptr;
+ packet->retransmittable_frames.clear();
+ }
+
+ protected:
+ QuicRstStreamFrame* CreateRstStreamFrame() {
+ return new QuicRstStreamFrame(1, QUIC_STREAM_NO_ERROR, 0);
+ }
+
+ QuicGoAwayFrame* CreateGoAwayFrame() {
+ return new QuicGoAwayFrame(QUIC_NO_ERROR, 1, string());
+ }
+
+ void CheckPacketContains(const PacketContents& contents,
+ size_t packet_index) {
+ ASSERT_GT(packets_.size(), packet_index);
+ const SerializedPacket& packet = packets_[packet_index];
+ size_t num_retransmittable_frames =
+ contents.num_connection_close_frames + contents.num_goaway_frames +
+ contents.num_rst_stream_frames + contents.num_stream_frames +
+ contents.num_ping_frames;
+ size_t num_frames =
+ contents.num_ack_frames + contents.num_stop_waiting_frames +
+ contents.num_mtu_discovery_frames + num_retransmittable_frames;
+
+ if (num_retransmittable_frames == 0) {
+ ASSERT_TRUE(packet.retransmittable_frames.empty());
+ } else {
+ ASSERT_FALSE(packet.retransmittable_frames.empty());
+ EXPECT_EQ(num_retransmittable_frames,
+ packet.retransmittable_frames.size());
+ }
+
+ ASSERT_TRUE(packet.encrypted_buffer != nullptr);
+ ASSERT_TRUE(simple_framer_.ProcessPacket(
+ QuicEncryptedPacket(packet.encrypted_buffer, packet.encrypted_length)));
+ EXPECT_EQ(num_frames, simple_framer_.num_frames());
+ EXPECT_EQ(contents.num_ack_frames, simple_framer_.ack_frames().size());
+ EXPECT_EQ(contents.num_connection_close_frames,
+ simple_framer_.connection_close_frames().size());
+ EXPECT_EQ(contents.num_goaway_frames,
+ simple_framer_.goaway_frames().size());
+ EXPECT_EQ(contents.num_rst_stream_frames,
+ simple_framer_.rst_stream_frames().size());
+ EXPECT_EQ(contents.num_stream_frames,
+ simple_framer_.stream_frames().size());
+ EXPECT_EQ(contents.num_stop_waiting_frames,
+ simple_framer_.stop_waiting_frames().size());
+
+ // From the receiver's perspective, MTU discovery frames are ping frames.
+ EXPECT_EQ(contents.num_ping_frames + contents.num_mtu_discovery_frames,
+ simple_framer_.ping_frames().size());
+ }
+
+ void CheckPacketHasSingleStreamFrame(size_t packet_index) {
+ ASSERT_GT(packets_.size(), packet_index);
+ const SerializedPacket& packet = packets_[packet_index];
+ ASSERT_FALSE(packet.retransmittable_frames.empty());
+ EXPECT_EQ(1u, packet.retransmittable_frames.size());
+ ASSERT_TRUE(packet.encrypted_buffer != nullptr);
+ ASSERT_TRUE(simple_framer_.ProcessPacket(
+ QuicEncryptedPacket(packet.encrypted_buffer, packet.encrypted_length)));
+ EXPECT_EQ(1u, simple_framer_.num_frames());
+ EXPECT_EQ(1u, simple_framer_.stream_frames().size());
+ }
+
+ void CheckAllPacketsHaveSingleStreamFrame() {
+ for (size_t i = 0; i < packets_.size(); i++) {
+ CheckPacketHasSingleStreamFrame(i);
+ }
+ }
+
+ QuicIOVector CreateData(size_t len) {
+ data_array_.reset(new char[len]);
+ memset(data_array_.get(), '?', len);
+ iov_.iov_base = data_array_.get();
+ iov_.iov_len = len;
+ return QuicIOVector(&iov_, 1, len);
+ }
+
+ QuicIOVector MakeIOVector(StringPiece s) {
+ return ::net::MakeIOVector(s, &iov_);
+ }
+
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+ QuicFramer framer_;
+ MockRandom random_;
+ SimpleBufferAllocator buffer_allocator_;
+ StrictMock<MockDelegate> delegate_;
+ QuicPacketGenerator generator_;
+ QuicPacketCreator* creator_;
+ SimpleQuicFramer simple_framer_;
+ vector<SerializedPacket> packets_;
+ QuicAckFrame ack_frame_;
+
+ private:
+ std::unique_ptr<char[]> data_array_;
+ struct iovec iov_;
+};
+
+class MockDebugDelegate : public QuicPacketCreator::DebugDelegate {
+ public:
+ MOCK_METHOD1(OnFrameAddedToPacket, void(const QuicFrame&));
+};
+
+TEST_F(QuicPacketGeneratorTest, ShouldSendAck_NotWritable) {
+ delegate_.SetCanNotWrite();
+
+ generator_.SetShouldSendAck(false);
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+}
+
+TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldNotFlush) {
+ StrictMock<MockDebugDelegate> debug_delegate;
+
+ generator_.set_debug_delegate(&debug_delegate);
+ delegate_.SetCanWriteOnlyNonRetransmittable();
+ generator_.StartBatchOperations();
+
+ EXPECT_CALL(delegate_, GetUpdatedAckFrame())
+ .WillOnce(Return(QuicFrame(&ack_frame_)));
+ EXPECT_CALL(debug_delegate, OnFrameAddedToPacket(_)).Times(1);
+
+ generator_.SetShouldSendAck(false);
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+}
+
+TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldFlush) {
+ delegate_.SetCanWriteOnlyNonRetransmittable();
+
+ EXPECT_CALL(delegate_, GetUpdatedAckFrame())
+ .WillOnce(Return(QuicFrame(&ack_frame_)));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+
+ generator_.SetShouldSendAck(false);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ PacketContents contents;
+ contents.num_ack_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
+TEST_F(QuicPacketGeneratorTest, ShouldSendAck_MultipleCalls) {
+ // Make sure that calling SetShouldSendAck multiple times does not result in a
+ // crash. Previously this would result in multiple QuicFrames queued in the
+ // packet generator, with all but the last with internal pointers to freed
+ // memory.
+ delegate_.SetCanWriteAnything();
+
+ // Only one AckFrame should be created.
+ EXPECT_CALL(delegate_, GetUpdatedAckFrame())
+ .WillOnce(Return(QuicFrame(&ack_frame_)));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .Times(1)
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+
+ generator_.StartBatchOperations();
+ generator_.SetShouldSendAck(false);
+ generator_.SetShouldSendAck(false);
+ generator_.FinishBatchOperations();
+}
+
+TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritable) {
+ delegate_.SetCanNotWrite();
+
+ generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+}
+
+TEST_F(QuicPacketGeneratorTest, AddControlFrame_OnlyAckWritable) {
+ delegate_.SetCanWriteOnlyNonRetransmittable();
+
+ generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+}
+
+TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldNotFlush) {
+ delegate_.SetCanWriteAnything();
+ generator_.StartBatchOperations();
+
+ generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+}
+
+TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritableBatchThenFlush) {
+ delegate_.SetCanNotWrite();
+ generator_.StartBatchOperations();
+
+ generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+ generator_.FinishBatchOperations();
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ generator_.FlushAllQueuedFrames();
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ PacketContents contents;
+ contents.num_rst_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
+TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldFlush) {
+ delegate_.SetCanWriteAnything();
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+
+ generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ PacketContents contents;
+ contents.num_rst_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
+TEST_F(QuicPacketGeneratorTest, ConsumeData_NotWritable) {
+ delegate_.SetCanNotWrite();
+
+ QuicConsumedData consumed = generator_.ConsumeData(
+ kHeadersStreamId, MakeIOVector("foo"), 2, true, nullptr);
+ EXPECT_EQ(0u, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+}
+
+TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) {
+ delegate_.SetCanWriteAnything();
+ generator_.StartBatchOperations();
+
+ QuicConsumedData consumed = generator_.ConsumeData(
+ kHeadersStreamId, MakeIOVector("foo"), 2, true, nullptr);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+}
+
+TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldFlush) {
+ delegate_.SetCanWriteAnything();
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ QuicConsumedData consumed = generator_.ConsumeData(
+ kHeadersStreamId, MakeIOVector("foo"), 2, true, nullptr);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ PacketContents contents;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
+// Test the behavior of ConsumeData when the data consumed is for the crypto
+// handshake stream. Ensure that the packet is always sent and padded even if
+// the generator operates in batch mode.
+TEST_F(QuicPacketGeneratorTest, ConsumeData_Handshake) {
+ delegate_.SetCanWriteAnything();
+ generator_.StartBatchOperations();
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ QuicConsumedData consumed = generator_.ConsumeData(
+ kCryptoStreamId, MakeIOVector("foo"), 0, false, nullptr);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ PacketContents contents;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+
+ ASSERT_EQ(1u, packets_.size());
+ ASSERT_EQ(kDefaultMaxPacketSize, generator_.GetCurrentMaxPacketLength());
+ EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length);
+}
+
+TEST_F(QuicPacketGeneratorTest, ConsumeData_EmptyData) {
+ EXPECT_QUIC_BUG(generator_.ConsumeData(kHeadersStreamId, MakeIOVector(""), 0,
+ false, nullptr),
+ "Attempt to consume empty data without FIN.");
+}
+
+TEST_F(QuicPacketGeneratorTest,
+ ConsumeDataMultipleTimes_WritableAndShouldNotFlush) {
+ delegate_.SetCanWriteAnything();
+ generator_.StartBatchOperations();
+
+ generator_.ConsumeData(kHeadersStreamId, MakeIOVector("foo"), 2, true,
+ nullptr);
+ QuicConsumedData consumed =
+ generator_.ConsumeData(3, MakeIOVector("quux"), 7, false, nullptr);
+ EXPECT_EQ(4u, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+}
+
+TEST_F(QuicPacketGeneratorTest, ConsumeData_BatchOperations) {
+ delegate_.SetCanWriteAnything();
+ generator_.StartBatchOperations();
+
+ generator_.ConsumeData(kHeadersStreamId, MakeIOVector("foo"), 2, true,
+ nullptr);
+ QuicConsumedData consumed =
+ generator_.ConsumeData(3, MakeIOVector("quux"), 7, false, nullptr);
+ EXPECT_EQ(4u, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+
+ // Now both frames will be flushed out.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ generator_.FinishBatchOperations();
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ PacketContents contents;
+ contents.num_stream_frames = 2;
+ CheckPacketContains(contents, 0);
+}
+
+TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
+ // Set the packet size be enough for two stream frames with 0 stream offset,
+ // but not enough for a stream frame of 0 offset and one with non-zero offset.
+ size_t length =
+ NullEncrypter().GetCiphertextSize(0) +
+ GetPacketHeaderSize(
+ framer_.version(), creator_->connection_id_length(), kIncludeVersion,
+ !kIncludePathId, !kIncludeDiversificationNonce,
+ QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) +
+ // Add an extra 3 bytes for the payload and 1 byte so BytesFree is larger
+ // than the GetMinStreamFrameSize.
+ QuicFramer::GetMinStreamFrameSize(1, 0, false) + 3 +
+ QuicFramer::GetMinStreamFrameSize(1, 0, true) + 1;
+ generator_.SetMaxPacketLength(length);
+ delegate_.SetCanWriteAnything();
+ {
+ InSequence dummy;
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ }
+ generator_.StartBatchOperations();
+ // Queue enough data to prevent a stream frame with a non-zero offset from
+ // fitting.
+ QuicConsumedData consumed = generator_.ConsumeData(
+ kHeadersStreamId, MakeIOVector("foo"), 0, false, nullptr);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+
+ // This frame will not fit with the existing frame, causing the queued frame
+ // to be serialized, and it will be added to a new open packet.
+ consumed = generator_.ConsumeData(kHeadersStreamId, MakeIOVector("bar"), 3,
+ true, nullptr);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+
+ creator_->Flush();
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ PacketContents contents;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+ CheckPacketContains(contents, 1);
+}
+
+TEST_F(QuicPacketGeneratorTest, ConsumeDataFastPath) {
+ delegate_.SetCanWriteAnything();
+
+ // Create a 10000 byte IOVector.
+ QuicIOVector iov(CreateData(10000));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ QuicConsumedData consumed =
+ generator_.ConsumeDataFastPath(kHeadersStreamId, iov, 0, true, nullptr);
+ EXPECT_EQ(10000u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ PacketContents contents;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
+TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) {
+ delegate_.SetCanNotWrite();
+
+ generator_.SetShouldSendAck(false);
+ generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+
+ delegate_.SetCanWriteAnything();
+
+ generator_.StartBatchOperations();
+
+ // When the first write operation is invoked, the ack frame will be returned.
+ EXPECT_CALL(delegate_, GetUpdatedAckFrame())
+ .WillOnce(Return(QuicFrame(&ack_frame_)));
+
+ // Send some data and a control frame
+ generator_.ConsumeData(3, MakeIOVector("quux"), 7, false, nullptr);
+ generator_.AddControlFrame(QuicFrame(CreateGoAwayFrame()));
+
+ // All five frames will be flushed out in a single packet.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ generator_.FinishBatchOperations();
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ PacketContents contents;
+ contents.num_ack_frames = 1;
+ contents.num_goaway_frames = 1;
+ contents.num_rst_stream_frames = 1;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
+TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) {
+ delegate_.SetCanNotWrite();
+
+ generator_.SetShouldSendAck(false);
+ generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+
+ delegate_.SetCanWriteAnything();
+
+ generator_.StartBatchOperations();
+
+ // When the first write operation is invoked, the ack frame will be returned.
+ EXPECT_CALL(delegate_, GetUpdatedAckFrame())
+ .WillOnce(Return(QuicFrame(&ack_frame_)));
+
+ {
+ InSequence dummy;
+ // All five frames will be flushed out in a single packet
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ }
+
+ // Send enough data to exceed one packet
+ size_t data_len = kDefaultMaxPacketSize + 100;
+ QuicConsumedData consumed =
+ generator_.ConsumeData(3, CreateData(data_len), 0, true, nullptr);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ generator_.AddControlFrame(QuicFrame(CreateGoAwayFrame()));
+
+ generator_.FinishBatchOperations();
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ // The first packet should have the queued data and part of the stream data.
+ PacketContents contents;
+ contents.num_ack_frames = 1;
+ contents.num_rst_stream_frames = 1;
+ contents.num_stream_frames = 1;
+ CheckPacketContains(contents, 0);
+
+ // The second should have the remainder of the stream data.
+ PacketContents contents2;
+ contents2.num_goaway_frames = 1;
+ contents2.num_stream_frames = 1;
+ CheckPacketContains(contents2, 1);
+}
+
+TEST_F(QuicPacketGeneratorTest, TestConnectionIdLength) {
+ generator_.SetConnectionIdLength(0);
+ EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, creator_->connection_id_length());
+
+ for (size_t i = 1; i < 10; i++) {
+ generator_.SetConnectionIdLength(i);
+ EXPECT_EQ(PACKET_8BYTE_CONNECTION_ID, creator_->connection_id_length());
+ }
+}
+
+// Test whether SetMaxPacketLength() works in the situation when the queue is
+// empty, and we send three packets worth of data.
+TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_Initial) {
+ delegate_.SetCanWriteAnything();
+
+ // Send enough data for three packets.
+ size_t data_len = 3 * kDefaultMaxPacketSize + 1;
+ size_t packet_len = kDefaultMaxPacketSize + 100;
+ ASSERT_LE(packet_len, kMaxPacketSize);
+ generator_.SetMaxPacketLength(packet_len);
+ EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength());
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .Times(3)
+ .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ QuicConsumedData consumed =
+ generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
+ /*offset=*/2,
+ /*fin=*/true, nullptr);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ // We expect three packets, and first two of them have to be of packet_len
+ // size. We check multiple packets (instead of just one) because we want to
+ // ensure that |max_packet_length_| does not get changed incorrectly by the
+ // generator after first packet is serialized.
+ ASSERT_EQ(3u, packets_.size());
+ EXPECT_EQ(packet_len, packets_[0].encrypted_length);
+ EXPECT_EQ(packet_len, packets_[1].encrypted_length);
+ CheckAllPacketsHaveSingleStreamFrame();
+}
+
+// Test whether SetMaxPacketLength() works in the situation when we first write
+// data, then change packet size, then write data again.
+TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_Middle) {
+ delegate_.SetCanWriteAnything();
+
+ // We send enough data to overflow default packet length, but not the altered
+ // one.
+ size_t data_len = kDefaultMaxPacketSize;
+ size_t packet_len = kDefaultMaxPacketSize + 100;
+ ASSERT_LE(packet_len, kMaxPacketSize);
+
+ // We expect to see three packets in total.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .Times(3)
+ .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+
+ // Send two packets before packet size change.
+ QuicConsumedData consumed =
+ generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
+ /*offset=*/2,
+ /*fin=*/false, nullptr);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ // Make sure we already have two packets.
+ ASSERT_EQ(2u, packets_.size());
+
+ // Increase packet size.
+ generator_.SetMaxPacketLength(packet_len);
+ EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength());
+
+ // Send a packet after packet size change.
+ consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
+ 2 + data_len,
+ /*fin=*/true, nullptr);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ // We expect first data chunk to get fragmented, but the second one to fit
+ // into a single packet.
+ ASSERT_EQ(3u, packets_.size());
+ EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length);
+ EXPECT_LE(kDefaultMaxPacketSize, packets_[2].encrypted_length);
+ CheckAllPacketsHaveSingleStreamFrame();
+}
+
+// Test whether SetMaxPacketLength() works correctly when we force the change of
+// the packet size in the middle of the batched packet.
+TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_MidpacketFlush) {
+ delegate_.SetCanWriteAnything();
+ generator_.StartBatchOperations();
+
+ size_t first_write_len = kDefaultMaxPacketSize / 2;
+ size_t packet_len = kDefaultMaxPacketSize + 100;
+ size_t second_write_len = packet_len + 1;
+ ASSERT_LE(packet_len, kMaxPacketSize);
+
+ // First send half of the packet worth of data. We are in the batch mode, so
+ // should not cause packet serialization.
+ QuicConsumedData consumed =
+ generator_.ConsumeData(kHeadersStreamId, CreateData(first_write_len),
+ /*offset=*/2,
+ /*fin=*/false, nullptr);
+ EXPECT_EQ(first_write_len, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+
+ // Make sure we have no packets so far.
+ ASSERT_EQ(0u, packets_.size());
+
+ // Expect a packet to be flushed.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+
+ // Increase packet size after flushing all frames.
+ // Ensure it's immediately enacted.
+ generator_.FlushAllQueuedFrames();
+ generator_.SetMaxPacketLength(packet_len);
+ EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength());
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ // We expect to see exactly one packet serialized after that, because we send
+ // a value somewhat exceeding new max packet size, and the tail data does not
+ // get serialized because we are still in the batch mode.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+
+ // Send a more than a packet worth of data to the same stream. This should
+ // trigger serialization of one packet, and queue another one.
+ consumed =
+ generator_.ConsumeData(kHeadersStreamId, CreateData(second_write_len),
+ /*offset=*/2 + first_write_len,
+ /*fin=*/true, nullptr);
+ EXPECT_EQ(second_write_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+
+ // We expect the first packet to be underfilled, and the second packet be up
+ // to the new max packet size.
+ ASSERT_EQ(2u, packets_.size());
+ EXPECT_GT(kDefaultMaxPacketSize, packets_[0].encrypted_length);
+ EXPECT_EQ(packet_len, packets_[1].encrypted_length);
+
+ CheckAllPacketsHaveSingleStreamFrame();
+}
+
+// Test sending an MTU probe, without any surrounding data.
+TEST_F(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_Simple) {
+ delegate_.SetCanWriteAnything();
+
+ const size_t target_mtu = kDefaultMaxPacketSize + 100;
+ static_assert(target_mtu < kMaxPacketSize,
+ "The MTU probe used by the test exceeds maximum packet size");
+
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+
+ generator_.GenerateMtuDiscoveryPacket(target_mtu, nullptr);
+
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+ ASSERT_EQ(1u, packets_.size());
+ EXPECT_EQ(target_mtu, packets_[0].encrypted_length);
+
+ PacketContents contents;
+ contents.num_mtu_discovery_frames = 1;
+ CheckPacketContains(contents, 0);
+}
+
+// Test sending an MTU probe. Surround it with data, to ensure that it resets
+// the MTU to the value before the probe was sent.
+TEST_F(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_SurroundedByData) {
+ delegate_.SetCanWriteAnything();
+
+ const size_t target_mtu = kDefaultMaxPacketSize + 100;
+ static_assert(target_mtu < kMaxPacketSize,
+ "The MTU probe used by the test exceeds maximum packet size");
+
+ // Send enough data so it would always cause two packets to be sent.
+ const size_t data_len = target_mtu + 1;
+
+ // Send a total of five packets: two packets before the probe, the probe
+ // itself, and two packets after the probe.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .Times(5)
+ .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+
+ // Send data before the MTU probe.
+ QuicConsumedData consumed =
+ generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
+ /*offset=*/2,
+ /*fin=*/false, nullptr);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_FALSE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ // Send the MTU probe.
+ generator_.GenerateMtuDiscoveryPacket(target_mtu, nullptr);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ // Send data after the MTU probe.
+ consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
+ /*offset=*/2 + data_len,
+ /*fin=*/true, nullptr);
+ EXPECT_EQ(data_len, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+
+ ASSERT_EQ(5u, packets_.size());
+ EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length);
+ EXPECT_EQ(target_mtu, packets_[2].encrypted_length);
+ EXPECT_EQ(kDefaultMaxPacketSize, packets_[3].encrypted_length);
+
+ PacketContents probe_contents;
+ probe_contents.num_mtu_discovery_frames = 1;
+
+ CheckPacketHasSingleStreamFrame(0);
+ CheckPacketHasSingleStreamFrame(1);
+ CheckPacketContains(probe_contents, 2);
+ CheckPacketHasSingleStreamFrame(3);
+ CheckPacketHasSingleStreamFrame(4);
+}
+
+TEST_F(QuicPacketGeneratorTest, DontCrashOnInvalidStopWaiting) {
+ // Test added to ensure the generator does not crash when an invalid frame is
+ // added. Because this is an indication of internal programming errors,
+ // DFATALs are expected.
+ // A 1 byte packet number length can't encode a gap of 1000.
+ QuicPacketCreatorPeer::SetPacketNumber(creator_, 1000);
+
+ delegate_.SetCanNotWrite();
+ generator_.SetShouldSendAck(true);
+ delegate_.SetCanWriteAnything();
+ generator_.StartBatchOperations();
+
+ // Set up frames to write into the creator when control frames are written.
+ EXPECT_CALL(delegate_, GetUpdatedAckFrame())
+ .WillOnce(Return(QuicFrame(&ack_frame_)));
+ EXPECT_CALL(delegate_, PopulateStopWaitingFrame(_));
+ // Generator should have queued control frames, and creator should be empty.
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+ EXPECT_FALSE(creator_->HasPendingFrames());
+
+ // This will not serialize any packets, because of the invalid frame.
+ EXPECT_CALL(delegate_,
+ OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, _,
+ ConnectionCloseSource::FROM_SELF));
+ EXPECT_QUIC_BUG(generator_.FinishBatchOperations(),
+ "packet_number_length 1 is too small "
+ "for least_unacked_delta: 1001");
+}
+
+TEST_F(QuicPacketGeneratorTest, SetCurrentPath) {
+ delegate_.SetCanWriteAnything();
+ generator_.StartBatchOperations();
+
+ QuicConsumedData consumed = generator_.ConsumeData(
+ kHeadersStreamId, MakeIOVector("foo"), 2, true, nullptr);
+ EXPECT_EQ(3u, consumed.bytes_consumed);
+ EXPECT_TRUE(consumed.fin_consumed);
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+ EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(creator_));
+ // Does not change current path.
+ generator_.SetCurrentPath(kDefaultPathId, 1, 0);
+ EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(creator_));
+
+ // Try to switch path when a packet is under construction.
+ QuicPathId kTestPathId1 = 1;
+ EXPECT_QUIC_BUG(generator_.SetCurrentPath(kTestPathId1, 1, 0),
+ "Unable to change paths when a packet is under construction");
+ EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(creator_));
+
+ // Try to switch path after current open packet gets serialized.
+ EXPECT_CALL(delegate_, OnSerializedPacket(_))
+ .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+ generator_.FlushAllQueuedFrames();
+ EXPECT_FALSE(generator_.HasQueuedFrames());
+ generator_.SetCurrentPath(kTestPathId1, 1, 0);
+ EXPECT_EQ(kTestPathId1, QuicPacketCreatorPeer::GetCurrentPath(creator_));
+}
+
+// Regression test for b/31486443.
+TEST_F(QuicPacketGeneratorTest, ConnectionCloseFrameLargerThanPacketSize) {
+ FLAGS_quic_close_connection_on_huge_frames = true;
+ delegate_.SetCanWriteAnything();
+ QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame();
+ frame->error_code = QUIC_PACKET_WRITE_ERROR;
+ char buf[2000];
+ StringPiece error_details(buf, 2000);
+ frame->error_details = error_details.as_string();
+ EXPECT_CALL(delegate_,
+ OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET,
+ "Single frame cannot fit into a packet", _));
+ EXPECT_QUIC_BUG(generator_.AddControlFrame(QuicFrame(frame)), "");
+ EXPECT_TRUE(generator_.HasQueuedFrames());
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_packet_writer.h b/chromium/net/quic/core/quic_packet_writer.h
new file mode 100644
index 00000000000..ea1adf90cc5
--- /dev/null
+++ b/chromium/net/quic/core/quic_packet_writer.h
@@ -0,0 +1,74 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_PACKET_WRITER_H_
+#define NET_QUIC_QUIC_PACKET_WRITER_H_
+
+#include <stddef.h>
+
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+class IPAddress;
+struct WriteResult;
+
+class NET_EXPORT_PRIVATE PerPacketOptions {
+ public:
+ PerPacketOptions() = default;
+ virtual ~PerPacketOptions() {}
+
+ // Returns a heap-allocated copy of |this|.
+ virtual PerPacketOptions* Clone() const = 0;
+
+ private:
+ PerPacketOptions(PerPacketOptions&& other) = delete;
+ PerPacketOptions& operator=(PerPacketOptions&& other) = delete;
+
+ DISALLOW_COPY_AND_ASSIGN(PerPacketOptions);
+};
+
+// An interface between writers and the entity managing the
+// socket (in our case the QuicDispatcher). This allows the Dispatcher to
+// control writes, and manage any writers who end up write blocked.
+class NET_EXPORT_PRIVATE QuicPacketWriter {
+ public:
+ virtual ~QuicPacketWriter() {}
+
+ // Sends the packet out to the peer, with some optional per-packet options.
+ // If the write succeeded, the result's status is WRITE_STATUS_OK and
+ // bytes_written is populated. If the write failed, the result's status is
+ // WRITE_STATUS_BLOCKED or WRITE_STATUS_ERROR and error_code is populated.
+ // Options must be either null, or created for the particular QuicPacketWriter
+ // implementation. Options may be ignored, depending on the implementation.
+ virtual WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const IPAddress& self_address,
+ const IPEndPoint& peer_address,
+ PerPacketOptions* options) = 0;
+
+ // Returns true if the writer buffers and subsequently rewrites data
+ // when an attempt to write results in the underlying socket becoming
+ // write blocked.
+ virtual bool IsWriteBlockedDataBuffered() const = 0;
+
+ // Returns true if the network socket is not writable.
+ virtual bool IsWriteBlocked() const = 0;
+
+ // Records that the socket has become writable, for example when an EPOLLOUT
+ // is received or an asynchronous write completes.
+ virtual void SetWritable() = 0;
+
+ // Returns the maximum size of the packet which can be written using this
+ // writer for the supplied peer address. This size may actually exceed the
+ // size of a valid QUIC packet.
+ virtual QuicByteCount GetMaxPacketSize(
+ const IPEndPoint& peer_address) const = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_PACKET_WRITER_H_
diff --git a/chromium/net/quic/core/quic_protocol.cc b/chromium/net/quic/core/quic_protocol.cc
new file mode 100644
index 00000000000..4053dc09926
--- /dev/null
+++ b/chromium/net/quic/core/quic_protocol.cc
@@ -0,0 +1,884 @@
+// 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/quic_protocol.h"
+
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+
+using base::StringPiece;
+using std::map;
+using std::numeric_limits;
+using std::ostream;
+using std::string;
+
+namespace net {
+
+const char* const kFinalOffsetHeaderKey = ":final-offset";
+
+size_t GetPacketHeaderSize(QuicVersion version,
+ const QuicPacketHeader& header) {
+ return GetPacketHeaderSize(version, header.public_header.connection_id_length,
+ header.public_header.version_flag,
+ header.public_header.multipath_flag,
+ header.public_header.nonce != nullptr,
+ header.public_header.packet_number_length);
+}
+
+size_t GetPacketHeaderSize(QuicVersion version,
+ QuicConnectionIdLength connection_id_length,
+ bool include_version,
+ bool include_path_id,
+ bool include_diversification_nonce,
+ QuicPacketNumberLength packet_number_length) {
+ return kPublicFlagsSize + connection_id_length +
+ (include_version ? kQuicVersionSize : 0) +
+ (include_path_id ? kQuicPathIdSize : 0) + packet_number_length +
+ (include_diversification_nonce ? kDiversificationNonceSize : 0) +
+ (version <= QUIC_VERSION_33 ? kPrivateFlagsSize : 0);
+}
+
+size_t GetStartOfEncryptedData(QuicVersion version,
+ const QuicPacketHeader& header) {
+ return GetPacketHeaderSize(version, header) -
+ (version <= QUIC_VERSION_33 ? kPrivateFlagsSize : 0);
+}
+
+size_t GetStartOfEncryptedData(QuicVersion version,
+ QuicConnectionIdLength connection_id_length,
+ bool include_version,
+ bool include_path_id,
+ bool include_diversification_nonce,
+ QuicPacketNumberLength packet_number_length) {
+ // Encryption starts before private flags.
+ return GetPacketHeaderSize(version, connection_id_length, include_version,
+ include_path_id, include_diversification_nonce,
+ packet_number_length) -
+ (version <= QUIC_VERSION_33 ? kPrivateFlagsSize : 0);
+}
+
+QuicPacketPublicHeader::QuicPacketPublicHeader()
+ : connection_id(0),
+ connection_id_length(PACKET_8BYTE_CONNECTION_ID),
+ multipath_flag(false),
+ reset_flag(false),
+ version_flag(false),
+ packet_number_length(PACKET_6BYTE_PACKET_NUMBER),
+ nonce(nullptr) {}
+
+QuicPacketPublicHeader::QuicPacketPublicHeader(
+ const QuicPacketPublicHeader& other) = default;
+
+QuicPacketPublicHeader::~QuicPacketPublicHeader() {}
+
+QuicPacketHeader::QuicPacketHeader()
+ : packet_number(0),
+ path_id(kDefaultPathId),
+ entropy_flag(false),
+ entropy_hash(0),
+ fec_flag(false) {}
+
+QuicPacketHeader::QuicPacketHeader(const QuicPacketPublicHeader& header)
+ : public_header(header),
+ packet_number(0),
+ path_id(kDefaultPathId),
+ entropy_flag(false),
+ entropy_hash(0),
+ fec_flag(false) {}
+
+QuicPacketHeader::QuicPacketHeader(const QuicPacketHeader& other) = default;
+
+QuicPublicResetPacket::QuicPublicResetPacket()
+ : nonce_proof(0), rejected_packet_number(0) {}
+
+QuicPublicResetPacket::QuicPublicResetPacket(
+ const QuicPacketPublicHeader& header)
+ : public_header(header), nonce_proof(0), rejected_packet_number(0) {}
+
+QuicBufferAllocator::~QuicBufferAllocator() = default;
+
+void StreamBufferDeleter::operator()(char* buffer) const {
+ if (allocator_ != nullptr && buffer != nullptr) {
+ allocator_->Delete(buffer);
+ }
+}
+
+UniqueStreamBuffer NewStreamBuffer(QuicBufferAllocator* allocator,
+ size_t size) {
+ return UniqueStreamBuffer(allocator->New(size),
+ StreamBufferDeleter(allocator));
+}
+
+QuicStreamFrame::QuicStreamFrame()
+ : QuicStreamFrame(0, false, 0, nullptr, 0, nullptr) {}
+
+QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
+ bool fin,
+ QuicStreamOffset offset,
+ StringPiece data)
+ : QuicStreamFrame(stream_id,
+ fin,
+ offset,
+ data.data(),
+ data.length(),
+ nullptr) {}
+
+QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
+ bool fin,
+ QuicStreamOffset offset,
+ QuicPacketLength data_length,
+ UniqueStreamBuffer buffer)
+ : QuicStreamFrame(stream_id,
+ fin,
+ offset,
+ nullptr,
+ data_length,
+ std::move(buffer)) {
+ DCHECK(this->buffer != nullptr);
+ DCHECK_EQ(data_buffer, this->buffer.get());
+}
+
+QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
+ bool fin,
+ QuicStreamOffset offset,
+ const char* data_buffer,
+ QuicPacketLength data_length,
+ UniqueStreamBuffer buffer)
+ : stream_id(stream_id),
+ fin(fin),
+ data_length(data_length),
+ data_buffer(data_buffer),
+ offset(offset),
+ buffer(std::move(buffer)) {
+ if (this->buffer != nullptr) {
+ DCHECK(data_buffer == nullptr);
+ this->data_buffer = this->buffer.get();
+ }
+}
+
+QuicStreamFrame::~QuicStreamFrame() {}
+
+uint32_t MakeQuicTag(char a, char b, char c, char d) {
+ return static_cast<uint32_t>(a) | static_cast<uint32_t>(b) << 8 |
+ static_cast<uint32_t>(c) << 16 | static_cast<uint32_t>(d) << 24;
+}
+
+bool ContainsQuicTag(const QuicTagVector& tag_vector, QuicTag tag) {
+ return std::find(tag_vector.begin(), tag_vector.end(), tag) !=
+ tag_vector.end();
+}
+
+QuicVersionVector AllSupportedVersions() {
+ QuicVersionVector supported_versions;
+ for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
+ supported_versions.push_back(kSupportedQuicVersions[i]);
+ }
+ return supported_versions;
+}
+
+QuicVersionVector CurrentSupportedVersions() {
+ return FilterSupportedVersions(AllSupportedVersions());
+}
+
+QuicVersionVector FilterSupportedVersions(QuicVersionVector versions) {
+ QuicVersionVector filtered_versions(versions.size());
+ filtered_versions.clear(); // Guaranteed by spec not to change capacity.
+ for (QuicVersion version : versions) {
+ if (version < QUIC_VERSION_32) {
+ if (!FLAGS_quic_disable_pre_32 && !FLAGS_quic_disable_pre_34) {
+ filtered_versions.push_back(version);
+ }
+ } else if (version < QUIC_VERSION_34) {
+ if (!FLAGS_quic_disable_pre_34) {
+ filtered_versions.push_back(version);
+ }
+ } else if (version == QUIC_VERSION_35) {
+ if (FLAGS_quic_enable_version_35) {
+ filtered_versions.push_back(version);
+ }
+ } else if (version == QUIC_VERSION_36) {
+ if (FLAGS_quic_enable_version_35 && FLAGS_quic_enable_version_36_v2) {
+ filtered_versions.push_back(version);
+ }
+ } else {
+ filtered_versions.push_back(version);
+ }
+ }
+ return filtered_versions;
+}
+
+QuicVersionVector VersionOfIndex(const QuicVersionVector& versions, int index) {
+ QuicVersionVector version;
+ int version_count = versions.size();
+ if (index >= 0 && index < version_count) {
+ version.push_back(versions[index]);
+ } else {
+ version.push_back(QUIC_VERSION_UNSUPPORTED);
+ }
+ return version;
+}
+
+QuicTag QuicVersionToQuicTag(const QuicVersion version) {
+ switch (version) {
+ case QUIC_VERSION_30:
+ return MakeQuicTag('Q', '0', '3', '0');
+ case QUIC_VERSION_31:
+ return MakeQuicTag('Q', '0', '3', '1');
+ case QUIC_VERSION_32:
+ return MakeQuicTag('Q', '0', '3', '2');
+ case QUIC_VERSION_33:
+ return MakeQuicTag('Q', '0', '3', '3');
+ case QUIC_VERSION_34:
+ return MakeQuicTag('Q', '0', '3', '4');
+ case QUIC_VERSION_35:
+ return MakeQuicTag('Q', '0', '3', '5');
+ case QUIC_VERSION_36:
+ return MakeQuicTag('Q', '0', '3', '6');
+ default:
+ // This shold be an ERROR because we should never attempt to convert an
+ // invalid QuicVersion to be written to the wire.
+ LOG(ERROR) << "Unsupported QuicVersion: " << version;
+ return 0;
+ }
+}
+
+QuicVersion QuicTagToQuicVersion(const QuicTag version_tag) {
+ for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
+ if (version_tag == QuicVersionToQuicTag(kSupportedQuicVersions[i])) {
+ return kSupportedQuicVersions[i];
+ }
+ }
+ // Reading from the client so this should not be considered an ERROR.
+ DVLOG(1) << "Unsupported QuicTag version: "
+ << QuicUtils::TagToString(version_tag);
+ return QUIC_VERSION_UNSUPPORTED;
+}
+
+#define RETURN_STRING_LITERAL(x) \
+ case x: \
+ return #x
+
+string QuicVersionToString(const QuicVersion version) {
+ switch (version) {
+ RETURN_STRING_LITERAL(QUIC_VERSION_30);
+ RETURN_STRING_LITERAL(QUIC_VERSION_31);
+ RETURN_STRING_LITERAL(QUIC_VERSION_32);
+ RETURN_STRING_LITERAL(QUIC_VERSION_33);
+ RETURN_STRING_LITERAL(QUIC_VERSION_34);
+ RETURN_STRING_LITERAL(QUIC_VERSION_35);
+ RETURN_STRING_LITERAL(QUIC_VERSION_36);
+ default:
+ return "QUIC_VERSION_UNSUPPORTED";
+ }
+}
+
+string QuicVersionVectorToString(const QuicVersionVector& versions) {
+ string result = "";
+ for (size_t i = 0; i < versions.size(); ++i) {
+ if (i != 0) {
+ result.append(",");
+ }
+ result.append(QuicVersionToString(versions[i]));
+ }
+ return result;
+}
+
+ostream& operator<<(ostream& os, const Perspective& s) {
+ if (s == Perspective::IS_SERVER) {
+ os << "IS_SERVER";
+ } else {
+ os << "IS_CLIENT";
+ }
+ return os;
+}
+
+ostream& operator<<(ostream& os, const QuicPacketHeader& header) {
+ os << "{ connection_id: " << header.public_header.connection_id
+ << ", connection_id_length: " << header.public_header.connection_id_length
+ << ", packet_number_length: " << header.public_header.packet_number_length
+ << ", multipath_flag: " << header.public_header.multipath_flag
+ << ", reset_flag: " << header.public_header.reset_flag
+ << ", version_flag: " << header.public_header.version_flag;
+ if (header.public_header.version_flag) {
+ os << ", version:";
+ for (size_t i = 0; i < header.public_header.versions.size(); ++i) {
+ os << " ";
+ os << QuicVersionToString(header.public_header.versions[i]);
+ }
+ }
+ if (header.public_header.nonce != nullptr) {
+ os << ", diversification_nonce: "
+ << QuicUtils::HexEncode(StringPiece(header.public_header.nonce->data(),
+ header.public_header.nonce->size()));
+ }
+ os << ", fec_flag: " << header.fec_flag
+ << ", entropy_flag: " << header.entropy_flag
+ << ", entropy hash: " << static_cast<int>(header.entropy_hash)
+ << ", path_id: " << static_cast<int>(header.path_id)
+ << ", packet_number: " << header.packet_number << " }\n";
+ return os;
+}
+
+bool IsAwaitingPacket(const QuicAckFrame& ack_frame,
+ QuicPacketNumber packet_number,
+ QuicPacketNumber peer_least_packet_awaiting_ack) {
+ if (ack_frame.missing) {
+ return packet_number > ack_frame.largest_observed ||
+ ack_frame.packets.Contains(packet_number);
+ }
+ return packet_number >= peer_least_packet_awaiting_ack &&
+ !ack_frame.packets.Contains(packet_number);
+}
+
+QuicStopWaitingFrame::QuicStopWaitingFrame()
+ : path_id(kDefaultPathId), entropy_hash(0), least_unacked(0) {}
+
+QuicStopWaitingFrame::~QuicStopWaitingFrame() {}
+
+QuicAckFrame::QuicAckFrame()
+ : largest_observed(0),
+ ack_delay_time(QuicTime::Delta::Infinite()),
+ path_id(kDefaultPathId),
+ entropy_hash(0),
+ is_truncated(false),
+ missing(true) {}
+
+QuicAckFrame::QuicAckFrame(const QuicAckFrame& other) = default;
+
+QuicAckFrame::~QuicAckFrame() {}
+
+QuicRstStreamErrorCode AdjustErrorForVersion(QuicRstStreamErrorCode error_code,
+ QuicVersion /*version*/) {
+ return error_code;
+}
+
+QuicRstStreamFrame::QuicRstStreamFrame()
+ : stream_id(0), error_code(QUIC_STREAM_NO_ERROR), byte_offset(0) {}
+
+QuicRstStreamFrame::QuicRstStreamFrame(QuicStreamId stream_id,
+ QuicRstStreamErrorCode error_code,
+ QuicStreamOffset bytes_written)
+ : stream_id(stream_id),
+ error_code(error_code),
+ byte_offset(bytes_written) {}
+
+QuicConnectionCloseFrame::QuicConnectionCloseFrame()
+ : error_code(QUIC_NO_ERROR) {}
+
+QuicFrame::QuicFrame() {}
+
+QuicFrame::QuicFrame(QuicPaddingFrame padding_frame)
+ : type(PADDING_FRAME), padding_frame(padding_frame) {}
+
+QuicFrame::QuicFrame(QuicStreamFrame* stream_frame)
+ : type(STREAM_FRAME), stream_frame(stream_frame) {}
+
+QuicFrame::QuicFrame(QuicAckFrame* frame) : type(ACK_FRAME), ack_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicMtuDiscoveryFrame frame)
+ : type(MTU_DISCOVERY_FRAME), mtu_discovery_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicStopWaitingFrame* frame)
+ : type(STOP_WAITING_FRAME), stop_waiting_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicPingFrame frame)
+ : type(PING_FRAME), ping_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicRstStreamFrame* frame)
+ : type(RST_STREAM_FRAME), rst_stream_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicConnectionCloseFrame* frame)
+ : type(CONNECTION_CLOSE_FRAME), connection_close_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicGoAwayFrame* frame)
+ : type(GOAWAY_FRAME), goaway_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicWindowUpdateFrame* frame)
+ : type(WINDOW_UPDATE_FRAME), window_update_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicBlockedFrame* frame)
+ : type(BLOCKED_FRAME), blocked_frame(frame) {}
+
+QuicFrame::QuicFrame(QuicPathCloseFrame* frame)
+ : type(PATH_CLOSE_FRAME), path_close_frame(frame) {}
+
+ostream& operator<<(ostream& os, const QuicStopWaitingFrame& sent_info) {
+ os << "{ entropy_hash: " << static_cast<int>(sent_info.entropy_hash)
+ << ", least_unacked: " << sent_info.least_unacked << " }\n";
+ return os;
+}
+
+PacketNumberQueue::PacketNumberQueue() = default;
+PacketNumberQueue::PacketNumberQueue(const PacketNumberQueue& other) = default;
+// TODO(rtenneti): on windows RValue reference gives errors.
+// PacketNumberQueue::PacketNumberQueue(PacketNumberQueue&& other) = default;
+PacketNumberQueue::~PacketNumberQueue() {}
+
+PacketNumberQueue& PacketNumberQueue::operator=(
+ const PacketNumberQueue& other) = default;
+// TODO(rtenneti): on windows RValue reference gives errors.
+// PacketNumberQueue& PacketNumberQueue::operator=(PacketNumberQueue&& other) =
+// default;
+
+void PacketNumberQueue::Add(QuicPacketNumber packet_number) {
+ packet_number_intervals_.Add(packet_number, packet_number + 1);
+}
+
+void PacketNumberQueue::Add(QuicPacketNumber lower, QuicPacketNumber higher) {
+ packet_number_intervals_.Add(lower, higher);
+}
+
+void PacketNumberQueue::Remove(QuicPacketNumber packet_number) {
+ packet_number_intervals_.Difference(packet_number, packet_number + 1);
+}
+
+void PacketNumberQueue::Remove(QuicPacketNumber lower,
+ QuicPacketNumber higher) {
+ packet_number_intervals_.Difference(lower, higher);
+}
+
+bool PacketNumberQueue::RemoveUpTo(QuicPacketNumber higher) {
+ if (Empty()) {
+ return false;
+ }
+ const QuicPacketNumber old_min = Min();
+ packet_number_intervals_.Difference(0, higher);
+ return Empty() || old_min != Min();
+}
+
+void PacketNumberQueue::Complement() {
+ if (Empty()) {
+ return;
+ }
+ packet_number_intervals_.Complement(Min(), Max() + 1);
+}
+
+bool PacketNumberQueue::Contains(QuicPacketNumber packet_number) const {
+ return packet_number_intervals_.Contains(packet_number);
+}
+
+bool PacketNumberQueue::Empty() const {
+ return packet_number_intervals_.Empty();
+}
+
+QuicPacketNumber PacketNumberQueue::Min() const {
+ DCHECK(!Empty());
+ return packet_number_intervals_.begin()->min();
+}
+
+QuicPacketNumber PacketNumberQueue::Max() const {
+ DCHECK(!Empty());
+ return packet_number_intervals_.rbegin()->max() - 1;
+}
+
+size_t PacketNumberQueue::NumPacketsSlow() const {
+ size_t num_packets = 0;
+ for (const auto& interval : packet_number_intervals_) {
+ num_packets += interval.Length();
+ }
+ return num_packets;
+}
+
+size_t PacketNumberQueue::NumIntervals() const {
+ return packet_number_intervals_.Size();
+}
+
+QuicPacketNumber PacketNumberQueue::LastIntervalLength() const {
+ DCHECK(!Empty());
+ return packet_number_intervals_.rbegin()->Length();
+}
+
+PacketNumberQueue::const_iterator PacketNumberQueue::lower_bound(
+ QuicPacketNumber packet_number) const {
+ // lower_bound returns the first interval that contains |packet_number| or the
+ // first interval after |packet_number|.
+ auto itr = packet_number_intervals_.Find(packet_number);
+ if (itr != packet_number_intervals_.end()) {
+ return itr;
+ }
+ for (itr = packet_number_intervals_.begin();
+ itr != packet_number_intervals_.end(); ++itr) {
+ if (packet_number < itr->min()) {
+ return itr;
+ }
+ }
+ return packet_number_intervals_.end();
+}
+
+PacketNumberQueue::const_iterator PacketNumberQueue::begin() const {
+ return packet_number_intervals_.begin();
+}
+
+PacketNumberQueue::const_iterator PacketNumberQueue::end() const {
+ return packet_number_intervals_.end();
+}
+
+PacketNumberQueue::const_reverse_iterator PacketNumberQueue::rbegin() const {
+ return packet_number_intervals_.rbegin();
+}
+
+PacketNumberQueue::const_reverse_iterator PacketNumberQueue::rend() const {
+ return packet_number_intervals_.rend();
+}
+
+ostream& operator<<(ostream& os, const PacketNumberQueue& q) {
+ for (const Interval<QuicPacketNumber>& interval : q) {
+ for (QuicPacketNumber packet_number = interval.min();
+ packet_number < interval.max(); ++packet_number) {
+ os << packet_number << " ";
+ }
+ }
+ return os;
+}
+
+ostream& operator<<(ostream& os, const QuicAckFrame& ack_frame) {
+ os << "{ entropy_hash: " << static_cast<int>(ack_frame.entropy_hash)
+ << ", largest_observed: " << ack_frame.largest_observed
+ << ", ack_delay_time: " << ack_frame.ack_delay_time.ToMicroseconds()
+ << ", packets: [ " << ack_frame.packets << " ]"
+ << ", is_truncated: " << ack_frame.is_truncated
+ << ", received_packets: [ ";
+ for (const std::pair<QuicPacketNumber, QuicTime>& p :
+ ack_frame.received_packet_times) {
+ os << p.first << " at " << p.second.ToDebuggingValue() << " ";
+ }
+ os << " ] }\n";
+ return os;
+}
+
+ostream& operator<<(ostream& os, const QuicFrame& frame) {
+ switch (frame.type) {
+ case PADDING_FRAME: {
+ os << "type { PADDING_FRAME } " << frame.padding_frame;
+ break;
+ }
+ case RST_STREAM_FRAME: {
+ os << "type { RST_STREAM_FRAME } " << *(frame.rst_stream_frame);
+ break;
+ }
+ case CONNECTION_CLOSE_FRAME: {
+ os << "type { CONNECTION_CLOSE_FRAME } "
+ << *(frame.connection_close_frame);
+ break;
+ }
+ case GOAWAY_FRAME: {
+ os << "type { GOAWAY_FRAME } " << *(frame.goaway_frame);
+ break;
+ }
+ case WINDOW_UPDATE_FRAME: {
+ os << "type { WINDOW_UPDATE_FRAME } " << *(frame.window_update_frame);
+ break;
+ }
+ case BLOCKED_FRAME: {
+ os << "type { BLOCKED_FRAME } " << *(frame.blocked_frame);
+ break;
+ }
+ case STREAM_FRAME: {
+ os << "type { STREAM_FRAME } " << *(frame.stream_frame);
+ break;
+ }
+ case ACK_FRAME: {
+ os << "type { ACK_FRAME } " << *(frame.ack_frame);
+ break;
+ }
+ case STOP_WAITING_FRAME: {
+ os << "type { STOP_WAITING_FRAME } " << *(frame.stop_waiting_frame);
+ break;
+ }
+ case PING_FRAME: {
+ os << "type { PING_FRAME } ";
+ break;
+ }
+ case MTU_DISCOVERY_FRAME: {
+ os << "type { MTU_DISCOVERY_FRAME } ";
+ break;
+ }
+ case PATH_CLOSE_FRAME: {
+ os << "type { PATH_CLOSE_FRAME } " << *(frame.path_close_frame);
+ break;
+ }
+ default: {
+ LOG(ERROR) << "Unknown frame type: " << frame.type;
+ break;
+ }
+ }
+ return os;
+}
+
+ostream& operator<<(ostream& os, const QuicPaddingFrame& padding_frame) {
+ os << "{ num_padding_bytes: " << padding_frame.num_padding_bytes << " }\n";
+ return os;
+}
+
+ostream& operator<<(ostream& os, const QuicRstStreamFrame& rst_frame) {
+ os << "{ stream_id: " << rst_frame.stream_id
+ << ", error_code: " << rst_frame.error_code << " }\n";
+ return os;
+}
+
+ostream& operator<<(ostream& os,
+ const QuicConnectionCloseFrame& connection_close_frame) {
+ os << "{ error_code: " << connection_close_frame.error_code
+ << ", error_details: '" << connection_close_frame.error_details << "' }\n";
+ return os;
+}
+
+ostream& operator<<(ostream& os, const QuicGoAwayFrame& goaway_frame) {
+ os << "{ error_code: " << goaway_frame.error_code
+ << ", last_good_stream_id: " << goaway_frame.last_good_stream_id
+ << ", reason_phrase: '" << goaway_frame.reason_phrase << "' }\n";
+ return os;
+}
+
+ostream& operator<<(ostream& os,
+ const QuicWindowUpdateFrame& window_update_frame) {
+ os << "{ stream_id: " << window_update_frame.stream_id
+ << ", byte_offset: " << window_update_frame.byte_offset << " }\n";
+ return os;
+}
+
+ostream& operator<<(ostream& os, const QuicBlockedFrame& blocked_frame) {
+ os << "{ stream_id: " << blocked_frame.stream_id << " }\n";
+ return os;
+}
+
+ostream& operator<<(ostream& os, const QuicPathCloseFrame& path_close_frame) {
+ os << "{ path_id: " << static_cast<int>(path_close_frame.path_id) << " }\n";
+ return os;
+}
+
+ostream& operator<<(ostream& os, const QuicStreamFrame& stream_frame) {
+ os << "{ stream_id: " << stream_frame.stream_id
+ << ", fin: " << stream_frame.fin << ", offset: " << stream_frame.offset
+ << ", length: " << stream_frame.data_length << " }\n";
+ return os;
+}
+
+QuicGoAwayFrame::QuicGoAwayFrame()
+ : error_code(QUIC_NO_ERROR), last_good_stream_id(0) {}
+
+QuicGoAwayFrame::QuicGoAwayFrame(QuicErrorCode error_code,
+ QuicStreamId last_good_stream_id,
+ const string& reason)
+ : error_code(error_code),
+ last_good_stream_id(last_good_stream_id),
+ reason_phrase(reason) {}
+
+QuicData::QuicData(const char* buffer, size_t length)
+ : buffer_(buffer), length_(length), owns_buffer_(false) {}
+
+QuicData::QuicData(const char* buffer, size_t length, bool owns_buffer)
+ : buffer_(buffer), length_(length), owns_buffer_(owns_buffer) {}
+
+QuicData::~QuicData() {
+ if (owns_buffer_) {
+ delete[] const_cast<char*>(buffer_);
+ }
+}
+
+QuicWindowUpdateFrame::QuicWindowUpdateFrame(QuicStreamId stream_id,
+ QuicStreamOffset byte_offset)
+ : stream_id(stream_id), byte_offset(byte_offset) {}
+
+QuicBlockedFrame::QuicBlockedFrame(QuicStreamId stream_id)
+ : stream_id(stream_id) {}
+
+QuicPathCloseFrame::QuicPathCloseFrame(QuicPathId path_id) : path_id(path_id) {}
+
+QuicPacket::QuicPacket(char* buffer,
+ size_t length,
+ bool owns_buffer,
+ QuicConnectionIdLength connection_id_length,
+ bool includes_version,
+ bool includes_path_id,
+ bool includes_diversification_nonce,
+ QuicPacketNumberLength packet_number_length)
+ : QuicData(buffer, length, owns_buffer),
+ buffer_(buffer),
+ connection_id_length_(connection_id_length),
+ includes_version_(includes_version),
+ includes_path_id_(includes_path_id),
+ includes_diversification_nonce_(includes_diversification_nonce),
+ packet_number_length_(packet_number_length) {}
+
+QuicEncryptedPacket::QuicEncryptedPacket(const char* buffer, size_t length)
+ : QuicData(buffer, length) {}
+
+QuicEncryptedPacket::QuicEncryptedPacket(const char* buffer,
+ size_t length,
+ bool owns_buffer)
+ : QuicData(buffer, length, owns_buffer) {}
+
+QuicEncryptedPacket* QuicEncryptedPacket::Clone() const {
+ char* buffer = new char[this->length()];
+ memcpy(buffer, this->data(), this->length());
+ return new QuicEncryptedPacket(buffer, this->length(), true);
+}
+
+ostream& operator<<(ostream& os, const QuicEncryptedPacket& s) {
+ os << s.length() << "-byte data";
+ return os;
+}
+
+QuicReceivedPacket::QuicReceivedPacket(const char* buffer,
+ size_t length,
+ QuicTime receipt_time)
+ : QuicReceivedPacket(buffer,
+ length,
+ receipt_time,
+ false /* owns_buffer */) {}
+
+QuicReceivedPacket::QuicReceivedPacket(const char* buffer,
+ size_t length,
+ QuicTime receipt_time,
+ bool owns_buffer)
+ : QuicReceivedPacket(buffer,
+ length,
+ receipt_time,
+ owns_buffer,
+ false /* potentially_small_mtu */,
+ -1 /* ttl */,
+ false /* ttl_valid */) {}
+
+QuicReceivedPacket::QuicReceivedPacket(const char* buffer,
+ size_t length,
+ QuicTime receipt_time,
+ bool owns_buffer,
+ bool potentially_small_mtu,
+ int ttl,
+ bool ttl_valid)
+ : QuicEncryptedPacket(buffer, length, owns_buffer),
+ receipt_time_(receipt_time),
+ ttl_(ttl_valid ? ttl : -1),
+ potentially_small_mtu_(potentially_small_mtu) {}
+
+QuicReceivedPacket* QuicReceivedPacket::Clone() const {
+ char* buffer = new char[this->length()];
+ memcpy(buffer, this->data(), this->length());
+ return new QuicReceivedPacket(buffer, this->length(), receipt_time(), true,
+ potentially_small_mtu(), ttl(), ttl() >= 0);
+}
+
+ostream& operator<<(ostream& os, const QuicReceivedPacket& s) {
+ os << s.length() << "-byte data";
+ return os;
+}
+
+StringPiece QuicPacket::AssociatedData(QuicVersion version) const {
+ return StringPiece(
+ data(), GetStartOfEncryptedData(version, connection_id_length_,
+ includes_version_, includes_path_id_,
+ includes_diversification_nonce_,
+ packet_number_length_));
+}
+
+StringPiece QuicPacket::Plaintext(QuicVersion version) const {
+ const size_t start_of_encrypted_data = GetStartOfEncryptedData(
+ version, connection_id_length_, includes_version_, includes_path_id_,
+ includes_diversification_nonce_, packet_number_length_);
+ return StringPiece(data() + start_of_encrypted_data,
+ length() - start_of_encrypted_data);
+}
+
+QuicVersionManager::QuicVersionManager(QuicVersionVector supported_versions)
+ : disable_pre_32_(FLAGS_quic_disable_pre_32),
+ disable_pre_34_(FLAGS_quic_disable_pre_34),
+ enable_version_35_(FLAGS_quic_enable_version_35),
+ enable_version_36_(FLAGS_quic_enable_version_36_v2),
+ allowed_supported_versions_(supported_versions),
+ filtered_supported_versions_(
+ FilterSupportedVersions(supported_versions)) {}
+
+QuicVersionManager::~QuicVersionManager() {}
+
+const QuicVersionVector& QuicVersionManager::GetSupportedVersions() {
+ if (disable_pre_32_ != FLAGS_quic_disable_pre_32 ||
+ disable_pre_34_ != FLAGS_quic_disable_pre_34 ||
+ enable_version_35_ != FLAGS_quic_enable_version_35 ||
+ enable_version_36_ != FLAGS_quic_enable_version_36_v2) {
+ disable_pre_32_ = FLAGS_quic_disable_pre_32;
+ disable_pre_34_ = FLAGS_quic_disable_pre_34;
+ enable_version_35_ = FLAGS_quic_enable_version_35;
+ enable_version_36_ = FLAGS_quic_enable_version_36_v2;
+ filtered_supported_versions_ =
+ FilterSupportedVersions(allowed_supported_versions_);
+ }
+ return filtered_supported_versions_;
+}
+
+AckListenerWrapper::AckListenerWrapper(QuicAckListenerInterface* listener,
+ QuicPacketLength data_length)
+ : ack_listener(listener), length(data_length) {
+ DCHECK(listener != nullptr);
+}
+
+AckListenerWrapper::AckListenerWrapper(const AckListenerWrapper& other) =
+ default;
+
+AckListenerWrapper::~AckListenerWrapper() {}
+
+SerializedPacket::SerializedPacket(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ QuicPacketNumberLength packet_number_length,
+ const char* encrypted_buffer,
+ QuicPacketLength encrypted_length,
+ QuicPacketEntropyHash entropy_hash,
+ bool has_ack,
+ bool has_stop_waiting)
+ : encrypted_buffer(encrypted_buffer),
+ encrypted_length(encrypted_length),
+ has_crypto_handshake(NOT_HANDSHAKE),
+ num_padding_bytes(0),
+ path_id(path_id),
+ packet_number(packet_number),
+ packet_number_length(packet_number_length),
+ encryption_level(ENCRYPTION_NONE),
+ entropy_hash(entropy_hash),
+ has_ack(has_ack),
+ has_stop_waiting(has_stop_waiting),
+ transmission_type(NOT_RETRANSMISSION),
+ original_path_id(kInvalidPathId),
+ original_packet_number(0) {}
+
+SerializedPacket::SerializedPacket(const SerializedPacket& other) = default;
+
+SerializedPacket::~SerializedPacket() {}
+
+TransmissionInfo::TransmissionInfo()
+ : encryption_level(ENCRYPTION_NONE),
+ packet_number_length(PACKET_1BYTE_PACKET_NUMBER),
+ bytes_sent(0),
+ sent_time(QuicTime::Zero()),
+ transmission_type(NOT_RETRANSMISSION),
+ in_flight(false),
+ is_unackable(false),
+ has_crypto_handshake(false),
+ num_padding_bytes(0),
+ retransmission(0) {}
+
+TransmissionInfo::TransmissionInfo(EncryptionLevel level,
+ QuicPacketNumberLength packet_number_length,
+ TransmissionType transmission_type,
+ QuicTime sent_time,
+ QuicPacketLength bytes_sent,
+ bool has_crypto_handshake,
+ int num_padding_bytes)
+ : encryption_level(level),
+ packet_number_length(packet_number_length),
+ bytes_sent(bytes_sent),
+ sent_time(sent_time),
+ transmission_type(transmission_type),
+ in_flight(false),
+ is_unackable(false),
+ has_crypto_handshake(has_crypto_handshake),
+ num_padding_bytes(num_padding_bytes),
+ retransmission(0) {}
+
+TransmissionInfo::TransmissionInfo(const TransmissionInfo& other) = default;
+
+TransmissionInfo::~TransmissionInfo() {}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_protocol.h b/chromium/net/quic/core/quic_protocol.h
new file mode 100644
index 00000000000..ce9fd2591bb
--- /dev/null
+++ b/chromium/net/quic/core/quic_protocol.h
@@ -0,0 +1,1553 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_PROTOCOL_H_
+#define NET_QUIC_QUIC_PROTOCOL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <array>
+#include <limits>
+#include <list>
+#include <map>
+#include <memory>
+#include <ostream>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
+#include "net/base/int128.h"
+#include "net/base/iovec.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/interval_set.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_time.h"
+#include "net/quic/core/quic_types.h"
+
+namespace net {
+
+class QuicPacket;
+struct QuicPacketHeader;
+class QuicAckListenerInterface;
+
+typedef uint64_t QuicConnectionId;
+typedef uint32_t QuicStreamId;
+typedef uint64_t QuicStreamOffset;
+typedef uint64_t QuicPacketNumber;
+typedef uint8_t QuicPathId;
+typedef uint64_t QuicPublicResetNonceProof;
+typedef uint8_t QuicPacketEntropyHash;
+typedef uint32_t QuicHeaderId;
+// QuicTag is the type of a tag in the wire protocol.
+typedef uint32_t QuicTag;
+typedef std::vector<QuicTag> QuicTagVector;
+typedef std::map<QuicTag, std::string> QuicTagValueMap;
+typedef uint16_t QuicPacketLength;
+
+// Default initial maximum size in bytes of a QUIC packet.
+const QuicByteCount kDefaultMaxPacketSize = 1350;
+// Default initial maximum size in bytes of a QUIC packet for servers.
+const QuicByteCount kDefaultServerMaxPacketSize = 1000;
+// Minimum size of a QUIC packet, used if a server receives packets from a
+// client with unusual network headers. 1280 - sizeof(eth) - sizeof(ipv6).
+const QuicByteCount kMinimumSupportedPacketSize = 1214;
+// The maximum packet size of any QUIC packet, based on ethernet's max size,
+// minus the IP and UDP headers. IPv6 has a 40 byte header, UDP adds an
+// additional 8 bytes. This is a total overhead of 48 bytes. Ethernet's
+// max packet size is 1500 bytes, 1500 - 48 = 1452.
+const QuicByteCount kMaxPacketSize = 1452;
+// Default maximum packet size used in the Linux TCP implementation.
+// Used in QUIC for congestion window computations in bytes.
+const QuicByteCount kDefaultTCPMSS = 1460;
+
+// We match SPDY's use of 32 (since we'd compete with SPDY).
+const QuicPacketCount kInitialCongestionWindow = 32;
+
+// Minimum size of initial flow control window, for both stream and session.
+const uint32_t kMinimumFlowControlSendWindow = 16 * 1024; // 16 KB
+
+// Maximum flow control receive window limits for connection and stream.
+const QuicByteCount kStreamReceiveWindowLimit = 16 * 1024 * 1024; // 16 MB
+const QuicByteCount kSessionReceiveWindowLimit = 24 * 1024 * 1024; // 24 MB
+
+// Minimum size of the CWND, in packets, when doing bandwidth resumption.
+const QuicPacketCount kMinCongestionWindowForBandwidthResumption = 10;
+
+// Maximum number of tracked packets.
+const QuicPacketCount kMaxTrackedPackets = 10000;
+
+// Default size of the socket receive buffer in bytes.
+const QuicByteCount kDefaultSocketReceiveBuffer = 1024 * 1024;
+// Minimum size of the socket receive buffer in bytes.
+// Smaller values are ignored.
+const QuicByteCount kMinSocketReceiveBuffer = 16 * 1024;
+
+// Fraction of the receive buffer that can be used, based on conservative
+// estimates and testing on Linux.
+// An alternative to kUsableRecieveBufferFraction.
+static const float kConservativeReceiveBufferFraction = 0.6f;
+
+// Don't allow a client to suggest an RTT shorter than 10ms.
+const uint32_t kMinInitialRoundTripTimeUs = 10 * kNumMicrosPerMilli;
+
+// Don't allow a client to suggest an RTT longer than 15 seconds.
+const uint32_t kMaxInitialRoundTripTimeUs = 15 * kNumMicrosPerSecond;
+
+// Maximum number of open streams per connection.
+const size_t kDefaultMaxStreamsPerConnection = 100;
+
+// Number of bytes reserved for public flags in the packet header.
+const size_t kPublicFlagsSize = 1;
+// Number of bytes reserved for version number in the packet header.
+const size_t kQuicVersionSize = 4;
+// Number of bytes reserved for path id in the packet header.
+const size_t kQuicPathIdSize = 1;
+// Number of bytes reserved for private flags in the packet header.
+const size_t kPrivateFlagsSize = 1;
+
+// Signifies that the QuicPacket will contain version of the protocol.
+const bool kIncludeVersion = true;
+// Signifies that the QuicPacket will contain path id.
+const bool kIncludePathId = true;
+// Signifies that the QuicPacket will include a diversification nonce.
+const bool kIncludeDiversificationNonce = true;
+
+// Stream ID is reserved to denote an invalid ID.
+const QuicStreamId kInvalidStreamId = 0;
+
+// Reserved ID for the crypto stream.
+const QuicStreamId kCryptoStreamId = 1;
+
+// Reserved ID for the headers stream.
+const QuicStreamId kHeadersStreamId = 3;
+
+// Header key used to identify final offset on data stream when sending HTTP/2
+// trailing headers over QUIC.
+NET_EXPORT_PRIVATE extern const char* const kFinalOffsetHeaderKey;
+
+// Maximum delayed ack time, in ms.
+const int64_t kMaxDelayedAckTimeMs = 25;
+
+// Minimum tail loss probe time in ms.
+static const int64_t kMinTailLossProbeTimeoutMs = 10;
+
+// The timeout before the handshake succeeds.
+const int64_t kInitialIdleTimeoutSecs = 5;
+// The default idle timeout.
+const int64_t kDefaultIdleTimeoutSecs = 30;
+// The maximum idle timeout that can be negotiated.
+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.
+
+// Default limit on the number of undecryptable packets the connection buffers
+// before the CHLO/SHLO arrive.
+const size_t kDefaultMaxUndecryptablePackets = 10;
+
+// Default ping timeout.
+const int64_t kPingTimeoutSecs = 15; // 15 secs.
+
+// Minimum number of RTTs between Server Config Updates (SCUP) sent to client.
+const int kMinIntervalBetweenServerConfigUpdatesRTTs = 10;
+
+// Minimum time between Server Config Updates (SCUP) sent to client.
+const int kMinIntervalBetweenServerConfigUpdatesMs = 1000;
+
+// Minimum number of packets between Server Config Updates (SCUP).
+const int kMinPacketsBetweenServerConfigUpdates = 100;
+
+// The number of open streams that a server will accept is set to be slightly
+// larger than the negotiated limit. Immediately closing the connection if the
+// client opens slightly too many streams is not ideal: the client may have sent
+// a FIN that was lost, and simultaneously opened a new stream. The number of
+// streams a server accepts is a fixed increment over the negotiated limit, or a
+// percentage increase, whichever is larger.
+const float kMaxStreamsMultiplier = 1.1f;
+const int kMaxStreamsMinimumIncrement = 10;
+
+// Available streams are ones with IDs less than the highest stream that has
+// been opened which have neither been opened or reset. The limit on the number
+// of available streams is 10 times the limit on the number of open streams.
+const int kMaxAvailableStreamsMultiplier = 10;
+
+// Track the number of promises that are not yet claimed by a
+// corresponding get. This must be smaller than
+// kMaxAvailableStreamsMultiplier, because RST on a promised stream my
+// create available streams entries.
+const int kMaxPromisedStreamsMultiplier = kMaxAvailableStreamsMultiplier - 1;
+
+// TCP RFC calls for 1 second RTO however Linux differs from this default and
+// define the minimum RTO to 200ms, we will use the same until we have data to
+// support a higher or lower value.
+static const int64_t kMinRetransmissionTimeMs = 200;
+
+// We define an unsigned 16-bit floating point value, inspired by IEEE floats
+// (http://en.wikipedia.org/wiki/Half_precision_floating-point_format),
+// with 5-bit exponent (bias 1), 11-bit mantissa (effective 12 with hidden
+// bit) and denormals, but without signs, transfinites or fractions. Wire format
+// 16 bits (little-endian byte order) are split into exponent (high 5) and
+// mantissa (low 11) and decoded as:
+// uint64_t value;
+// if (exponent == 0) value = mantissa;
+// else value = (mantissa | 1 << 11) << (exponent - 1)
+const int kUFloat16ExponentBits = 5;
+const int kUFloat16MaxExponent = (1 << kUFloat16ExponentBits) - 2; // 30
+const int kUFloat16MantissaBits = 16 - kUFloat16ExponentBits; // 11
+const int kUFloat16MantissaEffectiveBits = kUFloat16MantissaBits + 1; // 12
+const uint64_t kUFloat16MaxValue = // 0x3FFC0000000
+ ((UINT64_C(1) << kUFloat16MantissaEffectiveBits) - 1)
+ << kUFloat16MaxExponent;
+
+// Default path ID.
+const QuicPathId kDefaultPathId = 0;
+// Invalid path ID.
+const QuicPathId kInvalidPathId = 0xff;
+
+// kDiversificationNonceSize is the size, in bytes, of the nonce that a server
+// may set in the packet header to ensure that its INITIAL keys are not
+// duplicated.
+const size_t kDiversificationNonceSize = 32;
+
+// The largest gap in packets we'll accept without closing the connection.
+// This will likely have to be tuned.
+const QuicPacketNumber kMaxPacketGap = 5000;
+
+enum TransmissionType : int8_t {
+ NOT_RETRANSMISSION,
+ FIRST_TRANSMISSION_TYPE = NOT_RETRANSMISSION,
+ HANDSHAKE_RETRANSMISSION, // Retransmits due to handshake timeouts.
+ ALL_UNACKED_RETRANSMISSION, // Retransmits all unacked packets.
+ ALL_INITIAL_RETRANSMISSION, // Retransmits all initially encrypted packets.
+ LOSS_RETRANSMISSION, // Retransmits due to loss detection.
+ RTO_RETRANSMISSION, // Retransmits due to retransmit time out.
+ TLP_RETRANSMISSION, // Tail loss probes.
+ LAST_TRANSMISSION_TYPE = TLP_RETRANSMISSION,
+};
+
+enum HasRetransmittableData : int8_t {
+ NO_RETRANSMITTABLE_DATA,
+ HAS_RETRANSMITTABLE_DATA,
+};
+
+enum IsHandshake : int8_t { NOT_HANDSHAKE, IS_HANDSHAKE };
+
+enum class Perspective { IS_SERVER, IS_CLIENT };
+
+// Describes whether a ConnectionClose was originated by the peer.
+enum class ConnectionCloseSource { FROM_PEER, FROM_SELF };
+
+// Should a connection be closed silently or not.
+enum class ConnectionCloseBehavior {
+ SILENT_CLOSE,
+ SEND_CONNECTION_CLOSE_PACKET,
+ SEND_CONNECTION_CLOSE_PACKET_WITH_NO_ACK
+};
+
+NET_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
+ const Perspective& s);
+enum QuicFrameType {
+ // Regular frame types. The values set here cannot change without the
+ // introduction of a new QUIC version.
+ PADDING_FRAME = 0,
+ RST_STREAM_FRAME = 1,
+ CONNECTION_CLOSE_FRAME = 2,
+ GOAWAY_FRAME = 3,
+ WINDOW_UPDATE_FRAME = 4,
+ BLOCKED_FRAME = 5,
+ STOP_WAITING_FRAME = 6,
+ PING_FRAME = 7,
+ PATH_CLOSE_FRAME = 8,
+
+ // STREAM and ACK frames are special frames. They are encoded differently on
+ // the wire and their values do not need to be stable.
+ STREAM_FRAME,
+ ACK_FRAME,
+ // The path MTU discovery frame is encoded as a PING frame on the wire.
+ MTU_DISCOVERY_FRAME,
+ NUM_FRAME_TYPES
+};
+
+enum QuicConnectionIdLength {
+ PACKET_0BYTE_CONNECTION_ID = 0,
+ PACKET_8BYTE_CONNECTION_ID = 8
+};
+
+enum QuicPacketNumberLength : int8_t {
+ PACKET_1BYTE_PACKET_NUMBER = 1,
+ PACKET_2BYTE_PACKET_NUMBER = 2,
+ PACKET_4BYTE_PACKET_NUMBER = 4,
+ PACKET_6BYTE_PACKET_NUMBER = 6
+};
+
+// Used to indicate a QuicSequenceNumberLength using two flag bits.
+enum QuicPacketNumberLengthFlags {
+ PACKET_FLAGS_1BYTE_PACKET = 0, // 00
+ PACKET_FLAGS_2BYTE_PACKET = 1, // 01
+ PACKET_FLAGS_4BYTE_PACKET = 1 << 1, // 10
+ PACKET_FLAGS_6BYTE_PACKET = 1 << 1 | 1, // 11
+};
+
+// The public flags are specified in one byte.
+enum QuicPacketPublicFlags {
+ PACKET_PUBLIC_FLAGS_NONE = 0,
+
+ // Bit 0: Does the packet header contains version info?
+ PACKET_PUBLIC_FLAGS_VERSION = 1 << 0,
+
+ // Bit 1: Is this packet a public reset packet?
+ PACKET_PUBLIC_FLAGS_RST = 1 << 1,
+
+ // Bit 2: indicates the that public header includes a nonce.
+ PACKET_PUBLIC_FLAGS_NONCE = 1 << 2,
+
+ // Bit 3: indicates whether a ConnectionID is included.
+ PACKET_PUBLIC_FLAGS_0BYTE_CONNECTION_ID = 0,
+ PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID = 1 << 3,
+
+ // QUIC_VERSION_32 and earlier use two bits for an 8 byte
+ // connection id.
+ PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD = 1 << 3 | 1 << 2,
+
+ // Bits 4 and 5 describe the packet number length as follows:
+ // --00----: 1 byte
+ // --01----: 2 bytes
+ // --10----: 4 bytes
+ // --11----: 6 bytes
+ PACKET_PUBLIC_FLAGS_1BYTE_PACKET = PACKET_FLAGS_1BYTE_PACKET << 4,
+ PACKET_PUBLIC_FLAGS_2BYTE_PACKET = PACKET_FLAGS_2BYTE_PACKET << 4,
+ PACKET_PUBLIC_FLAGS_4BYTE_PACKET = PACKET_FLAGS_4BYTE_PACKET << 4,
+ PACKET_PUBLIC_FLAGS_6BYTE_PACKET = PACKET_FLAGS_6BYTE_PACKET << 4,
+
+ // Bit 6: Does the packet header contain a path id?
+ PACKET_PUBLIC_FLAGS_MULTIPATH = 1 << 6,
+
+ // Reserved, unimplemented flags:
+
+ // Bit 7: indicates the presence of a second flags byte.
+ PACKET_PUBLIC_FLAGS_TWO_OR_MORE_BYTES = 1 << 7,
+
+ // All bits set (bit 7 is not currently used): 01111111
+ PACKET_PUBLIC_FLAGS_MAX = (1 << 7) - 1,
+};
+
+// The private flags are specified in one byte.
+enum QuicPacketPrivateFlags {
+ PACKET_PRIVATE_FLAGS_NONE = 0,
+
+ // Bit 0: Does this packet contain an entropy bit?
+ PACKET_PRIVATE_FLAGS_ENTROPY = 1 << 0,
+
+ // Bit 1: Payload is part of an FEC group?
+ PACKET_PRIVATE_FLAGS_FEC_GROUP = 1 << 1,
+
+ // Bit 2: Payload is FEC as opposed to frames?
+ PACKET_PRIVATE_FLAGS_FEC = 1 << 2,
+
+ // All bits set (bits 3-7 are not currently used): 00000111
+ PACKET_PRIVATE_FLAGS_MAX = (1 << 3) - 1,
+
+ // For version 32 (bits 1-7 are not used): 00000001
+ PACKET_PRIVATE_FLAGS_MAX_VERSION_32 = (1 << 1) - 1
+};
+
+// The available versions of QUIC. Guaranteed that the integer value of the enum
+// will match the version number.
+// When adding a new version to this enum you should add it to
+// kSupportedQuicVersions (if appropriate), and also add a new case to the
+// helper methods QuicVersionToQuicTag, QuicTagToQuicVersion, and
+// QuicVersionToString.
+enum QuicVersion {
+ // Special case to indicate unknown/unsupported QUIC version.
+ QUIC_VERSION_UNSUPPORTED = 0,
+
+ QUIC_VERSION_30 = 30, // Add server side support of cert transparency.
+ QUIC_VERSION_31 = 31, // Adds a hash of the client hello to crypto proof.
+ QUIC_VERSION_32 = 32, // FEC related fields are removed from wire format.
+ QUIC_VERSION_33 = 33, // Adds diversification nonces.
+ QUIC_VERSION_34 = 34, // Deprecates entropy, removes private flag from packet
+ // header, uses new ack and stop waiting wire format.
+ QUIC_VERSION_35 = 35, // Allows endpoints to independently set stream limit.
+ QUIC_VERSION_36 = 36, // Add support to force HOL blocking.
+
+ // IMPORTANT: if you are adding to this std::list, follow the instructions at
+ // http://sites/quic/adding-and-removing-versions
+};
+
+// 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).
+//
+// IMPORTANT: if you are adding to this list, follow the instructions at
+// http://sites/quic/adding-and-removing-versions
+static const QuicVersion kSupportedQuicVersions[] = {
+ QUIC_VERSION_36, QUIC_VERSION_35, QUIC_VERSION_34, QUIC_VERSION_33,
+ QUIC_VERSION_32, QUIC_VERSION_31, QUIC_VERSION_30};
+
+typedef std::vector<QuicVersion> QuicVersionVector;
+
+// Returns a vector of QUIC versions in kSupportedQuicVersions.
+NET_EXPORT_PRIVATE QuicVersionVector AllSupportedVersions();
+
+// Returns a vector of QUIC versions from kSupportedQuicVersions which exclude
+// any versions which are disabled by flags.
+NET_EXPORT_PRIVATE QuicVersionVector CurrentSupportedVersions();
+
+// Returns a vector of QUIC versions from |versions| which exclude any versions
+// which are disabled by flags.
+NET_EXPORT_PRIVATE QuicVersionVector
+FilterSupportedVersions(QuicVersionVector versions);
+
+// Returns QUIC version of |index| in result of |versions|. Returns
+// QUIC_VERSION_UNSUPPORTED if |index| is out of bounds.
+NET_EXPORT_PRIVATE QuicVersionVector
+VersionOfIndex(const QuicVersionVector& versions, int index);
+
+// QuicTag is written to and read from the wire, but we prefer to use
+// the more readable QuicVersion at other levels.
+// Helper function which translates from a QuicVersion to a QuicTag. Returns 0
+// if QuicVersion is unsupported.
+NET_EXPORT_PRIVATE QuicTag QuicVersionToQuicTag(const QuicVersion version);
+
+// Returns appropriate QuicVersion from a QuicTag.
+// Returns QUIC_VERSION_UNSUPPORTED if version_tag cannot be understood.
+NET_EXPORT_PRIVATE QuicVersion QuicTagToQuicVersion(const QuicTag version_tag);
+
+// Helper function which translates from a QuicVersion to a string.
+// Returns strings corresponding to enum names (e.g. QUIC_VERSION_6).
+NET_EXPORT_PRIVATE std::string QuicVersionToString(const QuicVersion version);
+
+// Returns comma separated list of string representations of QuicVersion enum
+// values in the supplied |versions| vector.
+NET_EXPORT_PRIVATE std::string QuicVersionVectorToString(
+ const QuicVersionVector& versions);
+
+// Version and Crypto tags are written to the wire with a big-endian
+// representation of the name of the tag. For example
+// the client hello tag (CHLO) will be written as the
+// following 4 bytes: 'C' 'H' 'L' 'O'. Since it is
+// stored in memory as a little endian uint32_t, we need
+// to reverse the order of the bytes.
+
+// MakeQuicTag returns a value given the four bytes. For example:
+// MakeQuicTag('C', 'H', 'L', 'O');
+NET_EXPORT_PRIVATE QuicTag MakeQuicTag(char a, char b, char c, char d);
+
+// Returns true if the tag vector contains the specified tag.
+NET_EXPORT_PRIVATE bool ContainsQuicTag(const QuicTagVector& tag_vector,
+ QuicTag tag);
+
+// Size in bytes of the data packet header.
+NET_EXPORT_PRIVATE size_t GetPacketHeaderSize(QuicVersion version,
+ const QuicPacketHeader& header);
+
+NET_EXPORT_PRIVATE size_t
+GetPacketHeaderSize(QuicVersion version,
+ QuicConnectionIdLength connection_id_length,
+ bool include_version,
+ bool include_path_id,
+ bool include_diversification_nonce,
+ QuicPacketNumberLength packet_number_length);
+
+// Index of the first byte in a QUIC packet of encrypted data.
+NET_EXPORT_PRIVATE size_t
+GetStartOfEncryptedData(QuicVersion version, const QuicPacketHeader& header);
+
+NET_EXPORT_PRIVATE size_t
+GetStartOfEncryptedData(QuicVersion version,
+ QuicConnectionIdLength connection_id_length,
+ bool include_version,
+ bool include_path_id,
+ bool include_diversification_nonce,
+ QuicPacketNumberLength packet_number_length);
+
+enum QuicRstStreamErrorCode {
+ // Complete response has been sent, sending a RST to ask the other endpoint
+ // to stop sending request data without discarding the response.
+ QUIC_STREAM_NO_ERROR = 0,
+
+ // There was some error which halted stream processing.
+ QUIC_ERROR_PROCESSING_STREAM,
+ // We got two fin or reset offsets which did not match.
+ QUIC_MULTIPLE_TERMINATION_OFFSETS,
+ // We got bad payload and can not respond to it at the protocol level.
+ QUIC_BAD_APPLICATION_PAYLOAD,
+ // Stream closed due to connection error. No reset frame is sent when this
+ // happens.
+ QUIC_STREAM_CONNECTION_ERROR,
+ // GoAway frame sent. No more stream can be created.
+ QUIC_STREAM_PEER_GOING_AWAY,
+ // The stream has been cancelled.
+ QUIC_STREAM_CANCELLED,
+ // Closing stream locally, sending a RST to allow for proper flow control
+ // accounting. Sent in response to a RST from the peer.
+ QUIC_RST_ACKNOWLEDGEMENT,
+ // Receiver refused to create the stream (because its limit on open streams
+ // has been reached). The sender should retry the request later (using
+ // another stream).
+ QUIC_REFUSED_STREAM,
+ // Invalid URL in PUSH_PROMISE request header.
+ QUIC_INVALID_PROMISE_URL,
+ // Server is not authoritative for this URL.
+ QUIC_UNAUTHORIZED_PROMISE_URL,
+ // Can't have more than one active PUSH_PROMISE per URL.
+ QUIC_DUPLICATE_PROMISE_URL,
+ // Vary check failed.
+ QUIC_PROMISE_VARY_MISMATCH,
+ // Only GET and HEAD methods allowed.
+ QUIC_INVALID_PROMISE_METHOD,
+ // No error. Used as bound while iterating.
+ QUIC_STREAM_LAST_ERROR,
+};
+// QUIC error codes are encoded to a single octet on-the-wire.
+static_assert(static_cast<int>(QUIC_STREAM_LAST_ERROR) <=
+ std::numeric_limits<uint8_t>::max(),
+ "QuicErrorCode exceeds single octet");
+
+// Because receiving an unknown QuicRstStreamErrorCode results in connection
+// teardown, we use this to make sure any errors predating a given version are
+// downgraded to the most appropriate existing error.
+NET_EXPORT_PRIVATE QuicRstStreamErrorCode
+AdjustErrorForVersion(QuicRstStreamErrorCode error_code, QuicVersion version);
+
+// These values must remain stable as they are uploaded to UMA histograms.
+// To add a new error code, use the current value of QUIC_LAST_ERROR and
+// increment QUIC_LAST_ERROR.
+enum QuicErrorCode {
+ QUIC_NO_ERROR = 0,
+
+ // Connection has reached an invalid state.
+ QUIC_INTERNAL_ERROR = 1,
+ // There were data frames after the a fin or reset.
+ QUIC_STREAM_DATA_AFTER_TERMINATION = 2,
+ // Control frame is malformed.
+ QUIC_INVALID_PACKET_HEADER = 3,
+ // Frame data is malformed.
+ QUIC_INVALID_FRAME_DATA = 4,
+ // The packet contained no payload.
+ QUIC_MISSING_PAYLOAD = 48,
+ // FEC data is malformed.
+ QUIC_INVALID_FEC_DATA = 5,
+ // STREAM frame data is malformed.
+ QUIC_INVALID_STREAM_DATA = 46,
+ // STREAM frame data overlaps with buffered data.
+ QUIC_OVERLAPPING_STREAM_DATA = 87,
+ // Received STREAM frame data is not encrypted.
+ QUIC_UNENCRYPTED_STREAM_DATA = 61,
+ // Attempt to send unencrypted STREAM frame.
+ QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA = 88,
+ // Received a frame which is likely the result of memory corruption.
+ QUIC_MAYBE_CORRUPTED_MEMORY = 89,
+ // FEC frame data is not encrypted.
+ QUIC_UNENCRYPTED_FEC_DATA = 77,
+ // RST_STREAM frame data is malformed.
+ QUIC_INVALID_RST_STREAM_DATA = 6,
+ // CONNECTION_CLOSE frame data is malformed.
+ QUIC_INVALID_CONNECTION_CLOSE_DATA = 7,
+ // GOAWAY frame data is malformed.
+ QUIC_INVALID_GOAWAY_DATA = 8,
+ // WINDOW_UPDATE frame data is malformed.
+ QUIC_INVALID_WINDOW_UPDATE_DATA = 57,
+ // BLOCKED frame data is malformed.
+ QUIC_INVALID_BLOCKED_DATA = 58,
+ // STOP_WAITING frame data is malformed.
+ QUIC_INVALID_STOP_WAITING_DATA = 60,
+ // PATH_CLOSE frame data is malformed.
+ QUIC_INVALID_PATH_CLOSE_DATA = 78,
+ // ACK frame data is malformed.
+ QUIC_INVALID_ACK_DATA = 9,
+
+ // Version negotiation packet is malformed.
+ QUIC_INVALID_VERSION_NEGOTIATION_PACKET = 10,
+ // Public RST packet is malformed.
+ QUIC_INVALID_PUBLIC_RST_PACKET = 11,
+ // There was an error decrypting.
+ QUIC_DECRYPTION_FAILURE = 12,
+ // There was an error encrypting.
+ QUIC_ENCRYPTION_FAILURE = 13,
+ // The packet exceeded kMaxPacketSize.
+ QUIC_PACKET_TOO_LARGE = 14,
+ // The peer is going away. May be a client or server.
+ QUIC_PEER_GOING_AWAY = 16,
+ // A stream ID was invalid.
+ QUIC_INVALID_STREAM_ID = 17,
+ // A priority was invalid.
+ QUIC_INVALID_PRIORITY = 49,
+ // Too many streams already open.
+ QUIC_TOO_MANY_OPEN_STREAMS = 18,
+ // The peer created too many available streams.
+ QUIC_TOO_MANY_AVAILABLE_STREAMS = 76,
+ // Received public reset for this connection.
+ QUIC_PUBLIC_RESET = 19,
+ // Invalid protocol version.
+ QUIC_INVALID_VERSION = 20,
+
+ // The Header ID for a stream was too far from the previous.
+ QUIC_INVALID_HEADER_ID = 22,
+ // Negotiable parameter received during handshake had invalid value.
+ QUIC_INVALID_NEGOTIATED_VALUE = 23,
+ // There was an error decompressing data.
+ QUIC_DECOMPRESSION_FAILURE = 24,
+ // The connection timed out due to no network activity.
+ QUIC_NETWORK_IDLE_TIMEOUT = 25,
+ // The connection timed out waiting for the handshake to complete.
+ QUIC_HANDSHAKE_TIMEOUT = 67,
+ // There was an error encountered migrating addresses.
+ QUIC_ERROR_MIGRATING_ADDRESS = 26,
+ // There was an error encountered migrating port only.
+ QUIC_ERROR_MIGRATING_PORT = 86,
+ // There was an error while writing to the socket.
+ QUIC_PACKET_WRITE_ERROR = 27,
+ // There was an error while reading from the socket.
+ QUIC_PACKET_READ_ERROR = 51,
+ // We received a STREAM_FRAME with no data and no fin flag set.
+ QUIC_EMPTY_STREAM_FRAME_NO_FIN = 50,
+ // We received invalid data on the headers stream.
+ QUIC_INVALID_HEADERS_STREAM_DATA = 56,
+ // The peer received too much data, violating flow control.
+ QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA = 59,
+ // The peer sent too much data, violating flow control.
+ QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA = 63,
+ // The peer received an invalid flow control window.
+ QUIC_FLOW_CONTROL_INVALID_WINDOW = 64,
+ // The connection has been IP pooled into an existing connection.
+ QUIC_CONNECTION_IP_POOLED = 62,
+ // The connection has too many outstanding sent packets.
+ QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS = 68,
+ // The connection has too many outstanding received packets.
+ QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS = 69,
+ // The quic connection has been cancelled.
+ QUIC_CONNECTION_CANCELLED = 70,
+ // Disabled QUIC because of high packet loss rate.
+ QUIC_BAD_PACKET_LOSS_RATE = 71,
+ // Disabled QUIC because of too many PUBLIC_RESETs post handshake.
+ QUIC_PUBLIC_RESETS_POST_HANDSHAKE = 73,
+ // Disabled QUIC because of too many timeouts with streams open.
+ QUIC_TIMEOUTS_WITH_OPEN_STREAMS = 74,
+ // Closed because we failed to serialize a packet.
+ QUIC_FAILED_TO_SERIALIZE_PACKET = 75,
+ // QUIC timed out after too many RTOs.
+ QUIC_TOO_MANY_RTOS = 85,
+
+ // Crypto errors.
+
+ // Hanshake failed.
+ QUIC_HANDSHAKE_FAILED = 28,
+ // Handshake message contained out of order tags.
+ QUIC_CRYPTO_TAGS_OUT_OF_ORDER = 29,
+ // Handshake message contained too many entries.
+ QUIC_CRYPTO_TOO_MANY_ENTRIES = 30,
+ // Handshake message contained an invalid value length.
+ QUIC_CRYPTO_INVALID_VALUE_LENGTH = 31,
+ // A crypto message was received after the handshake was complete.
+ QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE = 32,
+ // A crypto message was received with an illegal message tag.
+ QUIC_INVALID_CRYPTO_MESSAGE_TYPE = 33,
+ // A crypto message was received with an illegal parameter.
+ QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER = 34,
+ // An invalid channel id signature was supplied.
+ QUIC_INVALID_CHANNEL_ID_SIGNATURE = 52,
+ // A crypto message was received with a mandatory parameter missing.
+ QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND = 35,
+ // A crypto message was received with a parameter that has no overlap
+ // with the local parameter.
+ QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP = 36,
+ // A crypto message was received that contained a parameter with too few
+ // values.
+ QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND = 37,
+ // A demand for an unsupport proof type was received.
+ QUIC_UNSUPPORTED_PROOF_DEMAND = 94,
+ // An internal error occured in crypto processing.
+ QUIC_CRYPTO_INTERNAL_ERROR = 38,
+ // A crypto handshake message specified an unsupported version.
+ QUIC_CRYPTO_VERSION_NOT_SUPPORTED = 39,
+ // A crypto handshake message resulted in a stateless reject.
+ QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT = 72,
+ // There was no intersection between the crypto primitives supported by the
+ // peer and ourselves.
+ QUIC_CRYPTO_NO_SUPPORT = 40,
+ // The server rejected our client hello messages too many times.
+ QUIC_CRYPTO_TOO_MANY_REJECTS = 41,
+ // The client rejected the server's certificate chain or signature.
+ QUIC_PROOF_INVALID = 42,
+ // A crypto message was received with a duplicate tag.
+ QUIC_CRYPTO_DUPLICATE_TAG = 43,
+ // A crypto message was received with the wrong encryption level (i.e. it
+ // should have been encrypted but was not.)
+ QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT = 44,
+ // The server config for a server has expired.
+ QUIC_CRYPTO_SERVER_CONFIG_EXPIRED = 45,
+ // We failed to setup the symmetric keys for a connection.
+ QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED = 53,
+ // A handshake message arrived, but we are still validating the
+ // previous handshake message.
+ QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO = 54,
+ // A server config update arrived before the handshake is complete.
+ QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE = 65,
+ // CHLO cannot fit in one packet.
+ QUIC_CRYPTO_CHLO_TOO_LARGE = 90,
+ // This connection involved a version negotiation which appears to have been
+ // tampered with.
+ QUIC_VERSION_NEGOTIATION_MISMATCH = 55,
+
+ // Multipath errors.
+ // Multipath is not enabled, but a packet with multipath flag on is received.
+ QUIC_BAD_MULTIPATH_FLAG = 79,
+ // A path is supposed to exist but does not.
+ QUIC_MULTIPATH_PATH_DOES_NOT_EXIST = 91,
+ // A path is supposed to be active but is not.
+ QUIC_MULTIPATH_PATH_NOT_ACTIVE = 92,
+
+ // IP address changed causing connection close.
+ QUIC_IP_ADDRESS_CHANGED = 80,
+
+ // Connection migration errors.
+ // Network changed, but connection had no migratable streams.
+ QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS = 81,
+ // Connection changed networks too many times.
+ QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES = 82,
+ // Connection migration was attempted, but there was no new network to
+ // migrate to.
+ QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK = 83,
+ // Network changed, but connection had one or more non-migratable streams.
+ 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,
+
+ // Sequencer buffer get into weird state where continuing read/write will lead
+ // to crash.
+ QUIC_STREAM_SEQUENCER_INVALID_STATE = 95,
+
+ // Connection closed because of server hits max number of sessions allowed.
+ // TODO(fayang): Add monitoring for QUIC_TOO_MANY_SESSIONS_ON_SERVER.
+ QUIC_TOO_MANY_SESSIONS_ON_SERVER = 96,
+
+ // No error. Used as bound while iterating.
+ QUIC_LAST_ERROR = 97,
+};
+
+typedef std::array<char, 32> DiversificationNonce;
+
+struct NET_EXPORT_PRIVATE QuicPacketPublicHeader {
+ QuicPacketPublicHeader();
+ explicit QuicPacketPublicHeader(const QuicPacketPublicHeader& other);
+ ~QuicPacketPublicHeader();
+
+ // Universal header. All QuicPacket headers will have a connection_id and
+ // public flags.
+ QuicConnectionId connection_id;
+ QuicConnectionIdLength connection_id_length;
+ bool multipath_flag;
+ bool reset_flag;
+ bool version_flag;
+ QuicPacketNumberLength packet_number_length;
+ QuicVersionVector versions;
+ // nonce contains an optional, 32-byte nonce value. If not included in the
+ // packet, |nonce| will be empty.
+ DiversificationNonce* nonce;
+};
+
+// An integer which cannot be a packet number.
+const QuicPacketNumber kInvalidPacketNumber = 0;
+
+// Header for Data packets.
+struct NET_EXPORT_PRIVATE QuicPacketHeader {
+ QuicPacketHeader();
+ explicit QuicPacketHeader(const QuicPacketPublicHeader& header);
+ QuicPacketHeader(const QuicPacketHeader& other);
+
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
+ const QuicPacketHeader& s);
+
+ QuicPacketPublicHeader public_header;
+ QuicPacketNumber packet_number;
+ QuicPathId path_id;
+ bool entropy_flag;
+ QuicPacketEntropyHash entropy_hash;
+ bool fec_flag;
+};
+
+struct NET_EXPORT_PRIVATE QuicPublicResetPacket {
+ QuicPublicResetPacket();
+ explicit QuicPublicResetPacket(const QuicPacketPublicHeader& header);
+
+ QuicPacketPublicHeader public_header;
+ QuicPublicResetNonceProof nonce_proof;
+ QuicPacketNumber rejected_packet_number;
+ IPEndPoint client_address;
+};
+
+enum QuicVersionNegotiationState {
+ START_NEGOTIATION = 0,
+ // Server-side this implies we've sent a version negotiation packet and are
+ // waiting on the client to select a compatible version. Client-side this
+ // implies we've gotten a version negotiation packet, are retransmitting the
+ // initial packets with a supported version and are waiting for our first
+ // packet from the server.
+ NEGOTIATION_IN_PROGRESS,
+ // This indicates this endpoint has received a packet from the peer with a
+ // version this endpoint supports. Version negotiation is complete, and the
+ // version number will no longer be sent with future packets.
+ NEGOTIATED_VERSION
+};
+
+typedef QuicPacketPublicHeader QuicVersionNegotiationPacket;
+
+// A padding frame contains no payload.
+struct NET_EXPORT_PRIVATE QuicPaddingFrame {
+ QuicPaddingFrame() : num_padding_bytes(-1) {}
+ explicit QuicPaddingFrame(int num_padding_bytes)
+ : num_padding_bytes(num_padding_bytes) {}
+
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
+ const QuicPaddingFrame& s);
+
+ // -1: full padding to the end of a max-sized packet
+ // otherwise: only pad up to num_padding_bytes bytes
+ int num_padding_bytes;
+};
+
+// A ping frame contains no payload, though it is retransmittable,
+// and ACK'd just like other normal frames.
+struct NET_EXPORT_PRIVATE QuicPingFrame {};
+
+// A path MTU discovery frame contains no payload and is serialized as a ping
+// frame.
+struct NET_EXPORT_PRIVATE QuicMtuDiscoveryFrame {};
+
+class NET_EXPORT_PRIVATE QuicBufferAllocator {
+ public:
+ virtual ~QuicBufferAllocator();
+
+ // Returns or allocates a new buffer of |size|. Never returns null.
+ virtual char* New(size_t size) = 0;
+
+ // Returns or allocates a new buffer of |size| if |flag_enable| is true.
+ // Otherwise, returns a buffer that is compatible with this class directly
+ // with operator new. Never returns null.
+ virtual char* New(size_t size, bool flag_enable) = 0;
+
+ // Releases a buffer.
+ virtual void Delete(char* buffer) = 0;
+
+ // Marks the allocator as being idle. Serves as a hint to notify the allocator
+ // that it should release any resources it's still holding on to.
+ virtual void MarkAllocatorIdle() {}
+};
+
+// Deleter for stream buffers. Copyable to support platforms where the deleter
+// of a unique_ptr must be copyable. Otherwise it would be nice for this to be
+// move-only.
+class NET_EXPORT_PRIVATE StreamBufferDeleter {
+ public:
+ StreamBufferDeleter() : allocator_(nullptr) {}
+ explicit StreamBufferDeleter(QuicBufferAllocator* allocator)
+ : allocator_(allocator) {}
+
+ // Deletes |buffer| using |allocator_|.
+ void operator()(char* buffer) const;
+
+ private:
+ // Not owned; must be valid so long as the buffer stored in the unique_ptr
+ // that owns |this| is valid.
+ QuicBufferAllocator* allocator_;
+};
+
+using UniqueStreamBuffer = std::unique_ptr<char[], StreamBufferDeleter>;
+
+// Allocates memory of size |size| using |allocator| for a QUIC stream buffer.
+NET_EXPORT_PRIVATE UniqueStreamBuffer
+NewStreamBuffer(QuicBufferAllocator* allocator, size_t size);
+
+struct NET_EXPORT_PRIVATE QuicStreamFrame {
+ QuicStreamFrame();
+ QuicStreamFrame(QuicStreamId stream_id,
+ bool fin,
+ QuicStreamOffset offset,
+ base::StringPiece data);
+ QuicStreamFrame(QuicStreamId stream_id,
+ bool fin,
+ QuicStreamOffset offset,
+ QuicPacketLength data_length,
+ UniqueStreamBuffer buffer);
+ ~QuicStreamFrame();
+
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
+ const QuicStreamFrame& s);
+
+ QuicStreamId stream_id;
+ bool fin;
+ QuicPacketLength data_length;
+ const char* data_buffer;
+ QuicStreamOffset offset; // Location of this data in the stream.
+ // nullptr when the QuicStreamFrame is received, and non-null when sent.
+ UniqueStreamBuffer buffer;
+
+ private:
+ QuicStreamFrame(QuicStreamId stream_id,
+ bool fin,
+ QuicStreamOffset offset,
+ const char* data_buffer,
+ QuicPacketLength data_length,
+ UniqueStreamBuffer buffer);
+
+ DISALLOW_COPY_AND_ASSIGN(QuicStreamFrame);
+};
+static_assert(sizeof(QuicStreamFrame) <= 64,
+ "Keep the QuicStreamFrame size to a cacheline.");
+
+typedef std::vector<std::pair<QuicPacketNumber, QuicTime>> PacketTimeVector;
+
+struct NET_EXPORT_PRIVATE QuicStopWaitingFrame {
+ QuicStopWaitingFrame();
+ ~QuicStopWaitingFrame();
+
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os,
+ const QuicStopWaitingFrame& s);
+ // Path which this stop waiting frame belongs to.
+ QuicPathId path_id;
+ // Entropy hash of all packets up to, but not including, the least unacked
+ // packet.
+ QuicPacketEntropyHash entropy_hash;
+ // The lowest packet we've sent which is unacked, and we expect an ack for.
+ QuicPacketNumber least_unacked;
+};
+
+// A sequence of packet numbers where each number is unique. Intended to be used
+// in a sliding window fashion, where smaller old packet numbers are removed and
+// larger new packet numbers are added, with the occasional random access.
+class NET_EXPORT_PRIVATE PacketNumberQueue {
+ public:
+ using const_iterator = IntervalSet<QuicPacketNumber>::const_iterator;
+ using const_reverse_iterator =
+ IntervalSet<QuicPacketNumber>::const_reverse_iterator;
+
+ PacketNumberQueue();
+ PacketNumberQueue(const PacketNumberQueue& other);
+ // TODO(rtenneti): on windows RValue reference gives errors.
+ // PacketNumberQueue(PacketNumberQueue&& other);
+ ~PacketNumberQueue();
+
+ PacketNumberQueue& operator=(const PacketNumberQueue& other);
+ // PacketNumberQueue& operator=(PacketNumberQueue&& other);
+
+ // Adds |packet_number| to the set of packets in the queue.
+ void Add(QuicPacketNumber packet_number);
+
+ // Adds packets between [lower, higher) to the set of packets in the queue. It
+ // is undefined behavior to call this with |higher| < |lower|.
+ void Add(QuicPacketNumber lower, QuicPacketNumber higher);
+
+ // Removes |packet_number| from the set of packets in the queue.
+ void Remove(QuicPacketNumber packet_number);
+
+ // Removes packets numbers between [lower, higher) to the set of packets in
+ // the queue. It is undefined behavior to call this with |higher| < |lower|.
+ void Remove(QuicPacketNumber lower, QuicPacketNumber higher);
+
+ // Removes packets with values less than |higher| from the set of packets in
+ // the queue. Returns true if packets were removed.
+ bool RemoveUpTo(QuicPacketNumber higher);
+
+ // Mutates packet number set so that it contains only those packet numbers
+ // from minimum to maximum packet number not currently in the set. Do nothing
+ // if packet number set is empty.
+ void Complement();
+
+ // Returns true if the queue contains |packet_number|.
+ bool Contains(QuicPacketNumber packet_number) const;
+
+ // Returns true if the queue is empty.
+ bool Empty() const;
+
+ // Returns the minimum packet number stored in the queue. It is undefined
+ // behavior to call this if the queue is empty.
+ QuicPacketNumber Min() const;
+
+ // Returns the maximum packet number stored in the queue. It is undefined
+ // behavior to call this if the queue is empty.
+ QuicPacketNumber Max() const;
+
+ // Returns the number of unique packets stored in the queue. Inefficient; only
+ // exposed for testing.
+ size_t NumPacketsSlow() const;
+
+ // Returns the number of disjoint packet number intervals contained in the
+ // queue.
+ size_t NumIntervals() const;
+
+ // Returns the length of last interval.
+ QuicPacketNumber LastIntervalLength() const;
+
+ // Returns iterators over the packet number intervals.
+ const_iterator begin() const;
+ const_iterator end() const;
+ const_reverse_iterator rbegin() const;
+ const_reverse_iterator rend() const;
+ const_iterator lower_bound(QuicPacketNumber packet_number) const;
+
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os,
+ const PacketNumberQueue& q);
+
+ private:
+ IntervalSet<QuicPacketNumber> packet_number_intervals_;
+};
+
+struct NET_EXPORT_PRIVATE QuicAckFrame {
+ QuicAckFrame();
+ QuicAckFrame(const QuicAckFrame& other);
+ ~QuicAckFrame();
+
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
+ const QuicAckFrame& s);
+
+ // The highest packet number we've observed from the peer.
+ //
+ // In general, this should be the largest packet number we've received. In
+ // the case of truncated acks, we may have to advertise a lower "upper bound"
+ // than largest received, to avoid implicitly acking missing packets that
+ // don't fit in the missing packet list due to size limitations. In this
+ // case, largest_observed may be a packet which is also in the missing packets
+ // list.
+ QuicPacketNumber largest_observed;
+
+ // Time elapsed since largest_observed was received until this Ack frame was
+ // sent.
+ QuicTime::Delta ack_delay_time;
+
+ // Vector of <packet_number, time> for when packets arrived.
+ PacketTimeVector received_packet_times;
+
+ // Set of packets.
+ PacketNumberQueue packets;
+
+ // Path which this ack belongs to.
+ QuicPathId path_id;
+
+ // Entropy hash of all packets up to largest observed not including missing
+ // packets.
+ QuicPacketEntropyHash entropy_hash;
+
+ // Whether the ack had to be truncated when sent.
+ bool is_truncated;
+
+ // If true, |packets| express missing packets. Otherwise, |packets| express
+ // received packets.
+ bool missing;
+};
+
+// True if the packet number is greater than largest_observed or is listed
+// as missing.
+// Always returns false for packet numbers less than least_unacked.
+bool NET_EXPORT_PRIVATE
+IsAwaitingPacket(const QuicAckFrame& ack_frame,
+ QuicPacketNumber packet_number,
+ QuicPacketNumber peer_least_packet_awaiting_ack);
+
+// Defines for all types of congestion control algorithms that can be used in
+// QUIC. Note that this is separate from the congestion feedback type -
+// some congestion control algorithms may use the same feedback type
+// (Reno and Cubic are the classic example for that).
+enum CongestionControlType {
+ kCubic,
+ kCubicBytes,
+ kReno,
+ kRenoBytes,
+ kBBR,
+};
+
+enum LossDetectionType {
+ kNack, // Used to mimic TCP's loss detection.
+ kTime, // Time based loss detection.
+ kAdaptiveTime, // Adaptive time based loss detection.
+};
+
+struct NET_EXPORT_PRIVATE QuicRstStreamFrame {
+ QuicRstStreamFrame();
+ QuicRstStreamFrame(QuicStreamId stream_id,
+ QuicRstStreamErrorCode error_code,
+ QuicStreamOffset bytes_written);
+
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os,
+ const QuicRstStreamFrame& r);
+
+ QuicStreamId stream_id;
+ QuicRstStreamErrorCode error_code;
+
+ // Used to update flow control windows. On termination of a stream, both
+ // endpoints must inform the peer of the number of bytes they have sent on
+ // that stream. This can be done through normal termination (data packet with
+ // FIN) or through a RST.
+ QuicStreamOffset byte_offset;
+};
+
+struct NET_EXPORT_PRIVATE QuicConnectionCloseFrame {
+ QuicConnectionCloseFrame();
+
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os,
+ const QuicConnectionCloseFrame& c);
+
+ QuicErrorCode error_code;
+ std::string error_details;
+};
+
+struct NET_EXPORT_PRIVATE QuicGoAwayFrame {
+ QuicGoAwayFrame();
+ QuicGoAwayFrame(QuicErrorCode error_code,
+ QuicStreamId last_good_stream_id,
+ const std::string& reason);
+
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
+ const QuicGoAwayFrame& g);
+
+ QuicErrorCode error_code;
+ QuicStreamId last_good_stream_id;
+ std::string reason_phrase;
+};
+
+// Flow control updates per-stream and at the connection levoel.
+// Based on SPDY's WINDOW_UPDATE frame, but uses an absolute byte offset rather
+// than a window delta.
+// TODO(rjshade): A possible future optimization is to make stream_id and
+// byte_offset variable length, similar to stream frames.
+struct NET_EXPORT_PRIVATE QuicWindowUpdateFrame {
+ QuicWindowUpdateFrame() {}
+ QuicWindowUpdateFrame(QuicStreamId stream_id, QuicStreamOffset byte_offset);
+
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os,
+ const QuicWindowUpdateFrame& w);
+
+ // The stream this frame applies to. 0 is a special case meaning the overall
+ // connection rather than a specific stream.
+ QuicStreamId stream_id;
+
+ // Byte offset in the stream or connection. The receiver of this frame must
+ // not send data which would result in this offset being exceeded.
+ QuicStreamOffset byte_offset;
+};
+
+// The BLOCKED frame is used to indicate to the remote endpoint that this
+// endpoint believes itself to be flow-control blocked but otherwise ready to
+// send data. The BLOCKED frame is purely advisory and optional.
+// Based on SPDY's BLOCKED frame (undocumented as of 2014-01-28).
+struct NET_EXPORT_PRIVATE QuicBlockedFrame {
+ QuicBlockedFrame() {}
+ explicit QuicBlockedFrame(QuicStreamId stream_id);
+
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
+ const QuicBlockedFrame& b);
+
+ // The stream this frame applies to. 0 is a special case meaning the overall
+ // connection rather than a specific stream.
+ QuicStreamId stream_id;
+};
+
+// The PATH_CLOSE frame is used to explicitly close a path. Both endpoints can
+// send a PATH_CLOSE frame to initiate a path termination. A path is considered
+// to be closed either a PATH_CLOSE frame is sent or received. An endpoint drops
+// receive side of a closed path, and packets with retransmittable frames on a
+// closed path are marked as retransmissions which will be transmitted on other
+// paths.
+struct NET_EXPORT_PRIVATE QuicPathCloseFrame {
+ QuicPathCloseFrame() {}
+ explicit QuicPathCloseFrame(QuicPathId path_id);
+
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os,
+ const QuicPathCloseFrame& p);
+
+ QuicPathId path_id;
+};
+
+// EncryptionLevel enumerates the stages of encryption that a QUIC connection
+// progresses through. When retransmitting a packet, the encryption level needs
+// to be specified so that it is retransmitted at a level which the peer can
+// understand.
+enum EncryptionLevel : int8_t {
+ ENCRYPTION_NONE = 0,
+ ENCRYPTION_INITIAL = 1,
+ ENCRYPTION_FORWARD_SECURE = 2,
+
+ NUM_ENCRYPTION_LEVELS,
+};
+
+enum PeerAddressChangeType {
+ // IP address and port remain unchanged.
+ NO_CHANGE,
+ // Port changed, but IP address remains unchanged.
+ PORT_CHANGE,
+ // IPv4 address changed, but within the /24 subnet (port may have changed.)
+ IPV4_SUBNET_CHANGE,
+ // IPv4 address changed, excluding /24 subnet change (port may have changed.)
+ IPV4_TO_IPV4_CHANGE,
+ // IP address change from an IPv4 to an IPv6 address (port may have changed.)
+ IPV4_TO_IPV6_CHANGE,
+ // IP address change from an IPv6 to an IPv4 address (port may have changed.)
+ IPV6_TO_IPV4_CHANGE,
+ // IP address change from an IPv6 to an IPv6 address (port may have changed.)
+ IPV6_TO_IPV6_CHANGE,
+};
+
+struct NET_EXPORT_PRIVATE QuicFrame {
+ QuicFrame();
+ explicit QuicFrame(QuicPaddingFrame padding_frame);
+ explicit QuicFrame(QuicMtuDiscoveryFrame frame);
+ explicit QuicFrame(QuicPingFrame frame);
+
+ explicit QuicFrame(QuicStreamFrame* stream_frame);
+ explicit QuicFrame(QuicAckFrame* frame);
+ explicit QuicFrame(QuicRstStreamFrame* frame);
+ explicit QuicFrame(QuicConnectionCloseFrame* frame);
+ explicit QuicFrame(QuicStopWaitingFrame* frame);
+ explicit QuicFrame(QuicGoAwayFrame* frame);
+ explicit QuicFrame(QuicWindowUpdateFrame* frame);
+ explicit QuicFrame(QuicBlockedFrame* frame);
+ explicit QuicFrame(QuicPathCloseFrame* frame);
+
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
+ const QuicFrame& frame);
+
+ QuicFrameType type;
+ union {
+ // Frames smaller than a pointer are inline.
+ QuicPaddingFrame padding_frame;
+ QuicMtuDiscoveryFrame mtu_discovery_frame;
+ QuicPingFrame ping_frame;
+
+ // Frames larger than a pointer.
+ QuicStreamFrame* stream_frame;
+ QuicAckFrame* ack_frame;
+ QuicStopWaitingFrame* stop_waiting_frame;
+ QuicRstStreamFrame* rst_stream_frame;
+ QuicConnectionCloseFrame* connection_close_frame;
+ QuicGoAwayFrame* goaway_frame;
+ QuicWindowUpdateFrame* window_update_frame;
+ QuicBlockedFrame* blocked_frame;
+ QuicPathCloseFrame* path_close_frame;
+ };
+};
+// QuicFrameType consumes 8 bytes with padding.
+static_assert(sizeof(QuicFrame) <= 16,
+ "Frames larger than 8 bytes should be referenced by pointer.");
+
+typedef std::vector<QuicFrame> QuicFrames;
+
+class NET_EXPORT_PRIVATE QuicData {
+ public:
+ QuicData(const char* buffer, size_t length);
+ QuicData(const char* buffer, size_t length, bool owns_buffer);
+ virtual ~QuicData();
+
+ base::StringPiece AsStringPiece() const {
+ return base::StringPiece(data(), length());
+ }
+
+ const char* data() const { return buffer_; }
+ size_t length() const { return length_; }
+ bool owns_buffer() const { return owns_buffer_; }
+
+ private:
+ const char* buffer_;
+ size_t length_;
+ bool owns_buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicData);
+};
+
+class NET_EXPORT_PRIVATE QuicPacket : public QuicData {
+ public:
+ // TODO(fayang): 4 fields from public header are passed in as arguments.
+ // Consider to add a convenience method which directly accepts the entire
+ // public header.
+ QuicPacket(char* buffer,
+ size_t length,
+ bool owns_buffer,
+ QuicConnectionIdLength connection_id_length,
+ bool includes_version,
+ bool includes_path_id,
+ bool includes_diversification_nonce,
+ QuicPacketNumberLength packet_number_length);
+
+ base::StringPiece AssociatedData(QuicVersion version) const;
+ base::StringPiece Plaintext(QuicVersion version) const;
+
+ char* mutable_data() { return buffer_; }
+
+ private:
+ char* buffer_;
+ const QuicConnectionIdLength connection_id_length_;
+ const bool includes_version_;
+ const bool includes_path_id_;
+ const bool includes_diversification_nonce_;
+ const QuicPacketNumberLength packet_number_length_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicPacket);
+};
+
+class NET_EXPORT_PRIVATE QuicEncryptedPacket : public QuicData {
+ public:
+ QuicEncryptedPacket(const char* buffer, size_t length);
+ QuicEncryptedPacket(const char* buffer, size_t length, bool owns_buffer);
+
+ // Clones the packet into a new packet which owns the buffer.
+ QuicEncryptedPacket* Clone() const;
+
+ // By default, gtest prints the raw bytes of an object. The bool data
+ // member (in the base class QuicData) causes this object to have padding
+ // bytes, which causes the default gtest object printer to read
+ // uninitialize memory. So we need to teach gtest how to print this object.
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os,
+ const QuicEncryptedPacket& s);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicEncryptedPacket);
+};
+
+// A received encrypted QUIC packet, with a recorded time of receipt.
+class NET_EXPORT_PRIVATE QuicReceivedPacket : public QuicEncryptedPacket {
+ public:
+ QuicReceivedPacket(const char* buffer, size_t length, QuicTime receipt_time);
+ QuicReceivedPacket(const char* buffer,
+ size_t length,
+ QuicTime receipt_time,
+ bool owns_buffer);
+ QuicReceivedPacket(const char* buffer,
+ size_t length,
+ QuicTime receipt_time,
+ bool owns_buffer,
+ bool potentially_small_mtu,
+ int ttl,
+ bool ttl_valid);
+
+ // Clones the packet into a new packet which owns the buffer.
+ QuicReceivedPacket* Clone() const;
+
+ // Returns the time at which the packet was received.
+ QuicTime receipt_time() const { return receipt_time_; }
+
+ // This is the TTL of the packet, assuming ttl_vaild_ is true.
+ int ttl() const { return ttl_; }
+
+ bool potentially_small_mtu() const { return potentially_small_mtu_; }
+
+ // By default, gtest prints the raw bytes of an object. The bool data
+ // member (in the base class QuicData) causes this object to have padding
+ // bytes, which causes the default gtest object printer to read
+ // uninitialize memory. So we need to teach gtest how to print this object.
+ NET_EXPORT_PRIVATE friend std::ostream& operator<<(
+ std::ostream& os,
+ const QuicReceivedPacket& s);
+
+ private:
+ const QuicTime receipt_time_;
+ int ttl_;
+ bool potentially_small_mtu_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicReceivedPacket);
+};
+
+// Pure virtual class to listen for packet acknowledgements.
+class NET_EXPORT_PRIVATE QuicAckListenerInterface
+ : public base::RefCounted<QuicAckListenerInterface> {
+ public:
+ QuicAckListenerInterface() {}
+
+ // Called when a packet is acked. Called once per packet.
+ // |acked_bytes| is the number of data bytes acked.
+ virtual void OnPacketAcked(int acked_bytes,
+ QuicTime::Delta ack_delay_time) = 0;
+
+ // Called when a packet is retransmitted. Called once per packet.
+ // |retransmitted_bytes| is the number of data bytes retransmitted.
+ virtual void OnPacketRetransmitted(int retransmitted_bytes) = 0;
+
+ protected:
+ friend class base::RefCounted<QuicAckListenerInterface>;
+
+ // Delegates are ref counted.
+ virtual ~QuicAckListenerInterface() {}
+};
+
+// Pure virtual class to close connection on unrecoverable errors.
+class NET_EXPORT_PRIVATE QuicConnectionCloseDelegateInterface {
+ public:
+ virtual ~QuicConnectionCloseDelegateInterface() {}
+
+ // Called when an unrecoverable error is encountered.
+ virtual void OnUnrecoverableError(QuicErrorCode error,
+ const std::string& error_details,
+ ConnectionCloseSource source) = 0;
+};
+
+// Used to generate filtered supported versions based on flags.
+class NET_EXPORT_PRIVATE QuicVersionManager {
+ public:
+ explicit QuicVersionManager(QuicVersionVector supported_versions);
+ ~QuicVersionManager();
+
+ // Returns supported versions based on flags.
+ const QuicVersionVector& GetSupportedVersions();
+
+ private:
+ // FLAGS_quic_disable_pre_32
+ bool disable_pre_32_;
+ // FLAGS_quic_disable_pre_34
+ bool disable_pre_34_;
+ // FLAGS_quic_enable_version_35
+ bool enable_version_35_;
+ // FLAGS_quic_enable_version_36_v2
+ bool enable_version_36_;
+ // The list of versions that may be supported.
+ QuicVersionVector allowed_supported_versions_;
+ // This vector contains QUIC versions which are currently supported based
+ // on flags.
+ QuicVersionVector filtered_supported_versions_;
+};
+
+struct NET_EXPORT_PRIVATE AckListenerWrapper {
+ AckListenerWrapper(QuicAckListenerInterface* listener,
+ QuicPacketLength data_length);
+ AckListenerWrapper(const AckListenerWrapper& other);
+ ~AckListenerWrapper();
+
+ scoped_refptr<QuicAckListenerInterface> ack_listener;
+ QuicPacketLength length;
+};
+
+struct NET_EXPORT_PRIVATE SerializedPacket {
+ SerializedPacket(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ QuicPacketNumberLength packet_number_length,
+ const char* encrypted_buffer,
+ QuicPacketLength encrypted_length,
+ QuicPacketEntropyHash entropy_hash,
+ bool has_ack,
+ bool has_stop_waiting);
+ SerializedPacket(const SerializedPacket& other);
+ ~SerializedPacket();
+
+ // Not owned.
+ const char* encrypted_buffer;
+ QuicPacketLength encrypted_length;
+ QuicFrames retransmittable_frames;
+ IsHandshake has_crypto_handshake;
+ // -1: full padding to the end of a max-sized packet
+ // 0: no padding
+ // otherwise: only pad up to num_padding_bytes bytes
+ int16_t num_padding_bytes;
+ QuicPathId path_id;
+ QuicPacketNumber packet_number;
+ QuicPacketNumberLength packet_number_length;
+ EncryptionLevel encryption_level;
+ QuicPacketEntropyHash entropy_hash;
+ bool has_ack;
+ bool has_stop_waiting;
+ TransmissionType transmission_type;
+ QuicPathId original_path_id;
+ QuicPacketNumber original_packet_number;
+
+ // Optional notifiers which will be informed when this packet has been ACKed.
+ std::list<AckListenerWrapper> listeners;
+};
+
+struct NET_EXPORT_PRIVATE TransmissionInfo {
+ // Used by STL when assigning into a map.
+ TransmissionInfo();
+
+ // Constructs a Transmission with a new all_transmissions set
+ // containing |packet_number|.
+ TransmissionInfo(EncryptionLevel level,
+ QuicPacketNumberLength packet_number_length,
+ TransmissionType transmission_type,
+ QuicTime sent_time,
+ QuicPacketLength bytes_sent,
+ bool has_crypto_handshake,
+ int num_padding_bytes);
+
+ TransmissionInfo(const TransmissionInfo& other);
+
+ ~TransmissionInfo();
+
+ QuicFrames retransmittable_frames;
+ EncryptionLevel encryption_level;
+ QuicPacketNumberLength packet_number_length;
+ QuicPacketLength bytes_sent;
+ QuicTime sent_time;
+ // Reason why this packet was transmitted.
+ TransmissionType transmission_type;
+ // In flight packets have not been abandoned or lost.
+ bool in_flight;
+ // True if the packet can never be acked, so it can be removed. Occurs when
+ // a packet is never sent, after it is acknowledged once, or if it's a crypto
+ // packet we never expect to receive an ack for.
+ bool is_unackable;
+ // True if the packet contains stream data from the crypto stream.
+ bool has_crypto_handshake;
+ // Non-zero if the packet needs padding if it's retransmitted.
+ int16_t num_padding_bytes;
+ // Stores the packet number of the next retransmission of this packet.
+ // Zero if the packet has not been retransmitted.
+ QuicPacketNumber retransmission;
+ // Non-empty if there is a listener for this packet.
+ std::list<AckListenerWrapper> ack_listeners;
+};
+
+// Struct to store the pending retransmission information.
+struct PendingRetransmission {
+ PendingRetransmission(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ TransmissionType transmission_type,
+ const QuicFrames& retransmittable_frames,
+ bool has_crypto_handshake,
+ int num_padding_bytes,
+ EncryptionLevel encryption_level,
+ QuicPacketNumberLength packet_number_length)
+ : packet_number(packet_number),
+ retransmittable_frames(retransmittable_frames),
+ transmission_type(transmission_type),
+ path_id(path_id),
+ has_crypto_handshake(has_crypto_handshake),
+ num_padding_bytes(num_padding_bytes),
+ encryption_level(encryption_level),
+ packet_number_length(packet_number_length) {}
+
+ QuicPacketNumber packet_number;
+ const QuicFrames& retransmittable_frames;
+ TransmissionType transmission_type;
+ QuicPathId path_id;
+ bool has_crypto_handshake;
+ int num_padding_bytes;
+ EncryptionLevel encryption_level;
+ QuicPacketNumberLength packet_number_length;
+};
+
+// Convenience wrapper to wrap an iovec array and the total length, which must
+// be less than or equal to the actual total length of the iovecs.
+struct NET_EXPORT_PRIVATE QuicIOVector {
+ QuicIOVector(const struct iovec* iov, int iov_count, size_t total_length)
+ : iov(iov), iov_count(iov_count), total_length(total_length) {}
+
+ const struct iovec* iov;
+ const int iov_count;
+ const size_t total_length;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_PROTOCOL_H_
diff --git a/chromium/net/quic/core/quic_protocol_test.cc b/chromium/net/quic/core/quic_protocol_test.cc
new file mode 100644
index 00000000000..03d545d6ac1
--- /dev/null
+++ b/chromium/net/quic/core/quic_protocol_test.cc
@@ -0,0 +1,553 @@
+// 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/quic_protocol.h"
+
+#include <sstream>
+
+#include "base/stl_util.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+namespace {
+
+TEST(QuicProtocolTest, AdjustErrorForVersion) {
+ ASSERT_EQ(14, QUIC_STREAM_LAST_ERROR)
+ << "Any additions to QuicRstStreamErrorCode require an addition to "
+ << "AdjustErrorForVersion and this associated test.";
+
+ // If we ever add different RST codes, we should have a test akin to the
+ // following.
+ // EXPECT_EQ(QUIC_RST_ACKNOWLEDGEMENT, AdjustErrorForVersion(
+ // QUIC_RST_ACKNOWLEDGEMENT,
+ // QUIC_VERSION_28));
+}
+
+TEST(QuicProtocolTest, MakeQuicTag) {
+ QuicTag tag = MakeQuicTag('A', 'B', 'C', 'D');
+ char bytes[4];
+ memcpy(bytes, &tag, 4);
+ EXPECT_EQ('A', bytes[0]);
+ EXPECT_EQ('B', bytes[1]);
+ EXPECT_EQ('C', bytes[2]);
+ EXPECT_EQ('D', bytes[3]);
+}
+
+TEST(QuicProtocolTest, IsAawaitingPacket) {
+ QuicAckFrame ack_frame;
+ ack_frame.largest_observed = 10u;
+ EXPECT_TRUE(IsAwaitingPacket(ack_frame, 11u, 0u));
+ EXPECT_FALSE(IsAwaitingPacket(ack_frame, 1u, 0u));
+
+ ack_frame.packets.Add(10);
+ EXPECT_TRUE(IsAwaitingPacket(ack_frame, 10u, 0u));
+
+ QuicAckFrame ack_frame1;
+ ack_frame1.missing = false;
+ ack_frame1.largest_observed = 10u;
+ ack_frame1.packets.Add(1, 11);
+ EXPECT_TRUE(IsAwaitingPacket(ack_frame1, 11u, 0u));
+ EXPECT_FALSE(IsAwaitingPacket(ack_frame1, 1u, 0u));
+
+ ack_frame1.packets.Remove(10);
+ EXPECT_TRUE(IsAwaitingPacket(ack_frame1, 10u, 0u));
+
+ QuicAckFrame ack_frame2;
+ ack_frame2.missing = false;
+ ack_frame2.largest_observed = 100u;
+ ack_frame2.packets.Add(21, 100);
+ EXPECT_FALSE(IsAwaitingPacket(ack_frame2, 11u, 20u));
+ EXPECT_FALSE(IsAwaitingPacket(ack_frame2, 80u, 20u));
+ EXPECT_TRUE(IsAwaitingPacket(ack_frame2, 101u, 20u));
+
+ ack_frame2.packets.Remove(50);
+ EXPECT_TRUE(IsAwaitingPacket(ack_frame2, 50u, 20u));
+}
+
+TEST(QuicProtocolTest, QuicVersionToQuicTag) {
+// If you add a new version to the QuicVersion enum you will need to add a new
+// case to QuicVersionToQuicTag, otherwise this test will fail.
+
+// TODO(rtenneti): Enable checking of Log(ERROR) messages.
+#if 0
+ // Any logs would indicate an unsupported version which we don't expect.
+ ScopedMockLog log(kDoNotCaptureLogsYet);
+ EXPECT_CALL(log, Log(_, _, _)).Times(0);
+ log.StartCapturingLogs();
+#endif
+
+ // Explicitly test a specific version.
+ EXPECT_EQ(MakeQuicTag('Q', '0', '3', '0'),
+ QuicVersionToQuicTag(QUIC_VERSION_30));
+
+ // 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 QuicTags).
+ for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
+ QuicVersion version = kSupportedQuicVersions[i];
+ EXPECT_LT(0u, QuicVersionToQuicTag(version));
+ }
+}
+
+TEST(QuicProtocolTest, QuicVersionToQuicTagUnsupported) {
+// TODO(rtenneti): Enable checking of Log(ERROR) messages.
+#if 0
+ // TODO(rjshade): Change to DFATAL once we actually support multiple versions,
+ // and QuicConnectionTest::SendVersionNegotiationPacket can be changed to use
+ // mis-matched versions rather than relying on QUIC_VERSION_UNSUPPORTED.
+ ScopedMockLog log(kDoNotCaptureLogsYet);
+ EXPECT_CALL(log, Log(base_logging::ERROR, _, "Unsupported QuicVersion: 0"))
+ .Times(1);
+ log.StartCapturingLogs();
+#endif
+
+ EXPECT_EQ(0u, QuicVersionToQuicTag(QUIC_VERSION_UNSUPPORTED));
+}
+
+TEST(QuicProtocolTest, QuicTagToQuicVersion) {
+// If you add a new version to the QuicVersion enum you will need to add a new
+// case to QuicTagToQuicVersion, otherwise this test will fail.
+
+// TODO(rtenneti): Enable checking of Log(ERROR) messages.
+#if 0
+ // Any logs would indicate an unsupported version which we don't expect.
+ ScopedMockLog log(kDoNotCaptureLogsYet);
+ EXPECT_CALL(log, Log(_, _, _)).Times(0);
+ log.StartCapturingLogs();
+#endif
+
+ // Explicitly test specific versions.
+ EXPECT_EQ(QUIC_VERSION_30,
+ QuicTagToQuicVersion(MakeQuicTag('Q', '0', '3', '0')));
+
+ for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
+ QuicVersion version = kSupportedQuicVersions[i];
+
+ // Get the tag from the version (we can loop over QuicVersions easily).
+ QuicTag tag = QuicVersionToQuicTag(version);
+ EXPECT_LT(0u, tag);
+
+ // Now try converting back.
+ QuicVersion tag_to_quic_version = QuicTagToQuicVersion(tag);
+ EXPECT_EQ(version, tag_to_quic_version);
+ EXPECT_NE(QUIC_VERSION_UNSUPPORTED, tag_to_quic_version);
+ }
+}
+
+TEST(QuicProtocolTest, QuicTagToQuicVersionUnsupported) {
+// TODO(rtenneti): Enable checking of Log(ERROR) messages.
+#if 0
+ ScopedMockLog log(kDoNotCaptureLogsYet);
+#ifndef NDEBUG
+ EXPECT_CALL(log,
+ Log(base_logging::INFO, _, "Unsupported QuicTag version: FAKE"))
+ .Times(1);
+#endif
+ log.StartCapturingLogs();
+#endif
+
+ EXPECT_EQ(QUIC_VERSION_UNSUPPORTED,
+ QuicTagToQuicVersion(MakeQuicTag('F', 'A', 'K', 'E')));
+}
+
+TEST(QuicProtocolTest, QuicVersionToString) {
+ EXPECT_EQ("QUIC_VERSION_30", QuicVersionToString(QUIC_VERSION_30));
+ EXPECT_EQ("QUIC_VERSION_UNSUPPORTED",
+ QuicVersionToString(QUIC_VERSION_UNSUPPORTED));
+
+ QuicVersion single_version[] = {QUIC_VERSION_30};
+ QuicVersionVector versions_vector;
+ for (size_t i = 0; i < arraysize(single_version); ++i) {
+ versions_vector.push_back(single_version[i]);
+ }
+ EXPECT_EQ("QUIC_VERSION_30", QuicVersionVectorToString(versions_vector));
+
+ QuicVersion multiple_versions[] = {QUIC_VERSION_UNSUPPORTED, QUIC_VERSION_30};
+ versions_vector.clear();
+ for (size_t i = 0; i < arraysize(multiple_versions); ++i) {
+ versions_vector.push_back(multiple_versions[i]);
+ }
+ EXPECT_EQ("QUIC_VERSION_UNSUPPORTED,QUIC_VERSION_30",
+ QuicVersionVectorToString(versions_vector));
+
+ // Make sure that all supported versions are present in QuicVersionToString.
+ for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
+ QuicVersion version = kSupportedQuicVersions[i];
+ EXPECT_NE("QUIC_VERSION_UNSUPPORTED", QuicVersionToString(version));
+ }
+}
+
+TEST(QuicProtocolTest, AckFrameToString) {
+ QuicAckFrame frame;
+ frame.entropy_hash = 1;
+ frame.largest_observed = 2;
+ frame.ack_delay_time = QuicTime::Delta::FromMicroseconds(3);
+ frame.packets.Add(4);
+ frame.packets.Add(5);
+ frame.received_packet_times = {
+ {6, QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(7)}};
+ std::ostringstream stream;
+ stream << frame;
+ EXPECT_EQ(
+ "{ entropy_hash: 1, largest_observed: 2, ack_delay_time: 3, "
+ "packets: [ 4 5 ], is_truncated: 0, received_packets: [ 6 at 7 ] }\n",
+ stream.str());
+}
+
+TEST(QuicProtocolTest, PaddingFrameToString) {
+ QuicPaddingFrame frame;
+ frame.num_padding_bytes = 1;
+ std::ostringstream stream;
+ stream << frame;
+ EXPECT_EQ("{ num_padding_bytes: 1 }\n", stream.str());
+}
+
+TEST(QuicProtocolTest, RstStreamFrameToString) {
+ QuicRstStreamFrame frame;
+ frame.stream_id = 1;
+ frame.error_code = QUIC_STREAM_CANCELLED;
+ std::ostringstream stream;
+ stream << frame;
+ EXPECT_EQ("{ stream_id: 1, error_code: 6 }\n", stream.str());
+}
+
+TEST(QuicProtocolTest, ConnectionCloseFrameToString) {
+ QuicConnectionCloseFrame frame;
+ frame.error_code = QUIC_NETWORK_IDLE_TIMEOUT;
+ frame.error_details = "No recent network activity.";
+ std::ostringstream stream;
+ stream << frame;
+ EXPECT_EQ(
+ "{ error_code: 25, error_details: 'No recent network activity.' }\n",
+ stream.str());
+}
+
+TEST(QuicProtocolTest, GoAwayFrameToString) {
+ QuicGoAwayFrame frame;
+ frame.error_code = QUIC_NETWORK_IDLE_TIMEOUT;
+ frame.last_good_stream_id = 2;
+ frame.reason_phrase = "Reason";
+ std::ostringstream stream;
+ stream << frame;
+ EXPECT_EQ(
+ "{ error_code: 25, last_good_stream_id: 2, reason_phrase: 'Reason' }\n",
+ stream.str());
+}
+
+TEST(QuicProtocolTest, WindowUpdateFrameToString) {
+ QuicWindowUpdateFrame frame;
+ std::ostringstream stream;
+ frame.stream_id = 1;
+ frame.byte_offset = 2;
+ stream << frame;
+ EXPECT_EQ("{ stream_id: 1, byte_offset: 2 }\n", stream.str());
+}
+
+TEST(QuicProtocolTest, BlockedFrameToString) {
+ QuicBlockedFrame frame;
+ frame.stream_id = 1;
+ std::ostringstream stream;
+ stream << frame;
+ EXPECT_EQ("{ stream_id: 1 }\n", stream.str());
+}
+
+TEST(QuicProtocolTest, StreamFrameToString) {
+ QuicStreamFrame frame;
+ frame.stream_id = 1;
+ frame.fin = false;
+ frame.offset = 2;
+ frame.data_length = 3;
+ std::ostringstream stream;
+ stream << frame;
+ EXPECT_EQ("{ stream_id: 1, fin: 0, offset: 2, length: 3 }\n", stream.str());
+}
+
+TEST(QuicProtocolTest, StopWaitingFrameToString) {
+ QuicStopWaitingFrame frame;
+ frame.entropy_hash = 1;
+ frame.least_unacked = 2;
+ std::ostringstream stream;
+ stream << frame;
+ EXPECT_EQ("{ entropy_hash: 1, least_unacked: 2 }\n", stream.str());
+}
+
+TEST(QuicProtocolTest, PathCloseFrameToString) {
+ QuicPathCloseFrame frame;
+ frame.path_id = 1;
+ std::ostringstream stream;
+ stream << frame;
+ EXPECT_EQ("{ path_id: 1 }\n", stream.str());
+}
+
+TEST(QuicProtocolTest, FilterSupportedVersions) {
+ QuicFlagSaver flags;
+ QuicVersionVector all_versions = {
+ QUIC_VERSION_30, QUIC_VERSION_31, QUIC_VERSION_32, QUIC_VERSION_33,
+ QUIC_VERSION_34, QUIC_VERSION_35, QUIC_VERSION_36};
+
+ FLAGS_quic_disable_pre_32 = true;
+ FLAGS_quic_disable_pre_34 = true;
+ FLAGS_quic_enable_version_35 = false;
+ FLAGS_quic_enable_version_36_v2 = false;
+
+ QuicVersionVector filtered_versions = FilterSupportedVersions(all_versions);
+ ASSERT_EQ(1u, filtered_versions.size());
+ EXPECT_EQ(QUIC_VERSION_34, filtered_versions[0]);
+}
+
+TEST(QuicProtocolTest, FilterSupportedVersionsAllVersions) {
+ QuicFlagSaver flags;
+ QuicVersionVector all_versions = {
+ QUIC_VERSION_30, QUIC_VERSION_31, QUIC_VERSION_32, QUIC_VERSION_33,
+ QUIC_VERSION_34, QUIC_VERSION_35, QUIC_VERSION_36};
+
+ FLAGS_quic_disable_pre_32 = false;
+ FLAGS_quic_disable_pre_34 = false;
+ FLAGS_quic_enable_version_35 = true;
+ FLAGS_quic_enable_version_36_v2 = true;
+
+ QuicVersionVector filtered_versions = FilterSupportedVersions(all_versions);
+ ASSERT_EQ(all_versions, filtered_versions);
+}
+
+TEST(QuicProtocolTest, FilterSupportedVersionsNo36) {
+ QuicFlagSaver flags;
+ QuicVersionVector all_versions = {
+ QUIC_VERSION_30, QUIC_VERSION_31, QUIC_VERSION_32, QUIC_VERSION_33,
+ QUIC_VERSION_34, QUIC_VERSION_35, QUIC_VERSION_36};
+
+ FLAGS_quic_disable_pre_32 = false;
+ FLAGS_quic_disable_pre_34 = false;
+ FLAGS_quic_enable_version_35 = true;
+ FLAGS_quic_enable_version_36_v2 = false;
+
+ all_versions.pop_back(); // Remove 36
+
+ ASSERT_EQ(all_versions, FilterSupportedVersions(all_versions));
+}
+
+TEST(QuicProtocolTest, FilterSupportedVersionsNo35) {
+ QuicFlagSaver flags;
+ QuicVersionVector all_versions = {
+ QUIC_VERSION_30, QUIC_VERSION_31, QUIC_VERSION_32, QUIC_VERSION_33,
+ QUIC_VERSION_34, QUIC_VERSION_35, QUIC_VERSION_36};
+
+ FLAGS_quic_disable_pre_32 = false;
+ FLAGS_quic_disable_pre_34 = false;
+ FLAGS_quic_enable_version_35 = true;
+ FLAGS_quic_enable_version_36_v2 = true;
+
+ all_versions.pop_back(); // Remove 36
+ all_versions.pop_back(); // Remove 35
+
+ ASSERT_EQ(all_versions, FilterSupportedVersions(all_versions));
+}
+
+TEST(QuicProtocolTest, FilterSupportedVersionsNoPre32) {
+ QuicFlagSaver flags;
+ QuicVersionVector all_versions = {
+ QUIC_VERSION_30, QUIC_VERSION_31, QUIC_VERSION_32, QUIC_VERSION_33,
+ QUIC_VERSION_34, QUIC_VERSION_35, QUIC_VERSION_36};
+
+ FLAGS_quic_disable_pre_32 = true;
+ FLAGS_quic_disable_pre_34 = false;
+ FLAGS_quic_enable_version_35 = true;
+ FLAGS_quic_enable_version_36_v2 = true;
+
+ all_versions.erase(all_versions.begin()); // Remove 30
+ all_versions.erase(all_versions.begin()); // Remove 31
+
+ ASSERT_EQ(all_versions, FilterSupportedVersions(all_versions));
+}
+
+TEST(QuicProtocolTest, FilterSupportedVersionsNoPre34) {
+ QuicFlagSaver flags;
+ QuicVersionVector all_versions = {
+ QUIC_VERSION_30, QUIC_VERSION_31, QUIC_VERSION_32, QUIC_VERSION_33,
+ QUIC_VERSION_34, QUIC_VERSION_35, QUIC_VERSION_36};
+
+ FLAGS_quic_disable_pre_32 = false;
+ FLAGS_quic_disable_pre_34 = true;
+ FLAGS_quic_enable_version_35 = true;
+ FLAGS_quic_enable_version_36_v2 = true;
+
+ all_versions.erase(all_versions.begin()); // Remove 30
+ all_versions.erase(all_versions.begin()); // Remove 31
+ all_versions.erase(all_versions.begin()); // Remove 32
+ all_versions.erase(all_versions.begin()); // Remove 33
+
+ ASSERT_EQ(all_versions, FilterSupportedVersions(all_versions));
+}
+
+TEST(QuicProtocolTest, QuicVersionManager) {
+ QuicFlagSaver flags;
+ FLAGS_quic_enable_version_35 = false;
+ FLAGS_quic_enable_version_36_v2 = false;
+ QuicVersionManager manager(AllSupportedVersions());
+ EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
+ manager.GetSupportedVersions());
+ FLAGS_quic_enable_version_35 = true;
+ FLAGS_quic_enable_version_36_v2 = true;
+ EXPECT_EQ(FilterSupportedVersions(AllSupportedVersions()),
+ manager.GetSupportedVersions());
+ EXPECT_EQ(QUIC_VERSION_36, manager.GetSupportedVersions()[0]);
+ EXPECT_EQ(QUIC_VERSION_35, manager.GetSupportedVersions()[1]);
+}
+
+TEST(QuicProtocolTest, LookUpVersionByIndex) {
+ QuicVersionVector all_versions = {
+ QUIC_VERSION_30, QUIC_VERSION_31, QUIC_VERSION_32, QUIC_VERSION_33,
+ QUIC_VERSION_34, QUIC_VERSION_35, QUIC_VERSION_36};
+ 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], VersionOfIndex(all_versions, i)[0]);
+ } else {
+ EXPECT_EQ(QUIC_VERSION_UNSUPPORTED, VersionOfIndex(all_versions, i)[0]);
+ }
+ }
+}
+
+// Tests that a queue contains the expected data after calls to Add().
+TEST(PacketNumberQueueTest, AddRange) {
+ PacketNumberQueue queue;
+ queue.Add(1, 51);
+ queue.Add(53);
+
+ EXPECT_FALSE(queue.Contains(0));
+ for (int i = 1; i < 51; ++i) {
+ EXPECT_TRUE(queue.Contains(i));
+ }
+ EXPECT_FALSE(queue.Contains(51));
+ EXPECT_FALSE(queue.Contains(52));
+ EXPECT_TRUE(queue.Contains(53));
+ EXPECT_FALSE(queue.Contains(54));
+ EXPECT_EQ(51u, queue.NumPacketsSlow());
+ EXPECT_EQ(1u, queue.Min());
+ EXPECT_EQ(53u, queue.Max());
+
+ queue.Add(70);
+ EXPECT_EQ(70u, queue.Max());
+}
+
+// Tests that a queue contains the expected data after calls to Remove().
+TEST(PacketNumberQueueTest, Removal) {
+ PacketNumberQueue queue;
+ queue.Add(0, 100);
+
+ EXPECT_TRUE(queue.RemoveUpTo(51));
+ EXPECT_FALSE(queue.RemoveUpTo(51));
+ queue.Remove(53);
+
+ EXPECT_FALSE(queue.Contains(0));
+ for (int i = 1; i < 51; ++i) {
+ EXPECT_FALSE(queue.Contains(i));
+ }
+ EXPECT_TRUE(queue.Contains(51));
+ EXPECT_TRUE(queue.Contains(52));
+ EXPECT_FALSE(queue.Contains(53));
+ EXPECT_TRUE(queue.Contains(54));
+ EXPECT_EQ(48u, queue.NumPacketsSlow());
+ EXPECT_EQ(51u, queue.Min());
+ EXPECT_EQ(99u, queue.Max());
+
+ queue.Remove(51);
+ EXPECT_EQ(52u, queue.Min());
+ queue.Remove(99);
+ EXPECT_EQ(98u, queue.Max());
+}
+
+// Tests that a queue is empty when all of its elements are removed.
+TEST(PacketNumberQueueTest, Empty) {
+ PacketNumberQueue queue;
+ EXPECT_TRUE(queue.Empty());
+ EXPECT_EQ(0u, queue.NumPacketsSlow());
+
+ queue.Add(1, 100);
+ EXPECT_TRUE(queue.RemoveUpTo(100));
+ EXPECT_TRUE(queue.Empty());
+ EXPECT_EQ(0u, queue.NumPacketsSlow());
+}
+
+// Tests that logging the state of a PacketNumberQueue does not crash.
+TEST(PacketNumberQueueTest, LogDoesNotCrash) {
+ std::ostringstream oss;
+ PacketNumberQueue queue;
+ oss << queue;
+
+ queue.Add(1);
+ queue.Add(50, 100);
+ oss << queue;
+}
+
+// Tests that the iterators returned from a packet queue iterate over the queue.
+TEST(PacketNumberQueueTest, Iterators) {
+ PacketNumberQueue queue;
+ queue.Add(1, 100);
+
+ const std::vector<Interval<QuicPacketNumber>> actual_intervals(queue.begin(),
+ queue.end());
+
+ std::vector<Interval<QuicPacketNumber>> expected_intervals;
+ expected_intervals.push_back(Interval<QuicPacketNumber>(1, 100));
+
+ EXPECT_EQ(expected_intervals, actual_intervals);
+}
+
+TEST(PacketNumberQueueTest, LowerBoundEquals) {
+ PacketNumberQueue queue;
+ queue.Add(1, 100);
+
+ PacketNumberQueue::const_iterator it = queue.lower_bound(10);
+ ASSERT_NE(queue.end(), it);
+ EXPECT_TRUE(it->Contains(10u));
+
+ it = queue.lower_bound(101);
+ EXPECT_TRUE(queue.end() == it);
+}
+
+TEST(PacketNumberQueueTest, LowerBoundGreater) {
+ PacketNumberQueue queue;
+ queue.Add(15, 25);
+ queue.Add(50, 100);
+
+ PacketNumberQueue::const_iterator it = queue.lower_bound(10);
+ ASSERT_NE(queue.end(), it);
+ EXPECT_EQ(15u, it->min());
+ EXPECT_EQ(25u, it->max());
+}
+
+TEST(PacketNumberQueueTest, IntervalLengthAndRemoveInterval) {
+ PacketNumberQueue queue;
+ queue.Add(1, 10);
+ queue.Add(20, 30);
+ queue.Add(40, 50);
+ EXPECT_EQ(3u, queue.NumIntervals());
+ EXPECT_EQ(10u, queue.LastIntervalLength());
+ queue.Remove(9, 21);
+ EXPECT_EQ(3u, queue.NumIntervals());
+ EXPECT_FALSE(queue.Contains(9));
+ EXPECT_FALSE(queue.Contains(20));
+}
+
+TEST(PacketNumberQueueTest, Complement) {
+ PacketNumberQueue queue;
+ queue.Add(1, 10);
+ queue.Add(12, 20);
+ queue.Add(22, 30);
+ queue.Complement();
+ EXPECT_EQ(2u, queue.NumIntervals());
+ EXPECT_TRUE(queue.Contains(10));
+ EXPECT_TRUE(queue.Contains(11));
+ EXPECT_TRUE(queue.Contains(20));
+ EXPECT_TRUE(queue.Contains(21));
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_received_packet_manager.cc b/chromium/net/quic/core/quic_received_packet_manager.cc
new file mode 100644
index 00000000000..64769c86b5d
--- /dev/null
+++ b/chromium/net/quic/core/quic_received_packet_manager.cc
@@ -0,0 +1,325 @@
+// Copyright 2013 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/quic_received_packet_manager.h"
+
+#include <limits>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "net/base/linked_hash_map.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_connection_stats.h"
+#include "net/quic/core/quic_flags.h"
+
+using std::max;
+using std::min;
+using std::numeric_limits;
+
+namespace net {
+
+namespace {
+
+// The maximum number of packets to ack immediately after a missing packet for
+// fast retransmission to kick in at the sender. This limit is created to
+// reduce the number of acks sent that have no benefit for fast retransmission.
+// Set to the number of nacks needed for fast retransmit plus one for protection
+// against an ack loss
+const size_t kMaxPacketsAfterNewMissing = 4;
+}
+
+QuicReceivedPacketManager::EntropyTracker::EntropyTracker()
+ : packets_entropy_hash_(0), first_gap_(1), largest_observed_(0) {}
+
+QuicReceivedPacketManager::EntropyTracker::~EntropyTracker() {}
+
+QuicPacketEntropyHash QuicReceivedPacketManager::EntropyTracker::EntropyHash(
+ QuicPacketNumber packet_number) const {
+ DCHECK_LE(packet_number, largest_observed_);
+ if (packet_number == largest_observed_) {
+ return packets_entropy_hash_;
+ }
+
+ DCHECK_GE(packet_number, first_gap_);
+ DCHECK_EQ(first_gap_ + packets_entropy_.size() - 1, largest_observed_);
+ QuicPacketEntropyHash hash = packets_entropy_hash_;
+ ReceivedEntropyHashes::const_reverse_iterator it = packets_entropy_.rbegin();
+ for (QuicPacketNumber i = 0; i < (largest_observed_ - packet_number);
+ ++i, ++it) {
+ hash ^= it->first;
+ }
+ return hash;
+}
+
+void QuicReceivedPacketManager::EntropyTracker::RecordPacketEntropyHash(
+ QuicPacketNumber packet_number,
+ QuicPacketEntropyHash entropy_hash) {
+ if (packet_number < first_gap_) {
+ DVLOG(1) << "Ignoring received packet entropy for packet_number:"
+ << packet_number
+ << " less than largest_peer_packet_number:" << first_gap_;
+ return;
+ }
+ // RecordPacketEntropyHash is only intended to be called once per packet.
+ DCHECK(packet_number > largest_observed_ ||
+ !packets_entropy_[packet_number - first_gap_].second);
+
+ packets_entropy_hash_ ^= entropy_hash;
+
+ // Optimize the typical case of no gaps.
+ if (packet_number == largest_observed_ + 1 && packets_entropy_.empty()) {
+ ++first_gap_;
+ largest_observed_ = packet_number;
+ return;
+ }
+ if (packet_number > largest_observed_) {
+ for (QuicPacketNumber i = 0; i < (packet_number - largest_observed_ - 1);
+ ++i) {
+ packets_entropy_.push_back(std::make_pair(0, false));
+ }
+ packets_entropy_.push_back(std::make_pair(entropy_hash, true));
+ largest_observed_ = packet_number;
+ } else {
+ packets_entropy_[packet_number - first_gap_] =
+ std::make_pair(entropy_hash, true);
+ AdvanceFirstGapAndGarbageCollectEntropyMap();
+ }
+
+ DVLOG(2) << "setting cumulative received entropy hash to: "
+ << static_cast<int>(packets_entropy_hash_)
+ << " updated with packet number " << packet_number
+ << " entropy hash: " << static_cast<int>(entropy_hash);
+}
+
+void QuicReceivedPacketManager::EntropyTracker::SetCumulativeEntropyUpTo(
+ QuicPacketNumber packet_number,
+ QuicPacketEntropyHash entropy_hash) {
+ DCHECK_LE(packet_number, largest_observed_);
+ if (packet_number < first_gap_) {
+ DVLOG(1) << "Ignoring set entropy at:" << packet_number
+ << " less than first_gap_:" << first_gap_;
+ return;
+ }
+ while (first_gap_ < packet_number) {
+ ++first_gap_;
+ if (!packets_entropy_.empty()) {
+ packets_entropy_.pop_front();
+ }
+ }
+ // Compute the current entropy by XORing in all entropies received including
+ // and since packet_number.
+ packets_entropy_hash_ = entropy_hash;
+ for (ReceivedEntropyHashes::const_iterator it = packets_entropy_.begin();
+ it != packets_entropy_.end(); ++it) {
+ packets_entropy_hash_ ^= it->first;
+ }
+
+ // Garbage collect entries from the beginning of the map.
+ AdvanceFirstGapAndGarbageCollectEntropyMap();
+}
+
+void QuicReceivedPacketManager::EntropyTracker::
+ AdvanceFirstGapAndGarbageCollectEntropyMap() {
+ while (!packets_entropy_.empty() && packets_entropy_.front().second) {
+ ++first_gap_;
+ packets_entropy_.pop_front();
+ }
+}
+
+QuicReceivedPacketManager::QuicReceivedPacketManager(QuicConnectionStats* stats)
+ : peer_least_packet_awaiting_ack_(0),
+ ack_frame_updated_(false),
+ time_largest_observed_(QuicTime::Zero()),
+ stats_(stats) {
+ ack_frame_.largest_observed = 0;
+ ack_frame_.entropy_hash = 0;
+}
+
+QuicReceivedPacketManager::~QuicReceivedPacketManager() {}
+
+void QuicReceivedPacketManager::RecordPacketReceived(
+ const QuicPacketHeader& header,
+ QuicTime receipt_time) {
+ QuicPacketNumber packet_number = header.packet_number;
+ DCHECK(IsAwaitingPacket(packet_number)) << " packet_number:" << packet_number;
+ if (!ack_frame_updated_) {
+ ack_frame_.received_packet_times.clear();
+ }
+ ack_frame_updated_ = true;
+ if (ack_frame_.missing) {
+ // Adds the range of packet numbers from max(largest observed + 1, least
+ // awaiting ack) up to packet_number not including packet_number.
+ ack_frame_.packets.Add(
+ max(ack_frame_.largest_observed + 1, peer_least_packet_awaiting_ack_),
+ packet_number);
+ } else {
+ ack_frame_.packets.Add(header.packet_number);
+ }
+
+ if (ack_frame_.largest_observed > packet_number) {
+ if (ack_frame_.missing) {
+ // We've gotten one of the out of order packets - remove it from our
+ // "missing packets" list.
+ DVLOG(1) << "Removing " << packet_number << " from missing list";
+ ack_frame_.packets.Remove(packet_number);
+ }
+
+ // Record how out of order stats.
+ ++stats_->packets_reordered;
+ stats_->max_sequence_reordering =
+ max(stats_->max_sequence_reordering,
+ ack_frame_.largest_observed - packet_number);
+ int64_t reordering_time_us =
+ (receipt_time - time_largest_observed_).ToMicroseconds();
+ stats_->max_time_reordering_us =
+ max(stats_->max_time_reordering_us, reordering_time_us);
+ }
+ if (packet_number > ack_frame_.largest_observed) {
+ ack_frame_.largest_observed = packet_number;
+ time_largest_observed_ = receipt_time;
+ }
+ if (ack_frame_.missing) {
+ entropy_tracker_.RecordPacketEntropyHash(packet_number,
+ header.entropy_hash);
+ }
+
+ ack_frame_.received_packet_times.push_back(
+ std::make_pair(packet_number, receipt_time));
+}
+
+bool QuicReceivedPacketManager::IsMissing(QuicPacketNumber packet_number) {
+ if (ack_frame_.missing) {
+ return ack_frame_.packets.Contains(packet_number);
+ }
+ return packet_number < ack_frame_.largest_observed &&
+ !ack_frame_.packets.Contains(packet_number);
+}
+
+bool QuicReceivedPacketManager::IsAwaitingPacket(
+ QuicPacketNumber packet_number) {
+ return ::net::IsAwaitingPacket(ack_frame_, packet_number,
+ peer_least_packet_awaiting_ack_);
+}
+
+namespace {
+struct isTooLarge {
+ explicit isTooLarge(QuicPacketNumber n) : largest_observed_(n) {}
+ QuicPacketNumber largest_observed_;
+
+ // Return true if the packet in p is too different from largest_observed_
+ // to express.
+ bool operator()(const std::pair<QuicPacketNumber, QuicTime>& p) const {
+ return largest_observed_ - p.first >= numeric_limits<uint8_t>::max();
+ }
+};
+} // namespace
+
+const QuicFrame QuicReceivedPacketManager::GetUpdatedAckFrame(
+ QuicTime approximate_now) {
+ ack_frame_updated_ = false;
+ if (ack_frame_.missing) {
+ ack_frame_.entropy_hash = EntropyHash(ack_frame_.largest_observed);
+ }
+
+ if (time_largest_observed_ == QuicTime::Zero()) {
+ // We have received no packets.
+ ack_frame_.ack_delay_time = QuicTime::Delta::Infinite();
+ } else {
+ // Ensure the delta is zero if approximate now is "in the past".
+ ack_frame_.ack_delay_time = approximate_now < time_largest_observed_
+ ? QuicTime::Delta::Zero()
+ : approximate_now - time_largest_observed_;
+ }
+
+ // Clear all packet times if any are too far from largest observed.
+ // It's expected this is extremely rare.
+ for (PacketTimeVector::iterator it = ack_frame_.received_packet_times.begin();
+ it != ack_frame_.received_packet_times.end();) {
+ if (ack_frame_.largest_observed - it->first >=
+ numeric_limits<uint8_t>::max()) {
+ it = ack_frame_.received_packet_times.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ return QuicFrame(&ack_frame_);
+}
+
+QuicPacketEntropyHash QuicReceivedPacketManager::EntropyHash(
+ QuicPacketNumber packet_number) const {
+ return entropy_tracker_.EntropyHash(packet_number);
+}
+
+bool QuicReceivedPacketManager::DontWaitForPacketsBefore(
+ QuicPacketNumber least_unacked) {
+ peer_least_packet_awaiting_ack_ = least_unacked;
+ return ack_frame_.packets.RemoveUpTo(least_unacked);
+}
+
+void QuicReceivedPacketManager::UpdatePacketInformationSentByPeer(
+ const QuicStopWaitingFrame& stop_waiting) {
+ // ValidateAck() should fail if peer_least_packet_awaiting_ack shrinks.
+ DCHECK_LE(peer_least_packet_awaiting_ack_, stop_waiting.least_unacked);
+ if (stop_waiting.least_unacked > peer_least_packet_awaiting_ack_) {
+ bool packets_updated = DontWaitForPacketsBefore(stop_waiting.least_unacked);
+ if (packets_updated) {
+ if (ack_frame_.missing) {
+ DVLOG(1) << "Updating entropy hashed since we missed packets";
+ // There were some missing packets that we won't ever get now.
+ // Recalculate the received entropy hash.
+ entropy_tracker_.SetCumulativeEntropyUpTo(stop_waiting.least_unacked,
+ stop_waiting.entropy_hash);
+ }
+ // Ack frame gets updated because packets set is updated because of stop
+ // waiting frame.
+ ack_frame_updated_ = true;
+ }
+ }
+ DCHECK(ack_frame_.packets.Empty() ||
+ ack_frame_.packets.Min() >= peer_least_packet_awaiting_ack_);
+}
+
+bool QuicReceivedPacketManager::HasMissingPackets() const {
+ if (ack_frame_.missing) {
+ return !ack_frame_.packets.Empty();
+ }
+
+ return ack_frame_.packets.NumIntervals() > 1 ||
+ (!ack_frame_.packets.Empty() &&
+ ack_frame_.packets.Min() >
+ max(QuicPacketNumber(1), peer_least_packet_awaiting_ack_));
+}
+
+bool QuicReceivedPacketManager::HasNewMissingPackets() const {
+ if (ack_frame_.missing) {
+ return !ack_frame_.packets.Empty() &&
+ (ack_frame_.largest_observed - ack_frame_.packets.Max()) <=
+ kMaxPacketsAfterNewMissing;
+ }
+
+ return HasMissingPackets() &&
+ ack_frame_.packets.LastIntervalLength() <= kMaxPacketsAfterNewMissing;
+}
+
+size_t QuicReceivedPacketManager::NumTrackedPackets() const {
+ return entropy_tracker_.size();
+}
+
+void QuicReceivedPacketManager::SetVersion(QuicVersion version) {
+ ack_frame_.missing = version <= QUIC_VERSION_33;
+}
+
+bool QuicReceivedPacketManager::ack_frame_updated() const {
+ return ack_frame_updated_;
+}
+
+QuicPacketNumber QuicReceivedPacketManager::GetLargestObserved() const {
+ return ack_frame_.largest_observed;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_received_packet_manager.h b/chromium/net/quic/core/quic_received_packet_manager.h
new file mode 100644
index 00000000000..16759ade20b
--- /dev/null
+++ b/chromium/net/quic/core/quic_received_packet_manager.h
@@ -0,0 +1,192 @@
+// Copyright 2013 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.
+//
+// Manages the packet entropy calculation for both sent and received packets
+// for a connection.
+
+#ifndef NET_QUIC_QUIC_RECEIVED_PACKET_MANAGER_H_
+#define NET_QUIC_QUIC_RECEIVED_PACKET_MANAGER_H_
+
+#include <stddef.h>
+
+#include <deque>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+namespace test {
+class EntropyTrackerPeer;
+class QuicConnectionPeer;
+class QuicReceivedPacketManagerPeer;
+} // namespace test
+
+struct QuicConnectionStats;
+
+// Records all received packets by a connection and tracks their entropy.
+// Also calculates the correct entropy for the framer when it truncates an ack
+// frame being serialized.
+class NET_EXPORT_PRIVATE QuicReceivedPacketManager
+ : public QuicReceivedEntropyHashCalculatorInterface {
+ public:
+ class NET_EXPORT_PRIVATE EntropyTracker {
+ public:
+ EntropyTracker();
+ ~EntropyTracker();
+
+ // Compute the XOR of the entropy of all received packets up to
+ // and including packet_number.
+ // Requires that either:
+ // packet_number == largest_observed_
+ // or:
+ // packet_number > first_gap_ &&
+ // packet_number < largest_observed_ &&
+ // packet_number in packets_entropy_
+ QuicPacketEntropyHash EntropyHash(QuicPacketNumber packet_number) const;
+
+ // Record the received entropy hash against |packet_number|.
+ // Performs garbage collection to advance first_gap_ if
+ // packet_number == first_gap_.
+ void RecordPacketEntropyHash(QuicPacketNumber packet_number,
+ QuicPacketEntropyHash entropy_hash);
+
+ // Sets the entropy hash up to but not including a packet number based
+ // on the hash provided by a StopWaiting frame. Clears older packet
+ // entropy entries and performs garbage collection up to the first gap.
+ void SetCumulativeEntropyUpTo(QuicPacketNumber packet_number,
+ QuicPacketEntropyHash entropy_hash);
+
+ size_t size() const { return packets_entropy_.size(); }
+
+ private:
+ friend class test::EntropyTrackerPeer;
+
+ // A deque indexed by packet number storing the packet's hash and whether
+ // a hash was recorded for that packet number.
+ typedef std::deque<std::pair<QuicPacketEntropyHash, bool>>
+ ReceivedEntropyHashes;
+
+ // Recomputes first_gap_ and removes packets_entropy_ entries that are no
+ // longer needed to compute EntropyHash.
+ void AdvanceFirstGapAndGarbageCollectEntropyMap();
+
+ // Map of received packet numbers to their corresponding entropy.
+ // Stores an entry for every received packet whose packet_number is larger
+ // than first_gap_. Packets without the entropy bit set have an entropy
+ // value of 0.
+ ReceivedEntropyHashes packets_entropy_;
+
+ // Cumulative hash of entropy of all received packets.
+ QuicPacketEntropyHash packets_entropy_hash_;
+
+ // packet number of the first packet that we do not know the entropy of.
+ // If there are no gaps in the received packet sequence,
+ // packets_entropy_ will be empty and first_gap_ will be equal to
+ // 'largest_observed_ + 1' since that's the first packet for which
+ // entropy is unknown. If there are gaps, packets_entropy_ will
+ // contain entries for all received packets with packet_number >
+ // first_gap_.
+ QuicPacketNumber first_gap_;
+
+ // packet number of the largest observed packet.
+ QuicPacketNumber largest_observed_;
+
+ DISALLOW_COPY_AND_ASSIGN(EntropyTracker);
+ };
+
+ explicit QuicReceivedPacketManager(QuicConnectionStats* stats);
+ ~QuicReceivedPacketManager() override;
+
+ // Updates the internal state concerning which packets have been received.
+ // header: the packet header.
+ // timestamp: the arrival time of the packet.
+ virtual void RecordPacketReceived(const QuicPacketHeader& header,
+ QuicTime receipt_time);
+
+ // Checks whether |packet_number| is missing and less than largest observed.
+ virtual bool IsMissing(QuicPacketNumber packet_number);
+
+ // Checks if we're still waiting for the packet with |packet_number|.
+ virtual bool IsAwaitingPacket(QuicPacketNumber packet_number);
+
+ // Retrieves a frame containing a QuicAckFrame. The ack frame may not be
+ // changed outside QuicReceivedPacketManager and must be serialized before
+ // another packet is received, or it will change.
+ const QuicFrame GetUpdatedAckFrame(QuicTime approximate_now);
+
+ // QuicReceivedEntropyHashCalculatorInterface
+ // Called by QuicFramer, when the outgoing ack gets truncated, to recalculate
+ // the received entropy hash for the truncated ack frame.
+ QuicPacketEntropyHash EntropyHash(
+ QuicPacketNumber packet_number) const override;
+
+ // Updates internal state based on |stop_waiting|.
+ virtual void UpdatePacketInformationSentByPeer(
+ const QuicStopWaitingFrame& stop_waiting);
+
+ // Returns true if there are any missing packets.
+ bool HasMissingPackets() const;
+
+ // Returns true when there are new missing packets to be reported within 3
+ // packets of the largest observed.
+ virtual bool HasNewMissingPackets() const;
+
+ // Returns the number of packets being tracked in the EntropyTracker.
+ size_t NumTrackedPackets() const;
+
+ // Sets the mode of packets set of ack_frame_ based on |version|.
+ void SetVersion(QuicVersion version);
+
+ QuicPacketNumber peer_least_packet_awaiting_ack() {
+ return peer_least_packet_awaiting_ack_;
+ }
+
+ virtual bool ack_frame_updated() const;
+
+ QuicPacketNumber GetLargestObserved() const;
+
+ // For logging purposes.
+ const QuicAckFrame& ack_frame() const { return ack_frame_; }
+
+ private:
+ friend class test::QuicConnectionPeer;
+ friend class test::QuicReceivedPacketManagerPeer;
+
+ // Deletes all missing packets before least unacked. The connection won't
+ // process any packets with packet number before |least_unacked| that it
+ // received after this call. Returns true if there were missing packets before
+ // |least_unacked| unacked, false otherwise.
+ bool DontWaitForPacketsBefore(QuicPacketNumber least_unacked);
+
+ // Tracks entropy hashes of received packets.
+ EntropyTracker entropy_tracker_;
+
+ // Least packet number of the the packet sent by the peer for which it
+ // hasn't received an ack.
+ QuicPacketNumber peer_least_packet_awaiting_ack_;
+
+ // Received packet information used to produce acks.
+ QuicAckFrame ack_frame_;
+
+ // True if |ack_frame_| has been updated since UpdateReceivedPacketInfo was
+ // last called.
+ bool ack_frame_updated_;
+
+ // The time we received the largest_observed packet number, or zero if
+ // no packet numbers have been received since UpdateReceivedPacketInfo.
+ // Needed for calculating ack_delay_time.
+ QuicTime time_largest_observed_;
+
+ QuicConnectionStats* stats_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicReceivedPacketManager);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_RECEIVED_PACKET_MANAGER_H_
diff --git a/chromium/net/quic/core/quic_received_packet_manager_test.cc b/chromium/net/quic/core/quic_received_packet_manager_test.cc
new file mode 100644
index 00000000000..acc9c0fea37
--- /dev/null
+++ b/chromium/net/quic/core/quic_received_packet_manager_test.cc
@@ -0,0 +1,396 @@
+// Copyright 2013 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/quic_received_packet_manager.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "net/quic/core/quic_connection_stats.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/test_tools/quic_received_packet_manager_peer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::pair;
+using std::vector;
+
+namespace net {
+namespace test {
+
+class EntropyTrackerPeer {
+ public:
+ static QuicPacketNumber first_gap(
+ const QuicReceivedPacketManager::EntropyTracker& tracker) {
+ return tracker.first_gap_;
+ }
+ static QuicPacketNumber largest_observed(
+ const QuicReceivedPacketManager::EntropyTracker& tracker) {
+ return tracker.largest_observed_;
+ }
+ static int packets_entropy_size(
+ const QuicReceivedPacketManager::EntropyTracker& tracker) {
+ return tracker.packets_entropy_.size();
+ }
+ static bool IsTrackingPacket(
+ const QuicReceivedPacketManager::EntropyTracker& tracker,
+ QuicPacketNumber packet_number) {
+ return packet_number >= tracker.first_gap_ &&
+ packet_number <
+ (tracker.first_gap_ + tracker.packets_entropy_.size()) &&
+ tracker.packets_entropy_[packet_number - tracker.first_gap_].second;
+ }
+};
+
+namespace {
+
+// Entropy of individual packets is not tracked if there are no gaps.
+TEST(EntropyTrackerTest, NoGaps) {
+ QuicReceivedPacketManager::EntropyTracker tracker;
+
+ tracker.RecordPacketEntropyHash(1, 23);
+ tracker.RecordPacketEntropyHash(2, 42);
+
+ EXPECT_EQ(23 ^ 42, tracker.EntropyHash(2));
+ EXPECT_EQ(3u, EntropyTrackerPeer::first_gap(tracker));
+
+ EXPECT_EQ(2u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(0, EntropyTrackerPeer::packets_entropy_size(tracker));
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 1));
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 2));
+}
+
+// Entropy of individual packets is tracked as long as there are gaps.
+// Filling the first gap results in entropy getting garbage collected.
+TEST(EntropyTrackerTest, FillGaps) {
+ QuicReceivedPacketManager::EntropyTracker tracker;
+
+ tracker.RecordPacketEntropyHash(2, 5);
+ tracker.RecordPacketEntropyHash(5, 17);
+ tracker.RecordPacketEntropyHash(6, 23);
+ tracker.RecordPacketEntropyHash(9, 42);
+
+ EXPECT_EQ(1u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(9, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(5, tracker.EntropyHash(2));
+ EXPECT_EQ(5 ^ 17, tracker.EntropyHash(5));
+ EXPECT_EQ(5 ^ 17 ^ 23, tracker.EntropyHash(6));
+ EXPECT_EQ(5 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
+
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 1));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 2));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 5));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 6));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 9));
+
+ // Fill the gap at 1.
+ tracker.RecordPacketEntropyHash(1, 2);
+
+ EXPECT_EQ(3u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(7, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(2 ^ 5 ^ 17, tracker.EntropyHash(5));
+ EXPECT_EQ(2 ^ 5 ^ 17 ^ 23, tracker.EntropyHash(6));
+ EXPECT_EQ(2 ^ 5 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
+
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 1));
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 2));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 5));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 6));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 9));
+
+ // Fill the gap at 4.
+ tracker.RecordPacketEntropyHash(4, 2);
+
+ EXPECT_EQ(3u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(7, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(5, tracker.EntropyHash(4));
+ EXPECT_EQ(5 ^ 17, tracker.EntropyHash(5));
+ EXPECT_EQ(5 ^ 17 ^ 23, tracker.EntropyHash(6));
+ EXPECT_EQ(5 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
+
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 3));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 4));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 5));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 6));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 9));
+
+ // Fill the gap at 3. Entropy for packets 3 to 6 are forgotten.
+ tracker.RecordPacketEntropyHash(3, 2);
+
+ EXPECT_EQ(7u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(3, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(2 ^ 5 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
+
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 3));
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 4));
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 5));
+ EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 6));
+ EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 9));
+
+ // Fill in the rest.
+ tracker.RecordPacketEntropyHash(7, 2);
+ tracker.RecordPacketEntropyHash(8, 2);
+
+ EXPECT_EQ(10u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(0, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(2 ^ 5 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
+}
+
+TEST(EntropyTrackerTest, SetCumulativeEntropyUpTo) {
+ QuicReceivedPacketManager::EntropyTracker tracker;
+
+ tracker.RecordPacketEntropyHash(2, 5);
+ tracker.RecordPacketEntropyHash(5, 17);
+ tracker.RecordPacketEntropyHash(6, 23);
+ tracker.RecordPacketEntropyHash(9, 42);
+
+ EXPECT_EQ(1u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(9, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ // Inform the tracker about value of the hash at a gap.
+ tracker.SetCumulativeEntropyUpTo(3, 7);
+ EXPECT_EQ(3u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(7, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(7 ^ 17, tracker.EntropyHash(5));
+ EXPECT_EQ(7 ^ 17 ^ 23, tracker.EntropyHash(6));
+ EXPECT_EQ(7 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
+
+ // Inform the tracker about value of the hash at a known location.
+ tracker.SetCumulativeEntropyUpTo(6, 1);
+ EXPECT_EQ(7u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(3, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(1 ^ 23 ^ 42, tracker.EntropyHash(9));
+
+ // Inform the tracker about value of the hash at the last location.
+ tracker.SetCumulativeEntropyUpTo(9, 21);
+ EXPECT_EQ(10u, EntropyTrackerPeer::first_gap(tracker));
+ EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
+ EXPECT_EQ(0, EntropyTrackerPeer::packets_entropy_size(tracker));
+
+ EXPECT_EQ(42 ^ 21, tracker.EntropyHash(9));
+}
+
+struct TestParams {
+ explicit TestParams(QuicVersion version) : version(version) {}
+
+ friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
+ os << "{ version: " << QuicVersionToString(p.version) << " }";
+ return os;
+ }
+
+ QuicVersion version;
+};
+
+vector<TestParams> GetTestParams() {
+ vector<TestParams> params;
+ QuicVersionVector all_supported_versions = AllSupportedVersions();
+ for (size_t i = 0; i < all_supported_versions.size(); ++i) {
+ params.push_back(TestParams(all_supported_versions[i]));
+ }
+ return params;
+}
+
+class QuicReceivedPacketManagerTest
+ : public ::testing::TestWithParam<TestParams> {
+ protected:
+ QuicReceivedPacketManagerTest() : received_manager_(&stats_) {
+ received_manager_.SetVersion(GetParam().version);
+ }
+
+ void RecordPacketReceipt(QuicPacketNumber packet_number,
+ QuicPacketEntropyHash entropy_hash) {
+ RecordPacketReceipt(packet_number, entropy_hash, QuicTime::Zero());
+ }
+
+ void RecordPacketReceipt(QuicPacketNumber packet_number,
+ QuicPacketEntropyHash entropy_hash,
+ QuicTime receipt_time) {
+ QuicPacketHeader header;
+ header.packet_number = packet_number;
+ header.entropy_hash = entropy_hash;
+ received_manager_.RecordPacketReceived(header, receipt_time);
+ }
+
+ QuicConnectionStats stats_;
+ QuicReceivedPacketManager received_manager_;
+};
+
+INSTANTIATE_TEST_CASE_P(QuicReceivedPacketManagerTest,
+ QuicReceivedPacketManagerTest,
+ ::testing::ValuesIn(GetTestParams()));
+
+TEST_P(QuicReceivedPacketManagerTest, ReceivedPacketEntropyHash) {
+ if (GetParam().version > QUIC_VERSION_33) {
+ return;
+ }
+ vector<pair<QuicPacketNumber, QuicPacketEntropyHash>> entropies;
+ entropies.push_back(std::make_pair(1, 12));
+ entropies.push_back(std::make_pair(7, 1));
+ entropies.push_back(std::make_pair(2, 33));
+ entropies.push_back(std::make_pair(5, 3));
+ entropies.push_back(std::make_pair(8, 34));
+
+ for (size_t i = 0; i < entropies.size(); ++i) {
+ RecordPacketReceipt(entropies[i].first, entropies[i].second);
+ }
+
+ std::sort(entropies.begin(), entropies.end());
+
+ QuicPacketEntropyHash hash = 0;
+ size_t index = 0;
+ for (size_t i = 1; i <= (*entropies.rbegin()).first; ++i) {
+ if (entropies[index].first == i) {
+ hash ^= entropies[index].second;
+ ++index;
+ }
+ if (i < 3)
+ continue;
+ EXPECT_EQ(hash, received_manager_.EntropyHash(i));
+ }
+ // Reorder by 5 when 2 is received after 7.
+ EXPECT_EQ(5u, stats_.max_sequence_reordering);
+ EXPECT_EQ(0, stats_.max_time_reordering_us);
+ EXPECT_EQ(2u, stats_.packets_reordered);
+}
+
+TEST_P(QuicReceivedPacketManagerTest, EntropyHashBelowLeastObserved) {
+ if (GetParam().version > QUIC_VERSION_33) {
+ return;
+ }
+ EXPECT_EQ(0, received_manager_.EntropyHash(0));
+ RecordPacketReceipt(4, 5);
+ EXPECT_EQ(0, received_manager_.EntropyHash(3));
+}
+
+TEST_P(QuicReceivedPacketManagerTest, EntropyHashAboveLargestObserved) {
+ if (GetParam().version > QUIC_VERSION_33) {
+ return;
+ }
+ EXPECT_EQ(0, received_manager_.EntropyHash(0));
+ RecordPacketReceipt(4, 5);
+ EXPECT_EQ(0, received_manager_.EntropyHash(3));
+}
+
+TEST_P(QuicReceivedPacketManagerTest, SetCumulativeEntropyUpTo) {
+ if (GetParam().version > QUIC_VERSION_33) {
+ return;
+ }
+ vector<pair<QuicPacketNumber, QuicPacketEntropyHash>> entropies;
+ entropies.push_back(std::make_pair(1, 12));
+ entropies.push_back(std::make_pair(2, 1));
+ entropies.push_back(std::make_pair(3, 33));
+ entropies.push_back(std::make_pair(4, 3));
+ entropies.push_back(std::make_pair(6, 34));
+ entropies.push_back(std::make_pair(7, 29));
+
+ QuicPacketEntropyHash entropy_hash = 0;
+ for (size_t i = 0; i < entropies.size(); ++i) {
+ RecordPacketReceipt(entropies[i].first, entropies[i].second);
+ entropy_hash ^= entropies[i].second;
+ }
+ EXPECT_EQ(entropy_hash, received_manager_.EntropyHash(7));
+
+ // Now set the entropy hash up to 5 to be 100.
+ entropy_hash ^= 100;
+ for (size_t i = 0; i < 4; ++i) {
+ entropy_hash ^= entropies[i].second;
+ }
+ QuicReceivedPacketManagerPeer::SetCumulativeEntropyUpTo(&received_manager_, 5,
+ 100);
+ EXPECT_EQ(entropy_hash, received_manager_.EntropyHash(7));
+
+ QuicReceivedPacketManagerPeer::SetCumulativeEntropyUpTo(&received_manager_, 1,
+ 50);
+ EXPECT_EQ(entropy_hash, received_manager_.EntropyHash(7));
+
+ // No reordering.
+ EXPECT_EQ(0u, stats_.max_sequence_reordering);
+ EXPECT_EQ(0, stats_.max_time_reordering_us);
+ EXPECT_EQ(0u, stats_.packets_reordered);
+}
+
+TEST_P(QuicReceivedPacketManagerTest, DontWaitForPacketsBefore) {
+ QuicPacketHeader header;
+ header.packet_number = 2u;
+ received_manager_.RecordPacketReceived(header, QuicTime::Zero());
+ header.packet_number = 7u;
+ received_manager_.RecordPacketReceived(header, QuicTime::Zero());
+ EXPECT_TRUE(received_manager_.IsAwaitingPacket(3u));
+ EXPECT_TRUE(received_manager_.IsAwaitingPacket(6u));
+ EXPECT_TRUE(QuicReceivedPacketManagerPeer::DontWaitForPacketsBefore(
+ &received_manager_, 4));
+ EXPECT_FALSE(received_manager_.IsAwaitingPacket(3u));
+ EXPECT_TRUE(received_manager_.IsAwaitingPacket(6u));
+}
+
+TEST_P(QuicReceivedPacketManagerTest, GetUpdatedAckFrame) {
+ QuicPacketHeader header;
+ header.packet_number = 2u;
+ QuicTime two_ms = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(2);
+ EXPECT_FALSE(received_manager_.ack_frame_updated());
+ received_manager_.RecordPacketReceived(header, two_ms);
+ EXPECT_TRUE(received_manager_.ack_frame_updated());
+
+ QuicFrame ack = received_manager_.GetUpdatedAckFrame(QuicTime::Zero());
+ EXPECT_FALSE(received_manager_.ack_frame_updated());
+ // When UpdateReceivedPacketInfo with a time earlier than the time of the
+ // largest observed packet, make sure that the delta is 0, not negative.
+ EXPECT_EQ(QuicTime::Delta::Zero(), ack.ack_frame->ack_delay_time);
+ EXPECT_EQ(1u, ack.ack_frame->received_packet_times.size());
+
+ QuicTime four_ms = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(4);
+ ack = received_manager_.GetUpdatedAckFrame(four_ms);
+ EXPECT_FALSE(received_manager_.ack_frame_updated());
+ // When UpdateReceivedPacketInfo after not having received a new packet,
+ // the delta should still be accurate.
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(2),
+ ack.ack_frame->ack_delay_time);
+ // And received packet times won't have change.
+ EXPECT_EQ(1u, ack.ack_frame->received_packet_times.size());
+
+ header.packet_number = 999u;
+ received_manager_.RecordPacketReceived(header, two_ms);
+ header.packet_number = 4u;
+ received_manager_.RecordPacketReceived(header, two_ms);
+ header.packet_number = 1000u;
+ received_manager_.RecordPacketReceived(header, two_ms);
+ EXPECT_TRUE(received_manager_.ack_frame_updated());
+ ack = received_manager_.GetUpdatedAckFrame(two_ms);
+ EXPECT_FALSE(received_manager_.ack_frame_updated());
+ // UpdateReceivedPacketInfo should discard any times which can't be
+ // expressed on the wire.
+ EXPECT_EQ(2u, ack.ack_frame->received_packet_times.size());
+}
+
+TEST_P(QuicReceivedPacketManagerTest, UpdateReceivedConnectionStats) {
+ EXPECT_FALSE(received_manager_.ack_frame_updated());
+ RecordPacketReceipt(1, 0);
+ EXPECT_TRUE(received_manager_.ack_frame_updated());
+ RecordPacketReceipt(6, 0);
+ RecordPacketReceipt(2, 0,
+ QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1));
+
+ EXPECT_EQ(4u, stats_.max_sequence_reordering);
+ EXPECT_EQ(1000, stats_.max_time_reordering_us);
+ EXPECT_EQ(1u, stats_.packets_reordered);
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_sent_entropy_manager.cc b/chromium/net/quic/core/quic_sent_entropy_manager.cc
new file mode 100644
index 00000000000..f10e5bc7673
--- /dev/null
+++ b/chromium/net/quic/core/quic_sent_entropy_manager.cc
@@ -0,0 +1,113 @@
+// Copyright 2013 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/quic_sent_entropy_manager.h"
+
+#include "base/logging.h"
+#include "net/base/linked_hash_map.h"
+#include "net/quic/core/quic_flags.h"
+
+using std::make_pair;
+using std::max;
+using std::min;
+
+namespace net {
+
+QuicSentEntropyManager::QuicSentEntropyManager() : map_offset_(1) {}
+
+QuicSentEntropyManager::~QuicSentEntropyManager() {}
+
+QuicPacketEntropyHash QuicSentEntropyManager::GetPacketEntropy(
+ QuicPacketNumber packet_number) const {
+ return packets_entropy_[packet_number - map_offset_];
+}
+
+QuicPacketNumber QuicSentEntropyManager::GetLargestPacketWithEntropy() const {
+ return map_offset_ + packets_entropy_.size() - 1;
+}
+
+QuicPacketNumber QuicSentEntropyManager::GetSmallestPacketWithEntropy() const {
+ return map_offset_;
+}
+
+void QuicSentEntropyManager::UpdateCumulativeEntropy(
+ QuicPacketNumber packet_number,
+ CumulativeEntropy* cumulative) const {
+ while (cumulative->packet_number < packet_number) {
+ ++cumulative->packet_number;
+ cumulative->entropy ^= GetPacketEntropy(cumulative->packet_number);
+ }
+}
+
+void QuicSentEntropyManager::RecordPacketEntropyHash(
+ QuicPacketNumber packet_number,
+ QuicPacketEntropyHash entropy_hash) {
+ if (!packets_entropy_.empty()) {
+ // Ensure packets always are recorded in order.
+ // Every packet's entropy is recorded, even if it's not sent, so there
+ // are not packet number gaps.
+ DCHECK_EQ(GetLargestPacketWithEntropy() + 1, packet_number);
+ }
+ packets_entropy_.push_back(entropy_hash);
+ DVLOG(2) << "Recorded packet number " << packet_number
+ << " with entropy hash: " << static_cast<int>(entropy_hash);
+}
+
+QuicPacketEntropyHash QuicSentEntropyManager::GetCumulativeEntropy(
+ QuicPacketNumber packet_number) {
+ DCHECK_LE(last_cumulative_entropy_.packet_number, packet_number);
+ DCHECK_GE(GetLargestPacketWithEntropy(), packet_number);
+ // First the entropy for largest_observed packet number should be updated.
+ UpdateCumulativeEntropy(packet_number, &last_cumulative_entropy_);
+ return last_cumulative_entropy_.entropy;
+}
+
+bool QuicSentEntropyManager::IsValidEntropy(
+ QuicPacketNumber largest_observed,
+ const PacketNumberQueue& missing_packets,
+ QuicPacketEntropyHash entropy_hash) {
+ DCHECK_GE(largest_observed, last_valid_entropy_.packet_number);
+ // Ensure the largest and smallest packet numbers are in range.
+ if (largest_observed > GetLargestPacketWithEntropy()) {
+ return false;
+ }
+ if (!missing_packets.Empty() &&
+ missing_packets.Min() < GetSmallestPacketWithEntropy()) {
+ return false;
+ }
+ // First the entropy for largest_observed packet number should be updated.
+ UpdateCumulativeEntropy(largest_observed, &last_valid_entropy_);
+
+ // Now XOR out all the missing entropies.
+ QuicPacketEntropyHash expected_entropy_hash = last_valid_entropy_.entropy;
+ for (const Interval<QuicPacketNumber>& interval : missing_packets) {
+ for (QuicPacketNumber packet_number = interval.min();
+ packet_number < interval.max(); ++packet_number) {
+ expected_entropy_hash ^= GetPacketEntropy(packet_number);
+ }
+ }
+ DLOG_IF(WARNING, entropy_hash != expected_entropy_hash)
+ << "Invalid entropy hash: " << static_cast<int>(entropy_hash)
+ << " expected entropy hash: " << static_cast<int>(expected_entropy_hash);
+ return entropy_hash == expected_entropy_hash;
+}
+
+void QuicSentEntropyManager::ClearEntropyBefore(
+ QuicPacketNumber packet_number) {
+ // Don't discard entropy before updating the cumulative entropy used to
+ // calculate EntropyHash and IsValidEntropy.
+ if (last_cumulative_entropy_.packet_number < packet_number) {
+ UpdateCumulativeEntropy(packet_number, &last_cumulative_entropy_);
+ }
+ if (last_valid_entropy_.packet_number < packet_number) {
+ UpdateCumulativeEntropy(packet_number, &last_valid_entropy_);
+ }
+ while (map_offset_ < packet_number) {
+ packets_entropy_.pop_front();
+ ++map_offset_;
+ }
+ DVLOG(2) << "Cleared entropy before: " << packet_number;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_sent_entropy_manager.h b/chromium/net/quic/core/quic_sent_entropy_manager.h
new file mode 100644
index 00000000000..59733a028e9
--- /dev/null
+++ b/chromium/net/quic/core/quic_sent_entropy_manager.h
@@ -0,0 +1,89 @@
+// Copyright 2013 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.
+//
+// Manages the packet entropy calculation for both sent and received packets
+// for a connection.
+
+#ifndef NET_QUIC_QUIC_SENT_ENTROPY_MANAGER_H_
+#define NET_QUIC_QUIC_SENT_ENTROPY_MANAGER_H_
+
+#include <deque>
+
+#include "base/macros.h"
+#include "net/base/linked_hash_map.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+namespace test {
+class QuicConnectionPeer;
+} // namespace test
+
+// Records all sent packets by a connection to track the cumulative entropy of
+// sent packets. It is used by the connection to validate an ack
+// frame sent by the peer as a preventive measure against the optimistic ack
+// attack.
+class NET_EXPORT_PRIVATE QuicSentEntropyManager {
+ public:
+ QuicSentEntropyManager();
+ virtual ~QuicSentEntropyManager();
+
+ // Record |entropy_hash| for sent packet corresponding to |packet_number|.
+ void RecordPacketEntropyHash(QuicPacketNumber packet_number,
+ QuicPacketEntropyHash entropy_hash);
+
+ // Retrieves the cumulative entropy up to |packet_number|.
+ // Must always be called with a monotonically increasing |packet_number|.
+ QuicPacketEntropyHash GetCumulativeEntropy(QuicPacketNumber packet_number);
+
+ // Returns true if |entropy_hash| matches the expected sent entropy hash
+ // up to |largest_observed| removing packet numbers from |missing_packets|.
+ // Must always be called with a monotonically increasing |largest_observed|.
+ bool IsValidEntropy(QuicPacketNumber largest_observed,
+ const PacketNumberQueue& missing_packets,
+ QuicPacketEntropyHash entropy_hash);
+
+ // Removes unnecessary entries before |packet_number|.
+ void ClearEntropyBefore(QuicPacketNumber packet_number);
+
+ private:
+ friend class test::QuicConnectionPeer;
+
+ typedef std::deque<QuicPacketEntropyHash> SentEntropyMap;
+
+ struct CumulativeEntropy {
+ CumulativeEntropy() : packet_number(0), entropy(0) {}
+
+ QuicPacketNumber packet_number;
+ QuicPacketEntropyHash entropy;
+ };
+
+ // Convenience methods to get the largest and smallest packets with entropies.
+ QuicPacketNumber GetLargestPacketWithEntropy() const;
+ QuicPacketNumber GetSmallestPacketWithEntropy() const;
+ // Convenience method to get the entropy hash for |packet_number|.
+ QuicPacketEntropyHash GetPacketEntropy(QuicPacketNumber packet_number) const;
+
+ // Update the cumulative entropy to |packet_number|.
+ void UpdateCumulativeEntropy(QuicPacketNumber packet_number,
+ CumulativeEntropy* cumulative) const;
+
+ // Maps packet numbers to the sent entropy hash for the packet number.
+ SentEntropyMap packets_entropy_;
+ QuicPacketNumber map_offset_;
+
+ // Cache the cumulative entropy for IsValidEntropy.
+ CumulativeEntropy last_valid_entropy_;
+
+ // Cache the cumulative entropy for the packet number used by EntropyHash.
+ CumulativeEntropy last_cumulative_entropy_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicSentEntropyManager);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_SENT_ENTROPY_MANAGER_H_
diff --git a/chromium/net/quic/core/quic_sent_entropy_manager_test.cc b/chromium/net/quic/core/quic_sent_entropy_manager_test.cc
new file mode 100644
index 00000000000..1f30ab0f558
--- /dev/null
+++ b/chromium/net/quic/core/quic_sent_entropy_manager_test.cc
@@ -0,0 +1,96 @@
+// Copyright 2013 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/quic_sent_entropy_manager.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::make_pair;
+using std::pair;
+
+namespace net {
+namespace test {
+namespace {
+
+class QuicSentEntropyManagerTest : public ::testing::Test {
+ protected:
+ QuicSentEntropyManager entropy_manager_;
+};
+
+TEST_F(QuicSentEntropyManagerTest, SentEntropyHash) {
+ EXPECT_EQ(0, entropy_manager_.GetCumulativeEntropy(0));
+
+ QuicPacketEntropyHash entropies[4] = {12, 1, 33, 3};
+ for (size_t i = 0; i < arraysize(entropies); ++i) {
+ entropy_manager_.RecordPacketEntropyHash(i + 1, entropies[i]);
+ }
+
+ QuicPacketEntropyHash hash = 0;
+ for (size_t i = 0; i < arraysize(entropies); ++i) {
+ hash ^= entropies[i];
+ EXPECT_EQ(hash, entropy_manager_.GetCumulativeEntropy(i + 1));
+ }
+}
+
+TEST_F(QuicSentEntropyManagerTest, IsValidEntropy) {
+ QuicPacketEntropyHash entropies[10] = {12, 1, 33, 3, 32,
+ 100, 28, 42, 22, 255};
+ for (size_t i = 0; i < arraysize(entropies); ++i) {
+ entropy_manager_.RecordPacketEntropyHash(i + 1, entropies[i]);
+ }
+
+ PacketNumberQueue missing_packets;
+ missing_packets.Add(1);
+ missing_packets.Add(4);
+ missing_packets.Add(7, 9);
+
+ QuicPacketEntropyHash entropy_hash = 0;
+ for (size_t i = 0; i < arraysize(entropies); ++i) {
+ if (!missing_packets.Contains(i + 1)) {
+ entropy_hash ^= entropies[i];
+ }
+ }
+
+ EXPECT_TRUE(
+ entropy_manager_.IsValidEntropy(10, missing_packets, entropy_hash));
+}
+
+TEST_F(QuicSentEntropyManagerTest, ClearEntropiesBefore) {
+ QuicPacketEntropyHash entropies[10] = {12, 1, 33, 3, 32,
+ 100, 28, 42, 22, 255};
+
+ for (size_t i = 0; i < arraysize(entropies); ++i) {
+ entropy_manager_.RecordPacketEntropyHash(i + 1, entropies[i]);
+ }
+
+ // Discard the first 5 entropies and ensure IsValidEntropy and EntropyHash
+ // still return correct results.
+ entropy_manager_.ClearEntropyBefore(5);
+
+ PacketNumberQueue missing_packets;
+ missing_packets.Add(7, 9);
+
+ QuicPacketEntropyHash entropy_hash = 0;
+ for (size_t i = 0; i < arraysize(entropies); ++i) {
+ if (!missing_packets.Contains(i + 1)) {
+ entropy_hash ^= entropies[i];
+ }
+ }
+ EXPECT_TRUE(
+ entropy_manager_.IsValidEntropy(10, missing_packets, entropy_hash));
+
+ entropy_hash = 0;
+ for (size_t i = 0; i < arraysize(entropies); ++i) {
+ entropy_hash ^= entropies[i];
+ }
+ EXPECT_EQ(entropy_hash, entropy_manager_.GetCumulativeEntropy(10));
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_sent_packet_manager.cc b/chromium/net/quic/core/quic_sent_packet_manager.cc
new file mode 100644
index 00000000000..c38db4c7548
--- /dev/null
+++ b/chromium/net/quic/core/quic_sent_packet_manager.cc
@@ -0,0 +1,1015 @@
+// Copyright 2013 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/quic_sent_packet_manager.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "net/quic/chromium/quic_utils_chromium.h"
+#include "net/quic/core/congestion_control/general_loss_algorithm.h"
+#include "net/quic/core/congestion_control/pacing_sender.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/proto/cached_network_parameters.pb.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_connection_stats.h"
+#include "net/quic/core/quic_flags.h"
+
+using std::max;
+using std::min;
+using std::pair;
+
+namespace net {
+
+namespace {
+static const int64_t kDefaultRetransmissionTimeMs = 500;
+static const int64_t kMaxRetransmissionTimeMs = 60000;
+// Maximum number of exponential backoffs used for RTO timeouts.
+static const size_t kMaxRetransmissions = 10;
+// Maximum number of packets retransmitted upon an RTO.
+static const size_t kMaxRetransmissionsOnTimeout = 2;
+// Minimum number of consecutive RTOs before path is considered to be degrading.
+const size_t kMinTimeoutsBeforePathDegrading = 2;
+
+// Ensure the handshake timer isnt't faster than 10ms.
+// This limits the tenth retransmitted packet to 10s after the initial CHLO.
+static const int64_t kMinHandshakeTimeoutMs = 10;
+
+// Ensure the handshake timer isnt't faster than 25ms.
+static const int64_t kConservativeMinHandshakeTimeoutMs = kMaxDelayedAckTimeMs;
+
+// Sends up to two tail loss probes before firing an RTO,
+// per draft RFC draft-dukkipati-tcpm-tcp-loss-probe.
+static const size_t kDefaultMaxTailLossProbes = 2;
+
+bool HasCryptoHandshake(const TransmissionInfo& transmission_info) {
+ DCHECK(!transmission_info.has_crypto_handshake ||
+ !transmission_info.retransmittable_frames.empty());
+ return transmission_info.has_crypto_handshake;
+}
+
+} // namespace
+
+#define ENDPOINT \
+ (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ")
+
+QuicSentPacketManager::QuicSentPacketManager(
+ Perspective perspective,
+ QuicPathId path_id,
+ const QuicClock* clock,
+ QuicConnectionStats* stats,
+ CongestionControlType congestion_control_type,
+ LossDetectionType loss_type,
+ MultipathDelegateInterface* delegate)
+ : unacked_packets_(),
+ perspective_(perspective),
+ path_id_(path_id),
+ clock_(clock),
+ stats_(stats),
+ delegate_(delegate),
+ debug_delegate_(nullptr),
+ network_change_visitor_(nullptr),
+ initial_congestion_window_(kInitialCongestionWindow),
+ loss_algorithm_(&general_loss_algorithm_),
+ general_loss_algorithm_(loss_type),
+ n_connection_simulation_(false),
+ receive_buffer_bytes_(kDefaultSocketReceiveBuffer),
+ least_packet_awaited_by_peer_(1),
+ first_rto_transmission_(0),
+ consecutive_rto_count_(0),
+ consecutive_tlp_count_(0),
+ consecutive_crypto_retransmission_count_(0),
+ pending_timer_transmission_count_(0),
+ max_tail_loss_probes_(kDefaultMaxTailLossProbes),
+ enable_half_rtt_tail_loss_probe_(false),
+ using_pacing_(false),
+ use_new_rto_(false),
+ undo_pending_retransmits_(false),
+ conservative_handshake_retransmits_(false),
+ largest_newly_acked_(0),
+ largest_mtu_acked_(0),
+ handshake_confirmed_(false) {
+ SetSendAlgorithm(congestion_control_type);
+}
+
+QuicSentPacketManager::~QuicSentPacketManager() {}
+
+void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
+ if (config.HasReceivedInitialRoundTripTimeUs() &&
+ config.ReceivedInitialRoundTripTimeUs() > 0) {
+ rtt_stats_.set_initial_rtt_us(
+ max(kMinInitialRoundTripTimeUs,
+ min(kMaxInitialRoundTripTimeUs,
+ config.ReceivedInitialRoundTripTimeUs())));
+ } else if (config.HasInitialRoundTripTimeUsToSend() &&
+ config.GetInitialRoundTripTimeUsToSend() > 0) {
+ rtt_stats_.set_initial_rtt_us(
+ max(kMinInitialRoundTripTimeUs,
+ min(kMaxInitialRoundTripTimeUs,
+ config.GetInitialRoundTripTimeUsToSend())));
+ }
+ // TODO(ianswett): BBR is currently a server only feature.
+ if (FLAGS_quic_allow_bbr && config.HasReceivedConnectionOptions() &&
+ ContainsQuicTag(config.ReceivedConnectionOptions(), kTBBR)) {
+ SetSendAlgorithm(kBBR);
+ }
+ if (config.HasReceivedConnectionOptions() &&
+ ContainsQuicTag(config.ReceivedConnectionOptions(), kRENO)) {
+ if (ContainsQuicTag(config.ReceivedConnectionOptions(), kBYTE)) {
+ SetSendAlgorithm(kRenoBytes);
+ } else {
+ SetSendAlgorithm(kReno);
+ }
+ } else if (config.HasReceivedConnectionOptions() &&
+ ContainsQuicTag(config.ReceivedConnectionOptions(), kBYTE)) {
+ SetSendAlgorithm(kCubicBytes);
+ }
+ using_pacing_ = !FLAGS_quic_disable_pacing_for_perf_tests;
+
+ if (config.HasClientSentConnectionOption(k1CON, perspective_)) {
+ send_algorithm_->SetNumEmulatedConnections(1);
+ }
+ if (config.HasClientSentConnectionOption(kNCON, perspective_)) {
+ n_connection_simulation_ = true;
+ }
+ if (config.HasClientSentConnectionOption(kNTLP, perspective_)) {
+ max_tail_loss_probes_ = 0;
+ }
+ if (config.HasClientSentConnectionOption(kTLPR, perspective_)) {
+ enable_half_rtt_tail_loss_probe_ = true;
+ }
+ if (config.HasClientSentConnectionOption(kNRTO, perspective_)) {
+ use_new_rto_ = true;
+ }
+ if (config.HasReceivedConnectionOptions() &&
+ ContainsQuicTag(config.ReceivedConnectionOptions(), kTIME)) {
+ general_loss_algorithm_.SetLossDetectionType(kTime);
+ }
+ if (config.HasReceivedConnectionOptions() &&
+ ContainsQuicTag(config.ReceivedConnectionOptions(), kATIM)) {
+ general_loss_algorithm_.SetLossDetectionType(kAdaptiveTime);
+ }
+ if (config.HasClientSentConnectionOption(kUNDO, perspective_)) {
+ undo_pending_retransmits_ = true;
+ }
+ if (FLAGS_quic_conservative_handshake_retransmits &&
+ config.HasClientSentConnectionOption(kCONH, perspective_)) {
+ conservative_handshake_retransmits_ = true;
+ }
+ send_algorithm_->SetFromConfig(config, perspective_);
+
+ if (network_change_visitor_ != nullptr) {
+ network_change_visitor_->OnCongestionChange();
+ }
+}
+
+void QuicSentPacketManager::ResumeConnectionState(
+ const CachedNetworkParameters& cached_network_params,
+ bool max_bandwidth_resumption) {
+ if (cached_network_params.has_min_rtt_ms()) {
+ uint32_t initial_rtt_us =
+ kNumMicrosPerMilli * cached_network_params.min_rtt_ms();
+ rtt_stats_.set_initial_rtt_us(
+ max(kMinInitialRoundTripTimeUs,
+ min(kMaxInitialRoundTripTimeUs, initial_rtt_us)));
+ }
+ send_algorithm_->ResumeConnectionState(cached_network_params,
+ max_bandwidth_resumption);
+}
+
+void QuicSentPacketManager::SetNumOpenStreams(size_t num_streams) {
+ if (n_connection_simulation_) {
+ // Ensure the number of connections is between 1 and 5.
+ send_algorithm_->SetNumEmulatedConnections(
+ min<size_t>(5, max<size_t>(1, num_streams)));
+ }
+}
+
+void QuicSentPacketManager::SetMaxPacingRate(QuicBandwidth max_pacing_rate) {
+ pacing_sender_.set_max_pacing_rate(max_pacing_rate);
+}
+
+void QuicSentPacketManager::SetHandshakeConfirmed() {
+ handshake_confirmed_ = true;
+}
+
+void QuicSentPacketManager::OnIncomingAck(const QuicAckFrame& ack_frame,
+ QuicTime ack_receive_time) {
+ DCHECK_LE(ack_frame.largest_observed, unacked_packets_.largest_sent_packet());
+ QuicByteCount bytes_in_flight = unacked_packets_.bytes_in_flight();
+ UpdatePacketInformationReceivedByPeer(ack_frame);
+ bool rtt_updated = MaybeUpdateRTT(ack_frame, ack_receive_time);
+ DCHECK_GE(ack_frame.largest_observed, unacked_packets_.largest_observed());
+ unacked_packets_.IncreaseLargestObserved(ack_frame.largest_observed);
+
+ HandleAckForSentPackets(ack_frame);
+ InvokeLossDetection(ack_receive_time);
+ // Ignore losses in RTO mode.
+ if (consecutive_rto_count_ > 0 && !use_new_rto_) {
+ packets_lost_.clear();
+ }
+ MaybeInvokeCongestionEvent(rtt_updated, bytes_in_flight);
+ unacked_packets_.RemoveObsoletePackets();
+
+ sustained_bandwidth_recorder_.RecordEstimate(
+ send_algorithm_->InRecovery(), send_algorithm_->InSlowStart(),
+ send_algorithm_->BandwidthEstimate(), ack_receive_time, clock_->WallNow(),
+ rtt_stats_.smoothed_rtt());
+
+ // Anytime we are making forward progress and have a new RTT estimate, reset
+ // the backoff counters.
+ if (rtt_updated) {
+ if (consecutive_rto_count_ > 0) {
+ // If the ack acknowledges data sent prior to the RTO,
+ // the RTO was spurious.
+ if (ack_frame.largest_observed < first_rto_transmission_) {
+ // Replace SRTT with latest_rtt and increase the variance to prevent
+ // a spurious RTO from happening again.
+ rtt_stats_.ExpireSmoothedMetrics();
+ } else {
+ if (!use_new_rto_) {
+ send_algorithm_->OnRetransmissionTimeout(true);
+ }
+ }
+ }
+ // Reset all retransmit counters any time a new packet is acked.
+ consecutive_rto_count_ = 0;
+ consecutive_tlp_count_ = 0;
+ consecutive_crypto_retransmission_count_ = 0;
+ }
+ // TODO(ianswett): Consider replacing the pending_retransmissions_ with a
+ // fast way to retrieve the next pending retransmission, if there are any.
+ // A single packet number indicating all packets below that are lost should
+ // be all the state that is necessary.
+ while (undo_pending_retransmits_ && !pending_retransmissions_.empty() &&
+ pending_retransmissions_.front().first > largest_newly_acked_ &&
+ pending_retransmissions_.front().second == LOSS_RETRANSMISSION) {
+ // Cancel any pending retransmissions larger than largest_newly_acked_.
+ unacked_packets_.RestoreToInFlight(pending_retransmissions_.front().first);
+ pending_retransmissions_.erase(pending_retransmissions_.begin());
+ }
+
+ if (debug_delegate_ != nullptr) {
+ debug_delegate_->OnIncomingAck(ack_frame, ack_receive_time,
+ unacked_packets_.largest_observed(),
+ rtt_updated, GetLeastUnacked(path_id_));
+ }
+}
+
+void QuicSentPacketManager::UpdatePacketInformationReceivedByPeer(
+ const QuicAckFrame& ack_frame) {
+ if (ack_frame.packets.Empty()) {
+ least_packet_awaited_by_peer_ = ack_frame.largest_observed + 1;
+ } else {
+ least_packet_awaited_by_peer_ = ack_frame.packets.Min();
+ }
+}
+
+void QuicSentPacketManager::MaybeInvokeCongestionEvent(
+ bool rtt_updated,
+ QuicByteCount bytes_in_flight) {
+ if (!rtt_updated && packets_acked_.empty() && packets_lost_.empty()) {
+ return;
+ }
+ if (using_pacing_) {
+ pacing_sender_.OnCongestionEvent(rtt_updated, bytes_in_flight,
+ packets_acked_, packets_lost_);
+ } else {
+ send_algorithm_->OnCongestionEvent(rtt_updated, bytes_in_flight,
+ packets_acked_, packets_lost_);
+ }
+ packets_acked_.clear();
+ packets_lost_.clear();
+ if (network_change_visitor_ != nullptr) {
+ network_change_visitor_->OnCongestionChange();
+ }
+}
+
+void QuicSentPacketManager::HandleAckForSentPackets(
+ const QuicAckFrame& ack_frame) {
+ // Go through the packets we have not received an ack for and see if this
+ // incoming_ack shows they've been seen by the peer.
+ QuicTime::Delta ack_delay_time = ack_frame.ack_delay_time;
+ QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
+ for (QuicUnackedPacketMap::iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it, ++packet_number) {
+ if (packet_number > ack_frame.largest_observed) {
+ // These packets are still in flight.
+ break;
+ }
+
+ if ((ack_frame.missing && ack_frame.packets.Contains(packet_number)) ||
+ (!ack_frame.missing && !ack_frame.packets.Contains(packet_number))) {
+ // Packet is still missing.
+ continue;
+ }
+ // Packet was acked, so remove it from our unacked packet list.
+ DVLOG(1) << ENDPOINT << "Got an ack for packet " << packet_number;
+ // If data is associated with the most recent transmission of this
+ // packet, then inform the caller.
+ if (it->in_flight) {
+ packets_acked_.push_back(std::make_pair(packet_number, it->bytes_sent));
+ } else if (!it->is_unackable) {
+ // Packets are marked unackable after they've been acked once.
+ largest_newly_acked_ = packet_number;
+ }
+ MarkPacketHandled(packet_number, &(*it), ack_delay_time);
+ }
+}
+
+void QuicSentPacketManager::RetransmitUnackedPackets(
+ TransmissionType retransmission_type) {
+ DCHECK(retransmission_type == ALL_UNACKED_RETRANSMISSION ||
+ retransmission_type == ALL_INITIAL_RETRANSMISSION);
+ QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
+ for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it, ++packet_number) {
+ if (!it->retransmittable_frames.empty() &&
+ (retransmission_type == ALL_UNACKED_RETRANSMISSION ||
+ it->encryption_level == ENCRYPTION_INITIAL)) {
+ MarkForRetransmission(packet_number, retransmission_type);
+ }
+ }
+}
+
+void QuicSentPacketManager::NeuterUnencryptedPackets() {
+ QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
+ for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it, ++packet_number) {
+ if (!it->retransmittable_frames.empty() &&
+ it->encryption_level == ENCRYPTION_NONE) {
+ // Once you're forward secure, no unencrypted packets will be sent, crypto
+ // or otherwise. Unencrypted packets are neutered and abandoned, to ensure
+ // they are not retransmitted or considered lost from a congestion control
+ // perspective.
+ if (delegate_ != nullptr) {
+ delegate_->OnUnencryptedPacketsNeutered(path_id_, packet_number);
+ } else {
+ pending_retransmissions_.erase(packet_number);
+ }
+ unacked_packets_.RemoveFromInFlight(packet_number);
+ unacked_packets_.RemoveRetransmittability(packet_number);
+ }
+ }
+}
+
+void QuicSentPacketManager::MarkForRetransmission(
+ QuicPacketNumber packet_number,
+ TransmissionType transmission_type) {
+ const TransmissionInfo& transmission_info =
+ unacked_packets_.GetTransmissionInfo(packet_number);
+ QUIC_BUG_IF(transmission_info.retransmittable_frames.empty());
+ // Both TLP and the new RTO leave the packets in flight and let the loss
+ // detection decide if packets are lost.
+ if (transmission_type != TLP_RETRANSMISSION &&
+ transmission_type != RTO_RETRANSMISSION) {
+ unacked_packets_.RemoveFromInFlight(packet_number);
+ }
+ if (delegate_ != nullptr) {
+ delegate_->OnRetransmissionMarked(path_id_, packet_number,
+ transmission_type);
+ } else {
+ // TODO(ianswett): Currently the RTO can fire while there are pending NACK
+ // retransmissions for the same data, which is not ideal.
+ if (base::ContainsKey(pending_retransmissions_, packet_number)) {
+ return;
+ }
+
+ pending_retransmissions_[packet_number] = transmission_type;
+ }
+}
+
+void QuicSentPacketManager::RecordOneSpuriousRetransmission(
+ const TransmissionInfo& info) {
+ stats_->bytes_spuriously_retransmitted += info.bytes_sent;
+ ++stats_->packets_spuriously_retransmitted;
+ if (debug_delegate_ != nullptr) {
+ debug_delegate_->OnSpuriousPacketRetransmission(info.transmission_type,
+ info.bytes_sent);
+ }
+}
+
+void QuicSentPacketManager::RecordSpuriousRetransmissions(
+ const TransmissionInfo& info,
+ QuicPacketNumber acked_packet_number) {
+ QuicPacketNumber retransmission = info.retransmission;
+ while (retransmission != 0) {
+ const TransmissionInfo& retransmit_info =
+ unacked_packets_.GetTransmissionInfo(retransmission);
+ retransmission = retransmit_info.retransmission;
+ RecordOneSpuriousRetransmission(retransmit_info);
+ }
+ // Only inform the loss detection of spurious retransmits it caused.
+ if (unacked_packets_.GetTransmissionInfo(info.retransmission)
+ .transmission_type == LOSS_RETRANSMISSION) {
+ loss_algorithm_->SpuriousRetransmitDetected(
+ unacked_packets_, clock_->Now(), rtt_stats_, info.retransmission);
+ }
+}
+
+bool QuicSentPacketManager::HasPendingRetransmissions() const {
+ return !pending_retransmissions_.empty();
+}
+
+PendingRetransmission QuicSentPacketManager::NextPendingRetransmission() {
+ QUIC_BUG_IF(pending_retransmissions_.empty())
+ << "Unexpected call to PendingRetransmissions() with empty pending "
+ << "retransmission list. Corrupted memory usage imminent.";
+ QuicPacketNumber packet_number = pending_retransmissions_.begin()->first;
+ TransmissionType transmission_type = pending_retransmissions_.begin()->second;
+ if (unacked_packets_.HasPendingCryptoPackets()) {
+ // Ensure crypto packets are retransmitted before other packets.
+ for (const auto& pair : pending_retransmissions_) {
+ if (HasCryptoHandshake(
+ unacked_packets_.GetTransmissionInfo(pair.first))) {
+ packet_number = pair.first;
+ transmission_type = pair.second;
+ break;
+ }
+ }
+ }
+ DCHECK(unacked_packets_.IsUnacked(packet_number)) << packet_number;
+ const TransmissionInfo& transmission_info =
+ unacked_packets_.GetTransmissionInfo(packet_number);
+ DCHECK(!transmission_info.retransmittable_frames.empty());
+
+ return PendingRetransmission(path_id_, packet_number, transmission_type,
+ transmission_info.retransmittable_frames,
+ transmission_info.has_crypto_handshake,
+ transmission_info.num_padding_bytes,
+ transmission_info.encryption_level,
+ transmission_info.packet_number_length);
+}
+
+QuicPacketNumber QuicSentPacketManager::GetNewestRetransmission(
+ QuicPacketNumber packet_number,
+ const TransmissionInfo& transmission_info) const {
+ QuicPacketNumber retransmission = transmission_info.retransmission;
+ while (retransmission != 0) {
+ packet_number = retransmission;
+ retransmission =
+ unacked_packets_.GetTransmissionInfo(retransmission).retransmission;
+ }
+ return packet_number;
+}
+
+void QuicSentPacketManager::MarkPacketNotRetransmittable(
+ QuicPacketNumber packet_number,
+ QuicTime::Delta ack_delay_time) {
+ if (!unacked_packets_.IsUnacked(packet_number)) {
+ return;
+ }
+
+ const TransmissionInfo& transmission_info =
+ unacked_packets_.GetTransmissionInfo(packet_number);
+ QuicPacketNumber newest_transmission =
+ GetNewestRetransmission(packet_number, transmission_info);
+ // We do not need to retransmit this packet anymore.
+ if (delegate_ != nullptr) {
+ delegate_->OnPacketMarkedNotRetransmittable(path_id_, newest_transmission,
+ ack_delay_time);
+ } else {
+ pending_retransmissions_.erase(newest_transmission);
+ }
+
+ unacked_packets_.NotifyAndClearListeners(newest_transmission, ack_delay_time);
+ unacked_packets_.RemoveRetransmittability(packet_number);
+}
+
+void QuicSentPacketManager::MarkPacketHandled(QuicPacketNumber packet_number,
+ TransmissionInfo* info,
+ QuicTime::Delta ack_delay_time) {
+ QuicPacketNumber newest_transmission =
+ GetNewestRetransmission(packet_number, *info);
+ // Remove the most recent packet, if it is pending retransmission.
+ if (delegate_ != nullptr) {
+ delegate_->OnPacketMarkedHandled(path_id_, newest_transmission,
+ ack_delay_time);
+ } else {
+ pending_retransmissions_.erase(newest_transmission);
+ }
+
+ // The AckListener needs to be notified about the most recent
+ // transmission, since that's the one only one it tracks.
+ if (newest_transmission == packet_number) {
+ unacked_packets_.NotifyAndClearListeners(&info->ack_listeners,
+ ack_delay_time);
+ } else {
+ unacked_packets_.NotifyAndClearListeners(newest_transmission,
+ ack_delay_time);
+ RecordSpuriousRetransmissions(*info, packet_number);
+ // Remove the most recent packet from flight if it's a crypto handshake
+ // packet, since they won't be acked now that one has been processed.
+ // Other crypto handshake packets won't be in flight, only the newest
+ // transmission of a crypto packet is in flight at once.
+ // TODO(ianswett): Instead of handling all crypto packets special,
+ // only handle nullptr encrypted packets in a special way.
+ const TransmissionInfo& newest_transmission_info =
+ unacked_packets_.GetTransmissionInfo(newest_transmission);
+ if (HasCryptoHandshake(newest_transmission_info)) {
+ unacked_packets_.RemoveFromInFlight(newest_transmission);
+ }
+ }
+
+ if (network_change_visitor_ != nullptr &&
+ info->bytes_sent > largest_mtu_acked_) {
+ largest_mtu_acked_ = info->bytes_sent;
+ network_change_visitor_->OnPathMtuIncreased(largest_mtu_acked_);
+ }
+ unacked_packets_.RemoveFromInFlight(info);
+ unacked_packets_.RemoveRetransmittability(info);
+ info->is_unackable = true;
+}
+
+bool QuicSentPacketManager::HasUnackedPackets() const {
+ return unacked_packets_.HasUnackedPackets();
+}
+
+QuicPacketNumber QuicSentPacketManager::GetLeastUnacked(QuicPathId) const {
+ return unacked_packets_.GetLeastUnacked();
+}
+
+bool QuicSentPacketManager::OnPacketSent(
+ SerializedPacket* serialized_packet,
+ QuicPathId /*original_path_id*/,
+ QuicPacketNumber original_packet_number,
+ QuicTime sent_time,
+ TransmissionType transmission_type,
+ HasRetransmittableData has_retransmittable_data) {
+ QuicPacketNumber packet_number = serialized_packet->packet_number;
+ DCHECK_LT(0u, packet_number);
+ DCHECK(!unacked_packets_.IsUnacked(packet_number));
+ QUIC_BUG_IF(serialized_packet->encrypted_length == 0)
+ << "Cannot send empty packets.";
+
+ if (delegate_ == nullptr && original_packet_number != 0) {
+ pending_retransmissions_.erase(original_packet_number);
+ }
+
+ if (pending_timer_transmission_count_ > 0) {
+ --pending_timer_transmission_count_;
+ }
+
+ bool in_flight;
+ if (using_pacing_) {
+ in_flight = pacing_sender_.OnPacketSent(
+ sent_time, unacked_packets_.bytes_in_flight(), packet_number,
+ serialized_packet->encrypted_length, has_retransmittable_data);
+ } else {
+ in_flight = send_algorithm_->OnPacketSent(
+ sent_time, unacked_packets_.bytes_in_flight(), packet_number,
+ serialized_packet->encrypted_length, has_retransmittable_data);
+ }
+
+ unacked_packets_.AddSentPacket(serialized_packet, original_packet_number,
+ transmission_type, sent_time, in_flight);
+ // Reset the retransmission timer anytime a pending packet is sent.
+ return in_flight;
+}
+
+void QuicSentPacketManager::OnRetransmissionTimeout() {
+ DCHECK(unacked_packets_.HasInFlightPackets());
+ DCHECK_EQ(0u, pending_timer_transmission_count_);
+ // Handshake retransmission, timer based loss detection, TLP, and RTO are
+ // implemented with a single alarm. The handshake alarm is set when the
+ // handshake has not completed, the loss alarm is set when the loss detection
+ // algorithm says to, and the TLP and RTO alarms are set after that.
+ // The TLP alarm is always set to run for under an RTO.
+ switch (GetRetransmissionMode()) {
+ case HANDSHAKE_MODE:
+ ++stats_->crypto_retransmit_count;
+ RetransmitCryptoPackets();
+ return;
+ case LOSS_MODE: {
+ ++stats_->loss_timeout_count;
+ QuicByteCount bytes_in_flight = unacked_packets_.bytes_in_flight();
+ InvokeLossDetection(clock_->Now());
+ MaybeInvokeCongestionEvent(false, bytes_in_flight);
+ return;
+ }
+ case TLP_MODE:
+ // If no tail loss probe can be sent, because there are no retransmittable
+ // packets, execute a conventional RTO to abandon old packets.
+ ++stats_->tlp_count;
+ ++consecutive_tlp_count_;
+ pending_timer_transmission_count_ = 1;
+ // TLPs prefer sending new data instead of retransmitting data, so
+ // give the connection a chance to write before completing the TLP.
+ return;
+ case RTO_MODE:
+ ++stats_->rto_count;
+ RetransmitRtoPackets();
+ if (network_change_visitor_ != nullptr &&
+ consecutive_rto_count_ == kMinTimeoutsBeforePathDegrading) {
+ network_change_visitor_->OnPathDegrading();
+ }
+ return;
+ }
+}
+
+void QuicSentPacketManager::RetransmitCryptoPackets() {
+ DCHECK_EQ(HANDSHAKE_MODE, GetRetransmissionMode());
+ ++consecutive_crypto_retransmission_count_;
+ bool packet_retransmitted = false;
+ QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
+ for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it, ++packet_number) {
+ // Only retransmit frames which are in flight, and therefore have been sent.
+ if (!it->in_flight || it->retransmittable_frames.empty() ||
+ !it->has_crypto_handshake) {
+ continue;
+ }
+ packet_retransmitted = true;
+ MarkForRetransmission(packet_number, HANDSHAKE_RETRANSMISSION);
+ ++pending_timer_transmission_count_;
+ }
+ DCHECK(packet_retransmitted) << "No crypto packets found to retransmit.";
+}
+
+bool QuicSentPacketManager::MaybeRetransmitTailLossProbe() {
+ if (pending_timer_transmission_count_ == 0) {
+ return false;
+ }
+ QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
+ for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it, ++packet_number) {
+ // Only retransmit frames which are in flight, and therefore have been sent.
+ if (!it->in_flight || it->retransmittable_frames.empty()) {
+ continue;
+ }
+ MarkForRetransmission(packet_number, TLP_RETRANSMISSION);
+ return true;
+ }
+ DLOG(ERROR)
+ << "No retransmittable packets, so RetransmitOldestPacket failed.";
+ return false;
+}
+
+void QuicSentPacketManager::RetransmitRtoPackets() {
+ QUIC_BUG_IF(pending_timer_transmission_count_ > 0)
+ << "Retransmissions already queued:" << pending_timer_transmission_count_;
+ // Mark two packets for retransmission.
+ QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
+ for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it, ++packet_number) {
+ if (!it->retransmittable_frames.empty() &&
+ pending_timer_transmission_count_ < kMaxRetransmissionsOnTimeout) {
+ MarkForRetransmission(packet_number, RTO_RETRANSMISSION);
+ ++pending_timer_transmission_count_;
+ }
+ // Abandon non-retransmittable data that's in flight to ensure it doesn't
+ // fill up the congestion window.
+ const bool has_retransmissions = it->retransmission != 0;
+ if (it->retransmittable_frames.empty() && it->in_flight &&
+ !has_retransmissions) {
+ // Log only for non-retransmittable data.
+ // Retransmittable data is marked as lost during loss detection, and will
+ // be logged later.
+ unacked_packets_.RemoveFromInFlight(packet_number);
+ if (debug_delegate_ != nullptr) {
+ debug_delegate_->OnPacketLoss(packet_number, RTO_RETRANSMISSION,
+ clock_->Now());
+ }
+ }
+ }
+ if (pending_timer_transmission_count_ > 0) {
+ if (consecutive_rto_count_ == 0) {
+ first_rto_transmission_ = unacked_packets_.largest_sent_packet() + 1;
+ }
+ ++consecutive_rto_count_;
+ }
+}
+
+QuicSentPacketManager::RetransmissionTimeoutMode
+QuicSentPacketManager::GetRetransmissionMode() const {
+ DCHECK(unacked_packets_.HasInFlightPackets());
+ if (!handshake_confirmed_ && unacked_packets_.HasPendingCryptoPackets()) {
+ return HANDSHAKE_MODE;
+ }
+ if (loss_algorithm_->GetLossTimeout() != QuicTime::Zero()) {
+ return LOSS_MODE;
+ }
+ if (consecutive_tlp_count_ < max_tail_loss_probes_) {
+ if (unacked_packets_.HasUnackedRetransmittableFrames()) {
+ return TLP_MODE;
+ }
+ }
+ return RTO_MODE;
+}
+
+void QuicSentPacketManager::InvokeLossDetection(QuicTime time) {
+ if (!packets_acked_.empty()) {
+ DCHECK_LE(packets_acked_.front().first, packets_acked_.back().first);
+ largest_newly_acked_ = packets_acked_.back().first;
+ }
+ loss_algorithm_->DetectLosses(unacked_packets_, time, rtt_stats_,
+ largest_newly_acked_, &packets_lost_);
+ for (const auto& pair : packets_lost_) {
+ ++stats_->packets_lost;
+ if (debug_delegate_ != nullptr) {
+ debug_delegate_->OnPacketLoss(pair.first, LOSS_RETRANSMISSION, time);
+ }
+
+ // TODO(ianswett): This could be optimized.
+ if (unacked_packets_.HasRetransmittableFrames(pair.first)) {
+ MarkForRetransmission(pair.first, LOSS_RETRANSMISSION);
+ } else {
+ // Since we will not retransmit this, we need to remove it from
+ // unacked_packets_. This is either the current transmission of
+ // a packet whose previous transmission has been acked or a packet that
+ // has been TLP retransmitted.
+ unacked_packets_.RemoveFromInFlight(pair.first);
+ }
+ }
+}
+
+bool QuicSentPacketManager::MaybeUpdateRTT(const QuicAckFrame& ack_frame,
+ QuicTime ack_receive_time) {
+ // We rely on ack_delay_time to compute an RTT estimate, so we
+ // only update rtt when the largest observed gets acked.
+ // NOTE: If ack is a truncated ack, then the largest observed is in fact
+ // unacked, and may cause an RTT sample to be taken.
+ if (!unacked_packets_.IsUnacked(ack_frame.largest_observed)) {
+ return false;
+ }
+ // We calculate the RTT based on the highest ACKed packet number, the lower
+ // packet numbers will include the ACK aggregation delay.
+ const TransmissionInfo& transmission_info =
+ unacked_packets_.GetTransmissionInfo(ack_frame.largest_observed);
+ // Ensure the packet has a valid sent time.
+ if (transmission_info.sent_time == QuicTime::Zero()) {
+ QUIC_BUG << "Acked packet has zero sent time, largest_observed:"
+ << ack_frame.largest_observed;
+ return false;
+ }
+
+ QuicTime::Delta send_delta = ack_receive_time - transmission_info.sent_time;
+ const int kMaxSendDeltaSeconds = 30;
+ if (!FLAGS_quic_allow_large_send_deltas &&
+ send_delta.ToSeconds() > kMaxSendDeltaSeconds) {
+ // send_delta can be very high if local clock is changed mid-connection.
+ LOG(WARNING) << "Excessive send delta: " << send_delta.ToSeconds()
+ << ", setting to: " << kMaxSendDeltaSeconds
+ << " largest_observed:" << ack_frame.largest_observed
+ << " ack_receive_time:" << ack_receive_time.ToDebuggingValue()
+ << " sent_time:"
+ << transmission_info.sent_time.ToDebuggingValue();
+ return false;
+ }
+ rtt_stats_.UpdateRtt(send_delta, ack_frame.ack_delay_time, ack_receive_time);
+
+ return true;
+}
+
+QuicTime::Delta QuicSentPacketManager::TimeUntilSend(QuicTime now,
+ QuicPathId* path_id) {
+ QuicTime::Delta delay = QuicTime::Delta::Infinite();
+ // The TLP logic is entirely contained within QuicSentPacketManager, so the
+ // send algorithm does not need to be consulted.
+ if (pending_timer_transmission_count_ > 0) {
+ delay = QuicTime::Delta::Zero();
+ } else if (using_pacing_) {
+ delay =
+ pacing_sender_.TimeUntilSend(now, unacked_packets_.bytes_in_flight());
+ } else {
+ delay =
+ send_algorithm_->TimeUntilSend(now, unacked_packets_.bytes_in_flight());
+ }
+ if (!delay.IsInfinite()) {
+ *path_id = path_id_;
+ }
+ return delay;
+}
+
+const QuicTime QuicSentPacketManager::GetRetransmissionTime() const {
+ // Don't set the timer if there are no packets in flight or we've already
+ // queued a tlp transmission and it hasn't been sent yet.
+ if (!unacked_packets_.HasInFlightPackets() ||
+ pending_timer_transmission_count_ > 0) {
+ return QuicTime::Zero();
+ }
+ switch (GetRetransmissionMode()) {
+ case HANDSHAKE_MODE:
+ return clock_->ApproximateNow() + GetCryptoRetransmissionDelay();
+ case LOSS_MODE:
+ return loss_algorithm_->GetLossTimeout();
+ case TLP_MODE: {
+ // TODO(ianswett): When CWND is available, it would be preferable to
+ // set the timer based on the earliest retransmittable packet.
+ // Base the updated timer on the send time of the last packet.
+ const QuicTime sent_time = unacked_packets_.GetLastPacketSentTime();
+ const QuicTime tlp_time = sent_time + GetTailLossProbeDelay();
+ // Ensure the TLP timer never gets set to a time in the past.
+ return std::max(clock_->ApproximateNow(), tlp_time);
+ }
+ case RTO_MODE: {
+ // The RTO is based on the first outstanding packet.
+ const QuicTime sent_time = unacked_packets_.GetLastPacketSentTime();
+ QuicTime rto_time = sent_time + GetRetransmissionDelay();
+ // Wait for TLP packets to be acked before an RTO fires.
+ QuicTime tlp_time =
+ unacked_packets_.GetLastPacketSentTime() + GetTailLossProbeDelay();
+ return std::max(tlp_time, rto_time);
+ }
+ }
+ DCHECK(false);
+ return QuicTime::Zero();
+}
+
+const QuicTime::Delta QuicSentPacketManager::GetCryptoRetransmissionDelay()
+ const {
+ // This is equivalent to the TailLossProbeDelay, but slightly more aggressive
+ // because crypto handshake messages don't incur a delayed ack time.
+ QuicTime::Delta srtt = rtt_stats_.smoothed_rtt();
+ int64_t delay_ms;
+ if (srtt.IsZero()) {
+ srtt = QuicTime::Delta::FromMicroseconds(rtt_stats_.initial_rtt_us());
+ }
+ if (conservative_handshake_retransmits_) {
+ delay_ms = max(kConservativeMinHandshakeTimeoutMs,
+ static_cast<int64_t>(2 * srtt.ToMilliseconds()));
+ } else {
+ delay_ms = max(kMinHandshakeTimeoutMs,
+ static_cast<int64_t>(1.5 * srtt.ToMilliseconds()));
+ }
+ return QuicTime::Delta::FromMilliseconds(
+ delay_ms << consecutive_crypto_retransmission_count_);
+}
+
+const QuicTime::Delta QuicSentPacketManager::GetTailLossProbeDelay() const {
+ QuicTime::Delta srtt = rtt_stats_.smoothed_rtt();
+ if (srtt.IsZero()) {
+ srtt = QuicTime::Delta::FromMicroseconds(rtt_stats_.initial_rtt_us());
+ }
+ if (enable_half_rtt_tail_loss_probe_ && consecutive_tlp_count_ == 0u) {
+ return QuicTime::Delta::FromMilliseconds(
+ max(kMinTailLossProbeTimeoutMs,
+ static_cast<int64_t>(0.5 * srtt.ToMilliseconds())));
+ }
+ if (!unacked_packets_.HasMultipleInFlightPackets()) {
+ return std::max(2 * srtt, 1.5 * srtt + QuicTime::Delta::FromMilliseconds(
+ kMinRetransmissionTimeMs / 2));
+ }
+ return QuicTime::Delta::FromMilliseconds(
+ max(kMinTailLossProbeTimeoutMs,
+ static_cast<int64_t>(2 * srtt.ToMilliseconds())));
+}
+
+const QuicTime::Delta QuicSentPacketManager::GetRetransmissionDelay() const {
+ QuicTime::Delta retransmission_delay = QuicTime::Delta::Zero();
+ if (rtt_stats_.smoothed_rtt().IsZero()) {
+ // We are in the initial state, use default timeout values.
+ retransmission_delay =
+ QuicTime::Delta::FromMilliseconds(kDefaultRetransmissionTimeMs);
+ } else {
+ retransmission_delay =
+ rtt_stats_.smoothed_rtt() + 4 * rtt_stats_.mean_deviation();
+ if (retransmission_delay.ToMilliseconds() < kMinRetransmissionTimeMs) {
+ retransmission_delay =
+ QuicTime::Delta::FromMilliseconds(kMinRetransmissionTimeMs);
+ }
+ }
+
+ // Calculate exponential back off.
+ retransmission_delay =
+ retransmission_delay *
+ (1 << min<size_t>(consecutive_rto_count_, kMaxRetransmissions));
+
+ if (retransmission_delay.ToMilliseconds() > kMaxRetransmissionTimeMs) {
+ return QuicTime::Delta::FromMilliseconds(kMaxRetransmissionTimeMs);
+ }
+ return retransmission_delay;
+}
+
+const RttStats* QuicSentPacketManager::GetRttStats() const {
+ return &rtt_stats_;
+}
+
+QuicBandwidth QuicSentPacketManager::BandwidthEstimate() const {
+ // TODO(ianswett): Remove BandwidthEstimate from SendAlgorithmInterface
+ // and implement the logic here.
+ return send_algorithm_->BandwidthEstimate();
+}
+
+const QuicSustainedBandwidthRecorder*
+QuicSentPacketManager::SustainedBandwidthRecorder() const {
+ return &sustained_bandwidth_recorder_;
+}
+
+QuicPacketCount QuicSentPacketManager::EstimateMaxPacketsInFlight(
+ QuicByteCount max_packet_length) const {
+ return send_algorithm_->GetCongestionWindow() / max_packet_length;
+}
+
+QuicPacketCount QuicSentPacketManager::GetCongestionWindowInTcpMss() const {
+ return send_algorithm_->GetCongestionWindow() / kDefaultTCPMSS;
+}
+
+QuicByteCount QuicSentPacketManager::GetCongestionWindowInBytes() const {
+ return send_algorithm_->GetCongestionWindow();
+}
+
+QuicPacketCount QuicSentPacketManager::GetSlowStartThresholdInTcpMss() const {
+ return send_algorithm_->GetSlowStartThreshold() / kDefaultTCPMSS;
+}
+
+std::string QuicSentPacketManager::GetDebugState() const {
+ return send_algorithm_->GetDebugState();
+}
+
+void QuicSentPacketManager::CancelRetransmissionsForStream(
+ QuicStreamId stream_id) {
+ unacked_packets_.CancelRetransmissionsForStream(stream_id);
+ if (delegate_ != nullptr) {
+ return;
+ }
+ PendingRetransmissionMap::iterator it = pending_retransmissions_.begin();
+ while (it != pending_retransmissions_.end()) {
+ if (unacked_packets_.HasRetransmittableFrames(it->first)) {
+ ++it;
+ continue;
+ }
+ it = pending_retransmissions_.erase(it);
+ }
+}
+
+void QuicSentPacketManager::SetSendAlgorithm(
+ CongestionControlType congestion_control_type) {
+ SetSendAlgorithm(SendAlgorithmInterface::Create(
+ clock_, &rtt_stats_, congestion_control_type, stats_,
+ initial_congestion_window_));
+}
+
+void QuicSentPacketManager::SetSendAlgorithm(
+ SendAlgorithmInterface* send_algorithm) {
+ send_algorithm_.reset(send_algorithm);
+ pacing_sender_.set_sender(send_algorithm);
+}
+
+void QuicSentPacketManager::OnConnectionMigration(QuicPathId,
+ PeerAddressChangeType type) {
+ if (type == PORT_CHANGE || type == IPV4_SUBNET_CHANGE) {
+ // Rtt and cwnd do not need to be reset when the peer address change is
+ // considered to be caused by NATs.
+ return;
+ }
+ consecutive_rto_count_ = 0;
+ consecutive_tlp_count_ = 0;
+ rtt_stats_.OnConnectionMigration();
+ send_algorithm_->OnConnectionMigration();
+}
+
+void QuicSentPacketManager::SetDebugDelegate(DebugDelegate* debug_delegate) {
+ debug_delegate_ = debug_delegate;
+}
+
+QuicPacketNumber QuicSentPacketManager::GetLargestObserved(QuicPathId) const {
+ return unacked_packets_.largest_observed();
+}
+
+QuicPacketNumber QuicSentPacketManager::GetLargestSentPacket(QuicPathId) const {
+ return unacked_packets_.largest_sent_packet();
+}
+
+// Remove this method when deprecating QUIC_VERSION_33.
+QuicPacketNumber QuicSentPacketManager::GetLeastPacketAwaitedByPeer(
+ QuicPathId) const {
+ return least_packet_awaited_by_peer_;
+}
+
+void QuicSentPacketManager::SetNetworkChangeVisitor(
+ NetworkChangeVisitor* visitor) {
+ DCHECK(!network_change_visitor_);
+ DCHECK(visitor);
+ network_change_visitor_ = visitor;
+}
+
+bool QuicSentPacketManager::InSlowStart() const {
+ return send_algorithm_->InSlowStart();
+}
+
+size_t QuicSentPacketManager::GetConsecutiveRtoCount() const {
+ return consecutive_rto_count_;
+}
+
+size_t QuicSentPacketManager::GetConsecutiveTlpCount() const {
+ return consecutive_tlp_count_;
+}
+
+TransmissionInfo* QuicSentPacketManager::GetMutableTransmissionInfo(
+ QuicPacketNumber packet_number) {
+ return unacked_packets_.GetMutableTransmissionInfo(packet_number);
+}
+
+void QuicSentPacketManager::RemoveObsoletePackets() {
+ unacked_packets_.RemoveObsoletePackets();
+}
+
+void QuicSentPacketManager::OnApplicationLimited() {
+ send_algorithm_->OnApplicationLimited(unacked_packets_.bytes_in_flight());
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_sent_packet_manager.h b/chromium/net/quic/core/quic_sent_packet_manager.h
new file mode 100644
index 00000000000..eacdfa5dca2
--- /dev/null
+++ b/chromium/net/quic/core/quic_sent_packet_manager.h
@@ -0,0 +1,420 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_SENT_PACKET_MANAGER_H_
+#define NET_QUIC_QUIC_SENT_PACKET_MANAGER_H_
+
+#include <stddef.h>
+
+#include <map>
+#include <memory>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "net/base/linked_hash_map.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/congestion_control/general_loss_algorithm.h"
+#include "net/quic/core/congestion_control/loss_detection_interface.h"
+#include "net/quic/core/congestion_control/pacing_sender.h"
+#include "net/quic/core/congestion_control/rtt_stats.h"
+#include "net/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_sent_packet_manager_interface.h"
+#include "net/quic/core/quic_unacked_packet_map.h"
+
+namespace net {
+
+namespace test {
+class QuicConnectionPeer;
+class QuicSentPacketManagerPeer;
+} // namespace test
+
+class QuicClock;
+class QuicConfig;
+struct QuicConnectionStats;
+
+// Class which tracks the set of packets sent on a QUIC connection and contains
+// a send algorithm to decide when to send new packets. It keeps track of any
+// retransmittable data associated with each packet. If a packet is
+// retransmitted, it will keep track of each version of a packet so that if a
+// previous transmission is acked, the data will not be retransmitted.
+class NET_EXPORT_PRIVATE QuicSentPacketManager
+ : public QuicSentPacketManagerInterface {
+ public:
+ // A delegate interface which manages pending retransmissions.
+ class MultipathDelegateInterface {
+ public:
+ virtual ~MultipathDelegateInterface() {}
+
+ // Called when unencrypted |packet_number| is requested to be neutered.
+ virtual void OnUnencryptedPacketsNeutered(
+ QuicPathId path_id,
+ QuicPacketNumber packet_number) = 0;
+ // Called when |packet_number| is requested to be retransmitted.
+ virtual void OnRetransmissionMarked(QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ TransmissionType transmission_type) = 0;
+ // Called when |packet_number| is marked as not retransmittable.
+ virtual void OnPacketMarkedNotRetransmittable(
+ QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ QuicTime::Delta delta_largest_observed) = 0;
+ // Called when any transmission of |packet_number| is handled.
+ virtual void OnPacketMarkedHandled(
+ QuicPathId path_id,
+ QuicPacketNumber packet_number,
+ QuicTime::Delta delta_largest_observed) = 0;
+ };
+
+ QuicSentPacketManager(Perspective perspective,
+ QuicPathId path_id,
+ const QuicClock* clock,
+ QuicConnectionStats* stats,
+ CongestionControlType congestion_control_type,
+ LossDetectionType loss_type,
+ MultipathDelegateInterface* delegate);
+ ~QuicSentPacketManager() override;
+
+ // Start implementation of QuicSentPacketManagerInterface.
+ void SetFromConfig(const QuicConfig& config) override;
+
+ // Pass the CachedNetworkParameters to the send algorithm.
+ void ResumeConnectionState(
+ const CachedNetworkParameters& cached_network_params,
+ bool max_bandwidth_resumption) override;
+
+ void SetNumOpenStreams(size_t num_streams) override;
+
+ void SetMaxPacingRate(QuicBandwidth max_pacing_rate) override;
+
+ void SetHandshakeConfirmed() override;
+
+ // Processes the incoming ack.
+ void OnIncomingAck(const QuicAckFrame& ack_frame,
+ QuicTime ack_receive_time) override;
+
+ // Requests retransmission of all unacked packets of |retransmission_type|.
+ // The behavior of this method depends on the value of |retransmission_type|:
+ // ALL_UNACKED_RETRANSMISSION - All unacked packets will be retransmitted.
+ // This can happen, for example, after a version negotiation packet has been
+ // received and all packets needs to be retransmitted with the new version.
+ // ALL_INITIAL_RETRANSMISSION - Only initially encrypted packets will be
+ // retransmitted. This can happen, for example, when a CHLO has been rejected
+ // and the previously encrypted data needs to be encrypted with a new key.
+ void RetransmitUnackedPackets(TransmissionType retransmission_type) override;
+
+ // Retransmits the oldest pending packet there is still a tail loss probe
+ // pending. Invoked after OnRetransmissionTimeout.
+ bool MaybeRetransmitTailLossProbe() override;
+
+ // Removes the retransmittable frames from all unencrypted packets to ensure
+ // they don't get retransmitted.
+ void NeuterUnencryptedPackets() override;
+
+ // Returns true if there are pending retransmissions.
+ // Not const because retransmissions may be cancelled before returning.
+ bool HasPendingRetransmissions() const override;
+
+ // Retrieves the next pending retransmission. You must ensure that
+ // there are pending retransmissions prior to calling this function.
+ PendingRetransmission NextPendingRetransmission() override;
+
+ bool HasUnackedPackets() const override;
+
+ // Returns the smallest packet number of a serialized packet which has not
+ // been acked by the peer.
+ QuicPacketNumber GetLeastUnacked(QuicPathId) const override;
+
+ // Called when we have sent bytes to the peer. This informs the manager both
+ // the number of bytes sent and if they were retransmitted. Returns true if
+ // the sender should reset the retransmission timer.
+ bool OnPacketSent(SerializedPacket* serialized_packet,
+ QuicPathId /*original_path_id*/,
+ QuicPacketNumber original_packet_number,
+ QuicTime sent_time,
+ TransmissionType transmission_type,
+ HasRetransmittableData has_retransmittable_data) override;
+
+ // Called when the retransmission timer expires.
+ void OnRetransmissionTimeout() override;
+
+ // Calculate the time until we can send the next packet to the wire.
+ // Note 1: When kUnknownWaitTime is returned, there is no need to poll
+ // TimeUntilSend again until we receive an OnIncomingAckFrame event.
+ // Note 2: Send algorithms may or may not use |retransmit| in their
+ // calculations.
+ QuicTime::Delta TimeUntilSend(QuicTime now, QuicPathId* path_id) override;
+
+ // Returns the current delay for the retransmission timer, which may send
+ // either a tail loss probe or do a full RTO. Returns QuicTime::Zero() if
+ // there are no retransmittable packets.
+ const QuicTime GetRetransmissionTime() const override;
+
+ const RttStats* GetRttStats() const override;
+
+ // Returns the estimated bandwidth calculated by the congestion algorithm.
+ QuicBandwidth BandwidthEstimate() const override;
+
+ const QuicSustainedBandwidthRecorder* SustainedBandwidthRecorder()
+ const override;
+
+ // Returns the size of the current congestion window in number of
+ // kDefaultTCPMSS-sized segments. Note, this is not the *available* window.
+ // Some send algorithms may not use a congestion window and will return 0.
+ QuicPacketCount GetCongestionWindowInTcpMss() const override;
+
+ // Returns the number of packets of length |max_packet_length| which fit in
+ // the current congestion window. More packets may end up in flight if the
+ // congestion window has been recently reduced, of if non-full packets are
+ // sent.
+ QuicPacketCount EstimateMaxPacketsInFlight(
+ QuicByteCount max_packet_length) const override;
+
+ // Returns the size of the current congestion window size in bytes.
+ QuicByteCount GetCongestionWindowInBytes() const override;
+
+ // Returns the size of the slow start congestion window in nume of 1460 byte
+ // TCP segments, aka ssthresh. Some send algorithms do not define a slow
+ // start threshold and will return 0.
+ QuicPacketCount GetSlowStartThresholdInTcpMss() const override;
+
+ // Returns debugging information about the state of the congestion controller.
+ std::string GetDebugState() const override;
+
+ // No longer retransmit data for |stream_id|.
+ void CancelRetransmissionsForStream(QuicStreamId stream_id) override;
+
+ // Called when peer address changes and the connection migrates.
+ void OnConnectionMigration(QuicPathId, PeerAddressChangeType type) override;
+
+ void SetDebugDelegate(DebugDelegate* debug_delegate) override;
+
+ QuicPacketNumber GetLargestObserved(QuicPathId) const override;
+
+ QuicPacketNumber GetLargestSentPacket(QuicPathId) const override;
+
+ QuicPacketNumber GetLeastPacketAwaitedByPeer(QuicPathId) const override;
+
+ void SetNetworkChangeVisitor(NetworkChangeVisitor* visitor) override;
+
+ bool InSlowStart() const override;
+
+ size_t GetConsecutiveRtoCount() const override;
+
+ size_t GetConsecutiveTlpCount() const override;
+
+ void OnApplicationLimited() override;
+
+ private:
+ friend class test::QuicConnectionPeer;
+ friend class test::QuicSentPacketManagerPeer;
+
+ // The retransmission timer is a single timer which switches modes depending
+ // upon connection state.
+ enum RetransmissionTimeoutMode {
+ // A conventional TCP style RTO.
+ RTO_MODE,
+ // A tail loss probe. By default, QUIC sends up to two before RTOing.
+ TLP_MODE,
+ // Retransmission of handshake packets prior to handshake completion.
+ HANDSHAKE_MODE,
+ // Re-invoke the loss detection when a packet is not acked before the
+ // loss detection algorithm expects.
+ LOSS_MODE,
+ };
+
+ typedef linked_hash_map<QuicPacketNumber, TransmissionType>
+ PendingRetransmissionMap;
+
+ // Updates the least_packet_awaited_by_peer.
+ void UpdatePacketInformationReceivedByPeer(const QuicAckFrame& ack_frame);
+
+ // Process the incoming ack looking for newly ack'd data packets.
+ void HandleAckForSentPackets(const QuicAckFrame& ack_frame);
+
+ // Returns the current retransmission mode.
+ RetransmissionTimeoutMode GetRetransmissionMode() const;
+
+ // Retransmits all crypto stream packets.
+ void RetransmitCryptoPackets();
+
+ // Retransmits two packets for an RTO and removes any non-retransmittable
+ // packets from flight.
+ void RetransmitRtoPackets();
+
+ // Returns the timer for retransmitting crypto handshake packets.
+ const QuicTime::Delta GetCryptoRetransmissionDelay() const;
+
+ // Returns the timer for a new tail loss probe.
+ const QuicTime::Delta GetTailLossProbeDelay() const;
+
+ // Returns the retransmission timeout, after which a full RTO occurs.
+ const QuicTime::Delta GetRetransmissionDelay() const;
+
+ // Returns the newest transmission associated with a packet.
+ QuicPacketNumber GetNewestRetransmission(
+ QuicPacketNumber packet_number,
+ const TransmissionInfo& transmission_info) const;
+
+ // Update the RTT if the ack is for the largest acked packet number.
+ // Returns true if the rtt was updated.
+ bool MaybeUpdateRTT(const QuicAckFrame& ack_frame, QuicTime ack_receive_time);
+
+ // Invokes the loss detection algorithm and loses and retransmits packets if
+ // necessary.
+ void InvokeLossDetection(QuicTime time);
+
+ // Invokes OnCongestionEvent if |rtt_updated| is true, there are pending acks,
+ // or pending losses. Clears pending acks and pending losses afterwards.
+ // |bytes_in_flight| is the number of bytes in flight before the losses or
+ // acks.
+ void MaybeInvokeCongestionEvent(bool rtt_updated,
+ QuicByteCount bytes_in_flight);
+
+ // Called when frames of |packet_number| has been received but the packet
+ // itself has not been received by the peer. Currently, this method is not
+ // used.
+ // TODO(fayang): Update the comment when multipath sent packet manager is
+ // landed.
+ // The packet needs no longer to be retransmitted, but the packet remains
+ // pending if it is and the congestion control does not consider the packet
+ // acked.
+ void MarkPacketNotRetransmittable(QuicPacketNumber packet_number,
+ QuicTime::Delta ack_delay_time);
+
+ // Removes the retransmittability and in flight properties from the packet at
+ // |info| due to receipt by the peer.
+ void MarkPacketHandled(QuicPacketNumber packet_number,
+ TransmissionInfo* info,
+ QuicTime::Delta ack_delay_time);
+
+ // Request that |packet_number| be retransmitted after the other pending
+ // retransmissions. Does not add it to the retransmissions if it's already
+ // a pending retransmission.
+ void MarkForRetransmission(QuicPacketNumber packet_number,
+ TransmissionType transmission_type);
+
+ // Notify observers that packet with TransmissionInfo |info| is a spurious
+ // retransmission. It is caller's responsibility to guarantee the packet with
+ // TransmissionInfo |info| is a spurious retransmission before calling this
+ // function.
+ void RecordOneSpuriousRetransmission(const TransmissionInfo& info);
+
+ // Notify observers about spurious retransmits of packet with TransmissionInfo
+ // |info|.
+ void RecordSpuriousRetransmissions(const TransmissionInfo& info,
+ QuicPacketNumber acked_packet_number);
+
+ // Returns mutable TransmissionInfo associated with |packet_number|, which
+ // must be unacked.
+ TransmissionInfo* GetMutableTransmissionInfo(QuicPacketNumber packet_number);
+
+ // Remove any packets no longer needed for retransmission, congestion, or
+ // RTT measurement purposes.
+ void RemoveObsoletePackets();
+
+ // Sets the send algorithm to the given congestion control type and points the
+ // pacing sender at |send_algorithm_|. Can be called any number of times.
+ void SetSendAlgorithm(CongestionControlType congestion_control_type);
+
+ // Sets the send algorithm to |send_algorithm| and points the pacing sender at
+ // |send_algorithm_|. Takes ownership of |send_algorithm|. Can be called any
+ // number of times.
+ void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm);
+
+ // Newly serialized retransmittable packets are added to this map, which
+ // contains owning pointers to any contained frames. If a packet is
+ // retransmitted, this map will contain entries for both the old and the new
+ // packet. The old packet's retransmittable frames entry will be nullptr,
+ // while the new packet's entry will contain the frames to retransmit.
+ // If the old packet is acked before the new packet, then the old entry will
+ // be removed from the map and the new entry's retransmittable frames will be
+ // set to nullptr.
+ QuicUnackedPacketMap unacked_packets_;
+
+ // Pending retransmissions which have not been packetized and sent yet.
+ PendingRetransmissionMap pending_retransmissions_;
+
+ // Tracks if the connection was created by the server or the client.
+ Perspective perspective_;
+
+ QuicPathId path_id_;
+
+ const QuicClock* clock_;
+ QuicConnectionStats* stats_;
+
+ // Pending retransmissions are managed by delegate_ if it is not null.
+ MultipathDelegateInterface* delegate_; // Not owned.
+
+ DebugDelegate* debug_delegate_;
+ NetworkChangeVisitor* network_change_visitor_;
+ const QuicPacketCount initial_congestion_window_;
+ RttStats rtt_stats_;
+ std::unique_ptr<SendAlgorithmInterface> send_algorithm_;
+ // Not owned. Always points to |general_loss_algorithm_| outside of tests.
+ LossDetectionInterface* loss_algorithm_;
+ GeneralLossAlgorithm general_loss_algorithm_;
+ bool n_connection_simulation_;
+
+ // Receiver side buffer in bytes.
+ QuicByteCount receive_buffer_bytes_;
+
+ // Least packet number which the peer is still waiting for.
+ QuicPacketNumber least_packet_awaited_by_peer_;
+
+ // Tracks the first RTO packet. If any packet before that packet gets acked,
+ // it indicates the RTO was spurious and should be reversed(F-RTO).
+ QuicPacketNumber first_rto_transmission_;
+ // Number of times the RTO timer has fired in a row without receiving an ack.
+ size_t consecutive_rto_count_;
+ // Number of times the tail loss probe has been sent.
+ size_t consecutive_tlp_count_;
+ // Number of times the crypto handshake has been retransmitted.
+ size_t consecutive_crypto_retransmission_count_;
+ // Number of pending transmissions of TLP, RTO, or crypto packets.
+ size_t pending_timer_transmission_count_;
+ // Maximum number of tail loss probes to send before firing an RTO.
+ size_t max_tail_loss_probes_;
+ // If true, send the TLP at 0.5 RTT.
+ bool enable_half_rtt_tail_loss_probe_;
+ bool using_pacing_;
+ // If true, use the new RTO with loss based CWND reduction instead of the send
+ // algorithms's OnRetransmissionTimeout to reduce the congestion window.
+ bool use_new_rto_;
+ // If true, cancel pending retransmissions if they're larger than
+ // largest_newly_acked.
+ bool undo_pending_retransmits_;
+ // If true, use a more conservative handshake retransmission policy.
+ bool conservative_handshake_retransmits_;
+
+ // Vectors packets acked and lost as a result of the last congestion event.
+ SendAlgorithmInterface::CongestionVector packets_acked_;
+ SendAlgorithmInterface::CongestionVector packets_lost_;
+ // Largest newly acknowledged packet.
+ QuicPacketNumber largest_newly_acked_;
+ // Largest packet in bytes ever acknowledged.
+ QuicPacketLength largest_mtu_acked_;
+
+ // Replaces certain calls to |send_algorithm_| when |using_pacing_| is true.
+ // Calls into |send_algorithm_| for the underlying congestion control.
+ PacingSender pacing_sender_;
+
+ // Set to true after the crypto handshake has successfully completed. After
+ // this is true we no longer use HANDSHAKE_MODE, and further frames sent on
+ // the crypto stream (i.e. SCUP messages) are treated like normal
+ // retransmittable frames.
+ bool handshake_confirmed_;
+
+ // Records bandwidth from server to client in normal operation, over periods
+ // of time with no loss events.
+ QuicSustainedBandwidthRecorder sustained_bandwidth_recorder_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicSentPacketManager);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_SENT_PACKET_MANAGER_H_
diff --git a/chromium/net/quic/core/quic_sent_packet_manager_interface.h b/chromium/net/quic/core/quic_sent_packet_manager_interface.h
new file mode 100644
index 00000000000..498f5cdc026
--- /dev/null
+++ b/chromium/net/quic/core/quic_sent_packet_manager_interface.h
@@ -0,0 +1,195 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_SENT_PACKET_MANAGER_INTERFACE_H_
+#define NET_QUIC_QUIC_SENT_PACKET_MANAGER_INTERFACE_H_
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_sustained_bandwidth_recorder.h"
+
+namespace net {
+
+class QuicConfig;
+class RttStats;
+
+class NET_EXPORT_PRIVATE QuicSentPacketManagerInterface {
+ public:
+ // Interface which gets callbacks from the QuicSentPacketManager at
+ // interesting points. Implementations must not mutate the state of
+ // the packet manager or connection as a result of these callbacks.
+ class NET_EXPORT_PRIVATE DebugDelegate {
+ public:
+ virtual ~DebugDelegate() {}
+
+ // Called when a spurious retransmission is detected.
+ virtual void OnSpuriousPacketRetransmission(
+ TransmissionType transmission_type,
+ QuicByteCount byte_size) {}
+
+ virtual void OnIncomingAck(const QuicAckFrame& ack_frame,
+ QuicTime ack_receive_time,
+ QuicPacketNumber largest_observed,
+ bool rtt_updated,
+ QuicPacketNumber least_unacked_sent_packet) {}
+
+ virtual void OnPacketLoss(QuicPacketNumber lost_packet_number,
+ TransmissionType transmission_type,
+ QuicTime detection_time) {}
+ };
+
+ // Interface which gets callbacks from the QuicSentPacketManager when
+ // network-related state changes. Implementations must not mutate the
+ // state of the packet manager as a result of these callbacks.
+ class NET_EXPORT_PRIVATE NetworkChangeVisitor {
+ public:
+ virtual ~NetworkChangeVisitor() {}
+
+ // Called when congestion window or RTT may have changed.
+ virtual void OnCongestionChange() = 0;
+
+ // Called with the path may be degrading. Note that the path may only be
+ // temporarily degrading.
+ // TODO(jri): With multipath, this method should probably have a path_id
+ // parameter, and should maybe result in the path being marked as inactive.
+ virtual void OnPathDegrading() = 0;
+
+ // Called when the Path MTU may have increased.
+ virtual void OnPathMtuIncreased(QuicPacketLength packet_size) = 0;
+ };
+
+ virtual ~QuicSentPacketManagerInterface() {}
+
+ virtual void SetFromConfig(const QuicConfig& config) = 0;
+
+ // Resumes connection state on the default path.
+ virtual void ResumeConnectionState(
+ const CachedNetworkParameters& cached_network_params,
+ bool max_bandwidth_resumption) = 0;
+
+ // Sets number of active streams of all paths.
+ virtual void SetNumOpenStreams(size_t num_streams) = 0;
+
+ // Sets max pacing rate of the default path.
+ virtual void SetMaxPacingRate(QuicBandwidth max_pacing_rate) = 0;
+
+ // Indicates the handshake has completed, so no handshake packets need to be
+ // retransmitted.
+ virtual void SetHandshakeConfirmed() = 0;
+
+ virtual void OnIncomingAck(const QuicAckFrame& ack_frame,
+ QuicTime ack_receive_time) = 0;
+
+ // Requests retransmission of all unacked packets of |retransmission_type| on
+ // the default path.
+ virtual void RetransmitUnackedPackets(
+ TransmissionType retransmission_type) = 0;
+
+ // Retransmits the oldest pending packet on the path (on which retransmission
+ // alarm fires) if there is still a tail loss probe pending. Invoked after
+ // OnRetransmissionTimeout.
+ virtual bool MaybeRetransmitTailLossProbe() = 0;
+
+ // Removes the retransmittable frames from all unencrypted packets on the
+ // default path to ensure they don't get retransmitted.
+ virtual void NeuterUnencryptedPackets() = 0;
+
+ virtual bool HasPendingRetransmissions() const = 0;
+
+ virtual PendingRetransmission NextPendingRetransmission() = 0;
+
+ // Returns true if the default path has unacked packets.
+ virtual bool HasUnackedPackets() const = 0;
+
+ virtual QuicPacketNumber GetLeastUnacked(QuicPathId path_id) const = 0;
+
+ virtual bool OnPacketSent(
+ SerializedPacket* serialized_packet,
+ QuicPathId original_path_id,
+ QuicPacketNumber original_packet_number,
+ QuicTime sent_time,
+ TransmissionType transmission_type,
+ HasRetransmittableData has_retransmittable_data) = 0;
+
+ virtual void OnRetransmissionTimeout() = 0;
+
+ // Returns the earliest time we can send the next packet. Sets |path_id| to be
+ // the path on which the next packet will be sent.
+ virtual QuicTime::Delta TimeUntilSend(QuicTime now, QuicPathId* path_id) = 0;
+
+ // Returns the earliest retransmission time of all paths.
+ // TODO(fayang): This method should not be const becasue the return value
+ // depends upon the time it is invoked.
+ virtual const QuicTime GetRetransmissionTime() const = 0;
+
+ // Returns the rtt stats of the default path.
+ virtual const RttStats* GetRttStats() const = 0;
+
+ // Returns the estimated bandwidth on default path calculated by the
+ // congestion algorithm.
+ virtual QuicBandwidth BandwidthEstimate() const = 0;
+
+ // Returns the sustained bandwidth recorder on the default path.
+ virtual const QuicSustainedBandwidthRecorder* SustainedBandwidthRecorder()
+ const = 0;
+
+ // Returns the size of the current congestion window on default path in number
+ // of kDefaultTCPMSS-sized segments.
+ virtual QuicPacketCount GetCongestionWindowInTcpMss() const = 0;
+
+ // Determines the number of packets of length |max_packet_length| which fit in
+ // the congestion windows for all paths, and returns the max number of packets
+ // across all paths.
+ virtual QuicPacketCount EstimateMaxPacketsInFlight(
+ QuicByteCount max_packet_length) const = 0;
+
+ // Returns the size of the current congestion window size on the default path
+ // in bytes.
+ virtual QuicByteCount GetCongestionWindowInBytes() const = 0;
+
+ // Returns the size of the slow start congestion window in number of 1460 byte
+ // TCP segments on the default path.
+ virtual QuicPacketCount GetSlowStartThresholdInTcpMss() const = 0;
+
+ // Returns debugging information about the current state of the
+ // congestion controller.
+ virtual std::string GetDebugState() const = 0;
+
+ // No longer retransmit data for |stream_id| on all paths.
+ virtual void CancelRetransmissionsForStream(QuicStreamId stream_id) = 0;
+
+ // Called when peer address changes and the connection migrates on |path_id|.
+ // TODO(fayang): Name of this method is confusing in multipath world because
+ // this migration is path level. Need to rename this as OnPeerMigration.
+ virtual void OnConnectionMigration(QuicPathId path_id,
+ PeerAddressChangeType type) = 0;
+
+ virtual void SetDebugDelegate(DebugDelegate* debug_delegate) = 0;
+
+ virtual QuicPacketNumber GetLargestObserved(QuicPathId path_id) const = 0;
+
+ virtual QuicPacketNumber GetLargestSentPacket(QuicPathId path_id) const = 0;
+
+ virtual QuicPacketNumber GetLeastPacketAwaitedByPeer(
+ QuicPathId path_id) const = 0;
+
+ virtual void SetNetworkChangeVisitor(NetworkChangeVisitor* visitor) = 0;
+
+ // Returns true if the default path is in slow start.
+ virtual bool InSlowStart() const = 0;
+
+ // These two methods return the consecutive RTO or TLP count of the default
+ // path.
+ virtual size_t GetConsecutiveRtoCount() const = 0;
+ virtual size_t GetConsecutiveTlpCount() const = 0;
+
+ // Signals to the congestion controller that the connection has no outstanding
+ // data to send.
+ virtual void OnApplicationLimited() = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_SENT_PACKET_MANAGER_INTERFACE_H_
diff --git a/chromium/net/quic/core/quic_sent_packet_manager_test.cc b/chromium/net/quic/core/quic_sent_packet_manager_test.cc
new file mode 100644
index 00000000000..f08dfa4df21
--- /dev/null
+++ b/chromium/net/quic/core/quic_sent_packet_manager_test.cc
@@ -0,0 +1,1744 @@
+// Copyright 2013 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/quic_sent_packet_manager.h"
+
+#include <memory>
+#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/test_tools/quic_config_peer.h"
+#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::vector;
+using testing::AnyNumber;
+using testing::ElementsAre;
+using testing::IsEmpty;
+using testing::Not;
+using testing::Pair;
+using testing::Pointwise;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::StrictMock;
+using testing::_;
+
+namespace net {
+namespace test {
+namespace {
+
+// Default packet length.
+const uint32_t kDefaultLength = 1000;
+
+// Stream ID for data sent in CreatePacket().
+const QuicStreamId kStreamId = 7;
+
+// Minimum number of consecutive RTOs before path is considered to be degrading.
+const size_t kMinTimeoutsBeforePathDegrading = 2;
+
+// Matcher to check the key of the key-value pair it receives as first argument
+// equals its second argument.
+MATCHER(KeyEq, "") {
+ return std::tr1::get<0>(arg).first == std::tr1::get<1>(arg);
+}
+
+class MockDebugDelegate : public QuicSentPacketManagerInterface::DebugDelegate {
+ public:
+ MOCK_METHOD2(OnSpuriousPacketRetransmission,
+ void(TransmissionType transmission_type,
+ QuicByteCount byte_size));
+ MOCK_METHOD3(OnPacketLoss,
+ void(QuicPacketNumber lost_packet_number,
+ TransmissionType transmission_type,
+ QuicTime detection_time));
+};
+
+// Run tests with different ack frame packets set mode.
+struct TestParams {
+ explicit TestParams(bool missing) : missing(missing) {}
+
+ friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
+ os << "{ ack frame packets set mode: " << p.missing << " }";
+ return os;
+ }
+
+ bool missing;
+};
+
+vector<TestParams> GetTestParams() {
+ vector<TestParams> params;
+ for (bool missing : {true, false}) {
+ params.push_back(TestParams(missing));
+ }
+ return params;
+}
+
+class QuicSentPacketManagerTest : public ::testing::TestWithParam<TestParams> {
+ protected:
+ QuicSentPacketManagerTest()
+ : manager_(Perspective::IS_SERVER,
+ kDefaultPathId,
+ &clock_,
+ &stats_,
+ kCubic,
+ kNack,
+ /*delegate=*/nullptr),
+ send_algorithm_(new StrictMock<MockSendAlgorithm>),
+ network_change_visitor_(new StrictMock<MockNetworkChangeVisitor>) {
+ QuicSentPacketManagerPeer::SetSendAlgorithm(&manager_, send_algorithm_);
+ // Disable tail loss probes for most tests.
+ QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 0);
+ // Advance the time 1s so the send times are never QuicTime::Zero.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000));
+ manager_.SetNetworkChangeVisitor(network_change_visitor_.get());
+
+ EXPECT_CALL(*send_algorithm_, HasReliableBandwidthEstimate())
+ .Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, BandwidthEstimate())
+ .Times(AnyNumber())
+ .WillRepeatedly(Return(QuicBandwidth::Zero()));
+ EXPECT_CALL(*send_algorithm_, InSlowStart()).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, InRecovery()).Times(AnyNumber());
+ EXPECT_CALL(*network_change_visitor_, OnPathMtuIncreased(1000))
+ .Times(AnyNumber());
+ }
+
+ ~QuicSentPacketManagerTest() override { base::STLDeleteElements(&packets_); }
+
+ QuicByteCount BytesInFlight() {
+ return QuicSentPacketManagerPeer::GetBytesInFlight(&manager_);
+ }
+ void VerifyUnackedPackets(QuicPacketNumber* packets, size_t num_packets) {
+ if (num_packets == 0) {
+ EXPECT_FALSE(manager_.HasUnackedPackets());
+ EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetNumRetransmittablePackets(
+ &manager_));
+ return;
+ }
+
+ EXPECT_TRUE(manager_.HasUnackedPackets());
+ EXPECT_EQ(packets[0], manager_.GetLeastUnacked(kDefaultPathId));
+ for (size_t i = 0; i < num_packets; ++i) {
+ EXPECT_TRUE(QuicSentPacketManagerPeer::IsUnacked(&manager_, packets[i]))
+ << packets[i];
+ }
+ }
+
+ void VerifyRetransmittablePackets(QuicPacketNumber* packets,
+ size_t num_packets) {
+ EXPECT_EQ(
+ num_packets,
+ QuicSentPacketManagerPeer::GetNumRetransmittablePackets(&manager_));
+ for (size_t i = 0; i < num_packets; ++i) {
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasRetransmittableFrames(
+ &manager_, packets[i]))
+ << " packets[" << i << "]:" << packets[i];
+ }
+ }
+
+ void ExpectAck(QuicPacketNumber largest_observed) {
+ EXPECT_CALL(
+ *send_algorithm_,
+ OnCongestionEvent(true, _, ElementsAre(Pair(largest_observed, _)),
+ IsEmpty()));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ }
+
+ void ExpectUpdatedRtt(QuicPacketNumber largest_observed) {
+ EXPECT_CALL(*send_algorithm_,
+ OnCongestionEvent(true, _, IsEmpty(), IsEmpty()));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ }
+
+ void ExpectAckAndLoss(bool rtt_updated,
+ QuicPacketNumber largest_observed,
+ QuicPacketNumber lost_packet) {
+ EXPECT_CALL(*send_algorithm_,
+ OnCongestionEvent(rtt_updated, _,
+ ElementsAre(Pair(largest_observed, _)),
+ ElementsAre(Pair(lost_packet, _))));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ }
+
+ // |packets_acked| and |packets_lost| should be in packet number order.
+ void ExpectAcksAndLosses(bool rtt_updated,
+ QuicPacketNumber* packets_acked,
+ size_t num_packets_acked,
+ QuicPacketNumber* packets_lost,
+ size_t num_packets_lost) {
+ vector<QuicPacketNumber> ack_vector;
+ for (size_t i = 0; i < num_packets_acked; ++i) {
+ ack_vector.push_back(packets_acked[i]);
+ }
+ vector<QuicPacketNumber> lost_vector;
+ for (size_t i = 0; i < num_packets_lost; ++i) {
+ lost_vector.push_back(packets_lost[i]);
+ }
+ EXPECT_CALL(
+ *send_algorithm_,
+ OnCongestionEvent(rtt_updated, _, Pointwise(KeyEq(), ack_vector),
+ Pointwise(KeyEq(), lost_vector)));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange())
+ .Times(AnyNumber());
+ }
+
+ void RetransmitAndSendPacket(QuicPacketNumber old_packet_number,
+ QuicPacketNumber new_packet_number) {
+ RetransmitAndSendPacket(old_packet_number, new_packet_number,
+ TLP_RETRANSMISSION);
+ }
+
+ void RetransmitAndSendPacket(QuicPacketNumber old_packet_number,
+ QuicPacketNumber new_packet_number,
+ TransmissionType transmission_type) {
+ QuicSentPacketManagerPeer::MarkForRetransmission(
+ &manager_, kDefaultPathId, old_packet_number, transmission_type);
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ PendingRetransmission next_retransmission =
+ manager_.NextPendingRetransmission();
+ EXPECT_EQ(old_packet_number, next_retransmission.packet_number);
+ EXPECT_EQ(transmission_type, next_retransmission.transmission_type);
+
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, BytesInFlight(), new_packet_number,
+ kDefaultLength, HAS_RETRANSMITTABLE_DATA))
+ .WillOnce(Return(true));
+ SerializedPacket packet(CreatePacket(new_packet_number, false));
+ manager_.OnPacketSent(&packet, packet.path_id, old_packet_number,
+ clock_.Now(), transmission_type,
+ HAS_RETRANSMITTABLE_DATA);
+ EXPECT_TRUE(QuicSentPacketManagerPeer::IsRetransmission(
+ &manager_, packet.path_id, new_packet_number));
+ }
+
+ SerializedPacket CreateDataPacket(QuicPacketNumber packet_number) {
+ return CreatePacket(packet_number, true);
+ }
+
+ SerializedPacket CreatePacket(QuicPacketNumber packet_number,
+ bool retransmittable) {
+ SerializedPacket packet(kDefaultPathId, packet_number,
+ PACKET_6BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+ 0u, false, false);
+ if (retransmittable) {
+ packet.retransmittable_frames.push_back(
+ QuicFrame(new QuicStreamFrame(kStreamId, false, 0, StringPiece())));
+ }
+ return packet;
+ }
+
+ void SendDataPacket(QuicPacketNumber packet_number) {
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, BytesInFlight(), packet_number, _, _))
+ .Times(1)
+ .WillOnce(Return(true));
+ SerializedPacket packet(CreateDataPacket(packet_number));
+ manager_.OnPacketSent(&packet, kInvalidPathId, 0, clock_.Now(),
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+ }
+
+ void SendCryptoPacket(QuicPacketNumber packet_number) {
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, BytesInFlight(), packet_number, kDefaultLength,
+ HAS_RETRANSMITTABLE_DATA))
+ .Times(1)
+ .WillOnce(Return(true));
+ SerializedPacket packet(CreateDataPacket(packet_number));
+ packet.retransmittable_frames.push_back(
+ QuicFrame(new QuicStreamFrame(1, false, 0, StringPiece())));
+ packet.has_crypto_handshake = IS_HANDSHAKE;
+ manager_.OnPacketSent(&packet, kInvalidPathId, 0, clock_.Now(),
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+ }
+
+ void SendAckPacket(QuicPacketNumber packet_number) {
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, BytesInFlight(), packet_number, kDefaultLength,
+ NO_RETRANSMITTABLE_DATA))
+ .Times(1)
+ .WillOnce(Return(false));
+ SerializedPacket packet(CreatePacket(packet_number, false));
+ manager_.OnPacketSent(&packet, kInvalidPathId, 0, clock_.Now(),
+ NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA);
+ }
+
+ // Based on QuicConnection's WritePendingRetransmissions.
+ void RetransmitNextPacket(QuicPacketNumber retransmission_packet_number) {
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ EXPECT_CALL(*send_algorithm_,
+ OnPacketSent(_, _, retransmission_packet_number, kDefaultLength,
+ HAS_RETRANSMITTABLE_DATA))
+ .Times(1)
+ .WillOnce(Return(true));
+ const PendingRetransmission pending = manager_.NextPendingRetransmission();
+ SerializedPacket packet(CreatePacket(retransmission_packet_number, false));
+ manager_.OnPacketSent(&packet, pending.path_id, pending.packet_number,
+ clock_.Now(), pending.transmission_type,
+ HAS_RETRANSMITTABLE_DATA);
+ }
+
+ // Initialize a frame acknowledging all packets up to largest_observed.
+ const QuicAckFrame InitAckFrame(QuicPacketNumber largest_observed) {
+ QuicAckFrame frame(MakeAckFrame(largest_observed));
+ frame.missing = GetParam().missing;
+ if (!GetParam().missing) {
+ if (largest_observed > 0) {
+ frame.packets.Add(1, largest_observed + 1);
+ }
+ }
+ return frame;
+ }
+
+ // Explicitly nack packet [lower, higher).
+ void NackPackets(QuicPacketNumber lower,
+ QuicPacketNumber higher,
+ QuicAckFrame* frame) {
+ if (frame->missing) {
+ frame->packets.Add(lower, higher);
+ } else {
+ frame->packets.Remove(lower, higher);
+ }
+ }
+
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+ QuicSentPacketManager manager_;
+ vector<QuicEncryptedPacket*> packets_;
+ MockClock clock_;
+ QuicConnectionStats stats_;
+ MockSendAlgorithm* send_algorithm_;
+ std::unique_ptr<MockNetworkChangeVisitor> network_change_visitor_;
+};
+
+INSTANTIATE_TEST_CASE_P(QuicSentPacketManagerTest,
+ QuicSentPacketManagerTest,
+ ::testing::ValuesIn(GetTestParams()));
+
+TEST_P(QuicSentPacketManagerTest, IsUnacked) {
+ VerifyUnackedPackets(nullptr, 0);
+ SendDataPacket(1);
+
+ QuicPacketNumber unacked[] = {1};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ QuicPacketNumber retransmittable[] = {1};
+ VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
+}
+
+TEST_P(QuicSentPacketManagerTest, IsUnAckedRetransmit) {
+ SendDataPacket(1);
+ RetransmitAndSendPacket(1, 2);
+
+ EXPECT_TRUE(QuicSentPacketManagerPeer::IsRetransmission(&manager_,
+ kDefaultPathId, 2));
+ QuicPacketNumber unacked[] = {1, 2};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ QuicPacketNumber retransmittable[] = {2};
+ VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
+}
+
+TEST_P(QuicSentPacketManagerTest, RetransmitThenAck) {
+ SendDataPacket(1);
+ RetransmitAndSendPacket(1, 2);
+
+ // Ack 2 but not 1.
+ QuicAckFrame ack_frame = InitAckFrame(2);
+ NackPackets(1, 2, &ack_frame);
+ ExpectAck(2);
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+
+ // Packet 1 is unacked, pending, but not retransmittable.
+ QuicPacketNumber unacked[] = {1};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
+ VerifyRetransmittablePackets(nullptr, 0);
+}
+
+TEST_P(QuicSentPacketManagerTest, RetransmitThenAckBeforeSend) {
+ SendDataPacket(1);
+ QuicSentPacketManagerPeer::MarkForRetransmission(&manager_, kDefaultPathId, 1,
+ TLP_RETRANSMISSION);
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+
+ // Ack 1.
+ QuicAckFrame ack_frame = InitAckFrame(1);
+ ExpectAck(1);
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+
+ // There should no longer be a pending retransmission.
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+
+ // No unacked packets remain.
+ VerifyUnackedPackets(nullptr, 0);
+ VerifyRetransmittablePackets(nullptr, 0);
+ EXPECT_EQ(0u, stats_.packets_spuriously_retransmitted);
+}
+
+TEST_P(QuicSentPacketManagerTest, RetransmitThenStopRetransmittingBeforeSend) {
+ SendDataPacket(1);
+ QuicSentPacketManagerPeer::MarkForRetransmission(&manager_, kDefaultPathId, 1,
+ TLP_RETRANSMISSION);
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+
+ manager_.CancelRetransmissionsForStream(kStreamId);
+
+ // There should no longer be a pending retransmission.
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+
+ QuicPacketNumber unacked[] = {1};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(nullptr, 0);
+ EXPECT_EQ(0u, stats_.packets_spuriously_retransmitted);
+}
+
+TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPrevious) {
+ SendDataPacket(1);
+ RetransmitAndSendPacket(1, 2);
+ QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(15);
+ clock_.AdvanceTime(rtt);
+
+ // Ack 1 but not 2.
+ ExpectAck(1);
+ QuicAckFrame ack_frame = InitAckFrame(1);
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+
+ // 2 remains unacked, but no packets have retransmittable data.
+ QuicPacketNumber unacked[] = {2};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
+ VerifyRetransmittablePackets(nullptr, 0);
+
+ EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted);
+}
+
+TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) {
+ SendDataPacket(1);
+ RetransmitAndSendPacket(1, 2);
+ QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(15);
+ clock_.AdvanceTime(rtt);
+
+ // First, ACK packet 1 which makes packet 2 non-retransmittable.
+ ExpectAck(1);
+ QuicAckFrame ack_frame = InitAckFrame(1);
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+
+ SendDataPacket(3);
+ SendDataPacket(4);
+ SendDataPacket(5);
+ clock_.AdvanceTime(rtt);
+
+ // Next, NACK packet 2 three times.
+ ack_frame = InitAckFrame(3);
+ NackPackets(2, 3, &ack_frame);
+ ExpectAck(3);
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+
+ ack_frame = InitAckFrame(4);
+ NackPackets(2, 3, &ack_frame);
+ ExpectAck(4);
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+
+ ack_frame = InitAckFrame(5);
+ NackPackets(2, 3, &ack_frame);
+ ExpectAckAndLoss(true, 5, 2);
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+
+ // No packets remain unacked.
+ VerifyUnackedPackets(nullptr, 0);
+ EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
+ VerifyRetransmittablePackets(nullptr, 0);
+
+ // Verify that the retransmission alarm would not fire,
+ // since there is no retransmittable data outstanding.
+ EXPECT_EQ(QuicTime::Zero(), manager_.GetRetransmissionTime());
+}
+
+TEST_P(QuicSentPacketManagerTest,
+ DISABLED_RetransmitTwiceThenAckPreviousBeforeSend) {
+ SendDataPacket(1);
+ RetransmitAndSendPacket(1, 2);
+
+ // Fire the RTO, which will mark 2 for retransmission (but will not send it).
+ EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ manager_.OnRetransmissionTimeout();
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+
+ // Ack 1 but not 2, before 2 is able to be sent.
+ // Since 1 has been retransmitted, it has already been lost, and so the
+ // send algorithm is not informed that it has been ACK'd.
+ QuicAckFrame ack_frame = InitAckFrame(1);
+ ExpectUpdatedRtt(1);
+ EXPECT_CALL(*send_algorithm_, RevertRetransmissionTimeout());
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+
+ // Since 2 was marked for retransmit, when 1 is acked, 2 is kept for RTT.
+ QuicPacketNumber unacked[] = {2};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
+ VerifyRetransmittablePackets(nullptr, 0);
+
+ // Verify that the retransmission alarm would not fire,
+ // since there is no retransmittable data outstanding.
+ EXPECT_EQ(QuicTime::Zero(), manager_.GetRetransmissionTime());
+}
+
+TEST_P(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) {
+ StrictMock<MockDebugDelegate> debug_delegate;
+ EXPECT_CALL(debug_delegate, OnSpuriousPacketRetransmission(TLP_RETRANSMISSION,
+ kDefaultLength))
+ .Times(2);
+ manager_.SetDebugDelegate(&debug_delegate);
+
+ SendDataPacket(1);
+ RetransmitAndSendPacket(1, 2);
+ RetransmitAndSendPacket(2, 3);
+ QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(15);
+ clock_.AdvanceTime(rtt);
+
+ // Ack 1 but not 2 or 3.
+ ExpectAck(1);
+ QuicAckFrame ack_frame = InitAckFrame(1);
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+
+ // 2 and 3 remain unacked, but no packets have retransmittable data.
+ QuicPacketNumber unacked[] = {2, 3};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
+ VerifyRetransmittablePackets(nullptr, 0);
+
+ // Ensure packet 2 is lost when 4 is sent and 3 and 4 are acked.
+ SendDataPacket(4);
+ ack_frame = InitAckFrame(4);
+ NackPackets(2, 3, &ack_frame);
+ QuicPacketNumber acked[] = {3, 4};
+ ExpectAcksAndLosses(true, acked, arraysize(acked), nullptr, 0);
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+
+ QuicPacketNumber unacked2[] = {2};
+ VerifyUnackedPackets(unacked2, arraysize(unacked2));
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
+
+ SendDataPacket(5);
+ ack_frame = InitAckFrame(5);
+ NackPackets(2, 3, &ack_frame);
+ ExpectAckAndLoss(true, 5, 2);
+ EXPECT_CALL(debug_delegate, OnPacketLoss(2, LOSS_RETRANSMISSION, _));
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+
+ VerifyUnackedPackets(nullptr, 0);
+ EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
+ EXPECT_EQ(2u, stats_.packets_spuriously_retransmitted);
+}
+
+TEST_P(QuicSentPacketManagerTest, AckOriginalTransmission) {
+ auto loss_algorithm = base::MakeUnique<MockLossAlgorithm>();
+ QuicSentPacketManagerPeer::SetLossAlgorithm(&manager_, loss_algorithm.get());
+
+ SendDataPacket(1);
+ RetransmitAndSendPacket(1, 2);
+
+ // Ack original transmission, but that wasn't lost via fast retransmit,
+ // so no call on OnSpuriousRetransmission is expected.
+ {
+ QuicAckFrame ack_frame = InitAckFrame(1);
+ ExpectAck(1);
+ EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+ }
+
+ SendDataPacket(3);
+ SendDataPacket(4);
+ // Ack 4, which causes 3 to be retransmitted.
+ {
+ QuicAckFrame ack_frame = InitAckFrame(4);
+ NackPackets(2, 4, &ack_frame);
+ ExpectAck(4);
+ EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+ RetransmitAndSendPacket(3, 5, LOSS_RETRANSMISSION);
+ }
+
+ // Ack 3, which causes SpuriousRetransmitDetected to be called.
+ {
+ QuicAckFrame ack_frame = InitAckFrame(4);
+ NackPackets(2, 3, &ack_frame);
+ }
+}
+
+TEST_P(QuicSentPacketManagerTest, GetLeastUnacked) {
+ EXPECT_EQ(1u, manager_.GetLeastUnacked(kDefaultPathId));
+}
+
+TEST_P(QuicSentPacketManagerTest, GetLeastUnackedUnacked) {
+ SendDataPacket(1);
+ EXPECT_EQ(1u, manager_.GetLeastUnacked(kDefaultPathId));
+}
+
+TEST_P(QuicSentPacketManagerTest, AckAckAndUpdateRtt) {
+ SendDataPacket(1);
+ SendAckPacket(2);
+
+ // Now ack the ack and expect an RTT update.
+ QuicAckFrame ack_frame = InitAckFrame(2);
+ ack_frame.ack_delay_time = QuicTime::Delta::FromMilliseconds(5);
+
+ ExpectAck(1);
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+
+ SendAckPacket(3);
+
+ // Now ack the ack and expect only an RTT update.
+ ack_frame = InitAckFrame(3);
+ ExpectUpdatedRtt(3);
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+}
+
+TEST_P(QuicSentPacketManagerTest, Rtt) {
+ QuicPacketNumber packet_number = 1;
+ QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(15);
+ SendDataPacket(packet_number);
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
+
+ ExpectAck(packet_number);
+ QuicAckFrame ack_frame = InitAckFrame(packet_number);
+ ack_frame.ack_delay_time = QuicTime::Delta::FromMilliseconds(5);
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+ EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
+}
+
+TEST_P(QuicSentPacketManagerTest, RttWithInvalidDelta) {
+ // Expect that the RTT is equal to the local time elapsed, since the
+ // ack_delay_time is larger than the local time elapsed
+ // and is hence invalid.
+ QuicPacketNumber packet_number = 1;
+ QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(10);
+ SendDataPacket(packet_number);
+ clock_.AdvanceTime(expected_rtt);
+
+ ExpectAck(packet_number);
+ QuicAckFrame ack_frame = InitAckFrame(packet_number);
+ ack_frame.ack_delay_time = QuicTime::Delta::FromMilliseconds(11);
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+ EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
+}
+
+TEST_P(QuicSentPacketManagerTest, RttWithInfiniteDelta) {
+ // Expect that the RTT is equal to the local time elapsed, since the
+ // ack_delay_time is infinite, and is hence invalid.
+ QuicPacketNumber packet_number = 1;
+ QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(10);
+ SendDataPacket(packet_number);
+ clock_.AdvanceTime(expected_rtt);
+
+ ExpectAck(packet_number);
+ QuicAckFrame ack_frame = InitAckFrame(packet_number);
+ ack_frame.ack_delay_time = QuicTime::Delta::Infinite();
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+ EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
+}
+
+TEST_P(QuicSentPacketManagerTest, RttZeroDelta) {
+ // Expect that the RTT is the time between send and receive since the
+ // ack_delay_time is zero.
+ QuicPacketNumber packet_number = 1;
+ QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(10);
+ SendDataPacket(packet_number);
+ clock_.AdvanceTime(expected_rtt);
+
+ ExpectAck(packet_number);
+ QuicAckFrame ack_frame = InitAckFrame(packet_number);
+ ack_frame.ack_delay_time = QuicTime::Delta::Zero();
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+ EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
+}
+
+TEST_P(QuicSentPacketManagerTest, TailLossProbeTimeout) {
+ QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2);
+
+ // Send 1 packet.
+ QuicPacketNumber packet_number = 1;
+ SendDataPacket(packet_number);
+
+ QuicPathId path_id = kInvalidPathId;
+ // The first tail loss probe retransmits 1 packet.
+ manager_.OnRetransmissionTimeout();
+ EXPECT_EQ(QuicTime::Delta::Zero(),
+ manager_.TimeUntilSend(clock_.Now(), &path_id));
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ manager_.MaybeRetransmitTailLossProbe();
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ RetransmitNextPacket(2);
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+
+ // The second tail loss probe retransmits 1 packet.
+ manager_.OnRetransmissionTimeout();
+ EXPECT_EQ(QuicTime::Delta::Zero(),
+ manager_.TimeUntilSend(clock_.Now(), &path_id));
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ manager_.MaybeRetransmitTailLossProbe();
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ RetransmitNextPacket(3);
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ .WillOnce(Return(QuicTime::Delta::Infinite()));
+ EXPECT_EQ(QuicTime::Delta::Infinite(),
+ manager_.TimeUntilSend(clock_.Now(), &path_id));
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+
+ // Ack the third and ensure the first two are still pending.
+ ExpectAck(3);
+
+ QuicAckFrame ack_frame = InitAckFrame(3);
+ NackPackets(1, 3, &ack_frame);
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
+
+ // Acking two more packets will lose both of them due to nacks.
+ SendDataPacket(4);
+ SendDataPacket(5);
+ ack_frame = InitAckFrame(5);
+ NackPackets(1, 3, &ack_frame);
+ QuicPacketNumber acked[] = {4, 5};
+ QuicPacketNumber lost[] = {1, 2};
+ ExpectAcksAndLosses(true, acked, arraysize(acked), lost, arraysize(lost));
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
+ EXPECT_EQ(2u, stats_.tlp_count);
+ EXPECT_EQ(0u, stats_.rto_count);
+}
+
+TEST_P(QuicSentPacketManagerTest, TailLossProbeThenRTO) {
+ QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2);
+
+ // Send 100 packets.
+ const size_t kNumSentPackets = 100;
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+ QuicTime rto_packet_time = clock_.Now();
+ // Advance the time.
+ clock_.AdvanceTime(manager_.GetRetransmissionTime() - clock_.Now());
+
+ // The first tail loss probe retransmits 1 packet.
+ manager_.OnRetransmissionTimeout();
+ QuicPathId path_id = kInvalidPathId;
+ EXPECT_EQ(QuicTime::Delta::Zero(),
+ manager_.TimeUntilSend(clock_.Now(), &path_id));
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ manager_.MaybeRetransmitTailLossProbe();
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ RetransmitNextPacket(101);
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ .WillOnce(Return(QuicTime::Delta::Infinite()));
+ EXPECT_EQ(QuicTime::Delta::Infinite(),
+ manager_.TimeUntilSend(clock_.Now(), &path_id));
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ clock_.AdvanceTime(manager_.GetRetransmissionTime() - clock_.Now());
+
+ // The second tail loss probe retransmits 1 packet.
+ manager_.OnRetransmissionTimeout();
+ EXPECT_EQ(QuicTime::Delta::Zero(),
+ manager_.TimeUntilSend(clock_.Now(), &path_id));
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ EXPECT_TRUE(manager_.MaybeRetransmitTailLossProbe());
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ RetransmitNextPacket(102);
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ .WillOnce(Return(QuicTime::Delta::Infinite()));
+ EXPECT_EQ(QuicTime::Delta::Infinite(),
+ manager_.TimeUntilSend(clock_.Now(), &path_id));
+
+ // Ensure the RTO is set based on the correct packet.
+ rto_packet_time = clock_.Now();
+ EXPECT_EQ(rto_packet_time + QuicTime::Delta::FromMilliseconds(500),
+ manager_.GetRetransmissionTime());
+
+ // Advance the time enough to ensure all packets are RTO'd.
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000));
+
+ manager_.OnRetransmissionTimeout();
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ EXPECT_EQ(2u, stats_.tlp_count);
+ EXPECT_EQ(1u, stats_.rto_count);
+
+ // Send and Ack the RTO and ensure OnRetransmissionTimeout is called.
+ EXPECT_EQ(102 * kDefaultLength,
+ QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+
+ RetransmitNextPacket(103);
+ QuicAckFrame ack_frame = InitAckFrame(103);
+ NackPackets(0, 103, &ack_frame);
+ EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
+ EXPECT_CALL(*send_algorithm_,
+ OnCongestionEvent(true, _, ElementsAre(Pair(103, _)), _));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+ // All packets before 103 should be lost.
+ EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeout) {
+ // Send 2 crypto packets and 3 data packets.
+ const size_t kNumSentCryptoPackets = 2;
+ for (size_t i = 1; i <= kNumSentCryptoPackets; ++i) {
+ SendCryptoPacket(i);
+ }
+ const size_t kNumSentDataPackets = 3;
+ for (size_t i = 1; i <= kNumSentDataPackets; ++i) {
+ SendDataPacket(kNumSentCryptoPackets + i);
+ }
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+
+ // The first retransmits 2 packets.
+ QuicPathId path_id = kInvalidPathId;
+ manager_.OnRetransmissionTimeout();
+ EXPECT_EQ(QuicTime::Delta::Zero(),
+ manager_.TimeUntilSend(clock_.Now(), &path_id));
+ RetransmitNextPacket(6);
+ RetransmitNextPacket(7);
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+
+ // The second retransmits 2 packets.
+ manager_.OnRetransmissionTimeout();
+ EXPECT_EQ(QuicTime::Delta::Zero(),
+ manager_.TimeUntilSend(clock_.Now(), &path_id));
+ RetransmitNextPacket(8);
+ RetransmitNextPacket(9);
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+
+ // 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);
+ QuicAckFrame ack_frame = InitAckFrame(9);
+ NackPackets(1, 3, &ack_frame);
+ NackPackets(6, 8, &ack_frame);
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+
+ EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) {
+ // Send 2 crypto packets and 3 data packets.
+ const size_t kNumSentCryptoPackets = 2;
+ for (size_t i = 1; i <= kNumSentCryptoPackets; ++i) {
+ SendCryptoPacket(i);
+ }
+ const size_t kNumSentDataPackets = 3;
+ for (size_t i = 1; i <= kNumSentDataPackets; ++i) {
+ SendDataPacket(kNumSentCryptoPackets + i);
+ }
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+
+ // The first retransmission timeout retransmits 2 crypto packets.
+ manager_.OnRetransmissionTimeout();
+ RetransmitNextPacket(6);
+ RetransmitNextPacket(7);
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+
+ // Now act like a version negotiation packet arrived, which would cause all
+ // unacked packets to be retransmitted.
+ manager_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION);
+
+ // Ensure the first two pending packets are the crypto retransmits.
+ ASSERT_TRUE(manager_.HasPendingRetransmissions());
+ EXPECT_EQ(6u, manager_.NextPendingRetransmission().packet_number);
+ RetransmitNextPacket(8);
+ EXPECT_EQ(7u, manager_.NextPendingRetransmission().packet_number);
+ RetransmitNextPacket(9);
+
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ // Send 3 more data packets and ensure the least unacked is raised.
+ RetransmitNextPacket(10);
+ RetransmitNextPacket(11);
+ RetransmitNextPacket(12);
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+
+ EXPECT_EQ(1u, manager_.GetLeastUnacked(kDefaultPathId));
+ // 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);
+ QuicAckFrame ack_frame = InitAckFrame(9);
+ for (QuicPacketNumber i = 1; i < 8; ++i) {
+ NackPackets(i, i + 1, &ack_frame);
+ }
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+ EXPECT_EQ(10u, manager_.GetLeastUnacked(kDefaultPathId));
+}
+
+TEST_P(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) {
+ // Send 1 crypto packet.
+ SendCryptoPacket(1);
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+
+ // Retransmit the crypto packet as 2.
+ manager_.OnRetransmissionTimeout();
+ RetransmitNextPacket(2);
+
+ // Retransmit the crypto packet as 3.
+ manager_.OnRetransmissionTimeout();
+ RetransmitNextPacket(3);
+
+ // Now ack the second crypto packet, and ensure the first gets removed, but
+ // the third does not.
+ ExpectUpdatedRtt(2);
+ QuicAckFrame ack_frame = InitAckFrame(2);
+ NackPackets(1, 2, &ack_frame);
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+
+ EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+ QuicPacketNumber unacked[] = {3};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+}
+
+TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutUnsentDataPacket) {
+ // Send 2 crypto packets and 1 data packet.
+ const size_t kNumSentCryptoPackets = 2;
+ for (size_t i = 1; i <= kNumSentCryptoPackets; ++i) {
+ SendCryptoPacket(i);
+ }
+ SendDataPacket(3);
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+
+ // Retransmit 2 crypto packets, but not the serialized packet.
+ manager_.OnRetransmissionTimeout();
+ RetransmitNextPacket(4);
+ RetransmitNextPacket(5);
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest,
+ CryptoHandshakeRetransmissionThenRetransmitAll) {
+ // Send 1 crypto packet.
+ SendCryptoPacket(1);
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+
+ // Retransmit the crypto packet as 2.
+ manager_.OnRetransmissionTimeout();
+ RetransmitNextPacket(2);
+
+ // Now retransmit all the unacked packets, which occurs when there is a
+ // version negotiation.
+ manager_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION);
+ QuicPacketNumber unacked[] = {1, 2};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+ EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest,
+ CryptoHandshakeRetransmissionThenNeuterAndAck) {
+ // Send 1 crypto packet.
+ SendCryptoPacket(1);
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+
+ // Retransmit the crypto packet as 2.
+ manager_.OnRetransmissionTimeout();
+ RetransmitNextPacket(2);
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+
+ // Retransmit the crypto packet as 3.
+ manager_.OnRetransmissionTimeout();
+ RetransmitNextPacket(3);
+ EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+
+ // Now neuter all unacked unencrypted packets, which occurs when the
+ // connection goes forward secure.
+ manager_.NeuterUnencryptedPackets();
+ EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+ QuicPacketNumber unacked[] = {1, 2, 3};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(nullptr, 0);
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
+ EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
+
+ // Ensure both packets get discarded when packet 2 is acked.
+ QuicAckFrame ack_frame = InitAckFrame(3);
+ NackPackets(1, 3, &ack_frame);
+ ExpectUpdatedRtt(3);
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+ VerifyUnackedPackets(nullptr, 0);
+ VerifyRetransmittablePackets(nullptr, 0);
+}
+
+TEST_P(QuicSentPacketManagerTest, RetransmissionTimeout) {
+ StrictMock<MockDebugDelegate> debug_delegate;
+ manager_.SetDebugDelegate(&debug_delegate);
+
+ // Send 100 packets.
+ const size_t kNumSentPackets = 100;
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+
+ EXPECT_FALSE(manager_.MaybeRetransmitTailLossProbe());
+ manager_.OnRetransmissionTimeout();
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ EXPECT_EQ(100 * kDefaultLength,
+ QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+ RetransmitNextPacket(101);
+ RetransmitNextPacket(102);
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+
+ // Ack a retransmission.
+ QuicAckFrame ack_frame = InitAckFrame(102);
+ NackPackets(0, 102, &ack_frame);
+ ack_frame.ack_delay_time = QuicTime::Delta::Zero();
+ // Ensure no packets are lost.
+ EXPECT_CALL(*send_algorithm_,
+ OnCongestionEvent(true, _, ElementsAre(Pair(102, _)),
+ /*lost_packets=*/IsEmpty()));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
+ // RTO's use loss detection instead of immediately declaring retransmitted
+ // packets lost.
+ for (int i = 1; i <= 99; ++i) {
+ EXPECT_CALL(debug_delegate, OnPacketLoss(i, LOSS_RETRANSMISSION, _));
+ }
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+}
+
+TEST_P(QuicSentPacketManagerTest, NewRetransmissionTimeout) {
+ QuicConfig client_config;
+ QuicTagVector options;
+ options.push_back(kNRTO);
+ QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT);
+ client_config.SetConnectionOptionsToSend(options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, PacingRate(_))
+ .WillRepeatedly(Return(QuicBandwidth::Zero()));
+ EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
+ .WillOnce(Return(10 * kDefaultTCPMSS));
+ manager_.SetFromConfig(client_config);
+ EXPECT_TRUE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
+
+ // Send 100 packets.
+ const size_t kNumSentPackets = 100;
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+
+ EXPECT_FALSE(manager_.MaybeRetransmitTailLossProbe());
+ manager_.OnRetransmissionTimeout();
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ EXPECT_EQ(100 * kDefaultLength,
+ QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+ RetransmitNextPacket(101);
+ RetransmitNextPacket(102);
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+
+ // Ack a retransmission and expect no call to OnRetransmissionTimeout.
+ QuicAckFrame ack_frame = InitAckFrame(102);
+ NackPackets(0, 102, &ack_frame);
+ ack_frame.ack_delay_time = QuicTime::Delta::Zero();
+ // This will include packets in the lost packet map.
+ EXPECT_CALL(*send_algorithm_,
+ OnCongestionEvent(true, _, ElementsAre(Pair(102, _)),
+ /*lost_packets=*/Not(IsEmpty())));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+}
+
+TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) {
+ // Send 1 packet.
+ SendDataPacket(1);
+
+ manager_.OnRetransmissionTimeout();
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ EXPECT_EQ(kDefaultLength,
+ QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+ RetransmitNextPacket(2);
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+
+ // Rto a second time.
+ EXPECT_CALL(*network_change_visitor_, OnPathDegrading());
+ manager_.OnRetransmissionTimeout();
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ EXPECT_EQ(2 * kDefaultLength,
+ QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+ RetransmitNextPacket(3);
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+
+ // Ack a retransmission and ensure OnRetransmissionTimeout is called.
+ EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
+ QuicAckFrame ack_frame = InitAckFrame(2);
+ NackPackets(1, 2, &ack_frame);
+ ack_frame.ack_delay_time = QuicTime::Delta::Zero();
+ ExpectAck(2);
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+
+ // The original packet and newest should be outstanding.
+ EXPECT_EQ(2 * kDefaultLength,
+ QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckFirst) {
+ // Send 1 packet.
+ SendDataPacket(1);
+
+ manager_.OnRetransmissionTimeout();
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ EXPECT_EQ(kDefaultLength,
+ QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+ RetransmitNextPacket(2);
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+
+ // Rto a second time.
+ EXPECT_CALL(*network_change_visitor_, OnPathDegrading());
+ manager_.OnRetransmissionTimeout();
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ EXPECT_EQ(2 * kDefaultLength,
+ QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+ RetransmitNextPacket(3);
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+
+ // Ack a retransmission and ensure OnRetransmissionTimeout is called.
+ EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
+ QuicAckFrame ack_frame = InitAckFrame(3);
+ NackPackets(1, 3, &ack_frame);
+ ack_frame.ack_delay_time = QuicTime::Delta::Zero();
+ ExpectAck(3);
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+
+ // The first two packets should still be outstanding.
+ EXPECT_EQ(2 * kDefaultLength,
+ QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest, OnPathDegrading) {
+ SendDataPacket(1);
+ for (size_t i = 1; i < kMinTimeoutsBeforePathDegrading; ++i) {
+ manager_.OnRetransmissionTimeout();
+ RetransmitNextPacket(i + 2);
+ }
+ // Next RTO should cause network_change_visitor_'s OnPathDegrading method
+ // to be called.
+ EXPECT_CALL(*network_change_visitor_, OnPathDegrading());
+ manager_.OnRetransmissionTimeout();
+}
+
+TEST_P(QuicSentPacketManagerTest, GetTransmissionTime) {
+ EXPECT_EQ(QuicTime::Zero(), manager_.GetRetransmissionTime());
+}
+
+TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeCryptoHandshake) {
+ SendCryptoPacket(1);
+
+ // Check the min.
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+ rtt_stats->set_initial_rtt_us(1 * kNumMicrosPerMilli);
+ EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromMilliseconds(10),
+ manager_.GetRetransmissionTime());
+
+ // Test with a standard smoothed RTT.
+ rtt_stats->set_initial_rtt_us(100 * kNumMicrosPerMilli);
+
+ QuicTime::Delta srtt =
+ QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
+ QuicTime expected_time = clock_.Now() + 1.5 * srtt;
+ EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
+
+ // Retransmit the packet by invoking the retransmission timeout.
+ clock_.AdvanceTime(1.5 * srtt);
+ manager_.OnRetransmissionTimeout();
+ RetransmitNextPacket(2);
+
+ // The retransmission time should now be twice as far in the future.
+ expected_time = clock_.Now() + srtt * 2 * 1.5;
+ EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
+}
+
+TEST_P(QuicSentPacketManagerTest,
+ GetConservativeTransmissionTimeCryptoHandshake) {
+ FLAGS_quic_conservative_handshake_retransmits = true;
+ QuicConfig config;
+ QuicTagVector options;
+ options.push_back(kCONH);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ manager_.SetFromConfig(config);
+ // Calling SetFromConfig requires mocking out some send algorithm methods.
+ EXPECT_CALL(*send_algorithm_, PacingRate(_))
+ .WillRepeatedly(Return(QuicBandwidth::Zero()));
+ EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
+ .WillRepeatedly(Return(10 * kDefaultTCPMSS));
+
+ SendCryptoPacket(1);
+
+ // Check the min.
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+ rtt_stats->set_initial_rtt_us(1 * kNumMicrosPerMilli);
+ EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromMilliseconds(25),
+ manager_.GetRetransmissionTime());
+
+ // Test with a standard smoothed RTT.
+ rtt_stats->set_initial_rtt_us(100 * kNumMicrosPerMilli);
+
+ QuicTime::Delta srtt =
+ QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
+ QuicTime expected_time = clock_.Now() + 2 * srtt;
+ EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
+
+ // Retransmit the packet by invoking the retransmission timeout.
+ clock_.AdvanceTime(2 * srtt);
+ manager_.OnRetransmissionTimeout();
+ RetransmitNextPacket(2);
+
+ // The retransmission time should now be twice as far in the future.
+ expected_time = clock_.Now() + srtt * 2 * 2;
+ EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
+}
+
+TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeTailLossProbe) {
+ QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2);
+ SendDataPacket(1);
+ SendDataPacket(2);
+
+ // Check the min.
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+ rtt_stats->set_initial_rtt_us(1 * kNumMicrosPerMilli);
+ EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromMilliseconds(10),
+ manager_.GetRetransmissionTime());
+
+ // Test with a standard smoothed RTT.
+ rtt_stats->set_initial_rtt_us(100 * kNumMicrosPerMilli);
+ QuicTime::Delta srtt =
+ QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
+ QuicTime::Delta expected_tlp_delay = 2 * srtt;
+ QuicTime expected_time = clock_.Now() + expected_tlp_delay;
+ EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
+
+ // Retransmit the packet by invoking the retransmission timeout.
+ clock_.AdvanceTime(expected_tlp_delay);
+ manager_.OnRetransmissionTimeout();
+ QuicPathId path_id = kInvalidPathId;
+ EXPECT_EQ(QuicTime::Delta::Zero(),
+ manager_.TimeUntilSend(clock_.Now(), &path_id));
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ EXPECT_TRUE(manager_.MaybeRetransmitTailLossProbe());
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ RetransmitNextPacket(3);
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ .WillOnce(Return(QuicTime::Delta::Infinite()));
+ EXPECT_EQ(QuicTime::Delta::Infinite(),
+ manager_.TimeUntilSend(clock_.Now(), &path_id));
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+
+ expected_time = clock_.Now() + expected_tlp_delay;
+ EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
+}
+
+TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeSpuriousRTO) {
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+
+ SendDataPacket(1);
+ SendDataPacket(2);
+ SendDataPacket(3);
+ SendDataPacket(4);
+
+ QuicTime::Delta expected_rto_delay =
+ rtt_stats->smoothed_rtt() + 4 * rtt_stats->mean_deviation();
+ QuicTime expected_time = clock_.Now() + expected_rto_delay;
+ EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
+
+ // Retransmit the packet by invoking the retransmission timeout.
+ clock_.AdvanceTime(expected_rto_delay);
+ manager_.OnRetransmissionTimeout();
+ // All packets are still considered inflight.
+ EXPECT_EQ(4 * kDefaultLength,
+ QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+ RetransmitNextPacket(5);
+ RetransmitNextPacket(6);
+ // All previous packets are inflight, plus two rto retransmissions.
+ EXPECT_EQ(6 * kDefaultLength,
+ QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+
+ // The delay should double the second time.
+ expected_time = clock_.Now() + expected_rto_delay + expected_rto_delay;
+ // Once we always base the timer on the right edge, leaving the older packets
+ // in flight doesn't change the timeout.
+ EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
+
+ // Ack a packet before the first RTO and ensure the RTO timeout returns to the
+ // original value and OnRetransmissionTimeout is not called or reverted.
+ QuicAckFrame ack_frame = InitAckFrame(2);
+ NackPackets(1, 2, &ack_frame);
+ ExpectAck(2);
+ manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ EXPECT_EQ(5 * kDefaultLength,
+ QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+
+ // Wait 2RTTs from now for the RTO, since it's the max of the RTO time
+ // and the TLP time. In production, there would always be two TLP's first.
+ // Since retransmission was spurious, smoothed_rtt_ is expired, and replaced
+ // by the latest RTT sample of 500ms.
+ expected_time = clock_.Now() + QuicTime::Delta::FromMilliseconds(1000);
+ // Once we always base the timer on the right edge, leaving the older packets
+ // in flight doesn't change the timeout.
+ EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
+}
+
+TEST_P(QuicSentPacketManagerTest, GetTransmissionDelayMin) {
+ SendDataPacket(1);
+ // Provide a 1ms RTT sample.
+ const_cast<RttStats*>(manager_.GetRttStats())
+ ->UpdateRtt(QuicTime::Delta::FromMilliseconds(1), QuicTime::Delta::Zero(),
+ QuicTime::Zero());
+ QuicTime::Delta delay = QuicTime::Delta::FromMilliseconds(200);
+
+ // If the delay is smaller than the min, ensure it exponentially backs off
+ // from the min.
+ EXPECT_CALL(*network_change_visitor_, OnPathDegrading());
+ for (int i = 0; i < 5; ++i) {
+ EXPECT_EQ(delay,
+ QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_));
+ delay = delay + delay;
+ manager_.OnRetransmissionTimeout();
+ RetransmitNextPacket(i + 2);
+ }
+}
+
+TEST_P(QuicSentPacketManagerTest, GetTransmissionDelayMax) {
+ SendDataPacket(1);
+ // Provide a 60s RTT sample.
+ const_cast<RttStats*>(manager_.GetRttStats())
+ ->UpdateRtt(QuicTime::Delta::FromSeconds(60), QuicTime::Delta::Zero(),
+ QuicTime::Zero());
+
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(60),
+ QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest, GetTransmissionDelayExponentialBackoff) {
+ SendDataPacket(1);
+ QuicTime::Delta delay = QuicTime::Delta::FromMilliseconds(500);
+
+ // Delay should back off exponentially.
+ EXPECT_CALL(*network_change_visitor_, OnPathDegrading());
+ for (int i = 0; i < 5; ++i) {
+ EXPECT_EQ(delay,
+ QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_));
+ delay = delay + delay;
+ manager_.OnRetransmissionTimeout();
+ RetransmitNextPacket(i + 2);
+ }
+}
+
+TEST_F(QuicSentPacketManagerTest, RetransmissionDelay) {
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+ const int64_t kRttMs = 250;
+ const int64_t kDeviationMs = 5;
+
+ rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRttMs),
+ QuicTime::Delta::Zero(), clock_.Now());
+
+ // Initial value is to set the median deviation to half of the initial rtt,
+ // the median in then multiplied by a factor of 4 and finally the smoothed rtt
+ // is added which is the initial rtt.
+ QuicTime::Delta expected_delay =
+ QuicTime::Delta::FromMilliseconds(kRttMs + kRttMs / 2 * 4);
+ EXPECT_EQ(expected_delay,
+ QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_));
+
+ for (int i = 0; i < 100; ++i) {
+ // Run to make sure that we converge.
+ rtt_stats->UpdateRtt(
+ QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs),
+ QuicTime::Delta::Zero(), clock_.Now());
+ rtt_stats->UpdateRtt(
+ QuicTime::Delta::FromMilliseconds(kRttMs - kDeviationMs),
+ QuicTime::Delta::Zero(), clock_.Now());
+ }
+ expected_delay = QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs * 4);
+
+ EXPECT_NEAR(kRttMs, rtt_stats->smoothed_rtt().ToMilliseconds(), 1);
+ EXPECT_NEAR(expected_delay.ToMilliseconds(),
+ QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_)
+ .ToMilliseconds(),
+ 1);
+}
+
+TEST_P(QuicSentPacketManagerTest, GetLossDelay) {
+ auto loss_algorithm = base::MakeUnique<MockLossAlgorithm>();
+ QuicSentPacketManagerPeer::SetLossAlgorithm(&manager_, loss_algorithm.get());
+
+ EXPECT_CALL(*loss_algorithm, GetLossTimeout())
+ .WillRepeatedly(Return(QuicTime::Zero()));
+ SendDataPacket(1);
+ SendDataPacket(2);
+
+ // Handle an ack which causes the loss algorithm to be evaluated and
+ // set the loss timeout.
+ ExpectAck(2);
+ EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
+ QuicAckFrame ack_frame = InitAckFrame(2);
+ NackPackets(1, 2, &ack_frame);
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+
+ QuicTime timeout(clock_.Now() + QuicTime::Delta::FromMilliseconds(10));
+ EXPECT_CALL(*loss_algorithm, GetLossTimeout())
+ .WillRepeatedly(Return(timeout));
+ EXPECT_EQ(timeout, manager_.GetRetransmissionTime());
+
+ // Fire the retransmission timeout and ensure the loss detection algorithm
+ // is invoked.
+ EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
+ manager_.OnRetransmissionTimeout();
+}
+
+TEST_P(QuicSentPacketManagerTest, NegotiateTimeLossDetectionFromOptions) {
+ EXPECT_EQ(kNack, QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_)
+ ->GetLossDetectionType());
+
+ QuicConfig config;
+ QuicTagVector options;
+ options.push_back(kTIME);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ manager_.SetFromConfig(config);
+
+ EXPECT_EQ(kTime, QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_)
+ ->GetLossDetectionType());
+}
+
+TEST_P(QuicSentPacketManagerTest, NegotiateCongestionControlFromOptions) {
+ FLAGS_quic_allow_bbr = true;
+ QuicConfig config;
+ QuicTagVector options;
+
+ options.push_back(kRENO);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ manager_.SetFromConfig(config);
+ EXPECT_EQ(kReno, QuicSentPacketManagerPeer::GetSendAlgorithm(manager_)
+ ->GetCongestionControlType());
+
+ options.clear();
+ options.push_back(kTBBR);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ manager_.SetFromConfig(config);
+ // TODO(vasilvv): change this back to kBBR when the new version is in.
+ EXPECT_EQ(kCubic, QuicSentPacketManagerPeer::GetSendAlgorithm(manager_)
+ ->GetCongestionControlType());
+
+ options.clear();
+ options.push_back(kBYTE);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ manager_.SetFromConfig(config);
+ EXPECT_EQ(kCubicBytes, QuicSentPacketManagerPeer::GetSendAlgorithm(manager_)
+ ->GetCongestionControlType());
+
+ options.clear();
+ options.push_back(kRENO);
+ options.push_back(kBYTE);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ manager_.SetFromConfig(config);
+ EXPECT_EQ(kRenoBytes, QuicSentPacketManagerPeer::GetSendAlgorithm(manager_)
+ ->GetCongestionControlType());
+}
+
+TEST_P(QuicSentPacketManagerTest, NegotiateNumConnectionsFromOptions) {
+ QuicConfig config;
+ QuicTagVector options;
+
+ options.push_back(k1CON);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(1));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ manager_.SetFromConfig(config);
+
+ QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT);
+ QuicConfig client_config;
+ client_config.SetConnectionOptionsToSend(options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(1));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ manager_.SetFromConfig(client_config);
+}
+
+TEST_P(QuicSentPacketManagerTest, NegotiateNConnectionFromOptions) {
+ // By default, changing the number of open streams does nothing.
+ manager_.SetNumOpenStreams(5);
+
+ QuicConfig config;
+ QuicTagVector options;
+
+ options.push_back(kNCON);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ manager_.SetFromConfig(config);
+
+ EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(5));
+ manager_.SetNumOpenStreams(5);
+}
+
+TEST_P(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtServer) {
+ QuicConfig config;
+ QuicTagVector options;
+
+ options.push_back(kNTLP);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ manager_.SetFromConfig(config);
+ EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtClient) {
+ QuicConfig client_config;
+ QuicTagVector options;
+
+ options.push_back(kNTLP);
+ 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(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtServer) {
+ QuicConfig config;
+ QuicTagVector options;
+
+ options.push_back(kTLPR);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ manager_.SetFromConfig(config);
+ EXPECT_TRUE(
+ QuicSentPacketManagerPeer::GetEnableHalfRttTailLossProbe(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtClient) {
+ QuicConfig client_config;
+ QuicTagVector options;
+
+ options.push_back(kTLPR);
+ 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_TRUE(
+ QuicSentPacketManagerPeer::GetEnableHalfRttTailLossProbe(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtServer) {
+ EXPECT_FALSE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
+ QuicConfig config;
+ QuicTagVector options;
+
+ options.push_back(kNRTO);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ manager_.SetFromConfig(config);
+ EXPECT_TRUE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtClient) {
+ EXPECT_FALSE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
+ QuicConfig client_config;
+ QuicTagVector options;
+
+ options.push_back(kNRTO);
+ 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_TRUE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest, NegotiateUndoFromOptionsAtServer) {
+ EXPECT_FALSE(QuicSentPacketManagerPeer::GetUndoRetransmits(&manager_));
+ QuicConfig config;
+ QuicTagVector options;
+
+ options.push_back(kUNDO);
+ QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ manager_.SetFromConfig(config);
+ EXPECT_TRUE(QuicSentPacketManagerPeer::GetUndoRetransmits(&manager_));
+
+ // Ensure undo works as intended.
+ // Send 5 packets, mark the first 4 for retransmission, and then cancel
+ // them when 1 is acked.
+ EXPECT_CALL(*send_algorithm_, PacingRate(_))
+ .WillRepeatedly(Return(QuicBandwidth::Zero()));
+ EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
+ .WillOnce(Return(10 * kDefaultTCPMSS));
+ const size_t kNumSentPackets = 5;
+ for (size_t i = 1; i <= kNumSentPackets; ++i) {
+ SendDataPacket(i);
+ }
+ auto loss_algorithm = base::MakeUnique<MockLossAlgorithm>();
+ QuicSentPacketManagerPeer::SetLossAlgorithm(&manager_, loss_algorithm.get());
+ EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ SendAlgorithmInterface::CongestionVector lost_packets;
+ for (size_t i = 1; i < kNumSentPackets; ++i) {
+ lost_packets.push_back(std::make_pair(i, kMaxPacketSize));
+ }
+ EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _))
+ .WillOnce(SetArgPointee<4>(lost_packets));
+ QuicAckFrame ack_frame = InitAckFrame(kNumSentPackets);
+ NackPackets(1, kNumSentPackets, &ack_frame);
+ // Congestion block the sending right before losing the packets.
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
+ .WillRepeatedly(Return(QuicTime::Delta::Infinite()));
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+ EXPECT_TRUE(manager_.HasPendingRetransmissions());
+ EXPECT_EQ(0u, BytesInFlight());
+
+ // Ack 1 and ensure the retransmissions are cancelled and put back in flight.
+ EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
+ ack_frame = InitAckFrame(5);
+ NackPackets(2, kNumSentPackets, &ack_frame);
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+ EXPECT_FALSE(manager_.HasPendingRetransmissions());
+ EXPECT_EQ(3u * kDefaultLength, BytesInFlight());
+}
+
+TEST_P(QuicSentPacketManagerTest, NegotiateUndoFromOptionsAtClient) {
+ EXPECT_FALSE(QuicSentPacketManagerPeer::GetUndoRetransmits(&manager_));
+ QuicConfig client_config;
+ QuicTagVector options;
+
+ options.push_back(kUNDO);
+ 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_TRUE(QuicSentPacketManagerPeer::GetUndoRetransmits(&manager_));
+}
+
+TEST_P(QuicSentPacketManagerTest, UseInitialRoundTripTimeToSend) {
+ uint32_t initial_rtt_us = 325000;
+ EXPECT_NE(initial_rtt_us,
+ manager_.GetRttStats()->smoothed_rtt().ToMicroseconds());
+
+ QuicConfig config;
+ config.SetInitialRoundTripTimeUsToSend(initial_rtt_us);
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+ manager_.SetFromConfig(config);
+
+ EXPECT_EQ(0, manager_.GetRttStats()->smoothed_rtt().ToMicroseconds());
+ EXPECT_EQ(initial_rtt_us, manager_.GetRttStats()->initial_rtt_us());
+}
+
+TEST_P(QuicSentPacketManagerTest, ResumeConnectionState) {
+ // The sent packet manager should use the RTT from CachedNetworkParameters if
+ // it is provided.
+ const int kRttMs = 1234;
+ CachedNetworkParameters cached_network_params;
+ cached_network_params.set_min_rtt_ms(kRttMs);
+
+ EXPECT_CALL(*send_algorithm_, ResumeConnectionState(_, false));
+ manager_.ResumeConnectionState(cached_network_params, false);
+ EXPECT_EQ(kRttMs * kNumMicrosPerMilli,
+ static_cast<uint64_t>(manager_.GetRttStats()->initial_rtt_us()));
+}
+
+TEST_P(QuicSentPacketManagerTest, ConnectionMigrationUnspecifiedChange) {
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+ int64_t default_init_rtt = rtt_stats->initial_rtt_us();
+ rtt_stats->set_initial_rtt_us(default_init_rtt * 2);
+ EXPECT_EQ(2 * default_init_rtt, rtt_stats->initial_rtt_us());
+
+ QuicSentPacketManagerPeer::SetConsecutiveRtoCount(&manager_, 1);
+ EXPECT_EQ(1u, manager_.GetConsecutiveRtoCount());
+ QuicSentPacketManagerPeer::SetConsecutiveTlpCount(&manager_, 2);
+ EXPECT_EQ(2u, manager_.GetConsecutiveTlpCount());
+
+ EXPECT_CALL(*send_algorithm_, OnConnectionMigration());
+ manager_.OnConnectionMigration(kDefaultPathId, IPV4_TO_IPV4_CHANGE);
+
+ EXPECT_EQ(default_init_rtt, rtt_stats->initial_rtt_us());
+ EXPECT_EQ(0u, manager_.GetConsecutiveRtoCount());
+ EXPECT_EQ(0u, manager_.GetConsecutiveTlpCount());
+}
+
+TEST_P(QuicSentPacketManagerTest, ConnectionMigrationIPSubnetChange) {
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+ int64_t default_init_rtt = rtt_stats->initial_rtt_us();
+ rtt_stats->set_initial_rtt_us(default_init_rtt * 2);
+ EXPECT_EQ(2 * default_init_rtt, rtt_stats->initial_rtt_us());
+
+ QuicSentPacketManagerPeer::SetConsecutiveRtoCount(&manager_, 1);
+ EXPECT_EQ(1u, manager_.GetConsecutiveRtoCount());
+ QuicSentPacketManagerPeer::SetConsecutiveTlpCount(&manager_, 2);
+ EXPECT_EQ(2u, manager_.GetConsecutiveTlpCount());
+
+ manager_.OnConnectionMigration(kDefaultPathId, IPV4_SUBNET_CHANGE);
+
+ EXPECT_EQ(2 * default_init_rtt, rtt_stats->initial_rtt_us());
+ EXPECT_EQ(1u, manager_.GetConsecutiveRtoCount());
+ EXPECT_EQ(2u, manager_.GetConsecutiveTlpCount());
+}
+
+TEST_P(QuicSentPacketManagerTest, ConnectionMigrationPortChange) {
+ RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
+ int64_t default_init_rtt = rtt_stats->initial_rtt_us();
+ rtt_stats->set_initial_rtt_us(default_init_rtt * 2);
+ EXPECT_EQ(2 * default_init_rtt, rtt_stats->initial_rtt_us());
+
+ QuicSentPacketManagerPeer::SetConsecutiveRtoCount(&manager_, 1);
+ EXPECT_EQ(1u, manager_.GetConsecutiveRtoCount());
+ QuicSentPacketManagerPeer::SetConsecutiveTlpCount(&manager_, 2);
+ EXPECT_EQ(2u, manager_.GetConsecutiveTlpCount());
+
+ manager_.OnConnectionMigration(kDefaultPathId, PORT_CHANGE);
+
+ EXPECT_EQ(2 * default_init_rtt, rtt_stats->initial_rtt_us());
+ EXPECT_EQ(1u, manager_.GetConsecutiveRtoCount());
+ EXPECT_EQ(2u, manager_.GetConsecutiveTlpCount());
+}
+
+TEST_P(QuicSentPacketManagerTest, PathMtuIncreased) {
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), 1, _, _))
+ .Times(1)
+ .WillOnce(Return(true));
+ SerializedPacket packet(kDefaultPathId, 1, PACKET_6BYTE_PACKET_NUMBER,
+ nullptr, kDefaultLength + 100, 0u, false, false);
+ manager_.OnPacketSent(&packet, kInvalidPathId, 0, clock_.Now(),
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+
+ // Ack the large packet and expect the path MTU to increase.
+ ExpectAck(1);
+ EXPECT_CALL(*network_change_visitor_,
+ OnPathMtuIncreased(kDefaultLength + 100));
+ QuicAckFrame ack_frame = InitAckFrame(1);
+ manager_.OnIncomingAck(ack_frame, clock_.Now());
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_server_id.cc b/chromium/net/quic/core/quic_server_id.cc
new file mode 100644
index 00000000000..9bcf84c979c
--- /dev/null
+++ b/chromium/net/quic/core/quic_server_id.cc
@@ -0,0 +1,59 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_server_id.h"
+
+#include <tuple>
+
+#include "base/logging.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/port_util.h"
+#include "url/gurl.h"
+
+using std::string;
+
+namespace net {
+
+QuicServerId::QuicServerId() : privacy_mode_(PRIVACY_MODE_DISABLED) {}
+
+QuicServerId::QuicServerId(const HostPortPair& host_port_pair,
+ PrivacyMode privacy_mode)
+ : host_port_pair_(host_port_pair), privacy_mode_(privacy_mode) {}
+
+QuicServerId::QuicServerId(const string& host, uint16_t port)
+ : host_port_pair_(host, port), privacy_mode_(PRIVACY_MODE_DISABLED) {}
+
+QuicServerId::QuicServerId(const string& host,
+ uint16_t port,
+ PrivacyMode privacy_mode)
+ : host_port_pair_(host, port), privacy_mode_(privacy_mode) {}
+
+QuicServerId::~QuicServerId() {}
+
+bool QuicServerId::operator<(const QuicServerId& other) const {
+ return std::tie(host_port_pair_, privacy_mode_) <
+ std::tie(other.host_port_pair_, other.privacy_mode_);
+}
+
+bool QuicServerId::operator==(const QuicServerId& other) const {
+ return privacy_mode_ == other.privacy_mode_ &&
+ host_port_pair_.Equals(other.host_port_pair_);
+}
+
+// static
+QuicServerId QuicServerId::FromString(const std::string& str) {
+ GURL url(str);
+ if (!url.is_valid())
+ return QuicServerId();
+ return QuicServerId(HostPortPair::FromURL(url), url.path() == "/private"
+ ? PRIVACY_MODE_ENABLED
+ : PRIVACY_MODE_DISABLED);
+}
+
+string QuicServerId::ToString() const {
+ return "https://" + host_port_pair_.ToString() +
+ (privacy_mode_ == PRIVACY_MODE_ENABLED ? "/private" : "");
+}
+
+} // namespace net
diff --git a/chromium/net/quic/quic_server_id.h b/chromium/net/quic/core/quic_server_id.h
index 97dbebbb49a..97dbebbb49a 100644
--- a/chromium/net/quic/quic_server_id.h
+++ b/chromium/net/quic/core/quic_server_id.h
diff --git a/chromium/net/quic/core/quic_server_id_test.cc b/chromium/net/quic/core/quic_server_id_test.cc
new file mode 100644
index 00000000000..95eeb670f3c
--- /dev/null
+++ b/chromium/net/quic/core/quic_server_id_test.cc
@@ -0,0 +1,145 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_server_id.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+
+namespace net {
+
+namespace {
+
+TEST(QuicServerIdTest, ToString) {
+ HostPortPair google_host_port_pair("google.com", 10);
+
+ QuicServerId google_server_id(google_host_port_pair, PRIVACY_MODE_DISABLED);
+ string google_server_id_str = google_server_id.ToString();
+ EXPECT_EQ("https://google.com:10", google_server_id_str);
+
+ QuicServerId private_server_id(google_host_port_pair, PRIVACY_MODE_ENABLED);
+ string private_server_id_str = private_server_id.ToString();
+ EXPECT_EQ("https://google.com:10/private", private_server_id_str);
+}
+
+TEST(QuicServerIdTest, LessThan) {
+ QuicServerId a_10_https(HostPortPair("a.com", 10), PRIVACY_MODE_DISABLED);
+ QuicServerId a_11_https(HostPortPair("a.com", 11), PRIVACY_MODE_DISABLED);
+ QuicServerId b_10_https(HostPortPair("b.com", 10), PRIVACY_MODE_DISABLED);
+ QuicServerId b_11_https(HostPortPair("b.com", 11), PRIVACY_MODE_DISABLED);
+
+ QuicServerId a_10_https_private(HostPortPair("a.com", 10),
+ PRIVACY_MODE_ENABLED);
+ QuicServerId a_11_https_private(HostPortPair("a.com", 11),
+ PRIVACY_MODE_ENABLED);
+ QuicServerId b_10_https_private(HostPortPair("b.com", 10),
+ PRIVACY_MODE_ENABLED);
+ QuicServerId b_11_https_private(HostPortPair("b.com", 11),
+ PRIVACY_MODE_ENABLED);
+
+ // Test combinations of host, port, and privacy being same on left and
+ // right side of less than.
+ EXPECT_FALSE(a_10_https < a_10_https);
+ EXPECT_TRUE(a_10_https < a_10_https_private);
+ EXPECT_FALSE(a_10_https_private < a_10_https);
+ EXPECT_FALSE(a_10_https_private < a_10_https_private);
+
+ // Test with either host, port or https being different on left and right side
+ // of less than.
+ PrivacyMode left_privacy;
+ PrivacyMode right_privacy;
+ for (int i = 0; i < 4; i++) {
+ left_privacy = static_cast<PrivacyMode>(i / 2);
+ right_privacy = static_cast<PrivacyMode>(i % 2);
+ QuicServerId a_10_https_left_private(HostPortPair("a.com", 10),
+ left_privacy);
+ QuicServerId a_10_https_right_private(HostPortPair("a.com", 10),
+ right_privacy);
+ QuicServerId a_11_https_left_private(HostPortPair("a.com", 11),
+ left_privacy);
+ QuicServerId a_11_https_right_private(HostPortPair("a.com", 11),
+ right_privacy);
+
+ QuicServerId b_10_https_left_private(HostPortPair("b.com", 10),
+ left_privacy);
+ QuicServerId b_10_https_right_private(HostPortPair("b.com", 10),
+ right_privacy);
+ QuicServerId b_11_https_left_private(HostPortPair("b.com", 11),
+ left_privacy);
+ QuicServerId b_11_https_right_private(HostPortPair("b.com", 11),
+ right_privacy);
+
+ EXPECT_TRUE(a_10_https_left_private < a_11_https_right_private);
+ EXPECT_TRUE(a_10_https_left_private < b_10_https_right_private);
+ EXPECT_TRUE(a_10_https_left_private < b_11_https_right_private);
+ EXPECT_FALSE(a_11_https_left_private < a_10_https_right_private);
+ EXPECT_FALSE(a_11_https_left_private < b_10_https_right_private);
+ EXPECT_TRUE(a_11_https_left_private < b_11_https_right_private);
+ EXPECT_FALSE(b_10_https_left_private < a_10_https_right_private);
+ EXPECT_TRUE(b_10_https_left_private < a_11_https_right_private);
+ EXPECT_TRUE(b_10_https_left_private < b_11_https_right_private);
+ EXPECT_FALSE(b_11_https_left_private < a_10_https_right_private);
+ EXPECT_FALSE(b_11_https_left_private < a_11_https_right_private);
+ EXPECT_FALSE(b_11_https_left_private < b_10_https_right_private);
+ }
+}
+
+TEST(QuicServerIdTest, Equals) {
+ PrivacyMode left_privacy;
+ PrivacyMode right_privacy;
+ for (int i = 0; i < 2; i++) {
+ left_privacy = right_privacy = static_cast<PrivacyMode>(i);
+ QuicServerId a_10_https_right_private(HostPortPair("a.com", 10),
+ right_privacy);
+ QuicServerId a_11_https_right_private(HostPortPair("a.com", 11),
+ right_privacy);
+ QuicServerId b_10_https_right_private(HostPortPair("b.com", 10),
+ right_privacy);
+ QuicServerId b_11_https_right_private(HostPortPair("b.com", 11),
+ right_privacy);
+
+ QuicServerId new_a_10_https_left_private(HostPortPair("a.com", 10),
+ left_privacy);
+ QuicServerId new_a_11_https_left_private(HostPortPair("a.com", 11),
+ left_privacy);
+ QuicServerId new_b_10_https_left_private(HostPortPair("b.com", 10),
+ left_privacy);
+ QuicServerId new_b_11_https_left_private(HostPortPair("b.com", 11),
+ left_privacy);
+
+ EXPECT_EQ(new_a_10_https_left_private, a_10_https_right_private);
+ EXPECT_EQ(new_a_11_https_left_private, a_11_https_right_private);
+ EXPECT_EQ(new_b_10_https_left_private, b_10_https_right_private);
+ EXPECT_EQ(new_b_11_https_left_private, b_11_https_right_private);
+ }
+
+ for (int i = 0; i < 2; i++) {
+ right_privacy = static_cast<PrivacyMode>(i);
+ QuicServerId a_10_https_right_private(HostPortPair("a.com", 10),
+ right_privacy);
+ QuicServerId a_11_https_right_private(HostPortPair("a.com", 11),
+ right_privacy);
+ QuicServerId b_10_https_right_private(HostPortPair("b.com", 10),
+ right_privacy);
+ QuicServerId b_11_https_right_private(HostPortPair("b.com", 11),
+ right_privacy);
+
+ QuicServerId new_a_10_https_left_private(HostPortPair("a.com", 10),
+ PRIVACY_MODE_DISABLED);
+
+ EXPECT_FALSE(new_a_10_https_left_private == a_11_https_right_private);
+ EXPECT_FALSE(new_a_10_https_left_private == b_10_https_right_private);
+ EXPECT_FALSE(new_a_10_https_left_private == b_11_https_right_private);
+ }
+ QuicServerId a_10_https_private(HostPortPair("a.com", 10),
+ PRIVACY_MODE_ENABLED);
+ QuicServerId new_a_10_https_no_private(HostPortPair("a.com", 10),
+ PRIVACY_MODE_DISABLED);
+ EXPECT_FALSE(new_a_10_https_no_private == a_10_https_private);
+}
+
+} // namespace
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_server_session_base.cc b/chromium/net/quic/core/quic_server_session_base.cc
new file mode 100644
index 00000000000..419c105042d
--- /dev/null
+++ b/chromium/net/quic/core/quic_server_session_base.cc
@@ -0,0 +1,249 @@
+// 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/quic_server_session_base.h"
+
+#include "base/logging.h"
+#include "net/quic/core/proto/cached_network_parameters.pb.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_spdy_session.h"
+#include "net/quic/core/reliable_quic_stream.h"
+
+using std::string;
+
+namespace net {
+
+QuicServerSessionBase::QuicServerSessionBase(
+ const QuicConfig& config,
+ QuicConnection* connection,
+ Visitor* visitor,
+ QuicCryptoServerStream::Helper* helper,
+ const QuicCryptoServerConfig* crypto_config,
+ QuicCompressedCertsCache* compressed_certs_cache)
+ : QuicSpdySession(connection, config),
+ crypto_config_(crypto_config),
+ compressed_certs_cache_(compressed_certs_cache),
+ visitor_(visitor),
+ helper_(helper),
+ bandwidth_resumption_enabled_(false),
+ bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
+ last_scup_time_(QuicTime::Zero()),
+ last_scup_packet_number_(0) {}
+
+QuicServerSessionBase::~QuicServerSessionBase() {}
+
+void QuicServerSessionBase::Initialize() {
+ crypto_stream_.reset(
+ CreateQuicCryptoServerStream(crypto_config_, compressed_certs_cache_));
+ QuicSpdySession::Initialize();
+}
+
+void QuicServerSessionBase::OnConfigNegotiated() {
+ QuicSpdySession::OnConfigNegotiated();
+
+ if (!config()->HasReceivedConnectionOptions()) {
+ return;
+ }
+
+ // Enable bandwidth resumption if peer sent correct connection options.
+ const bool last_bandwidth_resumption =
+ ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE);
+ const bool max_bandwidth_resumption =
+ ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWMX);
+ bandwidth_resumption_enabled_ =
+ last_bandwidth_resumption || max_bandwidth_resumption;
+
+ if (!FLAGS_quic_enable_server_push_by_default ||
+ connection()->version() < QUIC_VERSION_35) {
+ set_server_push_enabled(
+ ContainsQuicTag(config()->ReceivedConnectionOptions(), kSPSH));
+ }
+
+ // If the client has provided a bandwidth estimate from the same serving
+ // region as this server, then decide whether to use the data for bandwidth
+ // resumption.
+ const CachedNetworkParameters* cached_network_params =
+ crypto_stream_->PreviousCachedNetworkParams();
+ if (cached_network_params != nullptr &&
+ cached_network_params->serving_region() == serving_region_) {
+ // Log the received connection parameters, regardless of how they
+ // get used for bandwidth resumption.
+ connection()->OnReceiveConnectionState(*cached_network_params);
+
+ if (bandwidth_resumption_enabled_) {
+ // Only do bandwidth resumption if estimate is recent enough.
+ const int64_t seconds_since_estimate =
+ connection()->clock()->WallNow().ToUNIXSeconds() -
+ cached_network_params->timestamp();
+ if (seconds_since_estimate <= kNumSecondsPerHour) {
+ connection()->ResumeConnectionState(*cached_network_params,
+ max_bandwidth_resumption);
+ }
+ }
+ }
+}
+
+void QuicServerSessionBase::OnConnectionClosed(QuicErrorCode error,
+ const string& error_details,
+ ConnectionCloseSource source) {
+ QuicSession::OnConnectionClosed(error, error_details, source);
+ // In the unlikely event we get a connection close while doing an asynchronous
+ // crypto event, make sure we cancel the callback.
+ if (crypto_stream_.get() != nullptr) {
+ crypto_stream_->CancelOutstandingCallbacks();
+ }
+ visitor_->OnConnectionClosed(connection()->connection_id(), error,
+ error_details);
+}
+
+void QuicServerSessionBase::OnWriteBlocked() {
+ QuicSession::OnWriteBlocked();
+ visitor_->OnWriteBlocked(connection());
+}
+
+void QuicServerSessionBase::OnCongestionWindowChange(QuicTime now) {
+ if (!bandwidth_resumption_enabled_) {
+ return;
+ }
+ // Only send updates when the application has no data to write.
+ if (HasDataToWrite()) {
+ return;
+ }
+
+ // If not enough time has passed since the last time we sent an update to the
+ // client, or not enough packets have been sent, then return early.
+ const QuicSentPacketManagerInterface& sent_packet_manager =
+ connection()->sent_packet_manager();
+ int64_t srtt_ms =
+ sent_packet_manager.GetRttStats()->smoothed_rtt().ToMilliseconds();
+ int64_t now_ms = (now - last_scup_time_).ToMilliseconds();
+ int64_t packets_since_last_scup =
+ connection()->packet_number_of_last_sent_packet() -
+ last_scup_packet_number_;
+ if (now_ms < (kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms) ||
+ now_ms < kMinIntervalBetweenServerConfigUpdatesMs ||
+ packets_since_last_scup < kMinPacketsBetweenServerConfigUpdates) {
+ return;
+ }
+
+ // If the bandwidth recorder does not have a valid estimate, return early.
+ const QuicSustainedBandwidthRecorder* bandwidth_recorder =
+ sent_packet_manager.SustainedBandwidthRecorder();
+ if (bandwidth_recorder == nullptr || !bandwidth_recorder->HasEstimate()) {
+ return;
+ }
+
+ // The bandwidth recorder has recorded at least one sustained bandwidth
+ // estimate. Check that it's substantially different from the last one that
+ // we sent to the client, and if so, send the new one.
+ QuicBandwidth new_bandwidth_estimate =
+ bandwidth_recorder->BandwidthEstimate();
+
+ int64_t bandwidth_delta =
+ std::abs(new_bandwidth_estimate.ToBitsPerSecond() -
+ bandwidth_estimate_sent_to_client_.ToBitsPerSecond());
+
+ // Define "substantial" difference as a 50% increase or decrease from the
+ // last estimate.
+ bool substantial_difference =
+ bandwidth_delta >
+ 0.5 * bandwidth_estimate_sent_to_client_.ToBitsPerSecond();
+ if (!substantial_difference) {
+ return;
+ }
+
+ bandwidth_estimate_sent_to_client_ = new_bandwidth_estimate;
+ DVLOG(1) << "Server: sending new bandwidth estimate (KBytes/s): "
+ << bandwidth_estimate_sent_to_client_.ToKBytesPerSecond();
+
+ // Include max bandwidth in the update.
+ QuicBandwidth max_bandwidth_estimate =
+ bandwidth_recorder->MaxBandwidthEstimate();
+ int32_t max_bandwidth_timestamp = bandwidth_recorder->MaxBandwidthTimestamp();
+
+ // Fill the proto before passing it to the crypto stream to send.
+ const int32_t bw_estimate_bytes_per_second =
+ BandwidthToCachedParameterBytesPerSecond(
+ bandwidth_estimate_sent_to_client_);
+ const int32_t max_bw_estimate_bytes_per_second =
+ BandwidthToCachedParameterBytesPerSecond(max_bandwidth_estimate);
+ QUIC_BUG_IF(max_bw_estimate_bytes_per_second < 0)
+ << max_bw_estimate_bytes_per_second;
+ QUIC_BUG_IF(bw_estimate_bytes_per_second < 0) << bw_estimate_bytes_per_second;
+
+ CachedNetworkParameters cached_network_params;
+ cached_network_params.set_bandwidth_estimate_bytes_per_second(
+ bw_estimate_bytes_per_second);
+ cached_network_params.set_max_bandwidth_estimate_bytes_per_second(
+ max_bw_estimate_bytes_per_second);
+ cached_network_params.set_max_bandwidth_timestamp_seconds(
+ max_bandwidth_timestamp);
+ cached_network_params.set_min_rtt_ms(
+ sent_packet_manager.GetRttStats()->min_rtt().ToMilliseconds());
+ cached_network_params.set_previous_connection_state(
+ bandwidth_recorder->EstimateRecordedDuringSlowStart()
+ ? CachedNetworkParameters::SLOW_START
+ : CachedNetworkParameters::CONGESTION_AVOIDANCE);
+ cached_network_params.set_timestamp(
+ connection()->clock()->WallNow().ToUNIXSeconds());
+ if (!serving_region_.empty()) {
+ cached_network_params.set_serving_region(serving_region_);
+ }
+
+ crypto_stream_->SendServerConfigUpdate(&cached_network_params);
+
+ connection()->OnSendConnectionState(cached_network_params);
+
+ last_scup_time_ = now;
+ last_scup_packet_number_ = connection()->packet_number_of_last_sent_packet();
+}
+
+bool QuicServerSessionBase::ShouldCreateIncomingDynamicStream(QuicStreamId id) {
+ if (!connection()->connected()) {
+ QUIC_BUG << "ShouldCreateIncomingDynamicStream called when disconnected";
+ return false;
+ }
+
+ if (id % 2 == 0) {
+ DVLOG(1) << "Invalid incoming even stream_id:" << id;
+ connection()->CloseConnection(
+ QUIC_INVALID_STREAM_ID, "Client created even numbered stream",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+ return true;
+}
+
+bool QuicServerSessionBase::ShouldCreateOutgoingDynamicStream() {
+ if (!connection()->connected()) {
+ QUIC_BUG << "ShouldCreateOutgoingDynamicStream called when disconnected";
+ return false;
+ }
+ if (!crypto_stream_->encryption_established()) {
+ QUIC_BUG << "Encryption not established so no outgoing stream created.";
+ return false;
+ }
+ if (GetNumOpenOutgoingStreams() >= max_open_outgoing_streams()) {
+ VLOG(1) << "No more streams should be created. "
+ << "Already " << GetNumOpenOutgoingStreams() << " open.";
+ return false;
+ }
+ return true;
+}
+
+QuicCryptoServerStreamBase* QuicServerSessionBase::GetCryptoStream() {
+ return crypto_stream_.get();
+}
+
+int32_t QuicServerSessionBase::BandwidthToCachedParameterBytesPerSecond(
+ const QuicBandwidth& bandwidth) {
+ int64_t bytes_per_second = bandwidth.ToBytesPerSecond();
+ return (bytes_per_second > static_cast<int64_t>(INT32_MAX)
+ ? INT32_MAX
+ : static_cast<int32_t>(bytes_per_second));
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_server_session_base.h b/chromium/net/quic/core/quic_server_session_base.h
new file mode 100644
index 00000000000..46ad626286d
--- /dev/null
+++ b/chromium/net/quic/core/quic_server_session_base.h
@@ -0,0 +1,168 @@
+// 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.
+//
+// A server specific QuicSession subclass.
+
+#ifndef NET_QUIC_QUIC_SERVER_SESSION_BASE_H_
+#define NET_QUIC_QUIC_SERVER_SESSION_BASE_H_
+
+#include <stdint.h>
+
+#include <cstdint>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/crypto/quic_compressed_certs_cache.h"
+#include "net/quic/core/quic_crypto_server_stream.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_spdy_session.h"
+
+namespace net {
+
+class QuicBlockedWriterInterface;
+class QuicConfig;
+class QuicConnection;
+class QuicCryptoServerConfig;
+class ReliableQuicStream;
+
+namespace test {
+class QuicServerSessionBasePeer;
+class QuicSimpleServerSessionPeer;
+} // namespace test
+
+class NET_EXPORT_PRIVATE QuicServerSessionBase : public QuicSpdySession {
+ public:
+ // An interface from the session to the entity owning the session.
+ // This lets the session notify its owner (the Dispatcher) when the connection
+ // is closed, blocked, or added/removed from the time-wait std::list.
+ class Visitor {
+ public:
+ virtual ~Visitor() {}
+
+ // Called when the connection is closed.
+ virtual void OnConnectionClosed(QuicConnectionId connection_id,
+ QuicErrorCode error,
+ const std::string& error_details) = 0;
+
+ // Called when the session has become write blocked.
+ virtual void OnWriteBlocked(QuicBlockedWriterInterface* blocked_writer) = 0;
+
+ // Called after the given connection is added to the time-wait std::list.
+ virtual void OnConnectionAddedToTimeWaitList(
+ QuicConnectionId connection_id) = 0;
+
+ // Called before a packet is going to be processed by |session|.
+ virtual void OnPacketBeingDispatchedToSession(
+ QuicServerSessionBase* session) = 0;
+ };
+
+ // Does not take ownership of |connection|. |crypto_config| must outlive the
+ // session. |helper| must outlive any created crypto streams.
+ QuicServerSessionBase(const QuicConfig& config,
+ QuicConnection* connection,
+ Visitor* visitor,
+ QuicCryptoServerStream::Helper* helper,
+ const QuicCryptoServerConfig* crypto_config,
+ QuicCompressedCertsCache* compressed_certs_cache);
+
+ // Override the base class to notify the owner of the connection close.
+ void OnConnectionClosed(QuicErrorCode error,
+ const std::string& error_details,
+ ConnectionCloseSource source) override;
+ void OnWriteBlocked() override;
+
+ // Sends a server config update to the client, containing new bandwidth
+ // estimate.
+ void OnCongestionWindowChange(QuicTime now) override;
+
+ ~QuicServerSessionBase() override;
+
+ void Initialize() override;
+
+ const QuicCryptoServerStreamBase* crypto_stream() const {
+ return crypto_stream_.get();
+ }
+
+ // Override base class to process bandwidth related config received from
+ // client.
+ void OnConfigNegotiated() override;
+
+ void set_serving_region(const std::string& serving_region) {
+ serving_region_ = serving_region;
+ }
+
+ protected:
+ // QuicSession methods(override them with return type of QuicSpdyStream*):
+ QuicCryptoServerStreamBase* GetCryptoStream() override;
+
+ // If an outgoing stream can be created, return true.
+ // Return false when connection is closed or forward secure encryption hasn't
+ // established yet or number of server initiated streams already reaches the
+ // upper limit.
+ bool ShouldCreateOutgoingDynamicStream() override;
+
+ // If we should create an incoming stream, returns true. Otherwise
+ // does error handling, including communicating the error to the client and
+ // possibly closing the connection, and returns false.
+ bool ShouldCreateIncomingDynamicStream(QuicStreamId id) override;
+
+ virtual QuicCryptoServerStreamBase* CreateQuicCryptoServerStream(
+ const QuicCryptoServerConfig* crypto_config,
+ QuicCompressedCertsCache* compressed_certs_cache) = 0;
+
+ const QuicCryptoServerConfig* crypto_config() { return crypto_config_; }
+
+ Visitor* visitor() { return visitor_; }
+
+ QuicCryptoServerStream::Helper* stream_helper() { return helper_; }
+
+ private:
+ friend class test::QuicServerSessionBasePeer;
+ friend class test::QuicSimpleServerSessionPeer;
+
+ const QuicCryptoServerConfig* crypto_config_;
+
+ // The cache which contains most recently compressed certs.
+ // Owned by QuicDispatcher.
+ QuicCompressedCertsCache* compressed_certs_cache_;
+
+ std::unique_ptr<QuicCryptoServerStreamBase> crypto_stream_;
+ Visitor* visitor_;
+
+ // Pointer to the helper used to create crypto server streams. Must outlive
+ // streams created via CreateQuicCryptoServerStream.
+ QuicCryptoServerStream::Helper* helper_;
+
+ // Whether bandwidth resumption is enabled for this connection.
+ bool bandwidth_resumption_enabled_;
+
+ // The most recent bandwidth estimate sent to the client.
+ QuicBandwidth bandwidth_estimate_sent_to_client_;
+
+ // Text describing server location. Sent to the client as part of the bandwith
+ // estimate in the source-address token. Optional, can be left empty.
+ std::string serving_region_;
+
+ // Time at which we send the last SCUP to the client.
+ QuicTime last_scup_time_;
+
+ // Number of packets sent to the peer, at the time we last sent a SCUP.
+ int64_t last_scup_packet_number_;
+
+ // Converts QuicBandwidth to an int32 bytes/second that can be
+ // stored in CachedNetworkParameters. TODO(jokulik): This function
+ // should go away once we fix http://b//27897982
+ int32_t BandwidthToCachedParameterBytesPerSecond(
+ const QuicBandwidth& bandwidth);
+
+ DISALLOW_COPY_AND_ASSIGN(QuicServerSessionBase);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_SERVER_SESSION_BASE_H_
diff --git a/chromium/net/quic/core/quic_server_session_base_test.cc b/chromium/net/quic/core/quic_server_session_base_test.cc
new file mode 100644
index 00000000000..77ba4e2cbac
--- /dev/null
+++ b/chromium/net/quic/core/quic_server_session_base_test.cc
@@ -0,0 +1,577 @@
+// Copyright 2013 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/quic_server_session_base.h"
+
+#include <cstdint>
+#include <memory>
+
+#include "base/macros.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/proto/cached_network_parameters.pb.h"
+#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/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/quic_config_peer.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
+#include "net/quic/test_tools/quic_session_peer.h"
+#include "net/quic/test_tools/quic_spdy_session_peer.h"
+#include "net/quic/test_tools/quic_spdy_stream_peer.h"
+#include "net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/test/gtest_util.h"
+#include "net/tools/quic/quic_simple_server_stream.h"
+#include "net/tools/quic/test_tools/mock_quic_server_session_visitor.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using net::test::CryptoTestUtils;
+using net::test::MockQuicConnection;
+using net::test::MockQuicConnectionHelper;
+using net::test::QuicConfigPeer;
+using net::test::QuicConnectionPeer;
+using net::test::QuicSpdyStreamPeer;
+using net::test::QuicSentPacketManagerPeer;
+using net::test::QuicSessionPeer;
+using net::test::QuicSpdySessionPeer;
+using net::test::QuicSustainedBandwidthRecorderPeer;
+using net::test::SupportedVersions;
+using net::test::kClientDataStreamId1;
+using net::test::kClientDataStreamId2;
+using net::test::kClientDataStreamId3;
+using net::test::kInitialSessionFlowControlWindowForTest;
+using net::test::kInitialStreamFlowControlWindowForTest;
+using std::string;
+using testing::StrictMock;
+using testing::_;
+
+namespace net {
+namespace test {
+
+class QuicServerSessionBasePeer {
+ public:
+ static ReliableQuicStream* GetOrCreateDynamicStream(QuicServerSessionBase* s,
+ QuicStreamId id) {
+ return s->GetOrCreateDynamicStream(id);
+ }
+ static void SetCryptoStream(QuicServerSessionBase* s,
+ QuicCryptoServerStream* crypto_stream) {
+ s->crypto_stream_.reset(crypto_stream);
+ s->static_streams()[kCryptoStreamId] = crypto_stream;
+ }
+ static bool IsBandwidthResumptionEnabled(QuicServerSessionBase* s) {
+ return s->bandwidth_resumption_enabled_;
+ }
+};
+
+namespace {
+
+class TestServerSession : public QuicServerSessionBase {
+ public:
+ TestServerSession(const QuicConfig& config,
+ QuicConnection* connection,
+ QuicServerSessionBase::Visitor* visitor,
+ QuicCryptoServerStream::Helper* helper,
+ const QuicCryptoServerConfig* crypto_config,
+ QuicCompressedCertsCache* compressed_certs_cache)
+ : QuicServerSessionBase(config,
+ connection,
+ visitor,
+ helper,
+ crypto_config,
+ compressed_certs_cache) {}
+
+ ~TestServerSession() override { delete connection(); };
+
+ protected:
+ QuicSpdyStream* CreateIncomingDynamicStream(QuicStreamId id) override {
+ if (!ShouldCreateIncomingDynamicStream(id)) {
+ return nullptr;
+ }
+ QuicSpdyStream* stream = new QuicSimpleServerStream(id, this);
+ ActivateStream(stream);
+ return stream;
+ }
+
+ QuicSpdyStream* CreateOutgoingDynamicStream(SpdyPriority priority) override {
+ if (!ShouldCreateOutgoingDynamicStream()) {
+ return nullptr;
+ }
+
+ QuicSpdyStream* stream =
+ new QuicSimpleServerStream(GetNextOutgoingStreamId(), this);
+ stream->SetPriority(priority);
+ ActivateStream(stream);
+ return stream;
+ }
+
+ QuicCryptoServerStreamBase* CreateQuicCryptoServerStream(
+ const QuicCryptoServerConfig* crypto_config,
+ QuicCompressedCertsCache* compressed_certs_cache) override {
+ return new QuicCryptoServerStream(
+ crypto_config, compressed_certs_cache,
+ FLAGS_enable_quic_stateless_reject_support, this, stream_helper());
+ }
+};
+
+const size_t kMaxStreamsForTest = 10;
+
+class QuicServerSessionBaseTest : public ::testing::TestWithParam<QuicVersion> {
+ protected:
+ QuicServerSessionBaseTest()
+ : crypto_config_(QuicCryptoServerConfig::TESTING,
+ QuicRandom::GetInstance(),
+ CryptoTestUtils::ProofSourceForTesting()),
+ compressed_certs_cache_(
+ QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) {
+ config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, kMaxStreamsForTest);
+ config_.SetMaxIncomingDynamicStreamsToSend(kMaxStreamsForTest);
+ QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams(&config_,
+ kMaxStreamsForTest);
+ config_.SetInitialStreamFlowControlWindowToSend(
+ kInitialStreamFlowControlWindowForTest);
+ config_.SetInitialSessionFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+
+ connection_ = new StrictMock<MockQuicConnection>(
+ &helper_, &alarm_factory_, Perspective::IS_SERVER,
+ SupportedVersions(GetParam()));
+ session_.reset(new TestServerSession(config_, connection_, &owner_,
+ &stream_helper_, &crypto_config_,
+ &compressed_certs_cache_));
+ MockClock clock;
+ handshake_message_.reset(crypto_config_.AddDefaultConfig(
+ QuicRandom::GetInstance(), &clock,
+ QuicCryptoServerConfig::ConfigOptions()));
+ session_->Initialize();
+ visitor_ = QuicConnectionPeer::GetVisitor(connection_);
+ }
+
+ StrictMock<MockQuicServerSessionVisitor> owner_;
+ StrictMock<MockQuicCryptoServerStreamHelper> stream_helper_;
+ MockQuicConnectionHelper helper_;
+ MockAlarmFactory alarm_factory_;
+ StrictMock<MockQuicConnection>* connection_;
+ QuicConfig config_;
+ QuicCryptoServerConfig crypto_config_;
+ QuicCompressedCertsCache compressed_certs_cache_;
+ std::unique_ptr<TestServerSession> session_;
+ std::unique_ptr<CryptoHandshakeMessage> handshake_message_;
+ QuicConnectionVisitorInterface* visitor_;
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+};
+
+// Compares CachedNetworkParameters.
+MATCHER_P(EqualsProto, network_params, "") {
+ CachedNetworkParameters reference(network_params);
+ return (arg->bandwidth_estimate_bytes_per_second() ==
+ reference.bandwidth_estimate_bytes_per_second() &&
+ arg->bandwidth_estimate_bytes_per_second() ==
+ reference.bandwidth_estimate_bytes_per_second() &&
+ arg->max_bandwidth_estimate_bytes_per_second() ==
+ reference.max_bandwidth_estimate_bytes_per_second() &&
+ arg->max_bandwidth_timestamp_seconds() ==
+ reference.max_bandwidth_timestamp_seconds() &&
+ arg->min_rtt_ms() == reference.min_rtt_ms() &&
+ arg->previous_connection_state() ==
+ reference.previous_connection_state());
+}
+
+INSTANTIATE_TEST_CASE_P(Tests,
+ QuicServerSessionBaseTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
+
+TEST_P(QuicServerSessionBaseTest, ServerPushDisabledByDefault) {
+ FLAGS_quic_enable_server_push_by_default = true;
+ // Without the client explicitly sending kSPSH, server push will be disabled
+ // at the server, until version 35 when it is enabled by default.
+ EXPECT_FALSE(
+ session_->config()->HasReceivedConnectionOptions() &&
+ ContainsQuicTag(session_->config()->ReceivedConnectionOptions(), kSPSH));
+ session_->OnConfigNegotiated();
+ if (GetParam() <= QUIC_VERSION_34) {
+ EXPECT_FALSE(session_->server_push_enabled());
+ } else {
+ EXPECT_TRUE(session_->server_push_enabled());
+ }
+}
+
+TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) {
+ // Open a stream, then reset it.
+ // Send two bytes of payload to open it.
+ QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT"));
+ session_->OnStreamFrame(data1);
+ EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
+
+ // Send a reset (and expect the peer to send a RST in response).
+ QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM,
+ 0);
+ EXPECT_CALL(*connection_,
+ SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0));
+ visitor_->OnRstStream(rst1);
+ EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
+
+ // Send the same two bytes of payload in a new packet.
+ visitor_->OnStreamFrame(data1);
+
+ // The stream should not be re-opened.
+ EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
+ EXPECT_TRUE(connection_->connected());
+}
+
+TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) {
+ // Send a reset (and expect the peer to send a RST in response).
+ QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM,
+ 0);
+ EXPECT_CALL(*connection_,
+ SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0));
+ visitor_->OnRstStream(rst1);
+ EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
+
+ // Send two bytes of payload.
+ QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT"));
+ visitor_->OnStreamFrame(data1);
+
+ // The stream should never be opened, now that the reset is received.
+ EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
+ EXPECT_TRUE(connection_->connected());
+}
+
+TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) {
+ // Send (empty) compressed headers followed by two bytes of data.
+ QuicStreamFrame frame1(kClientDataStreamId1, false, 0,
+ StringPiece("\1\0\0\0\0\0\0\0HT"));
+ QuicStreamFrame frame2(kClientDataStreamId2, false, 0,
+ StringPiece("\2\0\0\0\0\0\0\0HT"));
+ visitor_->OnStreamFrame(frame1);
+ visitor_->OnStreamFrame(frame2);
+ EXPECT_EQ(2u, session_->GetNumOpenIncomingStreams());
+
+ // Send a reset (and expect the peer to send a RST in response).
+ QuicRstStreamFrame rst(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM, 0);
+ EXPECT_CALL(*connection_,
+ SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0));
+ visitor_->OnRstStream(rst);
+
+ // If we were tracking, we'd probably want to reject this because it's data
+ // past the reset point of stream 3. As it's a closed stream we just drop the
+ // data on the floor, but accept the packet because it has data for stream 5.
+ QuicStreamFrame frame3(kClientDataStreamId1, false, 2, StringPiece("TP"));
+ QuicStreamFrame frame4(kClientDataStreamId2, false, 2, StringPiece("TP"));
+ visitor_->OnStreamFrame(frame3);
+ visitor_->OnStreamFrame(frame4);
+ // The stream should never be opened, now that the reset is received.
+ EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
+ EXPECT_TRUE(connection_->connected());
+}
+
+TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) {
+ // Test that the server refuses if a client attempts to open too many data
+ // streams. The server accepts slightly more than the negotiated stream limit
+ // to deal with rare cases where a client FIN/RST is lost.
+
+ if (GetParam() <= QUIC_VERSION_34) {
+ EXPECT_EQ(kMaxStreamsForTest, session_->max_open_incoming_streams());
+ }
+
+ // The slightly increased stream limit is set during config negotiation. It
+ // is either an increase of 10 over negotiated limit, or a fixed percentage
+ // scaling, whichever is larger. Test both before continuing.
+ session_->OnConfigNegotiated();
+ EXPECT_LT(kMaxStreamsMultiplier * kMaxStreamsForTest,
+ kMaxStreamsForTest + kMaxStreamsMinimumIncrement);
+ EXPECT_EQ(kMaxStreamsForTest + kMaxStreamsMinimumIncrement,
+ session_->max_open_incoming_streams());
+ EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
+ QuicStreamId stream_id = kClientDataStreamId1;
+ // Open the max configured number of streams, should be no problem.
+ for (size_t i = 0; i < kMaxStreamsForTest; ++i) {
+ EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
+ session_.get(), stream_id));
+ stream_id += 2;
+ }
+
+ // Open more streams: server should accept slightly more than the limit.
+ for (size_t i = 0; i < kMaxStreamsMinimumIncrement; ++i) {
+ EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
+ session_.get(), stream_id));
+ stream_id += 2;
+ }
+
+ // Now violate the server's internal stream limit.
+ stream_id += 2;
+ EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
+ EXPECT_CALL(*connection_, SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0));
+ // Even if the connection remains open, the stream creation should fail.
+ EXPECT_FALSE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
+ session_.get(), stream_id));
+}
+
+TEST_P(QuicServerSessionBaseTest, MaxAvailableStreams) {
+ // Test that the server closes the connection if a client makes too many data
+ // streams available. The server accepts slightly more than the negotiated
+ // stream limit to deal with rare cases where a client FIN/RST is lost.
+
+ if (GetParam() <= QUIC_VERSION_34) {
+ // The slightly increased stream limit is set during config negotiation.
+ EXPECT_EQ(kMaxStreamsForTest, session_->max_open_incoming_streams());
+ }
+ session_->OnConfigNegotiated();
+ const size_t kAvailableStreamLimit = session_->MaxAvailableStreams();
+ EXPECT_EQ(
+ session_->max_open_incoming_streams() * kMaxAvailableStreamsMultiplier,
+ session_->MaxAvailableStreams());
+ // The protocol specification requires that there can be at least 10 times
+ // as many available streams as the connection's maximum open streams.
+ EXPECT_LE(10 * kMaxStreamsForTest, kAvailableStreamLimit);
+
+ EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
+ EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
+ session_.get(), kClientDataStreamId1));
+
+ // Establish available streams up to the server's limit.
+ const int kLimitingStreamId =
+ kClientDataStreamId1 + (kAvailableStreamLimit)*2 + 2;
+ EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
+ session_.get(), kLimitingStreamId));
+
+ // A further available stream will result in connection close.
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_TOO_MANY_AVAILABLE_STREAMS, _, _));
+ // This forces stream kLimitingStreamId + 2 to become available, which
+ // violates the quota.
+ EXPECT_FALSE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
+ session_.get(), kLimitingStreamId + 4));
+}
+
+// TODO(ckrasic): remove this when
+// FLAGS_quic_enable_server_push_by_default is
+// deprecated.
+TEST_P(QuicServerSessionBaseTest, EnableServerPushThroughConnectionOption) {
+ FLAGS_quic_enable_server_push_by_default = false;
+ // Assume server received server push connection option.
+ QuicTagVector copt;
+ copt.push_back(kSPSH);
+ QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
+ session_->OnConfigNegotiated();
+ EXPECT_TRUE(session_->server_push_enabled());
+}
+
+TEST_P(QuicServerSessionBaseTest, GetEvenIncomingError) {
+ // Incoming streams on the server session must be odd.
+ EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _));
+ EXPECT_EQ(nullptr, QuicServerSessionBasePeer::GetOrCreateDynamicStream(
+ session_.get(), 4));
+}
+
+TEST_P(QuicServerSessionBaseTest, GetStreamDisconnected) {
+ // Don't create new streams if the connection is disconnected.
+ QuicConnectionPeer::TearDownLocalConnectionState(connection_);
+ EXPECT_QUIC_BUG(
+ QuicServerSessionBasePeer::GetOrCreateDynamicStream(session_.get(), 5),
+ "ShouldCreateIncomingDynamicStream called when disconnected");
+}
+
+class MockQuicCryptoServerStream : public QuicCryptoServerStream {
+ public:
+ explicit MockQuicCryptoServerStream(
+ const QuicCryptoServerConfig* crypto_config,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ QuicServerSessionBase* session,
+ QuicCryptoServerStream::Helper* helper)
+ : QuicCryptoServerStream(crypto_config,
+ compressed_certs_cache,
+ FLAGS_enable_quic_stateless_reject_support,
+ session,
+ helper) {}
+ ~MockQuicCryptoServerStream() override {}
+
+ MOCK_METHOD1(SendServerConfigUpdate,
+ void(const CachedNetworkParameters* cached_network_parameters));
+
+ void set_encryption_established(bool has_established) {
+ encryption_established_ = has_established;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockQuicCryptoServerStream);
+};
+
+TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) {
+ // Test that bandwidth estimate updates are sent to the client, only when
+ // bandwidth resumption is enabled, the bandwidth estimate has changed
+ // sufficiently, enough time has passed,
+ // and we don't have any other data to write.
+
+ // Client has sent kBWRE connection option to trigger bandwidth resumption.
+ // Disable this flag because if connection uses multipath sent packet manager,
+ // static_cast here does not work.
+ QuicTagVector copt;
+ copt.push_back(kBWRE);
+ QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
+ session_->OnConfigNegotiated();
+ EXPECT_TRUE(
+ QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
+
+ int32_t bandwidth_estimate_kbytes_per_second = 123;
+ int32_t max_bandwidth_estimate_kbytes_per_second = 134;
+ int32_t max_bandwidth_estimate_timestamp = 1122334455;
+ const string serving_region = "not a real region";
+ session_->set_serving_region(serving_region);
+
+ MockQuicCryptoServerStream* crypto_stream =
+ new MockQuicCryptoServerStream(&crypto_config_, &compressed_certs_cache_,
+ session_.get(), &stream_helper_);
+ QuicServerSessionBasePeer::SetCryptoStream(session_.get(), crypto_stream);
+
+ // Set some initial bandwidth values.
+ QuicSentPacketManager* sent_packet_manager =
+ QuicConnectionPeer::GetSentPacketManager(session_->connection(),
+ kDefaultPathId);
+ QuicSustainedBandwidthRecorder& bandwidth_recorder =
+ QuicSentPacketManagerPeer::GetBandwidthRecorder(sent_packet_manager);
+ // Seed an rtt measurement equal to the initial default rtt.
+ RttStats* rtt_stats =
+ const_cast<RttStats*>(sent_packet_manager->GetRttStats());
+ rtt_stats->UpdateRtt(
+ QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us()),
+ QuicTime::Delta::Zero(), QuicTime::Zero());
+ QuicSustainedBandwidthRecorderPeer::SetBandwidthEstimate(
+ &bandwidth_recorder, bandwidth_estimate_kbytes_per_second);
+ QuicSustainedBandwidthRecorderPeer::SetMaxBandwidthEstimate(
+ &bandwidth_recorder, max_bandwidth_estimate_kbytes_per_second,
+ max_bandwidth_estimate_timestamp);
+ // Queue up some pending data.
+ session_->MarkConnectionLevelWriteBlocked(kCryptoStreamId);
+ EXPECT_TRUE(session_->HasDataToWrite());
+
+ // There will be no update sent yet - not enough time has passed.
+ QuicTime now = QuicTime::Zero();
+ session_->OnCongestionWindowChange(now);
+
+ // Bandwidth estimate has now changed sufficiently but not enough time has
+ // passed to send a Server Config Update.
+ bandwidth_estimate_kbytes_per_second =
+ bandwidth_estimate_kbytes_per_second * 1.6;
+ session_->OnCongestionWindowChange(now);
+
+ // Bandwidth estimate has now changed sufficiently and enough time has passed,
+ // but not enough packets have been sent.
+ int64_t srtt_ms =
+ sent_packet_manager->GetRttStats()->smoothed_rtt().ToMilliseconds();
+ now = now + QuicTime::Delta::FromMilliseconds(
+ kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms);
+ session_->OnCongestionWindowChange(now);
+
+ // The connection no longer has pending data to be written.
+ session_->OnCanWrite();
+ EXPECT_FALSE(session_->HasDataToWrite());
+ session_->OnCongestionWindowChange(now);
+
+ // Bandwidth estimate has now changed sufficiently, enough time has passed,
+ // and enough packets have been sent.
+ QuicConnectionPeer::SetPacketNumberOfLastSentPacket(
+ session_->connection(), kMinPacketsBetweenServerConfigUpdates);
+
+ // Verify that the proto has exactly the values we expect.
+ CachedNetworkParameters expected_network_params;
+ expected_network_params.set_bandwidth_estimate_bytes_per_second(
+ bandwidth_recorder.BandwidthEstimate().ToBytesPerSecond());
+ expected_network_params.set_max_bandwidth_estimate_bytes_per_second(
+ bandwidth_recorder.MaxBandwidthEstimate().ToBytesPerSecond());
+ expected_network_params.set_max_bandwidth_timestamp_seconds(
+ bandwidth_recorder.MaxBandwidthTimestamp());
+ expected_network_params.set_min_rtt_ms(session_->connection()
+ ->sent_packet_manager()
+ .GetRttStats()
+ ->min_rtt()
+ .ToMilliseconds());
+ expected_network_params.set_previous_connection_state(
+ CachedNetworkParameters::CONGESTION_AVOIDANCE);
+ expected_network_params.set_timestamp(
+ session_->connection()->clock()->WallNow().ToUNIXSeconds());
+ expected_network_params.set_serving_region(serving_region);
+
+ EXPECT_CALL(*crypto_stream,
+ SendServerConfigUpdate(EqualsProto(expected_network_params)))
+ .Times(1);
+ EXPECT_CALL(*connection_, OnSendConnectionState(_)).Times(1);
+ session_->OnCongestionWindowChange(now);
+}
+
+TEST_P(QuicServerSessionBaseTest, BandwidthResumptionExperiment) {
+ // Test that if a client provides a CachedNetworkParameters with the same
+ // serving region as the current server, and which was made within an hour of
+ // now, that this data is passed down to the send algorithm.
+
+ // Client has sent kBWRE connection option to trigger bandwidth resumption.
+ QuicTagVector copt;
+ copt.push_back(kBWRE);
+ QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
+
+ const string kTestServingRegion = "a serving region";
+ session_->set_serving_region(kTestServingRegion);
+
+ // Set the time to be one hour + one second from the 0 baseline.
+ connection_->AdvanceTime(
+ QuicTime::Delta::FromSeconds(kNumSecondsPerHour + 1));
+
+ QuicCryptoServerStream* crypto_stream = static_cast<QuicCryptoServerStream*>(
+ QuicSessionPeer::GetCryptoStream(session_.get()));
+
+ // No effect if no CachedNetworkParameters provided.
+ EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(0);
+ session_->OnConfigNegotiated();
+
+ // No effect if CachedNetworkParameters provided, but different serving
+ // regions.
+ CachedNetworkParameters cached_network_params;
+ cached_network_params.set_bandwidth_estimate_bytes_per_second(1);
+ cached_network_params.set_serving_region("different serving region");
+ crypto_stream->SetPreviousCachedNetworkParams(cached_network_params);
+ EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(0);
+ session_->OnConfigNegotiated();
+
+ // Same serving region, but timestamp is too old, should have no effect.
+ cached_network_params.set_serving_region(kTestServingRegion);
+ cached_network_params.set_timestamp(0);
+ crypto_stream->SetPreviousCachedNetworkParams(cached_network_params);
+ EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(0);
+ session_->OnConfigNegotiated();
+
+ // Same serving region, and timestamp is recent: estimate is stored.
+ cached_network_params.set_timestamp(
+ connection_->clock()->WallNow().ToUNIXSeconds());
+ crypto_stream->SetPreviousCachedNetworkParams(cached_network_params);
+ EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(1);
+ session_->OnConfigNegotiated();
+}
+
+TEST_P(QuicServerSessionBaseTest, BandwidthMaxEnablesResumption) {
+ EXPECT_FALSE(
+ QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
+
+ // Client has sent kBWMX connection option to trigger bandwidth resumption.
+ QuicTagVector copt;
+ copt.push_back(kBWMX);
+ QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
+ session_->OnConfigNegotiated();
+ EXPECT_TRUE(
+ QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
+}
+
+TEST_P(QuicServerSessionBaseTest, NoBandwidthResumptionByDefault) {
+ EXPECT_FALSE(
+ QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
+ session_->OnConfigNegotiated();
+ EXPECT_FALSE(
+ QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_session.cc b/chromium/net/quic/core/quic_session.cc
new file mode 100644
index 00000000000..b125fc7c798
--- /dev/null
+++ b/chromium/net/quic/core/quic_session.cc
@@ -0,0 +1,778 @@
+// 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/quic_session.h"
+
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "net/quic/core/crypto/proof_verifier.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_flow_controller.h"
+#include "net/ssl/ssl_info.h"
+
+using base::IntToString;
+using base::StringPiece;
+using std::make_pair;
+using std::map;
+using std::max;
+using std::string;
+using std::vector;
+using net::SpdyPriority;
+
+namespace net {
+
+#define ENDPOINT \
+ (perspective() == Perspective::IS_SERVER ? "Server: " : " Client: ")
+
+QuicSession::QuicSession(QuicConnection* connection, const QuicConfig& config)
+ : connection_(connection),
+ config_(config),
+ max_open_outgoing_streams_(kDefaultMaxStreamsPerConnection),
+ max_open_incoming_streams_(config_.GetMaxIncomingDynamicStreamsToSend()),
+ next_outgoing_stream_id_(perspective() == Perspective::IS_SERVER ? 2 : 3),
+ largest_peer_created_stream_id_(
+ perspective() == Perspective::IS_SERVER ? 1 : 0),
+ num_dynamic_incoming_streams_(0),
+ num_draining_incoming_streams_(0),
+ num_locally_closed_incoming_streams_highest_offset_(0),
+ error_(QUIC_NO_ERROR),
+ flow_controller_(connection_,
+ 0,
+ perspective(),
+ kMinimumFlowControlSendWindow,
+ config_.GetInitialSessionFlowControlWindowToSend(),
+ perspective() == Perspective::IS_SERVER),
+ currently_writing_stream_id_(0) {}
+
+void QuicSession::Initialize() {
+ connection_->set_visitor(this);
+ connection_->SetFromConfig(config_);
+
+ DCHECK_EQ(kCryptoStreamId, GetCryptoStream()->id());
+ static_stream_map_[kCryptoStreamId] = GetCryptoStream();
+}
+
+QuicSession::~QuicSession() {
+ base::STLDeleteElements(&closed_streams_);
+ base::STLDeleteValues(&dynamic_stream_map_);
+
+ DLOG_IF(WARNING, num_locally_closed_incoming_streams_highest_offset() >
+ max_open_incoming_streams_)
+ << "Surprisingly high number of locally closed peer initiated streams"
+ "still waiting for final byte offset: "
+ << num_locally_closed_incoming_streams_highest_offset();
+ DLOG_IF(WARNING, GetNumLocallyClosedOutgoingStreamsHighestOffset() >
+ max_open_outgoing_streams_)
+ << "Surprisingly high number of locally closed self initiated streams"
+ "still waiting for final byte offset: "
+ << GetNumLocallyClosedOutgoingStreamsHighestOffset();
+}
+
+void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) {
+ // TODO(rch) deal with the error case of stream id 0.
+ QuicStreamId stream_id = frame.stream_id;
+ ReliableQuicStream* stream = GetOrCreateStream(stream_id);
+ if (!stream) {
+ // The stream no longer exists, but we may still be interested in the
+ // final stream byte offset sent by the peer. A frame with a FIN can give
+ // us this offset.
+ if (frame.fin) {
+ QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
+ UpdateFlowControlOnFinalReceivedByteOffset(stream_id, final_byte_offset);
+ }
+ return;
+ }
+ stream->OnStreamFrame(frame);
+}
+
+void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
+ if (base::ContainsKey(static_stream_map_, frame.stream_id)) {
+ connection()->CloseConnection(
+ QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+
+ ReliableQuicStream* stream = GetOrCreateDynamicStream(frame.stream_id);
+ if (!stream) {
+ HandleRstOnValidNonexistentStream(frame);
+ return; // Errors are handled by GetOrCreateStream.
+ }
+
+ stream->OnStreamReset(frame);
+}
+
+void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) {
+ DCHECK(frame.last_good_stream_id < next_outgoing_stream_id_);
+}
+
+void QuicSession::OnConnectionClosed(QuicErrorCode error,
+ const string& /*error_details*/,
+ ConnectionCloseSource source) {
+ DCHECK(!connection_->connected());
+ if (error_ == QUIC_NO_ERROR) {
+ error_ = error;
+ }
+
+ while (!dynamic_stream_map_.empty()) {
+ DynamicStreamMap::iterator it = dynamic_stream_map_.begin();
+ QuicStreamId id = it->first;
+ it->second->OnConnectionClosed(error, source);
+ // The stream should call CloseStream as part of OnConnectionClosed.
+ if (dynamic_stream_map_.find(id) != dynamic_stream_map_.end()) {
+ QUIC_BUG << ENDPOINT << "Stream failed to close under OnConnectionClosed";
+ CloseStream(id);
+ }
+ }
+}
+
+void QuicSession::OnSuccessfulVersionNegotiation(
+ const QuicVersion& /*version*/) {}
+
+void QuicSession::OnPathDegrading() {}
+
+void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
+ // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
+ // assume that it still exists.
+ QuicStreamId stream_id = frame.stream_id;
+ if (stream_id == kConnectionLevelId) {
+ // This is a window update that applies to the connection, rather than an
+ // individual stream.
+ DVLOG(1) << ENDPOINT << "Received connection level flow control window "
+ "update with byte offset: "
+ << frame.byte_offset;
+ flow_controller_.UpdateSendWindowOffset(frame.byte_offset);
+ return;
+ }
+ ReliableQuicStream* stream = GetOrCreateStream(stream_id);
+ if (stream) {
+ stream->OnWindowUpdateFrame(frame);
+ }
+}
+
+void QuicSession::OnBlockedFrame(const QuicBlockedFrame& frame) {
+ // TODO(rjshade): Compare our flow control receive windows for specified
+ // streams: if we have a large window then maybe something
+ // had gone wrong with the flow control accounting.
+ DVLOG(1) << ENDPOINT
+ << "Received BLOCKED frame with stream id: " << frame.stream_id;
+}
+
+void QuicSession::OnCanWrite() {
+ // 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
+ // connections.
+ size_t num_writes = write_blocked_streams_.NumBlockedStreams();
+ if (flow_controller_.IsBlocked()) {
+ // If we are connection level flow control blocked, then only allow the
+ // crypto and headers streams to try writing as all other streams will be
+ // blocked.
+ num_writes = 0;
+ if (write_blocked_streams_.crypto_stream_blocked()) {
+ num_writes += 1;
+ }
+ if (write_blocked_streams_.headers_stream_blocked()) {
+ num_writes += 1;
+ }
+ }
+ if (num_writes == 0) {
+ return;
+ }
+
+ QuicConnection::ScopedPacketBundler ack_bundler(
+ connection_, QuicConnection::SEND_ACK_IF_QUEUED);
+ for (size_t i = 0; i < num_writes; ++i) {
+ if (!(write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
+ write_blocked_streams_.HasWriteBlockedDataStreams())) {
+ // Writing one stream removed another!? Something's broken.
+ QUIC_BUG << "WriteBlockedStream is missing";
+ connection_->CloseConnection(QUIC_INTERNAL_ERROR,
+ "WriteBlockedStream is missing",
+ ConnectionCloseBehavior::SILENT_CLOSE);
+ return;
+ }
+ if (!connection_->CanWriteStreamData()) {
+ return;
+ }
+ currently_writing_stream_id_ = write_blocked_streams_.PopFront();
+ ReliableQuicStream* stream =
+ GetOrCreateStream(currently_writing_stream_id_);
+ if (stream != nullptr && !stream->flow_controller()->IsBlocked()) {
+ // If the stream can't write all bytes it'll re-add itself to the blocked
+ // list.
+ stream->OnCanWrite();
+ }
+ currently_writing_stream_id_ = 0;
+ }
+}
+
+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() ||
+ (!flow_controller_.IsBlocked() &&
+ write_blocked_streams_.HasWriteBlockedDataStreams());
+}
+
+bool QuicSession::HasPendingHandshake() const {
+ return write_blocked_streams_.crypto_stream_blocked();
+}
+
+bool QuicSession::HasOpenDynamicStreams() const {
+ return (dynamic_stream_map_.size() - draining_streams_.size() +
+ locally_closed_streams_highest_offset_.size()) > 0;
+}
+
+void QuicSession::ProcessUdpPacket(const IPEndPoint& self_address,
+ const IPEndPoint& peer_address,
+ const QuicReceivedPacket& packet) {
+ connection_->ProcessUdpPacket(self_address, peer_address, packet);
+}
+
+QuicConsumedData QuicSession::WritevData(
+ ReliableQuicStream* stream,
+ QuicStreamId id,
+ QuicIOVector iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate) {
+ // This check is an attempt to deal with potential memory corruption
+ // in which |id| ends up set to 1 (the crypto stream id). If this happen
+ // it might end up resulting in unencrypted stream data being sent.
+ // While this is impossible to avoid given sufficient corruption, this
+ // seems like a reasonable mitigation.
+ if (id == kCryptoStreamId && stream != GetCryptoStream()) {
+ QUIC_BUG << "Stream id mismatch";
+ connection_->CloseConnection(
+ QUIC_INTERNAL_ERROR,
+ "Non-crypto stream attempted to write data as crypto stream.",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return QuicConsumedData(0, false);
+ }
+ if (!IsEncryptionEstablished() && id != kCryptoStreamId) {
+ // Do not let streams write without encryption. The calling stream will end
+ // up write blocked until OnCanWrite is next called.
+ return QuicConsumedData(0, false);
+ }
+ QuicConsumedData data =
+ connection_->SendStreamData(id, iov, offset, fin, ack_notifier_delegate);
+ write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed);
+ return data;
+}
+
+void QuicSession::SendRstStream(QuicStreamId id,
+ QuicRstStreamErrorCode error,
+ QuicStreamOffset bytes_written) {
+ if (base::ContainsKey(static_stream_map_, id)) {
+ QUIC_BUG << "Cannot send RST for a static stream with ID " << id;
+ return;
+ }
+
+ if (connection()->connected()) {
+ // Only send a RST_STREAM frame if still connected.
+ connection_->SendRstStream(id, error, bytes_written);
+ }
+ CloseStreamInner(id, true);
+}
+
+void QuicSession::SendGoAway(QuicErrorCode error_code, const string& reason) {
+ if (goaway_sent()) {
+ return;
+ }
+
+ connection_->SendGoAway(error_code, largest_peer_created_stream_id_, reason);
+}
+
+void QuicSession::CloseStream(QuicStreamId stream_id) {
+ CloseStreamInner(stream_id, false);
+}
+
+void QuicSession::InsertLocallyClosedStreamsHighestOffset(
+ const QuicStreamId id,
+ QuicStreamOffset offset) {
+ locally_closed_streams_highest_offset_[id] = offset;
+ if (IsIncomingStream(id)) {
+ ++num_locally_closed_incoming_streams_highest_offset_;
+ }
+}
+
+void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) {
+ DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
+
+ DynamicStreamMap::iterator it = dynamic_stream_map_.find(stream_id);
+ if (it == dynamic_stream_map_.end()) {
+ // When CloseStreamInner has been called recursively (via
+ // ReliableQuicStream::OnClose), the stream will already have been deleted
+ // from stream_map_, so return immediately.
+ DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
+ return;
+ }
+ ReliableQuicStream* stream = it->second;
+
+ // Tell the stream that a RST has been sent.
+ if (locally_reset) {
+ stream->set_rst_sent(true);
+ }
+
+ closed_streams_.push_back(it->second);
+
+ // If we haven't received a FIN or RST for this stream, we need to keep track
+ // of the how many bytes the stream's flow controller believes it has
+ // received, for accurate connection level flow control accounting.
+ if (!stream->HasFinalReceivedByteOffset()) {
+ InsertLocallyClosedStreamsHighestOffset(
+ stream_id, stream->flow_controller()->highest_received_byte_offset());
+ }
+
+ dynamic_stream_map_.erase(it);
+ if (IsIncomingStream(stream_id)) {
+ --num_dynamic_incoming_streams_;
+ }
+
+ if (draining_streams_.find(stream_id) != draining_streams_.end() &&
+ IsIncomingStream(stream_id)) {
+ --num_draining_incoming_streams_;
+ }
+ draining_streams_.erase(stream_id);
+
+ stream->OnClose();
+ // Decrease the number of streams being emulated when a new one is opened.
+ connection_->SetNumOpenStreams(dynamic_stream_map_.size());
+}
+
+void QuicSession::UpdateFlowControlOnFinalReceivedByteOffset(
+ QuicStreamId stream_id,
+ QuicStreamOffset final_byte_offset) {
+ map<QuicStreamId, QuicStreamOffset>::iterator it =
+ locally_closed_streams_highest_offset_.find(stream_id);
+ if (it == locally_closed_streams_highest_offset_.end()) {
+ return;
+ }
+
+ DVLOG(1) << ENDPOINT << "Received final byte offset " << final_byte_offset
+ << " for stream " << stream_id;
+ QuicByteCount offset_diff = final_byte_offset - it->second;
+ if (flow_controller_.UpdateHighestReceivedOffset(
+ flow_controller_.highest_received_byte_offset() + offset_diff)) {
+ // If the final offset violates flow control, close the connection now.
+ if (flow_controller_.FlowControlViolation()) {
+ connection_->CloseConnection(
+ QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
+ "Connection level flow control violation",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+ }
+
+ flow_controller_.AddBytesConsumed(offset_diff);
+ locally_closed_streams_highest_offset_.erase(it);
+ if (IsIncomingStream(stream_id)) {
+ --num_locally_closed_incoming_streams_highest_offset_;
+ }
+}
+
+bool QuicSession::IsEncryptionEstablished() {
+ return GetCryptoStream()->encryption_established();
+}
+
+bool QuicSession::IsCryptoHandshakeConfirmed() {
+ return GetCryptoStream()->handshake_confirmed();
+}
+
+void QuicSession::OnConfigNegotiated() {
+ connection_->SetFromConfig(config_);
+
+ const QuicVersion version = connection()->version();
+ uint32_t max_streams = 0;
+ if (version > QUIC_VERSION_34 &&
+ config_.HasReceivedMaxIncomingDynamicStreams()) {
+ max_streams = config_.ReceivedMaxIncomingDynamicStreams();
+ } else {
+ max_streams = config_.MaxStreamsPerConnection();
+ }
+ set_max_open_outgoing_streams(max_streams);
+
+ if (version <= QUIC_VERSION_34) {
+ // A small number of additional incoming streams beyond the limit should be
+ // allowed. This helps avoid early connection termination when FIN/RSTs for
+ // old streams are lost or arrive out of order.
+ // Use a minimum number of additional streams, or a percentage increase,
+ // whichever is larger.
+ uint32_t max_incoming_streams =
+ max(max_streams + kMaxStreamsMinimumIncrement,
+ static_cast<uint32_t>(max_streams * kMaxStreamsMultiplier));
+ set_max_open_incoming_streams(max_incoming_streams);
+ } else {
+ uint32_t max_incoming_streams_to_send =
+ config_.GetMaxIncomingDynamicStreamsToSend();
+ uint32_t max_incoming_streams =
+ max(max_incoming_streams_to_send + kMaxStreamsMinimumIncrement,
+ static_cast<uint32_t>(max_incoming_streams_to_send *
+ kMaxStreamsMultiplier));
+ set_max_open_incoming_streams(max_incoming_streams);
+ }
+
+ if (config_.HasReceivedInitialStreamFlowControlWindowBytes()) {
+ // Streams which were created before the SHLO was received (0-RTT
+ // requests) are now informed of the peer's initial flow control window.
+ OnNewStreamFlowControlWindow(
+ config_.ReceivedInitialStreamFlowControlWindowBytes());
+ }
+ if (config_.HasReceivedInitialSessionFlowControlWindowBytes()) {
+ OnNewSessionFlowControlWindow(
+ config_.ReceivedInitialSessionFlowControlWindowBytes());
+ }
+}
+
+void QuicSession::HandleFrameOnNonexistentOutgoingStream(
+ QuicStreamId stream_id) {
+ DCHECK(!IsClosedStream(stream_id));
+ // Received a frame for a locally-created stream that is not currently
+ // active. This is an error.
+ connection()->CloseConnection(
+ QUIC_INVALID_STREAM_ID, "Data for nonexistent stream",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+}
+
+void QuicSession::HandleRstOnValidNonexistentStream(
+ const QuicRstStreamFrame& frame) {
+ // If the stream is neither originally in active streams nor created in
+ // GetOrCreateDynamicStream(), it could be a closed stream in which case its
+ // final received byte offset need to be updated.
+ if (IsClosedStream(frame.stream_id)) {
+ // The RST frame contains the final byte offset for the stream: we can now
+ // update the connection level flow controller if needed.
+ UpdateFlowControlOnFinalReceivedByteOffset(frame.stream_id,
+ frame.byte_offset);
+ }
+}
+
+void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
+ if (new_window < kMinimumFlowControlSendWindow) {
+ LOG(ERROR) << "Peer sent us an invalid stream flow control send window: "
+ << new_window
+ << ", below default: " << kMinimumFlowControlSendWindow;
+ if (connection_->connected()) {
+ connection_->CloseConnection(
+ QUIC_FLOW_CONTROL_INVALID_WINDOW, "New stream window too low",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ }
+ return;
+ }
+
+ // Inform all existing streams about the new window.
+ for (auto const& kv : static_stream_map_) {
+ kv.second->UpdateSendWindowOffset(new_window);
+ }
+ for (auto const& kv : dynamic_stream_map_) {
+ kv.second->UpdateSendWindowOffset(new_window);
+ }
+}
+
+void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) {
+ if (new_window < kMinimumFlowControlSendWindow) {
+ LOG(ERROR) << "Peer sent us an invalid session flow control send window: "
+ << new_window
+ << ", below default: " << kMinimumFlowControlSendWindow;
+ if (connection_->connected()) {
+ connection_->CloseConnection(
+ QUIC_FLOW_CONTROL_INVALID_WINDOW, "New connection window too low",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ }
+ return;
+ }
+
+ flow_controller_.UpdateSendWindowOffset(new_window);
+}
+
+void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
+ switch (event) {
+ // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter
+ // to QuicSession since it is the glue.
+ case ENCRYPTION_FIRST_ESTABLISHED:
+ // Given any streams blocked by encryption a chance to write.
+ OnCanWrite();
+ break;
+
+ case ENCRYPTION_REESTABLISHED:
+ // Retransmit originally packets that were sent, since they can't be
+ // decrypted by the peer.
+ connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
+ // Given any streams blocked by encryption a chance to write.
+ OnCanWrite();
+ break;
+
+ case HANDSHAKE_CONFIRMED:
+ QUIC_BUG_IF(!config_.negotiated())
+ << ENDPOINT << "Handshake confirmed without parameter negotiation.";
+ // Discard originally encrypted packets, since they can't be decrypted by
+ // the peer.
+ connection_->NeuterUnencryptedPackets();
+ break;
+
+ default:
+ LOG(ERROR) << ENDPOINT << "Got unknown handshake event: " << event;
+ }
+}
+
+void QuicSession::OnCryptoHandshakeMessageSent(
+ const CryptoHandshakeMessage& /*message*/) {}
+
+void QuicSession::OnCryptoHandshakeMessageReceived(
+ const CryptoHandshakeMessage& /*message*/) {}
+
+QuicConfig* QuicSession::config() {
+ return &config_;
+}
+
+void QuicSession::ActivateStream(ReliableQuicStream* stream) {
+ DVLOG(1) << ENDPOINT << "num_streams: " << dynamic_stream_map_.size()
+ << ". activating " << stream->id();
+ DCHECK(!base::ContainsKey(dynamic_stream_map_, stream->id()));
+ DCHECK(!base::ContainsKey(static_stream_map_, stream->id()));
+ dynamic_stream_map_[stream->id()] = stream;
+ if (IsIncomingStream(stream->id())) {
+ ++num_dynamic_incoming_streams_;
+ }
+ // Increase the number of streams being emulated when a new one is opened.
+ connection_->SetNumOpenStreams(dynamic_stream_map_.size());
+}
+
+QuicStreamId QuicSession::GetNextOutgoingStreamId() {
+ QuicStreamId id = next_outgoing_stream_id_;
+ next_outgoing_stream_id_ += 2;
+ return id;
+}
+
+ReliableQuicStream* QuicSession::GetOrCreateStream(
+ const QuicStreamId stream_id) {
+ StaticStreamMap::iterator it = static_stream_map_.find(stream_id);
+ if (it != static_stream_map_.end()) {
+ return it->second;
+ }
+ return GetOrCreateDynamicStream(stream_id);
+}
+
+void QuicSession::StreamDraining(QuicStreamId stream_id) {
+ DCHECK(base::ContainsKey(dynamic_stream_map_, stream_id));
+ if (!base::ContainsKey(draining_streams_, stream_id)) {
+ draining_streams_.insert(stream_id);
+ if (IsIncomingStream(stream_id)) {
+ ++num_draining_incoming_streams_;
+ }
+ }
+}
+
+bool QuicSession::MaybeIncreaseLargestPeerStreamId(
+ const QuicStreamId stream_id) {
+ if (stream_id <= largest_peer_created_stream_id_) {
+ return true;
+ }
+
+ // Check if the new number of available streams would cause the number of
+ // available streams to exceed the limit. Note that the peer can create
+ // only alternately-numbered streams.
+ size_t additional_available_streams =
+ (stream_id - largest_peer_created_stream_id_) / 2 - 1;
+ size_t new_num_available_streams =
+ GetNumAvailableStreams() + additional_available_streams;
+ if (new_num_available_streams > MaxAvailableStreams()) {
+ DVLOG(1) << "Failed to create a new incoming stream with id:" << stream_id
+ << ". There are already " << GetNumAvailableStreams()
+ << " streams available, which would become "
+ << new_num_available_streams << ", which exceeds the limit "
+ << MaxAvailableStreams() << ".";
+ string details = IntToString(new_num_available_streams) + " above " +
+ IntToString(MaxAvailableStreams());
+ connection()->CloseConnection(
+ QUIC_TOO_MANY_AVAILABLE_STREAMS, details.c_str(),
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return false;
+ }
+ for (QuicStreamId id = largest_peer_created_stream_id_ + 2; id < stream_id;
+ id += 2) {
+ available_streams_.insert(id);
+ }
+ largest_peer_created_stream_id_ = stream_id;
+
+ return true;
+}
+
+bool QuicSession::ShouldYield(QuicStreamId stream_id) {
+ if (stream_id == currently_writing_stream_id_) {
+ return false;
+ }
+ return write_blocked_streams()->ShouldYield(stream_id);
+}
+
+ReliableQuicStream* QuicSession::GetOrCreateDynamicStream(
+ const QuicStreamId stream_id) {
+ DCHECK(!base::ContainsKey(static_stream_map_, stream_id))
+ << "Attempt to call GetOrCreateDynamicStream for a static stream";
+
+ DynamicStreamMap::iterator it = dynamic_stream_map_.find(stream_id);
+ if (it != dynamic_stream_map_.end()) {
+ return it->second;
+ }
+
+ if (IsClosedStream(stream_id)) {
+ return nullptr;
+ }
+
+ if (!IsIncomingStream(stream_id)) {
+ HandleFrameOnNonexistentOutgoingStream(stream_id);
+ return nullptr;
+ }
+
+ available_streams_.erase(stream_id);
+
+ if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
+ return nullptr;
+ }
+ // Check if the new number of open streams would cause the number of
+ // open streams to exceed the limit.
+ if (GetNumOpenIncomingStreams() >= max_open_incoming_streams()) {
+ // Refuse to open the stream.
+ SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
+ return nullptr;
+ }
+
+ return CreateIncomingDynamicStream(stream_id);
+}
+
+void QuicSession::set_max_open_incoming_streams(
+ size_t max_open_incoming_streams) {
+ DVLOG(1) << "Setting max_open_incoming_streams_ to "
+ << max_open_incoming_streams;
+ max_open_incoming_streams_ = max_open_incoming_streams;
+ DVLOG(1) << "MaxAvailableStreams() became " << MaxAvailableStreams();
+}
+
+void QuicSession::set_max_open_outgoing_streams(
+ size_t max_open_outgoing_streams) {
+ DVLOG(1) << "Setting max_open_outgoing_streams_ to "
+ << max_open_outgoing_streams;
+ max_open_outgoing_streams_ = max_open_outgoing_streams;
+}
+
+bool QuicSession::goaway_sent() const {
+ return connection_->goaway_sent();
+}
+
+bool QuicSession::goaway_received() const {
+ return connection_->goaway_received();
+}
+
+bool QuicSession::IsClosedStream(QuicStreamId id) {
+ DCHECK_NE(0u, id);
+ if (IsOpenStream(id)) {
+ // Stream is active
+ return false;
+ }
+ if (!IsIncomingStream(id)) {
+ // Locally created streams are strictly in-order. If the id is in the
+ // range of created streams and it's not active, it must have been closed.
+ return id < next_outgoing_stream_id_;
+ }
+ // For peer created streams, we also need to consider available streams.
+ return id <= largest_peer_created_stream_id_ &&
+ !base::ContainsKey(available_streams_, id);
+}
+
+bool QuicSession::IsOpenStream(QuicStreamId id) {
+ DCHECK_NE(0u, id);
+ if (base::ContainsKey(static_stream_map_, id) ||
+ base::ContainsKey(dynamic_stream_map_, id)) {
+ // Stream is active
+ return true;
+ }
+ return false;
+}
+
+size_t QuicSession::GetNumOpenIncomingStreams() const {
+ return num_dynamic_incoming_streams_ - num_draining_incoming_streams_ +
+ num_locally_closed_incoming_streams_highest_offset_;
+}
+
+size_t QuicSession::GetNumOpenOutgoingStreams() const {
+ return GetNumDynamicOutgoingStreams() - GetNumDrainingOutgoingStreams() +
+ GetNumLocallyClosedOutgoingStreamsHighestOffset();
+}
+
+size_t QuicSession::GetNumActiveStreams() const {
+ return dynamic_stream_map_.size() - draining_streams_.size();
+}
+
+size_t QuicSession::GetNumAvailableStreams() const {
+ return available_streams_.size();
+}
+
+void QuicSession::MarkConnectionLevelWriteBlocked(QuicStreamId id) {
+ QUIC_BUG_IF(GetOrCreateStream(id) == nullptr) << "Marking unknown stream "
+ << id << " blocked.";
+
+ write_blocked_streams_.AddStream(id);
+}
+
+bool QuicSession::HasDataToWrite() const {
+ return write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
+ write_blocked_streams_.HasWriteBlockedDataStreams() ||
+ connection_->HasQueuedData();
+}
+
+void QuicSession::PostProcessAfterData() {
+ base::STLDeleteElements(&closed_streams_);
+ closed_streams_.clear();
+}
+
+size_t QuicSession::GetNumDynamicOutgoingStreams() const {
+ DCHECK_GE(dynamic_stream_map_.size(), num_dynamic_incoming_streams_);
+ return dynamic_stream_map_.size() - num_dynamic_incoming_streams_;
+}
+
+size_t QuicSession::GetNumDrainingOutgoingStreams() const {
+ DCHECK_GE(draining_streams_.size(), num_draining_incoming_streams_);
+ return draining_streams_.size() - num_draining_incoming_streams_;
+}
+
+size_t QuicSession::GetNumLocallyClosedOutgoingStreamsHighestOffset() const {
+ DCHECK_GE(locally_closed_streams_highest_offset_.size(),
+ num_locally_closed_incoming_streams_highest_offset_);
+ return locally_closed_streams_highest_offset_.size() -
+ num_locally_closed_incoming_streams_highest_offset_;
+}
+
+bool QuicSession::IsConnectionFlowControlBlocked() const {
+ return flow_controller_.IsBlocked();
+}
+
+bool QuicSession::IsStreamFlowControlBlocked() {
+ for (auto const& kv : static_stream_map_) {
+ if (kv.second->flow_controller()->IsBlocked()) {
+ return true;
+ }
+ }
+ for (auto const& kv : dynamic_stream_map_) {
+ if (kv.second->flow_controller()->IsBlocked()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+size_t QuicSession::MaxAvailableStreams() const {
+ return max_open_incoming_streams_ * kMaxAvailableStreamsMultiplier;
+}
+
+bool QuicSession::IsIncomingStream(QuicStreamId id) const {
+ return id % 2 != next_outgoing_stream_id_ % 2;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_session.h b/chromium/net/quic/core/quic_session.h
new file mode 100644
index 00000000000..b0362f3f7f2
--- /dev/null
+++ b/chromium/net/quic/core/quic_session.h
@@ -0,0 +1,417 @@
+// 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.
+//
+// A QuicSession, which demuxes a single connection to individual streams.
+
+#ifndef NET_QUIC_QUIC_SESSION_H_
+#define NET_QUIC_QUIC_SESSION_H_
+
+#include <stddef.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/containers/small_map.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_crypto_stream.h"
+#include "net/quic/core/quic_packet_creator.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_write_blocked_list.h"
+#include "net/quic/core/reliable_quic_stream.h"
+
+namespace net {
+
+class QuicCryptoStream;
+class QuicFlowController;
+class ReliableQuicStream;
+
+namespace test {
+class QuicSessionPeer;
+} // namespace test
+
+class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
+ public:
+ // CryptoHandshakeEvent enumerates the events generated by a QuicCryptoStream.
+ enum CryptoHandshakeEvent {
+ // ENCRYPTION_FIRST_ESTABLISHED indicates that a full client hello has been
+ // sent by a client and that subsequent packets will be encrypted. (Client
+ // only.)
+ ENCRYPTION_FIRST_ESTABLISHED,
+ // ENCRYPTION_REESTABLISHED indicates that a client hello was rejected by
+ // the server and thus the encryption key has been updated. Therefore the
+ // connection should resend any packets that were sent under
+ // ENCRYPTION_INITIAL. (Client only.)
+ ENCRYPTION_REESTABLISHED,
+ // HANDSHAKE_CONFIRMED, in a client, indicates the the server has accepted
+ // our handshake. In a server it indicates that a full, valid client hello
+ // has been received. (Client and server.)
+ HANDSHAKE_CONFIRMED,
+ };
+
+ // Does not take ownership of |connection|.
+ QuicSession(QuicConnection* connection, const QuicConfig& config);
+
+ ~QuicSession() override;
+
+ virtual void Initialize();
+
+ // QuicConnectionVisitorInterface methods:
+ void OnStreamFrame(const QuicStreamFrame& frame) override;
+ void OnRstStream(const QuicRstStreamFrame& frame) override;
+ void OnGoAway(const QuicGoAwayFrame& frame) override;
+ void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
+ void OnBlockedFrame(const QuicBlockedFrame& frame) override;
+ void OnConnectionClosed(QuicErrorCode error,
+ const std::string& error_details,
+ ConnectionCloseSource source) override;
+ void OnWriteBlocked() override {}
+ void OnSuccessfulVersionNegotiation(const QuicVersion& version) override;
+ void OnCanWrite() override;
+ void OnCongestionWindowChange(QuicTime /*now*/) override {}
+ void OnConnectionMigration(PeerAddressChangeType type) override {}
+ // Deletes streams that are safe to be deleted now that it's safe to do so (no
+ // other operations are being done on the streams at this time).
+ void PostProcessAfterData() override;
+ bool WillingAndAbleToWrite() const override;
+ bool HasPendingHandshake() const override;
+ bool HasOpenDynamicStreams() const override;
+ void OnPathDegrading() override;
+
+ // Called on every incoming packet. Passes |packet| through to |connection_|.
+ virtual void ProcessUdpPacket(const IPEndPoint& self_address,
+ const IPEndPoint& peer_address,
+ const QuicReceivedPacket& packet);
+
+ // Called by streams when they want to write data to the peer.
+ // Returns a pair with the number of bytes consumed from data, and a boolean
+ // indicating if the fin bit was consumed. This does not indicate the data
+ // has been sent on the wire: it may have been turned into a packet and queued
+ // if the socket was unexpectedly blocked.
+ // If provided, |ack_notifier_delegate| will be registered to be notified when
+ // we have seen ACKs for all packets resulting from this call.
+ virtual QuicConsumedData WritevData(
+ ReliableQuicStream* stream,
+ QuicStreamId id,
+ QuicIOVector iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate);
+
+ // Called by streams when they want to close the stream in both directions.
+ virtual void SendRstStream(QuicStreamId id,
+ QuicRstStreamErrorCode error,
+ QuicStreamOffset bytes_written);
+
+ // Called when the session wants to go away and not accept any new streams.
+ void SendGoAway(QuicErrorCode error_code, const std::string& reason);
+
+ // Removes the stream associated with 'stream_id' from the active stream map.
+ virtual void CloseStream(QuicStreamId stream_id);
+
+ // Returns true if outgoing packets will be encrypted, even if the server
+ // hasn't confirmed the handshake yet.
+ virtual bool IsEncryptionEstablished();
+
+ // For a client, returns true if the server has confirmed our handshake. For
+ // a server, returns true if a full, valid client hello has been received.
+ virtual bool IsCryptoHandshakeConfirmed();
+
+ // Called by the QuicCryptoStream when a new QuicConfig has been negotiated.
+ virtual void OnConfigNegotiated();
+
+ // Called by the QuicCryptoStream when the handshake enters a new state.
+ //
+ // Clients will call this function in the order:
+ // ENCRYPTION_FIRST_ESTABLISHED
+ // zero or more ENCRYPTION_REESTABLISHED
+ // HANDSHAKE_CONFIRMED
+ //
+ // Servers will simply call it once with HANDSHAKE_CONFIRMED.
+ virtual void OnCryptoHandshakeEvent(CryptoHandshakeEvent event);
+
+ // Called by the QuicCryptoStream when a handshake message is sent.
+ virtual void OnCryptoHandshakeMessageSent(
+ const CryptoHandshakeMessage& message);
+
+ // Called by the QuicCryptoStream when a handshake message is received.
+ virtual void OnCryptoHandshakeMessageReceived(
+ const CryptoHandshakeMessage& message);
+
+ // Returns mutable config for this session. Returned config is owned
+ // by QuicSession.
+ QuicConfig* config();
+
+ // Returns true if the stream existed previously and has been closed.
+ // Returns false if the stream is still active or if the stream has
+ // not yet been created.
+ bool IsClosedStream(QuicStreamId id);
+
+ QuicConnection* connection() { return connection_; }
+ const QuicConnection* connection() const { return connection_; }
+ size_t num_active_requests() const { return dynamic_stream_map_.size(); }
+ const IPEndPoint& peer_address() const { return connection_->peer_address(); }
+ QuicConnectionId connection_id() const {
+ return connection_->connection_id();
+ }
+
+ // Returns the number of currently open streams, excluding the reserved
+ // headers and crypto streams, and never counting unfinished streams.
+ virtual size_t GetNumActiveStreams() const;
+
+ // Returns the number of currently open peer initiated streams, excluding the
+ // reserved headers and crypto streams.
+ virtual size_t GetNumOpenIncomingStreams() const;
+
+ // Returns the number of currently open self initiated streams, excluding the
+ // reserved headers and crypto streams.
+ virtual size_t GetNumOpenOutgoingStreams() const;
+
+ // Returns the number of "available" streams, the stream ids less than
+ // largest_peer_created_stream_id_ that have not yet been opened.
+ virtual size_t GetNumAvailableStreams() const;
+
+ // Add the stream to the session's write-blocked list because it is blocked by
+ // connection-level flow control but not by its own stream-level flow control.
+ // The stream will be given a chance to write when a connection-level
+ // WINDOW_UPDATE arrives.
+ void MarkConnectionLevelWriteBlocked(QuicStreamId id);
+
+ // Returns true if the session has data to be sent, either queued in the
+ // connection, or in a write-blocked stream.
+ bool HasDataToWrite() const;
+
+ bool goaway_sent() const;
+
+ bool goaway_received() const;
+
+ QuicErrorCode error() const { return error_; }
+
+ Perspective perspective() const { return connection_->perspective(); }
+
+ QuicFlowController* flow_controller() { return &flow_controller_; }
+
+ // Returns true if connection is flow controller blocked.
+ bool IsConnectionFlowControlBlocked() const;
+
+ // Returns true if any stream is flow controller blocked.
+ bool IsStreamFlowControlBlocked();
+
+ size_t max_open_incoming_streams() const {
+ return max_open_incoming_streams_;
+ }
+
+ size_t max_open_outgoing_streams() const {
+ return max_open_outgoing_streams_;
+ }
+
+ size_t MaxAvailableStreams() const;
+
+ // Returns existing static or dynamic stream with id = |stream_id|. If no
+ // such stream exists, and |stream_id| is a peer-created dynamic stream id,
+ // then a new stream is created and returned. In all other cases, nullptr is
+ // returned.
+ ReliableQuicStream* GetOrCreateStream(const QuicStreamId stream_id);
+
+ // Mark a stream as draining.
+ virtual void StreamDraining(QuicStreamId id);
+
+ // Returns true if this stream should yield writes to another blocked stream.
+ bool ShouldYield(QuicStreamId stream_id);
+
+ protected:
+ using StaticStreamMap =
+ base::SmallMap<std::unordered_map<QuicStreamId, ReliableQuicStream*>, 2>;
+
+ using DynamicStreamMap =
+ base::SmallMap<std::unordered_map<QuicStreamId, ReliableQuicStream*>, 10>;
+
+ // Creates a new stream to handle a peer-initiated stream.
+ // Caller does not own the returned stream.
+ // Returns nullptr and does error handling if the stream can not be created.
+ virtual ReliableQuicStream* CreateIncomingDynamicStream(QuicStreamId id) = 0;
+
+ // Create a new stream to handle a locally-initiated stream.
+ // Caller does not own the returned stream.
+ // Returns nullptr if max streams have already been opened.
+ virtual ReliableQuicStream* CreateOutgoingDynamicStream(
+ SpdyPriority priority) = 0;
+
+ // Return the reserved crypto stream.
+ virtual QuicCryptoStream* GetCryptoStream() = 0;
+
+ // Adds |stream| to the dynamic stream map.
+ // Takes ownership of |stream|.
+ virtual void ActivateStream(ReliableQuicStream* stream);
+
+ // Returns the stream ID for a new outgoing stream, and increments the
+ // underlying counter.
+ QuicStreamId GetNextOutgoingStreamId();
+
+ // Returns existing stream with id = |stream_id|. If no such stream exists,
+ // and |stream_id| is a peer-created id, then a new stream is created and
+ // returned. However if |stream_id| is a locally-created id and no such stream
+ // exists, the connection is closed.
+ // Caller does not own the returned stream.
+ ReliableQuicStream* GetOrCreateDynamicStream(QuicStreamId stream_id);
+
+ // Performs the work required to close |stream_id|. If |locally_reset|
+ // then the stream has been reset by this endpoint, not by the peer.
+ virtual void CloseStreamInner(QuicStreamId stream_id, bool locally_reset);
+
+ // When a stream is closed locally, it may not yet know how many bytes the
+ // peer sent on that stream.
+ // When this data arrives (via stream frame w. FIN, or RST) this method
+ // is called, and correctly updates the connection level flow controller.
+ void UpdateFlowControlOnFinalReceivedByteOffset(
+ QuicStreamId id,
+ QuicStreamOffset final_byte_offset);
+
+ // Return true if given stream is peer initiated.
+ bool IsIncomingStream(QuicStreamId id) const;
+
+ StaticStreamMap& static_streams() { return static_stream_map_; }
+ const StaticStreamMap& static_streams() const { return static_stream_map_; }
+
+ DynamicStreamMap& dynamic_streams() { return dynamic_stream_map_; }
+ const DynamicStreamMap& dynamic_streams() const {
+ return dynamic_stream_map_;
+ }
+
+ std::vector<ReliableQuicStream*>* closed_streams() {
+ return &closed_streams_;
+ }
+
+ void set_max_open_incoming_streams(size_t max_open_incoming_streams);
+ void set_max_open_outgoing_streams(size_t max_open_outgoing_streams);
+
+ void set_largest_peer_created_stream_id(
+ QuicStreamId largest_peer_created_stream_id) {
+ largest_peer_created_stream_id_ = largest_peer_created_stream_id;
+ }
+ void set_error(QuicErrorCode error) { error_ = error; }
+ QuicWriteBlockedList* write_blocked_streams() {
+ return &write_blocked_streams_;
+ }
+
+ size_t GetNumDynamicOutgoingStreams() const;
+
+ size_t GetNumDrainingOutgoingStreams() const;
+
+ size_t num_locally_closed_incoming_streams_highest_offset() const {
+ return num_locally_closed_incoming_streams_highest_offset_;
+ }
+
+ size_t GetNumLocallyClosedOutgoingStreamsHighestOffset() const;
+
+ // Returns true if the stream is still active.
+ bool IsOpenStream(QuicStreamId id);
+
+ QuicStreamId next_outgoing_stream_id() const {
+ return next_outgoing_stream_id_;
+ }
+
+ // Close connection when receive a frame for a locally-created nonexistant
+ // stream.
+ // Prerequisite: IsClosedStream(stream_id) == false
+ // Server session might need to override this method to allow server push
+ // stream to be promised before creating an active stream.
+ virtual void HandleFrameOnNonexistentOutgoingStream(QuicStreamId stream_id);
+
+ bool MaybeIncreaseLargestPeerStreamId(const QuicStreamId stream_id);
+
+ void InsertLocallyClosedStreamsHighestOffset(const QuicStreamId id,
+ QuicStreamOffset offset);
+ // If stream is a locally closed stream, this RST will update FIN offset.
+ // Otherwise stream is a preserved stream and the behavior of it depends on
+ // derived class's own implementation.
+ virtual void HandleRstOnValidNonexistentStream(
+ const QuicRstStreamFrame& frame);
+
+ private:
+ friend class test::QuicSessionPeer;
+
+ // Called in OnConfigNegotiated when we receive a new stream level flow
+ // control window in a negotiated config. Closes the connection if invalid.
+ void OnNewStreamFlowControlWindow(QuicStreamOffset new_window);
+
+ // Called in OnConfigNegotiated when we receive a new connection level flow
+ // control window in a negotiated config. Closes the connection if invalid.
+ void OnNewSessionFlowControlWindow(QuicStreamOffset new_window);
+
+ // 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>
+ locally_closed_streams_highest_offset_;
+
+ QuicConnection* connection_;
+
+ std::vector<ReliableQuicStream*> closed_streams_;
+
+ QuicConfig config_;
+
+ // The maximum number of outgoing streams this connection can open.
+ size_t max_open_outgoing_streams_;
+
+ // The maximum number of incoming streams this connection will allow.
+ size_t max_open_incoming_streams_;
+
+ // Static streams, such as crypto and header streams. Owned by child classes
+ // that create these streams.
+ StaticStreamMap static_stream_map_;
+
+ // Map from StreamId to pointers to streams. Owns the streams.
+ DynamicStreamMap dynamic_stream_map_;
+
+ // The ID to use for the next outgoing stream.
+ QuicStreamId next_outgoing_stream_id_;
+
+ // Set of stream ids that are less than the largest stream id that has been
+ // received, but are nonetheless available to be created.
+ std::unordered_set<QuicStreamId> available_streams_;
+
+ // Set of stream ids that are "draining" -- a FIN has been sent and received,
+ // but the stream object still exists because not all the received data has
+ // been consumed.
+ std::unordered_set<QuicStreamId> draining_streams_;
+
+ // A list of streams which need to write more data.
+ QuicWriteBlockedList write_blocked_streams_;
+
+ QuicStreamId largest_peer_created_stream_id_;
+
+ // A counter for peer initiated streams which are in the dynamic_stream_map_.
+ size_t num_dynamic_incoming_streams_;
+
+ // A counter for peer initiated streams which are in the draining_streams_.
+ size_t num_draining_incoming_streams_;
+
+ // A counter for peer initiated streams which are in the
+ // locally_closed_streams_highest_offset_.
+ size_t num_locally_closed_incoming_streams_highest_offset_;
+
+ // The latched error with which the connection was closed.
+ QuicErrorCode error_;
+
+ // Used for connection-level flow control.
+ QuicFlowController flow_controller_;
+
+ // The stream id which was last popped in OnCanWrite, or 0, if not under the
+ // call stack of OnCanWrite.
+ QuicStreamId currently_writing_stream_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicSession);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_SESSION_H_
diff --git a/chromium/net/quic/core/quic_session_test.cc b/chromium/net/quic/core/quic_session_test.cc
new file mode 100644
index 00000000000..9af64d11ef6
--- /dev/null
+++ b/chromium/net/quic/core/quic_session_test.cc
@@ -0,0 +1,1257 @@
+// 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/quic_session.h"
+
+#include <set>
+#include <utility>
+
+#include "base/rand_util.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "build/build_config.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/null_encrypter.h"
+#include "net/quic/core/quic_crypto_stream.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/core/reliable_quic_stream.h"
+#include "net/quic/test_tools/quic_config_peer.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_flow_controller_peer.h"
+#include "net/quic/test_tools/quic_headers_stream_peer.h"
+#include "net/quic/test_tools/quic_session_peer.h"
+#include "net/quic/test_tools/quic_spdy_session_peer.h"
+#include "net/quic/test_tools/quic_spdy_stream_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/reliable_quic_stream_peer.h"
+#include "net/spdy/spdy_framer.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gmock_mutant.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using net::SpdyHeaderBlock;
+using net::SpdyPriority;
+using std::set;
+using std::string;
+using std::vector;
+using testing::CreateFunctor;
+using testing::AtLeast;
+using testing::InSequence;
+using testing::Invoke;
+using testing::Return;
+using testing::StrictMock;
+using testing::_;
+
+namespace net {
+namespace test {
+namespace {
+
+const SpdyPriority kHighestPriority = kV3HighestPriority;
+
+class TestCryptoStream : public QuicCryptoStream {
+ public:
+ explicit TestCryptoStream(QuicSession* session) : QuicCryptoStream(session) {}
+
+ void OnHandshakeMessage(const CryptoHandshakeMessage& /*message*/) override {
+ encryption_established_ = true;
+ handshake_confirmed_ = true;
+ CryptoHandshakeMessage msg;
+ string error_details;
+ session()->config()->SetInitialStreamFlowControlWindowToSend(
+ kInitialStreamFlowControlWindowForTest);
+ session()->config()->SetInitialSessionFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+ session()->config()->ToHandshakeMessage(&msg);
+ const QuicErrorCode error =
+ session()->config()->ProcessPeerHello(msg, CLIENT, &error_details);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ session()->OnConfigNegotiated();
+ session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
+ }
+
+ MOCK_METHOD0(OnCanWrite, void());
+};
+
+class TestHeadersStream : public QuicHeadersStream {
+ public:
+ explicit TestHeadersStream(QuicSpdySession* session)
+ : QuicHeadersStream(session) {}
+
+ MOCK_METHOD0(OnCanWrite, void());
+};
+
+class TestStream : public QuicSpdyStream {
+ public:
+ TestStream(QuicStreamId id, QuicSpdySession* session)
+ : QuicSpdyStream(id, session) {}
+
+ using ReliableQuicStream::CloseWriteSide;
+
+ void OnDataAvailable() override {}
+
+ MOCK_METHOD0(OnCanWrite, void());
+};
+
+// Poor man's functor for use as callback in a mock.
+class StreamBlocker {
+ public:
+ StreamBlocker(QuicSession* session, QuicStreamId stream_id)
+ : session_(session), stream_id_(stream_id) {}
+
+ void MarkConnectionLevelWriteBlocked() {
+ session_->MarkConnectionLevelWriteBlocked(stream_id_);
+ }
+
+ private:
+ QuicSession* const session_;
+ const QuicStreamId stream_id_;
+};
+
+class TestSession : public QuicSpdySession {
+ public:
+ explicit TestSession(QuicConnection* connection)
+ : QuicSpdySession(connection, DefaultQuicConfig()),
+ crypto_stream_(this),
+ writev_consumes_all_data_(false) {
+ Initialize();
+ this->connection()->SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+ new NullEncrypter());
+ }
+
+ ~TestSession() override { delete connection(); }
+
+ TestCryptoStream* GetCryptoStream() override { return &crypto_stream_; }
+
+ TestStream* CreateOutgoingDynamicStream(SpdyPriority priority) override {
+ TestStream* stream = new TestStream(GetNextOutgoingStreamId(), this);
+ stream->SetPriority(priority);
+ ActivateStream(stream);
+ return stream;
+ }
+
+ TestStream* CreateIncomingDynamicStream(QuicStreamId id) override {
+ // Enforce the limit on the number of open streams.
+ if (GetNumOpenIncomingStreams() + 1 > max_open_incoming_streams()) {
+ connection()->CloseConnection(
+ QUIC_TOO_MANY_OPEN_STREAMS, "Too many streams!",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return nullptr;
+ } else {
+ TestStream* stream = new TestStream(id, this);
+ ActivateStream(stream);
+ return stream;
+ }
+ }
+
+ bool ShouldCreateIncomingDynamicStream(QuicStreamId /*id*/) override {
+ return true;
+ }
+
+ bool ShouldCreateOutgoingDynamicStream() override { return true; }
+
+ bool IsClosedStream(QuicStreamId id) {
+ return QuicSession::IsClosedStream(id);
+ }
+
+ ReliableQuicStream* GetOrCreateDynamicStream(QuicStreamId stream_id) {
+ return QuicSpdySession::GetOrCreateDynamicStream(stream_id);
+ }
+
+ QuicConsumedData WritevData(
+ ReliableQuicStream* stream,
+ QuicStreamId id,
+ QuicIOVector data,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate) override {
+ QuicConsumedData consumed(data.total_length, fin);
+ if (!writev_consumes_all_data_) {
+ consumed = QuicSession::WritevData(stream, id, data, offset, fin,
+ ack_notifier_delegate);
+ }
+ QuicSessionPeer::GetWriteBlockedStreams(this)->UpdateBytesForStream(
+ id, consumed.bytes_consumed);
+ return consumed;
+ }
+
+ void set_writev_consumes_all_data(bool val) {
+ writev_consumes_all_data_ = val;
+ }
+
+ QuicConsumedData SendStreamData(ReliableQuicStream* stream) {
+ struct iovec iov;
+ if (stream->id() != kCryptoStreamId) {
+ this->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ }
+ return WritevData(stream, stream->id(), MakeIOVector("not empty", &iov), 0,
+ true, nullptr);
+ }
+
+ QuicConsumedData SendLargeFakeData(ReliableQuicStream* stream, int bytes) {
+ DCHECK(writev_consumes_all_data_);
+ struct iovec iov;
+ iov.iov_base = nullptr; // should not be read.
+ iov.iov_len = static_cast<size_t>(bytes);
+ return WritevData(stream, stream->id(), QuicIOVector(&iov, 1, bytes), 0,
+ true, nullptr);
+ }
+
+ using QuicSession::PostProcessAfterData;
+
+ private:
+ StrictMock<TestCryptoStream> crypto_stream_;
+
+ bool writev_consumes_all_data_;
+};
+
+class QuicSessionTestBase : public ::testing::TestWithParam<QuicVersion> {
+ protected:
+ explicit QuicSessionTestBase(Perspective perspective)
+ : connection_(
+ new StrictMock<MockQuicConnection>(&helper_,
+ &alarm_factory_,
+ perspective,
+ SupportedVersions(GetParam()))),
+ session_(connection_) {
+ session_.config()->SetInitialStreamFlowControlWindowToSend(
+ kInitialStreamFlowControlWindowForTest);
+ session_.config()->SetInitialSessionFlowControlWindowToSend(
+ kInitialSessionFlowControlWindowForTest);
+ headers_[":host"] = "www.google.com";
+ headers_[":path"] = "/index.hml";
+ headers_[":scheme"] = "http";
+ headers_["cookie"] =
+ "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; "
+ "__utmc=160408618; "
+ "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX"
+ "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX"
+ "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT"
+ "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0"
+ "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh"
+ "1zFMi5vzcns38-8_Sns; "
+ "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-"
+ "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339"
+ "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c"
+ "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%"
+ "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4"
+ "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1"
+ "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP"
+ "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6"
+ "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b"
+ "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6"
+ "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG"
+ "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk"
+ "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn"
+ "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
+ "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
+ connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ }
+
+ void CheckClosedStreams() {
+ for (QuicStreamId i = kCryptoStreamId; i < 100; i++) {
+ if (!base::ContainsKey(closed_streams_, i)) {
+ EXPECT_FALSE(session_.IsClosedStream(i)) << " stream id: " << i;
+ } else {
+ EXPECT_TRUE(session_.IsClosedStream(i)) << " stream id: " << i;
+ }
+ }
+ }
+
+ void CloseStream(QuicStreamId id) {
+ EXPECT_CALL(*connection_, SendRstStream(id, _, _));
+ session_.CloseStream(id);
+ closed_streams_.insert(id);
+ }
+
+ QuicVersion version() const { return connection_->version(); }
+
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+ MockQuicConnectionHelper helper_;
+ MockAlarmFactory alarm_factory_;
+ StrictMock<MockQuicConnection>* connection_;
+ TestSession session_;
+ set<QuicStreamId> closed_streams_;
+ SpdyHeaderBlock headers_;
+};
+
+class QuicSessionTestServer : public QuicSessionTestBase {
+ protected:
+ QuicSessionTestServer() : QuicSessionTestBase(Perspective::IS_SERVER) {}
+};
+
+INSTANTIATE_TEST_CASE_P(Tests,
+ QuicSessionTestServer,
+ ::testing::ValuesIn(AllSupportedVersions()));
+
+TEST_P(QuicSessionTestServer, PeerAddress) {
+ EXPECT_EQ(IPEndPoint(Loopback4(), kTestPort), session_.peer_address());
+}
+
+TEST_P(QuicSessionTestServer, IsCryptoHandshakeConfirmed) {
+ EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed());
+ CryptoHandshakeMessage message;
+ session_.GetCryptoStream()->OnHandshakeMessage(message);
+ EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed());
+}
+
+TEST_P(QuicSessionTestServer, IsClosedStreamDefault) {
+ // Ensure that no streams are initially closed.
+ for (QuicStreamId i = kCryptoStreamId; i < 100; i++) {
+ EXPECT_FALSE(session_.IsClosedStream(i)) << "stream id: " << i;
+ }
+}
+
+TEST_P(QuicSessionTestServer, AvailableStreams) {
+ ASSERT_TRUE(session_.GetOrCreateDynamicStream(9) != nullptr);
+ // Both 5 and 7 should be available.
+ EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 5));
+ EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 7));
+ ASSERT_TRUE(session_.GetOrCreateDynamicStream(7) != nullptr);
+ ASSERT_TRUE(session_.GetOrCreateDynamicStream(5) != nullptr);
+}
+
+TEST_P(QuicSessionTestServer, IsClosedStreamLocallyCreated) {
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ EXPECT_EQ(2u, stream2->id());
+ TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ EXPECT_EQ(4u, stream4->id());
+
+ CheckClosedStreams();
+ CloseStream(4);
+ CheckClosedStreams();
+ CloseStream(2);
+ CheckClosedStreams();
+}
+
+TEST_P(QuicSessionTestServer, IsClosedStreamPeerCreated) {
+ QuicStreamId stream_id1 = kClientDataStreamId1;
+ QuicStreamId stream_id2 = kClientDataStreamId2;
+ session_.GetOrCreateDynamicStream(stream_id1);
+ session_.GetOrCreateDynamicStream(stream_id2);
+
+ CheckClosedStreams();
+ CloseStream(stream_id1);
+ CheckClosedStreams();
+ CloseStream(stream_id2);
+ // Create a stream, and make another available.
+ ReliableQuicStream* stream3 =
+ session_.GetOrCreateDynamicStream(stream_id2 + 4);
+ CheckClosedStreams();
+ // Close one, but make sure the other is still not closed
+ CloseStream(stream3->id());
+ CheckClosedStreams();
+}
+
+TEST_P(QuicSessionTestServer, MaximumAvailableOpenedStreams) {
+ QuicStreamId stream_id = kClientDataStreamId1;
+ session_.GetOrCreateDynamicStream(stream_id);
+ EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
+ EXPECT_NE(nullptr,
+ session_.GetOrCreateDynamicStream(
+ stream_id + 2 * (session_.max_open_incoming_streams() - 1)));
+}
+
+TEST_P(QuicSessionTestServer, TooManyAvailableStreams) {
+ QuicStreamId stream_id1 = kClientDataStreamId1;
+ QuicStreamId stream_id2;
+ EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id1));
+ // A stream ID which is too large to create.
+ stream_id2 = stream_id1 + 2 * session_.MaxAvailableStreams() + 4;
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_TOO_MANY_AVAILABLE_STREAMS, _, _));
+ EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream(stream_id2));
+}
+
+TEST_P(QuicSessionTestServer, ManyAvailableStreams) {
+ // When max_open_streams_ is 200, should be able to create 200 streams
+ // out-of-order, that is, creating the one with the largest stream ID first.
+ QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200);
+ QuicStreamId stream_id = kClientDataStreamId1;
+ // Create one stream.
+ session_.GetOrCreateDynamicStream(stream_id);
+ EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
+ // Create the largest stream ID of a threatened total of 200 streams.
+ session_.GetOrCreateDynamicStream(stream_id + 2 * (200 - 1));
+}
+
+TEST_P(QuicSessionTestServer, DebugDFatalIfMarkingClosedStreamWriteBlocked) {
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ QuicStreamId closed_stream_id = stream2->id();
+ // Close the stream.
+ EXPECT_CALL(*connection_, SendRstStream(closed_stream_id, _, _));
+ stream2->Reset(QUIC_BAD_APPLICATION_PAYLOAD);
+ EXPECT_QUIC_BUG(session_.MarkConnectionLevelWriteBlocked(closed_stream_id),
+ "Marking unknown stream 2 blocked.");
+}
+
+TEST_P(QuicSessionTestServer, OnCanWrite) {
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+
+ session_.MarkConnectionLevelWriteBlocked(stream2->id());
+ session_.MarkConnectionLevelWriteBlocked(stream6->id());
+ session_.MarkConnectionLevelWriteBlocked(stream4->id());
+
+ InSequence s;
+ StreamBlocker stream2_blocker(&session_, stream2->id());
+
+ // Reregister, to test the loop limit.
+ EXPECT_CALL(*stream2, OnCanWrite())
+ .WillOnce(Invoke(&stream2_blocker,
+ &StreamBlocker::MarkConnectionLevelWriteBlocked));
+ // 2 will get called a second time as it didn't finish its block
+ EXPECT_CALL(*stream2, OnCanWrite());
+ EXPECT_CALL(*stream6, OnCanWrite());
+ // 4 will not get called, as we exceeded the loop limit.
+ session_.OnCanWrite();
+ EXPECT_TRUE(session_.WillingAndAbleToWrite());
+}
+
+TEST_P(QuicSessionTestServer, TestBatchedWrites) {
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+
+ session_.set_writev_consumes_all_data(true);
+ session_.MarkConnectionLevelWriteBlocked(stream2->id());
+ session_.MarkConnectionLevelWriteBlocked(stream4->id());
+
+ StreamBlocker stream2_blocker(&session_, stream2->id());
+ StreamBlocker stream4_blocker(&session_, stream4->id());
+ StreamBlocker stream6_blocker(&session_, stream6->id());
+ // With two sessions blocked, we should get two write calls. They should both
+ // go to the first stream as it will only write 6k and mark itself blocked
+ // again.
+ InSequence s;
+ EXPECT_CALL(*stream2, OnCanWrite())
+ .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor(
+ &TestSession::SendLargeFakeData,
+ base::Unretained(&session_), stream2, 6000))),
+ Invoke(&stream2_blocker,
+ &StreamBlocker::MarkConnectionLevelWriteBlocked)));
+ EXPECT_CALL(*stream2, OnCanWrite())
+ .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor(
+ &TestSession::SendLargeFakeData,
+ base::Unretained(&session_), stream2, 6000))),
+ Invoke(&stream2_blocker,
+ &StreamBlocker::MarkConnectionLevelWriteBlocked)));
+ session_.OnCanWrite();
+
+ // We should get one more call for stream2, at which point it has used its
+ // write quota and we move over to stream 4.
+ EXPECT_CALL(*stream2, OnCanWrite())
+ .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor(
+ &TestSession::SendLargeFakeData,
+ base::Unretained(&session_), stream2, 6000))),
+ Invoke(&stream2_blocker,
+ &StreamBlocker::MarkConnectionLevelWriteBlocked)));
+ EXPECT_CALL(*stream4, OnCanWrite())
+ .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor(
+ &TestSession::SendLargeFakeData,
+ base::Unretained(&session_), stream4, 6000))),
+ Invoke(&stream4_blocker,
+ &StreamBlocker::MarkConnectionLevelWriteBlocked)));
+ session_.OnCanWrite();
+
+ // Now let stream 4 do the 2nd of its 3 writes, but add a block for a high
+ // priority stream 6. 4 should be preempted. 6 will write but *not* block so
+ // will cede back to 4.
+ stream6->SetPriority(kHighestPriority);
+ EXPECT_CALL(*stream4, OnCanWrite())
+ .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor(
+ &TestSession::SendLargeFakeData,
+ base::Unretained(&session_), stream4, 6000))),
+ Invoke(&stream4_blocker,
+ &StreamBlocker::MarkConnectionLevelWriteBlocked),
+ Invoke(&stream6_blocker,
+ &StreamBlocker::MarkConnectionLevelWriteBlocked)));
+ EXPECT_CALL(*stream6, OnCanWrite())
+ .WillOnce(testing::IgnoreResult(
+ Invoke(CreateFunctor(&TestSession::SendLargeFakeData,
+ base::Unretained(&session_), stream4, 6000))));
+ session_.OnCanWrite();
+
+ // Stream4 alread did 6k worth of writes, so after doing another 12k it should
+ // cede and 2 should resume.
+ EXPECT_CALL(*stream4, OnCanWrite())
+ .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor(
+ &TestSession::SendLargeFakeData,
+ base::Unretained(&session_), stream4, 12000))),
+ Invoke(&stream4_blocker,
+ &StreamBlocker::MarkConnectionLevelWriteBlocked)));
+ EXPECT_CALL(*stream2, OnCanWrite())
+ .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor(
+ &TestSession::SendLargeFakeData,
+ base::Unretained(&session_), stream2, 6000))),
+ Invoke(&stream2_blocker,
+ &StreamBlocker::MarkConnectionLevelWriteBlocked)));
+ session_.OnCanWrite();
+}
+
+TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) {
+ // Encryption needs to be established before data can be sent.
+ CryptoHandshakeMessage msg;
+ session_.GetCryptoStream()->OnHandshakeMessage(msg);
+
+ // Drive congestion control manually.
+ MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>;
+ QuicConnectionPeer::SetSendAlgorithm(session_.connection(), kDefaultPathId,
+ send_algorithm);
+
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+
+ session_.MarkConnectionLevelWriteBlocked(stream2->id());
+ session_.MarkConnectionLevelWriteBlocked(stream6->id());
+ session_.MarkConnectionLevelWriteBlocked(stream4->id());
+
+ EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _))
+ .WillRepeatedly(Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(*send_algorithm, GetCongestionWindow())
+ .WillRepeatedly(Return(kMaxPacketSize * 10));
+ EXPECT_CALL(*send_algorithm, InRecovery()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*stream2, OnCanWrite())
+ .WillOnce(testing::IgnoreResult(
+ Invoke(CreateFunctor(&TestSession::SendStreamData,
+ base::Unretained(&session_), stream2))));
+ EXPECT_CALL(*stream4, OnCanWrite())
+ .WillOnce(testing::IgnoreResult(
+ Invoke(CreateFunctor(&TestSession::SendStreamData,
+ base::Unretained(&session_), stream4))));
+ EXPECT_CALL(*stream6, OnCanWrite())
+ .WillOnce(testing::IgnoreResult(
+ Invoke(CreateFunctor(&TestSession::SendStreamData,
+ base::Unretained(&session_), stream6))));
+
+ // Expect that we only send one packet, the writes from different streams
+ // should be bundled together.
+ MockPacketWriter* writer = static_cast<MockPacketWriter*>(
+ QuicConnectionPeer::GetWriter(session_.connection()));
+ EXPECT_CALL(*writer, WritePacket(_, _, _, _, _))
+ .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
+ EXPECT_CALL(*send_algorithm, OnPacketSent(_, _, _, _, _));
+ EXPECT_CALL(*send_algorithm, OnApplicationLimited(_));
+ session_.OnCanWrite();
+ EXPECT_FALSE(session_.WillingAndAbleToWrite());
+}
+
+TEST_P(QuicSessionTestServer, OnCanWriteCongestionControlBlocks) {
+ InSequence s;
+
+ // Drive congestion control manually.
+ MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>;
+ QuicConnectionPeer::SetSendAlgorithm(session_.connection(), kDefaultPathId,
+ send_algorithm);
+
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+
+ session_.MarkConnectionLevelWriteBlocked(stream2->id());
+ session_.MarkConnectionLevelWriteBlocked(stream6->id());
+ session_.MarkConnectionLevelWriteBlocked(stream4->id());
+
+ StreamBlocker stream2_blocker(&session_, stream2->id());
+ EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _))
+ .WillOnce(Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(*stream2, OnCanWrite());
+ EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _))
+ .WillOnce(Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(*stream6, OnCanWrite());
+ EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _))
+ .WillOnce(Return(QuicTime::Delta::Infinite()));
+ // stream4->OnCanWrite is not called.
+
+ session_.OnCanWrite();
+ EXPECT_TRUE(session_.WillingAndAbleToWrite());
+
+ // Still congestion-control blocked.
+ EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _))
+ .WillOnce(Return(QuicTime::Delta::Infinite()));
+ session_.OnCanWrite();
+ EXPECT_TRUE(session_.WillingAndAbleToWrite());
+
+ // stream4->OnCanWrite is called once the connection stops being
+ // congestion-control blocked.
+ EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _))
+ .WillOnce(Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(*stream4, OnCanWrite());
+ EXPECT_CALL(*send_algorithm, OnApplicationLimited(_));
+ session_.OnCanWrite();
+ EXPECT_FALSE(session_.WillingAndAbleToWrite());
+}
+
+TEST_P(QuicSessionTestServer, OnCanWriteWriterBlocks) {
+ // Drive congestion control manually in order to ensure that
+ // application-limited signaling is handled correctly.
+ MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>;
+ QuicConnectionPeer::SetSendAlgorithm(session_.connection(), kDefaultPathId,
+ send_algorithm);
+ EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _))
+ .WillRepeatedly(Return(QuicTime::Delta::Zero()));
+
+ // Drive packet writer manually.
+ MockPacketWriter* writer = static_cast<MockPacketWriter*>(
+ QuicConnectionPeer::GetWriter(session_.connection()));
+ EXPECT_CALL(*writer, IsWriteBlocked()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*writer, IsWriteBlockedDataBuffered())
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*writer, WritePacket(_, _, _, _, _)).Times(0);
+
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+
+ session_.MarkConnectionLevelWriteBlocked(stream2->id());
+
+ EXPECT_CALL(*stream2, OnCanWrite()).Times(0);
+ EXPECT_CALL(*send_algorithm, OnApplicationLimited(_)).Times(0);
+
+ session_.OnCanWrite();
+ EXPECT_TRUE(session_.WillingAndAbleToWrite());
+}
+
+TEST_P(QuicSessionTestServer, BufferedHandshake) {
+ EXPECT_FALSE(session_.HasPendingHandshake()); // Default value.
+
+ // Test that blocking other streams does not change our status.
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ StreamBlocker stream2_blocker(&session_, stream2->id());
+ stream2_blocker.MarkConnectionLevelWriteBlocked();
+ EXPECT_FALSE(session_.HasPendingHandshake());
+
+ TestStream* stream3 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ StreamBlocker stream3_blocker(&session_, stream3->id());
+ stream3_blocker.MarkConnectionLevelWriteBlocked();
+ EXPECT_FALSE(session_.HasPendingHandshake());
+
+ // Blocking (due to buffering of) the Crypto stream is detected.
+ session_.MarkConnectionLevelWriteBlocked(kCryptoStreamId);
+ EXPECT_TRUE(session_.HasPendingHandshake());
+
+ TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ StreamBlocker stream4_blocker(&session_, stream4->id());
+ stream4_blocker.MarkConnectionLevelWriteBlocked();
+ EXPECT_TRUE(session_.HasPendingHandshake());
+
+ InSequence s;
+ // Force most streams to re-register, which is common scenario when we block
+ // the Crypto stream, and only the crypto stream can "really" write.
+
+ // Due to prioritization, we *should* be asked to write the crypto stream
+ // first.
+ // Don't re-register the crypto stream (which signals complete writing).
+ TestCryptoStream* crypto_stream = session_.GetCryptoStream();
+ EXPECT_CALL(*crypto_stream, OnCanWrite());
+
+ EXPECT_CALL(*stream2, OnCanWrite());
+ EXPECT_CALL(*stream3, OnCanWrite());
+ EXPECT_CALL(*stream4, OnCanWrite())
+ .WillOnce(Invoke(&stream4_blocker,
+ &StreamBlocker::MarkConnectionLevelWriteBlocked));
+
+ session_.OnCanWrite();
+ EXPECT_TRUE(session_.WillingAndAbleToWrite());
+ EXPECT_FALSE(session_.HasPendingHandshake()); // Crypto stream wrote.
+}
+
+TEST_P(QuicSessionTestServer, OnCanWriteWithClosedStream) {
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+
+ session_.MarkConnectionLevelWriteBlocked(stream2->id());
+ session_.MarkConnectionLevelWriteBlocked(stream6->id());
+ session_.MarkConnectionLevelWriteBlocked(stream4->id());
+ CloseStream(stream6->id());
+
+ InSequence s;
+ EXPECT_CALL(*stream2, OnCanWrite());
+ EXPECT_CALL(*stream4, OnCanWrite());
+ session_.OnCanWrite();
+ EXPECT_FALSE(session_.WillingAndAbleToWrite());
+}
+
+TEST_P(QuicSessionTestServer, OnCanWriteLimitsNumWritesIfFlowControlBlocked) {
+ // Drive congestion control manually in order to ensure that
+ // application-limited signaling is handled correctly.
+ MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>;
+ QuicConnectionPeer::SetSendAlgorithm(session_.connection(), kDefaultPathId,
+ send_algorithm);
+ EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _))
+ .WillRepeatedly(Return(QuicTime::Delta::Zero()));
+
+ // Ensure connection level flow control blockage.
+ QuicFlowControllerPeer::SetSendWindowOffset(session_.flow_controller(), 0);
+ EXPECT_TRUE(session_.flow_controller()->IsBlocked());
+ EXPECT_TRUE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
+
+ // Mark the crypto and headers streams as write blocked, we expect them to be
+ // allowed to write later.
+ session_.MarkConnectionLevelWriteBlocked(kCryptoStreamId);
+ session_.MarkConnectionLevelWriteBlocked(kHeadersStreamId);
+
+ // Create a data stream, and although it is write blocked we never expect it
+ // to be allowed to write as we are connection level flow control blocked.
+ TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ session_.MarkConnectionLevelWriteBlocked(stream->id());
+ EXPECT_CALL(*stream, OnCanWrite()).Times(0);
+
+ // The crypto and headers streams should be called even though we are
+ // connection flow control blocked.
+ TestCryptoStream* crypto_stream = session_.GetCryptoStream();
+ EXPECT_CALL(*crypto_stream, OnCanWrite());
+ TestHeadersStream* headers_stream = new TestHeadersStream(&session_);
+ QuicSpdySessionPeer::SetHeadersStream(&session_, headers_stream);
+ EXPECT_CALL(*headers_stream, OnCanWrite());
+
+ // After the crypto and header streams perform a write, the connection will be
+ // blocked by the flow control, hence it should become application-limited.
+ EXPECT_CALL(*send_algorithm, OnApplicationLimited(_));
+
+ session_.OnCanWrite();
+ EXPECT_FALSE(session_.WillingAndAbleToWrite());
+}
+
+TEST_P(QuicSessionTestServer, SendGoAway) {
+ MockPacketWriter* writer = static_cast<MockPacketWriter*>(
+ QuicConnectionPeer::GetWriter(session_.connection()));
+ EXPECT_CALL(*writer, WritePacket(_, _, _, _, _))
+ .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
+ EXPECT_CALL(*connection_, SendGoAway(_, _, _))
+ .WillOnce(Invoke(connection_, &MockQuicConnection::ReallySendGoAway));
+ session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away.");
+ EXPECT_TRUE(session_.goaway_sent());
+
+ const QuicStreamId kTestStreamId = 5u;
+ EXPECT_CALL(*connection_,
+ SendRstStream(kTestStreamId, QUIC_STREAM_PEER_GOING_AWAY, 0))
+ .Times(0);
+ EXPECT_TRUE(session_.GetOrCreateDynamicStream(kTestStreamId));
+}
+
+TEST_P(QuicSessionTestServer, IncreasedTimeoutAfterCryptoHandshake) {
+ EXPECT_EQ(kInitialIdleTimeoutSecs + 3,
+ QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
+ CryptoHandshakeMessage msg;
+ session_.GetCryptoStream()->OnHandshakeMessage(msg);
+ EXPECT_EQ(kMaximumIdleTimeoutSecs + 3,
+ QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
+}
+
+TEST_P(QuicSessionTestServer, RstStreamBeforeHeadersDecompressed) {
+ // Send two bytes of payload.
+ QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT"));
+ session_.OnStreamFrame(data1);
+ EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams());
+
+ EXPECT_CALL(*connection_, SendRstStream(kClientDataStreamId1, _, _));
+ QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM,
+ 0);
+ session_.OnRstStream(rst1);
+ EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+ // Connection should remain alive.
+ EXPECT_TRUE(connection_->connected());
+}
+
+TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedStream) {
+ // Test that if a stream is flow control blocked, then on receipt of the SHLO
+ // containing a suitable send window offset, the stream becomes unblocked.
+
+ // Ensure that Writev consumes all the data it is given (simulate no socket
+ // blocking).
+ session_.set_writev_consumes_all_data(true);
+
+ // Create a stream, and send enough data to make it flow control blocked.
+ TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ string body(kMinimumFlowControlSendWindow, '.');
+ EXPECT_FALSE(stream2->flow_controller()->IsBlocked());
+ EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
+ EXPECT_CALL(*connection_, SendBlocked(_)).Times(AtLeast(1));
+ EXPECT_CALL(*connection_, SendBlocked(0));
+ stream2->WriteOrBufferBody(body, false, nullptr);
+ EXPECT_TRUE(stream2->flow_controller()->IsBlocked());
+ EXPECT_TRUE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_TRUE(session_.IsStreamFlowControlBlocked());
+
+ // The handshake message will call OnCanWrite, so the stream can resume
+ // writing.
+ EXPECT_CALL(*stream2, OnCanWrite());
+ // Now complete the crypto handshake, resulting in an increased flow control
+ // send window.
+ CryptoHandshakeMessage msg;
+ session_.GetCryptoStream()->OnHandshakeMessage(msg);
+
+ // Stream is now unblocked.
+ EXPECT_FALSE(stream2->flow_controller()->IsBlocked());
+ EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
+}
+
+TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedCryptoStream) {
+ // Test that if the crypto stream is flow control blocked, then if the SHLO
+ // contains a larger send window offset, the stream becomes unblocked.
+ session_.set_writev_consumes_all_data(true);
+ TestCryptoStream* crypto_stream = session_.GetCryptoStream();
+ EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked());
+ EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
+ QuicHeadersStream* headers_stream =
+ QuicSpdySessionPeer::GetHeadersStream(&session_);
+ EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked());
+ EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
+ // Write until the crypto stream is flow control blocked.
+ EXPECT_CALL(*connection_, SendBlocked(kCryptoStreamId));
+ for (QuicStreamId i = 0;
+ !crypto_stream->flow_controller()->IsBlocked() && i < 1000u; i++) {
+ EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
+ QuicConfig config;
+ CryptoHandshakeMessage crypto_message;
+ config.ToHandshakeMessage(&crypto_message);
+ crypto_stream->SendHandshakeMessage(crypto_message);
+ }
+ EXPECT_TRUE(crypto_stream->flow_controller()->IsBlocked());
+ EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked());
+ EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_TRUE(session_.IsStreamFlowControlBlocked());
+ EXPECT_FALSE(session_.HasDataToWrite());
+ EXPECT_TRUE(crypto_stream->HasBufferedData());
+
+ // The handshake message will call OnCanWrite, so the stream can
+ // resume writing.
+ EXPECT_CALL(*crypto_stream, OnCanWrite());
+ // Now complete the crypto handshake, resulting in an increased flow control
+ // send window.
+ CryptoHandshakeMessage msg;
+ session_.GetCryptoStream()->OnHandshakeMessage(msg);
+
+ // Stream is now unblocked and will no longer have buffered data.
+ EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked());
+ EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
+}
+
+#if !defined(OS_IOS)
+// This test is failing flakily for iOS bots.
+// http://crbug.com/425050
+// NOTE: It's not possible to use the standard MAYBE_ convention to disable
+// this test on iOS because when this test gets instantiated it ends up with
+// various names that are dependent on the parameters passed.
+TEST_P(QuicSessionTestServer,
+ HandshakeUnblocksFlowControlBlockedHeadersStream) {
+ // Test that if the header stream is flow control blocked, then if the SHLO
+ // contains a larger send window offset, the stream becomes unblocked.
+ session_.set_writev_consumes_all_data(true);
+ TestCryptoStream* crypto_stream = session_.GetCryptoStream();
+ EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked());
+ EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
+ QuicHeadersStream* headers_stream =
+ QuicSpdySessionPeer::GetHeadersStream(&session_);
+ EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked());
+ EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
+ QuicStreamId stream_id = 5;
+ // Write until the header stream is flow control blocked.
+ EXPECT_CALL(*connection_, SendBlocked(kHeadersStreamId));
+ SpdyHeaderBlock headers;
+ while (!headers_stream->flow_controller()->IsBlocked() && stream_id < 2000) {
+ EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
+ headers["header"] = base::Uint64ToString(base::RandUint64()) +
+ base::Uint64ToString(base::RandUint64()) +
+ base::Uint64ToString(base::RandUint64());
+ headers_stream->WriteHeaders(stream_id, headers.Clone(), true, 0, nullptr);
+ stream_id += 2;
+ }
+ // Write once more to ensure that the headers stream has buffered data. The
+ // random headers may have exactly filled the flow control window.
+ headers_stream->WriteHeaders(stream_id, std::move(headers), true, 0, nullptr);
+ EXPECT_TRUE(headers_stream->HasBufferedData());
+
+ EXPECT_TRUE(headers_stream->flow_controller()->IsBlocked());
+ EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked());
+ EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_TRUE(session_.IsStreamFlowControlBlocked());
+ EXPECT_FALSE(session_.HasDataToWrite());
+
+ // Now complete the crypto handshake, resulting in an increased flow control
+ // send window.
+ CryptoHandshakeMessage msg;
+ session_.GetCryptoStream()->OnHandshakeMessage(msg);
+
+ // Stream is now unblocked and will no longer have buffered data.
+ EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked());
+ EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
+ EXPECT_FALSE(headers_stream->HasBufferedData());
+}
+#endif // !defined(OS_IOS)
+
+TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstOutOfOrder) {
+ // Test that when we receive an out of order stream RST we correctly adjust
+ // our connection level flow control receive window.
+ // On close, the stream should mark as consumed all bytes between the highest
+ // byte consumed so far and the final byte offset from the RST frame.
+ TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+
+ const QuicStreamOffset kByteOffset =
+ 1 + kInitialSessionFlowControlWindowForTest / 2;
+
+ // Expect no stream WINDOW_UPDATE frames, as stream read side closed.
+ EXPECT_CALL(*connection_, SendWindowUpdate(stream->id(), _)).Times(0);
+ // We do expect a connection level WINDOW_UPDATE when the stream is reset.
+ EXPECT_CALL(*connection_,
+ SendWindowUpdate(
+ 0, kInitialSessionFlowControlWindowForTest + kByteOffset));
+
+ EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _));
+ QuicRstStreamFrame rst_frame(stream->id(), QUIC_STREAM_CANCELLED,
+ kByteOffset);
+ session_.OnRstStream(rst_frame);
+ session_.PostProcessAfterData();
+ EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed());
+}
+
+TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingFinAndLocalReset) {
+ // Test the situation where we receive a FIN on a stream, and before we fully
+ // consume all the data from the sequencer buffer we locally RST the stream.
+ // The bytes between highest consumed byte, and the final byte offset that we
+ // determined when the FIN arrived, should be marked as consumed at the
+ // connection level flow controller when the stream is reset.
+ TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+
+ const QuicStreamOffset kByteOffset =
+ kInitialSessionFlowControlWindowForTest / 2 - 1;
+ QuicStreamFrame frame(stream->id(), true, kByteOffset, ".");
+ session_.OnStreamFrame(frame);
+ session_.PostProcessAfterData();
+ EXPECT_TRUE(connection_->connected());
+
+ EXPECT_EQ(0u, stream->flow_controller()->bytes_consumed());
+ EXPECT_EQ(kByteOffset + frame.data_length,
+ stream->flow_controller()->highest_received_byte_offset());
+
+ // Reset stream locally.
+ EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _));
+ stream->Reset(QUIC_STREAM_CANCELLED);
+ EXPECT_EQ(kByteOffset + frame.data_length,
+ session_.flow_controller()->bytes_consumed());
+}
+
+TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingFinAfterRst) {
+ // Test that when we RST the stream (and tear down stream state), and then
+ // receive a FIN from the peer, we correctly adjust our connection level flow
+ // control receive window.
+
+ // Connection starts with some non-zero highest received byte offset,
+ // due to other active streams.
+ const uint64_t kInitialConnectionBytesConsumed = 567;
+ const uint64_t kInitialConnectionHighestReceivedOffset = 1234;
+ EXPECT_LT(kInitialConnectionBytesConsumed,
+ kInitialConnectionHighestReceivedOffset);
+ session_.flow_controller()->UpdateHighestReceivedOffset(
+ kInitialConnectionHighestReceivedOffset);
+ session_.flow_controller()->AddBytesConsumed(kInitialConnectionBytesConsumed);
+
+ // Reset our stream: this results in the stream being closed locally.
+ TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _));
+ stream->Reset(QUIC_STREAM_CANCELLED);
+
+ // Now receive a response from the peer with a FIN. We should handle this by
+ // adjusting the connection level flow control receive window to take into
+ // account the total number of bytes sent by the peer.
+ const QuicStreamOffset kByteOffset = 5678;
+ string body = "hello";
+ QuicStreamFrame frame(stream->id(), true, kByteOffset, StringPiece(body));
+ session_.OnStreamFrame(frame);
+
+ QuicStreamOffset total_stream_bytes_sent_by_peer =
+ kByteOffset + body.length();
+ EXPECT_EQ(kInitialConnectionBytesConsumed + total_stream_bytes_sent_by_peer,
+ session_.flow_controller()->bytes_consumed());
+ EXPECT_EQ(
+ kInitialConnectionHighestReceivedOffset + total_stream_bytes_sent_by_peer,
+ session_.flow_controller()->highest_received_byte_offset());
+}
+
+TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstAfterRst) {
+ // Test that when we RST the stream (and tear down stream state), and then
+ // receive a RST from the peer, we correctly adjust our connection level flow
+ // control receive window.
+
+ // Connection starts with some non-zero highest received byte offset,
+ // due to other active streams.
+ const uint64_t kInitialConnectionBytesConsumed = 567;
+ const uint64_t kInitialConnectionHighestReceivedOffset = 1234;
+ EXPECT_LT(kInitialConnectionBytesConsumed,
+ kInitialConnectionHighestReceivedOffset);
+ session_.flow_controller()->UpdateHighestReceivedOffset(
+ kInitialConnectionHighestReceivedOffset);
+ session_.flow_controller()->AddBytesConsumed(kInitialConnectionBytesConsumed);
+
+ // Reset our stream: this results in the stream being closed locally.
+ TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _));
+ stream->Reset(QUIC_STREAM_CANCELLED);
+ EXPECT_TRUE(ReliableQuicStreamPeer::read_side_closed(stream));
+
+ // Now receive a RST from the peer. We should handle this by adjusting the
+ // connection level flow control receive window to take into account the total
+ // number of bytes sent by the peer.
+ const QuicStreamOffset kByteOffset = 5678;
+ QuicRstStreamFrame rst_frame(stream->id(), QUIC_STREAM_CANCELLED,
+ kByteOffset);
+ session_.OnRstStream(rst_frame);
+
+ EXPECT_EQ(kInitialConnectionBytesConsumed + kByteOffset,
+ session_.flow_controller()->bytes_consumed());
+ EXPECT_EQ(kInitialConnectionHighestReceivedOffset + kByteOffset,
+ session_.flow_controller()->highest_received_byte_offset());
+}
+
+TEST_P(QuicSessionTestServer, InvalidStreamFlowControlWindowInHandshake) {
+ // Test that receipt of an invalid (< default) stream flow control window from
+ // the peer results in the connection being torn down.
+ const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1;
+ QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(session_.config(),
+ kInvalidWindow);
+
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _));
+ session_.OnConfigNegotiated();
+}
+
+TEST_P(QuicSessionTestServer, InvalidSessionFlowControlWindowInHandshake) {
+ // Test that receipt of an invalid (< default) session flow control window
+ // from the peer results in the connection being torn down.
+ const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1;
+ QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(session_.config(),
+ kInvalidWindow);
+
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _));
+ session_.OnConfigNegotiated();
+}
+
+TEST_P(QuicSessionTestServer, FlowControlWithInvalidFinalOffset) {
+ // Test that if we receive a stream RST with a highest byte offset that
+ // violates flow control, that we close the connection.
+ const uint64_t kLargeOffset = kInitialSessionFlowControlWindowForTest + 1;
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _))
+ .Times(2);
+
+ // Check that stream frame + FIN results in connection close.
+ TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _));
+ stream->Reset(QUIC_STREAM_CANCELLED);
+ QuicStreamFrame frame(stream->id(), true, kLargeOffset, StringPiece());
+ session_.OnStreamFrame(frame);
+
+ // Check that RST results in connection close.
+ QuicRstStreamFrame rst_frame(stream->id(), QUIC_STREAM_CANCELLED,
+ kLargeOffset);
+ session_.OnRstStream(rst_frame);
+}
+
+TEST_P(QuicSessionTestServer, WindowUpdateUnblocksHeadersStream) {
+ // Test that a flow control blocked headers stream gets unblocked on recipt of
+ // a WINDOW_UPDATE frame.
+
+ // Set the headers stream to be flow control blocked.
+ QuicHeadersStream* headers_stream =
+ QuicSpdySessionPeer::GetHeadersStream(&session_);
+ QuicFlowControllerPeer::SetSendWindowOffset(headers_stream->flow_controller(),
+ 0);
+ EXPECT_TRUE(headers_stream->flow_controller()->IsBlocked());
+ EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_TRUE(session_.IsStreamFlowControlBlocked());
+
+ // Unblock the headers stream by supplying a WINDOW_UPDATE.
+ QuicWindowUpdateFrame window_update_frame(headers_stream->id(),
+ 2 * kMinimumFlowControlSendWindow);
+ session_.OnWindowUpdateFrame(window_update_frame);
+ EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked());
+ EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
+ EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
+}
+
+TEST_P(QuicSessionTestServer, TooManyUnfinishedStreamsCauseServerRejectStream) {
+ // If a buggy/malicious peer creates too many streams that are not ended
+ // with a FIN or RST then we send an RST to refuse streams.
+ const QuicStreamId kMaxStreams = 5;
+ QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams);
+ const QuicStreamId kFirstStreamId = kClientDataStreamId1;
+ const QuicStreamId kFinalStreamId = kClientDataStreamId1 + 2 * kMaxStreams;
+
+ // Create kMaxStreams data streams, and close them all without receiving a
+ // FIN or a RST_STREAM from the client.
+ for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += 2) {
+ QuicStreamFrame data1(i, false, 0, StringPiece("HT"));
+ session_.OnStreamFrame(data1);
+ // EXPECT_EQ(1u, session_.GetNumOpenStreams());
+ EXPECT_CALL(*connection_, SendRstStream(i, _, _));
+ session_.CloseStream(i);
+ }
+
+ EXPECT_CALL(*connection_,
+ SendRstStream(kFinalStreamId, QUIC_REFUSED_STREAM, _))
+ .Times(1);
+ // Create one more data streams to exceed limit of open stream.
+ QuicStreamFrame data1(kFinalStreamId, false, 0, StringPiece("HT"));
+ session_.OnStreamFrame(data1);
+
+ // Called after any new data is received by the session, and triggers the
+ // call to close the connection.
+ session_.PostProcessAfterData();
+}
+
+TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) {
+ // Verify that a draining stream (which has received a FIN but not consumed
+ // it) does not count against the open quota (because it is closed from the
+ // protocol point of view).
+ EXPECT_CALL(*connection_, SendRstStream(_, QUIC_REFUSED_STREAM, _)).Times(0);
+ const QuicStreamId kMaxStreams = 5;
+ QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams);
+
+ // Create kMaxStreams + 1 data streams, and mark them draining.
+ const QuicStreamId kFirstStreamId = kClientDataStreamId1;
+ const QuicStreamId kFinalStreamId =
+ kClientDataStreamId1 + 2 * kMaxStreams + 1;
+ for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += 2) {
+ QuicStreamFrame data1(i, true, 0, StringPiece("HT"));
+ session_.OnStreamFrame(data1);
+ EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams());
+ session_.StreamDraining(i);
+ EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
+ }
+
+ // Called after any new data is received by the session, and triggers the call
+ // to close the connection.
+ session_.PostProcessAfterData();
+}
+
+TEST_P(QuicSessionTestServer, TestMaxIncomingAndOutgoingStreamsAllowed) {
+ // Tests that on server side, the value of max_open_incoming/outgoing streams
+ // are setup correctly during negotiation.
+ // The value for outgoing stream is limited to negotiated value and for
+ // incoming stream it is set to be larger than that.
+ session_.OnConfigNegotiated();
+ // The max number of open outgoing streams is less than that of incoming
+ // streams, and it should be same as negotiated value.
+ EXPECT_LT(session_.max_open_outgoing_streams(),
+ session_.max_open_incoming_streams());
+ EXPECT_EQ(session_.max_open_outgoing_streams(),
+ kDefaultMaxStreamsPerConnection);
+ EXPECT_GT(session_.max_open_incoming_streams(),
+ kDefaultMaxStreamsPerConnection);
+}
+
+TEST_P(QuicSessionTestServer, EnableFHOLThroughConfigOption) {
+ QuicConfigPeer::SetReceivedForceHolBlocking(session_.config());
+ session_.OnConfigNegotiated();
+ if (version() <= QUIC_VERSION_35) {
+ EXPECT_FALSE(session_.force_hol_blocking());
+ } else {
+ EXPECT_TRUE(session_.force_hol_blocking());
+ }
+}
+
+class QuicSessionTestClient : public QuicSessionTestBase {
+ protected:
+ QuicSessionTestClient() : QuicSessionTestBase(Perspective::IS_CLIENT) {}
+};
+
+INSTANTIATE_TEST_CASE_P(Tests,
+ QuicSessionTestClient,
+ ::testing::ValuesIn(AllSupportedVersions()));
+
+TEST_P(QuicSessionTestClient, AvailableStreamsClient) {
+ ASSERT_TRUE(session_.GetOrCreateDynamicStream(6) != nullptr);
+ // Both 2 and 4 should be available.
+ EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 2));
+ EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 4));
+ ASSERT_TRUE(session_.GetOrCreateDynamicStream(2) != nullptr);
+ ASSERT_TRUE(session_.GetOrCreateDynamicStream(4) != nullptr);
+ // And 5 should be not available.
+ EXPECT_FALSE(QuicSessionPeer::IsStreamAvailable(&session_, 5));
+}
+
+TEST_P(QuicSessionTestClient, RecordFinAfterReadSideClosed) {
+ // Verify that an incoming FIN is recorded in a stream object even if the read
+ // side has been closed. This prevents an entry from being made in
+ // locally_closed_streams_highest_offset_ (which will never be deleted).
+ TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority);
+ QuicStreamId stream_id = stream->id();
+
+ // Close the read side manually.
+ ReliableQuicStreamPeer::CloseReadSide(stream);
+
+ // Receive a stream data frame with FIN.
+ QuicStreamFrame frame(stream_id, true, 0, StringPiece());
+ session_.OnStreamFrame(frame);
+ EXPECT_TRUE(stream->fin_received());
+
+ // Reset stream locally.
+ EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _));
+ stream->Reset(QUIC_STREAM_CANCELLED);
+ EXPECT_TRUE(ReliableQuicStreamPeer::read_side_closed(stream));
+
+ // Allow the session to delete the stream object.
+ session_.PostProcessAfterData();
+ EXPECT_TRUE(connection_->connected());
+ EXPECT_TRUE(QuicSessionPeer::IsStreamClosed(&session_, stream_id));
+ EXPECT_FALSE(QuicSessionPeer::IsStreamCreated(&session_, stream_id));
+
+ // The stream is not waiting for the arrival of the peer's final offset as it
+ // was received with the FIN earlier.
+ EXPECT_EQ(
+ 0u,
+ QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(&session_).size());
+}
+
+TEST_P(QuicSessionTestClient, TestMaxIncomingAndOutgoingStreamsAllowed) {
+ // Tests that on client side, the value of max_open_incoming/outgoing streams
+ // are setup correctly during negotiation.
+ // When flag is true, the value for outgoing stream is limited to negotiated
+ // value and for incoming stream it is set to be larger than that.
+ session_.OnConfigNegotiated();
+ EXPECT_LT(session_.max_open_outgoing_streams(),
+ session_.max_open_incoming_streams());
+ EXPECT_EQ(session_.max_open_outgoing_streams(),
+ kDefaultMaxStreamsPerConnection);
+}
+
+TEST_P(QuicSessionTestClient, EnableDHDTThroughConnectionOption) {
+ QuicTagVector copt;
+ copt.push_back(kDHDT);
+ QuicConfigPeer::SetConnectionOptionsToSend(session_.config(), copt);
+ session_.OnConfigNegotiated();
+ EXPECT_EQ(QuicHeadersStreamPeer::GetSpdyFramer(session_.headers_stream())
+ .header_encoder_table_size(),
+ 0UL);
+}
+
+TEST_P(QuicSessionTestClient, EnableFHOLThroughConfigOption) {
+ session_.config()->SetForceHolBlocking();
+ session_.OnConfigNegotiated();
+ if (version() <= QUIC_VERSION_35) {
+ EXPECT_FALSE(session_.force_hol_blocking());
+ } else {
+ EXPECT_TRUE(session_.force_hol_blocking());
+ }
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_simple_buffer_allocator.cc b/chromium/net/quic/core/quic_simple_buffer_allocator.cc
new file mode 100644
index 00000000000..efa20edf2f3
--- /dev/null
+++ b/chromium/net/quic/core/quic_simple_buffer_allocator.cc
@@ -0,0 +1,21 @@
+// 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/quic_simple_buffer_allocator.h"
+
+namespace net {
+
+char* SimpleBufferAllocator::New(size_t size) {
+ return new char[size];
+}
+
+char* SimpleBufferAllocator::New(size_t size, bool /* flag_enable */) {
+ return New(size);
+}
+
+void SimpleBufferAllocator::Delete(char* buffer) {
+ delete[] buffer;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_simple_buffer_allocator.h b/chromium/net/quic/core/quic_simple_buffer_allocator.h
new file mode 100644
index 00000000000..a980d03979f
--- /dev/null
+++ b/chromium/net/quic/core/quic_simple_buffer_allocator.h
@@ -0,0 +1,22 @@
+// 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.
+
+#ifndef NET_QUIC_SIMPLE_BUFFER_ALLOCATOR_H_
+#define NET_QUIC_SIMPLE_BUFFER_ALLOCATOR_H_
+
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE SimpleBufferAllocator : public QuicBufferAllocator {
+ public:
+ char* New(size_t size) override;
+ char* New(size_t size, bool flag_enable) override;
+ void Delete(char* buffer) override;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_SIMPLE_BUFFER_ALLOCATOR_H_
diff --git a/chromium/net/quic/core/quic_simple_buffer_allocator_test.cc b/chromium/net/quic/core/quic_simple_buffer_allocator_test.cc
new file mode 100644
index 00000000000..d999162378b
--- /dev/null
+++ b/chromium/net/quic/core/quic_simple_buffer_allocator_test.cc
@@ -0,0 +1,35 @@
+// 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/quic_simple_buffer_allocator.h"
+
+#include "net/quic/core/quic_protocol.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Eq;
+
+namespace net {
+namespace {
+
+TEST(SimpleBufferAllocatorTest, NewDelete) {
+ SimpleBufferAllocator alloc;
+ char* buf = alloc.New(4);
+ EXPECT_NE(nullptr, buf);
+ alloc.Delete(buf);
+}
+
+TEST(SimpleBufferAllocatorTest, DeleteNull) {
+ SimpleBufferAllocator alloc;
+ alloc.Delete(nullptr);
+}
+
+TEST(SimpleBufferAllocatorTest, StoreInUniqueStreamBuffer) {
+ SimpleBufferAllocator alloc;
+ UniqueStreamBuffer buf = NewStreamBuffer(&alloc, 4);
+ buf.reset();
+}
+
+} // namespace
+} // namespace net
diff --git a/chromium/net/quic/core/quic_socket_address_coder.cc b/chromium/net/quic/core/quic_socket_address_coder.cc
new file mode 100644
index 00000000000..9d9a043e3b1
--- /dev/null
+++ b/chromium/net/quic/core/quic_socket_address_coder.cc
@@ -0,0 +1,89 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_socket_address_coder.h"
+
+#include "net/base/ip_address.h"
+#include "net/base/sys_addrinfo.h"
+
+using std::string;
+
+namespace net {
+
+namespace {
+
+// For convenience, the values of these constants match the values of AF_INET
+// and AF_INET6 on Linux.
+const uint16_t kIPv4 = 2;
+const uint16_t kIPv6 = 10;
+
+} // namespace
+
+QuicSocketAddressCoder::QuicSocketAddressCoder() {}
+
+QuicSocketAddressCoder::QuicSocketAddressCoder(const IPEndPoint& address)
+ : address_(address) {}
+
+QuicSocketAddressCoder::~QuicSocketAddressCoder() {}
+
+string QuicSocketAddressCoder::Encode() const {
+ string serialized;
+ uint16_t address_family;
+ switch (address_.GetSockAddrFamily()) {
+ case AF_INET:
+ address_family = kIPv4;
+ break;
+ case AF_INET6:
+ address_family = kIPv6;
+ break;
+ default:
+ return serialized;
+ }
+ serialized.append(reinterpret_cast<const char*>(&address_family),
+ sizeof(address_family));
+ serialized.append(IPAddressToPackedString(address_.address()));
+ uint16_t port = address_.port();
+ serialized.append(reinterpret_cast<const char*>(&port), sizeof(port));
+ return serialized;
+}
+
+bool QuicSocketAddressCoder::Decode(const char* data, size_t length) {
+ uint16_t address_family;
+ if (length < sizeof(address_family)) {
+ return false;
+ }
+ memcpy(&address_family, data, sizeof(address_family));
+ data += sizeof(address_family);
+ length -= sizeof(address_family);
+
+ size_t ip_length;
+ switch (address_family) {
+ case kIPv4:
+ ip_length = IPAddress::kIPv4AddressSize;
+ break;
+ case kIPv6:
+ ip_length = IPAddress::kIPv6AddressSize;
+ break;
+ default:
+ return false;
+ }
+ if (length < ip_length) {
+ return false;
+ }
+ std::vector<uint8_t> ip(ip_length);
+ memcpy(&ip[0], data, ip_length);
+ data += ip_length;
+ length -= ip_length;
+
+ uint16_t port;
+ if (length != sizeof(port)) {
+ return false;
+ }
+ memcpy(&port, data, length);
+
+ address_ = IPEndPoint(IPAddress(ip), port);
+ return true;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/quic_socket_address_coder.h b/chromium/net/quic/core/quic_socket_address_coder.h
index e6f8bf6a08b..e6f8bf6a08b 100644
--- a/chromium/net/quic/quic_socket_address_coder.h
+++ b/chromium/net/quic/core/quic_socket_address_coder.h
diff --git a/chromium/net/quic/core/quic_socket_address_coder_test.cc b/chromium/net/quic/core/quic_socket_address_coder_test.cc
new file mode 100644
index 00000000000..7befddc22f9
--- /dev/null
+++ b/chromium/net/quic/core/quic_socket_address_coder_test.cc
@@ -0,0 +1,126 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_socket_address_coder.h"
+
+#include "net/base/sys_addrinfo.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+
+namespace net {
+namespace test {
+
+TEST(QuicSocketAddressCoderTest, EncodeIPv4) {
+ IPAddress ip;
+ ASSERT_TRUE(ip.AssignFromIPLiteral("4.31.198.44"));
+ QuicSocketAddressCoder coder(IPEndPoint(ip, 0x1234));
+ string serialized = coder.Encode();
+ string expected("\x02\x00\x04\x1f\xc6\x2c\x34\x12", 8);
+ EXPECT_EQ(expected, serialized);
+}
+
+TEST(QuicSocketAddressCoderTest, EncodeIPv6) {
+ IPAddress ip;
+ ASSERT_TRUE(ip.AssignFromIPLiteral("2001:700:300:1800::f"));
+ QuicSocketAddressCoder coder(IPEndPoint(ip, 0x5678));
+ string serialized = coder.Encode();
+ string expected(
+ "\x0a\x00"
+ "\x20\x01\x07\x00\x03\x00\x18\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x0f"
+ "\x78\x56",
+ 20);
+ EXPECT_EQ(expected, serialized);
+}
+
+TEST(QuicSocketAddressCoderTest, DecodeIPv4) {
+ string serialized("\x02\x00\x04\x1f\xc6\x2c\x34\x12", 8);
+ QuicSocketAddressCoder coder;
+ ASSERT_TRUE(coder.Decode(serialized.data(), serialized.length()));
+ EXPECT_EQ(AF_INET, ConvertAddressFamily(GetAddressFamily(coder.ip())));
+ string expected_addr("\x04\x1f\xc6\x2c", 4);
+ EXPECT_EQ(expected_addr, IPAddressToPackedString(coder.ip()));
+ EXPECT_EQ(0x1234, coder.port());
+}
+
+TEST(QuicSocketAddressCoderTest, DecodeIPv6) {
+ string serialized(
+ "\x0a\x00"
+ "\x20\x01\x07\x00\x03\x00\x18\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x0f"
+ "\x78\x56",
+ 20);
+ QuicSocketAddressCoder coder;
+ ASSERT_TRUE(coder.Decode(serialized.data(), serialized.length()));
+ EXPECT_EQ(AF_INET6, ConvertAddressFamily(GetAddressFamily(coder.ip())));
+ string expected_addr(
+ "\x20\x01\x07\x00\x03\x00\x18\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x0f",
+ 16);
+ EXPECT_EQ(expected_addr, IPAddressToPackedString(coder.ip()));
+ EXPECT_EQ(0x5678, coder.port());
+}
+
+TEST(QuicSocketAddressCoderTest, DecodeBad) {
+ string serialized(
+ "\x0a\x00"
+ "\x20\x01\x07\x00\x03\x00\x18\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x0f"
+ "\x78\x56",
+ 20);
+ QuicSocketAddressCoder coder;
+ EXPECT_TRUE(coder.Decode(serialized.data(), serialized.length()));
+ // Append junk.
+ serialized.push_back('\0');
+ EXPECT_FALSE(coder.Decode(serialized.data(), serialized.length()));
+ // Undo.
+ serialized.resize(20);
+ EXPECT_TRUE(coder.Decode(serialized.data(), serialized.length()));
+
+ // Set an unknown address family.
+ serialized[0] = '\x03';
+ EXPECT_FALSE(coder.Decode(serialized.data(), serialized.length()));
+ // Undo.
+ serialized[0] = '\x0a';
+ EXPECT_TRUE(coder.Decode(serialized.data(), serialized.length()));
+
+ // Truncate.
+ size_t len = serialized.length();
+ for (size_t i = 0; i < len; i++) {
+ ASSERT_FALSE(serialized.empty());
+ serialized.erase(serialized.length() - 1);
+ EXPECT_FALSE(coder.Decode(serialized.data(), serialized.length()));
+ }
+ EXPECT_TRUE(serialized.empty());
+}
+
+TEST(QuicSocketAddressCoderTest, EncodeAndDecode) {
+ struct {
+ const char* ip_literal;
+ uint16_t port;
+ } test_case[] = {
+ {"93.184.216.119", 0x1234},
+ {"199.204.44.194", 80},
+ {"149.20.4.69", 443},
+ {"127.0.0.1", 8080},
+ {"2001:700:300:1800::", 0x5678},
+ {"::1", 65534},
+ };
+
+ for (size_t i = 0; i < arraysize(test_case); i++) {
+ IPAddress ip;
+ ASSERT_TRUE(ip.AssignFromIPLiteral(test_case[i].ip_literal));
+ QuicSocketAddressCoder encoder(IPEndPoint(ip, test_case[i].port));
+ string serialized = encoder.Encode();
+
+ QuicSocketAddressCoder decoder;
+ ASSERT_TRUE(decoder.Decode(serialized.data(), serialized.length()));
+ EXPECT_EQ(encoder.ip(), decoder.ip());
+ EXPECT_EQ(encoder.port(), decoder.port());
+ }
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_spdy_session.cc b/chromium/net/quic/core/quic_spdy_session.cc
new file mode 100644
index 00000000000..37a165cb0dc
--- /dev/null
+++ b/chromium/net/quic/core/quic_spdy_session.cc
@@ -0,0 +1,189 @@
+// 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.
+
+#include "net/quic/core/quic_spdy_session.h"
+
+#include <utility>
+
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_headers_stream.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+QuicSpdySession::QuicSpdySession(QuicConnection* connection,
+ const QuicConfig& config)
+ : QuicSession(connection, config),
+ force_hol_blocking_(false),
+ server_push_enabled_(false) {}
+
+QuicSpdySession::~QuicSpdySession() {
+ // Set the streams' session pointers in closed and dynamic stream lists
+ // to null to avoid subsequent use of this session.
+ for (auto* stream : *closed_streams()) {
+ static_cast<QuicSpdyStream*>(stream)->ClearSession();
+ }
+ for (auto const& kv : dynamic_streams()) {
+ static_cast<QuicSpdyStream*>(kv.second)->ClearSession();
+ }
+}
+
+void QuicSpdySession::Initialize() {
+ QuicSession::Initialize();
+
+ if (perspective() == Perspective::IS_SERVER) {
+ set_largest_peer_created_stream_id(kHeadersStreamId);
+ } else {
+ QuicStreamId headers_stream_id = GetNextOutgoingStreamId();
+ DCHECK_EQ(headers_stream_id, kHeadersStreamId);
+ }
+
+ headers_stream_.reset(new QuicHeadersStream(this));
+ DCHECK_EQ(kHeadersStreamId, headers_stream_->id());
+ static_streams()[kHeadersStreamId] = headers_stream_.get();
+}
+
+void QuicSpdySession::OnStreamHeaders(QuicStreamId stream_id,
+ StringPiece headers_data) {
+ QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
+ if (!stream) {
+ // It's quite possible to receive headers after a stream has been reset.
+ return;
+ }
+ stream->OnStreamHeaders(headers_data);
+}
+
+void QuicSpdySession::OnStreamHeadersPriority(QuicStreamId stream_id,
+ SpdyPriority priority) {
+ QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
+ if (!stream) {
+ // It's quite possible to receive headers after a stream has been reset.
+ return;
+ }
+ stream->OnStreamHeadersPriority(priority);
+}
+
+void QuicSpdySession::OnStreamHeadersComplete(QuicStreamId stream_id,
+ bool fin,
+ size_t frame_len) {
+ QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
+ if (!stream) {
+ // It's quite possible to receive headers after a stream has been reset.
+ return;
+ }
+ stream->OnStreamHeadersComplete(fin, frame_len);
+}
+
+void QuicSpdySession::OnStreamHeaderList(QuicStreamId stream_id,
+ bool fin,
+ size_t frame_len,
+ const QuicHeaderList& header_list) {
+ QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
+ if (!stream) {
+ // It's quite possible to receive headers after a stream has been reset.
+ return;
+ }
+ stream->OnStreamHeaderList(fin, frame_len, header_list);
+}
+
+size_t QuicSpdySession::WriteHeaders(
+ QuicStreamId id,
+ SpdyHeaderBlock headers,
+ bool fin,
+ SpdyPriority priority,
+ QuicAckListenerInterface* ack_notifier_delegate) {
+ return headers_stream_->WriteHeaders(id, std::move(headers), fin, priority,
+ ack_notifier_delegate);
+}
+
+void QuicSpdySession::OnHeadersHeadOfLineBlocking(QuicTime::Delta delta) {
+ // Implemented in Chromium for stats tracking.
+}
+
+void QuicSpdySession::RegisterStreamPriority(QuicStreamId id,
+ SpdyPriority priority) {
+ write_blocked_streams()->RegisterStream(id, priority);
+}
+
+void QuicSpdySession::UnregisterStreamPriority(QuicStreamId id) {
+ write_blocked_streams()->UnregisterStream(id);
+}
+
+void QuicSpdySession::UpdateStreamPriority(QuicStreamId id,
+ SpdyPriority new_priority) {
+ write_blocked_streams()->UpdateStreamPriority(id, new_priority);
+}
+
+QuicSpdyStream* QuicSpdySession::GetSpdyDataStream(
+ const QuicStreamId stream_id) {
+ return static_cast<QuicSpdyStream*>(GetOrCreateDynamicStream(stream_id));
+}
+
+void QuicSpdySession::OnPromiseHeaders(QuicStreamId stream_id,
+ StringPiece headers_data) {
+ string error = "OnPromiseHeaders should be overriden in client code.";
+ QUIC_BUG << error;
+ connection()->CloseConnection(QUIC_INTERNAL_ERROR, error,
+ ConnectionCloseBehavior::SILENT_CLOSE);
+}
+
+void QuicSpdySession::OnPromiseHeadersComplete(QuicStreamId stream_id,
+ QuicStreamId promised_stream_id,
+ size_t frame_len) {
+ string error = "OnPromiseHeadersComplete should be overriden in client code.";
+ QUIC_BUG << error;
+ connection()->CloseConnection(QUIC_INTERNAL_ERROR, error,
+ ConnectionCloseBehavior::SILENT_CLOSE);
+}
+
+void QuicSpdySession::OnPromiseHeaderList(QuicStreamId stream_id,
+ QuicStreamId promised_stream_id,
+ size_t frame_len,
+ const QuicHeaderList& header_list) {
+ string error = "OnPromiseHeaderList should be overriden in client code.";
+ QUIC_BUG << error;
+ connection()->CloseConnection(QUIC_INTERNAL_ERROR, error,
+ ConnectionCloseBehavior::SILENT_CLOSE);
+}
+
+void QuicSpdySession::OnConfigNegotiated() {
+ QuicSession::OnConfigNegotiated();
+ if (config()->HasClientSentConnectionOption(kDHDT, perspective())) {
+ headers_stream_->DisableHpackDynamicTable();
+ }
+ const QuicVersion version = connection()->version();
+ if (version > QUIC_VERSION_35 && config()->ForceHolBlocking(perspective())) {
+ force_hol_blocking_ = true;
+ // Autotuning makes sure that the headers stream flow control does
+ // not get in the way, and normal stream and connection level flow
+ // control are active anyway. This is really only for the client
+ // side (and mainly there just in tests and toys), where
+ // autotuning and/or large buffers are not enabled by default.
+ headers_stream_->flow_controller()->set_auto_tune_receive_window(true);
+ }
+
+ if (version > QUIC_VERSION_34) {
+ server_push_enabled_ = FLAGS_quic_enable_server_push_by_default;
+ }
+}
+
+void QuicSpdySession::OnStreamFrameData(QuicStreamId stream_id,
+ const char* data,
+ size_t len,
+ bool fin) {
+ QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
+ if (stream == nullptr) {
+ return;
+ }
+ const QuicStreamOffset offset =
+ stream->flow_controller()->highest_received_byte_offset();
+ const QuicStreamFrame frame(stream_id, fin, offset, StringPiece(data, len));
+ DVLOG(1) << "De-encapsulating DATA frame for stream " << stream_id
+ << " offset " << offset << " len " << len << " fin " << fin;
+ OnStreamFrame(frame);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_spdy_session.h b/chromium/net/quic/core/quic_spdy_session.h
new file mode 100644
index 00000000000..b4db9288efc
--- /dev/null
+++ b/chromium/net/quic/core/quic_spdy_session.h
@@ -0,0 +1,154 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_SPDY_SESSION_H_
+#define NET_QUIC_QUIC_SPDY_SESSION_H_
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_header_list.h"
+#include "net/quic/core/quic_headers_stream.h"
+#include "net/quic/core/quic_session.h"
+#include "net/quic/core/quic_spdy_stream.h"
+
+namespace net {
+
+namespace test {
+class QuicSpdySessionPeer;
+} // namespace test
+
+// A QUIC session with a headers stream.
+class NET_EXPORT_PRIVATE QuicSpdySession : public QuicSession {
+ public:
+ // Does not take ownership of |connection|.
+ QuicSpdySession(QuicConnection* connection, const QuicConfig& config);
+
+ ~QuicSpdySession() override;
+
+ void Initialize() override;
+
+ // Called by |headers_stream_| when headers have been received for a stream.
+ virtual void OnStreamHeaders(QuicStreamId stream_id,
+ base::StringPiece headers_data);
+ // Called by |headers_stream_| when headers with a priority have been
+ // received for this stream. This method will only be called for server
+ // streams.
+ virtual void OnStreamHeadersPriority(QuicStreamId stream_id,
+ SpdyPriority priority);
+ // Called by |headers_stream_| when headers have been completely received
+ // for a stream. |fin| will be true if the fin flag was set in the headers
+ // frame.
+ virtual void OnStreamHeadersComplete(QuicStreamId stream_id,
+ bool fin,
+ size_t frame_len);
+
+ // Called by |headers_stream_| when headers have been completely received
+ // for a stream. |fin| will be true if the fin flag was set in the headers
+ // frame.
+ virtual void OnStreamHeaderList(QuicStreamId stream_id,
+ bool fin,
+ size_t frame_len,
+ const QuicHeaderList& header_list);
+
+ // Called by |headers_stream_| when push promise headers have been
+ // received for a stream.
+ virtual void OnPromiseHeaders(QuicStreamId stream_id,
+ base::StringPiece headers_data);
+
+ // Called by |headers_stream_| when push promise headers have been
+ // completely received. |fin| will be true if the fin flag was set
+ // in the headers.
+ virtual void OnPromiseHeadersComplete(QuicStreamId stream_id,
+ QuicStreamId promised_stream_id,
+ size_t frame_len);
+
+ // Called by |headers_stream_| when push promise headers have been
+ // completely received. |fin| will be true if the fin flag was set
+ // in the headers.
+ virtual void OnPromiseHeaderList(QuicStreamId stream_id,
+ QuicStreamId promised_stream_id,
+ size_t frame_len,
+ const QuicHeaderList& header_list);
+
+ // Writes |headers| for the stream |id| to the dedicated headers stream.
+ // If |fin| is true, then no more data will be sent for the stream |id|.
+ // If provided, |ack_notifier_delegate| will be registered to be notified when
+ // we have seen ACKs for all packets resulting from this call.
+ virtual size_t WriteHeaders(QuicStreamId id,
+ SpdyHeaderBlock headers,
+ bool fin,
+ SpdyPriority priority,
+ QuicAckListenerInterface* ack_notifier_delegate);
+
+ QuicHeadersStream* headers_stream() { return headers_stream_.get(); }
+
+ // Called when Head of Line Blocking happens in the headers stream.
+ // |delta| indicates how long that piece of data has been blocked.
+ 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);
+ // Called by the stream on deletion to clear priority crom the write blocked
+ // list.
+ 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);
+
+ void OnConfigNegotiated() override;
+
+ // Called by |headers_stream_| when |force_hol_blocking_| is true.
+ virtual void OnStreamFrameData(QuicStreamId stream_id,
+ const char* data,
+ size_t len,
+ bool fin);
+
+ bool force_hol_blocking() const { return force_hol_blocking_; }
+
+ bool server_push_enabled() const { return server_push_enabled_; }
+
+ // Called by |QuicHeadersStream::UpdateEnableServerPush()| with
+ // value from SETTINGS_ENABLE_PUSH.
+ void set_server_push_enabled(bool enable) { server_push_enabled_ = enable; }
+
+ protected:
+ // Override CreateIncomingDynamicStream() and CreateOutgoingDynamicStream()
+ // with QuicSpdyStream return type to make sure that all data streams are
+ // QuicSpdyStreams.
+ QuicSpdyStream* CreateIncomingDynamicStream(QuicStreamId id) override = 0;
+ QuicSpdyStream* CreateOutgoingDynamicStream(SpdyPriority priority) override =
+ 0;
+
+ QuicSpdyStream* GetSpdyDataStream(const QuicStreamId stream_id);
+
+ // If an incoming stream can be created, return true.
+ virtual bool ShouldCreateIncomingDynamicStream(QuicStreamId id) = 0;
+
+ // If an outgoing stream can be created, return true.
+ virtual bool ShouldCreateOutgoingDynamicStream() = 0;
+
+ private:
+ friend class test::QuicSpdySessionPeer;
+
+ std::unique_ptr<QuicHeadersStream> headers_stream_;
+
+ // If set, redirect all data through the headers stream in order to
+ // simulate forced HOL blocking between streams as happens in
+ // HTTP/2 over TCP.
+ bool force_hol_blocking_;
+
+ // Set during handshake. If true, resources in x-associated-content and link
+ // headers will be pushed.
+ bool server_push_enabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicSpdySession);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_SPDY_SESSION_H_
diff --git a/chromium/net/quic/core/quic_spdy_stream.cc b/chromium/net/quic/core/quic_spdy_stream.cc
new file mode 100644
index 00000000000..3777177c1bf
--- /dev/null
+++ b/chromium/net/quic/core/quic_spdy_stream.cc
@@ -0,0 +1,426 @@
+// Copyright 2013 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/quic_spdy_stream.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_spdy_session.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/core/quic_write_blocked_list.h"
+#include "net/quic/core/spdy_utils.h"
+
+using base::IntToString;
+using base::StringPiece;
+using std::min;
+using std::string;
+
+namespace net {
+
+#define ENDPOINT \
+ (session()->perspective() == Perspective::IS_SERVER ? "Server: " : "Client:" \
+ " ")
+
+QuicSpdyStream::QuicSpdyStream(QuicStreamId id, QuicSpdySession* spdy_session)
+ : ReliableQuicStream(id, spdy_session),
+ spdy_session_(spdy_session),
+ visitor_(nullptr),
+ headers_decompressed_(false),
+ priority_(kDefaultPriority),
+ trailers_decompressed_(false),
+ trailers_consumed_(false) {
+ DCHECK_NE(kCryptoStreamId, id);
+ // Don't receive any callbacks from the sequencer until headers
+ // are complete.
+ sequencer()->SetBlockedUntilFlush();
+ spdy_session_->RegisterStreamPriority(id, priority_);
+}
+
+QuicSpdyStream::~QuicSpdyStream() {
+ if (spdy_session_ != nullptr) {
+ spdy_session_->UnregisterStreamPriority(id());
+ }
+}
+
+void QuicSpdyStream::CloseWriteSide() {
+ if (!fin_received() && !rst_received() && sequencer()->ignore_read_data() &&
+ !rst_sent()) {
+ DCHECK(fin_sent());
+ // Tell the peer to stop sending further data.
+ DVLOG(1) << ENDPOINT << "Send QUIC_STREAM_NO_ERROR on stream " << id();
+ Reset(QUIC_STREAM_NO_ERROR);
+ }
+
+ ReliableQuicStream::CloseWriteSide();
+}
+
+void QuicSpdyStream::StopReading() {
+ if (!fin_received() && !rst_received() && write_side_closed() &&
+ !rst_sent()) {
+ DCHECK(fin_sent());
+ // Tell the peer to stop sending further data.
+ DVLOG(1) << ENDPOINT << "Send QUIC_STREAM_NO_ERROR on stream " << id();
+ Reset(QUIC_STREAM_NO_ERROR);
+ }
+ ReliableQuicStream::StopReading();
+}
+
+size_t QuicSpdyStream::WriteHeaders(
+ SpdyHeaderBlock header_block,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate) {
+ size_t bytes_written = spdy_session_->WriteHeaders(
+ id(), std::move(header_block), fin, priority_, ack_notifier_delegate);
+ if (fin) {
+ // TODO(rch): Add test to ensure fin_sent_ is set whenever a fin is sent.
+ set_fin_sent(true);
+ CloseWriteSide();
+ }
+ return bytes_written;
+}
+
+void QuicSpdyStream::WriteOrBufferBody(
+ const string& data,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate) {
+ WriteOrBufferData(data, fin, ack_notifier_delegate);
+}
+
+size_t QuicSpdyStream::WriteTrailers(
+ SpdyHeaderBlock trailer_block,
+ QuicAckListenerInterface* ack_notifier_delegate) {
+ if (fin_sent()) {
+ QUIC_BUG << "Trailers cannot be sent after a FIN.";
+ return 0;
+ }
+
+ // The header block must contain the final offset for this stream, as the
+ // trailers may be processed out of order at the peer.
+ DVLOG(1) << "Inserting trailer: (" << kFinalOffsetHeaderKey << ", "
+ << stream_bytes_written() + queued_data_bytes() << ")";
+ trailer_block.insert(std::make_pair(
+ kFinalOffsetHeaderKey,
+ IntToString(stream_bytes_written() + queued_data_bytes())));
+
+ // Write the trailing headers with a FIN, and close stream for writing:
+ // trailers are the last thing to be sent on a stream.
+ const bool kFin = true;
+ size_t bytes_written = spdy_session_->WriteHeaders(
+ id(), std::move(trailer_block), kFin, priority_, ack_notifier_delegate);
+ set_fin_sent(kFin);
+
+ // Trailers are the last thing to be sent on a stream, but if there is still
+ // queued data then CloseWriteSide() will cause it never to be sent.
+ if (queued_data_bytes() == 0) {
+ CloseWriteSide();
+ }
+
+ return bytes_written;
+}
+
+size_t QuicSpdyStream::Readv(const struct iovec* iov, size_t iov_len) {
+ DCHECK(FinishedReadingHeaders());
+ return sequencer()->Readv(iov, iov_len);
+}
+
+int QuicSpdyStream::GetReadableRegions(iovec* iov, size_t iov_len) const {
+ DCHECK(FinishedReadingHeaders());
+ return sequencer()->GetReadableRegions(iov, iov_len);
+}
+
+void QuicSpdyStream::MarkConsumed(size_t num_bytes) {
+ DCHECK(FinishedReadingHeaders());
+ return sequencer()->MarkConsumed(num_bytes);
+}
+
+bool QuicSpdyStream::IsDoneReading() const {
+ bool done_reading_headers = FinishedReadingHeaders();
+ bool done_reading_body = sequencer()->IsClosed();
+ bool done_reading_trailers = FinishedReadingTrailers();
+ return done_reading_headers && done_reading_body && done_reading_trailers;
+}
+
+bool QuicSpdyStream::HasBytesToRead() const {
+ bool headers_to_read = !decompressed_headers_.empty();
+ bool body_to_read = sequencer()->HasBytesToRead();
+ bool trailers_to_read = !decompressed_trailers_.empty();
+ return headers_to_read || body_to_read || trailers_to_read;
+}
+
+void QuicSpdyStream::MarkHeadersConsumed(size_t bytes_consumed) {
+ decompressed_headers_.erase(0, bytes_consumed);
+ if (FinishedReadingHeaders()) {
+ sequencer()->SetUnblocked();
+ }
+}
+
+void QuicSpdyStream::MarkTrailersConsumed(size_t bytes_consumed) {
+ decompressed_trailers_.erase(0, bytes_consumed);
+}
+
+void QuicSpdyStream::MarkTrailersConsumed() {
+ trailers_consumed_ = true;
+}
+
+void QuicSpdyStream::ConsumeHeaderList() {
+ header_list_.Clear();
+ if (FinishedReadingHeaders()) {
+ sequencer()->SetUnblocked();
+ }
+}
+
+void QuicSpdyStream::SetPriority(SpdyPriority priority) {
+ DCHECK_EQ(0u, stream_bytes_written());
+ spdy_session_->UpdateStreamPriority(id(), priority);
+ priority_ = priority;
+}
+
+void QuicSpdyStream::OnStreamHeaders(StringPiece headers_data) {
+ if (!headers_decompressed_) {
+ headers_data.AppendToString(&decompressed_headers_);
+ } else {
+ DCHECK(!trailers_decompressed_);
+ headers_data.AppendToString(&decompressed_trailers_);
+ }
+}
+
+void QuicSpdyStream::OnStreamHeadersPriority(SpdyPriority priority) {
+ DCHECK_EQ(Perspective::IS_SERVER, session()->connection()->perspective());
+ SetPriority(priority);
+}
+
+void QuicSpdyStream::OnStreamHeadersComplete(bool fin, size_t frame_len) {
+ if (!headers_decompressed_) {
+ OnInitialHeadersComplete(fin, frame_len);
+ } else {
+ OnTrailingHeadersComplete(fin, frame_len);
+ }
+}
+
+void QuicSpdyStream::OnStreamHeaderList(bool fin,
+ size_t frame_len,
+ const QuicHeaderList& header_list) {
+ if (!headers_decompressed_) {
+ OnInitialHeadersComplete(fin, frame_len, header_list);
+ } else {
+ OnTrailingHeadersComplete(fin, frame_len, header_list);
+ }
+}
+
+void QuicSpdyStream::OnInitialHeadersComplete(bool fin, size_t /*frame_len*/) {
+ headers_decompressed_ = true;
+ if (fin) {
+ OnStreamFrame(QuicStreamFrame(id(), fin, 0, StringPiece()));
+ }
+ if (FinishedReadingHeaders()) {
+ sequencer()->SetUnblocked();
+ }
+}
+
+void QuicSpdyStream::OnInitialHeadersComplete(
+ bool fin,
+ size_t /*frame_len*/,
+ const QuicHeaderList& header_list) {
+ headers_decompressed_ = true;
+ header_list_ = header_list;
+ if (fin) {
+ OnStreamFrame(QuicStreamFrame(id(), fin, 0, StringPiece()));
+ }
+ if (FinishedReadingHeaders()) {
+ sequencer()->SetUnblocked();
+ }
+}
+
+void QuicSpdyStream::OnPromiseHeaders(StringPiece headers_data) {
+ headers_data.AppendToString(&decompressed_headers_);
+}
+
+void QuicSpdyStream::OnPromiseHeadersComplete(
+ QuicStreamId /* promised_stream_id */,
+ size_t /* frame_len */) {
+ // To be overridden in QuicSpdyClientStream. Not supported on
+ // server side.
+ session()->connection()->CloseConnection(
+ QUIC_INVALID_HEADERS_STREAM_DATA, "Promise headers received by server",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+}
+
+void QuicSpdyStream::OnPromiseHeaderList(
+ QuicStreamId /* promised_id */,
+ size_t /* frame_len */,
+ const QuicHeaderList& /*header_list */) {
+ // To be overridden in QuicSpdyClientStream. Not supported on
+ // server side.
+ session()->connection()->CloseConnection(
+ QUIC_INVALID_HEADERS_STREAM_DATA, "Promise headers received by server",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+}
+
+void QuicSpdyStream::OnTrailingHeadersComplete(bool fin, size_t /*frame_len*/) {
+ DCHECK(!trailers_decompressed_);
+ if (fin_received()) {
+ DLOG(ERROR) << "Received Trailers after FIN, on stream: " << id();
+ session()->connection()->CloseConnection(
+ QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers after fin",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+ if (!fin) {
+ DLOG(ERROR) << "Trailers must have FIN set, on stream: " << id();
+ session()->connection()->CloseConnection(
+ QUIC_INVALID_HEADERS_STREAM_DATA, "Fin missing from trailers",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+
+ size_t final_byte_offset = 0;
+ if (!SpdyUtils::ParseTrailers(decompressed_trailers().data(),
+ decompressed_trailers().length(),
+ &final_byte_offset, &received_trailers_)) {
+ DLOG(ERROR) << "Trailers are malformed: " << id();
+ session()->connection()->CloseConnection(
+ QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers are malformed",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+
+ // The data on this stream ends at |final_byte_offset|.
+ DVLOG(1) << "Stream ends at byte offset: " << final_byte_offset
+ << " currently read: " << stream_bytes_read();
+ trailers_decompressed_ = true;
+ OnStreamFrame(QuicStreamFrame(id(), fin, final_byte_offset, StringPiece()));
+}
+
+void QuicSpdyStream::OnTrailingHeadersComplete(
+ bool fin,
+ size_t /*frame_len*/,
+ const QuicHeaderList& header_list) {
+ DCHECK(!trailers_decompressed_);
+ if (fin_received()) {
+ DLOG(ERROR) << "Received Trailers after FIN, on stream: " << id();
+ session()->connection()->CloseConnection(
+ QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers after fin",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+ if (!fin) {
+ DLOG(ERROR) << "Trailers must have FIN set, on stream: " << id();
+ session()->connection()->CloseConnection(
+ QUIC_INVALID_HEADERS_STREAM_DATA, "Fin missing from trailers",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+
+ size_t final_byte_offset = 0;
+ if (!SpdyUtils::CopyAndValidateTrailers(header_list, &final_byte_offset,
+ &received_trailers_)) {
+ DLOG(ERROR) << "Trailers are malformed: " << id();
+ session()->connection()->CloseConnection(
+ QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers are malformed",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ return;
+ }
+ trailers_decompressed_ = true;
+ OnStreamFrame(QuicStreamFrame(id(), fin, final_byte_offset, StringPiece()));
+}
+
+void QuicSpdyStream::OnStreamReset(const QuicRstStreamFrame& frame) {
+ if (frame.error_code != QUIC_STREAM_NO_ERROR) {
+ ReliableQuicStream::OnStreamReset(frame);
+ return;
+ }
+ DVLOG(1) << "Received QUIC_STREAM_NO_ERROR, not discarding response";
+ set_rst_received(true);
+ MaybeIncreaseHighestReceivedOffset(frame.byte_offset);
+ set_stream_error(frame.error_code);
+ CloseWriteSide();
+}
+
+void QuicSpdyStream::OnClose() {
+ ReliableQuicStream::OnClose();
+
+ if (visitor_) {
+ Visitor* visitor = visitor_;
+ // Calling Visitor::OnClose() may result the destruction of the visitor,
+ // so we need to ensure we don't call it again.
+ visitor_ = nullptr;
+ visitor->OnClose(this);
+ }
+}
+
+void QuicSpdyStream::OnCanWrite() {
+ ReliableQuicStream::OnCanWrite();
+
+ // Trailers (and hence a FIN) may have been sent ahead of queued body bytes.
+ if (!HasBufferedData() && fin_sent()) {
+ CloseWriteSide();
+ }
+}
+
+bool QuicSpdyStream::FinishedReadingHeaders() const {
+ return headers_decompressed_ && decompressed_headers_.empty() &&
+ header_list_.empty();
+}
+
+bool QuicSpdyStream::ParseHeaderStatusCode(const SpdyHeaderBlock& header,
+ int* status_code) const {
+ SpdyHeaderBlock::const_iterator it = header.find(":status");
+ if (it == header.end()) {
+ return false;
+ }
+ const StringPiece status(it->second);
+ if (status.size() != 3) {
+ return false;
+ }
+ // First character must be an integer in range [1,5].
+ if (status[0] < '1' || status[0] > '5') {
+ return false;
+ }
+ // The remaining two characters must be integers.
+ if (!isdigit(status[1]) || !isdigit(status[2])) {
+ return false;
+ }
+ return StringToInt(status, status_code);
+}
+
+bool QuicSpdyStream::FinishedReadingTrailers() const {
+ // If no further trailing headers are expected, and the decompressed trailers
+ // (if any) have been consumed, then reading of trailers is finished.
+ if (!fin_received()) {
+ return false;
+ } else if (!trailers_decompressed_) {
+ return true;
+ } else {
+ return trailers_consumed_ && decompressed_trailers_.empty();
+ }
+}
+
+SpdyPriority QuicSpdyStream::priority() const {
+ return priority_;
+}
+
+void QuicSpdyStream::ClearSession() {
+ spdy_session_ = nullptr;
+}
+
+QuicConsumedData QuicSpdyStream::WritevDataInner(
+ QuicIOVector iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate) {
+ if (spdy_session_->headers_stream() != nullptr &&
+ spdy_session_->force_hol_blocking()) {
+ return spdy_session_->headers_stream()->WritevStreamData(
+ id(), iov, offset, fin, ack_notifier_delegate);
+ }
+ return ReliableQuicStream::WritevDataInner(iov, offset, fin,
+ ack_notifier_delegate);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_spdy_stream.h b/chromium/net/quic/core/quic_spdy_stream.h
new file mode 100644
index 00000000000..b8c0b4995ed
--- /dev/null
+++ b/chromium/net/quic/core/quic_spdy_stream.h
@@ -0,0 +1,269 @@
+// Copyright 2013 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.
+//
+// The base class for streams which deliver data to/from an application.
+// In each direction, the data on such a stream first contains compressed
+// headers then body data.
+
+#ifndef NET_QUIC_QUIC_SPDY_STREAM_H_
+#define NET_QUIC_QUIC_SPDY_STREAM_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <list>
+#include <string>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/iovec.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_header_list.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_stream_sequencer.h"
+#include "net/quic/core/reliable_quic_stream.h"
+#include "net/spdy/spdy_framer.h"
+
+namespace net {
+
+namespace test {
+class QuicSpdyStreamPeer;
+class ReliableQuicStreamPeer;
+} // namespace test
+
+class QuicSpdySession;
+
+// This is somewhat arbitrary. It's possible, but unlikely, we will either fail
+// to set a priority client-side, or cancel a stream before stripping the
+// priority from the wire server-side. In either case, start out with a
+// priority in the middle.
+const SpdyPriority kDefaultPriority = 3;
+
+// A QUIC stream that can send and receive HTTP2 (SPDY) headers.
+class NET_EXPORT_PRIVATE QuicSpdyStream : public ReliableQuicStream {
+ public:
+ // Visitor receives callbacks from the stream.
+ class NET_EXPORT_PRIVATE Visitor {
+ public:
+ Visitor() {}
+
+ // Called when the stream is closed.
+ virtual void OnClose(QuicSpdyStream* stream) = 0;
+
+ // Allows subclasses to override and do work.
+ virtual void OnPromiseHeadersComplete(QuicStreamId promised_id,
+ size_t frame_len) {}
+
+ protected:
+ virtual ~Visitor() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Visitor);
+ };
+
+ QuicSpdyStream(QuicStreamId id, QuicSpdySession* spdy_session);
+ ~QuicSpdyStream() override;
+
+ // Override the base class to send QUIC_STREAM_NO_ERROR to the peer
+ // when the stream has not received all the data.
+ void CloseWriteSide() override;
+ void StopReading() override;
+
+ // ReliableQuicStream implementation
+ void OnClose() override;
+
+ // Override to maybe close the write side after writing.
+ void OnCanWrite() override;
+
+ // Called by the session when decompressed headers data is received
+ // for this stream.
+ // May be called multiple times, with each call providing additional headers
+ // data until OnStreamHeadersComplete is called.
+ virtual void OnStreamHeaders(base::StringPiece headers_data);
+
+ // Called by the session when headers with a priority have been received
+ // for this stream. This method will only be called for server streams.
+ virtual void OnStreamHeadersPriority(SpdyPriority priority);
+
+ // Called by the session when decompressed headers have been completely
+ // delivered to this stream. If |fin| is true, then this stream
+ // should be closed; no more data will be sent by the peer.
+ virtual void OnStreamHeadersComplete(bool fin, size_t frame_len);
+
+ // Called by the session when decompressed headers have been completely
+ // delivered to this stream. If |fin| is true, then this stream
+ // should be closed; no more data will be sent by the peer.
+ virtual void OnStreamHeaderList(bool fin,
+ size_t frame_len,
+ const QuicHeaderList& header_list);
+
+ // Called by the session when decompressed PUSH_PROMISE headers data
+ // is received for this stream.
+ // May be called multiple times, with each call providing additional headers
+ // data until OnPromiseHeadersComplete is called.
+ virtual void OnPromiseHeaders(base::StringPiece headers_data);
+
+ // Called by the session when decompressed push promise headers have
+ // been completely delivered to this stream.
+ virtual void OnPromiseHeadersComplete(QuicStreamId promised_id,
+ size_t frame_len);
+
+ // Called by the session when decompressed push promise headers have
+ // been completely delivered to this stream.
+ virtual void OnPromiseHeaderList(QuicStreamId promised_id,
+ size_t frame_len,
+ const QuicHeaderList& header_list);
+
+ // Override the base class to not discard response when receiving
+ // QUIC_STREAM_NO_ERROR.
+ void OnStreamReset(const QuicRstStreamFrame& frame) override;
+
+ // Writes the headers contained in |header_block| to the dedicated
+ // headers stream.
+ virtual size_t WriteHeaders(SpdyHeaderBlock header_block,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate);
+
+ // Sends |data| to the peer, or buffers if it can't be sent immediately.
+ void WriteOrBufferBody(const std::string& data,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate);
+
+ // Writes the trailers contained in |trailer_block| to the dedicated
+ // headers stream. Trailers will always have the FIN set.
+ virtual size_t WriteTrailers(SpdyHeaderBlock trailer_block,
+ QuicAckListenerInterface* ack_notifier_delegate);
+
+ // Marks |bytes_consumed| of the headers data as consumed.
+ void MarkHeadersConsumed(size_t bytes_consumed);
+
+ // Marks |bytes_consumed| of the trailers data as consumed. This applies to
+ // the case where this object receives headers and trailers data via calls to
+ // OnStreamHeaders().
+ void MarkTrailersConsumed(size_t bytes_consumed);
+
+ // Marks the trailers as consumed. This applies to the case where this object
+ // receives headers and trailers as QuicHeaderLists via calls to
+ // OnStreamHeaderList().
+ void MarkTrailersConsumed();
+
+ // Clears |header_list_|.
+ void ConsumeHeaderList();
+
+ // This block of functions wraps the sequencer's functions of the same
+ // name. These methods return uncompressed data until that has
+ // been fully processed. Then they simply delegate to the sequencer.
+ virtual size_t Readv(const struct iovec* iov, size_t iov_len);
+ virtual int GetReadableRegions(iovec* iov, size_t iov_len) const;
+ void MarkConsumed(size_t num_bytes);
+
+ // Returns true if header contains a valid 3-digit status and parse the status
+ // code to |status_code|.
+ bool ParseHeaderStatusCode(const SpdyHeaderBlock& header,
+ int* status_code) const;
+
+ // Returns true when all data has been read from the peer, including the fin.
+ bool IsDoneReading() const;
+ bool HasBytesToRead() const;
+
+ void set_visitor(Visitor* visitor) { visitor_ = visitor; }
+
+ bool headers_decompressed() const { return headers_decompressed_; }
+
+ const std::string& decompressed_headers() const {
+ return decompressed_headers_;
+ }
+
+ const QuicHeaderList& header_list() const { return header_list_; }
+
+ bool trailers_decompressed() const { return trailers_decompressed_; }
+
+ const std::string& decompressed_trailers() const {
+ return decompressed_trailers_;
+ }
+
+ // Returns whatever trailers have been received for this stream.
+ const SpdyHeaderBlock& received_trailers() const {
+ return received_trailers_;
+ }
+
+ // Returns true if headers have been fully read and consumed.
+ bool FinishedReadingHeaders() const;
+
+ // Returns true if trailers have been fully read and consumed.
+ bool FinishedReadingTrailers() const;
+
+ virtual SpdyPriority priority() const;
+
+ // Sets priority_ to priority. This should only be called before bytes are
+ // written to the server.
+ void SetPriority(SpdyPriority priority);
+
+ // Called when owning session is getting deleted to avoid subsequent
+ // use of the spdy_session_ member.
+ void ClearSession();
+
+ // Returns true if the sequencer has delivered the FIN, and no more body bytes
+ // will be available.
+ bool IsClosed() { return sequencer()->IsClosed(); }
+
+ protected:
+ // Called by OnStreamHeadersComplete depending on which type (initial or
+ // trailing) headers are expected next.
+ virtual void OnInitialHeadersComplete(bool fin, size_t frame_len);
+ virtual void OnTrailingHeadersComplete(bool fin, size_t frame_len);
+ virtual void OnInitialHeadersComplete(bool fin,
+ size_t frame_len,
+ const QuicHeaderList& header_list);
+ virtual void OnTrailingHeadersComplete(bool fin,
+ size_t frame_len,
+ const QuicHeaderList& header_list);
+ QuicSpdySession* spdy_session() const { return spdy_session_; }
+ Visitor* visitor() { return visitor_; }
+
+ // Redirects to the headers stream if force HOL blocking enabled,
+ // otherwise just pass through.
+ QuicConsumedData WritevDataInner(
+ QuicIOVector iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate) override;
+
+ private:
+ friend class test::QuicSpdyStreamPeer;
+ friend class test::ReliableQuicStreamPeer;
+ friend class QuicStreamUtils;
+
+ QuicSpdySession* spdy_session_;
+
+ Visitor* visitor_;
+ // True if the headers have been completely decompressed.
+ bool headers_decompressed_;
+ // The priority of the stream, once parsed.
+ SpdyPriority priority_;
+ // Contains a copy of the decompressed headers until they are consumed
+ // via ProcessData or Readv.
+ std::string decompressed_headers_;
+ // Contains a copy of the decompressed header (name, value) pairs until they
+ // are consumed via Readv.
+ QuicHeaderList header_list_;
+
+ // True if the trailers have been completely decompressed.
+ bool trailers_decompressed_;
+ // True if the trailers have been consumed.
+ bool trailers_consumed_;
+ // Contains a copy of the decompressed trailers until they are consumed
+ // via ProcessData or Readv.
+ std::string decompressed_trailers_;
+ // The parsed trailers received from the peer.
+ SpdyHeaderBlock received_trailers_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicSpdyStream);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_SPDY_STREAM_H_
diff --git a/chromium/net/quic/core/quic_spdy_stream_test.cc b/chromium/net/quic/core/quic_spdy_stream_test.cc
new file mode 100644
index 00000000000..c1ced633c89
--- /dev/null
+++ b/chromium/net/quic/core/quic_spdy_stream_test.cc
@@ -0,0 +1,1001 @@
+// Copyright 2013 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/quic_spdy_stream.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/strings/string_number_conversions.h"
+#include "net/quic/core/quic_connection.h"
+#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/test_tools/quic_flow_controller_peer.h"
+#include "net/quic/test_tools/quic_session_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/reliable_quic_stream_peer.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using base::StringPiece;
+using std::min;
+using std::string;
+using testing::AnyNumber;
+using testing::Invoke;
+using testing::Return;
+using testing::StrictMock;
+using testing::_;
+
+namespace net {
+namespace test {
+namespace {
+
+const bool kShouldProcessData = true;
+
+class TestStream : public QuicSpdyStream {
+ public:
+ TestStream(QuicStreamId id,
+ QuicSpdySession* session,
+ bool should_process_data)
+ : QuicSpdyStream(id, session),
+ should_process_data_(should_process_data) {}
+
+ void OnDataAvailable() override {
+ if (!should_process_data_) {
+ return;
+ }
+ char buffer[2048];
+ struct iovec vec;
+ vec.iov_base = buffer;
+ vec.iov_len = arraysize(buffer);
+ size_t bytes_read = Readv(&vec, 1);
+ data_ += string(buffer, bytes_read);
+ }
+
+ using ReliableQuicStream::WriteOrBufferData;
+ using ReliableQuicStream::CloseWriteSide;
+
+ const string& data() const { return data_; }
+
+ private:
+ bool should_process_data_;
+ string data_;
+};
+
+class QuicSpdyStreamTest : public ::testing::TestWithParam<QuicVersion> {
+ public:
+ QuicSpdyStreamTest() {
+ headers_[":host"] = "www.google.com";
+ headers_[":path"] = "/index.hml";
+ headers_[":scheme"] = "https";
+ headers_["cookie"] =
+ "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; "
+ "__utmc=160408618; "
+ "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX"
+ "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX"
+ "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT"
+ "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0"
+ "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh"
+ "1zFMi5vzcns38-8_Sns; "
+ "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-"
+ "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339"
+ "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c"
+ "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%"
+ "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4"
+ "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1"
+ "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP"
+ "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6"
+ "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b"
+ "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6"
+ "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG"
+ "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk"
+ "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn"
+ "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
+ "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
+ }
+
+ void Initialize(bool stream_should_process_data) {
+ connection_ = new testing::StrictMock<MockQuicConnection>(
+ &helper_, &alarm_factory_, Perspective::IS_SERVER,
+ SupportedVersions(GetParam()));
+ session_.reset(new testing::StrictMock<MockQuicSpdySession>(connection_));
+ stream_ = new TestStream(kClientDataStreamId1, session_.get(),
+ stream_should_process_data);
+ session_->ActivateStream(stream_);
+ stream2_ = new TestStream(kClientDataStreamId2, session_.get(),
+ stream_should_process_data);
+ session_->ActivateStream(stream2_);
+ }
+
+ protected:
+ MockQuicConnectionHelper helper_;
+ MockAlarmFactory alarm_factory_;
+ MockQuicConnection* connection_;
+ std::unique_ptr<MockQuicSpdySession> session_;
+
+ // Owned by the |session_|.
+ TestStream* stream_;
+ TestStream* stream2_;
+
+ SpdyHeaderBlock headers_;
+};
+
+INSTANTIATE_TEST_CASE_P(Tests,
+ QuicSpdyStreamTest,
+ ::testing::ValuesIn(AllSupportedVersions()));
+
+TEST_P(QuicSpdyStreamTest, ProcessHeaders) {
+ Initialize(kShouldProcessData);
+
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeadersPriority(kV3HighestPriority);
+ stream_->OnStreamHeaders(headers);
+ EXPECT_EQ("", stream_->data());
+ EXPECT_EQ(headers, stream_->decompressed_headers());
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ EXPECT_EQ(kV3HighestPriority, stream_->priority());
+ EXPECT_EQ("", stream_->data());
+ EXPECT_EQ(headers, stream_->decompressed_headers());
+ EXPECT_FALSE(stream_->IsDoneReading());
+}
+
+TEST_P(QuicSpdyStreamTest, ProcessHeaderList) {
+ Initialize(kShouldProcessData);
+
+ size_t total_bytes = 0;
+ QuicHeaderList headers;
+ for (auto p : headers_) {
+ headers.OnHeader(p.first, p.second);
+ total_bytes += p.first.size() + p.second.size();
+ }
+ stream_->OnStreamHeadersPriority(kV3HighestPriority);
+ stream_->OnStreamHeaderList(false, total_bytes, headers);
+ EXPECT_EQ("", stream_->data());
+ EXPECT_FALSE(stream_->header_list().empty());
+ EXPECT_FALSE(stream_->IsDoneReading());
+}
+
+TEST_P(QuicSpdyStreamTest, ProcessHeadersWithFin) {
+ Initialize(kShouldProcessData);
+
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeadersPriority(kV3HighestPriority);
+ stream_->OnStreamHeaders(headers);
+ EXPECT_EQ("", stream_->data());
+ EXPECT_EQ(headers, stream_->decompressed_headers());
+ stream_->OnStreamHeadersComplete(true, headers.size());
+ EXPECT_EQ(kV3HighestPriority, stream_->priority());
+ EXPECT_EQ("", stream_->data());
+ EXPECT_EQ(headers, stream_->decompressed_headers());
+ EXPECT_FALSE(stream_->IsDoneReading());
+ EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
+}
+
+TEST_P(QuicSpdyStreamTest, ProcessHeaderListWithFin) {
+ Initialize(kShouldProcessData);
+
+ size_t total_bytes = 0;
+ QuicHeaderList headers;
+ for (auto p : headers_) {
+ headers.OnHeader(p.first, p.second);
+ total_bytes += p.first.size() + p.second.size();
+ }
+ stream_->OnStreamHeadersPriority(kV3HighestPriority);
+ stream_->OnStreamHeaderList(true, total_bytes, headers);
+ EXPECT_EQ("", stream_->data());
+ EXPECT_FALSE(stream_->header_list().empty());
+ EXPECT_FALSE(stream_->IsDoneReading());
+ EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
+}
+
+TEST_P(QuicSpdyStreamTest, ParseHeaderStatusCode) {
+ // A valid status code should be 3-digit integer. The first digit should be in
+ // the range of [1, 5]. All the others are invalid.
+ Initialize(kShouldProcessData);
+ int status_code = 0;
+
+ // Valid status code.
+ headers_.ReplaceOrAppendHeader(":status", "404");
+ EXPECT_TRUE(stream_->ParseHeaderStatusCode(headers_, &status_code));
+ EXPECT_EQ(404, status_code);
+
+ // Invalid status codes.
+ headers_.ReplaceOrAppendHeader(":status", "010");
+ EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
+
+ headers_.ReplaceOrAppendHeader(":status", "600");
+ EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
+
+ headers_.ReplaceOrAppendHeader(":status", "200 ok");
+ EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
+
+ headers_.ReplaceOrAppendHeader(":status", "2000");
+ EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
+
+ headers_.ReplaceOrAppendHeader(":status", "+200");
+ EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
+
+ headers_.ReplaceOrAppendHeader(":status", "+20");
+ EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
+
+ // Leading or trailing spaces are also invalid.
+ headers_.ReplaceOrAppendHeader(":status", " 200");
+ EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
+
+ headers_.ReplaceOrAppendHeader(":status", "200 ");
+ EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
+
+ headers_.ReplaceOrAppendHeader(":status", " 200 ");
+ EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
+
+ headers_.ReplaceOrAppendHeader(":status", " ");
+ EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
+}
+
+TEST_P(QuicSpdyStreamTest, MarkHeadersConsumed) {
+ Initialize(kShouldProcessData);
+
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ string body = "this is the body";
+
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ EXPECT_EQ(headers, stream_->decompressed_headers());
+
+ headers.erase(0, 10);
+ stream_->MarkHeadersConsumed(10);
+ EXPECT_EQ(headers, stream_->decompressed_headers());
+
+ stream_->MarkHeadersConsumed(headers.length());
+ EXPECT_EQ("", stream_->decompressed_headers());
+}
+
+TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBody) {
+ Initialize(kShouldProcessData);
+
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ string body = "this is the body";
+
+ stream_->OnStreamHeaders(headers);
+ EXPECT_EQ("", stream_->data());
+ EXPECT_EQ(headers, stream_->decompressed_headers());
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ EXPECT_EQ(headers, stream_->decompressed_headers());
+ stream_->MarkHeadersConsumed(headers.length());
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
+ stream_->OnStreamFrame(frame);
+ EXPECT_EQ("", stream_->decompressed_headers());
+ EXPECT_EQ(body, stream_->data());
+}
+
+TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyFragments) {
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ string body = "this is the body";
+
+ for (size_t fragment_size = 1; fragment_size < body.size(); ++fragment_size) {
+ Initialize(kShouldProcessData);
+ for (size_t offset = 0; offset < headers.size(); offset += fragment_size) {
+ size_t remaining_data = headers.size() - offset;
+ StringPiece fragment(headers.data() + offset,
+ min(fragment_size, remaining_data));
+ stream_->OnStreamHeaders(fragment);
+ }
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ ASSERT_EQ(headers, stream_->decompressed_headers()) << "fragment_size: "
+ << fragment_size;
+ stream_->MarkHeadersConsumed(headers.length());
+ for (size_t offset = 0; offset < body.size(); offset += fragment_size) {
+ size_t remaining_data = body.size() - offset;
+ StringPiece fragment(body.data() + offset,
+ min(fragment_size, remaining_data));
+ QuicStreamFrame frame(kClientDataStreamId1, false, offset,
+ StringPiece(fragment));
+ stream_->OnStreamFrame(frame);
+ }
+ ASSERT_EQ(body, stream_->data()) << "fragment_size: " << fragment_size;
+ }
+}
+
+TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyFragmentsSplit) {
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ string body = "this is the body";
+
+ for (size_t split_point = 1; split_point < body.size() - 1; ++split_point) {
+ Initialize(kShouldProcessData);
+ StringPiece headers1(headers.data(), split_point);
+ stream_->OnStreamHeaders(headers1);
+
+ StringPiece headers2(headers.data() + split_point,
+ headers.size() - split_point);
+ stream_->OnStreamHeaders(headers2);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ ASSERT_EQ(headers, stream_->decompressed_headers()) << "split_point: "
+ << split_point;
+ stream_->MarkHeadersConsumed(headers.length());
+
+ StringPiece fragment1(body.data(), split_point);
+ QuicStreamFrame frame1(kClientDataStreamId1, false, 0,
+ StringPiece(fragment1));
+ stream_->OnStreamFrame(frame1);
+
+ StringPiece fragment2(body.data() + split_point, body.size() - split_point);
+ QuicStreamFrame frame2(kClientDataStreamId1, false, split_point,
+ StringPiece(fragment2));
+ stream_->OnStreamFrame(frame2);
+
+ ASSERT_EQ(body, stream_->data()) << "split_point: " << split_point;
+ }
+}
+
+TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyReadv) {
+ Initialize(!kShouldProcessData);
+
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ string body = "this is the body";
+
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
+ stream_->OnStreamFrame(frame);
+ stream_->MarkHeadersConsumed(headers.length());
+
+ char buffer[2048];
+ ASSERT_LT(body.length(), arraysize(buffer));
+ struct iovec vec;
+ vec.iov_base = buffer;
+ vec.iov_len = arraysize(buffer);
+
+ size_t bytes_read = stream_->Readv(&vec, 1);
+ EXPECT_EQ(body.length(), bytes_read);
+ EXPECT_EQ(body, string(buffer, bytes_read));
+}
+
+TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyMarkConsumed) {
+ Initialize(!kShouldProcessData);
+
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ string body = "this is the body";
+
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
+ stream_->OnStreamFrame(frame);
+ stream_->MarkHeadersConsumed(headers.length());
+
+ struct iovec vec;
+
+ EXPECT_EQ(1, stream_->GetReadableRegions(&vec, 1));
+ EXPECT_EQ(body.length(), vec.iov_len);
+ EXPECT_EQ(body, string(static_cast<char*>(vec.iov_base), vec.iov_len));
+
+ stream_->MarkConsumed(body.length());
+ EXPECT_EQ(body.length(), stream_->flow_controller()->bytes_consumed());
+}
+
+TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyIncrementalReadv) {
+ Initialize(!kShouldProcessData);
+
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ string body = "this is the body";
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
+ stream_->OnStreamFrame(frame);
+ stream_->MarkHeadersConsumed(headers.length());
+
+ char buffer[1];
+ struct iovec vec;
+ vec.iov_base = buffer;
+ vec.iov_len = arraysize(buffer);
+
+ for (size_t i = 0; i < body.length(); ++i) {
+ size_t bytes_read = stream_->Readv(&vec, 1);
+ ASSERT_EQ(1u, bytes_read);
+ EXPECT_EQ(body.data()[i], buffer[0]);
+ }
+}
+
+TEST_P(QuicSpdyStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) {
+ Initialize(!kShouldProcessData);
+
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ string body = "this is the body";
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
+ stream_->OnStreamFrame(frame);
+ stream_->MarkHeadersConsumed(headers.length());
+
+ char buffer1[1];
+ char buffer2[1];
+ struct iovec vec[2];
+ vec[0].iov_base = buffer1;
+ vec[0].iov_len = arraysize(buffer1);
+ vec[1].iov_base = buffer2;
+ vec[1].iov_len = arraysize(buffer2);
+
+ for (size_t i = 0; i < body.length(); i += 2) {
+ size_t bytes_read = stream_->Readv(vec, 2);
+ ASSERT_EQ(2u, bytes_read) << i;
+ ASSERT_EQ(body.data()[i], buffer1[0]) << i;
+ ASSERT_EQ(body.data()[i + 1], buffer2[0]) << i;
+ }
+}
+
+TEST_P(QuicSpdyStreamTest, StreamFlowControlBlocked) {
+ // Tests that we send a BLOCKED frame to the peer when we attempt to write,
+ // but are flow control blocked.
+ Initialize(kShouldProcessData);
+
+ // Set a small flow control limit.
+ const uint64_t kWindow = 36;
+ QuicFlowControllerPeer::SetSendWindowOffset(stream_->flow_controller(),
+ kWindow);
+ EXPECT_EQ(kWindow, QuicFlowControllerPeer::SendWindowOffset(
+ stream_->flow_controller()));
+
+ // Try to send more data than the flow control limit allows.
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ string body;
+ const uint64_t kOverflow = 15;
+ GenerateBody(&body, kWindow + kOverflow);
+
+ EXPECT_CALL(*connection_, SendBlocked(kClientDataStreamId1));
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(kWindow, true)));
+ stream_->WriteOrBufferData(body, false, nullptr);
+
+ // Should have sent as much as possible, resulting in no send window left.
+ EXPECT_EQ(0u,
+ QuicFlowControllerPeer::SendWindowSize(stream_->flow_controller()));
+
+ // And we should have queued the overflowed data.
+ EXPECT_EQ(kOverflow, ReliableQuicStreamPeer::SizeOfQueuedData(stream_));
+}
+
+TEST_P(QuicSpdyStreamTest, StreamFlowControlNoWindowUpdateIfNotConsumed) {
+ // The flow control receive window decreases whenever we add new bytes to the
+ // sequencer, whether they are consumed immediately or buffered. However we
+ // only send WINDOW_UPDATE frames based on increasing number of bytes
+ // consumed.
+
+ // Don't process data - it will be buffered instead.
+ Initialize(!kShouldProcessData);
+
+ // Expect no WINDOW_UPDATE frames to be sent.
+ EXPECT_CALL(*connection_, SendWindowUpdate(_, _)).Times(0);
+
+ // Set a small flow control receive window.
+ const uint64_t kWindow = 36;
+ QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(),
+ kWindow);
+ QuicFlowControllerPeer::SetMaxReceiveWindow(stream_->flow_controller(),
+ kWindow);
+ EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowOffset(
+ stream_->flow_controller()));
+
+ // Stream receives enough data to fill a fraction of the receive window.
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ string body;
+ GenerateBody(&body, kWindow / 3);
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+
+ QuicStreamFrame frame1(kClientDataStreamId1, false, 0, StringPiece(body));
+ stream_->OnStreamFrame(frame1);
+ EXPECT_EQ(kWindow - (kWindow / 3), QuicFlowControllerPeer::ReceiveWindowSize(
+ stream_->flow_controller()));
+
+ // Now receive another frame which results in the receive window being over
+ // half full. This should all be buffered, decreasing the receive window but
+ // not sending WINDOW_UPDATE.
+ QuicStreamFrame frame2(kClientDataStreamId1, false, kWindow / 3,
+ StringPiece(body));
+ stream_->OnStreamFrame(frame2);
+ EXPECT_EQ(
+ kWindow - (2 * kWindow / 3),
+ QuicFlowControllerPeer::ReceiveWindowSize(stream_->flow_controller()));
+}
+
+TEST_P(QuicSpdyStreamTest, StreamFlowControlWindowUpdate) {
+ // Tests that on receipt of data, the stream updates its receive window offset
+ // appropriately, and sends WINDOW_UPDATE frames when its receive window drops
+ // too low.
+ Initialize(kShouldProcessData);
+
+ // Set a small flow control limit.
+ const uint64_t kWindow = 36;
+ QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(),
+ kWindow);
+ QuicFlowControllerPeer::SetMaxReceiveWindow(stream_->flow_controller(),
+ kWindow);
+ EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowOffset(
+ stream_->flow_controller()));
+
+ // Stream receives enough data to fill a fraction of the receive window.
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ string body;
+ GenerateBody(&body, kWindow / 3);
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ stream_->MarkHeadersConsumed(headers.length());
+
+ QuicStreamFrame frame1(kClientDataStreamId1, false, 0, StringPiece(body));
+ stream_->OnStreamFrame(frame1);
+ EXPECT_EQ(kWindow - (kWindow / 3), QuicFlowControllerPeer::ReceiveWindowSize(
+ stream_->flow_controller()));
+
+ // Now receive another frame which results in the receive window being over
+ // half full. This will trigger the stream to increase its receive window
+ // offset and send a WINDOW_UPDATE. The result will be again an available
+ // window of kWindow bytes.
+ QuicStreamFrame frame2(kClientDataStreamId1, false, kWindow / 3,
+ StringPiece(body));
+ EXPECT_CALL(*connection_,
+ SendWindowUpdate(kClientDataStreamId1,
+ QuicFlowControllerPeer::ReceiveWindowOffset(
+ stream_->flow_controller()) +
+ 2 * kWindow / 3));
+ stream_->OnStreamFrame(frame2);
+ EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowSize(
+ stream_->flow_controller()));
+}
+
+TEST_P(QuicSpdyStreamTest, ConnectionFlowControlWindowUpdate) {
+ // Tests that on receipt of data, the connection updates its receive window
+ // offset appropriately, and sends WINDOW_UPDATE frames when its receive
+ // window drops too low.
+ Initialize(kShouldProcessData);
+
+ // Set a small flow control limit for streams and connection.
+ const uint64_t kWindow = 36;
+ QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(),
+ kWindow);
+ QuicFlowControllerPeer::SetMaxReceiveWindow(stream_->flow_controller(),
+ kWindow);
+ QuicFlowControllerPeer::SetReceiveWindowOffset(stream2_->flow_controller(),
+ kWindow);
+ QuicFlowControllerPeer::SetMaxReceiveWindow(stream2_->flow_controller(),
+ kWindow);
+ QuicFlowControllerPeer::SetReceiveWindowOffset(session_->flow_controller(),
+ kWindow);
+ QuicFlowControllerPeer::SetMaxReceiveWindow(session_->flow_controller(),
+ kWindow);
+
+ // Supply headers to both streams so that they are happy to receive data.
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ stream_->MarkHeadersConsumed(headers.length());
+ stream2_->OnStreamHeaders(headers);
+ stream2_->OnStreamHeadersComplete(false, headers.size());
+ stream2_->MarkHeadersConsumed(headers.length());
+
+ // Each stream gets a quarter window of data. This should not trigger a
+ // WINDOW_UPDATE for either stream, nor for the connection.
+ string body;
+ GenerateBody(&body, kWindow / 4);
+ QuicStreamFrame frame1(kClientDataStreamId1, false, 0, StringPiece(body));
+ stream_->OnStreamFrame(frame1);
+ QuicStreamFrame frame2(kClientDataStreamId2, false, 0, StringPiece(body));
+ stream2_->OnStreamFrame(frame2);
+
+ // Now receive a further single byte on one stream - again this does not
+ // trigger a stream WINDOW_UPDATE, but now the connection flow control window
+ // is over half full and thus a connection WINDOW_UPDATE is sent.
+ EXPECT_CALL(*connection_, SendWindowUpdate(kClientDataStreamId1, _)).Times(0);
+ EXPECT_CALL(*connection_, SendWindowUpdate(kClientDataStreamId2, _)).Times(0);
+ EXPECT_CALL(*connection_,
+ SendWindowUpdate(0, QuicFlowControllerPeer::ReceiveWindowOffset(
+ session_->flow_controller()) +
+ 1 + kWindow / 2));
+ QuicStreamFrame frame3(kClientDataStreamId1, false, (kWindow / 4),
+ StringPiece("a"));
+ stream_->OnStreamFrame(frame3);
+}
+
+TEST_P(QuicSpdyStreamTest, StreamFlowControlViolation) {
+ // Tests that on if the peer sends too much data (i.e. violates the flow
+ // control protocol), then we terminate the connection.
+
+ // Stream should not process data, so that data gets buffered in the
+ // sequencer, triggering flow control limits.
+ Initialize(!kShouldProcessData);
+
+ // Set a small flow control limit.
+ const uint64_t kWindow = 50;
+ QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(),
+ kWindow);
+
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+
+ // Receive data to overflow the window, violating flow control.
+ string body;
+ GenerateBody(&body, kWindow + 1);
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _));
+ stream_->OnStreamFrame(frame);
+}
+
+TEST_P(QuicSpdyStreamTest, TestHandlingQuicRstStreamNoError) {
+ Initialize(kShouldProcessData);
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+
+ stream_->OnStreamReset(
+ QuicRstStreamFrame(stream_->id(), QUIC_STREAM_NO_ERROR, 0));
+ EXPECT_TRUE(stream_->write_side_closed());
+ EXPECT_FALSE(stream_->reading_stopped());
+}
+
+TEST_P(QuicSpdyStreamTest, ConnectionFlowControlViolation) {
+ // Tests that on if the peer sends too much data (i.e. violates the flow
+ // control protocol), at the connection level (rather than the stream level)
+ // then we terminate the connection.
+
+ // Stream should not process data, so that data gets buffered in the
+ // sequencer, triggering flow control limits.
+ Initialize(!kShouldProcessData);
+
+ // Set a small flow control window on streams, and connection.
+ const uint64_t kStreamWindow = 50;
+ const uint64_t kConnectionWindow = 10;
+ QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(),
+ kStreamWindow);
+ QuicFlowControllerPeer::SetReceiveWindowOffset(session_->flow_controller(),
+ kConnectionWindow);
+
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+
+ // Send enough data to overflow the connection level flow control window.
+ string body;
+ GenerateBody(&body, kConnectionWindow + 1);
+ EXPECT_LT(body.size(), kStreamWindow);
+ QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
+
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _));
+ stream_->OnStreamFrame(frame);
+}
+
+TEST_P(QuicSpdyStreamTest, StreamFlowControlFinNotBlocked) {
+ // An attempt to write a FIN with no data should not be flow control blocked,
+ // even if the send window is 0.
+
+ Initialize(kShouldProcessData);
+
+ // Set a flow control limit of zero.
+ QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(), 0);
+ EXPECT_EQ(0u, QuicFlowControllerPeer::ReceiveWindowOffset(
+ stream_->flow_controller()));
+
+ // Send a frame with a FIN but no data. This should not be blocked.
+ string body = "";
+ bool fin = true;
+
+ EXPECT_CALL(*connection_, SendBlocked(kClientDataStreamId1)).Times(0);
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(0, fin)));
+
+ stream_->WriteOrBufferData(body, fin, nullptr);
+}
+
+TEST_P(QuicSpdyStreamTest, ReceivingTrailers) {
+ // Test that receiving trailing headers from the peer works, and can be read
+ // from the stream and consumed.
+ Initialize(kShouldProcessData);
+
+ // Receive initial headers.
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ stream_->MarkHeadersConsumed(stream_->decompressed_headers().size());
+
+ // Receive trailing headers.
+ SpdyHeaderBlock trailers_block;
+ trailers_block["key1"] = "value1";
+ trailers_block["key2"] = "value2";
+ trailers_block["key3"] = "value3";
+ trailers_block[kFinalOffsetHeaderKey] = "0";
+ string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
+ stream_->OnStreamHeaders(trailers);
+ stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size());
+
+ // The trailers should be decompressed, and readable from the stream.
+ EXPECT_TRUE(stream_->trailers_decompressed());
+ const string decompressed_trailers = stream_->decompressed_trailers();
+ EXPECT_EQ(trailers, decompressed_trailers);
+
+ // Consuming the trailers erases them from the stream.
+ stream_->MarkTrailersConsumed(decompressed_trailers.size());
+ EXPECT_EQ("", stream_->decompressed_trailers());
+}
+
+TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutOffset) {
+ // Test that receiving trailers without a final offset field is an error.
+ Initialize(kShouldProcessData);
+
+ // Receive initial headers.
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ stream_->MarkHeadersConsumed(stream_->decompressed_headers().size());
+
+ const string body = "this is the body";
+ // Receive trailing headers, without kFinalOffsetHeaderKey.
+ SpdyHeaderBlock trailers_block;
+ trailers_block["key1"] = "value1";
+ trailers_block["key2"] = "value2";
+ trailers_block["key3"] = "value3";
+ string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
+ stream_->OnStreamHeaders(trailers);
+
+ // Verify that the trailers block didn't contain a final offset.
+ EXPECT_EQ("", trailers_block[kFinalOffsetHeaderKey].as_string());
+
+ // Receipt of the malformed trailers will close the connection.
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _))
+ .Times(1);
+ stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size());
+}
+
+TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutFin) {
+ // Test that received Trailers must always have the FIN set.
+ Initialize(kShouldProcessData);
+
+ // Receive initial headers.
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+
+ // Receive trailing headers with FIN deliberately set to false.
+ SpdyHeaderBlock trailers_block;
+ string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
+ stream_->OnStreamHeaders(trailers);
+
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _))
+ .Times(1);
+ stream_->OnStreamHeadersComplete(/*fin=*/false, trailers.size());
+}
+
+TEST_P(QuicSpdyStreamTest, ReceivingTrailersAfterFin) {
+ // If Trailers are sent, neither Headers nor Body should contain a FIN.
+ Initialize(kShouldProcessData);
+
+ // Receive initial headers with FIN set.
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(/*fin=*/true, headers.size());
+
+ // Receive trailing headers after FIN already received.
+ SpdyHeaderBlock trailers_block;
+ string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
+ stream_->OnStreamHeaders(trailers);
+
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _))
+ .Times(1);
+ stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size());
+}
+
+TEST_P(QuicSpdyStreamTest, ReceivingTrailersAfterBodyWithFin) {
+ // If body data are received with a FIN, no trailers should then arrive.
+ Initialize(kShouldProcessData);
+
+ // Receive initial headers without FIN set.
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(/*fin=*/false, headers.size());
+
+ // Receive body data, with FIN.
+ QuicStreamFrame frame(kClientDataStreamId1, /*fin=*/true, 0, "body");
+ stream_->OnStreamFrame(frame);
+
+ // Receive trailing headers after FIN already received.
+ SpdyHeaderBlock trailers_block;
+ string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
+ stream_->OnStreamHeaders(trailers);
+
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _))
+ .Times(1);
+ stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size());
+}
+
+TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithOffset) {
+ // Test that when receiving trailing headers with an offset before response
+ // body, stream is closed at the right offset.
+ Initialize(kShouldProcessData);
+
+ // Receive initial headers.
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(false, headers.size());
+ stream_->MarkHeadersConsumed(stream_->decompressed_headers().size());
+
+ const string body = "this is the body";
+ // Receive trailing headers.
+ SpdyHeaderBlock trailers_block;
+ trailers_block["key1"] = "value1";
+ trailers_block["key2"] = "value2";
+ trailers_block["key3"] = "value3";
+ trailers_block[kFinalOffsetHeaderKey] = base::IntToString(body.size());
+ string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
+ stream_->OnStreamHeaders(trailers);
+ stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size());
+
+ // The trailers should be decompressed, and readable from the stream.
+ EXPECT_TRUE(stream_->trailers_decompressed());
+ const string decompressed_trailers = stream_->decompressed_trailers();
+ EXPECT_EQ(trailers, decompressed_trailers);
+ // Consuming the trailers erases them from the stream.
+ stream_->MarkTrailersConsumed(decompressed_trailers.size());
+ stream_->MarkTrailersConsumed();
+ EXPECT_EQ("", stream_->decompressed_trailers());
+
+ EXPECT_FALSE(stream_->IsDoneReading());
+ // Receive and consume body.
+ QuicStreamFrame frame(kClientDataStreamId1, /*fin=*/false, 0, body);
+ stream_->OnStreamFrame(frame);
+ EXPECT_EQ(body, stream_->data());
+ EXPECT_TRUE(stream_->IsDoneReading());
+}
+
+TEST_P(QuicSpdyStreamTest, ClosingStreamWithNoTrailers) {
+ // Verify that a stream receiving headers, body, and no trailers is correctly
+ // marked as done reading on consumption of headers and body.
+ Initialize(kShouldProcessData);
+
+ // Receive and consume initial headers with FIN not set.
+ string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
+ stream_->OnStreamHeaders(headers);
+ stream_->OnStreamHeadersComplete(/*fin=*/false, headers.size());
+ stream_->MarkHeadersConsumed(headers.size());
+
+ // Receive and consume body with FIN set, and no trailers.
+ const string kBody = string(1024, 'x');
+ QuicStreamFrame frame(kClientDataStreamId1, /*fin=*/true, 0, kBody);
+ stream_->OnStreamFrame(frame);
+
+ EXPECT_TRUE(stream_->IsDoneReading());
+}
+
+TEST_P(QuicSpdyStreamTest, WritingTrailersSendsAFin) {
+ // Test that writing trailers will send a FIN, as Trailers are the last thing
+ // to be sent on a stream.
+ Initialize(kShouldProcessData);
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .Times(AnyNumber())
+ .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
+
+ // Write the initial headers, without a FIN.
+ EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _));
+ stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
+
+ // Writing trailers implicitly sends a FIN.
+ SpdyHeaderBlock trailers;
+ trailers["trailer key"] = "trailer value";
+ EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _));
+ stream_->WriteTrailers(std::move(trailers), nullptr);
+ EXPECT_TRUE(stream_->fin_sent());
+}
+
+TEST_P(QuicSpdyStreamTest, WritingTrailersFinalOffset) {
+ // Test that when writing trailers, the trailers that are actually sent to the
+ // peer contain the final offset field indicating last byte of data.
+ Initialize(kShouldProcessData);
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .Times(AnyNumber())
+ .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
+
+ // Write the initial headers.
+ EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _));
+ stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
+
+ // Write non-zero body data to force a non-zero final offset.
+ const int kBodySize = 1 * 1024; // 1 MB
+ stream_->WriteOrBufferData(string(kBodySize, 'x'), false, nullptr);
+
+ // The final offset field in the trailing headers is populated with the
+ // number of body bytes written (including queued bytes).
+ SpdyHeaderBlock trailers;
+ trailers["trailer key"] = "trailer value";
+ SpdyHeaderBlock trailers_with_offset(trailers.Clone());
+ trailers_with_offset[kFinalOffsetHeaderKey] = base::IntToString(kBodySize);
+ EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _));
+ stream_->WriteTrailers(std::move(trailers), nullptr);
+ EXPECT_EQ(trailers_with_offset, session_->GetWriteHeaders());
+}
+
+TEST_P(QuicSpdyStreamTest, WritingTrailersClosesWriteSide) {
+ // Test that if trailers are written after all other data has been written
+ // (headers and body), that this closes the stream for writing.
+ Initialize(kShouldProcessData);
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .Times(AnyNumber())
+ .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
+
+ // Write the initial headers.
+ EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _));
+ stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
+
+ // Write non-zero body data.
+ const int kBodySize = 1 * 1024; // 1 MB
+ stream_->WriteOrBufferData(string(kBodySize, 'x'), false, nullptr);
+ EXPECT_EQ(0u, stream_->queued_data_bytes());
+
+ // Headers and body have been fully written, there is no queued data. Writing
+ // trailers marks the end of this stream, and thus the write side is closed.
+ EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _));
+ stream_->WriteTrailers(SpdyHeaderBlock(), nullptr);
+ EXPECT_TRUE(stream_->write_side_closed());
+}
+
+TEST_P(QuicSpdyStreamTest, WritingTrailersWithQueuedBytes) {
+ // Test that the stream is not closed for writing when trailers are sent
+ // while there are still body bytes queued.
+ Initialize(kShouldProcessData);
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .Times(AnyNumber())
+ .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
+
+ // Write the initial headers.
+ EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _));
+ stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
+
+ // Write non-zero body data, but only consume partially, ensuring queueing.
+ const int kBodySize = 1 * 1024; // 1 MB
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(kBodySize - 1, false)));
+ stream_->WriteOrBufferData(string(kBodySize, 'x'), false, nullptr);
+ if (!session_->force_hol_blocking()) {
+ EXPECT_EQ(1u, stream_->queued_data_bytes());
+ }
+
+ // Writing trailers will send a FIN, but not close the write side of the
+ // stream as there are queued bytes.
+ EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _));
+ stream_->WriteTrailers(SpdyHeaderBlock(), nullptr);
+ EXPECT_TRUE(stream_->fin_sent());
+ if (!session_->force_hol_blocking()) {
+ EXPECT_FALSE(stream_->write_side_closed());
+ }
+
+ // Writing the queued bytes will close the write side of the stream.
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(1, false)));
+ stream_->OnCanWrite();
+ EXPECT_TRUE(stream_->write_side_closed());
+}
+
+TEST_P(QuicSpdyStreamTest, WritingTrailersAfterFIN) {
+ // Test that it is not possible to write Trailers after a FIN has been sent.
+ Initialize(kShouldProcessData);
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .Times(AnyNumber())
+ .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
+
+ // Write the initial headers, with a FIN.
+ EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _));
+ stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/true, nullptr);
+ EXPECT_TRUE(stream_->fin_sent());
+
+ // Writing Trailers should fail, as the FIN has already been sent.
+ // populated with the number of body bytes written.
+ EXPECT_QUIC_BUG(stream_->WriteTrailers(SpdyHeaderBlock(), nullptr),
+ "Trailers cannot be sent after a FIN");
+}
+
+} // 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
new file mode 100644
index 00000000000..597244b5436
--- /dev/null
+++ b/chromium/net/quic/core/quic_stream_sequencer.cc
@@ -0,0 +1,236 @@
+// 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/quic_stream_sequencer.h"
+
+#include <algorithm>
+#include <limits>
+#include <string>
+#include <utility>
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_stream_sequencer_buffer.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/core/reliable_quic_stream.h"
+
+using base::IntToString;
+using base::StringPiece;
+using base::StringPrintf;
+using std::min;
+using std::numeric_limits;
+using std::string;
+
+namespace net {
+
+QuicStreamSequencer::QuicStreamSequencer(ReliableQuicStream* quic_stream,
+ const QuicClock* clock)
+ : stream_(quic_stream),
+ buffered_frames_(kStreamReceiveWindowLimit),
+ close_offset_(numeric_limits<QuicStreamOffset>::max()),
+ blocked_(false),
+ num_frames_received_(0),
+ num_duplicate_frames_received_(0),
+ clock_(clock),
+ ignore_read_data_(false) {}
+
+QuicStreamSequencer::~QuicStreamSequencer() {}
+
+void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) {
+ ++num_frames_received_;
+ const QuicStreamOffset byte_offset = frame.offset;
+ const size_t data_len = frame.data_length;
+
+ if (frame.fin) {
+ CloseStreamAtOffset(frame.offset + data_len);
+ if (data_len == 0) {
+ return;
+ }
+ }
+ size_t bytes_written;
+ string error_details;
+ QuicErrorCode result = buffered_frames_.OnStreamData(
+ byte_offset, StringPiece(frame.data_buffer, frame.data_length),
+ clock_->ApproximateNow(), &bytes_written, &error_details);
+ if (result != QUIC_NO_ERROR) {
+ string details = "Stream" + base::Uint64ToString(stream_->id()) + ": " +
+ QuicUtils::ErrorToString(result) + ": " + error_details +
+ "\nPeer Address: " +
+ stream_->PeerAddressOfLatestPacket().ToString();
+ DLOG(WARNING) << QuicUtils::ErrorToString(result);
+ DLOG(WARNING) << details;
+ stream_->CloseConnectionWithDetails(result, details);
+ return;
+ }
+
+ if (bytes_written == 0) {
+ ++num_duplicate_frames_received_;
+ // Silently ignore duplicates.
+ return;
+ }
+
+ if (blocked_) {
+ return;
+ }
+
+ if (byte_offset == buffered_frames_.BytesConsumed()) {
+ if (ignore_read_data_) {
+ FlushBufferedFrames();
+ } else {
+ stream_->OnDataAvailable();
+ }
+ }
+}
+
+void QuicStreamSequencer::CloseStreamAtOffset(QuicStreamOffset offset) {
+ const QuicStreamOffset kMaxOffset = numeric_limits<QuicStreamOffset>::max();
+
+ // If there is a scheduled close, the new offset should match it.
+ if (close_offset_ != kMaxOffset && offset != close_offset_) {
+ stream_->Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS);
+ return;
+ }
+
+ close_offset_ = offset;
+
+ MaybeCloseStream();
+}
+
+bool QuicStreamSequencer::MaybeCloseStream() {
+ if (blocked_ || !IsClosed()) {
+ return false;
+ }
+
+ DVLOG(1) << "Passing up termination, as we've processed "
+ << buffered_frames_.BytesConsumed() << " of " << close_offset_
+ << " bytes.";
+ // This will cause the stream to consume the FIN.
+ // Technically it's an error if |num_bytes_consumed| isn't exactly
+ // equal to |close_offset|, but error handling seems silly at this point.
+ if (ignore_read_data_) {
+ // The sequencer is discarding stream data and must notify the stream on
+ // receipt of a FIN because the consumer won't.
+ stream_->OnFinRead();
+ } else {
+ stream_->OnDataAvailable();
+ }
+ buffered_frames_.Clear();
+ return true;
+}
+
+int QuicStreamSequencer::GetReadableRegions(iovec* iov, size_t iov_len) const {
+ DCHECK(!blocked_);
+ return buffered_frames_.GetReadableRegions(iov, iov_len);
+}
+
+bool QuicStreamSequencer::GetReadableRegion(iovec* iov,
+ QuicTime* timestamp) const {
+ DCHECK(!blocked_);
+ return buffered_frames_.GetReadableRegion(iov, timestamp);
+}
+
+int QuicStreamSequencer::Readv(const struct iovec* iov, size_t iov_len) {
+ DCHECK(!blocked_);
+ string error_details;
+ size_t bytes_read;
+ QuicErrorCode read_error =
+ buffered_frames_.Readv(iov, iov_len, &bytes_read, &error_details);
+ if (FLAGS_quic_stream_sequencer_buffer_debug && read_error != QUIC_NO_ERROR) {
+ string details = StringPrintf("Stream %" PRIu32 ": %s", stream_->id(),
+ error_details.c_str());
+ stream_->CloseConnectionWithDetails(read_error, details);
+ return static_cast<int>(bytes_read);
+ }
+
+ stream_->AddBytesConsumed(bytes_read);
+ return static_cast<int>(bytes_read);
+}
+
+bool QuicStreamSequencer::HasBytesToRead() const {
+ return buffered_frames_.HasBytesToRead();
+}
+
+bool QuicStreamSequencer::IsClosed() const {
+ return buffered_frames_.BytesConsumed() >= close_offset_;
+}
+
+void QuicStreamSequencer::MarkConsumed(size_t num_bytes_consumed) {
+ DCHECK(!blocked_);
+ bool result = buffered_frames_.MarkConsumed(num_bytes_consumed);
+ if (!result) {
+ QUIC_BUG << "Invalid argument to MarkConsumed."
+ << " expect to consume: " << num_bytes_consumed
+ << ", but not enough bytes available. " << DebugString();
+ stream_->Reset(QUIC_ERROR_PROCESSING_STREAM);
+ return;
+ }
+ stream_->AddBytesConsumed(num_bytes_consumed);
+}
+
+void QuicStreamSequencer::SetBlockedUntilFlush() {
+ blocked_ = true;
+}
+
+void QuicStreamSequencer::SetUnblocked() {
+ blocked_ = false;
+ if (IsClosed() || HasBytesToRead()) {
+ stream_->OnDataAvailable();
+ }
+}
+
+void QuicStreamSequencer::StopReading() {
+ if (ignore_read_data_) {
+ return;
+ }
+ ignore_read_data_ = true;
+ FlushBufferedFrames();
+}
+
+void QuicStreamSequencer::ReleaseBuffer() {
+ buffered_frames_.ReleaseWholeBuffer();
+}
+
+void QuicStreamSequencer::ReleaseBufferIfEmpty() {
+ if (FLAGS_quic_release_crypto_stream_buffer && buffered_frames_.Empty()) {
+ buffered_frames_.ReleaseWholeBuffer();
+ }
+}
+
+void QuicStreamSequencer::FlushBufferedFrames() {
+ DCHECK(ignore_read_data_);
+ size_t bytes_flushed = buffered_frames_.FlushBufferedFrames();
+ DVLOG(1) << "Flushing buffered data at offset "
+ << buffered_frames_.BytesConsumed() << " length " << bytes_flushed
+ << " for stream " << stream_->id();
+ stream_->AddBytesConsumed(bytes_flushed);
+ MaybeCloseStream();
+}
+
+size_t QuicStreamSequencer::NumBytesBuffered() const {
+ return buffered_frames_.BytesBuffered();
+}
+
+QuicStreamOffset QuicStreamSequencer::NumBytesConsumed() const {
+ return buffered_frames_.BytesConsumed();
+}
+
+const string QuicStreamSequencer::DebugString() const {
+ // clang-format off
+ return "QuicStreamSequencer:"
+ "\n bytes buffered: " + IntToString(NumBytesBuffered()) +
+ "\n bytes consumed: " + IntToString( NumBytesConsumed()) +
+ "\n has bytes to read: " + (HasBytesToRead() ? "true" : "false") +
+ "\n frames received: " + IntToString(num_frames_received()) +
+ "\n close offset bytes: " + IntToString( close_offset_) +
+ "\n is closed: " + (IsClosed() ? "true" : "false");
+ // clang-format on
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_stream_sequencer.h b/chromium/net/quic/core/quic_stream_sequencer.h
new file mode 100644
index 00000000000..acd3e9ddb84
--- /dev/null
+++ b/chromium/net/quic/core/quic_stream_sequencer.h
@@ -0,0 +1,151 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_STREAM_SEQUENCER_H_
+#define NET_QUIC_QUIC_STREAM_SEQUENCER_H_
+
+#include <stddef.h>
+
+#include <map>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_stream_sequencer_buffer.h"
+
+namespace net {
+
+namespace test {
+class QuicStreamSequencerPeer;
+} // namespace test
+
+class QuicClock;
+class QuicSession;
+class ReliableQuicStream;
+
+// Buffers frames until we have something which can be passed
+// up to the next layer.
+class NET_EXPORT_PRIVATE QuicStreamSequencer {
+ public:
+ QuicStreamSequencer(ReliableQuicStream* quic_stream, const QuicClock* clock);
+ virtual ~QuicStreamSequencer();
+
+ // If the frame is the next one we need in order to process in-order data,
+ // ProcessData will be immediately called on the stream until all buffered
+ // data is processed or the stream fails to consume data. Any unconsumed
+ // data will be buffered. If the frame is not the next in line, it will be
+ // buffered.
+ void OnStreamFrame(const QuicStreamFrame& frame);
+
+ // Once data is buffered, it's up to the stream to read it when the stream
+ // can handle more data. The following three functions make that possible.
+
+ // Fills in up to iov_len iovecs with the next readable regions. Returns the
+ // number of iovs used. Non-destructive of the underlying data.
+ int GetReadableRegions(iovec* iov, size_t iov_len) const;
+
+ // Fills in one iovec with the next readable region. |timestamp| is
+ // data arrived at the sequencer, and is used for measuring head of
+ // line blocking (HOL). Returns false if there is no readable
+ // region available.
+ bool GetReadableRegion(iovec* iov, QuicTime* timestamp) const;
+
+ // Copies the data into the iov_len buffers provided. Returns the number of
+ // bytes read. Any buffered data no longer in use will be released.
+ // TODO(rch): remove this method and instead implement it as a helper method
+ // based on GetReadableRegions and MarkConsumed.
+ int Readv(const struct iovec* iov, size_t iov_len);
+
+ // Consumes |num_bytes| data. Used in conjunction with |GetReadableRegions|
+ // to do zero-copy reads.
+ void MarkConsumed(size_t num_bytes);
+
+ // Returns true if the sequncer has bytes available for reading.
+ bool HasBytesToRead() const;
+
+ // Returns true if the sequencer has delivered the fin.
+ bool IsClosed() const;
+
+ // Calls |OnDataAvailable| on |stream_| if there is buffered data that can
+ // be processed, and causes |OnDataAvailable| to be called as new data
+ // arrives.
+ void SetUnblocked();
+
+ // Blocks processing of frames until |SetUnblocked| is called.
+ void SetBlockedUntilFlush();
+
+ // Sets the sequencer to discard all incoming data itself and not call
+ // |stream_->OnDataAvailable()|. |stream_->OnFinRead()| will be called
+ // automatically when the FIN is consumed (which may be immediately).
+ void StopReading();
+
+ // Free the memory of underlying buffer.
+ void ReleaseBuffer();
+
+ // Free the memory of underlying buffer when no bytes remain in it.
+ void ReleaseBufferIfEmpty();
+
+ // Number of bytes in the buffer right now.
+ size_t NumBytesBuffered() const;
+
+ // Number of bytes has been consumed.
+ QuicStreamOffset NumBytesConsumed() const;
+
+ int num_frames_received() const { return num_frames_received_; }
+
+ int num_duplicate_frames_received() const {
+ return num_duplicate_frames_received_;
+ }
+
+ bool ignore_read_data() const { return ignore_read_data_; }
+
+ // Returns std::string describing internal state.
+ const std::string DebugString() const;
+
+ private:
+ friend class test::QuicStreamSequencerPeer;
+
+ // Deletes and records as consumed any buffered data that is now in-sequence.
+ // (To be called only after StopReading has been called.)
+ void FlushBufferedFrames();
+
+ // Wait until we've seen 'offset' bytes, and then terminate the stream.
+ void CloseStreamAtOffset(QuicStreamOffset offset);
+
+ // If we've received a FIN and have processed all remaining data, then inform
+ // the stream of FIN, and clear buffers.
+ bool MaybeCloseStream();
+
+ // The stream which owns this sequencer.
+ ReliableQuicStream* stream_;
+
+ // Stores received data in offset order.
+ QuicStreamSequencerBuffer buffered_frames_;
+
+ // The offset, if any, we got a stream termination for. When this many bytes
+ // have been processed, the sequencer will be closed.
+ QuicStreamOffset close_offset_;
+
+ // If true, the sequencer is blocked from passing data to the stream and will
+ // buffer all new incoming data until FlushBufferedFrames is called.
+ bool blocked_;
+
+ // Count of the number of frames received.
+ int num_frames_received_;
+
+ // Count of the number of duplicate frames received.
+ int num_duplicate_frames_received_;
+
+ // Not owned.
+ const QuicClock* clock_;
+
+ // If true, all incoming data will be discarded.
+ bool ignore_read_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicStreamSequencer);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_STREAM_SEQUENCER_H_
diff --git a/chromium/net/quic/core/quic_stream_sequencer_buffer.cc b/chromium/net/quic/core/quic_stream_sequencer_buffer.cc
new file mode 100644
index 00000000000..fcb617fb61d
--- /dev/null
+++ b/chromium/net/quic/core/quic_stream_sequencer_buffer.cc
@@ -0,0 +1,609 @@
+// 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.
+
+#include "net/quic/core/quic_stream_sequencer_buffer.h"
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+
+using base::StringPrintf;
+using std::min;
+using std::string;
+
+namespace net {
+namespace {
+
+// 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.
+const size_t kMaxNumGapsAllowed = 2 * kMaxPacketGap;
+
+} // namespace
+
+namespace {
+
+string RangeDebugString(QuicStreamOffset start, QuicStreamOffset end) {
+ return std::string("[") + base::Uint64ToString(start) + ", " +
+ base::Uint64ToString(end) + ") ";
+}
+
+} // namespace
+
+QuicStreamSequencerBuffer::Gap::Gap(QuicStreamOffset begin_offset,
+ QuicStreamOffset end_offset)
+ : begin_offset(begin_offset), end_offset(end_offset) {}
+
+QuicStreamSequencerBuffer::FrameInfo::FrameInfo()
+ : length(1), timestamp(QuicTime::Zero()) {}
+
+QuicStreamSequencerBuffer::FrameInfo::FrameInfo(size_t length,
+ QuicTime timestamp)
+ : length(length), timestamp(timestamp) {}
+
+QuicStreamSequencerBuffer::QuicStreamSequencerBuffer(size_t max_capacity_bytes)
+ : max_buffer_capacity_bytes_(max_capacity_bytes),
+ blocks_count_(
+ ceil(static_cast<double>(max_capacity_bytes) / kBlockSizeBytes)),
+ total_bytes_read_(0),
+ reduce_sequencer_buffer_memory_life_time_(
+ FLAGS_quic_reduce_sequencer_buffer_memory_life_time), // NOLINT
+ blocks_(reduce_sequencer_buffer_memory_life_time_
+ ? nullptr
+ : new BufferBlock*[blocks_count_]()) {
+ Clear();
+}
+
+QuicStreamSequencerBuffer::~QuicStreamSequencerBuffer() {
+ Clear();
+}
+
+void QuicStreamSequencerBuffer::Clear() {
+ if (!reduce_sequencer_buffer_memory_life_time_ || blocks_ != nullptr) {
+ for (size_t i = 0; i < blocks_count_; ++i) {
+ if (blocks_[i] != nullptr) {
+ RetireBlock(i);
+ }
+ }
+ }
+ 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())),
+ frame_arrival_time_map_.clear();
+}
+
+bool QuicStreamSequencerBuffer::RetireBlock(size_t idx) {
+ if (FLAGS_quic_stream_sequencer_buffer_debug && blocks_[idx] == nullptr) {
+ QUIC_BUG << "Try to retire block twice";
+ return false;
+ }
+ delete blocks_[idx];
+ blocks_[idx] = nullptr;
+ DVLOG(1) << "Retired block with index: " << idx;
+ return true;
+}
+
+QuicErrorCode QuicStreamSequencerBuffer::OnStreamData(
+ QuicStreamOffset starting_offset,
+ base::StringPiece data,
+ QuicTime timestamp,
+ size_t* const bytes_buffered,
+ std::string* error_details) {
+ *bytes_buffered = 0;
+ QuicStreamOffset offset = starting_offset;
+ size_t size = data.size();
+ if (size == 0) {
+ *error_details = "Received empty stream frame without FIN.";
+ return QUIC_EMPTY_STREAM_FRAME_NO_FIN;
+ }
+
+ // 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.
+ std::list<Gap>::iterator current_gap = gaps_.begin();
+ while (current_gap != gaps_.end() && current_gap->end_offset <= offset) {
+ ++current_gap;
+ }
+
+ DCHECK(current_gap != gaps_.end());
+
+ // "duplication": might duplicate with data alread filled,but also might
+ // overlap across different base::StringPiece objects already written.
+ // In both cases, don't write the data,
+ // and allow the caller of this method to handle the result.
+ if (offset < current_gap->begin_offset &&
+ offset + size <= current_gap->begin_offset) {
+ DVLOG(1) << "Duplicated data at offset: " << offset << " length: " << size;
+ return QUIC_NO_ERROR;
+ }
+ if (offset < current_gap->begin_offset &&
+ offset + size > current_gap->begin_offset) {
+ // Beginning of new data overlaps data before current gap.
+ *error_details =
+ string("Beginning of received data overlaps with buffered data.\n") +
+ "New frame range " + RangeDebugString(offset, offset + size) +
+ " with first 128 bytes: " +
+ string(data.data(), data.length() < 128 ? data.length() : 128) +
+ "\nCurrently received frames: " + ReceivedFramesDebugString() +
+ "\nCurrent gaps: " + GapsDebugString();
+ return QUIC_OVERLAPPING_STREAM_DATA;
+ }
+ if (offset + size > current_gap->end_offset) {
+ // End of new data overlaps with data after current gap.
+ *error_details =
+ string("End of received data overlaps with buffered data.\n") +
+ "New frame range " + RangeDebugString(offset, offset + size) +
+ " with first 128 bytes: " +
+ string(data.data(), data.length() < 128 ? data.length() : 128) +
+ "\nCurrently received frames: " + ReceivedFramesDebugString() +
+ "\nCurrent gaps: " + GapsDebugString();
+ return QUIC_OVERLAPPING_STREAM_DATA;
+ }
+
+ // Write beyond the current range this buffer is covering.
+ if (offset + size > total_bytes_read_ + max_buffer_capacity_bytes_) {
+ *error_details = "Received data beyond available range.";
+ return QUIC_INTERNAL_ERROR;
+ }
+
+ if (current_gap->begin_offset != starting_offset &&
+ current_gap->end_offset != starting_offset + data.length() &&
+ gaps_.size() >= kMaxNumGapsAllowed) {
+ // 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;
+ }
+
+ size_t total_written = 0;
+ size_t source_remaining = size;
+ const char* source = data.data();
+ // Write data block by block. If corresponding block has not created yet,
+ // create it first.
+ // Stop when all data are written or reaches the logical end of the buffer.
+ while (source_remaining > 0) {
+ const size_t write_block_num = GetBlockIndex(offset);
+ const size_t write_block_offset = GetInBlockOffset(offset);
+ DCHECK_GT(blocks_count_, write_block_num);
+
+ size_t block_capacity = GetBlockCapacity(write_block_num);
+ size_t bytes_avail = block_capacity - write_block_offset;
+
+ // If this write meets the upper boundary of the buffer,
+ // reduce the available free bytes.
+ if (offset + bytes_avail > total_bytes_read_ + max_buffer_capacity_bytes_) {
+ bytes_avail = total_bytes_read_ + max_buffer_capacity_bytes_ - offset;
+ }
+
+ if (reduce_sequencer_buffer_memory_life_time_ && blocks_ == nullptr) {
+ blocks_.reset(new BufferBlock*[blocks_count_]());
+ for (size_t i = 0; i < blocks_count_; ++i) {
+ blocks_[i] = nullptr;
+ }
+ }
+
+ if (FLAGS_quic_stream_sequencer_buffer_debug &&
+ write_block_num >= blocks_count_) {
+ *error_details = StringPrintf(
+ "QuicStreamSequencerBuffer error: OnStreamData() exceed array bounds."
+ "write offset = %" PRIu64 " write_block_num = %" PRIuS
+ " blocks_count_ = %" PRIuS,
+ offset, write_block_num, blocks_count_);
+ return QUIC_STREAM_SEQUENCER_INVALID_STATE;
+ }
+ if (blocks_ == nullptr) {
+ *error_details =
+ "QuicStreamSequencerBuffer error: OnStreamData() blocks_ is null";
+ return QUIC_STREAM_SEQUENCER_INVALID_STATE;
+ }
+ if (blocks_[write_block_num] == nullptr) {
+ // TODO(danzh): Investigate if using a freelist would improve performance.
+ // Same as RetireBlock().
+ blocks_[write_block_num] = new BufferBlock();
+ }
+
+ const size_t bytes_to_copy = min<size_t>(bytes_avail, source_remaining);
+ char* dest = blocks_[write_block_num]->buffer + write_block_offset;
+ DVLOG(1) << "Write at offset: " << offset << " length: " << bytes_to_copy;
+
+ if (FLAGS_quic_stream_sequencer_buffer_debug &&
+ (dest == nullptr || source == nullptr)) {
+ *error_details = StringPrintf(
+ "QuicStreamSequencerBuffer error: OnStreamData()"
+ " dest == nullptr: %s"
+ " source == nullptr: %s"
+ " Writing at offset %" PRIu64
+ " Gaps: %s"
+ " Remaining frames: %s"
+ " total_bytes_read_ = %" PRIu64,
+ (dest == nullptr ? "true" : "false"),
+ (source == nullptr ? "true" : "false"), offset,
+ GapsDebugString().c_str(), ReceivedFramesDebugString().c_str(),
+ total_bytes_read_);
+ return QUIC_STREAM_SEQUENCER_INVALID_STATE;
+ }
+ memcpy(dest, source, bytes_to_copy);
+ source += bytes_to_copy;
+ source_remaining -= bytes_to_copy;
+ offset += bytes_to_copy;
+ total_written += bytes_to_copy;
+ }
+
+ DCHECK_GT(total_written, 0u);
+ *bytes_buffered = total_written;
+ UpdateGapList(current_gap, starting_offset, total_written);
+
+ frame_arrival_time_map_.insert(
+ std::make_pair(starting_offset, FrameInfo(size, timestamp)));
+ num_bytes_buffered_ += total_written;
+ return QUIC_NO_ERROR;
+}
+
+inline void QuicStreamSequencerBuffer::UpdateGapList(
+ std::list<Gap>::iterator gap_with_new_data_written,
+ QuicStreamOffset start_offset,
+ size_t bytes_written) {
+ if (gap_with_new_data_written->begin_offset == start_offset &&
+ gap_with_new_data_written->end_offset > start_offset + bytes_written) {
+ // New data has been written into the left part of the buffer.
+ gap_with_new_data_written->begin_offset = start_offset + bytes_written;
+ } else if (gap_with_new_data_written->begin_offset < start_offset &&
+ gap_with_new_data_written->end_offset ==
+ start_offset + bytes_written) {
+ // New data has been written into the right part of the buffer.
+ gap_with_new_data_written->end_offset = start_offset;
+ } else if (gap_with_new_data_written->begin_offset < start_offset &&
+ gap_with_new_data_written->end_offset >
+ start_offset + bytes_written) {
+ // New data has been written into the middle of the buffer.
+ auto current = gap_with_new_data_written++;
+ QuicStreamOffset current_end = current->end_offset;
+ current->end_offset = start_offset;
+ gaps_.insert(gap_with_new_data_written,
+ Gap(start_offset + bytes_written, current_end));
+ } else if (gap_with_new_data_written->begin_offset == start_offset &&
+ gap_with_new_data_written->end_offset ==
+ start_offset + bytes_written) {
+ // This gap has been filled with new data. So it's no longer a gap.
+ gaps_.erase(gap_with_new_data_written);
+ }
+}
+
+QuicErrorCode QuicStreamSequencerBuffer::Readv(const iovec* dest_iov,
+ size_t dest_count,
+ size_t* bytes_read,
+ string* error_details) {
+ *bytes_read = 0;
+ for (size_t i = 0; i < dest_count && ReadableBytes() > 0; ++i) {
+ char* dest = reinterpret_cast<char*>(dest_iov[i].iov_base);
+ size_t dest_remaining = dest_iov[i].iov_len;
+ while (dest_remaining > 0 && ReadableBytes() > 0) {
+ size_t block_idx = NextBlockToRead();
+ size_t start_offset_in_block = ReadOffset();
+ size_t block_capacity = GetBlockCapacity(block_idx);
+ size_t bytes_available_in_block =
+ min<size_t>(ReadableBytes(), block_capacity - start_offset_in_block);
+ size_t bytes_to_copy =
+ min<size_t>(bytes_available_in_block, dest_remaining);
+ DCHECK_GT(bytes_to_copy, 0UL);
+ if (FLAGS_quic_stream_sequencer_buffer_debug &&
+ (blocks_[block_idx] == nullptr || dest == nullptr)) {
+ *error_details = StringPrintf(
+ "QuicStreamSequencerBuffer error:"
+ " Readv() dest == nullptr: %s"
+ " blocks_[%" PRIuS "] == nullptr: %s",
+ (dest == nullptr ? "true" : "false"), block_idx,
+ (blocks_[block_idx] == nullptr ? "true" : "false"));
+ return QUIC_STREAM_SEQUENCER_INVALID_STATE;
+ }
+ memcpy(dest, blocks_[block_idx]->buffer + start_offset_in_block,
+ bytes_to_copy);
+ dest += bytes_to_copy;
+ dest_remaining -= bytes_to_copy;
+ num_bytes_buffered_ -= bytes_to_copy;
+ total_bytes_read_ += bytes_to_copy;
+ *bytes_read += bytes_to_copy;
+
+ // Retire the block if all the data is read out and no other data is
+ // stored in this block.
+ // In case of failing to retire a block which is ready to retire, return
+ // immediately.
+ if (bytes_to_copy == bytes_available_in_block) {
+ bool retire_successfully = RetireBlockIfEmpty(block_idx);
+ if (FLAGS_quic_stream_sequencer_buffer_debug && !retire_successfully) {
+ *error_details = StringPrintf(
+ "QuicStreamSequencerBuffer error: fail to retire block %" PRIuS
+ " as the block is already released + total_bytes_read_ = %" PRIu64
+ " Gaps: %s",
+ block_idx, total_bytes_read_, GapsDebugString().c_str());
+ return QUIC_STREAM_SEQUENCER_INVALID_STATE;
+ }
+ }
+ }
+ }
+
+ if (*bytes_read > 0) {
+ UpdateFrameArrivalMap(total_bytes_read_);
+ }
+ return QUIC_NO_ERROR;
+}
+
+int QuicStreamSequencerBuffer::GetReadableRegions(struct iovec* iov,
+ int iov_count) const {
+ DCHECK(iov != nullptr);
+ DCHECK_GT(iov_count, 0);
+
+ if (ReadableBytes() == 0) {
+ iov[0].iov_base = nullptr;
+ iov[0].iov_len = 0;
+ return 0;
+ }
+
+ size_t start_block_idx = NextBlockToRead();
+ QuicStreamOffset readable_offset_end = gaps_.front().begin_offset - 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);
+
+ // If readable region is within one block, deal with it seperately.
+ if (start_block_idx == end_block_idx && ReadOffset() <= end_block_offset) {
+ iov[0].iov_base = blocks_[start_block_idx]->buffer + ReadOffset();
+ iov[0].iov_len = ReadableBytes();
+ DVLOG(1) << "Got only a single block with index: " << start_block_idx;
+ return 1;
+ }
+
+ // Get first block
+ iov[0].iov_base = blocks_[start_block_idx]->buffer + ReadOffset();
+ iov[0].iov_len = GetBlockCapacity(start_block_idx) - ReadOffset();
+ DVLOG(1) << "Got first block " << start_block_idx << " with len "
+ << iov[0].iov_len;
+ DCHECK_GT(readable_offset_end + 1, total_bytes_read_ + iov[0].iov_len)
+ << "there should be more available data";
+
+ // Get readable regions of the rest blocks till either 2nd to last block
+ // before gap is met or |iov| is filled. For these blocks, one whole block is
+ // a region.
+ int iov_used = 1;
+ size_t block_idx = (start_block_idx + iov_used) % blocks_count_;
+ while (block_idx != end_block_idx && iov_used < iov_count) {
+ DCHECK_NE(static_cast<BufferBlock*>(nullptr), blocks_[block_idx]);
+ iov[iov_used].iov_base = blocks_[block_idx]->buffer;
+ iov[iov_used].iov_len = GetBlockCapacity(block_idx);
+ DVLOG(1) << "Got block with index: " << block_idx;
+ ++iov_used;
+ block_idx = (start_block_idx + iov_used) % blocks_count_;
+ }
+
+ // Deal with last block if |iov| can hold more.
+ if (iov_used < iov_count) {
+ DCHECK_NE(static_cast<BufferBlock*>(nullptr), blocks_[block_idx]);
+ iov[iov_used].iov_base = blocks_[end_block_idx]->buffer;
+ iov[iov_used].iov_len = end_block_offset + 1;
+ DVLOG(1) << "Got last block with index: " << end_block_idx;
+ ++iov_used;
+ }
+ return iov_used;
+}
+
+bool QuicStreamSequencerBuffer::GetReadableRegion(iovec* iov,
+ QuicTime* timestamp) const {
+ if (ReadableBytes() == 0) {
+ iov[0].iov_base = nullptr;
+ iov[0].iov_len = 0;
+ return false;
+ }
+
+ size_t start_block_idx = NextBlockToRead();
+ iov->iov_base = blocks_[start_block_idx]->buffer + ReadOffset();
+ size_t readable_bytes_in_block = min<size_t>(
+ GetBlockCapacity(start_block_idx) - ReadOffset(), ReadableBytes());
+ size_t region_len = 0;
+ auto iter = frame_arrival_time_map_.begin();
+ *timestamp = iter->second.timestamp;
+ DVLOG(1) << "Readable bytes in block: " << readable_bytes_in_block;
+ for (; iter != frame_arrival_time_map_.end() &&
+ region_len + iter->second.length <= readable_bytes_in_block;
+ ++iter) {
+ if (iter->second.timestamp != *timestamp) {
+ // If reaches a frame arrive at another timestamp, stop expanding current
+ // region.
+ DVLOG(1) << "Meet frame with different timestamp.";
+ break;
+ }
+ region_len += iter->second.length;
+ DVLOG(1) << "Added bytes to region: " << iter->second.length;
+ }
+ if (iter == frame_arrival_time_map_.end() ||
+ iter->second.timestamp == *timestamp) {
+ // If encountered the end of readable bytes before reaching a different
+ // timestamp.
+ DVLOG(1) << "Got all readable bytes in first block.";
+ region_len = readable_bytes_in_block;
+ }
+ iov->iov_len = region_len;
+ return true;
+}
+
+bool QuicStreamSequencerBuffer::MarkConsumed(size_t bytes_used) {
+ if (bytes_used > ReadableBytes()) {
+ return false;
+ }
+ size_t bytes_to_consume = bytes_used;
+ while (bytes_to_consume > 0) {
+ size_t block_idx = NextBlockToRead();
+ size_t offset_in_block = ReadOffset();
+ size_t bytes_available = min<size_t>(
+ ReadableBytes(), GetBlockCapacity(block_idx) - offset_in_block);
+ size_t bytes_read = min<size_t>(bytes_to_consume, bytes_available);
+ total_bytes_read_ += bytes_read;
+ num_bytes_buffered_ -= bytes_read;
+ bytes_to_consume -= bytes_read;
+ // If advanced to the end of current block and end of buffer hasn't wrapped
+ // to this block yet.
+ if (bytes_available == bytes_read) {
+ RetireBlockIfEmpty(block_idx);
+ }
+ }
+ if (bytes_used > 0) {
+ UpdateFrameArrivalMap(total_bytes_read_);
+ }
+ return true;
+}
+
+size_t QuicStreamSequencerBuffer::FlushBufferedFrames() {
+ size_t prev_total_bytes_read = total_bytes_read_;
+ total_bytes_read_ = gaps_.back().begin_offset;
+ Clear();
+ return total_bytes_read_ - prev_total_bytes_read;
+}
+
+void QuicStreamSequencerBuffer::ReleaseWholeBuffer() {
+ if (!reduce_sequencer_buffer_memory_life_time_) {
+ // Don't release buffer if flag is off.
+ return;
+ }
+ Clear();
+ blocks_.reset(nullptr);
+}
+
+size_t QuicStreamSequencerBuffer::ReadableBytes() const {
+ return gaps_.front().begin_offset - total_bytes_read_;
+}
+
+bool QuicStreamSequencerBuffer::HasBytesToRead() const {
+ return ReadableBytes() > 0;
+}
+
+QuicStreamOffset QuicStreamSequencerBuffer::BytesConsumed() const {
+ return total_bytes_read_;
+}
+
+size_t QuicStreamSequencerBuffer::BytesBuffered() const {
+ return num_bytes_buffered_;
+}
+
+size_t QuicStreamSequencerBuffer::GetBlockIndex(QuicStreamOffset offset) const {
+ return (offset % max_buffer_capacity_bytes_) / kBlockSizeBytes;
+}
+
+size_t QuicStreamSequencerBuffer::GetInBlockOffset(
+ QuicStreamOffset offset) const {
+ return (offset % max_buffer_capacity_bytes_) % kBlockSizeBytes;
+}
+
+size_t QuicStreamSequencerBuffer::ReadOffset() const {
+ return GetInBlockOffset(total_bytes_read_);
+}
+
+size_t QuicStreamSequencerBuffer::NextBlockToRead() const {
+ return GetBlockIndex(total_bytes_read_);
+}
+
+bool QuicStreamSequencerBuffer::RetireBlockIfEmpty(size_t block_index) {
+ DCHECK(ReadableBytes() == 0 || GetInBlockOffset(total_bytes_read_) == 0)
+ << "RetireBlockIfEmpty() should only be called when advancing to next "
+ "block"
+ " or a gap has been reached.";
+ // If the whole buffer becomes empty, the last piece of data has been read.
+ if (Empty()) {
+ return RetireBlock(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) {
+ 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;
+ }
+ }
+ return RetireBlock(block_index);
+}
+
+bool QuicStreamSequencerBuffer::Empty() const {
+ return gaps_.size() == 1 && gaps_.front().begin_offset == total_bytes_read_;
+}
+
+size_t QuicStreamSequencerBuffer::GetBlockCapacity(size_t block_index) const {
+ if ((block_index + 1) == blocks_count_) {
+ size_t result = max_buffer_capacity_bytes_ % kBlockSizeBytes;
+ if (result == 0) { // whole block
+ result = kBlockSizeBytes;
+ }
+ return result;
+ } else {
+ return kBlockSizeBytes;
+ }
+}
+
+void QuicStreamSequencerBuffer::UpdateFrameArrivalMap(QuicStreamOffset offset) {
+ // Get the frame before which all frames should be removed.
+ auto next_frame = frame_arrival_time_map_.upper_bound(offset);
+ DCHECK(next_frame != frame_arrival_time_map_.begin());
+ auto iter = frame_arrival_time_map_.begin();
+ while (iter != next_frame) {
+ auto erased = *iter;
+ iter = frame_arrival_time_map_.erase(iter);
+ DVLOG(1) << "Removed FrameInfo with offset: " << erased.first
+ << " and length: " << erased.second.length;
+ if (erased.first + erased.second.length > offset) {
+ // If last frame is partially read out, update this FrameInfo and insert
+ // it back.
+ auto updated = std::make_pair(
+ offset, FrameInfo(erased.first + erased.second.length - offset,
+ erased.second.timestamp));
+ DVLOG(1) << "Inserted FrameInfo with offset: " << updated.first
+ << " and length: " << updated.second.length;
+ frame_arrival_time_map_.insert(updated);
+ }
+ }
+}
+
+string QuicStreamSequencerBuffer::GapsDebugString() {
+ string current_gaps_string;
+ for (const Gap& gap : gaps_) {
+ QuicStreamOffset current_gap_begin = gap.begin_offset;
+ QuicStreamOffset current_gap_end = gap.end_offset;
+ current_gaps_string += RangeDebugString(current_gap_begin, current_gap_end);
+ }
+ return current_gaps_string;
+}
+
+string QuicStreamSequencerBuffer::ReceivedFramesDebugString() {
+ string current_frames_string;
+ for (auto it : frame_arrival_time_map_) {
+ QuicStreamOffset current_frame_begin_offset = it.first;
+ QuicStreamOffset current_frame_end_offset =
+ it.second.length + current_frame_begin_offset;
+ if (FLAGS_quic_stream_sequencer_buffer_debug) {
+ current_frames_string = string(StringPrintf(
+ "%s[%" PRIu64 ", %" PRIu64 ") receiving time %" PRId64 " ",
+ current_frames_string.c_str(), current_frame_begin_offset,
+ current_frame_end_offset, it.second.timestamp.ToDebuggingValue()));
+ } else {
+ current_frames_string = string(StringPrintf(
+ "%s[%" PRIu64 ", %" PRIu64 ") ", current_frames_string.c_str(),
+ current_frame_begin_offset, current_frame_end_offset));
+ }
+ }
+ return current_frames_string;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_stream_sequencer_buffer.h b/chromium/net/quic/core/quic_stream_sequencer_buffer.h
new file mode 100644
index 00000000000..40bf64e4d17
--- /dev/null
+++ b/chromium/net/quic/core/quic_stream_sequencer_buffer.h
@@ -0,0 +1,263 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_STREAM_SEQUENCER_BUFFER_H_
+#define NET_QUIC_QUIC_STREAM_SEQUENCER_BUFFER_H_
+
+// QuicStreamSequencerBuffer implements QuicStreamSequencerBufferInterface.
+// It 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.
+// - 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).
+// - Data can be read from the buffer if there is no gap before it,
+// and the buffer shrinks as the data are consumed.
+// - An upper limit on the number of blocks in the buffer provides an upper
+// bound on memory use.
+//
+// This class is thread-unsafe.
+//
+// QuicStreamSequencerBuffer maintains a concept of the readable region, which
+// contains all written data that has not been read.
+// It promises stability of the underlying memory addresses in the readable
+// region, so pointers into it can be maintained, and the offset of a pointer
+// from the start of the read region can be calculated.
+//
+// Expected Use:
+// QuicStreamSequencerBuffer buffer(2.5 * 8 * 1024);
+// std::string source(1024, 'a');
+// base::StringPiece std::string_piece(source.data(), source.size());
+// size_t written = 0;
+// buffer.OnStreamData(800, std::string_piece, GetEpollClockNow(), &written);
+// source = std::string{800, 'b'};
+// base::StringPiece std::string_piece1(source.data(), 800);
+// // Try to write to [1, 801), but should fail due to overlapping,
+// // res should be QUIC_INVALID_STREAM_DATA
+// auto res = buffer.OnStreamData(1, std::string_piece1, &written));
+// // write to [0, 800), res should be QUIC_NO_ERROR
+// auto res = buffer.OnStreamData(0, std::string_piece1, GetEpollClockNow(),
+// &written);
+//
+// // Read into a iovec array with total capacity of 120 bytes.
+// char dest[120];
+// iovec iovecs[3]{iovec{dest, 40}, iovec{dest + 40, 40},
+// iovec{dest + 80, 40}};
+// size_t read = buffer.Readv(iovecs, 3);
+//
+// // Get single readable region with timestamp.
+// QuicTime t;
+// iovec iov;
+// buffer.GetReadableRegion(iov, &t);
+//
+// // Get readable regions from [256, 1024) and consume some of it.
+// iovec iovs[2];
+// int iov_count = buffer.GetReadableRegions(iovs, 2);
+// // Consume some bytes in iovs, returning number of bytes having been
+// consumed.
+// size_t consumed = consume_iovs(iovs, iov_count);
+// buffer.MarkConsumed(consumed);
+
+#include <stddef.h>
+
+#include <functional>
+#include <list>
+#include <memory>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+namespace test {
+class QuicStreamSequencerBufferPeer;
+} // namespace test
+
+class NET_EXPORT_PRIVATE QuicStreamSequencerBuffer {
+ public:
+ // A Gap indicates a missing chunk of bytes between
+ // [begin_offset, end_offset) in the stream
+ struct NET_EXPORT_PRIVATE Gap {
+ Gap(QuicStreamOffset begin_offset, QuicStreamOffset end_offset);
+ QuicStreamOffset begin_offset;
+ QuicStreamOffset end_offset;
+ };
+
+ // A FrameInfo stores the length of a frame and the time it arrived.
+ struct NET_EXPORT_PRIVATE FrameInfo {
+ FrameInfo();
+ FrameInfo(size_t length, QuicTime timestamp);
+
+ size_t length;
+ QuicTime timestamp;
+ };
+
+ // Size of blocks used by this buffer.
+ // Choose 8K to make block large enough to hold multiple frames, each of
+ // which could be up to 1.5 KB.
+ static const size_t kBlockSizeBytes = 8 * 1024; // 8KB
+
+ // The basic storage block used by this buffer.
+ struct BufferBlock {
+ char buffer[kBlockSizeBytes];
+ };
+
+ explicit QuicStreamSequencerBuffer(size_t max_capacity_bytes);
+ ~QuicStreamSequencerBuffer();
+
+ // Free the space used to buffer data.
+ void Clear();
+
+ // Returns true if there is nothing to read in this buffer.
+ bool Empty() const;
+
+ // Called to buffer new data received for this stream. If the data was
+ // successfully buffered, returns QUIC_NO_ERROR and stores the number of
+ // bytes buffered in |bytes_buffered|. Returns an error otherwise.
+ // |timestamp| is the time the data arrived.
+ QuicErrorCode OnStreamData(QuicStreamOffset offset,
+ base::StringPiece data,
+ QuicTime timestamp,
+ size_t* bytes_buffered,
+ std::string* error_details);
+
+ // Reads from this buffer into given iovec array, up to number of iov_len
+ // iovec objects and returns the number of bytes read.
+ QuicErrorCode Readv(const struct iovec* dest_iov,
+ size_t dest_count,
+ size_t* bytes_read,
+ std::string* error_details);
+
+ // Returns the readable region of valid data in iovec format. The readable
+ // region is the buffer region where there is valid data not yet read by
+ // client.
+ // Returns the number of iovec entries in |iov| which were populated.
+ // If the region is empty, one iovec entry with 0 length
+ // is returned, and the function returns 0. If there are more readable
+ // regions than iov_size, the function only processes the first
+ // iov_size of them.
+ int GetReadableRegions(struct iovec* iov, int iov_len) const;
+
+ // Fills in one iovec with data which all arrived at the same time from the
+ // next readable region.
+ // Populates |timestamp| with the time that this data arrived.
+ // Returns false if there is no readable region available.
+ bool GetReadableRegion(iovec* iov, QuicTime* timestamp) const;
+
+ // Called after GetReadableRegions() to free up |bytes_used| space if these
+ // bytes are processed.
+ // Pre-requisite: bytes_used <= available bytes to read.
+ bool MarkConsumed(size_t bytes_buffered);
+
+ // Deletes and records as consumed any buffered data and clear the buffer.
+ // (To be called only after sequencer's StopReading has been called.)
+ size_t FlushBufferedFrames();
+
+ // Free the memory of buffered data.
+ void ReleaseWholeBuffer();
+
+ // Whether there are bytes can be read out.
+ bool HasBytesToRead() const;
+
+ // Count how many bytes have been consumed (read out of buffer).
+ QuicStreamOffset BytesConsumed() const;
+
+ // Count how many bytes are in buffer at this moment.
+ size_t BytesBuffered() const;
+
+ bool reduce_sequencer_buffer_memory_life_time() const {
+ return reduce_sequencer_buffer_memory_life_time_;
+ }
+
+ private:
+ friend class test::QuicStreamSequencerBufferPeer;
+
+ // Dispose the given buffer block.
+ // After calling this method, blocks_[index] is set to nullptr
+ // in order to indicate that no memory set is allocated for that block.
+ // Returns true on success, false otherwise.
+ 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.
+ // If the block at |block_index| contains no buffered data, the block
+ // should be retired.
+ // Return false on success, or false otherwise.
+ bool RetireBlockIfEmpty(size_t block_index);
+
+ // Called within OnStreamData() to update the gap OnStreamData() writes into
+ // (remove, split or change begin/end offset).
+ void UpdateGapList(std::list<Gap>::iterator gap_with_new_data_written,
+ QuicStreamOffset start_offset,
+ size_t bytes_written);
+
+ // Calculate the capacity of block at specified index.
+ // Return value should be either kBlockSizeBytes for non-trailing blocks and
+ // max_buffer_capacity % kBlockSizeBytes for trailing block.
+ size_t GetBlockCapacity(size_t index) const;
+
+ // Does not check if offset is within reasonable range.
+ size_t GetBlockIndex(QuicStreamOffset offset) const;
+
+ // Given an offset in the stream, return the offset from the beginning of the
+ // block which contains this data.
+ size_t GetInBlockOffset(QuicStreamOffset offset) const;
+
+ // Get offset relative to index 0 in logical 1st block to start next read.
+ size_t ReadOffset() const;
+
+ // 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;
+
+ // Called after Readv() and MarkConsumed() to keep frame_arrival_time_map_
+ // up to date.
+ // |offset| is the byte next read should start from. All frames before it
+ // should be removed from the map.
+ void UpdateFrameArrivalMap(QuicStreamOffset offset);
+
+ // Return |gaps_| as a std::string: [1024, 1500) [1800, 2048)... for
+ // debugging.
+ std::string GapsDebugString();
+
+ // Return all received frames as a std::string in same format as
+ // GapsDebugString();
+ std::string ReceivedFramesDebugString();
+
+ // The maximum total capacity of this buffer in byte, as constructed.
+ const size_t max_buffer_capacity_bytes_;
+
+ // How many blocks this buffer would need when it reaches full capacity.
+ const size_t blocks_count_;
+
+ // Number of bytes read out of buffer.
+ QuicStreamOffset total_bytes_read_;
+
+ // Contains Gaps which represents currently missing data.
+ std::list<Gap> gaps_;
+
+ // If true, allocate buffer memory upon the first frame arrival and release
+ // the memory when stream is read closed.
+ bool reduce_sequencer_buffer_memory_life_time_;
+
+ // An ordered, variable-length list of blocks, with the length limited
+ // such that the number of blocks never exceeds blocks_count_.
+ // Each list entry can hold up to kBlockSizeBytes bytes.
+ std::unique_ptr<BufferBlock* []> blocks_;
+
+ // Number of bytes in buffer.
+ size_t num_bytes_buffered_;
+
+ // Stores all the buffered frames' start offset, length and arrival time.
+ std::map<QuicStreamOffset, FrameInfo> frame_arrival_time_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicStreamSequencerBuffer);
+};
+} // namespace net
+
+#endif // NET_QUIC_QUIC_STREAM_SEQUENCER_BUFFER_H_
diff --git a/chromium/net/quic/core/quic_stream_sequencer_buffer_interface.h b/chromium/net/quic/core/quic_stream_sequencer_buffer_interface.h
new file mode 100644
index 00000000000..96b6bb929d2
--- /dev/null
+++ b/chromium/net/quic/core/quic_stream_sequencer_buffer_interface.h
@@ -0,0 +1,77 @@
+// 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.
+
+#ifndef NET_QUIC_QUIC_STREAM_SEQUENCER_BUFFER_INTERFACE_H_
+#define NET_QUIC_QUIC_STREAM_SEQUENCER_BUFFER_INTERFACE_H_
+
+#include <stddef.h>
+
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+// The QuicStreamSequencer uses an implementation of this interface to store
+// received data.
+class NET_EXPORT_PRIVATE QuicStreamSequencerBufferInterface {
+ public:
+ virtual ~QuicStreamSequencerBufferInterface() {}
+
+ // Free the space used to buffer data.
+ virtual void Clear() = 0;
+
+ // Returns true if there is nothing to read in this buffer.
+ virtual bool Empty() const = 0;
+
+ // Called to buffer new data received for this stream. If the data was
+ // successfully buffered, returns QUIC_NO_ERROR and stores the number of
+ // bytes buffered in |bytes_buffered|. Returns an error otherwise.
+ // |timestamp| is the time the data arrived.
+ virtual QuicErrorCode OnStreamData(QuicStreamOffset offset,
+ base::StringPiece data,
+ QuicTime timestamp,
+ size_t* bytes_buffered) = 0;
+
+ // Reads from this buffer into given iovec array, up to number of iov_len
+ // iovec objects and returns the number of bytes read.
+ virtual size_t Readv(const struct iovec* iov, size_t iov_len) = 0;
+
+ // Returns the readable region of valid data in iovec format. The readable
+ // region is the buffer region where there is valid data not yet read by
+ // client.
+ // Returns the number of iovec entries in |iov| which were populated.
+ // If the region is empty, one iovec entry with 0 length
+ // is returned, and the function returns 0. If there are more readable
+ // regions than iov_size, the function only processes the first
+ // iov_size of them.
+ virtual int GetReadableRegions(struct iovec* iov, int iov_len) const = 0;
+
+ // Fills in one iovec with data which all arrived at the same time from the
+ // next readable region.
+ // Populates |timestamp| with the time that this data arrived.
+ // Returns false if there is no readable region available.
+ virtual bool GetReadableRegion(iovec* iov, QuicTime* timestamp) const = 0;
+
+ // Called after GetReadableRegions() to free up |bytes_used| space if these
+ // bytes are processed.
+ // Pre-requisite: bytes_used <= available bytes to read.
+ virtual bool MarkConsumed(size_t bytes_used) = 0;
+
+ // Deletes and records as consumed any buffered data and clear the buffer.
+ // (To be called only after sequencer's StopReading has been called.)
+ virtual size_t FlushBufferedFrames() = 0;
+
+ // Whether there are bytes can be read out.
+ virtual bool HasBytesToRead() const = 0;
+
+ // Count how many bytes have been consumed (read out of buffer).
+ virtual QuicStreamOffset BytesConsumed() const = 0;
+
+ // Count how many bytes are in buffer at this moment.
+ virtual size_t BytesBuffered() const = 0;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_STREAM_SEQUENCER_BUFFER_INTERFACE_H_
diff --git a/chromium/net/quic/core/quic_stream_sequencer_buffer_test.cc b/chromium/net/quic/core/quic_stream_sequencer_buffer_test.cc
new file mode 100644
index 00000000000..6db66a6da6d
--- /dev/null
+++ b/chromium/net/quic/core/quic_stream_sequencer_buffer_test.cc
@@ -0,0 +1,1065 @@
+// 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.
+#include "net/quic/core/quic_stream_sequencer_buffer.h"
+
+#include <algorithm>
+#include <limits>
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/rand_util.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/quic_stream_sequencer_buffer_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gmock_mutant.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::min;
+using std::string;
+
+namespace net {
+
+namespace test {
+
+char GetCharFromIOVecs(size_t offset, iovec iov[], size_t count) {
+ size_t start_offset = 0;
+ for (size_t i = 0; i < count; i++) {
+ if (iov[i].iov_len == 0) {
+ continue;
+ }
+ size_t end_offset = start_offset + iov[i].iov_len - 1;
+ if (offset >= start_offset && offset <= end_offset) {
+ const char* buf = reinterpret_cast<const char*>(iov[i].iov_base);
+ return buf[offset - start_offset];
+ }
+ start_offset += iov[i].iov_len;
+ }
+ LOG(ERROR) << "Could not locate char at offset " << offset << " in " << count
+ << " iovecs";
+ for (size_t i = 0; i < count; ++i) {
+ LOG(ERROR) << " iov[" << i << "].iov_len = " << iov[i].iov_len;
+ }
+ return '\0';
+}
+
+const size_t kMaxNumGapsAllowed = 2 * kMaxPacketGap;
+
+static const size_t kBlockSizeBytes =
+ QuicStreamSequencerBuffer::kBlockSizeBytes;
+typedef QuicStreamSequencerBuffer::BufferBlock BufferBlock;
+typedef QuicStreamSequencerBuffer::Gap Gap;
+typedef QuicStreamSequencerBuffer::FrameInfo FrameInfo;
+
+namespace {
+
+class QuicStreamSequencerBufferTest : public testing::Test {
+ public:
+ void SetUp() override { Initialize(); }
+
+ void ResetMaxCapacityBytes(size_t max_capacity_bytes) {
+ max_capacity_bytes_ = max_capacity_bytes;
+ Initialize();
+ }
+
+ protected:
+ void Initialize() {
+ buffer_.reset(new QuicStreamSequencerBuffer(max_capacity_bytes_));
+ helper_.reset(new QuicStreamSequencerBufferPeer(buffer_.get()));
+ }
+
+ // Use 2.5 here to make sure the buffer has more than one block and its end
+ // doesn't align with the end of a block in order to test all the offset
+ // calculation.
+ size_t max_capacity_bytes_ = 2.5 * kBlockSizeBytes;
+
+ MockClock clock_;
+ std::unique_ptr<QuicStreamSequencerBuffer> buffer_;
+ std::unique_ptr<QuicStreamSequencerBufferPeer> helper_;
+ QuicFlagSaver flag_saver_;
+ string error_details_;
+};
+
+TEST_F(QuicStreamSequencerBufferTest, InitializationWithDifferentSizes) {
+ const size_t kCapacity = 2 * QuicStreamSequencerBuffer::kBlockSizeBytes;
+ ResetMaxCapacityBytes(kCapacity);
+ EXPECT_EQ(max_capacity_bytes_, helper_->max_buffer_capacity());
+ EXPECT_TRUE(helper_->CheckInitialState());
+
+ const size_t kCapacity1 = 8 * QuicStreamSequencerBuffer::kBlockSizeBytes;
+ ResetMaxCapacityBytes(kCapacity1);
+ EXPECT_EQ(kCapacity1, helper_->max_buffer_capacity());
+ EXPECT_TRUE(helper_->CheckInitialState());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, ClearOnEmpty) {
+ buffer_->Clear();
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, OnStreamData0length) {
+ size_t written;
+ QuicErrorCode error = buffer_->OnStreamData(800, "", clock_.ApproximateNow(),
+ &written, &error_details_);
+ EXPECT_EQ(error, QUIC_EMPTY_STREAM_FRAME_NO_FIN);
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithinBlock) {
+ if (FLAGS_quic_reduce_sequencer_buffer_memory_life_time) { // NOLINT
+ EXPECT_FALSE(helper_->IsBufferAllocated());
+ }
+ string source(1024, 'a');
+ size_t written;
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ QuicTime t = clock_.ApproximateNow();
+ EXPECT_EQ(QUIC_NO_ERROR,
+ buffer_->OnStreamData(800, source, t, &written, &error_details_));
+ BufferBlock* block_ptr = helper_->GetBlock(0);
+ for (size_t i = 0; i < source.size(); ++i) {
+ 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);
+ auto* frame_map = helper_->frame_arrival_time_map();
+ EXPECT_EQ(1u, frame_map->size());
+ EXPECT_EQ(800u, frame_map->begin()->first);
+ EXPECT_EQ(t, (*frame_map)[800].timestamp);
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+ EXPECT_TRUE(helper_->IsBufferAllocated());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, OnStreamDataInvalidSource) {
+ FLAGS_quic_stream_sequencer_buffer_debug = true;
+ // Pass in an invalid source, expects to return error.
+ StringPiece source;
+ source.set(nullptr, 1024);
+ size_t written;
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ QuicTime t = clock_.ApproximateNow();
+ EXPECT_EQ(QUIC_STREAM_SEQUENCER_INVALID_STATE,
+ buffer_->OnStreamData(800, source, t, &written, &error_details_));
+ EXPECT_EQ(
+ 0u, error_details_.find("QuicStreamSequencerBuffer error: OnStreamData()"
+ " dest == nullptr: false"
+ " source == nullptr: true"));
+}
+
+TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithOverlap) {
+ string source(1024, 'a');
+ // Write something into [800, 1824)
+ size_t written;
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ QuicTime t1 = clock_.ApproximateNow();
+ 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();
+ 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);
+}
+
+TEST_F(QuicStreamSequencerBufferTest,
+ OnStreamDataOverlapAndDuplicateCornerCases) {
+ string source(1024, 'a');
+ // Write something into [800, 1824)
+ size_t written;
+ buffer_->OnStreamData(800, source, clock_.ApproximateNow(), &written,
+ &error_details_);
+ source = string(800, 'b');
+ // 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,
+ &error_details_));
+ // write to [0, 800)
+ EXPECT_EQ(QUIC_NO_ERROR,
+ 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_));
+ 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_));
+ auto* frame_map = helper_->frame_arrival_time_map();
+ EXPECT_EQ(3u, frame_map->size());
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithoutOverlap) {
+ string source(1024, 'a');
+ // Write something into [800, 1824).
+ size_t written;
+ EXPECT_EQ(QUIC_NO_ERROR,
+ buffer_->OnStreamData(800, source, clock_.ApproximateNow(),
+ &written, &error_details_));
+ source = string(100, 'b');
+ // Write something into [kBlockSizeBytes * 2 - 20, kBlockSizeBytes * 2 + 80).
+ EXPECT_EQ(QUIC_NO_ERROR,
+ buffer_->OnStreamData(kBlockSizeBytes * 2 - 20, source,
+ clock_.ApproximateNow(), &written,
+ &error_details_));
+ EXPECT_EQ(3, helper_->GapSize());
+ EXPECT_EQ(1024u + 100u, buffer_->BytesBuffered());
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+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())));
+
+ // Three new out of order frames arrive.
+ const size_t kBytesToWrite = 100;
+ string source(kBytesToWrite, 'a');
+ size_t written;
+ // Frame [2^32 + 500, 2^32 + 600).
+ QuicStreamOffset offset = pow(2, 32) + 500;
+ EXPECT_EQ(QUIC_NO_ERROR,
+ buffer_->OnStreamData(offset, source, clock_.ApproximateNow(),
+ &written, &error_details_));
+ EXPECT_EQ(2, helper_->GapSize());
+
+ // Frame [2^32 + 700, 2^32 + 800).
+ offset = pow(2, 32) + 700;
+ EXPECT_EQ(QUIC_NO_ERROR,
+ buffer_->OnStreamData(offset, source, clock_.ApproximateNow(),
+ &written, &error_details_));
+ EXPECT_EQ(3, helper_->GapSize());
+
+ // Another frame [2^32 + 300, 2^32 + 400).
+ offset = pow(2, 32) + 300;
+ EXPECT_EQ(QUIC_NO_ERROR,
+ buffer_->OnStreamData(offset, source, clock_.ApproximateNow(),
+ &written, &error_details_));
+ EXPECT_EQ(4, helper_->GapSize());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, OnStreamDataTillEnd) {
+ // Write 50 bytes to the end.
+ const size_t kBytesToWrite = 50;
+ string source(kBytesToWrite, 'a');
+ size_t written;
+ EXPECT_EQ(QUIC_NO_ERROR,
+ buffer_->OnStreamData(max_capacity_bytes_ - kBytesToWrite, source,
+ clock_.ApproximateNow(), &written,
+ &error_details_));
+ EXPECT_EQ(50u, buffer_->BytesBuffered());
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, OnStreamDataTillEndCorner) {
+ // Write 1 byte to the end.
+ const size_t kBytesToWrite = 1;
+ string source(kBytesToWrite, 'a');
+ size_t written;
+ EXPECT_EQ(QUIC_NO_ERROR,
+ buffer_->OnStreamData(max_capacity_bytes_ - kBytesToWrite, source,
+ clock_.ApproximateNow(), &written,
+ &error_details_));
+ EXPECT_EQ(1u, buffer_->BytesBuffered());
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, OnStreamDataBeyondCapacity) {
+ string source(60, 'a');
+ size_t written;
+ EXPECT_EQ(QUIC_INTERNAL_ERROR,
+ buffer_->OnStreamData(max_capacity_bytes_ - 50, source,
+ clock_.ApproximateNow(), &written,
+ &error_details_));
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+
+ source = "b";
+ EXPECT_EQ(QUIC_INTERNAL_ERROR,
+ buffer_->OnStreamData(max_capacity_bytes_, source,
+ clock_.ApproximateNow(), &written,
+ &error_details_));
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+
+ EXPECT_EQ(QUIC_INTERNAL_ERROR,
+ buffer_->OnStreamData(max_capacity_bytes_ * 1000, source,
+ clock_.ApproximateNow(), &written,
+ &error_details_));
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+ EXPECT_EQ(0u, buffer_->BytesBuffered());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, Readv100Bytes) {
+ string source(1024, 'a');
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ QuicTime t1 = clock_.ApproximateNow();
+ // Write something into [kBlockSizeBytes, kBlockSizeBytes + 1024).
+ size_t written;
+ buffer_->OnStreamData(kBlockSizeBytes, source, t1, &written, &error_details_);
+ EXPECT_FALSE(buffer_->HasBytesToRead());
+ source = string(100, 'b');
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ QuicTime t2 = clock_.ApproximateNow();
+ // Write something into [0, 100).
+ buffer_->OnStreamData(0, source, t2, &written, &error_details_);
+ EXPECT_TRUE(buffer_->HasBytesToRead());
+ EXPECT_EQ(2u, helper_->frame_arrival_time_map()->size());
+ // Read into a iovec array with total capacity of 120 bytes.
+ char dest[120];
+ iovec iovecs[3]{iovec{dest, 40}, iovec{dest + 40, 40}, iovec{dest + 80, 40}};
+ size_t read;
+ EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(iovecs, 3, &read, &error_details_));
+ LOG(ERROR) << error_details_;
+ EXPECT_EQ(100u, read);
+ EXPECT_EQ(100u, buffer_->BytesConsumed());
+ EXPECT_EQ(source, string(dest, read));
+ EXPECT_EQ(1u, helper_->frame_arrival_time_map()->size());
+ // The first block should be released as its data has been read out.
+ EXPECT_EQ(nullptr, helper_->GetBlock(0));
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, ReadvError) {
+ FLAGS_quic_stream_sequencer_buffer_debug = true;
+ string source = string(100, 'b');
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ QuicTime t1 = clock_.ApproximateNow();
+ // Write something into [0, 100).
+ size_t written;
+ buffer_->OnStreamData(0, source, t1, &written, &error_details_);
+ EXPECT_TRUE(helper_->GetBlock(0) != nullptr);
+ EXPECT_TRUE(buffer_->HasBytesToRead());
+ // Read into a iovec array with total capacity of 120 bytes.
+ iovec iov{nullptr, 120};
+ size_t read;
+ EXPECT_EQ(QUIC_STREAM_SEQUENCER_INVALID_STATE,
+ buffer_->Readv(&iov, 1, &read, &error_details_));
+ EXPECT_EQ(0u,
+ error_details_.find(
+ "QuicStreamSequencerBuffer error: Readv() dest == nullptr: true"
+ " blocks_[0] == nullptr: false"));
+}
+
+TEST_F(QuicStreamSequencerBufferTest, ReadvAcrossBlocks) {
+ string source(kBlockSizeBytes + 50, 'a');
+ // Write 1st block to full and extand 50 bytes to next block.
+ size_t written;
+ buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
+ &error_details_);
+ EXPECT_EQ(source.size(), helper_->ReadableBytes());
+ // Iteratively read 512 bytes from buffer_-> Overwrite dest[] each time.
+ char dest[512];
+ while (helper_->ReadableBytes()) {
+ std::fill(dest, dest + 512, 0);
+ iovec iovecs[2]{iovec{dest, 256}, iovec{dest + 256, 256}};
+ size_t read;
+ EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(iovecs, 2, &read, &error_details_));
+ }
+ // The last read only reads the rest 50 bytes in 2nd block.
+ EXPECT_EQ(string(50, 'a'), string(dest, 50));
+ EXPECT_EQ(0, dest[50]) << "Dest[50] shouln't be filled.";
+ EXPECT_EQ(source.size(), buffer_->BytesConsumed());
+ EXPECT_TRUE(buffer_->Empty());
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, ClearAfterRead) {
+ string source(kBlockSizeBytes + 50, 'a');
+ // Write 1st block to full with 'a'.
+ size_t written;
+ buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
+ &error_details_);
+ // Read first 512 bytes from buffer to make space at the beginning.
+ char dest[512]{0};
+ const iovec iov{dest, 512};
+ size_t read;
+ EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_));
+ // Clear() should make buffer empty while preserving BytesConsumed()
+ buffer_->Clear();
+ EXPECT_TRUE(buffer_->Empty());
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest,
+ OnStreamDataAcrossLastBlockAndFillCapacity) {
+ string source(kBlockSizeBytes + 50, 'a');
+ // Write 1st block to full with 'a'.
+ size_t written;
+ buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
+ &error_details_);
+ // Read first 512 bytes from buffer to make space at the beginning.
+ char dest[512]{0};
+ const iovec iov{dest, 512};
+ size_t read;
+ EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_));
+ EXPECT_EQ(source.size(), written);
+
+ // Write more than half block size of bytes in the last block with 'b', which
+ // will wrap to the beginning and reaches the full capacity.
+ source = string(0.5 * kBlockSizeBytes + 512, 'b');
+ EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData(2 * kBlockSizeBytes, source,
+ clock_.ApproximateNow(),
+ &written, &error_details_));
+ EXPECT_EQ(source.size(), written);
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest,
+ OnStreamDataAcrossLastBlockAndExceedCapacity) {
+ string source(kBlockSizeBytes + 50, 'a');
+ // Write 1st block to full.
+ size_t written;
+ buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
+ &error_details_);
+ // Read first 512 bytes from buffer to make space at the beginning.
+ char dest[512]{0};
+ const iovec iov{dest, 512};
+ size_t read;
+ EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_));
+
+ // Try to write from [max_capacity_bytes_ - 0.5 * kBlockSizeBytes,
+ // max_capacity_bytes_ + 512 + 1). But last bytes exceeds current capacity.
+ source = string(0.5 * kBlockSizeBytes + 512 + 1, 'b');
+ EXPECT_EQ(QUIC_INTERNAL_ERROR,
+ buffer_->OnStreamData(2 * kBlockSizeBytes, source,
+ clock_.ApproximateNow(), &written,
+ &error_details_));
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, ReadvAcrossLastBlock) {
+ // Write to full capacity and read out 512 bytes at beginning and continue
+ // appending 256 bytes.
+ string source(max_capacity_bytes_, 'a');
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ QuicTime t = clock_.ApproximateNow();
+ size_t written;
+ buffer_->OnStreamData(0, source, t, &written, &error_details_);
+ char dest[512]{0};
+ const iovec iov{dest, 512};
+ size_t read;
+ EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_));
+ source = string(256, 'b');
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ QuicTime t2 = clock_.ApproximateNow();
+ buffer_->OnStreamData(max_capacity_bytes_, source, t2, &written,
+ &error_details_);
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+ EXPECT_EQ(2u, helper_->frame_arrival_time_map()->size());
+
+ // Read all data out.
+ std::unique_ptr<char[]> dest1{new char[max_capacity_bytes_]};
+ dest1[0] = 0;
+ const iovec iov1{dest1.get(), max_capacity_bytes_};
+ EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov1, 1, &read, &error_details_));
+ EXPECT_EQ(max_capacity_bytes_ - 512 + 256, read);
+ EXPECT_EQ(max_capacity_bytes_ + 256, buffer_->BytesConsumed());
+ EXPECT_TRUE(buffer_->Empty());
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+ EXPECT_EQ(0u, helper_->frame_arrival_time_map()->size());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, ReadvEmpty) {
+ char dest[512]{0};
+ iovec iov{dest, 512};
+ size_t read;
+ EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_));
+ EXPECT_EQ(0u, read);
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionsEmpty) {
+ iovec iovs[2];
+ int iov_count = buffer_->GetReadableRegions(iovs, 2);
+ EXPECT_EQ(0, iov_count);
+ EXPECT_EQ(nullptr, iovs[iov_count].iov_base);
+ EXPECT_EQ(0u, iovs[iov_count].iov_len);
+}
+
+TEST_F(QuicStreamSequencerBufferTest, ReleaseWholeBuffer) {
+ // Tests that buffer is not deallocated unless ReleaseWholeBuffer() is called.
+ if (!FLAGS_quic_reduce_sequencer_buffer_memory_life_time) { // NOLINT
+ // Won't release buffer when flag is off.
+ return;
+ }
+
+ string source(100, 'b');
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ QuicTime t1 = clock_.ApproximateNow();
+ // Write something into [0, 100).
+ size_t written;
+ buffer_->OnStreamData(0, source, t1, &written, &error_details_);
+ EXPECT_TRUE(buffer_->HasBytesToRead());
+ char dest[120];
+ iovec iovecs[3]{iovec{dest, 40}, iovec{dest + 40, 40}, iovec{dest + 80, 40}};
+ size_t read;
+ EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(iovecs, 3, &read, &error_details_));
+ EXPECT_EQ(100u, read);
+ EXPECT_EQ(100u, buffer_->BytesConsumed());
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+ EXPECT_TRUE(helper_->IsBufferAllocated());
+ buffer_->ReleaseWholeBuffer();
+ EXPECT_FALSE(helper_->IsBufferAllocated());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionsBlockedByGap) {
+ // Write into [1, 1024).
+ string source(1023, 'a');
+ size_t written;
+ buffer_->OnStreamData(1, source, clock_.ApproximateNow(), &written,
+ &error_details_);
+ // Try to get readable regions, but none is there.
+ iovec iovs[2];
+ int iov_count = buffer_->GetReadableRegions(iovs, 2);
+ EXPECT_EQ(0, iov_count);
+}
+
+TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionsTillEndOfBlock) {
+ // Write first block to full with [0, 256) 'a' and the rest 'b' then read out
+ // [0, 256)
+ string source(kBlockSizeBytes, 'a');
+ size_t written;
+ buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
+ &error_details_);
+ char dest[256];
+ helper_->Read(dest, 256);
+ // Get readable region from [256, 1024)
+ iovec iovs[2];
+ int iov_count = buffer_->GetReadableRegions(iovs, 2);
+ EXPECT_EQ(1, iov_count);
+ EXPECT_EQ(
+ string(kBlockSizeBytes - 256, 'a'),
+ string(reinterpret_cast<const char*>(iovs[0].iov_base), iovs[0].iov_len));
+}
+
+TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionsWithinOneBlock) {
+ // Write into [0, 1024) and then read out [0, 256)
+ string source(1024, 'a');
+ size_t written;
+ buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
+ &error_details_);
+ char dest[256];
+ helper_->Read(dest, 256);
+ // Get readable region from [256, 1024)
+ iovec iovs[2];
+ int iov_count = buffer_->GetReadableRegions(iovs, 2);
+ EXPECT_EQ(1, iov_count);
+ EXPECT_EQ(
+ string(1024 - 256, 'a'),
+ string(reinterpret_cast<const char*>(iovs[0].iov_base), iovs[0].iov_len));
+}
+
+TEST_F(QuicStreamSequencerBufferTest,
+ GetReadableRegionsAcrossBlockWithLongIOV) {
+ // Write into [0, 2 * kBlockSizeBytes + 1024) and then read out [0, 1024)
+ string source(2 * kBlockSizeBytes + 1024, 'a');
+ size_t written;
+ buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
+ &error_details_);
+ char dest[1024];
+ helper_->Read(dest, 1024);
+
+ iovec iovs[4];
+ int iov_count = buffer_->GetReadableRegions(iovs, 4);
+ EXPECT_EQ(3, iov_count);
+ EXPECT_EQ(kBlockSizeBytes - 1024, iovs[0].iov_len);
+ EXPECT_EQ(kBlockSizeBytes, iovs[1].iov_len);
+ EXPECT_EQ(1024u, iovs[2].iov_len);
+}
+
+TEST_F(QuicStreamSequencerBufferTest,
+ GetReadableRegionsWithMultipleIOVsAcrossEnd) {
+ // Write into [0, 2 * kBlockSizeBytes + 1024) and then read out [0, 1024)
+ // and then append 1024 + 512 bytes.
+ string source(2.5 * kBlockSizeBytes - 1024, 'a');
+ size_t written;
+ buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
+ &error_details_);
+ char dest[1024];
+ helper_->Read(dest, 1024);
+ // Write across the end.
+ source = string(1024 + 512, 'b');
+ buffer_->OnStreamData(2.5 * kBlockSizeBytes - 1024, source,
+ clock_.ApproximateNow(), &written, &error_details_);
+ // Use short iovec's.
+ iovec iovs[2];
+ int iov_count = buffer_->GetReadableRegions(iovs, 2);
+ EXPECT_EQ(2, iov_count);
+ EXPECT_EQ(kBlockSizeBytes - 1024, iovs[0].iov_len);
+ EXPECT_EQ(kBlockSizeBytes, iovs[1].iov_len);
+ // Use long iovec's and wrap the end of buffer.
+ iovec iovs1[5];
+ EXPECT_EQ(4, buffer_->GetReadableRegions(iovs1, 5));
+ EXPECT_EQ(0.5 * kBlockSizeBytes, iovs1[2].iov_len);
+ EXPECT_EQ(512u, iovs1[3].iov_len);
+ EXPECT_EQ(string(512, 'b'),
+ string(reinterpret_cast<const char*>(iovs1[3].iov_base),
+ iovs1[3].iov_len));
+}
+
+TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionEmpty) {
+ iovec iov;
+ QuicTime t = QuicTime::Zero();
+ EXPECT_FALSE(buffer_->GetReadableRegion(&iov, &t));
+ EXPECT_EQ(nullptr, iov.iov_base);
+ EXPECT_EQ(0u, iov.iov_len);
+}
+
+TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionBeforeGap) {
+ // Write into [1, 1024).
+ string source(1023, 'a');
+ size_t written;
+ buffer_->OnStreamData(1, source, clock_.ApproximateNow(), &written,
+ &error_details_);
+ // GetReadableRegion should return false because range [0,1) hasn't been
+ // filled yet.
+ iovec iov;
+ QuicTime t = QuicTime::Zero();
+ EXPECT_FALSE(buffer_->GetReadableRegion(&iov, &t));
+}
+
+TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionTillEndOfBlock) {
+ // Write into [0, kBlockSizeBytes + 1) and then read out [0, 256)
+ string source(kBlockSizeBytes + 1, 'a');
+ size_t written;
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ QuicTime t = clock_.ApproximateNow();
+ buffer_->OnStreamData(0, source, t, &written, &error_details_);
+ char dest[256];
+ helper_->Read(dest, 256);
+ // Get readable region from [256, 1024)
+ iovec iov;
+ QuicTime t2 = QuicTime::Zero();
+ EXPECT_TRUE(buffer_->GetReadableRegion(&iov, &t2));
+ EXPECT_EQ(t, t2);
+ EXPECT_EQ(string(kBlockSizeBytes - 256, 'a'),
+ string(reinterpret_cast<const char*>(iov.iov_base), iov.iov_len));
+}
+
+TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionTillGap) {
+ // Write into [0, kBlockSizeBytes - 1) and then read out [0, 256)
+ string source(kBlockSizeBytes - 1, 'a');
+ size_t written;
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ QuicTime t = clock_.ApproximateNow();
+ buffer_->OnStreamData(0, source, t, &written, &error_details_);
+ char dest[256];
+ helper_->Read(dest, 256);
+ // Get readable region from [256, 1023)
+ iovec iov;
+ QuicTime t2 = QuicTime::Zero();
+ EXPECT_TRUE(buffer_->GetReadableRegion(&iov, &t2));
+ EXPECT_EQ(t, t2);
+ EXPECT_EQ(string(kBlockSizeBytes - 1 - 256, 'a'),
+ string(reinterpret_cast<const char*>(iov.iov_base), iov.iov_len));
+}
+
+TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionByArrivalTime) {
+ // Write into [0, kBlockSizeBytes - 100) and then read out [0, 256)
+ string source(kBlockSizeBytes - 100, 'a');
+ size_t written;
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ QuicTime t = clock_.ApproximateNow();
+ buffer_->OnStreamData(0, source, t, &written, &error_details_);
+ char dest[256];
+ helper_->Read(dest, 256);
+ // Write into [kBlockSizeBytes - 100, kBlockSizeBytes - 50)] in same time
+ string source2(50, 'b');
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ buffer_->OnStreamData(kBlockSizeBytes - 100, source2, t, &written,
+ &error_details_);
+
+ // Write into [kBlockSizeBytes - 50, kBlockSizeBytes)] in another time
+ string source3(50, 'c');
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ QuicTime t3 = clock_.ApproximateNow();
+ buffer_->OnStreamData(kBlockSizeBytes - 50, source3, t3, &written,
+ &error_details_);
+
+ // Get readable region from [256, 1024 - 50)
+ iovec iov;
+ QuicTime t4 = QuicTime::Zero();
+ EXPECT_TRUE(buffer_->GetReadableRegion(&iov, &t4));
+ EXPECT_EQ(t, t4);
+ EXPECT_EQ(string(kBlockSizeBytes - 100 - 256, 'a') + source2,
+ string(reinterpret_cast<const char*>(iov.iov_base), iov.iov_len));
+}
+
+TEST_F(QuicStreamSequencerBufferTest, MarkConsumedInOneBlock) {
+ // Write into [0, 1024) and then read out [0, 256)
+ string source(1024, 'a');
+ size_t written;
+ buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
+ &error_details_);
+ char dest[256];
+ helper_->Read(dest, 256);
+
+ EXPECT_TRUE(buffer_->MarkConsumed(512));
+ EXPECT_EQ(256u + 512u, buffer_->BytesConsumed());
+ EXPECT_EQ(256u, helper_->ReadableBytes());
+ EXPECT_EQ(1u, helper_->frame_arrival_time_map()->size());
+ buffer_->MarkConsumed(256);
+ EXPECT_EQ(0u, helper_->frame_arrival_time_map()->size());
+ EXPECT_TRUE(buffer_->Empty());
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, MarkConsumedNotEnoughBytes) {
+ // Write into [0, 1024) and then read out [0, 256)
+ string source(1024, 'a');
+ size_t written;
+ QuicTime t = clock_.ApproximateNow();
+ buffer_->OnStreamData(0, source, t, &written, &error_details_);
+ char dest[256];
+ helper_->Read(dest, 256);
+
+ // Consume 1st 512 bytes
+ EXPECT_TRUE(buffer_->MarkConsumed(512));
+ EXPECT_EQ(256u + 512u, buffer_->BytesConsumed());
+ EXPECT_EQ(256u, helper_->ReadableBytes());
+ // Try to consume one bytes more than available. Should return false.
+ EXPECT_FALSE(buffer_->MarkConsumed(257));
+ EXPECT_EQ(256u + 512u, buffer_->BytesConsumed());
+ QuicTime t2 = QuicTime::Zero();
+ iovec iov;
+ EXPECT_TRUE(buffer_->GetReadableRegion(&iov, &t2));
+ EXPECT_EQ(t, t2);
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, MarkConsumedAcrossBlock) {
+ // Write into [0, 2 * kBlockSizeBytes + 1024) and then read out [0, 1024)
+ string source(2 * kBlockSizeBytes + 1024, 'a');
+ size_t written;
+ buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
+ &error_details_);
+ char dest[1024];
+ helper_->Read(dest, 1024);
+
+ buffer_->MarkConsumed(2 * kBlockSizeBytes);
+ EXPECT_EQ(source.size(), buffer_->BytesConsumed());
+ EXPECT_TRUE(buffer_->Empty());
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, MarkConsumedAcrossEnd) {
+ // Write into [0, 2.5 * kBlockSizeBytes - 1024) and then read out [0, 1024)
+ // and then append 1024 + 512 bytes.
+ string source(2.5 * kBlockSizeBytes - 1024, 'a');
+ size_t written;
+ buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
+ &error_details_);
+ char dest[1024];
+ helper_->Read(dest, 1024);
+ source = string(1024 + 512, 'b');
+ buffer_->OnStreamData(2.5 * kBlockSizeBytes - 1024, source,
+ clock_.ApproximateNow(), &written, &error_details_);
+ EXPECT_EQ(1024u, buffer_->BytesConsumed());
+
+ // Consume to the end of 2nd block.
+ buffer_->MarkConsumed(2 * kBlockSizeBytes - 1024);
+ EXPECT_EQ(2 * kBlockSizeBytes, buffer_->BytesConsumed());
+ // Consume across the physical end of buffer
+ buffer_->MarkConsumed(0.5 * kBlockSizeBytes + 500);
+ EXPECT_EQ(max_capacity_bytes_ + 500, buffer_->BytesConsumed());
+ EXPECT_EQ(12u, helper_->ReadableBytes());
+ // Consume to the logical end of buffer
+ buffer_->MarkConsumed(12);
+ EXPECT_EQ(max_capacity_bytes_ + 512, buffer_->BytesConsumed());
+ EXPECT_TRUE(buffer_->Empty());
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, FlushBufferedFrames) {
+ // Write into [0, 2.5 * kBlockSizeBytes - 1024) and then read out [0, 1024).
+ string source(max_capacity_bytes_ - 1024, 'a');
+ size_t written;
+ buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
+ &error_details_);
+ char dest[1024];
+ helper_->Read(dest, 1024);
+ EXPECT_EQ(1024u, buffer_->BytesConsumed());
+ // Write [1024, 512) to the physical beginning.
+ source = string(512, 'b');
+ buffer_->OnStreamData(max_capacity_bytes_, source, clock_.ApproximateNow(),
+ &written, &error_details_);
+ EXPECT_EQ(512u, written);
+ EXPECT_EQ(max_capacity_bytes_ - 1024 + 512, buffer_->FlushBufferedFrames());
+ EXPECT_EQ(max_capacity_bytes_ + 512, buffer_->BytesConsumed());
+ EXPECT_TRUE(buffer_->Empty());
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+ // Clear buffer at this point should still preserve BytesConsumed().
+ buffer_->Clear();
+ EXPECT_EQ(max_capacity_bytes_ + 512, buffer_->BytesConsumed());
+ EXPECT_TRUE(helper_->CheckBufferInvariants());
+}
+
+TEST_F(QuicStreamSequencerBufferTest, TooManyGaps) {
+ // Make sure max capacity is large enough that it is possible to have more
+ // than |kMaxNumGapsAllowed| number of gaps.
+ max_capacity_bytes_ = 3 * kBlockSizeBytes;
+ // Feed buffer with 1-byte discontiguous frames. e.g. [1,2), [3,4), [5,6)...
+ for (QuicStreamOffset begin = 1; begin <= max_capacity_bytes_; begin += 2) {
+ size_t written;
+ QuicErrorCode rs = buffer_->OnStreamData(
+ begin, "a", clock_.ApproximateNow(), &written, &error_details_);
+
+ 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_);
+ break;
+ }
+ }
+}
+
+class QuicStreamSequencerBufferRandomIOTest
+ : public QuicStreamSequencerBufferTest {
+ public:
+ typedef std::pair<QuicStreamOffset, size_t> OffsetSizePair;
+
+ void SetUp() override {
+ // Test against a larger capacity then above tests. Also make sure the last
+ // block is partially available to use.
+ max_capacity_bytes_ = 6.25 * kBlockSizeBytes;
+ // Stream to be buffered should be larger than the capacity to test wrap
+ // around.
+ bytes_to_buffer_ = 2 * max_capacity_bytes_;
+ Initialize();
+
+ uint32_t seed = base::RandInt(0, std::numeric_limits<int32_t>::max());
+ LOG(INFO) << "RandomWriteAndProcessInPlace test seed is " << seed;
+ rng_.set_seed(seed);
+ }
+
+ // Create an out-of-order source stream with given size to populate
+ // shuffled_buf_.
+ void CreateSourceAndShuffle(size_t max_chunk_size_bytes) {
+ max_chunk_size_bytes_ = max_chunk_size_bytes;
+ std::unique_ptr<OffsetSizePair[]> chopped_stream(
+ new OffsetSizePair[bytes_to_buffer_]);
+
+ // Split stream into small chunks with random length. chopped_stream will be
+ // populated with segmented stream chunks.
+ size_t start_chopping_offset = 0;
+ size_t iterations = 0;
+ while (start_chopping_offset < bytes_to_buffer_) {
+ size_t max_chunk = min<size_t>(max_chunk_size_bytes_,
+ bytes_to_buffer_ - start_chopping_offset);
+ size_t chunk_size = rng_.RandUint64() % max_chunk + 1;
+ chopped_stream[iterations] =
+ OffsetSizePair(start_chopping_offset, chunk_size);
+ start_chopping_offset += chunk_size;
+ ++iterations;
+ }
+ DCHECK(start_chopping_offset == bytes_to_buffer_);
+ size_t chunk_num = iterations;
+
+ // Randomly change the sequence of in-ordered OffsetSizePairs to make a
+ // out-of-order array of OffsetSizePairs.
+ for (int i = chunk_num - 1; i >= 0; --i) {
+ size_t random_idx = rng_.RandUint64() % (i + 1);
+ DVLOG(1) << "chunk offset " << chopped_stream[random_idx].first
+ << " size " << chopped_stream[random_idx].second;
+ shuffled_buf_.push_front(chopped_stream[random_idx]);
+ chopped_stream[random_idx] = chopped_stream[i];
+ }
+ }
+
+ // Write the currently first chunk of data in the out-of-order stream into
+ // QuicStreamSequencerBuffer. If current chuck cannot be written into buffer
+ // because it goes beyond current capacity, move it to the end of
+ // shuffled_buf_ and write it later.
+ void WriteNextChunkToBuffer() {
+ OffsetSizePair& chunk = shuffled_buf_.front();
+ QuicStreamOffset offset = chunk.first;
+ const size_t num_to_write = chunk.second;
+ std::unique_ptr<char[]> write_buf{new char[max_chunk_size_bytes_]};
+ for (size_t i = 0; i < num_to_write; ++i) {
+ write_buf[i] = (offset + i) % 256;
+ }
+ base::StringPiece string_piece_w(write_buf.get(), num_to_write);
+ size_t written;
+ auto result =
+ buffer_->OnStreamData(offset, string_piece_w, clock_.ApproximateNow(),
+ &written, &error_details_);
+ if (result == QUIC_NO_ERROR) {
+ shuffled_buf_.pop_front();
+ total_bytes_written_ += num_to_write;
+ } else {
+ // This chunk offset exceeds window size.
+ shuffled_buf_.push_back(chunk);
+ shuffled_buf_.pop_front();
+ }
+ DVLOG(1) << " write at offset: " << offset
+ << " len to write: " << num_to_write << " write result: " << result
+ << " left over: " << shuffled_buf_.size();
+ }
+
+ protected:
+ std::list<OffsetSizePair> shuffled_buf_;
+ size_t max_chunk_size_bytes_;
+ QuicStreamOffset bytes_to_buffer_;
+ size_t total_bytes_written_ = 0;
+ size_t total_bytes_read_ = 0;
+ SimpleRandom rng_;
+};
+
+TEST_F(QuicStreamSequencerBufferRandomIOTest, RandomWriteAndReadv) {
+ // Set kMaxReadSize larger than kBlockSizeBytes to test both small and large
+ // read.
+ const size_t kMaxReadSize = kBlockSizeBytes * 2;
+ // kNumReads is larger than 1 to test how multiple read destinations work.
+ const size_t kNumReads = 2;
+ // Since write and read operation have equal possibility to be called. Bytes
+ // to be written into and read out of should roughly the same.
+ const size_t kMaxWriteSize = kNumReads * kMaxReadSize;
+ size_t iterations = 0;
+
+ CreateSourceAndShuffle(kMaxWriteSize);
+
+ while ((!shuffled_buf_.empty() || total_bytes_read_ < bytes_to_buffer_) &&
+ iterations <= 2 * bytes_to_buffer_) {
+ uint8_t next_action =
+ shuffled_buf_.empty() ? uint8_t{1} : rng_.RandUint64() % 2;
+ DVLOG(1) << "iteration: " << iterations;
+ switch (next_action) {
+ case 0: { // write
+ WriteNextChunkToBuffer();
+ ASSERT_TRUE(helper_->CheckBufferInvariants());
+ break;
+ }
+ case 1: { // readv
+ std::unique_ptr<char[][kMaxReadSize]> read_buf{
+ new char[kNumReads][kMaxReadSize]};
+ iovec dest_iov[kNumReads];
+ size_t num_to_read = 0;
+ for (size_t i = 0; i < kNumReads; ++i) {
+ dest_iov[i].iov_base =
+ reinterpret_cast<void*>(const_cast<char*>(read_buf[i]));
+ dest_iov[i].iov_len = rng_.RandUint64() % kMaxReadSize;
+ num_to_read += dest_iov[i].iov_len;
+ }
+ size_t actually_read;
+ EXPECT_EQ(QUIC_NO_ERROR,
+ buffer_->Readv(dest_iov, kNumReads, &actually_read,
+ &error_details_));
+ ASSERT_LE(actually_read, num_to_read);
+ DVLOG(1) << " read from offset: " << total_bytes_read_
+ << " size: " << num_to_read
+ << " actual read: " << actually_read;
+ for (size_t i = 0; i < actually_read; ++i) {
+ char ch = (i + total_bytes_read_) % 256;
+ ASSERT_EQ(ch, GetCharFromIOVecs(i, dest_iov, kNumReads))
+ << " at iteration " << iterations;
+ }
+ total_bytes_read_ += actually_read;
+ ASSERT_EQ(total_bytes_read_, buffer_->BytesConsumed());
+ ASSERT_TRUE(helper_->CheckBufferInvariants());
+ break;
+ }
+ }
+ ++iterations;
+ ASSERT_LE(total_bytes_read_, total_bytes_written_);
+ }
+ EXPECT_LT(iterations, bytes_to_buffer_) << "runaway test";
+ EXPECT_LE(bytes_to_buffer_, total_bytes_read_) << "iterations: "
+ << iterations;
+ EXPECT_LE(bytes_to_buffer_, total_bytes_written_);
+}
+
+TEST_F(QuicStreamSequencerBufferRandomIOTest, RandomWriteAndConsumeInPlace) {
+ // The value 4 is chosen such that the max write size is no larger than the
+ // maximum buffer capacity.
+ const size_t kMaxNumReads = 4;
+ // Adjust write amount be roughly equal to that GetReadableRegions() can get.
+ const size_t kMaxWriteSize = kMaxNumReads * kBlockSizeBytes;
+ ASSERT_LE(kMaxWriteSize, max_capacity_bytes_);
+ size_t iterations = 0;
+
+ CreateSourceAndShuffle(kMaxWriteSize);
+
+ while ((!shuffled_buf_.empty() || total_bytes_read_ < bytes_to_buffer_) &&
+ iterations <= 2 * bytes_to_buffer_) {
+ uint8_t next_action =
+ shuffled_buf_.empty() ? uint8_t{1} : rng_.RandUint64() % 2;
+ DVLOG(1) << "iteration: " << iterations;
+ switch (next_action) {
+ case 0: { // write
+ WriteNextChunkToBuffer();
+ ASSERT_TRUE(helper_->CheckBufferInvariants());
+ break;
+ }
+ case 1: { // GetReadableRegions and then MarkConsumed
+ size_t num_read = rng_.RandUint64() % kMaxNumReads + 1;
+ iovec dest_iov[kMaxNumReads];
+ ASSERT_TRUE(helper_->CheckBufferInvariants());
+ size_t actually_num_read =
+ buffer_->GetReadableRegions(dest_iov, num_read);
+ ASSERT_LE(actually_num_read, num_read);
+ size_t avail_bytes = 0;
+ for (size_t i = 0; i < actually_num_read; ++i) {
+ avail_bytes += dest_iov[i].iov_len;
+ }
+ // process random number of bytes (check the value of each byte).
+ size_t bytes_to_process = rng_.RandUint64() % (avail_bytes + 1);
+ size_t bytes_processed = 0;
+ for (size_t i = 0; i < actually_num_read; ++i) {
+ size_t bytes_in_block = min<size_t>(
+ bytes_to_process - bytes_processed, dest_iov[i].iov_len);
+ if (bytes_in_block == 0) {
+ break;
+ }
+ for (size_t j = 0; j < bytes_in_block; ++j) {
+ ASSERT_LE(bytes_processed, bytes_to_process);
+ char char_expected =
+ (buffer_->BytesConsumed() + bytes_processed) % 256;
+ ASSERT_EQ(char_expected,
+ reinterpret_cast<const char*>(dest_iov[i].iov_base)[j])
+ << " at iteration " << iterations;
+ ++bytes_processed;
+ }
+ }
+
+ buffer_->MarkConsumed(bytes_processed);
+
+ DVLOG(1) << "iteration " << iterations << ": try to get " << num_read
+ << " readable regions, actually get " << actually_num_read
+ << " from offset: " << total_bytes_read_
+ << "\nprocesse bytes: " << bytes_processed;
+ total_bytes_read_ += bytes_processed;
+ ASSERT_EQ(total_bytes_read_, buffer_->BytesConsumed());
+ ASSERT_TRUE(helper_->CheckBufferInvariants());
+ break;
+ }
+ }
+ ++iterations;
+ ASSERT_LE(total_bytes_read_, total_bytes_written_);
+ }
+ EXPECT_LT(iterations, bytes_to_buffer_) << "runaway test";
+ EXPECT_LE(bytes_to_buffer_, total_bytes_read_) << "iterations: "
+ << iterations;
+ EXPECT_LE(bytes_to_buffer_, total_bytes_written_);
+}
+
+} // anonymous namespace
+
+} // namespace test
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_stream_sequencer_test.cc b/chromium/net/quic/core/quic_stream_sequencer_test.cc
new file mode 100644
index 00000000000..b3b473f020a
--- /dev/null
+++ b/chromium/net/quic/core/quic_stream_sequencer_test.cc
@@ -0,0 +1,691 @@
+// 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/quic_stream_sequencer.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/rand_util.h"
+#include "net/base/ip_endpoint.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/core/reliable_quic_stream.h"
+#include "net/quic/test_tools/mock_clock.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/include/gmock/gmock.h"
+#include "testing/gmock_mutant.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringPiece;
+using std::map;
+using std::min;
+using std::pair;
+using std::string;
+using std::vector;
+using testing::_;
+using testing::AnyNumber;
+using testing::CreateFunctor;
+using testing::InSequence;
+using testing::Return;
+using testing::StrEq;
+
+namespace net {
+namespace test {
+
+class MockStream : public ReliableQuicStream {
+ public:
+ MockStream(QuicSession* session, QuicStreamId id)
+ : ReliableQuicStream(id, session) {}
+
+ MOCK_METHOD0(OnFinRead, void());
+ MOCK_METHOD0(OnDataAvailable, void());
+ MOCK_METHOD2(CloseConnectionWithDetails,
+ void(QuicErrorCode error, const string& details));
+ MOCK_METHOD1(Reset, void(QuicRstStreamErrorCode error));
+ MOCK_METHOD0(OnCanWrite, void());
+ virtual bool IsFlowControlEnabled() const { return true; }
+
+ const IPEndPoint& PeerAddressOfLatestPacket() const override {
+ return peer_address_;
+ }
+
+ protected:
+ IPEndPoint peer_address_ = IPEndPoint(net::test::Any4(), 65535);
+};
+
+namespace {
+
+static const char kPayload[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+class QuicStreamSequencerTest : public ::testing::Test {
+ public:
+ void ConsumeData(size_t num_bytes) {
+ char buffer[1024];
+ ASSERT_GT(arraysize(buffer), num_bytes);
+ struct iovec iov;
+ iov.iov_base = buffer;
+ iov.iov_len = num_bytes;
+ ASSERT_EQ(static_cast<int>(num_bytes), sequencer_->Readv(&iov, 1));
+ }
+
+ protected:
+ QuicStreamSequencerTest()
+ : connection_(new MockQuicConnection(&helper_,
+ &alarm_factory_,
+ Perspective::IS_CLIENT)),
+ session_(connection_),
+ stream_(&session_, 1),
+ sequencer_(new QuicStreamSequencer(&stream_, &clock_)) {}
+
+ // Verify that the data in first region match with the expected[0].
+ bool VerifyReadableRegion(const vector<string>& expected) {
+ iovec iovecs[1];
+ if (sequencer_->GetReadableRegions(iovecs, 1)) {
+ return (VerifyIovecs(iovecs, 1, vector<string>{expected[0]}));
+ }
+ return false;
+ }
+
+ // Verify that the data in each of currently readable regions match with each
+ // item given in |expected|.
+ bool VerifyReadableRegions(const vector<string>& expected) {
+ iovec iovecs[5];
+ size_t num_iovecs =
+ sequencer_->GetReadableRegions(iovecs, arraysize(iovecs));
+ return VerifyReadableRegion(expected) &&
+ VerifyIovecs(iovecs, num_iovecs, expected);
+ }
+
+ bool VerifyIovecs(iovec* iovecs,
+ size_t num_iovecs,
+ const vector<string>& expected) {
+ int start_position = 0;
+ for (size_t i = 0; i < num_iovecs; ++i) {
+ if (!VerifyIovec(iovecs[i],
+ expected[0].substr(start_position, iovecs[i].iov_len))) {
+ return false;
+ }
+ start_position += iovecs[i].iov_len;
+ }
+ return true;
+ }
+
+ bool VerifyIovec(const iovec& iovec, StringPiece expected) {
+ if (iovec.iov_len != expected.length()) {
+ LOG(ERROR) << "Invalid length: " << iovec.iov_len << " vs "
+ << expected.length();
+ return false;
+ }
+ if (memcmp(iovec.iov_base, expected.data(), expected.length()) != 0) {
+ LOG(ERROR) << "Invalid data: " << static_cast<char*>(iovec.iov_base)
+ << " vs " << expected;
+ return false;
+ }
+ return true;
+ }
+
+ void OnFinFrame(QuicStreamOffset byte_offset, const char* data) {
+ QuicStreamFrame frame;
+ frame.stream_id = 1;
+ frame.offset = byte_offset;
+ frame.data_buffer = data;
+ frame.data_length = strlen(data);
+ frame.fin = true;
+ sequencer_->OnStreamFrame(frame);
+ }
+
+ void OnFrame(QuicStreamOffset byte_offset, const char* data) {
+ QuicStreamFrame frame;
+ frame.stream_id = 1;
+ frame.offset = byte_offset;
+ frame.data_buffer = data;
+ frame.data_length = strlen(data);
+ frame.fin = false;
+ sequencer_->OnStreamFrame(frame);
+ }
+
+ size_t NumBufferedBytes() {
+ return QuicStreamSequencerPeer::GetNumBufferedBytes(sequencer_.get());
+ }
+
+ MockQuicConnectionHelper helper_;
+ MockAlarmFactory alarm_factory_;
+ MockQuicConnection* connection_;
+ MockClock clock_;
+ MockQuicSpdySession session_;
+ testing::StrictMock<MockStream> stream_;
+ std::unique_ptr<QuicStreamSequencer> sequencer_;
+};
+
+// TODO(rch): reorder these tests so they build on each other.
+
+TEST_F(QuicStreamSequencerTest, RejectOldFrame) {
+ EXPECT_CALL(stream_, OnDataAvailable())
+ .WillOnce(testing::Invoke(
+ CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
+ base::Unretained(this), 3)));
+
+ OnFrame(0, "abc");
+
+ EXPECT_EQ(0u, NumBufferedBytes());
+ EXPECT_EQ(3u, sequencer_->NumBytesConsumed());
+ EXPECT_EQ(3u, stream_.flow_controller()->bytes_consumed());
+ // Ignore this - it matches a past packet number and we should not see it
+ // again.
+ OnFrame(0, "def");
+ EXPECT_EQ(0u, NumBufferedBytes());
+}
+
+TEST_F(QuicStreamSequencerTest, RejectBufferedFrame) {
+ EXPECT_CALL(stream_, OnDataAvailable());
+
+ OnFrame(0, "abc");
+ EXPECT_EQ(3u, NumBufferedBytes());
+ EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
+
+ // Ignore this - it matches a buffered frame.
+ // Right now there's no checking that the payload is consistent.
+ OnFrame(0, "def");
+ EXPECT_EQ(3u, NumBufferedBytes());
+}
+
+TEST_F(QuicStreamSequencerTest, FullFrameConsumed) {
+ EXPECT_CALL(stream_, OnDataAvailable())
+ .WillOnce(testing::Invoke(
+ CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
+ base::Unretained(this), 3)));
+
+ OnFrame(0, "abc");
+ EXPECT_EQ(0u, NumBufferedBytes());
+ EXPECT_EQ(3u, sequencer_->NumBytesConsumed());
+}
+
+TEST_F(QuicStreamSequencerTest, BlockedThenFullFrameConsumed) {
+ sequencer_->SetBlockedUntilFlush();
+
+ OnFrame(0, "abc");
+ EXPECT_EQ(3u, NumBufferedBytes());
+ EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
+
+ EXPECT_CALL(stream_, OnDataAvailable())
+ .WillOnce(testing::Invoke(
+ CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
+ base::Unretained(this), 3)));
+ sequencer_->SetUnblocked();
+ EXPECT_EQ(0u, NumBufferedBytes());
+ EXPECT_EQ(3u, sequencer_->NumBytesConsumed());
+
+ EXPECT_CALL(stream_, OnDataAvailable())
+ .WillOnce(testing::Invoke(
+ CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
+ base::Unretained(this), 3)));
+ EXPECT_FALSE(sequencer_->IsClosed());
+ OnFinFrame(3, "def");
+ EXPECT_TRUE(sequencer_->IsClosed());
+}
+
+TEST_F(QuicStreamSequencerTest, BlockedThenFullFrameAndFinConsumed) {
+ sequencer_->SetBlockedUntilFlush();
+
+ OnFinFrame(0, "abc");
+ EXPECT_EQ(3u, NumBufferedBytes());
+ EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
+
+ EXPECT_CALL(stream_, OnDataAvailable())
+ .WillOnce(testing::Invoke(
+ CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
+ base::Unretained(this), 3)));
+ EXPECT_FALSE(sequencer_->IsClosed());
+ sequencer_->SetUnblocked();
+ EXPECT_TRUE(sequencer_->IsClosed());
+ EXPECT_EQ(0u, NumBufferedBytes());
+ EXPECT_EQ(3u, sequencer_->NumBytesConsumed());
+}
+
+TEST_F(QuicStreamSequencerTest, EmptyFrame) {
+ EXPECT_CALL(stream_,
+ CloseConnectionWithDetails(QUIC_EMPTY_STREAM_FRAME_NO_FIN, _));
+ OnFrame(0, "");
+ EXPECT_EQ(0u, NumBufferedBytes());
+ EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
+}
+
+TEST_F(QuicStreamSequencerTest, EmptyFinFrame) {
+ EXPECT_CALL(stream_, OnDataAvailable());
+ OnFinFrame(0, "");
+ EXPECT_EQ(0u, NumBufferedBytes());
+ EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
+}
+
+TEST_F(QuicStreamSequencerTest, PartialFrameConsumed) {
+ EXPECT_CALL(stream_, OnDataAvailable())
+ .WillOnce(testing::Invoke(
+ CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
+ base::Unretained(this), 2)));
+
+ OnFrame(0, "abc");
+ EXPECT_EQ(1u, NumBufferedBytes());
+ EXPECT_EQ(2u, sequencer_->NumBytesConsumed());
+}
+
+TEST_F(QuicStreamSequencerTest, NextxFrameNotConsumed) {
+ EXPECT_CALL(stream_, OnDataAvailable());
+
+ OnFrame(0, "abc");
+ EXPECT_EQ(3u, NumBufferedBytes());
+ EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
+}
+
+TEST_F(QuicStreamSequencerTest, FutureFrameNotProcessed) {
+ OnFrame(3, "abc");
+ EXPECT_EQ(3u, NumBufferedBytes());
+ EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
+}
+
+TEST_F(QuicStreamSequencerTest, OutOfOrderFrameProcessed) {
+ // Buffer the first
+ OnFrame(6, "ghi");
+ EXPECT_EQ(3u, NumBufferedBytes());
+ EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
+ EXPECT_EQ(3u, sequencer_->NumBytesBuffered());
+ // Buffer the second
+ OnFrame(3, "def");
+ EXPECT_EQ(6u, NumBufferedBytes());
+ EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
+ EXPECT_EQ(6u, sequencer_->NumBytesBuffered());
+
+ EXPECT_CALL(stream_, OnDataAvailable())
+ .WillOnce(testing::Invoke(
+ CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
+ base::Unretained(this), 9)));
+
+ // Now process all of them at once.
+ OnFrame(0, "abc");
+ EXPECT_EQ(9u, sequencer_->NumBytesConsumed());
+ EXPECT_EQ(0u, sequencer_->NumBytesBuffered());
+
+ EXPECT_EQ(0u, NumBufferedBytes());
+}
+
+TEST_F(QuicStreamSequencerTest, BasicHalfCloseOrdered) {
+ InSequence s;
+
+ EXPECT_CALL(stream_, OnDataAvailable())
+ .WillOnce(testing::Invoke(
+ CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
+ base::Unretained(this), 3)));
+ OnFinFrame(0, "abc");
+
+ EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
+}
+
+TEST_F(QuicStreamSequencerTest, BasicHalfCloseUnorderedWithFlush) {
+ OnFinFrame(6, "");
+ EXPECT_EQ(6u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
+
+ OnFrame(3, "def");
+ EXPECT_CALL(stream_, OnDataAvailable())
+ .WillOnce(testing::Invoke(
+ CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
+ base::Unretained(this), 6)));
+ EXPECT_FALSE(sequencer_->IsClosed());
+ OnFrame(0, "abc");
+ EXPECT_TRUE(sequencer_->IsClosed());
+}
+
+TEST_F(QuicStreamSequencerTest, BasicHalfUnordered) {
+ OnFinFrame(3, "");
+ EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
+
+ EXPECT_CALL(stream_, OnDataAvailable())
+ .WillOnce(testing::Invoke(
+ CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
+ base::Unretained(this), 3)));
+ EXPECT_FALSE(sequencer_->IsClosed());
+ OnFrame(0, "abc");
+ EXPECT_TRUE(sequencer_->IsClosed());
+}
+
+TEST_F(QuicStreamSequencerTest, TerminateWithReadv) {
+ char buffer[3];
+
+ OnFinFrame(3, "");
+ EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
+
+ EXPECT_FALSE(sequencer_->IsClosed());
+
+ EXPECT_CALL(stream_, OnDataAvailable());
+ OnFrame(0, "abc");
+
+ iovec iov = {&buffer[0], 3};
+ int bytes_read = sequencer_->Readv(&iov, 1);
+ EXPECT_EQ(3, bytes_read);
+ EXPECT_TRUE(sequencer_->IsClosed());
+}
+
+TEST_F(QuicStreamSequencerTest, MutipleOffsets) {
+ OnFinFrame(3, "");
+ EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
+
+ EXPECT_CALL(stream_, Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS));
+ OnFinFrame(5, "");
+ EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
+
+ EXPECT_CALL(stream_, Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS));
+ OnFinFrame(1, "");
+ EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
+
+ OnFinFrame(3, "");
+ EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
+}
+
+class QuicSequencerRandomTest : public QuicStreamSequencerTest {
+ public:
+ typedef pair<int, string> Frame;
+ typedef vector<Frame> FrameList;
+
+ void CreateFrames() {
+ int payload_size = arraysize(kPayload) - 1;
+ int remaining_payload = payload_size;
+ while (remaining_payload != 0) {
+ int size = min(OneToN(6), remaining_payload);
+ int index = payload_size - remaining_payload;
+ list_.push_back(std::make_pair(index, string(kPayload + index, size)));
+ remaining_payload -= size;
+ }
+ }
+
+ QuicSequencerRandomTest() { CreateFrames(); }
+
+ int OneToN(int n) { return base::RandInt(1, n); }
+
+ void ReadAvailableData() {
+ // Read all available data
+ char output[arraysize(kPayload) + 1];
+ iovec iov;
+ iov.iov_base = output;
+ iov.iov_len = arraysize(output);
+ int bytes_read = sequencer_->Readv(&iov, 1);
+ EXPECT_NE(0, bytes_read);
+ output_.append(output, bytes_read);
+ }
+
+ string output_;
+ // Data which peek at using GetReadableRegion if we back up.
+ string peeked_;
+ FrameList list_;
+};
+
+// All frames are processed as soon as we have sequential data.
+// Infinite buffering, so all frames are acked right away.
+TEST_F(QuicSequencerRandomTest, RandomFramesNoDroppingNoBackup) {
+ InSequence s;
+ EXPECT_CALL(stream_, OnDataAvailable())
+ .Times(AnyNumber())
+ .WillRepeatedly(
+ Invoke(this, &QuicSequencerRandomTest::ReadAvailableData));
+
+ while (!list_.empty()) {
+ int index = OneToN(list_.size()) - 1;
+ LOG(ERROR) << "Sending index " << index << " " << list_[index].second;
+ OnFrame(list_[index].first, list_[index].second.data());
+
+ list_.erase(list_.begin() + index);
+ }
+
+ ASSERT_EQ(arraysize(kPayload) - 1, output_.size());
+ EXPECT_EQ(kPayload, output_);
+}
+
+TEST_F(QuicSequencerRandomTest, RandomFramesNoDroppingBackup) {
+ char buffer[10];
+ iovec iov[2];
+ iov[0].iov_base = &buffer[0];
+ iov[0].iov_len = 5;
+ iov[1].iov_base = &buffer[5];
+ iov[1].iov_len = 5;
+
+ EXPECT_CALL(stream_, OnDataAvailable()).Times(AnyNumber());
+
+ while (output_.size() != arraysize(kPayload) - 1) {
+ if (!list_.empty() && (base::RandUint64() % 2 == 0)) { // Send data
+ int index = OneToN(list_.size()) - 1;
+ OnFrame(list_[index].first, list_[index].second.data());
+ list_.erase(list_.begin() + index);
+ } else { // Read data
+ bool has_bytes = sequencer_->HasBytesToRead();
+ iovec peek_iov[20];
+ int iovs_peeked = sequencer_->GetReadableRegions(peek_iov, 20);
+ QuicTime timestamp = clock_.ApproximateNow();
+ if (has_bytes) {
+ ASSERT_LT(0, iovs_peeked);
+ ASSERT_TRUE(sequencer_->GetReadableRegion(peek_iov, &timestamp));
+ } else {
+ ASSERT_EQ(0, iovs_peeked);
+ ASSERT_FALSE(sequencer_->GetReadableRegion(peek_iov, &timestamp));
+ }
+ int total_bytes_to_peek = arraysize(buffer);
+ for (int i = 0; i < iovs_peeked; ++i) {
+ int bytes_to_peek = min<int>(peek_iov[i].iov_len, total_bytes_to_peek);
+ peeked_.append(static_cast<char*>(peek_iov[i].iov_base), bytes_to_peek);
+ total_bytes_to_peek -= bytes_to_peek;
+ if (total_bytes_to_peek == 0) {
+ break;
+ }
+ }
+ int bytes_read = sequencer_->Readv(iov, 2);
+ output_.append(buffer, bytes_read);
+ ASSERT_EQ(output_.size(), peeked_.size());
+ }
+ }
+ EXPECT_EQ(string(kPayload), output_);
+ EXPECT_EQ(string(kPayload), peeked_);
+}
+
+// Same as above, just using a different method for reading.
+TEST_F(QuicStreamSequencerTest, MarkConsumed) {
+ InSequence s;
+ EXPECT_CALL(stream_, OnDataAvailable());
+
+ OnFrame(0, "abc");
+ OnFrame(3, "def");
+ OnFrame(6, "ghi");
+
+ // abcdefghi buffered.
+ EXPECT_EQ(9u, sequencer_->NumBytesBuffered());
+
+ // Peek into the data.
+ vector<string> expected = {"abcdefghi"};
+ ASSERT_TRUE(VerifyReadableRegions(expected));
+
+ // Consume 1 byte.
+ sequencer_->MarkConsumed(1);
+ EXPECT_EQ(1u, stream_.flow_controller()->bytes_consumed());
+ // Verify data.
+ vector<string> expected2 = {"bcdefghi"};
+ ASSERT_TRUE(VerifyReadableRegions(expected2));
+ EXPECT_EQ(8u, sequencer_->NumBytesBuffered());
+
+ // Consume 2 bytes.
+ sequencer_->MarkConsumed(2);
+ EXPECT_EQ(3u, stream_.flow_controller()->bytes_consumed());
+ // Verify data.
+ vector<string> expected3 = {"defghi"};
+ ASSERT_TRUE(VerifyReadableRegions(expected3));
+ EXPECT_EQ(6u, sequencer_->NumBytesBuffered());
+
+ // Consume 5 bytes.
+ sequencer_->MarkConsumed(5);
+ EXPECT_EQ(8u, stream_.flow_controller()->bytes_consumed());
+ // Verify data.
+ vector<string> expected4{"i"};
+ ASSERT_TRUE(VerifyReadableRegions(expected4));
+ EXPECT_EQ(1u, sequencer_->NumBytesBuffered());
+}
+
+TEST_F(QuicStreamSequencerTest, MarkConsumedError) {
+ EXPECT_CALL(stream_, OnDataAvailable());
+
+ OnFrame(0, "abc");
+ OnFrame(9, "jklmnopqrstuvwxyz");
+
+ // Peek into the data. Only the first chunk should be readable because of the
+ // missing data.
+ vector<string> expected{"abc"};
+ ASSERT_TRUE(VerifyReadableRegions(expected));
+
+ // Now, attempt to mark consumed more data than was readable and expect the
+ // stream to be closed.
+ EXPECT_CALL(stream_, Reset(QUIC_ERROR_PROCESSING_STREAM));
+ EXPECT_QUIC_BUG(sequencer_->MarkConsumed(4),
+ "Invalid argument to MarkConsumed."
+ " expect to consume: 4, but not enough bytes available.");
+}
+
+TEST_F(QuicStreamSequencerTest, MarkConsumedWithMissingPacket) {
+ InSequence s;
+ EXPECT_CALL(stream_, OnDataAvailable());
+
+ OnFrame(0, "abc");
+ OnFrame(3, "def");
+ // Missing packet: 6, ghi.
+ OnFrame(9, "jkl");
+
+ vector<string> expected = {"abcdef"};
+ ASSERT_TRUE(VerifyReadableRegions(expected));
+
+ sequencer_->MarkConsumed(6);
+}
+
+TEST_F(QuicStreamSequencerTest, DontAcceptOverlappingFrames) {
+ // The peer should never send us non-identical stream frames which contain
+ // overlapping byte ranges - if they do, we close the connection.
+
+ QuicStreamFrame frame1(kClientDataStreamId1, false, 1, StringPiece("hello"));
+ sequencer_->OnStreamFrame(frame1);
+
+ QuicStreamFrame frame2(kClientDataStreamId1, false, 2, StringPiece("hello"));
+ EXPECT_CALL(stream_,
+ CloseConnectionWithDetails(QUIC_OVERLAPPING_STREAM_DATA, _))
+ .Times(1);
+ sequencer_->OnStreamFrame(frame2);
+}
+
+TEST_F(QuicStreamSequencerTest, InOrderTimestamps) {
+ // This test verifies that timestamps returned by
+ // GetReadableRegion() are in the correct sequence when frames
+ // arrive at the sequencer in order.
+ EXPECT_CALL(stream_, OnDataAvailable());
+
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+
+ // Buffer the first frame.
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ QuicTime t1 = clock_.ApproximateNow();
+ OnFrame(0, "abc");
+ EXPECT_EQ(3u, NumBufferedBytes());
+ EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
+ EXPECT_EQ(3u, sequencer_->NumBytesBuffered());
+ // Buffer the second frame.
+ QuicTime t2 = clock_.ApproximateNow();
+ OnFrame(3, "def");
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ EXPECT_EQ(6u, NumBufferedBytes());
+ EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
+ EXPECT_EQ(6u, sequencer_->NumBytesBuffered());
+
+ iovec iovecs[1];
+ QuicTime timestamp(QuicTime::Zero());
+
+ EXPECT_TRUE(sequencer_->GetReadableRegion(iovecs, &timestamp));
+ EXPECT_EQ(timestamp, t1);
+ QuicStreamSequencerTest::ConsumeData(3);
+ EXPECT_EQ(3u, NumBufferedBytes());
+ EXPECT_EQ(3u, sequencer_->NumBytesConsumed());
+ EXPECT_EQ(3u, sequencer_->NumBytesBuffered());
+
+ EXPECT_TRUE(sequencer_->GetReadableRegion(iovecs, &timestamp));
+ EXPECT_EQ(timestamp, t2);
+ QuicStreamSequencerTest::ConsumeData(3);
+ EXPECT_EQ(0u, NumBufferedBytes());
+ EXPECT_EQ(6u, sequencer_->NumBytesConsumed());
+ EXPECT_EQ(0u, sequencer_->NumBytesBuffered());
+}
+
+TEST_F(QuicStreamSequencerTest, OutOfOrderTimestamps) {
+ // This test verifies that timestamps returned by
+ // GetReadableRegion() are in the correct sequence when frames
+ // arrive at the sequencer out of order.
+ EXPECT_CALL(stream_, OnDataAvailable());
+
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+
+ // Buffer the first frame
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ QuicTime t1 = clock_.ApproximateNow();
+ OnFrame(3, "def");
+ EXPECT_EQ(3u, NumBufferedBytes());
+ EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
+ EXPECT_EQ(3u, sequencer_->NumBytesBuffered());
+ // Buffer the second frame
+ QuicTime t2 = clock_.ApproximateNow();
+ OnFrame(0, "abc");
+ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+ EXPECT_EQ(6u, NumBufferedBytes());
+ EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
+ EXPECT_EQ(6u, sequencer_->NumBytesBuffered());
+
+ iovec iovecs[1];
+ QuicTime timestamp(QuicTime::Zero());
+
+ EXPECT_TRUE(sequencer_->GetReadableRegion(iovecs, &timestamp));
+ EXPECT_EQ(timestamp, t2);
+ QuicStreamSequencerTest::ConsumeData(3);
+ EXPECT_EQ(3u, NumBufferedBytes());
+ EXPECT_EQ(3u, sequencer_->NumBytesConsumed());
+ EXPECT_EQ(3u, sequencer_->NumBytesBuffered());
+
+ EXPECT_TRUE(sequencer_->GetReadableRegion(iovecs, &timestamp));
+ EXPECT_EQ(timestamp, t1);
+ QuicStreamSequencerTest::ConsumeData(3);
+ EXPECT_EQ(0u, NumBufferedBytes());
+ EXPECT_EQ(6u, sequencer_->NumBytesConsumed());
+ EXPECT_EQ(0u, sequencer_->NumBytesBuffered());
+}
+
+TEST_F(QuicStreamSequencerTest, OnStreamFrameWithNullSource) {
+ FLAGS_quic_stream_sequencer_buffer_debug = true;
+ // Pass in a frame with data pointing to null address, expect to close
+ // connection with error.
+ StringPiece source(nullptr, 5u);
+ QuicStreamFrame frame(kClientDataStreamId1, false, 1, source);
+ EXPECT_CALL(stream_, CloseConnectionWithDetails(
+ QUIC_STREAM_SEQUENCER_INVALID_STATE, _));
+ sequencer_->OnStreamFrame(frame);
+}
+
+TEST_F(QuicStreamSequencerTest, ReadvError) {
+ FLAGS_quic_stream_sequencer_buffer_debug = true;
+ EXPECT_CALL(stream_, OnDataAvailable());
+ string source(100, 'a');
+ OnFrame(0u, source.data());
+ EXPECT_EQ(source.length(), sequencer_->NumBytesBuffered());
+ // Pass in a null iovec, expect to tear down connection.
+ EXPECT_CALL(stream_, CloseConnectionWithDetails(
+ QUIC_STREAM_SEQUENCER_INVALID_STATE, _));
+ iovec iov{nullptr, 512};
+ sequencer_->Readv(&iov, 1u);
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_sustained_bandwidth_recorder.cc b/chromium/net/quic/core/quic_sustained_bandwidth_recorder.cc
new file mode 100644
index 00000000000..37068283781
--- /dev/null
+++ b/chromium/net/quic/core/quic_sustained_bandwidth_recorder.cc
@@ -0,0 +1,61 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_sustained_bandwidth_recorder.h"
+
+#include "base/logging.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+QuicSustainedBandwidthRecorder::QuicSustainedBandwidthRecorder()
+ : has_estimate_(false),
+ is_recording_(false),
+ bandwidth_estimate_recorded_during_slow_start_(false),
+ bandwidth_estimate_(QuicBandwidth::Zero()),
+ max_bandwidth_estimate_(QuicBandwidth::Zero()),
+ max_bandwidth_timestamp_(0),
+ start_time_(QuicTime::Zero()) {}
+
+void QuicSustainedBandwidthRecorder::RecordEstimate(bool in_recovery,
+ bool in_slow_start,
+ QuicBandwidth bandwidth,
+ QuicTime estimate_time,
+ QuicWallTime wall_time,
+ QuicTime::Delta srtt) {
+ if (in_recovery) {
+ is_recording_ = false;
+ DVLOG(1) << "Stopped recording at: " << estimate_time.ToDebuggingValue();
+ return;
+ }
+
+ if (!is_recording_) {
+ // This is the first estimate of a new recording period.
+ start_time_ = estimate_time;
+ is_recording_ = true;
+ DVLOG(1) << "Started recording at: " << start_time_.ToDebuggingValue();
+ return;
+ }
+
+ // If we have been recording for at least 3 * srtt, then record the latest
+ // bandwidth estimate as a valid sustained bandwidth estimate.
+ if (estimate_time - start_time_ >= 3 * srtt) {
+ has_estimate_ = true;
+ bandwidth_estimate_recorded_during_slow_start_ = in_slow_start;
+ bandwidth_estimate_ = bandwidth;
+ DVLOG(1) << "New sustained bandwidth estimate (KBytes/s): "
+ << bandwidth_estimate_.ToKBytesPerSecond();
+ }
+
+ // Check for an increase in max bandwidth.
+ if (bandwidth > max_bandwidth_estimate_) {
+ max_bandwidth_estimate_ = bandwidth;
+ max_bandwidth_timestamp_ = wall_time.ToUNIXSeconds();
+ DVLOG(1) << "New max bandwidth estimate (KBytes/s): "
+ << max_bandwidth_estimate_.ToKBytesPerSecond();
+ }
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_sustained_bandwidth_recorder.h b/chromium/net/quic/core/quic_sustained_bandwidth_recorder.h
new file mode 100644
index 00000000000..be5afef228f
--- /dev/null
+++ b/chromium/net/quic/core/quic_sustained_bandwidth_recorder.h
@@ -0,0 +1,94 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_SUSTAINED_BANDWIDTH_RECORDER_H_
+#define NET_QUIC_QUIC_SUSTAINED_BANDWIDTH_RECORDER_H_
+
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+
+namespace test {
+class QuicSustainedBandwidthRecorderPeer;
+} // namespace test
+
+// This class keeps track of a sustained bandwidth estimate to ultimately send
+// to the client in a server config update message. A sustained bandwidth
+// estimate is only marked as valid if the QuicSustainedBandwidthRecorder has
+// been given uninterrupted reliable estimates over a certain period of time.
+class NET_EXPORT_PRIVATE QuicSustainedBandwidthRecorder {
+ public:
+ QuicSustainedBandwidthRecorder();
+
+ // As long as |in_recovery| is consistently false, multiple calls to this
+ // method over a 3 * srtt period results in storage of a valid sustained
+ // bandwidth estimate.
+ // |time_now| is used as a max bandwidth timestamp if needed.
+ void RecordEstimate(bool in_recovery,
+ bool in_slow_start,
+ QuicBandwidth bandwidth,
+ QuicTime estimate_time,
+ QuicWallTime wall_time,
+ QuicTime::Delta srtt);
+
+ bool HasEstimate() const { return has_estimate_; }
+
+ QuicBandwidth BandwidthEstimate() const {
+ DCHECK(has_estimate_);
+ return bandwidth_estimate_;
+ }
+
+ QuicBandwidth MaxBandwidthEstimate() const {
+ DCHECK(has_estimate_);
+ return max_bandwidth_estimate_;
+ }
+
+ int64_t MaxBandwidthTimestamp() const {
+ DCHECK(has_estimate_);
+ return max_bandwidth_timestamp_;
+ }
+
+ bool EstimateRecordedDuringSlowStart() const {
+ DCHECK(has_estimate_);
+ return bandwidth_estimate_recorded_during_slow_start_;
+ }
+
+ private:
+ friend class test::QuicSustainedBandwidthRecorderPeer;
+
+ // True if we have been able to calculate sustained bandwidth, over at least
+ // one recording period (3 * rtt).
+ bool has_estimate_;
+
+ // True if the last call to RecordEstimate had a reliable estimate.
+ bool is_recording_;
+
+ // True if the current sustained bandwidth estimate was generated while in
+ // slow start.
+ bool bandwidth_estimate_recorded_during_slow_start_;
+
+ // The latest sustained bandwidth estimate.
+ QuicBandwidth bandwidth_estimate_;
+
+ // The maximum sustained bandwidth seen over the lifetime of the connection.
+ QuicBandwidth max_bandwidth_estimate_;
+
+ // Timestamp indicating when the max_bandwidth_estimate_ was seen.
+ int64_t max_bandwidth_timestamp_;
+
+ // Timestamp marking the beginning of the latest recording period.
+ QuicTime start_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicSustainedBandwidthRecorder);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_SUSTAINED_BANDWIDTH_RECORDER_H_
diff --git a/chromium/net/quic/core/quic_sustained_bandwidth_recorder_test.cc b/chromium/net/quic/core/quic_sustained_bandwidth_recorder_test.cc
new file mode 100644
index 00000000000..a93b9db079b
--- /dev/null
+++ b/chromium/net/quic/core/quic_sustained_bandwidth_recorder_test.cc
@@ -0,0 +1,131 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_sustained_bandwidth_recorder.h"
+
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+namespace {
+
+TEST(QuicSustainedBandwidthRecorderTest, BandwidthEstimates) {
+ QuicSustainedBandwidthRecorder recorder;
+ EXPECT_FALSE(recorder.HasEstimate());
+
+ QuicTime estimate_time = QuicTime::Zero();
+ QuicWallTime wall_time = QuicWallTime::Zero();
+ QuicTime::Delta srtt = QuicTime::Delta::FromMilliseconds(150);
+ const int kBandwidthBitsPerSecond = 12345678;
+ QuicBandwidth bandwidth =
+ QuicBandwidth::FromBitsPerSecond(kBandwidthBitsPerSecond);
+
+ bool in_recovery = false;
+ bool in_slow_start = false;
+
+ // This triggers recording, but should not yield a valid estimate yet.
+ recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
+ wall_time, srtt);
+ EXPECT_FALSE(recorder.HasEstimate());
+
+ // Send a second reading, again this should not result in a valid estimate,
+ // as not enough time has passed.
+ estimate_time = estimate_time + srtt;
+ recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
+ wall_time, srtt);
+ EXPECT_FALSE(recorder.HasEstimate());
+
+ // Now 3 * kSRTT has elapsed since first recording, expect a valid estimate.
+ estimate_time = estimate_time + srtt;
+ estimate_time = estimate_time + srtt;
+ recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
+ wall_time, srtt);
+ EXPECT_TRUE(recorder.HasEstimate());
+ EXPECT_EQ(recorder.BandwidthEstimate(), bandwidth);
+ EXPECT_EQ(recorder.BandwidthEstimate(), recorder.MaxBandwidthEstimate());
+
+ // Resetting, and sending a different estimate will only change output after
+ // a further 3 * kSRTT has passed.
+ QuicBandwidth second_bandwidth =
+ QuicBandwidth::FromBitsPerSecond(2 * kBandwidthBitsPerSecond);
+ // Reset the recorder by passing in a measurement while in recovery.
+ in_recovery = true;
+ recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
+ wall_time, srtt);
+ in_recovery = false;
+ recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
+ wall_time, srtt);
+ EXPECT_EQ(recorder.BandwidthEstimate(), bandwidth);
+
+ estimate_time = estimate_time + 3 * srtt;
+ const int64_t kSeconds = 556677;
+ QuicWallTime second_bandwidth_wall_time =
+ QuicWallTime::FromUNIXSeconds(kSeconds);
+ recorder.RecordEstimate(in_recovery, in_slow_start, second_bandwidth,
+ estimate_time, second_bandwidth_wall_time, srtt);
+ EXPECT_EQ(recorder.BandwidthEstimate(), second_bandwidth);
+ EXPECT_EQ(recorder.BandwidthEstimate(), recorder.MaxBandwidthEstimate());
+ EXPECT_EQ(recorder.MaxBandwidthTimestamp(), kSeconds);
+
+ // Reset again, this time recording a lower bandwidth than before.
+ QuicBandwidth third_bandwidth =
+ QuicBandwidth::FromBitsPerSecond(0.5 * kBandwidthBitsPerSecond);
+ // Reset the recorder by passing in an unreliable measurement.
+ recorder.RecordEstimate(in_recovery, in_slow_start, third_bandwidth,
+ estimate_time, wall_time, srtt);
+ recorder.RecordEstimate(in_recovery, in_slow_start, third_bandwidth,
+ estimate_time, wall_time, srtt);
+ EXPECT_EQ(recorder.BandwidthEstimate(), third_bandwidth);
+
+ estimate_time = estimate_time + 3 * srtt;
+ recorder.RecordEstimate(in_recovery, in_slow_start, third_bandwidth,
+ estimate_time, wall_time, srtt);
+ EXPECT_EQ(recorder.BandwidthEstimate(), third_bandwidth);
+
+ // Max bandwidth should not have changed.
+ EXPECT_LT(third_bandwidth, second_bandwidth);
+ EXPECT_EQ(recorder.MaxBandwidthEstimate(), second_bandwidth);
+ EXPECT_EQ(recorder.MaxBandwidthTimestamp(), kSeconds);
+}
+
+TEST(QuicSustainedBandwidthRecorderTest, SlowStart) {
+ // Verify that slow start status is correctly recorded.
+ QuicSustainedBandwidthRecorder recorder;
+ EXPECT_FALSE(recorder.HasEstimate());
+
+ QuicTime estimate_time = QuicTime::Zero();
+ QuicWallTime wall_time = QuicWallTime::Zero();
+ QuicTime::Delta srtt = QuicTime::Delta::FromMilliseconds(150);
+ const int kBandwidthBitsPerSecond = 12345678;
+ QuicBandwidth bandwidth =
+ QuicBandwidth::FromBitsPerSecond(kBandwidthBitsPerSecond);
+
+ bool in_recovery = false;
+ bool in_slow_start = true;
+
+ // This triggers recording, but should not yield a valid estimate yet.
+ recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
+ wall_time, srtt);
+
+ // Now 3 * kSRTT has elapsed since first recording, expect a valid estimate.
+ estimate_time = estimate_time + 3 * srtt;
+ recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
+ wall_time, srtt);
+ EXPECT_TRUE(recorder.HasEstimate());
+ EXPECT_TRUE(recorder.EstimateRecordedDuringSlowStart());
+
+ // Now send another estimate, this time not in slow start.
+ estimate_time = estimate_time + 3 * srtt;
+ in_slow_start = false;
+ recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
+ wall_time, srtt);
+ EXPECT_TRUE(recorder.HasEstimate());
+ EXPECT_FALSE(recorder.EstimateRecordedDuringSlowStart());
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_time.cc b/chromium/net/quic/core/quic_time.cc
new file mode 100644
index 00000000000..c9e72ce57de
--- /dev/null
+++ b/chromium/net/quic/core/quic_time.cc
@@ -0,0 +1,87 @@
+// 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/quic_time.h"
+
+#include <cinttypes>
+#include <cstdlib>
+#include <limits>
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+
+using base::StringPrintf;
+
+namespace net {
+
+std::string QuicTime::Delta::ToDebugValue() const {
+ const int64_t one_ms = 1000;
+ const int64_t one_s = 1000 * one_ms;
+
+ int64_t absolute_value = std::abs(time_offset_);
+
+ // For debugging purposes, always display the value with the highest precision
+ // available.
+ if (absolute_value > one_s && absolute_value % one_s == 0) {
+ return StringPrintf("%" PRId64 "s", time_offset_ / one_s);
+ }
+ if (absolute_value > one_ms && absolute_value % one_ms == 0) {
+ return StringPrintf("%" PRId64 "ms", time_offset_ / one_ms);
+ }
+ return StringPrintf("%" PRId64 "us", time_offset_);
+}
+
+uint64_t QuicWallTime::ToUNIXSeconds() const {
+ return microseconds_ / 1000000;
+}
+
+uint64_t QuicWallTime::ToUNIXMicroseconds() const {
+ return microseconds_;
+}
+
+bool QuicWallTime::IsAfter(QuicWallTime other) const {
+ return microseconds_ > other.microseconds_;
+}
+
+bool QuicWallTime::IsBefore(QuicWallTime other) const {
+ return microseconds_ < other.microseconds_;
+}
+
+bool QuicWallTime::IsZero() const {
+ return microseconds_ == 0;
+}
+
+QuicTime::Delta QuicWallTime::AbsoluteDifference(QuicWallTime other) const {
+ uint64_t d;
+
+ if (microseconds_ > other.microseconds_) {
+ d = microseconds_ - other.microseconds_;
+ } else {
+ d = other.microseconds_ - microseconds_;
+ }
+
+ if (d > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
+ d = std::numeric_limits<int64_t>::max();
+ }
+ return QuicTime::Delta::FromMicroseconds(d);
+}
+
+QuicWallTime QuicWallTime::Add(QuicTime::Delta delta) const {
+ uint64_t microseconds = microseconds_ + delta.ToMicroseconds();
+ if (microseconds < microseconds_) {
+ microseconds = std::numeric_limits<uint64_t>::max();
+ }
+ return QuicWallTime(microseconds);
+}
+
+// TODO(ianswett) Test this.
+QuicWallTime QuicWallTime::Subtract(QuicTime::Delta delta) const {
+ uint64_t microseconds = microseconds_ - delta.ToMicroseconds();
+ if (microseconds > microseconds_) {
+ microseconds = 0;
+ }
+ return QuicWallTime(microseconds);
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_time.h b/chromium/net/quic/core/quic_time.h
new file mode 100644
index 00000000000..92e31bcc54b
--- /dev/null
+++ b/chromium/net/quic/core/quic_time.h
@@ -0,0 +1,280 @@
+// 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.
+//
+// QuicTime represents one point in time, stored in microsecond resolution.
+// QuicTime is monotonically increasing, even across system clock adjustments.
+// The epoch (time 0) of QuicTime is unspecified.
+//
+// This implementation wraps the classes base::TimeTicks and base::TimeDelta.
+
+#ifndef NET_QUIC_QUIC_TIME_H_
+#define NET_QUIC_QUIC_TIME_H_
+
+#include <stdint.h>
+
+#include <cmath>
+#include <ostream>
+
+#include "base/compiler_specific.h"
+#include "base/time/time.h"
+#include "net/base/net_export.h"
+
+#define QUICTIME_CONSTEXPR inline
+
+namespace net {
+
+static const int kNumSecondsPerMinute = 60;
+static const int kNumSecondsPerHour = kNumSecondsPerMinute * 60;
+static const uint64_t kNumMicrosPerSecond = base::Time::kMicrosecondsPerSecond;
+static const uint64_t kNumMicrosPerMilli =
+ base::Time::kMicrosecondsPerMillisecond;
+
+// A QuicTime is a purely relative time. QuicTime values from different clocks
+// cannot be compared to each other. If you need an absolute time, see
+// QuicWallTime, below.
+class NET_EXPORT_PRIVATE QuicTime {
+ public:
+ // A QuicTime::Delta represents the signed difference between two points in
+ // time, stored in microsecond resolution.
+ class NET_EXPORT_PRIVATE Delta {
+ public:
+ explicit Delta(base::TimeDelta delta);
+
+ // Create a object with an offset of 0.
+ static QUICTIME_CONSTEXPR Delta Zero() { return Delta(0); }
+
+ // Create a object with infinite offset time.
+ static QUICTIME_CONSTEXPR Delta Infinite() {
+ return Delta(kQuicInfiniteTimeUs);
+ }
+
+ // Converts a number of seconds to a time offset.
+ static QUICTIME_CONSTEXPR Delta FromSeconds(int64_t secs) {
+ return Delta(secs * 1000 * 1000);
+ }
+
+ // Converts a number of milliseconds to a time offset.
+ static QUICTIME_CONSTEXPR Delta FromMilliseconds(int64_t ms) {
+ return Delta(ms * 1000);
+ }
+
+ // Converts a number of microseconds to a time offset.
+ static QUICTIME_CONSTEXPR Delta FromMicroseconds(int64_t us) {
+ return Delta(us);
+ }
+
+ // Converts the time offset to a rounded number of seconds.
+ inline int64_t ToSeconds() const { return time_offset_ / 1000 / 1000; }
+
+ // Converts the time offset to a rounded number of milliseconds.
+ inline int64_t ToMilliseconds() const { return time_offset_ / 1000; }
+
+ // Converts the time offset to a rounded number of microseconds.
+ inline int64_t ToMicroseconds() const { return time_offset_; }
+
+ inline bool IsZero() const { return time_offset_ == 0; }
+
+ inline bool IsInfinite() const {
+ return time_offset_ == kQuicInfiniteTimeUs;
+ }
+
+ std::string ToDebugValue() const;
+
+ private:
+ base::TimeDelta delta_;
+ friend inline bool operator==(QuicTime::Delta lhs, QuicTime::Delta rhs);
+ friend inline bool operator<(QuicTime::Delta lhs, QuicTime::Delta rhs);
+ friend inline QuicTime::Delta operator<<(QuicTime::Delta lhs, size_t rhs);
+ friend inline QuicTime::Delta operator>>(QuicTime::Delta lhs, size_t rhs);
+
+ friend inline QuicTime::Delta operator+(QuicTime::Delta lhs,
+ QuicTime::Delta rhs);
+ friend inline QuicTime::Delta operator-(QuicTime::Delta lhs,
+ QuicTime::Delta rhs);
+ friend inline QuicTime::Delta operator*(QuicTime::Delta lhs, int rhs);
+ friend inline QuicTime::Delta operator*(QuicTime::Delta lhs, double rhs);
+
+ friend inline QuicTime operator+(QuicTime lhs, QuicTime::Delta rhs);
+ friend inline QuicTime operator-(QuicTime lhs, QuicTime::Delta rhs);
+ friend inline QuicTime::Delta operator-(QuicTime lhs, QuicTime rhs);
+
+ static const int64_t kQuicInfiniteTimeUs =
+ std::numeric_limits<int64_t>::max();
+
+ explicit QUICTIME_CONSTEXPR Delta(int64_t time_offset)
+ : time_offset_(time_offset) {}
+
+ int64_t time_offset_;
+ friend class QuicTime;
+ friend class QuicClock;
+ };
+
+ explicit QuicTime(base::TimeTicks ticks) : time_(ticks.ToInternalValue()) {}
+
+ // Creates a new QuicTime with an internal value of 0. IsInitialized()
+ // will return false for these times.
+ static QUICTIME_CONSTEXPR QuicTime Zero() { return QuicTime(0); }
+
+ // Creates a new QuicTime with an infinite time.
+ static QUICTIME_CONSTEXPR QuicTime Infinite() {
+ return QuicTime(Delta::kQuicInfiniteTimeUs);
+ }
+
+ // Produce the internal value to be used when logging. This value
+ // represents the number of microseconds since some epoch. It may
+ // be the UNIX epoch on some platforms. On others, it may
+ // be a CPU ticks based value.
+ inline int64_t ToDebuggingValue() const { return time_; }
+
+ inline bool IsInitialized() const { return 0 != time_; }
+
+ private:
+ friend inline bool operator==(QuicTime lhs, QuicTime rhs);
+ friend inline bool operator<(QuicTime lhs, QuicTime rhs);
+ friend inline QuicTime operator+(QuicTime lhs, QuicTime::Delta rhs);
+ friend inline QuicTime operator-(QuicTime lhs, QuicTime::Delta rhs);
+ friend inline QuicTime::Delta operator-(QuicTime lhs, QuicTime rhs);
+
+ explicit QUICTIME_CONSTEXPR QuicTime(int64_t time) : time_(time) {}
+
+ int64_t time_;
+};
+
+// A QuicWallTime represents an absolute time that is globally consistent. In
+// practice, clock-skew means that comparing values from different machines
+// requires some flexibility.
+class NET_EXPORT_PRIVATE QuicWallTime {
+ public:
+ // FromUNIXSeconds constructs a QuicWallTime from a count of the seconds
+ // since the UNIX epoch.
+ static QUICTIME_CONSTEXPR QuicWallTime FromUNIXSeconds(uint64_t seconds) {
+ return QuicWallTime(seconds * 1000000);
+ }
+
+ static QUICTIME_CONSTEXPR QuicWallTime
+ FromUNIXMicroseconds(uint64_t microseconds) {
+ return QuicWallTime(microseconds);
+ }
+
+ // Zero returns a QuicWallTime set to zero. IsZero will return true for this
+ // value.
+ static QUICTIME_CONSTEXPR QuicWallTime Zero() { return QuicWallTime(0); }
+
+ // Returns the number of seconds since the UNIX epoch.
+ uint64_t ToUNIXSeconds() const;
+ // Returns the number of microseconds since the UNIX epoch.
+ uint64_t ToUNIXMicroseconds() const;
+
+ bool IsAfter(QuicWallTime other) const;
+ bool IsBefore(QuicWallTime other) const;
+
+ // IsZero returns true if this object is the result of calling |Zero|.
+ bool IsZero() const;
+
+ // AbsoluteDifference returns the absolute value of the time difference
+ // between |this| and |other|.
+ QuicTime::Delta AbsoluteDifference(QuicWallTime other) const;
+
+ // Add returns a new QuicWallTime that represents the time of |this| plus
+ // |delta|.
+ QuicWallTime Add(QuicTime::Delta delta) const WARN_UNUSED_RESULT;
+
+ // Subtract returns a new QuicWallTime that represents the time of |this|
+ // minus |delta|.
+ QuicWallTime Subtract(QuicTime::Delta delta) const WARN_UNUSED_RESULT;
+
+ private:
+ explicit QUICTIME_CONSTEXPR QuicWallTime(uint64_t microseconds)
+ : microseconds_(microseconds) {}
+
+ uint64_t microseconds_;
+};
+
+// Non-member relational operators for QuicTime::Delta.
+inline bool operator==(QuicTime::Delta lhs, QuicTime::Delta rhs) {
+ return lhs.time_offset_ == rhs.time_offset_;
+}
+inline bool operator!=(QuicTime::Delta lhs, QuicTime::Delta rhs) {
+ return !(lhs == rhs);
+}
+inline bool operator<(QuicTime::Delta lhs, QuicTime::Delta rhs) {
+ return lhs.time_offset_ < rhs.time_offset_;
+}
+inline bool operator>(QuicTime::Delta lhs, QuicTime::Delta rhs) {
+ return rhs < lhs;
+}
+inline bool operator<=(QuicTime::Delta lhs, QuicTime::Delta rhs) {
+ return !(rhs < lhs);
+}
+inline bool operator>=(QuicTime::Delta lhs, QuicTime::Delta rhs) {
+ return !(lhs < rhs);
+}
+inline QuicTime::Delta operator<<(QuicTime::Delta lhs, size_t rhs) {
+ return QuicTime::Delta(lhs.time_offset_ << rhs);
+}
+inline QuicTime::Delta operator>>(QuicTime::Delta lhs, size_t rhs) {
+ return QuicTime::Delta(lhs.time_offset_ >> rhs);
+}
+
+// Non-member relational operators for QuicTime.
+inline bool operator==(QuicTime lhs, QuicTime rhs) {
+ return lhs.time_ == rhs.time_;
+}
+inline bool operator!=(QuicTime lhs, QuicTime rhs) {
+ return !(lhs == rhs);
+}
+inline bool operator<(QuicTime lhs, QuicTime rhs) {
+ return lhs.time_ < rhs.time_;
+}
+inline bool operator>(QuicTime lhs, QuicTime rhs) {
+ return rhs < lhs;
+}
+inline bool operator<=(QuicTime lhs, QuicTime rhs) {
+ return !(rhs < lhs);
+}
+inline bool operator>=(QuicTime lhs, QuicTime rhs) {
+ return !(lhs < rhs);
+}
+
+// Non-member arithmetic operators for QuicTime::Delta.
+inline QuicTime::Delta operator+(QuicTime::Delta lhs, QuicTime::Delta rhs) {
+ return QuicTime::Delta(lhs.time_offset_ + rhs.time_offset_);
+}
+inline QuicTime::Delta operator-(QuicTime::Delta lhs, QuicTime::Delta rhs) {
+ return QuicTime::Delta(lhs.time_offset_ - rhs.time_offset_);
+}
+inline QuicTime::Delta operator*(QuicTime::Delta lhs, int rhs) {
+ return QuicTime::Delta(lhs.time_offset_ * rhs);
+}
+inline QuicTime::Delta operator*(QuicTime::Delta lhs, double rhs) {
+ return QuicTime::Delta(
+ static_cast<int64_t>(std::llround(lhs.time_offset_ * rhs)));
+}
+inline QuicTime::Delta operator*(int lhs, QuicTime::Delta rhs) {
+ return rhs * lhs;
+}
+inline QuicTime::Delta operator*(double lhs, QuicTime::Delta rhs) {
+ return rhs * lhs;
+}
+
+// Non-member arithmetic operators for QuicTime and QuicTime::Delta.
+inline QuicTime operator+(QuicTime lhs, QuicTime::Delta rhs) {
+ return QuicTime(lhs.time_ + rhs.time_offset_);
+}
+inline QuicTime operator-(QuicTime lhs, QuicTime::Delta rhs) {
+ return QuicTime(lhs.time_ - rhs.time_offset_);
+}
+inline QuicTime::Delta operator-(QuicTime lhs, QuicTime rhs) {
+ return QuicTime::Delta(lhs.time_ - rhs.time_);
+}
+
+// Override stream output operator for gtest.
+inline std::ostream& operator<<(std::ostream& output,
+ const QuicTime::Delta delta) {
+ output << delta.ToDebugValue();
+ return output;
+}
+} // namespace net
+
+#endif // NET_QUIC_QUIC_TIME_H_
diff --git a/chromium/net/quic/core/quic_time_test.cc b/chromium/net/quic/core/quic_time_test.cc
new file mode 100644
index 00000000000..5324002e0e1
--- /dev/null
+++ b/chromium/net/quic/core/quic_time_test.cc
@@ -0,0 +1,166 @@
+// 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/quic_time.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+TEST(QuicTimeDeltaTest, Zero) {
+ EXPECT_TRUE(QuicTime::Delta::Zero().IsZero());
+ EXPECT_FALSE(QuicTime::Delta::Zero().IsInfinite());
+ EXPECT_FALSE(QuicTime::Delta::FromMilliseconds(1).IsZero());
+}
+
+TEST(QuicTimeDeltaTest, Infinite) {
+ EXPECT_TRUE(QuicTime::Delta::Infinite().IsInfinite());
+ EXPECT_FALSE(QuicTime::Delta::Zero().IsInfinite());
+ EXPECT_FALSE(QuicTime::Delta::FromMilliseconds(1).IsInfinite());
+}
+
+TEST(QuicTimeDeltaTest, FromTo) {
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(1),
+ QuicTime::Delta::FromMicroseconds(1000));
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(1),
+ QuicTime::Delta::FromMilliseconds(1000));
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(1),
+ QuicTime::Delta::FromMicroseconds(1000000));
+
+ EXPECT_EQ(1, QuicTime::Delta::FromMicroseconds(1000).ToMilliseconds());
+ EXPECT_EQ(2, QuicTime::Delta::FromMilliseconds(2000).ToSeconds());
+ EXPECT_EQ(1000, QuicTime::Delta::FromMilliseconds(1).ToMicroseconds());
+ EXPECT_EQ(1, QuicTime::Delta::FromMicroseconds(1000).ToMilliseconds());
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(2000).ToMicroseconds(),
+ QuicTime::Delta::FromSeconds(2).ToMicroseconds());
+}
+
+TEST(QuicTimeDeltaTest, Add) {
+ EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2000),
+ QuicTime::Delta::Zero() + QuicTime::Delta::FromMilliseconds(2));
+}
+
+TEST(QuicTimeDeltaTest, Subtract) {
+ EXPECT_EQ(QuicTime::Delta::FromMicroseconds(1000),
+ QuicTime::Delta::FromMilliseconds(2) -
+ QuicTime::Delta::FromMilliseconds(1));
+}
+
+TEST(QuicTimeDeltaTest, Multiply) {
+ int i = 2;
+ EXPECT_EQ(QuicTime::Delta::FromMicroseconds(4000),
+ QuicTime::Delta::FromMilliseconds(2) * i);
+ EXPECT_EQ(QuicTime::Delta::FromMicroseconds(4000),
+ i * QuicTime::Delta::FromMilliseconds(2));
+ double d = 2;
+ EXPECT_EQ(QuicTime::Delta::FromMicroseconds(4000),
+ QuicTime::Delta::FromMilliseconds(2) * d);
+ EXPECT_EQ(QuicTime::Delta::FromMicroseconds(4000),
+ d * QuicTime::Delta::FromMilliseconds(2));
+
+ // Ensure we are rounding correctly within a single-bit level of precision.
+ EXPECT_EQ(QuicTime::Delta::FromMicroseconds(5),
+ QuicTime::Delta::FromMicroseconds(9) * 0.5);
+ EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2),
+ QuicTime::Delta::FromMicroseconds(12) * 0.2);
+}
+
+TEST(QuicTimeDeltaTest, Max) {
+ EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2000),
+ std::max(QuicTime::Delta::FromMicroseconds(1000),
+ QuicTime::Delta::FromMicroseconds(2000)));
+}
+
+TEST(QuicTimeDeltaTest, NotEqual) {
+ EXPECT_TRUE(QuicTime::Delta::FromSeconds(0) !=
+ QuicTime::Delta::FromSeconds(1));
+ EXPECT_FALSE(QuicTime::Delta::FromSeconds(0) !=
+ QuicTime::Delta::FromSeconds(0));
+}
+
+TEST(QuicTimeDeltaTest, DebugValue) {
+ const QuicTime::Delta one_us = QuicTime::Delta::FromMicroseconds(1);
+ const QuicTime::Delta one_ms = QuicTime::Delta::FromMilliseconds(1);
+ const QuicTime::Delta one_s = QuicTime::Delta::FromSeconds(1);
+
+ EXPECT_EQ("3s", (3 * one_s).ToDebugValue());
+ EXPECT_EQ("3ms", (3 * one_ms).ToDebugValue());
+ EXPECT_EQ("3us", (3 * one_us).ToDebugValue());
+
+ EXPECT_EQ("3001us", (3 * one_ms + one_us).ToDebugValue());
+ EXPECT_EQ("3001ms", (3 * one_s + one_ms).ToDebugValue());
+ EXPECT_EQ("3000001us", (3 * one_s + one_us).ToDebugValue());
+}
+
+class QuicTimeTest : public ::testing::Test {
+ protected:
+ MockClock clock_;
+};
+
+TEST_F(QuicTimeTest, Initialized) {
+ EXPECT_FALSE(QuicTime::Zero().IsInitialized());
+ EXPECT_TRUE((QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(1))
+ .IsInitialized());
+}
+
+TEST_F(QuicTimeTest, Add) {
+ QuicTime time_1 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1);
+ QuicTime time_2 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(2);
+
+ QuicTime::Delta diff = time_2 - time_1;
+
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(1), diff);
+ EXPECT_EQ(1000, diff.ToMicroseconds());
+ EXPECT_EQ(1, diff.ToMilliseconds());
+}
+
+TEST_F(QuicTimeTest, Subtract) {
+ QuicTime time_1 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1);
+ QuicTime time_2 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(2);
+
+ EXPECT_EQ(QuicTime::Delta::FromMilliseconds(1), time_2 - time_1);
+}
+
+TEST_F(QuicTimeTest, SubtractDelta) {
+ QuicTime time = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(2);
+ EXPECT_EQ(QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1),
+ time - QuicTime::Delta::FromMilliseconds(1));
+}
+
+TEST_F(QuicTimeTest, Max) {
+ QuicTime time_1 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1);
+ QuicTime time_2 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(2);
+
+ EXPECT_EQ(time_2, std::max(time_1, time_2));
+}
+
+TEST_F(QuicTimeTest, MockClock) {
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+
+ QuicTime now = clock_.ApproximateNow();
+ QuicTime time = QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(1000);
+
+ EXPECT_EQ(now, time);
+
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+ now = clock_.ApproximateNow();
+
+ EXPECT_NE(now, time);
+
+ time = time + QuicTime::Delta::FromMilliseconds(1);
+ EXPECT_EQ(now, time);
+}
+
+TEST_F(QuicTimeTest, LE) {
+ const QuicTime zero = QuicTime::Zero();
+ const QuicTime one = zero + QuicTime::Delta::FromSeconds(1);
+ EXPECT_TRUE(zero <= zero);
+ EXPECT_TRUE(zero <= one);
+ EXPECT_TRUE(one <= one);
+ EXPECT_FALSE(one <= zero);
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_types.cc b/chromium/net/quic/core/quic_types.cc
new file mode 100644
index 00000000000..49260ba4ef3
--- /dev/null
+++ b/chromium/net/quic/core/quic_types.cc
@@ -0,0 +1,25 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_types.h"
+
+using std::ostream;
+
+namespace net {
+
+QuicConsumedData::QuicConsumedData(size_t bytes_consumed, bool fin_consumed)
+ : bytes_consumed(bytes_consumed), fin_consumed(fin_consumed) {}
+
+ostream& operator<<(ostream& os, const QuicConsumedData& s) {
+ os << "bytes_consumed: " << s.bytes_consumed
+ << " fin_consumed: " << s.fin_consumed;
+ return os;
+}
+
+WriteResult::WriteResult() : status(WRITE_STATUS_ERROR), bytes_written(0) {}
+
+WriteResult::WriteResult(WriteStatus status, int bytes_written_or_error_code)
+ : status(status), bytes_written(bytes_written_or_error_code) {}
+
+} // namespace net
diff --git a/chromium/net/quic/quic_types.h b/chromium/net/quic/core/quic_types.h
index 4f24e95f62d..4f24e95f62d 100644
--- a/chromium/net/quic/quic_types.h
+++ b/chromium/net/quic/core/quic_types.h
diff --git a/chromium/net/quic/core/quic_unacked_packet_map.cc b/chromium/net/quic/core/quic_unacked_packet_map.cc
new file mode 100644
index 00000000000..adc4a653fa3
--- /dev/null
+++ b/chromium/net/quic/core/quic_unacked_packet_map.cc
@@ -0,0 +1,358 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_unacked_packet_map.h"
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "net/quic/chromium/quic_utils_chromium.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_connection_stats.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+
+using std::max;
+
+namespace net {
+
+QuicUnackedPacketMap::QuicUnackedPacketMap()
+ : largest_sent_packet_(0),
+ largest_sent_retransmittable_packet_(0),
+ largest_observed_(0),
+ least_unacked_(1),
+ bytes_in_flight_(0),
+ pending_crypto_packet_count_(0) {}
+
+QuicUnackedPacketMap::~QuicUnackedPacketMap() {
+ QuicPacketNumber index = least_unacked_;
+ for (UnackedPacketMap::iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it, ++index) {
+ QuicUtils::DeleteFrames(&it->retransmittable_frames);
+ }
+}
+
+void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet,
+ QuicPacketNumber old_packet_number,
+ TransmissionType transmission_type,
+ QuicTime sent_time,
+ bool set_in_flight) {
+ QuicPacketNumber packet_number = packet->packet_number;
+ QuicPacketLength bytes_sent = packet->encrypted_length;
+ QUIC_BUG_IF(largest_sent_packet_ >= packet_number) << packet_number;
+ DCHECK_GE(packet_number, least_unacked_ + unacked_packets_.size());
+ while (least_unacked_ + unacked_packets_.size() < packet_number) {
+ unacked_packets_.push_back(TransmissionInfo());
+ unacked_packets_.back().is_unackable = true;
+ }
+
+ const bool has_crypto_handshake =
+ packet->has_crypto_handshake == IS_HANDSHAKE;
+ TransmissionInfo info(packet->encryption_level, packet->packet_number_length,
+ transmission_type, sent_time, bytes_sent,
+ has_crypto_handshake, packet->num_padding_bytes);
+ if (old_packet_number > 0) {
+ TransferRetransmissionInfo(old_packet_number, packet_number,
+ transmission_type, &info);
+ }
+
+ largest_sent_packet_ = packet_number;
+ if (set_in_flight) {
+ bytes_in_flight_ += bytes_sent;
+ info.in_flight = true;
+ largest_sent_retransmittable_packet_ = packet_number;
+ }
+ unacked_packets_.push_back(info);
+ // Swap the ack listeners and retransmittable frames to avoid allocations.
+ // TODO(ianswett): Could use emplace_back when Chromium can.
+ if (old_packet_number == 0) {
+ if (has_crypto_handshake) {
+ ++pending_crypto_packet_count_;
+ }
+
+ packet->retransmittable_frames.swap(
+ unacked_packets_.back().retransmittable_frames);
+ unacked_packets_.back().ack_listeners.swap(packet->listeners);
+ }
+}
+
+void QuicUnackedPacketMap::RemoveObsoletePackets() {
+ while (!unacked_packets_.empty()) {
+ if (!IsPacketUseless(least_unacked_, unacked_packets_.front())) {
+ break;
+ }
+
+ unacked_packets_.pop_front();
+ ++least_unacked_;
+ }
+}
+
+void QuicUnackedPacketMap::TransferRetransmissionInfo(
+ QuicPacketNumber old_packet_number,
+ QuicPacketNumber new_packet_number,
+ TransmissionType transmission_type,
+ TransmissionInfo* info) {
+ if (old_packet_number < least_unacked_) {
+ // This can happen when a retransmission packet is queued because of write
+ // blocked socket, and the original packet gets acked before the
+ // retransmission gets sent.
+ return;
+ }
+ if (old_packet_number > largest_sent_packet_) {
+ QUIC_BUG << "Old TransmissionInfo never existed for :" << old_packet_number
+ << " largest_sent:" << largest_sent_packet_;
+ return;
+ }
+ DCHECK_GE(new_packet_number, least_unacked_ + unacked_packets_.size());
+ DCHECK_NE(NOT_RETRANSMISSION, transmission_type);
+
+ TransmissionInfo* transmission_info =
+ &unacked_packets_.at(old_packet_number - least_unacked_);
+ QuicFrames* frames = &transmission_info->retransmittable_frames;
+ for (AckListenerWrapper& wrapper : transmission_info->ack_listeners) {
+ wrapper.ack_listener->OnPacketRetransmitted(wrapper.length);
+ }
+
+ // Swap the frames and preserve num_padding_bytes and has_crypto_handshake.
+ frames->swap(info->retransmittable_frames);
+ info->has_crypto_handshake = transmission_info->has_crypto_handshake;
+ transmission_info->has_crypto_handshake = false;
+ info->num_padding_bytes = transmission_info->num_padding_bytes;
+
+ // Transfer the AckListeners if any are present.
+ info->ack_listeners.swap(transmission_info->ack_listeners);
+ QUIC_BUG_IF(frames == nullptr)
+ << "Attempt to retransmit packet with no "
+ << "retransmittable frames: " << old_packet_number;
+
+ // Don't link old transmissions to new ones when version or
+ // encryption changes.
+ if (transmission_type == ALL_INITIAL_RETRANSMISSION ||
+ transmission_type == ALL_UNACKED_RETRANSMISSION) {
+ transmission_info->is_unackable = true;
+ } else {
+ transmission_info->retransmission = new_packet_number;
+ }
+ // Proactively remove obsolete packets so the least unacked can be raised.
+ RemoveObsoletePackets();
+}
+
+bool QuicUnackedPacketMap::HasRetransmittableFrames(
+ QuicPacketNumber packet_number) const {
+ DCHECK_GE(packet_number, least_unacked_);
+ DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size());
+ return !unacked_packets_[packet_number - least_unacked_]
+ .retransmittable_frames.empty();
+}
+
+void QuicUnackedPacketMap::RemoveRetransmittability(TransmissionInfo* info) {
+ while (info->retransmission != 0) {
+ const QuicPacketNumber retransmission = info->retransmission;
+ info->retransmission = 0;
+ info = &unacked_packets_[retransmission - least_unacked_];
+ }
+ MaybeRemoveRetransmittableFrames(info);
+}
+
+void QuicUnackedPacketMap::RemoveRetransmittability(
+ QuicPacketNumber packet_number) {
+ DCHECK_GE(packet_number, least_unacked_);
+ DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size());
+ TransmissionInfo* info = &unacked_packets_[packet_number - least_unacked_];
+ RemoveRetransmittability(info);
+}
+
+void QuicUnackedPacketMap::MaybeRemoveRetransmittableFrames(
+ TransmissionInfo* transmission_info) {
+ if (transmission_info->has_crypto_handshake) {
+ DCHECK(!transmission_info->retransmittable_frames.empty());
+ DCHECK_LT(0u, pending_crypto_packet_count_);
+ --pending_crypto_packet_count_;
+ transmission_info->has_crypto_handshake = false;
+ }
+ QuicUtils::DeleteFrames(&transmission_info->retransmittable_frames);
+}
+
+void QuicUnackedPacketMap::IncreaseLargestObserved(
+ QuicPacketNumber largest_observed) {
+ DCHECK_LE(largest_observed_, largest_observed);
+ largest_observed_ = largest_observed;
+}
+
+bool QuicUnackedPacketMap::IsPacketUsefulForMeasuringRtt(
+ QuicPacketNumber packet_number,
+ const TransmissionInfo& info) const {
+ // Packet can be used for RTT measurement if it may yet be acked as the
+ // largest observed packet by the receiver.
+ return !info.is_unackable && packet_number > largest_observed_;
+}
+
+bool QuicUnackedPacketMap::IsPacketUsefulForCongestionControl(
+ const TransmissionInfo& info) const {
+ // Packet contributes to congestion control if it is considered inflight.
+ return info.in_flight;
+}
+
+bool QuicUnackedPacketMap::IsPacketUsefulForRetransmittableData(
+ const TransmissionInfo& info) const {
+ // Packet may have retransmittable frames, or the data may have been
+ // retransmitted with a new packet number.
+ return !info.retransmittable_frames.empty() ||
+ // Allow for an extra 1 RTT before stopping to track old packets.
+ info.retransmission > largest_observed_;
+}
+
+bool QuicUnackedPacketMap::IsPacketUseless(QuicPacketNumber packet_number,
+ const TransmissionInfo& info) const {
+ return !IsPacketUsefulForMeasuringRtt(packet_number, info) &&
+ !IsPacketUsefulForCongestionControl(info) &&
+ !IsPacketUsefulForRetransmittableData(info);
+}
+
+bool QuicUnackedPacketMap::IsUnacked(QuicPacketNumber packet_number) const {
+ if (packet_number < least_unacked_ ||
+ packet_number >= least_unacked_ + unacked_packets_.size()) {
+ return false;
+ }
+ return !IsPacketUseless(packet_number,
+ unacked_packets_[packet_number - least_unacked_]);
+}
+
+void QuicUnackedPacketMap::NotifyAndClearListeners(
+ std::list<AckListenerWrapper>* ack_listeners,
+ QuicTime::Delta ack_delay_time) {
+ for (const AckListenerWrapper& wrapper : *ack_listeners) {
+ wrapper.ack_listener->OnPacketAcked(wrapper.length, ack_delay_time);
+ }
+ ack_listeners->clear();
+}
+
+void QuicUnackedPacketMap::NotifyAndClearListeners(
+ QuicPacketNumber packet_number,
+ QuicTime::Delta ack_delay_time) {
+ DCHECK_GE(packet_number, least_unacked_);
+ DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size());
+ TransmissionInfo* info = &unacked_packets_[packet_number - least_unacked_];
+ NotifyAndClearListeners(&info->ack_listeners, ack_delay_time);
+}
+
+void QuicUnackedPacketMap::RemoveFromInFlight(TransmissionInfo* info) {
+ if (info->in_flight) {
+ QUIC_BUG_IF(bytes_in_flight_ < info->bytes_sent);
+ bytes_in_flight_ -= info->bytes_sent;
+ info->in_flight = false;
+ }
+}
+
+void QuicUnackedPacketMap::RemoveFromInFlight(QuicPacketNumber packet_number) {
+ DCHECK_GE(packet_number, least_unacked_);
+ DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size());
+ TransmissionInfo* info = &unacked_packets_[packet_number - least_unacked_];
+ RemoveFromInFlight(info);
+}
+
+void QuicUnackedPacketMap::RestoreToInFlight(QuicPacketNumber packet_number) {
+ DCHECK_GE(packet_number, least_unacked_);
+ DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size());
+ TransmissionInfo* info = &unacked_packets_[packet_number - least_unacked_];
+ DCHECK(!info->is_unackable);
+ bytes_in_flight_ += info->bytes_sent;
+ info->in_flight = true;
+}
+
+void QuicUnackedPacketMap::CancelRetransmissionsForStream(
+ QuicStreamId stream_id) {
+ QuicPacketNumber packet_number = least_unacked_;
+ for (UnackedPacketMap::iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it, ++packet_number) {
+ QuicFrames* frames = &it->retransmittable_frames;
+ if (frames->empty()) {
+ continue;
+ }
+ QuicUtils::RemoveFramesForStream(frames, stream_id);
+ if (frames->empty()) {
+ RemoveRetransmittability(packet_number);
+ }
+ }
+}
+
+bool QuicUnackedPacketMap::HasUnackedPackets() const {
+ return !unacked_packets_.empty();
+}
+
+bool QuicUnackedPacketMap::HasInFlightPackets() const {
+ return bytes_in_flight_ > 0;
+}
+
+const TransmissionInfo& QuicUnackedPacketMap::GetTransmissionInfo(
+ QuicPacketNumber packet_number) const {
+ return unacked_packets_[packet_number - least_unacked_];
+}
+
+TransmissionInfo* QuicUnackedPacketMap::GetMutableTransmissionInfo(
+ QuicPacketNumber packet_number) {
+ return &unacked_packets_[packet_number - least_unacked_];
+}
+
+QuicTime QuicUnackedPacketMap::GetLastPacketSentTime() const {
+ UnackedPacketMap::const_reverse_iterator it = unacked_packets_.rbegin();
+ while (it != unacked_packets_.rend()) {
+ if (it->in_flight) {
+ QUIC_BUG_IF(it->sent_time == QuicTime::Zero())
+ << "Sent time can never be zero for a packet in flight.";
+ return it->sent_time;
+ }
+ ++it;
+ }
+ QUIC_BUG << "GetLastPacketSentTime requires in flight packets.";
+ return QuicTime::Zero();
+}
+
+size_t QuicUnackedPacketMap::GetNumUnackedPacketsDebugOnly() const {
+ size_t unacked_packet_count = 0;
+ QuicPacketNumber packet_number = least_unacked_;
+ for (UnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it, ++packet_number) {
+ if (!IsPacketUseless(packet_number, *it)) {
+ ++unacked_packet_count;
+ }
+ }
+ return unacked_packet_count;
+}
+
+bool QuicUnackedPacketMap::HasMultipleInFlightPackets() const {
+ if (bytes_in_flight_ > kDefaultTCPMSS) {
+ return true;
+ }
+ size_t num_in_flight = 0;
+ for (UnackedPacketMap::const_reverse_iterator it = unacked_packets_.rbegin();
+ it != unacked_packets_.rend(); ++it) {
+ if (it->in_flight) {
+ ++num_in_flight;
+ }
+ if (num_in_flight > 1) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QuicUnackedPacketMap::HasPendingCryptoPackets() const {
+ return pending_crypto_packet_count_ > 0;
+}
+
+bool QuicUnackedPacketMap::HasUnackedRetransmittableFrames() const {
+ for (UnackedPacketMap::const_reverse_iterator it = unacked_packets_.rbegin();
+ it != unacked_packets_.rend(); ++it) {
+ if (it->in_flight && !it->retransmittable_frames.empty()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+QuicPacketNumber QuicUnackedPacketMap::GetLeastUnacked() const {
+ return least_unacked_;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_unacked_packet_map.h b/chromium/net/quic/core/quic_unacked_packet_map.h
new file mode 100644
index 00000000000..47352b3fbe3
--- /dev/null
+++ b/chromium/net/quic/core/quic_unacked_packet_map.h
@@ -0,0 +1,203 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_QUIC_UNACKED_PACKET_MAP_H_
+#define NET_QUIC_QUIC_UNACKED_PACKET_MAP_H_
+
+#include <stddef.h>
+
+#include <deque>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+
+namespace net {
+
+class AckNotifierManager;
+
+// Class which tracks unacked packets for three purposes:
+// 1) Track retransmittable data, including multiple transmissions of frames.
+// 2) Track packets and bytes in flight for congestion control.
+// 3) Track sent time of packets to provide RTT measurements from acks.
+class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
+ public:
+ QuicUnackedPacketMap();
+ ~QuicUnackedPacketMap();
+
+ // Adds |serialized_packet| to the map and marks it as sent at |sent_time|.
+ // Marks the packet as in flight if |set_in_flight| is true.
+ // Packets marked as in flight are expected to be marked as missing when they
+ // don't arrive, indicating the need for retransmission.
+ // |old_packet_number| is the packet number of the previous transmission,
+ // or 0 if there was none.
+ // Any AckNotifierWrappers in |serialized_packet| are swapped from the
+ // serialized packet into the TransmissionInfo.
+ void AddSentPacket(SerializedPacket* serialized_packet,
+ QuicPacketNumber old_packet_number,
+ TransmissionType transmission_type,
+ QuicTime sent_time,
+ bool set_in_flight);
+
+ // Returns true if the packet |packet_number| is unacked.
+ bool IsUnacked(QuicPacketNumber packet_number) const;
+
+ // Notifies all the AckListeners attached to the |info| and
+ // clears them to ensure they're not notified again.
+ void NotifyAndClearListeners(std::list<AckListenerWrapper>* ack_listeners,
+ QuicTime::Delta delta_largest_observed);
+
+ // Notifies all the AckListeners attached to |newest_transmission|.
+ void NotifyAndClearListeners(QuicPacketNumber newest_transmission,
+ QuicTime::Delta delta_largest_observed);
+
+ // Marks |info| as no longer in flight.
+ void RemoveFromInFlight(TransmissionInfo* info);
+
+ // Marks |packet_number| as no longer in flight.
+ void RemoveFromInFlight(QuicPacketNumber packet_number);
+
+ // Marks |packet_number| as in flight. Must not be unackable.
+ void RestoreToInFlight(QuicPacketNumber packet_number);
+
+ // No longer retransmit data for |stream_id|.
+ void CancelRetransmissionsForStream(QuicStreamId stream_id);
+
+ // Returns true if the unacked packet |packet_number| has retransmittable
+ // frames. This will return false if the packet has been acked, if a
+ // previous transmission of this packet was ACK'd, or if this packet has been
+ // retransmitted as with different packet number, or if the packet never
+ // had any retransmittable packets in the first place.
+ bool HasRetransmittableFrames(QuicPacketNumber packet_number) const;
+
+ // Returns true if there are any unacked packets.
+ bool HasUnackedPackets() const;
+
+ // Returns true if there are any unacked packets which have retransmittable
+ // frames.
+ bool HasUnackedRetransmittableFrames() const;
+
+ // Returns the largest packet number that has been sent.
+ QuicPacketNumber largest_sent_packet() const { return largest_sent_packet_; }
+
+ // Returns the largest retransmittable packet number that has been sent.
+ QuicPacketNumber largest_sent_retransmittable_packet() const {
+ return largest_sent_retransmittable_packet_;
+ }
+
+ // Returns the largest packet number that has been acked.
+ QuicPacketNumber largest_observed() const { return largest_observed_; }
+
+ // Returns the sum of bytes from all packets in flight.
+ QuicByteCount bytes_in_flight() const { return bytes_in_flight_; }
+
+ // Returns the smallest packet number of a serialized packet which has not
+ // been acked by the peer. If there are no unacked packets, returns 0.
+ QuicPacketNumber GetLeastUnacked() const;
+
+ typedef std::deque<TransmissionInfo> UnackedPacketMap;
+
+ typedef UnackedPacketMap::const_iterator const_iterator;
+ typedef UnackedPacketMap::iterator iterator;
+
+ const_iterator begin() const { return unacked_packets_.begin(); }
+ const_iterator end() const { return unacked_packets_.end(); }
+ iterator begin() { return unacked_packets_.begin(); }
+ iterator end() { return unacked_packets_.end(); }
+
+ // Returns true if there are unacked packets that are in flight.
+ bool HasInFlightPackets() const;
+
+ // Returns the TransmissionInfo associated with |packet_number|, which
+ // must be unacked.
+ const TransmissionInfo& GetTransmissionInfo(
+ QuicPacketNumber packet_number) const;
+
+ // Returns mutable TransmissionInfo associated with |packet_number|, which
+ // must be unacked.
+ TransmissionInfo* GetMutableTransmissionInfo(QuicPacketNumber packet_number);
+
+ // Returns the time that the last unacked packet was sent.
+ QuicTime GetLastPacketSentTime() const;
+
+ // Returns the number of unacked packets.
+ size_t GetNumUnackedPacketsDebugOnly() const;
+
+ // Returns true if there are multiple packets in flight.
+ bool HasMultipleInFlightPackets() const;
+
+ // Returns true if there are any pending crypto packets.
+ bool HasPendingCryptoPackets() const;
+
+ // Removes any retransmittable frames from this transmission or an associated
+ // transmission. It removes now useless transmissions, and disconnects any
+ // other packets from other transmissions.
+ void RemoveRetransmittability(TransmissionInfo* info);
+
+ // Looks up the TransmissionInfo by |packet_number| and calls
+ // RemoveRetransmittability.
+ void RemoveRetransmittability(QuicPacketNumber packet_number);
+
+ // Increases the largest observed. Any packets less or equal to
+ // |largest_acked_packet| are discarded if they are only for the RTT purposes.
+ void IncreaseLargestObserved(QuicPacketNumber largest_observed);
+
+ // Remove any packets no longer needed for retransmission, congestion, or
+ // RTT measurement purposes.
+ void RemoveObsoletePackets();
+
+ private:
+ // Called when a packet is retransmitted with a new packet number.
+ // |old_packet_number| will remain unacked, but will have no
+ // retransmittable data associated with it. Retransmittable frames will be
+ // transferred to |info| and all_transmissions will be populated.
+ void TransferRetransmissionInfo(QuicPacketNumber old_packet_number,
+ QuicPacketNumber new_packet_number,
+ TransmissionType transmission_type,
+ TransmissionInfo* info);
+
+ void MaybeRemoveRetransmittableFrames(TransmissionInfo* transmission_info);
+
+ // Returns true if packet may be useful for an RTT measurement.
+ bool IsPacketUsefulForMeasuringRtt(QuicPacketNumber packet_number,
+ const TransmissionInfo& info) const;
+
+ // Returns true if packet may be useful for congestion control purposes.
+ bool IsPacketUsefulForCongestionControl(const TransmissionInfo& info) const;
+
+ // Returns true if packet may be associated with retransmittable data
+ // directly or through retransmissions.
+ bool IsPacketUsefulForRetransmittableData(const TransmissionInfo& info) const;
+
+ // Returns true if the packet no longer has a purpose in the map.
+ bool IsPacketUseless(QuicPacketNumber packet_number,
+ const TransmissionInfo& info) const;
+
+ QuicPacketNumber largest_sent_packet_;
+ // The largest sent packet we expect to receive an ack for.
+ QuicPacketNumber largest_sent_retransmittable_packet_;
+ QuicPacketNumber largest_observed_;
+
+ // Newly serialized retransmittable packets are added to this map, which
+ // contains owning pointers to any contained frames. If a packet is
+ // retransmitted, this map will contain entries for both the old and the new
+ // packet. The old packet's retransmittable frames entry will be nullptr,
+ // while the new packet's entry will contain the frames to retransmit.
+ // If the old packet is acked before the new packet, then the old entry will
+ // be removed from the map and the new entry's retransmittable frames will be
+ // set to nullptr.
+ UnackedPacketMap unacked_packets_;
+ // The packet at the 0th index of unacked_packets_.
+ QuicPacketNumber least_unacked_;
+
+ QuicByteCount bytes_in_flight_;
+ // Number of retransmittable crypto handshake packets.
+ size_t pending_crypto_packet_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicUnackedPacketMap);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_UNACKED_PACKET_MAP_H_
diff --git a/chromium/net/quic/core/quic_unacked_packet_map_test.cc b/chromium/net/quic/core/quic_unacked_packet_map_test.cc
new file mode 100644
index 00000000000..c8418067692
--- /dev/null
+++ b/chromium/net/quic/core/quic_unacked_packet_map_test.cc
@@ -0,0 +1,395 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_unacked_packet_map.h"
+
+#include "base/stl_util.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::min;
+using std::vector;
+
+namespace net {
+namespace test {
+namespace {
+
+// Default packet length.
+const uint32_t kDefaultLength = 1000;
+
+class QuicUnackedPacketMapTest : public ::testing::Test {
+ protected:
+ QuicUnackedPacketMapTest()
+ : unacked_packets_(),
+ now_(QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1000)) {}
+
+ ~QuicUnackedPacketMapTest() override { base::STLDeleteElements(&packets_); }
+
+ SerializedPacket CreateRetransmittablePacket(QuicPacketNumber packet_number) {
+ return CreateRetransmittablePacketForStream(packet_number,
+ kHeadersStreamId);
+ }
+
+ SerializedPacket CreateRetransmittablePacketForStream(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id) {
+ SerializedPacket packet(kDefaultPathId, packet_number,
+ PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+ 0, false, false);
+ QuicStreamFrame* frame = new QuicStreamFrame();
+ frame->stream_id = stream_id;
+ packet.retransmittable_frames.push_back(QuicFrame(frame));
+ return packet;
+ }
+
+ SerializedPacket CreateNonRetransmittablePacket(
+ QuicPacketNumber packet_number) {
+ return SerializedPacket(kDefaultPathId, packet_number,
+ PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+ 0, false, false);
+ }
+
+ void VerifyInFlightPackets(QuicPacketNumber* packets, size_t num_packets) {
+ unacked_packets_.RemoveObsoletePackets();
+ if (num_packets == 0) {
+ EXPECT_FALSE(unacked_packets_.HasInFlightPackets());
+ EXPECT_FALSE(unacked_packets_.HasMultipleInFlightPackets());
+ return;
+ }
+ if (num_packets == 1) {
+ EXPECT_TRUE(unacked_packets_.HasInFlightPackets());
+ EXPECT_FALSE(unacked_packets_.HasMultipleInFlightPackets());
+ ASSERT_TRUE(unacked_packets_.IsUnacked(packets[0]));
+ EXPECT_TRUE(unacked_packets_.GetTransmissionInfo(packets[0]).in_flight);
+ }
+ for (size_t i = 0; i < num_packets; ++i) {
+ ASSERT_TRUE(unacked_packets_.IsUnacked(packets[i]));
+ EXPECT_TRUE(unacked_packets_.GetTransmissionInfo(packets[i]).in_flight);
+ }
+ size_t in_flight_count = 0;
+ for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it) {
+ if (it->in_flight) {
+ ++in_flight_count;
+ }
+ }
+ EXPECT_EQ(num_packets, in_flight_count);
+ }
+
+ void VerifyUnackedPackets(QuicPacketNumber* packets, size_t num_packets) {
+ unacked_packets_.RemoveObsoletePackets();
+ if (num_packets == 0) {
+ EXPECT_FALSE(unacked_packets_.HasUnackedPackets());
+ EXPECT_FALSE(unacked_packets_.HasUnackedRetransmittableFrames());
+ return;
+ }
+ EXPECT_TRUE(unacked_packets_.HasUnackedPackets());
+ for (size_t i = 0; i < num_packets; ++i) {
+ EXPECT_TRUE(unacked_packets_.IsUnacked(packets[i])) << packets[i];
+ }
+ EXPECT_EQ(num_packets, unacked_packets_.GetNumUnackedPacketsDebugOnly());
+ }
+
+ void VerifyRetransmittablePackets(QuicPacketNumber* packets,
+ size_t num_packets) {
+ unacked_packets_.RemoveObsoletePackets();
+ size_t num_retransmittable_packets = 0;
+ for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
+ it != unacked_packets_.end(); ++it) {
+ if (!it->retransmittable_frames.empty()) {
+ ++num_retransmittable_packets;
+ }
+ }
+ EXPECT_EQ(num_packets, num_retransmittable_packets);
+ for (size_t i = 0; i < num_packets; ++i) {
+ EXPECT_TRUE(unacked_packets_.HasRetransmittableFrames(packets[i]))
+ << " packets[" << i << "]:" << packets[i];
+ }
+ }
+ vector<QuicEncryptedPacket*> packets_;
+ QuicUnackedPacketMap unacked_packets_;
+ QuicTime now_;
+};
+
+TEST_F(QuicUnackedPacketMapTest, RttOnly) {
+ // Acks are only tracked for RTT measurement purposes.
+ SerializedPacket packet(CreateNonRetransmittablePacket(1));
+ unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, false);
+
+ QuicPacketNumber unacked[] = {1};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyInFlightPackets(nullptr, 0);
+ VerifyRetransmittablePackets(nullptr, 0);
+
+ unacked_packets_.IncreaseLargestObserved(1);
+ VerifyUnackedPackets(nullptr, 0);
+ VerifyInFlightPackets(nullptr, 0);
+ VerifyRetransmittablePackets(nullptr, 0);
+}
+
+TEST_F(QuicUnackedPacketMapTest, RetransmittableInflightAndRtt) {
+ // Simulate a retransmittable packet being sent and acked.
+ SerializedPacket packet(CreateRetransmittablePacket(1));
+ unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, true);
+
+ QuicPacketNumber unacked[] = {1};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyInFlightPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(unacked, arraysize(unacked));
+
+ unacked_packets_.RemoveRetransmittability(1);
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyInFlightPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(nullptr, 0);
+
+ unacked_packets_.IncreaseLargestObserved(1);
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyInFlightPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(nullptr, 0);
+
+ unacked_packets_.RemoveFromInFlight(1);
+ VerifyUnackedPackets(nullptr, 0);
+ VerifyInFlightPackets(nullptr, 0);
+ VerifyRetransmittablePackets(nullptr, 0);
+}
+
+TEST_F(QuicUnackedPacketMapTest, StopRetransmission) {
+ const QuicStreamId stream_id = 2;
+ SerializedPacket packet(CreateRetransmittablePacketForStream(1, stream_id));
+ unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, true);
+
+ QuicPacketNumber unacked[] = {1};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyInFlightPackets(unacked, arraysize(unacked));
+ QuicPacketNumber retransmittable[] = {1};
+ VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
+
+ unacked_packets_.CancelRetransmissionsForStream(stream_id);
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyInFlightPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(nullptr, 0);
+}
+
+TEST_F(QuicUnackedPacketMapTest, StopRetransmissionOnOtherStream) {
+ const QuicStreamId stream_id = 2;
+ SerializedPacket packet(CreateRetransmittablePacketForStream(1, stream_id));
+ unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, true);
+
+ QuicPacketNumber unacked[] = {1};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyInFlightPackets(unacked, arraysize(unacked));
+ QuicPacketNumber retransmittable[] = {1};
+ VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
+
+ // Stop retransmissions on another stream and verify the packet is unchanged.
+ unacked_packets_.CancelRetransmissionsForStream(stream_id + 2);
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyInFlightPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
+}
+
+TEST_F(QuicUnackedPacketMapTest, StopRetransmissionAfterRetransmission) {
+ const QuicStreamId stream_id = 2;
+ SerializedPacket packet1(CreateRetransmittablePacketForStream(1, stream_id));
+ unacked_packets_.AddSentPacket(&packet1, 0, NOT_RETRANSMISSION, now_, true);
+ SerializedPacket packet2(CreateNonRetransmittablePacket(2));
+ unacked_packets_.AddSentPacket(&packet2, 1, LOSS_RETRANSMISSION, now_, true);
+
+ QuicPacketNumber unacked[] = {1, 2};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyInFlightPackets(unacked, arraysize(unacked));
+ QuicPacketNumber retransmittable[] = {2};
+ VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
+
+ unacked_packets_.CancelRetransmissionsForStream(stream_id);
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyInFlightPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(nullptr, 0);
+}
+
+TEST_F(QuicUnackedPacketMapTest, RetransmittedPacket) {
+ // Simulate a retransmittable packet being sent, retransmitted, and the first
+ // transmission being acked.
+ SerializedPacket packet1(CreateRetransmittablePacket(1));
+ unacked_packets_.AddSentPacket(&packet1, 0, NOT_RETRANSMISSION, now_, true);
+ SerializedPacket packet2(CreateNonRetransmittablePacket(2));
+ unacked_packets_.AddSentPacket(&packet2, 1, LOSS_RETRANSMISSION, now_, true);
+
+ QuicPacketNumber unacked[] = {1, 2};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyInFlightPackets(unacked, arraysize(unacked));
+ QuicPacketNumber retransmittable[] = {2};
+ VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
+
+ unacked_packets_.RemoveRetransmittability(1);
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyInFlightPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(nullptr, 0);
+
+ unacked_packets_.IncreaseLargestObserved(2);
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyInFlightPackets(unacked, arraysize(unacked));
+ VerifyRetransmittablePackets(nullptr, 0);
+
+ unacked_packets_.RemoveFromInFlight(2);
+ QuicPacketNumber unacked2[] = {1};
+ VerifyUnackedPackets(unacked2, arraysize(unacked2));
+ VerifyInFlightPackets(unacked2, arraysize(unacked2));
+ VerifyRetransmittablePackets(nullptr, 0);
+
+ unacked_packets_.RemoveFromInFlight(1);
+ VerifyUnackedPackets(nullptr, 0);
+ VerifyInFlightPackets(nullptr, 0);
+ VerifyRetransmittablePackets(nullptr, 0);
+}
+
+TEST_F(QuicUnackedPacketMapTest, RetransmitThreeTimes) {
+ // Simulate a retransmittable packet being sent and retransmitted twice.
+ SerializedPacket packet1(CreateRetransmittablePacket(1));
+ unacked_packets_.AddSentPacket(&packet1, 0, NOT_RETRANSMISSION, now_, true);
+ SerializedPacket packet2(CreateRetransmittablePacket(2));
+ unacked_packets_.AddSentPacket(&packet2, 0, NOT_RETRANSMISSION, now_, true);
+
+ QuicPacketNumber unacked[] = {1, 2};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyInFlightPackets(unacked, arraysize(unacked));
+ QuicPacketNumber retransmittable[] = {1, 2};
+ VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
+
+ // Early retransmit 1 as 3 and send new data as 4.
+ unacked_packets_.IncreaseLargestObserved(2);
+ unacked_packets_.RemoveFromInFlight(2);
+ unacked_packets_.RemoveRetransmittability(2);
+ unacked_packets_.RemoveFromInFlight(1);
+ SerializedPacket packet3(CreateNonRetransmittablePacket(3));
+ unacked_packets_.AddSentPacket(&packet3, 1, LOSS_RETRANSMISSION, now_, true);
+ SerializedPacket packet4(CreateRetransmittablePacket(4));
+ unacked_packets_.AddSentPacket(&packet4, 0, NOT_RETRANSMISSION, now_, true);
+
+ QuicPacketNumber unacked2[] = {1, 3, 4};
+ VerifyUnackedPackets(unacked2, arraysize(unacked2));
+ QuicPacketNumber pending2[] = {3, 4};
+ VerifyInFlightPackets(pending2, arraysize(pending2));
+ QuicPacketNumber retransmittable2[] = {3, 4};
+ VerifyRetransmittablePackets(retransmittable2, arraysize(retransmittable2));
+
+ // Early retransmit 3 (formerly 1) as 5, and remove 1 from unacked.
+ unacked_packets_.IncreaseLargestObserved(4);
+ unacked_packets_.RemoveFromInFlight(4);
+ unacked_packets_.RemoveRetransmittability(4);
+ SerializedPacket packet5(CreateNonRetransmittablePacket(5));
+ unacked_packets_.AddSentPacket(&packet5, 3, LOSS_RETRANSMISSION, now_, true);
+ SerializedPacket packet6(CreateRetransmittablePacket(6));
+ unacked_packets_.AddSentPacket(&packet6, 0, NOT_RETRANSMISSION, now_, true);
+
+ QuicPacketNumber unacked3[] = {3, 5, 6};
+ VerifyUnackedPackets(unacked3, arraysize(unacked3));
+ QuicPacketNumber pending3[] = {3, 5, 6};
+ VerifyInFlightPackets(pending3, arraysize(pending3));
+ QuicPacketNumber retransmittable3[] = {5, 6};
+ VerifyRetransmittablePackets(retransmittable3, arraysize(retransmittable3));
+
+ // Early retransmit 5 as 7 and ensure in flight packet 3 is not removed.
+ unacked_packets_.IncreaseLargestObserved(6);
+ unacked_packets_.RemoveFromInFlight(6);
+ unacked_packets_.RemoveRetransmittability(6);
+ SerializedPacket packet7(CreateNonRetransmittablePacket(7));
+ unacked_packets_.AddSentPacket(&packet7, 5, LOSS_RETRANSMISSION, now_, true);
+
+ QuicPacketNumber unacked4[] = {3, 5, 7};
+ VerifyUnackedPackets(unacked4, arraysize(unacked4));
+ QuicPacketNumber pending4[] = {3, 5, 7};
+ VerifyInFlightPackets(pending4, arraysize(pending4));
+ QuicPacketNumber retransmittable4[] = {7};
+ VerifyRetransmittablePackets(retransmittable4, 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));
+}
+
+TEST_F(QuicUnackedPacketMapTest, RetransmitFourTimes) {
+ // Simulate a retransmittable packet being sent and retransmitted twice.
+ SerializedPacket packet1(CreateRetransmittablePacket(1));
+ unacked_packets_.AddSentPacket(&packet1, 0, NOT_RETRANSMISSION, now_, true);
+ SerializedPacket packet2(CreateRetransmittablePacket(2));
+ unacked_packets_.AddSentPacket(&packet2, 0, NOT_RETRANSMISSION, now_, true);
+
+ QuicPacketNumber unacked[] = {1, 2};
+ VerifyUnackedPackets(unacked, arraysize(unacked));
+ VerifyInFlightPackets(unacked, arraysize(unacked));
+ QuicPacketNumber retransmittable[] = {1, 2};
+ VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
+
+ // Early retransmit 1 as 3.
+ unacked_packets_.IncreaseLargestObserved(2);
+ unacked_packets_.RemoveFromInFlight(2);
+ unacked_packets_.RemoveRetransmittability(2);
+ unacked_packets_.RemoveFromInFlight(1);
+ SerializedPacket packet3(CreateNonRetransmittablePacket(3));
+ unacked_packets_.AddSentPacket(&packet3, 1, LOSS_RETRANSMISSION, now_, true);
+
+ QuicPacketNumber unacked2[] = {1, 3};
+ VerifyUnackedPackets(unacked2, arraysize(unacked2));
+ QuicPacketNumber pending2[] = {3};
+ VerifyInFlightPackets(pending2, arraysize(pending2));
+ QuicPacketNumber retransmittable2[] = {3};
+ VerifyRetransmittablePackets(retransmittable2, arraysize(retransmittable2));
+
+ // TLP 3 (formerly 1) as 4, and don't remove 1 from unacked.
+ SerializedPacket packet4(CreateNonRetransmittablePacket(4));
+ unacked_packets_.AddSentPacket(&packet4, 3, TLP_RETRANSMISSION, now_, true);
+ SerializedPacket packet5(CreateRetransmittablePacket(5));
+ unacked_packets_.AddSentPacket(&packet5, 0, NOT_RETRANSMISSION, now_, true);
+
+ QuicPacketNumber unacked3[] = {1, 3, 4, 5};
+ VerifyUnackedPackets(unacked3, arraysize(unacked3));
+ QuicPacketNumber pending3[] = {3, 4, 5};
+ VerifyInFlightPackets(pending3, arraysize(pending3));
+ QuicPacketNumber retransmittable3[] = {4, 5};
+ VerifyRetransmittablePackets(retransmittable3, arraysize(retransmittable3));
+
+ // Early retransmit 4 as 6 and ensure in flight packet 3 is removed.
+ unacked_packets_.IncreaseLargestObserved(5);
+ unacked_packets_.RemoveFromInFlight(5);
+ unacked_packets_.RemoveRetransmittability(5);
+ unacked_packets_.RemoveFromInFlight(3);
+ unacked_packets_.RemoveFromInFlight(4);
+ SerializedPacket packet6(CreateNonRetransmittablePacket(6));
+ unacked_packets_.AddSentPacket(&packet6, 4, LOSS_RETRANSMISSION, now_, true);
+
+ QuicPacketNumber unacked4[] = {4, 6};
+ VerifyUnackedPackets(unacked4, arraysize(unacked4));
+ QuicPacketNumber pending4[] = {6};
+ VerifyInFlightPackets(pending4, arraysize(pending4));
+ QuicPacketNumber retransmittable4[] = {6};
+ VerifyRetransmittablePackets(retransmittable4, arraysize(retransmittable4));
+}
+
+TEST_F(QuicUnackedPacketMapTest, SendWithGap) {
+ // Simulate a retransmittable packet being sent, retransmitted, and the first
+ // transmission being acked.
+ SerializedPacket packet1(CreateRetransmittablePacket(1));
+ unacked_packets_.AddSentPacket(&packet1, 0, NOT_RETRANSMISSION, now_, true);
+ SerializedPacket packet3(CreateRetransmittablePacket(3));
+ unacked_packets_.AddSentPacket(&packet3, 0, NOT_RETRANSMISSION, now_, true);
+ SerializedPacket packet5(CreateNonRetransmittablePacket(5));
+ unacked_packets_.AddSentPacket(&packet5, 3, LOSS_RETRANSMISSION, now_, true);
+
+ EXPECT_EQ(1u, unacked_packets_.GetLeastUnacked());
+ EXPECT_TRUE(unacked_packets_.IsUnacked(1));
+ EXPECT_FALSE(unacked_packets_.IsUnacked(2));
+ EXPECT_TRUE(unacked_packets_.IsUnacked(3));
+ EXPECT_FALSE(unacked_packets_.IsUnacked(4));
+ EXPECT_TRUE(unacked_packets_.IsUnacked(5));
+ EXPECT_EQ(5u, unacked_packets_.largest_sent_packet());
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_utils.cc b/chromium/net/quic/core/quic_utils.cc
new file mode 100644
index 00000000000..58909597b49
--- /dev/null
+++ b/chromium/net/quic/core/quic_utils.cc
@@ -0,0 +1,577 @@
+// 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/quic_utils.h"
+
+#include <ctype.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/containers/adapters.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
+#include "net/base/ip_address.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_write_blocked_list.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+namespace {
+
+// We know that >= GCC 4.8 and Clang have a __uint128_t intrinsic. Other
+// compilers don't necessarily, notably MSVC.
+#if defined(__x86_64__) && \
+ ((defined(__GNUC__) && \
+ (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || \
+ defined(__clang__))
+#define QUIC_UTIL_HAS_UINT128 1
+#endif
+
+#ifdef QUIC_UTIL_HAS_UINT128
+uint128 IncrementalHashFast(uint128 uhash, const char* data, size_t len) {
+ // This code ends up faster than the naive implementation for 2 reasons:
+ // 1. uint128 from base/int128.h is sufficiently complicated that the compiler
+ // cannot transform the multiplication by kPrime into a shift-multiply-add;
+ // it has go through all of the instructions for a 128-bit multiply.
+ // 2. Because there are so fewer instructions (around 13), the hot loop fits
+ // nicely in the instruction queue of many Intel CPUs.
+ // kPrime = 309485009821345068724781371
+ static const __uint128_t kPrime =
+ (static_cast<__uint128_t>(16777216) << 64) + 315;
+ __uint128_t xhash = (static_cast<__uint128_t>(Uint128High64(uhash)) << 64) +
+ Uint128Low64(uhash);
+ const uint8_t* octets = reinterpret_cast<const uint8_t*>(data);
+ for (size_t i = 0; i < len; ++i) {
+ xhash = (xhash ^ octets[i]) * kPrime;
+ }
+ return uint128(static_cast<uint64_t>(xhash >> 64),
+ static_cast<uint64_t>(xhash & UINT64_C(0xFFFFFFFFFFFFFFFF)));
+}
+#endif
+
+#ifndef QUIC_UTIL_HAS_UINT128
+// Slow implementation of IncrementalHash. In practice, only used by Chromium.
+uint128 IncrementalHashSlow(uint128 hash, const char* data, size_t len) {
+ // kPrime = 309485009821345068724781371
+ static const uint128 kPrime(16777216, 315);
+ const uint8_t* octets = reinterpret_cast<const uint8_t*>(data);
+ for (size_t i = 0; i < len; ++i) {
+ hash = hash ^ uint128(0, octets[i]);
+ hash = hash * kPrime;
+ }
+ return hash;
+}
+#endif
+
+uint128 IncrementalHash(uint128 hash, const char* data, size_t len) {
+#ifdef QUIC_UTIL_HAS_UINT128
+ return IncrementalHashFast(hash, data, len);
+#else
+ return IncrementalHashSlow(hash, data, len);
+#endif
+}
+
+bool IsInitializedIPEndPoint(const IPEndPoint& address) {
+ return address.address().IsValid();
+}
+
+} // namespace
+
+// static
+uint64_t QuicUtils::FNV1a_64_Hash(const char* data, int len) {
+ static const uint64_t kOffset = UINT64_C(14695981039346656037);
+ static const uint64_t kPrime = UINT64_C(1099511628211);
+
+ const uint8_t* octets = reinterpret_cast<const uint8_t*>(data);
+
+ uint64_t hash = kOffset;
+
+ for (int i = 0; i < len; ++i) {
+ hash = hash ^ octets[i];
+ hash = hash * kPrime;
+ }
+
+ return hash;
+}
+
+// static
+uint128 QuicUtils::FNV1a_128_Hash(const char* data, int len) {
+ return FNV1a_128_Hash_Two(data, len, nullptr, 0);
+}
+
+// static
+uint128 QuicUtils::FNV1a_128_Hash_Two(const char* data1,
+ int len1,
+ const char* data2,
+ int len2) {
+ // The two constants are defined as part of the hash algorithm.
+ // see http://www.isthe.com/chongo/tech/comp/fnv/
+ // kOffset = 144066263297769815596495629667062367629
+ const uint128 kOffset(UINT64_C(7809847782465536322),
+ UINT64_C(7113472399480571277));
+
+ uint128 hash = IncrementalHash(kOffset, data1, len1);
+ if (data2 == nullptr) {
+ return hash;
+ }
+ return IncrementalHash(hash, data2, len2);
+}
+
+// static
+bool QuicUtils::FindMutualTag(const QuicTagVector& our_tags_vector,
+ const QuicTag* their_tags,
+ size_t num_their_tags,
+ Priority priority,
+ QuicTag* out_result,
+ size_t* out_index) {
+ if (our_tags_vector.empty()) {
+ return false;
+ }
+ const size_t num_our_tags = our_tags_vector.size();
+ const QuicTag* our_tags = &our_tags_vector[0];
+
+ size_t num_priority_tags, num_inferior_tags;
+ const QuicTag* priority_tags;
+ const QuicTag* inferior_tags;
+ if (priority == LOCAL_PRIORITY) {
+ num_priority_tags = num_our_tags;
+ priority_tags = our_tags;
+ num_inferior_tags = num_their_tags;
+ inferior_tags = their_tags;
+ } else {
+ num_priority_tags = num_their_tags;
+ priority_tags = their_tags;
+ num_inferior_tags = num_our_tags;
+ inferior_tags = our_tags;
+ }
+
+ for (size_t i = 0; i < num_priority_tags; i++) {
+ for (size_t j = 0; j < num_inferior_tags; j++) {
+ if (priority_tags[i] == inferior_tags[j]) {
+ *out_result = priority_tags[i];
+ if (out_index) {
+ if (priority == LOCAL_PRIORITY) {
+ *out_index = j;
+ } else {
+ *out_index = i;
+ }
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+// static
+void QuicUtils::SerializeUint128Short(uint128 v, uint8_t* out) {
+ const uint64_t lo = Uint128Low64(v);
+ const uint64_t hi = Uint128High64(v);
+ // This assumes that the system is little-endian.
+ memcpy(out, &lo, sizeof(lo));
+ memcpy(out + sizeof(lo), &hi, sizeof(hi) / 2);
+}
+
+#define RETURN_STRING_LITERAL(x) \
+ case x: \
+ return #x;
+
+// static
+const char* QuicUtils::StreamErrorToString(QuicRstStreamErrorCode error) {
+ switch (error) {
+ RETURN_STRING_LITERAL(QUIC_STREAM_NO_ERROR);
+ RETURN_STRING_LITERAL(QUIC_STREAM_CONNECTION_ERROR);
+ RETURN_STRING_LITERAL(QUIC_ERROR_PROCESSING_STREAM);
+ RETURN_STRING_LITERAL(QUIC_MULTIPLE_TERMINATION_OFFSETS);
+ RETURN_STRING_LITERAL(QUIC_BAD_APPLICATION_PAYLOAD);
+ RETURN_STRING_LITERAL(QUIC_STREAM_PEER_GOING_AWAY);
+ RETURN_STRING_LITERAL(QUIC_STREAM_CANCELLED);
+ RETURN_STRING_LITERAL(QUIC_RST_ACKNOWLEDGEMENT);
+ RETURN_STRING_LITERAL(QUIC_REFUSED_STREAM);
+ RETURN_STRING_LITERAL(QUIC_STREAM_LAST_ERROR);
+ RETURN_STRING_LITERAL(QUIC_INVALID_PROMISE_URL);
+ RETURN_STRING_LITERAL(QUIC_UNAUTHORIZED_PROMISE_URL);
+ RETURN_STRING_LITERAL(QUIC_DUPLICATE_PROMISE_URL);
+ RETURN_STRING_LITERAL(QUIC_PROMISE_VARY_MISMATCH);
+ RETURN_STRING_LITERAL(QUIC_INVALID_PROMISE_METHOD);
+ }
+ // Return a default value so that we return this when |error| doesn't match
+ // any of the QuicRstStreamErrorCodes. This can happen when the RstStream
+ // frame sent by the peer (attacker) has invalid error code.
+ return "INVALID_RST_STREAM_ERROR_CODE";
+}
+
+// static
+const char* QuicUtils::ErrorToString(QuicErrorCode error) {
+ switch (error) {
+ RETURN_STRING_LITERAL(QUIC_NO_ERROR);
+ RETURN_STRING_LITERAL(QUIC_INTERNAL_ERROR);
+ RETURN_STRING_LITERAL(QUIC_STREAM_DATA_AFTER_TERMINATION);
+ RETURN_STRING_LITERAL(QUIC_INVALID_PACKET_HEADER);
+ RETURN_STRING_LITERAL(QUIC_INVALID_FRAME_DATA);
+ RETURN_STRING_LITERAL(QUIC_MISSING_PAYLOAD);
+ RETURN_STRING_LITERAL(QUIC_INVALID_FEC_DATA);
+ RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_DATA);
+ RETURN_STRING_LITERAL(QUIC_OVERLAPPING_STREAM_DATA);
+ RETURN_STRING_LITERAL(QUIC_UNENCRYPTED_STREAM_DATA);
+ RETURN_STRING_LITERAL(QUIC_INVALID_RST_STREAM_DATA);
+ RETURN_STRING_LITERAL(QUIC_INVALID_CONNECTION_CLOSE_DATA);
+ RETURN_STRING_LITERAL(QUIC_INVALID_GOAWAY_DATA);
+ RETURN_STRING_LITERAL(QUIC_INVALID_WINDOW_UPDATE_DATA);
+ RETURN_STRING_LITERAL(QUIC_INVALID_BLOCKED_DATA);
+ RETURN_STRING_LITERAL(QUIC_INVALID_STOP_WAITING_DATA);
+ RETURN_STRING_LITERAL(QUIC_INVALID_PATH_CLOSE_DATA);
+ RETURN_STRING_LITERAL(QUIC_INVALID_ACK_DATA);
+ RETURN_STRING_LITERAL(QUIC_INVALID_VERSION_NEGOTIATION_PACKET);
+ RETURN_STRING_LITERAL(QUIC_INVALID_PUBLIC_RST_PACKET);
+ RETURN_STRING_LITERAL(QUIC_DECRYPTION_FAILURE);
+ RETURN_STRING_LITERAL(QUIC_ENCRYPTION_FAILURE);
+ RETURN_STRING_LITERAL(QUIC_PACKET_TOO_LARGE);
+ RETURN_STRING_LITERAL(QUIC_PEER_GOING_AWAY);
+ RETURN_STRING_LITERAL(QUIC_HANDSHAKE_FAILED);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_TAGS_OUT_OF_ORDER);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_TOO_MANY_ENTRIES);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_TOO_MANY_REJECTS);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_INVALID_VALUE_LENGTH)
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_INTERNAL_ERROR);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_VERSION_NOT_SUPPORTED);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_NO_SUPPORT);
+ RETURN_STRING_LITERAL(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
+ RETURN_STRING_LITERAL(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND);
+ RETURN_STRING_LITERAL(QUIC_UNSUPPORTED_PROOF_DEMAND);
+ RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_ID);
+ RETURN_STRING_LITERAL(QUIC_INVALID_PRIORITY);
+ RETURN_STRING_LITERAL(QUIC_TOO_MANY_OPEN_STREAMS);
+ RETURN_STRING_LITERAL(QUIC_PUBLIC_RESET);
+ RETURN_STRING_LITERAL(QUIC_INVALID_VERSION);
+ RETURN_STRING_LITERAL(QUIC_INVALID_HEADER_ID);
+ RETURN_STRING_LITERAL(QUIC_INVALID_NEGOTIATED_VALUE);
+ RETURN_STRING_LITERAL(QUIC_DECOMPRESSION_FAILURE);
+ RETURN_STRING_LITERAL(QUIC_NETWORK_IDLE_TIMEOUT);
+ RETURN_STRING_LITERAL(QUIC_HANDSHAKE_TIMEOUT);
+ RETURN_STRING_LITERAL(QUIC_ERROR_MIGRATING_ADDRESS);
+ RETURN_STRING_LITERAL(QUIC_ERROR_MIGRATING_PORT);
+ RETURN_STRING_LITERAL(QUIC_PACKET_WRITE_ERROR);
+ RETURN_STRING_LITERAL(QUIC_PACKET_READ_ERROR);
+ RETURN_STRING_LITERAL(QUIC_EMPTY_STREAM_FRAME_NO_FIN);
+ RETURN_STRING_LITERAL(QUIC_INVALID_HEADERS_STREAM_DATA);
+ RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA);
+ RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA);
+ RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_INVALID_WINDOW);
+ RETURN_STRING_LITERAL(QUIC_CONNECTION_IP_POOLED);
+ RETURN_STRING_LITERAL(QUIC_PROOF_INVALID);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_DUPLICATE_TAG);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_SERVER_CONFIG_EXPIRED);
+ RETURN_STRING_LITERAL(QUIC_INVALID_CHANNEL_ID_SIGNATURE);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO);
+ RETURN_STRING_LITERAL(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE);
+ RETURN_STRING_LITERAL(QUIC_VERSION_NEGOTIATION_MISMATCH);
+ RETURN_STRING_LITERAL(QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS);
+ RETURN_STRING_LITERAL(QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS);
+ RETURN_STRING_LITERAL(QUIC_CONNECTION_CANCELLED);
+ RETURN_STRING_LITERAL(QUIC_BAD_PACKET_LOSS_RATE);
+ RETURN_STRING_LITERAL(QUIC_PUBLIC_RESETS_POST_HANDSHAKE);
+ RETURN_STRING_LITERAL(QUIC_TIMEOUTS_WITH_OPEN_STREAMS);
+ RETURN_STRING_LITERAL(QUIC_FAILED_TO_SERIALIZE_PACKET);
+ RETURN_STRING_LITERAL(QUIC_TOO_MANY_AVAILABLE_STREAMS);
+ RETURN_STRING_LITERAL(QUIC_UNENCRYPTED_FEC_DATA);
+ RETURN_STRING_LITERAL(QUIC_BAD_MULTIPATH_FLAG);
+ RETURN_STRING_LITERAL(QUIC_IP_ADDRESS_CHANGED);
+ RETURN_STRING_LITERAL(QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS);
+ RETURN_STRING_LITERAL(QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES);
+ RETURN_STRING_LITERAL(QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK);
+ RETURN_STRING_LITERAL(QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM);
+ RETURN_STRING_LITERAL(QUIC_TOO_MANY_RTOS);
+ RETURN_STRING_LITERAL(QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA);
+ RETURN_STRING_LITERAL(QUIC_MAYBE_CORRUPTED_MEMORY);
+ 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_STREAM_SEQUENCER_INVALID_STATE);
+ RETURN_STRING_LITERAL(QUIC_TOO_MANY_SESSIONS_ON_SERVER);
+ 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.
+ }
+ // Return a default value so that we return this when |error| doesn't match
+ // any of the QuicErrorCodes. This can happen when the ConnectionClose
+ // frame sent by the peer (attacker) has invalid error code.
+ return "INVALID_ERROR_CODE";
+}
+
+// static
+const char* QuicUtils::EncryptionLevelToString(EncryptionLevel level) {
+ switch (level) {
+ RETURN_STRING_LITERAL(ENCRYPTION_NONE);
+ RETURN_STRING_LITERAL(ENCRYPTION_INITIAL);
+ RETURN_STRING_LITERAL(ENCRYPTION_FORWARD_SECURE);
+ RETURN_STRING_LITERAL(NUM_ENCRYPTION_LEVELS);
+ }
+ return "INVALID_ENCRYPTION_LEVEL";
+}
+
+// static
+const char* QuicUtils::TransmissionTypeToString(TransmissionType type) {
+ switch (type) {
+ RETURN_STRING_LITERAL(NOT_RETRANSMISSION);
+ RETURN_STRING_LITERAL(HANDSHAKE_RETRANSMISSION);
+ RETURN_STRING_LITERAL(LOSS_RETRANSMISSION);
+ RETURN_STRING_LITERAL(ALL_UNACKED_RETRANSMISSION);
+ RETURN_STRING_LITERAL(ALL_INITIAL_RETRANSMISSION);
+ RETURN_STRING_LITERAL(RTO_RETRANSMISSION);
+ RETURN_STRING_LITERAL(TLP_RETRANSMISSION);
+ }
+ return "INVALID_TRANSMISSION_TYPE";
+}
+
+// static
+string QuicUtils::TagToString(QuicTag tag) {
+ char chars[sizeof tag];
+ bool ascii = true;
+ const QuicTag orig_tag = tag;
+
+ for (size_t i = 0; i < arraysize(chars); i++) {
+ chars[i] = static_cast<char>(tag);
+ if ((chars[i] == 0 || chars[i] == '\xff') && i == arraysize(chars) - 1) {
+ chars[i] = ' ';
+ }
+ if (!isprint(static_cast<unsigned char>(chars[i]))) {
+ ascii = false;
+ break;
+ }
+ tag >>= 8;
+ }
+
+ if (ascii) {
+ return string(chars, sizeof(chars));
+ }
+
+ return base::UintToString(orig_tag);
+}
+
+// static
+QuicTagVector QuicUtils::ParseQuicConnectionOptions(
+ const std::string& connection_options) {
+ QuicTagVector options;
+ // Tokens are expected to be no more than 4 characters long, but we
+ // handle overflow gracefully.
+ for (const base::StringPiece& token :
+ base::SplitStringPiece(connection_options, ",", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_ALL)) {
+ uint32_t option = 0;
+ for (char token_char : base::Reversed(token)) {
+ option <<= 8;
+ option |= static_cast<unsigned char>(token_char);
+ }
+ options.push_back(option);
+ }
+ return options;
+}
+
+string QuicUtils::PeerAddressChangeTypeToString(PeerAddressChangeType type) {
+ switch (type) {
+ RETURN_STRING_LITERAL(NO_CHANGE);
+ RETURN_STRING_LITERAL(PORT_CHANGE);
+ RETURN_STRING_LITERAL(IPV4_SUBNET_CHANGE);
+ RETURN_STRING_LITERAL(IPV4_TO_IPV6_CHANGE);
+ RETURN_STRING_LITERAL(IPV6_TO_IPV4_CHANGE);
+ RETURN_STRING_LITERAL(IPV6_TO_IPV6_CHANGE);
+ RETURN_STRING_LITERAL(IPV4_TO_IPV4_CHANGE);
+ }
+ return "INVALID_PEER_ADDRESS_CHANGE_TYPE";
+}
+
+// static
+void QuicUtils::DeleteFrames(QuicFrames* frames) {
+ for (QuicFrame& frame : *frames) {
+ switch (frame.type) {
+ // Frames smaller than a pointer are inlined, so don't need to be deleted.
+ case PADDING_FRAME:
+ case MTU_DISCOVERY_FRAME:
+ case PING_FRAME:
+ break;
+ case STREAM_FRAME:
+ delete frame.stream_frame;
+ break;
+ case ACK_FRAME:
+ delete frame.ack_frame;
+ break;
+ case STOP_WAITING_FRAME:
+ delete frame.stop_waiting_frame;
+ break;
+ case RST_STREAM_FRAME:
+ delete frame.rst_stream_frame;
+ break;
+ case CONNECTION_CLOSE_FRAME:
+ delete frame.connection_close_frame;
+ break;
+ case GOAWAY_FRAME:
+ delete frame.goaway_frame;
+ break;
+ case BLOCKED_FRAME:
+ delete frame.blocked_frame;
+ break;
+ case WINDOW_UPDATE_FRAME:
+ delete frame.window_update_frame;
+ break;
+ case PATH_CLOSE_FRAME:
+ delete frame.path_close_frame;
+ break;
+ case NUM_FRAME_TYPES:
+ DCHECK(false) << "Cannot delete type: " << frame.type;
+ }
+ }
+ frames->clear();
+}
+
+// static
+void QuicUtils::RemoveFramesForStream(QuicFrames* frames,
+ QuicStreamId stream_id) {
+ QuicFrames::iterator it = frames->begin();
+ while (it != frames->end()) {
+ if (it->type != STREAM_FRAME || it->stream_frame->stream_id != stream_id) {
+ ++it;
+ continue;
+ }
+ delete it->stream_frame;
+ it = frames->erase(it);
+ }
+}
+
+// static
+void QuicUtils::ClearSerializedPacket(SerializedPacket* serialized_packet) {
+ if (!serialized_packet->retransmittable_frames.empty()) {
+ DeleteFrames(&serialized_packet->retransmittable_frames);
+ }
+ serialized_packet->encrypted_buffer = nullptr;
+ serialized_packet->encrypted_length = 0;
+}
+
+// static
+uint64_t QuicUtils::PackPathIdAndPacketNumber(QuicPathId path_id,
+ QuicPacketNumber packet_number) {
+ // Setting the nonce below relies on QuicPathId and QuicPacketNumber being
+ // specific sizes.
+ static_assert(sizeof(path_id) == 1, "Size of QuicPathId changed.");
+ static_assert(sizeof(packet_number) == 8,
+ "Size of QuicPacketNumber changed.");
+ // Use path_id and lower 7 bytes of packet_number as lower 8 bytes of nonce.
+ uint64_t path_id_packet_number =
+ (static_cast<uint64_t>(path_id) << 56) | packet_number;
+ DCHECK(path_id != kDefaultPathId || path_id_packet_number == packet_number);
+ return path_id_packet_number;
+}
+
+// static
+char* QuicUtils::CopyBuffer(const SerializedPacket& packet) {
+ char* dst_buffer = new char[packet.encrypted_length];
+ memcpy(dst_buffer, packet.encrypted_buffer, packet.encrypted_length);
+ return dst_buffer;
+}
+
+// static
+PeerAddressChangeType QuicUtils::DetermineAddressChangeType(
+ const IPEndPoint& old_address,
+ const IPEndPoint& new_address) {
+ if (!IsInitializedIPEndPoint(old_address) ||
+ !IsInitializedIPEndPoint(new_address) || old_address == new_address) {
+ return NO_CHANGE;
+ }
+
+ if (old_address.address() == new_address.address()) {
+ return PORT_CHANGE;
+ }
+
+ bool old_ip_is_ipv4 = old_address.address().IsIPv4();
+ bool migrating_ip_is_ipv4 = new_address.address().IsIPv4();
+ if (old_ip_is_ipv4 && !migrating_ip_is_ipv4) {
+ return IPV4_TO_IPV6_CHANGE;
+ }
+
+ if (!old_ip_is_ipv4) {
+ return migrating_ip_is_ipv4 ? IPV6_TO_IPV4_CHANGE : IPV6_TO_IPV6_CHANGE;
+ }
+
+ if (IPAddressMatchesPrefix(old_address.address(), new_address.address(),
+ 24)) {
+ // Subnet part does not change (here, we use /24), which is considered to be
+ // caused by NATs.
+ return IPV4_SUBNET_CHANGE;
+ }
+
+ return IPV4_TO_IPV4_CHANGE;
+}
+
+string QuicUtils::HexEncode(const char* data, size_t length) {
+ return HexEncode(StringPiece(data, length));
+}
+
+string QuicUtils::HexEncode(StringPiece data) {
+ return ::base::HexEncode(data.data(), data.size());
+}
+
+string QuicUtils::HexDecode(const char* data, size_t length) {
+ return HexDecode(StringPiece(data, length));
+}
+
+string QuicUtils::HexDecode(StringPiece data) {
+ if (data.empty())
+ return "";
+ std::vector<uint8_t> v;
+ if (!base::HexStringToBytes(data.as_string(), &v))
+ return "";
+ string out;
+ if (!v.empty())
+ out.assign(reinterpret_cast<const char*>(&v[0]), v.size());
+ return out;
+}
+
+string QuicUtils::HexDump(StringPiece binary_input) {
+ int offset = 0;
+ const int kBytesPerLine = 16; // Max bytes dumped per line
+ const char* buf = binary_input.data();
+ int bytes_remaining = binary_input.size();
+ string s; // our output
+ const char* p = buf;
+ while (bytes_remaining > 0) {
+ const int line_bytes = std::min(bytes_remaining, kBytesPerLine);
+ base::StringAppendF(&s, "0x%04x: ", offset); // Do the line header
+ for (int i = 0; i < kBytesPerLine; ++i) {
+ if (i < line_bytes) {
+ base::StringAppendF(&s, "%02x", static_cast<unsigned char>(p[i]));
+ } else {
+ s += " "; // two-space filler instead of two-space hex digits
+ }
+ if (i % 2)
+ s += ' ';
+ }
+ s += ' ';
+ for (int i = 0; i < line_bytes; ++i) { // Do the ASCII dump
+ s += (p[i] > 32 && p[i] < 127) ? p[i] : '.';
+ }
+
+ bytes_remaining -= line_bytes;
+ offset += line_bytes;
+ p += line_bytes;
+ s += '\n';
+ }
+ return s;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_utils.h b/chromium/net/quic/core/quic_utils.h
new file mode 100644
index 00000000000..66b338ab751
--- /dev/null
+++ b/chromium/net/quic/core/quic_utils.h
@@ -0,0 +1,160 @@
+// 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.
+//
+// Some helpers for quic.
+
+#ifndef NET_QUIC_CORE_QUIC_UTILS_H_
+#define NET_QUIC_CORE_QUIC_UTILS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/base/int128.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_protocol.h"
+
+#ifdef _MSC_VER
+// MSVC 2013 and prior don't have alignof or aligned(); they have __alignof and
+// a __declspec instead.
+#define QUIC_ALIGN_OF __alignof
+#define QUIC_ALIGNED(X) __declspec(align(X))
+#else
+#define QUIC_ALIGN_OF alignof
+#define QUIC_ALIGNED(X) __attribute__((aligned(X)))
+#endif // _MSC_VER
+
+namespace net {
+
+class NET_EXPORT_PRIVATE QuicUtils {
+ public:
+ enum Priority {
+ LOCAL_PRIORITY,
+ PEER_PRIORITY,
+ };
+
+ // Returns the 64 bit FNV1a hash of the data. See
+ // http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param
+ static uint64_t FNV1a_64_Hash(const char* data, int len);
+
+ // returns the 128 bit FNV1a hash of the data. See
+ // http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param
+ static uint128 FNV1a_128_Hash(const char* data1, int len1);
+
+ // returns the 128 bit FNV1a hash of the two sequences of data. See
+ // http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param
+ static uint128 FNV1a_128_Hash_Two(const char* data1,
+ int len1,
+ const char* data2,
+ int len2);
+
+ // FindMutualTag sets |out_result| to the first tag in the priority list that
+ // is also in the other list and returns true. If there is no intersection it
+ // returns false.
+ //
+ // Which list has priority is determined by |priority|.
+ //
+ // If |out_index| is non-nullptr and a match is found then the index of that
+ // match in |their_tags| is written to |out_index|.
+ static bool FindMutualTag(const QuicTagVector& our_tags,
+ const QuicTag* their_tags,
+ size_t num_their_tags,
+ Priority priority,
+ QuicTag* out_result,
+ size_t* out_index);
+
+ // SerializeUint128 writes the first 96 bits of |v| in little-endian form
+ // to |out|.
+ static void SerializeUint128Short(uint128 v, uint8_t* out);
+
+ // Returns the name of the QuicRstStreamErrorCode as a char*
+ static const char* StreamErrorToString(QuicRstStreamErrorCode error);
+
+ // Returns the name of the QuicErrorCode as a char*
+ static const char* ErrorToString(QuicErrorCode error);
+
+ // Returns the level of encryption as a char*
+ static const char* EncryptionLevelToString(EncryptionLevel level);
+
+ // Returns TransmissionType as a char*
+ static const char* TransmissionTypeToString(TransmissionType type);
+
+ // TagToString is a utility function for pretty-printing handshake messages
+ // that converts a tag to a string. It will try to maintain the human friendly
+ // name if possible (i.e. kABCD -> "ABCD"), or will just treat it as a number
+ // if not.
+ static std::string TagToString(QuicTag tag);
+
+ // Returns the list of QUIC tags represented by the comma separated
+ // string in |connection_options|.
+ static QuicTagVector ParseQuicConnectionOptions(
+ const std::string& connection_options);
+
+ // Returns PeerAddressChangeType as a std::string.
+ static std::string PeerAddressChangeTypeToString(PeerAddressChangeType type);
+
+ static char* AsChars(unsigned char* data) {
+ return reinterpret_cast<char*>(data);
+ }
+
+ // Deletes all the sub-frames contained in |frames|.
+ static void DeleteFrames(QuicFrames* frames);
+
+ // Deletes all the QuicStreamFrames for the specified |stream_id|.
+ static void RemoveFramesForStream(QuicFrames* frames, QuicStreamId stream_id);
+
+ // Deletes and clears all the frames and the packet from serialized packet.
+ static void ClearSerializedPacket(SerializedPacket* serialized_packet);
+
+ // Returns a packed representation of |path_id| and |packet_number| in which
+ // the highest byte is set to |path_id| and the lower 7 bytes are the lower
+ // 7 bytes of |packet_number|.
+ static uint64_t PackPathIdAndPacketNumber(QuicPathId path_id,
+ QuicPacketNumber packet_number);
+
+ // Allocates a new char[] of size |packet.encrypted_length| and copies in
+ // |packet.encrypted_buffer|.
+ static char* CopyBuffer(const SerializedPacket& packet);
+
+ // Determines and returns change type of address change from |old_address| to
+ // |new_address|.
+ static PeerAddressChangeType DetermineAddressChangeType(
+ const IPEndPoint& old_address,
+ const IPEndPoint& new_address);
+
+ // This converts 'num' bytes of binary to a 2*'num'-character hexadecimal
+ // representation. Return value: 2*'num' characters of ascii std::string.
+ static std::string HexEncode(const char* data, size_t length);
+ static std::string HexEncode(base::StringPiece data);
+
+ // This converts 2*'num' hexadecimal characters to 'num' binary data.
+ // Return value: 'num' bytes of binary data (via the 'to' argument).
+ static std::string HexDecode(const char* data, size_t length);
+ static std::string HexDecode(base::StringPiece data);
+
+ // Returns a std::string containing hex and ASCII representations of |binary|,
+ // side-by-side in the style of hexdump. Non-printable characters will be
+ // printed as '.' in the ASCII output.
+ // "0x0000: 4865 6c6c 6f2c 2051 5549 4321 0102 0304 Hello,.QUIC!...."
+ static std::string HexDump(base::StringPiece binary_data);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicUtils);
+};
+
+// Utility function that returns an QuicIOVector object wrapped around |str|.
+// |str|'s data is stored in |iov|.
+inline QuicIOVector MakeIOVector(base::StringPiece str, struct iovec* iov) {
+ iov->iov_base = const_cast<char*>(str.data());
+ iov->iov_len = static_cast<size_t>(str.size());
+ QuicIOVector quic_iov(iov, 1, str.size());
+ return quic_iov;
+}
+
+} // namespace net
+
+#endif // NET_QUIC_CORE_QUIC_UTILS_H_
diff --git a/chromium/net/quic/core/quic_utils_test.cc b/chromium/net/quic/core/quic_utils_test.cc
new file mode 100644
index 00000000000..ca3df9bfbb8
--- /dev/null
+++ b/chromium/net/quic/core/quic_utils_test.cc
@@ -0,0 +1,159 @@
+// Copyright (c) 2013 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/quic_utils.h"
+
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/quic_flags.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+namespace test {
+namespace {
+
+TEST(QuicUtilsTest, StreamErrorToString) {
+ EXPECT_STREQ("QUIC_BAD_APPLICATION_PAYLOAD",
+ QuicUtils::StreamErrorToString(QUIC_BAD_APPLICATION_PAYLOAD));
+}
+
+TEST(QuicUtilsTest, ErrorToString) {
+ EXPECT_STREQ("QUIC_NO_ERROR", QuicUtils::ErrorToString(QUIC_NO_ERROR));
+}
+
+TEST(QuicUtilsTest, TagToString) {
+ EXPECT_EQ("SCFG", QuicUtils::TagToString(kSCFG));
+ EXPECT_EQ("SNO ", QuicUtils::TagToString(kServerNonceTag));
+ EXPECT_EQ("CRT ", QuicUtils::TagToString(kCertificateTag));
+ EXPECT_EQ("CHLO", QuicUtils::TagToString(MakeQuicTag('C', 'H', 'L', 'O')));
+ // A tag that contains a non-printing character will be printed as a decimal
+ // number.
+ EXPECT_EQ("525092931",
+ QuicUtils::TagToString(MakeQuicTag('C', 'H', 'L', '\x1f')));
+}
+
+TEST(QuicUtilsTest, ParseQuicConnectionOptions) {
+ QuicTagVector empty_options = QuicUtils::ParseQuicConnectionOptions("");
+ EXPECT_EQ(0ul, empty_options.size());
+
+ QuicTagVector parsed_options =
+ QuicUtils::ParseQuicConnectionOptions("TIMER,TBBR,REJ");
+ QuicTagVector expected_options;
+ expected_options.push_back(kTIME);
+ expected_options.push_back(kTBBR);
+ expected_options.push_back(kREJ);
+ EXPECT_EQ(expected_options, parsed_options);
+}
+
+TEST(QuicUtilsTest, DetermineAddressChangeType) {
+ const string kIPv4String1 = "1.2.3.4";
+ const string kIPv4String2 = "1.2.3.5";
+ const string kIPv4String3 = "1.1.3.5";
+ const string kIPv6String1 = "2001:700:300:1800::f";
+ const string kIPv6String2 = "2001:700:300:1800:1:1:1:f";
+ IPEndPoint old_address;
+ IPEndPoint new_address;
+ IPAddress address;
+
+ EXPECT_EQ(NO_CHANGE,
+ QuicUtils::DetermineAddressChangeType(old_address, new_address));
+ ASSERT_TRUE(address.AssignFromIPLiteral(kIPv4String1));
+ old_address = IPEndPoint(address, 1234);
+ EXPECT_EQ(NO_CHANGE,
+ QuicUtils::DetermineAddressChangeType(old_address, new_address));
+ new_address = IPEndPoint(address, 1234);
+ EXPECT_EQ(NO_CHANGE,
+ QuicUtils::DetermineAddressChangeType(old_address, new_address));
+
+ new_address = IPEndPoint(address, 5678);
+ EXPECT_EQ(PORT_CHANGE,
+ QuicUtils::DetermineAddressChangeType(old_address, new_address));
+ ASSERT_TRUE(address.AssignFromIPLiteral(kIPv6String1));
+ old_address = IPEndPoint(address, 1234);
+ new_address = IPEndPoint(address, 5678);
+ EXPECT_EQ(PORT_CHANGE,
+ QuicUtils::DetermineAddressChangeType(old_address, new_address));
+
+ ASSERT_TRUE(address.AssignFromIPLiteral(kIPv4String1));
+ old_address = IPEndPoint(address, 1234);
+ ASSERT_TRUE(address.AssignFromIPLiteral(kIPv6String1));
+ new_address = IPEndPoint(address, 1234);
+ EXPECT_EQ(IPV4_TO_IPV6_CHANGE,
+ QuicUtils::DetermineAddressChangeType(old_address, new_address));
+
+ old_address = IPEndPoint(address, 1234);
+ ASSERT_TRUE(address.AssignFromIPLiteral(kIPv4String1));
+ new_address = IPEndPoint(address, 1234);
+ EXPECT_EQ(IPV6_TO_IPV4_CHANGE,
+ QuicUtils::DetermineAddressChangeType(old_address, new_address));
+
+ ASSERT_TRUE(address.AssignFromIPLiteral(kIPv6String2));
+ new_address = IPEndPoint(address, 1234);
+ EXPECT_EQ(IPV6_TO_IPV6_CHANGE,
+ QuicUtils::DetermineAddressChangeType(old_address, new_address));
+
+ ASSERT_TRUE(address.AssignFromIPLiteral(kIPv4String1));
+ old_address = IPEndPoint(address, 1234);
+ ASSERT_TRUE(address.AssignFromIPLiteral(kIPv4String2));
+ new_address = IPEndPoint(address, 1234);
+ EXPECT_EQ(IPV4_SUBNET_CHANGE,
+ QuicUtils::DetermineAddressChangeType(old_address, new_address));
+ ASSERT_TRUE(address.AssignFromIPLiteral(kIPv4String3));
+ new_address = IPEndPoint(address, 1234);
+ EXPECT_EQ(IPV4_TO_IPV4_CHANGE,
+ QuicUtils::DetermineAddressChangeType(old_address, new_address));
+}
+
+uint128 IncrementalHashReference(const void* data, size_t len) {
+ // The two constants are defined as part of the hash algorithm.
+ // see http://www.isthe.com/chongo/tech/comp/fnv/
+ // hash = 144066263297769815596495629667062367629
+ uint128 hash =
+ uint128(UINT64_C(7809847782465536322), UINT64_C(7113472399480571277));
+ // kPrime = 309485009821345068724781371
+ const uint128 kPrime(16777216, 315);
+ const uint8_t* octets = reinterpret_cast<const uint8_t*>(data);
+ for (size_t i = 0; i < len; ++i) {
+ hash = hash ^ uint128(0, octets[i]);
+ hash = hash * kPrime;
+ }
+ return hash;
+}
+
+TEST(QuicUtilsHashTest, ReferenceTest) {
+ std::vector<uint8_t> data(32);
+ for (size_t i = 0; i < data.size(); ++i) {
+ data[i] = i % 255;
+ }
+ EXPECT_EQ(IncrementalHashReference(data.data(), data.size()),
+ QuicUtils::FNV1a_128_Hash(
+ reinterpret_cast<const char*>(data.data()), data.size()));
+}
+
+TEST(QuicUtilsTest, HexDump) {
+ // Verify output of the HexDump method is as expected.
+ char packet[] = {
+ 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x51, 0x55, 0x49, 0x43, 0x21,
+ 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+ 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x6c,
+ 0x6f, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x6f, 0x75, 0x67, 0x68, 0x20, 0x74,
+ 0x6f, 0x20, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69,
+ 0x70, 0x6c, 0x65, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x6f, 0x66,
+ 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x01, 0x02, 0x03, 0x00,
+ };
+ EXPECT_EQ(
+ QuicUtils::HexDump(packet),
+ "0x0000: 4865 6c6c 6f2c 2051 5549 4321 2054 6869 Hello,.QUIC!.Thi\n"
+ "0x0010: 7320 7374 7269 6e67 2073 686f 756c 6420 s.string.should.\n"
+ "0x0020: 6265 206c 6f6e 6720 656e 6f75 6768 2074 be.long.enough.t\n"
+ "0x0030: 6f20 7370 616e 206d 756c 7469 706c 6520 o.span.multiple.\n"
+ "0x0040: 6c69 6e65 7320 6f66 206f 7574 7075 742e lines.of.output.\n"
+ "0x0050: 0102 03 ...\n");
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/quic_write_blocked_list.cc b/chromium/net/quic/core/quic_write_blocked_list.cc
new file mode 100644
index 00000000000..32f23cf3eb9
--- /dev/null
+++ b/chromium/net/quic/core/quic_write_blocked_list.cc
@@ -0,0 +1,19 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/quic_write_blocked_list.h"
+
+namespace net {
+
+QuicWriteBlockedList::QuicWriteBlockedList()
+ : last_priority_popped_(0),
+ crypto_stream_blocked_(false),
+ headers_stream_blocked_(false) {
+ memset(batch_write_stream_id_, 0, sizeof(batch_write_stream_id_));
+ memset(bytes_left_for_batch_write_, 0, sizeof(bytes_left_for_batch_write_));
+}
+
+QuicWriteBlockedList::~QuicWriteBlockedList() {}
+
+} // namespace net
diff --git a/chromium/net/quic/core/quic_write_blocked_list.h b/chromium/net/quic/core/quic_write_blocked_list.h
new file mode 100644
index 00000000000..c7b6d446ac6
--- /dev/null
+++ b/chromium/net/quic/core/quic_write_blocked_list.h
@@ -0,0 +1,176 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#ifndef NET_QUIC_QUIC_WRITE_BLOCKED_LIST_H_
+#define NET_QUIC_QUIC_WRITE_BLOCKED_LIST_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <set>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/spdy/priority_write_scheduler.h"
+
+namespace net {
+
+// Keeps tracks of the QUIC streams that have data to write, sorted by
+// priority. QUIC stream priority order is:
+// Crypto stream > Headers stream > Data streams by requested priority.
+class NET_EXPORT_PRIVATE QuicWriteBlockedList {
+ private:
+ typedef PriorityWriteScheduler<QuicStreamId> QuicPriorityWriteScheduler;
+
+ public:
+ QuicWriteBlockedList();
+ ~QuicWriteBlockedList();
+
+ bool HasWriteBlockedDataStreams() const {
+ return priority_write_scheduler_.HasReadyStreams();
+ }
+
+ bool HasWriteBlockedCryptoOrHeadersStream() const {
+ return crypto_stream_blocked_ || headers_stream_blocked_;
+ }
+
+ size_t NumBlockedStreams() const {
+ size_t num_blocked = priority_write_scheduler_.NumReadyStreams();
+ if (crypto_stream_blocked_) {
+ ++num_blocked;
+ }
+ if (headers_stream_blocked_) {
+ ++num_blocked;
+ }
+
+ return num_blocked;
+ }
+
+ bool ShouldYield(QuicStreamId id) const {
+ if (id == kCryptoStreamId) {
+ return false; // The crypto stream yields to none.
+ }
+ if (crypto_stream_blocked_) {
+ return true; // If the crypto stream is blocked, all other streams yield.
+ }
+ if (id == kHeadersStreamId) {
+ return false; // The crypto stream isn't blocked so headers won't yield.
+ }
+ if (headers_stream_blocked_) {
+ return true; // All data streams yield to the headers stream.
+ }
+
+ return priority_write_scheduler_.ShouldYield(id);
+ }
+
+ // Pops the highest priorty stream, special casing crypto and headers streams.
+ // Latches the most recently popped data stream for batch writing purposes.
+ QuicStreamId PopFront() {
+ if (crypto_stream_blocked_) {
+ crypto_stream_blocked_ = false;
+ return kCryptoStreamId;
+ }
+
+ if (headers_stream_blocked_) {
+ headers_stream_blocked_ = false;
+ return kHeadersStreamId;
+ }
+
+ const auto id_and_precedence =
+ priority_write_scheduler_.PopNextReadyStreamAndPrecedence();
+ const QuicStreamId id = std::get<0>(id_and_precedence);
+ const SpdyPriority priority =
+ std::get<1>(id_and_precedence).spdy3_priority();
+
+ if (!priority_write_scheduler_.HasReadyStreams()) {
+ // If no streams are blocked, don't bother latching. This stream will be
+ // the first popped for its priority anyway.
+ batch_write_stream_id_[priority] = 0;
+ last_priority_popped_ = priority;
+ } else if (batch_write_stream_id_[priority] != id) {
+ // If newly latching this batch write stream, let it write 16k.
+ batch_write_stream_id_[priority] = id;
+ bytes_left_for_batch_write_[priority] = 16000;
+ last_priority_popped_ = priority;
+ }
+
+ return id;
+ }
+
+ void RegisterStream(QuicStreamId stream_id, SpdyPriority priority) {
+ priority_write_scheduler_.RegisterStream(stream_id,
+ SpdyStreamPrecedence(priority));
+ }
+
+ void UnregisterStream(QuicStreamId stream_id) {
+ priority_write_scheduler_.UnregisterStream(stream_id);
+ }
+
+ void UpdateStreamPriority(QuicStreamId stream_id, SpdyPriority new_priority) {
+ priority_write_scheduler_.UpdateStreamPrecedence(
+ stream_id, SpdyStreamPrecedence(new_priority));
+ }
+
+ void UpdateBytesForStream(QuicStreamId stream_id, size_t bytes) {
+ if (batch_write_stream_id_[last_priority_popped_] == stream_id) {
+ // If this was the last data stream popped by PopFront, update the
+ // bytes remaining in its batch write.
+ bytes_left_for_batch_write_[last_priority_popped_] -=
+ static_cast<int32_t>(bytes);
+ }
+ }
+
+ // Pushes a stream to the back of the list for its priority level *unless*
+ // it is latched for doing batched writes in which case it goes to the front
+ // of the list for its priority level.
+ // Headers and crypto streams are special cased to always resume first.
+ void AddStream(QuicStreamId stream_id) {
+ if (stream_id == kCryptoStreamId) {
+ // TODO(avd) Add DCHECK(!crypto_stream_blocked_)
+ crypto_stream_blocked_ = true;
+ return;
+ }
+
+ if (stream_id == kHeadersStreamId) {
+ // TODO(avd) Add DCHECK(!headers_stream_blocked_);
+ headers_stream_blocked_ = true;
+ return;
+ }
+ bool push_front =
+ stream_id == batch_write_stream_id_[last_priority_popped_] &&
+ bytes_left_for_batch_write_[last_priority_popped_] > 0;
+ priority_write_scheduler_.MarkStreamReady(stream_id, push_front);
+
+ return;
+ }
+
+ bool crypto_stream_blocked() const { return crypto_stream_blocked_; }
+ bool headers_stream_blocked() const { return headers_stream_blocked_; }
+
+ private:
+ QuicPriorityWriteScheduler priority_write_scheduler_;
+
+ // If performing batch writes, this will be the stream ID of the stream doing
+ // batch writes for this priority level. We will allow this stream to write
+ // until it has written kBatchWriteSize bytes, it has no more data to write,
+ // or a higher priority stream preempts.
+ QuicStreamId batch_write_stream_id_[kV3LowestPriority + 1];
+ // Set to kBatchWriteSize when we set a new batch_write_stream_id_ for a given
+ // priority. This is decremented with each write the stream does until it is
+ // done with its batch write.
+ int32_t bytes_left_for_batch_write_[kV3LowestPriority + 1];
+ // Tracks the last priority popped for UpdateBytesForStream.
+ SpdyPriority last_priority_popped_;
+
+ bool crypto_stream_blocked_;
+ bool headers_stream_blocked_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuicWriteBlockedList);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_QUIC_WRITE_BLOCKED_LIST_H_
diff --git a/chromium/net/quic/core/quic_write_blocked_list_test.cc b/chromium/net/quic/core/quic_write_blocked_list_test.cc
new file mode 100644
index 00000000000..8191062cfa3
--- /dev/null
+++ b/chromium/net/quic/core/quic_write_blocked_list_test.cc
@@ -0,0 +1,219 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#include "net/quic/core/quic_write_blocked_list.h"
+
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using net::kV3LowestPriority;
+using net::kV3HighestPriority;
+
+namespace net {
+namespace test {
+namespace {
+
+TEST(QuicWriteBlockedListTest, PriorityOrder) {
+ QuicWriteBlockedList write_blocked_list;
+
+ // Mark streams blocked in roughly reverse priority order, and
+ // verify that streams are sorted.
+ write_blocked_list.RegisterStream(40, kV3LowestPriority);
+ write_blocked_list.RegisterStream(23, kV3HighestPriority);
+ write_blocked_list.RegisterStream(17, kV3HighestPriority);
+ write_blocked_list.RegisterStream(kHeadersStreamId, kV3HighestPriority);
+ write_blocked_list.RegisterStream(kCryptoStreamId, kV3HighestPriority);
+
+ write_blocked_list.AddStream(40);
+ write_blocked_list.AddStream(23);
+ write_blocked_list.AddStream(17);
+ write_blocked_list.AddStream(kHeadersStreamId);
+ write_blocked_list.AddStream(kCryptoStreamId);
+
+ EXPECT_EQ(5u, write_blocked_list.NumBlockedStreams());
+ EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
+ EXPECT_TRUE(write_blocked_list.HasWriteBlockedDataStreams());
+ // The Crypto stream is highest priority.
+ EXPECT_EQ(kCryptoStreamId, write_blocked_list.PopFront());
+ // Followed by the Headers stream.
+ EXPECT_EQ(kHeadersStreamId, write_blocked_list.PopFront());
+ // Streams with same priority are popped in the order they were inserted.
+ EXPECT_EQ(23u, write_blocked_list.PopFront());
+ EXPECT_EQ(17u, write_blocked_list.PopFront());
+ // Low priority stream appears last.
+ EXPECT_EQ(40u, write_blocked_list.PopFront());
+
+ EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams());
+ EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
+ EXPECT_FALSE(write_blocked_list.HasWriteBlockedDataStreams());
+}
+
+TEST(QuicWriteBlockedListTest, CryptoStream) {
+ QuicWriteBlockedList write_blocked_list;
+ write_blocked_list.RegisterStream(kCryptoStreamId, kV3HighestPriority);
+ write_blocked_list.AddStream(kCryptoStreamId);
+
+ EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams());
+ EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
+ EXPECT_EQ(kCryptoStreamId, write_blocked_list.PopFront());
+ EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams());
+ EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
+}
+
+TEST(QuicWriteBlockedListTest, HeadersStream) {
+ QuicWriteBlockedList write_blocked_list;
+ write_blocked_list.RegisterStream(kHeadersStreamId, kV3HighestPriority);
+ write_blocked_list.AddStream(kHeadersStreamId);
+
+ EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams());
+ EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
+ EXPECT_EQ(kHeadersStreamId, write_blocked_list.PopFront());
+ EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams());
+ EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
+}
+
+TEST(QuicWriteBlockedListTest, VerifyHeadersStream) {
+ QuicWriteBlockedList write_blocked_list;
+ write_blocked_list.RegisterStream(5, kV3HighestPriority);
+ write_blocked_list.RegisterStream(kHeadersStreamId, kV3HighestPriority);
+ write_blocked_list.AddStream(5);
+ write_blocked_list.AddStream(kHeadersStreamId);
+
+ EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams());
+ EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
+ EXPECT_TRUE(write_blocked_list.HasWriteBlockedDataStreams());
+ // In newer QUIC versions, there is a headers stream which is
+ // higher priority than data streams.
+ EXPECT_EQ(kHeadersStreamId, write_blocked_list.PopFront());
+ EXPECT_EQ(5u, write_blocked_list.PopFront());
+ EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams());
+ EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
+ EXPECT_FALSE(write_blocked_list.HasWriteBlockedDataStreams());
+}
+
+TEST(QuicWriteBlockedListTest, NoDuplicateEntries) {
+ // Test that QuicWriteBlockedList doesn't allow duplicate entries.
+ QuicWriteBlockedList write_blocked_list;
+
+ // Try to add a stream to the write blocked list multiple times at the same
+ // priority.
+ const QuicStreamId kBlockedId = kClientDataStreamId1;
+ write_blocked_list.RegisterStream(kBlockedId, kV3HighestPriority);
+ write_blocked_list.AddStream(kBlockedId);
+ write_blocked_list.AddStream(kBlockedId);
+ write_blocked_list.AddStream(kBlockedId);
+
+ // This should only result in one blocked stream being added.
+ EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams());
+ EXPECT_TRUE(write_blocked_list.HasWriteBlockedDataStreams());
+
+ // There should only be one stream to pop off the front.
+ EXPECT_EQ(kBlockedId, write_blocked_list.PopFront());
+ EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams());
+ EXPECT_FALSE(write_blocked_list.HasWriteBlockedDataStreams());
+}
+
+TEST(QuicWriteBlockedListTest, BatchingWrites) {
+ QuicWriteBlockedList write_blocked_list;
+
+ const QuicStreamId id1 = kClientDataStreamId1;
+ const QuicStreamId id2 = kClientDataStreamId2;
+ const QuicStreamId id3 = kClientDataStreamId2 + 2;
+ write_blocked_list.RegisterStream(id1, kV3LowestPriority);
+ write_blocked_list.RegisterStream(id2, kV3LowestPriority);
+ write_blocked_list.RegisterStream(id3, kV3HighestPriority);
+
+ write_blocked_list.AddStream(id1);
+ write_blocked_list.AddStream(id2);
+ EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams());
+
+ // The first stream we push back should stay at the front until 16k is
+ // written.
+ EXPECT_EQ(id1, write_blocked_list.PopFront());
+ write_blocked_list.UpdateBytesForStream(id1, 15999);
+ write_blocked_list.AddStream(id1);
+ EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams());
+ EXPECT_EQ(id1, write_blocked_list.PopFront());
+
+ // Once 16k is written the first stream will yield to the next.
+ write_blocked_list.UpdateBytesForStream(id1, 1);
+ write_blocked_list.AddStream(id1);
+ EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams());
+ EXPECT_EQ(id2, write_blocked_list.PopFront());
+
+ // Set the new stream to have written all but one byte.
+ write_blocked_list.UpdateBytesForStream(id2, 15999);
+ write_blocked_list.AddStream(id2);
+ EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams());
+
+ // Ensure higher priority streams are popped first.
+ write_blocked_list.AddStream(id3);
+ EXPECT_EQ(id3, write_blocked_list.PopFront());
+
+ // Higher priority streams will always be popped first, even if using their
+ // byte quota
+ write_blocked_list.UpdateBytesForStream(id3, 20000);
+ write_blocked_list.AddStream(id3);
+ EXPECT_EQ(id3, write_blocked_list.PopFront());
+
+ // Once the higher priority stream is out of the way, id2 will resume its 16k
+ // write, with only 1 byte remaining of its guaranteed write allocation.
+ EXPECT_EQ(id2, write_blocked_list.PopFront());
+ write_blocked_list.AddStream(id2);
+ write_blocked_list.UpdateBytesForStream(id2, 1);
+ write_blocked_list.AddStream(id2);
+ EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams());
+ EXPECT_EQ(id1, write_blocked_list.PopFront());
+}
+
+TEST(QuicWriteBlockedListTest, Ceding) {
+ QuicWriteBlockedList write_blocked_list;
+
+ write_blocked_list.RegisterStream(15, kV3HighestPriority);
+ write_blocked_list.RegisterStream(16, kV3HighestPriority);
+ write_blocked_list.RegisterStream(5, 5);
+ write_blocked_list.RegisterStream(4, 5);
+ write_blocked_list.RegisterStream(7, 7);
+ write_blocked_list.RegisterStream(kHeadersStreamId, kV3HighestPriority);
+ write_blocked_list.RegisterStream(kCryptoStreamId, kV3HighestPriority);
+
+ // When nothing is on the list, nothing yields.
+ EXPECT_FALSE(write_blocked_list.ShouldYield(5));
+
+ write_blocked_list.AddStream(5);
+ // 5 should not yield to itself.
+ EXPECT_FALSE(write_blocked_list.ShouldYield(5));
+ // 4 and 7 are equal or lower priority and should yield to 5.
+ EXPECT_TRUE(write_blocked_list.ShouldYield(4));
+ EXPECT_TRUE(write_blocked_list.ShouldYield(7));
+ // 15, headers and crypto should preempt 5.
+ EXPECT_FALSE(write_blocked_list.ShouldYield(15));
+ EXPECT_FALSE(write_blocked_list.ShouldYield(kHeadersStreamId));
+ EXPECT_FALSE(write_blocked_list.ShouldYield(kCryptoStreamId));
+
+ // Block a high priority stream.
+ write_blocked_list.AddStream(15);
+ // 16 should yield (same priority) but headers and crypto will still not.
+ EXPECT_TRUE(write_blocked_list.ShouldYield(16));
+ EXPECT_FALSE(write_blocked_list.ShouldYield(kHeadersStreamId));
+ EXPECT_FALSE(write_blocked_list.ShouldYield(kCryptoStreamId));
+
+ // Block the headers stream. All streams but crypto and headers should yield.
+ write_blocked_list.AddStream(kHeadersStreamId);
+ EXPECT_TRUE(write_blocked_list.ShouldYield(16));
+ EXPECT_TRUE(write_blocked_list.ShouldYield(15));
+ EXPECT_FALSE(write_blocked_list.ShouldYield(kHeadersStreamId));
+ EXPECT_FALSE(write_blocked_list.ShouldYield(kCryptoStreamId));
+
+ // Block the crypto stream. All streams but crypto should yield.
+ write_blocked_list.AddStream(kCryptoStreamId);
+ EXPECT_TRUE(write_blocked_list.ShouldYield(16));
+ EXPECT_TRUE(write_blocked_list.ShouldYield(15));
+ EXPECT_TRUE(write_blocked_list.ShouldYield(kHeadersStreamId));
+ EXPECT_FALSE(write_blocked_list.ShouldYield(kCryptoStreamId));
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/reliable_quic_stream.cc b/chromium/net/quic/core/reliable_quic_stream.cc
new file mode 100644
index 00000000000..740f16116a5
--- /dev/null
+++ b/chromium/net/quic/core/reliable_quic_stream.cc
@@ -0,0 +1,473 @@
+// 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/reliable_quic_stream.h"
+
+#include "base/logging.h"
+#include "net/quic/core/iovector.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_flow_controller.h"
+#include "net/quic/core/quic_session.h"
+#include "net/quic/core/quic_write_blocked_list.h"
+
+using base::StringPiece;
+using std::min;
+using std::string;
+
+namespace net {
+
+#define ENDPOINT \
+ (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ")
+
+namespace {
+
+struct iovec MakeIovec(StringPiece data) {
+ struct iovec iov = {const_cast<char*>(data.data()),
+ static_cast<size_t>(data.size())};
+ return iov;
+}
+
+size_t GetInitialStreamFlowControlWindowToSend(QuicSession* session) {
+ return session->config()->GetInitialStreamFlowControlWindowToSend();
+}
+
+size_t GetReceivedFlowControlWindow(QuicSession* session) {
+ if (session->config()->HasReceivedInitialStreamFlowControlWindowBytes()) {
+ return session->config()->ReceivedInitialStreamFlowControlWindowBytes();
+ }
+
+ return kMinimumFlowControlSendWindow;
+}
+
+} // namespace
+
+ReliableQuicStream::PendingData::PendingData(
+ string data_in,
+ QuicAckListenerInterface* ack_listener_in)
+ : data(std::move(data_in)), offset(0), ack_listener(ack_listener_in) {}
+
+ReliableQuicStream::PendingData::~PendingData() {}
+
+ReliableQuicStream::ReliableQuicStream(QuicStreamId id, QuicSession* session)
+ : queued_data_bytes_(0),
+ sequencer_(this, session->connection()->clock()),
+ id_(id),
+ session_(session),
+ stream_bytes_read_(0),
+ stream_bytes_written_(0),
+ stream_error_(QUIC_STREAM_NO_ERROR),
+ connection_error_(QUIC_NO_ERROR),
+ read_side_closed_(false),
+ write_side_closed_(false),
+ fin_buffered_(false),
+ fin_sent_(false),
+ fin_received_(false),
+ rst_sent_(false),
+ rst_received_(false),
+ perspective_(session_->perspective()),
+ flow_controller_(session_->connection(),
+ id_,
+ perspective_,
+ GetReceivedFlowControlWindow(session),
+ GetInitialStreamFlowControlWindowToSend(session),
+ session_->flow_controller()->auto_tune_receive_window()),
+ connection_flow_controller_(session_->flow_controller()),
+ stream_contributes_to_connection_flow_control_(true) {
+ SetFromConfig();
+}
+
+ReliableQuicStream::~ReliableQuicStream() {}
+
+void ReliableQuicStream::SetFromConfig() {}
+
+void ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
+ DCHECK_EQ(frame.stream_id, id_);
+
+ DCHECK(!(read_side_closed_ && write_side_closed_));
+
+ if (frame.fin) {
+ fin_received_ = true;
+ if (fin_sent_) {
+ session_->StreamDraining(id_);
+ }
+ }
+
+ if (read_side_closed_) {
+ DVLOG(1) << ENDPOINT << "Ignoring data in frame " << frame.stream_id;
+ // The subclass does not want to read data: blackhole the data.
+ return;
+ }
+
+ // This count includes duplicate data received.
+ size_t frame_payload_size = frame.data_length;
+ stream_bytes_read_ += frame_payload_size;
+
+ // Flow control is interested in tracking highest received offset.
+ // Only interested in received frames that carry data.
+ if (frame_payload_size > 0 &&
+ MaybeIncreaseHighestReceivedOffset(frame.offset + frame_payload_size)) {
+ // As the highest received offset has changed, check to see if this is a
+ // violation of flow control.
+ if (flow_controller_.FlowControlViolation() ||
+ connection_flow_controller_->FlowControlViolation()) {
+ CloseConnectionWithDetails(
+ QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
+ "Flow control violation after increasing offset");
+ return;
+ }
+ }
+
+ sequencer_.OnStreamFrame(frame);
+}
+
+int ReliableQuicStream::num_frames_received() const {
+ return sequencer_.num_frames_received();
+}
+
+int ReliableQuicStream::num_duplicate_frames_received() const {
+ return sequencer_.num_duplicate_frames_received();
+}
+
+void ReliableQuicStream::OnStreamReset(const QuicRstStreamFrame& frame) {
+ rst_received_ = true;
+ MaybeIncreaseHighestReceivedOffset(frame.byte_offset);
+
+ stream_error_ = frame.error_code;
+ CloseWriteSide();
+ CloseReadSide();
+}
+
+void ReliableQuicStream::OnConnectionClosed(QuicErrorCode error,
+ ConnectionCloseSource /*source*/) {
+ if (read_side_closed_ && write_side_closed_) {
+ return;
+ }
+ if (error != QUIC_NO_ERROR) {
+ stream_error_ = QUIC_STREAM_CONNECTION_ERROR;
+ connection_error_ = error;
+ }
+
+ CloseWriteSide();
+ CloseReadSide();
+}
+
+void ReliableQuicStream::OnFinRead() {
+ DCHECK(sequencer_.IsClosed());
+ // OnFinRead can be called due to a FIN flag in a headers block, so there may
+ // have been no OnStreamFrame call with a FIN in the frame.
+ fin_received_ = true;
+ // If fin_sent_ is true, then CloseWriteSide has already been called, and the
+ // stream will be destroyed by CloseReadSide, so don't need to call
+ // StreamDraining.
+ CloseReadSide();
+}
+
+void ReliableQuicStream::Reset(QuicRstStreamErrorCode error) {
+ stream_error_ = error;
+ // Sending a RstStream results in calling CloseStream.
+ session()->SendRstStream(id(), error, stream_bytes_written_);
+ rst_sent_ = true;
+}
+
+void ReliableQuicStream::CloseConnectionWithDetails(QuicErrorCode error,
+ const string& details) {
+ session()->connection()->CloseConnection(
+ error, details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+}
+
+void ReliableQuicStream::WriteOrBufferData(
+ StringPiece data,
+ bool fin,
+ QuicAckListenerInterface* ack_listener) {
+ if (data.empty() && !fin) {
+ QUIC_BUG << "data.empty() && !fin";
+ return;
+ }
+
+ if (fin_buffered_) {
+ QUIC_BUG << "Fin already buffered";
+ return;
+ }
+ if (write_side_closed_) {
+ DLOG(ERROR) << ENDPOINT << "Attempt to write when the write side is closed";
+ return;
+ }
+
+ QuicConsumedData consumed_data(0, false);
+ fin_buffered_ = fin;
+
+ if (queued_data_.empty()) {
+ struct iovec iov(MakeIovec(data));
+ consumed_data = WritevData(&iov, 1, fin, ack_listener);
+ DCHECK_LE(consumed_data.bytes_consumed, data.length());
+ }
+
+ // If there's unconsumed data or an unconsumed fin, queue it.
+ if (consumed_data.bytes_consumed < data.length() ||
+ (fin && !consumed_data.fin_consumed)) {
+ StringPiece remainder(data.substr(consumed_data.bytes_consumed));
+ queued_data_bytes_ += remainder.size();
+ queued_data_.emplace_back(remainder.as_string(), ack_listener);
+ }
+}
+
+void ReliableQuicStream::OnCanWrite() {
+ bool fin = false;
+ while (!queued_data_.empty()) {
+ PendingData* pending_data = &queued_data_.front();
+ QuicAckListenerInterface* ack_listener = pending_data->ack_listener.get();
+ if (queued_data_.size() == 1 && fin_buffered_) {
+ fin = true;
+ }
+ if (pending_data->offset > 0 &&
+ pending_data->offset >= pending_data->data.size()) {
+ // This should be impossible because offset tracks the amount of
+ // pending_data written thus far.
+ QUIC_BUG << "Pending offset is beyond available data. offset: "
+ << pending_data->offset << " vs: " << pending_data->data.size();
+ return;
+ }
+ size_t remaining_len = pending_data->data.size() - pending_data->offset;
+ struct iovec iov = {
+ const_cast<char*>(pending_data->data.data()) + pending_data->offset,
+ remaining_len};
+ QuicConsumedData consumed_data = WritevData(&iov, 1, fin, ack_listener);
+ queued_data_bytes_ -= consumed_data.bytes_consumed;
+ if (consumed_data.bytes_consumed == remaining_len &&
+ fin == consumed_data.fin_consumed) {
+ queued_data_.pop_front();
+ } else {
+ if (consumed_data.bytes_consumed > 0) {
+ pending_data->offset += consumed_data.bytes_consumed;
+ }
+ break;
+ }
+ }
+}
+
+void ReliableQuicStream::MaybeSendBlocked() {
+ flow_controller_.MaybeSendBlocked();
+ if (!stream_contributes_to_connection_flow_control_) {
+ return;
+ }
+ connection_flow_controller_->MaybeSendBlocked();
+ // If the stream is blocked by connection-level flow control but not by
+ // stream-level flow control, add the stream to the write blocked list so that
+ // the stream will be given a chance to write when a connection-level
+ // WINDOW_UPDATE arrives.
+ if (connection_flow_controller_->IsBlocked() &&
+ !flow_controller_.IsBlocked()) {
+ session_->MarkConnectionLevelWriteBlocked(id());
+ }
+}
+
+QuicConsumedData ReliableQuicStream::WritevData(
+ const struct iovec* iov,
+ int iov_count,
+ bool fin,
+ QuicAckListenerInterface* ack_listener) {
+ if (write_side_closed_) {
+ DLOG(ERROR) << ENDPOINT << "Attempt to write when the write side is closed";
+ return QuicConsumedData(0, false);
+ }
+
+ // How much data was provided.
+ size_t write_length = TotalIovecLength(iov, iov_count);
+
+ // A FIN with zero data payload should not be flow control blocked.
+ bool fin_with_zero_data = (fin && write_length == 0);
+
+ // How much data flow control permits to be written.
+ QuicByteCount send_window = flow_controller_.SendWindowSize();
+ if (stream_contributes_to_connection_flow_control_) {
+ send_window =
+ min(send_window, connection_flow_controller_->SendWindowSize());
+ }
+
+ if (session_->ShouldYield(id())) {
+ session_->MarkConnectionLevelWriteBlocked(id());
+ return QuicConsumedData(0, false);
+ }
+
+ if (send_window == 0 && !fin_with_zero_data) {
+ // Quick return if nothing can be sent.
+ MaybeSendBlocked();
+ return QuicConsumedData(0, false);
+ }
+
+ if (write_length > send_window) {
+ // Don't send the FIN unless all the data will be sent.
+ fin = false;
+
+ // Writing more data would be a violation of flow control.
+ write_length = static_cast<size_t>(send_window);
+ }
+
+ QuicConsumedData consumed_data =
+ WritevDataInner(QuicIOVector(iov, iov_count, write_length),
+ stream_bytes_written_, fin, ack_listener);
+ stream_bytes_written_ += consumed_data.bytes_consumed;
+
+ AddBytesSent(consumed_data.bytes_consumed);
+
+ // The write may have generated a write error causing this stream to be
+ // closed. If so, simply return without marking the stream write blocked.
+ if (write_side_closed_) {
+ return consumed_data;
+ }
+
+ if (consumed_data.bytes_consumed == write_length) {
+ if (!fin_with_zero_data) {
+ MaybeSendBlocked();
+ }
+ if (fin && consumed_data.fin_consumed) {
+ fin_sent_ = true;
+ if (fin_received_) {
+ session_->StreamDraining(id_);
+ }
+ CloseWriteSide();
+ } else if (fin && !consumed_data.fin_consumed) {
+ session_->MarkConnectionLevelWriteBlocked(id());
+ }
+ } else {
+ session_->MarkConnectionLevelWriteBlocked(id());
+ }
+ return consumed_data;
+}
+
+QuicConsumedData ReliableQuicStream::WritevDataInner(
+ QuicIOVector iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate) {
+ return session()->WritevData(this, id(), iov, offset, fin,
+ ack_notifier_delegate);
+}
+
+void ReliableQuicStream::CloseReadSide() {
+ if (read_side_closed_) {
+ return;
+ }
+ DVLOG(1) << ENDPOINT << "Done reading from stream " << id();
+
+ read_side_closed_ = true;
+ sequencer_.ReleaseBuffer();
+
+ if (write_side_closed_) {
+ DVLOG(1) << ENDPOINT << "Closing stream: " << id();
+ session_->CloseStream(id());
+ }
+}
+
+void ReliableQuicStream::CloseWriteSide() {
+ if (write_side_closed_) {
+ return;
+ }
+ DVLOG(1) << ENDPOINT << "Done writing to stream " << id();
+
+ write_side_closed_ = true;
+ if (read_side_closed_) {
+ DVLOG(1) << ENDPOINT << "Closing stream: " << id();
+ session_->CloseStream(id());
+ }
+}
+
+bool ReliableQuicStream::HasBufferedData() const {
+ return !queued_data_.empty();
+}
+
+QuicVersion ReliableQuicStream::version() const {
+ return session_->connection()->version();
+}
+
+void ReliableQuicStream::StopReading() {
+ DVLOG(1) << ENDPOINT << "Stop reading from stream " << id();
+ sequencer_.StopReading();
+}
+
+const IPEndPoint& ReliableQuicStream::PeerAddressOfLatestPacket() const {
+ return session_->connection()->last_packet_source_address();
+}
+
+void ReliableQuicStream::OnClose() {
+ CloseReadSide();
+ CloseWriteSide();
+
+ if (!fin_sent_ && !rst_sent_) {
+ // For flow control accounting, tell the peer how many bytes have been
+ // written on this stream before termination. Done here if needed, using a
+ // RST_STREAM frame.
+ DVLOG(1) << ENDPOINT << "Sending RST_STREAM in OnClose: " << id();
+ session_->SendRstStream(id(), QUIC_RST_ACKNOWLEDGEMENT,
+ stream_bytes_written_);
+ rst_sent_ = true;
+ }
+
+ // The stream is being closed and will not process any further incoming bytes.
+ // As there may be more bytes in flight, to ensure that both endpoints have
+ // the same connection level flow control state, mark all unreceived or
+ // buffered bytes as consumed.
+ QuicByteCount bytes_to_consume =
+ flow_controller_.highest_received_byte_offset() -
+ flow_controller_.bytes_consumed();
+ AddBytesConsumed(bytes_to_consume);
+}
+
+void ReliableQuicStream::OnWindowUpdateFrame(
+ const QuicWindowUpdateFrame& frame) {
+ if (flow_controller_.UpdateSendWindowOffset(frame.byte_offset)) {
+ // Writing can be done again!
+ // TODO(rjshade): This does not respect priorities (e.g. multiple
+ // outstanding POSTs are unblocked on arrival of
+ // SHLO with initial window).
+ // As long as the connection is not flow control blocked, write on!
+ OnCanWrite();
+ }
+}
+
+bool ReliableQuicStream::MaybeIncreaseHighestReceivedOffset(
+ QuicStreamOffset new_offset) {
+ uint64_t increment =
+ new_offset - flow_controller_.highest_received_byte_offset();
+ if (!flow_controller_.UpdateHighestReceivedOffset(new_offset)) {
+ return false;
+ }
+
+ // If |new_offset| increased the stream flow controller's highest received
+ // offset, increase the connection flow controller's value by the incremental
+ // difference.
+ if (stream_contributes_to_connection_flow_control_) {
+ connection_flow_controller_->UpdateHighestReceivedOffset(
+ connection_flow_controller_->highest_received_byte_offset() +
+ increment);
+ }
+ return true;
+}
+
+void ReliableQuicStream::AddBytesSent(QuicByteCount bytes) {
+ flow_controller_.AddBytesSent(bytes);
+ if (stream_contributes_to_connection_flow_control_) {
+ connection_flow_controller_->AddBytesSent(bytes);
+ }
+}
+
+void ReliableQuicStream::AddBytesConsumed(QuicByteCount bytes) {
+ // Only adjust stream level flow controller if still reading.
+ if (!read_side_closed_) {
+ flow_controller_.AddBytesConsumed(bytes);
+ }
+
+ if (stream_contributes_to_connection_flow_control_) {
+ connection_flow_controller_->AddBytesConsumed(bytes);
+ }
+}
+
+void ReliableQuicStream::UpdateSendWindowOffset(QuicStreamOffset new_window) {
+ if (flow_controller_.UpdateSendWindowOffset(new_window)) {
+ OnCanWrite();
+ }
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/reliable_quic_stream.h b/chromium/net/quic/core/reliable_quic_stream.h
new file mode 100644
index 00000000000..2122e866cbd
--- /dev/null
+++ b/chromium/net/quic/core/reliable_quic_stream.h
@@ -0,0 +1,311 @@
+// 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.
+//
+// The base class for client/server reliable streams.
+
+// It does not contain the entire interface needed by an application to interact
+// with a QUIC stream. Some parts of the interface must be obtained by
+// accessing the owning session object. A subclass of ReliableQuicStream
+// connects the object and the application that generates and consumes the data
+// of the stream.
+
+// The ReliableQuicStream object has a dependent QuicStreamSequencer object,
+// which is given the stream frames as they arrive, and provides stream data in
+// order by invoking ProcessRawData().
+
+#ifndef NET_QUIC_RELIABLE_QUIC_STREAM_H_
+#define NET_QUIC_RELIABLE_QUIC_STREAM_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <list>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
+#include "net/base/iovec.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_flow_controller.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_stream_sequencer.h"
+#include "net/quic/core/quic_types.h"
+
+namespace net {
+
+namespace test {
+class ReliableQuicStreamPeer;
+} // namespace test
+
+class QuicSession;
+
+class NET_EXPORT_PRIVATE ReliableQuicStream {
+ public:
+ ReliableQuicStream(QuicStreamId id, QuicSession* session);
+
+ virtual ~ReliableQuicStream();
+
+ // Not in use currently.
+ void SetFromConfig();
+
+ // Called by the session when a (potentially duplicate) stream frame has been
+ // received for this stream.
+ virtual void OnStreamFrame(const QuicStreamFrame& frame);
+
+ // Called by the session when the connection becomes writeable to allow the
+ // stream to write any pending data.
+ virtual void OnCanWrite();
+
+ // Called by the session just before the object is destroyed.
+ // The object should not be accessed after OnClose is called.
+ // Sends a RST_STREAM with code QUIC_RST_ACKNOWLEDGEMENT if neither a FIN nor
+ // a RST_STREAM has been sent.
+ virtual void OnClose();
+
+ // Called by the session when the endpoint receives a RST_STREAM from the
+ // peer.
+ virtual void OnStreamReset(const QuicRstStreamFrame& frame);
+
+ // Called by the session when the endpoint receives or sends a connection
+ // close, and should immediately close the stream.
+ virtual void OnConnectionClosed(QuicErrorCode error,
+ ConnectionCloseSource source);
+
+ // Called by the stream subclass after it has consumed the final incoming
+ // data.
+ void OnFinRead();
+
+ // Called when new data is available from the sequencer. Subclasses must
+ // actively retrieve the data using the sequencer's Readv() or
+ // GetReadableRegions() method.
+ virtual void OnDataAvailable() = 0;
+
+ // Called by the subclass or the sequencer to reset the stream from this
+ // end.
+ virtual void Reset(QuicRstStreamErrorCode error);
+
+ // Called by the subclass or the sequencer to close the entire connection from
+ // this end.
+ virtual void CloseConnectionWithDetails(QuicErrorCode error,
+ const std::string& details);
+
+ QuicStreamId id() const { return id_; }
+
+ QuicRstStreamErrorCode stream_error() const { return stream_error_; }
+ QuicErrorCode connection_error() const { return connection_error_; }
+
+ bool reading_stopped() const {
+ return sequencer_.ignore_read_data() || read_side_closed_;
+ }
+ bool write_side_closed() const { return write_side_closed_; }
+
+ bool rst_received() { return rst_received_; }
+ bool rst_sent() { return rst_sent_; }
+ bool fin_received() { return fin_received_; }
+ bool fin_sent() { return fin_sent_; }
+
+ uint64_t queued_data_bytes() const { return queued_data_bytes_; }
+
+ uint64_t stream_bytes_read() const { return stream_bytes_read_; }
+ uint64_t stream_bytes_written() const { return stream_bytes_written_; }
+
+ void set_fin_sent(bool fin_sent) { fin_sent_ = fin_sent; }
+ void set_fin_received(bool fin_received) { fin_received_ = fin_received; }
+ void set_rst_sent(bool rst_sent) { rst_sent_ = rst_sent; }
+
+ void set_rst_received(bool rst_received) { rst_received_ = rst_received; }
+ void set_stream_error(QuicRstStreamErrorCode error) { stream_error_ = error; }
+
+ // Adjust the flow control window according to new offset in |frame|.
+ virtual void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame);
+
+ // Used in Chrome.
+ int num_frames_received() const;
+ int num_duplicate_frames_received() const;
+
+ QuicFlowController* flow_controller() { return &flow_controller_; }
+
+ // Called when endpoint receives a frame which could increase the highest
+ // offset.
+ // Returns true if the highest offset did increase.
+ bool MaybeIncreaseHighestReceivedOffset(QuicStreamOffset new_offset);
+ // Called when bytes are sent to the peer.
+ void AddBytesSent(QuicByteCount bytes);
+ // Called by the stream sequencer as bytes are consumed from the buffer.
+ // If the receive window has dropped below the threshold, then send a
+ // WINDOW_UPDATE frame.
+ void AddBytesConsumed(QuicByteCount bytes);
+
+ // Updates the flow controller's send window offset and calls OnCanWrite if
+ // it was blocked before.
+ void UpdateSendWindowOffset(QuicStreamOffset new_offset);
+
+ // Returns true if the stream has received either a RST_STREAM or a FIN -
+ // either of which gives a definitive number of bytes which the peer has
+ // sent. If this is not true on deletion of the stream object, the session
+ // must keep track of the stream's byte offset until a definitive final value
+ // arrives.
+ bool HasFinalReceivedByteOffset() const {
+ return fin_received_ || rst_received_;
+ }
+
+ // Returns true if the stream has queued data waiting to write.
+ bool HasBufferedData() const;
+
+ // Returns the version of QUIC being used for this stream.
+ QuicVersion version() const;
+
+ bool fin_received() const { return fin_received_; }
+
+ // Sets the sequencer to consume all incoming data itself and not call
+ // OnDataAvailable().
+ // When the FIN is received, the stream will be notified automatically (via
+ // OnFinRead()) (which may happen during the call of StopReading()).
+ // TODO(dworley): There should be machinery to send a RST_STREAM/NO_ERROR and
+ // stop sending stream-level flow-control updates when this end sends FIN.
+ virtual void StopReading();
+
+ // Get peer IP of the lastest packet which connection is dealing/delt with.
+ virtual const IPEndPoint& PeerAddressOfLatestPacket() const;
+
+ protected:
+ // Sends as much of 'data' to the connection as the connection will consume,
+ // and then buffers any remaining data in queued_data_.
+ // If fin is true: if it is immediately passed on to the session,
+ // write_side_closed() becomes true, otherwise fin_buffered_ becomes true.
+ void WriteOrBufferData(base::StringPiece data,
+ bool fin,
+ QuicAckListenerInterface* ack_listener);
+
+ // Sends as many bytes in the first |count| buffers of |iov| to the connection
+ // as the connection will consume.
+ // If |ack_listener| is provided, then it will be notified once all
+ // the ACKs for this write have been received.
+ // Returns the number of bytes consumed by the connection.
+ QuicConsumedData WritevData(const struct iovec* iov,
+ int iov_count,
+ bool fin,
+ QuicAckListenerInterface* ack_listener);
+
+ // Allows override of the session level writev, for the force HOL
+ // blocking experiment.
+ virtual QuicConsumedData WritevDataInner(
+ QuicIOVector iov,
+ QuicStreamOffset offset,
+ bool fin,
+ QuicAckListenerInterface* ack_notifier_delegate);
+
+ // Close the write side of the socket. Further writes will fail.
+ // Can be called by the subclass or internally.
+ // Does not send a FIN. May cause the stream to be closed.
+ virtual void CloseWriteSide();
+
+ bool fin_buffered() const { return fin_buffered_; }
+
+ const QuicSession* session() const { return session_; }
+ QuicSession* session() { return session_; }
+
+ const QuicStreamSequencer* sequencer() const { return &sequencer_; }
+ QuicStreamSequencer* sequencer() { return &sequencer_; }
+
+ void DisableConnectionFlowControlForThisStream() {
+ stream_contributes_to_connection_flow_control_ = false;
+ }
+
+ private:
+ friend class test::ReliableQuicStreamPeer;
+ friend class QuicStreamUtils;
+
+ // Close the read side of the socket. May cause the stream to be closed.
+ // Subclasses and consumers should use StopReading to terminate reading early.
+ void CloseReadSide();
+
+ // Subclasses and consumers should use reading_stopped.
+ bool read_side_closed() const { return read_side_closed_; }
+
+ struct PendingData {
+ PendingData(std::string data_in, QuicAckListenerInterface* ack_listener_in);
+ ~PendingData();
+
+ // Pending data to be written.
+ std::string data;
+ // Index of the first byte in data still to be written.
+ size_t offset;
+ // AckListener that should be notified when the pending data is acked.
+ // Can be nullptr.
+ scoped_refptr<QuicAckListenerInterface> ack_listener;
+ };
+
+ // Calls MaybeSendBlocked on the stream's flow controller and the connection
+ // level flow controller. If the stream is flow control blocked by the
+ // connection-level flow controller but not by the stream-level flow
+ // controller, marks this stream as connection-level write blocked.
+ void MaybeSendBlocked();
+
+ std::list<PendingData> queued_data_;
+ // How many bytes are queued?
+ uint64_t queued_data_bytes_;
+
+ QuicStreamSequencer sequencer_;
+ QuicStreamId id_;
+ // Pointer to the owning QuicSession object.
+ QuicSession* session_;
+ // Bytes read and written refer to payload bytes only: they do not include
+ // framing, encryption overhead etc.
+ uint64_t stream_bytes_read_;
+ uint64_t stream_bytes_written_;
+
+ // Stream error code received from a RstStreamFrame or error code sent by the
+ // visitor or sequencer in the RstStreamFrame.
+ QuicRstStreamErrorCode stream_error_;
+ // Connection error code due to which the stream was closed. |stream_error_|
+ // is set to |QUIC_STREAM_CONNECTION_ERROR| when this happens and consumers
+ // should check |connection_error_|.
+ QuicErrorCode connection_error_;
+
+ // True if the read side is closed and further frames should be rejected.
+ bool read_side_closed_;
+ // True if the write side is closed, and further writes should fail.
+ bool write_side_closed_;
+
+ // True if the subclass has written a FIN with WriteOrBufferData, but it was
+ // buffered in queued_data_ rather than being sent to the session.
+ bool fin_buffered_;
+ // True if a FIN has been sent to the session.
+ bool fin_sent_;
+
+ // True if this stream has received (and the sequencer has accepted) a
+ // StreamFrame with the FIN set.
+ bool fin_received_;
+
+ // True if an RST_STREAM has been sent to the session.
+ // In combination with fin_sent_, used to ensure that a FIN and/or a
+ // RST_STREAM is always sent to terminate the stream.
+ bool rst_sent_;
+
+ // True if this stream has received a RST_STREAM frame.
+ bool rst_received_;
+
+ // Tracks if the session this stream is running under was created by a
+ // server or a client.
+ Perspective perspective_;
+
+ QuicFlowController flow_controller_;
+
+ // The connection level flow controller. Not owned.
+ QuicFlowController* connection_flow_controller_;
+
+ // Special streams, such as the crypto and headers streams, do not respect
+ // connection level flow control limits (but are stream level flow control
+ // limited).
+ bool stream_contributes_to_connection_flow_control_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReliableQuicStream);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_RELIABLE_QUIC_STREAM_H_
diff --git a/chromium/net/quic/core/reliable_quic_stream_test.cc b/chromium/net/quic/core/reliable_quic_stream_test.cc
new file mode 100644
index 00000000000..ceeee843738
--- /dev/null
+++ b/chromium/net/quic/core/reliable_quic_stream_test.cc
@@ -0,0 +1,716 @@
+// 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/reliable_quic_stream.h"
+
+#include <memory>
+
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_flags.h"
+#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/test_tools/quic_config_peer.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
+#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_test_utils.h"
+#include "net/quic/test_tools/reliable_quic_stream_peer.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gmock_mutant.h"
+
+using base::StringPiece;
+using std::min;
+using std::string;
+using testing::AnyNumber;
+using testing::AtLeast;
+using testing::CreateFunctor;
+using testing::InSequence;
+using testing::Invoke;
+using testing::DoAll;
+using testing::Return;
+using testing::StrictMock;
+using testing::WithArgs;
+using testing::_;
+
+namespace net {
+namespace test {
+namespace {
+
+const char kData1[] = "FooAndBar";
+const char kData2[] = "EepAndBaz";
+const size_t kDataLen = 9;
+const bool kShouldProcessData = true;
+const bool kShouldNotProcessData = false;
+
+class TestStream : public ReliableQuicStream {
+ public:
+ TestStream(QuicStreamId id, QuicSession* session, bool should_process_data)
+ : ReliableQuicStream(id, session),
+ should_process_data_(should_process_data) {}
+
+ void OnDataAvailable() override {}
+
+ uint32_t ProcessRawData(const char* data, uint32_t data_len) {
+ EXPECT_NE(0u, data_len);
+ DVLOG(1) << "ProcessData data_len: " << data_len;
+ data_ += string(data, data_len);
+ return should_process_data_ ? data_len : 0;
+ }
+
+ using ReliableQuicStream::WriteOrBufferData;
+ using ReliableQuicStream::CloseWriteSide;
+ using ReliableQuicStream::OnClose;
+
+ private:
+ bool should_process_data_;
+ string data_;
+};
+
+class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> {
+ public:
+ ReliableQuicStreamTest()
+ : initial_flow_control_window_bytes_(kMaxPacketSize),
+ zero_(QuicTime::Delta::Zero()),
+ supported_versions_(AllSupportedVersions()) {
+ headers_[":host"] = "www.google.com";
+ headers_[":path"] = "/index.hml";
+ headers_[":scheme"] = "https";
+ headers_["cookie"] =
+ "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; "
+ "__utmc=160408618; "
+ "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX"
+ "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX"
+ "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT"
+ "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0"
+ "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh"
+ "1zFMi5vzcns38-8_Sns; "
+ "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-"
+ "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339"
+ "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c"
+ "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%"
+ "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4"
+ "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1"
+ "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP"
+ "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6"
+ "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b"
+ "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6"
+ "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG"
+ "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk"
+ "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn"
+ "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
+ "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
+ }
+
+ void Initialize(bool stream_should_process_data) {
+ connection_ = new StrictMock<MockQuicConnection>(
+ &helper_, &alarm_factory_, Perspective::IS_SERVER, supported_versions_);
+ session_.reset(new StrictMock<MockQuicSession>(connection_));
+
+ // New streams rely on having the peer's flow control receive window
+ // negotiated in the config.
+ QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(
+ session_->config(), initial_flow_control_window_bytes_);
+
+ stream_ = new TestStream(kTestStreamId, session_.get(),
+ stream_should_process_data);
+ // session_ now owns stream_.
+ session_->ActivateStream(stream_);
+ // Ignore resetting when session_ is terminated.
+ EXPECT_CALL(*session_, SendRstStream(kTestStreamId, _, _))
+ .Times(AnyNumber());
+ write_blocked_list_ =
+ QuicSessionPeer::GetWriteBlockedStreams(session_.get());
+ write_blocked_list_->RegisterStream(kTestStreamId, kV3HighestPriority);
+ }
+
+ bool fin_sent() { return ReliableQuicStreamPeer::FinSent(stream_); }
+ bool rst_sent() { return ReliableQuicStreamPeer::RstSent(stream_); }
+
+ void set_initial_flow_control_window_bytes(uint32_t val) {
+ initial_flow_control_window_bytes_ = val;
+ }
+
+ bool HasWriteBlockedStreams() {
+ return write_blocked_list_->HasWriteBlockedCryptoOrHeadersStream() ||
+ write_blocked_list_->HasWriteBlockedDataStreams();
+ }
+
+ QuicConsumedData CloseStreamOnWriteError(
+ ReliableQuicStream* /*stream*/,
+ QuicStreamId id,
+ QuicIOVector /*iov*/,
+ QuicStreamOffset /*offset*/,
+ bool /*fin*/,
+ QuicAckListenerInterface* /*ack_notifier_delegate*/) {
+ session_->CloseStream(id);
+ return QuicConsumedData(1, false);
+ }
+
+ protected:
+ MockQuicConnectionHelper helper_;
+ MockAlarmFactory alarm_factory_;
+ MockQuicConnection* connection_;
+ std::unique_ptr<MockQuicSession> session_;
+ TestStream* stream_;
+ SpdyHeaderBlock headers_;
+ QuicWriteBlockedList* write_blocked_list_;
+ uint32_t initial_flow_control_window_bytes_;
+ QuicTime::Delta zero_;
+ QuicVersionVector supported_versions_;
+ const QuicStreamId kTestStreamId = 5u;
+};
+
+TEST_F(ReliableQuicStreamTest, WriteAllData) {
+ Initialize(kShouldProcessData);
+
+ size_t length =
+ 1 + QuicPacketCreator::StreamFramePacketOverhead(
+ connection_->version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId, !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER, 0u);
+ connection_->SetMaxPacketLength(length);
+
+ EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(kDataLen, true)));
+ stream_->WriteOrBufferData(kData1, false, nullptr);
+ EXPECT_FALSE(HasWriteBlockedStreams());
+}
+
+TEST_F(ReliableQuicStreamTest, NoBlockingIfNoDataOrFin) {
+ Initialize(kShouldProcessData);
+
+ // Write no data and no fin. If we consume nothing we should not be write
+ // blocked.
+ EXPECT_QUIC_BUG(stream_->WriteOrBufferData(StringPiece(), false, nullptr),
+ "");
+ EXPECT_FALSE(HasWriteBlockedStreams());
+}
+
+TEST_F(ReliableQuicStreamTest, BlockIfOnlySomeDataConsumed) {
+ Initialize(kShouldProcessData);
+
+ // 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)));
+ stream_->WriteOrBufferData(StringPiece(kData1, 2), false, nullptr);
+ ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
+ EXPECT_EQ(1u, stream_->queued_data_bytes());
+}
+
+TEST_F(ReliableQuicStreamTest, BlockIfFinNotConsumedWithData) {
+ Initialize(kShouldProcessData);
+
+ // Write some data and no fin. If we consume all the data but not the fin,
+ // we should be write blocked because the fin was not consumed.
+ // (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)));
+ stream_->WriteOrBufferData(StringPiece(kData1, 2), true, nullptr);
+ ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
+}
+
+TEST_F(ReliableQuicStreamTest, BlockIfSoloFinNotConsumed) {
+ Initialize(kShouldProcessData);
+
+ // Write no data and a fin. If we consume nothing we should be write blocked,
+ // as the fin was not consumed.
+ EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(0, false)));
+ stream_->WriteOrBufferData(StringPiece(), true, nullptr);
+ ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
+}
+
+TEST_F(ReliableQuicStreamTest, CloseOnPartialWrite) {
+ Initialize(kShouldProcessData);
+
+ // Write some data and no fin. However, while writing the data
+ // close the stream and verify that MarkConnectionLevelWriteBlocked does not
+ // crash with an unknown stream.
+ EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
+ .WillOnce(Invoke(this, &ReliableQuicStreamTest::CloseStreamOnWriteError));
+ stream_->WriteOrBufferData(StringPiece(kData1, 2), false, nullptr);
+ ASSERT_EQ(0u, write_blocked_list_->NumBlockedStreams());
+}
+
+TEST_F(ReliableQuicStreamTest, WriteOrBufferData) {
+ Initialize(kShouldProcessData);
+
+ EXPECT_FALSE(HasWriteBlockedStreams());
+ size_t length =
+ 1 + QuicPacketCreator::StreamFramePacketOverhead(
+ connection_->version(), PACKET_8BYTE_CONNECTION_ID,
+ !kIncludeVersion, !kIncludePathId, !kIncludeDiversificationNonce,
+ PACKET_6BYTE_PACKET_NUMBER, 0u);
+ connection_->SetMaxPacketLength(length);
+
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(kDataLen - 1, false)));
+ stream_->WriteOrBufferData(kData1, false, nullptr);
+ EXPECT_TRUE(HasWriteBlockedStreams());
+
+ // Queue a bytes_consumed write.
+ stream_->WriteOrBufferData(kData2, false, nullptr);
+
+ // Make sure we get the tail of the first write followed by the bytes_consumed
+ InSequence s;
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(1, false)));
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(kDataLen - 2, false)));
+ stream_->OnCanWrite();
+
+ // And finally the end of the bytes_consumed.
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(2, true)));
+ stream_->OnCanWrite();
+}
+
+TEST_F(ReliableQuicStreamTest, ConnectionCloseAfterStreamClose) {
+ Initialize(kShouldProcessData);
+
+ ReliableQuicStreamPeer::CloseReadSide(stream_);
+ stream_->CloseWriteSide();
+ EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error());
+ EXPECT_EQ(QUIC_NO_ERROR, stream_->connection_error());
+ stream_->OnConnectionClosed(QUIC_INTERNAL_ERROR,
+ ConnectionCloseSource::FROM_SELF);
+ EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error());
+ EXPECT_EQ(QUIC_NO_ERROR, stream_->connection_error());
+}
+
+TEST_F(ReliableQuicStreamTest, RstAlwaysSentIfNoFinSent) {
+ // For flow control accounting, a stream must send either a FIN or a RST frame
+ // before termination.
+ // Test that if no FIN has been sent, we send a RST.
+
+ Initialize(kShouldProcessData);
+ EXPECT_FALSE(fin_sent());
+ EXPECT_FALSE(rst_sent());
+
+ // Write some data, with no FIN.
+ EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(1, false)));
+ stream_->WriteOrBufferData(StringPiece(kData1, 1), false, nullptr);
+ EXPECT_FALSE(fin_sent());
+ EXPECT_FALSE(rst_sent());
+
+ // Now close the stream, and expect that we send a RST.
+ EXPECT_CALL(*session_, SendRstStream(_, _, _));
+ stream_->OnClose();
+ EXPECT_FALSE(fin_sent());
+ EXPECT_TRUE(rst_sent());
+}
+
+TEST_F(ReliableQuicStreamTest, RstNotSentIfFinSent) {
+ // For flow control accounting, a stream must send either a FIN or a RST frame
+ // before termination.
+ // Test that if a FIN has been sent, we don't also send a RST.
+
+ Initialize(kShouldProcessData);
+ EXPECT_FALSE(fin_sent());
+ EXPECT_FALSE(rst_sent());
+
+ // Write some data, with FIN.
+ EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(1, true)));
+ stream_->WriteOrBufferData(StringPiece(kData1, 1), true, nullptr);
+ EXPECT_TRUE(fin_sent());
+ EXPECT_FALSE(rst_sent());
+
+ // Now close the stream, and expect that we do not send a RST.
+ stream_->OnClose();
+ EXPECT_TRUE(fin_sent());
+ EXPECT_FALSE(rst_sent());
+}
+
+TEST_F(ReliableQuicStreamTest, OnlySendOneRst) {
+ // For flow control accounting, a stream must send either a FIN or a RST frame
+ // before termination.
+ // Test that if a stream sends a RST, it doesn't send an additional RST during
+ // OnClose() (this shouldn't be harmful, but we shouldn't do it anyway...)
+
+ Initialize(kShouldProcessData);
+ EXPECT_FALSE(fin_sent());
+ EXPECT_FALSE(rst_sent());
+
+ // Reset the stream.
+ const int expected_resets = 1;
+ EXPECT_CALL(*session_, SendRstStream(_, _, _)).Times(expected_resets);
+ stream_->Reset(QUIC_STREAM_CANCELLED);
+ EXPECT_FALSE(fin_sent());
+ EXPECT_TRUE(rst_sent());
+
+ // Now close the stream (any further resets being sent would break the
+ // expectation above).
+ stream_->OnClose();
+ EXPECT_FALSE(fin_sent());
+ EXPECT_TRUE(rst_sent());
+}
+
+TEST_F(ReliableQuicStreamTest, StreamFlowControlMultipleWindowUpdates) {
+ set_initial_flow_control_window_bytes(1000);
+
+ Initialize(kShouldProcessData);
+
+ // If we receive multiple WINDOW_UPDATES (potentially out of order), then we
+ // want to make sure we latch the largest offset we see.
+
+ // Initially should be default.
+ EXPECT_EQ(
+ initial_flow_control_window_bytes_,
+ QuicFlowControllerPeer::SendWindowOffset(stream_->flow_controller()));
+
+ // Check a single WINDOW_UPDATE results in correct offset.
+ QuicWindowUpdateFrame window_update_1(stream_->id(), 1234);
+ stream_->OnWindowUpdateFrame(window_update_1);
+ EXPECT_EQ(
+ window_update_1.byte_offset,
+ QuicFlowControllerPeer::SendWindowOffset(stream_->flow_controller()));
+
+ // Now send a few more WINDOW_UPDATES and make sure that only the largest is
+ // remembered.
+ QuicWindowUpdateFrame window_update_2(stream_->id(), 1);
+ QuicWindowUpdateFrame window_update_3(stream_->id(), 9999);
+ QuicWindowUpdateFrame window_update_4(stream_->id(), 5678);
+ stream_->OnWindowUpdateFrame(window_update_2);
+ stream_->OnWindowUpdateFrame(window_update_3);
+ stream_->OnWindowUpdateFrame(window_update_4);
+ EXPECT_EQ(
+ window_update_3.byte_offset,
+ QuicFlowControllerPeer::SendWindowOffset(stream_->flow_controller()));
+}
+
+// TODO(ianswett): It's not clear this method is still needed now that
+// ProxyAckNotifierDelegate has been removed.
+void SaveAckListener(scoped_refptr<QuicAckListenerInterface>* listener_out,
+ QuicAckListenerInterface* listener) {
+ *listener_out = (listener);
+}
+
+TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithQuicAckNotifier) {
+ Initialize(kShouldProcessData);
+
+ scoped_refptr<MockAckListener> delegate(new StrictMock<MockAckListener>);
+
+ const int kDataSize = 16 * 1024;
+ const string kData(kDataSize, 'a');
+
+ const int kFirstWriteSize = 100;
+ const int kSecondWriteSize = 50;
+ const int kLastWriteSize = kDataSize - kFirstWriteSize - kSecondWriteSize;
+
+ // Set a large flow control send window so this doesn't interfere with test.
+ stream_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
+ session_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
+
+ scoped_refptr<QuicAckListenerInterface> ack_listener;
+
+ EXPECT_CALL(*session_, WritevData(_, kTestStreamId, _, _, _, _))
+ .WillOnce(DoAll(
+ WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &ack_listener))),
+ Return(QuicConsumedData(kFirstWriteSize, false))));
+ stream_->WriteOrBufferData(kData, false, delegate.get());
+ EXPECT_TRUE(HasWriteBlockedStreams());
+
+ EXPECT_CALL(*session_,
+ WritevData(stream_, kTestStreamId, _, _, _, ack_listener.get()))
+ .WillOnce(Return(QuicConsumedData(kSecondWriteSize, false)));
+ stream_->OnCanWrite();
+
+ // No ack expected for an empty write.
+ EXPECT_CALL(*session_,
+ WritevData(stream_, kTestStreamId, _, _, _, ack_listener.get()))
+ .WillOnce(Return(QuicConsumedData(0, false)));
+ stream_->OnCanWrite();
+
+ EXPECT_CALL(*session_,
+ WritevData(stream_, kTestStreamId, _, _, _, ack_listener.get()))
+ .WillOnce(Return(QuicConsumedData(kLastWriteSize, false)));
+ stream_->OnCanWrite();
+}
+
+// Verify delegate behavior when packets are acked before the WritevData call
+// that sends out the last byte.
+TEST_F(ReliableQuicStreamTest, WriteOrBufferDataAckNotificationBeforeFlush) {
+ Initialize(kShouldProcessData);
+
+ scoped_refptr<MockAckListener> ack_listener(new StrictMock<MockAckListener>);
+
+ const int kDataSize = 16 * 1024;
+ const string kData(kDataSize, 'a');
+
+ const int kInitialWriteSize = 100;
+
+ // Set a large flow control send window so this doesn't interfere with test.
+ stream_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
+ session_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
+
+ scoped_refptr<QuicAckListenerInterface> proxy_delegate;
+
+ EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
+ .WillOnce(DoAll(
+ WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))),
+ Return(QuicConsumedData(kInitialWriteSize, false))));
+ stream_->WriteOrBufferData(kData, false, ack_listener.get());
+ EXPECT_TRUE(HasWriteBlockedStreams());
+
+ EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
+ .WillOnce(DoAll(
+ WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))),
+ Return(QuicConsumedData(kDataSize - kInitialWriteSize, false))));
+ stream_->OnCanWrite();
+}
+
+// Verify delegate behavior when WriteOrBufferData does not buffer.
+TEST_F(ReliableQuicStreamTest, WriteAndBufferDataWithAckNotiferNoBuffer) {
+ Initialize(kShouldProcessData);
+
+ scoped_refptr<MockAckListener> delegate(new StrictMock<MockAckListener>);
+
+ scoped_refptr<QuicAckListenerInterface> proxy_delegate;
+
+ EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
+ .WillOnce(DoAll(
+ WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))),
+ Return(QuicConsumedData(kDataLen, true))));
+ stream_->WriteOrBufferData(kData1, true, delegate.get());
+ EXPECT_FALSE(HasWriteBlockedStreams());
+}
+
+// Verify delegate behavior when WriteOrBufferData buffers all the data.
+TEST_F(ReliableQuicStreamTest, BufferOnWriteAndBufferDataWithAckNotifer) {
+ Initialize(kShouldProcessData);
+
+ scoped_refptr<MockAckListener> delegate(new StrictMock<MockAckListener>);
+
+ scoped_refptr<QuicAckListenerInterface> proxy_delegate;
+
+ EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(0, false)));
+ stream_->WriteOrBufferData(kData1, true, delegate.get());
+ EXPECT_TRUE(HasWriteBlockedStreams());
+
+ EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
+ .WillOnce(DoAll(
+ WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))),
+ Return(QuicConsumedData(kDataLen, true))));
+ stream_->OnCanWrite();
+}
+
+// Verify delegate behavior when WriteOrBufferData when the FIN is
+// sent out in a different packet.
+TEST_F(ReliableQuicStreamTest, WriteAndBufferDataWithAckNotiferOnlyFinRemains) {
+ Initialize(kShouldProcessData);
+
+ scoped_refptr<MockAckListener> delegate(new StrictMock<MockAckListener>);
+
+ scoped_refptr<QuicAckListenerInterface> proxy_delegate;
+
+ EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
+ .WillOnce(DoAll(
+ WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))),
+ Return(QuicConsumedData(kDataLen, false))));
+ stream_->WriteOrBufferData(kData1, true, delegate.get());
+ EXPECT_TRUE(HasWriteBlockedStreams());
+
+ EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
+ .WillOnce(DoAll(
+ WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))),
+ Return(QuicConsumedData(0, true))));
+ stream_->OnCanWrite();
+}
+
+// Verify that when we receive a packet which violates flow control (i.e. sends
+// too much data on the stream) that the stream sequencer never sees this frame,
+// as we check for violation and close the connection early.
+TEST_F(ReliableQuicStreamTest,
+ StreamSequencerNeverSeesPacketsViolatingFlowControl) {
+ Initialize(kShouldProcessData);
+
+ // Receive a stream frame that violates flow control: the byte offset is
+ // higher than the receive window offset.
+ QuicStreamFrame frame(stream_->id(), false,
+ kInitialSessionFlowControlWindowForTest + 1,
+ StringPiece("."));
+ EXPECT_GT(frame.offset, QuicFlowControllerPeer::ReceiveWindowOffset(
+ stream_->flow_controller()));
+
+ // Stream should not accept the frame, and the connection should be closed.
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _));
+ stream_->OnStreamFrame(frame);
+}
+
+// Verify that after the consumer calls StopReading(), the stream still sends
+// flow control updates.
+TEST_F(ReliableQuicStreamTest, StopReadingSendsFlowControl) {
+ Initialize(kShouldProcessData);
+
+ stream_->StopReading();
+
+ // Connection should not get terminated due to flow control errors.
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _))
+ .Times(0);
+ EXPECT_CALL(*connection_, SendWindowUpdate(_, _)).Times(AtLeast(1));
+
+ string data(1000, 'x');
+ for (QuicStreamOffset offset = 0;
+ offset < 2 * kInitialStreamFlowControlWindowForTest;
+ offset += data.length()) {
+ QuicStreamFrame frame(stream_->id(), false, offset, data);
+ stream_->OnStreamFrame(frame);
+ }
+ EXPECT_LT(
+ kInitialStreamFlowControlWindowForTest,
+ QuicFlowControllerPeer::ReceiveWindowOffset(stream_->flow_controller()));
+}
+
+TEST_F(ReliableQuicStreamTest, FinalByteOffsetFromFin) {
+ Initialize(kShouldProcessData);
+
+ EXPECT_FALSE(stream_->HasFinalReceivedByteOffset());
+
+ QuicStreamFrame stream_frame_no_fin(stream_->id(), false, 1234,
+ StringPiece("."));
+ stream_->OnStreamFrame(stream_frame_no_fin);
+ EXPECT_FALSE(stream_->HasFinalReceivedByteOffset());
+
+ QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234,
+ StringPiece("."));
+ stream_->OnStreamFrame(stream_frame_with_fin);
+ EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
+}
+
+TEST_F(ReliableQuicStreamTest, FinalByteOffsetFromRst) {
+ Initialize(kShouldProcessData);
+
+ EXPECT_FALSE(stream_->HasFinalReceivedByteOffset());
+ QuicRstStreamFrame rst_frame(stream_->id(), QUIC_STREAM_CANCELLED, 1234);
+ stream_->OnStreamReset(rst_frame);
+ EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
+}
+
+TEST_F(ReliableQuicStreamTest, FinalByteOffsetFromZeroLengthStreamFrame) {
+ // When receiving Trailers, an empty stream frame is created with the FIN set,
+ // and is passed to OnStreamFrame. The Trailers may be sent in advance of
+ // queued body bytes being sent, and thus the final byte offset may exceed
+ // current flow control limits. Flow control should only be concerned with
+ // data that has actually been sent/received, so verify that flow control
+ // ignores such a stream frame.
+ Initialize(kShouldProcessData);
+
+ EXPECT_FALSE(stream_->HasFinalReceivedByteOffset());
+ const QuicStreamOffset kByteOffsetExceedingFlowControlWindow =
+ kInitialSessionFlowControlWindowForTest + 1;
+ const QuicStreamOffset current_stream_flow_control_offset =
+ QuicFlowControllerPeer::ReceiveWindowOffset(stream_->flow_controller());
+ const QuicStreamOffset current_connection_flow_control_offset =
+ QuicFlowControllerPeer::ReceiveWindowOffset(session_->flow_controller());
+ ASSERT_GT(kByteOffsetExceedingFlowControlWindow,
+ current_stream_flow_control_offset);
+ ASSERT_GT(kByteOffsetExceedingFlowControlWindow,
+ current_connection_flow_control_offset);
+ QuicStreamFrame zero_length_stream_frame_with_fin(
+ stream_->id(), /*fin=*/true, kByteOffsetExceedingFlowControlWindow,
+ StringPiece());
+ EXPECT_EQ(0, zero_length_stream_frame_with_fin.data_length);
+
+ EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
+ stream_->OnStreamFrame(zero_length_stream_frame_with_fin);
+ EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
+
+ // The flow control receive offset values should not have changed.
+ EXPECT_EQ(
+ current_stream_flow_control_offset,
+ QuicFlowControllerPeer::ReceiveWindowOffset(stream_->flow_controller()));
+ EXPECT_EQ(
+ current_connection_flow_control_offset,
+ QuicFlowControllerPeer::ReceiveWindowOffset(session_->flow_controller()));
+}
+
+TEST_F(ReliableQuicStreamTest, SetDrainingIncomingOutgoing) {
+ // Don't have incoming data consumed.
+ Initialize(kShouldNotProcessData);
+
+ // Incoming data with FIN.
+ QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234,
+ StringPiece("."));
+ stream_->OnStreamFrame(stream_frame_with_fin);
+ // The FIN has been received but not consumed.
+ EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
+ EXPECT_FALSE(ReliableQuicStreamPeer::read_side_closed(stream_));
+ EXPECT_FALSE(stream_->reading_stopped());
+
+ EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
+
+ // Outgoing data with FIN.
+ EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(2, true)));
+ stream_->WriteOrBufferData(StringPiece(kData1, 2), true, nullptr);
+ EXPECT_TRUE(stream_->write_side_closed());
+
+ EXPECT_EQ(1u, QuicSessionPeer::GetDrainingStreams(session_.get())
+ ->count(kTestStreamId));
+ EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
+}
+
+TEST_F(ReliableQuicStreamTest, SetDrainingOutgoingIncoming) {
+ // Don't have incoming data consumed.
+ Initialize(kShouldNotProcessData);
+
+ // Outgoing data with FIN.
+ EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
+ .WillOnce(Return(QuicConsumedData(2, true)));
+ stream_->WriteOrBufferData(StringPiece(kData1, 2), true, nullptr);
+ EXPECT_TRUE(stream_->write_side_closed());
+
+ EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
+
+ // Incoming data with FIN.
+ QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234,
+ StringPiece("."));
+ stream_->OnStreamFrame(stream_frame_with_fin);
+ // The FIN has been received but not consumed.
+ EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
+ EXPECT_FALSE(ReliableQuicStreamPeer::read_side_closed(stream_));
+ EXPECT_FALSE(stream_->reading_stopped());
+
+ EXPECT_EQ(1u, QuicSessionPeer::GetDrainingStreams(session_.get())
+ ->count(kTestStreamId));
+ EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
+}
+
+TEST_F(ReliableQuicStreamTest, EarlyResponseFinHandling) {
+ // Verify that if the server completes the response before reading the end of
+ // the request, the received FIN is recorded.
+
+ Initialize(kShouldProcessData);
+ EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
+ EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
+ .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
+
+ // Receive data for the request.
+ QuicStreamFrame frame1(stream_->id(), false, 0, StringPiece("Start"));
+ stream_->OnStreamFrame(frame1);
+ // When QuicSimpleServerStream sends the response, it calls
+ // ReliableQuicStream::CloseReadSide() first.
+ ReliableQuicStreamPeer::CloseReadSide(stream_);
+ // Send data and FIN for the response.
+ stream_->WriteOrBufferData(kData1, false, nullptr);
+ EXPECT_TRUE(ReliableQuicStreamPeer::read_side_closed(stream_));
+ // Receive remaining data and FIN for the request.
+ QuicStreamFrame frame2(stream_->id(), true, 0, StringPiece("End"));
+ stream_->OnStreamFrame(frame2);
+ EXPECT_TRUE(stream_->fin_received());
+ EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/core/spdy_utils.cc b/chromium/net/quic/core/spdy_utils.cc
new file mode 100644
index 00000000000..0f3e69cadee
--- /dev/null
+++ b/chromium/net/quic/core/spdy_utils.cc
@@ -0,0 +1,259 @@
+// Copyright (c) 2013 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/spdy_utils.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "net/spdy/spdy_flags.h"
+#include "net/spdy/spdy_frame_builder.h"
+#include "net/spdy/spdy_framer.h"
+#include "net/spdy/spdy_protocol.h"
+#include "url/gurl.h"
+
+using base::StringPiece;
+using base::ContainsKey;
+using std::string;
+using std::vector;
+
+namespace net {
+
+// static
+string SpdyUtils::SerializeUncompressedHeaders(const SpdyHeaderBlock& headers) {
+ SpdyMajorVersion spdy_version = HTTP2;
+
+ size_t length = SpdyFramer::GetSerializedLength(spdy_version, &headers);
+ SpdyFrameBuilder builder(length, spdy_version);
+ SpdyFramer framer(spdy_version);
+ framer.SerializeHeaderBlockWithoutCompression(&builder, headers);
+ SpdySerializedFrame block(builder.take());
+ return string(block.data(), length);
+}
+
+// static
+bool SpdyUtils::ParseHeaders(const char* data,
+ uint32_t data_len,
+ int64_t* content_length,
+ SpdyHeaderBlock* headers) {
+ SpdyFramer framer(HTTP2);
+ if (!framer.ParseHeaderBlockInBuffer(data, data_len, headers) ||
+ headers->empty()) {
+ return false; // Headers were invalid.
+ }
+
+ if (!ContainsKey(*headers, "content-length")) {
+ return true;
+ }
+
+ return ExtractContentLengthFromHeaders(content_length, headers);
+}
+
+// static
+bool SpdyUtils::ExtractContentLengthFromHeaders(int64_t* content_length,
+ SpdyHeaderBlock* headers) {
+ if (!ContainsKey(*headers, "content-length")) {
+ return false;
+ }
+ // Check whether multiple values are consistent.
+ base::StringPiece content_length_header = (*headers)["content-length"];
+ vector<string> values =
+ base::SplitString(content_length_header, base::StringPiece("\0", 1),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ for (const string& value : values) {
+ int64_t new_value;
+ if (!base::StringToInt64(value, &new_value) || new_value < 0) {
+ DLOG(ERROR) << "Content length was either unparseable or negative.";
+ return false;
+ }
+ if (*content_length < 0) {
+ *content_length = new_value;
+ continue;
+ }
+ if (new_value != *content_length) {
+ DLOG(ERROR) << "Parsed content length " << new_value << " is "
+ << "inconsistent with previously detected content length "
+ << *content_length;
+ return false;
+ }
+ }
+ return true;
+}
+
+// static
+bool SpdyUtils::ParseTrailers(const char* data,
+ uint32_t data_len,
+ size_t* final_byte_offset,
+ SpdyHeaderBlock* trailers) {
+ SpdyFramer framer(HTTP2);
+ if (!framer.ParseHeaderBlockInBuffer(data, data_len, trailers) ||
+ trailers->empty()) {
+ DVLOG(1) << "Request Trailers are invalid.";
+ return false; // Trailers were invalid.
+ }
+
+ // Pull out the final offset pseudo header which indicates the number of
+ // response body bytes expected.
+ auto it = trailers->find(kFinalOffsetHeaderKey);
+ if (it == trailers->end() ||
+ !base::StringToSizeT(it->second, final_byte_offset)) {
+ DVLOG(1) << "Required key '" << kFinalOffsetHeaderKey << "' not present";
+ return false;
+ }
+ // The final offset header is no longer needed.
+ trailers->erase(it->first);
+
+ // Trailers must not have empty keys, and must not contain pseudo headers.
+ for (const auto& trailer : *trailers) {
+ base::StringPiece key = trailer.first;
+ base::StringPiece value = trailer.second;
+ if (base::StartsWith(key, ":", base::CompareCase::INSENSITIVE_ASCII)) {
+ DVLOG(1) << "Trailers must not contain pseudo-header: '" << key << "','"
+ << value << "'.";
+ return false;
+ }
+
+ // TODO(rjshade): Check for other forbidden keys, following the HTTP/2 spec.
+ }
+
+ DVLOG(1) << "Successfully parsed Trailers.";
+ return true;
+}
+
+bool SpdyUtils::CopyAndValidateHeaders(const QuicHeaderList& header_list,
+ int64_t* content_length,
+ SpdyHeaderBlock* headers) {
+ for (const auto& p : header_list) {
+ const string& name = p.first;
+ if (name.empty()) {
+ DVLOG(1) << "Header name must not be empty.";
+ return false;
+ }
+
+ if (std::any_of(name.begin(), name.end(), base::IsAsciiUpper<char>)) {
+ DVLOG(1) << "Malformed header: Header name " << name
+ << " contains upper-case characters.";
+ return false;
+ }
+
+ headers->AppendValueOrAddHeader(name, p.second);
+ }
+
+ if (ContainsKey(*headers, "content-length") &&
+ !ExtractContentLengthFromHeaders(content_length, headers)) {
+ return false;
+ }
+
+ DVLOG(1) << "Successfully parsed headers: " << headers->DebugString();
+ return true;
+}
+
+bool SpdyUtils::CopyAndValidateTrailers(const QuicHeaderList& header_list,
+ size_t* final_byte_offset,
+ SpdyHeaderBlock* trailers) {
+ bool found_final_byte_offset = false;
+ for (const auto& p : header_list) {
+ const string& name = p.first;
+
+ // Pull out the final offset pseudo header which indicates the number of
+ // response body bytes expected.
+ int offset;
+ if (!found_final_byte_offset && name == kFinalOffsetHeaderKey &&
+ base::StringToInt(p.second, &offset)) {
+ *final_byte_offset = offset;
+ found_final_byte_offset = true;
+ continue;
+ }
+
+ if (name.empty() || name[0] == ':') {
+ DVLOG(1) << "Trailers must not be empty, and must not contain pseudo-"
+ << "headers. Found: '" << name << "'";
+ return false;
+ }
+
+ if (std::any_of(name.begin(), name.end(), base::IsAsciiUpper<char>)) {
+ DVLOG(1) << "Malformed header: Header name " << name
+ << " contains upper-case characters.";
+ return false;
+ }
+
+ if (trailers->find(name) != trailers->end()) {
+ DVLOG(1) << "Duplicate header '" << name << "' found in trailers.";
+ return false;
+ }
+
+ (*trailers)[name] = p.second;
+ }
+
+ if (!found_final_byte_offset) {
+ DVLOG(1) << "Required key '" << kFinalOffsetHeaderKey << "' not present";
+ return false;
+ }
+
+ // TODO(rjshade): Check for other forbidden keys, following the HTTP/2 spec.
+
+ DVLOG(1) << "Successfully parsed Trailers: " << trailers->DebugString();
+ return true;
+}
+
+// static
+string SpdyUtils::GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers) {
+ SpdyHeaderBlock::const_iterator it = headers.find(":scheme");
+ if (it == headers.end()) {
+ return "";
+ }
+ std::string url = it->second.as_string();
+
+ url.append("://");
+
+ it = headers.find(":authority");
+ if (it == headers.end()) {
+ return "";
+ }
+ url.append(it->second.as_string());
+
+ it = headers.find(":path");
+ if (it == headers.end()) {
+ return "";
+ }
+ url.append(it->second.as_string());
+ return url;
+}
+
+// static
+string SpdyUtils::GetHostNameFromHeaderBlock(const SpdyHeaderBlock& headers) {
+ return GURL(GetUrlFromHeaderBlock(headers)).host();
+}
+
+// static
+bool SpdyUtils::UrlIsValid(const SpdyHeaderBlock& headers) {
+ string url(GetUrlFromHeaderBlock(headers));
+ return url != "" && GURL(url).is_valid();
+}
+
+// static
+bool SpdyUtils::PopulateHeaderBlockFromUrl(const string url,
+ SpdyHeaderBlock* headers) {
+ (*headers)[":method"] = "GET";
+ size_t pos = url.find("://");
+ if (pos == string::npos) {
+ return false;
+ }
+ (*headers)[":scheme"] = url.substr(0, pos);
+ size_t start = pos + 3;
+ pos = url.find("/", start);
+ if (pos == string::npos) {
+ return false;
+ }
+ (*headers)[":authority"] = url.substr(start, pos - start);
+ (*headers)[":path"] = url.substr(pos);
+ return true;
+}
+
+} // namespace net
diff --git a/chromium/net/quic/core/spdy_utils.h b/chromium/net/quic/core/spdy_utils.h
new file mode 100644
index 00000000000..f69b4474d19
--- /dev/null
+++ b/chromium/net/quic/core/spdy_utils.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2013 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_SPDY_UTILS_H_
+#define NET_QUIC_SPDY_UTILS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <string>
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_header_list.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/spdy/spdy_framer.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE SpdyUtils {
+ public:
+ static std::string SerializeUncompressedHeaders(
+ const SpdyHeaderBlock& headers);
+
+ // Parses |data| as a std::string containing serialized HTTP/2 HEADERS frame,
+ // populating |headers| with the key->value std:pairs found.
+ // |content_length| will be populated with the value of the content-length
+ // header if one or more are present.
+ // Returns true on success, false if parsing fails, or invalid keys are found.
+ static bool ParseHeaders(const char* data,
+ uint32_t data_len,
+ int64_t* content_length,
+ SpdyHeaderBlock* headers);
+
+ // Populate |content length| with the value of the content-length header.
+ // Returns true on success, false if parsing fails or content-length header is
+ // missing.
+ static bool ExtractContentLengthFromHeaders(int64_t* content_length,
+ SpdyHeaderBlock* headers);
+
+ // Parses |data| as a std::string containing serialized HTTP/2 HEADERS frame,
+ // populating |trailers| with the key->value std:pairs found.
+ // The final offset header will be excluded from |trailers|, and instead the
+ // value will be copied to |final_byte_offset|.
+ // Returns true on success, false if parsing fails, or invalid keys are found.
+ static bool ParseTrailers(const char* data,
+ uint32_t data_len,
+ size_t* final_byte_offset,
+ SpdyHeaderBlock* trailers);
+
+ // Copies a list of headers to a SpdyHeaderBlock. Performs similar validation
+ // to SpdyFramer::ParseHeaderBlockInBuffer and ParseHeaders, above.
+ static bool CopyAndValidateHeaders(const QuicHeaderList& header_list,
+ int64_t* content_length,
+ SpdyHeaderBlock* headers);
+
+ // Copies a list of headers to a SpdyHeaderBlock. Performs similar validation
+ // to SpdyFramer::ParseHeaderBlockInBuffer and ParseTrailers, above.
+ static bool CopyAndValidateTrailers(const QuicHeaderList& header_list,
+ size_t* final_byte_offset,
+ SpdyHeaderBlock* trailers);
+
+ // Returns URL composed from scheme, authority, and path header
+ // values, or empty string if any of those fields are missing.
+ static std::string GetUrlFromHeaderBlock(const net::SpdyHeaderBlock& headers);
+
+ // Returns hostname, or empty std::string if missing.
+ static std::string GetHostNameFromHeaderBlock(const SpdyHeaderBlock& headers);
+
+ // Returns true if result of |GetUrlFromHeaderBlock()| is non-empty
+ // and is a well-formed URL.
+ static bool UrlIsValid(const net::SpdyHeaderBlock& headers);
+
+ // Populates the fields of |headers| to make a GET request of |url|,
+ // which must be fully-qualified.
+ static bool PopulateHeaderBlockFromUrl(const std::string url,
+ SpdyHeaderBlock* headers);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SpdyUtils);
+};
+
+} // namespace net
+
+#endif // NET_QUIC_SPDY_UTILS_H_
diff --git a/chromium/net/quic/core/spdy_utils_test.cc b/chromium/net/quic/core/spdy_utils_test.cc
new file mode 100644
index 00000000000..24c61a18b20
--- /dev/null
+++ b/chromium/net/quic/core/spdy_utils_test.cc
@@ -0,0 +1,374 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "net/quic/core/spdy_utils.h"
+
+#include "base/macros.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "net/test/gtest_util.h"
+
+using base::StringPiece;
+using std::string;
+using testing::UnorderedElementsAre;
+using testing::Pair;
+
+namespace net {
+namespace test {
+
+TEST(SpdyUtilsTest, SerializeAndParseHeaders) {
+ // Creates a SpdyHeaderBlock with some key->value pairs, serializes it, then
+ // parses the serialized output and verifies that the end result is the same
+ // as the headers that the test started with.
+
+ SpdyHeaderBlock input_headers;
+ input_headers[":pseudo1"] = "pseudo value1";
+ input_headers[":pseudo2"] = "pseudo value2";
+ input_headers["key1"] = "value1";
+ const int64_t kContentLength = 1234;
+ input_headers["content-length"] = base::Int64ToString(kContentLength);
+ input_headers["key2"] = "value2";
+
+ // Serialize the header block.
+ string serialized_headers =
+ SpdyUtils::SerializeUncompressedHeaders(input_headers);
+
+ // Take the serialized header block, and parse back into SpdyHeaderBlock.
+ SpdyHeaderBlock output_headers;
+ int64_t content_length = -1;
+ ASSERT_TRUE(SpdyUtils::ParseHeaders(serialized_headers.data(),
+ serialized_headers.size(),
+ &content_length, &output_headers));
+
+ // Should be back to the original headers.
+ EXPECT_EQ(content_length, kContentLength);
+ EXPECT_EQ(output_headers, input_headers);
+}
+
+TEST(SpdyUtilsTest, SerializeAndParseHeadersLargeContentLength) {
+ // Creates a SpdyHeaderBlock with some key->value pairs, serializes it, then
+ // parses the serialized output and verifies that the end result is the same
+ // as the headers that the test started with.
+
+ SpdyHeaderBlock input_headers;
+ input_headers[":pseudo1"] = "pseudo value1";
+ input_headers[":pseudo2"] = "pseudo value2";
+ input_headers["key1"] = "value1";
+ const int64_t kContentLength = 12345678900;
+ input_headers["content-length"] = base::Int64ToString(kContentLength);
+ input_headers["key2"] = "value2";
+
+ // Serialize the header block.
+ string serialized_headers =
+ SpdyUtils::SerializeUncompressedHeaders(input_headers);
+
+ // Take the serialized header block, and parse back into SpdyHeaderBlock.
+ SpdyHeaderBlock output_headers;
+ int64_t content_length = -1;
+ ASSERT_TRUE(SpdyUtils::ParseHeaders(serialized_headers.data(),
+ serialized_headers.size(),
+ &content_length, &output_headers));
+
+ // Should be back to the original headers.
+ EXPECT_EQ(content_length, kContentLength);
+ EXPECT_EQ(output_headers, input_headers);
+}
+
+TEST(SpdyUtilsTest, SerializeAndParseValidTrailers) {
+ // Creates a SpdyHeaderBlock with some valid Trailers key->value pairs,
+ // serializes it, then parses the serialized output and verifies that the end
+ // result is the same as the trailers that the test started with.
+ SpdyHeaderBlock input_trailers;
+ const size_t kFinalOffset = 5678;
+ input_trailers[kFinalOffsetHeaderKey] = base::IntToString(kFinalOffset);
+ input_trailers["key1"] = "value1";
+ input_trailers["key2"] = "value2";
+
+ // Serialize the trailers.
+ string serialized_trailers =
+ SpdyUtils::SerializeUncompressedHeaders(input_trailers);
+
+ // Take the serialized trailers, and parse back into a SpdyHeaderBlock.
+ SpdyHeaderBlock output_trailers;
+ size_t final_byte_offset = 0;
+ EXPECT_TRUE(SpdyUtils::ParseTrailers(serialized_trailers.data(),
+ serialized_trailers.size(),
+ &final_byte_offset, &output_trailers));
+
+ // Should be back to the original trailers, without the final offset header.
+ EXPECT_EQ(final_byte_offset, kFinalOffset);
+ input_trailers.erase(kFinalOffsetHeaderKey);
+ EXPECT_EQ(output_trailers, input_trailers);
+}
+
+TEST(SpdyUtilsTest, SerializeAndParseTrailersWithoutFinalOffset) {
+ // Verifies that parsing fails if Trailers are missing a final offset header.
+
+ SpdyHeaderBlock input_trailers;
+ input_trailers["key1"] = "value1";
+ input_trailers["key2"] = "value2";
+
+ // Serialize the trailers.
+ string serialized_trailers =
+ SpdyUtils::SerializeUncompressedHeaders(input_trailers);
+
+ // Parsing the serialized trailers fails because of the missing final offset.
+ SpdyHeaderBlock output_trailers;
+ size_t final_byte_offset = 0;
+ EXPECT_FALSE(SpdyUtils::ParseTrailers(serialized_trailers.data(),
+ serialized_trailers.size(),
+ &final_byte_offset, &output_trailers));
+ EXPECT_EQ(final_byte_offset, 0u);
+}
+
+TEST(SpdyUtilsTest, SerializeAndParseTrailersWithPseudoHeaders) {
+ // Verifies that parsing fails if Trailers include pseudo-headers.
+
+ SpdyHeaderBlock input_trailers;
+ input_trailers[kFinalOffsetHeaderKey] = "12345";
+ input_trailers[":disallowed-pseudo-header"] = "pseudo value";
+ input_trailers["key1"] = "value1";
+ input_trailers["key2"] = "value2";
+
+ // Serialize the trailers.
+ string serialized_trailers =
+ SpdyUtils::SerializeUncompressedHeaders(input_trailers);
+
+ // Parsing the serialized trailers fails because of the extra pseudo header.
+ SpdyHeaderBlock output_trailers;
+ size_t final_byte_offset = 0;
+ EXPECT_FALSE(SpdyUtils::ParseTrailers(serialized_trailers.data(),
+ serialized_trailers.size(),
+ &final_byte_offset, &output_trailers));
+}
+static std::unique_ptr<QuicHeaderList> FromList(
+ const QuicHeaderList::ListType& src) {
+ std::unique_ptr<QuicHeaderList> headers(new QuicHeaderList);
+ headers->OnHeaderBlockStart();
+ for (const auto& p : src) {
+ headers->OnHeader(p.first, p.second);
+ }
+ headers->OnHeaderBlockEnd(0);
+ return headers;
+}
+
+TEST(SpdyUtilsTest, CopyAndValidateHeaders) {
+ auto headers = FromList({// All cookie crumbs are joined.
+ {"cookie", " part 1"},
+ {"cookie", "part 2 "},
+ {"cookie", "part3"},
+
+ // Already-delimited headers are passed through.
+ {"passed-through", string("foo\0baz", 7)},
+
+ // Other headers are joined on \0.
+ {"joined", "value 1"},
+ {"joined", "value 2"},
+
+ // Empty headers remain empty.
+ {"empty", ""},
+
+ // Joined empty headers work as expected.
+ {"empty-joined", ""},
+ {"empty-joined", "foo"},
+ {"empty-joined", ""},
+ {"empty-joined", ""},
+
+ // Non-continguous cookie crumb.
+ {"cookie", " fin!"}});
+
+ int64_t content_length = -1;
+ SpdyHeaderBlock block;
+ ASSERT_TRUE(
+ SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
+ EXPECT_THAT(block, UnorderedElementsAre(
+ Pair("cookie", " part 1; part 2 ; part3; fin!"),
+ Pair("passed-through", StringPiece("foo\0baz", 7)),
+ Pair("joined", StringPiece("value 1\0value 2", 15)),
+ Pair("empty", ""),
+ Pair("empty-joined", StringPiece("\0foo\0\0", 6))));
+ EXPECT_EQ(-1, content_length);
+}
+
+TEST(SpdyUtilsTest, CopyAndValidateHeadersEmptyName) {
+ auto headers = FromList({{"foo", "foovalue"}, {"", "barvalue"}, {"baz", ""}});
+ int64_t content_length = -1;
+ SpdyHeaderBlock block;
+ ASSERT_FALSE(
+ SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
+}
+
+TEST(SpdyUtilsTest, CopyAndValidateHeadersUpperCaseName) {
+ auto headers =
+ FromList({{"foo", "foovalue"}, {"bar", "barvalue"}, {"bAz", ""}});
+ int64_t content_length = -1;
+ SpdyHeaderBlock block;
+ ASSERT_FALSE(
+ SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
+}
+
+TEST(SpdyUtilsTest, CopyAndValidateHeadersMultipleContentLengths) {
+ auto headers = FromList({{"content-length", "9"},
+ {"foo", "foovalue"},
+ {"content-length", "9"},
+ {"bar", "barvalue"},
+ {"baz", ""}});
+ int64_t content_length = -1;
+ SpdyHeaderBlock block;
+ ASSERT_TRUE(
+ SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
+ EXPECT_THAT(block, UnorderedElementsAre(
+ Pair("foo", "foovalue"), Pair("bar", "barvalue"),
+ Pair("content-length", StringPiece("9"
+ "\0"
+ "9",
+ 3)),
+ Pair("baz", "")));
+ EXPECT_EQ(9, content_length);
+}
+
+TEST(SpdyUtilsTest, CopyAndValidateHeadersInconsistentContentLengths) {
+ auto headers = FromList({{"content-length", "9"},
+ {"foo", "foovalue"},
+ {"content-length", "8"},
+ {"bar", "barvalue"},
+ {"baz", ""}});
+ int64_t content_length = -1;
+ SpdyHeaderBlock block;
+ ASSERT_FALSE(
+ SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
+}
+
+TEST(SpdyUtilsTest, CopyAndValidateHeadersLargeContentLength) {
+ auto headers = FromList({{"content-length", "9000000000"},
+ {"foo", "foovalue"},
+ {"bar", "barvalue"},
+ {"baz", ""}});
+ int64_t content_length = -1;
+ SpdyHeaderBlock block;
+ ASSERT_TRUE(
+ SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
+ EXPECT_THAT(block, UnorderedElementsAre(
+ Pair("foo", "foovalue"), Pair("bar", "barvalue"),
+ Pair("content-length", StringPiece("9000000000")),
+ Pair("baz", "")));
+ EXPECT_EQ(9000000000, content_length);
+}
+
+TEST(SpdyUtilsTest, CopyAndValidateHeadersMultipleValues) {
+ auto headers = FromList({{"foo", "foovalue"},
+ {"bar", "barvalue"},
+ {"baz", ""},
+ {"foo", "boo"},
+ {"baz", "buzz"}});
+ int64_t content_length = -1;
+ SpdyHeaderBlock block;
+ ASSERT_TRUE(
+ SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
+ EXPECT_THAT(
+ block, UnorderedElementsAre(Pair("foo", StringPiece("foovalue\0boo", 12)),
+ Pair("bar", "barvalue"),
+ Pair("baz", StringPiece("\0buzz", 5))));
+ EXPECT_EQ(-1, content_length);
+}
+
+TEST(SpdyUtilsTest, CopyAndValidateHeadersMoreThanTwoValues) {
+ auto headers = FromList({{"set-cookie", "value1"},
+ {"set-cookie", "value2"},
+ {"set-cookie", "value3"}});
+ int64_t content_length = -1;
+ SpdyHeaderBlock block;
+ ASSERT_TRUE(
+ SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
+ EXPECT_THAT(block,
+ UnorderedElementsAre(Pair(
+ "set-cookie", StringPiece("value1\0value2\0value3", 20))));
+ EXPECT_EQ(-1, content_length);
+}
+
+TEST(SpdyUtilsTest, CopyAndValidateHeadersCookie) {
+ auto headers = FromList({{"foo", "foovalue"},
+ {"bar", "barvalue"},
+ {"cookie", "value1"},
+ {"baz", ""}});
+ int64_t content_length = -1;
+ SpdyHeaderBlock block;
+ ASSERT_TRUE(
+ SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
+ EXPECT_THAT(block, UnorderedElementsAre(
+ Pair("foo", "foovalue"), Pair("bar", "barvalue"),
+ Pair("cookie", "value1"), Pair("baz", "")));
+ EXPECT_EQ(-1, content_length);
+}
+
+TEST(SpdyUtilsTest, CopyAndValidateHeadersMultipleCookies) {
+ auto headers = FromList({{"foo", "foovalue"},
+ {"bar", "barvalue"},
+ {"cookie", "value1"},
+ {"baz", ""},
+ {"cookie", "value2"}});
+ int64_t content_length = -1;
+ SpdyHeaderBlock block;
+ ASSERT_TRUE(
+ SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
+ EXPECT_THAT(block, UnorderedElementsAre(
+ Pair("foo", "foovalue"), Pair("bar", "barvalue"),
+ Pair("cookie", "value1; value2"), Pair("baz", "")));
+ EXPECT_EQ(-1, content_length);
+}
+
+TEST(SpdyUtilsTest, GetUrlFromHeaderBlock) {
+ SpdyHeaderBlock headers;
+ EXPECT_EQ(SpdyUtils::GetUrlFromHeaderBlock(headers), "");
+ headers[":scheme"] = "https";
+ EXPECT_EQ(SpdyUtils::GetUrlFromHeaderBlock(headers), "");
+ headers[":authority"] = "www.google.com";
+ EXPECT_EQ(SpdyUtils::GetUrlFromHeaderBlock(headers), "");
+ headers[":path"] = "/index.html";
+ EXPECT_EQ(SpdyUtils::GetUrlFromHeaderBlock(headers),
+ "https://www.google.com/index.html");
+ headers["key1"] = "value1";
+ headers["key2"] = "value2";
+ EXPECT_EQ(SpdyUtils::GetUrlFromHeaderBlock(headers),
+ "https://www.google.com/index.html");
+}
+
+TEST(SpdyUtilsTest, GetHostNameFromHeaderBlock) {
+ SpdyHeaderBlock headers;
+ EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "");
+ headers[":scheme"] = "https";
+ EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "");
+ headers[":authority"] = "www.google.com";
+ EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "");
+ headers[":path"] = "/index.html";
+ EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "www.google.com");
+ headers["key1"] = "value1";
+ headers["key2"] = "value2";
+ EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "www.google.com");
+ headers[":authority"] = "www.google.com:6666";
+ EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "www.google.com");
+ headers[":authority"] = "192.168.1.1";
+ EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "192.168.1.1");
+ headers[":authority"] = "192.168.1.1:6666";
+ EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "192.168.1.1");
+}
+
+TEST(SpdyUtilsTest, PopulateHeaderBlockFromUrl) {
+ string url = "https://www.google.com/index.html";
+ SpdyHeaderBlock headers;
+ EXPECT_TRUE(SpdyUtils::PopulateHeaderBlockFromUrl(url, &headers));
+ EXPECT_EQ("https", headers[":scheme"].as_string());
+ EXPECT_EQ("www.google.com", headers[":authority"].as_string());
+ EXPECT_EQ("/index.html", headers[":path"].as_string());
+}
+
+TEST(SpdyUtilsTest, PopulateHeaderBlockFromUrlFails) {
+ SpdyHeaderBlock headers;
+ EXPECT_FALSE(SpdyUtils::PopulateHeaderBlockFromUrl("/", &headers));
+ EXPECT_FALSE(SpdyUtils::PopulateHeaderBlockFromUrl("/index.html", &headers));
+ EXPECT_FALSE(
+ SpdyUtils::PopulateHeaderBlockFromUrl("www.google.com/", &headers));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/crypto/aead_base_decrypter.cc b/chromium/net/quic/crypto/aead_base_decrypter.cc
deleted file mode 100644
index 8b6661a9ba9..00000000000
--- a/chromium/net/quic/crypto/aead_base_decrypter.cc
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright (c) 2013 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 <openssl/err.h>
-#include <openssl/evp.h>
-
-#include <memory>
-
-#include "net/quic/crypto/aead_base_decrypter.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-
-namespace {
-
-// Clear OpenSSL error stack.
-void ClearOpenSslErrors() {
- while (ERR_get_error()) {
- }
-}
-
-// In debug builds only, log OpenSSL error stack. Then clear OpenSSL error
-// stack.
-void DLogOpenSslErrors() {
-#ifdef NDEBUG
- ClearOpenSslErrors();
-#else
- while (uint32_t error = ERR_get_error()) {
- char buf[120];
- ERR_error_string_n(error, buf, arraysize(buf));
- DLOG(ERROR) << "OpenSSL error: " << buf;
- }
-#endif
-}
-
-} // namespace
-
-AeadBaseDecrypter::AeadBaseDecrypter(const EVP_AEAD* aead_alg,
- size_t key_size,
- size_t auth_tag_size,
- size_t nonce_prefix_size)
- : aead_alg_(aead_alg),
- key_size_(key_size),
- auth_tag_size_(auth_tag_size),
- nonce_prefix_size_(nonce_prefix_size),
- have_preliminary_key_(false) {
- DCHECK_GT(256u, key_size);
- DCHECK_GT(256u, auth_tag_size);
- DCHECK_GT(256u, nonce_prefix_size);
- DCHECK_LE(key_size_, sizeof(key_));
- DCHECK_LE(nonce_prefix_size_, sizeof(nonce_prefix_));
-}
-
-AeadBaseDecrypter::~AeadBaseDecrypter() {}
-
-bool AeadBaseDecrypter::SetKey(StringPiece key) {
- DCHECK_EQ(key.size(), key_size_);
- if (key.size() != key_size_) {
- return false;
- }
- memcpy(key_, key.data(), key.size());
-
- EVP_AEAD_CTX_cleanup(ctx_.get());
- if (!EVP_AEAD_CTX_init(ctx_.get(), aead_alg_, key_, key_size_, auth_tag_size_,
- nullptr)) {
- DLogOpenSslErrors();
- return false;
- }
-
- return true;
-}
-
-bool AeadBaseDecrypter::SetNoncePrefix(StringPiece nonce_prefix) {
- DCHECK_EQ(nonce_prefix.size(), nonce_prefix_size_);
- if (nonce_prefix.size() != nonce_prefix_size_) {
- return false;
- }
- memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size());
- return true;
-}
-
-bool AeadBaseDecrypter::SetPreliminaryKey(StringPiece key) {
- DCHECK(!have_preliminary_key_);
- SetKey(key);
- have_preliminary_key_ = true;
-
- return true;
-}
-
-bool AeadBaseDecrypter::SetDiversificationNonce(DiversificationNonce nonce) {
- if (!have_preliminary_key_) {
- return true;
- }
-
- string key, nonce_prefix;
- DiversifyPreliminaryKey(
- StringPiece(reinterpret_cast<const char*>(key_), key_size_),
- StringPiece(reinterpret_cast<const char*>(nonce_prefix_),
- nonce_prefix_size_),
- nonce, key_size_, nonce_prefix_size_, &key, &nonce_prefix);
-
- if (!SetKey(key) || !SetNoncePrefix(nonce_prefix)) {
- DCHECK(false);
- return false;
- }
-
- have_preliminary_key_ = false;
- return true;
-}
-
-bool AeadBaseDecrypter::DecryptPacket(QuicPathId path_id,
- QuicPacketNumber packet_number,
- StringPiece associated_data,
- StringPiece ciphertext,
- char* output,
- size_t* output_length,
- size_t max_output_length) {
- if (ciphertext.length() < auth_tag_size_) {
- return false;
- }
-
- if (have_preliminary_key_) {
- QUIC_BUG << "Unable to decrypt while key diversification is pending";
- return false;
- }
-
- uint8_t nonce[sizeof(nonce_prefix_) + sizeof(packet_number)];
- const size_t nonce_size = nonce_prefix_size_ + sizeof(packet_number);
- memcpy(nonce, nonce_prefix_, nonce_prefix_size_);
- uint64_t path_id_packet_number =
- QuicUtils::PackPathIdAndPacketNumber(path_id, packet_number);
- memcpy(nonce + nonce_prefix_size_, &path_id_packet_number,
- sizeof(path_id_packet_number));
- if (!EVP_AEAD_CTX_open(
- ctx_.get(), reinterpret_cast<uint8_t*>(output), output_length,
- max_output_length, reinterpret_cast<const uint8_t*>(nonce),
- nonce_size, reinterpret_cast<const uint8_t*>(ciphertext.data()),
- ciphertext.size(),
- reinterpret_cast<const uint8_t*>(associated_data.data()),
- associated_data.size())) {
- // Because QuicFramer does trial decryption, decryption errors are expected
- // when encryption level changes. So we don't log decryption errors.
- ClearOpenSslErrors();
- return false;
- }
- return true;
-}
-
-StringPiece AeadBaseDecrypter::GetKey() const {
- return StringPiece(reinterpret_cast<const char*>(key_), key_size_);
-}
-
-StringPiece AeadBaseDecrypter::GetNoncePrefix() const {
- if (nonce_prefix_size_ == 0) {
- return StringPiece();
- }
- return StringPiece(reinterpret_cast<const char*>(nonce_prefix_),
- nonce_prefix_size_);
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/aead_base_decrypter.h b/chromium/net/quic/crypto/aead_base_decrypter.h
deleted file mode 100644
index ca5fa9c317a..00000000000
--- a/chromium/net/quic/crypto/aead_base_decrypter.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) 2013 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_CRYPTO_AEAD_BASE_DECRYPTER_H_
-#define NET_QUIC_CRYPTO_AEAD_BASE_DECRYPTER_H_
-
-#include <stddef.h>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/scoped_evp_aead_ctx.h"
-
-namespace net {
-
-// AeadBaseDecrypter is the base class of AEAD QuicDecrypter subclasses.
-class NET_EXPORT_PRIVATE AeadBaseDecrypter : public QuicDecrypter {
- public:
- AeadBaseDecrypter(const EVP_AEAD* aead_alg,
- size_t key_size,
- size_t auth_tag_size,
- size_t nonce_prefix_size);
- ~AeadBaseDecrypter() override;
-
- // QuicDecrypter implementation
- bool SetKey(base::StringPiece key) override;
- bool SetNoncePrefix(base::StringPiece nonce_prefix) override;
- bool SetPreliminaryKey(base::StringPiece key) override;
- bool SetDiversificationNonce(DiversificationNonce nonce) override;
- bool DecryptPacket(QuicPathId path_id,
- QuicPacketNumber packet_number,
- base::StringPiece associated_data,
- base::StringPiece ciphertext,
- char* output,
- size_t* output_length,
- size_t max_output_length) override;
- base::StringPiece GetKey() const override;
- base::StringPiece GetNoncePrefix() const override;
-
- protected:
- // Make these constants available to the subclasses so that the subclasses
- // can assert at compile time their key_size_ and nonce_prefix_size_ do not
- // exceed the maximum.
- static const size_t kMaxKeySize = 32;
- static const size_t kMaxNoncePrefixSize = 4;
-
- private:
- const EVP_AEAD* const aead_alg_;
- const size_t key_size_;
- const size_t auth_tag_size_;
- const size_t nonce_prefix_size_;
- bool have_preliminary_key_;
-
- // The key.
- unsigned char key_[kMaxKeySize];
- // The nonce prefix.
- unsigned char nonce_prefix_[kMaxNoncePrefixSize];
-
- ScopedEVPAEADCtx ctx_;
-
- DISALLOW_COPY_AND_ASSIGN(AeadBaseDecrypter);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_AEAD_BASE_DECRYPTER_H_
diff --git a/chromium/net/quic/crypto/aead_base_encrypter.cc b/chromium/net/quic/crypto/aead_base_encrypter.cc
deleted file mode 100644
index 108df582459..00000000000
--- a/chromium/net/quic/crypto/aead_base_encrypter.cc
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright (c) 2013 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 <openssl/err.h>
-#include <openssl/evp.h>
-#include <string.h>
-
-#include <memory>
-
-#include "net/quic/crypto/aead_base_encrypter.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-
-using base::StringPiece;
-
-namespace net {
-
-namespace {
-
-// The maximum size in bytes of the nonce, including 8 bytes of sequence number.
-// ChaCha20 uses only the 8 byte sequence number and AES-GCM uses 12 bytes.
-const size_t kMaxNonceSize = 12;
-
-// In debug builds only, log OpenSSL error stack. Then clear OpenSSL error
-// stack.
-void DLogOpenSslErrors() {
-#ifdef NDEBUG
- while (ERR_get_error()) {
- }
-#else
- while (unsigned long error = ERR_get_error()) {
- char buf[120];
- ERR_error_string_n(error, buf, arraysize(buf));
- DLOG(ERROR) << "OpenSSL error: " << buf;
- }
-#endif
-}
-
-} // namespace
-
-AeadBaseEncrypter::AeadBaseEncrypter(const EVP_AEAD* aead_alg,
- size_t key_size,
- size_t auth_tag_size,
- size_t nonce_prefix_size)
- : aead_alg_(aead_alg),
- key_size_(key_size),
- auth_tag_size_(auth_tag_size),
- nonce_prefix_size_(nonce_prefix_size) {
- DCHECK_LE(key_size_, sizeof(key_));
- DCHECK_LE(nonce_prefix_size_, sizeof(nonce_prefix_));
- DCHECK_GE(kMaxNonceSize, nonce_prefix_size_);
-}
-
-AeadBaseEncrypter::~AeadBaseEncrypter() {}
-
-bool AeadBaseEncrypter::SetKey(StringPiece key) {
- DCHECK_EQ(key.size(), key_size_);
- if (key.size() != key_size_) {
- return false;
- }
- memcpy(key_, key.data(), key.size());
-
- EVP_AEAD_CTX_cleanup(ctx_.get());
-
- if (!EVP_AEAD_CTX_init(ctx_.get(), aead_alg_, key_, key_size_, auth_tag_size_,
- nullptr)) {
- DLogOpenSslErrors();
- return false;
- }
-
- return true;
-}
-
-bool AeadBaseEncrypter::SetNoncePrefix(StringPiece nonce_prefix) {
- DCHECK_EQ(nonce_prefix.size(), nonce_prefix_size_);
- if (nonce_prefix.size() != nonce_prefix_size_) {
- return false;
- }
- memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size());
- return true;
-}
-
-bool AeadBaseEncrypter::Encrypt(StringPiece nonce,
- StringPiece associated_data,
- StringPiece plaintext,
- unsigned char* output) {
- if (nonce.size() != nonce_prefix_size_ + sizeof(QuicPacketNumber)) {
- return false;
- }
-
- size_t ciphertext_len;
- if (!EVP_AEAD_CTX_seal(
- ctx_.get(), output, &ciphertext_len,
- plaintext.size() + auth_tag_size_,
- reinterpret_cast<const uint8_t*>(nonce.data()), nonce.size(),
- reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size(),
- reinterpret_cast<const uint8_t*>(associated_data.data()),
- associated_data.size())) {
- DLogOpenSslErrors();
- return false;
- }
-
- return true;
-}
-
-bool AeadBaseEncrypter::EncryptPacket(QuicPathId path_id,
- QuicPacketNumber packet_number,
- StringPiece associated_data,
- StringPiece plaintext,
- char* output,
- size_t* output_length,
- size_t max_output_length) {
- size_t ciphertext_size = GetCiphertextSize(plaintext.length());
- if (max_output_length < ciphertext_size) {
- return false;
- }
- // TODO(ianswett): Introduce a check to ensure that we don't encrypt with the
- // same packet number twice.
- const size_t nonce_size = nonce_prefix_size_ + sizeof(packet_number);
- ALIGNAS(4) char nonce_buffer[kMaxNonceSize];
- memcpy(nonce_buffer, nonce_prefix_, nonce_prefix_size_);
- uint64_t path_id_packet_number =
- QuicUtils::PackPathIdAndPacketNumber(path_id, packet_number);
- memcpy(nonce_buffer + nonce_prefix_size_, &path_id_packet_number,
- sizeof(path_id_packet_number));
-
- if (!Encrypt(StringPiece(nonce_buffer, nonce_size), associated_data,
- plaintext, reinterpret_cast<unsigned char*>(output))) {
- return false;
- }
- *output_length = ciphertext_size;
- return true;
-}
-
-size_t AeadBaseEncrypter::GetKeySize() const {
- return key_size_;
-}
-
-size_t AeadBaseEncrypter::GetNoncePrefixSize() const {
- return nonce_prefix_size_;
-}
-
-size_t AeadBaseEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const {
- return ciphertext_size - auth_tag_size_;
-}
-
-size_t AeadBaseEncrypter::GetCiphertextSize(size_t plaintext_size) const {
- return plaintext_size + auth_tag_size_;
-}
-
-StringPiece AeadBaseEncrypter::GetKey() const {
- return StringPiece(reinterpret_cast<const char*>(key_), key_size_);
-}
-
-StringPiece AeadBaseEncrypter::GetNoncePrefix() const {
- if (nonce_prefix_size_ == 0) {
- return StringPiece();
- }
- return StringPiece(reinterpret_cast<const char*>(nonce_prefix_),
- nonce_prefix_size_);
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/aead_base_encrypter.h b/chromium/net/quic/crypto/aead_base_encrypter.h
deleted file mode 100644
index 05d996f537a..00000000000
--- a/chromium/net/quic/crypto/aead_base_encrypter.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2013 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_CRYPTO_AEAD_BASE_ENCRYPTER_H_
-#define NET_QUIC_CRYPTO_AEAD_BASE_ENCRYPTER_H_
-
-#include <stddef.h>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/crypto/scoped_evp_aead_ctx.h"
-
-namespace net {
-
-// AeadBaseEncrypter is the base class of AEAD QuicEncrypter subclasses.
-class NET_EXPORT_PRIVATE AeadBaseEncrypter : public QuicEncrypter {
- public:
- AeadBaseEncrypter(const EVP_AEAD* aead_alg,
- size_t key_size,
- size_t auth_tag_size,
- size_t nonce_prefix_size);
- ~AeadBaseEncrypter() override;
-
- // QuicEncrypter implementation
- bool SetKey(base::StringPiece key) override;
- bool SetNoncePrefix(base::StringPiece nonce_prefix) override;
- bool EncryptPacket(QuicPathId path_id,
- QuicPacketNumber packet_number,
- base::StringPiece associated_data,
- base::StringPiece plaintext,
- char* output,
- size_t* output_length,
- size_t max_output_length) override;
- size_t GetKeySize() const override;
- size_t GetNoncePrefixSize() const override;
- size_t GetMaxPlaintextSize(size_t ciphertext_size) const override;
- size_t GetCiphertextSize(size_t plaintext_size) const override;
- base::StringPiece GetKey() const override;
- base::StringPiece GetNoncePrefix() const override;
-
- // Necessary so unit tests can explicitly specify a nonce, instead of a
- // nonce prefix and packet number.
- bool Encrypt(base::StringPiece nonce,
- base::StringPiece associated_data,
- base::StringPiece plaintext,
- unsigned char* output);
-
- protected:
- // Make these constants available to the subclasses so that the subclasses
- // can assert at compile time their key_size_ and nonce_prefix_size_ do not
- // exceed the maximum.
- static const size_t kMaxKeySize = 32;
- static const size_t kMaxNoncePrefixSize = 4;
-
- private:
- const EVP_AEAD* const aead_alg_;
- const size_t key_size_;
- const size_t auth_tag_size_;
- const size_t nonce_prefix_size_;
-
- // The key.
- unsigned char key_[kMaxKeySize];
- // The nonce prefix.
- unsigned char nonce_prefix_[kMaxNoncePrefixSize];
-
- ScopedEVPAEADCtx ctx_;
-
- DISALLOW_COPY_AND_ASSIGN(AeadBaseEncrypter);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_AEAD_BASE_ENCRYPTER_H_
diff --git a/chromium/net/quic/crypto/aes_128_gcm_12_decrypter.cc b/chromium/net/quic/crypto/aes_128_gcm_12_decrypter.cc
deleted file mode 100644
index e0d500aa86e..00000000000
--- a/chromium/net/quic/crypto/aes_128_gcm_12_decrypter.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2013 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/crypto/aes_128_gcm_12_decrypter.h"
-
-#include <openssl/evp.h>
-#include <openssl/tls1.h>
-
-namespace net {
-
-namespace {
-
-const size_t kKeySize = 16;
-const size_t kNoncePrefixSize = 4;
-
-} // namespace
-
-Aes128Gcm12Decrypter::Aes128Gcm12Decrypter()
- : AeadBaseDecrypter(EVP_aead_aes_128_gcm(),
- kKeySize,
- kAuthTagSize,
- kNoncePrefixSize) {
- static_assert(kKeySize <= kMaxKeySize, "key size too big");
- static_assert(kNoncePrefixSize <= kMaxNoncePrefixSize,
- "nonce prefix size too big");
-}
-
-Aes128Gcm12Decrypter::~Aes128Gcm12Decrypter() {}
-
-const char* Aes128Gcm12Decrypter::cipher_name() const {
- return TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
-}
-
-uint32_t Aes128Gcm12Decrypter::cipher_id() const {
- // This OpenSSL macro has the value 0x0300C02F. The two most significant bytes
- // 0x0300 are OpenSSL specific and are NOT part of the TLS CipherSuite value
- // for TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256.
- return TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/aes_128_gcm_12_decrypter.h b/chromium/net/quic/crypto/aes_128_gcm_12_decrypter.h
deleted file mode 100644
index 5883c76f0c1..00000000000
--- a/chromium/net/quic/crypto/aes_128_gcm_12_decrypter.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2013 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_CRYPTO_AES_128_GCM_12_DECRYPTER_H_
-#define NET_QUIC_CRYPTO_AES_128_GCM_12_DECRYPTER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "net/quic/crypto/aead_base_decrypter.h"
-
-namespace net {
-
-// An Aes128Gcm12Decrypter is a QuicDecrypter that implements the
-// AEAD_AES_128_GCM_12 algorithm specified in RFC 5282. Create an instance by
-// calling QuicDecrypter::Create(kAESG).
-//
-// It uses an authentication tag of 12 bytes (96 bits). The fixed prefix
-// of the nonce is four bytes.
-class NET_EXPORT_PRIVATE Aes128Gcm12Decrypter : public AeadBaseDecrypter {
- public:
- enum {
- // Authentication tags are truncated to 96 bits.
- kAuthTagSize = 12,
- };
-
- Aes128Gcm12Decrypter();
- ~Aes128Gcm12Decrypter() override;
-
- const char* cipher_name() const override;
- uint32_t cipher_id() const override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Aes128Gcm12Decrypter);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_AES_128_GCM_12_DECRYPTER_H_
diff --git a/chromium/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc b/chromium/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc
deleted file mode 100644
index d9eb4cc4b43..00000000000
--- a/chromium/net/quic/crypto/aes_128_gcm_12_decrypter_test.cc
+++ /dev/null
@@ -1,287 +0,0 @@
-// Copyright (c) 2013 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/crypto/aes_128_gcm_12_decrypter.h"
-
-#include <memory>
-
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace {
-
-// The AES GCM test vectors come from the file gcmDecrypt128.rsp
-// downloaded from http://csrc.nist.gov/groups/STM/cavp/index.html on
-// 2013-02-01. The test vectors in that file look like this:
-//
-// [Keylen = 128]
-// [IVlen = 96]
-// [PTlen = 0]
-// [AADlen = 0]
-// [Taglen = 128]
-//
-// Count = 0
-// Key = cf063a34d4a9a76c2c86787d3f96db71
-// IV = 113b9785971864c83b01c787
-// CT =
-// AAD =
-// Tag = 72ac8493e3a5228b5d130a69d2510e42
-// PT =
-//
-// Count = 1
-// Key = a49a5e26a2f8cb63d05546c2a62f5343
-// IV = 907763b19b9b4ab6bd4f0281
-// CT =
-// AAD =
-// Tag = a2be08210d8c470a8df6e8fbd79ec5cf
-// FAIL
-//
-// ...
-//
-// The gcmDecrypt128.rsp file is huge (2.6 MB), so I selected just a
-// few test vectors for this unit test.
-
-// Describes a group of test vectors that all have a given key length, IV
-// length, plaintext length, AAD length, and tag length.
-struct TestGroupInfo {
- size_t key_len;
- size_t iv_len;
- size_t pt_len;
- size_t aad_len;
- size_t tag_len;
-};
-
-// Each test vector consists of six strings of lowercase hexadecimal digits.
-// The strings may be empty (zero length). A test vector with a nullptr |key|
-// marks the end of an array of test vectors.
-struct TestVector {
- // Input:
- const char* key;
- const char* iv;
- const char* ct;
- const char* aad;
- const char* tag;
-
- // Expected output:
- const char* pt; // An empty string "" means decryption succeeded and
- // the plaintext is zero-length. nullptr means decryption
- // failed.
-};
-
-const TestGroupInfo test_group_info[] = {
- {128, 96, 0, 0, 128}, {128, 96, 0, 128, 128}, {128, 96, 128, 0, 128},
- {128, 96, 408, 160, 128}, {128, 96, 408, 720, 128}, {128, 96, 104, 0, 128},
-};
-
-const TestVector test_group_0[] = {
- {"cf063a34d4a9a76c2c86787d3f96db71", "113b9785971864c83b01c787", "", "",
- "72ac8493e3a5228b5d130a69d2510e42", ""},
- {
- "a49a5e26a2f8cb63d05546c2a62f5343", "907763b19b9b4ab6bd4f0281", "", "",
- "a2be08210d8c470a8df6e8fbd79ec5cf",
- nullptr // FAIL
- },
- {nullptr}};
-
-const TestVector test_group_1[] = {
- {
- "d1f6af919cde85661208bdce0c27cb22", "898c6929b435017bf031c3c5", "",
- "7c5faa40e636bbc91107e68010c92b9f", "ae45f11777540a2caeb128be8092468a",
- nullptr // FAIL
- },
- {"2370e320d4344208e0ff5683f243b213", "04dbb82f044d30831c441228", "",
- "d43a8e5089eea0d026c03a85178b27da", "2a049c049d25aa95969b451d93c31c6e",
- ""},
- {nullptr}};
-
-const TestVector test_group_2[] = {
- {"e98b72a9881a84ca6b76e0f43e68647a", "8b23299fde174053f3d652ba",
- "5a3c1cf1985dbb8bed818036fdd5ab42", "", "23c7ab0f952b7091cd324835043b5eb5",
- "28286a321293253c3e0aa2704a278032"},
- {"33240636cd3236165f1a553b773e728e", "17c4d61493ecdc8f31700b12",
- "47bb7e23f7bdfe05a8091ac90e4f8b2e", "", "b723c70e931d9785f40fd4ab1d612dc9",
- "95695a5b12f2870b9cc5fdc8f218a97d"},
- {
- "5164df856f1e9cac04a79b808dc5be39", "e76925d5355e0584ce871b2b",
- "0216c899c88d6e32c958c7e553daa5bc", "",
- "a145319896329c96df291f64efbe0e3a",
- nullptr // FAIL
- },
- {nullptr}};
-
-const TestVector test_group_3[] = {
- {"af57f42c60c0fc5a09adb81ab86ca1c3", "a2dc01871f37025dc0fc9a79",
- "b9a535864f48ea7b6b1367914978f9bfa087d854bb0e269bed8d279d2eea1210e48947"
- "338b22f9bad09093276a331e9c79c7f4",
- "41dc38988945fcb44faf2ef72d0061289ef8efd8",
- "4f71e72bde0018f555c5adcce062e005",
- "3803a0727eeb0ade441e0ec107161ded2d425ec0d102f21f51bf2cf9947c7ec4aa7279"
- "5b2f69b041596e8817d0a3c16f8fadeb"},
- {"ebc753e5422b377d3cb64b58ffa41b61", "2e1821efaced9acf1f241c9b",
- "069567190554e9ab2b50a4e1fbf9c147340a5025fdbd201929834eaf6532325899ccb9"
- "f401823e04b05817243d2142a3589878",
- "b9673412fd4f88ba0e920f46dd6438ff791d8eef",
- "534d9234d2351cf30e565de47baece0b",
- "39077edb35e9c5a4b1e4c2a6b9bb1fce77f00f5023af40333d6d699014c2bcf4209c18"
- "353a18017f5b36bfc00b1f6dcb7ed485"},
- {
- "52bdbbf9cf477f187ec010589cb39d58", "d3be36d3393134951d324b31",
- "700188da144fa692cf46e4a8499510a53d90903c967f7f13e8a1bd8151a74adc4fe63e"
- "32b992760b3a5f99e9a47838867000a9",
- "93c4fc6a4135f54d640b0c976bf755a06a292c33",
- "8ca4e38aa3dfa6b1d0297021ccf3ea5f",
- nullptr // FAIL
- },
- {nullptr}};
-
-const TestVector test_group_4[] = {
- {"da2bb7d581493d692380c77105590201", "44aa3e7856ca279d2eb020c6",
- "9290d430c9e89c37f0446dbd620c9a6b34b1274aeb6f911f75867efcf95b6feda69f1a"
- "f4ee16c761b3c9aeac3da03aa9889c88",
- "4cd171b23bddb3a53cdf959d5c1710b481eb3785a90eb20a2345ee00d0bb7868c367ab"
- "12e6f4dd1dee72af4eee1d197777d1d6499cc541f34edbf45cda6ef90b3c024f9272d7"
- "2ec1909fb8fba7db88a4d6f7d3d925980f9f9f72",
- "9e3ac938d3eb0cadd6f5c9e35d22ba38",
- "9bbf4c1a2742f6ac80cb4e8a052e4a8f4f07c43602361355b717381edf9fabd4cb7e3a"
- "d65dbd1378b196ac270588dd0621f642"},
- {"d74e4958717a9d5c0e235b76a926cae8", "0b7471141e0c70b1995fd7b1",
- "e701c57d2330bf066f9ff8cf3ca4343cafe4894651cd199bdaaa681ba486b4a65c5a22"
- "b0f1420be29ea547d42c713bc6af66aa",
- "4a42b7aae8c245c6f1598a395316e4b8484dbd6e64648d5e302021b1d3fa0a38f46e22"
- "bd9c8080b863dc0016482538a8562a4bd0ba84edbe2697c76fd039527ac179ec5506cf"
- "34a6039312774cedebf4961f3978b14a26509f96",
- "e192c23cb036f0b31592989119eed55d",
- "840d9fb95e32559fb3602e48590280a172ca36d9b49ab69510f5bd552bfab7a306f85f"
- "f0a34bc305b88b804c60b90add594a17"},
- {
- "1986310c725ac94ecfe6422e75fc3ee7", "93ec4214fa8e6dc4e3afc775",
- "b178ec72f85a311ac4168f42a4b2c23113fbea4b85f4b9dabb74e143eb1b8b0a361e02"
- "43edfd365b90d5b325950df0ada058f9",
- "e80b88e62c49c958b5e0b8b54f532d9ff6aa84c8a40132e93e55b59fc24e8decf28463"
- "139f155d1e8ce4ee76aaeefcd245baa0fc519f83a5fb9ad9aa40c4b21126013f576c42"
- "72c2cb136c8fd091cc4539877a5d1e72d607f960",
- "8b347853f11d75e81e8a95010be81f17",
- nullptr // FAIL
- },
- {nullptr}};
-
-const TestVector test_group_5[] = {
- {"387218b246c1a8257748b56980e50c94", "dd7e014198672be39f95b69d",
- "cdba9e73eaf3d38eceb2b04a8d", "", "ecf90f4a47c9c626d6fb2c765d201556",
- "48f5b426baca03064554cc2b30"},
- {"294de463721e359863887c820524b3d4", "3338b35c9d57a5d28190e8c9",
- "2f46634e74b8e4c89812ac83b9", "", "dabd506764e68b82a7e720aa18da0abe",
- "46a2e55c8e264df211bd112685"},
- {"28ead7fd2179e0d12aa6d5d88c58c2dc", "5055347f18b4d5add0ae5c41",
- "142d8210c3fb84774cdbd0447a", "", "5fd321d9cdb01952dc85f034736c2a7d",
- "3b95b981086ee73cc4d0cc1422"},
- {
- "7d7b6c988137b8d470c57bf674a09c87", "9edf2aa970d016ac962e1fd8",
- "a85b66c3cb5eab91d5bdc8bc0e", "", "dc054efc01f3afd21d9c2484819f569a",
- nullptr // FAIL
- },
- {nullptr}};
-
-const TestVector* const test_group_array[] = {
- test_group_0, test_group_1, test_group_2,
- test_group_3, test_group_4, test_group_5,
-};
-
-} // namespace
-
-namespace net {
-namespace test {
-
-// DecryptWithNonce wraps the |Decrypt| method of |decrypter| to allow passing
-// in an nonce and also to allocate the buffer needed for the plaintext.
-QuicData* DecryptWithNonce(Aes128Gcm12Decrypter* decrypter,
- StringPiece nonce,
- StringPiece associated_data,
- StringPiece ciphertext) {
- QuicPathId path_id = kDefaultPathId;
- QuicPacketNumber packet_number;
- StringPiece nonce_prefix(nonce.data(), nonce.size() - sizeof(packet_number));
- decrypter->SetNoncePrefix(nonce_prefix);
- memcpy(&packet_number, nonce.data() + nonce_prefix.size(),
- sizeof(packet_number));
- path_id = static_cast<QuicPathId>(
- packet_number >> 8 * (sizeof(packet_number) - sizeof(path_id)));
- packet_number &= UINT64_C(0x00FFFFFFFFFFFFFF);
- std::unique_ptr<char[]> output(new char[ciphertext.length()]);
- size_t output_length = 0;
- const bool success = decrypter->DecryptPacket(
- path_id, packet_number, associated_data, ciphertext, output.get(),
- &output_length, ciphertext.length());
- if (!success) {
- return nullptr;
- }
- return new QuicData(output.release(), output_length, true);
-}
-
-TEST(Aes128Gcm12DecrypterTest, Decrypt) {
- for (size_t i = 0; i < arraysize(test_group_array); i++) {
- SCOPED_TRACE(i);
- const TestVector* test_vectors = test_group_array[i];
- const TestGroupInfo& test_info = test_group_info[i];
- for (size_t j = 0; test_vectors[j].key != nullptr; j++) {
- // If not present then decryption is expected to fail.
- bool has_pt = test_vectors[j].pt;
-
- // Decode the test vector.
- string key = QuicUtils::HexDecode(test_vectors[j].key);
- string iv = QuicUtils::HexDecode(test_vectors[j].iv);
- string ct = QuicUtils::HexDecode(test_vectors[j].ct);
- string aad = QuicUtils::HexDecode(test_vectors[j].aad);
- string tag = QuicUtils::HexDecode(test_vectors[j].tag);
- string pt;
- if (has_pt) {
- pt = QuicUtils::HexDecode(test_vectors[j].pt);
- }
-
- // The test vector's lengths should look sane. Note that the lengths
- // in |test_info| are in bits.
- EXPECT_EQ(test_info.key_len, key.length() * 8);
- EXPECT_EQ(test_info.iv_len, iv.length() * 8);
- EXPECT_EQ(test_info.pt_len, ct.length() * 8);
- EXPECT_EQ(test_info.aad_len, aad.length() * 8);
- EXPECT_EQ(test_info.tag_len, tag.length() * 8);
- if (has_pt) {
- EXPECT_EQ(test_info.pt_len, pt.length() * 8);
- }
-
- // The test vectors have 16 byte authenticators but this code only uses
- // the first 12.
- ASSERT_LE(static_cast<size_t>(Aes128Gcm12Decrypter::kAuthTagSize),
- tag.length());
- tag.resize(Aes128Gcm12Decrypter::kAuthTagSize);
- string ciphertext = ct + tag;
-
- Aes128Gcm12Decrypter decrypter;
- ASSERT_TRUE(decrypter.SetKey(key));
-
- std::unique_ptr<QuicData> decrypted(DecryptWithNonce(
- &decrypter, iv,
- // This deliberately tests that the decrypter can handle an AAD that
- // is set to nullptr, as opposed to a zero-length, non-nullptr
- // pointer.
- aad.length() ? aad : StringPiece(), ciphertext));
- if (!decrypted.get()) {
- EXPECT_FALSE(has_pt);
- continue;
- }
- EXPECT_TRUE(has_pt);
-
- ASSERT_EQ(pt.length(), decrypted->length());
- test::CompareCharArraysWithHexError("plaintext", decrypted->data(),
- pt.length(), pt.data(), pt.length());
- }
- }
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/aes_128_gcm_12_encrypter.cc b/chromium/net/quic/crypto/aes_128_gcm_12_encrypter.cc
deleted file mode 100644
index 2d7ea8f22a2..00000000000
--- a/chromium/net/quic/crypto/aes_128_gcm_12_encrypter.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2013 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/crypto/aes_128_gcm_12_encrypter.h"
-
-#include <openssl/evp.h>
-
-namespace net {
-
-namespace {
-
-const size_t kKeySize = 16;
-const size_t kNoncePrefixSize = 4;
-
-} // namespace
-
-Aes128Gcm12Encrypter::Aes128Gcm12Encrypter()
- : AeadBaseEncrypter(EVP_aead_aes_128_gcm(),
- kKeySize,
- kAuthTagSize,
- kNoncePrefixSize) {
- static_assert(kKeySize <= kMaxKeySize, "key size too big");
- static_assert(kNoncePrefixSize <= kMaxNoncePrefixSize,
- "nonce prefix size too big");
-}
-
-Aes128Gcm12Encrypter::~Aes128Gcm12Encrypter() {}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/aes_128_gcm_12_encrypter.h b/chromium/net/quic/crypto/aes_128_gcm_12_encrypter.h
deleted file mode 100644
index 3af151e1cb2..00000000000
--- a/chromium/net/quic/crypto/aes_128_gcm_12_encrypter.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2013 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_CRYPTO_AES_128_GCM_12_ENCRYPTER_H_
-#define NET_QUIC_CRYPTO_AES_128_GCM_12_ENCRYPTER_H_
-
-#include <stddef.h>
-
-#include "base/macros.h"
-#include "net/quic/crypto/aead_base_encrypter.h"
-
-namespace net {
-
-// An Aes128Gcm12Encrypter is a QuicEncrypter that implements the
-// AEAD_AES_128_GCM_12 algorithm specified in RFC 5282. Create an instance by
-// calling QuicEncrypter::Create(kAESG).
-//
-// It uses an authentication tag of 12 bytes (96 bits). The fixed prefix
-// of the nonce is four bytes.
-class NET_EXPORT_PRIVATE Aes128Gcm12Encrypter : public AeadBaseEncrypter {
- public:
- enum {
- // Authentication tags are truncated to 96 bits.
- kAuthTagSize = 12,
- };
-
- Aes128Gcm12Encrypter();
- ~Aes128Gcm12Encrypter() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Aes128Gcm12Encrypter);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_AES_128_GCM_12_ENCRYPTER_H_
diff --git a/chromium/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc b/chromium/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc
deleted file mode 100644
index 93582ebefa4..00000000000
--- a/chromium/net/quic/crypto/aes_128_gcm_12_encrypter_test.cc
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright (c) 2013 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/crypto/aes_128_gcm_12_encrypter.h"
-
-#include <memory>
-
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace {
-
-// The AES GCM test vectors come from the file gcmEncryptExtIV128.rsp
-// downloaded from http://csrc.nist.gov/groups/STM/cavp/index.html on
-// 2013-02-01. The test vectors in that file look like this:
-//
-// [Keylen = 128]
-// [IVlen = 96]
-// [PTlen = 0]
-// [AADlen = 0]
-// [Taglen = 128]
-//
-// Count = 0
-// Key = 11754cd72aec309bf52f7687212e8957
-// IV = 3c819d9a9bed087615030b65
-// PT =
-// AAD =
-// CT =
-// Tag = 250327c674aaf477aef2675748cf6971
-//
-// Count = 1
-// Key = ca47248ac0b6f8372a97ac43508308ed
-// IV = ffd2b598feabc9019262d2be
-// PT =
-// AAD =
-// CT =
-// Tag = 60d20404af527d248d893ae495707d1a
-//
-// ...
-//
-// The gcmEncryptExtIV128.rsp file is huge (2.8 MB), so I selected just a
-// few test vectors for this unit test.
-
-// Describes a group of test vectors that all have a given key length, IV
-// length, plaintext length, AAD length, and tag length.
-struct TestGroupInfo {
- size_t key_len;
- size_t iv_len;
- size_t pt_len;
- size_t aad_len;
- size_t tag_len;
-};
-
-// Each test vector consists of six strings of lowercase hexadecimal digits.
-// The strings may be empty (zero length). A test vector with a nullptr |key|
-// marks the end of an array of test vectors.
-struct TestVector {
- const char* key;
- const char* iv;
- const char* pt;
- const char* aad;
- const char* ct;
- const char* tag;
-};
-
-const TestGroupInfo test_group_info[] = {
- {128, 96, 0, 0, 128}, {128, 96, 0, 128, 128}, {128, 96, 128, 0, 128},
- {128, 96, 408, 160, 128}, {128, 96, 408, 720, 128}, {128, 96, 104, 0, 128},
-};
-
-const TestVector test_group_0[] = {
- {"11754cd72aec309bf52f7687212e8957", "3c819d9a9bed087615030b65", "", "", "",
- "250327c674aaf477aef2675748cf6971"},
- {"ca47248ac0b6f8372a97ac43508308ed", "ffd2b598feabc9019262d2be", "", "", "",
- "60d20404af527d248d893ae495707d1a"},
- {nullptr}};
-
-const TestVector test_group_1[] = {
- {"77be63708971c4e240d1cb79e8d77feb", "e0e00f19fed7ba0136a797f3", "",
- "7a43ec1d9c0a5a78a0b16533a6213cab", "",
- "209fcc8d3675ed938e9c7166709dd946"},
- {"7680c5d3ca6154758e510f4d25b98820", "f8f105f9c3df4965780321f8", "",
- "c94c410194c765e3dcc7964379758ed3", "",
- "94dca8edfcf90bb74b153c8d48a17930"},
- {nullptr}};
-
-const TestVector test_group_2[] = {
- {"7fddb57453c241d03efbed3ac44e371c", "ee283a3fc75575e33efd4887",
- "d5de42b461646c255c87bd2962d3b9a2", "", "2ccda4a5415cb91e135c2a0f78c9b2fd",
- "b36d1df9b9d5e596f83e8b7f52971cb3"},
- {"ab72c77b97cb5fe9a382d9fe81ffdbed", "54cc7dc2c37ec006bcc6d1da",
- "007c5e5b3e59df24a7c355584fc1518d", "", "0e1bde206a07a9c2c1b65300f8c64997",
- "2b4401346697138c7a4891ee59867d0c"},
- {nullptr}};
-
-const TestVector test_group_3[] = {
- {"fe47fcce5fc32665d2ae399e4eec72ba", "5adb9609dbaeb58cbd6e7275",
- "7c0e88c88899a779228465074797cd4c2e1498d259b54390b85e3eef1c02df60e743f1"
- "b840382c4bccaf3bafb4ca8429bea063",
- "88319d6e1d3ffa5f987199166c8a9b56c2aeba5a",
- "98f4826f05a265e6dd2be82db241c0fbbbf9ffb1c173aa83964b7cf539304373636525"
- "3ddbc5db8778371495da76d269e5db3e",
- "291ef1982e4defedaa2249f898556b47"},
- {"ec0c2ba17aa95cd6afffe949da9cc3a8", "296bce5b50b7d66096d627ef",
- "b85b3753535b825cbe5f632c0b843c741351f18aa484281aebec2f45bb9eea2d79d987"
- "b764b9611f6c0f8641843d5d58f3a242",
- "f8d00f05d22bf68599bcdeb131292ad6e2df5d14",
- "a7443d31c26bdf2a1c945e29ee4bd344a99cfaf3aa71f8b3f191f83c2adfc7a0716299"
- "5506fde6309ffc19e716eddf1a828c5a",
- "890147971946b627c40016da1ecf3e77"},
- {nullptr}};
-
-const TestVector test_group_4[] = {
- {"2c1f21cf0f6fb3661943155c3e3d8492", "23cb5ff362e22426984d1907",
- "42f758836986954db44bf37c6ef5e4ac0adaf38f27252a1b82d02ea949c8a1a2dbc0d6"
- "8b5615ba7c1220ff6510e259f06655d8",
- "5d3624879d35e46849953e45a32a624d6a6c536ed9857c613b572b0333e701557a713e"
- "3f010ecdf9a6bd6c9e3e44b065208645aff4aabee611b391528514170084ccf587177f"
- "4488f33cfb5e979e42b6e1cfc0a60238982a7aec",
- "81824f0e0d523db30d3da369fdc0d60894c7a0a20646dd015073ad2732bd989b14a222"
- "b6ad57af43e1895df9dca2a5344a62cc",
- "57a3ee28136e94c74838997ae9823f3a"},
- {"d9f7d2411091f947b4d6f1e2d1f0fb2e", "e1934f5db57cc983e6b180e7",
- "73ed042327f70fe9c572a61545eda8b2a0c6e1d6c291ef19248e973aee6c312012f490"
- "c2c6f6166f4a59431e182663fcaea05a",
- "0a8a18a7150e940c3d87b38e73baee9a5c049ee21795663e264b694a949822b639092d"
- "0e67015e86363583fcf0ca645af9f43375f05fdb4ce84f411dcbca73c2220dea03a201"
- "15d2e51398344b16bee1ed7c499b353d6c597af8",
- "aaadbd5c92e9151ce3db7210b8714126b73e43436d242677afa50384f2149b831f1d57"
- "3c7891c2a91fbc48db29967ec9542b23",
- "21b51ca862cb637cdd03b99a0f93b134"},
- {nullptr}};
-
-const TestVector test_group_5[] = {
- {"fe9bb47deb3a61e423c2231841cfd1fb", "4d328eb776f500a2f7fb47aa",
- "f1cc3818e421876bb6b8bbd6c9", "", "b88c5c1977b35b517b0aeae967",
- "43fd4727fe5cdb4b5b42818dea7ef8c9"},
- {"6703df3701a7f54911ca72e24dca046a", "12823ab601c350ea4bc2488c",
- "793cd125b0b84a043e3ac67717", "", "b2051c80014f42f08735a7b0cd",
- "38e6bcd29962e5f2c13626b85a877101"},
- {nullptr}};
-
-const TestVector* const test_group_array[] = {
- test_group_0, test_group_1, test_group_2,
- test_group_3, test_group_4, test_group_5,
-};
-
-} // namespace
-
-namespace net {
-namespace test {
-
-// EncryptWithNonce wraps the |Encrypt| method of |encrypter| to allow passing
-// in an nonce and also to allocate the buffer needed for the ciphertext.
-QuicData* EncryptWithNonce(Aes128Gcm12Encrypter* encrypter,
- StringPiece nonce,
- StringPiece associated_data,
- StringPiece plaintext) {
- size_t ciphertext_size = encrypter->GetCiphertextSize(plaintext.length());
- std::unique_ptr<char[]> ciphertext(new char[ciphertext_size]);
-
- if (!encrypter->Encrypt(nonce, associated_data, plaintext,
- reinterpret_cast<unsigned char*>(ciphertext.get()))) {
- return nullptr;
- }
-
- return new QuicData(ciphertext.release(), ciphertext_size, true);
-}
-
-TEST(Aes128Gcm12EncrypterTest, Encrypt) {
- for (size_t i = 0; i < arraysize(test_group_array); i++) {
- SCOPED_TRACE(i);
- const TestVector* test_vectors = test_group_array[i];
- const TestGroupInfo& test_info = test_group_info[i];
- for (size_t j = 0; test_vectors[j].key != nullptr; j++) {
- // Decode the test vector.
- string key = QuicUtils::HexDecode(test_vectors[j].key);
- string iv = QuicUtils::HexDecode(test_vectors[j].iv);
- string pt = QuicUtils::HexDecode(test_vectors[j].pt);
- string aad = QuicUtils::HexDecode(test_vectors[j].aad);
- string ct = QuicUtils::HexDecode(test_vectors[j].ct);
- string tag = QuicUtils::HexDecode(test_vectors[j].tag);
-
- // The test vector's lengths should look sane. Note that the lengths
- // in |test_info| are in bits.
- EXPECT_EQ(test_info.key_len, key.length() * 8);
- EXPECT_EQ(test_info.iv_len, iv.length() * 8);
- EXPECT_EQ(test_info.pt_len, pt.length() * 8);
- EXPECT_EQ(test_info.aad_len, aad.length() * 8);
- EXPECT_EQ(test_info.pt_len, ct.length() * 8);
- EXPECT_EQ(test_info.tag_len, tag.length() * 8);
-
- Aes128Gcm12Encrypter encrypter;
- ASSERT_TRUE(encrypter.SetKey(key));
- std::unique_ptr<QuicData> encrypted(EncryptWithNonce(
- &encrypter, iv,
- // This deliberately tests that the encrypter can handle an AAD that
- // is set to nullptr, as opposed to a zero-length, non-nullptr
- // pointer.
- aad.length() ? aad : StringPiece(), pt));
- ASSERT_TRUE(encrypted.get());
-
- // The test vectors have 16 byte authenticators but this code only uses
- // the first 12.
- ASSERT_LE(static_cast<size_t>(Aes128Gcm12Encrypter::kAuthTagSize),
- tag.length());
- tag.resize(Aes128Gcm12Encrypter::kAuthTagSize);
-
- ASSERT_EQ(ct.length() + tag.length(), encrypted->length());
- test::CompareCharArraysWithHexError("ciphertext", encrypted->data(),
- ct.length(), ct.data(), ct.length());
- test::CompareCharArraysWithHexError(
- "authentication tag", encrypted->data() + ct.length(), tag.length(),
- tag.data(), tag.length());
- }
- }
-}
-
-TEST(Aes128Gcm12EncrypterTest, GetMaxPlaintextSize) {
- Aes128Gcm12Encrypter encrypter;
- EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1012));
- EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(112));
- EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(22));
-}
-
-TEST(Aes128Gcm12EncrypterTest, GetCiphertextSize) {
- Aes128Gcm12Encrypter encrypter;
- EXPECT_EQ(1012u, encrypter.GetCiphertextSize(1000));
- EXPECT_EQ(112u, encrypter.GetCiphertextSize(100));
- EXPECT_EQ(22u, encrypter.GetCiphertextSize(10));
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/cert_compressor.cc b/chromium/net/quic/crypto/cert_compressor.cc
deleted file mode 100644
index 366252b2451..00000000000
--- a/chromium/net/quic/crypto/cert_compressor.cc
+++ /dev/null
@@ -1,647 +0,0 @@
-// Copyright (c) 2013 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/crypto/cert_compressor.h"
-
-#include <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-#include "net/quic/quic_utils.h"
-#include "third_party/zlib/zlib.h"
-
-using base::StringPiece;
-using std::string;
-using std::vector;
-
-namespace net {
-
-namespace {
-
-// kCommonCertSubstrings contains ~1500 bytes of common certificate substrings
-// in order to help zlib. This was generated via a fairly dumb algorithm from
-// the Alexa Top 5000 set - we could probably do better.
-static const unsigned char kCommonCertSubstrings[] = {
- 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04,
- 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
- 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30,
- 0x5f, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01,
- 0x06, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd, 0x6d, 0x01, 0x07,
- 0x17, 0x01, 0x30, 0x33, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65,
- 0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x20, 0x53, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x34,
- 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31,
- 0x32, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72,
- 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x30, 0x2d, 0x61, 0x69, 0x61, 0x2e,
- 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
- 0x2f, 0x45, 0x2d, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73,
- 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x45, 0x2e, 0x63, 0x65,
- 0x72, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x4a, 0x2e, 0x63,
- 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73,
- 0x2f, 0x63, 0x70, 0x73, 0x20, 0x28, 0x63, 0x29, 0x30, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
- 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x7b, 0x30, 0x1d, 0x06, 0x03, 0x55,
- 0x1d, 0x0e, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
- 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd2,
- 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x2e,
- 0x63, 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
- 0x04, 0x14, 0xb4, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69,
- 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x30, 0x0b, 0x06, 0x03,
- 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
- 0x81, 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08,
- 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30,
- 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74,
- 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03,
- 0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79,
- 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x33,
- 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x68, 0x74, 0x74,
- 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79,
- 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74,
- 0x6f, 0x72, 0x79, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03,
- 0x13, 0x27, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x53,
- 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
- 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
- 0x04, 0x05, 0x13, 0x08, 0x30, 0x37, 0x39, 0x36, 0x39, 0x32, 0x38, 0x37,
- 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
- 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0c,
- 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00,
- 0x30, 0x1d, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
- 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55,
- 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
- 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
- 0x03, 0x02, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
- 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x33, 0x06, 0x03, 0x55, 0x1d,
- 0x1f, 0x04, 0x2c, 0x30, 0x2a, 0x30, 0x28, 0xa0, 0x26, 0xa0, 0x24, 0x86,
- 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e,
- 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
- 0x67, 0x64, 0x73, 0x31, 0x2d, 0x32, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08,
- 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74,
- 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65,
- 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,
- 0x70, 0x73, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17,
- 0x0d, 0x31, 0x33, 0x30, 0x35, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01,
- 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a,
- 0x2f, 0x2f, 0x73, 0x30, 0x39, 0x30, 0x37, 0x06, 0x08, 0x2b, 0x06, 0x01,
- 0x05, 0x05, 0x07, 0x02, 0x30, 0x44, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04,
- 0x3d, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86,
- 0xf8, 0x45, 0x01, 0x07, 0x17, 0x06, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x1b, 0x53, 0x31, 0x17,
- 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72,
- 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31,
- 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, 0x65,
- 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74,
- 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3b, 0x30, 0x39,
- 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x32, 0x54, 0x65, 0x72, 0x6d, 0x73,
- 0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x65, 0x20, 0x61, 0x74, 0x20, 0x68,
- 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76,
- 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
- 0x72, 0x70, 0x61, 0x20, 0x28, 0x63, 0x29, 0x30, 0x31, 0x10, 0x30, 0x0e,
- 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x53, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x47, 0x31, 0x13, 0x30, 0x11,
- 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x3c, 0x02, 0x01,
- 0x03, 0x13, 0x02, 0x55, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x14, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
- 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0f, 0x13, 0x14, 0x50,
- 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x20, 0x4f, 0x72, 0x67, 0x61, 0x6e,
- 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x12, 0x31, 0x21, 0x30,
- 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x44, 0x6f, 0x6d, 0x61,
- 0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, 0x56,
- 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x31, 0x14, 0x31, 0x31,
- 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x28, 0x53, 0x65, 0x65,
- 0x20, 0x77, 0x77, 0x77, 0x2e, 0x72, 0x3a, 0x2f, 0x2f, 0x73, 0x65, 0x63,
- 0x75, 0x72, 0x65, 0x2e, 0x67, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53,
- 0x69, 0x67, 0x6e, 0x31, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x41,
- 0x2e, 0x63, 0x72, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e,
- 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x45, 0x63, 0x72,
- 0x6c, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63,
- 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x73, 0x64, 0x31, 0x1a,
- 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x3a,
- 0x2f, 0x2f, 0x45, 0x56, 0x49, 0x6e, 0x74, 0x6c, 0x2d, 0x63, 0x63, 0x72,
- 0x74, 0x2e, 0x67, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x69, 0x63, 0x65, 0x72,
- 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x31, 0x6f, 0x63, 0x73, 0x70, 0x2e,
- 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
- 0x30, 0x39, 0x72, 0x61, 0x70, 0x69, 0x64, 0x73, 0x73, 0x6c, 0x2e, 0x63,
- 0x6f, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63,
- 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72,
- 0x79, 0x2f, 0x30, 0x81, 0x80, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
- 0x07, 0x01, 0x01, 0x04, 0x74, 0x30, 0x72, 0x30, 0x24, 0x06, 0x08, 0x2b,
- 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74,
- 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64,
- 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x4a, 0x06,
- 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x3e, 0x68,
- 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64,
- 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73,
- 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x67, 0x64, 0x5f, 0x69, 0x6e, 0x74,
- 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72,
- 0x74, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
- 0x80, 0x14, 0xfd, 0xac, 0x61, 0x32, 0x93, 0x6c, 0x45, 0xd6, 0xe2, 0xee,
- 0x85, 0x5f, 0x9a, 0xba, 0xe7, 0x76, 0x99, 0x68, 0xcc, 0xe7, 0x30, 0x27,
- 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x86, 0x30,
- 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73,
-};
-
-// CertEntry represents a certificate in compressed form. Each entry is one of
-// the three types enumerated in |Type|.
-struct CertEntry {
- public:
- enum Type {
- // Type 0 is reserved to mean "end of list" in the wire format.
-
- // COMPRESSED means that the certificate is included in the trailing zlib
- // data.
- COMPRESSED = 1,
- // CACHED means that the certificate is already known to the peer and will
- // be replaced by its 64-bit hash (in |hash|).
- CACHED = 2,
- // COMMON means that the certificate is in a common certificate set known
- // to the peer with hash |set_hash| and certificate index |index|.
- COMMON = 3,
- };
-
- Type type;
- uint64_t hash;
- uint64_t set_hash;
- uint32_t index;
-};
-
-// MatchCerts returns a vector of CertEntries describing how to most
-// efficiently represent |certs| to a peer who has the common sets identified
-// by |client_common_set_hashes| and who has cached the certificates with the
-// 64-bit, FNV-1a hashes in |client_cached_cert_hashes|.
-vector<CertEntry> MatchCerts(const vector<string>& certs,
- StringPiece client_common_set_hashes,
- StringPiece client_cached_cert_hashes,
- const CommonCertSets* common_sets) {
- vector<CertEntry> entries;
- entries.reserve(certs.size());
-
- const bool cached_valid =
- client_cached_cert_hashes.size() % sizeof(uint64_t) == 0 &&
- !client_cached_cert_hashes.empty();
-
- for (vector<string>::const_iterator i = certs.begin(); i != certs.end();
- ++i) {
- CertEntry entry;
-
- if (cached_valid) {
- bool cached = false;
-
- uint64_t hash = QuicUtils::FNV1a_64_Hash(i->data(), i->size());
- // This assumes that the machine is little-endian.
- for (size_t j = 0; j < client_cached_cert_hashes.size();
- j += sizeof(uint64_t)) {
- uint64_t cached_hash;
- memcpy(&cached_hash, client_cached_cert_hashes.data() + j,
- sizeof(uint64_t));
- if (hash != cached_hash) {
- continue;
- }
-
- entry.type = CertEntry::CACHED;
- entry.hash = hash;
- entries.push_back(entry);
- cached = true;
- break;
- }
-
- if (cached) {
- continue;
- }
- }
-
- if (common_sets &&
- common_sets->MatchCert(*i, client_common_set_hashes, &entry.set_hash,
- &entry.index)) {
- entry.type = CertEntry::COMMON;
- entries.push_back(entry);
- continue;
- }
-
- entry.type = CertEntry::COMPRESSED;
- entries.push_back(entry);
- }
-
- return entries;
-}
-
-// CertEntriesSize returns the size, in bytes, of the serialised form of
-// |entries|.
-size_t CertEntriesSize(const vector<CertEntry>& entries) {
- size_t entries_size = 0;
-
- for (vector<CertEntry>::const_iterator i = entries.begin();
- i != entries.end(); ++i) {
- entries_size++;
- switch (i->type) {
- case CertEntry::COMPRESSED:
- break;
- case CertEntry::CACHED:
- entries_size += sizeof(uint64_t);
- break;
- case CertEntry::COMMON:
- entries_size += sizeof(uint64_t) + sizeof(uint32_t);
- break;
- }
- }
-
- entries_size++; // for end marker
-
- return entries_size;
-}
-
-// SerializeCertEntries serialises |entries| to |out|, which must have enough
-// space to contain them.
-void SerializeCertEntries(uint8_t* out, const vector<CertEntry>& entries) {
- for (vector<CertEntry>::const_iterator i = entries.begin();
- i != entries.end(); ++i) {
- *out++ = static_cast<uint8_t>(i->type);
- switch (i->type) {
- case CertEntry::COMPRESSED:
- break;
- case CertEntry::CACHED:
- memcpy(out, &i->hash, sizeof(i->hash));
- out += sizeof(uint64_t);
- break;
- case CertEntry::COMMON:
- // Assumes a little-endian machine.
- memcpy(out, &i->set_hash, sizeof(i->set_hash));
- out += sizeof(i->set_hash);
- memcpy(out, &i->index, sizeof(uint32_t));
- out += sizeof(uint32_t);
- break;
- }
- }
-
- *out++ = 0; // end marker
-}
-
-// ZlibDictForEntries returns a string that contains the zlib pre-shared
-// dictionary to use in order to decompress a zlib block following |entries|.
-// |certs| is one-to-one with |entries| and contains the certificates for those
-// entries that are CACHED or COMMON.
-string ZlibDictForEntries(const vector<CertEntry>& entries,
- const vector<string>& certs) {
- string zlib_dict;
-
- // The dictionary starts with the common and cached certs in reverse order.
- size_t zlib_dict_size = 0;
- for (size_t i = certs.size() - 1; i < certs.size(); i--) {
- if (entries[i].type != CertEntry::COMPRESSED) {
- zlib_dict_size += certs[i].size();
- }
- }
-
- // At the end of the dictionary is a block of common certificate substrings.
- zlib_dict_size += sizeof(kCommonCertSubstrings);
-
- zlib_dict.reserve(zlib_dict_size);
-
- for (size_t i = certs.size() - 1; i < certs.size(); i--) {
- if (entries[i].type != CertEntry::COMPRESSED) {
- zlib_dict += certs[i];
- }
- }
-
- zlib_dict += string(reinterpret_cast<const char*>(kCommonCertSubstrings),
- sizeof(kCommonCertSubstrings));
-
- DCHECK_EQ(zlib_dict.size(), zlib_dict_size);
-
- return zlib_dict;
-}
-
-// HashCerts returns the FNV-1a hashes of |certs|.
-vector<uint64_t> HashCerts(const vector<string>& certs) {
- vector<uint64_t> ret;
- ret.reserve(certs.size());
-
- for (vector<string>::const_iterator i = certs.begin(); i != certs.end();
- ++i) {
- ret.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size()));
- }
-
- return ret;
-}
-
-// ParseEntries parses the serialised form of a vector of CertEntries from
-// |in_out| and writes them to |out_entries|. CACHED and COMMON entries are
-// resolved using |cached_certs| and |common_sets| and written to |out_certs|.
-// |in_out| is updated to contain the trailing data.
-bool ParseEntries(StringPiece* in_out,
- const vector<string>& cached_certs,
- const CommonCertSets* common_sets,
- vector<CertEntry>* out_entries,
- vector<string>* out_certs) {
- StringPiece in = *in_out;
- vector<uint64_t> cached_hashes;
-
- out_entries->clear();
- out_certs->clear();
-
- for (;;) {
- if (in.empty()) {
- return false;
- }
- CertEntry entry;
- const uint8_t type_byte = in[0];
- in.remove_prefix(1);
-
- if (type_byte == 0) {
- break;
- }
-
- entry.type = static_cast<CertEntry::Type>(type_byte);
-
- switch (entry.type) {
- case CertEntry::COMPRESSED:
- out_certs->push_back(string());
- break;
- case CertEntry::CACHED: {
- if (in.size() < sizeof(uint64_t)) {
- return false;
- }
- memcpy(&entry.hash, in.data(), sizeof(uint64_t));
- in.remove_prefix(sizeof(uint64_t));
-
- if (cached_hashes.size() != cached_certs.size()) {
- cached_hashes = HashCerts(cached_certs);
- }
- bool found = false;
- for (size_t i = 0; i < cached_hashes.size(); i++) {
- if (cached_hashes[i] == entry.hash) {
- out_certs->push_back(cached_certs[i]);
- found = true;
- break;
- }
- }
- if (!found) {
- return false;
- }
- break;
- }
- case CertEntry::COMMON: {
- if (!common_sets) {
- return false;
- }
- if (in.size() < sizeof(uint64_t) + sizeof(uint32_t)) {
- return false;
- }
- memcpy(&entry.set_hash, in.data(), sizeof(uint64_t));
- in.remove_prefix(sizeof(uint64_t));
- memcpy(&entry.index, in.data(), sizeof(uint32_t));
- in.remove_prefix(sizeof(uint32_t));
-
- StringPiece cert = common_sets->GetCert(entry.set_hash, entry.index);
- if (cert.empty()) {
- return false;
- }
- out_certs->push_back(cert.as_string());
- break;
- }
- default:
- return false;
- }
- out_entries->push_back(entry);
- }
-
- *in_out = in;
- return true;
-}
-
-// ScopedZLib deals with the automatic destruction of a zlib context.
-class ScopedZLib {
- public:
- enum Type {
- INFLATE,
- DEFLATE,
- };
-
- explicit ScopedZLib(Type type) : z_(nullptr), type_(type) {}
-
- void reset(z_stream* z) {
- Clear();
- z_ = z;
- }
-
- ~ScopedZLib() { Clear(); }
-
- private:
- void Clear() {
- if (!z_) {
- return;
- }
-
- if (type_ == DEFLATE) {
- deflateEnd(z_);
- } else {
- inflateEnd(z_);
- }
- z_ = nullptr;
- }
-
- z_stream* z_;
- const Type type_;
-};
-
-} // anonymous namespace
-
-// static
-string CertCompressor::CompressChain(const vector<string>& certs,
- StringPiece client_common_set_hashes,
- StringPiece client_cached_cert_hashes,
- const CommonCertSets* common_sets) {
- const vector<CertEntry> entries = MatchCerts(
- certs, client_common_set_hashes, client_cached_cert_hashes, common_sets);
- DCHECK_EQ(entries.size(), certs.size());
-
- size_t uncompressed_size = 0;
- for (size_t i = 0; i < entries.size(); i++) {
- if (entries[i].type == CertEntry::COMPRESSED) {
- uncompressed_size += 4 /* uint32_t length */ + certs[i].size();
- }
- }
-
- size_t compressed_size = 0;
- z_stream z;
- ScopedZLib scoped_z(ScopedZLib::DEFLATE);
-
- if (uncompressed_size > 0) {
- memset(&z, 0, sizeof(z));
- int rv = deflateInit(&z, Z_DEFAULT_COMPRESSION);
- DCHECK_EQ(Z_OK, rv);
- if (rv != Z_OK) {
- return "";
- }
- scoped_z.reset(&z);
-
- string zlib_dict = ZlibDictForEntries(entries, certs);
-
- rv = deflateSetDictionary(
- &z, reinterpret_cast<const uint8_t*>(&zlib_dict[0]), zlib_dict.size());
- DCHECK_EQ(Z_OK, rv);
- if (rv != Z_OK) {
- return "";
- }
-
- compressed_size = deflateBound(&z, uncompressed_size);
- }
-
- const size_t entries_size = CertEntriesSize(entries);
-
- string result;
- result.resize(entries_size + (uncompressed_size > 0 ? 4 : 0) +
- compressed_size);
-
- uint8_t* j = reinterpret_cast<uint8_t*>(&result[0]);
- SerializeCertEntries(j, entries);
- j += entries_size;
-
- if (uncompressed_size == 0) {
- return result;
- }
-
- uint32_t uncompressed_size_32 = uncompressed_size;
- memcpy(j, &uncompressed_size_32, sizeof(uint32_t));
- j += sizeof(uint32_t);
-
- int rv;
-
- z.next_out = j;
- z.avail_out = compressed_size;
-
- for (size_t i = 0; i < certs.size(); i++) {
- if (entries[i].type != CertEntry::COMPRESSED) {
- continue;
- }
-
- uint32_t length32 = certs[i].size();
- z.next_in = reinterpret_cast<uint8_t*>(&length32);
- z.avail_in = sizeof(length32);
- rv = deflate(&z, Z_NO_FLUSH);
- DCHECK_EQ(Z_OK, rv);
- DCHECK_EQ(0u, z.avail_in);
- if (rv != Z_OK || z.avail_in) {
- return "";
- }
-
- z.next_in =
- const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(certs[i].data()));
- z.avail_in = certs[i].size();
- rv = deflate(&z, Z_NO_FLUSH);
- DCHECK_EQ(Z_OK, rv);
- DCHECK_EQ(0u, z.avail_in);
- if (rv != Z_OK || z.avail_in) {
- return "";
- }
- }
-
- z.avail_in = 0;
- rv = deflate(&z, Z_FINISH);
- DCHECK_EQ(Z_STREAM_END, rv);
- if (rv != Z_STREAM_END) {
- return "";
- }
-
- result.resize(result.size() - z.avail_out);
- return result;
-}
-
-// static
-bool CertCompressor::DecompressChain(StringPiece in,
- const vector<string>& cached_certs,
- const CommonCertSets* common_sets,
- vector<string>* out_certs) {
- vector<CertEntry> entries;
- if (!ParseEntries(&in, cached_certs, common_sets, &entries, out_certs)) {
- return false;
- }
- DCHECK_EQ(entries.size(), out_certs->size());
-
- std::unique_ptr<uint8_t[]> uncompressed_data;
- StringPiece uncompressed;
-
- if (!in.empty()) {
- if (in.size() < sizeof(uint32_t)) {
- return false;
- }
-
- uint32_t uncompressed_size;
- memcpy(&uncompressed_size, in.data(), sizeof(uncompressed_size));
- in.remove_prefix(sizeof(uint32_t));
-
- if (uncompressed_size > 128 * 1024) {
- return false;
- }
-
- uncompressed_data.reset(new uint8_t[uncompressed_size]);
- z_stream z;
- ScopedZLib scoped_z(ScopedZLib::INFLATE);
-
- memset(&z, 0, sizeof(z));
- z.next_out = uncompressed_data.get();
- z.avail_out = uncompressed_size;
- z.next_in =
- const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(in.data()));
- z.avail_in = in.size();
-
- if (Z_OK != inflateInit(&z)) {
- return false;
- }
- scoped_z.reset(&z);
-
- int rv = inflate(&z, Z_FINISH);
- if (rv == Z_NEED_DICT) {
- string zlib_dict = ZlibDictForEntries(entries, *out_certs);
- const uint8_t* dict = reinterpret_cast<const uint8_t*>(zlib_dict.data());
- if (Z_OK != inflateSetDictionary(&z, dict, zlib_dict.size())) {
- return false;
- }
- rv = inflate(&z, Z_FINISH);
- }
-
- if (Z_STREAM_END != rv || z.avail_out > 0 || z.avail_in > 0) {
- return false;
- }
-
- uncompressed = StringPiece(reinterpret_cast<char*>(uncompressed_data.get()),
- uncompressed_size);
- }
-
- for (size_t i = 0; i < entries.size(); i++) {
- switch (entries[i].type) {
- case CertEntry::COMPRESSED:
- if (uncompressed.size() < sizeof(uint32_t)) {
- return false;
- }
- uint32_t cert_len;
- memcpy(&cert_len, uncompressed.data(), sizeof(cert_len));
- uncompressed.remove_prefix(sizeof(uint32_t));
- if (uncompressed.size() < cert_len) {
- return false;
- }
- (*out_certs)[i] = uncompressed.substr(0, cert_len).as_string();
- uncompressed.remove_prefix(cert_len);
- break;
- case CertEntry::CACHED:
- case CertEntry::COMMON:
- break;
- }
- }
-
- if (!uncompressed.empty()) {
- return false;
- }
-
- return true;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/cert_compressor.h b/chromium/net/quic/crypto/cert_compressor.h
deleted file mode 100644
index c700f7ce616..00000000000
--- a/chromium/net/quic/crypto/cert_compressor.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2013 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_CRYPTO_CERT_COMPRESSOR_H_
-#define NET_QUIC_CRYPTO_CERT_COMPRESSOR_H_
-
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-#include "net/quic/crypto/common_cert_set.h"
-#include "net/quic/crypto/crypto_protocol.h"
-
-namespace net {
-
-// CertCompressor provides functions for compressing and decompressing
-// certificate chains using three techniquies:
-// 1) The peer may provide a list of a 64-bit, FNV-1a hashes of certificates
-// that they already have. In the event that one of them is to be
-// compressed, it can be replaced with just the hash.
-// 2) The peer may provide a number of hashes that represent sets of
-// pre-shared certificates (CommonCertSets). If one of those certificates
-// is to be compressed, and it's known to the given CommonCertSets, then it
-// can be replaced with a set hash and certificate index.
-// 3) Otherwise the certificates are compressed with zlib using a pre-shared
-// dictionary that consists of the certificates handled with the above
-// methods and a small chunk of common substrings.
-class NET_EXPORT_PRIVATE CertCompressor {
- public:
- // CompressChain compresses the certificates in |certs| and returns a
- // compressed representation. |common_sets| contains the common certificate
- // sets known locally and |client_common_set_hashes| contains the hashes of
- // the common sets known to the peer. |client_cached_cert_hashes| contains
- // 64-bit, FNV-1a hashes of certificates that the peer already possesses.
- static std::string CompressChain(const std::vector<std::string>& certs,
- base::StringPiece client_common_set_hashes,
- base::StringPiece client_cached_cert_hashes,
- const CommonCertSets* common_sets);
-
- // DecompressChain decompresses the result of |CompressChain|, given in |in|,
- // into a series of certificates that are written to |out_certs|.
- // |cached_certs| contains certificates that the peer may have omitted and
- // |common_sets| contains the common certificate sets known locally.
- static bool DecompressChain(base::StringPiece in,
- const std::vector<std::string>& cached_certs,
- const CommonCertSets* common_sets,
- std::vector<std::string>* out_certs);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CertCompressor);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_CERT_COMPRESSOR_H_
diff --git a/chromium/net/quic/crypto/cert_compressor_test.cc b/chromium/net/quic/crypto/cert_compressor_test.cc
deleted file mode 100644
index 0cd8c3eda22..00000000000
--- a/chromium/net/quic/crypto/cert_compressor_test.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright (c) 2013 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/crypto/cert_compressor.h"
-
-#include <memory>
-
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::StringPiece;
-using std::string;
-using std::vector;
-
-namespace net {
-namespace test {
-
-TEST(CertCompressor, EmptyChain) {
- vector<string> chain;
- const string compressed = CertCompressor::CompressChain(
- chain, StringPiece(), StringPiece(), nullptr);
- EXPECT_EQ("00", QuicUtils::HexEncode(compressed));
-
- vector<string> chain2, cached_certs;
- ASSERT_TRUE(CertCompressor::DecompressChain(compressed, cached_certs, nullptr,
- &chain2));
- EXPECT_EQ(chain.size(), chain2.size());
-}
-
-TEST(CertCompressor, Compressed) {
- vector<string> chain;
- chain.push_back("testcert");
- const string compressed = CertCompressor::CompressChain(
- chain, StringPiece(), StringPiece(), nullptr);
- ASSERT_GE(compressed.size(), 2u);
- EXPECT_EQ("0100", QuicUtils::HexEncode(compressed.substr(0, 2)));
-
- vector<string> chain2, cached_certs;
- ASSERT_TRUE(CertCompressor::DecompressChain(compressed, cached_certs, nullptr,
- &chain2));
- EXPECT_EQ(chain.size(), chain2.size());
- EXPECT_EQ(chain[0], chain2[0]);
-}
-
-TEST(CertCompressor, Common) {
- vector<string> chain;
- chain.push_back("testcert");
- static const uint64_t set_hash = 42;
- std::unique_ptr<CommonCertSets> common_sets(
- CryptoTestUtils::MockCommonCertSets(chain[0], set_hash, 1));
- const string compressed = CertCompressor::CompressChain(
- chain,
- StringPiece(reinterpret_cast<const char*>(&set_hash), sizeof(set_hash)),
- StringPiece(), common_sets.get());
- EXPECT_EQ(
- "03" /* common */
- "2A00000000000000" /* set hash 42 */
- "01000000" /* index 1 */
- "00" /* end of list */,
- QuicUtils::HexEncode(compressed));
-
- vector<string> chain2, cached_certs;
- ASSERT_TRUE(CertCompressor::DecompressChain(compressed, cached_certs,
- common_sets.get(), &chain2));
- EXPECT_EQ(chain.size(), chain2.size());
- EXPECT_EQ(chain[0], chain2[0]);
-}
-
-TEST(CertCompressor, Cached) {
- vector<string> chain;
- chain.push_back("testcert");
- uint64_t hash = QuicUtils::FNV1a_64_Hash(chain[0].data(), chain[0].size());
- StringPiece hash_bytes(reinterpret_cast<char*>(&hash), sizeof(hash));
- const string compressed =
- CertCompressor::CompressChain(chain, StringPiece(), hash_bytes, nullptr);
-
- EXPECT_EQ("02" /* cached */ + QuicUtils::HexEncode(hash_bytes) +
- "00" /* end of list */,
- QuicUtils::HexEncode(compressed));
-
- vector<string> cached_certs, chain2;
- cached_certs.push_back(chain[0]);
- ASSERT_TRUE(CertCompressor::DecompressChain(compressed, cached_certs, nullptr,
- &chain2));
- EXPECT_EQ(chain.size(), chain2.size());
- EXPECT_EQ(chain[0], chain2[0]);
-}
-
-TEST(CertCompressor, BadInputs) {
- vector<string> cached_certs, chain;
-
- EXPECT_FALSE(CertCompressor::DecompressChain(
- QuicUtils::HexEncode("04") /* bad entry type */, cached_certs, nullptr,
- &chain));
-
- EXPECT_FALSE(CertCompressor::DecompressChain(
- QuicUtils::HexEncode("01") /* no terminator */, cached_certs, nullptr,
- &chain));
-
- EXPECT_FALSE(CertCompressor::DecompressChain(
- QuicUtils::HexEncode("0200") /* hash truncated */, cached_certs, nullptr,
- &chain));
-
- EXPECT_FALSE(CertCompressor::DecompressChain(
- QuicUtils::HexEncode("0300") /* hash and index truncated */, cached_certs,
- nullptr, &chain));
-
- /* without a CommonCertSets */
- EXPECT_FALSE(
- CertCompressor::DecompressChain(QuicUtils::HexEncode("03"
- "0000000000000000"
- "00000000"),
- cached_certs, nullptr, &chain));
-
- std::unique_ptr<CommonCertSets> common_sets(
- CryptoTestUtils::MockCommonCertSets("foo", 42, 1));
-
- /* incorrect hash and index */
- EXPECT_FALSE(
- CertCompressor::DecompressChain(QuicUtils::HexEncode("03"
- "a200000000000000"
- "00000000"),
- cached_certs, nullptr, &chain));
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/chacha20_poly1305_decrypter.cc b/chromium/net/quic/crypto/chacha20_poly1305_decrypter.cc
deleted file mode 100644
index ccd1c242a33..00000000000
--- a/chromium/net/quic/crypto/chacha20_poly1305_decrypter.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/crypto/chacha20_poly1305_decrypter.h"
-
-#include <openssl/evp.h>
-#include <openssl/tls1.h>
-
-namespace net {
-
-namespace {
-
-const size_t kKeySize = 32;
-const size_t kNoncePrefixSize = 4;
-
-} // namespace
-
-ChaCha20Poly1305Decrypter::ChaCha20Poly1305Decrypter()
- : AeadBaseDecrypter(EVP_aead_chacha20_poly1305(),
- kKeySize,
- kAuthTagSize,
- kNoncePrefixSize) {
- static_assert(kKeySize <= kMaxKeySize, "key size too big");
- static_assert(kNoncePrefixSize <= kMaxNoncePrefixSize,
- "nonce prefix size too big");
-}
-
-ChaCha20Poly1305Decrypter::~ChaCha20Poly1305Decrypter() {}
-
-const char* ChaCha20Poly1305Decrypter::cipher_name() const {
- return TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305;
-}
-
-uint32_t ChaCha20Poly1305Decrypter::cipher_id() const {
- return TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/chacha20_poly1305_decrypter.h b/chromium/net/quic/crypto/chacha20_poly1305_decrypter.h
deleted file mode 100644
index a75556e1747..00000000000
--- a/chromium/net/quic/crypto/chacha20_poly1305_decrypter.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_CRYPTO_CHACHA20_POLY1305_DECRYPTER_H_
-#define NET_QUIC_CRYPTO_CHACHA20_POLY1305_DECRYPTER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "net/quic/crypto/aead_base_decrypter.h"
-
-namespace net {
-
-// A ChaCha20Poly1305Decrypter is a QuicDecrypter that implements the
-// AEAD_CHACHA20_POLY1305 algorithm specified in
-// draft-agl-tls-chacha20poly1305-04, except that it truncates the Poly1305
-// authenticator to 12 bytes. Create an instance by calling
-// QuicDecrypter::Create(kCC12).
-//
-// It uses an authentication tag of 16 bytes (128 bits). There is no
-// fixed nonce prefix.
-class NET_EXPORT_PRIVATE ChaCha20Poly1305Decrypter : public AeadBaseDecrypter {
- public:
- enum {
- kAuthTagSize = 12,
- };
-
- ChaCha20Poly1305Decrypter();
- ~ChaCha20Poly1305Decrypter() override;
-
- const char* cipher_name() const override;
- uint32_t cipher_id() const override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ChaCha20Poly1305Decrypter);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_CHACHA20_POLY1305_DECRYPTER_H_
diff --git a/chromium/net/quic/crypto/chacha20_poly1305_decrypter_test.cc b/chromium/net/quic/crypto/chacha20_poly1305_decrypter_test.cc
deleted file mode 100644
index af157655d16..00000000000
--- a/chromium/net/quic/crypto/chacha20_poly1305_decrypter_test.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/crypto/chacha20_poly1305_decrypter.h"
-
-#include <memory>
-
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace {
-
-// The test vectors come from RFC 7539 Section 2.8.2.
-
-// Each test vector consists of six strings of lowercase hexadecimal digits.
-// The strings may be empty (zero length). A test vector with a nullptr |key|
-// marks the end of an array of test vectors.
-struct TestVector {
- // Input:
- const char* key;
- const char* iv;
- const char* fixed;
- const char* aad;
- const char* ct;
-
- // Expected output:
- const char* pt; // An empty string "" means decryption succeeded and
- // the plaintext is zero-length. nullptr means decryption
- // failed.
-};
-
-const TestVector test_vectors[] = {
- {"808182838485868788898a8b8c8d8e8f"
- "909192939495969798999a9b9c9d9e9f",
-
- "4041424344454647",
-
- "07000000",
-
- "50515253c0c1c2c3c4c5c6c7",
-
- "d31a8d34648e60db7b86afbc53ef7ec2"
- "a4aded51296e08fea9e2b5a736ee62d6"
- "3dbea45e8ca9671282fafb69da92728b"
- "1a71de0a9e060b2905d6a5b67ecd3b36"
- "92ddbd7f2d778b8c9803aee328091b58"
- "fab324e4fad675945585808b4831d7bc"
- "3ff4def08e4b7a9de576d26586cec64b"
- "6116"
- "1ae10b594f09e26a7e902ecb", // "d0600691" truncated
-
- "4c616469657320616e642047656e746c"
- "656d656e206f662074686520636c6173"
- "73206f66202739393a20496620492063"
- "6f756c64206f6666657220796f75206f"
- "6e6c79206f6e652074697020666f7220"
- "746865206675747572652c2073756e73"
- "637265656e20776f756c642062652069"
- "742e"},
- // Modify the ciphertext (Poly1305 authenticator).
- {"808182838485868788898a8b8c8d8e8f"
- "909192939495969798999a9b9c9d9e9f",
-
- "4041424344454647",
-
- "07000000",
-
- "50515253c0c1c2c3c4c5c6c7",
-
- "d31a8d34648e60db7b86afbc53ef7ec2"
- "a4aded51296e08fea9e2b5a736ee62d6"
- "3dbea45e8ca9671282fafb69da92728b"
- "1a71de0a9e060b2905d6a5b67ecd3b36"
- "92ddbd7f2d778b8c9803aee328091b58"
- "fab324e4fad675945585808b4831d7bc"
- "3ff4def08e4b7a9de576d26586cec64b"
- "6116"
- "1ae10b594f09e26a7e902ecc", // "d0600691" truncated
-
- nullptr},
- // Modify the associated data.
- {"808182838485868788898a8b8c8d8e8f"
- "909192939495969798999a9b9c9d9e9f",
-
- "4041424344454647",
-
- "07000000",
-
- "60515253c0c1c2c3c4c5c6c7",
-
- "d31a8d34648e60db7b86afbc53ef7ec2"
- "a4aded51296e08fea9e2b5a736ee62d6"
- "3dbea45e8ca9671282fafb69da92728b"
- "1a71de0a9e060b2905d6a5b67ecd3b36"
- "92ddbd7f2d778b8c9803aee328091b58"
- "fab324e4fad675945585808b4831d7bc"
- "3ff4def08e4b7a9de576d26586cec64b"
- "6116"
- "1ae10b594f09e26a7e902ecb", // "d0600691" truncated
-
- nullptr},
- {nullptr}};
-
-} // namespace
-
-namespace net {
-namespace test {
-
-// DecryptWithNonce wraps the |Decrypt| method of |decrypter| to allow passing
-// in an nonce and also to allocate the buffer needed for the plaintext.
-QuicData* DecryptWithNonce(ChaCha20Poly1305Decrypter* decrypter,
- StringPiece nonce,
- StringPiece associated_data,
- StringPiece ciphertext) {
- QuicPathId path_id = kDefaultPathId;
- QuicPacketNumber packet_number;
- StringPiece nonce_prefix(nonce.data(), nonce.size() - sizeof(packet_number));
- decrypter->SetNoncePrefix(nonce_prefix);
- memcpy(&packet_number, nonce.data() + nonce_prefix.size(),
- sizeof(packet_number));
- path_id = static_cast<QuicPathId>(
- packet_number >> 8 * (sizeof(packet_number) - sizeof(path_id)));
- packet_number &= UINT64_C(0x00FFFFFFFFFFFFFF);
- std::unique_ptr<char[]> output(new char[ciphertext.length()]);
- size_t output_length = 0;
- const bool success = decrypter->DecryptPacket(
- path_id, packet_number, associated_data, ciphertext, output.get(),
- &output_length, ciphertext.length());
- if (!success) {
- return nullptr;
- }
- return new QuicData(output.release(), output_length, true);
-}
-
-TEST(ChaCha20Poly1305DecrypterTest, Decrypt) {
- for (size_t i = 0; test_vectors[i].key != nullptr; i++) {
- // If not present then decryption is expected to fail.
- bool has_pt = test_vectors[i].pt;
-
- // Decode the test vector.
- string key = QuicUtils::HexDecode(test_vectors[i].key);
- string iv = QuicUtils::HexDecode(test_vectors[i].iv);
- string fixed = QuicUtils::HexDecode(test_vectors[i].fixed);
- string aad = QuicUtils::HexDecode(test_vectors[i].aad);
- string ct = QuicUtils::HexDecode(test_vectors[i].ct);
- string pt;
- if (has_pt) {
- pt = QuicUtils::HexDecode(test_vectors[i].pt);
- }
-
- ChaCha20Poly1305Decrypter decrypter;
- ASSERT_TRUE(decrypter.SetKey(key));
- std::unique_ptr<QuicData> decrypted(DecryptWithNonce(
- &decrypter, fixed + iv,
- // This deliberately tests that the decrypter can handle an AAD that
- // is set to nullptr, as opposed to a zero-length, non-nullptr pointer.
- StringPiece(aad.length() ? aad.data() : nullptr, aad.length()), ct));
- if (!decrypted.get()) {
- EXPECT_FALSE(has_pt);
- continue;
- }
- EXPECT_TRUE(has_pt);
-
- EXPECT_EQ(12u, ct.size() - decrypted->length());
- ASSERT_EQ(pt.length(), decrypted->length());
- test::CompareCharArraysWithHexError("plaintext", decrypted->data(),
- pt.length(), pt.data(), pt.length());
- }
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/chacha20_poly1305_encrypter.cc b/chromium/net/quic/crypto/chacha20_poly1305_encrypter.cc
deleted file mode 100644
index b438109724b..00000000000
--- a/chromium/net/quic/crypto/chacha20_poly1305_encrypter.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/crypto/chacha20_poly1305_encrypter.h"
-
-#include <openssl/evp.h>
-
-namespace net {
-
-namespace {
-
-const size_t kKeySize = 32;
-const size_t kNoncePrefixSize = 4;
-
-} // namespace
-
-ChaCha20Poly1305Encrypter::ChaCha20Poly1305Encrypter()
- : AeadBaseEncrypter(EVP_aead_chacha20_poly1305(),
- kKeySize,
- kAuthTagSize,
- kNoncePrefixSize) {
- static_assert(kKeySize <= kMaxKeySize, "key size too big");
- static_assert(kNoncePrefixSize <= kMaxNoncePrefixSize,
- "nonce prefix size too big");
-}
-
-ChaCha20Poly1305Encrypter::~ChaCha20Poly1305Encrypter() {}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/chacha20_poly1305_encrypter.h b/chromium/net/quic/crypto/chacha20_poly1305_encrypter.h
deleted file mode 100644
index eb4afdde5ca..00000000000
--- a/chromium/net/quic/crypto/chacha20_poly1305_encrypter.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_CRYPTO_CHACHA20_POLY1305_ENCRYPTER_H_
-#define NET_QUIC_CRYPTO_CHACHA20_POLY1305_ENCRYPTER_H_
-
-#include <stddef.h>
-
-#include "base/macros.h"
-#include "net/quic/crypto/aead_base_encrypter.h"
-
-namespace net {
-
-// A ChaCha20Poly1305Encrypter is a QuicEncrypter that implements the
-// AEAD_CHACHA20_POLY1305 algorithm specified in
-// draft-agl-tls-chacha20poly1305-04, except that it truncates the Poly1305
-// authenticator to 12 bytes. Create an instance by calling
-// QuicEncrypter::Create(kCC12).
-//
-// It uses an authentication tag of 16 bytes (128 bits). There is no
-// fixed nonce prefix.
-class NET_EXPORT_PRIVATE ChaCha20Poly1305Encrypter : public AeadBaseEncrypter {
- public:
- enum {
- kAuthTagSize = 12,
- };
-
- ChaCha20Poly1305Encrypter();
- ~ChaCha20Poly1305Encrypter() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ChaCha20Poly1305Encrypter);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_CHACHA20_POLY1305_ENCRYPTER_H_
diff --git a/chromium/net/quic/crypto/chacha20_poly1305_encrypter_test.cc b/chromium/net/quic/crypto/chacha20_poly1305_encrypter_test.cc
deleted file mode 100644
index c4b13d85131..00000000000
--- a/chromium/net/quic/crypto/chacha20_poly1305_encrypter_test.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/crypto/chacha20_poly1305_encrypter.h"
-
-#include <memory>
-
-#include "net/quic/crypto/chacha20_poly1305_decrypter.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace {
-
-// The test vectors come from RFC 7539 Section 2.8.2.
-
-// Each test vector consists of five strings of lowercase hexadecimal digits.
-// The strings may be empty (zero length). A test vector with a nullptr |key|
-// marks the end of an array of test vectors.
-struct TestVector {
- const char* key;
- const char* pt;
- const char* iv;
- const char* fixed;
- const char* aad;
- const char* ct;
-};
-
-const TestVector test_vectors[] = {
- {
- "808182838485868788898a8b8c8d8e8f"
- "909192939495969798999a9b9c9d9e9f",
-
- "4c616469657320616e642047656e746c"
- "656d656e206f662074686520636c6173"
- "73206f66202739393a20496620492063"
- "6f756c64206f6666657220796f75206f"
- "6e6c79206f6e652074697020666f7220"
- "746865206675747572652c2073756e73"
- "637265656e20776f756c642062652069"
- "742e",
-
- "4041424344454647",
-
- "07000000",
-
- "50515253c0c1c2c3c4c5c6c7",
-
- "d31a8d34648e60db7b86afbc53ef7ec2"
- "a4aded51296e08fea9e2b5a736ee62d6"
- "3dbea45e8ca9671282fafb69da92728b"
- "1a71de0a9e060b2905d6a5b67ecd3b36"
- "92ddbd7f2d778b8c9803aee328091b58"
- "fab324e4fad675945585808b4831d7bc"
- "3ff4def08e4b7a9de576d26586cec64b"
- "6116"
- "1ae10b594f09e26a7e902ecb", // "d0600691" truncated
- },
- {nullptr}};
-
-} // namespace
-
-namespace net {
-namespace test {
-
-// EncryptWithNonce wraps the |Encrypt| method of |encrypter| to allow passing
-// in an nonce and also to allocate the buffer needed for the ciphertext.
-QuicData* EncryptWithNonce(ChaCha20Poly1305Encrypter* encrypter,
- StringPiece nonce,
- StringPiece associated_data,
- StringPiece plaintext) {
- size_t ciphertext_size = encrypter->GetCiphertextSize(plaintext.length());
- std::unique_ptr<char[]> ciphertext(new char[ciphertext_size]);
-
- if (!encrypter->Encrypt(nonce, associated_data, plaintext,
- reinterpret_cast<unsigned char*>(ciphertext.get()))) {
- return nullptr;
- }
-
- return new QuicData(ciphertext.release(), ciphertext_size, true);
-}
-
-TEST(ChaCha20Poly1305EncrypterTest, EncryptThenDecrypt) {
- ChaCha20Poly1305Encrypter encrypter;
- ChaCha20Poly1305Decrypter decrypter;
-
- string key = QuicUtils::HexDecode(test_vectors[0].key);
- ASSERT_TRUE(encrypter.SetKey(key));
- ASSERT_TRUE(decrypter.SetKey(key));
- ASSERT_TRUE(encrypter.SetNoncePrefix("abcd"));
- ASSERT_TRUE(decrypter.SetNoncePrefix("abcd"));
-
- QuicPathId path_id = 0x42;
- QuicPacketNumber packet_number = UINT64_C(0x123456789ABC);
- string associated_data = "associated_data";
- string plaintext = "plaintext";
- char encrypted[1024];
- size_t len;
- ASSERT_TRUE(encrypter.EncryptPacket(path_id, packet_number, associated_data,
- plaintext, encrypted, &len,
- arraysize(encrypted)));
- StringPiece ciphertext(encrypted, len);
- char decrypted[1024];
- ASSERT_TRUE(decrypter.DecryptPacket(path_id, packet_number, associated_data,
- ciphertext, decrypted, &len,
- arraysize(decrypted)));
-}
-
-TEST(ChaCha20Poly1305EncrypterTest, Encrypt) {
- for (size_t i = 0; test_vectors[i].key != nullptr; i++) {
- // Decode the test vector.
- string key = QuicUtils::HexDecode(test_vectors[i].key);
- string pt = QuicUtils::HexDecode(test_vectors[i].pt);
- string iv = QuicUtils::HexDecode(test_vectors[i].iv);
- string fixed = QuicUtils::HexDecode(test_vectors[i].fixed);
- string aad = QuicUtils::HexDecode(test_vectors[i].aad);
- string ct = QuicUtils::HexDecode(test_vectors[i].ct);
-
- ChaCha20Poly1305Encrypter encrypter;
- ASSERT_TRUE(encrypter.SetKey(key));
- std::unique_ptr<QuicData> encrypted(EncryptWithNonce(
- &encrypter, fixed + iv,
- // This deliberately tests that the encrypter can handle an AAD that
- // is set to nullptr, as opposed to a zero-length, non-nullptr pointer.
- StringPiece(aad.length() ? aad.data() : nullptr, aad.length()), pt));
- ASSERT_TRUE(encrypted.get());
- EXPECT_EQ(12u, ct.size() - pt.size());
- EXPECT_EQ(12u, encrypted->length() - pt.size());
-
- test::CompareCharArraysWithHexError("ciphertext", encrypted->data(),
- encrypted->length(), ct.data(),
- ct.length());
- }
-}
-
-TEST(ChaCha20Poly1305EncrypterTest, GetMaxPlaintextSize) {
- ChaCha20Poly1305Encrypter encrypter;
- EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1012));
- EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(112));
- EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(22));
-}
-
-TEST(ChaCha20Poly1305EncrypterTest, GetCiphertextSize) {
- ChaCha20Poly1305Encrypter encrypter;
- EXPECT_EQ(1012u, encrypter.GetCiphertextSize(1000));
- EXPECT_EQ(112u, encrypter.GetCiphertextSize(100));
- EXPECT_EQ(22u, encrypter.GetCiphertextSize(10));
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/channel_id.cc b/chromium/net/quic/crypto/channel_id.cc
deleted file mode 100644
index 3d93be0ab87..00000000000
--- a/chromium/net/quic/crypto/channel_id.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2013 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/crypto/channel_id.h"
-
-#include <openssl/bn.h>
-#include <openssl/ec.h>
-#include <openssl/ecdsa.h>
-#include <openssl/obj_mac.h>
-#include <openssl/sha.h>
-
-#include "crypto/openssl_util.h"
-#include "crypto/scoped_openssl_types.h"
-
-using base::StringPiece;
-
-namespace net {
-
-// static
-const char ChannelIDVerifier::kContextStr[] = "QUIC ChannelID";
-// static
-const char ChannelIDVerifier::kClientToServerStr[] = "client -> server";
-
-// static
-bool ChannelIDVerifier::Verify(StringPiece key,
- StringPiece signed_data,
- StringPiece signature) {
- return VerifyRaw(key, signed_data, signature, true);
-}
-
-// static
-bool ChannelIDVerifier::VerifyRaw(StringPiece key,
- StringPiece signed_data,
- StringPiece signature,
- bool is_channel_id_signature) {
- if (key.size() != 32 * 2 || signature.size() != 32 * 2) {
- return false;
- }
-
- crypto::ScopedEC_GROUP p256(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
- if (!p256) {
- return false;
- }
-
- crypto::ScopedBIGNUM x(BN_new()), y(BN_new()), r(BN_new()), s(BN_new());
-
- ECDSA_SIG sig;
- sig.r = r.get();
- sig.s = s.get();
-
- const uint8_t* key_bytes = reinterpret_cast<const uint8_t*>(key.data());
- const uint8_t* signature_bytes =
- reinterpret_cast<const uint8_t*>(signature.data());
-
- if (BN_bin2bn(key_bytes + 0, 32, x.get()) == nullptr ||
- BN_bin2bn(key_bytes + 32, 32, y.get()) == nullptr ||
- BN_bin2bn(signature_bytes + 0, 32, sig.r) == nullptr ||
- BN_bin2bn(signature_bytes + 32, 32, sig.s) == nullptr) {
- return false;
- }
-
- crypto::ScopedEC_POINT point(EC_POINT_new(p256.get()));
- if (!point ||
- !EC_POINT_set_affine_coordinates_GFp(p256.get(), point.get(), x.get(),
- y.get(), nullptr)) {
- return false;
- }
-
- crypto::ScopedEC_KEY ecdsa_key(EC_KEY_new());
- if (ecdsa_key.get() == nullptr ||
- !EC_KEY_set_group(ecdsa_key.get(), p256.get()) ||
- !EC_KEY_set_public_key(ecdsa_key.get(), point.get())) {
- return false;
- }
-
- SHA256_CTX sha256;
- SHA256_Init(&sha256);
- if (is_channel_id_signature) {
- SHA256_Update(&sha256, kContextStr, strlen(kContextStr) + 1);
- SHA256_Update(&sha256, kClientToServerStr, strlen(kClientToServerStr) + 1);
- }
- SHA256_Update(&sha256, signed_data.data(), signed_data.size());
-
- unsigned char digest[SHA256_DIGEST_LENGTH];
- SHA256_Final(digest, &sha256);
-
- return ECDSA_do_verify(digest, sizeof(digest), &sig, ecdsa_key.get()) == 1;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/channel_id.h b/chromium/net/quic/crypto/channel_id.h
deleted file mode 100644
index cb2632fd5d9..00000000000
--- a/chromium/net/quic/crypto/channel_id.h
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2013 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_CRYPTO_CHANNEL_ID_H_
-#define NET_QUIC_CRYPTO_CHANNEL_ID_H_
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_types.h"
-
-namespace net {
-
-// ChannelIDKey is an interface that supports signing with and serializing a
-// ChannelID key.
-class NET_EXPORT_PRIVATE ChannelIDKey {
- public:
- virtual ~ChannelIDKey() {}
-
- // Sign signs |signed_data| using the ChannelID private key and puts the
- // signature into |out_signature|. It returns true on success.
- virtual bool Sign(base::StringPiece signed_data,
- std::string* out_signature) const = 0;
-
- // SerializeKey returns the serialized ChannelID public key.
- virtual std::string SerializeKey() const = 0;
-};
-
-// ChannelIDSourceCallback provides a generic mechanism for a ChannelIDSource
-// to call back after an asynchronous GetChannelIDKey operation.
-class ChannelIDSourceCallback {
- public:
- virtual ~ChannelIDSourceCallback() {}
-
- // Run is called on the original thread to mark the completion of an
- // asynchonous GetChannelIDKey operation. If |*channel_id_key| is not nullptr
- // then the channel ID lookup is successful. |Run| may take ownership of
- // |*channel_id_key| by calling |release| on it.
- virtual void Run(std::unique_ptr<ChannelIDKey>* channel_id_key) = 0;
-};
-
-// ChannelIDSource is an abstract interface by which a QUIC client can obtain
-// a ChannelIDKey for a given hostname.
-class NET_EXPORT_PRIVATE ChannelIDSource {
- public:
- virtual ~ChannelIDSource() {}
-
- // GetChannelIDKey looks up the ChannelIDKey for |hostname|. On success it
- // returns QUIC_SUCCESS and stores the ChannelIDKey in |*channel_id_key|,
- // which the caller takes ownership of. On failure, it returns QUIC_FAILURE.
- //
- // This function may also return QUIC_PENDING, in which case the
- // ChannelIDSource will call back, on the original thread, via |callback|
- // when complete. In this case, the ChannelIDSource will take ownership of
- // |callback|.
- virtual QuicAsyncStatus GetChannelIDKey(
- const std::string& hostname,
- std::unique_ptr<ChannelIDKey>* channel_id_key,
- ChannelIDSourceCallback* callback) = 0;
-};
-
-// ChannelIDVerifier verifies ChannelID signatures.
-class NET_EXPORT_PRIVATE ChannelIDVerifier {
- public:
- // kContextStr is prepended to the data to be signed in order to ensure that
- // a ChannelID signature cannot be used in a different context. (The
- // terminating NUL byte is inclued.)
- static const char kContextStr[];
- // kClientToServerStr follows kContextStr to specify that the ChannelID is
- // being used in the client to server direction. (The terminating NUL byte is
- // included.)
- static const char kClientToServerStr[];
-
- // Verify returns true iff |signature| is a valid signature of |signed_data|
- // by |key|.
- static bool Verify(base::StringPiece key,
- base::StringPiece signed_data,
- base::StringPiece signature);
-
- // FOR TESTING ONLY: VerifyRaw returns true iff |signature| is a valid
- // signature of |signed_data| by |key|. |is_channel_id_signature| indicates
- // whether |signature| is a ChannelID signature (with kContextStr prepended
- // to the data to be signed).
- static bool VerifyRaw(base::StringPiece key,
- base::StringPiece signed_data,
- base::StringPiece signature,
- bool is_channel_id_signature);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ChannelIDVerifier);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_CHANNEL_ID_H_
diff --git a/chromium/net/quic/crypto/channel_id_chromium.cc b/chromium/net/quic/crypto/channel_id_chromium.cc
deleted file mode 100644
index f17a6900b97..00000000000
--- a/chromium/net/quic/crypto/channel_id_chromium.cc
+++ /dev/null
@@ -1,224 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/crypto/channel_id_chromium.h"
-
-#include <utility>
-#include <vector>
-
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-#include "crypto/ec_private_key.h"
-#include "crypto/ec_signature_creator.h"
-#include "net/base/net_errors.h"
-#include "net/cert/asn1_util.h"
-#include "net/ssl/channel_id_service.h"
-
-namespace net {
-
-ChannelIDKeyChromium::ChannelIDKeyChromium(
- std::unique_ptr<crypto::ECPrivateKey> ec_private_key)
- : ec_private_key_(std::move(ec_private_key)) {}
-
-ChannelIDKeyChromium::~ChannelIDKeyChromium() {}
-
-bool ChannelIDKeyChromium::Sign(base::StringPiece signed_data,
- std::string* out_signature) const {
- std::unique_ptr<crypto::ECSignatureCreator> sig_creator(
- crypto::ECSignatureCreator::Create(ec_private_key_.get()));
- if (!sig_creator) {
- return false;
- }
- const size_t len1 = strlen(ChannelIDVerifier::kContextStr) + 1;
- const size_t len2 = strlen(ChannelIDVerifier::kClientToServerStr) + 1;
- std::vector<uint8_t> data(len1 + len2 + signed_data.size());
- memcpy(&data[0], ChannelIDVerifier::kContextStr, len1);
- memcpy(&data[len1], ChannelIDVerifier::kClientToServerStr, len2);
- memcpy(&data[len1 + len2], signed_data.data(), signed_data.size());
- std::vector<uint8_t> der_signature;
- if (!sig_creator->Sign(&data[0], data.size(), &der_signature)) {
- return false;
- }
- std::vector<uint8_t> raw_signature;
- if (!sig_creator->DecodeSignature(der_signature, &raw_signature)) {
- return false;
- }
- memcpy(base::WriteInto(out_signature, raw_signature.size() + 1),
- &raw_signature[0], raw_signature.size());
- return true;
-}
-
-std::string ChannelIDKeyChromium::SerializeKey() const {
- std::string out_key;
- if (!ec_private_key_->ExportRawPublicKey(&out_key)) {
- return std::string();
- }
- return out_key;
-}
-
-// A Job handles the lookup of a single channel ID. It is owned by the
-// ChannelIDSource. If the operation can not complete synchronously, it will
-// notify the ChannelIDSource upon completion.
-class ChannelIDSourceChromium::Job {
- public:
- Job(ChannelIDSourceChromium* channel_id_source,
- ChannelIDService* channel_id_service);
-
- // Starts the channel ID lookup. If |QUIC_PENDING| is returned, then
- // |callback| will be invoked asynchronously when the operation completes.
- QuicAsyncStatus GetChannelIDKey(const std::string& hostname,
- std::unique_ptr<ChannelIDKey>* channel_id_key,
- ChannelIDSourceCallback* callback);
-
- private:
- enum State {
- STATE_NONE,
- STATE_GET_CHANNEL_ID_KEY,
- STATE_GET_CHANNEL_ID_KEY_COMPLETE,
- };
-
- int DoLoop(int last_io_result);
- void OnIOComplete(int result);
- int DoGetChannelIDKey(int result);
- int DoGetChannelIDKeyComplete(int result);
-
- // Channel ID source to notify when this jobs completes.
- ChannelIDSourceChromium* const channel_id_source_;
-
- ChannelIDService* const channel_id_service_;
-
- std::unique_ptr<crypto::ECPrivateKey> channel_id_crypto_key_;
- ChannelIDService::Request channel_id_request_;
-
- // |hostname| specifies the hostname for which we need a channel ID.
- std::string hostname_;
-
- std::unique_ptr<ChannelIDSourceCallback> callback_;
-
- std::unique_ptr<ChannelIDKey> channel_id_key_;
-
- State next_state_;
-
- DISALLOW_COPY_AND_ASSIGN(Job);
-};
-
-ChannelIDSourceChromium::Job::Job(ChannelIDSourceChromium* channel_id_source,
- ChannelIDService* channel_id_service)
- : channel_id_source_(channel_id_source),
- channel_id_service_(channel_id_service),
- next_state_(STATE_NONE) {}
-
-QuicAsyncStatus ChannelIDSourceChromium::Job::GetChannelIDKey(
- const std::string& hostname,
- std::unique_ptr<ChannelIDKey>* channel_id_key,
- ChannelIDSourceCallback* callback) {
- DCHECK(channel_id_key);
- DCHECK(callback);
-
- if (STATE_NONE != next_state_) {
- DLOG(DFATAL) << "GetChannelIDKey has begun";
- return QUIC_FAILURE;
- }
-
- channel_id_key_.reset();
-
- hostname_ = hostname;
-
- next_state_ = STATE_GET_CHANNEL_ID_KEY;
- switch (DoLoop(OK)) {
- case OK:
- channel_id_key->reset(channel_id_key_.release());
- return QUIC_SUCCESS;
- case ERR_IO_PENDING:
- callback_.reset(callback);
- return QUIC_PENDING;
- default:
- channel_id_key->reset();
- return QUIC_FAILURE;
- }
-}
-
-int ChannelIDSourceChromium::Job::DoLoop(int last_result) {
- int rv = last_result;
- do {
- State state = next_state_;
- next_state_ = STATE_NONE;
- switch (state) {
- case STATE_GET_CHANNEL_ID_KEY:
- DCHECK(rv == OK);
- rv = DoGetChannelIDKey(rv);
- break;
- case STATE_GET_CHANNEL_ID_KEY_COMPLETE:
- rv = DoGetChannelIDKeyComplete(rv);
- break;
- case STATE_NONE:
- default:
- rv = ERR_UNEXPECTED;
- LOG(DFATAL) << "unexpected state " << state;
- break;
- }
- } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
- return rv;
-}
-
-void ChannelIDSourceChromium::Job::OnIOComplete(int result) {
- int rv = DoLoop(result);
- if (rv != ERR_IO_PENDING) {
- std::unique_ptr<ChannelIDSourceCallback> callback(callback_.release());
- callback->Run(&channel_id_key_);
- // Will delete |this|.
- channel_id_source_->OnJobComplete(this);
- }
-}
-
-int ChannelIDSourceChromium::Job::DoGetChannelIDKey(int result) {
- next_state_ = STATE_GET_CHANNEL_ID_KEY_COMPLETE;
-
- return channel_id_service_->GetOrCreateChannelID(
- hostname_, &channel_id_crypto_key_,
- base::Bind(&ChannelIDSourceChromium::Job::OnIOComplete,
- base::Unretained(this)),
- &channel_id_request_);
-}
-
-int ChannelIDSourceChromium::Job::DoGetChannelIDKeyComplete(int result) {
- DCHECK_EQ(STATE_NONE, next_state_);
- if (result != OK) {
- DLOG(WARNING) << "Failed to look up channel ID: " << ErrorToString(result);
- return result;
- }
-
- DCHECK(channel_id_crypto_key_);
- channel_id_key_.reset(
- new ChannelIDKeyChromium(std::move(channel_id_crypto_key_)));
- return result;
-}
-
-ChannelIDSourceChromium::ChannelIDSourceChromium(
- ChannelIDService* channel_id_service)
- : channel_id_service_(channel_id_service) {}
-
-ChannelIDSourceChromium::~ChannelIDSourceChromium() {
- STLDeleteElements(&active_jobs_);
-}
-
-QuicAsyncStatus ChannelIDSourceChromium::GetChannelIDKey(
- const std::string& hostname,
- std::unique_ptr<ChannelIDKey>* channel_id_key,
- ChannelIDSourceCallback* callback) {
- std::unique_ptr<Job> job(new Job(this, channel_id_service_));
- QuicAsyncStatus status =
- job->GetChannelIDKey(hostname, channel_id_key, callback);
- if (status == QUIC_PENDING) {
- active_jobs_.insert(job.release());
- }
- return status;
-}
-
-void ChannelIDSourceChromium::OnJobComplete(Job* job) {
- active_jobs_.erase(job);
- delete job;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/channel_id_chromium.h b/chromium/net/quic/crypto/channel_id_chromium.h
deleted file mode 100644
index 7e696beea69..00000000000
--- a/chromium/net/quic/crypto/channel_id_chromium.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_CRYPTO_CHANNEL_ID_CHROMIUM_H_
-#define NET_QUIC_CRYPTO_CHANNEL_ID_CHROMIUM_H_
-
-#include <set>
-#include <string>
-
-#include "base/macros.h"
-#include "net/quic/crypto/channel_id.h"
-
-namespace crypto {
-class ECPrivateKey;
-} // namespace crypto
-
-namespace net {
-
-class ChannelIDService;
-
-class NET_EXPORT_PRIVATE ChannelIDKeyChromium : public ChannelIDKey {
- public:
- explicit ChannelIDKeyChromium(
- std::unique_ptr<crypto::ECPrivateKey> ec_private_key);
- ~ChannelIDKeyChromium() override;
-
- // ChannelIDKey interface
- bool Sign(base::StringPiece signed_data,
- std::string* out_signature) const override;
- std::string SerializeKey() const override;
-
- private:
- std::unique_ptr<crypto::ECPrivateKey> ec_private_key_;
-};
-
-// ChannelIDSourceChromium implements the QUIC ChannelIDSource interface.
-class ChannelIDSourceChromium : public ChannelIDSource {
- public:
- explicit ChannelIDSourceChromium(ChannelIDService* channel_id_service);
- ~ChannelIDSourceChromium() override;
-
- // ChannelIDSource interface
- QuicAsyncStatus GetChannelIDKey(const std::string& hostname,
- std::unique_ptr<ChannelIDKey>* channel_id_key,
- ChannelIDSourceCallback* callback) override;
-
- private:
- class Job;
- typedef std::set<Job*> JobSet;
-
- void OnJobComplete(Job* job);
-
- // Set owning pointers to active jobs.
- JobSet active_jobs_;
-
- // The service for retrieving Channel ID keys.
- ChannelIDService* const channel_id_service_;
-
- DISALLOW_COPY_AND_ASSIGN(ChannelIDSourceChromium);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_CHANNEL_ID_CHROMIUM_H_
diff --git a/chromium/net/quic/crypto/channel_id_test.cc b/chromium/net/quic/crypto/channel_id_test.cc
deleted file mode 100644
index bc1ca44a8a0..00000000000
--- a/chromium/net/quic/crypto/channel_id_test.cc
+++ /dev/null
@@ -1,274 +0,0 @@
-// Copyright 2013 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/crypto/channel_id.h"
-
-#include <memory>
-
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-namespace test {
-
-namespace {
-
-// The following ECDSA signature verification test vectors for P-256,SHA-256
-// come from the SigVer.rsp file in
-// http://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip
-// downloaded on 2013-06-11.
-struct TestVector {
- // Input:
- const char* msg;
- const char* qx;
- const char* qy;
- const char* r;
- const char* s;
-
- // Expected output:
- bool result; // true means "P", false means "F"
-};
-
-const TestVector test_vector[] = {
- {
- "e4796db5f785f207aa30d311693b3702821dff1168fd2e04c0836825aefd850d"
- "9aa60326d88cde1a23c7745351392ca2288d632c264f197d05cd424a30336c19"
- "fd09bb229654f0222fcb881a4b35c290a093ac159ce13409111ff0358411133c"
- "24f5b8e2090d6db6558afc36f06ca1f6ef779785adba68db27a409859fc4c4a0",
- "87f8f2b218f49845f6f10eec3877136269f5c1a54736dbdf69f89940cad41555",
- "e15f369036f49842fac7a86c8a2b0557609776814448b8f5e84aa9f4395205e9",
- "d19ff48b324915576416097d2544f7cbdf8768b1454ad20e0baac50e211f23b0",
- "a3e81e59311cdfff2d4784949f7a2cb50ba6c3a91fa54710568e61aca3e847c6",
- false // F (3 - S changed)
- },
- {
- "069a6e6b93dfee6df6ef6997cd80dd2182c36653cef10c655d524585655462d6"
- "83877f95ecc6d6c81623d8fac4e900ed0019964094e7de91f1481989ae187300"
- "4565789cbf5dc56c62aedc63f62f3b894c9c6f7788c8ecaadc9bd0e81ad91b2b"
- "3569ea12260e93924fdddd3972af5273198f5efda0746219475017557616170e",
- "5cf02a00d205bdfee2016f7421807fc38ae69e6b7ccd064ee689fc1a94a9f7d2",
- "ec530ce3cc5c9d1af463f264d685afe2b4db4b5828d7e61b748930f3ce622a85",
- "dc23d130c6117fb5751201455e99f36f59aba1a6a21cf2d0e7481a97451d6693",
- "d6ce7708c18dbf35d4f8aa7240922dc6823f2e7058cbc1484fcad1599db5018c",
- false // F (2 - R changed)
- },
- {
- "df04a346cf4d0e331a6db78cca2d456d31b0a000aa51441defdb97bbeb20b94d"
- "8d746429a393ba88840d661615e07def615a342abedfa4ce912e562af7149598"
- "96858af817317a840dcff85a057bb91a3c2bf90105500362754a6dd321cdd861"
- "28cfc5f04667b57aa78c112411e42da304f1012d48cd6a7052d7de44ebcc01de",
- "2ddfd145767883ffbb0ac003ab4a44346d08fa2570b3120dcce94562422244cb",
- "5f70c7d11ac2b7a435ccfbbae02c3df1ea6b532cc0e9db74f93fffca7c6f9a64",
- "9913111cff6f20c5bf453a99cd2c2019a4e749a49724a08774d14e4c113edda8",
- "9467cd4cd21ecb56b0cab0a9a453b43386845459127a952421f5c6382866c5cc",
- false // F (4 - Q changed)
- },
- {
- "e1130af6a38ccb412a9c8d13e15dbfc9e69a16385af3c3f1e5da954fd5e7c45f"
- "d75e2b8c36699228e92840c0562fbf3772f07e17f1add56588dd45f7450e1217"
- "ad239922dd9c32695dc71ff2424ca0dec1321aa47064a044b7fe3c2b97d03ce4"
- "70a592304c5ef21eed9f93da56bb232d1eeb0035f9bf0dfafdcc4606272b20a3",
- "e424dc61d4bb3cb7ef4344a7f8957a0c5134e16f7a67c074f82e6e12f49abf3c",
- "970eed7aa2bc48651545949de1dddaf0127e5965ac85d1243d6f60e7dfaee927",
- "bf96b99aa49c705c910be33142017c642ff540c76349b9dab72f981fd9347f4f",
- "17c55095819089c2e03b9cd415abdf12444e323075d98f31920b9e0f57ec871c",
- true // P (0 )
- },
- {
- "73c5f6a67456ae48209b5f85d1e7de7758bf235300c6ae2bdceb1dcb27a7730f"
- "b68c950b7fcada0ecc4661d3578230f225a875e69aaa17f1e71c6be5c831f226"
- "63bac63d0c7a9635edb0043ff8c6f26470f02a7bc56556f1437f06dfa27b487a"
- "6c4290d8bad38d4879b334e341ba092dde4e4ae694a9c09302e2dbf443581c08",
- "e0fc6a6f50e1c57475673ee54e3a57f9a49f3328e743bf52f335e3eeaa3d2864",
- "7f59d689c91e463607d9194d99faf316e25432870816dde63f5d4b373f12f22a",
- "1d75830cd36f4c9aa181b2c4221e87f176b7f05b7c87824e82e396c88315c407",
- "cb2acb01dac96efc53a32d4a0d85d0c2e48955214783ecf50a4f0414a319c05a",
- true // P (0 )
- },
- {
- "666036d9b4a2426ed6585a4e0fd931a8761451d29ab04bd7dc6d0c5b9e38e6c2"
- "b263ff6cb837bd04399de3d757c6c7005f6d7a987063cf6d7e8cb38a4bf0d74a"
- "282572bd01d0f41e3fd066e3021575f0fa04f27b700d5b7ddddf50965993c3f9"
- "c7118ed78888da7cb221849b3260592b8e632d7c51e935a0ceae15207bedd548",
- "a849bef575cac3c6920fbce675c3b787136209f855de19ffe2e8d29b31a5ad86",
- "bf5fe4f7858f9b805bd8dcc05ad5e7fb889de2f822f3d8b41694e6c55c16b471",
- "25acc3aa9d9e84c7abf08f73fa4195acc506491d6fc37cb9074528a7db87b9d6",
- "9b21d5b5259ed3f2ef07dfec6cc90d3a37855d1ce122a85ba6a333f307d31537",
- false // F (2 - R changed)
- },
- {
- "7e80436bce57339ce8da1b5660149a20240b146d108deef3ec5da4ae256f8f89"
- "4edcbbc57b34ce37089c0daa17f0c46cd82b5a1599314fd79d2fd2f446bd5a25"
- "b8e32fcf05b76d644573a6df4ad1dfea707b479d97237a346f1ec632ea5660ef"
- "b57e8717a8628d7f82af50a4e84b11f21bdff6839196a880ae20b2a0918d58cd",
- "3dfb6f40f2471b29b77fdccba72d37c21bba019efa40c1c8f91ec405d7dcc5df",
- "f22f953f1e395a52ead7f3ae3fc47451b438117b1e04d613bc8555b7d6e6d1bb",
- "548886278e5ec26bed811dbb72db1e154b6f17be70deb1b210107decb1ec2a5a",
- "e93bfebd2f14f3d827ca32b464be6e69187f5edbd52def4f96599c37d58eee75",
- false // F (4 - Q changed)
- },
- {
- "1669bfb657fdc62c3ddd63269787fc1c969f1850fb04c933dda063ef74a56ce1"
- "3e3a649700820f0061efabf849a85d474326c8a541d99830eea8131eaea584f2"
- "2d88c353965dabcdc4bf6b55949fd529507dfb803ab6b480cd73ca0ba00ca19c"
- "438849e2cea262a1c57d8f81cd257fb58e19dec7904da97d8386e87b84948169",
- "69b7667056e1e11d6caf6e45643f8b21e7a4bebda463c7fdbc13bc98efbd0214",
- "d3f9b12eb46c7c6fda0da3fc85bc1fd831557f9abc902a3be3cb3e8be7d1aa2f",
- "288f7a1cd391842cce21f00e6f15471c04dc182fe4b14d92dc18910879799790",
- "247b3c4e89a3bcadfea73c7bfd361def43715fa382b8c3edf4ae15d6e55e9979",
- false // F (1 - Message changed)
- },
- {
- "3fe60dd9ad6caccf5a6f583b3ae65953563446c4510b70da115ffaa0ba04c076"
- "115c7043ab8733403cd69c7d14c212c655c07b43a7c71b9a4cffe22c2684788e"
- "c6870dc2013f269172c822256f9e7cc674791bf2d8486c0f5684283e1649576e"
- "fc982ede17c7b74b214754d70402fb4bb45ad086cf2cf76b3d63f7fce39ac970",
- "bf02cbcf6d8cc26e91766d8af0b164fc5968535e84c158eb3bc4e2d79c3cc682",
- "069ba6cb06b49d60812066afa16ecf7b51352f2c03bd93ec220822b1f3dfba03",
- "f5acb06c59c2b4927fb852faa07faf4b1852bbb5d06840935e849c4d293d1bad",
- "049dab79c89cc02f1484c437f523e080a75f134917fda752f2d5ca397addfe5d",
- false // F (3 - S changed)
- },
- {
- "983a71b9994d95e876d84d28946a041f8f0a3f544cfcc055496580f1dfd4e312"
- "a2ad418fe69dbc61db230cc0c0ed97e360abab7d6ff4b81ee970a7e97466acfd"
- "9644f828ffec538abc383d0e92326d1c88c55e1f46a668a039beaa1be631a891"
- "29938c00a81a3ae46d4aecbf9707f764dbaccea3ef7665e4c4307fa0b0a3075c",
- "224a4d65b958f6d6afb2904863efd2a734b31798884801fcab5a590f4d6da9de",
- "178d51fddada62806f097aa615d33b8f2404e6b1479f5fd4859d595734d6d2b9",
- "87b93ee2fecfda54deb8dff8e426f3c72c8864991f8ec2b3205bb3b416de93d2",
- "4044a24df85be0cc76f21a4430b75b8e77b932a87f51e4eccbc45c263ebf8f66",
- false // F (2 - R changed)
- },
- {
- "4a8c071ac4fd0d52faa407b0fe5dab759f7394a5832127f2a3498f34aac28733"
- "9e043b4ffa79528faf199dc917f7b066ad65505dab0e11e6948515052ce20cfd"
- "b892ffb8aa9bf3f1aa5be30a5bbe85823bddf70b39fd7ebd4a93a2f75472c1d4"
- "f606247a9821f1a8c45a6cb80545de2e0c6c0174e2392088c754e9c8443eb5af",
- "43691c7795a57ead8c5c68536fe934538d46f12889680a9cb6d055a066228369",
- "f8790110b3c3b281aa1eae037d4f1234aff587d903d93ba3af225c27ddc9ccac",
- "8acd62e8c262fa50dd9840480969f4ef70f218ebf8ef9584f199031132c6b1ce",
- "cfca7ed3d4347fb2a29e526b43c348ae1ce6c60d44f3191b6d8ea3a2d9c92154",
- false // F (3 - S changed)
- },
- {
- "0a3a12c3084c865daf1d302c78215d39bfe0b8bf28272b3c0b74beb4b7409db0"
- "718239de700785581514321c6440a4bbaea4c76fa47401e151e68cb6c29017f0"
- "bce4631290af5ea5e2bf3ed742ae110b04ade83a5dbd7358f29a85938e23d87a"
- "c8233072b79c94670ff0959f9c7f4517862ff829452096c78f5f2e9a7e4e9216",
- "9157dbfcf8cf385f5bb1568ad5c6e2a8652ba6dfc63bc1753edf5268cb7eb596",
- "972570f4313d47fc96f7c02d5594d77d46f91e949808825b3d31f029e8296405",
- "dfaea6f297fa320b707866125c2a7d5d515b51a503bee817de9faa343cc48eeb",
- "8f780ad713f9c3e5a4f7fa4c519833dfefc6a7432389b1e4af463961f09764f2",
- false // F (1 - Message changed)
- },
- {
- "785d07a3c54f63dca11f5d1a5f496ee2c2f9288e55007e666c78b007d95cc285"
- "81dce51f490b30fa73dc9e2d45d075d7e3a95fb8a9e1465ad191904124160b7c"
- "60fa720ef4ef1c5d2998f40570ae2a870ef3e894c2bc617d8a1dc85c3c557749"
- "28c38789b4e661349d3f84d2441a3b856a76949b9f1f80bc161648a1cad5588e",
- "072b10c081a4c1713a294f248aef850e297991aca47fa96a7470abe3b8acfdda",
- "9581145cca04a0fb94cedce752c8f0370861916d2a94e7c647c5373ce6a4c8f5",
- "09f5483eccec80f9d104815a1be9cc1a8e5b12b6eb482a65c6907b7480cf4f19",
- "a4f90e560c5e4eb8696cb276e5165b6a9d486345dedfb094a76e8442d026378d",
- false // F (4 - Q changed)
- },
- {
- "76f987ec5448dd72219bd30bf6b66b0775c80b394851a43ff1f537f140a6e722"
- "9ef8cd72ad58b1d2d20298539d6347dd5598812bc65323aceaf05228f738b5ad"
- "3e8d9fe4100fd767c2f098c77cb99c2992843ba3eed91d32444f3b6db6cd212d"
- "d4e5609548f4bb62812a920f6e2bf1581be1ebeebdd06ec4e971862cc42055ca",
- "09308ea5bfad6e5adf408634b3d5ce9240d35442f7fe116452aaec0d25be8c24",
- "f40c93e023ef494b1c3079b2d10ef67f3170740495ce2cc57f8ee4b0618b8ee5",
- "5cc8aa7c35743ec0c23dde88dabd5e4fcd0192d2116f6926fef788cddb754e73",
- "9c9c045ebaa1b828c32f82ace0d18daebf5e156eb7cbfdc1eff4399a8a900ae7",
- false // F (1 - Message changed)
- },
- {
- "60cd64b2cd2be6c33859b94875120361a24085f3765cb8b2bf11e026fa9d8855"
- "dbe435acf7882e84f3c7857f96e2baab4d9afe4588e4a82e17a78827bfdb5ddb"
- "d1c211fbc2e6d884cddd7cb9d90d5bf4a7311b83f352508033812c776a0e00c0"
- "03c7e0d628e50736c7512df0acfa9f2320bd102229f46495ae6d0857cc452a84",
- "2d98ea01f754d34bbc3003df5050200abf445ec728556d7ed7d5c54c55552b6d",
- "9b52672742d637a32add056dfd6d8792f2a33c2e69dafabea09b960bc61e230a",
- "06108e525f845d0155bf60193222b3219c98e3d49424c2fb2a0987f825c17959",
- "62b5cdd591e5b507e560167ba8f6f7cda74673eb315680cb89ccbc4eec477dce",
- true // P (0 )
- },
- {nullptr}};
-
-} // namespace
-
-// A known answer test for ChannelIDVerifier.
-TEST(ChannelIDTest, VerifyKnownAnswerTest) {
- string msg;
- string qx;
- string qy;
- string r;
- string s;
-
- for (size_t i = 0; test_vector[i].msg != nullptr; i++) {
- SCOPED_TRACE(i);
- // Decode the test vector.
- ASSERT_TRUE(DecodeHexString(test_vector[i].msg, &msg));
- ASSERT_TRUE(DecodeHexString(test_vector[i].qx, &qx));
- ASSERT_TRUE(DecodeHexString(test_vector[i].qy, &qy));
- ASSERT_TRUE(DecodeHexString(test_vector[i].r, &r));
- ASSERT_TRUE(DecodeHexString(test_vector[i].s, &s));
-
- string key = qx + qy;
- string signature = r + s;
-
- // The test vector's lengths should look sane.
- EXPECT_EQ(32u, qx.size());
- EXPECT_EQ(32u, qy.size());
- EXPECT_EQ(32u, r.size());
- EXPECT_EQ(32u, s.size());
-
- EXPECT_EQ(test_vector[i].result,
- ChannelIDVerifier::VerifyRaw(key, msg, signature, false));
- }
-}
-
-TEST(ChannelIDTest, SignAndVerify) {
- std::unique_ptr<ChannelIDSource> source(
- CryptoTestUtils::ChannelIDSourceForTesting());
-
- const string signed_data = "signed data";
- const string hostname = "foo.example.com";
- std::unique_ptr<ChannelIDKey> channel_id_key;
- QuicAsyncStatus status =
- source->GetChannelIDKey(hostname, &channel_id_key, nullptr);
- ASSERT_EQ(QUIC_SUCCESS, status);
-
- string signature;
- ASSERT_TRUE(channel_id_key->Sign(signed_data, &signature));
-
- string key = channel_id_key->SerializeKey();
- EXPECT_TRUE(ChannelIDVerifier::Verify(key, signed_data, signature));
-
- EXPECT_FALSE(ChannelIDVerifier::Verify("a" + key, signed_data, signature));
- EXPECT_FALSE(ChannelIDVerifier::Verify(key, "a" + signed_data, signature));
-
- std::unique_ptr<char[]> bad_key(new char[key.size()]);
- memcpy(bad_key.get(), key.data(), key.size());
- bad_key[1] ^= 0x80;
- EXPECT_FALSE(ChannelIDVerifier::Verify(string(bad_key.get(), key.size()),
- signed_data, signature));
-
- std::unique_ptr<char[]> bad_signature(new char[signature.size()]);
- memcpy(bad_signature.get(), signature.data(), signature.size());
- bad_signature[1] ^= 0x80;
- EXPECT_FALSE(ChannelIDVerifier::Verify(
- key, signed_data, string(bad_signature.get(), signature.size())));
-
- EXPECT_FALSE(ChannelIDVerifier::Verify(key, "wrong signed data", signature));
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/common_cert_set.cc b/chromium/net/quic/crypto/common_cert_set.cc
deleted file mode 100644
index 426a39d76b7..00000000000
--- a/chromium/net/quic/crypto/common_cert_set.cc
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright (c) 2013 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/crypto/common_cert_set.h"
-
-#include <cstddef>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "net/quic/quic_utils.h"
-
-using base::StringPiece;
-
-namespace net {
-
-namespace common_cert_set_2 {
-#include "net/quic/crypto/common_cert_set_2.c"
-}
-
-namespace common_cert_set_3 {
-#include "net/quic/crypto/common_cert_set_3.c"
-}
-
-namespace {
-
-struct CertSet {
- // num_certs contains the number of certificates in this set.
- size_t num_certs;
- // certs is an array of |num_certs| pointers to the DER encoded certificates.
- const unsigned char* const* certs;
- // lens is an array of |num_certs| integers describing the length, in bytes,
- // of each certificate.
- const size_t* lens;
- // hash contains the 64-bit, FNV-1a hash of this set.
- uint64_t hash;
-};
-
-const CertSet kSets[] = {
- {
- common_cert_set_2::kNumCerts, common_cert_set_2::kCerts,
- common_cert_set_2::kLens, common_cert_set_2::kHash,
- },
- {
- common_cert_set_3::kNumCerts, common_cert_set_3::kCerts,
- common_cert_set_3::kLens, common_cert_set_3::kHash,
- },
-};
-
-const uint64_t kSetHashes[] = {
- common_cert_set_2::kHash, common_cert_set_3::kHash,
-};
-
-// Compare returns a value less than, equal to or greater than zero if |a| is
-// lexicographically less than, equal to or greater than |b|, respectively.
-int Compare(StringPiece a, const unsigned char* b, size_t b_len) {
- size_t len = a.size();
- if (len > b_len) {
- len = b_len;
- }
- int n = memcmp(a.data(), b, len);
- if (n != 0) {
- return n;
- }
-
- if (a.size() < b_len) {
- return -1;
- } else if (a.size() > b_len) {
- return 1;
- }
- return 0;
-}
-
-// CommonCertSetsQUIC implements the CommonCertSets interface using the default
-// certificate sets.
-class CommonCertSetsQUIC : public CommonCertSets {
- public:
- // CommonCertSets interface.
- StringPiece GetCommonHashes() const override {
- return StringPiece(reinterpret_cast<const char*>(kSetHashes),
- sizeof(uint64_t) * arraysize(kSetHashes));
- }
-
- StringPiece GetCert(uint64_t hash, uint32_t index) const override {
- for (size_t i = 0; i < arraysize(kSets); i++) {
- if (kSets[i].hash == hash) {
- if (index < kSets[i].num_certs) {
- return StringPiece(
- reinterpret_cast<const char*>(kSets[i].certs[index]),
- kSets[i].lens[index]);
- }
- break;
- }
- }
-
- return StringPiece();
- }
-
- bool MatchCert(StringPiece cert,
- StringPiece common_set_hashes,
- uint64_t* out_hash,
- uint32_t* out_index) const override {
- if (common_set_hashes.size() % sizeof(uint64_t) != 0) {
- return false;
- }
-
- for (size_t i = 0; i < common_set_hashes.size() / sizeof(uint64_t); i++) {
- uint64_t hash;
- memcpy(&hash, common_set_hashes.data() + i * sizeof(uint64_t),
- sizeof(uint64_t));
-
- for (size_t j = 0; j < arraysize(kSets); j++) {
- if (kSets[j].hash != hash) {
- continue;
- }
-
- if (kSets[j].num_certs == 0) {
- continue;
- }
-
- // Binary search for a matching certificate.
- size_t min = 0;
- size_t max = kSets[j].num_certs - 1;
- while (max >= min) {
- size_t mid = min + ((max - min) / 2);
- int n = Compare(cert, kSets[j].certs[mid], kSets[j].lens[mid]);
- if (n < 0) {
- if (mid == 0) {
- break;
- }
- max = mid - 1;
- } else if (n > 0) {
- min = mid + 1;
- } else {
- *out_hash = hash;
- *out_index = mid;
- return true;
- }
- }
- }
- }
-
- return false;
- }
-
- static CommonCertSetsQUIC* GetInstance() {
- return base::Singleton<CommonCertSetsQUIC>::get();
- }
-
- private:
- CommonCertSetsQUIC() {}
- ~CommonCertSetsQUIC() override {}
-
- friend struct base::DefaultSingletonTraits<CommonCertSetsQUIC>;
- DISALLOW_COPY_AND_ASSIGN(CommonCertSetsQUIC);
-};
-
-} // anonymous namespace
-
-CommonCertSets::~CommonCertSets() {}
-
-// static
-const CommonCertSets* CommonCertSets::GetInstanceQUIC() {
- return CommonCertSetsQUIC::GetInstance();
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/common_cert_set.h b/chromium/net/quic/crypto/common_cert_set.h
deleted file mode 100644
index 6d152054cc4..00000000000
--- a/chromium/net/quic/crypto/common_cert_set.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2013 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_CRYPTO_COMMON_CERT_SET_H_
-#define NET_QUIC_CRYPTO_COMMON_CERT_SET_H_
-
-#include <cstdint>
-
-#include "base/compiler_specific.h"
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-#include "net/quic/crypto/crypto_protocol.h"
-
-namespace net {
-
-// CommonCertSets is an interface to an object that contains a number of common
-// certificate sets and can match against them.
-class NET_EXPORT_PRIVATE CommonCertSets {
- public:
- virtual ~CommonCertSets();
-
- // GetInstanceQUIC returns the standard QUIC common certificate sets.
- static const CommonCertSets* GetInstanceQUIC();
-
- // GetCommonHashes returns a StringPiece containing the hashes of common sets
- // supported by this object. The 64-bit hashes are concatenated in the
- // StringPiece.
- virtual base::StringPiece GetCommonHashes() const = 0;
-
- // GetCert returns a specific certificate (at index |index|) in the common
- // set identified by |hash|. If no such certificate is known, an empty
- // StringPiece is returned.
- virtual base::StringPiece GetCert(uint64_t hash, uint32_t index) const = 0;
-
- // MatchCert tries to find |cert| in one of the common certificate sets
- // identified by |common_set_hashes|. On success it puts the hash of the
- // set in |out_hash|, the index of |cert| in the set in |out_index| and
- // returns true. Otherwise it returns false.
- virtual bool MatchCert(base::StringPiece cert,
- base::StringPiece common_set_hashes,
- uint64_t* out_hash,
- uint32_t* out_index) const = 0;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_COMMON_CERT_SET_H_
diff --git a/chromium/net/quic/crypto/common_cert_set_1.c b/chromium/net/quic/crypto/common_cert_set_1.c
deleted file mode 100644
index e8325758811..00000000000
--- a/chromium/net/quic/crypto/common_cert_set_1.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/* Copyright (c) 2013 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 common certificates. It's designed to be #included in
- * another file, in a namespace. */
-
-#include <stdint.h>
-
-#include "net/quic/crypto/common_cert_set_1a.inc"
-#include "net/quic/crypto/common_cert_set_1b.inc"
-
-static const size_t kNumCerts = 62;
-static const unsigned char* const kCerts[] = {
- kDERCert0,
- kDERCert1,
- kDERCert2,
- kDERCert3,
- kDERCert4,
- kDERCert5,
- kDERCert6,
- kDERCert7,
- kDERCert8,
- kDERCert9,
- kDERCert10,
- kDERCert11,
- kDERCert12,
- kDERCert13,
- kDERCert14,
- kDERCert15,
- kDERCert16,
- kDERCert17,
- kDERCert18,
- kDERCert19,
- kDERCert20,
- kDERCert21,
- kDERCert22,
- kDERCert23,
- kDERCert24,
- kDERCert25,
- kDERCert26,
- kDERCert27,
- kDERCert28,
- kDERCert29,
- kDERCert30,
- kDERCert31,
- kDERCert32,
- kDERCert33,
- kDERCert34,
- kDERCert35,
- kDERCert36,
- kDERCert37,
- kDERCert38,
- kDERCert39,
- kDERCert40,
- kDERCert41,
- kDERCert42,
- kDERCert43,
- kDERCert44,
- kDERCert45,
- kDERCert46,
- kDERCert47,
- kDERCert48,
- kDERCert49,
- kDERCert50,
- kDERCert51,
- kDERCert52,
- kDERCert53,
- kDERCert54,
- kDERCert55,
- kDERCert56,
- kDERCert57,
- kDERCert58,
- kDERCert59,
- kDERCert60,
- kDERCert61,
-};
-
-static const size_t kLens[] = {
- 897,
- 911,
- 985,
- 989,
- 1012,
- 1022,
- 1049,
- 1055,
- 1071,
- 1080,
- 1084,
- 1088,
- 1097,
- 1098,
- 1105,
- 1107,
- 1117,
- 1124,
- 1127,
- 1133,
- 1136,
- 1153,
- 1171,
- 1171,
- 1172,
- 1176,
- 1182,
- 1188,
- 1191,
- 1194,
- 1194,
- 1199,
- 1205,
- 1210,
- 1226,
- 1236,
- 1236,
- 1238,
- 1250,
- 1254,
- 1256,
- 1257,
- 1269,
- 1270,
- 1280,
- 1284,
- 1285,
- 1287,
- 1290,
- 1291,
- 1291,
- 1294,
- 1297,
- 1385,
- 1512,
- 1520,
- 1548,
- 1570,
- 1581,
- 1628,
- 1712,
- 1770,
-};
-
-static const uint64_t kHash = UINT64_C(0xff715ce4e7e9267b);
diff --git a/chromium/net/quic/crypto/common_cert_set_2.c b/chromium/net/quic/crypto/common_cert_set_2.c
deleted file mode 100644
index a10e892b832..00000000000
--- a/chromium/net/quic/crypto/common_cert_set_2.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/* 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 common certificates. It's designed to be #included in
- * another file, in a namespace. */
-
-#include <stdint.h>
-
-#include "net/quic/crypto/common_cert_set_2a.inc"
-#include "net/quic/crypto/common_cert_set_2b.inc"
-
-static const size_t kNumCerts = 54;
-static const unsigned char* const kCerts[] = {
- kDERCert0,
- kDERCert1,
- kDERCert2,
- kDERCert3,
- kDERCert4,
- kDERCert5,
- kDERCert6,
- kDERCert7,
- kDERCert8,
- kDERCert9,
- kDERCert10,
- kDERCert11,
- kDERCert12,
- kDERCert13,
- kDERCert14,
- kDERCert15,
- kDERCert16,
- kDERCert17,
- kDERCert18,
- kDERCert19,
- kDERCert20,
- kDERCert21,
- kDERCert22,
- kDERCert23,
- kDERCert24,
- kDERCert25,
- kDERCert26,
- kDERCert27,
- kDERCert28,
- kDERCert29,
- kDERCert30,
- kDERCert31,
- kDERCert32,
- kDERCert33,
- kDERCert34,
- kDERCert35,
- kDERCert36,
- kDERCert37,
- kDERCert38,
- kDERCert39,
- kDERCert40,
- kDERCert41,
- kDERCert42,
- kDERCert43,
- kDERCert44,
- kDERCert45,
- kDERCert46,
- kDERCert47,
- kDERCert48,
- kDERCert49,
- kDERCert50,
- kDERCert51,
- kDERCert52,
- kDERCert53,
-};
-
-static const size_t kLens[] = {
- 897,
- 911,
- 985,
- 1012,
- 1049,
- 1062,
- 1065,
- 1071,
- 1084,
- 1096,
- 1097,
- 1105,
- 1107,
- 1117,
- 1127,
- 1133,
- 1136,
- 1138,
- 1153,
- 1171,
- 1172,
- 1176,
- 1182,
- 1188,
- 1194,
- 1203,
- 1205,
- 1206,
- 1210,
- 1222,
- 1226,
- 1236,
- 1236,
- 1236,
- 1238,
- 1256,
- 1270,
- 1280,
- 1283,
- 1284,
- 1287,
- 1315,
- 1327,
- 1340,
- 1418,
- 1447,
- 1509,
- 1520,
- 1570,
- 1581,
- 1592,
- 1628,
- 1632,
- 1770,
-};
-
-static const uint64_t kHash = UINT64_C(0xe81a92926081e801);
diff --git a/chromium/net/quic/crypto/common_cert_set_3.c b/chromium/net/quic/crypto/common_cert_set_3.c
deleted file mode 100644
index e9e5e64e0e2..00000000000
--- a/chromium/net/quic/crypto/common_cert_set_3.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/* 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 common certificates. It's designed to be #included in
- * another file, in a namespace. */
-
-#include "net/quic/crypto/common_cert_set_3a.inc"
-#include "net/quic/crypto/common_cert_set_3b.inc"
-
-static const size_t kNumCerts = 52;
-static const unsigned char* const kCerts[] = {
- kDERCert0,
- kDERCert1,
- kDERCert2,
- kDERCert3,
- kDERCert4,
- kDERCert5,
- kDERCert6,
- kDERCert7,
- kDERCert8,
- kDERCert9,
- kDERCert10,
- kDERCert11,
- kDERCert12,
- kDERCert13,
- kDERCert14,
- kDERCert15,
- kDERCert16,
- kDERCert17,
- kDERCert18,
- kDERCert19,
- kDERCert20,
- kDERCert21,
- kDERCert22,
- kDERCert23,
- kDERCert24,
- kDERCert25,
- kDERCert26,
- kDERCert27,
- kDERCert28,
- kDERCert29,
- kDERCert30,
- kDERCert31,
- kDERCert32,
- kDERCert33,
- kDERCert34,
- kDERCert35,
- kDERCert36,
- kDERCert37,
- kDERCert38,
- kDERCert39,
- kDERCert40,
- kDERCert41,
- kDERCert42,
- kDERCert43,
- kDERCert44,
- kDERCert45,
- kDERCert46,
- kDERCert47,
- kDERCert48,
- kDERCert49,
- kDERCert50,
- kDERCert51,
-};
-
-static const size_t kLens[] = {
- 897,
- 911,
- 1012,
- 1049,
- 1065,
- 1096,
- 1097,
- 1101,
- 1105,
- 1105,
- 1107,
- 1117,
- 1127,
- 1133,
- 1136,
- 1138,
- 1139,
- 1145,
- 1149,
- 1153,
- 1167,
- 1172,
- 1174,
- 1174,
- 1176,
- 1188,
- 1194,
- 1196,
- 1203,
- 1205,
- 1206,
- 1208,
- 1209,
- 1210,
- 1222,
- 1227,
- 1236,
- 1236,
- 1238,
- 1283,
- 1284,
- 1287,
- 1298,
- 1315,
- 1327,
- 1340,
- 1357,
- 1418,
- 1447,
- 1509,
- 1513,
- 1632,
-};
-
-static const uint64_t kHash = UINT64_C(0x918215a28680ed7e);
diff --git a/chromium/net/quic/crypto/common_cert_set_test.cc b/chromium/net/quic/crypto/common_cert_set_test.cc
deleted file mode 100644
index f1c8d28bd17..00000000000
--- a/chromium/net/quic/crypto/common_cert_set_test.cc
+++ /dev/null
@@ -1,249 +0,0 @@
-// Copyright (c) 2013 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/crypto/common_cert_set.h"
-
-#include <stdint.h>
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::StringPiece;
-
-namespace net {
-namespace test {
-
-// Google Internet Authority cert from v2 of the cert set.
-static const unsigned char kGIACertificate2[] = {
- 0x30, 0x82, 0x03, 0xf0, 0x30, 0x82, 0x02, 0xd8, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x03, 0x02, 0x3a, 0x83, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
- 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47,
- 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e,
- 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47,
- 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62,
- 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30,
- 0x34, 0x30, 0x35, 0x31, 0x35, 0x31, 0x35, 0x35, 0x36, 0x5a, 0x17, 0x0d,
- 0x31, 0x36, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39,
- 0x5a, 0x30, 0x49, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
- 0x0a, 0x13, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e,
- 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c,
- 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72,
- 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
- 0x79, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
- 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
- 0x00, 0x9c, 0x2a, 0x04, 0x77, 0x5c, 0xd8, 0x50, 0x91, 0x3a, 0x06, 0xa3,
- 0x82, 0xe0, 0xd8, 0x50, 0x48, 0xbc, 0x89, 0x3f, 0xf1, 0x19, 0x70, 0x1a,
- 0x88, 0x46, 0x7e, 0xe0, 0x8f, 0xc5, 0xf1, 0x89, 0xce, 0x21, 0xee, 0x5a,
- 0xfe, 0x61, 0x0d, 0xb7, 0x32, 0x44, 0x89, 0xa0, 0x74, 0x0b, 0x53, 0x4f,
- 0x55, 0xa4, 0xce, 0x82, 0x62, 0x95, 0xee, 0xeb, 0x59, 0x5f, 0xc6, 0xe1,
- 0x05, 0x80, 0x12, 0xc4, 0x5e, 0x94, 0x3f, 0xbc, 0x5b, 0x48, 0x38, 0xf4,
- 0x53, 0xf7, 0x24, 0xe6, 0xfb, 0x91, 0xe9, 0x15, 0xc4, 0xcf, 0xf4, 0x53,
- 0x0d, 0xf4, 0x4a, 0xfc, 0x9f, 0x54, 0xde, 0x7d, 0xbe, 0xa0, 0x6b, 0x6f,
- 0x87, 0xc0, 0xd0, 0x50, 0x1f, 0x28, 0x30, 0x03, 0x40, 0xda, 0x08, 0x73,
- 0x51, 0x6c, 0x7f, 0xff, 0x3a, 0x3c, 0xa7, 0x37, 0x06, 0x8e, 0xbd, 0x4b,
- 0x11, 0x04, 0xeb, 0x7d, 0x24, 0xde, 0xe6, 0xf9, 0xfc, 0x31, 0x71, 0xfb,
- 0x94, 0xd5, 0x60, 0xf3, 0x2e, 0x4a, 0xaf, 0x42, 0xd2, 0xcb, 0xea, 0xc4,
- 0x6a, 0x1a, 0xb2, 0xcc, 0x53, 0xdd, 0x15, 0x4b, 0x8b, 0x1f, 0xc8, 0x19,
- 0x61, 0x1f, 0xcd, 0x9d, 0xa8, 0x3e, 0x63, 0x2b, 0x84, 0x35, 0x69, 0x65,
- 0x84, 0xc8, 0x19, 0xc5, 0x46, 0x22, 0xf8, 0x53, 0x95, 0xbe, 0xe3, 0x80,
- 0x4a, 0x10, 0xc6, 0x2a, 0xec, 0xba, 0x97, 0x20, 0x11, 0xc7, 0x39, 0x99,
- 0x10, 0x04, 0xa0, 0xf0, 0x61, 0x7a, 0x95, 0x25, 0x8c, 0x4e, 0x52, 0x75,
- 0xe2, 0xb6, 0xed, 0x08, 0xca, 0x14, 0xfc, 0xce, 0x22, 0x6a, 0xb3, 0x4e,
- 0xcf, 0x46, 0x03, 0x97, 0x97, 0x03, 0x7e, 0xc0, 0xb1, 0xde, 0x7b, 0xaf,
- 0x45, 0x33, 0xcf, 0xba, 0x3e, 0x71, 0xb7, 0xde, 0xf4, 0x25, 0x25, 0xc2,
- 0x0d, 0x35, 0x89, 0x9d, 0x9d, 0xfb, 0x0e, 0x11, 0x79, 0x89, 0x1e, 0x37,
- 0xc5, 0xaf, 0x8e, 0x72, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81,
- 0xe7, 0x30, 0x81, 0xe4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x18, 0x30, 0x16, 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb,
- 0xab, 0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc,
- 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
- 0x4a, 0xdd, 0x06, 0x16, 0x1b, 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81,
- 0xb6, 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, 0x0e, 0x06, 0x03,
- 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06,
- 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01,
- 0x04, 0x22, 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
- 0x05, 0x07, 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
- 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d,
- 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08,
- 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x35, 0x06, 0x03,
- 0x55, 0x1d, 0x1f, 0x04, 0x2e, 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0,
- 0x26, 0x86, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e,
- 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72,
- 0x6c, 0x73, 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e,
- 0x63, 0x72, 0x6c, 0x30, 0x17, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x10,
- 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6,
- 0x79, 0x02, 0x05, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
- 0xaa, 0xfa, 0xa9, 0x20, 0xcd, 0x6a, 0x67, 0x83, 0xed, 0x5e, 0xd4, 0x7e,
- 0xde, 0x1d, 0xc4, 0x7f, 0xe0, 0x25, 0x06, 0x00, 0xc5, 0x24, 0xfb, 0xa9,
- 0xc8, 0x2d, 0x6d, 0x7e, 0xde, 0x9d, 0x82, 0x65, 0x2c, 0x81, 0x63, 0x34,
- 0x66, 0x3e, 0xe9, 0x52, 0xc2, 0x08, 0xb4, 0xcb, 0x2f, 0xf7, 0x5f, 0x99,
- 0x3a, 0x6a, 0x9c, 0x50, 0x7a, 0x85, 0x05, 0x8c, 0x7d, 0xd1, 0x2a, 0x48,
- 0x84, 0xd3, 0x09, 0x6c, 0x7c, 0xc2, 0xcd, 0x35, 0x9f, 0xf3, 0x82, 0xee,
- 0x52, 0xde, 0x68, 0x5f, 0xe4, 0x00, 0x8a, 0x17, 0x20, 0x96, 0xf7, 0x29,
- 0x8d, 0x9a, 0x4d, 0xcb, 0xa8, 0xde, 0x86, 0xc8, 0x0d, 0x6f, 0x56, 0x87,
- 0x03, 0x7d, 0x03, 0x3f, 0xdc, 0xfa, 0x79, 0x7d, 0x21, 0x19, 0xf9, 0xc8,
- 0x3a, 0x2f, 0x51, 0x76, 0x8c, 0xc7, 0x41, 0x92, 0x71, 0x8f, 0x25, 0xce,
- 0x37, 0xf8, 0x4a, 0x4c, 0x00, 0x23, 0xef, 0xc4, 0x35, 0x10, 0xae, 0xe0,
- 0x23, 0x80, 0x73, 0x7c, 0x4d, 0x34, 0x2e, 0xc8, 0x6e, 0x90, 0xd6, 0x10,
- 0x1e, 0x99, 0x84, 0x73, 0x1a, 0x70, 0xf2, 0xed, 0x55, 0x0e, 0xee, 0x17,
- 0x06, 0xea, 0x67, 0xee, 0x32, 0xeb, 0x2c, 0xdd, 0x67, 0x07, 0x3f, 0xf6,
- 0x8b, 0xc2, 0x70, 0xde, 0x5b, 0x00, 0xe6, 0xbb, 0x1b, 0xd3, 0x36, 0x1a,
- 0x22, 0x6c, 0x6c, 0xb0, 0x35, 0x42, 0x6c, 0x90, 0x09, 0x3d, 0x93, 0xe9,
- 0x64, 0x09, 0x22, 0x0e, 0x85, 0x06, 0x9f, 0xc2, 0x73, 0x21, 0xd3, 0xe6,
- 0x5f, 0x80, 0xe4, 0x8d, 0x85, 0x22, 0x3a, 0x73, 0x03, 0xb1, 0x60, 0x8e,
- 0xae, 0x68, 0xe2, 0xf4, 0x3e, 0x97, 0xe7, 0x60, 0x12, 0x09, 0x68, 0x36,
- 0xde, 0x3a, 0xd6, 0xe2, 0x43, 0x95, 0x5b, 0x37, 0x81, 0x92, 0x81, 0x1f,
- 0xbb, 0x8d, 0xd7, 0xad, 0x52, 0x64, 0x16, 0x57, 0x96, 0xd9, 0x5e, 0x34,
- 0x7e, 0xc8, 0x35, 0xd8,
-};
-
-// Google Internet Authority cert from v3 of the cert set.
-static const unsigned char kGIACertificate3[] = {
- 0x30, 0x82, 0x03, 0xf0, 0x30, 0x82, 0x02, 0xd8, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x03, 0x02, 0x3a, 0x92, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
- 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47,
- 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e,
- 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47,
- 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62,
- 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30,
- 0x34, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d,
- 0x31, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39,
- 0x5a, 0x30, 0x49, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
- 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
- 0x0a, 0x13, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e,
- 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c,
- 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72,
- 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
- 0x79, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
- 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
- 0x00, 0x9c, 0x2a, 0x04, 0x77, 0x5c, 0xd8, 0x50, 0x91, 0x3a, 0x06, 0xa3,
- 0x82, 0xe0, 0xd8, 0x50, 0x48, 0xbc, 0x89, 0x3f, 0xf1, 0x19, 0x70, 0x1a,
- 0x88, 0x46, 0x7e, 0xe0, 0x8f, 0xc5, 0xf1, 0x89, 0xce, 0x21, 0xee, 0x5a,
- 0xfe, 0x61, 0x0d, 0xb7, 0x32, 0x44, 0x89, 0xa0, 0x74, 0x0b, 0x53, 0x4f,
- 0x55, 0xa4, 0xce, 0x82, 0x62, 0x95, 0xee, 0xeb, 0x59, 0x5f, 0xc6, 0xe1,
- 0x05, 0x80, 0x12, 0xc4, 0x5e, 0x94, 0x3f, 0xbc, 0x5b, 0x48, 0x38, 0xf4,
- 0x53, 0xf7, 0x24, 0xe6, 0xfb, 0x91, 0xe9, 0x15, 0xc4, 0xcf, 0xf4, 0x53,
- 0x0d, 0xf4, 0x4a, 0xfc, 0x9f, 0x54, 0xde, 0x7d, 0xbe, 0xa0, 0x6b, 0x6f,
- 0x87, 0xc0, 0xd0, 0x50, 0x1f, 0x28, 0x30, 0x03, 0x40, 0xda, 0x08, 0x73,
- 0x51, 0x6c, 0x7f, 0xff, 0x3a, 0x3c, 0xa7, 0x37, 0x06, 0x8e, 0xbd, 0x4b,
- 0x11, 0x04, 0xeb, 0x7d, 0x24, 0xde, 0xe6, 0xf9, 0xfc, 0x31, 0x71, 0xfb,
- 0x94, 0xd5, 0x60, 0xf3, 0x2e, 0x4a, 0xaf, 0x42, 0xd2, 0xcb, 0xea, 0xc4,
- 0x6a, 0x1a, 0xb2, 0xcc, 0x53, 0xdd, 0x15, 0x4b, 0x8b, 0x1f, 0xc8, 0x19,
- 0x61, 0x1f, 0xcd, 0x9d, 0xa8, 0x3e, 0x63, 0x2b, 0x84, 0x35, 0x69, 0x65,
- 0x84, 0xc8, 0x19, 0xc5, 0x46, 0x22, 0xf8, 0x53, 0x95, 0xbe, 0xe3, 0x80,
- 0x4a, 0x10, 0xc6, 0x2a, 0xec, 0xba, 0x97, 0x20, 0x11, 0xc7, 0x39, 0x99,
- 0x10, 0x04, 0xa0, 0xf0, 0x61, 0x7a, 0x95, 0x25, 0x8c, 0x4e, 0x52, 0x75,
- 0xe2, 0xb6, 0xed, 0x08, 0xca, 0x14, 0xfc, 0xce, 0x22, 0x6a, 0xb3, 0x4e,
- 0xcf, 0x46, 0x03, 0x97, 0x97, 0x03, 0x7e, 0xc0, 0xb1, 0xde, 0x7b, 0xaf,
- 0x45, 0x33, 0xcf, 0xba, 0x3e, 0x71, 0xb7, 0xde, 0xf4, 0x25, 0x25, 0xc2,
- 0x0d, 0x35, 0x89, 0x9d, 0x9d, 0xfb, 0x0e, 0x11, 0x79, 0x89, 0x1e, 0x37,
- 0xc5, 0xaf, 0x8e, 0x72, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81,
- 0xe7, 0x30, 0x81, 0xe4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
- 0x18, 0x30, 0x16, 0x80, 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb,
- 0xab, 0x05, 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc,
- 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
- 0x4a, 0xdd, 0x06, 0x16, 0x1b, 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81,
- 0xb6, 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, 0x0e, 0x06, 0x03,
- 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06,
- 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01,
- 0x04, 0x22, 0x30, 0x20, 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
- 0x05, 0x07, 0x30, 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
- 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d,
- 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08,
- 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x35, 0x06, 0x03,
- 0x55, 0x1d, 0x1f, 0x04, 0x2e, 0x30, 0x2c, 0x30, 0x2a, 0xa0, 0x28, 0xa0,
- 0x26, 0x86, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e,
- 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72,
- 0x6c, 0x73, 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e,
- 0x63, 0x72, 0x6c, 0x30, 0x17, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x10,
- 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6,
- 0x79, 0x02, 0x05, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
- 0x08, 0x4e, 0x04, 0xa7, 0x80, 0x7f, 0x10, 0x16, 0x43, 0x5e, 0x02, 0xad,
- 0xd7, 0x42, 0x80, 0xf4, 0xb0, 0x8e, 0xd2, 0xae, 0xb3, 0xeb, 0x11, 0x7d,
- 0x90, 0x84, 0x18, 0x7d, 0xe7, 0x90, 0x15, 0xfb, 0x49, 0x7f, 0xa8, 0x99,
- 0x05, 0x91, 0xbb, 0x7a, 0xc9, 0xd6, 0x3c, 0x37, 0x18, 0x09, 0x9a, 0xb6,
- 0xc7, 0x92, 0x20, 0x07, 0x35, 0x33, 0x09, 0xe4, 0x28, 0x63, 0x72, 0x0d,
- 0xb4, 0xe0, 0x32, 0x9c, 0x87, 0x98, 0xc4, 0x1b, 0x76, 0x89, 0x67, 0xc1,
- 0x50, 0x58, 0xb0, 0x13, 0xaa, 0x13, 0x1a, 0x1b, 0x32, 0xa5, 0xbe, 0xea,
- 0x11, 0x95, 0x4c, 0x48, 0x63, 0x49, 0xe9, 0x99, 0x5d, 0x20, 0x37, 0xcc,
- 0xfe, 0x2a, 0x69, 0x51, 0x16, 0x95, 0x4b, 0xa9, 0xde, 0x49, 0x82, 0xc0,
- 0x10, 0x70, 0xf4, 0x2c, 0xf3, 0xec, 0xbc, 0x24, 0x24, 0xd0, 0x4e, 0xac,
- 0xa5, 0xd9, 0x5e, 0x1e, 0x6d, 0x92, 0xc1, 0xa7, 0xac, 0x48, 0x35, 0x81,
- 0xf9, 0xe5, 0xe4, 0x9c, 0x65, 0x69, 0xcd, 0x87, 0xa4, 0x41, 0x50, 0x3f,
- 0x2e, 0x57, 0xa5, 0x91, 0x51, 0x12, 0x58, 0x0e, 0x8c, 0x09, 0xa1, 0xac,
- 0x7a, 0xa4, 0x12, 0xa5, 0x27, 0xf3, 0x9a, 0x10, 0x97, 0x7d, 0x55, 0x03,
- 0x06, 0xf7, 0x66, 0x58, 0x5f, 0x5f, 0x64, 0xe1, 0xab, 0x5d, 0x6d, 0xa5,
- 0x39, 0x48, 0x75, 0x98, 0x4c, 0x29, 0x5a, 0x3a, 0x8d, 0xd3, 0x2b, 0xca,
- 0x9c, 0x55, 0x04, 0xbf, 0xf4, 0xe6, 0x14, 0xd5, 0x80, 0xac, 0x26, 0xed,
- 0x17, 0x89, 0xa6, 0x93, 0x6c, 0x5c, 0xa4, 0xcc, 0xb8, 0xf0, 0x66, 0x8e,
- 0x64, 0xe3, 0x7d, 0x9a, 0xe2, 0x00, 0xb3, 0x49, 0xc7, 0xe4, 0x0a, 0xaa,
- 0xdd, 0x5b, 0x83, 0xc7, 0x70, 0x90, 0x46, 0x4e, 0xbe, 0xd0, 0xdb, 0x59,
- 0x96, 0x6c, 0x2e, 0xf5, 0x16, 0x36, 0xde, 0x71, 0xcc, 0x01, 0xc2, 0x12,
- 0xc1, 0x21, 0xc6, 0x16,
-};
-
-TEST(CommonCertSets, FindGIA_2) {
- StringPiece gia(reinterpret_cast<const char*>(kGIACertificate2),
- sizeof(kGIACertificate2));
-
- const CommonCertSets* sets(CommonCertSets::GetInstanceQUIC());
- // Common Cert Set 2's hash.
- const uint64_t in_hash = UINT64_C(0xe81a92926081e801);
- uint64_t hash;
- uint32_t index;
- ASSERT_TRUE(sets->MatchCert(
- gia,
- StringPiece(reinterpret_cast<const char*>(&in_hash), sizeof(in_hash)),
- &hash, &index));
- EXPECT_EQ(in_hash, hash);
-
- StringPiece gia_copy = sets->GetCert(hash, index);
- EXPECT_FALSE(gia_copy.empty());
- ASSERT_EQ(gia.size(), gia_copy.size());
- EXPECT_EQ(0, memcmp(gia.data(), gia_copy.data(), gia.size()));
-}
-
-TEST(CommonCertSets, FindGIA_3) {
- StringPiece gia(reinterpret_cast<const char*>(kGIACertificate3),
- sizeof(kGIACertificate3));
-
- const CommonCertSets* sets(CommonCertSets::GetInstanceQUIC());
- // Common Cert Set 3's hash.
- const uint64_t in_hash = UINT64_C(0x918215a28680ed7e);
- uint64_t hash;
- uint32_t index;
- ASSERT_TRUE(sets->MatchCert(
- gia,
- StringPiece(reinterpret_cast<const char*>(&in_hash), sizeof(in_hash)),
- &hash, &index));
- EXPECT_EQ(in_hash, hash);
-
- StringPiece gia_copy = sets->GetCert(hash, index);
- EXPECT_FALSE(gia_copy.empty());
- ASSERT_EQ(gia.size(), gia_copy.size());
- EXPECT_EQ(0, memcmp(gia.data(), gia_copy.data(), gia.size()));
-}
-
-TEST(CommonCertSets, NonMatch) {
- const CommonCertSets* sets(CommonCertSets::GetInstanceQUIC());
- StringPiece not_a_cert("hello");
- const uint64_t in_hash = UINT64_C(0xc9fef74053f99f39);
- uint64_t hash;
- uint32_t index;
- EXPECT_FALSE(sets->MatchCert(
- not_a_cert,
- StringPiece(reinterpret_cast<const char*>(&in_hash), sizeof(in_hash)),
- &hash, &index));
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/crypto_framer.cc b/chromium/net/quic/crypto/crypto_framer.cc
deleted file mode 100644
index 9b2fc2d80af..00000000000
--- a/chromium/net/quic/crypto/crypto_framer.cc
+++ /dev/null
@@ -1,294 +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/crypto/crypto_framer.h"
-
-#include <memory>
-
-#include "base/strings/stringprintf.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/quic_data_reader.h"
-#include "net/quic/quic_data_writer.h"
-
-using base::StringPiece;
-using std::pair;
-using std::vector;
-
-namespace net {
-
-namespace {
-
-const size_t kQuicTagSize = sizeof(uint32_t);
-const size_t kCryptoEndOffsetSize = sizeof(uint32_t);
-const size_t kNumEntriesSize = sizeof(uint16_t);
-
-// OneShotVisitor is a framer visitor that records a single handshake message.
-class OneShotVisitor : public CryptoFramerVisitorInterface {
- public:
- OneShotVisitor() : error_(false) {}
-
- void OnError(CryptoFramer* framer) override { error_ = true; }
-
- void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
- out_.reset(new CryptoHandshakeMessage(message));
- }
-
- bool error() const { return error_; }
-
- CryptoHandshakeMessage* release() { return out_.release(); }
-
- private:
- std::unique_ptr<CryptoHandshakeMessage> out_;
- bool error_;
-};
-
-} // namespace
-
-CryptoFramer::CryptoFramer()
- : visitor_(nullptr), error_detail_(""), num_entries_(0), values_len_(0) {
- Clear();
-}
-
-CryptoFramer::~CryptoFramer() {}
-
-// static
-CryptoHandshakeMessage* CryptoFramer::ParseMessage(StringPiece in) {
- OneShotVisitor visitor;
- CryptoFramer framer;
-
- framer.set_visitor(&visitor);
- if (!framer.ProcessInput(in) || visitor.error() ||
- framer.InputBytesRemaining()) {
- return nullptr;
- }
-
- return visitor.release();
-}
-
-bool CryptoFramer::ProcessInput(StringPiece input) {
- DCHECK_EQ(QUIC_NO_ERROR, error_);
- if (error_ != QUIC_NO_ERROR) {
- return false;
- }
- error_ = Process(input);
- if (error_ != QUIC_NO_ERROR) {
- DCHECK(!error_detail_.empty());
- visitor_->OnError(this);
- return false;
- }
-
- return true;
-}
-
-// static
-QuicData* CryptoFramer::ConstructHandshakeMessage(
- const CryptoHandshakeMessage& message) {
- size_t num_entries = message.tag_value_map().size();
- size_t pad_length = 0;
- bool need_pad_tag = false;
- bool need_pad_value = false;
-
- size_t len = message.size();
- if (len < message.minimum_size()) {
- need_pad_tag = true;
- need_pad_value = true;
- num_entries++;
-
- size_t delta = message.minimum_size() - len;
- const size_t overhead = kQuicTagSize + kCryptoEndOffsetSize;
- if (delta > overhead) {
- pad_length = delta - overhead;
- }
- len += overhead + pad_length;
- }
-
- if (num_entries > kMaxEntries) {
- return nullptr;
- }
-
- std::unique_ptr<char[]> buffer(new char[len]);
- QuicDataWriter writer(len, buffer.get());
- if (!writer.WriteUInt32(message.tag())) {
- DCHECK(false) << "Failed to write message tag.";
- return nullptr;
- }
- if (!writer.WriteUInt16(static_cast<uint16_t>(num_entries))) {
- DCHECK(false) << "Failed to write size.";
- return nullptr;
- }
- if (!writer.WriteUInt16(0)) {
- DCHECK(false) << "Failed to write padding.";
- return nullptr;
- }
-
- uint32_t end_offset = 0;
- // Tags and offsets
- for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin();
- it != message.tag_value_map().end(); ++it) {
- if (it->first == kPAD && need_pad_tag) {
- // Existing PAD tags are only checked when padding needs to be added
- // because parts of the code may need to reserialize received messages
- // and those messages may, legitimately include padding.
- DCHECK(false) << "Message needed padding but already contained a PAD tag";
- return nullptr;
- }
-
- if (it->first > kPAD && need_pad_tag) {
- need_pad_tag = false;
- if (!WritePadTag(&writer, pad_length, &end_offset)) {
- return nullptr;
- }
- }
-
- if (!writer.WriteUInt32(it->first)) {
- DCHECK(false) << "Failed to write tag.";
- return nullptr;
- }
- end_offset += it->second.length();
- if (!writer.WriteUInt32(end_offset)) {
- DCHECK(false) << "Failed to write end offset.";
- return nullptr;
- }
- }
-
- if (need_pad_tag) {
- if (!WritePadTag(&writer, pad_length, &end_offset)) {
- return nullptr;
- }
- }
-
- // Values
- for (QuicTagValueMap::const_iterator it = message.tag_value_map().begin();
- it != message.tag_value_map().end(); ++it) {
- if (it->first > kPAD && need_pad_value) {
- need_pad_value = false;
- if (!writer.WriteRepeatedByte('-', pad_length)) {
- DCHECK(false) << "Failed to write padding.";
- return nullptr;
- }
- }
-
- if (!writer.WriteBytes(it->second.data(), it->second.length())) {
- DCHECK(false) << "Failed to write value.";
- return nullptr;
- }
- }
-
- if (need_pad_value) {
- if (!writer.WriteRepeatedByte('-', pad_length)) {
- DCHECK(false) << "Failed to write padding.";
- return nullptr;
- }
- }
-
- return new QuicData(buffer.release(), len, true);
-}
-
-void CryptoFramer::Clear() {
- message_.Clear();
- tags_and_lengths_.clear();
- error_ = QUIC_NO_ERROR;
- error_detail_ = "";
- state_ = STATE_READING_TAG;
-}
-
-QuicErrorCode CryptoFramer::Process(StringPiece input) {
- // Add this data to the buffer.
- buffer_.append(input.data(), input.length());
- QuicDataReader reader(buffer_.data(), buffer_.length());
-
- switch (state_) {
- case STATE_READING_TAG:
- if (reader.BytesRemaining() < kQuicTagSize) {
- break;
- }
- QuicTag message_tag;
- reader.ReadUInt32(&message_tag);
- message_.set_tag(message_tag);
- state_ = STATE_READING_NUM_ENTRIES;
- case STATE_READING_NUM_ENTRIES:
- if (reader.BytesRemaining() < kNumEntriesSize + sizeof(uint16_t)) {
- break;
- }
- reader.ReadUInt16(&num_entries_);
- if (num_entries_ > kMaxEntries) {
- error_detail_ = base::StringPrintf("%u entries", num_entries_);
- return QUIC_CRYPTO_TOO_MANY_ENTRIES;
- }
- uint16_t padding;
- reader.ReadUInt16(&padding);
-
- tags_and_lengths_.reserve(num_entries_);
- state_ = STATE_READING_TAGS_AND_LENGTHS;
- values_len_ = 0;
- case STATE_READING_TAGS_AND_LENGTHS: {
- if (reader.BytesRemaining() <
- num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) {
- break;
- }
-
- uint32_t last_end_offset = 0;
- for (unsigned i = 0; i < num_entries_; ++i) {
- QuicTag tag;
- reader.ReadUInt32(&tag);
- if (i > 0 && tag <= tags_and_lengths_[i - 1].first) {
- if (tag == tags_and_lengths_[i - 1].first) {
- error_detail_ = base::StringPrintf("Duplicate tag:%u", tag);
- return QUIC_CRYPTO_DUPLICATE_TAG;
- }
- error_detail_ = base::StringPrintf("Tag %u out of order", tag);
- return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
- }
-
- uint32_t end_offset;
- reader.ReadUInt32(&end_offset);
-
- if (end_offset < last_end_offset) {
- error_detail_ = base::StringPrintf("End offset: %u vs %u", end_offset,
- last_end_offset);
- return QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
- }
- tags_and_lengths_.push_back(std::make_pair(
- tag, static_cast<size_t>(end_offset - last_end_offset)));
- last_end_offset = end_offset;
- }
- values_len_ = last_end_offset;
- state_ = STATE_READING_VALUES;
- }
- case STATE_READING_VALUES:
- if (reader.BytesRemaining() < values_len_) {
- break;
- }
- for (const pair<QuicTag, size_t>& item : tags_and_lengths_) {
- StringPiece value;
- reader.ReadStringPiece(&value, item.second);
- message_.SetStringPiece(item.first, value);
- }
- visitor_->OnHandshakeMessage(message_);
- Clear();
- state_ = STATE_READING_TAG;
- break;
- }
- // Save any remaining data.
- buffer_ = reader.PeekRemainingPayload().as_string();
- return QUIC_NO_ERROR;
-}
-
-// static
-bool CryptoFramer::WritePadTag(QuicDataWriter* writer,
- size_t pad_length,
- uint32_t* end_offset) {
- if (!writer->WriteUInt32(kPAD)) {
- DCHECK(false) << "Failed to write tag.";
- return false;
- }
- *end_offset += pad_length;
- if (!writer->WriteUInt32(*end_offset)) {
- DCHECK(false) << "Failed to write end offset.";
- return false;
- }
- return true;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/crypto_framer.h b/chromium/net/quic/crypto/crypto_framer.h
deleted file mode 100644
index 150b05a0c78..00000000000
--- a/chromium/net/quic/crypto/crypto_framer.h
+++ /dev/null
@@ -1,118 +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.
-
-#ifndef NET_QUIC_CRYPTO_CRYPTO_FRAMER_H_
-#define NET_QUIC_CRYPTO_CRYPTO_FRAMER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <utility>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-class CryptoFramer;
-class QuicData;
-class QuicDataReader;
-class QuicDataWriter;
-
-class NET_EXPORT_PRIVATE CryptoFramerVisitorInterface {
- public:
- virtual ~CryptoFramerVisitorInterface() {}
-
- // Called if an error is detected.
- virtual void OnError(CryptoFramer* framer) = 0;
-
- // Called when a complete handshake message has been parsed.
- virtual void OnHandshakeMessage(const CryptoHandshakeMessage& message) = 0;
-};
-
-// A class for framing the crypto messages that are exchanged in a QUIC
-// session.
-class NET_EXPORT_PRIVATE CryptoFramer {
- public:
- CryptoFramer();
-
- virtual ~CryptoFramer();
-
- // ParseMessage parses exactly one message from the given StringPiece. If
- // there is an error, the message is truncated, or the message has trailing
- // garbage then nullptr will be returned.
- static CryptoHandshakeMessage* ParseMessage(base::StringPiece in);
-
- // Set callbacks to be called from the framer. A visitor must be set, or
- // else the framer will crash. It is acceptable for the visitor to do
- // nothing. If this is called multiple times, only the last visitor
- // will be used. |visitor| will be owned by the framer.
- void set_visitor(CryptoFramerVisitorInterface* visitor) {
- visitor_ = visitor;
- }
-
- QuicErrorCode error() const { return error_; }
- const std::string& error_detail() const { return error_detail_; }
-
- // Processes input data, which must be delivered in order. Returns
- // false if there was an error, and true otherwise.
- bool ProcessInput(base::StringPiece input);
-
- // Returns the number of bytes of buffered input data remaining to be
- // parsed.
- size_t InputBytesRemaining() const { return buffer_.length(); }
-
- // Returns a new QuicData owned by the caller that contains a serialized
- // |message|, or nullptr if there was an error.
- static QuicData* ConstructHandshakeMessage(
- const CryptoHandshakeMessage& message);
-
- private:
- // Clears per-message state. Does not clear the visitor.
- void Clear();
-
- // Process does does the work of |ProcessInput|, but returns an error code,
- // doesn't set error_ and doesn't call |visitor_->OnError()|.
- QuicErrorCode Process(base::StringPiece input);
-
- static bool WritePadTag(QuicDataWriter* writer,
- size_t pad_length,
- uint32_t* end_offset);
-
- // Represents the current state of the parsing state machine.
- enum CryptoFramerState {
- STATE_READING_TAG,
- STATE_READING_NUM_ENTRIES,
- STATE_READING_TAGS_AND_LENGTHS,
- STATE_READING_VALUES
- };
-
- // Visitor to invoke when messages are parsed.
- CryptoFramerVisitorInterface* visitor_;
- // Last error.
- QuicErrorCode error_;
- // Remaining unparsed data.
- std::string buffer_;
- // Current state of the parsing.
- CryptoFramerState state_;
- // The message currently being parsed.
- CryptoHandshakeMessage message_;
- // The issue which caused |error_|
- std::string error_detail_;
- // Number of entires in the message currently being parsed.
- uint16_t num_entries_;
- // tags_and_lengths_ contains the tags that are currently being parsed and
- // their lengths.
- std::vector<std::pair<QuicTag, size_t>> tags_and_lengths_;
- // Cumulative length of all values in the message currently being parsed.
- size_t values_len_;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_CRYPTO_FRAMER_H_
diff --git a/chromium/net/quic/crypto/crypto_framer_test.cc b/chromium/net/quic/crypto/crypto_framer_test.cc
deleted file mode 100644
index e39c21f608b..00000000000
--- a/chromium/net/quic/crypto/crypto_framer_test.cc
+++ /dev/null
@@ -1,471 +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/crypto/crypto_framer.h"
-
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "base/logging.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-
-using base::StringPiece;
-using std::map;
-using std::string;
-using std::vector;
-
-namespace net {
-
-namespace {
-
-char* AsChars(unsigned char* data) {
- return reinterpret_cast<char*>(data);
-}
-
-} // namespace
-
-namespace test {
-
-class TestCryptoVisitor : public CryptoFramerVisitorInterface {
- public:
- TestCryptoVisitor() : error_count_(0) {}
-
- void OnError(CryptoFramer* framer) override {
- DLOG(ERROR) << "CryptoFramer Error: " << framer->error();
- ++error_count_;
- }
-
- void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
- messages_.push_back(message);
- }
-
- // Counters from the visitor callbacks.
- int error_count_;
-
- vector<CryptoHandshakeMessage> messages_;
-};
-
-TEST(CryptoFramerTest, ConstructHandshakeMessage) {
- CryptoHandshakeMessage message;
- message.set_tag(0xFFAA7733);
- message.SetStringPiece(0x12345678, "abcdef");
- message.SetStringPiece(0x12345679, "ghijk");
- message.SetStringPiece(0x1234567A, "lmnopqr");
-
- unsigned char packet[] = {
- // tag
- 0x33, 0x77, 0xAA, 0xFF,
- // num entries
- 0x03, 0x00,
- // padding
- 0x00, 0x00,
- // tag 1
- 0x78, 0x56, 0x34, 0x12,
- // end offset 1
- 0x06, 0x00, 0x00, 0x00,
- // tag 2
- 0x79, 0x56, 0x34, 0x12,
- // end offset 2
- 0x0b, 0x00, 0x00, 0x00,
- // tag 3
- 0x7A, 0x56, 0x34, 0x12,
- // end offset 3
- 0x12, 0x00, 0x00, 0x00,
- // value 1
- 'a', 'b', 'c', 'd', 'e', 'f',
- // value 2
- 'g', 'h', 'i', 'j', 'k',
- // value 3
- 'l', 'm', 'n', 'o', 'p', 'q', 'r',
- };
-
- CryptoFramer framer;
- std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
- ASSERT_TRUE(data.get() != nullptr);
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST(CryptoFramerTest, ConstructHandshakeMessageWithTwoKeys) {
- CryptoHandshakeMessage message;
- message.set_tag(0xFFAA7733);
- message.SetStringPiece(0x12345678, "abcdef");
- message.SetStringPiece(0x12345679, "ghijk");
-
- unsigned char packet[] = {
- // tag
- 0x33, 0x77, 0xAA, 0xFF,
- // num entries
- 0x02, 0x00,
- // padding
- 0x00, 0x00,
- // tag 1
- 0x78, 0x56, 0x34, 0x12,
- // end offset 1
- 0x06, 0x00, 0x00, 0x00,
- // tag 2
- 0x79, 0x56, 0x34, 0x12,
- // end offset 2
- 0x0b, 0x00, 0x00, 0x00,
- // value 1
- 'a', 'b', 'c', 'd', 'e', 'f',
- // value 2
- 'g', 'h', 'i', 'j', 'k',
- };
-
- CryptoFramer framer;
- std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
- ASSERT_TRUE(data.get() != nullptr);
-
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST(CryptoFramerTest, ConstructHandshakeMessageZeroLength) {
- CryptoHandshakeMessage message;
- message.set_tag(0xFFAA7733);
- message.SetStringPiece(0x12345678, "");
-
- unsigned char packet[] = {
- // tag
- 0x33, 0x77, 0xAA, 0xFF,
- // num entries
- 0x01, 0x00,
- // padding
- 0x00, 0x00,
- // tag 1
- 0x78, 0x56, 0x34, 0x12,
- // end offset 1
- 0x00, 0x00, 0x00, 0x00,
- };
-
- CryptoFramer framer;
- std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
- ASSERT_TRUE(data.get() != nullptr);
-
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST(CryptoFramerTest, ConstructHandshakeMessageTooManyEntries) {
- CryptoHandshakeMessage message;
- message.set_tag(0xFFAA7733);
- for (uint32_t key = 1; key <= kMaxEntries + 1; ++key) {
- message.SetStringPiece(key, "abcdef");
- }
-
- CryptoFramer framer;
- std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
- EXPECT_TRUE(data.get() == nullptr);
-}
-
-TEST(CryptoFramerTest, ConstructHandshakeMessageMinimumSize) {
- CryptoHandshakeMessage message;
- message.set_tag(0xFFAA7733);
- message.SetStringPiece(0x01020304, "test");
- message.set_minimum_size(64);
-
- unsigned char packet[] = {
- // tag
- 0x33, 0x77, 0xAA, 0xFF,
- // num entries
- 0x02, 0x00,
- // padding
- 0x00, 0x00,
- // tag 1
- 'P', 'A', 'D', 0,
- // end offset 1
- 0x24, 0x00, 0x00, 0x00,
- // tag 2
- 0x04, 0x03, 0x02, 0x01,
- // end offset 2
- 0x28, 0x00, 0x00, 0x00,
- // 36 bytes of padding.
- '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
- '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
- '-', '-', '-', '-', '-', '-',
- // value 2
- 't', 'e', 's', 't',
- };
-
- CryptoFramer framer;
- std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
- ASSERT_TRUE(data.get() != nullptr);
-
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST(CryptoFramerTest, ConstructHandshakeMessageMinimumSizePadLast) {
- CryptoHandshakeMessage message;
- message.set_tag(0xFFAA7733);
- message.SetStringPiece(1, "");
- message.set_minimum_size(64);
-
- unsigned char packet[] = {
- // tag
- 0x33, 0x77, 0xAA, 0xFF,
- // num entries
- 0x02, 0x00,
- // padding
- 0x00, 0x00,
- // tag 1
- 0x01, 0x00, 0x00, 0x00,
- // end offset 1
- 0x00, 0x00, 0x00, 0x00,
- // tag 2
- 'P', 'A', 'D', 0,
- // end offset 2
- 0x28, 0x00, 0x00, 0x00,
- // 40 bytes of padding.
- '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
- '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
- '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',
- };
-
- CryptoFramer framer;
- std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
- ASSERT_TRUE(data.get() != nullptr);
-
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST(CryptoFramerTest, ProcessInput) {
- test::TestCryptoVisitor visitor;
- CryptoFramer framer;
- framer.set_visitor(&visitor);
-
- unsigned char input[] = {
- // tag
- 0x33, 0x77, 0xAA, 0xFF,
- // num entries
- 0x02, 0x00,
- // padding
- 0x00, 0x00,
- // tag 1
- 0x78, 0x56, 0x34, 0x12,
- // end offset 1
- 0x06, 0x00, 0x00, 0x00,
- // tag 2
- 0x79, 0x56, 0x34, 0x12,
- // end offset 2
- 0x0b, 0x00, 0x00, 0x00,
- // value 1
- 'a', 'b', 'c', 'd', 'e', 'f',
- // value 2
- 'g', 'h', 'i', 'j', 'k',
- };
-
- EXPECT_TRUE(
- framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
- EXPECT_EQ(0u, framer.InputBytesRemaining());
- EXPECT_EQ(0, visitor.error_count_);
- ASSERT_EQ(1u, visitor.messages_.size());
- const CryptoHandshakeMessage& message = visitor.messages_[0];
- EXPECT_EQ(0xFFAA7733, message.tag());
- EXPECT_EQ(2u, message.tag_value_map().size());
- EXPECT_EQ("abcdef", CryptoTestUtils::GetValueForTag(message, 0x12345678));
- EXPECT_EQ("ghijk", CryptoTestUtils::GetValueForTag(message, 0x12345679));
-}
-
-TEST(CryptoFramerTest, ProcessInputWithThreeKeys) {
- test::TestCryptoVisitor visitor;
- CryptoFramer framer;
- framer.set_visitor(&visitor);
-
- unsigned char input[] = {
- // tag
- 0x33, 0x77, 0xAA, 0xFF,
- // num entries
- 0x03, 0x00,
- // padding
- 0x00, 0x00,
- // tag 1
- 0x78, 0x56, 0x34, 0x12,
- // end offset 1
- 0x06, 0x00, 0x00, 0x00,
- // tag 2
- 0x79, 0x56, 0x34, 0x12,
- // end offset 2
- 0x0b, 0x00, 0x00, 0x00,
- // tag 3
- 0x7A, 0x56, 0x34, 0x12,
- // end offset 3
- 0x12, 0x00, 0x00, 0x00,
- // value 1
- 'a', 'b', 'c', 'd', 'e', 'f',
- // value 2
- 'g', 'h', 'i', 'j', 'k',
- // value 3
- 'l', 'm', 'n', 'o', 'p', 'q', 'r',
- };
-
- EXPECT_TRUE(
- framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
- EXPECT_EQ(0u, framer.InputBytesRemaining());
- EXPECT_EQ(0, visitor.error_count_);
- ASSERT_EQ(1u, visitor.messages_.size());
- const CryptoHandshakeMessage& message = visitor.messages_[0];
- EXPECT_EQ(0xFFAA7733, message.tag());
- EXPECT_EQ(3u, message.tag_value_map().size());
- EXPECT_EQ("abcdef", CryptoTestUtils::GetValueForTag(message, 0x12345678));
- EXPECT_EQ("ghijk", CryptoTestUtils::GetValueForTag(message, 0x12345679));
- EXPECT_EQ("lmnopqr", CryptoTestUtils::GetValueForTag(message, 0x1234567A));
-}
-
-TEST(CryptoFramerTest, ProcessInputIncrementally) {
- test::TestCryptoVisitor visitor;
- CryptoFramer framer;
- framer.set_visitor(&visitor);
-
- unsigned char input[] = {
- // tag
- 0x33, 0x77, 0xAA, 0xFF,
- // num entries
- 0x02, 0x00,
- // padding
- 0x00, 0x00,
- // tag 1
- 0x78, 0x56, 0x34, 0x12,
- // end offset 1
- 0x06, 0x00, 0x00, 0x00,
- // tag 2
- 0x79, 0x56, 0x34, 0x12,
- // end offset 2
- 0x0b, 0x00, 0x00, 0x00,
- // value 1
- 'a', 'b', 'c', 'd', 'e', 'f',
- // value 2
- 'g', 'h', 'i', 'j', 'k',
- };
-
- for (size_t i = 0; i < arraysize(input); i++) {
- EXPECT_TRUE(framer.ProcessInput(StringPiece(AsChars(input) + i, 1)));
- }
- EXPECT_EQ(0u, framer.InputBytesRemaining());
- ASSERT_EQ(1u, visitor.messages_.size());
- const CryptoHandshakeMessage& message = visitor.messages_[0];
- EXPECT_EQ(0xFFAA7733, message.tag());
- EXPECT_EQ(2u, message.tag_value_map().size());
- EXPECT_EQ("abcdef", CryptoTestUtils::GetValueForTag(message, 0x12345678));
- EXPECT_EQ("ghijk", CryptoTestUtils::GetValueForTag(message, 0x12345679));
-}
-
-TEST(CryptoFramerTest, ProcessInputTagsOutOfOrder) {
- test::TestCryptoVisitor visitor;
- CryptoFramer framer;
- framer.set_visitor(&visitor);
-
- unsigned char input[] = {
- // tag
- 0x33, 0x77, 0xAA, 0xFF,
- // num entries
- 0x02, 0x00,
- // padding
- 0x00, 0x00,
- // tag 1
- 0x78, 0x56, 0x34, 0x13,
- // end offset 1
- 0x01, 0x00, 0x00, 0x00,
- // tag 2
- 0x79, 0x56, 0x34, 0x12,
- // end offset 2
- 0x02, 0x00, 0x00, 0x00,
- };
-
- EXPECT_FALSE(
- framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
- EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error());
- EXPECT_EQ(1, visitor.error_count_);
-}
-
-TEST(CryptoFramerTest, ProcessEndOffsetsOutOfOrder) {
- test::TestCryptoVisitor visitor;
- CryptoFramer framer;
- framer.set_visitor(&visitor);
-
- unsigned char input[] = {
- // tag
- 0x33, 0x77, 0xAA, 0xFF,
- // num entries
- 0x02, 0x00,
- // padding
- 0x00, 0x00,
- // tag 1
- 0x79, 0x56, 0x34, 0x12,
- // end offset 1
- 0x01, 0x00, 0x00, 0x00,
- // tag 2
- 0x78, 0x56, 0x34, 0x13,
- // end offset 2
- 0x00, 0x00, 0x00, 0x00,
- };
-
- EXPECT_FALSE(
- framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
- EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error());
- EXPECT_EQ(1, visitor.error_count_);
-}
-
-TEST(CryptoFramerTest, ProcessInputTooManyEntries) {
- test::TestCryptoVisitor visitor;
- CryptoFramer framer;
- framer.set_visitor(&visitor);
-
- unsigned char input[] = {
- // tag
- 0x33, 0x77, 0xAA, 0xFF,
- // num entries
- 0xA0, 0x00,
- // padding
- 0x00, 0x00,
- };
-
- EXPECT_FALSE(
- framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
- EXPECT_EQ(QUIC_CRYPTO_TOO_MANY_ENTRIES, framer.error());
- EXPECT_EQ(1, visitor.error_count_);
-}
-
-TEST(CryptoFramerTest, ProcessInputZeroLength) {
- test::TestCryptoVisitor visitor;
- CryptoFramer framer;
- framer.set_visitor(&visitor);
-
- unsigned char input[] = {
- // tag
- 0x33, 0x77, 0xAA, 0xFF,
- // num entries
- 0x02, 0x00,
- // padding
- 0x00, 0x00,
- // tag 1
- 0x78, 0x56, 0x34, 0x12,
- // end offset 1
- 0x00, 0x00, 0x00, 0x00,
- // tag 2
- 0x79, 0x56, 0x34, 0x12,
- // end offset 2
- 0x05, 0x00, 0x00, 0x00,
- };
-
- EXPECT_TRUE(
- framer.ProcessInput(StringPiece(AsChars(input), arraysize(input))));
- EXPECT_EQ(0, visitor.error_count_);
-}
-
-} // namespace test
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/crypto_handshake.cc b/chromium/net/quic/crypto/crypto_handshake.cc
deleted file mode 100644
index 23f64afdb4a..00000000000
--- a/chromium/net/quic/crypto/crypto_handshake.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2013 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/crypto/crypto_handshake.h"
-
-#include "net/quic/crypto/common_cert_set.h"
-#include "net/quic/crypto/key_exchange.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-
-namespace net {
-
-QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters()
- : key_exchange(0),
- aead(0),
- token_binding_key_param(0),
- x509_ecdsa_supported(false),
- x509_supported(false),
- sct_supported_by_client(false) {}
-
-QuicCryptoNegotiatedParameters::~QuicCryptoNegotiatedParameters() {}
-
-CrypterPair::CrypterPair() {}
-
-CrypterPair::~CrypterPair() {}
-
-// static
-const char QuicCryptoConfig::kInitialLabel[] = "QUIC key expansion";
-
-// static
-const char QuicCryptoConfig::kCETVLabel[] = "QUIC CETV block";
-
-// static
-const char QuicCryptoConfig::kForwardSecureLabel[] =
- "QUIC forward secure key expansion";
-
-QuicCryptoConfig::QuicCryptoConfig()
- : common_cert_sets(CommonCertSets::GetInstanceQUIC()) {}
-
-QuicCryptoConfig::~QuicCryptoConfig() {}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/crypto_handshake.h b/chromium/net/quic/crypto/crypto_handshake.h
deleted file mode 100644
index dd958c2e12a..00000000000
--- a/chromium/net/quic/crypto/crypto_handshake.h
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright (c) 2013 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_CRYPTO_CRYPTO_HANDSHAKE_H_
-#define NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-class CommonCertSets;
-class KeyExchange;
-class QuicDecrypter;
-class QuicEncrypter;
-
-// HandshakeFailureReason enum values are uploaded to UMA, they cannot be
-// changed.
-enum HandshakeFailureReason {
- HANDSHAKE_OK = 0,
-
- // Failure reasons for an invalid client nonce in CHLO.
- //
- // The default error value for nonce verification failures from strike
- // register (covers old strike registers and unknown failures).
- CLIENT_NONCE_UNKNOWN_FAILURE = 1,
- // Client nonce had incorrect length.
- CLIENT_NONCE_INVALID_FAILURE = 2,
- // Client nonce is not unique.
- CLIENT_NONCE_NOT_UNIQUE_FAILURE = 3,
- // Client orbit is invalid or incorrect.
- CLIENT_NONCE_INVALID_ORBIT_FAILURE = 4,
- // Client nonce's timestamp is not in the strike register's valid time range.
- CLIENT_NONCE_INVALID_TIME_FAILURE = 5,
- // Strike register's RPC call timed out, client nonce couldn't be verified.
- CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT = 6,
- // Strike register is down, client nonce couldn't be verified.
- CLIENT_NONCE_STRIKE_REGISTER_FAILURE = 7,
-
- // Failure reasons for an invalid server nonce in CHLO.
- //
- // Unbox of server nonce failed.
- SERVER_NONCE_DECRYPTION_FAILURE = 8,
- // Decrypted server nonce had incorrect length.
- SERVER_NONCE_INVALID_FAILURE = 9,
- // Server nonce is not unique.
- SERVER_NONCE_NOT_UNIQUE_FAILURE = 10,
- // Server nonce's timestamp is not in the strike register's valid time range.
- SERVER_NONCE_INVALID_TIME_FAILURE = 11,
- // The server requires handshake confirmation.
- SERVER_NONCE_REQUIRED_FAILURE = 20,
-
- // Failure reasons for an invalid server config in CHLO.
- //
- // Missing Server config id (kSCID) tag.
- SERVER_CONFIG_INCHOATE_HELLO_FAILURE = 12,
- // Couldn't find the Server config id (kSCID).
- SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE = 13,
-
- // Failure reasons for an invalid source-address token.
- //
- // Missing Source-address token (kSourceAddressTokenTag) tag.
- SOURCE_ADDRESS_TOKEN_INVALID_FAILURE = 14,
- // Unbox of Source-address token failed.
- SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE = 15,
- // Couldn't parse the unbox'ed Source-address token.
- SOURCE_ADDRESS_TOKEN_PARSE_FAILURE = 16,
- // Source-address token is for a different IP address.
- SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE = 17,
- // The source-address token has a timestamp in the future.
- SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE = 18,
- // The source-address token has expired.
- SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE = 19,
-
- // The expected leaf certificate hash could not be validated.
- INVALID_EXPECTED_LEAF_CERTIFICATE = 21,
-
- MAX_FAILURE_REASON = 22,
-};
-
-// These errors will be packed into an uint32_t and we don't want to set the
-// most significant bit, which may be misinterpreted as the sign bit.
-static_assert(MAX_FAILURE_REASON <= 32, "failure reason out of sync");
-
-// A CrypterPair contains the encrypter and decrypter for an encryption level.
-struct NET_EXPORT_PRIVATE CrypterPair {
- CrypterPair();
- ~CrypterPair();
- std::unique_ptr<QuicEncrypter> encrypter;
- std::unique_ptr<QuicDecrypter> decrypter;
-};
-
-// Parameters negotiated by the crypto handshake.
-struct NET_EXPORT_PRIVATE QuicCryptoNegotiatedParameters {
- // Initializes the members to 0 or empty values.
- QuicCryptoNegotiatedParameters();
- ~QuicCryptoNegotiatedParameters();
-
- QuicTag key_exchange;
- QuicTag aead;
- std::string initial_premaster_secret;
- std::string forward_secure_premaster_secret;
- // initial_subkey_secret is used as the PRK input to the HKDF used when
- // performing key extraction that needs to happen before forward-secure keys
- // are available.
- std::string initial_subkey_secret;
- // subkey_secret is used as the PRK input to the HKDF used for key extraction.
- std::string subkey_secret;
- CrypterPair initial_crypters;
- CrypterPair forward_secure_crypters;
- // Normalized SNI: converted to lower case and trailing '.' removed.
- std::string sni;
- std::string client_nonce;
- std::string server_nonce;
- // hkdf_input_suffix contains the HKDF input following the label: the
- // ConnectionId, client hello and server config. This is only populated in the
- // client because only the client needs to derive the forward secure keys at a
- // later time from the initial keys.
- std::string hkdf_input_suffix;
- // cached_certs contains the cached certificates that a client used when
- // sending a client hello.
- std::vector<std::string> cached_certs;
- // client_key_exchange is used by clients to store the ephemeral KeyExchange
- // for the connection.
- std::unique_ptr<KeyExchange> client_key_exchange;
- // channel_id is set by servers to a ChannelID key when the client correctly
- // proves possession of the corresponding private key. It consists of 32
- // bytes of x coordinate, followed by 32 bytes of y coordinate. Both values
- // are big-endian and the pair is a P-256 public key.
- std::string channel_id;
- QuicTag token_binding_key_param;
-
- // Used when generating proof signature when sending server config updates.
- bool x509_ecdsa_supported;
- bool x509_supported;
-
- // Used to generate cert chain when sending server config updates.
- std::string client_common_set_hashes;
- std::string client_cached_cert_hashes;
-
- // Default to false; set to true if the client indicates that it supports sct
- // by sending CSCT tag with an empty value in client hello.
- bool sct_supported_by_client;
-};
-
-// QuicCryptoConfig contains common configuration between clients and servers.
-class NET_EXPORT_PRIVATE QuicCryptoConfig {
- public:
- // kInitialLabel is a constant that is used when deriving the initial
- // (non-forward secure) keys for the connection in order to tie the resulting
- // key to this protocol.
- static const char kInitialLabel[];
-
- // kCETVLabel is a constant that is used when deriving the keys for the
- // encrypted tag/value block in the client hello.
- static const char kCETVLabel[];
-
- // kForwardSecureLabel is a constant that is used when deriving the forward
- // secure keys for the connection in order to tie the resulting key to this
- // protocol.
- static const char kForwardSecureLabel[];
-
- QuicCryptoConfig();
- ~QuicCryptoConfig();
-
- // Key exchange methods. The following two members' values correspond by
- // index.
- QuicTagVector kexs;
- // Authenticated encryption with associated data (AEAD) algorithms.
- QuicTagVector aead;
-
- // Supported Token Binding key parameters that can be negotiated in the client
- // hello.
- QuicTagVector tb_key_params;
-
- const CommonCertSets* common_cert_sets;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(QuicCryptoConfig);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_H_
diff --git a/chromium/net/quic/crypto/crypto_handshake_message.cc b/chromium/net/quic/crypto/crypto_handshake_message.cc
deleted file mode 100644
index aef8dbf0256..00000000000
--- a/chromium/net/quic/crypto/crypto_handshake_message.cc
+++ /dev/null
@@ -1,317 +0,0 @@
-// Copyright (c) 2013 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/crypto/crypto_handshake_message.h"
-
-#include <memory>
-
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "net/quic/crypto/crypto_framer.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/crypto_utils.h"
-#include "net/quic/quic_socket_address_coder.h"
-#include "net/quic/quic_utils.h"
-
-using base::StringPiece;
-using base::StringPrintf;
-using std::string;
-using std::vector;
-
-namespace net {
-
-CryptoHandshakeMessage::CryptoHandshakeMessage() : tag_(0), minimum_size_(0) {}
-
-CryptoHandshakeMessage::CryptoHandshakeMessage(
- const CryptoHandshakeMessage& other)
- : tag_(other.tag_),
- tag_value_map_(other.tag_value_map_),
- minimum_size_(other.minimum_size_) {
- // Don't copy serialized_. scoped_ptr doesn't have a copy constructor.
- // The new object can lazily reconstruct serialized_.
-}
-
-CryptoHandshakeMessage::~CryptoHandshakeMessage() {}
-
-CryptoHandshakeMessage& CryptoHandshakeMessage::operator=(
- const CryptoHandshakeMessage& other) {
- tag_ = other.tag_;
- tag_value_map_ = other.tag_value_map_;
- // Don't copy serialized_. scoped_ptr doesn't have an assignment operator.
- // However, invalidate serialized_.
- serialized_.reset();
- minimum_size_ = other.minimum_size_;
- return *this;
-}
-
-void CryptoHandshakeMessage::Clear() {
- tag_ = 0;
- tag_value_map_.clear();
- minimum_size_ = 0;
- serialized_.reset();
-}
-
-const QuicData& CryptoHandshakeMessage::GetSerialized() const {
- if (!serialized_.get()) {
- serialized_.reset(CryptoFramer::ConstructHandshakeMessage(*this));
- }
- return *serialized_;
-}
-
-void CryptoHandshakeMessage::MarkDirty() {
- serialized_.reset();
-}
-
-void CryptoHandshakeMessage::SetStringPiece(QuicTag tag, StringPiece value) {
- tag_value_map_[tag] = value.as_string();
-}
-
-void CryptoHandshakeMessage::Erase(QuicTag tag) {
- tag_value_map_.erase(tag);
-}
-
-QuicErrorCode CryptoHandshakeMessage::GetTaglist(QuicTag tag,
- const QuicTag** out_tags,
- size_t* out_len) const {
- QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
- QuicErrorCode ret = QUIC_NO_ERROR;
-
- if (it == tag_value_map_.end()) {
- ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
- } else if (it->second.size() % sizeof(QuicTag) != 0) {
- ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- if (ret != QUIC_NO_ERROR) {
- *out_tags = nullptr;
- *out_len = 0;
- return ret;
- }
-
- *out_tags = reinterpret_cast<const QuicTag*>(it->second.data());
- *out_len = it->second.size() / sizeof(QuicTag);
- return ret;
-}
-
-bool CryptoHandshakeMessage::GetStringPiece(QuicTag tag,
- StringPiece* out) const {
- QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
- if (it == tag_value_map_.end()) {
- return false;
- }
- *out = it->second;
- return true;
-}
-
-QuicErrorCode CryptoHandshakeMessage::GetNthValue24(QuicTag tag,
- unsigned index,
- StringPiece* out) const {
- StringPiece value;
- if (!GetStringPiece(tag, &value)) {
- return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
- }
-
- for (unsigned i = 0;; i++) {
- if (value.empty()) {
- return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND;
- }
- if (value.size() < 3) {
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- const unsigned char* data =
- reinterpret_cast<const unsigned char*>(value.data());
- size_t size = static_cast<size_t>(data[0]) |
- (static_cast<size_t>(data[1]) << 8) |
- (static_cast<size_t>(data[2]) << 16);
- value.remove_prefix(3);
-
- if (value.size() < size) {
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- if (i == index) {
- *out = StringPiece(value.data(), size);
- return QUIC_NO_ERROR;
- }
-
- value.remove_prefix(size);
- }
-}
-
-QuicErrorCode CryptoHandshakeMessage::GetUint32(QuicTag tag,
- uint32_t* out) const {
- return GetPOD(tag, out, sizeof(uint32_t));
-}
-
-QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag,
- uint64_t* out) const {
- return GetPOD(tag, out, sizeof(uint64_t));
-}
-
-size_t CryptoHandshakeMessage::size() const {
- size_t ret = sizeof(QuicTag) + sizeof(uint16_t) /* number of entries */ +
- sizeof(uint16_t) /* padding */;
- ret += (sizeof(QuicTag) + sizeof(uint32_t) /* end offset */) *
- tag_value_map_.size();
- for (QuicTagValueMap::const_iterator i = tag_value_map_.begin();
- i != tag_value_map_.end(); ++i) {
- ret += i->second.size();
- }
-
- return ret;
-}
-
-void CryptoHandshakeMessage::set_minimum_size(size_t min_bytes) {
- if (min_bytes == minimum_size_) {
- return;
- }
- serialized_.reset();
- minimum_size_ = min_bytes;
-}
-
-size_t CryptoHandshakeMessage::minimum_size() const {
- return minimum_size_;
-}
-
-string CryptoHandshakeMessage::DebugString() const {
- return DebugStringInternal(0);
-}
-
-QuicErrorCode CryptoHandshakeMessage::GetPOD(QuicTag tag,
- void* out,
- size_t len) const {
- QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
- QuicErrorCode ret = QUIC_NO_ERROR;
-
- if (it == tag_value_map_.end()) {
- ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
- } else if (it->second.size() != len) {
- ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- if (ret != QUIC_NO_ERROR) {
- memset(out, 0, len);
- return ret;
- }
-
- memcpy(out, it->second.data(), len);
- return ret;
-}
-
-string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
- string ret = string(2 * indent, ' ') + QuicUtils::TagToString(tag_) + "<\n";
- ++indent;
- for (QuicTagValueMap::const_iterator it = tag_value_map_.begin();
- it != tag_value_map_.end(); ++it) {
- ret += string(2 * indent, ' ') + QuicUtils::TagToString(it->first) + ": ";
-
- bool done = false;
- switch (it->first) {
- case kICSL:
- case kCFCW:
- case kSFCW:
- case kIRTT:
- case kMSPC:
- case kSRBF:
- case kSWND:
- // uint32_t value
- if (it->second.size() == 4) {
- uint32_t value;
- memcpy(&value, it->second.data(), sizeof(value));
- ret += base::UintToString(value);
- done = true;
- }
- break;
- case kRCID:
- // uint64_t value
- if (it->second.size() == 8) {
- uint64_t value;
- memcpy(&value, it->second.data(), sizeof(value));
- ret += base::Uint64ToString(value);
- done = true;
- }
- break;
- case kTBKP:
- case kKEXS:
- case kAEAD:
- case kCOPT:
- case kPDMD:
- case kVER:
- // tag lists
- if (it->second.size() % sizeof(QuicTag) == 0) {
- for (size_t j = 0; j < it->second.size(); j += sizeof(QuicTag)) {
- QuicTag tag;
- memcpy(&tag, it->second.data() + j, sizeof(tag));
- if (j > 0) {
- ret += ",";
- }
- ret += "'" + QuicUtils::TagToString(tag) + "'";
- }
- done = true;
- }
- break;
- case kRREJ:
- // uint32_t lists
- if (it->second.size() % sizeof(uint32_t) == 0) {
- for (size_t j = 0; j < it->second.size(); j += sizeof(uint32_t)) {
- uint32_t value;
- memcpy(&value, it->second.data() + j, sizeof(value));
- if (j > 0) {
- ret += ",";
- }
- ret += CryptoUtils::HandshakeFailureReasonToString(
- static_cast<HandshakeFailureReason>(value));
- }
- done = true;
- }
- break;
- case kCADR:
- // IP address and port
- if (!it->second.empty()) {
- QuicSocketAddressCoder decoder;
- if (decoder.Decode(it->second.data(), it->second.size())) {
- ret += IPAddressToStringWithPort(decoder.ip(), decoder.port());
- done = true;
- }
- }
- break;
- case kSCFG:
- // nested messages.
- if (!it->second.empty()) {
- std::unique_ptr<CryptoHandshakeMessage> msg(
- CryptoFramer::ParseMessage(it->second));
- if (msg.get()) {
- ret += "\n";
- ret += msg->DebugStringInternal(indent + 1);
-
- done = true;
- }
- }
- break;
- case kPAD:
- ret += StringPrintf("(%d bytes of padding)",
- static_cast<int>(it->second.size()));
- done = true;
- break;
- case kSNI:
- case kUAID:
- ret += "\"" + it->second + "\"";
- done = true;
- break;
- }
-
- if (!done) {
- // If there's no specific format for this tag, or the value is invalid,
- // then just use hex.
- ret += "0x" + QuicUtils::HexEncode(it->second);
- }
- ret += "\n";
- }
- --indent;
- ret += string(2 * indent, ' ') + ">";
- return ret;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/crypto_handshake_message.h b/chromium/net/quic/crypto/crypto_handshake_message.h
deleted file mode 100644
index 6e4da1609b7..00000000000
--- a/chromium/net/quic/crypto/crypto_handshake_message.h
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright (c) 2013 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_CRYPTO_CRYPTO_HANDSHAKE_MESSAGE_H_
-#define NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_MESSAGE_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-// An intermediate format of a handshake message that's convenient for a
-// CryptoFramer to serialize from or parse into.
-class NET_EXPORT_PRIVATE CryptoHandshakeMessage {
- public:
- CryptoHandshakeMessage();
- CryptoHandshakeMessage(const CryptoHandshakeMessage& other);
- ~CryptoHandshakeMessage();
-
- CryptoHandshakeMessage& operator=(const CryptoHandshakeMessage& other);
-
- // Clears state.
- void Clear();
-
- // GetSerialized returns the serialized form of this message and caches the
- // result. Subsequently altering the message does not invalidate the cache.
- const QuicData& GetSerialized() const;
-
- // MarkDirty invalidates the cache created by |GetSerialized|.
- void MarkDirty();
-
- // SetValue sets an element with the given tag to the raw, memory contents of
- // |v|.
- template <class T>
- void SetValue(QuicTag tag, const T& v) {
- tag_value_map_[tag] =
- std::string(reinterpret_cast<const char*>(&v), sizeof(v));
- }
-
- // SetVector sets an element with the given tag to the raw contents of an
- // array of elements in |v|.
- template <class T>
- void SetVector(QuicTag tag, const std::vector<T>& v) {
- if (v.empty()) {
- tag_value_map_[tag] = std::string();
- } else {
- tag_value_map_[tag] = std::string(reinterpret_cast<const char*>(&v[0]),
- v.size() * sizeof(T));
- }
- }
-
- // Returns the message tag.
- QuicTag tag() const { return tag_; }
- // Sets the message tag.
- void set_tag(QuicTag tag) { tag_ = tag; }
-
- const QuicTagValueMap& tag_value_map() const { return tag_value_map_; }
-
- void SetStringPiece(QuicTag tag, base::StringPiece value);
-
- // Erase removes a tag/value, if present, from the message.
- void Erase(QuicTag tag);
-
- // GetTaglist finds an element with the given tag containing zero or more
- // tags. If such a tag doesn't exist, it returns false. Otherwise it sets
- // |out_tags| and |out_len| to point to the array of tags and returns true.
- // The array points into the CryptoHandshakeMessage and is valid only for as
- // long as the CryptoHandshakeMessage exists and is not modified.
- QuicErrorCode GetTaglist(QuicTag tag,
- const QuicTag** out_tags,
- size_t* out_len) const;
-
- bool GetStringPiece(QuicTag tag, base::StringPiece* out) const;
-
- // GetNthValue24 interprets the value with the given tag to be a series of
- // 24-bit, length prefixed values and it returns the subvalue with the given
- // index.
- QuicErrorCode GetNthValue24(QuicTag tag,
- unsigned index,
- base::StringPiece* out) const;
- QuicErrorCode GetUint32(QuicTag tag, uint32_t* out) const;
- QuicErrorCode GetUint64(QuicTag tag, uint64_t* out) const;
-
- // size returns 4 (message tag) + 2 (uint16_t, number of entries) +
- // (4 (tag) + 4 (end offset))*tag_value_map_.size() + ∑ value sizes.
- size_t size() const;
-
- // set_minimum_size sets the minimum number of bytes that the message should
- // consume. The CryptoFramer will add a PAD tag as needed when serializing in
- // order to ensure this. Setting a value of 0 disables padding.
- //
- // Padding is useful in order to ensure that messages are a minimum size. A
- // QUIC server can require a minimum size in order to reduce the
- // amplification factor of any mirror DoS attack.
- void set_minimum_size(size_t min_bytes);
-
- size_t minimum_size() const;
-
- // DebugString returns a multi-line, string representation of the message
- // suitable for including in debug output.
- std::string DebugString() const;
-
- private:
- // GetPOD is a utility function for extracting a plain-old-data value. If
- // |tag| exists in the message, and has a value of exactly |len| bytes then
- // it copies |len| bytes of data into |out|. Otherwise |len| bytes at |out|
- // are zeroed out.
- //
- // If used to copy integers then this assumes that the machine is
- // little-endian.
- QuicErrorCode GetPOD(QuicTag tag, void* out, size_t len) const;
-
- std::string DebugStringInternal(size_t indent) const;
-
- QuicTag tag_;
- QuicTagValueMap tag_value_map_;
-
- size_t minimum_size_;
-
- // The serialized form of the handshake message. This member is constructed
- // lasily.
- mutable std::unique_ptr<QuicData> serialized_;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_CRYPTO_HANDSHAKE_MESSAGE_H_
diff --git a/chromium/net/quic/crypto/crypto_handshake_message_test.cc b/chromium/net/quic/crypto/crypto_handshake_message_test.cc
deleted file mode 100644
index e8a5e4f91d2..00000000000
--- a/chromium/net/quic/crypto/crypto_handshake_message_test.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.
-
-#include "net/quic/crypto/crypto_handshake_message.h"
-
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/test/gtest_util.h"
-
-namespace net {
-namespace test {
-namespace {
-
-TEST(CryptoHandshakeMessageTest, DebugString) {
- CryptoHandshakeMessage message;
- message.set_tag(kSHLO);
- EXPECT_EQ("SHLO<\n>", message.DebugString());
-}
-
-TEST(CryptoHandshakeMessageTest, DebugStringWithUintVector) {
- CryptoHandshakeMessage message;
- message.set_tag(kREJ);
- std::vector<uint32_t> reasons = {
- SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
- CLIENT_NONCE_NOT_UNIQUE_FAILURE};
- message.SetVector(kRREJ, reasons);
- EXPECT_EQ(
- "REJ <\n RREJ: "
- "SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,"
- "CLIENT_NONCE_NOT_UNIQUE_FAILURE\n>",
- message.DebugString());
-}
-
-TEST(CryptoHandshakeMessageTest, DebugStringWithTagVector) {
- CryptoHandshakeMessage message;
- message.set_tag(kCHLO);
- message.SetVector(kCOPT, QuicTagVector{kTBBR, kPAD, kBYTE});
- EXPECT_EQ("CHLO<\n COPT: 'TBBR','PAD ','BYTE'\n>", message.DebugString());
-}
-
-TEST(CryptoHandshakeMessageTest, ServerDesignatedConnectionId) {
- CryptoHandshakeMessage message;
- message.set_tag(kSREJ);
- message.SetValue(kRCID, UINT64_C(18364758544493064720));
- EXPECT_EQ("SREJ<\n RCID: 18364758544493064720\n>", message.DebugString());
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/crypto_protocol.h b/chromium/net/quic/crypto/crypto_protocol.h
deleted file mode 100644
index 4c47af09c9d..00000000000
--- a/chromium/net/quic/crypto/crypto_protocol.h
+++ /dev/null
@@ -1,250 +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.
-
-#ifndef NET_QUIC_CRYPTO_CRYPTO_PROTOCOL_H_
-#define NET_QUIC_CRYPTO_CRYPTO_PROTOCOL_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-
-#include "net/base/net_export.h"
-#include "net/quic/quic_protocol.h"
-
-// Version and Crypto tags are written to the wire with a big-endian
-// representation of the name of the tag. For example
-// the client hello tag (CHLO) will be written as the
-// following 4 bytes: 'C' 'H' 'L' 'O'. Since it is
-// stored in memory as a little endian uint32_t, we need
-// to reverse the order of the bytes.
-//
-// We use a macro to ensure that no static initialisers are created. Use the
-// MakeQuicTag function in normal code.
-#define TAG(a, b, c, d) \
- static_cast<QuicTag>((d << 24) + (c << 16) + (b << 8) + a)
-
-namespace net {
-
-typedef std::string ServerConfigID;
-
-// clang-format off
-const QuicTag kCHLO = TAG('C', 'H', 'L', 'O'); // Client hello
-const QuicTag kSHLO = TAG('S', 'H', 'L', 'O'); // Server hello
-const QuicTag kSCFG = TAG('S', 'C', 'F', 'G'); // Server config
-const QuicTag kREJ = TAG('R', 'E', 'J', '\0'); // Reject
-const QuicTag kSREJ = TAG('S', 'R', 'E', 'J'); // Stateless reject
-const QuicTag kCETV = TAG('C', 'E', 'T', 'V'); // Client encrypted tag-value
- // pairs
-const QuicTag kPRST = TAG('P', 'R', 'S', 'T'); // Public reset
-const QuicTag kSCUP = TAG('S', 'C', 'U', 'P'); // Server config update.
-
-// Key exchange methods
-const QuicTag kP256 = TAG('P', '2', '5', '6'); // ECDH, Curve P-256
-const QuicTag kC255 = TAG('C', '2', '5', '5'); // ECDH, Curve25519
-
-// AEAD algorithms
-const QuicTag kNULL = TAG('N', 'U', 'L', 'N'); // null algorithm
-const QuicTag kAESG = TAG('A', 'E', 'S', 'G'); // AES128 + GCM-12
-const QuicTag kCC20 = TAG('C', 'C', '2', '0'); // ChaCha20 + Poly1305 RFC7539
-
-// Socket receive buffer
-const QuicTag kSRBF = TAG('S', 'R', 'B', 'F'); // Socket receive buffer
-
-// Congestion control feedback types
-const QuicTag kQBIC = TAG('Q', 'B', 'I', 'C'); // TCP cubic
-
-// Connection options (COPT) values
-const QuicTag kAFCW = TAG('A', 'F', 'C', 'W'); // Auto-tune flow control
- // receive windows.
-const QuicTag kIFW5 = TAG('I', 'F', 'W', '5'); // Set initial size
- // of stream flow control
- // receive window to
- // 32KB. (2^5 KB).
-const QuicTag kIFW6 = TAG('I', 'F', 'W', '6'); // Set initial size
- // of stream flow control
- // receive window to
- // 64KB. (2^6 KB).
-const QuicTag kIFW7 = TAG('I', 'F', 'W', '7'); // Set initial size
- // of stream flow control
- // receive window to
- // 128KB. (2^7 KB).
-const QuicTag kTBBR = TAG('T', 'B', 'B', 'R'); // Reduced Buffer Bloat TCP
-const QuicTag kRENO = TAG('R', 'E', 'N', 'O'); // Reno Congestion Control
-const QuicTag kBYTE = TAG('B', 'Y', 'T', 'E'); // TCP cubic or reno in bytes
-const QuicTag kRATE = TAG('R', 'A', 'T', 'E'); // TCP cubic rate based sending
-const QuicTag kIW03 = TAG('I', 'W', '0', '3'); // Force ICWND to 3
-const QuicTag kIW10 = TAG('I', 'W', '1', '0'); // Force ICWND to 10
-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 kNCON = TAG('N', 'C', 'O', 'N'); // N Connection Congestion Ctrl
-const QuicTag kNRTO = TAG('N', 'R', 'T', 'O'); // CWND reduction on loss
-const QuicTag kUNDO = TAG('U', 'N', 'D', 'O'); // Undo any pending retransmits
- // if they're likely spurious.
-const QuicTag kTIME = TAG('T', 'I', 'M', 'E'); // Time based loss detection
-const QuicTag kATIM = TAG('A', 'T', 'I', 'M'); // Adaptive time loss detection
-const QuicTag kMIN1 = TAG('M', 'I', 'N', '1'); // Min CWND of 1 packet
-const QuicTag kMIN4 = TAG('M', 'I', 'N', '4'); // Min CWND of 4 packets,
- // with a min rate of 1 BDP.
-const QuicTag kTLPR = TAG('T', 'L', 'P', 'R'); // Tail loss probe delay of
- // 0.5RTT.
-const QuicTag kACKD = TAG('A', 'C', 'K', 'D'); // Ack decimation style acking.
-const QuicTag kAKD2 = TAG('A', 'K', 'D', '2'); // Ack decimation tolerating
- // out of order packets.
-const QuicTag kAKD3 = TAG('A', 'K', 'D', '3'); // Ack decimation style acking
- // with 1/8 RTT acks.
-const QuicTag kAKD4 = TAG('A', 'K', 'D', '4'); // Ack decimation with 1/8 RTT
- // tolerating out of order.
-const QuicTag kSSLR = TAG('S', 'S', 'L', 'R'); // Slow Start Large Reduction.
-const QuicTag kNPRR = TAG('N', 'P', 'R', 'R'); // Pace at unity instead of PRR
-const QuicTag k5RTO = TAG('5', 'R', 'T', 'O'); // Close connection on 5 RTOs
-const QuicTag kCTIM = TAG('C', 'T', 'I', 'M'); // Client timestamp in seconds
- // since UNIX epoch.
-const QuicTag kDHDT = TAG('D', 'H', 'D', 'T'); // Disable HPACK dynamic table.
-const QuicTag kIPFS = TAG('I', 'P', 'F', 'S'); // No Immediate Forward Secrecy
-
-// Optional support of truncated Connection IDs. If sent by a peer, the value
-// is the minimum number of bytes allowed for the connection ID sent to the
-// peer.
-const QuicTag kTCID = TAG('T', 'C', 'I', 'D'); // Connection ID truncation.
-
-// Multipath option.
-const QuicTag kMPTH = TAG('M', 'P', 'T', 'H'); // Enable multipath.
-
-const QuicTag kNCMR = TAG('N', 'C', 'M', 'R'); // Do not attempt connection
- // migration.
-
-// Enable bandwidth resumption experiment.
-const QuicTag kBWRE = TAG('B', 'W', 'R', 'E'); // Bandwidth resumption.
-const QuicTag kBWMX = TAG('B', 'W', 'M', 'X'); // Max bandwidth resumption.
-const QuicTag kBWRS = TAG('B', 'W', 'R', 'S'); // Server bandwidth resumption.
-
-// Enable path MTU discovery experiment.
-const QuicTag kMTUH = TAG('M', 'T', 'U', 'H'); // High-target MTU discovery.
-const QuicTag kMTUL = TAG('M', 'T', 'U', 'L'); // Low-target MTU discovery.
-
-// Proof types (i.e. certificate types)
-// NOTE: although it would be silly to do so, specifying both kX509 and kX59R
-// is allowed and is equivalent to specifying only kX509.
-const QuicTag kX509 = TAG('X', '5', '0', '9'); // X.509 certificate, all key
- // types
-const QuicTag kX59R = TAG('X', '5', '9', 'R'); // X.509 certificate, RSA keys
- // only
-const QuicTag kCHID = TAG('C', 'H', 'I', 'D'); // Channel ID.
-
-// Client hello tags
-const QuicTag kVER = TAG('V', 'E', 'R', '\0'); // Version
-const QuicTag kNONC = TAG('N', 'O', 'N', 'C'); // The client's nonce
-const QuicTag kNONP = TAG('N', 'O', 'N', 'P'); // The client's proof nonce
-const QuicTag kKEXS = TAG('K', 'E', 'X', 'S'); // Key exchange methods
-const QuicTag kAEAD = TAG('A', 'E', 'A', 'D'); // Authenticated
- // encryption algorithms
-const QuicTag kCOPT = TAG('C', 'O', 'P', 'T'); // Connection options
-const QuicTag kICSL = TAG('I', 'C', 'S', 'L'); // Idle connection state
- // lifetime
-const QuicTag kSCLS = TAG('S', 'C', 'L', 'S'); // Silently close on timeout
-const QuicTag kMSPC = TAG('M', 'S', 'P', 'C'); // Max streams per connection.
-const QuicTag kMIDS = TAG('M', 'I', 'D', 'S'); // Max incoming dynamic streams
-const QuicTag kIRTT = TAG('I', 'R', 'T', 'T'); // Estimated initial RTT in us.
-const QuicTag kSWND = TAG('S', 'W', 'N', 'D'); // Server's Initial congestion
- // window.
-const QuicTag kSNI = TAG('S', 'N', 'I', '\0'); // Server name
- // indication
-const QuicTag kPUBS = TAG('P', 'U', 'B', 'S'); // Public key values
-const QuicTag kSCID = TAG('S', 'C', 'I', 'D'); // Server config id
-const QuicTag kORBT = TAG('O', 'B', 'I', 'T'); // Server orbit.
-const QuicTag kPDMD = TAG('P', 'D', 'M', 'D'); // Proof demand.
-const QuicTag kPROF = TAG('P', 'R', 'O', 'F'); // Proof (signature).
-const QuicTag kCCS = TAG('C', 'C', 'S', 0); // Common certificate set
-const QuicTag kCCRT = TAG('C', 'C', 'R', 'T'); // Cached certificate
-const QuicTag kEXPY = TAG('E', 'X', 'P', 'Y'); // Expiry
-const QuicTag kSFCW = TAG('S', 'F', 'C', 'W'); // Initial stream flow control
- // receive window.
-const QuicTag kCFCW = TAG('C', 'F', 'C', 'W'); // Initial session/connection
- // flow control receive window.
-const QuicTag kUAID = TAG('U', 'A', 'I', 'D'); // Client's User Agent ID.
-const QuicTag kXLCT = TAG('X', 'L', 'C', 'T'); // Expected leaf certificate.
-const QuicTag kTBKP = TAG('T', 'B', 'K', 'P'); // Token Binding key params.
-
-// Rejection tags
-const QuicTag kRREJ = TAG('R', 'R', 'E', 'J'); // Reasons for server sending
-// Stateless Reject tags
-const QuicTag kRCID = TAG('R', 'C', 'I', 'D'); // Server-designated
- // connection ID
-// Server hello tags
-const QuicTag kCADR = TAG('C', 'A', 'D', 'R'); // Client IP address and port
-const QuicTag kASAD = TAG('A', 'S', 'A', 'D'); // Alternate Server IP address
- // and port.
-
-// CETV tags
-const QuicTag kCIDK = TAG('C', 'I', 'D', 'K'); // ChannelID key
-const QuicTag kCIDS = TAG('C', 'I', 'D', 'S'); // ChannelID signature
-
-// Public reset tags
-const QuicTag kRNON = TAG('R', 'N', 'O', 'N'); // Public reset nonce proof
-const QuicTag kRSEQ = TAG('R', 'S', 'E', 'Q'); // Rejected packet number
-
-// Universal tags
-const QuicTag kPAD = TAG('P', 'A', 'D', '\0'); // Padding
-
-// Server push tags
-const QuicTag kSPSH = TAG('S', 'P', 'S', 'H'); // Support server push.
-
-// Sent by clients with the fix to crbug/566156
-const QuicTag kFIXD = TAG('F', 'I', 'X', 'D'); // Client hello
-// clang-format on
-
-// These tags have a special form so that they appear either at the beginning
-// or the end of a handshake message. Since handshake messages are sorted by
-// tag value, the tags with 0 at the end will sort first and those with 255 at
-// the end will sort last.
-//
-// The certificate chain should have a tag that will cause it to be sorted at
-// the end of any handshake messages because it's likely to be large and the
-// client might be able to get everything that it needs from the small values at
-// the beginning.
-//
-// Likewise tags with random values should be towards the beginning of the
-// message because the server mightn't hold state for a rejected client hello
-// and therefore the client may have issues reassembling the rejection message
-// in the event that it sent two client hellos.
-const QuicTag kServerNonceTag = TAG('S', 'N', 'O', 0); // The server's nonce
-const QuicTag kSourceAddressTokenTag =
- TAG('S', 'T', 'K', 0); // Source-address token
-const QuicTag kCertificateTag = TAG('C', 'R', 'T', 255); // Certificate chain
-const QuicTag kCertificateSCTTag =
- TAG('C', 'S', 'C', 'T'); // Signed cert timestamp (RFC6962) of leaf cert.
-
-#undef TAG
-
-const size_t kMaxEntries = 128; // Max number of entries in a message.
-
-const size_t kNonceSize = 32; // Size in bytes of the connection nonce.
-
-const size_t kOrbitSize = 8; // Number of bytes in an orbit value.
-
-// kProofSignatureLabel is prepended to server configs before signing to avoid
-// any cross-protocol attacks on the signature.
-// TODO(rch): Remove this when QUIC_VERSION_30 is removed.
-const char kProofSignatureLabelOld[] = "QUIC server config signature";
-
-// kProofSignatureLabel is prepended to the CHLO hash and server configs before
-// signing to avoid any cross-protocol attacks on the signature.
-const char kProofSignatureLabel[] = "QUIC CHLO and server config signature";
-
-// kClientHelloMinimumSize is the minimum size of a client hello. Client hellos
-// will have PAD tags added in order to ensure this minimum is met and client
-// hellos smaller than this will be an error. This minimum size reduces the
-// amplification factor of any mirror DoS attack.
-//
-// A client may pad an inchoate client hello to a size larger than
-// kClientHelloMinimumSize to make it more likely to receive a complete
-// rejection message.
-const size_t kClientHelloMinimumSize = 1024;
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_CRYPTO_PROTOCOL_H_
diff --git a/chromium/net/quic/crypto/crypto_secret_boxer.cc b/chromium/net/quic/crypto/crypto_secret_boxer.cc
deleted file mode 100644
index 347333fb0d8..00000000000
--- a/chromium/net/quic/crypto/crypto_secret_boxer.cc
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright (c) 2013 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/crypto/crypto_secret_boxer.h"
-
-#include <memory>
-
-#include "base/logging.h"
-#include "net/quic/crypto/aes_128_gcm_12_decrypter.h"
-#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/crypto/quic_random.h"
-
-using base::StringPiece;
-using std::string;
-using std::vector;
-
-namespace net {
-
-// Defined kKeySize for GetKeySize() and SetKey().
-static const size_t kKeySize = 16;
-
-// kBoxNonceSize contains the number of bytes of nonce that we use in each box.
-// TODO(rtenneti): Add support for kBoxNonceSize to be 16 bytes.
-//
-// From agl@:
-// 96-bit nonces are on the edge. An attacker who can collect 2^41
-// source-address tokens has a 1% chance of finding a duplicate.
-//
-// The "average" DDoS is now 32.4M PPS. That's 2^25 source-address tokens
-// per second. So one day of that DDoS botnot would reach the 1% mark.
-//
-// It's not terrible, but it's not a "forget about it" margin.
-static const size_t kBoxNonceSize = 12;
-
-CryptoSecretBoxer::CryptoSecretBoxer() {}
-
-CryptoSecretBoxer::~CryptoSecretBoxer() {}
-
-// static
-size_t CryptoSecretBoxer::GetKeySize() {
- return kKeySize;
-}
-
-void CryptoSecretBoxer::SetKeys(const vector<string>& keys) {
- DCHECK(!keys.empty());
- vector<string> copy = keys;
- for (const string& key : keys) {
- DCHECK_EQ(kKeySize, key.size());
- }
- base::AutoLock l(lock_);
- keys_.swap(copy);
-}
-
-string CryptoSecretBoxer::Box(QuicRandom* rand, StringPiece plaintext) const {
- std::unique_ptr<Aes128Gcm12Encrypter> encrypter(new Aes128Gcm12Encrypter());
- {
- base::AutoLock l(lock_);
- DCHECK_EQ(kKeySize, keys_[0].size());
- if (!encrypter->SetKey(keys_[0])) {
- DLOG(DFATAL) << "CryptoSecretBoxer's encrypter->SetKey failed.";
- return string();
- }
- }
- size_t ciphertext_size = encrypter->GetCiphertextSize(plaintext.length());
-
- string ret;
- const size_t len = kBoxNonceSize + ciphertext_size;
- ret.resize(len);
- char* data = &ret[0];
-
- // Generate nonce.
- rand->RandBytes(data, kBoxNonceSize);
- memcpy(data + kBoxNonceSize, plaintext.data(), plaintext.size());
-
- if (!encrypter->Encrypt(
- StringPiece(data, kBoxNonceSize), StringPiece(), plaintext,
- reinterpret_cast<unsigned char*>(data + kBoxNonceSize))) {
- DLOG(DFATAL) << "CryptoSecretBoxer's Encrypt failed.";
- return string();
- }
-
- return ret;
-}
-
-bool CryptoSecretBoxer::Unbox(StringPiece ciphertext,
- string* out_storage,
- StringPiece* out) const {
- if (ciphertext.size() < kBoxNonceSize) {
- return false;
- }
-
- StringPiece nonce(ciphertext.data(), kBoxNonceSize);
- ciphertext.remove_prefix(kBoxNonceSize);
- QuicPacketNumber packet_number;
- StringPiece nonce_prefix(nonce.data(), nonce.size() - sizeof(packet_number));
- memcpy(&packet_number, nonce.data() + nonce_prefix.size(),
- sizeof(packet_number));
-
- std::unique_ptr<Aes128Gcm12Decrypter> decrypter(new Aes128Gcm12Decrypter());
- char plaintext[kMaxPacketSize];
- size_t plaintext_length = 0;
- bool ok = false;
- {
- base::AutoLock l(lock_);
- for (const string& key : keys_) {
- if (decrypter->SetKey(key)) {
- decrypter->SetNoncePrefix(nonce_prefix);
- if (decrypter->DecryptPacket(
- /*path_id=*/0u, packet_number,
- /*associated data=*/StringPiece(), ciphertext, plaintext,
- &plaintext_length, kMaxPacketSize)) {
- ok = true;
- break;
- }
- }
- }
- }
- if (!ok) {
- return false;
- }
-
- out_storage->resize(plaintext_length);
- out_storage->assign(plaintext, plaintext_length);
- out->set(out_storage->data(), plaintext_length);
- return true;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/crypto_secret_boxer_test.cc b/chromium/net/quic/crypto/crypto_secret_boxer_test.cc
deleted file mode 100644
index 6d5cad15016..00000000000
--- a/chromium/net/quic/crypto/crypto_secret_boxer_test.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2013 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/crypto/crypto_secret_boxer.h"
-
-#include <memory>
-
-#include "net/quic/crypto/quic_random.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-namespace test {
-
-TEST(CryptoSecretBoxerTest, BoxAndUnbox) {
- StringPiece message("hello world");
-
- CryptoSecretBoxer boxer;
- boxer.SetKeys({string(CryptoSecretBoxer::GetKeySize(), 0x11)});
-
- const string box = boxer.Box(QuicRandom::GetInstance(), message);
-
- string storage;
- StringPiece result;
- EXPECT_TRUE(boxer.Unbox(box, &storage, &result));
- EXPECT_EQ(result, message);
-
- EXPECT_FALSE(boxer.Unbox(string(1, 'X') + box, &storage, &result));
- EXPECT_FALSE(boxer.Unbox(box.substr(1, string::npos), &storage, &result));
- EXPECT_FALSE(boxer.Unbox(string(), &storage, &result));
- EXPECT_FALSE(
- boxer.Unbox(string(1, box[0] ^ 0x80) + box.substr(1, string::npos),
- &storage, &result));
-}
-
-// Helper function to test whether one boxer can decode the output of another.
-static bool CanDecode(const CryptoSecretBoxer& decoder,
- const CryptoSecretBoxer& encoder) {
- StringPiece message("hello world");
- const string boxed = encoder.Box(QuicRandom::GetInstance(), message);
- string storage;
- StringPiece result;
- bool ok = decoder.Unbox(boxed, &storage, &result);
- if (ok) {
- EXPECT_EQ(result, message);
- }
- return ok;
-}
-
-TEST(CryptoSecretBoxerTest, MultipleKeys) {
- string key_11(CryptoSecretBoxer::GetKeySize(), 0x11);
- string key_12(CryptoSecretBoxer::GetKeySize(), 0x12);
-
- CryptoSecretBoxer boxer_11, boxer_12, boxer;
- boxer_11.SetKeys({key_11});
- boxer_12.SetKeys({key_12});
- boxer.SetKeys({key_12, key_11});
-
- // Neither single-key boxer can decode the other's tokens.
- EXPECT_FALSE(CanDecode(boxer_11, boxer_12));
- EXPECT_FALSE(CanDecode(boxer_12, boxer_11));
-
- // |boxer| encodes with the first key, which is key_12.
- EXPECT_TRUE(CanDecode(boxer_12, boxer));
- EXPECT_FALSE(CanDecode(boxer_11, boxer));
-
- // The boxer with both keys can decode tokens from either single-key boxer.
- EXPECT_TRUE(CanDecode(boxer, boxer_11));
- EXPECT_TRUE(CanDecode(boxer, boxer_12));
-
- // After we flush key_11 from |boxer|, it can no longer decode tokens from
- // |boxer_11|.
- boxer.SetKeys({key_12});
- EXPECT_FALSE(CanDecode(boxer, boxer_11));
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/crypto_server_config_protobuf.cc b/chromium/net/quic/crypto/crypto_server_config_protobuf.cc
deleted file mode 100644
index 3acdf5eee36..00000000000
--- a/chromium/net/quic/crypto/crypto_server_config_protobuf.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2013 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/crypto/crypto_server_config_protobuf.h"
-
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-QuicServerConfigProtobuf::QuicServerConfigProtobuf()
- : primary_time_(QuicWallTime::Zero().ToUNIXSeconds()), priority_(0) {}
-
-QuicServerConfigProtobuf::~QuicServerConfigProtobuf() {
- STLDeleteElements(&keys_);
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/crypto_server_config_protobuf.h b/chromium/net/quic/crypto/crypto_server_config_protobuf.h
deleted file mode 100644
index 9e1f9d3be3f..00000000000
--- a/chromium/net/quic/crypto/crypto_server_config_protobuf.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2013 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_CRYPTO_CRYPTO_SERVER_CONFIG_PROTOBUF_H_
-#define NET_QUIC_CRYPTO_CRYPTO_SERVER_CONFIG_PROTOBUF_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/stl_util.h"
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-#include "net/quic/crypto/crypto_protocol.h"
-
-namespace net {
-
-// QuicServerConfigProtobuf contains QUIC server config block and the private
-// keys needed to prove ownership.
-// TODO(rch): sync with server more rationally.
-class NET_EXPORT_PRIVATE QuicServerConfigProtobuf {
- public:
- // PrivateKey contains a QUIC tag of a key exchange algorithm and a
- // serialised private key for that algorithm. The format of the serialised
- // private key is specific to the algorithm in question.
- class NET_EXPORT_PRIVATE PrivateKey {
- public:
- QuicTag tag() const { return tag_; }
- void set_tag(QuicTag tag) { tag_ = tag; }
- std::string private_key() const { return private_key_; }
- void set_private_key(const std::string& key) { private_key_ = key; }
-
- private:
- QuicTag tag_;
- std::string private_key_;
- };
-
- QuicServerConfigProtobuf();
- ~QuicServerConfigProtobuf();
-
- size_t key_size() const { return keys_.size(); }
-
- const PrivateKey& key(size_t i) const {
- DCHECK_GT(keys_.size(), i);
- return *keys_[i];
- }
-
- std::string config() const { return config_; }
-
- void set_config(base::StringPiece config) { config.CopyToString(&config_); }
-
- QuicServerConfigProtobuf::PrivateKey* add_key() {
- keys_.push_back(new PrivateKey);
- return keys_.back();
- }
-
- void clear_key() { STLDeleteElements(&keys_); }
-
- bool has_primary_time() const { return primary_time_ > 0; }
-
- int64_t primary_time() const { return primary_time_; }
-
- void set_primary_time(int64_t primary_time) { primary_time_ = primary_time; }
-
- bool has_priority() const { return priority_ > 0; }
-
- uint64_t priority() const { return priority_; }
-
- void set_priority(int64_t priority) { priority_ = priority; }
-
- bool has_source_address_token_secret_override() const {
- return !source_address_token_secret_override_.empty();
- }
-
- std::string source_address_token_secret_override() const {
- return source_address_token_secret_override_;
- }
-
- void set_source_address_token_secret_override(
- base::StringPiece source_address_token_secret_override) {
- source_address_token_secret_override.CopyToString(
- &source_address_token_secret_override_);
- }
-
- private:
- std::vector<PrivateKey*> keys_;
-
- // config_ is a serialised config in QUIC wire format.
- std::string config_;
-
- // primary_time_ contains a UNIX epoch seconds value that indicates when this
- // config should become primary.
- int64_t primary_time_;
-
- // Relative priority of this config vs other configs with the same
- // primary time. For use as a secondary sort key when selecting the
- // primary config.
- uint64_t priority_;
-
- // Optional override to the secret used to box/unbox source address
- // tokens when talking to clients that select this server config.
- // It can be of any length as it is fed into a KDF before use.
- std::string source_address_token_secret_override_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicServerConfigProtobuf);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_CRYPTO_SERVER_CONFIG_PROTOBUF_H_
diff --git a/chromium/net/quic/crypto/crypto_server_test.cc b/chromium/net/quic/crypto/crypto_server_test.cc
deleted file mode 100644
index 2e73826284a..00000000000
--- a/chromium/net/quic/crypto/crypto_server_test.cc
+++ /dev/null
@@ -1,1165 +0,0 @@
-// Copyright (c) 2013 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 <algorithm>
-#include <cstdint>
-#include <memory>
-#include <ostream>
-#include <vector>
-
-#include "base/strings/string_number_conversions.h"
-#include "crypto/secure_hash.h"
-#include "net/quic/crypto/cert_compressor.h"
-#include "net/quic/crypto/common_cert_set.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/crypto_server_config_protobuf.h"
-#include "net/quic/crypto/crypto_utils.h"
-#include "net/quic/crypto/proof_source.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_socket_address_coder.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/delayed_verify_strike_register_client.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/test_tools/mock_random.h"
-#include "net/quic/test_tools/quic_crypto_server_config_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::StringPiece;
-using std::endl;
-using std::ostream;
-using std::string;
-using std::vector;
-
-namespace net {
-namespace test {
-
-namespace {
-
-class DummyProofVerifierCallback : public ProofVerifierCallback {
- public:
- DummyProofVerifierCallback() {}
- ~DummyProofVerifierCallback() override {}
-
- void Run(bool ok,
- const std::string& error_details,
- std::unique_ptr<ProofVerifyDetails>* details) override {
- // Do nothing
- }
-};
-
-const char kOldConfigId[] = "old-config-id";
-
-} // namespace
-
-struct TestParams {
- TestParams(bool enable_stateless_rejects,
- bool use_stateless_rejects,
- QuicVersionVector supported_versions)
- : enable_stateless_rejects(enable_stateless_rejects),
- use_stateless_rejects(use_stateless_rejects),
- supported_versions(supported_versions) {}
-
- friend ostream& operator<<(ostream& os, const TestParams& p) {
- os << " enable_stateless_rejects: " << p.enable_stateless_rejects
- << std::endl;
- os << " use_stateless_rejects: " << p.use_stateless_rejects << std::endl;
- os << " versions: " << QuicVersionVectorToString(p.supported_versions)
- << " }";
- return os;
- }
-
- // This only enables the stateless reject feature via the feature-flag.
- // It does not force the crypto server to emit stateless rejects.
- bool enable_stateless_rejects;
- // If true, this forces the server to send a stateless reject when
- // rejecting messages. This should be a no-op if
- // enable_stateless_rejects is false.
- bool use_stateless_rejects;
- // Versions supported by client and server.
- QuicVersionVector supported_versions;
-};
-
-// Constructs various test permutations.
-vector<TestParams> GetTestParams() {
- vector<TestParams> params;
- static const bool kTrueFalse[] = {true, false};
- for (bool enable_stateless_rejects : kTrueFalse) {
- for (bool use_stateless_rejects : kTrueFalse) {
- // Start with all versions, remove highest on each iteration.
- QuicVersionVector supported_versions = QuicSupportedVersions();
- while (!supported_versions.empty()) {
- params.push_back(TestParams(enable_stateless_rejects,
- use_stateless_rejects, supported_versions));
- supported_versions.erase(supported_versions.begin());
- }
- }
- }
- return params;
-}
-
-class CryptoServerTest : public ::testing::TestWithParam<TestParams> {
- public:
- CryptoServerTest()
- : rand_(QuicRandom::GetInstance()),
- client_address_(Loopback4(), 1234),
- config_(QuicCryptoServerConfig::TESTING,
- rand_,
- CryptoTestUtils::ProofSourceForTesting()),
- compressed_certs_cache_(
- QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) {
- supported_versions_ = GetParam().supported_versions;
- config_.set_enable_serving_sct(true);
-
- client_version_ = supported_versions_.front();
- client_version_string_ =
- QuicUtils::TagToString(QuicVersionToQuicTag(client_version_));
-
- FLAGS_enable_quic_stateless_reject_support =
- GetParam().enable_stateless_rejects;
- use_stateless_rejects_ = GetParam().use_stateless_rejects;
- }
-
- void SetUp() override {
- QuicCryptoServerConfig::ConfigOptions old_config_options;
- old_config_options.id = kOldConfigId;
- delete config_.AddDefaultConfig(rand_, &clock_, old_config_options);
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000));
- std::unique_ptr<QuicServerConfigProtobuf> primary_config(
- config_.GenerateConfig(rand_, &clock_, config_options_));
- primary_config->set_primary_time(clock_.WallNow().ToUNIXSeconds());
- std::unique_ptr<CryptoHandshakeMessage> msg(
- config_.AddConfig(primary_config.get(), clock_.WallNow()));
-
- StringPiece orbit;
- CHECK(msg->GetStringPiece(kORBT, &orbit));
- CHECK_EQ(sizeof(orbit_), orbit.size());
- memcpy(orbit_, orbit.data(), orbit.size());
-
- char public_value[32];
- memset(public_value, 42, sizeof(public_value));
-
- nonce_hex_ = "#" + QuicUtils::HexEncode(GenerateNonce());
- pub_hex_ = "#" + QuicUtils::HexEncode(public_value, sizeof(public_value));
-
- // clang-format off
- CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "PUBS", pub_hex_.c_str(),
- "NONC", nonce_hex_.c_str(),
- "CSCT", "",
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
- ShouldSucceed(client_hello);
- // The message should be rejected because the source-address token is
- // missing.
- CheckRejectTag();
- const HandshakeFailureReason kRejectReasons[] = {
- SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
- CheckForServerDesignatedConnectionId();
-
- StringPiece srct;
- ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct));
- srct_hex_ = "#" + QuicUtils::HexEncode(srct);
-
- StringPiece scfg;
- ASSERT_TRUE(out_.GetStringPiece(kSCFG, &scfg));
- server_config_.reset(CryptoFramer::ParseMessage(scfg));
-
- StringPiece scid;
- ASSERT_TRUE(server_config_->GetStringPiece(kSCID, &scid));
- scid_hex_ = "#" + QuicUtils::HexEncode(scid);
-
- crypto_proof_ = QuicCryptoProof();
- DCHECK(crypto_proof_.chain.get() == nullptr);
- }
-
- // Helper used to accept the result of ValidateClientHello and pass
- // it on to ProcessClientHello.
- class ValidateCallback : public ValidateClientHelloResultCallback {
- public:
- ValidateCallback(CryptoServerTest* test,
- bool should_succeed,
- const char* error_substr,
- bool* called)
- : test_(test),
- should_succeed_(should_succeed),
- error_substr_(error_substr),
- called_(called) {
- *called_ = false;
- }
-
- void RunImpl(const CryptoHandshakeMessage& client_hello,
- const Result& result) override {
- {
- // Ensure that the strike register client lock is not held.
- QuicCryptoServerConfigPeer peer(&test_->config_);
- base::Lock* m = peer.GetStrikeRegisterClientLock();
- // In Chromium, we will dead lock if the lock is held by the current
- // thread. Chromium doesn't have AssertNotHeld API call.
- // m->AssertNotHeld();
- base::AutoLock lock(*m);
- }
- ASSERT_FALSE(*called_);
- test_->ProcessValidationResult(client_hello, result, should_succeed_,
- error_substr_);
- *called_ = true;
- }
-
- private:
- CryptoServerTest* test_;
- bool should_succeed_;
- const char* error_substr_;
- bool* called_;
- };
-
- void CheckServerHello(const CryptoHandshakeMessage& server_hello) {
- const QuicTag* versions;
- size_t num_versions;
- server_hello.GetTaglist(kVER, &versions, &num_versions);
- ASSERT_EQ(supported_versions_.size(), num_versions);
- for (size_t i = 0; i < num_versions; ++i) {
- EXPECT_EQ(QuicVersionToQuicTag(supported_versions_[i]), versions[i]);
- }
-
- StringPiece address;
- ASSERT_TRUE(server_hello.GetStringPiece(kCADR, &address));
- QuicSocketAddressCoder decoder;
- ASSERT_TRUE(decoder.Decode(address.data(), address.size()));
- EXPECT_EQ(client_address_.address(), decoder.ip());
- EXPECT_EQ(client_address_.port(), decoder.port());
- }
-
- void ShouldSucceed(const CryptoHandshakeMessage& message) {
- bool called = false;
- IPAddress server_ip;
- config_.ValidateClientHello(message, client_address_.address(), server_ip,
- supported_versions_.front(), &clock_,
- &crypto_proof_,
- new ValidateCallback(this, true, "", &called));
- EXPECT_TRUE(called);
- }
-
- void ShouldFailMentioning(const char* error_substr,
- const CryptoHandshakeMessage& message) {
- bool called = false;
- ShouldFailMentioning(error_substr, message, &called);
- EXPECT_TRUE(called);
- }
-
- void ShouldFailMentioning(const char* error_substr,
- const CryptoHandshakeMessage& message,
- bool* called) {
- IPAddress server_ip;
- config_.ValidateClientHello(
- message, client_address_.address(), server_ip,
- supported_versions_.front(), &clock_, &crypto_proof_,
- new ValidateCallback(this, false, error_substr, called));
- }
-
- void ProcessValidationResult(const CryptoHandshakeMessage& message,
- const ValidateCallback::Result& result,
- bool should_succeed,
- const char* error_substr) {
- IPAddress server_ip;
- DiversificationNonce diversification_nonce;
- string error_details;
- QuicConnectionId server_designated_connection_id =
- rand_for_id_generation_.RandUint64();
- QuicErrorCode error = config_.ProcessClientHello(
- result, /*reject_only=*/false, /*connection_id=*/1, server_ip,
- client_address_, supported_versions_.front(), supported_versions_,
- use_stateless_rejects_, server_designated_connection_id, &clock_, rand_,
- &compressed_certs_cache_, &params_, &crypto_proof_, &out_,
- &diversification_nonce, &error_details);
-
- if (should_succeed) {
- ASSERT_EQ(error, QUIC_NO_ERROR) << "Message failed with error "
- << error_details << ": "
- << message.DebugString();
- } else {
- ASSERT_NE(error, QUIC_NO_ERROR) << "Message didn't fail: "
- << message.DebugString();
-
- EXPECT_TRUE(error_details.find(error_substr) != string::npos)
- << error_substr << " not in " << error_details;
- }
- }
-
- string GenerateNonce() {
- string nonce;
- CryptoUtils::GenerateNonce(
- clock_.WallNow(), rand_,
- StringPiece(reinterpret_cast<const char*>(orbit_), sizeof(orbit_)),
- &nonce);
- return nonce;
- }
-
- void CheckRejectReasons(
- const HandshakeFailureReason* expected_handshake_failures,
- size_t expected_count) {
- const uint32_t* reject_reasons;
- size_t num_reject_reasons;
- static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync");
- QuicErrorCode error_code =
- out_.GetTaglist(kRREJ, &reject_reasons, &num_reject_reasons);
- ASSERT_EQ(QUIC_NO_ERROR, error_code);
-
- EXPECT_EQ(expected_count, num_reject_reasons);
- for (size_t i = 0; i < num_reject_reasons; ++i) {
- EXPECT_EQ(expected_handshake_failures[i], reject_reasons[i]);
- }
- }
-
- // If the server is rejecting statelessly, make sure it contains a
- // server-designated connection id. Once the check is complete,
- // allow the random id-generator to move to the next value.
- void CheckForServerDesignatedConnectionId() {
- QuicConnectionId server_designated_connection_id;
- if (!RejectsAreStateless()) {
- EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
- out_.GetUint64(kRCID, &server_designated_connection_id));
- } else {
- ASSERT_EQ(QUIC_NO_ERROR,
- out_.GetUint64(kRCID, &server_designated_connection_id));
- EXPECT_EQ(rand_for_id_generation_.RandUint64(),
- server_designated_connection_id);
- }
- rand_for_id_generation_.ChangeValue();
- }
-
- void CheckRejectTag() {
- if (RejectsAreStateless()) {
- ASSERT_EQ(kSREJ, out_.tag()) << QuicUtils::TagToString(out_.tag());
- } else {
- ASSERT_EQ(kREJ, out_.tag()) << QuicUtils::TagToString(out_.tag());
- }
- }
-
- bool RejectsAreStateless() {
- return GetParam().enable_stateless_rejects &&
- GetParam().use_stateless_rejects;
- }
-
- string XlctHexString() {
- uint64_t xlct = CryptoTestUtils::LeafCertHashForTesting();
- return "#" +
- QuicUtils::HexEncode(reinterpret_cast<char*>(&xlct), sizeof(xlct));
- }
-
- protected:
- QuicRandom* const rand_;
- MockRandom rand_for_id_generation_;
- MockClock clock_;
- IPEndPoint client_address_;
- QuicVersionVector supported_versions_;
- QuicVersion client_version_;
- string client_version_string_;
- QuicCryptoServerConfig config_;
- QuicCompressedCertsCache compressed_certs_cache_;
- QuicCryptoServerConfig::ConfigOptions config_options_;
- QuicCryptoNegotiatedParameters params_;
- QuicCryptoProof crypto_proof_;
- CryptoHandshakeMessage out_;
- uint8_t orbit_[kOrbitSize];
- bool use_stateless_rejects_;
-
- // These strings contain hex escaped values from the server suitable for using
- // when constructing client hello messages.
- string nonce_hex_, pub_hex_, srct_hex_, scid_hex_;
- std::unique_ptr<CryptoHandshakeMessage> server_config_;
-};
-
-INSTANTIATE_TEST_CASE_P(CryptoServerTests,
- CryptoServerTest,
- ::testing::ValuesIn(GetTestParams()));
-
-TEST_P(CryptoServerTest, BadSNI) {
- // clang-format off
- static const char* const kBadSNIs[] = {
- "",
- "foo",
- "#00",
- "#ff00",
- "127.0.0.1",
- "ffee::1",
- };
- // clang-format on
-
- for (size_t i = 0; i < arraysize(kBadSNIs); i++) {
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "SNI", kBadSNIs[i],
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
- ShouldFailMentioning("SNI", msg);
- const HandshakeFailureReason kRejectReasons[] = {
- SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
- }
-}
-
-TEST_P(CryptoServerTest, DefaultCert) {
- // Check that the server replies with a default certificate when no SNI is
- // specified. The CHLO is constructed to generate a REJ with certs, so must
- // not contain a valid STK, and must include PDMD.
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "PUBS", pub_hex_.c_str(),
- "NONC", nonce_hex_.c_str(),
- "PDMD", "X509",
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
-
- ShouldSucceed(msg);
- StringPiece cert, proof, cert_sct;
- EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert));
- EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof));
- EXPECT_EQ(client_version_ > QUIC_VERSION_29,
- out_.GetStringPiece(kCertificateSCTTag, &cert_sct));
- EXPECT_NE(0u, cert.size());
- EXPECT_NE(0u, proof.size());
- const HandshakeFailureReason kRejectReasons[] = {
- SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
- EXPECT_EQ(client_version_ > QUIC_VERSION_29, cert_sct.size() > 0);
-}
-
-TEST_P(CryptoServerTest, RejectTooLarge) {
- // Check that the server replies with no certificate when a CHLO is
- // constructed with a PDMD but no SKT when the REJ would be too large.
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "PUBS", pub_hex_.c_str(),
- "NONC", nonce_hex_.c_str(),
- "PDMD", "X509",
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
-
- // The REJ will be larger than the CHLO so no PROF or CRT will be sent.
- config_.set_chlo_multiplier(1);
-
- ShouldSucceed(msg);
- StringPiece cert, proof, cert_sct;
- EXPECT_FALSE(out_.GetStringPiece(kCertificateTag, &cert));
- EXPECT_FALSE(out_.GetStringPiece(kPROF, &proof));
- EXPECT_FALSE(out_.GetStringPiece(kCertificateSCTTag, &cert_sct));
- const HandshakeFailureReason kRejectReasons[] = {
- SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
-}
-
-TEST_P(CryptoServerTest, RejectTooLargeButValidSTK) {
- // Check that the server replies with no certificate when a CHLO is
- // constructed with a PDMD but no SKT when the REJ would be too large.
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "PUBS", pub_hex_.c_str(),
- "NONC", nonce_hex_.c_str(),
- "#004b5453", srct_hex_.c_str(),
- "PDMD", "X509",
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
-
- // The REJ will be larger than the CHLO so no PROF or CRT will be sent.
- config_.set_chlo_multiplier(1);
-
- ShouldSucceed(msg);
- StringPiece cert, proof, cert_sct;
- EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert));
- EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof));
- EXPECT_EQ(client_version_ > QUIC_VERSION_29,
- out_.GetStringPiece(kCertificateSCTTag, &cert_sct));
- EXPECT_NE(0u, cert.size());
- EXPECT_NE(0u, proof.size());
- const HandshakeFailureReason kRejectReasons[] = {
- SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
-}
-
-TEST_P(CryptoServerTest, TooSmall) {
- // clang-format off
- ShouldFailMentioning("too small", CryptoTestUtils::Message(
- "CHLO",
- "VER\0", client_version_string_.c_str(),
- nullptr));
- // clang-format on
- const HandshakeFailureReason kRejectReasons[] = {
- SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
-}
-
-TEST_P(CryptoServerTest, BadSourceAddressToken) {
- // Invalid source-address tokens should be ignored.
- // clang-format off
- static const char* const kBadSourceAddressTokens[] = {
- "",
- "foo",
- "#0000",
- "#0000000000000000000000000000000000000000",
- };
- // clang-format on
-
- for (size_t i = 0; i < arraysize(kBadSourceAddressTokens); i++) {
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "STK", kBadSourceAddressTokens[i],
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize), nullptr);
- // clang-format on
- ShouldSucceed(msg);
- const HandshakeFailureReason kRejectReasons[] = {
- SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
- }
-}
-
-TEST_P(CryptoServerTest, BadClientNonce) {
- // clang-format off
- static const char* const kBadNonces[] = {
- "",
- "#0000",
- "#0000000000000000000000000000000000000000",
- };
- // clang-format on
-
- for (size_t i = 0; i < arraysize(kBadNonces); i++) {
- // Invalid nonces should be ignored, in an inchoate CHLO.
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "NONC", kBadNonces[i],
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
- ShouldSucceed(msg);
- const HandshakeFailureReason kRejectReasons[] = {
- SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
-
- // Invalid nonces should result in CLIENT_NONCE_INVALID_FAILURE.
- // clang-format off
- CryptoHandshakeMessage msg1 = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "SCID", scid_hex_.c_str(),
- "#004b5453", srct_hex_.c_str(),
- "PUBS", pub_hex_.c_str(),
- "NONC", kBadNonces[i],
- "NONP", kBadNonces[i],
- "XLCT", XlctHexString().c_str(),
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
-
- ShouldSucceed(msg1);
-
- CheckRejectTag();
- const HandshakeFailureReason kRejectReasons1[] = {
- CLIENT_NONCE_INVALID_FAILURE};
- CheckRejectReasons(kRejectReasons1, arraysize(kRejectReasons1));
- }
-}
-
-TEST_P(CryptoServerTest, NoClientNonce) {
- // No client nonces should result in INCHOATE_HELLO_FAILURE.
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
-
- ShouldSucceed(msg);
- const HandshakeFailureReason kRejectReasons[] = {
- SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
-
- // clang-format off
- CryptoHandshakeMessage msg1 = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "SCID", scid_hex_.c_str(),
- "#004b5453", srct_hex_.c_str(),
- "PUBS", pub_hex_.c_str(),
- "XLCT", XlctHexString().c_str(),
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
-
- ShouldSucceed(msg1);
- CheckRejectTag();
- const HandshakeFailureReason kRejectReasons1[] = {
- SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
- CheckRejectReasons(kRejectReasons1, arraysize(kRejectReasons1));
-}
-
-TEST_P(CryptoServerTest, DowngradeAttack) {
- if (supported_versions_.size() == 1) {
- // No downgrade attack is possible if the server only supports one version.
- return;
- }
- // Set the client's preferred version to a supported version that
- // is not the "current" version (supported_versions_.front()).
- string bad_version =
- QuicUtils::TagToString(QuicVersionToQuicTag(supported_versions_.back()));
-
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "VER\0", bad_version.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
- ShouldFailMentioning("Downgrade", msg);
- const HandshakeFailureReason kRejectReasons[] = {
- SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
-}
-
-TEST_P(CryptoServerTest, CorruptServerConfig) {
- // This tests corrupted server config.
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "SCID", (string(1, 'X') + scid_hex_).c_str(),
- "#004b5453", srct_hex_.c_str(),
- "PUBS", pub_hex_.c_str(),
- "NONC", nonce_hex_.c_str(),
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
- ShouldSucceed(msg);
- CheckRejectTag();
- const HandshakeFailureReason kRejectReasons[] = {
- SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
-}
-
-TEST_P(CryptoServerTest, CorruptSourceAddressToken) {
- // This tests corrupted source address token.
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "SCID", scid_hex_.c_str(),
- "#004b5453", (string(1, 'X') + srct_hex_).c_str(),
- "PUBS", pub_hex_.c_str(),
- "NONC", nonce_hex_.c_str(),
- "XLCT", XlctHexString().c_str(),
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
- ShouldSucceed(msg);
- CheckRejectTag();
- const HandshakeFailureReason kRejectReasons[] = {
- SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
-}
-
-TEST_P(CryptoServerTest, CorruptClientNonceAndSourceAddressToken) {
- // This test corrupts client nonce and source address token.
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "SCID", scid_hex_.c_str(),
- "#004b5453", (string(1, 'X') + srct_hex_).c_str(),
- "PUBS", pub_hex_.c_str(),
- "NONC", (string(1, 'X') + nonce_hex_).c_str(),
- "XLCT", XlctHexString().c_str(),
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
- ShouldSucceed(msg);
- CheckRejectTag();
- const HandshakeFailureReason kRejectReasons[] = {
- SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
-}
-
-TEST_P(CryptoServerTest, CorruptMultipleTags) {
- // This test corrupts client nonce, server nonce and source address token.
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "SCID", scid_hex_.c_str(),
- "#004b5453", (string(1, 'X') + srct_hex_).c_str(),
- "PUBS", pub_hex_.c_str(),
- "NONC", (string(1, 'X') + nonce_hex_).c_str(),
- "NONP", (string(1, 'X') + nonce_hex_).c_str(),
- "SNO\0", (string(1, 'X') + nonce_hex_).c_str(),
- "XLCT", XlctHexString().c_str(),
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
- ShouldSucceed(msg);
- CheckRejectTag();
-
- if (client_version_ <= QUIC_VERSION_32) {
- const HandshakeFailureReason kRejectReasons[] = {
- SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE,
- SERVER_NONCE_DECRYPTION_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
- } else {
- const HandshakeFailureReason kRejectReasons[] = {
- SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
- };
-}
-
-TEST_P(CryptoServerTest, NoServerNonce) {
- // When no server nonce is present and no strike register is configured,
- // the CHLO should be rejected.
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "SCID", scid_hex_.c_str(),
- "#004b5453", srct_hex_.c_str(),
- "PUBS", pub_hex_.c_str(),
- "NONC", nonce_hex_.c_str(),
- "NONP", nonce_hex_.c_str(),
- "XLCT", XlctHexString().c_str(),
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
-
- ShouldSucceed(msg);
-
- if (client_version_ <= QUIC_VERSION_32) {
- CheckRejectTag();
- const HandshakeFailureReason kRejectReasons[] = {
- SERVER_NONCE_REQUIRED_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
- } else {
- // Even without a server nonce, this ClientHello should be accepted in
- // version 33.
- ASSERT_EQ(kSHLO, out_.tag());
- CheckServerHello(out_);
- }
-}
-
-TEST_P(CryptoServerTest, ProofForSuppliedServerConfig) {
- client_address_ = IPEndPoint(Loopback6(), 1234);
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "PDMD", "X509",
- "SCID", kOldConfigId,
- "#004b5453", srct_hex_.c_str(),
- "PUBS", pub_hex_.c_str(),
- "NONC", nonce_hex_.c_str(),
- "VER\0", client_version_string_.c_str(),
- "XLCT", XlctHexString().c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
- ShouldSucceed(msg);
- // The message should be rejected because the source-address token is no
- // longer valid.
- CheckRejectTag();
- const HandshakeFailureReason kRejectReasons[] = {
- SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
-
- StringPiece cert, proof, scfg_str;
- EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert));
- EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof));
- EXPECT_TRUE(out_.GetStringPiece(kSCFG, &scfg_str));
- std::unique_ptr<CryptoHandshakeMessage> scfg(
- CryptoFramer::ParseMessage(scfg_str));
- StringPiece scid;
- EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid));
- EXPECT_NE(scid, kOldConfigId);
-
- // Get certs from compressed certs.
- const CommonCertSets* common_cert_sets(CommonCertSets::GetInstanceQUIC());
- vector<string> cached_certs;
-
- vector<string> certs;
- ASSERT_TRUE(CertCompressor::DecompressChain(cert, cached_certs,
- common_cert_sets, &certs));
-
- // Check that the proof in the REJ message is valid.
- std::unique_ptr<ProofVerifier> proof_verifier(
- CryptoTestUtils::ProofVerifierForTesting());
- std::unique_ptr<ProofVerifyContext> verify_context(
- CryptoTestUtils::ProofVerifyContextForTesting());
- std::unique_ptr<ProofVerifyDetails> details;
- string error_details;
- DummyProofVerifierCallback callback;
- string chlo_hash;
- CryptoUtils::HashHandshakeMessage(msg, &chlo_hash);
- EXPECT_EQ(QUIC_SUCCESS,
- proof_verifier->VerifyProof(
- "test.example.com", 443, scfg_str.as_string(), client_version_,
- chlo_hash, certs, "", proof.as_string(), verify_context.get(),
- &error_details, &details, &callback));
-}
-
-TEST_P(CryptoServerTest, RejectInvalidXlct) {
- if (client_version_ <= QUIC_VERSION_25) {
- // XLCT tag introduced in QUIC_VERSION_26.
- return;
- }
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "SCID", scid_hex_.c_str(),
- "#004b5453", srct_hex_.c_str(),
- "PUBS", pub_hex_.c_str(),
- "NONC", nonce_hex_.c_str(),
- "VER\0", client_version_string_.c_str(),
- "XLCT", "#0102030405060708",
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
- // If replay protection isn't disabled, then
- // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false
- // and cause ProcessClientHello to exit early (and generate a REJ message).
- config_.set_replay_protection(false);
-
- ShouldSucceed(msg);
- // clang-format off
- const HandshakeFailureReason kRejectReasons[] = {
- INVALID_EXPECTED_LEAF_CERTIFICATE
- };
- // clang-format on
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
-}
-
-TEST_P(CryptoServerTest, ValidXlct) {
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "SCID", scid_hex_.c_str(),
- "#004b5453", srct_hex_.c_str(),
- "PUBS", pub_hex_.c_str(),
- "NONC", nonce_hex_.c_str(),
- "NONP", "123456789012345678901234567890",
- "VER\0", client_version_string_.c_str(),
- "XLCT", XlctHexString().c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
- // If replay protection isn't disabled, then
- // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false
- // and cause ProcessClientHello to exit early (and generate a REJ message).
- config_.set_replay_protection(false);
-
- ShouldSucceed(msg);
- EXPECT_EQ(kSHLO, out_.tag());
-}
-
-TEST_P(CryptoServerTest, NonceInSHLO) {
- // After QUIC_VERSION_27, the SHLO should contain a nonce.
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "SCID", scid_hex_.c_str(),
- "#004b5453", srct_hex_.c_str(),
- "PUBS", pub_hex_.c_str(),
- "NONC", nonce_hex_.c_str(),
- "VER\0", client_version_string_.c_str(),
- "XLCT", XlctHexString().c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
- // If replay protection isn't disabled, then
- // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false
- // and cause ProcessClientHello to exit early (and generate a REJ message).
- config_.set_replay_protection(false);
-
- ShouldSucceed(msg);
- EXPECT_EQ(kSHLO, out_.tag());
-
- StringPiece nonce;
- if (client_version_ <= QUIC_VERSION_26) {
- EXPECT_FALSE(out_.GetStringPiece(kServerNonceTag, &nonce));
- } else {
- EXPECT_TRUE(out_.GetStringPiece(kServerNonceTag, &nonce));
- }
-}
-
-TEST(CryptoServerConfigGenerationTest, Determinism) {
- // Test that using a deterministic PRNG causes the server-config to be
- // deterministic.
-
- MockRandom rand_a, rand_b;
- const QuicCryptoServerConfig::ConfigOptions options;
- MockClock clock;
-
- QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a,
- CryptoTestUtils::ProofSourceForTesting());
- QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b,
- CryptoTestUtils::ProofSourceForTesting());
- std::unique_ptr<CryptoHandshakeMessage> scfg_a(
- a.AddDefaultConfig(&rand_a, &clock, options));
- std::unique_ptr<CryptoHandshakeMessage> scfg_b(
- b.AddDefaultConfig(&rand_b, &clock, options));
-
- ASSERT_EQ(scfg_a->DebugString(), scfg_b->DebugString());
-}
-
-TEST(CryptoServerConfigGenerationTest, SCIDVaries) {
- // This test ensures that the server config ID varies for different server
- // configs.
-
- MockRandom rand_a, rand_b;
- const QuicCryptoServerConfig::ConfigOptions options;
- MockClock clock;
-
- QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a,
- CryptoTestUtils::ProofSourceForTesting());
- rand_b.ChangeValue();
- QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b,
- CryptoTestUtils::ProofSourceForTesting());
- std::unique_ptr<CryptoHandshakeMessage> scfg_a(
- a.AddDefaultConfig(&rand_a, &clock, options));
- std::unique_ptr<CryptoHandshakeMessage> scfg_b(
- b.AddDefaultConfig(&rand_b, &clock, options));
-
- StringPiece scid_a, scid_b;
- EXPECT_TRUE(scfg_a->GetStringPiece(kSCID, &scid_a));
- EXPECT_TRUE(scfg_b->GetStringPiece(kSCID, &scid_b));
-
- EXPECT_NE(scid_a, scid_b);
-}
-
-TEST(CryptoServerConfigGenerationTest, SCIDIsHashOfServerConfig) {
- MockRandom rand_a;
- const QuicCryptoServerConfig::ConfigOptions options;
- MockClock clock;
-
- QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a,
- CryptoTestUtils::ProofSourceForTesting());
- std::unique_ptr<CryptoHandshakeMessage> scfg(
- a.AddDefaultConfig(&rand_a, &clock, options));
-
- StringPiece scid;
- EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid));
- // Need to take a copy of |scid| has we're about to call |Erase|.
- const string scid_str(scid.as_string());
-
- scfg->Erase(kSCID);
- scfg->MarkDirty();
- const QuicData& serialized(scfg->GetSerialized());
-
- std::unique_ptr<crypto::SecureHash> hash(
- crypto::SecureHash::Create(crypto::SecureHash::SHA256));
- hash->Update(serialized.data(), serialized.length());
- uint8_t digest[16];
- hash->Finish(digest, sizeof(digest));
-
- ASSERT_EQ(scid.size(), sizeof(digest));
- EXPECT_EQ(0, memcmp(digest, scid_str.c_str(), sizeof(digest)));
-}
-
-class CryptoServerTestNoConfig : public CryptoServerTest {
- public:
- void SetUp() override {
- // Deliberately don't add a config so that we can test this situation.
- }
-};
-
-TEST_P(CryptoServerTestNoConfig, DontCrash) {
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
- ShouldFailMentioning("No config", msg);
-
- const HandshakeFailureReason kRejectReasons[] = {
- SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
- CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons));
-}
-
-class CryptoServerTestOldVersion : public CryptoServerTest {
- public:
- void SetUp() override {
- client_version_ = supported_versions_.back();
- client_version_string_ =
- QuicUtils::TagToString(QuicVersionToQuicTag(client_version_));
- CryptoServerTest::SetUp();
- }
-};
-
-TEST_P(CryptoServerTestOldVersion, ServerIgnoresXlct) {
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "SCID", scid_hex_.c_str(),
- "#004b5453", srct_hex_.c_str(),
- "PUBS", pub_hex_.c_str(),
- "NONC", nonce_hex_.c_str(),
- "VER\0", client_version_string_.c_str(),
- "XLCT", "#0100000000000000",
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
- // If replay protection isn't disabled, then
- // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false
- // and cause ProcessClientHello to exit early (and generate a REJ message).
- config_.set_replay_protection(false);
-
- ShouldSucceed(msg);
- EXPECT_EQ(kSHLO, out_.tag());
-}
-
-TEST_P(CryptoServerTestOldVersion, XlctNotRequired) {
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "SCID", scid_hex_.c_str(),
- "#004b5453", srct_hex_.c_str(),
- "PUBS", pub_hex_.c_str(),
- "NONC", nonce_hex_.c_str(),
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
- // If replay protection isn't disabled, then
- // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false
- // and cause ProcessClientHello to exit early (and generate a REJ message).
- config_.set_replay_protection(false);
-
- ShouldSucceed(msg);
- EXPECT_EQ(kSHLO, out_.tag());
-}
-
-class AsyncStrikeServerVerificationTest : public CryptoServerTest {
- protected:
- AsyncStrikeServerVerificationTest() {}
-
- void SetUp() override {
- const string kOrbit = "12345678";
- config_options_.orbit = kOrbit;
- strike_register_client_ = new DelayedVerifyStrikeRegisterClient(
- 10000, // strike_register_max_entries
- static_cast<uint32_t>(clock_.WallNow().ToUNIXSeconds()),
- 60, // strike_register_window_secs
- reinterpret_cast<const uint8_t*>(kOrbit.c_str()),
- StrikeRegister::NO_STARTUP_PERIOD_NEEDED);
- config_.SetStrikeRegisterClient(strike_register_client_);
- ASSERT_NO_FATAL_FAILURE(CryptoServerTest::SetUp());
- strike_register_client_->StartDelayingVerification();
- }
-
- DelayedVerifyStrikeRegisterClient* strike_register_client_;
-};
-
-TEST_P(AsyncStrikeServerVerificationTest, AsyncReplayProtection) {
- // This tests async validation with a strike register works.
- // clang-format off
- CryptoHandshakeMessage msg = CryptoTestUtils::Message(
- "CHLO",
- "AEAD", "AESG",
- "KEXS", "C255",
- "SCID", scid_hex_.c_str(),
- "#004b5453", srct_hex_.c_str(),
- "PUBS", pub_hex_.c_str(),
- "NONC", nonce_hex_.c_str(),
- "VER\0", client_version_string_.c_str(),
- "$padding", static_cast<int>(kClientHelloMinimumSize),
- nullptr);
- // clang-format on
-
- // Clear the message tag.
- out_.set_tag(0);
-
- bool called = false;
- IPAddress server_ip;
- config_.ValidateClientHello(msg, client_address_.address(), server_ip,
- client_version_, &clock_, &crypto_proof_,
- new ValidateCallback(this, true, "", &called));
- // The verification request was queued.
- ASSERT_FALSE(called);
- EXPECT_EQ(0u, out_.tag());
- EXPECT_EQ(1, strike_register_client_->PendingVerifications());
-
- // Continue processing the verification request.
- strike_register_client_->RunPendingVerifications();
- ASSERT_TRUE(called);
- EXPECT_EQ(0, strike_register_client_->PendingVerifications());
- // The message should be accepted now.
- EXPECT_EQ(kSHLO, out_.tag());
-
- // Rejected if replayed.
- config_.ValidateClientHello(msg, client_address_.address(), server_ip,
- client_version_, &clock_, &crypto_proof_,
- new ValidateCallback(this, true, "", &called));
- // The verification request was queued.
- ASSERT_FALSE(called);
- EXPECT_EQ(1, strike_register_client_->PendingVerifications());
-
- strike_register_client_->RunPendingVerifications();
- ASSERT_TRUE(called);
- EXPECT_EQ(0, strike_register_client_->PendingVerifications());
- // The message should be rejected now.
- CheckRejectTag();
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/crypto_utils.cc b/chromium/net/quic/crypto/crypto_utils.cc
deleted file mode 100644
index 6ec4e5e8aae..00000000000
--- a/chromium/net/quic/crypto/crypto_utils.cc
+++ /dev/null
@@ -1,340 +0,0 @@
-// Copyright (c) 2013 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/crypto/crypto_utils.h"
-
-#include <memory>
-
-#include "crypto/hkdf.h"
-#include "crypto/secure_hash.h"
-#include "net/base/url_util.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_time.h"
-#include "net/quic/quic_utils.h"
-#include "url/url_canon.h"
-
-using base::StringPiece;
-using std::numeric_limits;
-using std::string;
-
-namespace net {
-
-// static
-void CryptoUtils::GenerateNonce(QuicWallTime now,
- QuicRandom* random_generator,
- StringPiece orbit,
- string* nonce) {
- // a 4-byte timestamp + 28 random bytes.
- nonce->reserve(kNonceSize);
- nonce->resize(kNonceSize);
-
- uint32_t gmt_unix_time = static_cast<uint32_t>(now.ToUNIXSeconds());
- // The time in the nonce must be encoded in big-endian because the
- // strike-register depends on the nonces being ordered by time.
- (*nonce)[0] = static_cast<char>(gmt_unix_time >> 24);
- (*nonce)[1] = static_cast<char>(gmt_unix_time >> 16);
- (*nonce)[2] = static_cast<char>(gmt_unix_time >> 8);
- (*nonce)[3] = static_cast<char>(gmt_unix_time);
- size_t bytes_written = 4;
-
- if (orbit.size() == 8) {
- memcpy(&(*nonce)[bytes_written], orbit.data(), orbit.size());
- bytes_written += orbit.size();
- }
-
- random_generator->RandBytes(&(*nonce)[bytes_written],
- kNonceSize - bytes_written);
-}
-
-// static
-bool CryptoUtils::IsValidSNI(StringPiece sni) {
- // TODO(rtenneti): Support RFC2396 hostname.
- // NOTE: Microsoft does NOT enforce this spec, so if we throw away hostnames
- // based on the above spec, we may be losing some hostnames that windows
- // would consider valid. By far the most common hostname character NOT
- // accepted by the above spec is '_'.
- url::CanonHostInfo host_info;
- string canonicalized_host(CanonicalizeHost(sni.as_string(), &host_info));
- return !host_info.IsIPAddress() &&
- IsCanonicalizedHostCompliant(canonicalized_host) &&
- sni.find_last_of('.') != string::npos;
-}
-
-// static
-string CryptoUtils::NormalizeHostname(const char* hostname) {
- url::CanonHostInfo host_info;
- string host(CanonicalizeHost(hostname, &host_info));
-
- // Walk backwards over the string, stopping at the first trailing dot.
- size_t host_end = host.length();
- while (host_end != 0 && host[host_end - 1] == '.') {
- host_end--;
- }
-
- // Erase the trailing dots.
- if (host_end != host.length()) {
- host.erase(host_end, host.length() - host_end);
- }
- return host;
-}
-
-// static
-bool CryptoUtils::DeriveKeys(StringPiece premaster_secret,
- QuicTag aead,
- StringPiece client_nonce,
- StringPiece server_nonce,
- const string& hkdf_input,
- Perspective perspective,
- Diversification diversification,
- CrypterPair* crypters,
- string* subkey_secret) {
- crypters->encrypter.reset(QuicEncrypter::Create(aead));
- crypters->decrypter.reset(QuicDecrypter::Create(aead));
- size_t key_bytes = crypters->encrypter->GetKeySize();
- size_t nonce_prefix_bytes = crypters->encrypter->GetNoncePrefixSize();
- size_t subkey_secret_bytes =
- subkey_secret == nullptr ? 0 : premaster_secret.length();
-
- StringPiece nonce = client_nonce;
- string nonce_storage;
- if (!server_nonce.empty()) {
- nonce_storage = client_nonce.as_string() + server_nonce.as_string();
- nonce = nonce_storage;
- }
-
- crypto::HKDF hkdf(premaster_secret, nonce, hkdf_input, key_bytes,
- nonce_prefix_bytes, subkey_secret_bytes);
-
- // Key derivation depends on the key diversification method being employed.
- // both the client and the server support never doing key diversification.
- // The server also supports immediate diversification, and the client
- // supports pending diversification.
- switch (diversification.mode()) {
- case Diversification::NEVER: {
- if (perspective == Perspective::IS_SERVER) {
- if (!crypters->encrypter->SetKey(hkdf.server_write_key()) ||
- !crypters->encrypter->SetNoncePrefix(hkdf.server_write_iv()) ||
- !crypters->decrypter->SetKey(hkdf.client_write_key()) ||
- !crypters->decrypter->SetNoncePrefix(hkdf.client_write_iv())) {
- return false;
- }
- } else {
- if (!crypters->encrypter->SetKey(hkdf.client_write_key()) ||
- !crypters->encrypter->SetNoncePrefix(hkdf.client_write_iv()) ||
- !crypters->decrypter->SetKey(hkdf.server_write_key()) ||
- !crypters->decrypter->SetNoncePrefix(hkdf.server_write_iv())) {
- return false;
- }
- }
- break;
- }
- case Diversification::PENDING: {
- if (perspective == Perspective::IS_SERVER) {
- QUIC_BUG << "Pending diversification is only for clients.";
- return false;
- }
-
- if (!crypters->encrypter->SetKey(hkdf.client_write_key()) ||
- !crypters->encrypter->SetNoncePrefix(hkdf.client_write_iv()) ||
- !crypters->decrypter->SetPreliminaryKey(hkdf.server_write_key()) ||
- !crypters->decrypter->SetNoncePrefix(hkdf.server_write_iv())) {
- return false;
- }
- break;
- }
- case Diversification::NOW: {
- if (perspective == Perspective::IS_CLIENT) {
- QUIC_BUG << "Immediate diversification is only for servers.";
- return false;
- }
-
- string key, nonce_prefix;
- QuicDecrypter::DiversifyPreliminaryKey(
- hkdf.server_write_key(), hkdf.server_write_iv(),
- *diversification.nonce(), key_bytes, nonce_prefix_bytes, &key,
- &nonce_prefix);
- if (!crypters->decrypter->SetKey(hkdf.client_write_key()) ||
- !crypters->decrypter->SetNoncePrefix(hkdf.client_write_iv()) ||
- !crypters->encrypter->SetKey(key) ||
- !crypters->encrypter->SetNoncePrefix(nonce_prefix)) {
- return false;
- }
- break;
- }
- default:
- DCHECK(false);
- }
-
- if (subkey_secret != nullptr) {
- hkdf.subkey_secret().CopyToString(subkey_secret);
- }
-
- return true;
-}
-
-// static
-bool CryptoUtils::ExportKeyingMaterial(StringPiece subkey_secret,
- StringPiece label,
- StringPiece context,
- size_t result_len,
- string* result) {
- for (size_t i = 0; i < label.length(); i++) {
- if (label[i] == '\0') {
- LOG(ERROR) << "ExportKeyingMaterial label may not contain NULs";
- return false;
- }
- }
- // Create HKDF info input: null-terminated label + length-prefixed context
- if (context.length() >= numeric_limits<uint32_t>::max()) {
- LOG(ERROR) << "Context value longer than 2^32";
- return false;
- }
- uint32_t context_length = static_cast<uint32_t>(context.length());
- string info = label.as_string();
- info.push_back('\0');
- info.append(reinterpret_cast<char*>(&context_length), sizeof(context_length));
- info.append(context.data(), context.length());
-
- crypto::HKDF hkdf(subkey_secret, StringPiece() /* no salt */, info,
- result_len, 0 /* no fixed IV */, 0 /* no subkey secret */);
- hkdf.client_write_key().CopyToString(result);
- return true;
-}
-
-// static
-uint64_t CryptoUtils::ComputeLeafCertHash(const std::string& cert) {
- return QuicUtils::FNV1a_64_Hash(cert.data(), cert.size());
-}
-
-QuicErrorCode CryptoUtils::ValidateServerHello(
- const CryptoHandshakeMessage& server_hello,
- const QuicVersionVector& negotiated_versions,
- string* error_details) {
- DCHECK(error_details != nullptr);
-
- if (server_hello.tag() != kSHLO) {
- *error_details = "Bad tag";
- return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
- }
-
- const QuicTag* supported_version_tags;
- size_t num_supported_versions;
-
- if (server_hello.GetTaglist(kVER, &supported_version_tags,
- &num_supported_versions) != QUIC_NO_ERROR) {
- *error_details = "server hello missing version list";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
- if (!negotiated_versions.empty()) {
- bool mismatch = num_supported_versions != negotiated_versions.size();
- for (size_t i = 0; i < num_supported_versions && !mismatch; ++i) {
- mismatch = QuicTagToQuicVersion(supported_version_tags[i]) !=
- negotiated_versions[i];
- }
- // The server sent a list of supported versions, and the connection
- // reports that there was a version negotiation during the handshake.
- // Ensure that these two lists are identical.
- if (mismatch) {
- *error_details = "Downgrade attack detected";
- return QUIC_VERSION_NEGOTIATION_MISMATCH;
- }
- }
- return QUIC_NO_ERROR;
-}
-
-QuicErrorCode CryptoUtils::ValidateClientHello(
- const CryptoHandshakeMessage& client_hello,
- QuicVersion version,
- const QuicVersionVector& supported_versions,
- string* error_details) {
- if (client_hello.tag() != kCHLO) {
- *error_details = "Bad tag";
- return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
- }
-
- // If the client's preferred version is not the version we are currently
- // speaking, then the client went through a version negotiation. In this
- // case, we need to make sure that we actually do not support this version
- // and that it wasn't a downgrade attack.
- QuicTag client_version_tag;
- if (client_hello.GetUint32(kVER, &client_version_tag) != QUIC_NO_ERROR) {
- *error_details = "client hello missing version list";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
- QuicVersion client_version = QuicTagToQuicVersion(client_version_tag);
- if (client_version != version) {
- // Just because client_version is a valid version enum doesn't mean that
- // this server actually supports that version, so we check to see if
- // it's actually in the supported versions list.
- for (size_t i = 0; i < supported_versions.size(); ++i) {
- if (client_version == supported_versions[i]) {
- *error_details = "Downgrade attack detected";
- return QUIC_VERSION_NEGOTIATION_MISMATCH;
- }
- }
- }
- return QUIC_NO_ERROR;
-}
-
-#define RETURN_STRING_LITERAL(x) \
- case x: \
- return #x
-
-// Returns the name of the HandshakeFailureReason as a char*
-// static
-const char* CryptoUtils::HandshakeFailureReasonToString(
- HandshakeFailureReason reason) {
- switch (reason) {
- RETURN_STRING_LITERAL(HANDSHAKE_OK);
- RETURN_STRING_LITERAL(CLIENT_NONCE_UNKNOWN_FAILURE);
- RETURN_STRING_LITERAL(CLIENT_NONCE_INVALID_FAILURE);
- RETURN_STRING_LITERAL(CLIENT_NONCE_NOT_UNIQUE_FAILURE);
- RETURN_STRING_LITERAL(CLIENT_NONCE_INVALID_ORBIT_FAILURE);
- RETURN_STRING_LITERAL(CLIENT_NONCE_INVALID_TIME_FAILURE);
- RETURN_STRING_LITERAL(CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT);
- RETURN_STRING_LITERAL(CLIENT_NONCE_STRIKE_REGISTER_FAILURE);
-
- RETURN_STRING_LITERAL(SERVER_NONCE_DECRYPTION_FAILURE);
- RETURN_STRING_LITERAL(SERVER_NONCE_INVALID_FAILURE);
- RETURN_STRING_LITERAL(SERVER_NONCE_NOT_UNIQUE_FAILURE);
- RETURN_STRING_LITERAL(SERVER_NONCE_INVALID_TIME_FAILURE);
- RETURN_STRING_LITERAL(SERVER_NONCE_REQUIRED_FAILURE);
-
- RETURN_STRING_LITERAL(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
- RETURN_STRING_LITERAL(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
-
- RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_INVALID_FAILURE);
- RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE);
- RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_PARSE_FAILURE);
- RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE);
- RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE);
- RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE);
-
- RETURN_STRING_LITERAL(INVALID_EXPECTED_LEAF_CERTIFICATE);
- RETURN_STRING_LITERAL(MAX_FAILURE_REASON);
- }
- // Return a default value so that we return this when |reason| doesn't match
- // any HandshakeFailureReason.. This can happen when the message by the peer
- // (attacker) has invalid reason.
- return "INVALID_HANDSHAKE_FAILURE_REASON";
-}
-
-// static
-void CryptoUtils::HashHandshakeMessage(const CryptoHandshakeMessage& message,
- string* output) {
- const QuicData& serialized = message.GetSerialized();
- std::unique_ptr<crypto::SecureHash> hash(
- crypto::SecureHash::Create(crypto::SecureHash::SHA256));
- hash->Update(serialized.data(), serialized.length());
- uint8_t digest[32];
- hash->Finish(digest, sizeof(digest));
- output->assign(reinterpret_cast<const char*>(&digest), sizeof(digest));
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/crypto_utils.h b/chromium/net/quic/crypto/crypto_utils.h
deleted file mode 100644
index ddbff57ea57..00000000000
--- a/chromium/net/quic/crypto/crypto_utils.h
+++ /dev/null
@@ -1,170 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// Some helpers for quic crypto
-
-#ifndef NET_QUIC_CRYPTO_CRYPTO_UTILS_H_
-#define NET_QUIC_CRYPTO_CRYPTO_UTILS_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class QuicTime;
-class QuicRandom;
-struct QuicCryptoNegotiatedParameters;
-
-class NET_EXPORT_PRIVATE CryptoUtils {
- public:
- // Diversification is a utility class that's used to act like a union type.
- // Values can be created by calling the functions like |NoDiversification|,
- // below.
- class Diversification {
- public:
- enum Mode {
- NEVER, // Key diversification will never be used. Forward secure
- // crypters will always use this mode.
-
- PENDING, // Key diversification will happen when a nonce is later
- // received. This should only be used by clients initial
- // decrypters which are waiting on the divesification nonce
- // from the server.
-
- NOW, // Key diversification will happen immediate based on the nonce.
- // This should only be used by servers initial encrypters.
- };
-
- Diversification(const Diversification& diversification) = default;
-
- static Diversification Never() { return Diversification(NEVER, nullptr); }
- static Diversification Pending() {
- return Diversification(PENDING, nullptr);
- }
- static Diversification Now(DiversificationNonce* nonce) {
- return Diversification(NOW, nonce);
- }
-
- Mode mode() const { return mode_; }
- DiversificationNonce* nonce() const {
- DCHECK_EQ(mode_, NOW);
- return nonce_;
- }
-
- private:
- Diversification(Mode mode, DiversificationNonce* nonce)
- : mode_(mode), nonce_(nonce) {}
-
- Mode mode_;
- DiversificationNonce* nonce_;
- };
-
- // Generates the connection nonce. The nonce is formed as:
- // <4 bytes> current time
- // <8 bytes> |orbit| (or random if |orbit| is empty)
- // <20 bytes> random
- static void GenerateNonce(QuicWallTime now,
- QuicRandom* random_generator,
- base::StringPiece orbit,
- std::string* nonce);
-
- // Returns true if the sni is valid, false otherwise.
- // (1) disallow IP addresses;
- // (2) check that the hostname contains valid characters only; and
- // (3) contains at least one dot.
- static bool IsValidSNI(base::StringPiece sni);
-
- // Convert hostname to lowercase and remove the trailing '.'.
- // Returns |hostname|. NormalizeHostname() doesn't support IP address
- // literals. IsValidSNI() should be called before calling NormalizeHostname().
- static std::string NormalizeHostname(const char* hostname);
-
- // DeriveKeys populates |crypters->encrypter|, |crypters->decrypter|, and
- // |subkey_secret| (optional -- may be null) given the contents of
- // |premaster_secret|, |client_nonce|, |server_nonce| and |hkdf_input|. |aead|
- // determines which cipher will be used. |perspective| controls whether the
- // server's keys are assigned to |encrypter| or |decrypter|. |server_nonce| is
- // optional and, if non-empty, is mixed into the key derivation.
- // |subkey_secret| will have the same length as |premaster_secret|.
- //
- // If the mode of |diversification| is NEVER, the the crypters will be
- // configured to never perform key diversification. If the mode is
- // NOW (which is only for servers, then the encrypter will be keyed via a
- // two-step process that uses the nonce from |diversification|.
- // If the mode is PENDING (which is only for servres), then the
- // decrypter will only be keyed to a preliminary state: a call to
- // |SetDiversificationNonce| with a diversification nonce will be needed to
- // complete keying.
- static bool DeriveKeys(base::StringPiece premaster_secret,
- QuicTag aead,
- base::StringPiece client_nonce,
- base::StringPiece server_nonce,
- const std::string& hkdf_input,
- Perspective perspective,
- Diversification diversification,
- CrypterPair* crypters,
- std::string* subkey_secret);
-
- // Performs key extraction to derive a new secret of |result_len| bytes
- // dependent on |subkey_secret|, |label|, and |context|. Returns false if the
- // parameters are invalid (e.g. |label| contains null bytes); returns true on
- // success.
- static bool ExportKeyingMaterial(base::StringPiece subkey_secret,
- base::StringPiece label,
- base::StringPiece context,
- size_t result_len,
- std::string* result);
-
- // Computes the FNV-1a hash of the provided DER-encoded cert for use in the
- // XLCT tag.
- static uint64_t ComputeLeafCertHash(const std::string& cert);
-
- // Validates that |server_hello| is actually an SHLO message and that it is
- // not part of a downgrade attack.
- //
- // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error
- // code and sets |error_details|.
- static QuicErrorCode ValidateServerHello(
- const CryptoHandshakeMessage& server_hello,
- const QuicVersionVector& negotiated_versions,
- std::string* error_details);
-
- // Validates that |client_hello| is actually a CHLO and that this is not part
- // of a downgrade attack.
- // This includes verifiying versions and detecting downgrade attacks.
- //
- // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error
- // code and sets |error_details|.
- static QuicErrorCode ValidateClientHello(
- const CryptoHandshakeMessage& client_hello,
- QuicVersion version,
- const QuicVersionVector& supported_versions,
- std::string* error_details);
-
- // Returns the name of the HandshakeFailureReason as a char*
- static const char* HandshakeFailureReasonToString(
- HandshakeFailureReason reason);
-
- // Writes a hash of the serialized |message| into |output|.
- static void HashHandshakeMessage(const CryptoHandshakeMessage& message,
- std::string* output);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CryptoUtils);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_CRYPTO_UTILS_H_
diff --git a/chromium/net/quic/crypto/crypto_utils_test.cc b/chromium/net/quic/crypto/crypto_utils_test.cc
deleted file mode 100644
index 2fadf83b992..00000000000
--- a/chromium/net/quic/crypto/crypto_utils_test.cc
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright (c) 2013 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/crypto/crypto_utils.h"
-
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::string;
-
-namespace net {
-namespace test {
-namespace {
-
-TEST(CryptoUtilsTest, IsValidSNI) {
- // IP as SNI.
- EXPECT_FALSE(CryptoUtils::IsValidSNI("192.168.0.1"));
- // SNI without any dot.
- EXPECT_FALSE(CryptoUtils::IsValidSNI("somedomain"));
- // Invalid RFC2396 hostname
- // TODO(rtenneti): Support RFC2396 hostname.
- // EXPECT_FALSE(CryptoUtils::IsValidSNI("some_domain.com"));
- // An empty string must be invalid otherwise the QUIC client will try sending
- // it.
- EXPECT_FALSE(CryptoUtils::IsValidSNI(""));
-
- // Valid SNI
- EXPECT_TRUE(CryptoUtils::IsValidSNI("test.google.com"));
-}
-
-TEST(CryptoUtilsTest, NormalizeHostname) {
- struct {
- const char *input, *expected;
- } tests[] = {
- {
- "www.google.com", "www.google.com",
- },
- {
- "WWW.GOOGLE.COM", "www.google.com",
- },
- {
- "www.google.com.", "www.google.com",
- },
- {
- "www.google.COM.", "www.google.com",
- },
- {
- "www.google.com..", "www.google.com",
- },
- {
- "www.google.com........", "www.google.com",
- },
- };
-
- for (size_t i = 0; i < arraysize(tests); ++i) {
- char buf[256];
- snprintf(buf, sizeof(buf), "%s", tests[i].input);
- EXPECT_EQ(string(tests[i].expected), CryptoUtils::NormalizeHostname(buf));
- }
-}
-
-TEST(CryptoUtilsTest, TestExportKeyingMaterial) {
- const struct TestVector {
- // Input (strings of hexadecimal digits):
- const char* subkey_secret;
- const char* label;
- const char* context;
- size_t result_len;
-
- // Expected output (string of hexadecimal digits):
- const char* expected; // Null if it should fail.
- } test_vector[] = {
- // Try a typical input
- {"4823c1189ecc40fce888fbb4cf9ae6254f19ba12e6d9af54788f195a6f509ca3",
- "e934f78d7a71dd85420fceeb8cea0317",
- "b8d766b5d3c8aba0009c7ed3de553eba53b4de1030ea91383dcdf724cd8b7217", 32,
- "a9979da0d5f1c1387d7cbe68f5c4163ddb445a03c4ad6ee72cb49d56726d679e"},
- // Don't let the label contain nulls
- {"14fe51e082ffee7d1b4d8d4ab41f8c55", "3132333435363700",
- "58585858585858585858585858585858", 16, nullptr},
- // Make sure nulls in the context are fine
- {"d862c2e36b0a42f7827c67ebc8d44df7", "7a5b95e4e8378123",
- "4142434445464700", 16, "12d418c6d0738a2e4d85b2d0170f76e1"},
- // ... and give a different result than without
- {"d862c2e36b0a42f7827c67ebc8d44df7", "7a5b95e4e8378123", "41424344454647",
- 16, "abfa1c479a6e3ffb98a11dee7d196408"},
- // Try weird lengths
- {"d0ec8a34f6cc9a8c96", "49711798cc6251",
- "933d4a2f30d22f089cfba842791116adc121e0", 23,
- "c9a46ed0757bd1812f1f21b4d41e62125fec8364a21db7"},
- };
-
- for (size_t i = 0; i < arraysize(test_vector); i++) {
- // Decode the test vector.
- string subkey_secret = QuicUtils::HexDecode(test_vector[i].subkey_secret);
- string label = QuicUtils::HexDecode(test_vector[i].label);
- string context = QuicUtils::HexDecode(test_vector[i].context);
- size_t result_len = test_vector[i].result_len;
- bool expect_ok = test_vector[i].expected != nullptr;
- string expected;
- if (expect_ok) {
- expected = QuicUtils::HexDecode(test_vector[i].expected);
- }
-
- string result;
- bool ok = CryptoUtils::ExportKeyingMaterial(subkey_secret, label, context,
- result_len, &result);
- EXPECT_EQ(expect_ok, ok);
- if (expect_ok) {
- EXPECT_EQ(result_len, result.length());
- test::CompareCharArraysWithHexError("HKDF output", result.data(),
- result.length(), expected.data(),
- expected.length());
- }
- }
-}
-
-TEST(CryptoUtilsTest, HandshakeFailureReasonToString) {
- EXPECT_STREQ("HANDSHAKE_OK",
- CryptoUtils::HandshakeFailureReasonToString(HANDSHAKE_OK));
- EXPECT_STREQ("CLIENT_NONCE_UNKNOWN_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- CLIENT_NONCE_UNKNOWN_FAILURE));
- EXPECT_STREQ("CLIENT_NONCE_INVALID_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- CLIENT_NONCE_INVALID_FAILURE));
- EXPECT_STREQ("CLIENT_NONCE_NOT_UNIQUE_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- CLIENT_NONCE_NOT_UNIQUE_FAILURE));
- EXPECT_STREQ("CLIENT_NONCE_INVALID_ORBIT_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- CLIENT_NONCE_INVALID_ORBIT_FAILURE));
- EXPECT_STREQ("CLIENT_NONCE_INVALID_TIME_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- CLIENT_NONCE_INVALID_TIME_FAILURE));
- EXPECT_STREQ("CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT",
- CryptoUtils::HandshakeFailureReasonToString(
- CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT));
- EXPECT_STREQ("CLIENT_NONCE_STRIKE_REGISTER_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- CLIENT_NONCE_STRIKE_REGISTER_FAILURE));
- EXPECT_STREQ("SERVER_NONCE_DECRYPTION_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- SERVER_NONCE_DECRYPTION_FAILURE));
- EXPECT_STREQ("SERVER_NONCE_INVALID_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- SERVER_NONCE_INVALID_FAILURE));
- EXPECT_STREQ("SERVER_NONCE_NOT_UNIQUE_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- SERVER_NONCE_NOT_UNIQUE_FAILURE));
- EXPECT_STREQ("SERVER_NONCE_INVALID_TIME_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- SERVER_NONCE_INVALID_TIME_FAILURE));
- EXPECT_STREQ("SERVER_NONCE_REQUIRED_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- SERVER_NONCE_REQUIRED_FAILURE));
- EXPECT_STREQ("SERVER_CONFIG_INCHOATE_HELLO_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- SERVER_CONFIG_INCHOATE_HELLO_FAILURE));
- EXPECT_STREQ("SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE));
- EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_INVALID_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- SOURCE_ADDRESS_TOKEN_INVALID_FAILURE));
- EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE));
- EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_PARSE_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- SOURCE_ADDRESS_TOKEN_PARSE_FAILURE));
- EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE));
- EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE));
- EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE",
- CryptoUtils::HandshakeFailureReasonToString(
- SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE));
- EXPECT_STREQ("INVALID_EXPECTED_LEAF_CERTIFICATE",
- CryptoUtils::HandshakeFailureReasonToString(
- INVALID_EXPECTED_LEAF_CERTIFICATE));
- EXPECT_STREQ("MAX_FAILURE_REASON",
- CryptoUtils::HandshakeFailureReasonToString(MAX_FAILURE_REASON));
- EXPECT_STREQ(
- "INVALID_HANDSHAKE_FAILURE_REASON",
- CryptoUtils::HandshakeFailureReasonToString(
- static_cast<HandshakeFailureReason>(MAX_FAILURE_REASON + 1)));
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/curve25519_key_exchange.cc b/chromium/net/quic/crypto/curve25519_key_exchange.cc
deleted file mode 100644
index 6545d21bc2f..00000000000
--- a/chromium/net/quic/crypto/curve25519_key_exchange.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 2013 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/crypto/curve25519_key_exchange.h"
-
-#include "base/logging.h"
-#include "crypto/curve25519.h"
-#include "net/quic/crypto/quic_random.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-
-Curve25519KeyExchange::Curve25519KeyExchange() {}
-
-Curve25519KeyExchange::~Curve25519KeyExchange() {}
-
-// static
-Curve25519KeyExchange* Curve25519KeyExchange::New(StringPiece private_key) {
- Curve25519KeyExchange* ka;
- // We don't want to #include the NaCl headers in the public header file, so
- // we use literals for the sizes of private_key_ and public_key_. Here we
- // assert that those values are equal to the values from the NaCl header.
- static_assert(sizeof(ka->private_key_) == crypto::curve25519::kScalarBytes,
- "header out of sync");
- static_assert(sizeof(ka->public_key_) == crypto::curve25519::kBytes,
- "header out of sync");
-
- if (private_key.size() != crypto::curve25519::kScalarBytes) {
- return nullptr;
- }
-
- ka = new Curve25519KeyExchange();
- memcpy(ka->private_key_, private_key.data(),
- crypto::curve25519::kScalarBytes);
- crypto::curve25519::ScalarBaseMult(ka->private_key_, ka->public_key_);
- return ka;
-}
-
-// static
-string Curve25519KeyExchange::NewPrivateKey(QuicRandom* rand) {
- uint8_t private_key[crypto::curve25519::kScalarBytes];
- rand->RandBytes(private_key, sizeof(private_key));
-
- // This makes |private_key| a valid scalar, as specified on
- // http://cr.yp.to/ecdh.html
- private_key[0] &= 248;
- private_key[31] &= 127;
- private_key[31] |= 64;
- return string(reinterpret_cast<char*>(private_key), sizeof(private_key));
-}
-
-KeyExchange* Curve25519KeyExchange::NewKeyPair(QuicRandom* rand) const {
- const string private_value = NewPrivateKey(rand);
- return Curve25519KeyExchange::New(private_value);
-}
-
-bool Curve25519KeyExchange::CalculateSharedKey(StringPiece peer_public_value,
- string* out_result) const {
- if (peer_public_value.size() != crypto::curve25519::kBytes) {
- return false;
- }
-
- uint8_t result[crypto::curve25519::kBytes];
- if (!crypto::curve25519::ScalarMult(
- private_key_,
- reinterpret_cast<const uint8_t*>(peer_public_value.data()), result)) {
- return false;
- }
- out_result->assign(reinterpret_cast<char*>(result), sizeof(result));
-
- return true;
-}
-
-StringPiece Curve25519KeyExchange::public_value() const {
- return StringPiece(reinterpret_cast<const char*>(public_key_),
- sizeof(public_key_));
-}
-
-QuicTag Curve25519KeyExchange::tag() const {
- return kC255;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/curve25519_key_exchange.h b/chromium/net/quic/crypto/curve25519_key_exchange.h
deleted file mode 100644
index a95cf7f6ce6..00000000000
--- a/chromium/net/quic/crypto/curve25519_key_exchange.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2013 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_CRYPTO_CURVE25519_KEY_EXCHANGE_H_
-#define NET_QUIC_CRYPTO_CURVE25519_KEY_EXCHANGE_H_
-
-#include <stdint.h>
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-#include "net/quic/crypto/key_exchange.h"
-
-namespace net {
-
-class QuicRandom;
-
-// Curve25519KeyExchange implements a KeyExchange using elliptic-curve
-// Diffie-Hellman on curve25519. See http://cr.yp.to/ecdh.html
-class NET_EXPORT_PRIVATE Curve25519KeyExchange : public KeyExchange {
- public:
- ~Curve25519KeyExchange() override;
-
- // New creates a new object from a private key. If the private key is
- // invalid, nullptr is returned.
- static Curve25519KeyExchange* New(base::StringPiece private_key);
-
- // NewPrivateKey returns a private key, generated from |rand|, suitable for
- // passing to |New|.
- static std::string NewPrivateKey(QuicRandom* rand);
-
- // KeyExchange interface.
- KeyExchange* NewKeyPair(QuicRandom* rand) const override;
- bool CalculateSharedKey(base::StringPiece peer_public_value,
- std::string* shared_key) const override;
- base::StringPiece public_value() const override;
- QuicTag tag() const override;
-
- private:
- Curve25519KeyExchange();
-
- uint8_t private_key_[32];
- uint8_t public_key_[32];
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_CURVE25519_KEY_EXCHANGE_H_
diff --git a/chromium/net/quic/crypto/curve25519_key_exchange_test.cc b/chromium/net/quic/crypto/curve25519_key_exchange_test.cc
deleted file mode 100644
index 6c87d243f74..00000000000
--- a/chromium/net/quic/crypto/curve25519_key_exchange_test.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2013 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/crypto/curve25519_key_exchange.h"
-
-#include <memory>
-
-#include "base/strings/string_piece.h"
-#include "net/quic/crypto/quic_random.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-namespace test {
-
-// SharedKey just tests that the basic key exchange identity holds: that both
-// parties end up with the same key.
-TEST(Curve25519KeyExchange, SharedKey) {
- QuicRandom* const rand = QuicRandom::GetInstance();
-
- for (int i = 0; i < 5; i++) {
- const string alice_key(Curve25519KeyExchange::NewPrivateKey(rand));
- const string bob_key(Curve25519KeyExchange::NewPrivateKey(rand));
-
- std::unique_ptr<Curve25519KeyExchange> alice(
- Curve25519KeyExchange::New(alice_key));
- std::unique_ptr<Curve25519KeyExchange> bob(
- Curve25519KeyExchange::New(bob_key));
-
- const StringPiece alice_public(alice->public_value());
- const StringPiece bob_public(bob->public_value());
-
- string alice_shared, bob_shared;
- ASSERT_TRUE(alice->CalculateSharedKey(bob_public, &alice_shared));
- ASSERT_TRUE(bob->CalculateSharedKey(alice_public, &bob_shared));
- ASSERT_EQ(alice_shared, bob_shared);
- }
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/ephemeral_key_source.h b/chromium/net/quic/crypto/ephemeral_key_source.h
deleted file mode 100644
index 2700be0fe1b..00000000000
--- a/chromium/net/quic/crypto/ephemeral_key_source.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2013 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_CRYPTO_EPHEMERAL_KEY_SOURCE_H_
-#define NET_QUIC_CRYPTO_EPHEMERAL_KEY_SOURCE_H_
-
-#include <string>
-
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class KeyExchange;
-class QuicRandom;
-
-// EphemeralKeySource manages and rotates ephemeral keys as they can be reused
-// for several connections in a short space of time. Since the implementation
-// of this may involve locking or thread-local data, this interface abstracts
-// that away.
-class NET_EXPORT_PRIVATE EphemeralKeySource {
- public:
- virtual ~EphemeralKeySource() {}
-
- // CalculateForwardSecureKey generates an ephemeral public/private key pair
- // using the algorithm |key_exchange|, sets |*public_value| to the public key
- // and returns the shared key between |peer_public_value| and the private
- // key. |*public_value| will be sent to the peer to be used with the peer's
- // private key.
- virtual std::string CalculateForwardSecureKey(
- const KeyExchange* key_exchange,
- QuicRandom* rand,
- QuicTime now,
- base::StringPiece peer_public_value,
- std::string* public_value) = 0;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_EPHEMERAL_KEY_SOURCE_H_
diff --git a/chromium/net/quic/crypto/key_exchange.h b/chromium/net/quic/crypto/key_exchange.h
deleted file mode 100644
index a6de1c39dfd..00000000000
--- a/chromium/net/quic/crypto/key_exchange.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2013 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_CRYPTO_KEY_EXCHANGE_H_
-#define NET_QUIC_CRYPTO_KEY_EXCHANGE_H_
-
-#include <string>
-
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-#include "net/quic/crypto/crypto_protocol.h"
-
-namespace net {
-
-class QuicRandom;
-
-// KeyExchange is an abstract class that provides an interface to a
-// key-exchange primitive.
-class NET_EXPORT_PRIVATE KeyExchange {
- public:
- virtual ~KeyExchange() {}
-
- // NewKeyPair generates a new public, private key pair. The caller takes
- // ownership of the return value. (This is intended for servers that need to
- // generate forward-secure keys.)
- virtual KeyExchange* NewKeyPair(QuicRandom* rand) const = 0;
-
- // CalculateSharedKey computes the shared key between the local private key
- // (which is implicitly known by a KeyExchange object) and a public value
- // from the peer.
- virtual bool CalculateSharedKey(base::StringPiece peer_public_value,
- std::string* shared_key) const = 0;
-
- // public_value returns the local public key which can be sent to a peer in
- // order to complete a key exchange. The returned StringPiece is a reference
- // to a member of the KeyExchange and is only valid for as long as the
- // KeyExchange exists.
- virtual base::StringPiece public_value() const = 0;
-
- // tag returns the tag value that identifies this key exchange function.
- virtual QuicTag tag() const = 0;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_KEY_EXCHANGE_H_
diff --git a/chromium/net/quic/crypto/local_strike_register_client.cc b/chromium/net/quic/crypto/local_strike_register_client.cc
deleted file mode 100644
index 1d009a947e1..00000000000
--- a/chromium/net/quic/crypto/local_strike_register_client.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2013 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/crypto/local_strike_register_client.h"
-
-#include "net/quic/crypto/crypto_protocol.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-
-LocalStrikeRegisterClient::LocalStrikeRegisterClient(
- unsigned max_entries,
- uint32_t current_time_external,
- uint32_t window_secs,
- const uint8_t orbit[8],
- StrikeRegister::StartupType startup)
- : strike_register_(max_entries,
- current_time_external,
- window_secs,
- orbit,
- startup) {}
-
-bool LocalStrikeRegisterClient::IsKnownOrbit(StringPiece orbit) const {
- base::AutoLock lock(m_);
- if (orbit.length() != kOrbitSize) {
- return false;
- }
- return memcmp(orbit.data(), strike_register_.orbit(), kOrbitSize) == 0;
-}
-
-void LocalStrikeRegisterClient::VerifyNonceIsValidAndUnique(
- StringPiece nonce,
- QuicWallTime now,
- ResultCallback* cb) {
- InsertStatus nonce_error;
- if (nonce.length() != kNonceSize) {
- nonce_error = NONCE_INVALID_FAILURE;
- } else {
- base::AutoLock lock(m_);
- nonce_error =
- strike_register_.Insert(reinterpret_cast<const uint8_t*>(nonce.data()),
- static_cast<uint32_t>(now.ToUNIXSeconds()));
- }
-
- // m_ must not be held when the ResultCallback runs.
- cb->Run((nonce_error == NONCE_OK), nonce_error);
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/local_strike_register_client.h b/chromium/net/quic/crypto/local_strike_register_client.h
deleted file mode 100644
index 8e10497efb6..00000000000
--- a/chromium/net/quic/crypto/local_strike_register_client.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2013 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_CRYPTO_LOCAL_STRIKE_REGISTER_CLIENT_H_
-#define NET_QUIC_CRYPTO_LOCAL_STRIKE_REGISTER_CLIENT_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "base/synchronization/lock.h"
-#include "net/base/net_export.h"
-#include "net/quic/crypto/strike_register.h"
-#include "net/quic/crypto/strike_register_client.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-// StrikeRegisterClient implementation that wraps a local in-memory
-// strike register.
-class NET_EXPORT_PRIVATE LocalStrikeRegisterClient
- : public StrikeRegisterClient {
- public:
- LocalStrikeRegisterClient(unsigned max_entries,
- uint32_t current_time_external,
- uint32_t window_secs,
- const uint8_t orbit[8],
- StrikeRegister::StartupType startup);
-
- bool IsKnownOrbit(base::StringPiece orbit) const override;
- void VerifyNonceIsValidAndUnique(base::StringPiece nonce,
- QuicWallTime now,
- ResultCallback* cb) override;
-
- private:
- mutable base::Lock m_;
- StrikeRegister strike_register_;
-
- DISALLOW_COPY_AND_ASSIGN(LocalStrikeRegisterClient);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_LOCAL_STRIKE_REGISTER_CLIENT_H_
diff --git a/chromium/net/quic/crypto/local_strike_register_client_test.cc b/chromium/net/quic/crypto/local_strike_register_client_test.cc
deleted file mode 100644
index d72dcb1d8d3..00000000000
--- a/chromium/net/quic/crypto/local_strike_register_client_test.cc
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2013 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/crypto/local_strike_register_client.h"
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "base/sys_byteorder.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/quic_time.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-namespace test {
-namespace {
-
-class RecordResultCallback : public StrikeRegisterClient::ResultCallback {
- public:
- // RecordResultCallback stores the argument to RunImpl in
- // |*saved_value| and sets |*called| to true. The callback is self
- // deleting.
- RecordResultCallback(bool* called,
- bool* saved_value,
- InsertStatus* saved_nonce_error)
- : called_(called),
- saved_value_(saved_value),
- saved_nonce_error_(saved_nonce_error) {
- *called_ = false;
- }
-
- protected:
- void RunImpl(bool nonce_is_valid_and_unique,
- InsertStatus nonce_error) override {
- *called_ = true;
- *saved_value_ = nonce_is_valid_and_unique;
- *saved_nonce_error_ = nonce_error;
- }
-
- private:
- bool* called_;
- bool* saved_value_;
- InsertStatus* saved_nonce_error_;
-
- DISALLOW_COPY_AND_ASSIGN(RecordResultCallback);
-};
-
-const uint8_t kOrbit[] = "\x12\x34\x56\x78\x9A\xBC\xDE\xF0";
-const uint32_t kCurrentTimeExternalSecs = 12345678;
-size_t kMaxEntries = 100;
-uint32_t kWindowSecs = 60;
-
-class LocalStrikeRegisterClientTest : public ::testing::Test {
- protected:
- LocalStrikeRegisterClientTest() {}
-
- void SetUp() override {
- strike_register_.reset(new LocalStrikeRegisterClient(
- kMaxEntries, kCurrentTimeExternalSecs, kWindowSecs, kOrbit,
- StrikeRegister::NO_STARTUP_PERIOD_NEEDED));
- }
-
- std::unique_ptr<LocalStrikeRegisterClient> strike_register_;
-};
-
-TEST_F(LocalStrikeRegisterClientTest, CheckOrbit) {
- EXPECT_TRUE(strike_register_->IsKnownOrbit(
- StringPiece(reinterpret_cast<const char*>(kOrbit), kOrbitSize)));
- EXPECT_FALSE(strike_register_->IsKnownOrbit(
- StringPiece(reinterpret_cast<const char*>(kOrbit), kOrbitSize - 1)));
- EXPECT_FALSE(strike_register_->IsKnownOrbit(
- StringPiece(reinterpret_cast<const char*>(kOrbit), kOrbitSize + 1)));
- EXPECT_FALSE(strike_register_->IsKnownOrbit(
- StringPiece(reinterpret_cast<const char*>(kOrbit) + 1, kOrbitSize)));
-}
-
-TEST_F(LocalStrikeRegisterClientTest, IncorrectNonceLength) {
- string valid_nonce;
- uint32_t norder = htonl(kCurrentTimeExternalSecs);
- valid_nonce.assign(reinterpret_cast<const char*>(&norder), sizeof(norder));
- valid_nonce.append(string(reinterpret_cast<const char*>(kOrbit), kOrbitSize));
- valid_nonce.append(string(20, '\x17')); // 20 'random' bytes.
-
- {
- // Validation fails if you remove a byte from the nonce.
- bool called = false;
- bool is_valid = false;
- InsertStatus nonce_error = NONCE_UNKNOWN_FAILURE;
- string short_nonce = valid_nonce.substr(0, valid_nonce.length() - 1);
- strike_register_->VerifyNonceIsValidAndUnique(
- short_nonce, QuicWallTime::FromUNIXSeconds(kCurrentTimeExternalSecs),
- new RecordResultCallback(&called, &is_valid, &nonce_error));
- EXPECT_TRUE(called);
- EXPECT_FALSE(is_valid);
- EXPECT_EQ(NONCE_INVALID_FAILURE, nonce_error);
- }
-
- {
- // Validation fails if you add a byte to the nonce.
- bool called = false;
- bool is_valid = false;
- InsertStatus nonce_error = NONCE_UNKNOWN_FAILURE;
- string long_nonce(valid_nonce);
- long_nonce.append("a");
- strike_register_->VerifyNonceIsValidAndUnique(
- long_nonce, QuicWallTime::FromUNIXSeconds(kCurrentTimeExternalSecs),
- new RecordResultCallback(&called, &is_valid, &nonce_error));
- EXPECT_TRUE(called);
- EXPECT_FALSE(is_valid);
- EXPECT_EQ(NONCE_INVALID_FAILURE, nonce_error);
- }
-
- {
- // Verify that the base nonce validates was valid.
- bool called = false;
- bool is_valid = false;
- InsertStatus nonce_error = NONCE_UNKNOWN_FAILURE;
- strike_register_->VerifyNonceIsValidAndUnique(
- valid_nonce, QuicWallTime::FromUNIXSeconds(kCurrentTimeExternalSecs),
- new RecordResultCallback(&called, &is_valid, &nonce_error));
- EXPECT_TRUE(called);
- EXPECT_TRUE(is_valid);
- EXPECT_EQ(NONCE_OK, nonce_error);
- }
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/null_decrypter.cc b/chromium/net/quic/crypto/null_decrypter.cc
deleted file mode 100644
index b0bf4d34f9c..00000000000
--- a/chromium/net/quic/crypto/null_decrypter.cc
+++ /dev/null
@@ -1,104 +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/crypto/null_decrypter.h"
-
-#include <stdint.h>
-
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_data_reader.h"
-#include "net/quic/quic_utils.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-
-NullDecrypter::NullDecrypter() {}
-
-bool NullDecrypter::SetKey(StringPiece key) {
- return key.empty();
-}
-
-bool NullDecrypter::SetNoncePrefix(StringPiece nonce_prefix) {
- return nonce_prefix.empty();
-}
-
-bool NullDecrypter::SetPreliminaryKey(StringPiece key) {
- QUIC_BUG << "Should not be called";
- return false;
-}
-
-bool NullDecrypter::SetDiversificationNonce(DiversificationNonce nonce) {
- QUIC_BUG << "Should not be called";
- return true;
-}
-
-bool NullDecrypter::DecryptPacket(QuicPathId /*path_id*/,
- QuicPacketNumber /*packet_number*/,
- StringPiece associated_data,
- StringPiece ciphertext,
- char* output,
- size_t* output_length,
- size_t max_output_length) {
- QuicDataReader reader(ciphertext.data(), ciphertext.length());
- uint128 hash;
-
- if (!ReadHash(&reader, &hash)) {
- return false;
- }
-
- StringPiece plaintext = reader.ReadRemainingPayload();
- if (plaintext.length() > max_output_length) {
- QUIC_BUG << "Output buffer must be larger than the plaintext.";
- return false;
- }
- if (hash != ComputeHash(associated_data, plaintext)) {
- return false;
- }
- // Copy the plaintext to output.
- memcpy(output, plaintext.data(), plaintext.length());
- *output_length = plaintext.length();
- return true;
-}
-
-StringPiece NullDecrypter::GetKey() const {
- return StringPiece();
-}
-
-StringPiece NullDecrypter::GetNoncePrefix() const {
- return StringPiece();
-}
-
-const char* NullDecrypter::cipher_name() const {
- return "NULL";
-}
-
-uint32_t NullDecrypter::cipher_id() const {
- return 0;
-}
-
-bool NullDecrypter::ReadHash(QuicDataReader* reader, uint128* hash) {
- uint64_t lo;
- uint32_t hi;
- if (!reader->ReadUInt64(&lo) || !reader->ReadUInt32(&hi)) {
- return false;
- }
- *hash = hi;
- *hash <<= 64;
- *hash += lo;
- return true;
-}
-
-uint128 NullDecrypter::ComputeHash(const StringPiece data1,
- const StringPiece data2) const {
- uint128 correct_hash = QuicUtils::FNV1a_128_Hash_Two(
- data1.data(), data1.length(), data2.data(), data2.length());
- uint128 mask(UINT64_C(0x0), UINT64_C(0xffffffff));
- mask <<= 96;
- correct_hash &= ~mask;
- return correct_hash;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/null_decrypter.h b/chromium/net/quic/crypto/null_decrypter.h
deleted file mode 100644
index ecbfd4b14e6..00000000000
--- a/chromium/net/quic/crypto/null_decrypter.h
+++ /dev/null
@@ -1,55 +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.
-
-#ifndef NET_QUIC_CRYPTO_NULL_DECRYPTER_H_
-#define NET_QUIC_CRYPTO_NULL_DECRYPTER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/quic/crypto/quic_decrypter.h"
-
-namespace net {
-
-class QuicDataReader;
-
-// A NullDecrypter is a QuicDecrypter used before a crypto negotiation
-// has occurred. It does not actually decrypt the payload, but does
-// verify a hash (fnv128) over both the payload and associated data.
-class NET_EXPORT_PRIVATE NullDecrypter : public QuicDecrypter {
- public:
- NullDecrypter();
- ~NullDecrypter() override {}
-
- // QuicDecrypter implementation
- bool SetKey(base::StringPiece key) override;
- bool SetNoncePrefix(base::StringPiece nonce_prefix) override;
- bool SetPreliminaryKey(base::StringPiece key) override;
- bool SetDiversificationNonce(DiversificationNonce nonce) override;
- bool DecryptPacket(QuicPathId path_id,
- QuicPacketNumber packet_number,
- base::StringPiece associated_data,
- base::StringPiece ciphertext,
- char* output,
- size_t* output_length,
- size_t max_output_length) override;
- base::StringPiece GetKey() const override;
- base::StringPiece GetNoncePrefix() const override;
-
- const char* cipher_name() const override;
- uint32_t cipher_id() const override;
-
- private:
- bool ReadHash(QuicDataReader* reader, uint128* hash);
- uint128 ComputeHash(base::StringPiece data1, base::StringPiece data2) const;
-
- DISALLOW_COPY_AND_ASSIGN(NullDecrypter);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_NULL_DECRYPTER_H_
diff --git a/chromium/net/quic/crypto/null_decrypter_test.cc b/chromium/net/quic/crypto/null_decrypter_test.cc
deleted file mode 100644
index 43d980084c6..00000000000
--- a/chromium/net/quic/crypto/null_decrypter_test.cc
+++ /dev/null
@@ -1,67 +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/crypto/null_decrypter.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-
-using base::StringPiece;
-
-namespace net {
-namespace test {
-
-class NullDecrypterTest : public ::testing::TestWithParam<bool> {};
-
-TEST_F(NullDecrypterTest, Decrypt) {
- unsigned char expected[] = {
- // fnv hash
- 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13,
- // payload
- 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!',
- };
- const char* data = reinterpret_cast<const char*>(expected);
- size_t len = arraysize(expected);
- NullDecrypter decrypter;
- char buffer[256];
- size_t length = 0;
- ASSERT_TRUE(decrypter.DecryptPacket(kDefaultPathId, 0, "hello world!",
- StringPiece(data, len), buffer, &length,
- 256));
- EXPECT_LT(0u, length);
- EXPECT_EQ("goodbye!", StringPiece(buffer, length));
-}
-
-TEST_F(NullDecrypterTest, BadHash) {
- unsigned char expected[] = {
- // fnv hash
- 0x46, 0x11, 0xea, 0x5f, 0xcf, 0x1d, 0x66, 0x5b, 0xba, 0xf0, 0xbc, 0xfd,
- // payload
- 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!',
- };
- const char* data = reinterpret_cast<const char*>(expected);
- size_t len = arraysize(expected);
- NullDecrypter decrypter;
- char buffer[256];
- size_t length = 0;
- ASSERT_FALSE(decrypter.DecryptPacket(kDefaultPathId, 0, "hello world!",
- StringPiece(data, len), buffer, &length,
- 256));
-}
-
-TEST_F(NullDecrypterTest, ShortInput) {
- unsigned char expected[] = {
- // fnv hash (truncated)
- 0x46, 0x11, 0xea, 0x5f, 0xcf, 0x1d, 0x66, 0x5b, 0xba, 0xf0, 0xbc,
- };
- const char* data = reinterpret_cast<const char*>(expected);
- size_t len = arraysize(expected);
- NullDecrypter decrypter;
- char buffer[256];
- size_t length = 0;
- ASSERT_FALSE(decrypter.DecryptPacket(kDefaultPathId, 0, "hello world!",
- StringPiece(data, len), buffer, &length,
- 256));
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/null_encrypter.cc b/chromium/net/quic/crypto/null_encrypter.cc
deleted file mode 100644
index 6d7ef809e16..00000000000
--- a/chromium/net/quic/crypto/null_encrypter.cc
+++ /dev/null
@@ -1,78 +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/crypto/null_encrypter.h"
-
-#include "net/quic/quic_data_writer.h"
-#include "net/quic/quic_utils.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-
-const size_t kHashSizeShort = 12; // size of uint128 serialized short
-
-NullEncrypter::NullEncrypter() {}
-
-bool NullEncrypter::SetKey(StringPiece key) {
- return key.empty();
-}
-
-bool NullEncrypter::SetNoncePrefix(StringPiece nonce_prefix) {
- return nonce_prefix.empty();
-}
-
-bool NullEncrypter::EncryptPacket(QuicPathId /*path_id*/,
- QuicPacketNumber /*packet_number*/,
- StringPiece associated_data,
- StringPiece plaintext,
- char* output,
- size_t* output_length,
- size_t max_output_length) {
- const size_t len = plaintext.size() + GetHashLength();
- if (max_output_length < len) {
- return false;
- }
- uint128 hash = QuicUtils::FNV1a_128_Hash_Two(
- associated_data.data(), associated_data.size(), plaintext.data(),
- plaintext.size());
- // TODO(ianswett): memmove required for in place encryption. Placing the
- // hash at the end would allow use of memcpy, doing nothing for in place.
- memmove(output + GetHashLength(), plaintext.data(), plaintext.length());
- QuicUtils::SerializeUint128Short(hash,
- reinterpret_cast<unsigned char*>(output));
- *output_length = len;
- return true;
-}
-
-size_t NullEncrypter::GetKeySize() const {
- return 0;
-}
-
-size_t NullEncrypter::GetNoncePrefixSize() const {
- return 0;
-}
-
-size_t NullEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const {
- return ciphertext_size - GetHashLength();
-}
-
-size_t NullEncrypter::GetCiphertextSize(size_t plaintext_size) const {
- return plaintext_size + GetHashLength();
-}
-
-StringPiece NullEncrypter::GetKey() const {
- return StringPiece();
-}
-
-StringPiece NullEncrypter::GetNoncePrefix() const {
- return StringPiece();
-}
-
-size_t NullEncrypter::GetHashLength() const {
- return kHashSizeShort;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/null_encrypter.h b/chromium/net/quic/crypto/null_encrypter.h
deleted file mode 100644
index 77d6e91e388..00000000000
--- a/chromium/net/quic/crypto/null_encrypter.h
+++ /dev/null
@@ -1,50 +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.
-
-#ifndef NET_QUIC_CRYPTO_NULL_ENCRYPTER_H_
-#define NET_QUIC_CRYPTO_NULL_ENCRYPTER_H_
-
-#include <stddef.h>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/quic/crypto/quic_encrypter.h"
-
-namespace net {
-
-// A NullEncrypter is a QuicEncrypter used before a crypto negotiation
-// has occurred. It does not actually encrypt the payload, but does
-// generate a MAC (fnv128) over both the payload and associated data.
-class NET_EXPORT_PRIVATE NullEncrypter : public QuicEncrypter {
- public:
- NullEncrypter();
- ~NullEncrypter() override {}
-
- // QuicEncrypter implementation
- bool SetKey(base::StringPiece key) override;
- bool SetNoncePrefix(base::StringPiece nonce_prefix) override;
- bool EncryptPacket(QuicPathId path_id,
- QuicPacketNumber packet_number,
- base::StringPiece associated_data,
- base::StringPiece plaintext,
- char* output,
- size_t* output_length,
- size_t max_output_length) override;
- size_t GetKeySize() const override;
- size_t GetNoncePrefixSize() const override;
- size_t GetMaxPlaintextSize(size_t ciphertext_size) const override;
- size_t GetCiphertextSize(size_t plaintext_size) const override;
- base::StringPiece GetKey() const override;
- base::StringPiece GetNoncePrefix() const override;
-
- private:
- size_t GetHashLength() const;
-
- DISALLOW_COPY_AND_ASSIGN(NullEncrypter);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_NULL_ENCRYPTER_H_
diff --git a/chromium/net/quic/crypto/null_encrypter_test.cc b/chromium/net/quic/crypto/null_encrypter_test.cc
deleted file mode 100644
index b6b1e303fa5..00000000000
--- a/chromium/net/quic/crypto/null_encrypter_test.cc
+++ /dev/null
@@ -1,48 +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/crypto/null_encrypter.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-
-using base::StringPiece;
-
-namespace net {
-namespace test {
-
-class NullEncrypterTest : public ::testing::TestWithParam<bool> {};
-
-TEST_F(NullEncrypterTest, Encrypt) {
- unsigned char expected[] = {
- // fnv hash
- 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13,
- // payload
- 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!',
- };
- NullEncrypter encrypter;
- char encrypted[256];
- size_t encrypted_len = 0;
- ASSERT_TRUE(encrypter.EncryptPacket(kDefaultPathId, 0, "hello world!",
- "goodbye!", encrypted, &encrypted_len,
- 256));
- test::CompareCharArraysWithHexError(
- "encrypted data", encrypted, encrypted_len,
- reinterpret_cast<const char*>(expected), arraysize(expected));
-}
-
-TEST_F(NullEncrypterTest, GetMaxPlaintextSize) {
- NullEncrypter encrypter;
- EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1012));
- EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(112));
- EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(22));
-}
-
-TEST_F(NullEncrypterTest, GetCiphertextSize) {
- NullEncrypter encrypter;
- EXPECT_EQ(1012u, encrypter.GetCiphertextSize(1000));
- EXPECT_EQ(112u, encrypter.GetCiphertextSize(100));
- EXPECT_EQ(22u, encrypter.GetCiphertextSize(10));
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/p256_key_exchange.cc b/chromium/net/quic/crypto/p256_key_exchange.cc
deleted file mode 100644
index 47e68ba5705..00000000000
--- a/chromium/net/quic/crypto/p256_key_exchange.cc
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright (c) 2013 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/crypto/p256_key_exchange.h"
-
-#include <openssl/ec.h>
-#include <openssl/ecdh.h>
-#include <openssl/evp.h>
-
-#include "base/logging.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-
-P256KeyExchange::P256KeyExchange(EC_KEY* private_key, const uint8_t* public_key)
- : private_key_(private_key) {
- memcpy(public_key_, public_key, sizeof(public_key_));
-}
-
-P256KeyExchange::~P256KeyExchange() {}
-
-// static
-P256KeyExchange* P256KeyExchange::New(StringPiece key) {
- if (key.empty()) {
- DVLOG(1) << "Private key is empty";
- return nullptr;
- }
-
- const uint8_t* keyp = reinterpret_cast<const uint8_t*>(key.data());
- crypto::ScopedEC_KEY private_key(
- d2i_ECPrivateKey(nullptr, &keyp, key.size()));
- if (!private_key.get() || !EC_KEY_check_key(private_key.get())) {
- DVLOG(1) << "Private key is invalid.";
- return nullptr;
- }
-
- uint8_t public_key[kUncompressedP256PointBytes];
- if (EC_POINT_point2oct(EC_KEY_get0_group(private_key.get()),
- EC_KEY_get0_public_key(private_key.get()),
- POINT_CONVERSION_UNCOMPRESSED, public_key,
- sizeof(public_key), nullptr) != sizeof(public_key)) {
- DVLOG(1) << "Can't get public key.";
- return nullptr;
- }
-
- return new P256KeyExchange(private_key.release(), public_key);
-}
-
-// static
-string P256KeyExchange::NewPrivateKey() {
- crypto::ScopedEC_KEY key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
- if (!key.get() || !EC_KEY_generate_key(key.get())) {
- DVLOG(1) << "Can't generate a new private key.";
- return string();
- }
-
- int key_len = i2d_ECPrivateKey(key.get(), nullptr);
- if (key_len <= 0) {
- DVLOG(1) << "Can't convert private key to string";
- return string();
- }
- std::unique_ptr<uint8_t[]> private_key(new uint8_t[key_len]);
- uint8_t* keyp = private_key.get();
- if (!i2d_ECPrivateKey(key.get(), &keyp)) {
- DVLOG(1) << "Can't convert private key to string.";
- return string();
- }
- return string(reinterpret_cast<char*>(private_key.get()), key_len);
-}
-
-KeyExchange* P256KeyExchange::NewKeyPair(QuicRandom* /*rand*/) const {
- // TODO(agl): avoid the serialisation/deserialisation in this function.
- const string private_value = NewPrivateKey();
- return P256KeyExchange::New(private_value);
-}
-
-bool P256KeyExchange::CalculateSharedKey(StringPiece peer_public_value,
- string* out_result) const {
- if (peer_public_value.size() != kUncompressedP256PointBytes) {
- DVLOG(1) << "Peer public value is invalid";
- return false;
- }
-
- crypto::ScopedEC_POINT point(
- EC_POINT_new(EC_KEY_get0_group(private_key_.get())));
- if (!point ||
- !EC_POINT_oct2point(/* also test if point is on curve */
- EC_KEY_get0_group(private_key_.get()), point.get(),
- reinterpret_cast<const uint8_t*>(
- peer_public_value.data()),
- peer_public_value.size(), nullptr)) {
- DVLOG(1) << "Can't convert peer public value to curve point.";
- return false;
- }
-
- uint8_t result[kP256FieldBytes];
- if (ECDH_compute_key(result, sizeof(result), point.get(), private_key_.get(),
- nullptr) != sizeof(result)) {
- DVLOG(1) << "Can't compute ECDH shared key.";
- return false;
- }
-
- out_result->assign(reinterpret_cast<char*>(result), sizeof(result));
- return true;
-}
-
-StringPiece P256KeyExchange::public_value() const {
- return StringPiece(reinterpret_cast<const char*>(public_key_),
- sizeof(public_key_));
-}
-
-QuicTag P256KeyExchange::tag() const {
- return kP256;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/p256_key_exchange.h b/chromium/net/quic/crypto/p256_key_exchange.h
deleted file mode 100644
index db3e404e683..00000000000
--- a/chromium/net/quic/crypto/p256_key_exchange.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2013 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_CRYPTO_P256_KEY_EXCHANGE_H_
-#define NET_QUIC_CRYPTO_P256_KEY_EXCHANGE_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "crypto/openssl_util.h"
-#include "crypto/scoped_openssl_types.h"
-#include "net/base/net_export.h"
-#include "net/quic/crypto/key_exchange.h"
-
-
-namespace net {
-
-// P256KeyExchange implements a KeyExchange using elliptic-curve
-// Diffie-Hellman on NIST P-256.
-class NET_EXPORT_PRIVATE P256KeyExchange : public KeyExchange {
- public:
- ~P256KeyExchange() override;
-
- // New creates a new key exchange object from a private key. If
- // |private_key| is invalid, nullptr is returned.
- static P256KeyExchange* New(base::StringPiece private_key);
-
- // |NewPrivateKey| returns a private key, suitable for passing to |New|.
- // If |NewPrivateKey| can't generate a private key, it returns an empty
- // string.
- static std::string NewPrivateKey();
-
- // KeyExchange interface.
- KeyExchange* NewKeyPair(QuicRandom* rand) const override;
- bool CalculateSharedKey(base::StringPiece peer_public_value,
- std::string* shared_key) const override;
- base::StringPiece public_value() const override;
- QuicTag tag() const override;
-
- private:
- enum {
- // A P-256 field element consists of 32 bytes.
- kP256FieldBytes = 32,
- // A P-256 point in uncompressed form consists of 0x04 (to denote
- // that the point is uncompressed) followed by two, 32-byte field
- // elements.
- kUncompressedP256PointBytes = 1 + 2 * kP256FieldBytes,
- // The first byte in an uncompressed P-256 point.
- kUncompressedECPointForm = 0x04,
- };
-
- // P256KeyExchange takes ownership of |private_key|, and expects
- // |public_key| consists of |kUncompressedP256PointBytes| bytes.
- P256KeyExchange(EC_KEY* private_key, const uint8_t* public_key);
-
- crypto::ScopedEC_KEY private_key_;
- // The public key stored as an uncompressed P-256 point.
- uint8_t public_key_[kUncompressedP256PointBytes];
-
- DISALLOW_COPY_AND_ASSIGN(P256KeyExchange);
-};
-
-} // namespace net
-#endif // NET_QUIC_CRYPTO_P256_KEY_EXCHANGE_H_
diff --git a/chromium/net/quic/crypto/p256_key_exchange_test.cc b/chromium/net/quic/crypto/p256_key_exchange_test.cc
deleted file mode 100644
index 4972480bb5c..00000000000
--- a/chromium/net/quic/crypto/p256_key_exchange_test.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2013 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/crypto/p256_key_exchange.h"
-
-#include <memory>
-
-#include "base/logging.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::string;
-
-namespace net {
-namespace test {
-
-// SharedKey just tests that the basic key exchange identity holds: that both
-// parties end up with the same key.
-TEST(P256KeyExchange, SharedKey) {
- for (int i = 0; i < 5; i++) {
- string alice_private(P256KeyExchange::NewPrivateKey());
- string bob_private(P256KeyExchange::NewPrivateKey());
-
- ASSERT_FALSE(alice_private.empty());
- ASSERT_FALSE(bob_private.empty());
- ASSERT_NE(alice_private, bob_private);
-
- std::unique_ptr<P256KeyExchange> alice(P256KeyExchange::New(alice_private));
- std::unique_ptr<P256KeyExchange> bob(P256KeyExchange::New(bob_private));
-
- ASSERT_TRUE(alice.get() != nullptr);
- ASSERT_TRUE(bob.get() != nullptr);
-
- const base::StringPiece alice_public(alice->public_value());
- const base::StringPiece bob_public(bob->public_value());
-
- std::string alice_shared, bob_shared;
- ASSERT_TRUE(alice->CalculateSharedKey(bob_public, &alice_shared));
- ASSERT_TRUE(bob->CalculateSharedKey(alice_public, &bob_shared));
- ASSERT_EQ(alice_shared, bob_shared);
- }
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/proof_source.cc b/chromium/net/quic/crypto/proof_source.cc
deleted file mode 100644
index b695725ae7c..00000000000
--- a/chromium/net/quic/crypto/proof_source.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/crypto/proof_source.h"
-
-namespace net {
-
-ProofSource::Chain::Chain(const std::vector<std::string>& certs)
- : certs(certs) {}
-
-ProofSource::Chain::~Chain() {}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/proof_source.h b/chromium/net/quic/crypto/proof_source.h
deleted file mode 100644
index 74b9df3c7e0..00000000000
--- a/chromium/net/quic/crypto/proof_source.h
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2013 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_CRYPTO_PROOF_SOURCE_H_
-#define NET_QUIC_CRYPTO_PROOF_SOURCE_H_
-
-#include <string>
-#include <vector>
-
-#include "base/memory/ref_counted.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-class IPAddress;
-
-// ProofSource is an interface by which a QUIC server can obtain certificate
-// chains and signatures that prove its identity.
-class NET_EXPORT_PRIVATE ProofSource {
- public:
- // Chain is a reference-counted wrapper for a std::vector of std::stringified
- // certificates.
- struct NET_EXPORT_PRIVATE Chain : public base::RefCounted<Chain> {
- explicit Chain(const std::vector<std::string>& certs);
-
- const std::vector<std::string> certs;
-
- private:
- friend class base::RefCounted<Chain>;
-
- virtual ~Chain();
-
- DISALLOW_COPY_AND_ASSIGN(Chain);
- };
-
- virtual ~ProofSource() {}
-
- // GetProof finds a certificate chain for |hostname|, sets |out_certs| to
- // point to it (in leaf-first order), calculates a signature of
- // |server_config| using that chain and puts the result in |out_signature|.
- //
- // The signature uses SHA-256 as the hash function and PSS padding when the
- // key is RSA.
- //
- // The signature uses SHA-256 as the hash function when the key is ECDSA.
- //
- // If |ecdsa_ok| is true, the signature may use an ECDSA key. Otherwise, the
- // signature must use an RSA key.
- //
- // |out_chain| is reference counted to avoid the (assumed) expense of copying
- // out the certificates.
- //
- // The number of certificate chains is expected to be small and fixed thus
- // the ProofSource retains ownership of the contents of |out_certs|. The
- // expectation is that they will be cached forever.
- //
- // For version before QUIC_VERSION_30, the signature values should be cached
- // because |server_config| will be somewhat static. However, since they aren't
- // bounded, the ProofSource may wish to evicit entries from that cache, thus
- // the caller takes ownership of |*out_signature|.
- //
- // For QUIC_VERSION_30 and later, the signature depends on |chlo_hash|
- // which means that the signature can not be cached. The caller takes
- // ownership of |*out_signature|.
- //
- // |hostname| may be empty to signify that a default certificate should be
- // used.
- //
- // |out_leaf_cert_sct| points to the signed timestamp (RFC6962) of the leaf
- // cert.
- // This function may be called concurrently.
- virtual bool GetProof(const IPAddress& server_ip,
- const std::string& hostname,
- const std::string& server_config,
- QuicVersion quic_version,
- base::StringPiece chlo_hash,
- bool ecdsa_ok,
- scoped_refptr<Chain>* out_chain,
- std::string* out_signature,
- std::string* out_leaf_cert_sct) = 0;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_PROOF_SOURCE_H_
diff --git a/chromium/net/quic/crypto/proof_source_chromium.cc b/chromium/net/quic/crypto/proof_source_chromium.cc
deleted file mode 100644
index 3a62346ed34..00000000000
--- a/chromium/net/quic/crypto/proof_source_chromium.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2013 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/crypto/proof_source_chromium.h"
-
-#include <openssl/digest.h>
-#include <openssl/evp.h>
-#include <openssl/rsa.h>
-
-#include "base/strings/string_number_conversions.h"
-#include "crypto/openssl_util.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/ssl/scoped_openssl_types.h"
-
-using std::string;
-using std::vector;
-
-namespace net {
-
-ProofSourceChromium::ProofSourceChromium() {}
-
-ProofSourceChromium::~ProofSourceChromium() {}
-
-bool ProofSourceChromium::Initialize(const base::FilePath& cert_path,
- const base::FilePath& key_path,
- const base::FilePath& sct_path) {
- crypto::EnsureOpenSSLInit();
-
- std::string cert_data;
- if (!base::ReadFileToString(cert_path, &cert_data)) {
- DLOG(FATAL) << "Unable to read certificates.";
- return false;
- }
-
- CertificateList certs_in_file =
- X509Certificate::CreateCertificateListFromBytes(
- cert_data.data(), cert_data.size(), X509Certificate::FORMAT_AUTO);
-
- if (certs_in_file.empty()) {
- DLOG(FATAL) << "No certificates.";
- return false;
- }
-
- 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);
- }
- chain_ = new ProofSource::Chain(certs);
-
- std::string key_data;
- if (!base::ReadFileToString(key_path, &key_data)) {
- DLOG(FATAL) << "Unable to read key.";
- return false;
- }
-
- const uint8_t* p = reinterpret_cast<const uint8_t*>(key_data.data());
- std::vector<uint8_t> input(p, p + key_data.size());
- private_key_ = crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input);
- if (!private_key_) {
- DLOG(FATAL) << "Unable to create private key.";
- return false;
- }
-
- // Loading of the signed certificate timestamp is optional.
- if (sct_path.empty())
- return true;
-
- if (!base::ReadFileToString(sct_path, &signed_certificate_timestamp_)) {
- DLOG(FATAL) << "Unable to read signed certificate timestamp.";
- return false;
- }
-
- return true;
-}
-
-bool ProofSourceChromium::GetProof(const IPAddress& server_ip,
- const string& hostname,
- const string& server_config,
- QuicVersion quic_version,
- base::StringPiece chlo_hash,
- bool ecdsa_ok,
- scoped_refptr<ProofSource::Chain>* out_chain,
- string* out_signature,
- string* out_leaf_cert_sct) {
- DCHECK(private_key_.get()) << " this: " << this;
-
- crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- crypto::ScopedEVP_MD_CTX sign_context(EVP_MD_CTX_create());
- EVP_PKEY_CTX* pkey_ctx;
-
- if (quic_version > QUIC_VERSION_30) {
- uint32_t len = chlo_hash.length();
- if (!EVP_DigestSignInit(sign_context.get(), &pkey_ctx, EVP_sha256(),
- nullptr, private_key_->key()) ||
- !EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) ||
- !EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1) ||
- !EVP_DigestSignUpdate(
- sign_context.get(),
- reinterpret_cast<const uint8_t*>(kProofSignatureLabel),
- sizeof(kProofSignatureLabel)) ||
- !EVP_DigestSignUpdate(sign_context.get(),
- reinterpret_cast<const uint8_t*>(&len),
- sizeof(len)) ||
- !EVP_DigestSignUpdate(
- sign_context.get(),
- reinterpret_cast<const uint8_t*>(chlo_hash.data()), len) ||
- !EVP_DigestSignUpdate(
- sign_context.get(),
- reinterpret_cast<const uint8_t*>(server_config.data()),
- server_config.size())) {
- return false;
- }
- } else if (!EVP_DigestSignInit(sign_context.get(), &pkey_ctx, EVP_sha256(),
- nullptr, private_key_->key()) ||
- !EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) ||
- !EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1) ||
- !EVP_DigestSignUpdate(
- sign_context.get(),
- reinterpret_cast<const uint8_t*>(kProofSignatureLabelOld),
- sizeof(kProofSignatureLabelOld)) ||
- !EVP_DigestSignUpdate(
- sign_context.get(),
- reinterpret_cast<const uint8_t*>(server_config.data()),
- server_config.size())) {
- return false;
- }
-
- // Determine the maximum length of the signature.
- size_t len = 0;
- if (!EVP_DigestSignFinal(sign_context.get(), nullptr, &len)) {
- return false;
- }
- std::vector<uint8_t> signature(len);
- // Sign it.
- if (!EVP_DigestSignFinal(sign_context.get(), signature.data(), &len)) {
- return false;
- }
- signature.resize(len);
- out_signature->assign(reinterpret_cast<const char*>(signature.data()),
- signature.size());
- *out_chain = chain_;
- VLOG(1) << "signature: "
- << base::HexEncode(out_signature->data(), out_signature->size());
- *out_leaf_cert_sct = signed_certificate_timestamp_;
- return true;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/proof_source_chromium.h b/chromium/net/quic/crypto/proof_source_chromium.h
deleted file mode 100644
index f84746ee0cf..00000000000
--- a/chromium/net/quic/crypto/proof_source_chromium.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2013 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_CRYPTO_PROOF_SOURCE_CHROMIUM_H_
-#define NET_QUIC_CRYPTO_PROOF_SOURCE_CHROMIUM_H_
-
-#include <string>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/files/file_util.h"
-#include "base/macros.h"
-#include "crypto/rsa_private_key.h"
-#include "net/base/net_export.h"
-#include "net/cert/x509_certificate.h"
-#include "net/quic/crypto/proof_source.h"
-
-namespace net {
-
-// ProofSourceChromium implements the QUIC ProofSource interface.
-// TODO(rtenneti): implement details of this class.
-class NET_EXPORT_PRIVATE ProofSourceChromium : public ProofSource {
- public:
- ProofSourceChromium();
- ~ProofSourceChromium() override;
-
- // Initializes this object based on the certificate chain in |cert_path|,
- // and the PKCS#8 RSA private key in |key_path|. Signed certificate
- // timestamp may be loaded from |sct_path| if it is non-empty.
- bool Initialize(const base::FilePath& cert_path,
- const base::FilePath& key_path,
- const base::FilePath& sct_path);
-
- // ProofSource interface
- bool GetProof(const IPAddress& server_ip,
- const std::string& hostname,
- const std::string& server_config,
- QuicVersion quic_version,
- base::StringPiece chlo_hash,
- bool ecdsa_ok,
- scoped_refptr<ProofSource::Chain>* out_chain,
- std::string* out_signature,
- std::string* out_leaf_cert_sct) override;
-
- private:
- std::unique_ptr<crypto::RSAPrivateKey> private_key_;
- scoped_refptr<ProofSource::Chain> chain_;
- std::string signed_certificate_timestamp_;
-
- DISALLOW_COPY_AND_ASSIGN(ProofSourceChromium);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_PROOF_SOURCE_CHROMIUM_H_
diff --git a/chromium/net/quic/crypto/proof_test.cc b/chromium/net/quic/crypto/proof_test.cc
deleted file mode 100644
index 697674cfccb..00000000000
--- a/chromium/net/quic/crypto/proof_test.cc
+++ /dev/null
@@ -1,418 +0,0 @@
-// Copyright (c) 2013 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 <memory>
-
-#include "base/files/file_path.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_errors.h"
-#include "net/base/test_completion_callback.h"
-#include "net/cert/cert_status_flags.h"
-#include "net/cert/cert_verify_result.h"
-#include "net/cert/x509_certificate.h"
-#include "net/quic/crypto/proof_source.h"
-#include "net/quic/crypto/proof_verifier.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/test/cert_test_util.h"
-#include "net/test/test_data_directory.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::string;
-using std::vector;
-
-namespace net {
-namespace test {
-namespace {
-
-// TestProofVerifierCallback is a simple callback for a ProofVerifier that
-// signals a TestCompletionCallback when called and stores the results from the
-// ProofVerifier in pointers passed to the constructor.
-class TestProofVerifierCallback : public ProofVerifierCallback {
- public:
- TestProofVerifierCallback(TestCompletionCallback* comp_callback,
- bool* ok,
- string* error_details)
- : comp_callback_(comp_callback), ok_(ok), error_details_(error_details) {}
-
- void Run(bool ok,
- const string& error_details,
- std::unique_ptr<ProofVerifyDetails>* details) override {
- *ok_ = ok;
- *error_details_ = error_details;
-
- comp_callback_->callback().Run(0);
- }
-
- private:
- TestCompletionCallback* const comp_callback_;
- bool* const ok_;
- string* const error_details_;
-};
-
-// RunVerification runs |verifier->VerifyProof| and asserts that the result
-// matches |expected_ok|.
-void RunVerification(ProofVerifier* verifier,
- const string& hostname,
- const uint16_t port,
- const string& server_config,
- QuicVersion quic_version,
- StringPiece chlo_hash,
- const vector<string>& certs,
- const string& proof,
- bool expected_ok) {
- std::unique_ptr<ProofVerifyDetails> details;
- TestCompletionCallback comp_callback;
- bool ok;
- string error_details;
- std::unique_ptr<ProofVerifyContext> verify_context(
- CryptoTestUtils::ProofVerifyContextForTesting());
- TestProofVerifierCallback* callback =
- new TestProofVerifierCallback(&comp_callback, &ok, &error_details);
-
- QuicAsyncStatus status = verifier->VerifyProof(
- hostname, port, server_config, quic_version, chlo_hash, certs, "", proof,
- verify_context.get(), &error_details, &details, callback);
-
- switch (status) {
- case QUIC_FAILURE:
- delete callback;
- ASSERT_FALSE(expected_ok);
- ASSERT_NE("", error_details);
- return;
- case QUIC_SUCCESS:
- delete callback;
- ASSERT_TRUE(expected_ok);
- ASSERT_EQ("", error_details);
- return;
- case QUIC_PENDING:
- comp_callback.WaitForResult();
- ASSERT_EQ(expected_ok, ok);
- break;
- }
-}
-
-// Reads the certificate named "quic_" + |file_name| in the test data directory.
-// The certificate must be PEM encoded. Returns the DER-encoded certificate.
-string LoadTestCert(const string& file_name) {
- base::FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> cert =
- ImportCertFromFile(certs_dir, "quic_" + file_name);
- CHECK_NE(static_cast<X509Certificate*>(nullptr), cert.get());
-
- string der_bytes;
- CHECK(X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_bytes));
- return der_bytes;
-}
-
-class ProofTest : public ::testing::TestWithParam<QuicVersion> {};
-
-} // namespace
-
-INSTANTIATE_TEST_CASE_P(QuicVersion,
- ProofTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
-
-// TODO(rtenneti): Enable testing of ProofVerifier. See http://crbug.com/514468.
-TEST_P(ProofTest, DISABLED_Verify) {
- std::unique_ptr<ProofSource> source(CryptoTestUtils::ProofSourceForTesting());
- std::unique_ptr<ProofVerifier> verifier(
- CryptoTestUtils::ProofVerifierForTesting());
-
- const string server_config = "server config bytes";
- const string hostname = "test.example.com";
- const uint16_t port = 8443;
- const string first_chlo_hash = "first chlo hash bytes";
- const string second_chlo_hash = "first chlo hash bytes";
- const QuicVersion quic_version = GetParam();
-
- scoped_refptr<ProofSource::Chain> chain;
- scoped_refptr<ProofSource::Chain> first_chain;
- string error_details, signature, first_signature, first_cert_sct, cert_sct;
- IPAddress server_ip;
-
- ASSERT_TRUE(source->GetProof(
- server_ip, hostname, server_config, quic_version, first_chlo_hash,
- false /* no ECDSA */, &first_chain, &first_signature, &first_cert_sct));
- ASSERT_TRUE(source->GetProof(server_ip, hostname, server_config, quic_version,
- second_chlo_hash, false /* no ECDSA */, &chain,
- &signature, &cert_sct));
-
- // Check that the proof source is caching correctly:
- ASSERT_EQ(first_chain->certs, chain->certs);
- if (GetParam() < QUIC_VERSION_31) {
- ASSERT_EQ(signature, first_signature);
- } else {
- // QUIC 31 includes the CHLO hash.
- ASSERT_NE(signature, first_signature);
- }
- ASSERT_EQ(first_cert_sct, cert_sct);
-
- RunVerification(verifier.get(), hostname, port, server_config, quic_version,
- first_chlo_hash, chain->certs, signature, true);
-
- RunVerification(verifier.get(), "foo.com", port, server_config, quic_version,
- first_chlo_hash, chain->certs, signature, false);
-
- RunVerification(verifier.get(), server_config.substr(1, string::npos), port,
- server_config, quic_version, first_chlo_hash, chain->certs,
- signature, false);
-
- const string corrupt_signature = "1" + signature;
- RunVerification(verifier.get(), hostname, port, server_config, quic_version,
- first_chlo_hash, chain->certs, corrupt_signature, false);
-
- vector<string> wrong_certs;
- for (size_t i = 1; i < chain->certs.size(); i++) {
- wrong_certs.push_back(chain->certs[i]);
- }
-
- RunVerification(verifier.get(), "foo.com", port, server_config, quic_version,
- first_chlo_hash, wrong_certs, corrupt_signature, false);
-}
-
-TEST_P(ProofTest, UseAfterFree) {
- ProofSource* source = CryptoTestUtils::ProofSourceForTesting();
-
- const string server_config = "server config bytes";
- const string hostname = "test.example.com";
- const string chlo_hash = "proof nonce bytes";
- scoped_refptr<ProofSource::Chain> chain;
- string error_details, signature, cert_sct;
- IPAddress server_ip;
-
- ASSERT_TRUE(source->GetProof(server_ip, hostname, server_config, GetParam(),
- chlo_hash, false /* no ECDSA */, &chain,
- &signature, &cert_sct));
-
- // Make sure we can safely access results after deleting where they came from.
- EXPECT_FALSE(chain->HasOneRef());
- delete source;
- EXPECT_TRUE(chain->HasOneRef());
-
- EXPECT_FALSE(chain->certs.empty());
- for (const string& cert : chain->certs) {
- EXPECT_FALSE(cert.empty());
- }
-}
-
-// A known answer test that allows us to test ProofVerifier without a working
-// ProofSource.
-TEST_P(ProofTest, VerifyRSAKnownAnswerTest) {
- if (GetParam() > QUIC_VERSION_30) {
- return;
- }
- // These sample signatures were generated by running the Proof.Verify test
- // and dumping the bytes of the |signature| output of ProofSource::GetProof().
- static const unsigned char signature_data_0[] = {
- 0x31, 0xd5, 0xfb, 0x40, 0x30, 0x75, 0xd2, 0x7d, 0x61, 0xf9, 0xd7, 0x54,
- 0x30, 0x06, 0xaf, 0x54, 0x0d, 0xb0, 0x0a, 0xda, 0x63, 0xca, 0x7e, 0x9e,
- 0xce, 0xba, 0x10, 0x05, 0x1b, 0xa6, 0x7f, 0xef, 0x2b, 0xa3, 0xff, 0x3c,
- 0xbb, 0x9a, 0xe4, 0xbf, 0xb8, 0x0c, 0xc1, 0xbd, 0xed, 0xc2, 0x90, 0x68,
- 0xeb, 0x45, 0x48, 0xea, 0x3c, 0x95, 0xf8, 0xa2, 0xb9, 0xe7, 0x62, 0x29,
- 0x00, 0xc3, 0x18, 0xb4, 0x16, 0x6f, 0x5e, 0xb0, 0xc1, 0x26, 0xc0, 0x4b,
- 0x84, 0xf5, 0x97, 0xfc, 0x17, 0xf9, 0x1c, 0x43, 0xb8, 0xf2, 0x3f, 0x38,
- 0x32, 0xad, 0x36, 0x52, 0x2c, 0x26, 0x92, 0x7a, 0xea, 0x2c, 0xa2, 0xf4,
- 0x28, 0x2f, 0x19, 0x4d, 0x1f, 0x11, 0x46, 0x82, 0xd0, 0xc4, 0x86, 0x56,
- 0x5c, 0x97, 0x9e, 0xc6, 0x37, 0x8e, 0xaf, 0x9d, 0x69, 0xe9, 0x4f, 0x5a,
- 0x6d, 0x70, 0x75, 0xc7, 0x41, 0x95, 0x68, 0x53, 0x94, 0xca, 0x31, 0x63,
- 0x61, 0x9f, 0xb8, 0x8c, 0x3b, 0x75, 0x36, 0x8b, 0x69, 0xa2, 0x35, 0xc0,
- 0x4b, 0x77, 0x55, 0x08, 0xc2, 0xb4, 0x56, 0xd2, 0x81, 0xce, 0x9e, 0x25,
- 0xdb, 0x50, 0x74, 0xb3, 0x8a, 0xd9, 0x20, 0x42, 0x3f, 0x85, 0x2d, 0xaa,
- 0xfd, 0x66, 0xfa, 0xd6, 0x95, 0x55, 0x6b, 0x63, 0x63, 0x04, 0xf8, 0x6c,
- 0x3e, 0x08, 0x22, 0x39, 0xb9, 0x9a, 0xe0, 0xd7, 0x01, 0xff, 0xeb, 0x8a,
- 0xb9, 0xe2, 0x34, 0xa5, 0xa0, 0x51, 0xe9, 0xbe, 0x15, 0x12, 0xbf, 0xbe,
- 0x64, 0x3d, 0x3f, 0x98, 0xce, 0xc1, 0xa6, 0x33, 0x32, 0xd3, 0x5c, 0xa8,
- 0x39, 0x93, 0xdc, 0x1c, 0xb9, 0xab, 0x3c, 0x80, 0x62, 0xb3, 0x76, 0x21,
- 0xdf, 0x47, 0x1e, 0xa9, 0x0e, 0x5e, 0x8a, 0xbe, 0x66, 0x5b, 0x7c, 0x21,
- 0xfa, 0x78, 0x2d, 0xd1, 0x1d, 0x5c, 0x35, 0x8a, 0x34, 0xb2, 0x1a, 0xc2,
- 0xc4, 0x4b, 0x53, 0x54,
- };
- static const unsigned char signature_data_1[] = {
- 0x01, 0x7b, 0x52, 0x35, 0xe3, 0x51, 0xdd, 0xf1, 0x67, 0x8d, 0x31, 0x5e,
- 0xa3, 0x75, 0x1f, 0x68, 0x6c, 0xdd, 0x41, 0x7a, 0x18, 0x25, 0xe0, 0x12,
- 0x6e, 0x84, 0x46, 0x5e, 0xb2, 0x98, 0xd7, 0x84, 0xe1, 0x62, 0xe0, 0xc1,
- 0xc4, 0xd7, 0x4f, 0x4f, 0x80, 0xc1, 0x92, 0xd6, 0x02, 0xaf, 0xca, 0x28,
- 0x9f, 0xe0, 0xf3, 0x74, 0xd7, 0xf1, 0x44, 0x67, 0x59, 0x27, 0xc8, 0xc2,
- 0x8b, 0xd4, 0xe5, 0x4a, 0x07, 0xfd, 0x00, 0xd6, 0x8a, 0xbf, 0x8b, 0xcd,
- 0x6a, 0xe0, 0x1d, 0xf6, 0x4b, 0x68, 0x0f, 0xcf, 0xb9, 0xd0, 0xa1, 0xbc,
- 0x2e, 0xcf, 0x7c, 0x03, 0x47, 0x11, 0xe4, 0x4c, 0xbc, 0x1b, 0x6b, 0xa5,
- 0x2a, 0x82, 0x86, 0xa4, 0x7f, 0x1d, 0x85, 0x64, 0x21, 0x10, 0xd2, 0xb2,
- 0xa0, 0x31, 0xa2, 0x78, 0xe6, 0xf2, 0xea, 0x96, 0x38, 0x8c, 0x9a, 0xe1,
- 0x01, 0xab, 0x8e, 0x95, 0x66, 0xc8, 0xe5, 0xcc, 0x80, 0xa3, 0xbd, 0x16,
- 0xa7, 0x79, 0x19, 0x39, 0x61, 0x3d, 0xff, 0x37, 0xca, 0x9f, 0x97, 0x05,
- 0xc7, 0xcb, 0xf0, 0xea, 0xaf, 0x64, 0x07, 0xc0, 0xed, 0x2a, 0x98, 0xa4,
- 0xaf, 0x04, 0x6f, 0xf2, 0xc9, 0xb2, 0x73, 0x9a, 0x56, 0x85, 0x43, 0x64,
- 0x5f, 0xaa, 0xb7, 0xff, 0x31, 0x4c, 0x2e, 0x6c, 0x17, 0xcf, 0xe5, 0xbe,
- 0x7f, 0x7e, 0xad, 0xf5, 0x6f, 0x84, 0x50, 0x20, 0x29, 0xb3, 0x57, 0xe7,
- 0xb1, 0xdc, 0x2c, 0x95, 0x48, 0xfe, 0xb0, 0xc1, 0x92, 0xda, 0xc5, 0x58,
- 0x95, 0xb0, 0x1a, 0x3a, 0x05, 0x71, 0x3c, 0x6d, 0x20, 0x01, 0x4c, 0xa9,
- 0xe4, 0x38, 0x08, 0x65, 0xb4, 0xbd, 0x86, 0x76, 0xbd, 0xad, 0x25, 0x06,
- 0x74, 0x0b, 0xca, 0x95, 0x27, 0x0c, 0x13, 0x08, 0x7e, 0x30, 0xcf, 0xf6,
- 0xb5, 0xc1, 0x2a, 0x08, 0xfc, 0x4b, 0xc6, 0xb5, 0x2f, 0x23, 0x27, 0x32,
- 0x89, 0xdb, 0x0e, 0x4a,
- };
- static const unsigned char signature_data_2[] = {
- 0x6d, 0x7d, 0x22, 0x8c, 0x85, 0xc4, 0x8a, 0x80, 0x05, 0xe4, 0x3c, 0xaf,
- 0x10, 0x3b, 0xe3, 0x51, 0xb1, 0x86, 0x52, 0x63, 0xb6, 0x17, 0x33, 0xbd,
- 0x1b, 0x1e, 0xc4, 0x50, 0x10, 0xfc, 0xcc, 0xea, 0x6b, 0x11, 0xeb, 0x6d,
- 0x5e, 0x00, 0xe7, 0xf3, 0x67, 0x99, 0x74, 0x53, 0x12, 0x8f, 0xe4, 0x3e,
- 0x20, 0x17, 0x8e, 0x83, 0xe6, 0xdc, 0x83, 0x91, 0x0e, 0xf3, 0x69, 0x22,
- 0x95, 0x14, 0xdf, 0xc1, 0xda, 0xb5, 0xdb, 0x6a, 0x1a, 0xb4, 0x4f, 0x26,
- 0xd0, 0x32, 0x1d, 0x73, 0x95, 0x1f, 0x39, 0x1d, 0x00, 0xcb, 0xc3, 0x92,
- 0x49, 0x53, 0xcb, 0x5c, 0x36, 0x70, 0x19, 0xd9, 0x64, 0x36, 0xda, 0xfb,
- 0x20, 0xe5, 0x47, 0xd9, 0x08, 0xc6, 0x5a, 0x9e, 0x87, 0x1a, 0xdb, 0x11,
- 0x7b, 0x17, 0xfc, 0x53, 0x7b, 0xc1, 0xa0, 0xc0, 0x33, 0xcf, 0x96, 0xba,
- 0x03, 0x79, 0x8e, 0xc6, 0x05, 0xd2, 0xb7, 0xa2, 0xe2, 0xc1, 0x67, 0xb7,
- 0x6a, 0xeb, 0xb1, 0x40, 0xbb, 0x7d, 0x57, 0xcb, 0xc2, 0x60, 0x9f, 0xf1,
- 0x72, 0xe5, 0xad, 0xce, 0x95, 0x45, 0x7c, 0xbc, 0x75, 0x81, 0x45, 0x19,
- 0xe1, 0xa7, 0x2f, 0x05, 0x52, 0xeb, 0xed, 0xdd, 0x19, 0xd9, 0x1a, 0xc9,
- 0x5a, 0x06, 0x8e, 0x29, 0x54, 0xb5, 0x4f, 0x80, 0xaa, 0x36, 0x36, 0xc0,
- 0xff, 0x64, 0xac, 0xe8, 0x0f, 0x99, 0x35, 0x5e, 0xc6, 0x72, 0x1f, 0x8c,
- 0xc4, 0x2b, 0x7d, 0xc1, 0xfb, 0xf0, 0x12, 0x61, 0xb1, 0x18, 0x65, 0xdd,
- 0xc2, 0x38, 0x92, 0xba, 0x84, 0xf8, 0xc8, 0x5e, 0x17, 0x63, 0xe0, 0x9c,
- 0x2c, 0xe6, 0x70, 0x71, 0xdc, 0xe5, 0xc1, 0xea, 0xb3, 0x9a, 0xb6, 0x91,
- 0xdc, 0xc5, 0x56, 0x84, 0x8a, 0x31, 0x31, 0x23, 0x61, 0x94, 0x7e, 0x01,
- 0x22, 0x49, 0xf3, 0xcb, 0x0e, 0x31, 0x03, 0x04, 0x1b, 0x14, 0x43, 0x7c,
- 0xad, 0x42, 0xe5, 0x55,
- };
-
- std::unique_ptr<ProofVerifier> verifier(
- CryptoTestUtils::RealProofVerifierForTesting());
-
- const string server_config = "server config bytes";
- const string hostname = "test.example.com";
- const uint16_t port = 8443;
- const string chlo_hash = "proof nonce bytes";
- const QuicVersion quic_version = GetParam();
-
- vector<string> certs(2);
- certs[0] = LoadTestCert("test.example.com.crt");
- certs[1] = LoadTestCert("intermediate.crt");
-
- // Signatures are nondeterministic, so we test multiple signatures on the
- // same server_config.
- vector<string> signatures(3);
- signatures[0].assign(reinterpret_cast<const char*>(signature_data_0),
- sizeof(signature_data_0));
- signatures[1].assign(reinterpret_cast<const char*>(signature_data_1),
- sizeof(signature_data_1));
- signatures[2].assign(reinterpret_cast<const char*>(signature_data_2),
- sizeof(signature_data_2));
-
- for (size_t i = 0; i < signatures.size(); i++) {
- const string& signature = signatures[i];
-
- RunVerification(verifier.get(), hostname, port, server_config, quic_version,
- chlo_hash, certs, signature, true);
- RunVerification(verifier.get(), "foo.com", port, server_config,
- quic_version, chlo_hash, certs, signature, false);
- RunVerification(verifier.get(), hostname, port,
- server_config.substr(1, string::npos), quic_version,
- chlo_hash, certs, signature, false);
-
- const string corrupt_signature = "1" + signature;
- RunVerification(verifier.get(), hostname, port, server_config, quic_version,
- chlo_hash, certs, corrupt_signature, false);
-
- vector<string> wrong_certs;
- for (size_t i = 1; i < certs.size(); i++) {
- wrong_certs.push_back(certs[i]);
- }
- RunVerification(verifier.get(), hostname, port, server_config, quic_version,
- chlo_hash, wrong_certs, signature, false);
- }
-}
-
-// A known answer test that allows us to test ProofVerifier without a working
-// ProofSource.
-TEST_P(ProofTest, VerifyECDSAKnownAnswerTest) {
- if (GetParam() > QUIC_VERSION_30) {
- return;
- }
-
- // These sample signatures were generated by running the Proof.Verify test
- // (modified to use ECDSA for signing proofs) and dumping the bytes of the
- // |signature| output of ProofSource::GetProof().
- static const unsigned char signature_data_0[] = {
- 0x30, 0x45, 0x02, 0x21, 0x00, 0x89, 0xc4, 0x7d, 0x08, 0xd1, 0x49, 0x19,
- 0x6c, 0xd1, 0x7c, 0xb9, 0x25, 0xe0, 0xe3, 0xbd, 0x6a, 0x5c, 0xd7, 0xaa,
- 0x0c, 0xdc, 0x4f, 0x8e, 0xeb, 0xde, 0xbf, 0x32, 0xf8, 0xd1, 0x84, 0x95,
- 0x97, 0x02, 0x20, 0x29, 0x3d, 0x49, 0x22, 0x73, 0xed, 0x8b, 0xde, 0x3d,
- 0xc2, 0xa4, 0x20, 0xcc, 0xe7, 0xc8, 0x2a, 0x85, 0x20, 0x9b, 0x5b, 0xda,
- 0xcd, 0x58, 0x23, 0xbe, 0x89, 0x73, 0x31, 0x87, 0x51, 0xd1, 0x01,
- };
- static const unsigned char signature_data_1[] = {
- 0x30, 0x46, 0x02, 0x21, 0x00, 0xec, 0xdf, 0x69, 0xc8, 0x24, 0x59, 0x93,
- 0xda, 0x49, 0xee, 0x37, 0x28, 0xaf, 0xeb, 0x0e, 0x2f, 0x80, 0x17, 0x4b,
- 0x3b, 0xf6, 0x54, 0xcd, 0x3b, 0x86, 0xc5, 0x98, 0x0d, 0xff, 0xc6, 0xb1,
- 0xe7, 0x02, 0x21, 0x00, 0xe1, 0x36, 0x8c, 0xc0, 0xf4, 0x50, 0x5f, 0xba,
- 0xfb, 0xe2, 0xff, 0x1d, 0x5d, 0x64, 0xe4, 0x07, 0xbb, 0x5a, 0x4b, 0x19,
- 0xb6, 0x39, 0x7a, 0xc4, 0x12, 0xc6, 0xe5, 0x42, 0xc8, 0x78, 0x33, 0xcd,
- };
- static const unsigned char signature_data_2[] = {
- 0x30, 0x45, 0x02, 0x20, 0x09, 0x51, 0xe9, 0xde, 0xdb, 0x01, 0xfd, 0xb4,
- 0xd8, 0x20, 0xbb, 0xad, 0x41, 0xe3, 0xaa, 0xe7, 0xa3, 0xc3, 0x32, 0x10,
- 0x9d, 0xfa, 0x37, 0xce, 0x17, 0xd1, 0x29, 0xf9, 0xd4, 0x1d, 0x0d, 0x19,
- 0x02, 0x21, 0x00, 0xc6, 0x20, 0xd4, 0x28, 0xf9, 0x70, 0xb5, 0xb4, 0xff,
- 0x4a, 0x35, 0xba, 0xa0, 0xf2, 0x8e, 0x00, 0xf7, 0xcb, 0x43, 0xaf, 0x2d,
- 0x1f, 0xce, 0x92, 0x05, 0xca, 0x29, 0xfe, 0xd2, 0x8f, 0xd9, 0x31,
- };
-
- std::unique_ptr<ProofVerifier> verifier(
- CryptoTestUtils::RealProofVerifierForTesting());
-
- const string server_config = "server config bytes";
- const string hostname = "test.example.com";
- const uint16_t port = 8443;
- const string chlo_hash = "chlo_hash nonce bytes";
- const QuicVersion quic_version = GetParam();
-
- vector<string> certs(2);
- certs[0] = LoadTestCert("test_ecc.example.com.crt");
- certs[1] = LoadTestCert("intermediate.crt");
-
- // Signatures are nondeterministic, so we test multiple signatures on the
- // same server_config.
- vector<string> signatures(3);
- signatures[0].assign(reinterpret_cast<const char*>(signature_data_0),
- sizeof(signature_data_0));
- signatures[1].assign(reinterpret_cast<const char*>(signature_data_1),
- sizeof(signature_data_1));
- signatures[2].assign(reinterpret_cast<const char*>(signature_data_2),
- sizeof(signature_data_2));
-
- for (size_t i = 0; i < signatures.size(); i++) {
- const string& signature = signatures[i];
-
- RunVerification(verifier.get(), hostname, port, server_config, quic_version,
- chlo_hash, certs, signature, true);
- RunVerification(verifier.get(), "foo.com", port, server_config,
- quic_version, chlo_hash, certs, signature, false);
- RunVerification(verifier.get(), hostname, port,
- server_config.substr(1, string::npos), quic_version,
- chlo_hash, certs, signature, false);
-
- // An ECDSA signature is DER-encoded. Corrupt the last byte so that the
- // signature can still be DER-decoded correctly.
- string corrupt_signature = signature;
- corrupt_signature[corrupt_signature.size() - 1] += 1;
- RunVerification(verifier.get(), hostname, port, server_config, quic_version,
- chlo_hash, certs, corrupt_signature, false);
-
- // Prepending a "1" makes the DER invalid.
- const string bad_der_signature1 = "1" + signature;
- RunVerification(verifier.get(), hostname, port, server_config, quic_version,
- chlo_hash, certs, bad_der_signature1, false);
-
- vector<string> wrong_certs;
- for (size_t i = 1; i < certs.size(); i++) {
- wrong_certs.push_back(certs[i]);
- }
- RunVerification(verifier.get(), hostname, port, server_config, quic_version,
- chlo_hash, wrong_certs, signature, false);
- }
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/proof_verifier.h b/chromium/net/quic/crypto/proof_verifier.h
deleted file mode 100644
index fc520aab9b2..00000000000
--- a/chromium/net/quic/crypto/proof_verifier.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) 2013 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_CRYPTO_PROOF_VERIFIER_H_
-#define NET_QUIC_CRYPTO_PROOF_VERIFIER_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "net/base/net_export.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_types.h"
-
-namespace net {
-
-// ProofVerifyDetails is an abstract class that acts as a container for any
-// implementation specific details that a ProofVerifier wishes to return. These
-// details are saved in the CachedState for the origin in question.
-class NET_EXPORT_PRIVATE ProofVerifyDetails {
- public:
- virtual ~ProofVerifyDetails() {}
-
- // Returns an new ProofVerifyDetails object with the same contents
- // as this one.
- virtual ProofVerifyDetails* Clone() const = 0;
-};
-
-// ProofVerifyContext is an abstract class that acts as a container for any
-// implementation specific context that a ProofVerifier needs.
-class NET_EXPORT_PRIVATE ProofVerifyContext {
- public:
- virtual ~ProofVerifyContext() {}
-};
-
-// ProofVerifierCallback provides a generic mechanism for a ProofVerifier to
-// call back after an asynchronous verification.
-class NET_EXPORT_PRIVATE ProofVerifierCallback {
- public:
- virtual ~ProofVerifierCallback() {}
-
- // Run is called on the original thread to mark the completion of an
- // asynchonous verification. If |ok| is true then the certificate is valid
- // and |error_details| is unused. Otherwise, |error_details| contains a
- // description of the error. |details| contains implementation-specific
- // details of the verification. |Run| may take ownership of |details| by
- // calling |release| on it.
- virtual void Run(bool ok,
- const std::string& error_details,
- std::unique_ptr<ProofVerifyDetails>* details) = 0;
-};
-
-// A ProofVerifier checks the signature on a server config, and the certificate
-// chain that backs the public key.
-class NET_EXPORT_PRIVATE ProofVerifier {
- public:
- virtual ~ProofVerifier() {}
-
- // VerifyProof checks that |signature| is a valid signature of
- // |server_config| by the public key in the leaf certificate of |certs|, and
- // that |certs| is a valid chain for |hostname|. On success, it returns
- // QUIC_SUCCESS. On failure, it returns QUIC_FAILURE and sets |*error_details|
- // to a description of the problem. In either case it may set |*details|,
- // which the caller takes ownership of.
- //
- // |context| specifies an implementation specific struct (which may be nullptr
- // for some implementations) that provides useful information for the
- // verifier, e.g. logging handles.
- //
- // This function may also return QUIC_PENDING, in which case the ProofVerifier
- // will call back, on the original thread, via |callback| when complete.
- // In this case, the ProofVerifier will take ownership of |callback|.
- //
- // The signature uses SHA-256 as the hash function and PSS padding in the
- // case of RSA.
- virtual QuicAsyncStatus VerifyProof(
- const std::string& hostname,
- const uint16_t port,
- const std::string& server_config,
- QuicVersion quic_version,
- base::StringPiece chlo_hash,
- const std::vector<std::string>& certs,
- const std::string& cert_sct,
- const std::string& signature,
- const ProofVerifyContext* context,
- std::string* error_details,
- std::unique_ptr<ProofVerifyDetails>* details,
- ProofVerifierCallback* callback) = 0;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_PROOF_VERIFIER_H_
diff --git a/chromium/net/quic/crypto/proof_verifier_chromium.cc b/chromium/net/quic/crypto/proof_verifier_chromium.cc
deleted file mode 100644
index 096374a7472..00000000000
--- a/chromium/net/quic/crypto/proof_verifier_chromium.cc
+++ /dev/null
@@ -1,519 +0,0 @@
-// Copyright 2013 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/crypto/proof_verifier_chromium.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback_helpers.h"
-#include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
-#include "base/strings/stringprintf.h"
-#include "crypto/signature_verifier.h"
-#include "net/base/host_port_pair.h"
-#include "net/base/net_errors.h"
-#include "net/cert/asn1_util.h"
-#include "net/cert/cert_status_flags.h"
-#include "net/cert/cert_verifier.h"
-#include "net/cert/ct_policy_enforcer.h"
-#include "net/cert/ct_policy_status.h"
-#include "net/cert/ct_verifier.h"
-#include "net/cert/x509_util.h"
-#include "net/http/transport_security_state.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/ssl/ssl_config_service.h"
-
-using base::StringPiece;
-using base::StringPrintf;
-using std::string;
-using std::vector;
-
-namespace net {
-
-ProofVerifyDetailsChromium::ProofVerifyDetailsChromium()
- : pkp_bypassed(false) {}
-
-ProofVerifyDetailsChromium::~ProofVerifyDetailsChromium() {}
-
-ProofVerifyDetailsChromium::ProofVerifyDetailsChromium(
- const ProofVerifyDetailsChromium&) = default;
-
-ProofVerifyDetails* ProofVerifyDetailsChromium::Clone() const {
- ProofVerifyDetailsChromium* other = new ProofVerifyDetailsChromium;
- other->cert_verify_result = cert_verify_result;
- other->ct_verify_result = ct_verify_result;
- return other;
-}
-
-// A Job handles the verification of a single proof. It is owned by the
-// ProofVerifier. If the verification can not complete synchronously, it
-// will notify the ProofVerifier upon completion.
-class ProofVerifierChromium::Job {
- public:
- Job(ProofVerifierChromium* proof_verifier,
- CertVerifier* cert_verifier,
- CTPolicyEnforcer* ct_policy_enforcer,
- TransportSecurityState* transport_security_state,
- CTVerifier* cert_transparency_verifier,
- int cert_verify_flags,
- const BoundNetLog& net_log);
- ~Job();
-
- // Starts the proof verification. If |QUIC_PENDING| is returned, then
- // |callback| will be invoked asynchronously when the verification completes.
- QuicAsyncStatus VerifyProof(
- const std::string& hostname,
- const uint16_t port,
- const std::string& server_config,
- QuicVersion quic_version,
- base::StringPiece chlo_hash,
- const std::vector<std::string>& certs,
- const std::string& cert_sct,
- const std::string& signature,
- std::string* error_details,
- std::unique_ptr<ProofVerifyDetails>* verify_details,
- ProofVerifierCallback* callback);
-
- private:
- enum State {
- STATE_NONE,
- STATE_VERIFY_CERT,
- STATE_VERIFY_CERT_COMPLETE,
- };
-
- int DoLoop(int last_io_result);
- void OnIOComplete(int result);
- int DoVerifyCert(int result);
- int DoVerifyCertComplete(int result);
-
- bool VerifySignature(const std::string& signed_data,
- QuicVersion quic_version,
- StringPiece chlo_hash,
- const std::string& signature,
- const std::string& cert);
-
- // Proof verifier to notify when this jobs completes.
- ProofVerifierChromium* proof_verifier_;
-
- // The underlying verifier used for verifying certificates.
- CertVerifier* verifier_;
- std::unique_ptr<CertVerifier::Request> cert_verifier_request_;
-
- CTPolicyEnforcer* policy_enforcer_;
-
- TransportSecurityState* transport_security_state_;
-
- CTVerifier* cert_transparency_verifier_;
-
- // |hostname| specifies the hostname for which |certs| is a valid chain.
- std::string hostname_;
- // |port| specifies the target port for the connection.
- uint16_t port_;
-
- std::unique_ptr<ProofVerifierCallback> callback_;
- std::unique_ptr<ProofVerifyDetailsChromium> verify_details_;
- std::string error_details_;
-
- // X509Certificate from a chain of DER encoded certificates.
- scoped_refptr<X509Certificate> cert_;
-
- // |cert_verify_flags| is bitwise OR'd of CertVerifier::VerifyFlags and it is
- // passed to CertVerifier::Verify.
- int cert_verify_flags_;
-
- State next_state_;
-
- base::TimeTicks start_time_;
-
- BoundNetLog net_log_;
-
- DISALLOW_COPY_AND_ASSIGN(Job);
-};
-
-ProofVerifierChromium::Job::Job(
- ProofVerifierChromium* proof_verifier,
- CertVerifier* cert_verifier,
- CTPolicyEnforcer* ct_policy_enforcer,
- TransportSecurityState* transport_security_state,
- CTVerifier* cert_transparency_verifier,
- int cert_verify_flags,
- const BoundNetLog& net_log)
- : proof_verifier_(proof_verifier),
- verifier_(cert_verifier),
- policy_enforcer_(ct_policy_enforcer),
- transport_security_state_(transport_security_state),
- cert_transparency_verifier_(cert_transparency_verifier),
- cert_verify_flags_(cert_verify_flags),
- next_state_(STATE_NONE),
- start_time_(base::TimeTicks::Now()),
- net_log_(net_log) {
- CHECK(proof_verifier_);
- CHECK(verifier_);
- CHECK(policy_enforcer_);
- CHECK(transport_security_state_);
- CHECK(cert_transparency_verifier_);
-}
-
-ProofVerifierChromium::Job::~Job() {
- base::TimeTicks end_time = base::TimeTicks::Now();
- UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime",
- end_time - start_time_);
- // |hostname_| will always be canonicalized to lowercase.
- if (hostname_.compare("www.google.com") == 0) {
- UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime.google",
- end_time - start_time_);
- }
-}
-
-QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof(
- const string& hostname,
- const uint16_t port,
- const string& server_config,
- QuicVersion quic_version,
- StringPiece chlo_hash,
- const vector<string>& certs,
- const std::string& cert_sct,
- const string& signature,
- std::string* error_details,
- std::unique_ptr<ProofVerifyDetails>* verify_details,
- ProofVerifierCallback* callback) {
- DCHECK(error_details);
- DCHECK(verify_details);
- DCHECK(callback);
-
- error_details->clear();
-
- if (STATE_NONE != next_state_) {
- *error_details = "Certificate is already set and VerifyProof has begun";
- DLOG(DFATAL) << *error_details;
- return QUIC_FAILURE;
- }
-
- verify_details_.reset(new ProofVerifyDetailsChromium);
-
- if (certs.empty()) {
- *error_details = "Failed to create certificate chain. Certs are empty.";
- DLOG(WARNING) << *error_details;
- verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
- *verify_details = std::move(verify_details_);
- return QUIC_FAILURE;
- }
-
- // Convert certs to X509Certificate.
- vector<StringPiece> cert_pieces(certs.size());
- for (unsigned i = 0; i < certs.size(); i++) {
- cert_pieces[i] = base::StringPiece(certs[i]);
- }
- cert_ = X509Certificate::CreateFromDERCertChain(cert_pieces);
- if (!cert_.get()) {
- *error_details = "Failed to create certificate chain";
- DLOG(WARNING) << *error_details;
- verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
- *verify_details = std::move(verify_details_);
- return QUIC_FAILURE;
- }
-
- if (!cert_sct.empty()) {
- // 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,
- net_log_);
- }
-
- // We call VerifySignature first to avoid copying of server_config and
- // signature.
- if (!VerifySignature(server_config, quic_version, chlo_hash, signature,
- certs[0])) {
- *error_details = "Failed to verify signature of server config";
- DLOG(WARNING) << *error_details;
- verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
- *verify_details = std::move(verify_details_);
- return QUIC_FAILURE;
- }
-
- hostname_ = hostname;
- port_ = port;
-
- next_state_ = STATE_VERIFY_CERT;
- switch (DoLoop(OK)) {
- case OK:
- *verify_details = std::move(verify_details_);
- return QUIC_SUCCESS;
- case ERR_IO_PENDING:
- callback_.reset(callback);
- return QUIC_PENDING;
- default:
- *error_details = error_details_;
- *verify_details = std::move(verify_details_);
- return QUIC_FAILURE;
- }
-}
-
-int ProofVerifierChromium::Job::DoLoop(int last_result) {
- int rv = last_result;
- do {
- State state = next_state_;
- next_state_ = STATE_NONE;
- switch (state) {
- case STATE_VERIFY_CERT:
- DCHECK(rv == OK);
- rv = DoVerifyCert(rv);
- break;
- case STATE_VERIFY_CERT_COMPLETE:
- rv = DoVerifyCertComplete(rv);
- break;
- case STATE_NONE:
- default:
- rv = ERR_UNEXPECTED;
- LOG(DFATAL) << "unexpected state " << state;
- break;
- }
- } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
- return rv;
-}
-
-void ProofVerifierChromium::Job::OnIOComplete(int result) {
- int rv = DoLoop(result);
- if (rv != ERR_IO_PENDING) {
- std::unique_ptr<ProofVerifierCallback> callback(std::move(callback_));
- // Callback expects ProofVerifyDetails not ProofVerifyDetailsChromium.
- std::unique_ptr<ProofVerifyDetails> verify_details(
- std::move(verify_details_));
- callback->Run(rv == OK, error_details_, &verify_details);
- // Will delete |this|.
- proof_verifier_->OnJobComplete(this);
- }
-}
-
-int ProofVerifierChromium::Job::DoVerifyCert(int result) {
- next_state_ = STATE_VERIFY_CERT_COMPLETE;
-
- return verifier_->Verify(
- CertVerifier::RequestParams(cert_, hostname_, cert_verify_flags_,
- std::string(), CertificateList()),
- SSLConfigService::GetCRLSet().get(), &verify_details_->cert_verify_result,
- base::Bind(&ProofVerifierChromium::Job::OnIOComplete,
- base::Unretained(this)),
- &cert_verifier_request_, net_log_);
-}
-
-int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) {
- cert_verifier_request_.reset();
-
- const CertVerifyResult& cert_verify_result =
- verify_details_->cert_verify_result;
- const CertStatus cert_status = cert_verify_result.cert_status;
- verify_details_->ct_verify_result.ct_policies_applied = result == OK;
- verify_details_->ct_verify_result.ev_policy_compliance =
- ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY;
-
- // If the connection was good, check HPKP and CT status simultaneously,
- // but prefer to treat the HPKP error as more serious, if there was one.
- if ((result == OK ||
- (IsCertificateError(result) && IsCertStatusMinorError(cert_status)))) {
- if ((cert_verify_result.cert_status & CERT_STATUS_IS_EV)) {
- ct::EVPolicyCompliance ev_policy_compliance =
- policy_enforcer_->DoesConformToCTEVPolicy(
- cert_verify_result.verified_cert.get(),
- SSLConfigService::GetEVCertsWhitelist().get(),
- verify_details_->ct_verify_result.verified_scts, net_log_);
- verify_details_->ct_verify_result.ev_policy_compliance =
- ev_policy_compliance;
- if (ev_policy_compliance !=
- ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY &&
- ev_policy_compliance !=
- ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST &&
- ev_policy_compliance !=
- ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS) {
- verify_details_->cert_verify_result.cert_status |=
- CERT_STATUS_CT_COMPLIANCE_FAILED;
- verify_details_->cert_verify_result.cert_status &= ~CERT_STATUS_IS_EV;
- }
- }
-
- verify_details_->ct_verify_result.cert_policy_compliance =
- policy_enforcer_->DoesConformToCertPolicy(
- cert_verify_result.verified_cert.get(),
- verify_details_->ct_verify_result.verified_scts, net_log_);
-
- int ct_result = OK;
- if (verify_details_->ct_verify_result.cert_policy_compliance !=
- ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS &&
- transport_security_state_->ShouldRequireCT(
- hostname_, cert_verify_result.verified_cert.get(),
- cert_verify_result.public_key_hashes)) {
- verify_details_->cert_verify_result.cert_status |=
- CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED;
- ct_result = ERR_CERTIFICATE_TRANSPARENCY_REQUIRED;
- }
-
- TransportSecurityState::PKPStatus pin_validity =
- transport_security_state_->CheckPublicKeyPins(
- HostPortPair(hostname_, port_),
- cert_verify_result.is_issued_by_known_root,
- cert_verify_result.public_key_hashes, cert_.get(),
- cert_verify_result.verified_cert.get(),
- TransportSecurityState::ENABLE_PIN_REPORTS,
- &verify_details_->pinning_failure_log);
- switch (pin_validity) {
- case TransportSecurityState::PKPStatus::VIOLATED:
- result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
- verify_details_->cert_verify_result.cert_status |=
- CERT_STATUS_PINNED_KEY_MISSING;
- break;
- case TransportSecurityState::PKPStatus::BYPASSED:
- verify_details_->pkp_bypassed = true;
- // Fall through.
- case TransportSecurityState::PKPStatus::OK:
- // Do nothing.
- break;
- }
- if (result != ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN && ct_result != OK)
- result = ct_result;
- }
-
- if (result != OK) {
- std::string error_string = ErrorToString(result);
- error_details_ = StringPrintf("Failed to verify certificate chain: %s",
- error_string.c_str());
- DLOG(WARNING) << error_details_;
- }
-
- // Exit DoLoop and return the result to the caller to VerifyProof.
- DCHECK_EQ(STATE_NONE, next_state_);
- return result;
-}
-
-bool ProofVerifierChromium::Job::VerifySignature(const string& signed_data,
- QuicVersion quic_version,
- StringPiece chlo_hash,
- const string& signature,
- const string& cert) {
- StringPiece spki;
- if (!asn1::ExtractSPKIFromDERCert(cert, &spki)) {
- DLOG(WARNING) << "ExtractSPKIFromDERCert failed";
- return false;
- }
-
- crypto::SignatureVerifier verifier;
-
- size_t size_bits;
- X509Certificate::PublicKeyType type;
- X509Certificate::GetPublicKeyInfo(cert_->os_cert_handle(), &size_bits, &type);
- if (type == X509Certificate::kPublicKeyTypeRSA) {
- crypto::SignatureVerifier::HashAlgorithm hash_alg =
- crypto::SignatureVerifier::SHA256;
- crypto::SignatureVerifier::HashAlgorithm mask_hash_alg = hash_alg;
- unsigned int hash_len = 32; // 32 is the length of a SHA-256 hash.
-
- bool ok = verifier.VerifyInitRSAPSS(
- hash_alg, mask_hash_alg, hash_len,
- reinterpret_cast<const uint8_t*>(signature.data()), signature.size(),
- reinterpret_cast<const uint8_t*>(spki.data()), spki.size());
- if (!ok) {
- DLOG(WARNING) << "VerifyInitRSAPSS failed";
- return false;
- }
- } else if (type == X509Certificate::kPublicKeyTypeECDSA) {
- if (!verifier.VerifyInit(crypto::SignatureVerifier::ECDSA_SHA256,
- reinterpret_cast<const uint8_t*>(signature.data()),
- signature.size(),
- reinterpret_cast<const uint8_t*>(spki.data()),
- spki.size())) {
- DLOG(WARNING) << "VerifyInit failed";
- return false;
- }
- } else {
- LOG(ERROR) << "Unsupported public key type " << type;
- return false;
- }
-
- if (quic_version <= QUIC_VERSION_30) {
- verifier.VerifyUpdate(
- reinterpret_cast<const uint8_t*>(kProofSignatureLabelOld),
- sizeof(kProofSignatureLabelOld));
- } else {
- verifier.VerifyUpdate(
- reinterpret_cast<const uint8_t*>(kProofSignatureLabel),
- sizeof(kProofSignatureLabel));
- uint32_t len = chlo_hash.length();
- verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(&len), sizeof(len));
- verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(chlo_hash.data()),
- len);
- }
-
- verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(signed_data.data()),
- signed_data.size());
-
- if (!verifier.VerifyFinal()) {
- DLOG(WARNING) << "VerifyFinal failed";
- return false;
- }
-
- DVLOG(1) << "VerifyFinal success";
- return true;
-}
-
-ProofVerifierChromium::ProofVerifierChromium(
- CertVerifier* cert_verifier,
- CTPolicyEnforcer* ct_policy_enforcer,
- TransportSecurityState* transport_security_state,
- CTVerifier* cert_transparency_verifier)
- : cert_verifier_(cert_verifier),
- ct_policy_enforcer_(ct_policy_enforcer),
- transport_security_state_(transport_security_state),
- cert_transparency_verifier_(cert_transparency_verifier) {
- DCHECK(cert_verifier_);
- DCHECK(ct_policy_enforcer_);
- DCHECK(transport_security_state_);
- DCHECK(cert_transparency_verifier_);
-}
-
-ProofVerifierChromium::~ProofVerifierChromium() {
- STLDeleteElements(&active_jobs_);
-}
-
-QuicAsyncStatus ProofVerifierChromium::VerifyProof(
- const std::string& hostname,
- const uint16_t port,
- const std::string& server_config,
- QuicVersion quic_version,
- base::StringPiece chlo_hash,
- const std::vector<std::string>& certs,
- const std::string& cert_sct,
- const std::string& signature,
- const ProofVerifyContext* verify_context,
- std::string* error_details,
- std::unique_ptr<ProofVerifyDetails>* verify_details,
- ProofVerifierCallback* callback) {
- if (!verify_context) {
- *error_details = "Missing context";
- return QUIC_FAILURE;
- }
- const ProofVerifyContextChromium* chromium_context =
- reinterpret_cast<const ProofVerifyContextChromium*>(verify_context);
- std::unique_ptr<Job> job(
- new Job(this, cert_verifier_, ct_policy_enforcer_,
- transport_security_state_, cert_transparency_verifier_,
- chromium_context->cert_verify_flags, chromium_context->net_log));
- QuicAsyncStatus status = job->VerifyProof(
- hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct,
- signature, error_details, verify_details, callback);
- if (status == QUIC_PENDING) {
- active_jobs_.insert(job.release());
- }
- return status;
-}
-
-void ProofVerifierChromium::OnJobComplete(Job* job) {
- active_jobs_.erase(job);
- delete job;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/proof_verifier_chromium.h b/chromium/net/quic/crypto/proof_verifier_chromium.h
deleted file mode 100644
index fe84992e866..00000000000
--- a/chromium/net/quic/crypto/proof_verifier_chromium.h
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2013 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_CRYPTO_PROOF_VERIFIER_CHROMIUM_H_
-#define NET_QUIC_CRYPTO_PROOF_VERIFIER_CHROMIUM_H_
-
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/cert/cert_verify_result.h"
-#include "net/cert/ct_verify_result.h"
-#include "net/cert/x509_certificate.h"
-#include "net/log/net_log.h"
-#include "net/quic/crypto/proof_verifier.h"
-
-namespace net {
-
-class CTPolicyEnforcer;
-class CertVerifier;
-class CTVerifier;
-class TransportSecurityState;
-
-// ProofVerifyDetailsChromium is the implementation-specific information that a
-// ProofVerifierChromium returns about a certificate verification.
-class NET_EXPORT_PRIVATE ProofVerifyDetailsChromium
- : public ProofVerifyDetails {
- public:
- ProofVerifyDetailsChromium();
- ProofVerifyDetailsChromium(const ProofVerifyDetailsChromium&);
- ~ProofVerifyDetailsChromium() override;
-
- // ProofVerifyDetails implementation
- ProofVerifyDetails* Clone() const override;
-
- CertVerifyResult cert_verify_result;
- ct::CTVerifyResult ct_verify_result;
-
- // pinning_failure_log contains a message produced by
- // TransportSecurityState::PKPState::CheckPublicKeyPins in the event of a
- // pinning failure. It is a (somewhat) human-readable string.
- std::string pinning_failure_log;
-
- // True if PKP was bypassed due to a local trust anchor.
- bool pkp_bypassed;
-};
-
-// ProofVerifyContextChromium is the implementation-specific information that a
-// ProofVerifierChromium needs in order to log correctly.
-struct ProofVerifyContextChromium : public ProofVerifyContext {
- public:
- ProofVerifyContextChromium(int cert_verify_flags, const BoundNetLog& net_log)
- : cert_verify_flags(cert_verify_flags), net_log(net_log) {}
-
- int cert_verify_flags;
- BoundNetLog net_log;
-};
-
-// ProofVerifierChromium implements the QUIC ProofVerifier interface. It is
-// capable of handling multiple simultaneous requests.
-class NET_EXPORT_PRIVATE ProofVerifierChromium : public ProofVerifier {
- public:
- ProofVerifierChromium(CertVerifier* cert_verifier,
- CTPolicyEnforcer* ct_policy_enforcer,
- TransportSecurityState* transport_security_state,
- CTVerifier* cert_transparency_verifier);
- ~ProofVerifierChromium() override;
-
- // ProofVerifier interface
- QuicAsyncStatus VerifyProof(
- const std::string& hostname,
- const uint16_t port,
- const std::string& server_config,
- QuicVersion quic_version,
- base::StringPiece chlo_hash,
- const std::vector<std::string>& certs,
- const std::string& cert_sct,
- const std::string& signature,
- const ProofVerifyContext* verify_context,
- std::string* error_details,
- std::unique_ptr<ProofVerifyDetails>* verify_details,
- ProofVerifierCallback* callback) override;
-
- private:
- class Job;
- typedef std::set<Job*> JobSet;
-
- void OnJobComplete(Job* job);
-
- // Set owning pointers to active jobs.
- JobSet active_jobs_;
-
- // Underlying verifier used to verify certificates.
- CertVerifier* const cert_verifier_;
- CTPolicyEnforcer* const ct_policy_enforcer_;
-
- TransportSecurityState* const transport_security_state_;
- CTVerifier* const cert_transparency_verifier_;
-
- DISALLOW_COPY_AND_ASSIGN(ProofVerifierChromium);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_PROOF_VERIFIER_CHROMIUM_H_
diff --git a/chromium/net/quic/crypto/proof_verifier_chromium_test.cc b/chromium/net/quic/crypto/proof_verifier_chromium_test.cc
deleted file mode 100644
index ba881c6285b..00000000000
--- a/chromium/net/quic/crypto/proof_verifier_chromium_test.cc
+++ /dev/null
@@ -1,591 +0,0 @@
-// Copyright 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.
-
-#include "net/quic/crypto/proof_verifier_chromium.h"
-
-#include "base/memory/ref_counted.h"
-#include "net/base/net_errors.h"
-#include "net/cert/cert_status_flags.h"
-#include "net/cert/cert_verifier.h"
-#include "net/cert/ct_log_verifier.h"
-#include "net/cert/ct_policy_enforcer.h"
-#include "net/cert/ct_policy_status.h"
-#include "net/cert/ct_serialization.h"
-#include "net/cert/mock_cert_verifier.h"
-#include "net/cert/multi_log_ct_verifier.h"
-#include "net/http/transport_security_state.h"
-#include "net/quic/crypto/proof_verifier.h"
-#include "net/test/cert_test_util.h"
-#include "net/test/ct_test_util.h"
-#include "net/test/test_data_directory.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::_;
-using ::testing::Return;
-
-namespace net {
-namespace test {
-
-namespace {
-
-// CertVerifier that will fail the test if it is ever called.
-class FailsTestCertVerifier : public CertVerifier {
- public:
- FailsTestCertVerifier() {}
- ~FailsTestCertVerifier() override {}
-
- // CertVerifier implementation
- int Verify(const RequestParams& params,
- CRLSet* crl_set,
- CertVerifyResult* verify_result,
- const CompletionCallback& callback,
- std::unique_ptr<Request>* out_req,
- const BoundNetLog& net_log) override {
- ADD_FAILURE() << "CertVerifier::Verify() should not be called";
- return ERR_FAILED;
- }
-};
-
-// CTPolicyEnforcer that will fail the test if it is ever called.
-class FailsTestCTPolicyEnforcer : public CTPolicyEnforcer {
- public:
- FailsTestCTPolicyEnforcer() {}
- ~FailsTestCTPolicyEnforcer() override {}
-
- ct::EVPolicyCompliance DoesConformToCTEVPolicy(
- X509Certificate* cert,
- const ct::EVCertsWhitelist* ev_whitelist,
- const ct::SCTList& verified_scts,
- const BoundNetLog& net_log) override {
- ADD_FAILURE() << "CTPolicyEnforcer::DoesConformToCTEVPolicy() should "
- << "not be called";
- return ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY;
- }
-};
-
-// A mock CTPolicyEnforcer that returns a custom verification result.
-class MockCTPolicyEnforcer : public CTPolicyEnforcer {
- public:
- MOCK_METHOD3(DoesConformToCertPolicy,
- ct::CertPolicyCompliance(X509Certificate* cert,
- const ct::SCTList&,
- const BoundNetLog&));
- MOCK_METHOD4(DoesConformToCTEVPolicy,
- ct::EVPolicyCompliance(X509Certificate* cert,
- const ct::EVCertsWhitelist*,
- const ct::SCTList&,
- const BoundNetLog&));
-};
-
-class MockRequireCTDelegate : public TransportSecurityState::RequireCTDelegate {
- public:
- MOCK_METHOD1(IsCTRequiredForHost,
- CTRequirementLevel(const std::string& host));
-};
-
-class DummyProofVerifierCallback : public ProofVerifierCallback {
- public:
- DummyProofVerifierCallback() {}
- ~DummyProofVerifierCallback() override {}
-
- void Run(bool ok,
- const std::string& error_details,
- std::unique_ptr<ProofVerifyDetails>* details) override {
- // Do nothing
- }
-};
-
-const char kTestHostname[] = "test.example.com";
-const uint16_t kTestPort = 8443;
-const char kTestConfig[] = "server config bytes";
-const char kLogDescription[] = "somelog";
-
-} // namespace
-
-class ProofVerifierChromiumTest : public ::testing::Test {
- public:
- ProofVerifierChromiumTest()
- : verify_context_(new ProofVerifyContextChromium(0 /*cert_verify_flags*/,
- BoundNetLog())) {}
-
- void SetUp() override {
- EXPECT_CALL(ct_policy_enforcer_, DoesConformToCertPolicy(_, _, _))
- .WillRepeatedly(
- Return(ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS));
- EXPECT_CALL(ct_policy_enforcer_, DoesConformToCTEVPolicy(_, _, _, _))
- .WillRepeatedly(
- Return(ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY));
-
- scoped_refptr<const CTLogVerifier> log(CTLogVerifier::Create(
- ct::GetTestPublicKey(), kLogDescription, "https://test.example.com"));
- ASSERT_TRUE(log);
- log_verifiers_.push_back(log);
-
- ct_verifier_.reset(new MultiLogCTVerifier());
- ct_verifier_->AddLogs(log_verifiers_);
-
- ASSERT_NO_FATAL_FAILURE(GetTestCertificates(&certs_));
- }
-
- scoped_refptr<X509Certificate> GetTestServerCertificate() {
- static const char kTestCert[] = "quic_test.example.com.crt";
- return ImportCertFromFile(GetTestCertsDirectory(), kTestCert);
- }
-
- void GetTestCertificates(std::vector<std::string>* certs) {
- 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);
- }
-
- std::string GetTestSignature() {
- // Sample known answer test from ProofTest.VerifyRSAKnownAnswerTest.
- // Generated by dumping the bytes of the |signature| output of
- // ProofSource::GetProof().
- static const unsigned char kTestSignature[] = {
- 0x31, 0xd5, 0xfb, 0x40, 0x30, 0x75, 0xd2, 0x7d, 0x61, 0xf9, 0xd7, 0x54,
- 0x30, 0x06, 0xaf, 0x54, 0x0d, 0xb0, 0x0a, 0xda, 0x63, 0xca, 0x7e, 0x9e,
- 0xce, 0xba, 0x10, 0x05, 0x1b, 0xa6, 0x7f, 0xef, 0x2b, 0xa3, 0xff, 0x3c,
- 0xbb, 0x9a, 0xe4, 0xbf, 0xb8, 0x0c, 0xc1, 0xbd, 0xed, 0xc2, 0x90, 0x68,
- 0xeb, 0x45, 0x48, 0xea, 0x3c, 0x95, 0xf8, 0xa2, 0xb9, 0xe7, 0x62, 0x29,
- 0x00, 0xc3, 0x18, 0xb4, 0x16, 0x6f, 0x5e, 0xb0, 0xc1, 0x26, 0xc0, 0x4b,
- 0x84, 0xf5, 0x97, 0xfc, 0x17, 0xf9, 0x1c, 0x43, 0xb8, 0xf2, 0x3f, 0x38,
- 0x32, 0xad, 0x36, 0x52, 0x2c, 0x26, 0x92, 0x7a, 0xea, 0x2c, 0xa2, 0xf4,
- 0x28, 0x2f, 0x19, 0x4d, 0x1f, 0x11, 0x46, 0x82, 0xd0, 0xc4, 0x86, 0x56,
- 0x5c, 0x97, 0x9e, 0xc6, 0x37, 0x8e, 0xaf, 0x9d, 0x69, 0xe9, 0x4f, 0x5a,
- 0x6d, 0x70, 0x75, 0xc7, 0x41, 0x95, 0x68, 0x53, 0x94, 0xca, 0x31, 0x63,
- 0x61, 0x9f, 0xb8, 0x8c, 0x3b, 0x75, 0x36, 0x8b, 0x69, 0xa2, 0x35, 0xc0,
- 0x4b, 0x77, 0x55, 0x08, 0xc2, 0xb4, 0x56, 0xd2, 0x81, 0xce, 0x9e, 0x25,
- 0xdb, 0x50, 0x74, 0xb3, 0x8a, 0xd9, 0x20, 0x42, 0x3f, 0x85, 0x2d, 0xaa,
- 0xfd, 0x66, 0xfa, 0xd6, 0x95, 0x55, 0x6b, 0x63, 0x63, 0x04, 0xf8, 0x6c,
- 0x3e, 0x08, 0x22, 0x39, 0xb9, 0x9a, 0xe0, 0xd7, 0x01, 0xff, 0xeb, 0x8a,
- 0xb9, 0xe2, 0x34, 0xa5, 0xa0, 0x51, 0xe9, 0xbe, 0x15, 0x12, 0xbf, 0xbe,
- 0x64, 0x3d, 0x3f, 0x98, 0xce, 0xc1, 0xa6, 0x33, 0x32, 0xd3, 0x5c, 0xa8,
- 0x39, 0x93, 0xdc, 0x1c, 0xb9, 0xab, 0x3c, 0x80, 0x62, 0xb3, 0x76, 0x21,
- 0xdf, 0x47, 0x1e, 0xa9, 0x0e, 0x5e, 0x8a, 0xbe, 0x66, 0x5b, 0x7c, 0x21,
- 0xfa, 0x78, 0x2d, 0xd1, 0x1d, 0x5c, 0x35, 0x8a, 0x34, 0xb2, 0x1a, 0xc2,
- 0xc4, 0x4b, 0x53, 0x54,
- };
- return std::string(reinterpret_cast<const char*>(kTestSignature),
- sizeof(kTestSignature));
- }
-
- void GetSCTTestCertificates(std::vector<std::string>* certs) {
- std::string der_test_cert(ct::GetDerEncodedX509Cert());
- scoped_refptr<X509Certificate> test_cert = X509Certificate::CreateFromBytes(
- 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);
- }
-
- void CheckSCT(bool sct_expected_ok) {
- ProofVerifyDetailsChromium* proof_details =
- reinterpret_cast<ProofVerifyDetailsChromium*>(details_.get());
- const ct::CTVerifyResult& ct_verify_result =
- proof_details->ct_verify_result;
- if (sct_expected_ok) {
- ASSERT_TRUE(ct::CheckForSingleVerifiedSCTInResult(ct_verify_result,
- kLogDescription));
- ASSERT_TRUE(ct::CheckForSCTOrigin(
- ct_verify_result,
- ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION));
- } else {
- EXPECT_EQ(1U, ct_verify_result.unknown_logs_scts.size());
- }
- }
-
- protected:
- TransportSecurityState transport_security_state_;
- MockCTPolicyEnforcer ct_policy_enforcer_;
-
- std::unique_ptr<MultiLogCTVerifier> ct_verifier_;
- std::vector<scoped_refptr<const CTLogVerifier>> log_verifiers_;
- std::unique_ptr<ProofVerifyContext> verify_context_;
- std::unique_ptr<ProofVerifyDetails> details_;
- std::string error_details_;
- std::vector<std::string> certs_;
-};
-
-// Tests that the ProofVerifier fails verification if certificate
-// verification fails.
-TEST_F(ProofVerifierChromiumTest, FailsIfCertFails) {
- MockCertVerifier dummy_verifier;
- 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_25, "", certs_, "",
- GetTestSignature(), verify_context_.get(), &error_details_, &details_,
- callback.get());
- ASSERT_EQ(QUIC_FAILURE, status);
-}
-
-// Valid SCT, but invalid signature.
-TEST_F(ProofVerifierChromiumTest, ValidSCTList) {
- // Use different certificates for SCT tests.
- ASSERT_NO_FATAL_FAILURE(GetSCTTestCertificates(&certs_));
-
- MockCertVerifier cert_verifier;
- ProofVerifierChromium proof_verifier(&cert_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_25, "", certs_,
- ct::GetSCTListForTesting(), "", verify_context_.get(), &error_details_,
- &details_, callback.get());
- ASSERT_EQ(QUIC_FAILURE, status);
- CheckSCT(/*sct_expected_ok=*/true);
-}
-
-// Invalid SCT and signature.
-TEST_F(ProofVerifierChromiumTest, InvalidSCTList) {
- // Use different certificates for SCT tests.
- ASSERT_NO_FATAL_FAILURE(GetSCTTestCertificates(&certs_));
-
- MockCertVerifier cert_verifier;
- ProofVerifierChromium proof_verifier(&cert_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_25, "", certs_,
- ct::GetSCTListWithInvalidSCT(), "", verify_context_.get(),
- &error_details_, &details_, callback.get());
- ASSERT_EQ(QUIC_FAILURE, status);
- CheckSCT(/*sct_expected_ok=*/false);
-}
-
-// Tests that the ProofVerifier doesn't verify certificates if the config
-// signature fails.
-TEST_F(ProofVerifierChromiumTest, FailsIfSignatureFails) {
- FailsTestCertVerifier cert_verifier;
- ProofVerifierChromium proof_verifier(&cert_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_25, "", certs_, "",
- kTestConfig, verify_context_.get(), &error_details_, &details_,
- callback.get());
- ASSERT_EQ(QUIC_FAILURE, status);
-}
-
-// Tests that the certificate policy enforcer is consulted for EV
-// and the certificate is allowed to be EV.
-TEST_F(ProofVerifierChromiumTest, PreservesEVIfAllowed) {
- scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate();
- ASSERT_TRUE(test_cert);
-
- CertVerifyResult dummy_result;
- dummy_result.verified_cert = test_cert;
- dummy_result.cert_status = CERT_STATUS_IS_EV;
-
- MockCertVerifier dummy_verifier;
- dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, OK);
-
- EXPECT_CALL(ct_policy_enforcer_, DoesConformToCTEVPolicy(_, _, _, _))
- .WillRepeatedly(
- Return(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS));
-
- 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_25, "", certs_, "",
- GetTestSignature(), verify_context_.get(), &error_details_, &details_,
- callback.get());
- ASSERT_EQ(QUIC_SUCCESS, status);
-
- ASSERT_TRUE(details_.get());
- ProofVerifyDetailsChromium* verify_details =
- static_cast<ProofVerifyDetailsChromium*>(details_.get());
- EXPECT_EQ(dummy_result.cert_status,
- verify_details->cert_verify_result.cert_status);
-}
-
-// Tests that the certificate policy enforcer is consulted for EV
-// and the certificate is not allowed to be EV.
-TEST_F(ProofVerifierChromiumTest, StripsEVIfNotAllowed) {
- scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate();
- ASSERT_TRUE(test_cert);
-
- CertVerifyResult dummy_result;
- dummy_result.verified_cert = test_cert;
- dummy_result.cert_status = CERT_STATUS_IS_EV;
-
- MockCertVerifier dummy_verifier;
- dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, OK);
-
- EXPECT_CALL(ct_policy_enforcer_, DoesConformToCTEVPolicy(_, _, _, _))
- .WillRepeatedly(
- Return(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS));
-
- 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_25, "", certs_, "",
- GetTestSignature(), verify_context_.get(), &error_details_, &details_,
- callback.get());
- ASSERT_EQ(QUIC_SUCCESS, status);
-
- ASSERT_TRUE(details_.get());
- ProofVerifyDetailsChromium* verify_details =
- static_cast<ProofVerifyDetailsChromium*>(details_.get());
- EXPECT_EQ(CERT_STATUS_CT_COMPLIANCE_FAILED,
- verify_details->cert_verify_result.cert_status &
- (CERT_STATUS_CT_COMPLIANCE_FAILED | CERT_STATUS_IS_EV));
-}
-
-// Tests that the certificate policy enforcer is not consulted if
-// the certificate is not EV.
-TEST_F(ProofVerifierChromiumTest, IgnoresPolicyEnforcerIfNotEV) {
- scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate();
- ASSERT_TRUE(test_cert);
-
- CertVerifyResult dummy_result;
- dummy_result.verified_cert = test_cert;
- dummy_result.cert_status = 0;
-
- MockCertVerifier dummy_verifier;
- dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, OK);
-
- FailsTestCTPolicyEnforcer policy_enforcer;
-
- ProofVerifierChromium proof_verifier(&dummy_verifier, &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_25, "", certs_, "",
- GetTestSignature(), verify_context_.get(), &error_details_, &details_,
- callback.get());
- ASSERT_EQ(QUIC_SUCCESS, status);
-
- ASSERT_TRUE(details_.get());
- ProofVerifyDetailsChromium* verify_details =
- static_cast<ProofVerifyDetailsChromium*>(details_.get());
- EXPECT_EQ(0u, verify_details->cert_verify_result.cert_status);
-}
-
-HashValueVector MakeHashValueVector(uint8_t tag) {
- HashValue hash(HASH_VALUE_SHA256);
- memset(hash.data(), tag, hash.size());
- HashValueVector hashes;
- hashes.push_back(hash);
- return hashes;
-}
-
-// Test that PKP is enforced for certificates that chain up to known roots.
-TEST_F(ProofVerifierChromiumTest, PKPEnforced) {
- scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate();
- ASSERT_TRUE(test_cert);
-
- CertVerifyResult dummy_result;
- dummy_result.verified_cert = test_cert;
- dummy_result.is_issued_by_known_root = true;
- dummy_result.public_key_hashes = MakeHashValueVector(0x01);
- dummy_result.cert_status = 0;
-
- MockCertVerifier dummy_verifier;
- dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, OK);
-
- HashValueVector pin_hashes = MakeHashValueVector(0x02);
- transport_security_state_.AddHPKP(
- kTestHostname, base::Time::Now() + base::TimeDelta::FromSeconds(10000),
- true, pin_hashes, GURL());
-
- 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_25, "", certs_, "",
- GetTestSignature(), verify_context_.get(), &error_details_, &details_,
- callback.get());
- ASSERT_EQ(QUIC_FAILURE, status);
-
- ASSERT_TRUE(details_.get());
- ProofVerifyDetailsChromium* verify_details =
- static_cast<ProofVerifyDetailsChromium*>(details_.get());
- EXPECT_TRUE(verify_details->cert_verify_result.cert_status &
- CERT_STATUS_PINNED_KEY_MISSING);
- EXPECT_FALSE(verify_details->pkp_bypassed);
- EXPECT_NE("", verify_details->pinning_failure_log);
-}
-
-// Test |pkp_bypassed| is set when PKP is bypassed due to a local
-// trust anchor
-TEST_F(ProofVerifierChromiumTest, PKPBypassFlagSet) {
- scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate();
- ASSERT_TRUE(test_cert);
-
- CertVerifyResult dummy_result;
- dummy_result.verified_cert = test_cert;
- dummy_result.is_issued_by_known_root = false;
- dummy_result.public_key_hashes = MakeHashValueVector(0x01);
- dummy_result.cert_status = 0;
-
- MockCertVerifier dummy_verifier;
- dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, OK);
-
- HashValueVector expected_hashes = MakeHashValueVector(0x02);
- transport_security_state_.AddHPKP(
- kTestHostname, base::Time::Now() + base::TimeDelta::FromSeconds(10000),
- true, expected_hashes, GURL());
-
- 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_25, "", certs_, "",
- GetTestSignature(), verify_context_.get(), &error_details_, &details_,
- callback.get());
- ASSERT_EQ(QUIC_SUCCESS, status);
-
- ASSERT_TRUE(details_.get());
- ProofVerifyDetailsChromium* verify_details =
- static_cast<ProofVerifyDetailsChromium*>(details_.get());
- EXPECT_TRUE(verify_details->pkp_bypassed);
-}
-
-// Test that when CT is required (in this case, by the delegate), the
-// absence of CT information is a socket error.
-TEST_F(ProofVerifierChromiumTest, CTIsRequired) {
- scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate();
- ASSERT_TRUE(test_cert);
-
- CertVerifyResult dummy_result;
- dummy_result.verified_cert = test_cert;
- dummy_result.is_issued_by_known_root = true;
- dummy_result.public_key_hashes = MakeHashValueVector(0x01);
- dummy_result.cert_status = 0;
-
- MockCertVerifier dummy_verifier;
- dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, OK);
-
- // Set up CT.
- MockRequireCTDelegate require_ct_delegate;
- transport_security_state_.SetRequireCTDelegate(&require_ct_delegate);
- EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_))
- .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate::
- CTRequirementLevel::NOT_REQUIRED));
- EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(kTestHostname))
- .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate::
- CTRequirementLevel::REQUIRED));
- EXPECT_CALL(ct_policy_enforcer_, DoesConformToCertPolicy(_, _, _))
- .WillRepeatedly(
- Return(ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS));
-
- 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_25, "", certs_, "",
- GetTestSignature(), verify_context_.get(), &error_details_, &details_,
- callback.get());
- ASSERT_EQ(QUIC_FAILURE, status);
-
- ASSERT_TRUE(details_.get());
- ProofVerifyDetailsChromium* verify_details =
- static_cast<ProofVerifyDetailsChromium*>(details_.get());
- EXPECT_TRUE(verify_details->cert_verify_result.cert_status &
- CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED);
-}
-
-// Test that CT is considered even when HPKP fails.
-TEST_F(ProofVerifierChromiumTest, PKPAndCTBothTested) {
- scoped_refptr<X509Certificate> test_cert = GetTestServerCertificate();
- ASSERT_TRUE(test_cert);
-
- CertVerifyResult dummy_result;
- dummy_result.verified_cert = test_cert;
- dummy_result.is_issued_by_known_root = true;
- dummy_result.public_key_hashes = MakeHashValueVector(0x01);
- dummy_result.cert_status = 0;
-
- MockCertVerifier dummy_verifier;
- dummy_verifier.AddResultForCert(test_cert.get(), dummy_result, OK);
-
- // Set up HPKP.
- HashValueVector pin_hashes = MakeHashValueVector(0x02);
- transport_security_state_.AddHPKP(
- kTestHostname, base::Time::Now() + base::TimeDelta::FromSeconds(10000),
- true, pin_hashes, GURL());
-
- // Set up CT.
- MockRequireCTDelegate require_ct_delegate;
- transport_security_state_.SetRequireCTDelegate(&require_ct_delegate);
- EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_))
- .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate::
- CTRequirementLevel::NOT_REQUIRED));
- EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(kTestHostname))
- .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate::
- CTRequirementLevel::REQUIRED));
- EXPECT_CALL(ct_policy_enforcer_, DoesConformToCertPolicy(_, _, _))
- .WillRepeatedly(
- Return(ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS));
-
- 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_25, "", certs_, "",
- GetTestSignature(), verify_context_.get(), &error_details_, &details_,
- callback.get());
- ASSERT_EQ(QUIC_FAILURE, status);
-
- ASSERT_TRUE(details_.get());
- ProofVerifyDetailsChromium* verify_details =
- static_cast<ProofVerifyDetailsChromium*>(details_.get());
- EXPECT_TRUE(verify_details->cert_verify_result.cert_status &
- CERT_STATUS_PINNED_KEY_MISSING);
- EXPECT_TRUE(verify_details->cert_verify_result.cert_status &
- CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED);
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/properties_based_quic_server_info.cc b/chromium/net/quic/crypto/properties_based_quic_server_info.cc
deleted file mode 100644
index 5522f6c0606..00000000000
--- a/chromium/net/quic/crypto/properties_based_quic_server_info.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 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.
-
-#include "net/quic/crypto/properties_based_quic_server_info.h"
-
-#include "base/base64.h"
-#include "net/base/net_errors.h"
-#include "net/http/http_server_properties.h"
-
-using std::string;
-
-namespace net {
-
-PropertiesBasedQuicServerInfo::PropertiesBasedQuicServerInfo(
- const QuicServerId& server_id,
- HttpServerProperties* http_server_properties)
- : QuicServerInfo(server_id),
- http_server_properties_(http_server_properties) {
- DCHECK(http_server_properties_);
-}
-
-PropertiesBasedQuicServerInfo::~PropertiesBasedQuicServerInfo() {}
-
-void PropertiesBasedQuicServerInfo::Start() {}
-
-int PropertiesBasedQuicServerInfo::WaitForDataReady(
- const CompletionCallback& callback) {
- const string* data = http_server_properties_->GetQuicServerInfo(server_id_);
- string decoded;
- if (!data || !base::Base64Decode(*data, &decoded) || !Parse(decoded)) {
- return ERR_FAILED;
- }
- return OK;
-}
-
-void PropertiesBasedQuicServerInfo::ResetWaitForDataReadyCallback() {}
-
-void PropertiesBasedQuicServerInfo::CancelWaitForDataReadyCallback() {}
-
-bool PropertiesBasedQuicServerInfo::IsDataReady() {
- return true;
-}
-
-bool PropertiesBasedQuicServerInfo::IsReadyToPersist() {
- return true;
-}
-
-void PropertiesBasedQuicServerInfo::Persist() {
- string encoded;
- base::Base64Encode(Serialize(), &encoded);
- http_server_properties_->SetQuicServerInfo(server_id_, encoded);
-}
-
-void PropertiesBasedQuicServerInfo::OnExternalCacheHit() {}
-
-PropertiesBasedQuicServerInfoFactory::PropertiesBasedQuicServerInfoFactory(
- HttpServerProperties* http_server_properties)
- : http_server_properties_(http_server_properties) {}
-
-PropertiesBasedQuicServerInfoFactory::~PropertiesBasedQuicServerInfoFactory() {}
-
-QuicServerInfo* PropertiesBasedQuicServerInfoFactory::GetForServer(
- const QuicServerId& server_id) {
- return new PropertiesBasedQuicServerInfo(server_id, http_server_properties_);
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/properties_based_quic_server_info.h b/chromium/net/quic/crypto/properties_based_quic_server_info.h
deleted file mode 100644
index c4cea6981fa..00000000000
--- a/chromium/net/quic/crypto/properties_based_quic_server_info.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 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.
-
-#ifndef NET_QUIC_CRYPTO_PROPERTIES_BASED_QUIC_SERVER_INFO_H_
-#define NET_QUIC_CRYPTO_PROPERTIES_BASED_QUIC_SERVER_INFO_H_
-
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "net/base/completion_callback.h"
-#include "net/base/net_export.h"
-#include "net/quic/crypto/quic_server_info.h"
-
-namespace net {
-
-class HttpServerProperties;
-
-// PropertiesBasedQuicServerInfo fetches information about a QUIC server from
-// HttpServerProperties. Since the information is defined to be non-sensitive,
-// it's ok for us to keep it on disk.
-class NET_EXPORT_PRIVATE PropertiesBasedQuicServerInfo : public QuicServerInfo {
- public:
- PropertiesBasedQuicServerInfo(const QuicServerId& server_id,
- HttpServerProperties* http_server_properties);
- ~PropertiesBasedQuicServerInfo() override;
-
- // QuicServerInfo implementation.
- void Start() override;
- int WaitForDataReady(const CompletionCallback& callback) override;
- void ResetWaitForDataReadyCallback() override;
- void CancelWaitForDataReadyCallback() override;
- bool IsDataReady() override;
- bool IsReadyToPersist() override;
- void Persist() override;
- void OnExternalCacheHit() override;
-
- private:
- HttpServerProperties* http_server_properties_;
-
- DISALLOW_COPY_AND_ASSIGN(PropertiesBasedQuicServerInfo);
-};
-
-class NET_EXPORT_PRIVATE PropertiesBasedQuicServerInfoFactory
- : public QuicServerInfoFactory {
- public:
- explicit PropertiesBasedQuicServerInfoFactory(
- HttpServerProperties* http_server_properties);
- ~PropertiesBasedQuicServerInfoFactory() override;
-
- QuicServerInfo* GetForServer(const QuicServerId& server_id) override;
-
- private:
- HttpServerProperties* http_server_properties_;
-
- DISALLOW_COPY_AND_ASSIGN(PropertiesBasedQuicServerInfoFactory);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_PROPERTIES_BASED_QUIC_SERVER_INFO_H_
diff --git a/chromium/net/quic/crypto/properties_based_quic_server_info_test.cc b/chromium/net/quic/crypto/properties_based_quic_server_info_test.cc
deleted file mode 100644
index 497e88ce4f4..00000000000
--- a/chromium/net/quic/crypto/properties_based_quic_server_info_test.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 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.
-
-#include "net/quic/crypto/properties_based_quic_server_info.h"
-
-#include <string>
-
-#include "net/base/net_errors.h"
-#include "net/http/http_server_properties_impl.h"
-#include "net/quic/quic_server_id.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-namespace {
-const char kServerConfigA[] = "server_config_a";
-const char kSourceAddressTokenA[] = "source_address_token_a";
-const char kCertSCTA[] = "cert_sct_a";
-const char kChloHashA[] = "chlo_hash_a";
-const char kServerConfigSigA[] = "server_config_sig_a";
-const char kCertA[] = "cert_a";
-const char kCertB[] = "cert_b";
-} // namespace
-
-class PropertiesBasedQuicServerInfoTest : public ::testing::Test {
- protected:
- PropertiesBasedQuicServerInfoTest()
- : server_id_("www.google.com", 443, PRIVACY_MODE_DISABLED),
- server_info_(server_id_, &http_server_properties_) {}
-
- // Initialize |server_info_| object and persist it.
- void InitializeAndPersist() {
- server_info_.Start();
- EXPECT_TRUE(server_info_.IsDataReady());
- QuicServerInfo::State* state = server_info_.mutable_state();
- EXPECT_TRUE(state->certs.empty());
-
- state->server_config = kServerConfigA;
- state->source_address_token = kSourceAddressTokenA;
- state->server_config_sig = kServerConfigSigA;
- state->cert_sct = kCertSCTA;
- state->chlo_hash = kChloHashA;
- state->certs.push_back(kCertA);
- EXPECT_TRUE(server_info_.IsReadyToPersist());
- server_info_.Persist();
- EXPECT_TRUE(server_info_.IsReadyToPersist());
- EXPECT_TRUE(server_info_.IsDataReady());
- server_info_.OnExternalCacheHit();
- }
-
- // Verify the data that is persisted in InitializeAndPersist().
- void VerifyInitialData(const QuicServerInfo::State& state) {
- EXPECT_EQ(kServerConfigA, state.server_config);
- EXPECT_EQ(kSourceAddressTokenA, state.source_address_token);
- EXPECT_EQ(kCertSCTA, state.cert_sct);
- EXPECT_EQ(kChloHashA, state.chlo_hash);
- EXPECT_EQ(kServerConfigSigA, state.server_config_sig);
- EXPECT_EQ(kCertA, state.certs[0]);
- }
-
- HttpServerPropertiesImpl http_server_properties_;
- QuicServerId server_id_;
- PropertiesBasedQuicServerInfo server_info_;
- CompletionCallback callback_;
-};
-
-// Test persisting, reading and verifying and then updating and verifing.
-TEST_F(PropertiesBasedQuicServerInfoTest, Update) {
- InitializeAndPersist();
-
- // Read the persisted data and verify we have read the data correctly.
- PropertiesBasedQuicServerInfo server_info1(server_id_,
- &http_server_properties_);
- server_info1.Start();
- EXPECT_EQ(OK, server_info1.WaitForDataReady(callback_)); // Read the data.
- EXPECT_TRUE(server_info1.IsDataReady());
-
- // Verify the data.
- const QuicServerInfo::State& state1 = server_info1.state();
- EXPECT_EQ(1U, state1.certs.size());
- VerifyInitialData(state1);
-
- // Update the data, by adding another cert.
- QuicServerInfo::State* state2 = server_info1.mutable_state();
- state2->certs.push_back(kCertB);
- EXPECT_TRUE(server_info_.IsReadyToPersist());
- server_info1.Persist();
-
- // Read the persisted data and verify we have read the data correctly.
- PropertiesBasedQuicServerInfo server_info2(server_id_,
- &http_server_properties_);
- server_info2.Start();
- EXPECT_EQ(OK, server_info2.WaitForDataReady(callback_)); // Read the data.
- EXPECT_TRUE(server_info1.IsDataReady());
-
- // Verify updated data.
- const QuicServerInfo::State& state3 = server_info2.state();
- VerifyInitialData(state3);
- EXPECT_EQ(2U, state3.certs.size());
- EXPECT_EQ(kCertB, state3.certs[1]);
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/quic_compressed_certs_cache.cc b/chromium/net/quic/crypto/quic_compressed_certs_cache.cc
deleted file mode 100644
index 92d66d2cad4..00000000000
--- a/chromium/net/quic/crypto/quic_compressed_certs_cache.cc
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/crypto/quic_compressed_certs_cache.h"
-
-using std::string;
-
-namespace net {
-
-namespace {
-
-// Inline helper function for extending a 64-bit |seed| in-place with a 64-bit
-// |value|. Based on Boost's hash_combine function.
-inline void hash_combine(uint64_t* seed, const uint64_t& val) {
- (*seed) ^= val + 0x9e3779b9 + ((*seed) << 6) + ((*seed) >> 2);
-}
-
-} // namespace
-
-QuicCompressedCertsCache::UncompressedCerts::UncompressedCerts() {}
-
-QuicCompressedCertsCache::UncompressedCerts::UncompressedCerts(
- const scoped_refptr<ProofSource::Chain>& chain,
- const string* client_common_set_hashes,
- const string* client_cached_cert_hashes)
- : chain(chain),
- client_common_set_hashes(client_common_set_hashes),
- client_cached_cert_hashes(client_cached_cert_hashes) {}
-
-QuicCompressedCertsCache::UncompressedCerts::~UncompressedCerts() {}
-
-QuicCompressedCertsCache::CachedCerts::CachedCerts() {}
-
-QuicCompressedCertsCache::CachedCerts::CachedCerts(
- const UncompressedCerts& uncompressed_certs,
- const string& compressed_cert)
- : chain_(uncompressed_certs.chain),
- client_common_set_hashes_(*uncompressed_certs.client_common_set_hashes),
- client_cached_cert_hashes_(*uncompressed_certs.client_cached_cert_hashes),
- compressed_cert_(compressed_cert) {}
-
-QuicCompressedCertsCache::CachedCerts::CachedCerts(const CachedCerts& other) =
- default;
-
-QuicCompressedCertsCache::CachedCerts::~CachedCerts() {}
-
-bool QuicCompressedCertsCache::CachedCerts::MatchesUncompressedCerts(
- const UncompressedCerts& uncompressed_certs) const {
- return (client_common_set_hashes_ ==
- *uncompressed_certs.client_common_set_hashes &&
- client_cached_cert_hashes_ ==
- *uncompressed_certs.client_cached_cert_hashes &&
- chain_ == uncompressed_certs.chain);
-}
-
-const string* QuicCompressedCertsCache::CachedCerts::compressed_cert() const {
- return &compressed_cert_;
-}
-
-QuicCompressedCertsCache::QuicCompressedCertsCache(int64_t max_num_certs)
- : certs_cache_(max_num_certs) {}
-
-QuicCompressedCertsCache::~QuicCompressedCertsCache() {
- // Underlying cache must be cleared before destruction.
- certs_cache_.Clear();
-}
-
-const string* QuicCompressedCertsCache::GetCompressedCert(
- const scoped_refptr<ProofSource::Chain>& chain,
- const string& client_common_set_hashes,
- const string& client_cached_cert_hashes) {
- UncompressedCerts uncompressed_certs(chain, &client_common_set_hashes,
- &client_cached_cert_hashes);
-
- uint64_t key = ComputeUncompressedCertsHash(uncompressed_certs);
-
- auto cached_it = certs_cache_.Get(key);
-
- if (cached_it != certs_cache_.end()) {
- const CachedCerts& cached_value = cached_it->second;
- if (cached_value.MatchesUncompressedCerts(uncompressed_certs)) {
- return cached_value.compressed_cert();
- }
- }
- return nullptr;
-}
-
-void QuicCompressedCertsCache::Insert(
- const scoped_refptr<ProofSource::Chain>& chain,
- const string& client_common_set_hashes,
- const string& client_cached_cert_hashes,
- const string& compressed_cert) {
- UncompressedCerts uncompressed_certs(chain, &client_common_set_hashes,
- &client_cached_cert_hashes);
-
- uint64_t key = ComputeUncompressedCertsHash(uncompressed_certs);
-
- // Insert one unit to the cache.
- certs_cache_.Put(key, CachedCerts(uncompressed_certs, compressed_cert));
-}
-
-size_t QuicCompressedCertsCache::MaxSize() {
- return certs_cache_.max_size();
-}
-
-size_t QuicCompressedCertsCache::Size() {
- return certs_cache_.size();
-}
-
-uint64_t QuicCompressedCertsCache::ComputeUncompressedCertsHash(
- const UncompressedCerts& uncompressed_certs) {
- uint64_t hash =
- std::hash<string>()(*uncompressed_certs.client_common_set_hashes);
- uint64_t h =
- std::hash<string>()(*uncompressed_certs.client_cached_cert_hashes);
- hash_combine(&hash, h);
-
- hash_combine(&hash,
- reinterpret_cast<uint64_t>(uncompressed_certs.chain.get()));
- return hash;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/quic_compressed_certs_cache.h b/chromium/net/quic/crypto/quic_compressed_certs_cache.h
deleted file mode 100644
index fe120f6bff6..00000000000
--- a/chromium/net/quic/crypto/quic_compressed_certs_cache.h
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_CRYPTO_QUIC_COMPRESSED_CERTS_CACHE_H_
-#define NET_QUIC_CRYPTO_QUIC_COMPRESSED_CERTS_CACHE_H_
-
-#include <string>
-#include <vector>
-
-#include "base/containers/mru_cache.h"
-#include "base/memory/ref_counted.h"
-#include "net/quic/crypto/proof_source.h"
-
-namespace net {
-
-// QuicCompressedCertsCache is a cache to track most recently compressed certs.
-class NET_EXPORT_PRIVATE QuicCompressedCertsCache {
- public:
- explicit QuicCompressedCertsCache(int64_t max_num_certs);
- ~QuicCompressedCertsCache();
-
- // Returns the pointer to the cached compressed cert if
- // |chain, client_common_set_hashes, client_cached_cert_hashes| hits cache.
- // Otherwise, return nullptr.
- // Returned pointer might become invalid on the next call to Insert().
- const std::string* GetCompressedCert(
- const scoped_refptr<ProofSource::Chain>& chain,
- const std::string& client_common_set_hashes,
- const std::string& client_cached_cert_hashes);
-
- // Inserts the specified
- // |chain, client_common_set_hashes,
- // client_cached_cert_hashes, compressed_cert| tuple to the cache.
- // If the insertion causes the cache to become overfull, entries will
- // be deleted in an LRU order to make room.
- void Insert(const scoped_refptr<ProofSource::Chain>& chain,
- const std::string& client_common_set_hashes,
- const std::string& client_cached_cert_hashes,
- const std::string& compressed_cert);
-
- // Returns max number of cache entries the cache can carry.
- size_t MaxSize();
-
- // Returns current number of cache entries in the cache.
- size_t Size();
-
- // Default size of the QuicCompressedCertsCache per server side investigation.
- static const size_t kQuicCompressedCertsCacheSize = 225;
-
- private:
- // A wrapper of the tuple:
- // |chain, client_common_set_hashes, client_cached_cert_hashes|
- // to identify uncompressed representation of certs.
- struct UncompressedCerts {
- UncompressedCerts();
- UncompressedCerts(const scoped_refptr<ProofSource::Chain>& chain,
- const std::string* client_common_set_hashes,
- const std::string* client_cached_cert_hashes);
- ~UncompressedCerts();
-
- const scoped_refptr<ProofSource::Chain> chain;
- const std::string* client_common_set_hashes;
- const std::string* client_cached_cert_hashes;
- };
-
- // Certs stored by QuicCompressedCertsCache where uncompressed certs data is
- // used to identify the uncompressed representation of certs and
- // |compressed_cert| is the cached compressed representation.
- class CachedCerts {
- public:
- CachedCerts();
- CachedCerts(const UncompressedCerts& uncompressed_certs,
- const std::string& compressed_cert);
- CachedCerts(const CachedCerts& other);
-
- ~CachedCerts();
-
- // Returns true if the |uncompressed_certs| matches uncompressed
- // representation of this cert.
- bool MatchesUncompressedCerts(
- const UncompressedCerts& uncompressed_certs) const;
-
- const std::string* compressed_cert() const;
-
- private:
- // Uncompressed certs data.
- scoped_refptr<ProofSource::Chain> chain_;
- const std::string client_common_set_hashes_;
- const std::string client_cached_cert_hashes_;
-
- // Cached compressed representation derived from uncompressed certs.
- const std::string compressed_cert_;
- };
-
- // Computes a uint64_t hash for |uncompressed_certs|.
- uint64_t ComputeUncompressedCertsHash(
- const UncompressedCerts& uncompressed_certs);
-
- // Key is a unit64_t hash for UncompressedCerts. Stored associated value is
- // CachedCerts which has both original uncompressed certs data and the
- // compressed representation of the certs.
- base::MRUCache<uint64_t, CachedCerts> certs_cache_;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_QUIC_COMPRESSED_CERTS_CACHE_H_
diff --git a/chromium/net/quic/crypto/quic_compressed_certs_cache_test.cc b/chromium/net/quic/crypto/quic_compressed_certs_cache_test.cc
deleted file mode 100644
index d444c49d4ca..00000000000
--- a/chromium/net/quic/crypto/quic_compressed_certs_cache_test.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/crypto/quic_compressed_certs_cache.h"
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/strings/string_number_conversions.h"
-#include "net/quic/crypto/cert_compressor.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::string;
-using std::vector;
-
-namespace net {
-
-namespace test {
-
-namespace {
-
-class QuicCompressedCertsCacheTest : public testing::Test {
- public:
- QuicCompressedCertsCacheTest()
- : certs_cache_(QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) {}
-
- protected:
- QuicCompressedCertsCache certs_cache_;
-};
-
-TEST_F(QuicCompressedCertsCacheTest, CacheHit) {
- vector<string> certs = {"leaf cert", "intermediate cert", "root cert"};
- scoped_refptr<ProofSource::Chain> chain(new ProofSource::Chain(certs));
- string common_certs = "common certs";
- string cached_certs = "cached certs";
- string compressed = "compressed cert";
-
- certs_cache_.Insert(chain, common_certs, cached_certs, compressed);
-
- const string* cached_value =
- certs_cache_.GetCompressedCert(chain, common_certs, cached_certs);
- ASSERT_NE(nullptr, cached_value);
- EXPECT_EQ(*cached_value, compressed);
-}
-
-TEST_F(QuicCompressedCertsCacheTest, CacheMiss) {
- vector<string> certs = {"leaf cert", "intermediate cert", "root cert"};
- scoped_refptr<ProofSource::Chain> chain(new ProofSource::Chain(certs));
- string common_certs = "common certs";
- string cached_certs = "cached certs";
- string compressed = "compressed cert";
-
- certs_cache_.Insert(chain, common_certs, cached_certs, compressed);
-
- EXPECT_EQ(nullptr, certs_cache_.GetCompressedCert(
- chain, "mismatched common certs", cached_certs));
- EXPECT_EQ(nullptr, certs_cache_.GetCompressedCert(chain, common_certs,
- "mismatched cached certs"));
- scoped_refptr<ProofSource::Chain> chain2(new ProofSource::Chain(certs));
- EXPECT_EQ(nullptr,
- certs_cache_.GetCompressedCert(chain2, common_certs, cached_certs));
-}
-
-TEST_F(QuicCompressedCertsCacheTest, CacheMissDueToEviction) {
- // Test cache returns a miss when a queried uncompressed certs was cached but
- // then evicted.
- vector<string> certs = {"leaf cert", "intermediate cert", "root cert"};
- scoped_refptr<ProofSource::Chain> chain(new ProofSource::Chain(certs));
-
- string common_certs = "common certs";
- string cached_certs = "cached certs";
- string compressed = "compressed cert";
- certs_cache_.Insert(chain, common_certs, cached_certs, compressed);
-
- // Insert another kQuicCompressedCertsCacheSize certs to evict the first
- // cached cert.
- for (unsigned int i = 0;
- i < QuicCompressedCertsCache::kQuicCompressedCertsCacheSize; i++) {
- EXPECT_EQ(certs_cache_.Size(), i + 1);
- certs_cache_.Insert(chain, base::IntToString(i), "", base::IntToString(i));
- }
- EXPECT_EQ(certs_cache_.MaxSize(), certs_cache_.Size());
-
- EXPECT_EQ(nullptr,
- certs_cache_.GetCompressedCert(chain, common_certs, cached_certs));
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/quic_crypto_client_config.cc b/chromium/net/quic/crypto/quic_crypto_client_config.cc
deleted file mode 100644
index 53c60c2e805..00000000000
--- a/chromium/net/quic/crypto/quic_crypto_client_config.cc
+++ /dev/null
@@ -1,996 +0,0 @@
-// Copyright 2013 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/crypto/quic_crypto_client_config.h"
-
-#include <memory>
-
-#include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-#include "net/quic/crypto/cert_compressor.h"
-#include "net/quic/crypto/chacha20_poly1305_encrypter.h"
-#include "net/quic/crypto/channel_id.h"
-#include "net/quic/crypto/common_cert_set.h"
-#include "net/quic/crypto/crypto_framer.h"
-#include "net/quic/crypto/crypto_utils.h"
-#include "net/quic/crypto/curve25519_key_exchange.h"
-#include "net/quic/crypto/key_exchange.h"
-#include "net/quic/crypto/p256_key_exchange.h"
-#include "net/quic/crypto/proof_verifier.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-
-using base::StringPiece;
-using std::map;
-using std::string;
-using std::queue;
-using std::vector;
-
-namespace net {
-
-namespace {
-
-// Tracks the reason (the state of the server config) for sending inchoate
-// ClientHello to the server.
-void RecordInchoateClientHelloReason(
- QuicCryptoClientConfig::CachedState::ServerConfigState state) {
- UMA_HISTOGRAM_ENUMERATION(
- "Net.QuicInchoateClientHelloReason", state,
- QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT);
-}
-
-// Tracks the state of the QUIC server information loaded from the disk cache.
-void RecordDiskCacheServerConfigState(
- QuicCryptoClientConfig::CachedState::ServerConfigState state) {
- UMA_HISTOGRAM_ENUMERATION(
- "Net.QuicServerInfo.DiskCacheState", state,
- QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT);
-}
-
-} // namespace
-
-QuicCryptoClientConfig::QuicCryptoClientConfig(ProofVerifier* proof_verifier)
- : proof_verifier_(proof_verifier), disable_ecdsa_(false) {
- DCHECK(proof_verifier_.get());
- SetDefaults();
-}
-
-QuicCryptoClientConfig::~QuicCryptoClientConfig() {
- STLDeleteValues(&cached_states_);
-}
-
-QuicCryptoClientConfig::CachedState::CachedState()
- : server_config_valid_(false), generation_counter_(0) {}
-
-QuicCryptoClientConfig::CachedState::~CachedState() {}
-
-bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const {
- if (server_config_.empty()) {
- RecordInchoateClientHelloReason(SERVER_CONFIG_EMPTY);
- return false;
- }
-
- if (!server_config_valid_) {
- RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID);
- return false;
- }
-
- const CryptoHandshakeMessage* scfg = GetServerConfig();
- if (!scfg) {
- // Should be impossible short of cache corruption.
- DCHECK(false);
- RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED);
- return false;
- }
-
- uint64_t expiry_seconds;
- if (scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
- RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID_EXPIRY);
- return false;
- }
- if (now.ToUNIXSeconds() >= expiry_seconds) {
- UMA_HISTOGRAM_CUSTOM_TIMES(
- "Net.QuicClientHelloServerConfig.InvalidDuration",
- base::TimeDelta::FromSeconds(now.ToUNIXSeconds() - expiry_seconds),
- base::TimeDelta::FromMinutes(1), base::TimeDelta::FromDays(20), 50);
- RecordInchoateClientHelloReason(SERVER_CONFIG_EXPIRED);
- return false;
- }
-
- return true;
-}
-
-bool QuicCryptoClientConfig::CachedState::IsEmpty() const {
- return server_config_.empty();
-}
-
-const CryptoHandshakeMessage*
-QuicCryptoClientConfig::CachedState::GetServerConfig() const {
- if (server_config_.empty()) {
- return nullptr;
- }
-
- if (!scfg_.get()) {
- scfg_.reset(CryptoFramer::ParseMessage(server_config_));
- DCHECK(scfg_.get());
- }
- return scfg_.get();
-}
-
-void QuicCryptoClientConfig::CachedState::add_server_designated_connection_id(
- QuicConnectionId connection_id) {
- server_designated_connection_ids_.push(connection_id);
-}
-
-bool QuicCryptoClientConfig::CachedState::has_server_designated_connection_id()
- const {
- return !server_designated_connection_ids_.empty();
-}
-
-void QuicCryptoClientConfig::CachedState::add_server_nonce(
- const string& server_nonce) {
- server_nonces_.push(server_nonce);
-}
-
-bool QuicCryptoClientConfig::CachedState::has_server_nonce() const {
- return !server_nonces_.empty();
-}
-
-QuicCryptoClientConfig::CachedState::ServerConfigState
-QuicCryptoClientConfig::CachedState::SetServerConfig(StringPiece server_config,
- QuicWallTime now,
- string* error_details) {
- const bool matches_existing = server_config == server_config_;
-
- // Even if the new server config matches the existing one, we still wish to
- // reject it if it has expired.
- std::unique_ptr<CryptoHandshakeMessage> new_scfg_storage;
- const CryptoHandshakeMessage* new_scfg;
-
- if (!matches_existing) {
- new_scfg_storage.reset(CryptoFramer::ParseMessage(server_config));
- new_scfg = new_scfg_storage.get();
- } else {
- new_scfg = GetServerConfig();
- }
-
- if (!new_scfg) {
- *error_details = "SCFG invalid";
- return SERVER_CONFIG_INVALID;
- }
-
- uint64_t expiry_seconds;
- if (new_scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
- *error_details = "SCFG missing EXPY";
- return SERVER_CONFIG_INVALID_EXPIRY;
- }
-
- if (now.ToUNIXSeconds() >= expiry_seconds) {
- *error_details = "SCFG has expired";
- return SERVER_CONFIG_EXPIRED;
- }
-
- if (!matches_existing) {
- server_config_ = server_config.as_string();
- SetProofInvalid();
- scfg_.reset(new_scfg_storage.release());
- }
- return SERVER_CONFIG_VALID;
-}
-
-void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
- server_config_.clear();
- scfg_.reset();
- SetProofInvalid();
- queue<QuicConnectionId> empty_queue;
- swap(server_designated_connection_ids_, empty_queue);
-}
-
-void QuicCryptoClientConfig::CachedState::SetProof(const vector<string>& certs,
- StringPiece cert_sct,
- StringPiece chlo_hash,
- StringPiece signature) {
- bool has_changed = signature != server_config_sig_ ||
- chlo_hash != chlo_hash_ || certs_.size() != certs.size();
-
- if (!has_changed) {
- for (size_t i = 0; i < certs_.size(); i++) {
- if (certs_[i] != certs[i]) {
- has_changed = true;
- break;
- }
- }
- }
-
- if (!has_changed) {
- return;
- }
-
- // If the proof has changed then it needs to be revalidated.
- SetProofInvalid();
- certs_ = certs;
- cert_sct_ = cert_sct.as_string();
- chlo_hash_ = chlo_hash.as_string();
- server_config_sig_ = signature.as_string();
-}
-
-void QuicCryptoClientConfig::CachedState::Clear() {
- server_config_.clear();
- source_address_token_.clear();
- certs_.clear();
- cert_sct_.clear();
- chlo_hash_.clear();
- server_config_sig_.clear();
- server_config_valid_ = false;
- proof_verify_details_.reset();
- scfg_.reset();
- ++generation_counter_;
- queue<QuicConnectionId> empty_queue;
- swap(server_designated_connection_ids_, empty_queue);
-}
-
-void QuicCryptoClientConfig::CachedState::ClearProof() {
- SetProofInvalid();
- certs_.clear();
- cert_sct_.clear();
- chlo_hash_.clear();
- server_config_sig_.clear();
-}
-
-void QuicCryptoClientConfig::CachedState::SetProofValid() {
- server_config_valid_ = true;
-}
-
-void QuicCryptoClientConfig::CachedState::SetProofInvalid() {
- server_config_valid_ = false;
- ++generation_counter_;
-}
-
-bool QuicCryptoClientConfig::CachedState::Initialize(
- StringPiece server_config,
- StringPiece source_address_token,
- const vector<string>& certs,
- StringPiece cert_sct,
- StringPiece chlo_hash,
- StringPiece signature,
- QuicWallTime now) {
- DCHECK(server_config_.empty());
-
- if (server_config.empty()) {
- RecordDiskCacheServerConfigState(SERVER_CONFIG_EMPTY);
- return false;
- }
-
- string error_details;
- ServerConfigState state = SetServerConfig(server_config, now, &error_details);
- RecordDiskCacheServerConfigState(state);
- if (state != SERVER_CONFIG_VALID) {
- DVLOG(1) << "SetServerConfig failed with " << error_details;
- return false;
- }
-
- signature.CopyToString(&server_config_sig_);
- source_address_token.CopyToString(&source_address_token_);
- cert_sct.CopyToString(&cert_sct_);
- chlo_hash.CopyToString(&chlo_hash_);
- certs_ = certs;
- return true;
-}
-
-const string& QuicCryptoClientConfig::CachedState::server_config() const {
- return server_config_;
-}
-
-const string& QuicCryptoClientConfig::CachedState::source_address_token()
- const {
- return source_address_token_;
-}
-
-const vector<string>& QuicCryptoClientConfig::CachedState::certs() const {
- return certs_;
-}
-
-const string& QuicCryptoClientConfig::CachedState::cert_sct() const {
- return cert_sct_;
-}
-
-const string& QuicCryptoClientConfig::CachedState::chlo_hash() const {
- return chlo_hash_;
-}
-
-const string& QuicCryptoClientConfig::CachedState::signature() const {
- return server_config_sig_;
-}
-
-bool QuicCryptoClientConfig::CachedState::proof_valid() const {
- return server_config_valid_;
-}
-
-uint64_t QuicCryptoClientConfig::CachedState::generation_counter() const {
- return generation_counter_;
-}
-
-const ProofVerifyDetails*
-QuicCryptoClientConfig::CachedState::proof_verify_details() const {
- return proof_verify_details_.get();
-}
-
-void QuicCryptoClientConfig::CachedState::set_source_address_token(
- StringPiece token) {
- source_address_token_ = token.as_string();
-}
-
-void QuicCryptoClientConfig::CachedState::set_cert_sct(StringPiece cert_sct) {
- cert_sct_ = cert_sct.as_string();
-}
-
-void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails(
- ProofVerifyDetails* details) {
- proof_verify_details_.reset(details);
-}
-
-void QuicCryptoClientConfig::CachedState::InitializeFrom(
- const QuicCryptoClientConfig::CachedState& other) {
- DCHECK(server_config_.empty());
- DCHECK(!server_config_valid_);
- server_config_ = other.server_config_;
- source_address_token_ = other.source_address_token_;
- certs_ = other.certs_;
- cert_sct_ = other.cert_sct_;
- chlo_hash_ = other.chlo_hash_;
- server_config_sig_ = other.server_config_sig_;
- server_config_valid_ = other.server_config_valid_;
- server_designated_connection_ids_ = other.server_designated_connection_ids_;
- if (other.proof_verify_details_.get() != nullptr) {
- proof_verify_details_.reset(other.proof_verify_details_->Clone());
- }
- ++generation_counter_;
-}
-
-QuicConnectionId
-QuicCryptoClientConfig::CachedState::GetNextServerDesignatedConnectionId() {
- if (server_designated_connection_ids_.empty()) {
- QUIC_BUG
- << "Attempting to consume a connection id that was never designated.";
- return 0;
- }
- const QuicConnectionId next_id = server_designated_connection_ids_.front();
- server_designated_connection_ids_.pop();
- return next_id;
-}
-
-string QuicCryptoClientConfig::CachedState::GetNextServerNonce() {
- if (server_nonces_.empty()) {
- QUIC_BUG
- << "Attempting to consume a server nonce that was never designated.";
- return "";
- }
- const string server_nonce = server_nonces_.front();
- server_nonces_.pop();
- return server_nonce;
-}
-
-void QuicCryptoClientConfig::SetDefaults() {
- // Key exchange methods.
- kexs = {kC255, kP256};
-
- // Authenticated encryption algorithms. Prefer RFC 7539 ChaCha20 by default.
- aead = {kCC20, kAESG};
-
- disable_ecdsa_ = false;
-}
-
-QuicCryptoClientConfig::CachedState* QuicCryptoClientConfig::LookupOrCreate(
- const QuicServerId& server_id) {
- CachedStateMap::const_iterator it = cached_states_.find(server_id);
- if (it != cached_states_.end()) {
- return it->second;
- }
-
- CachedState* cached = new CachedState;
- cached_states_.insert(std::make_pair(server_id, cached));
- bool cache_populated = PopulateFromCanonicalConfig(server_id, cached);
- UMA_HISTOGRAM_BOOLEAN(
- "Net.QuicCryptoClientConfig.PopulatedFromCanonicalConfig",
- cache_populated);
- return cached;
-}
-
-void QuicCryptoClientConfig::ClearCachedStates() {
- for (CachedStateMap::const_iterator it = cached_states_.begin();
- it != cached_states_.end(); ++it) {
- it->second->Clear();
- }
-}
-
-void QuicCryptoClientConfig::FillInchoateClientHello(
- const QuicServerId& server_id,
- const QuicVersion preferred_version,
- const CachedState* cached,
- QuicRandom* rand,
- QuicCryptoNegotiatedParameters* out_params,
- CryptoHandshakeMessage* out) const {
- out->set_tag(kCHLO);
- out->set_minimum_size(kClientHelloMinimumSize);
-
- // Server name indication. We only send SNI if it's a valid domain name, as
- // per the spec.
- if (CryptoUtils::IsValidSNI(server_id.host())) {
- out->SetStringPiece(kSNI, server_id.host());
- }
- out->SetValue(kVER, QuicVersionToQuicTag(preferred_version));
-
- if (!user_agent_id_.empty()) {
- out->SetStringPiece(kUAID, user_agent_id_);
- }
-
- char proof_nonce[32];
- rand->RandBytes(proof_nonce, arraysize(proof_nonce));
- out->SetStringPiece(kNONP, StringPiece(proof_nonce, arraysize(proof_nonce)));
-
- // Even though this is an inchoate CHLO, send the SCID so that
- // the STK can be validated by the server.
- const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
- if (scfg != nullptr) {
- StringPiece scid;
- if (scfg->GetStringPiece(kSCID, &scid)) {
- out->SetStringPiece(kSCID, scid);
- }
- }
-
- if (!cached->source_address_token().empty()) {
- out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token());
- }
-
- if (disable_ecdsa_) {
- out->SetVector(kPDMD, QuicTagVector{kX59R});
- } else {
- out->SetVector(kPDMD, QuicTagVector{kX509});
- }
-
- if (common_cert_sets) {
- out->SetStringPiece(kCCS, common_cert_sets->GetCommonHashes());
- }
-
- if (preferred_version > QUIC_VERSION_29) {
- out->SetStringPiece(kCertificateSCTTag, "");
- }
-
- const vector<string>& certs = cached->certs();
- // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
- // client config is being used for multiple connections, another connection
- // doesn't update the cached certificates and cause us to be unable to
- // process the server's compressed certificate chain.
- out_params->cached_certs = certs;
- if (!certs.empty()) {
- vector<uint64_t> hashes;
- hashes.reserve(certs.size());
- for (vector<string>::const_iterator i = certs.begin(); i != certs.end();
- ++i) {
- hashes.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size()));
- }
- out->SetVector(kCCRT, hashes);
- }
-}
-
-QuicErrorCode QuicCryptoClientConfig::FillClientHello(
- const QuicServerId& server_id,
- QuicConnectionId connection_id,
- const QuicVersion actual_version,
- const QuicVersion preferred_version,
- const CachedState* cached,
- QuicWallTime now,
- QuicRandom* rand,
- const ChannelIDKey* channel_id_key,
- QuicCryptoNegotiatedParameters* out_params,
- CryptoHandshakeMessage* out,
- string* error_details) const {
- DCHECK(error_details != nullptr);
-
- FillInchoateClientHello(server_id, preferred_version, cached, rand,
- out_params, out);
-
- const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
- if (!scfg) {
- // This should never happen as our caller should have checked
- // cached->IsComplete() before calling this function.
- *error_details = "Handshake not ready";
- return QUIC_CRYPTO_INTERNAL_ERROR;
- }
-
- StringPiece scid;
- if (!scfg->GetStringPiece(kSCID, &scid)) {
- *error_details = "SCFG missing SCID";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
- out->SetStringPiece(kSCID, scid);
-
- if (preferred_version > QUIC_VERSION_29) {
- out->SetStringPiece(kCertificateSCTTag, "");
- }
-
- const QuicTag* their_aeads;
- const QuicTag* their_key_exchanges;
- size_t num_their_aeads, num_their_key_exchanges;
- if (scfg->GetTaglist(kAEAD, &their_aeads, &num_their_aeads) !=
- QUIC_NO_ERROR ||
- scfg->GetTaglist(kKEXS, &their_key_exchanges, &num_their_key_exchanges) !=
- QUIC_NO_ERROR) {
- *error_details = "Missing AEAD or KEXS";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- // AEAD: the work loads on the client and server are symmetric. Since the
- // client is more likely to be CPU-constrained, break the tie by favoring
- // the client's preference.
- // Key exchange: the client does more work than the server, so favor the
- // client's preference.
- size_t key_exchange_index;
- if (!QuicUtils::FindMutualTag(aead, their_aeads, num_their_aeads,
- QuicUtils::LOCAL_PRIORITY, &out_params->aead,
- nullptr) ||
- !QuicUtils::FindMutualTag(
- kexs, their_key_exchanges, num_their_key_exchanges,
- QuicUtils::LOCAL_PRIORITY, &out_params->key_exchange,
- &key_exchange_index)) {
- *error_details = "Unsupported AEAD or KEXS";
- return QUIC_CRYPTO_NO_SUPPORT;
- }
- out->SetVector(kAEAD, QuicTagVector{out_params->aead});
- out->SetVector(kKEXS, QuicTagVector{out_params->key_exchange});
-
- if (!tb_key_params.empty()) {
- const QuicTag* their_tbkps;
- size_t num_their_tbkps;
- switch (scfg->GetTaglist(kTBKP, &their_tbkps, &num_their_tbkps)) {
- case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
- break;
- case QUIC_NO_ERROR:
- if (QuicUtils::FindMutualTag(tb_key_params, their_tbkps,
- num_their_tbkps, QuicUtils::LOCAL_PRIORITY,
- &out_params->token_binding_key_param,
- nullptr)) {
- out->SetVector(kTBKP,
- QuicTagVector{out_params->token_binding_key_param});
- }
- break;
- default:
- *error_details = "Invalid TBKP";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
- }
-
- StringPiece public_value;
- if (scfg->GetNthValue24(kPUBS, key_exchange_index, &public_value) !=
- QUIC_NO_ERROR) {
- *error_details = "Missing public value";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- StringPiece orbit;
- if (!scfg->GetStringPiece(kORBT, &orbit) || orbit.size() != kOrbitSize) {
- *error_details = "SCFG missing OBIT";
- return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
- }
-
- CryptoUtils::GenerateNonce(now, rand, orbit, &out_params->client_nonce);
- out->SetStringPiece(kNONC, out_params->client_nonce);
- if (!out_params->server_nonce.empty()) {
- out->SetStringPiece(kServerNonceTag, out_params->server_nonce);
- }
-
- switch (out_params->key_exchange) {
- case kC255:
- out_params->client_key_exchange.reset(Curve25519KeyExchange::New(
- Curve25519KeyExchange::NewPrivateKey(rand)));
- break;
- case kP256:
- out_params->client_key_exchange.reset(
- P256KeyExchange::New(P256KeyExchange::NewPrivateKey()));
- break;
- default:
- DCHECK(false);
- *error_details = "Configured to support an unknown key exchange";
- return QUIC_CRYPTO_INTERNAL_ERROR;
- }
-
- if (!out_params->client_key_exchange->CalculateSharedKey(
- public_value, &out_params->initial_premaster_secret)) {
- *error_details = "Key exchange failure";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
- out->SetStringPiece(kPUBS, out_params->client_key_exchange->public_value());
-
- const vector<string>& certs = cached->certs();
- if (preferred_version > QUIC_VERSION_25) {
- if (certs.empty()) {
- *error_details = "No certs to calculate XLCT";
- return QUIC_CRYPTO_INTERNAL_ERROR;
- }
- out->SetValue(kXLCT, CryptoUtils::ComputeLeafCertHash(certs[0]));
- }
-
- if (channel_id_key) {
- // In order to calculate the encryption key for the CETV block we need to
- // serialise the client hello as it currently is (i.e. without the CETV
- // block). For this, the client hello is serialized without padding.
- const size_t orig_min_size = out->minimum_size();
- out->set_minimum_size(0);
-
- CryptoHandshakeMessage cetv;
- cetv.set_tag(kCETV);
-
- string hkdf_input;
- const QuicData& client_hello_serialized = out->GetSerialized();
- hkdf_input.append(QuicCryptoConfig::kCETVLabel,
- strlen(QuicCryptoConfig::kCETVLabel) + 1);
- hkdf_input.append(reinterpret_cast<char*>(&connection_id),
- sizeof(connection_id));
- hkdf_input.append(client_hello_serialized.data(),
- client_hello_serialized.length());
- hkdf_input.append(cached->server_config());
-
- string key = channel_id_key->SerializeKey();
- string signature;
- if (!channel_id_key->Sign(hkdf_input, &signature)) {
- *error_details = "Channel ID signature failed";
- return QUIC_INVALID_CHANNEL_ID_SIGNATURE;
- }
-
- cetv.SetStringPiece(kCIDK, key);
- cetv.SetStringPiece(kCIDS, signature);
-
- CrypterPair crypters;
- if (!CryptoUtils::DeriveKeys(
- out_params->initial_premaster_secret, out_params->aead,
- out_params->client_nonce, out_params->server_nonce, hkdf_input,
- Perspective::IS_CLIENT, CryptoUtils::Diversification::Never(),
- &crypters, nullptr /* subkey secret */)) {
- *error_details = "Symmetric key setup failed";
- return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
- }
-
- const QuicData& cetv_plaintext = cetv.GetSerialized();
- const size_t encrypted_len =
- crypters.encrypter->GetCiphertextSize(cetv_plaintext.length());
- std::unique_ptr<char[]> output(new char[encrypted_len]);
- size_t output_size = 0;
- if (!crypters.encrypter->EncryptPacket(
- kDefaultPathId /* path id */, 0 /* packet number */,
- StringPiece() /* associated data */, cetv_plaintext.AsStringPiece(),
- output.get(), &output_size, encrypted_len)) {
- *error_details = "Packet encryption failed";
- return QUIC_ENCRYPTION_FAILURE;
- }
-
- out->SetStringPiece(kCETV, StringPiece(output.get(), output_size));
- out->MarkDirty();
-
- out->set_minimum_size(orig_min_size);
- }
-
- // Derive the symmetric keys and set up the encrypters and decrypters.
- // Set the following members of out_params:
- // out_params->hkdf_input_suffix
- // out_params->initial_crypters
- out_params->hkdf_input_suffix.clear();
- out_params->hkdf_input_suffix.append(reinterpret_cast<char*>(&connection_id),
- sizeof(connection_id));
- const QuicData& client_hello_serialized = out->GetSerialized();
- out_params->hkdf_input_suffix.append(client_hello_serialized.data(),
- client_hello_serialized.length());
- out_params->hkdf_input_suffix.append(cached->server_config());
- if (preferred_version > QUIC_VERSION_25) {
- if (certs.empty()) {
- *error_details = "No certs found to include in KDF";
- return QUIC_CRYPTO_INTERNAL_ERROR;
- }
- out_params->hkdf_input_suffix.append(certs[0]);
- }
-
- string hkdf_input;
- const size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
- hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
- hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
- hkdf_input.append(out_params->hkdf_input_suffix);
-
- string* subkey_secret = &out_params->initial_subkey_secret;
-
- // Only perform key diversification for QUIC versions 33 and later.
- // TODO(rch): remove the |actual_version| argument to this method when
- // QUIC_VERSION_32 is removed.
- CryptoUtils::Diversification diversification =
- actual_version > QUIC_VERSION_32 ? CryptoUtils::Diversification::Pending()
- : CryptoUtils::Diversification::Never();
- if (!CryptoUtils::DeriveKeys(out_params->initial_premaster_secret,
- out_params->aead, out_params->client_nonce,
- out_params->server_nonce, hkdf_input,
- Perspective::IS_CLIENT, diversification,
- &out_params->initial_crypters, subkey_secret)) {
- *error_details = "Symmetric key setup failed";
- return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
- }
-
- return QUIC_NO_ERROR;
-}
-
-QuicErrorCode QuicCryptoClientConfig::CacheNewServerConfig(
- const CryptoHandshakeMessage& message,
- QuicWallTime now,
- QuicVersion version,
- StringPiece chlo_hash,
- const vector<string>& cached_certs,
- CachedState* cached,
- string* error_details) {
- DCHECK(error_details != nullptr);
-
- StringPiece scfg;
- if (!message.GetStringPiece(kSCFG, &scfg)) {
- *error_details = "Missing SCFG";
- return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
- }
-
- CachedState::ServerConfigState state =
- cached->SetServerConfig(scfg, now, error_details);
- if (state == CachedState::SERVER_CONFIG_EXPIRED) {
- return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED;
- }
- // TODO(rtenneti): Return more specific error code than returning
- // QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER.
- if (state != CachedState::SERVER_CONFIG_VALID) {
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- StringPiece token;
- if (message.GetStringPiece(kSourceAddressTokenTag, &token)) {
- cached->set_source_address_token(token);
- }
-
- StringPiece proof, cert_bytes, cert_sct;
- bool has_proof = message.GetStringPiece(kPROF, &proof);
- bool has_cert = message.GetStringPiece(kCertificateTag, &cert_bytes);
- if (has_proof && has_cert) {
- vector<string> certs;
- if (!CertCompressor::DecompressChain(cert_bytes, cached_certs,
- common_cert_sets, &certs)) {
- *error_details = "Certificate data invalid";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- if (version > QUIC_VERSION_29) {
- message.GetStringPiece(kCertificateSCTTag, &cert_sct);
- }
- cached->SetProof(certs, cert_sct, chlo_hash, proof);
- } else {
- // Secure QUIC: clear existing proof as we have been sent a new SCFG
- // without matching proof/certs.
- cached->ClearProof();
-
- if (has_proof && !has_cert) {
- *error_details = "Certificate missing";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- if (!has_proof && has_cert) {
- *error_details = "Proof missing";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
- }
-
- return QUIC_NO_ERROR;
-}
-
-QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
- const CryptoHandshakeMessage& rej,
- QuicWallTime now,
- const QuicVersion version,
- StringPiece chlo_hash,
- CachedState* cached,
- QuicCryptoNegotiatedParameters* out_params,
- string* error_details) {
- DCHECK(error_details != nullptr);
-
- if ((rej.tag() != kREJ) && (rej.tag() != kSREJ)) {
- *error_details = "Message is not REJ or SREJ";
- return QUIC_CRYPTO_INTERNAL_ERROR;
- }
-
- QuicErrorCode error =
- CacheNewServerConfig(rej, now, version, chlo_hash,
- out_params->cached_certs, cached, error_details);
- if (error != QUIC_NO_ERROR) {
- return error;
- }
-
- StringPiece nonce;
- if (rej.GetStringPiece(kServerNonceTag, &nonce)) {
- out_params->server_nonce = nonce.as_string();
- }
-
- if (rej.tag() == kSREJ) {
- QuicConnectionId connection_id;
- if (rej.GetUint64(kRCID, &connection_id) != QUIC_NO_ERROR) {
- *error_details = "Missing kRCID";
- return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
- }
- cached->add_server_designated_connection_id(connection_id);
- if (!nonce.empty()) {
- cached->add_server_nonce(nonce.as_string());
- }
- return QUIC_NO_ERROR;
- }
-
- return QUIC_NO_ERROR;
-}
-
-QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
- const CryptoHandshakeMessage& server_hello,
- QuicConnectionId connection_id,
- QuicVersion version,
- const QuicVersionVector& negotiated_versions,
- CachedState* cached,
- QuicCryptoNegotiatedParameters* out_params,
- string* error_details) {
- DCHECK(error_details != nullptr);
-
- QuicErrorCode valid = CryptoUtils::ValidateServerHello(
- server_hello, negotiated_versions, error_details);
- if (valid != QUIC_NO_ERROR) {
- return valid;
- }
-
- // Learn about updated source address tokens.
- StringPiece token;
- if (server_hello.GetStringPiece(kSourceAddressTokenTag, &token)) {
- cached->set_source_address_token(token);
- }
-
- StringPiece shlo_nonce;
- if (version > QUIC_VERSION_26 &&
- !server_hello.GetStringPiece(kServerNonceTag, &shlo_nonce)) {
- *error_details = "server hello missing server nonce";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- // TODO(agl):
- // learn about updated SCFGs.
-
- StringPiece public_value;
- if (!server_hello.GetStringPiece(kPUBS, &public_value)) {
- *error_details = "server hello missing forward secure public value";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- if (!out_params->client_key_exchange->CalculateSharedKey(
- public_value, &out_params->forward_secure_premaster_secret)) {
- *error_details = "Key exchange failure";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- string hkdf_input;
- const size_t label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
- hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
- hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, label_len);
- hkdf_input.append(out_params->hkdf_input_suffix);
-
- if (!CryptoUtils::DeriveKeys(
- out_params->forward_secure_premaster_secret, out_params->aead,
- out_params->client_nonce,
- shlo_nonce.empty() ? out_params->server_nonce : shlo_nonce,
- hkdf_input, Perspective::IS_CLIENT,
- CryptoUtils::Diversification::Never(),
- &out_params->forward_secure_crypters, &out_params->subkey_secret)) {
- *error_details = "Symmetric key setup failed";
- return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
- }
-
- return QUIC_NO_ERROR;
-}
-
-QuicErrorCode QuicCryptoClientConfig::ProcessServerConfigUpdate(
- const CryptoHandshakeMessage& server_config_update,
- QuicWallTime now,
- const QuicVersion version,
- StringPiece chlo_hash,
- CachedState* cached,
- QuicCryptoNegotiatedParameters* out_params,
- string* error_details) {
- DCHECK(error_details != nullptr);
-
- if (server_config_update.tag() != kSCUP) {
- *error_details = "ServerConfigUpdate must have kSCUP tag.";
- return QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
- }
- return CacheNewServerConfig(server_config_update, now, version, chlo_hash,
- out_params->cached_certs, cached, error_details);
-}
-
-ProofVerifier* QuicCryptoClientConfig::proof_verifier() const {
- return proof_verifier_.get();
-}
-
-ChannelIDSource* QuicCryptoClientConfig::channel_id_source() const {
- return channel_id_source_.get();
-}
-
-void QuicCryptoClientConfig::SetChannelIDSource(ChannelIDSource* source) {
- channel_id_source_.reset(source);
-}
-
-void QuicCryptoClientConfig::InitializeFrom(
- const QuicServerId& server_id,
- const QuicServerId& canonical_server_id,
- QuicCryptoClientConfig* canonical_crypto_config) {
- CachedState* canonical_cached =
- canonical_crypto_config->LookupOrCreate(canonical_server_id);
- if (!canonical_cached->proof_valid()) {
- return;
- }
- CachedState* cached = LookupOrCreate(server_id);
- cached->InitializeFrom(*canonical_cached);
-}
-
-void QuicCryptoClientConfig::AddCanonicalSuffix(const string& suffix) {
- canonical_suffixes_.push_back(suffix);
-}
-
-void QuicCryptoClientConfig::PreferAesGcm() {
- DCHECK(!aead.empty());
- if (aead.size() <= 1) {
- return;
- }
- QuicTagVector::iterator pos = std::find(aead.begin(), aead.end(), kAESG);
- if (pos != aead.end()) {
- aead.erase(pos);
- aead.insert(aead.begin(), kAESG);
- }
-}
-
-void QuicCryptoClientConfig::DisableEcdsa() {
- disable_ecdsa_ = true;
-}
-
-bool QuicCryptoClientConfig::PopulateFromCanonicalConfig(
- const QuicServerId& server_id,
- CachedState* server_state) {
- DCHECK(server_state->IsEmpty());
- size_t i = 0;
- for (; i < canonical_suffixes_.size(); ++i) {
- if (base::EndsWith(server_id.host(), canonical_suffixes_[i],
- base::CompareCase::INSENSITIVE_ASCII)) {
- break;
- }
- }
- if (i == canonical_suffixes_.size()) {
- return false;
- }
-
- QuicServerId suffix_server_id(canonical_suffixes_[i], server_id.port(),
- server_id.privacy_mode());
- if (!ContainsKey(canonical_server_map_, suffix_server_id)) {
- // This is the first host we've seen which matches the suffix, so make it
- // canonical.
- canonical_server_map_[suffix_server_id] = server_id;
- return false;
- }
-
- const QuicServerId& canonical_server_id =
- canonical_server_map_[suffix_server_id];
- CachedState* canonical_state = cached_states_[canonical_server_id];
- if (!canonical_state->proof_valid()) {
- return false;
- }
-
- // Update canonical version to point at the "most recent" entry.
- canonical_server_map_[suffix_server_id] = server_id;
-
- server_state->InitializeFrom(*canonical_state);
- return true;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/quic_crypto_client_config.h b/chromium/net/quic/crypto/quic_crypto_client_config.h
deleted file mode 100644
index b3063922a4a..00000000000
--- a/chromium/net/quic/crypto/quic_crypto_client_config.h
+++ /dev/null
@@ -1,384 +0,0 @@
-// Copyright 2013 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_CRYPTO_QUIC_CRYPTO_CLIENT_CONFIG_H_
-#define NET_QUIC_CRYPTO_QUIC_CRYPTO_CLIENT_CONFIG_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <queue>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_id.h"
-
-namespace net {
-
-class ChannelIDKey;
-class ChannelIDSource;
-class CryptoHandshakeMessage;
-class ProofVerifier;
-class ProofVerifyDetails;
-class QuicRandom;
-
-// QuicCryptoClientConfig contains crypto-related configuration settings for a
-// client. Note that this object isn't thread-safe. It's designed to be used on
-// a single thread at a time.
-class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
- public:
- // A CachedState contains the information that the client needs in order to
- // perform a 0-RTT handshake with a server. This information can be reused
- // over several connections to the same server.
- class NET_EXPORT_PRIVATE CachedState {
- public:
- // Enum to track if the server config is valid or not. If it is not valid,
- // it specifies why it is invalid.
- enum ServerConfigState {
- // WARNING: Do not change the numerical values of any of server config
- // state. Do not remove deprecated server config states - just comment
- // them as deprecated.
- SERVER_CONFIG_EMPTY = 0,
- SERVER_CONFIG_INVALID = 1,
- SERVER_CONFIG_CORRUPTED = 2,
- SERVER_CONFIG_EXPIRED = 3,
- SERVER_CONFIG_INVALID_EXPIRY = 4,
- SERVER_CONFIG_VALID = 5,
- // NOTE: Add new server config states only immediately above this line.
- // Make sure to update the QuicServerConfigState enum in
- // tools/metrics/histograms/histograms.xml accordingly.
- SERVER_CONFIG_COUNT
- };
-
- CachedState();
- ~CachedState();
-
- // IsComplete returns true if this object contains enough information to
- // perform a handshake with the server. |now| is used to judge whether any
- // cached server config has expired.
- bool IsComplete(QuicWallTime now) const;
-
- // IsEmpty returns true if |server_config_| is empty.
- bool IsEmpty() const;
-
- // GetServerConfig returns the parsed contents of |server_config|, or
- // nullptr if |server_config| is empty. The return value is owned by this
- // object and is destroyed when this object is.
- const CryptoHandshakeMessage* GetServerConfig() const;
-
- // SetServerConfig checks that |server_config| parses correctly and stores
- // it in |server_config_|. |now| is used to judge whether |server_config|
- // has expired.
- ServerConfigState SetServerConfig(base::StringPiece server_config,
- QuicWallTime now,
- std::string* error_details);
-
- // InvalidateServerConfig clears the cached server config (if any).
- void InvalidateServerConfig();
-
- // SetProof stores a certificate chain and signature.
- void SetProof(const std::vector<std::string>& certs,
- base::StringPiece cert_sct,
- base::StringPiece chlo_hash,
- base::StringPiece signature);
-
- // Clears all the data.
- void Clear();
-
- // Clears the certificate chain and signature and invalidates the proof.
- void ClearProof();
-
- // SetProofValid records that the certificate chain and signature have been
- // validated and that it's safe to assume that the server is legitimate.
- // (Note: this does not check the chain or signature.)
- void SetProofValid();
-
- // If the server config or the proof has changed then it needs to be
- // revalidated. Helper function to keep server_config_valid_ and
- // generation_counter_ in sync.
- void SetProofInvalid();
-
- const std::string& server_config() const;
- const std::string& source_address_token() const;
- const std::vector<std::string>& certs() const;
- const std::string& cert_sct() const;
- const std::string& chlo_hash() const;
- const std::string& signature() const;
- bool proof_valid() const;
- uint64_t generation_counter() const;
- const ProofVerifyDetails* proof_verify_details() const;
-
- void set_source_address_token(base::StringPiece token);
-
- void set_cert_sct(base::StringPiece cert_sct);
-
- // Adds the connection ID to the queue of server-designated connection-ids.
- void add_server_designated_connection_id(QuicConnectionId connection_id);
-
- // If true, the crypto config contains at least one connection ID specified
- // by the server, and the client should use one of these IDs when initiating
- // the next connection.
- bool has_server_designated_connection_id() const;
-
- // This function should only be called when
- // has_server_designated_connection_id is true. Returns the next
- // connection_id specified by the server and removes it from the
- // queue of ids.
- QuicConnectionId GetNextServerDesignatedConnectionId();
-
- // Adds the servernonce to the queue of server nonces.
- void add_server_nonce(const std::string& server_nonce);
-
- // If true, the crypto config contains at least one server nonce, and the
- // client should use one of these nonces.
- bool has_server_nonce() const;
-
- // This function should only be called when has_server_nonce is true.
- // Returns the next server_nonce specified by the server and removes it
- // from the queue of nonces.
- std::string GetNextServerNonce();
-
- // SetProofVerifyDetails takes ownership of |details|.
- void SetProofVerifyDetails(ProofVerifyDetails* details);
-
- // Copy the |server_config_|, |source_address_token_|, |certs_|,
- // |cert_sct_|, |chlo_hash_| and |server_config_sig_| from the |other|. The
- // remaining fields, |generation_counter_|, |proof_verify_details_|, and
- // |scfg_| remain unchanged.
- void InitializeFrom(const CachedState& other);
-
- // Initializes this cached state based on the arguments provided.
- // Returns false if there is a problem parsing the server config.
- bool Initialize(base::StringPiece server_config,
- base::StringPiece source_address_token,
- const std::vector<std::string>& certs,
- base::StringPiece cert_sct,
- base::StringPiece chlo_hash,
- base::StringPiece signature,
- QuicWallTime now);
-
- private:
- std::string server_config_; // A serialized handshake message.
- std::string source_address_token_; // An opaque proof of IP ownership.
- std::vector<std::string> certs_; // A list of certificates in leaf-first
- // order.
- std::string cert_sct_; // Signed timestamp of the leaf cert.
- std::string chlo_hash_; // Hash of the CHLO message.
- std::string server_config_sig_; // A signature of |server_config_|.
- bool server_config_valid_; // True if |server_config_| is correctly
- // signed and |certs_| has been
- // validated.
- // Generation counter associated with the |server_config_|, |certs_| and
- // |server_config_sig_| combination. It is incremented whenever we set
- // server_config_valid_ to false.
- uint64_t generation_counter_;
-
- std::unique_ptr<ProofVerifyDetails> proof_verify_details_;
-
- // scfg contains the cached, parsed value of |server_config|.
- mutable std::unique_ptr<CryptoHandshakeMessage> scfg_;
-
- // TODO(jokulik): Consider using a hash-set as extra book-keeping to ensure
- // that no connection-id is added twice. Also, consider keeping the server
- // nonces and connection_ids together in one queue.
- std::queue<QuicConnectionId> server_designated_connection_ids_;
- std::queue<std::string> server_nonces_;
-
- DISALLOW_COPY_AND_ASSIGN(CachedState);
- };
-
- explicit QuicCryptoClientConfig(ProofVerifier* proof_verifier);
- ~QuicCryptoClientConfig();
-
- // LookupOrCreate returns a CachedState for the given |server_id|. If no such
- // CachedState currently exists, it will be created and cached.
- CachedState* LookupOrCreate(const QuicServerId& server_id);
-
- // Delete all CachedState objects from cached_states_.
- void ClearCachedStates();
-
- // FillInchoateClientHello sets |out| to be a CHLO message that elicits a
- // source-address token or SCFG from a server. If |cached| is non-nullptr, the
- // source-address token will be taken from it. |out_params| is used in order
- // to store the cached certs that were sent as hints to the server in
- // |out_params->cached_certs|. |preferred_version| is the version of the
- // QUIC protocol that this client chose to use initially. This allows the
- // server to detect downgrade attacks.
- void FillInchoateClientHello(const QuicServerId& server_id,
- const QuicVersion preferred_version,
- const CachedState* cached,
- QuicRandom* rand,
- QuicCryptoNegotiatedParameters* out_params,
- CryptoHandshakeMessage* out) const;
-
- // FillClientHello sets |out| to be a CHLO message based on the configuration
- // of this object. This object must have cached enough information about
- // the server's hostname in order to perform a handshake. This can be checked
- // with the |IsComplete| member of |CachedState|.
- //
- // |now| and |rand| are used to generate the nonce and |out_params| is
- // filled with the results of the handshake that the server is expected to
- // accept. |preferred_version| is the version of the QUIC protocol that this
- // client chose to use initially. This allows the server to detect downgrade
- // attacks.
- //
- // If |channel_id_key| is not null, it is used to sign a secret value derived
- // from the client and server's keys, and the Channel ID public key and the
- // signature are placed in the CETV value of the CHLO.
- QuicErrorCode FillClientHello(const QuicServerId& server_id,
- QuicConnectionId connection_id,
- const QuicVersion actual_version,
- const QuicVersion preferred_version,
- const CachedState* cached,
- QuicWallTime now,
- QuicRandom* rand,
- const ChannelIDKey* channel_id_key,
- QuicCryptoNegotiatedParameters* out_params,
- CryptoHandshakeMessage* out,
- std::string* error_details) const;
-
- // ProcessRejection processes a REJ message from a server and updates the
- // cached information about that server. After this, |IsComplete| may return
- // true for that server's CachedState. If the rejection message contains state
- // about a future handshake (i.e. an nonce value from the server), then it
- // will be saved in |out_params|. |now| is used to judge whether the server
- // config in the rejection message has expired.
- QuicErrorCode ProcessRejection(const CryptoHandshakeMessage& rej,
- QuicWallTime now,
- QuicVersion version,
- base::StringPiece chlo_hash,
- CachedState* cached,
- QuicCryptoNegotiatedParameters* out_params,
- std::string* error_details);
-
- // ProcessServerHello processes the message in |server_hello|, updates the
- // cached information about that server, writes the negotiated parameters to
- // |out_params| and returns QUIC_NO_ERROR. If |server_hello| is unacceptable
- // then it puts an error message in |error_details| and returns an error
- // code. |version| is the QUIC version for the current connection.
- // |negotiated_versions| contains the list of version, if any, that were
- // present in a version negotiation packet previously recevied from the
- // server. The contents of this list will be compared against the list of
- // versions provided in the VER tag of the server hello.
- QuicErrorCode ProcessServerHello(const CryptoHandshakeMessage& server_hello,
- QuicConnectionId connection_id,
- QuicVersion version,
- const QuicVersionVector& negotiated_versions,
- CachedState* cached,
- QuicCryptoNegotiatedParameters* out_params,
- std::string* error_details);
-
- // Processes the message in |server_update|, updating the cached source
- // address token, and server config.
- // If |server_update| is invalid then |error_details| will contain an error
- // message, and an error code will be returned. If all has gone well
- // QUIC_NO_ERROR is returned.
- QuicErrorCode ProcessServerConfigUpdate(
- const CryptoHandshakeMessage& server_update,
- QuicWallTime now,
- const QuicVersion version,
- base::StringPiece chlo_hash,
- CachedState* cached,
- QuicCryptoNegotiatedParameters* out_params,
- std::string* error_details);
-
- ProofVerifier* proof_verifier() const;
-
- ChannelIDSource* channel_id_source() 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
- // |source|.
- void SetChannelIDSource(ChannelIDSource* source);
-
- // Initialize the CachedState from |canonical_crypto_config| for the
- // |canonical_server_id| as the initial CachedState for |server_id|. We will
- // copy config data only if |canonical_crypto_config| has valid proof.
- void InitializeFrom(const QuicServerId& server_id,
- const QuicServerId& canonical_server_id,
- QuicCryptoClientConfig* canonical_crypto_config);
-
- // Adds |suffix| as a domain suffix for which the server's crypto config
- // is expected to be shared among servers with the domain suffix. If a server
- // matches this suffix, then the server config from another server with the
- // suffix will be used to initialize the cached state for this server.
- void AddCanonicalSuffix(const std::string& suffix);
-
- // Prefers AES-GCM (kAESG) over other AEAD algorithms. Call this method if
- // the CPU has hardware acceleration for AES-GCM. This method can only be
- // called after SetDefaults().
- void PreferAesGcm();
-
- // Disables the use of ECDSA for proof verification.
- // Call this method on platforms that do not support ECDSA.
- // TODO(rch): remove this method when we drop support for Windows XP.
- void DisableEcdsa();
-
- // Saves the |user_agent_id| that will be passed in QUIC's CHLO message.
- void set_user_agent_id(const std::string& user_agent_id) {
- user_agent_id_ = user_agent_id;
- }
-
- private:
- typedef std::map<QuicServerId, CachedState*> CachedStateMap;
-
- // Sets the members to reasonable, default values.
- void SetDefaults();
-
- // CacheNewServerConfig checks for SCFG, STK, PROF, and CRT tags in |message|,
- // verifies them, and stores them in the cached state if they validate.
- // This is used on receipt of a REJ from a server, or when a server sends
- // updated server config during a connection.
- QuicErrorCode CacheNewServerConfig(
- const CryptoHandshakeMessage& message,
- QuicWallTime now,
- const QuicVersion version,
- base::StringPiece chlo_hash,
- const std::vector<std::string>& cached_certs,
- CachedState* cached,
- std::string* error_details);
-
- // If the suffix of the hostname in |server_id| is in |canonical_suffixes_|,
- // then populate |cached| with the canonical cached state from
- // |canonical_server_map_| for that suffix. Returns true if |cached| is
- // initialized with canonical cached state.
- bool PopulateFromCanonicalConfig(const QuicServerId& server_id,
- CachedState* cached);
-
- // cached_states_ maps from the server_id to the cached information about
- // that server.
- CachedStateMap cached_states_;
-
- // Contains a map of servers which could share the same server config. Map
- // from a canonical host suffix/port/scheme to a representative server with
- // the canonical suffix, which has a plausible set of initial certificates
- // (or at least server public key).
- std::map<QuicServerId, QuicServerId> canonical_server_map_;
-
- // Contains list of suffixes (for exmaple ".c.youtube.com",
- // ".googlevideo.com") of canonical hostnames.
- std::vector<std::string> canonical_suffixes_;
-
- std::unique_ptr<ProofVerifier> proof_verifier_;
- std::unique_ptr<ChannelIDSource> channel_id_source_;
-
- // True if ECDSA should be disabled.
- bool disable_ecdsa_;
-
- // The |user_agent_id_| passed in QUIC's CHLO message.
- std::string user_agent_id_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientConfig);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_QUIC_CRYPTO_CLIENT_CONFIG_H_
diff --git a/chromium/net/quic/crypto/quic_crypto_client_config_test.cc b/chromium/net/quic/crypto/quic_crypto_client_config_test.cc
deleted file mode 100644
index d15f6b0cdb6..00000000000
--- a/chromium/net/quic/crypto/quic_crypto_client_config_test.cc
+++ /dev/null
@@ -1,483 +0,0 @@
-// Copyright 2013 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/crypto/quic_crypto_client_config.h"
-
-#include "net/quic/crypto/proof_verifier.h"
-#include "net/quic/quic_server_id.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/mock_random.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::string;
-using std::vector;
-
-namespace net {
-namespace test {
-namespace {
-
-class TestProofVerifyDetails : public ProofVerifyDetails {
- ~TestProofVerifyDetails() override {}
-
- // ProofVerifyDetails implementation
- ProofVerifyDetails* Clone() const override {
- return new TestProofVerifyDetails;
- }
-};
-
-} // namespace
-
-TEST(QuicCryptoClientConfigTest, CachedState_IsEmpty) {
- QuicCryptoClientConfig::CachedState state;
- EXPECT_TRUE(state.IsEmpty());
-}
-
-TEST(QuicCryptoClientConfigTest, CachedState_IsComplete) {
- QuicCryptoClientConfig::CachedState state;
- EXPECT_FALSE(state.IsComplete(QuicWallTime::FromUNIXSeconds(0)));
-}
-
-TEST(QuicCryptoClientConfigTest, CachedState_GenerationCounter) {
- QuicCryptoClientConfig::CachedState state;
- EXPECT_EQ(0u, state.generation_counter());
- state.SetProofInvalid();
- EXPECT_EQ(1u, state.generation_counter());
-}
-
-TEST(QuicCryptoClientConfigTest, CachedState_SetProofVerifyDetails) {
- QuicCryptoClientConfig::CachedState state;
- EXPECT_TRUE(state.proof_verify_details() == nullptr);
- ProofVerifyDetails* details = new TestProofVerifyDetails;
- state.SetProofVerifyDetails(details);
- EXPECT_EQ(details, state.proof_verify_details());
-}
-
-TEST(QuicCryptoClientConfigTest, CachedState_ServerDesignatedConnectionId) {
- QuicCryptoClientConfig::CachedState state;
- EXPECT_FALSE(state.has_server_designated_connection_id());
-
- QuicConnectionId connection_id = 1234;
- state.add_server_designated_connection_id(connection_id);
- EXPECT_TRUE(state.has_server_designated_connection_id());
- EXPECT_EQ(connection_id, state.GetNextServerDesignatedConnectionId());
- EXPECT_FALSE(state.has_server_designated_connection_id());
-
- // Allow the ID to be set multiple times. It's unusual that this would
- // happen, but not impossible.
- ++connection_id;
- state.add_server_designated_connection_id(connection_id);
- EXPECT_TRUE(state.has_server_designated_connection_id());
- EXPECT_EQ(connection_id, state.GetNextServerDesignatedConnectionId());
- ++connection_id;
- state.add_server_designated_connection_id(connection_id);
- EXPECT_EQ(connection_id, state.GetNextServerDesignatedConnectionId());
- EXPECT_FALSE(state.has_server_designated_connection_id());
-
- // Test FIFO behavior.
- const QuicConnectionId first_cid = 0xdeadbeef;
- const QuicConnectionId second_cid = 0xfeedbead;
- state.add_server_designated_connection_id(first_cid);
- state.add_server_designated_connection_id(second_cid);
- EXPECT_TRUE(state.has_server_designated_connection_id());
- EXPECT_EQ(first_cid, state.GetNextServerDesignatedConnectionId());
- EXPECT_EQ(second_cid, state.GetNextServerDesignatedConnectionId());
-}
-
-TEST(QuicCryptoClientConfigTest, CachedState_ServerIdConsumedBeforeSet) {
- QuicCryptoClientConfig::CachedState state;
- EXPECT_FALSE(state.has_server_designated_connection_id());
-#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
- EXPECT_DEBUG_DEATH(state.GetNextServerDesignatedConnectionId(),
- "Attempting to consume a connection id "
- "that was never designated.");
-#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
-}
-
-TEST(QuicCryptoClientConfigTest, CachedState_ServerNonce) {
- QuicCryptoClientConfig::CachedState state;
- EXPECT_FALSE(state.has_server_nonce());
-
- string server_nonce = "nonce_1";
- state.add_server_nonce(server_nonce);
- EXPECT_TRUE(state.has_server_nonce());
- EXPECT_EQ(server_nonce, state.GetNextServerNonce());
- EXPECT_FALSE(state.has_server_nonce());
-
- // Allow the ID to be set multiple times. It's unusual that this would
- // happen, but not impossible.
- server_nonce = "nonce_2";
- state.add_server_nonce(server_nonce);
- EXPECT_TRUE(state.has_server_nonce());
- EXPECT_EQ(server_nonce, state.GetNextServerNonce());
- server_nonce = "nonce_3";
- state.add_server_nonce(server_nonce);
- EXPECT_EQ(server_nonce, state.GetNextServerNonce());
- EXPECT_FALSE(state.has_server_nonce());
-
- // Test FIFO behavior.
- const string first_nonce = "first_nonce";
- const string second_nonce = "second_nonce";
- state.add_server_nonce(first_nonce);
- state.add_server_nonce(second_nonce);
- EXPECT_TRUE(state.has_server_nonce());
- EXPECT_EQ(first_nonce, state.GetNextServerNonce());
- EXPECT_EQ(second_nonce, state.GetNextServerNonce());
-}
-
-TEST(QuicCryptoClientConfigTest, CachedState_ServerNonceConsumedBeforeSet) {
- QuicCryptoClientConfig::CachedState state;
- EXPECT_FALSE(state.has_server_nonce());
-#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
- EXPECT_DEBUG_DEATH(state.GetNextServerNonce(),
- "Attempting to consume a server nonce "
- "that was never designated.");
-#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
-}
-
-TEST(QuicCryptoClientConfigTest, CachedState_InitializeFrom) {
- QuicCryptoClientConfig::CachedState state;
- QuicCryptoClientConfig::CachedState other;
- state.set_source_address_token("TOKEN");
- // TODO(rch): Populate other fields of |state|.
- other.InitializeFrom(state);
- EXPECT_EQ(state.server_config(), other.server_config());
- EXPECT_EQ(state.source_address_token(), other.source_address_token());
- EXPECT_EQ(state.certs(), other.certs());
- EXPECT_EQ(1u, other.generation_counter());
- EXPECT_FALSE(state.has_server_designated_connection_id());
- EXPECT_FALSE(state.has_server_nonce());
-}
-
-TEST(QuicCryptoClientConfigTest, InchoateChlo) {
- QuicCryptoClientConfig::CachedState state;
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- QuicCryptoNegotiatedParameters params;
- CryptoHandshakeMessage msg;
- QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
- MockRandom rand;
- config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
- &params, &msg);
-
- QuicTag cver;
- EXPECT_EQ(QUIC_NO_ERROR, msg.GetUint32(kVER, &cver));
- EXPECT_EQ(QuicVersionToQuicTag(QuicVersionMax()), cver);
- StringPiece proof_nonce;
- EXPECT_TRUE(msg.GetStringPiece(kNONP, &proof_nonce));
- EXPECT_EQ(string(32, 'r'), proof_nonce);
-}
-
-TEST(QuicCryptoClientConfigTest, PreferAesGcm) {
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- if (config.aead.size() > 1)
- EXPECT_NE(kAESG, config.aead[0]);
- config.PreferAesGcm();
- EXPECT_EQ(kAESG, config.aead[0]);
-}
-
-TEST(QuicCryptoClientConfigTest, InchoateChloSecure) {
- QuicCryptoClientConfig::CachedState state;
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- QuicCryptoNegotiatedParameters params;
- CryptoHandshakeMessage msg;
- QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
- MockRandom rand;
- config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
- &params, &msg);
-
- QuicTag pdmd;
- EXPECT_EQ(QUIC_NO_ERROR, msg.GetUint32(kPDMD, &pdmd));
- EXPECT_EQ(kX509, pdmd);
- StringPiece scid;
- EXPECT_FALSE(msg.GetStringPiece(kSCID, &scid));
-}
-
-TEST(QuicCryptoClientConfigTest, InchoateChloSecureWithSCID) {
- QuicCryptoClientConfig::CachedState state;
- CryptoHandshakeMessage scfg;
- scfg.set_tag(kSCFG);
- uint64_t future = 1;
- scfg.SetValue(kEXPY, future);
- scfg.SetStringPiece(kSCID, "12345678");
- string details;
- state.SetServerConfig(scfg.GetSerialized().AsStringPiece(),
- QuicWallTime::FromUNIXSeconds(0), &details);
-
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- QuicCryptoNegotiatedParameters params;
- CryptoHandshakeMessage msg;
- QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
- MockRandom rand;
- config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
- &params, &msg);
-
- StringPiece scid;
- EXPECT_TRUE(msg.GetStringPiece(kSCID, &scid));
- EXPECT_EQ("12345678", scid);
-}
-
-TEST(QuicCryptoClientConfigTest, InchoateChloSecureNoEcdsa) {
- QuicCryptoClientConfig::CachedState state;
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- config.DisableEcdsa();
- QuicCryptoNegotiatedParameters params;
- CryptoHandshakeMessage msg;
- QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
- MockRandom rand;
- config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
- &params, &msg);
-
- QuicTag pdmd;
- EXPECT_EQ(QUIC_NO_ERROR, msg.GetUint32(kPDMD, &pdmd));
- EXPECT_EQ(kX59R, pdmd);
-}
-
-TEST(QuicCryptoClientConfigTest, FillClientHello) {
- QuicCryptoClientConfig::CachedState state;
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- QuicCryptoNegotiatedParameters params;
- QuicConnectionId kConnectionId = 1234;
- string error_details;
- MockRandom rand;
- CryptoHandshakeMessage chlo;
- QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
- config.FillClientHello(server_id, kConnectionId, QuicVersionMax(),
- QuicVersionMax(), &state, QuicWallTime::Zero(), &rand,
- nullptr, // channel_id_key
- &params, &chlo, &error_details);
-
- // Verify that certain QuicTags have been set correctly in the CHLO.
- QuicTag cver;
- EXPECT_EQ(QUIC_NO_ERROR, chlo.GetUint32(kVER, &cver));
- EXPECT_EQ(QuicVersionToQuicTag(QuicVersionMax()), cver);
-}
-
-TEST(QuicCryptoClientConfigTest, ProcessServerDowngradeAttack) {
- QuicVersionVector supported_versions = QuicSupportedVersions();
- if (supported_versions.size() == 1) {
- // No downgrade attack is possible if the client only supports one version.
- return;
- }
- QuicTagVector supported_version_tags;
- for (size_t i = supported_versions.size(); i > 0; --i) {
- supported_version_tags.push_back(
- QuicVersionToQuicTag(supported_versions[i - 1]));
- }
- CryptoHandshakeMessage msg;
- msg.set_tag(kSHLO);
- msg.SetVector(kVER, supported_version_tags);
-
- QuicCryptoClientConfig::CachedState cached;
- QuicCryptoNegotiatedParameters out_params;
- string error;
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- EXPECT_EQ(QUIC_VERSION_NEGOTIATION_MISMATCH,
- config.ProcessServerHello(msg, 0, supported_versions.front(),
- supported_versions, &cached, &out_params,
- &error));
- EXPECT_EQ("Downgrade attack detected", error);
-}
-
-TEST(QuicCryptoClientConfigTest, InitializeFrom) {
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- QuicServerId canonical_server_id("www.google.com", 443,
- PRIVACY_MODE_DISABLED);
- QuicCryptoClientConfig::CachedState* state =
- config.LookupOrCreate(canonical_server_id);
- // TODO(rch): Populate other fields of |state|.
- state->set_source_address_token("TOKEN");
- state->SetProofValid();
-
- QuicServerId other_server_id("mail.google.com", 443, PRIVACY_MODE_DISABLED);
- config.InitializeFrom(other_server_id, canonical_server_id, &config);
- QuicCryptoClientConfig::CachedState* other =
- config.LookupOrCreate(other_server_id);
-
- EXPECT_EQ(state->server_config(), other->server_config());
- EXPECT_EQ(state->source_address_token(), other->source_address_token());
- EXPECT_EQ(state->certs(), other->certs());
- EXPECT_EQ(1u, other->generation_counter());
-}
-
-TEST(QuicCryptoClientConfigTest, Canonical) {
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- config.AddCanonicalSuffix(".google.com");
- QuicServerId canonical_id1("www.google.com", 443, PRIVACY_MODE_DISABLED);
- QuicServerId canonical_id2("mail.google.com", 443, PRIVACY_MODE_DISABLED);
- QuicCryptoClientConfig::CachedState* state =
- config.LookupOrCreate(canonical_id1);
- // TODO(rch): Populate other fields of |state|.
- state->set_source_address_token("TOKEN");
- state->SetProofValid();
-
- QuicCryptoClientConfig::CachedState* other =
- config.LookupOrCreate(canonical_id2);
-
- EXPECT_TRUE(state->IsEmpty());
- EXPECT_EQ(state->server_config(), other->server_config());
- EXPECT_EQ(state->source_address_token(), other->source_address_token());
- EXPECT_EQ(state->certs(), other->certs());
- EXPECT_EQ(1u, other->generation_counter());
-
- QuicServerId different_id("mail.google.org", 443, PRIVACY_MODE_DISABLED);
- EXPECT_TRUE(config.LookupOrCreate(different_id)->IsEmpty());
-}
-
-TEST(QuicCryptoClientConfigTest, CanonicalNotUsedIfNotValid) {
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- config.AddCanonicalSuffix(".google.com");
- QuicServerId canonical_id1("www.google.com", 443, PRIVACY_MODE_DISABLED);
- QuicServerId canonical_id2("mail.google.com", 443, PRIVACY_MODE_DISABLED);
- QuicCryptoClientConfig::CachedState* state =
- config.LookupOrCreate(canonical_id1);
- // TODO(rch): Populate other fields of |state|.
- state->set_source_address_token("TOKEN");
-
- // Do not set the proof as valid, and check that it is not used
- // as a canonical entry.
- EXPECT_TRUE(config.LookupOrCreate(canonical_id2)->IsEmpty());
-}
-
-TEST(QuicCryptoClientConfigTest, ClearCachedStates) {
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
- QuicCryptoClientConfig::CachedState* state = config.LookupOrCreate(server_id);
- // TODO(rch): Populate other fields of |state|.
- vector<string> certs(1);
- certs[0] = "Hello Cert";
- state->SetProof(certs, "cert_sct", "chlo_hash", "signature");
- state->set_source_address_token("TOKEN");
- state->SetProofValid();
- EXPECT_EQ(1u, state->generation_counter());
-
- // Verify LookupOrCreate returns the same data.
- QuicCryptoClientConfig::CachedState* other = config.LookupOrCreate(server_id);
-
- EXPECT_EQ(state, other);
- EXPECT_EQ(1u, other->generation_counter());
-
- // Clear the cached states.
- config.ClearCachedStates();
-
- // Verify LookupOrCreate doesn't have any data.
- QuicCryptoClientConfig::CachedState* cleared_cache =
- config.LookupOrCreate(server_id);
-
- EXPECT_EQ(state, cleared_cache);
- EXPECT_FALSE(cleared_cache->proof_valid());
- EXPECT_TRUE(cleared_cache->server_config().empty());
- EXPECT_TRUE(cleared_cache->certs().empty());
- EXPECT_TRUE(cleared_cache->cert_sct().empty());
- EXPECT_TRUE(cleared_cache->signature().empty());
- EXPECT_EQ(2u, cleared_cache->generation_counter());
-}
-
-TEST(QuicCryptoClientConfigTest, ProcessReject) {
- CryptoHandshakeMessage rej;
- CryptoTestUtils::FillInDummyReject(&rej, /* stateless */ false);
-
- // Now process the rejection.
- QuicCryptoClientConfig::CachedState cached;
- QuicCryptoNegotiatedParameters out_params;
- string error;
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- EXPECT_EQ(QUIC_NO_ERROR,
- config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0),
- QuicSupportedVersions().front(), "",
- &cached, &out_params, &error));
- EXPECT_FALSE(cached.has_server_designated_connection_id());
- EXPECT_FALSE(cached.has_server_nonce());
-}
-
-TEST(QuicCryptoClientConfigTest, ProcessStatelessReject) {
- // Create a dummy reject message and mark it as stateless.
- CryptoHandshakeMessage rej;
- CryptoTestUtils::FillInDummyReject(&rej, /* stateless */ true);
- const QuicConnectionId kConnectionId = 0xdeadbeef;
- const string server_nonce = "SERVER_NONCE";
- rej.SetValue(kRCID, kConnectionId);
- rej.SetStringPiece(kServerNonceTag, server_nonce);
-
- // Now process the rejection.
- QuicCryptoClientConfig::CachedState cached;
- QuicCryptoNegotiatedParameters out_params;
- string error;
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- EXPECT_EQ(QUIC_NO_ERROR,
- config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0),
- QuicSupportedVersions().front(), "",
- &cached, &out_params, &error));
- EXPECT_TRUE(cached.has_server_designated_connection_id());
- EXPECT_EQ(kConnectionId, cached.GetNextServerDesignatedConnectionId());
- EXPECT_EQ(server_nonce, cached.GetNextServerNonce());
-}
-
-TEST(QuicCryptoClientConfigTest, BadlyFormattedStatelessReject) {
- // Create a dummy reject message and mark it as stateless. Do not
- // add an server-designated connection-id.
- CryptoHandshakeMessage rej;
- CryptoTestUtils::FillInDummyReject(&rej, /* stateless */ true);
-
- // Now process the rejection.
- QuicCryptoClientConfig::CachedState cached;
- QuicCryptoNegotiatedParameters out_params;
- string error;
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
- config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0),
- QuicSupportedVersions().front(), "",
- &cached, &out_params, &error));
- EXPECT_FALSE(cached.has_server_designated_connection_id());
- EXPECT_EQ("Missing kRCID", error);
-}
-
-TEST(QuicCryptoClientConfigTest, ServerNonceinSHLO_BeforeQ027) {
- // Test that in QUIC_VERSION_26 and lower, the the server does not need to
- // include a nonce in the SHLO.
- CryptoHandshakeMessage msg;
- msg.set_tag(kSHLO);
- // Choose the lowest version.
- QuicVersionVector supported_versions;
- QuicVersion version = QuicSupportedVersions().back();
- supported_versions.push_back(version);
- EXPECT_LE(version, QUIC_VERSION_26);
- QuicTagVector versions;
- versions.push_back(QuicVersionToQuicTag(version));
- msg.SetVector(kVER, versions);
-
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- QuicCryptoClientConfig::CachedState cached;
- QuicCryptoNegotiatedParameters out_params;
- string error_details;
- config.ProcessServerHello(msg, 0, version, supported_versions, &cached,
- &out_params, &error_details);
- EXPECT_NE("server hello missing server nonce", error_details);
-}
-
-TEST(QuicCryptoClientConfigTest, ServerNonceinSHLO_AfterQ027) {
- // Test that in QUIC_VERSION_27 and higher, the the server must include a
- // nonce in the SHLO.
- CryptoHandshakeMessage msg;
- msg.set_tag(kSHLO);
- // Choose the latest version.
- QuicVersionVector supported_versions;
- QuicVersion version = QuicSupportedVersions().front();
- supported_versions.push_back(version);
- EXPECT_LE(QUIC_VERSION_27, version);
- QuicTagVector versions;
- versions.push_back(QuicVersionToQuicTag(version));
- msg.SetVector(kVER, versions);
-
- QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
- QuicCryptoClientConfig::CachedState cached;
- QuicCryptoNegotiatedParameters out_params;
- string error_details;
- EXPECT_EQ(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
- config.ProcessServerHello(msg, 0, version, supported_versions,
- &cached, &out_params, &error_details));
- EXPECT_EQ("server hello missing server nonce", error_details);
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/quic_crypto_server_config.cc b/chromium/net/quic/crypto/quic_crypto_server_config.cc
deleted file mode 100644
index df3a3ced137..00000000000
--- a/chromium/net/quic/crypto/quic_crypto_server_config.cc
+++ /dev/null
@@ -1,1835 +0,0 @@
-// Copyright 2013 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/crypto/quic_crypto_server_config.h"
-
-#include <stdlib.h>
-
-#include <algorithm>
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/stl_util.h"
-#include "crypto/hkdf.h"
-#include "crypto/secure_hash.h"
-#include "net/base/ip_address.h"
-#include "net/quic/crypto/aes_128_gcm_12_decrypter.h"
-#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
-#include "net/quic/crypto/cert_compressor.h"
-#include "net/quic/crypto/chacha20_poly1305_encrypter.h"
-#include "net/quic/crypto/channel_id.h"
-#include "net/quic/crypto/crypto_framer.h"
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/crypto/crypto_server_config_protobuf.h"
-#include "net/quic/crypto/crypto_utils.h"
-#include "net/quic/crypto/curve25519_key_exchange.h"
-#include "net/quic/crypto/ephemeral_key_source.h"
-#include "net/quic/crypto/key_exchange.h"
-#include "net/quic/crypto/local_strike_register_client.h"
-#include "net/quic/crypto/p256_key_exchange.h"
-#include "net/quic/crypto/proof_source.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/crypto/strike_register.h"
-#include "net/quic/crypto/strike_register_client.h"
-#include "net/quic/proto/source_address_token.pb.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_socket_address_coder.h"
-#include "net/quic/quic_utils.h"
-
-using base::StringPiece;
-using crypto::SecureHash;
-using std::map;
-using std::sort;
-using std::string;
-using std::vector;
-
-namespace net {
-
-namespace {
-
-// kMultiplier is the multiple of the CHLO message size that a REJ message
-// must stay under when the client doesn't present a valid source-address
-// token. This is used to protect QUIC from amplification attacks.
-// TODO(rch): Reduce this to 2 again once b/25933682 is fixed.
-const size_t kMultiplier = 3;
-
-const int kMaxTokenAddresses = 4;
-
-string DeriveSourceAddressTokenKey(StringPiece source_address_token_secret) {
- crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */,
- "QUIC source address token key",
- CryptoSecretBoxer::GetKeySize(), 0 /* no fixed IV needed */,
- 0 /* no subkey secret */);
- return hkdf.server_write_key().as_string();
-}
-
-IPAddress DualstackIPAddress(const IPAddress& ip) {
- if (ip.IsIPv4()) {
- return ConvertIPv4ToIPv4MappedIPv6(ip);
- }
- return ip;
-}
-
-} // namespace
-
-class ValidateClientHelloHelper {
- public:
- ValidateClientHelloHelper(ValidateClientHelloResultCallback::Result* result,
- ValidateClientHelloResultCallback* done_cb)
- : result_(result), done_cb_(done_cb) {}
-
- ~ValidateClientHelloHelper() {
- QUIC_BUG_IF(done_cb_ != nullptr)
- << "Deleting ValidateClientHelloHelper with a pending callback.";
- }
-
- void ValidationComplete(QuicErrorCode error_code, const char* error_details) {
- result_->error_code = error_code;
- result_->error_details = error_details;
- done_cb_->Run(result_);
- DetachCallback();
- }
-
- void StartedAsyncCallback() { DetachCallback(); }
-
- private:
- void DetachCallback() {
- QUIC_BUG_IF(done_cb_ == nullptr) << "Callback already detached.";
- done_cb_ = nullptr;
- }
-
- ValidateClientHelloResultCallback::Result* result_;
- ValidateClientHelloResultCallback* done_cb_;
-
- DISALLOW_COPY_AND_ASSIGN(ValidateClientHelloHelper);
-};
-
-class VerifyNonceIsValidAndUniqueCallback
- : public StrikeRegisterClient::ResultCallback {
- public:
- VerifyNonceIsValidAndUniqueCallback(
- ValidateClientHelloResultCallback::Result* result,
- ValidateClientHelloResultCallback* done_cb)
- : result_(result), done_cb_(done_cb) {}
-
- protected:
- void RunImpl(bool nonce_is_valid_and_unique,
- InsertStatus nonce_error) override {
- DVLOG(1) << "Using client nonce, unique: " << nonce_is_valid_and_unique
- << " nonce_error: " << nonce_error;
- if (!nonce_is_valid_and_unique) {
- HandshakeFailureReason client_nonce_error;
- switch (nonce_error) {
- case NONCE_INVALID_FAILURE:
- client_nonce_error = CLIENT_NONCE_INVALID_FAILURE;
- break;
- case NONCE_NOT_UNIQUE_FAILURE:
- client_nonce_error = CLIENT_NONCE_NOT_UNIQUE_FAILURE;
- break;
- case NONCE_INVALID_ORBIT_FAILURE:
- client_nonce_error = CLIENT_NONCE_INVALID_ORBIT_FAILURE;
- break;
- case NONCE_INVALID_TIME_FAILURE:
- client_nonce_error = CLIENT_NONCE_INVALID_TIME_FAILURE;
- break;
- case STRIKE_REGISTER_TIMEOUT:
- client_nonce_error = CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT;
- break;
- case STRIKE_REGISTER_FAILURE:
- client_nonce_error = CLIENT_NONCE_STRIKE_REGISTER_FAILURE;
- break;
- case NONCE_UNKNOWN_FAILURE:
- client_nonce_error = CLIENT_NONCE_UNKNOWN_FAILURE;
- break;
- case NONCE_OK:
- default:
- QUIC_BUG << "Unexpected client nonce error: " << nonce_error;
- client_nonce_error = CLIENT_NONCE_UNKNOWN_FAILURE;
- break;
- }
- result_->info.reject_reasons.push_back(client_nonce_error);
- }
- done_cb_->Run(result_);
- }
-
- private:
- ValidateClientHelloResultCallback::Result* result_;
- ValidateClientHelloResultCallback* done_cb_;
-
- DISALLOW_COPY_AND_ASSIGN(VerifyNonceIsValidAndUniqueCallback);
-};
-
-// static
-const char QuicCryptoServerConfig::TESTING[] = "secret string for testing";
-
-ClientHelloInfo::ClientHelloInfo(const IPAddress& in_client_ip,
- QuicWallTime in_now)
- : client_ip(in_client_ip), now(in_now), valid_source_address_token(false) {}
-
-ClientHelloInfo::~ClientHelloInfo() {}
-
-PrimaryConfigChangedCallback::PrimaryConfigChangedCallback() {}
-
-PrimaryConfigChangedCallback::~PrimaryConfigChangedCallback() {}
-
-ValidateClientHelloResultCallback::Result::Result(
- const CryptoHandshakeMessage& in_client_hello,
- IPAddress in_client_ip,
- QuicWallTime in_now)
- : client_hello(in_client_hello),
- info(in_client_ip, in_now),
- error_code(QUIC_NO_ERROR) {}
-
-ValidateClientHelloResultCallback::Result::~Result() {}
-
-ValidateClientHelloResultCallback::ValidateClientHelloResultCallback() {}
-
-ValidateClientHelloResultCallback::~ValidateClientHelloResultCallback() {}
-
-void ValidateClientHelloResultCallback::Run(const Result* result) {
- RunImpl(result->client_hello, *result);
- delete result;
- delete this;
-}
-
-QuicCryptoServerConfig::ConfigOptions::ConfigOptions()
- : expiry_time(QuicWallTime::Zero()),
- channel_id_enabled(false),
- token_binding_enabled(false),
- p256(false) {}
-
-QuicCryptoServerConfig::ConfigOptions::ConfigOptions(
- const ConfigOptions& other) = default;
-
-QuicCryptoServerConfig::QuicCryptoServerConfig(
- StringPiece source_address_token_secret,
- QuicRandom* server_nonce_entropy,
- ProofSource* proof_source)
- : replay_protection_(true),
- chlo_multiplier_(kMultiplier),
- configs_lock_(),
- primary_config_(nullptr),
- next_config_promotion_time_(QuicWallTime::Zero()),
- server_nonce_strike_register_lock_(),
- proof_source_(proof_source),
- strike_register_no_startup_period_(false),
- strike_register_max_entries_(1 << 10),
- strike_register_window_secs_(600),
- source_address_token_future_secs_(3600),
- source_address_token_lifetime_secs_(86400),
- server_nonce_strike_register_max_entries_(1 << 10),
- server_nonce_strike_register_window_secs_(120),
- enable_serving_sct_(false) {
- DCHECK(proof_source_.get());
- default_source_address_token_boxer_.SetKeys(
- {DeriveSourceAddressTokenKey(source_address_token_secret)});
-
- // Generate a random key and orbit for server nonces.
- server_nonce_entropy->RandBytes(server_nonce_orbit_,
- sizeof(server_nonce_orbit_));
- const size_t key_size = server_nonce_boxer_.GetKeySize();
- std::unique_ptr<uint8_t[]> key_bytes(new uint8_t[key_size]);
- server_nonce_entropy->RandBytes(key_bytes.get(), key_size);
-
- server_nonce_boxer_.SetKeys(
- {string(reinterpret_cast<char*>(key_bytes.get()), key_size)});
-}
-
-QuicCryptoServerConfig::~QuicCryptoServerConfig() {
- primary_config_ = nullptr;
-}
-
-// static
-QuicServerConfigProtobuf* QuicCryptoServerConfig::GenerateConfig(
- QuicRandom* rand,
- const QuicClock* clock,
- const ConfigOptions& options) {
- CryptoHandshakeMessage msg;
-
- const string curve25519_private_key =
- Curve25519KeyExchange::NewPrivateKey(rand);
- std::unique_ptr<Curve25519KeyExchange> curve25519(
- Curve25519KeyExchange::New(curve25519_private_key));
- StringPiece curve25519_public_value = curve25519->public_value();
-
- string encoded_public_values;
- // First three bytes encode the length of the public value.
- DCHECK_LT(curve25519_public_value.size(), (1U << 24));
- encoded_public_values.push_back(
- static_cast<char>(curve25519_public_value.size()));
- encoded_public_values.push_back(
- static_cast<char>(curve25519_public_value.size() >> 8));
- encoded_public_values.push_back(
- static_cast<char>(curve25519_public_value.size() >> 16));
- encoded_public_values.append(curve25519_public_value.data(),
- curve25519_public_value.size());
-
- string p256_private_key;
- if (options.p256) {
- p256_private_key = P256KeyExchange::NewPrivateKey();
- std::unique_ptr<P256KeyExchange> p256(
- P256KeyExchange::New(p256_private_key));
- StringPiece p256_public_value = p256->public_value();
-
- DCHECK_LT(p256_public_value.size(), (1U << 24));
- encoded_public_values.push_back(
- static_cast<char>(p256_public_value.size()));
- encoded_public_values.push_back(
- static_cast<char>(p256_public_value.size() >> 8));
- encoded_public_values.push_back(
- static_cast<char>(p256_public_value.size() >> 16));
- encoded_public_values.append(p256_public_value.data(),
- p256_public_value.size());
- }
-
- msg.set_tag(kSCFG);
- if (options.p256) {
- msg.SetVector(kKEXS, QuicTagVector{kC255, kP256});
- } else {
- msg.SetVector(kKEXS, QuicTagVector{kC255});
- }
- msg.SetVector(kAEAD, QuicTagVector{kAESG, kCC20});
- msg.SetStringPiece(kPUBS, encoded_public_values);
-
- if (options.expiry_time.IsZero()) {
- const QuicWallTime now = clock->WallNow();
- const QuicWallTime expiry = now.Add(QuicTime::Delta::FromSeconds(
- 60 * 60 * 24 * 180 /* 180 days, ~six months */));
- const uint64_t expiry_seconds = expiry.ToUNIXSeconds();
- msg.SetValue(kEXPY, expiry_seconds);
- } else {
- msg.SetValue(kEXPY, options.expiry_time.ToUNIXSeconds());
- }
-
- char orbit_bytes[kOrbitSize];
- if (options.orbit.size() == sizeof(orbit_bytes)) {
- memcpy(orbit_bytes, options.orbit.data(), sizeof(orbit_bytes));
- } else {
- DCHECK(options.orbit.empty());
- rand->RandBytes(orbit_bytes, sizeof(orbit_bytes));
- }
- msg.SetStringPiece(kORBT, StringPiece(orbit_bytes, sizeof(orbit_bytes)));
-
- if (options.channel_id_enabled) {
- msg.SetVector(kPDMD, QuicTagVector{kCHID});
- }
-
- if (options.token_binding_enabled) {
- msg.SetVector(kTBKP, QuicTagVector{kP256});
- }
-
- if (options.id.empty()) {
- // We need to ensure that the SCID changes whenever the server config does
- // thus we make it a hash of the rest of the server config.
- std::unique_ptr<QuicData> serialized(
- CryptoFramer::ConstructHandshakeMessage(msg));
- std::unique_ptr<SecureHash> hash(SecureHash::Create(SecureHash::SHA256));
- hash->Update(serialized->data(), serialized->length());
-
- char scid_bytes[16];
- hash->Finish(scid_bytes, sizeof(scid_bytes));
- msg.SetStringPiece(kSCID, StringPiece(scid_bytes, sizeof(scid_bytes)));
- } else {
- msg.SetStringPiece(kSCID, options.id);
- }
- // Don't put new tags below this point. The SCID generation should hash over
- // everything but itself and so extra tags should be added prior to the
- // preceeding if block.
-
- std::unique_ptr<QuicData> serialized(
- CryptoFramer::ConstructHandshakeMessage(msg));
-
- std::unique_ptr<QuicServerConfigProtobuf> config(
- new QuicServerConfigProtobuf);
- config->set_config(serialized->AsStringPiece());
- QuicServerConfigProtobuf::PrivateKey* curve25519_key = config->add_key();
- curve25519_key->set_tag(kC255);
- curve25519_key->set_private_key(curve25519_private_key);
-
- if (options.p256) {
- QuicServerConfigProtobuf::PrivateKey* p256_key = config->add_key();
- p256_key->set_tag(kP256);
- p256_key->set_private_key(p256_private_key);
- }
-
- return config.release();
-}
-
-CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig(
- QuicServerConfigProtobuf* protobuf,
- const QuicWallTime now) {
- std::unique_ptr<CryptoHandshakeMessage> msg(
- CryptoFramer::ParseMessage(protobuf->config()));
-
- if (!msg.get()) {
- LOG(WARNING) << "Failed to parse server config message";
- return nullptr;
- }
-
- scoped_refptr<Config> config(ParseConfigProtobuf(protobuf));
- if (!config.get()) {
- LOG(WARNING) << "Failed to parse server config message";
- return nullptr;
- }
-
- {
- base::AutoLock locked(configs_lock_);
- if (configs_.find(config->id) != configs_.end()) {
- LOG(WARNING) << "Failed to add config because another with the same "
- "server config id already exists: "
- << QuicUtils::HexEncode(config->id);
- return nullptr;
- }
-
- configs_[config->id] = config;
- SelectNewPrimaryConfig(now);
- DCHECK(primary_config_.get());
- DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
- }
-
- return msg.release();
-}
-
-CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig(
- QuicRandom* rand,
- const QuicClock* clock,
- const ConfigOptions& options) {
- std::unique_ptr<QuicServerConfigProtobuf> config(
- GenerateConfig(rand, clock, options));
- return AddConfig(config.get(), clock->WallNow());
-}
-
-bool QuicCryptoServerConfig::SetConfigs(
- const vector<QuicServerConfigProtobuf*>& protobufs,
- const QuicWallTime now) {
- vector<scoped_refptr<Config>> parsed_configs;
- bool ok = true;
-
- for (vector<QuicServerConfigProtobuf*>::const_iterator i = protobufs.begin();
- i != protobufs.end(); ++i) {
- scoped_refptr<Config> config(ParseConfigProtobuf(*i));
- if (!config.get()) {
- ok = false;
- break;
- }
-
- parsed_configs.push_back(config);
- }
-
- if (parsed_configs.empty()) {
- LOG(WARNING) << "New config list is empty.";
- ok = false;
- }
-
- if (!ok) {
- LOG(WARNING) << "Rejecting QUIC configs because of above errors";
- } else {
- VLOG(1) << "Updating configs:";
-
- base::AutoLock locked(configs_lock_);
- ConfigMap new_configs;
-
- for (vector<scoped_refptr<Config>>::const_iterator i =
- parsed_configs.begin();
- i != parsed_configs.end(); ++i) {
- scoped_refptr<Config> config = *i;
-
- ConfigMap::iterator it = configs_.find(config->id);
- if (it != configs_.end()) {
- VLOG(1) << "Keeping scid: " << QuicUtils::HexEncode(config->id)
- << " orbit: "
- << QuicUtils::HexEncode(
- reinterpret_cast<const char*>(config->orbit), kOrbitSize)
- << " new primary_time " << config->primary_time.ToUNIXSeconds()
- << " old primary_time "
- << it->second->primary_time.ToUNIXSeconds() << " new priority "
- << config->priority << " old priority " << it->second->priority;
- // Update primary_time and priority.
- it->second->primary_time = config->primary_time;
- it->second->priority = config->priority;
- new_configs.insert(*it);
- } else {
- VLOG(1) << "Adding scid: " << QuicUtils::HexEncode(config->id)
- << " orbit: "
- << QuicUtils::HexEncode(
- reinterpret_cast<const char*>(config->orbit), kOrbitSize)
- << " primary_time " << config->primary_time.ToUNIXSeconds()
- << " priority " << config->priority;
- new_configs.insert(std::make_pair(config->id, config));
- }
- }
-
- configs_.swap(new_configs);
- SelectNewPrimaryConfig(now);
- DCHECK(primary_config_.get());
- DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
- }
-
- return ok;
-}
-
-void QuicCryptoServerConfig::SetDefaultSourceAddressTokenKeys(
- const vector<string>& keys) {
- default_source_address_token_boxer_.SetKeys(keys);
-}
-
-void QuicCryptoServerConfig::GetConfigIds(vector<string>* scids) const {
- base::AutoLock locked(configs_lock_);
- for (ConfigMap::const_iterator it = configs_.begin(); it != configs_.end();
- ++it) {
- scids->push_back(it->first);
- }
-}
-
-void QuicCryptoServerConfig::ValidateClientHello(
- const CryptoHandshakeMessage& client_hello,
- const IPAddress& client_ip,
- const IPAddress& server_ip,
- QuicVersion version,
- const QuicClock* clock,
- QuicCryptoProof* crypto_proof,
- ValidateClientHelloResultCallback* done_cb) const {
- const QuicWallTime now(clock->WallNow());
-
- ValidateClientHelloResultCallback::Result* result =
- new ValidateClientHelloResultCallback::Result(client_hello, client_ip,
- now);
-
- StringPiece requested_scid;
- client_hello.GetStringPiece(kSCID, &requested_scid);
-
- uint8_t primary_orbit[kOrbitSize];
- scoped_refptr<Config> requested_config;
- scoped_refptr<Config> primary_config;
- {
- base::AutoLock locked(configs_lock_);
-
- if (!primary_config_.get()) {
- result->error_code = QUIC_CRYPTO_INTERNAL_ERROR;
- result->error_details = "No configurations loaded";
- } else {
- if (!next_config_promotion_time_.IsZero() &&
- next_config_promotion_time_.IsAfter(now)) {
- SelectNewPrimaryConfig(now);
- DCHECK(primary_config_.get());
- DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
- }
-
- memcpy(primary_orbit, primary_config_->orbit, sizeof(primary_orbit));
- }
-
- requested_config = GetConfigWithScid(requested_scid);
- primary_config = primary_config_;
- crypto_proof->config = primary_config_;
- }
-
- if (result->error_code == QUIC_NO_ERROR) {
- EvaluateClientHello(server_ip, version, primary_orbit, requested_config,
- primary_config, crypto_proof, result, done_cb);
- } else {
- done_cb->Run(result);
- }
-}
-
-QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
- const ValidateClientHelloResultCallback::Result& validate_chlo_result,
- bool reject_only,
- QuicConnectionId connection_id,
- const IPAddress& server_ip,
- const IPEndPoint& client_address,
- QuicVersion version,
- const QuicVersionVector& supported_versions,
- bool use_stateless_rejects,
- QuicConnectionId server_designated_connection_id,
- const QuicClock* clock,
- QuicRandom* rand,
- QuicCompressedCertsCache* compressed_certs_cache,
- QuicCryptoNegotiatedParameters* params,
- QuicCryptoProof* crypto_proof,
- CryptoHandshakeMessage* out,
- DiversificationNonce* out_diversification_nonce,
- string* error_details) const {
- DCHECK(error_details);
-
- const CryptoHandshakeMessage& client_hello =
- validate_chlo_result.client_hello;
- const ClientHelloInfo& info = validate_chlo_result.info;
-
- QuicErrorCode valid = CryptoUtils::ValidateClientHello(
- client_hello, version, supported_versions, error_details);
- if (valid != QUIC_NO_ERROR)
- return valid;
-
- StringPiece requested_scid;
- client_hello.GetStringPiece(kSCID, &requested_scid);
- const QuicWallTime now(clock->WallNow());
-
- scoped_refptr<Config> requested_config;
- scoped_refptr<Config> primary_config;
- {
- base::AutoLock locked(configs_lock_);
-
- if (!primary_config_.get()) {
- *error_details = "No configurations loaded";
- return QUIC_CRYPTO_INTERNAL_ERROR;
- }
-
- if (!next_config_promotion_time_.IsZero() &&
- next_config_promotion_time_.IsAfter(now)) {
- SelectNewPrimaryConfig(now);
- DCHECK(primary_config_.get());
- DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
- }
-
- // Use the config that the client requested in order to do key-agreement.
- // Otherwise give it a copy of |primary_config_| to use.
- primary_config = crypto_proof->config;
- requested_config = GetConfigWithScid(requested_scid);
- }
-
- if (validate_chlo_result.error_code != QUIC_NO_ERROR) {
- *error_details = validate_chlo_result.error_details;
- return validate_chlo_result.error_code;
- }
-
- out->Clear();
-
- bool x509_supported = false;
- bool x509_ecdsa_supported = false;
- ParseProofDemand(client_hello, &x509_supported, &x509_ecdsa_supported);
- DCHECK(proof_source_.get());
- string chlo_hash;
- CryptoUtils::HashHandshakeMessage(client_hello, &chlo_hash);
- if (!crypto_proof->chain &&
- !proof_source_->GetProof(
- server_ip, info.sni.as_string(), primary_config->serialized, version,
- chlo_hash, x509_ecdsa_supported, &crypto_proof->chain,
- &crypto_proof->signature, &crypto_proof->cert_sct)) {
- return QUIC_HANDSHAKE_FAILED;
- }
-
- if (version > QUIC_VERSION_29) {
- StringPiece cert_sct;
- if (client_hello.GetStringPiece(kCertificateSCTTag, &cert_sct) &&
- cert_sct.empty()) {
- params->sct_supported_by_client = true;
- }
- }
-
- if (!info.reject_reasons.empty() || !requested_config.get()) {
- BuildRejection(version, *primary_config, client_hello, info,
- validate_chlo_result.cached_network_params,
- use_stateless_rejects, server_designated_connection_id, rand,
- compressed_certs_cache, params, *crypto_proof, out);
- return QUIC_NO_ERROR;
- }
-
- if (reject_only) {
- return QUIC_NO_ERROR;
- }
-
- const QuicTag* their_aeads;
- const QuicTag* their_key_exchanges;
- size_t num_their_aeads, num_their_key_exchanges;
- if (client_hello.GetTaglist(kAEAD, &their_aeads, &num_their_aeads) !=
- QUIC_NO_ERROR ||
- client_hello.GetTaglist(kKEXS, &their_key_exchanges,
- &num_their_key_exchanges) != QUIC_NO_ERROR ||
- num_their_aeads != 1 || num_their_key_exchanges != 1) {
- *error_details = "Missing or invalid AEAD or KEXS";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- size_t key_exchange_index;
- if (!QuicUtils::FindMutualTag(requested_config->aead, their_aeads,
- num_their_aeads, QuicUtils::LOCAL_PRIORITY,
- &params->aead, nullptr) ||
- !QuicUtils::FindMutualTag(requested_config->kexs, their_key_exchanges,
- num_their_key_exchanges,
- QuicUtils::LOCAL_PRIORITY,
- &params->key_exchange, &key_exchange_index)) {
- *error_details = "Unsupported AEAD or KEXS";
- return QUIC_CRYPTO_NO_SUPPORT;
- }
-
- if (!requested_config->tb_key_params.empty()) {
- const QuicTag* their_tbkps;
- size_t num_their_tbkps;
- switch (client_hello.GetTaglist(kTBKP, &their_tbkps, &num_their_tbkps)) {
- case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
- break;
- case QUIC_NO_ERROR:
- if (QuicUtils::FindMutualTag(
- requested_config->tb_key_params, their_tbkps, num_their_tbkps,
- QuicUtils::LOCAL_PRIORITY, &params->token_binding_key_param,
- nullptr)) {
- break;
- }
- default:
- *error_details = "Invalid Token Binding key parameter";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
- }
-
- StringPiece public_value;
- if (!client_hello.GetStringPiece(kPUBS, &public_value)) {
- *error_details = "Missing public value";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- const KeyExchange* key_exchange =
- requested_config->key_exchanges[key_exchange_index];
- if (!key_exchange->CalculateSharedKey(public_value,
- &params->initial_premaster_secret)) {
- *error_details = "Invalid public value";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- if (!info.sni.empty()) {
- std::unique_ptr<char[]> sni_tmp(new char[info.sni.length() + 1]);
- memcpy(sni_tmp.get(), info.sni.data(), info.sni.length());
- sni_tmp[info.sni.length()] = 0;
- params->sni = CryptoUtils::NormalizeHostname(sni_tmp.get());
- }
-
- string hkdf_suffix;
- const QuicData& client_hello_serialized = client_hello.GetSerialized();
- hkdf_suffix.reserve(sizeof(connection_id) + client_hello_serialized.length() +
- requested_config->serialized.size());
- hkdf_suffix.append(reinterpret_cast<char*>(&connection_id),
- sizeof(connection_id));
- hkdf_suffix.append(client_hello_serialized.data(),
- client_hello_serialized.length());
- hkdf_suffix.append(requested_config->serialized);
- DCHECK(proof_source_.get());
- if (version > QUIC_VERSION_25) {
- if (crypto_proof->chain->certs.empty()) {
- *error_details = "Failed to get certs";
- return QUIC_CRYPTO_INTERNAL_ERROR;
- }
- hkdf_suffix.append(crypto_proof->chain->certs.at(0));
- }
-
- StringPiece cetv_ciphertext;
- if (requested_config->channel_id_enabled &&
- client_hello.GetStringPiece(kCETV, &cetv_ciphertext)) {
- CryptoHandshakeMessage client_hello_copy(client_hello);
- client_hello_copy.Erase(kCETV);
- client_hello_copy.Erase(kPAD);
-
- const QuicData& client_hello_copy_serialized =
- client_hello_copy.GetSerialized();
- string hkdf_input;
- hkdf_input.append(QuicCryptoConfig::kCETVLabel,
- strlen(QuicCryptoConfig::kCETVLabel) + 1);
- hkdf_input.append(reinterpret_cast<char*>(&connection_id),
- sizeof(connection_id));
- hkdf_input.append(client_hello_copy_serialized.data(),
- client_hello_copy_serialized.length());
- hkdf_input.append(requested_config->serialized);
-
- CrypterPair crypters;
- if (!CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead,
- info.client_nonce, info.server_nonce,
- hkdf_input, Perspective::IS_SERVER,
- CryptoUtils::Diversification::Never(),
- &crypters, nullptr /* subkey secret */)) {
- *error_details = "Symmetric key setup failed";
- return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
- }
-
- char plaintext[kMaxPacketSize];
- size_t plaintext_length = 0;
- const bool success = crypters.decrypter->DecryptPacket(
- kDefaultPathId, 0 /* packet number */,
- StringPiece() /* associated data */, cetv_ciphertext, plaintext,
- &plaintext_length, kMaxPacketSize);
- if (!success) {
- *error_details = "CETV decryption failure";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
- std::unique_ptr<CryptoHandshakeMessage> cetv(
- CryptoFramer::ParseMessage(StringPiece(plaintext, plaintext_length)));
- if (!cetv.get()) {
- *error_details = "CETV parse error";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- StringPiece key, signature;
- if (cetv->GetStringPiece(kCIDK, &key) &&
- cetv->GetStringPiece(kCIDS, &signature)) {
- if (!ChannelIDVerifier::Verify(key, hkdf_input, signature)) {
- *error_details = "ChannelID signature failure";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
-
- params->channel_id = key.as_string();
- }
- }
-
- string hkdf_input;
- size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1;
- hkdf_input.reserve(label_len + hkdf_suffix.size());
- hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len);
- hkdf_input.append(hkdf_suffix);
-
- string* subkey_secret = &params->initial_subkey_secret;
- CryptoUtils::Diversification diversification =
- CryptoUtils::Diversification::Never();
- if (version > QUIC_VERSION_32) {
- rand->RandBytes(reinterpret_cast<char*>(out_diversification_nonce),
- sizeof(*out_diversification_nonce));
- diversification =
- CryptoUtils::Diversification::Now(out_diversification_nonce);
- }
-
- if (!CryptoUtils::DeriveKeys(params->initial_premaster_secret, params->aead,
- info.client_nonce, info.server_nonce, hkdf_input,
- Perspective::IS_SERVER, diversification,
- &params->initial_crypters, subkey_secret)) {
- *error_details = "Symmetric key setup failed";
- return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
- }
-
- string forward_secure_public_value;
- if (ephemeral_key_source_.get()) {
- params->forward_secure_premaster_secret =
- ephemeral_key_source_->CalculateForwardSecureKey(
- key_exchange, rand, clock->ApproximateNow(), public_value,
- &forward_secure_public_value);
- } else {
- std::unique_ptr<KeyExchange> forward_secure_key_exchange(
- key_exchange->NewKeyPair(rand));
- forward_secure_public_value =
- forward_secure_key_exchange->public_value().as_string();
- if (!forward_secure_key_exchange->CalculateSharedKey(
- public_value, &params->forward_secure_premaster_secret)) {
- *error_details = "Invalid public value";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
- }
- }
-
- string forward_secure_hkdf_input;
- label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
- forward_secure_hkdf_input.reserve(label_len + hkdf_suffix.size());
- forward_secure_hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel,
- label_len);
- forward_secure_hkdf_input.append(hkdf_suffix);
-
- string shlo_nonce;
- if (version > QUIC_VERSION_26) {
- shlo_nonce = NewServerNonce(rand, info.now);
- out->SetStringPiece(kServerNonceTag, shlo_nonce);
- }
-
- if (!CryptoUtils::DeriveKeys(
- params->forward_secure_premaster_secret, params->aead,
- info.client_nonce,
- shlo_nonce.empty() ? info.server_nonce : shlo_nonce,
- forward_secure_hkdf_input, Perspective::IS_SERVER,
- CryptoUtils::Diversification::Never(),
- &params->forward_secure_crypters, &params->subkey_secret)) {
- *error_details = "Symmetric key setup failed";
- return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED;
- }
-
- out->set_tag(kSHLO);
- QuicTagVector supported_version_tags;
- for (size_t i = 0; i < supported_versions.size(); ++i) {
- supported_version_tags.push_back(
- QuicVersionToQuicTag(supported_versions[i]));
- }
- out->SetVector(kVER, supported_version_tags);
- out->SetStringPiece(
- kSourceAddressTokenTag,
- NewSourceAddressToken(*requested_config.get(), info.source_address_tokens,
- client_address.address(), rand, info.now, nullptr));
- QuicSocketAddressCoder address_coder(client_address);
- out->SetStringPiece(kCADR, address_coder.Encode());
- out->SetStringPiece(kPUBS, forward_secure_public_value);
-
- return QUIC_NO_ERROR;
-}
-
-scoped_refptr<QuicCryptoServerConfig::Config>
-QuicCryptoServerConfig::GetConfigWithScid(StringPiece requested_scid) const {
- // In Chromium, we will dead lock if the lock is held by the current thread.
- // Chromium doesn't have AssertReaderHeld API call.
- // configs_lock_.AssertReaderHeld();
-
- if (!requested_scid.empty()) {
- ConfigMap::const_iterator it = configs_.find(requested_scid.as_string());
- if (it != configs_.end()) {
- // We'll use the config that the client requested in order to do
- // key-agreement.
- return scoped_refptr<Config>(it->second);
- }
- }
-
- return scoped_refptr<Config>();
-}
-
-// ConfigPrimaryTimeLessThan is a comparator that implements "less than" for
-// Config's based on their primary_time.
-// static
-bool QuicCryptoServerConfig::ConfigPrimaryTimeLessThan(
- const scoped_refptr<Config>& a,
- const scoped_refptr<Config>& b) {
- if (a->primary_time.IsBefore(b->primary_time) ||
- b->primary_time.IsBefore(a->primary_time)) {
- // Primary times differ.
- return a->primary_time.IsBefore(b->primary_time);
- } else if (a->priority != b->priority) {
- // Primary times are equal, sort backwards by priority.
- return a->priority < b->priority;
- } else {
- // Primary times and priorities are equal, sort by config id.
- return a->id < b->id;
- }
-}
-
-void QuicCryptoServerConfig::SelectNewPrimaryConfig(
- const QuicWallTime now) const {
- vector<scoped_refptr<Config>> configs;
- configs.reserve(configs_.size());
-
- for (ConfigMap::const_iterator it = configs_.begin(); it != configs_.end();
- ++it) {
- // TODO(avd) Exclude expired configs?
- configs.push_back(it->second);
- }
-
- if (configs.empty()) {
- if (primary_config_.get()) {
- QUIC_BUG << "No valid QUIC server config. Keeping the current config.";
- } else {
- QUIC_BUG << "No valid QUIC server config.";
- }
- return;
- }
-
- std::sort(configs.begin(), configs.end(), ConfigPrimaryTimeLessThan);
-
- Config* best_candidate = configs[0].get();
-
- for (size_t i = 0; i < configs.size(); ++i) {
- const scoped_refptr<Config> config(configs[i]);
- if (!config->primary_time.IsAfter(now)) {
- if (config->primary_time.IsAfter(best_candidate->primary_time)) {
- best_candidate = config.get();
- }
- continue;
- }
-
- // This is the first config with a primary_time in the future. Thus the
- // previous Config should be the primary and this one should determine the
- // next_config_promotion_time_.
- scoped_refptr<Config> new_primary(best_candidate);
- if (i == 0) {
- // We need the primary_time of the next config.
- if (configs.size() > 1) {
- next_config_promotion_time_ = configs[1]->primary_time;
- } else {
- next_config_promotion_time_ = QuicWallTime::Zero();
- }
- } else {
- next_config_promotion_time_ = config->primary_time;
- }
-
- if (primary_config_.get()) {
- primary_config_->is_primary = false;
- }
- primary_config_ = new_primary;
- new_primary->is_primary = true;
- DVLOG(1) << "New primary config. orbit: "
- << QuicUtils::HexEncode(
- reinterpret_cast<const char*>(primary_config_->orbit),
- kOrbitSize);
- if (primary_config_changed_cb_.get() != nullptr) {
- primary_config_changed_cb_->Run(primary_config_->id);
- }
-
- return;
- }
-
- // All config's primary times are in the past. We should make the most recent
- // and highest priority candidate primary.
- scoped_refptr<Config> new_primary(best_candidate);
- if (primary_config_.get()) {
- primary_config_->is_primary = false;
- }
- primary_config_ = new_primary;
- new_primary->is_primary = true;
- DVLOG(1) << "New primary config. orbit: "
- << QuicUtils::HexEncode(
- reinterpret_cast<const char*>(primary_config_->orbit),
- kOrbitSize)
- << " scid: " << QuicUtils::HexEncode(primary_config_->id);
- next_config_promotion_time_ = QuicWallTime::Zero();
- if (primary_config_changed_cb_.get() != nullptr) {
- primary_config_changed_cb_->Run(primary_config_->id);
- }
-}
-
-void QuicCryptoServerConfig::EvaluateClientHello(
- const IPAddress& server_ip,
- QuicVersion version,
- const uint8_t* primary_orbit,
- scoped_refptr<Config> requested_config,
- scoped_refptr<Config> primary_config,
- QuicCryptoProof* crypto_proof,
- ValidateClientHelloResultCallback::Result* client_hello_state,
- ValidateClientHelloResultCallback* done_cb) const {
- ValidateClientHelloHelper helper(client_hello_state, done_cb);
-
- const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello;
- ClientHelloInfo* info = &(client_hello_state->info);
-
- if (client_hello.size() < kClientHelloMinimumSize) {
- helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH,
- "Client hello too small");
- return;
- }
-
- if (client_hello.GetStringPiece(kSNI, &info->sni) &&
- !CryptoUtils::IsValidSNI(info->sni)) {
- helper.ValidationComplete(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
- "Invalid SNI name");
- return;
- }
-
- client_hello.GetStringPiece(kUAID, &info->user_agent_id);
-
- HandshakeFailureReason source_address_token_error = MAX_FAILURE_REASON;
- StringPiece srct;
- if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) {
- Config& config = requested_config ? *requested_config : *primary_config;
- source_address_token_error =
- ParseSourceAddressToken(config, srct, &info->source_address_tokens);
-
- if (source_address_token_error == HANDSHAKE_OK) {
- source_address_token_error = ValidateSourceAddressTokens(
- info->source_address_tokens, info->client_ip, info->now,
- &client_hello_state->cached_network_params);
- }
- info->valid_source_address_token =
- (source_address_token_error == HANDSHAKE_OK);
- } else {
- source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE;
- }
-
- if (!requested_config.get()) {
- StringPiece requested_scid;
- if (client_hello.GetStringPiece(kSCID, &requested_scid)) {
- info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
- } else {
- info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
- }
- // No server config with the requested ID.
- helper.ValidationComplete(QUIC_NO_ERROR, "");
- return;
- }
-
- if (!client_hello.GetStringPiece(kNONC, &info->client_nonce)) {
- info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE);
- // Report no client nonce as INCHOATE_HELLO_FAILURE.
- helper.ValidationComplete(QUIC_NO_ERROR, "");
- return;
- }
-
- bool found_error = false;
- if (source_address_token_error != HANDSHAKE_OK) {
- info->reject_reasons.push_back(source_address_token_error);
- // No valid source address token.
- found_error = true;
- }
-
- if (version > QUIC_VERSION_25) {
- bool x509_supported = false;
- bool x509_ecdsa_supported = false;
- ParseProofDemand(client_hello, &x509_supported, &x509_ecdsa_supported);
- string serialized_config = primary_config->serialized;
- string chlo_hash;
- CryptoUtils::HashHandshakeMessage(client_hello, &chlo_hash);
- if (!proof_source_->GetProof(
- server_ip, info->sni.as_string(), serialized_config, version,
- chlo_hash, x509_ecdsa_supported, &crypto_proof->chain,
- &crypto_proof->signature, &crypto_proof->cert_sct)) {
- found_error = true;
- info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE);
- }
-
- if (!ValidateExpectedLeafCertificate(client_hello, *crypto_proof)) {
- found_error = true;
- info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE);
- }
- }
-
- if (info->client_nonce.size() != kNonceSize) {
- info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
- // Invalid client nonce.
- LOG(ERROR) << "Invalid client nonce: " << client_hello.DebugString();
- DVLOG(1) << "Invalid client nonce.";
- found_error = true;
- }
-
- // Server nonce is optional, and used for key derivation if present.
- client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce);
-
- if (version > QUIC_VERSION_32) {
- 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_require_handshake_confirmation &&
- info->server_nonce.empty()) {
- info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE);
- }
- helper.ValidationComplete(QUIC_NO_ERROR, "");
- return;
- }
-
- if (!replay_protection_) {
- DVLOG(1) << "No replay protection.";
- helper.ValidationComplete(QUIC_NO_ERROR, "");
- return;
- }
-
- if (!info->server_nonce.empty()) {
- // If the server nonce is present, use it to establish uniqueness.
- HandshakeFailureReason server_nonce_error =
- ValidateServerNonce(info->server_nonce, info->now);
- bool is_unique = server_nonce_error == HANDSHAKE_OK;
- if (!is_unique) {
- info->reject_reasons.push_back(server_nonce_error);
- }
- DVLOG(1) << "Using server nonce, unique: " << is_unique;
- helper.ValidationComplete(QUIC_NO_ERROR, "");
- return;
- }
- // If we hit this block, the server nonce was empty. If we're requiring
- // handshake confirmation for DoS reasons and there's no server nonce present,
- // reject the CHLO.
- if (FLAGS_quic_require_handshake_confirmation) {
- info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE);
- helper.ValidationComplete(QUIC_NO_ERROR, "");
- return;
- }
-
- // We want to contact strike register only if there are no errors because it
- // is a RPC call and is expensive.
- if (found_error) {
- helper.ValidationComplete(QUIC_NO_ERROR, "");
- return;
- }
-
- // Use the client nonce to establish uniqueness.
- StrikeRegisterClient* strike_register_client;
- {
- base::AutoLock locked(strike_register_client_lock_);
- strike_register_client = strike_register_client_.get();
- }
-
- if (!strike_register_client) {
- // Either a valid server nonces or a strike register is required.
- // Since neither are present, reject the handshake which will send a
- // server nonce to the client.
- info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE);
- helper.ValidationComplete(QUIC_NO_ERROR, "");
- return;
- }
-
- strike_register_client->VerifyNonceIsValidAndUnique(
- info->client_nonce, info->now,
- new VerifyNonceIsValidAndUniqueCallback(client_hello_state, done_cb));
- helper.StartedAsyncCallback();
-}
-
-bool QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
- QuicVersion version,
- StringPiece chlo_hash,
- const SourceAddressTokens& previous_source_address_tokens,
- const IPAddress& server_ip,
- const IPAddress& client_ip,
- const QuicClock* clock,
- QuicRandom* rand,
- QuicCompressedCertsCache* compressed_certs_cache,
- const QuicCryptoNegotiatedParameters& params,
- const CachedNetworkParameters* cached_network_params,
- CryptoHandshakeMessage* out) const {
- base::AutoLock locked(configs_lock_);
- out->set_tag(kSCUP);
- out->SetStringPiece(kSCFG, primary_config_->serialized);
- out->SetStringPiece(
- kSourceAddressTokenTag,
- NewSourceAddressToken(*primary_config_.get(),
- previous_source_address_tokens, client_ip, rand,
- clock->WallNow(), cached_network_params));
-
- scoped_refptr<ProofSource::Chain> chain;
- string signature;
- string cert_sct;
- if (FLAGS_quic_use_hash_in_scup) {
- if (!proof_source_->GetProof(server_ip, params.sni,
- primary_config_->serialized, version,
- chlo_hash, params.x509_ecdsa_supported, &chain,
- &signature, &cert_sct)) {
- DVLOG(1) << "Server: failed to get proof.";
- return false;
- }
- } else {
- if (!proof_source_->GetProof(
- server_ip, params.sni, primary_config_->serialized, version,
- params.client_nonce, params.x509_ecdsa_supported, &chain,
- &signature, &cert_sct)) {
- DVLOG(1) << "Server: failed to get proof.";
- return false;
- }
- }
-
- const string compressed = CompressChain(
- compressed_certs_cache, chain, params.client_common_set_hashes,
- params.client_cached_cert_hashes, primary_config_->common_cert_sets);
-
- out->SetStringPiece(kCertificateTag, compressed);
- out->SetStringPiece(kPROF, signature);
- if (params.sct_supported_by_client && version > QUIC_VERSION_29 &&
- enable_serving_sct_) {
- if (cert_sct.empty()) {
- DLOG(WARNING) << "SCT is expected but it is empty.";
- } else {
- out->SetStringPiece(kCertificateSCTTag, cert_sct);
- }
- }
- return true;
-}
-
-void QuicCryptoServerConfig::BuildRejection(
- QuicVersion version,
- const Config& config,
- const CryptoHandshakeMessage& client_hello,
- const ClientHelloInfo& info,
- const CachedNetworkParameters& cached_network_params,
- bool use_stateless_rejects,
- QuicConnectionId server_designated_connection_id,
- QuicRandom* rand,
- QuicCompressedCertsCache* compressed_certs_cache,
- QuicCryptoNegotiatedParameters* params,
- const QuicCryptoProof& crypto_proof,
- CryptoHandshakeMessage* out) const {
- if (FLAGS_enable_quic_stateless_reject_support && use_stateless_rejects) {
- DVLOG(1) << "QUIC Crypto server config returning stateless reject "
- << "with server-designated connection ID "
- << server_designated_connection_id;
- out->set_tag(kSREJ);
- out->SetValue(kRCID, server_designated_connection_id);
- } else {
- out->set_tag(kREJ);
- }
- out->SetStringPiece(kSCFG, config.serialized);
- out->SetStringPiece(
- kSourceAddressTokenTag,
- NewSourceAddressToken(config, info.source_address_tokens, info.client_ip,
- rand, info.now, &cached_network_params));
- if (replay_protection_) {
- out->SetStringPiece(kServerNonceTag, NewServerNonce(rand, info.now));
- }
-
- // Send client the reject reason for debugging purposes.
- DCHECK_LT(0u, info.reject_reasons.size());
- out->SetVector(kRREJ, info.reject_reasons);
-
- // The client may have requested a certificate chain.
- bool x509_supported = false;
- ParseProofDemand(client_hello, &x509_supported,
- &params->x509_ecdsa_supported);
- if (!x509_supported) {
- return;
- }
-
- StringPiece client_common_set_hashes;
- if (client_hello.GetStringPiece(kCCS, &client_common_set_hashes)) {
- params->client_common_set_hashes = client_common_set_hashes.as_string();
- }
-
- StringPiece client_cached_cert_hashes;
- if (client_hello.GetStringPiece(kCCRT, &client_cached_cert_hashes)) {
- params->client_cached_cert_hashes = client_cached_cert_hashes.as_string();
- }
-
- const string compressed =
- CompressChain(compressed_certs_cache, crypto_proof.chain,
- params->client_common_set_hashes,
- params->client_cached_cert_hashes, config.common_cert_sets);
-
- // kREJOverheadBytes is a very rough estimate of how much of a REJ
- // message is taken up by things other than the certificates.
- // STK: 56 bytes
- // SNO: 56 bytes
- // SCFG
- // SCID: 16 bytes
- // PUBS: 38 bytes
- const size_t kREJOverheadBytes = 166;
- // max_unverified_size is the number of bytes that the certificate chain,
- // signature, and (optionally) signed certificate timestamp can consume before
- // we will demand a valid source-address token.
- const size_t max_unverified_size =
- client_hello.size() * chlo_multiplier_ - kREJOverheadBytes;
- static_assert(kClientHelloMinimumSize * kMultiplier >= kREJOverheadBytes,
- "overhead calculation may underflow");
- bool should_return_sct = params->sct_supported_by_client &&
- version > QUIC_VERSION_29 && enable_serving_sct_;
- const size_t sct_size = should_return_sct ? crypto_proof.cert_sct.size() : 0;
- if (info.valid_source_address_token ||
- crypto_proof.signature.size() + compressed.size() + sct_size <
- max_unverified_size) {
- out->SetStringPiece(kCertificateTag, compressed);
- out->SetStringPiece(kPROF, crypto_proof.signature);
- if (should_return_sct) {
- if (crypto_proof.cert_sct.empty()) {
- DLOG(WARNING) << "SCT is expected but it is empty.";
- } else {
- out->SetStringPiece(kCertificateSCTTag, crypto_proof.cert_sct);
- }
- }
- }
-}
-
-const string QuicCryptoServerConfig::CompressChain(
- QuicCompressedCertsCache* compressed_certs_cache,
- const scoped_refptr<ProofSource::Chain>& chain,
- const string& client_common_set_hashes,
- const string& client_cached_cert_hashes,
- const CommonCertSets* common_sets) const {
- // Check whether the compressed certs is available in the cache.
- DCHECK(compressed_certs_cache);
- const string* cached_value = compressed_certs_cache->GetCompressedCert(
- chain, client_common_set_hashes, client_cached_cert_hashes);
- if (cached_value) {
- return *cached_value;
- }
-
- const string 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,
- client_cached_cert_hashes, compressed);
- return compressed;
-}
-
-scoped_refptr<QuicCryptoServerConfig::Config>
-QuicCryptoServerConfig::ParseConfigProtobuf(
- QuicServerConfigProtobuf* protobuf) {
- std::unique_ptr<CryptoHandshakeMessage> msg(
- CryptoFramer::ParseMessage(protobuf->config()));
-
- if (msg->tag() != kSCFG) {
- LOG(WARNING) << "Server config message has tag " << msg->tag()
- << " expected " << kSCFG;
- return nullptr;
- }
-
- scoped_refptr<Config> config(new Config);
- config->serialized = protobuf->config();
-
- if (!protobuf->has_source_address_token_secret_override()) {
- // Use the default boxer.
- config->source_address_token_boxer = &default_source_address_token_boxer_;
- } else {
- // Create override boxer instance.
- CryptoSecretBoxer* boxer = new CryptoSecretBoxer;
- boxer->SetKeys({DeriveSourceAddressTokenKey(
- protobuf->source_address_token_secret_override())});
- config->source_address_token_boxer_storage.reset(boxer);
- config->source_address_token_boxer = boxer;
- }
-
- if (protobuf->has_primary_time()) {
- config->primary_time =
- QuicWallTime::FromUNIXSeconds(protobuf->primary_time());
- }
-
- config->priority = protobuf->priority();
-
- StringPiece scid;
- if (!msg->GetStringPiece(kSCID, &scid)) {
- LOG(WARNING) << "Server config message is missing SCID";
- return nullptr;
- }
- config->id = scid.as_string();
-
- const QuicTag* aead_tags;
- size_t aead_len;
- if (msg->GetTaglist(kAEAD, &aead_tags, &aead_len) != QUIC_NO_ERROR) {
- LOG(WARNING) << "Server config message is missing AEAD";
- return nullptr;
- }
- config->aead = vector<QuicTag>(aead_tags, aead_tags + aead_len);
-
- const QuicTag* kexs_tags;
- size_t kexs_len;
- if (msg->GetTaglist(kKEXS, &kexs_tags, &kexs_len) != QUIC_NO_ERROR) {
- LOG(WARNING) << "Server config message is missing KEXS";
- return nullptr;
- }
-
- const QuicTag* tbkp_tags;
- size_t tbkp_len;
- QuicErrorCode err;
- if ((err = msg->GetTaglist(kTBKP, &tbkp_tags, &tbkp_len)) !=
- QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND &&
- err != QUIC_NO_ERROR) {
- LOG(WARNING) << "Server config message is missing or has invalid TBKP";
- return nullptr;
- }
- config->tb_key_params = vector<QuicTag>(tbkp_tags, tbkp_tags + tbkp_len);
-
- StringPiece orbit;
- if (!msg->GetStringPiece(kORBT, &orbit)) {
- LOG(WARNING) << "Server config message is missing ORBT";
- return nullptr;
- }
-
- if (orbit.size() != kOrbitSize) {
- LOG(WARNING) << "Orbit value in server config is the wrong length."
- " Got "
- << orbit.size() << " want " << kOrbitSize;
- return nullptr;
- }
- static_assert(sizeof(config->orbit) == kOrbitSize,
- "orbit has incorrect size");
- memcpy(config->orbit, orbit.data(), sizeof(config->orbit));
-
- {
- StrikeRegisterClient* strike_register_client;
- {
- base::AutoLock locked(strike_register_client_lock_);
- strike_register_client = strike_register_client_.get();
- }
-
- if (strike_register_client != nullptr &&
- !strike_register_client->IsKnownOrbit(orbit)) {
- LOG(WARNING)
- << "Rejecting server config with orbit that the strike register "
- "client doesn't know about.";
- return nullptr;
- }
- }
-
- if (kexs_len != protobuf->key_size()) {
- LOG(WARNING) << "Server config has " << kexs_len
- << " key exchange methods configured, but "
- << protobuf->key_size() << " private keys";
- return nullptr;
- }
-
- const QuicTag* proof_demand_tags;
- size_t num_proof_demand_tags;
- if (msg->GetTaglist(kPDMD, &proof_demand_tags, &num_proof_demand_tags) ==
- QUIC_NO_ERROR) {
- for (size_t i = 0; i < num_proof_demand_tags; i++) {
- if (proof_demand_tags[i] == kCHID) {
- config->channel_id_enabled = true;
- break;
- }
- }
- }
-
- for (size_t i = 0; i < kexs_len; i++) {
- const QuicTag tag = kexs_tags[i];
- string private_key;
-
- config->kexs.push_back(tag);
-
- for (size_t j = 0; j < protobuf->key_size(); j++) {
- const QuicServerConfigProtobuf::PrivateKey& key = protobuf->key(i);
- if (key.tag() == tag) {
- private_key = key.private_key();
- break;
- }
- }
-
- if (private_key.empty()) {
- LOG(WARNING) << "Server config contains key exchange method without "
- "corresponding private key: "
- << tag;
- return nullptr;
- }
-
- std::unique_ptr<KeyExchange> ka;
- switch (tag) {
- case kC255:
- ka.reset(Curve25519KeyExchange::New(private_key));
- if (!ka.get()) {
- LOG(WARNING) << "Server config contained an invalid curve25519"
- " private key.";
- return nullptr;
- }
- break;
- case kP256:
- ka.reset(P256KeyExchange::New(private_key));
- if (!ka.get()) {
- LOG(WARNING) << "Server config contained an invalid P-256"
- " private key.";
- return nullptr;
- }
- break;
- default:
- LOG(WARNING) << "Server config message contains unknown key exchange "
- "method: "
- << tag;
- return nullptr;
- }
-
- for (const KeyExchange* key_exchange : config->key_exchanges) {
- if (key_exchange->tag() == tag) {
- LOG(WARNING) << "Duplicate key exchange in config: " << tag;
- return nullptr;
- }
- }
-
- config->key_exchanges.push_back(ka.release());
- }
-
- return config;
-}
-
-void QuicCryptoServerConfig::SetEphemeralKeySource(
- EphemeralKeySource* ephemeral_key_source) {
- ephemeral_key_source_.reset(ephemeral_key_source);
-}
-
-void QuicCryptoServerConfig::SetStrikeRegisterClient(
- StrikeRegisterClient* strike_register_client) {
- base::AutoLock locker(strike_register_client_lock_);
- DCHECK(!strike_register_client_.get());
- strike_register_client_.reset(strike_register_client);
-}
-
-void QuicCryptoServerConfig::set_replay_protection(bool on) {
- replay_protection_ = on;
-}
-
-void QuicCryptoServerConfig::set_chlo_multiplier(size_t multiplier) {
- chlo_multiplier_ = multiplier;
-}
-
-void QuicCryptoServerConfig::set_strike_register_no_startup_period() {
- base::AutoLock locker(strike_register_client_lock_);
- DCHECK(!strike_register_client_.get());
- strike_register_no_startup_period_ = true;
-}
-
-void QuicCryptoServerConfig::set_strike_register_max_entries(
- uint32_t max_entries) {
- base::AutoLock locker(strike_register_client_lock_);
- DCHECK(!strike_register_client_.get());
- strike_register_max_entries_ = max_entries;
-}
-
-void QuicCryptoServerConfig::set_strike_register_window_secs(
- uint32_t window_secs) {
- base::AutoLock locker(strike_register_client_lock_);
- DCHECK(!strike_register_client_.get());
- strike_register_window_secs_ = window_secs;
-}
-
-void QuicCryptoServerConfig::set_source_address_token_future_secs(
- uint32_t future_secs) {
- source_address_token_future_secs_ = future_secs;
-}
-
-void QuicCryptoServerConfig::set_source_address_token_lifetime_secs(
- uint32_t lifetime_secs) {
- source_address_token_lifetime_secs_ = lifetime_secs;
-}
-
-void QuicCryptoServerConfig::set_server_nonce_strike_register_max_entries(
- uint32_t max_entries) {
- DCHECK(!server_nonce_strike_register_.get());
- server_nonce_strike_register_max_entries_ = max_entries;
-}
-
-void QuicCryptoServerConfig::set_server_nonce_strike_register_window_secs(
- uint32_t window_secs) {
- DCHECK(!server_nonce_strike_register_.get());
- server_nonce_strike_register_window_secs_ = window_secs;
-}
-
-void QuicCryptoServerConfig::set_enable_serving_sct(bool enable_serving_sct) {
- enable_serving_sct_ = enable_serving_sct;
-}
-
-void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb(
- PrimaryConfigChangedCallback* cb) {
- base::AutoLock locked(configs_lock_);
- primary_config_changed_cb_.reset(cb);
-}
-
-string QuicCryptoServerConfig::NewSourceAddressToken(
- const Config& config,
- const SourceAddressTokens& previous_tokens,
- const IPAddress& ip,
- QuicRandom* rand,
- QuicWallTime now,
- const CachedNetworkParameters* cached_network_params) const {
- SourceAddressTokens source_address_tokens;
- SourceAddressToken* source_address_token = source_address_tokens.add_tokens();
- source_address_token->set_ip(IPAddressToPackedString(DualstackIPAddress(ip)));
- source_address_token->set_timestamp(now.ToUNIXSeconds());
- if (cached_network_params != nullptr) {
- *(source_address_token->mutable_cached_network_parameters()) =
- *cached_network_params;
- }
-
- // Append previous tokens.
- for (const SourceAddressToken& token : previous_tokens.tokens()) {
- if (source_address_tokens.tokens_size() > kMaxTokenAddresses) {
- break;
- }
-
- if (token.ip() == source_address_token->ip()) {
- // It's for the same IP address.
- continue;
- }
-
- if (ValidateSourceAddressTokenTimestamp(token, now) != HANDSHAKE_OK) {
- continue;
- }
-
- *(source_address_tokens.add_tokens()) = token;
- }
-
- return config.source_address_token_boxer->Box(
- rand, source_address_tokens.SerializeAsString());
-}
-
-int QuicCryptoServerConfig::NumberOfConfigs() const {
- base::AutoLock locked(configs_lock_);
- return configs_.size();
-}
-
-HandshakeFailureReason QuicCryptoServerConfig::ParseSourceAddressToken(
- const Config& config,
- StringPiece token,
- SourceAddressTokens* tokens) const {
- string storage;
- StringPiece plaintext;
- if (!config.source_address_token_boxer->Unbox(token, &storage, &plaintext)) {
- return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE;
- }
-
- if (!tokens->ParseFromArray(plaintext.data(), plaintext.size())) {
- // Some clients might still be using the old source token format so
- // attempt to parse that format.
- // TODO(rch): remove this code once the new format is ubiquitous.
- SourceAddressToken source_address_token;
- if (!source_address_token.ParseFromArray(plaintext.data(),
- plaintext.size())) {
- return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE;
- }
- *tokens->add_tokens() = source_address_token;
- }
-
- return HANDSHAKE_OK;
-}
-
-HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressTokens(
- const SourceAddressTokens& source_address_tokens,
- const IPAddress& ip,
- QuicWallTime now,
- CachedNetworkParameters* cached_network_params) const {
- HandshakeFailureReason reason =
- SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
- for (const SourceAddressToken& token : source_address_tokens.tokens()) {
- reason = ValidateSingleSourceAddressToken(token, ip, now);
- if (reason == HANDSHAKE_OK) {
- if (token.has_cached_network_parameters()) {
- *cached_network_params = token.cached_network_parameters();
- }
- break;
- }
- }
- return reason;
-}
-
-HandshakeFailureReason QuicCryptoServerConfig::ValidateSingleSourceAddressToken(
- const SourceAddressToken& source_address_token,
- const IPAddress& ip,
- QuicWallTime now) const {
- if (source_address_token.ip() !=
- IPAddressToPackedString(DualstackIPAddress(ip))) {
- // It's for a different IP address.
- return SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE;
- }
-
- return ValidateSourceAddressTokenTimestamp(source_address_token, now);
-}
-
-HandshakeFailureReason
-QuicCryptoServerConfig::ValidateSourceAddressTokenTimestamp(
- const SourceAddressToken& source_address_token,
- QuicWallTime now) const {
- const QuicWallTime timestamp(
- QuicWallTime::FromUNIXSeconds(source_address_token.timestamp()));
- const QuicTime::Delta delta(now.AbsoluteDifference(timestamp));
-
- if (now.IsBefore(timestamp) &&
- delta.ToSeconds() > source_address_token_future_secs_) {
- return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE;
- }
-
- if (now.IsAfter(timestamp) &&
- delta.ToSeconds() > source_address_token_lifetime_secs_) {
- return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE;
- }
-
- return HANDSHAKE_OK;
-}
-
-// kServerNoncePlaintextSize is the number of bytes in an unencrypted server
-// nonce.
-static const size_t kServerNoncePlaintextSize =
- 4 /* timestamp */ + 20 /* random bytes */;
-
-string QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand,
- QuicWallTime now) const {
- const uint32_t timestamp = static_cast<uint32_t>(now.ToUNIXSeconds());
-
- uint8_t server_nonce[kServerNoncePlaintextSize];
- static_assert(sizeof(server_nonce) > sizeof(timestamp), "nonce too small");
- server_nonce[0] = static_cast<uint8_t>(timestamp >> 24);
- server_nonce[1] = static_cast<uint8_t>(timestamp >> 16);
- server_nonce[2] = static_cast<uint8_t>(timestamp >> 8);
- server_nonce[3] = static_cast<uint8_t>(timestamp);
- rand->RandBytes(&server_nonce[sizeof(timestamp)],
- sizeof(server_nonce) - sizeof(timestamp));
-
- return server_nonce_boxer_.Box(
- rand,
- StringPiece(reinterpret_cast<char*>(server_nonce), sizeof(server_nonce)));
-}
-
-HandshakeFailureReason QuicCryptoServerConfig::ValidateServerNonce(
- StringPiece token,
- QuicWallTime now) const {
- string storage;
- StringPiece plaintext;
- if (!server_nonce_boxer_.Unbox(token, &storage, &plaintext)) {
- return SERVER_NONCE_DECRYPTION_FAILURE;
- }
-
- // plaintext contains:
- // uint32_t timestamp
- // uint8_t[20] random bytes
-
- if (plaintext.size() != kServerNoncePlaintextSize) {
- // This should never happen because the value decrypted correctly.
- QUIC_BUG << "Seemingly valid server nonce had incorrect length.";
- return SERVER_NONCE_INVALID_FAILURE;
- }
-
- uint8_t server_nonce[32];
- memcpy(server_nonce, plaintext.data(), 4);
- memcpy(server_nonce + 4, server_nonce_orbit_, sizeof(server_nonce_orbit_));
- memcpy(server_nonce + 4 + sizeof(server_nonce_orbit_), plaintext.data() + 4,
- 20);
- static_assert(4 + sizeof(server_nonce_orbit_) + 20 == sizeof(server_nonce),
- "bad nonce buffer length");
-
- InsertStatus nonce_error;
- {
- base::AutoLock auto_lock(server_nonce_strike_register_lock_);
- if (server_nonce_strike_register_.get() == nullptr) {
- server_nonce_strike_register_.reset(new StrikeRegister(
- server_nonce_strike_register_max_entries_,
- static_cast<uint32_t>(now.ToUNIXSeconds()),
- server_nonce_strike_register_window_secs_, server_nonce_orbit_,
- StrikeRegister::NO_STARTUP_PERIOD_NEEDED));
- }
- nonce_error = server_nonce_strike_register_->Insert(
- server_nonce, static_cast<uint32_t>(now.ToUNIXSeconds()));
- }
-
- switch (nonce_error) {
- case NONCE_OK:
- return HANDSHAKE_OK;
- case NONCE_INVALID_FAILURE:
- case NONCE_INVALID_ORBIT_FAILURE:
- return SERVER_NONCE_INVALID_FAILURE;
- case NONCE_NOT_UNIQUE_FAILURE:
- return SERVER_NONCE_NOT_UNIQUE_FAILURE;
- case NONCE_INVALID_TIME_FAILURE:
- return SERVER_NONCE_INVALID_TIME_FAILURE;
- case NONCE_UNKNOWN_FAILURE:
- case STRIKE_REGISTER_TIMEOUT:
- case STRIKE_REGISTER_FAILURE:
- default:
- QUIC_BUG << "Unexpected server nonce error: " << nonce_error;
- return SERVER_NONCE_NOT_UNIQUE_FAILURE;
- }
-}
-
-bool QuicCryptoServerConfig::ValidateExpectedLeafCertificate(
- const CryptoHandshakeMessage& client_hello,
- const QuicCryptoProof& crypto_proof) const {
- if (crypto_proof.chain->certs.empty()) {
- return false;
- }
-
- uint64_t hash_from_client;
- if (client_hello.GetUint64(kXLCT, &hash_from_client) != QUIC_NO_ERROR) {
- return false;
- }
- return CryptoUtils::ComputeLeafCertHash(crypto_proof.chain->certs.at(0)) ==
- hash_from_client;
-}
-
-void QuicCryptoServerConfig::ParseProofDemand(
- const CryptoHandshakeMessage& client_hello,
- bool* x509_supported,
- bool* x509_ecdsa_supported) const {
- const QuicTag* their_proof_demands;
- size_t num_their_proof_demands;
-
- if (client_hello.GetTaglist(kPDMD, &their_proof_demands,
- &num_their_proof_demands) != QUIC_NO_ERROR) {
- return;
- }
-
- *x509_supported = false;
- for (size_t i = 0; i < num_their_proof_demands; i++) {
- switch (their_proof_demands[i]) {
- case kX509:
- *x509_supported = true;
- *x509_ecdsa_supported = true;
- break;
- case kX59R:
- *x509_supported = true;
- break;
- }
- }
-}
-
-QuicCryptoServerConfig::Config::Config()
- : channel_id_enabled(false),
- is_primary(false),
- primary_time(QuicWallTime::Zero()),
- priority(0),
- source_address_token_boxer(nullptr) {}
-
-QuicCryptoServerConfig::Config::~Config() {
- STLDeleteElements(&key_exchanges);
-}
-
-QuicCryptoProof::QuicCryptoProof() {}
-QuicCryptoProof::~QuicCryptoProof() {}
-} // namespace net
diff --git a/chromium/net/quic/crypto/quic_crypto_server_config.h b/chromium/net/quic/crypto/quic_crypto_server_config.h
deleted file mode 100644
index a43bd783a6c..00000000000
--- a/chromium/net/quic/crypto/quic_crypto_server_config.h
+++ /dev/null
@@ -1,677 +0,0 @@
-// Copyright 2013 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_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_
-#define NET_QUIC_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/strings/string_piece.h"
-#include "base/synchronization/lock.h"
-#include "net/base/ip_address.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_export.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/crypto_secret_boxer.h"
-#include "net/quic/crypto/proof_source.h"
-#include "net/quic/crypto/quic_compressed_certs_cache.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/proto/source_address_token.pb.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class CryptoHandshakeMessage;
-class EphemeralKeySource;
-class KeyExchange;
-class ProofSource;
-class QuicClock;
-class QuicDecrypter;
-class QuicEncrypter;
-class QuicRandom;
-class QuicServerConfigProtobuf;
-class StrikeRegister;
-class StrikeRegisterClient;
-struct QuicCryptoProof;
-
-// ClientHelloInfo contains information about a client hello message that is
-// only kept for as long as it's being processed.
-struct ClientHelloInfo {
- ClientHelloInfo(const IPAddress& in_client_ip, QuicWallTime in_now);
- ~ClientHelloInfo();
-
- // Inputs to EvaluateClientHello.
- const IPAddress client_ip;
- const QuicWallTime now;
-
- // Outputs from EvaluateClientHello.
- bool valid_source_address_token;
- base::StringPiece sni;
- base::StringPiece client_nonce;
- base::StringPiece server_nonce;
- base::StringPiece user_agent_id;
- SourceAddressTokens source_address_tokens;
-
- // Errors from EvaluateClientHello.
- std::vector<uint32_t> reject_reasons;
- static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync");
-};
-
-namespace test {
-class QuicCryptoServerConfigPeer;
-} // namespace test
-
-// Hook that allows application code to subscribe to primary config changes.
-class PrimaryConfigChangedCallback {
- public:
- PrimaryConfigChangedCallback();
- virtual ~PrimaryConfigChangedCallback();
- virtual void Run(const std::string& scid) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PrimaryConfigChangedCallback);
-};
-
-// Callback used to accept the result of the |client_hello| validation step.
-class NET_EXPORT_PRIVATE ValidateClientHelloResultCallback {
- public:
- // Opaque token that holds information about the client_hello and
- // its validity. Can be interpreted by calling ProcessClientHello.
- struct Result {
- Result(const CryptoHandshakeMessage& in_client_hello,
- IPAddress in_client_ip,
- QuicWallTime in_now);
- ~Result();
-
- CryptoHandshakeMessage client_hello;
- ClientHelloInfo info;
- QuicErrorCode error_code;
- std::string error_details;
-
- // Populated if the CHLO STK contained a CachedNetworkParameters proto.
- CachedNetworkParameters cached_network_params;
- };
-
- ValidateClientHelloResultCallback();
- virtual ~ValidateClientHelloResultCallback();
- void Run(const Result* result);
-
- protected:
- virtual void RunImpl(const CryptoHandshakeMessage& client_hello,
- const Result& result) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ValidateClientHelloResultCallback);
-};
-
-// QuicCryptoServerConfig contains the crypto configuration of a QUIC server.
-// Unlike a client, a QUIC server can have multiple configurations active in
-// order to support clients resuming with a previous configuration.
-// TODO(agl): when adding configurations at runtime is added, this object will
-// need to consider locking.
-class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
- public:
- // ConfigOptions contains options for generating server configs.
- struct NET_EXPORT_PRIVATE ConfigOptions {
- ConfigOptions();
- ConfigOptions(const ConfigOptions& other);
-
- // expiry_time is the time, in UNIX seconds, when the server config will
- // expire. If unset, it defaults to the current time plus six months.
- QuicWallTime expiry_time;
- // channel_id_enabled controls whether the server config will indicate
- // support for ChannelIDs.
- bool channel_id_enabled;
- // token_binding_enabled controls whether the server config will indicate
- // support for Token Binding.
- bool token_binding_enabled;
- // id contains the server config id for the resulting config. If empty, a
- // random id is generated.
- std::string id;
- // orbit contains the kOrbitSize bytes of the orbit value for the server
- // config. If |orbit| is empty then a random orbit is generated.
- std::string orbit;
- // p256 determines whether a P-256 public key will be included in the
- // server config. Note that this breaks deterministic server-config
- // generation since P-256 key generation doesn't use the QuicRandom given
- // to DefaultConfig().
- bool p256;
- };
-
- // |source_address_token_secret|: secret key material used for encrypting and
- // decrypting source address tokens. It can be of any length as it is fed
- // into a KDF before use. In tests, use TESTING.
- // |server_nonce_entropy|: an entropy source used to generate the orbit and
- // key for server nonces, which are always local to a given instance of a
- // server. Not owned.
- // |proof_source|: provides certificate chains and signatures. This class
- // takes ownership of |proof_source|.
- QuicCryptoServerConfig(base::StringPiece source_address_token_secret,
- QuicRandom* server_nonce_entropy,
- ProofSource* proof_source);
- ~QuicCryptoServerConfig();
-
- // TESTING is a magic parameter for passing to the constructor in tests.
- static const char TESTING[];
-
- // Generates a QuicServerConfigProtobuf protobuf suitable for
- // AddConfig and SetConfigs.
- static QuicServerConfigProtobuf* GenerateConfig(QuicRandom* rand,
- const QuicClock* clock,
- const ConfigOptions& options);
-
- // AddConfig adds a QuicServerConfigProtobuf to the availible configurations.
- // It returns the SCFG message from the config if successful. The caller
- // takes ownership of the CryptoHandshakeMessage. |now| is used in
- // conjunction with |protobuf->primary_time()| to determine whether the
- // config should be made primary.
- CryptoHandshakeMessage* AddConfig(QuicServerConfigProtobuf* protobuf,
- QuicWallTime now);
-
- // AddDefaultConfig calls DefaultConfig to create a config and then calls
- // AddConfig to add it. See the comment for |DefaultConfig| for details of
- // the arguments.
- CryptoHandshakeMessage* AddDefaultConfig(QuicRandom* rand,
- const QuicClock* clock,
- const ConfigOptions& options);
-
- // SetConfigs takes a vector of config protobufs and the current time.
- // Configs are assumed to be uniquely identified by their server config ID.
- // Previously unknown configs are added and possibly made the primary config
- // depending on their |primary_time| and the value of |now|. Configs that are
- // known, but are missing from the protobufs are deleted, unless they are
- // currently the primary config. SetConfigs returns false if any errors were
- // encountered and no changes to the QuicCryptoServerConfig will occur.
- bool SetConfigs(const std::vector<QuicServerConfigProtobuf*>& protobufs,
- QuicWallTime now);
-
- // SetDefaultSourceAddressTokenKeys sets the keys to be tried, in order,
- // when decrypting a source address token. This modifies only the default
- // boxer, which is to say, it is a no-op if a key was specified in the Config.
- // Note that these keys are used *without* passing them through a KDF, in
- // contradistinction to the |source_address_token_secret| argument to the
- // constructor.
- void SetDefaultSourceAddressTokenKeys(const std::vector<std::string>& keys);
-
- // Get the server config ids for all known configs.
- void GetConfigIds(std::vector<std::string>* scids) const;
-
- // Checks |client_hello| for gross errors and determines whether it
- // can be shown to be fresh (i.e. not a replay). The result of the
- // validation step must be interpreted by calling
- // QuicCryptoServerConfig::ProcessClientHello from the done_cb.
- //
- // ValidateClientHello may invoke the done_cb before unrolling the
- // stack if it is able to assess the validity of the client_nonce
- // without asynchronous operations.
- //
- // client_hello: the incoming client hello message.
- // client_ip: the IP address of the client, which is used to generate and
- // validate source-address tokens.
- // server_ip: the IP address of the server. The IP address may be used for
- // certificate selection.
- // version: protocol version used for this connection.
- // clock: used to validate client nonces and ephemeral keys.
- // crypto_proof: output structure containing the crypto proof used in reply to
- // a proof demand.
- // done_cb: single-use callback that accepts an opaque
- // ValidatedClientHelloMsg token that holds information about
- // the client hello. The callback will always be called exactly
- // once, either under the current call stack, or after the
- // completion of an asynchronous operation.
- void ValidateClientHello(const CryptoHandshakeMessage& client_hello,
- const IPAddress& client_ip,
- const IPAddress& server_ip,
- QuicVersion version,
- const QuicClock* clock,
- QuicCryptoProof* crypto_proof,
- ValidateClientHelloResultCallback* done_cb) const;
-
- // ProcessClientHello processes |client_hello| and decides whether to accept
- // or reject the connection. If the connection is to be accepted, |out| is
- // set to the contents of the ServerHello, |out_params| is completed and
- // QUIC_NO_ERROR is returned. Otherwise |out| is set to be a REJ or SREJ
- // message and QUIC_NO_ERROR is returned.
- //
- // validate_chlo_result: Output from the asynchronous call to
- // ValidateClientHello. Contains the client hello message and
- // information about it.
- // reject_only: Only generate rejections, not server hello messages.
- // connection_id: the ConnectionId for the connection, which is used in key
- // derivation.
- // server_ip: the IP address of the server. The IP address may be used for
- // certificate selection.
- // client_address: the IP address and port of the client. The IP address is
- // used to generate and validate source-address tokens.
- // version: version of the QUIC protocol in use for this connection
- // supported_versions: versions of the QUIC protocol that this server
- // supports.
- // clock: used to validate client nonces and ephemeral keys.
- // rand: an entropy source
- // compressed_certs_cache: the cache that caches a set of most recently used
- // certs. Owned by QuicDispatcher.
- // params: the state of the handshake. This may be updated with a server
- // nonce when we send a rejection. After a successful handshake, this will
- // contain the state of the connection.
- // crypto_proof: output structure containing the crypto proof used in reply to
- // a proof demand.
- // out: the resulting handshake message (either REJ or SHLO)
- // out_diversification_nonce: If the resulting handshake message is SHLO and
- // the version is greater than QUIC_VERSION_32 then this contains a
- // 32-byte value that should be included in the public header of
- // initially encrypted packets.
- // error_details: used to store a std::string describing any error.
- QuicErrorCode ProcessClientHello(
- const ValidateClientHelloResultCallback::Result& validate_chlo_result,
- bool reject_only,
- QuicConnectionId connection_id,
- const IPAddress& server_ip,
- const IPEndPoint& client_address,
- QuicVersion version,
- const QuicVersionVector& supported_versions,
- bool use_stateless_rejects,
- QuicConnectionId server_designated_connection_id,
- const QuicClock* clock,
- QuicRandom* rand,
- QuicCompressedCertsCache* compressed_certs_cache,
- QuicCryptoNegotiatedParameters* params,
- QuicCryptoProof* crypto_proof,
- CryptoHandshakeMessage* out,
- DiversificationNonce* out_diversification_nonce,
- std::string* error_details) const;
-
- // BuildServerConfigUpdateMessage sets |out| to be a SCUP message containing
- // the current primary config, an up to date source-address token, and cert
- // chain and proof in the case of secure QUIC. Returns true if successfully
- // filled |out|.
- //
- // |cached_network_params| is optional, and can be nullptr.
- bool BuildServerConfigUpdateMessage(
- QuicVersion version,
- base::StringPiece chlo_hash,
- const SourceAddressTokens& previous_source_address_tokens,
- const IPAddress& server_ip,
- const IPAddress& client_ip,
- const QuicClock* clock,
- QuicRandom* rand,
- QuicCompressedCertsCache* compressed_certs_cache,
- const QuicCryptoNegotiatedParameters& params,
- const CachedNetworkParameters* cached_network_params,
- CryptoHandshakeMessage* out) const;
-
- // SetEphemeralKeySource installs an object that can cache ephemeral keys for
- // a short period of time. This object takes ownership of
- // |ephemeral_key_source|. If not set then ephemeral keys will be generated
- // per-connection.
- void SetEphemeralKeySource(EphemeralKeySource* ephemeral_key_source);
-
- // Install an externall created StrikeRegisterClient for use to
- // interact with the strike register. This object takes ownership
- // of the |strike_register_client|.
- void SetStrikeRegisterClient(StrikeRegisterClient* strike_register_client);
-
- // set_replay_protection controls whether replay protection is enabled. If
- // replay protection is disabled then no strike registers are needed and
- // frontends can share an orbit value without a shared strike-register.
- // However, an attacker can duplicate a handshake and cause a client's
- // request to be processed twice.
- void set_replay_protection(bool on);
-
- // set_chlo_multiplier specifies the multiple of the CHLO message size
- // that a REJ message must stay under when the client doesn't present a
- // valid source-address token.
- void set_chlo_multiplier(size_t multiplier);
-
- // set_strike_register_no_startup_period configures the strike register to
- // not have a startup period.
- void set_strike_register_no_startup_period();
-
- // set_strike_register_max_entries sets the maximum number of entries that
- // the internal strike register will hold. If the strike register fills up
- // then the oldest entries (by the client's clock) will be dropped.
- void set_strike_register_max_entries(uint32_t max_entries);
-
- // set_strike_register_window_secs sets the number of seconds around the
- // current time that the strike register will attempt to be authoritative
- // for. Setting a larger value allows for greater client clock-skew, but
- // means that the quiescent startup period must be longer.
- void set_strike_register_window_secs(uint32_t window_secs);
-
- // set_source_address_token_future_secs sets the number of seconds into the
- // future that source-address tokens will be accepted from. Since
- // source-address tokens are authenticated, this should only happen if
- // another, valid server has clock-skew.
- void set_source_address_token_future_secs(uint32_t future_secs);
-
- // set_source_address_token_lifetime_secs sets the number of seconds that a
- // source-address token will be valid for.
- void set_source_address_token_lifetime_secs(uint32_t lifetime_secs);
-
- // set_server_nonce_strike_register_max_entries sets the number of entries in
- // the server-nonce strike-register. This is used to record that server nonce
- // values have been used. If the number of entries is too small then clients
- // which are depending on server nonces may fail to handshake because their
- // nonce has expired in the amount of time it took to go from the server to
- // the client and back.
- void set_server_nonce_strike_register_max_entries(uint32_t max_entries);
-
- // set_server_nonce_strike_register_window_secs sets the number of seconds
- // around the current time that the server-nonce strike-register will accept
- // nonces from. Setting a larger value allows for clients to delay follow-up
- // client hellos for longer and still use server nonces as proofs of
- // uniqueness.
- void set_server_nonce_strike_register_window_secs(uint32_t window_secs);
-
- // set_enable_serving_sct enables or disables serving signed cert timestamp
- // (RFC6962) in server hello.
- void set_enable_serving_sct(bool enable_serving_sct);
-
- // Set and take ownership of the callback to invoke on primary config changes.
- void AcquirePrimaryConfigChangedCb(PrimaryConfigChangedCallback* cb);
-
- // Returns the number of configs this object owns.
- int NumberOfConfigs() const;
-
- private:
- friend class test::QuicCryptoServerConfigPeer;
- friend struct QuicCryptoProof;
-
- // Config represents a server config: a collection of preferences and
- // Diffie-Hellman public values.
- class NET_EXPORT_PRIVATE Config : public QuicCryptoConfig,
- public base::RefCounted<Config> {
- public:
- Config();
-
- // TODO(rtenneti): since this is a class, we should probably do
- // getters/setters here.
- // |serialized| contains the bytes of this server config, suitable for
- // sending on the wire.
- std::string serialized;
- // id contains the SCID of this server config.
- std::string id;
- // orbit contains the orbit value for this config: an opaque identifier
- // used to identify clusters of server frontends.
- unsigned char orbit[kOrbitSize];
-
- // key_exchanges contains key exchange objects with the private keys
- // already loaded. The values correspond, one-to-one, with the tags in
- // |kexs| from the parent class.
- std::vector<KeyExchange*> key_exchanges;
-
- // tag_value_map contains the raw key/value pairs for the config.
- QuicTagValueMap tag_value_map;
-
- // channel_id_enabled is true if the config in |serialized| specifies that
- // ChannelIDs are supported.
- bool channel_id_enabled;
-
- // is_primary is true if this config is the one that we'll give out to
- // clients as the current one.
- bool is_primary;
-
- // primary_time contains the timestamp when this config should become the
- // primary config. A value of QuicWallTime::Zero() means that this config
- // will not be promoted at a specific time.
- QuicWallTime primary_time;
-
- // Secondary sort key for use when selecting primary configs and
- // there are multiple configs with the same primary time.
- // Smaller numbers mean higher priority.
- uint64_t priority;
-
- // source_address_token_boxer_ is used to protect the
- // source-address tokens that are given to clients.
- // Points to either source_address_token_boxer_storage or the
- // default boxer provided by QuicCryptoServerConfig.
- const CryptoSecretBoxer* source_address_token_boxer;
-
- // Holds the override source_address_token_boxer instance if the
- // Config is not using the default source address token boxer
- // instance provided by QuicCryptoServerConfig.
- std::unique_ptr<CryptoSecretBoxer> source_address_token_boxer_storage;
-
- private:
- friend class base::RefCounted<Config>;
-
- virtual ~Config();
-
- DISALLOW_COPY_AND_ASSIGN(Config);
- };
-
- typedef std::map<ServerConfigID, scoped_refptr<Config>> ConfigMap;
-
- // Get a ref to the config with a given server config id.
- scoped_refptr<Config> GetConfigWithScid(
- base::StringPiece requested_scid) const;
-
- // ConfigPrimaryTimeLessThan returns true if a->primary_time <
- // b->primary_time.
- static bool ConfigPrimaryTimeLessThan(const scoped_refptr<Config>& a,
- const scoped_refptr<Config>& b);
-
- // SelectNewPrimaryConfig reevaluates the primary config based on the
- // "primary_time" deadlines contained in each.
- void SelectNewPrimaryConfig(QuicWallTime now) const;
-
- // EvaluateClientHello checks |client_hello| for gross errors and determines
- // whether it can be shown to be fresh (i.e. not a replay). The results are
- // written to |info|.
- void EvaluateClientHello(
- const IPAddress& server_ip,
- QuicVersion version,
- const uint8_t* primary_orbit,
- scoped_refptr<Config> requested_config,
- scoped_refptr<Config> primary_config,
- QuicCryptoProof* crypto_proof,
- ValidateClientHelloResultCallback::Result* client_hello_state,
- ValidateClientHelloResultCallback* done_cb) const;
-
- // BuildRejection sets |out| to be a REJ message in reply to |client_hello|.
- void BuildRejection(QuicVersion version,
- const Config& config,
- const CryptoHandshakeMessage& client_hello,
- const ClientHelloInfo& info,
- const CachedNetworkParameters& cached_network_params,
- bool use_stateless_rejects,
- QuicConnectionId server_designated_connection_id,
- QuicRandom* rand,
- QuicCompressedCertsCache* compressed_certs_cache,
- QuicCryptoNegotiatedParameters* params,
- const QuicCryptoProof& crypto_proof,
- CryptoHandshakeMessage* out) const;
-
- // CompressChain compresses the certificates in |chain->certs| and returns a
- // compressed representation. |common_sets| contains the common certificate
- // sets known locally and |client_common_set_hashes| contains the hashes of
- // the common sets known to the peer. |client_cached_cert_hashes| contains
- // 64-bit, FNV-1a hashes of certificates that the peer already possesses.
- const std::string CompressChain(
- QuicCompressedCertsCache* compressed_certs_cache,
- const scoped_refptr<ProofSource::Chain>& chain,
- const std::string& client_common_set_hashes,
- const std::string& client_cached_cert_hashes,
- const CommonCertSets* common_sets) const;
-
- // ParseConfigProtobuf parses the given config protobuf and returns a
- // scoped_refptr<Config> if successful. The caller adopts the reference to the
- // Config. On error, ParseConfigProtobuf returns nullptr.
- scoped_refptr<Config> ParseConfigProtobuf(QuicServerConfigProtobuf* protobuf);
-
- // NewSourceAddressToken returns a fresh source address token for the given
- // IP address. |cached_network_params| is optional, and can be nullptr.
- std::string NewSourceAddressToken(
- const Config& config,
- const SourceAddressTokens& previous_tokens,
- const IPAddress& ip,
- QuicRandom* rand,
- QuicWallTime now,
- const CachedNetworkParameters* cached_network_params) const;
-
- // ParseSourceAddressToken parses the source address tokens contained in
- // the encrypted |token|, and populates |tokens| with the parsed tokens.
- // Returns HANDSHAKE_OK if |token| could be parsed, or the reason for the
- // failure.
- HandshakeFailureReason ParseSourceAddressToken(
- const Config& config,
- base::StringPiece token,
- SourceAddressTokens* tokens) const;
-
- // ValidateSourceAddressTokens returns HANDSHAKE_OK if the source address
- // tokens in |tokens| contain a valid and timely token for the IP address
- // |ip| given that the current time is |now|. Otherwise it returns the
- // reason for failure. |cached_network_params| is populated if the valid
- // token contains a CachedNetworkParameters proto.
- HandshakeFailureReason ValidateSourceAddressTokens(
- const SourceAddressTokens& tokens,
- const IPAddress& ip,
- QuicWallTime now,
- CachedNetworkParameters* cached_network_params) const;
-
- // ValidateSingleSourceAddressToken returns HANDSHAKE_OK if the source
- // address token in |token| is a timely token for the IP address |ip|
- // given that the current time is |now|. Otherwise it returns the reason
- // for failure.
- HandshakeFailureReason ValidateSingleSourceAddressToken(
- const SourceAddressToken& token,
- const IPAddress& ip,
- QuicWallTime now) const;
-
- // Returns HANDSHAKE_OK if the source address token in |token| is a timely
- // token given that the current time is |now|. Otherwise it returns the
- // reason for failure.
- HandshakeFailureReason ValidateSourceAddressTokenTimestamp(
- const SourceAddressToken& token,
- QuicWallTime now) const;
-
- // NewServerNonce generates and encrypts a random nonce.
- std::string NewServerNonce(QuicRandom* rand, QuicWallTime now) const;
-
- // ValidateServerNonce decrypts |token| and verifies that it hasn't been
- // previously used and is recent enough that it is plausible that it was part
- // of a very recently provided rejection ("recent" will be on the order of
- // 10-30 seconds). If so, it records that it has been used and returns
- // HANDSHAKE_OK. Otherwise it returns the reason for failure.
- HandshakeFailureReason ValidateServerNonce(
- base::StringPiece echoed_server_nonce,
- QuicWallTime now) const;
-
- // ValidateExpectedLeafCertificate checks the |client_hello| to see if it has
- // an XLCT tag, and if so, verifies that its value matches the hash of the
- // server's leaf certificate. The certs field of |crypto_proof| is used to
- // compare against the XLCT value. This method returns true if the XLCT tag
- // is not present, or if the XLCT tag is present and valid. It returns false
- // otherwise.
- bool ValidateExpectedLeafCertificate(
- const CryptoHandshakeMessage& client_hello,
- const QuicCryptoProof& crypto_proof) const;
-
- // ParseProofDemand reads the PDMD field from the client hello and sets the
- // |x509_ecdsa_supported| and |x509_supported| output parameters.
- void ParseProofDemand(const CryptoHandshakeMessage& client_hello,
- bool* x509_supported,
- bool* x509_ecdsa_supported) const;
-
- // replay_protection_ controls whether the server enforces that handshakes
- // aren't replays.
- bool replay_protection_;
-
- // The multiple of the CHLO message size that a REJ message must stay under
- // when the client doesn't present a valid source-address token. This is
- // used to protect QUIC from amplification attacks.
- size_t chlo_multiplier_;
-
- // configs_ satisfies the following invariants:
- // 1) configs_.empty() <-> primary_config_ == nullptr
- // 2) primary_config_ != nullptr -> primary_config_->is_primary
- // 3) ∀ c∈configs_, c->is_primary <-> c == primary_config_
- mutable base::Lock configs_lock_;
- // configs_ contains all active server configs. It's expected that there are
- // about half-a-dozen configs active at any one time.
- ConfigMap configs_;
- // primary_config_ points to a Config (which is also in |configs_|) which is
- // the primary config - i.e. the one that we'll give out to new clients.
- mutable scoped_refptr<Config> primary_config_;
- // next_config_promotion_time_ contains the nearest, future time when an
- // active config will be promoted to primary.
- mutable QuicWallTime next_config_promotion_time_;
- // Callback to invoke when the primary config changes.
- std::unique_ptr<PrimaryConfigChangedCallback> primary_config_changed_cb_;
-
- // Protects access to the pointer held by strike_register_client_.
- mutable base::Lock strike_register_client_lock_;
- // strike_register_ contains a data structure that keeps track of previously
- // observed client nonces in order to prevent replay attacks.
- mutable std::unique_ptr<StrikeRegisterClient> strike_register_client_;
-
- // Default source_address_token_boxer_ used to protect the
- // source-address tokens that are given to clients. Individual
- // configs may use boxers with alternate secrets.
- CryptoSecretBoxer default_source_address_token_boxer_;
-
- // server_nonce_boxer_ is used to encrypt and validate suggested server
- // nonces.
- CryptoSecretBoxer server_nonce_boxer_;
-
- // server_nonce_orbit_ contains the random, per-server orbit values that this
- // server will use to generate server nonces (the moral equivalent of a SYN
- // cookies).
- uint8_t server_nonce_orbit_[8];
-
- mutable base::Lock server_nonce_strike_register_lock_;
- // server_nonce_strike_register_ contains a data structure that keeps track of
- // previously observed server nonces from this server, in order to prevent
- // replay attacks.
- mutable std::unique_ptr<StrikeRegister> server_nonce_strike_register_;
-
- // proof_source_ contains an object that can provide certificate chains and
- // signatures.
- std::unique_ptr<ProofSource> proof_source_;
-
- // ephemeral_key_source_ contains an object that caches ephemeral keys for a
- // short period of time.
- std::unique_ptr<EphemeralKeySource> ephemeral_key_source_;
-
- // These fields store configuration values. See the comments for their
- // respective setter functions.
- bool strike_register_no_startup_period_;
- uint32_t strike_register_max_entries_;
- uint32_t strike_register_window_secs_;
- uint32_t source_address_token_future_secs_;
- uint32_t source_address_token_lifetime_secs_;
- uint32_t server_nonce_strike_register_max_entries_;
- uint32_t server_nonce_strike_register_window_secs_;
-
- // Enable serving SCT or not.
- bool enable_serving_sct_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicCryptoServerConfig);
-};
-
-struct NET_EXPORT_PRIVATE QuicCryptoProof {
- QuicCryptoProof();
- ~QuicCryptoProof();
-
- std::string signature;
- scoped_refptr<ProofSource::Chain> chain;
- std::string cert_sct;
- // The server config that is used for this proof (and the rest of the
- // request).
- scoped_refptr<QuicCryptoServerConfig::Config> config;
- std::string primary_scid;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_
diff --git a/chromium/net/quic/crypto/quic_crypto_server_config_test.cc b/chromium/net/quic/crypto/quic_crypto_server_config_test.cc
deleted file mode 100644
index f1dab3a4ea3..00000000000
--- a/chromium/net/quic/crypto/quic_crypto_server_config_test.cc
+++ /dev/null
@@ -1,583 +0,0 @@
-// Copyright 2013 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/crypto/quic_crypto_server_config.h"
-
-#include <stdarg.h>
-
-#include <memory>
-
-#include "base/stl_util.h"
-#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
-#include "net/quic/crypto/cert_compressor.h"
-#include "net/quic/crypto/chacha20_poly1305_encrypter.h"
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/crypto/crypto_secret_boxer.h"
-#include "net/quic/crypto/crypto_server_config_protobuf.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/crypto/strike_register_client.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_time.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/test_tools/quic_crypto_server_config_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::StringPiece;
-using std::map;
-using std::pair;
-using std::string;
-using std::vector;
-
-namespace net {
-namespace test {
-
-class TestStrikeRegisterClient : public StrikeRegisterClient {
- public:
- explicit TestStrikeRegisterClient(QuicCryptoServerConfig* config)
- : config_(config), is_known_orbit_called_(false) {}
-
- bool IsKnownOrbit(StringPiece orbit) const override {
- // Ensure that the strike register client lock is not held.
- QuicCryptoServerConfigPeer peer(config_);
- base::Lock* m = peer.GetStrikeRegisterClientLock();
- // In Chromium, we will dead lock if the lock is held by the current thread.
- // Chromium doesn't have AssertNotHeld API call.
- // m->AssertNotHeld();
- base::AutoLock lock(*m);
-
- is_known_orbit_called_ = true;
- return true;
- }
-
- void VerifyNonceIsValidAndUnique(StringPiece nonce,
- QuicWallTime now,
- ResultCallback* cb) override {
- LOG(FATAL) << "Not implemented";
- }
-
- bool is_known_orbit_called() { return is_known_orbit_called_; }
-
- private:
- QuicCryptoServerConfig* config_;
- mutable bool is_known_orbit_called_;
-};
-
-TEST(QuicCryptoServerConfigTest, ServerConfig) {
- QuicRandom* rand = QuicRandom::GetInstance();
- QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
- CryptoTestUtils::ProofSourceForTesting());
- MockClock clock;
-
- std::unique_ptr<CryptoHandshakeMessage> message(server.AddDefaultConfig(
- rand, &clock, QuicCryptoServerConfig::ConfigOptions()));
-
- // The default configuration should have AES-GCM and at least one ChaCha20
- // cipher.
- const QuicTag* aead_tags;
- size_t aead_len;
- ASSERT_EQ(QUIC_NO_ERROR, message->GetTaglist(kAEAD, &aead_tags, &aead_len));
- vector<QuicTag> aead(aead_tags, aead_tags + aead_len);
- EXPECT_THAT(aead, ::testing::Contains(kAESG));
- EXPECT_LE(1u, aead.size());
-}
-
-TEST(QuicCryptoServerConfigTest, GetOrbitIsCalledWithoutTheStrikeRegisterLock) {
- QuicRandom* rand = QuicRandom::GetInstance();
- QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
- CryptoTestUtils::ProofSourceForTesting());
- MockClock clock;
-
- TestStrikeRegisterClient* strike_register =
- new TestStrikeRegisterClient(&server);
- server.SetStrikeRegisterClient(strike_register);
-
- QuicCryptoServerConfig::ConfigOptions options;
- std::unique_ptr<CryptoHandshakeMessage> message(
- server.AddDefaultConfig(rand, &clock, options));
- EXPECT_TRUE(strike_register->is_known_orbit_called());
-}
-
-TEST(QuicCryptoServerConfigTest, CompressCerts) {
- QuicCompressedCertsCache compressed_certs_cache(
- QuicCompressedCertsCache::kQuicCompressedCertsCacheSize);
-
- QuicRandom* rand = QuicRandom::GetInstance();
- QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
- CryptoTestUtils::ProofSourceForTesting());
- QuicCryptoServerConfigPeer peer(&server);
-
- vector<string> certs = {"testcert"};
- scoped_refptr<ProofSource::Chain> chain(new ProofSource::Chain(certs));
-
- string compressed =
- peer.CompressChain(&compressed_certs_cache, chain, "", "", nullptr);
-
- EXPECT_EQ(compressed_certs_cache.Size(), 1u);
-}
-
-TEST(QuicCryptoServerConfigTest, CompressSameCertsTwice) {
- QuicCompressedCertsCache compressed_certs_cache(
- QuicCompressedCertsCache::kQuicCompressedCertsCacheSize);
-
- QuicRandom* rand = QuicRandom::GetInstance();
- QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
- CryptoTestUtils::ProofSourceForTesting());
- QuicCryptoServerConfigPeer peer(&server);
-
- // Compress the certs for the first time.
- vector<string> certs = {"testcert"};
- scoped_refptr<ProofSource::Chain> chain(new ProofSource::Chain(certs));
- string common_certs = "";
- string cached_certs = "";
-
- string compressed = peer.CompressChain(&compressed_certs_cache, chain,
- common_certs, cached_certs, nullptr);
- EXPECT_EQ(compressed_certs_cache.Size(), 1u);
-
- // Compress the same certs, should use cache if available.
- string compressed2 = peer.CompressChain(&compressed_certs_cache, chain,
- common_certs, cached_certs, nullptr);
- EXPECT_EQ(compressed, compressed2);
- EXPECT_EQ(compressed_certs_cache.Size(), 1u);
-}
-
-TEST(QuicCryptoServerConfigTest, CompressDifferentCerts) {
- // This test compresses a set of similar but not identical certs. Cache if
- // used should return cache miss and add all the compressed certs.
- QuicCompressedCertsCache compressed_certs_cache(
- QuicCompressedCertsCache::kQuicCompressedCertsCacheSize);
-
- QuicRandom* rand = QuicRandom::GetInstance();
- QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
- CryptoTestUtils::ProofSourceForTesting());
- QuicCryptoServerConfigPeer peer(&server);
-
- vector<string> certs = {"testcert"};
- scoped_refptr<ProofSource::Chain> chain(new ProofSource::Chain(certs));
- string common_certs = "";
- string cached_certs = "";
-
- string compressed = peer.CompressChain(&compressed_certs_cache, chain,
- common_certs, cached_certs, nullptr);
- EXPECT_EQ(compressed_certs_cache.Size(), 1u);
-
- // Compress a similar certs which only differs in the chain.
- scoped_refptr<ProofSource::Chain> chain2(new ProofSource::Chain(certs));
-
- string compressed2 = peer.CompressChain(&compressed_certs_cache, chain2,
- common_certs, cached_certs, nullptr);
- EXPECT_EQ(compressed_certs_cache.Size(), 2u);
-
- // Compress a similar certs which only differs in common certs field.
- static const uint64_t set_hash = 42;
- std::unique_ptr<CommonCertSets> common_sets(
- CryptoTestUtils::MockCommonCertSets(certs[0], set_hash, 1));
- StringPiece different_common_certs(reinterpret_cast<const char*>(&set_hash),
- sizeof(set_hash));
- string compressed3 = peer.CompressChain(&compressed_certs_cache, chain,
- different_common_certs.as_string(),
- cached_certs, common_sets.get());
- EXPECT_EQ(compressed_certs_cache.Size(), 3u);
-}
-
-class SourceAddressTokenTest : public ::testing::Test {
- public:
- SourceAddressTokenTest()
- : ip4_(Loopback4()),
- ip4_dual_(ConvertIPv4ToIPv4MappedIPv6(ip4_)),
- ip6_(Loopback6()),
- original_time_(QuicWallTime::Zero()),
- rand_(QuicRandom::GetInstance()),
- server_(QuicCryptoServerConfig::TESTING,
- rand_,
- CryptoTestUtils::ProofSourceForTesting()),
- peer_(&server_) {
- // Advance the clock to some non-zero time.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000000));
- original_time_ = clock_.WallNow();
-
- primary_config_.reset(server_.AddDefaultConfig(
- rand_, &clock_, QuicCryptoServerConfig::ConfigOptions()));
-
- // Add a config that overrides the default boxer.
- QuicCryptoServerConfig::ConfigOptions options;
- options.id = kOverride;
- override_config_protobuf_.reset(
- QuicCryptoServerConfig::GenerateConfig(rand_, &clock_, options));
- override_config_protobuf_->set_source_address_token_secret_override(
- "a secret key");
- // Lower priority than the default config.
- override_config_protobuf_->set_priority(1);
- override_config_.reset(
- server_.AddConfig(override_config_protobuf_.get(), original_time_));
- }
-
- string NewSourceAddressToken(string config_id, const IPAddress& ip) {
- return NewSourceAddressToken(config_id, ip, nullptr);
- }
-
- string NewSourceAddressToken(string config_id,
- const IPAddress& ip,
- const SourceAddressTokens& previous_tokens) {
- return peer_.NewSourceAddressToken(config_id, previous_tokens, ip, rand_,
- clock_.WallNow(), nullptr);
- }
-
- string NewSourceAddressToken(string config_id,
- const IPAddress& ip,
- CachedNetworkParameters* cached_network_params) {
- SourceAddressTokens previous_tokens;
- return peer_.NewSourceAddressToken(config_id, previous_tokens, ip, rand_,
- clock_.WallNow(), cached_network_params);
- }
-
- HandshakeFailureReason ValidateSourceAddressTokens(string config_id,
- StringPiece srct,
- const IPAddress& ip) {
- return ValidateSourceAddressTokens(config_id, srct, ip, nullptr);
- }
-
- HandshakeFailureReason ValidateSourceAddressTokens(
- string config_id,
- StringPiece srct,
- const IPAddress& ip,
- CachedNetworkParameters* cached_network_params) {
- return peer_.ValidateSourceAddressTokens(
- config_id, srct, ip, clock_.WallNow(), cached_network_params);
- }
-
- const string kPrimary = "<primary>";
- const string kOverride = "Config with custom source address token key";
-
- IPAddress ip4_;
- IPAddress ip4_dual_;
- IPAddress ip6_;
-
- MockClock clock_;
- QuicWallTime original_time_;
- QuicRandom* rand_ = QuicRandom::GetInstance();
- QuicCryptoServerConfig server_;
- QuicCryptoServerConfigPeer peer_;
- // Stores the primary config.
- std::unique_ptr<CryptoHandshakeMessage> primary_config_;
- std::unique_ptr<QuicServerConfigProtobuf> override_config_protobuf_;
- std::unique_ptr<CryptoHandshakeMessage> override_config_;
-};
-
-// Test basic behavior of source address tokens including being specific
-// to a single IP address and server config.
-TEST_F(SourceAddressTokenTest, NewSourceAddressToken) {
- // Primary config generates configs that validate successfully.
- const string token4 = NewSourceAddressToken(kPrimary, ip4_);
- const string token4d = NewSourceAddressToken(kPrimary, ip4_dual_);
- const string token6 = NewSourceAddressToken(kPrimary, ip6_);
- EXPECT_EQ(HANDSHAKE_OK, ValidateSourceAddressTokens(kPrimary, token4, ip4_));
- ASSERT_EQ(HANDSHAKE_OK,
- ValidateSourceAddressTokens(kPrimary, token4, ip4_dual_));
- ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
- ValidateSourceAddressTokens(kPrimary, token4, ip6_));
- ASSERT_EQ(HANDSHAKE_OK, ValidateSourceAddressTokens(kPrimary, token4d, ip4_));
- ASSERT_EQ(HANDSHAKE_OK,
- ValidateSourceAddressTokens(kPrimary, token4d, ip4_dual_));
- ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
- ValidateSourceAddressTokens(kPrimary, token4d, ip6_));
- ASSERT_EQ(HANDSHAKE_OK, ValidateSourceAddressTokens(kPrimary, token6, ip6_));
-
- // Override config generates configs that validate successfully.
- const string override_token4 = NewSourceAddressToken(kOverride, ip4_);
- const string override_token6 = NewSourceAddressToken(kOverride, ip6_);
- ASSERT_EQ(HANDSHAKE_OK,
- ValidateSourceAddressTokens(kOverride, override_token4, ip4_));
- ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE,
- ValidateSourceAddressTokens(kOverride, override_token4, ip6_));
- ASSERT_EQ(HANDSHAKE_OK,
- ValidateSourceAddressTokens(kOverride, override_token6, ip6_));
-
- // Tokens generated by the primary config do not validate
- // successfully against the override config, and vice versa.
- ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
- ValidateSourceAddressTokens(kOverride, token4, ip4_));
- ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
- ValidateSourceAddressTokens(kOverride, token6, ip6_));
- ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
- ValidateSourceAddressTokens(kPrimary, override_token4, ip4_));
- ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE,
- ValidateSourceAddressTokens(kPrimary, override_token6, ip6_));
-}
-
-TEST_F(SourceAddressTokenTest, NewSourceAddressTokenExpiration) {
- const string token = NewSourceAddressToken(kPrimary, ip4_);
-
- // Validation fails if the token is from the future.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(-3600 * 2));
- ASSERT_EQ(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE,
- ValidateSourceAddressTokens(kPrimary, token, ip4_));
-
- // Validation fails after tokens expire.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(86400 * 7));
- ASSERT_EQ(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE,
- ValidateSourceAddressTokens(kPrimary, token, ip4_));
-}
-
-TEST_F(SourceAddressTokenTest, NewSourceAddressTokenWithNetworkParams) {
- // Make sure that if the source address token contains CachedNetworkParameters
- // that this gets written to ValidateSourceAddressToken output argument.
- CachedNetworkParameters cached_network_params_input;
- cached_network_params_input.set_bandwidth_estimate_bytes_per_second(1234);
- const string token4_with_cached_network_params =
- NewSourceAddressToken(kPrimary, ip4_, &cached_network_params_input);
-
- CachedNetworkParameters cached_network_params_output;
- EXPECT_NE(cached_network_params_output.SerializeAsString(),
- cached_network_params_input.SerializeAsString());
- ValidateSourceAddressTokens(kPrimary, token4_with_cached_network_params, ip4_,
- &cached_network_params_output);
- EXPECT_EQ(cached_network_params_output.SerializeAsString(),
- cached_network_params_input.SerializeAsString());
-}
-
-// Test the ability for a source address token to be valid for multiple
-// addresses.
-TEST_F(SourceAddressTokenTest, SourceAddressTokenMultipleAddresses) {
- QuicWallTime now = clock_.WallNow();
-
- // Now create a token which is usable for both addresses.
- SourceAddressToken previous_token;
- IPAddress ip_address = ip6_;
- if (ip6_.IsIPv4()) {
- ip_address = ConvertIPv4ToIPv4MappedIPv6(ip_address);
- }
- previous_token.set_ip(IPAddressToPackedString(ip_address));
- previous_token.set_timestamp(now.ToUNIXSeconds());
- SourceAddressTokens previous_tokens;
- (*previous_tokens.add_tokens()) = previous_token;
- const string token4or6 =
- NewSourceAddressToken(kPrimary, ip4_, previous_tokens);
-
- EXPECT_EQ(HANDSHAKE_OK,
- ValidateSourceAddressTokens(kPrimary, token4or6, ip4_));
- ASSERT_EQ(HANDSHAKE_OK,
- ValidateSourceAddressTokens(kPrimary, token4or6, ip6_));
-}
-
-TEST(QuicCryptoServerConfigTest, ValidateServerNonce) {
- QuicRandom* rand = QuicRandom::GetInstance();
- QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
- CryptoTestUtils::ProofSourceForTesting());
- QuicCryptoServerConfigPeer peer(&server);
-
- StringPiece message("hello world");
- const size_t key_size = CryptoSecretBoxer::GetKeySize();
- std::unique_ptr<uint8_t[]> key(new uint8_t[key_size]);
- memset(key.get(), 0x11, key_size);
-
- CryptoSecretBoxer boxer;
- boxer.SetKeys({string(reinterpret_cast<char*>(key.get()), key_size)});
- const string box = boxer.Box(rand, message);
- MockClock clock;
- QuicWallTime now = clock.WallNow();
- const QuicWallTime original_time = now;
- EXPECT_EQ(SERVER_NONCE_DECRYPTION_FAILURE,
- peer.ValidateServerNonce(box, now));
-
- string server_nonce = peer.NewServerNonce(rand, now);
- EXPECT_EQ(HANDSHAKE_OK, peer.ValidateServerNonce(server_nonce, now));
- EXPECT_EQ(SERVER_NONCE_NOT_UNIQUE_FAILURE,
- peer.ValidateServerNonce(server_nonce, now));
-
- now = original_time.Add(QuicTime::Delta::FromSeconds(1000 * 7));
- server_nonce = peer.NewServerNonce(rand, now);
- EXPECT_EQ(HANDSHAKE_OK, peer.ValidateServerNonce(server_nonce, now));
-}
-
-class CryptoServerConfigsTest : public ::testing::Test {
- public:
- CryptoServerConfigsTest()
- : rand_(QuicRandom::GetInstance()),
- config_(QuicCryptoServerConfig::TESTING,
- rand_,
- CryptoTestUtils::ProofSourceForTesting()),
- test_peer_(&config_) {}
-
- void SetUp() override {
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000));
- }
-
- // SetConfigs constructs suitable config protobufs and calls SetConfigs on
- // |config_|. The arguments are given as nullptr-terminated pairs. The first
- // of each pair is the server config ID of a Config. The second is the
- // |primary_time| of that Config, given in epoch seconds. (Although note that,
- // in these tests, time is set to 1000 seconds since the epoch.) For example:
- // SetConfigs(nullptr); // calls |config_.SetConfigs| with no protobufs.
- //
- // // Calls |config_.SetConfigs| with two protobufs: one for a Config with
- // // a |primary_time| of 900 and priority 1, and another with
- // // a |primary_time| of 1000 and priority 2.
-
- // CheckConfigs(
- // "id1", 900, 1,
- // "id2", 1000, 2,
- // nullptr);
- //
- // If the server config id starts with "INVALID" then the generated protobuf
- // will be invalid.
- void SetConfigs(const char* server_config_id1, ...) {
- const char kOrbit[] = "12345678";
-
- va_list ap;
- va_start(ap, server_config_id1);
- bool has_invalid = false;
- bool is_empty = true;
-
- vector<QuicServerConfigProtobuf*> protobufs;
- bool first = true;
- for (;;) {
- const char* server_config_id;
- if (first) {
- server_config_id = server_config_id1;
- first = false;
- } else {
- server_config_id = va_arg(ap, const char*);
- }
-
- if (!server_config_id) {
- break;
- }
-
- is_empty = false;
- int primary_time = va_arg(ap, int);
- int priority = va_arg(ap, int);
-
- QuicCryptoServerConfig::ConfigOptions options;
- options.id = server_config_id;
- options.orbit = kOrbit;
- QuicServerConfigProtobuf* protobuf(
- QuicCryptoServerConfig::GenerateConfig(rand_, &clock_, options));
- protobuf->set_primary_time(primary_time);
- protobuf->set_priority(priority);
- if (string(server_config_id).find("INVALID") == 0) {
- protobuf->clear_key();
- has_invalid = true;
- }
- protobufs.push_back(protobuf);
- }
-
- ASSERT_EQ(!has_invalid && !is_empty,
- config_.SetConfigs(protobufs, clock_.WallNow()));
- STLDeleteElements(&protobufs);
- }
-
- protected:
- QuicRandom* const rand_;
- MockClock clock_;
- QuicCryptoServerConfig config_;
- QuicCryptoServerConfigPeer test_peer_;
-};
-
-TEST_F(CryptoServerConfigsTest, NoConfigs) {
- test_peer_.CheckConfigs(nullptr);
-}
-
-TEST_F(CryptoServerConfigsTest, MakePrimaryFirst) {
- // Make sure that "b" is primary even though "a" comes first.
- SetConfigs("a", 1100, 1, "b", 900, 1, nullptr);
- test_peer_.CheckConfigs("a", false, "b", true, nullptr);
-}
-
-TEST_F(CryptoServerConfigsTest, MakePrimarySecond) {
- // Make sure that a remains primary after b is added.
- SetConfigs("a", 900, 1, "b", 1100, 1, nullptr);
- test_peer_.CheckConfigs("a", true, "b", false, nullptr);
-}
-
-TEST_F(CryptoServerConfigsTest, Delete) {
- // Ensure that configs get deleted when removed.
- SetConfigs("a", 800, 1, "b", 900, 1, "c", 1100, 1, nullptr);
- test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr);
- SetConfigs("b", 900, 1, "c", 1100, 1, nullptr);
- test_peer_.CheckConfigs("b", true, "c", false, nullptr);
-}
-
-TEST_F(CryptoServerConfigsTest, DeletePrimary) {
- // Ensure that deleting the primary config works.
- SetConfigs("a", 800, 1, "b", 900, 1, "c", 1100, 1, nullptr);
- test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr);
- SetConfigs("a", 800, 1, "c", 1100, 1, nullptr);
- test_peer_.CheckConfigs("a", true, "c", false, nullptr);
-}
-
-TEST_F(CryptoServerConfigsTest, FailIfDeletingAllConfigs) {
- // Ensure that configs get deleted when removed.
- SetConfigs("a", 800, 1, "b", 900, 1, nullptr);
- test_peer_.CheckConfigs("a", false, "b", true, nullptr);
- SetConfigs(nullptr);
- // Config change is rejected, still using old configs.
- test_peer_.CheckConfigs("a", false, "b", true, nullptr);
-}
-
-TEST_F(CryptoServerConfigsTest, ChangePrimaryTime) {
- // Check that updates to primary time get picked up.
- SetConfigs("a", 400, 1, "b", 800, 1, "c", 1200, 1, nullptr);
- test_peer_.SelectNewPrimaryConfig(500);
- test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr);
- SetConfigs("a", 1200, 1, "b", 800, 1, "c", 400, 1, nullptr);
- test_peer_.SelectNewPrimaryConfig(500);
- test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr);
-}
-
-TEST_F(CryptoServerConfigsTest, AllConfigsInThePast) {
- // Check that the most recent config is selected.
- SetConfigs("a", 400, 1, "b", 800, 1, "c", 1200, 1, nullptr);
- test_peer_.SelectNewPrimaryConfig(1500);
- test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr);
-}
-
-TEST_F(CryptoServerConfigsTest, AllConfigsInTheFuture) {
- // Check that the first config is selected.
- SetConfigs("a", 400, 1, "b", 800, 1, "c", 1200, 1, nullptr);
- test_peer_.SelectNewPrimaryConfig(100);
- test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr);
-}
-
-TEST_F(CryptoServerConfigsTest, SortByPriority) {
- // Check that priority is used to decide on a primary config when
- // configs have the same primary time.
- SetConfigs("a", 900, 1, "b", 900, 2, "c", 900, 3, nullptr);
- test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr);
- test_peer_.SelectNewPrimaryConfig(800);
- test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr);
- test_peer_.SelectNewPrimaryConfig(1000);
- test_peer_.CheckConfigs("a", true, "b", false, "c", false, nullptr);
-
- // Change priorities and expect sort order to change.
- SetConfigs("a", 900, 2, "b", 900, 1, "c", 900, 0, nullptr);
- test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr);
- test_peer_.SelectNewPrimaryConfig(800);
- test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr);
- test_peer_.SelectNewPrimaryConfig(1000);
- test_peer_.CheckConfigs("a", false, "b", false, "c", true, nullptr);
-}
-
-TEST_F(CryptoServerConfigsTest, AdvancePrimary) {
- // Check that a new primary config is enabled at the right time.
- SetConfigs("a", 900, 1, "b", 1100, 1, nullptr);
- test_peer_.SelectNewPrimaryConfig(1000);
- test_peer_.CheckConfigs("a", true, "b", false, nullptr);
- test_peer_.SelectNewPrimaryConfig(1101);
- test_peer_.CheckConfigs("a", false, "b", true, nullptr);
-}
-
-TEST_F(CryptoServerConfigsTest, InvalidConfigs) {
- // Ensure that invalid configs don't change anything.
- SetConfigs("a", 800, 1, "b", 900, 1, "c", 1100, 1, nullptr);
- test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr);
- SetConfigs("a", 800, 1, "c", 1100, 1, "INVALID1", 1000, 1, nullptr);
- test_peer_.CheckConfigs("a", false, "b", true, "c", false, nullptr);
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/quic_decrypter.cc b/chromium/net/quic/crypto/quic_decrypter.cc
deleted file mode 100644
index 7b2df54d137..00000000000
--- a/chromium/net/quic/crypto/quic_decrypter.cc
+++ /dev/null
@@ -1,49 +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/crypto/quic_decrypter.h"
-
-#include "crypto/hkdf.h"
-#include "net/quic/crypto/aes_128_gcm_12_decrypter.h"
-#include "net/quic/crypto/chacha20_poly1305_decrypter.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/null_decrypter.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-
-// static
-QuicDecrypter* QuicDecrypter::Create(QuicTag algorithm) {
- switch (algorithm) {
- case kAESG:
- return new Aes128Gcm12Decrypter();
- case kCC20:
- return new ChaCha20Poly1305Decrypter();
- case kNULL:
- return new NullDecrypter();
- default:
- LOG(FATAL) << "Unsupported algorithm: " << algorithm;
- return nullptr;
- }
-}
-
-// static
-void QuicDecrypter::DiversifyPreliminaryKey(StringPiece preliminary_key,
- StringPiece nonce_prefix,
- DiversificationNonce nonce,
- size_t key_size,
- size_t nonce_prefix_size,
- string* out_key,
- string* out_nonce_prefix) {
- crypto::HKDF hkdf(preliminary_key.as_string() + nonce_prefix.as_string(),
- StringPiece(nonce, kDiversificationNonceSize),
- "QUIC key diversification", 0, key_size, 0,
- nonce_prefix_size, 0);
- *out_key = hkdf.server_write_key().as_string();
- *out_nonce_prefix = hkdf.server_write_iv().as_string();
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/quic_decrypter.h b/chromium/net/quic/crypto/quic_decrypter.h
deleted file mode 100644
index 993e3dadcb8..00000000000
--- a/chromium/net/quic/crypto/quic_decrypter.h
+++ /dev/null
@@ -1,98 +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.
-
-#ifndef NET_QUIC_CRYPTO_QUIC_DECRYPTER_H_
-#define NET_QUIC_CRYPTO_QUIC_DECRYPTER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "net/base/net_export.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-class NET_EXPORT_PRIVATE QuicDecrypter {
- public:
- virtual ~QuicDecrypter() {}
-
- static QuicDecrypter* Create(QuicTag algorithm);
-
- // Sets the encryption key. Returns true on success, false on failure.
- //
- // NOTE: The key is the client_write_key or server_write_key derived from
- // the master secret.
- virtual bool SetKey(base::StringPiece key) = 0;
-
- // Sets the fixed initial bytes of the nonce. Returns true on success,
- // false on failure.
- //
- // NOTE: The nonce prefix is the client_write_iv or server_write_iv
- // derived from the master secret. A 64-bit packet number will
- // be appended to form the nonce.
- //
- // <------------ 64 bits ----------->
- // +---------------------+----------------------------------+
- // | Fixed prefix | packet number |
- // +---------------------+----------------------------------+
- // Nonce format
- //
- // The security of the nonce format requires that QUIC never reuse a
- // packet number, even when retransmitting a lost packet.
- virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) = 0;
-
- // Sets the encryption key. Returns true on success, false on failure.
- // |DecryptPacket| may not be called until |SetDiversificationNonce| is
- // called and the preliminary keying material will be combined with that
- // nonce in order to create the actual key and nonce-prefix.
- //
- // If this function is called, neither |SetKey| nor |SetNoncePrefix| may be
- // called.
- virtual bool SetPreliminaryKey(base::StringPiece key) = 0;
-
- // SetDiversificationNonce uses |nonce| to derive final keys based on the
- // input keying material given by calling |SetPreliminaryKey|.
- //
- // Calling this function is a no-op if |SetPreliminaryKey| hasn't been
- // called.
- virtual bool SetDiversificationNonce(DiversificationNonce nonce) = 0;
-
- // Populates |output| with the decrypted |ciphertext| and populates
- // |output_length| with the length. Returns 0 if there is an error.
- // |output| size is specified by |max_output_length| and must be
- // at least as large as the ciphertext. |packet_number| is
- // appended to the |nonce_prefix| value provided in SetNoncePrefix()
- // to form the nonce.
- // TODO(wtc): add a way for DecryptPacket to report decryption failure due
- // to non-authentic inputs, as opposed to other reasons for failure.
- virtual bool DecryptPacket(QuicPathId path_id,
- QuicPacketNumber packet_number,
- base::StringPiece associated_data,
- base::StringPiece ciphertext,
- char* output,
- size_t* output_length,
- size_t max_output_length) = 0;
-
- // The name of the cipher.
- virtual const char* cipher_name() const = 0;
- // The ID of the cipher. Return 0x03000000 ORed with the 'cryptographic suite
- // selector'.
- virtual uint32_t cipher_id() const = 0;
-
- // For use by unit tests only.
- virtual base::StringPiece GetKey() const = 0;
- virtual base::StringPiece GetNoncePrefix() const = 0;
-
- static void DiversifyPreliminaryKey(base::StringPiece preliminary_key,
- base::StringPiece nonce_prefix,
- DiversificationNonce nonce,
- size_t key_size,
- size_t nonce_prefix_size,
- std::string* out_key,
- std::string* out_nonce_prefix);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_QUIC_DECRYPTER_H_
diff --git a/chromium/net/quic/crypto/quic_encrypter.cc b/chromium/net/quic/crypto/quic_encrypter.cc
deleted file mode 100644
index 917d23ba5dd..00000000000
--- a/chromium/net/quic/crypto/quic_encrypter.cc
+++ /dev/null
@@ -1,29 +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/crypto/quic_encrypter.h"
-
-#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
-#include "net/quic/crypto/chacha20_poly1305_encrypter.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/null_encrypter.h"
-
-namespace net {
-
-// static
-QuicEncrypter* QuicEncrypter::Create(QuicTag algorithm) {
- switch (algorithm) {
- case kAESG:
- return new Aes128Gcm12Encrypter();
- case kCC20:
- return new ChaCha20Poly1305Encrypter();
- case kNULL:
- return new NullEncrypter();
- default:
- LOG(FATAL) << "Unsupported algorithm: " << algorithm;
- return nullptr;
- }
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/quic_encrypter.h b/chromium/net/quic/crypto/quic_encrypter.h
deleted file mode 100644
index a4cc9efe8eb..00000000000
--- a/chromium/net/quic/crypto/quic_encrypter.h
+++ /dev/null
@@ -1,85 +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.
-
-#ifndef NET_QUIC_CRYPTO_QUIC_ENCRYPTER_H_
-#define NET_QUIC_CRYPTO_QUIC_ENCRYPTER_H_
-
-#include <stddef.h>
-
-#include "net/base/net_export.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-class NET_EXPORT_PRIVATE QuicEncrypter {
- public:
- virtual ~QuicEncrypter() {}
-
- static QuicEncrypter* Create(QuicTag algorithm);
-
- // Sets the encryption key. Returns true on success, false on failure.
- //
- // NOTE: The key is the client_write_key or server_write_key derived from
- // the master secret.
- virtual bool SetKey(base::StringPiece key) = 0;
-
- // Sets the fixed initial bytes of the nonce. Returns true on success,
- // false on failure.
- //
- // NOTE: The nonce prefix is the client_write_iv or server_write_iv
- // derived from the master secret. A 64-bit packet number will
- // be appended to form the nonce.
- //
- // <------------ 64 bits ----------->
- // +---------------------+----------------------------------+
- // | Fixed prefix | packet number |
- // +---------------------+----------------------------------+
- // Nonce format
- //
- // The security of the nonce format requires that QUIC never reuse a
- // packet number, even when retransmitting a lost packet.
- virtual bool SetNoncePrefix(base::StringPiece nonce_prefix) = 0;
-
- // Writes encrypted |plaintext| and a MAC over |plaintext| and
- // |associated_data| into output. Sets |output_length| to the number of
- // bytes written. Returns true on success or false if there was an error.
- // |packet_number| is appended to the |nonce_prefix| value provided in
- // SetNoncePrefix() to form the nonce. |output| must not overlap with
- // |associated_data|. If |output| overlaps with |plaintext| then
- // |plaintext| must be <= |output|.
- virtual bool EncryptPacket(QuicPathId path_id,
- QuicPacketNumber packet_number,
- base::StringPiece associated_data,
- base::StringPiece plaintext,
- char* output,
- size_t* output_length,
- size_t max_output_length) = 0;
-
- // GetKeySize() and GetNoncePrefixSize() tell the HKDF class how many bytes
- // of key material needs to be derived from the master secret.
- // NOTE: the sizes returned by GetKeySize() and GetNoncePrefixSize() are
- // also correct for the QuicDecrypter of the same algorithm. So only
- // QuicEncrypter has these two methods.
-
- // Returns the size in bytes of a key for the algorithm.
- virtual size_t GetKeySize() const = 0;
- // Returns the size in bytes of the fixed initial part of the nonce.
- virtual size_t GetNoncePrefixSize() 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;
-
- // Returns the length of the ciphertext that would be generated by encrypting
- // to plaintext of size |plaintext_size|.
- virtual size_t GetCiphertextSize(size_t plaintext_size) const = 0;
-
- // For use by unit tests only.
- virtual base::StringPiece GetKey() const = 0;
- virtual base::StringPiece GetNoncePrefix() const = 0;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_QUIC_ENCRYPTER_H_
diff --git a/chromium/net/quic/crypto/quic_random.cc b/chromium/net/quic/crypto/quic_random.cc
deleted file mode 100644
index cc8ef2768f7..00000000000
--- a/chromium/net/quic/crypto/quic_random.cc
+++ /dev/null
@@ -1,59 +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/crypto/quic_random.h"
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "crypto/random.h"
-#include "net/quic/quic_bug_tracker.h"
-
-namespace net {
-
-namespace {
-
-class DefaultRandom : public QuicRandom {
- public:
- static DefaultRandom* GetInstance();
-
- // QuicRandom implementation
- void RandBytes(void* data, size_t len) override;
- uint64_t RandUint64() override;
- void Reseed(const void* additional_entropy, size_t entropy_len) override;
-
- private:
- DefaultRandom() {}
- ~DefaultRandom() override {}
-
- friend struct base::DefaultSingletonTraits<DefaultRandom>;
- DISALLOW_COPY_AND_ASSIGN(DefaultRandom);
-};
-
-DefaultRandom* DefaultRandom::GetInstance() {
- return base::Singleton<DefaultRandom>::get();
-}
-
-void DefaultRandom::RandBytes(void* data, size_t len) {
- crypto::RandBytes(data, len);
-}
-
-uint64_t DefaultRandom::RandUint64() {
- uint64_t value;
- RandBytes(&value, sizeof(value));
- return value;
-}
-
-void DefaultRandom::Reseed(const void* additional_entropy, size_t entropy_len) {
- // No such function exists in crypto/random.h.
-}
-
-} // namespace
-
-// static
-QuicRandom* QuicRandom::GetInstance() {
- return DefaultRandom::GetInstance();
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/quic_random_test.cc b/chromium/net/quic/crypto/quic_random_test.cc
deleted file mode 100644
index 431a22118da..00000000000
--- a/chromium/net/quic/crypto/quic_random_test.cc
+++ /dev/null
@@ -1,40 +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/crypto/quic_random.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-TEST(QuicRandomTest, RandBytes) {
- unsigned char buf1[16];
- unsigned char buf2[16];
- memset(buf1, 0xaf, sizeof(buf1));
- memset(buf2, 0xaf, sizeof(buf2));
- ASSERT_EQ(0, memcmp(buf1, buf2, sizeof(buf1)));
-
- QuicRandom* rng = QuicRandom::GetInstance();
- rng->RandBytes(buf1, sizeof(buf1));
- EXPECT_NE(0, memcmp(buf1, buf2, sizeof(buf1)));
-}
-
-TEST(QuicRandomTest, RandUint64) {
- QuicRandom* rng = QuicRandom::GetInstance();
- uint64_t value1 = rng->RandUint64();
- uint64_t value2 = rng->RandUint64();
- EXPECT_NE(value1, value2);
-}
-
-TEST(QuicRandomTest, Reseed) {
- char buf[1024];
- memset(buf, 0xaf, sizeof(buf));
-
- QuicRandom* rng = QuicRandom::GetInstance();
- rng->Reseed(buf, sizeof(buf));
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/crypto/quic_server_info.cc b/chromium/net/quic/crypto/quic_server_info.cc
deleted file mode 100644
index 24edb9bd622..00000000000
--- a/chromium/net/quic/crypto/quic_server_info.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/crypto/quic_server_info.h"
-
-#include <limits>
-
-#include "base/pickle.h"
-
-using std::string;
-
-namespace {
-
-// TODO(rtenneti): Delete kQuicCryptoConfigVersionNoChloHash after
-// QUIC_VERSION_31 becomes the default.
-const int kQuicCryptoConfigVersionNoChloHash = 1;
-const int kQuicCryptoConfigVersion = 2;
-
-} // namespace
-
-namespace net {
-
-QuicServerInfo::State::State() {}
-
-QuicServerInfo::State::~State() {}
-
-void QuicServerInfo::State::Clear() {
- server_config.clear();
- source_address_token.clear();
- cert_sct.clear();
- chlo_hash.clear();
- server_config_sig.clear();
- certs.clear();
-}
-
-QuicServerInfo::QuicServerInfo(const QuicServerId& server_id)
- : server_id_(server_id) {}
-
-QuicServerInfo::~QuicServerInfo() {}
-
-const QuicServerInfo::State& QuicServerInfo::state() const {
- return state_;
-}
-
-QuicServerInfo::State* QuicServerInfo::mutable_state() {
- return &state_;
-}
-
-bool QuicServerInfo::Parse(const string& data) {
- State* state = mutable_state();
-
- state->Clear();
-
- bool r = ParseInner(data);
- if (!r)
- state->Clear();
- return r;
-}
-
-bool QuicServerInfo::ParseInner(const string& data) {
- State* state = mutable_state();
-
- // No data was read from the disk cache.
- if (data.empty()) {
- return false;
- }
-
- base::Pickle p(data.data(), data.size());
- base::PickleIterator iter(p);
-
- int version = -1;
- if (!iter.ReadInt(&version)) {
- DVLOG(1) << "Missing version";
- return false;
- }
-
- // TODO(rtenneti): Delete kQuicCryptoConfigVersionNoChloHash after
- // QUIC_VERSION_31 becomes the default.
- if (!(version == kQuicCryptoConfigVersionNoChloHash ||
- version == kQuicCryptoConfigVersion)) {
- DVLOG(1) << "Unsupported version";
- return false;
- }
-
- if (!iter.ReadString(&state->server_config)) {
- DVLOG(1) << "Malformed server_config";
- return false;
- }
- if (!iter.ReadString(&state->source_address_token)) {
- DVLOG(1) << "Malformed source_address_token";
- return false;
- }
- // TODO(rtenneti): Delete kQuicCryptoConfigVersionNoChloHash after
- // QUIC_VERSION_31 becomes the default.
- if (version == kQuicCryptoConfigVersionNoChloHash) {
- state->cert_sct.clear();
- state->chlo_hash.clear();
- } else {
- if (!iter.ReadString(&state->cert_sct)) {
- DVLOG(1) << "Malformed cert_sct";
- return false;
- }
- if (!iter.ReadString(&state->chlo_hash)) {
- DVLOG(1) << "Malformed chlo_hash";
- return false;
- }
- }
- if (!iter.ReadString(&state->server_config_sig)) {
- DVLOG(1) << "Malformed server_config_sig";
- return false;
- }
-
- // Read certs.
- uint32_t num_certs;
- if (!iter.ReadUInt32(&num_certs)) {
- DVLOG(1) << "Malformed num_certs";
- return false;
- }
-
- for (uint32_t i = 0; i < num_certs; i++) {
- string cert;
- if (!iter.ReadString(&cert)) {
- DVLOG(1) << "Malformed cert";
- return false;
- }
- state->certs.push_back(cert);
- }
-
- return true;
-}
-
-string QuicServerInfo::Serialize() {
- string pickled_data = SerializeInner();
- state_.Clear();
- return pickled_data;
-}
-
-string QuicServerInfo::SerializeInner() const {
- base::Pickle p(sizeof(base::Pickle::Header));
-
- if (!p.WriteInt(kQuicCryptoConfigVersion) ||
- !p.WriteString(state_.server_config) ||
- !p.WriteString(state_.source_address_token) ||
- !p.WriteString(state_.cert_sct) || !p.WriteString(state_.chlo_hash) ||
- !p.WriteString(state_.server_config_sig) ||
- state_.certs.size() > std::numeric_limits<uint32_t>::max() ||
- !p.WriteUInt32(state_.certs.size())) {
- return string();
- }
-
- for (size_t i = 0; i < state_.certs.size(); i++) {
- if (!p.WriteString(state_.certs[i])) {
- return string();
- }
- }
-
- return string(reinterpret_cast<const char*>(p.data()), p.size());
-}
-
-QuicServerInfoFactory::~QuicServerInfoFactory() {}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/quic_server_info.h b/chromium/net/quic/crypto/quic_server_info.h
deleted file mode 100644
index f96de985421..00000000000
--- a/chromium/net/quic/crypto/quic_server_info.h
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_CRYPTO_QUIC_SERVER_INFO_H_
-#define NET_QUIC_CRYPTO_QUIC_SERVER_INFO_H_
-
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "net/base/completion_callback.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_server_id.h"
-
-namespace net {
-
-class X509Certificate;
-
-// QuicServerInfo is an interface for fetching information about a QUIC server.
-// This information may be stored on disk so does not include keys or other
-// sensitive information. Primarily it's intended for caching the QUIC server's
-// crypto config.
-class NET_EXPORT_PRIVATE QuicServerInfo {
- public:
- explicit QuicServerInfo(const QuicServerId& server_id);
- virtual ~QuicServerInfo();
-
- // Start will commence the lookup. This must be called before any other
- // methods. By opportunistically calling this early, it may be possible to
- // overlap this object's lookup and reduce latency.
- virtual void Start() = 0;
-
- // WaitForDataReady returns OK if the fetch of the requested data has
- // completed. Otherwise it returns ERR_IO_PENDING and will call |callback| on
- // the current thread when ready.
- //
- // Only a single callback can be outstanding at a given time and, in the
- // event that WaitForDataReady returns OK, it's the caller's responsibility
- // to delete |callback|.
- //
- // |callback| may be NULL, in which case ERR_IO_PENDING may still be returned
- // but, obviously, a callback will never be made.
- virtual int WaitForDataReady(const CompletionCallback& callback) = 0;
-
- // Reset's WaitForDataReady callback. This method shouldn't have any side
- // effects (could be called even if HttpCache doesn't exist).
- virtual void ResetWaitForDataReadyCallback() = 0;
-
- // Cancel's WaitForDataReady callback. |callback| passed in WaitForDataReady
- // will not be called.
- virtual void CancelWaitForDataReadyCallback() = 0;
-
- // Returns true if data is loaded from disk cache and ready (WaitForDataReady
- // doesn't have a pending callback).
- virtual bool IsDataReady() = 0;
-
- // Returns true if the object is ready to persist data, in other words, if
- // data is loaded from disk cache and ready and there are no pending writes.
- virtual bool IsReadyToPersist() = 0;
-
- // Persist allows for the server information to be updated for future users.
- // This is a fire and forget operation: the caller may drop its reference
- // from this object and the store operation will still complete. This can
- // only be called once WaitForDataReady has returned OK or called its
- // callback.
- virtual void Persist() = 0;
-
- // Called whenever an external cache reuses quic server config.
- virtual void OnExternalCacheHit() = 0;
-
- struct State {
- State();
- ~State();
-
- void Clear();
-
- // This class matches QuicClientCryptoConfig::CachedState.
- std::string server_config; // A serialized handshake message.
- std::string source_address_token; // An opaque proof of IP ownership.
- std::string cert_sct; // Signed timestamp of the leaf cert.
- std::string chlo_hash; // Hash of the CHLO message.
- std::vector<std::string> certs; // A list of certificates in leaf-first
- // order.
- std::string server_config_sig; // A signature of |server_config_|.
-
- private:
- DISALLOW_COPY_AND_ASSIGN(State);
- };
-
- // Once the data is ready, it can be read using the following members. These
- // members can then be updated before calling |Persist|.
- const State& state() const;
- State* mutable_state();
-
- base::TimeTicks wait_for_data_start_time() const {
- return wait_for_data_start_time_;
- }
-
- base::TimeTicks wait_for_data_end_time() const {
- return wait_for_data_end_time_;
- }
-
- protected:
- // Parse parses pickled data and fills out the public member fields of this
- // object. It returns true iff the parse was successful. The public member
- // fields will be set to something sane in any case.
- bool Parse(const std::string& data);
- std::string Serialize();
-
- State state_;
-
- // Time when WaitForDataReady was called and when it has finished.
- base::TimeTicks wait_for_data_start_time_;
- base::TimeTicks wait_for_data_end_time_;
-
- // This is the QUIC server (hostname, port, is_https, privacy_mode) tuple for
- // which we restore the crypto_config.
- const QuicServerId server_id_;
-
- private:
- // ParseInner is a helper function for Parse.
- bool ParseInner(const std::string& data);
-
- // SerializeInner is a helper function for Serialize.
- std::string SerializeInner() const;
-
- DISALLOW_COPY_AND_ASSIGN(QuicServerInfo);
-};
-
-class NET_EXPORT_PRIVATE QuicServerInfoFactory {
- public:
- QuicServerInfoFactory() {}
- virtual ~QuicServerInfoFactory();
-
- // GetForServer returns a fresh, allocated QuicServerInfo for the given
- // |server_id| or NULL on failure.
- virtual QuicServerInfo* GetForServer(const QuicServerId& server_id) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(QuicServerInfoFactory);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_QUIC_SERVER_INFO_H_
diff --git a/chromium/net/quic/crypto/scoped_evp_aead_ctx.cc b/chromium/net/quic/crypto/scoped_evp_aead_ctx.cc
deleted file mode 100644
index 7facf35e218..00000000000
--- a/chromium/net/quic/crypto/scoped_evp_aead_ctx.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/crypto/scoped_evp_aead_ctx.h"
-
-namespace net {
-
-ScopedEVPAEADCtx::ScopedEVPAEADCtx() {
- ctx_.aead = nullptr;
-}
-
-ScopedEVPAEADCtx::~ScopedEVPAEADCtx() {
- if (ctx_.aead != nullptr) {
- EVP_AEAD_CTX_cleanup(&ctx_);
- }
-}
-
-EVP_AEAD_CTX* ScopedEVPAEADCtx::get() {
- return &ctx_;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/strike_register.cc b/chromium/net/quic/crypto/strike_register.cc
deleted file mode 100644
index 9cea0f11f8c..00000000000
--- a/chromium/net/quic/crypto/strike_register.cc
+++ /dev/null
@@ -1,519 +0,0 @@
-// Copyright (c) 2013 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/crypto/strike_register.h"
-
-#include <algorithm>
-#include <limits>
-
-#include "base/logging.h"
-
-using std::pair;
-using std::set;
-using std::vector;
-
-namespace net {
-
-namespace {
-
-uint32_t GetInitialHorizon(uint32_t current_time_internal,
- uint32_t window_secs,
- StrikeRegister::StartupType startup) {
- if (startup == StrikeRegister::DENY_REQUESTS_AT_STARTUP) {
- // The horizon is initially set |window_secs| into the future because, if
- // we just crashed, then we may have accepted nonces in the span
- // [current_time...current_time+window_secs] and so we conservatively
- // reject the whole timespan unless |startup| tells us otherwise.
- return current_time_internal + window_secs + 1;
- } else { // startup == StrikeRegister::NO_STARTUP_PERIOD_NEEDED
- // The orbit can be assumed to be globally unique. Use a horizon
- // in the past.
- return 0;
- }
-}
-
-} // namespace
-
-// static
-const uint32_t StrikeRegister::kExternalNodeSize = 24;
-// static
-const uint32_t StrikeRegister::kNil = (1u << 31) | 1;
-// static
-const uint32_t StrikeRegister::kExternalFlag = 1 << 23;
-
-// InternalNode represents a non-leaf node in the critbit tree. See the comment
-// in the .h file for details.
-class StrikeRegister::InternalNode {
- public:
- void SetChild(unsigned direction, uint32_t child) {
- data_[direction] = (data_[direction] & 0xff) | (child << 8);
- }
-
- void SetCritByte(uint8_t critbyte) {
- data_[0] = (data_[0] & 0xffffff00) | critbyte;
- }
-
- void SetOtherBits(uint8_t otherbits) {
- data_[1] = (data_[1] & 0xffffff00) | otherbits;
- }
-
- void SetNextPtr(uint32_t next) { data_[0] = next; }
-
- uint32_t next() const { return data_[0]; }
-
- uint32_t child(unsigned n) const { return data_[n] >> 8; }
-
- uint8_t critbyte() const { return static_cast<uint8_t>(data_[0]); }
-
- uint8_t otherbits() const { return static_cast<uint8_t>(data_[1]); }
-
- // These bytes are organised thus:
- // <24 bits> left child
- // <8 bits> crit-byte
- // <24 bits> right child
- // <8 bits> other-bits
- uint32_t data_[2];
-};
-
-// kCreationTimeFromInternalEpoch contains the number of seconds between the
-// start of the internal epoch and the creation time. This allows us
-// to consider times that are before the creation time.
-static const uint32_t kCreationTimeFromInternalEpoch = 63115200; // 2 years.
-
-void StrikeRegister::ValidateStrikeRegisterConfig(unsigned max_entries) {
- // We only have 23 bits of index available.
- CHECK_LT(max_entries, 1u << 23);
- CHECK_GT(max_entries, 1u); // There must be at least two entries.
- CHECK_EQ(sizeof(InternalNode), 8u); // in case of compiler changes.
-}
-
-StrikeRegister::StrikeRegister(unsigned max_entries,
- uint32_t current_time,
- uint32_t window_secs,
- const uint8_t orbit[8],
- StartupType startup)
- : max_entries_(max_entries),
- window_secs_(window_secs),
- internal_epoch_(current_time > kCreationTimeFromInternalEpoch
- ? current_time - kCreationTimeFromInternalEpoch
- : 0),
- horizon_(GetInitialHorizon(ExternalTimeToInternal(current_time),
- window_secs,
- startup)) {
- memcpy(orbit_, orbit, sizeof(orbit_));
-
- ValidateStrikeRegisterConfig(max_entries);
- internal_nodes_ = new InternalNode[max_entries];
- external_nodes_.reset(new uint8_t[kExternalNodeSize * max_entries]);
-
- Reset();
-}
-
-StrikeRegister::~StrikeRegister() {
- delete[] internal_nodes_;
-}
-
-void StrikeRegister::Reset() {
- // Thread a free list through all of the internal nodes.
- internal_node_free_head_ = 0;
- for (unsigned i = 0; i < max_entries_ - 1; i++) {
- internal_nodes_[i].SetNextPtr(i + 1);
- }
- internal_nodes_[max_entries_ - 1].SetNextPtr(kNil);
-
- // Also thread a free list through the external nodes.
- external_node_free_head_ = 0;
- for (unsigned i = 0; i < max_entries_ - 1; i++) {
- external_node_next_ptr(i) = i + 1;
- }
- external_node_next_ptr(max_entries_ - 1) = kNil;
-
- // This is the root of the tree.
- internal_node_head_ = kNil;
-}
-
-InsertStatus StrikeRegister::Insert(const uint8_t nonce[32],
- uint32_t current_time_external) {
- // Make space for the insertion if the strike register is full.
- while (external_node_free_head_ == kNil || internal_node_free_head_ == kNil) {
- DropOldestNode();
- }
-
- const uint32_t current_time = ExternalTimeToInternal(current_time_external);
-
- // Check to see if the orbit is correct.
- if (memcmp(nonce + sizeof(current_time), orbit_, sizeof(orbit_))) {
- return NONCE_INVALID_ORBIT_FAILURE;
- }
-
- const uint32_t nonce_time = ExternalTimeToInternal(TimeFromBytes(nonce));
-
- // Check that the timestamp is in the valid range.
- pair<uint32_t, uint32_t> valid_range =
- StrikeRegister::GetValidRange(current_time);
- if (nonce_time < valid_range.first || nonce_time > valid_range.second) {
- return NONCE_INVALID_TIME_FAILURE;
- }
-
- // We strip the orbit out of the nonce.
- uint8_t value[24];
- memcpy(value, nonce, sizeof(nonce_time));
- memcpy(value + sizeof(nonce_time),
- nonce + sizeof(nonce_time) + sizeof(orbit_),
- sizeof(value) - sizeof(nonce_time));
-
- // Find the best match to |value| in the crit-bit tree. The best match is
- // simply the value which /could/ match |value|, if any does, so we still
- // need a memcmp to check.
- uint32_t best_match_index = BestMatch(value);
- if (best_match_index == kNil) {
- // Empty tree. Just insert the new value at the root.
- uint32_t index = GetFreeExternalNode();
- memcpy(external_node(index), value, sizeof(value));
- internal_node_head_ = (index | kExternalFlag) << 8;
- DCHECK_LE(horizon_, nonce_time);
- return NONCE_OK;
- }
-
- const uint8_t* best_match = external_node(best_match_index);
- if (memcmp(best_match, value, sizeof(value)) == 0) {
- // We found the value in the tree.
- return NONCE_NOT_UNIQUE_FAILURE;
- }
-
- // We are going to insert a new entry into the tree, so get the nodes now.
- uint32_t internal_node_index = GetFreeInternalNode();
- uint32_t external_node_index = GetFreeExternalNode();
-
- // If we just evicted the best match, then we have to try and match again.
- // We know that we didn't just empty the tree because we require that
- // max_entries_ >= 2. Also, we know that it doesn't match because, if it
- // did, it would have been returned previously.
- if (external_node_index == best_match_index) {
- best_match_index = BestMatch(value);
- best_match = external_node(best_match_index);
- }
-
- // Now we need to find the first bit where we differ from |best_match|.
- uint8_t differing_byte;
- uint8_t new_other_bits;
- for (differing_byte = 0; differing_byte < arraysize(value);
- differing_byte++) {
- new_other_bits = value[differing_byte] ^ best_match[differing_byte];
- if (new_other_bits) {
- break;
- }
- }
-
- // Once we have the XOR the of first differing byte in new_other_bits we need
- // to find the most significant differing bit. We could do this with a simple
- // for loop, testing bits 7..0. Instead we fold the bits so that we end up
- // with a byte where all the bits below the most significant one, are set.
- new_other_bits |= new_other_bits >> 1;
- new_other_bits |= new_other_bits >> 2;
- new_other_bits |= new_other_bits >> 4;
- // Now this bit trick results in all the bits set, except the original
- // most-significant one.
- new_other_bits = (new_other_bits & ~(new_other_bits >> 1)) ^ 255;
-
- // Consider the effect of ORing against |new_other_bits|. If |value| did not
- // have the critical bit set, the result is the same as |new_other_bits|. If
- // it did, the result is all ones.
-
- unsigned newdirection;
- if ((new_other_bits | value[differing_byte]) == 0xff) {
- newdirection = 1;
- } else {
- newdirection = 0;
- }
-
- memcpy(external_node(external_node_index), value, sizeof(value));
- InternalNode* inode = &internal_nodes_[internal_node_index];
-
- inode->SetChild(newdirection, external_node_index | kExternalFlag);
- inode->SetCritByte(differing_byte);
- inode->SetOtherBits(new_other_bits);
-
- // |where_index| is a pointer to the uint32_t which needs to be updated in
- // order to insert the new internal node into the tree. The internal nodes
- // store the child indexes in the top 24-bits of a 32-bit word and, to keep
- // the code simple, we define that |internal_node_head_| is organised the
- // same way.
- DCHECK_EQ(internal_node_head_ & 0xff, 0u);
- uint32_t* where_index = &internal_node_head_;
- while (((*where_index >> 8) & kExternalFlag) == 0) {
- InternalNode* node = &internal_nodes_[*where_index >> 8];
- if (node->critbyte() > differing_byte) {
- break;
- }
- if (node->critbyte() == differing_byte &&
- node->otherbits() > new_other_bits) {
- break;
- }
- if (node->critbyte() == differing_byte &&
- node->otherbits() == new_other_bits) {
- CHECK(false);
- }
-
- uint8_t c = value[node->critbyte()];
- const int direction =
- (1 + static_cast<unsigned>(node->otherbits() | c)) >> 8;
- where_index = &node->data_[direction];
- }
-
- inode->SetChild(newdirection ^ 1, *where_index >> 8);
- *where_index = (*where_index & 0xff) | (internal_node_index << 8);
-
- DCHECK_LE(horizon_, nonce_time);
- return NONCE_OK;
-}
-
-const uint8_t* StrikeRegister::orbit() const {
- return orbit_;
-}
-
-uint32_t StrikeRegister::GetCurrentValidWindowSecs(
- uint32_t current_time_external) const {
- uint32_t current_time = ExternalTimeToInternal(current_time_external);
- pair<uint32_t, uint32_t> valid_range =
- StrikeRegister::GetValidRange(current_time);
- if (valid_range.second >= valid_range.first) {
- return valid_range.second - current_time + 1;
- } else {
- return 0;
- }
-}
-
-void StrikeRegister::Validate() {
- set<uint32_t> free_internal_nodes;
- for (uint32_t i = internal_node_free_head_; i != kNil;
- i = internal_nodes_[i].next()) {
- CHECK_LT(i, max_entries_);
- CHECK_EQ(free_internal_nodes.count(i), 0u);
- free_internal_nodes.insert(i);
- }
-
- set<uint32_t> free_external_nodes;
- for (uint32_t i = external_node_free_head_; i != kNil;
- i = external_node_next_ptr(i)) {
- CHECK_LT(i, max_entries_);
- CHECK_EQ(free_external_nodes.count(i), 0u);
- free_external_nodes.insert(i);
- }
-
- set<uint32_t> used_external_nodes;
- set<uint32_t> used_internal_nodes;
-
- if (internal_node_head_ != kNil &&
- ((internal_node_head_ >> 8) & kExternalFlag) == 0) {
- vector<pair<unsigned, bool>> bits;
- ValidateTree(internal_node_head_ >> 8, -1, bits, free_internal_nodes,
- free_external_nodes, &used_internal_nodes,
- &used_external_nodes);
- }
-}
-
-// static
-uint32_t StrikeRegister::TimeFromBytes(const uint8_t d[4]) {
- return static_cast<uint32_t>(d[0]) << 24 | static_cast<uint32_t>(d[1]) << 16 |
- static_cast<uint32_t>(d[2]) << 8 | static_cast<uint32_t>(d[3]);
-}
-
-pair<uint32_t, uint32_t> StrikeRegister::GetValidRange(
- uint32_t current_time_internal) const {
- if (current_time_internal < horizon_) {
- // Empty valid range.
- return std::make_pair(std::numeric_limits<uint32_t>::max(), 0);
- }
-
- uint32_t lower_bound;
- if (current_time_internal >= window_secs_) {
- lower_bound = std::max(horizon_, current_time_internal - window_secs_);
- } else {
- lower_bound = horizon_;
- }
-
- // Also limit the upper range based on horizon_. This makes the
- // strike register reject inserts that are far in the future and
- // would consume strike register resources for a long time. This
- // allows the strike server to degrade optimally in cases where the
- // insert rate exceeds |max_entries_ / (2 * window_secs_)| entries
- // per second.
- uint32_t upper_bound =
- current_time_internal +
- std::min(current_time_internal - horizon_, window_secs_);
-
- return std::make_pair(lower_bound, upper_bound);
-}
-
-uint32_t StrikeRegister::ExternalTimeToInternal(uint32_t external_time) const {
- return external_time - internal_epoch_;
-}
-
-uint32_t StrikeRegister::BestMatch(const uint8_t v[24]) const {
- if (internal_node_head_ == kNil) {
- return kNil;
- }
-
- uint32_t next = internal_node_head_ >> 8;
- while ((next & kExternalFlag) == 0) {
- InternalNode* node = &internal_nodes_[next];
- uint8_t b = v[node->critbyte()];
- unsigned direction =
- (1 + static_cast<unsigned>(node->otherbits() | b)) >> 8;
- next = node->child(direction);
- }
-
- return next & ~kExternalFlag;
-}
-
-uint32_t& StrikeRegister::external_node_next_ptr(unsigned i) {
- return *reinterpret_cast<uint32_t*>(&external_nodes_[i * kExternalNodeSize]);
-}
-
-uint8_t* StrikeRegister::external_node(unsigned i) {
- return &external_nodes_[i * kExternalNodeSize];
-}
-
-uint32_t StrikeRegister::GetFreeExternalNode() {
- uint32_t index = external_node_free_head_;
- DCHECK(index != kNil);
- external_node_free_head_ = external_node_next_ptr(index);
- return index;
-}
-
-uint32_t StrikeRegister::GetFreeInternalNode() {
- uint32_t index = internal_node_free_head_;
- DCHECK(index != kNil);
- internal_node_free_head_ = internal_nodes_[index].next();
- return index;
-}
-
-void StrikeRegister::DropOldestNode() {
- // DropOldestNode should never be called on an empty tree.
- DCHECK(internal_node_head_ != kNil);
-
- // An internal node in a crit-bit tree always has exactly two children.
- // This means that, if we are removing an external node (which is one of
- // those children), then we also need to remove an internal node. In order
- // to do that we keep pointers to the parent (wherep) and grandparent
- // (whereq) when walking down the tree.
-
- uint32_t p = internal_node_head_ >> 8, *wherep = &internal_node_head_,
- *whereq = nullptr;
- while ((p & kExternalFlag) == 0) {
- whereq = wherep;
- InternalNode* inode = &internal_nodes_[p];
- // We always go left, towards the smallest element, exploiting the fact
- // that the timestamp is big-endian and at the start of the value.
- wherep = &inode->data_[0];
- p = (*wherep) >> 8;
- }
-
- const uint32_t ext_index = p & ~kExternalFlag;
- const uint8_t* ext_node = external_node(ext_index);
- uint32_t new_horizon = ExternalTimeToInternal(TimeFromBytes(ext_node)) + 1;
- DCHECK_LE(horizon_, new_horizon);
- horizon_ = new_horizon;
-
- if (!whereq) {
- // We are removing the last element in a tree.
- internal_node_head_ = kNil;
- FreeExternalNode(ext_index);
- return;
- }
-
- // |wherep| points to the left child pointer in the parent so we can add
- // one and dereference to get the right child.
- const uint32_t other_child = wherep[1];
- FreeInternalNode((*whereq) >> 8);
- *whereq = (*whereq & 0xff) | (other_child & 0xffffff00);
- FreeExternalNode(ext_index);
-}
-
-void StrikeRegister::FreeExternalNode(uint32_t index) {
- external_node_next_ptr(index) = external_node_free_head_;
- external_node_free_head_ = index;
-}
-
-void StrikeRegister::FreeInternalNode(uint32_t index) {
- internal_nodes_[index].SetNextPtr(internal_node_free_head_);
- internal_node_free_head_ = index;
-}
-
-void StrikeRegister::ValidateTree(uint32_t internal_node,
- int last_bit,
- const vector<pair<unsigned, bool>>& bits,
- const set<uint32_t>& free_internal_nodes,
- const set<uint32_t>& free_external_nodes,
- set<uint32_t>* used_internal_nodes,
- set<uint32_t>* used_external_nodes) {
- CHECK_LT(internal_node, max_entries_);
- const InternalNode* i = &internal_nodes_[internal_node];
- unsigned bit = 0;
- switch (i->otherbits()) {
- case 0xff & ~(1 << 7):
- bit = 0;
- break;
- case 0xff & ~(1 << 6):
- bit = 1;
- break;
- case 0xff & ~(1 << 5):
- bit = 2;
- break;
- case 0xff & ~(1 << 4):
- bit = 3;
- break;
- case 0xff & ~(1 << 3):
- bit = 4;
- break;
- case 0xff & ~(1 << 2):
- bit = 5;
- break;
- case 0xff & ~(1 << 1):
- bit = 6;
- break;
- case 0xff & ~1:
- bit = 7;
- break;
- default:
- CHECK(false);
- }
-
- bit += 8 * i->critbyte();
- if (last_bit > -1) {
- CHECK_GT(bit, static_cast<unsigned>(last_bit));
- }
-
- CHECK_EQ(free_internal_nodes.count(internal_node), 0u);
-
- for (unsigned child = 0; child < 2; child++) {
- if (i->child(child) & kExternalFlag) {
- uint32_t ext = i->child(child) & ~kExternalFlag;
- CHECK_EQ(free_external_nodes.count(ext), 0u);
- CHECK_EQ(used_external_nodes->count(ext), 0u);
- used_external_nodes->insert(ext);
- const uint8_t* bytes = external_node(ext);
- for (const pair<unsigned, bool>& pair : bits) {
- unsigned byte = pair.first / 8;
- DCHECK_LE(byte, 0xffu);
- unsigned bit_new = pair.first % 8;
- static const uint8_t kMasks[8] = {0x80, 0x40, 0x20, 0x10,
- 0x08, 0x04, 0x02, 0x01};
- CHECK_EQ((bytes[byte] & kMasks[bit_new]) != 0, pair.second);
- }
- } else {
- uint32_t inter = i->child(child);
- vector<pair<unsigned, bool>> new_bits(bits);
- new_bits.push_back(pair<unsigned, bool>(bit, child != 0));
- CHECK_EQ(free_internal_nodes.count(inter), 0u);
- CHECK_EQ(used_internal_nodes->count(inter), 0u);
- used_internal_nodes->insert(inter);
- ValidateTree(inter, bit, bits, free_internal_nodes, free_external_nodes,
- used_internal_nodes, used_external_nodes);
- }
- }
-}
-
-} // namespace net
diff --git a/chromium/net/quic/crypto/strike_register_client.h b/chromium/net/quic/crypto/strike_register_client.h
deleted file mode 100644
index 2bbf5b6d63c..00000000000
--- a/chromium/net/quic/crypto/strike_register_client.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2013 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_CRYPTO_STRIKE_REGISTER_CLIENT_H_
-#define NET_QUIC_CRYPTO_STRIKE_REGISTER_CLIENT_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-#include "net/quic/crypto/strike_register.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-// Interface implemented by clients that talk to strike registers
-// implemented as local or remote services.
-class NET_EXPORT_PRIVATE StrikeRegisterClient {
- public:
- // Single use callback that will be invoked once the validation
- // operation is complete.
- class NET_EXPORT_PRIVATE ResultCallback {
- public:
- ResultCallback() {}
- virtual ~ResultCallback() {}
- void Run(bool nonce_is_valid_and_unique, InsertStatus nonce_error) {
- RunImpl(nonce_is_valid_and_unique, nonce_error);
- delete this;
- }
-
- protected:
- virtual void RunImpl(bool nonce_is_valid_and_unique,
- InsertStatus nonce_error) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ResultCallback);
- };
-
- StrikeRegisterClient() {}
- virtual ~StrikeRegisterClient() {}
-
- // Returns true iff the strike register knows about the given orbit.
- virtual bool IsKnownOrbit(base::StringPiece orbit) const = 0;
- // Validate a nonce for freshness and uniqueness.
- // Will invoke cb->Run(ValidateResponse::nonce_is_valid_and_unique(),
- // ValidateResponse::nonce_error())
- // once the asynchronous operation is complete.
- virtual void VerifyNonceIsValidAndUnique(base::StringPiece nonce,
- QuicWallTime now,
- ResultCallback* cb) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(StrikeRegisterClient);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CRYPTO_STRIKE_REGISTER_CLIENT_H_
diff --git a/chromium/net/quic/crypto/strike_register_test.cc b/chromium/net/quic/crypto/strike_register_test.cc
deleted file mode 100644
index bff26108866..00000000000
--- a/chromium/net/quic/crypto/strike_register_test.cc
+++ /dev/null
@@ -1,407 +0,0 @@
-// Copyright (c) 2013 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/crypto/strike_register.h"
-
-#include <cstdint>
-#include <memory>
-#include <set>
-#include <string>
-
-#include "base/rand_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-namespace {
-
-using std::min;
-using std::pair;
-using std::set;
-using std::string;
-
-const uint8_t kOrbit[8] = {1, 2, 3, 4, 5, 6, 7, 8};
-
-// StrikeRegisterTests don't look at the random bytes so this function can
-// simply set the random bytes to 0.
-void SetNonce(uint8_t nonce[32], unsigned time, const uint8_t orbit[8]) {
- nonce[0] = time >> 24;
- nonce[1] = time >> 16;
- nonce[2] = time >> 8;
- nonce[3] = time;
- memcpy(nonce + 4, orbit, 8);
- memset(nonce + 12, 0, 20);
-}
-
-TEST(StrikeRegisterTest, SimpleHorizon) {
- // The set must reject values created on or before its own creation time.
- StrikeRegister set(10 /* max size */, 1000 /* current time */,
- 100 /* window secs */, kOrbit,
- StrikeRegister::DENY_REQUESTS_AT_STARTUP);
- uint8_t nonce[32];
- SetNonce(nonce, 999, kOrbit);
- EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce, 1000));
- SetNonce(nonce, 1000, kOrbit);
- EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce, 1000));
-
- EXPECT_EQ(0u, set.GetCurrentValidWindowSecs(1000 /* current time */));
- EXPECT_EQ(0u, set.GetCurrentValidWindowSecs(1100 /* current time */));
- EXPECT_EQ(1u, set.GetCurrentValidWindowSecs(1101 /* current time */));
- EXPECT_EQ(50u, set.GetCurrentValidWindowSecs(1150 /* current time */));
- EXPECT_EQ(100u, set.GetCurrentValidWindowSecs(1200 /* current time */));
- EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1300 /* current time */));
-}
-
-TEST(StrikeRegisterTest, NoStartupMode) {
- // Check that a strike register works immediately if NO_STARTUP_PERIOD_NEEDED
- // is specified.
- StrikeRegister set(10 /* max size */, 1000 /* current time */,
- 100 /* window secs */, kOrbit,
- StrikeRegister::NO_STARTUP_PERIOD_NEEDED);
- uint8_t nonce[32];
- SetNonce(nonce, 1000, kOrbit);
- EXPECT_EQ(NONCE_OK, set.Insert(nonce, 1000));
- EXPECT_EQ(NONCE_NOT_UNIQUE_FAILURE, set.Insert(nonce, 1000));
-
- EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1000 /* current time */));
- EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1050 /* current time */));
- EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1100 /* current time */));
- EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1200 /* current time */));
- EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1300 /* current time */));
-}
-
-TEST(StrikeRegisterTest, WindowFuture) {
- // The set must reject values outside the window.
- StrikeRegister set(10 /* max size */, 1000 /* current time */,
- 100 /* window secs */, kOrbit,
- StrikeRegister::DENY_REQUESTS_AT_STARTUP);
- uint8_t nonce[32];
- SetNonce(nonce, 1101, kOrbit);
- EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce, 1000));
- SetNonce(nonce, 999, kOrbit);
- EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce, 1100));
-}
-
-TEST(StrikeRegisterTest, BadOrbit) {
- // The set must reject values with the wrong orbit
- StrikeRegister set(10 /* max size */, 1000 /* current time */,
- 100 /* window secs */, kOrbit,
- StrikeRegister::DENY_REQUESTS_AT_STARTUP);
- uint8_t nonce[32];
- static const uint8_t kBadOrbit[8] = {0, 0, 0, 0, 1, 1, 1, 1};
- SetNonce(nonce, 1101, kBadOrbit);
- EXPECT_EQ(NONCE_INVALID_ORBIT_FAILURE, set.Insert(nonce, 1100));
-}
-
-TEST(StrikeRegisterTest, OneValue) {
- StrikeRegister set(10 /* max size */, 1000 /* current time */,
- 100 /* window secs */, kOrbit,
- StrikeRegister::DENY_REQUESTS_AT_STARTUP);
- uint8_t nonce[32];
- SetNonce(nonce, 1101, kOrbit);
- EXPECT_EQ(NONCE_OK, set.Insert(nonce, 1101));
-}
-
-TEST(StrikeRegisterTest, RejectDuplicate) {
- // The set must reject values with the wrong orbit
- StrikeRegister set(10 /* max size */, 1000 /* current time */,
- 100 /* window secs */, kOrbit,
- StrikeRegister::DENY_REQUESTS_AT_STARTUP);
- uint8_t nonce[32];
- SetNonce(nonce, 1101, kOrbit);
- EXPECT_EQ(NONCE_OK, set.Insert(nonce, 1101));
- EXPECT_EQ(NONCE_NOT_UNIQUE_FAILURE, set.Insert(nonce, 1101));
-}
-
-TEST(StrikeRegisterTest, HorizonUpdating) {
- StrikeRegister::StartupType startup_types[] = {
- StrikeRegister::DENY_REQUESTS_AT_STARTUP,
- StrikeRegister::NO_STARTUP_PERIOD_NEEDED};
-
- for (size_t type_idx = 0; type_idx < arraysize(startup_types); ++type_idx) {
- StrikeRegister set(5 /* max size */, 500 /* current time */,
- 100 /* window secs */, kOrbit, startup_types[type_idx]);
- uint8_t nonce[6][32];
- for (unsigned i = 0; i < 5; i++) {
- SetNonce(nonce[i], 1101 + i, kOrbit);
- nonce[i][31] = i;
- EXPECT_EQ(NONCE_OK, set.Insert(nonce[i], 1100));
- }
-
- // Valid window is still equal to |window_secs + 1|.
- EXPECT_EQ(101u, set.GetCurrentValidWindowSecs(1100));
-
- // This should push the oldest value out and force the horizon to
- // be updated.
- SetNonce(nonce[5], 1110, kOrbit);
- EXPECT_EQ(NONCE_OK, set.Insert(nonce[5], 1110));
- // Effective horizon is computed based on the timestamp of the
- // value that was pushed out.
- EXPECT_EQ(9u, set.GetCurrentValidWindowSecs(1110));
-
- SetNonce(nonce[5], 1111, kOrbit);
- EXPECT_EQ(NONCE_OK, set.Insert(nonce[5], 1110));
- EXPECT_EQ(8u, set.GetCurrentValidWindowSecs(1110));
-
- // This should be behind the horizon now:
- SetNonce(nonce[5], 1101, kOrbit);
- nonce[5][31] = 10;
- EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce[5], 1110));
-
- // Insert beyond the valid range.
- SetNonce(nonce[5], 1117, kOrbit);
- nonce[5][31] = 2;
- EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce[5], 1110));
-
- // Insert at the upper valid range.
- SetNonce(nonce[5], 1116, kOrbit);
- nonce[5][31] = 1;
- EXPECT_EQ(NONCE_OK, set.Insert(nonce[5], 1110));
-
- // This should be beyond the upper valid range now:
- SetNonce(nonce[5], 1116, kOrbit);
- nonce[5][31] = 2;
- EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce[5], 1110));
- }
-}
-
-TEST(StrikeRegisterTest, InsertMany) {
- StrikeRegister set(5000 /* max size */, 1000 /* current time */,
- 500 /* window secs */, kOrbit,
- StrikeRegister::DENY_REQUESTS_AT_STARTUP);
-
- uint8_t nonce[32];
- SetNonce(nonce, 1101, kOrbit);
- for (unsigned i = 0; i < 100000; i++) {
- SetNonce(nonce, 1101 + i / 500, kOrbit);
- memcpy(nonce + 12, &i, sizeof(i));
- EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, set.Insert(nonce, 1100));
- }
-}
-
-// For the following test we create a slow, but simple, version of a
-// StrikeRegister. The behaviour of this object is much easier to understand
-// than the fully fledged version. We then create a test to show, empirically,
-// that the two objects have identical behaviour.
-
-// A SlowStrikeRegister has the same public interface as a StrikeRegister, but
-// is much slower. Hopefully it is also more obviously correct and we can
-// empirically test that their behaviours are identical.
-class SlowStrikeRegister {
- public:
- SlowStrikeRegister(unsigned max_entries,
- uint32_t current_time,
- uint32_t window_secs,
- const uint8_t orbit[8])
- : max_entries_(max_entries),
- window_secs_(window_secs),
- creation_time_(current_time),
- horizon_(ExternalTimeToInternal(current_time + window_secs) + 1) {
- memcpy(orbit_, orbit, sizeof(orbit_));
- }
-
- InsertStatus Insert(const uint8_t nonce_bytes[32],
- const uint32_t nonce_time_external,
- const uint32_t current_time_external) {
- if (nonces_.size() == max_entries_) {
- DropOldestEntry();
- }
-
- const uint32_t current_time = ExternalTimeToInternal(current_time_external);
-
- // Check to see if the orbit is correct.
- if (memcmp(nonce_bytes + 4, orbit_, sizeof(orbit_))) {
- return NONCE_INVALID_ORBIT_FAILURE;
- }
- const uint32_t nonce_time =
- ExternalTimeToInternal(TimeFromBytes(nonce_bytes));
- EXPECT_EQ(ExternalTimeToInternal(nonce_time_external), nonce_time);
- // We have dropped one or more nonces with a time value of |horizon_ - 1|,
- // so we have to reject anything with a timestamp less than or
- // equal to that.
- if (nonce_time < horizon_) {
- return NONCE_INVALID_TIME_FAILURE;
- }
-
- // Check that the timestamp is in the current window.
- if ((current_time > window_secs_ &&
- nonce_time < (current_time - window_secs_)) ||
- nonce_time > (current_time + window_secs_)) {
- return NONCE_INVALID_TIME_FAILURE;
- }
-
- pair<uint32_t, string> nonce = std::make_pair(
- nonce_time, string(reinterpret_cast<const char*>(nonce_bytes), 32));
-
- set<pair<uint32_t, string>>::const_iterator it = nonces_.find(nonce);
- if (it != nonces_.end()) {
- return NONCE_NOT_UNIQUE_FAILURE;
- }
-
- nonces_.insert(nonce);
- return NONCE_OK;
- }
-
- uint32_t GetCurrentValidWindowSecs(
- const uint32_t current_time_external) const {
- const uint32_t current_time = ExternalTimeToInternal(current_time_external);
- if (horizon_ > current_time) {
- return 0;
- }
- return 1 + min(current_time - horizon_, window_secs_);
- }
-
- private:
- // TimeFromBytes returns a big-endian uint32_t from |d|.
- static uint32_t TimeFromBytes(const uint8_t d[4]) {
- return static_cast<uint32_t>(d[0]) << 24 |
- static_cast<uint32_t>(d[1]) << 16 |
- static_cast<uint32_t>(d[2]) << 8 | static_cast<uint32_t>(d[3]);
- }
-
- uint32_t ExternalTimeToInternal(uint32_t external_time) const {
- static const uint32_t kCreationTimeFromInternalEpoch = 63115200.0;
- uint32_t internal_epoch = 0;
- if (creation_time_ > kCreationTimeFromInternalEpoch) {
- internal_epoch = creation_time_ - kCreationTimeFromInternalEpoch;
- }
-
- return external_time - internal_epoch;
- }
-
- void DropOldestEntry() {
- set<pair<uint32_t, string>>::iterator oldest = nonces_.begin();
- horizon_ = oldest->first + 1;
- nonces_.erase(oldest);
- }
-
- const unsigned max_entries_;
- const unsigned window_secs_;
- const uint32_t creation_time_;
- uint8_t orbit_[8];
- uint32_t horizon_;
-
- set<pair<uint32_t, string>> nonces_;
-};
-
-class StrikeRegisterStressTest : public ::testing::Test {};
-
-TEST_F(StrikeRegisterStressTest, InOrderInsertion) {
- // Fixed seed gives reproducibility for this test.
- srand(42);
-
- unsigned max_entries = 64;
- uint32_t current_time = 10000, window = 200;
- std::unique_ptr<StrikeRegister> s1(
- new StrikeRegister(max_entries, current_time, window, kOrbit,
- StrikeRegister::DENY_REQUESTS_AT_STARTUP));
- std::unique_ptr<SlowStrikeRegister> s2(
- new SlowStrikeRegister(max_entries, current_time, window, kOrbit));
-
- uint64_t i;
- const uint64_t kMaxIterations = 10000;
- for (i = 0; i < kMaxIterations; i++) {
- const uint32_t time = current_time + i;
-
- uint8_t nonce[32];
- SetNonce(nonce, time, kOrbit);
-
- // There are 2048 possible nonce values:
- const uint32_t v = rand() % 2048;
- nonce[30] = v >> 8;
- nonce[31] = v;
-
- const InsertStatus nonce_error2 = s2->Insert(nonce, time, time);
- const InsertStatus nonce_error1 = s1->Insert(nonce, time);
- EXPECT_EQ(nonce_error1, nonce_error2);
-
- // Inserts succeed after the startup period.
- if (time > current_time + window) {
- EXPECT_EQ(NONCE_OK, nonce_error1);
- } else {
- EXPECT_EQ(NONCE_INVALID_TIME_FAILURE, nonce_error1);
- }
- EXPECT_EQ(s1->GetCurrentValidWindowSecs(time),
- s2->GetCurrentValidWindowSecs(time));
-
- if (i % 10 == 0) {
- s1->Validate();
- }
-
- if (HasFailure()) {
- break;
- }
- }
-
- if (i != kMaxIterations) {
- FAIL() << "Failed after " << i << " iterations";
- }
-}
-
-TEST_F(StrikeRegisterStressTest, Stress) {
- // Fixed seed gives reproducibility for this test.
- srand(42);
- unsigned max_entries = 64;
- uint32_t current_time = 10000, window = 200;
- std::unique_ptr<StrikeRegister> s1(
- new StrikeRegister(max_entries, current_time, window, kOrbit,
- StrikeRegister::DENY_REQUESTS_AT_STARTUP));
- std::unique_ptr<SlowStrikeRegister> s2(
- new SlowStrikeRegister(max_entries, current_time, window, kOrbit));
- uint64_t i;
-
- // When making changes it's worth removing the limit on this test and running
- // it for a while. For the initial development an opt binary was left running
- // for 10 minutes.
- const uint64_t kMaxIterations = 10000;
- for (i = 0; i < kMaxIterations; i++) {
- if (rand() % 1000 == 0) {
- // 0.1% chance of resetting the sets.
- max_entries = rand() % 300 + 2;
- current_time = rand() % 10000;
- window = rand() % 500;
- s1.reset(new StrikeRegister(max_entries, current_time, window, kOrbit,
- StrikeRegister::DENY_REQUESTS_AT_STARTUP));
- s2.reset(
- new SlowStrikeRegister(max_entries, current_time, window, kOrbit));
- }
-
- int32_t time_delta = rand() % (window * 4);
- time_delta -= window * 2;
- const uint32_t time = current_time + time_delta;
- if (time_delta < 0 && time > current_time) {
- continue; // overflow
- }
-
- uint8_t nonce[32];
- SetNonce(nonce, time, kOrbit);
-
- // There are 2048 possible nonce values:
- const uint32_t v = rand() % 2048;
- nonce[30] = v >> 8;
- nonce[31] = v;
-
- const InsertStatus nonce_error2 = s2->Insert(nonce, time, time);
- const InsertStatus nonce_error1 = s1->Insert(nonce, time);
- EXPECT_EQ(nonce_error1, nonce_error2);
- EXPECT_EQ(s1->GetCurrentValidWindowSecs(time),
- s2->GetCurrentValidWindowSecs(time));
-
- if (i % 10 == 0) {
- s1->Validate();
- }
-
- if (HasFailure()) {
- break;
- }
- }
-
- if (i != kMaxIterations) {
- FAIL() << "Failed after " << i << " iterations";
- }
-}
-
-} // namespace
-
-} // namespace net
diff --git a/chromium/net/quic/interval.h b/chromium/net/quic/interval.h
deleted file mode 100644
index ef4661c760b..00000000000
--- a/chromium/net/quic/interval.h
+++ /dev/null
@@ -1,362 +0,0 @@
-// Copyright 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.
-//
-// An Interval<T> is a data structure used to represent a contiguous, mutable
-// range over an ordered type T. Supported operations include testing a value to
-// see whether it is included in the interval, comparing two intervals, and
-// performing their union, intersection, and difference. For the purposes of
-// this library, an "ordered type" is any type that induces a total order on its
-// values via its less-than operator (operator<()). Examples of such types are
-// basic arithmetic types like int and double as well as class types like
-// string.
-//
-// An Interval<T> is represented using the usual C++ STL convention, namely as
-// the half-open interval [min, max). A point p is considered to be contained in
-// the interval iff p >= min && p < max. One consequence of this definition is
-// that for any non-empty interval, min is contained in the interval but max is
-// not. There is no canonical representation for the empty interval; rather, any
-// interval where max <= min is regarded as empty. As a consequence, two empty
-// intervals will still compare as equal despite possibly having different
-// underlying min() or max() values. Also beware of the terminology used here:
-// the library uses the terms "min" and "max" rather than "begin" and "end" as
-// is conventional for the STL.
-//
-// T is required to be default- and copy-constructable, to have an assignment
-// operator, and the full complement of comparison operators (<, <=, ==, !=, >=,
-// >). A difference operator (operator-()) is required if Interval<T>::Length
-// is used.
-//
-// For equality comparisons, Interval<T> supports an Equals() method and an
-// operator==() which delegates to it. Two intervals are considered equal if
-// either they are both empty or if their corresponding min and max fields
-// compare equal. For ordered comparisons, Interval<T> also provides the
-// comparator Interval<T>::Less and an operator<() which delegates to it.
-// Unfortunately this comparator is currently buggy because its behavior is
-// inconsistent with Equals(): two empty ranges with different representations
-// may be regarded as equivalent by Equals() but regarded as different by
-// the comparator. Bug 9240050 has been created to address this.
-//
-// This class is thread-compatible if T is thread-compatible. (See
-// go/thread-compatible).
-//
-// Examples:
-// Interval<int> r1(0, 100); // The interval [0, 100).
-// EXPECT_TRUE(r1.Contains(0));
-// EXPECT_TRUE(r1.Contains(50));
-// EXPECT_FALSE(r1.Contains(100)); // 100 is just outside the interval.
-//
-// Interval<int> r2(50, 150); // The interval [50, 150).
-// EXPECT_TRUE(r1.Intersects(r2));
-// EXPECT_FALSE(r1.Contains(r2));
-// EXPECT_TRUE(r1.IntersectWith(r2)); // Mutates r1.
-// EXPECT_EQ(Interval<int>(50, 100), r1); // r1 is now [50, 100).
-//
-// Interval<int> r3(1000, 2000); // The interval [1000, 2000).
-// EXPECT_TRUE(r1.IntersectWith(r3)); // Mutates r1.
-// EXPECT_TRUE(r1.Empty()); // Now r1 is empty.
-// EXPECT_FALSE(r1.Contains(r1.min())); // e.g. doesn't contain its own min.
-
-#ifndef NET_QUIC_INTERVAL_H_
-#define NET_QUIC_INTERVAL_H_
-
-#include <stddef.h>
-
-#include <algorithm>
-#include <functional>
-#include <ostream>
-#include <string>
-#include <utility>
-#include <vector>
-
-namespace net {
-
-template <typename T>
-class Interval {
- private:
-// TODO(rtenneti): Implement after suupport for std::decay.
-#if 0
- // Type trait for deriving the return type for Interval::Length. If
- // operator-() is not defined for T, then the return type is void. This makes
- // the signature for Length compile so that the class can be used for such T,
- // but code that calls Length would still generate a compilation error.
- template <typename U>
- class DiffTypeOrVoid {
- private:
- template <typename V>
- static auto f(const V* v) -> decltype(*v - *v);
- template <typename V>
- static void f(...);
-
- public:
- using type = typename std::decay<decltype(f<U>(0))>::type;
- };
-#endif
-
- public:
- // Compatibility alias.
- using Less = std::less<Interval>;
-
- // Construct an Interval representing an empty interval.
- Interval() : min_(), max_() {}
-
- // Construct an Interval representing the interval [min, max). If min < max,
- // the constructed object will represent the non-empty interval containing all
- // values from min up to (but not including) max. On the other hand, if min >=
- // max, the constructed object will represent the empty interval.
- Interval(const T& min, const T& max) : min_(min), max_(max) {}
-
- const T& min() const { return min_; }
- const T& max() const { return max_; }
- void SetMin(const T& t) { min_ = t; }
- void SetMax(const T& t) { max_ = t; }
-
- void Set(const T& min, const T& max) {
- SetMin(min);
- SetMax(max);
- }
-
- void Clear() { *this = {}; }
- void CopyFrom(const Interval& i) { *this = i; }
- bool Equals(const Interval& i) const { return *this == i; }
- bool Empty() const { return min() >= max(); }
-
- // Returns the length of this interval. The value returned is zero if
- // IsEmpty() is true; otherwise the value returned is max() - min().
- const T Length() const { return (min_ >= max_ ? min_ : max_) - min_; }
-
- // Returns true iff t >= min() && t < max().
- bool Contains(const T& t) const { return min() <= t && max() > t; }
-
- // Returns true iff *this and i are non-empty, and *this includes i. "*this
- // includes i" means that for all t, if i.Contains(t) then this->Contains(t).
- // Note the unintuitive consequence of this definition: this method always
- // returns false when i is the empty interval.
- bool Contains(const Interval& i) const {
- return !Empty() && !i.Empty() && min() <= i.min() && max() >= i.max();
- }
-
- // Returns true iff there exists some point t for which this->Contains(t) &&
- // i.Contains(t) evaluates to true, i.e. if the intersection is non-empty.
- bool Intersects(const Interval& i) const {
- return !Empty() && !i.Empty() && min() < i.max() && max() > i.min();
- }
-
- // Returns true iff there exists some point t for which this->Contains(t) &&
- // i.Contains(t) evaluates to true, i.e. if the intersection is non-empty.
- // Furthermore, if the intersection is non-empty and the intersection pointer
- // is not null, this method stores the calculated intersection in
- // *intersection.
- bool Intersects(const Interval& i, Interval* out) const;
-
- // Sets *this to be the intersection of itself with i. Returns true iff
- // *this was modified.
- bool IntersectWith(const Interval& i);
-
- // Calculates the smallest interval containing both *this i, and updates *this
- // to represent that interval, and returns true iff *this was modified.
- bool SpanningUnion(const Interval& i);
-
- // Determines the difference between two intervals by finding all points that
- // are contained in *this but not in i, coalesces those points into the
- // largest possible contiguous intervals, and appends those intervals to the
- // *difference vector. Intuitively this can be thought of as "erasing" i from
- // *this. This will either completely erase *this (leaving nothing behind),
- // partially erase some of *this from the left or right side (leaving some
- // residual behind), or erase a hole in the middle of *this (leaving behind an
- // interval on either side). Therefore, 0, 1, or 2 intervals will be appended
- // to *difference. The method returns true iff the intersection of *this and i
- // is non-empty. The caller owns the vector and the Interval* pointers
- // inside it. The difference vector is required to be non-null.
- bool Difference(const Interval& i, std::vector<Interval*>* difference) const;
-
- // Determines the difference between two intervals as in
- // Difference(Interval&, vector*), but stores the results directly in out
- // parameters rather than dynamically allocating an Interval* and appending
- // it to a vector. If two results are generated, the one with the smaller
- // value of min() will be stored in *lo and the other in *hi. Otherwise (if
- // fewer than two results are generated), unused arguments will be set to the
- // empty interval (it is possible that *lo will be empty and *hi non-empty).
- // The method returns true iff the intersection of *this and i is non-empty.
- bool Difference(const Interval& i, Interval* lo, Interval* hi) const;
-
- friend bool operator==(const Interval& a, const Interval& b) {
- bool ae = a.Empty();
- bool be = b.Empty();
- if (ae && be)
- return true; // All empties are equal.
- if (ae != be)
- return false; // Empty cannot equal nonempty.
- return a.min() == b.min() && a.max() == b.max();
- }
-
- friend bool operator!=(const Interval& a, const Interval& b) {
- return !(a == b);
- }
-
- // Defines a comparator which can be used to induce an order on Intervals, so
- // that, for example, they can be stored in an ordered container such as
- // std::set. The ordering is arbitrary, but does provide the guarantee that,
- // for non-empty intervals X and Y, if X contains Y, then X <= Y.
- // TODO(kosak): The current implementation of this comparator has a problem
- // because the ordering it induces is inconsistent with that of Equals(). In
- // particular, this comparator does not properly consider all empty intervals
- // equivalent. Bug b/9240050 has been created to track this.
- friend bool operator<(const Interval& a, const Interval& b) {
- return a.min() < b.min() || (a.min() == b.min() && a.max() > b.max());
- }
-
- friend std::ostream& operator<<(std::ostream& out, const Interval& i) {
- return out << "[" << i.min() << ", " << i.max() << ")";
- }
-
- private:
- T min_; // Inclusive lower bound.
- T max_; // Exclusive upper bound.
-};
-
-//==============================================================================
-// Implementation details: Clients can stop reading here.
-
-template <typename T>
-bool Interval<T>::Intersects(const Interval& i, Interval* out) const {
- if (!Intersects(i))
- return false;
- if (out != nullptr) {
- *out = Interval(std::max(min(), i.min()), std::min(max(), i.max()));
- }
- return true;
-}
-
-template <typename T>
-bool Interval<T>::IntersectWith(const Interval& i) {
- if (Empty())
- return false;
- bool modified = false;
- if (i.min() > min()) {
- SetMin(i.min());
- modified = true;
- }
- if (i.max() < max()) {
- SetMax(i.max());
- modified = true;
- }
- return modified;
-}
-
-template <typename T>
-bool Interval<T>::SpanningUnion(const Interval& i) {
- if (i.Empty())
- return false;
- if (Empty()) {
- *this = i;
- return true;
- }
- bool modified = false;
- if (i.min() < min()) {
- SetMin(i.min());
- modified = true;
- }
- if (i.max() > max()) {
- SetMax(i.max());
- modified = true;
- }
- return modified;
-}
-
-template <typename T>
-bool Interval<T>::Difference(const Interval& i,
- std::vector<Interval*>* difference) const {
- if (Empty()) {
- // <empty> - <i> = <empty>
- return false;
- }
- if (i.Empty()) {
- // <this> - <empty> = <this>
- difference->push_back(new Interval(*this));
- return false;
- }
- if (min() < i.max() && min() >= i.min() && max() > i.max()) {
- // [------ this ------)
- // [------ i ------)
- // [-- result ---)
- difference->push_back(new Interval(i.max(), max()));
- return true;
- }
- if (max() > i.min() && max() <= i.max() && min() < i.min()) {
- // [------ this ------)
- // [------ i ------)
- // [- result -)
- difference->push_back(new Interval(min(), i.min()));
- return true;
- }
- if (min() < i.min() && max() > i.max()) {
- // [------- this --------)
- // [---- i ----)
- // [ R1 ) [ R2 )
- // There are two results: R1 and R2.
- difference->push_back(new Interval(min(), i.min()));
- difference->push_back(new Interval(i.max(), max()));
- return true;
- }
- if (min() >= i.min() && max() <= i.max()) {
- // [--- this ---)
- // [------ i --------)
- // Intersection is <this>, so difference yields the empty interval.
- // Nothing is appended to *difference.
- return true;
- }
- // No intersection. Append <this>.
- difference->push_back(new Interval(*this));
- return false;
-}
-
-template <typename T>
-bool Interval<T>::Difference(const Interval& i,
- Interval* lo,
- Interval* hi) const {
- // Initialize *lo and *hi to empty
- *lo = {};
- *hi = {};
- if (Empty())
- return false;
- if (i.Empty()) {
- *lo = *this;
- return false;
- }
- if (min() < i.max() && min() >= i.min() && max() > i.max()) {
- // [------ this ------)
- // [------ i ------)
- // [-- result ---)
- *hi = Interval(i.max(), max());
- return true;
- }
- if (max() > i.min() && max() <= i.max() && min() < i.min()) {
- // [------ this ------)
- // [------ i ------)
- // [- result -)
- *lo = Interval(min(), i.min());
- return true;
- }
- if (min() < i.min() && max() > i.max()) {
- // [------- this --------)
- // [---- i ----)
- // [ R1 ) [ R2 )
- // There are two results: R1 and R2.
- *lo = Interval(min(), i.min());
- *hi = Interval(i.max(), max());
- return true;
- }
- if (min() >= i.min() && max() <= i.max()) {
- // [--- this ---)
- // [------ i --------)
- // Intersection is <this>, so difference yields the empty interval.
- return true;
- }
- *lo = *this; // No intersection.
- return false;
-}
-
-} // namespace net
-
-#endif // NET_QUIC_INTERVAL_H_
diff --git a/chromium/net/quic/interval_set.h b/chromium/net/quic/interval_set.h
deleted file mode 100644
index e7e4b6d2f74..00000000000
--- a/chromium/net/quic/interval_set.h
+++ /dev/null
@@ -1,857 +0,0 @@
-// Copyright 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.
-//
-// IntervalSet<T> is a data structure used to represent a sorted set of
-// non-empty, non-adjacent, and mutually disjoint intervals. Mutations to an
-// interval set preserve these properties, altering the set as needed. For
-// example, adding [2, 3) to a set containing only [1, 2) would result in the
-// set containing the single interval [1, 3).
-//
-// Supported operations include testing whether an Interval is contained in the
-// IntervalSet, comparing two IntervalSets, and performing IntervalSet union,
-// intersection, and difference.
-//
-// IntervalSet maintains the minimum number of entries needed to represent the
-// set of underlying intervals. When the IntervalSet is modified (e.g. due to an
-// Add operation), other interval entries may be coalesced, removed, or
-// otherwise modified in order to maintain this invariant. The intervals are
-// maintained in sorted order, by ascending min() value.
-//
-// The reader is cautioned to beware of the terminology used here: this library
-// uses the terms "min" and "max" rather than "begin" and "end" as is
-// conventional for the STL. The terminology [min, max) refers to the half-open
-// interval which (if the interval is not empty) contains min but does not
-// contain max. An interval is considered empty if min >= max.
-//
-// T is required to be default- and copy-constructible, to have an assignment
-// operator, a difference operator (operator-()), and the full complement of
-// comparison operators (<, <=, ==, !=, >=, >). These requirements are inherited
-// from Interval<T>.
-//
-// IntervalSet has constant-time move operations.
-//
-// This class is thread-compatible if T is thread-compatible. (See
-// go/thread-compatible).
-//
-// Examples:
-// IntervalSet<int> intervals;
-// intervals.Add(Interval<int>(10, 20));
-// intervals.Add(Interval<int>(30, 40));
-// // intervals contains [10,20) and [30,40).
-// intervals.Add(Interval<int>(15, 35));
-// // intervals has been coalesced. It now contains the single range [10,40).
-// EXPECT_EQ(1, intervals.Size());
-// EXPECT_TRUE(intervals.Contains(Interval<int>(10, 40)));
-//
-// intervals.Difference(Interval<int>(10, 20));
-// // intervals should now contain the single range [20, 40).
-// EXPECT_EQ(1, intervals.Size());
-// EXPECT_TRUE(intervals.Contains(Interval<int>(20, 40)));
-
-#ifndef NET_QUIC_INTERVAL_SET_H_
-#define NET_QUIC_INTERVAL_SET_H_
-
-#include <stddef.h>
-
-#include <algorithm>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/logging.h"
-#include "net/quic/interval.h"
-
-namespace net {
-
-template <typename T>
-class IntervalSet {
- private:
- struct IntervalComparator {
- bool operator()(const Interval<T>& a, const Interval<T>& b) const;
- };
- typedef std::set<Interval<T>, IntervalComparator> Set;
-
- public:
- typedef typename Set::value_type value_type;
- typedef typename Set::const_iterator const_iterator;
- typedef typename Set::const_reverse_iterator const_reverse_iterator;
-
- // Instantiates an empty IntervalSet.
- IntervalSet() {}
-
- // Instantiates an IntervalSet containing exactly one initial half-open
- // interval [min, max), unless the given interval is empty, in which case the
- // IntervalSet will be empty.
- explicit IntervalSet(const Interval<T>& interval) { Add(interval); }
-
- // Instantiates an IntervalSet containing the half-open interval [min, max).
- IntervalSet(const T& min, const T& max) { Add(min, max); }
-
-// TODO(rtenneti): Implement after suupport for std::initializer_list.
-#if 0
- IntervalSet(std::initializer_list<value_type> il) { assign(il); }
-#endif
-
- // Clears this IntervalSet.
- void Clear() { intervals_.clear(); }
-
- // Returns the number of disjoint intervals contained in this IntervalSet.
- size_t Size() const { return intervals_.size(); }
-
- // Returns the smallest interval that contains all intervals in this
- // IntervalSet, or the empty interval if the set is empty.
- Interval<T> SpanningInterval() const;
-
- // Adds "interval" to this IntervalSet. Adding the empty interval has no
- // effect.
- void Add(const Interval<T>& interval);
-
- // Adds the interval [min, max) to this IntervalSet. Adding the empty interval
- // has no effect.
- void Add(const T& min, const T& max) { Add(Interval<T>(min, max)); }
-
- // DEPRECATED(kosak). Use Union() instead. This method merges all of the
- // values contained in "other" into this IntervalSet.
- void Add(const IntervalSet& other);
-
- // Returns true if this IntervalSet represents exactly the same set of
- // intervals as the ones represented by "other".
- bool Equals(const IntervalSet& other) const;
-
- // Returns true if this IntervalSet is empty.
- bool Empty() const { return intervals_.empty(); }
-
- // Returns true if any interval in this IntervalSet contains the indicated
- // value.
- bool Contains(const T& value) const;
-
- // Returns true if there is some interval in this IntervalSet that wholly
- // contains the given interval. An interval O "wholly contains" a non-empty
- // interval I if O.Contains(p) is true for every p in I. This is the same
- // definition used by Interval<T>::Contains(). This method returns false on
- // the empty interval, due to a (perhaps unintuitive) convention inherited
- // from Interval<T>.
- // Example:
- // Assume an IntervalSet containing the entries { [10,20), [30,40) }.
- // Contains(Interval(15, 16)) returns true, because [10,20) contains
- // [15,16). However, Contains(Interval(15, 35)) returns false.
- bool Contains(const Interval<T>& interval) const;
-
- // Returns true if for each interval in "other", there is some (possibly
- // different) interval in this IntervalSet which wholly contains it. See
- // Contains(const Interval<T>& interval) for the meaning of "wholly contains".
- // Perhaps unintuitively, this method returns false if "other" is the empty
- // set. The algorithmic complexity of this method is O(other.Size() *
- // log(this->Size())), which is not efficient. The method could be rewritten
- // to run in O(other.Size() + this->Size()).
- bool Contains(const IntervalSet<T>& other) const;
-
- // Returns true if there is some interval in this IntervalSet that wholly
- // contains the interval [min, max). See Contains(const Interval<T>&).
- bool Contains(const T& min, const T& max) const {
- return Contains(Interval<T>(min, max));
- }
-
- // Returns true if for some interval in "other", there is some interval in
- // this IntervalSet that intersects with it. See Interval<T>::Intersects()
- // for the definition of interval intersection.
- bool Intersects(const IntervalSet& other) const;
-
- // Returns an iterator to the Interval<T> in the IntervalSet that contains the
- // given value. In other words, returns an iterator to the unique interval
- // [min, max) in the IntervalSet that has the property min <= value < max. If
- // there is no such interval, this method returns end().
- const_iterator Find(const T& value) const;
-
- // Returns an iterator to the Interval<T> in the IntervalSet that wholly
- // contains the given interval. In other words, returns an iterator to the
- // unique interval outer in the IntervalSet that has the property that
- // outer.Contains(interval). If there is no such interval, or if interval is
- // empty, returns end().
- const_iterator Find(const Interval<T>& interval) const;
-
- // Returns an iterator to the Interval<T> in the IntervalSet that wholly
- // contains [min, max). In other words, returns an iterator to the unique
- // interval outer in the IntervalSet that has the property that
- // outer.Contains(Interval<T>(min, max)). If there is no such interval, or if
- // interval is empty, returns end().
- const_iterator Find(const T& min, const T& max) const {
- return Find(Interval<T>(min, max));
- }
-
- // Returns true if every value within the passed interval is not Contained
- // within the IntervalSet.
- bool IsDisjoint(const Interval<T>& interval) const;
-
- // Merges all the values contained in "other" into this IntervalSet.
- void Union(const IntervalSet& other);
-
- // Modifies this IntervalSet so that it contains only those values that are
- // currently present both in *this and in the IntervalSet "other".
- void Intersection(const IntervalSet& other);
-
- // Mutates this IntervalSet so that it contains only those values that are
- // currently in *this but not in "interval".
- void Difference(const Interval<T>& interval);
-
- // Mutates this IntervalSet so that it contains only those values that are
- // currently in *this but not in the interval [min, max).
- void Difference(const T& min, const T& max);
-
- // Mutates this IntervalSet so that it contains only those values that are
- // currently in *this but not in the IntervalSet "other".
- void Difference(const IntervalSet& other);
-
- // Mutates this IntervalSet so that it contains only those values that are
- // in [min, max) but not currently in *this.
- void Complement(const T& min, const T& max);
-
- // IntervalSet's begin() iterator. The invariants of IntervalSet guarantee
- // that for each entry e in the set, e.min() < e.max() (because the entries
- // are non-empty) and for each entry f that appears later in the set,
- // e.max() < f.min() (because the entries are ordered, pairwise-disjoint, and
- // non-adjacent). Modifications to this IntervalSet invalidate these
- // iterators.
- const_iterator begin() const { return intervals_.begin(); }
-
- // IntervalSet's end() iterator.
- const_iterator end() const { return intervals_.end(); }
-
- // IntervalSet's rbegin() and rend() iterators. Iterator invalidation
- // semantics are the same as those for begin() / end().
- const_reverse_iterator rbegin() const { return intervals_.rbegin(); }
-
- const_reverse_iterator rend() const { return intervals_.rend(); }
-
- // Appends the intervals in this IntervalSet to the end of *out.
- void Get(std::vector<Interval<T>>* out) const {
- out->insert(out->end(), begin(), end());
- }
-
- // Copies the intervals in this IntervalSet to the given output iterator.
- template <typename Iter>
- Iter Get(Iter out_iter) const {
- return std::copy(begin(), end(), out_iter);
- }
-
- template <typename Iter>
- void assign(Iter first, Iter last) {
- Clear();
- for (; first != last; ++first)
- Add(*first);
- }
-
-// TODO(rtenneti): Implement after suupport for std::initializer_list.
-#if 0
- void assign(std::initializer_list<value_type> il) {
- assign(il.begin(), il.end());
- }
-#endif
-
- // Returns a human-readable representation of this set. This will typically be
- // (though is not guaranteed to be) of the form
- // "[a1, b1) [a2, b2) ... [an, bn)"
- // where the intervals are in the same order as given by traversal from
- // begin() to end(). This representation is intended for human consumption;
- // computer programs should not rely on the output being in exactly this form.
- std::string ToString() const;
-
- // Equality for IntervalSet<T>. Delegates to Equals().
- bool operator==(const IntervalSet& other) const { return Equals(other); }
-
- // Inequality for IntervalSet<T>. Delegates to Equals() (and returns its
- // negation).
- bool operator!=(const IntervalSet& other) const { return !Equals(other); }
-
-// TODO(rtenneti): Implement after suupport for std::initializer_list.
-#if 0
- IntervalSet& operator=(std::initializer_list<value_type> il) {
- assign(il.begin(), il.end());
- return *this;
- }
-#endif
-
- // Swap this IntervalSet with *other. This is a constant-time operation.
- void Swap(IntervalSet<T>* other) { intervals_.swap(other->intervals_); }
-
- private:
- // Removes overlapping ranges and coalesces adjacent intervals as needed.
- void Compact(const typename Set::iterator& begin,
- const typename Set::iterator& end);
-
- // Returns true if this set is valid (i.e. all intervals in it are non-empty,
- // non-adjacent, and mutually disjoint). Currently this is used as an
- // integrity check by the Intersection() and Difference() methods, but is only
- // invoked for debug builds (via DCHECK).
- bool Valid() const;
-
- // Finds the first interval that potentially intersects 'other'.
- const_iterator FindIntersectionCandidate(const IntervalSet& other) const;
-
- // Finds the first interval that potentially intersects 'interval'.
- const_iterator FindIntersectionCandidate(const Interval<T>& interval) const;
-
- // Helper for Intersection() and Difference(): Finds the next pair of
- // intervals from 'x' and 'y' that intersect. 'mine' is an iterator
- // over x->intervals_. 'theirs' is an iterator over y.intervals_. 'mine'
- // and 'theirs' are advanced until an intersecting pair is found.
- // Non-intersecting intervals (aka "holes") from x->intervals_ can be
- // optionally erased by "on_hole".
- template <typename X, typename Func>
- static bool FindNextIntersectingPairImpl(X* x,
- const IntervalSet& y,
- const_iterator* mine,
- const_iterator* theirs,
- Func on_hole);
-
- // The variant of the above method that doesn't mutate this IntervalSet.
- bool FindNextIntersectingPair(const IntervalSet& other,
- const_iterator* mine,
- const_iterator* theirs) const {
- return FindNextIntersectingPairImpl(
- this, other, mine, theirs,
- [](const IntervalSet*, const_iterator, const_iterator) {});
- }
-
- // The variant of the above method that mutates this IntervalSet by erasing
- // holes.
- bool FindNextIntersectingPairAndEraseHoles(const IntervalSet& other,
- const_iterator* mine,
- const_iterator* theirs) {
- return FindNextIntersectingPairImpl(
- this, other, mine, theirs,
- [](IntervalSet* x, const_iterator from, const_iterator to) {
- x->intervals_.erase(from, to);
- });
- }
-
- // The representation for the intervals. The intervals in this set are
- // non-empty, pairwise-disjoint, non-adjacent and ordered in ascending order
- // by min().
- Set intervals_;
-};
-
-template <typename T>
-std::ostream& operator<<(std::ostream& out, const IntervalSet<T>& seq);
-
-template <typename T>
-void swap(IntervalSet<T>& x, IntervalSet<T>& y);
-
-//==============================================================================
-// Implementation details: Clients can stop reading here.
-
-template <typename T>
-Interval<T> IntervalSet<T>::SpanningInterval() const {
- Interval<T> result;
- if (!intervals_.empty()) {
- result.SetMin(intervals_.begin()->min());
- result.SetMax(intervals_.rbegin()->max());
- }
- return result;
-}
-
-template <typename T>
-void IntervalSet<T>::Add(const Interval<T>& interval) {
- if (interval.Empty())
- return;
- std::pair<typename Set::iterator, bool> ins = intervals_.insert(interval);
- if (!ins.second) {
- // This interval already exists.
- return;
- }
- // Determine the minimal range that will have to be compacted. We know that
- // the IntervalSet was valid before the addition of the interval, so only
- // need to start with the interval itself (although Compact takes an open
- // range so begin needs to be the interval to the left). We don't know how
- // many ranges this interval may cover, so we need to find the appropriate
- // interval to end with on the right.
- typename Set::iterator begin = ins.first;
- if (begin != intervals_.begin())
- --begin;
- const Interval<T> target_end(interval.max(), interval.max());
- const typename Set::iterator end = intervals_.upper_bound(target_end);
- Compact(begin, end);
-}
-
-template <typename T>
-void IntervalSet<T>::Add(const IntervalSet& other) {
- for (const_iterator it = other.begin(); it != other.end(); ++it) {
- Add(*it);
- }
-}
-
-template <typename T>
-bool IntervalSet<T>::Equals(const IntervalSet& other) const {
- if (intervals_.size() != other.intervals_.size())
- return false;
- for (typename Set::iterator i = intervals_.begin(),
- j = other.intervals_.begin();
- i != intervals_.end(); ++i, ++j) {
- // Simple member-wise equality, since all intervals are non-empty.
- if (i->min() != j->min() || i->max() != j->max())
- return false;
- }
- return true;
-}
-
-template <typename T>
-bool IntervalSet<T>::Contains(const T& value) const {
- Interval<T> tmp(value, value);
- // Find the first interval with min() > value, then move back one step
- const_iterator it = intervals_.upper_bound(tmp);
- if (it == intervals_.begin())
- return false;
- --it;
- return it->Contains(value);
-}
-
-template <typename T>
-bool IntervalSet<T>::Contains(const Interval<T>& interval) const {
- // Find the first interval with min() > value, then move back one step.
- const_iterator it = intervals_.upper_bound(interval);
- if (it == intervals_.begin())
- return false;
- --it;
- return it->Contains(interval);
-}
-
-template <typename T>
-bool IntervalSet<T>::Contains(const IntervalSet<T>& other) const {
- if (!SpanningInterval().Contains(other.SpanningInterval())) {
- return false;
- }
-
- for (const_iterator i = other.begin(); i != other.end(); ++i) {
- // If we don't contain the interval, can return false now.
- if (!Contains(*i)) {
- return false;
- }
- }
- return true;
-}
-
-// This method finds the interval that Contains() "value", if such an interval
-// exists in the IntervalSet. The way this is done is to locate the "candidate
-// interval", the only interval that could *possibly* contain value, and test it
-// using Contains(). The candidate interval is the interval with the largest
-// min() having min() <= value.
-//
-// Determining the candidate interval takes a couple of steps. First, since the
-// underlying std::set stores intervals, not values, we need to create a "probe
-// interval" suitable for use as a search key. The probe interval used is
-// [value, value). Now we can restate the problem as finding the largest
-// interval in the IntervalSet that is <= the probe interval.
-//
-// This restatement only works if the set's comparator behaves in a certain way.
-// In particular it needs to order first by ascending min(), and then by
-// descending max(). The comparator used by this library is defined in exactly
-// this way. To see why descending max() is required, consider the following
-// example. Assume an IntervalSet containing these intervals:
-//
-// [0, 5) [10, 20) [50, 60)
-//
-// Consider searching for the value 15. The probe interval [15, 15) is created,
-// and [10, 20) is identified as the largest interval in the set <= the probe
-// interval. This is the correct interval needed for the Contains() test, which
-// will then return true.
-//
-// Now consider searching for the value 30. The probe interval [30, 30) is
-// created, and again [10, 20] is identified as the largest interval <= the
-// probe interval. This is again the correct interval needed for the Contains()
-// test, which in this case returns false.
-//
-// Finally, consider searching for the value 10. The probe interval [10, 10) is
-// created. Here the ordering relationship between [10, 10) and [10, 20) becomes
-// vitally important. If [10, 10) were to come before [10, 20), then [0, 5)
-// would be the largest interval <= the probe, leading to the wrong choice of
-// interval for the Contains() test. Therefore [10, 10) needs to come after
-// [10, 20). The simplest way to make this work in the general case is to order
-// by ascending min() but descending max(). In this ordering, the empty interval
-// is larger than any non-empty interval with the same min(). The comparator
-// used by this library is careful to induce this ordering.
-//
-// Another detail involves the choice of which std::set method to use to try to
-// find the candidate interval. The most appropriate entry point is
-// set::upper_bound(), which finds the smallest interval which is > the probe
-// interval. The semantics of upper_bound() are slightly different from what we
-// want (namely, to find the largest interval which is <= the probe interval)
-// but they are close enough; the interval found by upper_bound() will always be
-// one step past the interval we are looking for (if it exists) or at begin()
-// (if it does not). Getting to the proper interval is a simple matter of
-// decrementing the iterator.
-template <typename T>
-typename IntervalSet<T>::const_iterator IntervalSet<T>::Find(
- const T& value) const {
- Interval<T> tmp(value, value);
- const_iterator it = intervals_.upper_bound(tmp);
- if (it == intervals_.begin())
- return intervals_.end();
- --it;
- if (it->Contains(value))
- return it;
- else
- return intervals_.end();
-}
-
-// This method finds the interval that Contains() the interval "probe", if such
-// an interval exists in the IntervalSet. The way this is done is to locate the
-// "candidate interval", the only interval that could *possibly* contain
-// "probe", and test it using Contains(). The candidate interval is the largest
-// interval that is <= the probe interval.
-//
-// The search for the candidate interval only works if the comparator used
-// behaves in a certain way. In particular it needs to order first by ascending
-// min(), and then by descending max(). The comparator used by this library is
-// defined in exactly this way. To see why descending max() is required,
-// consider the following example. Assume an IntervalSet containing these
-// intervals:
-//
-// [0, 5) [10, 20) [50, 60)
-//
-// Consider searching for the probe [15, 17). [10, 20) is the largest interval
-// in the set which is <= the probe interval. This is the correct interval
-// needed for the Contains() test, which will then return true, because [10, 20)
-// contains [15, 17).
-//
-// Now consider searching for the probe [30, 32). Again [10, 20] is the largest
-// interval <= the probe interval. This is again the correct interval needed for
-// the Contains() test, which in this case returns false, because [10, 20) does
-// not contain [30, 32).
-//
-// Finally, consider searching for the probe [10, 12). Here the ordering
-// relationship between [10, 12) and [10, 20) becomes vitally important. If
-// [10, 12) were to come before [10, 20), then [0, 5) would be the largest
-// interval <= the probe, leading to the wrong choice of interval for the
-// Contains() test. Therefore [10, 12) needs to come after [10, 20). The
-// simplest way to make this work in the general case is to order by ascending
-// min() but descending max(). In this ordering, given two intervals with the
-// same min(), the wider one goes before the narrower one. The comparator used
-// by this library is careful to induce this ordering.
-//
-// Another detail involves the choice of which std::set method to use to try to
-// find the candidate interval. The most appropriate entry point is
-// set::upper_bound(), which finds the smallest interval which is > the probe
-// interval. The semantics of upper_bound() are slightly different from what we
-// want (namely, to find the largest interval which is <= the probe interval)
-// but they are close enough; the interval found by upper_bound() will always be
-// one step past the interval we are looking for (if it exists) or at begin()
-// (if it does not). Getting to the proper interval is a simple matter of
-// decrementing the iterator.
-template <typename T>
-typename IntervalSet<T>::const_iterator IntervalSet<T>::Find(
- const Interval<T>& probe) const {
- const_iterator it = intervals_.upper_bound(probe);
- if (it == intervals_.begin())
- return intervals_.end();
- --it;
- if (it->Contains(probe))
- return it;
- else
- return intervals_.end();
-}
-
-template <typename T>
-bool IntervalSet<T>::IsDisjoint(const Interval<T>& interval) const {
- Interval<T> tmp(interval.min(), interval.min());
- // Find the first interval with min() > interval.min()
- const_iterator it = intervals_.upper_bound(tmp);
- if (it != intervals_.end() && interval.max() > it->min())
- return false;
- if (it == intervals_.begin())
- return true;
- --it;
- return it->max() <= interval.min();
-}
-
-template <typename T>
-void IntervalSet<T>::Union(const IntervalSet& other) {
- intervals_.insert(other.begin(), other.end());
- Compact(intervals_.begin(), intervals_.end());
-}
-
-template <typename T>
-typename IntervalSet<T>::const_iterator
-IntervalSet<T>::FindIntersectionCandidate(const IntervalSet& other) const {
- return FindIntersectionCandidate(*other.intervals_.begin());
-}
-
-template <typename T>
-typename IntervalSet<T>::const_iterator
-IntervalSet<T>::FindIntersectionCandidate(const Interval<T>& interval) const {
- // Use upper_bound to efficiently find the first interval in intervals_
- // where min() is greater than interval.min(). If the result
- // isn't the beginning of intervals_ then move backwards one interval since
- // the interval before it is the first candidate where max() may be
- // greater than interval.min().
- // In other words, no interval before that can possibly intersect with any
- // of other.intervals_.
- const_iterator mine = intervals_.upper_bound(interval);
- if (mine != intervals_.begin()) {
- --mine;
- }
- return mine;
-}
-
-template <typename T>
-template <typename X, typename Func>
-bool IntervalSet<T>::FindNextIntersectingPairImpl(X* x,
- const IntervalSet& y,
- const_iterator* mine,
- const_iterator* theirs,
- Func on_hole) {
- CHECK(x != nullptr);
- if ((*mine == x->intervals_.end()) || (*theirs == y.intervals_.end())) {
- return false;
- }
- while (!(**mine).Intersects(**theirs)) {
- const_iterator erase_first = *mine;
- // Skip over intervals in 'mine' that don't reach 'theirs'.
- while (*mine != x->intervals_.end() && (**mine).max() <= (**theirs).min()) {
- ++(*mine);
- }
- on_hole(x, erase_first, *mine);
- // We're done if the end of intervals_ is reached.
- if (*mine == x->intervals_.end()) {
- return false;
- }
- // Skip over intervals 'theirs' that don't reach 'mine'.
- while (*theirs != y.intervals_.end() &&
- (**theirs).max() <= (**mine).min()) {
- ++(*theirs);
- }
- // If the end of other.intervals_ is reached, we're done.
- if (*theirs == y.intervals_.end()) {
- on_hole(x, *mine, x->intervals_.end());
- return false;
- }
- }
- return true;
-}
-
-template <typename T>
-void IntervalSet<T>::Intersection(const IntervalSet& other) {
- if (!SpanningInterval().Intersects(other.SpanningInterval())) {
- intervals_.clear();
- return;
- }
-
- const_iterator mine = FindIntersectionCandidate(other);
- // Remove any intervals that cannot possibly intersect with other.intervals_.
- intervals_.erase(intervals_.begin(), mine);
- const_iterator theirs = other.FindIntersectionCandidate(*this);
-
- while (FindNextIntersectingPairAndEraseHoles(other, &mine, &theirs)) {
- // OK, *mine and *theirs intersect. Now, we find the largest
- // span of intervals in other (starting at theirs) - say [a..b]
- // - that intersect *mine, and we replace *mine with (*mine
- // intersect x) for all x in [a..b] Note that subsequent
- // intervals in this can't intersect any intervals in [a..b) --
- // they may only intersect b or subsequent intervals in other.
- Interval<T> i(*mine);
- intervals_.erase(mine);
- mine = intervals_.end();
- Interval<T> intersection;
- while (theirs != other.intervals_.end() &&
- i.Intersects(*theirs, &intersection)) {
- std::pair<typename Set::iterator, bool> ins =
- intervals_.insert(intersection);
- DCHECK(ins.second);
- mine = ins.first;
- ++theirs;
- }
- DCHECK(mine != intervals_.end());
- --theirs;
- ++mine;
- }
- DCHECK(Valid());
-}
-
-template <typename T>
-bool IntervalSet<T>::Intersects(const IntervalSet& other) const {
- if (!SpanningInterval().Intersects(other.SpanningInterval())) {
- return false;
- }
-
- const_iterator mine = FindIntersectionCandidate(other);
- if (mine == intervals_.end()) {
- return false;
- }
- const_iterator theirs = other.FindIntersectionCandidate(*mine);
-
- return FindNextIntersectingPair(other, &mine, &theirs);
-}
-
-template <typename T>
-void IntervalSet<T>::Difference(const Interval<T>& interval) {
- if (!SpanningInterval().Intersects(interval)) {
- return;
- }
- Difference(IntervalSet<T>(interval));
-}
-
-template <typename T>
-void IntervalSet<T>::Difference(const T& min, const T& max) {
- Difference(Interval<T>(min, max));
-}
-
-template <typename T>
-void IntervalSet<T>::Difference(const IntervalSet& other) {
- if (!SpanningInterval().Intersects(other.SpanningInterval())) {
- return;
- }
-
- const_iterator mine = FindIntersectionCandidate(other);
- // If no interval in mine reaches the first interval of theirs then we're
- // done.
- if (mine == intervals_.end()) {
- return;
- }
- const_iterator theirs = other.FindIntersectionCandidate(*this);
-
- while (FindNextIntersectingPair(other, &mine, &theirs)) {
- // At this point *mine and *theirs overlap. Remove mine from
- // intervals_ and replace it with the possibly two intervals that are
- // the difference between mine and theirs.
- Interval<T> i(*mine);
- intervals_.erase(mine++);
- Interval<T> lo;
- Interval<T> hi;
- i.Difference(*theirs, &lo, &hi);
-
- if (!lo.Empty()) {
- // We have a low end. This can't intersect anything else.
- std::pair<typename Set::iterator, bool> ins = intervals_.insert(lo);
- DCHECK(ins.second);
- }
-
- if (!hi.Empty()) {
- std::pair<typename Set::iterator, bool> ins = intervals_.insert(hi);
- DCHECK(ins.second);
- mine = ins.first;
- }
- }
- DCHECK(Valid());
-}
-
-template <typename T>
-void IntervalSet<T>::Complement(const T& min, const T& max) {
- IntervalSet<T> span(min, max);
- span.Difference(*this);
- intervals_.swap(span.intervals_);
-}
-
-template <typename T>
-std::string IntervalSet<T>::ToString() const {
- std::ostringstream os;
- os << *this;
- return os.str();
-}
-
-// This method compacts the IntervalSet, merging pairs of overlapping intervals
-// into a single interval. In the steady state, the IntervalSet does not contain
-// any such pairs. However, the way the Union() and Add() methods work is to
-// temporarily put the IntervalSet into such a state and then to call Compact()
-// to "fix it up" so that it is no longer in that state.
-//
-// Compact() needs the interval set to allow two intervals [a,b) and [a,c)
-// (having the same min() but different max()) to briefly coexist in the set at
-// the same time, and be adjacent to each other, so that they can be efficiently
-// located and merged into a single interval. This state would be impossible
-// with a comparator which only looked at min(), as such a comparator would
-// consider such pairs equal. Fortunately, the comparator used by IntervalSet
-// does exactly what is needed, ordering first by ascending min(), then by
-// descending max().
-template <typename T>
-void IntervalSet<T>::Compact(const typename Set::iterator& begin,
- const typename Set::iterator& end) {
- if (begin == end)
- return;
- typename Set::iterator next = begin;
- typename Set::iterator prev = begin;
- typename Set::iterator it = begin;
- ++it;
- ++next;
- while (it != end) {
- ++next;
- if (prev->max() >= it->min()) {
- // Overlapping / coalesced range; merge the two intervals.
- T min = prev->min();
- T max = std::max(prev->max(), it->max());
- Interval<T> i(min, max);
- intervals_.erase(prev);
- intervals_.erase(it);
- std::pair<typename Set::iterator, bool> ins = intervals_.insert(i);
- DCHECK(ins.second);
- prev = ins.first;
- } else {
- prev = it;
- }
- it = next;
- }
-}
-
-template <typename T>
-bool IntervalSet<T>::Valid() const {
- const_iterator prev = end();
- for (const_iterator it = begin(); it != end(); ++it) {
- // invalid or empty interval.
- if (it->min() >= it->max())
- return false;
- // Not sorted, not disjoint, or adjacent.
- if (prev != end() && prev->max() >= it->min())
- return false;
- prev = it;
- }
- return true;
-}
-
-template <typename T>
-inline std::ostream& operator<<(std::ostream& out, const IntervalSet<T>& seq) {
-// TODO(rtenneti): Implement << method of IntervalSet.
-#if 0
- util::gtl::LogRangeToStream(out, seq.begin(), seq.end(),
- util::gtl::LogLegacy());
-#endif // 0
- return out;
-}
-
-template <typename T>
-void swap(IntervalSet<T>& x, IntervalSet<T>& y) {
- x.Swap(&y);
-}
-
-// This comparator orders intervals first by ascending min() and then by
-// descending max(). Readers who are satisified with that explanation can stop
-// reading here. The remainder of this comment is for the benefit of future
-// maintainers of this library.
-//
-// The reason for this ordering is that this comparator has to serve two
-// masters. First, it has to maintain the intervals in its internal set in the
-// order that clients expect to see them. Clients see these intervals via the
-// iterators provided by begin()/end() or as a result of invoking Get(). For
-// this reason, the comparator orders intervals by ascending min().
-//
-// If client iteration were the only consideration, then ordering by ascending
-// min() would be good enough. This is because the intervals in the IntervalSet
-// are non-empty, non-adjacent, and mutually disjoint; such intervals happen to
-// always have disjoint min() values, so such a comparator would never even have
-// to look at max() in order to work correctly for this class.
-//
-// However, in addition to ordering by ascending min(), this comparator also has
-// a second responsibility: satisfying the special needs of this library's
-// peculiar internal implementation. These needs require the comparator to order
-// first by ascending min() and then by descending max(). The best way to
-// understand why this is so is to check out the comments associated with the
-// Find() and Compact() methods.
-template <typename T>
-inline bool IntervalSet<T>::IntervalComparator::operator()(
- const Interval<T>& a,
- const Interval<T>& b) const {
- return (a.min() < b.min() || (a.min() == b.min() && a.max() > b.max()));
-}
-
-} // namespace net
-
-#endif // NET_QUIC_INTERVAL_SET_H_
diff --git a/chromium/net/quic/interval_set_test.cc b/chromium/net/quic/interval_set_test.cc
deleted file mode 100644
index e8ccb2c0863..00000000000
--- a/chromium/net/quic/interval_set_test.cc
+++ /dev/null
@@ -1,981 +0,0 @@
-// Copyright 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.
-
-#include "net/quic/interval_set.h"
-
-#include <stdarg.h>
-
-#include <iostream>
-#include <iterator>
-#include <limits>
-
-#include "net/test/gtest_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::pair;
-using std::string;
-using std::vector;
-
-namespace net {
-namespace test {
-namespace {
-
-using ::testing::ElementsAreArray;
-
-class IntervalSetTest : public ::testing::Test {
- protected:
- void SetUp() override {
- // Initialize two IntervalSets for union, intersection, and difference
- // tests
- is.Add(100, 200);
- is.Add(300, 400);
- is.Add(500, 600);
- is.Add(700, 800);
- is.Add(900, 1000);
- is.Add(1100, 1200);
- is.Add(1300, 1400);
- is.Add(1500, 1600);
- is.Add(1700, 1800);
- is.Add(1900, 2000);
- is.Add(2100, 2200);
-
- // Lots of different cases:
- other.Add(50, 70); // disjoint, at the beginning
- other.Add(2250, 2270); // disjoint, at the end
- other.Add(650, 670); // disjoint, in the middle
- other.Add(350, 360); // included
- other.Add(370, 380); // also included (two at once)
- other.Add(470, 530); // overlaps low end
- other.Add(770, 830); // overlaps high end
- other.Add(870, 900); // meets at low end
- other.Add(1200, 1230); // meets at high end
- other.Add(1270, 1830); // overlaps multiple ranges
- }
-
- void TearDown() override {
- is.Clear();
- EXPECT_TRUE(is.Empty());
- other.Clear();
- EXPECT_TRUE(other.Empty());
- }
- IntervalSet<int> is;
- IntervalSet<int> other;
-};
-
-TEST_F(IntervalSetTest, IsDisjoint) {
- EXPECT_TRUE(is.IsDisjoint(Interval<int>(0, 99)));
- EXPECT_TRUE(is.IsDisjoint(Interval<int>(0, 100)));
- EXPECT_TRUE(is.IsDisjoint(Interval<int>(200, 200)));
- EXPECT_TRUE(is.IsDisjoint(Interval<int>(200, 299)));
- EXPECT_TRUE(is.IsDisjoint(Interval<int>(400, 407)));
- EXPECT_TRUE(is.IsDisjoint(Interval<int>(405, 499)));
- EXPECT_TRUE(is.IsDisjoint(Interval<int>(2300, 2300)));
- EXPECT_TRUE(
- is.IsDisjoint(Interval<int>(2300, std::numeric_limits<int>::max())));
- EXPECT_FALSE(is.IsDisjoint(Interval<int>(100, 100)));
- EXPECT_FALSE(is.IsDisjoint(Interval<int>(100, 105)));
- EXPECT_FALSE(is.IsDisjoint(Interval<int>(199, 300)));
- EXPECT_FALSE(is.IsDisjoint(Interval<int>(250, 450)));
- EXPECT_FALSE(is.IsDisjoint(Interval<int>(299, 400)));
- EXPECT_FALSE(is.IsDisjoint(Interval<int>(250, 2000)));
- EXPECT_FALSE(
- is.IsDisjoint(Interval<int>(2199, std::numeric_limits<int>::max())));
-}
-
-// Base helper method for verifying the contents of an interval set.
-// Returns true iff <is> contains <count> intervals whose successive
-// endpoints match the sequence of args in <ap>:
-static bool VA_Check(const IntervalSet<int>& is, size_t count, va_list ap) {
- vector<Interval<int>> intervals;
- is.Get(&intervals);
- if (count != intervals.size()) {
- LOG(ERROR) << "Expected " << count << " intervals, got " << intervals.size()
- << ": " << is.ToString();
- return false;
- }
- if (count != is.Size()) {
- LOG(ERROR) << "Expected " << count << " intervals, got Size " << is.Size()
- << ": " << is.ToString();
- return false;
- }
- bool result = true;
- for (size_t i = 0; i < count; i++) {
- int min = va_arg(ap, int);
- int max = va_arg(ap, int);
- if (min != intervals[i].min() || max != intervals[i].max()) {
- LOG(ERROR) << "Expected: [" << min << ", " << max << ") got "
- << intervals[i] << " in " << is.ToString();
- result = false;
- }
- }
- return result;
-}
-
-static bool Check(const IntervalSet<int>& is, int count, ...) {
- va_list ap;
- va_start(ap, count);
- const bool result = VA_Check(is, count, ap);
- va_end(ap);
- return result;
-}
-
-// Some helper functions for testing Contains and Find, which are logically the
-// same.
-static void TestContainsAndFind(const IntervalSet<int>& is, int value) {
- EXPECT_TRUE(is.Contains(value)) << "Set does not contain " << value;
- auto it = is.Find(value);
- EXPECT_NE(it, is.end()) << "No iterator to interval containing " << value;
- EXPECT_TRUE(it->Contains(value)) << "Iterator does not contain " << value;
-}
-
-static void TestContainsAndFind(const IntervalSet<int>& is, int min, int max) {
- EXPECT_TRUE(is.Contains(min, max))
- << "Set does not contain interval with min " << min << "and max " << max;
- auto it = is.Find(min, max);
- EXPECT_NE(it, is.end()) << "No iterator to interval with min " << min
- << "and max " << max;
- EXPECT_TRUE(it->Contains(Interval<int>(min, max)))
- << "Iterator does not contain interval with min " << min << "and max "
- << max;
-}
-
-static void TestNotContainsAndFind(const IntervalSet<int>& is, int value) {
- EXPECT_FALSE(is.Contains(value)) << "Set contains " << value;
- auto it = is.Find(value);
- EXPECT_EQ(it, is.end()) << "There is iterator to interval containing "
- << value;
-}
-
-static void TestNotContainsAndFind(const IntervalSet<int>& is,
- int min,
- int max) {
- EXPECT_FALSE(is.Contains(min, max)) << "Set contains interval with min "
- << min << "and max " << max;
- auto it = is.Find(min, max);
- EXPECT_EQ(it, is.end()) << "There is iterator to interval with min " << min
- << "and max " << max;
-}
-
-TEST_F(IntervalSetTest, IntervalSetBasic) {
- // Test Add, Get, Contains and Find
- IntervalSet<int> iset;
- EXPECT_TRUE(iset.Empty());
- EXPECT_EQ(0u, iset.Size());
- iset.Add(100, 200);
- EXPECT_FALSE(iset.Empty());
- EXPECT_EQ(1u, iset.Size());
- iset.Add(100, 150);
- iset.Add(150, 200);
- iset.Add(130, 170);
- iset.Add(90, 150);
- iset.Add(170, 220);
- iset.Add(300, 400);
- iset.Add(250, 450);
- EXPECT_FALSE(iset.Empty());
- EXPECT_EQ(2u, iset.Size());
- EXPECT_TRUE(Check(iset, 2, 90, 220, 250, 450));
-
- // Test two intervals with a.max == b.min, that will just join up.
- iset.Clear();
- iset.Add(100, 200);
- iset.Add(200, 300);
- EXPECT_FALSE(iset.Empty());
- EXPECT_EQ(1u, iset.Size());
- EXPECT_TRUE(Check(iset, 1, 100, 300));
-
- // Test adding two sets together.
- iset.Clear();
- IntervalSet<int> iset_add;
- iset.Add(100, 200);
- iset.Add(100, 150);
- iset.Add(150, 200);
- iset.Add(130, 170);
- iset_add.Add(90, 150);
- iset_add.Add(170, 220);
- iset_add.Add(300, 400);
- iset_add.Add(250, 450);
-
- iset.Add(iset_add);
- EXPECT_FALSE(iset.Empty());
- EXPECT_EQ(2u, iset.Size());
- EXPECT_TRUE(Check(iset, 2, 90, 220, 250, 450));
-
- // Test Get() (using an output iterator), begin()/end(), and rbegin()/rend()
- // to iterate over intervals.
- {
- vector<Interval<int>> expected;
- iset.Get(&expected);
-
- vector<Interval<int>> actual1;
- iset.Get(back_inserter(actual1));
- ASSERT_EQ(expected.size(), actual1.size());
-
- vector<Interval<int>> actual2;
- std::copy(iset.begin(), iset.end(), back_inserter(actual2));
- ASSERT_EQ(expected.size(), actual2.size());
-
- for (size_t i = 0; i < expected.size(); i++) {
- EXPECT_EQ(expected[i].min(), actual1[i].min());
- EXPECT_EQ(expected[i].max(), actual1[i].max());
-
- EXPECT_EQ(expected[i].min(), actual2[i].min());
- EXPECT_EQ(expected[i].max(), actual2[i].max());
- }
-
- // Ensure that the rbegin()/rend() iterators correctly yield the intervals
- // in reverse order.
- EXPECT_THAT(vector<Interval<int>>(iset.rbegin(), iset.rend()),
- ElementsAreArray(expected.rbegin(), expected.rend()));
- }
-
- TestNotContainsAndFind(iset, 89);
- TestContainsAndFind(iset, 90);
- TestContainsAndFind(iset, 120);
- TestContainsAndFind(iset, 219);
- TestNotContainsAndFind(iset, 220);
- TestNotContainsAndFind(iset, 235);
- TestNotContainsAndFind(iset, 249);
- TestContainsAndFind(iset, 250);
- TestContainsAndFind(iset, 300);
- TestContainsAndFind(iset, 449);
- TestNotContainsAndFind(iset, 450);
- TestNotContainsAndFind(iset, 451);
-
- TestNotContainsAndFind(iset, 50, 60);
- TestNotContainsAndFind(iset, 50, 90);
- TestNotContainsAndFind(iset, 50, 200);
- TestNotContainsAndFind(iset, 90, 90);
- TestContainsAndFind(iset, 90, 200);
- TestContainsAndFind(iset, 100, 200);
- TestContainsAndFind(iset, 100, 220);
- TestNotContainsAndFind(iset, 100, 221);
- TestNotContainsAndFind(iset, 220, 220);
- TestNotContainsAndFind(iset, 240, 300);
- TestContainsAndFind(iset, 250, 300);
- TestContainsAndFind(iset, 260, 300);
- TestContainsAndFind(iset, 300, 450);
- TestNotContainsAndFind(iset, 300, 451);
-
- IntervalSet<int> iset_contains;
- iset_contains.Add(50, 90);
- EXPECT_FALSE(iset.Contains(iset_contains));
- iset_contains.Clear();
-
- iset_contains.Add(90, 200);
- EXPECT_TRUE(iset.Contains(iset_contains));
- iset_contains.Add(100, 200);
- EXPECT_TRUE(iset.Contains(iset_contains));
- iset_contains.Add(100, 220);
- EXPECT_TRUE(iset.Contains(iset_contains));
- iset_contains.Add(250, 300);
- EXPECT_TRUE(iset.Contains(iset_contains));
- iset_contains.Add(300, 450);
- EXPECT_TRUE(iset.Contains(iset_contains));
- iset_contains.Add(300, 451);
- EXPECT_FALSE(iset.Contains(iset_contains));
- EXPECT_FALSE(iset.Contains(Interval<int>()));
- EXPECT_FALSE(iset.Contains(IntervalSet<int>()));
-}
-
-TEST_F(IntervalSetTest, IntervalSetContainsEmpty) {
- const IntervalSet<int> empty;
- const IntervalSet<int> other_empty;
- EXPECT_FALSE(empty.Contains(empty));
- EXPECT_FALSE(empty.Contains(other_empty));
-// TODO(rtenneti): Implement after suupport for std::initializer_list.
-#if 0
- const IntervalSet<int> non_empty({{10, 20}, {40, 50}});
- EXPECT_FALSE(empty.Contains(non_empty));
- EXPECT_FALSE(non_empty.Contains(empty));
-#endif
-}
-
-TEST_F(IntervalSetTest, Equality) {
- IntervalSet<int> is_copy = is;
- EXPECT_TRUE(is.Equals(is));
- EXPECT_EQ(is, is);
- EXPECT_TRUE(is.Equals(is_copy));
- EXPECT_EQ(is, is_copy);
- EXPECT_FALSE(is.Equals(other));
- EXPECT_NE(is, other);
- EXPECT_FALSE(is.Equals(IntervalSet<int>()));
- EXPECT_NE(is, IntervalSet<int>());
- EXPECT_TRUE(IntervalSet<int>().Equals(IntervalSet<int>()));
- EXPECT_EQ(IntervalSet<int>(), IntervalSet<int>());
-}
-
-TEST_F(IntervalSetTest, SpanningInterval) {
- // Spanning interval of an empty set is empty:
- {
- IntervalSet<int> iset;
- const Interval<int>& ival = iset.SpanningInterval();
- EXPECT_TRUE(ival.Empty());
- }
-
- // Spanning interval of a set with one interval is that interval:
- {
- IntervalSet<int> iset;
- iset.Add(100, 200);
- const Interval<int>& ival = iset.SpanningInterval();
- EXPECT_EQ(100, ival.min());
- EXPECT_EQ(200, ival.max());
- }
-
- // Spanning interval of a set with multiple elements is determined
- // by the endpoints of the first and last element:
- {
- const Interval<int>& ival = is.SpanningInterval();
- EXPECT_EQ(100, ival.min());
- EXPECT_EQ(2200, ival.max());
- }
- {
- const Interval<int>& ival = other.SpanningInterval();
- EXPECT_EQ(50, ival.min());
- EXPECT_EQ(2270, ival.max());
- }
-}
-
-TEST_F(IntervalSetTest, IntervalSetUnion) {
- is.Union(other);
- EXPECT_TRUE(Check(is, 12, 50, 70, 100, 200, 300, 400, 470, 600, 650, 670, 700,
- 830, 870, 1000, 1100, 1230, 1270, 1830, 1900, 2000, 2100,
- 2200, 2250, 2270));
-}
-
-TEST_F(IntervalSetTest, IntervalSetIntersection) {
- EXPECT_TRUE(is.Intersects(other));
- EXPECT_TRUE(other.Intersects(is));
- is.Intersection(other);
- EXPECT_TRUE(Check(is, 7, 350, 360, 370, 380, 500, 530, 770, 800, 1300, 1400,
- 1500, 1600, 1700, 1800));
- EXPECT_TRUE(is.Intersects(other));
- EXPECT_TRUE(other.Intersects(is));
-}
-
-TEST_F(IntervalSetTest, IntervalSetIntersectionBothEmpty) {
- IntervalSet<string> mine, theirs;
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
- mine.Intersection(theirs);
- EXPECT_TRUE(mine.Empty());
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
-}
-
-TEST_F(IntervalSetTest, IntervalSetIntersectionEmptyMine) {
- IntervalSet<string> mine;
- IntervalSet<string> theirs("a", "b");
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
- mine.Intersection(theirs);
- EXPECT_TRUE(mine.Empty());
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
-}
-
-TEST_F(IntervalSetTest, IntervalSetIntersectionEmptyTheirs) {
- IntervalSet<string> mine("a", "b");
- IntervalSet<string> theirs;
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
- mine.Intersection(theirs);
- EXPECT_TRUE(mine.Empty());
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
-}
-
-TEST_F(IntervalSetTest, IntervalSetIntersectionTheirsBeforeMine) {
- IntervalSet<string> mine("y", "z");
- IntervalSet<string> theirs;
- theirs.Add("a", "b");
- theirs.Add("c", "d");
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
- mine.Intersection(theirs);
- EXPECT_TRUE(mine.Empty());
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
-}
-
-TEST_F(IntervalSetTest, IntervalSetIntersectionMineBeforeTheirs) {
- IntervalSet<string> mine;
- mine.Add("a", "b");
- mine.Add("c", "d");
- IntervalSet<string> theirs("y", "z");
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
- mine.Intersection(theirs);
- EXPECT_TRUE(mine.Empty());
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
-}
-
-// TODO(rtenneti): Implement after suupport for std::initializer_list.
-#if 0
-TEST_F(IntervalSetTest,
- IntervalSetIntersectionTheirsBeforeMineInt64Singletons) {
- IntervalSet<int64_t> mine({{10, 15}});
- IntervalSet<int64_t> theirs({{-20, -5}});
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
- mine.Intersection(theirs);
- EXPECT_TRUE(mine.Empty());
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
-}
-
-TEST_F(IntervalSetTest, IntervalSetIntersectionMineBeforeTheirsIntSingletons) {
- IntervalSet<int> mine({{10, 15}});
- IntervalSet<int> theirs({{90, 95}});
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
- mine.Intersection(theirs);
- EXPECT_TRUE(mine.Empty());
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
-}
-
-TEST_F(IntervalSetTest, IntervalSetIntersectionTheirsBetweenMine) {
- IntervalSet<int64_t> mine({{0, 5}, {40, 50}});
- IntervalSet<int64_t> theirs({{10, 15}});
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
- mine.Intersection(theirs);
- EXPECT_TRUE(mine.Empty());
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
-}
-
-TEST_F(IntervalSetTest, IntervalSetIntersectionMineBetweenTheirs) {
- IntervalSet<int> mine({{20, 25}});
- IntervalSet<int> theirs({{10, 15}, {30, 32}});
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
- mine.Intersection(theirs);
- EXPECT_TRUE(mine.Empty());
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
-}
-#endif // 0
-
-TEST_F(IntervalSetTest, IntervalSetIntersectionAlternatingIntervals) {
- IntervalSet<int> mine, theirs;
- mine.Add(10, 20);
- mine.Add(40, 50);
- mine.Add(60, 70);
- theirs.Add(25, 39);
- theirs.Add(55, 59);
- theirs.Add(75, 79);
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
- mine.Intersection(theirs);
- EXPECT_TRUE(mine.Empty());
- EXPECT_FALSE(mine.Intersects(theirs));
- EXPECT_FALSE(theirs.Intersects(mine));
-}
-
-// TODO(rtenneti): Implement after suupport for std::initializer_list.
-#if 0
-TEST_F(IntervalSetTest,
- IntervalSetIntersectionAdjacentAlternatingNonIntersectingIntervals) {
- // Make sure that intersection with adjacent interval set is empty.
- const IntervalSet<int> x1({{0, 10}});
- const IntervalSet<int> y1({{-50, 0}, {10, 95}});
-
- IntervalSet<int> result1 = x1;
- result1.Intersection(y1);
- EXPECT_TRUE(result1.Empty()) << result1;
-
- const IntervalSet<int16_t> x2({{0, 10}, {20, 30}, {40, 90}});
- const IntervalSet<int16_t> y2(
- {{-50, -40}, {-2, 0}, {10, 20}, {32, 40}, {90, 95}});
-
- IntervalSet<int16_t> result2 = x2;
- result2.Intersection(y2);
- EXPECT_TRUE(result2.Empty()) << result2;
-
- const IntervalSet<int64_t> x3({{-1, 5}, {5, 10}});
- const IntervalSet<int64_t> y3({{-10, -1}, {10, 95}});
-
- IntervalSet<int64_t> result3 = x3;
- result3.Intersection(y3);
- EXPECT_TRUE(result3.Empty()) << result3;
-}
-
-TEST_F(IntervalSetTest,
- IntervalSetIntersectionAlternatingIntersectingIntervals) {
- const IntervalSet<int> x1({{0, 10}});
- const IntervalSet<int> y1({{-50, 1}, {9, 95}});
- const IntervalSet<int> expected_result1({{0, 1}, {9, 10}});
-
- IntervalSet<int> result1 = x1;
- result1.Intersection(y1);
- EXPECT_EQ(result1, expected_result1);
-
- const IntervalSet<int16_t> x2({{0, 10}, {20, 30}, {40, 90}});
- const IntervalSet<int16_t> y2(
- {{-50, -40}, {-2, 2}, {9, 21}, {32, 41}, {85, 95}});
- const IntervalSet<int16_t> expected_result2(
- {{0, 2}, {9, 10}, {20, 21}, {40, 41}, {85, 90}});
-
- IntervalSet<int16_t> result2 = x2;
- result2.Intersection(y2);
- EXPECT_EQ(result2, expected_result2);
-
- const IntervalSet<int64_t> x3({{-1, 5}, {5, 10}});
- const IntervalSet<int64_t> y3({{-10, 3}, {4, 95}});
- const IntervalSet<int64_t> expected_result3({{-1, 3}, {4, 10}});
-
- IntervalSet<int64_t> result3 = x3;
- result3.Intersection(y3);
- EXPECT_EQ(result3, expected_result3);
-}
-
-#endif // 0
-
-TEST_F(IntervalSetTest, IntervalSetIntersectionIdentical) {
- IntervalSet<int> copy(is);
- EXPECT_TRUE(copy.Intersects(is));
- EXPECT_TRUE(is.Intersects(copy));
- is.Intersection(copy);
- EXPECT_EQ(copy, is);
-}
-
-TEST_F(IntervalSetTest, IntervalSetIntersectionSuperset) {
- IntervalSet<int> mine(-1, 10000);
- EXPECT_TRUE(mine.Intersects(is));
- EXPECT_TRUE(is.Intersects(mine));
- mine.Intersection(is);
- EXPECT_EQ(is, mine);
-}
-
-TEST_F(IntervalSetTest, IntervalSetIntersectionSubset) {
- IntervalSet<int> copy(is);
- IntervalSet<int> theirs(-1, 10000);
- EXPECT_TRUE(copy.Intersects(theirs));
- EXPECT_TRUE(theirs.Intersects(copy));
- is.Intersection(theirs);
- EXPECT_EQ(copy, is);
-}
-
-TEST_F(IntervalSetTest, IntervalSetIntersectionLargeSet) {
- IntervalSet<int> mine, theirs;
- // mine: [0, 9), [10, 19), ..., [990, 999)
- for (int i = 0; i < 1000; i += 10) {
- mine.Add(i, i + 9);
- }
-
- theirs.Add(500, 520);
- theirs.Add(535, 545);
- theirs.Add(801, 809);
- EXPECT_TRUE(mine.Intersects(theirs));
- EXPECT_TRUE(theirs.Intersects(mine));
- mine.Intersection(theirs);
- EXPECT_TRUE(Check(mine, 5, 500, 509, 510, 519, 535, 539, 540, 545, 801, 809));
- EXPECT_TRUE(mine.Intersects(theirs));
- EXPECT_TRUE(theirs.Intersects(mine));
-}
-
-TEST_F(IntervalSetTest, IntervalSetDifference) {
- is.Difference(other);
- EXPECT_TRUE(Check(is, 10, 100, 200, 300, 350, 360, 370, 380, 400, 530, 600,
- 700, 770, 900, 1000, 1100, 1200, 1900, 2000, 2100, 2200));
- IntervalSet<int> copy = is;
- is.Difference(copy);
- EXPECT_TRUE(is.Empty());
-}
-
-TEST_F(IntervalSetTest, IntervalSetDifferenceSingleBounds) {
- vector<Interval<int>> ivals;
- other.Get(&ivals);
- for (size_t i = 0; i < ivals.size(); ++i) {
- is.Difference(ivals[i].min(), ivals[i].max());
- }
- EXPECT_TRUE(Check(is, 10, 100, 200, 300, 350, 360, 370, 380, 400, 530, 600,
- 700, 770, 900, 1000, 1100, 1200, 1900, 2000, 2100, 2200));
-}
-
-TEST_F(IntervalSetTest, IntervalSetDifferenceSingleInterval) {
- vector<Interval<int>> ivals;
- other.Get(&ivals);
- for (size_t i = 0; i < ivals.size(); ++i) {
- is.Difference(ivals[i]);
- }
- EXPECT_TRUE(Check(is, 10, 100, 200, 300, 350, 360, 370, 380, 400, 530, 600,
- 700, 770, 900, 1000, 1100, 1200, 1900, 2000, 2100, 2200));
-}
-
-TEST_F(IntervalSetTest, IntervalSetDifferenceAlternatingIntervals) {
- IntervalSet<int> mine, theirs;
- mine.Add(10, 20);
- mine.Add(40, 50);
- mine.Add(60, 70);
- theirs.Add(25, 39);
- theirs.Add(55, 59);
- theirs.Add(75, 79);
-
- mine.Difference(theirs);
- EXPECT_TRUE(Check(mine, 3, 10, 20, 40, 50, 60, 70));
-}
-
-TEST_F(IntervalSetTest, IntervalSetDifferenceEmptyMine) {
- IntervalSet<string> mine, theirs;
- theirs.Add("a", "b");
-
- mine.Difference(theirs);
- EXPECT_TRUE(mine.Empty());
-}
-
-TEST_F(IntervalSetTest, IntervalSetDifferenceEmptyTheirs) {
- IntervalSet<string> mine, theirs;
- mine.Add("a", "b");
-
- mine.Difference(theirs);
- EXPECT_EQ(1u, mine.Size());
- EXPECT_EQ("a", mine.begin()->min());
- EXPECT_EQ("b", mine.begin()->max());
-}
-
-TEST_F(IntervalSetTest, IntervalSetDifferenceTheirsBeforeMine) {
- IntervalSet<string> mine, theirs;
- mine.Add("y", "z");
- theirs.Add("a", "b");
-
- mine.Difference(theirs);
- EXPECT_EQ(1u, mine.Size());
- EXPECT_EQ("y", mine.begin()->min());
- EXPECT_EQ("z", mine.begin()->max());
-}
-
-TEST_F(IntervalSetTest, IntervalSetDifferenceMineBeforeTheirs) {
- IntervalSet<string> mine, theirs;
- mine.Add("a", "b");
- theirs.Add("y", "z");
-
- mine.Difference(theirs);
- EXPECT_EQ(1u, mine.Size());
- EXPECT_EQ("a", mine.begin()->min());
- EXPECT_EQ("b", mine.begin()->max());
-}
-
-TEST_F(IntervalSetTest, IntervalSetDifferenceIdentical) {
- IntervalSet<string> mine;
- mine.Add("a", "b");
- mine.Add("c", "d");
- IntervalSet<string> theirs(mine);
-
- mine.Difference(theirs);
- EXPECT_TRUE(mine.Empty());
-}
-
-TEST_F(IntervalSetTest, EmptyComplement) {
- // The complement of an empty set is the input interval:
- IntervalSet<int> iset;
- iset.Complement(100, 200);
- EXPECT_TRUE(Check(iset, 1, 100, 200));
-}
-
-TEST(IntervalSetMultipleCompactionTest, OuterCovering) {
- IntervalSet<int> iset;
- // First add a bunch of disjoint ranges
- iset.Add(100, 150);
- iset.Add(200, 250);
- iset.Add(300, 350);
- iset.Add(400, 450);
- EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450));
- // Now add a big range that covers all of these ranges
- iset.Add(0, 500);
- EXPECT_TRUE(Check(iset, 1, 0, 500));
-}
-
-TEST(IntervalSetMultipleCompactionTest, InnerCovering) {
- IntervalSet<int> iset;
- // First add a bunch of disjoint ranges
- iset.Add(100, 150);
- iset.Add(200, 250);
- iset.Add(300, 350);
- iset.Add(400, 450);
- EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450));
- // Now add a big range that partially covers the left and right most ranges.
- iset.Add(125, 425);
- EXPECT_TRUE(Check(iset, 1, 100, 450));
-}
-
-TEST(IntervalSetMultipleCompactionTest, LeftCovering) {
- IntervalSet<int> iset;
- // First add a bunch of disjoint ranges
- iset.Add(100, 150);
- iset.Add(200, 250);
- iset.Add(300, 350);
- iset.Add(400, 450);
- EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450));
- // Now add a big range that partially covers the left most range.
- iset.Add(125, 500);
- EXPECT_TRUE(Check(iset, 1, 100, 500));
-}
-
-TEST(IntervalSetMultipleCompactionTest, RightCovering) {
- IntervalSet<int> iset;
- // First add a bunch of disjoint ranges
- iset.Add(100, 150);
- iset.Add(200, 250);
- iset.Add(300, 350);
- iset.Add(400, 450);
- EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450));
- // Now add a big range that partially covers the right most range.
- iset.Add(0, 425);
- EXPECT_TRUE(Check(iset, 1, 0, 450));
-}
-
-// Helper method for testing and verifying the results of a one-interval
-// completement case.
-static bool CheckOneComplement(int add_min,
- int add_max,
- int comp_min,
- int comp_max,
- int count,
- ...) {
- IntervalSet<int> iset;
- iset.Add(add_min, add_max);
- iset.Complement(comp_min, comp_max);
- bool result = true;
- va_list ap;
- va_start(ap, count);
- if (!VA_Check(iset, count, ap)) {
- result = false;
- }
- va_end(ap);
- return result;
-}
-
-TEST_F(IntervalSetTest, SingleIntervalComplement) {
- // Verify the complement of a set with one interval (i):
- // |----- i -----|
- // |----- args -----|
- EXPECT_TRUE(CheckOneComplement(0, 10, 50, 150, 1, 50, 150));
-
- // |----- i -----|
- // |----- args -----|
- EXPECT_TRUE(CheckOneComplement(50, 150, 0, 100, 1, 0, 50));
-
- // |----- i -----|
- // |----- args -----|
- EXPECT_TRUE(CheckOneComplement(50, 150, 50, 150, 0));
-
- // |---------- i ----------|
- // |----- args -----|
- EXPECT_TRUE(CheckOneComplement(50, 500, 100, 300, 0));
-
- // |----- i -----|
- // |---------- args ----------|
- EXPECT_TRUE(CheckOneComplement(50, 500, 0, 800, 2, 0, 50, 500, 800));
-
- // |----- i -----|
- // |----- args -----|
- EXPECT_TRUE(CheckOneComplement(50, 150, 100, 300, 1, 150, 300));
-
- // |----- i -----|
- // |----- args -----|
- EXPECT_TRUE(CheckOneComplement(50, 150, 200, 300, 1, 200, 300));
-}
-
-// Helper method that copies <iset> and takes its complement,
-// returning false if Check succeeds.
-static bool CheckComplement(const IntervalSet<int>& iset,
- int comp_min,
- int comp_max,
- int count,
- ...) {
- IntervalSet<int> iset_copy = iset;
- iset_copy.Complement(comp_min, comp_max);
- bool result = true;
- va_list ap;
- va_start(ap, count);
- if (!VA_Check(iset_copy, count, ap)) {
- result = false;
- }
- va_end(ap);
- return result;
-}
-
-TEST_F(IntervalSetTest, MultiIntervalComplement) {
- // Initialize a small test set:
- IntervalSet<int> iset;
- iset.Add(100, 200);
- iset.Add(300, 400);
- iset.Add(500, 600);
-
- // |----- i -----|
- // |----- comp -----|
- EXPECT_TRUE(CheckComplement(iset, 0, 50, 1, 0, 50));
-
- // |----- i -----|
- // |----- comp -----|
- EXPECT_TRUE(CheckComplement(iset, 0, 200, 1, 0, 100));
- EXPECT_TRUE(CheckComplement(iset, 0, 220, 2, 0, 100, 200, 220));
-
- // |----- i -----|
- // |----- comp -----|
- EXPECT_TRUE(CheckComplement(iset, 100, 600, 2, 200, 300, 400, 500));
-
- // |---------- i ----------|
- // |----- comp -----|
- EXPECT_TRUE(CheckComplement(iset, 300, 400, 0));
- EXPECT_TRUE(CheckComplement(iset, 250, 400, 1, 250, 300));
- EXPECT_TRUE(CheckComplement(iset, 300, 450, 1, 400, 450));
- EXPECT_TRUE(CheckComplement(iset, 250, 450, 2, 250, 300, 400, 450));
-
- // |----- i -----|
- // |---------- comp ----------|
- EXPECT_TRUE(
- CheckComplement(iset, 0, 700, 4, 0, 100, 200, 300, 400, 500, 600, 700));
-
- // |----- i -----|
- // |----- comp -----|
- EXPECT_TRUE(CheckComplement(iset, 400, 700, 2, 400, 500, 600, 700));
- EXPECT_TRUE(CheckComplement(iset, 350, 700, 2, 400, 500, 600, 700));
-
- // |----- i -----|
- // |----- comp -----|
- EXPECT_TRUE(CheckComplement(iset, 700, 800, 1, 700, 800));
-}
-
-// Verifies ToString, operator<< don't assert.
-// TODO(rtenneti): Implement ToString() method of IntervalSet.
-TEST_F(IntervalSetTest, DISABLED_ToString) {
- IntervalSet<int> iset;
- iset.Add(300, 400);
- iset.Add(100, 200);
- iset.Add(500, 600);
- EXPECT_TRUE(!iset.ToString().empty());
- VLOG(2) << iset.ToString();
- // Order and format of ToString() output is guaranteed.
- EXPECT_EQ("[100, 200) [300, 400) [500, 600)", iset.ToString());
- EXPECT_EQ("[1, 2)", IntervalSet<int>(1, 2).ToString());
- EXPECT_EQ("", IntervalSet<int>().ToString());
-}
-
-TEST_F(IntervalSetTest, ConstructionDiscardsEmptyInterval) {
- EXPECT_TRUE(IntervalSet<int>(Interval<int>(2, 2)).Empty());
- EXPECT_TRUE(IntervalSet<int>(2, 2).Empty());
- EXPECT_FALSE(IntervalSet<int>(Interval<int>(2, 3)).Empty());
- EXPECT_FALSE(IntervalSet<int>(2, 3).Empty());
-}
-
-TEST_F(IntervalSetTest, Swap) {
- IntervalSet<int> a, b;
- a.Add(300, 400);
- b.Add(100, 200);
- b.Add(500, 600);
- a.Swap(&b);
- EXPECT_TRUE(Check(a, 2, 100, 200, 500, 600));
- EXPECT_TRUE(Check(b, 1, 300, 400));
- swap(a, b);
- EXPECT_TRUE(Check(a, 1, 300, 400));
- EXPECT_TRUE(Check(b, 2, 100, 200, 500, 600));
-}
-
-// TODO(rtenneti): Enabled these tests.
-#if 0
-static void BM_Difference(int iters) {
- // StopBenchmarkTiming();
- IntervalSet<int> difference_set;
- int start = 10;
- for (int i = 0; i < 1000000; ++i) {
- difference_set.Add(start, start+5);
- start += 7;
- }
-
- // Create an interval somewhere in the middle of the difference set.
- // StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
- IntervalSet<int> initial(1000000, 1000020);
- initial.Difference(difference_set);
- }
-}
-
-BENCHMARK(BM_Difference);
-
-static void BM_IntersectionSmallAndLarge(int iters, int size) {
- // Intersects constant size 'mine' with large 'theirs'.
- StopBenchmarkTiming();
- IntervalSet<int> theirs;
- for (int i = 0; i < size; ++i) {
- theirs.Add(2 * i, 2 * i + 1);
- }
-
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
- // 'mine' starts in the middle of 'theirs'.
- IntervalSet<int> mine(size, size + 10);
- mine.Intersection(theirs);
- }
-}
-
-BENCHMARK_RANGE(BM_IntersectionSmallAndLarge, 0, 1 << 23);
-
-static void BM_IntersectionIdentical(int iters, int size) {
- // Intersects identical 'mine' and 'theirs'.
- StopBenchmarkTiming();
- IntervalSet<int> mine;
- for (int i = 0; i < size; ++i) {
- mine.Add(2 * i, 2 * i + 1);
- }
- IntervalSet<int> theirs(mine);
-
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
- mine.Intersection(theirs);
- }
-}
-
-BENCHMARK_RANGE(BM_IntersectionIdentical, 0, 1 << 23);
-
-class IntervalSetInitTest : public testing::Test {
- protected:
- const std::vector<Interval<int>> intervals_{{0, 1}, {2, 4}};
-};
-
-TEST_F(IntervalSetInitTest, DirectInit) {
- std::initializer_list<Interval<int>> il = {{0, 1}, {2, 3}, {3, 4}};
- IntervalSet<int> s(il);
- EXPECT_THAT(s, ElementsAreArray(intervals_));
-}
-
-TEST_F(IntervalSetInitTest, CopyInit) {
- std::initializer_list<Interval<int>> il = {{0, 1}, {2, 3}, {3, 4}};
- IntervalSet<int> s = il;
- EXPECT_THAT(s, ElementsAreArray(intervals_));
-}
-
-TEST_F(IntervalSetInitTest, AssignIterPair) {
- IntervalSet<int> s(0, 1000); // Make sure assign clears.
- s.assign(intervals_.begin(), intervals_.end());
- EXPECT_THAT(s, ElementsAreArray(intervals_));
-}
-
-TEST_F(IntervalSetInitTest, AssignInitList) {
- IntervalSet<int> s(0, 1000); // Make sure assign clears.
- s.assign({{0, 1}, {2, 3}, {3, 4}});
- EXPECT_THAT(s, ElementsAreArray(intervals_));
-}
-
-TEST_F(IntervalSetInitTest, AssignmentInitList) {
- std::initializer_list<Interval<int>> il = {{0, 1}, {2, 3}, {3, 4}};
- IntervalSet<int> s;
- s = il;
- EXPECT_THAT(s, ElementsAreArray(intervals_));
-}
-
-TEST_F(IntervalSetInitTest, BracedInitThenBracedAssign) {
- IntervalSet<int> s{{0, 1}, {2, 3}, {3, 4}};
- s = {{0, 1}, {2, 4}};
- EXPECT_THAT(s, ElementsAreArray(intervals_));
-}
-
-#endif // 0
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/interval_test.cc b/chromium/net/quic/interval_test.cc
deleted file mode 100644
index ead7501fc56..00000000000
--- a/chromium/net/quic/interval_test.cc
+++ /dev/null
@@ -1,333 +0,0 @@
-// Copyright 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.
-//
-// ----------------------------------------------------------------------
-//
-// Unittest for the Interval class.
-//
-// Author: Will Neveitt (wneveitt@google.com)
-// ----------------------------------------------------------------------
-
-#include "net/quic/interval.h"
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "net/test/gtest_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::pair;
-using std::string;
-using std::vector;
-
-namespace net {
-namespace test {
-namespace {
-
-class IntervalTest : public ::testing::Test {
- protected:
- // Test intersection between the two intervals i1 and i2. Tries
- // i1.IntersectWith(i2) and vice versa. The intersection should change i1 iff
- // changes_i1 is true, and the same for changes_i2. The resulting
- // intersection should be result.
- void TestIntersect(const Interval<int64_t>& i1,
- const Interval<int64_t>& i2,
- bool changes_i1,
- bool changes_i2,
- const Interval<int64_t>& result) {
- Interval<int64_t> i;
- i.CopyFrom(i1);
- EXPECT_TRUE(i.IntersectWith(i2) == changes_i1 && i.Equals(result));
- i.CopyFrom(i2);
- EXPECT_TRUE(i.IntersectWith(i1) == changes_i2 && i.Equals(result));
- }
-};
-
-TEST_F(IntervalTest, ConstructorsCopyAndClear) {
- Interval<int32_t> empty;
- EXPECT_TRUE(empty.Empty());
-
- Interval<int32_t> d2(0, 100);
- EXPECT_EQ(0, d2.min());
- EXPECT_EQ(100, d2.max());
- EXPECT_EQ(Interval<int32_t>(0, 100), d2);
- EXPECT_NE(Interval<int32_t>(0, 99), d2);
-
- empty.CopyFrom(d2);
- EXPECT_EQ(0, d2.min());
- EXPECT_EQ(100, d2.max());
- EXPECT_TRUE(empty.Equals(d2));
- EXPECT_EQ(empty, d2);
- EXPECT_TRUE(d2.Equals(empty));
- EXPECT_EQ(d2, empty);
-
- Interval<int32_t> max_less_than_min(40, 20);
- EXPECT_TRUE(max_less_than_min.Empty());
- EXPECT_EQ(40, max_less_than_min.min());
- EXPECT_EQ(20, max_less_than_min.max());
-
- Interval<int> d3(10, 20);
- d3.Clear();
- EXPECT_TRUE(d3.Empty());
-}
-
-TEST_F(IntervalTest, GettersSetters) {
- Interval<int32_t> d1(100, 200);
-
- // SetMin:
- d1.SetMin(30);
- EXPECT_EQ(30, d1.min());
- EXPECT_EQ(200, d1.max());
-
- // SetMax:
- d1.SetMax(220);
- EXPECT_EQ(30, d1.min());
- EXPECT_EQ(220, d1.max());
-
- // Set:
- d1.Clear();
- d1.Set(30, 220);
- EXPECT_EQ(30, d1.min());
- EXPECT_EQ(220, d1.max());
-
- // SpanningUnion:
- Interval<int32_t> d2;
- EXPECT_TRUE(!d1.SpanningUnion(d2));
- EXPECT_EQ(30, d1.min());
- EXPECT_EQ(220, d1.max());
-
- EXPECT_TRUE(d2.SpanningUnion(d1));
- EXPECT_EQ(30, d2.min());
- EXPECT_EQ(220, d2.max());
-
- d2.SetMin(40);
- d2.SetMax(100);
- EXPECT_TRUE(!d1.SpanningUnion(d2));
- EXPECT_EQ(30, d1.min());
- EXPECT_EQ(220, d1.max());
-
- d2.SetMin(20);
- d2.SetMax(100);
- EXPECT_TRUE(d1.SpanningUnion(d2));
- EXPECT_EQ(20, d1.min());
- EXPECT_EQ(220, d1.max());
-
- d2.SetMin(50);
- d2.SetMax(300);
- EXPECT_TRUE(d1.SpanningUnion(d2));
- EXPECT_EQ(20, d1.min());
- EXPECT_EQ(300, d1.max());
-
- d2.SetMin(0);
- d2.SetMax(500);
- EXPECT_TRUE(d1.SpanningUnion(d2));
- EXPECT_EQ(0, d1.min());
- EXPECT_EQ(500, d1.max());
-
- d2.SetMin(100);
- d2.SetMax(0);
- EXPECT_TRUE(!d1.SpanningUnion(d2));
- EXPECT_EQ(0, d1.min());
- EXPECT_EQ(500, d1.max());
- EXPECT_TRUE(d2.SpanningUnion(d1));
- EXPECT_EQ(0, d2.min());
- EXPECT_EQ(500, d2.max());
-}
-
-TEST_F(IntervalTest, CoveringOps) {
- const Interval<int64_t> empty;
- const Interval<int64_t> d(100, 200);
- const Interval<int64_t> d1(0, 50);
- const Interval<int64_t> d2(50, 110);
- const Interval<int64_t> d3(110, 180);
- const Interval<int64_t> d4(180, 220);
- const Interval<int64_t> d5(220, 300);
- const Interval<int64_t> d6(100, 150);
- const Interval<int64_t> d7(150, 200);
- const Interval<int64_t> d8(0, 300);
-
- // Intersection:
- EXPECT_TRUE(d.Intersects(d));
- EXPECT_TRUE(!empty.Intersects(d) && !d.Intersects(empty));
- EXPECT_TRUE(!d.Intersects(d1) && !d1.Intersects(d));
- EXPECT_TRUE(d.Intersects(d2) && d2.Intersects(d));
- EXPECT_TRUE(d.Intersects(d3) && d3.Intersects(d));
- EXPECT_TRUE(d.Intersects(d4) && d4.Intersects(d));
- EXPECT_TRUE(!d.Intersects(d5) && !d5.Intersects(d));
- EXPECT_TRUE(d.Intersects(d6) && d6.Intersects(d));
- EXPECT_TRUE(d.Intersects(d7) && d7.Intersects(d));
- EXPECT_TRUE(d.Intersects(d8) && d8.Intersects(d));
-
- Interval<int64_t> i;
- EXPECT_TRUE(d.Intersects(d, &i) && d.Equals(i));
- EXPECT_TRUE(!empty.Intersects(d, NULL) && !d.Intersects(empty, NULL));
- EXPECT_TRUE(!d.Intersects(d1, NULL) && !d1.Intersects(d, NULL));
- EXPECT_TRUE(d.Intersects(d2, &i) && i.Equals(Interval<int64_t>(100, 110)));
- EXPECT_TRUE(d2.Intersects(d, &i) && i.Equals(Interval<int64_t>(100, 110)));
- EXPECT_TRUE(d.Intersects(d3, &i) && i.Equals(d3));
- EXPECT_TRUE(d3.Intersects(d, &i) && i.Equals(d3));
- EXPECT_TRUE(d.Intersects(d4, &i) && i.Equals(Interval<int64_t>(180, 200)));
- EXPECT_TRUE(d4.Intersects(d, &i) && i.Equals(Interval<int64_t>(180, 200)));
- EXPECT_TRUE(!d.Intersects(d5, NULL) && !d5.Intersects(d, NULL));
- EXPECT_TRUE(d.Intersects(d6, &i) && i.Equals(d6));
- EXPECT_TRUE(d6.Intersects(d, &i) && i.Equals(d6));
- EXPECT_TRUE(d.Intersects(d7, &i) && i.Equals(d7));
- EXPECT_TRUE(d7.Intersects(d, &i) && i.Equals(d7));
- EXPECT_TRUE(d.Intersects(d8, &i) && i.Equals(d));
- EXPECT_TRUE(d8.Intersects(d, &i) && i.Equals(d));
-
- // Test IntersectsWith().
- // Arguments are TestIntersect(i1, i2, changes_i1, changes_i2, result).
- TestIntersect(empty, d, false, true, empty);
- TestIntersect(d, d1, true, true, empty);
- TestIntersect(d1, d2, true, true, empty);
- TestIntersect(d, d2, true, true, Interval<int64_t>(100, 110));
- TestIntersect(d8, d, true, false, d);
- TestIntersect(d8, d1, true, false, d1);
- TestIntersect(d8, d5, true, false, d5);
-
- // Contains:
- EXPECT_TRUE(!empty.Contains(d) && !d.Contains(empty));
- EXPECT_TRUE(d.Contains(d));
- EXPECT_TRUE(!d.Contains(d1) && !d1.Contains(d));
- EXPECT_TRUE(!d.Contains(d2) && !d2.Contains(d));
- EXPECT_TRUE(d.Contains(d3) && !d3.Contains(d));
- EXPECT_TRUE(!d.Contains(d4) && !d4.Contains(d));
- EXPECT_TRUE(!d.Contains(d5) && !d5.Contains(d));
- EXPECT_TRUE(d.Contains(d6) && !d6.Contains(d));
- EXPECT_TRUE(d.Contains(d7) && !d7.Contains(d));
- EXPECT_TRUE(!d.Contains(d8) && d8.Contains(d));
-
- EXPECT_TRUE(d.Contains(100));
- EXPECT_TRUE(!d.Contains(200));
- EXPECT_TRUE(d.Contains(150));
- EXPECT_TRUE(!d.Contains(99));
- EXPECT_TRUE(!d.Contains(201));
-
- // Difference:
- vector<Interval<int64_t>*> diff;
-
- EXPECT_TRUE(!d.Difference(empty, &diff));
- EXPECT_EQ(1u, diff.size());
- EXPECT_EQ(100u, diff[0]->min());
- EXPECT_EQ(200u, diff[0]->max());
- STLDeleteElements(&diff);
- EXPECT_TRUE(!empty.Difference(d, &diff) && diff.empty());
-
- EXPECT_TRUE(d.Difference(d, &diff) && diff.empty());
- EXPECT_TRUE(!d.Difference(d1, &diff));
- EXPECT_EQ(1u, diff.size());
- EXPECT_EQ(100u, diff[0]->min());
- EXPECT_EQ(200u, diff[0]->max());
- STLDeleteElements(&diff);
-
- Interval<int64_t> lo;
- Interval<int64_t> hi;
-
- EXPECT_TRUE(d.Difference(d2, &lo, &hi));
- EXPECT_TRUE(lo.Empty());
- EXPECT_EQ(110u, hi.min());
- EXPECT_EQ(200u, hi.max());
- EXPECT_TRUE(d.Difference(d2, &diff));
- EXPECT_EQ(1u, diff.size());
- EXPECT_EQ(110u, diff[0]->min());
- EXPECT_EQ(200u, diff[0]->max());
- STLDeleteElements(&diff);
-
- EXPECT_TRUE(d.Difference(d3, &lo, &hi));
- EXPECT_EQ(100u, lo.min());
- EXPECT_EQ(110u, lo.max());
- EXPECT_EQ(180u, hi.min());
- EXPECT_EQ(200u, hi.max());
- EXPECT_TRUE(d.Difference(d3, &diff));
- EXPECT_EQ(2u, diff.size());
- EXPECT_EQ(100u, diff[0]->min());
- EXPECT_EQ(110u, diff[0]->max());
- EXPECT_EQ(180u, diff[1]->min());
- EXPECT_EQ(200u, diff[1]->max());
- STLDeleteElements(&diff);
-
- EXPECT_TRUE(d.Difference(d4, &lo, &hi));
- EXPECT_EQ(100u, lo.min());
- EXPECT_EQ(180u, lo.max());
- EXPECT_TRUE(hi.Empty());
- EXPECT_TRUE(d.Difference(d4, &diff));
- EXPECT_EQ(1u, diff.size());
- EXPECT_EQ(100u, diff[0]->min());
- EXPECT_EQ(180u, diff[0]->max());
- STLDeleteElements(&diff);
-
- EXPECT_FALSE(d.Difference(d5, &lo, &hi));
- EXPECT_EQ(100u, lo.min());
- EXPECT_EQ(200u, lo.max());
- EXPECT_TRUE(hi.Empty());
- EXPECT_FALSE(d.Difference(d5, &diff));
- EXPECT_EQ(1u, diff.size());
- EXPECT_EQ(100u, diff[0]->min());
- EXPECT_EQ(200u, diff[0]->max());
- STLDeleteElements(&diff);
-
- EXPECT_TRUE(d.Difference(d6, &lo, &hi));
- EXPECT_TRUE(lo.Empty());
- EXPECT_EQ(150u, hi.min());
- EXPECT_EQ(200u, hi.max());
- EXPECT_TRUE(d.Difference(d6, &diff));
- EXPECT_EQ(1u, diff.size());
- EXPECT_EQ(150u, diff[0]->min());
- EXPECT_EQ(200u, diff[0]->max());
- STLDeleteElements(&diff);
-
- EXPECT_TRUE(d.Difference(d7, &lo, &hi));
- EXPECT_EQ(100u, lo.min());
- EXPECT_EQ(150u, lo.max());
- EXPECT_TRUE(hi.Empty());
- EXPECT_TRUE(d.Difference(d7, &diff));
- EXPECT_EQ(1u, diff.size());
- EXPECT_EQ(100u, diff[0]->min());
- EXPECT_EQ(150u, diff[0]->max());
- STLDeleteElements(&diff);
-
- EXPECT_TRUE(d.Difference(d8, &lo, &hi));
- EXPECT_TRUE(lo.Empty());
- EXPECT_TRUE(hi.Empty());
- EXPECT_TRUE(d.Difference(d8, &diff) && diff.empty());
-}
-
-TEST_F(IntervalTest, Length) {
- const Interval<int> empty1;
- const Interval<int> empty2(1, 1);
- const Interval<int> empty3(1, 0);
- const Interval<base::TimeDelta> empty4(
- base::TimeDelta() + base::TimeDelta::FromSeconds(1), base::TimeDelta());
- const Interval<int> d1(1, 2);
- const Interval<int> d2(0, 50);
- const Interval<base::TimeDelta> d3(
- base::TimeDelta(), base::TimeDelta() + base::TimeDelta::FromSeconds(1));
- const Interval<base::TimeDelta> d4(
- base::TimeDelta() + base::TimeDelta::FromHours(1),
- base::TimeDelta() + base::TimeDelta::FromMinutes(90));
-
- EXPECT_EQ(0, empty1.Length());
- EXPECT_EQ(0, empty2.Length());
- EXPECT_EQ(0, empty3.Length());
- EXPECT_EQ(base::TimeDelta(), empty4.Length());
- EXPECT_EQ(1, d1.Length());
- EXPECT_EQ(50, d2.Length());
- EXPECT_EQ(base::TimeDelta::FromSeconds(1), d3.Length());
- EXPECT_EQ(base::TimeDelta::FromMinutes(30), d4.Length());
-}
-
-TEST_F(IntervalTest, IntervalOfTypeWithNoOperatorMinus) {
- // Interval<T> should work even if T does not support operator-(). We just
- // can't call Interval<T>::Length() for such types.
- const Interval<string> d1("a", "b");
- const Interval<pair<int, int>> d2({1, 2}, {4, 3});
- EXPECT_EQ("a", d1.min());
- EXPECT_EQ("b", d1.max());
- EXPECT_EQ(std::make_pair(1, 2), d2.min());
- EXPECT_EQ(std::make_pair(4, 3), d2.max());
-}
-
-} // unnamed namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/iovector.cc b/chromium/net/quic/iovector.cc
deleted file mode 100644
index effa52d419e..00000000000
--- a/chromium/net/quic/iovector.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2013 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/iovector.h"
-
-namespace net {
-
-IOVector::IOVector() {}
-
-IOVector::IOVector(const IOVector& other) = default;
-
-IOVector::~IOVector() {}
-
-} // namespace net
diff --git a/chromium/net/quic/iovector_test.cc b/chromium/net/quic/iovector_test.cc
deleted file mode 100644
index 4daaaeed5c8..00000000000
--- a/chromium/net/quic/iovector_test.cc
+++ /dev/null
@@ -1,373 +0,0 @@
-// Copyright 2013 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/iovector.h"
-
-#include <string.h>
-
-#include <memory>
-#include <string>
-
-#include "net/test/gtest_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::string;
-
-namespace net {
-namespace test {
-namespace {
-
-const char* const test_data[] = {
- "test string 1, a medium size one.", "test string2",
- "test string 3, a looooooooooooong loooooooooooooooong string"};
-
-TEST(IOVectorTest, CopyConstructor) {
- IOVector iov1;
- for (size_t i = 0; i < arraysize(test_data); ++i) {
- iov1.Append(const_cast<char*>(test_data[i]), strlen(test_data[i]));
- }
- IOVector iov2 = iov1;
- EXPECT_EQ(iov2.Size(), iov1.Size());
- for (size_t i = 0; i < iov2.Size(); ++i) {
- EXPECT_TRUE(iov2.iovec()[i].iov_base == iov1.iovec()[i].iov_base);
- EXPECT_EQ(iov2.iovec()[i].iov_len, iov1.iovec()[i].iov_len);
- }
- EXPECT_EQ(iov2.TotalBufferSize(), iov1.TotalBufferSize());
-}
-
-TEST(IOVectorTest, AssignmentOperator) {
- IOVector iov1;
- for (size_t i = 0; i < arraysize(test_data); ++i) {
- iov1.Append(const_cast<char*>(test_data[i]), strlen(test_data[i]));
- }
- IOVector iov2;
- iov2.Append(const_cast<char*>("ephemeral string"), 16);
- // The following assignment results in a shallow copy;
- // both IOVectors point to the same underlying data.
- iov2 = iov1;
- EXPECT_EQ(iov2.Size(), iov1.Size());
- for (size_t i = 0; i < iov2.Size(); ++i) {
- EXPECT_TRUE(iov2.iovec()[i].iov_base == iov1.iovec()[i].iov_base);
- EXPECT_EQ(iov2.iovec()[i].iov_len, iov1.iovec()[i].iov_len);
- }
- EXPECT_EQ(iov2.TotalBufferSize(), iov1.TotalBufferSize());
-}
-
-TEST(IOVectorTest, Append) {
- IOVector iov;
- int length = 0;
- const struct iovec* iov2 = iov.iovec();
-
- ASSERT_EQ(0u, iov.Size());
- ASSERT_TRUE(iov2 == nullptr);
- for (size_t i = 0; i < arraysize(test_data); ++i) {
- const int str_len = strlen(test_data[i]);
- const int append_len = str_len / 2;
- // This should append a new block.
- iov.Append(const_cast<char*>(test_data[i]), append_len);
- length += append_len;
- ASSERT_EQ(i + 1, static_cast<size_t>(iov.Size()));
- ASSERT_TRUE(iov.LastBlockEnd() == test_data[i] + append_len);
- // This should just lengthen the existing block.
- iov.Append(const_cast<char*>(test_data[i] + append_len),
- str_len - append_len);
- length += (str_len - append_len);
- ASSERT_EQ(i + 1, static_cast<size_t>(iov.Size()));
- ASSERT_TRUE(iov.LastBlockEnd() == test_data[i] + str_len);
- }
-
- iov2 = iov.iovec();
- ASSERT_TRUE(iov2 != nullptr);
- for (size_t i = 0; i < iov.Size(); ++i) {
- ASSERT_TRUE(test_data[i] == iov2[i].iov_base);
- ASSERT_EQ(strlen(test_data[i]), iov2[i].iov_len);
- }
-}
-
-TEST(IOVectorTest, AppendIovec) {
- IOVector iov;
- const struct iovec test_iov[] = {{const_cast<char*>("foo"), 3},
- {const_cast<char*>("bar"), 3},
- {const_cast<char*>("buzzzz"), 6}};
- iov.AppendIovec(test_iov, arraysize(test_iov));
- for (size_t i = 0; i < arraysize(test_iov); ++i) {
- EXPECT_EQ(test_iov[i].iov_base, iov.iovec()[i].iov_base);
- EXPECT_EQ(test_iov[i].iov_len, iov.iovec()[i].iov_len);
- }
-
- // Test AppendIovecAtMostBytes.
- iov.Clear();
- // Stop in the middle of a block.
- EXPECT_EQ(5u, iov.AppendIovecAtMostBytes(test_iov, arraysize(test_iov), 5));
- EXPECT_EQ(5u, iov.TotalBufferSize());
- iov.Append(static_cast<char*>(test_iov[1].iov_base) + 2, 1);
- // Make sure the boundary case, where max_bytes == size of block also works.
- EXPECT_EQ(6u, iov.AppendIovecAtMostBytes(&test_iov[2], 1, 6));
- ASSERT_LE(arraysize(test_iov), static_cast<size_t>(iov.Size()));
- for (size_t i = 0; i < arraysize(test_iov); ++i) {
- EXPECT_EQ(test_iov[i].iov_base, iov.iovec()[i].iov_base);
- EXPECT_EQ(test_iov[i].iov_len, iov.iovec()[i].iov_len);
- }
-}
-
-TEST(IOVectorTest, ConsumeHalfBlocks) {
- IOVector iov;
- int length = 0;
-
- for (size_t i = 0; i < arraysize(test_data); ++i) {
- const int str_len = strlen(test_data[i]);
- iov.Append(const_cast<char*>(test_data[i]), str_len);
- length += str_len;
- }
- const char* endp = iov.LastBlockEnd();
- for (size_t i = 0; i < arraysize(test_data); ++i) {
- const struct iovec* iov2 = iov.iovec();
- const size_t str_len = strlen(test_data[i]);
- size_t tmp = str_len / 2;
-
- ASSERT_TRUE(iov2 != nullptr);
- ASSERT_TRUE(iov2[0].iov_base == test_data[i]);
- ASSERT_EQ(str_len, iov2[0].iov_len);
-
- // Consume half of the first block.
- size_t consumed = iov.Consume(tmp);
- ASSERT_EQ(tmp, consumed);
- ASSERT_EQ(arraysize(test_data) - i, static_cast<size_t>(iov.Size()));
- iov2 = iov.iovec();
- ASSERT_TRUE(iov2 != nullptr);
- ASSERT_TRUE(iov2[0].iov_base == test_data[i] + tmp);
- ASSERT_EQ(iov2[0].iov_len, str_len - tmp);
-
- // Consume the rest of the first block.
- consumed = iov.Consume(str_len - tmp);
- ASSERT_EQ(str_len - tmp, consumed);
- ASSERT_EQ(arraysize(test_data) - i - 1, static_cast<size_t>(iov.Size()));
- iov2 = iov.iovec();
- if (iov.Size() > 0) {
- ASSERT_TRUE(iov2 != nullptr);
- ASSERT_TRUE(iov.LastBlockEnd() == endp);
- } else {
- ASSERT_TRUE(iov2 == nullptr);
- ASSERT_TRUE(iov.LastBlockEnd() == nullptr);
- }
- }
-}
-
-TEST(IOVectorTest, ConsumeTwoAndHalfBlocks) {
- IOVector iov;
- int length = 0;
-
- for (size_t i = 0; i < arraysize(test_data); ++i) {
- const int str_len = strlen(test_data[i]);
- iov.Append(const_cast<char*>(test_data[i]), str_len);
- length += str_len;
- }
- const size_t last_len = strlen(test_data[arraysize(test_data) - 1]);
- const size_t half_len = last_len / 2;
-
- const char* endp = iov.LastBlockEnd();
- size_t consumed = iov.Consume(length - half_len);
- ASSERT_EQ(length - half_len, consumed);
- const struct iovec* iov2 = iov.iovec();
- ASSERT_TRUE(iov2 != nullptr);
- ASSERT_EQ(1u, iov.Size());
- ASSERT_TRUE(iov2[0].iov_base ==
- test_data[arraysize(test_data) - 1] + last_len - half_len);
- ASSERT_EQ(half_len, iov2[0].iov_len);
- ASSERT_TRUE(iov.LastBlockEnd() == endp);
-
- consumed = iov.Consume(half_len);
- ASSERT_EQ(half_len, consumed);
- iov2 = iov.iovec();
- ASSERT_EQ(0u, iov.Size());
- ASSERT_TRUE(iov2 == nullptr);
- ASSERT_TRUE(iov.LastBlockEnd() == nullptr);
-}
-
-TEST(IOVectorTest, ConsumeTooMuch) {
- IOVector iov;
- int length = 0;
-
- for (size_t i = 0; i < arraysize(test_data); ++i) {
- const int str_len = strlen(test_data[i]);
- iov.Append(const_cast<char*>(test_data[i]), str_len);
- length += str_len;
- }
-
- int consumed = 0;
- EXPECT_DFATAL({ consumed = iov.Consume(length + 1); },
- "Attempting to consume 1 non-existent bytes.");
- ASSERT_EQ(length, consumed);
- const struct iovec* iov2 = iov.iovec();
- ASSERT_EQ(0u, iov.Size());
- ASSERT_TRUE(iov2 == nullptr);
- ASSERT_TRUE(iov.LastBlockEnd() == nullptr);
-}
-
-TEST(IOVectorTest, ConsumeAndCopyHalfBlocks) {
- IOVector iov;
- int length = 0;
-
- for (size_t i = 0; i < arraysize(test_data); ++i) {
- const int str_len = strlen(test_data[i]);
- iov.Append(const_cast<char*>(test_data[i]), str_len);
- length += str_len;
- }
- const char* endp = iov.LastBlockEnd();
- for (size_t i = 0; i < arraysize(test_data); ++i) {
- const struct iovec* iov2 = iov.iovec();
- const size_t str_len = strlen(test_data[i]);
- size_t tmp = str_len / 2;
-
- ASSERT_TRUE(iov2 != nullptr);
- ASSERT_TRUE(iov2[0].iov_base == test_data[i]);
- ASSERT_EQ(str_len, iov2[0].iov_len);
-
- // Consume half of the first block.
- std::unique_ptr<char[]> buffer(new char[str_len]);
- size_t consumed = iov.ConsumeAndCopy(tmp, buffer.get());
- EXPECT_EQ(0, memcmp(test_data[i], buffer.get(), tmp));
- ASSERT_EQ(tmp, consumed);
- ASSERT_EQ(arraysize(test_data) - i, static_cast<size_t>(iov.Size()));
- iov2 = iov.iovec();
- ASSERT_TRUE(iov2 != nullptr);
- ASSERT_TRUE(iov2[0].iov_base == test_data[i] + tmp);
- ASSERT_EQ(iov2[0].iov_len, str_len - tmp);
-
- // Consume the rest of the first block.
- consumed = iov.ConsumeAndCopy(str_len - tmp, buffer.get());
- ASSERT_EQ(str_len - tmp, consumed);
- ASSERT_EQ(arraysize(test_data) - i - 1, static_cast<size_t>(iov.Size()));
- iov2 = iov.iovec();
- if (iov.Size() > 0) {
- ASSERT_TRUE(iov2 != nullptr);
- ASSERT_TRUE(iov.LastBlockEnd() == endp);
- } else {
- ASSERT_TRUE(iov2 == nullptr);
- ASSERT_TRUE(iov.LastBlockEnd() == nullptr);
- }
- }
-}
-
-TEST(IOVectorTest, ConsumeAndCopyTwoAndHalfBlocks) {
- IOVector iov;
- size_t length = 0;
-
- for (size_t i = 0; i < arraysize(test_data); ++i) {
- const int str_len = strlen(test_data[i]);
- iov.Append(const_cast<char*>(test_data[i]), str_len);
- length += str_len;
- }
- const size_t last_len = strlen(test_data[arraysize(test_data) - 1]);
- const size_t half_len = last_len / 2;
-
- const char* endp = iov.LastBlockEnd();
- std::unique_ptr<char[]> buffer(new char[length]);
- size_t consumed = iov.ConsumeAndCopy(length - half_len, buffer.get());
- ASSERT_EQ(length - half_len, consumed);
- const struct iovec* iov2 = iov.iovec();
- ASSERT_TRUE(iov2 != nullptr);
- ASSERT_EQ(1u, iov.Size());
- ASSERT_TRUE(iov2[0].iov_base ==
- test_data[arraysize(test_data) - 1] + last_len - half_len);
- ASSERT_EQ(half_len, iov2[0].iov_len);
- ASSERT_TRUE(iov.LastBlockEnd() == endp);
-
- consumed = iov.Consume(half_len);
- ASSERT_EQ(half_len, consumed);
- iov2 = iov.iovec();
- ASSERT_EQ(0u, iov.Size());
- ASSERT_TRUE(iov2 == nullptr);
- ASSERT_TRUE(iov.LastBlockEnd() == nullptr);
-}
-
-TEST(IOVectorTest, ConsumeAndCopyTooMuch) {
- IOVector iov;
- int length = 0;
-
- for (size_t i = 0; i < arraysize(test_data); ++i) {
- const int str_len = strlen(test_data[i]);
- iov.Append(const_cast<char*>(test_data[i]), str_len);
- length += str_len;
- }
-
- int consumed = 0;
- std::unique_ptr<char[]> buffer(new char[length + 1]);
- EXPECT_DFATAL({ consumed = iov.ConsumeAndCopy(length + 1, buffer.get()); },
- "Attempting to consume 1 non-existent bytes.");
- ASSERT_EQ(length, consumed);
- const struct iovec* iov2 = iov.iovec();
- ASSERT_EQ(0u, iov.Size());
- ASSERT_TRUE(iov2 == nullptr);
- ASSERT_TRUE(iov.LastBlockEnd() == nullptr);
-}
-
-TEST(IOVectorTest, Clear) {
- IOVector iov;
- int length = 0;
-
- for (size_t i = 0; i < arraysize(test_data); ++i) {
- const int str_len = strlen(test_data[i]);
- iov.Append(const_cast<char*>(test_data[i]), str_len);
- length += str_len;
- }
- const struct iovec* iov2 = iov.iovec();
- ASSERT_TRUE(iov2 != nullptr);
- ASSERT_EQ(arraysize(test_data), static_cast<size_t>(iov.Size()));
-
- iov.Clear();
- iov2 = iov.iovec();
- ASSERT_EQ(0u, iov.Size());
- ASSERT_TRUE(iov2 == nullptr);
-}
-
-TEST(IOVectorTest, Capacity) {
- IOVector iov;
- // Note: IOVector merges adjacent Appends() into a single iov.
- // Therefore, if we expect final size of iov to be 3, we must insure
- // that the items we are appending are not adjacent. To achieve that
- // we use use an array (a[1] provides a buffer between a[0] and b[0],
- // and makes them non-adjacent).
- char a[2], b[2], c[2];
- iov.Append(&a[0], 1);
- iov.Append(&b[0], 1);
- iov.Append(&c[0], 1);
- ASSERT_EQ(3u, iov.Size());
- size_t capacity = iov.Capacity();
- EXPECT_LE(iov.Size(), capacity);
- iov.Consume(2);
- // The capacity should not have changed.
- EXPECT_EQ(capacity, iov.Capacity());
-}
-
-TEST(IOVectorTest, Swap) {
- IOVector iov1, iov2;
- // See IOVector merge comment above.
- char a[2], b[2], c[2], d[2], e[2];
- iov1.Append(&a[0], 1);
- iov1.Append(&b[0], 1);
-
- iov2.Append(&c[0], 1);
- iov2.Append(&d[0], 1);
- iov2.Append(&e[0], 1);
- iov1.Swap(&iov2);
-
- ASSERT_EQ(3u, iov1.Size());
- EXPECT_EQ(&c[0], iov1.iovec()[0].iov_base);
- EXPECT_EQ(1u, iov1.iovec()[0].iov_len);
- EXPECT_EQ(&d[0], iov1.iovec()[1].iov_base);
- EXPECT_EQ(1u, iov1.iovec()[1].iov_len);
- EXPECT_EQ(&e[0], iov1.iovec()[2].iov_base);
- EXPECT_EQ(1u, iov1.iovec()[2].iov_len);
-
- ASSERT_EQ(2u, iov2.Size());
- EXPECT_EQ(&a[0], iov2.iovec()[0].iov_base);
- EXPECT_EQ(1u, iov2.iovec()[0].iov_len);
- EXPECT_EQ(&b[0], iov2.iovec()[1].iov_base);
- EXPECT_EQ(1u, iov2.iovec()[1].iov_len);
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/network_connection.cc b/chromium/net/quic/network_connection.cc
deleted file mode 100644
index a105b9076da..00000000000
--- a/chromium/net/quic/network_connection.cc
+++ /dev/null
@@ -1,75 +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/network_connection.h"
-
-#include "net/base/network_interfaces.h"
-
-namespace net {
-
-NetworkConnection::NetworkConnection()
- : connection_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN),
- connection_description_(nullptr) {}
-
-const char* NetworkConnection::GetDescription() {
- NetworkChangeNotifier::ConnectionType type =
- NetworkChangeNotifier::GetConnectionType();
- if (connection_description_ != nullptr && type == connection_type_)
- return connection_description_;
-
- DVLOG(1) << "Updating NetworkConnection's Cached Data";
-
- connection_description_ = NetworkChangeNotifier::ConnectionTypeToString(type);
- connection_type_ = type;
- if (connection_type_ == NetworkChangeNotifier::CONNECTION_UNKNOWN ||
- connection_type_ == NetworkChangeNotifier::CONNECTION_WIFI) {
- // This function only seems usefully defined on Windows currently.
- WifiPHYLayerProtocol wifi_type = GetWifiPHYLayerProtocol();
- switch (wifi_type) {
- case WIFI_PHY_LAYER_PROTOCOL_NONE:
- // No wifi support or no associated AP.
- break;
- case WIFI_PHY_LAYER_PROTOCOL_ANCIENT:
- // An obsolete modes introduced by the original 802.11, e.g. IR, FHSS.
- connection_description_ = "CONNECTION_WIFI_ANCIENT";
- break;
- case WIFI_PHY_LAYER_PROTOCOL_A:
- // 802.11a, OFDM-based rates.
- connection_description_ = "CONNECTION_WIFI_802.11a";
- break;
- case WIFI_PHY_LAYER_PROTOCOL_B:
- // 802.11b, DSSS or HR DSSS.
- connection_description_ = "CONNECTION_WIFI_802.11b";
- break;
- case WIFI_PHY_LAYER_PROTOCOL_G:
- // 802.11g, same rates as 802.11a but compatible with 802.11b.
- connection_description_ = "CONNECTION_WIFI_802.11g";
- break;
- case WIFI_PHY_LAYER_PROTOCOL_N:
- // 802.11n, HT rates.
- connection_description_ = "CONNECTION_WIFI_802.11n";
- break;
- case WIFI_PHY_LAYER_PROTOCOL_UNKNOWN:
- // Unclassified mode or failure to identify.
- break;
- }
- }
- return connection_description_;
-}
-
-void NetworkConnection::Clear() {
- connection_type_ = NetworkChangeNotifier::CONNECTION_UNKNOWN;
- connection_description_ = nullptr;
-}
-
-void NetworkConnection::OnIPAddressChanged() {
- Clear();
-}
-
-void NetworkConnection::OnConnectionTypeChanged(
- NetworkChangeNotifier::ConnectionType type) {
- Clear();
-}
-
-} // namespace net
diff --git a/chromium/net/quic/network_connection_unittest.cc b/chromium/net/quic/network_connection_unittest.cc
deleted file mode 100644
index 33194d9241a..00000000000
--- a/chromium/net/quic/network_connection_unittest.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 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.
-
-#include "net/quic/network_connection.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-class NetworkConnectionPeer {
- public:
- static NetworkChangeNotifier::ConnectionType connection_type(
- const NetworkConnection& network_connection) {
- return network_connection.connection_type_;
- }
- static void set_connection_type(NetworkConnection* network_connection,
- NetworkChangeNotifier::ConnectionType type) {
- network_connection->connection_type_ = type;
- }
-
- static const char* connection_description(
- const NetworkConnection& network_connection) {
- return network_connection.connection_description_;
- }
- static void set_connection_description(NetworkConnection* network_connection,
- const char* description) {
- network_connection->connection_description_ = description;
- }
-};
-
-// Test NetworkConnection().
-class NetworkConnectionTest : public testing::Test {
- protected:
- void CheckNetworkConnectionDescription() {
- NetworkChangeNotifier::ConnectionType type =
- NetworkChangeNotifier::GetConnectionType();
- const char* description = network_connection_.GetDescription();
- // Verify GetDescription() updated the cached data.
- EXPECT_EQ(NetworkConnectionPeer::connection_type(network_connection_),
- type);
- EXPECT_EQ(
- NetworkConnectionPeer::connection_description(network_connection_),
- description);
-
- if (type != NetworkChangeNotifier::CONNECTION_WIFI)
- EXPECT_EQ(description,
- NetworkChangeNotifier::ConnectionTypeToString(type));
- else
- EXPECT_NE(nullptr, network_connection_.GetDescription());
- }
-
- NetworkConnection network_connection_;
-};
-
-TEST_F(NetworkConnectionTest, GetDescription) {
- const char* description = network_connection_.GetDescription();
-
- // Set connection description to nullptr.
- NetworkConnectionPeer::set_connection_description(&network_connection_,
- nullptr);
- CheckNetworkConnectionDescription();
-
- // Set connection type to a junk value.
- NetworkConnectionPeer::set_connection_type(
- &network_connection_, NetworkChangeNotifier::CONNECTION_LAST);
- CheckNetworkConnectionDescription();
-
- EXPECT_EQ(description, network_connection_.GetDescription());
-}
-
-TEST_F(NetworkConnectionTest, Clear) {
- CheckNetworkConnectionDescription();
- network_connection_.Clear();
- CheckNetworkConnectionDescription();
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/p2p/quic_p2p_crypto_config.cc b/chromium/net/quic/p2p/quic_p2p_crypto_config.cc
deleted file mode 100644
index 6f32056255e..00000000000
--- a/chromium/net/quic/p2p/quic_p2p_crypto_config.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 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.
-
-#include "net/quic/p2p/quic_p2p_crypto_config.h"
-
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/crypto_utils.h"
-
-namespace net {
-
-QuicP2PCryptoConfig::QuicP2PCryptoConfig(const std::string& shared_key)
- : shared_key_(shared_key) {}
-
-QuicP2PCryptoConfig::~QuicP2PCryptoConfig() {}
-
-bool QuicP2PCryptoConfig::GetNegotiatedParameters(
- Perspective perspective,
- QuicCryptoNegotiatedParameters* out_params) {
- out_params->forward_secure_premaster_secret = shared_key_;
- out_params->aead = aead_;
- out_params->hkdf_input_suffix = hkdf_input_suffix_;
-
- std::string hkdf_input;
- const size_t label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1;
- hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size());
- hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, label_len);
- hkdf_input.append(out_params->hkdf_input_suffix);
-
- if (!CryptoUtils::DeriveKeys(
- out_params->forward_secure_premaster_secret, out_params->aead,
- out_params->client_nonce, out_params->server_nonce, hkdf_input,
- perspective, CryptoUtils::Diversification::Never(),
- &out_params->forward_secure_crypters, &out_params->subkey_secret)) {
- return false;
- }
-
- return true;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/p2p/quic_p2p_crypto_config.h b/chromium/net/quic/p2p/quic_p2p_crypto_config.h
deleted file mode 100644
index 786a7e111c2..00000000000
--- a/chromium/net/quic/p2p/quic_p2p_crypto_config.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 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.
-
-#ifndef NET_QUIC_P2P_QUIC_P2P_CRYPTO_CONFIG_H_
-#define NET_QUIC_P2P_QUIC_P2P_CRYPTO_CONFIG_H_
-
-#include <string>
-
-#include "net/quic/crypto/crypto_protocol.h"
-
-namespace net {
-
-struct QuicCryptoNegotiatedParameters;
-
-// Crypto configuration for P2P sessions.
-class NET_EXPORT QuicP2PCryptoConfig {
- public:
- // |shared_key| specifies a key that's used to generate crypto keys. The key
- // must be exchanged out-of-bound when the P2P transport is negotiated.
- explicit QuicP2PCryptoConfig(const std::string& shared_key);
- ~QuicP2PCryptoConfig();
-
- void set_aead(QuicTag aead) { aead_ = aead; }
-
- // Sets suffix for HKDF. E.g. can be channel name to make sure different
- // channels use different encryption keys derived from the same |shared_key|.
- // Empty by default.
- void set_hkdf_input_suffix(const std::string& hkdf_input_suffix) {
- hkdf_input_suffix_ = hkdf_input_suffix;
- }
-
- bool GetNegotiatedParameters(Perspective perspective,
- QuicCryptoNegotiatedParameters* out_params);
-
- private:
- QuicTag aead_ = kAESG;
- std::string shared_key_;
- std::string hkdf_input_suffix_;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_P2P_QUIC_P2P_CRYPTO_CONFIG_H_
diff --git a/chromium/net/quic/p2p/quic_p2p_crypto_stream.cc b/chromium/net/quic/p2p/quic_p2p_crypto_stream.cc
deleted file mode 100644
index f5acb98b1b9..00000000000
--- a/chromium/net/quic/p2p/quic_p2p_crypto_stream.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 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.
-
-#include "net/quic/p2p/quic_p2p_crypto_stream.h"
-
-#include "crypto/hkdf.h"
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/quic_session.h"
-
-namespace net {
-
-QuicP2PCryptoStream::QuicP2PCryptoStream(QuicSession* session,
- const QuicP2PCryptoConfig& config)
- : QuicCryptoStream(session), config_(config) {}
-
-QuicP2PCryptoStream::~QuicP2PCryptoStream() {}
-
-bool QuicP2PCryptoStream::Connect() {
- if (!config_.GetNegotiatedParameters(session()->connection()->perspective(),
- &crypto_negotiated_params_)) {
- return false;
- }
-
- CrypterPair* crypters = &crypto_negotiated_params_.forward_secure_crypters;
-
- session()->connection()->SetEncrypter(ENCRYPTION_FORWARD_SECURE,
- crypters->encrypter.release());
- session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
- session()->connection()->SetAlternativeDecrypter(
- ENCRYPTION_FORWARD_SECURE, crypters->decrypter.release(),
- false /* don't latch */);
- encryption_established_ = true;
- session()->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
- session()->OnConfigNegotiated();
- session()->connection()->OnHandshakeComplete();
- handshake_confirmed_ = true;
- session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
- if (session()->connection()->perspective() == Perspective::IS_CLIENT) {
- // Send a ping from the client to the server to satisfy QUIC's version
- // negotiation.
- session()->connection()->SendPing();
- }
- return true;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/p2p/quic_p2p_crypto_stream.h b/chromium/net/quic/p2p/quic_p2p_crypto_stream.h
deleted file mode 100644
index 185a8f81437..00000000000
--- a/chromium/net/quic/p2p/quic_p2p_crypto_stream.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 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.
-
-#ifndef NET_QUIC_P2P_QUIC_P2P_CRYPTO_STREAM_H_
-#define NET_QUIC_P2P_QUIC_P2P_CRYPTO_STREAM_H_
-
-#include "base/macros.h"
-#include "net/quic/p2p/quic_p2p_crypto_config.h"
-#include "net/quic/quic_crypto_stream.h"
-
-namespace net {
-
-class QuicSession;
-
-class NET_EXPORT_PRIVATE QuicP2PCryptoStream : public QuicCryptoStream {
- public:
- QuicP2PCryptoStream(QuicSession* session, const QuicP2PCryptoConfig& config);
- ~QuicP2PCryptoStream() override;
-
- bool Connect();
-
- private:
- QuicP2PCryptoConfig config_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicP2PCryptoStream);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_P2P_QUIC_P2P_CRYPTO_STREAM_H_
diff --git a/chromium/net/quic/p2p/quic_p2p_session.cc b/chromium/net/quic/p2p/quic_p2p_session.cc
deleted file mode 100644
index 718c05e752e..00000000000
--- a/chromium/net/quic/p2p/quic_p2p_session.cc
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 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.
-
-#include "net/quic/p2p/quic_p2p_session.h"
-
-#include <utility>
-
-#include "base/callback_helpers.h"
-#include "net/base/io_buffer.h"
-#include "net/base/ip_address.h"
-#include "net/base/net_errors.h"
-#include "net/quic/p2p/quic_p2p_crypto_stream.h"
-#include "net/quic/quic_connection.h"
-#include "net/socket/socket.h"
-
-namespace net {
-
-QuicP2PSession::QuicP2PSession(const QuicConfig& config,
- const QuicP2PCryptoConfig& crypto_config,
- std::unique_ptr<QuicConnection> connection,
- std::unique_ptr<Socket> socket)
- : QuicSession(connection.release(), config),
- socket_(std::move(socket)),
- crypto_stream_(new QuicP2PCryptoStream(this, crypto_config)),
- read_buffer_(new IOBuffer(static_cast<size_t>(kMaxPacketSize))) {
- DCHECK(config.negotiated());
-}
-
-QuicP2PSession::~QuicP2PSession() {}
-
-void QuicP2PSession::Initialize() {
- QuicSession::Initialize();
- crypto_stream_->Connect();
- DoReadLoop(OK);
-}
-
-void QuicP2PSession::SetDelegate(Delegate* delegate) {
- delegate_ = delegate;
-}
-
-QuicCryptoStream* QuicP2PSession::GetCryptoStream() {
- return crypto_stream_.get();
-}
-
-QuicP2PStream* QuicP2PSession::CreateIncomingDynamicStream(QuicStreamId id) {
- QuicP2PStream* stream = new QuicP2PStream(id, this);
- if (delegate_) {
- delegate_->OnIncomingStream(stream);
- }
- ActivateStream(stream);
- return stream;
-}
-
-QuicP2PStream* QuicP2PSession::CreateOutgoingDynamicStream(
- SpdyPriority priority) {
- QuicP2PStream* stream = new QuicP2PStream(GetNextOutgoingStreamId(), this);
- if (stream) {
- ActivateStream(stream);
- }
- return stream;
-}
-
-void QuicP2PSession::OnConnectionClosed(QuicErrorCode error,
- const std::string& error_details,
- ConnectionCloseSource source) {
- QuicSession::OnConnectionClosed(error, error_details, source);
-
- socket_.reset();
-
- if (delegate_) {
- Delegate* delegate = delegate_;
- delegate_ = nullptr;
- delegate->OnConnectionClosed(error);
- }
-}
-
-void QuicP2PSession::DoReadLoop(int result) {
- while (error() == QUIC_NO_ERROR) {
- switch (read_state_) {
- case READ_STATE_DO_READ:
- CHECK_EQ(result, OK);
- result = DoRead();
- break;
- case READ_STATE_DO_READ_COMPLETE:
- result = DoReadComplete(result);
- break;
- default:
- NOTREACHED() << "read_state_: " << read_state_;
- break;
- }
-
- if (result < 0)
- break;
- }
-}
-
-int QuicP2PSession::DoRead() {
- DCHECK_EQ(read_state_, READ_STATE_DO_READ);
- read_state_ = READ_STATE_DO_READ_COMPLETE;
-
- if (!socket_) {
- return ERR_SOCKET_NOT_CONNECTED;
- }
-
- return socket_->Read(
- read_buffer_.get(), kMaxPacketSize,
- base::Bind(&QuicP2PSession::DoReadLoop, base::Unretained(this)));
-}
-
-int QuicP2PSession::DoReadComplete(int result) {
- DCHECK_EQ(read_state_, READ_STATE_DO_READ_COMPLETE);
- read_state_ = READ_STATE_DO_READ;
-
- if (result <= 0) {
- connection()->CloseConnection(QUIC_PACKET_READ_ERROR, "packet read error",
- ConnectionCloseBehavior::SILENT_CLOSE);
- return result;
- }
-
- QuicReceivedPacket packet(read_buffer_->data(), result, clock_.Now());
- connection()->ProcessUdpPacket(connection()->self_address(),
- connection()->peer_address(), packet);
- return OK;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/p2p/quic_p2p_session.h b/chromium/net/quic/p2p/quic_p2p_session.h
deleted file mode 100644
index a385c27cc72..00000000000
--- a/chromium/net/quic/p2p/quic_p2p_session.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 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.
-
-#ifndef NET_QUIC_P2P_QUIC_P2P_SESSION_H_
-#define NET_QUIC_P2P_QUIC_P2P_SESSION_H_
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "net/quic/p2p/quic_p2p_stream.h"
-#include "net/quic/quic_client_session_base.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-class QuicConfig;
-class QuicConnection;
-class QuicP2PCryptoStream;
-class QuicP2PCryptoConfig;
-class Socket;
-class IOBuffer;
-
-// QuicP2PSession represents a QUIC session over peer-to-peer transport
-// specified by |socket|. There is no handshake performed by this class, i.e.
-// the handshake is expected to happen out-of-bound before QuicP2PSession is
-// created. The out-of-bound handshake should generate the following parameters
-// passed to the constructor:
-// 1. Negotiated QuicConfig.
-// 2. Secret key exchanged with the peer on the other end of the |socket|.
-// This key is passed to the constructor as part of the |crypto_config|.
-class NET_EXPORT QuicP2PSession : public QuicSession {
- public:
- class Delegate {
- public:
- virtual void OnIncomingStream(QuicP2PStream* stream) = 0;
-
- virtual void OnConnectionClosed(QuicErrorCode error) = 0;
- };
-
- // |config| must be already negotiated. |crypto_config| contains a secret key
- // shared with the peer.
- QuicP2PSession(const QuicConfig& config,
- const QuicP2PCryptoConfig& crypto_config,
- std::unique_ptr<QuicConnection> connection,
- std::unique_ptr<Socket> socket);
- ~QuicP2PSession() override;
-
- // QuicSession overrides.
- void Initialize() override;
- QuicP2PStream* CreateOutgoingDynamicStream(
- net::SpdyPriority priority) override;
-
- // QuicConnectionVisitorInterface overrides.
- void OnConnectionClosed(QuicErrorCode error,
- const std::string& error_details,
- ConnectionCloseSource source) override;
-
- void SetDelegate(Delegate* delegate);
-
- protected:
- // QuicSession overrides.
- QuicCryptoStream* GetCryptoStream() override;
- QuicP2PStream* CreateIncomingDynamicStream(QuicStreamId id) override;
-
- QuicP2PSession* CreateDataStream(QuicStreamId id);
-
- private:
- enum ReadState {
- READ_STATE_DO_READ,
- READ_STATE_DO_READ_COMPLETE,
- };
-
- void DoReadLoop(int result);
- int DoRead();
- int DoReadComplete(int result);
-
- std::unique_ptr<Socket> socket_;
- std::unique_ptr<QuicP2PCryptoStream> crypto_stream_;
-
- Delegate* delegate_ = nullptr;
-
- ReadState read_state_ = READ_STATE_DO_READ;
- scoped_refptr<IOBuffer> read_buffer_;
-
- // For recording receipt time
- QuicClock clock_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicP2PSession);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_P2P_QUIC_P2P_SESSION_H_
diff --git a/chromium/net/quic/p2p/quic_p2p_session_test.cc b/chromium/net/quic/p2p/quic_p2p_session_test.cc
deleted file mode 100644
index 04f8ef46768..00000000000
--- a/chromium/net/quic/p2p/quic_p2p_session_test.cc
+++ /dev/null
@@ -1,405 +0,0 @@
-// Copyright 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.
-
-#include "net/quic/p2p/quic_p2p_session.h"
-
-#include <algorithm>
-#include <deque>
-#include <utility>
-#include <vector>
-
-#include "base/callback_helpers.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/p2p/quic_p2p_crypto_config.h"
-#include "net/quic/p2p/quic_p2p_stream.h"
-#include "net/quic/quic_chromium_alarm_factory.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_chromium_packet_writer.h"
-#include "net/quic/test_tools/quic_session_peer.h"
-#include "net/socket/socket.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-namespace {
-
-const char kTestSharedKey[] = "Shared key exchanged out of bound.";
-
-class FakeP2PDatagramSocket : public Socket {
- public:
- FakeP2PDatagramSocket() : weak_factory_(this) {}
- ~FakeP2PDatagramSocket() override {}
-
- base::WeakPtr<FakeP2PDatagramSocket> GetWeakPtr() {
- return weak_factory_.GetWeakPtr();
- }
-
- void ConnectWith(FakeP2PDatagramSocket* peer_socket) {
- peer_socket_ = peer_socket->GetWeakPtr();
- peer_socket->peer_socket_ = GetWeakPtr();
- }
-
- void SetReadError(int error) {
- read_error_ = error;
- if (!read_callback_.is_null()) {
- base::ResetAndReturn(&read_callback_).Run(error);
- }
- }
-
- void SetWriteError(int error) { write_error_ = error; }
-
- void AppendInputPacket(const std::vector<char>& data) {
- if (!read_callback_.is_null()) {
- int size = std::min(read_buffer_size_, static_cast<int>(data.size()));
- memcpy(read_buffer_->data(), &data[0], data.size());
- read_buffer_ = nullptr;
- base::ResetAndReturn(&read_callback_).Run(size);
- } else {
- incoming_packets_.push_back(data);
- }
- }
-
- // Socket interface.
- int Read(IOBuffer* buf,
- int buf_len,
- const CompletionCallback& callback) override {
- DCHECK(read_callback_.is_null());
-
- if (read_error_ != OK) {
- return read_error_;
- }
-
- if (!incoming_packets_.empty()) {
- scoped_refptr<IOBuffer> buffer(buf);
- int size =
- std::min(static_cast<int>(incoming_packets_.front().size()), buf_len);
- memcpy(buffer->data(), &*incoming_packets_.front().begin(), size);
- incoming_packets_.pop_front();
- return size;
- } else {
- read_callback_ = callback;
- read_buffer_ = buf;
- read_buffer_size_ = buf_len;
- return ERR_IO_PENDING;
- }
- }
-
- int Write(IOBuffer* buf,
- int buf_len,
- const CompletionCallback& callback) override {
- if (write_error_ != OK) {
- return write_error_;
- }
-
- if (peer_socket_) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&FakeP2PDatagramSocket::AppendInputPacket, peer_socket_,
- std::vector<char>(buf->data(), buf->data() + buf_len)));
- }
-
- return buf_len;
- }
-
- int SetReceiveBufferSize(int32_t size) override {
- NOTIMPLEMENTED();
- return ERR_NOT_IMPLEMENTED;
- }
- int SetSendBufferSize(int32_t size) override {
- NOTIMPLEMENTED();
- return ERR_NOT_IMPLEMENTED;
- }
-
- private:
- int read_error_ = OK;
- int write_error_ = OK;
-
- scoped_refptr<IOBuffer> read_buffer_;
- int read_buffer_size_;
- CompletionCallback read_callback_;
-
- std::deque<std::vector<char>> incoming_packets_;
-
- base::WeakPtr<FakeP2PDatagramSocket> peer_socket_;
-
- base::WeakPtrFactory<FakeP2PDatagramSocket> weak_factory_;
-};
-
-class TestP2PStreamDelegate : public QuicP2PStream::Delegate {
- public:
- TestP2PStreamDelegate() {}
- ~TestP2PStreamDelegate() override {}
-
- void OnDataReceived(const char* data, int length) override {
- received_data_.append(data, length);
- }
- void OnClose(QuicErrorCode error) override {
- is_closed_ = true;
- error_ = error;
- }
-
- const std::string& received_data() { return received_data_; }
- bool is_closed() { return is_closed_; }
- QuicErrorCode error() { return error_; }
-
- private:
- std::string received_data_;
- bool is_closed_ = false;
- QuicErrorCode error_ = QUIC_NO_ERROR;
-
- DISALLOW_COPY_AND_ASSIGN(TestP2PStreamDelegate);
-};
-
-class TestP2PSessionDelegate : public QuicP2PSession::Delegate {
- public:
- void OnIncomingStream(QuicP2PStream* stream) override {
- last_incoming_stream_ = stream;
- stream->SetDelegate(next_incoming_stream_delegate_);
- next_incoming_stream_delegate_ = nullptr;
- if (!on_incoming_stream_callback_.is_null())
- base::ResetAndReturn(&on_incoming_stream_callback_).Run();
- }
-
- void OnConnectionClosed(QuicErrorCode error) override {
- is_closed_ = true;
- error_ = error;
- }
-
- void set_next_incoming_stream_delegate(QuicP2PStream::Delegate* delegate) {
- next_incoming_stream_delegate_ = delegate;
- }
- void set_on_incoming_stream_callback(const base::Closure& callback) {
- on_incoming_stream_callback_ = callback;
- }
- QuicP2PStream* last_incoming_stream() { return last_incoming_stream_; }
- bool is_closed() { return is_closed_; }
- QuicErrorCode error() { return error_; }
-
- private:
- QuicP2PStream::Delegate* next_incoming_stream_delegate_ = nullptr;
- base::Closure on_incoming_stream_callback_;
- QuicP2PStream* last_incoming_stream_ = nullptr;
- bool is_closed_ = false;
- QuicErrorCode error_ = QUIC_NO_ERROR;
-};
-
-} // namespace
-
-class QuicP2PSessionTest : public ::testing::Test {
- public:
- void OnWriteResult(int result);
-
- protected:
- QuicP2PSessionTest()
- : quic_helper_(&quic_clock_, QuicRandom::GetInstance()),
- alarm_factory_(base::ThreadTaskRunnerHandle::Get().get(),
- &quic_clock_) {
- // Simulate out-of-bound config handshake.
- CryptoHandshakeMessage hello_message;
- config_.ToHandshakeMessage(&hello_message);
- std::string error_detail;
- EXPECT_EQ(QUIC_NO_ERROR,
- config_.ProcessPeerHello(hello_message, CLIENT, &error_detail));
- }
-
- void CreateSessions() {
- std::unique_ptr<FakeP2PDatagramSocket> socket1(new FakeP2PDatagramSocket());
- std::unique_ptr<FakeP2PDatagramSocket> socket2(new FakeP2PDatagramSocket());
- socket1->ConnectWith(socket2.get());
-
- socket1_ = socket1->GetWeakPtr();
- socket2_ = socket2->GetWeakPtr();
-
- QuicP2PCryptoConfig crypto_config(kTestSharedKey);
-
- session1_ = CreateP2PSession(std::move(socket1), crypto_config,
- Perspective::IS_SERVER);
- session2_ = CreateP2PSession(std::move(socket2), crypto_config,
- Perspective::IS_CLIENT);
- }
-
- std::unique_ptr<QuicP2PSession> CreateP2PSession(
- std::unique_ptr<Socket> socket,
- QuicP2PCryptoConfig crypto_config,
- Perspective perspective) {
- QuicChromiumPacketWriter* writer =
- new QuicChromiumPacketWriter(socket.get());
- std::unique_ptr<QuicConnection> quic_connection1(new QuicConnection(
- 0, IPEndPoint(IPAddress::IPv4AllZeros(), 0), &quic_helper_,
- &alarm_factory_, writer, true /* owns_writer */, perspective,
- QuicSupportedVersions()));
- writer->SetConnection(quic_connection1.get());
-
- std::unique_ptr<QuicP2PSession> result(
- new QuicP2PSession(config_, crypto_config, std::move(quic_connection1),
- std::move(socket)));
- result->Initialize();
- return result;
- }
-
- void TestStreamConnection(QuicP2PSession* from_session,
- QuicP2PSession* to_session,
- QuicStreamId expected_stream_id);
-
- QuicClock quic_clock_;
- QuicChromiumConnectionHelper quic_helper_;
- QuicChromiumAlarmFactory alarm_factory_;
- QuicConfig config_;
-
- base::WeakPtr<FakeP2PDatagramSocket> socket1_;
- std::unique_ptr<QuicP2PSession> session1_;
-
- base::WeakPtr<FakeP2PDatagramSocket> socket2_;
- std::unique_ptr<QuicP2PSession> session2_;
-};
-
-void QuicP2PSessionTest::OnWriteResult(int result) {
- EXPECT_EQ(OK, result);
-}
-
-void QuicP2PSessionTest::TestStreamConnection(QuicP2PSession* from_session,
- QuicP2PSession* to_session,
- QuicStreamId expected_stream_id) {
- QuicP2PStream* outgoing_stream =
- from_session->CreateOutgoingDynamicStream(kDefaultPriority);
- EXPECT_TRUE(outgoing_stream);
- TestP2PStreamDelegate outgoing_stream_delegate;
- outgoing_stream->SetDelegate(&outgoing_stream_delegate);
- EXPECT_EQ(expected_stream_id, outgoing_stream->id());
-
- // Add streams to write_blocked_lists of both QuicSession objects.
- QuicWriteBlockedList* write_blocked_list1 =
- test::QuicSessionPeer::GetWriteBlockedStreams(from_session);
- write_blocked_list1->RegisterStream(expected_stream_id, kV3HighestPriority);
- QuicWriteBlockedList* write_blocked_list2 =
- test::QuicSessionPeer::GetWriteBlockedStreams(to_session);
- write_blocked_list2->RegisterStream(expected_stream_id, kV3HighestPriority);
-
- // Send a test message to the client.
- const char kTestMessage[] = "Hi";
- const char kTestResponse[] = "Response";
- outgoing_stream->Write(
- std::string(kTestMessage),
- base::Bind(&QuicP2PSessionTest::OnWriteResult, base::Unretained(this)));
-
- // Wait for the incoming stream to be created.
- TestP2PStreamDelegate incoming_stream_delegate;
- base::RunLoop run_loop;
- TestP2PSessionDelegate session_delegate;
- session_delegate.set_next_incoming_stream_delegate(&incoming_stream_delegate);
- session_delegate.set_on_incoming_stream_callback(
- base::Bind(&base::RunLoop::Quit, base::Unretained(&run_loop)));
- to_session->SetDelegate(&session_delegate);
- run_loop.Run();
- to_session->SetDelegate(nullptr);
-
- QuicP2PStream* incoming_stream = session_delegate.last_incoming_stream();
- ASSERT_TRUE(incoming_stream);
- EXPECT_EQ(expected_stream_id, incoming_stream->id());
- EXPECT_EQ(kTestMessage, incoming_stream_delegate.received_data());
-
- incoming_stream->Write(
- std::string(kTestResponse),
- base::Bind(&QuicP2PSessionTest::OnWriteResult, base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(kTestResponse, outgoing_stream_delegate.received_data());
-
- from_session->CloseStream(outgoing_stream->id());
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(outgoing_stream_delegate.is_closed());
- EXPECT_TRUE(incoming_stream_delegate.is_closed());
-}
-
-TEST_F(QuicP2PSessionTest, ClientToServer) {
- CreateSessions();
- TestStreamConnection(session2_.get(), session1_.get(), 3);
-}
-
-TEST_F(QuicP2PSessionTest, ServerToClient) {
- CreateSessions();
- TestStreamConnection(session1_.get(), session2_.get(), 2);
-}
-
-TEST_F(QuicP2PSessionTest, DestroySocketWhenClosed) {
- CreateSessions();
-
- // The socket must be destroyed when connection is closed.
- EXPECT_TRUE(socket1_);
- session1_->connection()->CloseConnection(
- QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
- EXPECT_FALSE(socket1_);
-}
-
-TEST_F(QuicP2PSessionTest, TransportWriteError) {
- CreateSessions();
-
- TestP2PSessionDelegate session_delegate;
- session1_->SetDelegate(&session_delegate);
-
- QuicP2PStream* stream =
- session1_->CreateOutgoingDynamicStream(kDefaultPriority);
- EXPECT_TRUE(stream);
- TestP2PStreamDelegate stream_delegate;
- stream->SetDelegate(&stream_delegate);
- EXPECT_EQ(2U, stream->id());
-
- // Add stream to write_blocked_list.
- QuicWriteBlockedList* write_blocked_list =
- test::QuicSessionPeer::GetWriteBlockedStreams(session1_.get());
- write_blocked_list->RegisterStream(stream->id(), kV3HighestPriority);
-
- socket1_->SetWriteError(ERR_INTERNET_DISCONNECTED);
-
- const char kTestMessage[] = "Hi";
- stream->Write(
- std::string(kTestMessage),
- base::Bind(&QuicP2PSessionTest::OnWriteResult, base::Unretained(this)));
-
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(stream_delegate.is_closed());
- EXPECT_EQ(QUIC_PACKET_WRITE_ERROR, stream_delegate.error());
- EXPECT_TRUE(session_delegate.is_closed());
- EXPECT_EQ(QUIC_PACKET_WRITE_ERROR, session_delegate.error());
-
- // Verify that the socket was destroyed.
- EXPECT_FALSE(socket1_);
-}
-
-TEST_F(QuicP2PSessionTest, TransportReceiveError) {
- CreateSessions();
-
- TestP2PSessionDelegate session_delegate;
- session1_->SetDelegate(&session_delegate);
-
- QuicP2PStream* stream =
- session1_->CreateOutgoingDynamicStream(kDefaultPriority);
- EXPECT_TRUE(stream);
- TestP2PStreamDelegate stream_delegate;
- stream->SetDelegate(&stream_delegate);
- EXPECT_EQ(2U, stream->id());
-
- socket1_->SetReadError(ERR_INTERNET_DISCONNECTED);
-
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(stream_delegate.is_closed());
- EXPECT_EQ(QUIC_PACKET_READ_ERROR, stream_delegate.error());
- EXPECT_TRUE(session_delegate.is_closed());
- EXPECT_EQ(QUIC_PACKET_READ_ERROR, session_delegate.error());
-
- // Verify that the socket was destroyed.
- EXPECT_FALSE(socket1_);
-}
-
-} // namespace net
diff --git a/chromium/net/quic/p2p/quic_p2p_stream.cc b/chromium/net/quic/p2p/quic_p2p_stream.cc
deleted file mode 100644
index da01019674b..00000000000
--- a/chromium/net/quic/p2p/quic_p2p_stream.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 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.
-
-#include "net/quic/p2p/quic_p2p_stream.h"
-
-#include "base/callback_helpers.h"
-#include "net/base/net_errors.h"
-#include "net/quic/quic_session.h"
-#include "net/quic/quic_write_blocked_list.h"
-
-namespace net {
-
-QuicP2PStream::QuicP2PStream(QuicStreamId id, QuicSession* session)
- : ReliableQuicStream(id, session) {}
-
-QuicP2PStream::~QuicP2PStream() {}
-
-void QuicP2PStream::OnDataAvailable() {
- DCHECK(delegate_);
-
- struct iovec iov;
- while (true) {
- if (sequencer()->GetReadableRegions(&iov, 1) != 1) {
- // No more data to read.
- break;
- }
- delegate_->OnDataReceived(reinterpret_cast<const char*>(iov.iov_base),
- iov.iov_len);
- sequencer()->MarkConsumed(iov.iov_len);
- }
-}
-
-void QuicP2PStream::OnClose() {
- ReliableQuicStream::OnClose();
-
- if (delegate_) {
- Delegate* delegate = delegate_;
- delegate_ = nullptr;
- delegate->OnClose(connection_error());
- }
-}
-
-void QuicP2PStream::OnCanWrite() {
- ReliableQuicStream::OnCanWrite();
-
- if (!HasBufferedData() && !write_callback_.is_null()) {
- base::ResetAndReturn(&write_callback_).Run(last_write_size_);
- }
-}
-
-void QuicP2PStream::WriteHeader(base::StringPiece data) {
- WriteOrBufferData(data, false, nullptr);
-}
-
-int QuicP2PStream::Write(base::StringPiece data,
- const CompletionCallback& callback) {
- DCHECK(write_callback_.is_null());
-
- // Writes the data, or buffers it.
- WriteOrBufferData(data, false, nullptr);
- if (!HasBufferedData()) {
- return data.size();
- }
-
- write_callback_ = callback;
- last_write_size_ = data.size();
- return ERR_IO_PENDING;
-}
-
-void QuicP2PStream::SetDelegate(QuicP2PStream::Delegate* delegate) {
- DCHECK(!(delegate_ && delegate));
- delegate_ = delegate;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/p2p/quic_p2p_stream.h b/chromium/net/quic/p2p/quic_p2p_stream.h
deleted file mode 100644
index 4e456b20d3a..00000000000
--- a/chromium/net/quic/p2p/quic_p2p_stream.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 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.
-
-#ifndef NET_QUIC_P2P_QUIC_P2P_STREAM_H_
-#define NET_QUIC_P2P_QUIC_P2P_STREAM_H_
-
-#include "base/macros.h"
-#include "net/base/completion_callback.h"
-#include "net/base/net_export.h"
-#include "net/quic/reliable_quic_stream.h"
-
-namespace net {
-
-// Streams created by QuicP2PSession.
-class NET_EXPORT QuicP2PStream : public ReliableQuicStream {
- public:
- // Delegate handles protocol specific behavior of a quic stream.
- class NET_EXPORT Delegate {
- public:
- Delegate() {}
-
- // Called when data is received.
- virtual void OnDataReceived(const char* data, int length) = 0;
-
- // Called when the stream is closed by the peer.
- virtual void OnClose(QuicErrorCode error) = 0;
-
- protected:
- virtual ~Delegate() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Delegate);
- };
-
- QuicP2PStream(QuicStreamId id, QuicSession* session);
-
- ~QuicP2PStream() override;
-
- // ReliableQuicStream overrides.
- void OnDataAvailable() override;
- void OnClose() override;
- void OnCanWrite() override;
-
- void WriteHeader(base::StringPiece data);
-
- int Write(base::StringPiece data, const CompletionCallback& callback);
-
- void SetDelegate(Delegate* delegate);
- Delegate* GetDelegate() { return delegate_; }
-
- private:
- Delegate* delegate_ = nullptr;
-
- CompletionCallback write_callback_;
- int last_write_size_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(QuicP2PStream);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_P2P_QUIC_P2P_STREAM_H_
diff --git a/chromium/net/quic/port_suggester.cc b/chromium/net/quic/port_suggester.cc
deleted file mode 100644
index a15fcf0d3b4..00000000000
--- a/chromium/net/quic/port_suggester.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2013 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/port_suggester.h"
-
-#include "base/logging.h"
-
-namespace net {
-
-PortSuggester::PortSuggester(const HostPortPair& server, uint64_t seed)
- : call_count_(0), previous_suggestion_(-1) {
- unsigned char hash_bytes[base::kSHA1Length];
- base::SHA1HashBytes(
- reinterpret_cast<const unsigned char*>(server.host().data()),
- server.host().length(), hash_bytes);
- static_assert(sizeof(seed_) < sizeof(hash_bytes), "seed larger than hash");
- memcpy(&seed_, hash_bytes, sizeof(seed_));
- seed_ ^= seed ^ server.port();
-}
-
-int PortSuggester::SuggestPort(int min, int max) {
- // Sometimes our suggestion can't be used, so we ensure that if additional
- // calls are made, then each call (probably) provides a new suggestion.
- if (++call_count_ > 1) {
- // Evolve the seed.
- unsigned char hash_bytes[base::kSHA1Length];
- base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(&seed_),
- sizeof(seed_), hash_bytes);
- memcpy(&seed_, hash_bytes, sizeof(seed_));
- }
- DCHECK_LE(min, max);
- DCHECK_GT(min, 0);
- int range = max - min + 1;
- // Ports (and hence the extent of the |range|) are generally under 2^16, so
- // the tiny non-uniformity in the pseudo-random distribution is not
- // significant.
- previous_suggestion_ = static_cast<int>(seed_ % range) + min;
- return previous_suggestion_;
-}
-
-int PortSuggester::previous_suggestion() const {
- DCHECK_LT(0u, call_count_);
- return previous_suggestion_;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/port_suggester_unittest.cc b/chromium/net/quic/port_suggester_unittest.cc
deleted file mode 100644
index 3c486197696..00000000000
--- a/chromium/net/quic/port_suggester_unittest.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2013 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/port_suggester.h"
-
-#include <set>
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-class PortSuggesterTest : public ::testing::Test {
- protected:
- PortSuggesterTest()
- : entropy_(1345689),
- min_ephemeral_port_(1025),
- max_ephemeral_port_(65535) {}
-
- uint64_t entropy_;
- int min_ephemeral_port_;
- int max_ephemeral_port_;
-};
-
-TEST_F(PortSuggesterTest, SmallRangeTest) {
- // When the range is small (one wide), we always get that as our answer.
- scoped_refptr<PortSuggester> port_suggester =
- new PortSuggester(HostPortPair("www.example.com", 443), entropy_);
- // Test this for a few different (small) ranges.
- for (int port = 2000; port < 2010; ++port) {
- // Use |port| for both |min| and |max| delimiting the suggestion range.
- EXPECT_EQ(port, port_suggester->SuggestPort(port, port));
- EXPECT_EQ(port, port_suggester->previous_suggestion());
- }
-}
-
-TEST_F(PortSuggesterTest, SuggestAllPorts) {
- // We should eventually fill out any range, but we'll just ensure that we
- // fill out a small range of ports.
- scoped_refptr<PortSuggester> port_suggester =
- new PortSuggester(HostPortPair("www.example.com", 443), entropy_);
- std::set<int> ports;
- const uint32_t port_range = 20;
- const int insertion_limit = 200; // We should be done by then.
- for (int i = 0; i < insertion_limit; ++i) {
- ports.insert(port_suggester->SuggestPort(
- min_ephemeral_port_, min_ephemeral_port_ + port_range - 1));
- if (ports.size() == port_range) {
- break;
- }
- }
- EXPECT_EQ(port_range, ports.size());
-}
-
-TEST_F(PortSuggesterTest, AvoidDuplication) {
- // When the range is large, duplicates are rare, but we'll ask for a few
- // suggestions and make sure they are unique.
- scoped_refptr<PortSuggester> port_suggester =
- new PortSuggester(HostPortPair("www.example.com", 80), entropy_);
- std::set<int> ports;
- const size_t port_count = 200;
- for (size_t i = 0; i < port_count; ++i) {
- ports.insert(
- port_suggester->SuggestPort(min_ephemeral_port_, max_ephemeral_port_));
- }
- EXPECT_EQ(port_suggester->call_count(), port_count);
- EXPECT_EQ(port_count, ports.size());
-}
-
-TEST_F(PortSuggesterTest, ConsistentPorts) {
- // For given hostname, port, and entropy, we should always get the same
- // suggestions.
- scoped_refptr<PortSuggester> port_suggester1 =
- new PortSuggester(HostPortPair("www.example.com", 443), entropy_);
- scoped_refptr<PortSuggester> port_suggester2 =
- new PortSuggester(HostPortPair("www.example.com", 443), entropy_);
- for (int test_count = 20; test_count > 0; --test_count) {
- EXPECT_EQ(
- port_suggester1->SuggestPort(min_ephemeral_port_, min_ephemeral_port_),
- port_suggester2->SuggestPort(min_ephemeral_port_, min_ephemeral_port_));
- }
-}
-
-TEST_F(PortSuggesterTest, DifferentHostPortEntropy) {
- // When we have different hosts, port, or entropy, we probably won't collide.
- scoped_refptr<PortSuggester> port_suggester[] = {
- new PortSuggester(HostPortPair("www.example.com", 80), entropy_),
- new PortSuggester(HostPortPair("www.example.ORG", 80), entropy_),
- new PortSuggester(HostPortPair("www.example.com", 443), entropy_),
- new PortSuggester(HostPortPair("www.example.com", 80), entropy_ + 123456),
- };
-
- std::set<int> ports;
- const int port_count = 40;
- size_t insertion_count = 0;
- for (size_t j = 0; j < arraysize(port_suggester); ++j) {
- for (int i = 0; i < port_count; ++i) {
- ports.insert(port_suggester[j]->SuggestPort(min_ephemeral_port_,
- max_ephemeral_port_));
- ++insertion_count;
- }
- }
- EXPECT_EQ(insertion_count, ports.size());
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_address_mismatch.cc b/chromium/net/quic/quic_address_mismatch.cc
deleted file mode 100644
index 9a26c26521b..00000000000
--- a/chromium/net/quic/quic_address_mismatch.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_address_mismatch.h"
-
-#include "base/logging.h"
-#include "net/base/ip_address.h"
-
-namespace net {
-
-int GetAddressMismatch(const IPEndPoint& first_address,
- const IPEndPoint& second_address) {
- if (first_address.address().empty() || second_address.address().empty()) {
- return -1;
- }
- IPAddress first_ip_address = first_address.address();
- if (first_ip_address.IsIPv4MappedIPv6()) {
- first_ip_address = ConvertIPv4MappedIPv6ToIPv4(first_ip_address);
- }
- IPAddress second_ip_address = second_address.address();
- if (second_ip_address.IsIPv4MappedIPv6()) {
- second_ip_address = ConvertIPv4MappedIPv6ToIPv4(second_ip_address);
- }
-
- int sample;
- if (first_ip_address != second_ip_address) {
- sample = QUIC_ADDRESS_MISMATCH_BASE;
- } else if (first_address.port() != second_address.port()) {
- sample = QUIC_PORT_MISMATCH_BASE;
- } else {
- sample = QUIC_ADDRESS_AND_PORT_MATCH_BASE;
- }
-
- // Add an offset to |sample|:
- // V4_V4: add 0
- // V6_V6: add 1
- // V4_V6: add 2
- // V6_V4: add 3
- bool first_ipv4 = first_ip_address.IsIPv4();
- if (first_ipv4 != second_ip_address.IsIPv4()) {
- CHECK_EQ(sample, QUIC_ADDRESS_MISMATCH_BASE);
- sample += 2;
- }
- if (!first_ipv4) {
- sample += 1;
- }
- return sample;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_address_mismatch_test.cc b/chromium/net/quic/quic_address_mismatch_test.cc
deleted file mode 100644
index 5c6d5874e2e..00000000000
--- a/chromium/net/quic/quic_address_mismatch_test.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_address_mismatch.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-// Test all cases of the GetAddressMismatch function.
-TEST(QuicAddressMismatchTest, GetAddressMismatch) {
- IPAddress ip4_1;
- IPAddress ip4_2;
- IPAddress ip6_1;
- IPAddress ip6_2;
- IPAddress ip4_mapped_1;
- IPAddress ip4_mapped_2;
- ASSERT_TRUE(ip4_1.AssignFromIPLiteral("1.2.3.4"));
- ASSERT_TRUE(ip4_2.AssignFromIPLiteral("5.6.7.8"));
- ASSERT_TRUE(ip6_1.AssignFromIPLiteral("1234::1"));
- ASSERT_TRUE(ip6_2.AssignFromIPLiteral("1234::2"));
- ip4_mapped_1 = ConvertIPv4ToIPv4MappedIPv6(ip4_1);
- ip4_mapped_2 = ConvertIPv4ToIPv4MappedIPv6(ip4_2);
- ASSERT_NE(ip4_1, ip4_2);
- ASSERT_NE(ip6_1, ip6_2);
- ASSERT_NE(ip4_mapped_1, ip4_mapped_2);
-
- EXPECT_EQ(-1, GetAddressMismatch(IPEndPoint(), IPEndPoint()));
- EXPECT_EQ(-1, GetAddressMismatch(IPEndPoint(), IPEndPoint(ip4_1, 443)));
- EXPECT_EQ(-1, GetAddressMismatch(IPEndPoint(ip4_1, 443), IPEndPoint()));
-
- EXPECT_EQ(QUIC_ADDRESS_AND_PORT_MATCH_V4_V4,
- GetAddressMismatch(IPEndPoint(ip4_1, 443), IPEndPoint(ip4_1, 443)));
- EXPECT_EQ(QUIC_ADDRESS_AND_PORT_MATCH_V4_V4,
- GetAddressMismatch(IPEndPoint(ip4_1, 443),
- IPEndPoint(ip4_mapped_1, 443)));
- EXPECT_EQ(QUIC_ADDRESS_AND_PORT_MATCH_V4_V4,
- GetAddressMismatch(IPEndPoint(ip4_mapped_1, 443),
- IPEndPoint(ip4_mapped_1, 443)));
- EXPECT_EQ(QUIC_ADDRESS_AND_PORT_MATCH_V6_V6,
- GetAddressMismatch(IPEndPoint(ip6_1, 443), IPEndPoint(ip6_1, 443)));
-
- EXPECT_EQ(QUIC_PORT_MISMATCH_V4_V4,
- GetAddressMismatch(IPEndPoint(ip4_1, 80), IPEndPoint(ip4_1, 443)));
- EXPECT_EQ(
- QUIC_PORT_MISMATCH_V4_V4,
- GetAddressMismatch(IPEndPoint(ip4_1, 80), IPEndPoint(ip4_mapped_1, 443)));
- EXPECT_EQ(QUIC_PORT_MISMATCH_V4_V4,
- GetAddressMismatch(IPEndPoint(ip4_mapped_1, 80),
- IPEndPoint(ip4_mapped_1, 443)));
- EXPECT_EQ(QUIC_PORT_MISMATCH_V6_V6,
- GetAddressMismatch(IPEndPoint(ip6_1, 80), IPEndPoint(ip6_1, 443)));
-
- EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V4,
- GetAddressMismatch(IPEndPoint(ip4_1, 443), IPEndPoint(ip4_2, 443)));
- EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V4,
- GetAddressMismatch(IPEndPoint(ip4_1, 443),
- IPEndPoint(ip4_mapped_2, 443)));
- EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V4,
- GetAddressMismatch(IPEndPoint(ip4_mapped_1, 443),
- IPEndPoint(ip4_mapped_2, 443)));
- EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V4,
- GetAddressMismatch(IPEndPoint(ip4_1, 80), IPEndPoint(ip4_2, 443)));
- EXPECT_EQ(
- QUIC_ADDRESS_MISMATCH_V4_V4,
- GetAddressMismatch(IPEndPoint(ip4_1, 80), IPEndPoint(ip4_mapped_2, 443)));
- EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V4,
- GetAddressMismatch(IPEndPoint(ip4_mapped_1, 80),
- IPEndPoint(ip4_mapped_2, 443)));
- EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V6_V6,
- GetAddressMismatch(IPEndPoint(ip6_1, 443), IPEndPoint(ip6_2, 443)));
- EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V6_V6,
- GetAddressMismatch(IPEndPoint(ip6_1, 80), IPEndPoint(ip6_2, 443)));
- EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V6,
- GetAddressMismatch(IPEndPoint(ip4_1, 443), IPEndPoint(ip6_1, 443)));
- EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V6,
- GetAddressMismatch(IPEndPoint(ip4_mapped_1, 443),
- IPEndPoint(ip6_1, 443)));
- EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V4_V6,
- GetAddressMismatch(IPEndPoint(ip4_1, 80), IPEndPoint(ip6_1, 443)));
- EXPECT_EQ(
- QUIC_ADDRESS_MISMATCH_V4_V6,
- GetAddressMismatch(IPEndPoint(ip4_mapped_1, 80), IPEndPoint(ip6_1, 443)));
- EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V6_V4,
- GetAddressMismatch(IPEndPoint(ip6_1, 443), IPEndPoint(ip4_1, 443)));
- EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V6_V4,
- GetAddressMismatch(IPEndPoint(ip6_1, 443),
- IPEndPoint(ip4_mapped_1, 443)));
- EXPECT_EQ(QUIC_ADDRESS_MISMATCH_V6_V4,
- GetAddressMismatch(IPEndPoint(ip6_1, 80), IPEndPoint(ip4_1, 443)));
- EXPECT_EQ(
- QUIC_ADDRESS_MISMATCH_V6_V4,
- GetAddressMismatch(IPEndPoint(ip6_1, 80), IPEndPoint(ip4_mapped_1, 443)));
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_alarm.cc b/chromium/net/quic/quic_alarm.cc
deleted file mode 100644
index 30edcaa4423..00000000000
--- a/chromium/net/quic/quic_alarm.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_alarm.h"
-
-#include "base/logging.h"
-#include "net/quic/quic_flags.h"
-
-namespace net {
-
-QuicAlarm::QuicAlarm(QuicArenaScopedPtr<Delegate> delegate)
- : delegate_(std::move(delegate)), deadline_(QuicTime::Zero()) {}
-
-QuicAlarm::~QuicAlarm() {}
-
-void QuicAlarm::Set(QuicTime new_deadline) {
- DCHECK(!IsSet());
- DCHECK(new_deadline.IsInitialized());
- deadline_ = new_deadline;
- SetImpl();
-}
-
-void QuicAlarm::Cancel() {
- if (!IsSet()) {
- // Don't try to cancel an alarm that hasn't been set.
- return;
- }
- deadline_ = QuicTime::Zero();
- CancelImpl();
-}
-
-void QuicAlarm::Update(QuicTime new_deadline, QuicTime::Delta granularity) {
- if (!new_deadline.IsInitialized()) {
- Cancel();
- return;
- }
- if (std::abs(new_deadline.Subtract(deadline_).ToMicroseconds()) <
- granularity.ToMicroseconds()) {
- return;
- }
- Cancel();
- Set(new_deadline);
-}
-
-bool QuicAlarm::IsSet() const {
- return deadline_.IsInitialized();
-}
-
-void QuicAlarm::Fire() {
- if (!IsSet()) {
- return;
- }
-
- deadline_ = QuicTime::Zero();
- delegate_->OnAlarm();
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_alarm.h b/chromium/net/quic/quic_alarm.h
deleted file mode 100644
index ed492cfeb00..00000000000
--- a/chromium/net/quic/quic_alarm.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_ALARM_H_
-#define NET_QUIC_QUIC_ALARM_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_arena_scoped_ptr.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-// Abstract class which represents an alarm which will go off at a
-// scheduled time, and execute the |OnAlarm| method of the delegate.
-// An alarm may be cancelled, in which case it may or may not be
-// removed from the underlying scheduling system, but in either case
-// the task will not be executed.
-class NET_EXPORT_PRIVATE QuicAlarm {
- public:
- class NET_EXPORT_PRIVATE Delegate {
- public:
- virtual ~Delegate() {}
-
- // Invoked when the alarm fires.
- virtual void OnAlarm() = 0;
- };
-
- explicit QuicAlarm(QuicArenaScopedPtr<Delegate> delegate);
- virtual ~QuicAlarm();
-
- // Sets the alarm to fire at |deadline|. Must not be called while
- // the alarm is set. To reschedule an alarm, call Cancel() first,
- // then Set().
- void Set(QuicTime new_deadline);
-
- // Cancels the alarm. May be called repeatedly. Does not
- // guarantee that the underlying scheduling system will remove
- // the alarm's associated task, but guarantees that the
- // delegates OnAlarm method will not be called.
- void Cancel();
-
- // Cancels and sets the alarm if the |deadline| is farther from the current
- // deadline than |granularity|, and otherwise does nothing. If |deadline| is
- // not initialized, the alarm is cancelled.
- void Update(QuicTime new_deadline, QuicTime::Delta granularity);
-
- // Returns true if |deadline_| has been set to a non-zero time.
- bool IsSet() const;
-
- QuicTime deadline() const { return deadline_; }
-
- protected:
- // Subclasses implement this method to perform the platform-specific
- // scheduling of the alarm. Is called from Set() or Fire(), after the
- // deadline has been updated.
- virtual void SetImpl() = 0;
-
- // Subclasses implement this method to perform the platform-specific
- // cancelation of the alarm.
- virtual void CancelImpl() = 0;
-
- // Called by subclasses when the alarm fires. Invokes the
- // delegates |OnAlarm| if a delegate is set, and if the deadline
- // has been exceeded. Implementations which do not remove the
- // alarm from the underlying scheduler on Cancel() may need to handle
- // the situation where the task executes before the deadline has been
- // reached, in which case they need to reschedule the task and must not
- // call invoke this method.
- void Fire();
-
- private:
- QuicArenaScopedPtr<Delegate> delegate_;
- QuicTime deadline_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicAlarm);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_ALARM_H_
diff --git a/chromium/net/quic/quic_alarm_factory.h b/chromium/net/quic/quic_alarm_factory.h
deleted file mode 100644
index 237f2a27eb2..00000000000
--- a/chromium/net/quic/quic_alarm_factory.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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.
-
-#ifndef NET_QUIC_QUIC_ALARM_FACTORY_H_
-#define NET_QUIC_QUIC_ALARM_FACTORY_H_
-
-#include "net/base/net_export.h"
-#include "net/quic/quic_alarm.h"
-#include "net/quic/quic_one_block_arena.h"
-
-namespace net {
-
-// QuicConnections currently use around 1KB of polymorphic types which would
-// ordinarily be on the heap. Instead, store them inline in an arena.
-using QuicConnectionArena = QuicOneBlockArena<1024>;
-
-// Creates platform-specific alarms used throughout QUIC.
-class NET_EXPORT_PRIVATE QuicAlarmFactory {
- public:
- virtual ~QuicAlarmFactory() {}
-
- // Creates a new platform-specific alarm which will be configured to notify
- // |delegate| when the alarm fires. Returns an alarm allocated on the heap.
- // Caller takes ownership of the new alarm, which will not yet be "set" to
- // fire.
- virtual QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) = 0;
-
- // Creates a new platform-specific alarm which will be configured to notify
- // |delegate| when the alarm fires. Caller takes ownership of the new alarm,
- // which will not yet be "set" to fire. If |arena| is null, then the alarm
- // will be created on the heap. Otherwise, it will be created in |arena|.
- virtual QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
- QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
- QuicConnectionArena* arena) = 0;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_ALARM_FACTORY_H_
diff --git a/chromium/net/quic/quic_alarm_test.cc b/chromium/net/quic/quic_alarm_test.cc
deleted file mode 100644
index 0509090e747..00000000000
--- a/chromium/net/quic/quic_alarm_test.cc
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_alarm.h"
-
-#include "base/logging.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::Return;
-using testing::Invoke;
-
-namespace net {
-namespace test {
-namespace {
-
-class MockDelegate : public QuicAlarm::Delegate {
- public:
- MOCK_METHOD0(OnAlarm, void());
-};
-
-class DestructiveDelegate : public QuicAlarm::Delegate {
- public:
- DestructiveDelegate() : alarm_(nullptr) {}
-
- void set_alarm(QuicAlarm* alarm) { alarm_ = alarm; }
-
- void OnAlarm() override {
- DCHECK(alarm_);
- delete alarm_;
- }
-
- private:
- QuicAlarm* alarm_;
-};
-
-class TestAlarm : public QuicAlarm {
- public:
- explicit TestAlarm(QuicAlarm::Delegate* delegate)
- : QuicAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate)) {}
-
- bool scheduled() const { return scheduled_; }
-
- void FireAlarm() {
- scheduled_ = false;
- Fire();
- }
-
- protected:
- void SetImpl() override {
- DCHECK(deadline().IsInitialized());
- scheduled_ = true;
- }
-
- void CancelImpl() override {
- DCHECK(!deadline().IsInitialized());
- scheduled_ = false;
- }
-
- private:
- bool scheduled_;
-};
-
-class DestructiveAlarm : public QuicAlarm {
- public:
- explicit DestructiveAlarm(DestructiveDelegate* delegate)
- : QuicAlarm(QuicArenaScopedPtr<DestructiveDelegate>(delegate)) {}
-
- void FireAlarm() { Fire(); }
-
- protected:
- void SetImpl() override {}
-
- void CancelImpl() override {}
-};
-
-class QuicAlarmTest : public ::testing::Test {
- public:
- QuicAlarmTest()
- : delegate_(new MockDelegate()),
- alarm_(delegate_),
- deadline_(QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(7))),
- deadline2_(QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(14))),
- new_deadline_(QuicTime::Zero()) {}
-
- void ResetAlarm() { alarm_.Set(new_deadline_); }
-
- MockDelegate* delegate_; // not owned
- TestAlarm alarm_;
- QuicTime deadline_;
- QuicTime deadline2_;
- QuicTime new_deadline_;
-};
-
-TEST_F(QuicAlarmTest, IsSet) {
- EXPECT_FALSE(alarm_.IsSet());
-}
-
-TEST_F(QuicAlarmTest, Set) {
- QuicTime deadline = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(7));
- alarm_.Set(deadline);
- EXPECT_TRUE(alarm_.IsSet());
- EXPECT_TRUE(alarm_.scheduled());
- EXPECT_EQ(deadline, alarm_.deadline());
-}
-
-TEST_F(QuicAlarmTest, Cancel) {
- QuicTime deadline = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(7));
- alarm_.Set(deadline);
- alarm_.Cancel();
- EXPECT_FALSE(alarm_.IsSet());
- EXPECT_FALSE(alarm_.scheduled());
- EXPECT_EQ(QuicTime::Zero(), alarm_.deadline());
-}
-
-TEST_F(QuicAlarmTest, Update) {
- QuicTime deadline = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(7));
- alarm_.Set(deadline);
- QuicTime new_deadline = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(8));
- alarm_.Update(new_deadline, QuicTime::Delta::Zero());
- EXPECT_TRUE(alarm_.IsSet());
- EXPECT_TRUE(alarm_.scheduled());
- EXPECT_EQ(new_deadline, alarm_.deadline());
-}
-
-TEST_F(QuicAlarmTest, UpdateWithZero) {
- QuicTime deadline = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(7));
- alarm_.Set(deadline);
- alarm_.Update(QuicTime::Zero(), QuicTime::Delta::Zero());
- EXPECT_FALSE(alarm_.IsSet());
- EXPECT_FALSE(alarm_.scheduled());
- EXPECT_EQ(QuicTime::Zero(), alarm_.deadline());
-}
-
-TEST_F(QuicAlarmTest, Fire) {
- QuicTime deadline = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(7));
- alarm_.Set(deadline);
- alarm_.FireAlarm();
- EXPECT_FALSE(alarm_.IsSet());
- EXPECT_FALSE(alarm_.scheduled());
- EXPECT_EQ(QuicTime::Zero(), alarm_.deadline());
-}
-
-TEST_F(QuicAlarmTest, FireAndResetViaSet) {
- alarm_.Set(deadline_);
- new_deadline_ = deadline2_;
- EXPECT_CALL(*delegate_, OnAlarm())
- .WillOnce(Invoke(this, &QuicAlarmTest::ResetAlarm));
- alarm_.FireAlarm();
- EXPECT_TRUE(alarm_.IsSet());
- EXPECT_TRUE(alarm_.scheduled());
- EXPECT_EQ(deadline2_, alarm_.deadline());
-}
-
-TEST_F(QuicAlarmTest, FireDestroysAlarm) {
- DestructiveDelegate* delegate(new DestructiveDelegate);
- DestructiveAlarm* alarm = new DestructiveAlarm(delegate);
- delegate->set_alarm(alarm);
- QuicTime deadline = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(7));
- alarm->Set(deadline);
- // This should not crash, even though it will destroy alarm.
- alarm->FireAlarm();
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_arena_scoped_ptr.h b/chromium/net/quic/quic_arena_scoped_ptr.h
deleted file mode 100644
index 5083036f907..00000000000
--- a/chromium/net/quic/quic_arena_scoped_ptr.h
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// unique_ptr-style pointer that stores values that may be from an arena. Takes
-// up the same storage as the platform's native pointer type. Takes ownership
-// of the value it's constructed with; if holding a value in an arena, and the
-// type has a non-trivial destructor, the arena must outlive the
-// QuicArenaScopedPtr. Does not support array overloads.
-
-#ifndef NET_QUIC_QUIC_ARENA_SCOPED_PTR_H_
-#define NET_QUIC_QUIC_ARENA_SCOPED_PTR_H_
-
-#include <cstdint> // for uintptr_t
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "net/quic/quic_utils.h"
-
-namespace net {
-
-template <typename T>
-class QuicArenaScopedPtr {
- static_assert(QUIC_ALIGN_OF(T*) > 1,
- "QuicArenaScopedPtr can only store objects that are aligned to "
- "greater than 1 byte.");
-
- public:
- // Constructs an empty QuicArenaScopedPtr.
- QuicArenaScopedPtr();
-
- // Constructs a QuicArenaScopedPtr referencing the heap-allocated memory
- // provided.
- explicit QuicArenaScopedPtr(T* value);
-
- template <typename U>
- QuicArenaScopedPtr(QuicArenaScopedPtr<U>&& other); // NOLINT
- template <typename U>
- QuicArenaScopedPtr& operator=(QuicArenaScopedPtr<U>&& other);
- ~QuicArenaScopedPtr();
-
- // Returns a pointer to the value.
- T* get() const;
-
- // Returns a reference to the value.
- T& operator*() const;
-
- // Returns a pointer to the value.
- T* operator->() const;
-
- // Swaps the value of this pointer with |other|.
- void swap(QuicArenaScopedPtr& other);
-
- // Resets the held value to |value|.
- void reset(T* value = nullptr);
-
- // Returns true if |this| came from an arena. Primarily exposed for testing
- // and assertions.
- bool is_from_arena();
-
- private:
- // Friends with other derived types of QuicArenaScopedPtr, to support the
- // derived-types case.
- template <typename U>
- friend class QuicArenaScopedPtr;
- // Also befriend all known arenas, only to prevent misuse.
- template <uint32_t ArenaSize>
- friend class QuicOneBlockArena;
-
- // Tag to denote that a QuicArenaScopedPtr is being explicitly created by an
- // arena.
- enum class ConstructFrom { kHeap, kArena };
-
- // Constructs a QuicArenaScopedPtr with the given representation.
- QuicArenaScopedPtr(void* value, ConstructFrom from);
-
- // Low-order bits of value_ that determine if the pointer came from an arena.
- static const uintptr_t kFromArenaMask = 0x1;
-
- // Every platform we care about has at least 4B aligned integers, so store the
- // is_from_arena bit in the least significant bit.
- void* value_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicArenaScopedPtr);
-};
-
-template <typename T>
-bool operator==(const QuicArenaScopedPtr<T>& left,
- const QuicArenaScopedPtr<T>& right) {
- return left.get() == right.get();
-}
-
-template <typename T>
-bool operator!=(const QuicArenaScopedPtr<T>& left,
- const QuicArenaScopedPtr<T>& right) {
- return left.get() != right.get();
-}
-
-template <typename T>
-bool operator==(std::nullptr_t, const QuicArenaScopedPtr<T>& right) {
- return nullptr == right.get();
-}
-
-template <typename T>
-bool operator!=(std::nullptr_t, const QuicArenaScopedPtr<T>& right) {
- return nullptr != right.get();
-}
-
-template <typename T>
-bool operator==(const QuicArenaScopedPtr<T>& left, std::nullptr_t) {
- return left.get() == nullptr;
-}
-
-template <typename T>
-bool operator!=(const QuicArenaScopedPtr<T>& left, std::nullptr_t) {
- return left.get() != nullptr;
-}
-
-template <typename T>
-QuicArenaScopedPtr<T>::QuicArenaScopedPtr()
- : value_(nullptr) {}
-
-template <typename T>
-QuicArenaScopedPtr<T>::QuicArenaScopedPtr(T* value)
- : QuicArenaScopedPtr(value, ConstructFrom::kHeap) {}
-
-template <typename T>
-template <typename U>
-QuicArenaScopedPtr<T>::QuicArenaScopedPtr(QuicArenaScopedPtr<U>&& other)
- : value_(other.value_) {
- static_assert(
- std::is_base_of<T, U>::value || std::is_same<T, U>::value,
- "Cannot construct QuicArenaScopedPtr; type is not derived or same.");
- other.value_ = nullptr;
-}
-
-template <typename T>
-template <typename U>
-QuicArenaScopedPtr<T>& QuicArenaScopedPtr<T>::operator=(
- QuicArenaScopedPtr<U>&& other) {
- static_assert(
- std::is_base_of<T, U>::value || std::is_same<T, U>::value,
- "Cannot assign QuicArenaScopedPtr; type is not derived or same.");
- swap(other);
- return *this;
-}
-
-template <typename T>
-QuicArenaScopedPtr<T>::~QuicArenaScopedPtr() {
- reset();
-}
-
-template <typename T>
-T* QuicArenaScopedPtr<T>::get() const {
- return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(value_) &
- ~kFromArenaMask);
-}
-
-template <typename T>
-T& QuicArenaScopedPtr<T>::operator*() const {
- return *get();
-}
-
-template <typename T>
-T* QuicArenaScopedPtr<T>::operator->() const {
- return get();
-}
-
-template <typename T>
-void QuicArenaScopedPtr<T>::swap(QuicArenaScopedPtr& other) {
- using std::swap;
- swap(value_, other.value_);
-}
-
-template <typename T>
-bool QuicArenaScopedPtr<T>::is_from_arena() {
- return (reinterpret_cast<uintptr_t>(value_) & kFromArenaMask) != 0;
-}
-
-template <typename T>
-void QuicArenaScopedPtr<T>::reset(T* value) {
- if (value_ != nullptr) {
- if (is_from_arena()) {
- // Manually invoke the destructor.
- get()->~T();
- } else {
- delete get();
- }
- }
- DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(value) & kFromArenaMask);
- value_ = value;
-}
-
-template <typename T>
-QuicArenaScopedPtr<T>::QuicArenaScopedPtr(void* value, ConstructFrom from_arena)
- : value_(value) {
- DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(value_) & kFromArenaMask);
- switch (from_arena) {
- case ConstructFrom::kHeap:
- break;
- case ConstructFrom::kArena:
- value_ = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(value_) |
- QuicArenaScopedPtr<T>::kFromArenaMask);
- break;
- }
-}
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_ARENA_SCOPED_PTR_H_
diff --git a/chromium/net/quic/quic_arena_scoped_ptr_test.cc b/chromium/net/quic/quic_arena_scoped_ptr_test.cc
deleted file mode 100644
index 22c9ebb8bcb..00000000000
--- a/chromium/net/quic/quic_arena_scoped_ptr_test.cc
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-#include "net/quic/quic_arena_scoped_ptr.h"
-
-#include "net/quic/quic_one_block_arena.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace {
-
-enum class TestParam { kFromHeap, kFromArena };
-
-struct TestObject {
- explicit TestObject(uintptr_t value) : value(value) { buffer.resize(1024); }
- uintptr_t value;
-
- // Ensure that we have a non-trivial destructor that will leak memory if it's
- // not called.
- std::vector<char> buffer;
-};
-
-class QuicArenaScopedPtrParamTest : public ::testing::TestWithParam<TestParam> {
- protected:
- QuicArenaScopedPtr<TestObject> CreateObject(uintptr_t value) {
- QuicArenaScopedPtr<TestObject> ptr;
- switch (GetParam()) {
- case TestParam::kFromHeap:
- ptr = QuicArenaScopedPtr<TestObject>(new TestObject(value));
- CHECK(!ptr.is_from_arena());
- break;
- case TestParam::kFromArena:
- ptr = arena_.New<TestObject>(value);
- CHECK(ptr.is_from_arena());
- break;
- }
- return ptr;
- }
-
- private:
- QuicOneBlockArena<1024> arena_;
-};
-
-INSTANTIATE_TEST_CASE_P(QuicArenaScopedPtrParamTest,
- QuicArenaScopedPtrParamTest,
- testing::Values(TestParam::kFromHeap,
- TestParam::kFromArena));
-
-TEST(QuicArenaScopedPtrTest, NullObjects) {
- QuicArenaScopedPtr<TestObject> def;
- QuicArenaScopedPtr<TestObject> null(nullptr);
- EXPECT_EQ(def, null);
- EXPECT_EQ(def, nullptr);
- EXPECT_EQ(null, nullptr);
-}
-
-TEST(QuicArenaScopedPtrTest, FromArena) {
- QuicOneBlockArena<1024> arena_;
- EXPECT_TRUE(arena_.New<TestObject>(0).is_from_arena());
- EXPECT_FALSE(
- QuicArenaScopedPtr<TestObject>(new TestObject(0)).is_from_arena());
-}
-
-TEST_P(QuicArenaScopedPtrParamTest, Assign) {
- QuicArenaScopedPtr<TestObject> ptr = CreateObject(12345);
- ptr = CreateObject(54321);
- EXPECT_EQ(54321u, ptr->value);
-}
-
-TEST_P(QuicArenaScopedPtrParamTest, MoveConstruct) {
- QuicArenaScopedPtr<TestObject> ptr1 = CreateObject(12345);
- QuicArenaScopedPtr<TestObject> ptr2(std::move(ptr1));
- EXPECT_EQ(nullptr, ptr1);
- EXPECT_EQ(12345u, ptr2->value);
-}
-
-TEST_P(QuicArenaScopedPtrParamTest, Accessors) {
- QuicArenaScopedPtr<TestObject> ptr = CreateObject(12345);
- EXPECT_EQ(12345u, (*ptr).value);
- EXPECT_EQ(12345u, ptr->value);
- // We explicitly want to test that get() returns a valid pointer to the data,
- // but the call looks redundant.
- EXPECT_EQ(12345u, ptr.get()->value); // NOLINT
-}
-
-TEST_P(QuicArenaScopedPtrParamTest, Reset) {
- QuicArenaScopedPtr<TestObject> ptr = CreateObject(12345);
- ptr.reset(new TestObject(54321));
- EXPECT_EQ(54321u, ptr->value);
-}
-
-TEST_P(QuicArenaScopedPtrParamTest, Swap) {
- QuicArenaScopedPtr<TestObject> ptr1 = CreateObject(12345);
- QuicArenaScopedPtr<TestObject> ptr2 = CreateObject(54321);
- ptr1.swap(ptr2);
- EXPECT_EQ(12345u, ptr2->value);
- EXPECT_EQ(54321u, ptr1->value);
-}
-
-} // namespace
-} // namespace net
diff --git a/chromium/net/quic/quic_bandwidth.cc b/chromium/net/quic/quic_bandwidth.cc
deleted file mode 100644
index 734858d5bbb..00000000000
--- a/chromium/net/quic/quic_bandwidth.cc
+++ /dev/null
@@ -1,118 +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/quic_bandwidth.h"
-
-#include <stdint.h>
-
-#include "base/logging.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_time.h"
-#include "net/quic/quic_types.h"
-
-namespace net {
-
-// Highest number that QuicBandwidth can hold.
-const int64_t kQuicInfiniteBandwidth = INT64_C(0x7fffffffffffffff);
-
-// static
-QuicBandwidth QuicBandwidth::Zero() {
- return QuicBandwidth(0);
-}
-
-// static
-QuicBandwidth QuicBandwidth::FromBitsPerSecond(int64_t bits_per_second) {
- return QuicBandwidth(bits_per_second);
-}
-
-// static
-QuicBandwidth QuicBandwidth::FromKBitsPerSecond(int64_t k_bits_per_second) {
- DCHECK(k_bits_per_second < kQuicInfiniteBandwidth / 1000);
- return QuicBandwidth(k_bits_per_second * 1000);
-}
-
-// static
-QuicBandwidth QuicBandwidth::FromBytesPerSecond(int64_t bytes_per_second) {
- DCHECK(bytes_per_second < kQuicInfiniteBandwidth / 8);
- return QuicBandwidth(bytes_per_second * 8);
-}
-
-// static
-QuicBandwidth QuicBandwidth::FromKBytesPerSecond(int64_t k_bytes_per_second) {
- DCHECK(k_bytes_per_second < kQuicInfiniteBandwidth / 8000);
- return QuicBandwidth(k_bytes_per_second * 8000);
-}
-
-// static
-QuicBandwidth QuicBandwidth::FromBytesAndTimeDelta(QuicByteCount bytes,
- QuicTime::Delta delta) {
- DCHECK_LT(bytes, static_cast<uint64_t>(kQuicInfiniteBandwidth /
- (8 * kNumMicrosPerSecond)));
- int64_t bytes_per_second =
- (bytes * kNumMicrosPerSecond) / delta.ToMicroseconds();
- return QuicBandwidth(bytes_per_second * 8);
-}
-
-QuicBandwidth::QuicBandwidth(int64_t bits_per_second)
- : bits_per_second_(bits_per_second) {
- if (bits_per_second < 0) {
- QUIC_BUG << "Can't set negative bandwidth " << bits_per_second;
- bits_per_second_ = 0;
- return;
- }
- bits_per_second_ = bits_per_second;
-}
-
-int64_t QuicBandwidth::ToBitsPerSecond() const {
- return bits_per_second_;
-}
-
-int64_t QuicBandwidth::ToKBitsPerSecond() const {
- return bits_per_second_ / 1000;
-}
-
-int64_t QuicBandwidth::ToBytesPerSecond() const {
- return bits_per_second_ / 8;
-}
-
-int64_t QuicBandwidth::ToKBytesPerSecond() const {
- return bits_per_second_ / 8000;
-}
-
-QuicByteCount QuicBandwidth::ToBytesPerPeriod(
- QuicTime::Delta time_period) const {
- return ToBytesPerSecond() * time_period.ToMicroseconds() /
- kNumMicrosPerSecond;
-}
-
-int64_t QuicBandwidth::ToKBytesPerPeriod(QuicTime::Delta time_period) const {
- return ToKBytesPerSecond() * time_period.ToMicroseconds() /
- kNumMicrosPerSecond;
-}
-
-bool QuicBandwidth::IsZero() const {
- return (bits_per_second_ == 0);
-}
-
-QuicBandwidth QuicBandwidth::Add(QuicBandwidth delta) const {
- return QuicBandwidth(bits_per_second_ + delta.bits_per_second_);
-}
-
-QuicBandwidth QuicBandwidth::Subtract(QuicBandwidth delta) const {
- return QuicBandwidth(bits_per_second_ - delta.bits_per_second_);
-}
-
-QuicBandwidth QuicBandwidth::Scale(float scale_factor) const {
- return QuicBandwidth(static_cast<int64_t>(bits_per_second_ * scale_factor));
-}
-
-QuicTime::Delta QuicBandwidth::TransferTime(QuicByteCount bytes) const {
- if (bits_per_second_ == 0) {
- return QuicTime::Delta::Zero();
- }
- return QuicTime::Delta::FromMicroseconds(bytes * 8 * kNumMicrosPerSecond /
- bits_per_second_);
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_bandwidth.h b/chromium/net/quic/quic_bandwidth.h
deleted file mode 100644
index 215ee25fc04..00000000000
--- a/chromium/net/quic/quic_bandwidth.h
+++ /dev/null
@@ -1,89 +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.
-//
-// QuicBandwidth represents a bandwidth, stored in bits per second resolution.
-
-#ifndef NET_QUIC_QUIC_BANDWIDTH_H_
-#define NET_QUIC_QUIC_BANDWIDTH_H_
-
-#include <stdint.h>
-
-#include "base/compiler_specific.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-typedef uint64_t QuicByteCount;
-typedef uint64_t QuicPacketCount;
-
-class NET_EXPORT_PRIVATE QuicBandwidth {
- public:
- // Creates a new QuicBandwidth with an internal value of 0.
- static QuicBandwidth Zero();
-
- // Create a new QuicBandwidth holding the bits per second.
- static QuicBandwidth FromBitsPerSecond(int64_t bits_per_second);
-
- // Create a new QuicBandwidth holding the kilo bits per second.
- static QuicBandwidth FromKBitsPerSecond(int64_t k_bits_per_second);
-
- // Create a new QuicBandwidth holding the bytes per second.
- static QuicBandwidth FromBytesPerSecond(int64_t bytes_per_second);
-
- // Create a new QuicBandwidth holding the kilo bytes per second.
- static QuicBandwidth FromKBytesPerSecond(int64_t k_bytes_per_second);
-
- // Create a new QuicBandwidth based on the bytes per the elapsed delta.
- static QuicBandwidth FromBytesAndTimeDelta(QuicByteCount bytes,
- QuicTime::Delta delta);
-
- int64_t ToBitsPerSecond() const;
-
- int64_t ToKBitsPerSecond() const;
-
- int64_t ToBytesPerSecond() const;
-
- int64_t ToKBytesPerSecond() const;
-
- QuicByteCount ToBytesPerPeriod(QuicTime::Delta time_period) const;
-
- int64_t ToKBytesPerPeriod(QuicTime::Delta time_period) const;
-
- bool IsZero() const;
-
- QuicBandwidth Add(QuicBandwidth delta) const WARN_UNUSED_RESULT;
-
- QuicBandwidth Subtract(QuicBandwidth delta) const WARN_UNUSED_RESULT;
-
- QuicBandwidth Scale(float scale_factor) const WARN_UNUSED_RESULT;
-
- QuicTime::Delta TransferTime(QuicByteCount bytes) const;
-
- private:
- explicit QuicBandwidth(int64_t bits_per_second);
- int64_t bits_per_second_;
-};
-
-// Non-member relational operators for QuicBandwidth.
-inline bool operator==(QuicBandwidth lhs, QuicBandwidth rhs) {
- return lhs.ToBitsPerSecond() == rhs.ToBitsPerSecond();
-}
-inline bool operator!=(QuicBandwidth lhs, QuicBandwidth rhs) {
- return !(lhs == rhs);
-}
-inline bool operator<(QuicBandwidth lhs, QuicBandwidth rhs) {
- return lhs.ToBitsPerSecond() < rhs.ToBitsPerSecond();
-}
-inline bool operator>(QuicBandwidth lhs, QuicBandwidth rhs) {
- return rhs < lhs;
-}
-inline bool operator<=(QuicBandwidth lhs, QuicBandwidth rhs) {
- return !(rhs < lhs);
-}
-inline bool operator>=(QuicBandwidth lhs, QuicBandwidth rhs) {
- return !(lhs < rhs);
-}
-
-} // namespace net
-#endif // NET_QUIC_QUIC_BANDWIDTH_H_
diff --git a/chromium/net/quic/quic_bandwidth_test.cc b/chromium/net/quic/quic_bandwidth_test.cc
deleted file mode 100644
index 191405c61d7..00000000000
--- a/chromium/net/quic/quic_bandwidth_test.cc
+++ /dev/null
@@ -1,99 +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/quic_bandwidth.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-class QuicBandwidthTest : public ::testing::Test {};
-
-TEST_F(QuicBandwidthTest, FromTo) {
- EXPECT_EQ(QuicBandwidth::FromKBitsPerSecond(1),
- QuicBandwidth::FromBitsPerSecond(1000));
- EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(1),
- QuicBandwidth::FromBytesPerSecond(1000));
- EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(8000),
- QuicBandwidth::FromBytesPerSecond(1000));
- EXPECT_EQ(QuicBandwidth::FromKBitsPerSecond(8),
- QuicBandwidth::FromKBytesPerSecond(1));
-
- EXPECT_EQ(0, QuicBandwidth::Zero().ToBitsPerSecond());
- EXPECT_EQ(0, QuicBandwidth::Zero().ToKBitsPerSecond());
- EXPECT_EQ(0, QuicBandwidth::Zero().ToBytesPerSecond());
- EXPECT_EQ(0, QuicBandwidth::Zero().ToKBytesPerSecond());
-
- EXPECT_EQ(1, QuicBandwidth::FromBitsPerSecond(1000).ToKBitsPerSecond());
- EXPECT_EQ(1000, QuicBandwidth::FromKBitsPerSecond(1).ToBitsPerSecond());
- EXPECT_EQ(1, QuicBandwidth::FromBytesPerSecond(1000).ToKBytesPerSecond());
- EXPECT_EQ(1000, QuicBandwidth::FromKBytesPerSecond(1).ToBytesPerSecond());
-}
-
-TEST_F(QuicBandwidthTest, Add) {
- QuicBandwidth bandwidht_1 = QuicBandwidth::FromKBitsPerSecond(1);
- QuicBandwidth bandwidht_2 = QuicBandwidth::FromKBytesPerSecond(1);
-
- EXPECT_EQ(9000, bandwidht_1.Add(bandwidht_2).ToBitsPerSecond());
- EXPECT_EQ(9000, bandwidht_2.Add(bandwidht_1).ToBitsPerSecond());
-}
-
-TEST_F(QuicBandwidthTest, Subtract) {
- QuicBandwidth bandwidht_1 = QuicBandwidth::FromKBitsPerSecond(1);
- QuicBandwidth bandwidht_2 = QuicBandwidth::FromKBytesPerSecond(1);
-
- EXPECT_EQ(7000, bandwidht_2.Subtract(bandwidht_1).ToBitsPerSecond());
-}
-
-TEST_F(QuicBandwidthTest, TimeDelta) {
- EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(1000),
- QuicBandwidth::FromBytesAndTimeDelta(
- 1000, QuicTime::Delta::FromMilliseconds(1)));
-
- EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(10),
- QuicBandwidth::FromBytesAndTimeDelta(
- 1000, QuicTime::Delta::FromMilliseconds(100)));
-}
-
-TEST_F(QuicBandwidthTest, Scale) {
- EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(500),
- QuicBandwidth::FromKBytesPerSecond(1000).Scale(0.5f));
- EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(750),
- QuicBandwidth::FromKBytesPerSecond(1000).Scale(0.75f));
- EXPECT_EQ(QuicBandwidth::FromKBytesPerSecond(1250),
- QuicBandwidth::FromKBytesPerSecond(1000).Scale(1.25f));
-}
-
-TEST_F(QuicBandwidthTest, BytesPerPeriod) {
- EXPECT_EQ(2000u, QuicBandwidth::FromKBytesPerSecond(2000)
- .ToBytesPerPeriod(QuicTime::Delta::FromMilliseconds(1)));
- EXPECT_EQ(2u, QuicBandwidth::FromKBytesPerSecond(2000)
- .ToKBytesPerPeriod(QuicTime::Delta::FromMilliseconds(1)));
- EXPECT_EQ(200000u, QuicBandwidth::FromKBytesPerSecond(2000).ToBytesPerPeriod(
- QuicTime::Delta::FromMilliseconds(100)));
- EXPECT_EQ(200u, QuicBandwidth::FromKBytesPerSecond(2000).ToKBytesPerPeriod(
- QuicTime::Delta::FromMilliseconds(100)));
-}
-
-TEST_F(QuicBandwidthTest, TransferTime) {
- EXPECT_EQ(QuicTime::Delta::FromSeconds(1),
- QuicBandwidth::FromKBytesPerSecond(1).TransferTime(1000));
- EXPECT_EQ(QuicTime::Delta::Zero(), QuicBandwidth::Zero().TransferTime(1000));
-}
-
-TEST_F(QuicBandwidthTest, RelOps) {
- const QuicBandwidth b1 = QuicBandwidth::FromKBitsPerSecond(1);
- const QuicBandwidth b2 = QuicBandwidth::FromKBytesPerSecond(2);
- EXPECT_EQ(b1, b1);
- EXPECT_NE(b1, b2);
- EXPECT_LT(b1, b2);
- EXPECT_GT(b2, b1);
- EXPECT_LE(b1, b1);
- EXPECT_LE(b1, b2);
- EXPECT_GE(b1, b1);
- EXPECT_GE(b2, b1);
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_buffered_packet_store.cc b/chromium/net/quic/quic_buffered_packet_store.cc
deleted file mode 100644
index 5d6b8805684..00000000000
--- a/chromium/net/quic/quic_buffered_packet_store.cc
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_buffered_packet_store.h"
-
-#include <list>
-
-#include "base/stl_util.h"
-
-using std::list;
-
-namespace net {
-
-typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket;
-typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult;
-typedef QuicBufferedPacketStore::BufferedPacketList BufferedPacketList;
-
-// Max number of connections this store can keep track.
-static const size_t kDefaultMaxConnectionsInStore = 100;
-
-namespace {
-
-// This alarm removes expired entries in map each time this alarm fires.
-class ConnectionExpireAlarm : public QuicAlarm::Delegate {
- public:
- explicit ConnectionExpireAlarm(QuicBufferedPacketStore* store)
- : connection_store_(store) {}
-
- void OnAlarm() override { connection_store_->OnExpirationTimeout(); }
-
- // Disallow copy and asign.
- ConnectionExpireAlarm(const ConnectionExpireAlarm&) = delete;
- ConnectionExpireAlarm& operator=(const ConnectionExpireAlarm&) = delete;
-
- private:
- QuicBufferedPacketStore* connection_store_;
-};
-
-} // namespace
-
-BufferedPacket::BufferedPacket(std::unique_ptr<QuicReceivedPacket> packet,
- IPEndPoint server_address,
- IPEndPoint client_address)
- : packet(std::move(packet)),
- server_address(server_address),
- client_address(client_address) {}
-
-BufferedPacket::BufferedPacket(BufferedPacket&& other) = default;
-
-BufferedPacket& BufferedPacket::operator=(BufferedPacket&& other) = default;
-
-BufferedPacket::~BufferedPacket() {}
-
-BufferedPacketList::BufferedPacketList() : creation_time(QuicTime::Zero()) {}
-
-BufferedPacketList::BufferedPacketList(BufferedPacketList&& other) = default;
-
-BufferedPacketList& BufferedPacketList::operator=(BufferedPacketList&& other) =
- default;
-
-BufferedPacketList::~BufferedPacketList() {}
-
-QuicBufferedPacketStore::QuicBufferedPacketStore(
- VisitorInterface* visitor,
- const QuicClock* clock,
- QuicAlarmFactory* alarm_factory)
- : connection_life_span_(
- QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs)),
- visitor_(visitor),
- clock_(clock),
- expiration_alarm_(
- alarm_factory->CreateAlarm(new ConnectionExpireAlarm(this))) {}
-
-QuicBufferedPacketStore::~QuicBufferedPacketStore() {}
-
-EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket(
- QuicConnectionId connection_id,
- const QuicReceivedPacket& packet,
- IPEndPoint server_address,
- IPEndPoint client_address) {
- if (!ContainsKey(undecryptable_packets_, connection_id) &&
- undecryptable_packets_.size() >= kDefaultMaxConnectionsInStore) {
- // Drop the packet if store can't keep track of more connections.
- return TOO_MANY_CONNECTIONS;
- } else if (!ContainsKey(undecryptable_packets_, connection_id)) {
- undecryptable_packets_.emplace(
- std::make_pair(connection_id, BufferedPacketList()));
- }
- CHECK(ContainsKey(undecryptable_packets_, connection_id));
- BufferedPacketList& queue =
- undecryptable_packets_.find(connection_id)->second;
-
- if (queue.buffered_packets.size() >= kDefaultMaxUndecryptablePackets) {
- // If there are kMaxBufferedPacketsPerConnection packets buffered up for
- // this connection, drop the current packet.
- return TOO_MANY_PACKETS;
- }
-
- if (queue.buffered_packets.empty()) {
- // If this is the first packet arrived on a new connection, initialize the
- // creation time.
- queue.creation_time = clock_->ApproximateNow();
- }
-
- BufferedPacket new_entry(std::unique_ptr<QuicReceivedPacket>(packet.Clone()),
- server_address, client_address);
-
- queue.buffered_packets.push_back(std::move(new_entry));
-
- if (!expiration_alarm_->IsSet()) {
- expiration_alarm_->Set(clock_->ApproximateNow().Add(connection_life_span_));
- }
- return SUCCESS;
-}
-
-bool QuicBufferedPacketStore::HasBufferedPackets(
- QuicConnectionId connection_id) const {
- return ContainsKey(undecryptable_packets_, connection_id);
-}
-
-list<BufferedPacket> QuicBufferedPacketStore::DeliverPackets(
- QuicConnectionId connection_id) {
- list<BufferedPacket> packets_to_deliver;
- auto it = undecryptable_packets_.find(connection_id);
- if (it != undecryptable_packets_.end()) {
- packets_to_deliver = std::move(it->second.buffered_packets);
- undecryptable_packets_.erase(connection_id);
- }
- return packets_to_deliver;
-}
-
-void QuicBufferedPacketStore::OnExpirationTimeout() {
- QuicTime expiration_time =
- clock_->ApproximateNow().Subtract(connection_life_span_);
- while (!undecryptable_packets_.empty()) {
- auto& entry = undecryptable_packets_.front();
- if (entry.second.creation_time > expiration_time) {
- break;
- }
- visitor_->OnExpiredPackets(entry.first, std::move(entry.second));
- undecryptable_packets_.erase(undecryptable_packets_.begin());
- }
- if (!undecryptable_packets_.empty()) {
- expiration_alarm_->Set(clock_->ApproximateNow().Add(connection_life_span_));
- }
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_buffered_packet_store.h b/chromium/net/quic/quic_buffered_packet_store.h
deleted file mode 100644
index 67220fb3bdc..00000000000
--- a/chromium/net/quic/quic_buffered_packet_store.h
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_BUFFERED_PACKET_STORE_H_
-#define NET_QUIC_QUIC_BUFFERED_PACKET_STORE_H_
-
-#include "net/base/ip_address.h"
-#include "net/base/linked_hash_map.h"
-#include "net/quic/quic_alarm.h"
-#include "net/quic/quic_alarm_factory.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-namespace test {
-class QuicBufferedPacketStorePeer;
-} // namespace test
-
-// This class buffers undeliverable packets for each connection until either
-// 1) They are requested to be delivered via DeliverPacket(), or
-// 2) They expire after exceeding their lifetime in the store.
-class NET_EXPORT_PRIVATE QuicBufferedPacketStore {
- public:
- enum EnqueuePacketResult {
- SUCCESS = 0,
- TOO_MANY_PACKETS, // Too many packets stored up for a certain connection.
- TOO_MANY_CONNECTIONS // Too many connections stored up in the store.
- };
-
- // A packets with client/server address.
- struct NET_EXPORT_PRIVATE BufferedPacket {
- BufferedPacket(std::unique_ptr<QuicReceivedPacket> packet,
- IPEndPoint server_address,
- IPEndPoint client_address);
- BufferedPacket(BufferedPacket&& other);
-
- BufferedPacket& operator=(BufferedPacket&& other);
-
- ~BufferedPacket();
-
- std::unique_ptr<QuicReceivedPacket> packet;
- IPEndPoint server_address;
- IPEndPoint client_address;
- };
-
- // A queue of BufferedPackets for a connection.
- struct NET_EXPORT_PRIVATE BufferedPacketList {
- BufferedPacketList();
- BufferedPacketList(BufferedPacketList&& other);
-
- BufferedPacketList& operator=(BufferedPacketList&& other);
-
- ~BufferedPacketList();
-
- std::list<BufferedPacket> buffered_packets;
- QuicTime creation_time;
- };
-
- typedef linked_hash_map<QuicConnectionId, BufferedPacketList>
- BufferedPacketMap;
-
- class NET_EXPORT_PRIVATE VisitorInterface {
- public:
- virtual ~VisitorInterface() {}
-
- // Called for each expired connection when alarm fires.
- virtual void OnExpiredPackets(QuicConnectionId connection_id,
- BufferedPacketList early_arrived_packets) = 0;
- };
-
- QuicBufferedPacketStore(VisitorInterface* vistor,
- const QuicClock* clock,
- QuicAlarmFactory* alarm_factory);
-
- QuicBufferedPacketStore(const QuicBufferedPacketStore&) = delete;
-
- ~QuicBufferedPacketStore();
-
- QuicBufferedPacketStore& operator=(const QuicBufferedPacketStore&) = delete;
-
- // Adds a copy of packet into packet queue for given connection.
- EnqueuePacketResult EnqueuePacket(QuicConnectionId connection_id,
- const QuicReceivedPacket& packet,
- IPEndPoint server_address,
- IPEndPoint client_address);
-
- // Returns true if there are any packets buffered for |connection_id|.
- bool HasBufferedPackets(QuicConnectionId connection_id) const;
-
- // Returns the list of buffered packets for |connection_id| and removes them
- // from the store. Returns an empty list if no early arrived packets for this
- // connection are present.
- std::list<BufferedPacket> DeliverPackets(QuicConnectionId connection_id);
-
- // Examines how long packets have been buffered in the store for each
- // connection. If they stay too long, removes them for new coming packets and
- // calls |visitor_|'s OnPotentialConnectionExpire().
- // Resets the alarm at the end.
- void OnExpirationTimeout();
-
- private:
- friend class test::QuicBufferedPacketStorePeer;
-
- // A map to store packet queues with creation time for each connection.
- BufferedPacketMap undecryptable_packets_;
-
- // The max time the packets of a connection can be buffer in the store.
- QuicTime::Delta connection_life_span_;
-
- VisitorInterface* visitor_; // Unowned.
-
- const QuicClock* clock_; // Unowned.
-
- // This alarm fires every |connection_life_span_| to clean up
- // packets staying in the store for too long.
- std::unique_ptr<QuicAlarm> expiration_alarm_;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_BUFFERED_PACKET_STORE_H_
diff --git a/chromium/net/quic/quic_buffered_packet_store_test.cc b/chromium/net/quic/quic_buffered_packet_store_test.cc
deleted file mode 100644
index 84f22f0fd22..00000000000
--- a/chromium/net/quic/quic_buffered_packet_store_test.cc
+++ /dev/null
@@ -1,231 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_buffered_packet_store.h"
-
-#include <list>
-#include <string>
-
-#include "base/stl_util.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::list;
-using std::string;
-
-namespace net {
-
-typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket;
-typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult;
-
-static const size_t kDefaultMaxConnectionsInStore = 100;
-
-namespace test {
-class QuicBufferedPacketStorePeer {
- public:
- static QuicAlarm* expiration_alarm(QuicBufferedPacketStore* store) {
- return store->expiration_alarm_.get();
- }
-};
-
-namespace {
-
-typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket;
-typedef QuicBufferedPacketStore::BufferedPacketList BufferedPacketList;
-
-class QuicBufferedPacketStoreVisitor
- : public QuicBufferedPacketStore::VisitorInterface {
- public:
- QuicBufferedPacketStoreVisitor() {}
-
- ~QuicBufferedPacketStoreVisitor() override {}
-
- void OnExpiredPackets(QuicConnectionId connection_id,
- BufferedPacketList early_arrived_packets) override {
- last_expired_packet_queue_ = std::move(early_arrived_packets);
- }
-
- // The packets queue for most recently expirect connection.
- BufferedPacketList last_expired_packet_queue_;
-};
-
-class QuicBufferedPacketStoreTest : public ::testing::Test {
- public:
- QuicBufferedPacketStoreTest()
- : store_(&visitor_, &clock_, &alarm_factory_),
- server_address_(Loopback6(), 65535),
- client_address_(Loopback6(), 65535),
- packet_content_("some encrypted content"),
- packet_time_(
- QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(42))),
- data_packet_(packet_content_.data(),
- packet_content_.size(),
- packet_time_) {}
-
- protected:
- QuicBufferedPacketStoreVisitor visitor_;
- MockClock clock_;
- MockAlarmFactory alarm_factory_;
- QuicBufferedPacketStore store_;
- IPEndPoint server_address_;
- IPEndPoint client_address_;
- string packet_content_;
- QuicTime packet_time_;
- QuicReceivedPacket data_packet_;
-};
-
-TEST_F(QuicBufferedPacketStoreTest, SimpleEnqueueAndDeliverPacket) {
- QuicConnectionId connection_id = 1;
- store_.EnqueuePacket(connection_id, data_packet_, server_address_,
- client_address_);
- EXPECT_TRUE(store_.HasBufferedPackets(connection_id));
- list<BufferedPacket> queue = store_.DeliverPackets(connection_id);
- ASSERT_EQ(1u, queue.size());
- // Check content of the only packet in the queue.
- EXPECT_EQ(packet_content_, queue.front().packet->AsStringPiece());
- EXPECT_EQ(packet_time_, queue.front().packet->receipt_time());
- EXPECT_EQ(client_address_, queue.front().client_address);
- EXPECT_EQ(server_address_, queue.front().server_address);
- // No more packets on connection 1 should remain in the store.
- EXPECT_TRUE(store_.DeliverPackets(connection_id).empty());
- EXPECT_FALSE(store_.HasBufferedPackets(connection_id));
-}
-
-TEST_F(QuicBufferedPacketStoreTest, DifferentPacketAddressOnOneConnection) {
- IPEndPoint addr_with_new_port(Loopback4(), 256);
- QuicConnectionId connection_id = 1;
- store_.EnqueuePacket(connection_id, data_packet_, server_address_,
- client_address_);
- store_.EnqueuePacket(connection_id, data_packet_, server_address_,
- addr_with_new_port);
- list<BufferedPacket> queue = store_.DeliverPackets(connection_id);
- ASSERT_EQ(2u, queue.size());
- // The address migration path should be preserved.
- EXPECT_EQ(client_address_, queue.front().client_address);
- EXPECT_EQ(addr_with_new_port, queue.back().client_address);
-}
-
-TEST_F(QuicBufferedPacketStoreTest,
- EnqueueAndDeliverMultiplePacketsOnMultipleConnections) {
- size_t num_connections = 10;
- for (QuicConnectionId connection_id = 1; connection_id <= num_connections;
- ++connection_id) {
- store_.EnqueuePacket(connection_id, data_packet_, server_address_,
- client_address_);
- store_.EnqueuePacket(connection_id, data_packet_, server_address_,
- client_address_);
- }
-
- // Deliver packets in reversed order.
- for (QuicConnectionId connection_id = num_connections; connection_id > 0;
- --connection_id) {
- list<BufferedPacket> queue = store_.DeliverPackets(connection_id);
- ASSERT_EQ(2u, queue.size());
- }
-}
-
-TEST_F(QuicBufferedPacketStoreTest,
- FailToBufferTooManyPacketsOnExistingConnection) {
- // Tests that for one connection, only limited number of packets can be
- // buffered.
- size_t num_packets = kDefaultMaxUndecryptablePackets + 1;
- QuicConnectionId connection_id = 1;
- for (size_t i = 1; i <= num_packets; ++i) {
- // Only first |kDefaultMaxUndecryptablePackets packets| will be buffered.
- EnqueuePacketResult result = store_.EnqueuePacket(
- connection_id, data_packet_, server_address_, client_address_);
- if (i <= kDefaultMaxUndecryptablePackets) {
- EXPECT_EQ(EnqueuePacketResult::SUCCESS, result);
- } else {
- EXPECT_EQ(EnqueuePacketResult::TOO_MANY_PACKETS, result);
- }
- }
-
- // Only first |kDefaultMaxUndecryptablePackets| packets are kept in the store
- // and can be delivered.
- EXPECT_EQ(kDefaultMaxUndecryptablePackets,
- store_.DeliverPackets(connection_id).size());
-}
-
-TEST_F(QuicBufferedPacketStoreTest, FailToBufferPacketsForTooManyConnections) {
- // Tests that store can only keep early arrived packets for limited number of
- // connections.
- size_t num_connections = kDefaultMaxConnectionsInStore + 1;
- for (size_t connection_id = 1; connection_id <= num_connections;
- ++connection_id) {
- EnqueuePacketResult result = store_.EnqueuePacket(
- connection_id, data_packet_, server_address_, client_address_);
- if (connection_id <= kDefaultMaxConnectionsInStore) {
- EXPECT_EQ(EnqueuePacketResult::SUCCESS, result);
- } else {
- EXPECT_EQ(EnqueuePacketResult::TOO_MANY_CONNECTIONS, result);
- }
- }
- // Store only keeps early arrived packets upto |kDefaultMaxConnectionsInStore|
- // connections.
- for (size_t connection_id = 1; connection_id <= num_connections;
- ++connection_id) {
- list<BufferedPacket> queue = store_.DeliverPackets(connection_id);
- if (connection_id <= kDefaultMaxConnectionsInStore) {
- EXPECT_EQ(1u, queue.size());
- } else {
- EXPECT_EQ(0u, queue.size());
- }
- }
-}
-
-TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) {
- QuicConnectionId connection_id = 1;
- store_.EnqueuePacket(connection_id, data_packet_, server_address_,
- client_address_);
- // Packet for another connection arrive 1ms later.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- QuicConnectionId connection_id2 = 2;
- // Use different client address to differetiate packets from different
- // connections.
- IPEndPoint another_client_address(Loopback4(), 255);
- store_.EnqueuePacket(connection_id2, data_packet_, server_address_,
- another_client_address);
- // Advance clock to the time when connection 1 expires.
- clock_.AdvanceTime(QuicBufferedPacketStorePeer::expiration_alarm(&store_)
- ->deadline()
- .Subtract(clock_.ApproximateNow()));
- ASSERT_GE(clock_.ApproximateNow(),
- QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline());
- // Fire alarm to remove long-staying connection 1 packets.
- alarm_factory_.FireAlarm(
- QuicBufferedPacketStorePeer::expiration_alarm(&store_));
- EXPECT_EQ(1u, visitor_.last_expired_packet_queue_.buffered_packets.size());
- // Try to deliver packets, but packet queue has been removed so no
- // packets can be returned.
- ASSERT_EQ(0u, store_.DeliverPackets(connection_id).size());
-
- // Deliver packets on connection 2. And the queue for connection 2 should be
- // returned.
- list<BufferedPacket> queue = store_.DeliverPackets(connection_id2);
- ASSERT_EQ(1u, queue.size());
- // Packets in connection 2 should use another client address.
- EXPECT_EQ(another_client_address, queue.front().client_address);
-
- // Test the alarm is reset by enqueueing 2 packets for 3rd connection and wait
- // for them to expire.
- QuicConnectionId connection_id3 = 3;
- store_.EnqueuePacket(connection_id3, data_packet_, server_address_,
- client_address_);
- store_.EnqueuePacket(connection_id3, data_packet_, server_address_,
- client_address_);
- clock_.AdvanceTime(QuicBufferedPacketStorePeer::expiration_alarm(&store_)
- ->deadline()
- .Subtract(clock_.ApproximateNow()));
- alarm_factory_.FireAlarm(
- QuicBufferedPacketStorePeer::expiration_alarm(&store_));
- // |last_expired_packet_queue_| should be updated.
- EXPECT_EQ(2u, visitor_.last_expired_packet_queue_.buffered_packets.size());
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_chromium_alarm_factory.cc b/chromium/net/quic/quic_chromium_alarm_factory.cc
deleted file mode 100644
index 8973b97e35c..00000000000
--- a/chromium/net/quic/quic_chromium_alarm_factory.cc
+++ /dev/null
@@ -1,117 +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/quic_chromium_alarm_factory.h"
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/metrics/sparse_histogram.h"
-#include "base/task_runner.h"
-#include "base/time/time.h"
-
-namespace net {
-
-namespace {
-
-class QuicChromeAlarm : public QuicAlarm {
- public:
- QuicChromeAlarm(const QuicClock* clock,
- base::TaskRunner* task_runner,
- QuicArenaScopedPtr<QuicAlarm::Delegate> delegate)
- : QuicAlarm(std::move(delegate)),
- clock_(clock),
- task_runner_(task_runner),
- task_deadline_(QuicTime::Zero()),
- weak_factory_(this) {}
-
- protected:
- void SetImpl() override {
- DCHECK(deadline().IsInitialized());
- if (task_deadline_.IsInitialized()) {
- if (task_deadline_ <= deadline()) {
- // Since tasks can not be un-posted, OnAlarm will be invoked which
- // will notice that deadline has not yet been reached, and will set
- // the alarm for the new deadline.
- return;
- }
- // The scheduled task is after new deadline. Invalidate the weak ptrs
- // so that task does not execute when we're not expecting it.
- weak_factory_.InvalidateWeakPtrs();
- }
-
- int64_t delay_us = deadline().Subtract(clock_->Now()).ToMicroseconds();
- if (delay_us < 0) {
- delay_us = 0;
- }
- task_runner_->PostDelayedTask(
- FROM_HERE,
- base::Bind(&QuicChromeAlarm::OnAlarm, weak_factory_.GetWeakPtr()),
- base::TimeDelta::FromMicroseconds(delay_us));
- task_deadline_ = deadline();
- }
-
- void CancelImpl() override {
- DCHECK(!deadline().IsInitialized());
- // Since tasks can not be un-posted, OnAlarm will be invoked which
- // will notice that deadline is not Initialized and will do nothing.
- }
-
- private:
- void OnAlarm() {
- DCHECK(task_deadline_.IsInitialized());
- task_deadline_ = QuicTime::Zero();
- // The alarm may have been cancelled.
- if (!deadline().IsInitialized()) {
- return;
- }
-
- // The alarm may have been re-set to a later time.
- if (clock_->Now() < deadline()) {
- SetImpl();
- return;
- }
-
- Fire();
- }
-
- const QuicClock* clock_;
- base::TaskRunner* task_runner_;
- // If a task has been posted to the message loop, this is the time it
- // was scheduled to fire. Tracking this allows us to avoid posting a
- // new tast if the new deadline is in the future, but permits us to
- // post a new task when the new deadline now earlier than when
- // previously posted.
- QuicTime task_deadline_;
- base::WeakPtrFactory<QuicChromeAlarm> weak_factory_;
-};
-
-} // namespace
-
-QuicChromiumAlarmFactory::QuicChromiumAlarmFactory(
- base::TaskRunner* task_runner,
- const QuicClock* clock)
- : task_runner_(task_runner), clock_(clock), weak_factory_(this) {}
-
-QuicChromiumAlarmFactory::~QuicChromiumAlarmFactory() {}
-
-QuicArenaScopedPtr<QuicAlarm> QuicChromiumAlarmFactory::CreateAlarm(
- QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
- QuicConnectionArena* arena) {
- if (arena != nullptr) {
- return arena->New<QuicChromeAlarm>(clock_, task_runner_,
- std::move(delegate));
- } else {
- return QuicArenaScopedPtr<QuicAlarm>(
- new QuicChromeAlarm(clock_, task_runner_, std::move(delegate)));
- }
-}
-
-QuicAlarm* QuicChromiumAlarmFactory::CreateAlarm(
- QuicAlarm::Delegate* delegate) {
- return new QuicChromeAlarm(clock_, task_runner_,
- QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate));
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_chromium_alarm_factory.h b/chromium/net/quic/quic_chromium_alarm_factory.h
deleted file mode 100644
index 16345b7251b..00000000000
--- a/chromium/net/quic/quic_chromium_alarm_factory.h
+++ /dev/null
@@ -1,48 +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.
-//
-// The Chrome-specific helper for QuicConnection which uses
-// a TaskRunner for alarms, and uses a DatagramClientSocket for writing data.
-
-#ifndef NET_QUIC_QUIC_CHROMIUM_ALARM_FACTORY_H_
-#define NET_QUIC_QUIC_CHROMIUM_ALARM_FACTORY_H_
-
-#include <set>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "net/quic/quic_alarm_factory.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace base {
-class TaskRunner;
-} // namespace base
-
-namespace net {
-
-class NET_EXPORT_PRIVATE QuicChromiumAlarmFactory : public QuicAlarmFactory {
- public:
- QuicChromiumAlarmFactory(base::TaskRunner* task_runner,
- const QuicClock* clock);
- ~QuicChromiumAlarmFactory() override;
-
- // QuicAlarmFactory
- QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override;
- QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
- QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
- QuicConnectionArena* arena) override;
-
- private:
- base::TaskRunner* task_runner_;
- const QuicClock* clock_;
- base::WeakPtrFactory<QuicChromiumAlarmFactory> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicChromiumAlarmFactory);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CHROMIUM_ALARM_FACTORY_H_
diff --git a/chromium/net/quic/quic_chromium_alarm_factory_test.cc b/chromium/net/quic/quic_chromium_alarm_factory_test.cc
deleted file mode 100644
index d47c98eb34e..00000000000
--- a/chromium/net/quic/quic_chromium_alarm_factory_test.cc
+++ /dev/null
@@ -1,175 +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/quic_chromium_alarm_factory.h"
-
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/test_tools/test_task_runner.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-namespace {
-
-class TestDelegate : public QuicAlarm::Delegate {
- public:
- TestDelegate() : fired_(false) {}
-
- void OnAlarm() override { fired_ = true; }
-
- bool fired() const { return fired_; }
- void Clear() { fired_ = false; }
-
- private:
- bool fired_;
-};
-
-class QuicChromiumAlarmFactoryTest : public ::testing::Test {
- protected:
- QuicChromiumAlarmFactoryTest()
- : runner_(new TestTaskRunner(&clock_)),
- alarm_factory_(runner_.get(), &clock_) {}
-
- scoped_refptr<TestTaskRunner> runner_;
- QuicChromiumAlarmFactory alarm_factory_;
- MockClock clock_;
-};
-
-TEST_F(QuicChromiumAlarmFactoryTest, CreateAlarm) {
- TestDelegate* delegate = new TestDelegate();
- std::unique_ptr<QuicAlarm> alarm(alarm_factory_.CreateAlarm(delegate));
-
- QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
- alarm->Set(clock_.Now().Add(delta));
-
- // Verify that the alarm task has been posted.
- ASSERT_EQ(1u, runner_->GetPostedTasks().size());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()),
- runner_->GetPostedTasks()[0].delay);
-
- runner_->RunNextTask();
- EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.Now());
- EXPECT_TRUE(delegate->fired());
-}
-
-TEST_F(QuicChromiumAlarmFactoryTest, CreateAlarmAndCancel) {
- TestDelegate* delegate = new TestDelegate();
- std::unique_ptr<QuicAlarm> alarm(alarm_factory_.CreateAlarm(delegate));
-
- QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
- alarm->Set(clock_.Now().Add(delta));
- alarm->Cancel();
-
- // The alarm task should still be posted.
- ASSERT_EQ(1u, runner_->GetPostedTasks().size());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()),
- runner_->GetPostedTasks()[0].delay);
-
- runner_->RunNextTask();
- EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.Now());
- EXPECT_FALSE(delegate->fired());
-}
-
-TEST_F(QuicChromiumAlarmFactoryTest, CreateAlarmAndReset) {
- TestDelegate* delegate = new TestDelegate();
- std::unique_ptr<QuicAlarm> alarm(alarm_factory_.CreateAlarm(delegate));
-
- QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
- alarm->Set(clock_.Now().Add(delta));
- alarm->Cancel();
- QuicTime::Delta new_delta = QuicTime::Delta::FromMicroseconds(3);
- alarm->Set(clock_.Now().Add(new_delta));
-
- // The alarm task should still be posted.
- ASSERT_EQ(1u, runner_->GetPostedTasks().size());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()),
- runner_->GetPostedTasks()[0].delay);
-
- runner_->RunNextTask();
- EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.Now());
- EXPECT_FALSE(delegate->fired());
-
- // The alarm task should be posted again.
- ASSERT_EQ(1u, runner_->GetPostedTasks().size());
-
- runner_->RunNextTask();
- EXPECT_EQ(QuicTime::Zero().Add(new_delta), clock_.Now());
- EXPECT_TRUE(delegate->fired());
-}
-
-TEST_F(QuicChromiumAlarmFactoryTest, CreateAlarmAndResetEarlier) {
- TestDelegate* delegate = new TestDelegate();
- std::unique_ptr<QuicAlarm> alarm(alarm_factory_.CreateAlarm(delegate));
-
- QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(3);
- alarm->Set(clock_.Now().Add(delta));
- alarm->Cancel();
- QuicTime::Delta new_delta = QuicTime::Delta::FromMicroseconds(1);
- alarm->Set(clock_.Now().Add(new_delta));
-
- // Both alarm tasks will be posted.
- ASSERT_EQ(2u, runner_->GetPostedTasks().size());
-
- // The earlier task will execute and will fire the alarm->
- runner_->RunNextTask();
- EXPECT_EQ(QuicTime::Zero().Add(new_delta), clock_.Now());
- EXPECT_TRUE(delegate->fired());
- delegate->Clear();
-
- // The latter task is still posted.
- ASSERT_EQ(1u, runner_->GetPostedTasks().size());
-
- // When the latter task is executed, the weak ptr will be invalid and
- // the alarm will not fire.
- runner_->RunNextTask();
- EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.Now());
- EXPECT_FALSE(delegate->fired());
-}
-
-TEST_F(QuicChromiumAlarmFactoryTest, CreateAlarmAndUpdate) {
- TestDelegate* delegate = new TestDelegate();
- std::unique_ptr<QuicAlarm> alarm(alarm_factory_.CreateAlarm(delegate));
-
- QuicTime start = clock_.Now();
- QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
- alarm->Set(clock_.Now().Add(delta));
- QuicTime::Delta new_delta = QuicTime::Delta::FromMicroseconds(3);
- alarm->Update(clock_.Now().Add(new_delta),
- QuicTime::Delta::FromMicroseconds(1));
-
- // The alarm task should still be posted.
- ASSERT_EQ(1u, runner_->GetPostedTasks().size());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()),
- runner_->GetPostedTasks()[0].delay);
-
- runner_->RunNextTask();
- EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.Now());
- EXPECT_FALSE(delegate->fired());
-
- // Move the alarm forward 1us and ensure it doesn't move forward.
- alarm->Update(clock_.Now().Add(new_delta),
- QuicTime::Delta::FromMicroseconds(2));
-
- ASSERT_EQ(1u, runner_->GetPostedTasks().size());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(
- new_delta.Subtract(delta).ToMicroseconds()),
- runner_->GetPostedTasks()[0].delay);
- runner_->RunNextTask();
- EXPECT_EQ(start.Add(new_delta), clock_.Now());
- EXPECT_TRUE(delegate->fired());
-
- // Set the alarm via an update call.
- new_delta = QuicTime::Delta::FromMicroseconds(5);
- alarm->Update(clock_.Now().Add(new_delta),
- QuicTime::Delta::FromMicroseconds(1));
- EXPECT_TRUE(alarm->IsSet());
-
- // Update it with an uninitialized time and ensure it's cancelled.
- alarm->Update(QuicTime::Zero(), QuicTime::Delta::FromMicroseconds(1));
- EXPECT_FALSE(alarm->IsSet());
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_chromium_client_session.cc b/chromium/net/quic/quic_chromium_client_session.cc
deleted file mode 100644
index d789cad4cea..00000000000
--- a/chromium/net/quic/quic_chromium_client_session.cc
+++ /dev/null
@@ -1,1214 +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/quic_chromium_client_session.h"
-
-#include <utility>
-
-#include "base/callback_helpers.h"
-#include "base/location.h"
-#include "base/memory/ptr_util.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"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/values.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/base/network_activity_monitor.h"
-#include "net/http/http_log_util.h"
-#include "net/http/transport_security_state.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/crypto/quic_server_info.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_client_promised_info.h"
-#include "net/quic/quic_crypto_client_stream_factory.h"
-#include "net/quic/quic_stream_factory.h"
-#include "net/spdy/spdy_session.h"
-#include "net/ssl/channel_id_service.h"
-#include "net/ssl/ssl_connection_status_flags.h"
-#include "net/ssl/ssl_info.h"
-#include "net/ssl/token_binding.h"
-#include "net/udp/datagram_client_socket.h"
-
-namespace net {
-
-namespace {
-
-// The length of time to wait for a 0-RTT handshake to complete
-// before allowing the requests to possibly proceed over TCP.
-const int k0RttHandshakeTimeoutMs = 300;
-
-// IPv6 packets have an additional 20 bytes of overhead than IPv4 packets.
-const size_t kAdditionalOverheadForIPv6 = 20;
-
-// Maximum number of Readers that are created for any session due to
-// connection migration. A new Reader is created every time this endpoint's
-// IP address changes.
-const size_t kMaxReadersPerQuicSession = 5;
-
-// Size of the MRU cache of Token Binding signatures. Since the material being
-// signed is constant and there aren't many keys being used to sign, a fairly
-// small number was chosen, somewhat arbitrarily, and to match
-// SSLClientSocketImpl.
-const size_t kTokenBindingSignatureMapSize = 10;
-
-// Histograms for tracking down the crashes from http://crbug.com/354669
-// Note: these values must be kept in sync with the corresponding values in:
-// tools/metrics/histograms/histograms.xml
-enum Location {
- DESTRUCTOR = 0,
- ADD_OBSERVER = 1,
- TRY_CREATE_STREAM = 2,
- CREATE_OUTGOING_RELIABLE_STREAM = 3,
- NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER = 4,
- NOTIFY_FACTORY_OF_SESSION_CLOSED = 5,
- NUM_LOCATIONS = 6,
-};
-
-void RecordUnexpectedOpenStreams(Location location) {
- UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedOpenStreams", location,
- NUM_LOCATIONS);
-}
-
-void RecordUnexpectedObservers(Location location) {
- UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedObservers", location,
- NUM_LOCATIONS);
-}
-
-void RecordUnexpectedNotGoingAway(Location location) {
- UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.UnexpectedNotGoingAway", location,
- NUM_LOCATIONS);
-}
-
-// Histogram for recording the different reasons that a QUIC session is unable
-// to complete the handshake.
-enum HandshakeFailureReason {
- HANDSHAKE_FAILURE_UNKNOWN = 0,
- HANDSHAKE_FAILURE_BLACK_HOLE = 1,
- HANDSHAKE_FAILURE_PUBLIC_RESET = 2,
- NUM_HANDSHAKE_FAILURE_REASONS = 3,
-};
-
-void RecordHandshakeFailureReason(HandshakeFailureReason reason) {
- UMA_HISTOGRAM_ENUMERATION(
- "Net.QuicSession.ConnectionClose.HandshakeNotConfirmed.Reason", reason,
- NUM_HANDSHAKE_FAILURE_REASONS);
-}
-
-// Note: these values must be kept in sync with the corresponding values in:
-// tools/metrics/histograms/histograms.xml
-enum HandshakeState {
- STATE_STARTED = 0,
- STATE_ENCRYPTION_ESTABLISHED = 1,
- STATE_HANDSHAKE_CONFIRMED = 2,
- STATE_FAILED = 3,
- NUM_HANDSHAKE_STATES = 4
-};
-
-void RecordHandshakeState(HandshakeState state) {
- UMA_HISTOGRAM_ENUMERATION("Net.QuicHandshakeState", state,
- NUM_HANDSHAKE_STATES);
-}
-
-std::unique_ptr<base::Value> NetLogQuicClientSessionCallback(
- const QuicServerId* server_id,
- int cert_verify_flags,
- bool require_confirmation,
- NetLogCaptureMode /* capture_mode */) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetString("host", server_id->host());
- dict->SetInteger("port", server_id->port());
- dict->SetBoolean("privacy_mode",
- server_id->privacy_mode() == PRIVACY_MODE_ENABLED);
- dict->SetBoolean("require_confirmation", require_confirmation);
- dict->SetInteger("cert_verify_flags", cert_verify_flags);
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicPushPromiseReceivedCallback(
- const SpdyHeaderBlock* headers,
- SpdyStreamId stream_id,
- SpdyStreamId promised_stream_id,
- NetLogCaptureMode capture_mode) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->Set("headers", ElideSpdyHeaderBlockForNetLog(*headers, capture_mode));
- dict->SetInteger("id", stream_id);
- dict->SetInteger("promised_stream_id", promised_stream_id);
- return std::move(dict);
-}
-
-class HpackEncoderDebugVisitor : public QuicHeadersStream::HpackDebugVisitor {
- void OnUseEntry(QuicTime::Delta elapsed) override {
- UMA_HISTOGRAM_TIMES(
- "Net.QuicHpackEncoder.IndexedEntryAge",
- base::TimeDelta::FromMicroseconds(elapsed.ToMicroseconds()));
- }
-};
-
-class HpackDecoderDebugVisitor : public QuicHeadersStream::HpackDebugVisitor {
- void OnUseEntry(QuicTime::Delta elapsed) override {
- UMA_HISTOGRAM_TIMES(
- "Net.QuicHpackDecoder.IndexedEntryAge",
- base::TimeDelta::FromMicroseconds(elapsed.ToMicroseconds()));
- }
-};
-
-} // namespace
-
-QuicChromiumClientSession::StreamRequest::StreamRequest() : stream_(nullptr) {}
-
-QuicChromiumClientSession::StreamRequest::~StreamRequest() {
- CancelRequest();
-}
-
-int QuicChromiumClientSession::StreamRequest::StartRequest(
- const base::WeakPtr<QuicChromiumClientSession>& session,
- QuicChromiumClientStream** stream,
- const CompletionCallback& callback) {
- session_ = session;
- stream_ = stream;
- int rv = session_->TryCreateStream(this, stream_);
- if (rv == ERR_IO_PENDING) {
- callback_ = callback;
- }
-
- return rv;
-}
-
-void QuicChromiumClientSession::StreamRequest::CancelRequest() {
- if (session_)
- session_->CancelRequest(this);
- session_.reset();
- callback_.Reset();
-}
-
-void QuicChromiumClientSession::StreamRequest::OnRequestCompleteSuccess(
- QuicChromiumClientStream* stream) {
- session_.reset();
- *stream_ = stream;
- base::ResetAndReturn(&callback_).Run(OK);
-}
-
-void QuicChromiumClientSession::StreamRequest::OnRequestCompleteFailure(
- int rv) {
- session_.reset();
- base::ResetAndReturn(&callback_).Run(rv);
-}
-
-QuicChromiumClientSession::QuicChromiumClientSession(
- QuicConnection* connection,
- std::unique_ptr<DatagramClientSocket> socket,
- QuicStreamFactory* stream_factory,
- QuicCryptoClientStreamFactory* crypto_client_stream_factory,
- QuicClock* clock,
- TransportSecurityState* transport_security_state,
- std::unique_ptr<QuicServerInfo> server_info,
- const QuicServerId& server_id,
- int yield_after_packets,
- QuicTime::Delta yield_after_duration,
- int cert_verify_flags,
- const QuicConfig& config,
- QuicCryptoClientConfig* crypto_config,
- const char* const connection_description,
- base::TimeTicks dns_resolution_end_time,
- QuicClientPushPromiseIndex* push_promise_index,
- base::TaskRunner* task_runner,
- std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
- NetLog* net_log)
- : QuicClientSessionBase(connection, push_promise_index, config),
- server_id_(server_id),
- require_confirmation_(false),
- stream_factory_(stream_factory),
- transport_security_state_(transport_security_state),
- server_info_(std::move(server_info)),
- pkp_bypassed_(false),
- num_total_streams_(0),
- task_runner_(task_runner),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
- dns_resolution_end_time_(dns_resolution_end_time),
- logger_(new QuicConnectionLogger(this,
- connection_description,
- std::move(socket_performance_watcher),
- net_log_)),
- going_away_(false),
- port_migration_detected_(false),
- disabled_reason_(QUIC_DISABLED_NOT),
- token_binding_signatures_(kTokenBindingSignatureMapSize),
- streams_pushed_count_(0),
- streams_pushed_and_claimed_count_(0),
- weak_factory_(this) {
- sockets_.push_back(std::move(socket));
- packet_readers_.push_back(base::WrapUnique(new QuicChromiumPacketReader(
- sockets_.back().get(), clock, this, yield_after_packets,
- yield_after_duration, net_log_)));
- crypto_stream_.reset(
- crypto_client_stream_factory->CreateQuicCryptoClientStream(
- server_id, this, base::WrapUnique(new ProofVerifyContextChromium(
- cert_verify_flags, net_log_)),
- crypto_config));
- connection->set_debug_visitor(logger_.get());
- connection->set_creator_debug_delegate(logger_.get());
- net_log_.BeginEvent(NetLog::TYPE_QUIC_SESSION,
- base::Bind(NetLogQuicClientSessionCallback, &server_id,
- cert_verify_flags, require_confirmation_));
- IPEndPoint address;
- if (socket && socket->GetLocalAddress(&address) == OK &&
- address.GetFamily() == ADDRESS_FAMILY_IPV6) {
- connection->SetMaxPacketLength(connection->max_packet_length() -
- kAdditionalOverheadForIPv6);
- }
-}
-
-QuicChromiumClientSession::~QuicChromiumClientSession() {
- if (!dynamic_streams().empty())
- RecordUnexpectedOpenStreams(DESTRUCTOR);
- if (!observers_.empty())
- RecordUnexpectedObservers(DESTRUCTOR);
- if (!going_away_)
- RecordUnexpectedNotGoingAway(DESTRUCTOR);
-
- while (!dynamic_streams().empty() || !observers_.empty() ||
- !stream_requests_.empty()) {
- // The session must be closed before it is destroyed.
- DCHECK(dynamic_streams().empty());
- CloseAllStreams(ERR_UNEXPECTED);
- DCHECK(observers_.empty());
- CloseAllObservers(ERR_UNEXPECTED);
-
- connection()->set_debug_visitor(nullptr);
- net_log_.EndEvent(NetLog::TYPE_QUIC_SESSION);
-
- while (!stream_requests_.empty()) {
- StreamRequest* request = stream_requests_.front();
- stream_requests_.pop_front();
- request->OnRequestCompleteFailure(ERR_ABORTED);
- }
- }
-
- if (connection()->connected()) {
- // Ensure that the connection is closed by the time the session is
- // destroyed.
- connection()->CloseConnection(QUIC_INTERNAL_ERROR, "session torn down",
- ConnectionCloseBehavior::SILENT_CLOSE);
- }
-
- if (IsEncryptionEstablished())
- RecordHandshakeState(STATE_ENCRYPTION_ESTABLISHED);
- if (IsCryptoHandshakeConfirmed())
- RecordHandshakeState(STATE_HANDSHAKE_CONFIRMED);
- else
- RecordHandshakeState(STATE_FAILED);
-
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumTotalStreams", num_total_streams_);
- UMA_HISTOGRAM_COUNTS("Net.QuicNumSentClientHellos",
- crypto_stream_->num_sent_client_hellos());
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.Pushed", streams_pushed_count_);
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.PushedAndClaimed",
- streams_pushed_and_claimed_count_);
- if (!IsCryptoHandshakeConfirmed())
- return;
-
- // Sending one client_hello means we had zero handshake-round-trips.
- int round_trip_handshakes = crypto_stream_->num_sent_client_hellos() - 1;
-
- // Don't bother with these histogram during tests, which mock out
- // num_sent_client_hellos().
- if (round_trip_handshakes < 0 || !stream_factory_)
- return;
-
- bool port_selected = stream_factory_->enable_port_selection();
- SSLInfo ssl_info;
- // QUIC supports only secure urls.
- if (GetSSLInfo(&ssl_info) && ssl_info.cert.get()) {
- if (!port_selected) {
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.ConnectRandomPortForHTTPS",
- round_trip_handshakes, 0, 3, 4);
- if (require_confirmation_) {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Net.QuicSession.ConnectRandomPortRequiringConfirmationForHTTPS",
- round_trip_handshakes, 0, 3, 4);
- }
- }
- }
- const QuicConnectionStats stats = connection()->GetStats();
- if (server_info_ && stats.min_rtt_us > 0) {
- base::TimeTicks wait_for_data_start_time =
- server_info_->wait_for_data_start_time();
- base::TimeTicks wait_for_data_end_time =
- server_info_->wait_for_data_end_time();
- if (!wait_for_data_start_time.is_null() &&
- !wait_for_data_end_time.is_null()) {
- base::TimeDelta wait_time =
- wait_for_data_end_time - wait_for_data_start_time;
- const base::HistogramBase::Sample kMaxWaitToRtt = 1000;
- base::HistogramBase::Sample wait_to_rtt =
- static_cast<base::HistogramBase::Sample>(
- 100 * wait_time.InMicroseconds() / stats.min_rtt_us);
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicServerInfo.WaitForDataReadyToRtt",
- wait_to_rtt, 0, kMaxWaitToRtt, 50);
- }
- }
-
- // 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);
-
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.MtuProbesSent",
- connection()->mtu_probe_count());
-
- if (stats.max_sequence_reordering == 0)
- return;
- const base::HistogramBase::Sample kMaxReordering = 100;
- base::HistogramBase::Sample reordering = kMaxReordering;
- if (stats.min_rtt_us > 0) {
- reordering = static_cast<base::HistogramBase::Sample>(
- 100 * stats.max_time_reordering_us / stats.min_rtt_us);
- }
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTime", reordering,
- 0, kMaxReordering, 50);
- if (stats.min_rtt_us > 100 * 1000) {
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt",
- reordering, 0, kMaxReordering, 50);
- }
- UMA_HISTOGRAM_COUNTS(
- "Net.QuicSession.MaxReordering",
- static_cast<base::HistogramBase::Sample>(stats.max_sequence_reordering));
-}
-
-void QuicChromiumClientSession::Initialize() {
- QuicClientSessionBase::Initialize();
- headers_stream()->SetHpackEncoderDebugVisitor(
- base::WrapUnique(new HpackEncoderDebugVisitor()));
- headers_stream()->SetHpackDecoderDebugVisitor(
- base::WrapUnique(new HpackDecoderDebugVisitor()));
-}
-
-void QuicChromiumClientSession::OnHeadersHeadOfLineBlocking(
- QuicTime::Delta delta) {
- UMA_HISTOGRAM_TIMES(
- "Net.QuicSession.HeadersHOLBlockedTime",
- base::TimeDelta::FromMicroseconds(delta.ToMicroseconds()));
-}
-
-void QuicChromiumClientSession::OnStreamFrame(const QuicStreamFrame& frame) {
- // Record total number of stream frames.
- UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesInPacket", 1);
-
- // Record number of frames per stream in packet.
- UMA_HISTOGRAM_COUNTS("Net.QuicNumStreamFramesPerStreamInPacket", 1);
-
- return QuicSpdySession::OnStreamFrame(frame);
-}
-
-void QuicChromiumClientSession::AddObserver(Observer* observer) {
- if (going_away_) {
- RecordUnexpectedObservers(ADD_OBSERVER);
- observer->OnSessionClosed(ERR_UNEXPECTED, port_migration_detected_);
- return;
- }
-
- DCHECK(!ContainsKey(observers_, observer));
- observers_.insert(observer);
-}
-
-void QuicChromiumClientSession::RemoveObserver(Observer* observer) {
- DCHECK(ContainsKey(observers_, observer));
- observers_.erase(observer);
-}
-
-int QuicChromiumClientSession::TryCreateStream(
- StreamRequest* request,
- QuicChromiumClientStream** stream) {
- if (!crypto_stream_->encryption_established()) {
- DLOG(DFATAL) << "Encryption not established.";
- return ERR_CONNECTION_CLOSED;
- }
-
- if (goaway_received()) {
- DVLOG(1) << "Going away.";
- return ERR_CONNECTION_CLOSED;
- }
-
- if (!connection()->connected()) {
- DVLOG(1) << "Already closed.";
- return ERR_CONNECTION_CLOSED;
- }
-
- if (going_away_) {
- RecordUnexpectedOpenStreams(TRY_CREATE_STREAM);
- return ERR_CONNECTION_CLOSED;
- }
-
- if (GetNumOpenOutgoingStreams() < max_open_outgoing_streams()) {
- *stream = CreateOutgoingReliableStreamImpl();
- return OK;
- }
-
- stream_requests_.push_back(request);
- return ERR_IO_PENDING;
-}
-
-void QuicChromiumClientSession::CancelRequest(StreamRequest* request) {
- // Remove |request| from the queue while preserving the order of the
- // other elements.
- StreamRequestQueue::iterator it =
- std::find(stream_requests_.begin(), stream_requests_.end(), request);
- if (it != stream_requests_.end()) {
- it = stream_requests_.erase(it);
- }
-}
-
-bool QuicChromiumClientSession::ShouldCreateOutgoingDynamicStream() {
- if (!crypto_stream_->encryption_established()) {
- DVLOG(1) << "Encryption not active so no outgoing stream created.";
- return false;
- }
- if (GetNumOpenOutgoingStreams() >= max_open_outgoing_streams()) {
- DVLOG(1) << "Failed to create a new outgoing stream. "
- << "Already " << GetNumOpenOutgoingStreams() << " open.";
- return false;
- }
- if (goaway_received()) {
- DVLOG(1) << "Failed to create a new outgoing stream. "
- << "Already received goaway.";
- return false;
- }
- if (going_away_) {
- RecordUnexpectedOpenStreams(CREATE_OUTGOING_RELIABLE_STREAM);
- return false;
- }
- return true;
-}
-
-QuicChromiumClientStream*
-QuicChromiumClientSession::CreateOutgoingDynamicStream(SpdyPriority priority) {
- if (!ShouldCreateOutgoingDynamicStream()) {
- return nullptr;
- }
- return CreateOutgoingReliableStreamImpl();
-}
-
-QuicChromiumClientStream*
-QuicChromiumClientSession::CreateOutgoingReliableStreamImpl() {
- DCHECK(connection()->connected());
- QuicChromiumClientStream* stream =
- new QuicChromiumClientStream(GetNextOutgoingStreamId(), this, net_log_);
- ActivateStream(stream);
- ++num_total_streams_;
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.NumOpenStreams",
- GetNumOpenOutgoingStreams());
- // The previous histogram puts 100 in a bucket betweeen 86-113 which does
- // not shed light on if chrome ever things it has more than 100 streams open.
- UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.TooManyOpenStreams",
- GetNumOpenOutgoingStreams() > 100);
- return stream;
-}
-
-QuicCryptoClientStream* QuicChromiumClientSession::GetCryptoStream() {
- return crypto_stream_.get();
-}
-
-// TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
-// we learn about SSL info (sync vs async vs cached).
-bool QuicChromiumClientSession::GetSSLInfo(SSLInfo* ssl_info) const {
- ssl_info->Reset();
- if (!cert_verify_result_) {
- return false;
- }
-
- ssl_info->cert_status = cert_verify_result_->cert_status;
- ssl_info->cert = cert_verify_result_->verified_cert;
-
- // TODO(wtc): Define QUIC "cipher suites".
- // Report the TLS cipher suite that most closely resembles the crypto
- // parameters of the QUIC connection.
- QuicTag aead = crypto_stream_->crypto_negotiated_params().aead;
- uint16_t cipher_suite;
- int security_bits;
- switch (aead) {
- case kAESG:
- cipher_suite = 0xc02f; // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- security_bits = 128;
- break;
- case kCC20:
- cipher_suite = 0xcc13; // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
- security_bits = 256;
- break;
- default:
- NOTREACHED();
- return false;
- }
- int ssl_connection_status = 0;
- ssl_connection_status |= cipher_suite;
- ssl_connection_status |=
- (SSL_CONNECTION_VERSION_QUIC & SSL_CONNECTION_VERSION_MASK)
- << SSL_CONNECTION_VERSION_SHIFT;
-
- ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
- ssl_info->is_issued_by_known_root =
- cert_verify_result_->is_issued_by_known_root;
- ssl_info->pkp_bypassed = pkp_bypassed_;
-
- ssl_info->connection_status = ssl_connection_status;
- ssl_info->client_cert_sent = false;
- ssl_info->channel_id_sent = crypto_stream_->WasChannelIDSent();
- ssl_info->security_bits = security_bits;
- ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
- ssl_info->pinning_failure_log = pinning_failure_log_;
-
- ssl_info->UpdateCertificateTransparencyInfo(*ct_verify_result_);
-
- if (crypto_stream_->crypto_negotiated_params().token_binding_key_param ==
- kP256) {
- ssl_info->token_binding_negotiated = true;
- ssl_info->token_binding_key_param = TB_PARAM_ECDSAP256;
- }
-
- return true;
-}
-
-Error QuicChromiumClientSession::GetTokenBindingSignature(
- crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) {
- // The same key will be used across multiple requests to sign the same value,
- // so the signature is cached.
- std::string raw_public_key;
- if (!key->ExportRawPublicKey(&raw_public_key))
- return ERR_FAILED;
- TokenBindingSignatureMap::iterator it =
- token_binding_signatures_.Get(raw_public_key);
- if (it != token_binding_signatures_.end()) {
- *out = it->second;
- return OK;
- }
-
- std::string key_material;
- if (!crypto_stream_->ExportTokenBindingKeyingMaterial(&key_material))
- return ERR_FAILED;
- if (!SignTokenBindingEkm(key_material, key, out))
- return ERR_FAILED;
- token_binding_signatures_.Put(raw_public_key, *out);
- return OK;
-}
-
-int QuicChromiumClientSession::CryptoConnect(
- bool require_confirmation,
- const CompletionCallback& callback) {
- require_confirmation_ = require_confirmation;
- handshake_start_ = base::TimeTicks::Now();
- RecordHandshakeState(STATE_STARTED);
- DCHECK(flow_controller());
- crypto_stream_->CryptoConnect();
-
- if (IsCryptoHandshakeConfirmed())
- return OK;
-
- // Unless we require handshake confirmation, activate the session if
- // we have established initial encryption.
- if (!require_confirmation_ && IsEncryptionEstablished()) {
- // To mitigate the effects of hanging 0-RTT connections, set up a timer to
- // cancel any requests, if the handshake takes too long.
- task_runner_->PostDelayedTask(
- FROM_HERE, base::Bind(&QuicChromiumClientSession::OnConnectTimeout,
- weak_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(k0RttHandshakeTimeoutMs));
- return OK;
- }
-
- callback_ = callback;
- return ERR_IO_PENDING;
-}
-
-int QuicChromiumClientSession::ResumeCryptoConnect(
- const CompletionCallback& callback) {
- if (IsCryptoHandshakeConfirmed())
- return OK;
-
- if (!connection()->connected())
- return ERR_QUIC_HANDSHAKE_FAILED;
-
- callback_ = callback;
- return ERR_IO_PENDING;
-}
-
-int QuicChromiumClientSession::GetNumSentClientHellos() const {
- return crypto_stream_->num_sent_client_hellos();
-}
-
-bool QuicChromiumClientSession::CanPool(const std::string& hostname,
- PrivacyMode privacy_mode) const {
- DCHECK(connection()->connected());
- if (privacy_mode != server_id_.privacy_mode()) {
- // Privacy mode must always match.
- return false;
- }
- SSLInfo ssl_info;
- if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
- NOTREACHED() << "QUIC should always have certificates.";
- return false;
- }
-
- return SpdySession::CanPool(transport_security_state_, ssl_info,
- server_id_.host(), hostname);
-}
-
-bool QuicChromiumClientSession::ShouldCreateIncomingDynamicStream(
- QuicStreamId id) {
- if (!connection()->connected()) {
- LOG(DFATAL) << "ShouldCreateIncomingDynamicStream called when disconnected";
- return false;
- }
- if (goaway_received()) {
- DVLOG(1) << "Cannot create a new outgoing stream. "
- << "Already received goaway.";
- return false;
- }
- if (going_away_) {
- return false;
- }
- if (id % 2 != 0) {
- LOG(WARNING) << "Received invalid push stream id " << id;
- connection()->CloseConnection(
- QUIC_INVALID_STREAM_ID, "Server created odd numbered stream",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return false;
- }
- return true;
-}
-
-QuicChromiumClientStream*
-QuicChromiumClientSession::CreateIncomingDynamicStream(QuicStreamId id) {
- if (!ShouldCreateIncomingDynamicStream(id)) {
- return nullptr;
- }
- return CreateIncomingReliableStreamImpl(id);
-}
-
-QuicChromiumClientStream*
-QuicChromiumClientSession::CreateIncomingReliableStreamImpl(QuicStreamId id) {
- DCHECK(connection()->connected());
- QuicChromiumClientStream* stream =
- new QuicChromiumClientStream(id, this, net_log_);
- stream->CloseWriteSide();
- ActivateStream(stream);
- ++num_total_streams_;
- return stream;
-}
-
-void QuicChromiumClientSession::CloseStream(QuicStreamId stream_id) {
- ReliableQuicStream* stream = GetOrCreateStream(stream_id);
- if (stream) {
- logger_->UpdateReceivedFrameCounts(stream_id, stream->num_frames_received(),
- stream->num_duplicate_frames_received());
- }
- QuicSpdySession::CloseStream(stream_id);
- OnClosedStream();
-}
-
-void QuicChromiumClientSession::SendRstStream(QuicStreamId id,
- QuicRstStreamErrorCode error,
- QuicStreamOffset bytes_written) {
- QuicSpdySession::SendRstStream(id, error, bytes_written);
- OnClosedStream();
-}
-
-void QuicChromiumClientSession::OnClosedStream() {
- if (GetNumOpenOutgoingStreams() < max_open_outgoing_streams() &&
- !stream_requests_.empty() && crypto_stream_->encryption_established() &&
- !goaway_received() && !going_away_ && connection()->connected()) {
- StreamRequest* request = stream_requests_.front();
- stream_requests_.pop_front();
- request->OnRequestCompleteSuccess(CreateOutgoingReliableStreamImpl());
- }
-
- if (GetNumOpenOutgoingStreams() == 0 && stream_factory_) {
- stream_factory_->OnIdleSession(this);
- }
-}
-
-void QuicChromiumClientSession::OnCryptoHandshakeEvent(
- CryptoHandshakeEvent event) {
- if (stream_factory_ && event == HANDSHAKE_CONFIRMED &&
- (stream_factory_->OnHandshakeConfirmed(
- this, logger_->ReceivedPacketLossRate()))) {
- return;
- }
-
- if (!callback_.is_null() &&
- (!require_confirmation_ || event == HANDSHAKE_CONFIRMED ||
- event == ENCRYPTION_REESTABLISHED)) {
- // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
- // could be called because there are no error events in CryptoHandshakeEvent
- // enum. If error events are added to CryptoHandshakeEvent, then the
- // following code needs to changed.
- base::ResetAndReturn(&callback_).Run(OK);
- }
- if (event == HANDSHAKE_CONFIRMED) {
- UMA_HISTOGRAM_TIMES("Net.QuicSession.HandshakeConfirmedTime",
- base::TimeTicks::Now() - handshake_start_);
- if (server_info_) {
- // TODO(rtenneti): Should we delete this histogram?
- // Track how long it has taken to finish handshake once we start waiting
- // for reading of QUIC server information from disk cache. We could use
- // this data to compare total time taken if we were to cancel the disk
- // cache read vs waiting for the read to complete.
- base::TimeTicks wait_for_data_start_time =
- server_info_->wait_for_data_start_time();
- if (!wait_for_data_start_time.is_null()) {
- UMA_HISTOGRAM_TIMES(
- "Net.QuicServerInfo.WaitForDataReady.HandshakeConfirmedTime",
- base::TimeTicks::Now() - wait_for_data_start_time);
- }
- }
- // Track how long it has taken to finish handshake after we have finished
- // DNS host resolution.
- if (!dns_resolution_end_time_.is_null()) {
- UMA_HISTOGRAM_TIMES(
- "Net.QuicSession.HostResolution.HandshakeConfirmedTime",
- base::TimeTicks::Now() - dns_resolution_end_time_);
- }
-
- ObserverSet::iterator it = observers_.begin();
- while (it != observers_.end()) {
- Observer* observer = *it;
- ++it;
- observer->OnCryptoHandshakeConfirmed();
- }
- if (server_info_)
- server_info_->OnExternalCacheHit();
- }
- QuicSpdySession::OnCryptoHandshakeEvent(event);
-}
-
-void QuicChromiumClientSession::OnCryptoHandshakeMessageSent(
- const CryptoHandshakeMessage& message) {
- logger_->OnCryptoHandshakeMessageSent(message);
-
- if (message.tag() == kREJ || message.tag() == kSREJ) {
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.RejectLength",
- message.GetSerialized().length(), 1000, 10000,
- 50);
- }
-}
-
-void QuicChromiumClientSession::OnCryptoHandshakeMessageReceived(
- const CryptoHandshakeMessage& message) {
- logger_->OnCryptoHandshakeMessageReceived(message);
-}
-
-void QuicChromiumClientSession::OnGoAway(const QuicGoAwayFrame& frame) {
- QuicSession::OnGoAway(frame);
- NotifyFactoryOfSessionGoingAway();
- port_migration_detected_ = frame.error_code == QUIC_ERROR_MIGRATING_PORT;
-}
-
-void QuicChromiumClientSession::OnRstStream(const QuicRstStreamFrame& frame) {
- QuicSession::OnRstStream(frame);
- OnClosedStream();
-}
-
-void QuicChromiumClientSession::OnConnectionClosed(
- QuicErrorCode error,
- const std::string& error_details,
- ConnectionCloseSource source) {
- DCHECK(!connection()->connected());
- logger_->OnConnectionClosed(error, error_details, source);
- if (source == ConnectionCloseSource::FROM_PEER) {
- if (IsCryptoHandshakeConfirmed()) {
- UMA_HISTOGRAM_SPARSE_SLOWLY(
- "Net.QuicSession.ConnectionCloseErrorCodeServer.HandshakeConfirmed",
- error);
- base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
- "Net.QuicSession.StreamCloseErrorCodeServer.HandshakeConfirmed",
- base::HistogramBase::kUmaTargetedHistogramFlag);
- size_t num_streams = GetNumActiveStreams();
- if (num_streams > 0)
- histogram->AddCount(error, num_streams);
- }
- UMA_HISTOGRAM_SPARSE_SLOWLY(
- "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
- } else {
- if (IsCryptoHandshakeConfirmed()) {
- UMA_HISTOGRAM_SPARSE_SLOWLY(
- "Net.QuicSession.ConnectionCloseErrorCodeClient.HandshakeConfirmed",
- error);
- base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
- "Net.QuicSession.StreamCloseErrorCodeClient.HandshakeConfirmed",
- base::HistogramBase::kUmaTargetedHistogramFlag);
- size_t num_streams = GetNumActiveStreams();
- if (num_streams > 0)
- histogram->AddCount(error, num_streams);
- }
- UMA_HISTOGRAM_SPARSE_SLOWLY(
- "Net.QuicSession.ConnectionCloseErrorCodeClient", error);
- }
-
- if (error == QUIC_NETWORK_IDLE_TIMEOUT) {
- UMA_HISTOGRAM_COUNTS(
- "Net.QuicSession.ConnectionClose.NumOpenStreams.TimedOut",
- GetNumOpenOutgoingStreams());
- if (IsCryptoHandshakeConfirmed()) {
- if (GetNumOpenOutgoingStreams() > 0) {
- disabled_reason_ = QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS;
- UMA_HISTOGRAM_BOOLEAN(
- "Net.QuicSession.TimedOutWithOpenStreams.HasUnackedPackets",
- connection()->sent_packet_manager().HasUnackedPackets());
- UMA_HISTOGRAM_COUNTS(
- "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveRTOCount",
- connection()->sent_packet_manager().GetConsecutiveRtoCount());
- UMA_HISTOGRAM_COUNTS(
- "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
- connection()->sent_packet_manager().GetConsecutiveTlpCount());
- }
- if (connection()->sent_packet_manager().HasUnackedPackets()) {
- UMA_HISTOGRAM_TIMES(
- "Net.QuicSession.LocallyTimedOutWithOpenStreams."
- "TimeSinceLastReceived.UnackedPackets",
- NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
- } else {
- UMA_HISTOGRAM_TIMES(
- "Net.QuicSession.LocallyTimedOutWithOpenStreams."
- "TimeSinceLastReceived.NoUnackedPackets",
- NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
- }
-
- } else {
- UMA_HISTOGRAM_COUNTS(
- "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
- GetNumOpenOutgoingStreams());
- UMA_HISTOGRAM_COUNTS(
- "Net.QuicSession.ConnectionClose.NumTotalStreams.HandshakeTimedOut",
- num_total_streams_);
- }
- }
-
- if (!IsCryptoHandshakeConfirmed()) {
- if (error == QUIC_PUBLIC_RESET) {
- RecordHandshakeFailureReason(HANDSHAKE_FAILURE_PUBLIC_RESET);
- } else if (connection()->GetStats().packets_received == 0) {
- RecordHandshakeFailureReason(HANDSHAKE_FAILURE_BLACK_HOLE);
- UMA_HISTOGRAM_SPARSE_SLOWLY(
- "Net.QuicSession.ConnectionClose.HandshakeFailureBlackHole.QuicError",
- error);
- } else {
- RecordHandshakeFailureReason(HANDSHAKE_FAILURE_UNKNOWN);
- UMA_HISTOGRAM_SPARSE_SLOWLY(
- "Net.QuicSession.ConnectionClose.HandshakeFailureUnknown.QuicError",
- error);
- }
- } else if (error == QUIC_PUBLIC_RESET) {
- disabled_reason_ = QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE;
- }
-
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
- connection()->version());
- NotifyFactoryOfSessionGoingAway();
- QuicSession::OnConnectionClosed(error, error_details, source);
-
- if (!callback_.is_null()) {
- base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR);
- }
-
- for (auto& socket : sockets_) {
- socket->Close();
- }
- DCHECK(dynamic_streams().empty());
- CloseAllStreams(ERR_UNEXPECTED);
- CloseAllObservers(ERR_UNEXPECTED);
- NotifyFactoryOfSessionClosedLater();
-}
-
-void QuicChromiumClientSession::OnSuccessfulVersionNegotiation(
- const QuicVersion& version) {
- logger_->OnSuccessfulVersionNegotiation(version);
- QuicSpdySession::OnSuccessfulVersionNegotiation(version);
-}
-
-void QuicChromiumClientSession::OnPathDegrading() {
- if (stream_factory_) {
- stream_factory_->MaybeMigrateSessionEarly(this);
- }
-}
-
-bool QuicChromiumClientSession::HasOpenDynamicStreams() const {
- return QuicSession::HasOpenDynamicStreams() ||
- GetNumDrainingOutgoingStreams() > 0;
-}
-
-void QuicChromiumClientSession::OnProofValid(
- const QuicCryptoClientConfig::CachedState& cached) {
- DCHECK(cached.proof_valid());
-
- if (!server_info_) {
- return;
- }
-
- QuicServerInfo::State* state = server_info_->mutable_state();
-
- state->server_config = cached.server_config();
- state->source_address_token = cached.source_address_token();
- state->cert_sct = cached.cert_sct();
- state->chlo_hash = cached.chlo_hash();
- state->server_config_sig = cached.signature();
- state->certs = cached.certs();
-
- server_info_->Persist();
-}
-
-void QuicChromiumClientSession::OnProofVerifyDetailsAvailable(
- const ProofVerifyDetails& verify_details) {
- const ProofVerifyDetailsChromium* verify_details_chromium =
- reinterpret_cast<const ProofVerifyDetailsChromium*>(&verify_details);
- cert_verify_result_.reset(
- new CertVerifyResult(verify_details_chromium->cert_verify_result));
- pinning_failure_log_ = verify_details_chromium->pinning_failure_log;
- std::unique_ptr<ct::CTVerifyResult> ct_verify_result_copy(
- new ct::CTVerifyResult(verify_details_chromium->ct_verify_result));
- ct_verify_result_ = std::move(ct_verify_result_copy);
- logger_->OnCertificateVerified(*cert_verify_result_);
- pkp_bypassed_ = verify_details_chromium->pkp_bypassed;
-}
-
-void QuicChromiumClientSession::StartReading() {
- for (auto& packet_reader : packet_readers_) {
- packet_reader->StartReading();
- }
-}
-
-void QuicChromiumClientSession::CloseSessionOnError(int error,
- QuicErrorCode quic_error) {
- RecordAndCloseSessionOnError(error, quic_error);
- NotifyFactoryOfSessionClosed();
-}
-
-void QuicChromiumClientSession::CloseSessionOnErrorAndNotifyFactoryLater(
- int error,
- QuicErrorCode quic_error) {
- RecordAndCloseSessionOnError(error, quic_error);
- NotifyFactoryOfSessionClosedLater();
-}
-
-void QuicChromiumClientSession::RecordAndCloseSessionOnError(
- int error,
- QuicErrorCode quic_error) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseSessionOnError", -error);
- CloseSessionOnErrorInner(error, quic_error);
-}
-
-void QuicChromiumClientSession::CloseSessionOnErrorInner(
- int net_error,
- QuicErrorCode quic_error) {
- if (!callback_.is_null()) {
- base::ResetAndReturn(&callback_).Run(net_error);
- }
- CloseAllStreams(net_error);
- CloseAllObservers(net_error);
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_CLOSE_ON_ERROR,
- NetLog::IntCallback("net_error", net_error));
-
- if (connection()->connected())
- connection()->CloseConnection(quic_error, "net error",
- ConnectionCloseBehavior::SILENT_CLOSE);
- DCHECK(!connection()->connected());
-}
-
-void QuicChromiumClientSession::CloseAllStreams(int net_error) {
- while (!dynamic_streams().empty()) {
- ReliableQuicStream* stream = dynamic_streams().begin()->second;
- QuicStreamId id = stream->id();
- static_cast<QuicChromiumClientStream*>(stream)->OnError(net_error);
- CloseStream(id);
- }
-}
-
-void QuicChromiumClientSession::CloseAllObservers(int net_error) {
- while (!observers_.empty()) {
- Observer* observer = *observers_.begin();
- observers_.erase(observer);
- observer->OnSessionClosed(net_error, port_migration_detected_);
- }
-}
-
-std::unique_ptr<base::Value> QuicChromiumClientSession::GetInfoAsValue(
- const std::set<HostPortPair>& aliases) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetString("version", QuicVersionToString(connection()->version()));
- dict->SetInteger("open_streams", GetNumOpenOutgoingStreams());
- std::unique_ptr<base::ListValue> stream_list(new base::ListValue());
- for (StreamMap::const_iterator it = dynamic_streams().begin();
- it != dynamic_streams().end(); ++it) {
- stream_list->AppendString(base::UintToString(it->second->id()));
- }
- dict->Set("active_streams", std::move(stream_list));
-
- dict->SetInteger("total_streams", num_total_streams_);
- dict->SetString("peer_address", peer_address().ToString());
- dict->SetString("connection_id", base::Uint64ToString(connection_id()));
- dict->SetBoolean("connected", connection()->connected());
- const QuicConnectionStats& stats = connection()->GetStats();
- dict->SetInteger("packets_sent", stats.packets_sent);
- dict->SetInteger("packets_received", stats.packets_received);
- dict->SetInteger("packets_lost", stats.packets_lost);
- SSLInfo ssl_info;
- dict->SetBoolean("secure", GetSSLInfo(&ssl_info) && ssl_info.cert.get());
-
- std::unique_ptr<base::ListValue> alias_list(new base::ListValue());
- for (std::set<HostPortPair>::const_iterator it = aliases.begin();
- it != aliases.end(); it++) {
- alias_list->AppendString(it->ToString());
- }
- dict->Set("aliases", std::move(alias_list));
-
- return std::move(dict);
-}
-
-base::WeakPtr<QuicChromiumClientSession>
-QuicChromiumClientSession::GetWeakPtr() {
- return weak_factory_.GetWeakPtr();
-}
-
-void QuicChromiumClientSession::OnReadError(
- int result,
- const DatagramClientSocket* socket) {
- DCHECK(socket != nullptr);
- if (socket != GetDefaultSocket()) {
- // Ignore read errors from old sockets that are no longer active.
- // TODO(jri): Maybe clean up old sockets on error.
- return;
- }
- DVLOG(1) << "Closing session on read error: " << result;
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result);
- NotifyFactoryOfSessionGoingAway();
- CloseSessionOnErrorInner(result, QUIC_PACKET_READ_ERROR);
- NotifyFactoryOfSessionClosedLater();
-}
-
-bool QuicChromiumClientSession::OnPacket(const QuicReceivedPacket& packet,
- IPEndPoint local_address,
- IPEndPoint peer_address) {
- ProcessUdpPacket(local_address, peer_address, packet);
- if (!connection()->connected()) {
- NotifyFactoryOfSessionClosedLater();
- return false;
- }
- return true;
-}
-
-void QuicChromiumClientSession::NotifyFactoryOfSessionGoingAway() {
- going_away_ = true;
- if (stream_factory_)
- stream_factory_->OnSessionGoingAway(this);
-}
-
-void QuicChromiumClientSession::NotifyFactoryOfSessionClosedLater() {
- if (!dynamic_streams().empty())
- RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
-
- if (!going_away_)
- RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED_LATER);
-
- going_away_ = true;
- DCHECK_EQ(0u, GetNumActiveStreams());
- DCHECK(!connection()->connected());
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&QuicChromiumClientSession::NotifyFactoryOfSessionClosed,
- weak_factory_.GetWeakPtr()));
-}
-
-void QuicChromiumClientSession::NotifyFactoryOfSessionClosed() {
- if (!dynamic_streams().empty())
- RecordUnexpectedOpenStreams(NOTIFY_FACTORY_OF_SESSION_CLOSED);
-
- if (!going_away_)
- RecordUnexpectedNotGoingAway(NOTIFY_FACTORY_OF_SESSION_CLOSED);
-
- going_away_ = true;
- DCHECK_EQ(0u, GetNumActiveStreams());
- // Will delete |this|.
- if (stream_factory_)
- stream_factory_->OnSessionClosed(this);
-}
-
-void QuicChromiumClientSession::OnConnectTimeout() {
- DCHECK(callback_.is_null());
-
- if (IsCryptoHandshakeConfirmed())
- return;
-
- // TODO(rch): re-enable this code once beta is cut.
- // if (stream_factory_)
- // stream_factory_->OnSessionConnectTimeout(this);
- // CloseAllStreams(ERR_QUIC_HANDSHAKE_FAILED);
- // DCHECK_EQ(0u, GetNumOpenOutgoingStreams());
-}
-
-bool QuicChromiumClientSession::MigrateToSocket(
- std::unique_ptr<DatagramClientSocket> socket,
- std::unique_ptr<QuicChromiumPacketReader> reader,
- std::unique_ptr<QuicPacketWriter> writer) {
- DCHECK_EQ(sockets_.size(), packet_readers_.size());
- if (sockets_.size() >= kMaxReadersPerQuicSession) {
- return false;
- }
- // TODO(jri): Make SetQuicPacketWriter take a scoped_ptr.
- connection()->SetQuicPacketWriter(writer.release(), /*owns_writer=*/true);
- packet_readers_.push_back(std::move(reader));
- sockets_.push_back(std::move(socket));
- StartReading();
- connection()->SendPing();
- return true;
-}
-
-void QuicChromiumClientSession::PopulateNetErrorDetails(
- NetErrorDetails* details) {
- details->quic_port_migration_detected = port_migration_detected_;
-}
-
-const DatagramClientSocket* QuicChromiumClientSession::GetDefaultSocket()
- const {
- DCHECK(sockets_.back().get() != nullptr);
- // The most recently added socket is the currently active one.
- return sockets_.back().get();
-}
-
-bool QuicChromiumClientSession::IsAuthorized(const std::string& hostname) {
- bool result = CanPool(hostname, server_id_.privacy_mode());
- if (result)
- streams_pushed_count_++;
- return result;
-}
-
-bool QuicChromiumClientSession::HasNonMigratableStreams() const {
- for (const auto& stream : dynamic_streams()) {
- if (!static_cast<QuicChromiumClientStream*>(stream.second)->can_migrate())
- return true;
- }
- return false;
-}
-
-void QuicChromiumClientSession::HandlePromised(QuicStreamId id,
- QuicStreamId promised_id,
- const SpdyHeaderBlock& headers) {
- QuicClientSessionBase::HandlePromised(id, promised_id, headers);
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PUSH_PROMISE_RECEIVED,
- base::Bind(&NetLogQuicPushPromiseReceivedCallback, &headers,
- id, promised_id));
-}
-
-void QuicChromiumClientSession::DeletePromised(
- QuicClientPromisedInfo* promised) {
- if (IsOpenStream(promised->id()))
- streams_pushed_and_claimed_count_++;
- QuicClientSessionBase::DeletePromised(promised);
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_chromium_client_session.h b/chromium/net/quic/quic_chromium_client_session.h
deleted file mode 100644
index c6c84dbd06a..00000000000
--- a/chromium/net/quic/quic_chromium_client_session.h
+++ /dev/null
@@ -1,364 +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.
-//
-// A client specific QuicSession subclass. This class owns the underlying
-// QuicConnection and QuicConnectionHelper objects. The connection stores
-// a non-owning pointer to the helper so this session needs to ensure that
-// the helper outlives the connection.
-
-#ifndef NET_QUIC_QUIC_CHROMIUM_CLIENT_SESSION_H_
-#define NET_QUIC_QUIC_CHROMIUM_CLIENT_SESSION_H_
-
-#include <stddef.h>
-
-#include <list>
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/containers/mru_cache.h"
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "net/base/completion_callback.h"
-#include "net/base/net_error_details.h"
-#include "net/cert/ct_verify_result.h"
-#include "net/proxy/proxy_server.h"
-#include "net/quic/quic_chromium_client_stream.h"
-#include "net/quic/quic_chromium_packet_reader.h"
-#include "net/quic/quic_client_session_base.h"
-#include "net/quic/quic_connection_logger.h"
-#include "net/quic/quic_crypto_client_stream.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_id.h"
-#include "net/quic/quic_time.h"
-#include "net/socket/socket_performance_watcher.h"
-
-namespace net {
-
-class CertVerifyResult;
-class DatagramClientSocket;
-class QuicCryptoClientStreamFactory;
-class QuicServerInfo;
-class QuicStreamFactory;
-class SSLInfo;
-class TransportSecurityState;
-
-using TokenBindingSignatureMap =
- base::MRUCache<std::string, std::vector<uint8_t>>;
-
-namespace test {
-class QuicChromiumClientSessionPeer;
-} // namespace test
-
-class NET_EXPORT_PRIVATE QuicChromiumClientSession
- : public QuicClientSessionBase,
- public QuicChromiumPacketReader::Visitor {
- public:
- // Reasons to disable QUIC, that is under certain pathological
- // connection errors. Note: these values must be kept in sync with
- // the corresponding values of QuicDisabledReason in:
- // tools/metrics/histograms/histograms.xml
- enum QuicDisabledReason {
- QUIC_DISABLED_NOT = 0, // default, not disabled
- QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE = 1,
- QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS = 2,
- QUIC_DISABLED_BAD_PACKET_LOSS_RATE = 3,
- QUIC_DISABLED_MAX = 4,
- };
-
- // An interface for observing events on a session.
- class NET_EXPORT_PRIVATE Observer {
- public:
- virtual ~Observer() {}
- virtual void OnCryptoHandshakeConfirmed() = 0;
- virtual void OnSessionClosed(int error, bool port_migration_detected) = 0;
- };
-
- // A helper class used to manage a request to create a stream.
- class NET_EXPORT_PRIVATE StreamRequest {
- public:
- StreamRequest();
- ~StreamRequest();
-
- // Starts a request to create a stream. If OK is returned, then
- // |stream| will be updated with the newly created stream. If
- // ERR_IO_PENDING is returned, then when the request is eventuallly
- // complete |callback| will be called.
- int StartRequest(const base::WeakPtr<QuicChromiumClientSession>& session,
- QuicChromiumClientStream** stream,
- const CompletionCallback& callback);
-
- // Cancels any pending stream creation request. May be called
- // repeatedly.
- void CancelRequest();
-
- private:
- friend class QuicChromiumClientSession;
-
- // Called by |session_| for an asynchronous request when the stream
- // request has finished successfully.
- void OnRequestCompleteSuccess(QuicChromiumClientStream* stream);
-
- // Called by |session_| for an asynchronous request when the stream
- // request has finished with an error. Also called with ERR_ABORTED
- // if |session_| is destroyed while the stream request is still pending.
- void OnRequestCompleteFailure(int rv);
-
- base::WeakPtr<QuicChromiumClientSession> session_;
- CompletionCallback callback_;
- QuicChromiumClientStream** stream_;
-
- DISALLOW_COPY_AND_ASSIGN(StreamRequest);
- };
-
- // Constructs a new session which will own |connection|, but not
- // |stream_factory|, which must outlive this session.
- // TODO(rch): decouple the factory from the session via a Delegate interface.
- QuicChromiumClientSession(
- QuicConnection* connection,
- std::unique_ptr<DatagramClientSocket> socket,
- QuicStreamFactory* stream_factory,
- QuicCryptoClientStreamFactory* crypto_client_stream_factory,
- QuicClock* clock,
- TransportSecurityState* transport_security_state,
- std::unique_ptr<QuicServerInfo> server_info,
- const QuicServerId& server_id,
- int yield_after_packets,
- QuicTime::Delta yield_after_duration,
- int cert_verify_flags,
- const QuicConfig& config,
- QuicCryptoClientConfig* crypto_config,
- const char* const connection_description,
- base::TimeTicks dns_resolution_end_time,
- QuicClientPushPromiseIndex* push_promise_index,
- base::TaskRunner* task_runner,
- std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
- NetLog* net_log);
- ~QuicChromiumClientSession() override;
-
- void Initialize() override;
-
- void AddObserver(Observer* observer);
- void RemoveObserver(Observer* observer);
-
- // Attempts to create a new stream. If the stream can be
- // created immediately, returns OK. If the open stream limit
- // has been reached, returns ERR_IO_PENDING, and |request|
- // will be added to the stream requets queue and will
- // be completed asynchronously.
- // TODO(rch): remove |stream| from this and use setter on |request|
- // and fix in spdy too.
- int TryCreateStream(StreamRequest* request,
- QuicChromiumClientStream** stream);
-
- // Cancels the pending stream creation request.
- void CancelRequest(StreamRequest* request);
-
- // QuicSpdySession methods:
- void OnHeadersHeadOfLineBlocking(QuicTime::Delta delta) override;
-
- // QuicSession methods:
- void OnStreamFrame(const QuicStreamFrame& frame) override;
- QuicChromiumClientStream* CreateOutgoingDynamicStream(
- SpdyPriority priority) override;
- QuicCryptoClientStream* GetCryptoStream() override;
- void CloseStream(QuicStreamId stream_id) override;
- void SendRstStream(QuicStreamId id,
- QuicRstStreamErrorCode error,
- QuicStreamOffset bytes_written) override;
- void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override;
- void OnCryptoHandshakeMessageSent(
- const CryptoHandshakeMessage& message) override;
- void OnCryptoHandshakeMessageReceived(
- const CryptoHandshakeMessage& message) override;
- void OnGoAway(const QuicGoAwayFrame& frame) override;
- void OnRstStream(const QuicRstStreamFrame& frame) override;
-
- // QuicClientSessionBase methods:
- void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override;
- void OnProofVerifyDetailsAvailable(
- const ProofVerifyDetails& verify_details) override;
-
- // QuicConnectionVisitorInterface methods:
- void OnConnectionClosed(QuicErrorCode error,
- const std::string& error_details,
- ConnectionCloseSource source) override;
- void OnSuccessfulVersionNegotiation(const QuicVersion& version) override;
- void OnPathDegrading() override;
- bool HasOpenDynamicStreams() const override;
-
- // QuicChromiumPacketReader::Visitor methods:
- void OnReadError(int result, const DatagramClientSocket* socket) override;
- bool OnPacket(const QuicReceivedPacket& packet,
- IPEndPoint local_address,
- IPEndPoint peer_address) override;
-
- // Gets the SSL connection information.
- bool GetSSLInfo(SSLInfo* ssl_info) const;
-
- // Signs the exported keying material used for Token Binding using key |*key|
- // and puts the signature in |*out|. Returns a net error code.
- Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out);
-
- // Performs a crypto handshake with the server.
- int CryptoConnect(bool require_confirmation,
- const CompletionCallback& callback);
-
- // Resumes a crypto handshake with the server after a timeout.
- int ResumeCryptoConnect(const CompletionCallback& callback);
-
- // Causes the QuicConnectionHelper to start reading from all sockets
- // and passing the data along to the QuicConnection.
- void StartReading();
-
- // Close the session because of |error| and notifies the factory
- // that this session has been closed, which will delete the session.
- void CloseSessionOnError(int error, QuicErrorCode quic_error);
-
- // Close the session because of |error| and notifies the factory later that
- // this session has been closed, which will delete the session.
- void CloseSessionOnErrorAndNotifyFactoryLater(int error,
- QuicErrorCode quic_error);
-
- std::unique_ptr<base::Value> GetInfoAsValue(
- const std::set<HostPortPair>& aliases);
-
- const BoundNetLog& net_log() const { return net_log_; }
-
- base::WeakPtr<QuicChromiumClientSession> GetWeakPtr();
-
- // 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
- // than the number of round-trips needed for the handshake.
- int GetNumSentClientHellos() const;
-
- // Returns true if |hostname| may be pooled onto this session. If this
- // is a secure QUIC session, then |hostname| must match the certificate
- // presented during the handshake.
- bool CanPool(const std::string& hostname, PrivacyMode privacy_mode) const;
-
- const QuicServerId& server_id() const { return server_id_; }
-
- QuicDisabledReason disabled_reason() const { return disabled_reason_; }
-
- // Migrates session onto new socket, i.e., starts reading from |socket|
- // in addition to any previous sockets, and sets |writer| to be the new
- // default writer. Returns true if socket was successfully added to the
- // session and the session was successfully migrated to using the new socket.
- // Returns false if number of migrations exceeds kMaxReadersPerQuicSession.
- // Takes ownership of |socket|, |reader|, and |writer|.
- bool MigrateToSocket(std::unique_ptr<DatagramClientSocket> socket,
- std::unique_ptr<QuicChromiumPacketReader> reader,
- std::unique_ptr<QuicPacketWriter> writer);
-
- // Populates network error details for this session.
- void PopulateNetErrorDetails(NetErrorDetails* details);
-
- // Returns current default socket. This is the socket over which all
- // QUIC packets are sent. This default socket can change, so do not store the
- // returned socket.
- const DatagramClientSocket* GetDefaultSocket() const;
-
- bool IsAuthorized(const std::string& hostname) override;
-
- // Returns true if session has one ore more streams marked as non-migratable.
- bool HasNonMigratableStreams() const;
-
- void HandlePromised(QuicStreamId associated_id,
- QuicStreamId promised_id,
- const SpdyHeaderBlock& headers) override;
-
- void DeletePromised(QuicClientPromisedInfo* promised) override;
-
- protected:
- // QuicSession methods:
- bool ShouldCreateIncomingDynamicStream(QuicStreamId id) override;
- bool ShouldCreateOutgoingDynamicStream() override;
-
- QuicChromiumClientStream* CreateIncomingDynamicStream(
- QuicStreamId id) override;
-
- private:
- friend class test::QuicChromiumClientSessionPeer;
-
- typedef std::set<Observer*> ObserverSet;
- typedef std::list<StreamRequest*> StreamRequestQueue;
-
- QuicChromiumClientStream* CreateOutgoingReliableStreamImpl();
- QuicChromiumClientStream* CreateIncomingReliableStreamImpl(QuicStreamId id);
- // A completion callback invoked when a read completes.
- void OnReadComplete(int result);
-
- void OnClosedStream();
-
- // Close the session because of |error| and records it in UMA histogram.
- void RecordAndCloseSessionOnError(int error, QuicErrorCode quic_error);
-
- // A Session may be closed via any of three methods:
- // OnConnectionClosed - called by the connection when the connection has been
- // closed, perhaps due to a timeout or a protocol error.
- // CloseSessionOnError - called from the owner of the session,
- // the QuicStreamFactory, when there is an error.
- // OnReadComplete - when there is a read error.
- // This method closes all stream and performs any necessary cleanup.
- void CloseSessionOnErrorInner(int net_error, QuicErrorCode quic_error);
-
- void CloseAllStreams(int net_error);
- void CloseAllObservers(int net_error);
-
- // Notifies the factory that this session is going away and no more streams
- // should be created from it. This needs to be called before closing any
- // streams, because closing a stream may cause a new stream to be created.
- void NotifyFactoryOfSessionGoingAway();
-
- // Posts a task to notify the factory that this session has been closed.
- void NotifyFactoryOfSessionClosedLater();
-
- // Notifies the factory that this session has been closed which will
- // delete |this|.
- void NotifyFactoryOfSessionClosed();
-
- void OnConnectTimeout();
-
- QuicServerId server_id_;
- bool require_confirmation_;
- std::unique_ptr<QuicCryptoClientStream> crypto_stream_;
- QuicStreamFactory* stream_factory_;
- std::vector<std::unique_ptr<DatagramClientSocket>> sockets_;
- TransportSecurityState* transport_security_state_;
- std::unique_ptr<QuicServerInfo> server_info_;
- std::unique_ptr<CertVerifyResult> cert_verify_result_;
- std::unique_ptr<ct::CTVerifyResult> ct_verify_result_;
- std::string pinning_failure_log_;
- bool pkp_bypassed_;
- ObserverSet observers_;
- StreamRequestQueue stream_requests_;
- CompletionCallback callback_;
- size_t num_total_streams_;
- base::TaskRunner* task_runner_;
- BoundNetLog net_log_;
- std::vector<std::unique_ptr<QuicChromiumPacketReader>> packet_readers_;
- base::TimeTicks dns_resolution_end_time_;
- base::TimeTicks handshake_start_; // Time the handshake was started.
- std::unique_ptr<QuicConnectionLogger> logger_;
- // True when the session is going away, and streams may no longer be created
- // on this session. Existing stream will continue to be processed.
- bool going_away_;
- // True when the session receives a go away from server due to port migration.
- bool port_migration_detected_;
- QuicDisabledReason disabled_reason_;
- TokenBindingSignatureMap token_binding_signatures_;
- // UMA histogram counters for streams pushed to this session.
- int streams_pushed_count_;
- int streams_pushed_and_claimed_count_;
- base::WeakPtrFactory<QuicChromiumClientSession> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicChromiumClientSession);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CHROMIUM_CLIENT_SESSION_H_
diff --git a/chromium/net/quic/quic_chromium_client_session_test.cc b/chromium/net/quic/quic_chromium_client_session_test.cc
deleted file mode 100644
index 9a189b2c35f..00000000000
--- a/chromium/net/quic/quic_chromium_client_session_test.cc
+++ /dev/null
@@ -1,555 +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/quic_chromium_client_session.h"
-
-#include "base/base64.h"
-#include "base/files/file_path.h"
-#include "base/memory/ptr_util.h"
-#include "base/rand_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "net/base/test_completion_callback.h"
-#include "net/cert/cert_verify_result.h"
-#include "net/http/transport_security_state.h"
-#include "net/log/test_net_log.h"
-#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/crypto/quic_server_info.h"
-#include "net/quic/quic_chromium_alarm_factory.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_chromium_packet_reader.h"
-#include "net/quic/quic_chromium_packet_writer.h"
-#include "net/quic/quic_crypto_client_stream_factory.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_http_utils.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
-#include "net/quic/test_tools/quic_chromium_client_session_peer.h"
-#include "net/quic/test_tools/quic_spdy_session_peer.h"
-#include "net/quic/test_tools/quic_test_packet_maker.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/quic/test_tools/simple_quic_framer.h"
-#include "net/socket/socket_test_util.h"
-#include "net/spdy/spdy_test_utils.h"
-#include "net/test/cert_test_util.h"
-#include "net/test/test_data_directory.h"
-#include "net/udp/datagram_client_socket.h"
-
-using testing::_;
-
-namespace net {
-namespace test {
-namespace {
-
-const IPEndPoint kIpEndPoint = IPEndPoint(IPAddress::IPv4AllZeros(), 0);
-const char kServerHostname[] = "test.example.com";
-const uint16_t kServerPort = 443;
-const size_t kMaxReadersPerQuicSession = 5;
-
-class QuicChromiumClientSessionTest
- : public ::testing::TestWithParam<QuicVersion> {
- protected:
- QuicChromiumClientSessionTest()
- : crypto_config_(CryptoTestUtils::ProofVerifierForTesting()),
- default_read_(new MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)),
- socket_data_(
- new SequencedSocketData(default_read_.get(), 1, nullptr, 0)),
- random_(0),
- helper_(&clock_, &random_),
- alarm_factory_(base::ThreadTaskRunnerHandle::Get().get(), &clock_),
- client_maker_(GetParam(),
- 0,
- &clock_,
- kServerHostname,
- Perspective::IS_CLIENT),
- server_maker_(GetParam(),
- 0,
- &clock_,
- kServerHostname,
- Perspective::IS_SERVER) {
- // Advance the time, because timers do not like uninitialized times.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- }
-
- void Initialize() {
- socket_factory_.AddSocketDataProvider(socket_data_.get());
- std::unique_ptr<DatagramClientSocket> socket =
- socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND,
- base::Bind(&base::RandInt),
- &net_log_, NetLog::Source());
- socket->Connect(kIpEndPoint);
- QuicChromiumPacketWriter* writer =
- new net::QuicChromiumPacketWriter(socket.get());
- QuicConnection* connection = new QuicConnection(
- 0, kIpEndPoint, &helper_, &alarm_factory_, writer, true,
- Perspective::IS_CLIENT, SupportedVersions(GetParam()));
- writer->SetConnection(connection);
- session_.reset(new QuicChromiumClientSession(
- connection, std::move(socket),
- /*stream_factory=*/nullptr, &crypto_client_stream_factory_, &clock_,
- &transport_security_state_,
- base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)),
- QuicServerId(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED),
- kQuicYieldAfterPacketsRead,
- QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds),
- /*cert_verify_flags=*/0, DefaultQuicConfig(), &crypto_config_,
- "CONNECTION_UNKNOWN", base::TimeTicks::Now(), &push_promise_index_,
- base::ThreadTaskRunnerHandle::Get().get(),
- /*socket_performance_watcher=*/nullptr, &net_log_));
-
- scoped_refptr<X509Certificate> cert(
- ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"));
- verify_details_.cert_verify_result.verified_cert = cert;
- verify_details_.cert_verify_result.is_issued_by_known_root = true;
- session_->Initialize();
- session_->StartReading();
- }
-
- void TearDown() override {
- session_->CloseSessionOnError(ERR_ABORTED, QUIC_INTERNAL_ERROR);
- }
-
- void CompleteCryptoHandshake() {
- ASSERT_EQ(OK, session_->CryptoConnect(false, callback_.callback()));
- }
-
- QuicPacketWriter* CreateQuicPacketWriter(DatagramClientSocket* socket,
- QuicConnection* connection) const {
- std::unique_ptr<QuicChromiumPacketWriter> writer(
- new QuicChromiumPacketWriter(socket));
- writer->SetConnection(connection);
- return writer.release();
- }
-
- QuicCryptoClientConfig crypto_config_;
- TestNetLog net_log_;
- BoundTestNetLog bound_net_log_;
- MockClientSocketFactory socket_factory_;
- std::unique_ptr<MockRead> default_read_;
- std::unique_ptr<SequencedSocketData> socket_data_;
- MockClock clock_;
- MockRandom random_;
- QuicChromiumConnectionHelper helper_;
- QuicChromiumAlarmFactory alarm_factory_;
- TransportSecurityState transport_security_state_;
- MockCryptoClientStreamFactory crypto_client_stream_factory_;
- std::unique_ptr<QuicChromiumClientSession> session_;
- QuicConnectionVisitorInterface* visitor_;
- TestCompletionCallback callback_;
- QuicTestPacketMaker client_maker_;
- QuicTestPacketMaker server_maker_;
- ProofVerifyDetailsChromium verify_details_;
- QuicClientPushPromiseIndex push_promise_index_;
-};
-
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicChromiumClientSessionTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
-
-TEST_P(QuicChromiumClientSessionTest, CryptoConnect) {
- Initialize();
- CompleteCryptoHandshake();
-}
-
-TEST_P(QuicChromiumClientSessionTest, MaxNumStreams) {
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
- 1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT));
- MockWrite writes[] = {
- MockWrite(ASYNC, client_rst->data(), client_rst->length(), 1)};
- socket_data_.reset(new SequencedSocketData(reads, arraysize(reads), writes,
- arraysize(writes)));
-
- Initialize();
- CompleteCryptoHandshake();
- const size_t kMaxOpenStreams = session_->max_open_outgoing_streams();
-
- std::vector<QuicChromiumClientStream*> streams;
- for (size_t i = 0; i < kMaxOpenStreams; i++) {
- QuicChromiumClientStream* stream =
- session_->CreateOutgoingDynamicStream(kDefaultPriority);
- EXPECT_TRUE(stream);
- streams.push_back(stream);
- }
- EXPECT_FALSE(session_->CreateOutgoingDynamicStream(kDefaultPriority));
-
- EXPECT_EQ(kMaxOpenStreams, session_->GetNumOpenOutgoingStreams());
-
- // Close a stream and ensure I can now open a new one.
- QuicStreamId stream_id = streams[0]->id();
- session_->CloseStream(stream_id);
-
- EXPECT_FALSE(session_->CreateOutgoingDynamicStream(kDefaultPriority));
- QuicRstStreamFrame rst1(stream_id, QUIC_STREAM_NO_ERROR, 0);
- session_->OnRstStream(rst1);
- EXPECT_EQ(kMaxOpenStreams - 1, session_->GetNumOpenOutgoingStreams());
- EXPECT_TRUE(session_->CreateOutgoingDynamicStream(kDefaultPriority));
-}
-
-TEST_P(QuicChromiumClientSessionTest, MaxNumStreamsViaRequest) {
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
- 1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT));
- MockWrite writes[] = {
- MockWrite(ASYNC, client_rst->data(), client_rst->length(), 1)};
- socket_data_.reset(new SequencedSocketData(reads, arraysize(reads), writes,
- arraysize(writes)));
-
- Initialize();
- CompleteCryptoHandshake();
- const size_t kMaxOpenStreams = session_->max_open_outgoing_streams();
-
- std::vector<QuicChromiumClientStream*> streams;
- for (size_t i = 0; i < kMaxOpenStreams; i++) {
- QuicChromiumClientStream* stream =
- session_->CreateOutgoingDynamicStream(kDefaultPriority);
- EXPECT_TRUE(stream);
- streams.push_back(stream);
- }
-
- QuicChromiumClientStream* stream;
- QuicChromiumClientSession::StreamRequest stream_request;
- TestCompletionCallback callback;
- ASSERT_EQ(ERR_IO_PENDING,
- stream_request.StartRequest(session_->GetWeakPtr(), &stream,
- callback.callback()));
-
- // Close a stream and ensure I can now open a new one.
- QuicStreamId stream_id = streams[0]->id();
- session_->CloseStream(stream_id);
- QuicRstStreamFrame rst1(stream_id, QUIC_STREAM_NO_ERROR, 0);
- session_->OnRstStream(rst1);
- ASSERT_TRUE(callback.have_result());
- EXPECT_EQ(OK, callback.WaitForResult());
- EXPECT_TRUE(stream != nullptr);
-}
-
-TEST_P(QuicChromiumClientSessionTest, GoAwayReceived) {
- Initialize();
- CompleteCryptoHandshake();
-
- // After receiving a GoAway, I should no longer be able to create outgoing
- // streams.
- session_->connection()->OnGoAwayFrame(
- QuicGoAwayFrame(QUIC_PEER_GOING_AWAY, 1u, "Going away."));
- EXPECT_EQ(nullptr, session_->CreateOutgoingDynamicStream(kDefaultPriority));
-}
-
-TEST_P(QuicChromiumClientSessionTest, CanPool) {
- Initialize();
- // Load a cert that is valid for:
- // www.example.org
- // mail.example.org
- // www.example.com
-
- ProofVerifyDetailsChromium details;
- details.cert_verify_result.verified_cert =
- ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
- ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
-
- CompleteCryptoHandshake();
- session_->OnProofVerifyDetailsAvailable(details);
-
- EXPECT_TRUE(session_->CanPool("www.example.org", PRIVACY_MODE_DISABLED));
- EXPECT_FALSE(session_->CanPool("www.example.org", PRIVACY_MODE_ENABLED));
- EXPECT_TRUE(session_->CanPool("mail.example.org", PRIVACY_MODE_DISABLED));
- EXPECT_TRUE(session_->CanPool("mail.example.com", PRIVACY_MODE_DISABLED));
- EXPECT_FALSE(session_->CanPool("mail.google.com", PRIVACY_MODE_DISABLED));
-}
-
-TEST_P(QuicChromiumClientSessionTest, ConnectionPooledWithTlsChannelId) {
- Initialize();
- // Load a cert that is valid for:
- // www.example.org
- // mail.example.org
- // www.example.com
-
- ProofVerifyDetailsChromium details;
- details.cert_verify_result.verified_cert =
- ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
- ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
-
- CompleteCryptoHandshake();
- session_->OnProofVerifyDetailsAvailable(details);
- QuicChromiumClientSessionPeer::SetHostname(session_.get(), "www.example.org");
- QuicChromiumClientSessionPeer::SetChannelIDSent(session_.get(), true);
-
- EXPECT_TRUE(session_->CanPool("www.example.org", PRIVACY_MODE_DISABLED));
- EXPECT_TRUE(session_->CanPool("mail.example.org", PRIVACY_MODE_DISABLED));
- EXPECT_FALSE(session_->CanPool("mail.example.com", PRIVACY_MODE_DISABLED));
- EXPECT_FALSE(session_->CanPool("mail.google.com", PRIVACY_MODE_DISABLED));
-}
-
-TEST_P(QuicChromiumClientSessionTest, ConnectionNotPooledWithDifferentPin) {
- Initialize();
-
- uint8_t primary_pin = 1;
- uint8_t backup_pin = 2;
- uint8_t bad_pin = 3;
- AddPin(&transport_security_state_, "mail.example.org", primary_pin,
- backup_pin);
-
- ProofVerifyDetailsChromium details;
- details.cert_verify_result.verified_cert =
- ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
- details.cert_verify_result.is_issued_by_known_root = true;
- details.cert_verify_result.public_key_hashes.push_back(
- GetTestHashValue(bad_pin));
-
- ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
-
- CompleteCryptoHandshake();
- session_->OnProofVerifyDetailsAvailable(details);
- QuicChromiumClientSessionPeer::SetHostname(session_.get(), "www.example.org");
- QuicChromiumClientSessionPeer::SetChannelIDSent(session_.get(), true);
-
- EXPECT_FALSE(session_->CanPool("mail.example.org", PRIVACY_MODE_DISABLED));
-}
-
-TEST_P(QuicChromiumClientSessionTest, ConnectionPooledWithMatchingPin) {
- Initialize();
-
- uint8_t primary_pin = 1;
- uint8_t backup_pin = 2;
- AddPin(&transport_security_state_, "mail.example.org", primary_pin,
- backup_pin);
-
- ProofVerifyDetailsChromium details;
- details.cert_verify_result.verified_cert =
- ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
- details.cert_verify_result.is_issued_by_known_root = true;
- details.cert_verify_result.public_key_hashes.push_back(
- GetTestHashValue(primary_pin));
-
- ASSERT_TRUE(details.cert_verify_result.verified_cert.get());
-
- CompleteCryptoHandshake();
- session_->OnProofVerifyDetailsAvailable(details);
- QuicChromiumClientSessionPeer::SetHostname(session_.get(), "www.example.org");
- QuicChromiumClientSessionPeer::SetChannelIDSent(session_.get(), true);
-
- EXPECT_TRUE(session_->CanPool("mail.example.org", PRIVACY_MODE_DISABLED));
-}
-
-TEST_P(QuicChromiumClientSessionTest, MigrateToSocket) {
- Initialize();
- CompleteCryptoHandshake();
-
- char data[] = "ABCD";
- std::unique_ptr<QuicEncryptedPacket> client_ping(
- client_maker_.MakePingPacket(1, /*include_version=*/false));
- std::unique_ptr<QuicEncryptedPacket> server_ping(
- server_maker_.MakePingPacket(1, /*include_version=*/false));
- std::unique_ptr<QuicEncryptedPacket> ack_and_data_out(
- client_maker_.MakeAckAndDataPacket(2, false, 5, 1, 1, false, 0,
- StringPiece(data)));
- MockRead reads[] = {
- MockRead(SYNCHRONOUS, server_ping->data(), server_ping->length(), 0),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 1)};
- MockWrite writes[] = {
- MockWrite(SYNCHRONOUS, client_ping->data(), client_ping->length(), 2),
- MockWrite(SYNCHRONOUS, ack_and_data_out->data(),
- ack_and_data_out->length(), 3)};
- StaticSocketDataProvider socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create connected socket.
- std::unique_ptr<DatagramClientSocket> new_socket =
- socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND,
- base::Bind(&base::RandInt),
- &net_log_, NetLog::Source());
- EXPECT_EQ(OK, new_socket->Connect(kIpEndPoint));
-
- // Create reader and writer.
- std::unique_ptr<QuicChromiumPacketReader> new_reader(
- new QuicChromiumPacketReader(new_socket.get(), &clock_, session_.get(),
- kQuicYieldAfterPacketsRead,
- QuicTime::Delta::FromMilliseconds(
- kQuicYieldAfterDurationMilliseconds),
- bound_net_log_.bound()));
- std::unique_ptr<QuicPacketWriter> new_writer(
- CreateQuicPacketWriter(new_socket.get(), session_->connection()));
-
- // Migrate session.
- EXPECT_TRUE(session_->MigrateToSocket(
- std::move(new_socket), std::move(new_reader), std::move(new_writer)));
-
- // Write data to session.
- QuicChromiumClientStream* stream =
- session_->CreateOutgoingDynamicStream(kDefaultPriority);
- struct iovec iov[1];
- iov[0].iov_base = data;
- iov[0].iov_len = 4;
- session_->WritevData(stream, stream->id(),
- QuicIOVector(iov, arraysize(iov), 4), 0, false, nullptr);
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicChromiumClientSessionTest, MigrateToSocketMaxReaders) {
- Initialize();
- CompleteCryptoHandshake();
-
- for (size_t i = 0; i < kMaxReadersPerQuicSession; ++i) {
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 1)};
- std::unique_ptr<QuicEncryptedPacket> ping_out(
- client_maker_.MakePingPacket(i + 1, /*include_version=*/true));
- MockWrite writes[] = {
- MockWrite(SYNCHRONOUS, ping_out->data(), ping_out->length(), i + 2)};
- StaticSocketDataProvider socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create connected socket.
- std::unique_ptr<DatagramClientSocket> new_socket =
- socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND,
- base::Bind(&base::RandInt),
- &net_log_, NetLog::Source());
- EXPECT_EQ(OK, new_socket->Connect(kIpEndPoint));
-
- // Create reader and writer.
- std::unique_ptr<QuicChromiumPacketReader> new_reader(
- new QuicChromiumPacketReader(new_socket.get(), &clock_, session_.get(),
- kQuicYieldAfterPacketsRead,
- QuicTime::Delta::FromMilliseconds(
- kQuicYieldAfterDurationMilliseconds),
- bound_net_log_.bound()));
- std::unique_ptr<QuicPacketWriter> new_writer(
- CreateQuicPacketWriter(new_socket.get(), session_->connection()));
-
- // Migrate session.
- if (i < kMaxReadersPerQuicSession - 1) {
- EXPECT_TRUE(session_->MigrateToSocket(
- std::move(new_socket), std::move(new_reader), std::move(new_writer)));
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- } else {
- // Max readers exceeded.
- EXPECT_FALSE(session_->MigrateToSocket(
- std::move(new_socket), std::move(new_reader), std::move(new_writer)));
-
- EXPECT_FALSE(socket_data.AllReadDataConsumed());
- EXPECT_FALSE(socket_data.AllWriteDataConsumed());
- }
- }
-}
-
-TEST_P(QuicChromiumClientSessionTest, MigrateToSocketReadError) {
- std::unique_ptr<QuicEncryptedPacket> client_ping(
- client_maker_.MakePingPacket(1, /*include_version=*/false));
- std::unique_ptr<QuicEncryptedPacket> server_ping(
- server_maker_.MakePingPacket(1, /*include_version=*/false));
- MockRead old_reads[] = {
- MockRead(SYNCHRONOUS, client_ping->data(), client_ping->length(), 0),
- MockRead(ASYNC, ERR_IO_PENDING, 1), // causes reading to pause.
- MockRead(ASYNC, ERR_NETWORK_CHANGED, 2)};
- socket_data_.reset(
- new SequencedSocketData(old_reads, arraysize(old_reads), nullptr, 0));
- Initialize();
- CompleteCryptoHandshake();
-
- MockWrite writes[] = {
- MockWrite(SYNCHRONOUS, client_ping->data(), client_ping->length(), 1)};
- MockRead new_reads[] = {
- MockRead(SYNCHRONOUS, server_ping->data(), server_ping->length(), 0),
- MockRead(ASYNC, ERR_IO_PENDING, 2), // pause reading.
- MockRead(ASYNC, server_ping->data(), server_ping->length(), 3),
- MockRead(ASYNC, ERR_IO_PENDING, 4), // pause reading
- MockRead(ASYNC, ERR_NETWORK_CHANGED, 5)};
- SequencedSocketData new_socket_data(new_reads, arraysize(new_reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&new_socket_data);
-
- // Create connected socket.
- std::unique_ptr<DatagramClientSocket> new_socket =
- socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND,
- base::Bind(&base::RandInt),
- &net_log_, NetLog::Source());
- EXPECT_EQ(OK, new_socket->Connect(kIpEndPoint));
-
- // Create reader and writer.
- std::unique_ptr<QuicChromiumPacketReader> new_reader(
- new QuicChromiumPacketReader(new_socket.get(), &clock_, session_.get(),
- kQuicYieldAfterPacketsRead,
- QuicTime::Delta::FromMilliseconds(
- kQuicYieldAfterDurationMilliseconds),
- bound_net_log_.bound()));
- std::unique_ptr<QuicPacketWriter> new_writer(
- CreateQuicPacketWriter(new_socket.get(), session_->connection()));
-
- // Store old socket and migrate session.
- EXPECT_TRUE(session_->MigrateToSocket(
- std::move(new_socket), std::move(new_reader), std::move(new_writer)));
-
- // Read error on old socket does not impact session.
- EXPECT_TRUE(socket_data_->IsPaused());
- socket_data_->Resume();
- EXPECT_TRUE(session_->connection()->connected());
- EXPECT_TRUE(new_socket_data.IsPaused());
- new_socket_data.Resume();
-
- // Read error on new socket causes session close.
- EXPECT_TRUE(new_socket_data.IsPaused());
- EXPECT_TRUE(session_->connection()->connected());
- new_socket_data.Resume();
- EXPECT_FALSE(session_->connection()->connected());
-
- EXPECT_TRUE(socket_data_->AllReadDataConsumed());
- EXPECT_TRUE(socket_data_->AllWriteDataConsumed());
- EXPECT_TRUE(new_socket_data.AllReadDataConsumed());
- EXPECT_TRUE(new_socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicChromiumClientSessionTest, MigrateToSocketWriteError) {
- Initialize();
- CompleteCryptoHandshake();
-
- std::unique_ptr<QuicEncryptedPacket> ping(
- client_maker_.MakePingPacket(1, /*include_version=*/true));
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- MockWrite writes[] = {MockWrite(SYNCHRONOUS, ping->data(), ping->length(), 1),
- MockWrite(SYNCHRONOUS, ERR_FAILED, 2)};
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create connected socket.
- std::unique_ptr<DatagramClientSocket> new_socket =
- socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND,
- base::Bind(&base::RandInt),
- &net_log_, NetLog::Source());
- EXPECT_EQ(OK, new_socket->Connect(kIpEndPoint));
-
- // Create reader and writer.
- std::unique_ptr<QuicChromiumPacketReader> new_reader(
- new QuicChromiumPacketReader(new_socket.get(), &clock_, session_.get(),
- kQuicYieldAfterPacketsRead,
- QuicTime::Delta::FromMilliseconds(
- kQuicYieldAfterDurationMilliseconds),
- bound_net_log_.bound()));
- std::unique_ptr<QuicPacketWriter> new_writer(
- CreateQuicPacketWriter(new_socket.get(), session_->connection()));
-
- // Migrate session.
- EXPECT_TRUE(session_->MigrateToSocket(
- std::move(new_socket), std::move(new_reader), std::move(new_writer)));
-
- // Write error on new socket causes session close.
- EXPECT_TRUE(session_->connection()->connected());
- session_->connection()->SendPing();
- EXPECT_FALSE(session_->connection()->connected());
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_chromium_client_stream.cc b/chromium/net/quic/quic_chromium_client_stream.cc
deleted file mode 100644
index 405db0f89a3..00000000000
--- a/chromium/net/quic/quic_chromium_client_stream.cc
+++ /dev/null
@@ -1,320 +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/quic_chromium_client_stream.h"
-
-#include <utility>
-
-#include "base/bind_helpers.h"
-#include "base/callback_helpers.h"
-#include "base/location.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/quic/quic_chromium_client_session.h"
-#include "net/quic/quic_http_utils.h"
-#include "net/quic/quic_spdy_session.h"
-#include "net/quic/quic_write_blocked_list.h"
-#include "net/quic/spdy_utils.h"
-
-namespace net {
-
-QuicChromiumClientStream::QuicChromiumClientStream(
- QuicStreamId id,
- QuicClientSessionBase* session,
- const BoundNetLog& net_log)
- : QuicSpdyStream(id, session),
- net_log_(net_log),
- delegate_(nullptr),
- headers_delivered_(false),
- session_(session),
- can_migrate_(true),
- weak_factory_(this) {}
-
-QuicChromiumClientStream::~QuicChromiumClientStream() {
- if (delegate_)
- delegate_->OnClose();
-}
-
-void QuicChromiumClientStream::OnStreamHeadersComplete(bool fin,
- size_t frame_len) {
- QuicSpdyStream::OnStreamHeadersComplete(fin, frame_len);
- if (decompressed_headers().empty() && !decompressed_trailers().empty()) {
- DCHECK(trailers_decompressed());
- // The delegate will read the trailers via a posted task.
- NotifyDelegateOfHeadersCompleteLater(received_trailers().Clone(),
- frame_len);
- } else {
- DCHECK(!headers_delivered_);
- SpdyHeaderBlock headers;
- SpdyFramer framer(HTTP2);
- size_t headers_len = decompressed_headers().length();
- const char* header_data = decompressed_headers().data();
- if (!framer.ParseHeaderBlockInBuffer(header_data, headers_len, &headers)) {
- DLOG(WARNING) << "Invalid headers";
- Reset(QUIC_BAD_APPLICATION_PAYLOAD);
- return;
- }
- MarkHeadersConsumed(headers_len);
- session_->OnInitialHeadersComplete(id(), headers);
-
- // The delegate will read the headers via a posted task.
- NotifyDelegateOfHeadersCompleteLater(std::move(headers), frame_len);
- }
-}
-
-void QuicChromiumClientStream::OnInitialHeadersComplete(
- bool fin,
- size_t frame_len,
- const QuicHeaderList& header_list) {
- QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list);
-
- SpdyHeaderBlock header_block;
- int64_t length = -1;
- if (!SpdyUtils::CopyAndValidateHeaders(header_list, &length, &header_block)) {
- DLOG(ERROR) << "Failed to parse header list: " << header_list.DebugString();
- ConsumeHeaderList();
- Reset(QUIC_BAD_APPLICATION_PAYLOAD);
- return;
- }
-
- ConsumeHeaderList();
- session_->OnInitialHeadersComplete(id(), header_block);
-
- // The delegate will read the headers via a posted task.
- NotifyDelegateOfHeadersCompleteLater(std::move(header_block), frame_len);
-}
-
-void QuicChromiumClientStream::OnTrailingHeadersComplete(
- bool fin,
- size_t frame_len,
- const QuicHeaderList& header_list) {
- QuicSpdyStream::OnTrailingHeadersComplete(fin, frame_len, header_list);
- NotifyDelegateOfHeadersCompleteLater(received_trailers().Clone(), frame_len);
-}
-
-void QuicChromiumClientStream::OnPromiseHeadersComplete(
- QuicStreamId promised_id,
- size_t frame_len) {
- size_t headers_len = decompressed_headers().length();
- SpdyHeaderBlock headers;
- SpdyFramer framer(HTTP2);
- if (!framer.ParseHeaderBlockInBuffer(decompressed_headers().data(),
- headers_len, &headers)) {
- DLOG(WARNING) << "Invalid headers";
- Reset(QUIC_BAD_APPLICATION_PAYLOAD);
- return;
- }
- MarkHeadersConsumed(headers_len);
-
- session_->HandlePromised(id(), promised_id, headers);
-}
-
-void QuicChromiumClientStream::OnPromiseHeaderList(
- QuicStreamId promised_id,
- size_t frame_len,
- const QuicHeaderList& header_list) {
- SpdyHeaderBlock promise_headers;
- int64_t content_length = -1;
- if (!SpdyUtils::CopyAndValidateHeaders(header_list, &content_length,
- &promise_headers)) {
- DLOG(ERROR) << "Failed to parse header list: " << header_list.DebugString();
- ConsumeHeaderList();
- Reset(QUIC_BAD_APPLICATION_PAYLOAD);
- return;
- }
- ConsumeHeaderList();
-
- session_->HandlePromised(id(), promised_id, promise_headers);
-}
-
-void QuicChromiumClientStream::OnDataAvailable() {
- if (!FinishedReadingHeaders() || !headers_delivered_) {
- // Buffer the data in the sequencer until the headers have been read.
- return;
- }
-
- // The delegate will read the data via a posted task, and
- // will be able to, potentially, read all data which has queued up.
- NotifyDelegateOfDataAvailableLater();
-}
-
-void QuicChromiumClientStream::OnClose() {
- if (delegate_) {
- delegate_->OnClose();
- delegate_ = nullptr;
- delegate_tasks_.clear();
- }
- ReliableQuicStream::OnClose();
-}
-
-void QuicChromiumClientStream::OnCanWrite() {
- ReliableQuicStream::OnCanWrite();
-
- if (!HasBufferedData() && !callback_.is_null()) {
- base::ResetAndReturn(&callback_).Run(OK);
- }
-}
-
-size_t QuicChromiumClientStream::WriteHeaders(
- SpdyHeaderBlock header_block,
- bool fin,
- QuicAckListenerInterface* ack_notifier_delegate) {
- if (!session()->IsCryptoHandshakeConfirmed()) {
- auto entry = header_block.find(":method");
- DCHECK(entry != header_block.end());
- DCHECK_NE("POST", entry->second);
- }
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
- base::Bind(&QuicRequestNetLogCallback, id(), &header_block,
- QuicSpdyStream::priority()));
- return QuicSpdyStream::WriteHeaders(std::move(header_block), fin,
- ack_notifier_delegate);
-}
-
-SpdyPriority QuicChromiumClientStream::priority() const {
- if (delegate_ && delegate_->HasSendHeadersComplete()) {
- return QuicSpdyStream::priority();
- }
- return net::kV3HighestPriority;
-}
-
-int QuicChromiumClientStream::WriteStreamData(
- base::StringPiece data,
- bool fin,
- const CompletionCallback& callback) {
- // We should not have data buffered.
- DCHECK(!HasBufferedData());
- // Writes the data, or buffers it.
- WriteOrBufferData(data, fin, nullptr);
- if (!HasBufferedData()) {
- return OK;
- }
-
- callback_ = callback;
- return ERR_IO_PENDING;
-}
-
-int QuicChromiumClientStream::WritevStreamData(
- const std::vector<scoped_refptr<IOBuffer>>& buffers,
- const std::vector<int>& lengths,
- bool fin,
- const CompletionCallback& callback) {
- // Must not be called when data is buffered.
- DCHECK(!HasBufferedData());
- // Writes the data, or buffers it.
- for (size_t i = 0; i < buffers.size(); ++i) {
- bool is_fin = fin && (i == buffers.size() - 1);
- base::StringPiece string_data(buffers[i]->data(), lengths[i]);
- WriteOrBufferData(string_data, is_fin, nullptr);
- }
- if (!HasBufferedData()) {
- return OK;
- }
-
- callback_ = callback;
- return ERR_IO_PENDING;
-}
-
-void QuicChromiumClientStream::SetDelegate(
- QuicChromiumClientStream::Delegate* delegate) {
- DCHECK(!(delegate_ && delegate));
- delegate_ = delegate;
- while (!delegate_tasks_.empty()) {
- base::Closure closure = delegate_tasks_.front();
- delegate_tasks_.pop_front();
- closure.Run();
- }
- if (delegate == nullptr && sequencer()->IsClosed()) {
- OnFinRead();
- }
-}
-
-void QuicChromiumClientStream::OnError(int error) {
- if (delegate_) {
- QuicChromiumClientStream::Delegate* delegate = delegate_;
- delegate_ = nullptr;
- delegate_tasks_.clear();
- delegate->OnError(error);
- }
-}
-
-int QuicChromiumClientStream::Read(IOBuffer* buf, int buf_len) {
- if (sequencer()->IsClosed())
- return 0; // EOF
-
- if (!HasBytesToRead())
- return ERR_IO_PENDING;
-
- iovec iov;
- iov.iov_base = buf->data();
- iov.iov_len = buf_len;
- return Readv(&iov, 1);
-}
-
-bool QuicChromiumClientStream::CanWrite(const CompletionCallback& callback) {
- bool can_write = session()->connection()->CanWrite(HAS_RETRANSMITTABLE_DATA);
- if (!can_write) {
- session()->MarkConnectionLevelWriteBlocked(id());
- DCHECK(callback_.is_null());
- callback_ = callback;
- }
- return can_write;
-}
-
-void QuicChromiumClientStream::NotifyDelegateOfHeadersCompleteLater(
- SpdyHeaderBlock headers,
- size_t frame_len) {
- RunOrBuffer(base::Bind(
- &QuicChromiumClientStream::NotifyDelegateOfHeadersComplete,
- weak_factory_.GetWeakPtr(), base::Passed(std::move(headers)), frame_len));
-}
-
-void QuicChromiumClientStream::NotifyDelegateOfHeadersComplete(
- SpdyHeaderBlock headers,
- size_t frame_len) {
- if (!delegate_)
- return;
- // Only mark trailers consumed when we are about to notify delegate.
- if (headers_delivered_) {
- MarkTrailersConsumed(decompressed_trailers().length());
- MarkTrailersDelivered();
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_TRAILERS,
- base::Bind(&SpdyHeaderBlockNetLogCallback, &headers));
- } else {
- headers_delivered_ = true;
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_HEADERS,
- base::Bind(&SpdyHeaderBlockNetLogCallback, &headers));
- }
-
- delegate_->OnHeadersAvailable(headers, frame_len);
-}
-
-void QuicChromiumClientStream::NotifyDelegateOfDataAvailableLater() {
- RunOrBuffer(
- base::Bind(&QuicChromiumClientStream::NotifyDelegateOfDataAvailable,
- weak_factory_.GetWeakPtr()));
-}
-
-void QuicChromiumClientStream::NotifyDelegateOfDataAvailable() {
- if (delegate_)
- delegate_->OnDataAvailable();
-}
-
-void QuicChromiumClientStream::RunOrBuffer(base::Closure closure) {
- if (delegate_) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure);
- } else {
- delegate_tasks_.push_back(closure);
- }
-}
-
-void QuicChromiumClientStream::DisableConnectionMigration() {
- can_migrate_ = false;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_chromium_client_stream.h b/chromium/net/quic/quic_chromium_client_stream.h
deleted file mode 100644
index 976db2a8b89..00000000000
--- a/chromium/net/quic/quic_chromium_client_stream.h
+++ /dev/null
@@ -1,157 +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.
-//
-// NOTE: This code is not shared between Google and Chrome.
-
-#ifndef NET_QUIC_QUIC_CHROMIUM_CLIENT_STREAM_H_
-#define NET_QUIC_QUIC_CHROMIUM_CLIENT_STREAM_H_
-
-#include <stddef.h>
-
-#include <deque>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/macros.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/upload_data_stream.h"
-#include "net/http/http_request_info.h"
-#include "net/http/http_response_info.h"
-#include "net/http/http_stream.h"
-#include "net/quic/quic_spdy_stream.h"
-
-namespace net {
-
-class QuicClientSessionBase;
-
-// A client-initiated ReliableQuicStream. Instances of this class
-// are owned by the QuicClientSession which created them.
-class NET_EXPORT_PRIVATE QuicChromiumClientStream : public QuicSpdyStream {
- public:
- // Delegate handles protocol specific behavior of a quic stream.
- class NET_EXPORT_PRIVATE Delegate {
- public:
- Delegate() {}
-
- // Called when headers are available.
- virtual void OnHeadersAvailable(const SpdyHeaderBlock& headers,
- size_t frame_len) = 0;
-
- // Called when data is available to be read.
- virtual void OnDataAvailable() = 0;
-
- // Called when the stream is closed by the peer.
- virtual void OnClose() = 0;
-
- // Called when the stream is closed because of an error.
- virtual void OnError(int error) = 0;
-
- // Returns true if sending of headers has completed.
- virtual bool HasSendHeadersComplete() = 0;
-
- protected:
- virtual ~Delegate() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Delegate);
- };
-
- QuicChromiumClientStream(QuicStreamId id,
- QuicClientSessionBase* session,
- const BoundNetLog& net_log);
-
- ~QuicChromiumClientStream() override;
-
- // QuicSpdyStream
- void OnStreamHeadersComplete(bool fin, size_t frame_len) override;
- void OnInitialHeadersComplete(bool fin,
- size_t frame_len,
- const QuicHeaderList& header_list) override;
- void OnTrailingHeadersComplete(bool fin,
- size_t frame_len,
- const QuicHeaderList& header_list) override;
- void OnPromiseHeadersComplete(QuicStreamId promised_stream_id,
- size_t frame_len) override;
- void OnPromiseHeaderList(QuicStreamId promised_id,
- size_t frame_len,
- const QuicHeaderList& header_list) override;
- void OnDataAvailable() override;
- void OnClose() override;
- void OnCanWrite() override;
- size_t WriteHeaders(SpdyHeaderBlock header_block,
- bool fin,
- QuicAckListenerInterface* ack_notifier_delegate) override;
- SpdyPriority priority() const override;
-
- // While the server's set_priority shouldn't be called externally, the creator
- // of client-side streams should be able to set the priority.
- using QuicSpdyStream::SetPriority;
-
- int WriteStreamData(base::StringPiece data,
- bool fin,
- const CompletionCallback& callback);
- // Same as WriteStreamData except it writes data from a vector of IOBuffers,
- // with the length of each buffer at the corresponding index in |lengths|.
- int WritevStreamData(const std::vector<scoped_refptr<IOBuffer>>& buffers,
- const std::vector<int>& lengths,
- bool fin,
- const CompletionCallback& callback);
- // Set new |delegate|. |delegate| must not be NULL.
- // If this stream has already received data, OnDataReceived() will be
- // called on the delegate.
- void SetDelegate(Delegate* delegate);
- Delegate* GetDelegate() { return delegate_; }
- void OnError(int error);
-
- // Reads at most |buf_len| bytes into |buf|. Returns the number of bytes read.
- int Read(IOBuffer* buf, int buf_len);
-
- // Returns true if the stream can possible write data. (The socket may
- // turn out to be write blocked, of course). If the stream can not write,
- // this method returns false, and |callback| will be invoked when
- // it becomes writable.
- bool CanWrite(const CompletionCallback& callback);
-
- const BoundNetLog& net_log() const { return net_log_; }
-
- // Prevents this stream from migrating to a new network. May cause other
- // concurrent streams within the session to also not migrate.
- void DisableConnectionMigration();
-
- bool can_migrate() { return can_migrate_; }
-
- using QuicSpdyStream::HasBufferedData;
-
- private:
- void NotifyDelegateOfHeadersCompleteLater(SpdyHeaderBlock headers,
- size_t frame_len);
- void NotifyDelegateOfHeadersComplete(SpdyHeaderBlock headers,
- size_t frame_len);
- void NotifyDelegateOfDataAvailableLater();
- void NotifyDelegateOfDataAvailable();
- void RunOrBuffer(base::Closure closure);
-
- BoundNetLog net_log_;
- Delegate* delegate_;
-
- bool headers_delivered_;
-
- CompletionCallback callback_;
-
- QuicClientSessionBase* session_;
-
- // Set to false if this stream to not be migrated during connection migration.
- bool can_migrate_;
-
- // Holds notifications generated before delegate_ is set.
- std::deque<base::Closure> delegate_tasks_;
-
- base::WeakPtrFactory<QuicChromiumClientStream> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicChromiumClientStream);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CHROMIUM_CLIENT_STREAM_H_
diff --git a/chromium/net/quic/quic_chromium_client_stream_test.cc b/chromium/net/quic/quic_chromium_client_stream_test.cc
deleted file mode 100644
index 7a1e5a6d479..00000000000
--- a/chromium/net/quic/quic_chromium_client_stream_test.cc
+++ /dev/null
@@ -1,559 +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/quic_chromium_client_stream.h"
-
-#include <string>
-
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/base/test_completion_callback.h"
-#include "net/quic/quic_chromium_client_session.h"
-#include "net/quic/quic_client_session_base.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/spdy_utils.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gmock_mutant.h"
-
-using testing::AnyNumber;
-using testing::CreateFunctor;
-using testing::Invoke;
-using testing::Return;
-using testing::StrEq;
-using testing::_;
-
-namespace net {
-namespace test {
-namespace {
-
-const QuicStreamId kTestStreamId = 5u;
-
-class MockDelegate : public QuicChromiumClientStream::Delegate {
- public:
- MockDelegate() {}
-
- MOCK_METHOD0(OnSendData, int());
- MOCK_METHOD2(OnSendDataComplete, int(int, bool*));
- void OnHeadersAvailable(const SpdyHeaderBlock& headers,
- size_t frame_len) override {
- headers_ = headers.Clone();
- OnHeadersAvailableMock(headers, frame_len);
- }
- MOCK_METHOD2(OnHeadersAvailableMock,
- void(const SpdyHeaderBlock& headers, size_t frame_len));
- MOCK_METHOD2(OnDataReceived, int(const char*, int));
- MOCK_METHOD0(OnDataAvailable, void());
- MOCK_METHOD0(OnClose, void());
- MOCK_METHOD1(OnError, void(int));
- MOCK_METHOD0(HasSendHeadersComplete, bool());
-
- SpdyHeaderBlock headers_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockDelegate);
-};
-
-class MockQuicClientSessionBase : public QuicClientSessionBase {
- public:
- explicit MockQuicClientSessionBase(QuicConnection* connection,
- QuicClientPushPromiseIndex* index);
- ~MockQuicClientSessionBase() override;
-
- QuicCryptoStream* GetCryptoStream() override { return crypto_stream_.get(); }
-
- // From QuicSession.
- MOCK_METHOD3(OnConnectionClosed,
- void(QuicErrorCode error,
- const std::string& error_details,
- ConnectionCloseSource source));
- MOCK_METHOD1(CreateIncomingDynamicStream, QuicSpdyStream*(QuicStreamId id));
- MOCK_METHOD1(CreateOutgoingDynamicStream,
- QuicChromiumClientStream*(SpdyPriority priority));
- MOCK_METHOD6(WritevData,
- QuicConsumedData(ReliableQuicStream* stream,
- QuicStreamId id,
- QuicIOVector data,
- QuicStreamOffset offset,
- bool fin,
- QuicAckListenerInterface*));
- MOCK_METHOD3(SendRstStream,
- void(QuicStreamId stream_id,
- QuicRstStreamErrorCode error,
- QuicStreamOffset bytes_written));
-
- MOCK_METHOD2(OnStreamHeaders,
- void(QuicStreamId stream_id, base::StringPiece headers_data));
- MOCK_METHOD2(OnStreamHeadersPriority,
- void(QuicStreamId stream_id, SpdyPriority priority));
- MOCK_METHOD3(OnStreamHeadersComplete,
- void(QuicStreamId stream_id, bool fin, size_t frame_len));
- MOCK_METHOD2(OnPromiseHeaders,
- void(QuicStreamId stream_id, StringPiece headers_data));
- MOCK_METHOD3(OnPromiseHeadersComplete,
- void(QuicStreamId stream_id,
- QuicStreamId promised_stream_id,
- size_t frame_len));
- MOCK_METHOD0(IsCryptoHandshakeConfirmed, bool());
- // Methods taking non-copyable types like SpdyHeaderBlock by value cannot be
- // mocked directly.
- size_t WriteHeaders(
- QuicStreamId id,
- SpdyHeaderBlock headers,
- bool fin,
- SpdyPriority priority,
- QuicAckListenerInterface* ack_notifier_delegate) override {
- return WriteHeadersMock(id, headers, fin, priority, ack_notifier_delegate);
- }
- MOCK_METHOD5(WriteHeadersMock,
- size_t(QuicStreamId id,
- const SpdyHeaderBlock& headers,
- bool fin,
- SpdyPriority priority,
- QuicAckListenerInterface* ack_notifier_delegate));
- MOCK_METHOD1(OnHeadersHeadOfLineBlocking, void(QuicTime::Delta delta));
-
- using QuicSession::ActivateStream;
-
- // Returns a QuicConsumedData that indicates all of |data| (and |fin| if set)
- // has been consumed.
- static QuicConsumedData ConsumeAllData(
- QuicStreamId id,
- const QuicIOVector& data,
- QuicStreamOffset offset,
- bool fin,
- QuicAckListenerInterface* ack_notifier_delegate);
-
- void OnProofValid(
- const QuicCryptoClientConfig::CachedState& cached) override {}
- void OnProofVerifyDetailsAvailable(
- const ProofVerifyDetails& verify_details) override {}
- bool IsAuthorized(const std::string& hostname) override { return true; }
-
- protected:
- MOCK_METHOD1(ShouldCreateIncomingDynamicStream, bool(QuicStreamId id));
- MOCK_METHOD0(ShouldCreateOutgoingDynamicStream, bool());
-
- private:
- std::unique_ptr<QuicCryptoStream> crypto_stream_;
-
- DISALLOW_COPY_AND_ASSIGN(MockQuicClientSessionBase);
-};
-
-MockQuicClientSessionBase::MockQuicClientSessionBase(
- QuicConnection* connection,
- QuicClientPushPromiseIndex* push_promise_index)
- : QuicClientSessionBase(connection,
- push_promise_index,
- DefaultQuicConfig()) {
- crypto_stream_.reset(new QuicCryptoStream(this));
- Initialize();
- ON_CALL(*this, WritevData(_, _, _, _, _, _))
- .WillByDefault(testing::Return(QuicConsumedData(0, false)));
-}
-
-MockQuicClientSessionBase::~MockQuicClientSessionBase() {}
-
-class QuicChromiumClientStreamTest
- : public ::testing::TestWithParam<QuicVersion> {
- public:
- QuicChromiumClientStreamTest()
- : crypto_config_(CryptoTestUtils::ProofVerifierForTesting()),
- session_(new MockQuicConnection(&helper_,
- &alarm_factory_,
- Perspective::IS_CLIENT,
- SupportedVersions(GetParam())),
- &push_promise_index_) {
- stream_ =
- new QuicChromiumClientStream(kTestStreamId, &session_, BoundNetLog());
- session_.ActivateStream(stream_);
- stream_->SetDelegate(&delegate_);
- }
-
- void InitializeHeaders() {
- headers_[":host"] = "www.google.com";
- headers_[":path"] = "/index.hml";
- headers_[":scheme"] = "https";
- headers_["cookie"] =
- "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; "
- "__utmc=160408618; "
- "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX"
- "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX"
- "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT"
- "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0"
- "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh"
- "1zFMi5vzcns38-8_Sns; "
- "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-"
- "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339"
- "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c"
- "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%"
- "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4"
- "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1"
- "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP"
- "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6"
- "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b"
- "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6"
- "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG"
- "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk"
- "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn"
- "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
- "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
- }
-
- void ReadData(StringPiece expected_data) {
- scoped_refptr<IOBuffer> buffer(new IOBuffer(expected_data.length() + 1));
- EXPECT_EQ(static_cast<int>(expected_data.length()),
- stream_->Read(buffer.get(), expected_data.length() + 1));
- EXPECT_EQ(expected_data,
- StringPiece(buffer->data(), expected_data.length()));
- }
-
- QuicCryptoClientConfig crypto_config_;
- testing::StrictMock<MockDelegate> delegate_;
- MockQuicConnectionHelper helper_;
- MockAlarmFactory alarm_factory_;
- MockQuicClientSessionBase session_;
- QuicChromiumClientStream* stream_;
- SpdyHeaderBlock headers_;
- QuicClientPushPromiseIndex push_promise_index_;
-};
-
-INSTANTIATE_TEST_CASE_P(Version,
- QuicChromiumClientStreamTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
-
-TEST_P(QuicChromiumClientStreamTest, OnFinRead) {
- InitializeHeaders();
- std::string uncompressed_headers =
- SpdyUtils::SerializeUncompressedHeaders(headers_);
- QuicStreamOffset offset = 0;
- stream_->OnStreamHeaders(uncompressed_headers);
- stream_->OnStreamHeadersComplete(false, uncompressed_headers.length());
-
- EXPECT_CALL(delegate_,
- OnHeadersAvailableMock(_, uncompressed_headers.length()));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(headers_, delegate_.headers_);
- EXPECT_TRUE(stream_->decompressed_headers().empty());
-
- QuicStreamFrame frame2(kTestStreamId, true, offset, StringPiece());
- EXPECT_CALL(delegate_, OnClose());
- stream_->OnStreamFrame(frame2);
-}
-
-TEST_P(QuicChromiumClientStreamTest, OnDataAvailableBeforeHeaders) {
- EXPECT_CALL(delegate_, OnClose());
-
- EXPECT_CALL(delegate_, OnDataAvailable()).Times(0);
- stream_->OnDataAvailable();
-}
-
-TEST_P(QuicChromiumClientStreamTest, OnDataAvailable) {
- InitializeHeaders();
- std::string uncompressed_headers =
- SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeaders(uncompressed_headers);
- stream_->OnStreamHeadersComplete(false, uncompressed_headers.length());
-
- EXPECT_CALL(delegate_,
- OnHeadersAvailableMock(_, uncompressed_headers.length()));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(headers_, delegate_.headers_);
- EXPECT_TRUE(stream_->decompressed_headers().empty());
-
- const char data[] = "hello world!";
- stream_->OnStreamFrame(QuicStreamFrame(kTestStreamId, /*fin=*/false,
- /*offset=*/0, data));
-
- EXPECT_CALL(delegate_, OnDataAvailable())
- .WillOnce(testing::Invoke(
- CreateFunctor(&QuicChromiumClientStreamTest::ReadData,
- base::Unretained(this),
- StringPiece(data, arraysize(data) - 1))));
- base::RunLoop().RunUntilIdle();
-
- EXPECT_CALL(delegate_, OnClose());
-}
-
-TEST_P(QuicChromiumClientStreamTest, ProcessHeadersWithError) {
- std::string bad_headers = "...";
- EXPECT_CALL(session_,
- SendRstStream(kTestStreamId, QUIC_BAD_APPLICATION_PAYLOAD, 0));
-
- stream_->OnStreamHeaders(StringPiece(bad_headers));
- stream_->OnStreamHeadersComplete(false, bad_headers.length());
-
- base::RunLoop().RunUntilIdle();
-
- EXPECT_CALL(delegate_, OnClose());
-}
-
-TEST_P(QuicChromiumClientStreamTest, OnDataAvailableWithError) {
- InitializeHeaders();
- std::string uncompressed_headers =
- SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeaders(uncompressed_headers);
- stream_->OnStreamHeadersComplete(false, uncompressed_headers.length());
-
- EXPECT_CALL(delegate_,
- OnHeadersAvailableMock(_, uncompressed_headers.length()));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(headers_, delegate_.headers_);
- EXPECT_TRUE(stream_->decompressed_headers().empty());
-
- const char data[] = "hello world!";
- stream_->OnStreamFrame(QuicStreamFrame(kTestStreamId, /*fin=*/false,
- /*offset=*/0, data));
- EXPECT_CALL(delegate_, OnDataAvailable())
- .WillOnce(testing::Invoke(CreateFunctor(
- &QuicChromiumClientStream::Reset,
- base::Unretained(stream_), QUIC_STREAM_CANCELLED)));
- base::RunLoop().RunUntilIdle();
-
- EXPECT_CALL(delegate_, OnClose());
-}
-
-TEST_P(QuicChromiumClientStreamTest, OnError) {
- EXPECT_CALL(delegate_, OnError(ERR_INTERNET_DISCONNECTED));
-
- stream_->OnError(ERR_INTERNET_DISCONNECTED);
- EXPECT_FALSE(stream_->GetDelegate());
-}
-
-TEST_P(QuicChromiumClientStreamTest, OnTrailers) {
- InitializeHeaders();
- std::string uncompressed_headers =
- SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeaders(uncompressed_headers);
- stream_->OnStreamHeadersComplete(false, uncompressed_headers.length());
-
- EXPECT_CALL(delegate_,
- OnHeadersAvailableMock(_, uncompressed_headers.length()));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(headers_, delegate_.headers_);
- EXPECT_TRUE(stream_->decompressed_headers().empty());
-
- const char data[] = "hello world!";
- stream_->OnStreamFrame(QuicStreamFrame(kTestStreamId, /*fin=*/false,
- /*offset=*/0, data));
-
- EXPECT_CALL(delegate_, OnDataAvailable())
- .WillOnce(testing::Invoke(CreateFunctor(
- &QuicChromiumClientStreamTest::ReadData, base::Unretained(this),
- StringPiece(data, arraysize(data) - 1))));
-
- SpdyHeaderBlock trailers;
- trailers["bar"] = "foo";
- trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(data));
- std::string uncompressed_trailers =
- SpdyUtils::SerializeUncompressedHeaders(trailers);
-
- stream_->OnStreamHeaders(uncompressed_trailers);
- stream_->OnStreamHeadersComplete(true, uncompressed_trailers.length());
-
- base::RunLoop run_loop;
- EXPECT_CALL(delegate_,
- OnHeadersAvailableMock(_, uncompressed_trailers.length()))
- .WillOnce(testing::InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); }));
-
- run_loop.Run();
- // Make sure kFinalOffsetHeaderKey is gone from the delivered actual trailers.
- trailers.erase(kFinalOffsetHeaderKey);
- EXPECT_EQ(trailers, delegate_.headers_);
- base::RunLoop().RunUntilIdle();
- EXPECT_CALL(delegate_, OnClose());
-}
-
-// Tests that trailers are marked as consumed only before delegate is to be
-// immediately notified about trailers.
-TEST_P(QuicChromiumClientStreamTest, MarkTrailersConsumedWhenNotifyDelegate) {
- InitializeHeaders();
- std::string uncompressed_headers =
- SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeaders(uncompressed_headers);
- stream_->OnStreamHeadersComplete(false, uncompressed_headers.length());
-
- EXPECT_CALL(delegate_,
- OnHeadersAvailableMock(_, uncompressed_headers.length()));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(headers_, delegate_.headers_);
- EXPECT_TRUE(stream_->decompressed_headers().empty());
-
- const char data[] = "hello world!";
- stream_->OnStreamFrame(QuicStreamFrame(kTestStreamId, /*fin=*/false,
- /*offset=*/0, data));
-
- base::RunLoop run_loop;
- EXPECT_CALL(delegate_, OnDataAvailable())
- .Times(1)
- .WillOnce(testing::DoAll(
- testing::Invoke(CreateFunctor(
- &QuicChromiumClientStreamTest::ReadData, base::Unretained(this),
- StringPiece(data, arraysize(data) - 1))),
- testing::Invoke([&run_loop]() { run_loop.Quit(); })));
-
- // Wait for the read to complete.
- run_loop.Run();
-
- // Read again, and it will be pending.
- scoped_refptr<IOBuffer> buffer(new IOBuffer(1));
- EXPECT_EQ(ERR_IO_PENDING, stream_->Read(buffer.get(), 1));
-
- SpdyHeaderBlock trailers;
- trailers["bar"] = "foo";
- trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(data));
- std::string uncompressed_trailers =
- SpdyUtils::SerializeUncompressedHeaders(trailers);
-
- stream_->OnStreamHeaders(uncompressed_trailers);
- stream_->OnStreamHeadersComplete(true, uncompressed_trailers.length());
- EXPECT_FALSE(stream_->IsDoneReading());
-
- // Now the pending should complete. Make sure that IsDoneReading() is false
- // even though ReadData returns 0 byte, because OnHeadersAvailable callback
- // comes after this OnDataAvailable callback.
- base::RunLoop run_loop2;
- EXPECT_CALL(delegate_, OnDataAvailable())
- .Times(1)
- .WillOnce(testing::DoAll(
- testing::Invoke(CreateFunctor(&QuicChromiumClientStreamTest::ReadData,
- base::Unretained(this), StringPiece())),
- testing::InvokeWithoutArgs([&run_loop2]() { run_loop2.Quit(); })));
- run_loop2.Run();
- // Make sure that the stream is not closed, even though ReadData returns 0.
- EXPECT_FALSE(stream_->IsDoneReading());
-
- // The OnHeadersAvailable call should follow.
- base::RunLoop run_loop3;
- EXPECT_CALL(delegate_,
- OnHeadersAvailableMock(_, uncompressed_trailers.length()))
- .WillOnce(
- testing::InvokeWithoutArgs([&run_loop3]() { run_loop3.Quit(); }));
-
- run_loop3.Run();
- // Make sure the stream is properly closed since trailers and data are all
- // consumed.
- EXPECT_TRUE(stream_->IsDoneReading());
- // Make sure kFinalOffsetHeaderKey is gone from the delivered actual trailers.
- trailers.erase(kFinalOffsetHeaderKey);
- EXPECT_EQ(trailers, delegate_.headers_);
-
- base::RunLoop().RunUntilIdle();
- EXPECT_CALL(delegate_, OnClose());
-}
-
-TEST_P(QuicChromiumClientStreamTest, WriteStreamData) {
- EXPECT_CALL(delegate_, OnClose());
-
- const char kData1[] = "hello world";
- const size_t kDataLen = arraysize(kData1);
-
- // All data written.
- EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _, _))
- .WillOnce(Return(QuicConsumedData(kDataLen, true)));
- TestCompletionCallback callback;
- EXPECT_EQ(OK, stream_->WriteStreamData(base::StringPiece(kData1, kDataLen),
- true, callback.callback()));
-}
-
-TEST_P(QuicChromiumClientStreamTest, WriteStreamDataAsync) {
- EXPECT_CALL(delegate_, HasSendHeadersComplete()).Times(AnyNumber());
- EXPECT_CALL(delegate_, OnClose());
-
- const char kData1[] = "hello world";
- const size_t kDataLen = arraysize(kData1);
-
- // No data written.
- EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _, _))
- .WillOnce(Return(QuicConsumedData(0, false)));
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- stream_->WriteStreamData(base::StringPiece(kData1, kDataLen), true,
- callback.callback()));
- ASSERT_FALSE(callback.have_result());
-
- // All data written.
- EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _, _))
- .WillOnce(Return(QuicConsumedData(kDataLen, true)));
- stream_->OnCanWrite();
- ASSERT_TRUE(callback.have_result());
- EXPECT_EQ(OK, callback.WaitForResult());
-}
-
-TEST_P(QuicChromiumClientStreamTest, WritevStreamData) {
- EXPECT_CALL(delegate_, OnClose());
-
- scoped_refptr<StringIOBuffer> buf1(new StringIOBuffer("hello world!"));
- scoped_refptr<StringIOBuffer> buf2(
- new StringIOBuffer("Just a small payload"));
-
- // All data written.
- EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _, _))
- .WillOnce(Return(QuicConsumedData(buf1->size(), false)))
- .WillOnce(Return(QuicConsumedData(buf2->size(), true)));
- TestCompletionCallback callback;
- EXPECT_EQ(
- OK, stream_->WritevStreamData({buf1, buf2}, {buf1->size(), buf2->size()},
- true, callback.callback()));
-}
-
-TEST_P(QuicChromiumClientStreamTest, WritevStreamDataAsync) {
- EXPECT_CALL(delegate_, HasSendHeadersComplete()).Times(AnyNumber());
- EXPECT_CALL(delegate_, OnClose());
-
- scoped_refptr<StringIOBuffer> buf1(new StringIOBuffer("hello world!"));
- scoped_refptr<StringIOBuffer> buf2(
- new StringIOBuffer("Just a small payload"));
-
- // Only a part of the data is written.
- EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _, _))
- // First piece of data is written.
- .WillOnce(Return(QuicConsumedData(buf1->size(), false)))
- // Second piece of data is queued.
- .WillOnce(Return(QuicConsumedData(0, false)));
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- stream_->WritevStreamData({buf1.get(), buf2.get()},
- {buf1->size(), buf2->size()}, true,
- callback.callback()));
- ASSERT_FALSE(callback.have_result());
-
- // The second piece of data is written.
- EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _, _))
- .WillOnce(Return(QuicConsumedData(buf2->size(), true)));
- stream_->OnCanWrite();
- ASSERT_TRUE(callback.have_result());
- EXPECT_EQ(OK, callback.WaitForResult());
-}
-
-TEST_P(QuicChromiumClientStreamTest, HeadersBeforeDelegate) {
- // We don't use stream_ because we want an incoming server push
- // stream.
- QuicChromiumClientStream* stream = new QuicChromiumClientStream(
- kServerDataStreamId1, &session_, BoundNetLog());
- session_.ActivateStream(stream);
-
- InitializeHeaders();
- std::string uncompressed_headers =
- SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream->OnStreamHeaders(uncompressed_headers);
- stream->OnStreamHeadersComplete(false, uncompressed_headers.length());
- EXPECT_TRUE(stream->decompressed_headers().empty());
-
- EXPECT_CALL(delegate_,
- OnHeadersAvailableMock(_, uncompressed_headers.length()));
- stream->SetDelegate(&delegate_);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(headers_, delegate_.headers_);
-
- // Times(2) because OnClose will be called for stream and stream_.
- EXPECT_CALL(delegate_, OnClose()).Times(2);
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_chromium_connection_helper.cc b/chromium/net/quic/quic_chromium_connection_helper.cc
deleted file mode 100644
index 9bdb4072559..00000000000
--- a/chromium/net/quic/quic_chromium_connection_helper.cc
+++ /dev/null
@@ -1,28 +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/quic_chromium_connection_helper.h"
-
-namespace net {
-
-QuicChromiumConnectionHelper::QuicChromiumConnectionHelper(
- const QuicClock* clock,
- QuicRandom* random_generator)
- : clock_(clock), random_generator_(random_generator) {}
-
-QuicChromiumConnectionHelper::~QuicChromiumConnectionHelper() {}
-
-const QuicClock* QuicChromiumConnectionHelper::GetClock() const {
- return clock_;
-}
-
-QuicRandom* QuicChromiumConnectionHelper::GetRandomGenerator() {
- return random_generator_;
-}
-
-QuicBufferAllocator* QuicChromiumConnectionHelper::GetBufferAllocator() {
- return &buffer_allocator_;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_chromium_connection_helper.h b/chromium/net/quic/quic_chromium_connection_helper.h
deleted file mode 100644
index 0fbe7c3bb3a..00000000000
--- a/chromium/net/quic/quic_chromium_connection_helper.h
+++ /dev/null
@@ -1,46 +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.
-//
-// The Chrome-specific helper for QuicConnection which uses
-// a TaskRunner for alarms, and uses a DatagramClientSocket for writing data.
-
-#ifndef NET_QUIC_QUIC_CHROMIUM_CONNECTION_HELPER_H_
-#define NET_QUIC_QUIC_CHROMIUM_CONNECTION_HELPER_H_
-
-#include "base/macros.h"
-#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_simple_buffer_allocator.h"
-#include "net/quic/quic_time.h"
-#include "net/udp/datagram_client_socket.h"
-
-namespace net {
-
-class QuicClock;
-class QuicRandom;
-
-class NET_EXPORT_PRIVATE QuicChromiumConnectionHelper
- : public QuicConnectionHelperInterface {
- public:
- QuicChromiumConnectionHelper(const QuicClock* clock,
- QuicRandom* random_generator);
- ~QuicChromiumConnectionHelper() override;
-
- // QuicConnectionHelperInterface
- const QuicClock* GetClock() const override;
- QuicRandom* GetRandomGenerator() override;
- QuicBufferAllocator* GetBufferAllocator() override;
-
- private:
- const QuicClock* clock_;
- QuicRandom* random_generator_;
- SimpleBufferAllocator buffer_allocator_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicChromiumConnectionHelper);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CHROMIUM_CONNECTION_HELPER_H_
diff --git a/chromium/net/quic/quic_chromium_connection_helper_test.cc b/chromium/net/quic/quic_chromium_connection_helper_test.cc
deleted file mode 100644
index 356ac6c7880..00000000000
--- a/chromium/net/quic/quic_chromium_connection_helper_test.cc
+++ /dev/null
@@ -1,34 +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/quic_chromium_connection_helper.h"
-
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/test_tools/mock_random.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-namespace {
-
-class QuicChromiumConnectionHelperTest : public ::testing::Test {
- protected:
- QuicChromiumConnectionHelperTest() : helper_(&clock_, &random_generator_) {}
-
- QuicChromiumConnectionHelper helper_;
- MockClock clock_;
- MockRandom random_generator_;
-};
-
-TEST_F(QuicChromiumConnectionHelperTest, GetClock) {
- EXPECT_EQ(&clock_, helper_.GetClock());
-}
-
-TEST_F(QuicChromiumConnectionHelperTest, GetRandomGenerator) {
- EXPECT_EQ(&random_generator_, helper_.GetRandomGenerator());
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_chromium_packet_reader.cc b/chromium/net/quic/quic_chromium_packet_reader.cc
deleted file mode 100644
index dbd67a562be..00000000000
--- a/chromium/net/quic/quic_chromium_packet_reader.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-// 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.
-
-#include "net/quic/quic_chromium_packet_reader.h"
-
-#include "base/location.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "net/base/net_errors.h"
-#include "net/quic/quic_clock.h"
-
-namespace net {
-
-QuicChromiumPacketReader::QuicChromiumPacketReader(
- DatagramClientSocket* socket,
- QuicClock* clock,
- Visitor* visitor,
- int yield_after_packets,
- QuicTime::Delta yield_after_duration,
- const BoundNetLog& net_log)
- : socket_(socket),
- visitor_(visitor),
- read_pending_(false),
- num_packets_read_(0),
- clock_(clock),
- yield_after_packets_(yield_after_packets),
- yield_after_duration_(yield_after_duration),
- yield_after_(QuicTime::Infinite()),
- read_buffer_(new IOBufferWithSize(static_cast<size_t>(kMaxPacketSize))),
- net_log_(net_log),
- weak_factory_(this) {}
-
-QuicChromiumPacketReader::~QuicChromiumPacketReader() {}
-
-void QuicChromiumPacketReader::StartReading() {
- if (read_pending_)
- return;
-
- if (num_packets_read_ == 0)
- yield_after_ = clock_->Now().Add(yield_after_duration_);
-
- DCHECK(socket_);
- read_pending_ = true;
- int rv = socket_->Read(read_buffer_.get(), read_buffer_->size(),
- base::Bind(&QuicChromiumPacketReader::OnReadComplete,
- weak_factory_.GetWeakPtr()));
- UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.AsyncRead", rv == ERR_IO_PENDING);
- if (rv == ERR_IO_PENDING) {
- num_packets_read_ = 0;
- return;
- }
-
- if (++num_packets_read_ > yield_after_packets_ ||
- clock_->Now() > yield_after_) {
- num_packets_read_ = 0;
- // Data was read, process it.
- // Schedule the work through the message loop to 1) prevent infinite
- // recursion and 2) avoid blocking the thread for too long.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&QuicChromiumPacketReader::OnReadComplete,
- weak_factory_.GetWeakPtr(), rv));
- } else {
- OnReadComplete(rv);
- }
-}
-
-void QuicChromiumPacketReader::OnReadComplete(int result) {
- read_pending_ = false;
- if (result == 0)
- result = ERR_CONNECTION_CLOSED;
-
- if (result < 0) {
- visitor_->OnReadError(result, socket_);
- return;
- }
-
- QuicReceivedPacket packet(read_buffer_->data(), result, clock_->Now());
- IPEndPoint local_address;
- IPEndPoint peer_address;
- socket_->GetLocalAddress(&local_address);
- socket_->GetPeerAddress(&peer_address);
- if (!visitor_->OnPacket(packet, local_address, peer_address))
- return;
-
- StartReading();
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_chromium_packet_reader.h b/chromium/net/quic/quic_chromium_packet_reader.h
deleted file mode 100644
index 1991ea6ec38..00000000000
--- a/chromium/net/quic/quic_chromium_packet_reader.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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.
-//
-
-#ifndef NET_QUIC_QUIC_CHROMIUM_PACKET_READER_H_
-#define NET_QUIC_QUIC_CHROMIUM_PACKET_READER_H_
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_export.h"
-#include "net/log/net_log.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-#include "net/udp/datagram_client_socket.h"
-
-namespace net {
-
-class QuicClock;
-
-// If more than this many packets have been read or more than that many
-// milliseconds have passed, QuicChromiumPacketReader::StartReading() yields by
-// doing a QuicChromiumPacketReader::PostTask().
-const int kQuicYieldAfterPacketsRead = 32;
-const int kQuicYieldAfterDurationMilliseconds = 20;
-
-class NET_EXPORT_PRIVATE QuicChromiumPacketReader {
- public:
- class NET_EXPORT_PRIVATE Visitor {
- public:
- virtual ~Visitor() {}
- virtual void OnReadError(int result,
- const DatagramClientSocket* socket) = 0;
- virtual bool OnPacket(const QuicReceivedPacket& packet,
- IPEndPoint local_address,
- IPEndPoint peer_address) = 0;
- };
-
- QuicChromiumPacketReader(DatagramClientSocket* socket,
- QuicClock* clock,
- Visitor* visitor,
- int yield_after_packets,
- QuicTime::Delta yield_after_duration,
- const BoundNetLog& net_log);
- virtual ~QuicChromiumPacketReader();
-
- // Causes the QuicConnectionHelper to start reading from the socket
- // and passing the data along to the QuicConnection.
- void StartReading();
-
- private:
- // A completion callback invoked when a read completes.
- void OnReadComplete(int result);
-
- DatagramClientSocket* socket_;
- Visitor* visitor_;
- bool read_pending_;
- int num_packets_read_;
- QuicClock* clock_; // Owned by QuicStreamFactory
- int yield_after_packets_;
- QuicTime::Delta yield_after_duration_;
- QuicTime yield_after_;
- scoped_refptr<IOBufferWithSize> read_buffer_;
- BoundNetLog net_log_;
-
- base::WeakPtrFactory<QuicChromiumPacketReader> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicChromiumPacketReader);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CHROMIUM_PACKET_READER_H_
diff --git a/chromium/net/quic/quic_chromium_packet_writer.cc b/chromium/net/quic/quic_chromium_packet_writer.cc
deleted file mode 100644
index fac2f708826..00000000000
--- a/chromium/net/quic/quic_chromium_packet_writer.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_chromium_packet_writer.h"
-
-#include <string>
-
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/sparse_histogram.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-
-namespace net {
-
-QuicChromiumPacketWriter::QuicChromiumPacketWriter() : weak_factory_(this) {}
-
-QuicChromiumPacketWriter::QuicChromiumPacketWriter(Socket* socket)
- : socket_(socket), write_blocked_(false), weak_factory_(this) {}
-
-QuicChromiumPacketWriter::~QuicChromiumPacketWriter() {}
-
-WriteResult QuicChromiumPacketWriter::WritePacket(
- const char* buffer,
- size_t buf_len,
- const IPAddress& self_address,
- const IPEndPoint& peer_address,
- PerPacketOptions* /*options*/) {
- scoped_refptr<StringIOBuffer> buf(
- new StringIOBuffer(std::string(buffer, buf_len)));
- DCHECK(!IsWriteBlocked());
- base::TimeTicks now = base::TimeTicks::Now();
- int rv = socket_->Write(buf.get(), buf_len,
- base::Bind(&QuicChromiumPacketWriter::OnWriteComplete,
- weak_factory_.GetWeakPtr()));
- WriteStatus status = WRITE_STATUS_OK;
- if (rv < 0) {
- if (rv != ERR_IO_PENDING) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.WriteError", -rv);
- status = WRITE_STATUS_ERROR;
- } else {
- status = WRITE_STATUS_BLOCKED;
- write_blocked_ = true;
- }
- }
-
- base::TimeDelta delta = base::TimeTicks::Now() - now;
- if (status == WRITE_STATUS_OK) {
- UMA_HISTOGRAM_TIMES("Net.QuicSession.PacketWriteTime.Synchronous", delta);
- } else if (status == WRITE_STATUS_BLOCKED) {
- UMA_HISTOGRAM_TIMES("Net.QuicSession.PacketWriteTime.Asynchronous", delta);
- }
-
- return WriteResult(status, rv);
-}
-
-bool QuicChromiumPacketWriter::IsWriteBlockedDataBuffered() const {
- // Chrome sockets' Write() methods buffer the data until the Write is
- // permitted.
- return true;
-}
-
-bool QuicChromiumPacketWriter::IsWriteBlocked() const {
- return write_blocked_;
-}
-
-void QuicChromiumPacketWriter::SetWritable() {
- write_blocked_ = false;
-}
-
-void QuicChromiumPacketWriter::OnWriteComplete(int rv) {
- DCHECK_NE(rv, ERR_IO_PENDING);
- write_blocked_ = false;
- if (rv < 0) {
- connection_->OnWriteError(rv);
- }
- connection_->OnCanWrite();
-}
-
-QuicByteCount QuicChromiumPacketWriter::GetMaxPacketSize(
- const IPEndPoint& peer_address) const {
- return kMaxPacketSize;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_chromium_packet_writer.h b/chromium/net/quic/quic_chromium_packet_writer.h
deleted file mode 100644
index c8aa757b045..00000000000
--- a/chromium/net/quic/quic_chromium_packet_writer.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_CHROMIUM_PACKET_WRITER_H_
-#define NET_QUIC_QUIC_CHROMIUM_PACKET_WRITER_H_
-
-#include <stddef.h>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_types.h"
-#include "net/udp/datagram_client_socket.h"
-
-namespace net {
-
-// Chrome specific packet writer which uses a datagram Socket for writing data.
-class NET_EXPORT_PRIVATE QuicChromiumPacketWriter : public QuicPacketWriter {
- public:
- QuicChromiumPacketWriter();
- explicit QuicChromiumPacketWriter(Socket* socket);
- ~QuicChromiumPacketWriter() override;
-
- // QuicPacketWriter
- WriteResult WritePacket(const char* buffer,
- size_t buf_len,
- const IPAddress& self_address,
- const IPEndPoint& peer_address,
- PerPacketOptions* options) override;
- bool IsWriteBlockedDataBuffered() const override;
- bool IsWriteBlocked() const override;
- void SetWritable() override;
- QuicByteCount GetMaxPacketSize(const IPEndPoint& peer_address) const override;
-
- void OnWriteComplete(int rv);
- void SetConnection(QuicConnection* connection) { connection_ = connection; }
-
- protected:
- void set_write_blocked(bool is_blocked) { write_blocked_ = is_blocked; }
-
- private:
- Socket* socket_;
- QuicConnection* connection_;
-
- // Whether a write is currently in flight.
- bool write_blocked_;
-
- base::WeakPtrFactory<QuicChromiumPacketWriter> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicChromiumPacketWriter);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CHROMIUM_PACKET_WRITER_H_
diff --git a/chromium/net/quic/quic_client_promised_info.cc b/chromium/net/quic/quic_client_promised_info.cc
deleted file mode 100644
index 4de7adf83f3..00000000000
--- a/chromium/net/quic/quic_client_promised_info.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_client_promised_info.h"
-
-#include "base/logging.h"
-#include "net/quic/spdy_utils.h"
-
-using net::SpdyHeaderBlock;
-using net::kPushPromiseTimeoutSecs;
-using std::string;
-
-namespace net {
-
-QuicClientPromisedInfo::QuicClientPromisedInfo(QuicClientSessionBase* session,
- QuicStreamId id,
- string url)
- : session_(session),
- id_(id),
- url_(url),
- client_request_delegate_(nullptr) {}
-
-QuicClientPromisedInfo::~QuicClientPromisedInfo() {}
-
-void QuicClientPromisedInfo::CleanupAlarm::OnAlarm() {
- DVLOG(1) << "self GC alarm for stream " << promised_->id_;
- promised_->Reset(QUIC_STREAM_CANCELLED);
-}
-
-void QuicClientPromisedInfo::Init() {
- cleanup_alarm_.reset(session_->connection()->alarm_factory()->CreateAlarm(
- new QuicClientPromisedInfo::CleanupAlarm(this)));
- cleanup_alarm_->Set(
- session_->connection()->helper()->GetClock()->ApproximateNow().Add(
- QuicTime::Delta::FromSeconds(kPushPromiseTimeoutSecs)));
-}
-
-void QuicClientPromisedInfo::OnPromiseHeaders(const SpdyHeaderBlock& headers) {
- // RFC7540, Section 8.2, requests MUST be safe [RFC7231], Section
- // 4.2.1. GET and HEAD are the methods that are safe and required.
- SpdyHeaderBlock::const_iterator it = headers.find(":method");
- DCHECK(it != headers.end());
- if (!(it->second == "GET" || it->second == "HEAD")) {
- DVLOG(1) << "Promise for stream " << id_ << " has invalid method "
- << it->second;
- Reset(QUIC_INVALID_PROMISE_METHOD);
- return;
- }
- if (!SpdyUtils::UrlIsValid(headers)) {
- DVLOG(1) << "Promise for stream " << id_ << " has invalid URL " << url_;
- Reset(QUIC_INVALID_PROMISE_URL);
- return;
- }
- if (!session_->IsAuthorized(SpdyUtils::GetHostNameFromHeaderBlock(headers))) {
- Reset(QUIC_UNAUTHORIZED_PROMISE_URL);
- return;
- }
- request_headers_.reset(new SpdyHeaderBlock(headers.Clone()));
-}
-
-void QuicClientPromisedInfo::OnResponseHeaders(const SpdyHeaderBlock& headers) {
- response_headers_.reset(new SpdyHeaderBlock(headers.Clone()));
- if (client_request_delegate_) {
- // We already have a client request waiting.
- FinalValidation();
- }
-}
-
-void QuicClientPromisedInfo::Reset(QuicRstStreamErrorCode error_code) {
- QuicClientPushPromiseIndex::Delegate* delegate = client_request_delegate_;
- session_->ResetPromised(id_, error_code);
- session_->DeletePromised(this);
- if (delegate) {
- delegate->OnRendezvousResult(nullptr);
- }
-}
-
-QuicAsyncStatus QuicClientPromisedInfo::FinalValidation() {
- if (!client_request_delegate_->CheckVary(
- *client_request_headers_, *request_headers_, *response_headers_)) {
- Reset(QUIC_PROMISE_VARY_MISMATCH);
- return QUIC_FAILURE;
- }
- QuicSpdyStream* stream = session_->GetPromisedStream(id_);
- if (!stream) {
- // This shouldn't be possible, as |ClientRequest| guards against
- // closed stream for the synchronous case. And in the
- // asynchronous case, a RST can only be caught by |OnAlarm()|.
- QUIC_BUG << "missing promised stream" << id_;
- }
- QuicClientPushPromiseIndex::Delegate* delegate = client_request_delegate_;
- session_->DeletePromised(this);
- // Stream can start draining now
- if (delegate) {
- delegate->OnRendezvousResult(stream);
- }
- return QUIC_SUCCESS;
-}
-
-QuicAsyncStatus QuicClientPromisedInfo::HandleClientRequest(
- const SpdyHeaderBlock& request_headers,
- QuicClientPushPromiseIndex::Delegate* delegate) {
- if (session_->IsClosedStream(id_)) {
- // There was a RST on the response stream.
- session_->DeletePromised(this);
- return QUIC_FAILURE;
- }
- client_request_delegate_ = delegate;
- client_request_headers_.reset(new SpdyHeaderBlock(request_headers.Clone()));
- if (!response_headers_) {
- return QUIC_PENDING;
- }
- return FinalValidation();
-}
-
-void QuicClientPromisedInfo::Cancel() {
- // Don't fire OnRendezvousResult() for client initiated cancel.
- client_request_delegate_ = nullptr;
- Reset(QUIC_STREAM_CANCELLED);
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_client_promised_info.h b/chromium/net/quic/quic_client_promised_info.h
deleted file mode 100644
index 5b14d145491..00000000000
--- a/chromium/net/quic/quic_client_promised_info.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_CLIENT_PROMISED_INFO_H_
-#define NET_QUIC_QUIC_CLIENT_PROMISED_INFO_H_
-
-#include <sys/types.h>
-#include <string>
-
-#include "net/quic/quic_alarm.h"
-#include "net/quic/quic_client_push_promise_index.h"
-#include "net/quic/quic_client_session_base.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_spdy_stream.h"
-#include "net/spdy/spdy_framer.h"
-
-namespace net {
-
-class QuicClientSessionBase;
-class QuicDataToResend;
-class QuicConnectionHelperInterface;
-
-namespace test {
-class QuicClientPromisedInfoPeer;
-} // namespace test
-
-// QuicClientPromisedInfo tracks the client state of a server push
-// stream from the time a PUSH_PROMISE is received until rendezvous
-// between the promised response and the corresponding client request
-// is complete.
-class NET_EXPORT_PRIVATE QuicClientPromisedInfo
- : public QuicClientPushPromiseIndex::TryHandle {
- public:
- // Interface to QuicSpdyClientStream
- QuicClientPromisedInfo(QuicClientSessionBase* session,
- QuicStreamId id,
- std::string url);
- virtual ~QuicClientPromisedInfo();
-
- void Init();
-
- // Validate promise headers etc.
- void OnPromiseHeaders(const SpdyHeaderBlock& request_headers);
-
- // Store response, possibly proceed with final validation.
- void OnResponseHeaders(const SpdyHeaderBlock& response_headers);
-
- // Rendezvous between this promised stream and a client request that
- // has a matching URL.
- virtual QuicAsyncStatus HandleClientRequest(
- const SpdyHeaderBlock& headers,
- QuicClientPushPromiseIndex::Delegate* delegate);
-
- void Cancel() override;
-
- void Reset(QuicRstStreamErrorCode error_code);
-
- // Client requests are initially associated to promises by matching
- // URL in the client request against the URL in the promise headers,
- // uing the |promised_by_url| map. The push can be cross-origin, so
- // the client should validate that the session is authoritative for
- // the promised URL. If not, it should call |RejectUnauthorized|.
- QuicClientSessionBase* session() { return session_; }
-
- // If the promised response contains Vary header, then the fields
- // specified by Vary must match between the client request header
- // and the promise headers (see https://crbug.com//554220). Vary
- // validation requires the response headers (for the actual Vary
- // field list), the promise headers (taking the role of the "cached"
- // request), and the client request headers.
- SpdyHeaderBlock* request_headers() { return request_headers_.get(); }
-
- SpdyHeaderBlock* response_headers() { return response_headers_.get(); }
-
- QuicStreamId id() const { return id_; }
-
- const std::string url() const { return url_; }
-
- private:
- friend class test::QuicClientPromisedInfoPeer;
-
- class CleanupAlarm : public QuicAlarm::Delegate {
- public:
- explicit CleanupAlarm(QuicClientPromisedInfo* promised)
- : promised_(promised) {}
-
- void OnAlarm() override;
-
- QuicClientPromisedInfo* promised_;
- };
-
- QuicAsyncStatus FinalValidation();
-
- QuicClientSessionBase* session_;
- QuicStreamId id_;
- std::string url_;
- std::unique_ptr<SpdyHeaderBlock> request_headers_;
- std::unique_ptr<SpdyHeaderBlock> response_headers_;
- std::unique_ptr<SpdyHeaderBlock> client_request_headers_;
- QuicClientPushPromiseIndex::Delegate* client_request_delegate_;
-
- // The promise will commit suicide eventually if it is not claimed
- // by a GET first.
- std::unique_ptr<QuicAlarm> cleanup_alarm_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicClientPromisedInfo);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CLIENT_PROMISED_INFO_H_
diff --git a/chromium/net/quic/quic_client_promised_info_test.cc b/chromium/net/quic/quic_client_promised_info_test.cc
deleted file mode 100644
index fef467f72a9..00000000000
--- a/chromium/net/quic/quic_client_promised_info_test.cc
+++ /dev/null
@@ -1,380 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_client_promised_info.h"
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/scoped_ptr.h"
-#include "net/gfe2/balsa_headers.h"
-#include "net/quic/quic_client.h"
-#include "net/quic/quic_client_session.h"
-#include "net/quic/quic_spdy_client_stream.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/spdy_balsa_utils.h"
-#include "net/quic/spdy_utils.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/util/ipaddress.h"
-#include "testing/base/public/gunit.h"
-
-using SpdyHeaderBlock;
-using BalsaHeaders;
-using testing::StrictMock;
-
-namespace net {
-namespace test {
-
-class QuicClientPromisedInfoPeer {
- public:
- static QuicAlarm* GetAlarm(QuicClientPromisedInfo* promised_stream) {
- return promised_stream->cleanup_alarm_.get();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(QuicClientPromisedInfoPeer);
-};
-
-namespace {
-
-class MockQuicClientSession : public QuicClientSession {
- public:
- explicit MockQuicClientSession(QuicConnection* connection,
- QuicClientPushPromiseIndex* push_promise_index)
- : QuicClientSession(
- DefaultQuicConfig(),
- connection,
- QuicServerId("example.com", 443, PRIVACY_MODE_DISABLED),
- &crypto_config_,
- push_promise_index),
- crypto_config_(CryptoTestUtils::ProofVerifierForTesting()),
- authorized_(true) {}
- ~MockQuicClientSession() override {}
-
- bool IsAuthorized(const string& authority) override { return authorized_; }
-
- void set_authorized(bool authorized) { authorized_ = authorized; }
-
- MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id));
-
- private:
- QuicCryptoClientConfig crypto_config_;
-
- bool authorized_;
-
- DISALLOW_COPY_AND_ASSIGN(MockQuicClientSession);
-};
-
-class QuicClientPromisedInfoTest : public ::testing::Test {
- public:
- class StreamVisitor;
-
- QuicClientPromisedInfoTest()
- : connection_(new StrictMock<MockQuicConnection>(&helper_,
- &alarm_factory_,
- Perspective::IS_CLIENT)),
- session_(connection_, &push_promise_index_),
- body_("hello world"),
- promise_id_(gfe_quic::test::kServerDataStreamId1) {
- FLAGS_quic_supports_push_promise = true;
-
- session_.Initialize();
-
- headers_.SetResponseFirstline("HTTP/1.1", 200, "Ok");
- headers_.ReplaceOrAppendHeader("content-length", "11");
- headers_string_ = SpdyBalsaUtils::SerializeResponseHeaders(headers_);
-
- stream_.reset(new QuicSpdyClientStream(gfe_quic::test::kClientDataStreamId1,
- &session_));
- stream_visitor_.reset(new StreamVisitor());
- stream_->set_visitor(stream_visitor_.get());
-
- push_promise_[":path"] = "/bar";
- push_promise_[":authority"] = "www.google.com";
- push_promise_[":version"] = "HTTP/1.1";
- push_promise_[":method"] = "GET";
- push_promise_[":scheme"] = "https";
-
- promise_url_ = SpdyUtils::GetUrlFromHeaderBlock(push_promise_);
- serialized_push_promise_ =
- SpdyUtils::SerializeUncompressedHeaders(push_promise_);
-
- client_request_ = push_promise_.Clone();
- }
-
- class StreamVisitor : public QuicSpdyClientStream::Visitor {
- void OnClose(QuicSpdyStream* stream) override {
- DVLOG(1) << "stream " << stream->id();
- }
- };
-
- class PushPromiseDelegate : public QuicClientPushPromiseIndex::Delegate {
- public:
- explicit PushPromiseDelegate(bool match)
- : match_(match),
- rendezvous_fired_(false),
- rendezvous_stream_(nullptr) {}
-
- bool CheckVary(const SpdyHeaderBlock& client_request,
- const SpdyHeaderBlock& promise_request,
- const SpdyHeaderBlock& promise_response) override {
- DVLOG(1) << "match " << match_;
- return match_;
- }
-
- void OnRendezvousResult(QuicSpdyClientStream* stream) override {
- rendezvous_fired_ = true;
- rendezvous_stream_ = stream;
- }
-
- QuicSpdyClientStream* rendezvous_stream() { return rendezvous_stream_; }
- bool rendezvous_fired() { return rendezvous_fired_; }
-
- private:
- bool match_;
- bool rendezvous_fired_;
- QuicSpdyClientStream* rendezvous_stream_;
- };
-
- void ReceivePromise(QuicStreamId id) {
- stream_->OnStreamHeaders(serialized_push_promise_);
-
- stream_->OnPromiseHeadersComplete(id, serialized_push_promise_.size());
- }
-
- MockQuicConnectionHelper helper_;
- MockAlarmFactory alarm_factory_;
- StrictMock<MockQuicConnection>* connection_;
- QuicClientPushPromiseIndex push_promise_index_;
-
- MockQuicClientSession session_;
- std::unique_ptr<QuicSpdyClientStream> stream_;
- std::unique_ptr<StreamVisitor> stream_visitor_;
- std::unique_ptr<QuicSpdyClientStream> promised_stream_;
- BalsaHeaders headers_;
- string headers_string_;
- string body_;
- SpdyHeaderBlock push_promise_;
- QuicStreamId promise_id_;
- string promise_url_;
- string serialized_push_promise_;
- SpdyHeaderBlock client_request_;
-};
-
-TEST_F(QuicClientPromisedInfoTest, PushPromise) {
- ReceivePromise(promise_id_);
-
- // Verify that the promise is in the unclaimed streams map.
- EXPECT_NE(session_.GetPromisedById(promise_id_), nullptr);
-}
-
-TEST_F(QuicClientPromisedInfoTest, PushPromiseCleanupAlarm) {
- ReceivePromise(promise_id_);
-
- // Verify that the promise is in the unclaimed streams map.
- QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_);
- ASSERT_NE(promised, nullptr);
-
- // Fire the alarm that will cancel the promised stream.
- EXPECT_CALL(*connection_,
- SendRstStream(promise_id_, QUIC_STREAM_CANCELLED, 0));
- alarm_factory_.FireAlarm(QuicClientPromisedInfoPeer::GetAlarm(promised));
-
- // Verify that the promise is gone after the alarm fires.
- EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
- EXPECT_EQ(session_.GetPromisedByUrl(promise_url_), nullptr);
-}
-
-TEST_F(QuicClientPromisedInfoTest, PushPromiseInvalidMethod) {
- // Promise with an unsafe method
- push_promise_[":method"] = "PUT";
- serialized_push_promise_ =
- SpdyUtils::SerializeUncompressedHeaders(push_promise_);
-
- EXPECT_CALL(*connection_,
- SendRstStream(promise_id_, QUIC_INVALID_PROMISE_METHOD, 0));
- ReceivePromise(promise_id_);
-
- // Verify that the promise headers were ignored
- EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
- EXPECT_EQ(session_.GetPromisedByUrl(promise_url_), nullptr);
-}
-
-TEST_F(QuicClientPromisedInfoTest, PushPromiseInvalidUrl) {
- // Remove required header field to make URL invalid
- push_promise_.erase(":authority");
- serialized_push_promise_ =
- SpdyUtils::SerializeUncompressedHeaders(push_promise_);
-
- EXPECT_CALL(*connection_,
- SendRstStream(promise_id_, QUIC_INVALID_PROMISE_URL, 0));
- ReceivePromise(promise_id_);
-
- // Verify that the promise headers were ignored
- EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
- EXPECT_EQ(session_.GetPromisedByUrl(promise_url_), nullptr);
-}
-
-TEST_F(QuicClientPromisedInfoTest, PushPromiseInvalidUrl) {
- // Promise with an unsafe method
- push_promise_[":method"] = "PUT";
- serialized_push_promise_ =
- SpdyUtils::SerializeUncompressedHeaders(push_promise_);
-
- EXPECT_CALL(*connection_,
- SendRstStream(promise_id_, QUIC_INVALID_PROMISE_METHOD, 0));
- ReceivePromise(promise_id_);
-
- // Verify that the promise headers were ignored
- EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
- EXPECT_EQ(session_.GetPromisedByUrl(promise_url_), nullptr);
-}
-
-TEST_F(QuicClientPromisedInfoTest, PushPromiseUnauthorizedUrl) {
- session_.set_authorized(false);
-
- EXPECT_CALL(*connection_,
- SendRstStream(promise_id_, QUIC_UNAUTHORIZED_PROMISE_URL, 0));
-
- ReceivePromise(promise_id_);
-
- QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_);
- ASSERT_EQ(promised, nullptr);
-}
-
-TEST_F(QuicClientPromisedInfoTest, PushPromiseMismatch) {
- ReceivePromise(promise_id_);
-
- QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_);
- ASSERT_NE(promised, nullptr);
-
- // Need to send the promised response headers and initiate the
- // rendezvous for secondary validation to proceed.
- QuicSpdyClientStream* promise_stream = static_cast<QuicSpdyClientStream*>(
- session_.GetOrCreateStream(promise_id_));
- promise_stream->OnStreamHeaders(headers_string_);
- promise_stream->OnStreamHeadersComplete(false, headers_string_.size());
-
- PushPromiseDelegate delegate(/*match=*/false);
- EXPECT_CALL(*connection_,
- SendRstStream(promise_id_, QUIC_PROMISE_VARY_MISMATCH, 0));
- EXPECT_CALL(session_, CloseStream(promise_id_));
-
- promised->HandleClientRequest(client_request_, &delegate);
-}
-
-TEST_F(QuicClientPromisedInfoTest, PushPromiseVaryWaits) {
- ReceivePromise(promise_id_);
-
- QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_);
- ASSERT_NE(promised, nullptr);
-
- // Now initiate rendezvous.
- PushPromiseDelegate delegate(/*match=*/true);
- promised->HandleClientRequest(std::move(client_request_), &delegate);
-
- // Promise is still there, waiting for response.
- EXPECT_NE(session_.GetPromisedById(promise_id_), nullptr);
-
- // Send Response, should trigger promise validation and complete rendezvous
- QuicSpdyClientStream* promise_stream = static_cast<QuicSpdyClientStream*>(
- session_.GetOrCreateStream(promise_id_));
- ASSERT_NE(promise_stream, nullptr);
- promise_stream->OnStreamHeaders(headers_string_);
- promise_stream->OnStreamHeadersComplete(false, headers_string_.size());
-
- // Promise is gone
- EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
-}
-
-TEST_F(QuicClientPromisedInfoTest, PushPromiseVaryNoWait) {
- ReceivePromise(promise_id_);
-
- QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_);
- ASSERT_NE(promised, nullptr);
-
- QuicSpdyClientStream* promise_stream = static_cast<QuicSpdyClientStream*>(
- session_.GetOrCreateStream(promise_id_));
- ASSERT_NE(promise_stream, nullptr);
-
- // Send Response, should trigger promise validation and complete rendezvous
- promise_stream->OnStreamHeaders(headers_string_);
- promise_stream->OnStreamHeadersComplete(false, headers_string_.size());
-
- // Now initiate rendezvous.
- PushPromiseDelegate delegate(/*match=*/true);
- promised->HandleClientRequest(std::move(client_request_), &delegate);
-
- // Promise is gone
- EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
- // Have a push stream
- EXPECT_TRUE(delegate.rendezvous_fired());
-
- EXPECT_NE(delegate.rendezvous_stream(), nullptr);
-}
-
-TEST_F(QuicClientPromisedInfoTest, PushPromiseWaitCancels) {
- ReceivePromise(promise_id_);
-
- QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_);
- ASSERT_NE(promised, nullptr);
-
- // Now initiate rendezvous.
- PushPromiseDelegate delegate(/*match=*/true);
- promised->HandleClientRequest(std::move(client_request_), &delegate);
-
- // Promise is still there, waiting for response.
- EXPECT_NE(session_.GetPromisedById(promise_id_), nullptr);
-
- // Create response stream, but no data yet.
- session_.GetOrCreateStream(promise_id_);
-
- // Fire the alarm that will cancel the promised stream.
- EXPECT_CALL(session_, CloseStream(promise_id_));
- EXPECT_CALL(*connection_,
- SendRstStream(promise_id_, QUIC_STREAM_CANCELLED, 0));
- promised->Cancel();
-
- // Promise is gone
- EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
-}
-
-TEST_F(QuicClientPromisedInfoTest, PushPromiseDataClosed) {
- ReceivePromise(promise_id_);
-
- QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_);
- ASSERT_NE(promised, nullptr);
-
- QuicSpdyClientStream* promise_stream = static_cast<QuicSpdyClientStream*>(
- session_.GetOrCreateStream(promise_id_));
- ASSERT_NE(promise_stream, nullptr);
-
- // Send response, rendezvous will be able to finish synchronously.
- promise_stream->OnStreamHeaders(headers_string_);
- promise_stream->OnStreamHeadersComplete(false, headers_string_.size());
-
- EXPECT_CALL(session_, CloseStream(promise_id_));
- EXPECT_CALL(*connection_,
- SendRstStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0));
- session_.SendRstStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0);
-
- // Now initiate rendezvous.
- PushPromiseDelegate delegate(/*match=*/true);
- EXPECT_EQ(
- promised->HandleClientRequest(std::move(client_request_), &delegate),
- QUIC_FAILURE);
-
- // Got an indication of the stream failure, client should retry
- // request.
- EXPECT_FALSE(delegate.rendezvous_fired());
- EXPECT_EQ(delegate.rendezvous_stream(), nullptr);
-
- // Promise is gone
- EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr);
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_client_push_promise_index.cc b/chromium/net/quic/quic_client_push_promise_index.cc
deleted file mode 100644
index e62f1f07c38..00000000000
--- a/chromium/net/quic/quic_client_push_promise_index.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_client_push_promise_index.h"
-
-#include <string>
-
-#include "net/quic/quic_client_promised_info.h"
-#include "net/quic/spdy_utils.h"
-
-using net::SpdyHeaderBlock;
-using std::string;
-
-namespace net {
-
-QuicClientPushPromiseIndex::QuicClientPushPromiseIndex() {}
-
-QuicClientPushPromiseIndex::~QuicClientPushPromiseIndex() {}
-
-QuicClientPushPromiseIndex::TryHandle::~TryHandle() {}
-
-QuicClientPromisedInfo* QuicClientPushPromiseIndex::GetPromised(
- const string& url) {
- QuicPromisedByUrlMap::iterator it = promised_by_url_.find(url);
- if (it == promised_by_url_.end()) {
- return nullptr;
- }
- return it->second;
-}
-
-QuicAsyncStatus QuicClientPushPromiseIndex::Try(
- const SpdyHeaderBlock& request,
- QuicClientPushPromiseIndex::Delegate* delegate,
- TryHandle** handle) {
- string url(SpdyUtils::GetUrlFromHeaderBlock(request));
- QuicPromisedByUrlMap::iterator it = promised_by_url_.find(url);
- if (it != promised_by_url_.end()) {
- QuicClientPromisedInfo* promised = it->second;
- QuicAsyncStatus rv = promised->HandleClientRequest(request, delegate);
- if (rv == QUIC_PENDING) {
- *handle = promised;
- }
- return rv;
- }
- return QUIC_FAILURE;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_client_push_promise_index.h b/chromium/net/quic/quic_client_push_promise_index.h
deleted file mode 100644
index f8167ae01af..00000000000
--- a/chromium/net/quic/quic_client_push_promise_index.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_CLIENT_PUSH_PROMISE_INDEX_H_
-#define NET_QUIC_QUIC_CLIENT_PUSH_PROMISE_INDEX_H_
-
-#include <string>
-
-#include "net/quic/quic_client_session_base.h"
-#include "net/quic/quic_types.h"
-
-namespace net {
-
-// QuicClientPushPromiseIndex is the interface to support rendezvous
-// between client requests and resources delivered via server push.
-// The same index can be shared across multiple sessions (e.g. for the
-// same browser users profile), since cross-origin pushes are allowed
-// (subject to authority constraints).
-
-class NET_EXPORT_PRIVATE QuicClientPushPromiseIndex {
- public:
- // Delegate is used to complete the rendezvous that began with
- // |Try()|.
- class NET_EXPORT_PRIVATE Delegate {
- public:
- virtual ~Delegate() {}
-
- // The primary lookup matched request with push promise by URL. A
- // secondary match is necessary to ensure Vary (RFC 2616, 14.14)
- // is honored. If Vary is not present, return true. If Vary is
- // present, return whether designated header fields of
- // |promise_request| and |client_request| match.
- virtual bool CheckVary(const SpdyHeaderBlock& client_request,
- const SpdyHeaderBlock& promise_request,
- const SpdyHeaderBlock& promise_response) = 0;
-
- // On rendezvous success, provides the promised |stream|. Callee
- // does not inherit ownership of |stream|. On rendezvous failure,
- // |stream| is |nullptr| and the client should retry the request.
- // Rendezvous can fail due to promise validation failure or RST on
- // promised stream. |url| will have been removed from the index
- // before |OnRendezvousResult()| is invoked, so a recursive call to
- // |Try()| will return |QUIC_FAILURE|, which may be convenient for
- // retry purposes.
- virtual void OnRendezvousResult(QuicSpdyStream* stream) = 0;
- };
-
- class NET_EXPORT_PRIVATE TryHandle {
- public:
- // Cancel the request.
- virtual void Cancel() = 0;
-
- protected:
- TryHandle() {}
- ~TryHandle();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TryHandle);
- };
-
- QuicClientPushPromiseIndex();
- virtual ~QuicClientPushPromiseIndex();
-
- // Called by client code, used to enforce affinity between requests
- // for promised streams and the session the promise came from.
- QuicClientPromisedInfo* GetPromised(const std::string& url);
-
- // Called by client code, to initiate rendezvous between a request
- // and a server push stream. If |request|'s url is in the index,
- // rendezvous will be attempted and may complete immediately or
- // asynchronously. If the matching promise and response headers
- // have already arrived, the delegate's methods will fire
- // recursively from within |Try()|. Returns |QUIC_SUCCESS| if the
- // rendezvous was a success. Returns |QUIC_FAILURE| if there was no
- // matching promise, or if there was but the rendezvous has failed.
- // Returns QUIC_PENDING if a matching promise was found, but the
- // rendezvous needs to complete asynchronously because the promised
- // response headers are not yet available. If result is
- // QUIC_PENDING, then |*handle| will set so that the caller may
- // cancel the request if need be. The caller does not inherit
- // ownership of |*handle|, and it ceases to be valid if the caller
- // invokes |handle->Cancel()| or if |delegate->OnReponse()| fires.
- QuicAsyncStatus Try(const SpdyHeaderBlock& request,
- Delegate* delegate,
- TryHandle** handle);
-
- QuicPromisedByUrlMap* promised_by_url() { return &promised_by_url_; }
-
- private:
- QuicPromisedByUrlMap promised_by_url_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicClientPushPromiseIndex);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CLIENT_PUSH_PROMISE_INDEX_H_
diff --git a/chromium/net/quic/quic_client_push_promise_index_test.cc b/chromium/net/quic/quic_client_push_promise_index_test.cc
deleted file mode 100644
index a06379a43aa..00000000000
--- a/chromium/net/quic/quic_client_push_promise_index_test.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_client_push_promise_index.h"
-
-#include <string>
-
-#include "net/quic/spdy_utils.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/mock_quic_client_promised_info.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/tools/quic/quic_client_session.h"
-
-using testing::_;
-using testing::Return;
-using testing::StrictMock;
-using std::string;
-
-namespace net {
-namespace test {
-namespace {
-
-class MockQuicClientSession : public QuicClientSession {
- public:
- explicit MockQuicClientSession(QuicConnection* connection,
- QuicClientPushPromiseIndex* push_promise_index)
- : QuicClientSession(
- DefaultQuicConfig(),
- connection,
- QuicServerId("example.com", 443, PRIVACY_MODE_DISABLED),
- &crypto_config_,
- push_promise_index),
- crypto_config_(CryptoTestUtils::ProofVerifierForTesting()) {}
- ~MockQuicClientSession() override {}
-
- MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id));
-
- private:
- QuicCryptoClientConfig crypto_config_;
-
- DISALLOW_COPY_AND_ASSIGN(MockQuicClientSession);
-};
-
-class QuicClientPushPromiseIndexTest : public ::testing::Test {
- public:
- QuicClientPushPromiseIndexTest()
- : connection_(new StrictMock<MockQuicConnection>(&helper_,
- &alarm_factory_,
- Perspective::IS_CLIENT)),
- session_(connection_, &index_),
- promised_(&session_, kServerDataStreamId1, url_) {
- FLAGS_quic_supports_push_promise = true;
- request_[":path"] = "/bar";
- request_[":authority"] = "www.google.com";
- request_[":version"] = "HTTP/1.1";
- request_[":method"] = "GET";
- request_[":scheme"] = "https";
- url_ = SpdyUtils::GetUrlFromHeaderBlock(request_);
- }
-
- MockQuicConnectionHelper helper_;
- MockAlarmFactory alarm_factory_;
- StrictMock<MockQuicConnection>* connection_;
- MockQuicClientSession session_;
- QuicClientPushPromiseIndex index_;
- SpdyHeaderBlock request_;
- string url_;
- MockQuicClientPromisedInfo promised_;
- QuicClientPushPromiseIndex::TryHandle* handle_;
-};
-
-TEST_F(QuicClientPushPromiseIndexTest, TryRequestSuccess) {
- (*index_.promised_by_url())[url_] = &promised_;
- EXPECT_CALL(promised_, HandleClientRequest(_, _))
- .WillOnce(Return(QUIC_SUCCESS));
- EXPECT_EQ(index_.Try(request_, nullptr, &handle_), QUIC_SUCCESS);
-}
-
-TEST_F(QuicClientPushPromiseIndexTest, TryRequestPending) {
- (*index_.promised_by_url())[url_] = &promised_;
- EXPECT_CALL(promised_, HandleClientRequest(_, _))
- .WillOnce(Return(QUIC_PENDING));
- EXPECT_EQ(index_.Try(request_, nullptr, &handle_), QUIC_PENDING);
-}
-
-TEST_F(QuicClientPushPromiseIndexTest, TryRequestFailure) {
- (*index_.promised_by_url())[url_] = &promised_;
- EXPECT_CALL(promised_, HandleClientRequest(_, _))
- .WillOnce(Return(QUIC_FAILURE));
- EXPECT_EQ(index_.Try(request_, nullptr, &handle_), QUIC_FAILURE);
-}
-
-TEST_F(QuicClientPushPromiseIndexTest, TryNoPromise) {
- EXPECT_EQ(index_.Try(request_, nullptr, &handle_), QUIC_FAILURE);
-}
-
-TEST_F(QuicClientPushPromiseIndexTest, GetNoPromise) {
- EXPECT_EQ(index_.GetPromised(url_), nullptr);
-}
-
-TEST_F(QuicClientPushPromiseIndexTest, GetPromise) {
- (*index_.promised_by_url())[url_] = &promised_;
- EXPECT_EQ(index_.GetPromised(url_), &promised_);
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_client_session_base.cc b/chromium/net/quic/quic_client_session_base.cc
deleted file mode 100644
index dff71e43e24..00000000000
--- a/chromium/net/quic/quic_client_session_base.cc
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_client_session_base.h"
-
-#include "net/quic/quic_client_promised_info.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/spdy_utils.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-
-QuicClientSessionBase::QuicClientSessionBase(
- QuicConnection* connection,
- QuicClientPushPromiseIndex* push_promise_index,
- const QuicConfig& config)
- : QuicSpdySession(connection, config),
- push_promise_index_(push_promise_index),
- largest_promised_stream_id_(kInvalidStreamId) {}
-
-QuicClientSessionBase::~QuicClientSessionBase() {
- // all promised streams for this session
- for (auto& it : promised_by_id_) {
- DVLOG(1) << "erase stream " << it.first << " url " << it.second->url();
- push_promise_index_->promised_by_url()->erase(it.second->url());
- }
-}
-
-void QuicClientSessionBase::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
- QuicSession::OnCryptoHandshakeEvent(event);
-}
-
-void QuicClientSessionBase::OnPromiseHeaders(QuicStreamId stream_id,
- StringPiece headers_data) {
- QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
- if (!stream) {
- // It's quite possible to receive headers after a stream has been reset.
- return;
- }
- stream->OnPromiseHeaders(headers_data);
-}
-
-void QuicClientSessionBase::OnInitialHeadersComplete(
- QuicStreamId stream_id,
- const SpdyHeaderBlock& response_headers) {
- // Note that the strong ordering of the headers stream means that
- // QuicSpdyClientStream::OnPromiseHeadersComplete must have already
- // been called (on the associated stream) if this is a promised
- // stream. However, this stream may not have existed at this time,
- // hence the need to query the session.
- QuicClientPromisedInfo* promised = GetPromisedById(stream_id);
- if (!promised)
- return;
-
- promised->OnResponseHeaders(response_headers);
-}
-
-void QuicClientSessionBase::OnPromiseHeadersComplete(
- QuicStreamId stream_id,
- QuicStreamId promised_stream_id,
- size_t frame_len) {
- if (promised_stream_id != kInvalidStreamId &&
- promised_stream_id <= largest_promised_stream_id_) {
- connection()->CloseConnection(
- QUIC_INVALID_STREAM_ID,
- "Received push stream id lesser or equal to the"
- " last accepted before",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
- largest_promised_stream_id_ = promised_stream_id;
-
- QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
- if (!stream) {
- // It's quite possible to receive headers after a stream has been reset.
- return;
- }
- stream->OnPromiseHeadersComplete(promised_stream_id, frame_len);
-}
-
-void QuicClientSessionBase::OnPromiseHeaderList(
- QuicStreamId stream_id,
- QuicStreamId promised_stream_id,
- size_t frame_len,
- const QuicHeaderList& header_list) {
- if (promised_stream_id != kInvalidStreamId &&
- promised_stream_id <= largest_promised_stream_id_) {
- connection()->CloseConnection(
- QUIC_INVALID_STREAM_ID,
- "Received push stream id lesser or equal to the"
- " last accepted before",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
- largest_promised_stream_id_ = promised_stream_id;
-
- QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
- if (!stream) {
- // It's quite possible to receive headers after a stream has been reset.
- return;
- }
- stream->OnPromiseHeaderList(promised_stream_id, frame_len, header_list);
-}
-
-void QuicClientSessionBase::HandlePromised(QuicStreamId /* associated_id */,
- QuicStreamId id,
- const SpdyHeaderBlock& headers) {
- // Due to pathalogical packet re-ordering, it is possible that
- // frames for the promised stream have already arrived, and the
- // promised stream could be active or closed.
- if (IsClosedStream(id)) {
- // There was a RST on the data stream already, perhaps
- // QUIC_REFUSED_STREAM?
- DVLOG(1) << "Promise ignored for stream " << id
- << " that is already closed";
- return;
- }
-
- if (push_promise_index_->promised_by_url()->size() >= get_max_promises()) {
- DVLOG(1) << "Too many promises, rejecting promise for stream " << id;
- ResetPromised(id, QUIC_REFUSED_STREAM);
- return;
- }
-
- const string url = SpdyUtils::GetUrlFromHeaderBlock(headers);
- QuicClientPromisedInfo* old_promised = GetPromisedByUrl(url);
- if (old_promised) {
- DVLOG(1) << "Promise for stream " << id << " is duplicate URL " << url
- << " of previous promise for stream " << old_promised->id();
- ResetPromised(id, QUIC_DUPLICATE_PROMISE_URL);
- return;
- }
-
- if (GetPromisedById(id)) {
- // OnPromiseHeadersComplete() would have closed the connection if
- // promised id is a duplicate.
- QUIC_BUG << "Duplicate promise for id " << id;
- return;
- }
-
- QuicClientPromisedInfo* promised = new QuicClientPromisedInfo(this, id, url);
- std::unique_ptr<QuicClientPromisedInfo> promised_owner(promised);
- promised->Init();
- DVLOG(1) << "stream " << id << " emplace url " << url;
- (*push_promise_index_->promised_by_url())[url] = promised;
- promised_by_id_[id] = std::move(promised_owner);
- promised->OnPromiseHeaders(headers);
-}
-
-QuicClientPromisedInfo* QuicClientSessionBase::GetPromisedByUrl(
- const string& url) {
- QuicPromisedByUrlMap::iterator it =
- push_promise_index_->promised_by_url()->find(url);
- if (it != push_promise_index_->promised_by_url()->end()) {
- return it->second;
- }
- return nullptr;
-}
-
-QuicClientPromisedInfo* QuicClientSessionBase::GetPromisedById(
- const QuicStreamId id) {
- QuicPromisedByIdMap::iterator it = promised_by_id_.find(id);
- if (it != promised_by_id_.end()) {
- return it->second.get();
- }
- return nullptr;
-}
-
-QuicSpdyStream* QuicClientSessionBase::GetPromisedStream(
- const QuicStreamId id) {
- if (IsClosedStream(id)) {
- return nullptr;
- }
- StreamMap::iterator it = dynamic_streams().find(id);
- if (it != dynamic_streams().end()) {
- return static_cast<QuicSpdyStream*>(it->second);
- }
- QUIC_BUG << "Open promised stream " << id << " is missing!";
- return nullptr;
-}
-
-void QuicClientSessionBase::DeletePromised(QuicClientPromisedInfo* promised) {
- push_promise_index_->promised_by_url()->erase(promised->url());
- // Since promised_by_id_ contains the unique_ptr, this will destroy
- // promised.
- promised_by_id_.erase(promised->id());
-}
-
-void QuicClientSessionBase::ResetPromised(QuicStreamId id,
- QuicRstStreamErrorCode error_code) {
- SendRstStream(id, error_code, 0);
- if (!IsOpenStream(id)) {
- MaybeIncreaseLargestPeerStreamId(id);
- InsertLocallyClosedStreamsHighestOffset(id, 0);
- }
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_client_session_base.h b/chromium/net/quic/quic_client_session_base.h
deleted file mode 100644
index 58c7d65be58..00000000000
--- a/chromium/net/quic/quic_client_session_base.h
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_CLIENT_SESSION_BASE_H_
-#define NET_QUIC_QUIC_CLIENT_SESSION_BASE_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "net/quic/quic_crypto_client_stream.h"
-#include "net/quic/quic_spdy_session.h"
-
-namespace net {
-
-class QuicClientPromisedInfo;
-class QuicClientPushPromiseIndex;
-class QuicSpdyClientStream;
-
-// For client/http layer code. Lookup promised streams based on
-// matching promised request url. The same map can be shared across
-// multiple sessions, since cross-origin pushes are allowed (subject
-// to authority constraints). Clients should use this map to enforce
-// session affinity for requests corresponding to cross-origin push
-// promised streams.
-using QuicPromisedByUrlMap =
- std::unordered_map<std::string, QuicClientPromisedInfo*>;
-
-// The maximum time a promises stream can be reserved without being
-// claimed by a client request.
-const int64_t kPushPromiseTimeoutSecs = 60;
-
-// Base class for all client-specific QuicSession subclasses.
-class NET_EXPORT_PRIVATE QuicClientSessionBase
- : public QuicSpdySession,
- public QuicCryptoClientStream::ProofHandler {
- public:
- // Caller retains ownership of |promised_by_url|.
- QuicClientSessionBase(QuicConnection* connection,
- QuicClientPushPromiseIndex* push_promise_index,
- const QuicConfig& config);
-
- ~QuicClientSessionBase() override;
-
- // Override base class to set FEC policy before any data is sent by client.
- void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override;
-
- // Called by |headers_stream_| when push promise headers have been
- // received for a stream.
- void OnPromiseHeaders(QuicStreamId stream_id,
- base::StringPiece headers_data) override;
-
- // Called by |headers_stream_| when push promise headers have been
- // completely received.
- void OnPromiseHeadersComplete(QuicStreamId stream_id,
- QuicStreamId promised_stream_id,
- size_t frame_len) override;
-
- // Called by |headers_stream_| when push promise headers have been
- // completely received.
- void OnPromiseHeaderList(QuicStreamId stream_id,
- QuicStreamId promised_stream_id,
- size_t frame_len,
- const QuicHeaderList& header_list) override;
-
- // Called by |QuicSpdyClientStream| on receipt of response headers,
- // needed to detect promised server push streams, as part of
- // client-request to push-stream rendezvous.
- void OnInitialHeadersComplete(QuicStreamId stream_id,
- const SpdyHeaderBlock& response_headers);
-
- // Called by |QuicSpdyClientStream| on receipt of PUSH_PROMISE, does
- // some session level validation and creates the
- // |QuicClientPromisedInfo| inserting into maps by (promised) id and
- // url.
- virtual void HandlePromised(QuicStreamId associated_id,
- QuicStreamId promised_id,
- const SpdyHeaderBlock& headers);
-
- // For cross-origin server push, this should verify the server is
- // authoritative per [RFC2818], Section 3. Roughly, subjectAltName
- // std::list in the certificate should contain a matching DNS name, or IP
- // address. |hostname| is derived from the ":authority" header field of
- // the PUSH_PROMISE frame, port if present there will be dropped.
- virtual bool IsAuthorized(const std::string& hostname) = 0;
-
- // Session retains ownership.
- QuicClientPromisedInfo* GetPromisedByUrl(const std::string& url);
- // Session retains ownership.
- QuicClientPromisedInfo* GetPromisedById(const QuicStreamId id);
-
- //
- QuicSpdyStream* GetPromisedStream(const QuicStreamId id);
-
- // Removes |promised| from the maps by url.
- void ErasePromisedByUrl(QuicClientPromisedInfo* promised);
-
- // Removes |promised| from the maps by url and id and destroys
- // promised.
- virtual void DeletePromised(QuicClientPromisedInfo* promised);
-
- // Sends Rst for the stream, and makes sure that future calls to
- // IsClosedStream(id) return true, which ensures that any subsequent
- // frames related to this stream will be ignored (modulo flow
- // control accounting).
- void ResetPromised(QuicStreamId id, QuicRstStreamErrorCode error_code);
-
- size_t get_max_promises() const {
- return max_open_incoming_streams() * kMaxPromisedStreamsMultiplier;
- }
-
- QuicClientPushPromiseIndex* push_promise_index() {
- return push_promise_index_;
- }
-
- private:
- // For QuicSpdyClientStream to detect that a response corresponds to a
- // promise.
- using QuicPromisedByIdMap =
- std::unordered_map<QuicStreamId, std::unique_ptr<QuicClientPromisedInfo>>;
-
- // As per rfc7540, section 10.5: track promise streams in "reserved
- // (remote)". The primary key is URL from he promise request
- // headers. The promised stream id is a secondary key used to get
- // promise info when the response headers of the promised stream
- // arrive.
- QuicClientPushPromiseIndex* push_promise_index_;
- QuicPromisedByIdMap promised_by_id_;
- QuicStreamId largest_promised_stream_id_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicClientSessionBase);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CLIENT_SESSION_BASE_H_
diff --git a/chromium/net/quic/quic_clock.cc b/chromium/net/quic/quic_clock.cc
deleted file mode 100644
index 6196bbbe6b5..00000000000
--- a/chromium/net/quic/quic_clock.cc
+++ /dev/null
@@ -1,48 +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/quic_clock.h"
-
-#include "base/time/time.h"
-
-namespace net {
-
-QuicClock::QuicClock() {}
-
-QuicClock::~QuicClock() {}
-
-QuicTime QuicClock::ApproximateNow() const {
- // At the moment, Chrome does not have a distinct notion of ApproximateNow().
- // We should consider implementing this using MessageLoop::recent_time_.
- return Now();
-}
-
-QuicTime QuicClock::Now() const {
- return QuicTime(base::TimeTicks::Now());
-}
-
-QuicWallTime QuicClock::WallNow() const {
- return QuicWallTime::FromUNIXMicroseconds(base::Time::Now().ToJavaTime() *
- 1000);
-}
-
-QuicTime QuicClock::ConvertWallTimeToQuicTime(
- const QuicWallTime& walltime) const {
- // ..........................
- // | | |
- // unix epoch |walltime| WallNow()
- // ..........................
- // | | |
- // clock epoch | Now()
- // result
- //
- // result = Now() - (WallNow() - walltime)
- return Now().Subtract(QuicTime::Delta::FromMicroseconds(
- WallNow()
- .Subtract(
- QuicTime::Delta::FromMicroseconds(walltime.ToUNIXMicroseconds()))
- .ToUNIXMicroseconds()));
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_clock.h b/chromium/net/quic/quic_clock.h
deleted file mode 100644
index 23e41946d30..00000000000
--- a/chromium/net/quic/quic_clock.h
+++ /dev/null
@@ -1,44 +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.
-
-#ifndef NET_QUIC_QUIC_CLOCK_H_
-#define NET_QUIC_QUIC_CLOCK_H_
-
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-typedef double WallTime;
-
-// Clock to efficiently retrieve an approximately accurate time from an
-// EpollServer.
-class NET_EXPORT_PRIVATE QuicClock {
- public:
- QuicClock();
- virtual ~QuicClock();
-
- // Returns the approximate current time as a QuicTime object.
- virtual QuicTime ApproximateNow() const;
-
- // Returns the current time as a QuicTime object.
- // Note: this use significant resources please use only if needed.
- virtual QuicTime Now() const;
-
- // WallNow returns the current wall-time - a time that is consistent across
- // different clocks.
- virtual QuicWallTime WallNow() const;
-
- // Converts |walltime| to a QuicTime relative to this clock's epoch.
- virtual QuicTime ConvertWallTimeToQuicTime(
- const QuicWallTime& walltime) const;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(QuicClock);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CLOCK_H_
diff --git a/chromium/net/quic/quic_clock_test.cc b/chromium/net/quic/quic_clock_test.cc
deleted file mode 100644
index b6800611ebe..00000000000
--- a/chromium/net/quic/quic_clock_test.cc
+++ /dev/null
@@ -1,38 +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/quic_clock.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-TEST(QuicClockTest, Now) {
- QuicClock clock;
-
- QuicTime start(base::TimeTicks::Now());
- QuicTime now = clock.ApproximateNow();
- QuicTime end(base::TimeTicks::Now());
-
- EXPECT_LE(start, now);
- EXPECT_LE(now, end);
-}
-
-TEST(QuicClockTest, WallNow) {
- QuicClock clock;
-
- base::Time start = base::Time::Now();
- QuicWallTime now = clock.WallNow();
- base::Time end = base::Time::Now();
-
- // If end > start, then we can check now is between start and end.
- if (end > start) {
- EXPECT_LE(static_cast<uint64_t>(start.ToTimeT()), now.ToUNIXSeconds());
- EXPECT_LE(now.ToUNIXSeconds(), static_cast<uint64_t>(end.ToTimeT()));
- }
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_config.cc b/chromium/net/quic/quic_config.cc
deleted file mode 100644
index 25e567cb0a4..00000000000
--- a/chromium/net/quic/quic_config.cc
+++ /dev/null
@@ -1,744 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_config.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_socket_address_coder.h"
-#include "net/quic/quic_utils.h"
-
-using std::min;
-using std::string;
-
-namespace net {
-
-// Reads the value corresponding to |name_| from |msg| into |out|. If the
-// |name_| is absent in |msg| and |presence| is set to OPTIONAL |out| is set
-// to |default_value|.
-QuicErrorCode ReadUint32(const CryptoHandshakeMessage& msg,
- QuicTag tag,
- QuicConfigPresence presence,
- uint32_t default_value,
- uint32_t* out,
- string* error_details) {
- DCHECK(error_details != nullptr);
- QuicErrorCode error = msg.GetUint32(tag, out);
- switch (error) {
- case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
- if (presence == PRESENCE_REQUIRED) {
- *error_details = "Missing " + QuicUtils::TagToString(tag);
- break;
- }
- error = QUIC_NO_ERROR;
- *out = default_value;
- break;
- case QUIC_NO_ERROR:
- break;
- default:
- *error_details = "Bad " + QuicUtils::TagToString(tag);
- break;
- }
- return error;
-}
-
-QuicConfigValue::QuicConfigValue(QuicTag tag, QuicConfigPresence presence)
- : tag_(tag), presence_(presence) {}
-QuicConfigValue::~QuicConfigValue() {}
-
-QuicNegotiableValue::QuicNegotiableValue(QuicTag tag,
- QuicConfigPresence presence)
- : QuicConfigValue(tag, presence), negotiated_(false) {}
-QuicNegotiableValue::~QuicNegotiableValue() {}
-
-QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag,
- QuicConfigPresence presence)
- : QuicNegotiableValue(tag, presence),
- max_value_(0),
- default_value_(0),
- negotiated_value_(0) {}
-QuicNegotiableUint32::~QuicNegotiableUint32() {}
-
-void QuicNegotiableUint32::set(uint32_t max, uint32_t default_value) {
- DCHECK_LE(default_value, max);
- max_value_ = max;
- default_value_ = default_value;
-}
-
-uint32_t QuicNegotiableUint32::GetUint32() const {
- if (negotiated()) {
- return negotiated_value_;
- }
- return default_value_;
-}
-
-void QuicNegotiableUint32::ToHandshakeMessage(
- CryptoHandshakeMessage* out) const {
- if (negotiated()) {
- out->SetValue(tag_, negotiated_value_);
- } else {
- out->SetValue(tag_, max_value_);
- }
-}
-
-QuicErrorCode QuicNegotiableUint32::ProcessPeerHello(
- const CryptoHandshakeMessage& peer_hello,
- HelloType hello_type,
- string* error_details) {
- DCHECK(!negotiated());
- DCHECK(error_details != nullptr);
- uint32_t value;
- QuicErrorCode error = ReadUint32(peer_hello, tag_, presence_, default_value_,
- &value, error_details);
- if (error != QUIC_NO_ERROR) {
- return error;
- }
- if (hello_type == SERVER && value > max_value_) {
- *error_details =
- "Invalid value received for " + QuicUtils::TagToString(tag_);
- return QUIC_INVALID_NEGOTIATED_VALUE;
- }
-
- set_negotiated(true);
- negotiated_value_ = min(value, max_value_);
- return QUIC_NO_ERROR;
-}
-
-QuicNegotiableTag::QuicNegotiableTag(QuicTag tag, QuicConfigPresence presence)
- : QuicNegotiableValue(tag, presence),
- negotiated_tag_(0),
- default_value_(0) {}
-
-QuicNegotiableTag::~QuicNegotiableTag() {}
-
-void QuicNegotiableTag::set(const QuicTagVector& possible,
- QuicTag default_value) {
- DCHECK(ContainsQuicTag(possible, default_value));
- possible_values_ = possible;
- default_value_ = default_value;
-}
-
-void QuicNegotiableTag::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
- if (negotiated()) {
- // Because of the way we serialize and parse handshake messages we can
- // serialize this as value and still parse it as a vector.
- out->SetValue(tag_, negotiated_tag_);
- } else {
- out->SetVector(tag_, possible_values_);
- }
-}
-
-QuicErrorCode QuicNegotiableTag::ReadVector(const CryptoHandshakeMessage& msg,
- const QuicTag** out,
- size_t* out_length,
- string* error_details) const {
- DCHECK(error_details != nullptr);
- QuicErrorCode error = msg.GetTaglist(tag_, out, out_length);
- switch (error) {
- case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
- if (presence_ == PRESENCE_REQUIRED) {
- *error_details = "Missing " + QuicUtils::TagToString(tag_);
- break;
- }
- error = QUIC_NO_ERROR;
- *out_length = 1;
- *out = &default_value_;
-
- case QUIC_NO_ERROR:
- break;
- default:
- *error_details = "Bad " + QuicUtils::TagToString(tag_);
- break;
- }
- return error;
-}
-
-QuicErrorCode QuicNegotiableTag::ProcessPeerHello(
- const CryptoHandshakeMessage& peer_hello,
- HelloType hello_type,
- string* error_details) {
- DCHECK(!negotiated());
- DCHECK(error_details != nullptr);
- const QuicTag* received_tags;
- size_t received_tags_length;
- QuicErrorCode error = ReadVector(peer_hello, &received_tags,
- &received_tags_length, error_details);
- if (error != QUIC_NO_ERROR) {
- return error;
- }
-
- if (hello_type == SERVER) {
- if (received_tags_length != 1 ||
- !ContainsQuicTag(possible_values_, *received_tags)) {
- *error_details = "Invalid " + QuicUtils::TagToString(tag_);
- return QUIC_INVALID_NEGOTIATED_VALUE;
- }
- negotiated_tag_ = *received_tags;
- } else {
- QuicTag negotiated_tag;
- if (!QuicUtils::FindMutualTag(
- possible_values_, received_tags, received_tags_length,
- QuicUtils::LOCAL_PRIORITY, &negotiated_tag, nullptr)) {
- *error_details = "Unsupported " + QuicUtils::TagToString(tag_);
- return QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP;
- }
- negotiated_tag_ = negotiated_tag;
- }
-
- set_negotiated(true);
- return QUIC_NO_ERROR;
-}
-
-QuicFixedUint32::QuicFixedUint32(QuicTag tag, QuicConfigPresence presence)
- : QuicConfigValue(tag, presence),
- has_send_value_(false),
- has_receive_value_(false) {}
-QuicFixedUint32::~QuicFixedUint32() {}
-
-bool QuicFixedUint32::HasSendValue() const {
- return has_send_value_;
-}
-
-uint32_t QuicFixedUint32::GetSendValue() const {
- QUIC_BUG_IF(!has_send_value_) << "No send value to get for tag:"
- << QuicUtils::TagToString(tag_);
- return send_value_;
-}
-
-void QuicFixedUint32::SetSendValue(uint32_t value) {
- has_send_value_ = true;
- send_value_ = value;
-}
-
-bool QuicFixedUint32::HasReceivedValue() const {
- return has_receive_value_;
-}
-
-uint32_t QuicFixedUint32::GetReceivedValue() const {
- QUIC_BUG_IF(!has_receive_value_) << "No receive value to get for tag:"
- << QuicUtils::TagToString(tag_);
- return receive_value_;
-}
-
-void QuicFixedUint32::SetReceivedValue(uint32_t value) {
- has_receive_value_ = true;
- receive_value_ = value;
-}
-
-void QuicFixedUint32::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
- if (has_send_value_) {
- out->SetValue(tag_, send_value_);
- }
-}
-
-QuicErrorCode QuicFixedUint32::ProcessPeerHello(
- const CryptoHandshakeMessage& peer_hello,
- HelloType hello_type,
- string* error_details) {
- DCHECK(error_details != nullptr);
- QuicErrorCode error = peer_hello.GetUint32(tag_, &receive_value_);
- switch (error) {
- case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
- if (presence_ == PRESENCE_OPTIONAL) {
- return QUIC_NO_ERROR;
- }
- *error_details = "Missing " + QuicUtils::TagToString(tag_);
- break;
- case QUIC_NO_ERROR:
- has_receive_value_ = true;
- break;
- default:
- *error_details = "Bad " + QuicUtils::TagToString(tag_);
- break;
- }
- return error;
-}
-
-QuicFixedTagVector::QuicFixedTagVector(QuicTag name,
- QuicConfigPresence presence)
- : QuicConfigValue(name, presence),
- has_send_values_(false),
- has_receive_values_(false) {}
-
-QuicFixedTagVector::QuicFixedTagVector(const QuicFixedTagVector& other) =
- default;
-
-QuicFixedTagVector::~QuicFixedTagVector() {}
-
-bool QuicFixedTagVector::HasSendValues() const {
- return has_send_values_;
-}
-
-QuicTagVector QuicFixedTagVector::GetSendValues() const {
- QUIC_BUG_IF(!has_send_values_) << "No send values to get for tag:"
- << QuicUtils::TagToString(tag_);
- return send_values_;
-}
-
-void QuicFixedTagVector::SetSendValues(const QuicTagVector& values) {
- has_send_values_ = true;
- send_values_ = values;
-}
-
-bool QuicFixedTagVector::HasReceivedValues() const {
- return has_receive_values_;
-}
-
-QuicTagVector QuicFixedTagVector::GetReceivedValues() const {
- QUIC_BUG_IF(!has_receive_values_) << "No receive value to get for tag:"
- << QuicUtils::TagToString(tag_);
- return receive_values_;
-}
-
-void QuicFixedTagVector::SetReceivedValues(const QuicTagVector& values) {
- has_receive_values_ = true;
- receive_values_ = values;
-}
-
-void QuicFixedTagVector::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
- if (has_send_values_) {
- out->SetVector(tag_, send_values_);
- }
-}
-
-QuicErrorCode QuicFixedTagVector::ProcessPeerHello(
- const CryptoHandshakeMessage& peer_hello,
- HelloType hello_type,
- string* error_details) {
- DCHECK(error_details != nullptr);
- const QuicTag* received_tags;
- size_t received_tags_length;
- QuicErrorCode error =
- peer_hello.GetTaglist(tag_, &received_tags, &received_tags_length);
- switch (error) {
- case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
- if (presence_ == PRESENCE_OPTIONAL) {
- return QUIC_NO_ERROR;
- }
- *error_details = "Missing " + QuicUtils::TagToString(tag_);
- break;
- case QUIC_NO_ERROR:
- DVLOG(1) << "Received Connection Option tags from receiver.";
- has_receive_values_ = true;
- for (size_t i = 0; i < received_tags_length; ++i) {
- receive_values_.push_back(received_tags[i]);
- }
- break;
- default:
- *error_details = "Bad " + QuicUtils::TagToString(tag_);
- break;
- }
- return error;
-}
-
-QuicFixedIPEndPoint::QuicFixedIPEndPoint(QuicTag tag,
- QuicConfigPresence presence)
- : QuicConfigValue(tag, presence),
- has_send_value_(false),
- has_receive_value_(false) {}
-
-QuicFixedIPEndPoint::~QuicFixedIPEndPoint() {}
-
-bool QuicFixedIPEndPoint::HasSendValue() const {
- return has_send_value_;
-}
-
-const IPEndPoint& QuicFixedIPEndPoint::GetSendValue() const {
- QUIC_BUG_IF(!has_send_value_) << "No send value to get for tag:"
- << QuicUtils::TagToString(tag_);
- return send_value_;
-}
-
-void QuicFixedIPEndPoint::SetSendValue(const IPEndPoint& value) {
- has_send_value_ = true;
- send_value_ = value;
-}
-
-bool QuicFixedIPEndPoint::HasReceivedValue() const {
- return has_receive_value_;
-}
-
-const IPEndPoint& QuicFixedIPEndPoint::GetReceivedValue() const {
- QUIC_BUG_IF(!has_receive_value_) << "No receive value to get for tag:"
- << QuicUtils::TagToString(tag_);
- return receive_value_;
-}
-
-void QuicFixedIPEndPoint::SetReceivedValue(const IPEndPoint& value) {
- has_receive_value_ = true;
- receive_value_ = value;
-}
-
-void QuicFixedIPEndPoint::ToHandshakeMessage(
- CryptoHandshakeMessage* out) const {
- if (has_send_value_) {
- QuicSocketAddressCoder address_coder(send_value_);
- out->SetStringPiece(tag_, address_coder.Encode());
- }
-}
-
-QuicErrorCode QuicFixedIPEndPoint::ProcessPeerHello(
- const CryptoHandshakeMessage& peer_hello,
- HelloType hello_type,
- string* error_details) {
- base::StringPiece address;
- if (!peer_hello.GetStringPiece(tag_, &address)) {
- if (presence_ == PRESENCE_REQUIRED) {
- *error_details = "Missing " + QuicUtils::TagToString(tag_);
- return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
- }
- } else {
- QuicSocketAddressCoder address_coder;
- if (address_coder.Decode(address.data(), address.length())) {
- SetReceivedValue(IPEndPoint(address_coder.ip(), address_coder.port()));
- }
- }
- return QUIC_NO_ERROR;
-}
-
-QuicConfig::QuicConfig()
- : max_time_before_crypto_handshake_(QuicTime::Delta::Zero()),
- max_idle_time_before_crypto_handshake_(QuicTime::Delta::Zero()),
- max_undecryptable_packets_(0),
- connection_options_(kCOPT, PRESENCE_OPTIONAL),
- idle_connection_state_lifetime_seconds_(kICSL, PRESENCE_REQUIRED),
- silent_close_(kSCLS, PRESENCE_OPTIONAL),
- max_streams_per_connection_(kMSPC, PRESENCE_OPTIONAL),
- max_incoming_dynamic_streams_(kMIDS, PRESENCE_OPTIONAL),
- bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL),
- initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL),
- initial_stream_flow_control_window_bytes_(kSFCW, PRESENCE_OPTIONAL),
- initial_session_flow_control_window_bytes_(kCFCW, PRESENCE_OPTIONAL),
- socket_receive_buffer_(kSRBF, PRESENCE_OPTIONAL),
- multipath_enabled_(kMPTH, PRESENCE_OPTIONAL),
- connection_migration_disabled_(kNCMR, PRESENCE_OPTIONAL),
- alternate_server_address_(kASAD, PRESENCE_OPTIONAL) {
- SetDefaults();
-}
-
-QuicConfig::QuicConfig(const QuicConfig& other) = default;
-
-QuicConfig::~QuicConfig() {}
-
-bool QuicConfig::SetInitialReceivedConnectionOptions(
- const QuicTagVector& tags) {
- if (HasReceivedConnectionOptions()) {
- // If we have already received connection options (via handshake or due to a
- // previous call), don't re-initialize.
- return false;
- }
- connection_options_.SetReceivedValues(tags);
- return true;
-}
-
-void QuicConfig::SetConnectionOptionsToSend(
- const QuicTagVector& connection_options) {
- connection_options_.SetSendValues(connection_options);
-}
-
-bool QuicConfig::HasReceivedConnectionOptions() const {
- return connection_options_.HasReceivedValues();
-}
-
-QuicTagVector QuicConfig::ReceivedConnectionOptions() const {
- return connection_options_.GetReceivedValues();
-}
-
-bool QuicConfig::HasSendConnectionOptions() const {
- return connection_options_.HasSendValues();
-}
-
-QuicTagVector QuicConfig::SendConnectionOptions() const {
- return connection_options_.GetSendValues();
-}
-
-bool QuicConfig::HasClientSentConnectionOption(QuicTag tag,
- Perspective perspective) const {
- if (perspective == Perspective::IS_SERVER) {
- if (HasReceivedConnectionOptions() &&
- ContainsQuicTag(ReceivedConnectionOptions(), tag)) {
- return true;
- }
- } else if (HasSendConnectionOptions() &&
- ContainsQuicTag(SendConnectionOptions(), tag)) {
- return true;
- }
- return false;
-}
-
-void QuicConfig::SetIdleConnectionStateLifetime(
- QuicTime::Delta max_idle_connection_state_lifetime,
- QuicTime::Delta default_idle_conection_state_lifetime) {
- idle_connection_state_lifetime_seconds_.set(
- static_cast<uint32_t>(max_idle_connection_state_lifetime.ToSeconds()),
- static_cast<uint32_t>(default_idle_conection_state_lifetime.ToSeconds()));
-}
-
-QuicTime::Delta QuicConfig::IdleConnectionStateLifetime() const {
- return QuicTime::Delta::FromSeconds(
- idle_connection_state_lifetime_seconds_.GetUint32());
-}
-
-// TODO(ianswett) Use this for silent close on mobile, or delete.
-void QuicConfig::SetSilentClose(bool silent_close) {
- silent_close_.set(silent_close ? 1 : 0, silent_close ? 1 : 0);
-}
-
-bool QuicConfig::SilentClose() const {
- return silent_close_.GetUint32() > 0;
-}
-
-void QuicConfig::SetMaxStreamsPerConnection(size_t max_streams,
- size_t default_streams) {
- max_streams_per_connection_.set(max_streams, default_streams);
-}
-
-uint32_t QuicConfig::MaxStreamsPerConnection() const {
- return max_streams_per_connection_.GetUint32();
-}
-
-void QuicConfig::SetMaxIncomingDynamicStreamsToSend(
- uint32_t max_incoming_dynamic_streams) {
- max_incoming_dynamic_streams_.SetSendValue(max_incoming_dynamic_streams);
-}
-
-uint32_t QuicConfig::GetMaxIncomingDynamicStreamsToSend() {
- return max_incoming_dynamic_streams_.GetSendValue();
-}
-
-bool QuicConfig::HasReceivedMaxIncomingDynamicStreams() {
- return max_incoming_dynamic_streams_.HasReceivedValue();
-}
-
-uint32_t QuicConfig::ReceivedMaxIncomingDynamicStreams() {
- return max_incoming_dynamic_streams_.GetReceivedValue();
-}
-
-bool QuicConfig::HasSetBytesForConnectionIdToSend() const {
- return bytes_for_connection_id_.HasSendValue();
-}
-
-void QuicConfig::SetBytesForConnectionIdToSend(uint32_t bytes) {
- bytes_for_connection_id_.SetSendValue(bytes);
-}
-
-bool QuicConfig::HasReceivedBytesForConnectionId() const {
- return bytes_for_connection_id_.HasReceivedValue();
-}
-
-uint32_t QuicConfig::ReceivedBytesForConnectionId() const {
- return bytes_for_connection_id_.GetReceivedValue();
-}
-
-void QuicConfig::SetInitialRoundTripTimeUsToSend(uint32_t rtt) {
- initial_round_trip_time_us_.SetSendValue(rtt);
-}
-
-bool QuicConfig::HasReceivedInitialRoundTripTimeUs() const {
- return initial_round_trip_time_us_.HasReceivedValue();
-}
-
-uint32_t QuicConfig::ReceivedInitialRoundTripTimeUs() const {
- return initial_round_trip_time_us_.GetReceivedValue();
-}
-
-bool QuicConfig::HasInitialRoundTripTimeUsToSend() const {
- return initial_round_trip_time_us_.HasSendValue();
-}
-
-uint32_t QuicConfig::GetInitialRoundTripTimeUsToSend() const {
- return initial_round_trip_time_us_.GetSendValue();
-}
-
-void QuicConfig::SetInitialStreamFlowControlWindowToSend(
- uint32_t window_bytes) {
- if (window_bytes < kMinimumFlowControlSendWindow) {
- QUIC_BUG << "Initial stream flow control receive window (" << window_bytes
- << ") cannot be set lower than default ("
- << kMinimumFlowControlSendWindow << ").";
- window_bytes = kMinimumFlowControlSendWindow;
- }
- initial_stream_flow_control_window_bytes_.SetSendValue(window_bytes);
-}
-
-uint32_t QuicConfig::GetInitialStreamFlowControlWindowToSend() const {
- return initial_stream_flow_control_window_bytes_.GetSendValue();
-}
-
-bool QuicConfig::HasReceivedInitialStreamFlowControlWindowBytes() const {
- return initial_stream_flow_control_window_bytes_.HasReceivedValue();
-}
-
-uint32_t QuicConfig::ReceivedInitialStreamFlowControlWindowBytes() const {
- return initial_stream_flow_control_window_bytes_.GetReceivedValue();
-}
-
-void QuicConfig::SetInitialSessionFlowControlWindowToSend(
- uint32_t window_bytes) {
- if (window_bytes < kMinimumFlowControlSendWindow) {
- QUIC_BUG << "Initial session flow control receive window (" << window_bytes
- << ") cannot be set lower than default ("
- << kMinimumFlowControlSendWindow << ").";
- window_bytes = kMinimumFlowControlSendWindow;
- }
- initial_session_flow_control_window_bytes_.SetSendValue(window_bytes);
-}
-
-uint32_t QuicConfig::GetInitialSessionFlowControlWindowToSend() const {
- return initial_session_flow_control_window_bytes_.GetSendValue();
-}
-
-bool QuicConfig::HasReceivedInitialSessionFlowControlWindowBytes() const {
- return initial_session_flow_control_window_bytes_.HasReceivedValue();
-}
-
-uint32_t QuicConfig::ReceivedInitialSessionFlowControlWindowBytes() const {
- return initial_session_flow_control_window_bytes_.GetReceivedValue();
-}
-
-void QuicConfig::SetSocketReceiveBufferToSend(uint32_t tcp_receive_window) {
- socket_receive_buffer_.SetSendValue(tcp_receive_window);
-}
-
-bool QuicConfig::HasReceivedSocketReceiveBuffer() const {
- return socket_receive_buffer_.HasReceivedValue();
-}
-
-uint32_t QuicConfig::ReceivedSocketReceiveBuffer() const {
- return socket_receive_buffer_.GetReceivedValue();
-}
-
-void QuicConfig::SetMultipathEnabled(bool multipath_enabled) {
- uint32_t value = multipath_enabled ? 1 : 0;
- multipath_enabled_.set(value, value);
-}
-
-bool QuicConfig::MultipathEnabled() const {
- return multipath_enabled_.GetUint32() > 0;
-}
-
-void QuicConfig::SetDisableConnectionMigration() {
- connection_migration_disabled_.SetSendValue(1);
-}
-
-bool QuicConfig::DisableConnectionMigration() const {
- return connection_migration_disabled_.HasReceivedValue();
-}
-
-void QuicConfig::SetAlternateServerAddressToSend(
- const IPEndPoint& alternate_server_address) {
- alternate_server_address_.SetSendValue(alternate_server_address);
-}
-
-bool QuicConfig::HasReceivedAlternateServerAddress() const {
- return alternate_server_address_.HasReceivedValue();
-}
-
-const IPEndPoint& QuicConfig::ReceivedAlternateServerAddress() const {
- return alternate_server_address_.GetReceivedValue();
-}
-
-bool QuicConfig::negotiated() const {
- // TODO(ianswett): Add the negotiated parameters once and iterate over all
- // of them in negotiated, ToHandshakeMessage, ProcessClientHello, and
- // ProcessServerHello.
- return idle_connection_state_lifetime_seconds_.negotiated() &&
- max_streams_per_connection_.negotiated();
-}
-
-void QuicConfig::SetDefaults() {
- idle_connection_state_lifetime_seconds_.set(kMaximumIdleTimeoutSecs,
- kDefaultIdleTimeoutSecs);
- silent_close_.set(1, 0);
- SetMaxStreamsPerConnection(kDefaultMaxStreamsPerConnection,
- kDefaultMaxStreamsPerConnection);
- SetMaxIncomingDynamicStreamsToSend(kDefaultMaxStreamsPerConnection);
- max_time_before_crypto_handshake_ =
- QuicTime::Delta::FromSeconds(kMaxTimeForCryptoHandshakeSecs);
- max_idle_time_before_crypto_handshake_ =
- QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs);
- max_undecryptable_packets_ = kDefaultMaxUndecryptablePackets;
-
- SetInitialStreamFlowControlWindowToSend(kMinimumFlowControlSendWindow);
- SetInitialSessionFlowControlWindowToSend(kMinimumFlowControlSendWindow);
-}
-
-void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
- idle_connection_state_lifetime_seconds_.ToHandshakeMessage(out);
- silent_close_.ToHandshakeMessage(out);
- max_streams_per_connection_.ToHandshakeMessage(out);
- max_incoming_dynamic_streams_.ToHandshakeMessage(out);
- bytes_for_connection_id_.ToHandshakeMessage(out);
- initial_round_trip_time_us_.ToHandshakeMessage(out);
- initial_stream_flow_control_window_bytes_.ToHandshakeMessage(out);
- initial_session_flow_control_window_bytes_.ToHandshakeMessage(out);
- socket_receive_buffer_.ToHandshakeMessage(out);
- connection_migration_disabled_.ToHandshakeMessage(out);
- connection_options_.ToHandshakeMessage(out);
- alternate_server_address_.ToHandshakeMessage(out);
-}
-
-QuicErrorCode QuicConfig::ProcessPeerHello(
- const CryptoHandshakeMessage& peer_hello,
- HelloType hello_type,
- string* error_details) {
- DCHECK(error_details != nullptr);
-
- QuicErrorCode error = QUIC_NO_ERROR;
- if (error == QUIC_NO_ERROR) {
- error = idle_connection_state_lifetime_seconds_.ProcessPeerHello(
- peer_hello, hello_type, error_details);
- }
- if (error == QUIC_NO_ERROR) {
- error =
- silent_close_.ProcessPeerHello(peer_hello, hello_type, error_details);
- }
- if (error == QUIC_NO_ERROR) {
- error = max_streams_per_connection_.ProcessPeerHello(peer_hello, hello_type,
- error_details);
- }
- if (error == QUIC_NO_ERROR) {
- error = max_incoming_dynamic_streams_.ProcessPeerHello(
- peer_hello, hello_type, error_details);
- }
- if (error == QUIC_NO_ERROR) {
- error = bytes_for_connection_id_.ProcessPeerHello(peer_hello, hello_type,
- error_details);
- }
- if (error == QUIC_NO_ERROR) {
- error = initial_round_trip_time_us_.ProcessPeerHello(peer_hello, hello_type,
- error_details);
- }
- if (error == QUIC_NO_ERROR) {
- error = initial_stream_flow_control_window_bytes_.ProcessPeerHello(
- peer_hello, hello_type, error_details);
- }
- if (error == QUIC_NO_ERROR) {
- error = initial_session_flow_control_window_bytes_.ProcessPeerHello(
- peer_hello, hello_type, error_details);
- }
- if (error == QUIC_NO_ERROR) {
- error = socket_receive_buffer_.ProcessPeerHello(peer_hello, hello_type,
- error_details);
- }
- if (error == QUIC_NO_ERROR) {
- error = connection_migration_disabled_.ProcessPeerHello(
- peer_hello, hello_type, error_details);
- }
- if (error == QUIC_NO_ERROR) {
- error = connection_options_.ProcessPeerHello(peer_hello, hello_type,
- error_details);
- }
- if (error == QUIC_NO_ERROR) {
- error = alternate_server_address_.ProcessPeerHello(peer_hello, hello_type,
- error_details);
- }
- return error;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_config.h b/chromium/net/quic/quic_config.h
deleted file mode 100644
index ddafce4c87a..00000000000
--- a/chromium/net/quic/quic_config.h
+++ /dev/null
@@ -1,452 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_CONFIG_H_
-#define NET_QUIC_QUIC_CONFIG_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-namespace test {
-class QuicConfigPeer;
-} // namespace test
-
-class CryptoHandshakeMessage;
-
-// Describes whether or not a given QuicTag is required or optional in the
-// handshake message.
-enum QuicConfigPresence {
- // This negotiable value can be absent from the handshake message. Default
- // value is selected as the negotiated value in such a case.
- PRESENCE_OPTIONAL,
- // This negotiable value is required in the handshake message otherwise the
- // Process*Hello function returns an error.
- PRESENCE_REQUIRED,
-};
-
-// Whether the CryptoHandshakeMessage is from the client or server.
-enum HelloType {
- CLIENT,
- SERVER,
-};
-
-// An abstract base class that stores a value that can be sent in CHLO/SHLO
-// message. These values can be OPTIONAL or REQUIRED, depending on |presence_|.
-class NET_EXPORT_PRIVATE QuicConfigValue {
- public:
- QuicConfigValue(QuicTag tag, QuicConfigPresence presence);
- virtual ~QuicConfigValue();
-
- // Serialises tag name and value(s) to |out|.
- virtual void ToHandshakeMessage(CryptoHandshakeMessage* out) const = 0;
-
- // Selects a mutually acceptable value from those offered in |peer_hello|
- // and those defined in the subclass.
- virtual QuicErrorCode ProcessPeerHello(
- const CryptoHandshakeMessage& peer_hello,
- HelloType hello_type,
- std::string* error_details) = 0;
-
- protected:
- const QuicTag tag_;
- const QuicConfigPresence presence_;
-};
-
-class NET_EXPORT_PRIVATE QuicNegotiableValue : public QuicConfigValue {
- public:
- QuicNegotiableValue(QuicTag tag, QuicConfigPresence presence);
- ~QuicNegotiableValue() override;
-
- bool negotiated() const { return negotiated_; }
-
- protected:
- void set_negotiated(bool negotiated) { negotiated_ = negotiated; }
-
- private:
- bool negotiated_;
-};
-
-class NET_EXPORT_PRIVATE QuicNegotiableUint32 : public QuicNegotiableValue {
- // TODO(fayang): some negotiated values use uint32 as bool (e.g., silent
- // close). Consider adding a QuicNegotiableBool type.
- public:
- // Default and max values default to 0.
- QuicNegotiableUint32(QuicTag name, QuicConfigPresence presence);
- ~QuicNegotiableUint32() override;
-
- // Sets the maximum possible value that can be achieved after negotiation and
- // also the default values to be assumed if PRESENCE_OPTIONAL and the *HLO msg
- // doesn't contain a value corresponding to |name_|. |max| is serialised via
- // ToHandshakeMessage call if |negotiated_| is false.
- void set(uint32_t max, uint32_t default_value);
-
- // Returns the value negotiated if |negotiated_| is true, otherwise returns
- // default_value_ (used to set default values before negotiation finishes).
- uint32_t GetUint32() const;
-
- // Serialises |name_| and value to |out|. If |negotiated_| is true then
- // |negotiated_value_| is serialised, otherwise |max_value_| is serialised.
- void ToHandshakeMessage(CryptoHandshakeMessage* out) const override;
-
- // Sets |negotiated_value_| to the minimum of |max_value_| and the
- // corresponding value from |peer_hello|. If the corresponding value is
- // missing and PRESENCE_OPTIONAL then |negotiated_value_| is set to
- // |default_value_|.
- QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello,
- HelloType hello_type,
- std::string* error_details) override;
-
- private:
- uint32_t max_value_;
- uint32_t default_value_;
- uint32_t negotiated_value_;
-};
-
-class NET_EXPORT_PRIVATE QuicNegotiableTag : public QuicNegotiableValue {
- public:
- QuicNegotiableTag(QuicTag name, QuicConfigPresence presence);
- ~QuicNegotiableTag() override;
-
- // Sets the possible values that |negotiated_tag_| can take after negotiation
- // and the default value that |negotiated_tag_| takes if OPTIONAL and *HLO
- // msg doesn't contain tag |name_|.
- void set(const QuicTagVector& possible_values, QuicTag default_value);
-
- // Serialises |name_| and vector (either possible or negotiated) to |out|. If
- // |negotiated_| is true then |negotiated_tag_| is serialised, otherwise
- // |possible_values_| is serialised.
- void ToHandshakeMessage(CryptoHandshakeMessage* out) const override;
-
- // Selects the tag common to both tags in |client_hello| for |name_| and
- // |possible_values_| with preference to tag in |possible_values_|. The
- // selected tag is set as |negotiated_tag_|.
- QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello,
- HelloType hello_type,
- std::string* error_details) override;
-
- private:
- // Reads the vector corresponding to |name_| from |msg| into |out|. If the
- // |name_| is absent in |msg| and |presence_| is set to OPTIONAL |out| is set
- // to |possible_values_|.
- QuicErrorCode ReadVector(const CryptoHandshakeMessage& msg,
- const QuicTag** out,
- size_t* out_length,
- std::string* error_details) const;
-
- QuicTag negotiated_tag_;
- QuicTagVector possible_values_;
- QuicTag default_value_;
-};
-
-// Stores uint32_t from CHLO or SHLO messages that are not negotiated.
-class NET_EXPORT_PRIVATE QuicFixedUint32 : public QuicConfigValue {
- public:
- QuicFixedUint32(QuicTag name, QuicConfigPresence presence);
- ~QuicFixedUint32() override;
-
- bool HasSendValue() const;
-
- uint32_t GetSendValue() const;
-
- void SetSendValue(uint32_t value);
-
- bool HasReceivedValue() const;
-
- uint32_t GetReceivedValue() const;
-
- void SetReceivedValue(uint32_t value);
-
- // If has_send_value is true, serialises |tag_| and |send_value_| to |out|.
- void ToHandshakeMessage(CryptoHandshakeMessage* out) const override;
-
- // Sets |value_| to the corresponding value from |peer_hello_| if it exists.
- QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello,
- HelloType hello_type,
- std::string* error_details) override;
-
- private:
- uint32_t send_value_;
- bool has_send_value_;
- uint32_t receive_value_;
- bool has_receive_value_;
-};
-
-// Stores tag from CHLO or SHLO messages that are not negotiated.
-class NET_EXPORT_PRIVATE QuicFixedTagVector : public QuicConfigValue {
- public:
- QuicFixedTagVector(QuicTag name, QuicConfigPresence presence);
- QuicFixedTagVector(const QuicFixedTagVector& other);
- ~QuicFixedTagVector() override;
-
- bool HasSendValues() const;
-
- QuicTagVector GetSendValues() const;
-
- void SetSendValues(const QuicTagVector& values);
-
- bool HasReceivedValues() const;
-
- QuicTagVector GetReceivedValues() const;
-
- void SetReceivedValues(const QuicTagVector& values);
-
- // If has_send_value is true, serialises |tag_vector_| and |send_value_| to
- // |out|.
- void ToHandshakeMessage(CryptoHandshakeMessage* out) const override;
-
- // Sets |receive_values_| to the corresponding value from |client_hello_| if
- // it exists.
- QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello,
- HelloType hello_type,
- std::string* error_details) override;
-
- private:
- QuicTagVector send_values_;
- bool has_send_values_;
- QuicTagVector receive_values_;
- bool has_receive_values_;
-};
-
-// Stores IPEndPoint from CHLO or SHLO messages that are not negotiated.
-class QuicFixedIPEndPoint : public QuicConfigValue {
- public:
- QuicFixedIPEndPoint(QuicTag tag, QuicConfigPresence presence);
- ~QuicFixedIPEndPoint() override;
-
- bool HasSendValue() const;
-
- const IPEndPoint& GetSendValue() const;
-
- void SetSendValue(const IPEndPoint& value);
-
- bool HasReceivedValue() const;
-
- const IPEndPoint& GetReceivedValue() const;
-
- void SetReceivedValue(const IPEndPoint& value);
-
- void ToHandshakeMessage(CryptoHandshakeMessage* out) const override;
-
- QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello,
- HelloType hello_type,
- std::string* error_details) override;
-
- private:
- IPEndPoint send_value_;
- bool has_send_value_;
- IPEndPoint receive_value_;
- bool has_receive_value_;
-};
-
-// QuicConfig contains non-crypto configuration options that are negotiated in
-// the crypto handshake.
-class NET_EXPORT_PRIVATE QuicConfig {
- public:
- QuicConfig();
- QuicConfig(const QuicConfig& other);
- ~QuicConfig();
-
- void SetConnectionOptionsToSend(const QuicTagVector& connection_options);
-
- bool HasReceivedConnectionOptions() const;
-
- // Sets initial received connection options. All received connection options
- // will be initialized with these fields. Initial received options may only be
- // set once per config, prior to the setting of any other options. If options
- // have already been set (either by previous calls or via handshake), this
- // function does nothing and returns false.
- bool SetInitialReceivedConnectionOptions(const QuicTagVector& tags);
-
- QuicTagVector ReceivedConnectionOptions() const;
-
- bool HasSendConnectionOptions() const;
-
- QuicTagVector SendConnectionOptions() const;
-
- // Returns true if the client is sending or the server has received a
- // connection option.
- bool HasClientSentConnectionOption(QuicTag tag,
- Perspective perspective) const;
-
- void SetIdleConnectionStateLifetime(
- QuicTime::Delta max_idle_connection_state_lifetime,
- QuicTime::Delta default_idle_conection_state_lifetime);
-
- QuicTime::Delta IdleConnectionStateLifetime() const;
-
- void SetSilentClose(bool silent_close);
-
- bool SilentClose() const;
-
- void SetMaxStreamsPerConnection(size_t max_streams, size_t default_streams);
-
- uint32_t MaxStreamsPerConnection() const;
-
- void SetMaxIncomingDynamicStreamsToSend(
- uint32_t max_incoming_dynamic_streams);
-
- uint32_t GetMaxIncomingDynamicStreamsToSend();
-
- bool HasReceivedMaxIncomingDynamicStreams();
-
- uint32_t ReceivedMaxIncomingDynamicStreams();
-
- void set_max_time_before_crypto_handshake(
- QuicTime::Delta max_time_before_crypto_handshake) {
- max_time_before_crypto_handshake_ = max_time_before_crypto_handshake;
- }
-
- QuicTime::Delta max_time_before_crypto_handshake() const {
- return max_time_before_crypto_handshake_;
- }
-
- void set_max_idle_time_before_crypto_handshake(
- QuicTime::Delta max_idle_time_before_crypto_handshake) {
- max_idle_time_before_crypto_handshake_ =
- max_idle_time_before_crypto_handshake;
- }
-
- QuicTime::Delta max_idle_time_before_crypto_handshake() const {
- return max_idle_time_before_crypto_handshake_;
- }
-
- void set_max_undecryptable_packets(size_t max_undecryptable_packets) {
- max_undecryptable_packets_ = max_undecryptable_packets;
- }
-
- size_t max_undecryptable_packets() const {
- return max_undecryptable_packets_;
- }
-
- bool HasSetBytesForConnectionIdToSend() const;
-
- // Sets the peer's connection id length, in bytes.
- void SetBytesForConnectionIdToSend(uint32_t bytes);
-
- bool HasReceivedBytesForConnectionId() const;
-
- uint32_t ReceivedBytesForConnectionId() const;
-
- // Sets an estimated initial round trip time in us.
- void SetInitialRoundTripTimeUsToSend(uint32_t rtt_us);
-
- bool HasReceivedInitialRoundTripTimeUs() const;
-
- uint32_t ReceivedInitialRoundTripTimeUs() const;
-
- bool HasInitialRoundTripTimeUsToSend() const;
-
- uint32_t GetInitialRoundTripTimeUsToSend() const;
-
- // Sets an initial stream flow control window size to transmit to the peer.
- void SetInitialStreamFlowControlWindowToSend(uint32_t window_bytes);
-
- uint32_t GetInitialStreamFlowControlWindowToSend() const;
-
- bool HasReceivedInitialStreamFlowControlWindowBytes() const;
-
- uint32_t ReceivedInitialStreamFlowControlWindowBytes() const;
-
- // Sets an initial session flow control window size to transmit to the peer.
- void SetInitialSessionFlowControlWindowToSend(uint32_t window_bytes);
-
- uint32_t GetInitialSessionFlowControlWindowToSend() const;
-
- bool HasReceivedInitialSessionFlowControlWindowBytes() const;
-
- uint32_t ReceivedInitialSessionFlowControlWindowBytes() const;
-
- // Sets socket receive buffer to transmit to the peer.
- void SetSocketReceiveBufferToSend(uint32_t window_bytes);
-
- bool HasReceivedSocketReceiveBuffer() const;
-
- uint32_t ReceivedSocketReceiveBuffer() const;
-
- void SetMultipathEnabled(bool multipath_enabled);
-
- bool MultipathEnabled() const;
-
- void SetDisableConnectionMigration();
-
- bool DisableConnectionMigration() const;
-
- void SetAlternateServerAddressToSend(
- const IPEndPoint& alternate_server_address);
-
- bool HasReceivedAlternateServerAddress() const;
-
- const IPEndPoint& ReceivedAlternateServerAddress() const;
-
- bool negotiated() const;
-
- // ToHandshakeMessage serialises the settings in this object as a series of
- // tags /value pairs and adds them to |out|.
- void ToHandshakeMessage(CryptoHandshakeMessage* out) const;
-
- // Calls ProcessPeerHello on each negotiable parameter. On failure returns
- // the corresponding QuicErrorCode and sets detailed error in |error_details|.
- QuicErrorCode ProcessPeerHello(const CryptoHandshakeMessage& peer_hello,
- HelloType hello_type,
- std::string* error_details);
-
- private:
- friend class test::QuicConfigPeer;
-
- // SetDefaults sets the members to sensible, default values.
- void SetDefaults();
-
- // Configurations options that are not negotiated.
- // Maximum time the session can be alive before crypto handshake is finished.
- QuicTime::Delta max_time_before_crypto_handshake_;
- // Maximum idle time before the crypto handshake has completed.
- QuicTime::Delta max_idle_time_before_crypto_handshake_;
- // Maximum number of undecryptable packets stored before CHLO/SHLO.
- size_t max_undecryptable_packets_;
-
- // Connection options.
- QuicFixedTagVector connection_options_;
- // Idle connection state lifetime
- QuicNegotiableUint32 idle_connection_state_lifetime_seconds_;
- // Whether to use silent close. Defaults to 0 (false) and is otherwise true.
- QuicNegotiableUint32 silent_close_;
- // Maximum number of streams that the connection can support.
- // TODO(rjshade): Remove when removing QUIC_VERSION_34
- QuicNegotiableUint32 max_streams_per_connection_;
- // Maximum number of incoming dynamic streams that the connection can support.
- QuicFixedUint32 max_incoming_dynamic_streams_;
- // The number of bytes required for the connection ID.
- QuicFixedUint32 bytes_for_connection_id_;
- // Initial round trip time estimate in microseconds.
- QuicFixedUint32 initial_round_trip_time_us_;
-
- // Initial stream flow control receive window in bytes.
- QuicFixedUint32 initial_stream_flow_control_window_bytes_;
- // Initial session flow control receive window in bytes.
- QuicFixedUint32 initial_session_flow_control_window_bytes_;
-
- // Socket receive buffer in bytes.
- // TODO(ianswett): Deprecate once QUIC_VERSION_34 is deprecated.
- QuicFixedUint32 socket_receive_buffer_;
-
- // Whether to support multipath for this connection.
- QuicNegotiableUint32 multipath_enabled_;
-
- // Whether tell peer not to attempt connection migration.
- QuicFixedUint32 connection_migration_disabled_;
-
- // An alternate server address the client could connect to.
- QuicFixedIPEndPoint alternate_server_address_;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CONFIG_H_
diff --git a/chromium/net/quic/quic_config_test.cc b/chromium/net/quic/quic_config_test.cc
deleted file mode 100644
index 7d813a55ad7..00000000000
--- a/chromium/net/quic/quic_config_test.cc
+++ /dev/null
@@ -1,252 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_config.h"
-
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/quic_config_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/test/gtest_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::string;
-
-namespace net {
-namespace test {
-namespace {
-
-class QuicConfigTest : public ::testing::Test {
- protected:
- QuicConfig config_;
-};
-
-TEST_F(QuicConfigTest, ToHandshakeMessage) {
- config_.SetInitialStreamFlowControlWindowToSend(
- kInitialStreamFlowControlWindowForTest);
- config_.SetInitialSessionFlowControlWindowToSend(
- kInitialSessionFlowControlWindowForTest);
- config_.SetIdleConnectionStateLifetime(QuicTime::Delta::FromSeconds(5),
- QuicTime::Delta::FromSeconds(2));
- config_.SetMaxStreamsPerConnection(4, 2);
- config_.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer);
- CryptoHandshakeMessage msg;
- config_.ToHandshakeMessage(&msg);
-
- uint32_t value;
- QuicErrorCode error = msg.GetUint32(kICSL, &value);
- EXPECT_EQ(QUIC_NO_ERROR, error);
- EXPECT_EQ(5u, value);
-
- error = msg.GetUint32(kMSPC, &value);
- EXPECT_EQ(QUIC_NO_ERROR, error);
- EXPECT_EQ(4u, value);
-
- error = msg.GetUint32(kSFCW, &value);
- EXPECT_EQ(QUIC_NO_ERROR, error);
- EXPECT_EQ(kInitialStreamFlowControlWindowForTest, value);
-
- error = msg.GetUint32(kCFCW, &value);
- EXPECT_EQ(QUIC_NO_ERROR, error);
- EXPECT_EQ(kInitialSessionFlowControlWindowForTest, value);
-
- error = msg.GetUint32(kSRBF, &value);
- EXPECT_EQ(QUIC_NO_ERROR, error);
- EXPECT_EQ(kDefaultSocketReceiveBuffer, value);
-}
-
-TEST_F(QuicConfigTest, ProcessClientHello) {
- QuicConfig client_config;
- QuicTagVector cgst;
- cgst.push_back(kQBIC);
- client_config.SetIdleConnectionStateLifetime(
- QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs),
- QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs));
- client_config.SetMaxStreamsPerConnection(2 * kDefaultMaxStreamsPerConnection,
- kDefaultMaxStreamsPerConnection);
- client_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli);
- client_config.SetInitialStreamFlowControlWindowToSend(
- 2 * kInitialStreamFlowControlWindowForTest);
- client_config.SetInitialSessionFlowControlWindowToSend(
- 2 * kInitialSessionFlowControlWindowForTest);
- client_config.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer);
- QuicTagVector copt;
- copt.push_back(kTBBR);
- client_config.SetConnectionOptionsToSend(copt);
- CryptoHandshakeMessage msg;
- client_config.ToHandshakeMessage(&msg);
-
- string error_details;
- QuicTagVector initial_received_options;
- initial_received_options.push_back(kIW50);
- EXPECT_TRUE(
- config_.SetInitialReceivedConnectionOptions(initial_received_options));
- EXPECT_FALSE(
- config_.SetInitialReceivedConnectionOptions(initial_received_options))
- << "You can only set initial options once.";
- const QuicErrorCode error =
- config_.ProcessPeerHello(msg, CLIENT, &error_details);
- EXPECT_FALSE(
- config_.SetInitialReceivedConnectionOptions(initial_received_options))
- << "You cannot set initial options after the hello.";
- EXPECT_EQ(QUIC_NO_ERROR, error);
- EXPECT_TRUE(config_.negotiated());
- EXPECT_EQ(QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs),
- config_.IdleConnectionStateLifetime());
- EXPECT_EQ(kDefaultMaxStreamsPerConnection, config_.MaxStreamsPerConnection());
- EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs());
- EXPECT_TRUE(config_.HasReceivedConnectionOptions());
- EXPECT_EQ(2u, config_.ReceivedConnectionOptions().size());
- EXPECT_EQ(config_.ReceivedConnectionOptions()[0], kIW50);
- EXPECT_EQ(config_.ReceivedConnectionOptions()[1], kTBBR);
- EXPECT_EQ(config_.ReceivedInitialStreamFlowControlWindowBytes(),
- 2 * kInitialStreamFlowControlWindowForTest);
- EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(),
- 2 * kInitialSessionFlowControlWindowForTest);
- EXPECT_EQ(config_.ReceivedSocketReceiveBuffer(), kDefaultSocketReceiveBuffer);
-}
-
-TEST_F(QuicConfigTest, ProcessServerHello) {
- const IPEndPoint kTestServerAddress(IPAddress(127, 0, 3, 1), 1234);
- QuicConfig server_config;
- QuicTagVector cgst;
- cgst.push_back(kQBIC);
- server_config.SetIdleConnectionStateLifetime(
- QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2),
- QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2));
- server_config.SetMaxStreamsPerConnection(kDefaultMaxStreamsPerConnection / 2,
- kDefaultMaxStreamsPerConnection / 2);
- server_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli);
- server_config.SetInitialStreamFlowControlWindowToSend(
- 2 * kInitialStreamFlowControlWindowForTest);
- server_config.SetInitialSessionFlowControlWindowToSend(
- 2 * kInitialSessionFlowControlWindowForTest);
- server_config.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer);
- server_config.SetAlternateServerAddressToSend(kTestServerAddress);
- CryptoHandshakeMessage msg;
- server_config.ToHandshakeMessage(&msg);
- string error_details;
- const QuicErrorCode error =
- config_.ProcessPeerHello(msg, SERVER, &error_details);
- EXPECT_EQ(QUIC_NO_ERROR, error);
- EXPECT_TRUE(config_.negotiated());
- EXPECT_EQ(QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs / 2),
- config_.IdleConnectionStateLifetime());
- EXPECT_EQ(kDefaultMaxStreamsPerConnection / 2,
- config_.MaxStreamsPerConnection());
- EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs());
- EXPECT_EQ(config_.ReceivedInitialStreamFlowControlWindowBytes(),
- 2 * kInitialStreamFlowControlWindowForTest);
- EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(),
- 2 * kInitialSessionFlowControlWindowForTest);
- EXPECT_EQ(config_.ReceivedSocketReceiveBuffer(), kDefaultSocketReceiveBuffer);
- EXPECT_TRUE(config_.HasReceivedAlternateServerAddress());
- EXPECT_EQ(kTestServerAddress, config_.ReceivedAlternateServerAddress());
-}
-
-TEST_F(QuicConfigTest, MissingOptionalValuesInCHLO) {
- CryptoHandshakeMessage msg;
- msg.SetValue(kICSL, 1);
-
- // Set all REQUIRED tags.
- msg.SetValue(kICSL, 1);
- msg.SetValue(kMSPC, 1);
-
- // No error, as rest are optional.
- string error_details;
- const QuicErrorCode error =
- config_.ProcessPeerHello(msg, CLIENT, &error_details);
- EXPECT_EQ(QUIC_NO_ERROR, error);
- EXPECT_TRUE(config_.negotiated());
-}
-
-TEST_F(QuicConfigTest, MissingOptionalValuesInSHLO) {
- CryptoHandshakeMessage msg;
-
- // Set all REQUIRED tags.
- msg.SetValue(kICSL, 1);
- msg.SetValue(kMSPC, 1);
-
- // No error, as rest are optional.
- string error_details;
- const QuicErrorCode error =
- config_.ProcessPeerHello(msg, SERVER, &error_details);
- EXPECT_EQ(QUIC_NO_ERROR, error);
- EXPECT_TRUE(config_.negotiated());
-}
-
-TEST_F(QuicConfigTest, MissingValueInCHLO) {
- // Server receives CHLO with missing kICSL.
- CryptoHandshakeMessage msg;
- string error_details;
- const QuicErrorCode error =
- config_.ProcessPeerHello(msg, CLIENT, &error_details);
- EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, error);
-}
-
-TEST_F(QuicConfigTest, MissingValueInSHLO) {
- // Client receives SHLO with missing kICSL.
- CryptoHandshakeMessage msg;
- string error_details;
- const QuicErrorCode error =
- config_.ProcessPeerHello(msg, SERVER, &error_details);
- EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, error);
-}
-
-TEST_F(QuicConfigTest, OutOfBoundSHLO) {
- QuicConfig server_config;
- server_config.SetIdleConnectionStateLifetime(
- QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs),
- QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs));
-
- CryptoHandshakeMessage msg;
- server_config.ToHandshakeMessage(&msg);
- string error_details;
- const QuicErrorCode error =
- config_.ProcessPeerHello(msg, SERVER, &error_details);
- EXPECT_EQ(QUIC_INVALID_NEGOTIATED_VALUE, error);
-}
-
-TEST_F(QuicConfigTest, InvalidFlowControlWindow) {
- // QuicConfig should not accept an invalid flow control window to send to the
- // peer: the receive window must be at least the default of 16 Kb.
- QuicConfig config;
- const uint64_t kInvalidWindow = kMinimumFlowControlSendWindow - 1;
- EXPECT_DFATAL(config.SetInitialStreamFlowControlWindowToSend(kInvalidWindow),
- "Initial stream flow control receive window");
-
- EXPECT_EQ(kMinimumFlowControlSendWindow,
- config.GetInitialStreamFlowControlWindowToSend());
-}
-
-TEST_F(QuicConfigTest, HasClientSentConnectionOption) {
- QuicConfig client_config;
- QuicTagVector copt;
- copt.push_back(kTBBR);
- client_config.SetConnectionOptionsToSend(copt);
- EXPECT_TRUE(client_config.HasClientSentConnectionOption(
- kTBBR, Perspective::IS_CLIENT));
-
- CryptoHandshakeMessage msg;
- client_config.ToHandshakeMessage(&msg);
-
- string error_details;
- const QuicErrorCode error =
- config_.ProcessPeerHello(msg, CLIENT, &error_details);
- EXPECT_EQ(QUIC_NO_ERROR, error);
- EXPECT_TRUE(config_.negotiated());
-
- EXPECT_TRUE(config_.HasReceivedConnectionOptions());
- EXPECT_EQ(1u, config_.ReceivedConnectionOptions().size());
- EXPECT_TRUE(
- config_.HasClientSentConnectionOption(kTBBR, Perspective::IS_SERVER));
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_connection.cc b/chromium/net/quic/quic_connection.cc
deleted file mode 100644
index 932b0c31c55..00000000000
--- a/chromium/net/quic/quic_connection.cc
+++ /dev/null
@@ -1,2536 +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/quic_connection.h"
-
-#include <string.h>
-#include <sys/types.h>
-
-#include <algorithm>
-#include <iterator>
-#include <limits>
-#include <memory>
-#include <set>
-#include <utility>
-
-#include "base/format_macros.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "net/base/address_family.h"
-#include "net/base/ip_address.h"
-#include "net/base/net_errors.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_packet_generator.h"
-#include "net/quic/quic_sent_packet_manager.h"
-#include "net/quic/quic_utils.h"
-
-using base::StringPiece;
-using base::StringPrintf;
-using std::list;
-using std::make_pair;
-using std::max;
-using std::min;
-using std::numeric_limits;
-using std::set;
-using std::string;
-using std::vector;
-
-namespace net {
-
-class QuicDecrypter;
-class QuicEncrypter;
-
-namespace {
-
-// The largest gap in packets we'll accept without closing the connection.
-// This will likely have to be tuned.
-const QuicPacketNumber kMaxPacketGap = 5000;
-
-// Maximum number of acks received before sending an ack in response.
-const QuicPacketCount kMaxPacketsReceivedBeforeAckSend = 20;
-
-// Maximum number of retransmittable packets received before sending an ack.
-const QuicPacketCount kDefaultRetransmittablePacketsBeforeAck = 2;
-// Minimum number of packets received before ack decimation is enabled.
-// This intends to avoid the beginning of slow start, when CWNDs may be
-// rapidly increasing.
-const QuicPacketCount kMinReceivedBeforeAckDecimation = 100;
-// Wait for up to 10 retransmittable packets before sending an ack.
-const QuicPacketCount kMaxRetransmittablePacketsBeforeAck = 10;
-// One quarter RTT delay when doing ack decimation.
-const float kAckDecimationDelay = 0.25;
-// One eighth RTT delay when doing ack decimation.
-const float kShortAckDecimationDelay = 0.125;
-
-bool Near(QuicPacketNumber a, QuicPacketNumber b) {
- QuicPacketNumber delta = (a > b) ? a - b : b - a;
- return delta <= kMaxPacketGap;
-}
-
-bool IsInitializedIPEndPoint(const IPEndPoint& address) {
- return net::GetAddressFamily(address.address()) !=
- net::ADDRESS_FAMILY_UNSPECIFIED;
-}
-
-// An alarm that is scheduled to send an ack if a timeout occurs.
-class AckAlarmDelegate : public QuicAlarm::Delegate {
- public:
- explicit AckAlarmDelegate(QuicConnection* connection)
- : connection_(connection) {}
-
- void OnAlarm() override {
- DCHECK(connection_->ack_frame_updated());
- QuicConnection::ScopedPacketBundler bundler(connection_,
- QuicConnection::SEND_ACK);
- }
-
- private:
- QuicConnection* connection_;
-
- DISALLOW_COPY_AND_ASSIGN(AckAlarmDelegate);
-};
-
-// This alarm will be scheduled any time a data-bearing packet is sent out.
-// When the alarm goes off, the connection checks to see if the oldest packets
-// have been acked, and retransmit them if they have not.
-class RetransmissionAlarmDelegate : public QuicAlarm::Delegate {
- public:
- explicit RetransmissionAlarmDelegate(QuicConnection* connection)
- : connection_(connection) {}
-
- void OnAlarm() override { connection_->OnRetransmissionTimeout(); }
-
- private:
- QuicConnection* connection_;
-
- DISALLOW_COPY_AND_ASSIGN(RetransmissionAlarmDelegate);
-};
-
-// An alarm that is scheduled when the SentPacketManager requires a delay
-// before sending packets and fires when the packet may be sent.
-class SendAlarmDelegate : public QuicAlarm::Delegate {
- public:
- explicit SendAlarmDelegate(QuicConnection* connection)
- : connection_(connection) {}
-
- void OnAlarm() override { connection_->WriteAndBundleAcksIfNotBlocked(); }
-
- private:
- QuicConnection* connection_;
-
- DISALLOW_COPY_AND_ASSIGN(SendAlarmDelegate);
-};
-
-class TimeoutAlarmDelegate : public QuicAlarm::Delegate {
- public:
- explicit TimeoutAlarmDelegate(QuicConnection* connection)
- : connection_(connection) {}
-
- void OnAlarm() override { connection_->CheckForTimeout(); }
-
- private:
- QuicConnection* connection_;
-
- DISALLOW_COPY_AND_ASSIGN(TimeoutAlarmDelegate);
-};
-
-class PingAlarmDelegate : public QuicAlarm::Delegate {
- public:
- explicit PingAlarmDelegate(QuicConnection* connection)
- : connection_(connection) {}
-
- void OnAlarm() override { connection_->OnPingTimeout(); }
-
- private:
- QuicConnection* connection_;
-
- DISALLOW_COPY_AND_ASSIGN(PingAlarmDelegate);
-};
-
-class MtuDiscoveryAlarmDelegate : public QuicAlarm::Delegate {
- public:
- explicit MtuDiscoveryAlarmDelegate(QuicConnection* connection)
- : connection_(connection) {}
-
- void OnAlarm() override { connection_->DiscoverMtu(); }
-
- private:
- QuicConnection* connection_;
-
- DISALLOW_COPY_AND_ASSIGN(MtuDiscoveryAlarmDelegate);
-};
-
-// Listens for acks of MTU discovery packets and raises the maximum packet size
-// of the connection if the probe succeeds.
-class MtuDiscoveryAckListener : public QuicAckListenerInterface {
- public:
- MtuDiscoveryAckListener(QuicConnection* connection, QuicByteCount probe_size)
- : connection_(connection), probe_size_(probe_size) {}
-
- void OnPacketAcked(int /*acked_bytes*/,
- QuicTime::Delta /*ack delay time*/) override {
- // MTU discovery packets are not retransmittable, so it must be acked.
- MaybeIncreaseMtu();
- }
-
- void OnPacketRetransmitted(int /*retransmitted_bytes*/) override {}
-
- protected:
- // MtuDiscoveryAckListener is ref counted.
- ~MtuDiscoveryAckListener() override {}
-
- private:
- void MaybeIncreaseMtu() {
- if (probe_size_ > connection_->max_packet_length()) {
- connection_->SetMaxPacketLength(probe_size_);
- }
- }
-
- QuicConnection* connection_;
- QuicByteCount probe_size_;
-
- DISALLOW_COPY_AND_ASSIGN(MtuDiscoveryAckListener);
-};
-
-} // namespace
-
-#define ENDPOINT \
- (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ")
-
-QuicConnection::QuicConnection(QuicConnectionId connection_id,
- IPEndPoint address,
- QuicConnectionHelperInterface* helper,
- QuicAlarmFactory* alarm_factory,
- QuicPacketWriter* writer,
- bool owns_writer,
- Perspective perspective,
- const QuicVersionVector& supported_versions)
- : framer_(supported_versions,
- helper->GetClock()->ApproximateNow(),
- perspective),
- helper_(helper),
- alarm_factory_(alarm_factory),
- per_packet_options_(nullptr),
- writer_(writer),
- owns_writer_(owns_writer),
- encryption_level_(ENCRYPTION_NONE),
- has_forward_secure_encrypter_(false),
- first_required_forward_secure_packet_(0),
- clock_(helper->GetClock()),
- random_generator_(helper->GetRandomGenerator()),
- connection_id_(connection_id),
- peer_address_(address),
- active_peer_migration_type_(NO_CHANGE),
- highest_packet_sent_before_peer_migration_(0),
- last_packet_decrypted_(false),
- last_size_(0),
- current_packet_data_(nullptr),
- last_decrypted_packet_level_(ENCRYPTION_NONE),
- should_last_packet_instigate_acks_(false),
- largest_seen_packet_with_ack_(0),
- largest_seen_packet_with_stop_waiting_(0),
- max_undecryptable_packets_(0),
- pending_version_negotiation_packet_(false),
- save_crypto_packets_as_termination_packets_(false),
- idle_timeout_connection_close_behavior_(
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET),
- close_connection_after_five_rtos_(false),
- received_packet_manager_(&stats_),
- ack_queued_(false),
- num_retransmittable_packets_received_since_last_ack_sent_(0),
- last_ack_had_missing_packets_(false),
- num_packets_received_since_last_ack_sent_(0),
- stop_waiting_count_(0),
- ack_mode_(TCP_ACKING),
- ack_decimation_delay_(kAckDecimationDelay),
- delay_setting_retransmission_alarm_(false),
- pending_retransmission_alarm_(false),
- defer_send_in_response_to_packets_(false),
- arena_(),
- ack_alarm_(alarm_factory_->CreateAlarm(arena_.New<AckAlarmDelegate>(this),
- &arena_)),
- retransmission_alarm_(alarm_factory_->CreateAlarm(
- arena_.New<RetransmissionAlarmDelegate>(this),
- &arena_)),
- send_alarm_(
- alarm_factory_->CreateAlarm(arena_.New<SendAlarmDelegate>(this),
- &arena_)),
- resume_writes_alarm_(
- alarm_factory_->CreateAlarm(arena_.New<SendAlarmDelegate>(this),
- &arena_)),
- timeout_alarm_(
- alarm_factory_->CreateAlarm(arena_.New<TimeoutAlarmDelegate>(this),
- &arena_)),
- ping_alarm_(
- alarm_factory_->CreateAlarm(arena_.New<PingAlarmDelegate>(this),
- &arena_)),
- mtu_discovery_alarm_(alarm_factory_->CreateAlarm(
- arena_.New<MtuDiscoveryAlarmDelegate>(this),
- &arena_)),
- visitor_(nullptr),
- debug_visitor_(nullptr),
- packet_generator_(connection_id_,
- &framer_,
- random_generator_,
- helper->GetBufferAllocator(),
- this),
- idle_network_timeout_(QuicTime::Delta::Infinite()),
- handshake_timeout_(QuicTime::Delta::Infinite()),
- time_of_last_received_packet_(clock_->ApproximateNow()),
- time_of_last_sent_new_packet_(clock_->ApproximateNow()),
- last_send_for_timeout_(clock_->ApproximateNow()),
- packet_number_of_last_sent_packet_(0),
- sent_packet_manager_(new QuicSentPacketManager(perspective,
- kDefaultPathId,
- clock_,
- &stats_,
- kCubic,
- kNack,
- /*delegate=*/nullptr)),
- version_negotiation_state_(START_NEGOTIATION),
- perspective_(perspective),
- connected_(true),
- can_truncate_connection_ids_(true),
- mtu_discovery_target_(0),
- mtu_probe_count_(0),
- packets_between_mtu_probes_(kPacketsBetweenMtuProbesBase),
- next_mtu_probe_at_(kPacketsBetweenMtuProbesBase),
- largest_received_packet_size_(0),
- goaway_sent_(false),
- goaway_received_(false),
- multipath_enabled_(false) {
- DVLOG(1) << ENDPOINT
- << "Created connection with connection_id: " << connection_id;
- framer_.set_visitor(this);
- framer_.set_received_entropy_calculator(&received_packet_manager_);
- last_stop_waiting_frame_.least_unacked = 0;
- stats_.connection_creation_time = clock_->ApproximateNow();
- // TODO(ianswett): Supply the NetworkChangeVisitor as a constructor argument
- // and make it required non-null, because it's always used.
- sent_packet_manager_->SetNetworkChangeVisitor(this);
- // Allow the packet writer to potentially reduce the packet size to a value
- // even smaller than kDefaultMaxPacketSize.
- SetMaxPacketLength(perspective_ == Perspective::IS_SERVER
- ? kDefaultServerMaxPacketSize
- : kDefaultMaxPacketSize);
- received_packet_manager_.SetVersion(version());
-}
-
-QuicConnection::~QuicConnection() {
- if (owns_writer_) {
- delete writer_;
- }
- STLDeleteElements(&undecryptable_packets_);
- ClearQueuedPackets();
-}
-
-void QuicConnection::ClearQueuedPackets() {
- for (QueuedPacketList::iterator it = queued_packets_.begin();
- it != queued_packets_.end(); ++it) {
- // Delete the buffer before calling ClearSerializedPacket, which sets
- // encrypted_buffer to nullptr.
- delete[] it->encrypted_buffer;
- QuicUtils::ClearSerializedPacket(&(*it));
- }
- queued_packets_.clear();
-}
-
-void QuicConnection::SetFromConfig(const QuicConfig& config) {
- if (config.negotiated()) {
- // Handshake complete, set handshake timeout to Infinite.
- SetNetworkTimeouts(QuicTime::Delta::Infinite(),
- config.IdleConnectionStateLifetime());
- if (config.SilentClose()) {
- idle_timeout_connection_close_behavior_ =
- ConnectionCloseBehavior::SILENT_CLOSE;
- }
- if (FLAGS_quic_enable_multipath && config.MultipathEnabled()) {
- multipath_enabled_ = true;
- }
- } else {
- SetNetworkTimeouts(config.max_time_before_crypto_handshake(),
- config.max_idle_time_before_crypto_handshake());
- }
-
- sent_packet_manager_->SetFromConfig(config);
- if (config.HasReceivedBytesForConnectionId() &&
- can_truncate_connection_ids_) {
- packet_generator_.SetConnectionIdLength(
- config.ReceivedBytesForConnectionId());
- }
- max_undecryptable_packets_ = config.max_undecryptable_packets();
-
- if (config.HasClientSentConnectionOption(kMTUH, perspective_)) {
- SetMtuDiscoveryTarget(kMtuDiscoveryTargetPacketSizeHigh);
- }
- if (config.HasClientSentConnectionOption(kMTUL, perspective_)) {
- SetMtuDiscoveryTarget(kMtuDiscoveryTargetPacketSizeLow);
- }
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnSetFromConfig(config);
- }
- if (config.HasClientSentConnectionOption(kACKD, perspective_)) {
- ack_mode_ = ACK_DECIMATION;
- }
- if (config.HasClientSentConnectionOption(kAKD2, perspective_)) {
- ack_mode_ = ACK_DECIMATION_WITH_REORDERING;
- }
- if (config.HasClientSentConnectionOption(kAKD3, perspective_)) {
- ack_mode_ = ACK_DECIMATION;
- ack_decimation_delay_ = kShortAckDecimationDelay;
- }
- if (config.HasClientSentConnectionOption(kAKD4, perspective_)) {
- ack_mode_ = ACK_DECIMATION_WITH_REORDERING;
- ack_decimation_delay_ = kShortAckDecimationDelay;
- }
- if (config.HasClientSentConnectionOption(k5RTO, perspective_)) {
- close_connection_after_five_rtos_ = true;
- }
-}
-
-void QuicConnection::OnSendConnectionState(
- const CachedNetworkParameters& cached_network_params) {
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnSendConnectionState(cached_network_params);
- }
-}
-
-void QuicConnection::OnReceiveConnectionState(
- const CachedNetworkParameters& cached_network_params) {
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnReceiveConnectionState(cached_network_params);
- }
-}
-
-void QuicConnection::ResumeConnectionState(
- const CachedNetworkParameters& cached_network_params,
- bool max_bandwidth_resumption) {
- sent_packet_manager_->ResumeConnectionState(cached_network_params,
- max_bandwidth_resumption);
-}
-
-void QuicConnection::SetMaxPacingRate(QuicBandwidth max_pacing_rate) {
- sent_packet_manager_->SetMaxPacingRate(max_pacing_rate);
-}
-
-void QuicConnection::SetNumOpenStreams(size_t num_streams) {
- sent_packet_manager_->SetNumOpenStreams(num_streams);
-}
-
-bool QuicConnection::SelectMutualVersion(
- const QuicVersionVector& 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 QuicVersionVector& supported_versions = framer_.supported_versions();
- for (size_t i = 0; i < supported_versions.size(); ++i) {
- const QuicVersion& version = supported_versions[i];
- if (ContainsValue(available_versions, version)) {
- framer_.set_version(version);
- return true;
- }
- }
-
- return false;
-}
-
-void QuicConnection::OnError(QuicFramer* framer) {
- // Packets that we can not or have not decrypted are dropped.
- // TODO(rch): add stats to measure this.
- if (!connected_ || last_packet_decrypted_ == false) {
- return;
- }
- CloseConnection(framer->error(), framer->detailed_error(),
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-}
-
-void QuicConnection::OnPacket() {
- last_packet_decrypted_ = false;
-}
-
-void QuicConnection::OnPublicResetPacket(const QuicPublicResetPacket& packet) {
- // Check that any public reset packet with a different connection ID that was
- // routed to this QuicConnection has been redirected before control reaches
- // here. (Check for a bug regression.)
- DCHECK_EQ(connection_id_, packet.public_header.connection_id);
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnPublicResetPacket(packet);
- }
- const string error_details = "Received public reset.";
- DVLOG(1) << ENDPOINT << error_details;
- TearDownLocalConnectionState(QUIC_PUBLIC_RESET, error_details,
- ConnectionCloseSource::FROM_PEER);
-}
-
-bool QuicConnection::OnProtocolVersionMismatch(QuicVersion received_version) {
- DVLOG(1) << ENDPOINT << "Received packet with mismatched version "
- << received_version;
- // TODO(satyamshekhar): Implement no server state in this mode.
- if (perspective_ == Perspective::IS_CLIENT) {
- const string error_details = "Protocol version mismatch.";
- QUIC_BUG << ENDPOINT << error_details;
- TearDownLocalConnectionState(QUIC_INTERNAL_ERROR, error_details,
- ConnectionCloseSource::FROM_SELF);
- return false;
- }
- DCHECK_NE(version(), received_version);
-
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnProtocolVersionMismatch(received_version);
- }
-
- switch (version_negotiation_state_) {
- case START_NEGOTIATION:
- if (!framer_.IsSupportedVersion(received_version)) {
- SendVersionNegotiationPacket();
- version_negotiation_state_ = NEGOTIATION_IN_PROGRESS;
- return false;
- }
- break;
-
- case NEGOTIATION_IN_PROGRESS:
- if (!framer_.IsSupportedVersion(received_version)) {
- SendVersionNegotiationPacket();
- return false;
- }
- break;
-
- case NEGOTIATED_VERSION:
- // Might be old packets that were sent by the client before the version
- // was negotiated. Drop these.
- return false;
-
- default:
- DCHECK(false);
- }
-
- version_negotiation_state_ = NEGOTIATED_VERSION;
- received_packet_manager_.SetVersion(received_version);
- visitor_->OnSuccessfulVersionNegotiation(received_version);
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnSuccessfulVersionNegotiation(received_version);
- }
- DVLOG(1) << ENDPOINT << "version negotiated " << received_version;
-
- // Store the new version.
- framer_.set_version(received_version);
-
- // TODO(satyamshekhar): Store the packet number of this packet and close the
- // connection if we ever received a packet with incorrect version and whose
- // packet number is greater.
- return true;
-}
-
-// Handles version negotiation for client connection.
-void QuicConnection::OnVersionNegotiationPacket(
- const QuicVersionNegotiationPacket& packet) {
- // Check that any public reset packet with a different connection ID that was
- // routed to this QuicConnection has been redirected before control reaches
- // here. (Check for a bug regression.)
- DCHECK_EQ(connection_id_, packet.connection_id);
- if (perspective_ == Perspective::IS_SERVER) {
- const string error_details = "Server receieved version negotiation packet.";
- QUIC_BUG << error_details;
- TearDownLocalConnectionState(QUIC_INTERNAL_ERROR, error_details,
- ConnectionCloseSource::FROM_SELF);
- return;
- }
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnVersionNegotiationPacket(packet);
- }
-
- if (version_negotiation_state_ != START_NEGOTIATION) {
- // Possibly a duplicate version negotiation packet.
- return;
- }
-
- if (ContainsValue(packet.versions, version())) {
- const string error_details =
- "Server already supports client's version and should have accepted the "
- "connection.";
- DLOG(WARNING) << error_details;
- TearDownLocalConnectionState(QUIC_INVALID_VERSION_NEGOTIATION_PACKET,
- error_details,
- ConnectionCloseSource::FROM_SELF);
- return;
- }
-
- if (!SelectMutualVersion(packet.versions)) {
- CloseConnection(QUIC_INVALID_VERSION, "No common version found.",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
-
- DVLOG(1) << ENDPOINT
- << "Negotiated version: " << QuicVersionToString(version());
- received_packet_manager_.SetVersion(version());
- server_supported_versions_ = packet.versions;
- version_negotiation_state_ = NEGOTIATION_IN_PROGRESS;
- RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION);
-}
-
-bool QuicConnection::OnUnauthenticatedPublicHeader(
- const QuicPacketPublicHeader& header) {
- if (header.connection_id == connection_id_) {
- return true;
- }
-
- ++stats_.packets_dropped;
- DVLOG(1) << ENDPOINT << "Ignoring packet from unexpected ConnectionId: "
- << header.connection_id << " instead of " << connection_id_;
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnIncorrectConnectionId(header.connection_id);
- }
- // If this is a server, the dispatcher routes each packet to the
- // QuicConnection responsible for the packet's connection ID. So if control
- // arrives here and this is a server, the dispatcher must be malfunctioning.
- DCHECK_NE(Perspective::IS_SERVER, perspective_);
- return false;
-}
-
-bool QuicConnection::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnUnauthenticatedHeader(header);
- }
-
- // Check that any public reset packet with a different connection ID that was
- // routed to this QuicConnection has been redirected before control reaches
- // here.
- DCHECK_EQ(connection_id_, header.public_header.connection_id);
-
- // Multipath is not enabled, but a packet with multipath flag on is received.
- if (!multipath_enabled_ && header.public_header.multipath_flag) {
- const string error_details =
- "Received a packet with multipath flag but multipath is not enabled.";
- QUIC_BUG << error_details;
- CloseConnection(QUIC_BAD_MULTIPATH_FLAG, error_details,
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return false;
- }
- if (!packet_generator_.IsPendingPacketEmpty()) {
- // Incoming packets may change a queued ACK frame.
- const string error_details =
- "Pending frames must be serialized before incoming packets are "
- "processed.";
- QUIC_BUG << error_details;
- CloseConnection(QUIC_INTERNAL_ERROR, error_details,
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return false;
- }
-
- // If this packet has already been seen, or the sender has told us that it
- // will not be retransmitted, then stop processing the packet.
- if (!received_packet_manager_.IsAwaitingPacket(header.packet_number)) {
- DVLOG(1) << ENDPOINT << "Packet " << header.packet_number
- << " no longer being waited for. Discarding.";
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnDuplicatePacket(header.packet_number);
- }
- ++stats_.packets_dropped;
- return false;
- }
-
- return true;
-}
-
-void QuicConnection::OnDecryptedPacket(EncryptionLevel level) {
- last_decrypted_packet_level_ = level;
- last_packet_decrypted_ = true;
-
- // If this packet was foward-secure encrypted and the forward-secure encrypter
- // is not being used, start using it.
- if (encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
- has_forward_secure_encrypter_ && level == ENCRYPTION_FORWARD_SECURE) {
- SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
- }
-
- // Once the server receives a forward secure packet, the handshake is
- // confirmed.
- if (FLAGS_quic_no_shlo_listener && level == ENCRYPTION_FORWARD_SECURE &&
- perspective_ == Perspective::IS_SERVER) {
- sent_packet_manager_->SetHandshakeConfirmed();
- }
-}
-
-bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnPacketHeader(header);
- }
-
- // Will be decremented below if we fall through to return true.
- ++stats_.packets_dropped;
-
- if (!ProcessValidatedPacket(header)) {
- return false;
- }
-
- // Only migrate connection to a new peer address if a change is not underway.
- PeerAddressChangeType peer_migration_type =
- QuicUtils::DetermineAddressChangeType(peer_address_,
- last_packet_source_address_);
- if (active_peer_migration_type_ == NO_CHANGE &&
- peer_migration_type != NO_CHANGE) {
- StartPeerMigration(header.path_id, peer_migration_type);
- }
-
- --stats_.packets_dropped;
- DVLOG(1) << ENDPOINT << "Received packet header: " << header;
- last_header_ = header;
- DCHECK(connected_);
- return true;
-}
-
-bool QuicConnection::OnStreamFrame(const QuicStreamFrame& frame) {
- DCHECK(connected_);
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnStreamFrame(frame);
- }
- if (frame.stream_id != kCryptoStreamId &&
- last_decrypted_packet_level_ == ENCRYPTION_NONE) {
- if (MaybeConsiderAsMemoryCorruption(frame)) {
- CloseConnection(QUIC_MAYBE_CORRUPTED_MEMORY,
- "Received crypto frame on non crypto stream.",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return false;
- }
-
- QUIC_BUG << ENDPOINT
- << "Received an unencrypted data frame: closing connection"
- << " packet_number:" << last_header_.packet_number
- << " stream_id:" << frame.stream_id
- << " received_packets:" << received_packet_manager_.ack_frame();
- CloseConnection(QUIC_UNENCRYPTED_STREAM_DATA,
- "Unencrypted stream data seen.",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return false;
- }
- visitor_->OnStreamFrame(frame);
- visitor_->PostProcessAfterData();
- stats_.stream_bytes_received += frame.data_length;
- should_last_packet_instigate_acks_ = true;
- return connected_;
-}
-
-bool QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) {
- DCHECK(connected_);
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnAckFrame(incoming_ack);
- }
- DVLOG(1) << ENDPOINT << "OnAckFrame: " << incoming_ack;
-
- if (last_header_.packet_number <= largest_seen_packet_with_ack_) {
- DVLOG(1) << ENDPOINT << "Received an old ack frame: ignoring";
- return true;
- }
-
- const char* error = ValidateAckFrame(incoming_ack);
- if (error != nullptr) {
- CloseConnection(QUIC_INVALID_ACK_DATA, error,
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return false;
- }
-
- if (send_alarm_->IsSet()) {
- send_alarm_->Cancel();
- }
- ProcessAckFrame(incoming_ack);
- if (incoming_ack.is_truncated) {
- should_last_packet_instigate_acks_ = true;
- }
- // If the incoming ack's packets set expresses missing packets: peer is still
- // waiting for a packet lower than a packet that we are no longer planning to
- // send.
- // If the incoming ack's packets set expresses received packets: peer is still
- // acking packets which we never care about.
- // Send an ack to raise the high water mark.
- if (!incoming_ack.packets.Empty() &&
- GetLeastUnacked(incoming_ack.path_id) > incoming_ack.packets.Min()) {
- ++stop_waiting_count_;
- } else {
- stop_waiting_count_ = 0;
- }
-
- return connected_;
-}
-
-void QuicConnection::ProcessAckFrame(const QuicAckFrame& incoming_ack) {
- largest_seen_packet_with_ack_ = last_header_.packet_number;
- sent_packet_manager_->OnIncomingAck(incoming_ack,
- time_of_last_received_packet_);
- if (version() <= QUIC_VERSION_33) {
- sent_entropy_manager_.ClearEntropyBefore(
- sent_packet_manager_->GetLeastPacketAwaitedByPeer(
- incoming_ack.path_id) -
- 1);
- }
- // Always reset the retransmission alarm when an ack comes in, since we now
- // have a better estimate of the current rtt than when it was set.
- SetRetransmissionAlarm();
-}
-
-void QuicConnection::ProcessStopWaitingFrame(
- const QuicStopWaitingFrame& stop_waiting) {
- largest_seen_packet_with_stop_waiting_ = last_header_.packet_number;
- received_packet_manager_.UpdatePacketInformationSentByPeer(stop_waiting);
-}
-
-bool QuicConnection::OnStopWaitingFrame(const QuicStopWaitingFrame& frame) {
- DCHECK(connected_);
-
- if (last_header_.packet_number <= largest_seen_packet_with_stop_waiting_) {
- DVLOG(1) << ENDPOINT << "Received an old stop waiting frame: ignoring";
- return true;
- }
-
- const char* error = ValidateStopWaitingFrame(frame);
- if (error != nullptr) {
- CloseConnection(QUIC_INVALID_STOP_WAITING_DATA, error,
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return false;
- }
-
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnStopWaitingFrame(frame);
- }
-
- last_stop_waiting_frame_ = frame;
- return connected_;
-}
-
-bool QuicConnection::OnPaddingFrame(const QuicPaddingFrame& frame) {
- DCHECK(connected_);
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnPaddingFrame(frame);
- }
- return true;
-}
-
-bool QuicConnection::OnPingFrame(const QuicPingFrame& frame) {
- DCHECK(connected_);
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnPingFrame(frame);
- }
- should_last_packet_instigate_acks_ = true;
- return true;
-}
-
-const char* QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
- if (incoming_ack.largest_observed > packet_generator_.packet_number()) {
- LOG(WARNING) << ENDPOINT << "Peer's observed unsent packet:"
- << incoming_ack.largest_observed << " vs "
- << packet_generator_.packet_number();
- // We got an error for data we have not sent. Error out.
- return "Largest observed too high.";
- }
-
- if (incoming_ack.largest_observed <
- sent_packet_manager_->GetLargestObserved(incoming_ack.path_id)) {
- LOG(WARNING) << ENDPOINT << "Peer's largest_observed packet decreased:"
- << incoming_ack.largest_observed << " vs "
- << sent_packet_manager_->GetLargestObserved(
- incoming_ack.path_id)
- << " packet_number:" << last_header_.packet_number
- << " largest seen with ack:" << largest_seen_packet_with_ack_
- << " connection_id: " << connection_id_;
- // A new ack has a diminished largest_observed value. Error out.
- // If this was an old packet, we wouldn't even have checked.
- return "Largest observed too low.";
- }
-
- if (version() <= QUIC_VERSION_33) {
- if (!incoming_ack.packets.Empty() &&
- incoming_ack.packets.Max() > incoming_ack.largest_observed) {
- LOG(WARNING) << ENDPOINT
- << "Peer sent missing packet: " << incoming_ack.packets.Max()
- << " which is greater than largest observed: "
- << incoming_ack.largest_observed;
- return "Missing packet higher than largest observed.";
- }
-
- if (!incoming_ack.packets.Empty() &&
- incoming_ack.packets.Min() <
- sent_packet_manager_->GetLeastPacketAwaitedByPeer(
- incoming_ack.path_id)) {
- LOG(WARNING) << ENDPOINT
- << "Peer sent missing packet: " << incoming_ack.packets.Min()
- << " which is smaller than least_packet_awaited_by_peer_: "
- << sent_packet_manager_->GetLeastPacketAwaitedByPeer(
- incoming_ack.path_id);
- return "Missing packet smaller than least awaited.";
- }
- if (!sent_entropy_manager_.IsValidEntropy(incoming_ack.largest_observed,
- incoming_ack.packets,
- incoming_ack.entropy_hash)) {
- LOG(WARNING) << ENDPOINT << "Peer sent invalid entropy."
- << " largest_observed:" << incoming_ack.largest_observed
- << " last_received:" << last_header_.packet_number;
- return "Invalid entropy.";
- }
- } else {
- if (!incoming_ack.packets.Empty() &&
- incoming_ack.packets.Max() != incoming_ack.largest_observed) {
- QUIC_BUG << ENDPOINT
- << "Peer last received packet: " << incoming_ack.packets.Max()
- << " which is not equal to largest observed: "
- << incoming_ack.largest_observed;
- return "Last received packet not equal to largest observed.";
- }
- }
-
- return nullptr;
-}
-
-const char* QuicConnection::ValidateStopWaitingFrame(
- const QuicStopWaitingFrame& stop_waiting) {
- if (stop_waiting.least_unacked <
- received_packet_manager_.peer_least_packet_awaiting_ack()) {
- DLOG(ERROR) << ENDPOINT << "Peer's sent low least_unacked: "
- << stop_waiting.least_unacked << " vs "
- << received_packet_manager_.peer_least_packet_awaiting_ack();
- // We never process old ack frames, so this number should only increase.
- return "Least unacked too small.";
- }
-
- if (stop_waiting.least_unacked > last_header_.packet_number) {
- DLOG(ERROR) << ENDPOINT
- << "Peer sent least_unacked:" << stop_waiting.least_unacked
- << " greater than the enclosing packet number:"
- << last_header_.packet_number;
- return "Least unacked too large.";
- }
-
- return nullptr;
-}
-
-bool QuicConnection::OnRstStreamFrame(const QuicRstStreamFrame& frame) {
- DCHECK(connected_);
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnRstStreamFrame(frame);
- }
- DVLOG(1) << ENDPOINT
- << "RST_STREAM_FRAME received for stream: " << frame.stream_id
- << " with error: "
- << QuicUtils::StreamErrorToString(frame.error_code);
- visitor_->OnRstStream(frame);
- visitor_->PostProcessAfterData();
- should_last_packet_instigate_acks_ = true;
- return connected_;
-}
-
-bool QuicConnection::OnConnectionCloseFrame(
- const QuicConnectionCloseFrame& frame) {
- DCHECK(connected_);
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnConnectionCloseFrame(frame);
- }
- DVLOG(1) << ENDPOINT
- << "Received ConnectionClose for connection: " << connection_id()
- << ", with error: " << QuicUtils::ErrorToString(frame.error_code)
- << " (" << frame.error_details << ")";
- TearDownLocalConnectionState(frame.error_code, frame.error_details,
- ConnectionCloseSource::FROM_PEER);
- return connected_;
-}
-
-bool QuicConnection::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
- DCHECK(connected_);
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnGoAwayFrame(frame);
- }
- DVLOG(1) << ENDPOINT << "GOAWAY_FRAME received with last good stream: "
- << frame.last_good_stream_id
- << " and error: " << QuicUtils::ErrorToString(frame.error_code)
- << " and reason: " << frame.reason_phrase;
-
- goaway_received_ = true;
- visitor_->OnGoAway(frame);
- visitor_->PostProcessAfterData();
- should_last_packet_instigate_acks_ = true;
- return connected_;
-}
-
-bool QuicConnection::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
- DCHECK(connected_);
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnWindowUpdateFrame(frame);
- }
- DVLOG(1) << ENDPOINT
- << "WINDOW_UPDATE_FRAME received for stream: " << frame.stream_id
- << " with byte offset: " << frame.byte_offset;
- visitor_->OnWindowUpdateFrame(frame);
- visitor_->PostProcessAfterData();
- should_last_packet_instigate_acks_ = true;
- return connected_;
-}
-
-bool QuicConnection::OnBlockedFrame(const QuicBlockedFrame& frame) {
- DCHECK(connected_);
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnBlockedFrame(frame);
- }
- DVLOG(1) << ENDPOINT
- << "BLOCKED_FRAME received for stream: " << frame.stream_id;
- visitor_->OnBlockedFrame(frame);
- visitor_->PostProcessAfterData();
- should_last_packet_instigate_acks_ = true;
- return connected_;
-}
-
-bool QuicConnection::OnPathCloseFrame(const QuicPathCloseFrame& frame) {
- DCHECK(connected_);
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnPathCloseFrame(frame);
- }
- DVLOG(1) << ENDPOINT
- << "PATH_CLOSE_FRAME received for path: " << frame.path_id;
- OnPathClosed(frame.path_id);
- return connected_;
-}
-
-void QuicConnection::OnPacketComplete() {
- // Don't do anything if this packet closed the connection.
- if (!connected_) {
- ClearLastFrames();
- return;
- }
-
- DVLOG(1) << ENDPOINT << "Got packet " << last_header_.packet_number << " for "
- << last_header_.public_header.connection_id;
-
- // An ack will be sent if a missing retransmittable packet was received;
- const bool was_missing =
- should_last_packet_instigate_acks_ &&
- received_packet_manager_.IsMissing(last_header_.packet_number);
-
- // Record received to populate ack info correctly before processing stream
- // frames, since the processing may result in a response packet with a bundled
- // ack.
- received_packet_manager_.RecordPacketReceived(last_size_, last_header_,
- time_of_last_received_packet_);
-
- // Process stop waiting frames here, instead of inline, because the packet
- // needs to be considered 'received' before the entropy can be updated.
- if (last_stop_waiting_frame_.least_unacked > 0) {
- ProcessStopWaitingFrame(last_stop_waiting_frame_);
- if (!connected_) {
- return;
- }
- }
-
- MaybeQueueAck(was_missing);
-
- ClearLastFrames();
- MaybeCloseIfTooManyOutstandingPackets();
-}
-
-void QuicConnection::MaybeQueueAck(bool was_missing) {
- ++num_packets_received_since_last_ack_sent_;
- // Always send an ack every 20 packets in order to allow the peer to discard
- // information from the SentPacketManager and provide an RTT measurement.
- if (num_packets_received_since_last_ack_sent_ >=
- kMaxPacketsReceivedBeforeAckSend) {
- ack_queued_ = true;
- }
-
- // Determine whether the newly received packet was missing before recording
- // the received packet.
- // Ack decimation with reordering relies on the timer to send an ack, but if
- // missing packets we reported in the previous ack, send an ack immediately.
- if (was_missing && (ack_mode_ != ACK_DECIMATION_WITH_REORDERING ||
- last_ack_had_missing_packets_)) {
- ack_queued_ = true;
- }
-
- if (should_last_packet_instigate_acks_ && !ack_queued_) {
- ++num_retransmittable_packets_received_since_last_ack_sent_;
- if (ack_mode_ != TCP_ACKING &&
- last_header_.packet_number > kMinReceivedBeforeAckDecimation) {
- // Ack up to 10 packets at once.
- if (num_retransmittable_packets_received_since_last_ack_sent_ >=
- kMaxRetransmittablePacketsBeforeAck) {
- ack_queued_ = true;
- } else if (!ack_alarm_->IsSet()) {
- // Wait the minimum of a quarter min_rtt and the delayed ack time.
- QuicTime::Delta ack_delay = QuicTime::Delta::Min(
- DelayedAckTime(),
- sent_packet_manager_->GetRttStats()->min_rtt().Multiply(
- ack_decimation_delay_));
- ack_alarm_->Set(clock_->ApproximateNow().Add(ack_delay));
- }
- } else {
- // Ack with a timer or every 2 packets by default.
- if (num_retransmittable_packets_received_since_last_ack_sent_ >=
- kDefaultRetransmittablePacketsBeforeAck) {
- ack_queued_ = true;
- } else if (!ack_alarm_->IsSet()) {
- ack_alarm_->Set(clock_->ApproximateNow().Add(DelayedAckTime()));
- }
- }
-
- // If there are new missing packets to report, send an ack immediately.
- if (received_packet_manager_.HasNewMissingPackets()) {
- if (ack_mode_ == ACK_DECIMATION_WITH_REORDERING) {
- // Wait the minimum of an eighth min_rtt and the existing ack time.
- QuicTime ack_time = clock_->ApproximateNow().Add(
- sent_packet_manager_->GetRttStats()->min_rtt().Multiply(0.125));
- if (!ack_alarm_->IsSet() || ack_alarm_->deadline() > ack_time) {
- ack_alarm_->Cancel();
- ack_alarm_->Set(ack_time);
- }
- } else {
- ack_queued_ = true;
- }
- }
- }
-
- if (ack_queued_) {
- ack_alarm_->Cancel();
- }
-}
-
-void QuicConnection::ClearLastFrames() {
- should_last_packet_instigate_acks_ = false;
- last_stop_waiting_frame_.least_unacked = 0;
-}
-
-void QuicConnection::MaybeCloseIfTooManyOutstandingPackets() {
- if (version() > QUIC_VERSION_33) {
- return;
- }
- // This occurs if we don't discard old packets we've sent fast enough.
- // It's possible largest observed is less than least unacked.
- if (sent_packet_manager_->GetLargestObserved(last_header_.path_id) >
- (sent_packet_manager_->GetLeastUnacked(last_header_.path_id) +
- kMaxTrackedPackets)) {
- CloseConnection(
- QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS,
- StringPrintf("More than %" PRIu64 " outstanding.", kMaxTrackedPackets),
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- }
- // This occurs if there are received packet gaps and the peer does not raise
- // the least unacked fast enough.
- if (received_packet_manager_.NumTrackedPackets() > kMaxTrackedPackets) {
- CloseConnection(
- QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS,
- StringPrintf("More than %" PRIu64 " outstanding.", kMaxTrackedPackets),
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- }
-}
-
-const QuicFrame QuicConnection::GetUpdatedAckFrame() {
- return received_packet_manager_.GetUpdatedAckFrame(clock_->ApproximateNow());
-}
-
-void QuicConnection::PopulateStopWaitingFrame(
- QuicStopWaitingFrame* stop_waiting) {
- stop_waiting->least_unacked = GetLeastUnacked(stop_waiting->path_id);
- if (version() <= QUIC_VERSION_33) {
- stop_waiting->entropy_hash = sent_entropy_manager_.GetCumulativeEntropy(
- stop_waiting->least_unacked - 1);
- }
-}
-
-QuicPacketNumber QuicConnection::GetLeastUnacked(QuicPathId path_id) const {
- return sent_packet_manager_->GetLeastUnacked(path_id);
-}
-
-void QuicConnection::MaybeSendInResponseToPacket() {
- if (!connected_) {
- return;
- }
- // Now that we have received an ack, we might be able to send packets which
- // are queued locally, or drain streams which are blocked.
- if (defer_send_in_response_to_packets_) {
- send_alarm_->Cancel();
- send_alarm_->Set(clock_->ApproximateNow());
- } else {
- WriteAndBundleAcksIfNotBlocked();
- }
-}
-
-void QuicConnection::SendVersionNegotiationPacket() {
- // TODO(alyssar): implement zero server state negotiation.
- pending_version_negotiation_packet_ = true;
- if (writer_->IsWriteBlocked()) {
- visitor_->OnWriteBlocked();
- return;
- }
- DVLOG(1) << ENDPOINT << "Sending version negotiation packet: {"
- << QuicVersionVectorToString(framer_.supported_versions()) << "}";
- std::unique_ptr<QuicEncryptedPacket> version_packet(
- packet_generator_.SerializeVersionNegotiationPacket(
- framer_.supported_versions()));
- WriteResult result = writer_->WritePacket(
- version_packet->data(), version_packet->length(),
- self_address().address(), peer_address(), per_packet_options_);
-
- if (result.status == WRITE_STATUS_ERROR) {
- OnWriteError(result.error_code);
- return;
- }
- if (result.status == WRITE_STATUS_BLOCKED) {
- visitor_->OnWriteBlocked();
- if (writer_->IsWriteBlockedDataBuffered()) {
- pending_version_negotiation_packet_ = false;
- }
- return;
- }
-
- pending_version_negotiation_packet_ = false;
-}
-
-QuicConsumedData QuicConnection::SendStreamData(
- QuicStreamId id,
- QuicIOVector iov,
- QuicStreamOffset offset,
- bool fin,
- QuicAckListenerInterface* listener) {
- if (!fin && iov.total_length == 0) {
- QUIC_BUG << "Attempt to send empty stream frame";
- return QuicConsumedData(0, false);
- }
-
- // Opportunistically bundle an ack with every outgoing packet.
- // Particularly, we want to bundle with handshake packets since we don't know
- // which decrypter will be used on an ack packet following a handshake
- // packet (a handshake packet from client to server could result in a REJ or a
- // SHLO from the server, leading to two different decrypters at the server.)
- ScopedRetransmissionScheduler alarm_delayer(this);
- ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
- // The optimized path may be used for data only packets which fit into a
- // standard buffer and don't need padding.
- if (FLAGS_quic_use_optimized_write_path && id != kCryptoStreamId &&
- !packet_generator_.HasQueuedFrames() &&
- iov.total_length > kMaxPacketSize) {
- // Use the fast path to send full data packets.
- return packet_generator_.ConsumeDataFastPath(id, iov, offset, fin,
- listener);
- }
- return packet_generator_.ConsumeData(id, iov, offset, fin, listener);
-}
-
-void QuicConnection::SendRstStream(QuicStreamId id,
- QuicRstStreamErrorCode error,
- QuicStreamOffset bytes_written) {
- // Opportunistically bundle an ack with this outgoing packet.
- ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
- packet_generator_.AddControlFrame(QuicFrame(new QuicRstStreamFrame(
- id, AdjustErrorForVersion(error, version()), bytes_written)));
-
- if (error == QUIC_STREAM_NO_ERROR && version() > QUIC_VERSION_28) {
- // All data for streams which are reset with QUIC_STREAM_NO_ERROR must
- // be received by the peer.
- return;
- }
-
- sent_packet_manager_->CancelRetransmissionsForStream(id);
- // Remove all queued packets which only contain data for the reset stream.
- QueuedPacketList::iterator packet_iterator = queued_packets_.begin();
- while (packet_iterator != queued_packets_.end()) {
- QuicFrames* retransmittable_frames =
- &packet_iterator->retransmittable_frames;
- if (retransmittable_frames->empty()) {
- ++packet_iterator;
- continue;
- }
- QuicUtils::RemoveFramesForStream(retransmittable_frames, id);
- if (!retransmittable_frames->empty()) {
- ++packet_iterator;
- continue;
- }
- delete[] packet_iterator->encrypted_buffer;
- QuicUtils::ClearSerializedPacket(&(*packet_iterator));
- packet_iterator = queued_packets_.erase(packet_iterator);
- }
-}
-
-void QuicConnection::SendWindowUpdate(QuicStreamId id,
- QuicStreamOffset byte_offset) {
- // Opportunistically bundle an ack with this outgoing packet.
- ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
- packet_generator_.AddControlFrame(
- QuicFrame(new QuicWindowUpdateFrame(id, byte_offset)));
-}
-
-void QuicConnection::SendBlocked(QuicStreamId id) {
- // Opportunistically bundle an ack with this outgoing packet.
- ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
- packet_generator_.AddControlFrame(QuicFrame(new QuicBlockedFrame(id)));
-}
-
-void QuicConnection::SendPathClose(QuicPathId path_id) {
- // Opportunistically bundle an ack with this outgoing packet.
- ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
- packet_generator_.AddControlFrame(QuicFrame(new QuicPathCloseFrame(path_id)));
- OnPathClosed(path_id);
-}
-
-const QuicConnectionStats& QuicConnection::GetStats() {
- const RttStats* rtt_stats = sent_packet_manager_->GetRttStats();
-
- // Update rtt and estimated bandwidth.
- QuicTime::Delta min_rtt = rtt_stats->min_rtt();
- if (min_rtt.IsZero()) {
- // If min RTT has not been set, use initial RTT instead.
- min_rtt = QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
- }
- stats_.min_rtt_us = min_rtt.ToMicroseconds();
-
- QuicTime::Delta srtt = rtt_stats->smoothed_rtt();
- if (srtt.IsZero()) {
- // If SRTT has not been set, use initial RTT instead.
- srtt = QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
- }
- stats_.srtt_us = srtt.ToMicroseconds();
-
- stats_.estimated_bandwidth = sent_packet_manager_->BandwidthEstimate();
- stats_.max_packet_size = packet_generator_.GetCurrentMaxPacketLength();
- stats_.max_received_packet_size = largest_received_packet_size_;
- return stats_;
-}
-
-void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address,
- const IPEndPoint& peer_address,
- const QuicReceivedPacket& packet) {
- if (!connected_) {
- return;
- }
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnPacketReceived(self_address, peer_address, packet);
- }
- last_size_ = packet.length();
- current_packet_data_ = packet.data();
-
- last_packet_destination_address_ = self_address;
- last_packet_source_address_ = peer_address;
- if (!IsInitializedIPEndPoint(self_address_)) {
- self_address_ = last_packet_destination_address_;
- }
- if (!IsInitializedIPEndPoint(peer_address_)) {
- peer_address_ = last_packet_source_address_;
- }
-
- stats_.bytes_received += packet.length();
- ++stats_.packets_received;
-
- time_of_last_received_packet_ = packet.receipt_time();
- DVLOG(1) << ENDPOINT << "time of last received packet: "
- << time_of_last_received_packet_.ToDebuggingValue();
-
- ScopedRetransmissionScheduler alarm_delayer(this);
- if (!framer_.ProcessPacket(packet)) {
- // If we are unable to decrypt this packet, it might be
- // because the CHLO or SHLO packet was lost.
- if (framer_.error() == QUIC_DECRYPTION_FAILURE) {
- if (encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
- undecryptable_packets_.size() < max_undecryptable_packets_) {
- QueueUndecryptablePacket(packet);
- } else if (debug_visitor_ != nullptr) {
- debug_visitor_->OnUndecryptablePacket();
- }
- }
- DVLOG(1) << ENDPOINT << "Unable to process packet. Last packet processed: "
- << last_header_.packet_number;
- current_packet_data_ = nullptr;
- return;
- }
-
- ++stats_.packets_processed;
- if (active_peer_migration_type_ != NO_CHANGE &&
- sent_packet_manager_->GetLargestObserved(last_header_.path_id) >
- highest_packet_sent_before_peer_migration_) {
- OnPeerMigrationValidated(last_header_.path_id);
- }
- MaybeProcessUndecryptablePackets();
- MaybeSendInResponseToPacket();
- SetPingAlarm();
- current_packet_data_ = nullptr;
-}
-
-void QuicConnection::OnCanWrite() {
- DCHECK(!writer_->IsWriteBlocked());
-
- WriteQueuedPackets();
- WritePendingRetransmissions();
-
- // Sending queued packets may have caused the socket to become write blocked,
- // or the congestion manager to prohibit sending. If we've sent everything
- // we had queued and we're still not blocked, let the visitor know it can
- // write more.
- if (!CanWrite(HAS_RETRANSMITTABLE_DATA)) {
- return;
- }
-
- {
- ScopedPacketBundler bundler(this, SEND_ACK_IF_QUEUED);
- visitor_->OnCanWrite();
- visitor_->PostProcessAfterData();
- }
-
- // After the visitor writes, it may have caused the socket to become write
- // blocked or the congestion manager to prohibit sending, so check again.
- if (visitor_->WillingAndAbleToWrite() && !resume_writes_alarm_->IsSet() &&
- CanWrite(HAS_RETRANSMITTABLE_DATA)) {
- // We're not write blocked, but some stream didn't write out all of its
- // bytes. Register for 'immediate' resumption so we'll keep writing after
- // other connections and events have had a chance to use the thread.
- resume_writes_alarm_->Set(clock_->ApproximateNow());
- }
-}
-
-void QuicConnection::WriteIfNotBlocked() {
- if (!writer_->IsWriteBlocked()) {
- OnCanWrite();
- }
-}
-
-void QuicConnection::WriteAndBundleAcksIfNotBlocked() {
- if (!writer_->IsWriteBlocked()) {
- ScopedPacketBundler bundler(this, SEND_ACK_IF_QUEUED);
- OnCanWrite();
- }
-}
-
-bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) {
- if (header.fec_flag) {
- // Drop any FEC packet.
- return false;
- }
-
- if (perspective_ == Perspective::IS_SERVER &&
- IsInitializedIPEndPoint(self_address_) &&
- IsInitializedIPEndPoint(last_packet_destination_address_) &&
- (!(self_address_ == last_packet_destination_address_))) {
- CloseConnection(QUIC_ERROR_MIGRATING_ADDRESS,
- "Self address migration is not supported at the server.",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return false;
- }
-
- if (!Near(header.packet_number, last_header_.packet_number)) {
- DVLOG(1) << ENDPOINT << "Packet " << header.packet_number
- << " out of bounds. Discarding";
- CloseConnection(QUIC_INVALID_PACKET_HEADER, "packet number out of bounds.",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return false;
- }
-
- if (version_negotiation_state_ != NEGOTIATED_VERSION) {
- if (perspective_ == Perspective::IS_SERVER) {
- if (!header.public_header.version_flag) {
- // Packets should have the version flag till version negotiation is
- // done.
- string error_details =
- StringPrintf("%s Packet %" PRIu64
- " without version flag before version negotiated.",
- ENDPOINT, header.packet_number);
- DLOG(WARNING) << error_details;
- CloseConnection(QUIC_INVALID_VERSION, error_details,
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return false;
- } else {
- DCHECK_EQ(1u, header.public_header.versions.size());
- DCHECK_EQ(header.public_header.versions[0], version());
- version_negotiation_state_ = NEGOTIATED_VERSION;
- received_packet_manager_.SetVersion(version());
- visitor_->OnSuccessfulVersionNegotiation(version());
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnSuccessfulVersionNegotiation(version());
- }
- }
- } else {
- DCHECK(!header.public_header.version_flag);
- // If the client gets a packet without the version flag from the server
- // it should stop sending version since the version negotiation is done.
- packet_generator_.StopSendingVersion();
- version_negotiation_state_ = NEGOTIATED_VERSION;
- received_packet_manager_.SetVersion(version());
- visitor_->OnSuccessfulVersionNegotiation(version());
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnSuccessfulVersionNegotiation(version());
- }
- }
- }
-
- DCHECK_EQ(NEGOTIATED_VERSION, version_negotiation_state_);
-
- if (last_size_ > largest_received_packet_size_) {
- largest_received_packet_size_ = last_size_;
- }
-
- if (perspective_ == Perspective::IS_SERVER &&
- encryption_level_ == ENCRYPTION_NONE &&
- last_size_ > packet_generator_.GetCurrentMaxPacketLength()) {
- SetMaxPacketLength(last_size_);
- }
- return true;
-}
-
-void QuicConnection::WriteQueuedPackets() {
- DCHECK(!writer_->IsWriteBlocked());
-
- if (pending_version_negotiation_packet_) {
- SendVersionNegotiationPacket();
- }
-
- QueuedPacketList::iterator packet_iterator = queued_packets_.begin();
- while (packet_iterator != queued_packets_.end() &&
- WritePacket(&(*packet_iterator))) {
- delete[] packet_iterator->encrypted_buffer;
- QuicUtils::ClearSerializedPacket(&(*packet_iterator));
- packet_iterator = queued_packets_.erase(packet_iterator);
- }
-}
-
-void QuicConnection::WritePendingRetransmissions() {
- // Keep writing as long as there's a pending retransmission which can be
- // written.
- while (sent_packet_manager_->HasPendingRetransmissions()) {
- const PendingRetransmission pending =
- sent_packet_manager_->NextPendingRetransmission();
- if (!CanWrite(HAS_RETRANSMITTABLE_DATA)) {
- break;
- }
-
- // Re-packetize the frames with a new packet number for retransmission.
- // Retransmitted packets use the same packet number length as the
- // original.
- // Flush the packet generator before making a new packet.
- // TODO(ianswett): Implement ReserializeAllFrames as a separate path that
- // does not require the creator to be flushed.
- packet_generator_.FlushAllQueuedFrames();
- char buffer[kMaxPacketSize];
- packet_generator_.ReserializeAllFrames(pending, buffer, kMaxPacketSize);
- }
-}
-
-void QuicConnection::RetransmitUnackedPackets(
- TransmissionType retransmission_type) {
- sent_packet_manager_->RetransmitUnackedPackets(retransmission_type);
-
- WriteIfNotBlocked();
-}
-
-void QuicConnection::NeuterUnencryptedPackets() {
- sent_packet_manager_->NeuterUnencryptedPackets();
- // This may have changed the retransmission timer, so re-arm it.
- SetRetransmissionAlarm();
-}
-
-bool QuicConnection::ShouldGeneratePacket(
- HasRetransmittableData retransmittable,
- IsHandshake handshake) {
- // We should serialize handshake packets immediately to ensure that they
- // end up sent at the right encryption level.
- if (handshake == IS_HANDSHAKE) {
- return true;
- }
-
- return CanWrite(retransmittable);
-}
-
-bool QuicConnection::CanWrite(HasRetransmittableData retransmittable) {
- if (!connected_) {
- return false;
- }
-
- if (writer_->IsWriteBlocked()) {
- visitor_->OnWriteBlocked();
- return false;
- }
-
- // Allow acks to be sent immediately.
- // TODO(ianswett): Remove retransmittable from
- // SendAlgorithmInterface::TimeUntilSend.
- if (retransmittable == NO_RETRANSMITTABLE_DATA) {
- return true;
- }
- // If the send alarm is set, wait for it to fire.
- if (send_alarm_->IsSet()) {
- return false;
- }
-
- // TODO(fayang): If delay is not infinite, the next packet will be created and
- // sent on path_id.
- QuicPathId path_id = kInvalidPathId;
- QuicTime now = clock_->Now();
- QuicTime::Delta delay =
- sent_packet_manager_->TimeUntilSend(now, retransmittable, &path_id);
- if (delay.IsInfinite()) {
- DCHECK_EQ(kInvalidPathId, path_id);
- send_alarm_->Cancel();
- return false;
- }
-
- DCHECK_NE(kInvalidPathId, path_id);
- // If the scheduler requires a delay, then we can not send this packet now.
- if (!delay.IsZero()) {
- send_alarm_->Update(now.Add(delay), QuicTime::Delta::FromMilliseconds(1));
- DVLOG(1) << ENDPOINT << "Delaying sending " << delay.ToMilliseconds()
- << "ms";
- return false;
- }
- return true;
-}
-
-bool QuicConnection::WritePacket(SerializedPacket* packet) {
- if (packet->packet_number <
- sent_packet_manager_->GetLargestSentPacket(packet->path_id)) {
- QUIC_BUG << "Attempt to write packet:" << packet->packet_number << " after:"
- << sent_packet_manager_->GetLargestSentPacket(packet->path_id);
- CloseConnection(QUIC_INTERNAL_ERROR, "Packet written out of order.",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return true;
- }
- if (ShouldDiscardPacket(*packet)) {
- ++stats_.packets_discarded;
- return true;
- }
- // Termination packets are encrypted and saved, so don't exit early.
- const bool is_termination_packet = IsTerminationPacket(*packet);
- if (writer_->IsWriteBlocked() && !is_termination_packet) {
- return false;
- }
-
- QuicPacketNumber packet_number = packet->packet_number;
- DCHECK_LE(packet_number_of_last_sent_packet_, packet_number);
- packet_number_of_last_sent_packet_ = packet_number;
-
- QuicPacketLength encrypted_length = packet->encrypted_length;
- // Termination packets are eventually owned by TimeWaitListManager.
- // Others are deleted at the end of this call.
- if (is_termination_packet) {
- if (termination_packets_.get() == nullptr) {
- termination_packets_.reset(
- new std::vector<std::unique_ptr<QuicEncryptedPacket>>);
- }
- // Copy the buffer so it's owned in the future.
- char* buffer_copy = QuicUtils::CopyBuffer(*packet);
- termination_packets_->push_back(std::unique_ptr<QuicEncryptedPacket>(
- new QuicEncryptedPacket(buffer_copy, encrypted_length, true)));
- // This assures we won't try to write *forced* packets when blocked.
- // Return true to stop processing.
- if (writer_->IsWriteBlocked()) {
- visitor_->OnWriteBlocked();
- return true;
- }
- }
-
- DCHECK_LE(encrypted_length, kMaxPacketSize);
- DCHECK_LE(encrypted_length, packet_generator_.GetCurrentMaxPacketLength());
- DVLOG(1) << ENDPOINT << "Sending packet " << packet_number << " : "
- << (IsRetransmittable(*packet) == HAS_RETRANSMITTABLE_DATA
- ? "data bearing "
- : " ack only ")
- << ", encryption level: "
- << QuicUtils::EncryptionLevelToString(packet->encryption_level)
- << ", encrypted length:" << encrypted_length;
- DVLOG(2) << ENDPOINT << "packet(" << packet_number << "): " << std::endl
- << QuicUtils::StringToHexASCIIDump(
- StringPiece(packet->encrypted_buffer, encrypted_length));
-
- // Measure the RTT from before the write begins to avoid underestimating the
- // min_rtt_, especially in cases where the thread blocks or gets swapped out
- // during the WritePacket below.
- QuicTime packet_send_time = clock_->Now();
- WriteResult result = writer_->WritePacket(
- packet->encrypted_buffer, encrypted_length, self_address().address(),
- peer_address(), per_packet_options_);
- if (result.error_code == ERR_IO_PENDING) {
- DCHECK_EQ(WRITE_STATUS_BLOCKED, result.status);
- }
-
- if (result.status == WRITE_STATUS_BLOCKED) {
- visitor_->OnWriteBlocked();
- // If the socket buffers the the data, then the packet should not
- // be queued and sent again, which would result in an unnecessary
- // duplicate packet being sent. The helper must call OnCanWrite
- // when the write completes, and OnWriteError if an error occurs.
- if (!writer_->IsWriteBlockedDataBuffered()) {
- return false;
- }
- }
- if (result.status != WRITE_STATUS_ERROR && debug_visitor_ != nullptr) {
- // Pass the write result to the visitor.
- debug_visitor_->OnPacketSent(*packet, packet->original_path_id,
- packet->original_packet_number,
- packet->transmission_type, packet_send_time);
- }
- if (packet->transmission_type == NOT_RETRANSMISSION) {
- time_of_last_sent_new_packet_ = packet_send_time;
- if (IsRetransmittable(*packet) == HAS_RETRANSMITTABLE_DATA &&
- last_send_for_timeout_ <= time_of_last_received_packet_) {
- last_send_for_timeout_ = packet_send_time;
- }
- }
- SetPingAlarm();
- MaybeSetMtuAlarm();
- DVLOG(1) << ENDPOINT << "time we began writing last sent packet: "
- << packet_send_time.ToDebuggingValue();
-
- if (!FLAGS_quic_simple_packet_number_length) {
- // TODO(ianswett): Change the packet number length and other packet creator
- // options by a more explicit API than setting a struct value directly,
- // perhaps via the NetworkChangeVisitor.
- if (FLAGS_quic_least_unacked_packet_number_length) {
- packet_generator_.UpdateSequenceNumberLength(
- sent_packet_manager_->GetLeastUnacked(packet->path_id),
- sent_packet_manager_->EstimateMaxPacketsInFlight(
- max_packet_length()));
- } else {
- packet_generator_.UpdateSequenceNumberLength(
- sent_packet_manager_->GetLeastPacketAwaitedByPeer(packet->path_id),
- sent_packet_manager_->EstimateMaxPacketsInFlight(
- max_packet_length()));
- }
- }
-
- bool reset_retransmission_alarm = sent_packet_manager_->OnPacketSent(
- packet, packet->original_path_id, packet->original_packet_number,
- packet_send_time, packet->transmission_type, IsRetransmittable(*packet));
-
- if (reset_retransmission_alarm || !retransmission_alarm_->IsSet()) {
- SetRetransmissionAlarm();
- }
-
- if (FLAGS_quic_simple_packet_number_length) {
- // The packet number length must be updated after OnPacketSent, because it
- // may change the packet number length in packet.
- if (FLAGS_quic_least_unacked_packet_number_length) {
- packet_generator_.UpdateSequenceNumberLength(
- sent_packet_manager_->GetLeastUnacked(packet->path_id),
- sent_packet_manager_->EstimateMaxPacketsInFlight(
- max_packet_length()));
- } else {
- packet_generator_.UpdateSequenceNumberLength(
- sent_packet_manager_->GetLeastPacketAwaitedByPeer(packet->path_id),
- sent_packet_manager_->EstimateMaxPacketsInFlight(
- max_packet_length()));
- }
- }
-
- stats_.bytes_sent += result.bytes_written;
- ++stats_.packets_sent;
- if (packet->transmission_type != NOT_RETRANSMISSION) {
- stats_.bytes_retransmitted += result.bytes_written;
- ++stats_.packets_retransmitted;
- }
-
- if (result.status == WRITE_STATUS_ERROR) {
- OnWriteError(result.error_code);
- DLOG(ERROR) << ENDPOINT << "failed writing " << encrypted_length
- << " bytes "
- << " from host " << (self_address().address().empty()
- ? " empty address "
- : self_address().ToStringWithoutPort())
- << " to address " << peer_address().ToString();
- return false;
- }
-
- return true;
-}
-
-bool QuicConnection::ShouldDiscardPacket(const SerializedPacket& packet) {
- if (!connected_) {
- DVLOG(1) << ENDPOINT << "Not sending packet as connection is disconnected.";
- return true;
- }
-
- QuicPacketNumber packet_number = packet.packet_number;
- if (encryption_level_ == ENCRYPTION_FORWARD_SECURE &&
- packet.encryption_level == ENCRYPTION_NONE) {
- // Drop packets that are NULL encrypted since the peer won't accept them
- // anymore.
- DVLOG(1) << ENDPOINT << "Dropping NULL encrypted packet: " << packet_number
- << " since the connection is forward secure.";
- return true;
- }
-
- // TODO(fayang): Remove IsUnacked and HasRetransmittableFrames from
- // QuicSentPacketManagerInterface when deprecating
- // gfe2_reloadable_flag_quic_always_write_queued_retransmissions.
- if (FLAGS_quic_always_write_queued_retransmissions) {
- return false;
- }
-
- // If a retransmission has been acked before sending, don't send it.
- // This occurs if a packet gets serialized, queued, then discarded.
- if (packet.transmission_type != NOT_RETRANSMISSION &&
- (!sent_packet_manager_->IsUnacked(packet.original_path_id,
- packet.original_packet_number) ||
- !sent_packet_manager_->HasRetransmittableFrames(
- packet.original_path_id, packet.original_packet_number))) {
- DVLOG(1) << ENDPOINT << "Dropping unacked packet: " << packet_number
- << " A previous transmission was acked while write blocked.";
- return true;
- }
-
- return false;
-}
-
-void QuicConnection::OnWriteError(int error_code) {
- const string error_details = "Write failed with error: " +
- base::IntToString(error_code) + " (" +
- ErrorToString(error_code) + ")";
- DVLOG(1) << ENDPOINT << error_details;
- // We can't send an error as the socket is presumably borked.
- TearDownLocalConnectionState(QUIC_PACKET_WRITE_ERROR, error_details,
- ConnectionCloseSource::FROM_SELF);
-}
-
-void QuicConnection::OnSerializedPacket(SerializedPacket* serialized_packet) {
- DCHECK_NE(kInvalidPathId, serialized_packet->path_id);
- if (serialized_packet->encrypted_buffer == nullptr) {
- // We failed to serialize the packet, so close the connection.
- // TearDownLocalConnectionState does not send close packet, so no infinite
- // loop here.
- // TODO(ianswett): This is actually an internal error, not an
- // encryption failure.
- TearDownLocalConnectionState(
- QUIC_ENCRYPTION_FAILURE,
- "Serialized packet does not have an encrypted buffer.",
- ConnectionCloseSource::FROM_SELF);
- return;
- }
- SendOrQueuePacket(serialized_packet);
-}
-
-void QuicConnection::OnUnrecoverableError(QuicErrorCode error,
- const string& error_details,
- ConnectionCloseSource source) {
- // The packet creator or generator encountered an unrecoverable error: tear
- // down local connection state immediately.
- TearDownLocalConnectionState(error, error_details, source);
-}
-
-void QuicConnection::OnCongestionChange() {
- visitor_->OnCongestionWindowChange(clock_->ApproximateNow());
-
- // Uses the connection's smoothed RTT. If zero, uses initial_rtt.
- QuicTime::Delta rtt = sent_packet_manager_->GetRttStats()->smoothed_rtt();
- if (rtt.IsZero()) {
- rtt = QuicTime::Delta::FromMicroseconds(
- sent_packet_manager_->GetRttStats()->initial_rtt_us());
- }
-
- if (debug_visitor_)
- debug_visitor_->OnRttChanged(rtt);
-}
-
-void QuicConnection::OnPathDegrading() {
- visitor_->OnPathDegrading();
-}
-
-void QuicConnection::OnPathMtuIncreased(QuicPacketLength packet_size) {
- DCHECK(FLAGS_quic_no_mtu_discovery_ack_listener);
- if (packet_size > max_packet_length()) {
- SetMaxPacketLength(packet_size);
- }
-}
-
-void QuicConnection::OnHandshakeComplete() {
- sent_packet_manager_->SetHandshakeConfirmed();
- // The client should immediately ack the SHLO to confirm the handshake is
- // complete with the server.
- if (perspective_ == Perspective::IS_CLIENT && !ack_queued_ &&
- ack_frame_updated()) {
- ack_alarm_->Cancel();
- ack_alarm_->Set(clock_->ApproximateNow());
- }
-}
-
-void QuicConnection::SendOrQueuePacket(SerializedPacket* packet) {
- // The caller of this function is responsible for checking CanWrite().
- if (packet->encrypted_buffer == nullptr) {
- QUIC_BUG << "packet.encrypted_buffer == nullptr in to SendOrQueuePacket";
- return;
- }
- if (version() <= QUIC_VERSION_33) {
- sent_entropy_manager_.RecordPacketEntropyHash(packet->packet_number,
- packet->entropy_hash);
- }
- // If there are already queued packets, queue this one immediately to ensure
- // it's written in sequence number order.
- if (!queued_packets_.empty() || !WritePacket(packet)) {
- // Take ownership of the underlying encrypted packet.
- packet->encrypted_buffer = QuicUtils::CopyBuffer(*packet);
- queued_packets_.push_back(*packet);
- packet->retransmittable_frames.clear();
- }
-
- QuicUtils::ClearSerializedPacket(packet);
- // If a forward-secure encrypter is available but is not being used and the
- // next packet number is the first packet which requires
- // forward security, start using the forward-secure encrypter.
- if (encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
- has_forward_secure_encrypter_ &&
- packet->packet_number >= first_required_forward_secure_packet_ - 1) {
- SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
- }
-}
-
-void QuicConnection::OnPingTimeout() {
- if (!retransmission_alarm_->IsSet()) {
- SendPing();
- }
-}
-
-void QuicConnection::SendPing() {
- ScopedPacketBundler bundler(this, SEND_ACK_IF_QUEUED);
- packet_generator_.AddControlFrame(QuicFrame(QuicPingFrame()));
- // Send PING frame immediately, without checking for congestion window bounds.
- packet_generator_.FlushAllQueuedFrames();
-}
-
-void QuicConnection::SendAck() {
- ack_alarm_->Cancel();
- ack_queued_ = false;
- stop_waiting_count_ = 0;
- num_retransmittable_packets_received_since_last_ack_sent_ = 0;
- last_ack_had_missing_packets_ = received_packet_manager_.HasMissingPackets();
- num_packets_received_since_last_ack_sent_ = 0;
-
- packet_generator_.SetShouldSendAck(true);
-}
-
-void QuicConnection::OnRetransmissionTimeout() {
- DCHECK(sent_packet_manager_->HasUnackedPackets());
-
- if (close_connection_after_five_rtos_ &&
- sent_packet_manager_->GetConsecutiveRtoCount() >= 4) {
- // Close on the 5th consecutive RTO, so after 4 previous RTOs have occurred.
- CloseConnection(QUIC_TOO_MANY_RTOS, "5 consecutive retransmission timeouts",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
-
- sent_packet_manager_->OnRetransmissionTimeout();
- WriteIfNotBlocked();
-
- // A write failure can result in the connection being closed, don't attempt to
- // write further packets, or to set alarms.
- if (!connected_) {
- return;
- }
-
- // In the TLP case, the SentPacketManager gives the connection the opportunity
- // to send new data before retransmitting.
- if (sent_packet_manager_->MaybeRetransmitTailLossProbe()) {
- // Send the pending retransmission now that it's been queued.
- WriteIfNotBlocked();
- }
-
- // Ensure the retransmission alarm is always set if there are unacked packets
- // and nothing waiting to be sent.
- // This happens if the loss algorithm invokes a timer based loss, but the
- // packet doesn't need to be retransmitted.
- if (!HasQueuedData() && !retransmission_alarm_->IsSet()) {
- SetRetransmissionAlarm();
- }
-}
-
-void QuicConnection::SetEncrypter(EncryptionLevel level,
- QuicEncrypter* encrypter) {
- packet_generator_.SetEncrypter(level, encrypter);
- if (level == ENCRYPTION_FORWARD_SECURE) {
- has_forward_secure_encrypter_ = true;
- first_required_forward_secure_packet_ =
- packet_number_of_last_sent_packet_ +
- // 3 times the current congestion window (in slow start) should cover
- // about two full round trips worth of packets, which should be
- // sufficient.
- 3 *
- sent_packet_manager_->EstimateMaxPacketsInFlight(
- max_packet_length());
- }
-}
-
-void QuicConnection::SetDiversificationNonce(const DiversificationNonce nonce) {
- DCHECK_EQ(Perspective::IS_SERVER, perspective_);
- packet_generator_.SetDiversificationNonce(nonce);
-}
-
-void QuicConnection::SetDefaultEncryptionLevel(EncryptionLevel level) {
- encryption_level_ = level;
- packet_generator_.set_encryption_level(level);
-}
-
-void QuicConnection::SetDecrypter(EncryptionLevel level,
- QuicDecrypter* decrypter) {
- framer_.SetDecrypter(level, decrypter);
-}
-
-void QuicConnection::SetAlternativeDecrypter(EncryptionLevel level,
- QuicDecrypter* decrypter,
- bool latch_once_used) {
- framer_.SetAlternativeDecrypter(level, decrypter, latch_once_used);
-}
-
-const QuicDecrypter* QuicConnection::decrypter() const {
- return framer_.decrypter();
-}
-
-const QuicDecrypter* QuicConnection::alternative_decrypter() const {
- return framer_.alternative_decrypter();
-}
-
-void QuicConnection::QueueUndecryptablePacket(
- const QuicEncryptedPacket& packet) {
- DVLOG(1) << ENDPOINT << "Queueing undecryptable packet.";
- undecryptable_packets_.push_back(packet.Clone());
-}
-
-void QuicConnection::MaybeProcessUndecryptablePackets() {
- if (undecryptable_packets_.empty() || encryption_level_ == ENCRYPTION_NONE) {
- return;
- }
-
- while (connected_ && !undecryptable_packets_.empty()) {
- DVLOG(1) << ENDPOINT << "Attempting to process undecryptable packet";
- QuicEncryptedPacket* packet = undecryptable_packets_.front();
- if (!framer_.ProcessPacket(*packet) &&
- framer_.error() == QUIC_DECRYPTION_FAILURE) {
- DVLOG(1) << ENDPOINT << "Unable to process undecryptable packet...";
- break;
- }
- DVLOG(1) << ENDPOINT << "Processed undecryptable packet!";
- ++stats_.packets_processed;
- delete packet;
- undecryptable_packets_.pop_front();
- }
-
- // Once forward secure encryption is in use, there will be no
- // new keys installed and hence any undecryptable packets will
- // never be able to be decrypted.
- if (encryption_level_ == ENCRYPTION_FORWARD_SECURE) {
- if (debug_visitor_ != nullptr) {
- // TODO(rtenneti): perhaps more efficient to pass the number of
- // undecryptable packets as the argument to OnUndecryptablePacket so that
- // we just need to call OnUndecryptablePacket once?
- for (size_t i = 0; i < undecryptable_packets_.size(); ++i) {
- debug_visitor_->OnUndecryptablePacket();
- }
- }
- STLDeleteElements(&undecryptable_packets_);
- }
-}
-
-void QuicConnection::CloseConnection(
- QuicErrorCode error,
- const string& error_details,
- ConnectionCloseBehavior connection_close_behavior) {
- DCHECK(!error_details.empty());
- if (!connected_) {
- DVLOG(1) << "Connection is already closed.";
- return;
- }
-
- DVLOG(1) << ENDPOINT << "Closing connection: " << connection_id()
- << ", with error: " << QuicUtils::ErrorToString(error) << " ("
- << error << "), and details: " << error_details;
-
- if (connection_close_behavior ==
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET) {
- SendConnectionClosePacket(error, error_details);
- }
-
- TearDownLocalConnectionState(error, error_details,
- ConnectionCloseSource::FROM_SELF);
-}
-
-void QuicConnection::SendConnectionClosePacket(QuicErrorCode error,
- const string& details) {
- DVLOG(1) << ENDPOINT << "Sending connection close packet.";
- ClearQueuedPackets();
- ScopedPacketBundler ack_bundler(this, SEND_ACK);
- QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame();
- frame->error_code = error;
- frame->error_details = details;
- packet_generator_.AddControlFrame(QuicFrame(frame));
- packet_generator_.FlushAllQueuedFrames();
-}
-
-void QuicConnection::TearDownLocalConnectionState(
- QuicErrorCode error,
- const string& error_details,
- ConnectionCloseSource source) {
- if (!connected_) {
- DVLOG(1) << "Connection is already closed.";
- return;
- }
- connected_ = false;
- DCHECK(visitor_ != nullptr);
- // TODO(rtenneti): crbug.com/546668. A temporary fix. Added a check for null
- // |visitor_| to fix crash bug. Delete |visitor_| check and histogram after
- // fix is merged.
- if (visitor_ != nullptr) {
- visitor_->OnConnectionClosed(error, error_details, source);
- } else {
- UMA_HISTOGRAM_BOOLEAN("Net.QuicCloseConnection.NullVisitor", true);
- }
- if (debug_visitor_ != nullptr) {
- debug_visitor_->OnConnectionClosed(error, error_details, source);
- }
- // Cancel the alarms so they don't trigger any action now that the
- // connection is closed.
- CancelAllAlarms();
-}
-
-void QuicConnection::CancelAllAlarms() {
- ack_alarm_->Cancel();
- ping_alarm_->Cancel();
- resume_writes_alarm_->Cancel();
- retransmission_alarm_->Cancel();
- send_alarm_->Cancel();
- timeout_alarm_->Cancel();
- mtu_discovery_alarm_->Cancel();
-}
-
-void QuicConnection::SendGoAway(QuicErrorCode error,
- QuicStreamId last_good_stream_id,
- const string& reason) {
- if (goaway_sent_) {
- return;
- }
- goaway_sent_ = true;
-
- DVLOG(1) << ENDPOINT << "Going away with error "
- << QuicUtils::ErrorToString(error) << " (" << error << ")";
-
- // Opportunistically bundle an ack with this outgoing packet.
- ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING);
- packet_generator_.AddControlFrame(
- QuicFrame(new QuicGoAwayFrame(error, last_good_stream_id, reason)));
-}
-
-QuicByteCount QuicConnection::max_packet_length() const {
- return packet_generator_.GetCurrentMaxPacketLength();
-}
-
-void QuicConnection::SetMaxPacketLength(QuicByteCount length) {
- return packet_generator_.SetMaxPacketLength(LimitMaxPacketSize(length));
-}
-
-bool QuicConnection::HasQueuedData() const {
- return pending_version_negotiation_packet_ || !queued_packets_.empty() ||
- packet_generator_.HasQueuedFrames();
-}
-
-void QuicConnection::EnableSavingCryptoPackets() {
- save_crypto_packets_as_termination_packets_ = true;
-}
-
-bool QuicConnection::CanWriteStreamData() {
- // Don't write stream data if there are negotiation or queued data packets
- // to send. Otherwise, continue and bundle as many frames as possible.
- if (pending_version_negotiation_packet_ || !queued_packets_.empty()) {
- return false;
- }
-
- IsHandshake pending_handshake =
- visitor_->HasPendingHandshake() ? IS_HANDSHAKE : NOT_HANDSHAKE;
- // Sending queued packets may have caused the socket to become write blocked,
- // or the congestion manager to prohibit sending. If we've sent everything
- // we had queued and we're still not blocked, let the visitor know it can
- // write more.
- return ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, pending_handshake);
-}
-
-void QuicConnection::SetNetworkTimeouts(QuicTime::Delta handshake_timeout,
- QuicTime::Delta idle_timeout) {
- QUIC_BUG_IF(idle_timeout > handshake_timeout)
- << "idle_timeout:" << idle_timeout.ToMilliseconds()
- << " handshake_timeout:" << handshake_timeout.ToMilliseconds();
- // Adjust the idle timeout on client and server to prevent clients from
- // sending requests to servers which have already closed the connection.
- if (perspective_ == Perspective::IS_SERVER) {
- idle_timeout = idle_timeout.Add(QuicTime::Delta::FromSeconds(3));
- } else if (idle_timeout > QuicTime::Delta::FromSeconds(1)) {
- idle_timeout = idle_timeout.Subtract(QuicTime::Delta::FromSeconds(1));
- }
- handshake_timeout_ = handshake_timeout;
- idle_network_timeout_ = idle_timeout;
-
- SetTimeoutAlarm();
-}
-
-void QuicConnection::CheckForTimeout() {
- QuicTime now = clock_->ApproximateNow();
- QuicTime time_of_last_packet =
- max(time_of_last_received_packet_, last_send_for_timeout_);
-
- // |delta| can be < 0 as |now| is approximate time but |time_of_last_packet|
- // is accurate time. However, this should not change the behavior of
- // timeout handling.
- QuicTime::Delta idle_duration = now.Subtract(time_of_last_packet);
- DVLOG(1) << ENDPOINT << "last packet "
- << time_of_last_packet.ToDebuggingValue()
- << " now:" << now.ToDebuggingValue()
- << " idle_duration:" << idle_duration.ToMicroseconds()
- << " idle_network_timeout: "
- << idle_network_timeout_.ToMicroseconds();
- if (idle_duration >= idle_network_timeout_) {
- const string error_details = "No recent network activity.";
- DVLOG(1) << ENDPOINT << error_details;
- CloseConnection(QUIC_NETWORK_IDLE_TIMEOUT, error_details,
- idle_timeout_connection_close_behavior_);
- return;
- }
-
- if (!handshake_timeout_.IsInfinite()) {
- QuicTime::Delta connected_duration =
- now.Subtract(stats_.connection_creation_time);
- DVLOG(1) << ENDPOINT
- << "connection time: " << connected_duration.ToMicroseconds()
- << " handshake timeout: " << handshake_timeout_.ToMicroseconds();
- if (connected_duration >= handshake_timeout_) {
- const string error_details = "Handshake timeout expired.";
- DVLOG(1) << ENDPOINT << error_details;
- CloseConnection(QUIC_HANDSHAKE_TIMEOUT, error_details,
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
- }
-
- SetTimeoutAlarm();
-}
-
-void QuicConnection::SetTimeoutAlarm() {
- QuicTime time_of_last_packet =
- max(time_of_last_received_packet_, time_of_last_sent_new_packet_);
-
- QuicTime deadline = time_of_last_packet.Add(idle_network_timeout_);
- if (!handshake_timeout_.IsInfinite()) {
- deadline =
- min(deadline, stats_.connection_creation_time.Add(handshake_timeout_));
- }
-
- timeout_alarm_->Cancel();
- timeout_alarm_->Set(deadline);
-}
-
-void QuicConnection::SetPingAlarm() {
- if (perspective_ == Perspective::IS_SERVER) {
- // Only clients send pings.
- return;
- }
- if (!visitor_->HasOpenDynamicStreams()) {
- ping_alarm_->Cancel();
- // Don't send a ping unless there are open streams.
- return;
- }
- QuicTime::Delta ping_timeout = QuicTime::Delta::FromSeconds(kPingTimeoutSecs);
- ping_alarm_->Update(clock_->ApproximateNow().Add(ping_timeout),
- QuicTime::Delta::FromSeconds(1));
-}
-
-void QuicConnection::SetRetransmissionAlarm() {
- if (delay_setting_retransmission_alarm_) {
- pending_retransmission_alarm_ = true;
- return;
- }
- QuicTime retransmission_time = sent_packet_manager_->GetRetransmissionTime();
- retransmission_alarm_->Update(retransmission_time,
- QuicTime::Delta::FromMilliseconds(1));
-}
-
-void QuicConnection::MaybeSetMtuAlarm() {
- // Do not set the alarm if the target size is less than the current size.
- // This covers the case when |mtu_discovery_target_| is at its default value,
- // zero.
- if (mtu_discovery_target_ <= max_packet_length()) {
- return;
- }
-
- if (mtu_probe_count_ >= kMtuDiscoveryAttempts) {
- return;
- }
-
- if (mtu_discovery_alarm_->IsSet()) {
- return;
- }
-
- if (packet_number_of_last_sent_packet_ >= next_mtu_probe_at_) {
- // Use an alarm to send the MTU probe to ensure that no ScopedPacketBundlers
- // are active.
- mtu_discovery_alarm_->Set(clock_->ApproximateNow());
- }
-}
-
-QuicConnection::ScopedPacketBundler::ScopedPacketBundler(
- QuicConnection* connection,
- AckBundling ack_mode)
- : connection_(connection),
- already_in_batch_mode_(connection != nullptr &&
- connection->packet_generator_.InBatchMode()) {
- if (connection_ == nullptr) {
- return;
- }
- // Move generator into batch mode. If caller wants us to include an ack,
- // check the delayed-ack timer to see if there's ack info to be sent.
- if (!already_in_batch_mode_) {
- DVLOG(1) << "Entering Batch Mode.";
- connection_->packet_generator_.StartBatchOperations();
- }
- if (ShouldSendAck(ack_mode)) {
- DVLOG(1) << "Bundling ack with outgoing packet.";
- DCHECK(ack_mode == SEND_ACK || connection_->ack_frame_updated() ||
- connection_->stop_waiting_count_ > 1);
- connection_->SendAck();
- }
-}
-
-bool QuicConnection::ScopedPacketBundler::ShouldSendAck(
- AckBundling ack_mode) const {
- switch (ack_mode) {
- case SEND_ACK:
- return true;
- case SEND_ACK_IF_QUEUED:
- return connection_->ack_queued();
- case SEND_ACK_IF_PENDING:
- return connection_->ack_alarm_->IsSet() ||
- connection_->stop_waiting_count_ > 1;
- default:
- QUIC_BUG << "Unsupported ack_mode.";
- return true;
- }
-}
-
-QuicConnection::ScopedPacketBundler::~ScopedPacketBundler() {
- if (connection_ == nullptr) {
- return;
- }
- // If we changed the generator's batch state, restore original batch state.
- if (!already_in_batch_mode_) {
- DVLOG(1) << "Leaving Batch Mode.";
- connection_->packet_generator_.FinishBatchOperations();
- }
- DCHECK_EQ(already_in_batch_mode_,
- connection_->packet_generator_.InBatchMode());
-}
-
-QuicConnection::ScopedRetransmissionScheduler::ScopedRetransmissionScheduler(
- QuicConnection* connection)
- : connection_(connection),
- already_delayed_(connection_->delay_setting_retransmission_alarm_) {
- connection_->delay_setting_retransmission_alarm_ = true;
-}
-
-QuicConnection::ScopedRetransmissionScheduler::
- ~ScopedRetransmissionScheduler() {
- if (already_delayed_) {
- return;
- }
- connection_->delay_setting_retransmission_alarm_ = false;
- if (connection_->pending_retransmission_alarm_) {
- connection_->SetRetransmissionAlarm();
- connection_->pending_retransmission_alarm_ = false;
- }
-}
-
-HasRetransmittableData QuicConnection::IsRetransmittable(
- const SerializedPacket& packet) {
- // Retransmitted packets retransmittable frames are owned by the unacked
- // packet map, but are not present in the serialized packet.
- if (packet.transmission_type != NOT_RETRANSMISSION ||
- !packet.retransmittable_frames.empty()) {
- return HAS_RETRANSMITTABLE_DATA;
- } else {
- return NO_RETRANSMITTABLE_DATA;
- }
-}
-
-bool QuicConnection::IsTerminationPacket(const SerializedPacket& packet) {
- if (packet.retransmittable_frames.empty()) {
- return false;
- }
- for (const QuicFrame& frame : packet.retransmittable_frames) {
- if (frame.type == CONNECTION_CLOSE_FRAME) {
- return true;
- }
- if (save_crypto_packets_as_termination_packets_ &&
- frame.type == STREAM_FRAME &&
- frame.stream_frame->stream_id == kCryptoStreamId) {
- return true;
- }
- }
- return false;
-}
-
-void QuicConnection::SetMtuDiscoveryTarget(QuicByteCount target) {
- mtu_discovery_target_ = LimitMaxPacketSize(target);
-}
-
-QuicByteCount QuicConnection::LimitMaxPacketSize(
- QuicByteCount suggested_max_packet_size) {
- if (peer_address_.address().empty()) {
- QUIC_BUG << "Attempted to use a connection without a valid peer address";
- return suggested_max_packet_size;
- }
-
- const QuicByteCount writer_limit = writer_->GetMaxPacketSize(peer_address());
-
- QuicByteCount max_packet_size = suggested_max_packet_size;
- if (max_packet_size > writer_limit) {
- max_packet_size = writer_limit;
- }
- if (max_packet_size > kMaxPacketSize) {
- max_packet_size = kMaxPacketSize;
- }
- return max_packet_size;
-}
-
-void QuicConnection::SendMtuDiscoveryPacket(QuicByteCount target_mtu) {
- // Currently, this limit is ensured by the caller.
- DCHECK_EQ(target_mtu, LimitMaxPacketSize(target_mtu));
-
- // Create a listener for the new probe. The ownership of the listener is
- // transferred to the AckNotifierManager. The notifier will get destroyed
- // before the connection (because it's stored in one of the connection's
- // subfields), hence |this| pointer is guaranteed to stay valid at all times.
- scoped_refptr<MtuDiscoveryAckListener> last_mtu_discovery_ack_listener(
- new MtuDiscoveryAckListener(this, target_mtu));
-
- // Send the probe.
- packet_generator_.GenerateMtuDiscoveryPacket(
- target_mtu, FLAGS_quic_no_mtu_discovery_ack_listener
- ? nullptr
- : last_mtu_discovery_ack_listener.get());
-}
-
-void QuicConnection::DiscoverMtu() {
- DCHECK(!mtu_discovery_alarm_->IsSet());
-
- // Check if the MTU has been already increased.
- if (mtu_discovery_target_ <= max_packet_length()) {
- return;
- }
-
- // Calculate the packet number of the next probe *before* sending the current
- // one. Otherwise, when SendMtuDiscoveryPacket() is called,
- // MaybeSetMtuAlarm() will not realize that the probe has been just sent, and
- // will reschedule this probe again.
- packets_between_mtu_probes_ *= 2;
- next_mtu_probe_at_ =
- packet_number_of_last_sent_packet_ + packets_between_mtu_probes_ + 1;
- ++mtu_probe_count_;
-
- DVLOG(2) << "Sending a path MTU discovery packet #" << mtu_probe_count_;
- SendMtuDiscoveryPacket(mtu_discovery_target_);
-
- DCHECK(!mtu_discovery_alarm_->IsSet());
-}
-
-void QuicConnection::OnPeerMigrationValidated(QuicPathId path_id) {
- if (active_peer_migration_type_ == NO_CHANGE) {
- QUIC_BUG << "No migration underway.";
- return;
- }
- highest_packet_sent_before_peer_migration_ = 0;
- active_peer_migration_type_ = NO_CHANGE;
-}
-
-// TODO(jri): Modify method to start migration whenever a new IP address is seen
-// from a packet with sequence number > the one that triggered the previous
-// migration. This should happen even if a migration is underway, since the
-// most recent migration is the one that we should pay attention to.
-void QuicConnection::StartPeerMigration(
- QuicPathId path_id,
- PeerAddressChangeType peer_migration_type) {
- // TODO(fayang): Currently, all peer address change type are allowed. Need to
- // add a method ShouldAllowPeerAddressChange(PeerAddressChangeType type) to
- // determine whether |type| is allowed.
- if (active_peer_migration_type_ != NO_CHANGE ||
- peer_migration_type == NO_CHANGE) {
- QUIC_BUG << "Migration underway or no new migration started.";
- return;
- }
- DVLOG(1) << ENDPOINT << "Peer's ip:port changed from "
- << peer_address_.ToString() << " to "
- << last_packet_source_address_.ToString()
- << ", migrating connection.";
-
- highest_packet_sent_before_peer_migration_ =
- packet_number_of_last_sent_packet_;
- peer_address_ = last_packet_source_address_;
- active_peer_migration_type_ = peer_migration_type;
-
- // TODO(jri): Move these calls to OnPeerMigrationValidated. Rename
- // OnConnectionMigration methods to OnPeerMigration.
- visitor_->OnConnectionMigration(peer_migration_type);
- sent_packet_manager_->OnConnectionMigration(path_id, peer_migration_type);
-}
-
-void QuicConnection::OnPathClosed(QuicPathId path_id) {
- // Stop receiving packets on this path.
- framer_.OnPathClosed(path_id);
-}
-
-bool QuicConnection::ack_frame_updated() const {
- return received_packet_manager_.ack_frame_updated();
-}
-
-StringPiece QuicConnection::GetCurrentPacket() {
- if (current_packet_data_ == nullptr) {
- return StringPiece();
- }
- return StringPiece(current_packet_data_, last_size_);
-}
-
-bool QuicConnection::MaybeConsiderAsMemoryCorruption(
- const QuicStreamFrame& frame) {
- if (frame.stream_id == kCryptoStreamId ||
- last_decrypted_packet_level_ != ENCRYPTION_NONE) {
- return false;
- }
-
- if (perspective_ == Perspective::IS_SERVER &&
- frame.data_length >= sizeof(kCHLO) &&
- strncmp(frame.data_buffer, reinterpret_cast<const char*>(&kCHLO),
- sizeof(kCHLO)) == 0) {
- return true;
- }
-
- if (perspective_ == Perspective::IS_CLIENT &&
- frame.data_length >= sizeof(kREJ) &&
- strncmp(frame.data_buffer, reinterpret_cast<const char*>(&kREJ),
- sizeof(kREJ)) == 0) {
- return true;
- }
-
- return false;
-}
-
-// Uses a 25ms delayed ack timer. Also helps with better signaling
-// in low-bandwidth (< ~384 kbps), where an ack is sent per packet.
-// Ensures that the Delayed Ack timer is always set to a value lesser
-// than the retransmission timer's minimum value (MinRTO). We want the
-// delayed ack to get back to the QUIC peer before the sender's
-// retransmission timer triggers. Since we do not know the
-// reverse-path one-way delay, we assume equal delays for forward and
-// reverse paths, and ensure that the timer is set to less than half
-// of the MinRTO.
-// There may be a value in making this delay adaptive with the help of
-// the sender and a signaling mechanism -- if the sender uses a
-// different MinRTO, we may get spurious retransmissions. May not have
-// any benefits, but if the delayed ack becomes a significant source
-// of (likely, tail) latency, then consider such a mechanism.
-const QuicTime::Delta QuicConnection::DelayedAckTime() {
- return QuicTime::Delta::FromMilliseconds(
- min(kMaxDelayedAckTimeMs, kMinRetransmissionTimeMs / 2));
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_connection.h b/chromium/net/quic/quic_connection.h
deleted file mode 100644
index 7014b07351c..00000000000
--- a/chromium/net/quic/quic_connection.h
+++ /dev/null
@@ -1,1078 +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.
-//
-// The entity that handles framing writes for a Quic client or server.
-// Each QuicSession will have a connection associated with it.
-//
-// On the server side, the Dispatcher handles the raw reads, and hands off
-// packets via ProcessUdpPacket for framing and processing.
-//
-// On the client side, the Connection handles the raw reads, as well as the
-// processing.
-//
-// Note: this class is not thread-safe.
-
-#ifndef NET_QUIC_QUIC_CONNECTION_H_
-#define NET_QUIC_QUIC_CONNECTION_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <deque>
-#include <list>
-#include <map>
-#include <memory>
-#include <queue>
-#include <string>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "net/base/ip_address.h"
-#include "net/base/ip_endpoint.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/quic_alarm.h"
-#include "net/quic/quic_alarm_factory.h"
-#include "net/quic/quic_blocked_writer_interface.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_one_block_arena.h"
-#include "net/quic/quic_packet_creator.h"
-#include "net/quic/quic_packet_generator.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_received_packet_manager.h"
-#include "net/quic/quic_sent_entropy_manager.h"
-#include "net/quic/quic_sent_packet_manager_interface.h"
-#include "net/quic/quic_time.h"
-#include "net/quic/quic_types.h"
-
-namespace net {
-
-class QuicClock;
-class QuicConfig;
-class QuicConnection;
-class QuicEncrypter;
-class QuicRandom;
-
-namespace test {
-class PacketSavingConnection;
-class QuicConnectionPeer;
-} // namespace test
-
-// The initial number of packets between MTU probes. After each attempt the
-// number is doubled.
-const QuicPacketCount kPacketsBetweenMtuProbesBase = 100;
-
-// The number of MTU probes that get sent before giving up.
-const size_t kMtuDiscoveryAttempts = 3;
-
-// Ensure that exponential back-off does not result in an integer overflow.
-// The number of packets can be potentially capped, but that is not useful at
-// current kMtuDiscoveryAttempts value, and hence is not implemented at present.
-static_assert(kMtuDiscoveryAttempts + 8 < 8 * sizeof(QuicPacketNumber),
- "The number of MTU discovery attempts is too high");
-static_assert(kPacketsBetweenMtuProbesBase < (1 << 8),
- "The initial number of packets between MTU probes is too high");
-
-// The incresed packet size targeted when doing path MTU discovery.
-const QuicByteCount kMtuDiscoveryTargetPacketSizeHigh = 1450;
-const QuicByteCount kMtuDiscoveryTargetPacketSizeLow = 1430;
-
-static_assert(kMtuDiscoveryTargetPacketSizeLow <= kMaxPacketSize,
- "MTU discovery target is too large");
-static_assert(kMtuDiscoveryTargetPacketSizeHigh <= kMaxPacketSize,
- "MTU discovery target is too large");
-
-static_assert(kMtuDiscoveryTargetPacketSizeLow > kDefaultMaxPacketSize,
- "MTU discovery target does not exceed the default packet size");
-static_assert(kMtuDiscoveryTargetPacketSizeHigh > kDefaultMaxPacketSize,
- "MTU discovery target does not exceed the default packet size");
-
-// Class that receives callbacks from the connection when frames are received
-// and when other interesting events happen.
-class NET_EXPORT_PRIVATE QuicConnectionVisitorInterface {
- public:
- virtual ~QuicConnectionVisitorInterface() {}
-
- // A simple visitor interface for dealing with a data frame.
- virtual void OnStreamFrame(const QuicStreamFrame& frame) = 0;
-
- // The session should process the WINDOW_UPDATE frame, adjusting both stream
- // and connection level flow control windows.
- virtual void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) = 0;
-
- // A BLOCKED frame indicates the peer is flow control blocked
- // on a specified stream.
- virtual void OnBlockedFrame(const QuicBlockedFrame& frame) = 0;
-
- // Called when the stream is reset by the peer.
- virtual void OnRstStream(const QuicRstStreamFrame& frame) = 0;
-
- // Called when the connection is going away according to the peer.
- virtual void OnGoAway(const QuicGoAwayFrame& frame) = 0;
-
- // Called when the connection is closed either locally by the framer, or
- // remotely by the peer.
- virtual void OnConnectionClosed(QuicErrorCode error,
- const std::string& error_details,
- ConnectionCloseSource source) = 0;
-
- // Called when the connection failed to write because the socket was blocked.
- virtual void OnWriteBlocked() = 0;
-
- // Called once a specific QUIC version is agreed by both endpoints.
- virtual void OnSuccessfulVersionNegotiation(const QuicVersion& version) = 0;
-
- // Called when a blocked socket becomes writable.
- virtual void OnCanWrite() = 0;
-
- // Called when the connection experiences a change in congestion window.
- virtual void OnCongestionWindowChange(QuicTime now) = 0;
-
- // Called when the connection receives a packet from a migrated client.
- virtual void OnConnectionMigration(PeerAddressChangeType type) = 0;
-
- // Called when the peer seems unreachable over the current path.
- virtual void OnPathDegrading() = 0;
-
- // Called after OnStreamFrame, OnRstStream, OnGoAway, OnWindowUpdateFrame,
- // OnBlockedFrame, and OnCanWrite to allow post-processing once the work has
- // been done.
- virtual void PostProcessAfterData() = 0;
-
- // Called to ask if the visitor wants to schedule write resumption as it both
- // has pending data to write, and is able to write (e.g. based on flow control
- // limits).
- // Writes may be pending because they were write-blocked, congestion-throttled
- // or yielded to other connections.
- virtual bool WillingAndAbleToWrite() const = 0;
-
- // Called to ask if any handshake messages are pending in this visitor.
- virtual bool HasPendingHandshake() const = 0;
-
- // Called to ask if any streams are open in this visitor, excluding the
- // reserved crypto and headers stream.
- virtual bool HasOpenDynamicStreams() const = 0;
-};
-
-// Interface which gets callbacks from the QuicConnection at interesting
-// points. Implementations must not mutate the state of the connection
-// as a result of these callbacks.
-class NET_EXPORT_PRIVATE QuicConnectionDebugVisitor
- : public QuicSentPacketManagerInterface::DebugDelegate {
- public:
- ~QuicConnectionDebugVisitor() override {}
-
- // Called when a packet has been sent.
- virtual void OnPacketSent(const SerializedPacket& serialized_packet,
- QuicPathId original_path_id,
- QuicPacketNumber original_packet_number,
- TransmissionType transmission_type,
- QuicTime sent_time) {}
-
- // Called when a packet has been received, but before it is
- // validated or parsed.
- virtual void OnPacketReceived(const IPEndPoint& self_address,
- const IPEndPoint& peer_address,
- const QuicEncryptedPacket& packet) {}
-
- // Called when the unauthenticated portion of the header has been parsed.
- virtual void OnUnauthenticatedHeader(const QuicPacketHeader& header) {}
-
- // Called when a packet is received with a connection id that does not
- // match the ID of this connection.
- virtual void OnIncorrectConnectionId(QuicConnectionId connection_id) {}
-
- // Called when an undecryptable packet has been received.
- virtual void OnUndecryptablePacket() {}
-
- // Called when a duplicate packet has been received.
- virtual void OnDuplicatePacket(QuicPacketNumber packet_number) {}
-
- // Called when the protocol version on the received packet doensn't match
- // current protocol version of the connection.
- virtual void OnProtocolVersionMismatch(QuicVersion version) {}
-
- // Called when the complete header of a packet has been parsed.
- virtual void OnPacketHeader(const QuicPacketHeader& header) {}
-
- // Called when a StreamFrame has been parsed.
- virtual void OnStreamFrame(const QuicStreamFrame& frame) {}
-
- // Called when a AckFrame has been parsed.
- virtual void OnAckFrame(const QuicAckFrame& frame) {}
-
- // Called when a StopWaitingFrame has been parsed.
- virtual void OnStopWaitingFrame(const QuicStopWaitingFrame& frame) {}
-
- // Called when a QuicPaddingFrame has been parsed.
- virtual void OnPaddingFrame(const QuicPaddingFrame& frame) {}
-
- // Called when a Ping has been parsed.
- virtual void OnPingFrame(const QuicPingFrame& frame) {}
-
- // Called when a GoAway has been parsed.
- virtual void OnGoAwayFrame(const QuicGoAwayFrame& frame) {}
-
- // Called when a RstStreamFrame has been parsed.
- virtual void OnRstStreamFrame(const QuicRstStreamFrame& frame) {}
-
- // Called when a ConnectionCloseFrame has been parsed.
- virtual void OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) {}
-
- // Called when a WindowUpdate has been parsed.
- virtual void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {}
-
- // Called when a BlockedFrame has been parsed.
- virtual void OnBlockedFrame(const QuicBlockedFrame& frame) {}
-
- // Called when a PathCloseFrame has been parsed.
- virtual void OnPathCloseFrame(const QuicPathCloseFrame& frame) {}
-
- // Called when a public reset packet has been received.
- virtual void OnPublicResetPacket(const QuicPublicResetPacket& packet) {}
-
- // Called when a version negotiation packet has been received.
- virtual void OnVersionNegotiationPacket(
- const QuicVersionNegotiationPacket& packet) {}
-
- // Called when the connection is closed.
- virtual void OnConnectionClosed(QuicErrorCode error,
- const std::string& error_details,
- ConnectionCloseSource source) {}
-
- // Called when the version negotiation is successful.
- virtual void OnSuccessfulVersionNegotiation(const QuicVersion& version) {}
-
- // Called when a CachedNetworkParameters is sent to the client.
- virtual void OnSendConnectionState(
- const CachedNetworkParameters& cached_network_params) {}
-
- // Called when a CachedNetworkParameters are recieved from the client.
- virtual void OnReceiveConnectionState(
- const CachedNetworkParameters& cached_network_params) {}
-
- // Called when the connection parameters are set from the supplied
- // |config|.
- virtual void OnSetFromConfig(const QuicConfig& config) {}
-
- // Called when RTT may have changed, including when an RTT is read from
- // the config.
- virtual void OnRttChanged(QuicTime::Delta rtt) const {}
-};
-
-// QuicConnections currently use around 1KB of polymorphic types which would
-// ordinarily be on the heap. Instead, store them inline in an arena.
-using QuicConnectionArena = QuicOneBlockArena<1024>;
-
-class NET_EXPORT_PRIVATE QuicConnectionHelperInterface {
- public:
- virtual ~QuicConnectionHelperInterface() {}
-
- // Returns a QuicClock to be used for all time related functions.
- virtual const QuicClock* GetClock() const = 0;
-
- // Returns a QuicRandom to be used for all random number related functions.
- virtual QuicRandom* GetRandomGenerator() = 0;
-
- // Returns a QuicBufferAllocator to be used for all stream frame buffers.
- virtual QuicBufferAllocator* GetBufferAllocator() = 0;
-};
-
-class NET_EXPORT_PRIVATE QuicConnection
- : public QuicFramerVisitorInterface,
- public QuicBlockedWriterInterface,
- public QuicPacketGenerator::DelegateInterface,
- public QuicSentPacketManager::NetworkChangeVisitor {
- public:
- enum AckBundling {
- // Send an ack if it's already queued in the connection.
- SEND_ACK_IF_QUEUED,
- // Always send an ack.
- SEND_ACK,
- // Bundle an ack with outgoing data.
- SEND_ACK_IF_PENDING,
- };
-
- enum AckMode { TCP_ACKING, ACK_DECIMATION, ACK_DECIMATION_WITH_REORDERING };
-
- // Constructs a new QuicConnection for |connection_id| and |address| using
- // |writer| to write packets. |owns_writer| specifies whether the connection
- // takes ownership of |writer|. |helper| must outlive this connection.
- QuicConnection(QuicConnectionId connection_id,
- IPEndPoint address,
- QuicConnectionHelperInterface* helper,
- QuicAlarmFactory* alarm_factory,
- QuicPacketWriter* writer,
- bool owns_writer,
- Perspective perspective,
- const QuicVersionVector& supported_versions);
- ~QuicConnection() override;
-
- // Sets connection parameters from the supplied |config|.
- void SetFromConfig(const QuicConfig& config);
-
- // Called by the session when sending connection state to the client.
- virtual void OnSendConnectionState(
- const CachedNetworkParameters& cached_network_params);
-
- // Called by the session when receiving connection state from the client.
- virtual void OnReceiveConnectionState(
- const CachedNetworkParameters& cached_network_params);
-
- // Called by the Session when the client has provided CachedNetworkParameters.
- virtual void ResumeConnectionState(
- const CachedNetworkParameters& cached_network_params,
- bool max_bandwidth_resumption);
-
- // Called by the Session when a max pacing rate for the connection is needed.
- virtual void SetMaxPacingRate(QuicBandwidth max_pacing_rate);
-
- // Sets the number of active streams on the connection for congestion control.
- void SetNumOpenStreams(size_t num_streams);
-
- // Send the data in |data| to the peer in as few packets as possible.
- // Returns a pair with the number of bytes consumed from data, and a boolean
- // indicating if the fin bit was consumed. This does not indicate the data
- // has been sent on the wire: it may have been turned into a packet and queued
- // if the socket was unexpectedly blocked.
- // If |listener| is provided, then it will be informed once ACKs have been
- // received for all the packets written in this call.
- // The |listener| is not owned by the QuicConnection and must outlive it.
- virtual QuicConsumedData SendStreamData(QuicStreamId id,
- QuicIOVector iov,
- QuicStreamOffset offset,
- bool fin,
- QuicAckListenerInterface* listener);
-
- // Send a RST_STREAM frame to the peer.
- virtual void SendRstStream(QuicStreamId id,
- QuicRstStreamErrorCode error,
- QuicStreamOffset bytes_written);
-
- // Send a BLOCKED frame to the peer.
- virtual void SendBlocked(QuicStreamId id);
-
- // Send a WINDOW_UPDATE frame to the peer.
- virtual void SendWindowUpdate(QuicStreamId id, QuicStreamOffset byte_offset);
-
- // Send a PATH_CLOSE frame to the peer.
- virtual void SendPathClose(QuicPathId path_id);
-
- // Closes the connection.
- // |connection_close_behavior| determines whether or not a connection close
- // packet is sent to the peer.
- virtual void CloseConnection(
- QuicErrorCode error,
- const std::string& details,
- ConnectionCloseBehavior connection_close_behavior);
-
- // Sends a GOAWAY frame. Does nothing if a GOAWAY frame has already been sent.
- virtual void SendGoAway(QuicErrorCode error,
- QuicStreamId last_good_stream_id,
- const std::string& reason);
-
- // Returns statistics tracked for this connection.
- const QuicConnectionStats& GetStats();
-
- // Processes an incoming UDP packet (consisting of a QuicEncryptedPacket) from
- // the peer.
- // In a client, the packet may be "stray" and have a different connection ID
- // than that of this connection.
- virtual void ProcessUdpPacket(const IPEndPoint& self_address,
- const IPEndPoint& peer_address,
- const QuicReceivedPacket& packet);
-
- // QuicBlockedWriterInterface
- // Called when the underlying connection becomes writable to allow queued
- // writes to happen.
- void OnCanWrite() override;
-
- // Called when an error occurs while attempting to write a packet to the
- // network.
- void OnWriteError(int error_code);
-
- // If the socket is not blocked, writes queued packets.
- void WriteIfNotBlocked();
-
- // If the socket is not blocked, writes queued packets and bundles any pending
- // ACKs.
- void WriteAndBundleAcksIfNotBlocked();
-
- // Set the packet writer.
- void SetQuicPacketWriter(QuicPacketWriter* writer, bool owns_writer) {
- DCHECK(writer != nullptr);
- if (writer_ != nullptr && owns_writer_) {
- delete writer_;
- }
- writer_ = writer;
- owns_writer_ = owns_writer;
- }
-
- // Set self address.
- void SetSelfAddress(IPEndPoint address) { self_address_ = address; }
-
- // The version of the protocol this connection is using.
- QuicVersion version() const { return framer_.version(); }
-
- // The versions of the protocol that this connection supports.
- const QuicVersionVector& supported_versions() const {
- return framer_.supported_versions();
- }
-
- // From QuicFramerVisitorInterface
- void OnError(QuicFramer* framer) override;
- bool OnProtocolVersionMismatch(QuicVersion received_version) override;
- void OnPacket() override;
- void OnPublicResetPacket(const QuicPublicResetPacket& packet) override;
- void OnVersionNegotiationPacket(
- const QuicVersionNegotiationPacket& packet) override;
- bool OnUnauthenticatedPublicHeader(
- const QuicPacketPublicHeader& header) override;
- bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override;
- void OnDecryptedPacket(EncryptionLevel level) override;
- bool OnPacketHeader(const QuicPacketHeader& header) override;
- bool OnStreamFrame(const QuicStreamFrame& frame) override;
- bool OnAckFrame(const QuicAckFrame& frame) override;
- bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override;
- bool OnPaddingFrame(const QuicPaddingFrame& frame) override;
- bool OnPingFrame(const QuicPingFrame& frame) override;
- bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override;
- bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override;
- bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override;
- bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
- bool OnBlockedFrame(const QuicBlockedFrame& frame) override;
- bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override;
- void OnPacketComplete() override;
-
- // QuicConnectionCloseDelegateInterface
- void OnUnrecoverableError(QuicErrorCode error,
- const std::string& error_details,
- ConnectionCloseSource source) override;
-
- // QuicPacketGenerator::DelegateInterface
- bool ShouldGeneratePacket(HasRetransmittableData retransmittable,
- IsHandshake handshake) override;
- const QuicFrame GetUpdatedAckFrame() override;
- void PopulateStopWaitingFrame(QuicStopWaitingFrame* stop_waiting) override;
-
- // QuicPacketCreator::DelegateInterface
- void OnSerializedPacket(SerializedPacket* packet) override;
-
- // QuicSentPacketManager::NetworkChangeVisitor
- void OnCongestionChange() override;
- void OnPathDegrading() override;
- void OnPathMtuIncreased(QuicPacketLength packet_size) override;
-
- // Called by the crypto stream when the handshake completes. In the server's
- // case this is when the SHLO has been ACKed. Clients call this on receipt of
- // the SHLO.
- void OnHandshakeComplete();
-
- // Accessors
- void set_visitor(QuicConnectionVisitorInterface* visitor) {
- visitor_ = visitor;
- }
- void set_debug_visitor(QuicConnectionDebugVisitor* debug_visitor) {
- debug_visitor_ = debug_visitor;
- sent_packet_manager_->SetDebugDelegate(debug_visitor);
- }
- // Used in Chromium, but not internally.
- void set_creator_debug_delegate(QuicPacketCreator::DebugDelegate* visitor) {
- packet_generator_.set_debug_delegate(visitor);
- }
- const IPEndPoint& self_address() const { return self_address_; }
- const IPEndPoint& peer_address() const { return peer_address_; }
- QuicConnectionId connection_id() const { return connection_id_; }
- const QuicClock* clock() const { return clock_; }
- QuicRandom* random_generator() const { return random_generator_; }
- QuicByteCount max_packet_length() const;
- void SetMaxPacketLength(QuicByteCount length);
-
- size_t mtu_probe_count() const { return mtu_probe_count_; }
-
- bool connected() const { return connected_; }
-
- bool goaway_sent() const { return goaway_sent_; }
-
- bool goaway_received() const { return goaway_received_; }
-
- // Must only be called on client connections.
- const QuicVersionVector& server_supported_versions() const {
- DCHECK_EQ(Perspective::IS_CLIENT, perspective_);
- return server_supported_versions_;
- }
-
- // Testing only.
- size_t NumQueuedPackets() const { return queued_packets_.size(); }
-
- // Once called, any sent crypto packets to be saved as the
- // termination packet, for use with stateless rejections.
- void EnableSavingCryptoPackets();
-
- // Returns true if the underlying UDP socket is writable, there is
- // no queued data and the connection is not congestion-control
- // blocked.
- bool CanWriteStreamData();
-
- // Returns true if the connection has queued packets or frames.
- bool HasQueuedData() const;
-
- // Sets the handshake and idle state connection timeouts.
- void SetNetworkTimeouts(QuicTime::Delta handshake_timeout,
- QuicTime::Delta idle_timeout);
-
- // If the connection has timed out, this will close the connection.
- // Otherwise, it will reschedule the timeout alarm.
- void CheckForTimeout();
-
- // Called when the ping alarm fires. Causes a ping frame to be sent only
- // if the retransmission alarm is not running.
- void OnPingTimeout();
-
- // Sends a ping frame.
- void SendPing();
-
- // Sets up a packet with an QuicAckFrame and sends it out.
- void SendAck();
-
- // Called when an RTO fires. Resets the retransmission alarm if there are
- // remaining unacked packets.
- void OnRetransmissionTimeout();
-
- // Retransmits all unacked packets with retransmittable frames if
- // |retransmission_type| is ALL_UNACKED_PACKETS, otherwise retransmits only
- // initially encrypted packets. Used when the negotiated protocol version is
- // different from what was initially assumed and when the initial encryption
- // changes.
- void RetransmitUnackedPackets(TransmissionType retransmission_type);
-
- // Calls |sent_packet_manager_|'s NeuterUnencryptedPackets. Used when the
- // connection becomes forward secure and hasn't received acks for all packets.
- void NeuterUnencryptedPackets();
-
- // Changes the encrypter used for level |level| to |encrypter|. The function
- // takes ownership of |encrypter|.
- void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter);
-
- // SetNonceForPublicHeader sets the nonce that will be transmitted in the
- // public header of each packet encrypted at the initial encryption level
- // decrypted. This should only be called on the server side.
- void SetDiversificationNonce(const DiversificationNonce nonce);
-
- // SetDefaultEncryptionLevel sets the encryption level that will be applied
- // to new packets.
- void SetDefaultEncryptionLevel(EncryptionLevel level);
-
- // SetDecrypter sets the primary decrypter, replacing any that already exists,
- // and takes ownership. If an alternative decrypter is in place then the
- // function DCHECKs. This is intended for cases where one knows that future
- // packets will be using the new decrypter and the previous decrypter is now
- // obsolete. |level| indicates the encryption level of the new decrypter.
- void SetDecrypter(EncryptionLevel level, QuicDecrypter* decrypter);
-
- // SetAlternativeDecrypter sets a decrypter that may be used to decrypt
- // future packets and takes ownership of it. |level| indicates the encryption
- // level of the decrypter. If |latch_once_used| is true, then the first time
- // that the decrypter is successful it will replace the primary decrypter.
- // Otherwise both decrypters will remain active and the primary decrypter
- // will be the one last used.
- void SetAlternativeDecrypter(EncryptionLevel level,
- QuicDecrypter* decrypter,
- bool latch_once_used);
-
- const QuicDecrypter* decrypter() const;
- const QuicDecrypter* alternative_decrypter() const;
-
- Perspective perspective() const { return perspective_; }
-
- // Allow easy overriding of truncated connection IDs.
- void set_can_truncate_connection_ids(bool can) {
- can_truncate_connection_ids_ = can;
- }
-
- // Returns the underlying sent packet manager.
- const QuicSentPacketManagerInterface& sent_packet_manager() const {
- return *sent_packet_manager_;
- }
-
- bool CanWrite(HasRetransmittableData retransmittable);
-
- // Stores current batch state for connection, puts the connection
- // into batch mode, and destruction restores the stored batch state.
- // While the bundler is in scope, any generated frames are bundled
- // as densely as possible into packets. In addition, this bundler
- // can be configured to ensure that an ACK frame is included in the
- // first packet created, if there's new ack information to be sent.
- class NET_EXPORT_PRIVATE ScopedPacketBundler {
- public:
- // In addition to all outgoing frames being bundled when the
- // bundler is in scope, setting |include_ack| to true ensures that
- // an ACK frame is opportunistically bundled with the first
- // outgoing packet.
- ScopedPacketBundler(QuicConnection* connection, AckBundling send_ack);
- ~ScopedPacketBundler();
-
- private:
- bool ShouldSendAck(AckBundling ack_mode) const;
-
- QuicConnection* connection_;
- bool already_in_batch_mode_;
- };
-
- // Delays setting the retransmission alarm until the scope is exited.
- // When nested, only the outermost scheduler will set the alarm, and inner
- // ones have no effect.
- class NET_EXPORT_PRIVATE ScopedRetransmissionScheduler {
- public:
- explicit ScopedRetransmissionScheduler(QuicConnection* connection);
- ~ScopedRetransmissionScheduler();
-
- private:
- QuicConnection* connection_;
- // Set to the connection's delay_setting_retransmission_alarm_ value in the
- // constructor and when true, causes this class to do nothing.
- const bool already_delayed_;
- };
-
- QuicPacketNumber packet_number_of_last_sent_packet() const {
- return packet_number_of_last_sent_packet_;
- }
-
- QuicPacketWriter* writer() { return writer_; }
- const QuicPacketWriter* writer() const { return writer_; }
-
- // Sends an MTU discovery packet of size |target_mtu|. If the packet is
- // acknowledged by the peer, the maximum packet size will be increased to
- // |target_mtu|.
- void SendMtuDiscoveryPacket(QuicByteCount target_mtu);
-
- // Sends an MTU discovery packet of size |mtu_discovery_target_| and updates
- // the MTU discovery alarm.
- void DiscoverMtu();
-
- // Return the name of the cipher of the primary decrypter of the framer.
- const char* cipher_name() const { return framer_.decrypter()->cipher_name(); }
- // Return the id of the cipher of the primary decrypter of the framer.
- uint32_t cipher_id() const { return framer_.decrypter()->cipher_id(); }
-
- std::vector<std::unique_ptr<QuicEncryptedPacket>>* termination_packets() {
- return termination_packets_.get();
- }
-
- bool ack_queued() const { return ack_queued_; }
-
- bool ack_frame_updated() const;
-
- QuicConnectionHelperInterface* helper() { return helper_; }
- QuicAlarmFactory* alarm_factory() { return alarm_factory_; }
-
- base::StringPiece GetCurrentPacket();
-
- const QuicPacketGenerator& packet_generator() const {
- return packet_generator_;
- }
-
- EncryptionLevel encryption_level() const { return encryption_level_; }
-
- const IPEndPoint& last_packet_source_address() const {
- return last_packet_source_address_;
- }
-
- protected:
- // Calls cancel() on all the alarms owned by this connection.
- void CancelAllAlarms();
-
- // Send a packet to the peer, and takes ownership of the packet if the packet
- // cannot be written immediately.
- virtual void SendOrQueuePacket(SerializedPacket* packet);
-
- // Called after a packet is received from a new peer address on existing
- // |path_id| and is decrypted. Starts validation of peer's address change.
- virtual void StartPeerMigration(QuicPathId path_id,
- PeerAddressChangeType peer_migration_type);
-
- // Called when a peer address migration is validated on |path_id|.
- virtual void OnPeerMigrationValidated(QuicPathId path_id);
-
- // 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 QuicVersionVector& available_versions);
-
- // Returns the current per-packet options for the connection.
- PerPacketOptions* per_packet_options() { return per_packet_options_; }
- // Sets the current per-packet options for the connection. The QuicConnection
- // does not take ownership of |options|; |options| must live for as long as
- // the QuicConnection is in use.
- void set_per_packet_options(PerPacketOptions* options) {
- per_packet_options_ = options;
- }
-
- // If |defer| is true, configures the connection to defer sending packets in
- // response to an ACK to the SendAlarm. If |defer| is false, packets may be
- // sent immediately after receiving an ACK.
- void set_defer_send_in_response_to_packets(bool defer) {
- defer_send_in_response_to_packets_ = defer;
- }
-
- PeerAddressChangeType active_peer_migration_type() {
- return active_peer_migration_type_;
- }
-
- // Sends the connection close packet to the peer.
- virtual void SendConnectionClosePacket(QuicErrorCode error,
- const std::string& details);
-
- private:
- friend class test::QuicConnectionPeer;
- friend class test::PacketSavingConnection;
-
- typedef std::list<SerializedPacket> QueuedPacketList;
-
- // Notifies the visitor of the close and marks the connection as disconnected.
- // Does not send a connection close frame to the peer.
- void TearDownLocalConnectionState(QuicErrorCode error,
- const std::string& details,
- ConnectionCloseSource source);
-
- // Writes the given packet to socket, encrypted with packet's
- // encryption_level. Returns true on successful write, and false if the writer
- // was blocked and the write needs to be tried again. Notifies the
- // SentPacketManager when the write is successful and sets
- // retransmittable frames to nullptr.
- // Saves the connection close packet for later transmission, even if the
- // writer is write blocked.
- bool WritePacket(SerializedPacket* packet);
-
- // Make sure an ack we got from our peer is sane.
- // Returns nullptr for valid acks or an error std::string if it was invalid.
- const char* ValidateAckFrame(const QuicAckFrame& incoming_ack);
-
- // Make sure a stop waiting we got from our peer is sane.
- // Returns nullptr if the frame is valid or an error std::string if it was
- // invalid.
- const char* ValidateStopWaitingFrame(
- const QuicStopWaitingFrame& stop_waiting);
-
- // Sends a version negotiation packet to the peer.
- void SendVersionNegotiationPacket();
-
- // Clears any accumulated frames from the last received packet.
- void ClearLastFrames();
-
- // Deletes and clears any queued packets.
- void ClearQueuedPackets();
-
- // Closes the connection if the sent or received packet manager are tracking
- // too many outstanding packets.
- void MaybeCloseIfTooManyOutstandingPackets();
-
- // Writes as many queued packets as possible. The connection must not be
- // blocked when this is called.
- void WriteQueuedPackets();
-
- // Writes as many pending retransmissions as possible.
- void WritePendingRetransmissions();
-
- // Returns true if the packet should be discarded and not sent.
- bool ShouldDiscardPacket(const SerializedPacket& packet);
-
- // Queues |packet| in the hopes that it can be decrypted in the
- // future, when a new key is installed.
- void QueueUndecryptablePacket(const QuicEncryptedPacket& packet);
-
- // Attempts to process any queued undecryptable packets.
- void MaybeProcessUndecryptablePackets();
-
- void ProcessAckFrame(const QuicAckFrame& incoming_ack);
-
- void ProcessStopWaitingFrame(const QuicStopWaitingFrame& stop_waiting);
-
- // Sends any packets which are a response to the last packet, including both
- // acks and pending writes if an ack opened the congestion window.
- void MaybeSendInResponseToPacket();
-
- // Queue an ack or set the ack alarm if needed. |was_missing| is true if
- // the most recently received packet was formerly missing.
- void MaybeQueueAck(bool was_missing);
-
- // Gets the least unacked packet number of |path_id|, which is the next packet
- // number to be sent if there are no outstanding packets.
- QuicPacketNumber GetLeastUnacked(QuicPathId path_id) const;
-
- // Sets the timeout alarm to the appropriate value, if any.
- void SetTimeoutAlarm();
-
- // Sets the ping alarm to the appropriate value, if any.
- void SetPingAlarm();
-
- // Sets the retransmission alarm based on SentPacketManager.
- void SetRetransmissionAlarm();
-
- // Sets the MTU discovery alarm if necessary.
- void MaybeSetMtuAlarm();
-
- // On arrival of a new packet, checks to see if the socket addresses have
- // changed since the last packet we saw on this connection.
- void CheckForAddressMigration(const IPEndPoint& self_address,
- const IPEndPoint& peer_address);
-
- HasRetransmittableData IsRetransmittable(const SerializedPacket& packet);
- bool IsTerminationPacket(const SerializedPacket& packet);
-
- // Set the size of the packet we are targeting while doing path MTU discovery.
- void SetMtuDiscoveryTarget(QuicByteCount target);
-
- // Validates the potential maximum packet size, and reduces it if it exceeds
- // the largest supported by the protocol or the packet writer.
- QuicByteCount LimitMaxPacketSize(QuicByteCount suggested_max_packet_size);
-
- // Called when |path_id| is considered as closed because either a PATH_CLOSE
- // frame is sent or received. Stops receiving packets on closed path. Drops
- // receive side of a closed path, and packets with retransmittable frames on a
- // closed path are marked as retransmissions which will be transmitted on
- // other paths.
- // TODO(fayang): complete OnPathClosed once QuicMultipathSentPacketManager and
- // QuicMultipathReceivedPacketManager are landed in QuicConnection.
- void OnPathClosed(QuicPathId path_id);
-
- // Do any work which logically would be done in OnPacket but can not be
- // safely done until the packet is validated. Returns true if packet can be
- // handled, false otherwise.
- bool ProcessValidatedPacket(const QuicPacketHeader& header);
-
- // Consider receiving crypto frame on non crypto stream as memory corruption.
- bool MaybeConsiderAsMemoryCorruption(const QuicStreamFrame& frame);
-
- const QuicTime::Delta DelayedAckTime();
-
- QuicFramer framer_;
- QuicConnectionHelperInterface* helper_; // Not owned.
- QuicAlarmFactory* alarm_factory_; // Not owned.
- PerPacketOptions* per_packet_options_; // Not owned.
- QuicPacketWriter* writer_; // Owned or not depending on |owns_writer_|.
- bool owns_writer_;
- // Encryption level for new packets. Should only be changed via
- // SetDefaultEncryptionLevel().
- EncryptionLevel encryption_level_;
- bool has_forward_secure_encrypter_;
- // The packet number of the first packet which will be encrypted with the
- // foward-secure encrypter, even if the peer has not started sending
- // forward-secure packets.
- QuicPacketNumber first_required_forward_secure_packet_;
- const QuicClock* clock_;
- QuicRandom* random_generator_;
-
- const QuicConnectionId connection_id_;
- // Address on the last successfully processed packet received from the
- // client.
- IPEndPoint self_address_;
- IPEndPoint peer_address_;
-
- // Records change type when the peer initiates migration to a new peer
- // address. Reset to NO_CHANGE after peer migration is validated.
- PeerAddressChangeType active_peer_migration_type_;
-
- // Records highest sent packet number when peer migration is started.
- QuicPacketNumber highest_packet_sent_before_peer_migration_;
-
- // True if the last packet has gotten far enough in the framer to be
- // decrypted.
- bool last_packet_decrypted_;
- QuicByteCount last_size_; // Size of the last received packet.
- // TODO(rch): remove this when b/27221014 is fixed.
- const char* current_packet_data_; // UDP payload of packet currently being
- // parsed or nullptr.
- EncryptionLevel last_decrypted_packet_level_;
- QuicPacketHeader last_header_;
- QuicStopWaitingFrame last_stop_waiting_frame_;
- bool should_last_packet_instigate_acks_;
-
- // Track some peer state so we can do less bookkeeping
- // Largest sequence sent by the peer which had an ack frame (latest ack info).
- QuicPacketNumber largest_seen_packet_with_ack_;
-
- // Largest packet number sent by the peer which had a stop waiting frame.
- QuicPacketNumber largest_seen_packet_with_stop_waiting_;
-
- // Collection of packets which were received before encryption was
- // established, but which could not be decrypted. We buffer these on
- // the assumption that they could not be processed because they were
- // sent with the INITIAL encryption and the CHLO message was lost.
- std::deque<QuicEncryptedPacket*> undecryptable_packets_;
-
- // Maximum number of undecryptable packets the connection will store.
- size_t max_undecryptable_packets_;
-
- // When the version negotiation packet could not be sent because the socket
- // was not writable, this is set to true.
- bool pending_version_negotiation_packet_;
-
- // When packets could not be sent because the socket was not writable,
- // they are added to this std::list. All corresponding frames are in
- // unacked_packets_ if they are to be retransmitted. Packets encrypted_buffer
- // fields are owned by the QueuedPacketList, in order to ensure they outlast
- // the original scope of the SerializedPacket.
- QueuedPacketList queued_packets_;
-
- // If true, then crypto packets will be saved as termination packets.
- bool save_crypto_packets_as_termination_packets_;
-
- // Contains the connection close packets if the connection has been closed.
- std::unique_ptr<std::vector<std::unique_ptr<QuicEncryptedPacket>>>
- termination_packets_;
-
- // Determines whether or not a connection close packet is sent to the peer
- // after idle timeout due to lack of network activity.
- // This is particularly important on mobile, where waking up the radio is
- // undesirable.
- ConnectionCloseBehavior idle_timeout_connection_close_behavior_;
-
- // When true, close the QUIC connection after 5 RTOs. Due to the min rto of
- // 200ms, this is over 5 seconds.
- bool close_connection_after_five_rtos_;
-
- QuicReceivedPacketManager received_packet_manager_;
- QuicSentEntropyManager sent_entropy_manager_;
-
- // Indicates whether an ack should be sent the next time we try to write.
- bool ack_queued_;
- // How many retransmittable packets have arrived without sending an ack.
- QuicPacketCount num_retransmittable_packets_received_since_last_ack_sent_;
- // Whether there were missing packets in the last sent ack.
- bool last_ack_had_missing_packets_;
- // How many consecutive packets have arrived without sending an ack.
- QuicPacketCount num_packets_received_since_last_ack_sent_;
- // Indicates how many consecutive times an ack has arrived which indicates
- // the peer needs to stop waiting for some packets.
- int stop_waiting_count_;
- // Indicates the current ack mode, defaults to acking every 2 packets.
- AckMode ack_mode_;
- // The max delay in fraction of min_rtt to use when sending decimated acks.
- float ack_decimation_delay_;
-
- // Indicates the retransmit alarm is going to be set by the
- // ScopedRetransmitAlarmDelayer
- bool delay_setting_retransmission_alarm_;
- // Indicates the retransmission alarm needs to be set.
- bool pending_retransmission_alarm_;
-
- // If true, defer sending data in response to received packets to the
- // SendAlarm.
- bool defer_send_in_response_to_packets_;
-
- // Arena to store class implementations within the QuicConnection.
- QuicConnectionArena arena_;
-
- // An alarm that fires when an ACK should be sent to the peer.
- QuicArenaScopedPtr<QuicAlarm> ack_alarm_;
- // An alarm that fires when a packet needs to be retransmitted.
- QuicArenaScopedPtr<QuicAlarm> retransmission_alarm_;
- // An alarm that is scheduled when the SentPacketManager requires a delay
- // before sending packets and fires when the packet may be sent.
- QuicArenaScopedPtr<QuicAlarm> send_alarm_;
- // An alarm that is scheduled when the connection can still write and there
- // may be more data to send.
- // TODO(ianswett): Remove resume_writes_alarm when deprecating
- // FLAGS_quic_only_one_sending_alarm
- QuicArenaScopedPtr<QuicAlarm> resume_writes_alarm_;
- // An alarm that fires when the connection may have timed out.
- QuicArenaScopedPtr<QuicAlarm> timeout_alarm_;
- // An alarm that fires when a ping should be sent.
- QuicArenaScopedPtr<QuicAlarm> ping_alarm_;
- // An alarm that fires when an MTU probe should be sent.
- QuicArenaScopedPtr<QuicAlarm> mtu_discovery_alarm_;
-
- // Neither visitor is owned by this class.
- QuicConnectionVisitorInterface* visitor_;
- QuicConnectionDebugVisitor* debug_visitor_;
-
- QuicPacketGenerator packet_generator_;
-
- // Network idle time before this connection is closed.
- QuicTime::Delta idle_network_timeout_;
- // The connection will wait this long for the handshake to complete.
- QuicTime::Delta handshake_timeout_;
-
- // Statistics for this session.
- QuicConnectionStats stats_;
-
- // The time that we got a packet for this connection.
- // This is used for timeouts, and does not indicate the packet was processed.
- QuicTime time_of_last_received_packet_;
-
- // The last time this connection began sending a new (non-retransmitted)
- // packet.
- QuicTime time_of_last_sent_new_packet_;
-
- // The the send time of the first retransmittable packet sent after
- // |time_of_last_received_packet_|.
- QuicTime last_send_for_timeout_;
-
- // packet number of the last sent packet. Packets are guaranteed to be sent
- // in packet number order.
- QuicPacketNumber packet_number_of_last_sent_packet_;
-
- // Sent packet manager which tracks the status of packets sent by this
- // connection and contains the send and receive algorithms to determine when
- // to send packets.
- std::unique_ptr<QuicSentPacketManagerInterface> sent_packet_manager_;
-
- // The state of connection in version negotiation finite state machine.
- QuicVersionNegotiationState version_negotiation_state_;
-
- // Tracks if the connection was created by the server or the client.
- Perspective perspective_;
-
- // True by default. False if we've received or sent an explicit connection
- // close.
- bool connected_;
-
- // Destination address of the last received packet.
- IPEndPoint last_packet_destination_address_;
-
- // Source address of the last received packet.
- IPEndPoint last_packet_source_address_;
-
- // Set to false if the connection should not send truncated connection IDs to
- // the peer, even if the peer supports it.
- bool can_truncate_connection_ids_;
-
- // If non-empty this contains the set of versions received in a
- // version negotiation packet.
- QuicVersionVector server_supported_versions_;
-
- // The size of the packet we are targeting while doing path MTU discovery.
- QuicByteCount mtu_discovery_target_;
-
- // The number of MTU probes already sent.
- size_t mtu_probe_count_;
-
- // The number of packets between MTU probes.
- QuicPacketCount packets_between_mtu_probes_;
-
- // The packet number of the packet after which the next MTU probe will be
- // sent.
- QuicPacketNumber next_mtu_probe_at_;
-
- // The size of the largest packet received from peer.
- QuicByteCount largest_received_packet_size_;
-
- // Whether a GoAway has been sent.
- bool goaway_sent_;
-
- // Whether a GoAway has been received.
- bool goaway_received_;
-
- // If true, multipath is enabled for this connection.
- bool multipath_enabled_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicConnection);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CONNECTION_H_
diff --git a/chromium/net/quic/quic_connection_logger.cc b/chromium/net/quic/quic_connection_logger.cc
deleted file mode 100644
index fd4c088178e..00000000000
--- a/chromium/net/quic/quic_connection_logger.cc
+++ /dev/null
@@ -1,898 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_connection_logger.h"
-
-#include <algorithm>
-#include <limits>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/metrics/histogram_base.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/sparse_histogram.h"
-#include "base/profiler/scoped_tracker.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/values.h"
-#include "net/base/ip_address.h"
-#include "net/cert/x509_certificate.h"
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/quic_address_mismatch.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_socket_address_coder.h"
-#include "net/quic/quic_time.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-
-namespace {
-
-// We have ranges-of-buckets in the cumulative histogram (covering 21 packet
-// sequences) of length 2, 3, 4, ... 22.
-// Hence the largest sample is bounded by the sum of those numbers.
-const int kBoundingSampleInCumulativeHistogram = ((2 + 22) * 21) / 2;
-
-std::unique_ptr<base::Value> NetLogQuicPacketCallback(
- const IPEndPoint* self_address,
- const IPEndPoint* peer_address,
- size_t packet_size,
- NetLogCaptureMode /* capture_mode */) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetString("self_address", self_address->ToString());
- dict->SetString("peer_address", peer_address->ToString());
- dict->SetInteger("size", packet_size);
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicPacketSentCallback(
- const SerializedPacket& serialized_packet,
- TransmissionType transmission_type,
- QuicTime sent_time,
- NetLogCaptureMode /* capture_mode */) {
- 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));
- dict->SetInteger("size", serialized_packet.encrypted_length);
- dict->SetString("sent_time_us",
- base::Int64ToString(sent_time.ToDebuggingValue()));
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicPacketRetransmittedCallback(
- QuicPacketNumber old_packet_number,
- 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));
- return std::move(dict);
-}
-
-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));
- return std::move(dict);
-}
-
-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->public_header.connection_id));
- dict->SetInteger("reset_flag", header->public_header.reset_flag);
- dict->SetInteger("version_flag", header->public_header.version_flag);
- dict->SetString("packet_number", base::Uint64ToString(header->packet_number));
- dict->SetInteger("entropy_flag", header->entropy_flag);
- dict->SetInteger("fec_flag", header->fec_flag);
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicStreamFrameCallback(
- const QuicStreamFrame* frame,
- NetLogCaptureMode /* capture_mode */) {
- 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->SetInteger("length", frame->data_length);
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicAckFrameCallback(
- const QuicAckFrame* frame,
- NetLogCaptureMode /* capture_mode */) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetString("largest_observed",
- base::Uint64ToString(frame->largest_observed));
- dict->SetString("delta_time_largest_observed_us",
- base::Int64ToString(frame->ack_delay_time.ToMicroseconds()));
- if (frame->missing) {
- // Entropy and Truncated are not present in v34 and above.
- dict->SetInteger("entropy_hash", frame->entropy_hash);
- dict->SetBoolean("truncated", frame->is_truncated);
- }
-
- base::ListValue* missing = new base::ListValue();
- dict->Set("missing_packets", missing);
- if (frame->missing) {
- for (QuicPacketNumber packet : frame->packets)
- missing->AppendString(base::Uint64ToString(packet));
- } else if (!frame->packets.Empty()) {
- // 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->largest_observed; ++packet) {
- if (!frame->packets.Contains(packet)) {
- missing->AppendString(base::Uint64ToString(packet));
- }
- }
- }
-
- base::ListValue* received = new base::ListValue();
- dict->Set("received_packet_times", received);
- const PacketTimeVector& received_times = frame->received_packet_times;
- for (PacketTimeVector::const_iterator it = received_times.begin();
- it != received_times.end(); ++it) {
- std::unique_ptr<base::DictionaryValue> info(new base::DictionaryValue());
- info->SetInteger("packet_number", static_cast<int>(it->first));
- info->SetString("received",
- base::Int64ToString(it->second.ToDebuggingValue()));
- received->Append(std::move(info));
- }
-
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicRstStreamFrameCallback(
- const QuicRstStreamFrame* frame,
- NetLogCaptureMode /* capture_mode */) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetInteger("stream_id", frame->stream_id);
- dict->SetInteger("quic_rst_stream_error", frame->error_code);
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicConnectionCloseFrameCallback(
- const QuicConnectionCloseFrame* frame,
- NetLogCaptureMode /* capture_mode */) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetInteger("quic_error", frame->error_code);
- dict->SetString("details", frame->error_details);
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicWindowUpdateFrameCallback(
- const QuicWindowUpdateFrame* frame,
- 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));
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicBlockedFrameCallback(
- const QuicBlockedFrame* frame,
- NetLogCaptureMode /* capture_mode */) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetInteger("stream_id", frame->stream_id);
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicGoAwayFrameCallback(
- const QuicGoAwayFrame* frame,
- NetLogCaptureMode /* capture_mode */) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetInteger("quic_error", frame->error_code);
- dict->SetInteger("last_good_stream_id", frame->last_good_stream_id);
- dict->SetString("reason_phrase", frame->reason_phrase);
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicStopWaitingFrameCallback(
- const QuicStopWaitingFrame* frame,
- NetLogCaptureMode /* capture_mode */) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- base::DictionaryValue* sent_info = new base::DictionaryValue();
- dict->Set("sent_info", sent_info);
- sent_info->SetString("least_unacked",
- base::Uint64ToString(frame->least_unacked));
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicVersionNegotiationPacketCallback(
- const QuicVersionNegotiationPacket* packet,
- NetLogCaptureMode /* capture_mode */) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- base::ListValue* versions = new base::ListValue();
- dict->Set("versions", versions);
- for (QuicVersionVector::const_iterator it = packet->versions.begin();
- it != packet->versions.end(); ++it) {
- versions->AppendString(QuicVersionToString(*it));
- }
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicCryptoHandshakeMessageCallback(
- const CryptoHandshakeMessage* message,
- NetLogCaptureMode /* capture_mode */) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetString("quic_crypto_handshake_message", message->DebugString());
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicOnConnectionClosedCallback(
- QuicErrorCode error,
- ConnectionCloseSource source,
- NetLogCaptureMode /* capture_mode */) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetInteger("quic_error", error);
- dict->SetBoolean("from_peer",
- source == ConnectionCloseSource::FROM_PEER ? true : false);
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicCertificateVerifiedCallback(
- scoped_refptr<X509Certificate> cert,
- NetLogCaptureMode /* capture_mode */) {
- // Only the subjects are logged so that we can investigate connection pooling.
- // More fields could be logged in the future.
- std::vector<std::string> dns_names;
- cert->GetDNSNames(&dns_names);
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- base::ListValue* subjects = new base::ListValue();
- for (std::vector<std::string>::const_iterator it = dns_names.begin();
- it != dns_names.end(); it++) {
- subjects->AppendString(*it);
- }
- dict->Set("subjects", subjects);
- return std::move(dict);
-}
-
-void UpdatePacketGapSentHistogram(size_t num_consecutive_missing_packets) {
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.PacketGapSent",
- num_consecutive_missing_packets);
-}
-
-void UpdatePublicResetAddressMismatchHistogram(
- const IPEndPoint& server_hello_address,
- const IPEndPoint& public_reset_address) {
- int sample = GetAddressMismatch(server_hello_address, public_reset_address);
- // We are seemingly talking to an older server that does not support the
- // feature, so we can't report the results in the histogram.
- if (sample < 0) {
- return;
- }
- UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.PublicResetAddressMismatch2",
- sample, QUIC_ADDRESS_MISMATCH_MAX);
-}
-
-// If |address| is an IPv4-mapped IPv6 address, returns ADDRESS_FAMILY_IPV4
-// instead of ADDRESS_FAMILY_IPV6. Othewise, behaves like GetAddressFamily().
-AddressFamily GetRealAddressFamily(const IPAddress& address) {
- return address.IsIPv4MappedIPv6() ? ADDRESS_FAMILY_IPV4
- : GetAddressFamily(address);
-}
-
-} // namespace
-
-QuicConnectionLogger::QuicConnectionLogger(
- QuicSpdySession* session,
- const char* const connection_description,
- std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
- const BoundNetLog& net_log)
- : net_log_(net_log),
- session_(session),
- last_received_packet_number_(0),
- last_received_packet_size_(0),
- previous_received_packet_size_(0),
- last_packet_sent_time_(base::TimeTicks()),
- largest_received_packet_number_(0),
- largest_received_missing_packet_number_(0),
- num_out_of_order_received_packets_(0),
- num_out_of_order_large_received_packets_(0),
- num_packets_received_(0),
- num_truncated_acks_sent_(0),
- num_truncated_acks_received_(0),
- num_frames_received_(0),
- num_duplicate_frames_received_(0),
- num_incorrect_connection_ids_(0),
- num_undecryptable_packets_(0),
- num_duplicate_packets_(0),
- num_blocked_frames_received_(0),
- num_blocked_frames_sent_(0),
- connection_description_(connection_description),
- socket_performance_watcher_(std::move(socket_performance_watcher)) {}
-
-QuicConnectionLogger::~QuicConnectionLogger() {
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.OutOfOrderPacketsReceived",
- num_out_of_order_received_packets_);
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.OutOfOrderLargePacketsReceived",
- num_out_of_order_large_received_packets_);
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.TruncatedAcksSent",
- num_truncated_acks_sent_);
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.TruncatedAcksReceived",
- num_truncated_acks_received_);
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.IncorrectConnectionIDsReceived",
- num_incorrect_connection_ids_);
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.UndecryptablePacketsReceived",
- num_undecryptable_packets_);
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.DuplicatePacketsReceived",
- num_duplicate_packets_);
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.BlockedFrames.Received",
- num_blocked_frames_received_);
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.BlockedFrames.Sent",
- num_blocked_frames_sent_);
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.HeadersStream.EarlyFramesReceived",
- session_->headers_stream()->num_early_frames_received());
-
- if (num_frames_received_ > 0) {
- int duplicate_stream_frame_per_thousand =
- num_duplicate_frames_received_ * 1000 / num_frames_received_;
- if (num_packets_received_ < 100) {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Net.QuicSession.StreamFrameDuplicatedShortConnection",
- duplicate_stream_frame_per_thousand, 1, 1000, 75);
- } else {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Net.QuicSession.StreamFrameDuplicatedLongConnection",
- duplicate_stream_frame_per_thousand, 1, 1000, 75);
- }
- }
-
- RecordLossHistograms();
-}
-
-void QuicConnectionLogger::OnFrameAddedToPacket(const QuicFrame& frame) {
- switch (frame.type) {
- case PADDING_FRAME:
- break;
- case STREAM_FRAME:
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_SESSION_STREAM_FRAME_SENT,
- base::Bind(&NetLogQuicStreamFrameCallback, frame.stream_frame));
- break;
- case ACK_FRAME: {
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_SESSION_ACK_FRAME_SENT,
- base::Bind(&NetLogQuicAckFrameCallback, frame.ack_frame));
- // Missing packets histogram only relevant for v33 and lower
- // TODO(rch, rtenneti) sort out histograms for v34+
- if (session_->connection()->version() > QUIC_VERSION_33) {
- break;
- }
- const PacketNumberQueue& missing_packets = frame.ack_frame->packets;
- const uint8_t max_ranges = std::numeric_limits<uint8_t>::max();
- // Compute an upper bound on the number of NACK ranges. If the bound
- // is below the max, then it clearly isn't truncated.
- if (missing_packets.NumPacketsSlow() < max_ranges ||
- (missing_packets.Max() - missing_packets.Min() -
- missing_packets.NumPacketsSlow() + 1) < max_ranges) {
- break;
- }
- size_t num_ranges = 0;
- QuicPacketNumber last_missing = 0;
- for (QuicPacketNumber packet : missing_packets) {
- if (packet != last_missing + 1 && ++num_ranges >= max_ranges) {
- ++num_truncated_acks_sent_;
- break;
- }
- last_missing = packet;
- }
- break;
- }
- case RST_STREAM_FRAME:
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeClient",
- frame.rst_stream_frame->error_code);
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_RST_STREAM_FRAME_SENT,
- base::Bind(&NetLogQuicRstStreamFrameCallback,
- frame.rst_stream_frame));
- break;
- case CONNECTION_CLOSE_FRAME:
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_CONNECTION_CLOSE_FRAME_SENT,
- base::Bind(&NetLogQuicConnectionCloseFrameCallback,
- frame.connection_close_frame));
- break;
- case GOAWAY_FRAME:
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_SESSION_GOAWAY_FRAME_SENT,
- base::Bind(&NetLogQuicGoAwayFrameCallback, frame.goaway_frame));
- break;
- case WINDOW_UPDATE_FRAME:
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_WINDOW_UPDATE_FRAME_SENT,
- base::Bind(&NetLogQuicWindowUpdateFrameCallback,
- frame.window_update_frame));
- break;
- case BLOCKED_FRAME:
- ++num_blocked_frames_sent_;
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_SESSION_BLOCKED_FRAME_SENT,
- base::Bind(&NetLogQuicBlockedFrameCallback, frame.blocked_frame));
- break;
- case STOP_WAITING_FRAME:
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_SENT,
- base::Bind(&NetLogQuicStopWaitingFrameCallback,
- frame.stop_waiting_frame));
- break;
- case PING_FRAME:
- UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ConnectionFlowControlBlocked",
- session_->IsConnectionFlowControlBlocked());
- UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.StreamFlowControlBlocked",
- session_->IsStreamFlowControlBlocked());
- // PingFrame has no contents to log, so just record that it was sent.
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PING_FRAME_SENT);
- break;
- case MTU_DISCOVERY_FRAME:
- // MtuDiscoveryFrame is PingFrame on wire, it does not have any payload.
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_MTU_DISCOVERY_FRAME_SENT);
- break;
- default:
- DCHECK(false) << "Illegal frame type: " << frame.type;
- }
-}
-
-void QuicConnectionLogger::OnPacketSent(
- const SerializedPacket& serialized_packet,
- QuicPathId /* original_path_id */,
- QuicPacketNumber original_packet_number,
- TransmissionType transmission_type,
- QuicTime sent_time) {
- if (original_packet_number == 0) {
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_SESSION_PACKET_SENT,
- base::Bind(&NetLogQuicPacketSentCallback, serialized_packet,
- transmission_type, sent_time));
- } else {
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_SESSION_PACKET_RETRANSMITTED,
- base::Bind(&NetLogQuicPacketRetransmittedCallback,
- original_packet_number, serialized_packet.packet_number));
- }
- // Record time duration from last packet sent to the new packet sent.
- if (last_packet_sent_time_.IsInitialized()) {
- UMA_HISTOGRAM_CUSTOM_TIMES(
- "Net.QuicTimeBetweenTwoPacketSent",
- base::TimeDelta::FromMilliseconds(
- sent_time.Subtract(last_packet_sent_time_).ToMilliseconds()),
- base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
- 100);
- }
- last_packet_sent_time_ = sent_time;
-}
-
-void QuicConnectionLogger::OnPacketReceived(const IPEndPoint& self_address,
- const IPEndPoint& peer_address,
- const QuicEncryptedPacket& packet) {
- if (local_address_from_self_.GetFamily() == ADDRESS_FAMILY_UNSPECIFIED) {
- local_address_from_self_ = self_address;
- UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionTypeFromSelf",
- GetRealAddressFamily(self_address.address()),
- ADDRESS_FAMILY_LAST);
- }
-
- previous_received_packet_size_ = last_received_packet_size_;
- last_received_packet_size_ = packet.length();
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PACKET_RECEIVED,
- base::Bind(&NetLogQuicPacketCallback, &self_address,
- &peer_address, packet.length()));
-}
-
-void QuicConnectionLogger::OnUnauthenticatedHeader(
- const QuicPacketHeader& header) {
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_SESSION_UNAUTHENTICATED_PACKET_HEADER_RECEIVED,
- base::Bind(&NetLogQuicPacketHeaderCallback, &header));
-}
-
-void QuicConnectionLogger::OnIncorrectConnectionId(
- QuicConnectionId connection_id) {
- ++num_incorrect_connection_ids_;
-}
-
-void QuicConnectionLogger::OnUndecryptablePacket() {
- ++num_undecryptable_packets_;
-}
-
-void QuicConnectionLogger::OnDuplicatePacket(QuicPacketNumber packet_number) {
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_SESSION_DUPLICATE_PACKET_RECEIVED,
- base::Bind(&NetLogQuicDuplicatePacketCallback, packet_number));
- ++num_duplicate_packets_;
-}
-
-void QuicConnectionLogger::OnProtocolVersionMismatch(
- QuicVersion received_version) {
- // TODO(rtenneti): Add logging.
-}
-
-void QuicConnectionLogger::OnPacketHeader(const QuicPacketHeader& header) {
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PACKET_AUTHENTICATED);
- ++num_packets_received_;
- if (largest_received_packet_number_ < header.packet_number) {
- QuicPacketNumber delta =
- header.packet_number - largest_received_packet_number_;
- if (delta > 1) {
- // There is a gap between the largest packet previously received and
- // the current packet. This indicates either loss, or out-of-order
- // delivery.
- UMA_HISTOGRAM_COUNTS("Net.QuicSession.PacketGapReceived",
- static_cast<base::HistogramBase::Sample>(delta - 1));
- }
- largest_received_packet_number_ = header.packet_number;
- }
- if (header.packet_number < received_packets_.size()) {
- received_packets_[static_cast<size_t>(header.packet_number)] = true;
- }
- if (header.packet_number < last_received_packet_number_) {
- ++num_out_of_order_received_packets_;
- if (previous_received_packet_size_ < last_received_packet_size_)
- ++num_out_of_order_large_received_packets_;
- UMA_HISTOGRAM_COUNTS(
- "Net.QuicSession.OutOfOrderGapReceived",
- static_cast<base::HistogramBase::Sample>(last_received_packet_number_ -
- header.packet_number));
- }
- last_received_packet_number_ = header.packet_number;
-}
-
-void QuicConnectionLogger::OnStreamFrame(const QuicStreamFrame& frame) {
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_STREAM_FRAME_RECEIVED,
- base::Bind(&NetLogQuicStreamFrameCallback, &frame));
-}
-
-void QuicConnectionLogger::OnAckFrame(const QuicAckFrame& frame) {
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_ACK_FRAME_RECEIVED,
- base::Bind(&NetLogQuicAckFrameCallback, &frame));
-
- const size_t kApproximateLargestSoloAckBytes = 100;
- if (last_received_packet_number_ < received_acks_.size() &&
- last_received_packet_size_ < kApproximateLargestSoloAckBytes) {
- received_acks_[static_cast<size_t>(last_received_packet_number_)] = true;
- }
-
- if (frame.is_truncated)
- ++num_truncated_acks_received_;
-
- if (frame.packets.Empty())
- return;
-
- // TODO(rch, rtenneti) sort out histograms for QUIC_VERSION_34 and above.
- if (session_->connection()->version() > QUIC_VERSION_33) {
- return;
- }
- const PacketNumberQueue& missing_packets = frame.packets;
- PacketNumberQueue::const_iterator it =
- missing_packets.lower_bound(largest_received_missing_packet_number_);
- if (it == missing_packets.end())
- return;
-
- if (*it == largest_received_missing_packet_number_) {
- ++it;
- if (it == missing_packets.end())
- return;
- }
- // Scan through the list and log consecutive ranges of missing packets.
- size_t num_consecutive_missing_packets = 0;
- QuicPacketNumber previous_missing_packet = *it - 1;
- while (it != missing_packets.end()) {
- if (previous_missing_packet == *it - 1) {
- ++num_consecutive_missing_packets;
- } else {
- DCHECK_NE(0u, num_consecutive_missing_packets);
- UpdatePacketGapSentHistogram(num_consecutive_missing_packets);
- // Make sure this packet it included in the count.
- num_consecutive_missing_packets = 1;
- }
- previous_missing_packet = *it;
- ++it;
- }
- if (num_consecutive_missing_packets != 0) {
- UpdatePacketGapSentHistogram(num_consecutive_missing_packets);
- }
- largest_received_missing_packet_number_ = missing_packets.Max();
-}
-
-void QuicConnectionLogger::OnStopWaitingFrame(
- const QuicStopWaitingFrame& frame) {
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_RECEIVED,
- base::Bind(&NetLogQuicStopWaitingFrameCallback, &frame));
-}
-
-void QuicConnectionLogger::OnRstStreamFrame(const QuicRstStreamFrame& frame) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeServer",
- frame.error_code);
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_RST_STREAM_FRAME_RECEIVED,
- base::Bind(&NetLogQuicRstStreamFrameCallback, &frame));
-}
-
-void QuicConnectionLogger::OnConnectionCloseFrame(
- const QuicConnectionCloseFrame& frame) {
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_SESSION_CONNECTION_CLOSE_FRAME_RECEIVED,
- base::Bind(&NetLogQuicConnectionCloseFrameCallback, &frame));
-}
-
-void QuicConnectionLogger::OnWindowUpdateFrame(
- const QuicWindowUpdateFrame& frame) {
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_WINDOW_UPDATE_FRAME_RECEIVED,
- base::Bind(&NetLogQuicWindowUpdateFrameCallback, &frame));
-}
-
-void QuicConnectionLogger::OnBlockedFrame(const QuicBlockedFrame& frame) {
- ++num_blocked_frames_received_;
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_BLOCKED_FRAME_RECEIVED,
- base::Bind(&NetLogQuicBlockedFrameCallback, &frame));
-}
-
-void QuicConnectionLogger::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
- UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.GoAwayReceivedForConnectionMigration",
- frame.error_code == QUIC_ERROR_MIGRATING_PORT);
-
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_GOAWAY_FRAME_RECEIVED,
- base::Bind(&NetLogQuicGoAwayFrameCallback, &frame));
-}
-
-void QuicConnectionLogger::OnPingFrame(const QuicPingFrame& frame) {
- // PingFrame has no contents to log, so just record that it was received.
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PING_FRAME_RECEIVED);
-}
-
-void QuicConnectionLogger::OnPublicResetPacket(
- const QuicPublicResetPacket& packet) {
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PUBLIC_RESET_PACKET_RECEIVED);
- UpdatePublicResetAddressMismatchHistogram(local_address_from_shlo_,
- packet.client_address);
-}
-
-void QuicConnectionLogger::OnVersionNegotiationPacket(
- const QuicVersionNegotiationPacket& packet) {
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_SESSION_VERSION_NEGOTIATION_PACKET_RECEIVED,
- base::Bind(&NetLogQuicVersionNegotiationPacketCallback, &packet));
-}
-
-void QuicConnectionLogger::OnCryptoHandshakeMessageReceived(
- const CryptoHandshakeMessage& message) {
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_RECEIVED,
- base::Bind(&NetLogQuicCryptoHandshakeMessageCallback, &message));
-
- if (message.tag() == kSHLO) {
- StringPiece address;
- QuicSocketAddressCoder decoder;
- if (message.GetStringPiece(kCADR, &address) &&
- decoder.Decode(address.data(), address.size())) {
- local_address_from_shlo_ = IPEndPoint(decoder.ip(), decoder.port());
- UMA_HISTOGRAM_ENUMERATION(
- "Net.QuicSession.ConnectionTypeFromPeer",
- GetRealAddressFamily(local_address_from_shlo_.address()),
- ADDRESS_FAMILY_LAST);
- }
- }
-}
-
-void QuicConnectionLogger::OnCryptoHandshakeMessageSent(
- const CryptoHandshakeMessage& message) {
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_SENT,
- base::Bind(&NetLogQuicCryptoHandshakeMessageCallback, &message));
-}
-
-void QuicConnectionLogger::OnConnectionClosed(QuicErrorCode error,
- const string& error_details,
- ConnectionCloseSource source) {
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_SESSION_CLOSED,
- base::Bind(&NetLogQuicOnConnectionClosedCallback, error, source));
-}
-
-void QuicConnectionLogger::OnSuccessfulVersionNegotiation(
- const QuicVersion& version) {
- string quic_version = QuicVersionToString(version);
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_VERSION_NEGOTIATED,
- NetLog::StringCallback("version", &quic_version));
-}
-
-void QuicConnectionLogger::UpdateReceivedFrameCounts(
- QuicStreamId stream_id,
- int num_frames_received,
- int num_duplicate_frames_received) {
- if (stream_id != kCryptoStreamId) {
- num_frames_received_ += num_frames_received;
- num_duplicate_frames_received_ += num_duplicate_frames_received;
- }
-}
-
-void QuicConnectionLogger::OnCertificateVerified(
- const CertVerifyResult& result) {
- if (result.cert_status == CERT_STATUS_INVALID) {
- net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_CERTIFICATE_VERIFY_FAILED);
- return;
- }
- net_log_.AddEvent(
- NetLog::TYPE_QUIC_SESSION_CERTIFICATE_VERIFIED,
- base::Bind(&NetLogQuicCertificateVerifiedCallback, result.verified_cert));
-}
-
-base::HistogramBase* QuicConnectionLogger::GetPacketNumberHistogram(
- const char* statistic_name) const {
- string prefix("Net.QuicSession.PacketReceived_");
- return base::LinearHistogram::FactoryGet(
- prefix + statistic_name + connection_description_, 1,
- received_packets_.size(), received_packets_.size() + 1,
- base::HistogramBase::kUmaTargetedHistogramFlag);
-}
-
-base::HistogramBase* QuicConnectionLogger::Get6PacketHistogram(
- const char* which_6) const {
- // This histogram takes a binary encoding of the 6 consecutive packets
- // received. As a result, there are 64 possible sample-patterns.
- string prefix("Net.QuicSession.6PacketsPatternsReceived_");
- return base::LinearHistogram::FactoryGet(
- prefix + which_6 + connection_description_, 1, 64, 65,
- base::HistogramBase::kUmaTargetedHistogramFlag);
-}
-
-base::HistogramBase* QuicConnectionLogger::Get21CumulativeHistogram(
- const char* which_21) const {
- // This histogram contains, for each sequence of 21 packets, the results from
- // 21 distinct questions about that sequence. Conceptually the histogtram is
- // broken into 21 distinct ranges, and one sample is added into each of those
- // ranges whenever we process a set of 21 packets.
- // There is a little rendundancy, as each "range" must have the same number
- // of samples, all told, but the histogram is a tad easier to read this way.
- // The questions are:
- // Was the first packet present (bucket 0==>no; bucket 1==>yes)
- // Of the first two packets, how many were present? (bucket 2==> none;
- // bucket 3==> 1 of 2; bucket 4==> 2 of 2)
- // Of the first three packets, how many were present? (bucket 5==>none;
- // bucket 6==> 1 of 3; bucket 7==> 2 of 3; bucket 8==> 3 of 3).
- // etc.
- string prefix("Net.QuicSession.21CumulativePacketsReceived_");
- return base::LinearHistogram::FactoryGet(
- prefix + which_21 + connection_description_, 1,
- kBoundingSampleInCumulativeHistogram,
- kBoundingSampleInCumulativeHistogram + 1,
- base::HistogramBase::kUmaTargetedHistogramFlag);
-}
-
-// static
-void QuicConnectionLogger::AddTo21CumulativeHistogram(
- base::HistogramBase* histogram,
- int bit_mask_of_packets,
- int valid_bits_in_mask) {
- DCHECK_LE(valid_bits_in_mask, 21);
- DCHECK_LT(bit_mask_of_packets, 1 << 21);
- const int blank_bits_in_mask = 21 - valid_bits_in_mask;
- DCHECK_EQ(bit_mask_of_packets & ((1 << blank_bits_in_mask) - 1), 0);
- bit_mask_of_packets >>= blank_bits_in_mask;
- int bits_so_far = 0;
- int range_start = 0;
- for (int i = 1; i <= valid_bits_in_mask; ++i) {
- bits_so_far += bit_mask_of_packets & 1;
- bit_mask_of_packets >>= 1;
- DCHECK_LT(range_start + bits_so_far, kBoundingSampleInCumulativeHistogram);
- histogram->Add(range_start + bits_so_far);
- range_start += i + 1;
- }
-}
-
-float QuicConnectionLogger::ReceivedPacketLossRate() const {
- if (largest_received_packet_number_ <= num_packets_received_)
- return 0.0f;
- float num_received = largest_received_packet_number_ - num_packets_received_;
- return num_received / largest_received_packet_number_;
-}
-
-void QuicConnectionLogger::OnRttChanged(QuicTime::Delta rtt) const {
- // Notify socket performance watcher of the updated RTT value.
- if (!socket_performance_watcher_)
- return;
-
- int64_t microseconds = rtt.ToMicroseconds();
- if (microseconds != 0) {
- socket_performance_watcher_->OnUpdatedRTTAvailable(
- base::TimeDelta::FromMicroseconds(rtt.ToMicroseconds()));
- }
-}
-
-void QuicConnectionLogger::RecordAggregatePacketLossRate() const {
- // For short connections under 22 packets in length, we'll rely on the
- // Net.QuicSession.21CumulativePacketsReceived_* histogram to indicate packet
- // loss rates. This way we avoid tremendously anomalous contributions to our
- // histogram. (e.g., if we only got 5 packets, but lost 1, we'd otherwise
- // record a 20% loss in this histogram!). We may still get some strange data
- // (1 loss in 22 is still high :-/).
- if (largest_received_packet_number_ <= 21)
- return;
-
- string prefix("Net.QuicSession.PacketLossRate_");
- base::HistogramBase* histogram = base::Histogram::FactoryGet(
- prefix + connection_description_, 1, 1000, 75,
- base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->Add(static_cast<base::HistogramBase::Sample>(
- ReceivedPacketLossRate() * 1000));
-}
-
-void QuicConnectionLogger::RecordLossHistograms() const {
- if (largest_received_packet_number_ == 0)
- return; // Connection was never used.
- RecordAggregatePacketLossRate();
-
- base::HistogramBase* is_not_ack_histogram =
- GetPacketNumberHistogram("IsNotAck_");
- base::HistogramBase* is_an_ack_histogram =
- GetPacketNumberHistogram("IsAnAck_");
- base::HistogramBase* packet_arrived_histogram =
- GetPacketNumberHistogram("Ack_");
- base::HistogramBase* packet_missing_histogram =
- GetPacketNumberHistogram("Nack_");
- base::HistogramBase* ongoing_cumulative_packet_histogram =
- Get21CumulativeHistogram("Some21s_");
- base::HistogramBase* first_cumulative_packet_histogram =
- Get21CumulativeHistogram("First21_");
- base::HistogramBase* six_packet_histogram = Get6PacketHistogram("Some6s_");
-
- DCHECK_EQ(received_packets_.size(), received_acks_.size());
- const QuicPacketNumber last_index = std::min<QuicPacketNumber>(
- received_packets_.size() - 1, largest_received_packet_number_);
- const QuicPacketNumber index_of_first_21_contribution =
- std::min<QuicPacketNumber>(21, last_index);
- // Bit pattern of consecutively received packets that is maintained as we scan
- // through the received_packets_ vector. Less significant bits correspond to
- // less recent packets, and only the low order 21 bits are ever defined.
- // Bit is 1 iff corresponding packet was received.
- int packet_pattern_21 = 0;
- // Zero is an invalid packet sequence number.
- DCHECK(!received_packets_[0]);
- for (size_t i = 1; i <= last_index; ++i) {
- if (received_acks_[i])
- is_an_ack_histogram->Add(i);
- else
- is_not_ack_histogram->Add(i);
-
- packet_pattern_21 >>= 1;
- if (received_packets_[i]) {
- packet_arrived_histogram->Add(i);
- packet_pattern_21 |= (1 << 20); // Turn on the 21st bit.
- } else {
- packet_missing_histogram->Add(i);
- }
-
- if (i == index_of_first_21_contribution) {
- AddTo21CumulativeHistogram(first_cumulative_packet_histogram,
- packet_pattern_21, i);
- }
- // We'll just record for non-overlapping ranges, to reduce histogramming
- // cost for now. Each call does 21 separate histogram additions.
- if (i > 21 || i % 21 == 0) {
- AddTo21CumulativeHistogram(ongoing_cumulative_packet_histogram,
- packet_pattern_21, 21);
- }
-
- if (i < 6)
- continue; // Not enough packets to do any pattern recording.
- int recent_6_mask = packet_pattern_21 >> 15;
- DCHECK_LT(recent_6_mask, 64);
- if (i == 6) {
- Get6PacketHistogram("First6_")->Add(recent_6_mask);
- continue;
- }
- // Record some overlapping patterns, to get a better picture, since this is
- // not very expensive.
- if (i % 3 == 0)
- six_packet_histogram->Add(recent_6_mask);
- }
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_connection_logger.h b/chromium/net/quic/quic_connection_logger.h
deleted file mode 100644
index 2a28369f8d7..00000000000
--- a/chromium/net/quic/quic_connection_logger.h
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_CONNECTION_LOGGER_H_
-#define NET_QUIC_QUIC_CONNECTION_LOGGER_H_
-
-#include <stddef.h>
-
-#include <bitset>
-#include <string>
-
-#include "base/macros.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/network_change_notifier.h"
-#include "net/cert/cert_verify_result.h"
-#include "net/log/net_log.h"
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_spdy_session.h"
-#include "net/socket/socket_performance_watcher.h"
-
-namespace base {
-class HistogramBase;
-}
-
-namespace net {
-namespace test {
-class QuicConnectionLoggerPeer;
-} // namespace test
-
-
-// This class is a debug visitor of a QuicConnection which logs
-// events to |net_log|.
-class NET_EXPORT_PRIVATE QuicConnectionLogger
- : public QuicConnectionDebugVisitor,
- public QuicPacketCreator::DebugDelegate {
- public:
- QuicConnectionLogger(
- QuicSpdySession* session,
- const char* const connection_description,
- std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
- const BoundNetLog& net_log);
-
- ~QuicConnectionLogger() override;
-
- // QuicPacketCreator::DebugDelegateInterface
- void OnFrameAddedToPacket(const QuicFrame& frame) override;
-
- // QuicConnectionDebugVisitorInterface
- void OnPacketSent(const SerializedPacket& serialized_packet,
- QuicPathId original_path_id,
- QuicPacketNumber original_packet_number,
- TransmissionType transmission_type,
- QuicTime sent_time) override;
- void OnPacketReceived(const IPEndPoint& self_address,
- const IPEndPoint& peer_address,
- const QuicEncryptedPacket& packet) override;
- void OnUnauthenticatedHeader(const QuicPacketHeader& header) override;
- void OnIncorrectConnectionId(QuicConnectionId connection_id) override;
- void OnUndecryptablePacket() override;
- void OnDuplicatePacket(QuicPacketNumber packet_number) override;
- void OnProtocolVersionMismatch(QuicVersion version) override;
- void OnPacketHeader(const QuicPacketHeader& header) override;
- void OnStreamFrame(const QuicStreamFrame& frame) override;
- void OnAckFrame(const QuicAckFrame& frame) override;
- void OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override;
- void OnRstStreamFrame(const QuicRstStreamFrame& frame) override;
- void OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override;
- void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
- void OnBlockedFrame(const QuicBlockedFrame& frame) override;
- void OnGoAwayFrame(const QuicGoAwayFrame& frame) override;
- void OnPingFrame(const QuicPingFrame& frame) override;
- void OnPublicResetPacket(const QuicPublicResetPacket& packet) override;
- void OnVersionNegotiationPacket(
- const QuicVersionNegotiationPacket& packet) override;
- void OnConnectionClosed(QuicErrorCode error,
- const std::string& error_details,
- ConnectionCloseSource source) override;
- void OnSuccessfulVersionNegotiation(const QuicVersion& version) override;
- void OnRttChanged(QuicTime::Delta rtt) const override;
-
- void OnCryptoHandshakeMessageReceived(const CryptoHandshakeMessage& message);
- void OnCryptoHandshakeMessageSent(const CryptoHandshakeMessage& message);
- void UpdateReceivedFrameCounts(QuicStreamId stream_id,
- int num_frames_received,
- int num_duplicate_frames_received);
- void OnCertificateVerified(const CertVerifyResult& result);
-
- // Returns connection's overall packet loss rate in fraction.
- float ReceivedPacketLossRate() const;
-
- private:
- friend class test::QuicConnectionLoggerPeer;
-
- // Do a factory get for a histogram for recording data, about individual
- // packet numbers, that was gathered in the vectors
- // received_packets_ and received_acks_. |statistic_name| identifies which
- // element of data is recorded, and is used to form the histogram name.
- base::HistogramBase* GetPacketNumberHistogram(
- const char* statistic_name) const;
- // Do a factory get for a histogram to record a 6-packet loss-sequence as a
- // sample. The histogram will record the 64 distinct possible combinations.
- // |which_6| is used to adjust the name of the histogram to distinguish the
- // first 6 packets in a connection, vs. some later 6 packets.
- base::HistogramBase* Get6PacketHistogram(const char* which_6) const;
- // Do a factory get for a histogram to record cumulative stats across a 21
- // packet sequence. |which_21| is used to adjust the name of the histogram
- // to distinguish the first 21 packets' loss data, vs. some later 21 packet
- // sequences' loss data.
- base::HistogramBase* Get21CumulativeHistogram(const char* which_21) const;
- // Add samples associated with a |bit_mask_of_packets| to the given histogram
- // that was provided by Get21CumulativeHistogram(). The LSB of that mask
- // corresponds to the oldest packet number in the series of packets,
- // and the bit in the 2^20 position corresponds to the most recently received
- // packet. Of the maximum of 21 bits that are valid (correspond to packets),
- // only the most significant |valid_bits_in_mask| are processed.
- // A bit value of 0 indicates that a packet was never received, and a 1
- // indicates the packet was received.
- static void AddTo21CumulativeHistogram(base::HistogramBase* histogram,
- int bit_mask_of_packets,
- int valid_bits_in_mask);
- // For connections longer than 21 received packets, this call will calculate
- // the overall packet loss rate, and record it into a histogram.
- void RecordAggregatePacketLossRate() const;
- // At destruction time, this records results of |pacaket_received_| into
- // histograms for specific connection types.
- void RecordLossHistograms() const;
-
- BoundNetLog net_log_;
- QuicSpdySession* session_; // Unowned.
- // The last packet number received.
- QuicPacketNumber last_received_packet_number_;
- // The size of the most recently received packet.
- size_t last_received_packet_size_;
- // The size of the previously received packet.
- size_t previous_received_packet_size_;
- // The timestamp of last packet sent.
- QuicTime last_packet_sent_time_;
- // The largest packet number received. In the case where a packet is
- // received late (out of order), this value will not be updated.
- QuicPacketNumber largest_received_packet_number_;
- // The largest packet number which the peer has failed to
- // receive, according to the missing packet set in their ack frames.
- QuicPacketNumber largest_received_missing_packet_number_;
- // Number of times that the current received packet number is
- // smaller than the last received packet number.
- size_t num_out_of_order_received_packets_;
- // Number of times that the current received packet number is
- // smaller than the last received packet number and where the
- // size of the current packet is larger than the size of the previous
- // packet.
- size_t num_out_of_order_large_received_packets_;
- // The number of times that OnPacketHeader was called.
- // If the network replicates packets, then this number may be slightly
- // different from the real number of distinct packets received.
- QuicPacketCount num_packets_received_;
- // Number of times a truncated ACK frame was sent.
- size_t num_truncated_acks_sent_;
- // Number of times a truncated ACK frame was received.
- size_t num_truncated_acks_received_;
- // The kCADR value provided by the server in ServerHello.
- IPEndPoint local_address_from_shlo_;
- // The first local address from which a packet was received.
- IPEndPoint local_address_from_self_;
- // Count of the number of frames received.
- int num_frames_received_;
- // Count of the number of duplicate frames received.
- int num_duplicate_frames_received_;
- // Count of the number of packets received with incorrect connection IDs.
- int num_incorrect_connection_ids_;
- // Count of the number of undecryptable packets received.
- int num_undecryptable_packets_;
- // Count of the number of duplicate packets received.
- int num_duplicate_packets_;
- // Count of the number of BLOCKED frames received.
- int num_blocked_frames_received_;
- // Count of the number of BLOCKED frames sent.
- int num_blocked_frames_sent_;
- // Vector of inital packets status' indexed by packet numbers, where
- // false means never received. Zero is not a valid packet number, so
- // that offset is never used, and we'll track 150 packets.
- std::bitset<151> received_packets_;
- // Vector to indicate which of the initial 150 received packets turned out to
- // contain solo ACK frames. An element is true iff an ACK frame was in the
- // corresponding packet, and there was very little else.
- std::bitset<151> received_acks_;
- // The available type of connection (WiFi, 3G, etc.) when connection was first
- // used.
- const char* const connection_description_;
- // Receives notifications regarding the performance of the underlying socket
- // for the QUIC connection. May be null.
- const std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicConnectionLogger);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CONNECTION_LOGGER_H_
diff --git a/chromium/net/quic/quic_connection_logger_unittest.cc b/chromium/net/quic/quic_connection_logger_unittest.cc
deleted file mode 100644
index df3c02f6edd..00000000000
--- a/chromium/net/quic/quic_connection_logger_unittest.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_connection_logger.h"
-
-#include "net/cert/x509_certificate.h"
-#include "net/quic/test_tools/quic_connection_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-class QuicConnectionLoggerPeer {
- public:
- static size_t num_truncated_acks_sent(const QuicConnectionLogger& logger) {
- return logger.num_truncated_acks_sent_;
- }
-
- static void set_num_packets_received(QuicConnectionLogger* logger,
- int value) {
- logger->num_packets_received_ = value;
- }
-
- static void set_largest_received_packet_number(QuicConnectionLogger* logger,
- int value) {
- logger->largest_received_packet_number_ = value;
- }
-};
-
-class QuicConnectionLoggerTest : public ::testing::Test {
- protected:
- QuicConnectionLoggerTest()
- : session_(new MockQuicConnection(&helper_,
- &alarm_factory_,
- Perspective::IS_CLIENT)),
- logger_(&session_,
- "CONNECTION_UNKNOWN",
- /*socket_performance_watcher=*/nullptr,
- net_log_) {
- QuicConnectionPeer::GetFramer(session_.connection())
- ->set_version(QUIC_VERSION_33);
- }
-
- BoundNetLog net_log_;
- MockQuicConnectionHelper helper_;
- MockAlarmFactory alarm_factory_;
- MockQuicSpdySession session_;
- QuicConnectionLogger logger_;
-};
-
-TEST_F(QuicConnectionLoggerTest, TruncatedAcksSentNotChanged) {
- QuicAckFrame frame;
- logger_.OnFrameAddedToPacket(QuicFrame(&frame));
- EXPECT_EQ(0u, QuicConnectionLoggerPeer::num_truncated_acks_sent(logger_));
-
- for (QuicPacketNumber i = 0; i < 256; ++i) {
- frame.packets.Add(i);
- }
- logger_.OnFrameAddedToPacket(QuicFrame(&frame));
- EXPECT_EQ(0u, QuicConnectionLoggerPeer::num_truncated_acks_sent(logger_));
-}
-
-TEST_F(QuicConnectionLoggerTest, TruncatedAcksSent) {
- QuicAckFrame frame;
- for (QuicPacketNumber i = 0; i < 512; i += 2) {
- frame.packets.Add(i);
- }
- logger_.OnFrameAddedToPacket(QuicFrame(&frame));
- EXPECT_EQ(1u, QuicConnectionLoggerPeer::num_truncated_acks_sent(logger_));
-}
-
-TEST_F(QuicConnectionLoggerTest, ReceivedPacketLossRate) {
- QuicConnectionLoggerPeer::set_num_packets_received(&logger_, 1);
- QuicConnectionLoggerPeer::set_largest_received_packet_number(&logger_, 2);
- EXPECT_EQ(0.5f, logger_.ReceivedPacketLossRate());
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_connection_stats.cc b/chromium/net/quic/quic_connection_stats.cc
deleted file mode 100644
index df6e643d28c..00000000000
--- a/chromium/net/quic/quic_connection_stats.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_connection_stats.h"
-
-using std::ostream;
-
-namespace net {
-
-QuicConnectionStats::QuicConnectionStats()
- : bytes_sent(0),
- packets_sent(0),
- stream_bytes_sent(0),
- packets_discarded(0),
- bytes_received(0),
- packets_received(0),
- packets_processed(0),
- stream_bytes_received(0),
- bytes_retransmitted(0),
- packets_retransmitted(0),
- bytes_spuriously_retransmitted(0),
- packets_spuriously_retransmitted(0),
- packets_lost(0),
- slowstart_packets_sent(0),
- slowstart_packets_lost(0),
- slowstart_bytes_lost(0),
- packets_dropped(0),
- crypto_retransmit_count(0),
- loss_timeout_count(0),
- tlp_count(0),
- rto_count(0),
- min_rtt_us(0),
- srtt_us(0),
- max_packet_size(0),
- max_received_packet_size(0),
- estimated_bandwidth(QuicBandwidth::Zero()),
- packets_reordered(0),
- max_sequence_reordering(0),
- max_time_reordering_us(0),
- tcp_loss_events(0),
- connection_creation_time(QuicTime::Zero()) {}
-
-QuicConnectionStats::QuicConnectionStats(const QuicConnectionStats& other) =
- default;
-
-QuicConnectionStats::~QuicConnectionStats() {}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_connection_stats.h b/chromium/net/quic/quic_connection_stats.h
deleted file mode 100644
index 2f491ae832a..00000000000
--- a/chromium/net/quic/quic_connection_stats.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_CONNECTION_STATS_H_
-#define NET_QUIC_QUIC_CONNECTION_STATS_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <ostream>
-
-#include "net/base/net_export.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-// Structure to hold stats for a QuicConnection.
-struct NET_EXPORT_PRIVATE QuicConnectionStats {
- QuicConnectionStats();
- QuicConnectionStats(const QuicConnectionStats& other);
- ~QuicConnectionStats();
-
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(
- std::ostream& os,
- const QuicConnectionStats& s);
-
- QuicByteCount bytes_sent; // Includes retransmissions.
- QuicPacketCount packets_sent;
- // Non-retransmitted bytes sent in a stream frame.
- QuicByteCount stream_bytes_sent;
- // Packets serialized and discarded before sending.
- QuicPacketCount packets_discarded;
-
- // These include version negotiation and public reset packets, which do not
- // have packet numbers or frame data.
- QuicByteCount bytes_received; // Includes duplicate data for a stream.
- // Includes packets which were not processable.
- QuicPacketCount packets_received;
- // Excludes packets which were not processable.
- QuicPacketCount packets_processed;
- QuicByteCount stream_bytes_received; // Bytes received in a stream frame.
-
- QuicByteCount bytes_retransmitted;
- QuicPacketCount packets_retransmitted;
-
- QuicByteCount bytes_spuriously_retransmitted;
- QuicPacketCount packets_spuriously_retransmitted;
- // Number of packets abandoned as lost by the loss detection algorithm.
- QuicPacketCount packets_lost;
-
- // Number of packets sent in slow start.
- QuicPacketCount slowstart_packets_sent;
- // Number of packets lost exiting slow start.
- QuicPacketCount slowstart_packets_lost;
- // Number of bytes lost exiting slow start.
- QuicByteCount slowstart_bytes_lost;
-
- QuicPacketCount packets_dropped; // Duplicate or less than least unacked.
- size_t crypto_retransmit_count;
- // Count of times the loss detection alarm fired. At least one packet should
- // be lost when the alarm fires.
- size_t loss_timeout_count;
- size_t tlp_count;
- size_t rto_count; // Count of times the rto timer fired.
-
- int64_t min_rtt_us; // Minimum RTT in microseconds.
- int64_t srtt_us; // Smoothed RTT in microseconds.
- QuicByteCount max_packet_size;
- QuicByteCount max_received_packet_size;
- QuicBandwidth estimated_bandwidth;
-
- // Reordering stats for received packets.
- // Number of packets received out of packet number order.
- QuicPacketCount packets_reordered;
- // Maximum reordering observed in packet number space.
- QuicPacketNumber max_sequence_reordering;
- // Maximum reordering observed in microseconds
- int64_t max_time_reordering_us;
-
- // The following stats are used only in TcpCubicSender.
- // The number of loss events from TCP's perspective. Each loss event includes
- // one or more lost packets.
- uint32_t tcp_loss_events;
-
- // Creation time, as reported by the QuicClock.
- QuicTime connection_creation_time;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CONNECTION_STATS_H_
diff --git a/chromium/net/quic/quic_connection_test.cc b/chromium/net/quic/quic_connection_test.cc
deleted file mode 100644
index 80ba471ae07..00000000000
--- a/chromium/net/quic/quic_connection_test.cc
+++ /dev/null
@@ -1,4984 +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/quic_connection.h"
-
-#include <errno.h>
-#include <memory>
-#include <ostream>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/stl_util.h"
-#include "net/base/ip_address.h"
-#include "net/base/net_errors.h"
-#include "net/quic/congestion_control/loss_detection_interface.h"
-#include "net/quic/congestion_control/send_algorithm_interface.h"
-#include "net/quic/crypto/null_encrypter.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_simple_buffer_allocator.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/test_tools/mock_random.h"
-#include "net/quic/test_tools/quic_config_peer.h"
-#include "net/quic/test_tools/quic_connection_peer.h"
-#include "net/quic/test_tools/quic_framer_peer.h"
-#include "net/quic/test_tools/quic_packet_creator_peer.h"
-#include "net/quic/test_tools/quic_packet_generator_peer.h"
-#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/quic/test_tools/simple_quic_framer.h"
-#include "net/test/gtest_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::StringPiece;
-using std::map;
-using std::ostream;
-using std::string;
-using std::vector;
-using testing::AnyNumber;
-using testing::AtLeast;
-using testing::Contains;
-using testing::DoAll;
-using testing::InSequence;
-using testing::InvokeWithoutArgs;
-using testing::NiceMock;
-using testing::Ref;
-using testing::Return;
-using testing::SaveArg;
-using testing::SetArgPointee;
-using testing::StrictMock;
-using testing::_;
-
-namespace net {
-namespace test {
-namespace {
-
-const char data1[] = "foo";
-const char data2[] = "bar";
-
-const bool kFin = true;
-const bool kEntropyFlag = true;
-const bool kHasStopWaiting = true;
-
-const QuicPacketEntropyHash kTestEntropyHash = 76;
-
-const int kDefaultRetransmissionTimeMs = 500;
-
-const IPEndPoint kPeerAddress = IPEndPoint(Loopback6(), /*port=*/12345);
-const IPEndPoint kSelfAddress = IPEndPoint(Loopback6(), /*port=*/443);
-
-Perspective InvertPerspective(Perspective perspective) {
- return perspective == Perspective::IS_CLIENT ? Perspective::IS_SERVER
- : Perspective::IS_CLIENT;
-}
-
-// TaggingEncrypter appends kTagSize bytes of |tag| to the end of each message.
-class TaggingEncrypter : public QuicEncrypter {
- public:
- explicit TaggingEncrypter(uint8_t tag) : tag_(tag) {}
-
- ~TaggingEncrypter() override {}
-
- // QuicEncrypter interface.
- bool SetKey(StringPiece key) override { return true; }
-
- bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
-
- bool EncryptPacket(QuicPathId path_id,
- QuicPacketNumber packet_number,
- StringPiece associated_data,
- StringPiece plaintext,
- char* output,
- size_t* output_length,
- size_t max_output_length) override {
- const size_t len = plaintext.size() + kTagSize;
- if (max_output_length < len) {
- return false;
- }
- // Memmove is safe for inplace encryption.
- memmove(output, plaintext.data(), plaintext.size());
- output += plaintext.size();
- memset(output, tag_, kTagSize);
- *output_length = len;
- return true;
- }
-
- size_t GetKeySize() const override { return 0; }
- size_t GetNoncePrefixSize() const override { return 0; }
-
- size_t GetMaxPlaintextSize(size_t ciphertext_size) const override {
- return ciphertext_size - kTagSize;
- }
-
- size_t GetCiphertextSize(size_t plaintext_size) const override {
- return plaintext_size + kTagSize;
- }
-
- StringPiece GetKey() const override { return StringPiece(); }
-
- StringPiece GetNoncePrefix() const override { return StringPiece(); }
-
- private:
- enum {
- kTagSize = 12,
- };
-
- const uint8_t tag_;
-
- DISALLOW_COPY_AND_ASSIGN(TaggingEncrypter);
-};
-
-// TaggingDecrypter ensures that the final kTagSize bytes of the message all
-// have the same value and then removes them.
-class TaggingDecrypter : public QuicDecrypter {
- public:
- ~TaggingDecrypter() override {}
-
- // QuicDecrypter interface
- bool SetKey(StringPiece key) override { return true; }
-
- bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
-
- bool SetPreliminaryKey(StringPiece key) override {
- QUIC_BUG << "should not be called";
- return false;
- }
-
- bool SetDiversificationNonce(DiversificationNonce key) override {
- return true;
- }
-
- bool DecryptPacket(QuicPathId path_id,
- QuicPacketNumber packet_number,
- StringPiece associated_data,
- StringPiece ciphertext,
- char* output,
- size_t* output_length,
- size_t max_output_length) override {
- if (ciphertext.size() < kTagSize) {
- return false;
- }
- if (!CheckTag(ciphertext, GetTag(ciphertext))) {
- return false;
- }
- *output_length = ciphertext.size() - kTagSize;
- memcpy(output, ciphertext.data(), *output_length);
- return true;
- }
-
- StringPiece GetKey() const override { return StringPiece(); }
- StringPiece GetNoncePrefix() const override { return StringPiece(); }
- const char* cipher_name() const override { return "Tagging"; }
- // Use a distinct value starting with 0xFFFFFF, which is never used by TLS.
- uint32_t cipher_id() const override { return 0xFFFFFFF0; }
-
- protected:
- virtual uint8_t GetTag(StringPiece ciphertext) {
- return ciphertext.data()[ciphertext.size() - 1];
- }
-
- private:
- enum {
- kTagSize = 12,
- };
-
- bool CheckTag(StringPiece ciphertext, uint8_t tag) {
- for (size_t i = ciphertext.size() - kTagSize; i < ciphertext.size(); i++) {
- if (ciphertext.data()[i] != tag) {
- return false;
- }
- }
-
- return true;
- }
-};
-
-// StringTaggingDecrypter ensures that the final kTagSize bytes of the message
-// match the expected value.
-class StrictTaggingDecrypter : public TaggingDecrypter {
- public:
- explicit StrictTaggingDecrypter(uint8_t tag) : tag_(tag) {}
- ~StrictTaggingDecrypter() override {}
-
- // TaggingQuicDecrypter
- uint8_t GetTag(StringPiece ciphertext) override { return tag_; }
-
- const char* cipher_name() const override { return "StrictTagging"; }
- // Use a distinct value starting with 0xFFFFFF, which is never used by TLS.
- uint32_t cipher_id() const override { return 0xFFFFFFF1; }
-
- private:
- const uint8_t tag_;
-};
-
-class TestConnectionHelper : public QuicConnectionHelperInterface {
- public:
- TestConnectionHelper(MockClock* clock, MockRandom* random_generator)
- : clock_(clock), random_generator_(random_generator) {
- clock_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
- }
-
- // QuicConnectionHelperInterface
- const QuicClock* GetClock() const override { return clock_; }
-
- QuicRandom* GetRandomGenerator() override { return random_generator_; }
-
- QuicBufferAllocator* GetBufferAllocator() override {
- return &buffer_allocator_;
- }
-
- private:
- MockClock* clock_;
- MockRandom* random_generator_;
- SimpleBufferAllocator buffer_allocator_;
-
- DISALLOW_COPY_AND_ASSIGN(TestConnectionHelper);
-};
-
-class TestAlarmFactory : public QuicAlarmFactory {
- public:
- class TestAlarm : public QuicAlarm {
- public:
- explicit TestAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate> delegate)
- : QuicAlarm(std::move(delegate)) {}
-
- void SetImpl() override {}
- void CancelImpl() override {}
- using QuicAlarm::Fire;
- };
-
- TestAlarmFactory() {}
-
- QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override {
- return new TestAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate));
- }
-
- QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
- QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
- QuicConnectionArena* arena) override {
- return arena->New<TestAlarm>(std::move(delegate));
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestAlarmFactory);
-};
-
-class TestPacketWriter : public QuicPacketWriter {
- public:
- TestPacketWriter(QuicVersion version, MockClock* clock)
- : version_(version),
- framer_(SupportedVersions(version_)),
- last_packet_size_(0),
- write_blocked_(false),
- write_should_fail_(false),
- block_on_next_write_(false),
- is_write_blocked_data_buffered_(false),
- final_bytes_of_last_packet_(0),
- final_bytes_of_previous_packet_(0),
- use_tagging_decrypter_(false),
- packets_write_attempts_(0),
- clock_(clock),
- write_pause_time_delta_(QuicTime::Delta::Zero()),
- max_packet_size_(kMaxPacketSize) {}
-
- // QuicPacketWriter interface
- WriteResult WritePacket(const char* buffer,
- size_t buf_len,
- const IPAddress& self_address,
- const IPEndPoint& peer_address,
- PerPacketOptions* options) override {
- QuicEncryptedPacket packet(buffer, buf_len);
- ++packets_write_attempts_;
-
- if (packet.length() >= sizeof(final_bytes_of_last_packet_)) {
- final_bytes_of_previous_packet_ = final_bytes_of_last_packet_;
- memcpy(&final_bytes_of_last_packet_, packet.data() + packet.length() - 4,
- sizeof(final_bytes_of_last_packet_));
- }
-
- if (use_tagging_decrypter_) {
- framer_.framer()->SetDecrypter(ENCRYPTION_NONE, new TaggingDecrypter);
- }
- EXPECT_TRUE(framer_.ProcessPacket(packet));
- if (block_on_next_write_) {
- write_blocked_ = true;
- block_on_next_write_ = false;
- }
- if (IsWriteBlocked()) {
- return WriteResult(WRITE_STATUS_BLOCKED, -1);
- }
-
- if (ShouldWriteFail()) {
- return WriteResult(WRITE_STATUS_ERROR, 0);
- }
-
- last_packet_size_ = packet.length();
-
- if (!write_pause_time_delta_.IsZero()) {
- clock_->AdvanceTime(write_pause_time_delta_);
- }
- return WriteResult(WRITE_STATUS_OK, last_packet_size_);
- }
-
- bool IsWriteBlockedDataBuffered() const override {
- return is_write_blocked_data_buffered_;
- }
-
- bool ShouldWriteFail() { return write_should_fail_; }
-
- bool IsWriteBlocked() const override { return write_blocked_; }
-
- void SetWritable() override { write_blocked_ = false; }
-
- void SetShouldWriteFail() { write_should_fail_ = true; }
-
- QuicByteCount GetMaxPacketSize(
- const IPEndPoint& /*peer_address*/) const override {
- return max_packet_size_;
- }
-
- void BlockOnNextWrite() { block_on_next_write_ = true; }
-
- // Sets the amount of time that the writer should before the actual write.
- void SetWritePauseTimeDelta(QuicTime::Delta delta) {
- write_pause_time_delta_ = delta;
- }
-
- const QuicPacketHeader& header() { return framer_.header(); }
-
- size_t frame_count() const { return framer_.num_frames(); }
-
- const vector<QuicAckFrame>& ack_frames() const {
- return framer_.ack_frames();
- }
-
- const vector<QuicStopWaitingFrame>& stop_waiting_frames() const {
- return framer_.stop_waiting_frames();
- }
-
- const vector<QuicConnectionCloseFrame>& connection_close_frames() const {
- return framer_.connection_close_frames();
- }
-
- const vector<QuicRstStreamFrame>& rst_stream_frames() const {
- return framer_.rst_stream_frames();
- }
-
- const vector<QuicStreamFrame*>& stream_frames() const {
- return framer_.stream_frames();
- }
-
- const vector<QuicPingFrame>& ping_frames() const {
- return framer_.ping_frames();
- }
-
- size_t last_packet_size() { return last_packet_size_; }
-
- const QuicVersionNegotiationPacket* version_negotiation_packet() {
- return framer_.version_negotiation_packet();
- }
-
- void set_is_write_blocked_data_buffered(bool buffered) {
- is_write_blocked_data_buffered_ = buffered;
- }
-
- void set_perspective(Perspective perspective) {
- // We invert perspective here, because the framer needs to parse packets
- // we send.
- QuicFramerPeer::SetPerspective(framer_.framer(),
- InvertPerspective(perspective));
- }
-
- // final_bytes_of_last_packet_ returns the last four bytes of the previous
- // packet as a little-endian, uint32_t. This is intended to be used with a
- // TaggingEncrypter so that tests can determine which encrypter was used for
- // a given packet.
- uint32_t final_bytes_of_last_packet() { return final_bytes_of_last_packet_; }
-
- // Returns the final bytes of the second to last packet.
- uint32_t final_bytes_of_previous_packet() {
- return final_bytes_of_previous_packet_;
- }
-
- void use_tagging_decrypter() { use_tagging_decrypter_ = true; }
-
- uint32_t packets_write_attempts() { return packets_write_attempts_; }
-
- void Reset() { framer_.Reset(); }
-
- void SetSupportedVersions(const QuicVersionVector& versions) {
- framer_.SetSupportedVersions(versions);
- }
-
- void set_max_packet_size(QuicByteCount max_packet_size) {
- max_packet_size_ = max_packet_size;
- }
-
- private:
- QuicVersion version_;
- SimpleQuicFramer framer_;
- size_t last_packet_size_;
- bool write_blocked_;
- bool write_should_fail_;
- bool block_on_next_write_;
- bool is_write_blocked_data_buffered_;
- uint32_t final_bytes_of_last_packet_;
- uint32_t final_bytes_of_previous_packet_;
- bool use_tagging_decrypter_;
- uint32_t packets_write_attempts_;
- MockClock* clock_;
- // If non-zero, the clock will pause during WritePacket for this amount of
- // time.
- QuicTime::Delta write_pause_time_delta_;
- QuicByteCount max_packet_size_;
-
- DISALLOW_COPY_AND_ASSIGN(TestPacketWriter);
-};
-
-class TestConnection : public QuicConnection {
- public:
- TestConnection(QuicConnectionId connection_id,
- IPEndPoint address,
- TestConnectionHelper* helper,
- TestAlarmFactory* alarm_factory,
- TestPacketWriter* writer,
- Perspective perspective,
- QuicVersion version)
- : QuicConnection(connection_id,
- address,
- helper,
- alarm_factory,
- writer,
- /* owns_writer= */ false,
- perspective,
- SupportedVersions(version)) {
- writer->set_perspective(perspective);
- }
-
- void SendAck() { QuicConnectionPeer::SendAck(this); }
-
- void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) {
- QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm);
- }
-
- void SetLossAlgorithm(LossDetectionInterface* loss_algorithm) {
- // TODO(fayang): connection tests should use MockSentPacketManager.
- QuicSentPacketManagerPeer::SetLossAlgorithm(
- static_cast<QuicSentPacketManager*>(
- QuicConnectionPeer::GetSentPacketManager(this)),
- loss_algorithm);
- }
-
- void SendPacket(EncryptionLevel level,
- QuicPathId path_id,
- QuicPacketNumber packet_number,
- QuicPacket* packet,
- QuicPacketEntropyHash entropy_hash,
- HasRetransmittableData retransmittable,
- bool has_ack,
- bool has_pending_frames) {
- char buffer[kMaxPacketSize];
- size_t encrypted_length =
- QuicConnectionPeer::GetFramer(this)->EncryptPayload(
- ENCRYPTION_NONE, path_id, packet_number, *packet, buffer,
- kMaxPacketSize);
- delete packet;
- SerializedPacket serialized_packet(
- kDefaultPathId, packet_number, PACKET_6BYTE_PACKET_NUMBER, buffer,
- encrypted_length, entropy_hash, has_ack, has_pending_frames);
- if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
- serialized_packet.retransmittable_frames.push_back(
- QuicFrame(new QuicStreamFrame()));
- }
- OnSerializedPacket(&serialized_packet);
- }
-
- QuicConsumedData SendStreamDataWithString(
- QuicStreamId id,
- StringPiece data,
- QuicStreamOffset offset,
- bool fin,
- QuicAckListenerInterface* listener) {
- struct iovec iov;
- QuicIOVector data_iov(MakeIOVector(data, &iov));
- return QuicConnection::SendStreamData(id, data_iov, offset, fin, listener);
- }
-
- QuicConsumedData SendStreamData3() {
- return SendStreamDataWithString(kClientDataStreamId1, "food", 0, !kFin,
- nullptr);
- }
-
- QuicConsumedData SendStreamData5() {
- return SendStreamDataWithString(kClientDataStreamId2, "food2", 0, !kFin,
- nullptr);
- }
-
- // Ensures the connection can write stream data before writing.
- QuicConsumedData EnsureWritableAndSendStreamData5() {
- EXPECT_TRUE(CanWriteStreamData());
- return SendStreamData5();
- }
-
- // The crypto stream has special semantics so that it is not blocked by a
- // congestion window limitation, and also so that it gets put into a separate
- // packet (so that it is easier to reason about a crypto frame not being
- // split needlessly across packet boundaries). As a result, we have separate
- // tests for some cases for this stream.
- QuicConsumedData SendCryptoStreamData() {
- return SendStreamDataWithString(kCryptoStreamId, "chlo", 0, !kFin, nullptr);
- }
-
- void set_version(QuicVersion version) {
- QuicConnectionPeer::GetFramer(this)->set_version(version);
- }
-
- void SetSupportedVersions(const QuicVersionVector& versions) {
- QuicConnectionPeer::GetFramer(this)->SetSupportedVersions(versions);
- writer()->SetSupportedVersions(versions);
- }
-
- void set_perspective(Perspective perspective) {
- writer()->set_perspective(perspective);
- QuicConnectionPeer::SetPerspective(this, perspective);
- }
-
- // Enable path MTU discovery. Assumes that the test is performed from the
- // client perspective and the higher value of MTU target is used.
- void EnablePathMtuDiscovery(MockSendAlgorithm* send_algorithm) {
- ASSERT_EQ(Perspective::IS_CLIENT, perspective());
-
- QuicConfig config;
- QuicTagVector connection_options;
- connection_options.push_back(kMTUH);
- config.SetConnectionOptionsToSend(connection_options);
- EXPECT_CALL(*send_algorithm, SetFromConfig(_, _));
- SetFromConfig(config);
-
- // Normally, the pacing would be disabled in the test, but calling
- // SetFromConfig enables it. Set nearly-infinite bandwidth to make the
- // pacing algorithm work.
- EXPECT_CALL(*send_algorithm, PacingRate(_))
- .WillRepeatedly(Return(QuicBandwidth::FromKBytesPerSecond(10000)));
- }
-
- TestAlarmFactory::TestAlarm* GetAckAlarm() {
- return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
- QuicConnectionPeer::GetAckAlarm(this));
- }
-
- TestAlarmFactory::TestAlarm* GetPingAlarm() {
- return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
- QuicConnectionPeer::GetPingAlarm(this));
- }
-
- TestAlarmFactory::TestAlarm* GetResumeWritesAlarm() {
- return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
- QuicConnectionPeer::GetResumeWritesAlarm(this));
- }
-
- TestAlarmFactory::TestAlarm* GetRetransmissionAlarm() {
- return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
- QuicConnectionPeer::GetRetransmissionAlarm(this));
- }
-
- TestAlarmFactory::TestAlarm* GetSendAlarm() {
- return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
- QuicConnectionPeer::GetSendAlarm(this));
- }
-
- TestAlarmFactory::TestAlarm* GetTimeoutAlarm() {
- return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
- QuicConnectionPeer::GetTimeoutAlarm(this));
- }
-
- TestAlarmFactory::TestAlarm* GetMtuDiscoveryAlarm() {
- return reinterpret_cast<TestAlarmFactory::TestAlarm*>(
- QuicConnectionPeer::GetMtuDiscoveryAlarm(this));
- }
-
- void DisableTailLossProbe() {
- QuicSentPacketManagerPeer::SetMaxTailLossProbes(
- QuicConnectionPeer::GetSentPacketManager(this), 0);
- }
-
- using QuicConnection::SelectMutualVersion;
- using QuicConnection::set_defer_send_in_response_to_packets;
-
- private:
- TestPacketWriter* writer() {
- return static_cast<TestPacketWriter*>(QuicConnection::writer());
- }
-
- DISALLOW_COPY_AND_ASSIGN(TestConnection);
-};
-
-enum class AckResponse { kDefer, kImmediate };
-
-// Run tests with combinations of {QuicVersion, AckResponse}.
-struct TestParams {
- TestParams(QuicVersion version, AckResponse ack_response)
- : version(version), ack_response(ack_response) {}
-
- friend ostream& operator<<(ostream& os, const TestParams& p) {
- os << "{ client_version: " << QuicVersionToString(p.version)
- << " ack_response: "
- << (p.ack_response == AckResponse::kDefer ? "defer" : "immediate")
- << " }";
- return os;
- }
-
- QuicVersion version;
- AckResponse ack_response;
-};
-
-// Constructs various test permutations.
-vector<TestParams> GetTestParams() {
- vector<TestParams> params;
- QuicVersionVector all_supported_versions = QuicSupportedVersions();
- for (size_t i = 0; i < all_supported_versions.size(); ++i) {
- for (AckResponse ack_response :
- {AckResponse::kDefer, AckResponse::kImmediate}) {
- params.push_back(TestParams(all_supported_versions[i], ack_response));
- }
- }
- return params;
-}
-
-class QuicConnectionTest : public ::testing::TestWithParam<TestParams> {
- protected:
- QuicConnectionTest()
- : connection_id_(42),
- 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_(SupportedVersions(version()),
- QuicTime::Zero(),
- Perspective::IS_SERVER),
- peer_creator_(connection_id_,
- &peer_framer_,
- &random_generator_,
- &buffer_allocator_,
- /*delegate=*/nullptr),
- writer_(new TestPacketWriter(version(), &clock_)),
- connection_(connection_id_,
- kPeerAddress,
- helper_.get(),
- alarm_factory_.get(),
- writer_.get(),
- Perspective::IS_CLIENT,
- version()),
- creator_(QuicConnectionPeer::GetPacketCreator(&connection_)),
- generator_(QuicConnectionPeer::GetPacketGenerator(&connection_)),
- manager_(QuicConnectionPeer::GetSentPacketManager(&connection_)),
- frame1_(1, false, 0, StringPiece(data1)),
- frame2_(1, false, 3, StringPiece(data2)),
- packet_number_length_(PACKET_6BYTE_PACKET_NUMBER),
- connection_id_length_(PACKET_8BYTE_CONNECTION_ID) {
- connection_.set_defer_send_in_response_to_packets(GetParam().ack_response ==
- AckResponse::kDefer);
- FLAGS_quic_always_log_bugs_for_tests = true;
- connection_.set_visitor(&visitor_);
- connection_.SetSendAlgorithm(send_algorithm_);
- connection_.SetLossAlgorithm(loss_algorithm_);
- framer_.set_received_entropy_calculator(&entropy_calculator_);
- peer_framer_.set_received_entropy_calculator(&peer_entropy_calculator_);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillRepeatedly(Return(QuicTime::Delta::Zero()));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .Times(AnyNumber());
- EXPECT_CALL(*send_algorithm_, RetransmissionDelay())
- .WillRepeatedly(Return(QuicTime::Delta::Zero()));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillRepeatedly(Return(kDefaultTCPMSS));
- EXPECT_CALL(*send_algorithm_, PacingRate(_))
- .WillRepeatedly(Return(QuicBandwidth::Zero()));
- ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillByDefault(Return(true));
- EXPECT_CALL(*send_algorithm_, HasReliableBandwidthEstimate())
- .Times(AnyNumber());
- EXPECT_CALL(*send_algorithm_, BandwidthEstimate())
- .Times(AnyNumber())
- .WillRepeatedly(Return(QuicBandwidth::Zero()));
- EXPECT_CALL(*send_algorithm_, InSlowStart()).Times(AnyNumber());
- EXPECT_CALL(*send_algorithm_, InRecovery()).Times(AnyNumber());
- EXPECT_CALL(visitor_, WillingAndAbleToWrite()).Times(AnyNumber());
- EXPECT_CALL(visitor_, HasPendingHandshake()).Times(AnyNumber());
- EXPECT_CALL(visitor_, OnCanWrite()).Times(AnyNumber());
- EXPECT_CALL(visitor_, PostProcessAfterData()).Times(AnyNumber());
- EXPECT_CALL(visitor_, HasOpenDynamicStreams())
- .WillRepeatedly(Return(false));
- EXPECT_CALL(visitor_, OnCongestionWindowChange(_)).Times(AnyNumber());
-
- EXPECT_CALL(*loss_algorithm_, GetLossTimeout())
- .WillRepeatedly(Return(QuicTime::Zero()));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
- .Times(AnyNumber());
- // TODO(ianswett): Fix QuicConnectionTests so they don't attempt to write
- // non-crypto stream data at ENCRYPTION_NONE.
- FLAGS_quic_never_write_unencrypted_data = false;
- }
-
- QuicVersion version() { return GetParam().version; }
-
- QuicAckFrame* outgoing_ack() {
- QuicFrame ack_frame = QuicConnectionPeer::GetUpdatedAckFrame(&connection_);
- ack_ = *ack_frame.ack_frame;
- return &ack_;
- }
-
- QuicStopWaitingFrame* stop_waiting() {
- QuicConnectionPeer::PopulateStopWaitingFrame(&connection_, &stop_waiting_);
- return &stop_waiting_;
- }
-
- QuicPacketNumber least_unacked() {
- if (writer_->stop_waiting_frames().empty()) {
- return 0;
- }
- return writer_->stop_waiting_frames()[0].least_unacked;
- }
-
- void use_tagging_decrypter() { writer_->use_tagging_decrypter(); }
-
- void ProcessPacket(QuicPathId path_id, QuicPacketNumber number) {
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacket(path_id, number, !kEntropyFlag);
- if (connection_.GetSendAlarm()->IsSet()) {
- connection_.GetSendAlarm()->Fire();
- }
- }
-
- QuicPacketEntropyHash ProcessFramePacket(QuicFrame frame) {
- return ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress);
- }
-
- QuicPacketEntropyHash ProcessFramePacketWithAddresses(
- QuicFrame frame,
- IPEndPoint self_address,
- IPEndPoint peer_address) {
- QuicFrames frames;
- frames.push_back(QuicFrame(frame));
- QuicPacketCreatorPeer::SetSendVersionInPacket(
- &peer_creator_, connection_.perspective() == Perspective::IS_SERVER);
-
- char buffer[kMaxPacketSize];
- SerializedPacket serialized_packet =
- QuicPacketCreatorPeer::SerializeAllFrames(&peer_creator_, frames,
- buffer, kMaxPacketSize);
- connection_.ProcessUdpPacket(
- self_address, peer_address,
- QuicReceivedPacket(serialized_packet.encrypted_buffer,
- serialized_packet.encrypted_length, clock_.Now()));
- if (connection_.GetSendAlarm()->IsSet()) {
- connection_.GetSendAlarm()->Fire();
- }
- return serialized_packet.entropy_hash;
- }
-
- QuicPacketEntropyHash ProcessFramePacketAtLevel(QuicPathId path_id,
- QuicPacketNumber number,
- QuicFrame frame,
- EncryptionLevel level) {
- QuicPacketHeader header;
- header.public_header.connection_id = connection_id_;
- header.public_header.packet_number_length = packet_number_length_;
- header.public_header.connection_id_length = connection_id_length_;
- header.public_header.multipath_flag = path_id != kDefaultPathId;
- header.path_id = path_id;
- header.packet_number = number;
- QuicFrames frames;
- frames.push_back(frame);
- std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
-
- char buffer[kMaxPacketSize];
- size_t encrypted_length = framer_.EncryptPayload(
- level, path_id, number, *packet, buffer, kMaxPacketSize);
- connection_.ProcessUdpPacket(
- kSelfAddress, kPeerAddress,
- QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
- return base::checked_cast<QuicPacketEntropyHash>(encrypted_length);
- }
-
- size_t ProcessDataPacket(QuicPathId path_id,
- QuicPacketNumber number,
- bool entropy_flag) {
- return ProcessDataPacketAtLevel(path_id, number, entropy_flag, false,
- ENCRYPTION_NONE);
- }
-
- size_t ProcessDataPacketAtLevel(QuicPathId path_id,
- QuicPacketNumber number,
- bool entropy_flag,
- bool has_stop_waiting,
- EncryptionLevel level) {
- std::unique_ptr<QuicPacket> packet(
- ConstructDataPacket(path_id, number, entropy_flag, has_stop_waiting));
- char buffer[kMaxPacketSize];
- size_t encrypted_length = framer_.EncryptPayload(
- level, path_id, number, *packet, buffer, kMaxPacketSize);
- connection_.ProcessUdpPacket(
- kSelfAddress, kPeerAddress,
- QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
- if (connection_.GetSendAlarm()->IsSet()) {
- connection_.GetSendAlarm()->Fire();
- }
- return encrypted_length;
- }
-
- void ProcessClosePacket(QuicPathId path_id, QuicPacketNumber number) {
- std::unique_ptr<QuicPacket> packet(ConstructClosePacket(number));
- char buffer[kMaxPacketSize];
- size_t encrypted_length = framer_.EncryptPayload(
- ENCRYPTION_NONE, path_id, number, *packet, buffer, kMaxPacketSize);
- connection_.ProcessUdpPacket(
- kSelfAddress, kPeerAddress,
- QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
- }
-
- QuicByteCount SendStreamDataToPeer(QuicStreamId id,
- StringPiece data,
- QuicStreamOffset offset,
- bool fin,
- QuicPacketNumber* last_packet) {
- QuicByteCount packet_size;
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillOnce(DoAll(SaveArg<3>(&packet_size), Return(true)));
- connection_.SendStreamDataWithString(id, data, offset, fin, nullptr);
- if (last_packet != nullptr) {
- *last_packet = creator_->packet_number();
- }
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .Times(AnyNumber());
- return packet_size;
- }
-
- void SendAckPacketToPeer() {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- connection_.SendAck();
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .Times(AnyNumber());
- }
-
- void ProcessAckPacket(QuicPacketNumber packet_number, QuicAckFrame* frame) {
- QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, packet_number - 1);
- ProcessFramePacket(QuicFrame(frame));
- }
-
- QuicPacketEntropyHash ProcessAckPacket(QuicAckFrame* frame) {
- return ProcessFramePacket(QuicFrame(frame));
- }
-
- QuicPacketEntropyHash ProcessStopWaitingPacket(QuicStopWaitingFrame* frame) {
- return ProcessFramePacket(QuicFrame(frame));
- }
-
- QuicPacketEntropyHash ProcessStopWaitingPacketAtLevel(
- QuicPathId path_id,
- QuicPacketNumber number,
- QuicStopWaitingFrame* frame,
- EncryptionLevel level) {
- return ProcessFramePacketAtLevel(path_id, number, QuicFrame(frame),
- ENCRYPTION_INITIAL);
- }
-
- QuicPacketEntropyHash ProcessGoAwayPacket(QuicGoAwayFrame* frame) {
- return ProcessFramePacket(QuicFrame(frame));
- }
-
- QuicPacketEntropyHash ProcessPathClosePacket(QuicPathCloseFrame* frame) {
- return ProcessFramePacket(QuicFrame(frame));
- }
-
- bool IsMissing(QuicPacketNumber number) {
- return IsAwaitingPacket(*outgoing_ack(), number, 0);
- }
-
- QuicPacket* ConstructPacket(QuicPacketHeader header, QuicFrames frames) {
- QuicPacket* packet = BuildUnsizedDataPacket(&peer_framer_, header, frames);
- EXPECT_NE(nullptr, packet);
- return packet;
- }
-
- QuicPacket* ConstructDataPacket(QuicPathId path_id,
- QuicPacketNumber number,
- bool entropy_flag,
- bool has_stop_waiting) {
- QuicPacketHeader header;
- header.public_header.connection_id = connection_id_;
- header.public_header.packet_number_length = packet_number_length_;
- header.public_header.connection_id_length = connection_id_length_;
- header.public_header.multipath_flag = path_id != kDefaultPathId;
- header.entropy_flag = entropy_flag;
- header.path_id = path_id;
- header.packet_number = number;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&frame1_));
- if (has_stop_waiting) {
- frames.push_back(QuicFrame(&stop_waiting_));
- }
- return ConstructPacket(header, frames);
- }
-
- QuicPacket* ConstructClosePacket(QuicPacketNumber number) {
- QuicPacketHeader header;
- header.public_header.connection_id = connection_id_;
- header.packet_number = number;
-
- QuicConnectionCloseFrame qccf;
- qccf.error_code = QUIC_PEER_GOING_AWAY;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&qccf));
- return ConstructPacket(header, frames);
- }
-
- QuicTime::Delta DefaultRetransmissionTime() {
- return QuicTime::Delta::FromMilliseconds(kDefaultRetransmissionTimeMs);
- }
-
- QuicTime::Delta DefaultDelayedAckTime() {
- return QuicTime::Delta::FromMilliseconds(kMaxDelayedAckTimeMs);
- }
-
- // Initialize a frame acknowledging all packets up to largest_observed.
- const QuicAckFrame InitAckFrame(QuicPacketNumber largest_observed) {
- QuicAckFrame frame(MakeAckFrame(largest_observed));
- if (GetParam().version <= QUIC_VERSION_33) {
- if (largest_observed > 0) {
- frame.entropy_hash = QuicConnectionPeer::GetSentEntropyHash(
- &connection_, largest_observed);
- }
- } else {
- frame.missing = false;
- if (largest_observed > 0) {
- frame.packets.Add(1, largest_observed + 1);
- }
- }
- return frame;
- }
-
- const QuicStopWaitingFrame InitStopWaitingFrame(
- QuicPacketNumber least_unacked) {
- QuicStopWaitingFrame frame;
- frame.least_unacked = least_unacked;
- return frame;
- }
-
- // Explicitly nack a packet.
- void NackPacket(QuicPacketNumber missing, QuicAckFrame* frame) {
- if (frame->missing) {
- frame->packets.Add(missing);
- frame->entropy_hash ^=
- QuicConnectionPeer::PacketEntropy(&connection_, missing);
- } else {
- frame->packets.Remove(missing);
- }
- }
-
- // Undo nacking a packet within the frame.
- void AckPacket(QuicPacketNumber arrived, QuicAckFrame* frame) {
- if (frame->missing) {
- EXPECT_TRUE(frame->packets.Contains(arrived));
- frame->packets.Remove(arrived);
- frame->entropy_hash ^=
- QuicConnectionPeer::PacketEntropy(&connection_, arrived);
- } else {
- EXPECT_FALSE(frame->packets.Contains(arrived));
- frame->packets.Add(arrived);
- }
- }
-
- void TriggerConnectionClose() {
- // Send an erroneous packet to close the connection.
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, _,
- ConnectionCloseSource::FROM_SELF));
- // Call ProcessDataPacket rather than ProcessPacket, as we should not get a
- // packet call to the visitor.
- ProcessDataPacket(kDefaultPathId, 6000, !kEntropyFlag);
- EXPECT_FALSE(QuicConnectionPeer::GetConnectionClosePacket(&connection_) ==
- nullptr);
- }
-
- void BlockOnNextWrite() {
- writer_->BlockOnNextWrite();
- EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1));
- }
-
- void SetWritePauseTimeDelta(QuicTime::Delta delta) {
- writer_->SetWritePauseTimeDelta(delta);
- }
-
- void CongestionBlockWrites() {
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillRepeatedly(testing::Return(QuicTime::Delta::FromSeconds(1)));
- }
-
- void CongestionUnblockWrites() {
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
- }
-
- void set_perspective(Perspective perspective) {
- connection_.set_perspective(perspective);
- QuicFramerPeer::SetPerspective(&peer_framer_,
- InvertPerspective(perspective));
- }
-
- QuicConnectionId connection_id_;
- QuicFramer framer_;
- MockEntropyCalculator entropy_calculator_;
- MockEntropyCalculator peer_entropy_calculator_;
-
- MockSendAlgorithm* send_algorithm_;
- MockLossAlgorithm* loss_algorithm_;
- MockClock clock_;
- MockRandom random_generator_;
- SimpleBufferAllocator buffer_allocator_;
- std::unique_ptr<TestConnectionHelper> helper_;
- std::unique_ptr<TestAlarmFactory> alarm_factory_;
- QuicFramer peer_framer_;
- QuicPacketCreator peer_creator_;
- std::unique_ptr<TestPacketWriter> writer_;
- TestConnection connection_;
- QuicPacketCreator* creator_;
- QuicPacketGenerator* generator_;
- QuicSentPacketManager* manager_;
- StrictMock<MockQuicConnectionVisitor> visitor_;
-
- QuicStreamFrame frame1_;
- QuicStreamFrame frame2_;
- QuicAckFrame ack_;
- QuicStopWaitingFrame stop_waiting_;
- QuicPacketNumberLength packet_number_length_;
- QuicConnectionIdLength connection_id_length_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(QuicConnectionTest);
-};
-
-// Run all end to end tests with all supported versions.
-INSTANTIATE_TEST_CASE_P(SupportedVersion,
- QuicConnectionTest,
- ::testing::ValuesIn(GetTestParams()));
-
-TEST_P(QuicConnectionTest, SelfAddressChangeAtClient) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective());
- EXPECT_TRUE(connection_.connected());
-
- QuicStreamFrame stream_frame(1u, false, 0u, StringPiece());
- EXPECT_CALL(visitor_, OnStreamFrame(_));
- ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress,
- kPeerAddress);
- // Cause change in self_address.
- IPEndPoint self_address(IPAddress(1, 1, 1, 1), 123);
- EXPECT_CALL(visitor_, OnStreamFrame(_));
- ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), self_address,
- kPeerAddress);
- EXPECT_TRUE(connection_.connected());
-}
-
-TEST_P(QuicConnectionTest, SelfAddressChangeAtServer) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- set_perspective(Perspective::IS_SERVER);
- QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
-
- EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
- EXPECT_TRUE(connection_.connected());
-
- QuicStreamFrame stream_frame(1u, false, 0u, StringPiece());
- EXPECT_CALL(visitor_, OnStreamFrame(_));
- ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), kSelfAddress,
- kPeerAddress);
- // Cause change in self_address.
- IPEndPoint self_address(IPAddress(1, 1, 1, 1), 123);
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_ERROR_MIGRATING_ADDRESS, _, _));
- ProcessFramePacketWithAddresses(QuicFrame(&stream_frame), self_address,
- kPeerAddress);
- EXPECT_FALSE(connection_.connected());
-}
-
-TEST_P(QuicConnectionTest, MaxPacketSize) {
- EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective());
- EXPECT_EQ(1350u, connection_.max_packet_length());
-}
-
-TEST_P(QuicConnectionTest, SmallerServerMaxPacketSize) {
- QuicConnectionId connection_id = 42;
- TestConnection connection(connection_id, kPeerAddress, helper_.get(),
- alarm_factory_.get(), writer_.get(),
- Perspective::IS_SERVER, version());
- EXPECT_EQ(Perspective::IS_SERVER, connection.perspective());
- EXPECT_EQ(1000u, connection.max_packet_length());
-}
-
-TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSize) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- set_perspective(Perspective::IS_SERVER);
- connection_.SetMaxPacketLength(1000);
-
- QuicPacketHeader header;
- header.public_header.connection_id = connection_id_;
- header.public_header.version_flag = true;
- header.path_id = kDefaultPathId;
- header.packet_number = 1;
-
- QuicFrames frames;
- QuicPaddingFrame padding;
- frames.push_back(QuicFrame(&frame1_));
- frames.push_back(QuicFrame(padding));
- std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
- char buffer[kMaxPacketSize];
- size_t encrypted_length = framer_.EncryptPayload(
- ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize);
- EXPECT_EQ(kMaxPacketSize, encrypted_length);
-
- framer_.set_version(version());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- connection_.ProcessUdpPacket(
- kSelfAddress, kPeerAddress,
- QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
-
- EXPECT_EQ(kMaxPacketSize, connection_.max_packet_length());
-}
-
-TEST_P(QuicConnectionTest, IncreaseServerMaxPacketSizeWhileWriterLimited) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- const QuicByteCount lower_max_packet_size = 1240;
- writer_->set_max_packet_size(lower_max_packet_size);
- set_perspective(Perspective::IS_SERVER);
- connection_.SetMaxPacketLength(1000);
- EXPECT_EQ(1000u, connection_.max_packet_length());
-
- QuicPacketHeader header;
- header.public_header.connection_id = connection_id_;
- header.public_header.version_flag = true;
- header.path_id = kDefaultPathId;
- header.packet_number = 1;
-
- QuicFrames frames;
- QuicPaddingFrame padding;
- frames.push_back(QuicFrame(&frame1_));
- frames.push_back(QuicFrame(padding));
- std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
- char buffer[kMaxPacketSize];
- size_t encrypted_length = framer_.EncryptPayload(
- ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize);
- EXPECT_EQ(kMaxPacketSize, encrypted_length);
-
- framer_.set_version(version());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- connection_.ProcessUdpPacket(
- kSelfAddress, kPeerAddress,
- QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
-
- // Here, the limit imposed by the writer is lower than the size of the packet
- // received, so the writer max packet size is used.
- EXPECT_EQ(lower_max_packet_size, connection_.max_packet_length());
-}
-
-TEST_P(QuicConnectionTest, LimitMaxPacketSizeByWriter) {
- const QuicByteCount lower_max_packet_size = 1240;
- writer_->set_max_packet_size(lower_max_packet_size);
-
- static_assert(lower_max_packet_size < kDefaultMaxPacketSize,
- "Default maximum packet size is too low");
- connection_.SetMaxPacketLength(kDefaultMaxPacketSize);
-
- EXPECT_EQ(lower_max_packet_size, connection_.max_packet_length());
-}
-
-TEST_P(QuicConnectionTest, LimitMaxPacketSizeByWriterForNewConnection) {
- const QuicConnectionId connection_id = 17;
- const QuicByteCount lower_max_packet_size = 1240;
- writer_->set_max_packet_size(lower_max_packet_size);
- TestConnection connection(connection_id, kPeerAddress, helper_.get(),
- alarm_factory_.get(), writer_.get(),
- Perspective::IS_CLIENT, version());
- EXPECT_EQ(Perspective::IS_CLIENT, connection.perspective());
- EXPECT_EQ(lower_max_packet_size, connection.max_packet_length());
-}
-
-TEST_P(QuicConnectionTest, PacketsInOrder) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- ProcessPacket(kDefaultPathId, 1);
- EXPECT_EQ(1u, outgoing_ack()->largest_observed);
- if (outgoing_ack()->missing) {
- EXPECT_TRUE(outgoing_ack()->packets.Empty());
- } else {
- EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
- }
-
- ProcessPacket(kDefaultPathId, 2);
- EXPECT_EQ(2u, outgoing_ack()->largest_observed);
- if (outgoing_ack()->missing) {
- EXPECT_TRUE(outgoing_ack()->packets.Empty());
- } else {
- EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
- }
-
- ProcessPacket(kDefaultPathId, 3);
- EXPECT_EQ(3u, outgoing_ack()->largest_observed);
- if (outgoing_ack()->missing) {
- EXPECT_TRUE(outgoing_ack()->packets.Empty());
- } else {
- EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals());
- }
-}
-
-TEST_P(QuicConnectionTest, PacketsOutOfOrder) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- ProcessPacket(kDefaultPathId, 3);
- EXPECT_EQ(3u, outgoing_ack()->largest_observed);
- EXPECT_TRUE(IsMissing(2));
- EXPECT_TRUE(IsMissing(1));
-
- ProcessPacket(kDefaultPathId, 2);
- EXPECT_EQ(3u, outgoing_ack()->largest_observed);
- EXPECT_FALSE(IsMissing(2));
- EXPECT_TRUE(IsMissing(1));
-
- ProcessPacket(kDefaultPathId, 1);
- EXPECT_EQ(3u, outgoing_ack()->largest_observed);
- EXPECT_FALSE(IsMissing(2));
- EXPECT_FALSE(IsMissing(1));
-}
-
-TEST_P(QuicConnectionTest, DuplicatePacket) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- ProcessPacket(kDefaultPathId, 3);
- EXPECT_EQ(3u, outgoing_ack()->largest_observed);
- EXPECT_TRUE(IsMissing(2));
- EXPECT_TRUE(IsMissing(1));
-
- // Send packet 3 again, but do not set the expectation that
- // the visitor OnStreamFrame() will be called.
- ProcessDataPacket(kDefaultPathId, 3, !kEntropyFlag);
- EXPECT_EQ(3u, outgoing_ack()->largest_observed);
- EXPECT_TRUE(IsMissing(2));
- EXPECT_TRUE(IsMissing(1));
-}
-
-TEST_P(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- ProcessPacket(kDefaultPathId, 3);
- EXPECT_EQ(3u, outgoing_ack()->largest_observed);
- EXPECT_TRUE(IsMissing(2));
- EXPECT_TRUE(IsMissing(1));
-
- ProcessPacket(kDefaultPathId, 2);
- EXPECT_EQ(3u, outgoing_ack()->largest_observed);
- EXPECT_TRUE(IsMissing(1));
-
- ProcessPacket(kDefaultPathId, 5);
- EXPECT_EQ(5u, outgoing_ack()->largest_observed);
- EXPECT_TRUE(IsMissing(1));
- EXPECT_TRUE(IsMissing(4));
-
- // Pretend at this point the client has gotten acks for 2 and 3 and 1 is a
- // packet the peer will not retransmit. It indicates this by sending 'least
- // awaiting' is 4. The connection should then realize 1 will not be
- // retransmitted, and will remove it from the missing list.
- QuicAckFrame frame = InitAckFrame(1);
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _));
- ProcessAckPacket(6, &frame);
-
- // Force an ack to be sent.
- SendAckPacketToPeer();
- EXPECT_TRUE(IsMissing(4));
-}
-
-TEST_P(QuicConnectionTest, RejectPacketTooFarOut) {
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_PACKET_HEADER, _,
- ConnectionCloseSource::FROM_SELF));
- // Call ProcessDataPacket rather than ProcessPacket, as we should not get a
- // packet call to the visitor.
- ProcessDataPacket(kDefaultPathId, 6000, !kEntropyFlag);
- EXPECT_FALSE(QuicConnectionPeer::GetConnectionClosePacket(&connection_) ==
- nullptr);
-}
-
-TEST_P(QuicConnectionTest, RejectUnencryptedStreamData) {
- // Process an unencrypted packet from the non-crypto stream.
- frame1_.stream_id = 3;
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_UNENCRYPTED_STREAM_DATA, _,
- ConnectionCloseSource::FROM_SELF));
- EXPECT_DFATAL(ProcessDataPacket(kDefaultPathId, 1, !kEntropyFlag), "");
- EXPECT_FALSE(QuicConnectionPeer::GetConnectionClosePacket(&connection_) ==
- nullptr);
- const vector<QuicConnectionCloseFrame>& connection_close_frames =
- writer_->connection_close_frames();
- EXPECT_EQ(1u, connection_close_frames.size());
- EXPECT_EQ(QUIC_UNENCRYPTED_STREAM_DATA,
- connection_close_frames[0].error_code);
-}
-
-TEST_P(QuicConnectionTest, TruncatedAck) {
- if (GetParam().version > QUIC_VERSION_33) {
- return;
- }
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- QuicPacketNumber num_packets = 256 * 2 + 1;
- for (QuicPacketNumber i = 0; i < num_packets; ++i) {
- SendStreamDataToPeer(3, "foo", i * 3, !kFin, nullptr);
- }
-
- QuicAckFrame frame = InitAckFrame(num_packets);
- // Create an ack with 256 nacks, none adjacent to one another.
- for (QuicPacketNumber i = 1; i <= 256; ++i) {
- NackPacket(i * 2, &frame);
- }
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
- EXPECT_CALL(peer_entropy_calculator_, EntropyHash(511))
- .WillOnce(Return(static_cast<QuicPacketEntropyHash>(0)));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(&frame);
-
- // A truncated ack will not have the true largest observed.
- EXPECT_GT(num_packets, manager_->GetLargestObserved(frame.path_id));
-
- AckPacket(192, &frame);
-
- // Removing one missing packet allows us to ack 192 and one more range, but
- // 192 has already been declared lost, so it doesn't register as an ack.
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(&frame);
- EXPECT_EQ(num_packets, manager_->GetLargestObserved(frame.path_id));
-}
-
-TEST_P(QuicConnectionTest, AckReceiptCausesAckSendBadEntropy) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- ProcessPacket(kDefaultPathId, 1);
- // Delay sending, then queue up an ack.
- QuicConnectionPeer::SendAck(&connection_);
-
- // Process an ack with a least unacked of the received ack.
- // This causes an ack to be sent when TimeUntilSend returns 0.
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
- // Skip a packet and then record an ack.
- QuicAckFrame frame = InitAckFrame(0);
- ProcessAckPacket(3, &frame);
-}
-
-TEST_P(QuicConnectionTest, OutOfOrderReceiptCausesAckSend) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- ProcessPacket(kDefaultPathId, 3);
- // Should ack immediately since we have missing packets.
- EXPECT_EQ(1u, writer_->packets_write_attempts());
-
- ProcessPacket(kDefaultPathId, 2);
- // Should ack immediately since we have missing packets.
- EXPECT_EQ(2u, writer_->packets_write_attempts());
-
- ProcessPacket(kDefaultPathId, 1);
- // Should ack immediately, since this fills the last hole.
- EXPECT_EQ(3u, writer_->packets_write_attempts());
-
- ProcessPacket(kDefaultPathId, 4);
- // Should not cause an ack.
- EXPECT_EQ(3u, writer_->packets_write_attempts());
-}
-
-TEST_P(QuicConnectionTest, OutOfOrderAckReceiptCausesNoAck) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- SendStreamDataToPeer(1, "foo", 0, !kFin, nullptr);
- SendStreamDataToPeer(1, "bar", 3, !kFin, nullptr);
- EXPECT_EQ(2u, writer_->packets_write_attempts());
-
- QuicAckFrame ack1 = InitAckFrame(1);
- QuicAckFrame ack2 = InitAckFrame(2);
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(2, &ack2);
- // Should ack immediately since we have missing packets.
- EXPECT_EQ(2u, writer_->packets_write_attempts());
-
- ProcessAckPacket(1, &ack1);
- // Should not ack an ack filling a missing packet.
- EXPECT_EQ(2u, writer_->packets_write_attempts());
-}
-
-TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- QuicPacketNumber original;
- QuicByteCount packet_size;
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillOnce(
- DoAll(SaveArg<2>(&original), SaveArg<3>(&packet_size), Return(true)));
- connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
- QuicAckFrame frame = InitAckFrame(original);
- NackPacket(original, &frame);
- // First nack triggers early retransmit.
- SendAlgorithmInterface::CongestionVector lost_packets;
- lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
- .WillOnce(SetArgPointee<4>(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- QuicPacketNumber retransmission;
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, _, _, packet_size - kQuicVersionSize, _))
- .WillOnce(DoAll(SaveArg<2>(&retransmission), Return(true)));
-
- ProcessAckPacket(&frame);
-
- QuicAckFrame frame2 = InitAckFrame(retransmission);
- NackPacket(original, &frame2);
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
- ProcessAckPacket(&frame2);
-
- // Now if the peer sends an ack which still reports the retransmitted packet
- // as missing, that will bundle an ack with data after two acks in a row
- // indicate the high water mark needs to be raised.
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA));
- connection_.SendStreamDataWithString(3, "foo", 3, !kFin, nullptr);
- // No ack sent.
- EXPECT_EQ(1u, writer_->frame_count());
- EXPECT_EQ(1u, writer_->stream_frames().size());
-
- // No more packet loss for the rest of the test.
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _)).Times(AnyNumber());
- ProcessAckPacket(&frame2);
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA));
- connection_.SendStreamDataWithString(3, "foo", 3, !kFin, nullptr);
- // Ack bundled.
- EXPECT_EQ(3u, writer_->frame_count());
- EXPECT_EQ(1u, writer_->stream_frames().size());
- EXPECT_FALSE(writer_->ack_frames().empty());
-
- // But an ack with no missing packets will not send an ack.
- AckPacket(original, &frame2);
- ProcessAckPacket(&frame2);
- ProcessAckPacket(&frame2);
-}
-
-TEST_P(QuicConnectionTest, 20AcksCausesAckSend) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- SendStreamDataToPeer(1, "foo", 0, !kFin, nullptr);
-
- QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
- // But an ack with no missing packets will not send an ack.
- QuicAckFrame frame = InitAckFrame(1);
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- for (int i = 0; i < 19; ++i) {
- ProcessAckPacket(&frame);
- EXPECT_FALSE(ack_alarm->IsSet());
- }
- EXPECT_EQ(1u, writer_->packets_write_attempts());
- // The 20th ack packet will cause an ack to be sent.
- ProcessAckPacket(&frame);
- EXPECT_EQ(2u, writer_->packets_write_attempts());
-}
-
-TEST_P(QuicConnectionTest, LeastUnackedLower) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- SendStreamDataToPeer(1, "foo", 0, !kFin, nullptr);
- SendStreamDataToPeer(1, "bar", 3, !kFin, nullptr);
- SendStreamDataToPeer(1, "eep", 6, !kFin, nullptr);
-
- // Start out saying the least unacked is 2.
- QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 5);
- QuicStopWaitingFrame frame = InitStopWaitingFrame(2);
- ProcessStopWaitingPacket(&frame);
-
- // Change it to 1, but lower the packet number to fake out-of-order packets.
- // This should be fine.
- QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 1);
- // The scheduler will not process out of order acks, but all packet processing
- // causes the connection to try to write.
- EXPECT_CALL(visitor_, OnCanWrite());
- QuicStopWaitingFrame frame2 = InitStopWaitingFrame(1);
- ProcessStopWaitingPacket(&frame2);
-
- // Now claim it's one, but set the ordering so it was sent "after" the first
- // one. This should cause a connection error.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 7);
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_STOP_WAITING_DATA, _,
- ConnectionCloseSource::FROM_SELF));
- QuicStopWaitingFrame frame3 = InitStopWaitingFrame(1);
- ProcessStopWaitingPacket(&frame3);
-}
-
-TEST_P(QuicConnectionTest, TooManySentPackets) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- const int num_packets = kMaxTrackedPackets + 100;
- for (int i = 0; i < num_packets; ++i) {
- SendStreamDataToPeer(1, "foo", 3 * i, !kFin, nullptr);
- }
-
- // Ack packet 1, which leaves more than the limit outstanding.
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- if (GetParam().version <= QUIC_VERSION_33) {
- EXPECT_CALL(visitor_,
- OnConnectionClosed(QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS, _,
- ConnectionCloseSource::FROM_SELF));
- // We're receive buffer limited, so the connection won't try to write more.
- EXPECT_CALL(visitor_, OnCanWrite()).Times(0);
- }
-
- // Nack the first packet and ack the rest, leaving a huge gap.
- QuicAckFrame frame1 = InitAckFrame(num_packets);
- NackPacket(1, &frame1);
- ProcessAckPacket(&frame1);
-}
-
-TEST_P(QuicConnectionTest, TooManyReceivedPackets) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- if (GetParam().version <= QUIC_VERSION_33) {
- EXPECT_CALL(visitor_,
- OnConnectionClosed(QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS,
- _, ConnectionCloseSource::FROM_SELF));
- }
- // Miss 99 of every 100 packets for 5500 packets.
- for (QuicPacketNumber i = 1; i < kMaxTrackedPackets + 500; i += 100) {
- ProcessPacket(kDefaultPathId, i);
- if (!connection_.connected()) {
- break;
- }
- }
-}
-
-TEST_P(QuicConnectionTest, LargestObservedLower) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- SendStreamDataToPeer(1, "foo", 0, !kFin, nullptr);
- SendStreamDataToPeer(1, "bar", 3, !kFin, nullptr);
- SendStreamDataToPeer(1, "eep", 6, !kFin, nullptr);
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
-
- // Start out saying the largest observed is 2.
- QuicAckFrame frame1 = InitAckFrame(1);
- QuicAckFrame frame2 = InitAckFrame(2);
- ProcessAckPacket(&frame2);
-
- // Now change it to 1, and it should cause a connection error.
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, _,
- ConnectionCloseSource::FROM_SELF));
- EXPECT_CALL(visitor_, OnCanWrite()).Times(0);
- ProcessAckPacket(&frame1);
-}
-
-TEST_P(QuicConnectionTest, AckUnsentData) {
- // Ack a packet which has not been sent.
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_ACK_DATA, _,
- ConnectionCloseSource::FROM_SELF));
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- QuicAckFrame frame(MakeAckFrame(1));
- EXPECT_CALL(visitor_, OnCanWrite()).Times(0);
- ProcessAckPacket(&frame);
-}
-
-TEST_P(QuicConnectionTest, AckAll) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- ProcessPacket(kDefaultPathId, 1);
-
- QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 1);
- QuicAckFrame frame1 = InitAckFrame(0);
- ProcessAckPacket(&frame1);
-}
-
-TEST_P(QuicConnectionTest, BasicSending) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- QuicPacketNumber last_packet;
- SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1
- EXPECT_EQ(1u, last_packet);
- SendAckPacketToPeer(); // Packet 2
-
- EXPECT_EQ(1u, least_unacked());
-
- SendAckPacketToPeer(); // Packet 3
- EXPECT_EQ(1u, least_unacked());
-
- SendStreamDataToPeer(1, "bar", 3, !kFin, &last_packet); // Packet 4
- EXPECT_EQ(4u, last_packet);
- SendAckPacketToPeer(); // Packet 5
- EXPECT_EQ(1u, least_unacked());
-
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
-
- // Peer acks up to packet 3.
- QuicAckFrame frame = InitAckFrame(3);
- ProcessAckPacket(&frame);
- SendAckPacketToPeer(); // Packet 6
-
- // As soon as we've acked one, we skip ack packets 2 and 3 and note lack of
- // ack for 4.
- EXPECT_EQ(4u, least_unacked());
-
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
-
- // Peer acks up to packet 4, the last packet.
- QuicAckFrame frame2 = InitAckFrame(6);
- ProcessAckPacket(&frame2); // Acks don't instigate acks.
-
- // Verify that we did not send an ack.
- EXPECT_EQ(6u, writer_->header().packet_number);
-
- // So the last ack has not changed.
- EXPECT_EQ(4u, least_unacked());
-
- // If we force an ack, we shouldn't change our retransmit state.
- SendAckPacketToPeer(); // Packet 7
- EXPECT_EQ(7u, least_unacked());
-
- // But if we send more data it should.
- SendStreamDataToPeer(1, "eep", 6, !kFin, &last_packet); // Packet 8
- EXPECT_EQ(8u, last_packet);
- SendAckPacketToPeer(); // Packet 9
- EXPECT_EQ(7u, least_unacked());
-}
-
-// QuicConnection should record the the packet sent-time prior to sending the
-// packet.
-TEST_P(QuicConnectionTest, RecordSentTimeBeforePacketSent) {
- // We're using a MockClock for the tests, so we have complete control over the
- // time.
- // Our recorded timestamp for the last packet sent time will be passed in to
- // the send_algorithm. Make sure that it is set to the correct value.
- QuicTime actual_recorded_send_time = QuicTime::Zero();
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true)));
-
- // First send without any pause and check the result.
- QuicTime expected_recorded_send_time = clock_.Now();
- connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
- EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time)
- << "Expected time = " << expected_recorded_send_time.ToDebuggingValue()
- << ". Actual time = " << actual_recorded_send_time.ToDebuggingValue();
-
- // Now pause during the write, and check the results.
- actual_recorded_send_time = QuicTime::Zero();
- const QuicTime::Delta write_pause_time_delta =
- QuicTime::Delta::FromMilliseconds(5000);
- SetWritePauseTimeDelta(write_pause_time_delta);
- expected_recorded_send_time = clock_.Now();
-
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true)));
- connection_.SendStreamDataWithString(2, "baz", 0, !kFin, nullptr);
- EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time)
- << "Expected time = " << expected_recorded_send_time.ToDebuggingValue()
- << ". Actual time = " << actual_recorded_send_time.ToDebuggingValue();
-}
-
-TEST_P(QuicConnectionTest, FramePacking) {
- // Send an ack and two stream frames in 1 packet by queueing them.
- {
- QuicConnection::ScopedPacketBundler bundler(&connection_,
- QuicConnection::SEND_ACK);
- connection_.SendStreamData3();
- connection_.SendStreamData5();
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- }
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
- EXPECT_FALSE(connection_.HasQueuedData());
-
- // Parse the last packet and ensure it's an ack and two stream frames from
- // two different streams.
- EXPECT_EQ(4u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_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.
- {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
- QuicConnection::ScopedPacketBundler bundler(&connection_,
- QuicConnection::SEND_ACK);
- connection_.SendStreamData3();
- connection_.SendCryptoStreamData();
- }
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
- EXPECT_FALSE(connection_.HasQueuedData());
-
- // Parse the last packet and ensure it's the crypto stream frame.
- EXPECT_EQ(1u, writer_->frame_count());
- ASSERT_EQ(1u, writer_->stream_frames().size());
- EXPECT_EQ(kCryptoStreamId, writer_->stream_frames()[0]->stream_id);
-}
-
-TEST_P(QuicConnectionTest, FramePackingCryptoThenNonCrypto) {
- // Send an ack and two stream frames (one crypto, then one non-crypto) in 2
- // packets by queueing them.
- {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
- QuicConnection::ScopedPacketBundler bundler(&connection_,
- QuicConnection::SEND_ACK);
- connection_.SendCryptoStreamData();
- connection_.SendStreamData3();
- }
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
- EXPECT_FALSE(connection_.HasQueuedData());
-
- // Parse the last packet and ensure it's the stream frame from stream 3.
- EXPECT_EQ(1u, writer_->frame_count());
- ASSERT_EQ(1u, writer_->stream_frames().size());
- EXPECT_EQ(kClientDataStreamId1, writer_->stream_frames()[0]->stream_id);
-}
-
-TEST_P(QuicConnectionTest, FramePackingAckResponse) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- // Process a data packet to queue up a pending ack.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacket(kDefaultPathId, 1, kEntropyFlag);
-
- EXPECT_CALL(visitor_, OnCanWrite())
- .WillOnce(DoAll(IgnoreResult(InvokeWithoutArgs(
- &connection_, &TestConnection::SendStreamData3)),
- IgnoreResult(InvokeWithoutArgs(
- &connection_, &TestConnection::SendStreamData5))));
-
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
-
- // Process an ack to cause the visitor's OnCanWrite to be invoked.
- QuicAckFrame ack_one = InitAckFrame(0);
- ProcessAckPacket(3, &ack_one);
-
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
- EXPECT_FALSE(connection_.HasQueuedData());
-
- // Parse the last packet and ensure it's an ack and two stream frames from
- // two different streams.
- EXPECT_EQ(4u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_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, FramePackingSendv) {
- // Send data in 1 packet by writing multiple blocks in a single iovector
- // using writev.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
-
- char data[] = "ABCD";
- struct iovec iov[2];
- iov[0].iov_base = data;
- iov[0].iov_len = 2;
- iov[1].iov_base = data + 2;
- iov[1].iov_len = 2;
- connection_.SendStreamData(1, QuicIOVector(iov, 2, 4), 0, !kFin, nullptr);
-
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
- EXPECT_FALSE(connection_.HasQueuedData());
-
- // Parse the last packet and ensure multiple iovector blocks have
- // been packed into a single stream frame from one stream.
- EXPECT_EQ(1u, writer_->frame_count());
- EXPECT_EQ(1u, writer_->stream_frames().size());
- QuicStreamFrame* frame = writer_->stream_frames()[0];
- EXPECT_EQ(1u, frame->stream_id);
- EXPECT_EQ("ABCD", StringPiece(frame->data_buffer, frame->data_length));
-}
-
-TEST_P(QuicConnectionTest, FramePackingSendvQueued) {
- // Try to send two stream frames in 1 packet by using writev.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
-
- BlockOnNextWrite();
- char data[] = "ABCD";
- struct iovec iov[2];
- iov[0].iov_base = data;
- iov[0].iov_len = 2;
- iov[1].iov_base = data + 2;
- iov[1].iov_len = 2;
- connection_.SendStreamData(1, QuicIOVector(iov, 2, 4), 0, !kFin, nullptr);
-
- EXPECT_EQ(1u, connection_.NumQueuedPackets());
- EXPECT_TRUE(connection_.HasQueuedData());
-
- // Unblock the writes and actually send.
- writer_->SetWritable();
- connection_.OnCanWrite();
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
-
- // Parse the last packet and ensure it's one stream frame from one stream.
- EXPECT_EQ(1u, writer_->frame_count());
- EXPECT_EQ(1u, writer_->stream_frames().size());
- EXPECT_EQ(1u, writer_->stream_frames()[0]->stream_id);
-}
-
-TEST_P(QuicConnectionTest, SendingZeroBytes) {
- // Send a zero byte write with a fin using writev.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- QuicIOVector empty_iov(nullptr, 0, 0);
- connection_.SendStreamData(kHeadersStreamId, empty_iov, 0, kFin, nullptr);
-
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
- EXPECT_FALSE(connection_.HasQueuedData());
-
- // Parse the last packet and ensure it's one stream frame from one stream.
- EXPECT_EQ(1u, writer_->frame_count());
- EXPECT_EQ(1u, writer_->stream_frames().size());
- EXPECT_EQ(kHeadersStreamId, writer_->stream_frames()[0]->stream_id);
- EXPECT_TRUE(writer_->stream_frames()[0]->fin);
-}
-
-TEST_P(QuicConnectionTest, LargeSendWithPendingAck) {
- // Set the ack alarm by processing a ping frame.
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- // Processs a PING frame.
- ProcessFramePacket(QuicFrame(QuicPingFrame()));
- // Ensure that this has caused the ACK alarm to be set.
- QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
- EXPECT_TRUE(ack_alarm->IsSet());
-
- // Send data and ensure the ack is bundled.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(8);
- size_t len = 10000;
- std::unique_ptr<char[]> data_array(new char[len]);
- memset(data_array.get(), '?', len);
- struct iovec iov;
- iov.iov_base = data_array.get();
- iov.iov_len = len;
- QuicIOVector iovector(&iov, 1, len);
- QuicConsumedData consumed =
- connection_.SendStreamData(kHeadersStreamId, iovector, 0, true, nullptr);
- EXPECT_EQ(len, consumed.bytes_consumed);
- EXPECT_TRUE(consumed.fin_consumed);
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
- EXPECT_FALSE(connection_.HasQueuedData());
-
- // Parse the last packet and ensure it's one stream frame with a fin.
- EXPECT_EQ(1u, writer_->frame_count());
- EXPECT_EQ(1u, writer_->stream_frames().size());
- EXPECT_EQ(kHeadersStreamId, writer_->stream_frames()[0]->stream_id);
- EXPECT_TRUE(writer_->stream_frames()[0]->fin);
- // Ensure the ack alarm was cancelled when the ack was sent.
- EXPECT_FALSE(ack_alarm->IsSet());
-}
-
-TEST_P(QuicConnectionTest, OnCanWrite) {
- // Visitor's OnCanWrite will send data, but will have more pending writes.
- EXPECT_CALL(visitor_, OnCanWrite())
- .WillOnce(DoAll(IgnoreResult(InvokeWithoutArgs(
- &connection_, &TestConnection::SendStreamData3)),
- IgnoreResult(InvokeWithoutArgs(
- &connection_, &TestConnection::SendStreamData5))));
- EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillOnce(Return(true));
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
-
- connection_.OnCanWrite();
-
- // Parse the last packet and ensure it's the two stream frames from
- // two different streams.
- EXPECT_EQ(2u, writer_->frame_count());
- EXPECT_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, RetransmitOnNack) {
- QuicPacketNumber last_packet;
- QuicByteCount second_packet_size;
- SendStreamDataToPeer(3, "foo", 0, !kFin, &last_packet); // Packet 1
- second_packet_size =
- SendStreamDataToPeer(3, "foos", 3, !kFin, &last_packet); // Packet 2
- SendStreamDataToPeer(3, "fooos", 7, !kFin, &last_packet); // Packet 3
-
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- // Don't lose a packet on an ack, and nothing is retransmitted.
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- QuicAckFrame ack_one = InitAckFrame(1);
- ProcessAckPacket(&ack_one);
-
- // Lose a packet and ensure it triggers retransmission.
- QuicAckFrame nack_two = InitAckFrame(3);
- NackPacket(2, &nack_two);
- SendAlgorithmInterface::CongestionVector lost_packets;
- lost_packets.push_back(std::make_pair(2, kMaxPacketSize));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
- .WillOnce(SetArgPointee<4>(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, _, _, second_packet_size - kQuicVersionSize, _))
- .Times(1);
- ProcessAckPacket(&nack_two);
-}
-
-TEST_P(QuicConnectionTest, DoNotSendQueuedPacketForResetStream) {
- // Block the connection to queue the packet.
- BlockOnNextWrite();
-
- QuicStreamId stream_id = 2;
- connection_.SendStreamDataWithString(stream_id, "foo", 0, !kFin, nullptr);
-
- // Now that there is a queued packet, reset the stream.
- connection_.SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 14);
-
- // Unblock the connection and verify that only the RST_STREAM is sent.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- writer_->SetWritable();
- connection_.OnCanWrite();
- EXPECT_EQ(1u, writer_->frame_count());
- EXPECT_EQ(1u, writer_->rst_stream_frames().size());
-}
-
-TEST_P(QuicConnectionTest, SendQueuedPacketForQuicRstStreamNoError) {
- // Block the connection to queue the packet.
- BlockOnNextWrite();
-
- QuicStreamId stream_id = 2;
- connection_.SendStreamDataWithString(stream_id, "foo", 0, !kFin, nullptr);
-
- // Now that there is a queued packet, reset the stream.
- connection_.SendRstStream(stream_id, QUIC_STREAM_NO_ERROR, 14);
-
- // Unblock the connection and verify that the RST_STREAM is sent and the data
- // packet is sent on QUIC_VERSION_29 or later versions.
- if (version() > QUIC_VERSION_28) {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .Times(AtLeast(2));
- } else {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- }
- writer_->SetWritable();
- connection_.OnCanWrite();
- EXPECT_EQ(1u, writer_->frame_count());
- EXPECT_EQ(1u, writer_->rst_stream_frames().size());
-}
-
-TEST_P(QuicConnectionTest, DoNotRetransmitForResetStreamOnNack) {
- QuicStreamId stream_id = 2;
- QuicPacketNumber last_packet;
- SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
- SendStreamDataToPeer(stream_id, "foos", 3, !kFin, &last_packet);
- SendStreamDataToPeer(stream_id, "fooos", 7, !kFin, &last_packet);
-
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- connection_.SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 14);
-
- // Lose a packet and ensure it does not trigger retransmission.
- QuicAckFrame nack_two = InitAckFrame(last_packet);
- NackPacket(last_packet - 1, &nack_two);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
- ProcessAckPacket(&nack_two);
-}
-
-TEST_P(QuicConnectionTest, RetransmitForQuicRstStreamNoErrorOnNack) {
- QuicStreamId stream_id = 2;
- QuicPacketNumber last_packet;
- SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
- SendStreamDataToPeer(stream_id, "foos", 3, !kFin, &last_packet);
- SendStreamDataToPeer(stream_id, "fooos", 7, !kFin, &last_packet);
-
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- connection_.SendRstStream(stream_id, QUIC_STREAM_NO_ERROR, 14);
-
- // Lose a packet, ensure it triggers retransmission on QUIC_VERSION_29
- // or later versions.
- QuicAckFrame nack_two = InitAckFrame(last_packet);
- NackPacket(last_packet - 1, &nack_two);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- SendAlgorithmInterface::CongestionVector lost_packets;
- lost_packets.push_back(std::make_pair(last_packet - 1, kMaxPacketSize));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
- .WillOnce(SetArgPointee<4>(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- if (version() > QUIC_VERSION_28) {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .Times(AtLeast(1));
- } else {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
- }
- ProcessAckPacket(&nack_two);
-}
-
-TEST_P(QuicConnectionTest, DoNotRetransmitForResetStreamOnRTO) {
- QuicStreamId stream_id = 2;
- QuicPacketNumber last_packet;
- SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
-
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- connection_.SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 14);
-
- // Fire the RTO and verify that the RST_STREAM is resent, not stream data.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- clock_.AdvanceTime(DefaultRetransmissionTime());
- connection_.GetRetransmissionAlarm()->Fire();
- EXPECT_EQ(1u, writer_->frame_count());
- EXPECT_EQ(1u, writer_->rst_stream_frames().size());
- EXPECT_EQ(stream_id, writer_->rst_stream_frames().front().stream_id);
-}
-
-TEST_P(QuicConnectionTest, RetransmitForQuicRstStreamNoErrorOnRTO) {
- connection_.DisableTailLossProbe();
-
- QuicStreamId stream_id = 2;
- QuicPacketNumber last_packet;
- SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
-
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- connection_.SendRstStream(stream_id, QUIC_STREAM_NO_ERROR, 14);
-
- // Fire the RTO and verify that the RST_STREAM is resent, the stream data
- // is only sent on QUIC_VERSION_29 or later versions.
- if (version() > QUIC_VERSION_28) {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .Times(AtLeast(2));
- } else {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- }
- clock_.AdvanceTime(DefaultRetransmissionTime());
- connection_.GetRetransmissionAlarm()->Fire();
- EXPECT_EQ(1u, writer_->frame_count());
- ASSERT_EQ(1u, writer_->rst_stream_frames().size());
- EXPECT_EQ(stream_id, writer_->rst_stream_frames().front().stream_id);
-}
-
-TEST_P(QuicConnectionTest, DoNotSendPendingRetransmissionForResetStream) {
- QuicStreamId stream_id = 2;
- QuicPacketNumber last_packet;
- SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
- SendStreamDataToPeer(stream_id, "foos", 3, !kFin, &last_packet);
- BlockOnNextWrite();
- connection_.SendStreamDataWithString(stream_id, "fooos", 7, !kFin, nullptr);
-
- // Lose a packet which will trigger a pending retransmission.
- QuicAckFrame ack = InitAckFrame(last_packet);
- NackPacket(last_packet - 1, &ack);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
- ProcessAckPacket(&ack);
-
- connection_.SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 14);
-
- // Unblock the connection and verify that the RST_STREAM is sent but not the
- // second data packet nor a retransmit.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- writer_->SetWritable();
- connection_.OnCanWrite();
- EXPECT_EQ(1u, writer_->frame_count());
- EXPECT_EQ(1u, writer_->rst_stream_frames().size());
- EXPECT_EQ(stream_id, writer_->rst_stream_frames().front().stream_id);
-}
-
-TEST_P(QuicConnectionTest, SendPendingRetransmissionForQuicRstStreamNoError) {
- QuicStreamId stream_id = 2;
- QuicPacketNumber last_packet;
- SendStreamDataToPeer(stream_id, "foo", 0, !kFin, &last_packet);
- SendStreamDataToPeer(stream_id, "foos", 3, !kFin, &last_packet);
- BlockOnNextWrite();
- connection_.SendStreamDataWithString(stream_id, "fooos", 7, !kFin, nullptr);
-
- // Lose a packet which will trigger a pending retransmission.
- QuicAckFrame ack = InitAckFrame(last_packet);
- NackPacket(last_packet - 1, &ack);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- SendAlgorithmInterface::CongestionVector lost_packets;
- lost_packets.push_back(std::make_pair(last_packet - 1, kMaxPacketSize));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
- .WillOnce(SetArgPointee<4>(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
- ProcessAckPacket(&ack);
-
- connection_.SendRstStream(stream_id, QUIC_STREAM_NO_ERROR, 14);
-
- // Unblock the connection and verify that the RST_STREAM is sent and the
- // second data packet or a retransmit is only sent on QUIC_VERSION_29 or
- // later versions.
- if (version() > QUIC_VERSION_28) {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .Times(AtLeast(2));
- } else {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- }
- writer_->SetWritable();
- connection_.OnCanWrite();
- EXPECT_EQ(1u, writer_->frame_count());
- if (version() > QUIC_VERSION_28) {
- EXPECT_EQ(0u, writer_->rst_stream_frames().size());
- } else {
- EXPECT_EQ(1u, writer_->rst_stream_frames().size());
- EXPECT_EQ(stream_id, writer_->rst_stream_frames().front().stream_id);
- }
-}
-
-TEST_P(QuicConnectionTest, DiscardRetransmit) {
- FLAGS_quic_always_write_queued_retransmissions = false;
- QuicPacketNumber last_packet;
- SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1
- SendStreamDataToPeer(1, "foos", 3, !kFin, &last_packet); // Packet 2
- SendStreamDataToPeer(1, "fooos", 7, !kFin, &last_packet); // Packet 3
-
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- // Instigate a loss with an ack.
- QuicAckFrame nack_two = InitAckFrame(3);
- NackPacket(2, &nack_two);
- // The first nack should trigger a fast retransmission, but we'll be
- // write blocked, so the packet will be queued.
- BlockOnNextWrite();
-
- SendAlgorithmInterface::CongestionVector lost_packets;
- lost_packets.push_back(std::make_pair(2, kMaxPacketSize));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
- .WillOnce(SetArgPointee<4>(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(&nack_two);
- EXPECT_EQ(1u, connection_.NumQueuedPackets());
-
- // Now, ack the previous transmission.
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
- QuicAckFrame ack_all = InitAckFrame(3);
- ProcessAckPacket(&ack_all);
-
- // Unblock the socket and attempt to send the queued packets. However,
- // since the previous transmission has been acked, we will not
- // send the retransmission.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
-
- writer_->SetWritable();
- connection_.OnCanWrite();
-
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
-}
-
-TEST_P(QuicConnectionTest, RetransmitAckedPacket) {
- FLAGS_quic_always_write_queued_retransmissions = true;
- QuicPacketNumber last_packet;
- SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1
- SendStreamDataToPeer(1, "foos", 3, !kFin, &last_packet); // Packet 2
- SendStreamDataToPeer(1, "fooos", 7, !kFin, &last_packet); // Packet 3
-
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- // Instigate a loss with an ack.
- QuicAckFrame nack_two = InitAckFrame(3);
- NackPacket(2, &nack_two);
- // The first nack should trigger a fast retransmission, but we'll be
- // write blocked, so the packet will be queued.
- BlockOnNextWrite();
-
- SendAlgorithmInterface::CongestionVector lost_packets;
- lost_packets.push_back(std::make_pair(2, kMaxPacketSize));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
- .WillOnce(SetArgPointee<4>(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(&nack_two);
- EXPECT_EQ(1u, connection_.NumQueuedPackets());
-
- // Now, ack the previous transmission.
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
- QuicAckFrame ack_all = InitAckFrame(3);
- ProcessAckPacket(&ack_all);
-
- // Unblock the socket and attempt to send the queued packets. We will always
- // send the retransmission.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 4, _, _)).Times(1);
-
- writer_->SetWritable();
- connection_.OnCanWrite();
-
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
- // We do not store retransmittable frames of this retransmission.
- EXPECT_FALSE(connection_.sent_packet_manager().HasRetransmittableFrames(
- kDefaultPathId, 4));
-}
-
-TEST_P(QuicConnectionTest, RetransmitNackedLargestObserved) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- QuicPacketNumber largest_observed;
- QuicByteCount packet_size;
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillOnce(DoAll(SaveArg<2>(&largest_observed), SaveArg<3>(&packet_size),
- Return(true)));
- connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
-
- QuicAckFrame frame = InitAckFrame(1);
- NackPacket(largest_observed, &frame);
- // The first nack should retransmit the largest observed packet.
- SendAlgorithmInterface::CongestionVector lost_packets;
- lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
- .WillOnce(SetArgPointee<4>(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, _, _, packet_size - kQuicVersionSize, _));
- ProcessAckPacket(&frame);
-}
-
-TEST_P(QuicConnectionTest, QueueAfterTwoRTOs) {
- connection_.DisableTailLossProbe();
-
- for (int i = 0; i < 10; ++i) {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- connection_.SendStreamDataWithString(3, "foo", i * 3, !kFin, nullptr);
- }
-
- // Block the writer and ensure they're queued.
- BlockOnNextWrite();
- clock_.AdvanceTime(DefaultRetransmissionTime());
- // Only one packet should be retransmitted.
- connection_.GetRetransmissionAlarm()->Fire();
- EXPECT_TRUE(connection_.HasQueuedData());
-
- // Unblock the writer.
- writer_->SetWritable();
- clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(
- 2 * DefaultRetransmissionTime().ToMicroseconds()));
- // Retransmit already retransmitted packets event though the packet number
- // greater than the largest observed.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
- connection_.GetRetransmissionAlarm()->Fire();
- connection_.OnCanWrite();
-}
-
-TEST_P(QuicConnectionTest, WriteBlockedBufferedThenSent) {
- BlockOnNextWrite();
- writer_->set_is_write_blocked_data_buffered(true);
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
- EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
-
- writer_->SetWritable();
- connection_.OnCanWrite();
- EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, WriteBlockedThenSent) {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
- BlockOnNextWrite();
- connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
- EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
- EXPECT_EQ(1u, connection_.NumQueuedPackets());
-
- // The second packet should also be queued, in order to ensure packets are
- // never sent out of order.
- writer_->SetWritable();
- connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
- EXPECT_EQ(2u, connection_.NumQueuedPackets());
-
- // Now both are sent in order when we unblock.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
- connection_.OnCanWrite();
- EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, RetransmitWriteBlockedAckedOriginalThenSent) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
- EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
-
- BlockOnNextWrite();
- writer_->set_is_write_blocked_data_buffered(true);
- // Simulate the retransmission alarm firing.
- clock_.AdvanceTime(DefaultRetransmissionTime());
- connection_.GetRetransmissionAlarm()->Fire();
-
- // Ack the sent packet before the callback returns, which happens in
- // rare circumstances with write blocked sockets.
- QuicAckFrame ack = InitAckFrame(1);
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(&ack);
-
- writer_->SetWritable();
- connection_.OnCanWrite();
- // There is now a pending packet, but with no retransmittable frames.
- EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
- EXPECT_FALSE(connection_.sent_packet_manager().HasRetransmittableFrames(
- ack.path_id, 2));
-}
-
-TEST_P(QuicConnectionTest, AlarmsWhenWriteBlocked) {
- // Block the connection.
- BlockOnNextWrite();
- connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
- EXPECT_EQ(1u, writer_->packets_write_attempts());
- EXPECT_TRUE(writer_->IsWriteBlocked());
-
- // Set the send and resumption alarms. Fire the alarms and ensure they don't
- // attempt to write.
- connection_.GetResumeWritesAlarm()->Set(clock_.ApproximateNow());
- connection_.GetSendAlarm()->Set(clock_.ApproximateNow());
- connection_.GetResumeWritesAlarm()->Fire();
- connection_.GetSendAlarm()->Fire();
- EXPECT_TRUE(writer_->IsWriteBlocked());
- EXPECT_EQ(1u, writer_->packets_write_attempts());
-}
-
-TEST_P(QuicConnectionTest, NoLimitPacketsPerNack) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- int offset = 0;
- // Send packets 1 to 15.
- for (int i = 0; i < 15; ++i) {
- SendStreamDataToPeer(1, "foo", offset, !kFin, nullptr);
- offset += 3;
- }
-
- // Ack 15, nack 1-14.
-
- QuicAckFrame nack = InitAckFrame(15);
- for (int i = 1; i < 15; ++i) {
- NackPacket(i, &nack);
- }
-
- // 14 packets have been NACK'd and lost.
- SendAlgorithmInterface::CongestionVector lost_packets;
- for (int i = 1; i < 15; ++i) {
- lost_packets.push_back(std::make_pair(i, kMaxPacketSize));
- }
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
- .WillOnce(SetArgPointee<4>(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(14);
- ProcessAckPacket(&nack);
-}
-
-// Test sending multiple acks from the connection to the session.
-TEST_P(QuicConnectionTest, MultipleAcks) {
- QuicPacketNumber last_packet;
- SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet); // Packet 1
- EXPECT_EQ(1u, last_packet);
- SendStreamDataToPeer(3, "foo", 0, !kFin, &last_packet); // Packet 2
- EXPECT_EQ(2u, last_packet);
- SendAckPacketToPeer(); // Packet 3
- SendStreamDataToPeer(5, "foo", 0, !kFin, &last_packet); // Packet 4
- EXPECT_EQ(4u, last_packet);
- SendStreamDataToPeer(1, "foo", 3, !kFin, &last_packet); // Packet 5
- EXPECT_EQ(5u, last_packet);
- SendStreamDataToPeer(3, "foo", 3, !kFin, &last_packet); // Packet 6
- EXPECT_EQ(6u, last_packet);
-
- // Client will ack packets 1, 2, [!3], 4, 5.
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- QuicAckFrame frame1 = InitAckFrame(5);
- NackPacket(3, &frame1);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- ProcessAckPacket(&frame1);
-
- // Now the client implicitly acks 3, and explicitly acks 6.
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- QuicAckFrame frame2 = InitAckFrame(6);
- ProcessAckPacket(&frame2);
-}
-
-TEST_P(QuicConnectionTest, DontLatchUnackedPacket) {
- SendStreamDataToPeer(1, "foo", 0, !kFin, nullptr); // Packet 1;
- // From now on, we send acks, so the send algorithm won't mark them pending.
- ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillByDefault(Return(false));
- SendAckPacketToPeer(); // Packet 2
-
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- QuicAckFrame frame = InitAckFrame(1);
- ProcessAckPacket(&frame);
-
- // Verify that our internal state has least-unacked as 2, because we're still
- // waiting for a potential ack for 2.
-
- EXPECT_EQ(2u, stop_waiting()->least_unacked);
-
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- frame = InitAckFrame(2);
- ProcessAckPacket(&frame);
- EXPECT_EQ(3u, stop_waiting()->least_unacked);
-
- // When we send an ack, we make sure our least-unacked makes sense. In this
- // case since we're not waiting on an ack for 2 and all packets are acked, we
- // set it to 3.
- SendAckPacketToPeer(); // Packet 3
- // Least_unacked remains at 3 until another ack is received.
- EXPECT_EQ(3u, stop_waiting()->least_unacked);
- // Check that the outgoing ack had its packet number as least_unacked.
- EXPECT_EQ(3u, least_unacked());
-
- // Ack the ack, which updates the rtt and raises the least unacked.
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- frame = InitAckFrame(3);
- ProcessAckPacket(&frame);
-
- ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillByDefault(Return(true));
- SendStreamDataToPeer(1, "bar", 3, false, nullptr); // Packet 4
- EXPECT_EQ(4u, stop_waiting()->least_unacked);
- ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillByDefault(Return(false));
- SendAckPacketToPeer(); // Packet 5
- EXPECT_EQ(4u, least_unacked());
-
- // Send two data packets at the end, and ensure if the last one is acked,
- // the least unacked is raised above the ack packets.
- ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillByDefault(Return(true));
- SendStreamDataToPeer(1, "bar", 6, false, nullptr); // Packet 6
- SendStreamDataToPeer(1, "bar", 9, false, nullptr); // Packet 7
-
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- frame = InitAckFrame(7);
- NackPacket(5, &frame);
- NackPacket(6, &frame);
- ProcessAckPacket(&frame);
-
- EXPECT_EQ(6u, stop_waiting()->least_unacked);
-}
-
-TEST_P(QuicConnectionTest, TLP) {
- QuicSentPacketManagerPeer::SetMaxTailLossProbes(manager_, 1);
-
- SendStreamDataToPeer(3, "foo", 0, !kFin, nullptr);
- EXPECT_EQ(1u, stop_waiting()->least_unacked);
- QuicTime retransmission_time =
- connection_.GetRetransmissionAlarm()->deadline();
- EXPECT_NE(QuicTime::Zero(), retransmission_time);
-
- EXPECT_EQ(1u, writer_->header().packet_number);
- // Simulate the retransmission alarm firing and sending a tlp,
- // so send algorithm's OnRetransmissionTimeout is not called.
- clock_.AdvanceTime(retransmission_time.Subtract(clock_.Now()));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
- connection_.GetRetransmissionAlarm()->Fire();
- EXPECT_EQ(2u, writer_->header().packet_number);
- // We do not raise the high water mark yet.
- EXPECT_EQ(1u, stop_waiting()->least_unacked);
-}
-
-TEST_P(QuicConnectionTest, RTO) {
- connection_.DisableTailLossProbe();
-
- QuicTime default_retransmission_time =
- clock_.ApproximateNow().Add(DefaultRetransmissionTime());
- SendStreamDataToPeer(3, "foo", 0, !kFin, nullptr);
- EXPECT_EQ(1u, stop_waiting()->least_unacked);
-
- EXPECT_EQ(1u, writer_->header().packet_number);
- EXPECT_EQ(default_retransmission_time,
- connection_.GetRetransmissionAlarm()->deadline());
- // Simulate the retransmission alarm firing.
- clock_.AdvanceTime(DefaultRetransmissionTime());
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
- connection_.GetRetransmissionAlarm()->Fire();
- EXPECT_EQ(2u, writer_->header().packet_number);
- // We do not raise the high water mark yet.
- EXPECT_EQ(1u, stop_waiting()->least_unacked);
-}
-
-TEST_P(QuicConnectionTest, RTOWithSameEncryptionLevel) {
- connection_.DisableTailLossProbe();
-
- QuicTime default_retransmission_time =
- clock_.ApproximateNow().Add(DefaultRetransmissionTime());
- use_tagging_decrypter();
-
- // A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at
- // the end of the packet. We can test this to check which encrypter was used.
- connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01));
- SendStreamDataToPeer(3, "foo", 0, !kFin, nullptr);
- EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet());
-
- connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(0x02));
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
- SendStreamDataToPeer(3, "foo", 0, !kFin, nullptr);
- EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
-
- EXPECT_EQ(default_retransmission_time,
- connection_.GetRetransmissionAlarm()->deadline());
- {
- InSequence s;
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 3, _, _));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 4, _, _));
- }
-
- // Simulate the retransmission alarm firing.
- clock_.AdvanceTime(DefaultRetransmissionTime());
- connection_.GetRetransmissionAlarm()->Fire();
-
- // Packet should have been sent with ENCRYPTION_NONE.
- EXPECT_EQ(0x01010101u, writer_->final_bytes_of_previous_packet());
-
- // Packet should have been sent with ENCRYPTION_INITIAL.
- EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
-}
-
-TEST_P(QuicConnectionTest, SendHandshakeMessages) {
- use_tagging_decrypter();
- // A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at
- // the end of the packet. We can test this to check which encrypter was used.
- connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01));
-
- // Attempt to send a handshake message and have the socket block.
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
- BlockOnNextWrite();
- connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
- // The packet should be serialized, but not queued.
- EXPECT_EQ(1u, connection_.NumQueuedPackets());
-
- // Switch to the new encrypter.
- connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(0x02));
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
-
- // Now become writeable and flush the packets.
- writer_->SetWritable();
- EXPECT_CALL(visitor_, OnCanWrite());
- connection_.OnCanWrite();
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
-
- // Verify that the handshake packet went out at the null encryption.
- EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet());
-}
-
-TEST_P(QuicConnectionTest,
- DropRetransmitsForNullEncryptedPacketAfterForwardSecure) {
- use_tagging_decrypter();
- connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01));
- QuicPacketNumber packet_number;
- SendStreamDataToPeer(3, "foo", 0, !kFin, &packet_number);
-
- // Simulate the retransmission alarm firing and the socket blocking.
- BlockOnNextWrite();
- clock_.AdvanceTime(DefaultRetransmissionTime());
- connection_.GetRetransmissionAlarm()->Fire();
-
- // Go forward secure.
- connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
- new TaggingEncrypter(0x02));
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
- connection_.NeuterUnencryptedPackets();
-
- EXPECT_EQ(QuicTime::Zero(), connection_.GetRetransmissionAlarm()->deadline());
- // Unblock the socket and ensure that no packets are sent.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
- writer_->SetWritable();
- connection_.OnCanWrite();
-}
-
-TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) {
- use_tagging_decrypter();
- connection_.SetEncrypter(ENCRYPTION_NONE, new TaggingEncrypter(0x01));
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_NONE);
-
- SendStreamDataToPeer(1, "foo", 0, !kFin, nullptr);
-
- connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(0x02));
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
-
- SendStreamDataToPeer(2, "bar", 0, !kFin, nullptr);
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
-
- connection_.RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
-}
-
-TEST_P(QuicConnectionTest, DelayForwardSecureEncryptionUntilClientIsReady) {
- // A TaggingEncrypter puts kTagSize copies of the given byte (0x02 here) at
- // the end of the packet. We can test this to check which encrypter was used.
- use_tagging_decrypter();
- connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(0x02));
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
- SendAckPacketToPeer();
- EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
-
- // Set a forward-secure encrypter but do not make it the default, and verify
- // that it is not yet used.
- connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
- new TaggingEncrypter(0x03));
- SendAckPacketToPeer();
- EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
-
- // Now simulate receipt of a forward-secure packet and verify that the
- // forward-secure encrypter is now used.
- connection_.OnDecryptedPacket(ENCRYPTION_FORWARD_SECURE);
- SendAckPacketToPeer();
- EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet());
-}
-
-TEST_P(QuicConnectionTest, DelayForwardSecureEncryptionUntilManyPacketSent) {
- // Set a congestion window of 10 packets.
- QuicPacketCount congestion_window = 10;
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillRepeatedly(Return(congestion_window * kDefaultMaxPacketSize));
-
- // A TaggingEncrypter puts kTagSize copies of the given byte (0x02 here) at
- // the end of the packet. We can test this to check which encrypter was used.
- use_tagging_decrypter();
- connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(0x02));
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
- SendAckPacketToPeer();
- EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
-
- // Set a forward-secure encrypter but do not make it the default, and
- // verify that it is not yet used.
- connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
- new TaggingEncrypter(0x03));
- SendAckPacketToPeer();
- EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
-
- // Now send a packet "Far enough" after the encrypter was set and verify that
- // the forward-secure encrypter is now used.
- for (uint64_t i = 0; i < 3 * congestion_window - 1; ++i) {
- EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet());
- SendAckPacketToPeer();
- }
- EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet());
-}
-
-TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) {
- // SetFromConfig is always called after construction from InitializeSession.
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- QuicConfig config;
- connection_.SetFromConfig(config);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- use_tagging_decrypter();
-
- const uint8_t tag = 0x07;
- framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
-
- // Process an encrypted packet which can not yet be decrypted which should
- // result in the packet being buffered.
- ProcessDataPacketAtLevel(kDefaultPathId, 1, kEntropyFlag, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
-
- // Transition to the new encryption state and process another encrypted packet
- // which should result in the original packet being processed.
- connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
- connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(2);
- ProcessDataPacketAtLevel(kDefaultPathId, 2, kEntropyFlag, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
-
- // Finally, process a third packet and note that we do not reprocess the
- // buffered packet.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, 3, kEntropyFlag, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
-}
-
-TEST_P(QuicConnectionTest, Buffer100NonDecryptablePackets) {
- // SetFromConfig is always called after construction from InitializeSession.
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- QuicConfig config;
- config.set_max_undecryptable_packets(100);
- connection_.SetFromConfig(config);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- use_tagging_decrypter();
-
- const uint8_t tag = 0x07;
- framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
-
- // Process an encrypted packet which can not yet be decrypted which should
- // result in the packet being buffered.
- for (QuicPacketNumber i = 1; i <= 100; ++i) {
- ProcessDataPacketAtLevel(kDefaultPathId, i, kEntropyFlag, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
- }
-
- // Transition to the new encryption state and process another encrypted packet
- // which should result in the original packets being processed.
- connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
- connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
- connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(101);
- ProcessDataPacketAtLevel(kDefaultPathId, 101, kEntropyFlag, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
-
- // Finally, process a third packet and note that we do not reprocess the
- // buffered packet.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, 102, kEntropyFlag, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
-}
-
-TEST_P(QuicConnectionTest, TestRetransmitOrder) {
- connection_.DisableTailLossProbe();
-
- QuicByteCount first_packet_size;
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillOnce(DoAll(SaveArg<3>(&first_packet_size), Return(true)));
-
- connection_.SendStreamDataWithString(3, "first_packet", 0, !kFin, nullptr);
- QuicByteCount second_packet_size;
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillOnce(DoAll(SaveArg<3>(&second_packet_size), Return(true)));
- connection_.SendStreamDataWithString(3, "second_packet", 12, !kFin, nullptr);
- EXPECT_NE(first_packet_size, second_packet_size);
- // Advance the clock by huge time to make sure packets will be retransmitted.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
- {
- InSequence s;
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, first_packet_size, _));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, second_packet_size, _));
- }
- connection_.GetRetransmissionAlarm()->Fire();
-
- // Advance again and expect the packets to be sent again in the same order.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(20));
- {
- InSequence s;
- EXPECT_CALL(visitor_, OnPathDegrading());
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, first_packet_size, _));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, second_packet_size, _));
- }
- connection_.GetRetransmissionAlarm()->Fire();
-}
-
-TEST_P(QuicConnectionTest, SetRTOAfterWritingToSocket) {
- BlockOnNextWrite();
- connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
- // Make sure that RTO is not started when the packet is queued.
- EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
-
- // Test that RTO is started once we write to the socket.
- writer_->SetWritable();
- connection_.OnCanWrite();
- EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, DelayRTOWithAckReceipt) {
- connection_.DisableTailLossProbe();
-
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
- connection_.SendStreamDataWithString(2, "foo", 0, !kFin, nullptr);
- connection_.SendStreamDataWithString(3, "bar", 0, !kFin, nullptr);
- QuicAlarm* retransmission_alarm = connection_.GetRetransmissionAlarm();
- EXPECT_TRUE(retransmission_alarm->IsSet());
- EXPECT_EQ(clock_.Now().Add(DefaultRetransmissionTime()),
- retransmission_alarm->deadline());
-
- // Advance the time right before the RTO, then receive an ack for the first
- // packet to delay the RTO.
- clock_.AdvanceTime(DefaultRetransmissionTime());
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- QuicAckFrame ack = InitAckFrame(1);
- ProcessAckPacket(&ack);
- EXPECT_TRUE(retransmission_alarm->IsSet());
- EXPECT_GT(retransmission_alarm->deadline(), clock_.Now());
-
- // Move forward past the original RTO and ensure the RTO is still pending.
- clock_.AdvanceTime(DefaultRetransmissionTime().Multiply(2));
-
- // Ensure the second packet gets retransmitted when it finally fires.
- EXPECT_TRUE(retransmission_alarm->IsSet());
- EXPECT_LT(retransmission_alarm->deadline(), clock_.ApproximateNow());
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- // Manually cancel the alarm to simulate a real test.
- connection_.GetRetransmissionAlarm()->Fire();
-
- // The new retransmitted packet number should set the RTO to a larger value
- // than previously.
- EXPECT_TRUE(retransmission_alarm->IsSet());
- QuicTime next_rto_time = retransmission_alarm->deadline();
- QuicTime expected_rto_time =
- connection_.sent_packet_manager().GetRetransmissionTime();
- EXPECT_EQ(next_rto_time, expected_rto_time);
-}
-
-TEST_P(QuicConnectionTest, TestQueued) {
- connection_.DisableTailLossProbe();
-
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
- BlockOnNextWrite();
- connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
- EXPECT_EQ(1u, connection_.NumQueuedPackets());
-
- // Unblock the writes and actually send.
- writer_->SetWritable();
- connection_.OnCanWrite();
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
-}
-
-TEST_P(QuicConnectionTest, InitialTimeout) {
- EXPECT_TRUE(connection_.connected());
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
- EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
-
- // SetFromConfig sets the initial timeouts before negotiation.
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- QuicConfig config;
- connection_.SetFromConfig(config);
- // Subtract a second from the idle timeout on the client side.
- QuicTime default_timeout = clock_.ApproximateNow().Add(
- QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1));
- EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
-
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NETWORK_IDLE_TIMEOUT, _,
- ConnectionCloseSource::FROM_SELF));
- // Simulate the timeout alarm firing.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1));
- connection_.GetTimeoutAlarm()->Fire();
-
- EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_FALSE(connection_.connected());
-
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetResumeWritesAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetSendAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, HandshakeTimeout) {
- // Use a shorter handshake timeout than idle timeout for this test.
- const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(5);
- connection_.SetNetworkTimeouts(timeout, timeout);
- EXPECT_TRUE(connection_.connected());
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
-
- QuicTime handshake_timeout = clock_.ApproximateNow().Add(timeout).Subtract(
- QuicTime::Delta::FromSeconds(1));
- EXPECT_EQ(handshake_timeout, connection_.GetTimeoutAlarm()->deadline());
- EXPECT_TRUE(connection_.connected());
-
- // Send and ack new data 3 seconds later to lengthen the idle timeout.
- SendStreamDataToPeer(kHeadersStreamId, "GET /", 0, kFin, nullptr);
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(3));
- QuicAckFrame frame = InitAckFrame(1);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(&frame);
-
- // Fire early to verify it wouldn't timeout yet.
- connection_.GetTimeoutAlarm()->Fire();
- EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_TRUE(connection_.connected());
-
- clock_.AdvanceTime(timeout.Subtract(QuicTime::Delta::FromSeconds(2)));
-
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_HANDSHAKE_TIMEOUT, _,
- ConnectionCloseSource::FROM_SELF));
- // Simulate the timeout alarm firing.
- connection_.GetTimeoutAlarm()->Fire();
-
- EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_FALSE(connection_.connected());
-
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetResumeWritesAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetSendAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, PingAfterSend) {
- EXPECT_TRUE(connection_.connected());
- EXPECT_CALL(visitor_, HasOpenDynamicStreams()).WillRepeatedly(Return(true));
- EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
-
- // Advance to 5ms, and send a packet to the peer, which will set
- // the ping alarm.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
- SendStreamDataToPeer(kHeadersStreamId, "GET /", 0, kFin, nullptr);
- EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
- EXPECT_EQ(clock_.ApproximateNow().Add(QuicTime::Delta::FromSeconds(15)),
- connection_.GetPingAlarm()->deadline());
-
- // Now recevie and ACK of the previous packet, which will move the
- // ping alarm forward.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- QuicAckFrame frame = InitAckFrame(1);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(&frame);
- EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
- // The ping timer is set slightly less than 15 seconds in the future, because
- // of the 1s ping timer alarm granularity.
- EXPECT_EQ(clock_.ApproximateNow()
- .Add(QuicTime::Delta::FromSeconds(15))
- .Subtract(QuicTime::Delta::FromMilliseconds(5)),
- connection_.GetPingAlarm()->deadline());
-
- writer_->Reset();
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(15));
- connection_.GetPingAlarm()->Fire();
- EXPECT_EQ(1u, writer_->frame_count());
- ASSERT_EQ(1u, writer_->ping_frames().size());
- writer_->Reset();
-
- EXPECT_CALL(visitor_, HasOpenDynamicStreams()).WillRepeatedly(Return(false));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- SendAckPacketToPeer();
-
- EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
-}
-
-// Tests whether sending an MTU discovery packet to peer successfully causes the
-// maximum packet size to increase.
-TEST_P(QuicConnectionTest, SendMtuDiscoveryPacket) {
- EXPECT_TRUE(connection_.connected());
-
- // Send an MTU probe.
- const size_t new_mtu = kDefaultMaxPacketSize + 100;
- QuicByteCount mtu_probe_size;
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillOnce(DoAll(SaveArg<3>(&mtu_probe_size), Return(true)));
- connection_.SendMtuDiscoveryPacket(new_mtu);
- EXPECT_EQ(new_mtu, mtu_probe_size);
- EXPECT_EQ(1u, creator_->packet_number());
-
- // Send more than MTU worth of data. No acknowledgement was received so far,
- // so the MTU should be at its old value.
- const string data(kDefaultMaxPacketSize + 1, '.');
- QuicByteCount size_before_mtu_change;
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillOnce(DoAll(SaveArg<3>(&size_before_mtu_change), Return(true)))
- .WillOnce(Return(true));
- connection_.SendStreamDataWithString(3, data, 0, kFin, nullptr);
- EXPECT_EQ(3u, creator_->packet_number());
- EXPECT_EQ(kDefaultMaxPacketSize, size_before_mtu_change);
-
- // Acknowledge all packets so far.
- QuicAckFrame probe_ack = InitAckFrame(3);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(&probe_ack);
- EXPECT_EQ(new_mtu, connection_.max_packet_length());
-
- // Send the same data again. Check that it fits into a single packet now.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- connection_.SendStreamDataWithString(3, data, 0, kFin, nullptr);
- EXPECT_EQ(4u, creator_->packet_number());
-}
-
-// Tests whether MTU discovery does not happen when it is not explicitly enabled
-// by the connection options.
-TEST_P(QuicConnectionTest, MtuDiscoveryDisabled) {
- EXPECT_TRUE(connection_.connected());
-
- const QuicPacketCount number_of_packets = kPacketsBetweenMtuProbesBase * 2;
- for (QuicPacketCount i = 0; i < number_of_packets; i++) {
- SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
- EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
- EXPECT_EQ(0u, connection_.mtu_probe_count());
- }
-}
-
-// Tests whether MTU discovery works when the probe gets acknowledged on the
-// first try.
-TEST_P(QuicConnectionTest, MtuDiscoveryEnabled) {
- EXPECT_TRUE(connection_.connected());
-
- connection_.EnablePathMtuDiscovery(send_algorithm_);
-
- // Send enough packets so that the next one triggers path MTU discovery.
- for (QuicPacketCount i = 0; i < kPacketsBetweenMtuProbesBase - 1; i++) {
- SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
- ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
- }
-
- // Trigger the probe.
- SendStreamDataToPeer(3, "!", kPacketsBetweenMtuProbesBase,
- /*fin=*/false, nullptr);
- ASSERT_TRUE(connection_.GetMtuDiscoveryAlarm()->IsSet());
- QuicByteCount probe_size;
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillOnce(DoAll(SaveArg<3>(&probe_size), Return(true)));
- connection_.GetMtuDiscoveryAlarm()->Fire();
- EXPECT_EQ(kMtuDiscoveryTargetPacketSizeHigh, probe_size);
-
- const QuicPacketCount probe_packet_number = kPacketsBetweenMtuProbesBase + 1;
- ASSERT_EQ(probe_packet_number, creator_->packet_number());
-
- // Acknowledge all packets sent so far.
- QuicAckFrame probe_ack = InitAckFrame(probe_packet_number);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(&probe_ack);
- EXPECT_EQ(kMtuDiscoveryTargetPacketSizeHigh, connection_.max_packet_length());
- EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager_));
-
- // Send more packets, and ensure that none of them sets the alarm.
- for (QuicPacketCount i = 0; i < 4 * kPacketsBetweenMtuProbesBase; i++) {
- SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
- ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
- }
-
- EXPECT_EQ(1u, connection_.mtu_probe_count());
-}
-
-// Tests whether MTU discovery works correctly when the probes never get
-// acknowledged.
-TEST_P(QuicConnectionTest, MtuDiscoveryFailed) {
- EXPECT_TRUE(connection_.connected());
-
- connection_.EnablePathMtuDiscovery(send_algorithm_);
-
- const QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(100);
-
- EXPECT_EQ(kPacketsBetweenMtuProbesBase,
- QuicConnectionPeer::GetPacketsBetweenMtuProbes(&connection_));
- // Lower the number of probes between packets in order to make the test go
- // much faster.
- const QuicPacketCount packets_between_probes_base = 10;
- QuicConnectionPeer::SetPacketsBetweenMtuProbes(&connection_,
- packets_between_probes_base);
- QuicConnectionPeer::SetNextMtuProbeAt(&connection_,
- packets_between_probes_base);
-
- // This tests sends more packets than strictly necessary to make sure that if
- // the connection was to send more discovery packets than needed, those would
- // get caught as well.
- const QuicPacketCount number_of_packets =
- packets_between_probes_base * (1 << (kMtuDiscoveryAttempts + 1));
- vector<QuicPacketNumber> mtu_discovery_packets;
- // Called by the first ack.
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- // Called on many acks.
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _))
- .Times(AnyNumber());
- for (QuicPacketCount i = 0; i < number_of_packets; i++) {
- SendStreamDataToPeer(3, "!", i, /*fin=*/false, nullptr);
- clock_.AdvanceTime(rtt);
-
- // Receive an ACK, which marks all data packets as received, and all MTU
- // discovery packets as missing.
- QuicAckFrame ack = InitAckFrame(creator_->packet_number());
- for (QuicPacketNumber& packet : mtu_discovery_packets) {
- NackPacket(packet, &ack);
- }
- ProcessAckPacket(&ack);
-
- // Trigger MTU probe if it would be scheduled now.
- if (!connection_.GetMtuDiscoveryAlarm()->IsSet()) {
- continue;
- }
-
- // Fire the alarm. The alarm should cause a packet to be sent.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillOnce(Return(true));
- connection_.GetMtuDiscoveryAlarm()->Fire();
- // Record the packet number of the MTU discovery packet in order to
- // mark it as NACK'd.
- mtu_discovery_packets.push_back(creator_->packet_number());
- }
-
- // Ensure the number of packets between probes grows exponentially by checking
- // it against the closed-form expression for the packet number.
- ASSERT_EQ(kMtuDiscoveryAttempts, mtu_discovery_packets.size());
- for (QuicPacketNumber i = 0; i < kMtuDiscoveryAttempts; i++) {
- // 2^0 + 2^1 + 2^2 + ... + 2^n = 2^(n + 1) - 1
- const QuicPacketCount packets_between_probes =
- packets_between_probes_base * ((1 << (i + 1)) - 1);
- EXPECT_EQ(packets_between_probes + (i + 1), mtu_discovery_packets[i]);
- }
-
- EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
- EXPECT_EQ(kDefaultMaxPacketSize, connection_.max_packet_length());
- EXPECT_EQ(kMtuDiscoveryAttempts, connection_.mtu_probe_count());
-}
-
-// Tests whether MTU discovery works when the writer has a limit on how large a
-// packet can be.
-TEST_P(QuicConnectionTest, MtuDiscoveryWriterLimited) {
- EXPECT_TRUE(connection_.connected());
-
- const QuicByteCount mtu_limit = kMtuDiscoveryTargetPacketSizeHigh - 1;
- writer_->set_max_packet_size(mtu_limit);
- connection_.EnablePathMtuDiscovery(send_algorithm_);
-
- // Send enough packets so that the next one triggers path MTU discovery.
- for (QuicPacketCount i = 0; i < kPacketsBetweenMtuProbesBase - 1; i++) {
- SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
- ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
- }
-
- // Trigger the probe.
- SendStreamDataToPeer(3, "!", kPacketsBetweenMtuProbesBase,
- /*fin=*/false, nullptr);
- ASSERT_TRUE(connection_.GetMtuDiscoveryAlarm()->IsSet());
- QuicByteCount probe_size;
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillOnce(DoAll(SaveArg<3>(&probe_size), Return(true)));
- connection_.GetMtuDiscoveryAlarm()->Fire();
- EXPECT_EQ(mtu_limit, probe_size);
-
- const QuicPacketCount probe_sequence_number =
- kPacketsBetweenMtuProbesBase + 1;
- ASSERT_EQ(probe_sequence_number, creator_->packet_number());
-
- // Acknowledge all packets sent so far.
- QuicAckFrame probe_ack = InitAckFrame(probe_sequence_number);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(&probe_ack);
- EXPECT_EQ(mtu_limit, connection_.max_packet_length());
- EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager_));
-
- // Send more packets, and ensure that none of them sets the alarm.
- for (QuicPacketCount i = 0; i < 4 * kPacketsBetweenMtuProbesBase; i++) {
- SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
- ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
- }
-
- EXPECT_EQ(1u, connection_.mtu_probe_count());
-}
-
-TEST_P(QuicConnectionTest, NoMtuDiscoveryAfterConnectionClosed) {
- EXPECT_TRUE(connection_.connected());
-
- connection_.EnablePathMtuDiscovery(send_algorithm_);
-
- // Send enough packets so that the next one triggers path MTU discovery.
- for (QuicPacketCount i = 0; i < kPacketsBetweenMtuProbesBase - 1; i++) {
- SendStreamDataToPeer(3, ".", i, /*fin=*/false, nullptr);
- ASSERT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
- }
-
- SendStreamDataToPeer(3, "!", kPacketsBetweenMtuProbesBase,
- /*fin=*/false, nullptr);
- EXPECT_TRUE(connection_.GetMtuDiscoveryAlarm()->IsSet());
-
- EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _));
- connection_.CloseConnection(QUIC_PEER_GOING_AWAY, "no reason",
- ConnectionCloseBehavior::SILENT_CLOSE);
- EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, TimeoutAfterSend) {
- EXPECT_TRUE(connection_.connected());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- QuicConfig config;
- connection_.SetFromConfig(config);
- EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
-
- const QuicTime::Delta initial_idle_timeout =
- QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
- const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
- QuicTime default_timeout = clock_.ApproximateNow().Add(initial_idle_timeout);
-
- // When we send a packet, the timeout will change to 5ms +
- // kInitialIdleTimeoutSecs.
- clock_.AdvanceTime(five_ms);
- SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, kFin, nullptr);
- EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
-
- // Now send more data. This will not move the timeout becase
- // no data has been recieved since the previous write.
- clock_.AdvanceTime(five_ms);
- SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, kFin, nullptr);
- EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
-
- // The original alarm will fire. We should not time out because we had a
- // network event at t=5ms. The alarm will reregister.
- clock_.AdvanceTime(initial_idle_timeout.Subtract(five_ms).Subtract(five_ms));
- EXPECT_EQ(default_timeout, clock_.ApproximateNow());
- connection_.GetTimeoutAlarm()->Fire();
- EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_TRUE(connection_.connected());
- EXPECT_EQ(default_timeout.Add(five_ms).Add(five_ms),
- connection_.GetTimeoutAlarm()->deadline());
-
- // This time, we should time out.
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NETWORK_IDLE_TIMEOUT, _,
- ConnectionCloseSource::FROM_SELF));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- clock_.AdvanceTime(five_ms);
- EXPECT_EQ(default_timeout.Add(five_ms), clock_.ApproximateNow());
- connection_.GetTimeoutAlarm()->Fire();
- EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_FALSE(connection_.connected());
-}
-
-TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) {
- // Same test as above, but complete a handshake which enables silent close,
- // causing no connection close packet to be sent.
- EXPECT_TRUE(connection_.connected());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- QuicConfig config;
-
- // Create a handshake message that also enables silent close.
- CryptoHandshakeMessage msg;
- string error_details;
- QuicConfig client_config;
- client_config.SetInitialStreamFlowControlWindowToSend(
- kInitialStreamFlowControlWindowForTest);
- client_config.SetInitialSessionFlowControlWindowToSend(
- kInitialSessionFlowControlWindowForTest);
- client_config.SetIdleConnectionStateLifetime(
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs),
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs));
- client_config.ToHandshakeMessage(&msg);
- const QuicErrorCode error =
- config.ProcessPeerHello(msg, CLIENT, &error_details);
- EXPECT_EQ(QUIC_NO_ERROR, error);
-
- connection_.SetFromConfig(config);
- EXPECT_TRUE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
-
- const QuicTime::Delta default_idle_timeout =
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs - 1);
- const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
- QuicTime default_timeout = clock_.ApproximateNow().Add(default_idle_timeout);
-
- // When we send a packet, the timeout will change to 5ms +
- // kInitialIdleTimeoutSecs.
- clock_.AdvanceTime(five_ms);
- SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, kFin, nullptr);
- EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
-
- // Now send more data. This will not move the timeout becase
- // no data has been recieved since the previous write.
- clock_.AdvanceTime(five_ms);
- SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, kFin, nullptr);
- EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
-
- // The original alarm will fire. We should not time out because we had a
- // network event at t=5ms. The alarm will reregister.
- clock_.AdvanceTime(default_idle_timeout.Subtract(five_ms).Subtract(five_ms));
- EXPECT_EQ(default_timeout, clock_.ApproximateNow());
- connection_.GetTimeoutAlarm()->Fire();
- EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_TRUE(connection_.connected());
- EXPECT_EQ(default_timeout.Add(five_ms).Add(five_ms),
- connection_.GetTimeoutAlarm()->deadline());
-
- // This time, we should time out.
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NETWORK_IDLE_TIMEOUT, _,
- ConnectionCloseSource::FROM_SELF));
- clock_.AdvanceTime(five_ms);
- EXPECT_EQ(default_timeout.Add(five_ms), clock_.ApproximateNow());
- connection_.GetTimeoutAlarm()->Fire();
- EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_FALSE(connection_.connected());
-}
-
-TEST_P(QuicConnectionTest, TimeoutAfterReceive) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_TRUE(connection_.connected());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- QuicConfig config;
- connection_.SetFromConfig(config);
- EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
-
- const QuicTime::Delta initial_idle_timeout =
- QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
- const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
- QuicTime default_timeout = clock_.ApproximateNow().Add(initial_idle_timeout);
-
- connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0, !kFin,
- nullptr);
- connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 3, !kFin,
- nullptr);
-
- EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
- clock_.AdvanceTime(five_ms);
-
- // When we receive a packet, the timeout will change to 5ms +
- // kInitialIdleTimeoutSecs.
- QuicAckFrame ack = InitAckFrame(2);
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(&ack);
-
- // The original alarm will fire. We should not time out because we had a
- // network event at t=5ms. The alarm will reregister.
- clock_.AdvanceTime(initial_idle_timeout.Subtract(five_ms));
- EXPECT_EQ(default_timeout, clock_.ApproximateNow());
- connection_.GetTimeoutAlarm()->Fire();
- EXPECT_TRUE(connection_.connected());
- EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_EQ(default_timeout.Add(five_ms),
- connection_.GetTimeoutAlarm()->deadline());
-
- // This time, we should time out.
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NETWORK_IDLE_TIMEOUT, _,
- ConnectionCloseSource::FROM_SELF));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- clock_.AdvanceTime(five_ms);
- EXPECT_EQ(default_timeout.Add(five_ms), clock_.ApproximateNow());
- connection_.GetTimeoutAlarm()->Fire();
- EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_FALSE(connection_.connected());
-}
-
-TEST_P(QuicConnectionTest, TimeoutAfterReceiveNotSendWhenUnacked) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_TRUE(connection_.connected());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- QuicConfig config;
- connection_.SetFromConfig(config);
- EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_));
-
- const QuicTime::Delta initial_idle_timeout =
- QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
- connection_.SetNetworkTimeouts(
- QuicTime::Delta::Infinite(),
- initial_idle_timeout.Add(QuicTime::Delta::FromSeconds(1)));
- const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
- QuicTime default_timeout = clock_.ApproximateNow().Add(initial_idle_timeout);
-
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0, !kFin,
- nullptr);
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 3, !kFin,
- nullptr);
-
- EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
-
- clock_.AdvanceTime(five_ms);
-
- // When we receive a packet, the timeout will change to 5ms +
- // kInitialIdleTimeoutSecs.
- QuicAckFrame ack = InitAckFrame(2);
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(&ack);
-
- // The original alarm will fire. We should not time out because we had a
- // network event at t=5ms. The alarm will reregister.
- clock_.AdvanceTime(initial_idle_timeout.Subtract(five_ms));
- EXPECT_EQ(default_timeout, clock_.ApproximateNow());
- connection_.GetTimeoutAlarm()->Fire();
- EXPECT_TRUE(connection_.connected());
- EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_EQ(default_timeout.Add(five_ms),
- connection_.GetTimeoutAlarm()->deadline());
-
- // Now, send packets while advancing the time and verify that the connection
- // eventually times out.
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NETWORK_IDLE_TIMEOUT, _,
- ConnectionCloseSource::FROM_SELF));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
- for (int i = 0; i < 100 && connection_.connected(); ++i) {
- VLOG(1) << "sending data packet";
- connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0, !kFin,
- nullptr);
- connection_.GetTimeoutAlarm()->Fire();
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- }
- EXPECT_FALSE(connection_.connected());
- EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, TimeoutAfter5RTOs) {
- QuicSentPacketManagerPeer::SetMaxTailLossProbes(manager_, 2);
- EXPECT_TRUE(connection_.connected());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- QuicConfig config;
- QuicTagVector connection_options;
- connection_options.push_back(k5RTO);
- config.SetConnectionOptionsToSend(connection_options);
- connection_.SetFromConfig(config);
-
- // Send stream data.
- SendStreamDataToPeer(kClientDataStreamId1, "foo", 0, kFin, nullptr);
-
- EXPECT_CALL(visitor_, OnPathDegrading());
- // Fire the retransmission alarm 6 times, twice for TLP and 4 times for RTO.
- for (int i = 0; i < 6; ++i) {
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- connection_.GetRetransmissionAlarm()->Fire();
- EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_TRUE(connection_.connected());
- }
-
- EXPECT_EQ(2u, connection_.sent_packet_manager().GetConsecutiveTlpCount());
- EXPECT_EQ(4u, connection_.sent_packet_manager().GetConsecutiveRtoCount());
- // This time, we should time out.
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_TOO_MANY_RTOS, _,
- ConnectionCloseSource::FROM_SELF));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- connection_.GetRetransmissionAlarm()->Fire();
- EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_FALSE(connection_.connected());
-}
-
-TEST_P(QuicConnectionTest, SendScheduler) {
- // Test that if we send a packet without delay, it is not queued.
- QuicPacket* packet =
- ConstructDataPacket(kDefaultPathId, 1, !kEntropyFlag, !kHasStopWaiting);
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet,
- kTestEntropyHash, HAS_RETRANSMITTABLE_DATA, false,
- false);
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
-}
-
-TEST_P(QuicConnectionTest, FailToSendFirstPacket) {
- // Test that the connection does not crash when it fails to send the first
- // packet at which point self_address_ might be uninitialized.
- EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(1);
- QuicPacket* packet =
- ConstructDataPacket(kDefaultPathId, 1, !kEntropyFlag, !kHasStopWaiting);
- writer_->SetShouldWriteFail();
- connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet,
- kTestEntropyHash, HAS_RETRANSMITTABLE_DATA, false,
- false);
-}
-
-TEST_P(QuicConnectionTest, SendSchedulerEAGAIN) {
- QuicPacket* packet =
- ConstructDataPacket(kDefaultPathId, 1, !kEntropyFlag, !kHasStopWaiting);
- BlockOnNextWrite();
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0);
- connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet,
- kTestEntropyHash, HAS_RETRANSMITTABLE_DATA, false,
- false);
- EXPECT_EQ(1u, connection_.NumQueuedPackets());
-}
-
-TEST_P(QuicConnectionTest, TestQueueLimitsOnSendStreamData) {
- // All packets carry version info till version is negotiated.
- size_t payload_length;
- size_t length = GetPacketLengthForOneStream(
- connection_.version(), kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID,
- PACKET_1BYTE_PACKET_NUMBER, &payload_length);
- connection_.SetMaxPacketLength(length);
-
- // Queue the first packet.
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillOnce(testing::Return(QuicTime::Delta::FromMicroseconds(10)));
- const string payload(payload_length, 'a');
- EXPECT_EQ(0u,
- connection_.SendStreamDataWithString(3, payload, 0, !kFin, nullptr)
- .bytes_consumed);
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
-}
-
-TEST_P(QuicConnectionTest, LoopThroughSendingPackets) {
- // All packets carry version info till version is negotiated.
- size_t payload_length;
- // GetPacketLengthForOneStream() assumes a stream offset of 0 in determining
- // packet length. The size of the offset field in a stream frame is 0 for
- // offset 0, and 2 for non-zero offsets up through 16K. Increase
- // max_packet_length by 2 so that subsequent packets containing subsequent
- // stream frames with non-zero offets will fit within the packet length.
- size_t length =
- 2 + GetPacketLengthForOneStream(
- connection_.version(), kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID,
- PACKET_1BYTE_PACKET_NUMBER, &payload_length);
- connection_.SetMaxPacketLength(length);
-
- // Queue the first packet.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(7);
- // The first stream frame will have 2 fewer overhead bytes than the other six.
- const string payload(payload_length * 7 + 2, 'a');
- EXPECT_EQ(payload.size(),
- connection_.SendStreamDataWithString(1, payload, 0, !kFin, nullptr)
- .bytes_consumed);
-}
-
-TEST_P(QuicConnectionTest, LoopThroughSendingPacketsWithTruncation) {
- // Set up a larger payload than will fit in one packet.
- const string payload(connection_.max_packet_length(), 'a');
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
-
- // Now send some packets with no truncation.
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
- EXPECT_EQ(payload.size(),
- connection_.SendStreamDataWithString(3, payload, 0, !kFin, nullptr)
- .bytes_consumed);
- // Track the size of the second packet here. The overhead will be the largest
- // we see in this test, due to the non-truncated connection id.
- size_t non_truncated_packet_size = writer_->last_packet_size();
-
- // Change to a 0 byte connection id.
- QuicConfig config;
- QuicConfigPeer::SetReceivedBytesForConnectionId(&config, 0);
- connection_.SetFromConfig(config);
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
- EXPECT_EQ(payload.size(),
- connection_.SendStreamDataWithString(3, payload, 0, !kFin, nullptr)
- .bytes_consumed);
- // Just like above, we save 8 bytes on payload, and 8 on truncation.
- EXPECT_EQ(non_truncated_packet_size, writer_->last_packet_size() + 8 * 2);
-}
-
-TEST_P(QuicConnectionTest, SendDelayedAck) {
- QuicTime ack_time = clock_.ApproximateNow().Add(DefaultDelayedAckTime());
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
- framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
- // Process a packet from the non-crypto stream.
- frame1_.stream_id = 3;
-
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
- // instead of ENCRYPTION_NONE.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, 1, !kEntropyFlag, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
- // Simulate delayed ack alarm firing.
- connection_.GetAckAlarm()->Fire();
- // Check that ack is sent and that delayed ack alarm is reset.
- EXPECT_EQ(2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, SendDelayedAckDecimation) {
- QuicConnectionPeer::SetAckMode(&connection_, QuicConnection::ACK_DECIMATION);
-
- const size_t kMinRttMs = 40;
- RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- // The ack time should be based on min_rtt/4, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow().Add(
- QuicTime::Delta::FromMilliseconds(kMinRttMs / 4));
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
- framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
- // Process a packet from the non-crypto stream.
- frame1_.stream_id = 3;
-
- // Process all the initial packets in order so there aren't missing packets.
- QuicPacketNumber kFirstDecimatedPacket = 101;
- for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kEntropyFlag,
- !kHasStopWaiting, ENCRYPTION_INITIAL);
- }
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
- // instead of ENCRYPTION_NONE.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, !kEntropyFlag,
- !kHasStopWaiting, ENCRYPTION_INITIAL);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 0; i < 9; ++i) {
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i,
- !kEntropyFlag, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
- }
- // Check that ack is sent and that delayed ack alarm is reset.
- EXPECT_EQ(2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) {
- QuicConnectionPeer::SetAckMode(&connection_, QuicConnection::ACK_DECIMATION);
- QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125);
-
- const size_t kMinRttMs = 40;
- RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- // The ack time should be based on min_rtt/8, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow().Add(
- QuicTime::Delta::FromMilliseconds(kMinRttMs / 8));
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
- framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
- // Process a packet from the non-crypto stream.
- frame1_.stream_id = 3;
-
- // Process all the initial packets in order so there aren't missing packets.
- QuicPacketNumber kFirstDecimatedPacket = 101;
- for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kEntropyFlag,
- !kHasStopWaiting, ENCRYPTION_INITIAL);
- }
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
- // instead of ENCRYPTION_NONE.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, !kEntropyFlag,
- !kHasStopWaiting, ENCRYPTION_INITIAL);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 0; i < 9; ++i) {
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i,
- !kEntropyFlag, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
- }
- // Check that ack is sent and that delayed ack alarm is reset.
- EXPECT_EQ(2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) {
- QuicConnectionPeer::SetAckMode(
- &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING);
-
- const size_t kMinRttMs = 40;
- RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- // The ack time should be based on min_rtt/4, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow().Add(
- QuicTime::Delta::FromMilliseconds(kMinRttMs / 4));
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
- framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
- // Process a packet from the non-crypto stream.
- frame1_.stream_id = 3;
-
- // Process all the initial packets in order so there aren't missing packets.
- QuicPacketNumber kFirstDecimatedPacket = 101;
- for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kEntropyFlag,
- !kHasStopWaiting, ENCRYPTION_INITIAL);
- }
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
- // instead of ENCRYPTION_NONE.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, !kEntropyFlag,
- !kHasStopWaiting, ENCRYPTION_INITIAL);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // Process packet 10 first and ensure the alarm is one eighth min_rtt.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 9,
- !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
- ack_time = clock_.ApproximateNow().Add(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 0; i < 8; ++i) {
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i,
- !kEntropyFlag, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
- }
- // Check that ack is sent and that delayed ack alarm is reset.
- EXPECT_EQ(2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) {
- QuicConnectionPeer::SetAckMode(
- &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING);
-
- const size_t kMinRttMs = 40;
- RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- // The ack time should be based on min_rtt/4, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow().Add(
- QuicTime::Delta::FromMilliseconds(kMinRttMs / 4));
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
- framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
- // Process a packet from the non-crypto stream.
- frame1_.stream_id = 3;
-
- // Process all the initial packets in order so there aren't missing packets.
- QuicPacketNumber kFirstDecimatedPacket = 101;
- for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kEntropyFlag,
- !kHasStopWaiting, ENCRYPTION_INITIAL);
- }
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
- // instead of ENCRYPTION_NONE.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, !kEntropyFlag,
- !kHasStopWaiting, ENCRYPTION_INITIAL);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // Process packet 10 first and ensure the alarm is one eighth min_rtt.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 19,
- !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
- ack_time = clock_.ApproximateNow().Add(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 0; i < 8; ++i) {
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i,
- !kEntropyFlag, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
- }
- // Check that ack is sent and that delayed ack alarm is reset.
- EXPECT_EQ(2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-
- // The next packet received in order will cause an immediate ack,
- // because it fills a hole.
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 10,
- !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
- // Check that ack is sent and that delayed ack alarm is reset.
- EXPECT_EQ(2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) {
- QuicConnectionPeer::SetAckMode(
- &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING);
- QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125);
-
- const size_t kMinRttMs = 40;
- RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- // The ack time should be based on min_rtt/8, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow().Add(
- QuicTime::Delta::FromMilliseconds(kMinRttMs / 8));
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
- framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
- // Process a packet from the non-crypto stream.
- frame1_.stream_id = 3;
-
- // Process all the initial packets in order so there aren't missing packets.
- QuicPacketNumber kFirstDecimatedPacket = 101;
- for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kEntropyFlag,
- !kHasStopWaiting, ENCRYPTION_INITIAL);
- }
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
- // instead of ENCRYPTION_NONE.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, !kEntropyFlag,
- !kHasStopWaiting, ENCRYPTION_INITIAL);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // Process packet 10 first and ensure the alarm is one eighth min_rtt.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 9,
- !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
- ack_time = clock_.ApproximateNow().Add(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 0; i < 8; ++i) {
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i,
- !kEntropyFlag, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
- }
- // Check that ack is sent and that delayed ack alarm is reset.
- EXPECT_EQ(2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest,
- SendDelayedAckDecimationWithLargeReorderingEighthRtt) {
- QuicConnectionPeer::SetAckMode(
- &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING);
- QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125);
-
- const size_t kMinRttMs = 40;
- RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- // The ack time should be based on min_rtt/8, since it's less than the
- // default delayed ack time.
- QuicTime ack_time = clock_.ApproximateNow().Add(
- QuicTime::Delta::FromMilliseconds(kMinRttMs / 8));
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- const uint8_t tag = 0x07;
- connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag));
- framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag));
- // Process a packet from the non-crypto stream.
- frame1_.stream_id = 3;
-
- // Process all the initial packets in order so there aren't missing packets.
- QuicPacketNumber kFirstDecimatedPacket = 101;
- for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) {
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kEntropyFlag,
- !kHasStopWaiting, ENCRYPTION_INITIAL);
- }
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used
- // instead of ENCRYPTION_NONE.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, !kEntropyFlag,
- !kHasStopWaiting, ENCRYPTION_INITIAL);
-
- // Check if delayed ack timer is running for the expected interval.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // Process packet 10 first and ensure the alarm is one eighth min_rtt.
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 19,
- !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
- ack_time = clock_.ApproximateNow().Add(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // The 10th received packet causes an ack to be sent.
- for (int i = 0; i < 8; ++i) {
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i,
- !kEntropyFlag, !kHasStopWaiting,
- ENCRYPTION_INITIAL);
- }
- // Check that ack is sent and that delayed ack alarm is reset.
- EXPECT_EQ(2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-
- // The next packet received in order will cause an immediate ack,
- // because it fills a hole.
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 10,
- !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
- // Check that ack is sent and that delayed ack alarm is reset.
- EXPECT_EQ(2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, SendDelayedAckOnHandshakeConfirmed) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- ProcessPacket(kDefaultPathId, 1);
- // Check that ack is sent and that delayed ack alarm is set.
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- QuicTime ack_time = clock_.ApproximateNow().Add(DefaultDelayedAckTime());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // Completing the handshake as the server does nothing.
- QuicConnectionPeer::SetPerspective(&connection_, Perspective::IS_SERVER);
- connection_.OnHandshakeComplete();
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-
- // Complete the handshake as the client decreases the delayed ack time to 0ms.
- QuicConnectionPeer::SetPerspective(&connection_, Perspective::IS_CLIENT);
- connection_.OnHandshakeComplete();
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
- EXPECT_EQ(clock_.ApproximateNow(), connection_.GetAckAlarm()->deadline());
-}
-
-TEST_P(QuicConnectionTest, SendDelayedAckOnSecondPacket) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- ProcessPacket(kDefaultPathId, 1);
- ProcessPacket(kDefaultPathId, 2);
- // Check that ack is sent and that delayed ack alarm is reset.
- EXPECT_EQ(2u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, NoAckOnOldNacks) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- // Drop one packet, triggering a sequence of acks.
- ProcessPacket(kDefaultPathId, 2);
- size_t frames_per_ack = 2;
- EXPECT_EQ(frames_per_ack, writer_->frame_count());
- EXPECT_FALSE(writer_->ack_frames().empty());
- writer_->Reset();
- ProcessPacket(kDefaultPathId, 3);
- EXPECT_EQ(frames_per_ack, writer_->frame_count());
- EXPECT_FALSE(writer_->ack_frames().empty());
- writer_->Reset();
- ProcessPacket(kDefaultPathId, 4);
- EXPECT_EQ(frames_per_ack, writer_->frame_count());
- EXPECT_FALSE(writer_->ack_frames().empty());
- writer_->Reset();
- ProcessPacket(kDefaultPathId, 5);
- EXPECT_EQ(frames_per_ack, writer_->frame_count());
- EXPECT_FALSE(writer_->ack_frames().empty());
- writer_->Reset();
- // Now only set the timer on the 6th packet, instead of sending another ack.
- ProcessPacket(kDefaultPathId, 6);
- EXPECT_EQ(0u, writer_->frame_count());
- EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingPacket) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- ProcessPacket(kDefaultPathId, 1);
- connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0, !kFin,
- nullptr);
- // Check that ack is bundled with outgoing data and that delayed ack
- // alarm is reset.
- EXPECT_EQ(3u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingCryptoPacket) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- ProcessPacket(kDefaultPathId, 1);
- connection_.SendStreamDataWithString(kCryptoStreamId, "foo", 0, !kFin,
- nullptr);
- // Check that ack is bundled with outgoing crypto data.
- EXPECT_EQ(3u, writer_->frame_count());
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, BlockAndBufferOnFirstCHLOPacketOfTwo) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- ProcessPacket(kDefaultPathId, 1);
- BlockOnNextWrite();
- writer_->set_is_write_blocked_data_buffered(true);
- connection_.SendStreamDataWithString(kCryptoStreamId, "foo", 0, !kFin,
- nullptr);
- EXPECT_TRUE(writer_->IsWriteBlocked());
- EXPECT_FALSE(connection_.HasQueuedData());
- connection_.SendStreamDataWithString(kCryptoStreamId, "bar", 3, !kFin,
- nullptr);
- EXPECT_TRUE(writer_->IsWriteBlocked());
- EXPECT_TRUE(connection_.HasQueuedData());
-}
-
-TEST_P(QuicConnectionTest, BundleAckForSecondCHLO) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- EXPECT_CALL(visitor_, OnCanWrite())
- .WillOnce(IgnoreResult(InvokeWithoutArgs(
- &connection_, &TestConnection::SendCryptoStreamData)));
- // Process a packet from the crypto stream, which is frame1_'s default.
- // Receiving the CHLO as packet 2 first will cause the connection to
- // immediately send an ack, due to the packet gap.
- ProcessPacket(kDefaultPathId, 2);
- // Check that ack is sent and that delayed ack alarm is reset.
- EXPECT_EQ(3u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- EXPECT_EQ(1u, writer_->stream_frames().size());
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, BundleAckWithDataOnIncomingAck) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0, !kFin,
- nullptr);
- connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 3, !kFin,
- nullptr);
- // Ack the second packet, which will retransmit the first packet.
- QuicAckFrame ack = InitAckFrame(2);
- NackPacket(1, &ack);
- SendAlgorithmInterface::CongestionVector lost_packets;
- lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
- .WillOnce(SetArgPointee<4>(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(&ack);
- EXPECT_EQ(1u, writer_->frame_count());
- EXPECT_EQ(1u, writer_->stream_frames().size());
- writer_->Reset();
-
- // Now ack the retransmission, which will both raise the high water mark
- // and see if there is more data to send.
- ack = InitAckFrame(3);
- NackPacket(1, &ack);
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(&ack);
-
- // Check that no packet is sent and the ack alarm isn't set.
- EXPECT_EQ(0u, writer_->frame_count());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- writer_->Reset();
-
- // Send the same ack, but send both data and an ack together.
- ack = InitAckFrame(3);
- NackPacket(1, &ack);
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
- EXPECT_CALL(visitor_, OnCanWrite())
- .WillOnce(IgnoreResult(InvokeWithoutArgs(
- &connection_, &TestConnection::EnsureWritableAndSendStreamData5)));
- ProcessAckPacket(&ack);
-
- // Check that ack is bundled with outgoing data and the delayed ack
- // alarm is reset.
- EXPECT_EQ(3u, writer_->frame_count());
- EXPECT_FALSE(writer_->stop_waiting_frames().empty());
- EXPECT_FALSE(writer_->ack_frames().empty());
- EXPECT_EQ(1u, writer_->stream_frames().size());
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-}
-
-TEST_P(QuicConnectionTest, NoAckSentForClose) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- ProcessPacket(kDefaultPathId, 1);
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, _,
- ConnectionCloseSource::FROM_PEER));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
- ProcessClosePacket(kDefaultPathId, 2);
-}
-
-TEST_P(QuicConnectionTest, SendWhenDisconnected) {
- EXPECT_TRUE(connection_.connected());
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, _,
- ConnectionCloseSource::FROM_SELF));
- connection_.CloseConnection(QUIC_PEER_GOING_AWAY, "no reason",
- ConnectionCloseBehavior::SILENT_CLOSE);
- EXPECT_FALSE(connection_.connected());
- EXPECT_FALSE(connection_.CanWriteStreamData());
- QuicPacket* packet =
- ConstructDataPacket(kDefaultPathId, 1, !kEntropyFlag, !kHasStopWaiting);
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0);
- connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet,
- kTestEntropyHash, HAS_RETRANSMITTABLE_DATA, false,
- false);
-}
-
-TEST_P(QuicConnectionTest, PublicReset) {
- QuicPublicResetPacket header;
- header.public_header.connection_id = connection_id_;
- header.public_header.reset_flag = true;
- header.public_header.version_flag = false;
- header.rejected_packet_number = 10101;
- std::unique_ptr<QuicEncryptedPacket> packet(
- framer_.BuildPublicResetPacket(header));
- std::unique_ptr<QuicReceivedPacket> received(
- ConstructReceivedPacket(*packet, QuicTime::Zero()));
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PUBLIC_RESET, _,
- ConnectionCloseSource::FROM_PEER));
- connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received);
-}
-
-TEST_P(QuicConnectionTest, GoAway) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- QuicGoAwayFrame goaway;
- goaway.last_good_stream_id = 1;
- goaway.error_code = QUIC_PEER_GOING_AWAY;
- goaway.reason_phrase = "Going away.";
- EXPECT_CALL(visitor_, OnGoAway(_));
- ProcessGoAwayPacket(&goaway);
-}
-
-TEST_P(QuicConnectionTest, WindowUpdate) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- QuicWindowUpdateFrame window_update;
- window_update.stream_id = 3;
- window_update.byte_offset = 1234;
- EXPECT_CALL(visitor_, OnWindowUpdateFrame(_));
- ProcessFramePacket(QuicFrame(&window_update));
-}
-
-TEST_P(QuicConnectionTest, Blocked) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- QuicBlockedFrame blocked;
- blocked.stream_id = 3;
- EXPECT_CALL(visitor_, OnBlockedFrame(_));
- ProcessFramePacket(QuicFrame(&blocked));
-}
-
-TEST_P(QuicConnectionTest, PathClose) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- QuicPathCloseFrame path_close = QuicPathCloseFrame(1);
- ProcessPathClosePacket(&path_close);
- EXPECT_TRUE(QuicFramerPeer::IsPathClosed(
- QuicConnectionPeer::GetFramer(&connection_), 1));
-}
-
-TEST_P(QuicConnectionTest, ZeroBytePacket) {
- // Don't close the connection for zero byte packets.
- EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(0);
- QuicReceivedPacket encrypted(nullptr, 0, QuicTime::Zero());
- connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, encrypted);
-}
-
-TEST_P(QuicConnectionTest, MissingPacketsBeforeLeastUnacked) {
- // Set the packet number of the ack packet to be least unacked (4).
- QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 3);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- QuicStopWaitingFrame frame = InitStopWaitingFrame(4);
- ProcessStopWaitingPacket(&frame);
- if (outgoing_ack()->missing) {
- EXPECT_TRUE(outgoing_ack()->packets.Empty());
- } else {
- EXPECT_FALSE(outgoing_ack()->packets.Empty());
- }
-}
-
-TEST_P(QuicConnectionTest, ReceivedEntropyHashCalculation) {
- if (GetParam().version > QUIC_VERSION_33) {
- return;
- }
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AtLeast(1));
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- ProcessDataPacket(kDefaultPathId, 1, kEntropyFlag);
- ProcessDataPacket(kDefaultPathId, 4, kEntropyFlag);
- ProcessDataPacket(kDefaultPathId, 3, !kEntropyFlag);
- ProcessDataPacket(kDefaultPathId, 7, kEntropyFlag);
- EXPECT_EQ(146u, outgoing_ack()->entropy_hash);
-}
-
-TEST_P(QuicConnectionTest, UpdateEntropyForReceivedPackets) {
- if (GetParam().version > QUIC_VERSION_33) {
- return;
- }
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AtLeast(1));
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- ProcessDataPacket(kDefaultPathId, 1, kEntropyFlag);
- ProcessDataPacket(kDefaultPathId, 5, kEntropyFlag);
- ProcessDataPacket(kDefaultPathId, 4, !kEntropyFlag);
- EXPECT_EQ(34u, outgoing_ack()->entropy_hash);
- // Make 4th packet my least unacked, and update entropy for 2, 3 packets.
- QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 5);
- QuicPacketEntropyHash six_packet_entropy_hash = 0;
- QuicPacketEntropyHash random_entropy_hash = 129u;
- QuicStopWaitingFrame frame = InitStopWaitingFrame(4);
- frame.entropy_hash = random_entropy_hash;
- if (ProcessStopWaitingPacket(&frame)) {
- six_packet_entropy_hash = 1 << 6;
- }
-
- EXPECT_EQ((random_entropy_hash + (1 << 5) + six_packet_entropy_hash),
- outgoing_ack()->entropy_hash);
-}
-
-TEST_P(QuicConnectionTest, UpdateEntropyHashUptoCurrentPacket) {
- if (GetParam().version > QUIC_VERSION_33) {
- return;
- }
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AtLeast(1));
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- ProcessDataPacket(kDefaultPathId, 1, kEntropyFlag);
- ProcessDataPacket(kDefaultPathId, 5, !kEntropyFlag);
- ProcessDataPacket(kDefaultPathId, 22, kEntropyFlag);
- EXPECT_EQ(66u, outgoing_ack()->entropy_hash);
- QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 22);
- QuicPacketEntropyHash random_entropy_hash = 85u;
- // Current packet is the least unacked packet.
- QuicPacketEntropyHash ack_entropy_hash;
- QuicStopWaitingFrame frame = InitStopWaitingFrame(23);
- frame.entropy_hash = random_entropy_hash;
- ack_entropy_hash = ProcessStopWaitingPacket(&frame);
- EXPECT_EQ((random_entropy_hash + ack_entropy_hash),
- outgoing_ack()->entropy_hash);
- ProcessDataPacket(kDefaultPathId, 25, kEntropyFlag);
- EXPECT_EQ((random_entropy_hash + ack_entropy_hash + (1 << (25 % 8))),
- outgoing_ack()->entropy_hash);
-}
-
-TEST_P(QuicConnectionTest, EntropyCalculationForTruncatedAck) {
- if (GetParam().version > QUIC_VERSION_33) {
- return;
- }
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AtLeast(1));
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- QuicPacketEntropyHash entropy[51];
- entropy[0] = 0;
- for (int i = 1; i < 51; ++i) {
- bool should_send = i % 10 != 1;
- bool entropy_flag = (i & (i - 1)) != 0;
- if (!should_send) {
- entropy[i] = entropy[i - 1];
- continue;
- }
- if (entropy_flag) {
- entropy[i] = entropy[i - 1] ^ (1 << (i % 8));
- } else {
- entropy[i] = entropy[i - 1];
- }
- ProcessDataPacket(kDefaultPathId, i, entropy_flag);
- }
- for (int i = 1; i < 50; ++i) {
- EXPECT_EQ(entropy[i],
- QuicConnectionPeer::ReceivedEntropyHash(&connection_, i));
- }
-}
-
-TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacket) {
- connection_.SetSupportedVersions(QuicSupportedVersions());
- set_perspective(Perspective::IS_SERVER);
- peer_framer_.set_version_for_tests(QUIC_VERSION_UNSUPPORTED);
-
- QuicPacketHeader header;
- header.public_header.connection_id = connection_id_;
- header.public_header.version_flag = true;
- header.path_id = kDefaultPathId;
- header.packet_number = 12;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&frame1_));
- std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
- char buffer[kMaxPacketSize];
- size_t encrypted_length = framer_.EncryptPayload(
- ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize);
-
- 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(kSupportedQuicVersions);
- ASSERT_EQ(num_versions,
- writer_->version_negotiation_packet()->versions.size());
-
- // We expect all versions in kSupportedQuicVersions to be
- // included in the packet.
- for (size_t i = 0; i < num_versions; ++i) {
- EXPECT_EQ(kSupportedQuicVersions[i],
- writer_->version_negotiation_packet()->versions[i]);
- }
-}
-
-TEST_P(QuicConnectionTest, ServerSendsVersionNegotiationPacketSocketBlocked) {
- connection_.SetSupportedVersions(QuicSupportedVersions());
- set_perspective(Perspective::IS_SERVER);
- peer_framer_.set_version_for_tests(QUIC_VERSION_UNSUPPORTED);
-
- QuicPacketHeader header;
- header.public_header.connection_id = connection_id_;
- header.public_header.version_flag = true;
- header.packet_number = 12;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&frame1_));
- std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
- char buffer[kMaxPacketSize];
- size_t encrypted_length = framer_.EncryptPayload(
- ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize);
-
- framer_.set_version(version());
- BlockOnNextWrite();
- connection_.ProcessUdpPacket(
- kSelfAddress, kPeerAddress,
- QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
- EXPECT_EQ(0u, writer_->last_packet_size());
- EXPECT_TRUE(connection_.HasQueuedData());
-
- writer_->SetWritable();
- connection_.OnCanWrite();
- EXPECT_TRUE(writer_->version_negotiation_packet() != nullptr);
-
- size_t num_versions = arraysize(kSupportedQuicVersions);
- ASSERT_EQ(num_versions,
- writer_->version_negotiation_packet()->versions.size());
-
- // We expect all versions in kSupportedQuicVersions to be
- // included in the packet.
- for (size_t i = 0; i < num_versions; ++i) {
- EXPECT_EQ(kSupportedQuicVersions[i],
- writer_->version_negotiation_packet()->versions[i]);
- }
-}
-
-TEST_P(QuicConnectionTest,
- ServerSendsVersionNegotiationPacketSocketBlockedDataBuffered) {
- connection_.SetSupportedVersions(QuicSupportedVersions());
- set_perspective(Perspective::IS_SERVER);
- peer_framer_.set_version_for_tests(QUIC_VERSION_UNSUPPORTED);
-
- QuicPacketHeader header;
- header.public_header.connection_id = connection_id_;
- header.public_header.version_flag = true;
- header.packet_number = 12;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&frame1_));
- std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
- char buffer[kMaxPacketSize];
- size_t encryped_length = framer_.EncryptPayload(
- ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize);
-
- framer_.set_version(version());
- set_perspective(Perspective::IS_SERVER);
- BlockOnNextWrite();
- writer_->set_is_write_blocked_data_buffered(true);
- connection_.ProcessUdpPacket(
- kSelfAddress, kPeerAddress,
- QuicReceivedPacket(buffer, encryped_length, QuicTime::Zero(), false));
- EXPECT_EQ(0u, writer_->last_packet_size());
- EXPECT_FALSE(connection_.HasQueuedData());
-}
-
-TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) {
- // Start out with some unsupported version.
- QuicConnectionPeer::GetFramer(&connection_)
- ->set_version_for_tests(QUIC_VERSION_UNSUPPORTED);
-
- // Send a version negotiation packet.
- std::unique_ptr<QuicEncryptedPacket> encrypted(
- framer_.BuildVersionNegotiationPacket(connection_id_,
- QuicSupportedVersions()));
- std::unique_ptr<QuicReceivedPacket> received(
- ConstructReceivedPacket(*encrypted, QuicTime::Zero()));
- connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received);
-
- // Now force another packet. The connection should transition into
- // NEGOTIATED_VERSION state and tell the packet creator to StopSendingVersion.
- QuicPacketHeader header;
- header.public_header.connection_id = connection_id_;
- header.path_id = kDefaultPathId;
- header.packet_number = 12;
- header.public_header.version_flag = false;
- QuicFrames frames;
- frames.push_back(QuicFrame(&frame1_));
- std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
- char buffer[kMaxPacketSize];
- size_t encrypted_length = framer_.EncryptPayload(
- ENCRYPTION_NONE, kDefaultPathId, 12, *packet, buffer, kMaxPacketSize);
- ASSERT_NE(0u, encrypted_length);
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- connection_.ProcessUdpPacket(
- kSelfAddress, kPeerAddress,
- QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
-
- ASSERT_FALSE(QuicPacketCreatorPeer::SendVersionInPacket(creator_));
-}
-
-TEST_P(QuicConnectionTest, BadVersionNegotiation) {
- // Send a version negotiation packet with the version the client started with.
- // It should be rejected.
- EXPECT_CALL(visitor_,
- OnConnectionClosed(QUIC_INVALID_VERSION_NEGOTIATION_PACKET, _,
- ConnectionCloseSource::FROM_SELF));
- std::unique_ptr<QuicEncryptedPacket> encrypted(
- framer_.BuildVersionNegotiationPacket(connection_id_,
- QuicSupportedVersions()));
- std::unique_ptr<QuicReceivedPacket> received(
- ConstructReceivedPacket(*encrypted, QuicTime::Zero()));
- connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received);
-}
-
-TEST_P(QuicConnectionTest, CheckSendStats) {
- connection_.DisableTailLossProbe();
-
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- connection_.SendStreamDataWithString(3, "first", 0, !kFin, nullptr);
- size_t first_packet_size = writer_->last_packet_size();
-
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- connection_.SendStreamDataWithString(5, "second", 0, !kFin, nullptr);
- size_t second_packet_size = writer_->last_packet_size();
-
- // 2 retransmissions due to rto, 1 due to explicit nack.
- EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(3);
-
- // Retransmit due to RTO.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10));
- connection_.GetRetransmissionAlarm()->Fire();
-
- // Retransmit due to explicit nacks.
- QuicAckFrame nack_three = InitAckFrame(4);
- NackPacket(3, &nack_three);
- NackPacket(1, &nack_three);
- SendAlgorithmInterface::CongestionVector lost_packets;
- lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
- lost_packets.push_back(std::make_pair(3, kMaxPacketSize));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
- .WillOnce(SetArgPointee<4>(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- EXPECT_CALL(visitor_, OnCanWrite());
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- ProcessAckPacket(&nack_three);
-
- EXPECT_CALL(*send_algorithm_, BandwidthEstimate())
- .WillOnce(Return(QuicBandwidth::Zero()));
-
- const QuicConnectionStats& stats = connection_.GetStats();
- EXPECT_EQ(3 * first_packet_size + 2 * second_packet_size - kQuicVersionSize,
- stats.bytes_sent);
- EXPECT_EQ(5u, stats.packets_sent);
- EXPECT_EQ(2 * first_packet_size + second_packet_size - kQuicVersionSize,
- stats.bytes_retransmitted);
- EXPECT_EQ(3u, stats.packets_retransmitted);
- EXPECT_EQ(1u, stats.rto_count);
- EXPECT_EQ(kDefaultMaxPacketSize, stats.max_packet_size);
-}
-
-TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) {
- // Construct a packet with stream frame and connection close frame.
- QuicPacketHeader header;
- header.public_header.connection_id = connection_id_;
- header.packet_number = 1;
- header.public_header.version_flag = false;
-
- QuicConnectionCloseFrame qccf;
- qccf.error_code = QUIC_PEER_GOING_AWAY;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&frame1_));
- frames.push_back(QuicFrame(&qccf));
- std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
- EXPECT_TRUE(nullptr != packet.get());
- char buffer[kMaxPacketSize];
- size_t encrypted_length = framer_.EncryptPayload(
- ENCRYPTION_NONE, kDefaultPathId, 1, *packet, buffer, kMaxPacketSize);
-
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, _,
- ConnectionCloseSource::FROM_PEER));
- EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- connection_.ProcessUdpPacket(
- kSelfAddress, kPeerAddress,
- QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
-}
-
-TEST_P(QuicConnectionTest, SelectMutualVersion) {
- connection_.SetSupportedVersions(QuicSupportedVersions());
- // Set the connection to speak the lowest quic version.
- connection_.set_version(QuicVersionMin());
- EXPECT_EQ(QuicVersionMin(), connection_.version());
-
- // Pass in available versions which includes a higher mutually supported
- // version. The higher mutually supported version should be selected.
- QuicVersionVector supported_versions;
- for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
- supported_versions.push_back(kSupportedQuicVersions[i]);
- }
- EXPECT_TRUE(connection_.SelectMutualVersion(supported_versions));
- 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());
- QuicVersionVector lowest_version_vector;
- lowest_version_vector.push_back(QuicVersionMin());
- EXPECT_TRUE(connection_.SelectMutualVersion(lowest_version_vector));
- EXPECT_EQ(QuicVersionMin(), connection_.version());
-
- // Shouldn't be able to find a mutually supported version.
- QuicVersionVector unsupported_version;
- unsupported_version.push_back(QUIC_VERSION_UNSUPPORTED);
- EXPECT_FALSE(connection_.SelectMutualVersion(unsupported_version));
-}
-
-TEST_P(QuicConnectionTest, ConnectionCloseWhenWritable) {
- EXPECT_FALSE(writer_->IsWriteBlocked());
-
- // Send a packet.
- connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
- EXPECT_EQ(0u, connection_.NumQueuedPackets());
- EXPECT_EQ(1u, writer_->packets_write_attempts());
-
- TriggerConnectionClose();
- EXPECT_EQ(2u, writer_->packets_write_attempts());
-}
-
-TEST_P(QuicConnectionTest, ConnectionCloseGettingWriteBlocked) {
- BlockOnNextWrite();
- TriggerConnectionClose();
- EXPECT_EQ(1u, writer_->packets_write_attempts());
- EXPECT_TRUE(writer_->IsWriteBlocked());
-}
-
-TEST_P(QuicConnectionTest, ConnectionCloseWhenWriteBlocked) {
- BlockOnNextWrite();
- connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
- EXPECT_EQ(1u, connection_.NumQueuedPackets());
- EXPECT_EQ(1u, writer_->packets_write_attempts());
- EXPECT_TRUE(writer_->IsWriteBlocked());
- TriggerConnectionClose();
- EXPECT_EQ(1u, writer_->packets_write_attempts());
-}
-
-TEST_P(QuicConnectionTest, AckNotifierTriggerCallback) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- // Create a listener which we expect to be called.
- scoped_refptr<MockAckListener> listener(new MockAckListener);
- EXPECT_CALL(*listener, OnPacketAcked(_, _)).Times(1);
-
- // Send some data, which will register the listener to be notified.
- connection_.SendStreamDataWithString(1, "foo", 0, !kFin, listener.get());
-
- // Process an ACK from the server which should trigger the callback.
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- QuicAckFrame frame = InitAckFrame(1);
- ProcessAckPacket(&frame);
-}
-
-TEST_P(QuicConnectionTest, AckNotifierFailToTriggerCallback) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- // Create a listener which we don't expect to be called.
- scoped_refptr<MockAckListener> listener(new MockAckListener);
- EXPECT_CALL(*listener, OnPacketAcked(_, _)).Times(0);
-
- // Send some data, which will register the listener to be notified. This will
- // not be ACKed and so the listener should never be called.
- connection_.SendStreamDataWithString(1, "foo", 0, !kFin, listener.get());
-
- // Send some other data which we will ACK.
- connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
- connection_.SendStreamDataWithString(1, "bar", 0, !kFin, nullptr);
-
- // Now we receive ACK for packets 2 and 3, but importantly missing packet 1
- // which we registered to be notified about.
- QuicAckFrame frame = InitAckFrame(3);
- NackPacket(1, &frame);
- SendAlgorithmInterface::CongestionVector lost_packets;
- lost_packets.push_back(std::make_pair(1, kMaxPacketSize));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
- .WillOnce(SetArgPointee<4>(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- ProcessAckPacket(&frame);
-}
-
-TEST_P(QuicConnectionTest, AckNotifierCallbackAfterRetransmission) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- // Create a listener which we expect to be called.
- scoped_refptr<MockAckListener> listener(new MockAckListener);
- EXPECT_CALL(*listener, OnPacketRetransmitted(3)).Times(1);
- EXPECT_CALL(*listener, OnPacketAcked(3, _)).Times(1);
-
- // Send four packets, and register to be notified on ACK of packet 2.
- connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
- connection_.SendStreamDataWithString(3, "bar", 0, !kFin, listener.get());
- connection_.SendStreamDataWithString(3, "baz", 0, !kFin, nullptr);
- connection_.SendStreamDataWithString(3, "qux", 0, !kFin, nullptr);
-
- // Now we receive ACK for packets 1, 3, and 4 and lose 2.
- QuicAckFrame frame = InitAckFrame(4);
- NackPacket(2, &frame);
- SendAlgorithmInterface::CongestionVector lost_packets;
- lost_packets.push_back(std::make_pair(2, kMaxPacketSize));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
- .WillOnce(SetArgPointee<4>(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- ProcessAckPacket(&frame);
-
- // Now we get an ACK for packet 5 (retransmitted packet 2), which should
- // trigger the callback.
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- QuicAckFrame second_ack_frame = InitAckFrame(5);
- ProcessAckPacket(&second_ack_frame);
-}
-
-// AckNotifierCallback is triggered by the ack of a packet that timed
-// out and was retransmitted, even though the retransmission has a
-// different packet number.
-TEST_P(QuicConnectionTest, AckNotifierCallbackForAckAfterRTO) {
- connection_.DisableTailLossProbe();
-
- // Create a listener which we expect to be called.
- scoped_refptr<MockAckListener> listener(new StrictMock<MockAckListener>);
-
- QuicTime default_retransmission_time =
- clock_.ApproximateNow().Add(DefaultRetransmissionTime());
- connection_.SendStreamDataWithString(3, "foo", 0, !kFin, listener.get());
- EXPECT_EQ(1u, stop_waiting()->least_unacked);
-
- EXPECT_EQ(1u, writer_->header().packet_number);
- EXPECT_EQ(default_retransmission_time,
- connection_.GetRetransmissionAlarm()->deadline());
- // Simulate the retransmission alarm firing.
- clock_.AdvanceTime(DefaultRetransmissionTime());
- EXPECT_CALL(*listener, OnPacketRetransmitted(3));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
- connection_.GetRetransmissionAlarm()->Fire();
- EXPECT_EQ(2u, writer_->header().packet_number);
- // We do not raise the high water mark yet.
- EXPECT_EQ(1u, stop_waiting()->least_unacked);
-
- // Ack the original packet, which will revert the RTO.
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- EXPECT_CALL(*listener, OnPacketAcked(3, _));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- QuicAckFrame ack_frame = InitAckFrame(1);
- ProcessAckPacket(&ack_frame);
-
- // listener is not notified again when the retransmit is acked.
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- QuicAckFrame second_ack_frame = InitAckFrame(2);
- ProcessAckPacket(&second_ack_frame);
-}
-
-// AckNotifierCallback is triggered by the ack of a packet that was
-// previously nacked, even though the retransmission has a different
-// packet number.
-TEST_P(QuicConnectionTest, AckNotifierCallbackForAckOfNackedPacket) {
- // Create a listener which we expect to be called.
- scoped_refptr<MockAckListener> listener(new StrictMock<MockAckListener>);
-
- // Send four packets, and register to be notified on ACK of packet 2.
- connection_.SendStreamDataWithString(3, "foo", 0, !kFin, nullptr);
- connection_.SendStreamDataWithString(3, "bar", 0, !kFin, listener.get());
- connection_.SendStreamDataWithString(3, "baz", 0, !kFin, nullptr);
- connection_.SendStreamDataWithString(3, "qux", 0, !kFin, nullptr);
-
- // Now we receive ACK for packets 1, 3, and 4 and lose 2.
- QuicAckFrame frame = InitAckFrame(4);
- NackPacket(2, &frame);
- EXPECT_CALL(*listener, OnPacketRetransmitted(_));
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- SendAlgorithmInterface::CongestionVector lost_packets;
- lost_packets.push_back(std::make_pair(2, kMaxPacketSize));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _))
- .WillOnce(SetArgPointee<4>(lost_packets));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- ProcessAckPacket(&frame);
-
- // Now we get an ACK for packet 2, which was previously nacked.
- EXPECT_CALL(*listener, OnPacketAcked(3, _));
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
- QuicAckFrame second_ack_frame = InitAckFrame(4);
- ProcessAckPacket(&second_ack_frame);
-
- // Verify that the listener is not notified again when the
- // retransmit is acked.
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- QuicAckFrame third_ack_frame = InitAckFrame(5);
- ProcessAckPacket(&third_ack_frame);
-}
-
-TEST_P(QuicConnectionTest, OnPacketHeaderDebugVisitor) {
- QuicPacketHeader header;
-
- std::unique_ptr<MockQuicConnectionDebugVisitor> debug_visitor(
- new MockQuicConnectionDebugVisitor());
- connection_.set_debug_visitor(debug_visitor.get());
- EXPECT_CALL(*debug_visitor, OnPacketHeader(Ref(header))).Times(1);
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)).Times(1);
- EXPECT_CALL(*debug_visitor, OnSuccessfulVersionNegotiation(_)).Times(1);
- connection_.OnPacketHeader(header);
-}
-
-TEST_P(QuicConnectionTest, Pacing) {
- // static_cast here does not work if using multipath_sent_packet_manager.
- FLAGS_quic_enable_multipath = false;
- TestConnection server(connection_id_, kSelfAddress, helper_.get(),
- alarm_factory_.get(), writer_.get(),
- Perspective::IS_SERVER, version());
- TestConnection client(connection_id_, kPeerAddress, helper_.get(),
- alarm_factory_.get(), writer_.get(),
- Perspective::IS_CLIENT, version());
- EXPECT_FALSE(QuicSentPacketManagerPeer::UsingPacing(
- static_cast<const QuicSentPacketManager*>(
- &client.sent_packet_manager())));
- EXPECT_FALSE(QuicSentPacketManagerPeer::UsingPacing(
- static_cast<const QuicSentPacketManager*>(
- &server.sent_packet_manager())));
-}
-
-TEST_P(QuicConnectionTest, WindowUpdateInstigateAcks) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- // Send a WINDOW_UPDATE frame.
- QuicWindowUpdateFrame window_update;
- window_update.stream_id = 3;
- window_update.byte_offset = 1234;
- EXPECT_CALL(visitor_, OnWindowUpdateFrame(_));
- ProcessFramePacket(QuicFrame(&window_update));
-
- // Ensure that this has caused the ACK alarm to be set.
- QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
- EXPECT_TRUE(ack_alarm->IsSet());
-}
-
-TEST_P(QuicConnectionTest, BlockedFrameInstigateAcks) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- // Send a BLOCKED frame.
- QuicBlockedFrame blocked;
- blocked.stream_id = 3;
- EXPECT_CALL(visitor_, OnBlockedFrame(_));
- ProcessFramePacket(QuicFrame(&blocked));
-
- // Ensure that this has caused the ACK alarm to be set.
- QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_);
- EXPECT_TRUE(ack_alarm->IsSet());
-}
-
-TEST_P(QuicConnectionTest, NoDataNoFin) {
- // Make sure that a call to SendStreamWithData, with no data and no FIN, does
- // not result in a QuicAckNotifier being used-after-free (fail under ASAN).
- // Regression test for b/18594622
- scoped_refptr<MockAckListener> listener(new MockAckListener);
- EXPECT_DFATAL(
- connection_.SendStreamDataWithString(3, "", 0, !kFin, listener.get()),
- "Attempt to send empty stream frame");
-}
-
-TEST_P(QuicConnectionTest, DoNotSendGoAwayTwice) {
- EXPECT_FALSE(connection_.goaway_sent());
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- connection_.SendGoAway(QUIC_PEER_GOING_AWAY, kHeadersStreamId, "Going Away.");
- EXPECT_TRUE(connection_.goaway_sent());
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
- connection_.SendGoAway(QUIC_PEER_GOING_AWAY, kHeadersStreamId, "Going Away.");
-}
-
-TEST_P(QuicConnectionTest, ReevaluateTimeUntilSendOnAck) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
- connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0, !kFin,
- nullptr);
-
- // Evaluate CanWrite, and have it return a non-Zero value.
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillRepeatedly(Return(QuicTime::Delta::FromMilliseconds(1)));
- connection_.OnCanWrite();
- EXPECT_TRUE(connection_.GetSendAlarm()->IsSet());
- EXPECT_EQ(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(1)),
- connection_.GetSendAlarm()->deadline());
-
- // Process an ack and the send alarm will be set to the new 2ms delay.
- QuicAckFrame ack = InitAckFrame(1);
- EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _));
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillRepeatedly(Return(QuicTime::Delta::FromMilliseconds(2)));
- ProcessAckPacket(&ack);
- EXPECT_EQ(1u, writer_->frame_count());
- EXPECT_EQ(1u, writer_->stream_frames().size());
- EXPECT_TRUE(connection_.GetSendAlarm()->IsSet());
- EXPECT_EQ(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(2)),
- connection_.GetSendAlarm()->deadline());
- writer_->Reset();
-}
-
-TEST_P(QuicConnectionTest, SendAcksImmediately) {
- CongestionBlockWrites();
- SendAckPacketToPeer();
-}
-
-TEST_P(QuicConnectionTest, SendPingImmediately) {
- CongestionBlockWrites();
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
- connection_.SendPing();
- EXPECT_FALSE(connection_.HasQueuedData());
-}
-
-TEST_P(QuicConnectionTest, SendingUnencryptedStreamDataFails) {
- FLAGS_quic_never_write_unencrypted_data = true;
- EXPECT_CALL(visitor_,
- OnConnectionClosed(QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA,
- _, ConnectionCloseSource::FROM_SELF));
- EXPECT_DFATAL(connection_.SendStreamDataWithString(3, "", 0, kFin, nullptr),
- "Cannot send stream data without encryption.");
- EXPECT_FALSE(connection_.connected());
-}
-
-TEST_P(QuicConnectionTest, EnableMultipathNegotiation) {
- // Test multipath negotiation during crypto handshake. Multipath is enabled
- // when both endpoints enable multipath.
- ValueRestore<bool> old_flag(&FLAGS_quic_enable_multipath, true);
- EXPECT_TRUE(connection_.connected());
- EXPECT_FALSE(QuicConnectionPeer::IsMultipathEnabled(&connection_));
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- QuicConfig config;
- // Enable multipath on server side.
- config.SetMultipathEnabled(true);
-
- // Create a handshake message enables multipath.
- CryptoHandshakeMessage msg;
- string error_details;
- QuicConfig client_config;
- // Enable multipath on client side.
- client_config.SetMultipathEnabled(true);
- client_config.ToHandshakeMessage(&msg);
- const QuicErrorCode error =
- config.ProcessPeerHello(msg, CLIENT, &error_details);
- EXPECT_EQ(QUIC_NO_ERROR, error);
-
- connection_.SetFromConfig(config);
- EXPECT_TRUE(QuicConnectionPeer::IsMultipathEnabled(&connection_));
-}
-
-TEST_P(QuicConnectionTest, ClosePath) {
- QuicPathId kTestPathId = 1;
- connection_.SendPathClose(kTestPathId);
- EXPECT_TRUE(QuicFramerPeer::IsPathClosed(
- QuicConnectionPeer::GetFramer(&connection_), kTestPathId));
-}
-
-TEST_P(QuicConnectionTest, BadMultipathFlag) {
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_BAD_MULTIPATH_FLAG, _,
- ConnectionCloseSource::FROM_SELF));
-
- // Receieve a packet with multipath flag on when multipath is not enabled.
- EXPECT_TRUE(connection_.connected());
- EXPECT_FALSE(QuicConnectionPeer::IsMultipathEnabled(&connection_));
- peer_creator_.SetCurrentPath(/*path_id=*/1u, 1u, 10u);
- QuicStreamFrame stream_frame(1u, false, 0u, StringPiece());
- EXPECT_DFATAL(
- ProcessFramePacket(QuicFrame(&stream_frame)),
- "Received a packet with multipath flag but multipath is not enabled.");
- EXPECT_FALSE(connection_.connected());
-}
-
-TEST_P(QuicConnectionTest, OnPathDegrading) {
- QuicByteCount packet_size;
- const size_t kMinTimeoutsBeforePathDegrading = 2;
-
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillOnce(DoAll(SaveArg<3>(&packet_size), Return(true)));
- connection_.SendStreamDataWithString(3, "packet", 0, !kFin, nullptr);
- size_t num_timeouts =
- kMinTimeoutsBeforePathDegrading +
- QuicSentPacketManagerPeer::GetMaxTailLossProbes(
- QuicConnectionPeer::GetSentPacketManager(&connection_));
- for (size_t i = 1; i < num_timeouts; ++i) {
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(10 * i));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, packet_size, _));
- connection_.GetRetransmissionAlarm()->Fire();
- }
- // Next RTO should cause OnPathDegrading to be called before the
- // retransmission is sent out.
- clock_.AdvanceTime(
- QuicTime::Delta::FromSeconds(kMinTimeoutsBeforePathDegrading * 10));
- {
- InSequence s;
- EXPECT_CALL(visitor_, OnPathDegrading());
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, packet_size, _));
- }
- connection_.GetRetransmissionAlarm()->Fire();
-}
-
-TEST_P(QuicConnectionTest, MultipleCallsToCloseConnection) {
- // Verifies that multiple calls to CloseConnection do not
- // result in multiple attempts to close the connection - it will be marked as
- // disconnected after the first call.
- EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(1);
- connection_.CloseConnection(QUIC_NO_ERROR, "no reason",
- ConnectionCloseBehavior::SILENT_CLOSE);
- connection_.CloseConnection(QUIC_NO_ERROR, "no reason",
- ConnectionCloseBehavior::SILENT_CLOSE);
-}
-
-TEST_P(QuicConnectionTest, ServerReceivesChloOnNonCryptoStream) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- set_perspective(Perspective::IS_SERVER);
- QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
-
- CryptoHandshakeMessage message;
- CryptoFramer framer;
- message.set_tag(kCHLO);
- std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
- frame1_.stream_id = 10;
- frame1_.data_buffer = data->data();
- frame1_.data_length = data->length();
-
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_MAYBE_CORRUPTED_MEMORY, _,
- ConnectionCloseSource::FROM_SELF));
- ProcessFramePacket(QuicFrame(&frame1_));
-}
-
-TEST_P(QuicConnectionTest, ClientReceivesRejOnNonCryptoStream) {
- EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-
- CryptoHandshakeMessage message;
- CryptoFramer framer;
- message.set_tag(kREJ);
- std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
- frame1_.stream_id = 10;
- frame1_.data_buffer = data->data();
- frame1_.data_length = data->length();
-
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_MAYBE_CORRUPTED_MEMORY, _,
- ConnectionCloseSource::FROM_SELF));
- ProcessFramePacket(QuicFrame(&frame1_));
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_crypto_client_stream.cc b/chromium/net/quic/quic_crypto_client_stream.cc
deleted file mode 100644
index 68d0f0d7a37..00000000000
--- a/chromium/net/quic/quic_crypto_client_stream.cc
+++ /dev/null
@@ -1,705 +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/quic_crypto_client_stream.h"
-
-#include <memory>
-#include <vector>
-
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/sparse_histogram.h"
-#include "base/strings/stringprintf.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/crypto_utils.h"
-#include "net/quic/crypto/null_encrypter.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_session.h"
-#include "net/quic/quic_utils.h"
-
-using std::string;
-using std::vector;
-
-namespace net {
-
-namespace {
-
-void AppendFixed(CryptoHandshakeMessage* message) {
- vector<QuicTag> tags;
- tags.push_back(kFIXD);
-
- const QuicTag* received_tags;
- size_t received_tags_length;
- QuicErrorCode error =
- message->GetTaglist(kCOPT, &received_tags, &received_tags_length);
- if (error == QUIC_NO_ERROR) {
- for (size_t i = 0; i < received_tags_length; ++i) {
- tags.push_back(received_tags[i]);
- }
- }
- message->SetVector(kCOPT, tags);
-}
-
-} // namespace
-
-QuicCryptoClientStreamBase::QuicCryptoClientStreamBase(QuicSession* session)
- : QuicCryptoStream(session) {}
-
-QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
- ChannelIDSourceCallbackImpl(QuicCryptoClientStream* stream)
- : stream_(stream) {}
-
-QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
- ~ChannelIDSourceCallbackImpl() {}
-
-void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Run(
- std::unique_ptr<ChannelIDKey>* channel_id_key) {
- if (stream_ == nullptr) {
- return;
- }
-
- stream_->channel_id_key_.reset(channel_id_key->release());
- stream_->channel_id_source_callback_run_ = true;
- stream_->channel_id_source_callback_ = nullptr;
- stream_->DoHandshakeLoop(nullptr);
-
- // The ChannelIDSource owns this object and will delete it when this method
- // returns.
-}
-
-void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Cancel() {
- stream_ = nullptr;
-}
-
-QuicCryptoClientStream::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl(
- QuicCryptoClientStream* stream)
- : stream_(stream) {}
-
-QuicCryptoClientStream::ProofVerifierCallbackImpl::
- ~ProofVerifierCallbackImpl() {}
-
-void QuicCryptoClientStream::ProofVerifierCallbackImpl::Run(
- bool ok,
- const string& error_details,
- std::unique_ptr<ProofVerifyDetails>* details) {
- if (stream_ == nullptr) {
- return;
- }
-
- stream_->verify_ok_ = ok;
- stream_->verify_error_details_ = error_details;
- stream_->verify_details_.reset(details->release());
- stream_->proof_verify_callback_ = nullptr;
- stream_->DoHandshakeLoop(nullptr);
-
- // The ProofVerifier owns this object and will delete it when this method
- // returns.
-}
-
-void QuicCryptoClientStream::ProofVerifierCallbackImpl::Cancel() {
- stream_ = nullptr;
-}
-
-QuicCryptoClientStream::QuicCryptoClientStream(
- const QuicServerId& server_id,
- QuicSession* session,
- ProofVerifyContext* verify_context,
- QuicCryptoClientConfig* crypto_config,
- ProofHandler* proof_handler)
- : QuicCryptoClientStreamBase(session),
- next_state_(STATE_IDLE),
- num_client_hellos_(0),
- crypto_config_(crypto_config),
- server_id_(server_id),
- generation_counter_(0),
- channel_id_sent_(false),
- channel_id_source_callback_run_(false),
- channel_id_source_callback_(nullptr),
- verify_context_(verify_context),
- proof_verify_callback_(nullptr),
- proof_handler_(proof_handler),
- stateless_reject_received_(false),
- num_scup_messages_received_(0) {
- DCHECK_EQ(Perspective::IS_CLIENT, session->connection()->perspective());
-}
-
-QuicCryptoClientStream::~QuicCryptoClientStream() {
- if (channel_id_source_callback_) {
- channel_id_source_callback_->Cancel();
- }
- if (proof_verify_callback_) {
- proof_verify_callback_->Cancel();
- }
-}
-
-void QuicCryptoClientStream::OnHandshakeMessage(
- const CryptoHandshakeMessage& message) {
- QuicCryptoClientStreamBase::OnHandshakeMessage(message);
-
- if (message.tag() == kSCUP) {
- if (!handshake_confirmed()) {
- CloseConnectionWithDetails(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE,
- "Early SCUP disallowed");
- return;
- }
-
- // |message| is an update from the server, so we treat it differently from a
- // handshake message.
- HandleServerConfigUpdateMessage(message);
- num_scup_messages_received_++;
- return;
- }
-
- // Do not process handshake messages after the handshake is confirmed.
- if (handshake_confirmed()) {
- CloseConnectionWithDetails(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
- "Unexpected handshake message");
- return;
- }
-
- DoHandshakeLoop(&message);
-}
-
-void QuicCryptoClientStream::CryptoConnect() {
- next_state_ = STATE_INITIALIZE;
- DoHandshakeLoop(nullptr);
-}
-
-int QuicCryptoClientStream::num_sent_client_hellos() const {
- return num_client_hellos_;
-}
-
-int QuicCryptoClientStream::num_scup_messages_received() const {
- return num_scup_messages_received_;
-}
-
-// Used in Chromium, but not in the server.
-bool QuicCryptoClientStream::WasChannelIDSent() const {
- return channel_id_sent_;
-}
-
-bool QuicCryptoClientStream::WasChannelIDSourceCallbackRun() const {
- return channel_id_source_callback_run_;
-}
-
-void QuicCryptoClientStream::HandleServerConfigUpdateMessage(
- const CryptoHandshakeMessage& server_config_update) {
- DCHECK(server_config_update.tag() == kSCUP);
- string error_details;
- QuicCryptoClientConfig::CachedState* cached =
- crypto_config_->LookupOrCreate(server_id_);
- QuicErrorCode error = crypto_config_->ProcessServerConfigUpdate(
- server_config_update, session()->connection()->clock()->WallNow(),
- session()->connection()->version(), cached->chlo_hash(), cached,
- &crypto_negotiated_params_, &error_details);
-
- if (error != QUIC_NO_ERROR) {
- CloseConnectionWithDetails(
- error, "Server config update invalid: " + error_details);
- return;
- }
-
- DCHECK(handshake_confirmed());
- if (proof_verify_callback_) {
- proof_verify_callback_->Cancel();
- }
- next_state_ = STATE_INITIALIZE_SCUP;
- DoHandshakeLoop(nullptr);
-}
-
-void QuicCryptoClientStream::DoHandshakeLoop(const CryptoHandshakeMessage* in) {
- QuicCryptoClientConfig::CachedState* cached =
- crypto_config_->LookupOrCreate(server_id_);
-
- QuicAsyncStatus rv = QUIC_SUCCESS;
- do {
- CHECK_NE(STATE_NONE, next_state_);
- const State state = next_state_;
- next_state_ = STATE_IDLE;
- rv = QUIC_SUCCESS;
- switch (state) {
- case STATE_INITIALIZE:
- DoInitialize(cached);
- break;
- case STATE_SEND_CHLO:
- DoSendCHLO(cached);
- return; // return waiting to hear from server.
- case STATE_RECV_REJ:
- DoReceiveREJ(in, cached);
- break;
- case STATE_VERIFY_PROOF:
- rv = DoVerifyProof(cached);
- break;
- case STATE_VERIFY_PROOF_COMPLETE:
- DoVerifyProofComplete(cached);
- break;
- case STATE_GET_CHANNEL_ID:
- rv = DoGetChannelID(cached);
- break;
- case STATE_GET_CHANNEL_ID_COMPLETE:
- DoGetChannelIDComplete();
- break;
- case STATE_RECV_SHLO:
- DoReceiveSHLO(in, cached);
- break;
- case STATE_IDLE:
- // This means that the peer sent us a message that we weren't expecting.
- CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
- "Handshake in idle state");
- return;
- case STATE_INITIALIZE_SCUP:
- DoInitializeServerConfigUpdate(cached);
- break;
- case STATE_NONE:
- NOTREACHED();
- return; // We are done.
- }
- } while (rv != QUIC_PENDING && next_state_ != STATE_NONE);
-}
-
-void QuicCryptoClientStream::DoInitialize(
- QuicCryptoClientConfig::CachedState* cached) {
- if (!cached->IsEmpty() && !cached->signature().empty()) {
- // Note that we verify the proof even if the cached proof is valid.
- // This allows us to respond to CA trust changes or certificate
- // expiration because it may have been a while since we last verified
- // the proof.
- DCHECK(crypto_config_->proof_verifier());
- // Track proof verification time when cached server config is used.
- proof_verify_start_time_ = base::TimeTicks::Now();
- chlo_hash_ = cached->chlo_hash();
- // If the cached state needs to be verified, do it now.
- next_state_ = STATE_VERIFY_PROOF;
- } else {
- next_state_ = STATE_GET_CHANNEL_ID;
- }
-}
-
-void QuicCryptoClientStream::DoSendCHLO(
- QuicCryptoClientConfig::CachedState* cached) {
- if (stateless_reject_received_) {
- // If we've gotten to this point, we've sent at least one hello
- // and received a stateless reject in response. We cannot
- // continue to send hellos because the server has abandoned state
- // for this connection. Abandon further handshakes.
- next_state_ = STATE_NONE;
- if (session()->connection()->connected()) {
- session()->connection()->CloseConnection(
- QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject received",
- ConnectionCloseBehavior::SILENT_CLOSE);
- }
- return;
- }
-
- // Send the client hello in plaintext.
- session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
- encryption_established_ = false;
- if (num_client_hellos_ > kMaxClientHellos) {
- CloseConnectionWithDetails(
- QUIC_CRYPTO_TOO_MANY_REJECTS,
- base::StringPrintf("More than %u rejects", kMaxClientHellos).c_str());
- return;
- }
- num_client_hellos_++;
-
- CryptoHandshakeMessage out;
- DCHECK(session() != nullptr);
- DCHECK(session()->config() != nullptr);
- // Send all the options, regardless of whether we're sending an
- // inchoate or subsequent hello.
- session()->config()->ToHandshakeMessage(&out);
-
- // This call and function should be removed after removing QUIC_VERSION_25.
- AppendFixed(&out);
-
- // Send a local timestamp to the server.
- out.SetValue(kCTIM,
- session()->connection()->clock()->WallNow().ToUNIXSeconds());
-
- if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
- crypto_config_->FillInchoateClientHello(
- server_id_, session()->connection()->supported_versions().front(),
- cached, session()->connection()->random_generator(),
- &crypto_negotiated_params_, &out);
- // Pad the inchoate client hello to fill up a packet.
- const QuicByteCount kFramingOverhead = 50; // A rough estimate.
- const QuicByteCount max_packet_size =
- session()->connection()->max_packet_length();
- if (max_packet_size <= kFramingOverhead) {
- DLOG(DFATAL) << "max_packet_length (" << max_packet_size
- << ") has no room for framing overhead.";
- CloseConnectionWithDetails(QUIC_INTERNAL_ERROR,
- "max_packet_size too smalll");
- return;
- }
- if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
- DLOG(DFATAL) << "Client hello won't fit in a single packet.";
- CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, "CHLO too large");
- return;
- }
- out.set_minimum_size(
- static_cast<size_t>(max_packet_size - kFramingOverhead));
- next_state_ = STATE_RECV_REJ;
- CryptoUtils::HashHandshakeMessage(out, &chlo_hash_);
- SendHandshakeMessage(out);
- return;
- }
-
- // If the server nonce is empty, copy over the server nonce from a previous
- // SREJ, if there is one.
- if (FLAGS_enable_quic_stateless_reject_support &&
- crypto_negotiated_params_.server_nonce.empty() &&
- cached->has_server_nonce()) {
- crypto_negotiated_params_.server_nonce = cached->GetNextServerNonce();
- DCHECK(!crypto_negotiated_params_.server_nonce.empty());
- }
-
- string error_details;
- QuicErrorCode error = crypto_config_->FillClientHello(
- server_id_, session()->connection()->connection_id(),
- session()->connection()->version(),
- session()->connection()->supported_versions().front(), cached,
- session()->connection()->clock()->WallNow(),
- session()->connection()->random_generator(), channel_id_key_.get(),
- &crypto_negotiated_params_, &out, &error_details);
- if (error != QUIC_NO_ERROR) {
- // Flush the cached config so that, if it's bad, the server has a
- // chance to send us another in the future.
- cached->InvalidateServerConfig();
- CloseConnectionWithDetails(error, error_details);
- return;
- }
- CryptoUtils::HashHandshakeMessage(out, &chlo_hash_);
- channel_id_sent_ = (channel_id_key_.get() != nullptr);
- if (cached->proof_verify_details()) {
- proof_handler_->OnProofVerifyDetailsAvailable(
- *cached->proof_verify_details());
- }
- next_state_ = STATE_RECV_SHLO;
- SendHandshakeMessage(out);
- // Be prepared to decrypt with the new server write key.
- session()->connection()->SetAlternativeDecrypter(
- ENCRYPTION_INITIAL,
- crypto_negotiated_params_.initial_crypters.decrypter.release(),
- true /* latch once used */);
- // Send subsequent packets under encryption on the assumption that the
- // server will accept the handshake.
- session()->connection()->SetEncrypter(
- ENCRYPTION_INITIAL,
- crypto_negotiated_params_.initial_crypters.encrypter.release());
- session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
-
- if (FLAGS_quic_reply_to_rej) {
- // TODO(ianswett): Merge ENCRYPTION_REESTABLISHED and
- // ENCRYPTION_FIRST_ESTABLSIHED.
- encryption_established_ = true;
- session()->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_REESTABLISHED);
- } else {
- if (!encryption_established_) {
- encryption_established_ = true;
- session()->OnCryptoHandshakeEvent(
- QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
- } else {
- session()->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_REESTABLISHED);
- }
- }
-}
-
-void QuicCryptoClientStream::DoReceiveREJ(
- const CryptoHandshakeMessage* in,
- QuicCryptoClientConfig::CachedState* cached) {
- // We sent a dummy CHLO because we didn't have enough information to
- // perform a handshake, or we sent a full hello that the server
- // rejected. Here we hope to have a REJ that contains the information
- // that we need.
- if ((in->tag() != kREJ) && (in->tag() != kSREJ)) {
- next_state_ = STATE_NONE;
- CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
- "Expected REJ");
- return;
- }
-
- const uint32_t* reject_reasons;
- size_t num_reject_reasons;
- static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync");
- if (in->GetTaglist(kRREJ, &reject_reasons, &num_reject_reasons) ==
- QUIC_NO_ERROR) {
- uint32_t packed_error = 0;
- for (size_t i = 0; i < num_reject_reasons; ++i) {
- // HANDSHAKE_OK is 0 and don't report that as error.
- if (reject_reasons[i] == HANDSHAKE_OK || reject_reasons[i] >= 32) {
- continue;
- }
- HandshakeFailureReason reason =
- static_cast<HandshakeFailureReason>(reject_reasons[i]);
- packed_error |= 1 << (reason - 1);
- }
- DVLOG(1) << "Reasons for rejection: " << packed_error;
- if (num_client_hellos_ == kMaxClientHellos) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.TooMany",
- packed_error);
- }
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicClientHelloRejectReasons.Secure",
- packed_error);
- }
-
- stateless_reject_received_ = in->tag() == kSREJ;
- string error_details;
- QuicErrorCode error = crypto_config_->ProcessRejection(
- *in, session()->connection()->clock()->WallNow(),
- session()->connection()->version(), chlo_hash_, cached,
- &crypto_negotiated_params_, &error_details);
-
- if (error != QUIC_NO_ERROR) {
- next_state_ = STATE_NONE;
- CloseConnectionWithDetails(error, error_details);
- return;
- }
- if (!cached->proof_valid()) {
- if (!cached->signature().empty()) {
- // Note that we only verify the proof if the cached proof is not
- // valid. If the cached proof is valid here, someone else must have
- // just added the server config to the cache and verified the proof,
- // so we can assume no CA trust changes or certificate expiration
- // has happened since then.
- next_state_ = STATE_VERIFY_PROOF;
- return;
- }
- }
- next_state_ = STATE_GET_CHANNEL_ID;
-}
-
-QuicAsyncStatus QuicCryptoClientStream::DoVerifyProof(
- QuicCryptoClientConfig::CachedState* cached) {
- ProofVerifier* verifier = crypto_config_->proof_verifier();
- DCHECK(verifier);
- next_state_ = STATE_VERIFY_PROOF_COMPLETE;
- generation_counter_ = cached->generation_counter();
-
- ProofVerifierCallbackImpl* proof_verify_callback =
- new ProofVerifierCallbackImpl(this);
-
- verify_ok_ = false;
-
- QuicAsyncStatus status = verifier->VerifyProof(
- server_id_.host(), server_id_.port(), cached->server_config(),
- session()->connection()->version(), chlo_hash_, cached->certs(),
- cached->cert_sct(), cached->signature(), verify_context_.get(),
- &verify_error_details_, &verify_details_, proof_verify_callback);
-
- switch (status) {
- case QUIC_PENDING:
- proof_verify_callback_ = proof_verify_callback;
- DVLOG(1) << "Doing VerifyProof";
- break;
- case QUIC_FAILURE:
- delete proof_verify_callback;
- break;
- case QUIC_SUCCESS:
- delete proof_verify_callback;
- verify_ok_ = true;
- break;
- }
- return status;
-}
-
-void QuicCryptoClientStream::DoVerifyProofComplete(
- QuicCryptoClientConfig::CachedState* cached) {
- if (!proof_verify_start_time_.is_null()) {
- UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime.CachedServerConfig",
- base::TimeTicks::Now() - proof_verify_start_time_);
- }
- if (!verify_ok_) {
- if (verify_details_.get()) {
- proof_handler_->OnProofVerifyDetailsAvailable(*verify_details_);
- }
- if (num_client_hellos_ == 0) {
- cached->Clear();
- next_state_ = STATE_INITIALIZE;
- return;
- }
- next_state_ = STATE_NONE;
- UMA_HISTOGRAM_BOOLEAN("Net.QuicVerifyProofFailed.HandshakeConfirmed",
- handshake_confirmed());
- CloseConnectionWithDetails(QUIC_PROOF_INVALID,
- "Proof invalid: " + verify_error_details_);
- return;
- }
-
- // Check if generation_counter has changed between STATE_VERIFY_PROOF and
- // STATE_VERIFY_PROOF_COMPLETE state changes.
- if (generation_counter_ != cached->generation_counter()) {
- next_state_ = STATE_VERIFY_PROOF;
- } else {
- SetCachedProofValid(cached);
- cached->SetProofVerifyDetails(verify_details_.release());
- if (!handshake_confirmed()) {
- next_state_ = STATE_GET_CHANNEL_ID;
- } else {
- next_state_ = STATE_NONE;
- }
- }
-}
-
-QuicAsyncStatus QuicCryptoClientStream::DoGetChannelID(
- QuicCryptoClientConfig::CachedState* cached) {
- next_state_ = STATE_GET_CHANNEL_ID_COMPLETE;
- channel_id_key_.reset();
- if (!RequiresChannelID(cached)) {
- next_state_ = STATE_SEND_CHLO;
- return QUIC_SUCCESS;
- }
-
- ChannelIDSourceCallbackImpl* channel_id_source_callback =
- new ChannelIDSourceCallbackImpl(this);
- QuicAsyncStatus status = crypto_config_->channel_id_source()->GetChannelIDKey(
- server_id_.host(), &channel_id_key_, channel_id_source_callback);
-
- switch (status) {
- case QUIC_PENDING:
- channel_id_source_callback_ = channel_id_source_callback;
- DVLOG(1) << "Looking up channel ID";
- break;
- case QUIC_FAILURE:
- next_state_ = STATE_NONE;
- delete channel_id_source_callback;
- CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
- "Channel ID lookup failed");
- break;
- case QUIC_SUCCESS:
- delete channel_id_source_callback;
- break;
- }
- return status;
-}
-
-void QuicCryptoClientStream::DoGetChannelIDComplete() {
- if (!channel_id_key_.get()) {
- next_state_ = STATE_NONE;
- CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
- "Channel ID lookup failed");
- return;
- }
- next_state_ = STATE_SEND_CHLO;
-}
-
-void QuicCryptoClientStream::DoReceiveSHLO(
- const CryptoHandshakeMessage* in,
- QuicCryptoClientConfig::CachedState* cached) {
- next_state_ = STATE_NONE;
- // We sent a CHLO that we expected to be accepted and now we're
- // hoping for a SHLO from the server to confirm that. First check
- // to see whether the response was a reject, and if so, move on to
- // the reject-processing state.
- if ((in->tag() == kREJ) || (in->tag() == kSREJ)) {
- // alternative_decrypter will be nullptr if the original alternative
- // decrypter latched and became the primary decrypter. That happens
- // if we received a message encrypted with the INITIAL key.
- if (session()->connection()->alternative_decrypter() == nullptr) {
- // The rejection was sent encrypted!
- CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
- "encrypted REJ message");
- return;
- }
- next_state_ = STATE_RECV_REJ;
- return;
- }
-
- if (in->tag() != kSHLO) {
- CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
- "Expected SHLO or REJ");
- return;
- }
-
- // alternative_decrypter will be nullptr if the original alternative
- // decrypter latched and became the primary decrypter. That happens
- // if we received a message encrypted with the INITIAL key.
- if (session()->connection()->alternative_decrypter() != nullptr) {
- // The server hello was sent without encryption.
- CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
- "unencrypted SHLO message");
- return;
- }
-
- string error_details;
- QuicErrorCode error = crypto_config_->ProcessServerHello(
- *in, session()->connection()->connection_id(),
- session()->connection()->version(),
- session()->connection()->server_supported_versions(), cached,
- &crypto_negotiated_params_, &error_details);
-
- if (error != QUIC_NO_ERROR) {
- CloseConnectionWithDetails(error, "Server hello invalid: " + error_details);
- return;
- }
- error = session()->config()->ProcessPeerHello(*in, SERVER, &error_details);
- if (error != QUIC_NO_ERROR) {
- CloseConnectionWithDetails(error, "Server hello invalid: " + error_details);
- return;
- }
- session()->OnConfigNegotiated();
-
- CrypterPair* crypters = &crypto_negotiated_params_.forward_secure_crypters;
- // TODO(agl): we don't currently latch this decrypter because the idea
- // has been floated that the server shouldn't send packets encrypted
- // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
- // packet from the client.
- session()->connection()->SetAlternativeDecrypter(
- ENCRYPTION_FORWARD_SECURE, crypters->decrypter.release(),
- false /* don't latch */);
- session()->connection()->SetEncrypter(ENCRYPTION_FORWARD_SECURE,
- crypters->encrypter.release());
- session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
-
- handshake_confirmed_ = true;
- session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
- session()->connection()->OnHandshakeComplete();
-}
-
-void QuicCryptoClientStream::DoInitializeServerConfigUpdate(
- QuicCryptoClientConfig::CachedState* cached) {
- bool update_ignored = false;
- if (!cached->IsEmpty() && !cached->signature().empty()) {
- // Note that we verify the proof even if the cached proof is valid.
- DCHECK(crypto_config_->proof_verifier());
- next_state_ = STATE_VERIFY_PROOF;
- } else {
- update_ignored = true;
- next_state_ = STATE_NONE;
- }
- UMA_HISTOGRAM_COUNTS("Net.QuicNumServerConfig.UpdateMessagesIgnored",
- update_ignored);
-}
-
-void QuicCryptoClientStream::SetCachedProofValid(
- QuicCryptoClientConfig::CachedState* cached) {
- cached->SetProofValid();
- proof_handler_->OnProofValid(*cached);
-}
-
-bool QuicCryptoClientStream::RequiresChannelID(
- QuicCryptoClientConfig::CachedState* cached) {
- if (server_id_.privacy_mode() == PRIVACY_MODE_ENABLED ||
- !crypto_config_->channel_id_source()) {
- return false;
- }
- const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
- if (!scfg) { // scfg may be null then we send an inchoate CHLO.
- return false;
- }
- const QuicTag* their_proof_demands;
- size_t num_their_proof_demands;
- if (scfg->GetTaglist(kPDMD, &their_proof_demands, &num_their_proof_demands) !=
- QUIC_NO_ERROR) {
- return false;
- }
- for (size_t i = 0; i < num_their_proof_demands; i++) {
- if (their_proof_demands[i] == kCHID) {
- return true;
- }
- }
- return false;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_crypto_client_stream.h b/chromium/net/quic/quic_crypto_client_stream.h
deleted file mode 100644
index 75913d1edd1..00000000000
--- a/chromium/net/quic/quic_crypto_client_stream.h
+++ /dev/null
@@ -1,276 +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.
-
-#ifndef NET_QUIC_QUIC_CRYPTO_CLIENT_STREAM_H_
-#define NET_QUIC_QUIC_CRYPTO_CLIENT_STREAM_H_
-
-#include <cstdint>
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "net/quic/crypto/channel_id.h"
-#include "net/quic/crypto/proof_verifier.h"
-#include "net/quic/crypto/quic_crypto_client_config.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_crypto_stream.h"
-#include "net/quic/quic_server_id.h"
-
-namespace net {
-
-namespace test {
-class CryptoTestUtils;
-class QuicChromiumClientSessionPeer;
-} // namespace test
-
-class NET_EXPORT_PRIVATE QuicCryptoClientStreamBase : public QuicCryptoStream {
- public:
- explicit QuicCryptoClientStreamBase(QuicSession* session);
-
- ~QuicCryptoClientStreamBase() override{};
-
- // Performs a crypto handshake with the server.
- virtual void CryptoConnect() = 0;
-
- // num_sent_client_hellos returns the number of client hello messages that
- // have been sent. If the handshake has completed then this is one greater
- // than the number of round-trips needed for the handshake.
- virtual int num_sent_client_hellos() const = 0;
-
- // The number of server config update messages received by the
- // client. Does not count update messages that were received prior
- // to handshake confirmation.
- virtual int num_scup_messages_received() const = 0;
-};
-
-class NET_EXPORT_PRIVATE QuicCryptoClientStream
- : public QuicCryptoClientStreamBase {
- public:
- // kMaxClientHellos is the maximum number of times that we'll send a client
- // hello. The value 3 accounts for:
- // * One failure due to an incorrect or missing source-address token.
- // * One failure due the server's certificate chain being unavailible and
- // the server being unwilling to send it without a valid source-address
- // token.
- static const int kMaxClientHellos = 3;
-
- // ProofHandler is an interface that handles callbacks from the crypto
- // stream when the client has proof verification details of the server.
- class NET_EXPORT_PRIVATE ProofHandler {
- public:
- virtual ~ProofHandler() {}
-
- // Called when the proof in |cached| is marked valid. If this is a secure
- // QUIC session, then this will happen only after the proof verifier
- // completes.
- virtual void OnProofValid(
- const QuicCryptoClientConfig::CachedState& cached) = 0;
-
- // Called when proof verification details become available, either because
- // proof verification is complete, or when cached details are used. This
- // will only be called for secure QUIC connections.
- virtual void OnProofVerifyDetailsAvailable(
- const ProofVerifyDetails& verify_details) = 0;
- };
-
- QuicCryptoClientStream(const QuicServerId& server_id,
- QuicSession* session,
- ProofVerifyContext* verify_context,
- QuicCryptoClientConfig* crypto_config,
- ProofHandler* proof_handler);
-
- ~QuicCryptoClientStream() override;
-
- // From QuicCryptoClientStreamBase
- void CryptoConnect() override;
- int num_sent_client_hellos() const override;
-
- int num_scup_messages_received() const override;
-
- // CryptoFramerVisitorInterface implementation
- void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
-
- // Returns true if a channel ID was sent on this connection.
- bool WasChannelIDSent() const;
-
- // Returns true if our ChannelIDSourceCallback was run, which implies the
- // ChannelIDSource operated asynchronously. Intended for testing.
- bool WasChannelIDSourceCallbackRun() const;
-
- private:
- // ChannelIDSourceCallbackImpl is passed as the callback method to
- // GetChannelIDKey. The ChannelIDSource calls this class with the result of
- // channel ID lookup when lookup is performed asynchronously.
- class ChannelIDSourceCallbackImpl : public ChannelIDSourceCallback {
- public:
- explicit ChannelIDSourceCallbackImpl(QuicCryptoClientStream* stream);
- ~ChannelIDSourceCallbackImpl() override;
-
- // ChannelIDSourceCallback interface.
- void Run(std::unique_ptr<ChannelIDKey>* channel_id_key) override;
-
- // Cancel causes any future callbacks to be ignored. It must be called on
- // the same thread as the callback will be made on.
- void Cancel();
-
- private:
- QuicCryptoClientStream* stream_;
- };
-
- // ProofVerifierCallbackImpl is passed as the callback method to VerifyProof.
- // The ProofVerifier calls this class with the result of proof verification
- // when verification is performed asynchronously.
- class ProofVerifierCallbackImpl : public ProofVerifierCallback {
- public:
- explicit ProofVerifierCallbackImpl(QuicCryptoClientStream* stream);
- ~ProofVerifierCallbackImpl() override;
-
- // ProofVerifierCallback interface.
- void Run(bool ok,
- const std::string& error_details,
- std::unique_ptr<ProofVerifyDetails>* details) override;
-
- // Cancel causes any future callbacks to be ignored. It must be called on
- // the same thread as the callback will be made on.
- void Cancel();
-
- private:
- QuicCryptoClientStream* stream_;
- };
-
- friend class test::CryptoTestUtils;
- friend class test::QuicChromiumClientSessionPeer;
-
- enum State {
- STATE_IDLE,
- STATE_INITIALIZE,
- STATE_SEND_CHLO,
- STATE_RECV_REJ,
- STATE_VERIFY_PROOF,
- STATE_VERIFY_PROOF_COMPLETE,
- STATE_GET_CHANNEL_ID,
- STATE_GET_CHANNEL_ID_COMPLETE,
- STATE_RECV_SHLO,
- STATE_INITIALIZE_SCUP,
- STATE_NONE,
- };
-
- // Handles new server config and optional source-address token provided by the
- // server during a connection.
- void HandleServerConfigUpdateMessage(
- const CryptoHandshakeMessage& server_config_update);
-
- // DoHandshakeLoop performs a step of the handshake state machine. Note that
- // |in| may be nullptr if the call did not result from a received message.
- void DoHandshakeLoop(const CryptoHandshakeMessage* in);
-
- // Start the handshake process.
- void DoInitialize(QuicCryptoClientConfig::CachedState* cached);
-
- // Send either InchoateClientHello or ClientHello message to the server.
- void DoSendCHLO(QuicCryptoClientConfig::CachedState* cached);
-
- // Process REJ message from the server.
- void DoReceiveREJ(const CryptoHandshakeMessage* in,
- QuicCryptoClientConfig::CachedState* cached);
-
- // Start the proof verification process. Returns the QuicAsyncStatus returned
- // by the ProofVerifier's VerifyProof.
- QuicAsyncStatus DoVerifyProof(QuicCryptoClientConfig::CachedState* cached);
-
- // If proof is valid then it sets the proof as valid (which persists the
- // server config). If not, it closes the connection.
- void DoVerifyProofComplete(QuicCryptoClientConfig::CachedState* cached);
-
- // Start the look up of Channel ID process. Returns either QUIC_SUCCESS if
- // RequiresChannelID returns false or QuicAsyncStatus returned by
- // GetChannelIDKey.
- QuicAsyncStatus DoGetChannelID(QuicCryptoClientConfig::CachedState* cached);
-
- // If there is no channel ID, then close the connection otherwise transtion to
- // STATE_SEND_CHLO state.
- void DoGetChannelIDComplete();
-
- // Process SHLO message from the server.
- void DoReceiveSHLO(const CryptoHandshakeMessage* in,
- QuicCryptoClientConfig::CachedState* cached);
-
- // Start the proof verification if |server_id_| is https and |cached| has
- // signature.
- void DoInitializeServerConfigUpdate(
- QuicCryptoClientConfig::CachedState* cached);
-
- // Called to set the proof of |cached| valid. Also invokes the session's
- // OnProofValid() method.
- void SetCachedProofValid(QuicCryptoClientConfig::CachedState* cached);
-
- // Returns true if the server crypto config in |cached| requires a ChannelID
- // and the client config settings also allow sending a ChannelID.
- bool RequiresChannelID(QuicCryptoClientConfig::CachedState* cached);
-
- State next_state_;
- // num_client_hellos_ contains the number of client hello messages that this
- // connection has sent.
- int num_client_hellos_;
-
- QuicCryptoClientConfig* const crypto_config_;
-
- // SHA-256 hash of the most recently sent CHLO.
- std::string chlo_hash_;
-
- // Server's (hostname, port, is_https, privacy_mode) tuple.
- const QuicServerId server_id_;
-
- // Generation counter from QuicCryptoClientConfig's CachedState.
- uint64_t generation_counter_;
-
- // True if a channel ID was sent.
- bool channel_id_sent_;
-
- // True if channel_id_source_callback_ was run.
- bool channel_id_source_callback_run_;
-
- // channel_id_source_callback_ contains the callback object that we passed
- // to an asynchronous channel ID lookup. The ChannelIDSource owns this
- // object.
- ChannelIDSourceCallbackImpl* channel_id_source_callback_;
-
- // These members are used to store the result of an asynchronous channel ID
- // lookup. These members must not be used after
- // STATE_GET_CHANNEL_ID_COMPLETE.
- std::unique_ptr<ChannelIDKey> channel_id_key_;
-
- // verify_context_ contains the context object that we pass to asynchronous
- // proof verifications.
- std::unique_ptr<ProofVerifyContext> verify_context_;
-
- // proof_verify_callback_ contains the callback object that we passed to an
- // asynchronous proof verification. The ProofVerifier owns this object.
- ProofVerifierCallbackImpl* proof_verify_callback_;
- // proof_handler_ contains the callback object used by a quic client
- // for proof verification. It is not owned by this class.
- ProofHandler* proof_handler_;
-
- // These members are used to store the result of an asynchronous proof
- // verification. These members must not be used after
- // STATE_VERIFY_PROOF_COMPLETE.
- bool verify_ok_;
- std::string verify_error_details_;
- std::unique_ptr<ProofVerifyDetails> verify_details_;
-
- // True if the server responded to a previous CHLO with a stateless
- // reject. Used for book-keeping between the STATE_RECV_REJ,
- // STATE_VERIFY_PROOF*, and subsequent STATE_SEND_CHLO state.
- bool stateless_reject_received_;
-
- base::TimeTicks proof_verify_start_time_;
-
- int num_scup_messages_received_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientStream);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CRYPTO_CLIENT_STREAM_H_
diff --git a/chromium/net/quic/quic_crypto_client_stream_factory.cc b/chromium/net/quic/quic_crypto_client_stream_factory.cc
deleted file mode 100644
index 8c43218ed94..00000000000
--- a/chromium/net/quic/quic_crypto_client_stream_factory.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_crypto_client_stream_factory.h"
-
-#include "base/lazy_instance.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/quic_chromium_client_session.h"
-#include "net/quic/quic_crypto_client_stream.h"
-
-namespace net {
-
-namespace {
-
-class DefaultCryptoStreamFactory : public QuicCryptoClientStreamFactory {
- public:
- QuicCryptoClientStream* CreateQuicCryptoClientStream(
- const QuicServerId& server_id,
- QuicChromiumClientSession* session,
- std::unique_ptr<ProofVerifyContext> proof_verify_context,
- QuicCryptoClientConfig* crypto_config) override {
- return new QuicCryptoClientStream(server_id, session,
- proof_verify_context.release(),
- crypto_config, session);
- }
-};
-
-static base::LazyInstance<DefaultCryptoStreamFactory>::Leaky
- g_default_crypto_stream_factory = LAZY_INSTANCE_INITIALIZER;
-
-} // namespace
-
-// static
-QuicCryptoClientStreamFactory*
-QuicCryptoClientStreamFactory::GetDefaultFactory() {
- return g_default_crypto_stream_factory.Pointer();
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_crypto_client_stream_factory.h b/chromium/net/quic/quic_crypto_client_stream_factory.h
deleted file mode 100644
index c6cc93e7f6a..00000000000
--- a/chromium/net/quic/quic_crypto_client_stream_factory.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_CRYPTO_CLIENT_STREAM_FACTORY_H_
-#define NET_QUIC_QUIC_CRYPTO_CLIENT_STREAM_FACTORY_H_
-
-#include <memory>
-#include <string>
-
-#include "net/base/net_export.h"
-#include "net/quic/quic_server_id.h"
-
-namespace net {
-
-class ProofVerifyContext;
-class QuicChromiumClientSession;
-class QuicCryptoClientConfig;
-class QuicCryptoClientStream;
-
-// An interface used to instantiate QuicCryptoClientStream objects. Used to
-// facilitate testing code with mock implementations.
-class NET_EXPORT QuicCryptoClientStreamFactory {
- public:
- virtual ~QuicCryptoClientStreamFactory() {}
-
- virtual QuicCryptoClientStream* CreateQuicCryptoClientStream(
- const QuicServerId& server_id,
- QuicChromiumClientSession* session,
- std::unique_ptr<ProofVerifyContext> proof_verify_context,
- QuicCryptoClientConfig* crypto_config) = 0;
-
- static QuicCryptoClientStreamFactory* GetDefaultFactory();
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CRYPTO_CLIENT_STREAM_FACTORY_H_
diff --git a/chromium/net/quic/quic_crypto_client_stream_test.cc b/chromium/net/quic/quic_crypto_client_stream_test.cc
deleted file mode 100644
index 3c6b91b10f2..00000000000
--- a/chromium/net/quic/quic_crypto_client_stream_test.cc
+++ /dev/null
@@ -1,363 +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/quic_crypto_client_stream.h"
-
-#include <memory>
-
-#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_id.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/quic/test_tools/simple_quic_framer.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::string;
-using std::vector;
-
-using testing::_;
-
-namespace net {
-namespace test {
-namespace {
-
-const char kServerHostname[] = "test.example.com";
-const uint16_t kServerPort = 443;
-
-class QuicCryptoClientStreamTest : public ::testing::Test {
- public:
- QuicCryptoClientStreamTest()
- : server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED),
- crypto_config_(CryptoTestUtils::ProofVerifierForTesting()) {
- CreateConnection();
- }
-
- void CreateConnection() {
- connection_ = new PacketSavingConnection(&helper_, &alarm_factory_,
- Perspective::IS_CLIENT);
- // Advance the time, because timers do not like uninitialized times.
- connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
-
- session_.reset(new TestQuicSpdyClientSession(
- connection_, DefaultQuicConfig(), server_id_, &crypto_config_));
- }
-
- void CompleteCryptoHandshake() {
- stream()->CryptoConnect();
- QuicConfig config;
- CryptoTestUtils::HandshakeWithFakeServer(&config, &helper_, &alarm_factory_,
- connection_, stream(),
- server_options_);
- }
-
- void ConstructHandshakeMessage() {
- CryptoFramer framer;
- message_data_.reset(framer.ConstructHandshakeMessage(message_));
- }
-
- QuicCryptoClientStream* stream() { return session_->GetCryptoStream(); }
-
- MockQuicConnectionHelper helper_;
- MockAlarmFactory alarm_factory_;
- PacketSavingConnection* connection_;
- std::unique_ptr<TestQuicSpdyClientSession> session_;
- QuicServerId server_id_;
- CryptoHandshakeMessage message_;
- std::unique_ptr<QuicData> message_data_;
- QuicCryptoClientConfig crypto_config_;
- CryptoTestUtils::FakeServerOptions server_options_;
-};
-
-TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) {
- EXPECT_FALSE(stream()->encryption_established());
- EXPECT_FALSE(stream()->handshake_confirmed());
-}
-
-TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) {
- CompleteCryptoHandshake();
- EXPECT_TRUE(stream()->encryption_established());
- EXPECT_TRUE(stream()->handshake_confirmed());
-}
-
-TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
- CompleteCryptoHandshake();
-
- EXPECT_CALL(
- *connection_,
- CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE, _, _));
- message_.set_tag(kCHLO);
- ConstructHandshakeMessage();
- stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false,
- /*offset=*/0,
- message_data_->AsStringPiece()));
-}
-
-TEST_F(QuicCryptoClientStreamTest, BadMessageType) {
- stream()->CryptoConnect();
-
- message_.set_tag(kCHLO);
- ConstructHandshakeMessage();
-
- EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
- "Expected REJ", _));
- stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false,
- /*offset=*/0,
- message_data_->AsStringPiece()));
-}
-
-TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) {
- CompleteCryptoHandshake();
-
- const QuicConfig* config = session_->config();
- EXPECT_EQ(kMaximumIdleTimeoutSecs,
- config->IdleConnectionStateLifetime().ToSeconds());
- EXPECT_EQ(kDefaultMaxStreamsPerConnection, config->MaxStreamsPerConnection());
-
- const QuicCryptoNegotiatedParameters& crypto_params(
- stream()->crypto_negotiated_params());
- EXPECT_EQ(crypto_config_.aead[0], crypto_params.aead);
- EXPECT_EQ(crypto_config_.kexs[0], crypto_params.key_exchange);
-}
-
-TEST_F(QuicCryptoClientStreamTest, ExpiredServerConfig) {
- // Seed the config with a cached server config.
- CompleteCryptoHandshake();
-
- // Recreate connection with the new config.
- CreateConnection();
-
- // Advance time 5 years to ensure that we pass the expiry time of the cached
- // server config.
- connection_->AdvanceTime(
- QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
-
- stream()->CryptoConnect();
- // Check that a client hello was sent.
- ASSERT_EQ(1u, connection_->encrypted_packets_.size());
-}
-
-TEST_F(QuicCryptoClientStreamTest, InvalidCachedServerConfig) {
- // Seed the config with a cached server config.
- CompleteCryptoHandshake();
-
- // Recreate connection with the new config.
- CreateConnection();
-
- QuicCryptoClientConfig::CachedState* state =
- crypto_config_.LookupOrCreate(server_id_);
-
- vector<string> certs = state->certs();
- string cert_sct = state->cert_sct();
- string signature = state->signature();
- string chlo_hash = state->chlo_hash();
- state->SetProof(certs, cert_sct, chlo_hash, signature + signature);
-
- stream()->CryptoConnect();
- // Check that a client hello was sent.
- ASSERT_EQ(1u, connection_->encrypted_packets_.size());
-}
-
-TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdate) {
- // Test that the crypto client stream can receive server config updates after
- // the connection has been established.
- CompleteCryptoHandshake();
-
- QuicCryptoClientConfig::CachedState* state =
- crypto_config_.LookupOrCreate(server_id_);
-
- // Ensure cached STK is different to what we send in the handshake.
- EXPECT_NE("xstk", state->source_address_token());
-
- // Initialize using {...} syntax to avoid trailing \0 if converting from
- // string.
- unsigned char stk[] = {'x', 's', 't', 'k'};
-
- // Minimum SCFG that passes config validation checks.
- unsigned char scfg[] = {// SCFG
- 0x53, 0x43, 0x46, 0x47,
- // num entries
- 0x01, 0x00,
- // padding
- 0x00, 0x00,
- // EXPY
- 0x45, 0x58, 0x50, 0x59,
- // EXPY end offset
- 0x08, 0x00, 0x00, 0x00,
- // Value
- '1', '2', '3', '4', '5', '6', '7', '8'};
-
- CryptoHandshakeMessage server_config_update;
- server_config_update.set_tag(kSCUP);
- server_config_update.SetValue(kSourceAddressTokenTag, stk);
- server_config_update.SetValue(kSCFG, scfg);
-
- std::unique_ptr<QuicData> data(
- CryptoFramer::ConstructHandshakeMessage(server_config_update));
- stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false,
- /*offset=*/0, data->AsStringPiece()));
-
- // Make sure that the STK and SCFG are cached correctly.
- EXPECT_EQ("xstk", state->source_address_token());
-
- string cached_scfg = state->server_config();
- test::CompareCharArraysWithHexError(
- "scfg", cached_scfg.data(), cached_scfg.length(),
- QuicUtils::AsChars(scfg), arraysize(scfg));
-}
-
-TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateBeforeHandshake) {
- EXPECT_CALL(
- *connection_,
- CloseConnection(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE, _, _));
- CryptoHandshakeMessage server_config_update;
- server_config_update.set_tag(kSCUP);
- std::unique_ptr<QuicData> data(
- CryptoFramer::ConstructHandshakeMessage(server_config_update));
- stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false,
- /*offset=*/0, data->AsStringPiece()));
-}
-
-TEST_F(QuicCryptoClientStreamTest, TokenBindingNegotiation) {
- server_options_.token_binding_enabled = true;
- crypto_config_.tb_key_params.push_back(kP256);
-
- CompleteCryptoHandshake();
- EXPECT_TRUE(stream()->encryption_established());
- EXPECT_TRUE(stream()->handshake_confirmed());
- EXPECT_EQ(kP256,
- stream()->crypto_negotiated_params().token_binding_key_param);
-}
-
-TEST_F(QuicCryptoClientStreamTest, NoTokenBindingWithoutServerSupport) {
- crypto_config_.tb_key_params.push_back(kP256);
-
- CompleteCryptoHandshake();
- EXPECT_TRUE(stream()->encryption_established());
- EXPECT_TRUE(stream()->handshake_confirmed());
- EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
-}
-
-TEST_F(QuicCryptoClientStreamTest, NoTokenBindingWithoutClientSupport) {
- server_options_.token_binding_enabled = true;
-
- CompleteCryptoHandshake();
- EXPECT_TRUE(stream()->encryption_established());
- EXPECT_TRUE(stream()->handshake_confirmed());
- EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
-}
-
-TEST_F(QuicCryptoClientStreamTest, TokenBindingNotNegotiated) {
- CompleteCryptoHandshake();
- EXPECT_TRUE(stream()->encryption_established());
- EXPECT_TRUE(stream()->handshake_confirmed());
- EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
-}
-
-class QuicCryptoClientStreamStatelessTest : public ::testing::Test {
- public:
- QuicCryptoClientStreamStatelessTest()
- : client_crypto_config_(CryptoTestUtils::ProofVerifierForTesting()),
- server_crypto_config_(QuicCryptoServerConfig::TESTING,
- QuicRandom::GetInstance(),
- CryptoTestUtils::ProofSourceForTesting()),
- server_compressed_certs_cache_(
- QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
- server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED) {
- TestQuicSpdyClientSession* client_session = nullptr;
- CreateClientSessionForTest(server_id_,
- /* supports_stateless_rejects= */ true,
- QuicTime::Delta::FromSeconds(100000),
- QuicSupportedVersions(), &helper_,
- &alarm_factory_, &client_crypto_config_,
- &client_connection_, &client_session);
- CHECK(client_session);
- client_session_.reset(client_session);
- }
-
- QuicCryptoServerStream* server_stream() {
- return server_session_->GetCryptoStream();
- }
-
- void AdvanceHandshakeWithFakeServer() {
- client_session_->GetCryptoStream()->CryptoConnect();
- CryptoTestUtils::AdvanceHandshake(client_connection_,
- client_session_->GetCryptoStream(), 0,
- server_connection_, server_stream(), 0);
- }
-
- // Initializes the server_stream_ for stateless rejects.
- void InitializeFakeStatelessRejectServer() {
- TestQuicSpdyServerSession* server_session = nullptr;
- CreateServerSessionForTest(server_id_, QuicTime::Delta::FromSeconds(100000),
- QuicSupportedVersions(), &helper_,
- &alarm_factory_, &server_crypto_config_,
- &server_compressed_certs_cache_,
- &server_connection_, &server_session);
- CHECK(server_session);
- server_session_.reset(server_session);
- CryptoTestUtils::FakeServerOptions options;
- CryptoTestUtils::SetupCryptoServerConfigForTest(
- server_connection_->clock(), server_connection_->random_generator(),
- server_session_->config(), &server_crypto_config_, options);
- FLAGS_enable_quic_stateless_reject_support = true;
- }
-
- MockQuicConnectionHelper helper_;
- MockAlarmFactory alarm_factory_;
-
- // Client crypto stream state
- PacketSavingConnection* client_connection_;
- std::unique_ptr<TestQuicSpdyClientSession> client_session_;
- QuicCryptoClientConfig client_crypto_config_;
-
- // Server crypto stream state
- PacketSavingConnection* server_connection_;
- std::unique_ptr<TestQuicSpdyServerSession> server_session_;
- QuicCryptoServerConfig server_crypto_config_;
- QuicCompressedCertsCache server_compressed_certs_cache_;
- QuicServerId server_id_;
-};
-
-TEST_F(QuicCryptoClientStreamStatelessTest, StatelessReject) {
- ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support,
- true);
-
- QuicCryptoClientConfig::CachedState* client_state =
- client_crypto_config_.LookupOrCreate(server_id_);
-
- EXPECT_FALSE(client_state->has_server_designated_connection_id());
- EXPECT_CALL(*client_session_, OnProofValid(testing::_));
-
- InitializeFakeStatelessRejectServer();
- AdvanceHandshakeWithFakeServer();
-
- EXPECT_EQ(1, server_stream()->NumHandshakeMessages());
- EXPECT_EQ(0, server_stream()->NumHandshakeMessagesWithServerNonces());
-
- EXPECT_FALSE(client_session_->GetCryptoStream()->encryption_established());
- EXPECT_FALSE(client_session_->GetCryptoStream()->handshake_confirmed());
- // Even though the handshake was not complete, the cached client_state is
- // complete, and can be used for a subsequent successful handshake.
- EXPECT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
-
- ASSERT_TRUE(client_state->has_server_nonce());
- ASSERT_FALSE(client_state->GetNextServerNonce().empty());
- ASSERT_TRUE(client_state->has_server_designated_connection_id());
- QuicConnectionId server_designated_id =
- client_state->GetNextServerDesignatedConnectionId();
- QuicConnectionId expected_id =
- server_session_->connection()->random_generator()->RandUint64();
- EXPECT_EQ(expected_id, server_designated_id);
- EXPECT_FALSE(client_state->has_server_designated_connection_id());
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_crypto_framer_parse_message_fuzzer.cc b/chromium/net/quic/quic_crypto_framer_parse_message_fuzzer.cc
deleted file mode 100644
index 47dad64d6cf..00000000000
--- a/chromium/net/quic/quic_crypto_framer_parse_message_fuzzer.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 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.
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/strings/string_piece.h"
-#include "net/quic/crypto/crypto_framer.h"
-
-// Entry point for LibFuzzer.
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- base::StringPiece crypto_input(reinterpret_cast<const char*>(data), size);
- std::unique_ptr<net::CryptoHandshakeMessage> handshake_message(
- net::CryptoFramer::ParseMessage(crypto_input));
-
- return 0;
-}
diff --git a/chromium/net/quic/quic_crypto_server_stream.cc b/chromium/net/quic/quic_crypto_server_stream.cc
deleted file mode 100644
index 452cd37d25f..00000000000
--- a/chromium/net/quic/quic_crypto_server_stream.cc
+++ /dev/null
@@ -1,427 +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/quic_crypto_server_stream.h"
-
-#include <memory>
-
-#include "base/base64.h"
-#include "crypto/secure_hash.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/crypto_utils.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_session_base.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-
-namespace {
-bool HasFixedTag(const CryptoHandshakeMessage& message) {
- const QuicTag* received_tags;
- size_t received_tags_length;
- QuicErrorCode error =
- message.GetTaglist(kCOPT, &received_tags, &received_tags_length);
- if (error == QUIC_NO_ERROR) {
- DCHECK(received_tags);
- for (size_t i = 0; i < received_tags_length; ++i) {
- if (received_tags[i] == kFIXD) {
- return true;
- }
- }
- }
- return false;
-}
-} // namespace
-
-void ServerHelloNotifier::OnPacketAcked(int acked_bytes,
- QuicTime::Delta ack_delay_time) {
- DCHECK(!FLAGS_quic_no_shlo_listener);
- // The SHLO is sent in one packet.
- server_stream_->OnServerHelloAcked();
-}
-
-void ServerHelloNotifier::OnPacketRetransmitted(int /*retransmitted_bytes*/) {}
-
-QuicCryptoServerStreamBase::QuicCryptoServerStreamBase(
- QuicServerSessionBase* session)
- : QuicCryptoStream(session) {}
-
-// TODO(jokulik): Once stateless rejects support is inherent in the version
-// number, this function will likely go away entirely.
-// static
-bool QuicCryptoServerStreamBase::DoesPeerSupportStatelessRejects(
- const CryptoHandshakeMessage& message) {
- const QuicTag* received_tags;
- size_t received_tags_length;
- QuicErrorCode error =
- message.GetTaglist(kCOPT, &received_tags, &received_tags_length);
- if (error != QUIC_NO_ERROR) {
- return false;
- }
- for (size_t i = 0; i < received_tags_length; ++i) {
- if (received_tags[i] == kSREJ) {
- return true;
- }
- }
- return false;
-}
-
-QuicCryptoServerStream::QuicCryptoServerStream(
- const QuicCryptoServerConfig* crypto_config,
- QuicCompressedCertsCache* compressed_certs_cache,
- bool use_stateless_rejects_if_peer_supported,
- QuicServerSessionBase* session)
- : QuicCryptoServerStreamBase(session),
- crypto_config_(crypto_config),
- compressed_certs_cache_(compressed_certs_cache),
- validate_client_hello_cb_(nullptr),
- num_handshake_messages_(0),
- num_handshake_messages_with_server_nonces_(0),
- num_server_config_update_messages_sent_(0),
- use_stateless_rejects_if_peer_supported_(
- use_stateless_rejects_if_peer_supported),
- peer_supports_stateless_rejects_(false) {
- DCHECK_EQ(Perspective::IS_SERVER, session->connection()->perspective());
-}
-
-QuicCryptoServerStream::~QuicCryptoServerStream() {
- CancelOutstandingCallbacks();
-}
-
-void QuicCryptoServerStream::CancelOutstandingCallbacks() {
- // Detach from the validation callback. Calling this multiple times is safe.
- if (validate_client_hello_cb_ != nullptr) {
- validate_client_hello_cb_->Cancel();
- validate_client_hello_cb_ = nullptr;
- }
-}
-
-void QuicCryptoServerStream::OnHandshakeMessage(
- const CryptoHandshakeMessage& message) {
- QuicCryptoServerStreamBase::OnHandshakeMessage(message);
- ++num_handshake_messages_;
-
- // This block should be removed with support for QUIC_VERSION_25.
- if (FLAGS_quic_require_fix && !HasFixedTag(message)) {
- CloseConnectionWithDetails(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
- "Missing kFIXD");
- return;
- }
-
- // Do not process handshake messages after the handshake is confirmed.
- if (handshake_confirmed_) {
- CloseConnectionWithDetails(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
- "Unexpected handshake message from client");
- return;
- }
-
- if (message.tag() != kCHLO) {
- CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
- "Handshake packet not CHLO");
- return;
- }
-
- if (validate_client_hello_cb_ != nullptr) {
- // Already processing some other handshake message. The protocol
- // does not allow for clients to send multiple handshake messages
- // before the server has a chance to respond.
- CloseConnectionWithDetails(
- QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO,
- "Unexpected handshake message while processing CHLO");
- return;
- }
-
- CryptoUtils::HashHandshakeMessage(message, &chlo_hash_);
-
- validate_client_hello_cb_ = new ValidateCallback(this);
- crypto_config_->ValidateClientHello(
- message, session()->connection()->peer_address().address(),
- session()->connection()->self_address().address(), version(),
- session()->connection()->clock(), &crypto_proof_,
- validate_client_hello_cb_);
-}
-
-void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
- const CryptoHandshakeMessage& message,
- const ValidateClientHelloResultCallback::Result& result) {
- // Clear the callback that got us here.
- DCHECK(validate_client_hello_cb_ != nullptr);
- validate_client_hello_cb_ = nullptr;
-
- if (use_stateless_rejects_if_peer_supported_) {
- peer_supports_stateless_rejects_ = DoesPeerSupportStatelessRejects(message);
- }
-
- CryptoHandshakeMessage reply;
- DiversificationNonce diversification_nonce;
- string error_details;
- QuicErrorCode error = ProcessClientHello(
- message, result, &reply, &diversification_nonce, &error_details);
-
- if (error != QUIC_NO_ERROR) {
- CloseConnectionWithDetails(error, error_details);
- return;
- }
-
- if (reply.tag() != kSHLO) {
- if (reply.tag() == kSREJ) {
- DCHECK(use_stateless_rejects_if_peer_supported_);
- DCHECK(peer_supports_stateless_rejects_);
- // Before sending the SREJ, cause the connection to save crypto packets
- // so that they can be added to the time wait list manager and
- // retransmitted.
- session()->connection()->EnableSavingCryptoPackets();
- }
- SendHandshakeMessage(reply);
-
- if (reply.tag() == kSREJ) {
- DCHECK(use_stateless_rejects_if_peer_supported_);
- DCHECK(peer_supports_stateless_rejects_);
- DCHECK(!handshake_confirmed());
- DVLOG(1) << "Closing connection "
- << session()->connection()->connection_id()
- << " because of a stateless reject.";
- session()->connection()->CloseConnection(
- QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject",
- ConnectionCloseBehavior::SILENT_CLOSE);
- }
- return;
- }
-
- // If we are returning a SHLO then we accepted the handshake. Now
- // process the negotiated configuration options as part of the
- // session config.
- QuicConfig* config = session()->config();
- OverrideQuicConfigDefaults(config);
- error = config->ProcessPeerHello(message, CLIENT, &error_details);
- if (error != QUIC_NO_ERROR) {
- CloseConnectionWithDetails(error, error_details);
- return;
- }
-
- session()->OnConfigNegotiated();
-
- config->ToHandshakeMessage(&reply);
-
- // Receiving a full CHLO implies the client is prepared to decrypt with
- // the new server write key. We can start to encrypt with the new server
- // write key.
- //
- // NOTE: the SHLO will be encrypted with the new server write key.
- session()->connection()->SetEncrypter(
- ENCRYPTION_INITIAL,
- crypto_negotiated_params_.initial_crypters.encrypter.release());
- session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
- // Set the decrypter immediately so that we no longer accept unencrypted
- // packets.
- session()->connection()->SetDecrypter(
- ENCRYPTION_INITIAL,
- crypto_negotiated_params_.initial_crypters.decrypter.release());
- if (version() > QUIC_VERSION_32) {
- session()->connection()->SetDiversificationNonce(diversification_nonce);
- }
-
- // We want to be notified when the SHLO is ACKed so that we can disable
- // HANDSHAKE_MODE in the sent packet manager.
- scoped_refptr<ServerHelloNotifier> server_hello_notifier(
- new ServerHelloNotifier(this));
- SendHandshakeMessage(reply, FLAGS_quic_no_shlo_listener
- ? nullptr
- : server_hello_notifier.get());
-
- session()->connection()->SetEncrypter(
- ENCRYPTION_FORWARD_SECURE,
- crypto_negotiated_params_.forward_secure_crypters.encrypter.release());
- if (FLAGS_quic_default_immediate_forward_secure !=
- config->HasClientSentConnectionOption(kIPFS, Perspective::IS_SERVER)) {
- session()->connection()->SetDefaultEncryptionLevel(
- ENCRYPTION_FORWARD_SECURE);
- }
-
- session()->connection()->SetAlternativeDecrypter(
- ENCRYPTION_FORWARD_SECURE,
- crypto_negotiated_params_.forward_secure_crypters.decrypter.release(),
- false /* don't latch */);
-
- encryption_established_ = true;
- handshake_confirmed_ = true;
- session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
-}
-
-void QuicCryptoServerStream::SendServerConfigUpdate(
- const CachedNetworkParameters* cached_network_params) {
- if (!handshake_confirmed_) {
- return;
- }
-
- CryptoHandshakeMessage server_config_update_message;
- if (!crypto_config_->BuildServerConfigUpdateMessage(
- session()->connection()->version(), chlo_hash_,
- previous_source_address_tokens_,
- session()->connection()->self_address().address(),
- session()->connection()->peer_address().address(),
- session()->connection()->clock(),
- session()->connection()->random_generator(), compressed_certs_cache_,
- crypto_negotiated_params_, cached_network_params,
- &server_config_update_message)) {
- DVLOG(1) << "Server: Failed to build server config update (SCUP)!";
- return;
- }
-
- DVLOG(1) << "Server: Sending server config update: "
- << server_config_update_message.DebugString();
- const QuicData& data = server_config_update_message.GetSerialized();
- WriteOrBufferData(StringPiece(data.data(), data.length()), false, nullptr);
-
- ++num_server_config_update_messages_sent_;
-}
-
-void QuicCryptoServerStream::OnServerHelloAcked() {
- session()->connection()->OnHandshakeComplete();
-}
-
-uint8_t QuicCryptoServerStream::NumHandshakeMessages() const {
- return num_handshake_messages_;
-}
-
-uint8_t QuicCryptoServerStream::NumHandshakeMessagesWithServerNonces() const {
- return num_handshake_messages_with_server_nonces_;
-}
-
-int QuicCryptoServerStream::NumServerConfigUpdateMessagesSent() const {
- return num_server_config_update_messages_sent_;
-}
-
-const CachedNetworkParameters*
-QuicCryptoServerStream::PreviousCachedNetworkParams() const {
- return previous_cached_network_params_.get();
-}
-
-bool QuicCryptoServerStream::UseStatelessRejectsIfPeerSupported() const {
- return use_stateless_rejects_if_peer_supported_;
-}
-
-bool QuicCryptoServerStream::PeerSupportsStatelessRejects() const {
- return peer_supports_stateless_rejects_;
-}
-
-void QuicCryptoServerStream::SetPeerSupportsStatelessRejects(
- bool peer_supports_stateless_rejects) {
- peer_supports_stateless_rejects_ = peer_supports_stateless_rejects;
-}
-
-void QuicCryptoServerStream::SetPreviousCachedNetworkParams(
- CachedNetworkParameters cached_network_params) {
- previous_cached_network_params_.reset(
- new CachedNetworkParameters(cached_network_params));
-}
-
-bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID(
- string* output) const {
- if (!encryption_established_ ||
- crypto_negotiated_params_.channel_id.empty()) {
- return false;
- }
-
- const string& channel_id(crypto_negotiated_params_.channel_id);
- std::unique_ptr<crypto::SecureHash> hash(
- crypto::SecureHash::Create(crypto::SecureHash::SHA256));
- hash->Update(channel_id.data(), channel_id.size());
- uint8_t digest[32];
- hash->Finish(digest, sizeof(digest));
-
- base::Base64Encode(
- string(reinterpret_cast<const char*>(digest), sizeof(digest)), output);
- // Remove padding.
- size_t len = output->size();
- if (len >= 2) {
- if ((*output)[len - 1] == '=') {
- len--;
- if ((*output)[len - 1] == '=') {
- len--;
- }
- output->resize(len);
- }
- }
- return true;
-}
-
-QuicErrorCode QuicCryptoServerStream::ProcessClientHello(
- const CryptoHandshakeMessage& message,
- const ValidateClientHelloResultCallback::Result& result,
- CryptoHandshakeMessage* reply,
- DiversificationNonce* out_diversification_nonce,
- string* error_details) {
- QuicServerSessionBase* session_base =
- static_cast<QuicServerSessionBase*>(session());
- if (FLAGS_quic_enable_chlo_policy &&
- !session_base->CanAcceptClientHello(message, error_details)) {
- return QUIC_HANDSHAKE_FAILED;
- }
-
- if (!result.info.server_nonce.empty()) {
- ++num_handshake_messages_with_server_nonces_;
- }
- // Store the bandwidth estimate from the client.
- if (result.cached_network_params.bandwidth_estimate_bytes_per_second() > 0) {
- previous_cached_network_params_.reset(
- new CachedNetworkParameters(result.cached_network_params));
- }
- previous_source_address_tokens_ = result.info.source_address_tokens;
-
- const bool use_stateless_rejects_in_crypto_config =
- use_stateless_rejects_if_peer_supported_ &&
- peer_supports_stateless_rejects_;
- QuicConnection* connection = session()->connection();
- const QuicConnectionId server_designated_connection_id =
- use_stateless_rejects_in_crypto_config
- ? GenerateConnectionIdForReject(connection->connection_id())
- : 0;
- return crypto_config_->ProcessClientHello(
- result, /*reject_only=*/false, connection->connection_id(),
- connection->self_address().address(), connection->peer_address(),
- 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_, &crypto_proof_,
- reply, out_diversification_nonce, error_details);
-}
-
-void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {}
-
-QuicCryptoServerStream::ValidateCallback::ValidateCallback(
- QuicCryptoServerStream* parent)
- : parent_(parent) {}
-
-void QuicCryptoServerStream::ValidateCallback::Cancel() {
- parent_ = nullptr;
-}
-
-void QuicCryptoServerStream::ValidateCallback::RunImpl(
- const CryptoHandshakeMessage& client_hello,
- const Result& result) {
- if (parent_ != nullptr) {
- parent_->FinishProcessingHandshakeMessage(client_hello, result);
- }
-}
-
-QuicConnectionId QuicCryptoServerStream::GenerateConnectionIdForReject(
- QuicConnectionId connection_id) {
- // TODO(rch): Remove this method when this flag is removed.
- if (FLAGS_quic_dispatcher_creates_id) {
- QuicServerSessionBase* session_base =
- static_cast<QuicServerSessionBase*>(session());
- return session_base->GenerateConnectionIdForReject(connection_id);
- }
- return session()->connection()->random_generator()->RandUint64();
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_crypto_server_stream.h b/chromium/net/quic/quic_crypto_server_stream.h
deleted file mode 100644
index f3900847f48..00000000000
--- a/chromium/net/quic/quic_crypto_server_stream.h
+++ /dev/null
@@ -1,223 +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.
-
-#ifndef NET_QUIC_QUIC_CRYPTO_SERVER_STREAM_H_
-#define NET_QUIC_QUIC_CRYPTO_SERVER_STREAM_H_
-
-#include <cstdint>
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/quic_compressed_certs_cache.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/proto/source_address_token.pb.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_crypto_stream.h"
-
-namespace net {
-
-class CachedNetworkParameters;
-class CryptoHandshakeMessage;
-class QuicCryptoServerConfig;
-class QuicCryptoServerStreamBase;
-class QuicServerSessionBase;
-
-namespace test {
-class CryptoTestUtils;
-class QuicCryptoServerStreamPeer;
-} // namespace test
-
-// Receives a notification when the server hello (SHLO) has been ACKed by the
-// peer. At this point we disable HANDSHAKE_MODE in the sent packet manager.
-class NET_EXPORT_PRIVATE ServerHelloNotifier : public QuicAckListenerInterface {
- public:
- explicit ServerHelloNotifier(QuicCryptoServerStreamBase* stream)
- : server_stream_(stream) {}
-
- void OnPacketAcked(int acked_bytes, QuicTime::Delta ack_delay_time) override;
-
- void OnPacketRetransmitted(int retransmitted_bytes) override;
-
- private:
- ~ServerHelloNotifier() override {}
-
- QuicCryptoServerStreamBase* server_stream_;
-
- DISALLOW_COPY_AND_ASSIGN(ServerHelloNotifier);
-};
-
-// TODO(alyssar) see what can be moved out of QuicCryptoServerStream with
-// various code and test refactoring.
-class NET_EXPORT_PRIVATE QuicCryptoServerStreamBase : public QuicCryptoStream {
- public:
- explicit QuicCryptoServerStreamBase(QuicServerSessionBase* session);
- ~QuicCryptoServerStreamBase() override {}
-
- // Cancel any outstanding callbacks, such as asynchronous validation of client
- // hello.
- virtual void CancelOutstandingCallbacks() = 0;
-
- // GetBase64SHA256ClientChannelID sets |*output| to the base64 encoded,
- // SHA-256 hash of the client's ChannelID key and returns true, if the client
- // presented a ChannelID. Otherwise it returns false.
- virtual bool GetBase64SHA256ClientChannelID(std::string* output) const = 0;
-
- virtual int NumServerConfigUpdateMessagesSent() const = 0;
-
- // Sends the latest server config and source-address token to the client.
- virtual void SendServerConfigUpdate(
- const CachedNetworkParameters* cached_network_params) = 0;
-
- // Called by the ServerHello AckNotifier once the SHLO has been ACKed by the
- // client.
- virtual void OnServerHelloAcked() = 0;
-
- // These are all accessors and setters to their respective counters.
- virtual uint8_t NumHandshakeMessages() const = 0;
- virtual uint8_t NumHandshakeMessagesWithServerNonces() const = 0;
- virtual bool UseStatelessRejectsIfPeerSupported() const = 0;
- virtual bool PeerSupportsStatelessRejects() const = 0;
- virtual void SetPeerSupportsStatelessRejects(bool set) = 0;
- virtual const CachedNetworkParameters* PreviousCachedNetworkParams()
- const = 0;
- virtual void SetPreviousCachedNetworkParams(
- CachedNetworkParameters cached_network_params) = 0;
-
- // Checks the options on the handshake-message to see whether the
- // peer supports stateless-rejects.
- static bool DoesPeerSupportStatelessRejects(
- const CryptoHandshakeMessage& message);
-};
-
-class NET_EXPORT_PRIVATE QuicCryptoServerStream
- : public QuicCryptoServerStreamBase {
- public:
- // |crypto_config| must outlive the stream.
- QuicCryptoServerStream(const QuicCryptoServerConfig* crypto_config,
- QuicCompressedCertsCache* compressed_certs_cache,
- bool use_stateless_rejects_if_peer_supported,
- QuicServerSessionBase* session);
- ~QuicCryptoServerStream() override;
-
- // From QuicCryptoServerStreamBase
- void CancelOutstandingCallbacks() override;
- void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
- bool GetBase64SHA256ClientChannelID(std::string* output) const override;
- void SendServerConfigUpdate(
- const CachedNetworkParameters* cached_network_params) override;
- void OnServerHelloAcked() override;
- uint8_t NumHandshakeMessages() const override;
- uint8_t NumHandshakeMessagesWithServerNonces() const override;
- int NumServerConfigUpdateMessagesSent() const override;
- const CachedNetworkParameters* PreviousCachedNetworkParams() const override;
- bool UseStatelessRejectsIfPeerSupported() const override;
- bool PeerSupportsStatelessRejects() const override;
- void SetPeerSupportsStatelessRejects(
- bool peer_supports_stateless_rejects) override;
- void SetPreviousCachedNetworkParams(
- CachedNetworkParameters cached_network_params) override;
-
- protected:
- virtual QuicErrorCode ProcessClientHello(
- const CryptoHandshakeMessage& message,
- const ValidateClientHelloResultCallback::Result& result,
- CryptoHandshakeMessage* reply,
- DiversificationNonce* out_diversification_nonce,
- std::string* error_details);
-
- // Hook that allows the server to set QuicConfig defaults just
- // before going through the parameter negotiation step.
- virtual void OverrideQuicConfigDefaults(QuicConfig* config);
-
- // Given the current connection_id, generates a new ConnectionId to
- // be returned with a stateless reject.
- virtual QuicConnectionId GenerateConnectionIdForReject(
- QuicConnectionId connection_id);
-
- private:
- friend class test::CryptoTestUtils;
- friend class test::QuicCryptoServerStreamPeer;
-
- class ValidateCallback : public ValidateClientHelloResultCallback {
- public:
- explicit ValidateCallback(QuicCryptoServerStream* parent);
- // To allow the parent to detach itself from the callback before deletion.
- void Cancel();
-
- // From ValidateClientHelloResultCallback
- void RunImpl(const CryptoHandshakeMessage& client_hello,
- const Result& result) override;
-
- private:
- QuicCryptoServerStream* parent_;
-
- DISALLOW_COPY_AND_ASSIGN(ValidateCallback);
- };
-
- // Invoked by ValidateCallback::RunImpl once initial validation of
- // the client hello is complete. Finishes processing of the client
- // hello message and handles handshake success/failure.
- void FinishProcessingHandshakeMessage(
- const CryptoHandshakeMessage& message,
- const ValidateClientHelloResultCallback::Result& result);
-
- // crypto_config_ contains crypto parameters for the handshake.
- const QuicCryptoServerConfig* crypto_config_;
-
- // compressed_certs_cache_ contains a set of most recently compressed certs.
- // Owned by QuicDispatcher.
- QuicCompressedCertsCache* compressed_certs_cache_;
-
- // Server's certificate chain and signature of the server config, as provided
- // by ProofSource::GetProof.
- QuicCryptoProof crypto_proof_;
-
- // Hash of the last received CHLO message which can be used for generating
- // server config update messages.
- std::string chlo_hash_;
-
- // Pointer to the active callback that will receive the result of
- // the client hello validation request and forward it to
- // FinishProcessingHandshakeMessage for processing. nullptr if no
- // handshake message is being validated.
- ValidateCallback* validate_client_hello_cb_;
-
- // Number of handshake messages received by this stream.
- uint8_t num_handshake_messages_;
-
- // Number of handshake messages received by this stream that contain
- // server nonces (indicating that this is a non-zero-RTT handshake
- // attempt).
- uint8_t num_handshake_messages_with_server_nonces_;
-
- // Number of server config update (SCUP) messages sent by this stream.
- int num_server_config_update_messages_sent_;
-
- // If the client provides CachedNetworkParameters in the STK in the CHLO, then
- // store here, and send back in future STKs if we have no better bandwidth
- // estimate to send.
- std::unique_ptr<CachedNetworkParameters> previous_cached_network_params_;
-
- // Contains any source address tokens which were present in the CHLO.
- SourceAddressTokens previous_source_address_tokens_;
-
- // If true, the server should use stateless rejects, so long as the
- // client supports them, as indicated by
- // peer_supports_stateless_rejects_.
- bool use_stateless_rejects_if_peer_supported_;
-
- // Set to true, once the server has received information from the
- // client that it supports stateless reject.
- // TODO(jokulik): Remove once client stateless reject support
- // becomes the default.
- bool peer_supports_stateless_rejects_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicCryptoServerStream);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CRYPTO_SERVER_STREAM_H_
diff --git a/chromium/net/quic/quic_crypto_server_stream_test.cc b/chromium/net/quic/quic_crypto_server_stream_test.cc
deleted file mode 100644
index 1cf2d5cd381..00000000000
--- a/chromium/net/quic/quic_crypto_server_stream_test.cc
+++ /dev/null
@@ -1,610 +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/quic_crypto_server_stream.h"
-
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "base/stl_util.h"
-#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
-#include "net/quic/crypto/crypto_framer.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/crypto_utils.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_crypto_client_stream.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_session.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/delayed_verify_strike_register_client.h"
-#include "net/quic/test_tools/quic_crypto_server_config_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-class QuicConnection;
-class ReliableQuicStream;
-} // namespace net
-
-using std::pair;
-using std::string;
-using testing::_;
-
-namespace net {
-namespace test {
-
-class QuicCryptoServerStreamPeer {
- public:
- static bool DoesPeerSupportStatelessRejects(
- const CryptoHandshakeMessage& message) {
- return net::QuicCryptoServerStream::DoesPeerSupportStatelessRejects(
- message);
- }
-};
-
-namespace {
-
-const char kServerHostname[] = "test.example.com";
-const uint16_t kServerPort = 443;
-
-class QuicCryptoServerStreamTest : public ::testing::TestWithParam<bool> {
- public:
- QuicCryptoServerStreamTest()
- : server_crypto_config_(QuicCryptoServerConfig::TESTING,
- QuicRandom::GetInstance(),
- CryptoTestUtils::ProofSourceForTesting()),
- server_compressed_certs_cache_(
- QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
- server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED),
- client_crypto_config_(CryptoTestUtils::ProofVerifierForTesting()) {
- FLAGS_enable_quic_stateless_reject_support = false;
- server_crypto_config_.set_strike_register_no_startup_period();
- }
-
- void Initialize() {
- InitializeServer();
-
- if (AsyncStrikeRegisterVerification()) {
- QuicCryptoServerConfigPeer peer(&server_crypto_config_);
- strike_register_client_ = new DelayedVerifyStrikeRegisterClient(
- 10000, // strike_register_max_entries
- static_cast<uint32_t>(
- server_connection_->clock()->WallNow().ToUNIXSeconds()),
- 60, // strike_register_window_secs
- peer.GetPrimaryConfig()->orbit,
- StrikeRegister::NO_STARTUP_PERIOD_NEEDED);
- strike_register_client_->StartDelayingVerification();
- server_crypto_config_.SetStrikeRegisterClient(strike_register_client_);
- }
- }
-
- ~QuicCryptoServerStreamTest() override {
- // Ensure that anything that might reference |helpers_| is destroyed before
- // |helpers_| is destroyed.
- server_session_.reset();
- client_session_.reset();
- STLDeleteElements(&helpers_);
- STLDeleteElements(&alarm_factories_);
- }
-
- // Initializes the crypto server stream state for testing. May be
- // called multiple times.
- void InitializeServer() {
- TestQuicSpdyServerSession* server_session = nullptr;
- helpers_.push_back(new MockQuicConnectionHelper);
- alarm_factories_.push_back(new MockAlarmFactory);
- CreateServerSessionForTest(
- server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_,
- helpers_.back(), alarm_factories_.back(), &server_crypto_config_,
- &server_compressed_certs_cache_, &server_connection_, &server_session);
- CHECK(server_session);
- server_session_.reset(server_session);
- CryptoTestUtils::FakeServerOptions options;
- options.token_binding_enabled = true;
- CryptoTestUtils::SetupCryptoServerConfigForTest(
- server_connection_->clock(), server_connection_->random_generator(),
- server_session_->config(), &server_crypto_config_, options);
- }
-
- QuicCryptoServerStream* server_stream() {
- return server_session_->GetCryptoStream();
- }
-
- QuicCryptoClientStream* client_stream() {
- return client_session_->GetCryptoStream();
- }
-
- // Initializes a fake client, and all its associated state, for
- // testing. May be called multiple times.
- void InitializeFakeClient(bool supports_stateless_rejects) {
- TestQuicSpdyClientSession* client_session = nullptr;
- helpers_.push_back(new MockQuicConnectionHelper);
- alarm_factories_.push_back(new MockAlarmFactory);
- CreateClientSessionForTest(
- server_id_, supports_stateless_rejects,
- QuicTime::Delta::FromSeconds(100000), supported_versions_,
-
- helpers_.back(), alarm_factories_.back(), &client_crypto_config_,
- &client_connection_, &client_session);
- CHECK(client_session);
- client_session_.reset(client_session);
- }
-
- bool AsyncStrikeRegisterVerification() {
- if (server_connection_->version() > QUIC_VERSION_32) {
- return false;
- }
- return GetParam();
- }
-
- void ConstructHandshakeMessage() {
- CryptoFramer framer;
- message_data_.reset(framer.ConstructHandshakeMessage(message_));
- }
-
- int CompleteCryptoHandshake() {
- CHECK(server_connection_);
- CHECK(server_session_ != nullptr);
- return CryptoTestUtils::HandshakeWithFakeClient(
- helpers_.back(), alarm_factories_.back(), server_connection_,
- server_stream(), server_id_, client_options_);
- }
-
- // Performs a single round of handshake message-exchange between the
- // client and server.
- void AdvanceHandshakeWithFakeClient() {
- CHECK(server_connection_);
- CHECK(client_session_ != nullptr);
-
- EXPECT_CALL(*client_session_, OnProofValid(_)).Times(testing::AnyNumber());
- client_stream()->CryptoConnect();
- CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream(), 0,
- server_connection_, server_stream(), 0);
- }
-
- protected:
- // Every connection gets its own MockQuicConnectionHelper and
- // MockAlarmFactory,
- // tracked separately from
- // the server and client state so their lifetimes persist through the whole
- // test.
- std::vector<MockQuicConnectionHelper*> helpers_;
- std::vector<MockAlarmFactory*> alarm_factories_;
-
- // Server state
- PacketSavingConnection* server_connection_;
- std::unique_ptr<TestQuicSpdyServerSession> server_session_;
- QuicCryptoServerConfig server_crypto_config_;
- QuicCompressedCertsCache server_compressed_certs_cache_;
- QuicServerId server_id_;
-
- // Client state
- PacketSavingConnection* client_connection_;
- QuicCryptoClientConfig client_crypto_config_;
- std::unique_ptr<TestQuicSpdyClientSession> client_session_;
-
- CryptoHandshakeMessage message_;
- std::unique_ptr<QuicData> message_data_;
- CryptoTestUtils::FakeClientOptions client_options_;
- DelayedVerifyStrikeRegisterClient* strike_register_client_;
-
- // Which QUIC versions the client and server support.
- QuicVersionVector supported_versions_ = QuicSupportedVersions();
-};
-
-INSTANTIATE_TEST_CASE_P(Tests, QuicCryptoServerStreamTest, testing::Bool());
-
-TEST_P(QuicCryptoServerStreamTest, NotInitiallyConected) {
- Initialize();
- EXPECT_FALSE(server_stream()->encryption_established());
- EXPECT_FALSE(server_stream()->handshake_confirmed());
-}
-
-TEST_P(QuicCryptoServerStreamTest, NotInitiallySendingStatelessRejects) {
- Initialize();
- EXPECT_FALSE(server_stream()->UseStatelessRejectsIfPeerSupported());
- EXPECT_FALSE(server_stream()->PeerSupportsStatelessRejects());
-}
-
-TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) {
- // CompleteCryptoHandshake returns the number of client hellos sent. This
- // test should send:
- // * One to get a source-address token and certificates.
- // * One to complete the handshake.
- Initialize();
- EXPECT_EQ(2, CompleteCryptoHandshake());
- EXPECT_TRUE(server_stream()->encryption_established());
- EXPECT_TRUE(server_stream()->handshake_confirmed());
-}
-
-TEST_P(QuicCryptoServerStreamTest, InitialEncryptionAfterCHLO) {
- Initialize();
- InitializeFakeClient(/* supports_stateless_rejects= */ false);
-
- // Do a first handshake in order to prime the client config with the server's
- // information.
- AdvanceHandshakeWithFakeClient();
- EXPECT_FALSE(server_stream()->encryption_established());
- EXPECT_FALSE(server_stream()->handshake_confirmed());
-
- // Now do another handshake, with the blocking SHLO connection option.
- InitializeServer();
- InitializeFakeClient(/* supports_stateless_rejects= */ false);
- if (FLAGS_quic_default_immediate_forward_secure) {
- client_session_->config()->SetConnectionOptionsToSend({kIPFS});
- }
-
- AdvanceHandshakeWithFakeClient();
- EXPECT_TRUE(server_stream()->encryption_established());
- EXPECT_TRUE(server_stream()->handshake_confirmed());
- EXPECT_EQ(ENCRYPTION_INITIAL,
- server_session_->connection()->encryption_level());
-}
-
-TEST_P(QuicCryptoServerStreamTest, ForwardSecureAfterCHLO) {
- Initialize();
- InitializeFakeClient(/* supports_stateless_rejects= */ false);
-
- // Do a first handshake in order to prime the client config with the server's
- // information.
- AdvanceHandshakeWithFakeClient();
- EXPECT_FALSE(server_stream()->encryption_established());
- EXPECT_FALSE(server_stream()->handshake_confirmed());
-
- // Now do another handshake, with the blocking SHLO connection option.
- InitializeServer();
- InitializeFakeClient(/* supports_stateless_rejects= */ false);
- if (!FLAGS_quic_default_immediate_forward_secure) {
- client_session_->config()->SetConnectionOptionsToSend({kIPFS});
- }
-
- AdvanceHandshakeWithFakeClient();
- EXPECT_TRUE(server_stream()->encryption_established());
- EXPECT_TRUE(server_stream()->handshake_confirmed());
- EXPECT_EQ(ENCRYPTION_FORWARD_SECURE,
- server_session_->connection()->encryption_level());
-}
-
-TEST_P(QuicCryptoServerStreamTest, StatelessRejectAfterCHLO) {
- ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support,
- true);
- Initialize();
-
- EXPECT_CALL(*server_connection_,
- CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _));
-
- InitializeFakeClient(/* supports_stateless_rejects= */ true);
- AdvanceHandshakeWithFakeClient();
-
- // Check the server to make the sure the handshake did not succeed.
- EXPECT_FALSE(server_stream()->encryption_established());
- EXPECT_FALSE(server_stream()->handshake_confirmed());
-
- // Check the client state to make sure that it received a server-designated
- // connection id.
- QuicCryptoClientConfig::CachedState* client_state =
- client_crypto_config_.LookupOrCreate(server_id_);
-
- ASSERT_TRUE(client_state->has_server_nonce());
- ASSERT_FALSE(client_state->GetNextServerNonce().empty());
- ASSERT_FALSE(client_state->has_server_nonce());
-
- ASSERT_TRUE(client_state->has_server_designated_connection_id());
- const QuicConnectionId server_designated_connection_id =
- client_state->GetNextServerDesignatedConnectionId();
- const QuicConnectionId expected_id =
- server_connection_->random_generator()->RandUint64();
- EXPECT_EQ(expected_id, server_designated_connection_id);
- EXPECT_FALSE(client_state->has_server_designated_connection_id());
- ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
-}
-
-TEST_P(QuicCryptoServerStreamTest, ConnectedAfterStatelessHandshake) {
- ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support,
- true);
- Initialize();
-
- InitializeFakeClient(/* supports_stateless_rejects= */ true);
- AdvanceHandshakeWithFakeClient();
-
- // On the first round, encryption will not be established.
- EXPECT_FALSE(server_stream()->encryption_established());
- EXPECT_FALSE(server_stream()->handshake_confirmed());
- EXPECT_EQ(1, server_stream()->NumHandshakeMessages());
- EXPECT_EQ(0, server_stream()->NumHandshakeMessagesWithServerNonces());
-
- // Now check the client state.
- QuicCryptoClientConfig::CachedState* client_state =
- client_crypto_config_.LookupOrCreate(server_id_);
-
- ASSERT_TRUE(client_state->has_server_designated_connection_id());
- const QuicConnectionId server_designated_connection_id =
- client_state->GetNextServerDesignatedConnectionId();
- const QuicConnectionId expected_id =
- server_connection_->random_generator()->RandUint64();
- EXPECT_EQ(expected_id, server_designated_connection_id);
- EXPECT_FALSE(client_state->has_server_designated_connection_id());
- ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
-
- // Now create new client and server streams with the existing config
- // and try the handshake again (0-RTT handshake).
- InitializeServer();
-
- InitializeFakeClient(/* supports_stateless_rejects= */ true);
-
- // In the stateless case, the second handshake contains a server-nonce, so the
- // AsyncStrikeRegisterVerification() case will still succeed (unlike a 0-RTT
- // handshake).
- AdvanceHandshakeWithFakeClient();
-
- // On the second round, encryption will be established.
- EXPECT_TRUE(server_stream()->encryption_established());
- EXPECT_TRUE(server_stream()->handshake_confirmed());
- EXPECT_EQ(1, server_stream()->NumHandshakeMessages());
- EXPECT_EQ(1, server_stream()->NumHandshakeMessagesWithServerNonces());
-}
-
-TEST_P(QuicCryptoServerStreamTest, NoStatelessRejectIfNoClientSupport) {
- ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support,
- true);
- Initialize();
-
- // The server is configured to use stateless rejects, but the client does not
- // support it.
- InitializeFakeClient(/* supports_stateless_rejects= */ false);
- AdvanceHandshakeWithFakeClient();
-
- // Check the server to make the sure the handshake did not succeed.
- EXPECT_FALSE(server_stream()->encryption_established());
- EXPECT_FALSE(server_stream()->handshake_confirmed());
-
- // Check the client state to make sure that it did not receive a
- // server-designated connection id.
- QuicCryptoClientConfig::CachedState* client_state =
- client_crypto_config_.LookupOrCreate(server_id_);
-
- ASSERT_FALSE(client_state->has_server_designated_connection_id());
- ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
-}
-
-TEST_P(QuicCryptoServerStreamTest, ZeroRTT) {
- Initialize();
- InitializeFakeClient(/* supports_stateless_rejects= */ false);
-
- // Do a first handshake in order to prime the client config with the server's
- // information.
- AdvanceHandshakeWithFakeClient();
-
- // Now do another handshake, hopefully in 0-RTT.
- DVLOG(1) << "Resetting for 0-RTT handshake attempt";
- InitializeFakeClient(/* supports_stateless_rejects= */ false);
- InitializeServer();
-
- client_stream()->CryptoConnect();
-
- if (AsyncStrikeRegisterVerification()) {
- EXPECT_FALSE(client_stream()->handshake_confirmed());
- EXPECT_FALSE(server_stream()->handshake_confirmed());
-
- // Advance the handshake. Expect that the server will be stuck waiting for
- // client nonce verification to complete.
- pair<size_t, size_t> messages_moved = CryptoTestUtils::AdvanceHandshake(
- client_connection_, client_stream(), 0, server_connection_,
- server_stream(), 0);
- EXPECT_EQ(1u, messages_moved.first);
- EXPECT_EQ(0u, messages_moved.second);
- EXPECT_EQ(1, strike_register_client_->PendingVerifications());
- EXPECT_FALSE(client_stream()->handshake_confirmed());
- EXPECT_FALSE(server_stream()->handshake_confirmed());
-
- // The server handshake completes once the nonce verification completes.
- strike_register_client_->RunPendingVerifications();
- EXPECT_FALSE(client_stream()->handshake_confirmed());
- EXPECT_TRUE(server_stream()->handshake_confirmed());
-
- messages_moved = CryptoTestUtils::AdvanceHandshake(
- client_connection_, client_stream(), messages_moved.first,
- server_connection_, server_stream(), messages_moved.second);
- EXPECT_EQ(1u, messages_moved.first);
- EXPECT_EQ(1u, messages_moved.second);
- EXPECT_TRUE(client_stream()->handshake_confirmed());
- EXPECT_TRUE(server_stream()->handshake_confirmed());
- } else {
- CryptoTestUtils::CommunicateHandshakeMessages(
- client_connection_, client_stream(), server_connection_,
- server_stream());
- }
-
- EXPECT_EQ(1, client_stream()->num_sent_client_hellos());
-}
-
-TEST_P(QuicCryptoServerStreamTest, FailByPolicy) {
- FLAGS_quic_enable_chlo_policy = true;
- FLAGS_quic_require_fix = false;
- Initialize();
- InitializeFakeClient(/* supports_stateless_rejects= */ false);
-
- EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _))
- .WillOnce(testing::Return(false));
- EXPECT_CALL(*server_connection_,
- CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
-
- AdvanceHandshakeWithFakeClient();
-}
-
-TEST_P(QuicCryptoServerStreamTest, MessageAfterHandshake) {
- FLAGS_quic_require_fix = false;
- Initialize();
- CompleteCryptoHandshake();
- EXPECT_CALL(
- *server_connection_,
- CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE, _, _));
- message_.set_tag(kCHLO);
- ConstructHandshakeMessage();
- server_stream()->OnStreamFrame(
- QuicStreamFrame(kCryptoStreamId, /*fin=*/false, /*offset=*/0,
- message_data_->AsStringPiece()));
-}
-
-TEST_P(QuicCryptoServerStreamTest, BadMessageType) {
- FLAGS_quic_require_fix = false;
- Initialize();
-
- message_.set_tag(kSHLO);
- ConstructHandshakeMessage();
- EXPECT_CALL(*server_connection_,
- CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, _, _));
- server_stream()->OnStreamFrame(
- QuicStreamFrame(kCryptoStreamId, /*fin=*/false, /*offset=*/0,
- message_data_->AsStringPiece()));
-}
-
-TEST_P(QuicCryptoServerStreamTest, ChannelID) {
- Initialize();
-
- client_options_.channel_id_enabled = true;
- client_options_.channel_id_source_async = false;
- // CompleteCryptoHandshake verifies
- // server_stream()->crypto_negotiated_params().channel_id is correct.
- EXPECT_EQ(2, CompleteCryptoHandshake());
- EXPECT_TRUE(server_stream()->encryption_established());
- EXPECT_TRUE(server_stream()->handshake_confirmed());
-}
-
-TEST_P(QuicCryptoServerStreamTest, ChannelIDAsync) {
- Initialize();
-
- client_options_.channel_id_enabled = true;
- client_options_.channel_id_source_async = true;
- // CompleteCryptoHandshake verifies
- // server_stream()->crypto_negotiated_params().channel_id is correct.
- EXPECT_EQ(2, CompleteCryptoHandshake());
- EXPECT_TRUE(server_stream()->encryption_established());
- EXPECT_TRUE(server_stream()->handshake_confirmed());
-}
-
-TEST_P(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) {
- // An attempt to send a SCUP before completing handshake should fail.
- Initialize();
-
- server_stream()->SendServerConfigUpdate(nullptr);
- EXPECT_EQ(0, server_stream()->NumServerConfigUpdateMessagesSent());
-}
-
-TEST_P(QuicCryptoServerStreamTest, SendSCUPAfterHandshakeComplete) {
- FLAGS_quic_use_hash_in_scup = true;
- Initialize();
-
- InitializeFakeClient(/* supports_stateless_rejects= */ false);
-
- // Do a first handshake in order to prime the client config with the server's
- // information.
- AdvanceHandshakeWithFakeClient();
-
- // Now do another handshake, with the blocking SHLO connection option.
- InitializeServer();
- InitializeFakeClient(/* supports_stateless_rejects= */ false);
- AdvanceHandshakeWithFakeClient();
-
- // Send a SCUP message and ensure that the client was able to verify it.
- EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0);
- server_stream()->SendServerConfigUpdate(nullptr);
- CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream(), 1,
- server_connection_, server_stream(), 1);
-
- EXPECT_EQ(1, server_stream()->NumServerConfigUpdateMessagesSent());
- EXPECT_EQ(1, client_stream()->num_scup_messages_received());
-}
-
-TEST_P(QuicCryptoServerStreamTest, DoesPeerSupportStatelessRejects) {
- Initialize();
-
- ConstructHandshakeMessage();
- QuicConfig stateless_reject_config = DefaultQuicConfigStatelessRejects();
- stateless_reject_config.ToHandshakeMessage(&message_);
- EXPECT_TRUE(
- QuicCryptoServerStreamPeer::DoesPeerSupportStatelessRejects(message_));
-
- message_.Clear();
- QuicConfig stateful_reject_config = DefaultQuicConfig();
- stateful_reject_config.ToHandshakeMessage(&message_);
- EXPECT_FALSE(
- QuicCryptoServerStreamPeer::DoesPeerSupportStatelessRejects(message_));
-}
-
-TEST_P(QuicCryptoServerStreamTest, TokenBindingNegotiated) {
- Initialize();
-
- client_options_.token_binding_enabled = true;
- CompleteCryptoHandshake();
- EXPECT_EQ(
- kP256,
- server_stream()->crypto_negotiated_params().token_binding_key_param);
- EXPECT_TRUE(server_stream()->encryption_established());
- EXPECT_TRUE(server_stream()->handshake_confirmed());
-}
-
-TEST_P(QuicCryptoServerStreamTest, NoTokenBindingWithoutClientSupport) {
- Initialize();
-
- CompleteCryptoHandshake();
- EXPECT_EQ(
- 0u, server_stream()->crypto_negotiated_params().token_binding_key_param);
- EXPECT_TRUE(server_stream()->encryption_established());
- EXPECT_TRUE(server_stream()->handshake_confirmed());
-}
-
-TEST_P(QuicCryptoServerStreamTest, CancelRPCBeforeVerificationCompletes) {
- // Tests that the client can close the connection while the remote strike
- // register verification RPC is still pending.
-
- // Set version to QUIC_VERSION_25 as QUIC_VERSION_26 and later don't support
- // asynchronous strike register RPCs.
- supported_versions_ = {QUIC_VERSION_25};
- Initialize();
- if (!AsyncStrikeRegisterVerification()) {
- return;
- }
- InitializeFakeClient(/* supports_stateless_rejects= */ false);
-
- // Do a first handshake in order to prime the client config with the server's
- // information.
- AdvanceHandshakeWithFakeClient();
-
- // Now start another handshake, this time the server will attempt to verify
- // the client's nonce with the strike registers.
- InitializeFakeClient(/* supports_stateless_rejects= */ false);
- InitializeServer();
- client_stream()->CryptoConnect();
- EXPECT_FALSE(client_stream()->handshake_confirmed());
- EXPECT_FALSE(server_stream()->handshake_confirmed());
-
- // Advance the handshake. Expect that the server will be stuck waiting for
- // client nonce verification to complete.
- CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream(), 0,
- server_connection_, server_stream(), 0);
- EXPECT_EQ(1, strike_register_client_->PendingVerifications());
- EXPECT_FALSE(client_stream()->handshake_confirmed());
- EXPECT_FALSE(server_stream()->handshake_confirmed());
-
- // While waiting for the asynchronous verification to complete, the client
- // decides to close the connection.
- server_session_->connection()->CloseConnection(
- QUIC_NO_ERROR, "", ConnectionCloseBehavior::SILENT_CLOSE);
-
- // The outstanding nonce verification RPC now completes.
- strike_register_client_->RunPendingVerifications();
-}
-
-} // namespace
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_crypto_stream.cc b/chromium/net/quic/quic_crypto_stream.cc
deleted file mode 100644
index f9048716737..00000000000
--- a/chromium/net/quic/quic_crypto_stream.cc
+++ /dev/null
@@ -1,108 +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/quic_crypto_stream.h"
-
-#include <string>
-
-#include "base/strings/string_piece.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/crypto_utils.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_session.h"
-#include "net/quic/quic_utils.h"
-
-using std::string;
-using base::StringPiece;
-using net::SpdyPriority;
-
-namespace net {
-
-#define ENDPOINT \
- (session()->perspective() == Perspective::IS_SERVER ? "Server: " : "Client:" \
- " ")
-
-QuicCryptoStream::QuicCryptoStream(QuicSession* session)
- : ReliableQuicStream(kCryptoStreamId, session),
- encryption_established_(false),
- handshake_confirmed_(false) {
- crypto_framer_.set_visitor(this);
- // The crypto stream is exempt from connection level flow control.
- DisableConnectionFlowControlForThisStream();
-}
-
-void QuicCryptoStream::OnError(CryptoFramer* framer) {
- DLOG(WARNING) << "Error processing crypto data: "
- << QuicUtils::ErrorToString(framer->error());
-}
-
-void QuicCryptoStream::OnHandshakeMessage(
- const CryptoHandshakeMessage& message) {
- DVLOG(1) << ENDPOINT << "Received " << message.DebugString();
- session()->OnCryptoHandshakeMessageReceived(message);
-}
-
-void QuicCryptoStream::OnDataAvailable() {
- struct iovec iov;
- while (true) {
- if (sequencer()->GetReadableRegions(&iov, 1) != 1) {
- // No more data to read.
- break;
- }
- StringPiece data(static_cast<char*>(iov.iov_base), iov.iov_len);
- if (!crypto_framer_.ProcessInput(data)) {
- CloseConnectionWithDetails(crypto_framer_.error(),
- crypto_framer_.error_detail());
- return;
- }
- sequencer()->MarkConsumed(iov.iov_len);
- }
-}
-
-void QuicCryptoStream::SendHandshakeMessage(
- const CryptoHandshakeMessage& message) {
- SendHandshakeMessage(message, nullptr);
-}
-
-void QuicCryptoStream::SendHandshakeMessage(
- const CryptoHandshakeMessage& message,
- QuicAckListenerInterface* listener) {
- DVLOG(1) << ENDPOINT << "Sending " << message.DebugString();
- session()->OnCryptoHandshakeMessageSent(message);
- const QuicData& data = message.GetSerialized();
- // TODO(wtc): check the return value.
- WriteOrBufferData(StringPiece(data.data(), data.length()), false, listener);
-}
-
-bool QuicCryptoStream::ExportKeyingMaterial(StringPiece label,
- StringPiece context,
- size_t result_len,
- string* result) const {
- if (!handshake_confirmed()) {
- DLOG(ERROR) << "ExportKeyingMaterial was called before forward-secure"
- << "encryption was established.";
- return false;
- }
- return CryptoUtils::ExportKeyingMaterial(
- crypto_negotiated_params_.subkey_secret, label, context, result_len,
- result);
-}
-
-bool QuicCryptoStream::ExportTokenBindingKeyingMaterial(string* result) const {
- if (!encryption_established()) {
- QUIC_BUG << "ExportTokenBindingKeyingMaterial was called before initial"
- << "encryption was established.";
- return false;
- }
- return CryptoUtils::ExportKeyingMaterial(
- crypto_negotiated_params_.initial_subkey_secret, "EXPORTER-Token-Binding",
- /* context= */ "", 32, result);
-}
-
-const QuicCryptoNegotiatedParameters&
-QuicCryptoStream::crypto_negotiated_params() const {
- return crypto_negotiated_params_;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_crypto_stream.h b/chromium/net/quic/quic_crypto_stream.h
deleted file mode 100644
index a5bf812ab5e..00000000000
--- a/chromium/net/quic/quic_crypto_stream.h
+++ /dev/null
@@ -1,91 +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.
-
-#ifndef NET_QUIC_QUIC_CRYPTO_STREAM_H_
-#define NET_QUIC_QUIC_CRYPTO_STREAM_H_
-
-#include <stddef.h>
-
-#include "base/macros.h"
-#include "net/quic/crypto/crypto_framer.h"
-#include "net/quic/crypto/crypto_utils.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/reliable_quic_stream.h"
-
-namespace net {
-
-class CryptoHandshakeMessage;
-class QuicSession;
-
-// Crypto handshake messages in QUIC take place over a reserved
-// reliable stream with the id 1. Each endpoint (client and server)
-// will allocate an instance of a subclass of QuicCryptoStream
-// to send and receive handshake messages. (In the normal 1-RTT
-// handshake, the client will send a client hello, CHLO, message.
-// The server will receive this message and respond with a server
-// hello message, SHLO. At this point both sides will have established
-// a crypto context they can use to send encrypted messages.
-//
-// For more details: http://goto.google.com/quic-crypto
-class NET_EXPORT_PRIVATE QuicCryptoStream
- : public ReliableQuicStream,
- public CryptoFramerVisitorInterface {
- public:
- explicit QuicCryptoStream(QuicSession* session);
-
- // CryptoFramerVisitorInterface implementation
- void OnError(CryptoFramer* framer) override;
- void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
-
- // ReliableQuicStream implementation
- void OnDataAvailable() override;
-
- // Sends |message| to the peer.
- // TODO(wtc): return a success/failure status.
- void SendHandshakeMessage(const CryptoHandshakeMessage& message);
- // As above, but registers |delegate| for notification when |message| has been
- // ACKed by the peer.
- void SendHandshakeMessage(const CryptoHandshakeMessage& message,
- QuicAckListenerInterface* listener);
-
- // Performs key extraction to derive a new secret of |result_len| bytes
- // dependent on |label|, |context|, and the stream's negotiated subkey secret.
- // Returns false if the handshake has not been confirmed or the parameters are
- // invalid (e.g. |label| contains null bytes); returns true on success.
- bool ExportKeyingMaterial(base::StringPiece label,
- base::StringPiece context,
- size_t result_len,
- std::string* result) const;
-
- // Performs key extraction for Token Binding. Unlike ExportKeyingMaterial,
- // this function can be called before forward-secure encryption is
- // established. Returns false if initial encryption has not been established,
- // and true on success.
- //
- // Since this depends only on the initial keys, a signature over it can be
- // repurposed by an attacker who obtains the client's or server's DH private
- // value.
- bool ExportTokenBindingKeyingMaterial(std::string* result) const;
-
- bool encryption_established() const { return encryption_established_; }
- bool handshake_confirmed() const { return handshake_confirmed_; }
-
- const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const;
-
- protected:
- bool encryption_established_;
- bool handshake_confirmed_;
-
- QuicCryptoNegotiatedParameters crypto_negotiated_params_;
-
- private:
- CryptoFramer crypto_framer_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicCryptoStream);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_CRYPTO_STREAM_H_
diff --git a/chromium/net/quic/quic_crypto_stream_test.cc b/chromium/net/quic/quic_crypto_stream_test.cc
deleted file mode 100644
index c7024f7cf61..00000000000
--- a/chromium/net/quic/quic_crypto_stream_test.cc
+++ /dev/null
@@ -1,115 +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/quic_crypto_stream.h"
-
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/quic/test_tools/reliable_quic_stream_peer.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::string;
-using std::vector;
-
-namespace net {
-namespace test {
-namespace {
-
-class MockQuicCryptoStream : public QuicCryptoStream {
- public:
- explicit MockQuicCryptoStream(QuicSession* session)
- : QuicCryptoStream(session) {}
-
- void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
- messages_.push_back(message);
- }
-
- vector<CryptoHandshakeMessage>* messages() { return &messages_; }
-
- private:
- vector<CryptoHandshakeMessage> messages_;
-
- DISALLOW_COPY_AND_ASSIGN(MockQuicCryptoStream);
-};
-
-class QuicCryptoStreamTest : public ::testing::Test {
- public:
- QuicCryptoStreamTest()
- : connection_(new MockQuicConnection(&helper_,
- &alarm_factory_,
- Perspective::IS_CLIENT)),
- session_(connection_),
- stream_(&session_) {
- message_.set_tag(kSHLO);
- message_.SetStringPiece(1, "abc");
- message_.SetStringPiece(2, "def");
- ConstructHandshakeMessage();
- }
-
- void ConstructHandshakeMessage() {
- CryptoFramer framer;
- message_data_.reset(framer.ConstructHandshakeMessage(message_));
- }
-
- protected:
- MockQuicConnectionHelper helper_;
- MockAlarmFactory alarm_factory_;
- MockQuicConnection* connection_;
- MockQuicSpdySession session_;
- MockQuicCryptoStream stream_;
- CryptoHandshakeMessage message_;
- std::unique_ptr<QuicData> message_data_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(QuicCryptoStreamTest);
-};
-
-TEST_F(QuicCryptoStreamTest, NotInitiallyConected) {
- EXPECT_FALSE(stream_.encryption_established());
- EXPECT_FALSE(stream_.handshake_confirmed());
-}
-
-TEST_F(QuicCryptoStreamTest, ProcessRawData) {
- stream_.OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false,
- /*offset=*/0,
- message_data_->AsStringPiece()));
- ASSERT_EQ(1u, stream_.messages()->size());
- const CryptoHandshakeMessage& message = (*stream_.messages())[0];
- EXPECT_EQ(kSHLO, message.tag());
- EXPECT_EQ(2u, message.tag_value_map().size());
- EXPECT_EQ("abc", CryptoTestUtils::GetValueForTag(message, 1));
- EXPECT_EQ("def", CryptoTestUtils::GetValueForTag(message, 2));
-}
-
-TEST_F(QuicCryptoStreamTest, ProcessBadData) {
- string bad(message_data_->data(), message_data_->length());
- const int kFirstTagIndex = sizeof(uint32_t) + // message tag
- sizeof(uint16_t) + // number of tag-value pairs
- sizeof(uint16_t); // padding
- EXPECT_EQ(1, bad[kFirstTagIndex]);
- bad[kFirstTagIndex] = 0x7F; // out of order tag
-
- EXPECT_CALL(*connection_, CloseConnection(QUIC_CRYPTO_TAGS_OUT_OF_ORDER,
- testing::_, testing::_));
- stream_.OnStreamFrame(
- QuicStreamFrame(kCryptoStreamId, /*fin=*/false, /*offset=*/0, bad));
-}
-
-TEST_F(QuicCryptoStreamTest, NoConnectionLevelFlowControl) {
- EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl(
- &stream_));
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_data_reader.cc b/chromium/net/quic/quic_data_reader.cc
deleted file mode 100644
index fb8443d88f8..00000000000
--- a/chromium/net/quic/quic_data_reader.cc
+++ /dev/null
@@ -1,133 +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/quic_data_reader.h"
-
-#include "net/base/int128.h"
-#include "net/quic/quic_protocol.h"
-
-using base::StringPiece;
-
-namespace net {
-
-QuicDataReader::QuicDataReader(const char* data, const size_t len)
- : data_(data), len_(len), pos_(0) {}
-
-bool QuicDataReader::ReadUInt16(uint16_t* result) {
- return ReadBytes(result, sizeof(*result));
-}
-
-bool QuicDataReader::ReadUInt32(uint32_t* result) {
- return ReadBytes(result, sizeof(*result));
-}
-
-bool QuicDataReader::ReadUInt64(uint64_t* result) {
- return ReadBytes(result, sizeof(*result));
-}
-
-bool QuicDataReader::ReadUFloat16(uint64_t* result) {
- uint16_t value;
- if (!ReadUInt16(&value)) {
- return false;
- }
-
- *result = value;
- if (*result < (1 << kUFloat16MantissaEffectiveBits)) {
- // Fast path: either the value is denormalized (no hidden bit), or
- // normalized (hidden bit set, exponent offset by one) with exponent zero.
- // Zero exponent offset by one sets the bit exactly where the hidden bit is.
- // So in both cases the value encodes itself.
- return true;
- }
-
- uint16_t exponent =
- value >> kUFloat16MantissaBits; // No sign extend on uint!
- // After the fast pass, the exponent is at least one (offset by one).
- // Un-offset the exponent.
- --exponent;
- DCHECK_GE(exponent, 1);
- DCHECK_LE(exponent, kUFloat16MaxExponent);
- // Here we need to clear the exponent and set the hidden bit. We have already
- // decremented the exponent, so when we subtract it, it leaves behind the
- // hidden bit.
- *result -= exponent << kUFloat16MantissaBits;
- *result <<= exponent;
- DCHECK_GE(*result,
- static_cast<uint64_t>(1 << kUFloat16MantissaEffectiveBits));
- DCHECK_LE(*result, kUFloat16MaxValue);
- return true;
-}
-
-bool QuicDataReader::ReadStringPiece16(StringPiece* result) {
- // Read resultant length.
- uint16_t result_len;
- if (!ReadUInt16(&result_len)) {
- // OnFailure() already called.
- return false;
- }
-
- return ReadStringPiece(result, result_len);
-}
-
-bool QuicDataReader::ReadStringPiece(StringPiece* result, size_t size) {
- // Make sure that we have enough data to read.
- if (!CanRead(size)) {
- OnFailure();
- return false;
- }
-
- // Set result.
- result->set(data_ + pos_, size);
-
- // Iterate.
- pos_ += size;
-
- return true;
-}
-
-StringPiece QuicDataReader::ReadRemainingPayload() {
- StringPiece payload = PeekRemainingPayload();
- pos_ = len_;
- return payload;
-}
-
-StringPiece QuicDataReader::PeekRemainingPayload() {
- return StringPiece(data_ + pos_, len_ - pos_);
-}
-
-bool QuicDataReader::ReadBytes(void* result, size_t size) {
- // Make sure that we have enough data to read.
- if (!CanRead(size)) {
- OnFailure();
- return false;
- }
-
- // Read into result.
- memcpy(result, data_ + pos_, size);
-
- // Iterate.
- pos_ += size;
-
- return true;
-}
-
-bool QuicDataReader::IsDoneReading() const {
- return len_ == pos_;
-}
-
-size_t QuicDataReader::BytesRemaining() const {
- return len_ - pos_;
-}
-
-bool QuicDataReader::CanRead(size_t bytes) const {
- return bytes <= (len_ - pos_);
-}
-
-void QuicDataReader::OnFailure() {
- // Set our iterator to the end of the buffer so that further reads fail
- // immediately.
- pos_ = len_;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_data_writer.cc b/chromium/net/quic/quic_data_writer.cc
deleted file mode 100644
index 81cc7127f7e..00000000000
--- a/chromium/net/quic/quic_data_writer.cc
+++ /dev/null
@@ -1,145 +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/quic_data_writer.h"
-
-#include <stdint.h>
-#include <algorithm>
-#include <limits>
-
-using base::StringPiece;
-using std::numeric_limits;
-
-namespace net {
-
-QuicDataWriter::QuicDataWriter(size_t size, char* buffer)
- : buffer_(buffer), capacity_(size), length_(0) {}
-
-QuicDataWriter::~QuicDataWriter() {}
-
-char* QuicDataWriter::data() {
- return buffer_;
-}
-
-bool QuicDataWriter::WriteUInt8(uint8_t value) {
- return WriteBytes(&value, sizeof(value));
-}
-
-bool QuicDataWriter::WriteUInt16(uint16_t value) {
- return WriteBytes(&value, sizeof(value));
-}
-
-bool QuicDataWriter::WriteUInt32(uint32_t value) {
- return WriteBytes(&value, sizeof(value));
-}
-
-bool QuicDataWriter::WriteUInt48(uint64_t value) {
- uint16_t hi = static_cast<uint16_t>(value >> 32);
- uint32_t lo = static_cast<uint32_t>(value);
- return WriteUInt32(lo) && WriteUInt16(hi);
-}
-
-bool QuicDataWriter::WriteUInt64(uint64_t value) {
- return WriteBytes(&value, sizeof(value));
-}
-
-bool QuicDataWriter::WriteUFloat16(uint64_t value) {
- uint16_t result;
- if (value < (UINT64_C(1) << kUFloat16MantissaEffectiveBits)) {
- // Fast path: either the value is denormalized, or has exponent zero.
- // Both cases are represented by the value itself.
- result = static_cast<uint16_t>(value);
- } else if (value >= kUFloat16MaxValue) {
- // Value is out of range; clamp it to the maximum representable.
- result = numeric_limits<uint16_t>::max();
- } else {
- // The highest bit is between position 13 and 42 (zero-based), which
- // corresponds to exponent 1-30. In the output, mantissa is from 0 to 10,
- // hidden bit is 11 and exponent is 11 to 15. Shift the highest bit to 11
- // and count the shifts.
- uint16_t exponent = 0;
- for (uint16_t offset = 16; offset > 0; offset /= 2) {
- // Right-shift the value until the highest bit is in position 11.
- // For offset of 16, 8, 4, 2 and 1 (binary search over 1-30),
- // shift if the bit is at or above 11 + offset.
- if (value >= (UINT64_C(1) << (kUFloat16MantissaBits + offset))) {
- exponent += offset;
- value >>= offset;
- }
- }
-
- DCHECK_GE(exponent, 1);
- DCHECK_LE(exponent, kUFloat16MaxExponent);
- DCHECK_GE(value, UINT64_C(1) << kUFloat16MantissaBits);
- DCHECK_LT(value, UINT64_C(1) << kUFloat16MantissaEffectiveBits);
-
- // Hidden bit (position 11) is set. We should remove it and increment the
- // exponent. Equivalently, we just add it to the exponent.
- // This hides the bit.
- result = static_cast<uint16_t>(value + (exponent << kUFloat16MantissaBits));
- }
-
- return WriteBytes(&result, sizeof(result));
-}
-
-bool QuicDataWriter::WriteStringPiece16(StringPiece val) {
- if (val.size() > numeric_limits<uint16_t>::max()) {
- return false;
- }
- if (!WriteUInt16(static_cast<uint16_t>(val.size()))) {
- return false;
- }
- return WriteBytes(val.data(), val.size());
-}
-
-char* QuicDataWriter::BeginWrite(size_t length) {
- if (length_ > capacity_) {
- return nullptr;
- }
-
- if (capacity_ - length_ < length) {
- return nullptr;
- }
-
-#ifdef ARCH_CPU_64_BITS
- DCHECK_LE(length, std::numeric_limits<uint32_t>::max());
-#endif
-
- return buffer_ + length_;
-}
-
-bool QuicDataWriter::WriteBytes(const void* data, size_t data_len) {
- char* dest = BeginWrite(data_len);
- if (!dest) {
- return false;
- }
-
- memcpy(dest, data, data_len);
-
- length_ += data_len;
- return true;
-}
-
-bool QuicDataWriter::WriteRepeatedByte(uint8_t byte, size_t count) {
- char* dest = BeginWrite(count);
- if (!dest) {
- return false;
- }
-
- memset(dest, byte, count);
-
- length_ += count;
- return true;
-}
-
-void QuicDataWriter::WritePadding() {
- DCHECK_LE(length_, capacity_);
- if (length_ > capacity_) {
- return;
- }
- memset(buffer_ + length_, 0x00, capacity_ - length_);
- length_ = capacity_;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_data_writer.h b/chromium/net/quic/quic_data_writer.h
deleted file mode 100644
index dfe0fdaab52..00000000000
--- a/chromium/net/quic/quic_data_writer.h
+++ /dev/null
@@ -1,76 +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.
-
-#ifndef NET_QUIC_QUIC_DATA_WRITER_H_
-#define NET_QUIC_QUIC_DATA_WRITER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <cstddef>
-#include <string>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "net/base/int128.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-// This class provides facilities for packing QUIC data.
-//
-// The QuicDataWriter supports appending primitive values (int, string, etc)
-// to a frame instance. The internal memory buffer is exposed as the "data"
-// of the QuicDataWriter.
-class NET_EXPORT_PRIVATE QuicDataWriter {
- public:
- // Creates a QuicDataWriter where |buffer| is not owned.
- QuicDataWriter(size_t size, char* buffer);
-
- ~QuicDataWriter();
-
- // Returns the size of the QuicDataWriter's data.
- size_t length() const { return length_; }
-
- // Retrieves the buffer from the QuicDataWriter without changing ownership.
- char* data();
-
- // Methods for adding to the payload. These values are appended to the end
- // of the QuicDataWriter payload. Note - binary integers are written in
- // host byte order (little endian) not network byte order (big endian).
- bool WriteUInt8(uint8_t value);
- bool WriteUInt16(uint16_t value);
- bool WriteUInt32(uint32_t value);
- bool WriteUInt48(uint64_t value);
- bool WriteUInt64(uint64_t value);
- // Write unsigned floating point corresponding to the value. Large values are
- // clamped to the maximum representable (kUFloat16MaxValue). Values that can
- // not be represented directly are rounded down.
- bool WriteUFloat16(uint64_t value);
- bool WriteStringPiece16(base::StringPiece val);
- bool WriteBytes(const void* data, size_t data_len);
- bool WriteRepeatedByte(uint8_t byte, size_t count);
- // Fills the remaining buffer with null characters.
- void WritePadding();
-
- size_t capacity() const { return capacity_; }
-
- private:
- // Returns the location that the data should be written at, or nullptr if
- // there is not enough room. Call EndWrite with the returned offset and the
- // given length to pad out for the next write.
- char* BeginWrite(size_t length);
-
- char* buffer_;
- size_t capacity_; // Allocation size of payload (or -1 if buffer is const).
- size_t length_; // Current length of the buffer.
-
- DISALLOW_COPY_AND_ASSIGN(QuicDataWriter);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_DATA_WRITER_H_
diff --git a/chromium/net/quic/quic_data_writer_test.cc b/chromium/net/quic/quic_data_writer_test.cc
deleted file mode 100644
index f3d2bbbdafe..00000000000
--- a/chromium/net/quic/quic_data_writer_test.cc
+++ /dev/null
@@ -1,204 +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/quic_data_writer.h"
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "net/quic/quic_data_reader.h"
-#include "net/test/gtest_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-namespace {
-
-TEST(QuicDataWriterTest, SanityCheckUFloat16Consts) {
- // Check the arithmetic on the constants - otherwise the values below make
- // no sense.
- EXPECT_EQ(30, kUFloat16MaxExponent);
- EXPECT_EQ(11, kUFloat16MantissaBits);
- EXPECT_EQ(12, kUFloat16MantissaEffectiveBits);
- EXPECT_EQ(UINT64_C(0x3FFC0000000), kUFloat16MaxValue);
-}
-
-TEST(QuicDataWriterTest, WriteUFloat16) {
- struct TestCase {
- uint64_t decoded;
- uint16_t encoded;
- };
- TestCase test_cases[] = {
- // Small numbers represent themselves.
- {0, 0},
- {1, 1},
- {2, 2},
- {3, 3},
- {4, 4},
- {5, 5},
- {6, 6},
- {7, 7},
- {15, 15},
- {31, 31},
- {42, 42},
- {123, 123},
- {1234, 1234},
- // Check transition through 2^11.
- {2046, 2046},
- {2047, 2047},
- {2048, 2048},
- {2049, 2049},
- // Running out of mantissa at 2^12.
- {4094, 4094},
- {4095, 4095},
- {4096, 4096},
- {4097, 4096},
- {4098, 4097},
- {4099, 4097},
- {4100, 4098},
- {4101, 4098},
- // Check transition through 2^13.
- {8190, 6143},
- {8191, 6143},
- {8192, 6144},
- {8193, 6144},
- {8194, 6144},
- {8195, 6144},
- {8196, 6145},
- {8197, 6145},
- // Half-way through the exponents.
- {0x7FF8000, 0x87FF},
- {0x7FFFFFF, 0x87FF},
- {0x8000000, 0x8800},
- {0xFFF0000, 0x8FFF},
- {0xFFFFFFF, 0x8FFF},
- {0x10000000, 0x9000},
- // Transition into the largest exponent.
- {0x1FFFFFFFFFE, 0xF7FF},
- {0x1FFFFFFFFFF, 0xF7FF},
- {0x20000000000, 0xF800},
- {0x20000000001, 0xF800},
- {0x2003FFFFFFE, 0xF800},
- {0x2003FFFFFFF, 0xF800},
- {0x20040000000, 0xF801},
- {0x20040000001, 0xF801},
- // Transition into the max value and clamping.
- {0x3FF80000000, 0xFFFE},
- {0x3FFBFFFFFFF, 0xFFFE},
- {0x3FFC0000000, 0xFFFF},
- {0x3FFC0000001, 0xFFFF},
- {0x3FFFFFFFFFF, 0xFFFF},
- {0x40000000000, 0xFFFF},
- {0xFFFFFFFFFFFFFFFF, 0xFFFF},
- };
- int num_test_cases = sizeof(test_cases) / sizeof(test_cases[0]);
-
- for (int i = 0; i < num_test_cases; ++i) {
- char buffer[2];
- QuicDataWriter writer(2, buffer);
- EXPECT_TRUE(writer.WriteUFloat16(test_cases[i].decoded));
- EXPECT_EQ(test_cases[i].encoded,
- *reinterpret_cast<uint16_t*>(writer.data()));
- }
-}
-
-TEST(QuicDataWriterTest, ReadUFloat16) {
- struct TestCase {
- uint64_t decoded;
- uint16_t encoded;
- };
- TestCase test_cases[] = {
- // There are fewer decoding test cases because encoding truncates, and
- // decoding returns the smallest expansion.
- // Small numbers represent themselves.
- {0, 0},
- {1, 1},
- {2, 2},
- {3, 3},
- {4, 4},
- {5, 5},
- {6, 6},
- {7, 7},
- {15, 15},
- {31, 31},
- {42, 42},
- {123, 123},
- {1234, 1234},
- // Check transition through 2^11.
- {2046, 2046},
- {2047, 2047},
- {2048, 2048},
- {2049, 2049},
- // Running out of mantissa at 2^12.
- {4094, 4094},
- {4095, 4095},
- {4096, 4096},
- {4098, 4097},
- {4100, 4098},
- // Check transition through 2^13.
- {8190, 6143},
- {8192, 6144},
- {8196, 6145},
- // Half-way through the exponents.
- {0x7FF8000, 0x87FF},
- {0x8000000, 0x8800},
- {0xFFF0000, 0x8FFF},
- {0x10000000, 0x9000},
- // Transition into the largest exponent.
- {0x1FFE0000000, 0xF7FF},
- {0x20000000000, 0xF800},
- {0x20040000000, 0xF801},
- // Transition into the max value.
- {0x3FF80000000, 0xFFFE},
- {0x3FFC0000000, 0xFFFF},
- };
- int num_test_cases = sizeof(test_cases) / sizeof(test_cases[0]);
-
- for (int i = 0; i < num_test_cases; ++i) {
- QuicDataReader reader(reinterpret_cast<char*>(&test_cases[i].encoded), 2);
- uint64_t value;
- EXPECT_TRUE(reader.ReadUFloat16(&value));
- EXPECT_EQ(test_cases[i].decoded, value);
- }
-}
-
-TEST(QuicDataWriterTest, RoundTripUFloat16) {
- // Just test all 16-bit encoded values. 0 and max already tested above.
- uint64_t previous_value = 0;
- for (uint16_t i = 1; i < 0xFFFF; ++i) {
- // Read the two bytes.
- QuicDataReader reader(reinterpret_cast<char*>(&i), 2);
- uint64_t value;
- // All values must be decodable.
- EXPECT_TRUE(reader.ReadUFloat16(&value));
- // Check that small numbers represent themselves
- if (i < 4097)
- EXPECT_EQ(i, value);
- // Check there's monotonic growth.
- EXPECT_LT(previous_value, value);
- // Check that precision is within 0.5% away from the denormals.
- if (i > 2000)
- EXPECT_GT(previous_value * 1005, value * 1000);
- // Check we're always within the promised range.
- EXPECT_LT(value, UINT64_C(0x3FFC0000000));
- previous_value = value;
- char buffer[6];
- QuicDataWriter writer(6, buffer);
- EXPECT_TRUE(writer.WriteUFloat16(value - 1));
- EXPECT_TRUE(writer.WriteUFloat16(value));
- EXPECT_TRUE(writer.WriteUFloat16(value + 1));
- // Check minimal decoding (previous decoding has previous encoding).
- EXPECT_EQ(i - 1, *reinterpret_cast<uint16_t*>(writer.data()));
- // Check roundtrip.
- EXPECT_EQ(i, *reinterpret_cast<uint16_t*>(writer.data() + 2));
- // Check next decoding.
- EXPECT_EQ(i < 4096 ? i + 1 : i,
- *reinterpret_cast<uint16_t*>(writer.data() + 4));
- }
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_end_to_end_unittest.cc b/chromium/net/quic/quic_end_to_end_unittest.cc
deleted file mode 100644
index 15602a78ba4..00000000000
--- a/chromium/net/quic/quic_end_to_end_unittest.cc
+++ /dev/null
@@ -1,386 +0,0 @@
-// Copyright 2013 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 <memory>
-#include <ostream>
-#include <utility>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "net/base/elements_upload_data_stream.h"
-#include "net/base/ip_address.h"
-#include "net/base/test_completion_callback.h"
-#include "net/base/upload_bytes_element_reader.h"
-#include "net/base/upload_data_stream.h"
-#include "net/cert/ct_policy_enforcer.h"
-#include "net/cert/mock_cert_verifier.h"
-#include "net/cert/multi_log_ct_verifier.h"
-#include "net/dns/mapped_host_resolver.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/http/http_auth_handler_factory.h"
-#include "net/http/http_network_session.h"
-#include "net/http/http_network_transaction.h"
-#include "net/http/http_server_properties_impl.h"
-#include "net/http/http_transaction_test_util.h"
-#include "net/http/transport_security_state.h"
-#include "net/proxy/proxy_service.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/ssl/default_channel_id_store.h"
-#include "net/ssl/ssl_config_service_defaults.h"
-#include "net/test/cert_test_util.h"
-#include "net/test/test_data_directory.h"
-#include "net/tools/quic/quic_in_memory_cache.h"
-#include "net/tools/quic/quic_server.h"
-#include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h"
-#include "net/tools/quic/test_tools/server_thread.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-using base::StringPiece;
-
-namespace net {
-
-using test::QuicInMemoryCachePeer;
-using test::ServerThread;
-
-namespace test {
-
-namespace {
-
-const char kResponseBody[] = "some arbitrary response body";
-
-// Factory for creating HttpTransactions, used by TestTransactionConsumer.
-class TestTransactionFactory : public HttpTransactionFactory {
- public:
- explicit TestTransactionFactory(const HttpNetworkSession::Params& params)
- : session_(new HttpNetworkSession(params)) {}
-
- ~TestTransactionFactory() override {}
-
- // HttpTransactionFactory methods
- int CreateTransaction(RequestPriority priority,
- std::unique_ptr<HttpTransaction>* trans) override {
- trans->reset(new HttpNetworkTransaction(priority, session_.get()));
- return OK;
- }
-
- HttpCache* GetCache() override { return nullptr; }
-
- HttpNetworkSession* GetSession() override { return session_.get(); };
-
- private:
- std::unique_ptr<HttpNetworkSession> session_;
-};
-
-struct TestParams {
- explicit TestParams(bool use_stateless_rejects)
- : use_stateless_rejects(use_stateless_rejects) {}
-
- friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
- os << "{ use_stateless_rejects: " << p.use_stateless_rejects << " }";
- return os;
- }
- bool use_stateless_rejects;
-};
-
-std::vector<TestParams> GetTestParams() {
- return std::vector<TestParams>{TestParams(true), TestParams(false)};
-}
-
-} // namespace
-
-class QuicEndToEndTest : public ::testing::TestWithParam<TestParams> {
- protected:
- QuicEndToEndTest()
- : host_resolver_impl_(CreateResolverImpl()),
- host_resolver_(std::move(host_resolver_impl_)),
- cert_transparency_verifier_(new MultiLogCTVerifier()),
- ssl_config_service_(new SSLConfigServiceDefaults),
- proxy_service_(ProxyService::CreateDirect()),
- auth_handler_factory_(
- HttpAuthHandlerFactory::CreateDefault(&host_resolver_)),
- strike_register_no_startup_period_(false) {
- request_.method = "GET";
- request_.url = GURL("https://test.example.com/");
- request_.load_flags = 0;
-
- params_.enable_quic = true;
- params_.quic_clock = nullptr;
- params_.quic_random = nullptr;
- if (GetParam().use_stateless_rejects) {
- params_.quic_connection_options.push_back(kSREJ);
- }
- params_.host_resolver = &host_resolver_;
- params_.cert_verifier = &cert_verifier_;
- params_.transport_security_state = &transport_security_state_;
- params_.cert_transparency_verifier = cert_transparency_verifier_.get();
- params_.ct_policy_enforcer = &ct_policy_enforcer_;
- params_.proxy_service = proxy_service_.get();
- params_.ssl_config_service = ssl_config_service_.get();
- params_.http_auth_handler_factory = auth_handler_factory_.get();
- params_.http_server_properties = &http_server_properties_;
- channel_id_service_.reset(
- new ChannelIDService(new DefaultChannelIDStore(nullptr),
- base::ThreadTaskRunnerHandle::Get()));
- params_.channel_id_service = channel_id_service_.get();
-
- 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");
- cert_verifier_.AddResultForCertAndHost(verify_result.verified_cert.get(),
- "test.example.com", verify_result,
- OK);
- }
-
- // Creates a mock host resolver in which test.example.com
- // resolves to localhost.
- static MockHostResolver* CreateResolverImpl() {
- MockHostResolver* resolver = new MockHostResolver();
- resolver->rules()->AddRule("test.example.com", "127.0.0.1");
- return resolver;
- }
-
- void SetUp() override {
- QuicInMemoryCachePeer::ResetForTests();
- StartServer();
-
- // Use a mapped host resolver so that request for test.example.com (port 80)
- // reach the server running on localhost.
- std::string map_rule = "MAP test.example.com test.example.com:" +
- base::IntToString(server_thread_->GetPort());
- EXPECT_TRUE(host_resolver_.AddRuleFromString(map_rule));
-
- // To simplify the test, and avoid the race with the HTTP request, we force
- // QUIC for these requests.
- params_.origins_to_force_quic_on.insert(
- HostPortPair::FromString("test.example.com:443"));
-
- transaction_factory_.reset(new TestTransactionFactory(params_));
- }
-
- void TearDown() override {
- StopServer();
- QuicInMemoryCachePeer::ResetForTests();
- }
-
- // Starts the QUIC server listening on a random port.
- void StartServer() {
- server_address_ = IPEndPoint(IPAddress(127, 0, 0, 1), 0);
- server_config_.SetInitialStreamFlowControlWindowToSend(
- kInitialStreamFlowControlWindowForTest);
- server_config_.SetInitialSessionFlowControlWindowToSend(
- kInitialSessionFlowControlWindowForTest);
- server_config_options_.token_binding_enabled = true;
- QuicServer* server =
- new QuicServer(CryptoTestUtils::ProofSourceForTesting(), server_config_,
- server_config_options_, QuicSupportedVersions());
- server_thread_.reset(new ServerThread(server, server_address_,
- strike_register_no_startup_period_));
- server_thread_->Initialize();
- server_address_ =
- IPEndPoint(server_address_.address(), server_thread_->GetPort());
- server_thread_->Start();
- server_started_ = true;
- }
-
- // Stops the QUIC server.
- void StopServer() {
- if (!server_started_) {
- return;
- }
- if (server_thread_.get()) {
- server_thread_->Quit();
- server_thread_->Join();
- }
- }
-
- // Adds an entry to the cache used by the QUIC server to serve
- // responses.
- void AddToCache(StringPiece path,
- int response_code,
- StringPiece response_detail,
- StringPiece body) {
- QuicInMemoryCache::GetInstance()->AddSimpleResponse(
- "test.example.com", path, response_code, body);
- }
-
- // Populates |request_body_| with |length_| ASCII bytes.
- void GenerateBody(size_t length) {
- request_body_.clear();
- request_body_.reserve(length);
- for (size_t i = 0; i < length; ++i) {
- request_body_.append(1, static_cast<char>(32 + i % (126 - 32)));
- }
- }
-
- // Initializes |request_| for a post of |length| bytes.
- void InitializePostRequest(size_t length) {
- GenerateBody(length);
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(base::WrapUnique(new UploadBytesElementReader(
- request_body_.data(), request_body_.length())));
- upload_data_stream_.reset(
- new ElementsUploadDataStream(std::move(element_readers), 0));
- request_.method = "POST";
- request_.url = GURL("https://test.example.com/");
- request_.upload_data_stream = upload_data_stream_.get();
- ASSERT_EQ(OK, request_.upload_data_stream->Init(CompletionCallback()));
- }
-
- // Checks that |consumer| completed and received |status_line| and |body|.
- void CheckResponse(const TestTransactionConsumer& consumer,
- const std::string& status_line,
- const std::string& body) {
- ASSERT_TRUE(consumer.is_done());
- ASSERT_EQ(OK, consumer.error());
- EXPECT_EQ(status_line, consumer.response_info()->headers->GetStatusLine());
- EXPECT_EQ(body, consumer.content());
- }
-
- std::unique_ptr<MockHostResolver> host_resolver_impl_;
- MappedHostResolver host_resolver_;
- MockCertVerifier cert_verifier_;
- std::unique_ptr<ChannelIDService> channel_id_service_;
- TransportSecurityState transport_security_state_;
- std::unique_ptr<CTVerifier> cert_transparency_verifier_;
- CTPolicyEnforcer ct_policy_enforcer_;
- scoped_refptr<SSLConfigServiceDefaults> ssl_config_service_;
- std::unique_ptr<ProxyService> proxy_service_;
- std::unique_ptr<HttpAuthHandlerFactory> auth_handler_factory_;
- HttpServerPropertiesImpl http_server_properties_;
- HttpNetworkSession::Params params_;
- std::unique_ptr<TestTransactionFactory> transaction_factory_;
- HttpRequestInfo request_;
- std::string request_body_;
- std::unique_ptr<UploadDataStream> upload_data_stream_;
- std::unique_ptr<ServerThread> server_thread_;
- IPEndPoint server_address_;
- std::string server_hostname_;
- QuicConfig server_config_;
- QuicCryptoServerConfig::ConfigOptions server_config_options_;
- bool server_started_;
- bool strike_register_no_startup_period_;
-};
-
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicEndToEndTest,
- ::testing::ValuesIn(GetTestParams()));
-
-TEST_P(QuicEndToEndTest, LargeGetWithNoPacketLoss) {
- std::string response(10 * 1024, 'x');
-
- AddToCache(request_.url.PathForRequest(), 200, "OK", response);
-
- TestTransactionConsumer consumer(DEFAULT_PRIORITY,
- transaction_factory_.get());
- consumer.Start(&request_, BoundNetLog());
-
- // Will terminate when the last consumer completes.
- base::MessageLoop::current()->Run();
-
- CheckResponse(consumer, "HTTP/1.1 200", response);
-}
-
-TEST_P(QuicEndToEndTest, TokenBinding) {
- // Enable token binding and re-initialize the TestTransactionFactory.
- params_.enable_token_binding = true;
- transaction_factory_.reset(new TestTransactionFactory(params_));
-
- AddToCache(request_.url.PathForRequest(), 200, "OK", kResponseBody);
-
- TestTransactionConsumer consumer(DEFAULT_PRIORITY,
- transaction_factory_.get());
- consumer.Start(&request_, BoundNetLog());
-
- // Will terminate when the last consumer completes.
- base::MessageLoop::current()->Run();
-
- CheckResponse(consumer, "HTTP/1.1 200", kResponseBody);
- HttpRequestHeaders headers;
- ASSERT_TRUE(consumer.transaction()->GetFullRequestHeaders(&headers));
- EXPECT_TRUE(headers.HasHeader(HttpRequestHeaders::kTokenBinding));
-}
-
-// crbug.com/559173
-#if defined(THREAD_SANITIZER)
-TEST_P(QuicEndToEndTest, DISABLED_LargePostWithNoPacketLoss) {
-#else
-TEST_P(QuicEndToEndTest, LargePostWithNoPacketLoss) {
-#endif
- InitializePostRequest(1024 * 1024);
-
- AddToCache(request_.url.PathForRequest(), 200, "OK", kResponseBody);
-
- TestTransactionConsumer consumer(DEFAULT_PRIORITY,
- transaction_factory_.get());
- consumer.Start(&request_, BoundNetLog());
-
- // Will terminate when the last consumer completes.
- base::MessageLoop::current()->Run();
-
- CheckResponse(consumer, "HTTP/1.1 200", kResponseBody);
-}
-
-// crbug.com/559173
-#if defined(THREAD_SANITIZER)
-TEST_P(QuicEndToEndTest, DISABLED_LargePostWithPacketLoss) {
-#else
-TEST_P(QuicEndToEndTest, LargePostWithPacketLoss) {
-#endif
- // FLAGS_fake_packet_loss_percentage = 30;
- InitializePostRequest(1024 * 1024);
-
- const char kResponseBody[] = "some really big response body";
- AddToCache(request_.url.PathForRequest(), 200, "OK", kResponseBody);
-
- TestTransactionConsumer consumer(DEFAULT_PRIORITY,
- transaction_factory_.get());
- consumer.Start(&request_, BoundNetLog());
-
- // Will terminate when the last consumer completes.
- base::MessageLoop::current()->Run();
-
- CheckResponse(consumer, "HTTP/1.1 200", kResponseBody);
-}
-
-// crbug.com/536845
-#if defined(THREAD_SANITIZER)
-TEST_P(QuicEndToEndTest, DISABLED_UberTest) {
-#else
-TEST_P(QuicEndToEndTest, UberTest) {
-#endif
- // FLAGS_fake_packet_loss_percentage = 30;
-
- const char kResponseBody[] = "some really big response body";
- AddToCache(request_.url.PathForRequest(), 200, "OK", kResponseBody);
-
- std::vector<TestTransactionConsumer*> consumers;
- size_t num_requests = 100;
- for (size_t i = 0; i < num_requests; ++i) {
- TestTransactionConsumer* consumer = new TestTransactionConsumer(
- DEFAULT_PRIORITY, transaction_factory_.get());
- consumers.push_back(consumer);
- consumer->Start(&request_, BoundNetLog());
- }
-
- // Will terminate when the last consumer completes.
- base::MessageLoop::current()->Run();
-
- for (size_t i = 0; i < num_requests; ++i) {
- CheckResponse(*consumers[i], "HTTP/1.1 200", kResponseBody);
- }
- STLDeleteElements(&consumers);
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_flags.cc b/chromium/net/quic/quic_flags.cc
deleted file mode 100644
index 3ababa247fb..00000000000
--- a/chromium/net/quic/quic_flags.cc
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_flags.h"
-
-// If true, it will return as soon as an error is detected while validating
-// CHLO.
-bool FLAGS_use_early_return_when_verifying_chlo = true;
-
-// If true, QUIC BBR congestion control may be enabled via Finch and/or via QUIC
-// connection options.
-bool FLAGS_quic_allow_bbr = false;
-
-// Time period for which a given connection_id should live in the time-wait
-// state.
-int64_t FLAGS_quic_time_wait_list_seconds = 200;
-
-// Currently, this number is quite conservative. The max QPS limit for an
-// individual server silo is currently set to 1000 qps, though the actual max
-// that we see in the wild is closer to 450 qps. Regardless, this means that
-// the longest time-wait list we should see is 200 seconds * 1000 qps = 200000.
-// Of course, there are usually many queries per QUIC connection, so we allow a
-// factor of 3 leeway.
-//
-// Maximum number of connections on the time-wait list. A negative value implies
-// no configured limit.
-int64_t FLAGS_quic_time_wait_list_max_connections = 600000;
-
-// Enables server-side support for QUIC stateless rejects.
-bool FLAGS_enable_quic_stateless_reject_support = true;
-
-// This flag is not in use, just to keep consistency for shared code.
-bool FLAGS_quic_always_log_bugs_for_tests = true;
-
-// If true, a QUIC connection option with tag DHDT can be used to disable
-// HPACK\'s dynamic table.
-bool FLAGS_quic_disable_hpack_dynamic_table = true;
-
-// If true, multipath is enabled for the connection.
-bool FLAGS_quic_enable_multipath = false;
-
-// If true, require handshake confirmation for QUIC connections, functionally
-// disabling 0-rtt handshakes.
-// TODO(rtenneti): Enable this flag after CryptoServerTest's are fixed.
-bool FLAGS_quic_require_handshake_confirmation = false;
-
-// If true, Cubic's epoch is shifted when the sender is application-limited.
-bool FLAGS_shift_quic_cubic_epoch_when_app_limited = false;
-
-// If true, QUIC will measure head of line (HOL) blocking due between
-// streams due to packet losses on the headers stream. The
-// measurements will be surfaced via UMA histogram
-// Net.QuicSession.HeadersHOLBlockedTime.
-bool FLAGS_quic_measure_headers_hol_blocking_time = true;
-
-// If true, disable pacing in QUIC.
-bool FLAGS_quic_disable_pacing_for_perf_tests = false;
-
-// If true, Close the connection instead of writing unencrypted stream data.
-bool FLAGS_quic_never_write_unencrypted_data = true;
-
-// If true, reject any incoming QUIC which does not have the FIXD tag.
-bool FLAGS_quic_require_fix = true;
-
-// If true, headers stream will support receiving PUSH_PROMISE frames.
-bool FLAGS_quic_supports_push_promise = true;
-
-// If true, make sure new incoming streams correctly cede to higher
-// priority (or batch) streams when doing QUIC writes.
-bool FLAGS_quic_cede_correctly = true;
-
-// If true, QUIC should correctly report if it supports ChaCha20. Otherwise,
-// QUIC will lie and claim that it does not support ChaCha20. The primary use
-// case for this is places where ChaCha20 is prohibitively expensive compared to
-// AES-GCM.
-bool FLAGS_quic_crypto_server_config_default_has_chacha20 = true;
-
-// Resend 0RTT requests in response to an REJ that re-establishes encryption.
-bool FLAGS_quic_reply_to_rej = true;
-
-// If true, QUIC connections can do bandwidth resumption with an initial window
-// of < 10 packets.
-bool FLAGS_quic_no_lower_bw_resumption_limit = true;
-
-// Limit the ruction of slow start large reduction to 1/2 the current CWND once
-// the initial flight has been acked.
-bool FLAGS_quic_sslr_limit_reduction = true;
-
-// If true, flow controller may grow the receive window size if necessary.
-bool FLAGS_quic_auto_tune_receive_window = true;
-
-// If true, enable auto tuning by default (server side).
-bool FLAGS_quic_enable_autotune_by_default = true;
-
-// Use largest acked in the most recent ack instead of largest acked ever in
-// loss recovery.
-bool FLAGS_quic_loss_recovery_use_largest_acked = true;
-
-// Only set one alarm for sending at once, either the send alarm or
-// retransmission alarm. Disabled because it breaks QUIC time loss detection.
-bool FLAGS_quic_only_one_sending_alarm = false;
-
-// If true, the hash of the CHLO message will be used in the proof generated for
-// an SCUP message.
-bool FLAGS_quic_use_hash_in_scup = true;
-
-// If true, QUIC public reset packets will have the \"pre-v33\" public header
-// flags.
-bool FLAGS_quic_use_old_public_reset_packets = true;
-
-// Ignore the peer's recieve buffer size and instead set max CWND based on the
-// amount of data the sender is willing to have in flight.
-bool FLAGS_quic_ignore_srbf = true;
-
-// Allow the NPRR connection option which reduces QUIC\'s pacing rate during
-// recovery instead of PRR.
-bool FLAGS_quic_allow_noprr = true;
-
-// Use a write path optimized for StreamFrames.
-bool FLAGS_quic_use_optimized_write_path = true;
-
-// If true, the dispatcher is responsible for generating server designated
-// connection IDs.
-bool FLAGS_quic_dispatcher_creates_id = true;
-
-// If true, checks if the CHLO is acceptable as a matter of policy.
-bool FLAGS_quic_enable_chlo_policy = true;
-
-// If true, ignore QUIC data frames of length 0 for flow control.
-bool FLAGS_quic_ignore_zero_length_frames = true;
-
-// If true, replace ServerHelloNotifier with a check to see if a decrypted
-// packet is forward secure.
-bool FLAGS_quic_no_shlo_listener = true;
-
-// If true, queued retransmission packets, because of write blocked
-// socket, are always sent once the socket gets unblocked
-bool FLAGS_quic_always_write_queued_retransmissions = true;
-
-// Use GetLeastUnacked when updating the packet number length, instead of
-// GetLeastPacketAwaitedByPeer.
-bool FLAGS_quic_least_unacked_packet_number_length = true;
-
-// Adds a RATE connection option to do rate based sending.
-bool FLAGS_quic_rate_based_sending = true;
-
-// If true, QUIC will use cheap stateless rejects without creating a full
-// connection.
-bool FLAGS_quic_use_cheap_stateless_rejects = false;
-
-// If true, treat timestamps from SO_TIMESTAMPING as QuicWallTimes rather
-// than QuicTimes.
-bool FLAGS_quic_socket_walltimestamps = false;
-
-// If true, default to immediate forward secure once established on the
-// server side, and the IPFS connection option disables this instead of
-// enabling it.
-bool FLAGS_quic_default_immediate_forward_secure = true;
-
-// If true, disables support for QUIC version 29 and earlier.
-bool FLAGS_quic_disable_pre_30 = false;
-
-// If true, QUIC respect HTTP2 SETTINGS frame rather than always close the
-// connection.
-bool FLAGS_quic_respect_http2_settings_frame = true;
-
-// Do not use a QuicAckListener in order to confirm a larger Path MTU.
-bool FLAGS_quic_no_mtu_discovery_ack_listener = false;
-
-// Deprecate QuicPacketCreator::next_packet_number_length_ because it's no
-// longer necessary.
-bool FLAGS_quic_simple_packet_number_length = false;
-
-// If true, enables QUIC_VERSION_35.
-bool FLAGS_quic_enable_version_35 = false;
diff --git a/chromium/net/quic/quic_flags.h b/chromium/net/quic/quic_flags.h
deleted file mode 100644
index cebbace883c..00000000000
--- a/chromium/net/quic/quic_flags.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_FLAGS_H_
-#define NET_QUIC_QUIC_FLAGS_H_
-
-#include <stdint.h>
-
-#include "net/base/net_export.h"
-
-NET_EXPORT_PRIVATE extern bool FLAGS_use_early_return_when_verifying_chlo;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_bbr;
-NET_EXPORT_PRIVATE extern int64_t FLAGS_quic_time_wait_list_seconds;
-NET_EXPORT_PRIVATE extern int64_t FLAGS_quic_time_wait_list_max_connections;
-NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_stateless_reject_support;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_always_log_bugs_for_tests;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_disable_hpack_dynamic_table;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_enable_multipath;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_require_handshake_confirmation;
-NET_EXPORT_PRIVATE extern bool FLAGS_shift_quic_cubic_epoch_when_app_limited;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_measure_headers_hol_blocking_time;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_disable_pacing_for_perf_tests;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_never_write_unencrypted_data;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_require_fix;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_supports_push_promise;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_supports_push_promise;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_cede_correctly;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_least_unacked_packet_number_length;
-NET_EXPORT_PRIVATE extern bool
- FLAGS_quic_crypto_server_config_default_has_chacha20;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_reply_to_rej;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_no_lower_bw_resumption_limit;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_sslr_limit_reduction;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_auto_tune_receive_window;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_enable_autotune_by_default;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_loss_recovery_use_largest_acked;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_only_one_sending_alarm;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_hash_in_scup;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_old_public_reset_packets;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_ignore_srbf;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_noprr;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_optimized_write_path;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_dispatcher_creates_id;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_enable_chlo_policy;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_ignore_zero_length_frames;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_no_shlo_listener;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_always_write_queued_retransmissions;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_rate_based_sending;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_cheap_stateless_rejects;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_socket_walltimestamps;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_default_immediate_forward_secure;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_disable_pre_30;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_respect_http2_settings_frame;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_no_mtu_discovery_ack_listener;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_simple_packet_number_length;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_enable_version_35;
-
-#endif // NET_QUIC_QUIC_FLAGS_H_
diff --git a/chromium/net/quic/quic_flow_controller.cc b/chromium/net/quic/quic_flow_controller.cc
deleted file mode 100644
index 30c5386f53a..00000000000
--- a/chromium/net/quic/quic_flow_controller.cc
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_flow_controller.h"
-
-#include "base/strings/stringprintf.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-#define ENDPOINT \
- (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ")
-
-QuicFlowController::QuicFlowController(QuicConnection* connection,
- QuicStreamId id,
- Perspective perspective,
- QuicStreamOffset send_window_offset,
- QuicStreamOffset receive_window_offset,
- bool should_auto_tune_receive_window)
- : connection_(connection),
- id_(id),
- perspective_(perspective),
- bytes_sent_(0),
- send_window_offset_(send_window_offset),
- bytes_consumed_(0),
- highest_received_byte_offset_(0),
- receive_window_offset_(receive_window_offset),
- receive_window_size_(receive_window_offset),
- auto_tune_receive_window_(should_auto_tune_receive_window),
- last_blocked_send_window_offset_(0),
- prev_window_update_time_(QuicTime::Zero()) {
- receive_window_size_limit_ = (id_ == kConnectionLevelId)
- ? kSessionReceiveWindowLimit
- : kStreamReceiveWindowLimit;
-
- DVLOG(1) << ENDPOINT << "Created flow controller for stream " << id_
- << ", setting initial receive window offset to: "
- << receive_window_offset_
- << ", max receive window to: " << receive_window_size_
- << ", max receive window limit to: " << receive_window_size_limit_
- << ", setting send window offset to: " << send_window_offset_;
-}
-
-void QuicFlowController::AddBytesConsumed(QuicByteCount bytes_consumed) {
- bytes_consumed_ += bytes_consumed;
- DVLOG(1) << ENDPOINT << "Stream " << id_ << " consumed: " << bytes_consumed_;
-
- MaybeSendWindowUpdate();
-}
-
-bool QuicFlowController::UpdateHighestReceivedOffset(
- QuicStreamOffset new_offset) {
- // Only update if offset has increased.
- if (new_offset <= highest_received_byte_offset_) {
- return false;
- }
-
- DVLOG(1) << ENDPOINT << "Stream " << id_
- << " highest byte offset increased from: "
- << highest_received_byte_offset_ << " to " << new_offset;
- highest_received_byte_offset_ = new_offset;
- return true;
-}
-
-void QuicFlowController::AddBytesSent(QuicByteCount bytes_sent) {
- if (bytes_sent_ + bytes_sent > send_window_offset_) {
- QUIC_BUG << ENDPOINT << "Stream " << id_ << " Trying to send an extra "
- << bytes_sent << " bytes, when bytes_sent = " << bytes_sent_
- << ", and send_window_offset_ = " << send_window_offset_;
- bytes_sent_ = send_window_offset_;
-
- // This is an error on our side, close the connection as soon as possible.
- connection_->CloseConnection(
- QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA,
- base::StringPrintf(
- "%llu bytes over send window offset",
- static_cast<unsigned long long>(send_window_offset_ -
- (bytes_sent_ + bytes_sent)))
- .c_str(),
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
-
- bytes_sent_ += bytes_sent;
- DVLOG(1) << ENDPOINT << "Stream " << id_ << " sent: " << bytes_sent_;
-}
-
-bool QuicFlowController::FlowControlViolation() {
- if (highest_received_byte_offset_ > receive_window_offset_) {
- LOG(ERROR) << ENDPOINT << "Flow control violation on stream " << id_
- << ", receive window offset: " << receive_window_offset_
- << ", highest received byte offset: "
- << highest_received_byte_offset_;
- return true;
- }
- return false;
-}
-
-void QuicFlowController::MaybeIncreaseMaxWindowSize() {
- // Core of receive window auto tuning. This method should be called before a
- // WINDOW_UPDATE frame is sent. Ideally, window updates should occur close to
- // once per RTT. If a window update happens much faster than RTT, it implies
- // that the flow control window is imposing a bottleneck. To prevent this,
- // this method will increase the receive window size (subject to a reasonable
- // upper bound). For simplicity this algorithm is deliberately asymmetric, in
- // that it may increase window size but never decreases.
-
- if (!FLAGS_quic_auto_tune_receive_window) {
- return;
- }
-
- // Keep track of timing between successive window updates.
- QuicTime now = connection_->clock()->ApproximateNow();
- QuicTime prev = prev_window_update_time_;
- prev_window_update_time_ = now;
- if (!prev.IsInitialized()) {
- DVLOG(1) << ENDPOINT << "first window update for stream " << id_;
- return;
- }
-
- if (!auto_tune_receive_window_) {
- return;
- }
-
- // Get outbound RTT.
- QuicTime::Delta rtt =
- connection_->sent_packet_manager().GetRttStats()->smoothed_rtt();
- if (rtt.IsZero()) {
- DVLOG(1) << ENDPOINT << "rtt zero for stream " << id_;
- return;
- }
-
- // Now we can compare timing of window updates with RTT.
- QuicTime::Delta since_last = now.Subtract(prev);
- QuicTime::Delta two_rtt = rtt.Multiply(2);
-
- if (since_last >= two_rtt) {
- // If interval between window updates is sufficiently large, there
- // is no need to increase receive_window_size_.
- return;
- }
-
- QuicByteCount old_window = receive_window_size_;
- receive_window_size_ *= 2;
- receive_window_size_ =
- std::min(receive_window_size_, receive_window_size_limit_);
-
- if (receive_window_size_ > old_window) {
- DVLOG(1) << ENDPOINT << "New max window increase for stream " << id_
- << " after " << since_last.ToMicroseconds() << " us, and RTT is "
- << rtt.ToMicroseconds()
- << "us. max wndw: " << receive_window_size_;
- } else {
- // TODO(ckrasic) - add a varz to track this (?).
- DVLOG(1) << ENDPOINT << "Max window at limit for stream " << id_
- << " after " << since_last.ToMicroseconds() << " us, and RTT is "
- << rtt.ToMicroseconds()
- << "us. Limit size: " << receive_window_size_;
- }
-}
-
-QuicByteCount QuicFlowController::WindowUpdateThreshold() {
- return receive_window_size_ / 2;
-}
-
-void QuicFlowController::MaybeSendWindowUpdate() {
- // Send WindowUpdate to increase receive window if
- // (receive window offset - consumed bytes) < (max window / 2).
- // This is behaviour copied from SPDY.
- DCHECK_LE(bytes_consumed_, receive_window_offset_);
- QuicStreamOffset available_window = receive_window_offset_ - bytes_consumed_;
- QuicByteCount threshold = WindowUpdateThreshold();
-
- if (available_window >= threshold) {
- DVLOG(1) << ENDPOINT << "Not sending WindowUpdate for stream " << id_
- << ", available window: " << available_window
- << " >= threshold: " << threshold;
- return;
- }
-
- MaybeIncreaseMaxWindowSize();
-
- // Update our receive window.
- receive_window_offset_ += (receive_window_size_ - available_window);
-
- DVLOG(1) << ENDPOINT << "Sending WindowUpdate frame for stream " << id_
- << ", consumed bytes: " << bytes_consumed_
- << ", available window: " << available_window
- << ", and threshold: " << threshold
- << ", and receive window size: " << receive_window_size_
- << ". New receive window offset is: " << receive_window_offset_;
-
- // Inform the peer of our new receive window.
- connection_->SendWindowUpdate(id_, receive_window_offset_);
-}
-
-void QuicFlowController::MaybeSendBlocked() {
- if (SendWindowSize() == 0 &&
- last_blocked_send_window_offset_ < send_window_offset_) {
- DVLOG(1) << ENDPOINT << "Stream " << id_ << " is flow control blocked. "
- << "Send window: " << SendWindowSize()
- << ", bytes sent: " << bytes_sent_
- << ", send limit: " << send_window_offset_;
- // The entire send_window has been consumed, we are now flow control
- // blocked.
- connection_->SendBlocked(id_);
-
- // Keep track of when we last sent a BLOCKED frame so that we only send one
- // at a given send offset.
- last_blocked_send_window_offset_ = send_window_offset_;
- }
-}
-
-bool QuicFlowController::UpdateSendWindowOffset(
- QuicStreamOffset new_send_window_offset) {
- // Only update if send window has increased.
- if (new_send_window_offset <= send_window_offset_) {
- return false;
- }
-
- DVLOG(1) << ENDPOINT << "UpdateSendWindowOffset for stream " << id_
- << " with new offset " << new_send_window_offset
- << " current offset: " << send_window_offset_
- << " bytes_sent: " << bytes_sent_;
-
- const bool blocked = IsBlocked();
- send_window_offset_ = new_send_window_offset;
- return blocked;
-}
-
-bool QuicFlowController::IsBlocked() const {
- return SendWindowSize() == 0;
-}
-
-uint64_t QuicFlowController::SendWindowSize() const {
- if (bytes_sent_ > send_window_offset_) {
- return 0;
- }
- return send_window_offset_ - bytes_sent_;
-}
-
-void QuicFlowController::UpdateReceiveWindowSize(QuicStreamOffset size) {
- DVLOG(1) << ENDPOINT << "UpdateReceiveWindowSize for stream " << id_ << ": "
- << size;
- if (receive_window_size_ != receive_window_offset_) {
- QUIC_BUG << "receive_window_size_:" << receive_window_size_
- << " != receive_window_offset:" << receive_window_offset_;
- return;
- }
- receive_window_size_ = size;
- receive_window_offset_ = size;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_flow_controller.h b/chromium/net/quic/quic_flow_controller.h
deleted file mode 100644
index 62ae5b65664..00000000000
--- a/chromium/net/quic/quic_flow_controller.h
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_FLOW_CONTROLLER_H_
-#define NET_QUIC_QUIC_FLOW_CONTROLLER_H_
-
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-namespace test {
-class QuicFlowControllerPeer;
-} // namespace test
-
-class QuicConnection;
-
-const QuicStreamId kConnectionLevelId = 0;
-
-// QuicFlowController allows a QUIC stream or connection to perform flow
-// control. The stream/connection owns a QuicFlowController which keeps track of
-// bytes sent/received, can tell the owner if it is flow control blocked, and
-// can send WINDOW_UPDATE or BLOCKED frames when needed.
-class NET_EXPORT_PRIVATE QuicFlowController {
- public:
- QuicFlowController(QuicConnection* connection,
- QuicStreamId id,
- Perspective perspective,
- QuicStreamOffset send_window_offset,
- QuicStreamOffset receive_window_offset,
- bool should_auto_tune_receive_window);
-
- ~QuicFlowController() {}
-
- // Called when we see a new highest received byte offset from the peer, either
- // via a data frame or a RST.
- // Returns true if this call changes highest_received_byte_offset_, and false
- // in the case where |new_offset| is <= highest_received_byte_offset_.
- bool UpdateHighestReceivedOffset(QuicStreamOffset new_offset);
-
- // Called when bytes received from the peer are consumed locally. This may
- // trigger the sending of a WINDOW_UPDATE frame using |connection|.
- void AddBytesConsumed(QuicByteCount bytes_consumed);
-
- // Called when bytes are sent to the peer.
- void AddBytesSent(QuicByteCount bytes_sent);
-
- // Set a new send window offset.
- // Returns true if this increases send_window_offset_ and is now blocked.
- bool UpdateSendWindowOffset(QuicStreamOffset new_send_window_offset);
-
- // Returns the current available send window.
- QuicByteCount SendWindowSize() const;
-
- // Send a BLOCKED frame if appropriate.
- void MaybeSendBlocked();
-
- // Returns true if flow control send limits have been reached.
- bool IsBlocked() const;
-
- // Returns true if flow control receive limits have been violated by the peer.
- bool FlowControlViolation();
-
- QuicByteCount bytes_consumed() const { return bytes_consumed_; }
-
- QuicStreamOffset highest_received_byte_offset() const {
- return highest_received_byte_offset_;
- }
-
- void set_receive_window_size_limit(QuicByteCount receive_window_size_limit) {
- DCHECK_GE(receive_window_size_limit, receive_window_size_limit_);
- receive_window_size_limit_ = receive_window_size_limit;
- }
-
- void set_auto_tune_receive_window(bool enable) {
- auto_tune_receive_window_ = enable;
- }
-
- // Should only be called before any data is received.
- void UpdateReceiveWindowSize(QuicStreamOffset size);
-
- bool auto_tune_receive_window() { return auto_tune_receive_window_; }
-
- private:
- friend class test::QuicFlowControllerPeer;
-
- // Send a WINDOW_UPDATE frame if appropriate.
- void MaybeSendWindowUpdate();
-
- // Auto-tune the max receive window size.
- void MaybeIncreaseMaxWindowSize();
-
- // The parent connection, used to send connection close on flow control
- // violation, and WINDOW_UPDATE and BLOCKED frames when appropriate.
- // Not owned.
- QuicConnection* connection_;
-
- // ID of stream this flow controller belongs to. This can be 0 if this is a
- // connection level flow controller.
- QuicStreamId id_;
-
- // Tracks if this is owned by a server or a client.
- Perspective perspective_;
-
- // Tracks number of bytes sent to the peer.
- QuicByteCount bytes_sent_;
-
- // The absolute offset in the outgoing byte stream. If this offset is reached
- // then we become flow control blocked until we receive a WINDOW_UPDATE.
- QuicStreamOffset send_window_offset_;
-
- // Overview of receive flow controller.
- //
- // 0=...===1=======2-------3 ...... FIN
- // |<--- <= 4 --->|
- //
-
- // 1) bytes_consumed_ - moves forward when data is read out of the
- // stream.
- //
- // 2) highest_received_byte_offset_ - moves when data is received
- // from the peer.
- //
- // 3) receive_window_offset_ - moves when WINDOW_UPDATE is sent.
- //
- // 4) receive_window_size_ - maximum allowed unread data (3 - 1).
- // This value may be increased by auto-tuning.
- //
- // 5) receive_window_size_limit_ - limit on receive_window_size_;
- // auto-tuning will not increase window size beyond this limit.
-
- // Track number of bytes received from the peer, which have been consumed
- // locally.
- QuicByteCount bytes_consumed_;
-
- // The highest byte offset we have seen from the peer. This could be the
- // highest offset in a data frame, or a final value in a RST.
- QuicStreamOffset highest_received_byte_offset_;
-
- // The absolute offset in the incoming byte stream. The peer should never send
- // us bytes which are beyond this offset.
- QuicStreamOffset receive_window_offset_;
-
- // Largest size the receive window can grow to.
- QuicByteCount receive_window_size_;
-
- // Upper limit on receive_window_size_;
- QuicByteCount receive_window_size_limit_;
-
- // Used to dynamically enable receive window auto-tuning.
- bool auto_tune_receive_window_;
-
- // Send window update when receive window size drops below this.
- QuicByteCount WindowUpdateThreshold();
-
- // Keep track of the last time we sent a BLOCKED frame. We should only send
- // another when the number of bytes we have sent has changed.
- QuicStreamOffset last_blocked_send_window_offset_;
-
- // Keep time of the last time a window update was sent. We use this
- // as part of the receive window auto tuning.
- QuicTime prev_window_update_time_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicFlowController);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_FLOW_CONTROLLER_H_
diff --git a/chromium/net/quic/quic_flow_controller_test.cc b/chromium/net/quic/quic_flow_controller_test.cc
deleted file mode 100644
index fdc236a651b..00000000000
--- a/chromium/net/quic/quic_flow_controller_test.cc
+++ /dev/null
@@ -1,379 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_flow_controller.h"
-
-#include <memory>
-
-#include "base/format_macros.h"
-#include "base/strings/stringprintf.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/quic_connection_peer.h"
-#include "net/quic/test_tools/quic_flow_controller_peer.h"
-#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/test/gtest_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using testing::_;
-
-namespace net {
-namespace test {
-
-// Receive window auto-tuning uses RTT in its logic.
-const int64_t kRtt = 100;
-
-class QuicFlowControllerTest : public ::testing::Test {
- public:
- QuicFlowControllerTest()
- : stream_id_(1234),
- send_window_(kInitialSessionFlowControlWindowForTest),
- receive_window_(kInitialSessionFlowControlWindowForTest),
- connection_(&helper_, &alarm_factory_, Perspective::IS_CLIENT) {}
-
- void Initialize() {
- flow_controller_.reset(
- new QuicFlowController(&connection_, stream_id_, Perspective::IS_CLIENT,
- send_window_, receive_window_, false));
- }
-
- protected:
- QuicStreamId stream_id_;
- QuicByteCount send_window_;
- QuicByteCount receive_window_;
- std::unique_ptr<QuicFlowController> flow_controller_;
- MockQuicConnectionHelper helper_;
- MockAlarmFactory alarm_factory_;
- MockQuicConnection connection_;
-};
-
-TEST_F(QuicFlowControllerTest, SendingBytes) {
- Initialize();
-
- EXPECT_FALSE(flow_controller_->IsBlocked());
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(send_window_, flow_controller_->SendWindowSize());
-
- // Send some bytes, but not enough to block.
- flow_controller_->AddBytesSent(send_window_ / 2);
- EXPECT_FALSE(flow_controller_->IsBlocked());
- EXPECT_EQ(send_window_ / 2, flow_controller_->SendWindowSize());
-
- // Send enough bytes to block.
- flow_controller_->AddBytesSent(send_window_ / 2);
- EXPECT_TRUE(flow_controller_->IsBlocked());
- EXPECT_EQ(0u, flow_controller_->SendWindowSize());
-
- // BLOCKED frame should get sent.
- EXPECT_CALL(connection_, SendBlocked(stream_id_)).Times(1);
- flow_controller_->MaybeSendBlocked();
-
- // Update the send window, and verify this has unblocked.
- EXPECT_TRUE(flow_controller_->UpdateSendWindowOffset(2 * send_window_));
- EXPECT_FALSE(flow_controller_->IsBlocked());
- EXPECT_EQ(send_window_, flow_controller_->SendWindowSize());
-
- // Updating with a smaller offset doesn't change anything.
- EXPECT_FALSE(flow_controller_->UpdateSendWindowOffset(send_window_ / 10));
- EXPECT_EQ(send_window_, flow_controller_->SendWindowSize());
-
- // Try to send more bytes, violating flow control.
- EXPECT_CALL(connection_,
- CloseConnection(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA, _, _));
- EXPECT_DFATAL(flow_controller_->AddBytesSent(send_window_ * 10),
- base::StringPrintf("Trying to send an extra %" PRIu64 " bytes",
- send_window_ * 10));
- EXPECT_TRUE(flow_controller_->IsBlocked());
- EXPECT_EQ(0u, flow_controller_->SendWindowSize());
-}
-
-TEST_F(QuicFlowControllerTest, ReceivingBytes) {
- Initialize();
-
- EXPECT_FALSE(flow_controller_->IsBlocked());
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
- QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-
- // Receive some bytes, updating highest received offset, but not enough to
- // fill flow control receive window.
- EXPECT_TRUE(
- flow_controller_->UpdateHighestReceivedOffset(1 + receive_window_ / 2));
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ((receive_window_ / 2) - 1,
- QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-
- // Consume enough bytes to send a WINDOW_UPDATE frame.
- EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(1);
-
- flow_controller_->AddBytesConsumed(1 + receive_window_ / 2);
-
- // Result is that once again we have a fully open receive window.
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
- QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-}
-
-TEST_F(QuicFlowControllerTest, OnlySendBlockedFrameOncePerOffset) {
- Initialize();
-
- // Test that we don't send duplicate BLOCKED frames. We should only send one
- // BLOCKED frame at a given send window offset.
- EXPECT_FALSE(flow_controller_->IsBlocked());
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(send_window_, flow_controller_->SendWindowSize());
-
- // Send enough bytes to block.
- flow_controller_->AddBytesSent(send_window_);
- EXPECT_TRUE(flow_controller_->IsBlocked());
- EXPECT_EQ(0u, flow_controller_->SendWindowSize());
-
- // Expect that 2 BLOCKED frames should get sent in total.
- EXPECT_CALL(connection_, SendBlocked(stream_id_)).Times(2);
-
- // BLOCKED frame should get sent.
- flow_controller_->MaybeSendBlocked();
-
- // BLOCKED frame should not get sent again until our send offset changes.
- flow_controller_->MaybeSendBlocked();
- flow_controller_->MaybeSendBlocked();
- flow_controller_->MaybeSendBlocked();
- flow_controller_->MaybeSendBlocked();
- flow_controller_->MaybeSendBlocked();
-
- // Update the send window, then send enough bytes to block again.
- EXPECT_TRUE(flow_controller_->UpdateSendWindowOffset(2 * send_window_));
- EXPECT_FALSE(flow_controller_->IsBlocked());
- EXPECT_EQ(send_window_, flow_controller_->SendWindowSize());
- flow_controller_->AddBytesSent(send_window_);
- EXPECT_TRUE(flow_controller_->IsBlocked());
- EXPECT_EQ(0u, flow_controller_->SendWindowSize());
-
- // BLOCKED frame should get sent as send offset has changed.
- flow_controller_->MaybeSendBlocked();
-}
-
-TEST_F(QuicFlowControllerTest, ReceivingBytesFastIncreasesFlowWindow) {
- FLAGS_quic_auto_tune_receive_window = true;
- // This test will generate two WINDOW_UPDATE frames.
- EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
-
- Initialize();
- flow_controller_->set_auto_tune_receive_window(true);
-
- // Make sure clock is inititialized.
- connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
-
- QuicSentPacketManagerInterface* manager =
- QuicConnectionPeer::GetSentPacketManager(&connection_);
-
- RttStats* rtt_stats = const_cast<RttStats*>(manager->GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
- QuicTime::Delta::Zero(), QuicTime::Zero());
-
- EXPECT_FALSE(flow_controller_->IsBlocked());
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
- QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-
- QuicByteCount threshold =
- QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
-
- QuicStreamOffset receive_offset = threshold + 1;
- // Receive some bytes, updating highest received offset, but not enough to
- // fill flow control receive window.
- EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
- QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-
- // Consume enough bytes to send a WINDOW_UPDATE frame.
- flow_controller_->AddBytesConsumed(threshold + 1);
- // Result is that once again we have a fully open receive window.
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
- QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-
- // Move time forward, but by less than two RTTs. Then receive and consume
- // some more, forcing a second WINDOW_UPDATE with an increased max window
- // size.
- connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt - 1));
- receive_offset += threshold + 1;
- EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
- flow_controller_->AddBytesConsumed(threshold + 1);
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- QuicByteCount new_threshold =
- QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
- EXPECT_GT(new_threshold, threshold);
-}
-
-TEST_F(QuicFlowControllerTest, ReceivingBytesFastStatusQuo) {
- FLAGS_quic_auto_tune_receive_window = false;
- // This test will generate two WINDOW_UPDATE frames.
- EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
-
- Initialize();
- flow_controller_->set_auto_tune_receive_window(true);
-
- // Make sure clock is inititialized.
- connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
-
- QuicSentPacketManagerInterface* manager =
- QuicConnectionPeer::GetSentPacketManager(&connection_);
-
- RttStats* rtt_stats = const_cast<RttStats*>(manager->GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
- QuicTime::Delta::Zero(), QuicTime::Zero());
-
- EXPECT_FALSE(flow_controller_->IsBlocked());
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
- QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-
- QuicByteCount threshold =
- QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
-
- QuicStreamOffset receive_offset = threshold + 1;
- // Receive some bytes, updating highest received offset, but not enough to
- // fill flow control receive window.
- EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
- QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-
- // Consume enough bytes to send a WINDOW_UPDATE frame.
- flow_controller_->AddBytesConsumed(threshold + 1);
- // Result is that once again we have a fully open receive window.
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
- QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-
- // Move time forward, but by less than two RTTs. Then receive and consume
- // some more, forcing a second WINDOW_UPDATE with an increased max window
- // size.
- connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt - 1));
- receive_offset += threshold + 1;
- EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
- flow_controller_->AddBytesConsumed(threshold + 1);
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- QuicByteCount new_threshold =
- QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
- EXPECT_EQ(new_threshold, threshold);
-}
-
-TEST_F(QuicFlowControllerTest, ReceivingBytesNormalStableFlowWindow) {
- FLAGS_quic_auto_tune_receive_window = true;
- // This test will generate two WINDOW_UPDATE frames.
- EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
-
- Initialize();
- flow_controller_->set_auto_tune_receive_window(true);
-
- // Make sure clock is inititialized.
- connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
-
- QuicSentPacketManagerInterface* manager =
- QuicConnectionPeer::GetSentPacketManager(&connection_);
- RttStats* rtt_stats = const_cast<RttStats*>(manager->GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
- QuicTime::Delta::Zero(), QuicTime::Zero());
-
- EXPECT_FALSE(flow_controller_->IsBlocked());
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
- QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-
- QuicByteCount threshold =
- QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
-
- QuicStreamOffset receive_offset = threshold + 1;
- // Receive some bytes, updating highest received offset, but not enough to
- // fill flow control receive window.
- EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
- QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-
- flow_controller_->AddBytesConsumed(threshold + 1);
-
- // Result is that once again we have a fully open receive window.
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
- QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-
- // Move time forward, but by more than two RTTs. Then receive and consume
- // some more, forcing a second WINDOW_UPDATE with unchanged max window size.
- connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt + 1));
-
- receive_offset += threshold + 1;
- EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
-
- flow_controller_->AddBytesConsumed(threshold + 1);
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
-
- QuicByteCount new_threshold =
- QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
-
- EXPECT_EQ(new_threshold, threshold);
-}
-
-TEST_F(QuicFlowControllerTest, ReceivingBytesNormalStatusQuo) {
- FLAGS_quic_auto_tune_receive_window = false;
- // This test will generate two WINDOW_UPDATE frames.
- EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
-
- Initialize();
- flow_controller_->set_auto_tune_receive_window(true);
-
- // Make sure clock is inititialized.
- connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
-
- QuicSentPacketManagerInterface* manager =
- QuicConnectionPeer::GetSentPacketManager(&connection_);
- RttStats* rtt_stats = const_cast<RttStats*>(manager->GetRttStats());
- rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
- QuicTime::Delta::Zero(), QuicTime::Zero());
-
- EXPECT_FALSE(flow_controller_->IsBlocked());
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
- QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-
- QuicByteCount threshold =
- QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
-
- QuicStreamOffset receive_offset = threshold + 1;
- // Receive some bytes, updating highest received offset, but not enough to
- // fill flow control receive window.
- EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
- QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-
- flow_controller_->AddBytesConsumed(threshold + 1);
-
- // Result is that once again we have a fully open receive window.
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
- EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
- QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
-
- // Move time forward, but by more than two RTTs. Then receive and consume
- // some more, forcing a second WINDOW_UPDATE with unchanged max window size.
- connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt + 1));
-
- receive_offset += threshold + 1;
- EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
-
- flow_controller_->AddBytesConsumed(threshold + 1);
- EXPECT_FALSE(flow_controller_->FlowControlViolation());
-
- QuicByteCount new_threshold =
- QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
-
- EXPECT_EQ(new_threshold, threshold);
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_frame_list.cc b/chromium/net/quic/quic_frame_list.cc
deleted file mode 100644
index 92670746aeb..00000000000
--- a/chromium/net/quic/quic_frame_list.cc
+++ /dev/null
@@ -1,254 +0,0 @@
-// 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.
-
-#include "net/quic/quic_frame_list.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-
-using std::list;
-using std::string;
-
-namespace net {
-
-QuicFrameList::FrameData::FrameData(QuicStreamOffset offset,
- string segment,
- const QuicTime timestamp)
- : offset(offset), segment(segment), timestamp(timestamp) {}
-
-QuicFrameList::QuicFrameList() {}
-
-QuicFrameList::~QuicFrameList() {
- Clear();
-}
-
-void QuicFrameList::Clear() {
- frame_list_.clear();
- num_bytes_buffered_ = 0;
-}
-
-bool QuicFrameList::Empty() const {
- return frame_list_.empty();
-}
-
-QuicErrorCode QuicFrameList::OnStreamData(QuicStreamOffset offset,
- base::StringPiece data,
- QuicTime timestamp,
- size_t* const bytes_buffered) {
- *bytes_buffered = 0;
- const size_t data_len = data.size();
- auto insertion_point = FindInsertionPoint(offset, data_len);
- if (IsDuplicate(offset, data_len, insertion_point)) {
- return QUIC_NO_ERROR;
- }
-
- if (FrameOverlapsBufferedData(offset, data_len, insertion_point)) {
- return QUIC_INVALID_STREAM_DATA;
- }
-
- DVLOG(1) << "Buffering stream data at offset " << offset;
- // Inserting an empty string and then copying to avoid the extra copy.
- insertion_point =
- frame_list_.insert(insertion_point, FrameData(offset, "", timestamp));
- data.CopyToString(&insertion_point->segment);
- *bytes_buffered = data_len;
- num_bytes_buffered_ += data_len;
- return QUIC_NO_ERROR;
-}
-
-// Finds the place the frame should be inserted. If an identical frame is
-// present, stops on the identical frame.
-list<QuicFrameList::FrameData>::iterator QuicFrameList::FindInsertionPoint(
- QuicStreamOffset offset,
- size_t len) {
- if (frame_list_.empty()) {
- return frame_list_.begin();
- }
- // If it's after all buffered_frames, return the end.
- if (offset >=
- (frame_list_.rbegin()->offset + frame_list_.rbegin()->segment.length())) {
- return frame_list_.end();
- }
- auto iter = frame_list_.begin();
- // Only advance the iterator if the data begins after the already received
- // frame. If the new frame overlaps with an existing frame, the iterator will
- // still point to the frame it overlaps with.
- while (iter != frame_list_.end() &&
- offset >= iter->offset + iter->segment.length()) {
- ++iter;
- }
- return iter;
-}
-
-// Returns true if |frame| contains data which overlaps buffered data
-// (indicating an invalid stream frame has been received).
-bool QuicFrameList::FrameOverlapsBufferedData(
- QuicStreamOffset offset,
- size_t data_len,
- list<FrameData>::const_iterator insertion_point) const {
- if (frame_list_.empty() || insertion_point == frame_list_.end()) {
- return false;
- }
- // If there is a buffered frame with a higher starting offset, then check to
- // see if the new frame overlaps the beginning of the higher frame.
- if (offset < insertion_point->offset &&
- offset + data_len > insertion_point->offset) {
- DVLOG(1) << "New frame overlaps next frame: " << offset << " + " << data_len
- << " > " << insertion_point->offset;
- return true;
- }
- // If there is a buffered frame with a lower starting offset, then check to
- // see if the buffered frame runs into the new frame.
- if (offset >= insertion_point->offset &&
- offset < insertion_point->offset + insertion_point->segment.length()) {
- DVLOG(1) << "Preceeding frame overlaps new frame: "
- << insertion_point->offset << " + "
- << insertion_point->segment.length() << " > " << offset;
- return true;
- }
-
- return false;
-}
-
-// Returns true if the sequencer has received this frame before.
-bool QuicFrameList::IsDuplicate(
- QuicStreamOffset offset,
- size_t data_len,
- list<FrameData>::const_iterator insertion_point) const {
- // A frame is duplicate if the frame offset is smaller than the bytes consumed
- // or identical to an already received frame.
- return offset < total_bytes_read_ || (insertion_point != frame_list_.end() &&
- offset == insertion_point->offset);
-}
-
-int QuicFrameList::GetReadableRegions(struct iovec* iov, int iov_len) const {
- list<FrameData>::const_iterator it = frame_list_.begin();
- int index = 0;
- QuicStreamOffset offset = total_bytes_read_;
- while (it != frame_list_.end() && index < iov_len) {
- if (it->offset != offset) {
- return index;
- }
-
- iov[index].iov_base =
- static_cast<void*>(const_cast<char*>(it->segment.data()));
- iov[index].iov_len = it->segment.size();
- offset += it->segment.size();
-
- ++index;
- ++it;
- }
- return index;
-}
-
-bool QuicFrameList::GetReadableRegion(iovec* iov, QuicTime* timestamp) const {
- list<FrameData>::const_iterator it = frame_list_.begin();
- if (it == frame_list_.end() || it->offset != total_bytes_read_) {
- return false;
- }
- iov->iov_base = static_cast<void*>(const_cast<char*>(it->segment.data()));
- iov->iov_len = it->segment.size();
- *timestamp = it->timestamp;
- return true;
-}
-
-bool QuicFrameList::MarkConsumed(size_t bytes_used) {
- size_t end_offset = total_bytes_read_ + bytes_used;
- while (!frame_list_.empty() && end_offset != total_bytes_read_) {
- list<FrameData>::iterator it = frame_list_.begin();
- if (it->offset != total_bytes_read_) {
- return false;
- }
-
- if (it->offset + it->segment.length() <= end_offset) {
- total_bytes_read_ += it->segment.length();
- num_bytes_buffered_ -= it->segment.length();
- // This chunk is entirely consumed.
- frame_list_.erase(it);
- continue;
- }
-
- // Partially consume this frame.
- size_t delta = end_offset - it->offset;
- total_bytes_read_ += delta;
- num_bytes_buffered_ -= delta;
- string new_data = it->segment.substr(delta);
- const QuicTime timestamp = it->timestamp;
- frame_list_.erase(it);
- frame_list_.push_front(FrameData(total_bytes_read_, new_data, timestamp));
- break;
- }
- return true;
-}
-
-size_t QuicFrameList::Readv(const struct iovec* iov, size_t iov_len) {
- list<FrameData>::iterator it = frame_list_.begin();
- size_t iov_index = 0;
- size_t iov_offset = 0;
- size_t frame_offset = 0;
- QuicStreamOffset initial_bytes_consumed = total_bytes_read_;
-
- while (iov_index < iov_len && it != frame_list_.end() &&
- it->offset == total_bytes_read_) {
- int bytes_to_read = std::min(iov[iov_index].iov_len - iov_offset,
- it->segment.size() - frame_offset);
-
- char* iov_ptr = static_cast<char*>(iov[iov_index].iov_base) + iov_offset;
- memcpy(iov_ptr, it->segment.data() + frame_offset, bytes_to_read);
- frame_offset += bytes_to_read;
- iov_offset += bytes_to_read;
-
- if (iov[iov_index].iov_len == iov_offset) {
- // We've filled this buffer.
- iov_offset = 0;
- ++iov_index;
- }
- if (it->segment.size() == frame_offset) {
- // We've copied this whole frame
- total_bytes_read_ += it->segment.size();
- num_bytes_buffered_ -= it->segment.size();
- frame_list_.erase(it);
- it = frame_list_.begin();
- frame_offset = 0;
- }
- }
- // Done copying. If there is a partial frame, update it.
- if (frame_offset != 0) {
- frame_list_.push_front(FrameData(it->offset + frame_offset,
- it->segment.substr(frame_offset),
- it->timestamp));
- frame_list_.erase(it);
- total_bytes_read_ += frame_offset;
- num_bytes_buffered_ -= frame_offset;
- }
- return total_bytes_read_ - initial_bytes_consumed;
-}
-
-size_t QuicFrameList::FlushBufferedFrames() {
- QuicStreamOffset initial_bytes_consumed = total_bytes_read_;
- if (!frame_list_.empty()) {
- // Consume all of the bytes up to the last byte yet seen, including the
- // ones that haven't arrived yet.
- auto it = frame_list_.back();
- total_bytes_read_ = it.offset + it.segment.length();
- frame_list_.clear();
- }
- return total_bytes_read_ - initial_bytes_consumed;
-}
-
-bool QuicFrameList::HasBytesToRead() const {
- return !frame_list_.empty() &&
- frame_list_.begin()->offset == total_bytes_read_;
-}
-
-QuicStreamOffset QuicFrameList::BytesConsumed() const {
- return total_bytes_read_;
-}
-
-size_t QuicFrameList::BytesBuffered() const {
- return num_bytes_buffered_;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_frame_list.h b/chromium/net/quic/quic_frame_list.h
deleted file mode 100644
index f529016f66a..00000000000
--- a/chromium/net/quic/quic_frame_list.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// 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.
-
-#ifndef NET_QUIC_QUIC_FRAME_LIST_H_
-#define NET_QUIC_QUIC_FRAME_LIST_H_
-
-#include <stddef.h>
-#include <list>
-#include <string>
-
-#include "base/strings/string_piece.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_stream_sequencer_buffer_interface.h"
-
-namespace net {
-
-namespace test {
-class QuicStreamSequencerPeer;
-}
-
-class NET_EXPORT_PRIVATE QuicFrameList
- : public QuicStreamSequencerBufferInterface {
- public:
- // A contiguous segment received by a QUIC stream.
- struct FrameData {
- FrameData(QuicStreamOffset offset,
- std::string segment,
- const QuicTime timestamp);
-
- const QuicStreamOffset offset;
- std::string segment;
- const QuicTime timestamp;
- };
-
- QuicFrameList();
-
- ~QuicFrameList() override;
-
- // QuicStreamSequencerBufferInterface implementation
- void Clear() override;
- bool Empty() const override;
- QuicErrorCode OnStreamData(QuicStreamOffset offset,
- base::StringPiece data,
- QuicTime timestamp,
- size_t* bytes_buffered) override;
- size_t Readv(const struct iovec* iov, size_t iov_len) override;
- int GetReadableRegions(struct iovec* iov, int iov_len) const override;
- bool GetReadableRegion(iovec* iov, QuicTime* timestamp) const override;
- bool MarkConsumed(size_t bytes_used) override;
- size_t FlushBufferedFrames() override;
- bool HasBytesToRead() const override;
- QuicStreamOffset BytesConsumed() const override;
- size_t BytesBuffered() const override;
-
- private:
- friend class test::QuicStreamSequencerPeer;
-
- std::list<FrameData>::iterator FindInsertionPoint(QuicStreamOffset offset,
- size_t len);
-
- bool FrameOverlapsBufferedData(
- QuicStreamOffset offset,
- size_t data_len,
- std::list<FrameData>::const_iterator insertion_point) const;
-
- bool IsDuplicate(QuicStreamOffset offset,
- size_t data_len,
- std::list<FrameData>::const_iterator insertion_point) const;
-
- std::list<FrameData> frame_list_;
-
- // Number of bytes in buffer.
- size_t num_bytes_buffered_ = 0;
-
- QuicStreamOffset total_bytes_read_ = 0;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_FRAME_LIST_H_
diff --git a/chromium/net/quic/quic_framer.cc b/chromium/net/quic/quic_framer.cc
deleted file mode 100644
index 889e0705f18..00000000000
--- a/chromium/net/quic/quic_framer.cc
+++ /dev/null
@@ -1,2600 +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/quic_framer.h"
-
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "net/quic/crypto/crypto_framer.h"
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_data_reader.h"
-#include "net/quic/quic_data_writer.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_socket_address_coder.h"
-#include "net/quic/quic_utils.h"
-
-using base::StringPiece;
-using std::map;
-using std::max;
-using std::min;
-using std::numeric_limits;
-using std::string;
-
-namespace net {
-
-namespace {
-
-// Mask to select the lowest 48 bits of a packet number.
-const QuicPacketNumber k6ByteSequenceNumberMask = UINT64_C(0x0000FFFFFFFFFFFF);
-const QuicPacketNumber k4ByteSequenceNumberMask = UINT64_C(0x00000000FFFFFFFF);
-const QuicPacketNumber k2ByteSequenceNumberMask = UINT64_C(0x000000000000FFFF);
-const QuicPacketNumber k1ByteSequenceNumberMask = UINT64_C(0x00000000000000FF);
-
-// Number of bits the packet number length bits are shifted from the right
-// edge of the public header.
-const uint8_t kPublicHeaderSequenceNumberShift = 4;
-
-// New Frame Types, QUIC v. >= 10:
-// There are two interpretations for the Frame Type byte in the QUIC protocol,
-// resulting in two Frame Types: Special Frame Types and Regular Frame Types.
-//
-// Regular Frame Types use the Frame Type byte simply. Currently defined
-// Regular Frame Types are:
-// Padding : 0b 00000000 (0x00)
-// ResetStream : 0b 00000001 (0x01)
-// ConnectionClose : 0b 00000010 (0x02)
-// GoAway : 0b 00000011 (0x03)
-// WindowUpdate : 0b 00000100 (0x04)
-// Blocked : 0b 00000101 (0x05)
-//
-// Special Frame Types encode both a Frame Type and corresponding flags
-// all in the Frame Type byte. Currently defined Special Frame Types are:
-// Stream : 0b 1xxxxxxx
-// Ack : 0b 01xxxxxx
-//
-// Semantics of the flag bits above (the x bits) depends on the frame type.
-
-// Masks to determine if the frame type is a special use
-// and for specific special frame types.
-const uint8_t kQuicFrameTypeSpecialMask = 0xE0; // 0b 11100000
-const uint8_t kQuicFrameTypeStreamMask = 0x80;
-const uint8_t kQuicFrameTypeAckMask = 0x40;
-
-// Stream frame relative shifts and masks for interpreting the stream flags.
-// StreamID may be 1, 2, 3, or 4 bytes.
-const uint8_t kQuicStreamIdShift = 2;
-const uint8_t kQuicStreamIDLengthMask = 0x03;
-
-// Offset may be 0, 2, 3, 4, 5, 6, 7, 8 bytes.
-const uint8_t kQuicStreamOffsetShift = 3;
-const uint8_t kQuicStreamOffsetMask = 0x07;
-
-// Data length may be 0 or 2 bytes.
-const uint8_t kQuicStreamDataLengthShift = 1;
-const uint8_t kQuicStreamDataLengthMask = 0x01;
-
-// Fin bit may be set or not.
-const uint8_t kQuicStreamFinShift = 1;
-const uint8_t kQuicStreamFinMask = 0x01;
-
-// packet number size shift used in AckFrames.
-const uint8_t kQuicSequenceNumberLengthShift = 2;
-
-// Acks may be truncated.
-const uint8_t kQuicAckTruncatedShift = 1;
-const uint8_t kQuicAckTruncatedMask = 0x01;
-
-// Acks may not have any nacks.
-const uint8_t kQuicHasNacksMask = 0x01;
-// Acks may have only one ack block.
-const uint8_t kQuicHasMultipleAckBlocksMask = 0x01;
-const uint8_t kQuicHasMultipleAckBlocksShift = 1;
-
-// Returns the absolute value of the difference between |a| and |b|.
-QuicPacketNumber Delta(QuicPacketNumber a, QuicPacketNumber b) {
- // Since these are unsigned numbers, we can't just return abs(a - b)
- if (a < b) {
- return b - a;
- }
- return a - b;
-}
-
-QuicPacketNumber ClosestTo(QuicPacketNumber target,
- QuicPacketNumber a,
- QuicPacketNumber b) {
- return (Delta(target, a) < Delta(target, b)) ? a : b;
-}
-
-QuicPacketNumberLength ReadSequenceNumberLength(uint8_t flags) {
- switch (flags & PACKET_FLAGS_6BYTE_PACKET) {
- case PACKET_FLAGS_6BYTE_PACKET:
- return PACKET_6BYTE_PACKET_NUMBER;
- case PACKET_FLAGS_4BYTE_PACKET:
- return PACKET_4BYTE_PACKET_NUMBER;
- case PACKET_FLAGS_2BYTE_PACKET:
- return PACKET_2BYTE_PACKET_NUMBER;
- case PACKET_FLAGS_1BYTE_PACKET:
- return PACKET_1BYTE_PACKET_NUMBER;
- default:
- QUIC_BUG << "Unreachable case statement.";
- return PACKET_6BYTE_PACKET_NUMBER;
- }
-}
-
-} // namespace
-
-QuicFramer::QuicFramer(const QuicVersionVector& supported_versions,
- QuicTime creation_time,
- Perspective perspective)
- : visitor_(nullptr),
- entropy_calculator_(nullptr),
- error_(QUIC_NO_ERROR),
- last_packet_number_(0),
- last_path_id_(kInvalidPathId),
- last_serialized_connection_id_(0),
- supported_versions_(supported_versions),
- decrypter_level_(ENCRYPTION_NONE),
- alternative_decrypter_level_(ENCRYPTION_NONE),
- alternative_decrypter_latch_(false),
- perspective_(perspective),
- validate_flags_(true),
- creation_time_(creation_time),
- last_timestamp_(QuicTime::Delta::Zero()) {
- DCHECK(!supported_versions.empty());
- quic_version_ = supported_versions_[0];
- decrypter_.reset(QuicDecrypter::Create(kNULL));
- encrypter_[ENCRYPTION_NONE].reset(QuicEncrypter::Create(kNULL));
-}
-
-QuicFramer::~QuicFramer() {}
-
-// static
-size_t QuicFramer::GetMinStreamFrameSize(QuicStreamId stream_id,
- QuicStreamOffset offset,
- bool last_frame_in_packet) {
- return kQuicFrameTypeSize + GetStreamIdSize(stream_id) +
- GetStreamOffsetSize(offset) +
- (last_frame_in_packet ? 0 : kQuicStreamPayloadLengthSize);
-}
-
-// static
-size_t QuicFramer::GetMinAckFrameSize(
- QuicVersion version,
- QuicPacketNumberLength largest_observed_length) {
- size_t min_size = kQuicFrameTypeSize + largest_observed_length +
- kQuicDeltaTimeLargestObservedSize;
- if (version <= QUIC_VERSION_33) {
- return min_size + kQuicEntropyHashSize;
- }
- return min_size + kQuicNumTimestampsSize;
-}
-
-// static
-size_t QuicFramer::GetStopWaitingFrameSize(
- QuicVersion version,
- QuicPacketNumberLength packet_number_length) {
- size_t min_size = kQuicFrameTypeSize + packet_number_length;
- if (version <= QUIC_VERSION_33) {
- return min_size + kQuicEntropyHashSize;
- }
- return min_size;
-}
-
-// static
-size_t QuicFramer::GetRstStreamFrameSize() {
- return kQuicFrameTypeSize + kQuicMaxStreamIdSize + kQuicMaxStreamOffsetSize +
- kQuicErrorCodeSize;
-}
-
-// static
-size_t QuicFramer::GetMinConnectionCloseFrameSize() {
- return kQuicFrameTypeSize + kQuicErrorCodeSize + kQuicErrorDetailsLengthSize;
-}
-
-// static
-size_t QuicFramer::GetMinGoAwayFrameSize() {
- return kQuicFrameTypeSize + kQuicErrorCodeSize + kQuicErrorDetailsLengthSize +
- kQuicMaxStreamIdSize;
-}
-
-// static
-size_t QuicFramer::GetWindowUpdateFrameSize() {
- return kQuicFrameTypeSize + kQuicMaxStreamIdSize + kQuicMaxStreamOffsetSize;
-}
-
-// static
-size_t QuicFramer::GetBlockedFrameSize() {
- return kQuicFrameTypeSize + kQuicMaxStreamIdSize;
-}
-
-// static
-size_t QuicFramer::GetPathCloseFrameSize() {
- return kQuicFrameTypeSize + kQuicPathIdSize;
-}
-
-// static
-size_t QuicFramer::GetStreamIdSize(QuicStreamId stream_id) {
- // Sizes are 1 through 4 bytes.
- for (int i = 1; i <= 4; ++i) {
- stream_id >>= 8;
- if (stream_id == 0) {
- return i;
- }
- }
- QUIC_BUG << "Failed to determine StreamIDSize.";
- return 4;
-}
-
-// static
-size_t QuicFramer::GetStreamOffsetSize(QuicStreamOffset offset) {
- // 0 is a special case.
- if (offset == 0) {
- return 0;
- }
- // 2 through 8 are the remaining sizes.
- offset >>= 8;
- for (int i = 2; i <= 8; ++i) {
- offset >>= 8;
- if (offset == 0) {
- return i;
- }
- }
- QUIC_BUG << "Failed to determine StreamOffsetSize.";
- return 8;
-}
-
-// static
-size_t QuicFramer::GetVersionNegotiationPacketSize(size_t number_versions) {
- return kPublicFlagsSize + PACKET_8BYTE_CONNECTION_ID +
- number_versions * kQuicVersionSize;
-}
-
-bool QuicFramer::IsSupportedVersion(const QuicVersion version) const {
- for (size_t i = 0; i < supported_versions_.size(); ++i) {
- if (version == supported_versions_[i]) {
- return true;
- }
- }
- return false;
-}
-
-size_t QuicFramer::GetSerializedFrameLength(
- const QuicFrame& frame,
- size_t free_bytes,
- bool first_frame,
- bool last_frame,
- QuicPacketNumberLength packet_number_length) {
- // Prevent a rare crash reported in b/19458523.
- if ((frame.type == STREAM_FRAME || frame.type == ACK_FRAME) &&
- frame.stream_frame == nullptr) {
- QUIC_BUG << "Cannot compute the length of a null frame. "
- << "type:" << frame.type << "free_bytes:" << free_bytes
- << " first_frame:" << first_frame << " last_frame:" << last_frame
- << " seq num length:" << packet_number_length;
- set_error(QUIC_INTERNAL_ERROR);
- visitor_->OnError(this);
- return 0;
- }
- if (frame.type == PADDING_FRAME) {
- if (frame.padding_frame.num_padding_bytes == -1) {
- // Full padding to the end of the packet.
- return free_bytes;
- } else {
- // Lite padding.
- return free_bytes <
- static_cast<size_t>(frame.padding_frame.num_padding_bytes)
- ? free_bytes
- : frame.padding_frame.num_padding_bytes;
- }
- }
-
- size_t frame_len =
- ComputeFrameLength(frame, last_frame, packet_number_length);
- if (frame_len <= free_bytes) {
- // Frame fits within packet. Note that acks may be truncated.
- return frame_len;
- }
- // Only truncate the first frame in a packet, so if subsequent ones go
- // over, stop including more frames.
- if (!first_frame) {
- return 0;
- }
- bool can_truncate =
- frame.type == ACK_FRAME &&
- free_bytes >=
- GetMinAckFrameSize(quic_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.
- DVLOG(1) << "Truncating large frame, free bytes: " << free_bytes;
- return free_bytes;
- }
- return 0;
-}
-
-QuicFramer::AckFrameInfo::AckFrameInfo() : max_delta(0) {}
-
-QuicFramer::AckFrameInfo::AckFrameInfo(const AckFrameInfo& other) = default;
-
-QuicFramer::AckFrameInfo::~AckFrameInfo() {}
-
-QuicFramer::AckBlock::AckBlock(uint8_t gap, QuicPacketNumber length)
- : gap(gap), length(length) {}
-
-QuicFramer::AckBlock::AckBlock(const AckBlock& other) = default;
-
-QuicFramer::AckBlock::~AckBlock() {}
-
-QuicFramer::NewAckFrameInfo::NewAckFrameInfo()
- : max_block_length(0), first_block_length(0) {}
-
-QuicFramer::NewAckFrameInfo::NewAckFrameInfo(const NewAckFrameInfo& other) =
- default;
-
-QuicFramer::NewAckFrameInfo::~NewAckFrameInfo() {}
-
-// static
-QuicPacketEntropyHash QuicFramer::GetPacketEntropyHash(
- const QuicPacketHeader& header) {
- return header.entropy_flag << (header.packet_number % 8);
-}
-
-size_t QuicFramer::BuildDataPacket(const QuicPacketHeader& header,
- const QuicFrames& frames,
- char* buffer,
- size_t packet_length) {
- QuicDataWriter writer(packet_length, buffer);
- if (!AppendPacketHeader(header, &writer)) {
- QUIC_BUG << "AppendPacketHeader failed";
- return 0;
- }
-
- size_t i = 0;
- for (const QuicFrame& frame : frames) {
- // Determine if we should write stream frame length in header.
- const bool no_stream_frame_length = i == frames.size() - 1;
- if (!AppendTypeByte(frame, no_stream_frame_length, &writer)) {
- QUIC_BUG << "AppendTypeByte failed";
- return 0;
- }
-
- switch (frame.type) {
- case PADDING_FRAME:
- writer.WritePadding();
- break;
- case STREAM_FRAME:
- if (!AppendStreamFrame(*frame.stream_frame, no_stream_frame_length,
- &writer)) {
- QUIC_BUG << "AppendStreamFrame failed";
- return 0;
- }
- break;
- case ACK_FRAME:
- if (quic_version_ <= QUIC_VERSION_33) {
- if (!AppendAckFrameAndTypeByte(header, *frame.ack_frame, &writer)) {
- QUIC_BUG << "AppendAckFrameAndTypeByte failed"
- << " header: " << header
- << " ack_fame: " << *frame.ack_frame;
- return 0;
- }
- } else {
- if (!AppendNewAckFrameAndTypeByte(*frame.ack_frame, &writer)) {
- QUIC_BUG << "AppendNewAckFrameAndTypeByte failed";
- return 0;
- }
- }
- break;
- case STOP_WAITING_FRAME:
- if (!AppendStopWaitingFrame(header, *frame.stop_waiting_frame,
- &writer)) {
- QUIC_BUG << "AppendStopWaitingFrame failed";
- return 0;
- }
- break;
- case MTU_DISCOVERY_FRAME:
- // MTU discovery frames are serialized as ping frames.
- case PING_FRAME:
- // Ping has no payload.
- break;
- case RST_STREAM_FRAME:
- if (!AppendRstStreamFrame(*frame.rst_stream_frame, &writer)) {
- QUIC_BUG << "AppendRstStreamFrame failed";
- return 0;
- }
- break;
- case CONNECTION_CLOSE_FRAME:
- if (!AppendConnectionCloseFrame(*frame.connection_close_frame,
- &writer)) {
- QUIC_BUG << "AppendConnectionCloseFrame failed";
- return 0;
- }
- break;
- case GOAWAY_FRAME:
- if (!AppendGoAwayFrame(*frame.goaway_frame, &writer)) {
- QUIC_BUG << "AppendGoAwayFrame failed";
- return 0;
- }
- break;
- case WINDOW_UPDATE_FRAME:
- if (!AppendWindowUpdateFrame(*frame.window_update_frame, &writer)) {
- QUIC_BUG << "AppendWindowUpdateFrame failed";
- return 0;
- }
- break;
- case BLOCKED_FRAME:
- if (!AppendBlockedFrame(*frame.blocked_frame, &writer)) {
- QUIC_BUG << "AppendBlockedFrame failed";
- return 0;
- }
- break;
- case PATH_CLOSE_FRAME:
- if (!AppendPathCloseFrame(*frame.path_close_frame, &writer)) {
- QUIC_BUG << "AppendPathCloseFrame failed";
- return 0;
- }
- break;
- default:
- RaiseError(QUIC_INVALID_FRAME_DATA);
- QUIC_BUG << "QUIC_INVALID_FRAME_DATA";
- return 0;
- }
- ++i;
- }
-
- return writer.length();
-}
-
-// static
-QuicEncryptedPacket* QuicFramer::BuildPublicResetPacket(
- const QuicPublicResetPacket& packet) {
- DCHECK(packet.public_header.reset_flag);
-
- CryptoHandshakeMessage reset;
- reset.set_tag(kPRST);
- reset.SetValue(kRNON, packet.nonce_proof);
- reset.SetValue(kRSEQ, packet.rejected_packet_number);
- if (!packet.client_address.address().empty()) {
- // packet.client_address is non-empty.
- QuicSocketAddressCoder address_coder(packet.client_address);
- string serialized_address = address_coder.Encode();
- if (serialized_address.empty()) {
- return nullptr;
- }
- reset.SetStringPiece(kCADR, serialized_address);
- }
- const QuicData& reset_serialized = reset.GetSerialized();
-
- size_t len =
- kPublicFlagsSize + PACKET_8BYTE_CONNECTION_ID + reset_serialized.length();
- std::unique_ptr<char[]> buffer(new char[len]);
- QuicDataWriter writer(len, buffer.get());
-
- uint8_t flags = static_cast<uint8_t>(PACKET_PUBLIC_FLAGS_RST |
- PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID);
- if (FLAGS_quic_use_old_public_reset_packets) {
- // TODO(rch): Remove this QUIC_VERSION_32 is retired.
- flags |= static_cast<uint8_t>(PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD);
- }
- if (!writer.WriteUInt8(flags)) {
- return nullptr;
- }
-
- if (!writer.WriteUInt64(packet.public_header.connection_id)) {
- return nullptr;
- }
-
- if (!writer.WriteBytes(reset_serialized.data(), reset_serialized.length())) {
- return nullptr;
- }
-
- return new QuicEncryptedPacket(buffer.release(), len, true);
-}
-
-// static
-QuicEncryptedPacket* QuicFramer::BuildVersionNegotiationPacket(
- QuicConnectionId connection_id,
- const QuicVersionVector& versions) {
- DCHECK(!versions.empty());
- size_t len = GetVersionNegotiationPacketSize(versions.size());
- std::unique_ptr<char[]> buffer(new char[len]);
- QuicDataWriter writer(len, buffer.get());
-
- uint8_t flags = static_cast<uint8_t>(
- PACKET_PUBLIC_FLAGS_VERSION | PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID |
- // TODO(rch): Remove this QUIC_VERSION_32 is retired.
- PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD);
- if (!writer.WriteUInt8(flags)) {
- return nullptr;
- }
-
- if (!writer.WriteUInt64(connection_id)) {
- return nullptr;
- }
-
- for (QuicVersion version : versions) {
- if (!writer.WriteUInt32(QuicVersionToQuicTag(version))) {
- return nullptr;
- }
- }
-
- return new QuicEncryptedPacket(buffer.release(), len, true);
-}
-
-bool QuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) {
- QuicDataReader reader(packet.data(), packet.length());
-
- visitor_->OnPacket();
-
- // First parse the public header.
- QuicPacketPublicHeader public_header;
- if (!ProcessPublicHeader(&reader, &public_header)) {
- DLOG(WARNING) << "Unable to process public header.";
- DCHECK_NE("", detailed_error_);
- return RaiseError(QUIC_INVALID_PACKET_HEADER);
- }
-
- if (!visitor_->OnUnauthenticatedPublicHeader(public_header)) {
- // The visitor suppresses further processing of the packet.
- return true;
- }
-
- if (perspective_ == Perspective::IS_SERVER && public_header.version_flag &&
- public_header.versions[0] != quic_version_) {
- if (!visitor_->OnProtocolVersionMismatch(public_header.versions[0])) {
- return true;
- }
- }
-
- bool rv;
- if (perspective_ == Perspective::IS_CLIENT && public_header.version_flag) {
- rv = ProcessVersionNegotiationPacket(&reader, &public_header);
- } else if (public_header.reset_flag) {
- rv = ProcessPublicResetPacket(&reader, public_header);
- } else if (packet.length() <= kMaxPacketSize) {
- // The optimized decryption algorithm implementations run faster when
- // operating on aligned memory.
- //
- // TODO(rtenneti): Change the default 64 alignas value (used the default
- // value from CACHELINE_SIZE).
- ALIGNAS(64) char buffer[kMaxPacketSize];
- rv = ProcessDataPacket(&reader, public_header, packet, buffer,
- kMaxPacketSize);
- } else {
- std::unique_ptr<char[]> large_buffer(new char[packet.length()]);
- rv = ProcessDataPacket(&reader, public_header, packet, large_buffer.get(),
- packet.length());
- QUIC_BUG_IF(rv) << "QUIC should never successfully process packets larger"
- << "than kMaxPacketSize. packet size:" << packet.length();
- }
-
- return rv;
-}
-
-bool QuicFramer::ProcessVersionNegotiationPacket(
- QuicDataReader* reader,
- QuicPacketPublicHeader* public_header) {
- DCHECK_EQ(Perspective::IS_CLIENT, perspective_);
- // Try reading at least once to raise error if the packet is invalid.
- do {
- QuicTag version;
- if (!reader->ReadBytes(&version, kQuicVersionSize)) {
- set_detailed_error("Unable to read supported version in negotiation.");
- return RaiseError(QUIC_INVALID_VERSION_NEGOTIATION_PACKET);
- }
- public_header->versions.push_back(QuicTagToQuicVersion(version));
- } while (!reader->IsDoneReading());
-
- visitor_->OnVersionNegotiationPacket(*public_header);
- return true;
-}
-
-bool QuicFramer::ProcessDataPacket(QuicDataReader* encrypted_reader,
- const QuicPacketPublicHeader& public_header,
- const QuicEncryptedPacket& packet,
- char* decrypted_buffer,
- size_t buffer_length) {
- QuicPacketHeader header(public_header);
- if (!ProcessUnauthenticatedHeader(encrypted_reader, &header)) {
- DLOG(WARNING) << "Unable to process packet header. Stopping parsing.";
- return false;
- }
-
- size_t decrypted_length = 0;
- if (!DecryptPayload(encrypted_reader, header, packet, decrypted_buffer,
- buffer_length, &decrypted_length)) {
- set_detailed_error("Unable to decrypt payload.");
- return RaiseError(QUIC_DECRYPTION_FAILURE);
- }
-
- QuicDataReader reader(decrypted_buffer, decrypted_length);
- if (quic_version_ <= QUIC_VERSION_33) {
- if (!ProcessAuthenticatedHeader(&reader, &header)) {
- DLOG(WARNING) << "Unable to process packet header. Stopping parsing.";
- return false;
- }
- }
-
- // Set the last packet number after we have decrypted the packet
- // so we are confident is not attacker controlled.
- SetLastPacketNumber(header);
-
- if (!visitor_->OnPacketHeader(header)) {
- // The visitor suppresses further processing of the packet.
- return true;
- }
-
- if (packet.length() > kMaxPacketSize) {
- // If the packet has gotten this far, it should not be too large.
- QUIC_BUG << "Packet too large:" << packet.length();
- return RaiseError(QUIC_PACKET_TOO_LARGE);
- }
-
- DCHECK(!header.fec_flag);
- // Handle the payload.
- if (!ProcessFrameData(&reader, header)) {
- DCHECK_NE(QUIC_NO_ERROR, error_); // ProcessFrameData sets the error.
- DLOG(WARNING) << "Unable to process frame data.";
- return false;
- }
-
- visitor_->OnPacketComplete();
- return true;
-}
-
-bool QuicFramer::ProcessPublicResetPacket(
- QuicDataReader* reader,
- const QuicPacketPublicHeader& public_header) {
- QuicPublicResetPacket packet(public_header);
-
- std::unique_ptr<CryptoHandshakeMessage> reset(
- CryptoFramer::ParseMessage(reader->ReadRemainingPayload()));
- if (!reset.get()) {
- set_detailed_error("Unable to read reset message.");
- return RaiseError(QUIC_INVALID_PUBLIC_RST_PACKET);
- }
- if (reset->tag() != kPRST) {
- set_detailed_error("Incorrect message tag.");
- return RaiseError(QUIC_INVALID_PUBLIC_RST_PACKET);
- }
-
- if (reset->GetUint64(kRNON, &packet.nonce_proof) != QUIC_NO_ERROR) {
- set_detailed_error("Unable to read nonce proof.");
- return RaiseError(QUIC_INVALID_PUBLIC_RST_PACKET);
- }
- // TODO(satyamshekhar): validate nonce to protect against DoS.
-
- StringPiece address;
- if (reset->GetStringPiece(kCADR, &address)) {
- QuicSocketAddressCoder address_coder;
- if (address_coder.Decode(address.data(), address.length())) {
- packet.client_address =
- IPEndPoint(address_coder.ip(), address_coder.port());
- }
- }
-
- visitor_->OnPublicResetPacket(packet);
- return true;
-}
-
-bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header,
- QuicDataWriter* writer) {
- DVLOG(1) << "Appending header: " << header;
- uint8_t public_flags = 0;
- if (header.public_header.reset_flag) {
- public_flags |= PACKET_PUBLIC_FLAGS_RST;
- }
- if (header.public_header.version_flag) {
- public_flags |= PACKET_PUBLIC_FLAGS_VERSION;
- }
- if (header.public_header.multipath_flag) {
- public_flags |= PACKET_PUBLIC_FLAGS_MULTIPATH;
- }
-
- public_flags |=
- GetSequenceNumberFlags(header.public_header.packet_number_length)
- << kPublicHeaderSequenceNumberShift;
-
- if (header.public_header.nonce != nullptr) {
- DCHECK_EQ(Perspective::IS_SERVER, perspective_);
- public_flags |= PACKET_PUBLIC_FLAGS_NONCE;
- }
-
- switch (header.public_header.connection_id_length) {
- case PACKET_0BYTE_CONNECTION_ID:
- if (!writer->WriteUInt8(public_flags |
- PACKET_PUBLIC_FLAGS_0BYTE_CONNECTION_ID)) {
- return false;
- }
- break;
- case PACKET_8BYTE_CONNECTION_ID:
- if (quic_version_ > QUIC_VERSION_32) {
- public_flags |= PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID;
- if (perspective_ == Perspective::IS_CLIENT) {
- // TODO(rch): Fix this when v33 flags are supported by middle boxes.
- public_flags |= PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD;
- }
-
- } else {
- public_flags |= PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD;
- }
- if (!writer->WriteUInt8(public_flags) ||
- !writer->WriteUInt64(header.public_header.connection_id)) {
- return false;
- }
- break;
- }
- last_serialized_connection_id_ = header.public_header.connection_id;
-
- if (header.public_header.version_flag) {
- DCHECK_EQ(Perspective::IS_CLIENT, perspective_);
- QuicTag tag = QuicVersionToQuicTag(quic_version_);
- writer->WriteUInt32(tag);
- DVLOG(1) << "version = " << quic_version_ << ", tag = '"
- << QuicUtils::TagToString(tag) << "'";
- }
-
- if (header.public_header.multipath_flag &&
- !writer->WriteUInt8(header.path_id)) {
- return false;
- }
-
- if (header.public_header.nonce != nullptr &&
- !writer->WriteBytes(header.public_header.nonce,
- kDiversificationNonceSize)) {
- return false;
- }
-
- if (!AppendPacketSequenceNumber(header.public_header.packet_number_length,
- header.packet_number, writer)) {
- return false;
- }
- if (quic_version_ > QUIC_VERSION_33) {
- return true;
- }
-
- uint8_t private_flags = 0;
- if (header.entropy_flag) {
- private_flags |= PACKET_PRIVATE_FLAGS_ENTROPY;
- }
- if (!writer->WriteUInt8(private_flags)) {
- return false;
- }
-
- return true;
-}
-
-const QuicTime::Delta QuicFramer::CalculateTimestampFromWire(
- uint32_t time_delta_us) {
- // The new time_delta might have wrapped to the next epoch, or it
- // might have reverse wrapped to the previous epoch, or it might
- // remain in the same epoch. Select the time closest to the previous
- // time.
- //
- // epoch_delta is the delta between epochs. A delta is 4 bytes of
- // microseconds.
- const uint64_t epoch_delta = UINT64_C(1) << 32;
- uint64_t epoch = last_timestamp_.ToMicroseconds() & ~(epoch_delta - 1);
- // Wrapping is safe here because a wrapped value will not be ClosestTo below.
- uint64_t prev_epoch = epoch - epoch_delta;
- uint64_t next_epoch = epoch + epoch_delta;
-
- uint64_t time = ClosestTo(
- last_timestamp_.ToMicroseconds(), epoch + time_delta_us,
- ClosestTo(last_timestamp_.ToMicroseconds(), prev_epoch + time_delta_us,
- next_epoch + time_delta_us));
-
- return QuicTime::Delta::FromMicroseconds(time);
-}
-
-bool QuicFramer::IsValidPath(QuicPathId path_id,
- QuicPacketNumber* last_packet_number) {
- if (ContainsKey(closed_paths_, path_id)) {
- // Path is closed.
- return false;
- }
-
- if (path_id == last_path_id_) {
- *last_packet_number = last_packet_number_;
- return true;
- }
-
- if (ContainsKey(last_packet_numbers_, path_id)) {
- *last_packet_number = last_packet_numbers_[path_id];
- } else {
- *last_packet_number = 0;
- }
-
- return true;
-}
-
-void QuicFramer::SetLastPacketNumber(const QuicPacketHeader& header) {
- if (header.public_header.multipath_flag && header.path_id != last_path_id_) {
- if (last_path_id_ != kInvalidPathId) {
- // Save current last packet number before changing path.
- last_packet_numbers_[last_path_id_] = last_packet_number_;
- }
- // Change path.
- last_path_id_ = header.path_id;
- }
- last_packet_number_ = header.packet_number;
-}
-
-void QuicFramer::OnPathClosed(QuicPathId path_id) {
- closed_paths_.insert(path_id);
- last_packet_numbers_.erase(path_id);
-}
-
-QuicPacketNumber QuicFramer::CalculatePacketNumberFromWire(
- QuicPacketNumberLength packet_number_length,
- QuicPacketNumber last_packet_number,
- QuicPacketNumber packet_number) const {
- // The new packet number might have wrapped to the next epoch, or
- // it might have reverse wrapped to the previous epoch, or it might
- // remain in the same epoch. Select the packet number closest to the
- // next expected packet number, the previous packet number plus 1.
-
- // epoch_delta is the delta between epochs the packet number was serialized
- // with, so the correct value is likely the same epoch as the last sequence
- // number or an adjacent epoch.
- const QuicPacketNumber epoch_delta = UINT64_C(1)
- << (8 * packet_number_length);
- QuicPacketNumber next_packet_number = last_packet_number + 1;
- QuicPacketNumber epoch = last_packet_number & ~(epoch_delta - 1);
- QuicPacketNumber prev_epoch = epoch - epoch_delta;
- QuicPacketNumber next_epoch = epoch + epoch_delta;
-
- return ClosestTo(next_packet_number, epoch + packet_number,
- ClosestTo(next_packet_number, prev_epoch + packet_number,
- next_epoch + packet_number));
-}
-
-bool QuicFramer::ProcessPublicHeader(QuicDataReader* reader,
- QuicPacketPublicHeader* public_header) {
- uint8_t public_flags;
- if (!reader->ReadBytes(&public_flags, 1)) {
- set_detailed_error("Unable to read public flags.");
- return false;
- }
-
- public_header->multipath_flag =
- (public_flags & PACKET_PUBLIC_FLAGS_MULTIPATH) != 0;
- public_header->reset_flag = (public_flags & PACKET_PUBLIC_FLAGS_RST) != 0;
- public_header->version_flag =
- (public_flags & PACKET_PUBLIC_FLAGS_VERSION) != 0;
-
- if (validate_flags_ && !public_header->version_flag &&
- public_flags > PACKET_PUBLIC_FLAGS_MAX) {
- set_detailed_error("Illegal public flags value.");
- return false;
- }
-
- if (public_header->reset_flag && public_header->version_flag) {
- set_detailed_error("Got version flag in reset packet");
- return false;
- }
-
- switch (public_flags & PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID) {
- case PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID:
- if (!reader->ReadUInt64(&public_header->connection_id)) {
- set_detailed_error("Unable to read ConnectionId.");
- return false;
- }
- public_header->connection_id_length = PACKET_8BYTE_CONNECTION_ID;
- break;
- case PACKET_PUBLIC_FLAGS_0BYTE_CONNECTION_ID:
- public_header->connection_id_length = PACKET_0BYTE_CONNECTION_ID;
- public_header->connection_id = last_serialized_connection_id_;
- break;
- }
-
- public_header->packet_number_length = ReadSequenceNumberLength(
- public_flags >> kPublicHeaderSequenceNumberShift);
-
- // Read the version only if the packet is from the client.
- // version flag from the server means version negotiation packet.
- if (public_header->version_flag && perspective_ == Perspective::IS_SERVER) {
- QuicTag version_tag;
- if (!reader->ReadUInt32(&version_tag)) {
- set_detailed_error("Unable to read protocol version.");
- return false;
- }
-
- // 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_tag_ = version_tag;
- QuicVersion version = QuicTagToQuicVersion(version_tag);
- if (version == quic_version_ && public_flags > PACKET_PUBLIC_FLAGS_MAX) {
- set_detailed_error("Illegal public flags value.");
- return false;
- }
- public_header->versions.push_back(version);
- }
-
- // A nonce should only be present in packets from the server to the client,
- // which are neither version negotiation nor public reset packets
- // and only for versions after QUIC_VERSION_32. Earlier versions will
- // set this bit when indicating an 8-byte connection ID, which should
- // not be interpreted as indicating a nonce is present.
- if (quic_version_ > QUIC_VERSION_32 &&
- public_flags & PACKET_PUBLIC_FLAGS_NONCE &&
- !(public_flags & PACKET_PUBLIC_FLAGS_VERSION) &&
- !(public_flags & PACKET_PUBLIC_FLAGS_RST) &&
- // The nonce flag from a client is ignored and is assumed to be an older
- // client indicating an eight-byte connection ID.
- perspective_ == Perspective::IS_CLIENT) {
- if (!reader->ReadBytes(reinterpret_cast<uint8_t*>(last_nonce_),
- sizeof(last_nonce_))) {
- set_detailed_error("Unable to read nonce.");
- return false;
- }
- public_header->nonce = &last_nonce_;
- } else {
- public_header->nonce = nullptr;
- }
-
- return true;
-}
-
-// static
-QuicPacketNumberLength QuicFramer::GetMinSequenceNumberLength(
- QuicPacketNumber packet_number) {
- if (packet_number < 1 << (PACKET_1BYTE_PACKET_NUMBER * 8)) {
- return PACKET_1BYTE_PACKET_NUMBER;
- } else if (packet_number < 1 << (PACKET_2BYTE_PACKET_NUMBER * 8)) {
- return PACKET_2BYTE_PACKET_NUMBER;
- } else if (packet_number < UINT64_C(1) << (PACKET_4BYTE_PACKET_NUMBER * 8)) {
- return PACKET_4BYTE_PACKET_NUMBER;
- } else {
- return PACKET_6BYTE_PACKET_NUMBER;
- }
-}
-
-// static
-uint8_t QuicFramer::GetSequenceNumberFlags(
- QuicPacketNumberLength packet_number_length) {
- switch (packet_number_length) {
- case PACKET_1BYTE_PACKET_NUMBER:
- return PACKET_FLAGS_1BYTE_PACKET;
- case PACKET_2BYTE_PACKET_NUMBER:
- return PACKET_FLAGS_2BYTE_PACKET;
- case PACKET_4BYTE_PACKET_NUMBER:
- return PACKET_FLAGS_4BYTE_PACKET;
- case PACKET_6BYTE_PACKET_NUMBER:
- return PACKET_FLAGS_6BYTE_PACKET;
- default:
- QUIC_BUG << "Unreachable case statement.";
- return PACKET_FLAGS_6BYTE_PACKET;
- }
-}
-
-// static
-QuicFramer::AckFrameInfo QuicFramer::GetAckFrameInfo(
- const QuicAckFrame& frame) {
- AckFrameInfo ack_info;
- if (frame.packets.Empty()) {
- return ack_info;
- }
- DCHECK_GE(frame.largest_observed, frame.packets.Max());
- size_t cur_range_length = 0;
- PacketNumberQueue::const_iterator iter = frame.packets.begin();
- // TODO(jdorfman): Switch this logic to use the intervals in PacketNumberQueue
- // instead of reconstructing them from the sequence.
- QuicPacketNumber last_missing = *iter;
- ++iter;
- for (; iter != frame.packets.end(); ++iter) {
- if (cur_range_length < numeric_limits<uint8_t>::max() &&
- *iter == (last_missing + 1)) {
- ++cur_range_length;
- } else {
- ack_info.nack_ranges[last_missing - cur_range_length] =
- static_cast<uint8_t>(cur_range_length);
- cur_range_length = 0;
- }
- ack_info.max_delta = max(ack_info.max_delta, *iter - last_missing);
- last_missing = *iter;
- }
- // Include the last nack range.
- ack_info.nack_ranges[last_missing - cur_range_length] =
- static_cast<uint8_t>(cur_range_length);
- // Include the range to the largest observed.
- ack_info.max_delta =
- max(ack_info.max_delta, frame.largest_observed - last_missing);
- return ack_info;
-}
-
-// static
-QuicFramer::NewAckFrameInfo QuicFramer::GetNewAckFrameInfo(
- const QuicAckFrame& frame) {
- NewAckFrameInfo new_ack_info;
- if (frame.packets.Empty()) {
- return new_ack_info;
- }
- uint64_t cur_range_length = 1;
- PacketNumberQueue::const_iterator iter = frame.packets.begin();
- QuicPacketNumber last_received = *iter;
- ++iter;
- for (; iter != frame.packets.end(); ++iter) {
- if (*iter == (last_received + 1)) {
- ++cur_range_length;
- } else {
- size_t total_gap = *iter - last_received - 1;
- size_t num_blocks = static_cast<size_t>(ceil(
- static_cast<double>(total_gap) / numeric_limits<uint8_t>::max()));
- uint8_t last_gap = static_cast<uint8_t>(
- total_gap - (num_blocks - 1) * numeric_limits<uint8_t>::max());
- for (size_t i = 0; i < num_blocks; ++i) {
- if (i == 0) {
- new_ack_info.ack_blocks.push_back(
- AckBlock(last_gap, cur_range_length));
- } else {
- // Add an ack block of length 0 because there are more than 255
- // missing packets in a row.
- new_ack_info.ack_blocks.push_back(
- AckBlock(numeric_limits<uint8_t>::max(), 0));
- }
- }
- new_ack_info.max_block_length =
- max(new_ack_info.max_block_length, cur_range_length);
- cur_range_length = 1;
- }
- last_received = *iter;
- }
- new_ack_info.first_block_length = cur_range_length;
- new_ack_info.max_block_length =
- max(new_ack_info.max_block_length, new_ack_info.first_block_length);
- return new_ack_info;
-}
-
-bool QuicFramer::ProcessUnauthenticatedHeader(QuicDataReader* encrypted_reader,
- QuicPacketHeader* header) {
- header->path_id = kDefaultPathId;
- if (header->public_header.multipath_flag &&
- !ProcessPathId(encrypted_reader, &header->path_id)) {
- set_detailed_error("Unable to read path id.");
- return RaiseError(QUIC_INVALID_PACKET_HEADER);
- }
-
- QuicPacketNumber last_packet_number = last_packet_number_;
- if (header->public_header.multipath_flag &&
- !IsValidPath(header->path_id, &last_packet_number)) {
- // Stop processing because path is closed.
- return false;
- }
-
- if (!ProcessPacketSequenceNumber(
- encrypted_reader, header->public_header.packet_number_length,
- last_packet_number, &header->packet_number)) {
- set_detailed_error("Unable to read packet number.");
- return RaiseError(QUIC_INVALID_PACKET_HEADER);
- }
-
- if (header->packet_number == 0u) {
- set_detailed_error("packet numbers cannot be 0.");
- return RaiseError(QUIC_INVALID_PACKET_HEADER);
- }
-
- if (!visitor_->OnUnauthenticatedHeader(*header)) {
- return false;
- }
- return true;
-}
-
-bool QuicFramer::ProcessAuthenticatedHeader(QuicDataReader* reader,
- QuicPacketHeader* header) {
- uint8_t private_flags;
- if (!reader->ReadBytes(&private_flags, 1)) {
- set_detailed_error("Unable to read private flags.");
- return RaiseError(QUIC_INVALID_PACKET_HEADER);
- }
-
- if (quic_version_ > QUIC_VERSION_31) {
- if (private_flags > PACKET_PRIVATE_FLAGS_MAX_VERSION_32) {
- set_detailed_error("Illegal private flags value.");
- return RaiseError(QUIC_INVALID_PACKET_HEADER);
- }
- } else {
- if (private_flags > PACKET_PRIVATE_FLAGS_MAX) {
- set_detailed_error("Illegal private flags value.");
- return RaiseError(QUIC_INVALID_PACKET_HEADER);
- }
- }
-
- header->entropy_flag = (private_flags & PACKET_PRIVATE_FLAGS_ENTROPY) != 0;
- header->fec_flag = (private_flags & PACKET_PRIVATE_FLAGS_FEC) != 0;
-
- if ((private_flags & PACKET_PRIVATE_FLAGS_FEC_GROUP) != 0) {
- uint8_t first_fec_protected_packet_offset;
- if (!reader->ReadBytes(&first_fec_protected_packet_offset, 1)) {
- set_detailed_error("Unable to read first fec protected packet offset.");
- return RaiseError(QUIC_INVALID_PACKET_HEADER);
- }
- if (first_fec_protected_packet_offset >= header->packet_number) {
- set_detailed_error(
- "First fec protected packet offset must be less "
- "than the packet number.");
- return RaiseError(QUIC_INVALID_PACKET_HEADER);
- }
- }
-
- header->entropy_hash = GetPacketEntropyHash(*header);
- return true;
-}
-
-bool QuicFramer::ProcessPathId(QuicDataReader* reader, QuicPathId* path_id) {
- if (!reader->ReadBytes(path_id, 1)) {
- return false;
- }
-
- return true;
-}
-
-bool QuicFramer::ProcessPacketSequenceNumber(
- QuicDataReader* reader,
- QuicPacketNumberLength packet_number_length,
- QuicPacketNumber last_packet_number,
- QuicPacketNumber* packet_number) {
- QuicPacketNumber wire_packet_number = 0u;
- if (!reader->ReadBytes(&wire_packet_number, packet_number_length)) {
- return false;
- }
-
- // TODO(ianswett): Explore the usefulness of trying multiple packet numbers
- // in case the first guess is incorrect.
- *packet_number = CalculatePacketNumberFromWire(
- packet_number_length, last_packet_number, wire_packet_number);
- return true;
-}
-
-bool QuicFramer::ProcessFrameData(QuicDataReader* reader,
- const QuicPacketHeader& header) {
- if (reader->IsDoneReading()) {
- set_detailed_error("Packet has no frames.");
- return RaiseError(QUIC_MISSING_PAYLOAD);
- }
- while (!reader->IsDoneReading()) {
- uint8_t frame_type;
- if (!reader->ReadBytes(&frame_type, 1)) {
- set_detailed_error("Unable to read frame type.");
- return RaiseError(QUIC_INVALID_FRAME_DATA);
- }
-
- if (frame_type & kQuicFrameTypeSpecialMask) {
- // Stream Frame
- if (frame_type & kQuicFrameTypeStreamMask) {
- QuicStreamFrame frame;
- if (!ProcessStreamFrame(reader, frame_type, &frame)) {
- return RaiseError(QUIC_INVALID_STREAM_DATA);
- }
- if (!visitor_->OnStreamFrame(frame)) {
- DVLOG(1) << "Visitor asked to stop further processing.";
- // Returning true since there was no parsing error.
- return true;
- }
- continue;
- }
-
- // Ack Frame
- if (frame_type & kQuicFrameTypeAckMask) {
- QuicAckFrame frame;
- if (quic_version_ <= QUIC_VERSION_33) {
- if (!ProcessAckFrame(reader, frame_type, &frame)) {
- return RaiseError(QUIC_INVALID_ACK_DATA);
- }
- } else {
- if (!ProcessNewAckFrame(reader, frame_type, &frame)) {
- return RaiseError(QUIC_INVALID_ACK_DATA);
- }
- }
- if (!visitor_->OnAckFrame(frame)) {
- DVLOG(1) << "Visitor asked to stop further processing.";
- // Returning true since there was no parsing error.
- return true;
- }
- continue;
- }
-
- // This was a special frame type that did not match any
- // of the known ones. Error.
- set_detailed_error("Illegal frame type.");
- DLOG(WARNING) << "Illegal frame type: " << static_cast<int>(frame_type);
- return RaiseError(QUIC_INVALID_FRAME_DATA);
- }
-
- switch (frame_type) {
- case PADDING_FRAME: {
- QuicPaddingFrame frame(reader->BytesRemaining());
- if (!visitor_->OnPaddingFrame(frame)) {
- DVLOG(1) << "Visitor asked to stop further processing.";
- }
- // We're done with the packet.
- return true;
- }
-
- case RST_STREAM_FRAME: {
- QuicRstStreamFrame frame;
- if (!ProcessRstStreamFrame(reader, &frame)) {
- return RaiseError(QUIC_INVALID_RST_STREAM_DATA);
- }
- if (!visitor_->OnRstStreamFrame(frame)) {
- DVLOG(1) << "Visitor asked to stop further processing.";
- // Returning true since there was no parsing error.
- return true;
- }
- continue;
- }
-
- case CONNECTION_CLOSE_FRAME: {
- QuicConnectionCloseFrame frame;
- if (!ProcessConnectionCloseFrame(reader, &frame)) {
- return RaiseError(QUIC_INVALID_CONNECTION_CLOSE_DATA);
- }
-
- if (!visitor_->OnConnectionCloseFrame(frame)) {
- DVLOG(1) << "Visitor asked to stop further processing.";
- // Returning true since there was no parsing error.
- return true;
- }
- continue;
- }
-
- case GOAWAY_FRAME: {
- QuicGoAwayFrame goaway_frame;
- if (!ProcessGoAwayFrame(reader, &goaway_frame)) {
- return RaiseError(QUIC_INVALID_GOAWAY_DATA);
- }
- if (!visitor_->OnGoAwayFrame(goaway_frame)) {
- DVLOG(1) << "Visitor asked to stop further processing.";
- // Returning true since there was no parsing error.
- return true;
- }
- continue;
- }
-
- case WINDOW_UPDATE_FRAME: {
- QuicWindowUpdateFrame window_update_frame;
- if (!ProcessWindowUpdateFrame(reader, &window_update_frame)) {
- return RaiseError(QUIC_INVALID_WINDOW_UPDATE_DATA);
- }
- if (!visitor_->OnWindowUpdateFrame(window_update_frame)) {
- DVLOG(1) << "Visitor asked to stop further processing.";
- // Returning true since there was no parsing error.
- return true;
- }
- continue;
- }
-
- case BLOCKED_FRAME: {
- QuicBlockedFrame blocked_frame;
- if (!ProcessBlockedFrame(reader, &blocked_frame)) {
- return RaiseError(QUIC_INVALID_BLOCKED_DATA);
- }
- if (!visitor_->OnBlockedFrame(blocked_frame)) {
- DVLOG(1) << "Visitor asked to stop further processing.";
- // Returning true since there was no parsing error.
- return true;
- }
- continue;
- }
-
- case STOP_WAITING_FRAME: {
- QuicStopWaitingFrame stop_waiting_frame;
- if (!ProcessStopWaitingFrame(reader, header, &stop_waiting_frame)) {
- return RaiseError(QUIC_INVALID_STOP_WAITING_DATA);
- }
- if (!visitor_->OnStopWaitingFrame(stop_waiting_frame)) {
- DVLOG(1) << "Visitor asked to stop further processing.";
- // Returning true since there was no parsing error.
- return true;
- }
- continue;
- }
- case PING_FRAME: {
- // Ping has no payload.
- QuicPingFrame ping_frame;
- if (!visitor_->OnPingFrame(ping_frame)) {
- DVLOG(1) << "Visitor asked to stop further processing.";
- // Returning true since there was no parsing error.
- return true;
- }
- continue;
- }
- case PATH_CLOSE_FRAME: {
- QuicPathCloseFrame path_close_frame;
- if (!ProcessPathCloseFrame(reader, &path_close_frame)) {
- return RaiseError(QUIC_INVALID_PATH_CLOSE_DATA);
- }
- if (!visitor_->OnPathCloseFrame(path_close_frame)) {
- DVLOG(1) << "Visitor asked to stop further processing.";
- // Returning true since there was no parsing error.
- return true;
- }
- continue;
- }
-
- default:
- set_detailed_error("Illegal frame type.");
- DLOG(WARNING) << "Illegal frame type: " << static_cast<int>(frame_type);
- return RaiseError(QUIC_INVALID_FRAME_DATA);
- }
- }
-
- return true;
-}
-
-bool QuicFramer::ProcessStreamFrame(QuicDataReader* reader,
- uint8_t frame_type,
- QuicStreamFrame* frame) {
- uint8_t stream_flags = frame_type;
-
- stream_flags &= ~kQuicFrameTypeStreamMask;
-
- // Read from right to left: StreamID, Offset, Data Length, Fin.
- const uint8_t stream_id_length = (stream_flags & kQuicStreamIDLengthMask) + 1;
- stream_flags >>= kQuicStreamIdShift;
-
- uint8_t offset_length = (stream_flags & kQuicStreamOffsetMask);
- // There is no encoding for 1 byte, only 0 and 2 through 8.
- if (offset_length > 0) {
- offset_length += 1;
- }
- stream_flags >>= kQuicStreamOffsetShift;
-
- bool has_data_length =
- (stream_flags & kQuicStreamDataLengthMask) == kQuicStreamDataLengthMask;
- stream_flags >>= kQuicStreamDataLengthShift;
-
- frame->fin = (stream_flags & kQuicStreamFinMask) == kQuicStreamFinShift;
-
- frame->stream_id = 0;
- if (!reader->ReadBytes(&frame->stream_id, stream_id_length)) {
- set_detailed_error("Unable to read stream_id.");
- return false;
- }
-
- frame->offset = 0;
- if (!reader->ReadBytes(&frame->offset, offset_length)) {
- set_detailed_error("Unable to read offset.");
- return false;
- }
-
- // TODO(ianswett): Don't use StringPiece as an intermediary.
- StringPiece data;
- if (has_data_length) {
- if (!reader->ReadStringPiece16(&data)) {
- set_detailed_error("Unable to read frame data.");
- return false;
- }
- } else {
- if (!reader->ReadStringPiece(&data, reader->BytesRemaining())) {
- set_detailed_error("Unable to read frame data.");
- return false;
- }
- }
- frame->data_buffer = data.data();
- frame->data_length = static_cast<uint16_t>(data.length());
-
- return true;
-}
-
-bool QuicFramer::ProcessAckFrame(QuicDataReader* reader,
- uint8_t frame_type,
- QuicAckFrame* ack_frame) {
- // Determine the three lengths from the frame type: largest observed length,
- // missing packet number length, and missing range length.
- const QuicPacketNumberLength missing_packet_number_length =
- ReadSequenceNumberLength(frame_type);
- frame_type >>= kQuicSequenceNumberLengthShift;
- const QuicPacketNumberLength largest_observed_packet_number_length =
- ReadSequenceNumberLength(frame_type);
- frame_type >>= kQuicSequenceNumberLengthShift;
- ack_frame->is_truncated = frame_type & kQuicAckTruncatedMask;
- frame_type >>= kQuicAckTruncatedShift;
- bool has_nacks = frame_type & kQuicHasNacksMask;
-
- if (!reader->ReadBytes(&ack_frame->entropy_hash, 1)) {
- set_detailed_error("Unable to read entropy hash for received packets.");
- return false;
- }
-
- if (!reader->ReadBytes(&ack_frame->largest_observed,
- largest_observed_packet_number_length)) {
- set_detailed_error("Unable to read largest observed.");
- return false;
- }
-
- uint64_t ack_delay_time_us;
- if (!reader->ReadUFloat16(&ack_delay_time_us)) {
- set_detailed_error("Unable to read ack delay time.");
- return false;
- }
-
- if (ack_delay_time_us == kUFloat16MaxValue) {
- ack_frame->ack_delay_time = QuicTime::Delta::Infinite();
- } else {
- ack_frame->ack_delay_time =
- QuicTime::Delta::FromMicroseconds(ack_delay_time_us);
- }
-
- if (!ProcessTimestampsInAckFrame(reader, ack_frame)) {
- return false;
- }
-
- if (!has_nacks) {
- return true;
- }
-
- uint8_t num_missing_ranges;
- if (!reader->ReadBytes(&num_missing_ranges, 1)) {
- set_detailed_error("Unable to read num missing packet ranges.");
- return false;
- }
-
- QuicPacketNumber last_packet_number = ack_frame->largest_observed;
- for (size_t i = 0; i < num_missing_ranges; ++i) {
- QuicPacketNumber missing_delta = 0;
- if (!reader->ReadBytes(&missing_delta, missing_packet_number_length)) {
- set_detailed_error("Unable to read missing packet number delta.");
- return false;
- }
- last_packet_number -= missing_delta;
- QuicPacketNumber range_length = 0;
- if (!reader->ReadBytes(&range_length, PACKET_1BYTE_PACKET_NUMBER)) {
- set_detailed_error("Unable to read missing packet number range.");
- return false;
- }
- ack_frame->packets.Add(last_packet_number - range_length,
- last_packet_number + 1);
- // Subtract an extra 1 to ensure ranges are represented efficiently and
- // can't overlap by 1 packet number. This allows a missing_delta of 0
- // to represent an adjacent nack range.
- last_packet_number -= (range_length + 1);
- }
-
- if (quic_version_ > QUIC_VERSION_31) {
- return true;
- }
-
- // Parse the revived packets list.
- // TODO(ianswett): Change the ack frame so it only expresses one revived.
- uint8_t num_revived_packets;
- if (!reader->ReadBytes(&num_revived_packets, 1)) {
- set_detailed_error("Unable to read num revived packets.");
- return false;
- }
-
- for (size_t i = 0; i < num_revived_packets; ++i) {
- QuicPacketNumber revived_packet = 0;
- if (!reader->ReadBytes(&revived_packet,
- largest_observed_packet_number_length)) {
- set_detailed_error("Unable to read revived packet.");
- return false;
- }
- }
-
- return true;
-}
-
-bool QuicFramer::ProcessNewAckFrame(QuicDataReader* reader,
- uint8_t frame_type,
- QuicAckFrame* ack_frame) {
- // Determine the two lengths from the frame type: largest acked length,
- // ack block length.
- const QuicPacketNumberLength ack_block_length =
- ReadSequenceNumberLength(frame_type);
- frame_type >>= kQuicSequenceNumberLengthShift;
- const QuicPacketNumberLength largest_acked_length =
- ReadSequenceNumberLength(frame_type);
- frame_type >>= kQuicSequenceNumberLengthShift;
- frame_type >>= kQuicHasMultipleAckBlocksShift;
- bool has_ack_blocks = frame_type & kQuicHasMultipleAckBlocksMask;
- ack_frame->missing = false;
-
- if (!reader->ReadBytes(&ack_frame->largest_observed, largest_acked_length)) {
- set_detailed_error("Unable to read largest acked.");
- return false;
- }
-
- uint64_t ack_delay_time_us;
- if (!reader->ReadUFloat16(&ack_delay_time_us)) {
- set_detailed_error("Unable to read ack delay time.");
- return false;
- }
-
- if (ack_delay_time_us == kUFloat16MaxValue) {
- ack_frame->ack_delay_time = QuicTime::Delta::Infinite();
- } else {
- ack_frame->ack_delay_time =
- QuicTime::Delta::FromMicroseconds(ack_delay_time_us);
- }
-
- uint8_t num_ack_blocks = 0;
- if (has_ack_blocks) {
- if (!reader->ReadBytes(&num_ack_blocks, 1)) {
- set_detailed_error("Unable to read num of ack blocks.");
- return false;
- }
- }
-
- size_t first_block_length = 0;
- if (!reader->ReadBytes(&first_block_length, ack_block_length)) {
- set_detailed_error("Unable to read first ack block length.");
- return false;
- }
- QuicPacketNumber first_received =
- ack_frame->largest_observed + 1 - first_block_length;
- ack_frame->packets.Add(first_received, ack_frame->largest_observed + 1);
-
- if (num_ack_blocks > 0) {
- for (size_t i = 0; i < num_ack_blocks; ++i) {
- size_t gap = 0;
- if (!reader->ReadBytes(&gap, PACKET_1BYTE_PACKET_NUMBER)) {
- set_detailed_error("Unable to read gap to next ack block.");
- return false;
- }
- size_t current_block_length = 0;
- if (!reader->ReadBytes(&current_block_length, ack_block_length)) {
- set_detailed_error("Unable to ack block length.");
- return false;
- }
- first_received -= (gap + current_block_length);
- if (current_block_length > 0) {
- ack_frame->packets.Add(first_received,
- first_received + current_block_length);
- }
- }
- }
-
- if (!ProcessTimestampsInAckFrame(reader, ack_frame)) {
- return false;
- }
-
- return true;
-}
-
-bool QuicFramer::ProcessTimestampsInAckFrame(QuicDataReader* reader,
- QuicAckFrame* ack_frame) {
- if (ack_frame->is_truncated) {
- return true;
- }
- uint8_t num_received_packets;
- if (!reader->ReadBytes(&num_received_packets, 1)) {
- set_detailed_error("Unable to read num received packets.");
- return false;
- }
-
- if (num_received_packets > 0) {
- ack_frame->received_packet_times.reserve(num_received_packets);
- uint8_t delta_from_largest_observed;
- if (!reader->ReadBytes(&delta_from_largest_observed,
- PACKET_1BYTE_PACKET_NUMBER)) {
- set_detailed_error("Unable to read sequence delta in received packets.");
- return false;
- }
- QuicPacketNumber seq_num =
- ack_frame->largest_observed - delta_from_largest_observed;
-
- // Time delta from the framer creation.
- uint32_t time_delta_us;
- if (!reader->ReadBytes(&time_delta_us, sizeof(time_delta_us))) {
- set_detailed_error("Unable to read time delta in received packets.");
- return false;
- }
-
- last_timestamp_ = CalculateTimestampFromWire(time_delta_us);
-
- ack_frame->received_packet_times.reserve(num_received_packets);
- ack_frame->received_packet_times.push_back(
- std::make_pair(seq_num, creation_time_.Add(last_timestamp_)));
-
- for (uint8_t i = 1; i < num_received_packets; ++i) {
- if (!reader->ReadBytes(&delta_from_largest_observed,
- PACKET_1BYTE_PACKET_NUMBER)) {
- set_detailed_error(
- "Unable to read sequence delta in received packets.");
- return false;
- }
- seq_num = ack_frame->largest_observed - delta_from_largest_observed;
-
- // Time delta from the previous timestamp.
- uint64_t incremental_time_delta_us;
- if (!reader->ReadUFloat16(&incremental_time_delta_us)) {
- set_detailed_error(
- "Unable to read incremental time delta in received packets.");
- return false;
- }
-
- last_timestamp_ = last_timestamp_.Add(
- QuicTime::Delta::FromMicroseconds(incremental_time_delta_us));
- ack_frame->received_packet_times.push_back(
- std::make_pair(seq_num, creation_time_.Add(last_timestamp_)));
- }
- }
- return true;
-}
-
-bool QuicFramer::ProcessStopWaitingFrame(QuicDataReader* reader,
- const QuicPacketHeader& header,
- QuicStopWaitingFrame* stop_waiting) {
- if (quic_version_ <= QUIC_VERSION_33) {
- if (!reader->ReadBytes(&stop_waiting->entropy_hash, 1)) {
- set_detailed_error("Unable to read entropy hash for sent packets.");
- return false;
- }
- }
-
- QuicPacketNumber least_unacked_delta = 0;
- if (!reader->ReadBytes(&least_unacked_delta,
- header.public_header.packet_number_length)) {
- set_detailed_error("Unable to read least unacked delta.");
- return false;
- }
- DCHECK_GE(header.packet_number, least_unacked_delta);
- stop_waiting->least_unacked = header.packet_number - least_unacked_delta;
-
- return true;
-}
-
-bool QuicFramer::ProcessRstStreamFrame(QuicDataReader* reader,
- QuicRstStreamFrame* frame) {
- if (!reader->ReadUInt32(&frame->stream_id)) {
- set_detailed_error("Unable to read stream_id.");
- return false;
- }
-
- if (!reader->ReadUInt64(&frame->byte_offset)) {
- set_detailed_error("Unable to read rst stream sent byte offset.");
- return false;
- }
-
- uint32_t error_code;
- if (!reader->ReadUInt32(&error_code)) {
- set_detailed_error("Unable to read rst stream error code.");
- return false;
- }
-
- if (error_code >= QUIC_STREAM_LAST_ERROR) {
- // Ignore invalid stream error code if any.
- error_code = QUIC_STREAM_LAST_ERROR;
- }
-
- frame->error_code = static_cast<QuicRstStreamErrorCode>(error_code);
- return true;
-}
-
-bool QuicFramer::ProcessConnectionCloseFrame(QuicDataReader* reader,
- QuicConnectionCloseFrame* frame) {
- uint32_t error_code;
- if (!reader->ReadUInt32(&error_code)) {
- set_detailed_error("Unable to read connection close error code.");
- return false;
- }
-
- if (error_code >= QUIC_LAST_ERROR) {
- // Ignore invalid QUIC error code if any.
- error_code = QUIC_LAST_ERROR;
- }
-
- frame->error_code = static_cast<QuicErrorCode>(error_code);
-
- StringPiece error_details;
- if (!reader->ReadStringPiece16(&error_details)) {
- set_detailed_error("Unable to read connection close error details.");
- return false;
- }
- frame->error_details = error_details.as_string();
-
- return true;
-}
-
-bool QuicFramer::ProcessGoAwayFrame(QuicDataReader* reader,
- QuicGoAwayFrame* frame) {
- uint32_t error_code;
- if (!reader->ReadUInt32(&error_code)) {
- set_detailed_error("Unable to read go away error code.");
- return false;
- }
-
- if (error_code >= QUIC_LAST_ERROR) {
- // Ignore invalid QUIC error code if any.
- error_code = QUIC_LAST_ERROR;
- }
- frame->error_code = static_cast<QuicErrorCode>(error_code);
-
- uint32_t stream_id;
- if (!reader->ReadUInt32(&stream_id)) {
- set_detailed_error("Unable to read last good stream id.");
- return false;
- }
- frame->last_good_stream_id = static_cast<QuicStreamId>(stream_id);
-
- StringPiece reason_phrase;
- if (!reader->ReadStringPiece16(&reason_phrase)) {
- set_detailed_error("Unable to read goaway reason.");
- return false;
- }
- frame->reason_phrase = reason_phrase.as_string();
-
- return true;
-}
-
-bool QuicFramer::ProcessWindowUpdateFrame(QuicDataReader* reader,
- QuicWindowUpdateFrame* frame) {
- if (!reader->ReadUInt32(&frame->stream_id)) {
- set_detailed_error("Unable to read stream_id.");
- return false;
- }
-
- if (!reader->ReadUInt64(&frame->byte_offset)) {
- set_detailed_error("Unable to read window byte_offset.");
- return false;
- }
-
- return true;
-}
-
-bool QuicFramer::ProcessBlockedFrame(QuicDataReader* reader,
- QuicBlockedFrame* frame) {
- if (!reader->ReadUInt32(&frame->stream_id)) {
- set_detailed_error("Unable to read stream_id.");
- return false;
- }
-
- return true;
-}
-
-bool QuicFramer::ProcessPathCloseFrame(QuicDataReader* reader,
- QuicPathCloseFrame* frame) {
- if (!reader->ReadBytes(&frame->path_id, 1)) {
- set_detailed_error("Unable to read path_id.");
- return false;
- }
-
- return true;
-}
-
-// static
-StringPiece QuicFramer::GetAssociatedDataFromEncryptedPacket(
- QuicVersion version,
- const QuicEncryptedPacket& encrypted,
- QuicConnectionIdLength connection_id_length,
- bool includes_version,
- bool includes_path_id,
- bool includes_diversification_nonce,
- QuicPacketNumberLength packet_number_length) {
- // TODO(ianswett): This is identical to QuicData::AssociatedData.
- return StringPiece(
- encrypted.data(),
- GetStartOfEncryptedData(version, connection_id_length, includes_version,
- includes_path_id, includes_diversification_nonce,
- packet_number_length));
-}
-
-void QuicFramer::SetDecrypter(EncryptionLevel level, QuicDecrypter* decrypter) {
- DCHECK(alternative_decrypter_.get() == nullptr);
- DCHECK_GE(level, decrypter_level_);
- decrypter_.reset(decrypter);
- decrypter_level_ = level;
-}
-
-void QuicFramer::SetAlternativeDecrypter(EncryptionLevel level,
- QuicDecrypter* decrypter,
- bool latch_once_used) {
- alternative_decrypter_.reset(decrypter);
- alternative_decrypter_level_ = level;
- alternative_decrypter_latch_ = latch_once_used;
-}
-
-const QuicDecrypter* QuicFramer::decrypter() const {
- return decrypter_.get();
-}
-
-const QuicDecrypter* QuicFramer::alternative_decrypter() const {
- return alternative_decrypter_.get();
-}
-
-void QuicFramer::SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter) {
- DCHECK_GE(level, 0);
- DCHECK_LT(level, NUM_ENCRYPTION_LEVELS);
- encrypter_[level].reset(encrypter);
-}
-
-size_t QuicFramer::EncryptInPlace(EncryptionLevel level,
- QuicPathId path_id,
- QuicPacketNumber packet_number,
- size_t ad_len,
- size_t total_len,
- size_t buffer_len,
- char* buffer) {
- size_t output_length = 0;
- if (!encrypter_[level]->EncryptPacket(
- path_id, packet_number,
- StringPiece(buffer, ad_len), // Associated data
- StringPiece(buffer + ad_len, total_len - ad_len), // Plaintext
- buffer + ad_len, // Destination buffer
- &output_length, buffer_len - ad_len)) {
- RaiseError(QUIC_ENCRYPTION_FAILURE);
- return 0;
- }
-
- return ad_len + output_length;
-}
-
-size_t QuicFramer::EncryptPayload(EncryptionLevel level,
- QuicPathId path_id,
- QuicPacketNumber packet_number,
- const QuicPacket& packet,
- char* buffer,
- size_t buffer_len) {
- DCHECK(encrypter_[level].get() != nullptr);
-
- StringPiece associated_data = packet.AssociatedData(quic_version_);
- // Copy in the header, because the encrypter only populates the encrypted
- // plaintext content.
- const size_t ad_len = associated_data.length();
- memmove(buffer, associated_data.data(), ad_len);
- // Encrypt the plaintext into the buffer.
- size_t output_length = 0;
- if (!encrypter_[level]->EncryptPacket(path_id, packet_number, associated_data,
- packet.Plaintext(quic_version_),
- buffer + ad_len, &output_length,
- buffer_len - ad_len)) {
- RaiseError(QUIC_ENCRYPTION_FAILURE);
- return 0;
- }
-
- return ad_len + output_length;
-}
-
-size_t QuicFramer::GetMaxPlaintextSize(size_t ciphertext_size) {
- // In order to keep the code simple, we don't have the current encryption
- // level to hand. Both the NullEncrypter and AES-GCM have a tag length of 12.
- size_t min_plaintext_size = ciphertext_size;
-
- for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; i++) {
- if (encrypter_[i].get() != nullptr) {
- size_t size = encrypter_[i]->GetMaxPlaintextSize(ciphertext_size);
- if (size < min_plaintext_size) {
- min_plaintext_size = size;
- }
- }
- }
-
- return min_plaintext_size;
-}
-
-bool QuicFramer::DecryptPayload(QuicDataReader* encrypted_reader,
- const QuicPacketHeader& header,
- const QuicEncryptedPacket& packet,
- char* decrypted_buffer,
- size_t buffer_length,
- size_t* decrypted_length) {
- StringPiece encrypted = encrypted_reader->ReadRemainingPayload();
- DCHECK(decrypter_.get() != nullptr);
- StringPiece associated_data = GetAssociatedDataFromEncryptedPacket(
- quic_version_, packet, header.public_header.connection_id_length,
- header.public_header.version_flag, header.public_header.multipath_flag,
- header.public_header.nonce != nullptr,
- header.public_header.packet_number_length);
-
- bool success = decrypter_->DecryptPacket(
- header.path_id, header.packet_number, associated_data, encrypted,
- decrypted_buffer, decrypted_length, buffer_length);
- if (success) {
- visitor_->OnDecryptedPacket(decrypter_level_);
- } else if (alternative_decrypter_.get() != nullptr) {
- if (header.public_header.nonce != nullptr) {
- DCHECK_EQ(perspective_, Perspective::IS_CLIENT);
- alternative_decrypter_->SetDiversificationNonce(
- *header.public_header.nonce);
- }
- bool try_alternative_decryption = true;
- if (alternative_decrypter_level_ == ENCRYPTION_INITIAL) {
- if (perspective_ == Perspective::IS_CLIENT &&
- quic_version_ > QUIC_VERSION_32) {
- if (header.public_header.nonce == nullptr) {
- // Can not use INITIAL decryption without a diversification nonce.
- try_alternative_decryption = false;
- }
- } else {
- DCHECK(header.public_header.nonce == nullptr);
- }
- }
-
- if (try_alternative_decryption) {
- success = alternative_decrypter_->DecryptPacket(
- header.path_id, header.packet_number, associated_data, encrypted,
- decrypted_buffer, decrypted_length, buffer_length);
- }
- if (success) {
- visitor_->OnDecryptedPacket(alternative_decrypter_level_);
- if (alternative_decrypter_latch_) {
- // Switch to the alternative decrypter and latch so that we cannot
- // switch back.
- decrypter_.reset(alternative_decrypter_.release());
- decrypter_level_ = alternative_decrypter_level_;
- alternative_decrypter_level_ = ENCRYPTION_NONE;
- } else {
- // Switch the alternative decrypter so that we use it first next time.
- decrypter_.swap(alternative_decrypter_);
- EncryptionLevel level = alternative_decrypter_level_;
- alternative_decrypter_level_ = decrypter_level_;
- decrypter_level_ = level;
- }
- }
- }
-
- if (!success) {
- DLOG(WARNING) << "DecryptPacket failed for packet_number:"
- << header.packet_number;
- return false;
- }
-
- return true;
-}
-
-size_t QuicFramer::GetAckFrameTimeStampSize(const QuicAckFrame& ack) {
- if (ack.received_packet_times.empty()) {
- return 0;
- }
-
- return 5 + 3 * (ack.received_packet_times.size() - 1);
-}
-
-size_t QuicFramer::GetAckFrameSize(
- const QuicAckFrame& ack,
- QuicPacketNumberLength packet_number_length) {
- size_t ack_size = 0;
- if (quic_version_ <= QUIC_VERSION_33) {
- AckFrameInfo ack_info = GetAckFrameInfo(ack);
- QuicPacketNumberLength largest_observed_length =
- GetMinSequenceNumberLength(ack.largest_observed);
- QuicPacketNumberLength missing_packet_number_length =
- GetMinSequenceNumberLength(ack_info.max_delta);
-
- ack_size = GetMinAckFrameSize(quic_version_, largest_observed_length);
- if (!ack_info.nack_ranges.empty()) {
- ack_size += kNumberOfNackRangesSize;
- if (quic_version_ <= QUIC_VERSION_31) {
- ack_size += kNumberOfRevivedPacketsSize;
- }
- ack_size += min(ack_info.nack_ranges.size(), kMaxNackRanges) *
- (missing_packet_number_length + PACKET_1BYTE_PACKET_NUMBER);
- }
-
- // In version 23, if the ack will be truncated due to too many nack ranges,
- // then do not include the number of timestamps (1 byte).
- if (ack_info.nack_ranges.size() <= kMaxNackRanges) {
- // 1 byte for the number of timestamps.
- ack_size += 1;
- ack_size += GetAckFrameTimeStampSize(ack);
- }
-
- return ack_size;
- }
-
- NewAckFrameInfo ack_info = GetNewAckFrameInfo(ack);
- QuicPacketNumberLength largest_acked_length =
- GetMinSequenceNumberLength(ack.largest_observed);
- QuicPacketNumberLength ack_block_length =
- GetMinSequenceNumberLength(ack_info.max_block_length);
-
- ack_size = GetMinAckFrameSize(quic_version_, largest_acked_length);
- // First ack block length.
- ack_size += ack_block_length;
- if (!ack_info.ack_blocks.empty()) {
- ack_size += kNumberOfAckBlocksSize;
- ack_size += min(ack_info.ack_blocks.size(), kMaxAckBlocks) *
- (ack_block_length + PACKET_1BYTE_PACKET_NUMBER);
- }
-
- // Include timestamps.
- ack_size += GetAckFrameTimeStampSize(ack);
-
- return ack_size;
-}
-
-size_t QuicFramer::ComputeFrameLength(
- const QuicFrame& frame,
- bool last_frame_in_packet,
- QuicPacketNumberLength packet_number_length) {
- switch (frame.type) {
- case STREAM_FRAME:
- return GetMinStreamFrameSize(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(quic_version_, packet_number_length);
- case MTU_DISCOVERY_FRAME:
- // MTU discovery frames are serialized as ping frames.
- case PING_FRAME:
- // Ping has no payload.
- return kQuicFrameTypeSize;
- case RST_STREAM_FRAME:
- return GetRstStreamFrameSize();
- case CONNECTION_CLOSE_FRAME:
- return GetMinConnectionCloseFrameSize() +
- frame.connection_close_frame->error_details.size();
- case GOAWAY_FRAME:
- return GetMinGoAwayFrameSize() + frame.goaway_frame->reason_phrase.size();
- case WINDOW_UPDATE_FRAME:
- return GetWindowUpdateFrameSize();
- case BLOCKED_FRAME:
- return GetBlockedFrameSize();
- case PATH_CLOSE_FRAME:
- return GetPathCloseFrameSize();
- case PADDING_FRAME:
- DCHECK(false);
- return 0;
- case NUM_FRAME_TYPES:
- DCHECK(false);
- return 0;
- }
-
- // Not reachable, but some Chrome compilers can't figure that out. *sigh*
- DCHECK(false);
- return 0;
-}
-
-bool QuicFramer::AppendTypeByte(const QuicFrame& frame,
- bool no_stream_frame_length,
- QuicDataWriter* writer) {
- uint8_t type_byte = 0;
- switch (frame.type) {
- case STREAM_FRAME: {
- if (frame.stream_frame == nullptr) {
- QUIC_BUG << "Failed to append STREAM frame with no stream_frame.";
- }
- // Fin bit.
- type_byte |= frame.stream_frame->fin ? kQuicStreamFinMask : 0;
-
- // Data Length bit.
- type_byte <<= kQuicStreamDataLengthShift;
- type_byte |= no_stream_frame_length ? 0 : kQuicStreamDataLengthMask;
-
- // Offset 3 bits.
- type_byte <<= kQuicStreamOffsetShift;
- const size_t offset_len = GetStreamOffsetSize(frame.stream_frame->offset);
- if (offset_len > 0) {
- type_byte |= offset_len - 1;
- }
-
- // stream id 2 bits.
- type_byte <<= kQuicStreamIdShift;
- type_byte |= GetStreamIdSize(frame.stream_frame->stream_id) - 1;
- type_byte |= kQuicFrameTypeStreamMask; // Set Stream Frame Type to 1.
- break;
- }
- case ACK_FRAME:
- return true;
- case MTU_DISCOVERY_FRAME:
- type_byte = static_cast<uint8_t>(PING_FRAME);
- break;
- default:
- type_byte = static_cast<uint8_t>(frame.type);
- break;
- }
-
- return writer->WriteUInt8(type_byte);
-}
-
-// static
-bool QuicFramer::AppendPacketSequenceNumber(
- QuicPacketNumberLength packet_number_length,
- QuicPacketNumber packet_number,
- QuicDataWriter* writer) {
- // Ensure the entire packet number can be written.
- if (writer->capacity() - writer->length() <
- static_cast<size_t>(packet_number_length)) {
- return false;
- }
- switch (packet_number_length) {
- case PACKET_1BYTE_PACKET_NUMBER:
- return writer->WriteUInt8(packet_number & k1ByteSequenceNumberMask);
- break;
- case PACKET_2BYTE_PACKET_NUMBER:
- return writer->WriteUInt16(packet_number & k2ByteSequenceNumberMask);
- break;
- case PACKET_4BYTE_PACKET_NUMBER:
- return writer->WriteUInt32(packet_number & k4ByteSequenceNumberMask);
- break;
- case PACKET_6BYTE_PACKET_NUMBER:
- return writer->WriteUInt48(packet_number & k6ByteSequenceNumberMask);
- break;
- default:
- DCHECK(false) << "packet_number_length: " << packet_number_length;
- return false;
- }
-}
-
-bool QuicFramer::AppendStreamFrame(const QuicStreamFrame& frame,
- bool no_stream_frame_length,
- QuicDataWriter* writer) {
- if (!writer->WriteBytes(&frame.stream_id, GetStreamIdSize(frame.stream_id))) {
- QUIC_BUG << "Writing stream id size failed.";
- return false;
- }
- if (!writer->WriteBytes(&frame.offset, GetStreamOffsetSize(frame.offset))) {
- QUIC_BUG << "Writing offset size failed.";
- return false;
- }
- if (!no_stream_frame_length) {
- if ((frame.data_length > numeric_limits<uint16_t>::max()) ||
- !writer->WriteUInt16(static_cast<uint16_t>(frame.data_length))) {
- QUIC_BUG << "Writing stream frame length failed";
- return false;
- }
- }
-
- if (!writer->WriteBytes(frame.data_buffer, frame.data_length)) {
- QUIC_BUG << "Writing frame data failed.";
- return false;
- }
- return true;
-}
-
-void QuicFramer::set_version(const QuicVersion version) {
- DCHECK(IsSupportedVersion(version)) << QuicVersionToString(version);
- quic_version_ = version;
-}
-
-bool QuicFramer::AppendAckFrameAndTypeByte(const QuicPacketHeader& header,
- const QuicAckFrame& frame,
- QuicDataWriter* writer) {
- AckFrameInfo ack_info = GetAckFrameInfo(frame);
- QuicPacketNumber ack_largest_observed = frame.largest_observed;
- QuicPacketNumberLength largest_observed_length =
- GetMinSequenceNumberLength(ack_largest_observed);
- QuicPacketNumberLength missing_packet_number_length =
- GetMinSequenceNumberLength(ack_info.max_delta);
- // Determine whether we need to truncate ranges.
- size_t available_range_bytes =
- writer->capacity() - writer->length() - kNumberOfNackRangesSize -
- GetMinAckFrameSize(quic_version_, largest_observed_length);
- if (quic_version_ <= QUIC_VERSION_31) {
- available_range_bytes -= kNumberOfRevivedPacketsSize;
- }
- size_t max_num_ranges =
- available_range_bytes /
- (missing_packet_number_length + PACKET_1BYTE_PACKET_NUMBER);
- max_num_ranges = min(kMaxNackRanges, max_num_ranges);
- bool truncated = ack_info.nack_ranges.size() > max_num_ranges;
- DVLOG_IF(1, truncated) << "Truncating ack from "
- << ack_info.nack_ranges.size() << " ranges to "
- << max_num_ranges;
- // Write out the type byte by setting the low order bits and doing shifts
- // to make room for the next bit flags to be set.
- // Whether there are any nacks.
- uint8_t type_byte = ack_info.nack_ranges.empty() ? 0 : kQuicHasNacksMask;
-
- // truncating bit.
- type_byte <<= kQuicAckTruncatedShift;
- type_byte |= truncated ? kQuicAckTruncatedMask : 0;
-
- // Largest observed packet number length.
- type_byte <<= kQuicSequenceNumberLengthShift;
- type_byte |= GetSequenceNumberFlags(largest_observed_length);
-
- // Missing packet number length.
- type_byte <<= kQuicSequenceNumberLengthShift;
- type_byte |= GetSequenceNumberFlags(missing_packet_number_length);
-
- type_byte |= kQuicFrameTypeAckMask;
-
- if (!writer->WriteUInt8(type_byte)) {
- QUIC_BUG << "type byte failed";
- return false;
- }
-
- QuicPacketEntropyHash ack_entropy_hash = frame.entropy_hash;
- NackRangeMap::reverse_iterator ack_iter = ack_info.nack_ranges.rbegin();
- if (truncated) {
- // Skip the nack ranges which the truncated ack won't include and set
- // a correct largest observed for the truncated ack.
- for (size_t i = 1; i < (ack_info.nack_ranges.size() - max_num_ranges);
- ++i) {
- ++ack_iter;
- }
- // If the last range is followed by acks, include them.
- // If the last range is followed by another range, specify the end of the
- // range as the largest_observed.
- ack_largest_observed = ack_iter->first - 1;
- // Also update the entropy so it matches the largest observed.
- ack_entropy_hash = entropy_calculator_->EntropyHash(ack_largest_observed);
- ++ack_iter;
- }
-
- if (!writer->WriteUInt8(ack_entropy_hash)) {
- QUIC_BUG << "hash failed.";
- return false;
- }
-
- if (!AppendPacketSequenceNumber(largest_observed_length, ack_largest_observed,
- writer)) {
- QUIC_BUG << "AppendPacketSequenceNumber failed. "
- << "largest_observed_length: " << largest_observed_length
- << " ack_largest_observed: " << ack_largest_observed;
- return false;
- }
-
- uint64_t ack_delay_time_us = kUFloat16MaxValue;
- if (!frame.ack_delay_time.IsInfinite()) {
- DCHECK_LE(0u, frame.ack_delay_time.ToMicroseconds());
- ack_delay_time_us = frame.ack_delay_time.ToMicroseconds();
- }
-
- if (!writer->WriteUFloat16(ack_delay_time_us)) {
- QUIC_BUG << "ack delay time failed.";
- return false;
- }
-
- // Timestamp goes at the end of the required fields.
- if (!truncated) {
- if (!AppendTimestampToAckFrame(frame, writer)) {
- QUIC_BUG << "AppendTimestampToAckFrame failed";
- return false;
- }
- }
-
- if (ack_info.nack_ranges.empty()) {
- return true;
- }
-
- const uint8_t num_missing_ranges =
- static_cast<uint8_t>(min(ack_info.nack_ranges.size(), max_num_ranges));
- if (!writer->WriteBytes(&num_missing_ranges, 1)) {
- QUIC_BUG << "num_missing_ranges failed: "
- << static_cast<uint32_t>(num_missing_ranges);
- return false;
- }
-
- int num_ranges_written = 0;
- QuicPacketNumber last_sequence_written = ack_largest_observed;
- for (; ack_iter != ack_info.nack_ranges.rend(); ++ack_iter) {
- // Calculate the delta to the last number in the range.
- QuicPacketNumber missing_delta =
- last_sequence_written - (ack_iter->first + ack_iter->second);
- if (!AppendPacketSequenceNumber(missing_packet_number_length, missing_delta,
- writer)) {
- QUIC_BUG << "AppendPacketSequenceNumber failed: "
- << "missing_packet_number_length: "
- << missing_packet_number_length << " missing_delta "
- << missing_delta;
- return false;
- }
- if (!AppendPacketSequenceNumber(PACKET_1BYTE_PACKET_NUMBER,
- ack_iter->second, writer)) {
- QUIC_BUG << "AppendPacketSequenceNumber failed";
- return false;
- }
- // Subtract 1 so a missing_delta of 0 means an adjacent range.
- last_sequence_written = ack_iter->first - 1;
- ++num_ranges_written;
- }
- DCHECK_EQ(num_missing_ranges, num_ranges_written);
-
- if (quic_version_ > QUIC_VERSION_31) {
- return true;
- }
-
- // Append revived packets.
- // FEC is not supported.
- uint8_t num_revived_packets = 0;
- if (!writer->WriteBytes(&num_revived_packets, 1)) {
- QUIC_BUG << "num_revived_packets failed: " << num_revived_packets;
- return false;
- }
-
- return true;
-}
-
-bool QuicFramer::AppendNewAckFrameAndTypeByte(const QuicAckFrame& frame,
- QuicDataWriter* writer) {
- NewAckFrameInfo new_ack_info = GetNewAckFrameInfo(frame);
- QuicPacketNumber largest_acked = frame.largest_observed;
- QuicPacketNumberLength largest_acked_length =
- GetMinSequenceNumberLength(largest_acked);
- QuicPacketNumberLength ack_block_length =
- GetMinSequenceNumberLength(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(quic_version_, largest_acked_length) -
- (!new_ack_info.ack_blocks.empty() ? kNumberOfAckBlocksSize : 0);
- DCHECK_LE(0, available_timestamp_and_ack_block_bytes);
-
- // Write out the type byte by setting the low order bits and doing shifts
- // to make room for the next bit flags to be set.
- // Whether there are multiple ack blocks.
- uint8_t type_byte =
- new_ack_info.ack_blocks.empty() ? 0 : kQuicHasMultipleAckBlocksMask;
- type_byte <<= kQuicHasMultipleAckBlocksShift;
-
- // Largest acked length.
- type_byte <<= kQuicSequenceNumberLengthShift;
- type_byte |= GetSequenceNumberFlags(largest_acked_length);
-
- // Ack block length.
- type_byte <<= kQuicSequenceNumberLengthShift;
- type_byte |= GetSequenceNumberFlags(ack_block_length);
-
- type_byte |= kQuicFrameTypeAckMask;
-
- if (!writer->WriteUInt8(type_byte)) {
- return false;
- }
-
- // Largest acked.
- if (!AppendPacketSequenceNumber(largest_acked_length, largest_acked,
- writer)) {
- return false;
- }
-
- // Largest acked delta time.
- uint64_t ack_delay_time_us = kUFloat16MaxValue;
- if (!frame.ack_delay_time.IsInfinite()) {
- DCHECK_LE(0u, frame.ack_delay_time.ToMicroseconds());
- ack_delay_time_us = frame.ack_delay_time.ToMicroseconds();
- }
- if (!writer->WriteUFloat16(ack_delay_time_us)) {
- return false;
- }
-
- size_t max_num_ack_blocks = available_timestamp_and_ack_block_bytes /
- (ack_block_length + PACKET_1BYTE_PACKET_NUMBER);
-
- // Number of ack blocks.
- size_t num_ack_blocks =
- min(new_ack_info.ack_blocks.size(), max_num_ack_blocks);
- if (num_ack_blocks > numeric_limits<uint8_t>::max()) {
- num_ack_blocks = numeric_limits<uint8_t>::max();
- }
-
- if (num_ack_blocks > 0) {
- if (!writer->WriteBytes(&num_ack_blocks, 1)) {
- return false;
- }
- }
-
- // First ack block length.
- if (!AppendPacketSequenceNumber(ack_block_length,
- new_ack_info.first_block_length, writer)) {
- return false;
- }
-
- // Ack blocks.
- if (num_ack_blocks > 0) {
- std::vector<AckBlock>::reverse_iterator iter =
- new_ack_info.ack_blocks.rbegin();
- size_t num_ack_blocks_written = 0;
- for (; iter != new_ack_info.ack_blocks.rend(); ++iter) {
- if (!AppendPacketSequenceNumber(PACKET_1BYTE_PACKET_NUMBER, iter->gap,
- writer)) {
- return false;
- }
- if (!AppendPacketSequenceNumber(ack_block_length, iter->length, writer)) {
- return false;
- }
- if (++num_ack_blocks_written == num_ack_blocks) {
- break;
- }
- }
- DCHECK_EQ(num_ack_blocks, num_ack_blocks_written);
- }
-
- // Timestamps.
- // If we don't have enough available space to append all the timestamps, don't
- // append any of them.
- if (writer->capacity() - writer->length() >=
- GetAckFrameTimeStampSize(frame)) {
- if (!AppendTimestampToAckFrame(frame, writer)) {
- return false;
- }
- } else {
- uint8_t num_received_packets = 0;
- if (!writer->WriteBytes(&num_received_packets, 1)) {
- return false;
- }
- }
-
- return true;
-}
-
-bool QuicFramer::AppendTimestampToAckFrame(const QuicAckFrame& frame,
- QuicDataWriter* writer) {
- DCHECK_GE(numeric_limits<uint8_t>::max(), frame.received_packet_times.size());
- // num_received_packets is only 1 byte.
- if (frame.received_packet_times.size() > numeric_limits<uint8_t>::max()) {
- return false;
- }
-
- uint8_t num_received_packets = frame.received_packet_times.size();
- if (!writer->WriteBytes(&num_received_packets, 1)) {
- return false;
- }
- if (num_received_packets == 0) {
- return true;
- }
-
- PacketTimeVector::const_iterator it = frame.received_packet_times.begin();
- QuicPacketNumber packet_number = it->first;
- QuicPacketNumber delta_from_largest_observed =
- frame.largest_observed - packet_number;
-
- DCHECK_GE(numeric_limits<uint8_t>::max(), delta_from_largest_observed);
- if (delta_from_largest_observed > numeric_limits<uint8_t>::max()) {
- return false;
- }
-
- if (!writer->WriteUInt8(delta_from_largest_observed &
- k1ByteSequenceNumberMask)) {
- return false;
- }
-
- // Use the lowest 4 bytes of the time delta from the creation_time_.
- const uint64_t time_epoch_delta_us = UINT64_C(1) << 32;
- uint32_t time_delta_us = static_cast<uint32_t>(
- it->second.Subtract(creation_time_).ToMicroseconds() &
- (time_epoch_delta_us - 1));
- if (!writer->WriteBytes(&time_delta_us, sizeof(time_delta_us))) {
- return false;
- }
-
- QuicTime prev_time = it->second;
-
- for (++it; it != frame.received_packet_times.end(); ++it) {
- packet_number = it->first;
- delta_from_largest_observed = frame.largest_observed - packet_number;
-
- if (delta_from_largest_observed > numeric_limits<uint8_t>::max()) {
- return false;
- }
-
- if (!writer->WriteUInt8(delta_from_largest_observed &
- k1ByteSequenceNumberMask)) {
- return false;
- }
-
- uint64_t frame_time_delta_us =
- it->second.Subtract(prev_time).ToMicroseconds();
- prev_time = it->second;
- if (!writer->WriteUFloat16(frame_time_delta_us)) {
- return false;
- }
- }
- return true;
-}
-
-bool QuicFramer::AppendStopWaitingFrame(const QuicPacketHeader& header,
- const QuicStopWaitingFrame& frame,
- QuicDataWriter* writer) {
- DCHECK_GE(header.packet_number, frame.least_unacked);
- const QuicPacketNumber least_unacked_delta =
- header.packet_number - frame.least_unacked;
- const QuicPacketNumber length_shift =
- header.public_header.packet_number_length * 8;
- if (quic_version_ <= QUIC_VERSION_33) {
- if (!writer->WriteUInt8(frame.entropy_hash)) {
- QUIC_BUG << " hash failed";
- return false;
- }
- }
-
- if (least_unacked_delta >> length_shift > 0) {
- QUIC_BUG << "packet_number_length "
- << header.public_header.packet_number_length
- << " is too small for least_unacked_delta: " << least_unacked_delta
- << " packet_number:" << header.packet_number
- << " least_unacked:" << frame.least_unacked
- << " version:" << quic_version_;
- return false;
- }
- if (!AppendPacketSequenceNumber(header.public_header.packet_number_length,
- least_unacked_delta, writer)) {
- QUIC_BUG << " seq failed: " << header.public_header.packet_number_length;
- return false;
- }
-
- return true;
-}
-
-bool QuicFramer::AppendRstStreamFrame(const QuicRstStreamFrame& frame,
- QuicDataWriter* writer) {
- if (!writer->WriteUInt32(frame.stream_id)) {
- return false;
- }
-
- if (!writer->WriteUInt64(frame.byte_offset)) {
- return false;
- }
-
- uint32_t error_code = static_cast<uint32_t>(frame.error_code);
- if (!writer->WriteUInt32(error_code)) {
- return false;
- }
-
- return true;
-}
-
-bool QuicFramer::AppendConnectionCloseFrame(
- const QuicConnectionCloseFrame& frame,
- QuicDataWriter* writer) {
- uint32_t error_code = static_cast<uint32_t>(frame.error_code);
- if (!writer->WriteUInt32(error_code)) {
- return false;
- }
- if (!writer->WriteStringPiece16(frame.error_details)) {
- return false;
- }
- return true;
-}
-
-bool QuicFramer::AppendGoAwayFrame(const QuicGoAwayFrame& frame,
- QuicDataWriter* writer) {
- uint32_t error_code = static_cast<uint32_t>(frame.error_code);
- if (!writer->WriteUInt32(error_code)) {
- return false;
- }
- uint32_t stream_id = static_cast<uint32_t>(frame.last_good_stream_id);
- if (!writer->WriteUInt32(stream_id)) {
- return false;
- }
- if (!writer->WriteStringPiece16(frame.reason_phrase)) {
- return false;
- }
- return true;
-}
-
-bool QuicFramer::AppendWindowUpdateFrame(const QuicWindowUpdateFrame& frame,
- QuicDataWriter* writer) {
- uint32_t stream_id = static_cast<uint32_t>(frame.stream_id);
- if (!writer->WriteUInt32(stream_id)) {
- return false;
- }
- if (!writer->WriteUInt64(frame.byte_offset)) {
- return false;
- }
- return true;
-}
-
-bool QuicFramer::AppendBlockedFrame(const QuicBlockedFrame& frame,
- QuicDataWriter* writer) {
- uint32_t stream_id = static_cast<uint32_t>(frame.stream_id);
- if (!writer->WriteUInt32(stream_id)) {
- return false;
- }
- return true;
-}
-
-bool QuicFramer::AppendPathCloseFrame(const QuicPathCloseFrame& frame,
- QuicDataWriter* writer) {
- uint8_t path_id = static_cast<uint8_t>(frame.path_id);
- if (!writer->WriteUInt8(path_id)) {
- return false;
- }
- return true;
-}
-
-bool QuicFramer::RaiseError(QuicErrorCode error) {
- DVLOG(1) << "Error: " << QuicUtils::ErrorToString(error)
- << " detail: " << detailed_error_;
- set_error(error);
- visitor_->OnError(this);
- return false;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_framer.h b/chromium/net/quic/quic_framer.h
deleted file mode 100644
index 383b3fd6d5c..00000000000
--- a/chromium/net/quic/quic_framer.h
+++ /dev/null
@@ -1,617 +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.
-
-#ifndef NET_QUIC_QUIC_FRAMER_H_
-#define NET_QUIC_QUIC_FRAMER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-namespace test {
-class QuicFramerPeer;
-} // namespace test
-
-class QuicDataReader;
-class QuicDataWriter;
-class QuicDecrypter;
-class QuicEncrypter;
-class QuicFramer;
-
-// Number of bytes reserved for the frame type preceding each frame.
-const size_t kQuicFrameTypeSize = 1;
-// Number of bytes reserved for error code.
-const size_t kQuicErrorCodeSize = 4;
-// Number of bytes reserved to denote the length of error details field.
-const size_t kQuicErrorDetailsLengthSize = 2;
-
-// Maximum number of bytes reserved for stream id.
-const size_t kQuicMaxStreamIdSize = 4;
-// Maximum number of bytes reserved for byte offset in stream frame.
-const size_t kQuicMaxStreamOffsetSize = 8;
-// Number of bytes reserved to store payload length in stream frame.
-const size_t kQuicStreamPayloadLengthSize = 2;
-
-// Size in bytes of the entropy hash sent in ack frames.
-const size_t kQuicEntropyHashSize = 1;
-// Size in bytes reserved for the delta time of the largest observed
-// packet number in ack frames.
-const size_t kQuicDeltaTimeLargestObservedSize = 2;
-// Size in bytes reserved for the number of received packets with timestamps.
-const size_t kQuicNumTimestampsSize = 1;
-// Size in bytes reserved for the number of missing packets in ack frames.
-const size_t kNumberOfNackRangesSize = 1;
-// Size in bytes reserved for the number of ack blocks in ack frames.
-const size_t kNumberOfAckBlocksSize = 1;
-// Maximum number of missing packet ranges that can fit within an ack frame.
-const size_t kMaxNackRanges = (1 << (kNumberOfNackRangesSize * 8)) - 1;
-// Maximum number of ack blocks that can fit within an ack frame.
-const size_t kMaxAckBlocks = (1 << (kNumberOfAckBlocksSize * 8)) - 1;
-// Size in bytes reserved for the number of revived packets in ack frames.
-const size_t kNumberOfRevivedPacketsSize = 1;
-
-// This class receives callbacks from the framer when packets
-// are processed.
-class NET_EXPORT_PRIVATE QuicFramerVisitorInterface {
- public:
- virtual ~QuicFramerVisitorInterface() {}
-
- // Called if an error is detected in the QUIC protocol.
- virtual void OnError(QuicFramer* framer) = 0;
-
- // Called only when |perspective_| is IS_SERVER and the the framer gets a
- // packet with version flag true and the version on the packet doesn't match
- // |quic_version_|. The visitor should return true after it updates the
- // version of the |framer_| to |received_version| or false to stop processing
- // this packet.
- virtual bool OnProtocolVersionMismatch(QuicVersion received_version) = 0;
-
- // Called when a new packet has been received, before it
- // has been validated or processed.
- virtual void OnPacket() = 0;
-
- // Called when a public reset packet has been parsed but has not yet
- // been validated.
- virtual void OnPublicResetPacket(const QuicPublicResetPacket& packet) = 0;
-
- // Called only when |perspective_| is IS_CLIENT and a version negotiation
- // packet has been parsed.
- virtual void OnVersionNegotiationPacket(
- const QuicVersionNegotiationPacket& packet) = 0;
-
- // Called when the public header has been parsed, but has not been
- // authenticated. If it returns false, framing for this packet will cease.
- virtual bool OnUnauthenticatedPublicHeader(
- const QuicPacketPublicHeader& header) = 0;
-
- // Called when the unauthenticated portion of the header has been parsed.
- // If OnUnauthenticatedHeader returns false, framing for this packet will
- // cease.
- virtual bool OnUnauthenticatedHeader(const QuicPacketHeader& header) = 0;
-
- // Called when a packet has been decrypted. |level| is the encryption level
- // of the packet.
- virtual void OnDecryptedPacket(EncryptionLevel level) = 0;
-
- // Called when the complete header of a packet had been parsed.
- // If OnPacketHeader returns false, framing for this packet will cease.
- virtual bool OnPacketHeader(const QuicPacketHeader& header) = 0;
-
- // Called when a StreamFrame has been parsed.
- virtual bool OnStreamFrame(const QuicStreamFrame& frame) = 0;
-
- // Called when a AckFrame has been parsed. If OnAckFrame returns false,
- // the framer will stop parsing the current packet.
- virtual bool OnAckFrame(const QuicAckFrame& frame) = 0;
-
- // Called when a StopWaitingFrame has been parsed.
- virtual bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) = 0;
-
- // Called when a QuicPaddingFrame has been parsed.
- virtual bool OnPaddingFrame(const QuicPaddingFrame& frame) = 0;
-
- // Called when a PingFrame has been parsed.
- virtual bool OnPingFrame(const QuicPingFrame& frame) = 0;
-
- // Called when a RstStreamFrame has been parsed.
- virtual bool OnRstStreamFrame(const QuicRstStreamFrame& frame) = 0;
-
- // Called when a ConnectionCloseFrame has been parsed.
- virtual bool OnConnectionCloseFrame(
- const QuicConnectionCloseFrame& frame) = 0;
-
- // Called when a GoAwayFrame has been parsed.
- virtual bool OnGoAwayFrame(const QuicGoAwayFrame& frame) = 0;
-
- // Called when a WindowUpdateFrame has been parsed.
- virtual bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) = 0;
-
- // Called when a BlockedFrame has been parsed.
- virtual bool OnBlockedFrame(const QuicBlockedFrame& frame) = 0;
-
- // Called when a PathCloseFrame has been parsed.
- virtual bool OnPathCloseFrame(const QuicPathCloseFrame& frame) = 0;
-
- // Called when a packet has been completely processed.
- virtual void OnPacketComplete() = 0;
-};
-
-// This class calculates the received entropy of the ack packet being
-// framed, should it get truncated.
-class NET_EXPORT_PRIVATE QuicReceivedEntropyHashCalculatorInterface {
- public:
- virtual ~QuicReceivedEntropyHashCalculatorInterface() {}
-
- // When an ack frame gets truncated while being framed the received
- // entropy of the ack frame needs to be calculated since the some of the
- // missing packets are not added and the largest observed might be lowered.
- // This should return the received entropy hash of the packets received up to
- // and including |packet_number|.
- virtual QuicPacketEntropyHash EntropyHash(
- QuicPacketNumber packet_number) const = 0;
-};
-
-// Class for parsing and constructing QUIC packets. It has a
-// QuicFramerVisitorInterface that is called when packets are parsed.
-class NET_EXPORT_PRIVATE QuicFramer {
- public:
- // Constructs a new framer that installs a kNULL QuicEncrypter and
- // 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 QuicVersionVector& supported_versions,
- QuicTime creation_time,
- Perspective perspective);
-
- virtual ~QuicFramer();
-
- // Returns true if |version| is a supported protocol version.
- bool IsSupportedVersion(const QuicVersion 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
- // to do nothing. If this is called multiple times, only the last visitor
- // will be used.
- void set_visitor(QuicFramerVisitorInterface* visitor) { visitor_ = visitor; }
-
- const QuicVersionVector& supported_versions() const {
- return supported_versions_;
- }
-
- QuicVersion version() const { return quic_version_; }
-
- void set_version(const QuicVersion version);
-
- // Does not DCHECK for supported version. Used by tests to set unsupported
- // version to trigger version negotiation.
- void set_version_for_tests(const QuicVersion version) {
- quic_version_ = version;
- }
-
- // Set entropy calculator to be called from the framer when it needs the
- // entropy of a truncated ack frame. An entropy calculator must be set or else
- // the framer will likely crash. If this is called multiple times, only the
- // last calculator will be used.
- void set_received_entropy_calculator(
- QuicReceivedEntropyHashCalculatorInterface* entropy_calculator) {
- entropy_calculator_ = entropy_calculator;
- }
-
- QuicErrorCode error() const { return error_; }
-
- // Pass a UDP packet into the framer for parsing.
- // Return true if the packet was processed succesfully. |packet| must be a
- // single, complete UDP packet (not a frame of a packet). This packet
- // might be null padded past the end of the payload, which will be correctly
- // ignored.
- bool ProcessPacket(const QuicEncryptedPacket& packet);
-
- // Largest size in bytes of all stream frame fields without the payload.
- static size_t GetMinStreamFrameSize(QuicStreamId stream_id,
- QuicStreamOffset offset,
- bool last_frame_in_packet);
- // Size in bytes of all ack frame fields without the missing packets or ack
- // blocks.
- static size_t GetMinAckFrameSize(
- QuicVersion version,
- QuicPacketNumberLength largest_observed_length);
- // Size in bytes of a stop waiting frame.
- static size_t GetStopWaitingFrameSize(
- QuicVersion version,
- QuicPacketNumberLength packet_number_length);
- // Size in bytes of all reset stream frame without the error details.
- // Used before QUIC_VERSION_25.
- static size_t GetMinRstStreamFrameSize();
- // Size in bytes of all reset stream frame fields.
- static size_t GetRstStreamFrameSize();
- // Size in bytes of all connection close frame fields without the error
- // details and the missing packets from the enclosed ack frame.
- static size_t GetMinConnectionCloseFrameSize();
- // Size in bytes of all GoAway frame fields without the reason phrase.
- static size_t GetMinGoAwayFrameSize();
- // Size in bytes of all WindowUpdate frame fields.
- static size_t GetWindowUpdateFrameSize();
- // Size in bytes of all Blocked frame fields.
- static size_t GetBlockedFrameSize();
- // Size in bytes of all PathClose frame fields.
- static size_t GetPathCloseFrameSize();
- // Size in bytes required to serialize the stream id.
- static size_t GetStreamIdSize(QuicStreamId stream_id);
- // Size in bytes required to serialize the stream offset.
- static size_t GetStreamOffsetSize(QuicStreamOffset offset);
- // Size in bytes required for a serialized version negotiation packet
- static size_t GetVersionNegotiationPacketSize(size_t number_versions);
-
- // Returns the number of bytes added to the packet for the specified frame,
- // and 0 if the frame doesn't fit. Includes the header size for the first
- // frame.
- size_t GetSerializedFrameLength(const QuicFrame& frame,
- size_t free_bytes,
- bool first_frame_in_packet,
- bool last_frame_in_packet,
- QuicPacketNumberLength packet_number_length);
-
- // Returns the associated data from the encrypted packet |encrypted| as a
- // stringpiece.
- static base::StringPiece GetAssociatedDataFromEncryptedPacket(
- QuicVersion version,
- const QuicEncryptedPacket& encrypted,
- QuicConnectionIdLength connection_id_length,
- bool includes_version,
- bool includes_path_id,
- bool includes_diversification_nonce,
- QuicPacketNumberLength packet_number_length);
-
- // Serializes a packet containing |frames| into |buffer|.
- // Returns the length of the packet, which must not be longer than
- // |packet_length|. Returns 0 if it fails to serialize.
- size_t BuildDataPacket(const QuicPacketHeader& header,
- const QuicFrames& frames,
- char* buffer,
- size_t packet_length);
-
- // Returns a new public reset packet, owned by the caller.
- static QuicEncryptedPacket* BuildPublicResetPacket(
- const QuicPublicResetPacket& packet);
-
- // Returns a new version negotiation packet, owned by the caller.
- static QuicEncryptedPacket* BuildVersionNegotiationPacket(
- QuicConnectionId connection_id,
- const QuicVersionVector& versions);
-
- // If header.public_header.version_flag is set, the version in the
- // packet will be set -- but it will be set from quic_version_ not
- // header.public_header.versions.
- bool AppendPacketHeader(const QuicPacketHeader& header,
- QuicDataWriter* writer);
- bool AppendTypeByte(const QuicFrame& frame,
- bool last_frame_in_packet,
- QuicDataWriter* writer);
- bool AppendStreamFrame(const QuicStreamFrame& frame,
- bool last_frame_in_packet,
- QuicDataWriter* builder);
-
- // SetDecrypter sets the primary decrypter, replacing any that already exists,
- // and takes ownership. If an alternative decrypter is in place then the
- // function DCHECKs. This is intended for cases where one knows that future
- // packets will be using the new decrypter and the previous decrypter is now
- // obsolete. |level| indicates the encryption level of the new decrypter.
- void SetDecrypter(EncryptionLevel level, QuicDecrypter* decrypter);
-
- // SetAlternativeDecrypter sets a decrypter that may be used to decrypt
- // future packets and takes ownership of it. |level| indicates the encryption
- // level of the decrypter. If |latch_once_used| is true, then the first time
- // that the decrypter is successful it will replace the primary decrypter.
- // Otherwise both decrypters will remain active and the primary decrypter
- // will be the one last used.
- void SetAlternativeDecrypter(EncryptionLevel level,
- QuicDecrypter* decrypter,
- bool latch_once_used);
-
- const QuicDecrypter* decrypter() const;
- const QuicDecrypter* alternative_decrypter() const;
-
- // Changes the encrypter used for level |level| to |encrypter|. The function
- // takes ownership of |encrypter|.
- void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter);
-
- // Encrypts a payload in |buffer|. |ad_len| is the length of the associated
- // data. |total_len| is the length of the associated data plus plaintext.
- // |buffer_len| is the full length of the allocated buffer.
- size_t EncryptInPlace(EncryptionLevel level,
- QuicPathId path_id,
- QuicPacketNumber packet_number,
- size_t ad_len,
- size_t total_len,
- size_t buffer_len,
- char* buffer);
-
- // Returns the length of the data encrypted into |buffer| if |buffer_len| is
- // long enough, and otherwise 0.
- size_t EncryptPayload(EncryptionLevel level,
- QuicPathId path_id,
- QuicPacketNumber packet_number,
- const QuicPacket& packet,
- char* buffer,
- size_t buffer_len);
-
- // Returns the maximum length of plaintext that can be encrypted
- // to ciphertext no larger than |ciphertext_size|.
- size_t GetMaxPlaintextSize(size_t ciphertext_size);
-
- const std::string& detailed_error() { return detailed_error_; }
-
- // The minimum packet number length required to represent |packet_number|.
- static QuicPacketNumberLength GetMinSequenceNumberLength(
- QuicPacketNumber packet_number);
-
- void SetSupportedVersions(const QuicVersionVector& versions) {
- supported_versions_ = versions;
- quic_version_ = versions[0];
- }
-
- void set_validate_flags(bool value) { validate_flags_ = value; }
-
- Perspective perspective() const { return perspective_; }
-
- static QuicPacketEntropyHash GetPacketEntropyHash(
- const QuicPacketHeader& header);
-
- // Called when a PATH_CLOSED frame has been sent/received on |path_id|.
- void OnPathClosed(QuicPathId path_id);
-
- QuicTag last_version_tag() { return last_version_tag_; }
-
- private:
- friend class test::QuicFramerPeer;
-
- typedef std::map<QuicPacketNumber, uint8_t> NackRangeMap;
-
- struct AckFrameInfo {
- AckFrameInfo();
- AckFrameInfo(const AckFrameInfo& other);
- ~AckFrameInfo();
-
- // The maximum delta between ranges.
- QuicPacketNumber max_delta;
- // Nack ranges starting with start packet numbers and lengths.
- NackRangeMap nack_ranges;
- };
-
- struct AckBlock {
- AckBlock(uint8_t gap, QuicPacketNumber length);
- AckBlock(const AckBlock& other);
- ~AckBlock();
-
- // Gap to the next ack block.
- uint8_t gap;
- // Length of this ack block.
- QuicPacketNumber length;
- };
-
- struct NewAckFrameInfo {
- NewAckFrameInfo();
- NewAckFrameInfo(const NewAckFrameInfo& other);
- ~NewAckFrameInfo();
-
- // The maximum ack block length.
- QuicPacketNumber max_block_length;
- // Length of first ack block.
- QuicPacketNumber first_block_length;
- // Ack blocks starting with gaps to next block and ack block lengths.
- std::vector<AckBlock> ack_blocks;
- };
-
- bool ProcessDataPacket(QuicDataReader* reader,
- const QuicPacketPublicHeader& public_header,
- const QuicEncryptedPacket& packet,
- char* decrypted_buffer,
- size_t buffer_length);
-
- bool ProcessPublicResetPacket(QuicDataReader* reader,
- const QuicPacketPublicHeader& public_header);
-
- bool ProcessVersionNegotiationPacket(QuicDataReader* reader,
- QuicPacketPublicHeader* public_header);
-
- bool ProcessPublicHeader(QuicDataReader* reader,
- QuicPacketPublicHeader* header);
-
- // Processes the unauthenticated portion of the header into |header| from
- // the current QuicDataReader. Returns true on success, false on failure.
- bool ProcessUnauthenticatedHeader(QuicDataReader* encrypted_reader,
- QuicPacketHeader* header);
-
- // Processes the authenticated portion of the header into |header| from
- // the current QuicDataReader. Returns true on success, false on failure.
- bool ProcessAuthenticatedHeader(QuicDataReader* reader,
- QuicPacketHeader* header);
-
- bool ProcessPathId(QuicDataReader* reader, QuicPathId* path_id);
- bool ProcessPacketSequenceNumber(QuicDataReader* reader,
- QuicPacketNumberLength packet_number_length,
- QuicPacketNumber last_packet_number,
- QuicPacketNumber* packet_number);
- bool ProcessFrameData(QuicDataReader* reader, const QuicPacketHeader& header);
- bool ProcessStreamFrame(QuicDataReader* reader,
- uint8_t frame_type,
- QuicStreamFrame* frame);
- bool ProcessAckFrame(QuicDataReader* reader,
- uint8_t frame_type,
- QuicAckFrame* frame);
- bool ProcessNewAckFrame(QuicDataReader* reader,
- uint8_t frame_type,
- QuicAckFrame* frame);
- bool ProcessTimestampsInAckFrame(QuicDataReader* reader, QuicAckFrame* frame);
- bool ProcessStopWaitingFrame(QuicDataReader* reader,
- const QuicPacketHeader& public_header,
- QuicStopWaitingFrame* stop_waiting);
- bool ProcessRstStreamFrame(QuicDataReader* reader, QuicRstStreamFrame* frame);
- bool ProcessConnectionCloseFrame(QuicDataReader* reader,
- QuicConnectionCloseFrame* frame);
- bool ProcessGoAwayFrame(QuicDataReader* reader, QuicGoAwayFrame* frame);
- bool ProcessWindowUpdateFrame(QuicDataReader* reader,
- QuicWindowUpdateFrame* frame);
- bool ProcessBlockedFrame(QuicDataReader* reader, QuicBlockedFrame* frame);
- bool ProcessPathCloseFrame(QuicDataReader* reader, QuicPathCloseFrame* frame);
-
- bool DecryptPayload(QuicDataReader* encrypted_reader,
- const QuicPacketHeader& header,
- const QuicEncryptedPacket& packet,
- char* decrypted_buffer,
- size_t buffer_length,
- size_t* decrypted_length);
-
- // Checks if |path_id| is a viable path to receive packets on. Returns true
- // and sets |last_packet_number| if the path is not closed. Returns false
- // otherwise.
- bool IsValidPath(QuicPathId path_id, QuicPacketNumber* last_packet_number);
-
- // Sets last_packet_number_. This can only be called after the packet is
- // successfully decrypted.
- void SetLastPacketNumber(const QuicPacketHeader& header);
-
- // Returns the full packet number from the truncated
- // wire format version and the last seen packet number.
- QuicPacketNumber CalculatePacketNumberFromWire(
- QuicPacketNumberLength packet_number_length,
- QuicPacketNumber last_packet_number,
- QuicPacketNumber packet_number) const;
-
- // Returns the QuicTime::Delta corresponding to the time from when the framer
- // was created.
- const QuicTime::Delta CalculateTimestampFromWire(uint32_t time_delta_us);
-
- // Computes the wire size in bytes of time stamps in |ack|.
- size_t GetAckFrameTimeStampSize(const QuicAckFrame& ack);
-
- // Computes the wire size in bytes of the |ack| frame, assuming no truncation.
- size_t GetAckFrameSize(const QuicAckFrame& ack,
- QuicPacketNumberLength packet_number_length);
-
- // Computes the wire size in bytes of the |ack| frame.
- size_t GetNewAckFrameSize(const QuicAckFrame& ack);
-
- // Computes the wire size in bytes of the payload of |frame|.
- size_t ComputeFrameLength(const QuicFrame& frame,
- bool last_frame_in_packet,
- QuicPacketNumberLength packet_number_length);
-
- static bool AppendPacketSequenceNumber(
- QuicPacketNumberLength packet_number_length,
- QuicPacketNumber packet_number,
- QuicDataWriter* writer);
-
- static uint8_t GetSequenceNumberFlags(
- QuicPacketNumberLength packet_number_length);
-
- static AckFrameInfo GetAckFrameInfo(const QuicAckFrame& frame);
-
- static NewAckFrameInfo GetNewAckFrameInfo(const QuicAckFrame& frame);
-
- // The Append* methods attempt to write the provided header or frame using the
- // |writer|, and return true if successful.
-
- bool AppendAckFrameAndTypeByte(const QuicPacketHeader& header,
- const QuicAckFrame& frame,
- QuicDataWriter* builder);
- bool AppendNewAckFrameAndTypeByte(const QuicAckFrame& frame,
- QuicDataWriter* builder);
- bool AppendTimestampToAckFrame(const QuicAckFrame& frame,
- QuicDataWriter* builder);
- bool AppendStopWaitingFrame(const QuicPacketHeader& header,
- const QuicStopWaitingFrame& frame,
- QuicDataWriter* builder);
- bool AppendRstStreamFrame(const QuicRstStreamFrame& frame,
- QuicDataWriter* builder);
- bool AppendConnectionCloseFrame(const QuicConnectionCloseFrame& frame,
- QuicDataWriter* builder);
- bool AppendGoAwayFrame(const QuicGoAwayFrame& frame, QuicDataWriter* writer);
- bool AppendWindowUpdateFrame(const QuicWindowUpdateFrame& frame,
- QuicDataWriter* writer);
- bool AppendBlockedFrame(const QuicBlockedFrame& frame,
- QuicDataWriter* writer);
- bool AppendPathCloseFrame(const QuicPathCloseFrame& frame,
- QuicDataWriter* writer);
-
- bool RaiseError(QuicErrorCode error);
-
- void set_error(QuicErrorCode error) { error_ = error; }
-
- void set_detailed_error(const char* error) { detailed_error_ = error; }
-
- std::string detailed_error_;
- QuicFramerVisitorInterface* visitor_;
- QuicReceivedEntropyHashCalculatorInterface* entropy_calculator_;
- QuicErrorCode error_;
- // Set of closed paths. A path is considered as closed if a PATH_CLOSED frame
- // has been sent/received.
- // TODO(fayang): this set is never cleaned up. A possible improvement is to
- // use intervals.
- std::unordered_set<QuicPathId> closed_paths_;
- // Map mapping path id to packet number of last successfully decrypted
- // received packet.
- std::unordered_map<QuicPathId, QuicPacketNumber> last_packet_numbers_;
- // Updated by ProcessPacketHeader when it succeeds.
- QuicPacketNumber last_packet_number_;
- // The path on which last successfully decrypted packet was received.
- QuicPathId last_path_id_;
- // Updated by WritePacketHeader.
- QuicConnectionId last_serialized_connection_id_;
- // The last QUIC version tag received.
- QuicTag last_version_tag_;
- // Version of the protocol being used.
- QuicVersion quic_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).
- QuicVersionVector 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.
- std::unique_ptr<QuicDecrypter> alternative_decrypter_;
- // The encryption level of |decrypter_|.
- EncryptionLevel decrypter_level_;
- // The encryption level of |alternative_decrypter_|.
- EncryptionLevel alternative_decrypter_level_;
- // |alternative_decrypter_latch_| is true if, when |alternative_decrypter_|
- // successfully decrypts a packet, we should install it as the only
- // decrypter.
- bool alternative_decrypter_latch_;
- // Encrypters used to encrypt packets via EncryptPayload().
- std::unique_ptr<QuicEncrypter> encrypter_[NUM_ENCRYPTION_LEVELS];
- // Tracks if the framer is being used by the entity that received the
- // connection or the entity that initiated it.
- Perspective perspective_;
- // If false, skip validation that the public flags are set to legal values.
- bool validate_flags_;
- // The time this framer was created. Time written to the wire will be
- // written as a delta from this value.
- QuicTime creation_time_;
- // The time delta computed for the last timestamp frame. This is relative to
- // the creation_time.
- QuicTime::Delta last_timestamp_;
- // The diversification nonce from the last received packet.
- DiversificationNonce last_nonce_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicFramer);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_FRAMER_H_
diff --git a/chromium/net/quic/quic_framer_test.cc b/chromium/net/quic/quic_framer_test.cc
deleted file mode 100644
index 4f2ba4fd681..00000000000
--- a/chromium/net/quic/quic_framer_test.cc
+++ /dev/null
@@ -1,7192 +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/quic_framer.h"
-
-#include <stdint.h>
-
-#include <algorithm>
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "net/quic/crypto/null_decrypter.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/quic_framer_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/test/gtest_util.h"
-
-using base::StringPiece;
-using std::make_pair;
-using std::map;
-using std::numeric_limits;
-using std::pair;
-using std::string;
-using std::vector;
-using testing::Return;
-using testing::Truly;
-using testing::_;
-
-namespace net {
-namespace test {
-
-const QuicPacketNumber kEpoch = UINT64_C(1) << 48;
-const QuicPacketNumber kMask = kEpoch - 1;
-
-// Use fields in which each byte is distinct to ensure that every byte is
-// framed correctly. The values are otherwise arbitrary.
-const QuicConnectionId kConnectionId = UINT64_C(0xFEDCBA9876543210);
-const QuicPathId kPathId = 0x42;
-const QuicPacketNumber kPacketNumber = UINT64_C(0x123456789ABC);
-const QuicPacketNumber kLargestObserved = UINT64_C(0x0123456789ABF);
-const QuicPacketNumber kSmallLargestObserved = UINT16_C(0x1234);
-const QuicPacketNumber kMissingPacket = UINT64_C(0x0123456789ABE);
-const QuicPacketNumber kSmallMissingPacket = UINT16_C(0x1233);
-const QuicPacketNumber kLeastUnacked = UINT64_C(0x0123456789AA0);
-const QuicStreamId kStreamId = UINT64_C(0x01020304);
-const QuicStreamOffset kStreamOffset = UINT64_C(0xBA98FEDC32107654);
-const QuicPublicResetNonceProof kNonceProof = UINT64_C(0xABCDEF0123456789);
-
-// Index into the connection_id offset in the header.
-const size_t kConnectionIdOffset = kPublicFlagsSize;
-// Index into the version string in the header. (if present).
-const size_t kVersionOffset = kConnectionIdOffset + PACKET_8BYTE_CONNECTION_ID;
-
-// Size in bytes of the stream frame fields for an arbitrary StreamID and
-// offset and the last frame in a packet.
-size_t GetMinStreamFrameSize() {
- return kQuicFrameTypeSize + kQuicMaxStreamIdSize + kQuicMaxStreamOffsetSize;
-}
-
-// Index into the path id offset in the header (if present).
-size_t GetPathIdOffset(QuicConnectionIdLength connection_id_length,
- bool include_version) {
- return kConnectionIdOffset + connection_id_length +
- (include_version ? kQuicVersionSize : 0);
-}
-
-// Index into the packet number offset in the header.
-size_t GetPacketNumberOffset(QuicConnectionIdLength connection_id_length,
- bool include_version,
- bool include_path_id) {
- return kConnectionIdOffset + connection_id_length +
- (include_version ? kQuicVersionSize : 0) +
- (include_path_id ? kQuicPathIdSize : 0);
-}
-
-size_t GetPacketNumberOffset(bool include_version, bool include_path_id) {
- return GetPacketNumberOffset(PACKET_8BYTE_CONNECTION_ID, include_version,
- include_path_id);
-}
-
-// Index into the private flags offset in the data packet header.
-size_t GetPrivateFlagsOffset(QuicConnectionIdLength connection_id_length,
- bool include_version,
- bool include_path_id) {
- return GetPacketNumberOffset(connection_id_length, include_version,
- include_path_id) +
- PACKET_6BYTE_PACKET_NUMBER;
-}
-
-size_t GetPrivateFlagsOffset(bool include_version, bool include_path_id) {
- return GetPrivateFlagsOffset(PACKET_8BYTE_CONNECTION_ID, include_version,
- include_path_id);
-}
-
-size_t GetPrivateFlagsOffset(bool include_version,
- bool include_path_id,
- QuicPacketNumberLength packet_number_length) {
- return GetPacketNumberOffset(PACKET_8BYTE_CONNECTION_ID, include_version,
- include_path_id) +
- packet_number_length;
-}
-
-// Index into the message tag of the public reset packet.
-// Public resets always have full connection_ids.
-const size_t kPublicResetPacketMessageTagOffset =
- kConnectionIdOffset + PACKET_8BYTE_CONNECTION_ID;
-
-class TestEncrypter : public QuicEncrypter {
- public:
- ~TestEncrypter() override {}
- bool SetKey(StringPiece key) override { return true; }
- bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
- bool EncryptPacket(QuicPathId path_id,
- QuicPacketNumber packet_number,
- StringPiece associated_data,
- StringPiece plaintext,
- char* output,
- size_t* output_length,
- size_t max_output_length) override {
- path_id_ = path_id;
- packet_number_ = packet_number;
- associated_data_ = associated_data.as_string();
- plaintext_ = plaintext.as_string();
- memcpy(output, plaintext.data(), plaintext.length());
- *output_length = plaintext.length();
- return true;
- }
- size_t GetKeySize() const override { return 0; }
- size_t GetNoncePrefixSize() const override { return 0; }
- size_t GetMaxPlaintextSize(size_t ciphertext_size) const override {
- return ciphertext_size;
- }
- size_t GetCiphertextSize(size_t plaintext_size) const override {
- return plaintext_size;
- }
- StringPiece GetKey() const override { return StringPiece(); }
- StringPiece GetNoncePrefix() const override { return StringPiece(); }
- QuicPathId path_id_;
- QuicPacketNumber packet_number_;
- string associated_data_;
- string plaintext_;
-};
-
-class TestDecrypter : public QuicDecrypter {
- public:
- ~TestDecrypter() override {}
- bool SetKey(StringPiece key) override { return true; }
- bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
- bool SetPreliminaryKey(StringPiece key) override {
- QUIC_BUG << "should not be called";
- return false;
- }
- bool SetDiversificationNonce(DiversificationNonce key) override {
- return true;
- }
- bool DecryptPacket(QuicPathId path_id,
- QuicPacketNumber packet_number,
- StringPiece associated_data,
- StringPiece ciphertext,
- char* output,
- size_t* output_length,
- size_t max_output_length) override {
- path_id_ = path_id;
- packet_number_ = packet_number;
- associated_data_ = associated_data.as_string();
- ciphertext_ = ciphertext.as_string();
- memcpy(output, ciphertext.data(), ciphertext.length());
- *output_length = ciphertext.length();
- return true;
- }
- StringPiece GetKey() const override { return StringPiece(); }
- StringPiece GetNoncePrefix() const override { return StringPiece(); }
- const char* cipher_name() const override { return "Test"; }
- // Use a distinct value starting with 0xFFFFFF, which is never used by TLS.
- uint32_t cipher_id() const override { return 0xFFFFFFF2; }
- QuicPathId path_id_;
- QuicPacketNumber packet_number_;
- string associated_data_;
- string ciphertext_;
-};
-
-class TestQuicVisitor : public QuicFramerVisitorInterface {
- public:
- TestQuicVisitor()
- : error_count_(0),
- version_mismatch_(0),
- packet_count_(0),
- frame_count_(0),
- complete_packets_(0),
- accept_packet_(true),
- accept_public_header_(true) {}
-
- ~TestQuicVisitor() override {
- STLDeleteElements(&stream_frames_);
- STLDeleteElements(&ack_frames_);
- STLDeleteElements(&stop_waiting_frames_);
- STLDeleteElements(&padding_frames_);
- STLDeleteElements(&ping_frames_);
- STLDeleteElements(&stream_data_);
- }
-
- void OnError(QuicFramer* f) override {
- DVLOG(1) << "QuicFramer Error: " << QuicUtils::ErrorToString(f->error())
- << " (" << f->error() << ")";
- ++error_count_;
- }
-
- void OnPacket() override {}
-
- void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {
- public_reset_packet_.reset(new QuicPublicResetPacket(packet));
- }
-
- void OnVersionNegotiationPacket(
- const QuicVersionNegotiationPacket& packet) override {
- version_negotiation_packet_.reset(new QuicVersionNegotiationPacket(packet));
- }
-
- bool OnProtocolVersionMismatch(QuicVersion version) override {
- DVLOG(1) << "QuicFramer Version Mismatch, version: " << version;
- ++version_mismatch_;
- return true;
- }
-
- bool OnUnauthenticatedPublicHeader(
- const QuicPacketPublicHeader& header) override {
- public_header_.reset(new QuicPacketPublicHeader(header));
- return accept_public_header_;
- }
-
- bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override {
- return true;
- }
-
- void OnDecryptedPacket(EncryptionLevel level) override {}
-
- bool OnPacketHeader(const QuicPacketHeader& header) override {
- if (header.fec_flag) {
- // Drop any FEC packet.
- return false;
- }
- ++packet_count_;
- header_.reset(new QuicPacketHeader(header));
- return accept_packet_;
- }
-
- bool OnStreamFrame(const QuicStreamFrame& frame) override {
- ++frame_count_;
- // Save a copy of the data so it is valid after the packet is processed.
- string* string_data = new string();
- StringPiece(frame.data_buffer, frame.data_length)
- .AppendToString(string_data);
- stream_data_.push_back(string_data);
- stream_frames_.push_back(new QuicStreamFrame(frame.stream_id, frame.fin,
- frame.offset, *string_data));
- return true;
- }
-
- bool OnAckFrame(const QuicAckFrame& frame) override {
- ++frame_count_;
- ack_frames_.push_back(new QuicAckFrame(frame));
- return true;
- }
-
- bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override {
- ++frame_count_;
- stop_waiting_frames_.push_back(new QuicStopWaitingFrame(frame));
- return true;
- }
-
- bool OnPaddingFrame(const QuicPaddingFrame& frame) override {
- padding_frames_.push_back(new QuicPaddingFrame(frame));
- return true;
- }
-
- bool OnPingFrame(const QuicPingFrame& frame) override {
- ++frame_count_;
- ping_frames_.push_back(new QuicPingFrame(frame));
- return true;
- }
-
- void OnPacketComplete() override { ++complete_packets_; }
-
- bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override {
- rst_stream_frame_ = frame;
- return true;
- }
-
- bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override {
- connection_close_frame_ = frame;
- return true;
- }
-
- bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override {
- goaway_frame_ = frame;
- return true;
- }
-
- bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override {
- window_update_frame_ = frame;
- return true;
- }
-
- bool OnBlockedFrame(const QuicBlockedFrame& frame) override {
- blocked_frame_ = frame;
- return true;
- }
-
- bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override {
- path_close_frame_ = frame;
- return true;
- }
-
- // Counters from the visitor_ callbacks.
- int error_count_;
- int version_mismatch_;
- int packet_count_;
- int frame_count_;
- int complete_packets_;
- bool accept_packet_;
- bool accept_public_header_;
-
- std::unique_ptr<QuicPacketHeader> header_;
- std::unique_ptr<QuicPacketPublicHeader> public_header_;
- std::unique_ptr<QuicPublicResetPacket> public_reset_packet_;
- std::unique_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_;
- vector<QuicStreamFrame*> stream_frames_;
- vector<QuicAckFrame*> ack_frames_;
- vector<QuicStopWaitingFrame*> stop_waiting_frames_;
- vector<QuicPaddingFrame*> padding_frames_;
- vector<QuicPingFrame*> ping_frames_;
- QuicRstStreamFrame rst_stream_frame_;
- QuicConnectionCloseFrame connection_close_frame_;
- QuicGoAwayFrame goaway_frame_;
- QuicWindowUpdateFrame window_update_frame_;
- QuicBlockedFrame blocked_frame_;
- QuicPathCloseFrame path_close_frame_;
- vector<string*> stream_data_;
-};
-
-class QuicFramerTest : public ::testing::TestWithParam<QuicVersion> {
- public:
- QuicFramerTest()
- : encrypter_(new test::TestEncrypter()),
- decrypter_(new test::TestDecrypter()),
- start_(QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(0x10))),
- framer_(QuicSupportedVersions(), start_, Perspective::IS_SERVER) {
- version_ = GetParam();
- framer_.set_version(version_);
- framer_.SetDecrypter(ENCRYPTION_NONE, decrypter_);
- framer_.SetEncrypter(ENCRYPTION_NONE, encrypter_);
- framer_.set_visitor(&visitor_);
- framer_.set_received_entropy_calculator(&entropy_calculator_);
- }
-
- // 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);
- }
-
- // 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);
- }
-
- bool CheckEncryption(QuicPathId path_id,
- QuicPacketNumber packet_number,
- QuicPacket* packet) {
- if (packet_number != encrypter_->packet_number_) {
- LOG(ERROR) << "Encrypted incorrect packet number. expected "
- << packet_number << " actual: " << encrypter_->packet_number_;
- return false;
- }
- if (packet->AssociatedData(framer_.version()) !=
- encrypter_->associated_data_) {
- LOG(ERROR) << "Encrypted incorrect associated data. expected "
- << packet->AssociatedData(framer_.version())
- << " actual: " << encrypter_->associated_data_;
- return false;
- }
- if (packet->Plaintext(framer_.version()) != encrypter_->plaintext_) {
- LOG(ERROR) << "Encrypted incorrect plaintext data. expected "
- << packet->Plaintext(framer_.version())
- << " actual: " << encrypter_->plaintext_;
- return false;
- }
- return true;
- }
-
- bool CheckDecryption(const QuicEncryptedPacket& encrypted,
- bool includes_version,
- bool includes_path_id,
- bool includes_diversification_nonce) {
- if (visitor_.header_->packet_number != decrypter_->packet_number_) {
- LOG(ERROR) << "Decrypted incorrect packet number. expected "
- << visitor_.header_->packet_number
- << " actual: " << decrypter_->packet_number_;
- return false;
- }
- if (QuicFramer::GetAssociatedDataFromEncryptedPacket(
- framer_.version(), encrypted, PACKET_8BYTE_CONNECTION_ID,
- includes_version, includes_path_id, includes_diversification_nonce,
- PACKET_6BYTE_PACKET_NUMBER) != decrypter_->associated_data_) {
- LOG(ERROR) << "Decrypted incorrect associated data. expected "
- << QuicFramer::GetAssociatedDataFromEncryptedPacket(
- framer_.version(), encrypted,
- PACKET_8BYTE_CONNECTION_ID, includes_version,
- includes_path_id, includes_diversification_nonce,
- PACKET_6BYTE_PACKET_NUMBER)
- << " actual: " << decrypter_->associated_data_;
- return false;
- }
- StringPiece ciphertext(
- encrypted.AsStringPiece().substr(GetStartOfEncryptedData(
- framer_.version(), PACKET_8BYTE_CONNECTION_ID, includes_version,
- includes_path_id, includes_diversification_nonce,
- PACKET_6BYTE_PACKET_NUMBER)));
- if (ciphertext != decrypter_->ciphertext_) {
- LOG(ERROR) << "Decrypted incorrect ciphertext data. expected "
- << ciphertext << " actual: " << decrypter_->ciphertext_;
- return false;
- }
- return true;
- }
-
- char* AsChars(unsigned char* data) { return reinterpret_cast<char*>(data); }
-
- void CheckProcessingFails(unsigned char* packet,
- size_t len,
- string expected_error,
- QuicErrorCode error_code) {
- QuicEncryptedPacket encrypted(AsChars(packet), len, false);
- EXPECT_FALSE(framer_.ProcessPacket(encrypted)) << "len: " << len;
- EXPECT_EQ(expected_error, framer_.detailed_error()) << "len: " << len;
- EXPECT_EQ(error_code, framer_.error()) << "len: " << len;
- }
-
- // Checks if the supplied string matches data in the supplied StreamFrame.
- void CheckStreamFrameData(string str, QuicStreamFrame* frame) {
- EXPECT_EQ(str, string(frame->data_buffer, frame->data_length));
- }
-
- void CheckStreamFrameBoundaries(unsigned char* packet,
- size_t stream_id_size,
- bool include_version) {
- // Now test framing boundaries.
- for (size_t i = kQuicFrameTypeSize; i < GetMinStreamFrameSize(); ++i) {
- string expected_error;
- if (i < kQuicFrameTypeSize + stream_id_size) {
- expected_error = "Unable to read stream_id.";
- } else if (i < kQuicFrameTypeSize + stream_id_size +
- kQuicMaxStreamOffsetSize) {
- expected_error = "Unable to read offset.";
- } else {
- expected_error = "Unable to read frame data.";
- }
- CheckProcessingFails(
- packet,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- include_version, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_STREAM_DATA);
- }
- }
-
- void CheckCalculatePacketNumber(QuicPacketNumber expected_packet_number,
- QuicPacketNumber last_packet_number) {
- QuicPacketNumber wire_packet_number = expected_packet_number & kMask;
- QuicFramerPeer::SetLastPacketNumber(&framer_, last_packet_number);
- EXPECT_EQ(
- expected_packet_number,
- QuicFramerPeer::CalculatePacketNumberFromWire(
- &framer_, PACKET_6BYTE_PACKET_NUMBER,
- QuicFramerPeer::GetLastPacketNumber(&framer_), wire_packet_number))
- << "last_packet_number: " << last_packet_number
- << " wire_packet_number: " << wire_packet_number;
- }
-
- QuicPacket* BuildDataPacket(const QuicPacketHeader& header,
- const QuicFrames& frames) {
- return BuildUnsizedDataPacket(&framer_, header, frames);
- }
-
- QuicPacket* BuildDataPacket(const QuicPacketHeader& header,
- const QuicFrames& frames,
- size_t packet_size) {
- return BuildUnsizedDataPacket(&framer_, header, frames, packet_size);
- }
-
- test::TestEncrypter* encrypter_;
- test::TestDecrypter* decrypter_;
- QuicVersion version_;
- QuicTime start_;
- QuicFramer framer_;
- test::TestQuicVisitor visitor_;
- test::TestEntropyCalculator entropy_calculator_;
-};
-
-// Run all framer tests with all supported versions of QUIC.
-INSTANTIATE_TEST_CASE_P(QuicFramerTests,
- QuicFramerTest,
- ::testing::ValuesIn(kSupportedQuicVersions));
-
-TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochStart) {
- // A few quick manual sanity checks.
- CheckCalculatePacketNumber(UINT64_C(1), UINT64_C(0));
- CheckCalculatePacketNumber(kEpoch + 1, kMask);
- CheckCalculatePacketNumber(kEpoch, kMask);
-
- // Cases where the last number was close to the start of the range.
- for (uint64_t last = 0; last < 10; last++) {
- // Small numbers should not wrap (even if they're out of order).
- for (uint64_t j = 0; j < 10; j++) {
- CheckCalculatePacketNumber(j, last);
- }
-
- // Large numbers should not wrap either (because we're near 0 already).
- for (uint64_t j = 0; j < 10; j++) {
- CheckCalculatePacketNumber(kEpoch - 1 - j, last);
- }
- }
-}
-
-TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearEpochEnd) {
- // Cases where the last number was close to the end of the range
- for (uint64_t i = 0; i < 10; i++) {
- QuicPacketNumber last = kEpoch - i;
-
- // Small numbers should wrap.
- for (uint64_t j = 0; j < 10; j++) {
- CheckCalculatePacketNumber(kEpoch + j, last);
- }
-
- // Large numbers should not (even if they're out of order).
- for (uint64_t j = 0; j < 10; j++) {
- CheckCalculatePacketNumber(kEpoch - 1 - j, last);
- }
- }
-}
-
-// Next check where we're in a non-zero epoch to verify we handle
-// reverse wrapping, too.
-TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearPrevEpoch) {
- const uint64_t prev_epoch = 1 * kEpoch;
- const uint64_t cur_epoch = 2 * kEpoch;
- // Cases where the last number was close to the start of the range
- for (uint64_t i = 0; i < 10; i++) {
- uint64_t last = cur_epoch + i;
- // Small number should not wrap (even if they're out of order).
- for (uint64_t j = 0; j < 10; j++) {
- CheckCalculatePacketNumber(cur_epoch + j, last);
- }
-
- // But large numbers should reverse wrap.
- for (uint64_t j = 0; j < 10; j++) {
- uint64_t num = kEpoch - 1 - j;
- CheckCalculatePacketNumber(prev_epoch + num, last);
- }
- }
-}
-
-TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearNextEpoch) {
- const uint64_t cur_epoch = 2 * kEpoch;
- const uint64_t next_epoch = 3 * kEpoch;
- // Cases where the last number was close to the end of the range
- for (uint64_t i = 0; i < 10; i++) {
- QuicPacketNumber last = next_epoch - 1 - i;
-
- // Small numbers should wrap.
- for (uint64_t j = 0; j < 10; j++) {
- CheckCalculatePacketNumber(next_epoch + j, last);
- }
-
- // but large numbers should not (even if they're out of order).
- for (uint64_t j = 0; j < 10; j++) {
- uint64_t num = kEpoch - 1 - j;
- CheckCalculatePacketNumber(cur_epoch + num, last);
- }
- }
-}
-
-TEST_P(QuicFramerTest, CalculatePacketNumberFromWireNearNextMax) {
- const uint64_t max_number = numeric_limits<uint64_t>::max();
- const uint64_t max_epoch = max_number & ~kMask;
-
- // Cases where the last number was close to the end of the range
- for (uint64_t i = 0; i < 10; i++) {
- // Subtract 1, because the expected next packet number is 1 more than the
- // last packet number.
- QuicPacketNumber last = max_number - i - 1;
-
- // Small numbers should not wrap, because they have nowhere to go.
- for (uint64_t j = 0; j < 10; j++) {
- CheckCalculatePacketNumber(max_epoch + j, last);
- }
-
- // Large numbers should not wrap either.
- for (uint64_t j = 0; j < 10; j++) {
- uint64_t num = kEpoch - 1 - j;
- CheckCalculatePacketNumber(max_epoch + num, last);
- }
- }
-}
-
-TEST_P(QuicFramerTest, EmptyPacket) {
- char packet[] = {0x00};
- QuicEncryptedPacket encrypted(packet, 0, false);
- EXPECT_FALSE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
-}
-
-TEST_P(QuicFramerTest, LargePacket) {
- // clang-format off
- unsigned char packet[kMaxPacketSize + 1] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags
- 0x00,
- };
- // clang-format on
-
- const size_t header_size = GetPacketHeaderSize(
- framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
- !kIncludePathId, !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER);
-
- memset(packet + header_size, 0, kMaxPacketSize - header_size);
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_DFATAL(framer_.ProcessPacket(encrypted), "Packet too large:1");
-
- ASSERT_TRUE(visitor_.header_.get());
- // Make sure we've parsed the packet header, so we can send an error.
- EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
- // Make sure the correct error is propagated.
- EXPECT_EQ(QUIC_PACKET_TOO_LARGE, framer_.error());
-}
-
-TEST_P(QuicFramerTest, PacketHeader) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags
- 0x00,
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_FALSE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
- EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
- EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
- EXPECT_FALSE(visitor_.header_->public_header.version_flag);
- EXPECT_FALSE(visitor_.header_->fec_flag);
- EXPECT_FALSE(visitor_.header_->entropy_flag);
- EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
-
- // Now test framing boundaries.
- for (size_t i = 0;
- i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER);
- ++i) {
- string expected_error;
- if (i < kConnectionIdOffset) {
- expected_error = "Unable to read public flags.";
- } else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) {
- expected_error = "Unable to read ConnectionId.";
- } else {
- if (framer_.version() <= QUIC_VERSION_33) {
- if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId)) {
- expected_error = "Unable to read packet number.";
- } else {
- expected_error = "Unable to read private flags.";
- }
- } else {
- expected_error = "Unable to read packet number.";
- }
- }
- CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
- expected_error, QUIC_INVALID_PACKET_HEADER);
- }
-}
-
-TEST_P(QuicFramerTest, PacketHeaderWith0ByteConnectionId) {
- QuicFramerPeer::SetLastSerializedConnectionId(&framer_, kConnectionId);
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (0 byte connection_id)
- 0x30,
- // connection_id
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
- };
- unsigned char packet_34[] = {
- // public flags (0 byte connection_id)
- 0x30,
- // connection_id
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_FALSE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
- EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
- EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
- EXPECT_FALSE(visitor_.header_->public_header.version_flag);
- EXPECT_FALSE(visitor_.header_->fec_flag);
- EXPECT_FALSE(visitor_.header_->entropy_flag);
- EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
-
- // Now test framing boundaries.
- for (size_t i = 0;
- i < GetPacketHeaderSize(framer_.version(), PACKET_0BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER);
- ++i) {
- string expected_error;
- if (i < kConnectionIdOffset) {
- expected_error = "Unable to read public flags.";
- } else if (i < GetPacketNumberOffset(PACKET_0BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId)) {
- expected_error = "Unable to read ConnectionId.";
- } else {
- if (framer_.version() <= QUIC_VERSION_33) {
- if (i < GetPrivateFlagsOffset(PACKET_0BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId)) {
- expected_error = "Unable to read packet number.";
- } else {
- expected_error = "Unable to read private flags.";
- }
- } else {
- expected_error = "Unable to read packet number.";
- }
- }
- CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
- expected_error, QUIC_INVALID_PACKET_HEADER);
- }
-}
-
-TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (version)
- 0x39,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags
- 0x00,
- };
- unsigned char packet_34[] = {
- // public flags (version)
- 0x39,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_FALSE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
- EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
- EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
- EXPECT_TRUE(visitor_.header_->public_header.version_flag);
- EXPECT_EQ(GetParam(), visitor_.header_->public_header.versions[0]);
- EXPECT_FALSE(visitor_.header_->fec_flag);
- EXPECT_FALSE(visitor_.header_->entropy_flag);
- EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
-
- // Now test framing boundaries.
- for (size_t i = 0;
- i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER);
- ++i) {
- string expected_error;
- if (i < kConnectionIdOffset) {
- expected_error = "Unable to read public flags.";
- } else if (i < kVersionOffset) {
- expected_error = "Unable to read ConnectionId.";
- } else if (i < GetPacketNumberOffset(kIncludeVersion, !kIncludePathId)) {
- expected_error = "Unable to read protocol version.";
- } else {
- if (framer_.version() <= QUIC_VERSION_33) {
- if (i < GetPrivateFlagsOffset(kIncludeVersion, !kIncludePathId)) {
- expected_error = "Unable to read packet number.";
- } else {
- expected_error = "Unable to read private flags.";
- }
- } else {
- expected_error = "Unable to read packet number.";
- }
- }
- CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
- expected_error, QUIC_INVALID_PACKET_HEADER);
- }
-}
-
-TEST_P(QuicFramerTest, PacketHeaderWithMultipathFlag) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (version)
- 0x78,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags
- 0x00,
- };
- unsigned char packet_34[] = {
- // public flags (version)
- 0x78,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_FALSE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, kIncludePathId,
- !kIncludeDiversificationNonce));
- EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
- EXPECT_TRUE(visitor_.header_->public_header.multipath_flag);
- EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
- EXPECT_FALSE(visitor_.header_->public_header.version_flag);
- EXPECT_FALSE(visitor_.header_->fec_flag);
- EXPECT_FALSE(visitor_.header_->entropy_flag);
- EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(kPathId, visitor_.header_->path_id);
- EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
-
- // Now test framing boundaries.
- for (size_t i = 0;
- i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER);
- ++i) {
- string expected_error;
- if (i < kConnectionIdOffset) {
- expected_error = "Unable to read public flags.";
- } else if (i <
- GetPathIdOffset(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion)) {
- expected_error = "Unable to read ConnectionId.";
- } else if (i < GetPacketNumberOffset(!kIncludeVersion, kIncludePathId)) {
- expected_error = "Unable to read path id.";
- } else {
- if (framer_.version() <= QUIC_VERSION_33) {
- if (i < GetPrivateFlagsOffset(!kIncludeVersion, kIncludePathId)) {
- expected_error = "Unable to read packet number.";
- } else {
- expected_error = "Unable to read private flags.";
- }
- } else {
- expected_error = "Unable to read packet number.";
- }
- }
- CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
- expected_error, QUIC_INVALID_PACKET_HEADER);
- }
-}
-
-TEST_P(QuicFramerTest, PacketHeaderWithBothVersionFlagAndMultipathFlag) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (version)
- 0x79,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags
- 0x00,
- };
- unsigned char packet_34[] = {
- // public flags (version)
- 0x79,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_FALSE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, kIncludeVersion, kIncludePathId,
- !kIncludeDiversificationNonce));
- EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
- EXPECT_TRUE(visitor_.header_->public_header.multipath_flag);
- EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
- EXPECT_TRUE(visitor_.header_->public_header.version_flag);
- EXPECT_EQ(GetParam(), visitor_.header_->public_header.versions[0]);
- EXPECT_FALSE(visitor_.header_->fec_flag);
- EXPECT_FALSE(visitor_.header_->entropy_flag);
- EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(kPathId, visitor_.header_->path_id);
- EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
-
- // Now test framing boundaries.
- for (size_t i = 0;
- i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER);
- ++i) {
- string expected_error;
- if (i < kConnectionIdOffset) {
- expected_error = "Unable to read public flags.";
- } else if (i < kVersionOffset) {
- expected_error = "Unable to read ConnectionId.";
- } else if (i <
- GetPathIdOffset(PACKET_8BYTE_CONNECTION_ID, kIncludeVersion)) {
- expected_error = "Unable to read protocol version.";
- } else if (i < GetPacketNumberOffset(kIncludeVersion, kIncludePathId)) {
- expected_error = "Unable to read path id.";
- } else {
- if (framer_.version() <= QUIC_VERSION_33) {
- if (i < GetPrivateFlagsOffset(kIncludeVersion, kIncludePathId)) {
- expected_error = "Unable to read packet number.";
- } else {
- expected_error = "Unable to read private flags.";
- }
- } else {
- expected_error = "Unable to read packet number.";
- }
- }
- CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
- expected_error, QUIC_INVALID_PACKET_HEADER);
- }
-}
-
-TEST_P(QuicFramerTest, PacketHeaderWithPathChange) {
- // Packet 1 from path 0x42.
- // clang-format off
- unsigned char packet1[] = {
- // public flags (version)
- 0x78,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags
- 0x00,
- };
- unsigned char packet1_34[] = {
- // public flags (version)
- 0x78,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- };
- // clang-format on
-
- EXPECT_EQ(0u, QuicFramerPeer::GetLastPacketNumber(&framer_));
- EXPECT_EQ(kInvalidPathId, QuicFramerPeer::GetLastPathId(&framer_));
- QuicEncryptedPacket encrypted1(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet1 : packet1_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet1)
- : arraysize(packet1_34),
- false);
- EXPECT_FALSE(framer_.ProcessPacket(encrypted1));
- EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
- EXPECT_EQ(kPathId, visitor_.header_->path_id);
- EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
- EXPECT_EQ(kPacketNumber, QuicFramerPeer::GetLastPacketNumber(&framer_));
- EXPECT_EQ(kPathId, QuicFramerPeer::GetLastPathId(&framer_));
-
- // Packet 2 from default path.
- // clang-format off
- unsigned char packet2[] = {
- // public flags (version)
- 0x78,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x00,
- // packet number
- 0xCC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags
- 0x00,
- };
- unsigned char packet2_34[] = {
- // public flags (version)
- 0x78,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x00,
- // packet number
- 0xCC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted2(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet2 : packet2_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet2)
- : arraysize(packet2_34),
- false);
- EXPECT_FALSE(framer_.ProcessPacket(encrypted2));
- EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
- EXPECT_EQ(kDefaultPathId, visitor_.header_->path_id);
- EXPECT_EQ(kPacketNumber + 16, visitor_.header_->packet_number);
- EXPECT_EQ(kPacketNumber + 16, QuicFramerPeer::GetLastPacketNumber(&framer_));
- EXPECT_EQ(kDefaultPathId, QuicFramerPeer::GetLastPathId(&framer_));
-
- // Packet 3 from path 0x42.
- // clang-format off
- unsigned char packet3[] = {
- // public flags (version)
- 0x78,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x42,
- // packet number
- 0xBD, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags
- 0x00,
- };
- unsigned char packet3_34[] = {
- // public flags (version)
- 0x78,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x42,
- // packet number
- 0xBD, 0x9A, 0x78, 0x56, 0x34, 0x12,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted3(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet3 : packet3_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet3)
- : arraysize(packet3_34),
- false);
- EXPECT_FALSE(framer_.ProcessPacket(encrypted3));
- EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
- EXPECT_EQ(kPathId, visitor_.header_->path_id);
- EXPECT_EQ(kPacketNumber + 1, visitor_.header_->packet_number);
- EXPECT_EQ(kPacketNumber + 1, QuicFramerPeer::GetLastPacketNumber(&framer_));
- EXPECT_EQ(kPathId, QuicFramerPeer::GetLastPathId(&framer_));
-}
-
-TEST_P(QuicFramerTest, ReceivedPacketOnClosedPath) {
- // Packet 1 from path 0x42.
- // clang-format off
- unsigned char packet[] = {
- // public flags (version)
- 0x78,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags
- 0x00,
- };
- unsigned char packet_34[] = {
- // public flags (version)
- 0x78,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags
- 0x00,
- };
- // clang-format on
-
- framer_.OnPathClosed(kPathId);
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_FALSE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- EXPECT_EQ(0u, QuicFramerPeer::GetLastPacketNumber(&framer_));
- EXPECT_EQ(kInvalidPathId, QuicFramerPeer::GetLastPathId(&framer_));
-}
-
-TEST_P(QuicFramerTest, PacketHeaderWith4BytePacketNumber) {
- QuicFramerPeer::SetLastPacketNumber(&framer_, kPacketNumber - 2);
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id and 4 byte packet number)
- 0x28,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- // private flags
- 0x00,
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id and 4 byte packet number)
- 0x28,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_FALSE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
- EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
- EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
- EXPECT_FALSE(visitor_.header_->public_header.version_flag);
- EXPECT_FALSE(visitor_.header_->fec_flag);
- EXPECT_FALSE(visitor_.header_->entropy_flag);
- EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
-
- // Now test framing boundaries.
- for (size_t i = 0;
- i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_4BYTE_PACKET_NUMBER);
- ++i) {
- string expected_error;
- if (i < kConnectionIdOffset) {
- expected_error = "Unable to read public flags.";
- } else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) {
- expected_error = "Unable to read ConnectionId.";
- } else {
- if (framer_.version() <= QUIC_VERSION_33) {
- if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId,
- PACKET_4BYTE_PACKET_NUMBER)) {
- expected_error = "Unable to read packet number.";
- } else {
- expected_error = "Unable to read private flags.";
- }
- } else {
- expected_error = "Unable to read packet number.";
- }
- }
- CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
- expected_error, QUIC_INVALID_PACKET_HEADER);
- }
-}
-
-TEST_P(QuicFramerTest, PacketHeaderWith2BytePacketNumber) {
- QuicFramerPeer::SetLastPacketNumber(&framer_, kPacketNumber - 2);
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id and 2 byte packet number)
- 0x18,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A,
- // private flags
- 0x00,
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id and 2 byte packet number)
- 0x18,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_FALSE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
- EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
- EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
- EXPECT_FALSE(visitor_.header_->public_header.version_flag);
- EXPECT_FALSE(visitor_.header_->fec_flag);
- EXPECT_FALSE(visitor_.header_->entropy_flag);
- EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
-
- // Now test framing boundaries.
- for (size_t i = 0;
- i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_2BYTE_PACKET_NUMBER);
- ++i) {
- string expected_error;
- if (i < kConnectionIdOffset) {
- expected_error = "Unable to read public flags.";
- } else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) {
- expected_error = "Unable to read ConnectionId.";
- } else {
- if (framer_.version() <= QUIC_VERSION_33) {
- if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId,
- PACKET_2BYTE_PACKET_NUMBER)) {
- expected_error = "Unable to read packet number.";
- } else {
- expected_error = "Unable to read private flags.";
- }
- } else {
- expected_error = "Unable to read packet number.";
- }
- }
- CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
- expected_error, QUIC_INVALID_PACKET_HEADER);
- }
-}
-
-TEST_P(QuicFramerTest, PacketHeaderWith1BytePacketNumber) {
- QuicFramerPeer::SetLastPacketNumber(&framer_, kPacketNumber - 2);
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id and 1 byte packet number)
- 0x08,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC,
- // private flags
- 0x00,
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id and 1 byte packet number)
- 0x08,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_FALSE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id);
- EXPECT_FALSE(visitor_.header_->public_header.multipath_flag);
- EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
- EXPECT_FALSE(visitor_.header_->public_header.version_flag);
- EXPECT_FALSE(visitor_.header_->fec_flag);
- EXPECT_FALSE(visitor_.header_->entropy_flag);
- EXPECT_EQ(0, visitor_.header_->entropy_hash);
- EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number);
-
- // Now test framing boundaries.
- for (size_t i = 0;
- i < GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_1BYTE_PACKET_NUMBER);
- ++i) {
- string expected_error;
- if (i < kConnectionIdOffset) {
- expected_error = "Unable to read public flags.";
- } else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) {
- expected_error = "Unable to read ConnectionId.";
- } else {
- if (framer_.version() <= QUIC_VERSION_33) {
- if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId,
- PACKET_1BYTE_PACKET_NUMBER)) {
- expected_error = "Unable to read packet number.";
- } else {
- expected_error = "Unable to read private flags.";
- }
- } else {
- expected_error = "Unable to read packet number.";
- }
- }
- CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, i,
- expected_error, QUIC_INVALID_PACKET_HEADER);
- }
-}
-
-TEST_P(QuicFramerTest, InvalidPublicFlag) {
- if (framer_.version() > QUIC_VERSION_33) {
- return;
- }
- // clang-format off
- unsigned char packet[] = {
- // public flags: all flags set but the public reset flag and version flag.
- 0xF8,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (padding)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- // clang-format on
-
- CheckProcessingFails(packet, arraysize(packet), "Illegal public flags value.",
- QUIC_INVALID_PACKET_HEADER);
-
- // Now turn off validation.
- framer_.set_validate_flags(false);
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-};
-
-TEST_P(QuicFramerTest, PacketWithDiversificationNonce) {
- // clang-format off
- unsigned char packet[] = {
- // public flags: includes nonce flag
- 0x7C,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // nonce
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (padding)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- unsigned char packet_34[] = {
- // public flags: includes nonce flag
- 0x7C,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // nonce
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
-
- // frame type (padding)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
- if (framer_.version() > QUIC_VERSION_32) {
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- ASSERT_TRUE(visitor_.public_header_->nonce != nullptr);
- for (char i = 0; i < 32; ++i) {
- EXPECT_EQ(i, (*visitor_.public_header_->nonce)[static_cast<int>(i)]);
- }
- } else if (framer_.version() < QUIC_VERSION_32) {
- // Packet is successfully parsed by accident.
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- ASSERT_TRUE(visitor_.public_header_ != nullptr);
- } else {
- EXPECT_FALSE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
- EXPECT_EQ("Illegal private flags value.", framer_.detailed_error());
- }
-};
-
-TEST_P(QuicFramerTest, InvalidPublicFlagWithMatchingVersions) {
- if (framer_.version() > QUIC_VERSION_33) {
- return;
- }
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id and version flag and an unknown flag)
- 0x8D,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (padding)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- // clang-format on
- CheckProcessingFails(packet, arraysize(packet), "Illegal public flags value.",
- QUIC_INVALID_PACKET_HEADER);
-};
-
-TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id, version flag and an unknown flag)
- 0x79,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', '0', '0',
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id, version flag and an unknown flag)
- 0x79,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', '0', '0',
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- // clang-format on
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_EQ(0, visitor_.frame_count_);
- EXPECT_EQ(1, visitor_.version_mismatch_);
-};
-
-TEST_P(QuicFramerTest, InvalidPrivateFlag) {
- if (framer_.version() > QUIC_VERSION_33) {
- return;
- }
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x10,
-
- // frame type (padding)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- // clang-format on
- CheckProcessingFails(packet, arraysize(packet),
- "Illegal private flags value.",
- QUIC_INVALID_PACKET_HEADER);
-};
-
-TEST_P(QuicFramerTest, InvalidFECGroupOffset) {
- if (framer_.version() > QUIC_VERSION_33) {
- return;
- }
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00,
- // private flags (fec group)
- 0x02,
- // first fec protected packet offset
- 0x10
- };
- // clang-format on
- if (framer_.version() > QUIC_VERSION_31) {
- CheckProcessingFails(packet, arraysize(packet),
- "Illegal private flags value.",
- QUIC_INVALID_PACKET_HEADER);
- } else {
- CheckProcessingFails(packet, arraysize(packet),
- "First fec protected packet offset must be less "
- "than the packet number.",
- QUIC_INVALID_PACKET_HEADER);
- }
-};
-
-TEST_P(QuicFramerTest, PaddingFrame) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (padding frame)
- 0x00,
- // Ignored data (which in this case is a stream frame)
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (padding frame)
- 0x00,
- // Ignored data (which in this case is a stream frame)
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- ASSERT_EQ(0u, visitor_.stream_frames_.size());
- EXPECT_EQ(0u, visitor_.ack_frames_.size());
- // A packet with no frames is not acceptable.
- CheckProcessingFails(
- packet, GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- "Packet has no frames.", QUIC_MISSING_PAYLOAD);
-}
-
-TEST_P(QuicFramerTest, StreamFrame) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- ASSERT_EQ(1u, visitor_.stream_frames_.size());
- EXPECT_EQ(0u, visitor_.ack_frames_.size());
- EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id);
- EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
- CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
-
- // Now test framing boundaries.
- CheckStreamFrameBoundaries(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
- kQuicMaxStreamIdSize, !kIncludeVersion);
-}
-
-TEST_P(QuicFramerTest, MissingDiversificationNonce) {
- QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
- framer_.SetDecrypter(ENCRYPTION_NONE, new NullDecrypter());
- decrypter_ = new test::TestDecrypter();
- framer_.SetAlternativeDecrypter(ENCRYPTION_INITIAL, decrypter_, false);
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- if (framer_.version() > QUIC_VERSION_32) {
- EXPECT_FALSE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_DECRYPTION_FAILURE, framer_.error());
-
- } else {
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
- }
-}
-
-TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (stream frame with fin)
- 0xFE,
- // stream id
- 0x04, 0x03, 0x02,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (stream frame with fin)
- 0xFE,
- // stream id
- 0x04, 0x03, 0x02,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- ASSERT_EQ(1u, visitor_.stream_frames_.size());
- EXPECT_EQ(0u, visitor_.ack_frames_.size());
- // Stream ID should be the last 3 bytes of kStreamId.
- EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id);
- EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
- CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
-
- // Now test framing boundaries.
- const size_t stream_id_size = 3;
- CheckStreamFrameBoundaries(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, stream_id_size,
- !kIncludeVersion);
-}
-
-TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (stream frame with fin)
- 0xFD,
- // stream id
- 0x04, 0x03,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (stream frame with fin)
- 0xFD,
- // stream id
- 0x04, 0x03,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- ASSERT_EQ(1u, visitor_.stream_frames_.size());
- EXPECT_EQ(0u, visitor_.ack_frames_.size());
- // Stream ID should be the last 2 bytes of kStreamId.
- EXPECT_EQ(0x0000FFFF & kStreamId, visitor_.stream_frames_[0]->stream_id);
- EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
- CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
-
- // Now test framing boundaries.
- const size_t stream_id_size = 2;
- CheckStreamFrameBoundaries(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, stream_id_size,
- !kIncludeVersion);
-}
-
-TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (stream frame with fin)
- 0xFC,
- // stream id
- 0x04,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (stream frame with fin)
- 0xFC,
- // stream id
- 0x04,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- ASSERT_EQ(1u, visitor_.stream_frames_.size());
- EXPECT_EQ(0u, visitor_.ack_frames_.size());
- // Stream ID should be the last byte of kStreamId.
- EXPECT_EQ(0x000000FF & kStreamId, visitor_.stream_frames_[0]->stream_id);
- EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
- CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
-
- // Now test framing boundaries.
- const size_t stream_id_size = 1;
- CheckStreamFrameBoundaries(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34, stream_id_size,
- !kIncludeVersion);
-}
-
-TEST_P(QuicFramerTest, StreamFrameWithVersion) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (version, 8 byte connection_id)
- 0x39,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- unsigned char packet_34[] = {
- // public flags (version, 8 byte connection_id)
- 0x39,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(visitor_.header_->public_header.version_flag);
- EXPECT_EQ(GetParam(), visitor_.header_->public_header.versions[0]);
- EXPECT_TRUE(CheckDecryption(encrypted, kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- ASSERT_EQ(1u, visitor_.stream_frames_.size());
- EXPECT_EQ(0u, visitor_.ack_frames_.size());
- EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id);
- EXPECT_TRUE(visitor_.stream_frames_[0]->fin);
- EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset);
- CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]);
-
- // Now test framing boundaries.
- CheckStreamFrameBoundaries(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
- kQuicMaxStreamIdSize, kIncludeVersion);
-}
-
-TEST_P(QuicFramerTest, RejectPacket) {
- visitor_.accept_packet_ = false;
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- ASSERT_EQ(0u, visitor_.stream_frames_.size());
- EXPECT_EQ(0u, visitor_.ack_frames_.size());
-}
-
-TEST_P(QuicFramerTest, RejectPublicHeader) {
- visitor_.accept_public_header_ = false;
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.public_header_.get());
- ASSERT_FALSE(visitor_.header_.get());
-}
-
-TEST_P(QuicFramerTest, AckFrameTwoTimestamp) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
- 0x6C,
- // entropy hash of all received packets.
- 0xBA,
- // largest observed packet number
- 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // Number of timestamps.
- 0x02,
- // Delta from largest observed.
- 0x01,
- // Delta time.
- 0x10, 0x32, 0x54, 0x76,
- // Delta from largest observed.
- 0x02,
- // Delta time.
- 0x10, 0x32,
- // num missing packets
- 0x01,
- // missing packet delta
- 0x01,
- // 0 more missing packets in range.
- 0x00,
- // Number of revived packets.
- 0x00,
- };
- // clang-format on
-
- if (framer_.version() > QUIC_VERSION_31) {
- return;
- }
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(0u, visitor_.stream_frames_.size());
- ASSERT_EQ(1u, visitor_.ack_frames_.size());
- const QuicAckFrame& frame = *visitor_.ack_frames_[0];
- EXPECT_EQ(0xBA, frame.entropy_hash);
- EXPECT_EQ(kLargestObserved, frame.largest_observed);
- ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
- ASSERT_EQ(2u, frame.received_packet_times.size());
- EXPECT_EQ(kMissingPacket, frame.packets.Min());
-
- const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
- const size_t kLargestObservedOffset =
- kReceivedEntropyOffset + kQuicEntropyHashSize;
- const size_t kMissingDeltaTimeOffset =
- kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
- const size_t kNumTimestampsOffset =
- kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
- const size_t kTimestampDeltaLargestObserved1 =
- kNumTimestampsOffset + kQuicNumTimestampsSize;
- const size_t kTimestampTimeDeltaLargestObserved1 =
- kTimestampDeltaLargestObserved1 + 1;
- const size_t kTimestampDeltaLargestObserved2 =
- kTimestampTimeDeltaLargestObserved1 + 4;
- const size_t kTimestampTimeDeltaLargestObserved2 =
- kTimestampDeltaLargestObserved2 + 1;
- const size_t kNumMissingPacketOffset =
- kTimestampTimeDeltaLargestObserved2 + 2;
- const size_t kMissingPacketsOffset =
- kNumMissingPacketOffset + kNumberOfNackRangesSize;
- const size_t kMissingPacketsRange =
- kMissingPacketsOffset + PACKET_1BYTE_PACKET_NUMBER;
- const size_t kRevivedPacketsLength =
- kMissingPacketsRange + PACKET_1BYTE_PACKET_NUMBER;
- // Now test framing boundaries.
- const size_t ack_frame_size =
- kRevivedPacketsLength + PACKET_1BYTE_PACKET_NUMBER;
- for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
- string expected_error;
- if (i < kLargestObservedOffset) {
- expected_error = "Unable to read entropy hash for received packets.";
- } else if (i < kMissingDeltaTimeOffset) {
- expected_error = "Unable to read largest observed.";
- } else if (i < kNumTimestampsOffset) {
- expected_error = "Unable to read ack delay time.";
- } else if (i < kTimestampDeltaLargestObserved1) {
- expected_error = "Unable to read num received packets.";
- } else if (i < kTimestampTimeDeltaLargestObserved1) {
- expected_error = "Unable to read sequence delta in received packets.";
- } else if (i < kTimestampDeltaLargestObserved2) {
- expected_error = "Unable to read time delta in received packets.";
- } else if (i < kTimestampTimeDeltaLargestObserved2) {
- expected_error = "Unable to read sequence delta in received packets.";
- } else if (i < kNumMissingPacketOffset) {
- expected_error =
- "Unable to read incremental time delta in received packets.";
- } else if (i < kMissingPacketsOffset) {
- expected_error = "Unable to read num missing packet ranges.";
- } else if (i < kMissingPacketsRange) {
- expected_error = "Unable to read missing packet number delta.";
- } else if (i < kRevivedPacketsLength) {
- expected_error = "Unable to read missing packet number range.";
- } else {
- expected_error = "Unable to read num revived packets.";
- }
- CheckProcessingFails(
- packet,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_ACK_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, AckFrameTwoTimestampVersion32) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x3C,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
- 0x6C,
- // entropy hash of all received packets.
- 0xBA,
- // largest observed packet number
- 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // Number of timestamps.
- 0x02,
- // Delta from largest observed.
- 0x01,
- // Delta time.
- 0x10, 0x32, 0x54, 0x76,
- // Delta from largest observed.
- 0x02,
- // Delta time.
- 0x10, 0x32,
- // num missing packets
- 0x01,
- // missing packet delta
- 0x01,
- // 0 more missing packets in range.
- 0x00,
- };
- // clang-format on
-
- if (framer_.version() <= QUIC_VERSION_31 ||
- framer_.version() > QUIC_VERSION_33) {
- return;
- }
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(0u, visitor_.stream_frames_.size());
- ASSERT_EQ(1u, visitor_.ack_frames_.size());
- const QuicAckFrame& frame = *visitor_.ack_frames_[0];
- EXPECT_EQ(0xBA, frame.entropy_hash);
- EXPECT_EQ(kLargestObserved, frame.largest_observed);
- ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
- ASSERT_EQ(2u, frame.received_packet_times.size());
- EXPECT_EQ(kMissingPacket, frame.packets.Min());
-
- const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
- const size_t kLargestObservedOffset =
- kReceivedEntropyOffset + kQuicEntropyHashSize;
- const size_t kMissingDeltaTimeOffset =
- kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
- const size_t kNumTimestampsOffset =
- kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
- const size_t kTimestampDeltaLargestObserved1 =
- kNumTimestampsOffset + kQuicNumTimestampsSize;
- const size_t kTimestampTimeDeltaLargestObserved1 =
- kTimestampDeltaLargestObserved1 + 1;
- const size_t kTimestampDeltaLargestObserved2 =
- kTimestampTimeDeltaLargestObserved1 + 4;
- const size_t kTimestampTimeDeltaLargestObserved2 =
- kTimestampDeltaLargestObserved2 + 1;
- const size_t kNumMissingPacketOffset =
- kTimestampTimeDeltaLargestObserved2 + 2;
- const size_t kMissingPacketsOffset =
- kNumMissingPacketOffset + kNumberOfNackRangesSize;
- // Now test framing boundaries.
- const size_t ack_frame_size = PACKET_1BYTE_PACKET_NUMBER;
- for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
- string expected_error;
- if (i < kLargestObservedOffset) {
- expected_error = "Unable to read entropy hash for received packets.";
- } else if (i < kMissingDeltaTimeOffset) {
- expected_error = "Unable to read largest observed.";
- } else if (i < kNumTimestampsOffset) {
- expected_error = "Unable to read ack delay time.";
- } else if (i < kTimestampDeltaLargestObserved1) {
- expected_error = "Unable to read num received packets.";
- } else if (i < kTimestampTimeDeltaLargestObserved1) {
- expected_error = "Unable to read sequence delta in received packets.";
- } else if (i < kTimestampDeltaLargestObserved2) {
- expected_error = "Unable to read time delta in received packets.";
- } else if (i < kTimestampTimeDeltaLargestObserved2) {
- expected_error = "Unable to read sequence delta in received packets.";
- } else if (i < kNumMissingPacketOffset) {
- expected_error =
- "Unable to read incremental time delta in received packets.";
- } else if (i < kMissingPacketsOffset) {
- expected_error = "Unable to read num missing packet ranges.";
- } else {
- expected_error = "Unable to read missing packet number delta.";
- }
- CheckProcessingFails(
- packet,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_ACK_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, AckFrameOneTimestamp) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
- 0x6C,
- // entropy hash of all received packets.
- 0xBA,
- // largest observed packet number
- 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // Number of timestamps.
- 0x01,
- // Delta from largest observed.
- 0x01,
- // Delta time.
- 0x10, 0x32, 0x54, 0x76,
- // num missing packets
- 0x01,
- // missing packet delta
- 0x01,
- // 0 more missing packets in range.
- 0x00,
- // Number of revived packets.
- 0x00,
- };
- // clang-format on
-
- if (framer_.version() > QUIC_VERSION_31) {
- return;
- }
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(0u, visitor_.stream_frames_.size());
- ASSERT_EQ(1u, visitor_.ack_frames_.size());
- const QuicAckFrame& frame = *visitor_.ack_frames_[0];
- EXPECT_EQ(0xBA, frame.entropy_hash);
- EXPECT_EQ(kLargestObserved, frame.largest_observed);
- ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
- ASSERT_EQ(1u, frame.received_packet_times.size());
- EXPECT_EQ(kMissingPacket, frame.packets.Min());
-
- const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
- const size_t kLargestObservedOffset =
- kReceivedEntropyOffset + kQuicEntropyHashSize;
- const size_t kMissingDeltaTimeOffset =
- kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
- const size_t kNumTimestampsOffset =
- kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
- const size_t kTimestampDeltaLargestObserved =
- kNumTimestampsOffset + kQuicNumTimestampsSize;
- const size_t kTimestampTimeDeltaLargestObserved =
- kTimestampDeltaLargestObserved + 1;
- const size_t kNumMissingPacketOffset = kTimestampTimeDeltaLargestObserved + 4;
- const size_t kMissingPacketsOffset =
- kNumMissingPacketOffset + kNumberOfNackRangesSize;
- const size_t kMissingPacketsRange =
- kMissingPacketsOffset + PACKET_1BYTE_PACKET_NUMBER;
- const size_t kRevivedPacketsLength =
- kMissingPacketsRange + PACKET_1BYTE_PACKET_NUMBER;
- // Now test framing boundaries.
- const size_t ack_frame_size =
- kRevivedPacketsLength + PACKET_1BYTE_PACKET_NUMBER;
- for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
- string expected_error;
- if (i < kLargestObservedOffset) {
- expected_error = "Unable to read entropy hash for received packets.";
- } else if (i < kMissingDeltaTimeOffset) {
- expected_error = "Unable to read largest observed.";
- } else if (i < kNumTimestampsOffset) {
- expected_error = "Unable to read ack delay time.";
- } else if (i < kTimestampDeltaLargestObserved) {
- expected_error = "Unable to read num received packets.";
- } else if (i < kTimestampTimeDeltaLargestObserved) {
- expected_error = "Unable to read sequence delta in received packets.";
- } else if (i < kNumMissingPacketOffset) {
- expected_error = "Unable to read time delta in received packets.";
- } else if (i < kMissingPacketsOffset) {
- expected_error = "Unable to read num missing packet ranges.";
- } else if (i < kMissingPacketsRange) {
- expected_error = "Unable to read missing packet number delta.";
- } else if (i < kRevivedPacketsLength) {
- expected_error = "Unable to read missing packet number range.";
- } else {
- expected_error = "Unable to read num revived packets.";
- }
- CheckProcessingFails(
- packet,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_ACK_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, AckFrameOneTimestampVersion32) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x3C,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
- 0x6C,
- // entropy hash of all received packets.
- 0xBA,
- // largest observed packet number
- 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // Number of timestamps.
- 0x01,
- // Delta from largest observed.
- 0x01,
- // Delta time.
- 0x10, 0x32, 0x54, 0x76,
- // num missing packets
- 0x01,
- // missing packet delta
- 0x01,
- // 0 more missing packets in range.
- 0x00,
- };
- // clang-format on
-
- if (framer_.version() <= QUIC_VERSION_31 ||
- framer_.version() > QUIC_VERSION_33) {
- return;
- }
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(0u, visitor_.stream_frames_.size());
- ASSERT_EQ(1u, visitor_.ack_frames_.size());
- const QuicAckFrame& frame = *visitor_.ack_frames_[0];
- EXPECT_EQ(0xBA, frame.entropy_hash);
- EXPECT_EQ(kLargestObserved, frame.largest_observed);
- ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
- ASSERT_EQ(1u, frame.received_packet_times.size());
- EXPECT_EQ(kMissingPacket, frame.packets.Min());
-
- const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
- const size_t kLargestObservedOffset =
- kReceivedEntropyOffset + kQuicEntropyHashSize;
- const size_t kMissingDeltaTimeOffset =
- kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
- const size_t kNumTimestampsOffset =
- kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
- const size_t kTimestampDeltaLargestObserved =
- kNumTimestampsOffset + kQuicNumTimestampsSize;
- const size_t kTimestampTimeDeltaLargestObserved =
- kTimestampDeltaLargestObserved + 1;
- const size_t kNumMissingPacketOffset = kTimestampTimeDeltaLargestObserved + 4;
- const size_t kMissingPacketsOffset =
- kNumMissingPacketOffset + kNumberOfNackRangesSize;
- // Now test framing boundaries.
- const size_t ack_frame_size = PACKET_1BYTE_PACKET_NUMBER;
- for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
- string expected_error;
- if (i < kLargestObservedOffset) {
- expected_error = "Unable to read entropy hash for received packets.";
- } else if (i < kMissingDeltaTimeOffset) {
- expected_error = "Unable to read largest observed.";
- } else if (i < kNumTimestampsOffset) {
- expected_error = "Unable to read ack delay time.";
- } else if (i < kTimestampDeltaLargestObserved) {
- expected_error = "Unable to read num received packets.";
- } else if (i < kTimestampTimeDeltaLargestObserved) {
- expected_error = "Unable to read sequence delta in received packets.";
- } else if (i < kNumMissingPacketOffset) {
- expected_error = "Unable to read time delta in received packets.";
- } else if (i < kMissingPacketsOffset) {
- expected_error = "Unable to read num missing packet ranges.";
- } else {
- expected_error = "Unable to read missing packet number delta.";
- }
- CheckProcessingFails(
- packet,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_ACK_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, AckFrame) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x3C,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
- 0x6C,
- // entropy hash of all received packets.
- 0xBA,
- // largest observed packet number
- 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // Number of timestamps.
- 0x00,
- // num missing packets
- 0x01,
- // missing packet delta
- 0x01,
- // 0 more missing packets in range.
- 0x00,
- // Number of revived packets.
- 0x00,
- };
- // clang-format on
-
- if (framer_.version() > QUIC_VERSION_31) {
- return;
- }
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(0u, visitor_.stream_frames_.size());
- ASSERT_EQ(1u, visitor_.ack_frames_.size());
- const QuicAckFrame& frame = *visitor_.ack_frames_[0];
- EXPECT_EQ(0xBA, frame.entropy_hash);
- EXPECT_EQ(kLargestObserved, frame.largest_observed);
- ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
- EXPECT_EQ(kMissingPacket, frame.packets.Min());
-
- const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
- const size_t kLargestObservedOffset =
- kReceivedEntropyOffset + kQuicEntropyHashSize;
- const size_t kMissingDeltaTimeOffset =
- kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
- const size_t kNumTimestampsOffset =
- kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
- const size_t kNumMissingPacketOffset =
- kNumTimestampsOffset + kQuicNumTimestampsSize;
- const size_t kMissingPacketsOffset =
- kNumMissingPacketOffset + kNumberOfNackRangesSize;
- const size_t kMissingPacketsRange =
- kMissingPacketsOffset + PACKET_1BYTE_PACKET_NUMBER;
- const size_t kRevivedPacketsLength =
- kMissingPacketsRange + PACKET_1BYTE_PACKET_NUMBER;
- // Now test framing boundaries.
- const size_t ack_frame_size =
- kRevivedPacketsLength + PACKET_1BYTE_PACKET_NUMBER;
- for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
- string expected_error;
- if (i < kLargestObservedOffset) {
- expected_error = "Unable to read entropy hash for received packets.";
- } else if (i < kMissingDeltaTimeOffset) {
- expected_error = "Unable to read largest observed.";
- } else if (i < kNumTimestampsOffset) {
- expected_error = "Unable to read ack delay time.";
- } else if (i < kNumMissingPacketOffset) {
- expected_error = "Unable to read num received packets.";
- } else if (i < kMissingPacketsOffset) {
- expected_error = "Unable to read num missing packet ranges.";
- } else if (i < kMissingPacketsRange) {
- expected_error = "Unable to read missing packet number delta.";
- } else if (i < kRevivedPacketsLength) {
- expected_error = "Unable to read missing packet number range.";
- } else {
- expected_error = "Unable to read num revived packets.";
- }
- CheckProcessingFails(
- packet,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_ACK_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, NewAckFrameOneAckBlock) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x3C,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
-
- // frame type (ack frame)
- // (one ack block, 2 byte largest observed, 2 byte block length)
- 0x45,
- // largest acked
- 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // first ack block length.
- 0x34, 0x12,
- // num timestamps.
- 0x00,
- };
- // clang-format on
-
- if (framer_.version() <= QUIC_VERSION_33) {
- return;
- }
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(0u, visitor_.stream_frames_.size());
- ASSERT_EQ(1u, visitor_.ack_frames_.size());
- const QuicAckFrame& frame = *visitor_.ack_frames_[0];
- EXPECT_EQ(kSmallLargestObserved, frame.largest_observed);
- EXPECT_FALSE(frame.missing);
- ASSERT_EQ(4660u, frame.packets.NumPacketsSlow());
-
- const size_t kLargestAckedOffset = kQuicFrameTypeSize;
- const size_t kLargestAckedDeltaTimeOffset =
- kLargestAckedOffset + PACKET_2BYTE_PACKET_NUMBER;
- const size_t kFirstAckBlockLengthOffset =
- kLargestAckedDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
- const size_t kNumTimestampsOffset =
- kFirstAckBlockLengthOffset + PACKET_2BYTE_PACKET_NUMBER;
- // Now test framing boundaries.
- const size_t ack_frame_size =
- kFirstAckBlockLengthOffset + PACKET_2BYTE_PACKET_NUMBER;
- for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
- string expected_error;
- if (i < kLargestAckedDeltaTimeOffset) {
- expected_error = "Unable to read largest acked.";
- } else if (i < kFirstAckBlockLengthOffset) {
- expected_error = "Unable to read ack delay time.";
- } else if (i < kNumTimestampsOffset) {
- expected_error = "Unable to read first ack block length.";
- } else {
- expected_error = "Unable to read num received packets.";
- }
- CheckProcessingFails(
- packet,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_ACK_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, NewAckFrameTwoTimeStampsMultipleAckBlocks) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x3C,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // 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
- 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // num ack blocks ranges.
- 0x04,
- // first ack block length.
- 0x01, 0x00,
- // gap to next block.
- 0x01,
- // ack block length.
- 0xaf, 0x0e,
- // gap to next block.
- 0xff,
- // ack block length.
- 0x00, 0x00,
- // gap to next block.
- 0x91,
- // ack block length.
- 0xea, 0x01,
- // gap to next block.
- 0x05,
- // ack block length.
- 0x04, 0x00,
- // Number of timestamps.
- 0x02,
- // Delta from largest observed.
- 0x01,
- // Delta time.
- 0x10, 0x32, 0x54, 0x76,
- // Delta from largest observed.
- 0x02,
- // Delta time.
- 0x10, 0x32,
- };
- // clang-format on
-
- if (framer_.version() <= QUIC_VERSION_33) {
- return;
- }
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(0u, visitor_.stream_frames_.size());
- ASSERT_EQ(1u, visitor_.ack_frames_.size());
- const QuicAckFrame& frame = *visitor_.ack_frames_[0];
- EXPECT_EQ(kSmallLargestObserved, frame.largest_observed);
- EXPECT_FALSE(frame.missing);
- ASSERT_EQ(4254u, frame.packets.NumPacketsSlow());
-
- const size_t kLargestAckedOffset = kQuicFrameTypeSize;
- const size_t kLargestAckedDeltaTimeOffset =
- kLargestAckedOffset + PACKET_2BYTE_PACKET_NUMBER;
- const size_t kNumberOfAckBlocksOffset =
- kLargestAckedDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
- const size_t kFirstAckBlockLengthOffset =
- kNumberOfAckBlocksOffset + kNumberOfAckBlocksSize;
- const size_t kGapToNextBlockOffset1 =
- kFirstAckBlockLengthOffset + PACKET_2BYTE_PACKET_NUMBER;
- const size_t kAckBlockLengthOffset1 = kGapToNextBlockOffset1 + 1;
- const size_t kGapToNextBlockOffset2 =
- kAckBlockLengthOffset1 + PACKET_2BYTE_PACKET_NUMBER;
- const size_t kAckBlockLengthOffset2 = kGapToNextBlockOffset2 + 1;
- const size_t kGapToNextBlockOffset3 =
- kAckBlockLengthOffset2 + PACKET_2BYTE_PACKET_NUMBER;
- const size_t kAckBlockLengthOffset3 = kGapToNextBlockOffset3 + 1;
- const size_t kGapToNextBlockOffset4 =
- kAckBlockLengthOffset3 + PACKET_2BYTE_PACKET_NUMBER;
- const size_t kAckBlockLengthOffset4 = kGapToNextBlockOffset3 + 1;
- const size_t kNumTimestampsOffset =
- kAckBlockLengthOffset4 + PACKET_2BYTE_PACKET_NUMBER;
- const size_t kTimestampDeltaLargestObserved1 =
- kNumTimestampsOffset + kQuicNumTimestampsSize;
- const size_t kTimestampTimeDeltaLargestObserved1 =
- kTimestampDeltaLargestObserved1 + 1;
- const size_t kTimestampDeltaLargestObserved2 =
- kTimestampTimeDeltaLargestObserved1 + 4;
- const size_t kTimestampTimeDeltaLargestObserved2 =
- kTimestampDeltaLargestObserved2 + 1;
-
- // Now test framing boundaries.
- const size_t ack_frame_size =
- kAckBlockLengthOffset4 + PACKET_2BYTE_PACKET_NUMBER;
- for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
- string expected_error;
- if (i < kLargestAckedDeltaTimeOffset) {
- expected_error = "Unable to read largest acked.";
- } else if (i < kNumberOfAckBlocksOffset) {
- expected_error = "Unable to read ack delay time.";
- } else if (i < kFirstAckBlockLengthOffset) {
- expected_error = "Unable to read num of ack blocks.";
- } else if (i < kGapToNextBlockOffset1) {
- expected_error = "Unable to read first ack block length.";
- } else if (i < kAckBlockLengthOffset1) {
- expected_error = "Unable to read gap to next ack block.";
- } else if (i < kGapToNextBlockOffset2) {
- expected_error = "Unable to ack block length.";
- } else if (i < kAckBlockLengthOffset2) {
- expected_error = "Unable to read gap to next ack block.";
- } else if (i < kGapToNextBlockOffset3) {
- expected_error = "Unable to ack block length.";
- } else if (i < kAckBlockLengthOffset3) {
- expected_error = "Unable to read gap to next ack block.";
- } else if (i < kGapToNextBlockOffset4) {
- expected_error = "Unable to ack block length.";
- } else if (i < kAckBlockLengthOffset4) {
- expected_error = "Unable to read gap to next ack block.";
- } else if (i < kNumTimestampsOffset) {
- expected_error = "Unable to ack block length.";
- } else if (i < kTimestampDeltaLargestObserved1) {
- expected_error = "Unable to read num received packets.";
- } else if (i < kTimestampTimeDeltaLargestObserved1) {
- expected_error = "Unable to read sequence delta in received packets.";
- } else if (i < kTimestampDeltaLargestObserved2) {
- expected_error = "Unable to read time delta in received packets.";
- } else if (i < kTimestampTimeDeltaLargestObserved2) {
- expected_error = "Unable to read sequence delta in received packets.";
- } else {
- expected_error =
- "Unable to read incremental time delta in received packets.";
- }
-
- CheckProcessingFails(
- packet,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_ACK_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, AckFrameVersion32) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
- 0x6C,
- // entropy hash of all received packets.
- 0xBA,
- // largest observed packet number
- 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // Number of timestamps.
- 0x00,
- // num missing packets
- 0x01,
- // missing packet delta
- 0x01,
- // 0 more missing packets in range.
- 0x00,
- };
- // clang-format on
-
- if (framer_.version() <= QUIC_VERSION_31 ||
- framer_.version() > QUIC_VERSION_33) {
- return;
- }
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(0u, visitor_.stream_frames_.size());
- ASSERT_EQ(1u, visitor_.ack_frames_.size());
- const QuicAckFrame& frame = *visitor_.ack_frames_[0];
- EXPECT_EQ(0xBA, frame.entropy_hash);
- EXPECT_EQ(kLargestObserved, frame.largest_observed);
- ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
- EXPECT_EQ(kMissingPacket, frame.packets.Min());
-
- const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
- const size_t kLargestObservedOffset =
- kReceivedEntropyOffset + kQuicEntropyHashSize;
- const size_t kMissingDeltaTimeOffset =
- kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
- const size_t kNumTimestampsOffset =
- kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
- const size_t kNumMissingPacketOffset =
- kNumTimestampsOffset + kQuicNumTimestampsSize;
- const size_t kMissingPacketsOffset =
- kNumMissingPacketOffset + kNumberOfNackRangesSize;
- // Now test framing boundaries.
- const size_t ack_frame_size = PACKET_1BYTE_PACKET_NUMBER;
- for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
- string expected_error;
- if (i < kLargestObservedOffset) {
- expected_error = "Unable to read entropy hash for received packets.";
- } else if (i < kMissingDeltaTimeOffset) {
- expected_error = "Unable to read largest observed.";
- } else if (i < kNumTimestampsOffset) {
- expected_error = "Unable to read ack delay time.";
- } else if (i < kNumMissingPacketOffset) {
- expected_error = "Unable to read num received packets.";
- } else if (i < kMissingPacketsOffset) {
- expected_error = "Unable to read num missing packet ranges.";
- } else {
- expected_error = "Unable to read missing packet number delta.";
- }
- CheckProcessingFails(
- packet,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_ACK_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, AckFrameRevivedPackets) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
- 0x6C,
- // entropy hash of all received packets.
- 0xBA,
- // largest observed packet number
- 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // num received packets.
- 0x00,
- // num missing packets
- 0x01,
- // missing packet delta
- 0x01,
- // 0 more missing packets in range.
- 0x00,
- // Number of revived packets.
- 0x01,
- // Revived packet number.
- 0xBE, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // Number of revived packets.
- 0x00,
- };
- // clang-format on
-
- if (framer_.version() > QUIC_VERSION_31) {
- return;
- }
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(0u, visitor_.stream_frames_.size());
- ASSERT_EQ(1u, visitor_.ack_frames_.size());
- const QuicAckFrame& frame = *visitor_.ack_frames_[0];
- EXPECT_EQ(0xBA, frame.entropy_hash);
- EXPECT_EQ(kLargestObserved, frame.largest_observed);
- ASSERT_EQ(1u, frame.packets.NumPacketsSlow());
- EXPECT_EQ(kMissingPacket, frame.packets.Min());
-
- const size_t kReceivedEntropyOffset = kQuicFrameTypeSize;
- const size_t kLargestObservedOffset =
- kReceivedEntropyOffset + kQuicEntropyHashSize;
- const size_t kMissingDeltaTimeOffset =
- kLargestObservedOffset + PACKET_6BYTE_PACKET_NUMBER;
- const size_t kNumTimestampsOffset =
- kMissingDeltaTimeOffset + kQuicDeltaTimeLargestObservedSize;
- const size_t kNumMissingPacketOffset =
- kNumTimestampsOffset + kQuicNumTimestampsSize;
- const size_t kMissingPacketsOffset =
- kNumMissingPacketOffset + kNumberOfNackRangesSize;
- const size_t kMissingPacketsRange =
- kMissingPacketsOffset + PACKET_1BYTE_PACKET_NUMBER;
- const size_t kRevivedPacketsLength =
- kMissingPacketsRange + PACKET_1BYTE_PACKET_NUMBER;
- const size_t kRevivedPacketSequenceNumberLength =
- kRevivedPacketsLength + PACKET_1BYTE_PACKET_NUMBER;
- // Now test framing boundaries.
- const size_t ack_frame_size =
- kRevivedPacketSequenceNumberLength + PACKET_6BYTE_PACKET_NUMBER;
- for (size_t i = kQuicFrameTypeSize; i < ack_frame_size; ++i) {
- string expected_error;
- if (i < kReceivedEntropyOffset) {
- expected_error = "Unable to read least unacked delta.";
- } else if (i < kLargestObservedOffset) {
- expected_error = "Unable to read entropy hash for received packets.";
- } else if (i < kMissingDeltaTimeOffset) {
- expected_error = "Unable to read largest observed.";
- } else if (i < kNumTimestampsOffset) {
- expected_error = "Unable to read ack delay time.";
- } else if (i < kNumMissingPacketOffset) {
- expected_error = "Unable to read num received packets.";
- } else if (i < kMissingPacketsOffset) {
- expected_error = "Unable to read num missing packet ranges.";
- } else if (i < kMissingPacketsRange) {
- expected_error = "Unable to read missing packet number delta.";
- } else if (i < kRevivedPacketsLength) {
- expected_error = "Unable to read missing packet number range.";
- } else if (i < kRevivedPacketSequenceNumberLength) {
- expected_error = "Unable to read num revived packets.";
- } else {
- expected_error = "Unable to read revived packet.";
- }
- CheckProcessingFails(
- packet,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_ACK_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, AckFrameNoNacks) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (no nacks, not truncated, 6 byte largest observed, 1 byte delta)
- 0x4C,
- // entropy hash of all received packets.
- 0xBA,
- // largest observed packet number
- 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // Number of received packets.
- 0x00,
- };
- // clang-format on
- if (framer_.version() >= QUIC_VERSION_31) {
- return;
- }
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(0u, visitor_.stream_frames_.size());
- ASSERT_EQ(1u, visitor_.ack_frames_.size());
- QuicAckFrame* frame = visitor_.ack_frames_[0];
- EXPECT_EQ(0xBA, frame->entropy_hash);
- EXPECT_EQ(kLargestObserved, frame->largest_observed);
- ASSERT_TRUE(frame->packets.Empty());
-
- // Verify that the packet re-serializes identically.
- QuicFrames frames;
- frames.push_back(QuicFrame(frame));
- std::unique_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST_P(QuicFramerTest, AckFrame500Nacks) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
- 0x6C,
- // entropy hash of all received packets.
- 0xBA,
- // largest observed packet number
- 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // No received packets.
- 0x00,
- // num missing packet ranges
- 0x02,
- // missing packet delta
- 0x01,
- // 243 more missing packets in range.
- // The ranges are listed in this order so the re-constructed packet
- // matches.
- 0xF3,
- // No gap between ranges
- 0x00,
- // 255 more missing packets in range.
- 0xFF,
- // No revived packets.
- 0x00,
- };
- // clang-format on
-
- if (framer_.version() > QUIC_VERSION_31) {
- return;
- }
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(0u, visitor_.stream_frames_.size());
- ASSERT_EQ(1u, visitor_.ack_frames_.size());
- QuicAckFrame* frame = visitor_.ack_frames_[0];
- EXPECT_EQ(0xBA, frame->entropy_hash);
- EXPECT_EQ(kLargestObserved, frame->largest_observed);
- ASSERT_EQ(500u, frame->packets.NumPacketsSlow());
- EXPECT_EQ(kMissingPacket - 499, frame->packets.Min());
- EXPECT_EQ(kMissingPacket, frame->packets.Max());
-
- // Verify that the packet re-serializes identically.
- QuicFrames frames;
- frames.push_back(QuicFrame(frame));
- std::unique_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST_P(QuicFramerTest, AckFrame500NacksVersion32) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xA8, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
- 0x6C,
- // entropy hash of all received packets.
- 0xBA,
- // largest observed packet number
- 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // No received packets.
- 0x00,
- // num missing packet ranges
- 0x02,
- // missing packet delta
- 0x01,
- // 243 more missing packets in range.
- // The ranges are listed in this order so the re-constructed packet
- // matches.
- 0xF3,
- // No gap between ranges
- 0x00,
- // 255 more missing packets in range.
- 0xFF,
- };
- // clang-format on
-
- if (framer_.version() <= QUIC_VERSION_31 ||
- framer_.version() > QUIC_VERSION_33) {
- return;
- }
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(0u, visitor_.stream_frames_.size());
- ASSERT_EQ(1u, visitor_.ack_frames_.size());
- QuicAckFrame* frame = visitor_.ack_frames_[0];
- EXPECT_EQ(0xBA, frame->entropy_hash);
- EXPECT_EQ(kLargestObserved, frame->largest_observed);
- ASSERT_EQ(500u, frame->packets.NumPacketsSlow());
- EXPECT_EQ(kMissingPacket - 499, frame->packets.Min());
- EXPECT_EQ(kMissingPacket, frame->packets.Max());
-
- // Verify that the packet re-serializes identically.
- QuicFrames frames;
- frames.push_back(QuicFrame(frame));
- std::unique_ptr<QuicPacket> data(BuildDataPacket(*visitor_.header_, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST_P(QuicFramerTest, StopWaitingFrame) {
- if (framer_.version() > QUIC_VERSION_33) {
- return;
- }
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xA8, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
- 0x06,
- // entropy hash of sent packets till least awaiting - 1.
- 0xAB,
- // least packet number awaiting an ack, delta from packet number.
- 0x08, 0x00, 0x00, 0x00,
- 0x00, 0x00,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(0u, visitor_.stream_frames_.size());
- ASSERT_EQ(1u, visitor_.stop_waiting_frames_.size());
- const QuicStopWaitingFrame& frame = *visitor_.stop_waiting_frames_[0];
- EXPECT_EQ(0xAB, frame.entropy_hash);
- EXPECT_EQ(kLeastUnacked, frame.least_unacked);
-
- const size_t kSentEntropyOffset = kQuicFrameTypeSize;
- const size_t kLeastUnackedOffset = kSentEntropyOffset + kQuicEntropyHashSize;
- const size_t frame_size = 7;
- for (size_t i = kQuicFrameTypeSize; i < frame_size; ++i) {
- string expected_error;
- if (i < kLeastUnackedOffset) {
- expected_error = "Unable to read entropy hash for sent packets.";
- } else {
- expected_error = "Unable to read least unacked delta.";
- }
- CheckProcessingFails(
- packet,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_STOP_WAITING_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, NewStopWaitingFrame) {
- if (framer_.version() <= QUIC_VERSION_33) {
- return;
- }
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x3C,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xA8, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // frame type (stop waiting frame)
- 0x06,
- // least packet number awaiting an ack, delta from packet number.
- 0x08, 0x00, 0x00, 0x00,
- 0x00, 0x00,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(0u, visitor_.stream_frames_.size());
- ASSERT_EQ(1u, visitor_.stop_waiting_frames_.size());
- const QuicStopWaitingFrame& frame = *visitor_.stop_waiting_frames_[0];
- EXPECT_EQ(kLeastUnacked, frame.least_unacked);
-
- const size_t frame_size = 7;
- for (size_t i = kQuicFrameTypeSize; i < frame_size; ++i) {
- string expected_error;
- expected_error = "Unable to read least unacked delta.";
- CheckProcessingFails(
- packet,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_STOP_WAITING_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, RstStreamFrameQuic) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (rst stream frame)
- 0x01,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
-
- // sent byte offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
-
- // error code
- 0x01, 0x00, 0x00, 0x00,
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (rst stream frame)
- 0x01,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
-
- // sent byte offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
-
- // error code
- 0x01, 0x00, 0x00, 0x00,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(kStreamId, visitor_.rst_stream_frame_.stream_id);
- EXPECT_EQ(0x01, visitor_.rst_stream_frame_.error_code);
- EXPECT_EQ(kStreamOffset, visitor_.rst_stream_frame_.byte_offset);
-
- // Now test framing boundaries.
- for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetRstStreamFrameSize();
- ++i) {
- string expected_error;
- if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
- expected_error = "Unable to read stream_id.";
- } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
- kQuicMaxStreamOffsetSize) {
- expected_error = "Unable to read rst stream sent byte offset.";
- } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
- kQuicMaxStreamOffsetSize + kQuicErrorCodeSize) {
- expected_error = "Unable to read rst stream error code.";
- }
- CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_RST_STREAM_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, ConnectionCloseFrame) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (connection close frame)
- 0x02,
- // error code
- 0x11, 0x00, 0x00, 0x00,
-
- // error details length
- 0x0d, 0x00,
- // error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n',
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (connection close frame)
- 0x02,
- // error code
- 0x11, 0x00, 0x00, 0x00,
-
- // error details length
- 0x0d, 0x00,
- // error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n',
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(0u, visitor_.stream_frames_.size());
-
- EXPECT_EQ(0x11, visitor_.connection_close_frame_.error_code);
- EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details);
-
- ASSERT_EQ(0u, visitor_.ack_frames_.size());
-
- // Now test framing boundaries.
- for (size_t i = kQuicFrameTypeSize;
- i < QuicFramer::GetMinConnectionCloseFrameSize(); ++i) {
- string expected_error;
- if (i < kQuicFrameTypeSize + kQuicErrorCodeSize) {
- expected_error = "Unable to read connection close error code.";
- } else {
- expected_error = "Unable to read connection close error details.";
- }
- CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_CONNECTION_CLOSE_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, GoAwayFrame) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (go away frame)
- 0x03,
- // error code
- 0x09, 0x00, 0x00, 0x00,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // error details length
- 0x0d, 0x00,
- // error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n',
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (go away frame)
- 0x03,
- // error code
- 0x09, 0x00, 0x00, 0x00,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // error details length
- 0x0d, 0x00,
- // error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n',
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(kStreamId, visitor_.goaway_frame_.last_good_stream_id);
- EXPECT_EQ(0x9, visitor_.goaway_frame_.error_code);
- EXPECT_EQ("because I can", visitor_.goaway_frame_.reason_phrase);
-
- const size_t reason_size = arraysize("because I can") - 1;
- // Now test framing boundaries.
- for (size_t i = kQuicFrameTypeSize;
- i < QuicFramer::GetMinGoAwayFrameSize() + reason_size; ++i) {
- string expected_error;
- if (i < kQuicFrameTypeSize + kQuicErrorCodeSize) {
- expected_error = "Unable to read go away error code.";
- } else if (i <
- kQuicFrameTypeSize + kQuicErrorCodeSize + kQuicMaxStreamIdSize) {
- expected_error = "Unable to read last good stream id.";
- } else {
- expected_error = "Unable to read goaway reason.";
- }
- CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_GOAWAY_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, WindowUpdateFrame) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (window update frame)
- 0x04,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // byte offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (window update frame)
- 0x04,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // byte offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
-
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(kStreamId, visitor_.window_update_frame_.stream_id);
- EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.byte_offset);
-
- // Now test framing boundaries.
- for (size_t i = kQuicFrameTypeSize;
- i < QuicFramer::GetWindowUpdateFrameSize(); ++i) {
- string expected_error;
- if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
- expected_error = "Unable to read stream_id.";
- } else {
- expected_error = "Unable to read window byte_offset.";
- }
- CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_WINDOW_UPDATE_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, BlockedFrame) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (blocked frame)
- 0x05,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (blocked frame)
- 0x05,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
-
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(kStreamId, visitor_.blocked_frame_.stream_id);
-
- // Now test framing boundaries.
- for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetBlockedFrameSize();
- ++i) {
- string expected_error = "Unable to read stream_id.";
- CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_BLOCKED_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, PingFrame) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (ping frame)
- 0x07,
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (ping frame)
- 0x07,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce));
-
- EXPECT_EQ(1u, visitor_.ping_frames_.size());
-
- // No need to check the PING frame boundaries because it has no payload.
-}
-
-TEST_P(QuicFramerTest, PathCloseFrame) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (version)
- 0x78,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x00,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (path_close_frame)
- 0x08,
- // path id
- 0x42,
- };
- unsigned char packet_34[] = {
- // public flags (version)
- 0x78,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x00,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
-
- // frame type (path_close_frame)
- 0x08,
- // path id
- 0x42,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
-
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- // TODO(fayang): CheckDecryption after cl/110553865 is landed.
- EXPECT_EQ(kPathId, visitor_.path_close_frame_.path_id);
-
- // Now test framing boundaries.
- for (size_t i = kQuicFrameTypeSize; i < QuicFramer::GetPathCloseFrameSize();
- ++i) {
- string expected_error;
- if (i < kQuicFrameTypeSize + kQuicPathIdSize) {
- expected_error = "Unable to read path_id.";
- }
- CheckProcessingFails(
- framer_.version() <= QUIC_VERSION_33 ? packet : packet_34,
- i + GetPacketHeaderSize(framer_.version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, kIncludePathId,
- !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER),
- expected_error, QUIC_INVALID_PATH_CLOSE_DATA);
- }
-}
-
-TEST_P(QuicFramerTest, PublicResetPacketV33) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (public reset, 8 byte connection_id)
- 0x0A,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // message tag (kPRST)
- 'P', 'R', 'S', 'T',
- // num_entries (2) + padding
- 0x02, 0x00, 0x00, 0x00,
- // tag kRNON
- 'R', 'N', 'O', 'N',
- // end offset 8
- 0x08, 0x00, 0x00, 0x00,
- // tag kRSEQ
- 'R', 'S', 'E', 'Q',
- // end offset 16
- 0x10, 0x00, 0x00, 0x00,
- // nonce proof
- 0x89, 0x67, 0x45, 0x23,
- 0x01, 0xEF, 0xCD, 0xAB,
- // rejected packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12, 0x00, 0x00,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.public_reset_packet_.get());
- EXPECT_EQ(kConnectionId,
- visitor_.public_reset_packet_->public_header.connection_id);
- EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag);
- EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag);
- EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof);
- EXPECT_EQ(0u, visitor_.public_reset_packet_->rejected_packet_number);
- EXPECT_EQ(ADDRESS_FAMILY_UNSPECIFIED,
- visitor_.public_reset_packet_->client_address.GetFamily());
-
- // Now test framing boundaries.
- for (size_t i = 0; i < arraysize(packet); ++i) {
- string expected_error;
- DVLOG(1) << "iteration: " << i;
- if (i < kConnectionIdOffset) {
- expected_error = "Unable to read public flags.";
- CheckProcessingFails(packet, i, expected_error,
- QUIC_INVALID_PACKET_HEADER);
- } else if (i < kPublicResetPacketMessageTagOffset) {
- expected_error = "Unable to read ConnectionId.";
- CheckProcessingFails(packet, i, expected_error,
- QUIC_INVALID_PACKET_HEADER);
- } else {
- expected_error = "Unable to read reset message.";
- CheckProcessingFails(packet, i, expected_error,
- QUIC_INVALID_PUBLIC_RST_PACKET);
- }
- }
-}
-
-TEST_P(QuicFramerTest, PublicResetPacket) {
- QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (public reset, 8 byte connection_id)
- 0x0E,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // message tag (kPRST)
- 'P', 'R', 'S', 'T',
- // num_entries (2) + padding
- 0x02, 0x00, 0x00, 0x00,
- // tag kRNON
- 'R', 'N', 'O', 'N',
- // end offset 8
- 0x08, 0x00, 0x00, 0x00,
- // tag kRSEQ
- 'R', 'S', 'E', 'Q',
- // end offset 16
- 0x10, 0x00, 0x00, 0x00,
- // nonce proof
- 0x89, 0x67, 0x45, 0x23,
- 0x01, 0xEF, 0xCD, 0xAB,
- // rejected packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12, 0x00, 0x00,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.public_reset_packet_.get());
- EXPECT_EQ(kConnectionId,
- visitor_.public_reset_packet_->public_header.connection_id);
- EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag);
- EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag);
- EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof);
- EXPECT_EQ(0u, visitor_.public_reset_packet_->rejected_packet_number);
- EXPECT_EQ(ADDRESS_FAMILY_UNSPECIFIED,
- visitor_.public_reset_packet_->client_address.GetFamily());
-
- // Now test framing boundaries.
- for (size_t i = 0; i < arraysize(packet); ++i) {
- string expected_error;
- DVLOG(1) << "iteration: " << i;
- if (i < kConnectionIdOffset) {
- expected_error = "Unable to read public flags.";
- CheckProcessingFails(packet, i, expected_error,
- QUIC_INVALID_PACKET_HEADER);
- } else if (i < kPublicResetPacketMessageTagOffset) {
- expected_error = "Unable to read ConnectionId.";
- CheckProcessingFails(packet, i, expected_error,
- QUIC_INVALID_PACKET_HEADER);
- } else {
- expected_error = "Unable to read reset message.";
- CheckProcessingFails(packet, i, expected_error,
- QUIC_INVALID_PUBLIC_RST_PACKET);
- }
- }
-}
-
-TEST_P(QuicFramerTest, PublicResetPacketWithTrailingJunk) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (public reset, 8 byte connection_id)
- 0x0A,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // message tag (kPRST)
- 'P', 'R', 'S', 'T',
- // num_entries (2) + padding
- 0x02, 0x00, 0x00, 0x00,
- // tag kRNON
- 'R', 'N', 'O', 'N',
- // end offset 8
- 0x08, 0x00, 0x00, 0x00,
- // tag kRSEQ
- 'R', 'S', 'E', 'Q',
- // end offset 16
- 0x10, 0x00, 0x00, 0x00,
- // nonce proof
- 0x89, 0x67, 0x45, 0x23,
- 0x01, 0xEF, 0xCD, 0xAB,
- // rejected packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12, 0x00, 0x00,
- // trailing junk
- 'j', 'u', 'n', 'k',
- };
- // clang-format on
-
- string expected_error = "Unable to read reset message.";
- CheckProcessingFails(packet, arraysize(packet), expected_error,
- QUIC_INVALID_PUBLIC_RST_PACKET);
-}
-
-TEST_P(QuicFramerTest, PublicResetPacketWithClientAddress) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (public reset, 8 byte connection_id)
- 0x0A,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // message tag (kPRST)
- 'P', 'R', 'S', 'T',
- // num_entries (3) + padding
- 0x03, 0x00, 0x00, 0x00,
- // tag kRNON
- 'R', 'N', 'O', 'N',
- // end offset 8
- 0x08, 0x00, 0x00, 0x00,
- // tag kRSEQ
- 'R', 'S', 'E', 'Q',
- // end offset 16
- 0x10, 0x00, 0x00, 0x00,
- // tag kCADR
- 'C', 'A', 'D', 'R',
- // end offset 24
- 0x18, 0x00, 0x00, 0x00,
- // nonce proof
- 0x89, 0x67, 0x45, 0x23,
- 0x01, 0xEF, 0xCD, 0xAB,
- // rejected packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12, 0x00, 0x00,
- // client address: 4.31.198.44:443
- 0x02, 0x00,
- 0x04, 0x1F, 0xC6, 0x2C,
- 0xBB, 0x01,
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.public_reset_packet_.get());
- EXPECT_EQ(kConnectionId,
- visitor_.public_reset_packet_->public_header.connection_id);
- EXPECT_TRUE(visitor_.public_reset_packet_->public_header.reset_flag);
- EXPECT_FALSE(visitor_.public_reset_packet_->public_header.version_flag);
- EXPECT_EQ(kNonceProof, visitor_.public_reset_packet_->nonce_proof);
- EXPECT_EQ(0u, visitor_.public_reset_packet_->rejected_packet_number);
- EXPECT_EQ("4.31.198.44",
- visitor_.public_reset_packet_->client_address.address().ToString());
- EXPECT_EQ(443, visitor_.public_reset_packet_->client_address.port());
-
- // Now test framing boundaries.
- for (size_t i = 0; i < arraysize(packet); ++i) {
- string expected_error;
- DVLOG(1) << "iteration: " << i;
- if (i < kConnectionIdOffset) {
- expected_error = "Unable to read public flags.";
- CheckProcessingFails(packet, i, expected_error,
- QUIC_INVALID_PACKET_HEADER);
- } else if (i < kPublicResetPacketMessageTagOffset) {
- expected_error = "Unable to read ConnectionId.";
- CheckProcessingFails(packet, i, expected_error,
- QUIC_INVALID_PACKET_HEADER);
- } else {
- expected_error = "Unable to read reset message.";
- CheckProcessingFails(packet, i, expected_error,
- QUIC_INVALID_PUBLIC_RST_PACKET);
- }
- }
-}
-
-TEST_P(QuicFramerTest, VersionNegotiationPacket) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (version, 8 byte connection_id)
- 0x39,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
- 'Q', '2', '.', '0',
- };
- // clang-format on
-
- QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.version_negotiation_packet_.get());
- EXPECT_EQ(2u, visitor_.version_negotiation_packet_->versions.size());
- EXPECT_EQ(GetParam(), visitor_.version_negotiation_packet_->versions[0]);
-
- for (size_t i = 0; i <= kPublicFlagsSize + PACKET_8BYTE_CONNECTION_ID; ++i) {
- string expected_error;
- QuicErrorCode error_code = QUIC_INVALID_PACKET_HEADER;
- if (i < kConnectionIdOffset) {
- expected_error = "Unable to read public flags.";
- } else if (i < kVersionOffset) {
- expected_error = "Unable to read ConnectionId.";
- } else {
- expected_error = "Unable to read supported version in negotiation.";
- error_code = QUIC_INVALID_VERSION_NEGOTIATION_PACKET;
- }
- CheckProcessingFails(packet, i, expected_error, error_code);
- }
-}
-
-TEST_P(QuicFramerTest, OldVersionNegotiationPacket) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (version, 8 byte connection_id)
- 0x3D,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
- 'Q', '2', '.', '0',
- };
- // clang-format on
-
- QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.version_negotiation_packet_.get());
- EXPECT_EQ(2u, visitor_.version_negotiation_packet_->versions.size());
- EXPECT_EQ(GetParam(), visitor_.version_negotiation_packet_->versions[0]);
-
- for (size_t i = 0; i <= kPublicFlagsSize + PACKET_8BYTE_CONNECTION_ID; ++i) {
- string expected_error;
- QuicErrorCode error_code = QUIC_INVALID_PACKET_HEADER;
- if (i < kConnectionIdOffset) {
- expected_error = "Unable to read public flags.";
- } else if (i < kVersionOffset) {
- expected_error = "Unable to read ConnectionId.";
- } else {
- expected_error = "Unable to read supported version in negotiation.";
- error_code = QUIC_INVALID_VERSION_NEGOTIATION_PACKET;
- }
- CheckProcessingFails(packet, i, expected_error, error_code);
- }
-}
-
-TEST_P(QuicFramerTest, DropFecPacket) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags (fec group & FEC)
- 0x06,
- // first fec protected packet offset
- 0x01,
-
- // redundancy
- 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p',
- };
- if (framer_.version() > QUIC_VERSION_33) {
- return;
- }
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- if (framer_.version() <= QUIC_VERSION_31) {
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- } else {
- EXPECT_FALSE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
- }
- EXPECT_FALSE(visitor_.header_.get());
-}
-
-TEST_P(QuicFramerTest, BuildPaddingFramePacket) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = false;
- header.packet_number = kPacketNumber;
-
- QuicPaddingFrame padding_frame;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(padding_frame));
-
- // clang-format off
- unsigned char packet[kMaxPacketSize] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- unsigned char packet_34[kMaxPacketSize] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- // clang-format on
-
- uint64_t header_size = GetPacketHeaderSize(
- framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
- !kIncludePathId, !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER);
- memset((framer_.version() <= QUIC_VERSION_33 ? packet : packet_34) +
- header_size + 1,
- 0x00, kMaxPacketSize - header_size - 1);
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-TEST_P(QuicFramerTest, Build4ByteSequenceNumberPaddingFramePacket) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = false;
- header.public_header.packet_number_length = PACKET_4BYTE_PACKET_NUMBER;
- header.packet_number = kPacketNumber;
-
- QuicPaddingFrame padding_frame;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(padding_frame));
-
- // clang-format off
- unsigned char packet[kMaxPacketSize] = {
- // public flags (8 byte connection_id and 4 byte packet number)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x28 : 0x2C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- // private flags
- 0x00,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- unsigned char packet_34[kMaxPacketSize] = {
- // public flags (8 byte connection_id and 4 byte packet number)
- 0x28,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- // clang-format on
-
- uint64_t header_size = GetPacketHeaderSize(
- framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
- !kIncludePathId, !kIncludeDiversificationNonce,
- PACKET_4BYTE_PACKET_NUMBER);
- memset((framer_.version() <= QUIC_VERSION_33 ? packet : packet_34) +
- header_size + 1,
- 0x00, kMaxPacketSize - header_size - 1);
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-TEST_P(QuicFramerTest, Build2ByteSequenceNumberPaddingFramePacket) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = false;
- header.public_header.packet_number_length = PACKET_2BYTE_PACKET_NUMBER;
- header.packet_number = kPacketNumber;
-
- QuicPaddingFrame padding_frame;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(padding_frame));
-
- // clang-format off
- unsigned char packet[kMaxPacketSize] = {
- // public flags (8 byte connection_id and 2 byte packet number)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x18 : 0x1C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A,
- // private flags
- 0x00,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- unsigned char packet_34[kMaxPacketSize] = {
- // public flags (8 byte connection_id and 2 byte packet number)
- 0x18,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- // clang-format on
-
- uint64_t header_size = GetPacketHeaderSize(
- framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
- !kIncludePathId, !kIncludeDiversificationNonce,
- PACKET_2BYTE_PACKET_NUMBER);
- memset((framer_.version() <= QUIC_VERSION_33 ? packet : packet_34) +
- header_size + 1,
- 0x00, kMaxPacketSize - header_size - 1);
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-TEST_P(QuicFramerTest, Build1ByteSequenceNumberPaddingFramePacket) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = false;
- header.public_header.packet_number_length = PACKET_1BYTE_PACKET_NUMBER;
- header.packet_number = kPacketNumber;
-
- QuicPaddingFrame padding_frame;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(padding_frame));
-
- // clang-format off
- unsigned char packet[kMaxPacketSize] = {
- // public flags (8 byte connection_id and 1 byte packet number)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x08 : 0x0C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC,
- // private flags
- 0x00,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- unsigned char packet_34[kMaxPacketSize] = {
- // public flags (8 byte connection_id and 1 byte packet number)
- 0x08,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC,
-
- // frame type (padding frame)
- 0x00,
- 0x00, 0x00, 0x00, 0x00
- };
- // clang-format on
-
- uint64_t header_size = GetPacketHeaderSize(
- framer_.version(), PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion,
- !kIncludePathId, !kIncludeDiversificationNonce,
- PACKET_1BYTE_PACKET_NUMBER);
- memset((framer_.version() <= QUIC_VERSION_33 ? packet : packet_34) +
- header_size + 1,
- 0x00, kMaxPacketSize - header_size - 1);
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-TEST_P(QuicFramerTest, BuildStreamFramePacket) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.packet_number = kPacketNumber;
-
- QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
- StringPiece("hello world!"));
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&stream_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (stream frame with fin and no length)
- 0xDF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (stream frame with fin and no length)
- 0xDF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = true;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.packet_number = kPacketNumber;
-
- QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
- StringPiece("hello world!"));
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&stream_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (version, 8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x3D : 0x3D),
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (stream frame with fin and no length)
- 0xDF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32, 0xDC, 0xFE, 0x98, 0xBA,
- // data
- 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
- };
- unsigned char packet_34[] = {
- // public flags (version, 8 byte connection_id)
- 0x3D,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
-
- // frame type (stream frame with fin and no length)
- 0xDF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32, 0xDC, 0xFE, 0x98, 0xBA,
- // data
- 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
- };
- // clang-format on
-
- QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-TEST_P(QuicFramerTest, BuildStreamFramePacketWithMultipathFlag) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.multipath_flag = true;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.path_id = kPathId;
- header.packet_number = kPacketNumber;
-
- QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
- StringPiece("hello world!"));
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&stream_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x78 : 0x7C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (stream frame with fin and no length)
- 0xDF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x78,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (stream frame with fin and no length)
- 0xDF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-TEST_P(QuicFramerTest, BuildStreamFramePacketWithBothVersionAndMultipathFlag) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.multipath_flag = true;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = true;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.path_id = kPathId;
- header.packet_number = kPacketNumber;
-
- QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset,
- StringPiece("hello world!"));
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&stream_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x7D : 0x7D),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (stream frame with fin and no length)
- 0xDF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x7D,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (stream frame with fin and no length)
- 0xDF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- // clang-format on
-
- QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT);
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-TEST_P(QuicFramerTest, BuildVersionNegotiationPacket) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (version, 8 byte connection_id)
- 0x0D,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '0', GetQuicVersionDigitTens(), GetQuicVersionDigitOnes(),
- };
- // clang-format on
-
- QuicConnectionId connection_id = kConnectionId;
- std::unique_ptr<QuicEncryptedPacket> data(
- framer_.BuildVersionNegotiationPacket(connection_id,
- SupportedVersions(GetParam())));
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST_P(QuicFramerTest, BuildAckFramePacket) {
- if (framer_.version() > QUIC_VERSION_33) {
- return;
- }
-
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.packet_number = kPacketNumber;
-
- QuicAckFrame ack_frame;
- ack_frame.entropy_hash = 0x43;
- ack_frame.largest_observed = kLargestObserved;
- ack_frame.ack_delay_time = QuicTime::Delta::Zero();
- ack_frame.packets.Add(kMissingPacket);
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&ack_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x3C,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
- 0x6C,
- // entropy hash of all received packets.
- 0x43,
- // largest observed packet number
- 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // num received packets.
- 0x00,
- // num missing packet ranges
- 0x01,
- // missing packet delta
- 0x01,
- // 0 more missing packets in range.
- 0x00,
- // 0 revived packets.
- 0x00,
- };
- // clang-format on
-
- // clang-format off
- unsigned char packet_version32[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, not truncated, 6 byte largest observed, 1 byte delta)
- 0x6C,
- // entropy hash of all received packets.
- 0x43,
- // largest observed packet number
- 0xBF, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // num received packets.
- 0x00,
- // num missing packet ranges
- 0x01,
- // missing packet delta
- 0x01,
- // 0 more missing packets in range.
- 0x00,
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- if (framer_.version() <= QUIC_VERSION_31) {
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
- } else {
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(packet_version32), arraysize(packet_version32));
- }
-}
-
-// TODO(jri): Add test for tuncated packets in which the original ack frame had
-// revived packets. (In both the large and small packet cases below).
-
-TEST_P(QuicFramerTest, BuildTruncatedAckFrameLargePacket) {
- if (framer_.version() > QUIC_VERSION_33) {
- return;
- }
-
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.packet_number = kPacketNumber;
-
- QuicAckFrame ack_frame;
- // This entropy hash is different from what shows up in the packet below,
- // since entropy is recomputed by the framer on ack truncation (by
- // TestEntropyCalculator for this test.)
- ack_frame.entropy_hash = 0x43;
- ack_frame.largest_observed = 2 * 300;
- ack_frame.ack_delay_time = QuicTime::Delta::Zero();
- for (size_t i = 1; i < 2 * 300; i += 2) {
- ack_frame.packets.Add(i);
- }
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&ack_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x3C,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
- 0x74,
- // entropy hash of all received packets, set to 1 by TestEntropyCalculator
- // since ack is truncated.
- 0x01,
- // 2-byte largest observed packet number.
- // Expected to be 510 (0x1FE), since only 255 nack ranges can fit.
- 0xFE, 0x01,
- // Zero delta time.
- 0x00, 0x00,
- // num missing packet ranges (limited to 255 by size of this field).
- 0xFF,
- // {missing packet delta, further missing packets in range}
- // 6 nack ranges x 42 + 3 nack ranges
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
-
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
-
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
-
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
-
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
-
- // 0 revived packets.
- 0x00,
- };
- // clang-format on
-
- // clang-format off
- unsigned char packet_version32[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
- 0x74,
- // entropy hash of all received packets, set to 1 by TestEntropyCalculator
- // since ack is truncated.
- 0x01,
- // 2-byte largest observed packet number.
- // Expected to be 510 (0x1FE), since only 255 nack ranges can fit.
- 0xFE, 0x01,
- // Zero delta time.
- 0x00, 0x00,
- // num missing packet ranges (limited to 255 by size of this field).
- 0xFF,
- // {missing packet delta, further missing packets in range}
- // 6 nack ranges x 42 + 3 nack ranges
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
-
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
-
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
-
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
-
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- if (framer_.version() <= QUIC_VERSION_31) {
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
- } else {
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(packet_version32), arraysize(packet_version32));
- }
-}
-
-TEST_P(QuicFramerTest, BuildTruncatedAckFrameSmallPacket) {
- if (framer_.version() > QUIC_VERSION_33) {
- return;
- }
-
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.packet_number = kPacketNumber;
-
- QuicAckFrame ack_frame;
- // This entropy hash is different from what shows up in the packet below,
- // since entropy is recomputed by the framer on ack truncation (by
- // TestEntropyCalculator for this test.)
- ack_frame.entropy_hash = 0x43;
- ack_frame.largest_observed = 2 * 300;
- ack_frame.ack_delay_time = QuicTime::Delta::Zero();
- for (size_t i = 1; i < 2 * 300; i += 2) {
- ack_frame.packets.Add(i);
- }
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&ack_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x3C,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
- 0x74,
- // entropy hash of all received packets, set to 1 by TestEntropyCalculator
- // since ack is truncated.
- 0x01,
- // 2-byte largest observed packet number.
- // Expected to be 12 (0x0C), since only 6 nack ranges can fit.
- 0x0C, 0x00,
- // Zero delta time.
- 0x00, 0x00,
- // num missing packet ranges (limited to 6 by packet size of 37).
- 0x06,
- // {missing packet delta, further missing packets in range}
- // 6 nack ranges
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- // 0 revived packets.
- 0x00,
- };
- // clang-format on
-
- // clang-format off
- unsigned char packet_version32[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (ack frame)
- // (has nacks, is truncated, 2 byte largest observed, 1 byte delta)
- 0x74,
- // entropy hash of all received packets, set to 1 by TestEntropyCalculator
- // since ack is truncated.
- 0x01,
- // 2-byte largest observed packet number.
- // Expected to be 12 (0x0C), since only 6 nack ranges can fit.
- 0x0C, 0x00,
- // Zero delta time.
- 0x00, 0x00,
- // num missing packet ranges (limited to 6 by packet size of 37).
- 0x06,
- // {missing packet delta, further missing packets in range}
- // 6 nack ranges
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- };
- // clang-format on
-
- if (framer_.version() <= QUIC_VERSION_31) {
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames, 37u));
- ASSERT_TRUE(data != nullptr);
- // Expect 1 byte unused since at least 2 bytes are needed to fit more nacks.
- EXPECT_EQ(36u, data->length());
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
- } else {
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames, 36u));
- ASSERT_TRUE(data != nullptr);
- // Expect 1 byte unused since at least 2 bytes are needed to fit more nacks.
- EXPECT_EQ(35u, data->length());
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(packet_version32), arraysize(packet_version32));
- }
-}
-
-TEST_P(QuicFramerTest, BuildNewAckFramePacketOneAckBlock) {
- if (framer_.version() <= QUIC_VERSION_33) {
- return;
- }
-
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.packet_number = kPacketNumber;
-
- // Use kSmallLargestObserved to make this test finished in a short time.
- QuicAckFrame ack_frame;
- ack_frame.largest_observed = kSmallLargestObserved;
- ack_frame.ack_delay_time = QuicTime::Delta::Zero();
- ack_frame.missing = false;
- ack_frame.packets.Add(1, kSmallLargestObserved + 1);
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&ack_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
-
- // frame type (ack frame)
- // (no ack blocks, 2 byte largest observed, 2 byte block length)
- 0x45,
- // largest acked
- 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // first ack block length.
- 0x34, 0x12,
- // num timestamps.
- 0x00,
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST_P(QuicFramerTest, BuildNewAckFramePacketMultipleAckBlocks) {
- if (framer_.version() <= QUIC_VERSION_33) {
- return;
- }
-
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.packet_number = kPacketNumber;
-
- // Use kSmallLargestObserved to make this test finished in a short time.
- QuicAckFrame ack_frame;
- ack_frame.largest_observed = kSmallLargestObserved;
- ack_frame.ack_delay_time = QuicTime::Delta::Zero();
- ack_frame.missing = false;
- ack_frame.packets.Add(1, 5);
- ack_frame.packets.Add(10, 500);
- ack_frame.packets.Add(900, kSmallMissingPacket);
- ack_frame.packets.Add(kSmallMissingPacket + 1, kSmallLargestObserved + 1);
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&ack_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
-
- // frame type (ack frame)
- // (has ack blocks, 2 byte largest observed, 2 byte block length)
- 0x65,
- // largest acked
- 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // num ack blocks ranges.
- 0x04,
- // first ack block length.
- 0x01, 0x00,
- // gap to next block.
- 0x01,
- // ack block length.
- 0xaf, 0x0e,
- // gap to next block.
- 0xff,
- // ack block length.
- 0x00, 0x00,
- // gap to next block.
- 0x91,
- // ack block length.
- 0xea, 0x01,
- // gap to next block.
- 0x05,
- // ack block length.
- 0x04, 0x00,
- // num timestamps.
- 0x00,
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST_P(QuicFramerTest, BuildNewAckFramePacketMaxAckBlocks) {
- if (framer_.version() <= QUIC_VERSION_33) {
- return;
- }
-
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.packet_number = kPacketNumber;
-
- // Use kSmallLargestObservedto make this test finished in a short time.
- QuicAckFrame ack_frame;
- ack_frame.largest_observed = kSmallLargestObserved;
- ack_frame.ack_delay_time = QuicTime::Delta::Zero();
- ack_frame.missing = false;
- // 300 ack blocks.
- for (size_t i = 2; i < 2 * 300; i += 2) {
- ack_frame.packets.Add(i);
- }
- ack_frame.packets.Add(600, kSmallLargestObserved + 1);
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&ack_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // frame type (ack frame)
- // (has ack blocks, 2 byte largest observed, 2 byte block length)
- 0x65,
- // largest acked
- 0x34, 0x12,
- // Zero delta time.
- 0x00, 0x00,
- // num ack blocks ranges.
- 0xff,
- // first ack block length.
- 0xdd, 0x0f,
- // 255 = 4 * 63 + 3
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
-
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
-
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
-
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
-
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
-
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
-
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
- // num timestamps.
- 0x00,
- };
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST_P(QuicFramerTest, BuildStopWaitingPacket) {
- if (framer_.version() > QUIC_VERSION_33) {
- return;
- }
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.packet_number = kPacketNumber;
-
- QuicStopWaitingFrame stop_waiting_frame;
- stop_waiting_frame.entropy_hash = 0x14;
- stop_waiting_frame.least_unacked = kLeastUnacked;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&stop_waiting_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (stop waiting frame)
- 0x06,
- // entropy hash of sent packets till least awaiting - 1.
- 0x14,
- // least packet number awaiting an ack, delta from packet number.
- 0x1C, 0x00, 0x00, 0x00,
- 0x00, 0x00,
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST_P(QuicFramerTest, BuildNewStopWaitingPacket) {
- if (framer_.version() <= QUIC_VERSION_33) {
- return;
- }
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = false;
- header.packet_number = kPacketNumber;
-
- QuicStopWaitingFrame stop_waiting_frame;
- stop_waiting_frame.least_unacked = kLeastUnacked;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&stop_waiting_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
-
- // frame type (stop waiting frame)
- 0x06,
- // least packet number awaiting an ack, delta from packet number.
- 0x1C, 0x00, 0x00, 0x00,
- 0x00, 0x00,
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST_P(QuicFramerTest, BuildRstFramePacketQuic) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = false;
- header.packet_number = kPacketNumber;
-
- QuicRstStreamFrame rst_frame;
- rst_frame.stream_id = kStreamId;
- rst_frame.error_code = static_cast<QuicRstStreamErrorCode>(0x05060708);
- rst_frame.byte_offset = 0x0807060504030201;
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (rst stream frame)
- 0x01,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // sent byte offset
- 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
- // error code
- 0x08, 0x07, 0x06, 0x05,
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (rst stream frame)
- 0x01,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // sent byte offset
- 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
- // error code
- 0x08, 0x07, 0x06, 0x05,
- };
- // clang-format on
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&rst_frame));
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-TEST_P(QuicFramerTest, BuildCloseFramePacket) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.packet_number = kPacketNumber;
-
- QuicConnectionCloseFrame close_frame;
- close_frame.error_code = static_cast<QuicErrorCode>(0x05060708);
- close_frame.error_details = "because I can";
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&close_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (connection close frame)
- 0x02,
- // error code
- 0x08, 0x07, 0x06, 0x05,
- // error details length
- 0x0d, 0x00,
- // error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n',
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (connection close frame)
- 0x02,
- // error code
- 0x08, 0x07, 0x06, 0x05,
- // error details length
- 0x0d, 0x00,
- // error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n',
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-TEST_P(QuicFramerTest, BuildGoAwayPacket) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.packet_number = kPacketNumber;
-
- QuicGoAwayFrame goaway_frame;
- goaway_frame.error_code = static_cast<QuicErrorCode>(0x05060708);
- goaway_frame.last_good_stream_id = kStreamId;
- goaway_frame.reason_phrase = "because I can";
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&goaway_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags(entropy)
- 0x01,
-
- // frame type (go away frame)
- 0x03,
- // error code
- 0x08, 0x07, 0x06, 0x05,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // error details length
- 0x0d, 0x00,
- // error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n',
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (go away frame)
- 0x03,
- // error code
- 0x08, 0x07, 0x06, 0x05,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // error details length
- 0x0d, 0x00,
- // error details
- 'b', 'e', 'c', 'a',
- 'u', 's', 'e', ' ',
- 'I', ' ', 'c', 'a',
- 'n',
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-TEST_P(QuicFramerTest, BuildWindowUpdatePacket) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.packet_number = kPacketNumber;
-
- QuicWindowUpdateFrame window_update_frame;
- window_update_frame.stream_id = kStreamId;
- window_update_frame.byte_offset = 0x1122334455667788;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&window_update_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags(entropy)
- 0x01,
-
- // frame type (window update frame)
- 0x04,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // byte offset
- 0x88, 0x77, 0x66, 0x55,
- 0x44, 0x33, 0x22, 0x11,
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (window update frame)
- 0x04,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // byte offset
- 0x88, 0x77, 0x66, 0x55,
- 0x44, 0x33, 0x22, 0x11,
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-TEST_P(QuicFramerTest, BuildBlockedPacket) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.packet_number = kPacketNumber;
-
- QuicBlockedFrame blocked_frame;
- blocked_frame.stream_id = kStreamId;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&blocked_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags(entropy)
- 0x01,
-
- // frame type (blocked frame)
- 0x05,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- 0x38,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (blocked frame)
- 0x05,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-TEST_P(QuicFramerTest, BuildPingPacket) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.packet_number = kPacketNumber;
-
- QuicPingFrame ping_frame;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(ping_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags(entropy)
- 0x01,
-
- // frame type (ping frame)
- 0x07,
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (ping frame)
- 0x07,
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-TEST_P(QuicFramerTest, BuildPathClosePacket) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.multipath_flag = true;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.path_id = kDefaultPathId;
- header.packet_number = kPacketNumber;
-
- QuicPathCloseFrame path_close;
- path_close.path_id = kPathId;
- QuicFrames frames;
- frames.push_back(QuicFrame(&path_close));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (version)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x78 : 0X7C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x00,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
- // private flags (entropy)
- 0x01,
-
- // frame type (path_close_frame)
- 0x08,
- // path id
- 0x42,
- };
- unsigned char packet_34[] = {
- // public flags (version)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x78 : 0X7C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x00,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
-
- // frame type (path_close_frame)
- 0x08,
- // path id
- 0x42,
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-// Test that the MTU discovery packet is serialized correctly as a PING packet.
-TEST_P(QuicFramerTest, BuildMtuDiscoveryPacket) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.packet_number = kPacketNumber;
-
- QuicMtuDiscoveryFrame mtu_discovery_frame;
-
- QuicFrames frames;
- frames.push_back(QuicFrame(mtu_discovery_frame));
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags(entropy)
- 0x01,
-
- // frame type (ping frame)
- 0x07,
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (ping frame)
- 0x07,
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError(
- "constructed packet", data->data(), data->length(),
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34));
-}
-
-TEST_P(QuicFramerTest, BuildPublicResetPacketOld) {
- FLAGS_quic_use_old_public_reset_packets = true;
- QuicPublicResetPacket reset_packet;
- reset_packet.public_header.connection_id = kConnectionId;
- reset_packet.public_header.reset_flag = true;
- reset_packet.public_header.version_flag = false;
- reset_packet.rejected_packet_number = kPacketNumber;
- reset_packet.nonce_proof = kNonceProof;
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (public reset, 8 byte ConnectionId)
- 0x0E,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // message tag (kPRST)
- 'P', 'R', 'S', 'T',
- // num_entries (2) + padding
- 0x02, 0x00, 0x00, 0x00,
- // tag kRNON
- 'R', 'N', 'O', 'N',
- // end offset 8
- 0x08, 0x00, 0x00, 0x00,
- // tag kRSEQ
- 'R', 'S', 'E', 'Q',
- // end offset 16
- 0x10, 0x00, 0x00, 0x00,
- // nonce proof
- 0x89, 0x67, 0x45, 0x23,
- 0x01, 0xEF, 0xCD, 0xAB,
- // rejected packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12, 0x00, 0x00,
- };
- // clang-format on
-
- std::unique_ptr<QuicEncryptedPacket> data(
- framer_.BuildPublicResetPacket(reset_packet));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST_P(QuicFramerTest, BuildPublicResetPacket) {
- FLAGS_quic_use_old_public_reset_packets = false;
- QuicPublicResetPacket reset_packet;
- reset_packet.public_header.connection_id = kConnectionId;
- reset_packet.public_header.reset_flag = true;
- reset_packet.public_header.version_flag = false;
- reset_packet.rejected_packet_number = kPacketNumber;
- reset_packet.nonce_proof = kNonceProof;
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (public reset, 8 byte ConnectionId)
- 0x0A,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // message tag (kPRST)
- 'P', 'R', 'S', 'T',
- // num_entries (2) + padding
- 0x02, 0x00, 0x00, 0x00,
- // tag kRNON
- 'R', 'N', 'O', 'N',
- // end offset 8
- 0x08, 0x00, 0x00, 0x00,
- // tag kRSEQ
- 'R', 'S', 'E', 'Q',
- // end offset 16
- 0x10, 0x00, 0x00, 0x00,
- // nonce proof
- 0x89, 0x67, 0x45, 0x23,
- 0x01, 0xEF, 0xCD, 0xAB,
- // rejected packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12, 0x00, 0x00,
- };
- // clang-format on
-
- std::unique_ptr<QuicEncryptedPacket> data(
- framer_.BuildPublicResetPacket(reset_packet));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST_P(QuicFramerTest, BuildPublicResetPacketWithClientAddress) {
- FLAGS_quic_use_old_public_reset_packets = false;
- QuicPublicResetPacket reset_packet;
- reset_packet.public_header.connection_id = kConnectionId;
- reset_packet.public_header.reset_flag = true;
- reset_packet.public_header.version_flag = false;
- reset_packet.rejected_packet_number = kPacketNumber;
- reset_packet.nonce_proof = kNonceProof;
- reset_packet.client_address = IPEndPoint(Loopback4(), 0x1234);
-
- // clang-format off
- unsigned char packet[] = {
- // public flags (public reset, 8 byte ConnectionId)
- 0x0A,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // message tag (kPRST)
- 'P', 'R', 'S', 'T',
- // num_entries (3) + padding
- 0x03, 0x00, 0x00, 0x00,
- // tag kRNON
- 'R', 'N', 'O', 'N',
- // end offset 8
- 0x08, 0x00, 0x00, 0x00,
- // tag kRSEQ
- 'R', 'S', 'E', 'Q',
- // end offset 16
- 0x10, 0x00, 0x00, 0x00,
- // tag kCADR
- 'C', 'A', 'D', 'R',
- // end offset 24
- 0x18, 0x00, 0x00, 0x00,
- // nonce proof
- 0x89, 0x67, 0x45, 0x23,
- 0x01, 0xEF, 0xCD, 0xAB,
- // rejected packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12, 0x00, 0x00,
- // client address
- 0x02, 0x00,
- 0x7F, 0x00, 0x00, 0x01,
- 0x34, 0x12,
- };
- // clang-format on
-
- std::unique_ptr<QuicEncryptedPacket> data(
- framer_.BuildPublicResetPacket(reset_packet));
- ASSERT_TRUE(data != nullptr);
-
- test::CompareCharArraysWithHexError("constructed packet", data->data(),
- data->length(), AsChars(packet),
- arraysize(packet));
-}
-
-TEST_P(QuicFramerTest, EncryptPacket) {
- QuicPacketNumber packet_number = kPacketNumber;
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // redundancy
- 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p',
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // redundancy
- 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p',
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> raw(new QuicPacket(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false, PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER));
- char buffer[kMaxPacketSize];
- size_t encrypted_length =
- framer_.EncryptPayload(ENCRYPTION_NONE, kDefaultPathId, packet_number,
- *raw, buffer, kMaxPacketSize);
-
- ASSERT_NE(0u, encrypted_length);
- EXPECT_TRUE(CheckEncryption(kDefaultPathId, packet_number, raw.get()));
-}
-
-TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) {
- QuicPacketNumber packet_number = kPacketNumber;
- // clang-format off
- unsigned char packet[] = {
- // public flags (version, 8 byte connection_id)
- 0x39,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '.', '1', '0',
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // redundancy
- 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p',
- };
- unsigned char packet_34[] = {
- // public flags (version, 8 byte connection_id)
- 0x39,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '.', '1', '0',
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // redundancy
- 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p',
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> raw(new QuicPacket(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false, PACKET_8BYTE_CONNECTION_ID, kIncludeVersion, !kIncludePathId,
- !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER));
- char buffer[kMaxPacketSize];
- size_t encrypted_length =
- framer_.EncryptPayload(ENCRYPTION_NONE, kDefaultPathId, packet_number,
- *raw, buffer, kMaxPacketSize);
-
- ASSERT_NE(0u, encrypted_length);
- EXPECT_TRUE(CheckEncryption(kDefaultPathId, packet_number, raw.get()));
-}
-
-TEST_P(QuicFramerTest, EncryptPacketWithMultipathFlag) {
- QuicPacketNumber packet_number = kPacketNumber;
- // clang-format off
- unsigned char packet[] = {
- // public flags (version, 8 byte connection_id)
- 0x78,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // redundancy
- 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p',
- };
- unsigned char packet_34[] = {
- // public flags (version, 8 byte connection_id)
- 0x78,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // redundancy
- 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p',
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> raw(new QuicPacket(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false, PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, kIncludePathId,
- !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER));
- char buffer[kMaxPacketSize];
- size_t encrypted_length = framer_.EncryptPayload(
- ENCRYPTION_NONE, kPathId, packet_number, *raw, buffer, kMaxPacketSize);
-
- ASSERT_NE(0u, encrypted_length);
- EXPECT_TRUE(CheckEncryption(kPathId, packet_number, raw.get()));
-}
-
-TEST_P(QuicFramerTest, EncryptPacketWithBothVersionFlagAndMultipathFlag) {
- QuicPacketNumber packet_number = kPacketNumber;
- // clang-format off
- unsigned char packet[] = {
- // public flags (version, 8 byte connection_id)
- 0x79,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '.', '1', '0',
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // redundancy
- 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p',
- };
- unsigned char packet_34[] = {
- // public flags (version, 8 byte connection_id)
- 0x79,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // version tag
- 'Q', '.', '1', '0',
- // path_id
- 0x42,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // redundancy
- 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p',
- };
- // clang-format on
-
- std::unique_ptr<QuicPacket> raw(new QuicPacket(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false, PACKET_8BYTE_CONNECTION_ID, kIncludeVersion, kIncludePathId,
- !kIncludeDiversificationNonce, PACKET_6BYTE_PACKET_NUMBER));
- char buffer[kMaxPacketSize];
- size_t encrypted_length = framer_.EncryptPayload(
- ENCRYPTION_NONE, kPathId, packet_number, *raw, buffer, kMaxPacketSize);
-
- ASSERT_NE(0u, encrypted_length);
- EXPECT_TRUE(CheckEncryption(kPathId, packet_number, raw.get()));
-}
-
-TEST_P(QuicFramerTest, AckTruncationLargePacket) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = false;
- header.packet_number = kPacketNumber;
-
- QuicAckFrame ack_frame;
- // Create a packet with just the ack.
- if (framer_.version() <= QUIC_VERSION_33) {
- ack_frame = MakeAckFrameWithNackRanges(300, 0u);
- } else {
- ack_frame = MakeAckFrameWithAckBlocks(300, 0u);
- }
- QuicFrame frame;
- frame.type = ACK_FRAME;
- frame.ack_frame = &ack_frame;
- QuicFrames frames;
- frames.push_back(frame);
-
- // Build an ack packet with truncation due to limit in number of nack ranges.
- std::unique_ptr<QuicPacket> raw_ack_packet(BuildDataPacket(header, frames));
- ASSERT_TRUE(raw_ack_packet != nullptr);
- char buffer[kMaxPacketSize];
- size_t encrypted_length = framer_.EncryptPayload(
- ENCRYPTION_NONE, kDefaultPathId, header.packet_number, *raw_ack_packet,
- buffer, kMaxPacketSize);
- ASSERT_NE(0u, encrypted_length);
- // Now make sure we can turn our ack packet back into an ack frame.
- ASSERT_TRUE(framer_.ProcessPacket(
- QuicEncryptedPacket(buffer, encrypted_length, false)));
- ASSERT_EQ(1u, visitor_.ack_frames_.size());
- QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
- if (framer_.version() <= QUIC_VERSION_33) {
- EXPECT_TRUE(processed_ack_frame.is_truncated);
- EXPECT_EQ(510u, processed_ack_frame.largest_observed);
- EXPECT_TRUE(processed_ack_frame.missing);
- ASSERT_EQ(255u, processed_ack_frame.packets.NumPacketsSlow());
- EXPECT_EQ(1u, processed_ack_frame.packets.Min());
- EXPECT_EQ(509u, processed_ack_frame.packets.Max());
- } else {
- EXPECT_FALSE(processed_ack_frame.is_truncated);
- EXPECT_FALSE(processed_ack_frame.missing);
- EXPECT_EQ(600u, processed_ack_frame.largest_observed);
- ASSERT_EQ(256u, processed_ack_frame.packets.NumPacketsSlow());
- EXPECT_EQ(90u, processed_ack_frame.packets.Min());
- EXPECT_EQ(600u, processed_ack_frame.packets.Max());
- }
-}
-
-TEST_P(QuicFramerTest, AckTruncationSmallPacket) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = false;
- header.packet_number = kPacketNumber;
-
- // Create a packet with just the ack.
- QuicAckFrame ack_frame;
- if (framer_.version() <= QUIC_VERSION_33) {
- ack_frame = MakeAckFrameWithNackRanges(300, 0u);
- } else {
- ack_frame = MakeAckFrameWithAckBlocks(300, 0u);
- }
- QuicFrame frame;
- frame.type = ACK_FRAME;
- frame.ack_frame = &ack_frame;
- QuicFrames frames;
- frames.push_back(frame);
-
- // Build an ack packet with truncation due to limit in number of nack ranges.
- std::unique_ptr<QuicPacket> raw_ack_packet(
- BuildDataPacket(header, frames, 500));
- ASSERT_TRUE(raw_ack_packet != nullptr);
- char buffer[kMaxPacketSize];
- size_t encrypted_length = framer_.EncryptPayload(
- ENCRYPTION_NONE, kDefaultPathId, header.packet_number, *raw_ack_packet,
- buffer, kMaxPacketSize);
- ASSERT_NE(0u, encrypted_length);
- // Now make sure we can turn our ack packet back into an ack frame.
- ASSERT_TRUE(framer_.ProcessPacket(
- QuicEncryptedPacket(buffer, encrypted_length, false)));
- ASSERT_EQ(1u, visitor_.ack_frames_.size());
- QuicAckFrame& processed_ack_frame = *visitor_.ack_frames_[0];
- if (framer_.version() <= QUIC_VERSION_33) {
- EXPECT_TRUE(processed_ack_frame.is_truncated);
- EXPECT_EQ(476u, processed_ack_frame.largest_observed);
- EXPECT_TRUE(processed_ack_frame.missing);
- ASSERT_EQ(238u, processed_ack_frame.packets.NumPacketsSlow());
- EXPECT_EQ(1u, processed_ack_frame.packets.Min());
- EXPECT_EQ(475u, processed_ack_frame.packets.Max());
- } else {
- EXPECT_FALSE(processed_ack_frame.is_truncated);
- EXPECT_EQ(600u, processed_ack_frame.largest_observed);
- EXPECT_FALSE(processed_ack_frame.missing);
- ASSERT_EQ(239u, processed_ack_frame.packets.NumPacketsSlow());
- EXPECT_EQ(124u, processed_ack_frame.packets.Min());
- EXPECT_EQ(600u, processed_ack_frame.packets.Max());
- }
-}
-
-TEST_P(QuicFramerTest, CleanTruncation) {
- QuicPacketHeader header;
- header.public_header.connection_id = kConnectionId;
- header.public_header.reset_flag = false;
- header.public_header.version_flag = false;
- header.fec_flag = false;
- header.entropy_flag = true;
- header.packet_number = kPacketNumber;
-
- QuicAckFrame ack_frame;
- ack_frame.largest_observed = 201;
- ack_frame.packets.Add(1, ack_frame.largest_observed);
-
- // Create a packet with just the ack.
- QuicFrame frame;
- frame.type = ACK_FRAME;
- frame.ack_frame = &ack_frame;
- QuicFrames frames;
- frames.push_back(frame);
-
- std::unique_ptr<QuicPacket> raw_ack_packet(BuildDataPacket(header, frames));
- ASSERT_TRUE(raw_ack_packet != nullptr);
-
- char buffer[kMaxPacketSize];
- size_t encrypted_length = framer_.EncryptPayload(
- ENCRYPTION_NONE, kDefaultPathId, header.packet_number, *raw_ack_packet,
- buffer, kMaxPacketSize);
- ASSERT_NE(0u, encrypted_length);
-
- // Now make sure we can turn our ack packet back into an ack frame.
- ASSERT_TRUE(framer_.ProcessPacket(
- QuicEncryptedPacket(buffer, encrypted_length, false)));
-
- // Test for clean truncation of the ack by comparing the length of the
- // original packets to the re-serialized packets.
- frames.clear();
- frame.type = ACK_FRAME;
- frame.ack_frame = visitor_.ack_frames_[0];
- frames.push_back(frame);
-
- size_t original_raw_length = raw_ack_packet->length();
- raw_ack_packet.reset(BuildDataPacket(header, frames));
- ASSERT_TRUE(raw_ack_packet != nullptr);
- EXPECT_EQ(original_raw_length, raw_ack_packet->length());
- ASSERT_TRUE(raw_ack_packet != nullptr);
-}
-
-TEST_P(QuicFramerTest, EntropyFlagTest) {
- if (framer_.version() > QUIC_VERSION_33) {
- return;
- }
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags (Entropy)
- 0x01,
-
- // frame type (stream frame with fin and no length)
- 0xDF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- // clang-format on
-
- QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
- ASSERT_TRUE(visitor_.header_.get());
- EXPECT_TRUE(visitor_.header_->entropy_flag);
- EXPECT_EQ(1 << 4, visitor_.header_->entropy_hash);
- EXPECT_FALSE(visitor_.header_->fec_flag);
-};
-
-TEST_P(QuicFramerTest, StopPacketProcessing) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // Entropy
- 0x01,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
-
- // frame type (ack frame)
- 0x40,
- // entropy hash of sent packets till least awaiting - 1.
- 0x14,
- // least packet number awaiting an ack
- 0xA0, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // entropy hash of all received packets.
- 0x43,
- // largest observed packet number
- 0xBF, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // num missing packets
- 0x01,
- // missing packet
- 0xBE, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- };
- unsigned char packet_34[] = {
- // public flags (8 byte connection_id)
- static_cast<unsigned char>(
- framer_.version() > QUIC_VERSION_32 ? 0x38 : 0x3C),
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
-
- // frame type (ack frame)
- 0x40,
- // entropy hash of sent packets till least awaiting - 1.
- 0x14,
- // least packet number awaiting an ack
- 0xA0, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // entropy hash of all received packets.
- 0x43,
- // largest observed packet number
- 0xBF, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // num missing packets
- 0x01,
- // missing packet
- 0xBE, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- };
- // clang-format on
-
- MockFramerVisitor visitor;
- framer_.set_visitor(&visitor);
- EXPECT_CALL(visitor, OnPacket());
- EXPECT_CALL(visitor, OnPacketHeader(_));
- EXPECT_CALL(visitor, OnStreamFrame(_)).WillOnce(Return(false));
- EXPECT_CALL(visitor, OnAckFrame(_)).Times(0);
- EXPECT_CALL(visitor, OnPacketComplete());
- EXPECT_CALL(visitor, OnUnauthenticatedPublicHeader(_)).WillOnce(Return(true));
- EXPECT_CALL(visitor, OnUnauthenticatedHeader(_)).WillOnce(Return(true));
- EXPECT_CALL(visitor, OnDecryptedPacket(_));
-
- QuicEncryptedPacket encrypted(
- AsChars(framer_.version() <= QUIC_VERSION_33 ? packet : packet_34),
- framer_.version() <= QUIC_VERSION_33 ? arraysize(packet)
- : arraysize(packet_34),
- false);
- EXPECT_TRUE(framer_.ProcessPacket(encrypted));
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
-}
-
-static char kTestString[] = "At least 20 characters.";
-static QuicStreamId kTestQuicStreamId = 1;
-static bool ExpectedStreamFrame(const QuicStreamFrame& frame) {
- return frame.stream_id == kTestQuicStreamId && !frame.fin &&
- frame.offset == 0 &&
- string(frame.data_buffer, frame.data_length) == kTestString;
- // FIN is hard-coded false in ConstructEncryptedPacket.
- // Offset 0 is hard-coded in ConstructEncryptedPacket.
-}
-
-// Verify that the packet returned by ConstructEncryptedPacket() can be properly
-// parsed by the framer.
-TEST_P(QuicFramerTest, ConstructEncryptedPacket) {
- // Since we are using ConstructEncryptedPacket, we have to set the framer's
- // crypto to be Null.
- framer_.SetDecrypter(ENCRYPTION_NONE, QuicDecrypter::Create(kNULL));
- framer_.SetEncrypter(ENCRYPTION_NONE, QuicEncrypter::Create(kNULL));
- QuicVersionVector versions;
- versions.push_back(framer_.version());
- std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
- 42, false, false, false, kDefaultPathId, kTestQuicStreamId, kTestString,
- PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, &versions));
-
- MockFramerVisitor visitor;
- framer_.set_visitor(&visitor);
- EXPECT_CALL(visitor, OnPacket()).Times(1);
- EXPECT_CALL(visitor, OnUnauthenticatedPublicHeader(_))
- .Times(1)
- .WillOnce(Return(true));
- EXPECT_CALL(visitor, OnUnauthenticatedHeader(_))
- .Times(1)
- .WillOnce(Return(true));
- EXPECT_CALL(visitor, OnPacketHeader(_)).Times(1).WillOnce(Return(true));
- EXPECT_CALL(visitor, OnDecryptedPacket(_)).Times(1);
- EXPECT_CALL(visitor, OnError(_)).Times(0);
- EXPECT_CALL(visitor, OnStreamFrame(_)).Times(0);
- EXPECT_CALL(visitor, OnStreamFrame(Truly(ExpectedStreamFrame))).Times(1);
- EXPECT_CALL(visitor, OnAckFrame(_)).Times(0);
- EXPECT_CALL(visitor, OnPacketComplete()).Times(1);
-
- EXPECT_TRUE(framer_.ProcessPacket(*packet));
- EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
-}
-
-// Verify that the packet returned by ConstructMisFramedEncryptedPacket()
-// does cause the framer to return an error.
-TEST_P(QuicFramerTest, ConstructMisFramedEncryptedPacket) {
- // Since we are using ConstructEncryptedPacket, we have to set the framer's
- // crypto to be Null.
- framer_.SetDecrypter(ENCRYPTION_NONE, QuicDecrypter::Create(kNULL));
- framer_.SetEncrypter(ENCRYPTION_NONE, QuicEncrypter::Create(kNULL));
- QuicVersionVector versions;
- versions.push_back(framer_.version());
- std::unique_ptr<QuicEncryptedPacket> packet(ConstructMisFramedEncryptedPacket(
- 42, false, false, false, kDefaultPathId, kTestQuicStreamId, kTestString,
- PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, &versions,
- Perspective::IS_SERVER));
-
- MockFramerVisitor visitor;
- framer_.set_visitor(&visitor);
- EXPECT_CALL(visitor, OnPacket()).Times(1);
- EXPECT_CALL(visitor, OnUnauthenticatedPublicHeader(_))
- .Times(1)
- .WillOnce(Return(true));
- EXPECT_CALL(visitor, OnUnauthenticatedHeader(_))
- .Times(1)
- .WillOnce(Return(true));
- if (framer_.version() <= QUIC_VERSION_33) {
- EXPECT_CALL(visitor, OnPacketHeader(_)).Times(0);
- } else {
- EXPECT_CALL(visitor, OnPacketHeader(_)).Times(1);
- }
- EXPECT_CALL(visitor, OnDecryptedPacket(_)).Times(1);
- EXPECT_CALL(visitor, OnError(_)).Times(1);
- EXPECT_CALL(visitor, OnStreamFrame(_)).Times(0);
- EXPECT_CALL(visitor, OnAckFrame(_)).Times(0);
- EXPECT_CALL(visitor, OnPacketComplete()).Times(0);
-
- EXPECT_FALSE(framer_.ProcessPacket(*packet));
- if (framer_.version() <= QUIC_VERSION_33) {
- EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
- } else {
- EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error());
- }
-}
-
-// Tests for fuzzing with Dr. Fuzz
-// Xref http://www.chromium.org/developers/testing/dr-fuzz for more details.
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// target function to be fuzzed by Dr. Fuzz
-void QuicFramerFuzzFunc(unsigned char* data, size_t size) {
- QuicFramer framer(QuicSupportedVersions(), QuicTime::Zero(),
- Perspective::IS_SERVER);
- const char* const packet_bytes = reinterpret_cast<const char*>(data);
-
- // Test the CryptoFramer.
- StringPiece crypto_input(packet_bytes, size);
- std::unique_ptr<CryptoHandshakeMessage> handshake_message(
- CryptoFramer::ParseMessage(crypto_input));
-
- // Test the regular QuicFramer with the same input.
- NoOpFramerVisitor visitor;
- framer.set_visitor(&visitor);
- QuicEncryptedPacket packet(packet_bytes, size);
- framer.ProcessPacket(packet);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-TEST_P(QuicFramerTest, FramerFuzzTest) {
- // clang-format off
- unsigned char packet[] = {
- // public flags (8 byte connection_id)
- 0x3C,
- // connection_id
- 0x10, 0x32, 0x54, 0x76,
- 0x98, 0xBA, 0xDC, 0xFE,
- // packet number
- 0xBC, 0x9A, 0x78, 0x56,
- 0x34, 0x12,
- // private flags
- 0x00,
-
- // frame type (stream frame with fin)
- 0xFF,
- // stream id
- 0x04, 0x03, 0x02, 0x01,
- // offset
- 0x54, 0x76, 0x10, 0x32,
- 0xDC, 0xFE, 0x98, 0xBA,
- // data length
- 0x0c, 0x00,
- // data
- 'h', 'e', 'l', 'l',
- 'o', ' ', 'w', 'o',
- 'r', 'l', 'd', '!',
- };
- // clang-format on
-
- QuicFramerFuzzFunc(packet, arraysize(packet));
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_header_list.cc b/chromium/net/quic/quic_header_list.cc
deleted file mode 100644
index 4d2f3f64bab..00000000000
--- a/chromium/net/quic/quic_header_list.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_header_list.h"
-
-using std::string;
-
-namespace net {
-
-QuicHeaderList::QuicHeaderList() : uncompressed_header_bytes_(0) {}
-
-QuicHeaderList::QuicHeaderList(QuicHeaderList&& other) = default;
-
-QuicHeaderList::QuicHeaderList(const QuicHeaderList& other) = default;
-
-QuicHeaderList& QuicHeaderList::operator=(const QuicHeaderList& other) =
- default;
-
-QuicHeaderList& QuicHeaderList::operator=(QuicHeaderList&& other) = default;
-
-QuicHeaderList::~QuicHeaderList() {}
-
-void QuicHeaderList::OnHeaderBlockStart() {
- QUIC_BUG_IF(uncompressed_header_bytes_ != 0)
- << "OnHeaderBlockStart called more than once!";
-}
-
-void QuicHeaderList::OnHeader(base::StringPiece name, base::StringPiece value) {
- header_list_.emplace_back(name.as_string(), value.as_string());
-}
-
-void QuicHeaderList::OnHeaderBlockEnd(size_t uncompressed_header_bytes) {
- uncompressed_header_bytes_ = uncompressed_header_bytes;
-}
-
-void QuicHeaderList::Clear() {
- header_list_.clear();
- uncompressed_header_bytes_ = 0;
-}
-
-string QuicHeaderList::DebugString() const {
- string s = "{ ";
- for (const auto& p : *this) {
- s.append(p.first + "=" + p.second + ", ");
- }
- s.append("}");
- return s;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_header_list.h b/chromium/net/quic/quic_header_list.h
deleted file mode 100644
index b218f359f34..00000000000
--- a/chromium/net/quic/quic_header_list.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_HEADER_LIST_H_
-#define NET_QUIC_QUIC_HEADER_LIST_H_
-
-#include <deque>
-#include <functional>
-
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/spdy/spdy_header_block.h"
-#include "net/spdy/spdy_headers_handler_interface.h"
-
-namespace net {
-
-// A simple class that accumulates header pairs
-class NET_EXPORT_PRIVATE QuicHeaderList : public SpdyHeadersHandlerInterface {
- public:
- typedef std::deque<std::pair<std::string, std::string>> ListType;
- typedef ListType::const_iterator const_iterator;
-
- QuicHeaderList();
- QuicHeaderList(QuicHeaderList&& other);
- QuicHeaderList(const QuicHeaderList& other);
- QuicHeaderList& operator=(QuicHeaderList&& other);
- QuicHeaderList& operator=(const QuicHeaderList& other);
- ~QuicHeaderList() override;
-
- // From SpdyHeadersHandlerInteface.
- void OnHeaderBlockStart() override;
- void OnHeader(base::StringPiece name, base::StringPiece value) override;
- void OnHeaderBlockEnd(size_t uncompressed_header_bytes) override;
-
- void Clear();
-
- const_iterator begin() const { return header_list_.begin(); }
- const_iterator end() const { return header_list_.end(); }
-
- bool empty() const { return header_list_.empty(); }
- size_t uncompressed_header_bytes() const {
- return uncompressed_header_bytes_;
- }
-
- std::string DebugString() const;
-
- private:
- std::deque<std::pair<std::string, std::string>> header_list_;
- size_t uncompressed_header_bytes_;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_HEADER_LIST_H_
diff --git a/chromium/net/quic/quic_header_list_test.cc b/chromium/net/quic/quic_header_list_test.cc
deleted file mode 100644
index 94f824972e7..00000000000
--- a/chromium/net/quic/quic_header_list_test.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_header_list.h"
-
-#include "net/test/gtest_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace net {
-
-// This test verifies that QuicHeaderList accumulates header pairs in order.
-TEST(QuicHeaderListTest, OnHeader) {
- QuicHeaderList headers;
- headers.OnHeader("foo", "bar");
- headers.OnHeader("april", "fools");
- headers.OnHeader("beep", "");
-
- EXPECT_EQ("{ foo=bar, april=fools, beep=, }", headers.DebugString());
-}
-
-// This test verifies that QuicHeaderList is copyable and assignable.
-TEST(QuicHeaderListTest, IsCopyableAndAssignable) {
- QuicHeaderList headers;
- headers.OnHeader("foo", "bar");
- headers.OnHeader("april", "fools");
- headers.OnHeader("beep", "");
-
- QuicHeaderList headers2(headers);
- QuicHeaderList headers3 = headers;
-
- EXPECT_EQ("{ foo=bar, april=fools, beep=, }", headers2.DebugString());
- EXPECT_EQ("{ foo=bar, april=fools, beep=, }", headers3.DebugString());
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_headers_stream.cc b/chromium/net/quic/quic_headers_stream.cc
deleted file mode 100644
index 72c3ac9bbef..00000000000
--- a/chromium/net/quic/quic_headers_stream.cc
+++ /dev/null
@@ -1,509 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_headers_stream.h"
-
-#include <utility>
-
-#include "base/macros.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_header_list.h"
-#include "net/quic/quic_spdy_session.h"
-#include "net/quic/quic_time.h"
-#include "net/spdy/spdy_protocol.h"
-
-using base::StringPiece;
-using net::HTTP2;
-using net::SpdyFrameType;
-using std::string;
-
-namespace net {
-
-namespace {
-
-class HeaderTableDebugVisitor : public HpackHeaderTable::DebugVisitorInterface {
- public:
- HeaderTableDebugVisitor(
- const QuicClock* clock,
- std::unique_ptr<QuicHeadersStream::HpackDebugVisitor> visitor)
- : clock_(clock), headers_stream_hpack_visitor_(std::move(visitor)) {}
-
- int64_t OnNewEntry(const HpackEntry& entry) override {
- DVLOG(1) << entry.GetDebugString();
- return clock_->ApproximateNow().Subtract(QuicTime::Zero()).ToMicroseconds();
- }
-
- void OnUseEntry(const HpackEntry& entry) override {
- const QuicTime::Delta elapsed(
- clock_->ApproximateNow()
- .Subtract(QuicTime::Delta::FromMicroseconds(entry.time_added()))
- .Subtract(QuicTime::Zero()));
- DVLOG(1) << entry.GetDebugString() << " " << elapsed.ToMilliseconds()
- << " ms";
- headers_stream_hpack_visitor_->OnUseEntry(elapsed);
- }
-
- private:
- const QuicClock* clock_;
- std::unique_ptr<QuicHeadersStream::HpackDebugVisitor>
- headers_stream_hpack_visitor_;
-
- DISALLOW_COPY_AND_ASSIGN(HeaderTableDebugVisitor);
-};
-
-} // namespace
-
-QuicHeadersStream::HpackDebugVisitor::HpackDebugVisitor() {}
-
-QuicHeadersStream::HpackDebugVisitor::~HpackDebugVisitor() {}
-
-// A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to
-// the QuicSpdyStream, and closes the connection if any unexpected frames
-// are received.
-class QuicHeadersStream::SpdyFramerVisitor
- : public SpdyFramerVisitorInterface,
- public SpdyFramerDebugVisitorInterface {
- public:
- explicit SpdyFramerVisitor(QuicHeadersStream* stream) : stream_(stream) {}
-
- // SpdyFramerVisitorInterface implementation
- void OnSynStream(SpdyStreamId stream_id,
- SpdyStreamId associated_stream_id,
- SpdyPriority priority,
- bool fin,
- bool unidirectional) override {
- CloseConnection("SPDY SYN_STREAM frame received.");
- }
-
- void OnSynReply(SpdyStreamId stream_id, bool fin) override {
- CloseConnection("SPDY SYN_REPLY frame received.");
- }
-
- bool OnControlFrameHeaderData(SpdyStreamId stream_id,
- const char* header_data,
- size_t len) override {
- if (!stream_->IsConnected()) {
- return false;
- }
- stream_->OnControlFrameHeaderData(stream_id, header_data, len);
- return true;
- }
-
- void OnStreamFrameData(SpdyStreamId stream_id,
- const char* data,
- size_t len) override {
- CloseConnection("SPDY DATA frame received.");
- }
-
- void OnStreamEnd(SpdyStreamId stream_id) override {
- // The framer invokes OnStreamEnd after processing a SYN_STREAM
- // or SYN_REPLY frame that had the fin bit set.
- }
-
- void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {
- CloseConnection("SPDY frame padding received.");
- }
-
- SpdyHeadersHandlerInterface* OnHeaderFrameStart(
- SpdyStreamId /* stream_id */) override {
- return &header_list_;
- }
-
- void OnHeaderFrameEnd(SpdyStreamId /* stream_id */,
- bool end_headers) override {
- if (end_headers) {
- if (stream_->IsConnected()) {
- stream_->OnHeaderList(header_list_);
- }
- header_list_.Clear();
- }
- }
-
- void OnError(SpdyFramer* framer) override {
- CloseConnection(base::StringPrintf(
- "SPDY framing error: %s",
- SpdyFramer::ErrorCodeToString(framer->error_code())));
- }
-
- void OnDataFrameHeader(SpdyStreamId stream_id,
- size_t length,
- bool fin) override {
- CloseConnection("SPDY DATA frame received.");
- }
-
- void OnRstStream(SpdyStreamId stream_id,
- SpdyRstStreamStatus status) override {
- CloseConnection("SPDY RST_STREAM frame received.");
- }
-
- void OnSetting(SpdySettingsIds id, uint8_t flags, uint32_t value) override {
- if (!FLAGS_quic_respect_http2_settings_frame) {
- CloseConnection("SPDY SETTINGS frame received.");
- return;
- }
- switch (id) {
- case SETTINGS_HEADER_TABLE_SIZE:
- stream_->UpdateHeaderEncoderTableSize(value);
- break;
- // TODO(fayang): Need to support SETTINGS_MAX_HEADER_LIST_SIZE when
- // clients are actually sending it.
- default:
- CloseConnection("Unsupported field of HTTP/2 SETTINGS frame: " +
- base::IntToString(id));
- }
- }
-
- void OnSettingsAck() override {
- if (!FLAGS_quic_respect_http2_settings_frame) {
- CloseConnection("SPDY SETTINGS frame received.");
- }
- }
-
- void OnSettingsEnd() override {
- if (!FLAGS_quic_respect_http2_settings_frame) {
- CloseConnection("SPDY SETTINGS frame received.");
- }
- }
-
- void OnPing(SpdyPingId unique_id, bool is_ack) override {
- CloseConnection("SPDY PING frame received.");
- }
-
- void OnGoAway(SpdyStreamId last_accepted_stream_id,
- SpdyGoAwayStatus status) override {
- CloseConnection("SPDY GOAWAY frame received.");
- }
-
- void OnHeaders(SpdyStreamId stream_id,
- bool has_priority,
- int weight,
- SpdyStreamId parent_stream_id,
- bool exclusive,
- bool fin,
- bool end) override {
- if (!stream_->IsConnected()) {
- return;
- }
-
- // TODO(mpw): avoid down-conversion and plumb SpdyStreamPrecedence through
- // QuicHeadersStream.
- SpdyPriority priority =
- has_priority ? Http2WeightToSpdy3Priority(weight) : 0;
- stream_->OnHeaders(stream_id, has_priority, priority, fin);
- }
-
- void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override {
- CloseConnection("SPDY WINDOW_UPDATE frame received.");
- }
-
- void OnPushPromise(SpdyStreamId stream_id,
- SpdyStreamId promised_stream_id,
- bool end) override {
- if (!stream_->supports_push_promise()) {
- CloseConnection("PUSH_PROMISE not supported.");
- return;
- }
- if (!stream_->IsConnected()) {
- return;
- }
- stream_->OnPushPromise(stream_id, promised_stream_id, end);
- }
-
- void OnContinuation(SpdyStreamId stream_id, bool end) override {}
-
- void OnPriority(SpdyStreamId stream_id,
- SpdyStreamId parent_id,
- int weight,
- bool exclusive) override {
- CloseConnection("SPDY PRIORITY frame received.");
- }
-
- bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override {
- CloseConnection("Unknown frame type received.");
- return false;
- }
-
- // SpdyFramerDebugVisitorInterface implementation
- void OnSendCompressedFrame(SpdyStreamId stream_id,
- SpdyFrameType type,
- size_t payload_len,
- size_t frame_len) override {
- if (payload_len == 0) {
- QUIC_BUG << "Zero payload length.";
- return;
- }
- int compression_pct = 100 - (100 * frame_len) / payload_len;
- DVLOG(1) << "Net.QuicHpackCompressionPercentage: " << compression_pct;
- UMA_HISTOGRAM_PERCENTAGE("Net.QuicHpackCompressionPercentage",
- compression_pct);
- }
-
- void OnReceiveCompressedFrame(SpdyStreamId stream_id,
- SpdyFrameType type,
- size_t frame_len) override {
- if (stream_->IsConnected()) {
- stream_->OnCompressedFrameSize(frame_len);
- }
- }
-
- private:
- void CloseConnection(const string& details) {
- if (stream_->IsConnected()) {
- stream_->CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
- details);
- }
- }
-
- private:
- QuicHeadersStream* stream_;
- QuicHeaderList header_list_;
-
- DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor);
-};
-
-QuicHeadersStream::QuicHeadersStream(QuicSpdySession* session)
- : ReliableQuicStream(kHeadersStreamId, session),
- spdy_session_(session),
- stream_id_(kInvalidStreamId),
- promised_stream_id_(kInvalidStreamId),
- fin_(false),
- frame_len_(0),
- uncompressed_frame_len_(0),
- measure_headers_hol_blocking_time_(
- FLAGS_quic_measure_headers_hol_blocking_time),
- supports_push_promise_(session->perspective() == Perspective::IS_CLIENT &&
- FLAGS_quic_supports_push_promise),
- cur_max_timestamp_(QuicTime::Zero()),
- prev_max_timestamp_(QuicTime::Zero()),
- spdy_framer_(HTTP2),
- spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
- spdy_framer_.set_visitor(spdy_framer_visitor_.get());
- spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
- // The headers stream is exempt from connection level flow control.
- DisableConnectionFlowControlForThisStream();
-}
-
-QuicHeadersStream::~QuicHeadersStream() {}
-
-size_t QuicHeadersStream::WriteHeaders(QuicStreamId stream_id,
- SpdyHeaderBlock headers,
- bool fin,
- SpdyPriority priority,
- QuicAckListenerInterface* ack_listener) {
- SpdyHeadersIR headers_frame(stream_id, std::move(headers));
- headers_frame.set_fin(fin);
- if (session()->perspective() == Perspective::IS_CLIENT) {
- headers_frame.set_has_priority(true);
- headers_frame.set_weight(Spdy3PriorityToHttp2Weight(priority));
- }
- SpdySerializedFrame frame(spdy_framer_.SerializeFrame(headers_frame));
- WriteOrBufferData(StringPiece(frame.data(), frame.size()), false,
- ack_listener);
- return frame.size();
-}
-
-size_t QuicHeadersStream::WritePushPromise(
- QuicStreamId original_stream_id,
- QuicStreamId promised_stream_id,
- SpdyHeaderBlock headers,
- QuicAckListenerInterface* ack_listener) {
- if (session()->perspective() == Perspective::IS_CLIENT) {
- QUIC_BUG << "Client shouldn't send PUSH_PROMISE";
- return 0;
- }
-
- SpdyPushPromiseIR push_promise(original_stream_id, promised_stream_id,
- std::move(headers));
-
- // PUSH_PROMISE must not be the last frame sent out, at least followed by
- // response headers.
- push_promise.set_fin(false);
-
- SpdySerializedFrame frame(spdy_framer_.SerializeFrame(push_promise));
- WriteOrBufferData(StringPiece(frame.data(), frame.size()), false,
- ack_listener);
- return frame.size();
-}
-
-void QuicHeadersStream::OnDataAvailable() {
- char buffer[1024];
- struct iovec iov;
- QuicTime timestamp(QuicTime::Zero());
- while (true) {
- iov.iov_base = buffer;
- iov.iov_len = arraysize(buffer);
- if (measure_headers_hol_blocking_time_) {
- if (!sequencer()->GetReadableRegion(&iov, &timestamp)) {
- // No more data to read.
- break;
- }
- DCHECK(timestamp.IsInitialized());
- cur_max_timestamp_ = QuicTime::Max(timestamp, cur_max_timestamp_);
- } else {
- if (sequencer()->GetReadableRegions(&iov, 1) != 1) {
- // No more data to read.
- break;
- }
- }
- if (spdy_framer_.ProcessInput(static_cast<char*>(iov.iov_base),
- iov.iov_len) != iov.iov_len) {
- // Error processing data.
- return;
- }
- sequencer()->MarkConsumed(iov.iov_len);
- }
-}
-
-void QuicHeadersStream::OnHeaders(SpdyStreamId stream_id,
- bool has_priority,
- SpdyPriority priority,
- bool fin) {
- if (has_priority) {
- if (session()->perspective() == Perspective::IS_CLIENT) {
- CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
- "Server must not send priorities.");
- return;
- }
- spdy_session_->OnStreamHeadersPriority(stream_id, priority);
- } else {
- if (session()->perspective() == Perspective::IS_SERVER) {
- CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
- "Client must send priorities.");
- return;
- }
- }
- DCHECK_EQ(kInvalidStreamId, stream_id_);
- DCHECK_EQ(kInvalidStreamId, promised_stream_id_);
- stream_id_ = stream_id;
- fin_ = fin;
-}
-
-void QuicHeadersStream::OnPushPromise(SpdyStreamId stream_id,
- SpdyStreamId promised_stream_id,
- bool end) {
- DCHECK_EQ(kInvalidStreamId, stream_id_);
- DCHECK_EQ(kInvalidStreamId, promised_stream_id_);
- stream_id_ = stream_id;
- promised_stream_id_ = promised_stream_id;
-}
-
-void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id,
- const char* header_data,
- size_t len) {
- DCHECK_EQ(stream_id_, stream_id);
- if (len == 0) {
- DCHECK_NE(0u, stream_id_);
- DCHECK_NE(0u, frame_len_);
- if (measure_headers_hol_blocking_time_) {
- if (prev_max_timestamp_ > cur_max_timestamp_) {
- // prev_max_timestamp_ > cur_max_timestamp_ implies that
- // headers from lower numbered streams actually came off the
- // wire after headers for the current stream, hence there was
- // HOL blocking.
- QuicTime::Delta delta(prev_max_timestamp_.Subtract(cur_max_timestamp_));
- DVLOG(1) << "stream " << stream_id
- << ": Net.QuicSession.HeadersHOLBlockedTime "
- << delta.ToMilliseconds();
- spdy_session_->OnHeadersHeadOfLineBlocking(delta);
- }
- prev_max_timestamp_ = std::max(prev_max_timestamp_, cur_max_timestamp_);
- cur_max_timestamp_ = QuicTime::Zero();
- }
- if (promised_stream_id_ == kInvalidStreamId) {
- spdy_session_->OnStreamHeadersComplete(stream_id_, fin_, frame_len_);
- } else {
- spdy_session_->OnPromiseHeadersComplete(stream_id_, promised_stream_id_,
- frame_len_);
- }
- if (uncompressed_frame_len_ != 0) {
- int compression_pct = 100 - (100 * frame_len_) / uncompressed_frame_len_;
- DVLOG(1) << "Net.QuicHpackDecompressionPercentage: " << compression_pct;
- UMA_HISTOGRAM_PERCENTAGE("Net.QuicHpackDecompressionPercentage",
- compression_pct);
- }
- // Reset state for the next frame.
- promised_stream_id_ = kInvalidStreamId;
- stream_id_ = kInvalidStreamId;
- fin_ = false;
- frame_len_ = 0;
- uncompressed_frame_len_ = 0;
- } else {
- uncompressed_frame_len_ += len;
- if (promised_stream_id_ == kInvalidStreamId) {
- spdy_session_->OnStreamHeaders(stream_id_, StringPiece(header_data, len));
- } else {
- spdy_session_->OnPromiseHeaders(stream_id_,
- StringPiece(header_data, len));
- }
- }
-}
-
-void QuicHeadersStream::OnHeaderList(const QuicHeaderList& header_list) {
- DVLOG(1) << "Received header list for stream " << stream_id_ << ": "
- << header_list.DebugString();
- if (measure_headers_hol_blocking_time_) {
- if (prev_max_timestamp_ > cur_max_timestamp_) {
- // prev_max_timestamp_ > cur_max_timestamp_ implies that
- // headers from lower numbered streams actually came off the
- // wire after headers for the current stream, hence there was
- // HOL blocking.
- QuicTime::Delta delta = prev_max_timestamp_.Subtract(cur_max_timestamp_);
- DVLOG(1) << "stream " << stream_id_
- << ": Net.QuicSession.HeadersHOLBlockedTime "
- << delta.ToMilliseconds();
- spdy_session_->OnHeadersHeadOfLineBlocking(delta);
- }
- prev_max_timestamp_ = std::max(prev_max_timestamp_, cur_max_timestamp_);
- cur_max_timestamp_ = QuicTime::Zero();
- }
- if (promised_stream_id_ == kInvalidStreamId) {
- spdy_session_->OnStreamHeaderList(stream_id_, fin_, frame_len_,
- header_list);
- } else {
- spdy_session_->OnPromiseHeaderList(stream_id_, promised_stream_id_,
- frame_len_, header_list);
- }
- // Reset state for the next frame.
- promised_stream_id_ = kInvalidStreamId;
- stream_id_ = kInvalidStreamId;
- fin_ = false;
- frame_len_ = 0;
- uncompressed_frame_len_ = 0;
-}
-
-void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len) {
- frame_len_ += frame_len;
-}
-
-bool QuicHeadersStream::IsConnected() {
- return session()->connection()->connected();
-}
-
-void QuicHeadersStream::DisableHpackDynamicTable() {
- spdy_framer_.UpdateHeaderEncoderTableSize(0);
-}
-
-void QuicHeadersStream::SetHpackEncoderDebugVisitor(
- std::unique_ptr<HpackDebugVisitor> visitor) {
- spdy_framer_.SetEncoderHeaderTableDebugVisitor(
- std::unique_ptr<HeaderTableDebugVisitor>(new HeaderTableDebugVisitor(
- session()->connection()->helper()->GetClock(), std::move(visitor))));
-}
-
-void QuicHeadersStream::SetHpackDecoderDebugVisitor(
- std::unique_ptr<HpackDebugVisitor> visitor) {
- spdy_framer_.SetDecoderHeaderTableDebugVisitor(
- std::unique_ptr<HeaderTableDebugVisitor>(new HeaderTableDebugVisitor(
- session()->connection()->helper()->GetClock(), std::move(visitor))));
-}
-
-void QuicHeadersStream::UpdateHeaderEncoderTableSize(uint32_t value) {
- spdy_framer_.UpdateHeaderEncoderTableSize(value);
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_headers_stream.h b/chromium/net/quic/quic_headers_stream.h
deleted file mode 100644
index 3f174030878..00000000000
--- a/chromium/net/quic/quic_headers_stream.h
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_HEADERS_STREAM_H_
-#define NET_QUIC_QUIC_HEADERS_STREAM_H_
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_header_list.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/reliable_quic_stream.h"
-#include "net/spdy/spdy_framer.h"
-
-namespace net {
-
-class QuicSpdySession;
-
-namespace test {
-class QuicHeadersStreamPeer;
-} // namespace test
-
-// Headers in QUIC are sent as HTTP/2 HEADERS or PUSH_PROMISE frames
-// over a reserved reliable stream with the id 3. Each endpoint
-// (client and server) will allocate an instance of QuicHeadersStream
-// to send and receive headers.
-class NET_EXPORT_PRIVATE QuicHeadersStream : public ReliableQuicStream {
- public:
- class NET_EXPORT_PRIVATE HpackDebugVisitor {
- public:
- HpackDebugVisitor();
-
- virtual ~HpackDebugVisitor();
-
- // For each HPACK indexed representation processed, |elapsed| is
- // the time since the corresponding entry was added to the dynamic
- // table.
- virtual void OnUseEntry(QuicTime::Delta elapsed) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(HpackDebugVisitor);
- };
-
- explicit QuicHeadersStream(QuicSpdySession* session);
- ~QuicHeadersStream() override;
-
- // Writes |headers| for |stream_id| in an HTTP/2 HEADERS frame to the peer.
- // If |fin| is true, the fin flag will be set on the HEADERS frame. Returns
- // the size, in bytes, of the resulting HEADERS frame.
- virtual size_t WriteHeaders(QuicStreamId stream_id,
- SpdyHeaderBlock headers,
- bool fin,
- SpdyPriority priority,
- QuicAckListenerInterface* ack_listener);
-
- // 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.
- virtual size_t WritePushPromise(QuicStreamId original_stream_id,
- QuicStreamId promised_stream_id,
- SpdyHeaderBlock headers,
- QuicAckListenerInterface* ack_listener);
-
- // ReliableQuicStream implementation
- void OnDataAvailable() override;
-
- bool supports_push_promise() { return supports_push_promise_; }
-
- // Experimental: force HPACK to use static table and huffman coding
- // only. Part of exploring improvements related to headers stream
- // induced HOL blocking in QUIC.
- void DisableHpackDynamicTable();
-
- // Optional, enables instrumentation related to go/quic-hpack.
- void SetHpackEncoderDebugVisitor(std::unique_ptr<HpackDebugVisitor> visitor);
- void SetHpackDecoderDebugVisitor(std::unique_ptr<HpackDebugVisitor> visitor);
-
- // Sets the maximum size of the header compression table spdy_framer_ is
- // willing to use to decode header blocks.
- void UpdateHeaderEncoderTableSize(uint32_t value);
-
- // Sets how much encoded data the hpack decoder of spdy_framer_ is willing to
- // buffer.
- void set_max_decode_buffer_size_bytes(size_t max_decode_buffer_size_bytes) {
- spdy_framer_.set_max_decode_buffer_size_bytes(max_decode_buffer_size_bytes);
- }
-
- private:
- friend class test::QuicHeadersStreamPeer;
-
- class SpdyFramerVisitor;
-
- // The following methods are called by the SimpleVisitor.
-
- // Called when a HEADERS frame has been received.
- void OnHeaders(SpdyStreamId stream_id,
- bool has_priority,
- SpdyPriority priority,
- bool fin);
-
- // Called when a PUSH_PROMISE frame has been received.
- void OnPushPromise(SpdyStreamId stream_id,
- SpdyStreamId promised_stream_id,
- bool end);
-
- // Called when a chunk of header data is available. This is called
- // after OnHeaders.
- // |stream_id| The stream receiving the header data.
- // |header_data| A buffer containing the header data chunk received.
- // |len| The length of the header data buffer. A length of zero indicates
- // that the header data block has been completely sent.
- void OnControlFrameHeaderData(SpdyStreamId stream_id,
- const char* header_data,
- size_t len);
-
- // Called when the complete list of headers is available.
- void OnHeaderList(const QuicHeaderList& header_list);
-
- // Called when the size of the compressed frame payload is available.
- void OnCompressedFrameSize(size_t frame_len);
-
- // Returns true if the session is still connected.
- bool IsConnected();
-
- QuicSpdySession* spdy_session_;
-
- // Data about the stream whose headers are being processed.
- QuicStreamId stream_id_;
- QuicStreamId promised_stream_id_;
- bool fin_;
- size_t frame_len_;
- size_t uncompressed_frame_len_;
-
- // Helper variables that cache the corresponding feature flag.
- bool measure_headers_hol_blocking_time_;
- bool supports_push_promise_;
-
- // Timestamps used to measure HOL blocking, these are recorded by
- // the sequencer approximate to the time of arrival off the wire.
- // |cur_max_timestamp_| tracks the most recent arrival time of
- // frames for current (at the headers stream level) processed
- // stream's headers, and |prev_max_timestamp_| tracks the most
- // recent arrival time of lower numbered streams.
- QuicTime cur_max_timestamp_;
- QuicTime prev_max_timestamp_;
-
- SpdyFramer spdy_framer_;
- std::unique_ptr<SpdyFramerVisitor> spdy_framer_visitor_;
-
- // Either empty, or contains the complete list of headers.
- QuicHeaderList header_list_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicHeadersStream);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_HEADERS_STREAM_H_
diff --git a/chromium/net/quic/quic_headers_stream_test.cc b/chromium/net/quic/quic_headers_stream_test.cc
deleted file mode 100644
index 2a606856bb0..00000000000
--- a/chromium/net/quic/quic_headers_stream_test.cc
+++ /dev/null
@@ -1,792 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_headers_stream.h"
-
-#include <string>
-
-#include "base/strings/string_number_conversions.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/spdy_utils.h"
-#include "net/quic/test_tools/quic_connection_peer.h"
-#include "net/quic/test_tools/quic_spdy_session_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/quic/test_tools/reliable_quic_stream_peer.h"
-#include "net/spdy/spdy_alt_svc_wire_format.h"
-#include "net/spdy/spdy_flags.h"
-#include "net/spdy/spdy_protocol.h"
-#include "net/spdy/spdy_test_utils.h"
-#include "net/test/gtest_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::StringPiece;
-using std::ostream;
-using std::string;
-using std::vector;
-using testing::ElementsAre;
-using testing::InSequence;
-using testing::Invoke;
-using testing::Return;
-using testing::StrictMock;
-using testing::WithArgs;
-using testing::_;
-
-namespace net {
-namespace test {
-
-class MockHpackDebugVisitor : public QuicHeadersStream::HpackDebugVisitor {
- public:
- explicit MockHpackDebugVisitor() : HpackDebugVisitor() {}
-
- MOCK_METHOD1(OnUseEntry, void(QuicTime::Delta elapsed));
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockHpackDebugVisitor);
-};
-
-class QuicHeadersStreamPeer {
- public:
- static const SpdyFramer& GetSpdyFramer(QuicHeadersStream* stream) {
- return stream->spdy_framer_;
- }
-};
-
-namespace {
-
-// TODO(ckrasic): this workaround is due to absence of std::initializer_list
-const bool kFins[] = {false, true};
-
-class MockVisitor : public SpdyFramerVisitorInterface {
- public:
- MOCK_METHOD1(OnError, void(SpdyFramer* framer));
- MOCK_METHOD3(OnDataFrameHeader,
- void(SpdyStreamId stream_id, size_t length, bool fin));
- MOCK_METHOD3(OnStreamFrameData,
- void(SpdyStreamId stream_id, const char* data, size_t len));
- MOCK_METHOD1(OnStreamEnd, void(SpdyStreamId stream_id));
- MOCK_METHOD2(OnStreamPadding, void(SpdyStreamId stream_id, size_t len));
- MOCK_METHOD1(OnHeaderFrameStart,
- SpdyHeadersHandlerInterface*(SpdyStreamId stream_id));
- MOCK_METHOD2(OnHeaderFrameEnd, void(SpdyStreamId stream_id, bool end));
- MOCK_METHOD3(OnControlFrameHeaderData,
- bool(SpdyStreamId stream_id,
- const char* header_data,
- size_t len));
- MOCK_METHOD5(OnSynStream,
- void(SpdyStreamId stream_id,
- SpdyStreamId associated_stream_id,
- SpdyPriority priority,
- bool fin,
- bool unidirectional));
- MOCK_METHOD2(OnSynReply, void(SpdyStreamId stream_id, bool fin));
- MOCK_METHOD2(OnRstStream,
- void(SpdyStreamId stream_id, SpdyRstStreamStatus status));
- MOCK_METHOD1(OnSettings, void(bool clear_persisted));
- MOCK_METHOD3(OnSetting,
- void(SpdySettingsIds id, uint8_t flags, uint32_t value));
- MOCK_METHOD0(OnSettingsAck, void());
- MOCK_METHOD0(OnSettingsEnd, void());
- MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack));
- MOCK_METHOD2(OnGoAway,
- void(SpdyStreamId last_accepted_stream_id,
- SpdyGoAwayStatus status));
- MOCK_METHOD7(OnHeaders,
- void(SpdyStreamId stream_id,
- bool has_priority,
- int weight,
- SpdyStreamId parent_stream_id,
- bool exclusive,
- bool fin,
- bool end));
- MOCK_METHOD2(OnWindowUpdate,
- void(SpdyStreamId stream_id, int delta_window_size));
- MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id));
- MOCK_METHOD3(OnPushPromise,
- void(SpdyStreamId stream_id,
- SpdyStreamId promised_stream_id,
- bool end));
- MOCK_METHOD2(OnContinuation, void(SpdyStreamId stream_id, bool end));
- MOCK_METHOD4(OnPriority,
- void(SpdyStreamId stream_id,
- SpdyStreamId parent_id,
- int weight,
- bool exclusive));
- MOCK_METHOD3(OnAltSvc,
- void(SpdyStreamId stream_id,
- StringPiece origin,
- const SpdyAltSvcWireFormat::AlternativeServiceVector&
- altsvc_vector));
- MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type));
-};
-
-// Run all tests with each version, perspective (client or server),
-// and relevant flag options (false or true)
-struct TestParams {
- TestParams(QuicVersion version, Perspective perspective)
- : version(version), perspective(perspective) {}
-
- friend ostream& operator<<(ostream& os, const TestParams& p) {
- os << "{ version: " << QuicVersionToString(p.version);
- os << ", perspective: " << p.perspective << " }";
- return os;
- }
-
- QuicVersion version;
- Perspective perspective;
-};
-
-// Constructs various test permutations.
-vector<TestParams> GetTestParams() {
- vector<TestParams> params;
- QuicVersionVector all_supported_versions = QuicSupportedVersions();
- for (const QuicVersion version : all_supported_versions) {
- params.push_back(TestParams(version, Perspective::IS_CLIENT));
- params.push_back(TestParams(version, Perspective::IS_SERVER));
- }
- FLAGS_quic_supports_push_promise = true;
- return params;
-}
-
-class QuicHeadersStreamTest : public ::testing::TestWithParam<TestParams> {
- public:
- QuicHeadersStreamTest()
- : connection_(new StrictMock<MockQuicConnection>(&helper_,
- &alarm_factory_,
- perspective(),
- GetVersion())),
- session_(connection_),
- headers_stream_(QuicSpdySessionPeer::GetHeadersStream(&session_)),
- body_("hello world"),
- hpack_encoder_visitor_(new StrictMock<MockHpackDebugVisitor>),
- hpack_decoder_visitor_(new StrictMock<MockHpackDebugVisitor>),
- stream_frame_(kHeadersStreamId, /*fin=*/false, /*offset=*/0, ""),
- next_promised_stream_id_(2) {
- FLAGS_quic_always_log_bugs_for_tests = true;
- headers_[":version"] = "HTTP/1.1";
- headers_[":status"] = "200 Ok";
- headers_["content-length"] = "11";
- framer_ = std::unique_ptr<SpdyFramer>(new SpdyFramer(HTTP2));
- framer_->set_visitor(&visitor_);
- EXPECT_EQ(version(), session_.connection()->version());
- EXPECT_TRUE(headers_stream_ != nullptr);
- VLOG(1) << GetParam();
- connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- }
-
- QuicConsumedData SaveIov(const QuicIOVector& data) {
- const iovec* iov = data.iov;
- int count = data.iov_count;
- for (int i = 0; i < count; ++i) {
- saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
- }
- return QuicConsumedData(saved_data_.length(), false);
- }
-
- bool SaveHeaderData(const char* data, int len) {
- saved_header_data_.append(data, len);
- return true;
- }
-
- void SaveHeaderDataStringPiece(StringPiece data) {
- saved_header_data_.append(data.data(), data.length());
- }
-
- void SavePromiseHeaderList(QuicStreamId /* stream_id */,
- QuicStreamId /* promised_stream_id */,
- size_t size,
- const QuicHeaderList& header_list) {
- SaveToHandler(size, header_list);
- }
-
- void SaveHeaderList(QuicStreamId /* stream_id */,
- bool /* fin */,
- size_t size,
- const QuicHeaderList& header_list) {
- SaveToHandler(size, header_list);
- }
-
- void SaveToHandler(size_t size, const QuicHeaderList& header_list) {
- headers_handler_.reset(new TestHeadersHandler);
- headers_handler_->OnHeaderBlockStart();
- for (const auto& p : header_list) {
- headers_handler_->OnHeader(p.first, p.second);
- }
- headers_handler_->OnHeaderBlockEnd(size);
- }
-
- void WriteHeadersAndExpectSynStream(QuicStreamId stream_id,
- bool fin,
- SpdyPriority priority) {
- WriteHeadersAndCheckData(stream_id, fin, priority, SYN_STREAM);
- }
-
- void WriteHeadersAndExpectSynReply(QuicStreamId stream_id, bool fin) {
- WriteHeadersAndCheckData(stream_id, fin, 0, SYN_REPLY);
- }
-
- void WriteHeadersAndCheckData(QuicStreamId stream_id,
- bool fin,
- SpdyPriority priority,
- SpdyFrameType type) {
- // Write the headers and capture the outgoing data
- EXPECT_CALL(session_, WritevData(headers_stream_, kHeadersStreamId, _, _,
- false, nullptr))
- .WillOnce(WithArgs<2>(Invoke(this, &QuicHeadersStreamTest::SaveIov)));
- headers_stream_->WriteHeaders(stream_id, headers_.Clone(), fin, priority,
- nullptr);
-
- // Parse the outgoing data and check that it matches was was written.
- if (type == SYN_STREAM) {
- EXPECT_CALL(visitor_,
- OnHeaders(stream_id, kHasPriority,
- Spdy3PriorityToHttp2Weight(priority),
- /*parent_stream_id=*/0,
- /*exclusive=*/false, fin, kFrameComplete));
- } else {
- EXPECT_CALL(visitor_,
- OnHeaders(stream_id, !kHasPriority,
- /*priority=*/0,
- /*parent_stream_id=*/0,
- /*exclusive=*/false, fin, kFrameComplete));
- }
- headers_handler_.reset(new TestHeadersHandler);
- EXPECT_CALL(visitor_, OnHeaderFrameStart(stream_id))
- .WillOnce(Return(headers_handler_.get()));
- EXPECT_CALL(visitor_, OnHeaderFrameEnd(stream_id, true)).Times(1);
- if (fin) {
- EXPECT_CALL(visitor_, OnStreamEnd(stream_id));
- }
- framer_->ProcessInput(saved_data_.data(), saved_data_.length());
- EXPECT_FALSE(framer_->HasError())
- << SpdyFramer::ErrorCodeToString(framer_->error_code());
-
- CheckHeaders();
- saved_data_.clear();
- }
-
- void CheckHeaders() {
- EXPECT_EQ(headers_, headers_handler_->decoded_block());
- headers_handler_.reset();
- }
-
- Perspective perspective() { return GetParam().perspective; }
-
- QuicVersion version() { return GetParam().version; }
-
- QuicVersionVector GetVersion() {
- QuicVersionVector versions;
- versions.push_back(version());
- return versions;
- }
-
- void TearDownLocalConnectionState() {
- QuicConnectionPeer::TearDownLocalConnectionState(connection_);
- }
-
- QuicStreamId NextPromisedStreamId() { return next_promised_stream_id_ += 2; }
-
- static const bool kFrameComplete = true;
- static const bool kHasPriority = true;
-
- MockQuicConnectionHelper helper_;
- MockAlarmFactory alarm_factory_;
- StrictMock<MockQuicConnection>* connection_;
- StrictMock<MockQuicSpdySession> session_;
- QuicHeadersStream* headers_stream_;
- SpdyHeaderBlock headers_;
- std::unique_ptr<TestHeadersHandler> headers_handler_;
- string body_;
- string saved_data_;
- string saved_header_data_;
- std::unique_ptr<SpdyFramer> framer_;
- StrictMock<MockVisitor> visitor_;
- std::unique_ptr<StrictMock<MockHpackDebugVisitor>> hpack_encoder_visitor_;
- std::unique_ptr<StrictMock<MockHpackDebugVisitor>> hpack_decoder_visitor_;
- QuicStreamFrame stream_frame_;
- QuicStreamId next_promised_stream_id_;
-};
-
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicHeadersStreamTest,
- ::testing::ValuesIn(GetTestParams()));
-
-TEST_P(QuicHeadersStreamTest, StreamId) {
- EXPECT_EQ(3u, headers_stream_->id());
-}
-
-TEST_P(QuicHeadersStreamTest, WriteHeaders) {
- for (QuicStreamId stream_id = kClientDataStreamId1;
- stream_id < kClientDataStreamId3; stream_id += 2) {
- for (bool fin : kFins) {
- if (perspective() == Perspective::IS_SERVER) {
- WriteHeadersAndExpectSynReply(stream_id, fin);
- } else {
- for (SpdyPriority priority = 0; priority < 7; ++priority) {
- // TODO(rch): implement priorities correctly.
- WriteHeadersAndExpectSynStream(stream_id, fin, 0);
- }
- }
- }
- }
-}
-
-TEST_P(QuicHeadersStreamTest, WritePushPromises) {
- for (QuicStreamId stream_id = kClientDataStreamId1;
- stream_id < kClientDataStreamId3; stream_id += 2) {
- QuicStreamId promised_stream_id = NextPromisedStreamId();
- if (perspective() == Perspective::IS_SERVER) {
- // Write the headers and capture the outgoing data
- EXPECT_CALL(session_, WritevData(headers_stream_, kHeadersStreamId, _, _,
- false, nullptr))
- .WillOnce(WithArgs<2>(Invoke(this, &QuicHeadersStreamTest::SaveIov)));
- headers_stream_->WritePushPromise(stream_id, promised_stream_id,
- headers_.Clone(), nullptr);
-
- // Parse the outgoing data and check that it matches was was written.
- EXPECT_CALL(visitor_,
- OnPushPromise(stream_id, promised_stream_id, kFrameComplete));
- headers_handler_.reset(new TestHeadersHandler);
- EXPECT_CALL(visitor_, OnHeaderFrameStart(stream_id))
- .WillOnce(Return(headers_handler_.get()));
- EXPECT_CALL(visitor_, OnHeaderFrameEnd(stream_id, true)).Times(1);
- framer_->ProcessInput(saved_data_.data(), saved_data_.length());
- EXPECT_FALSE(framer_->HasError())
- << SpdyFramer::ErrorCodeToString(framer_->error_code());
- CheckHeaders();
- saved_data_.clear();
- } else {
- EXPECT_DFATAL(
- headers_stream_->WritePushPromise(stream_id, promised_stream_id,
- headers_.Clone(), nullptr),
- "Client shouldn't send PUSH_PROMISE");
- }
- }
-}
-
-TEST_P(QuicHeadersStreamTest, ProcessRawData) {
- for (QuicStreamId stream_id = kClientDataStreamId1;
- stream_id < kClientDataStreamId3; stream_id += 2) {
- for (bool fin : {false, true}) {
- for (SpdyPriority priority = 0; priority < 7; ++priority) {
- // Replace with "WriteHeadersAndSaveData"
- SpdySerializedFrame frame;
- if (perspective() == Perspective::IS_SERVER) {
- SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
- headers_frame.set_fin(fin);
- headers_frame.set_has_priority(true);
- headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0));
- frame = framer_->SerializeFrame(headers_frame);
- EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
- } else {
- SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
- headers_frame.set_fin(fin);
- frame = framer_->SerializeFrame(headers_frame);
- }
- EXPECT_CALL(session_,
- OnStreamHeaderList(stream_id, fin, frame.size(), _))
- .WillOnce(Invoke(this, &QuicHeadersStreamTest::SaveHeaderList));
- stream_frame_.data_buffer = frame.data();
- stream_frame_.data_length = frame.size();
- headers_stream_->OnStreamFrame(stream_frame_);
- stream_frame_.offset += frame.size();
- CheckHeaders();
- }
- }
- }
-}
-
-TEST_P(QuicHeadersStreamTest, ProcessPushPromise) {
- if (perspective() == Perspective::IS_SERVER)
- return;
- for (QuicStreamId stream_id = kClientDataStreamId1;
- stream_id < kClientDataStreamId3; stream_id += 2) {
- QuicStreamId promised_stream_id = NextPromisedStreamId();
- SpdyPushPromiseIR push_promise(stream_id, promised_stream_id,
- headers_.Clone());
- SpdySerializedFrame frame(framer_->SerializeFrame(push_promise));
- if (perspective() == Perspective::IS_SERVER) {
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
- "PUSH_PROMISE not supported.", _))
- .WillRepeatedly(InvokeWithoutArgs(
- this, &QuicHeadersStreamTest::TearDownLocalConnectionState));
- } else {
- EXPECT_CALL(session_, OnPromiseHeaderList(stream_id, promised_stream_id,
- frame.size(), _))
- .WillOnce(
- Invoke(this, &QuicHeadersStreamTest::SavePromiseHeaderList));
- }
- stream_frame_.data_buffer = frame.data();
- stream_frame_.data_length = frame.size();
- headers_stream_->OnStreamFrame(stream_frame_);
- if (perspective() == Perspective::IS_CLIENT) {
- stream_frame_.offset += frame.size();
- CheckHeaders();
- }
- }
-}
-
-TEST_P(QuicHeadersStreamTest, EmptyHeaderHOLBlockedTime) {
- if (!FLAGS_quic_measure_headers_hol_blocking_time) {
- return;
- }
- EXPECT_CALL(session_, OnHeadersHeadOfLineBlocking(_)).Times(0);
- testing::InSequence seq;
- bool fin = true;
- for (int stream_num = 0; stream_num < 10; stream_num++) {
- QuicStreamId stream_id = QuicClientDataStreamId(stream_num);
- // Replace with "WriteHeadersAndSaveData"
- SpdySerializedFrame frame;
- if (perspective() == Perspective::IS_SERVER) {
- SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
- headers_frame.set_fin(fin);
- headers_frame.set_has_priority(true);
- headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0));
- frame = framer_->SerializeFrame(headers_frame);
- EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
- } else {
- SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
- headers_frame.set_fin(fin);
- frame = framer_->SerializeFrame(headers_frame);
- }
- EXPECT_CALL(session_, OnStreamHeaderList(stream_id, fin, frame.size(), _))
- .Times(1);
- stream_frame_.data_buffer = frame.data();
- stream_frame_.data_length = frame.size();
- headers_stream_->OnStreamFrame(stream_frame_);
- connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- stream_frame_.offset += frame.size();
- }
-}
-
-TEST_P(QuicHeadersStreamTest, NonEmptyHeaderHOLBlockedTime) {
- if (!FLAGS_quic_measure_headers_hol_blocking_time) {
- return;
- }
- QuicStreamId stream_id;
- bool fin = true;
- QuicStreamFrame stream_frames[10];
- SpdySerializedFrame frames[10];
- // First create all the frames in order
- {
- InSequence seq;
- for (int stream_num = 0; stream_num < 10; ++stream_num) {
- stream_id = QuicClientDataStreamId(stream_num);
- if (perspective() == Perspective::IS_SERVER) {
- SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
- headers_frame.set_fin(fin);
- headers_frame.set_has_priority(true);
- headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0));
- frames[stream_num] = framer_->SerializeFrame(headers_frame);
- EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)).Times(1);
- } else {
- SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
- headers_frame.set_fin(fin);
- frames[stream_num] = framer_->SerializeFrame(headers_frame);
- }
- stream_frames[stream_num].stream_id = stream_frame_.stream_id;
- stream_frames[stream_num].offset = stream_frame_.offset;
- stream_frames[stream_num].data_buffer = frames[stream_num].data();
- stream_frames[stream_num].data_length = frames[stream_num].size();
- DVLOG(1) << "make frame for stream " << stream_num << " offset "
- << stream_frames[stream_num].offset;
- stream_frame_.offset += frames[stream_num].size();
- EXPECT_CALL(session_, OnStreamHeaderList(stream_id, fin, _, _)).Times(1);
- }
- }
-
- // Actually writing the frames in reverse order will cause HOL blocking.
- EXPECT_CALL(session_, OnHeadersHeadOfLineBlocking(_)).Times(9);
-
- for (int stream_num = 9; stream_num >= 0; --stream_num) {
- DVLOG(1) << "OnStreamFrame for stream " << stream_num << " offset "
- << stream_frames[stream_num].offset;
- headers_stream_->OnStreamFrame(stream_frames[stream_num]);
- connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- }
-}
-
-TEST_P(QuicHeadersStreamTest, ProcessLargeRawData) {
- // We want to create a frame that is more than the SPDY Framer's max control
- // frame size, which is 16K, but less than the HPACK decoders max decode
- // buffer size, which is 32K.
- headers_["key0"] = string(1 << 13, '.');
- headers_["key1"] = string(1 << 13, '.');
- headers_["key2"] = string(1 << 13, '.');
- for (QuicStreamId stream_id = kClientDataStreamId1;
- stream_id < kClientDataStreamId3; stream_id += 2) {
- for (bool fin : {false, true}) {
- for (SpdyPriority priority = 0; priority < 7; ++priority) {
- // Replace with "WriteHeadersAndSaveData"
- SpdySerializedFrame frame;
- if (perspective() == Perspective::IS_SERVER) {
- SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
- headers_frame.set_fin(fin);
- headers_frame.set_has_priority(true);
- headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0));
- frame = framer_->SerializeFrame(headers_frame);
- EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
- } else {
- SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
- headers_frame.set_fin(fin);
- frame = framer_->SerializeFrame(headers_frame);
- }
- EXPECT_CALL(session_,
- OnStreamHeaderList(stream_id, fin, frame.size(), _))
- .WillOnce(Invoke(this, &QuicHeadersStreamTest::SaveHeaderList));
- stream_frame_.data_buffer = frame.data();
- stream_frame_.data_length = frame.size();
- headers_stream_->OnStreamFrame(stream_frame_);
- stream_frame_.offset += frame.size();
- CheckHeaders();
- }
- }
- }
-}
-
-TEST_P(QuicHeadersStreamTest, ProcessBadData) {
- const char kBadData[] = "blah blah blah";
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _))
- .Times(::testing::AnyNumber());
- stream_frame_.data_buffer = kBadData;
- stream_frame_.data_length = strlen(kBadData);
- headers_stream_->OnStreamFrame(stream_frame_);
-}
-
-TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrame) {
- SpdyDataIR data(2, "");
- SpdySerializedFrame frame(framer_->SerializeFrame(data));
- EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
- "SPDY DATA frame received.", _))
- .WillOnce(InvokeWithoutArgs(
- this, &QuicHeadersStreamTest::TearDownLocalConnectionState));
- stream_frame_.data_buffer = frame.data();
- stream_frame_.data_length = frame.size();
- headers_stream_->OnStreamFrame(stream_frame_);
-}
-
-TEST_P(QuicHeadersStreamTest, ProcessSpdyRstStreamFrame) {
- SpdyRstStreamIR data(2, RST_STREAM_PROTOCOL_ERROR);
- SpdySerializedFrame frame(framer_->SerializeFrame(data));
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
- "SPDY RST_STREAM frame received.", _))
- .WillOnce(InvokeWithoutArgs(
- this, &QuicHeadersStreamTest::TearDownLocalConnectionState));
- stream_frame_.data_buffer = frame.data();
- stream_frame_.data_length = frame.size();
- headers_stream_->OnStreamFrame(stream_frame_);
-}
-
-TEST_P(QuicHeadersStreamTest, ProcessSpdySettingsFrame) {
- FLAGS_quic_respect_http2_settings_frame = false;
- SpdySettingsIR data;
- data.AddSetting(SETTINGS_HEADER_TABLE_SIZE, true, true, 0);
- SpdySerializedFrame frame(framer_->SerializeFrame(data));
- EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
- "SPDY SETTINGS frame received.", _))
- .WillOnce(InvokeWithoutArgs(
- this, &QuicHeadersStreamTest::TearDownLocalConnectionState));
- stream_frame_.data_buffer = frame.data();
- stream_frame_.data_length = frame.size();
- headers_stream_->OnStreamFrame(stream_frame_);
-}
-
-TEST_P(QuicHeadersStreamTest, RespectHttp2SettingsFrameSupportedFields) {
- FLAGS_quic_respect_http2_settings_frame = true;
- const uint32_t kTestHeaderTableSize = 1000;
- SpdySettingsIR data;
- // Respect supported settings frames SETTINGS_HEADER_TABLE_SIZE.
- data.AddSetting(SETTINGS_HEADER_TABLE_SIZE, true, true, kTestHeaderTableSize);
- SpdySerializedFrame frame(framer_->SerializeFrame(data));
- stream_frame_.data_buffer = frame.data();
- stream_frame_.data_length = frame.size();
- headers_stream_->OnStreamFrame(stream_frame_);
- EXPECT_EQ(kTestHeaderTableSize,
- QuicHeadersStreamPeer::GetSpdyFramer(headers_stream_)
- .header_encoder_table_size());
-}
-
-TEST_P(QuicHeadersStreamTest, RespectHttp2SettingsFrameUnsupportedFields) {
- FLAGS_quic_respect_http2_settings_frame = true;
- SpdySettingsIR data;
- // Does not support SETTINGS_MAX_HEADER_LIST_SIZE,
- // SETTINGS_MAX_CONCURRENT_STREAMS, SETTINGS_INITIAL_WINDOW_SIZE,
- // SETTINGS_ENABLE_PUSH and SETTINGS_MAX_FRAME_SIZE.
- data.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, true, true, 2000);
- data.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, true, true, 100);
- data.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, true, true, 100);
- data.AddSetting(SETTINGS_ENABLE_PUSH, true, true, 1);
- data.AddSetting(SETTINGS_MAX_FRAME_SIZE, true, true, 1250);
- SpdySerializedFrame frame(framer_->SerializeFrame(data));
- EXPECT_CALL(
- *connection_,
- CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
- "Unsupported field of HTTP/2 SETTINGS frame: " +
- base::IntToString(SETTINGS_MAX_HEADER_LIST_SIZE),
- _));
- EXPECT_CALL(
- *connection_,
- CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
- "Unsupported field of HTTP/2 SETTINGS frame: " +
- base::IntToString(SETTINGS_MAX_CONCURRENT_STREAMS),
- _));
- EXPECT_CALL(
- *connection_,
- CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
- "Unsupported field of HTTP/2 SETTINGS frame: " +
- base::IntToString(SETTINGS_INITIAL_WINDOW_SIZE),
- _));
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
- "Unsupported field of HTTP/2 SETTINGS frame: " +
- base::IntToString(SETTINGS_ENABLE_PUSH),
- _));
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
- "Unsupported field of HTTP/2 SETTINGS frame: " +
- base::IntToString(SETTINGS_MAX_FRAME_SIZE),
- _));
- stream_frame_.data_buffer = frame.data();
- stream_frame_.data_length = frame.size();
- headers_stream_->OnStreamFrame(stream_frame_);
-}
-
-TEST_P(QuicHeadersStreamTest, ProcessSpdyPingFrame) {
- SpdyPingIR data(1);
- SpdySerializedFrame frame(framer_->SerializeFrame(data));
- EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
- "SPDY PING frame received.", _))
- .WillOnce(InvokeWithoutArgs(
- this, &QuicHeadersStreamTest::TearDownLocalConnectionState));
- stream_frame_.data_buffer = frame.data();
- stream_frame_.data_length = frame.size();
- headers_stream_->OnStreamFrame(stream_frame_);
-}
-
-TEST_P(QuicHeadersStreamTest, ProcessSpdyGoAwayFrame) {
- SpdyGoAwayIR data(1, GOAWAY_PROTOCOL_ERROR, "go away");
- SpdySerializedFrame frame(framer_->SerializeFrame(data));
- EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
- "SPDY GOAWAY frame received.", _))
- .WillOnce(InvokeWithoutArgs(
- this, &QuicHeadersStreamTest::TearDownLocalConnectionState));
- stream_frame_.data_buffer = frame.data();
- stream_frame_.data_length = frame.size();
- headers_stream_->OnStreamFrame(stream_frame_);
-}
-
-TEST_P(QuicHeadersStreamTest, ProcessSpdyWindowUpdateFrame) {
- SpdyWindowUpdateIR data(1, 1);
- SpdySerializedFrame frame(framer_->SerializeFrame(data));
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
- "SPDY WINDOW_UPDATE frame received.", _))
- .WillOnce(InvokeWithoutArgs(
- this, &QuicHeadersStreamTest::TearDownLocalConnectionState));
- stream_frame_.data_buffer = frame.data();
- stream_frame_.data_length = frame.size();
- headers_stream_->OnStreamFrame(stream_frame_);
-}
-
-TEST_P(QuicHeadersStreamTest, NoConnectionLevelFlowControl) {
- EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl(
- headers_stream_));
-}
-
-TEST_P(QuicHeadersStreamTest, HpackDecoderDebugVisitor) {
- if (FLAGS_use_nested_spdy_framer_decoder)
- return;
-
- StrictMock<MockHpackDebugVisitor>* hpack_decoder_visitor =
- hpack_decoder_visitor_.get();
- headers_stream_->SetHpackDecoderDebugVisitor(
- std::move(hpack_decoder_visitor_));
-
- // Create some headers we expect to generate entries in HPACK's
- // dynamic table, in addition to content-length.
- headers_["key0"] = string(1 << 1, '.');
- headers_["key1"] = string(1 << 2, '.');
- headers_["key2"] = string(1 << 3, '.');
- {
- testing::InSequence seq;
- // Number of indexed representations generated in headers below.
- for (int i = 1; i < 28; i++) {
- EXPECT_CALL(*hpack_decoder_visitor,
- OnUseEntry(QuicTime::Delta::FromMilliseconds(i)))
- .Times(4);
- }
- }
- for (QuicStreamId stream_id = kClientDataStreamId1;
- stream_id < kClientDataStreamId3; stream_id += 2) {
- for (bool fin : {false, true}) {
- for (SpdyPriority priority = 0; priority < 7; ++priority) {
- // Replace with "WriteHeadersAndSaveData"
- SpdySerializedFrame frame;
- if (perspective() == Perspective::IS_SERVER) {
- SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
- headers_frame.set_fin(fin);
- headers_frame.set_has_priority(true);
- headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0));
- frame = framer_->SerializeFrame(headers_frame);
- EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0));
- } else {
- SpdyHeadersIR headers_frame(stream_id, headers_.Clone());
- headers_frame.set_fin(fin);
- frame = framer_->SerializeFrame(headers_frame);
- }
- EXPECT_CALL(session_,
- OnStreamHeaderList(stream_id, fin, frame.size(), _))
- .WillOnce(Invoke(this, &QuicHeadersStreamTest::SaveHeaderList));
- stream_frame_.data_buffer = frame.data();
- stream_frame_.data_length = frame.size();
- connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- headers_stream_->OnStreamFrame(stream_frame_);
- stream_frame_.offset += frame.size();
- CheckHeaders();
- }
- }
- }
-}
-
-TEST_P(QuicHeadersStreamTest, HpackEncoderDebugVisitor) {
- StrictMock<MockHpackDebugVisitor>* hpack_encoder_visitor =
- hpack_encoder_visitor_.get();
- headers_stream_->SetHpackEncoderDebugVisitor(
- std::move(hpack_encoder_visitor_));
-
- if (perspective() == Perspective::IS_SERVER) {
- testing::InSequence seq;
- for (int i = 1; i < 4; i++) {
- EXPECT_CALL(*hpack_encoder_visitor,
- OnUseEntry(QuicTime::Delta::FromMilliseconds(i)));
- }
- } else {
- testing::InSequence seq;
- for (int i = 1; i < 28; i++) {
- EXPECT_CALL(*hpack_encoder_visitor,
- OnUseEntry(QuicTime::Delta::FromMilliseconds(i)));
- }
- }
- for (QuicStreamId stream_id = kClientDataStreamId1;
- stream_id < kClientDataStreamId3; stream_id += 2) {
- for (bool fin : {false, true}) {
- if (perspective() == Perspective::IS_SERVER) {
- WriteHeadersAndExpectSynReply(stream_id, fin);
- connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- } else {
- for (SpdyPriority priority = 0; priority < 7; ++priority) {
- // TODO(rch): implement priorities correctly.
- WriteHeadersAndExpectSynStream(stream_id, fin, 0);
- connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- }
- }
- }
- }
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_http_stream.cc b/chromium/net/quic/quic_http_stream.cc
deleted file mode 100644
index 5009a2edf6d..00000000000
--- a/chromium/net/quic/quic_http_stream.cc
+++ /dev/null
@@ -1,828 +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/quic_http_stream.h"
-
-#include <utility>
-
-#include "base/callback_helpers.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/string_split.h"
-#include "base/strings/stringprintf.h"
-#include "net/base/load_flags.h"
-#include "net/base/net_errors.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_util.h"
-#include "net/quic/quic_client_promised_info.h"
-#include "net/quic/quic_http_utils.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/spdy_utils.h"
-#include "net/socket/next_proto.h"
-#include "net/spdy/spdy_frame_builder.h"
-#include "net/spdy/spdy_framer.h"
-#include "net/spdy/spdy_http_utils.h"
-#include "net/ssl/ssl_info.h"
-
-namespace net {
-
-namespace {
-
-std::unique_ptr<base::Value> NetLogQuicPushStreamCallback(
- QuicStreamId stream_id,
- const GURL* url,
- NetLogCaptureMode capture_mode) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetInteger("stream_id", stream_id);
- dict->SetString("url", url->spec());
- return std::move(dict);
-}
-
-} // namespace
-
-QuicHttpStream::QuicHttpStream(
- const base::WeakPtr<QuicChromiumClientSession>& session)
- : next_state_(STATE_NONE),
- session_(session),
- session_error_(OK),
- was_handshake_confirmed_(session->IsCryptoHandshakeConfirmed()),
- stream_(nullptr),
- request_info_(nullptr),
- request_body_stream_(nullptr),
- priority_(MINIMUM_PRIORITY),
- response_info_(nullptr),
- response_status_(OK),
- response_headers_received_(false),
- headers_bytes_received_(0),
- headers_bytes_sent_(0),
- closed_stream_received_bytes_(0),
- closed_stream_sent_bytes_(0),
- user_buffer_len_(0),
- quic_connection_error_(QUIC_NO_ERROR),
- port_migration_detected_(false),
- found_promise_(false),
- push_handle_(nullptr),
- weak_factory_(this) {
- DCHECK(session_);
- session_->AddObserver(this);
-}
-
-QuicHttpStream::~QuicHttpStream() {
- Close(false);
- if (session_)
- session_->RemoveObserver(this);
-}
-
-bool QuicHttpStream::CheckVary(const SpdyHeaderBlock& client_request,
- const SpdyHeaderBlock& promise_request,
- const SpdyHeaderBlock& promise_response) {
- HttpResponseInfo promise_response_info;
-
- HttpRequestInfo promise_request_info;
- ConvertHeaderBlockToHttpRequestHeaders(promise_request,
- &promise_request_info.extra_headers);
- HttpRequestInfo client_request_info;
- ConvertHeaderBlockToHttpRequestHeaders(client_request,
- &client_request_info.extra_headers);
-
- if (!SpdyHeadersToHttpResponse(promise_response, HTTP2,
- &promise_response_info)) {
- DLOG(WARNING) << "Invalid headers";
- return false;
- }
-
- HttpVaryData vary_data;
- if (!vary_data.Init(promise_request_info,
- *promise_response_info.headers.get())) {
- // Promise didn't contain valid vary info, so URL match was sufficient.
- return true;
- }
- // Now compare the client request for matching.
- return vary_data.MatchesRequest(client_request_info,
- *promise_response_info.headers.get());
-}
-
-void QuicHttpStream::OnRendezvousResult(QuicSpdyStream* stream) {
- push_handle_ = nullptr;
- if (stream) {
- stream_ = static_cast<QuicChromiumClientStream*>(stream);
- stream_->SetDelegate(this);
- }
- // callback_ should be non-null in the case of asynchronous
- // rendezvous; i.e. |Try()| returned QUIC_PENDING.
- if (!callback_.is_null()) {
- if (stream) {
- next_state_ = STATE_OPEN;
- stream_net_log_.AddEvent(
- NetLog::TYPE_QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM,
- base::Bind(&NetLogQuicPushStreamCallback, stream_->id(),
- &request_info_->url));
- session_->net_log().AddEvent(
- NetLog::TYPE_QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM,
- base::Bind(&NetLogQuicPushStreamCallback, stream_->id(),
- &request_info_->url));
- DoCallback(OK);
- return;
- }
- // rendezvous has failed so proceed as with a non-push request.
- next_state_ = STATE_REQUEST_STREAM;
- OnIOComplete(OK);
- }
-}
-
-int QuicHttpStream::InitializeStream(const HttpRequestInfo* request_info,
- RequestPriority priority,
- const BoundNetLog& stream_net_log,
- const CompletionCallback& callback) {
- DCHECK(!stream_);
- if (!session_)
- return was_handshake_confirmed_ ? ERR_CONNECTION_CLOSED
- : ERR_QUIC_HANDSHAKE_FAILED;
-
- stream_net_log.AddEvent(
- NetLog::TYPE_HTTP_STREAM_REQUEST_BOUND_TO_QUIC_SESSION,
- session_->net_log().source().ToEventParametersCallback());
-
- stream_net_log_ = stream_net_log;
- request_info_ = request_info;
- request_time_ = base::Time::Now();
- priority_ = priority;
-
- bool success = session_->GetSSLInfo(&ssl_info_);
- DCHECK(success);
- DCHECK(ssl_info_.cert.get());
-
- std::string url(request_info->url.spec());
- QuicClientPromisedInfo* promised =
- session_->push_promise_index()->GetPromised(url);
- if (promised) {
- found_promise_ = true;
- stream_net_log_.AddEvent(
- NetLog::TYPE_QUIC_HTTP_STREAM_PUSH_PROMISE_RENDEZVOUS,
- base::Bind(&NetLogQuicPushStreamCallback, promised->id(),
- &request_info_->url));
- session_->net_log().AddEvent(
- NetLog::TYPE_QUIC_HTTP_STREAM_PUSH_PROMISE_RENDEZVOUS,
- base::Bind(&NetLogQuicPushStreamCallback, promised->id(),
- &request_info_->url));
- return OK;
- }
-
- next_state_ = STATE_REQUEST_STREAM;
- int rv = DoLoop(OK);
- if (rv == ERR_IO_PENDING)
- callback_ = callback;
-
- return rv;
-}
-
-void QuicHttpStream::OnStreamReady(int rv) {
- DCHECK(rv == OK || !stream_);
- if (rv == OK) {
- stream_->SetDelegate(this);
- if (request_info_->load_flags & LOAD_DISABLE_CONNECTION_MIGRATION) {
- stream_->DisableConnectionMigration();
- }
- if (response_info_) {
- // This happens in the case of a asynchronous push rendezvous
- // that ultimately fails (e.g. vary failure). |response_info_|
- // non-null implies that |DoStreamRequest()| was called via
- // |SendRequest()|.
- next_state_ = STATE_SET_REQUEST_PRIORITY;
- rv = DoLoop(OK);
- }
- } else if (!was_handshake_confirmed_) {
- rv = ERR_QUIC_HANDSHAKE_FAILED;
- }
- if (rv != ERR_IO_PENDING) {
- DoCallback(rv);
- }
-}
-
-bool QuicHttpStream::CancelPromiseIfHasBody() {
- if (!request_body_stream_)
- return false;
- // Method type or request with body ineligble for push.
- this->push_handle_->Cancel();
- this->push_handle_ = nullptr;
- next_state_ = STATE_REQUEST_STREAM;
- return true;
-}
-
-int QuicHttpStream::HandlePromise() {
- QuicAsyncStatus push_status = session_->push_promise_index()->Try(
- request_headers_, this, &this->push_handle_);
-
- switch (push_status) {
- case QUIC_FAILURE:
- // Push rendezvous failed.
- next_state_ = STATE_REQUEST_STREAM;
- break;
- case QUIC_SUCCESS:
- next_state_ = STATE_OPEN;
- if (!CancelPromiseIfHasBody()) {
- stream_net_log_.AddEvent(
- NetLog::TYPE_QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM,
- base::Bind(&NetLogQuicPushStreamCallback, stream_->id(),
- &request_info_->url));
- session_->net_log().AddEvent(
- NetLog::TYPE_QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM,
- base::Bind(&NetLogQuicPushStreamCallback, stream_->id(),
- &request_info_->url));
- // Avoid the call to |DoLoop()| below, which would reset
- // next_state_ to STATE_NONE.
- return OK;
- }
-
- break;
- case QUIC_PENDING:
- if (!CancelPromiseIfHasBody()) {
- // Have a promise but the promised stream doesn't exist yet.
- // Still have to do validation before accepting the promised
- // stream for sure.
- return ERR_IO_PENDING;
- }
- break;
- }
- return DoLoop(OK);
-}
-
-int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
- HttpResponseInfo* response,
- const CompletionCallback& callback) {
- CHECK(!request_body_stream_);
- CHECK(!response_info_);
- CHECK(!callback.is_null());
- CHECK(response);
-
- // TODO(rch): remove this once we figure out why channel ID is not being
- // sent when it should be.
- HostPortPair origin = HostPortPair::FromURL(request_info_->url);
- if (origin.Equals(HostPortPair("accounts.google.com", 443)) &&
- request_headers.HasHeader(HttpRequestHeaders::kCookie)) {
- UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.CookieSentToAccountsOverChannelId",
- ssl_info_.channel_id_sent);
- }
- if ((!found_promise_ && !stream_) || !session_) {
- return was_handshake_confirmed_ ? ERR_CONNECTION_CLOSED
- : ERR_QUIC_HANDSHAKE_FAILED;
- }
-
- // Store the serialized request headers.
- CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers, HTTP2,
- /*direct=*/true, &request_headers_);
-
- // Store the request body.
- request_body_stream_ = request_info_->upload_data_stream;
- if (request_body_stream_) {
- // TODO(rch): Can we be more precise about when to allocate
- // raw_request_body_buf_. Removed the following check. DoReadRequestBody()
- // was being called even if we didn't yet allocate raw_request_body_buf_.
- // && (request_body_stream_->size() ||
- // request_body_stream_->is_chunked()))
- // Use 10 packets as the body buffer size to give enough space to
- // help ensure we don't often send out partial packets.
- raw_request_body_buf_ =
- new IOBufferWithSize(static_cast<size_t>(10 * kMaxPacketSize));
- // The request body buffer is empty at first.
- request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_.get(), 0);
- }
-
- // Store the response info.
- response_info_ = response;
-
- int rv;
-
- if (found_promise_) {
- rv = HandlePromise();
- } else {
- next_state_ = STATE_SET_REQUEST_PRIORITY;
- rv = DoLoop(OK);
- }
-
- if (rv == ERR_IO_PENDING)
- callback_ = callback;
-
- return rv > 0 ? OK : rv;
-}
-
-UploadProgress QuicHttpStream::GetUploadProgress() const {
- if (!request_body_stream_)
- return UploadProgress();
-
- return UploadProgress(request_body_stream_->position(),
- request_body_stream_->size());
-}
-
-int QuicHttpStream::ReadResponseHeaders(const CompletionCallback& callback) {
- CHECK(!callback.is_null());
-
- if (stream_ == nullptr)
- return response_status_;
-
- // Check if we already have the response headers. If so, return synchronously.
- if (response_headers_received_)
- return OK;
-
- // Still waiting for the response, return IO_PENDING.
- CHECK(callback_.is_null());
- callback_ = callback;
- return ERR_IO_PENDING;
-}
-
-int QuicHttpStream::ReadResponseBody(IOBuffer* buf,
- int buf_len,
- const CompletionCallback& callback) {
- if (!stream_) {
- // If the stream is already closed, there is no body to read.
- return response_status_;
- }
-
- int rv = ReadAvailableData(buf, buf_len);
- if (rv != ERR_IO_PENDING)
- return rv;
-
- CHECK(callback_.is_null());
- CHECK(!user_buffer_.get());
- CHECK_EQ(0, user_buffer_len_);
-
- callback_ = callback;
- user_buffer_ = buf;
- user_buffer_len_ = buf_len;
- return ERR_IO_PENDING;
-}
-
-void QuicHttpStream::Close(bool not_reusable) {
- // Note: the not_reusable flag has no meaning for SPDY streams.
- if (stream_) {
- stream_->SetDelegate(nullptr);
- stream_->Reset(QUIC_STREAM_CANCELLED);
- ResetStream();
- response_status_ = was_handshake_confirmed_ ? ERR_CONNECTION_CLOSED
- : ERR_QUIC_HANDSHAKE_FAILED;
- }
-}
-
-HttpStream* QuicHttpStream::RenewStreamForAuth() {
- return nullptr;
-}
-
-bool QuicHttpStream::IsResponseBodyComplete() const {
- return next_state_ == STATE_OPEN && !stream_;
-}
-
-bool QuicHttpStream::IsConnectionReused() const {
- // TODO(rch): do something smarter here.
- return stream_ && stream_->id() > 1;
-}
-
-void QuicHttpStream::SetConnectionReused() {
- // QUIC doesn't need an indicator here.
-}
-
-bool QuicHttpStream::CanReuseConnection() const {
- // QUIC streams aren't considered reusable.
- return false;
-}
-
-int64_t QuicHttpStream::GetTotalReceivedBytes() const {
- // TODO(sclittle): Currently, this only includes headers and response body
- // bytes. Change this to include QUIC overhead as well.
- int64_t total_received_bytes = headers_bytes_received_;
- if (stream_) {
- total_received_bytes += stream_->stream_bytes_read();
- } else {
- total_received_bytes += closed_stream_received_bytes_;
- }
- return total_received_bytes;
-}
-
-int64_t QuicHttpStream::GetTotalSentBytes() const {
- // TODO(sclittle): Currently, this only includes request headers and body
- // bytes. Change this to include QUIC overhead as well.
- int64_t total_sent_bytes = headers_bytes_sent_;
- if (stream_) {
- total_sent_bytes += stream_->stream_bytes_written();
- } else {
- total_sent_bytes += closed_stream_sent_bytes_;
- }
- return total_sent_bytes;
-}
-
-bool QuicHttpStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
- // TODO(mmenke): Figure out what to do here.
- return true;
-}
-
-void QuicHttpStream::GetSSLInfo(SSLInfo* ssl_info) {
- *ssl_info = ssl_info_;
-}
-
-void QuicHttpStream::GetSSLCertRequestInfo(
- SSLCertRequestInfo* cert_request_info) {
- DCHECK(stream_);
- NOTIMPLEMENTED();
-}
-
-bool QuicHttpStream::GetRemoteEndpoint(IPEndPoint* endpoint) {
- if (!session_)
- return false;
-
- *endpoint = session_->peer_address();
- return true;
-}
-
-Error QuicHttpStream::GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) {
- return session_->GetTokenBindingSignature(key, out);
-}
-
-void QuicHttpStream::Drain(HttpNetworkSession* session) {
- NOTREACHED();
- Close(false);
- delete this;
-}
-
-void QuicHttpStream::PopulateNetErrorDetails(NetErrorDetails* details) {
- details->connection_info = HttpResponseInfo::CONNECTION_INFO_QUIC1_SPDY3;
- if (was_handshake_confirmed_)
- details->quic_connection_error = quic_connection_error_;
- if (session_) {
- session_->PopulateNetErrorDetails(details);
- } else {
- details->quic_port_migration_detected = port_migration_detected_;
- }
-}
-
-void QuicHttpStream::SetPriority(RequestPriority priority) {
- priority_ = priority;
-}
-
-void QuicHttpStream::OnHeadersAvailable(const SpdyHeaderBlock& headers,
- size_t frame_len) {
- headers_bytes_received_ += frame_len;
-
- // QuicHttpStream ignores trailers.
- if (response_headers_received_) {
- if (stream_->IsDoneReading()) {
- // Close the read side. If the write side has been closed, this will
- // invoke QuicHttpStream::OnClose to reset the stream.
- stream_->OnFinRead();
- }
- return;
- }
-
- int rv = ProcessResponseHeaders(headers);
- if (rv != ERR_IO_PENDING && !callback_.is_null()) {
- DoCallback(rv);
- }
-}
-
-void QuicHttpStream::OnDataAvailable() {
- if (callback_.is_null()) {
- // Data is available, but can't be delivered
- return;
- }
-
- CHECK(user_buffer_.get());
- CHECK_NE(0, user_buffer_len_);
- int rv = ReadAvailableData(user_buffer_.get(), user_buffer_len_);
- if (rv == ERR_IO_PENDING) {
- // This was a spurrious notification. Wait for the next one.
- return;
- }
-
- CHECK(!callback_.is_null());
- user_buffer_ = nullptr;
- user_buffer_len_ = 0;
- DoCallback(rv);
-}
-
-void QuicHttpStream::OnClose() {
- if (stream_->connection_error() != QUIC_NO_ERROR ||
- stream_->stream_error() != QUIC_STREAM_NO_ERROR) {
- response_status_ = was_handshake_confirmed_ ? ERR_QUIC_PROTOCOL_ERROR
- : ERR_QUIC_HANDSHAKE_FAILED;
- } else if (!response_headers_received_) {
- response_status_ = ERR_ABORTED;
- }
-
- quic_connection_error_ = stream_->connection_error();
- ResetStream();
- if (!callback_.is_null()) {
- DoCallback(response_status_);
- }
-}
-
-void QuicHttpStream::OnError(int error) {
- ResetStream();
- response_status_ =
- was_handshake_confirmed_ ? error : ERR_QUIC_HANDSHAKE_FAILED;
- if (!callback_.is_null())
- DoCallback(response_status_);
-}
-
-bool QuicHttpStream::HasSendHeadersComplete() {
- return next_state_ > STATE_SEND_HEADERS_COMPLETE;
-}
-
-void QuicHttpStream::OnCryptoHandshakeConfirmed() {
- was_handshake_confirmed_ = true;
- if (next_state_ == STATE_WAIT_FOR_CONFIRMATION_COMPLETE) {
- int rv = DoLoop(OK);
-
- if (rv != ERR_IO_PENDING && !callback_.is_null()) {
- DoCallback(rv);
- }
- }
-}
-
-void QuicHttpStream::OnSessionClosed(int error, bool port_migration_detected) {
- Close(false);
- session_error_ = error;
- port_migration_detected_ = port_migration_detected;
- session_.reset();
-}
-
-void QuicHttpStream::OnIOComplete(int rv) {
- rv = DoLoop(rv);
-
- if (rv != ERR_IO_PENDING && !callback_.is_null()) {
- DoCallback(rv);
- }
-}
-
-void QuicHttpStream::DoCallback(int rv) {
- CHECK_NE(rv, ERR_IO_PENDING);
- CHECK(!callback_.is_null());
-
- // The client callback can do anything, including destroying this class,
- // so any pending callback must be issued after everything else is done.
- base::ResetAndReturn(&callback_).Run(rv);
-}
-
-int QuicHttpStream::DoLoop(int rv) {
- do {
- State state = next_state_;
- next_state_ = STATE_NONE;
- switch (state) {
- case STATE_REQUEST_STREAM:
- rv = DoStreamRequest();
- break;
- case STATE_SET_REQUEST_PRIORITY:
- rv = DoSetRequestPriority();
- break;
- case STATE_WAIT_FOR_CONFIRMATION:
- CHECK_EQ(OK, rv);
- rv = DoWaitForConfirmation();
- break;
- case STATE_WAIT_FOR_CONFIRMATION_COMPLETE:
- rv = DoWaitForConfirmationComplete(rv);
- break;
- case STATE_SEND_HEADERS:
- CHECK_EQ(OK, rv);
- rv = DoSendHeaders();
- break;
- case STATE_SEND_HEADERS_COMPLETE:
- rv = DoSendHeadersComplete(rv);
- break;
- case STATE_READ_REQUEST_BODY:
- CHECK_EQ(OK, rv);
- rv = DoReadRequestBody();
- break;
- case STATE_READ_REQUEST_BODY_COMPLETE:
- rv = DoReadRequestBodyComplete(rv);
- break;
- case STATE_SEND_BODY:
- CHECK_EQ(OK, rv);
- rv = DoSendBody();
- break;
- case STATE_SEND_BODY_COMPLETE:
- rv = DoSendBodyComplete(rv);
- break;
- case STATE_OPEN:
- CHECK_EQ(OK, rv);
- break;
- default:
- NOTREACHED() << "next_state_: " << next_state_;
- break;
- }
- } while (next_state_ != STATE_NONE && next_state_ != STATE_OPEN &&
- rv != ERR_IO_PENDING);
-
- return rv;
-}
-
-int QuicHttpStream::DoStreamRequest() {
- // TODO(rtenneti) Bug: b/28676259 - a temporary fix until we find out why
- // |session_| could be a nullptr. Delete |null_session| check and histogram if
- // session is never a nullptr.
- bool null_session = session_ == nullptr;
- if (null_session) {
- UMA_HISTOGRAM_BOOLEAN("Net.QuicHttpStream::DoStreamRequest.IsNullSession",
- null_session);
- return was_handshake_confirmed_ ? ERR_CONNECTION_CLOSED
- : ERR_QUIC_HANDSHAKE_FAILED;
- }
- int rv = stream_request_.StartRequest(
- session_, &stream_,
- base::Bind(&QuicHttpStream::OnStreamReady, weak_factory_.GetWeakPtr()));
- if (rv == OK) {
- stream_->SetDelegate(this);
- if (request_info_->load_flags & LOAD_DISABLE_CONNECTION_MIGRATION) {
- stream_->DisableConnectionMigration();
- }
- if (response_info_) {
- next_state_ = STATE_SET_REQUEST_PRIORITY;
- }
- } else if (rv != ERR_IO_PENDING && !was_handshake_confirmed_) {
- rv = ERR_QUIC_HANDSHAKE_FAILED;
- }
- return rv;
-}
-
-int QuicHttpStream::DoSetRequestPriority() {
- // Set priority according to request
- DCHECK(stream_);
- DCHECK(response_info_);
- SpdyPriority priority = ConvertRequestPriorityToQuicPriority(priority_);
- stream_->SetPriority(priority);
- next_state_ = STATE_WAIT_FOR_CONFIRMATION;
- return OK;
-}
-
-int QuicHttpStream::DoWaitForConfirmation() {
- next_state_ = STATE_WAIT_FOR_CONFIRMATION_COMPLETE;
- if (!session_->IsCryptoHandshakeConfirmed() &&
- request_info_->method == "POST") {
- return ERR_IO_PENDING;
- }
- return OK;
-}
-
-int QuicHttpStream::DoWaitForConfirmationComplete(int rv) {
- if (rv < 0)
- return rv;
-
- next_state_ = STATE_SEND_HEADERS;
- return OK;
-}
-
-int QuicHttpStream::DoSendHeaders() {
- if (!stream_)
- return ERR_UNEXPECTED;
-
- // Log the actual request with the URL Request's net log.
- stream_net_log_.AddEvent(
- NetLog::TYPE_HTTP_TRANSACTION_QUIC_SEND_REQUEST_HEADERS,
- base::Bind(&QuicRequestNetLogCallback, stream_->id(), &request_headers_,
- priority_));
- bool has_upload_data = request_body_stream_ != nullptr;
-
- next_state_ = STATE_SEND_HEADERS_COMPLETE;
- size_t frame_len = stream_->WriteHeaders(std::move(request_headers_),
- !has_upload_data, nullptr);
- headers_bytes_sent_ += frame_len;
-
- request_headers_ = SpdyHeaderBlock();
- return static_cast<int>(frame_len);
-}
-
-int QuicHttpStream::DoSendHeadersComplete(int rv) {
- if (rv < 0)
- return rv;
-
- // If the stream is already closed, don't read the request the body.
- if (!stream_)
- return response_status_;
-
- next_state_ = request_body_stream_ ? STATE_READ_REQUEST_BODY : STATE_OPEN;
-
- return OK;
-}
-
-int QuicHttpStream::DoReadRequestBody() {
- next_state_ = STATE_READ_REQUEST_BODY_COMPLETE;
- return request_body_stream_->Read(
- raw_request_body_buf_.get(), raw_request_body_buf_->size(),
- base::Bind(&QuicHttpStream::OnIOComplete, weak_factory_.GetWeakPtr()));
-}
-
-int QuicHttpStream::DoReadRequestBodyComplete(int rv) {
- // If the stream is already closed, don't continue.
- if (!stream_)
- return response_status_;
-
- // |rv| is the result of read from the request body from the last call to
- // DoSendBody().
- if (rv < 0) {
- stream_->SetDelegate(nullptr);
- stream_->Reset(QUIC_ERROR_PROCESSING_STREAM);
- ResetStream();
- return rv;
- }
-
- request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_.get(), rv);
- if (rv == 0) { // Reached the end.
- DCHECK(request_body_stream_->IsEOF());
- }
-
- next_state_ = STATE_SEND_BODY;
- return OK;
-}
-
-int QuicHttpStream::DoSendBody() {
- if (!stream_)
- return ERR_UNEXPECTED;
-
- CHECK(request_body_stream_);
- CHECK(request_body_buf_.get());
- const bool eof = request_body_stream_->IsEOF();
- int len = request_body_buf_->BytesRemaining();
- if (len > 0 || eof) {
- next_state_ = STATE_SEND_BODY_COMPLETE;
- base::StringPiece data(request_body_buf_->data(), len);
- return stream_->WriteStreamData(
- data, eof,
- base::Bind(&QuicHttpStream::OnIOComplete, weak_factory_.GetWeakPtr()));
- }
-
- next_state_ = STATE_OPEN;
- return OK;
-}
-
-int QuicHttpStream::DoSendBodyComplete(int rv) {
- if (rv < 0)
- return rv;
-
- // If the stream is already closed, don't continue.
- if (!stream_)
- return response_status_;
-
- request_body_buf_->DidConsume(request_body_buf_->BytesRemaining());
-
- if (!request_body_stream_->IsEOF()) {
- next_state_ = STATE_READ_REQUEST_BODY;
- return OK;
- }
-
- next_state_ = STATE_OPEN;
- return OK;
-}
-
-int QuicHttpStream::ProcessResponseHeaders(const SpdyHeaderBlock& headers) {
- if (!SpdyHeadersToHttpResponse(headers, HTTP2, response_info_)) {
- DLOG(WARNING) << "Invalid headers";
- return ERR_QUIC_PROTOCOL_ERROR;
- }
- // Put the peer's IP address and port into the response.
- IPEndPoint address = session_->peer_address();
- response_info_->socket_address = HostPortPair::FromIPEndPoint(address);
- response_info_->connection_info =
- HttpResponseInfo::CONNECTION_INFO_QUIC1_SPDY3;
- response_info_->vary_data.Init(*request_info_,
- *response_info_->headers.get());
- response_info_->was_npn_negotiated = true;
- response_info_->npn_negotiated_protocol = "quic/1+spdy/3";
- response_info_->response_time = base::Time::Now();
- response_info_->request_time = request_time_;
- response_headers_received_ = true;
-
- return OK;
-}
-
-int QuicHttpStream::ReadAvailableData(IOBuffer* buf, int buf_len) {
- int rv = stream_->Read(buf, buf_len);
- // TODO(rtenneti): Temporary fix for crbug.com/585591. Added a check for null
- // |stream_| to fix crash bug. Delete |stream_| check and histogram after fix
- // is merged.
- bool null_stream = stream_ == nullptr;
- UMA_HISTOGRAM_BOOLEAN("Net.QuicReadAvailableData.NullStream", null_stream);
- if (null_stream)
- return rv;
- if (stream_->IsDoneReading()) {
- stream_->SetDelegate(nullptr);
- stream_->OnFinRead();
- ResetStream();
- }
- return rv;
-}
-
-void QuicHttpStream::ResetStream() {
- if (push_handle_) {
- push_handle_->Cancel();
- push_handle_ = nullptr;
- }
- if (!stream_)
- return;
- closed_stream_received_bytes_ = stream_->stream_bytes_read();
- closed_stream_sent_bytes_ = stream_->stream_bytes_written();
- stream_ = nullptr;
-
- // If |request_body_stream_| is non-NULL, Reset it, to abort any in progress
- // read.
- if (request_body_stream_)
- request_body_stream_->Reset();
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_http_stream.h b/chromium/net/quic/quic_http_stream.h
deleted file mode 100644
index 25eb3348844..00000000000
--- a/chromium/net/quic/quic_http_stream.h
+++ /dev/null
@@ -1,217 +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.
-
-#ifndef NET_QUIC_QUIC_HTTP_STREAM_H_
-#define NET_QUIC_QUIC_HTTP_STREAM_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <list>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "net/base/io_buffer.h"
-#include "net/http/http_stream.h"
-#include "net/quic/quic_chromium_client_session.h"
-#include "net/quic/quic_chromium_client_stream.h"
-#include "net/quic/quic_client_push_promise_index.h"
-
-namespace net {
-
-namespace test {
-class QuicHttpStreamPeer;
-} // namespace test
-
-// The QuicHttpStream is a QUIC-specific HttpStream subclass. It holds a
-// non-owning pointer to a QuicChromiumClientStream which it uses to
-// send and receive data.
-class NET_EXPORT_PRIVATE QuicHttpStream
- : public QuicChromiumClientSession::Observer,
- public QuicChromiumClientStream::Delegate,
- public QuicClientPushPromiseIndex::Delegate,
- public HttpStream {
- public:
- explicit QuicHttpStream(
- const base::WeakPtr<QuicChromiumClientSession>& session);
-
- ~QuicHttpStream() override;
-
- // HttpStream implementation.
- int InitializeStream(const HttpRequestInfo* request_info,
- RequestPriority priority,
- const BoundNetLog& net_log,
- const CompletionCallback& callback) override;
- int SendRequest(const HttpRequestHeaders& request_headers,
- HttpResponseInfo* response,
- const CompletionCallback& callback) override;
- UploadProgress GetUploadProgress() const override;
- int ReadResponseHeaders(const CompletionCallback& callback) override;
- int ReadResponseBody(IOBuffer* buf,
- int buf_len,
- const CompletionCallback& callback) override;
- void Close(bool not_reusable) override;
- HttpStream* RenewStreamForAuth() override;
- bool IsResponseBodyComplete() const override;
- bool IsConnectionReused() const override;
- void SetConnectionReused() override;
- bool CanReuseConnection() const override;
- int64_t GetTotalReceivedBytes() const override;
- int64_t GetTotalSentBytes() const override;
- bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
- void GetSSLInfo(SSLInfo* ssl_info) override;
- void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
- bool GetRemoteEndpoint(IPEndPoint* endpoint) override;
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) override;
- void Drain(HttpNetworkSession* session) override;
- void PopulateNetErrorDetails(NetErrorDetails* details) override;
- void SetPriority(RequestPriority priority) override;
-
- // QuicChromiumClientStream::Delegate implementation
- void OnHeadersAvailable(const SpdyHeaderBlock& headers,
- size_t frame_len) override;
- void OnDataAvailable() override;
- void OnClose() override;
- void OnError(int error) override;
- bool HasSendHeadersComplete() override;
-
- // QuicChromiumClientSession::Observer implementation
- void OnCryptoHandshakeConfirmed() override;
- void OnSessionClosed(int error, bool port_migration_detected) override;
-
- // QuicClientPushPromiseIndex::Delegate implementation
- bool CheckVary(const SpdyHeaderBlock& client_request,
- const SpdyHeaderBlock& promise_request,
- const SpdyHeaderBlock& promise_response) override;
- void OnRendezvousResult(QuicSpdyStream* stream) override;
-
- private:
- friend class test::QuicHttpStreamPeer;
-
- enum State {
- STATE_NONE,
- STATE_REQUEST_STREAM,
- STATE_SET_REQUEST_PRIORITY,
- STATE_WAIT_FOR_CONFIRMATION,
- STATE_WAIT_FOR_CONFIRMATION_COMPLETE,
- STATE_SEND_HEADERS,
- STATE_SEND_HEADERS_COMPLETE,
- STATE_READ_REQUEST_BODY,
- STATE_READ_REQUEST_BODY_COMPLETE,
- STATE_SEND_BODY,
- STATE_SEND_BODY_COMPLETE,
- STATE_OPEN,
- };
-
- void OnStreamReady(int rv);
- void OnIOComplete(int rv);
- void DoCallback(int rv);
-
- int DoLoop(int rv);
- int DoStreamRequest();
- int DoSetRequestPriority();
- int DoWaitForConfirmation();
- int DoWaitForConfirmationComplete(int rv);
- int DoSendHeaders();
- int DoSendHeadersComplete(int rv);
- int DoReadRequestBody();
- int DoReadRequestBodyComplete(int rv);
- int DoSendBody();
- int DoSendBodyComplete(int rv);
-
- int ProcessResponseHeaders(const SpdyHeaderBlock& headers);
-
- int ReadAvailableData(IOBuffer* buf, int buf_len);
- void EnterStateSendHeaders();
- int HandlePromise();
-
- void ResetStream();
- bool CancelPromiseIfHasBody();
-
- State next_state_;
-
- base::WeakPtr<QuicChromiumClientSession> session_;
- int session_error_; // Error code from the connection shutdown.
- bool was_handshake_confirmed_; // True if the crypto handshake succeeded.
- QuicChromiumClientSession::StreamRequest stream_request_;
- QuicChromiumClientStream* stream_; // Non-owning.
-
- // The following three fields are all owned by the caller and must
- // outlive this object, according to the HttpStream contract.
-
- // The request to send.
- const HttpRequestInfo* request_info_;
- // The request body to send, if any, owned by the caller.
- UploadDataStream* request_body_stream_;
- // Time the request was issued.
- base::Time request_time_;
- // The priority of the request.
- RequestPriority priority_;
- // |response_info_| is the HTTP response data object which is filled in
- // when a the response headers are read. It is not owned by this stream.
- HttpResponseInfo* response_info_;
- // Because response data is buffered, also buffer the response status if the
- // stream is explicitly closed via OnError or OnClose with an error.
- // Once all buffered data has been returned, this will be used as the final
- // response.
- int response_status_;
-
- // Serialized request headers.
- SpdyHeaderBlock request_headers_;
-
- bool response_headers_received_;
-
- // Serialized HTTP request.
- std::string request_;
-
- // Number of bytes received by the headers stream on behalf of this stream.
- int64_t headers_bytes_received_;
- // Number of bytes sent by the headers stream on behalf of this stream.
- int64_t headers_bytes_sent_;
-
- // Number of bytes received when the stream was closed.
- int64_t closed_stream_received_bytes_;
- // Number of bytes sent when the stream was closed.
- int64_t closed_stream_sent_bytes_;
-
- // The caller's callback to be used for asynchronous operations.
- CompletionCallback callback_;
-
- // Caller provided buffer for the ReadResponseBody() response.
- scoped_refptr<IOBuffer> user_buffer_;
- int user_buffer_len_;
-
- // Temporary buffer used to read the request body from UploadDataStream.
- scoped_refptr<IOBufferWithSize> raw_request_body_buf_;
- // Wraps raw_request_body_buf_ to read the remaining data progressively.
- scoped_refptr<DrainableIOBuffer> request_body_buf_;
-
- BoundNetLog stream_net_log_;
-
- QuicErrorCode quic_connection_error_;
-
- // SSLInfo from the underlying QuicSession.
- SSLInfo ssl_info_;
-
- // True when this stream receives a go away from server due to port migration.
- bool port_migration_detected_;
-
- bool found_promise_;
- // |QuicClientPromisedInfo| owns this. It will be set when |Try()|
- // is asynchronous, i.e. it returned QUIC_PENDING, and remains valid
- // until |OnRendezvouResult()| fires or |push_handle_->Cancel()| is
- // invoked.
- QuicClientPushPromiseIndex::TryHandle* push_handle_;
-
- base::WeakPtrFactory<QuicHttpStream> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicHttpStream);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_HTTP_STREAM_H_
diff --git a/chromium/net/quic/quic_http_stream_test.cc b/chromium/net/quic/quic_http_stream_test.cc
deleted file mode 100644
index 26f16eef711..00000000000
--- a/chromium/net/quic/quic_http_stream_test.cc
+++ /dev/null
@@ -1,1841 +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/quic_http_stream.h"
-
-#include <stdint.h>
-
-#include <memory>
-#include <utility>
-
-#include "base/memory/ptr_util.h"
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "net/base/chunked_upload_data_stream.h"
-#include "net/base/elements_upload_data_stream.h"
-#include "net/base/net_errors.h"
-#include "net/base/test_completion_callback.h"
-#include "net/base/upload_bytes_element_reader.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/transport_security_state.h"
-#include "net/log/test_net_log.h"
-#include "net/log/test_net_log_util.h"
-#include "net/quic/congestion_control/send_algorithm_interface.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/crypto/quic_server_info.h"
-#include "net/quic/quic_chromium_alarm_factory.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_chromium_packet_reader.h"
-#include "net/quic/quic_chromium_packet_writer.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_http_utils.h"
-#include "net/quic/quic_write_blocked_list.h"
-#include "net/quic/spdy_utils.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
-#include "net/quic/test_tools/mock_random.h"
-#include "net/quic/test_tools/quic_connection_peer.h"
-#include "net/quic/test_tools/quic_test_packet_maker.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/quic/test_tools/test_task_runner.h"
-#include "net/socket/socket_performance_watcher.h"
-#include "net/socket/socket_test_util.h"
-#include "net/spdy/spdy_frame_builder.h"
-#include "net/spdy/spdy_framer.h"
-#include "net/spdy/spdy_http_utils.h"
-#include "net/spdy/spdy_protocol.h"
-#include "net/test/cert_test_util.h"
-#include "net/test/test_data_directory.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::string;
-using testing::_;
-using testing::AnyNumber;
-using testing::Return;
-
-namespace net {
-namespace test {
-namespace {
-
-const char kUploadData[] = "Really nifty data!";
-const char kDefaultServerHostName[] = "www.example.org";
-const uint16_t kDefaultServerPort = 80;
-
-class TestQuicConnection : public QuicConnection {
- public:
- TestQuicConnection(const QuicVersionVector& versions,
- QuicConnectionId connection_id,
- IPEndPoint address,
- QuicChromiumConnectionHelper* helper,
- QuicChromiumAlarmFactory* alarm_factory,
- QuicPacketWriter* writer)
- : QuicConnection(connection_id,
- address,
- helper,
- alarm_factory,
- writer,
- true /* owns_writer */,
- Perspective::IS_CLIENT,
- versions) {}
-
- void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) {
- QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm);
- }
-};
-
-// Subclass of QuicHttpStream that closes itself when the first piece of data
-// is received.
-class AutoClosingStream : public QuicHttpStream {
- public:
- explicit AutoClosingStream(
- const base::WeakPtr<QuicChromiumClientSession>& session)
- : QuicHttpStream(session) {}
-
- void OnHeadersAvailable(const SpdyHeaderBlock& headers,
- size_t frame_len) override {
- Close(false);
- }
-
- void OnDataAvailable() override { Close(false); }
-};
-
-// UploadDataStream that always returns errors on data read.
-class ReadErrorUploadDataStream : public UploadDataStream {
- public:
- enum class FailureMode { SYNC, ASYNC };
-
- explicit ReadErrorUploadDataStream(FailureMode mode)
- : UploadDataStream(true, 0), async_(mode), weak_factory_(this) {}
- ~ReadErrorUploadDataStream() override {}
-
- private:
- void CompleteRead() { UploadDataStream::OnReadCompleted(ERR_FAILED); }
-
- // UploadDataStream implementation:
- int InitInternal() override { return OK; }
-
- int ReadInternal(IOBuffer* buf, int buf_len) override {
- if (async_ == FailureMode::ASYNC) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&ReadErrorUploadDataStream::CompleteRead,
- weak_factory_.GetWeakPtr()));
- return ERR_IO_PENDING;
- }
- return ERR_FAILED;
- }
-
- void ResetInternal() override {}
-
- const FailureMode async_;
-
- base::WeakPtrFactory<ReadErrorUploadDataStream> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ReadErrorUploadDataStream);
-};
-
-} // namespace
-
-class QuicHttpStreamPeer {
- public:
- static QuicChromiumClientStream* GetQuicChromiumClientStream(
- QuicHttpStream* stream) {
- return stream->stream_;
- }
-
- static bool WasHandshakeConfirmed(QuicHttpStream* stream) {
- return stream->was_handshake_confirmed_;
- }
-
- static void SetHandshakeConfirmed(QuicHttpStream* stream, bool confirmed) {
- stream->was_handshake_confirmed_ = confirmed;
- }
-};
-
-class QuicHttpStreamTest : public ::testing::TestWithParam<QuicVersion> {
- protected:
- static const bool kFin = true;
- static const bool kIncludeVersion = true;
- static const bool kIncludeCongestionFeedback = true;
-
- // Holds a packet to be written to the wire, and the IO mode that should
- // be used by the mock socket when performing the write.
- struct PacketToWrite {
- PacketToWrite(IoMode mode, QuicReceivedPacket* packet)
- : mode(mode), packet(packet) {}
- PacketToWrite(IoMode mode, int rv) : mode(mode), packet(nullptr), rv(rv) {}
- IoMode mode;
- QuicReceivedPacket* packet;
- int rv;
- };
-
- QuicHttpStreamTest()
- : use_closing_stream_(false),
- crypto_config_(CryptoTestUtils::ProofVerifierForTesting()),
- read_buffer_(new IOBufferWithSize(4096)),
- promise_id_(kServerDataStreamId1),
- stream_id_(kClientDataStreamId1),
- connection_id_(2),
- client_maker_(GetParam(),
- connection_id_,
- &clock_,
- kDefaultServerHostName,
- Perspective::IS_CLIENT),
- server_maker_(GetParam(),
- connection_id_,
- &clock_,
- kDefaultServerHostName,
- Perspective::IS_SERVER),
- random_generator_(0),
- response_offset_(0) {
- IPAddress ip(192, 0, 2, 33);
- peer_addr_ = IPEndPoint(ip, 443);
- self_addr_ = IPEndPoint(ip, 8435);
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
- }
-
- ~QuicHttpStreamTest() {
- session_->CloseSessionOnError(ERR_ABORTED, QUIC_INTERNAL_ERROR);
- for (size_t i = 0; i < writes_.size(); i++) {
- delete writes_[i].packet;
- }
- }
-
- // Adds a packet to the list of expected writes.
- void AddWrite(std::unique_ptr<QuicReceivedPacket> packet) {
- writes_.push_back(PacketToWrite(SYNCHRONOUS, packet.release()));
- }
-
- void AddWrite(IoMode mode, int rv) {
- writes_.push_back(PacketToWrite(mode, rv));
- }
-
- // Returns the packet to be written at position |pos|.
- QuicReceivedPacket* GetWrite(size_t pos) { return writes_[pos].packet; }
-
- bool AtEof() {
- return socket_data_->AllReadDataConsumed() &&
- socket_data_->AllWriteDataConsumed();
- }
-
- void ProcessPacket(std::unique_ptr<QuicReceivedPacket> packet) {
- connection_->ProcessUdpPacket(self_addr_, peer_addr_, *packet);
- }
-
- // Configures the test fixture to use the list of expected writes.
- void Initialize() {
- mock_writes_.reset(new MockWrite[writes_.size()]);
- for (size_t i = 0; i < writes_.size(); i++) {
- if (writes_[i].packet == nullptr) {
- mock_writes_[i] = MockWrite(writes_[i].mode, writes_[i].rv, i);
- } else {
- mock_writes_[i] = MockWrite(writes_[i].mode, writes_[i].packet->data(),
- writes_[i].packet->length());
- }
- }
-
- socket_data_.reset(new StaticSocketDataProvider(
- nullptr, 0, mock_writes_.get(), writes_.size()));
-
- std::unique_ptr<MockUDPClientSocket> socket(new MockUDPClientSocket(
- socket_data_.get(), net_log_.bound().net_log()));
- socket->Connect(peer_addr_);
- runner_ = new TestTaskRunner(&clock_);
- send_algorithm_ = new MockSendAlgorithm();
- EXPECT_CALL(*send_algorithm_, InRecovery()).WillRepeatedly(Return(false));
- EXPECT_CALL(*send_algorithm_, InSlowStart()).WillRepeatedly(Return(false));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
- .WillRepeatedly(Return(true));
- EXPECT_CALL(*send_algorithm_, RetransmissionDelay())
- .WillRepeatedly(Return(QuicTime::Delta::Zero()));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillRepeatedly(Return(kMaxPacketSize));
- EXPECT_CALL(*send_algorithm_, PacingRate(_))
- .WillRepeatedly(Return(QuicBandwidth::Zero()));
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillRepeatedly(Return(QuicTime::Delta::Zero()));
- EXPECT_CALL(*send_algorithm_, BandwidthEstimate())
- .WillRepeatedly(Return(QuicBandwidth::Zero()));
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
- helper_.reset(
- new QuicChromiumConnectionHelper(&clock_, &random_generator_));
- alarm_factory_.reset(new QuicChromiumAlarmFactory(runner_.get(), &clock_));
-
- connection_ =
- new TestQuicConnection(SupportedVersions(GetParam()), connection_id_,
- peer_addr_, helper_.get(), alarm_factory_.get(),
- new QuicChromiumPacketWriter(socket.get()));
- connection_->set_visitor(&visitor_);
- connection_->SetSendAlgorithm(send_algorithm_);
-
- // Load a certificate that is valid for *.example.org
- scoped_refptr<X509Certificate> test_cert(
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
- EXPECT_TRUE(test_cert.get());
-
- verify_details_.cert_verify_result.verified_cert = test_cert;
- verify_details_.cert_verify_result.is_issued_by_known_root = true;
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details_);
-
- session_.reset(new QuicChromiumClientSession(
- connection_, std::move(socket),
- /*stream_factory=*/nullptr, &crypto_client_stream_factory_, &clock_,
- &transport_security_state_,
- base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)),
- QuicServerId(kDefaultServerHostName, kDefaultServerPort,
- PRIVACY_MODE_DISABLED),
- kQuicYieldAfterPacketsRead,
- QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds),
- /*cert_verify_flags=*/0, DefaultQuicConfig(), &crypto_config_,
- "CONNECTION_UNKNOWN", base::TimeTicks::Now(), &push_promise_index_,
- base::ThreadTaskRunnerHandle::Get().get(),
- /*socket_performance_watcher=*/nullptr, net_log_.bound().net_log()));
- session_->Initialize();
- session_->GetCryptoStream()->CryptoConnect();
- EXPECT_TRUE(session_->IsCryptoHandshakeConfirmed());
- stream_.reset(use_closing_stream_
- ? new AutoClosingStream(session_->GetWeakPtr())
- : new QuicHttpStream(session_->GetWeakPtr()));
-
- promised_stream_.reset(use_closing_stream_
- ? new AutoClosingStream(session_->GetWeakPtr())
- : new QuicHttpStream(session_->GetWeakPtr()));
-
- push_promise_[":path"] = "/bar";
- push_promise_[":authority"] = "www.example.org";
- push_promise_[":version"] = "HTTP/1.1";
- push_promise_[":method"] = "GET";
- push_promise_[":scheme"] = "https";
-
- promised_response_[":status"] = "200 OK";
- promised_response_[":version"] = "HTTP/1.1";
- promised_response_["content-type"] = "text/plain";
-
- promise_url_ = SpdyUtils::GetUrlFromHeaderBlock(push_promise_);
-
- serialized_push_promise_ =
- SpdyUtils::SerializeUncompressedHeaders(push_promise_);
- }
-
- void SetRequest(const string& method,
- const string& path,
- RequestPriority priority) {
- request_headers_ = client_maker_.GetRequestHeaders(method, "http", path);
- }
-
- void SetResponse(const string& status, const string& body) {
- response_headers_ = server_maker_.GetResponseHeaders(status);
- response_data_ = body;
- }
-
- std::unique_ptr<QuicReceivedPacket> InnerConstructDataPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool should_include_version,
- bool fin,
- QuicStreamOffset offset,
- base::StringPiece data,
- QuicTestPacketMaker* maker) {
- return maker->MakeDataPacket(packet_number, stream_id,
- should_include_version, fin, offset, data);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructClientDataPacket(
- QuicPacketNumber packet_number,
- bool should_include_version,
- bool fin,
- QuicStreamOffset offset,
- base::StringPiece data) {
- return InnerConstructDataPacket(packet_number, stream_id_,
- should_include_version, fin, offset, data,
- &client_maker_);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructServerDataPacket(
- QuicPacketNumber packet_number,
- bool should_include_version,
- bool fin,
- QuicStreamOffset offset,
- base::StringPiece data) {
- return InnerConstructDataPacket(packet_number, stream_id_,
- should_include_version, fin, offset, data,
- &server_maker_);
- }
-
- std::unique_ptr<QuicReceivedPacket> InnerConstructRequestHeadersPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool should_include_version,
- bool fin,
- RequestPriority request_priority,
- size_t* spdy_headers_frame_length) {
- 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);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructRequestHeadersPacket(
- QuicPacketNumber packet_number,
- bool fin,
- RequestPriority request_priority,
- size_t* spdy_headers_frame_length) {
- return InnerConstructRequestHeadersPacket(
- packet_number, stream_id_, kIncludeVersion, fin, request_priority,
- spdy_headers_frame_length);
- }
-
- std::unique_ptr<QuicReceivedPacket> InnerConstructResponseHeadersPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool fin,
- size_t* spdy_headers_frame_length) {
- return server_maker_.MakeResponseHeadersPacket(
- packet_number, stream_id, !kIncludeVersion, fin,
- std::move(response_headers_), spdy_headers_frame_length,
- &response_offset_);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructResponseHeadersPacket(
- QuicPacketNumber packet_number,
- bool fin,
- size_t* spdy_headers_frame_length) {
- return InnerConstructResponseHeadersPacket(packet_number, stream_id_, fin,
- spdy_headers_frame_length);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructResponseHeadersPacketWithOffset(
- QuicPacketNumber packet_number,
- bool fin,
- size_t* spdy_headers_frame_length,
- QuicStreamOffset* offset) {
- return server_maker_.MakeResponseHeadersPacket(
- packet_number, stream_id_, !kIncludeVersion, fin,
- std::move(response_headers_), spdy_headers_frame_length, offset);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructResponseTrailersPacket(
- QuicPacketNumber packet_number,
- bool fin,
- SpdyHeaderBlock trailers,
- size_t* spdy_headers_frame_length,
- QuicStreamOffset* offset) {
- return server_maker_.MakeResponseHeadersPacket(
- packet_number, stream_id_, !kIncludeVersion, fin, std::move(trailers),
- spdy_headers_frame_length, offset);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructClientRstStreamPacket(
- QuicPacketNumber packet_number) {
- return client_maker_.MakeRstPacket(
- packet_number, true, stream_id_,
- AdjustErrorForVersion(QUIC_RST_ACKNOWLEDGEMENT, GetParam()));
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructClientRstStreamCancelledPacket(
- QuicPacketNumber packet_number) {
- return client_maker_.MakeRstPacket(packet_number, !kIncludeVersion,
- stream_id_, QUIC_STREAM_CANCELLED);
- }
-
- std::unique_ptr<QuicReceivedPacket>
- ConstructClientRstStreamVaryMismatchPacket(QuicPacketNumber packet_number) {
- return client_maker_.MakeRstPacket(packet_number, !kIncludeVersion,
- promise_id_, QUIC_PROMISE_VARY_MISMATCH);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructAckAndRstStreamPacket(
- QuicPacketNumber packet_number,
- QuicPacketNumber largest_received,
- QuicPacketNumber ack_least_unacked,
- QuicPacketNumber stop_least_unacked) {
- return client_maker_.MakeAckAndRstPacket(
- packet_number, !kIncludeVersion, stream_id_, QUIC_STREAM_CANCELLED,
- largest_received, ack_least_unacked, stop_least_unacked,
- !kIncludeCongestionFeedback);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructClientRstStreamErrorPacket(
- QuicPacketNumber packet_number,
- bool include_version) {
- return client_maker_.MakeRstPacket(packet_number, include_version,
- stream_id_,
- QUIC_ERROR_PROCESSING_STREAM);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructAckAndRstStreamPacket(
- QuicPacketNumber packet_number) {
- return ConstructAckAndRstStreamPacket(packet_number, 2, 1, 1);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructClientAckPacket(
- QuicPacketNumber packet_number,
- QuicPacketNumber largest_received,
- QuicPacketNumber least_unacked) {
- return client_maker_.MakeAckPacket(packet_number, largest_received,
- least_unacked,
- !kIncludeCongestionFeedback);
- }
-
- std::unique_ptr<QuicReceivedPacket> ConstructServerAckPacket(
- QuicPacketNumber packet_number,
- QuicPacketNumber largest_received,
- QuicPacketNumber least_unacked) {
- return server_maker_.MakeAckPacket(packet_number, largest_received,
- least_unacked,
- !kIncludeCongestionFeedback);
- }
-
- void ReceivePromise(QuicStreamId id) {
- QuicChromiumClientStream* stream =
- QuicHttpStreamPeer::GetQuicChromiumClientStream(stream_.get());
- stream->OnStreamHeaders(serialized_push_promise_);
-
- stream->OnPromiseHeadersComplete(id, serialized_push_promise_.size());
- }
-
- BoundTestNetLog net_log_;
- bool use_closing_stream_;
- MockSendAlgorithm* send_algorithm_;
- scoped_refptr<TestTaskRunner> runner_;
- std::unique_ptr<MockWrite[]> mock_writes_;
- MockClock clock_;
- TestQuicConnection* connection_;
- std::unique_ptr<QuicChromiumConnectionHelper> helper_;
- std::unique_ptr<QuicChromiumAlarmFactory> alarm_factory_;
- testing::StrictMock<MockQuicConnectionVisitor> visitor_;
- std::unique_ptr<QuicHttpStream> stream_;
- TransportSecurityState transport_security_state_;
- std::unique_ptr<QuicChromiumClientSession> session_;
- QuicCryptoClientConfig crypto_config_;
- TestCompletionCallback callback_;
- HttpRequestInfo request_;
- HttpRequestHeaders headers_;
- HttpResponseInfo response_;
- scoped_refptr<IOBufferWithSize> read_buffer_;
- SpdyHeaderBlock request_headers_;
- SpdyHeaderBlock response_headers_;
- string request_data_;
- string response_data_;
- QuicClientPushPromiseIndex push_promise_index_;
-
- // For server push testing
- std::unique_ptr<QuicHttpStream> promised_stream_;
- SpdyHeaderBlock push_promise_;
- SpdyHeaderBlock promised_response_;
- const QuicStreamId promise_id_;
- string promise_url_;
- string serialized_push_promise_;
- const QuicStreamId stream_id_;
-
- const QuicConnectionId connection_id_;
- QuicTestPacketMaker client_maker_;
- QuicTestPacketMaker server_maker_;
- IPEndPoint self_addr_;
- IPEndPoint peer_addr_;
- MockRandom random_generator_;
- ProofVerifyDetailsChromium verify_details_;
- MockCryptoClientStreamFactory crypto_client_stream_factory_;
- std::unique_ptr<StaticSocketDataProvider> socket_data_;
- std::vector<PacketToWrite> writes_;
- QuicStreamOffset response_offset_;
-};
-
-INSTANTIATE_TEST_CASE_P(Version,
- QuicHttpStreamTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
-
-TEST_P(QuicHttpStreamTest, RenewStreamForAuth) {
- Initialize();
- EXPECT_EQ(nullptr, stream_->RenewStreamForAuth());
-}
-
-TEST_P(QuicHttpStreamTest, CanReuseConnection) {
- Initialize();
- EXPECT_FALSE(stream_->CanReuseConnection());
-}
-
-TEST_P(QuicHttpStreamTest, DisableConnectionMigrationForStream) {
- request_.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION;
- Initialize();
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
- QuicChromiumClientStream* client_stream =
- QuicHttpStreamPeer::GetQuicChromiumClientStream(stream_.get());
- EXPECT_FALSE(client_stream->can_migrate());
-}
-
-TEST_P(QuicHttpStreamTest, GetRequest) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- size_t spdy_request_header_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
- &spdy_request_header_frame_length));
- Initialize();
-
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
- EXPECT_EQ(OK,
- stream_->SendRequest(headers_, &response_, callback_.callback()));
-
- // Ack the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- EXPECT_EQ(ERR_IO_PENDING, stream_->ReadResponseHeaders(callback_.callback()));
-
- SetResponse("404 Not Found", string());
- size_t spdy_response_header_frame_length;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, kFin, &spdy_response_header_frame_length));
-
- // Now that the headers have been processed, the callback will return.
- EXPECT_EQ(OK, callback_.WaitForResult());
- ASSERT_TRUE(response_.headers.get());
- EXPECT_EQ(404, response_.headers->response_code());
- EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
- EXPECT_FALSE(response_.response_time.is_null());
- EXPECT_FALSE(response_.request_time.is_null());
-
- // There is no body, so this should return immediately.
- EXPECT_EQ(0,
- stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
- callback_.callback()));
- EXPECT_TRUE(stream_->IsResponseBodyComplete());
- EXPECT_TRUE(AtEof());
-
- // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
- // headers and payload.
- EXPECT_EQ(static_cast<int64_t>(spdy_request_header_frame_length),
- stream_->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_header_frame_length),
- stream_->GetTotalReceivedBytes());
-}
-
-// QuicHttpStream does not currently support trailers. It should ignore
-// trailers upon receiving them.
-TEST_P(QuicHttpStreamTest, GetRequestWithTrailers) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- size_t spdy_request_header_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
- &spdy_request_header_frame_length));
- AddWrite(ConstructClientAckPacket(2, 3, 1)); // Ack the data packet.
-
- Initialize();
-
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
-
- EXPECT_EQ(OK,
- stream_->SendRequest(headers_, &response_, callback_.callback()));
- // Ack the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- EXPECT_EQ(ERR_IO_PENDING, stream_->ReadResponseHeaders(callback_.callback()));
-
- SetResponse("200 OK", string());
-
- // Send the response headers.
- size_t spdy_response_header_frame_length;
- QuicStreamOffset offset = 0;
- ProcessPacket(ConstructResponseHeadersPacketWithOffset(
- 2, !kFin, &spdy_response_header_frame_length, &offset));
- // Now that the headers have been processed, the callback will return.
- EXPECT_EQ(OK, callback_.WaitForResult());
- ASSERT_TRUE(response_.headers.get());
- EXPECT_EQ(200, response_.headers->response_code());
- EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
- EXPECT_FALSE(response_.response_time.is_null());
- EXPECT_FALSE(response_.request_time.is_null());
-
- // Send the response body.
- const char kResponseBody[] = "Hello world!";
- ProcessPacket(
- ConstructServerDataPacket(3, false, !kFin, /*offset=*/0, kResponseBody));
- SpdyHeaderBlock trailers;
- size_t spdy_trailers_frame_length;
- trailers["foo"] = "bar";
- trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
- ProcessPacket(ConstructResponseTrailersPacket(
- 4, kFin, std::move(trailers), &spdy_trailers_frame_length, &offset));
-
- // Make sure trailers are processed.
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(static_cast<int>(strlen(kResponseBody)),
- stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
- callback_.callback()));
- EXPECT_TRUE(stream_->IsResponseBodyComplete());
-
- EXPECT_EQ(OK,
- stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
- callback_.callback()));
-
- EXPECT_TRUE(stream_->IsResponseBodyComplete());
- EXPECT_TRUE(AtEof());
-
- // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
- // headers and payload.
- EXPECT_EQ(static_cast<int64_t>(spdy_request_header_frame_length),
- stream_->GetTotalSentBytes());
- EXPECT_EQ(
- static_cast<int64_t>(spdy_response_header_frame_length +
- strlen(kResponseBody) + +spdy_trailers_frame_length),
- stream_->GetTotalReceivedBytes());
- // Check that NetLog was filled as expected.
- TestNetLogEntry::List entries;
- net_log_.GetEntries(&entries);
- size_t pos = ExpectLogContainsSomewhere(
- entries, /*min_offset=*/0,
- NetLog::TYPE_QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
- NetLog::PHASE_NONE);
- pos = ExpectLogContainsSomewhere(
- entries, /*min_offset=*/pos,
- NetLog::TYPE_QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
- NetLog::PHASE_NONE);
- ExpectLogContainsSomewhere(
- entries, /*min_offset=*/pos,
- NetLog::TYPE_QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
- NetLog::PHASE_NONE);
-}
-
-// Regression test for http://crbug.com/288128
-TEST_P(QuicHttpStreamTest, GetRequestLargeResponse) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- Initialize();
-
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
- EXPECT_EQ(OK,
- stream_->SendRequest(headers_, &response_, callback_.callback()));
-
- // Ack the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- EXPECT_EQ(ERR_IO_PENDING, stream_->ReadResponseHeaders(callback_.callback()));
-
- response_headers_[":status"] = "200 OK";
- response_headers_[":version"] = "HTTP/1.1";
- response_headers_["content-type"] = "text/plain";
- response_headers_["big6"] = string(1000, 'x'); // Lots of x's.
-
- size_t spdy_response_headers_frame_length;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, kFin, &spdy_response_headers_frame_length));
-
- // Now that the headers have been processed, the callback will return.
- EXPECT_EQ(OK, callback_.WaitForResult());
- ASSERT_TRUE(response_.headers.get());
- EXPECT_EQ(200, response_.headers->response_code());
- EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
-
- // There is no body, so this should return immediately.
- EXPECT_EQ(0,
- stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
- callback_.callback()));
- EXPECT_TRUE(stream_->IsResponseBodyComplete());
- EXPECT_TRUE(AtEof());
-
- // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
- // headers and payload.
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
- stream_->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length),
- stream_->GetTotalReceivedBytes());
-}
-
-// Regression test for http://crbug.com/409101
-TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendRequest) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- Initialize();
-
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
-
- session_->connection()->CloseConnection(
- QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
-
- EXPECT_EQ(ERR_CONNECTION_CLOSED,
- stream_->SendRequest(headers_, &response_, callback_.callback()));
-
- EXPECT_EQ(0, stream_->GetTotalSentBytes());
- EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
-}
-
-// Regression test for http://crbug.com/584441
-TEST_P(QuicHttpStreamTest, GetSSLInfoAfterSessionClosed) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- Initialize();
-
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
-
- SSLInfo ssl_info;
- EXPECT_FALSE(ssl_info.is_valid());
- stream_->GetSSLInfo(&ssl_info);
- EXPECT_TRUE(ssl_info.is_valid());
-
- session_->connection()->CloseConnection(
- QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
-
- SSLInfo ssl_info2;
- stream_->GetSSLInfo(&ssl_info2);
- EXPECT_TRUE(ssl_info2.is_valid());
-}
-
-TEST_P(QuicHttpStreamTest, LogGranularQuicConnectionError) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructAckAndRstStreamPacket(2));
- use_closing_stream_ = true;
- Initialize();
-
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
- EXPECT_EQ(OK,
- stream_->SendRequest(headers_, &response_, callback_.callback()));
-
- // Ack the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
- EXPECT_EQ(ERR_IO_PENDING, stream_->ReadResponseHeaders(callback_.callback()));
-
- EXPECT_TRUE(QuicHttpStreamPeer::WasHandshakeConfirmed(stream_.get()));
-
- QuicConnectionCloseFrame frame;
- frame.error_code = QUIC_PEER_GOING_AWAY;
- session_->connection()->OnConnectionCloseFrame(frame);
-
- NetErrorDetails details;
- EXPECT_EQ(QUIC_NO_ERROR, details.quic_connection_error);
- stream_->PopulateNetErrorDetails(&details);
- EXPECT_EQ(QUIC_PEER_GOING_AWAY, details.quic_connection_error);
-}
-
-TEST_P(QuicHttpStreamTest, DoNotLogGranularQuicErrorIfHandshakeNotConfirmed) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructAckAndRstStreamPacket(2));
- use_closing_stream_ = true;
- Initialize();
-
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
- EXPECT_EQ(OK,
- stream_->SendRequest(headers_, &response_, callback_.callback()));
-
- // Ack the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
- EXPECT_EQ(ERR_IO_PENDING, stream_->ReadResponseHeaders(callback_.callback()));
-
- // The test setup defaults handshake to be confirmed. Manually set
- // it to be not confirmed.
- // Granular errors shouldn't be reported if handshake not confirmed.
- QuicHttpStreamPeer::SetHandshakeConfirmed(stream_.get(), false);
-
- EXPECT_FALSE(QuicHttpStreamPeer::WasHandshakeConfirmed(stream_.get()));
- QuicConnectionCloseFrame frame;
- frame.error_code = QUIC_PEER_GOING_AWAY;
- session_->connection()->OnConnectionCloseFrame(frame);
-
- NetErrorDetails details;
- EXPECT_EQ(QUIC_NO_ERROR, details.quic_connection_error);
- stream_->PopulateNetErrorDetails(&details);
- EXPECT_EQ(QUIC_NO_ERROR, details.quic_connection_error);
-}
-
-// Regression test for http://crbug.com/409871
-TEST_P(QuicHttpStreamTest, SessionClosedBeforeReadResponseHeaders) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- Initialize();
-
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
-
- EXPECT_EQ(OK,
- stream_->SendRequest(headers_, &response_, callback_.callback()));
-
- session_->connection()->CloseConnection(
- QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
-
- EXPECT_NE(OK, stream_->ReadResponseHeaders(callback_.callback()));
-
- // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
- // headers and payload.
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
- stream_->GetTotalSentBytes());
- EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
-}
-
-TEST_P(QuicHttpStreamTest, SendPostRequest) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructClientDataPacket(2, kIncludeVersion, kFin, 0, kUploadData));
- AddWrite(ConstructClientAckPacket(3, 3, 1));
-
- Initialize();
-
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(base::WrapUnique(
- new UploadBytesElementReader(kUploadData, strlen(kUploadData))));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- request_.method = "POST";
- request_.url = GURL("http://www.example.org/");
- request_.upload_data_stream = &upload_data_stream;
- ASSERT_EQ(OK, request_.upload_data_stream->Init(CompletionCallback()));
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
- EXPECT_EQ(OK,
- stream_->SendRequest(headers_, &response_, callback_.callback()));
-
- // Ack both packets in the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Send the response headers (but not the body).
- SetResponse("200 OK", string());
- size_t spdy_response_headers_frame_length;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, !kFin, &spdy_response_headers_frame_length));
-
- // The headers have arrived, but they are delivered asynchronously.
- EXPECT_EQ(ERR_IO_PENDING, stream_->ReadResponseHeaders(callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- ASSERT_TRUE(response_.headers.get());
- EXPECT_EQ(200, response_.headers->response_code());
- EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
-
- // Send the response body.
- const char kResponseBody[] = "Hello world!";
- ProcessPacket(ConstructServerDataPacket(3, false, kFin, 0, kResponseBody));
- // Since the body has already arrived, this should return immediately.
- EXPECT_EQ(static_cast<int>(strlen(kResponseBody)),
- stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
- callback_.callback()));
-
- EXPECT_TRUE(stream_->IsResponseBodyComplete());
- EXPECT_TRUE(AtEof());
-
- // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
- // headers and payload.
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
- strlen(kUploadData)),
- stream_->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
- strlen(kResponseBody)),
- stream_->GetTotalReceivedBytes());
-}
-
-TEST_P(QuicHttpStreamTest, SendChunkedPostRequest) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t chunk_size = strlen(kUploadData);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(
- ConstructClientDataPacket(2, kIncludeVersion, !kFin, 0, kUploadData));
- AddWrite(ConstructClientDataPacket(3, kIncludeVersion, kFin, chunk_size,
- kUploadData));
- AddWrite(ConstructClientAckPacket(4, 3, 1));
- Initialize();
-
- ChunkedUploadDataStream upload_data_stream(0);
- upload_data_stream.AppendData(kUploadData, chunk_size, false);
-
- request_.method = "POST";
- request_.url = GURL("http://www.example.org/");
- request_.upload_data_stream = &upload_data_stream;
- ASSERT_EQ(OK, request_.upload_data_stream->Init(
- TestCompletionCallback().callback()));
-
- ASSERT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
- ASSERT_EQ(ERR_IO_PENDING,
- stream_->SendRequest(headers_, &response_, callback_.callback()));
-
- upload_data_stream.AppendData(kUploadData, chunk_size, true);
- EXPECT_EQ(OK, callback_.WaitForResult());
-
- // Ack both packets in the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Send the response headers (but not the body).
- SetResponse("200 OK", string());
- size_t spdy_response_headers_frame_length;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, !kFin, &spdy_response_headers_frame_length));
-
- // The headers have arrived, but they are delivered asynchronously
- EXPECT_EQ(ERR_IO_PENDING, stream_->ReadResponseHeaders(callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- ASSERT_TRUE(response_.headers.get());
- EXPECT_EQ(200, response_.headers->response_code());
- EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
-
- // Send the response body.
- const char kResponseBody[] = "Hello world!";
- ProcessPacket(ConstructServerDataPacket(
- 3, false, kFin, response_data_.length(), kResponseBody));
-
- // Since the body has already arrived, this should return immediately.
- ASSERT_EQ(static_cast<int>(strlen(kResponseBody)),
- stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
- callback_.callback()));
-
- EXPECT_TRUE(stream_->IsResponseBodyComplete());
- EXPECT_TRUE(AtEof());
-
- // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
- // headers and payload.
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
- strlen(kUploadData) * 2),
- stream_->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
- strlen(kResponseBody)),
- stream_->GetTotalReceivedBytes());
-}
-
-TEST_P(QuicHttpStreamTest, SendChunkedPostRequestWithFinalEmptyDataPacket) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t chunk_size = strlen(kUploadData);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(
- ConstructClientDataPacket(2, kIncludeVersion, !kFin, 0, kUploadData));
- AddWrite(ConstructClientDataPacket(3, kIncludeVersion, kFin, chunk_size, ""));
- AddWrite(ConstructClientAckPacket(4, 3, 1));
- Initialize();
-
- ChunkedUploadDataStream upload_data_stream(0);
- upload_data_stream.AppendData(kUploadData, chunk_size, false);
-
- request_.method = "POST";
- request_.url = GURL("http://www.example.org/");
- request_.upload_data_stream = &upload_data_stream;
- ASSERT_EQ(OK, request_.upload_data_stream->Init(
- TestCompletionCallback().callback()));
-
- ASSERT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
- ASSERT_EQ(ERR_IO_PENDING,
- stream_->SendRequest(headers_, &response_, callback_.callback()));
-
- upload_data_stream.AppendData(nullptr, 0, true);
- EXPECT_EQ(OK, callback_.WaitForResult());
-
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Send the response headers (but not the body).
- SetResponse("200 OK", string());
- size_t spdy_response_headers_frame_length;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, !kFin, &spdy_response_headers_frame_length));
-
- // The headers have arrived, but they are delivered asynchronously
- EXPECT_EQ(ERR_IO_PENDING, stream_->ReadResponseHeaders(callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- ASSERT_TRUE(response_.headers.get());
- EXPECT_EQ(200, response_.headers->response_code());
- EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
-
- // Send the response body.
- const char kResponseBody[] = "Hello world!";
- ProcessPacket(ConstructServerDataPacket(
- 3, false, kFin, response_data_.length(), kResponseBody));
-
- // The body has arrived, but it is delivered asynchronously
- ASSERT_EQ(static_cast<int>(strlen(kResponseBody)),
- stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
- callback_.callback()));
- EXPECT_TRUE(stream_->IsResponseBodyComplete());
- EXPECT_TRUE(AtEof());
-
- // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
- // headers and payload.
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
- strlen(kUploadData)),
- stream_->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
- strlen(kResponseBody)),
- stream_->GetTotalReceivedBytes());
-}
-
-TEST_P(QuicHttpStreamTest, SendChunkedPostRequestWithOneEmptyDataPacket) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructClientDataPacket(2, kIncludeVersion, kFin, 0, ""));
- AddWrite(ConstructClientAckPacket(3, 3, 1));
- Initialize();
-
- ChunkedUploadDataStream upload_data_stream(0);
-
- request_.method = "POST";
- request_.url = GURL("http://www.example.org/");
- request_.upload_data_stream = &upload_data_stream;
- ASSERT_EQ(OK, request_.upload_data_stream->Init(
- TestCompletionCallback().callback()));
-
- ASSERT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
- ASSERT_EQ(ERR_IO_PENDING,
- stream_->SendRequest(headers_, &response_, callback_.callback()));
-
- upload_data_stream.AppendData(nullptr, 0, true);
- EXPECT_EQ(OK, callback_.WaitForResult());
-
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
-
- // Send the response headers (but not the body).
- SetResponse("200 OK", string());
- size_t spdy_response_headers_frame_length;
- ProcessPacket(ConstructResponseHeadersPacket(
- 2, !kFin, &spdy_response_headers_frame_length));
-
- // The headers have arrived, but they are delivered asynchronously
- EXPECT_EQ(ERR_IO_PENDING, stream_->ReadResponseHeaders(callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- ASSERT_TRUE(response_.headers.get());
- EXPECT_EQ(200, response_.headers->response_code());
- EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
-
- // Send the response body.
- const char kResponseBody[] = "Hello world!";
- ProcessPacket(ConstructServerDataPacket(
- 3, false, kFin, response_data_.length(), kResponseBody));
-
- // The body has arrived, but it is delivered asynchronously
- ASSERT_EQ(static_cast<int>(strlen(kResponseBody)),
- stream_->ReadResponseBody(read_buffer_.get(), read_buffer_->size(),
- callback_.callback()));
-
- EXPECT_TRUE(stream_->IsResponseBodyComplete());
- EXPECT_TRUE(AtEof());
-
- // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
- // headers and payload.
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
- stream_->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
- strlen(kResponseBody)),
- stream_->GetTotalReceivedBytes());
-}
-
-TEST_P(QuicHttpStreamTest, DestroyedEarly) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructAckAndRstStreamPacket(2));
- use_closing_stream_ = true;
- Initialize();
-
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
- EXPECT_EQ(OK,
- stream_->SendRequest(headers_, &response_, callback_.callback()));
-
- // Ack the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
- EXPECT_EQ(ERR_IO_PENDING, stream_->ReadResponseHeaders(callback_.callback()));
-
- // Send the response with a body.
- SetResponse("404 OK", "hello world!");
- // In the course of processing this packet, the QuicHttpStream close itself.
- ProcessPacket(ConstructResponseHeadersPacket(2, kFin, nullptr));
-
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(AtEof());
-
- // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
- // headers and payload.
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
- stream_->GetTotalSentBytes());
- // Zero since the stream is closed before processing the headers.
- EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
-}
-
-TEST_P(QuicHttpStreamTest, Priority) {
- SetRequest("GET", "/", MEDIUM);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, kFin, MEDIUM,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructAckAndRstStreamPacket(2));
- use_closing_stream_ = true;
- Initialize();
-
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK, stream_->InitializeStream(&request_, MEDIUM, net_log_.bound(),
- callback_.callback()));
-
- // Check that priority is highest.
- QuicChromiumClientStream* reliable_stream =
- QuicHttpStreamPeer::GetQuicChromiumClientStream(stream_.get());
- DCHECK(reliable_stream);
- DCHECK_EQ(kV3HighestPriority, reliable_stream->priority());
-
- EXPECT_EQ(OK,
- stream_->SendRequest(headers_, &response_, callback_.callback()));
-
- // Check that priority has now dropped back to MEDIUM.
- DCHECK_EQ(MEDIUM,
- ConvertQuicPriorityToRequestPriority(reliable_stream->priority()));
-
- // Ack the request.
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
- EXPECT_EQ(ERR_IO_PENDING, stream_->ReadResponseHeaders(callback_.callback()));
-
- // Send the response with a body.
- SetResponse("404 OK", "hello world!");
- // In the course of processing this packet, the QuicHttpStream close itself.
- ProcessPacket(ConstructResponseHeadersPacket(2, kFin, nullptr));
-
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(AtEof());
-
- // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
- // headers and payload.
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
- stream_->GetTotalSentBytes());
- // Zero since the stream is closed before processing the headers.
- EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
-}
-
-// Regression test for http://crbug.com/294870
-TEST_P(QuicHttpStreamTest, CheckPriorityWithNoDelegate) {
- SetRequest("GET", "/", MEDIUM);
- use_closing_stream_ = true;
-
- AddWrite(ConstructClientRstStreamPacket(1));
-
- Initialize();
-
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK, stream_->InitializeStream(&request_, MEDIUM, net_log_.bound(),
- callback_.callback()));
-
- // Check that priority is highest.
- QuicChromiumClientStream* reliable_stream =
- QuicHttpStreamPeer::GetQuicChromiumClientStream(stream_.get());
- DCHECK(reliable_stream);
- QuicChromiumClientStream::Delegate* delegate = reliable_stream->GetDelegate();
- DCHECK(delegate);
- DCHECK_EQ(kV3HighestPriority, reliable_stream->priority());
-
- // Set Delegate to nullptr and make sure Priority returns highest
- // priority.
- reliable_stream->SetDelegate(nullptr);
- DCHECK_EQ(kV3HighestPriority, reliable_stream->priority());
- reliable_stream->SetDelegate(delegate);
-
- EXPECT_EQ(0, stream_->GetTotalSentBytes());
- EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
-}
-
-TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendHeadersComplete) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- AddWrite(SYNCHRONOUS, ERR_FAILED);
- Initialize();
-
- ChunkedUploadDataStream upload_data_stream(0);
-
- request_.method = "POST";
- request_.url = GURL("http://www.example.org/");
- request_.upload_data_stream = &upload_data_stream;
- ASSERT_EQ(OK, request_.upload_data_stream->Init(
- TestCompletionCallback().callback()));
-
- ASSERT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
- ASSERT_EQ(ERR_QUIC_PROTOCOL_ERROR,
- stream_->SendRequest(headers_, &response_, callback_.callback()));
-}
-
-TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendBodyComplete) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(SYNCHRONOUS, ERR_FAILED);
- Initialize();
-
- ChunkedUploadDataStream upload_data_stream(0);
- size_t chunk_size = strlen(kUploadData);
- upload_data_stream.AppendData(kUploadData, chunk_size, false);
-
- request_.method = "POST";
- request_.url = GURL("http://www.example.org/");
- request_.upload_data_stream = &upload_data_stream;
- ASSERT_EQ(OK, request_.upload_data_stream->Init(
- TestCompletionCallback().callback()));
-
- ASSERT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
- ASSERT_EQ(ERR_QUIC_PROTOCOL_ERROR,
- stream_->SendRequest(headers_, &response_, callback_.callback()));
-}
-
-TEST_P(QuicHttpStreamTest, ServerPushGetRequest) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- Initialize();
-
- // Initialize the first stream, for receiving the promise on.
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
-
- // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE
- // packet, but does it matter?
- ReceivePromise(promise_id_);
- EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
-
- request_.url = GURL(promise_url_);
-
- // 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()));
-
- // Receive the promised response headers.
- response_headers_ = promised_response_.Clone();
- size_t spdy_response_headers_frame_length;
- ProcessPacket(InnerConstructResponseHeadersPacket(
- 1, promise_id_, false, &spdy_response_headers_frame_length));
-
- // Receive the promised response body.
- const char kResponseBody[] = "Hello world!";
- ProcessPacket(InnerConstructDataPacket(2, promise_id_, false, kFin, 0,
- kResponseBody, &server_maker_));
-
- // Now sending a matching request will have successful rendezvous
- // with the promised stream.
- EXPECT_EQ(OK, promised_stream_->SendRequest(headers_, &response_,
- callback_.callback()));
-
- EXPECT_EQ(
- QuicHttpStreamPeer::GetQuicChromiumClientStream(promised_stream_.get())
- ->id(),
- promise_id_);
-
- // The headers will be immediately available.
- EXPECT_EQ(OK, promised_stream_->ReadResponseHeaders(callback_.callback()));
-
- // As will be the body.
- EXPECT_EQ(
- static_cast<int>(strlen(kResponseBody)),
- promised_stream_->ReadResponseBody(
- read_buffer_.get(), read_buffer_->size(), callback_.callback()));
- EXPECT_TRUE(promised_stream_->IsResponseBodyComplete());
- EXPECT_TRUE(AtEof());
-
- EXPECT_EQ(0, stream_->GetTotalSentBytes());
- EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
- EXPECT_EQ(0, promised_stream_->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
- strlen(kResponseBody)),
- promised_stream_->GetTotalReceivedBytes());
-}
-
-TEST_P(QuicHttpStreamTest, ServerPushGetRequestSlowResponse) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- Initialize();
-
- // Initialize the first stream, for receiving the promise on.
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
-
- // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE
- // packet, but does it matter?
- ReceivePromise(promise_id_);
- EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
-
- request_.url = GURL(promise_url_);
-
- // 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()));
-
- // Now sending a matching request will rendezvous with the promised
- // stream, but pending secondary validation.
- EXPECT_EQ(ERR_IO_PENDING, promised_stream_->SendRequest(
- headers_, &response_, callback_.callback()));
-
- // Receive the promised response headers.
- response_headers_ = promised_response_.Clone();
- size_t spdy_response_headers_frame_length;
- ProcessPacket(InnerConstructResponseHeadersPacket(
- 1, promise_id_, false, &spdy_response_headers_frame_length));
-
- // Receive the promised response body.
- const char kResponseBody[] = "Hello world!";
- ProcessPacket(InnerConstructDataPacket(2, promise_id_, false, kFin, 0,
- kResponseBody, &server_maker_));
-
- base::RunLoop().RunUntilIdle();
-
- // Rendezvous should have succeeded now, so the promised stream
- // should point at our push stream, and we should be able read
- // headers and data from it.
- EXPECT_EQ(OK, callback_.WaitForResult());
-
- EXPECT_EQ(
- QuicHttpStreamPeer::GetQuicChromiumClientStream(promised_stream_.get())
- ->id(),
- promise_id_);
-
- EXPECT_EQ(OK, promised_stream_->ReadResponseHeaders(callback_.callback()));
-
- EXPECT_EQ(
- static_cast<int>(strlen(kResponseBody)),
- promised_stream_->ReadResponseBody(
- read_buffer_.get(), read_buffer_->size(), callback_.callback()));
-
- // Callback should return
- EXPECT_TRUE(promised_stream_->IsResponseBodyComplete());
- EXPECT_TRUE(AtEof());
-
- EXPECT_EQ(0, stream_->GetTotalSentBytes());
- EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
- EXPECT_EQ(0, promised_stream_->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
- strlen(kResponseBody)),
- promised_stream_->GetTotalReceivedBytes());
-}
-
-TEST_P(QuicHttpStreamTest, ServerPushCrossOriginOK) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- Initialize();
-
- // Initialize the first stream, for receiving the promise on.
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
-
- // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE
- // packet, but does it matter?
-
- push_promise_[":authority"] = "mail.example.org";
- promise_url_ = SpdyUtils::GetUrlFromHeaderBlock(push_promise_);
- serialized_push_promise_ =
- SpdyUtils::SerializeUncompressedHeaders(push_promise_);
-
- ReceivePromise(promise_id_);
- EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
-
- request_.url = GURL(promise_url_);
-
- // 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()));
-
- // Receive the promised response headers.
- response_headers_ = promised_response_.Clone();
- size_t spdy_response_headers_frame_length;
- ProcessPacket(InnerConstructResponseHeadersPacket(
- 1, promise_id_, false, &spdy_response_headers_frame_length));
-
- // Receive the promised response body.
- const char kResponseBody[] = "Hello world!";
- ProcessPacket(InnerConstructDataPacket(2, promise_id_, false, kFin, 0,
- kResponseBody, &server_maker_));
-
- // Now sending a matching request will have successful rendezvous
- // with the promised stream.
- EXPECT_EQ(OK, promised_stream_->SendRequest(headers_, &response_,
- callback_.callback()));
-
- EXPECT_EQ(
- QuicHttpStreamPeer::GetQuicChromiumClientStream(promised_stream_.get())
- ->id(),
- promise_id_);
-
- // The headers will be immediately available.
- EXPECT_EQ(OK, promised_stream_->ReadResponseHeaders(callback_.callback()));
-
- // As will be the body.
- EXPECT_EQ(
- static_cast<int>(strlen(kResponseBody)),
- promised_stream_->ReadResponseBody(
- read_buffer_.get(), read_buffer_->size(), callback_.callback()));
- EXPECT_TRUE(promised_stream_->IsResponseBodyComplete());
- EXPECT_TRUE(AtEof());
-
- EXPECT_EQ(0, stream_->GetTotalSentBytes());
- EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
- EXPECT_EQ(0, promised_stream_->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
- strlen(kResponseBody)),
- promised_stream_->GetTotalReceivedBytes());
-}
-
-TEST_P(QuicHttpStreamTest, ServerPushCrossOriginFail) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- Initialize();
-
- // Initialize the first stream, for receiving the promise on.
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
-
- // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE
- // packet, but does it matter?
- push_promise_[":authority"] = "www.notexample.org";
- promise_url_ = SpdyUtils::GetUrlFromHeaderBlock(push_promise_);
- serialized_push_promise_ =
- SpdyUtils::SerializeUncompressedHeaders(push_promise_);
-
- ReceivePromise(promise_id_);
- // The promise will have been rejected because the cert doesn't
- // match.
- EXPECT_EQ(session_->GetPromisedByUrl(promise_url_), nullptr);
-}
-
-TEST_P(QuicHttpStreamTest, ServerPushVaryCheckOK) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- Initialize();
-
- // Initialize the first stream, for receiving the promise on.
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
-
- push_promise_["accept-encoding"] = "gzip";
- serialized_push_promise_ =
- SpdyUtils::SerializeUncompressedHeaders(push_promise_);
-
- // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE
- // packet, but does it matter?
- ReceivePromise(promise_id_);
- EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
-
- request_.url = GURL(promise_url_);
-
- // 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()));
-
- headers_.SetHeader("accept-encoding", "gzip");
-
- // Now sending a matching request will rendezvous with the promised
- // stream, but pending secondary validation.
- EXPECT_EQ(ERR_IO_PENDING, promised_stream_->SendRequest(
- headers_, &response_, callback_.callback()));
-
- // Receive the promised response headers.
- promised_response_["vary"] = "accept-encoding";
- response_headers_ = promised_response_.Clone();
- size_t spdy_response_headers_frame_length;
- ProcessPacket(InnerConstructResponseHeadersPacket(
- 1, promise_id_, false, &spdy_response_headers_frame_length));
-
- // Receive the promised response body.
- const char kResponseBody[] = "Hello world!";
- ProcessPacket(InnerConstructDataPacket(2, promise_id_, false, kFin, 0,
- kResponseBody, &server_maker_));
-
- base::RunLoop().RunUntilIdle();
-
- // Rendezvous should have succeeded now, so the promised stream
- // should point at our push stream, and we should be able read
- // headers and data from it.
- EXPECT_EQ(OK, callback_.WaitForResult());
-
- EXPECT_EQ(
- QuicHttpStreamPeer::GetQuicChromiumClientStream(promised_stream_.get())
- ->id(),
- promise_id_);
-
- EXPECT_EQ(OK, promised_stream_->ReadResponseHeaders(callback_.callback()));
-
- EXPECT_EQ(
- static_cast<int>(strlen(kResponseBody)),
- promised_stream_->ReadResponseBody(
- read_buffer_.get(), read_buffer_->size(), callback_.callback()));
-
- // Callback should return
- EXPECT_TRUE(promised_stream_->IsResponseBodyComplete());
- EXPECT_TRUE(AtEof());
-
- EXPECT_EQ(0, stream_->GetTotalSentBytes());
- EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
- EXPECT_EQ(0, promised_stream_->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length +
- strlen(kResponseBody)),
- promised_stream_->GetTotalReceivedBytes());
-}
-
-TEST_P(QuicHttpStreamTest, ServerPushVaryCheckFail) {
- SetRequest("GET", "/", DEFAULT_PRIORITY);
- request_headers_[":scheme"] = "https";
- request_headers_[":path"] = "/bar";
- request_headers_["accept-encoding"] = "sdch";
-
- size_t spdy_request_header_frame_length;
- AddWrite(ConstructClientRstStreamVaryMismatchPacket(1));
- AddWrite(InnerConstructRequestHeadersPacket(
- 2, stream_id_ + 2, !kIncludeVersion, kFin, DEFAULT_PRIORITY,
- &spdy_request_header_frame_length));
- AddWrite(ConstructClientAckPacket(3, 3, 1));
- AddWrite(ConstructClientRstStreamCancelledPacket(4));
- Initialize();
-
- // Initialize the first stream, for receiving the promise on.
- request_.method = "GET";
- request_.url = GURL("http://www.example.org/");
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
-
- push_promise_["accept-encoding"] = "gzip";
- serialized_push_promise_ =
- SpdyUtils::SerializeUncompressedHeaders(push_promise_);
-
- // TODO(ckrasic) - could do this via constructing a PUSH_PROMISE
- // packet, but does it matter?
- ReceivePromise(promise_id_);
- EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr);
-
- request_.url = GURL(promise_url_);
-
- // 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()));
-
- headers_.SetHeader("accept-encoding", "sdch");
-
- // Now sending a matching request will rendezvous with the promised
- // stream, but pending secondary validation.
- EXPECT_EQ(ERR_IO_PENDING, promised_stream_->SendRequest(
- headers_, &response_, callback_.callback()));
-
- // Receive the promised response headers.
- promised_response_["vary"] = "accept-encoding";
- response_headers_ = promised_response_.Clone();
- size_t spdy_response_headers_frame_length;
- ProcessPacket(InnerConstructResponseHeadersPacket(
- 1, promise_id_, false, &spdy_response_headers_frame_length));
-
- base::RunLoop().RunUntilIdle();
-
- // Rendezvous should have failed due to vary mismatch, so the
- // promised stream should have been aborted, and instead we have a
- // new, regular client initiated stream.
- EXPECT_EQ(OK, callback_.WaitForResult());
-
- // Not a server-initiated stream.
- EXPECT_NE(
- QuicHttpStreamPeer::GetQuicChromiumClientStream(promised_stream_.get())
- ->id(),
- promise_id_);
-
- // Instead, a new client-initiated stream.
- EXPECT_EQ(
- QuicHttpStreamPeer::GetQuicChromiumClientStream(promised_stream_.get())
- ->id(),
- stream_id_ + 2);
-
- // After rendezvous failure, the push stream has been cancelled.
- EXPECT_EQ(session_->GetPromisedByUrl(promise_url_), nullptr);
-
- // The rest of the test verifies that the retried as
- // client-initiated version of |promised_stream_| works as intended.
-
- // Ack the request.
- ProcessPacket(ConstructServerAckPacket(2, 0, 0));
-
- SetResponse("404 Not Found", string());
- size_t spdy_response_header_frame_length;
- ProcessPacket(InnerConstructResponseHeadersPacket(
- 3, stream_id_ + 2, kFin, &spdy_response_header_frame_length));
-
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(OK, promised_stream_->ReadResponseHeaders(callback_.callback()));
- ASSERT_TRUE(response_.headers.get());
- EXPECT_EQ(404, response_.headers->response_code());
- EXPECT_TRUE(response_.headers->HasHeaderValue("Content-Type", "text/plain"));
- EXPECT_FALSE(response_.response_time.is_null());
- EXPECT_FALSE(response_.request_time.is_null());
-
- // There is no body, so this should return immediately.
- EXPECT_EQ(
- 0, promised_stream_->ReadResponseBody(
- read_buffer_.get(), read_buffer_->size(), callback_.callback()));
- EXPECT_TRUE(promised_stream_->IsResponseBodyComplete());
-
- stream_->Close(true);
-
- EXPECT_TRUE(AtEof());
-
- // QuicHttpStream::GetTotalSent/ReceivedBytes currently only includes the
- // headers and payload.
- EXPECT_EQ(static_cast<int64_t>(spdy_request_header_frame_length),
- promised_stream_->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(spdy_response_header_frame_length),
- promised_stream_->GetTotalReceivedBytes());
-}
-
-TEST_P(QuicHttpStreamTest, DataReadErrorSynchronous) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructClientRstStreamErrorPacket(2, kIncludeVersion));
-
- Initialize();
-
- ReadErrorUploadDataStream upload_data_stream(
- ReadErrorUploadDataStream::FailureMode::SYNC);
- request_.method = "POST";
- request_.url = GURL("http://www.example.org/");
- request_.upload_data_stream = &upload_data_stream;
- ASSERT_EQ(OK, request_.upload_data_stream->Init(
- TestCompletionCallback().callback()));
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
-
- int result = stream_->SendRequest(headers_, &response_, callback_.callback());
- EXPECT_EQ(ERR_FAILED, result);
-
- EXPECT_TRUE(AtEof());
-
- // QuicHttpStream::GetTotalSent/ReceivedBytes includes only headers.
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
- stream_->GetTotalSentBytes());
- EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
-}
-
-TEST_P(QuicHttpStreamTest, DataReadErrorAsynchronous) {
- SetRequest("POST", "/", DEFAULT_PRIORITY);
- size_t spdy_request_headers_frame_length;
- AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
- &spdy_request_headers_frame_length));
- AddWrite(ConstructClientRstStreamErrorPacket(2, !kIncludeVersion));
-
- Initialize();
-
- ReadErrorUploadDataStream upload_data_stream(
- ReadErrorUploadDataStream::FailureMode::ASYNC);
- request_.method = "POST";
- request_.url = GURL("http://www.example.org/");
- request_.upload_data_stream = &upload_data_stream;
- ASSERT_EQ(OK, request_.upload_data_stream->Init(
- TestCompletionCallback().callback()));
-
- EXPECT_EQ(OK,
- stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
- net_log_.bound(), callback_.callback()));
-
- int result = stream_->SendRequest(headers_, &response_, callback_.callback());
-
- ProcessPacket(ConstructServerAckPacket(1, 0, 0));
- SetResponse("200 OK", string());
-
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(ERR_FAILED, callback_.GetResult(result));
-
- EXPECT_TRUE(AtEof());
-
- // QuicHttpStream::GetTotalSent/ReceivedBytes includes only headers.
- EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length),
- stream_->GetTotalSentBytes());
- EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_http_utils.cc b/chromium/net/quic/quic_http_utils.cc
deleted file mode 100644
index c6dd505f2c6..00000000000
--- a/chromium/net/quic/quic_http_utils.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_http_utils.h"
-
-#include <utility>
-
-namespace net {
-
-SpdyPriority ConvertRequestPriorityToQuicPriority(
- const RequestPriority priority) {
- DCHECK_GE(priority, MINIMUM_PRIORITY);
- DCHECK_LE(priority, MAXIMUM_PRIORITY);
- return static_cast<SpdyPriority>(HIGHEST - priority);
-}
-
-NET_EXPORT_PRIVATE RequestPriority
-ConvertQuicPriorityToRequestPriority(SpdyPriority priority) {
- // Handle invalid values gracefully.
- return (priority >= 5) ? IDLE
- : static_cast<RequestPriority>(HIGHEST - priority);
-}
-
-std::unique_ptr<base::Value> QuicRequestNetLogCallback(
- QuicStreamId stream_id,
- const SpdyHeaderBlock* headers,
- SpdyPriority priority,
- NetLogCaptureMode capture_mode) {
- std::unique_ptr<base::DictionaryValue> dict(
- static_cast<base::DictionaryValue*>(
- SpdyHeaderBlockNetLogCallback(headers, capture_mode).release()));
- dict->SetInteger("quic_priority", static_cast<int>(priority));
- dict->SetInteger("quic_stream_id", static_cast<int>(stream_id));
- return std::move(dict);
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_http_utils.h b/chromium/net/quic/quic_http_utils.h
deleted file mode 100644
index ce5dd2f59a7..00000000000
--- a/chromium/net/quic/quic_http_utils.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_HTTP_UTILS_H_
-#define NET_QUIC_QUIC_HTTP_UTILS_H_
-
-#include "base/values.h"
-#include "net/base/net_export.h"
-#include "net/base/request_priority.h"
-#include "net/quic/quic_protocol.h"
-#include "net/spdy/spdy_header_block.h"
-#include "net/spdy/spdy_protocol.h"
-
-namespace net {
-
-NET_EXPORT_PRIVATE SpdyPriority
-ConvertRequestPriorityToQuicPriority(RequestPriority priority);
-
-NET_EXPORT_PRIVATE RequestPriority
-ConvertQuicPriorityToRequestPriority(SpdyPriority priority);
-
-// Converts a SpdyHeaderBlock and priority into NetLog event parameters.
-NET_EXPORT std::unique_ptr<base::Value> QuicRequestNetLogCallback(
- QuicStreamId stream_id,
- const SpdyHeaderBlock* headers,
- SpdyPriority priority,
- NetLogCaptureMode capture_mode);
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_HTTP_UTILS_H_
diff --git a/chromium/net/quic/quic_http_utils_test.cc b/chromium/net/quic/quic_http_utils_test.cc
deleted file mode 100644
index 5f33096a14b..00000000000
--- a/chromium/net/quic/quic_http_utils_test.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_http_utils.h"
-
-#include <stdint.h>
-
-#include <limits>
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-TEST(QuicHttpUtilsTest, ConvertRequestPriorityToQuicPriority) {
- EXPECT_EQ(0u, ConvertRequestPriorityToQuicPriority(HIGHEST));
- EXPECT_EQ(1u, ConvertRequestPriorityToQuicPriority(MEDIUM));
- EXPECT_EQ(2u, ConvertRequestPriorityToQuicPriority(LOW));
- EXPECT_EQ(3u, ConvertRequestPriorityToQuicPriority(LOWEST));
- EXPECT_EQ(4u, ConvertRequestPriorityToQuicPriority(IDLE));
-}
-
-TEST(QuicHttpUtilsTest, ConvertQuicPriorityToRequestPriority) {
- EXPECT_EQ(HIGHEST, ConvertQuicPriorityToRequestPriority(0));
- EXPECT_EQ(MEDIUM, ConvertQuicPriorityToRequestPriority(1));
- EXPECT_EQ(LOW, ConvertQuicPriorityToRequestPriority(2));
- EXPECT_EQ(LOWEST, ConvertQuicPriorityToRequestPriority(3));
- EXPECT_EQ(IDLE, ConvertQuicPriorityToRequestPriority(4));
- // These are invalid values, but we should still handle them
- // gracefully. TODO(rtenneti): should we test for all possible values of
- // uint32_t?
- for (int i = 5; i < std::numeric_limits<uint8_t>::max(); ++i) {
- EXPECT_EQ(IDLE, ConvertQuicPriorityToRequestPriority(i));
- }
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_multipath_received_packet_manager.cc b/chromium/net/quic/quic_multipath_received_packet_manager.cc
deleted file mode 100644
index fd2898f0a67..00000000000
--- a/chromium/net/quic/quic_multipath_received_packet_manager.cc
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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.
-
-#include "net/quic/quic_multipath_received_packet_manager.h"
-
-#include "base/stl_util.h"
-
-#include "net/quic/quic_bug_tracker.h"
-
-namespace net {
-
-QuicMultipathReceivedPacketManager::QuicMultipathReceivedPacketManager(
- QuicConnectionStats* stats) {
- path_managers_[kDefaultPathId] = new QuicReceivedPacketManager(stats);
-}
-
-QuicMultipathReceivedPacketManager::~QuicMultipathReceivedPacketManager() {
- STLDeleteValues(&path_managers_);
-}
-
-void QuicMultipathReceivedPacketManager::OnPathCreated(
- QuicPathId path_id,
- QuicConnectionStats* stats) {
- if (path_managers_[path_id] != nullptr) {
- QUIC_BUG << "Received packet manager of path already exists: "
- << static_cast<uint32_t>(path_id);
- return;
- }
-
- path_managers_[path_id] = new QuicReceivedPacketManager(stats);
-}
-
-void QuicMultipathReceivedPacketManager::OnPathClosed(QuicPathId path_id) {
- QuicReceivedPacketManager* manager = path_managers_[path_id];
- if (manager == nullptr) {
- QUIC_BUG << "Received packet manager of path does not exist: "
- << static_cast<uint32_t>(path_id);
- return;
- }
-
- delete manager;
- path_managers_.erase(path_id);
-}
-
-void QuicMultipathReceivedPacketManager::RecordPacketReceived(
- QuicPathId path_id,
- QuicByteCount bytes,
- const QuicPacketHeader& header,
- QuicTime receipt_time) {
- QuicReceivedPacketManager* manager = path_managers_[path_id];
- if (manager == nullptr) {
- QUIC_BUG << "Received a packet on a non-existent path.";
- return;
- }
-
- manager->RecordPacketReceived(bytes, header, receipt_time);
-}
-
-bool QuicMultipathReceivedPacketManager::IsMissing(
- QuicPathId path_id,
- QuicPacketNumber packet_number) {
- QuicReceivedPacketManager* manager = path_managers_[path_id];
- if (manager == nullptr) {
- QUIC_BUG << "Check whether a packet is missing on a non-existent path.";
- return true;
- }
-
- return manager->IsMissing(packet_number);
-}
-
-bool QuicMultipathReceivedPacketManager::IsAwaitingPacket(
- QuicPathId path_id,
- QuicPacketNumber packet_number) {
- QuicReceivedPacketManager* manager = path_managers_[path_id];
- if (manager == nullptr) {
- QUIC_BUG << "Check whether a packet is awaited on a non-existent path.";
- return false;
- }
-
- return manager->IsAwaitingPacket(packet_number);
-}
-
-void QuicMultipathReceivedPacketManager::UpdatePacketInformationSentByPeer(
- const std::vector<QuicStopWaitingFrame>& stop_waitings) {
- for (QuicStopWaitingFrame stop_waiting : stop_waitings) {
- QuicReceivedPacketManager* manager = path_managers_[stop_waiting.path_id];
- if (manager != nullptr) {
- manager->UpdatePacketInformationSentByPeer(stop_waiting);
- }
- }
-}
-
-bool QuicMultipathReceivedPacketManager::HasNewMissingPackets(
- QuicPathId path_id) const {
- MultipathReceivedPacketManagerMap::const_iterator it =
- path_managers_.find(path_id);
- if (it == path_managers_.end()) {
- QUIC_BUG << "Check whether has new missing packets on a non-existent path.";
- return false;
- }
-
- return it->second->HasNewMissingPackets();
-}
-
-QuicPacketNumber
-QuicMultipathReceivedPacketManager::GetPeerLeastPacketAwaitingAck(
- QuicPathId path_id) {
- QuicReceivedPacketManager* manager = path_managers_[path_id];
- if (manager == nullptr) {
- QUIC_BUG
- << "Try to get peer_least_packet_awaiting_ack of a non-existent path.";
- return false;
- }
-
- return manager->peer_least_packet_awaiting_ack();
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_multipath_received_packet_manager.h b/chromium/net/quic/quic_multipath_received_packet_manager.h
deleted file mode 100644
index 5f1f3a3fa7e..00000000000
--- a/chromium/net/quic/quic_multipath_received_packet_manager.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// 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.
-
-// A connection level received packet manager which manages multiple per path
-// received packet managers.
-
-#ifndef NET_QUIC_QUIC_MULTIPATH_RECEIVED_PACKET_MANAGER_H_
-#define NET_QUIC_QUIC_MULTIPATH_RECEIVED_PACKET_MANAGER_H_
-
-#include <unordered_map>
-#include <vector>
-
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_received_packet_manager.h"
-
-namespace net {
-
-namespace test {
-class QuicMultipathReceivedPacketManagerPeer;
-} // namespace test
-
-class NET_EXPORT_PRIVATE QuicMultipathReceivedPacketManager {
- public:
- typedef std::unordered_map<QuicPathId, QuicReceivedPacketManager*>
- MultipathReceivedPacketManagerMap;
-
- explicit QuicMultipathReceivedPacketManager(QuicConnectionStats* stats);
- ~QuicMultipathReceivedPacketManager();
-
- // Called when a new path with |path_id| is created.
- void OnPathCreated(QuicPathId path_id, QuicConnectionStats* stats);
-
- // Called when path with |path_id| is closed.
- void OnPathClosed(QuicPathId path_id);
-
- // Records packet receipt information on path with |path_id|.
- void RecordPacketReceived(QuicPathId path_id,
- QuicByteCount bytes,
- const QuicPacketHeader& header,
- QuicTime receipt_time);
-
- // Checks whether |packet_number| is missing on path with |path_id|.
- bool IsMissing(QuicPathId path_id, QuicPacketNumber packet_number);
-
- // Checks if we're still waiting for the packet with |packet_number| on path
- // with |path_id|.
- bool IsAwaitingPacket(QuicPathId path_id, QuicPacketNumber packet_number);
-
- // If |force_all_paths| is false, populates ack information for paths whose
- // ack has been updated since UpdateReceivedPacketInfo was called last time.
- // Otherwise, populates ack for all paths.
- void UpdateReceivedPacketInfo(std::vector<QuicAckFrame>* ack_frames,
- QuicTime approximate_now,
- bool force_all_paths);
-
- // Updates internal state based on stop_waiting frames for corresponding path.
- void UpdatePacketInformationSentByPeer(
- const std::vector<QuicStopWaitingFrame>& stop_waitings);
-
- // Returns true when there are new missing packets to be reported within 3
- // packets of the largest observed on path with |path_id|.
- bool HasNewMissingPackets(QuicPathId path_id) const;
-
- QuicPacketNumber GetPeerLeastPacketAwaitingAck(QuicPathId path_id);
-
- private:
- friend class test::QuicMultipathReceivedPacketManagerPeer;
-
- // Map mapping path id to path received packet manager.
- MultipathReceivedPacketManagerMap path_managers_;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_MULTIPATH_RECEIVED_PACKET_MANAGER_H_
diff --git a/chromium/net/quic/quic_multipath_received_packet_manager_test.cc b/chromium/net/quic/quic_multipath_received_packet_manager_test.cc
deleted file mode 100644
index e03a28a0de7..00000000000
--- a/chromium/net/quic/quic_multipath_received_packet_manager_test.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-// 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.
-
-#include "net/quic/quic_multipath_received_packet_manager.h"
-
-#include "net/quic/quic_connection_stats.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/test/gtest_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::Return;
-using testing::_;
-
-namespace net {
-namespace test {
-
-class QuicMultipathReceivedPacketManagerPeer {
- public:
- static bool PathReceivedPacketManagerExists(
- QuicMultipathReceivedPacketManager* multipath_manager,
- QuicPathId path_id) {
- return multipath_manager->path_managers_.count(path_id);
- }
-
- static void SetPathReceivedPacketManager(
- QuicMultipathReceivedPacketManager* multipath_manager,
- QuicPathId path_id,
- QuicReceivedPacketManager* manager) {
- delete multipath_manager->path_managers_[path_id];
- multipath_manager->path_managers_[path_id] = manager;
- }
-};
-
-namespace {
-
-const QuicPathId kPathId1 = 1;
-const QuicPathId kPathId2 = 2;
-const QuicPathId kPathId3 = 3;
-const QuicByteCount kBytes = 1350;
-
-class QuicMultipathReceivedPacketManagerTest : public testing::Test {
- public:
- QuicMultipathReceivedPacketManagerTest()
- : multipath_manager_(&stats_),
- manager_0_(new MockReceivedPacketManager(&stats_)),
- manager_1_(new MockReceivedPacketManager(&stats_)) {
- QuicMultipathReceivedPacketManagerPeer::SetPathReceivedPacketManager(
- &multipath_manager_, kDefaultPathId, manager_0_);
- QuicMultipathReceivedPacketManagerPeer::SetPathReceivedPacketManager(
- &multipath_manager_, kPathId1, manager_1_);
- }
-
- QuicConnectionStats stats_;
- QuicMultipathReceivedPacketManager multipath_manager_;
- MockReceivedPacketManager* manager_0_;
- MockReceivedPacketManager* manager_1_;
- QuicPacketHeader header_;
-};
-
-TEST_F(QuicMultipathReceivedPacketManagerTest, OnPathCreatedAndClosed) {
- EXPECT_TRUE(
- QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists(
- &multipath_manager_, kDefaultPathId));
- EXPECT_TRUE(
- QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists(
- &multipath_manager_, kPathId1));
- EXPECT_DFATAL(multipath_manager_.OnPathCreated(kDefaultPathId, &stats_),
- "Received packet manager of path already exists");
- // Path 2 created.
- multipath_manager_.OnPathCreated(kPathId2, &stats_);
- EXPECT_TRUE(
- QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists(
- &multipath_manager_, kPathId2));
- EXPECT_FALSE(
- QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists(
- &multipath_manager_, kPathId3));
- // Path 3 created.
- multipath_manager_.OnPathCreated(kPathId3, &stats_);
- EXPECT_TRUE(
- QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists(
- &multipath_manager_, kPathId3));
-
- // Path 0 closed.
- multipath_manager_.OnPathClosed(kDefaultPathId);
- EXPECT_FALSE(
- QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists(
- &multipath_manager_, kDefaultPathId));
- EXPECT_DFATAL(multipath_manager_.OnPathClosed(kDefaultPathId),
- "Received packet manager of path does not exist");
-}
-
-TEST_F(QuicMultipathReceivedPacketManagerTest, RecordPacketReceived) {
- EXPECT_CALL(*manager_0_, RecordPacketReceived(_, _, _)).Times(1);
- multipath_manager_.RecordPacketReceived(kDefaultPathId, kBytes, header_,
- QuicTime::Zero());
- EXPECT_DFATAL(multipath_manager_.RecordPacketReceived(
- kPathId2, kBytes, header_, QuicTime::Zero()),
- "Received a packet on a non-existent path");
-}
-
-TEST_F(QuicMultipathReceivedPacketManagerTest, IsMissing) {
- EXPECT_CALL(*manager_0_, IsMissing(header_.packet_number))
- .WillOnce(Return(true));
- EXPECT_CALL(*manager_1_, IsMissing(header_.packet_number))
- .WillOnce(Return(false));
- EXPECT_TRUE(
- multipath_manager_.IsMissing(kDefaultPathId, header_.packet_number));
- EXPECT_FALSE(multipath_manager_.IsMissing(kPathId1, header_.packet_number));
- EXPECT_DFATAL(multipath_manager_.IsMissing(kPathId2, header_.packet_number),
- "Check whether a packet is missing on a non-existent path");
-}
-
-TEST_F(QuicMultipathReceivedPacketManagerTest, IsAwaitingPacket) {
- EXPECT_CALL(*manager_0_, IsAwaitingPacket(header_.packet_number))
- .WillOnce(Return(true));
- EXPECT_CALL(*manager_1_, IsAwaitingPacket(header_.packet_number))
- .WillOnce(Return(false));
- EXPECT_TRUE(multipath_manager_.IsAwaitingPacket(kDefaultPathId,
- header_.packet_number));
- EXPECT_FALSE(
- multipath_manager_.IsAwaitingPacket(kPathId1, header_.packet_number));
- EXPECT_DFATAL(
- multipath_manager_.IsAwaitingPacket(kPathId2, header_.packet_number),
- "Check whether a packet is awaited on a non-existent path");
-}
-
-TEST_F(QuicMultipathReceivedPacketManagerTest,
- UpdatePacketInformationSentByPeer) {
- std::vector<QuicStopWaitingFrame> stop_waitings;
- QuicStopWaitingFrame stop_waiting_0;
- QuicStopWaitingFrame stop_waiting_1;
- QuicStopWaitingFrame stop_waiting_2;
- stop_waiting_0.path_id = kDefaultPathId;
- stop_waiting_1.path_id = kPathId1;
- stop_waiting_2.path_id = kPathId2;
- stop_waitings.push_back(stop_waiting_0);
- stop_waitings.push_back(stop_waiting_1);
- stop_waitings.push_back(stop_waiting_2);
- EXPECT_CALL(*manager_0_, UpdatePacketInformationSentByPeer(_)).Times(1);
- EXPECT_CALL(*manager_1_, UpdatePacketInformationSentByPeer(_)).Times(1);
- multipath_manager_.UpdatePacketInformationSentByPeer(stop_waitings);
-}
-
-TEST_F(QuicMultipathReceivedPacketManagerTest, HasNewMissingPackets) {
- EXPECT_CALL(*manager_0_, HasNewMissingPackets()).WillOnce(Return(true));
- EXPECT_CALL(*manager_1_, HasNewMissingPackets()).WillOnce(Return(false));
- EXPECT_TRUE(multipath_manager_.HasNewMissingPackets(kDefaultPathId));
- EXPECT_FALSE(multipath_manager_.HasNewMissingPackets(kPathId1));
- EXPECT_DFATAL(multipath_manager_.HasNewMissingPackets(kPathId2),
- "Check whether has new missing packets on a non-existent path");
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_multipath_transmissions_map.cc b/chromium/net/quic/quic_multipath_transmissions_map.cc
deleted file mode 100644
index a960e5a64c7..00000000000
--- a/chromium/net/quic/quic_multipath_transmissions_map.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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.
-
-#include "net/quic/quic_multipath_transmissions_map.h"
-
-namespace net {
-
-QuicMultipathTransmissionsMap::QuicMultipathTransmissionsMap() {}
-
-QuicMultipathTransmissionsMap::~QuicMultipathTransmissionsMap() {
- for (std::pair<QuicPathIdPacketNumber, MultipathTransmissionsList*>
- packet_transmissions : transmission_map_) {
- packet_transmissions.second->pop_front();
- if (packet_transmissions.second->empty()) {
- delete packet_transmissions.second;
- }
- }
-}
-
-void QuicMultipathTransmissionsMap::OnPacketRetransmittedOnDifferentPath(
- QuicPathIdPacketNumber original_path_id_packet_number,
- QuicPathIdPacketNumber path_id_packet_number) {
- MultipathTransmissionsList* across_paths_transmission_list = nullptr;
- MultipathTransmissionsMap::iterator it =
- transmission_map_.find(original_path_id_packet_number);
- if (it != transmission_map_.end()) {
- across_paths_transmission_list = it->second;
- } else {
- across_paths_transmission_list = new MultipathTransmissionsList();
- across_paths_transmission_list->push_back(original_path_id_packet_number);
- transmission_map_[original_path_id_packet_number] =
- across_paths_transmission_list;
- }
-
- across_paths_transmission_list->push_back(path_id_packet_number);
- transmission_map_[path_id_packet_number] = across_paths_transmission_list;
-}
-
-const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
-QuicMultipathTransmissionsMap::MaybeGetTransmissionsOnOtherPaths(
- QuicPathIdPacketNumber path_id_packet_number) const {
- MultipathTransmissionsMap::const_iterator it =
- transmission_map_.find(path_id_packet_number);
- if (it == transmission_map_.end()) {
- return nullptr;
- }
-
- return it->second;
-}
-
-void QuicMultipathTransmissionsMap::OnPacketHandled(
- QuicPathIdPacketNumber path_id_packet_number) {
- MultipathTransmissionsMap::iterator it =
- transmission_map_.find(path_id_packet_number);
- if (it == transmission_map_.end()) {
- return;
- }
-
- MultipathTransmissionsList* transmission_list = it->second;
- MultipathTransmissionsList::iterator transmission_it;
- // Remove all across paths transmissions of this packet from the map.
- for (QuicPathIdPacketNumber path_id_packet_number : *transmission_list) {
- transmission_map_.erase(path_id_packet_number);
- }
- // Remove the multipath transmissions list.
- delete transmission_list;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_multipath_transmissions_map.h b/chromium/net/quic/quic_multipath_transmissions_map.h
deleted file mode 100644
index 203fb285328..00000000000
--- a/chromium/net/quic/quic_multipath_transmissions_map.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// 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.
-
-// A map manages packets which are transmitted across multiple paths.
-// For example, a packet is originally transmitted on path 1 with packet number
-// 1. Then this packet is retransmitted on path 2 with packet number 1. (1, 1)
-// and (2, 1) are inserted into this map. Suppose (2, 1) is detected lost and
-// gets retransmitted on path 2 with packet 2. (2, 2) will not be inserted
-// because this transmission does not "across" path compared to (2, 1).
-
-#ifndef NET_QUIC_QUIC_MULTIPATH_TRANSMISSIONS_MAP_H_
-#define NET_QUIC_QUIC_MULTIPATH_TRANSMISSIONS_MAP_H_
-
-#include <deque>
-#include <unordered_map>
-
-#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_utils.h"
-
-namespace net {
-
-typedef std::pair<QuicPathId, QuicPacketNumber> QuicPathIdPacketNumber;
-
-class NET_EXPORT_PRIVATE QuicMultipathTransmissionsMap {
- public:
- struct QuicPathIdPacketNumberHash {
- size_t operator()(std::pair<QuicPathId, QuicPacketNumber> value) const {
- return QuicUtils::PackPathIdAndPacketNumber(value.first, value.second);
- }
- };
-
- typedef std::deque<QuicPathIdPacketNumber> MultipathTransmissionsList;
- typedef std::unordered_map<QuicPathIdPacketNumber,
- MultipathTransmissionsList*,
- QuicPathIdPacketNumberHash>
- MultipathTransmissionsMap;
-
- QuicMultipathTransmissionsMap();
- ~QuicMultipathTransmissionsMap();
-
- // Called when a packet is retransmitted on a different path. Adds both
- // |original_path_id_packet_number| (if not exists) and
- // |path_id_packet_number| to |transmission_map_|.
- void OnPacketRetransmittedOnDifferentPath(
- QuicPathIdPacketNumber original_path_id_packet_number,
- QuicPathIdPacketNumber path_id_packet_number);
-
- // Returns all multipath transmissions list if |path_id_packet_number| has
- // been transmitted across multiple paths, nullptr otherwise.
- const MultipathTransmissionsList* MaybeGetTransmissionsOnOtherPaths(
- QuicPathIdPacketNumber path_id_packet_number) const;
-
- // Called after packet |path_id_packet_number| is received.
- // If |path_id_packet_number| has been transmitted across multiple paths,
- // clears all multipath transmissions list and removes each transmission from
- // |transmission_map_|, does nothing otherwise.
- void OnPacketHandled(QuicPathIdPacketNumber path_id_packet_number);
-
- private:
- // Keys of the map are QuicPathIdPacketNumber, and values are pointers to
- // lists of multipath transmissions of the same packet. For example, if a
- // packet has been transmitted as (1, 1) and (2, 1), two entries are added
- // to this map and both values point to the same list: {(1, 1), (2, 1)}.
- // The MultipathTransmissionsList is owned by the transmission which is
- // received first (on any path).
- MultipathTransmissionsMap transmission_map_;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_MULTIPATH_TRANSMISSIONS_MAP_H_
diff --git a/chromium/net/quic/quic_multipath_transmissions_map_test.cc b/chromium/net/quic/quic_multipath_transmissions_map_test.cc
deleted file mode 100644
index ec31910ba75..00000000000
--- a/chromium/net/quic/quic_multipath_transmissions_map_test.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-// 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.
-
-#include "net/quic/quic_multipath_transmissions_map.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-namespace {
-
-TEST(QuicAcrossPathsTransmissionMapTest, OnPacketRetransmittedOnDifferentPath) {
- QuicMultipathTransmissionsMap transmission_map;
- // Packet0's original transmission sent on path 1 with packet number 1.
- QuicPathIdPacketNumber packet0_0(1, 1);
- // Packet0's retransmission sent on path 2 with packet number 1.
- QuicPathIdPacketNumber packet0_1(2, 1);
- // packet0's 2nd retransmission sent on path 3 with packet number 1.
- QuicPathIdPacketNumber packet0_2(3, 1);
-
- transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_0, packet0_1);
- const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
- transmission_list1 =
- transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0);
- EXPECT_EQ(packet0_0, (*transmission_list1)[0]);
- EXPECT_EQ(packet0_1, (*transmission_list1)[1]);
-
- transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_1, packet0_2);
- const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
- transmission_list2 =
- transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0);
- EXPECT_EQ(packet0_0, (*transmission_list2)[0]);
- EXPECT_EQ(packet0_1, (*transmission_list2)[1]);
- EXPECT_EQ(packet0_2, (*transmission_list2)[2]);
- // Make sure there is no memory leakage.
-}
-
-TEST(QuicAcrossPathsTransmissionMapTest, MaybeGetTransmissionsOnOtherPaths) {
- QuicMultipathTransmissionsMap transmission_map;
- // Packet0's original transmission sent on path 1 with packet number 1.
- QuicPathIdPacketNumber packet0_0(1, 1);
- // Packet0's retransmission sent on path 2 with packet number 1.
- QuicPathIdPacketNumber packet0_1(2, 1);
- // packet0's 2nd retransmission sent on path 3 with packet number 1.
- QuicPathIdPacketNumber packet0_2(3, 1);
-
- transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_0, packet0_1);
- transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_1, packet0_2);
-
- const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
- transmission_list1 =
- transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0);
- const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
- transmission_list2 =
- transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_1);
- const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
- transmission_list3 =
- transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_2);
- // Make sure all three pointers point to the same list.
- EXPECT_EQ(transmission_list1, transmission_list2);
- EXPECT_EQ(transmission_list2, transmission_list3);
- EXPECT_EQ(packet0_0, (*transmission_list1)[0]);
- EXPECT_EQ(packet0_1, (*transmission_list1)[1]);
- EXPECT_EQ(packet0_2, (*transmission_list1)[2]);
-
- // Packet1 which is not transmitted across path.
- QuicPathIdPacketNumber packet1_0(1, 2);
- EXPECT_EQ(nullptr,
- transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_0));
- // Make sure there is no memory leakage.
-}
-
-TEST(QuicAcrossPathsTransmissionMapTest, OnPacketHandled) {
- QuicMultipathTransmissionsMap transmission_map;
-
- // Packet's original transmission sent on path 1 with packet number 1.
- QuicPathIdPacketNumber packet0_0(1, 1);
- // Packet's retransmission sent on path 2 with packet number 1.
- QuicPathIdPacketNumber packet0_1(2, 1);
- // packet's 2nd retransmission sent on path 3 with packet number 1.
- QuicPathIdPacketNumber packet0_2(3, 1);
- transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_0, packet0_1);
- transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_1, packet0_2);
-
- // Packet1's original transmission sent on path 1 with packet number 2.
- QuicPathIdPacketNumber packet1_0(1, 2);
- // Packet1's retransmission sent on path 2 with packet number 2.
- QuicPathIdPacketNumber packet1_1(2, 2);
- transmission_map.OnPacketRetransmittedOnDifferentPath(packet1_0, packet1_1);
-
- transmission_map.OnPacketHandled(packet0_0);
- EXPECT_EQ(nullptr,
- transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0));
- EXPECT_EQ(nullptr,
- transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_1));
- EXPECT_EQ(nullptr,
- transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_2));
- const QuicMultipathTransmissionsMap::MultipathTransmissionsList*
- transmission_list =
- transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_0);
- EXPECT_EQ(packet1_0, (*transmission_list)[0]);
- EXPECT_EQ(packet1_1, (*transmission_list)[1]);
- // Packet 1 is received on path 2.
- transmission_map.OnPacketHandled(packet1_1);
- EXPECT_EQ(nullptr,
- transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_0));
- EXPECT_EQ(nullptr,
- transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_1));
- // Make sure there is no memory leakage.
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_network_transaction_unittest.cc b/chromium/net/quic/quic_network_transaction_unittest.cc
deleted file mode 100644
index c06d255ea07..00000000000
--- a/chromium/net/quic/quic_network_transaction_unittest.cc
+++ /dev/null
@@ -1,2751 +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 <memory>
-#include <ostream>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/stl_util.h"
-#include "base/strings/stringprintf.h"
-#include "net/base/chunked_upload_data_stream.h"
-#include "net/base/test_completion_callback.h"
-#include "net/cert/ct_policy_enforcer.h"
-#include "net/cert/mock_cert_verifier.h"
-#include "net/cert/multi_log_ct_verifier.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/http/http_auth_handler_factory.h"
-#include "net/http/http_network_session.h"
-#include "net/http/http_network_transaction.h"
-#include "net/http/http_server_properties_impl.h"
-#include "net/http/http_stream.h"
-#include "net/http/http_stream_factory.h"
-#include "net/http/http_transaction_test_util.h"
-#include "net/http/transport_security_state.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/proxy/proxy_config_service_fixed.h"
-#include "net/proxy/proxy_resolver.h"
-#include "net/proxy/proxy_service.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_http_utils.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
-#include "net/quic/test_tools/mock_random.h"
-#include "net/quic/test_tools/quic_test_packet_maker.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/socket/client_socket_factory.h"
-#include "net/socket/mock_client_socket_pool_manager.h"
-#include "net/socket/socket_performance_watcher.h"
-#include "net/socket/socket_performance_watcher_factory.h"
-#include "net/socket/socket_test_util.h"
-#include "net/socket/ssl_client_socket.h"
-#include "net/spdy/spdy_frame_builder.h"
-#include "net/spdy/spdy_framer.h"
-#include "net/ssl/ssl_config_service_defaults.h"
-#include "net/test/cert_test_util.h"
-#include "net/test/test_data_directory.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#include "url/gurl.h"
-
-namespace net {
-namespace test {
-
-namespace {
-
-enum DestinationType {
- // In pooling tests with two requests for different origins to the same
- // destination, the destination should be
- SAME_AS_FIRST, // the same as the first origin,
- SAME_AS_SECOND, // the same as the second origin, or
- DIFFERENT, // different from both.
-};
-
-static const char kQuicAlternativeServiceHeader[] =
- "Alt-Svc: quic=\":443\"\r\n\r\n";
-static const char kQuicAlternativeServiceWithProbabilityHeader[] =
- "Alt-Svc: quic=\":443\";p=\".5\"\r\n\r\n";
-static const char kQuicAlternativeServiceDifferentPortHeader[] =
- "Alt-Svc: quic=\":137\"\r\n\r\n";
-
-const char kDefaultServerHostName[] = "mail.example.org";
-const char kDifferentHostname[] = "different.example.com";
-
-// Run QuicNetworkTransactionWithDestinationTest instances with all value
-// combinations of version and destination_type.
-struct PoolingTestParams {
- friend std::ostream& operator<<(std::ostream& os,
- const PoolingTestParams& p) {
- os << "{ version: " << QuicVersionToString(p.version)
- << ", destination_type: ";
- switch (p.destination_type) {
- case SAME_AS_FIRST:
- os << "SAME_AS_FIRST";
- break;
- case SAME_AS_SECOND:
- os << "SAME_AS_SECOND";
- break;
- case DIFFERENT:
- os << "DIFFERENT";
- break;
- }
- os << " }";
- return os;
- }
-
- QuicVersion version;
- DestinationType destination_type;
-};
-
-std::vector<PoolingTestParams> GetPoolingTestParams() {
- std::vector<PoolingTestParams> params;
- QuicVersionVector all_supported_versions = QuicSupportedVersions();
- for (const QuicVersion 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});
- }
- return params;
-}
-
-} // namespace
-
-// Helper class to encapsulate MockReads and MockWrites for QUIC.
-// Simplify ownership issues and the interaction with the MockSocketFactory.
-class MockQuicData {
- public:
- MockQuicData() : packet_number_(0) {}
-
- ~MockQuicData() { STLDeleteElements(&packets_); }
-
- void AddSynchronousRead(std::unique_ptr<QuicEncryptedPacket> packet) {
- reads_.push_back(MockRead(SYNCHRONOUS, packet->data(), packet->length(),
- packet_number_++));
- packets_.push_back(packet.release());
- }
-
- void AddRead(std::unique_ptr<QuicEncryptedPacket> packet) {
- reads_.push_back(
- MockRead(ASYNC, packet->data(), packet->length(), packet_number_++));
- packets_.push_back(packet.release());
- }
-
- void AddRead(IoMode mode, int rv) {
- reads_.push_back(MockRead(mode, rv, packet_number_++));
- }
-
- void AddWrite(std::unique_ptr<QuicEncryptedPacket> packet) {
- writes_.push_back(MockWrite(SYNCHRONOUS, packet->data(), packet->length(),
- packet_number_++));
- packets_.push_back(packet.release());
- }
-
- void AddSocketDataToFactory(MockClientSocketFactory* factory) {
- MockRead* reads = reads_.empty() ? nullptr : &reads_[0];
- MockWrite* writes = writes_.empty() ? nullptr : &writes_[0];
- socket_data_.reset(
- new SequencedSocketData(reads, reads_.size(), writes, writes_.size()));
- factory->AddSocketDataProvider(socket_data_.get());
- }
-
- void Resume() { socket_data_->Resume(); }
-
- private:
- std::vector<QuicEncryptedPacket*> packets_;
- std::vector<MockWrite> writes_;
- std::vector<MockRead> reads_;
- size_t packet_number_;
- std::unique_ptr<SequencedSocketData> socket_data_;
-};
-
-class HeadersHandler {
- public:
- HeadersHandler() : was_proxied_(false) {}
-
- bool was_proxied() { return was_proxied_; }
-
- void OnBeforeHeadersSent(const ProxyInfo& proxy_info,
- HttpRequestHeaders* request_headers) {
- if (!proxy_info.is_http() && !proxy_info.is_https() &&
- !proxy_info.is_quic()) {
- return;
- }
- was_proxied_ = true;
- }
-
- private:
- bool was_proxied_;
-};
-
-class TestSocketPerformanceWatcher : public SocketPerformanceWatcher {
- public:
- explicit TestSocketPerformanceWatcher(bool* rtt_notification_received)
- : rtt_notification_received_(rtt_notification_received) {}
- ~TestSocketPerformanceWatcher() override {}
-
- bool ShouldNotifyUpdatedRTT() const override { return true; }
-
- void OnUpdatedRTTAvailable(const base::TimeDelta& rtt) override {
- *rtt_notification_received_ = true;
- }
-
- void OnConnectionChanged() override {}
-
- private:
- bool* rtt_notification_received_;
-
- DISALLOW_COPY_AND_ASSIGN(TestSocketPerformanceWatcher);
-};
-
-class TestSocketPerformanceWatcherFactory
- : public SocketPerformanceWatcherFactory {
- public:
- TestSocketPerformanceWatcherFactory()
- : watcher_count_(0u), rtt_notification_received_(false) {}
- ~TestSocketPerformanceWatcherFactory() override {}
-
- // SocketPerformanceWatcherFactory implementation:
- std::unique_ptr<SocketPerformanceWatcher> CreateSocketPerformanceWatcher(
- const Protocol protocol) override {
- if (protocol != PROTOCOL_QUIC) {
- return nullptr;
- }
- ++watcher_count_;
- return std::unique_ptr<SocketPerformanceWatcher>(
- new TestSocketPerformanceWatcher(&rtt_notification_received_));
- }
-
- size_t watcher_count() const { return watcher_count_; }
-
- bool rtt_notification_received() const { return rtt_notification_received_; }
-
- private:
- size_t watcher_count_;
- bool rtt_notification_received_;
-
- DISALLOW_COPY_AND_ASSIGN(TestSocketPerformanceWatcherFactory);
-};
-
-class QuicNetworkTransactionTest
- : public PlatformTest,
- public ::testing::WithParamInterface<QuicVersion> {
- protected:
- QuicNetworkTransactionTest()
- : clock_(new MockClock),
- client_maker_(GetParam(),
- 0,
- clock_,
- kDefaultServerHostName,
- Perspective::IS_CLIENT),
- server_maker_(GetParam(),
- 0,
- clock_,
- kDefaultServerHostName,
- Perspective::IS_SERVER),
- cert_transparency_verifier_(new MultiLogCTVerifier()),
- ssl_config_service_(new SSLConfigServiceDefaults),
- proxy_service_(ProxyService::CreateDirect()),
- auth_handler_factory_(
- HttpAuthHandlerFactory::CreateDefault(&host_resolver_)),
- random_generator_(0),
- ssl_data_(ASYNC, OK) {
- request_.method = "GET";
- std::string url("https://");
- url.append(kDefaultServerHostName);
- request_.url = GURL(url);
- request_.load_flags = 0;
- clock_->AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
-
- scoped_refptr<X509Certificate> cert(
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
- 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_);
- }
-
- void SetUp() override {
- NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
- base::RunLoop().RunUntilIdle();
- }
-
- void TearDown() override {
- NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
- // Empty the current queue.
- base::RunLoop().RunUntilIdle();
- PlatformTest::TearDown();
- NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
- base::RunLoop().RunUntilIdle();
- session_.reset();
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructClientConnectionClosePacket(
- QuicPacketNumber num) {
- return client_maker_.MakeConnectionClosePacket(num);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructServerConnectionClosePacket(
- QuicPacketNumber num) {
- return server_maker_.MakeConnectionClosePacket(num);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructServerGoAwayPacket(
- QuicPacketNumber num,
- QuicErrorCode error_code,
- std::string reason_phrase) {
- return server_maker_.MakeGoAwayPacket(num, error_code, reason_phrase);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructClientAckPacket(
- QuicPacketNumber largest_received,
- QuicPacketNumber least_unacked) {
- return client_maker_.MakeAckPacket(2, largest_received, least_unacked,
- least_unacked, true);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructClientAckAndRstPacket(
- QuicPacketNumber num,
- QuicStreamId stream_id,
- QuicRstStreamErrorCode error_code,
- QuicPacketNumber largest_received,
- QuicPacketNumber ack_least_unacked,
- QuicPacketNumber stop_least_unacked) {
- return client_maker_.MakeAckAndRstPacket(
- num, false, stream_id, error_code, largest_received, ack_least_unacked,
- stop_least_unacked, true);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructClientAckPacket(
- QuicPacketNumber largest_received,
- QuicPacketNumber least_unacked,
- QuicTestPacketMaker* maker) {
- return client_maker_.MakeAckPacket(2, largest_received, least_unacked,
- least_unacked, true);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructClientAckPacket(
- QuicPacketNumber packet_number,
- QuicPacketNumber largest_received,
- QuicPacketNumber ack_least_unacked,
- QuicPacketNumber stop_least_unacked) {
- return client_maker_.MakeAckPacket(packet_number, largest_received,
- ack_least_unacked, stop_least_unacked,
- true);
- }
-
- std::unique_ptr<QuicEncryptedPacket>
- ConstructClientAckAndConnectionClosePacket(
- QuicPacketNumber packet_number,
- QuicPacketNumber largest_received,
- QuicPacketNumber ack_least_unacked,
- QuicPacketNumber stop_least_unacked) {
- return client_maker_.MakeAckPacket(packet_number, largest_received,
- ack_least_unacked, stop_least_unacked,
- true);
- }
-
- std::unique_ptr<QuicEncryptedPacket>
- ConstructClientAckAndConnectionClosePacket(
- QuicPacketNumber num,
- QuicTime::Delta delta_time_largest_observed,
- QuicPacketNumber largest_received,
- QuicPacketNumber least_unacked,
- QuicErrorCode quic_error,
- const std::string& quic_error_details) {
- return client_maker_.MakeAckAndConnectionClosePacket(
- num, false, delta_time_largest_observed, largest_received,
- least_unacked, quic_error, quic_error_details);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructServerRstPacket(
- QuicPacketNumber num,
- bool include_version,
- QuicStreamId stream_id,
- QuicRstStreamErrorCode error_code) {
- return server_maker_.MakeRstPacket(num, include_version, stream_id,
- error_code);
- }
-
- // Uses default QuicTestPacketMaker.
- SpdyHeaderBlock GetRequestHeaders(const std::string& method,
- const std::string& scheme,
- const std::string& path) {
- return GetRequestHeaders(method, scheme, path, &client_maker_);
- }
-
- // Uses customized QuicTestPacketMaker.
- SpdyHeaderBlock GetRequestHeaders(const std::string& method,
- const std::string& scheme,
- const std::string& path,
- QuicTestPacketMaker* maker) {
- return maker->GetRequestHeaders(method, scheme, path);
- }
-
- SpdyHeaderBlock GetResponseHeaders(const std::string& status) {
- return server_maker_.GetResponseHeaders(status);
- }
-
- // Appends alt_svc headers in the response headers.
- SpdyHeaderBlock GetResponseHeaders(const std::string& status,
- const std::string& alt_svc) {
- return server_maker_.GetResponseHeaders(status, alt_svc);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructServerDataPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool should_include_version,
- bool fin,
- QuicStreamOffset offset,
- base::StringPiece data) {
- return server_maker_.MakeDataPacket(
- packet_number, stream_id, should_include_version, fin, offset, data);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool should_include_version,
- bool fin,
- SpdyHeaderBlock headers,
- 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::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool should_include_version,
- bool fin,
- SpdyHeaderBlock headers,
- QuicStreamOffset* offset,
- QuicTestPacketMaker* maker) {
- SpdyPriority priority =
- ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY);
- return client_maker_.MakeRequestHeadersPacketWithOffsetTracking(
- packet_number, stream_id, should_include_version, fin, priority,
- std::move(headers), offset);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool should_include_version,
- bool fin,
- SpdyHeaderBlock headers) {
- return ConstructClientRequestHeadersPacket(
- packet_number, stream_id, should_include_version, fin,
- std::move(headers), nullptr, &client_maker_);
- }
- std::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool should_include_version,
- bool fin,
- SpdyHeaderBlock headers,
- QuicTestPacketMaker* maker) {
- return ConstructClientRequestHeadersPacket(
- packet_number, stream_id, should_include_version, fin,
- std::move(headers), nullptr, maker);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructServerPushPromisePacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- QuicStreamId promised_stream_id,
- bool should_include_version,
- SpdyHeaderBlock headers,
- QuicStreamOffset* offset,
- QuicTestPacketMaker* maker) {
- return maker->MakePushPromisePacket(
- packet_number, stream_id, promised_stream_id, should_include_version,
- false, std::move(headers), nullptr, offset);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructServerResponseHeadersPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool should_include_version,
- bool fin,
- SpdyHeaderBlock headers) {
- return ConstructServerResponseHeadersPacket(
- packet_number, stream_id, should_include_version, fin,
- std::move(headers), nullptr, &server_maker_);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructServerResponseHeadersPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool should_include_version,
- bool fin,
- SpdyHeaderBlock headers,
- QuicTestPacketMaker* maker) {
- return ConstructServerResponseHeadersPacket(
- packet_number, stream_id, should_include_version, fin,
- std::move(headers), nullptr, maker);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructServerResponseHeadersPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool should_include_version,
- bool fin,
- SpdyHeaderBlock headers,
- QuicStreamOffset* offset) {
- return server_maker_.MakeResponseHeadersPacketWithOffsetTracking(
- packet_number, stream_id, should_include_version, fin,
- std::move(headers), offset);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructServerResponseHeadersPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool should_include_version,
- bool fin,
- SpdyHeaderBlock headers,
- QuicStreamOffset* offset,
- QuicTestPacketMaker* maker) {
- return server_maker_.MakeResponseHeadersPacketWithOffsetTracking(
- packet_number, stream_id, should_include_version, fin,
- std::move(headers), offset);
- }
-
- void CreateSession() {
- params_.enable_quic = true;
- params_.quic_clock = clock_;
- params_.quic_random = &random_generator_;
- params_.client_socket_factory = &socket_factory_;
- params_.quic_crypto_client_stream_factory = &crypto_client_stream_factory_;
- params_.host_resolver = &host_resolver_;
- params_.cert_verifier = &cert_verifier_;
- params_.transport_security_state = &transport_security_state_;
- params_.cert_transparency_verifier = cert_transparency_verifier_.get();
- params_.ct_policy_enforcer = &ct_policy_enforcer_;
- params_.socket_performance_watcher_factory =
- &test_socket_performance_watcher_factory_;
- params_.proxy_service = proxy_service_.get();
- params_.ssl_config_service = ssl_config_service_.get();
- params_.http_auth_handler_factory = auth_handler_factory_.get();
- params_.http_server_properties = &http_server_properties_;
- params_.quic_supported_versions = SupportedVersions(GetParam());
- for (const char* host :
- {kDefaultServerHostName, "www.example.org", "news.example.org",
- "bar.example.org", "foo.example.org", "invalid.example.org",
- "mail.example.com"}) {
- params_.quic_host_whitelist.insert(host);
- }
-
- session_.reset(new HttpNetworkSession(params_));
- session_->quic_stream_factory()->set_require_confirmation(false);
- ASSERT_EQ(params_.quic_socket_receive_buffer_size,
- session_->quic_stream_factory()->socket_receive_buffer_size());
- }
-
- void CheckWasQuicResponse(
- const std::unique_ptr<HttpNetworkTransaction>& trans) {
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response != nullptr);
- ASSERT_TRUE(response->headers.get() != nullptr);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
- EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_QUIC1_SPDY3,
- response->connection_info);
- }
-
- void CheckResponsePort(const std::unique_ptr<HttpNetworkTransaction>& trans,
- uint16_t port) {
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response != nullptr);
- EXPECT_EQ(port, response->socket_address.port());
- }
-
- void CheckWasHttpResponse(
- const std::unique_ptr<HttpNetworkTransaction>& trans) {
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response != nullptr);
- ASSERT_TRUE(response->headers.get() != nullptr);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_FALSE(response->was_npn_negotiated);
- EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
- response->connection_info);
- }
-
- void CheckResponseData(const std::unique_ptr<HttpNetworkTransaction>& trans,
- const std::string& expected) {
- std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
- EXPECT_EQ(expected, response_data);
- }
-
- void RunTransaction(const std::unique_ptr<HttpNetworkTransaction>& trans) {
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), net_log_.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
- }
-
- void SendRequestAndExpectHttpResponse(const std::string& expected) {
- std::unique_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
- RunTransaction(trans);
- CheckWasHttpResponse(trans);
- CheckResponseData(trans, expected);
- }
-
- void SendRequestAndExpectQuicResponse(const std::string& expected) {
- SendRequestAndExpectQuicResponseMaybeFromProxy(expected, false, 443);
- }
-
- void SendRequestAndExpectQuicResponseFromProxyOnPort(
- const std::string& expected,
- uint16_t port) {
- SendRequestAndExpectQuicResponseMaybeFromProxy(expected, true, port);
- }
-
- void AddQuicAlternateProtocolMapping(
- MockCryptoClientStream::HandshakeMode handshake_mode) {
- crypto_client_stream_factory_.set_handshake_mode(handshake_mode);
- url::SchemeHostPort server(request_.url);
- AlternativeService alternative_service(QUIC, server.host(), 443);
- base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
- http_server_properties_.SetAlternativeService(server, alternative_service,
- expiration);
- }
-
- void AddQuicRemoteAlternativeServiceMapping(
- MockCryptoClientStream::HandshakeMode handshake_mode,
- const HostPortPair& alternative) {
- crypto_client_stream_factory_.set_handshake_mode(handshake_mode);
- url::SchemeHostPort server(request_.url);
- AlternativeService alternative_service(QUIC, alternative.host(),
- alternative.port());
- base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
- http_server_properties_.SetAlternativeService(server, alternative_service,
- expiration);
- }
-
- void ExpectBrokenAlternateProtocolMapping() {
- const url::SchemeHostPort server(request_.url);
- const AlternativeServiceVector alternative_service_vector =
- http_server_properties_.GetAlternativeServices(server);
- EXPECT_EQ(1u, alternative_service_vector.size());
- EXPECT_TRUE(http_server_properties_.IsAlternativeServiceBroken(
- alternative_service_vector[0]));
- }
-
- void ExpectQuicAlternateProtocolMapping() {
- const url::SchemeHostPort server(request_.url);
- const AlternativeServiceVector alternative_service_vector =
- http_server_properties_.GetAlternativeServices(server);
- EXPECT_EQ(1u, alternative_service_vector.size());
- EXPECT_EQ(QUIC, alternative_service_vector[0].protocol);
- }
-
- void AddHangingNonAlternateProtocolSocketData() {
- std::unique_ptr<StaticSocketDataProvider> hanging_data;
- hanging_data.reset(new StaticSocketDataProvider());
- MockConnect hanging_connect(SYNCHRONOUS, ERR_IO_PENDING);
- hanging_data->set_connect_data(hanging_connect);
- hanging_data_.push_back(std::move(hanging_data));
- socket_factory_.AddSocketDataProvider(hanging_data_.back().get());
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
- }
-
- MockClock* clock_; // Owned by QuicStreamFactory after CreateSession.
- QuicTestPacketMaker client_maker_;
- QuicTestPacketMaker server_maker_;
- std::unique_ptr<HttpNetworkSession> session_;
- MockClientSocketFactory socket_factory_;
- ProofVerifyDetailsChromium verify_details_;
- MockCryptoClientStreamFactory crypto_client_stream_factory_;
- MockHostResolver host_resolver_;
- MockCertVerifier cert_verifier_;
- TransportSecurityState transport_security_state_;
- std::unique_ptr<CTVerifier> cert_transparency_verifier_;
- CTPolicyEnforcer ct_policy_enforcer_;
- TestSocketPerformanceWatcherFactory test_socket_performance_watcher_factory_;
- scoped_refptr<SSLConfigServiceDefaults> ssl_config_service_;
- std::unique_ptr<ProxyService> proxy_service_;
- std::unique_ptr<HttpAuthHandlerFactory> auth_handler_factory_;
- MockRandom random_generator_;
- HttpServerPropertiesImpl http_server_properties_;
- HttpNetworkSession::Params params_;
- HttpRequestInfo request_;
- BoundTestNetLog net_log_;
- std::vector<std::unique_ptr<StaticSocketDataProvider>> hanging_data_;
- SSLSocketDataProvider ssl_data_;
-
- private:
- void SendRequestAndExpectQuicResponseMaybeFromProxy(
- const std::string& expected,
- bool used_proxy,
- uint16_t port) {
- std::unique_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
- HeadersHandler headers_handler;
- trans->SetBeforeHeadersSentCallback(
- base::Bind(&HeadersHandler::OnBeforeHeadersSent,
- base::Unretained(&headers_handler)));
- RunTransaction(trans);
- CheckWasQuicResponse(trans);
- CheckResponsePort(trans, port);
- CheckResponseData(trans, expected);
- EXPECT_EQ(used_proxy, headers_handler.was_proxied());
- }
-};
-
-INSTANTIATE_TEST_CASE_P(Version,
- QuicNetworkTransactionTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
-
-TEST_P(QuicNetworkTransactionTest, ForceQuic) {
- params_.origins_to_force_quic_on.insert(
- HostPortPair::FromString("mail.example.org:443"));
-
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
- mock_quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // No more data to read
-
- mock_quic_data.AddSocketDataToFactory(&socket_factory_);
-
- // The non-alternate protocol job needs to hang in order to guarantee that
- // the alternate-protocol job will "win".
- AddHangingNonAlternateProtocolSocketData();
-
- CreateSession();
-
- EXPECT_FALSE(
- test_socket_performance_watcher_factory_.rtt_notification_received());
- SendRequestAndExpectQuicResponse("hello!");
- EXPECT_TRUE(
- test_socket_performance_watcher_factory_.rtt_notification_received());
-
- // Check that the NetLog was filled reasonably.
- TestNetLogEntry::List entries;
- net_log_.GetEntries(&entries);
- EXPECT_LT(0u, entries.size());
-
- // Check that we logged a QUIC_SESSION_PACKET_RECEIVED.
- int pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_QUIC_SESSION_PACKET_RECEIVED,
- NetLog::PHASE_NONE);
- EXPECT_LT(0, pos);
-
- // ... and also a TYPE_QUIC_SESSION_UNAUTHENTICATED_PACKET_HEADER_RECEIVED.
- pos = ExpectLogContainsSomewhere(
- entries, 0,
- NetLog::TYPE_QUIC_SESSION_UNAUTHENTICATED_PACKET_HEADER_RECEIVED,
- NetLog::PHASE_NONE);
- EXPECT_LT(0, pos);
-
- std::string packet_number;
- ASSERT_TRUE(entries[pos].GetStringValue("packet_number", &packet_number));
- EXPECT_EQ("1", packet_number);
-
- // ... and also a TYPE_QUIC_SESSION_PACKET_AUTHENTICATED.
- pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_QUIC_SESSION_PACKET_AUTHENTICATED,
- NetLog::PHASE_NONE);
- EXPECT_LT(0, pos);
-
- // ... and also a QUIC_SESSION_STREAM_FRAME_RECEIVED.
- pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_QUIC_SESSION_STREAM_FRAME_RECEIVED,
- NetLog::PHASE_NONE);
- EXPECT_LT(0, pos);
-
- int log_stream_id;
- ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &log_stream_id));
- EXPECT_EQ(3, log_stream_id);
-}
-
-TEST_P(QuicNetworkTransactionTest, QuicProxy) {
- params_.enable_quic = true;
- proxy_service_ =
- ProxyService::CreateFixedFromPacResult("QUIC mail.example.org:70");
-
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "http", "/")));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 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_);
-
- EXPECT_FALSE(
- test_socket_performance_watcher_factory_.rtt_notification_received());
- // There is no need to set up an alternate protocol job, because
- // no attempt will be made to speak to the proxy over TCP.
-
- request_.url = GURL("http://mail.example.org/");
- CreateSession();
-
- SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 70);
- EXPECT_TRUE(
- test_socket_performance_watcher_factory_.rtt_notification_received());
-}
-
-// Regression test for https://crbug.com/492458. Test that for an HTTP
-// connection through a QUIC proxy, the certificate exhibited by the proxy is
-// checked against the proxy hostname, not the origin hostname.
-TEST_P(QuicNetworkTransactionTest, QuicProxyWithCert) {
- const std::string origin_host = "mail.example.com";
- const std::string proxy_host = "www.example.org";
-
- params_.enable_quic = true;
- proxy_service_ =
- ProxyService::CreateFixedFromPacResult("QUIC " + proxy_host + ":70");
-
- client_maker_.set_hostname(origin_host);
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "http", "/")));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
- mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read
- mock_quic_data.AddRead(ASYNC, 0);
- mock_quic_data.AddSocketDataToFactory(&socket_factory_);
-
- scoped_refptr<X509Certificate> cert(
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
- ASSERT_TRUE(cert.get());
- // This certificate is valid for the proxy, but not for the origin.
- bool common_name_fallback_used;
- EXPECT_TRUE(cert->VerifyNameMatch(proxy_host, &common_name_fallback_used));
- EXPECT_FALSE(cert->VerifyNameMatch(origin_host, &common_name_fallback_used));
- ProofVerifyDetailsChromium verify_details;
- verify_details.cert_verify_result.verified_cert = cert;
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- ProofVerifyDetailsChromium verify_details2;
- verify_details2.cert_verify_result.verified_cert = cert;
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2);
-
- request_.url = GURL("http://" + origin_host);
- AddHangingNonAlternateProtocolSocketData();
- CreateSession();
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::CONFIRM_HANDSHAKE);
- SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 70);
-}
-
-TEST_P(QuicNetworkTransactionTest, AlternativeServicesDifferentHost) {
- HostPortPair origin("www.example.org", 443);
- HostPortPair alternative("mail.example.org", 443);
-
- base::FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> cert(
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
- ASSERT_TRUE(cert.get());
- // TODO(rch): the connection should be "to" the origin, so if the cert is
- // valid for the origin but not the alternative, that should work too.
- bool common_name_fallback_used;
- EXPECT_TRUE(cert->VerifyNameMatch(origin.host(), &common_name_fallback_used));
- EXPECT_TRUE(
- cert->VerifyNameMatch(alternative.host(), &common_name_fallback_used));
- ProofVerifyDetailsChromium verify_details;
- verify_details.cert_verify_result.verified_cert = cert;
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- client_maker_.set_hostname(origin.host());
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
- mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read
- mock_quic_data.AddRead(ASYNC, 0);
- mock_quic_data.AddSocketDataToFactory(&socket_factory_);
-
- request_.url = GURL("https://" + origin.host());
- AddQuicRemoteAlternativeServiceMapping(
- MockCryptoClientStream::CONFIRM_HANDSHAKE, alternative);
- AddHangingNonAlternateProtocolSocketData();
- CreateSession();
-
- SendRequestAndExpectQuicResponse("hello!");
-}
-
-TEST_P(QuicNetworkTransactionTest, ForceQuicWithErrorConnecting) {
- params_.origins_to_force_quic_on.insert(
- HostPortPair::FromString("mail.example.org:443"));
-
- MockQuicData mock_quic_data1;
- mock_quic_data1.AddRead(ASYNC, ERR_SOCKET_NOT_CONNECTED);
-
- MockQuicData mock_quic_data2;
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details_);
- mock_quic_data2.AddRead(ASYNC, ERR_SOCKET_NOT_CONNECTED);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details_);
-
- mock_quic_data1.AddSocketDataToFactory(&socket_factory_);
- mock_quic_data2.AddSocketDataToFactory(&socket_factory_);
-
- CreateSession();
-
- EXPECT_EQ(0U, test_socket_performance_watcher_factory_.watcher_count());
- for (size_t i = 0; i < 2; ++i) {
- std::unique_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), net_log_.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.WaitForResult());
- EXPECT_EQ(1 + i, test_socket_performance_watcher_factory_.watcher_count());
- }
-}
-
-TEST_P(QuicNetworkTransactionTest, DoNotForceQuicForHttps) {
- // Attempt to "force" quic on 443, which will not be honored.
- params_.origins_to_force_quic_on.insert(
- HostPortPair::FromString("www.google.com:443"));
-
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider data(http_reads, arraysize(http_reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- socket_factory_.AddSSLSocketDataProvider(&ssl);
-
- CreateSession();
-
- SendRequestAndExpectHttpResponse("hello world");
- EXPECT_EQ(0U, test_socket_performance_watcher_factory_.watcher_count());
-}
-
-TEST_P(QuicNetworkTransactionTest, UseAlternativeServiceForQuic) {
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"), MockRead(kQuicAlternativeServiceHeader),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 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_);
-
- AddHangingNonAlternateProtocolSocketData();
- CreateSession();
-
- SendRequestAndExpectHttpResponse("hello world");
- SendRequestAndExpectQuicResponse("hello!");
-}
-
-TEST_P(QuicNetworkTransactionTest,
- UseAlternativeServiceWithProbabilityForQuic) {
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(kQuicAlternativeServiceWithProbabilityHeader),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 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_);
-
- AddHangingNonAlternateProtocolSocketData();
- CreateSession();
-
- SendRequestAndExpectHttpResponse("hello world");
- SendRequestAndExpectQuicResponse("hello!");
-}
-
-TEST_P(QuicNetworkTransactionTest, SetAlternativeServiceWithScheme) {
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Alt-Svc: quic=\"foo.example.org:443\", quic=\":444\"\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
-
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- CreateSession();
- // Send https request, ignore alternative service advertising if response
- // header advertises alternative service for mail.example.org.
- request_.url = GURL("https://mail.example.org:443");
- SendRequestAndExpectHttpResponse("hello world");
- HttpServerProperties* http_server_properties =
- session_->http_server_properties();
- url::SchemeHostPort http_server("http", "mail.example.org", 443);
- url::SchemeHostPort https_server("https", "mail.example.org", 443);
- // Check alternative service is set for the correct origin.
- EXPECT_EQ(
- 2u, http_server_properties->GetAlternativeServices(https_server).size());
- EXPECT_TRUE(
- http_server_properties->GetAlternativeServices(http_server).empty());
-}
-
-TEST_P(QuicNetworkTransactionTest, DoNotGetAltSvcForDifferentOrigin) {
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Alt-Svc: quic=\"foo.example.org:443\", quic=\":444\"\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
-
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- CreateSession();
-
- // Send https request and set alternative services if response header
- // advertises alternative service for mail.example.org.
- SendRequestAndExpectHttpResponse("hello world");
- HttpServerProperties* http_server_properties =
- session_->http_server_properties();
-
- const url::SchemeHostPort https_server(request_.url);
- // Check alternative service is set.
- AlternativeServiceVector alternative_service_vector =
- http_server_properties->GetAlternativeServices(https_server);
- EXPECT_EQ(2u, alternative_service_vector.size());
-
- // Send http request to the same origin but with diffrent scheme, should not
- // use QUIC.
- request_.url = GURL("http://mail.example.org:443");
- SendRequestAndExpectHttpResponse("hello world");
-}
-
-TEST_P(QuicNetworkTransactionTest, UseAlternativeServiceQuicSupportedVersion) {
- std::string altsvc_header = base::StringPrintf(
- "Alt-Svc: quic=\":443\"; v=\"%u\"\r\n\r\n", GetParam());
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"), MockRead(altsvc_header.c_str()),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 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_);
-
- AddHangingNonAlternateProtocolSocketData();
- CreateSession();
-
- SendRequestAndExpectHttpResponse("hello world");
- SendRequestAndExpectQuicResponse("hello!");
-}
-
-TEST_P(QuicNetworkTransactionTest, GoAwayWithConnectionMigrationOnPortsOnly) {
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
- // Read a GoAway packet with
- // QuicErrorCode: QUIC_ERROR_MIGRATING_PORT from the peer.
- mock_quic_data.AddRead(ConstructServerGoAwayPacket(
- 2, QUIC_ERROR_MIGRATING_PORT,
- "connection migration with port change only"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
- mock_quic_data.AddRead(ConstructServerDataPacket(3, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckAndRstPacket(
- 3, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 3, 3, 1));
- mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read
- mock_quic_data.AddRead(ASYNC, 0); // EOF
-
- mock_quic_data.AddSocketDataToFactory(&socket_factory_);
-
- // The non-alternate protocol job needs to hang in order to guarantee that
- // the alternate-protocol job will "win".
- AddHangingNonAlternateProtocolSocketData();
-
- // In order for a new QUIC session to be established via alternate-protocol
- // without racing an HTTP connection, we need the host resolution to happen
- // synchronously. Of course, even though QUIC *could* perform a 0-RTT
- // connection to the the server, in this test we require confirmation
- // before encrypting so the HTTP job will still start.
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
- "");
- HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
- AddressList address;
- host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
- nullptr, net_log_.bound());
-
- CreateSession();
- session_->quic_stream_factory()->set_require_confirmation(true);
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
-
- std::unique_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), net_log_.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
- QuicSession::HANDSHAKE_CONFIRMED);
- EXPECT_EQ(OK, callback.WaitForResult());
-
- // Check whether this transaction is correctly marked as received a go-away
- // because of migrating port.
- NetErrorDetails details;
- EXPECT_FALSE(details.quic_port_migration_detected);
- trans->PopulateNetErrorDetails(&details);
- EXPECT_TRUE(details.quic_port_migration_detected);
-}
-
-TEST_P(QuicNetworkTransactionTest,
- DoNotUseAlternativeServiceQuicUnsupportedVersion) {
- std::string altsvc_header = base::StringPrintf(
- "Alt-Svc: quic=\":443\"; v=\"%u\"\r\n\r\n", GetParam() - 1);
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"), MockRead(altsvc_header.c_str()),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- CreateSession();
-
- SendRequestAndExpectHttpResponse("hello world");
- SendRequestAndExpectHttpResponse("hello world");
-}
-
-// When multiple alternative services are advertised,
-// HttpStreamFactoryImpl::RequestStreamInternal() should select the alternative
-// service which uses existing QUIC session if available. If no existing QUIC
-// session can be used, use the first alternative service from the list.
-TEST_P(QuicNetworkTransactionTest, UseExistingAlternativeServiceForQuic) {
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Alt-Svc: quic=\"foo.example.org:443\", quic=\":444\"\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- QuicStreamOffset request_header_offset = 0;
- QuicStreamOffset response_header_offset = 0;
- // First QUIC request data.
- // Open a session to foo.example.org:443 using the first entry of the
- // alternative service list.
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/"), &request_header_offset));
-
- std::string alt_svc_list =
- "quic=\"mail.example.org:444\", quic=\"foo.example.org:443\", "
- "quic=\"bar.example.org:445\"";
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false,
- GetResponseHeaders("200 OK", alt_svc_list), &response_header_offset));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
-
- // Second QUIC request data.
- // Connection pooling, using existing session, no need to include version
- // as version negotiation has been completed.
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 3, kClientDataStreamId2, false, true,
- GetRequestHeaders("GET", "https", "/"), &request_header_offset));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 3, kClientDataStreamId2, false, false, GetResponseHeaders("200 OK"),
- &response_header_offset));
- mock_quic_data.AddRead(ConstructServerDataPacket(4, kClientDataStreamId2,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(
- ConstructClientAckAndConnectionClosePacket(4, 4, 3, 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_);
-
- AddHangingNonAlternateProtocolSocketData();
- CreateSession();
-
- SendRequestAndExpectHttpResponse("hello world");
-
- SendRequestAndExpectQuicResponse("hello!");
- SendRequestAndExpectQuicResponse("hello!");
-}
-
-// Pool to existing session with matching QuicServerId
-// even if alternative service destination is different.
-TEST_P(QuicNetworkTransactionTest, PoolByOrigin) {
- MockQuicData mock_quic_data;
- QuicStreamOffset request_header_offset(0);
- QuicStreamOffset response_header_offset(0);
-
- // First request.
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/"), &request_header_offset));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK"),
- &response_header_offset));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
-
- // Second request.
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 3, kClientDataStreamId2, false, true,
- GetRequestHeaders("GET", "https", "/"), &request_header_offset));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 3, kClientDataStreamId2, false, false, GetResponseHeaders("200 OK"),
- &response_header_offset));
- mock_quic_data.AddRead(ConstructServerDataPacket(4, kClientDataStreamId2,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(
- ConstructClientAckAndConnectionClosePacket(4, 4, 3, 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_);
-
- AddHangingNonAlternateProtocolSocketData();
- AddHangingNonAlternateProtocolSocketData();
-
- CreateSession();
-
- const char destination1[] = "first.example.com";
- const char destination2[] = "second.example.com";
-
- // Set up alternative service entry to destination1.
- url::SchemeHostPort server(request_.url);
- AlternativeService alternative_service(QUIC, destination1, 443);
- base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
- http_server_properties_.SetAlternativeService(server, alternative_service,
- expiration);
- // First request opens connection to |destination1|
- // with QuicServerId.host() == kDefaultServerHostName.
- SendRequestAndExpectQuicResponse("hello!");
-
- // Set up alternative service entry to a different destination.
- alternative_service = AlternativeService(QUIC, destination2, 443);
- http_server_properties_.SetAlternativeService(server, alternative_service,
- expiration);
- // Second request pools to existing connection with same QuicServerId,
- // even though alternative service destination is different.
- SendRequestAndExpectQuicResponse("hello!");
-}
-
-// Pool to existing session with matching destination and matching certificate
-// even if origin is different, and even if the alternative service with
-// matching destination is not the first one on the list.
-TEST_P(QuicNetworkTransactionTest, PoolByDestination) {
- GURL origin1 = request_.url;
- GURL origin2("https://www.example.org/");
- ASSERT_NE(origin1.host(), origin2.host());
-
- MockQuicData mock_quic_data;
- QuicStreamOffset request_header_offset(0);
- QuicStreamOffset response_header_offset(0);
-
- // First request.
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/"), &request_header_offset));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK"),
- &response_header_offset));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
-
- // Second request.
- QuicTestPacketMaker client_maker2(GetParam(), 0, clock_, origin2.host(),
- Perspective::IS_CLIENT);
- QuicTestPacketMaker server_maker2(GetParam(), 0, clock_, origin2.host(),
- Perspective::IS_SERVER);
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 3, kClientDataStreamId2, false, true,
- GetRequestHeaders("GET", "https", "/", &client_maker2),
- &request_header_offset, &client_maker2));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 3, kClientDataStreamId2, false, false, GetResponseHeaders("200 OK"),
- &response_header_offset, &server_maker2));
- mock_quic_data.AddRead(ConstructServerDataPacket(4, kClientDataStreamId2,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(
- ConstructClientAckAndConnectionClosePacket(4, 4, 3, 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_);
-
- AddHangingNonAlternateProtocolSocketData();
- AddHangingNonAlternateProtocolSocketData();
-
- CreateSession();
-
- const char destination1[] = "first.example.com";
- const char destination2[] = "second.example.com";
-
- // Set up alternative service for |origin1|.
- AlternativeService alternative_service1(QUIC, destination1, 443);
- base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
- http_server_properties_.SetAlternativeService(
- url::SchemeHostPort(origin1), alternative_service1, expiration);
-
- // Set up multiple alternative service entries for |origin2|,
- // the first one with a different destination as for |origin1|,
- // the second one with the same. The second one should be used,
- // because the request can be pooled to that one.
- AlternativeService alternative_service2(QUIC, destination2, 443);
- AlternativeServiceInfoVector alternative_services;
- alternative_services.push_back(
- AlternativeServiceInfo(alternative_service2, expiration));
- alternative_services.push_back(
- AlternativeServiceInfo(alternative_service1, expiration));
- http_server_properties_.SetAlternativeServices(url::SchemeHostPort(origin2),
- alternative_services);
- // First request opens connection to |destination1|
- // with QuicServerId.host() == origin1.host().
- SendRequestAndExpectQuicResponse("hello!");
-
- // Second request pools to existing connection with same destination,
- // because certificate matches, even though QuicServerId is different.
- request_.url = origin2;
-
- SendRequestAndExpectQuicResponse("hello!");
-}
-
-// Multiple origins have listed the same alternative services. When there's a
-// existing QUIC session opened by a request to other origin,
-// if the cert is valid, should select this QUIC session to make the request
-// if this is also the first existing QUIC session.
-TEST_P(QuicNetworkTransactionTest,
- UseSharedExistingAlternativeServiceForQuicWithValidCert) {
- // Default cert is valid for *.example.org
-
- // HTTP data for request to www.example.org.
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Alt-Svc: quic=\":443\"\r\n\r\n"),
- MockRead("hello world from www.example.org"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- // HTTP data for request to mail.example.org.
- MockRead http_reads2[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Alt-Svc: quic=\":444\", quic=\"www.example.org:443\"\r\n\r\n"),
- MockRead("hello world from mail.example.org"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data2(http_reads2, arraysize(http_reads2),
- nullptr, 0);
- socket_factory_.AddSocketDataProvider(&http_data2);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- QuicStreamOffset request_header_offset = 0;
- QuicStreamOffset response_header_offset = 0;
-
- QuicTestPacketMaker client_maker(GetParam(), 0, clock_, "mail.example.org",
- Perspective::IS_CLIENT);
- server_maker_.set_hostname("www.example.org");
- client_maker_.set_hostname("www.example.org");
- MockQuicData mock_quic_data;
-
- // First QUIC request data.
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/"), &request_header_offset));
-
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK"),
- &response_header_offset));
- mock_quic_data.AddRead(ConstructServerDataPacket(
- 2, kClientDataStreamId1, false, true, 0, "hello from mail QUIC!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
- // Second QUIC request data.
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 3, kClientDataStreamId2, false, true,
- GetRequestHeaders("GET", "https", "/", &client_maker),
- &request_header_offset, &client_maker));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 3, kClientDataStreamId2, false, false, GetResponseHeaders("200 OK"),
- &response_header_offset));
- mock_quic_data.AddRead(ConstructServerDataPacket(
- 4, kClientDataStreamId2, false, true, 0, "hello from mail QUIC!"));
- mock_quic_data.AddWrite(
- ConstructClientAckAndConnectionClosePacket(4, 4, 3, 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_);
-
- AddHangingNonAlternateProtocolSocketData();
- CreateSession();
-
- // Send two HTTP requests, responses set up alt-svc lists for the origins.
- request_.url = GURL("https://www.example.org/");
- SendRequestAndExpectHttpResponse("hello world from www.example.org");
- request_.url = GURL("https://mail.example.org/");
- SendRequestAndExpectHttpResponse("hello world from mail.example.org");
-
- // Open a QUIC session to mail.example.org:443 when making request
- // to mail.example.org.
- request_.url = GURL("https://www.example.org/");
- SendRequestAndExpectQuicResponse("hello from mail QUIC!");
-
- // Uses the existing QUIC session when making request to www.example.org.
- request_.url = GURL("https://mail.example.org/");
- SendRequestAndExpectQuicResponse("hello from mail QUIC!");
-}
-
-TEST_P(QuicNetworkTransactionTest, AlternativeServiceDifferentPort) {
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(kQuicAlternativeServiceDifferentPortHeader),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- AddHangingNonAlternateProtocolSocketData();
- CreateSession();
-
- SendRequestAndExpectHttpResponse("hello world");
-
- url::SchemeHostPort http_server("https", kDefaultServerHostName, 443);
- AlternativeServiceVector alternative_service_vector =
- http_server_properties_.GetAlternativeServices(http_server);
- ASSERT_EQ(1u, alternative_service_vector.size());
- const AlternativeService alternative_service = alternative_service_vector[0];
- EXPECT_EQ(QUIC, alternative_service_vector[0].protocol);
- EXPECT_EQ(kDefaultServerHostName, alternative_service_vector[0].host);
- EXPECT_EQ(137, alternative_service_vector[0].port);
-}
-
-TEST_P(QuicNetworkTransactionTest, ConfirmAlternativeService) {
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"), MockRead(kQuicAlternativeServiceHeader),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 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_);
-
- AddHangingNonAlternateProtocolSocketData();
- CreateSession();
-
- AlternativeService alternative_service(QUIC,
- HostPortPair::FromURL(request_.url));
- http_server_properties_.MarkAlternativeServiceRecentlyBroken(
- alternative_service);
- EXPECT_TRUE(http_server_properties_.WasAlternativeServiceRecentlyBroken(
- alternative_service));
-
- SendRequestAndExpectHttpResponse("hello world");
- SendRequestAndExpectQuicResponse("hello!");
-
- mock_quic_data.Resume();
-
- EXPECT_FALSE(http_server_properties_.WasAlternativeServiceRecentlyBroken(
- alternative_service));
-}
-
-TEST_P(QuicNetworkTransactionTest, UseAlternativeServiceForQuicForHttps) {
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"), MockRead(kQuicAlternativeServiceHeader),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
- mock_quic_data.AddRead(SYNCHRONOUS, 0); // EOF
-
- mock_quic_data.AddSocketDataToFactory(&socket_factory_);
-
- AddHangingNonAlternateProtocolSocketData();
- CreateSession();
-
- // TODO(rtenneti): Test QUIC over HTTPS, GetSSLInfo().
- SendRequestAndExpectHttpResponse("hello world");
-}
-
-TEST_P(QuicNetworkTransactionTest, HungAlternativeService) {
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::COLD_START);
-
- MockWrite http_writes[] = {
- MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n"),
- MockWrite(SYNCHRONOUS, 1, "Host: mail.example.org\r\n"),
- MockWrite(SYNCHRONOUS, 2, "Connection: keep-alive\r\n\r\n")};
-
- MockRead http_reads[] = {
- MockRead(SYNCHRONOUS, 3, "HTTP/1.1 200 OK\r\n"),
- MockRead(SYNCHRONOUS, 4, kQuicAlternativeServiceHeader),
- MockRead(SYNCHRONOUS, 5, "hello world"), MockRead(SYNCHRONOUS, OK, 6)};
-
- SequencedSocketData http_data(http_reads, arraysize(http_reads), http_writes,
- arraysize(http_writes));
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- // The QUIC transaction will not be allowed to complete.
- MockWrite quic_writes[] = {MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 1)};
- MockRead quic_reads[] = {
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0),
- };
- SequencedSocketData quic_data(quic_reads, arraysize(quic_reads), quic_writes,
- arraysize(quic_writes));
- socket_factory_.AddSocketDataProvider(&quic_data);
-
- // The HTTP transaction will complete.
- SequencedSocketData http_data2(http_reads, arraysize(http_reads), http_writes,
- arraysize(http_writes));
- socket_factory_.AddSocketDataProvider(&http_data2);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- CreateSession();
-
- // Run the first request.
- SendRequestAndExpectHttpResponse("hello world");
- ASSERT_TRUE(http_data.AllReadDataConsumed());
- ASSERT_TRUE(http_data.AllWriteDataConsumed());
-
- // Now run the second request in which the QUIC socket hangs,
- // and verify the the transaction continues over HTTP.
- SendRequestAndExpectHttpResponse("hello world");
- base::RunLoop().RunUntilIdle();
-
- ASSERT_TRUE(http_data2.AllReadDataConsumed());
- ASSERT_TRUE(http_data2.AllWriteDataConsumed());
- ASSERT_TRUE(quic_data.AllReadDataConsumed());
-}
-
-TEST_P(QuicNetworkTransactionTest, ZeroRTTWithHttpRace) {
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
- mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read
- mock_quic_data.AddRead(ASYNC, 0); // EOF
-
- mock_quic_data.AddSocketDataToFactory(&socket_factory_);
-
- // The non-alternate protocol job needs to hang in order to guarantee that
- // the alternate-protocol job will "win".
- AddHangingNonAlternateProtocolSocketData();
-
- CreateSession();
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
- SendRequestAndExpectQuicResponse("hello!");
-}
-
-TEST_P(QuicNetworkTransactionTest, ZeroRTTWithNoHttpRace) {
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 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_);
-
- // In order for a new QUIC session to be established via alternate-protocol
- // without racing an HTTP connection, we need the host resolution to happen
- // synchronously.
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
- "");
- HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
- AddressList address;
- host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
- nullptr, net_log_.bound());
-
- AddHangingNonAlternateProtocolSocketData();
- CreateSession();
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
- SendRequestAndExpectQuicResponse("hello!");
-}
-
-TEST_P(QuicNetworkTransactionTest, ZeroRTTWithProxy) {
- proxy_service_ = ProxyService::CreateFixedFromPacResult("PROXY myproxy:70");
-
- // Since we are using a proxy, the QUIC job will not succeed.
- MockWrite http_writes[] = {
- MockWrite(SYNCHRONOUS, 0, "GET http://mail.example.org/ HTTP/1.1\r\n"),
- MockWrite(SYNCHRONOUS, 1, "Host: mail.example.org\r\n"),
- MockWrite(SYNCHRONOUS, 2, "Proxy-Connection: keep-alive\r\n\r\n")};
-
- MockRead http_reads[] = {
- MockRead(SYNCHRONOUS, 3, "HTTP/1.1 200 OK\r\n"),
- MockRead(SYNCHRONOUS, 4, kQuicAlternativeServiceHeader),
- MockRead(SYNCHRONOUS, 5, "hello world"), MockRead(SYNCHRONOUS, OK, 6)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads),
- http_writes, arraysize(http_writes));
- socket_factory_.AddSocketDataProvider(&http_data);
-
- // In order for a new QUIC session to be established via alternate-protocol
- // without racing an HTTP connection, we need the host resolution to happen
- // synchronously.
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
- "");
- HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
- AddressList address;
- host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
- nullptr, net_log_.bound());
-
- request_.url = GURL("http://mail.example.org/");
- CreateSession();
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
- SendRequestAndExpectHttpResponse("hello world");
-}
-
-TEST_P(QuicNetworkTransactionTest, ZeroRTTWithConfirmationRequired) {
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
- mock_quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // No more data to read
- mock_quic_data.AddSocketDataToFactory(&socket_factory_);
-
- // The non-alternate protocol job needs to hang in order to guarantee that
- // the alternate-protocol job will "win".
- AddHangingNonAlternateProtocolSocketData();
-
- // In order for a new QUIC session to be established via alternate-protocol
- // without racing an HTTP connection, we need the host resolution to happen
- // synchronously. Of course, even though QUIC *could* perform a 0-RTT
- // connection to the the server, in this test we require confirmation
- // before encrypting so the HTTP job will still start.
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
- "");
- HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
- AddressList address;
- host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
- nullptr, net_log_.bound());
-
- CreateSession();
- session_->quic_stream_factory()->set_require_confirmation(true);
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
-
- std::unique_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), net_log_.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
- QuicSession::HANDSHAKE_CONFIRMED);
- EXPECT_EQ(OK, callback.WaitForResult());
-
- CheckWasQuicResponse(trans);
- CheckResponseData(trans, "hello!");
-}
-
-TEST_P(QuicNetworkTransactionTest,
- LogGranularQuicErrorCodeOnQuicProtocolErrorLocal) {
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- // Read a close connection packet with
- // QuicErrorCode: QUIC_CRYPTO_VERSION_NOT_SUPPORTED from the peer.
- mock_quic_data.AddRead(ConstructServerConnectionClosePacket(1));
- mock_quic_data.AddSocketDataToFactory(&socket_factory_);
-
- // The non-alternate protocol job needs to hang in order to guarantee that
- // the alternate-protocol job will "win".
- AddHangingNonAlternateProtocolSocketData();
-
- // In order for a new QUIC session to be established via alternate-protocol
- // without racing an HTTP connection, we need the host resolution to happen
- // synchronously. Of course, even though QUIC *could* perform a 0-RTT
- // connection to the the server, in this test we require confirmation
- // before encrypting so the HTTP job will still start.
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
- "");
- HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
- AddressList address;
- host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
- nullptr, net_log_.bound());
-
- CreateSession();
- session_->quic_stream_factory()->set_require_confirmation(true);
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
-
- std::unique_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), net_log_.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
- QuicSession::HANDSHAKE_CONFIRMED);
- EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, callback.WaitForResult());
-
- NetErrorDetails details;
- EXPECT_EQ(QUIC_NO_ERROR, details.quic_connection_error);
-
- trans->PopulateNetErrorDetails(&details);
- // Verify the error code logged is what sent by the peer.
- EXPECT_EQ(QUIC_CRYPTO_VERSION_NOT_SUPPORTED, details.quic_connection_error);
-}
-
-TEST_P(QuicNetworkTransactionTest,
- LogGranularQuicErrorCodeOnQuicProtocolErrorRemote) {
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- // Peer sending data from an non-existing stream causes this end to raise
- // error and close connection.
- mock_quic_data.AddRead(
- ConstructServerRstPacket(1, false, 99, QUIC_STREAM_LAST_ERROR));
- std::string quic_error_details = "Data for nonexistent stream";
- mock_quic_data.AddWrite(ConstructClientAckAndConnectionClosePacket(
- 2, QuicTime::Delta::Infinite(), 0, 1, QUIC_INVALID_STREAM_ID,
- quic_error_details));
- mock_quic_data.AddSocketDataToFactory(&socket_factory_);
-
- // The non-alternate protocol job needs to hang in order to guarantee that
- // the alternate-protocol job will "win".
- AddHangingNonAlternateProtocolSocketData();
-
- // In order for a new QUIC session to be established via alternate-protocol
- // without racing an HTTP connection, we need the host resolution to happen
- // synchronously. Of course, even though QUIC *could* perform a 0-RTT
- // connection to the the server, in this test we require confirmation
- // before encrypting so the HTTP job will still start.
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
- "");
- HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
- AddressList address;
- host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
- nullptr, net_log_.bound());
-
- CreateSession();
- session_->quic_stream_factory()->set_require_confirmation(true);
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
-
- std::unique_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), net_log_.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
- QuicSession::HANDSHAKE_CONFIRMED);
- EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, callback.WaitForResult());
- NetErrorDetails details;
- EXPECT_EQ(QUIC_NO_ERROR, details.quic_connection_error);
-
- trans->PopulateNetErrorDetails(&details);
- EXPECT_EQ(QUIC_INVALID_STREAM_ID, details.quic_connection_error);
-}
-
-TEST_P(QuicNetworkTransactionTest, RstSteamErrorHandling) {
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- // Read the response headers, then a RST_STREAM frame.
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
- mock_quic_data.AddRead(ConstructServerRstPacket(
- 2, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
- mock_quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // No more read data.
- mock_quic_data.AddSocketDataToFactory(&socket_factory_);
-
- // The non-alternate protocol job needs to hang in order to guarantee that
- // the alternate-protocol job will "win".
- AddHangingNonAlternateProtocolSocketData();
-
- // In order for a new QUIC session to be established via alternate-protocol
- // without racing an HTTP connection, we need the host resolution to happen
- // synchronously. Of course, even though QUIC *could* perform a 0-RTT
- // connection to the the server, in this test we require confirmation
- // before encrypting so the HTTP job will still start.
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
- "");
- HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
- AddressList address;
- host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
- nullptr, net_log_.bound());
-
- CreateSession();
- session_->quic_stream_factory()->set_require_confirmation(true);
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
-
- std::unique_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), net_log_.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
- QuicSession::HANDSHAKE_CONFIRMED);
- // Read the headers.
- EXPECT_EQ(OK, callback.WaitForResult());
-
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response != nullptr);
- ASSERT_TRUE(response->headers.get() != nullptr);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
- EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_QUIC1_SPDY3,
- response->connection_info);
-
- std::string response_data;
- ASSERT_EQ(ERR_QUIC_PROTOCOL_ERROR,
- ReadTransaction(trans.get(), &response_data));
-}
-
-TEST_P(QuicNetworkTransactionTest, RstSteamBeforeHeaders) {
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- mock_quic_data.AddRead(ConstructServerRstPacket(
- 1, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
- mock_quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // No more read data.
- mock_quic_data.AddSocketDataToFactory(&socket_factory_);
-
- // The non-alternate protocol job needs to hang in order to guarantee that
- // the alternate-protocol job will "win".
- AddHangingNonAlternateProtocolSocketData();
-
- // In order for a new QUIC session to be established via alternate-protocol
- // without racing an HTTP connection, we need the host resolution to happen
- // synchronously. Of course, even though QUIC *could* perform a 0-RTT
- // connection to the the server, in this test we require confirmation
- // before encrypting so the HTTP job will still start.
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
- "");
- HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
- AddressList address;
- host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
- nullptr, net_log_.bound());
-
- CreateSession();
- session_->quic_stream_factory()->set_require_confirmation(true);
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
-
- std::unique_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), net_log_.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
- QuicSession::HANDSHAKE_CONFIRMED);
- // Read the headers.
- EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, callback.WaitForResult());
-}
-
-TEST_P(QuicNetworkTransactionTest, BrokenAlternateProtocol) {
- // Alternate-protocol job
- std::unique_ptr<QuicEncryptedPacket> close(
- ConstructServerConnectionClosePacket(1));
- MockRead quic_reads[] = {
- MockRead(ASYNC, close->data(), close->length()),
- MockRead(ASYNC, ERR_IO_PENDING), // No more data to read
- MockRead(ASYNC, OK), // EOF
- };
- StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&quic_data);
-
- // Main job which will succeed even though the alternate job fails.
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello from http"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- CreateSession();
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START);
- SendRequestAndExpectHttpResponse("hello from http");
- ExpectBrokenAlternateProtocolMapping();
-}
-
-TEST_P(QuicNetworkTransactionTest, BrokenAlternateProtocolReadError) {
- // Alternate-protocol job
- MockRead quic_reads[] = {
- MockRead(ASYNC, ERR_SOCKET_NOT_CONNECTED),
- };
- StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&quic_data);
-
- // Main job which will succeed even though the alternate job fails.
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello from http"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- CreateSession();
-
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START);
- SendRequestAndExpectHttpResponse("hello from http");
- ExpectBrokenAlternateProtocolMapping();
-}
-
-TEST_P(QuicNetworkTransactionTest, NoBrokenAlternateProtocolIfTcpFails) {
- // Alternate-protocol job will fail when the session attempts to read.
- MockRead quic_reads[] = {
- MockRead(ASYNC, ERR_SOCKET_NOT_CONNECTED),
- };
- StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&quic_data);
-
- // Main job will also fail.
- MockRead http_reads[] = {
- MockRead(ASYNC, ERR_SOCKET_NOT_CONNECTED),
- };
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- http_data.set_connect_data(MockConnect(ASYNC, ERR_SOCKET_NOT_CONNECTED));
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- AddHangingNonAlternateProtocolSocketData();
- CreateSession();
-
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START);
- std::unique_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), net_log_.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, callback.WaitForResult());
- ExpectQuicAlternateProtocolMapping();
-}
-
-TEST_P(QuicNetworkTransactionTest, FailedZeroRttBrokenAlternateProtocol) {
- // Alternate-protocol job
- MockRead quic_reads[] = {
- MockRead(ASYNC, ERR_SOCKET_NOT_CONNECTED),
- };
- StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&quic_data);
-
- // Second Alternate-protocol job which will race with the TCP job.
- StaticSocketDataProvider quic_data2(quic_reads, arraysize(quic_reads),
- nullptr, 0);
- socket_factory_.AddSocketDataProvider(&quic_data2);
-
- // Final job that will proceed when the QUIC job fails.
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello from http"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- AddHangingNonAlternateProtocolSocketData();
- CreateSession();
-
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
-
- SendRequestAndExpectHttpResponse("hello from http");
-
- ExpectBrokenAlternateProtocolMapping();
-
- EXPECT_TRUE(quic_data.AllReadDataConsumed());
- EXPECT_TRUE(quic_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicNetworkTransactionTest, DISABLED_HangingZeroRttFallback) {
- // Alternate-protocol job
- MockRead quic_reads[] = {
- MockRead(SYNCHRONOUS, ERR_IO_PENDING),
- };
- StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&quic_data);
-
- // Main job that will proceed when the QUIC job fails.
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello from http"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&http_data);
-
- AddHangingNonAlternateProtocolSocketData();
- CreateSession();
-
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
-
- SendRequestAndExpectHttpResponse("hello from http");
-}
-
-TEST_P(QuicNetworkTransactionTest, BrokenAlternateProtocolOnConnectFailure) {
- // Alternate-protocol job will fail before creating a QUIC session.
- StaticSocketDataProvider quic_data(nullptr, 0, nullptr, 0);
- quic_data.set_connect_data(
- MockConnect(SYNCHRONOUS, ERR_INTERNET_DISCONNECTED));
- socket_factory_.AddSocketDataProvider(&quic_data);
-
- // Main job which will succeed even though the alternate job fails.
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello from http"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- CreateSession();
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START);
- SendRequestAndExpectHttpResponse("hello from http");
-
- ExpectBrokenAlternateProtocolMapping();
-}
-
-TEST_P(QuicNetworkTransactionTest, ConnectionCloseDuringConnect) {
- MockQuicData mock_quic_data;
- mock_quic_data.AddSynchronousRead(ConstructServerConnectionClosePacket(1));
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
- mock_quic_data.AddSocketDataToFactory(&socket_factory_);
-
- // When the QUIC connection fails, we will try the request again over HTTP.
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"), MockRead(kQuicAlternativeServiceHeader),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
-
- StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
- 0);
- socket_factory_.AddSocketDataProvider(&http_data);
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
-
- // In order for a new QUIC session to be established via alternate-protocol
- // without racing an HTTP connection, we need the host resolution to happen
- // synchronously.
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
- "");
- HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
- AddressList address;
- host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
- nullptr, net_log_.bound());
-
- CreateSession();
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
- SendRequestAndExpectHttpResponse("hello world");
-}
-
-TEST_P(QuicNetworkTransactionTest, SecureResourceOverSecureQuic) {
- client_maker_.set_hostname("www.example.org");
- EXPECT_FALSE(
- test_socket_performance_watcher_factory_.rtt_notification_received());
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
- mock_quic_data.AddRead(ConstructServerDataPacket(2, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 1));
- mock_quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // No more read data.
- mock_quic_data.AddSocketDataToFactory(&socket_factory_);
-
- request_.url = GURL("https://www.example.org:443");
- AddHangingNonAlternateProtocolSocketData();
- CreateSession();
- AddQuicAlternateProtocolMapping(MockCryptoClientStream::CONFIRM_HANDSHAKE);
- SendRequestAndExpectQuicResponse("hello!");
- EXPECT_TRUE(
- test_socket_performance_watcher_factory_.rtt_notification_received());
-}
-
-TEST_P(QuicNetworkTransactionTest, QuicUpload) {
- params_.origins_to_force_quic_on.insert(
- HostPortPair::FromString("mail.example.org:443"));
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- MockWrite writes[] = {MockWrite(SYNCHRONOUS, ERR_FAILED, 1)};
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // The non-alternate protocol job needs to hang in order to guarantee that
- // the alternate-protocol job will "win".
- AddHangingNonAlternateProtocolSocketData();
-
- CreateSession();
- request_.method = "POST";
- ChunkedUploadDataStream upload_data(0);
- upload_data.AppendData("1", 1, true);
-
- request_.upload_data_stream = &upload_data;
-
- std::unique_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), net_log_.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_NE(OK, callback.WaitForResult());
-}
-
-// Adds coverage to catch regression such as https://crbug.com/622043
-TEST_P(QuicNetworkTransactionTest, QuicServerPush) {
- params_.origins_to_force_quic_on.insert(
- HostPortPair::FromString("mail.example.org:443"));
-
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, true,
- GetRequestHeaders("GET", "https", "/")));
- QuicStreamOffset server_header_offset = 0;
- mock_quic_data.AddRead(ConstructServerPushPromisePacket(
- 1, kClientDataStreamId1, kServerDataStreamId1, false,
- GetRequestHeaders("GET", "https", "/pushed.jpg"), &server_header_offset,
- &server_maker_));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 2, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK"),
- &server_header_offset));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 2, 1, 1));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 3, kServerDataStreamId1, false, false, GetResponseHeaders("200 OK"),
- &server_header_offset));
- mock_quic_data.AddRead(ConstructServerDataPacket(4, kClientDataStreamId1,
- false, true, 0, "hello!"));
- mock_quic_data.AddWrite(ConstructClientAckPacket(3, 4, 3, 1));
- mock_quic_data.AddRead(ConstructServerDataPacket(
- 5, kServerDataStreamId1, false, true, 0, "and hello!"));
- mock_quic_data.AddWrite(
- ConstructClientAckAndRstPacket(4, 4, QUIC_RST_ACKNOWLEDGEMENT, 5, 5, 1));
- mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read
- mock_quic_data.AddRead(ASYNC, 0); // EOF
- mock_quic_data.AddSocketDataToFactory(&socket_factory_);
-
- // The non-alternate protocol job needs to hang in order to guarantee that
- // the alternate-protocol job will "win".
- AddHangingNonAlternateProtocolSocketData();
-
- CreateSession();
-
- // PUSH_PROMISE handling in the http layer gets exercised here.
- SendRequestAndExpectQuicResponse("hello!");
-
- request_.url = GURL("https://mail.example.org/pushed.jpg");
- SendRequestAndExpectQuicResponse("and hello!");
-
- // Check that the NetLog was filled reasonably.
- TestNetLogEntry::List entries;
- net_log_.GetEntries(&entries);
- EXPECT_LT(0u, entries.size());
-
- // Check that we logged a QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM
- int pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_QUIC_HTTP_STREAM_ADOPTED_PUSH_STREAM,
- NetLog::PHASE_NONE);
- EXPECT_LT(0, pos);
-}
-
-class QuicNetworkTransactionWithDestinationTest
- : public PlatformTest,
- public ::testing::WithParamInterface<PoolingTestParams> {
- protected:
- QuicNetworkTransactionWithDestinationTest()
- : clock_(new MockClock),
- version_(GetParam().version),
- destination_type_(GetParam().destination_type),
- cert_transparency_verifier_(new MultiLogCTVerifier()),
- ssl_config_service_(new SSLConfigServiceDefaults),
- proxy_service_(ProxyService::CreateDirect()),
- auth_handler_factory_(
- HttpAuthHandlerFactory::CreateDefault(&host_resolver_)),
- random_generator_(0),
- ssl_data_(ASYNC, OK) {}
-
- void SetUp() override {
- NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
- base::RunLoop().RunUntilIdle();
-
- HttpNetworkSession::Params params;
-
- clock_->AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
- params.quic_clock = clock_;
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::CONFIRM_HANDSHAKE);
- params.quic_crypto_client_stream_factory = &crypto_client_stream_factory_;
-
- params.enable_quic = true;
- params.quic_random = &random_generator_;
- params.client_socket_factory = &socket_factory_;
- params.host_resolver = &host_resolver_;
- params.cert_verifier = &cert_verifier_;
- params.transport_security_state = &transport_security_state_;
- params.cert_transparency_verifier = cert_transparency_verifier_.get();
- params.ct_policy_enforcer = &ct_policy_enforcer_;
- params.socket_performance_watcher_factory =
- &test_socket_performance_watcher_factory_;
- params.ssl_config_service = ssl_config_service_.get();
- params.proxy_service = proxy_service_.get();
- params.http_auth_handler_factory = auth_handler_factory_.get();
- params.http_server_properties = &http_server_properties_;
- params.quic_supported_versions = SupportedVersions(version_);
- params.quic_host_whitelist.insert("news.example.org");
- params.quic_host_whitelist.insert("mail.example.org");
- params.quic_host_whitelist.insert("mail.example.com");
-
- session_.reset(new HttpNetworkSession(params));
- session_->quic_stream_factory()->set_require_confirmation(true);
- ASSERT_EQ(params.quic_socket_receive_buffer_size,
- session_->quic_stream_factory()->socket_receive_buffer_size());
- }
-
- void TearDown() override {
- NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
- // Empty the current queue.
- base::RunLoop().RunUntilIdle();
- PlatformTest::TearDown();
- NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
- base::RunLoop().RunUntilIdle();
- session_.reset();
- }
-
- void SetAlternativeService(const std::string& origin) {
- HostPortPair destination;
- switch (destination_type_) {
- case SAME_AS_FIRST:
- destination = HostPortPair(origin1_, 443);
- break;
- case SAME_AS_SECOND:
- destination = HostPortPair(origin2_, 443);
- break;
- case DIFFERENT:
- destination = HostPortPair(kDifferentHostname, 443);
- break;
- }
- AlternativeService alternative_service(QUIC, destination);
- base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
- http_server_properties_.SetAlternativeService(
- url::SchemeHostPort("https", origin, 443), alternative_service,
- expiration);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool should_include_version,
- QuicStreamOffset* offset,
- QuicTestPacketMaker* maker) {
- SpdyPriority priority =
- ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY);
- SpdyHeaderBlock headers(maker->GetRequestHeaders("GET", "https", "/"));
- return maker->MakeRequestHeadersPacketWithOffsetTracking(
- packet_number, stream_id, should_include_version, true, priority,
- std::move(headers), offset);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructClientRequestHeadersPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool should_include_version,
- QuicTestPacketMaker* maker) {
- return ConstructClientRequestHeadersPacket(
- packet_number, stream_id, should_include_version, nullptr, maker);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructServerResponseHeadersPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- QuicStreamOffset* offset,
- QuicTestPacketMaker* maker) {
- SpdyHeaderBlock headers(maker->GetResponseHeaders("200 OK"));
- return maker->MakeResponseHeadersPacketWithOffsetTracking(
- packet_number, stream_id, false, false, std::move(headers), offset);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructServerResponseHeadersPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- QuicTestPacketMaker* maker) {
- return ConstructServerResponseHeadersPacket(packet_number, stream_id,
- nullptr, maker);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructServerDataPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- QuicTestPacketMaker* maker) {
- return maker->MakeDataPacket(packet_number, stream_id, false, true, 0,
- "hello");
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructClientAckPacket(
- QuicPacketNumber packet_number,
- QuicPacketNumber largest_received,
- QuicPacketNumber ack_least_unacked,
- QuicPacketNumber stop_least_unacked,
- QuicTestPacketMaker* maker) {
- return maker->MakeAckPacket(packet_number, largest_received,
- ack_least_unacked, stop_least_unacked, true);
- }
-
- void AddRefusedSocketData() {
- std::unique_ptr<StaticSocketDataProvider> refused_data(
- new StaticSocketDataProvider());
- MockConnect refused_connect(SYNCHRONOUS, ERR_CONNECTION_REFUSED);
- refused_data->set_connect_data(refused_connect);
- socket_factory_.AddSocketDataProvider(refused_data.get());
- static_socket_data_provider_vector_.push_back(std::move(refused_data));
- }
-
- void AddHangingSocketData() {
- std::unique_ptr<StaticSocketDataProvider> hanging_data(
- new StaticSocketDataProvider());
- MockConnect hanging_connect(SYNCHRONOUS, ERR_IO_PENDING);
- hanging_data->set_connect_data(hanging_connect);
- socket_factory_.AddSocketDataProvider(hanging_data.get());
- static_socket_data_provider_vector_.push_back(std::move(hanging_data));
- socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
- }
-
- bool AllDataConsumed() {
- for (const auto& socket_data_ptr : static_socket_data_provider_vector_) {
- if (!socket_data_ptr->AllReadDataConsumed() ||
- !socket_data_ptr->AllWriteDataConsumed()) {
- return false;
- }
- }
- return true;
- }
-
- void SendRequestAndExpectQuicResponse(const std::string& host) {
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
- HttpRequestInfo request;
- std::string url("https://");
- url.append(host);
- request.url = GURL(url);
- request.load_flags = 0;
- request.method = "GET";
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), net_log_.bound());
- EXPECT_EQ(OK, callback.GetResult(rv));
-
- std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(&trans, &response_data));
- EXPECT_EQ("hello", response_data);
-
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response != nullptr);
- ASSERT_TRUE(response->headers.get() != nullptr);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
- EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_QUIC1_SPDY3,
- response->connection_info);
- EXPECT_EQ(443, response->socket_address.port());
- }
-
- MockClock* clock_;
- QuicVersion version_;
- DestinationType destination_type_;
- std::string origin1_;
- std::string origin2_;
- std::unique_ptr<HttpNetworkSession> session_;
- MockClientSocketFactory socket_factory_;
- MockHostResolver host_resolver_;
- MockCertVerifier cert_verifier_;
- TransportSecurityState transport_security_state_;
- std::unique_ptr<CTVerifier> cert_transparency_verifier_;
- CTPolicyEnforcer ct_policy_enforcer_;
- TestSocketPerformanceWatcherFactory test_socket_performance_watcher_factory_;
- scoped_refptr<SSLConfigServiceDefaults> ssl_config_service_;
- std::unique_ptr<ProxyService> proxy_service_;
- std::unique_ptr<HttpAuthHandlerFactory> auth_handler_factory_;
- MockRandom random_generator_;
- HttpServerPropertiesImpl http_server_properties_;
- BoundTestNetLog net_log_;
- MockCryptoClientStreamFactory crypto_client_stream_factory_;
- std::vector<std::unique_ptr<StaticSocketDataProvider>>
- static_socket_data_provider_vector_;
- SSLSocketDataProvider ssl_data_;
-};
-
-INSTANTIATE_TEST_CASE_P(Version,
- QuicNetworkTransactionWithDestinationTest,
- ::testing::ValuesIn(GetPoolingTestParams()));
-
-// A single QUIC request fails because the certificate does not match the origin
-// hostname, regardless of whether it matches the alternative service hostname.
-TEST_P(QuicNetworkTransactionWithDestinationTest, InvalidCertificate) {
- if (destination_type_ == DIFFERENT)
- return;
-
- GURL url("https://mail.example.com/");
- origin1_ = url.host();
-
- // Not used for requests, but this provides a test case where the certificate
- // is valid for the hostname of the alternative service.
- origin2_ = "mail.example.org";
-
- SetAlternativeService(origin1_);
-
- scoped_refptr<X509Certificate> cert(
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
- bool unused;
- ASSERT_FALSE(cert->VerifyNameMatch(origin1_, &unused));
- ASSERT_TRUE(cert->VerifyNameMatch(origin2_, &unused));
-
- 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;
- mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING);
- mock_quic_data.AddRead(ASYNC, 0);
-
- mock_quic_data.AddSocketDataToFactory(&socket_factory_);
-
- AddRefusedSocketData();
-
- HttpRequestInfo request;
- request.url = url;
-
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), net_log_.bound());
- EXPECT_EQ(ERR_CONNECTION_REFUSED, callback.GetResult(rv));
-
- EXPECT_TRUE(AllDataConsumed());
-}
-
-// First request opens QUIC session to alternative service. Second request
-// pools to it, because destination matches and certificate is valid, even
-// though QuicServerId is different.
-TEST_P(QuicNetworkTransactionWithDestinationTest, PoolIfCertificateValid) {
- origin1_ = "mail.example.org";
- origin2_ = "news.example.org";
-
- SetAlternativeService(origin1_);
- SetAlternativeService(origin2_);
-
- scoped_refptr<X509Certificate> cert(
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
- bool unused;
- ASSERT_TRUE(cert->VerifyNameMatch(origin1_, &unused));
- ASSERT_TRUE(cert->VerifyNameMatch(origin2_, &unused));
- ASSERT_FALSE(cert->VerifyNameMatch(kDifferentHostname, &unused));
-
- 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);
-
- QuicTestPacketMaker client_maker1(version_, 0, clock_, origin1_,
- Perspective::IS_CLIENT);
- QuicTestPacketMaker server_maker1(version_, 0, clock_, origin1_,
- Perspective::IS_SERVER);
-
- QuicStreamOffset request_header_offset(0);
- QuicStreamOffset response_header_offset(0);
-
- MockQuicData mock_quic_data;
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, &request_header_offset, &client_maker1));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, &response_header_offset, &server_maker1));
- mock_quic_data.AddRead(
- ConstructServerDataPacket(2, kClientDataStreamId1, &server_maker1));
- mock_quic_data.AddWrite(ConstructClientAckPacket(2, 2, 1, 1, &client_maker1));
-
- QuicTestPacketMaker client_maker2(version_, 0, clock_, origin2_,
- Perspective::IS_CLIENT);
- QuicTestPacketMaker server_maker2(version_, 0, clock_, origin2_,
- Perspective::IS_SERVER);
-
- mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
- 3, kClientDataStreamId2, false, &request_header_offset, &client_maker2));
- mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
- 3, kClientDataStreamId2, &response_header_offset, &server_maker2));
- mock_quic_data.AddRead(
- ConstructServerDataPacket(4, kClientDataStreamId2, &server_maker2));
- mock_quic_data.AddWrite(ConstructClientAckPacket(4, 4, 3, 1, &client_maker2));
- 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_);
-
- AddHangingSocketData();
- AddHangingSocketData();
-
- SendRequestAndExpectQuicResponse(origin1_);
- SendRequestAndExpectQuicResponse(origin2_);
-
- EXPECT_TRUE(AllDataConsumed());
-}
-
-// First request opens QUIC session to alternative service. Second request does
-// not pool to it, even though destination matches, because certificate is not
-// valid. Instead, a new QUIC session is opened to the same destination with a
-// different QuicServerId.
-TEST_P(QuicNetworkTransactionWithDestinationTest,
- DoNotPoolIfCertificateInvalid) {
- origin1_ = "news.example.org";
- origin2_ = "mail.example.com";
-
- SetAlternativeService(origin1_);
- SetAlternativeService(origin2_);
-
- scoped_refptr<X509Certificate> cert1(
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
- bool unused;
- ASSERT_TRUE(cert1->VerifyNameMatch(origin1_, &unused));
- ASSERT_FALSE(cert1->VerifyNameMatch(origin2_, &unused));
- ASSERT_FALSE(cert1->VerifyNameMatch(kDifferentHostname, &unused));
-
- scoped_refptr<X509Certificate> cert2(
- ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"));
- ASSERT_TRUE(cert2->VerifyNameMatch(origin2_, &unused));
- ASSERT_FALSE(cert2->VerifyNameMatch(kDifferentHostname, &unused));
-
- ProofVerifyDetailsChromium verify_details1;
- verify_details1.cert_verify_result.verified_cert = cert1;
- verify_details1.cert_verify_result.is_issued_by_known_root = true;
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details1);
-
- ProofVerifyDetailsChromium verify_details2;
- verify_details2.cert_verify_result.verified_cert = cert2;
- 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 server_maker1(version_, 0, clock_, origin1_,
- Perspective::IS_SERVER);
-
- MockQuicData mock_quic_data1;
- mock_quic_data1.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, &client_maker1));
- mock_quic_data1.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, &server_maker1));
- mock_quic_data1.AddRead(
- ConstructServerDataPacket(2, kClientDataStreamId1, &server_maker1));
- mock_quic_data1.AddWrite(
- ConstructClientAckPacket(2, 2, 1, 1, &client_maker1));
- mock_quic_data1.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read
- mock_quic_data1.AddRead(ASYNC, 0); // EOF
-
- mock_quic_data1.AddSocketDataToFactory(&socket_factory_);
-
- AddHangingSocketData();
-
- QuicTestPacketMaker client_maker2(version_, 0, clock_, origin2_,
- Perspective::IS_CLIENT);
- QuicTestPacketMaker server_maker2(version_, 0, clock_, origin2_,
- Perspective::IS_SERVER);
-
- MockQuicData mock_quic_data2;
- mock_quic_data2.AddWrite(ConstructClientRequestHeadersPacket(
- 1, kClientDataStreamId1, true, &client_maker2));
- mock_quic_data2.AddRead(ConstructServerResponseHeadersPacket(
- 1, kClientDataStreamId1, &server_maker2));
- mock_quic_data2.AddRead(
- ConstructServerDataPacket(2, kClientDataStreamId1, &server_maker2));
- mock_quic_data2.AddWrite(
- ConstructClientAckPacket(2, 2, 1, 1, &client_maker2));
- 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_);
-
- AddHangingSocketData();
-
- SendRequestAndExpectQuicResponse(origin1_);
- SendRequestAndExpectQuicResponse(origin2_);
-
- EXPECT_TRUE(AllDataConsumed());
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_one_block_arena.h b/chromium/net/quic/quic_one_block_arena.h
deleted file mode 100644
index 37fc7307902..00000000000
--- a/chromium/net/quic/quic_one_block_arena.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// An arena that consists of a single inlined block of |ArenaSize|. Useful to
-// avoid repeated calls to malloc/new and to improve memory locality. DCHECK's
-// if an allocation out of the arena ever fails in debug builds; falls back to
-// heap allocation in release builds.
-
-#ifndef NET_QUIC_QUIC_ONE_BLOCK_ARENA_H_
-#define NET_QUIC_QUIC_ONE_BLOCK_ARENA_H_
-
-#include "net/quic/quic_arena_scoped_ptr.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-
-#define PREDICT_FALSE(x) x
-
-namespace net {
-
-template <uint32_t ArenaSize>
-class QuicOneBlockArena {
- static const uint32_t kMaxAlign = 8;
-
- public:
- QuicOneBlockArena();
-
- // Instantiates an object of type |T| with |args|. |args| are perfectly
- // forwarded to |T|'s constructor. The returned pointer's lifetime is
- // controlled by QuicArenaScopedPtr.
- template <typename T, typename... Args>
- QuicArenaScopedPtr<T> New(Args&&... args);
-
- private:
- // Returns the size of |T| aligned up to |kMaxAlign|.
- template <typename T>
- static inline uint32_t AlignedSize() {
- return ((sizeof(T) + (kMaxAlign - 1)) / kMaxAlign) * kMaxAlign;
- }
-
- // Actual storage.
- // Subtle/annoying: the value '8' must be coded explicitly into the alignment
- // declaration for MSVC.
- QUIC_ALIGNED(8) char storage_[ArenaSize];
- // Current offset into the storage.
- uint32_t offset_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicOneBlockArena);
-};
-
-template <uint32_t ArenaSize>
-QuicOneBlockArena<ArenaSize>::QuicOneBlockArena() : offset_(0) {}
-
-template <uint32_t ArenaSize>
-template <typename T, typename... Args>
-QuicArenaScopedPtr<T> QuicOneBlockArena<ArenaSize>::New(Args&&... args) {
- DCHECK_LT(AlignedSize<T>(), ArenaSize)
- << "Object is too large for the arena.";
- static_assert(QUIC_ALIGN_OF(T) > 1,
- "Objects added to the arena must be at least 2B aligned.");
- if (PREDICT_FALSE(offset_ > ArenaSize - AlignedSize<T>())) {
- LOG(DFATAL) << "Ran out of space in QuicOneBlockArena at " << this
- << ", max size was " << ArenaSize << ", failing request was "
- << AlignedSize<T>() << ", end of arena was " << offset_;
- return QuicArenaScopedPtr<T>(new T(std::forward<Args>(args)...));
- }
-
- void* buf = &storage_[offset_];
- new (buf) T(std::forward<Args>(args)...);
- offset_ += AlignedSize<T>();
- return QuicArenaScopedPtr<T>(buf,
- QuicArenaScopedPtr<T>::ConstructFrom::kArena);
-}
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_ONE_BLOCK_ARENA_H_
diff --git a/chromium/net/quic/quic_one_block_arena_test.cc b/chromium/net/quic/quic_one_block_arena_test.cc
deleted file mode 100644
index 39e7767c356..00000000000
--- a/chromium/net/quic/quic_one_block_arena_test.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_one_block_arena.h"
-
-#include "net/quic/interval_set.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-#include "net/test/gtest_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace {
-
-static const uint32_t kMaxAlign = 8;
-
-struct TestObject {
- uint32_t value;
-};
-
-TEST(QuicOneBlockArenaTest, AllocateSuccess) {
- QuicOneBlockArena<1024> arena;
- QuicArenaScopedPtr<TestObject> ptr = arena.New<TestObject>();
- EXPECT_TRUE(ptr.is_from_arena());
-}
-
-TEST(QuicOneBlockArenaTest, Exhaust) {
- QuicOneBlockArena<1024> arena;
- for (size_t i = 0; i < 1024 / kMaxAlign; ++i) {
- QuicArenaScopedPtr<TestObject> ptr = arena.New<TestObject>();
- EXPECT_TRUE(ptr.is_from_arena());
- }
- QuicArenaScopedPtr<TestObject> ptr;
- EXPECT_DFATAL(ptr = arena.New<TestObject>(),
- "Ran out of space in QuicOneBlockArena");
- EXPECT_FALSE(ptr.is_from_arena());
-}
-
-TEST(QuicOneBlockArenaTest, NoOverlaps) {
- QuicOneBlockArena<1024> arena;
- std::vector<QuicArenaScopedPtr<TestObject>> objects;
- IntervalSet<uintptr_t> used;
- for (size_t i = 0; i < 1024 / kMaxAlign; ++i) {
- QuicArenaScopedPtr<TestObject> ptr = arena.New<TestObject>();
- EXPECT_TRUE(ptr.is_from_arena());
-
- uintptr_t begin = reinterpret_cast<uintptr_t>(ptr.get());
- uintptr_t end = begin + sizeof(TestObject);
- EXPECT_FALSE(used.Contains(begin));
- EXPECT_FALSE(used.Contains(end - 1));
- used.Add(begin, end);
- }
-}
-
-} // namespace
-} // namespace net
diff --git a/chromium/net/quic/quic_packet_creator.cc b/chromium/net/quic/quic_packet_creator.cc
deleted file mode 100644
index b940c99b739..00000000000
--- a/chromium/net/quic/quic_packet_creator.cc
+++ /dev/null
@@ -1,724 +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/quic_packet_creator.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_data_writer.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-
-using base::StringPiece;
-using std::make_pair;
-using std::max;
-using std::min;
-using std::pair;
-using std::string;
-using std::vector;
-
-namespace net {
-
-QuicPacketCreator::QuicPacketCreator(QuicConnectionId connection_id,
- QuicFramer* framer,
- QuicRandom* random_generator,
- QuicBufferAllocator* buffer_allocator,
- DelegateInterface* delegate)
- : delegate_(delegate),
- debug_delegate_(nullptr),
- framer_(framer),
- random_bool_source_(random_generator),
- buffer_allocator_(buffer_allocator),
- send_version_in_packet_(framer->perspective() == Perspective::IS_CLIENT),
- send_path_id_in_packet_(false),
- next_packet_number_length_(PACKET_1BYTE_PACKET_NUMBER),
- have_diversification_nonce_(false),
- max_packet_length_(0),
- connection_id_length_(PACKET_8BYTE_CONNECTION_ID),
- packet_size_(0),
- connection_id_(connection_id),
- packet_(kDefaultPathId,
- 0,
- PACKET_1BYTE_PACKET_NUMBER,
- nullptr,
- 0,
- 0,
- false,
- false) {
- SetMaxPacketLength(kDefaultMaxPacketSize);
-}
-
-QuicPacketCreator::~QuicPacketCreator() {
- QuicUtils::DeleteFrames(&packet_.retransmittable_frames);
-}
-
-void QuicPacketCreator::SetEncrypter(EncryptionLevel level,
- QuicEncrypter* encrypter) {
- framer_->SetEncrypter(level, encrypter);
- max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_);
-}
-
-bool QuicPacketCreator::CanSetMaxPacketLength() const {
- // |max_packet_length_| should not be changed mid-packet.
- return queued_frames_.empty();
-}
-
-void QuicPacketCreator::SetMaxPacketLength(QuicByteCount length) {
- DCHECK(CanSetMaxPacketLength());
-
- // Avoid recomputing |max_plaintext_size_| if the length does not actually
- // change.
- if (length == max_packet_length_) {
- return;
- }
-
- max_packet_length_ = length;
- max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_);
-}
-
-void QuicPacketCreator::MaybeUpdatePacketNumberLength() {
- DCHECK(!FLAGS_quic_simple_packet_number_length);
- if (!queued_frames_.empty()) {
- // Don't change creator state if there are frames queued.
- return;
- }
-
- // Update packet number length only on packet boundary.
- packet_.packet_number_length = next_packet_number_length_;
-}
-
-// Stops serializing version of the protocol in packets sent after this call.
-// A packet that is already open might send kQuicVersionSize bytes less than the
-// maximum packet size if we stop sending version before it is serialized.
-void QuicPacketCreator::StopSendingVersion() {
- DCHECK(send_version_in_packet_);
- send_version_in_packet_ = false;
- if (packet_size_ > 0) {
- DCHECK_LT(kQuicVersionSize, packet_size_);
- packet_size_ -= kQuicVersionSize;
- }
-}
-
-void QuicPacketCreator::SetDiversificationNonce(
- const DiversificationNonce nonce) {
- DCHECK(!have_diversification_nonce_);
- have_diversification_nonce_ = true;
- memcpy(&diversification_nonce_, nonce, sizeof(diversification_nonce_));
-}
-
-void QuicPacketCreator::UpdatePacketNumberLength(
- QuicPacketNumber least_packet_awaited_by_peer,
- QuicPacketCount max_packets_in_flight) {
- if (FLAGS_quic_simple_packet_number_length && !queued_frames_.empty()) {
- // Don't change creator state if there are frames queued.
- QUIC_BUG << "Called UpdatePacketNumberLength with " << queued_frames_.size()
- << " queued_frames.";
- return;
- }
-
- DCHECK_LE(least_packet_awaited_by_peer, packet_.packet_number + 1);
- const QuicPacketNumber current_delta =
- packet_.packet_number + 1 - least_packet_awaited_by_peer;
- const uint64_t delta = max(current_delta, max_packets_in_flight);
- if (FLAGS_quic_simple_packet_number_length) {
- packet_.packet_number_length =
- QuicFramer::GetMinSequenceNumberLength(delta * 4);
- } else {
- next_packet_number_length_ =
- QuicFramer::GetMinSequenceNumberLength(delta * 4);
- }
-}
-
-bool QuicPacketCreator::ConsumeData(QuicStreamId id,
- QuicIOVector iov,
- size_t iov_offset,
- QuicStreamOffset offset,
- bool fin,
- bool needs_full_padding,
- QuicFrame* frame) {
- if (!HasRoomForStreamFrame(id, offset)) {
- return false;
- }
- CreateStreamFrame(id, iov, iov_offset, offset, fin, frame);
- // Explicitly disallow multi-packet CHLOs.
- if (id == kCryptoStreamId &&
- frame->stream_frame->data_length >= sizeof(kCHLO) &&
- strncmp(frame->stream_frame->data_buffer,
- reinterpret_cast<const char*>(&kCHLO), sizeof(kCHLO)) == 0) {
- DCHECK_EQ(static_cast<size_t>(0), iov_offset);
- if (frame->stream_frame->data_length < iov.iov->iov_len) {
- const string error_details = "Client hello won't fit in a single packet.";
- QUIC_BUG << error_details << " Constructed stream frame length: "
- << frame->stream_frame->data_length
- << " CHLO length: " << iov.iov->iov_len;
- delegate_->OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, error_details,
- ConnectionCloseSource::FROM_SELF);
- delete frame->stream_frame;
- return false;
- }
- }
- if (!AddFrame(*frame, /*save_retransmittable_frames=*/true)) {
- // Fails if we try to write unencrypted stream data.
- delete frame->stream_frame;
- return false;
- }
- if (needs_full_padding) {
- packet_.num_padding_bytes = -1;
- }
- return true;
-}
-
-bool QuicPacketCreator::HasRoomForStreamFrame(QuicStreamId id,
- QuicStreamOffset offset) {
- return BytesFree() > QuicFramer::GetMinStreamFrameSize(id, offset, true);
-}
-
-// static
-size_t QuicPacketCreator::StreamFramePacketOverhead(
- QuicVersion version,
- QuicConnectionIdLength connection_id_length,
- bool include_version,
- bool include_path_id,
- bool include_diversification_nonce,
- QuicPacketNumberLength packet_number_length,
- QuicStreamOffset offset) {
- return GetPacketHeaderSize(version, connection_id_length, include_version,
- include_path_id, include_diversification_nonce,
- packet_number_length) +
- // Assumes this is a stream with a single lone packet.
- QuicFramer::GetMinStreamFrameSize(1u, offset, true);
-}
-
-void QuicPacketCreator::CreateStreamFrame(QuicStreamId id,
- QuicIOVector iov,
- size_t iov_offset,
- QuicStreamOffset offset,
- bool fin,
- QuicFrame* frame) {
- DCHECK_GT(max_packet_length_,
- StreamFramePacketOverhead(framer_->version(), connection_id_length_,
- kIncludeVersion, kIncludePathId,
- IncludeNonceInPublicHeader(),
- PACKET_6BYTE_PACKET_NUMBER, offset));
-
- if (!FLAGS_quic_simple_packet_number_length) {
- MaybeUpdatePacketNumberLength();
- }
- QUIC_BUG_IF(!HasRoomForStreamFrame(id, offset))
- << "No room for Stream frame, BytesFree: " << BytesFree()
- << " MinStreamFrameSize: "
- << QuicFramer::GetMinStreamFrameSize(id, offset, true);
-
- if (iov_offset == iov.total_length) {
- QUIC_BUG_IF(!fin) << "Creating a stream frame with no data or fin.";
- // Create a new packet for the fin, if necessary.
- *frame = QuicFrame(new QuicStreamFrame(id, true, offset, StringPiece()));
- return;
- }
-
- const size_t data_size = iov.total_length - iov_offset;
- size_t min_frame_size = QuicFramer::GetMinStreamFrameSize(
- id, offset, /* last_frame_in_packet= */ true);
- size_t bytes_consumed = min<size_t>(BytesFree() - min_frame_size, data_size);
-
- bool set_fin = fin && bytes_consumed == data_size; // Last frame.
- UniqueStreamBuffer buffer =
- NewStreamBuffer(buffer_allocator_, bytes_consumed);
- CopyToBuffer(iov, iov_offset, bytes_consumed, buffer.get());
- *frame = QuicFrame(new QuicStreamFrame(id, set_fin, offset, bytes_consumed,
- std::move(buffer)));
-}
-
-// static
-void QuicPacketCreator::CopyToBuffer(QuicIOVector iov,
- size_t iov_offset,
- size_t length,
- char* buffer) {
- int iovnum = 0;
- while (iovnum < iov.iov_count && iov_offset >= iov.iov[iovnum].iov_len) {
- iov_offset -= iov.iov[iovnum].iov_len;
- ++iovnum;
- }
- DCHECK_LE(iovnum, iov.iov_count);
- DCHECK_LE(iov_offset, iov.iov[iovnum].iov_len);
- if (iovnum >= iov.iov_count || length == 0) {
- return;
- }
-
- // Unroll the first iteration that handles iov_offset.
- const size_t iov_available = iov.iov[iovnum].iov_len - iov_offset;
- size_t copy_len = min(length, iov_available);
-
- // Try to prefetch the next iov if there is at least one more after the
- // current. Otherwise, it looks like an irregular access that the hardware
- // prefetcher won't speculatively prefetch. Only prefetch one iov because
- // 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.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);
- // 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.
- // prefetch(next_base, PREFETCH_HINT_T0);
- if (iov.iov[iovnum + 1].iov_len >= 64) {
- // TODO(ckrasic) - investigate what to do about prefetch directives.
- // prefetch(next_base + CACHELINE_SIZE, PREFETCH_HINT_T0);
- }
- }
-
- const char* src = static_cast<char*>(iov.iov[iovnum].iov_base) + iov_offset;
- while (true) {
- memcpy(buffer, src, copy_len);
- length -= copy_len;
- buffer += copy_len;
- if (length == 0 || ++iovnum >= iov.iov_count) {
- break;
- }
- src = static_cast<char*>(iov.iov[iovnum].iov_base);
- copy_len = min(length, iov.iov[iovnum].iov_len);
- }
- QUIC_BUG_IF(length > 0) << "Failed to copy entire length to buffer.";
-}
-
-void QuicPacketCreator::ReserializeAllFrames(
- const PendingRetransmission& retransmission,
- char* buffer,
- size_t buffer_len) {
- DCHECK(queued_frames_.empty());
- DCHECK_EQ(0, packet_.num_padding_bytes);
- QUIC_BUG_IF(retransmission.retransmittable_frames.empty())
- << "Attempt to serialize empty packet";
- const QuicPacketNumberLength saved_length = packet_.packet_number_length;
- const QuicPacketNumberLength saved_next_length = next_packet_number_length_;
- const EncryptionLevel default_encryption_level = packet_.encryption_level;
-
- // Temporarily set the packet number length and change the encryption level.
- packet_.packet_number_length = retransmission.packet_number_length;
- if (!FLAGS_quic_simple_packet_number_length) {
- next_packet_number_length_ = retransmission.packet_number_length;
- }
- packet_.num_padding_bytes = retransmission.num_padding_bytes;
- // Only preserve the original encryption level if it's a handshake packet or
- // if we haven't gone forward secure.
- if (retransmission.has_crypto_handshake ||
- packet_.encryption_level != ENCRYPTION_FORWARD_SECURE) {
- packet_.encryption_level = retransmission.encryption_level;
- }
-
- // Serialize the packet and restore packet number length state.
- for (const QuicFrame& frame : retransmission.retransmittable_frames) {
- bool success = AddFrame(frame, false);
- LOG_IF(DFATAL, !success)
- << " Failed to add frame of type:" << frame.type
- << " num_frames:" << retransmission.retransmittable_frames.size()
- << " retransmission.packet_number_length:"
- << retransmission.packet_number_length
- << " packet_.packet_number_length:" << packet_.packet_number_length;
- }
- SerializePacket(buffer, buffer_len);
- packet_.original_path_id = retransmission.path_id;
- packet_.original_packet_number = retransmission.packet_number;
- packet_.transmission_type = retransmission.transmission_type;
- OnSerializedPacket();
- // Restore old values.
- if (!FLAGS_quic_simple_packet_number_length) {
- // OnSerializedPacket updates the packet_number_length, so it's incorrect to
- // restore it here.
- packet_.packet_number_length = saved_length;
- next_packet_number_length_ = saved_next_length;
- }
- packet_.encryption_level = default_encryption_level;
-}
-
-void QuicPacketCreator::Flush() {
- if (!HasPendingFrames()) {
- return;
- }
-
- // TODO(rtenneti): Change the default 64 alignas value (used the default
- // value from CACHELINE_SIZE).
- ALIGNAS(64) char seralized_packet_buffer[kMaxPacketSize];
- SerializePacket(seralized_packet_buffer, kMaxPacketSize);
- OnSerializedPacket();
-}
-
-void QuicPacketCreator::OnSerializedPacket() {
- if (packet_.encrypted_buffer == nullptr) {
- const string error_details = "Failed to SerializePacket.";
- QUIC_BUG << error_details;
- delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET,
- error_details,
- ConnectionCloseSource::FROM_SELF);
- return;
- }
-
- delegate_->OnSerializedPacket(&packet_);
- ClearPacket();
- // Maximum packet size may be only enacted while no packet is currently being
- // constructed, so here we have a good opportunity to actually change it.
- if (CanSetMaxPacketLength()) {
- SetMaxPacketLength(max_packet_length_);
- }
-}
-
-void QuicPacketCreator::ClearPacket() {
- packet_.has_ack = false;
- packet_.has_stop_waiting = false;
- packet_.has_crypto_handshake = NOT_HANDSHAKE;
- packet_.num_padding_bytes = 0;
- packet_.original_path_id = kInvalidPathId;
- packet_.original_packet_number = 0;
- packet_.transmission_type = NOT_RETRANSMISSION;
- packet_.encrypted_buffer = nullptr;
- packet_.encrypted_length = 0;
- DCHECK(packet_.retransmittable_frames.empty());
- packet_.listeners.clear();
-}
-
-void QuicPacketCreator::CreateAndSerializeStreamFrame(
- QuicStreamId id,
- const QuicIOVector& iov,
- QuicStreamOffset iov_offset,
- QuicStreamOffset stream_offset,
- bool fin,
- QuicAckListenerInterface* listener,
- char* encrypted_buffer,
- size_t encrypted_buffer_len,
- size_t* num_bytes_consumed) {
- DCHECK(queued_frames_.empty());
- // Write out the packet header
- QuicPacketHeader header;
- FillPacketHeader(&header);
- QuicDataWriter writer(kMaxPacketSize, encrypted_buffer);
- if (!framer_->AppendPacketHeader(header, &writer)) {
- QUIC_BUG << "AppendPacketHeader failed";
- return;
- }
-
- // Create a Stream frame with the remaining space.
- QUIC_BUG_IF(iov_offset == iov.total_length && !fin)
- << "Creating a stream frame with no data or fin.";
- const size_t remaining_data_size = iov.total_length - iov_offset;
- const size_t min_frame_size = QuicFramer::GetMinStreamFrameSize(
- id, stream_offset, /* last_frame_in_packet= */ true);
- const size_t available_size =
- max_plaintext_size_ - writer.length() - min_frame_size;
- const size_t bytes_consumed =
- min<size_t>(available_size, remaining_data_size);
-
- const bool set_fin = fin && (bytes_consumed == remaining_data_size);
- UniqueStreamBuffer stream_buffer =
- NewStreamBuffer(buffer_allocator_, bytes_consumed);
- CopyToBuffer(iov, iov_offset, bytes_consumed, stream_buffer.get());
- std::unique_ptr<QuicStreamFrame> frame(new QuicStreamFrame(
- id, set_fin, stream_offset, bytes_consumed, std::move(stream_buffer)));
-
- // TODO(ianswett): AppendTypeByte and AppendStreamFrame could be optimized
- // into one method that takes a QuicStreamFrame, if warranted.
- if (!framer_->AppendTypeByte(QuicFrame(frame.get()),
- /* no stream frame length */ true, &writer)) {
- QUIC_BUG << "AppendTypeByte failed";
- return;
- }
- if (!framer_->AppendStreamFrame(*frame, /* no stream frame length */ true,
- &writer)) {
- QUIC_BUG << "AppendStreamFrame failed";
- return;
- }
-
- size_t encrypted_length = framer_->EncryptInPlace(
- packet_.encryption_level, packet_.path_id, packet_.packet_number,
- GetStartOfEncryptedData(framer_->version(), header), writer.length(),
- encrypted_buffer_len, encrypted_buffer);
- if (encrypted_length == 0) {
- QUIC_BUG << "Failed to encrypt packet number " << header.packet_number;
- return;
- }
- // TODO(ianswett): Optimize the storage so RetransmitableFrames can be
- // unioned with a QuicStreamFrame and a UniqueStreamBuffer.
- *num_bytes_consumed = bytes_consumed;
- packet_size_ = 0;
- packet_.entropy_hash = QuicFramer::GetPacketEntropyHash(header);
- packet_.encrypted_buffer = encrypted_buffer;
- packet_.encrypted_length = encrypted_length;
- if (listener != nullptr) {
- packet_.listeners.emplace_back(listener, bytes_consumed);
- }
- packet_.retransmittable_frames.push_back(QuicFrame(frame.release()));
- OnSerializedPacket();
-}
-
-bool QuicPacketCreator::HasPendingFrames() const {
- return !queued_frames_.empty();
-}
-
-bool QuicPacketCreator::HasPendingRetransmittableFrames() const {
- return !packet_.retransmittable_frames.empty();
-}
-
-size_t QuicPacketCreator::ExpansionOnNewFrame() const {
- // If the last frame in the packet is a stream frame, then it will expand to
- // include the stream_length field when a new frame is added.
- bool has_trailing_stream_frame =
- !queued_frames_.empty() && queued_frames_.back().type == STREAM_FRAME;
- return has_trailing_stream_frame ? kQuicStreamPayloadLengthSize : 0;
-}
-
-size_t QuicPacketCreator::BytesFree() {
- DCHECK_GE(max_plaintext_size_, PacketSize());
- return max_plaintext_size_ -
- min(max_plaintext_size_, PacketSize() + ExpansionOnNewFrame());
-}
-
-size_t QuicPacketCreator::PacketSize() {
- if (!queued_frames_.empty()) {
- return packet_size_;
- }
- // Update packet number length on packet boundary.
- if (!FLAGS_quic_simple_packet_number_length) {
- packet_.packet_number_length = next_packet_number_length_;
- }
- packet_size_ = GetPacketHeaderSize(
- framer_->version(), connection_id_length_, send_version_in_packet_,
- send_path_id_in_packet_, IncludeNonceInPublicHeader(),
- packet_.packet_number_length);
- return packet_size_;
-}
-
-bool QuicPacketCreator::AddSavedFrame(const QuicFrame& frame) {
- return AddFrame(frame, /*save_retransmittable_frames=*/true);
-}
-
-bool QuicPacketCreator::AddPaddedSavedFrame(const QuicFrame& frame) {
- if (AddFrame(frame, /*save_retransmittable_frames=*/true)) {
- packet_.num_padding_bytes = -1;
- return true;
- }
- return false;
-}
-
-void QuicPacketCreator::AddAckListener(QuicAckListenerInterface* listener,
- QuicPacketLength length) {
- DCHECK(!queued_frames_.empty());
- packet_.listeners.emplace_back(listener, length);
-}
-
-void QuicPacketCreator::SerializePacket(char* encrypted_buffer,
- size_t encrypted_buffer_len) {
- DCHECK_LT(0u, encrypted_buffer_len);
- QUIC_BUG_IF(queued_frames_.empty()) << "Attempt to serialize empty packet";
- QuicPacketHeader header;
- // FillPacketHeader increments packet_number_.
- FillPacketHeader(&header);
-
- MaybeAddPadding();
-
- DCHECK_GE(max_plaintext_size_, packet_size_);
- // Use the packet_size_ instead of the buffer size to ensure smaller
- // packet sizes are properly used.
- size_t length = framer_->BuildDataPacket(header, queued_frames_,
- encrypted_buffer, packet_size_);
- if (length == 0) {
- QUIC_BUG << "Failed to serialize " << queued_frames_.size() << " frames.";
- return;
- }
-
- // ACK Frames will be truncated due to length only if they're the only frame
- // in the packet, and if packet_size_ was set to max_plaintext_size_. If
- // truncation due to length occurred, then GetSerializedFrameLength will have
- // returned all bytes free.
- bool possibly_truncated_by_length = packet_size_ == max_plaintext_size_ &&
- queued_frames_.size() == 1 &&
- queued_frames_.back().type == ACK_FRAME;
- // Because of possible truncation, we can't be confident that our
- // packet size calculation worked correctly.
- if (!possibly_truncated_by_length) {
- DCHECK_EQ(packet_size_, length);
- }
- const size_t encrypted_length = framer_->EncryptInPlace(
- packet_.encryption_level, packet_.path_id, packet_.packet_number,
- GetStartOfEncryptedData(framer_->version(), header), length,
- encrypted_buffer_len, encrypted_buffer);
- if (encrypted_length == 0) {
- QUIC_BUG << "Failed to encrypt packet number " << packet_.packet_number;
- return;
- }
-
- packet_size_ = 0;
- queued_frames_.clear();
- packet_.entropy_hash = QuicFramer::GetPacketEntropyHash(header);
- packet_.encrypted_buffer = encrypted_buffer;
- packet_.encrypted_length = encrypted_length;
-}
-
-QuicEncryptedPacket* QuicPacketCreator::SerializeVersionNegotiationPacket(
- const QuicVersionVector& supported_versions) {
- DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective());
- QuicEncryptedPacket* encrypted = QuicFramer::BuildVersionNegotiationPacket(
- connection_id_, supported_versions);
- DCHECK(encrypted);
- DCHECK_GE(max_packet_length_, encrypted->length());
- return encrypted;
-}
-
-// TODO(jri): Make this a public method of framer?
-SerializedPacket QuicPacketCreator::NoPacket() {
- return SerializedPacket(kInvalidPathId, 0, PACKET_1BYTE_PACKET_NUMBER,
- nullptr, 0, 0, false, false);
-}
-
-void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) {
- header->public_header.connection_id = connection_id_;
- header->public_header.connection_id_length = connection_id_length_;
- header->public_header.multipath_flag = send_path_id_in_packet_;
- header->public_header.reset_flag = false;
- header->public_header.version_flag = send_version_in_packet_;
- if (IncludeNonceInPublicHeader()) {
- DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective());
- header->public_header.nonce = &diversification_nonce_;
- } else {
- header->public_header.nonce = nullptr;
- }
- header->path_id = packet_.path_id;
- header->packet_number = ++packet_.packet_number;
- header->public_header.packet_number_length = packet_.packet_number_length;
- header->entropy_flag = random_bool_source_.RandBool();
-}
-
-bool QuicPacketCreator::ShouldRetransmit(const QuicFrame& frame) {
- switch (frame.type) {
- case ACK_FRAME:
- case PADDING_FRAME:
- case STOP_WAITING_FRAME:
- case MTU_DISCOVERY_FRAME:
- return false;
- default:
- return true;
- }
-}
-
-bool QuicPacketCreator::AddFrame(const QuicFrame& frame,
- bool save_retransmittable_frames) {
- DVLOG(1) << "Adding frame: " << frame;
- if (FLAGS_quic_never_write_unencrypted_data && frame.type == STREAM_FRAME &&
- frame.stream_frame->stream_id != kCryptoStreamId &&
- packet_.encryption_level == ENCRYPTION_NONE) {
- const string error_details = "Cannot send stream data without encryption.";
- QUIC_BUG << error_details;
- delegate_->OnUnrecoverableError(
- QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA, error_details,
- ConnectionCloseSource::FROM_SELF);
- return false;
- }
- if (!FLAGS_quic_simple_packet_number_length) {
- MaybeUpdatePacketNumberLength();
- }
- size_t frame_len = framer_->GetSerializedFrameLength(
- frame, BytesFree(), queued_frames_.empty(), true,
- packet_.packet_number_length);
- if (frame_len == 0) {
- // Current open packet is full.
- Flush();
- return false;
- }
- DCHECK_LT(0u, packet_size_);
- packet_size_ += ExpansionOnNewFrame() + frame_len;
-
- if (save_retransmittable_frames && ShouldRetransmit(frame)) {
- if (packet_.retransmittable_frames.empty()) {
- packet_.retransmittable_frames.reserve(2);
- }
- packet_.retransmittable_frames.push_back(frame);
- queued_frames_.push_back(frame);
- if (frame.type == STREAM_FRAME &&
- frame.stream_frame->stream_id == kCryptoStreamId) {
- packet_.has_crypto_handshake = IS_HANDSHAKE;
- }
- } else {
- queued_frames_.push_back(frame);
- }
-
- if (frame.type == ACK_FRAME) {
- packet_.has_ack = true;
- }
- if (frame.type == STOP_WAITING_FRAME) {
- packet_.has_stop_waiting = true;
- }
- if (debug_delegate_ != nullptr) {
- debug_delegate_->OnFrameAddedToPacket(frame);
- }
-
- return true;
-}
-
-void QuicPacketCreator::MaybeAddPadding() {
- if (packet_.num_padding_bytes == 0) {
- return;
- }
-
- if (BytesFree() == 0) {
- // Don't pad full packets.
- return;
- }
-
- bool success =
- AddFrame(QuicFrame(QuicPaddingFrame(packet_.num_padding_bytes)), false);
- DCHECK(success);
-}
-
-void QuicPacketCreator::SetCurrentPath(
- QuicPathId path_id,
- QuicPacketNumber least_packet_awaited_by_peer,
- QuicPacketCount max_packets_in_flight) {
- if (packet_.path_id == path_id) {
- return;
- }
-
- if (HasPendingFrames()) {
- QUIC_BUG << "Unable to change paths when a packet is under construction.";
- return;
- }
- // Save current packet number and load switching path's packet number.
- multipath_packet_number_[packet_.path_id] = packet_.packet_number;
- std::unordered_map<QuicPathId, QuicPacketNumber>::iterator it =
- multipath_packet_number_.find(path_id);
- // If path_id is not in the map, it's a new path. Set packet_number to 0.
- packet_.packet_number = it == multipath_packet_number_.end() ? 0 : it->second;
- packet_.path_id = path_id;
- DCHECK(packet_.path_id != kInvalidPathId);
- // Send path in packet if current path is not the default path.
- send_path_id_in_packet_ = packet_.path_id != kDefaultPathId ? true : false;
- // Switching path needs to update packet number length.
- UpdatePacketNumberLength(least_packet_awaited_by_peer, max_packets_in_flight);
-}
-
-bool QuicPacketCreator::IncludeNonceInPublicHeader() {
- return have_diversification_nonce_ &&
- packet_.encryption_level == ENCRYPTION_INITIAL;
-}
-
-QuicPacketCreator::QuicRandomBoolSource::QuicRandomBoolSource(
- QuicRandom* random)
- : random_(random), bit_bucket_(0), bit_mask_(0) {}
-
-QuicPacketCreator::QuicRandomBoolSource::~QuicRandomBoolSource() {}
-
-bool QuicPacketCreator::QuicRandomBoolSource::RandBool() {
- if (bit_mask_ == 0) {
- bit_bucket_ = random_->RandUint64();
- bit_mask_ = 1;
- }
- bool result = ((bit_bucket_ & bit_mask_) != 0);
- bit_mask_ <<= 1;
- return result;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_packet_creator.h b/chromium/net/quic/quic_packet_creator.h
deleted file mode 100644
index 14cf69e5711..00000000000
--- a/chromium/net/quic/quic_packet_creator.h
+++ /dev/null
@@ -1,354 +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.
-//
-// Accumulates frames for the next packet until more frames no longer fit or
-// it's time to create a packet from them. If multipath enabled, only creates
-// packets on one path at the same time. Currently, next packet number is
-// tracked per-path.
-
-#ifndef NET_QUIC_QUIC_PACKET_CREATOR_H_
-#define NET_QUIC_QUIC_PACKET_CREATOR_H_
-
-#include <stddef.h>
-
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-namespace test {
-class QuicPacketCreatorPeer;
-}
-
-class QuicRandom;
-
-class NET_EXPORT_PRIVATE QuicPacketCreator {
- public:
- // A delegate interface for further processing serialized packet.
- class NET_EXPORT_PRIVATE DelegateInterface
- : public QuicConnectionCloseDelegateInterface {
- public:
- ~DelegateInterface() override {}
- // Called when a packet is serialized. Delegate does not take the ownership
- // of |serialized_packet|, but takes ownership of any frames it removes
- // from |packet.retransmittable_frames|.
- virtual void OnSerializedPacket(SerializedPacket* serialized_packet) = 0;
- };
-
- // Interface which gets callbacks from the QuicPacketCreator at interesting
- // points. Implementations must not mutate the state of the creator
- // as a result of these callbacks.
- class NET_EXPORT_PRIVATE DebugDelegate {
- public:
- virtual ~DebugDelegate() {}
-
- // Called when a frame has been added to the current packet.
- virtual void OnFrameAddedToPacket(const QuicFrame& frame) {}
- };
-
- // QuicRandom* required for packet entropy.
- QuicPacketCreator(QuicConnectionId connection_id,
- QuicFramer* framer,
- QuicRandom* random_generator,
- QuicBufferAllocator* buffer_allocator,
- DelegateInterface* delegate);
-
- ~QuicPacketCreator();
-
- // Makes the framer not serialize the protocol version in sent packets.
- void StopSendingVersion();
-
- // SetDiversificationNonce sets the nonce that will be sent in each public
- // header of packets encrypted at the initial encryption level. Should only
- // be called by servers.
- void SetDiversificationNonce(const DiversificationNonce nonce);
-
- // Update the packet number length to use in future packets as soon as it
- // can be safely changed.
- // TODO(fayang): Directly set packet number length instead of compute it in
- // creator.
- void UpdatePacketNumberLength(QuicPacketNumber least_packet_awaited_by_peer,
- QuicPacketCount max_packets_in_flight);
-
- // The overhead the framing will add for a packet with one frame.
- static size_t StreamFramePacketOverhead(
- QuicVersion version,
- QuicConnectionIdLength connection_id_length,
- bool include_version,
- bool include_path_id,
- bool include_diversification_nonce,
- QuicPacketNumberLength packet_number_length,
- QuicStreamOffset offset);
-
- // Returns false and flushes all pending frames if current open packet is
- // full.
- // If current packet is not full, converts a raw payload into a stream frame
- // that fits into the open packet and adds it to the packet.
- // The payload begins at |iov_offset| into the |iov|.
- bool ConsumeData(QuicStreamId id,
- QuicIOVector iov,
- size_t iov_offset,
- QuicStreamOffset offset,
- bool fin,
- bool needs_full_padding,
- QuicFrame* frame);
-
- // Returns true if current open packet can accommodate more stream frames of
- // stream |id| at |offset|, false otherwise.
- bool HasRoomForStreamFrame(QuicStreamId id, QuicStreamOffset offset);
-
- // Re-serializes frames with the original packet's packet number length.
- // Used for retransmitting packets to ensure they aren't too long.
- void ReserializeAllFrames(const PendingRetransmission& retransmission,
- char* buffer,
- size_t buffer_len);
-
- // Serializes all added frames into a single packet and invokes the delegate_
- // to further process the SerializedPacket.
- void Flush();
-
- // Optimized method to create a QuicStreamFrame, serialize it, and encrypt it
- // into |encrypted_buffer|. Adds the QuicStreamFrame to the returned
- // SerializedPacket. Sets |num_bytes_consumed| to the number of bytes
- // consumed to create the QuicStreamFrame.
- void CreateAndSerializeStreamFrame(QuicStreamId id,
- const QuicIOVector& iov,
- QuicStreamOffset iov_offset,
- QuicStreamOffset stream_offset,
- bool fin,
- QuicAckListenerInterface* listener,
- char* encrypted_buffer,
- size_t encrypted_buffer_len,
- size_t* num_bytes_consumed);
-
- // Returns true if there are frames pending to be serialized.
- bool HasPendingFrames() const;
-
- // Returns true if there are retransmittable frames pending to be serialized.
- bool HasPendingRetransmittableFrames() const;
-
- // Returns the number of bytes which are available to be used by additional
- // frames in the packet. Since stream frames are slightly smaller when they
- // are the last frame in a packet, this method will return a different
- // value than max_packet_size - PacketSize(), in this case.
- size_t BytesFree();
-
- // Returns the number of bytes that the packet will expand by if a new frame
- // is added to the packet. If the last frame was a stream frame, it will
- // expand slightly when a new frame is added, and this method returns the
- // amount of expected expansion.
- size_t ExpansionOnNewFrame() const;
-
- // Returns the number of bytes in the current packet, including the header,
- // if serialized with the current frames. Adding a frame to the packet
- // may change the serialized length of existing frames, as per the comment
- // in BytesFree.
- size_t PacketSize();
-
- // Tries to add |frame| to the packet creator's list of frames to be
- // serialized. If the frame does not fit into the current packet, flushes the
- // packet and returns false.
- bool AddSavedFrame(const QuicFrame& frame);
-
- // Identical to AddSavedFrame, but allows the frame to be padded.
- bool AddPaddedSavedFrame(const QuicFrame& frame);
-
- // Adds |listener| to the next serialized packet and notifies the
- // std::listener with |length| as the number of acked bytes.
- void AddAckListener(QuicAckListenerInterface* listener,
- QuicPacketLength length);
-
- // Creates a version negotiation packet which supports |supported_versions|.
- // Caller owns the created packet. Also, sets the entropy hash of the
- // serialized packet to a random bool and returns that value as a member of
- // SerializedPacket.
- QuicEncryptedPacket* SerializeVersionNegotiationPacket(
- const QuicVersionVector& supported_versions);
-
- // Returns a dummy packet that is valid but contains no useful information.
- static SerializedPacket NoPacket();
-
- // Sets the encryption level that will be applied to new packets.
- void set_encryption_level(EncryptionLevel level) {
- packet_.encryption_level = level;
- }
-
- // packet number of the last created packet, or 0 if no packets have been
- // created.
- QuicPacketNumber packet_number() const { return packet_.packet_number; }
-
- QuicConnectionIdLength connection_id_length() const {
- return connection_id_length_;
- }
-
- void set_connection_id_length(QuicConnectionIdLength length) {
- connection_id_length_ = length;
- }
-
- QuicByteCount max_packet_length() const { return max_packet_length_; }
-
- bool has_ack() const { return packet_.has_ack; }
-
- bool has_stop_waiting() const { return packet_.has_stop_waiting; }
-
- // Sets the encrypter to use for the encryption level and updates the max
- // plaintext size.
- void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter);
-
- // Indicates whether the packet creator is in a state where it can change
- // current maximum packet length.
- bool CanSetMaxPacketLength() const;
-
- // Sets the maximum packet length.
- void SetMaxPacketLength(QuicByteCount length);
-
- // Sets the path on which subsequent packets will be created. It is the
- // caller's responsibility to guarantee no packet is under construction before
- // calling this function. If |path_id| is different from current_path_,
- // next_packet_number_length_ is recalculated.
- void SetCurrentPath(QuicPathId path_id,
- QuicPacketNumber least_packet_awaited_by_peer,
- QuicPacketCount max_packets_in_flight);
-
- void set_debug_delegate(DebugDelegate* debug_delegate) {
- debug_delegate_ = debug_delegate;
- }
-
- private:
- friend class test::QuicPacketCreatorPeer;
-
- // A QuicRandom wrapper that gets a bucket of entropy and distributes it
- // bit-by-bit. Replenishes the bucket as needed. Not thread-safe. Expose this
- // class if single bit randomness is needed elsewhere.
- class QuicRandomBoolSource {
- public:
- // random: Source of entropy. Not owned.
- explicit QuicRandomBoolSource(QuicRandom* random);
-
- ~QuicRandomBoolSource();
-
- // Returns the next random bit from the bucket.
- bool RandBool();
-
- private:
- // Source of entropy.
- QuicRandom* random_;
- // Stored random bits.
- uint64_t bit_bucket_;
- // The next available bit has "1" in the mask. Zero means empty bucket.
- uint64_t bit_mask_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicRandomBoolSource);
- };
-
- static bool ShouldRetransmit(const QuicFrame& frame);
-
- // Converts a raw payload to a frame which fits into the current open
- // packet. The payload begins at |iov_offset| into the |iov|.
- // If data is empty and fin is true, the expected behavior is to consume the
- // fin but return 0. If any data is consumed, it will be copied into a
- // new buffer that |frame| will point to and own.
- void CreateStreamFrame(QuicStreamId id,
- QuicIOVector iov,
- size_t iov_offset,
- QuicStreamOffset offset,
- bool fin,
- QuicFrame* frame);
-
- // Copies |length| bytes from iov starting at offset |iov_offset| into buffer.
- // |iov| must be at least iov_offset+length total length and buffer must be
- // at least |length| long.
- static void CopyToBuffer(QuicIOVector iov,
- size_t iov_offset,
- size_t length,
- char* buffer);
-
- // Updates packet number length on packet boundary.
- void MaybeUpdatePacketNumberLength();
-
- void FillPacketHeader(QuicPacketHeader* header);
-
- // Adds a |frame| if there is space and returns false and flushes all pending
- // frames if there isn't room. If |save_retransmittable_frames| is true,
- // saves the |frame| in the next SerializedPacket.
- bool AddFrame(const QuicFrame& frame, bool save_retransmittable_frames);
-
- // Adds a padding frame to the current packet only if the current packet
- // contains a handshake message, and there is sufficient room to fit a
- // padding frame.
- void MaybeAddPadding();
-
- // Serializes all frames which have been added and adds any which should be
- // retransmitted to packet_.retransmittable_frames. All frames must fit into
- // a single packet. Sets the entropy hash of the serialized packet to a
- // random bool.
- // Fails if |buffer_len| isn't long enough for the encrypted packet.
- void SerializePacket(char* encrypted_buffer, size_t buffer_len);
-
- // Called after a new SerialiedPacket is created to call the delegate's
- // OnSerializedPacket and reset state.
- void OnSerializedPacket();
-
- // Clears all fields of packet_ that should be cleared between serializations.
- void ClearPacket();
-
- // Returns true if a diversification nonce should be included in the current
- // packet's public header.
- bool IncludeNonceInPublicHeader();
-
- // Does not own these delegates or the framer.
- DelegateInterface* delegate_;
- DebugDelegate* debug_delegate_;
- QuicFramer* framer_;
-
- QuicRandomBoolSource random_bool_source_;
- QuicBufferAllocator* const buffer_allocator_;
-
- // Controls whether version should be included while serializing the packet.
- bool send_version_in_packet_;
- // Controls whether path id should be included while serializing the packet.
- bool send_path_id_in_packet_;
- // Staging variable to hold next packet number length. When sequence
- // number length is to be changed, this variable holds the new length until
- // a packet boundary, when the creator's packet_number_length_ can be changed
- // to this new value.
- QuicPacketNumberLength next_packet_number_length_;
- // If true, then |nonce_for_public_header_| will be included in the public
- // header of all packets created at the initial encryption level.
- bool have_diversification_nonce_;
- DiversificationNonce diversification_nonce_;
- // Maximum length including headers and encryption (UDP payload length.)
- QuicByteCount max_packet_length_;
- size_t max_plaintext_size_;
- // Length of connection_id to send over the wire.
- QuicConnectionIdLength connection_id_length_;
-
- // Frames to be added to the next SerializedPacket
- QuicFrames queued_frames_;
-
- // packet_size should never be read directly, use PacketSize() instead.
- // TODO(ianswett): Move packet_size_ into SerializedPacket once
- // QuicEncryptedPacket has been flattened into SerializedPacket.
- size_t packet_size_;
- QuicConnectionId connection_id_;
-
- // Packet used to invoke OnSerializedPacket.
- SerializedPacket packet_;
-
- // Map mapping path_id to last sent packet number on the path.
- std::unordered_map<QuicPathId, QuicPacketNumber> multipath_packet_number_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicPacketCreator);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_PACKET_CREATOR_H_
diff --git a/chromium/net/quic/quic_packet_creator_test.cc b/chromium/net/quic/quic_packet_creator_test.cc
deleted file mode 100644
index df2e399ddc3..00000000000
--- a/chromium/net/quic/quic_packet_creator_test.cc
+++ /dev/null
@@ -1,1337 +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/quic_packet_creator.h"
-
-#include <cstdint>
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/stl_util.h"
-#include "net/quic/crypto/null_encrypter.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_simple_buffer_allocator.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/mock_random.h"
-#include "net/quic/test_tools/quic_framer_peer.h"
-#include "net/quic/test_tools/quic_packet_creator_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/test/gtest_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using base::StringPiece;
-using std::ostream;
-using std::string;
-using std::vector;
-using testing::DoAll;
-using testing::InSequence;
-using testing::Return;
-using testing::SaveArg;
-using testing::StrictMock;
-using testing::_;
-
-namespace net {
-namespace test {
-namespace {
-
-// Run tests with combinations of {QuicVersion, ToggleVersionSerialization}.
-struct TestParams {
- TestParams(QuicVersion version,
- bool version_serialization,
- QuicConnectionIdLength length)
- : version(version),
- connection_id_length(length),
- version_serialization(version_serialization) {}
-
- friend ostream& operator<<(ostream& os, const TestParams& p) {
- os << "{ client_version: " << QuicVersionToString(p.version)
- << " connection id length: " << p.connection_id_length
- << " include version: " << p.version_serialization << " }";
- return os;
- }
-
- QuicVersion version;
- QuicConnectionIdLength connection_id_length;
- bool version_serialization;
-};
-
-// Constructs various test permutations.
-vector<TestParams> GetTestParams() {
- vector<TestParams> params;
- constexpr QuicConnectionIdLength kMax = PACKET_8BYTE_CONNECTION_ID;
- QuicVersionVector all_supported_versions = QuicSupportedVersions();
- for (size_t i = 0; i < all_supported_versions.size(); ++i) {
- params.push_back(TestParams(all_supported_versions[i], true, kMax));
- params.push_back(TestParams(all_supported_versions[i], false, kMax));
- }
- params.push_back(
- TestParams(all_supported_versions[0], true, PACKET_0BYTE_CONNECTION_ID));
- params.push_back(TestParams(all_supported_versions[0], true, kMax));
- return params;
-}
-
-class MockDelegate : public QuicPacketCreator::DelegateInterface {
- public:
- MockDelegate() {}
- ~MockDelegate() override {}
-
- MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet));
- MOCK_METHOD3(OnUnrecoverableError,
- void(QuicErrorCode,
- const string&,
- ConnectionCloseSource source));
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockDelegate);
-};
-
-class QuicPacketCreatorTest : public ::testing::TestWithParam<TestParams> {
- public:
- void ClearSerializedPacket(SerializedPacket* serialized_packet) {
- if (serialized_packet == nullptr) {
- return;
- }
- QuicUtils::ClearSerializedPacket(serialized_packet);
- }
-
- void SaveSerializedPacket(SerializedPacket* serialized_packet) {
- if (serialized_packet == nullptr) {
- return;
- }
- delete[] serialized_packet_.encrypted_buffer;
- serialized_packet_ = *serialized_packet;
- serialized_packet_.encrypted_buffer =
- QuicUtils::CopyBuffer(*serialized_packet);
- serialized_packet->retransmittable_frames.clear();
- }
-
- void DeleteSerializedPacket() {
- delete[] serialized_packet_.encrypted_buffer;
- serialized_packet_.encrypted_buffer = nullptr;
- ClearSerializedPacket(&serialized_packet_);
- }
-
- protected:
- QuicPacketCreatorTest()
- : server_framer_(SupportedVersions(GetParam().version),
- QuicTime::Zero(),
- Perspective::IS_SERVER),
- client_framer_(SupportedVersions(GetParam().version),
- QuicTime::Zero(),
- Perspective::IS_CLIENT),
- connection_id_(2),
- data_("foo"),
- creator_(connection_id_,
- &client_framer_,
- &mock_random_,
- &buffer_allocator_,
- &delegate_),
- serialized_packet_(creator_.NoPacket()) {
- FLAGS_quic_always_log_bugs_for_tests = true;
- creator_.set_connection_id_length(GetParam().connection_id_length);
-
- creator_.SetEncrypter(ENCRYPTION_INITIAL, new NullEncrypter());
- creator_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, new NullEncrypter());
- client_framer_.set_visitor(&framer_visitor_);
- client_framer_.set_received_entropy_calculator(&entropy_calculator_);
- server_framer_.set_visitor(&framer_visitor_);
- // TODO(ianswett): Fix this test so it uses a non-null encrypter.
- FLAGS_quic_never_write_unencrypted_data = false;
- }
-
- ~QuicPacketCreatorTest() override {
- delete[] serialized_packet_.encrypted_buffer;
- ClearSerializedPacket(&serialized_packet_);
- }
-
- SerializedPacket SerializeAllFrames(const QuicFrames& frames) {
- SerializedPacket packet = QuicPacketCreatorPeer::SerializeAllFrames(
- &creator_, frames, buffer_, kMaxPacketSize);
- EXPECT_EQ(QuicPacketCreatorPeer::GetEncryptionLevel(&creator_),
- packet.encryption_level);
- return packet;
- }
-
- void ProcessPacket(const SerializedPacket& packet) {
- QuicEncryptedPacket encrypted_packet(packet.encrypted_buffer,
- packet.encrypted_length);
- server_framer_.ProcessPacket(encrypted_packet);
- }
-
- void CheckStreamFrame(const QuicFrame& frame,
- QuicStreamId stream_id,
- const string& data,
- QuicStreamOffset offset,
- bool fin) {
- EXPECT_EQ(STREAM_FRAME, frame.type);
- ASSERT_TRUE(frame.stream_frame);
- EXPECT_EQ(stream_id, frame.stream_frame->stream_id);
- EXPECT_EQ(data, StringPiece(frame.stream_frame->data_buffer,
- frame.stream_frame->data_length));
- EXPECT_EQ(offset, frame.stream_frame->offset);
- EXPECT_EQ(fin, frame.stream_frame->fin);
- }
-
- // Returns the number of bytes consumed by the header of packet, including
- // the version.
- size_t GetPacketHeaderOverhead(QuicVersion version) {
- if (FLAGS_quic_simple_packet_number_length) {
- return GetPacketHeaderSize(
- version, creator_.connection_id_length(), kIncludeVersion,
- !kIncludePathId, !kIncludeDiversificationNonce,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
- } else {
- return GetPacketHeaderSize(
- version, creator_.connection_id_length(), kIncludeVersion,
- !kIncludePathId, !kIncludeDiversificationNonce,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
- }
- }
-
- // Returns the number of bytes of overhead that will be added to a packet
- // of maximum length.
- size_t GetEncryptionOverhead() {
- return creator_.max_packet_length() -
- client_framer_.GetMaxPlaintextSize(creator_.max_packet_length());
- }
-
- // Returns the number of bytes consumed by the non-data fields of a stream
- // frame, assuming it is the last frame in the packet
- size_t GetStreamFrameOverhead() {
- return QuicFramer::GetMinStreamFrameSize(kClientDataStreamId1, kOffset,
- true);
- }
-
- QuicIOVector MakeIOVector(StringPiece s) {
- return ::net::MakeIOVector(s, &iov_);
- }
-
- PendingRetransmission CreateRetransmission(
- const QuicFrames& retransmittable_frames,
- bool has_crypto_handshake,
- int num_padding_bytes,
- EncryptionLevel encryption_level,
- QuicPacketNumberLength packet_number_length) {
- return PendingRetransmission(1u, 1u, NOT_RETRANSMISSION,
- retransmittable_frames, has_crypto_handshake,
- num_padding_bytes, encryption_level,
- packet_number_length);
- }
-
- static const QuicStreamOffset kOffset = 1u;
-
- char buffer_[kMaxPacketSize];
- QuicFrames frames_;
- QuicFramer server_framer_;
- QuicFramer client_framer_;
- StrictMock<MockFramerVisitor> framer_visitor_;
- StrictMock<MockDelegate> delegate_;
- QuicConnectionId connection_id_;
- string data_;
- struct iovec iov_;
- MockRandom mock_random_;
- SimpleBufferAllocator buffer_allocator_;
- QuicPacketCreator creator_;
- MockEntropyCalculator entropy_calculator_;
- SerializedPacket serialized_packet_;
-};
-
-// Run all packet creator tests with all supported versions of QUIC, and with
-// and without version in the packet header, as well as doing a run for each
-// length of truncated connection id.
-INSTANTIATE_TEST_CASE_P(QuicPacketCreatorTests,
- QuicPacketCreatorTest,
- ::testing::ValuesIn(GetTestParams()));
-
-TEST_P(QuicPacketCreatorTest, SerializeFrames) {
- for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; ++i) {
- EncryptionLevel level = static_cast<EncryptionLevel>(i);
- creator_.set_encryption_level(level);
- frames_.push_back(QuicFrame(new QuicAckFrame(MakeAckFrame(0u))));
- frames_.push_back(
- QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
- frames_.push_back(
- QuicFrame(new QuicStreamFrame(0u, true, 0u, StringPiece())));
- SerializedPacket serialized = SerializeAllFrames(frames_);
- EXPECT_EQ(level, serialized.encryption_level);
- delete frames_[0].ack_frame;
- delete frames_[1].stream_frame;
- delete frames_[2].stream_frame;
- frames_.clear();
-
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- EXPECT_CALL(framer_visitor_, OnAckFrame(_));
- EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
- EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
- }
- ProcessPacket(serialized);
- }
-}
-
-TEST_P(QuicPacketCreatorTest, SerializeChangingSequenceNumberLength) {
- FLAGS_quic_simple_packet_number_length = false;
- frames_.push_back(QuicFrame(new QuicAckFrame(MakeAckFrame(0u))));
- creator_.AddSavedFrame(frames_[0]);
- QuicPacketCreatorPeer::SetNextPacketNumberLength(&creator_,
- PACKET_4BYTE_PACKET_NUMBER);
-
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillRepeatedly(
- Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- creator_.Flush();
- // The packet number length will not change mid-packet.
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- serialized_packet_.packet_number_length);
-
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- EXPECT_CALL(framer_visitor_, OnAckFrame(_));
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
- }
- ProcessPacket(serialized_packet_);
- DeleteSerializedPacket();
-
- creator_.AddSavedFrame(frames_[0]);
- creator_.Flush();
- // Now the actual packet number length should have changed.
- EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
- serialized_packet_.packet_number_length);
- delete frames_[0].ack_frame;
-
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- EXPECT_CALL(framer_visitor_, OnAckFrame(_));
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
- }
- ProcessPacket(serialized_packet_);
- DeleteSerializedPacket();
-}
-
-TEST_P(QuicPacketCreatorTest, ChangeSequenceNumberLengthMidPacket) {
- FLAGS_quic_simple_packet_number_length = false;
- // Changing the packet number length with queued frames in the creator
- // should hold the change until after any currently queued frames are
- // serialized.
-
- // Packet 1.
- // Queue a frame in the creator.
- EXPECT_FALSE(creator_.HasPendingFrames());
- QuicFrame ack_frame = QuicFrame(new QuicAckFrame(MakeAckFrame(0u)));
- creator_.AddSavedFrame(ack_frame);
-
- // Now change packet number length.
- QuicPacketCreatorPeer::SetNextPacketNumberLength(&creator_,
- PACKET_4BYTE_PACKET_NUMBER);
-
- // Add a STOP_WAITING frame since it contains a packet number,
- // whose length should be 1.
- QuicStopWaitingFrame stop_waiting_frame;
- EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&stop_waiting_frame)));
- EXPECT_TRUE(creator_.HasPendingFrames());
-
- // Ensure the packet is successfully created.
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillRepeatedly(
- Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- creator_.Flush();
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- serialized_packet_.packet_number_length);
-
- // Verify that header in transmitted packet has 1 byte sequence length.
- QuicPacketHeader header;
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_))
- .WillOnce(DoAll(SaveArg<0>(&header), Return(true)));
- EXPECT_CALL(framer_visitor_, OnAckFrame(_));
- EXPECT_CALL(framer_visitor_, OnStopWaitingFrame(_));
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
- }
- ProcessPacket(serialized_packet_);
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- header.public_header.packet_number_length);
- DeleteSerializedPacket();
-
- // Packet 2.
- EXPECT_FALSE(creator_.HasPendingFrames());
- // Generate Packet 2 with one frame -- packet number length should now
- // change to 4 bytes.
- EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&stop_waiting_frame)));
- EXPECT_TRUE(creator_.HasPendingFrames());
-
- // Ensure the packet is successfully created.
- creator_.Flush();
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
- EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
- serialized_packet_.packet_number_length);
-
- // Verify that header in transmitted packet has 4 byte sequence length.
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_))
- .WillOnce(DoAll(SaveArg<0>(&header), Return(true)));
- EXPECT_CALL(framer_visitor_, OnStopWaitingFrame(_));
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
- }
- ProcessPacket(serialized_packet_);
- EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
- header.public_header.packet_number_length);
-
- DeleteSerializedPacket();
- delete ack_frame.ack_frame;
-}
-
-TEST_P(QuicPacketCreatorTest, ChangeSequenceNumberLengthMidPacketDoesNothing) {
- FLAGS_quic_simple_packet_number_length = true;
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
- // Changing the packet number length with queued frames in the creator
- // should do nothing.
- EXPECT_FALSE(creator_.HasPendingFrames());
- QuicFrame ack_frame = QuicFrame(new QuicAckFrame(MakeAckFrame(0u)));
- creator_.AddSavedFrame(ack_frame);
-
- // Now change packet number length and expect a QUIC_BUG and no change in
- // packet number length.
- EXPECT_DFATAL(creator_.UpdatePacketNumberLength(0, 256),
- "Called UpdatePacketNumberLength with 1 queued_frames.");
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
- delete ack_frame.ack_frame;
-}
-
-TEST_P(QuicPacketCreatorTest, ReserializeFramesWithSequenceNumberLength) {
- // If the original packet number length, the current packet number
- // length, and the configured send packet number length are different, the
- // retransmit must sent with the original length and the others do not change.
- if (!FLAGS_quic_simple_packet_number_length) {
- QuicPacketCreatorPeer::SetNextPacketNumberLength(
- &creator_, PACKET_4BYTE_PACKET_NUMBER);
- }
- QuicPacketCreatorPeer::SetPacketNumberLength(&creator_,
- PACKET_2BYTE_PACKET_NUMBER);
- QuicStreamFrame* stream_frame =
- new QuicStreamFrame(kCryptoStreamId, /*fin=*/false, 0u, StringPiece());
- QuicFrames frames;
- frames.push_back(QuicFrame(stream_frame));
- char buffer[kMaxPacketSize];
- PendingRetransmission retransmission(CreateRetransmission(
- frames, true /* has_crypto_handshake */, -1 /* needs full padding */,
- ENCRYPTION_NONE, PACKET_1BYTE_PACKET_NUMBER));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- creator_.ReserializeAllFrames(retransmission, buffer, kMaxPacketSize);
- if (FLAGS_quic_simple_packet_number_length) {
- // The packet number length is updated after every packet is sent,
- // so there is no need to restore the old length after sending.
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
- } else {
- EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
- EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
- }
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- serialized_packet_.packet_number_length);
-
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
- EXPECT_CALL(framer_visitor_, OnPaddingFrame(_));
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
- }
- ProcessPacket(serialized_packet_);
- delete stream_frame;
-}
-
-TEST_P(QuicPacketCreatorTest, ReserializeCryptoFrameWithForwardSecurity) {
- QuicStreamFrame* stream_frame =
- new QuicStreamFrame(kCryptoStreamId, /*fin=*/false, 0u, StringPiece());
- QuicFrames frames;
- frames.push_back(QuicFrame(stream_frame));
- creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- char buffer[kMaxPacketSize];
- PendingRetransmission retransmission(CreateRetransmission(
- frames, true /* has_crypto_handshake */, -1 /* needs full padding */,
- ENCRYPTION_NONE,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- creator_.ReserializeAllFrames(retransmission, buffer, kMaxPacketSize);
- EXPECT_EQ(ENCRYPTION_NONE, serialized_packet_.encryption_level);
- delete stream_frame;
-}
-
-TEST_P(QuicPacketCreatorTest, ReserializeFrameWithForwardSecurity) {
- QuicStreamFrame* stream_frame =
- new QuicStreamFrame(0u, /*fin=*/false, 0u, StringPiece());
- QuicFrames frames;
- frames.push_back(QuicFrame(stream_frame));
- creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
- char buffer[kMaxPacketSize];
- PendingRetransmission retransmission(CreateRetransmission(
- frames, false /* has_crypto_handshake */, 0 /* no padding */,
- ENCRYPTION_NONE,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- creator_.ReserializeAllFrames(retransmission, buffer, kMaxPacketSize);
- EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, serialized_packet_.encryption_level);
- delete stream_frame;
-}
-
-TEST_P(QuicPacketCreatorTest, ReserializeFramesWithFullPadding) {
- QuicFrame frame;
- QuicIOVector io_vector(MakeIOVector("fake handshake message data"));
- QuicPacketCreatorPeer::CreateStreamFrame(&creator_, kCryptoStreamId,
- io_vector, 0u, 0u, false, &frame);
- QuicFrames frames;
- frames.push_back(frame);
- char buffer[kMaxPacketSize];
- PendingRetransmission retransmission(CreateRetransmission(
- frames, true /* has_crypto_handshake */, -1 /* needs full padding */,
- ENCRYPTION_NONE,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- creator_.ReserializeAllFrames(retransmission, buffer, kMaxPacketSize);
- EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_.encrypted_length);
- delete frame.stream_frame;
-}
-
-TEST_P(QuicPacketCreatorTest, ReserializeFramesWithSpecifiedPadding) {
- QuicFrame frame;
- QuicIOVector io_vector(MakeIOVector("fake message data"));
- QuicPacketCreatorPeer::CreateStreamFrame(&creator_, kCryptoStreamId,
- io_vector, 0u, 0u, false, &frame);
-
- const int kNumPaddingBytes1 = 4;
- int packet_size = 0;
- {
- QuicFrames frames;
- frames.push_back(frame);
- char buffer[kMaxPacketSize];
- PendingRetransmission retransmission(CreateRetransmission(
- frames, false /* has_crypto_handshake */,
- kNumPaddingBytes1 /* padding bytes */, ENCRYPTION_NONE,
- FLAGS_quic_simple_packet_number_length
- ? QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)
- : QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- creator_.ReserializeAllFrames(retransmission, buffer, kMaxPacketSize);
- packet_size = serialized_packet_.encrypted_length;
- }
-
- const int kNumPaddingBytes2 = 44;
- QuicFrames frames;
- frames.push_back(frame);
- char buffer[kMaxPacketSize];
- PendingRetransmission retransmission(CreateRetransmission(
- frames, false /* has_crypto_handshake */,
- kNumPaddingBytes2 /* padding bytes */, ENCRYPTION_NONE,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- creator_.ReserializeAllFrames(retransmission, buffer, kMaxPacketSize);
-
- EXPECT_EQ(packet_size + kNumPaddingBytes2 - kNumPaddingBytes1,
- serialized_packet_.encrypted_length);
- delete frame.stream_frame;
-}
-
-TEST_P(QuicPacketCreatorTest, ReserializeFramesWithFullPacketAndPadding) {
- const size_t overhead = GetPacketHeaderOverhead(client_framer_.version()) +
- GetEncryptionOverhead() + GetStreamFrameOverhead();
- size_t capacity = kDefaultMaxPacketSize - overhead;
- for (int delta = -5; delta <= 0; ++delta) {
- string data(capacity + delta, 'A');
- size_t bytes_free = 0 - delta;
-
- QuicFrame frame;
- QuicIOVector io_vector(MakeIOVector(data));
- UniqueStreamBuffer stream_buffer;
- QuicPacketCreatorPeer::CreateStreamFrame(
- &creator_, kCryptoStreamId, io_vector, 0, kOffset, false, &frame);
- QuicFrames frames;
- frames.push_back(frame);
- char buffer[kMaxPacketSize];
- PendingRetransmission retransmission(CreateRetransmission(
- frames, true /* has_crypto_handshake */, -1 /* needs full padding */,
- ENCRYPTION_NONE,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- creator_.ReserializeAllFrames(retransmission, buffer, kMaxPacketSize);
-
- // If there is not enough space in the packet to fit a padding frame
- // (1 byte) and to expand the stream frame (another 2 bytes) the packet
- // will not be padded.
- if (bytes_free < 3) {
- EXPECT_EQ(kDefaultMaxPacketSize - bytes_free,
- serialized_packet_.encrypted_length);
- } else {
- EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_.encrypted_length);
- }
-
- delete frame.stream_frame;
- frames_.clear();
- }
-}
-
-TEST_P(QuicPacketCreatorTest, SerializeConnectionClose) {
- QuicConnectionCloseFrame frame;
- frame.error_code = QUIC_NO_ERROR;
- frame.error_details = "error";
-
- QuicFrames frames;
- frames.push_back(QuicFrame(&frame));
- SerializedPacket serialized = SerializeAllFrames(frames);
- EXPECT_EQ(ENCRYPTION_NONE, serialized.encryption_level);
- ASSERT_EQ(1u, serialized.packet_number);
- ASSERT_EQ(1u, creator_.packet_number());
-
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
- EXPECT_CALL(framer_visitor_, OnConnectionCloseFrame(_));
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
-
- ProcessPacket(serialized);
-}
-
-TEST_P(QuicPacketCreatorTest, ConsumeData) {
- QuicFrame frame;
- QuicIOVector io_vector(MakeIOVector("test"));
- ASSERT_TRUE(
- creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame));
- ASSERT_TRUE(frame.stream_frame);
- size_t consumed = frame.stream_frame->data_length;
- EXPECT_EQ(4u, consumed);
- CheckStreamFrame(frame, 1u, "test", 0u, false);
- EXPECT_TRUE(creator_.HasPendingFrames());
-}
-
-TEST_P(QuicPacketCreatorTest, ConsumeDataFin) {
- QuicFrame frame;
- QuicIOVector io_vector(MakeIOVector("test"));
- ASSERT_TRUE(
- creator_.ConsumeData(1u, io_vector, 0u, 10u, true, false, &frame));
- ASSERT_TRUE(frame.stream_frame);
- size_t consumed = frame.stream_frame->data_length;
- EXPECT_EQ(4u, consumed);
- CheckStreamFrame(frame, 1u, "test", 10u, true);
- EXPECT_TRUE(creator_.HasPendingFrames());
-}
-
-TEST_P(QuicPacketCreatorTest, ConsumeDataFinOnly) {
- QuicFrame frame;
- QuicIOVector io_vector(nullptr, 0, 0);
- ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, true, false, &frame));
- ASSERT_TRUE(frame.stream_frame);
- size_t consumed = frame.stream_frame->data_length;
- EXPECT_EQ(0u, consumed);
- CheckStreamFrame(frame, 1u, string(), 0u, true);
- EXPECT_TRUE(creator_.HasPendingFrames());
-}
-
-TEST_P(QuicPacketCreatorTest, CreateAllFreeBytesForStreamFrames) {
- const size_t overhead = GetPacketHeaderOverhead(client_framer_.version()) +
- GetEncryptionOverhead();
- for (size_t i = overhead; i < overhead + 100; ++i) {
- creator_.SetMaxPacketLength(i);
- const bool should_have_room = i > overhead + GetStreamFrameOverhead();
- ASSERT_EQ(should_have_room,
- creator_.HasRoomForStreamFrame(kClientDataStreamId1, kOffset));
- if (should_have_room) {
- QuicFrame frame;
- QuicIOVector io_vector(MakeIOVector("testdata"));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillRepeatedly(
- Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket));
- ASSERT_TRUE(creator_.ConsumeData(kClientDataStreamId1, io_vector, 0u,
- kOffset, false, false, &frame));
- ASSERT_TRUE(frame.stream_frame);
- size_t bytes_consumed = frame.stream_frame->data_length;
- EXPECT_LT(0u, bytes_consumed);
- creator_.Flush();
- }
- }
-}
-
-TEST_P(QuicPacketCreatorTest, StreamFrameConsumption) {
- // Compute the total overhead for a single frame in packet.
- const size_t overhead = GetPacketHeaderOverhead(client_framer_.version()) +
- GetEncryptionOverhead() + GetStreamFrameOverhead();
- size_t capacity = kDefaultMaxPacketSize - overhead;
- // Now, test various sizes around this size.
- for (int delta = -5; delta <= 5; ++delta) {
- string data(capacity + delta, 'A');
- size_t bytes_free = delta > 0 ? 0 : 0 - delta;
- QuicFrame frame;
- QuicIOVector io_vector(MakeIOVector(data));
- ASSERT_TRUE(creator_.ConsumeData(kClientDataStreamId1, io_vector, 0u,
- kOffset, false, false, &frame));
- ASSERT_TRUE(frame.stream_frame);
-
- // BytesFree() returns bytes available for the next frame, which will
- // be two bytes smaller since the stream frame would need to be grown.
- EXPECT_EQ(2u, creator_.ExpansionOnNewFrame());
- size_t expected_bytes_free = bytes_free < 3 ? 0 : bytes_free - 2;
- EXPECT_EQ(expected_bytes_free, creator_.BytesFree()) << "delta: " << delta;
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- creator_.Flush();
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
- DeleteSerializedPacket();
- }
-}
-
-TEST_P(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) {
- // Compute the total overhead for a single frame in packet.
- const size_t overhead = GetPacketHeaderOverhead(client_framer_.version()) +
- GetEncryptionOverhead() + GetStreamFrameOverhead();
- ASSERT_GT(kMaxPacketSize, overhead);
- size_t capacity = kDefaultMaxPacketSize - overhead;
- // Now, test various sizes around this size.
- for (int delta = -5; delta <= 5; ++delta) {
- string data(capacity + delta, 'A');
- size_t bytes_free = delta > 0 ? 0 : 0 - delta;
-
- QuicFrame frame;
- QuicIOVector io_vector(MakeIOVector(data));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillRepeatedly(
- Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- ASSERT_TRUE(creator_.ConsumeData(kCryptoStreamId, io_vector, 0u, kOffset,
- false, true, &frame));
- ASSERT_TRUE(frame.stream_frame);
- size_t bytes_consumed = frame.stream_frame->data_length;
- EXPECT_LT(0u, bytes_consumed);
- creator_.Flush();
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
- // If there is not enough space in the packet to fit a padding frame
- // (1 byte) and to expand the stream frame (another 2 bytes) the packet
- // will not be padded.
- if (bytes_free < 3) {
- EXPECT_EQ(kDefaultMaxPacketSize - bytes_free,
- serialized_packet_.encrypted_length);
- } else {
- EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_.encrypted_length);
- }
- DeleteSerializedPacket();
- }
-}
-
-TEST_P(QuicPacketCreatorTest, NonCryptoStreamFramePacketNonPadding) {
- // Compute the total overhead for a single frame in packet.
- const size_t overhead = GetPacketHeaderOverhead(client_framer_.version()) +
- GetEncryptionOverhead() + GetStreamFrameOverhead();
- ASSERT_GT(kDefaultMaxPacketSize, overhead);
- size_t capacity = kDefaultMaxPacketSize - overhead;
- // Now, test various sizes around this size.
- for (int delta = -5; delta <= 5; ++delta) {
- string data(capacity + delta, 'A');
- size_t bytes_free = delta > 0 ? 0 : 0 - delta;
-
- QuicFrame frame;
- QuicIOVector io_vector(MakeIOVector(data));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- ASSERT_TRUE(creator_.ConsumeData(kClientDataStreamId1, io_vector, 0u,
- kOffset, false, false, &frame));
- ASSERT_TRUE(frame.stream_frame);
- size_t bytes_consumed = frame.stream_frame->data_length;
- EXPECT_LT(0u, bytes_consumed);
- creator_.Flush();
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
- if (bytes_free > 0) {
- EXPECT_EQ(kDefaultMaxPacketSize - bytes_free,
- serialized_packet_.encrypted_length);
- } else {
- EXPECT_EQ(kDefaultMaxPacketSize, serialized_packet_.encrypted_length);
- }
- DeleteSerializedPacket();
- }
-}
-
-TEST_P(QuicPacketCreatorTest, SerializeVersionNegotiationPacket) {
- QuicFramerPeer::SetPerspective(&client_framer_, Perspective::IS_SERVER);
- QuicVersionVector versions;
- versions.push_back(test::QuicVersionMax());
- std::unique_ptr<QuicEncryptedPacket> encrypted(
- creator_.SerializeVersionNegotiationPacket(versions));
-
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnVersionNegotiationPacket(_));
- }
- QuicFramerPeer::SetPerspective(&client_framer_, Perspective::IS_CLIENT);
- client_framer_.ProcessPacket(*encrypted);
-}
-
-TEST_P(QuicPacketCreatorTest, UpdatePacketNumberLengthLeastAwaiting_Old) {
- FLAGS_quic_simple_packet_number_length = false;
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
-
- QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64);
- creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
-
- QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64 * 256);
- creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
-
- QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64 * 256 * 256);
- creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
-
- QuicPacketCreatorPeer::SetPacketNumber(&creator_,
- UINT64_C(64) * 256 * 256 * 256 * 256);
- creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
-}
-
-TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthBandwidth_old) {
- FLAGS_quic_simple_packet_number_length = false;
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
-
- creator_.UpdatePacketNumberLength(1, 10000 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
-
- creator_.UpdatePacketNumberLength(1, 10000 * 256 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
-
- creator_.UpdatePacketNumberLength(1,
- 10000 * 256 * 256 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
-
- creator_.UpdatePacketNumberLength(
- 1, UINT64_C(1000) * 256 * 256 * 256 * 256 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
-}
-
-TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthLeastAwaiting) {
- FLAGS_quic_simple_packet_number_length = true;
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
-
- QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64);
- creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
-
- QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64 * 256);
- creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
-
- QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64 * 256 * 256);
- creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
-
- QuicPacketCreatorPeer::SetPacketNumber(&creator_,
- UINT64_C(64) * 256 * 256 * 256 * 256);
- creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
-}
-
-TEST_P(QuicPacketCreatorTest, UpdatePacketSequenceNumberLengthCwnd) {
- FLAGS_quic_simple_packet_number_length = true;
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
-
- creator_.UpdatePacketNumberLength(1, 10000 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
-
- creator_.UpdatePacketNumberLength(1, 10000 * 256 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
-
- creator_.UpdatePacketNumberLength(1,
- 10000 * 256 * 256 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
-
- creator_.UpdatePacketNumberLength(
- 1, UINT64_C(1000) * 256 * 256 * 256 * 256 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
-}
-
-TEST_P(QuicPacketCreatorTest, SerializeFrame) {
- if (!GetParam().version_serialization) {
- creator_.StopSendingVersion();
- }
- frames_.push_back(
- QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
- SerializedPacket serialized = SerializeAllFrames(frames_);
- delete frames_[0].stream_frame;
-
- QuicPacketHeader header;
- {
- InSequence s;
- EXPECT_CALL(framer_visitor_, OnPacket());
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_));
- EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_));
- EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_));
- EXPECT_CALL(framer_visitor_, OnPacketHeader(_))
- .WillOnce(DoAll(SaveArg<0>(&header), Return(true)));
- EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
- EXPECT_CALL(framer_visitor_, OnPacketComplete());
- }
- ProcessPacket(serialized);
- EXPECT_EQ(GetParam().version_serialization,
- header.public_header.version_flag);
-}
-
-TEST_P(QuicPacketCreatorTest, ConsumeDataLargerThanOneStreamFrame) {
- if (!GetParam().version_serialization) {
- creator_.StopSendingVersion();
- }
- // A string larger than fits into a frame.
- size_t payload_length;
- creator_.SetMaxPacketLength(GetPacketLengthForOneStream(
- client_framer_.version(),
- QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
- QuicPacketCreatorPeer::SendPathIdInPacket(&creator_),
- !kIncludeDiversificationNonce, creator_.connection_id_length(),
- PACKET_1BYTE_PACKET_NUMBER, &payload_length));
- QuicFrame frame;
- const string too_long_payload(payload_length * 2, 'a');
- QuicIOVector io_vector(MakeIOVector(too_long_payload));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, true, false, &frame));
- ASSERT_TRUE(frame.stream_frame);
- size_t consumed = frame.stream_frame->data_length;
- EXPECT_EQ(payload_length, consumed);
- const string payload(payload_length, 'a');
- CheckStreamFrame(frame, 1u, payload, 0u, false);
- creator_.Flush();
- DeleteSerializedPacket();
-}
-
-TEST_P(QuicPacketCreatorTest, AddFrameAndFlush) {
- if (!GetParam().version_serialization) {
- creator_.StopSendingVersion();
- }
- const size_t max_plaintext_size =
- client_framer_.GetMaxPlaintextSize(creator_.max_packet_length());
- EXPECT_FALSE(creator_.HasPendingFrames());
- EXPECT_EQ(max_plaintext_size -
- GetPacketHeaderSize(
- client_framer_.version(), creator_.connection_id_length(),
- QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
- QuicPacketCreatorPeer::SendPathIdInPacket(&creator_),
- !kIncludeDiversificationNonce, PACKET_1BYTE_PACKET_NUMBER),
- creator_.BytesFree());
-
- // Add a variety of frame types and then a padding frame.
- QuicAckFrame ack_frame(MakeAckFrame(0u));
- EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&ack_frame)));
- EXPECT_TRUE(creator_.HasPendingFrames());
-
- QuicFrame frame;
- QuicIOVector io_vector(MakeIOVector("test"));
- ASSERT_TRUE(
- creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame));
- ASSERT_TRUE(frame.stream_frame);
- size_t consumed = frame.stream_frame->data_length;
- EXPECT_EQ(4u, consumed);
- EXPECT_TRUE(creator_.HasPendingFrames());
-
- QuicPaddingFrame padding_frame;
- EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(padding_frame)));
- EXPECT_TRUE(creator_.HasPendingFrames());
- EXPECT_EQ(0u, creator_.BytesFree());
-
- // Packet is full. Creator will flush.
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- EXPECT_FALSE(creator_.AddSavedFrame(QuicFrame(&ack_frame)));
-
- // Ensure the packet is successfully created.
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
- ASSERT_FALSE(serialized_packet_.retransmittable_frames.empty());
- const QuicFrames& retransmittable = serialized_packet_.retransmittable_frames;
- ASSERT_EQ(1u, retransmittable.size());
- EXPECT_EQ(STREAM_FRAME, retransmittable[0].type);
- ASSERT_TRUE(retransmittable[0].stream_frame);
- DeleteSerializedPacket();
-
- EXPECT_FALSE(creator_.HasPendingFrames());
- EXPECT_EQ(max_plaintext_size -
- GetPacketHeaderSize(
- client_framer_.version(), creator_.connection_id_length(),
- QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
- /*include_path_id=*/false, !kIncludeDiversificationNonce,
- PACKET_1BYTE_PACKET_NUMBER),
- creator_.BytesFree());
-}
-
-TEST_P(QuicPacketCreatorTest, SerializeAndSendStreamFrame) {
- if (!GetParam().version_serialization) {
- creator_.StopSendingVersion();
- }
- EXPECT_FALSE(creator_.HasPendingFrames());
-
- QuicIOVector iov(MakeIOVector("test"));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- ALIGNAS(64) char encrypted_buffer[kMaxPacketSize];
- size_t num_bytes_consumed;
- creator_.CreateAndSerializeStreamFrame(kHeadersStreamId, iov, 0, 0, true,
- nullptr, encrypted_buffer,
- kMaxPacketSize, &num_bytes_consumed);
- EXPECT_EQ(static_cast<size_t>(4), num_bytes_consumed);
-
- // Ensure the packet is successfully created.
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
- ASSERT_FALSE(serialized_packet_.retransmittable_frames.empty());
- const QuicFrames& retransmittable = serialized_packet_.retransmittable_frames;
- ASSERT_EQ(1u, retransmittable.size());
- EXPECT_EQ(STREAM_FRAME, retransmittable[0].type);
- ASSERT_TRUE(retransmittable[0].stream_frame);
- DeleteSerializedPacket();
-
- EXPECT_FALSE(creator_.HasPendingFrames());
-}
-
-TEST_P(QuicPacketCreatorTest, SerializeTruncatedAckFrameWithLargePacketSize) {
- if (!GetParam().version_serialization) {
- creator_.StopSendingVersion();
- }
- creator_.SetMaxPacketLength(kMaxPacketSize);
-
- // Serialized length of ack frame with 2000 nack ranges should be limited by
- // the number of nack ranges that can be fit in an ack frame.
- QuicAckFrame ack_frame = MakeAckFrameWithNackRanges(2000u, 0u);
- size_t frame_len = client_framer_.GetSerializedFrameLength(
- QuicFrame(&ack_frame), creator_.BytesFree(), true, true,
- PACKET_1BYTE_PACKET_NUMBER);
- EXPECT_GT(creator_.BytesFree(), frame_len);
- EXPECT_GT(creator_.max_packet_length(), creator_.PacketSize());
-
- // Add ack frame to creator.
- EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&ack_frame)));
- EXPECT_TRUE(creator_.HasPendingFrames());
- EXPECT_GT(creator_.max_packet_length(), creator_.PacketSize());
- EXPECT_LT(0u, creator_.BytesFree());
-
- // Make sure that an additional stream frame can be added to the packet.
- QuicFrame frame;
- QuicIOVector io_vector(MakeIOVector("test"));
- ASSERT_TRUE(
- creator_.ConsumeData(2u, io_vector, 0u, 0u, false, false, &frame));
- ASSERT_TRUE(frame.stream_frame);
- size_t consumed = frame.stream_frame->data_length;
- EXPECT_EQ(4u, consumed);
- EXPECT_TRUE(creator_.HasPendingFrames());
-
- // Ensure the packet is successfully created, and the packet size estimate
- // matches the serialized packet length.
- if (GetParam().version <= QUIC_VERSION_33) {
- EXPECT_CALL(entropy_calculator_, EntropyHash(_))
- .WillOnce(testing::Return(0));
- }
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- size_t est_packet_size = creator_.PacketSize();
- creator_.Flush();
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
- EXPECT_EQ(est_packet_size, client_framer_.GetMaxPlaintextSize(
- serialized_packet_.encrypted_length));
- DeleteSerializedPacket();
-}
-
-TEST_P(QuicPacketCreatorTest, SerializeTruncatedAckFrameWithSmallPacketSize) {
- if (!GetParam().version_serialization) {
- creator_.StopSendingVersion();
- }
- creator_.SetMaxPacketLength(500u);
-
- const size_t max_plaintext_size =
- client_framer_.GetMaxPlaintextSize(creator_.max_packet_length());
- EXPECT_EQ(max_plaintext_size - creator_.PacketSize(), creator_.BytesFree());
-
- // Serialized length of ack frame with 2000 nack ranges should be limited by
- // the packet size.
- QuicAckFrame ack_frame = MakeAckFrameWithNackRanges(2000u, 0u);
- size_t frame_len = client_framer_.GetSerializedFrameLength(
- QuicFrame(&ack_frame), creator_.BytesFree(), true, true,
- PACKET_1BYTE_PACKET_NUMBER);
- EXPECT_EQ(creator_.BytesFree(), frame_len);
-
- // Add ack frame to creator.
- EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&ack_frame)));
- EXPECT_TRUE(creator_.HasPendingFrames());
- EXPECT_EQ(client_framer_.GetMaxPlaintextSize(creator_.max_packet_length()),
- creator_.PacketSize());
- EXPECT_EQ(0u, creator_.BytesFree());
-
- // Ensure the packet is successfully created, and the packet size estimate
- // may not match the serialized packet length.
- if (GetParam().version <= QUIC_VERSION_33) {
- EXPECT_CALL(entropy_calculator_, EntropyHash(_)).WillOnce(Return(0));
- }
- size_t est_packet_size = creator_.PacketSize();
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- creator_.Flush();
- ASSERT_TRUE(serialized_packet_.encrypted_buffer);
- EXPECT_GE(est_packet_size, client_framer_.GetMaxPlaintextSize(
- serialized_packet_.encrypted_length));
- DeleteSerializedPacket();
-}
-
-TEST_P(QuicPacketCreatorTest, EntropyFlag) {
- frames_.push_back(
- QuicFrame(new QuicStreamFrame(0u, false, 0u, StringPiece())));
-
- for (int i = 0; i < 2; ++i) {
- for (int j = 0; j < 64; ++j) {
- SerializedPacket serialized = SerializeAllFrames(frames_);
- // Verify both BoolSource and hash algorithm.
- bool expected_rand_bool =
- (mock_random_.RandUint64() & (UINT64_C(1) << j)) != 0;
- bool observed_rand_bool =
- (serialized.entropy_hash & (1 << ((j + 1) % 8))) != 0;
- uint8_t rest_of_hash = serialized.entropy_hash & ~(1 << ((j + 1) % 8));
- EXPECT_EQ(expected_rand_bool, observed_rand_bool);
- EXPECT_EQ(0, rest_of_hash);
- }
- // After 64 calls, BoolSource will refresh the bucket - make sure it does.
- mock_random_.ChangeValue();
- }
-
- delete frames_[0].stream_frame;
-}
-
-TEST_P(QuicPacketCreatorTest, SetCurrentPath) {
- // Current path is the default path.
- EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(&creator_));
- EXPECT_EQ(0u, creator_.packet_number());
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
- // Add a stream frame to the creator.
- QuicFrame frame;
- QuicIOVector io_vector(MakeIOVector("test"));
- ASSERT_TRUE(
- creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame));
- ASSERT_TRUE(frame.stream_frame);
- size_t consumed = frame.stream_frame->data_length;
- EXPECT_EQ(4u, consumed);
- EXPECT_TRUE(creator_.HasPendingFrames());
- EXPECT_EQ(0u, creator_.packet_number());
-
- // Change current path.
- QuicPathId kPathId1 = 1;
- EXPECT_DFATAL(creator_.SetCurrentPath(kPathId1, 1, 0),
- "Unable to change paths when a packet is under construction");
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .Times(1)
- .WillRepeatedly(
- Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket));
- creator_.Flush();
- EXPECT_FALSE(creator_.HasPendingFrames());
- creator_.SetCurrentPath(kPathId1, 1, 0);
- EXPECT_EQ(kPathId1, QuicPacketCreatorPeer::GetCurrentPath(&creator_));
- EXPECT_FALSE(creator_.HasPendingFrames());
- EXPECT_EQ(0u, creator_.packet_number());
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
-
- // Change current path back.
- creator_.SetCurrentPath(kDefaultPathId, 2, 1);
- EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(&creator_));
- EXPECT_EQ(1u, creator_.packet_number());
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
- // Add a stream frame to the creator.
- ASSERT_TRUE(
- creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame));
- ASSERT_TRUE(frame.stream_frame);
- consumed = frame.stream_frame->data_length;
- EXPECT_EQ(4u, consumed);
- EXPECT_TRUE(creator_.HasPendingFrames());
-
- // Does not change current path.
- creator_.SetCurrentPath(kDefaultPathId, 2, 0);
- EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(&creator_));
- EXPECT_TRUE(creator_.HasPendingFrames());
- EXPECT_EQ(1u, creator_.packet_number());
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
-}
-
-TEST_P(QuicPacketCreatorTest,
- SetCurrentPathAndUpdatePacketSequenceNumberLength) {
- FLAGS_quic_simple_packet_number_length = false;
- // Current path is the default path.
- EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(&creator_));
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
- QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64 * 256 - 2);
- // Add a stream frame to the creator and send the packet.
- QuicFrame frame;
- QuicIOVector io_vector(MakeIOVector("test"));
- ASSERT_TRUE(
- creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .Times(1)
- .WillRepeatedly(
- Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket));
- creator_.Flush();
- EXPECT_EQ(UINT64_C(64 * 256 - 1), creator_.packet_number());
- creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize);
- EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
-
- // Change current path.
- QuicPathId kPathId1 = 1;
- creator_.SetCurrentPath(kPathId1, 1, 0);
- EXPECT_EQ(0u, creator_.packet_number());
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
-
- // Change current path back.
- creator_.SetCurrentPath(kDefaultPathId, 2, 10000 / kDefaultMaxPacketSize);
- EXPECT_EQ(UINT64_C(64 * 256 - 1), creator_.packet_number());
- EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::NextPacketNumberLength(&creator_));
-}
-
-TEST_P(QuicPacketCreatorTest, SerializePacketOnDifferentPath) {
- // Current path is the default path.
- EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(&creator_));
- EXPECT_EQ(0u, creator_.packet_number());
- // Add a stream frame to the creator and flush the packet.
- QuicFrame frame;
- QuicIOVector io_vector(MakeIOVector("test"));
- ASSERT_TRUE(
- creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame));
- ASSERT_TRUE(frame.stream_frame);
- size_t consumed = frame.stream_frame->data_length;
- EXPECT_EQ(4u, consumed);
- EXPECT_TRUE(creator_.HasPendingFrames());
- EXPECT_EQ(0u, creator_.packet_number());
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillRepeatedly(
- Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
- creator_.Flush();
- EXPECT_FALSE(creator_.HasPendingFrames());
- EXPECT_EQ(1u, creator_.packet_number());
- // Verify serialized data packet's path id.
- EXPECT_EQ(kDefaultPathId, serialized_packet_.path_id);
- DeleteSerializedPacket();
-
- // Change to path 1.
- QuicPathId kPathId1 = 1;
- creator_.SetCurrentPath(kPathId1, 1, 0);
- EXPECT_EQ(kPathId1, QuicPacketCreatorPeer::GetCurrentPath(&creator_));
- EXPECT_FALSE(creator_.HasPendingFrames());
- EXPECT_EQ(0u, creator_.packet_number());
- EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER,
- QuicPacketCreatorPeer::GetPacketNumberLength(&creator_));
-
- // Add a stream frame to the creator and flush the packet.
- ASSERT_TRUE(
- creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame));
- ASSERT_TRUE(frame.stream_frame);
- consumed = frame.stream_frame->data_length;
- EXPECT_EQ(4u, consumed);
- EXPECT_TRUE(creator_.HasPendingFrames());
- creator_.Flush();
- // Verify serialized data packet's path id.
- EXPECT_EQ(kPathId1, serialized_packet_.path_id);
- DeleteSerializedPacket();
-}
-
-TEST_P(QuicPacketCreatorTest, AddUnencryptedStreamDataClosesConnection) {
- FLAGS_quic_never_write_unencrypted_data = true;
- EXPECT_CALL(delegate_, OnUnrecoverableError(_, _, _));
- QuicStreamFrame stream_frame(kHeadersStreamId, /*fin=*/false, 0u,
- StringPiece());
- EXPECT_DFATAL(creator_.AddSavedFrame(QuicFrame(&stream_frame)),
- "Cannot send stream data without encryption.");
-}
-
-TEST_P(QuicPacketCreatorTest, ChloTooLarge) {
- CryptoHandshakeMessage message;
- message.set_tag(kCHLO);
- message.set_minimum_size(kMaxPacketSize);
- CryptoFramer framer;
- std::unique_ptr<QuicData> message_data;
- message_data.reset(framer.ConstructHandshakeMessage(message));
-
- struct iovec iov;
- QuicIOVector data_iovec(::net::MakeIOVector(
- StringPiece(message_data->data(), message_data->length()), &iov));
- QuicFrame frame;
- EXPECT_CALL(delegate_,
- OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, _, _));
- EXPECT_DFATAL(
- creator_.ConsumeData(1u, data_iovec, 0u, 0u, false, false, &frame),
- "Client hello won't fit in a single packet.");
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_packet_generator.cc b/chromium/net/quic/quic_packet_generator.cc
deleted file mode 100644
index b9814c5f509..00000000000
--- a/chromium/net/quic/quic_packet_generator.cc
+++ /dev/null
@@ -1,329 +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/quic_packet_generator.h"
-
-#include "base/logging.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-
-using base::StringPiece;
-
-namespace net {
-
-QuicPacketGenerator::QuicPacketGenerator(QuicConnectionId connection_id,
- QuicFramer* framer,
- QuicRandom* random_generator,
- QuicBufferAllocator* buffer_allocator,
- DelegateInterface* delegate)
- : delegate_(delegate),
- packet_creator_(connection_id,
- framer,
- random_generator,
- buffer_allocator,
- delegate),
- batch_mode_(false),
- should_send_ack_(false),
- should_send_stop_waiting_(false) {}
-
-QuicPacketGenerator::~QuicPacketGenerator() {
- QuicUtils::DeleteFrames(&queued_control_frames_);
-}
-
-void QuicPacketGenerator::SetShouldSendAck(bool also_send_stop_waiting) {
- if (packet_creator_.has_ack()) {
- // Ack already queued, nothing to do.
- return;
- }
-
- if (also_send_stop_waiting && packet_creator_.has_stop_waiting()) {
- QUIC_BUG << "Should only ever be one pending stop waiting frame.";
- return;
- }
-
- should_send_ack_ = true;
- should_send_stop_waiting_ = also_send_stop_waiting;
- SendQueuedFrames(/*flush=*/false);
-}
-
-void QuicPacketGenerator::AddControlFrame(const QuicFrame& frame) {
- queued_control_frames_.push_back(frame);
- SendQueuedFrames(/*flush=*/false);
-}
-
-QuicConsumedData QuicPacketGenerator::ConsumeData(
- QuicStreamId id,
- QuicIOVector iov,
- QuicStreamOffset offset,
- bool fin,
- QuicAckListenerInterface* listener) {
- bool has_handshake = (id == kCryptoStreamId);
- QUIC_BUG_IF(has_handshake && fin)
- << "Handshake packets should never send a fin";
- // To make reasoning about crypto frames easier, we don't combine them with
- // other retransmittable frames in a single packet.
- const bool flush =
- has_handshake && packet_creator_.HasPendingRetransmittableFrames();
- SendQueuedFrames(flush);
-
- size_t total_bytes_consumed = 0;
- bool fin_consumed = false;
-
- if (!packet_creator_.HasRoomForStreamFrame(id, offset)) {
- packet_creator_.Flush();
- }
-
- if (!fin && (iov.total_length == 0)) {
- QUIC_BUG << "Attempt to consume empty data without FIN.";
- return QuicConsumedData(0, false);
- }
-
- while (delegate_->ShouldGeneratePacket(
- HAS_RETRANSMITTABLE_DATA, has_handshake ? IS_HANDSHAKE : NOT_HANDSHAKE)) {
- QuicFrame frame;
- if (!packet_creator_.ConsumeData(id, iov, total_bytes_consumed,
- offset + total_bytes_consumed, fin,
- has_handshake, &frame)) {
- // The creator is always flushed if there's not enough room for a new
- // stream frame before ConsumeData, so ConsumeData should always succeed.
- QUIC_BUG << "Failed to ConsumeData, stream:" << id;
- return QuicConsumedData(0, false);
- }
-
- // A stream frame is created and added.
- size_t bytes_consumed = frame.stream_frame->data_length;
- if (listener != nullptr) {
- packet_creator_.AddAckListener(listener, bytes_consumed);
- }
- total_bytes_consumed += bytes_consumed;
- fin_consumed = fin && total_bytes_consumed == iov.total_length;
- DCHECK(total_bytes_consumed == iov.total_length ||
- (bytes_consumed > 0 && packet_creator_.HasPendingFrames()));
-
- if (!InBatchMode()) {
- packet_creator_.Flush();
- }
-
- if (total_bytes_consumed == iov.total_length) {
- // We're done writing the data. Exit the loop.
- // We don't make this a precondition because we could have 0 bytes of data
- // if we're simply writing a fin.
- break;
- }
- // TODO(ianswett): Move to having the creator flush itself when it's full.
- packet_creator_.Flush();
- }
-
- // Don't allow the handshake to be bundled with other retransmittable frames.
- if (has_handshake) {
- SendQueuedFrames(/*flush=*/true);
- }
-
- DCHECK(InBatchMode() || !packet_creator_.HasPendingFrames());
- return QuicConsumedData(total_bytes_consumed, fin_consumed);
-}
-
-QuicConsumedData QuicPacketGenerator::ConsumeDataFastPath(
- QuicStreamId id,
- const QuicIOVector& iov,
- QuicStreamOffset offset,
- bool fin,
- QuicAckListenerInterface* listener) {
- DCHECK_NE(id, kCryptoStreamId);
- size_t total_bytes_consumed = 0;
- while (total_bytes_consumed < iov.total_length &&
- delegate_->ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA,
- NOT_HANDSHAKE)) {
- // Serialize and encrypt the packet.
- ALIGNAS(64) char encrypted_buffer[kMaxPacketSize];
- size_t bytes_consumed = 0;
- packet_creator_.CreateAndSerializeStreamFrame(
- id, iov, total_bytes_consumed, offset + total_bytes_consumed, fin,
- listener, encrypted_buffer, kMaxPacketSize, &bytes_consumed);
- total_bytes_consumed += bytes_consumed;
- }
-
- return QuicConsumedData(total_bytes_consumed,
- fin && (total_bytes_consumed == iov.total_length));
-}
-
-void QuicPacketGenerator::GenerateMtuDiscoveryPacket(
- QuicByteCount target_mtu,
- QuicAckListenerInterface* listener) {
- // MTU discovery frames must be sent by themselves.
- if (!packet_creator_.CanSetMaxPacketLength()) {
- QUIC_BUG << "MTU discovery packets should only be sent when no other "
- << "frames needs to be sent.";
- return;
- }
- const QuicByteCount current_mtu = GetCurrentMaxPacketLength();
-
- // The MTU discovery frame is allocated on the stack, since it is going to be
- // serialized within this function.
- QuicMtuDiscoveryFrame mtu_discovery_frame;
- QuicFrame frame(mtu_discovery_frame);
-
- // Send the probe packet with the new length.
- SetMaxPacketLength(target_mtu);
- const bool success = packet_creator_.AddPaddedSavedFrame(frame);
- if (listener != nullptr) {
- packet_creator_.AddAckListener(listener, 0);
- }
- packet_creator_.Flush();
- // The only reason AddFrame can fail is that the packet is too full to fit in
- // a ping. This is not possible for any sane MTU.
- DCHECK(success);
-
- // Reset the packet length back.
- SetMaxPacketLength(current_mtu);
-}
-
-bool QuicPacketGenerator::CanSendWithNextPendingFrameAddition() const {
- DCHECK(HasPendingFrames());
- HasRetransmittableData retransmittable =
- (should_send_ack_ || should_send_stop_waiting_)
- ? NO_RETRANSMITTABLE_DATA
- : HAS_RETRANSMITTABLE_DATA;
- if (retransmittable == HAS_RETRANSMITTABLE_DATA) {
- DCHECK(!queued_control_frames_.empty()); // These are retransmittable.
- }
- return delegate_->ShouldGeneratePacket(retransmittable, NOT_HANDSHAKE);
-}
-
-void QuicPacketGenerator::SendQueuedFrames(bool flush) {
- // Only add pending frames if we are SURE we can then send the whole packet.
- while (HasPendingFrames() &&
- (flush || CanSendWithNextPendingFrameAddition())) {
- AddNextPendingFrame();
- }
- if (flush || !InBatchMode()) {
- packet_creator_.Flush();
- }
-}
-
-bool QuicPacketGenerator::InBatchMode() {
- return batch_mode_;
-}
-
-void QuicPacketGenerator::StartBatchOperations() {
- batch_mode_ = true;
-}
-
-void QuicPacketGenerator::FinishBatchOperations() {
- batch_mode_ = false;
- SendQueuedFrames(/*flush=*/false);
-}
-
-void QuicPacketGenerator::FlushAllQueuedFrames() {
- SendQueuedFrames(/*flush=*/true);
-}
-
-bool QuicPacketGenerator::HasQueuedFrames() const {
- return packet_creator_.HasPendingFrames() || HasPendingFrames();
-}
-
-bool QuicPacketGenerator::IsPendingPacketEmpty() const {
- return !packet_creator_.HasPendingFrames();
-}
-
-bool QuicPacketGenerator::HasPendingFrames() const {
- return should_send_ack_ || should_send_stop_waiting_ ||
- !queued_control_frames_.empty();
-}
-
-bool QuicPacketGenerator::AddNextPendingFrame() {
- if (should_send_ack_) {
- should_send_ack_ =
- !packet_creator_.AddSavedFrame(delegate_->GetUpdatedAckFrame());
- return !should_send_ack_;
- }
-
- if (should_send_stop_waiting_) {
- delegate_->PopulateStopWaitingFrame(&pending_stop_waiting_frame_);
- // If we can't this add the frame now, then we still need to do so later.
- should_send_stop_waiting_ =
- !packet_creator_.AddSavedFrame(QuicFrame(&pending_stop_waiting_frame_));
- // Return success if we have cleared out this flag (i.e., added the frame).
- // If we still need to send, then the frame is full, and we have failed.
- return !should_send_stop_waiting_;
- }
-
- QUIC_BUG_IF(queued_control_frames_.empty())
- << "AddNextPendingFrame called with no queued control frames.";
- if (!packet_creator_.AddSavedFrame(queued_control_frames_.back())) {
- // Packet was full.
- return false;
- }
- queued_control_frames_.pop_back();
- return true;
-}
-
-void QuicPacketGenerator::StopSendingVersion() {
- packet_creator_.StopSendingVersion();
-}
-
-void QuicPacketGenerator::SetDiversificationNonce(
- const DiversificationNonce nonce) {
- packet_creator_.SetDiversificationNonce(nonce);
-}
-
-QuicPacketNumber QuicPacketGenerator::packet_number() const {
- return packet_creator_.packet_number();
-}
-
-QuicByteCount QuicPacketGenerator::GetCurrentMaxPacketLength() const {
- return packet_creator_.max_packet_length();
-}
-
-void QuicPacketGenerator::SetMaxPacketLength(QuicByteCount length) {
- DCHECK(packet_creator_.CanSetMaxPacketLength());
- packet_creator_.SetMaxPacketLength(length);
-}
-
-QuicEncryptedPacket* QuicPacketGenerator::SerializeVersionNegotiationPacket(
- const QuicVersionVector& supported_versions) {
- return packet_creator_.SerializeVersionNegotiationPacket(supported_versions);
-}
-
-void QuicPacketGenerator::ReserializeAllFrames(
- const PendingRetransmission& retransmission,
- char* buffer,
- size_t buffer_len) {
- packet_creator_.ReserializeAllFrames(retransmission, buffer, buffer_len);
-}
-
-void QuicPacketGenerator::UpdateSequenceNumberLength(
- QuicPacketNumber least_packet_awaited_by_peer,
- QuicPacketCount max_packets_in_flight) {
- return packet_creator_.UpdatePacketNumberLength(least_packet_awaited_by_peer,
- max_packets_in_flight);
-}
-
-void QuicPacketGenerator::SetConnectionIdLength(uint32_t length) {
- if (length == 0) {
- packet_creator_.set_connection_id_length(PACKET_0BYTE_CONNECTION_ID);
- } else {
- packet_creator_.set_connection_id_length(PACKET_8BYTE_CONNECTION_ID);
- }
-}
-
-void QuicPacketGenerator::set_encryption_level(EncryptionLevel level) {
- packet_creator_.set_encryption_level(level);
-}
-
-void QuicPacketGenerator::SetEncrypter(EncryptionLevel level,
- QuicEncrypter* encrypter) {
- packet_creator_.SetEncrypter(level, encrypter);
-}
-
-void QuicPacketGenerator::SetCurrentPath(
- QuicPathId path_id,
- QuicPacketNumber least_packet_awaited_by_peer,
- QuicPacketCount max_packets_in_flight) {
- packet_creator_.SetCurrentPath(path_id, least_packet_awaited_by_peer,
- max_packets_in_flight);
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_packet_generator.h b/chromium/net/quic/quic_packet_generator.h
deleted file mode 100644
index 498c95ce091..00000000000
--- a/chromium/net/quic/quic_packet_generator.h
+++ /dev/null
@@ -1,225 +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.
-//
-// Responsible for generating packets on behalf of a QuicConnection.
-// Packets are serialized just-in-time. Control frames are queued.
-// Ack and Feedback frames will be requested from the Connection
-// just-in-time. When a packet needs to be sent, the Generator
-// will serialize a packet and pass it to QuicConnection::SendOrQueuePacket()
-//
-// The Generator's mode of operation is controlled by two conditions:
-//
-// 1) Is the Delegate writable?
-//
-// If the Delegate is not writable, then no operations will cause
-// a packet to be serialized. In particular:
-// * SetShouldSendAck will simply record that an ack is to be sent.
-// * AddControlFrame will enqueue the control frame.
-// * ConsumeData will do nothing.
-//
-// If the Delegate is writable, then the behavior depends on the second
-// condition:
-//
-// 2) Is the Generator in batch mode?
-//
-// If the Generator is NOT in batch mode, then each call to a write
-// operation will serialize one or more packets. The contents will
-// include any previous queued frames. If an ack should be sent
-// but has not been sent, then the Delegate will be asked to create
-// an Ack frame which will then be included in the packet. When
-// the write call completes, the current packet will be serialized
-// and sent to the Delegate, even if it is not full.
-//
-// If the Generator is in batch mode, then each write operation will
-// add data to the "current" packet. When the current packet becomes
-// full, it will be serialized and sent to the packet. When batch
-// mode is ended via |FinishBatchOperations|, the current packet
-// will be serialzied, even if it is not full.
-
-#ifndef NET_QUIC_QUIC_PACKET_GENERATOR_H_
-#define NET_QUIC_QUIC_PACKET_GENERATOR_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <list>
-
-#include "base/macros.h"
-#include "net/quic/quic_packet_creator.h"
-#include "net/quic/quic_sent_packet_manager.h"
-#include "net/quic/quic_types.h"
-
-namespace net {
-
-namespace test {
-class QuicPacketGeneratorPeer;
-} // namespace test
-
-class NET_EXPORT_PRIVATE QuicPacketGenerator {
- public:
- class NET_EXPORT_PRIVATE DelegateInterface
- : public QuicPacketCreator::DelegateInterface {
- public:
- ~DelegateInterface() override {}
- // Consults delegate whether a packet should be generated.
- virtual bool ShouldGeneratePacket(HasRetransmittableData retransmittable,
- IsHandshake handshake) = 0;
- virtual const QuicFrame GetUpdatedAckFrame() = 0;
- virtual void PopulateStopWaitingFrame(
- QuicStopWaitingFrame* stop_waiting) = 0;
- };
-
- QuicPacketGenerator(QuicConnectionId connection_id,
- QuicFramer* framer,
- QuicRandom* random_generator,
- QuicBufferAllocator* buffer_allocator,
- DelegateInterface* delegate);
-
- ~QuicPacketGenerator();
-
- // Indicates that an ACK frame should be sent.
- // If |also_send_stop_waiting| is true, then it also indicates that a
- // STOP_WAITING frame should be sent as well.
- // The contents of the frame(s) will be generated via a call to the delegate
- // CreateAckFrame() when the packet is serialized.
- void SetShouldSendAck(bool also_send_stop_waiting);
-
- void AddControlFrame(const QuicFrame& frame);
-
- // Given some data, may consume part or all of it and pass it to the
- // packet creator to be serialized into packets. If not in batch
- // mode, these packets will also be sent during this call.
- // |delegate| (if not nullptr) will be informed once all packets sent as a
- // result of this call are ACKed by the peer.
- QuicConsumedData ConsumeData(QuicStreamId id,
- QuicIOVector iov,
- QuicStreamOffset offset,
- bool fin,
- QuicAckListenerInterface* listener);
-
- // Sends as many data only packets as allowed by the send algorithm and the
- // available iov.
- // This path does not support FEC, padding, or bundling pending frames.
- QuicConsumedData ConsumeDataFastPath(QuicStreamId id,
- const QuicIOVector& iov,
- QuicStreamOffset offset,
- bool fin,
- QuicAckListenerInterface* listener);
-
- // Generates an MTU discovery packet of specified size.
- void GenerateMtuDiscoveryPacket(QuicByteCount target_mtu,
- QuicAckListenerInterface* listener);
-
- // Indicates whether batch mode is currently enabled.
- bool InBatchMode();
- // Disables flushing.
- void StartBatchOperations();
- // Enables flushing and flushes queued data which can be sent.
- void FinishBatchOperations();
-
- // Flushes all queued frames, even frames which are not sendable.
- void FlushAllQueuedFrames();
-
- bool HasQueuedFrames() const;
-
- // Whether the pending packet has no frames in it at the moment.
- bool IsPendingPacketEmpty() const;
-
- // Makes the framer not serialize the protocol version in sent packets.
- void StopSendingVersion();
-
- // SetDiversificationNonce sets the nonce that will be sent in each public
- // header of packets encrypted at the initial encryption level. Should only
- // be called by servers.
- void SetDiversificationNonce(const DiversificationNonce nonce);
-
- // Creates a version negotiation packet which supports |supported_versions|.
- // Caller owns the created packet. Also, sets the entropy hash of the
- // serialized packet to a random bool and returns that value as a member of
- // SerializedPacket.
- QuicEncryptedPacket* SerializeVersionNegotiationPacket(
- const QuicVersionVector& supported_versions);
-
- // Re-serializes frames with the original packet's packet number length.
- // Used for retransmitting packets to ensure they aren't too long.
- void ReserializeAllFrames(const PendingRetransmission& retransmission,
- char* buffer,
- size_t buffer_len);
-
- // Update the packet number length to use in future packets as soon as it
- // can be safely changed.
- void UpdateSequenceNumberLength(QuicPacketNumber least_packet_awaited_by_peer,
- QuicPacketCount max_packets_in_flight);
-
- // Set the minimum number of bytes for the connection id length;
- void SetConnectionIdLength(uint32_t length);
-
- // Sets the encrypter to use for the encryption level.
- void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter);
-
- // Sets the encryption level that will be applied to new packets.
- void set_encryption_level(EncryptionLevel level);
-
- // packet number of the last created packet, or 0 if no packets have been
- // created.
- QuicPacketNumber packet_number() const;
-
- // Returns the maximum length a current packet can actually have.
- QuicByteCount GetCurrentMaxPacketLength() const;
-
- // Set maximum packet length in the creator immediately. May not be called
- // when there are frames queued in the creator.
- void SetMaxPacketLength(QuicByteCount length);
-
- // Sets |path_id| to be the path on which next packet is generated.
- void SetCurrentPath(QuicPathId path_id,
- QuicPacketNumber least_packet_awaited_by_peer,
- QuicPacketCount max_packets_in_flight);
-
- void set_debug_delegate(QuicPacketCreator::DebugDelegate* debug_delegate) {
- packet_creator_.set_debug_delegate(debug_delegate);
- }
-
- const QuicAckFrame& pending_ack_frame() const { return pending_ack_frame_; }
-
- private:
- friend class test::QuicPacketGeneratorPeer;
-
- void SendQueuedFrames(bool flush);
-
- // Test to see if we have pending ack, or control frames.
- bool HasPendingFrames() const;
- // Returns true if addition of a pending frame (which might be
- // retransmittable) would still allow the resulting packet to be sent now.
- bool CanSendWithNextPendingFrameAddition() const;
- // Add exactly one pending frame, preferring ack frames over control frames.
- // Returns true if a pending frame is successfully added.
- // Returns false and flushes current open packet if the pending frame cannot
- // fit into current open packet.
- bool AddNextPendingFrame();
-
- DelegateInterface* delegate_;
-
- QuicPacketCreator packet_creator_;
- QuicFrames queued_control_frames_;
-
- // True if batch mode is currently enabled.
- bool batch_mode_;
-
- // Flags to indicate the need for just-in-time construction of a frame.
- bool should_send_ack_;
- bool should_send_stop_waiting_;
- // If we put a non-retransmittable frame in this packet, then we have to hold
- // a reference to it until we flush (and serialize it). Retransmittable frames
- // are referenced elsewhere so that they can later be (optionally)
- // retransmitted.
- QuicAckFrame pending_ack_frame_;
- QuicStopWaitingFrame pending_stop_waiting_frame_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicPacketGenerator);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_PACKET_GENERATOR_H_
diff --git a/chromium/net/quic/quic_packet_generator_test.cc b/chromium/net/quic/quic_packet_generator_test.cc
deleted file mode 100644
index a63d0bd5379..00000000000
--- a/chromium/net/quic/quic_packet_generator_test.cc
+++ /dev/null
@@ -1,880 +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/quic_packet_generator.h"
-
-#include <cstdint>
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/null_encrypter.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_simple_buffer_allocator.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/quic_packet_creator_peer.h"
-#include "net/quic/test_tools/quic_packet_generator_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/quic/test_tools/simple_quic_framer.h"
-#include "net/test/gtest_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::StringPiece;
-using std::string;
-using std::vector;
-using testing::InSequence;
-using testing::Return;
-using testing::StrictMock;
-using testing::_;
-
-namespace net {
-namespace test {
-namespace {
-
-class MockDelegate : public QuicPacketGenerator::DelegateInterface {
- public:
- MockDelegate() {}
- ~MockDelegate() override {}
-
- MOCK_METHOD2(ShouldGeneratePacket,
- bool(HasRetransmittableData retransmittable,
- IsHandshake handshake));
- MOCK_METHOD0(GetUpdatedAckFrame, const QuicFrame());
- MOCK_METHOD1(PopulateStopWaitingFrame, void(QuicStopWaitingFrame*));
- MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet));
- MOCK_METHOD3(OnUnrecoverableError,
- void(QuicErrorCode, const string&, ConnectionCloseSource));
-
- void SetCanWriteAnything() {
- EXPECT_CALL(*this, ShouldGeneratePacket(_, _)).WillRepeatedly(Return(true));
- EXPECT_CALL(*this, ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, _))
- .WillRepeatedly(Return(true));
- }
-
- void SetCanNotWrite() {
- EXPECT_CALL(*this, ShouldGeneratePacket(_, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(*this, ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, _))
- .WillRepeatedly(Return(false));
- }
-
- // Use this when only ack frames should be allowed to be written.
- void SetCanWriteOnlyNonRetransmittable() {
- EXPECT_CALL(*this, ShouldGeneratePacket(_, _))
- .WillRepeatedly(Return(false));
- EXPECT_CALL(*this, ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, _))
- .WillRepeatedly(Return(true));
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockDelegate);
-};
-
-// Simple struct for describing the contents of a packet.
-// Useful in conjunction with a SimpleQuicFrame for validating that a packet
-// contains the expected frames.
-struct PacketContents {
- PacketContents()
- : num_ack_frames(0),
- num_connection_close_frames(0),
- num_goaway_frames(0),
- num_rst_stream_frames(0),
- num_stop_waiting_frames(0),
- num_stream_frames(0),
- num_ping_frames(0),
- num_mtu_discovery_frames(0) {}
-
- size_t num_ack_frames;
- size_t num_connection_close_frames;
- size_t num_goaway_frames;
- size_t num_rst_stream_frames;
- size_t num_stop_waiting_frames;
- size_t num_stream_frames;
- size_t num_ping_frames;
- size_t num_mtu_discovery_frames;
-};
-
-} // namespace
-
-class QuicPacketGeneratorTest : public ::testing::Test {
- public:
- QuicPacketGeneratorTest()
- : framer_(QuicSupportedVersions(),
- QuicTime::Zero(),
- Perspective::IS_CLIENT),
- generator_(42, &framer_, &random_, &buffer_allocator_, &delegate_),
- creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)) {
- // TODO(ianswett): Fix this test so it uses a non-null encrypter.
- FLAGS_quic_never_write_unencrypted_data = false;
- }
-
- ~QuicPacketGeneratorTest() override {
- for (SerializedPacket& packet : packets_) {
- delete[] packet.encrypted_buffer;
- QuicUtils::ClearSerializedPacket(&packet);
- }
- }
-
- void SavePacket(SerializedPacket* packet) {
- packet->encrypted_buffer = QuicUtils::CopyBuffer(*packet);
- packets_.push_back(*packet);
- packet->encrypted_buffer = nullptr;
- packet->retransmittable_frames.clear();
- }
-
- protected:
- QuicRstStreamFrame* CreateRstStreamFrame() {
- return new QuicRstStreamFrame(1, QUIC_STREAM_NO_ERROR, 0);
- }
-
- QuicGoAwayFrame* CreateGoAwayFrame() {
- return new QuicGoAwayFrame(QUIC_NO_ERROR, 1, string());
- }
-
- void CheckPacketContains(const PacketContents& contents,
- size_t packet_index) {
- ASSERT_GT(packets_.size(), packet_index);
- const SerializedPacket& packet = packets_[packet_index];
- size_t num_retransmittable_frames =
- contents.num_connection_close_frames + contents.num_goaway_frames +
- contents.num_rst_stream_frames + contents.num_stream_frames +
- contents.num_ping_frames;
- size_t num_frames =
- contents.num_ack_frames + contents.num_stop_waiting_frames +
- contents.num_mtu_discovery_frames + num_retransmittable_frames;
-
- if (num_retransmittable_frames == 0) {
- ASSERT_TRUE(packet.retransmittable_frames.empty());
- } else {
- ASSERT_FALSE(packet.retransmittable_frames.empty());
- EXPECT_EQ(num_retransmittable_frames,
- packet.retransmittable_frames.size());
- }
-
- ASSERT_TRUE(packet.encrypted_buffer != nullptr);
- ASSERT_TRUE(simple_framer_.ProcessPacket(
- QuicEncryptedPacket(packet.encrypted_buffer, packet.encrypted_length)));
- EXPECT_EQ(num_frames, simple_framer_.num_frames());
- EXPECT_EQ(contents.num_ack_frames, simple_framer_.ack_frames().size());
- EXPECT_EQ(contents.num_connection_close_frames,
- simple_framer_.connection_close_frames().size());
- EXPECT_EQ(contents.num_goaway_frames,
- simple_framer_.goaway_frames().size());
- EXPECT_EQ(contents.num_rst_stream_frames,
- simple_framer_.rst_stream_frames().size());
- EXPECT_EQ(contents.num_stream_frames,
- simple_framer_.stream_frames().size());
- EXPECT_EQ(contents.num_stop_waiting_frames,
- simple_framer_.stop_waiting_frames().size());
-
- // From the receiver's perspective, MTU discovery frames are ping frames.
- EXPECT_EQ(contents.num_ping_frames + contents.num_mtu_discovery_frames,
- simple_framer_.ping_frames().size());
- }
-
- void CheckPacketHasSingleStreamFrame(size_t packet_index) {
- ASSERT_GT(packets_.size(), packet_index);
- const SerializedPacket& packet = packets_[packet_index];
- ASSERT_FALSE(packet.retransmittable_frames.empty());
- EXPECT_EQ(1u, packet.retransmittable_frames.size());
- ASSERT_TRUE(packet.encrypted_buffer != nullptr);
- ASSERT_TRUE(simple_framer_.ProcessPacket(
- QuicEncryptedPacket(packet.encrypted_buffer, packet.encrypted_length)));
- EXPECT_EQ(1u, simple_framer_.num_frames());
- EXPECT_EQ(1u, simple_framer_.stream_frames().size());
- }
-
- void CheckAllPacketsHaveSingleStreamFrame() {
- for (size_t i = 0; i < packets_.size(); i++) {
- CheckPacketHasSingleStreamFrame(i);
- }
- }
-
- QuicIOVector CreateData(size_t len) {
- data_array_.reset(new char[len]);
- memset(data_array_.get(), '?', len);
- iov_.iov_base = data_array_.get();
- iov_.iov_len = len;
- return QuicIOVector(&iov_, 1, len);
- }
-
- QuicIOVector MakeIOVector(StringPiece s) {
- return ::net::MakeIOVector(s, &iov_);
- }
-
- QuicFramer framer_;
- MockRandom random_;
- SimpleBufferAllocator buffer_allocator_;
- StrictMock<MockDelegate> delegate_;
- QuicPacketGenerator generator_;
- QuicPacketCreator* creator_;
- SimpleQuicFramer simple_framer_;
- vector<SerializedPacket> packets_;
- QuicAckFrame ack_frame_;
-
- private:
- std::unique_ptr<char[]> data_array_;
- struct iovec iov_;
-};
-
-class MockDebugDelegate : public QuicPacketCreator::DebugDelegate {
- public:
- MOCK_METHOD1(OnFrameAddedToPacket, void(const QuicFrame&));
-};
-
-TEST_F(QuicPacketGeneratorTest, ShouldSendAck_NotWritable) {
- delegate_.SetCanNotWrite();
-
- generator_.SetShouldSendAck(false);
- EXPECT_TRUE(generator_.HasQueuedFrames());
-}
-
-TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldNotFlush) {
- StrictMock<MockDebugDelegate> debug_delegate;
-
- generator_.set_debug_delegate(&debug_delegate);
- delegate_.SetCanWriteOnlyNonRetransmittable();
- generator_.StartBatchOperations();
-
- EXPECT_CALL(delegate_, GetUpdatedAckFrame())
- .WillOnce(Return(QuicFrame(&ack_frame_)));
- EXPECT_CALL(debug_delegate, OnFrameAddedToPacket(_)).Times(1);
-
- generator_.SetShouldSendAck(false);
- EXPECT_TRUE(generator_.HasQueuedFrames());
-}
-
-TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldFlush) {
- delegate_.SetCanWriteOnlyNonRetransmittable();
-
- EXPECT_CALL(delegate_, GetUpdatedAckFrame())
- .WillOnce(Return(QuicFrame(&ack_frame_)));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-
- generator_.SetShouldSendAck(false);
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- PacketContents contents;
- contents.num_ack_frames = 1;
- CheckPacketContains(contents, 0);
-}
-
-TEST_F(QuicPacketGeneratorTest, ShouldSendAck_MultipleCalls) {
- // Make sure that calling SetShouldSendAck multiple times does not result in a
- // crash. Previously this would result in multiple QuicFrames queued in the
- // packet generator, with all but the last with internal pointers to freed
- // memory.
- delegate_.SetCanWriteAnything();
-
- // Only one AckFrame should be created.
- EXPECT_CALL(delegate_, GetUpdatedAckFrame())
- .WillOnce(Return(QuicFrame(&ack_frame_)));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .Times(1)
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-
- generator_.StartBatchOperations();
- generator_.SetShouldSendAck(false);
- generator_.SetShouldSendAck(false);
- generator_.FinishBatchOperations();
-}
-
-TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritable) {
- delegate_.SetCanNotWrite();
-
- generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
- EXPECT_TRUE(generator_.HasQueuedFrames());
-}
-
-TEST_F(QuicPacketGeneratorTest, AddControlFrame_OnlyAckWritable) {
- delegate_.SetCanWriteOnlyNonRetransmittable();
-
- generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
- EXPECT_TRUE(generator_.HasQueuedFrames());
-}
-
-TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldNotFlush) {
- delegate_.SetCanWriteAnything();
- generator_.StartBatchOperations();
-
- generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
- EXPECT_TRUE(generator_.HasQueuedFrames());
-}
-
-TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritableBatchThenFlush) {
- delegate_.SetCanNotWrite();
- generator_.StartBatchOperations();
-
- generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
- EXPECT_TRUE(generator_.HasQueuedFrames());
- generator_.FinishBatchOperations();
- EXPECT_TRUE(generator_.HasQueuedFrames());
-
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- generator_.FlushAllQueuedFrames();
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- PacketContents contents;
- contents.num_rst_stream_frames = 1;
- CheckPacketContains(contents, 0);
-}
-
-TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldFlush) {
- delegate_.SetCanWriteAnything();
-
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-
- generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- PacketContents contents;
- contents.num_rst_stream_frames = 1;
- CheckPacketContains(contents, 0);
-}
-
-TEST_F(QuicPacketGeneratorTest, ConsumeData_NotWritable) {
- delegate_.SetCanNotWrite();
-
- QuicConsumedData consumed = generator_.ConsumeData(
- kHeadersStreamId, MakeIOVector("foo"), 2, true, nullptr);
- EXPECT_EQ(0u, consumed.bytes_consumed);
- EXPECT_FALSE(consumed.fin_consumed);
- EXPECT_FALSE(generator_.HasQueuedFrames());
-}
-
-TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) {
- delegate_.SetCanWriteAnything();
- generator_.StartBatchOperations();
-
- QuicConsumedData consumed = generator_.ConsumeData(
- kHeadersStreamId, MakeIOVector("foo"), 2, true, nullptr);
- EXPECT_EQ(3u, consumed.bytes_consumed);
- EXPECT_TRUE(consumed.fin_consumed);
- EXPECT_TRUE(generator_.HasQueuedFrames());
-}
-
-TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldFlush) {
- delegate_.SetCanWriteAnything();
-
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- QuicConsumedData consumed = generator_.ConsumeData(
- kHeadersStreamId, MakeIOVector("foo"), 2, true, nullptr);
- EXPECT_EQ(3u, consumed.bytes_consumed);
- EXPECT_TRUE(consumed.fin_consumed);
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- PacketContents contents;
- contents.num_stream_frames = 1;
- CheckPacketContains(contents, 0);
-}
-
-// Test the behavior of ConsumeData when the data consumed is for the crypto
-// handshake stream. Ensure that the packet is always sent and padded even if
-// the generator operates in batch mode.
-TEST_F(QuicPacketGeneratorTest, ConsumeData_Handshake) {
- delegate_.SetCanWriteAnything();
- generator_.StartBatchOperations();
-
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- QuicConsumedData consumed = generator_.ConsumeData(
- kCryptoStreamId, MakeIOVector("foo"), 0, false, nullptr);
- EXPECT_EQ(3u, consumed.bytes_consumed);
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- PacketContents contents;
- contents.num_stream_frames = 1;
- CheckPacketContains(contents, 0);
-
- ASSERT_EQ(1u, packets_.size());
- ASSERT_EQ(kDefaultMaxPacketSize, generator_.GetCurrentMaxPacketLength());
- EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length);
-}
-
-TEST_F(QuicPacketGeneratorTest, ConsumeData_EmptyData) {
- EXPECT_DFATAL(generator_.ConsumeData(kHeadersStreamId, MakeIOVector(""), 0,
- false, nullptr),
- "Attempt to consume empty data without FIN.");
-}
-
-TEST_F(QuicPacketGeneratorTest,
- ConsumeDataMultipleTimes_WritableAndShouldNotFlush) {
- delegate_.SetCanWriteAnything();
- generator_.StartBatchOperations();
-
- generator_.ConsumeData(kHeadersStreamId, MakeIOVector("foo"), 2, true,
- nullptr);
- QuicConsumedData consumed =
- generator_.ConsumeData(3, MakeIOVector("quux"), 7, false, nullptr);
- EXPECT_EQ(4u, consumed.bytes_consumed);
- EXPECT_FALSE(consumed.fin_consumed);
- EXPECT_TRUE(generator_.HasQueuedFrames());
-}
-
-TEST_F(QuicPacketGeneratorTest, ConsumeData_BatchOperations) {
- delegate_.SetCanWriteAnything();
- generator_.StartBatchOperations();
-
- generator_.ConsumeData(kHeadersStreamId, MakeIOVector("foo"), 2, true,
- nullptr);
- QuicConsumedData consumed =
- generator_.ConsumeData(3, MakeIOVector("quux"), 7, false, nullptr);
- EXPECT_EQ(4u, consumed.bytes_consumed);
- EXPECT_FALSE(consumed.fin_consumed);
- EXPECT_TRUE(generator_.HasQueuedFrames());
-
- // Now both frames will be flushed out.
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- generator_.FinishBatchOperations();
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- PacketContents contents;
- contents.num_stream_frames = 2;
- CheckPacketContains(contents, 0);
-}
-
-TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) {
- // Set the packet size be enough for two stream frames with 0 stream offset,
- // but not enough for a stream frame of 0 offset and one with non-zero offset.
- size_t length =
- NullEncrypter().GetCiphertextSize(0) +
- GetPacketHeaderSize(
- framer_.version(), creator_->connection_id_length(), kIncludeVersion,
- !kIncludePathId, !kIncludeDiversificationNonce,
- QuicPacketCreatorPeer::NextPacketNumberLength(creator_)) +
- // Add an extra 3 bytes for the payload and 1 byte so BytesFree is larger
- // than the GetMinStreamFrameSize.
- QuicFramer::GetMinStreamFrameSize(1, 0, false) + 3 +
- QuicFramer::GetMinStreamFrameSize(1, 0, true) + 1;
- generator_.SetMaxPacketLength(length);
- delegate_.SetCanWriteAnything();
- {
- InSequence dummy;
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- }
- generator_.StartBatchOperations();
- // Queue enough data to prevent a stream frame with a non-zero offset from
- // fitting.
- QuicConsumedData consumed = generator_.ConsumeData(
- kHeadersStreamId, MakeIOVector("foo"), 0, false, nullptr);
- EXPECT_EQ(3u, consumed.bytes_consumed);
- EXPECT_FALSE(consumed.fin_consumed);
- EXPECT_TRUE(generator_.HasQueuedFrames());
-
- // This frame will not fit with the existing frame, causing the queued frame
- // to be serialized, and it will be added to a new open packet.
- consumed = generator_.ConsumeData(kHeadersStreamId, MakeIOVector("bar"), 3,
- true, nullptr);
- EXPECT_EQ(3u, consumed.bytes_consumed);
- EXPECT_TRUE(consumed.fin_consumed);
- EXPECT_TRUE(generator_.HasQueuedFrames());
-
- creator_->Flush();
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- PacketContents contents;
- contents.num_stream_frames = 1;
- CheckPacketContains(contents, 0);
- CheckPacketContains(contents, 1);
-}
-
-TEST_F(QuicPacketGeneratorTest, ConsumeDataFastPath) {
- delegate_.SetCanWriteAnything();
-
- // Create a 10000 byte IOVector.
- QuicIOVector iov(CreateData(10000));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- QuicConsumedData consumed =
- generator_.ConsumeDataFastPath(kHeadersStreamId, iov, 0, true, nullptr);
- EXPECT_EQ(10000u, consumed.bytes_consumed);
- EXPECT_TRUE(consumed.fin_consumed);
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- PacketContents contents;
- contents.num_stream_frames = 1;
- CheckPacketContains(contents, 0);
-}
-
-TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) {
- delegate_.SetCanNotWrite();
-
- generator_.SetShouldSendAck(false);
- generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
- EXPECT_TRUE(generator_.HasQueuedFrames());
-
- delegate_.SetCanWriteAnything();
-
- generator_.StartBatchOperations();
-
- // When the first write operation is invoked, the ack frame will be returned.
- EXPECT_CALL(delegate_, GetUpdatedAckFrame())
- .WillOnce(Return(QuicFrame(&ack_frame_)));
-
- // Send some data and a control frame
- generator_.ConsumeData(3, MakeIOVector("quux"), 7, false, nullptr);
- generator_.AddControlFrame(QuicFrame(CreateGoAwayFrame()));
-
- // All five frames will be flushed out in a single packet.
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- generator_.FinishBatchOperations();
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- PacketContents contents;
- contents.num_ack_frames = 1;
- contents.num_goaway_frames = 1;
- contents.num_rst_stream_frames = 1;
- contents.num_stream_frames = 1;
- CheckPacketContains(contents, 0);
-}
-
-TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) {
- delegate_.SetCanNotWrite();
-
- generator_.SetShouldSendAck(false);
- generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame()));
- EXPECT_TRUE(generator_.HasQueuedFrames());
-
- delegate_.SetCanWriteAnything();
-
- generator_.StartBatchOperations();
-
- // When the first write operation is invoked, the ack frame will be returned.
- EXPECT_CALL(delegate_, GetUpdatedAckFrame())
- .WillOnce(Return(QuicFrame(&ack_frame_)));
-
- {
- InSequence dummy;
- // All five frames will be flushed out in a single packet
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- }
-
- // Send enough data to exceed one packet
- size_t data_len = kDefaultMaxPacketSize + 100;
- QuicConsumedData consumed =
- generator_.ConsumeData(3, CreateData(data_len), 0, true, nullptr);
- EXPECT_EQ(data_len, consumed.bytes_consumed);
- EXPECT_TRUE(consumed.fin_consumed);
- generator_.AddControlFrame(QuicFrame(CreateGoAwayFrame()));
-
- generator_.FinishBatchOperations();
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- // The first packet should have the queued data and part of the stream data.
- PacketContents contents;
- contents.num_ack_frames = 1;
- contents.num_rst_stream_frames = 1;
- contents.num_stream_frames = 1;
- CheckPacketContains(contents, 0);
-
- // The second should have the remainder of the stream data.
- PacketContents contents2;
- contents2.num_goaway_frames = 1;
- contents2.num_stream_frames = 1;
- CheckPacketContains(contents2, 1);
-}
-
-TEST_F(QuicPacketGeneratorTest, TestConnectionIdLength) {
- generator_.SetConnectionIdLength(0);
- EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, creator_->connection_id_length());
-
- for (size_t i = 1; i < 10; i++) {
- generator_.SetConnectionIdLength(i);
- EXPECT_EQ(PACKET_8BYTE_CONNECTION_ID, creator_->connection_id_length());
- }
-}
-
-// Test whether SetMaxPacketLength() works in the situation when the queue is
-// empty, and we send three packets worth of data.
-TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_Initial) {
- delegate_.SetCanWriteAnything();
-
- // Send enough data for three packets.
- size_t data_len = 3 * kDefaultMaxPacketSize + 1;
- size_t packet_len = kDefaultMaxPacketSize + 100;
- ASSERT_LE(packet_len, kMaxPacketSize);
- generator_.SetMaxPacketLength(packet_len);
- EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength());
-
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .Times(3)
- .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- QuicConsumedData consumed =
- generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
- /*offset=*/2,
- /*fin=*/true, nullptr);
- EXPECT_EQ(data_len, consumed.bytes_consumed);
- EXPECT_TRUE(consumed.fin_consumed);
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- // We expect three packets, and first two of them have to be of packet_len
- // size. We check multiple packets (instead of just one) because we want to
- // ensure that |max_packet_length_| does not get changed incorrectly by the
- // generator after first packet is serialized.
- ASSERT_EQ(3u, packets_.size());
- EXPECT_EQ(packet_len, packets_[0].encrypted_length);
- EXPECT_EQ(packet_len, packets_[1].encrypted_length);
- CheckAllPacketsHaveSingleStreamFrame();
-}
-
-// Test whether SetMaxPacketLength() works in the situation when we first write
-// data, then change packet size, then write data again.
-TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_Middle) {
- delegate_.SetCanWriteAnything();
-
- // We send enough data to overflow default packet length, but not the altered
- // one.
- size_t data_len = kDefaultMaxPacketSize;
- size_t packet_len = kDefaultMaxPacketSize + 100;
- ASSERT_LE(packet_len, kMaxPacketSize);
-
- // We expect to see three packets in total.
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .Times(3)
- .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-
- // Send two packets before packet size change.
- QuicConsumedData consumed =
- generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
- /*offset=*/2,
- /*fin=*/false, nullptr);
- EXPECT_EQ(data_len, consumed.bytes_consumed);
- EXPECT_FALSE(consumed.fin_consumed);
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- // Make sure we already have two packets.
- ASSERT_EQ(2u, packets_.size());
-
- // Increase packet size.
- generator_.SetMaxPacketLength(packet_len);
- EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength());
-
- // Send a packet after packet size change.
- consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
- 2 + data_len,
- /*fin=*/true, nullptr);
- EXPECT_EQ(data_len, consumed.bytes_consumed);
- EXPECT_TRUE(consumed.fin_consumed);
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- // We expect first data chunk to get fragmented, but the second one to fit
- // into a single packet.
- ASSERT_EQ(3u, packets_.size());
- EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length);
- EXPECT_LE(kDefaultMaxPacketSize, packets_[2].encrypted_length);
- CheckAllPacketsHaveSingleStreamFrame();
-}
-
-// Test whether SetMaxPacketLength() works correctly when we force the change of
-// the packet size in the middle of the batched packet.
-TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_MidpacketFlush) {
- delegate_.SetCanWriteAnything();
- generator_.StartBatchOperations();
-
- size_t first_write_len = kDefaultMaxPacketSize / 2;
- size_t packet_len = kDefaultMaxPacketSize + 100;
- size_t second_write_len = packet_len + 1;
- ASSERT_LE(packet_len, kMaxPacketSize);
-
- // First send half of the packet worth of data. We are in the batch mode, so
- // should not cause packet serialization.
- QuicConsumedData consumed =
- generator_.ConsumeData(kHeadersStreamId, CreateData(first_write_len),
- /*offset=*/2,
- /*fin=*/false, nullptr);
- EXPECT_EQ(first_write_len, consumed.bytes_consumed);
- EXPECT_FALSE(consumed.fin_consumed);
- EXPECT_TRUE(generator_.HasQueuedFrames());
-
- // Make sure we have no packets so far.
- ASSERT_EQ(0u, packets_.size());
-
- // Expect a packet to be flushed.
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-
- // Increase packet size after flushing all frames.
- // Ensure it's immediately enacted.
- generator_.FlushAllQueuedFrames();
- generator_.SetMaxPacketLength(packet_len);
- EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength());
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- // We expect to see exactly one packet serialized after that, because we send
- // a value somewhat exceeding new max packet size, and the tail data does not
- // get serialized because we are still in the batch mode.
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-
- // Send a more than a packet worth of data to the same stream. This should
- // trigger serialization of one packet, and queue another one.
- consumed =
- generator_.ConsumeData(kHeadersStreamId, CreateData(second_write_len),
- /*offset=*/2 + first_write_len,
- /*fin=*/true, nullptr);
- EXPECT_EQ(second_write_len, consumed.bytes_consumed);
- EXPECT_TRUE(consumed.fin_consumed);
- EXPECT_TRUE(generator_.HasQueuedFrames());
-
- // We expect the first packet to be underfilled, and the second packet be up
- // to the new max packet size.
- ASSERT_EQ(2u, packets_.size());
- EXPECT_GT(kDefaultMaxPacketSize, packets_[0].encrypted_length);
- EXPECT_EQ(packet_len, packets_[1].encrypted_length);
-
- CheckAllPacketsHaveSingleStreamFrame();
-}
-
-// Test sending an MTU probe, without any surrounding data.
-TEST_F(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_Simple) {
- delegate_.SetCanWriteAnything();
-
- const size_t target_mtu = kDefaultMaxPacketSize + 100;
- static_assert(target_mtu < kMaxPacketSize,
- "The MTU probe used by the test exceeds maximum packet size");
-
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-
- generator_.GenerateMtuDiscoveryPacket(target_mtu, nullptr);
-
- EXPECT_FALSE(generator_.HasQueuedFrames());
- ASSERT_EQ(1u, packets_.size());
- EXPECT_EQ(target_mtu, packets_[0].encrypted_length);
-
- PacketContents contents;
- contents.num_mtu_discovery_frames = 1;
- CheckPacketContains(contents, 0);
-}
-
-// Test sending an MTU probe. Surround it with data, to ensure that it resets
-// the MTU to the value before the probe was sent.
-TEST_F(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_SurroundedByData) {
- delegate_.SetCanWriteAnything();
-
- const size_t target_mtu = kDefaultMaxPacketSize + 100;
- static_assert(target_mtu < kMaxPacketSize,
- "The MTU probe used by the test exceeds maximum packet size");
-
- // Send enough data so it would always cause two packets to be sent.
- const size_t data_len = target_mtu + 1;
-
- // Send a total of five packets: two packets before the probe, the probe
- // itself, and two packets after the probe.
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .Times(5)
- .WillRepeatedly(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-
- // Send data before the MTU probe.
- QuicConsumedData consumed =
- generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
- /*offset=*/2,
- /*fin=*/false, nullptr);
- EXPECT_EQ(data_len, consumed.bytes_consumed);
- EXPECT_FALSE(consumed.fin_consumed);
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- // Send the MTU probe.
- generator_.GenerateMtuDiscoveryPacket(target_mtu, nullptr);
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- // Send data after the MTU probe.
- consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(data_len),
- /*offset=*/2 + data_len,
- /*fin=*/true, nullptr);
- EXPECT_EQ(data_len, consumed.bytes_consumed);
- EXPECT_TRUE(consumed.fin_consumed);
- EXPECT_FALSE(generator_.HasQueuedFrames());
-
- ASSERT_EQ(5u, packets_.size());
- EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length);
- EXPECT_EQ(target_mtu, packets_[2].encrypted_length);
- EXPECT_EQ(kDefaultMaxPacketSize, packets_[3].encrypted_length);
-
- PacketContents probe_contents;
- probe_contents.num_mtu_discovery_frames = 1;
-
- CheckPacketHasSingleStreamFrame(0);
- CheckPacketHasSingleStreamFrame(1);
- CheckPacketContains(probe_contents, 2);
- CheckPacketHasSingleStreamFrame(3);
- CheckPacketHasSingleStreamFrame(4);
-}
-
-TEST_F(QuicPacketGeneratorTest, DontCrashOnInvalidStopWaiting) {
- // Test added to ensure the generator does not crash when an invalid frame is
- // added. Because this is an indication of internal programming errors,
- // DFATALs are expected.
- // A 1 byte packet number length can't encode a gap of 1000.
- QuicPacketCreatorPeer::SetPacketNumber(creator_, 1000);
-
- delegate_.SetCanNotWrite();
- generator_.SetShouldSendAck(true);
- delegate_.SetCanWriteAnything();
- generator_.StartBatchOperations();
-
- // Set up frames to write into the creator when control frames are written.
- EXPECT_CALL(delegate_, GetUpdatedAckFrame())
- .WillOnce(Return(QuicFrame(&ack_frame_)));
- EXPECT_CALL(delegate_, PopulateStopWaitingFrame(_));
- // Generator should have queued control frames, and creator should be empty.
- EXPECT_TRUE(generator_.HasQueuedFrames());
- EXPECT_FALSE(creator_->HasPendingFrames());
-
- // This will not serialize any packets, because of the invalid frame.
- EXPECT_CALL(delegate_,
- OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, _,
- ConnectionCloseSource::FROM_SELF));
- EXPECT_DFATAL(generator_.FinishBatchOperations(),
- "packet_number_length 1 is too small "
- "for least_unacked_delta: 1001");
-}
-
-TEST_F(QuicPacketGeneratorTest, SetCurrentPath) {
- delegate_.SetCanWriteAnything();
- generator_.StartBatchOperations();
-
- QuicConsumedData consumed = generator_.ConsumeData(
- kHeadersStreamId, MakeIOVector("foo"), 2, true, nullptr);
- EXPECT_EQ(3u, consumed.bytes_consumed);
- EXPECT_TRUE(consumed.fin_consumed);
- EXPECT_TRUE(generator_.HasQueuedFrames());
- EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(creator_));
- // Does not change current path.
- generator_.SetCurrentPath(kDefaultPathId, 1, 0);
- EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(creator_));
-
- // Try to switch path when a packet is under construction.
- QuicPathId kTestPathId1 = 1;
- EXPECT_DFATAL(generator_.SetCurrentPath(kTestPathId1, 1, 0),
- "Unable to change paths when a packet is under construction");
- EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(creator_));
-
- // Try to switch path after current open packet gets serialized.
- EXPECT_CALL(delegate_, OnSerializedPacket(_))
- .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
- generator_.FlushAllQueuedFrames();
- EXPECT_FALSE(generator_.HasQueuedFrames());
- generator_.SetCurrentPath(kTestPathId1, 1, 0);
- EXPECT_EQ(kTestPathId1, QuicPacketCreatorPeer::GetCurrentPath(creator_));
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_packet_writer.h b/chromium/net/quic/quic_packet_writer.h
deleted file mode 100644
index de6804b9f72..00000000000
--- a/chromium/net/quic/quic_packet_writer.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_PACKET_WRITER_H_
-#define NET_QUIC_QUIC_PACKET_WRITER_H_
-
-#include <stddef.h>
-
-#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-class IPAddress;
-struct WriteResult;
-
-class NET_EXPORT_PRIVATE PerPacketOptions {
- public:
- PerPacketOptions() = default;
- virtual ~PerPacketOptions() {}
-
- // Returns a heap-allocated copy of |this|.
- virtual PerPacketOptions* Clone() const = 0;
-
- private:
- PerPacketOptions(PerPacketOptions&& other) = delete;
- PerPacketOptions& operator=(PerPacketOptions&& other) = delete;
-
- DISALLOW_COPY_AND_ASSIGN(PerPacketOptions);
-};
-
-// An interface between writers and the entity managing the
-// socket (in our case the QuicDispatcher). This allows the Dispatcher to
-// control writes, and manage any writers who end up write blocked.
-class NET_EXPORT_PRIVATE QuicPacketWriter {
- public:
- virtual ~QuicPacketWriter() {}
-
- // Sends the packet out to the peer, with some optional per-packet options.
- // If the write succeeded, the result's status is WRITE_STATUS_OK and
- // bytes_written is populated. If the write failed, the result's status is
- // WRITE_STATUS_BLOCKED or WRITE_STATUS_ERROR and error_code is populated.
- // Options must be either null, or created for the particular QuicPacketWriter
- // implementation. Options may be ignored, depending on the implementation.
- virtual WriteResult WritePacket(const char* buffer,
- size_t buf_len,
- const IPAddress& self_address,
- const IPEndPoint& peer_address,
- PerPacketOptions* options) = 0;
-
- // Returns true if the writer buffers and subsequently rewrites data
- // when an attempt to write results in the underlying socket becoming
- // write blocked.
- virtual bool IsWriteBlockedDataBuffered() const = 0;
-
- // Returns true if the network socket is not writable.
- virtual bool IsWriteBlocked() const = 0;
-
- // Records that the socket has become writable, for example when an EPOLLOUT
- // is received or an asynchronous write completes.
- virtual void SetWritable() = 0;
-
- // Returns the maximum size of the packet which can be written using this
- // writer for the supplied peer address. This size may actually exceed the
- // size of a valid QUIC packet.
- virtual QuicByteCount GetMaxPacketSize(
- const IPEndPoint& peer_address) const = 0;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_PACKET_WRITER_H_
diff --git a/chromium/net/quic/quic_protocol.cc b/chromium/net/quic/quic_protocol.cc
deleted file mode 100644
index 41ef5c7bf7e..00000000000
--- a/chromium/net/quic/quic_protocol.cc
+++ /dev/null
@@ -1,881 +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/quic_protocol.h"
-
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-
-using base::StringPiece;
-using std::map;
-using std::numeric_limits;
-using std::ostream;
-using std::string;
-
-namespace net {
-
-const char* const kFinalOffsetHeaderKey = ":final-offset";
-
-size_t GetPacketHeaderSize(QuicVersion version,
- const QuicPacketHeader& header) {
- return GetPacketHeaderSize(version, header.public_header.connection_id_length,
- header.public_header.version_flag,
- header.public_header.multipath_flag,
- header.public_header.nonce != nullptr,
- header.public_header.packet_number_length);
-}
-
-size_t GetPacketHeaderSize(QuicVersion version,
- QuicConnectionIdLength connection_id_length,
- bool include_version,
- bool include_path_id,
- bool include_diversification_nonce,
- QuicPacketNumberLength packet_number_length) {
- return kPublicFlagsSize + connection_id_length +
- (include_version ? kQuicVersionSize : 0) +
- (include_path_id ? kQuicPathIdSize : 0) + packet_number_length +
- (include_diversification_nonce ? kDiversificationNonceSize : 0) +
- (version <= QUIC_VERSION_33 ? kPrivateFlagsSize : 0);
-}
-
-size_t GetStartOfEncryptedData(QuicVersion version,
- const QuicPacketHeader& header) {
- return GetPacketHeaderSize(version, header) -
- (version <= QUIC_VERSION_33 ? kPrivateFlagsSize : 0);
-}
-
-size_t GetStartOfEncryptedData(QuicVersion version,
- QuicConnectionIdLength connection_id_length,
- bool include_version,
- bool include_path_id,
- bool include_diversification_nonce,
- QuicPacketNumberLength packet_number_length) {
- // Encryption starts before private flags.
- return GetPacketHeaderSize(version, connection_id_length, include_version,
- include_path_id, include_diversification_nonce,
- packet_number_length) -
- (version <= QUIC_VERSION_33 ? kPrivateFlagsSize : 0);
-}
-
-QuicPacketPublicHeader::QuicPacketPublicHeader()
- : connection_id(0),
- connection_id_length(PACKET_8BYTE_CONNECTION_ID),
- multipath_flag(false),
- reset_flag(false),
- version_flag(false),
- packet_number_length(PACKET_6BYTE_PACKET_NUMBER),
- nonce(nullptr) {}
-
-QuicPacketPublicHeader::QuicPacketPublicHeader(
- const QuicPacketPublicHeader& other) = default;
-
-QuicPacketPublicHeader::~QuicPacketPublicHeader() {}
-
-QuicPacketHeader::QuicPacketHeader()
- : packet_number(0),
- path_id(kDefaultPathId),
- entropy_flag(false),
- entropy_hash(0),
- fec_flag(false) {}
-
-QuicPacketHeader::QuicPacketHeader(const QuicPacketPublicHeader& header)
- : public_header(header),
- packet_number(0),
- path_id(kDefaultPathId),
- entropy_flag(false),
- entropy_hash(0),
- fec_flag(false) {}
-
-QuicPacketHeader::QuicPacketHeader(const QuicPacketHeader& other) = default;
-
-QuicPublicResetPacket::QuicPublicResetPacket()
- : nonce_proof(0), rejected_packet_number(0) {}
-
-QuicPublicResetPacket::QuicPublicResetPacket(
- const QuicPacketPublicHeader& header)
- : public_header(header), nonce_proof(0), rejected_packet_number(0) {}
-
-QuicBufferAllocator::~QuicBufferAllocator() = default;
-
-void StreamBufferDeleter::operator()(char* buffer) const {
- if (allocator_ != nullptr && buffer != nullptr) {
- allocator_->Delete(buffer);
- }
-}
-
-UniqueStreamBuffer NewStreamBuffer(QuicBufferAllocator* allocator,
- size_t size) {
- return UniqueStreamBuffer(allocator->New(size),
- StreamBufferDeleter(allocator));
-}
-
-QuicStreamFrame::QuicStreamFrame()
- : QuicStreamFrame(0, false, 0, nullptr, 0, nullptr) {}
-
-QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
- bool fin,
- QuicStreamOffset offset,
- StringPiece data)
- : QuicStreamFrame(stream_id,
- fin,
- offset,
- data.data(),
- data.length(),
- nullptr) {}
-
-QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
- bool fin,
- QuicStreamOffset offset,
- QuicPacketLength data_length,
- UniqueStreamBuffer buffer)
- : QuicStreamFrame(stream_id,
- fin,
- offset,
- nullptr,
- data_length,
- std::move(buffer)) {
- DCHECK(this->buffer != nullptr);
- DCHECK_EQ(data_buffer, this->buffer.get());
-}
-
-QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
- bool fin,
- QuicStreamOffset offset,
- const char* data_buffer,
- QuicPacketLength data_length,
- UniqueStreamBuffer buffer)
- : stream_id(stream_id),
- fin(fin),
- data_length(data_length),
- data_buffer(data_buffer),
- offset(offset),
- buffer(std::move(buffer)) {
- if (this->buffer != nullptr) {
- DCHECK(data_buffer == nullptr);
- this->data_buffer = this->buffer.get();
- }
-}
-
-QuicStreamFrame::~QuicStreamFrame() {}
-
-uint32_t MakeQuicTag(char a, char b, char c, char d) {
- return static_cast<uint32_t>(a) | static_cast<uint32_t>(b) << 8 |
- static_cast<uint32_t>(c) << 16 | static_cast<uint32_t>(d) << 24;
-}
-
-bool ContainsQuicTag(const QuicTagVector& tag_vector, QuicTag tag) {
- return std::find(tag_vector.begin(), tag_vector.end(), tag) !=
- tag_vector.end();
-}
-
-QuicVersionVector QuicSupportedVersions() {
- QuicVersionVector supported_versions;
- for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
- supported_versions.push_back(kSupportedQuicVersions[i]);
- }
- return supported_versions;
-}
-
-QuicVersionVector FilterSupportedVersions(QuicVersionVector versions) {
- QuicVersionVector filtered_versions(versions.size());
- filtered_versions.clear(); // Guaranteed by spec not to change capacity.
- for (QuicVersion version : versions) {
- if (version < QUIC_VERSION_30) {
- if (!FLAGS_quic_disable_pre_30) {
- filtered_versions.push_back(version);
- }
- } else {
- if (version == QUIC_VERSION_35) {
- if (FLAGS_quic_enable_version_35) {
- filtered_versions.push_back(version);
- }
- } else {
- filtered_versions.push_back(version);
- }
- }
- }
- return filtered_versions;
-}
-
-QuicTag QuicVersionToQuicTag(const QuicVersion version) {
- switch (version) {
- case QUIC_VERSION_25:
- return MakeQuicTag('Q', '0', '2', '5');
- case QUIC_VERSION_26:
- return MakeQuicTag('Q', '0', '2', '6');
- case QUIC_VERSION_27:
- return MakeQuicTag('Q', '0', '2', '7');
- case QUIC_VERSION_28:
- return MakeQuicTag('Q', '0', '2', '8');
- case QUIC_VERSION_29:
- return MakeQuicTag('Q', '0', '2', '9');
- case QUIC_VERSION_30:
- return MakeQuicTag('Q', '0', '3', '0');
- case QUIC_VERSION_31:
- return MakeQuicTag('Q', '0', '3', '1');
- case QUIC_VERSION_32:
- return MakeQuicTag('Q', '0', '3', '2');
- case QUIC_VERSION_33:
- return MakeQuicTag('Q', '0', '3', '3');
- case QUIC_VERSION_34:
- return MakeQuicTag('Q', '0', '3', '4');
- case QUIC_VERSION_35:
- return MakeQuicTag('Q', '0', '3', '5');
- default:
- // This shold be an ERROR because we should never attempt to convert an
- // invalid QuicVersion to be written to the wire.
- LOG(ERROR) << "Unsupported QuicVersion: " << version;
- return 0;
- }
-}
-
-QuicVersion QuicTagToQuicVersion(const QuicTag version_tag) {
- for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
- if (version_tag == QuicVersionToQuicTag(kSupportedQuicVersions[i])) {
- return kSupportedQuicVersions[i];
- }
- }
- // Reading from the client so this should not be considered an ERROR.
- DVLOG(1) << "Unsupported QuicTag version: "
- << QuicUtils::TagToString(version_tag);
- return QUIC_VERSION_UNSUPPORTED;
-}
-
-#define RETURN_STRING_LITERAL(x) \
- case x: \
- return #x
-
-string QuicVersionToString(const QuicVersion version) {
- switch (version) {
- RETURN_STRING_LITERAL(QUIC_VERSION_25);
- RETURN_STRING_LITERAL(QUIC_VERSION_26);
- RETURN_STRING_LITERAL(QUIC_VERSION_27);
- RETURN_STRING_LITERAL(QUIC_VERSION_28);
- RETURN_STRING_LITERAL(QUIC_VERSION_29);
- RETURN_STRING_LITERAL(QUIC_VERSION_30);
- RETURN_STRING_LITERAL(QUIC_VERSION_31);
- RETURN_STRING_LITERAL(QUIC_VERSION_32);
- RETURN_STRING_LITERAL(QUIC_VERSION_33);
- RETURN_STRING_LITERAL(QUIC_VERSION_34);
- RETURN_STRING_LITERAL(QUIC_VERSION_35);
- default:
- return "QUIC_VERSION_UNSUPPORTED";
- }
-}
-
-string QuicVersionVectorToString(const QuicVersionVector& versions) {
- string result = "";
- for (size_t i = 0; i < versions.size(); ++i) {
- if (i != 0) {
- result.append(",");
- }
- result.append(QuicVersionToString(versions[i]));
- }
- return result;
-}
-
-ostream& operator<<(ostream& os, const Perspective& s) {
- if (s == Perspective::IS_SERVER) {
- os << "IS_SERVER";
- } else {
- os << "IS_CLIENT";
- }
- return os;
-}
-
-ostream& operator<<(ostream& os, const QuicPacketHeader& header) {
- os << "{ connection_id: " << header.public_header.connection_id
- << ", connection_id_length: " << header.public_header.connection_id_length
- << ", packet_number_length: " << header.public_header.packet_number_length
- << ", multipath_flag: " << header.public_header.multipath_flag
- << ", reset_flag: " << header.public_header.reset_flag
- << ", version_flag: " << header.public_header.version_flag;
- if (header.public_header.version_flag) {
- os << ", version:";
- for (size_t i = 0; i < header.public_header.versions.size(); ++i) {
- os << " ";
- os << QuicVersionToString(header.public_header.versions[i]);
- }
- }
- if (header.public_header.nonce != nullptr) {
- os << ", diversification_nonce: "
- << net::QuicUtils::HexDecode(*header.public_header.nonce);
- }
- os << ", fec_flag: " << header.fec_flag
- << ", entropy_flag: " << header.entropy_flag
- << ", entropy hash: " << static_cast<int>(header.entropy_hash)
- << ", path_id: " << static_cast<int>(header.path_id)
- << ", packet_number: " << header.packet_number << " }\n";
- return os;
-}
-
-bool IsAwaitingPacket(const QuicAckFrame& ack_frame,
- QuicPacketNumber packet_number,
- QuicPacketNumber peer_least_packet_awaiting_ack) {
- if (ack_frame.missing) {
- return packet_number > ack_frame.largest_observed ||
- ack_frame.packets.Contains(packet_number);
- }
- return packet_number >= peer_least_packet_awaiting_ack &&
- !ack_frame.packets.Contains(packet_number);
-}
-
-QuicStopWaitingFrame::QuicStopWaitingFrame()
- : path_id(kDefaultPathId), entropy_hash(0), least_unacked(0) {}
-
-QuicStopWaitingFrame::~QuicStopWaitingFrame() {}
-
-QuicAckFrame::QuicAckFrame()
- : largest_observed(0),
- ack_delay_time(QuicTime::Delta::Infinite()),
- path_id(kDefaultPathId),
- entropy_hash(0),
- is_truncated(false),
- missing(true) {}
-
-QuicAckFrame::QuicAckFrame(const QuicAckFrame& other) = default;
-
-QuicAckFrame::~QuicAckFrame() {}
-
-QuicRstStreamErrorCode AdjustErrorForVersion(QuicRstStreamErrorCode error_code,
- QuicVersion /*version*/) {
- return error_code;
-}
-
-QuicRstStreamFrame::QuicRstStreamFrame()
- : stream_id(0), error_code(QUIC_STREAM_NO_ERROR), byte_offset(0) {}
-
-QuicRstStreamFrame::QuicRstStreamFrame(QuicStreamId stream_id,
- QuicRstStreamErrorCode error_code,
- QuicStreamOffset bytes_written)
- : stream_id(stream_id),
- error_code(error_code),
- byte_offset(bytes_written) {}
-
-QuicConnectionCloseFrame::QuicConnectionCloseFrame()
- : error_code(QUIC_NO_ERROR) {}
-
-QuicFrame::QuicFrame() {}
-
-QuicFrame::QuicFrame(QuicPaddingFrame padding_frame)
- : type(PADDING_FRAME), padding_frame(padding_frame) {}
-
-QuicFrame::QuicFrame(QuicStreamFrame* stream_frame)
- : type(STREAM_FRAME), stream_frame(stream_frame) {}
-
-QuicFrame::QuicFrame(QuicAckFrame* frame) : type(ACK_FRAME), ack_frame(frame) {}
-
-QuicFrame::QuicFrame(QuicMtuDiscoveryFrame frame)
- : type(MTU_DISCOVERY_FRAME), mtu_discovery_frame(frame) {}
-
-QuicFrame::QuicFrame(QuicStopWaitingFrame* frame)
- : type(STOP_WAITING_FRAME), stop_waiting_frame(frame) {}
-
-QuicFrame::QuicFrame(QuicPingFrame frame)
- : type(PING_FRAME), ping_frame(frame) {}
-
-QuicFrame::QuicFrame(QuicRstStreamFrame* frame)
- : type(RST_STREAM_FRAME), rst_stream_frame(frame) {}
-
-QuicFrame::QuicFrame(QuicConnectionCloseFrame* frame)
- : type(CONNECTION_CLOSE_FRAME), connection_close_frame(frame) {}
-
-QuicFrame::QuicFrame(QuicGoAwayFrame* frame)
- : type(GOAWAY_FRAME), goaway_frame(frame) {}
-
-QuicFrame::QuicFrame(QuicWindowUpdateFrame* frame)
- : type(WINDOW_UPDATE_FRAME), window_update_frame(frame) {}
-
-QuicFrame::QuicFrame(QuicBlockedFrame* frame)
- : type(BLOCKED_FRAME), blocked_frame(frame) {}
-
-QuicFrame::QuicFrame(QuicPathCloseFrame* frame)
- : type(PATH_CLOSE_FRAME), path_close_frame(frame) {}
-
-ostream& operator<<(ostream& os, const QuicStopWaitingFrame& sent_info) {
- os << "{ entropy_hash: " << static_cast<int>(sent_info.entropy_hash)
- << ", least_unacked: " << sent_info.least_unacked << " }\n";
- return os;
-}
-
-PacketNumberQueue::const_iterator::const_iterator(
- IntervalSet<QuicPacketNumber>::const_iterator interval_set_iter,
- QuicPacketNumber first,
- QuicPacketNumber last)
- : interval_set_iter_(std::move(interval_set_iter)),
- current_(first),
- last_(last) {}
-
-PacketNumberQueue::const_iterator::const_iterator(const const_iterator& other) =
- default;
-// TODO(rtenneti): on windows RValue reference gives errors.
-// PacketNumberQueue::const_iterator::const_iterator(const_iterator&& other) =
-// default;
-PacketNumberQueue::const_iterator::~const_iterator() {}
-
-PacketNumberQueue::const_iterator& PacketNumberQueue::const_iterator::operator=(
- const const_iterator& other) = default;
-// TODO(rtenneti): on windows RValue reference gives errors.
-// PacketNumberQueue::const_iterator&
-// PacketNumberQueue::const_iterator::operator=(
-// const_iterator&& other) = default;
-
-bool PacketNumberQueue::const_iterator::operator!=(
- const const_iterator& other) const {
- return current_ != other.current_;
-}
-
-bool PacketNumberQueue::const_iterator::operator==(
- const const_iterator& other) const {
- return current_ == other.current_;
-}
-
-PacketNumberQueue::const_iterator::value_type
- PacketNumberQueue::const_iterator::operator*() const {
- return current_;
-}
-
-PacketNumberQueue::const_iterator& PacketNumberQueue::const_iterator::
-operator++() {
- ++current_;
- if (current_ < last_) {
- if (current_ >= interval_set_iter_->max()) {
- ++interval_set_iter_;
- current_ = interval_set_iter_->min();
- }
- } else {
- current_ = last_;
- }
- return *this;
-}
-
-PacketNumberQueue::const_iterator PacketNumberQueue::const_iterator::operator++(
- int /* postincrement */) {
- PacketNumberQueue::const_iterator preincrement(*this);
- operator++();
- return preincrement;
-}
-
-PacketNumberQueue::PacketNumberQueue() = default;
-PacketNumberQueue::PacketNumberQueue(const PacketNumberQueue& other) = default;
-// TODO(rtenneti): on windows RValue reference gives errors.
-// PacketNumberQueue::PacketNumberQueue(PacketNumberQueue&& other) = default;
-PacketNumberQueue::~PacketNumberQueue() {}
-
-PacketNumberQueue& PacketNumberQueue::operator=(
- const PacketNumberQueue& other) = default;
-// TODO(rtenneti): on windows RValue reference gives errors.
-// PacketNumberQueue& PacketNumberQueue::operator=(PacketNumberQueue&& other) =
-// default;
-
-void PacketNumberQueue::Add(QuicPacketNumber packet_number) {
- packet_number_intervals_.Add(packet_number, packet_number + 1);
-}
-
-void PacketNumberQueue::Add(QuicPacketNumber lower, QuicPacketNumber higher) {
- packet_number_intervals_.Add(lower, higher);
-}
-
-void PacketNumberQueue::Remove(QuicPacketNumber packet_number) {
- packet_number_intervals_.Difference(packet_number, packet_number + 1);
-}
-
-void PacketNumberQueue::Remove(QuicPacketNumber lower,
- QuicPacketNumber higher) {
- packet_number_intervals_.Difference(lower, higher);
-}
-
-bool PacketNumberQueue::RemoveUpTo(QuicPacketNumber higher) {
- if (Empty()) {
- return false;
- }
- const QuicPacketNumber old_min = Min();
- packet_number_intervals_.Difference(0, higher);
- return Empty() || old_min != Min();
-}
-
-bool PacketNumberQueue::Contains(QuicPacketNumber packet_number) const {
- return packet_number_intervals_.Contains(packet_number);
-}
-
-bool PacketNumberQueue::Empty() const {
- return packet_number_intervals_.Empty();
-}
-
-QuicPacketNumber PacketNumberQueue::Min() const {
- DCHECK(!Empty());
- return packet_number_intervals_.begin()->min();
-}
-
-QuicPacketNumber PacketNumberQueue::Max() const {
- DCHECK(!Empty());
- return packet_number_intervals_.rbegin()->max() - 1;
-}
-
-size_t PacketNumberQueue::NumPacketsSlow() const {
- size_t num_packets = 0;
- for (const auto& interval : packet_number_intervals_) {
- num_packets += interval.Length();
- }
- return num_packets;
-}
-
-size_t PacketNumberQueue::NumIntervals() const {
- return packet_number_intervals_.Size();
-}
-
-QuicPacketNumber PacketNumberQueue::LastIntervalLength() const {
- DCHECK(!Empty());
- return packet_number_intervals_.rbegin()->Length();
-}
-
-PacketNumberQueue::const_iterator PacketNumberQueue::begin() const {
- QuicPacketNumber first;
- QuicPacketNumber last;
- if (packet_number_intervals_.Empty()) {
- first = 0;
- last = 0;
- } else {
- first = packet_number_intervals_.begin()->min();
- last = packet_number_intervals_.rbegin()->max();
- }
- return const_iterator(packet_number_intervals_.begin(), first, last);
-}
-
-PacketNumberQueue::const_iterator PacketNumberQueue::end() const {
- QuicPacketNumber last = packet_number_intervals_.Empty()
- ? 0
- : packet_number_intervals_.rbegin()->max();
- return const_iterator(packet_number_intervals_.end(), last, last);
-}
-
-PacketNumberQueue::const_iterator PacketNumberQueue::lower_bound(
- QuicPacketNumber packet_number) const {
- QuicPacketNumber first;
- QuicPacketNumber last;
- if (packet_number_intervals_.Empty()) {
- first = 0;
- last = 0;
- return const_iterator(packet_number_intervals_.begin(), first, last);
- }
- if (!packet_number_intervals_.Contains(packet_number)) {
- return end();
- }
- IntervalSet<QuicPacketNumber>::const_iterator it =
- packet_number_intervals_.Find(packet_number);
- first = packet_number;
- last = packet_number_intervals_.rbegin()->max();
- return const_iterator(it, first, last);
-}
-
-ostream& operator<<(ostream& os, const PacketNumberQueue& q) {
- for (QuicPacketNumber packet_number : q) {
- os << packet_number << " ";
- }
- return os;
-}
-
-ostream& operator<<(ostream& os, const QuicAckFrame& ack_frame) {
- os << "{ entropy_hash: " << static_cast<int>(ack_frame.entropy_hash)
- << ", largest_observed: " << ack_frame.largest_observed
- << ", ack_delay_time: " << ack_frame.ack_delay_time.ToMicroseconds()
- << ", packets: [ " << ack_frame.packets << " ]"
- << ", is_truncated: " << ack_frame.is_truncated
- << ", received_packets: [ ";
- for (const std::pair<QuicPacketNumber, QuicTime>& p :
- ack_frame.received_packet_times) {
- os << p.first << " at " << p.second.ToDebuggingValue() << " ";
- }
- os << " ] }\n";
- return os;
-}
-
-ostream& operator<<(ostream& os, const QuicFrame& frame) {
- switch (frame.type) {
- case PADDING_FRAME: {
- os << "type { PADDING_FRAME } " << frame.padding_frame;
- break;
- }
- case RST_STREAM_FRAME: {
- os << "type { RST_STREAM_FRAME } " << *(frame.rst_stream_frame);
- break;
- }
- case CONNECTION_CLOSE_FRAME: {
- os << "type { CONNECTION_CLOSE_FRAME } "
- << *(frame.connection_close_frame);
- break;
- }
- case GOAWAY_FRAME: {
- os << "type { GOAWAY_FRAME } " << *(frame.goaway_frame);
- break;
- }
- case WINDOW_UPDATE_FRAME: {
- os << "type { WINDOW_UPDATE_FRAME } " << *(frame.window_update_frame);
- break;
- }
- case BLOCKED_FRAME: {
- os << "type { BLOCKED_FRAME } " << *(frame.blocked_frame);
- break;
- }
- case STREAM_FRAME: {
- os << "type { STREAM_FRAME } " << *(frame.stream_frame);
- break;
- }
- case ACK_FRAME: {
- os << "type { ACK_FRAME } " << *(frame.ack_frame);
- break;
- }
- case STOP_WAITING_FRAME: {
- os << "type { STOP_WAITING_FRAME } " << *(frame.stop_waiting_frame);
- break;
- }
- case PING_FRAME: {
- os << "type { PING_FRAME } ";
- break;
- }
- case MTU_DISCOVERY_FRAME: {
- os << "type { MTU_DISCOVERY_FRAME } ";
- break;
- }
- case PATH_CLOSE_FRAME: {
- os << "type { PATH_CLOSE_FRAME } " << *(frame.path_close_frame);
- break;
- }
- default: {
- LOG(ERROR) << "Unknown frame type: " << frame.type;
- break;
- }
- }
- return os;
-}
-
-ostream& operator<<(ostream& os, const QuicPaddingFrame& padding_frame) {
- os << "{ num_padding_bytes: " << padding_frame.num_padding_bytes << " }\n";
- return os;
-}
-
-ostream& operator<<(ostream& os, const QuicRstStreamFrame& rst_frame) {
- os << "{ stream_id: " << rst_frame.stream_id
- << ", error_code: " << rst_frame.error_code << " }\n";
- return os;
-}
-
-ostream& operator<<(ostream& os,
- const QuicConnectionCloseFrame& connection_close_frame) {
- os << "{ error_code: " << connection_close_frame.error_code
- << ", error_details: '" << connection_close_frame.error_details << "' }\n";
- return os;
-}
-
-ostream& operator<<(ostream& os, const QuicGoAwayFrame& goaway_frame) {
- os << "{ error_code: " << goaway_frame.error_code
- << ", last_good_stream_id: " << goaway_frame.last_good_stream_id
- << ", reason_phrase: '" << goaway_frame.reason_phrase << "' }\n";
- return os;
-}
-
-ostream& operator<<(ostream& os,
- const QuicWindowUpdateFrame& window_update_frame) {
- os << "{ stream_id: " << window_update_frame.stream_id
- << ", byte_offset: " << window_update_frame.byte_offset << " }\n";
- return os;
-}
-
-ostream& operator<<(ostream& os, const QuicBlockedFrame& blocked_frame) {
- os << "{ stream_id: " << blocked_frame.stream_id << " }\n";
- return os;
-}
-
-ostream& operator<<(ostream& os, const QuicPathCloseFrame& path_close_frame) {
- os << "{ path_id: " << static_cast<int>(path_close_frame.path_id) << " }\n";
- return os;
-}
-
-ostream& operator<<(ostream& os, const QuicStreamFrame& stream_frame) {
- os << "{ stream_id: " << stream_frame.stream_id
- << ", fin: " << stream_frame.fin << ", offset: " << stream_frame.offset
- << ", length: " << stream_frame.data_length << " }\n";
- return os;
-}
-
-QuicGoAwayFrame::QuicGoAwayFrame()
- : error_code(QUIC_NO_ERROR), last_good_stream_id(0) {}
-
-QuicGoAwayFrame::QuicGoAwayFrame(QuicErrorCode error_code,
- QuicStreamId last_good_stream_id,
- const string& reason)
- : error_code(error_code),
- last_good_stream_id(last_good_stream_id),
- reason_phrase(reason) {}
-
-QuicData::QuicData(const char* buffer, size_t length)
- : buffer_(buffer), length_(length), owns_buffer_(false) {}
-
-QuicData::QuicData(char* buffer, size_t length, bool owns_buffer)
- : buffer_(buffer), length_(length), owns_buffer_(owns_buffer) {}
-
-QuicData::~QuicData() {
- if (owns_buffer_) {
- delete[] const_cast<char*>(buffer_);
- }
-}
-
-QuicWindowUpdateFrame::QuicWindowUpdateFrame(QuicStreamId stream_id,
- QuicStreamOffset byte_offset)
- : stream_id(stream_id), byte_offset(byte_offset) {}
-
-QuicBlockedFrame::QuicBlockedFrame(QuicStreamId stream_id)
- : stream_id(stream_id) {}
-
-QuicPathCloseFrame::QuicPathCloseFrame(QuicPathId path_id) : path_id(path_id) {}
-
-QuicPacket::QuicPacket(char* buffer,
- size_t length,
- bool owns_buffer,
- QuicConnectionIdLength connection_id_length,
- bool includes_version,
- bool includes_path_id,
- bool includes_diversification_nonce,
- QuicPacketNumberLength packet_number_length)
- : QuicData(buffer, length, owns_buffer),
- buffer_(buffer),
- connection_id_length_(connection_id_length),
- includes_version_(includes_version),
- includes_path_id_(includes_path_id),
- includes_diversification_nonce_(includes_diversification_nonce),
- packet_number_length_(packet_number_length) {}
-
-QuicEncryptedPacket::QuicEncryptedPacket(const char* buffer, size_t length)
- : QuicData(buffer, length) {}
-
-QuicEncryptedPacket::QuicEncryptedPacket(char* buffer,
- size_t length,
- bool owns_buffer)
- : QuicData(buffer, length, owns_buffer) {}
-
-QuicEncryptedPacket* QuicEncryptedPacket::Clone() const {
- char* buffer = new char[this->length()];
- memcpy(buffer, this->data(), this->length());
- return new QuicEncryptedPacket(buffer, this->length(), true);
-}
-
-ostream& operator<<(ostream& os, const QuicEncryptedPacket& s) {
- os << s.length() << "-byte data";
- return os;
-}
-
-QuicReceivedPacket::QuicReceivedPacket(const char* buffer,
- size_t length,
- QuicTime receipt_time)
- : QuicEncryptedPacket(buffer, length), receipt_time_(receipt_time) {}
-
-QuicReceivedPacket::QuicReceivedPacket(char* buffer,
- size_t length,
- QuicTime receipt_time,
- bool owns_buffer)
- : QuicEncryptedPacket(buffer, length, owns_buffer),
- receipt_time_(receipt_time) {}
-
-QuicReceivedPacket* QuicReceivedPacket::Clone() const {
- char* buffer = new char[this->length()];
- memcpy(buffer, this->data(), this->length());
- return new QuicReceivedPacket(buffer, this->length(), receipt_time(), true);
-}
-
-ostream& operator<<(ostream& os, const QuicReceivedPacket& s) {
- os << s.length() << "-byte data";
- return os;
-}
-
-StringPiece QuicPacket::AssociatedData(QuicVersion version) const {
- return StringPiece(
- data(), GetStartOfEncryptedData(version, connection_id_length_,
- includes_version_, includes_path_id_,
- includes_diversification_nonce_,
- packet_number_length_));
-}
-
-StringPiece QuicPacket::Plaintext(QuicVersion version) const {
- const size_t start_of_encrypted_data = GetStartOfEncryptedData(
- version, connection_id_length_, includes_version_, includes_path_id_,
- includes_diversification_nonce_, packet_number_length_);
- return StringPiece(data() + start_of_encrypted_data,
- length() - start_of_encrypted_data);
-}
-
-AckListenerWrapper::AckListenerWrapper(QuicAckListenerInterface* listener,
- QuicPacketLength data_length)
- : ack_listener(listener), length(data_length) {
- DCHECK(listener != nullptr);
-}
-
-AckListenerWrapper::AckListenerWrapper(const AckListenerWrapper& other) =
- default;
-
-AckListenerWrapper::~AckListenerWrapper() {}
-
-SerializedPacket::SerializedPacket(QuicPathId path_id,
- QuicPacketNumber packet_number,
- QuicPacketNumberLength packet_number_length,
- const char* encrypted_buffer,
- QuicPacketLength encrypted_length,
- QuicPacketEntropyHash entropy_hash,
- bool has_ack,
- bool has_stop_waiting)
- : encrypted_buffer(encrypted_buffer),
- encrypted_length(encrypted_length),
- has_crypto_handshake(NOT_HANDSHAKE),
- num_padding_bytes(0),
- path_id(path_id),
- packet_number(packet_number),
- packet_number_length(packet_number_length),
- encryption_level(ENCRYPTION_NONE),
- entropy_hash(entropy_hash),
- has_ack(has_ack),
- has_stop_waiting(has_stop_waiting),
- transmission_type(NOT_RETRANSMISSION),
- original_path_id(kInvalidPathId),
- original_packet_number(0) {}
-
-SerializedPacket::SerializedPacket(const SerializedPacket& other) = default;
-
-SerializedPacket::~SerializedPacket() {}
-
-TransmissionInfo::TransmissionInfo()
- : encryption_level(ENCRYPTION_NONE),
- packet_number_length(PACKET_1BYTE_PACKET_NUMBER),
- bytes_sent(0),
- sent_time(QuicTime::Zero()),
- transmission_type(NOT_RETRANSMISSION),
- in_flight(false),
- is_unackable(false),
- has_crypto_handshake(false),
- num_padding_bytes(0),
- retransmission(0) {}
-
-TransmissionInfo::TransmissionInfo(EncryptionLevel level,
- QuicPacketNumberLength packet_number_length,
- TransmissionType transmission_type,
- QuicTime sent_time,
- QuicPacketLength bytes_sent,
- bool has_crypto_handshake,
- int num_padding_bytes)
- : encryption_level(level),
- packet_number_length(packet_number_length),
- bytes_sent(bytes_sent),
- sent_time(sent_time),
- transmission_type(transmission_type),
- in_flight(false),
- is_unackable(false),
- has_crypto_handshake(has_crypto_handshake),
- num_padding_bytes(num_padding_bytes),
- retransmission(0) {}
-
-TransmissionInfo::TransmissionInfo(const TransmissionInfo& other) = default;
-
-TransmissionInfo::~TransmissionInfo() {}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_protocol.h b/chromium/net/quic/quic_protocol.h
deleted file mode 100644
index d5b6c5383cc..00000000000
--- a/chromium/net/quic/quic_protocol.h
+++ /dev/null
@@ -1,1502 +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.
-
-#ifndef NET_QUIC_QUIC_PROTOCOL_H_
-#define NET_QUIC_QUIC_PROTOCOL_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <limits>
-#include <list>
-#include <map>
-#include <memory>
-#include <ostream>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/strings/string_piece.h"
-#include "net/base/int128.h"
-#include "net/base/iovec.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_export.h"
-#include "net/quic/interval_set.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_time.h"
-#include "net/quic/quic_types.h"
-
-namespace net {
-
-class QuicPacket;
-struct QuicPacketHeader;
-class QuicAckListenerInterface;
-
-typedef uint64_t QuicConnectionId;
-typedef uint32_t QuicStreamId;
-typedef uint64_t QuicStreamOffset;
-typedef uint64_t QuicPacketNumber;
-typedef uint8_t QuicPathId;
-typedef uint64_t QuicPublicResetNonceProof;
-typedef uint8_t QuicPacketEntropyHash;
-typedef uint32_t QuicHeaderId;
-// QuicTag is the type of a tag in the wire protocol.
-typedef uint32_t QuicTag;
-typedef std::vector<QuicTag> QuicTagVector;
-typedef std::map<QuicTag, std::string> QuicTagValueMap;
-typedef uint16_t QuicPacketLength;
-
-// Default initial maximum size in bytes of a QUIC packet.
-const QuicByteCount kDefaultMaxPacketSize = 1350;
-// Default initial maximum size in bytes of a QUIC packet for servers.
-const QuicByteCount kDefaultServerMaxPacketSize = 1000;
-// The maximum packet size of any QUIC packet, based on ethernet's max size,
-// minus the IP and UDP headers. IPv6 has a 40 byte header, UDP adds an
-// additional 8 bytes. This is a total overhead of 48 bytes. Ethernet's
-// max packet size is 1500 bytes, 1500 - 48 = 1452.
-const QuicByteCount kMaxPacketSize = 1452;
-// Default maximum packet size used in the Linux TCP implementation.
-// Used in QUIC for congestion window computations in bytes.
-const QuicByteCount kDefaultTCPMSS = 1460;
-
-// We match SPDY's use of 32 (since we'd compete with SPDY).
-const QuicPacketCount kInitialCongestionWindow = 32;
-
-// Minimum size of initial flow control window, for both stream and session.
-const uint32_t kMinimumFlowControlSendWindow = 16 * 1024; // 16 KB
-
-// Maximum flow control receive window limits for connection and stream.
-const QuicByteCount kStreamReceiveWindowLimit = 16 * 1024 * 1024; // 16 MB
-const QuicByteCount kSessionReceiveWindowLimit = 24 * 1024 * 1024; // 24 MB
-
-// Minimum size of the CWND, in packets, when doing bandwidth resumption.
-const QuicPacketCount kMinCongestionWindowForBandwidthResumption = 10;
-
-// Maximum number of tracked packets.
-const QuicPacketCount kMaxTrackedPackets = 10000;
-
-// Default size of the socket receive buffer in bytes.
-const QuicByteCount kDefaultSocketReceiveBuffer = 1024 * 1024;
-// Minimum size of the socket receive buffer in bytes.
-// Smaller values are ignored.
-const QuicByteCount kMinSocketReceiveBuffer = 16 * 1024;
-
-// Fraction of the receive buffer that can be used, based on conservative
-// estimates and testing on Linux.
-// An alternative to kUsableRecieveBufferFraction.
-static const float kConservativeReceiveBufferFraction = 0.6f;
-
-// Don't allow a client to suggest an RTT shorter than 10ms.
-const uint32_t kMinInitialRoundTripTimeUs = 10 * kNumMicrosPerMilli;
-
-// Don't allow a client to suggest an RTT longer than 15 seconds.
-const uint32_t kMaxInitialRoundTripTimeUs = 15 * kNumMicrosPerSecond;
-
-// Maximum number of open streams per connection.
-const size_t kDefaultMaxStreamsPerConnection = 100;
-
-// Number of bytes reserved for public flags in the packet header.
-const size_t kPublicFlagsSize = 1;
-// Number of bytes reserved for version number in the packet header.
-const size_t kQuicVersionSize = 4;
-// Number of bytes reserved for path id in the packet header.
-const size_t kQuicPathIdSize = 1;
-// Number of bytes reserved for private flags in the packet header.
-const size_t kPrivateFlagsSize = 1;
-
-// Signifies that the QuicPacket will contain version of the protocol.
-const bool kIncludeVersion = true;
-// Signifies that the QuicPacket will contain path id.
-const bool kIncludePathId = true;
-// Signifies that the QuicPacket will include a diversification nonce.
-const bool kIncludeDiversificationNonce = true;
-
-// Stream ID is reserved to denote an invalid ID.
-const QuicStreamId kInvalidStreamId = 0;
-
-// Reserved ID for the crypto stream.
-const QuicStreamId kCryptoStreamId = 1;
-
-// Reserved ID for the headers stream.
-const QuicStreamId kHeadersStreamId = 3;
-
-// Header key used to identify final offset on data stream when sending HTTP/2
-// trailing headers over QUIC.
-NET_EXPORT_PRIVATE extern const char* const kFinalOffsetHeaderKey;
-
-// Maximum delayed ack time, in ms.
-const int64_t kMaxDelayedAckTimeMs = 25;
-
-// Minimum tail loss probe time in ms.
-static const int64_t kMinTailLossProbeTimeoutMs = 10;
-
-// The timeout before the handshake succeeds.
-const int64_t kInitialIdleTimeoutSecs = 5;
-// The default idle timeout.
-const int64_t kDefaultIdleTimeoutSecs = 30;
-// The maximum idle timeout that can be negotiated.
-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.
-
-// Default limit on the number of undecryptable packets the connection buffers
-// before the CHLO/SHLO arrive.
-const size_t kDefaultMaxUndecryptablePackets = 10;
-
-// Default ping timeout.
-const int64_t kPingTimeoutSecs = 15; // 15 secs.
-
-// Minimum number of RTTs between Server Config Updates (SCUP) sent to client.
-const int kMinIntervalBetweenServerConfigUpdatesRTTs = 10;
-
-// Minimum time between Server Config Updates (SCUP) sent to client.
-const int kMinIntervalBetweenServerConfigUpdatesMs = 1000;
-
-// Minimum number of packets between Server Config Updates (SCUP).
-const int kMinPacketsBetweenServerConfigUpdates = 100;
-
-// The number of open streams that a server will accept is set to be slightly
-// larger than the negotiated limit. Immediately closing the connection if the
-// client opens slightly too many streams is not ideal: the client may have sent
-// a FIN that was lost, and simultaneously opened a new stream. The number of
-// streams a server accepts is a fixed increment over the negotiated limit, or a
-// percentage increase, whichever is larger.
-const float kMaxStreamsMultiplier = 1.1f;
-const int kMaxStreamsMinimumIncrement = 10;
-
-// Available streams are ones with IDs less than the highest stream that has
-// been opened which have neither been opened or reset. The limit on the number
-// of available streams is 10 times the limit on the number of open streams.
-const int kMaxAvailableStreamsMultiplier = 10;
-
-// Track the number of promises that are not yet claimed by a
-// corresponding get. This must be smaller than
-// kMaxAvailableStreamsMultiplier, because RST on a promised stream my
-// create available streams entries.
-const int kMaxPromisedStreamsMultiplier = kMaxAvailableStreamsMultiplier - 1;
-
-// TCP RFC calls for 1 second RTO however Linux differs from this default and
-// define the minimum RTO to 200ms, we will use the same until we have data to
-// support a higher or lower value.
-static const int64_t kMinRetransmissionTimeMs = 200;
-
-// We define an unsigned 16-bit floating point value, inspired by IEEE floats
-// (http://en.wikipedia.org/wiki/Half_precision_floating-point_format),
-// with 5-bit exponent (bias 1), 11-bit mantissa (effective 12 with hidden
-// bit) and denormals, but without signs, transfinites or fractions. Wire format
-// 16 bits (little-endian byte order) are split into exponent (high 5) and
-// mantissa (low 11) and decoded as:
-// uint64_t value;
-// if (exponent == 0) value = mantissa;
-// else value = (mantissa | 1 << 11) << (exponent - 1)
-const int kUFloat16ExponentBits = 5;
-const int kUFloat16MaxExponent = (1 << kUFloat16ExponentBits) - 2; // 30
-const int kUFloat16MantissaBits = 16 - kUFloat16ExponentBits; // 11
-const int kUFloat16MantissaEffectiveBits = kUFloat16MantissaBits + 1; // 12
-const uint64_t kUFloat16MaxValue = // 0x3FFC0000000
- ((UINT64_C(1) << kUFloat16MantissaEffectiveBits) - 1)
- << kUFloat16MaxExponent;
-
-// Default path ID.
-const QuicPathId kDefaultPathId = 0;
-// Invalid path ID.
-const QuicPathId kInvalidPathId = 0xff;
-
-// kDiversificationNonceSize is the size, in bytes, of the nonce that a server
-// may set in the packet header to ensure that its INITIAL keys are not
-// duplicated.
-const size_t kDiversificationNonceSize = 32;
-
-enum TransmissionType : int8_t {
- NOT_RETRANSMISSION,
- FIRST_TRANSMISSION_TYPE = NOT_RETRANSMISSION,
- HANDSHAKE_RETRANSMISSION, // Retransmits due to handshake timeouts.
- ALL_UNACKED_RETRANSMISSION, // Retransmits all unacked packets.
- ALL_INITIAL_RETRANSMISSION, // Retransmits all initially encrypted packets.
- LOSS_RETRANSMISSION, // Retransmits due to loss detection.
- RTO_RETRANSMISSION, // Retransmits due to retransmit time out.
- TLP_RETRANSMISSION, // Tail loss probes.
- LAST_TRANSMISSION_TYPE = TLP_RETRANSMISSION,
-};
-
-enum HasRetransmittableData : int8_t {
- NO_RETRANSMITTABLE_DATA,
- HAS_RETRANSMITTABLE_DATA,
-};
-
-enum IsHandshake : int8_t { NOT_HANDSHAKE, IS_HANDSHAKE };
-
-enum class Perspective { IS_SERVER, IS_CLIENT };
-
-// Describes whether a ConnectionClose was originated by the peer.
-enum class ConnectionCloseSource { FROM_PEER, FROM_SELF };
-
-// Should a connection be closed silently or not.
-enum class ConnectionCloseBehavior {
- SILENT_CLOSE,
- SEND_CONNECTION_CLOSE_PACKET
-};
-
-NET_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
- const Perspective& s);
-enum QuicFrameType {
- // Regular frame types. The values set here cannot change without the
- // introduction of a new QUIC version.
- PADDING_FRAME = 0,
- RST_STREAM_FRAME = 1,
- CONNECTION_CLOSE_FRAME = 2,
- GOAWAY_FRAME = 3,
- WINDOW_UPDATE_FRAME = 4,
- BLOCKED_FRAME = 5,
- STOP_WAITING_FRAME = 6,
- PING_FRAME = 7,
- PATH_CLOSE_FRAME = 8,
-
- // STREAM and ACK frames are special frames. They are encoded differently on
- // the wire and their values do not need to be stable.
- STREAM_FRAME,
- ACK_FRAME,
- // The path MTU discovery frame is encoded as a PING frame on the wire.
- MTU_DISCOVERY_FRAME,
- NUM_FRAME_TYPES
-};
-
-enum QuicConnectionIdLength {
- PACKET_0BYTE_CONNECTION_ID = 0,
- PACKET_8BYTE_CONNECTION_ID = 8
-};
-
-enum QuicPacketNumberLength : int8_t {
- PACKET_1BYTE_PACKET_NUMBER = 1,
- PACKET_2BYTE_PACKET_NUMBER = 2,
- PACKET_4BYTE_PACKET_NUMBER = 4,
- PACKET_6BYTE_PACKET_NUMBER = 6
-};
-
-// Used to indicate a QuicSequenceNumberLength using two flag bits.
-enum QuicPacketNumberLengthFlags {
- PACKET_FLAGS_1BYTE_PACKET = 0, // 00
- PACKET_FLAGS_2BYTE_PACKET = 1, // 01
- PACKET_FLAGS_4BYTE_PACKET = 1 << 1, // 10
- PACKET_FLAGS_6BYTE_PACKET = 1 << 1 | 1, // 11
-};
-
-// The public flags are specified in one byte.
-enum QuicPacketPublicFlags {
- PACKET_PUBLIC_FLAGS_NONE = 0,
-
- // Bit 0: Does the packet header contains version info?
- PACKET_PUBLIC_FLAGS_VERSION = 1 << 0,
-
- // Bit 1: Is this packet a public reset packet?
- PACKET_PUBLIC_FLAGS_RST = 1 << 1,
-
- // Bit 2: indicates the that public header includes a nonce.
- PACKET_PUBLIC_FLAGS_NONCE = 1 << 2,
-
- // Bit 3: indicates whether a ConnectionID is included.
- PACKET_PUBLIC_FLAGS_0BYTE_CONNECTION_ID = 0,
- PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID = 1 << 3,
-
- // QUIC_VERSION_32 and earlier use two bits for an 8 byte
- // connection id.
- PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD = 1 << 3 | 1 << 2,
-
- // Bits 4 and 5 describe the packet number length as follows:
- // --00----: 1 byte
- // --01----: 2 bytes
- // --10----: 4 bytes
- // --11----: 6 bytes
- PACKET_PUBLIC_FLAGS_1BYTE_PACKET = PACKET_FLAGS_1BYTE_PACKET << 4,
- PACKET_PUBLIC_FLAGS_2BYTE_PACKET = PACKET_FLAGS_2BYTE_PACKET << 4,
- PACKET_PUBLIC_FLAGS_4BYTE_PACKET = PACKET_FLAGS_4BYTE_PACKET << 4,
- PACKET_PUBLIC_FLAGS_6BYTE_PACKET = PACKET_FLAGS_6BYTE_PACKET << 4,
-
- // Bit 6: Does the packet header contain a path id?
- PACKET_PUBLIC_FLAGS_MULTIPATH = 1 << 6,
-
- // Reserved, unimplemented flags:
-
- // Bit 7: indicates the presence of a second flags byte.
- PACKET_PUBLIC_FLAGS_TWO_OR_MORE_BYTES = 1 << 7,
-
- // All bits set (bit 7 is not currently used): 01111111
- PACKET_PUBLIC_FLAGS_MAX = (1 << 7) - 1,
-};
-
-// The private flags are specified in one byte.
-enum QuicPacketPrivateFlags {
- PACKET_PRIVATE_FLAGS_NONE = 0,
-
- // Bit 0: Does this packet contain an entropy bit?
- PACKET_PRIVATE_FLAGS_ENTROPY = 1 << 0,
-
- // Bit 1: Payload is part of an FEC group?
- PACKET_PRIVATE_FLAGS_FEC_GROUP = 1 << 1,
-
- // Bit 2: Payload is FEC as opposed to frames?
- PACKET_PRIVATE_FLAGS_FEC = 1 << 2,
-
- // All bits set (bits 3-7 are not currently used): 00000111
- PACKET_PRIVATE_FLAGS_MAX = (1 << 3) - 1,
-
- // For version 32 (bits 1-7 are not used): 00000001
- PACKET_PRIVATE_FLAGS_MAX_VERSION_32 = (1 << 1) - 1
-};
-
-// The available versions of QUIC. Guaranteed that the integer value of the enum
-// will match the version number.
-// When adding a new version to this enum you should add it to
-// kSupportedQuicVersions (if appropriate), and also add a new case to the
-// helper methods QuicVersionToQuicTag, QuicTagToQuicVersion, and
-// QuicVersionToString.
-enum QuicVersion {
- // Special case to indicate unknown/unsupported QUIC version.
- QUIC_VERSION_UNSUPPORTED = 0,
-
- QUIC_VERSION_25 = 25, // SPDY/4 header keys, and removal of error_details
- // from QuicRstStreamFrame
- QUIC_VERSION_26 = 26, // In CHLO, send XLCT tag containing hash of leaf cert
- QUIC_VERSION_27 = 27, // Sends a nonce in the SHLO.
- QUIC_VERSION_28 = 28, // Receiver can refuse to create a requested stream.
- QUIC_VERSION_29 = 29, // Server and client honor QUIC_STREAM_NO_ERROR.
- QUIC_VERSION_30 = 30, // Add server side support of cert transparency.
- QUIC_VERSION_31 = 31, // Adds a hash of the client hello to crypto proof.
- QUIC_VERSION_32 = 32, // FEC related fields are removed from wire format.
- QUIC_VERSION_33 = 33, // Adds diversification nonces.
- QUIC_VERSION_34 = 34, // Deprecates entropy, removes private flag from packet
- // header, uses new ack and stop waiting wire format.
- QUIC_VERSION_35 = 35, // Allows endpoints to independently set stream limit.
-};
-
-// 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).
-//
-// IMPORTANT: if you are adding to this list, follow the instructions at
-// http://sites/quic/adding-and-removing-versions
-static const QuicVersion kSupportedQuicVersions[] = {
- QUIC_VERSION_35, QUIC_VERSION_34, QUIC_VERSION_33, QUIC_VERSION_32,
- QUIC_VERSION_31, QUIC_VERSION_30, QUIC_VERSION_29, QUIC_VERSION_28,
- QUIC_VERSION_27, QUIC_VERSION_26, QUIC_VERSION_25};
-
-typedef std::vector<QuicVersion> QuicVersionVector;
-
-// Returns a vector of QUIC versions in kSupportedQuicVersions.
-NET_EXPORT_PRIVATE QuicVersionVector QuicSupportedVersions();
-
-// Returns a vector of QUIC versions from |versions| which exclude any versions
-// which are disabled by flags.
-NET_EXPORT_PRIVATE QuicVersionVector
-FilterSupportedVersions(QuicVersionVector versions);
-
-// QuicTag is written to and read from the wire, but we prefer to use
-// the more readable QuicVersion at other levels.
-// Helper function which translates from a QuicVersion to a QuicTag. Returns 0
-// if QuicVersion is unsupported.
-NET_EXPORT_PRIVATE QuicTag QuicVersionToQuicTag(const QuicVersion version);
-
-// Returns appropriate QuicVersion from a QuicTag.
-// Returns QUIC_VERSION_UNSUPPORTED if version_tag cannot be understood.
-NET_EXPORT_PRIVATE QuicVersion QuicTagToQuicVersion(const QuicTag version_tag);
-
-// Helper function which translates from a QuicVersion to a string.
-// Returns strings corresponding to enum names (e.g. QUIC_VERSION_6).
-NET_EXPORT_PRIVATE std::string QuicVersionToString(const QuicVersion version);
-
-// Returns comma separated list of string representations of QuicVersion enum
-// values in the supplied |versions| vector.
-NET_EXPORT_PRIVATE std::string QuicVersionVectorToString(
- const QuicVersionVector& versions);
-
-// Version and Crypto tags are written to the wire with a big-endian
-// representation of the name of the tag. For example
-// the client hello tag (CHLO) will be written as the
-// following 4 bytes: 'C' 'H' 'L' 'O'. Since it is
-// stored in memory as a little endian uint32_t, we need
-// to reverse the order of the bytes.
-
-// MakeQuicTag returns a value given the four bytes. For example:
-// MakeQuicTag('C', 'H', 'L', 'O');
-NET_EXPORT_PRIVATE QuicTag MakeQuicTag(char a, char b, char c, char d);
-
-// Returns true if the tag vector contains the specified tag.
-NET_EXPORT_PRIVATE bool ContainsQuicTag(const QuicTagVector& tag_vector,
- QuicTag tag);
-
-// Size in bytes of the data packet header.
-NET_EXPORT_PRIVATE size_t GetPacketHeaderSize(QuicVersion version,
- const QuicPacketHeader& header);
-
-NET_EXPORT_PRIVATE size_t
-GetPacketHeaderSize(QuicVersion version,
- QuicConnectionIdLength connection_id_length,
- bool include_version,
- bool include_path_id,
- bool include_diversification_nonce,
- QuicPacketNumberLength packet_number_length);
-
-// Index of the first byte in a QUIC packet of encrypted data.
-NET_EXPORT_PRIVATE size_t
-GetStartOfEncryptedData(QuicVersion version, const QuicPacketHeader& header);
-
-NET_EXPORT_PRIVATE size_t
-GetStartOfEncryptedData(QuicVersion version,
- QuicConnectionIdLength connection_id_length,
- bool include_version,
- bool include_path_id,
- bool include_diversification_nonce,
- QuicPacketNumberLength packet_number_length);
-
-enum QuicRstStreamErrorCode {
- // Complete response has been sent, sending a RST to ask the other endpoint
- // to stop sending request data without discarding the response.
- QUIC_STREAM_NO_ERROR = 0,
-
- // There was some error which halted stream processing.
- QUIC_ERROR_PROCESSING_STREAM,
- // We got two fin or reset offsets which did not match.
- QUIC_MULTIPLE_TERMINATION_OFFSETS,
- // We got bad payload and can not respond to it at the protocol level.
- QUIC_BAD_APPLICATION_PAYLOAD,
- // Stream closed due to connection error. No reset frame is sent when this
- // happens.
- QUIC_STREAM_CONNECTION_ERROR,
- // GoAway frame sent. No more stream can be created.
- QUIC_STREAM_PEER_GOING_AWAY,
- // The stream has been cancelled.
- QUIC_STREAM_CANCELLED,
- // Closing stream locally, sending a RST to allow for proper flow control
- // accounting. Sent in response to a RST from the peer.
- QUIC_RST_ACKNOWLEDGEMENT,
- // Receiver refused to create the stream (because its limit on open streams
- // has been reached). The sender should retry the request later (using
- // another stream).
- QUIC_REFUSED_STREAM,
- // Invalid URL in PUSH_PROMISE request header.
- QUIC_INVALID_PROMISE_URL,
- // Server is not authoritative for this URL.
- QUIC_UNAUTHORIZED_PROMISE_URL,
- // Can't have more than one active PUSH_PROMISE per URL.
- QUIC_DUPLICATE_PROMISE_URL,
- // Vary check failed.
- QUIC_PROMISE_VARY_MISMATCH,
- // Only GET and HEAD methods allowed.
- QUIC_INVALID_PROMISE_METHOD,
- // No error. Used as bound while iterating.
- QUIC_STREAM_LAST_ERROR,
-};
-// QUIC error codes are encoded to a single octet on-the-wire.
-static_assert(static_cast<int>(QUIC_STREAM_LAST_ERROR) <=
- std::numeric_limits<uint8_t>::max(),
- "QuicErrorCode exceeds single octet");
-
-// Because receiving an unknown QuicRstStreamErrorCode results in connection
-// teardown, we use this to make sure any errors predating a given version are
-// downgraded to the most appropriate existing error.
-NET_EXPORT_PRIVATE QuicRstStreamErrorCode
-AdjustErrorForVersion(QuicRstStreamErrorCode error_code, QuicVersion version);
-
-// These values must remain stable as they are uploaded to UMA histograms.
-// To add a new error code, use the current value of QUIC_LAST_ERROR and
-// increment QUIC_LAST_ERROR.
-enum QuicErrorCode {
- QUIC_NO_ERROR = 0,
-
- // Connection has reached an invalid state.
- QUIC_INTERNAL_ERROR = 1,
- // There were data frames after the a fin or reset.
- QUIC_STREAM_DATA_AFTER_TERMINATION = 2,
- // Control frame is malformed.
- QUIC_INVALID_PACKET_HEADER = 3,
- // Frame data is malformed.
- QUIC_INVALID_FRAME_DATA = 4,
- // The packet contained no payload.
- QUIC_MISSING_PAYLOAD = 48,
- // FEC data is malformed.
- QUIC_INVALID_FEC_DATA = 5,
- // STREAM frame data is malformed.
- QUIC_INVALID_STREAM_DATA = 46,
- // STREAM frame data overlaps with buffered data.
- QUIC_OVERLAPPING_STREAM_DATA = 87,
- // Received STREAM frame data is not encrypted.
- QUIC_UNENCRYPTED_STREAM_DATA = 61,
- // Attempt to send unencrypted STREAM frame.
- QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA = 88,
- // Received a frame which is likely the result of memory corruption.
- QUIC_MAYBE_CORRUPTED_MEMORY = 89,
- // FEC frame data is not encrypted.
- QUIC_UNENCRYPTED_FEC_DATA = 77,
- // RST_STREAM frame data is malformed.
- QUIC_INVALID_RST_STREAM_DATA = 6,
- // CONNECTION_CLOSE frame data is malformed.
- QUIC_INVALID_CONNECTION_CLOSE_DATA = 7,
- // GOAWAY frame data is malformed.
- QUIC_INVALID_GOAWAY_DATA = 8,
- // WINDOW_UPDATE frame data is malformed.
- QUIC_INVALID_WINDOW_UPDATE_DATA = 57,
- // BLOCKED frame data is malformed.
- QUIC_INVALID_BLOCKED_DATA = 58,
- // STOP_WAITING frame data is malformed.
- QUIC_INVALID_STOP_WAITING_DATA = 60,
- // PATH_CLOSE frame data is malformed.
- QUIC_INVALID_PATH_CLOSE_DATA = 78,
- // ACK frame data is malformed.
- QUIC_INVALID_ACK_DATA = 9,
-
- // Version negotiation packet is malformed.
- QUIC_INVALID_VERSION_NEGOTIATION_PACKET = 10,
- // Public RST packet is malformed.
- QUIC_INVALID_PUBLIC_RST_PACKET = 11,
- // There was an error decrypting.
- QUIC_DECRYPTION_FAILURE = 12,
- // There was an error encrypting.
- QUIC_ENCRYPTION_FAILURE = 13,
- // The packet exceeded kMaxPacketSize.
- QUIC_PACKET_TOO_LARGE = 14,
- // The peer is going away. May be a client or server.
- QUIC_PEER_GOING_AWAY = 16,
- // A stream ID was invalid.
- QUIC_INVALID_STREAM_ID = 17,
- // A priority was invalid.
- QUIC_INVALID_PRIORITY = 49,
- // Too many streams already open.
- QUIC_TOO_MANY_OPEN_STREAMS = 18,
- // The peer created too many available streams.
- QUIC_TOO_MANY_AVAILABLE_STREAMS = 76,
- // Received public reset for this connection.
- QUIC_PUBLIC_RESET = 19,
- // Invalid protocol version.
- QUIC_INVALID_VERSION = 20,
-
- // The Header ID for a stream was too far from the previous.
- QUIC_INVALID_HEADER_ID = 22,
- // Negotiable parameter received during handshake had invalid value.
- QUIC_INVALID_NEGOTIATED_VALUE = 23,
- // There was an error decompressing data.
- QUIC_DECOMPRESSION_FAILURE = 24,
- // The connection timed out due to no network activity.
- QUIC_NETWORK_IDLE_TIMEOUT = 25,
- // The connection timed out waiting for the handshake to complete.
- QUIC_HANDSHAKE_TIMEOUT = 67,
- // There was an error encountered migrating addresses.
- QUIC_ERROR_MIGRATING_ADDRESS = 26,
- // There was an error encountered migrating port only.
- QUIC_ERROR_MIGRATING_PORT = 86,
- // There was an error while writing to the socket.
- QUIC_PACKET_WRITE_ERROR = 27,
- // There was an error while reading from the socket.
- QUIC_PACKET_READ_ERROR = 51,
- // We received a STREAM_FRAME with no data and no fin flag set.
- QUIC_EMPTY_STREAM_FRAME_NO_FIN = 50,
- // We received invalid data on the headers stream.
- QUIC_INVALID_HEADERS_STREAM_DATA = 56,
- // The peer received too much data, violating flow control.
- QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA = 59,
- // The peer sent too much data, violating flow control.
- QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA = 63,
- // The peer received an invalid flow control window.
- QUIC_FLOW_CONTROL_INVALID_WINDOW = 64,
- // The connection has been IP pooled into an existing connection.
- QUIC_CONNECTION_IP_POOLED = 62,
- // The connection has too many outstanding sent packets.
- QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS = 68,
- // The connection has too many outstanding received packets.
- QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS = 69,
- // The quic connection has been cancelled.
- QUIC_CONNECTION_CANCELLED = 70,
- // Disabled QUIC because of high packet loss rate.
- QUIC_BAD_PACKET_LOSS_RATE = 71,
- // Disabled QUIC because of too many PUBLIC_RESETs post handshake.
- QUIC_PUBLIC_RESETS_POST_HANDSHAKE = 73,
- // Disabled QUIC because of too many timeouts with streams open.
- QUIC_TIMEOUTS_WITH_OPEN_STREAMS = 74,
- // Closed because we failed to serialize a packet.
- QUIC_FAILED_TO_SERIALIZE_PACKET = 75,
- // QUIC timed out after too many RTOs.
- QUIC_TOO_MANY_RTOS = 85,
-
- // Crypto errors.
-
- // Hanshake failed.
- QUIC_HANDSHAKE_FAILED = 28,
- // Handshake message contained out of order tags.
- QUIC_CRYPTO_TAGS_OUT_OF_ORDER = 29,
- // Handshake message contained too many entries.
- QUIC_CRYPTO_TOO_MANY_ENTRIES = 30,
- // Handshake message contained an invalid value length.
- QUIC_CRYPTO_INVALID_VALUE_LENGTH = 31,
- // A crypto message was received after the handshake was complete.
- QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE = 32,
- // A crypto message was received with an illegal message tag.
- QUIC_INVALID_CRYPTO_MESSAGE_TYPE = 33,
- // A crypto message was received with an illegal parameter.
- QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER = 34,
- // An invalid channel id signature was supplied.
- QUIC_INVALID_CHANNEL_ID_SIGNATURE = 52,
- // A crypto message was received with a mandatory parameter missing.
- QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND = 35,
- // A crypto message was received with a parameter that has no overlap
- // with the local parameter.
- QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP = 36,
- // A crypto message was received that contained a parameter with too few
- // values.
- QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND = 37,
- // An internal error occured in crypto processing.
- QUIC_CRYPTO_INTERNAL_ERROR = 38,
- // A crypto handshake message specified an unsupported version.
- QUIC_CRYPTO_VERSION_NOT_SUPPORTED = 39,
- // A crypto handshake message resulted in a stateless reject.
- QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT = 72,
- // There was no intersection between the crypto primitives supported by the
- // peer and ourselves.
- QUIC_CRYPTO_NO_SUPPORT = 40,
- // The server rejected our client hello messages too many times.
- QUIC_CRYPTO_TOO_MANY_REJECTS = 41,
- // The client rejected the server's certificate chain or signature.
- QUIC_PROOF_INVALID = 42,
- // A crypto message was received with a duplicate tag.
- QUIC_CRYPTO_DUPLICATE_TAG = 43,
- // A crypto message was received with the wrong encryption level (i.e. it
- // should have been encrypted but was not.)
- QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT = 44,
- // The server config for a server has expired.
- QUIC_CRYPTO_SERVER_CONFIG_EXPIRED = 45,
- // We failed to setup the symmetric keys for a connection.
- QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED = 53,
- // A handshake message arrived, but we are still validating the
- // previous handshake message.
- QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO = 54,
- // A server config update arrived before the handshake is complete.
- QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE = 65,
- // CHLO cannot fit in one packet.
- QUIC_CRYPTO_CHLO_TOO_LARGE = 90,
- // This connection involved a version negotiation which appears to have been
- // tampered with.
- QUIC_VERSION_NEGOTIATION_MISMATCH = 55,
-
- // Multipath is not enabled, but a packet with multipath flag on is received.
- QUIC_BAD_MULTIPATH_FLAG = 79,
-
- // IP address changed causing connection close.
- QUIC_IP_ADDRESS_CHANGED = 80,
-
- // Connection migration errors.
- // Network changed, but connection had no migratable streams.
- QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS = 81,
- // Connection changed networks too many times.
- QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES = 82,
- // Connection migration was attempted, but there was no new network to
- // migrate to.
- QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK = 83,
- // Network changed, but connection had one or more non-migratable streams.
- QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM = 84,
-
- // No error. Used as bound while iterating.
- QUIC_LAST_ERROR = 91,
-};
-
-typedef char DiversificationNonce[32];
-
-struct NET_EXPORT_PRIVATE QuicPacketPublicHeader {
- QuicPacketPublicHeader();
- explicit QuicPacketPublicHeader(const QuicPacketPublicHeader& other);
- ~QuicPacketPublicHeader();
-
- // Universal header. All QuicPacket headers will have a connection_id and
- // public flags.
- QuicConnectionId connection_id;
- QuicConnectionIdLength connection_id_length;
- bool multipath_flag;
- bool reset_flag;
- bool version_flag;
- QuicPacketNumberLength packet_number_length;
- QuicVersionVector versions;
- // nonce contains an optional, 32-byte nonce value. If not included in the
- // packet, |nonce| will be empty.
- DiversificationNonce* nonce;
-};
-
-// An integer which cannot be a packet number.
-const QuicPacketNumber kInvalidPacketNumber = 0;
-
-// Header for Data packets.
-struct NET_EXPORT_PRIVATE QuicPacketHeader {
- QuicPacketHeader();
- explicit QuicPacketHeader(const QuicPacketPublicHeader& header);
- QuicPacketHeader(const QuicPacketHeader& other);
-
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
- const QuicPacketHeader& s);
-
- QuicPacketPublicHeader public_header;
- QuicPacketNumber packet_number;
- QuicPathId path_id;
- bool entropy_flag;
- QuicPacketEntropyHash entropy_hash;
- bool fec_flag;
-};
-
-struct NET_EXPORT_PRIVATE QuicPublicResetPacket {
- QuicPublicResetPacket();
- explicit QuicPublicResetPacket(const QuicPacketPublicHeader& header);
-
- QuicPacketPublicHeader public_header;
- QuicPublicResetNonceProof nonce_proof;
- QuicPacketNumber rejected_packet_number;
- IPEndPoint client_address;
-};
-
-enum QuicVersionNegotiationState {
- START_NEGOTIATION = 0,
- // Server-side this implies we've sent a version negotiation packet and are
- // waiting on the client to select a compatible version. Client-side this
- // implies we've gotten a version negotiation packet, are retransmitting the
- // initial packets with a supported version and are waiting for our first
- // packet from the server.
- NEGOTIATION_IN_PROGRESS,
- // This indicates this endpoint has received a packet from the peer with a
- // version this endpoint supports. Version negotiation is complete, and the
- // version number will no longer be sent with future packets.
- NEGOTIATED_VERSION
-};
-
-typedef QuicPacketPublicHeader QuicVersionNegotiationPacket;
-
-// A padding frame contains no payload.
-struct NET_EXPORT_PRIVATE QuicPaddingFrame {
- QuicPaddingFrame() : num_padding_bytes(-1) {}
- explicit QuicPaddingFrame(int num_padding_bytes)
- : num_padding_bytes(num_padding_bytes) {}
-
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
- const QuicPaddingFrame& s);
-
- // -1: full padding to the end of a max-sized packet
- // otherwise: only pad up to num_padding_bytes bytes
- int num_padding_bytes;
-};
-
-// A ping frame contains no payload, though it is retransmittable,
-// and ACK'd just like other normal frames.
-struct NET_EXPORT_PRIVATE QuicPingFrame {};
-
-// A path MTU discovery frame contains no payload and is serialized as a ping
-// frame.
-struct NET_EXPORT_PRIVATE QuicMtuDiscoveryFrame {};
-
-class NET_EXPORT_PRIVATE QuicBufferAllocator {
- public:
- virtual ~QuicBufferAllocator();
-
- // Returns or allocates a new buffer of |size|. Never returns null.
- virtual char* New(size_t size) = 0;
-
- // Returns or allocates a new buffer of |size| if |flag_enable| is true.
- // Otherwise, returns a buffer that is compatible with this class directly
- // with operator new. Never returns null.
- virtual char* New(size_t size, bool flag_enable) = 0;
-
- // Releases a buffer.
- virtual void Delete(char* buffer) = 0;
-
- // Marks the allocator as being idle. Serves as a hint to notify the allocator
- // that it should release any resources it's still holding on to.
- virtual void MarkAllocatorIdle() {}
-};
-
-// Deleter for stream buffers. Copyable to support platforms where the deleter
-// of a unique_ptr must be copyable. Otherwise it would be nice for this to be
-// move-only.
-class NET_EXPORT_PRIVATE StreamBufferDeleter {
- public:
- StreamBufferDeleter() : allocator_(nullptr) {}
- explicit StreamBufferDeleter(QuicBufferAllocator* allocator)
- : allocator_(allocator) {}
-
- // Deletes |buffer| using |allocator_|.
- void operator()(char* buffer) const;
-
- private:
- // Not owned; must be valid so long as the buffer stored in the unique_ptr
- // that owns |this| is valid.
- QuicBufferAllocator* allocator_;
-};
-
-using UniqueStreamBuffer = std::unique_ptr<char[], StreamBufferDeleter>;
-
-// Allocates memory of size |size| using |allocator| for a QUIC stream buffer.
-NET_EXPORT_PRIVATE UniqueStreamBuffer
-NewStreamBuffer(QuicBufferAllocator* allocator, size_t size);
-
-struct NET_EXPORT_PRIVATE QuicStreamFrame {
- QuicStreamFrame();
- QuicStreamFrame(QuicStreamId stream_id,
- bool fin,
- QuicStreamOffset offset,
- base::StringPiece data);
- QuicStreamFrame(QuicStreamId stream_id,
- bool fin,
- QuicStreamOffset offset,
- QuicPacketLength data_length,
- UniqueStreamBuffer buffer);
- ~QuicStreamFrame();
-
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
- const QuicStreamFrame& s);
-
- QuicStreamId stream_id;
- bool fin;
- QuicPacketLength data_length;
- const char* data_buffer;
- QuicStreamOffset offset; // Location of this data in the stream.
- // nullptr when the QuicStreamFrame is received, and non-null when sent.
- UniqueStreamBuffer buffer;
-
- private:
- QuicStreamFrame(QuicStreamId stream_id,
- bool fin,
- QuicStreamOffset offset,
- const char* data_buffer,
- QuicPacketLength data_length,
- UniqueStreamBuffer buffer);
-
- DISALLOW_COPY_AND_ASSIGN(QuicStreamFrame);
-};
-static_assert(sizeof(QuicStreamFrame) <= 64,
- "Keep the QuicStreamFrame size to a cacheline.");
-
-typedef std::vector<std::pair<QuicPacketNumber, QuicTime>> PacketTimeVector;
-
-struct NET_EXPORT_PRIVATE QuicStopWaitingFrame {
- QuicStopWaitingFrame();
- ~QuicStopWaitingFrame();
-
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(
- std::ostream& os,
- const QuicStopWaitingFrame& s);
- // Path which this stop waiting frame belongs to.
- QuicPathId path_id;
- // Entropy hash of all packets up to, but not including, the least unacked
- // packet.
- QuicPacketEntropyHash entropy_hash;
- // The lowest packet we've sent which is unacked, and we expect an ack for.
- QuicPacketNumber least_unacked;
-};
-
-// A sequence of packet numbers where each number is unique. Intended to be used
-// in a sliding window fashion, where smaller old packet numbers are removed and
-// larger new packet numbers are added, with the occasional random access.
-class NET_EXPORT_PRIVATE PacketNumberQueue {
- public:
- // TODO(jdorfman): remove const_iterator and change the callers to iterate
- // over the intervals.
- class NET_EXPORT_PRIVATE const_iterator
- : public std::iterator<std::input_iterator_tag,
- QuicPacketNumber,
- std::ptrdiff_t,
- const QuicPacketNumber*,
- const QuicPacketNumber&> {
- public:
- const_iterator(
- IntervalSet<QuicPacketNumber>::const_iterator interval_set_iter,
- QuicPacketNumber first,
- QuicPacketNumber last);
- const_iterator(const const_iterator& other);
- const_iterator& operator=(const const_iterator& other);
- // TODO(rtenneti): on windows RValue reference gives errors.
- // const_iterator(const_iterator&& other);
- ~const_iterator();
-
- // TODO(rtenneti): on windows RValue reference gives errors.
- // const_iterator& operator=(const_iterator&& other);
- bool operator!=(const const_iterator& other) const;
- bool operator==(const const_iterator& other) const;
- value_type operator*() const;
- const_iterator& operator++();
- const_iterator operator++(int /* postincrement */);
-
- private:
- IntervalSet<QuicPacketNumber>::const_iterator interval_set_iter_;
- QuicPacketNumber current_;
- QuicPacketNumber last_;
- };
-
- PacketNumberQueue();
- PacketNumberQueue(const PacketNumberQueue& other);
- // TODO(rtenneti): on windows RValue reference gives errors.
- // PacketNumberQueue(PacketNumberQueue&& other);
- ~PacketNumberQueue();
-
- PacketNumberQueue& operator=(const PacketNumberQueue& other);
- // PacketNumberQueue& operator=(PacketNumberQueue&& other);
-
- // Adds |packet_number| to the set of packets in the queue.
- void Add(QuicPacketNumber packet_number);
-
- // Adds packets between [lower, higher) to the set of packets in the queue. It
- // is undefined behavior to call this with |higher| < |lower|.
- void Add(QuicPacketNumber lower, QuicPacketNumber higher);
-
- // Removes |packet_number| from the set of packets in the queue.
- void Remove(QuicPacketNumber packet_number);
-
- // Removes packets numbers between [lower, higher) to the set of packets in
- // the queue. It is undefined behavior to call this with |higher| < |lower|.
- void Remove(QuicPacketNumber lower, QuicPacketNumber higher);
-
- // Removes packets with values less than |higher| from the set of packets in
- // the queue. Returns true if packets were removed.
- bool RemoveUpTo(QuicPacketNumber higher);
-
- // Returns true if the queue contains |packet_number|.
- bool Contains(QuicPacketNumber packet_number) const;
-
- // Returns true if the queue is empty.
- bool Empty() const;
-
- // Returns the minimum packet number stored in the queue. It is undefined
- // behavior to call this if the queue is empty.
- QuicPacketNumber Min() const;
-
- // Returns the maximum packet number stored in the queue. It is undefined
- // behavior to call this if the queue is empty.
- QuicPacketNumber Max() const;
-
- // Returns the number of unique packets stored in the queue. Inefficient; only
- // exposed for testing.
- size_t NumPacketsSlow() const;
-
- // Returns the number of disjoint packet number intervals contained in the
- // queue.
- size_t NumIntervals() const;
-
- // Returns the length of last interval.
- QuicPacketNumber LastIntervalLength() const;
-
- // Returns iterators over the individual packet numbers.
- const_iterator begin() const;
- const_iterator end() const;
- const_iterator lower_bound(QuicPacketNumber packet_number) const;
-
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(
- std::ostream& os,
- const PacketNumberQueue& q);
-
- private:
- IntervalSet<QuicPacketNumber> packet_number_intervals_;
-};
-
-struct NET_EXPORT_PRIVATE QuicAckFrame {
- QuicAckFrame();
- QuicAckFrame(const QuicAckFrame& other);
- ~QuicAckFrame();
-
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
- const QuicAckFrame& s);
-
- // The highest packet number we've observed from the peer.
- //
- // In general, this should be the largest packet number we've received. In
- // the case of truncated acks, we may have to advertise a lower "upper bound"
- // than largest received, to avoid implicitly acking missing packets that
- // don't fit in the missing packet list due to size limitations. In this
- // case, largest_observed may be a packet which is also in the missing packets
- // list.
- QuicPacketNumber largest_observed;
-
- // Time elapsed since largest_observed was received until this Ack frame was
- // sent.
- QuicTime::Delta ack_delay_time;
-
- // Vector of <packet_number, time> for when packets arrived.
- PacketTimeVector received_packet_times;
-
- // Set of packets.
- PacketNumberQueue packets;
-
- // Path which this ack belongs to.
- QuicPathId path_id;
-
- // Entropy hash of all packets up to largest observed not including missing
- // packets.
- QuicPacketEntropyHash entropy_hash;
-
- // Whether the ack had to be truncated when sent.
- bool is_truncated;
-
- // If true, |packets| express missing packets. Otherwise, |packets| express
- // received packets.
- bool missing;
-};
-
-// True if the packet number is greater than largest_observed or is listed
-// as missing.
-// Always returns false for packet numbers less than least_unacked.
-bool NET_EXPORT_PRIVATE
-IsAwaitingPacket(const QuicAckFrame& ack_frame,
- QuicPacketNumber packet_number,
- QuicPacketNumber peer_least_packet_awaiting_ack);
-
-// Defines for all types of congestion control algorithms that can be used in
-// QUIC. Note that this is separate from the congestion feedback type -
-// some congestion control algorithms may use the same feedback type
-// (Reno and Cubic are the classic example for that).
-enum CongestionControlType {
- kCubic,
- kCubicBytes,
- kReno,
- kRenoBytes,
- kBBR,
-};
-
-enum LossDetectionType {
- kNack, // Used to mimic TCP's loss detection.
- kTime, // Time based loss detection.
- kAdaptiveTime, // Adaptive time based loss detection.
-};
-
-struct NET_EXPORT_PRIVATE QuicRstStreamFrame {
- QuicRstStreamFrame();
- QuicRstStreamFrame(QuicStreamId stream_id,
- QuicRstStreamErrorCode error_code,
- QuicStreamOffset bytes_written);
-
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(
- std::ostream& os,
- const QuicRstStreamFrame& r);
-
- QuicStreamId stream_id;
- QuicRstStreamErrorCode error_code;
-
- // Used to update flow control windows. On termination of a stream, both
- // endpoints must inform the peer of the number of bytes they have sent on
- // that stream. This can be done through normal termination (data packet with
- // FIN) or through a RST.
- QuicStreamOffset byte_offset;
-};
-
-struct NET_EXPORT_PRIVATE QuicConnectionCloseFrame {
- QuicConnectionCloseFrame();
-
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(
- std::ostream& os,
- const QuicConnectionCloseFrame& c);
-
- QuicErrorCode error_code;
- std::string error_details;
-};
-
-struct NET_EXPORT_PRIVATE QuicGoAwayFrame {
- QuicGoAwayFrame();
- QuicGoAwayFrame(QuicErrorCode error_code,
- QuicStreamId last_good_stream_id,
- const std::string& reason);
-
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
- const QuicGoAwayFrame& g);
-
- QuicErrorCode error_code;
- QuicStreamId last_good_stream_id;
- std::string reason_phrase;
-};
-
-// Flow control updates per-stream and at the connection levoel.
-// Based on SPDY's WINDOW_UPDATE frame, but uses an absolute byte offset rather
-// than a window delta.
-// TODO(rjshade): A possible future optimization is to make stream_id and
-// byte_offset variable length, similar to stream frames.
-struct NET_EXPORT_PRIVATE QuicWindowUpdateFrame {
- QuicWindowUpdateFrame() {}
- QuicWindowUpdateFrame(QuicStreamId stream_id, QuicStreamOffset byte_offset);
-
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(
- std::ostream& os,
- const QuicWindowUpdateFrame& w);
-
- // The stream this frame applies to. 0 is a special case meaning the overall
- // connection rather than a specific stream.
- QuicStreamId stream_id;
-
- // Byte offset in the stream or connection. The receiver of this frame must
- // not send data which would result in this offset being exceeded.
- QuicStreamOffset byte_offset;
-};
-
-// The BLOCKED frame is used to indicate to the remote endpoint that this
-// endpoint believes itself to be flow-control blocked but otherwise ready to
-// send data. The BLOCKED frame is purely advisory and optional.
-// Based on SPDY's BLOCKED frame (undocumented as of 2014-01-28).
-struct NET_EXPORT_PRIVATE QuicBlockedFrame {
- QuicBlockedFrame() {}
- explicit QuicBlockedFrame(QuicStreamId stream_id);
-
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
- const QuicBlockedFrame& b);
-
- // The stream this frame applies to. 0 is a special case meaning the overall
- // connection rather than a specific stream.
- QuicStreamId stream_id;
-};
-
-// The PATH_CLOSE frame is used to explicitly close a path. Both endpoints can
-// send a PATH_CLOSE frame to initiate a path termination. A path is considered
-// to be closed either a PATH_CLOSE frame is sent or received. An endpoint drops
-// receive side of a closed path, and packets with retransmittable frames on a
-// closed path are marked as retransmissions which will be transmitted on other
-// paths.
-struct NET_EXPORT_PRIVATE QuicPathCloseFrame {
- QuicPathCloseFrame() {}
- explicit QuicPathCloseFrame(QuicPathId path_id);
-
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(
- std::ostream& os,
- const QuicPathCloseFrame& p);
-
- QuicPathId path_id;
-};
-
-// EncryptionLevel enumerates the stages of encryption that a QUIC connection
-// progresses through. When retransmitting a packet, the encryption level needs
-// to be specified so that it is retransmitted at a level which the peer can
-// understand.
-enum EncryptionLevel : int8_t {
- ENCRYPTION_NONE = 0,
- ENCRYPTION_INITIAL = 1,
- ENCRYPTION_FORWARD_SECURE = 2,
-
- NUM_ENCRYPTION_LEVELS,
-};
-
-enum PeerAddressChangeType {
- // IP address and port remain unchanged.
- NO_CHANGE,
- // Port changed, but IP address remains unchanged.
- PORT_CHANGE,
- // IPv4 address changed, but within the /24 subnet (port may have changed.)
- IPV4_SUBNET_CHANGE,
- // IP address change from an IPv4 to an IPv6 address (port may have changed.)
- IPV4_TO_IPV6_CHANGE,
- // IP address change from an IPv6 to an IPv4 address (port may have changed.)
- IPV6_TO_IPV4_CHANGE,
- // IP address change from an IPv6 to an IPv6 address (port may have changed.)
- IPV6_TO_IPV6_CHANGE,
- // All other peer address changes.
- UNSPECIFIED_CHANGE,
-};
-
-struct NET_EXPORT_PRIVATE QuicFrame {
- QuicFrame();
- explicit QuicFrame(QuicPaddingFrame padding_frame);
- explicit QuicFrame(QuicMtuDiscoveryFrame frame);
- explicit QuicFrame(QuicPingFrame frame);
-
- explicit QuicFrame(QuicStreamFrame* stream_frame);
- explicit QuicFrame(QuicAckFrame* frame);
- explicit QuicFrame(QuicRstStreamFrame* frame);
- explicit QuicFrame(QuicConnectionCloseFrame* frame);
- explicit QuicFrame(QuicStopWaitingFrame* frame);
- explicit QuicFrame(QuicGoAwayFrame* frame);
- explicit QuicFrame(QuicWindowUpdateFrame* frame);
- explicit QuicFrame(QuicBlockedFrame* frame);
- explicit QuicFrame(QuicPathCloseFrame* frame);
-
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
- const QuicFrame& frame);
-
- QuicFrameType type;
- union {
- // Frames smaller than a pointer are inline.
- QuicPaddingFrame padding_frame;
- QuicMtuDiscoveryFrame mtu_discovery_frame;
- QuicPingFrame ping_frame;
-
- // Frames larger than a pointer.
- QuicStreamFrame* stream_frame;
- QuicAckFrame* ack_frame;
- QuicStopWaitingFrame* stop_waiting_frame;
- QuicRstStreamFrame* rst_stream_frame;
- QuicConnectionCloseFrame* connection_close_frame;
- QuicGoAwayFrame* goaway_frame;
- QuicWindowUpdateFrame* window_update_frame;
- QuicBlockedFrame* blocked_frame;
- QuicPathCloseFrame* path_close_frame;
- };
-};
-// QuicFrameType consumes 8 bytes with padding.
-static_assert(sizeof(QuicFrame) <= 16,
- "Frames larger than 8 bytes should be referenced by pointer.");
-
-typedef std::vector<QuicFrame> QuicFrames;
-
-class NET_EXPORT_PRIVATE QuicData {
- public:
- QuicData(const char* buffer, size_t length);
- QuicData(char* buffer, size_t length, bool owns_buffer);
- virtual ~QuicData();
-
- base::StringPiece AsStringPiece() const {
- return base::StringPiece(data(), length());
- }
-
- const char* data() const { return buffer_; }
- size_t length() const { return length_; }
- bool owns_buffer() const { return owns_buffer_; }
-
- private:
- const char* buffer_;
- size_t length_;
- bool owns_buffer_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicData);
-};
-
-class NET_EXPORT_PRIVATE QuicPacket : public QuicData {
- public:
- // TODO(fayang): 4 fields from public header are passed in as arguments.
- // Consider to add a convenience method which directly accepts the entire
- // public header.
- QuicPacket(char* buffer,
- size_t length,
- bool owns_buffer,
- QuicConnectionIdLength connection_id_length,
- bool includes_version,
- bool includes_path_id,
- bool includes_diversification_nonce,
- QuicPacketNumberLength packet_number_length);
-
- base::StringPiece AssociatedData(QuicVersion version) const;
- base::StringPiece Plaintext(QuicVersion version) const;
-
- char* mutable_data() { return buffer_; }
-
- private:
- char* buffer_;
- const QuicConnectionIdLength connection_id_length_;
- const bool includes_version_;
- const bool includes_path_id_;
- const bool includes_diversification_nonce_;
- const QuicPacketNumberLength packet_number_length_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicPacket);
-};
-
-class NET_EXPORT_PRIVATE QuicEncryptedPacket : public QuicData {
- public:
- QuicEncryptedPacket(const char* buffer, size_t length);
- QuicEncryptedPacket(char* buffer, size_t length, bool owns_buffer);
-
- // Clones the packet into a new packet which owns the buffer.
- QuicEncryptedPacket* Clone() const;
-
- // By default, gtest prints the raw bytes of an object. The bool data
- // member (in the base class QuicData) causes this object to have padding
- // bytes, which causes the default gtest object printer to read
- // uninitialize memory. So we need to teach gtest how to print this object.
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(
- std::ostream& os,
- const QuicEncryptedPacket& s);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(QuicEncryptedPacket);
-};
-
-// A received encrypted QUIC packet, with a recorded time of receipt.
-class NET_EXPORT_PRIVATE QuicReceivedPacket : public QuicEncryptedPacket {
- public:
- QuicReceivedPacket(const char* buffer, size_t length, QuicTime receipt_time);
- QuicReceivedPacket(char* buffer,
- size_t length,
- QuicTime receipt_time,
- bool owns_buffer);
-
- // Clones the packet into a new packet which owns the buffer.
- QuicReceivedPacket* Clone() const;
-
- // Returns the time at which the packet was received.
- QuicTime receipt_time() const { return receipt_time_; }
-
- // By default, gtest prints the raw bytes of an object. The bool data
- // member (in the base class QuicData) causes this object to have padding
- // bytes, which causes the default gtest object printer to read
- // uninitialize memory. So we need to teach gtest how to print this object.
- NET_EXPORT_PRIVATE friend std::ostream& operator<<(
- std::ostream& os,
- const QuicReceivedPacket& s);
-
- private:
- const QuicTime receipt_time_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicReceivedPacket);
-};
-
-// Pure virtual class to listen for packet acknowledgements.
-class NET_EXPORT_PRIVATE QuicAckListenerInterface
- : public base::RefCounted<QuicAckListenerInterface> {
- public:
- QuicAckListenerInterface() {}
-
- // Called when a packet is acked. Called once per packet.
- // |acked_bytes| is the number of data bytes acked.
- virtual void OnPacketAcked(int acked_bytes,
- QuicTime::Delta ack_delay_time) = 0;
-
- // Called when a packet is retransmitted. Called once per packet.
- // |retransmitted_bytes| is the number of data bytes retransmitted.
- virtual void OnPacketRetransmitted(int retransmitted_bytes) = 0;
-
- protected:
- friend class base::RefCounted<QuicAckListenerInterface>;
-
- // Delegates are ref counted.
- virtual ~QuicAckListenerInterface() {}
-};
-
-// Pure virtual class to close connection on unrecoverable errors.
-class NET_EXPORT_PRIVATE QuicConnectionCloseDelegateInterface {
- public:
- virtual ~QuicConnectionCloseDelegateInterface() {}
-
- // Called when an unrecoverable error is encountered.
- virtual void OnUnrecoverableError(QuicErrorCode error,
- const std::string& error_details,
- ConnectionCloseSource source) = 0;
-};
-
-struct NET_EXPORT_PRIVATE AckListenerWrapper {
- AckListenerWrapper(QuicAckListenerInterface* listener,
- QuicPacketLength data_length);
- AckListenerWrapper(const AckListenerWrapper& other);
- ~AckListenerWrapper();
-
- scoped_refptr<QuicAckListenerInterface> ack_listener;
- QuicPacketLength length;
-};
-
-struct NET_EXPORT_PRIVATE SerializedPacket {
- SerializedPacket(QuicPathId path_id,
- QuicPacketNumber packet_number,
- QuicPacketNumberLength packet_number_length,
- const char* encrypted_buffer,
- QuicPacketLength encrypted_length,
- QuicPacketEntropyHash entropy_hash,
- bool has_ack,
- bool has_stop_waiting);
- SerializedPacket(const SerializedPacket& other);
- ~SerializedPacket();
-
- // Not owned.
- const char* encrypted_buffer;
- QuicPacketLength encrypted_length;
- QuicFrames retransmittable_frames;
- IsHandshake has_crypto_handshake;
- // -1: full padding to the end of a max-sized packet
- // 0: no padding
- // otherwise: only pad up to num_padding_bytes bytes
- int16_t num_padding_bytes;
- QuicPathId path_id;
- QuicPacketNumber packet_number;
- QuicPacketNumberLength packet_number_length;
- EncryptionLevel encryption_level;
- QuicPacketEntropyHash entropy_hash;
- bool has_ack;
- bool has_stop_waiting;
- TransmissionType transmission_type;
- QuicPathId original_path_id;
- QuicPacketNumber original_packet_number;
-
- // Optional notifiers which will be informed when this packet has been ACKed.
- std::list<AckListenerWrapper> listeners;
-};
-
-struct NET_EXPORT_PRIVATE TransmissionInfo {
- // Used by STL when assigning into a map.
- TransmissionInfo();
-
- // Constructs a Transmission with a new all_transmissions set
- // containing |packet_number|.
- TransmissionInfo(EncryptionLevel level,
- QuicPacketNumberLength packet_number_length,
- TransmissionType transmission_type,
- QuicTime sent_time,
- QuicPacketLength bytes_sent,
- bool has_crypto_handshake,
- int num_padding_bytes);
-
- TransmissionInfo(const TransmissionInfo& other);
-
- ~TransmissionInfo();
-
- QuicFrames retransmittable_frames;
- EncryptionLevel encryption_level;
- QuicPacketNumberLength packet_number_length;
- QuicPacketLength bytes_sent;
- QuicTime sent_time;
- // Reason why this packet was transmitted.
- TransmissionType transmission_type;
- // In flight packets have not been abandoned or lost.
- bool in_flight;
- // True if the packet can never be acked, so it can be removed. Occurs when
- // a packet is never sent, after it is acknowledged once, or if it's a crypto
- // packet we never expect to receive an ack for.
- bool is_unackable;
- // True if the packet contains stream data from the crypto stream.
- bool has_crypto_handshake;
- // Non-zero if the packet needs padding if it's retransmitted.
- int16_t num_padding_bytes;
- // Stores the packet number of the next retransmission of this packet.
- // Zero if the packet has not been retransmitted.
- QuicPacketNumber retransmission;
- // Non-empty if there is a listener for this packet.
- std::list<AckListenerWrapper> ack_listeners;
-};
-
-// Struct to store the pending retransmission information.
-struct PendingRetransmission {
- PendingRetransmission(QuicPathId path_id,
- QuicPacketNumber packet_number,
- TransmissionType transmission_type,
- const QuicFrames& retransmittable_frames,
- bool has_crypto_handshake,
- int num_padding_bytes,
- EncryptionLevel encryption_level,
- QuicPacketNumberLength packet_number_length)
- : packet_number(packet_number),
- retransmittable_frames(retransmittable_frames),
- transmission_type(transmission_type),
- path_id(path_id),
- has_crypto_handshake(has_crypto_handshake),
- num_padding_bytes(num_padding_bytes),
- encryption_level(encryption_level),
- packet_number_length(packet_number_length) {}
-
- QuicPacketNumber packet_number;
- const QuicFrames& retransmittable_frames;
- TransmissionType transmission_type;
- QuicPathId path_id;
- bool has_crypto_handshake;
- int num_padding_bytes;
- EncryptionLevel encryption_level;
- QuicPacketNumberLength packet_number_length;
-};
-
-// Convenience wrapper to wrap an iovec array and the total length, which must
-// be less than or equal to the actual total length of the iovecs.
-struct NET_EXPORT_PRIVATE QuicIOVector {
- QuicIOVector(const struct iovec* iov, int iov_count, size_t total_length)
- : iov(iov), iov_count(iov_count), total_length(total_length) {}
-
- const struct iovec* iov;
- const int iov_count;
- const size_t total_length;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_PROTOCOL_H_
diff --git a/chromium/net/quic/quic_protocol_test.cc b/chromium/net/quic/quic_protocol_test.cc
deleted file mode 100644
index 64ac0956eee..00000000000
--- a/chromium/net/quic/quic_protocol_test.cc
+++ /dev/null
@@ -1,405 +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/quic_protocol.h"
-
-#include <sstream>
-
-#include "base/stl_util.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-namespace {
-
-TEST(QuicProtocolTest, AdjustErrorForVersion) {
- ASSERT_EQ(14, QUIC_STREAM_LAST_ERROR)
- << "Any additions to QuicRstStreamErrorCode require an addition to "
- << "AdjustErrorForVersion and this associated test.";
-
- // If we ever add different RST codes, we should have a test akin to the
- // following.
- // EXPECT_EQ(QUIC_RST_ACKNOWLEDGEMENT, AdjustErrorForVersion(
- // QUIC_RST_ACKNOWLEDGEMENT,
- // QUIC_VERSION_28));
-}
-
-TEST(QuicProtocolTest, MakeQuicTag) {
- QuicTag tag = MakeQuicTag('A', 'B', 'C', 'D');
- char bytes[4];
- memcpy(bytes, &tag, 4);
- EXPECT_EQ('A', bytes[0]);
- EXPECT_EQ('B', bytes[1]);
- EXPECT_EQ('C', bytes[2]);
- EXPECT_EQ('D', bytes[3]);
-}
-
-TEST(QuicProtocolTest, IsAawaitingPacket) {
- QuicAckFrame ack_frame;
- ack_frame.largest_observed = 10u;
- EXPECT_TRUE(IsAwaitingPacket(ack_frame, 11u, 0u));
- EXPECT_FALSE(IsAwaitingPacket(ack_frame, 1u, 0u));
-
- ack_frame.packets.Add(10);
- EXPECT_TRUE(IsAwaitingPacket(ack_frame, 10u, 0u));
-
- QuicAckFrame ack_frame1;
- ack_frame1.missing = false;
- ack_frame1.largest_observed = 10u;
- ack_frame1.packets.Add(1, 11);
- EXPECT_TRUE(IsAwaitingPacket(ack_frame1, 11u, 0u));
- EXPECT_FALSE(IsAwaitingPacket(ack_frame1, 1u, 0u));
-
- ack_frame1.packets.Remove(10);
- EXPECT_TRUE(IsAwaitingPacket(ack_frame1, 10u, 0u));
-
- QuicAckFrame ack_frame2;
- ack_frame2.missing = false;
- ack_frame2.largest_observed = 100u;
- ack_frame2.packets.Add(21, 100);
- EXPECT_FALSE(IsAwaitingPacket(ack_frame2, 11u, 20u));
- EXPECT_FALSE(IsAwaitingPacket(ack_frame2, 80u, 20u));
- EXPECT_TRUE(IsAwaitingPacket(ack_frame2, 101u, 20u));
-
- ack_frame2.packets.Remove(50);
- EXPECT_TRUE(IsAwaitingPacket(ack_frame2, 50u, 20u));
-}
-
-TEST(QuicProtocolTest, QuicVersionToQuicTag) {
-// If you add a new version to the QuicVersion enum you will need to add a new
-// case to QuicVersionToQuicTag, otherwise this test will fail.
-
-// TODO(rtenneti): Enable checking of Log(ERROR) messages.
-#if 0
- // Any logs would indicate an unsupported version which we don't expect.
- ScopedMockLog log(kDoNotCaptureLogsYet);
- EXPECT_CALL(log, Log(_, _, _)).Times(0);
- log.StartCapturingLogs();
-#endif
-
- // Explicitly test a specific version.
- EXPECT_EQ(MakeQuicTag('Q', '0', '2', '5'),
- QuicVersionToQuicTag(QUIC_VERSION_25));
-
- // 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 QuicTags).
- for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
- QuicVersion version = kSupportedQuicVersions[i];
- EXPECT_LT(0u, QuicVersionToQuicTag(version));
- }
-}
-
-TEST(QuicProtocolTest, QuicVersionToQuicTagUnsupported) {
-// TODO(rtenneti): Enable checking of Log(ERROR) messages.
-#if 0
- // TODO(rjshade): Change to DFATAL once we actually support multiple versions,
- // and QuicConnectionTest::SendVersionNegotiationPacket can be changed to use
- // mis-matched versions rather than relying on QUIC_VERSION_UNSUPPORTED.
- ScopedMockLog log(kDoNotCaptureLogsYet);
- EXPECT_CALL(log, Log(base_logging::ERROR, _, "Unsupported QuicVersion: 0"))
- .Times(1);
- log.StartCapturingLogs();
-#endif
-
- EXPECT_EQ(0u, QuicVersionToQuicTag(QUIC_VERSION_UNSUPPORTED));
-}
-
-TEST(QuicProtocolTest, QuicTagToQuicVersion) {
-// If you add a new version to the QuicVersion enum you will need to add a new
-// case to QuicTagToQuicVersion, otherwise this test will fail.
-
-// TODO(rtenneti): Enable checking of Log(ERROR) messages.
-#if 0
- // Any logs would indicate an unsupported version which we don't expect.
- ScopedMockLog log(kDoNotCaptureLogsYet);
- EXPECT_CALL(log, Log(_, _, _)).Times(0);
- log.StartCapturingLogs();
-#endif
-
- // Explicitly test specific versions.
- EXPECT_EQ(QUIC_VERSION_25,
- QuicTagToQuicVersion(MakeQuicTag('Q', '0', '2', '5')));
-
- for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
- QuicVersion version = kSupportedQuicVersions[i];
-
- // Get the tag from the version (we can loop over QuicVersions easily).
- QuicTag tag = QuicVersionToQuicTag(version);
- EXPECT_LT(0u, tag);
-
- // Now try converting back.
- QuicVersion tag_to_quic_version = QuicTagToQuicVersion(tag);
- EXPECT_EQ(version, tag_to_quic_version);
- EXPECT_NE(QUIC_VERSION_UNSUPPORTED, tag_to_quic_version);
- }
-}
-
-TEST(QuicProtocolTest, QuicTagToQuicVersionUnsupported) {
-// TODO(rtenneti): Enable checking of Log(ERROR) messages.
-#if 0
- ScopedMockLog log(kDoNotCaptureLogsYet);
-#ifndef NDEBUG
- EXPECT_CALL(log,
- Log(base_logging::INFO, _, "Unsupported QuicTag version: FAKE"))
- .Times(1);
-#endif
- log.StartCapturingLogs();
-#endif
-
- EXPECT_EQ(QUIC_VERSION_UNSUPPORTED,
- QuicTagToQuicVersion(MakeQuicTag('F', 'A', 'K', 'E')));
-}
-
-TEST(QuicProtocolTest, QuicVersionToString) {
- EXPECT_EQ("QUIC_VERSION_25", QuicVersionToString(QUIC_VERSION_25));
- EXPECT_EQ("QUIC_VERSION_UNSUPPORTED",
- QuicVersionToString(QUIC_VERSION_UNSUPPORTED));
-
- QuicVersion single_version[] = {QUIC_VERSION_25};
- QuicVersionVector versions_vector;
- for (size_t i = 0; i < arraysize(single_version); ++i) {
- versions_vector.push_back(single_version[i]);
- }
- EXPECT_EQ("QUIC_VERSION_25", QuicVersionVectorToString(versions_vector));
-
- QuicVersion multiple_versions[] = {QUIC_VERSION_UNSUPPORTED, QUIC_VERSION_25};
- versions_vector.clear();
- for (size_t i = 0; i < arraysize(multiple_versions); ++i) {
- versions_vector.push_back(multiple_versions[i]);
- }
- EXPECT_EQ("QUIC_VERSION_UNSUPPORTED,QUIC_VERSION_25",
- QuicVersionVectorToString(versions_vector));
-
- // Make sure that all supported versions are present in QuicVersionToString.
- for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
- QuicVersion version = kSupportedQuicVersions[i];
- EXPECT_NE("QUIC_VERSION_UNSUPPORTED", QuicVersionToString(version));
- }
-}
-
-TEST(QuicProtocolTest, AckFrameToString) {
- QuicAckFrame frame;
- frame.entropy_hash = 1;
- frame.largest_observed = 2;
- frame.ack_delay_time = QuicTime::Delta::FromMicroseconds(3);
- frame.packets.Add(4);
- frame.packets.Add(5);
- frame.received_packet_times = {
- {6, QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(7))}};
- std::ostringstream stream;
- stream << frame;
- EXPECT_EQ(
- "{ entropy_hash: 1, largest_observed: 2, ack_delay_time: 3, "
- "packets: [ 4 5 ], is_truncated: 0, received_packets: [ 6 at 7 ] }\n",
- stream.str());
-}
-
-TEST(QuicProtocolTest, PaddingFrameToString) {
- QuicPaddingFrame frame;
- frame.num_padding_bytes = 1;
- std::ostringstream stream;
- stream << frame;
- EXPECT_EQ("{ num_padding_bytes: 1 }\n", stream.str());
-}
-
-TEST(QuicProtocolTest, RstStreamFrameToString) {
- QuicRstStreamFrame frame;
- frame.stream_id = 1;
- frame.error_code = QUIC_STREAM_CANCELLED;
- std::ostringstream stream;
- stream << frame;
- EXPECT_EQ("{ stream_id: 1, error_code: 6 }\n", stream.str());
-}
-
-TEST(QuicProtocolTest, ConnectionCloseFrameToString) {
- QuicConnectionCloseFrame frame;
- frame.error_code = QUIC_NETWORK_IDLE_TIMEOUT;
- frame.error_details = "No recent network activity.";
- std::ostringstream stream;
- stream << frame;
- EXPECT_EQ(
- "{ error_code: 25, error_details: 'No recent network activity.' }\n",
- stream.str());
-}
-
-TEST(QuicProtocolTest, GoAwayFrameToString) {
- QuicGoAwayFrame frame;
- frame.error_code = QUIC_NETWORK_IDLE_TIMEOUT;
- frame.last_good_stream_id = 2;
- frame.reason_phrase = "Reason";
- std::ostringstream stream;
- stream << frame;
- EXPECT_EQ(
- "{ error_code: 25, last_good_stream_id: 2, reason_phrase: 'Reason' }\n",
- stream.str());
-}
-
-TEST(QuicProtocolTest, WindowUpdateFrameToString) {
- QuicWindowUpdateFrame frame;
- std::ostringstream stream;
- frame.stream_id = 1;
- frame.byte_offset = 2;
- stream << frame;
- EXPECT_EQ("{ stream_id: 1, byte_offset: 2 }\n", stream.str());
-}
-
-TEST(QuicProtocolTest, BlockedFrameToString) {
- QuicBlockedFrame frame;
- frame.stream_id = 1;
- std::ostringstream stream;
- stream << frame;
- EXPECT_EQ("{ stream_id: 1 }\n", stream.str());
-}
-
-TEST(QuicProtocolTest, StreamFrameToString) {
- QuicStreamFrame frame;
- frame.stream_id = 1;
- frame.fin = false;
- frame.offset = 2;
- frame.data_length = 3;
- std::ostringstream stream;
- stream << frame;
- EXPECT_EQ("{ stream_id: 1, fin: 0, offset: 2, length: 3 }\n", stream.str());
-}
-
-TEST(QuicProtocolTest, StopWaitingFrameToString) {
- QuicStopWaitingFrame frame;
- frame.entropy_hash = 1;
- frame.least_unacked = 2;
- std::ostringstream stream;
- stream << frame;
- EXPECT_EQ("{ entropy_hash: 1, least_unacked: 2 }\n", stream.str());
-}
-
-TEST(QuicProtocolTest, PathCloseFrameToString) {
- QuicPathCloseFrame frame;
- frame.path_id = 1;
- std::ostringstream stream;
- stream << frame;
- EXPECT_EQ("{ path_id: 1 }\n", stream.str());
-}
-
-TEST(QuicProtocolTest, FilterSupportedVersions) {
- QuicVersionVector all_versions = {QUIC_VERSION_25, QUIC_VERSION_26,
- QUIC_VERSION_27, QUIC_VERSION_29,
- QUIC_VERSION_30};
-
- FLAGS_quic_disable_pre_30 = true;
- QuicVersionVector filtered_versions = FilterSupportedVersions(all_versions);
- ASSERT_EQ(1u, filtered_versions.size());
- EXPECT_EQ(QUIC_VERSION_30, filtered_versions[0]);
-}
-
-// Tests that a queue contains the expected data after calls to Add().
-TEST(PacketNumberQueueTest, AddRange) {
- PacketNumberQueue queue;
- queue.Add(1, 51);
- queue.Add(53);
-
- EXPECT_FALSE(queue.Contains(0));
- for (int i = 1; i < 51; ++i) {
- EXPECT_TRUE(queue.Contains(i));
- }
- EXPECT_FALSE(queue.Contains(51));
- EXPECT_FALSE(queue.Contains(52));
- EXPECT_TRUE(queue.Contains(53));
- EXPECT_FALSE(queue.Contains(54));
- EXPECT_EQ(51u, queue.NumPacketsSlow());
- EXPECT_EQ(1u, queue.Min());
- EXPECT_EQ(53u, queue.Max());
-
- queue.Add(70);
- EXPECT_EQ(70u, queue.Max());
-}
-
-// Tests that a queue contains the expected data after calls to Remove().
-TEST(PacketNumberQueueTest, Removal) {
- PacketNumberQueue queue;
- queue.Add(0, 100);
-
- EXPECT_TRUE(queue.RemoveUpTo(51));
- EXPECT_FALSE(queue.RemoveUpTo(51));
- queue.Remove(53);
-
- EXPECT_FALSE(queue.Contains(0));
- for (int i = 1; i < 51; ++i) {
- EXPECT_FALSE(queue.Contains(i));
- }
- EXPECT_TRUE(queue.Contains(51));
- EXPECT_TRUE(queue.Contains(52));
- EXPECT_FALSE(queue.Contains(53));
- EXPECT_TRUE(queue.Contains(54));
- EXPECT_EQ(48u, queue.NumPacketsSlow());
- EXPECT_EQ(51u, queue.Min());
- EXPECT_EQ(99u, queue.Max());
-
- queue.Remove(51);
- EXPECT_EQ(52u, queue.Min());
- queue.Remove(99);
- EXPECT_EQ(98u, queue.Max());
-}
-
-// Tests that a queue is empty when all of its elements are removed.
-TEST(PacketNumberQueueTest, Empty) {
- PacketNumberQueue queue;
- EXPECT_TRUE(queue.Empty());
- EXPECT_EQ(0u, queue.NumPacketsSlow());
-
- queue.Add(1, 100);
- EXPECT_TRUE(queue.RemoveUpTo(100));
- EXPECT_TRUE(queue.Empty());
- EXPECT_EQ(0u, queue.NumPacketsSlow());
-}
-
-// Tests that logging the state of a PacketNumberQueue does not crash.
-TEST(PacketNumberQueueTest, LogDoesNotCrash) {
- std::ostringstream oss;
- PacketNumberQueue queue;
- oss << queue;
-
- queue.Add(1);
- queue.Add(50, 100);
- oss << queue;
-}
-
-// Tests that the iterators returned from a packet queue iterate over the queue.
-TEST(PacketNumberQueueTest, Iterators) {
- PacketNumberQueue queue;
- queue.Add(1, 100);
-
- const std::vector<QuicPacketNumber> actual(queue.begin(), queue.end());
-
- std::vector<QuicPacketNumber> expected;
- for (int i = 1; i < 100; ++i) {
- expected.push_back(i);
- }
-
- EXPECT_EQ(expected, actual);
-
- PacketNumberQueue::const_iterator it_low = queue.lower_bound(10);
- EXPECT_EQ(10u, *it_low);
-
- it_low = queue.lower_bound(101);
- EXPECT_TRUE(queue.end() == it_low);
-}
-
-TEST(PacketNumberQueueTest, IntervalLengthAndRemoveInterval) {
- PacketNumberQueue queue;
- queue.Add(1, 10);
- queue.Add(20, 30);
- queue.Add(40, 50);
- EXPECT_EQ(3u, queue.NumIntervals());
- EXPECT_EQ(10u, queue.LastIntervalLength());
- queue.Remove(9, 21);
- EXPECT_EQ(3u, queue.NumIntervals());
- EXPECT_FALSE(queue.Contains(9));
- EXPECT_FALSE(queue.Contains(20));
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_received_packet_manager.cc b/chromium/net/quic/quic_received_packet_manager.cc
deleted file mode 100644
index 73226a1d245..00000000000
--- a/chromium/net/quic/quic_received_packet_manager.cc
+++ /dev/null
@@ -1,323 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_received_packet_manager.h"
-
-#include <limits>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "base/strings/stringprintf.h"
-#include "net/base/linked_hash_map.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_connection_stats.h"
-#include "net/quic/quic_flags.h"
-
-using std::max;
-using std::min;
-using std::numeric_limits;
-
-namespace net {
-
-namespace {
-
-// The maximum number of packets to ack immediately after a missing packet for
-// fast retransmission to kick in at the sender. This limit is created to
-// reduce the number of acks sent that have no benefit for fast retransmission.
-// Set to the number of nacks needed for fast retransmit plus one for protection
-// against an ack loss
-const size_t kMaxPacketsAfterNewMissing = 4;
-}
-
-QuicReceivedPacketManager::EntropyTracker::EntropyTracker()
- : packets_entropy_hash_(0), first_gap_(1), largest_observed_(0) {}
-
-QuicReceivedPacketManager::EntropyTracker::~EntropyTracker() {}
-
-QuicPacketEntropyHash QuicReceivedPacketManager::EntropyTracker::EntropyHash(
- QuicPacketNumber packet_number) const {
- DCHECK_LE(packet_number, largest_observed_);
- if (packet_number == largest_observed_) {
- return packets_entropy_hash_;
- }
-
- DCHECK_GE(packet_number, first_gap_);
- DCHECK_EQ(first_gap_ + packets_entropy_.size() - 1, largest_observed_);
- QuicPacketEntropyHash hash = packets_entropy_hash_;
- ReceivedEntropyHashes::const_reverse_iterator it = packets_entropy_.rbegin();
- for (QuicPacketNumber i = 0; i < (largest_observed_ - packet_number);
- ++i, ++it) {
- hash ^= it->first;
- }
- return hash;
-}
-
-void QuicReceivedPacketManager::EntropyTracker::RecordPacketEntropyHash(
- QuicPacketNumber packet_number,
- QuicPacketEntropyHash entropy_hash) {
- if (packet_number < first_gap_) {
- DVLOG(1) << "Ignoring received packet entropy for packet_number:"
- << packet_number
- << " less than largest_peer_packet_number:" << first_gap_;
- return;
- }
- // RecordPacketEntropyHash is only intended to be called once per packet.
- DCHECK(packet_number > largest_observed_ ||
- !packets_entropy_[packet_number - first_gap_].second);
-
- packets_entropy_hash_ ^= entropy_hash;
-
- // Optimize the typical case of no gaps.
- if (packet_number == largest_observed_ + 1 && packets_entropy_.empty()) {
- ++first_gap_;
- largest_observed_ = packet_number;
- return;
- }
- if (packet_number > largest_observed_) {
- for (QuicPacketNumber i = 0; i < (packet_number - largest_observed_ - 1);
- ++i) {
- packets_entropy_.push_back(std::make_pair(0, false));
- }
- packets_entropy_.push_back(std::make_pair(entropy_hash, true));
- largest_observed_ = packet_number;
- } else {
- packets_entropy_[packet_number - first_gap_] =
- std::make_pair(entropy_hash, true);
- AdvanceFirstGapAndGarbageCollectEntropyMap();
- }
-
- DVLOG(2) << "setting cumulative received entropy hash to: "
- << static_cast<int>(packets_entropy_hash_)
- << " updated with packet number " << packet_number
- << " entropy hash: " << static_cast<int>(entropy_hash);
-}
-
-void QuicReceivedPacketManager::EntropyTracker::SetCumulativeEntropyUpTo(
- QuicPacketNumber packet_number,
- QuicPacketEntropyHash entropy_hash) {
- DCHECK_LE(packet_number, largest_observed_);
- if (packet_number < first_gap_) {
- DVLOG(1) << "Ignoring set entropy at:" << packet_number
- << " less than first_gap_:" << first_gap_;
- return;
- }
- while (first_gap_ < packet_number) {
- ++first_gap_;
- if (!packets_entropy_.empty()) {
- packets_entropy_.pop_front();
- }
- }
- // Compute the current entropy by XORing in all entropies received including
- // and since packet_number.
- packets_entropy_hash_ = entropy_hash;
- for (ReceivedEntropyHashes::const_iterator it = packets_entropy_.begin();
- it != packets_entropy_.end(); ++it) {
- packets_entropy_hash_ ^= it->first;
- }
-
- // Garbage collect entries from the beginning of the map.
- AdvanceFirstGapAndGarbageCollectEntropyMap();
-}
-
-void QuicReceivedPacketManager::EntropyTracker::
- AdvanceFirstGapAndGarbageCollectEntropyMap() {
- while (!packets_entropy_.empty() && packets_entropy_.front().second) {
- ++first_gap_;
- packets_entropy_.pop_front();
- }
-}
-
-QuicReceivedPacketManager::QuicReceivedPacketManager(QuicConnectionStats* stats)
- : peer_least_packet_awaiting_ack_(0),
- ack_frame_updated_(false),
- time_largest_observed_(QuicTime::Zero()),
- stats_(stats) {
- ack_frame_.largest_observed = 0;
- ack_frame_.entropy_hash = 0;
-}
-
-QuicReceivedPacketManager::~QuicReceivedPacketManager() {}
-
-void QuicReceivedPacketManager::RecordPacketReceived(
- QuicByteCount bytes,
- const QuicPacketHeader& header,
- QuicTime receipt_time) {
- QuicPacketNumber packet_number = header.packet_number;
- DCHECK(IsAwaitingPacket(packet_number));
- if (!ack_frame_updated_) {
- ack_frame_.received_packet_times.clear();
- }
- ack_frame_updated_ = true;
- if (ack_frame_.missing) {
- // Adds the range of packet numbers from max(largest observed + 1, least
- // awaiting ack) up to packet_number not including packet_number.
- ack_frame_.packets.Add(
- max(ack_frame_.largest_observed + 1, peer_least_packet_awaiting_ack_),
- packet_number);
- } else {
- ack_frame_.packets.Add(header.packet_number);
- }
-
- if (ack_frame_.largest_observed > packet_number) {
- if (ack_frame_.missing) {
- // We've gotten one of the out of order packets - remove it from our
- // "missing packets" list.
- DVLOG(1) << "Removing " << packet_number << " from missing list";
- ack_frame_.packets.Remove(packet_number);
- }
-
- // Record how out of order stats.
- ++stats_->packets_reordered;
- stats_->max_sequence_reordering =
- max(stats_->max_sequence_reordering,
- ack_frame_.largest_observed - packet_number);
- int64_t reordering_time_us =
- receipt_time.Subtract(time_largest_observed_).ToMicroseconds();
- stats_->max_time_reordering_us =
- max(stats_->max_time_reordering_us, reordering_time_us);
- }
- if (packet_number > ack_frame_.largest_observed) {
- ack_frame_.largest_observed = packet_number;
- time_largest_observed_ = receipt_time;
- }
- if (ack_frame_.missing) {
- entropy_tracker_.RecordPacketEntropyHash(packet_number,
- header.entropy_hash);
- }
-
- ack_frame_.received_packet_times.push_back(
- std::make_pair(packet_number, receipt_time));
-}
-
-bool QuicReceivedPacketManager::IsMissing(QuicPacketNumber packet_number) {
- if (ack_frame_.missing) {
- return ack_frame_.packets.Contains(packet_number);
- }
- return packet_number < ack_frame_.largest_observed &&
- !ack_frame_.packets.Contains(packet_number);
-}
-
-bool QuicReceivedPacketManager::IsAwaitingPacket(
- QuicPacketNumber packet_number) {
- return ::net::IsAwaitingPacket(ack_frame_, packet_number,
- peer_least_packet_awaiting_ack_);
-}
-
-namespace {
-struct isTooLarge {
- explicit isTooLarge(QuicPacketNumber n) : largest_observed_(n) {}
- QuicPacketNumber largest_observed_;
-
- // Return true if the packet in p is too different from largest_observed_
- // to express.
- bool operator()(const std::pair<QuicPacketNumber, QuicTime>& p) const {
- return largest_observed_ - p.first >= numeric_limits<uint8_t>::max();
- }
-};
-} // namespace
-
-const QuicFrame QuicReceivedPacketManager::GetUpdatedAckFrame(
- QuicTime approximate_now) {
- ack_frame_updated_ = false;
- if (ack_frame_.missing) {
- ack_frame_.entropy_hash = EntropyHash(ack_frame_.largest_observed);
- }
-
- if (time_largest_observed_ == QuicTime::Zero()) {
- // We have received no packets.
- ack_frame_.ack_delay_time = QuicTime::Delta::Infinite();
- } else {
- // Ensure the delta is zero if approximate now is "in the past".
- ack_frame_.ack_delay_time =
- approximate_now < time_largest_observed_
- ? QuicTime::Delta::Zero()
- : approximate_now.Subtract(time_largest_observed_);
- }
-
- // Clear all packet times if any are too far from largest observed.
- // It's expected this is extremely rare.
- for (PacketTimeVector::iterator it = ack_frame_.received_packet_times.begin();
- it != ack_frame_.received_packet_times.end();) {
- if (ack_frame_.largest_observed - it->first >=
- numeric_limits<uint8_t>::max()) {
- it = ack_frame_.received_packet_times.erase(it);
- } else {
- ++it;
- }
- }
-
- return QuicFrame(&ack_frame_);
-}
-
-QuicPacketEntropyHash QuicReceivedPacketManager::EntropyHash(
- QuicPacketNumber packet_number) const {
- return entropy_tracker_.EntropyHash(packet_number);
-}
-
-bool QuicReceivedPacketManager::DontWaitForPacketsBefore(
- QuicPacketNumber least_unacked) {
- peer_least_packet_awaiting_ack_ = least_unacked;
- return ack_frame_.packets.RemoveUpTo(least_unacked);
-}
-
-void QuicReceivedPacketManager::UpdatePacketInformationSentByPeer(
- const QuicStopWaitingFrame& stop_waiting) {
- // ValidateAck() should fail if peer_least_packet_awaiting_ack shrinks.
- DCHECK_LE(peer_least_packet_awaiting_ack_, stop_waiting.least_unacked);
- if (stop_waiting.least_unacked > peer_least_packet_awaiting_ack_) {
- bool packets_updated = DontWaitForPacketsBefore(stop_waiting.least_unacked);
- if (packets_updated) {
- if (ack_frame_.missing) {
- DVLOG(1) << "Updating entropy hashed since we missed packets";
- // There were some missing packets that we won't ever get now.
- // Recalculate the received entropy hash.
- entropy_tracker_.SetCumulativeEntropyUpTo(stop_waiting.least_unacked,
- stop_waiting.entropy_hash);
- }
- // Ack frame gets updated because packets set is updated because of stop
- // waiting frame.
- ack_frame_updated_ = true;
- }
- }
- DCHECK(ack_frame_.packets.Empty() ||
- ack_frame_.packets.Min() >= peer_least_packet_awaiting_ack_);
-}
-
-bool QuicReceivedPacketManager::HasMissingPackets() const {
- if (ack_frame_.missing) {
- return !ack_frame_.packets.Empty();
- }
-
- return ack_frame_.packets.NumIntervals() > 1 ||
- (!ack_frame_.packets.Empty() &&
- ack_frame_.packets.Min() >
- max(QuicPacketNumber(1), peer_least_packet_awaiting_ack_));
-}
-
-bool QuicReceivedPacketManager::HasNewMissingPackets() const {
- if (ack_frame_.missing) {
- return !ack_frame_.packets.Empty() &&
- (ack_frame_.largest_observed - ack_frame_.packets.Max()) <=
- kMaxPacketsAfterNewMissing;
- }
-
- return HasMissingPackets() &&
- ack_frame_.packets.LastIntervalLength() <= kMaxPacketsAfterNewMissing;
-}
-
-size_t QuicReceivedPacketManager::NumTrackedPackets() const {
- return entropy_tracker_.size();
-}
-
-void QuicReceivedPacketManager::SetVersion(QuicVersion version) {
- ack_frame_.missing = version <= QUIC_VERSION_33;
-}
-
-bool QuicReceivedPacketManager::ack_frame_updated() const {
- return ack_frame_updated_;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_received_packet_manager.h b/chromium/net/quic/quic_received_packet_manager.h
deleted file mode 100644
index 44a770b751d..00000000000
--- a/chromium/net/quic/quic_received_packet_manager.h
+++ /dev/null
@@ -1,191 +0,0 @@
-// Copyright 2013 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.
-//
-// Manages the packet entropy calculation for both sent and received packets
-// for a connection.
-
-#ifndef NET_QUIC_QUIC_RECEIVED_PACKET_MANAGER_H_
-#define NET_QUIC_QUIC_RECEIVED_PACKET_MANAGER_H_
-
-#include <stddef.h>
-
-#include <deque>
-
-#include "base/macros.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-namespace test {
-class EntropyTrackerPeer;
-class QuicConnectionPeer;
-class QuicReceivedPacketManagerPeer;
-} // namespace test
-
-struct QuicConnectionStats;
-
-// Records all received packets by a connection and tracks their entropy.
-// Also calculates the correct entropy for the framer when it truncates an ack
-// frame being serialized.
-class NET_EXPORT_PRIVATE QuicReceivedPacketManager
- : public QuicReceivedEntropyHashCalculatorInterface {
- public:
- class NET_EXPORT_PRIVATE EntropyTracker {
- public:
- EntropyTracker();
- ~EntropyTracker();
-
- // Compute the XOR of the entropy of all received packets up to
- // and including packet_number.
- // Requires that either:
- // packet_number == largest_observed_
- // or:
- // packet_number > first_gap_ &&
- // packet_number < largest_observed_ &&
- // packet_number in packets_entropy_
- QuicPacketEntropyHash EntropyHash(QuicPacketNumber packet_number) const;
-
- // Record the received entropy hash against |packet_number|.
- // Performs garbage collection to advance first_gap_ if
- // packet_number == first_gap_.
- void RecordPacketEntropyHash(QuicPacketNumber packet_number,
- QuicPacketEntropyHash entropy_hash);
-
- // Sets the entropy hash up to but not including a packet number based
- // on the hash provided by a StopWaiting frame. Clears older packet
- // entropy entries and performs garbage collection up to the first gap.
- void SetCumulativeEntropyUpTo(QuicPacketNumber packet_number,
- QuicPacketEntropyHash entropy_hash);
-
- size_t size() const { return packets_entropy_.size(); }
-
- private:
- friend class test::EntropyTrackerPeer;
-
- // A deque indexed by packet number storing the packet's hash and whether
- // a hash was recorded for that packet number.
- typedef std::deque<std::pair<QuicPacketEntropyHash, bool>>
- ReceivedEntropyHashes;
-
- // Recomputes first_gap_ and removes packets_entropy_ entries that are no
- // longer needed to compute EntropyHash.
- void AdvanceFirstGapAndGarbageCollectEntropyMap();
-
- // Map of received packet numbers to their corresponding entropy.
- // Stores an entry for every received packet whose packet_number is larger
- // than first_gap_. Packets without the entropy bit set have an entropy
- // value of 0.
- ReceivedEntropyHashes packets_entropy_;
-
- // Cumulative hash of entropy of all received packets.
- QuicPacketEntropyHash packets_entropy_hash_;
-
- // packet number of the first packet that we do not know the entropy of.
- // If there are no gaps in the received packet sequence,
- // packets_entropy_ will be empty and first_gap_ will be equal to
- // 'largest_observed_ + 1' since that's the first packet for which
- // entropy is unknown. If there are gaps, packets_entropy_ will
- // contain entries for all received packets with packet_number >
- // first_gap_.
- QuicPacketNumber first_gap_;
-
- // packet number of the largest observed packet.
- QuicPacketNumber largest_observed_;
-
- DISALLOW_COPY_AND_ASSIGN(EntropyTracker);
- };
-
- explicit QuicReceivedPacketManager(QuicConnectionStats* stats);
- ~QuicReceivedPacketManager() override;
-
- // Updates the internal state concerning which packets have been received.
- // bytes: the packet size in bytes including Quic Headers.
- // header: the packet header.
- // timestamp: the arrival time of the packet.
- virtual void RecordPacketReceived(QuicByteCount bytes,
- const QuicPacketHeader& header,
- QuicTime receipt_time);
-
- // Checks whether |packet_number| is missing and less than largest observed.
- virtual bool IsMissing(QuicPacketNumber packet_number);
-
- // Checks if we're still waiting for the packet with |packet_number|.
- virtual bool IsAwaitingPacket(QuicPacketNumber packet_number);
-
- // Retrieves a frame containing a QuicAckFrame. The ack frame may not be
- // changed outside QuicReceivedPacketManager and must be serialized before
- // another packet is received, or it will change.
- const QuicFrame GetUpdatedAckFrame(QuicTime approximate_now);
-
- // QuicReceivedEntropyHashCalculatorInterface
- // Called by QuicFramer, when the outgoing ack gets truncated, to recalculate
- // the received entropy hash for the truncated ack frame.
- QuicPacketEntropyHash EntropyHash(
- QuicPacketNumber packet_number) const override;
-
- // Updates internal state based on |stop_waiting|.
- virtual void UpdatePacketInformationSentByPeer(
- const QuicStopWaitingFrame& stop_waiting);
-
- // Returns true if there are any missing packets.
- bool HasMissingPackets() const;
-
- // Returns true when there are new missing packets to be reported within 3
- // packets of the largest observed.
- virtual bool HasNewMissingPackets() const;
-
- // Returns the number of packets being tracked in the EntropyTracker.
- size_t NumTrackedPackets() const;
-
- // Sets the mode of packets set of ack_frame_ based on |version|.
- void SetVersion(QuicVersion version);
-
- QuicPacketNumber peer_least_packet_awaiting_ack() {
- return peer_least_packet_awaiting_ack_;
- }
-
- virtual bool ack_frame_updated() const;
-
- // For logging purposes.
- const QuicAckFrame& ack_frame() const { return ack_frame_; }
-
- private:
- friend class test::QuicConnectionPeer;
- friend class test::QuicReceivedPacketManagerPeer;
-
- // Deletes all missing packets before least unacked. The connection won't
- // process any packets with packet number before |least_unacked| that it
- // received after this call. Returns true if there were missing packets before
- // |least_unacked| unacked, false otherwise.
- bool DontWaitForPacketsBefore(QuicPacketNumber least_unacked);
-
- // Tracks entropy hashes of received packets.
- EntropyTracker entropy_tracker_;
-
- // Least packet number of the the packet sent by the peer for which it
- // hasn't received an ack.
- QuicPacketNumber peer_least_packet_awaiting_ack_;
-
- // Received packet information used to produce acks.
- QuicAckFrame ack_frame_;
-
- // True if |ack_frame_| has been updated since UpdateReceivedPacketInfo was
- // last called.
- bool ack_frame_updated_;
-
- // The time we received the largest_observed packet number, or zero if
- // no packet numbers have been received since UpdateReceivedPacketInfo.
- // Needed for calculating ack_delay_time.
- QuicTime time_largest_observed_;
-
- QuicConnectionStats* stats_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicReceivedPacketManager);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_RECEIVED_PACKET_MANAGER_H_
diff --git a/chromium/net/quic/quic_received_packet_manager_test.cc b/chromium/net/quic/quic_received_packet_manager_test.cc
deleted file mode 100644
index a3bca2f539d..00000000000
--- a/chromium/net/quic/quic_received_packet_manager_test.cc
+++ /dev/null
@@ -1,396 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_received_packet_manager.h"
-
-#include <algorithm>
-#include <vector>
-
-#include "net/quic/quic_connection_stats.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/test_tools/quic_received_packet_manager_peer.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::pair;
-using std::vector;
-
-namespace net {
-namespace test {
-
-class EntropyTrackerPeer {
- public:
- static QuicPacketNumber first_gap(
- const QuicReceivedPacketManager::EntropyTracker& tracker) {
- return tracker.first_gap_;
- }
- static QuicPacketNumber largest_observed(
- const QuicReceivedPacketManager::EntropyTracker& tracker) {
- return tracker.largest_observed_;
- }
- static int packets_entropy_size(
- const QuicReceivedPacketManager::EntropyTracker& tracker) {
- return tracker.packets_entropy_.size();
- }
- static bool IsTrackingPacket(
- const QuicReceivedPacketManager::EntropyTracker& tracker,
- QuicPacketNumber packet_number) {
- return packet_number >= tracker.first_gap_ &&
- packet_number <
- (tracker.first_gap_ + tracker.packets_entropy_.size()) &&
- tracker.packets_entropy_[packet_number - tracker.first_gap_].second;
- }
-};
-
-namespace {
-
-// Entropy of individual packets is not tracked if there are no gaps.
-TEST(EntropyTrackerTest, NoGaps) {
- QuicReceivedPacketManager::EntropyTracker tracker;
-
- tracker.RecordPacketEntropyHash(1, 23);
- tracker.RecordPacketEntropyHash(2, 42);
-
- EXPECT_EQ(23 ^ 42, tracker.EntropyHash(2));
- EXPECT_EQ(3u, EntropyTrackerPeer::first_gap(tracker));
-
- EXPECT_EQ(2u, EntropyTrackerPeer::largest_observed(tracker));
- EXPECT_EQ(0, EntropyTrackerPeer::packets_entropy_size(tracker));
- EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 1));
- EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 2));
-}
-
-// Entropy of individual packets is tracked as long as there are gaps.
-// Filling the first gap results in entropy getting garbage collected.
-TEST(EntropyTrackerTest, FillGaps) {
- QuicReceivedPacketManager::EntropyTracker tracker;
-
- tracker.RecordPacketEntropyHash(2, 5);
- tracker.RecordPacketEntropyHash(5, 17);
- tracker.RecordPacketEntropyHash(6, 23);
- tracker.RecordPacketEntropyHash(9, 42);
-
- EXPECT_EQ(1u, EntropyTrackerPeer::first_gap(tracker));
- EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
- EXPECT_EQ(9, EntropyTrackerPeer::packets_entropy_size(tracker));
-
- EXPECT_EQ(5, tracker.EntropyHash(2));
- EXPECT_EQ(5 ^ 17, tracker.EntropyHash(5));
- EXPECT_EQ(5 ^ 17 ^ 23, tracker.EntropyHash(6));
- EXPECT_EQ(5 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
-
- EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 1));
- EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 2));
- EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 5));
- EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 6));
- EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 9));
-
- // Fill the gap at 1.
- tracker.RecordPacketEntropyHash(1, 2);
-
- EXPECT_EQ(3u, EntropyTrackerPeer::first_gap(tracker));
- EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
- EXPECT_EQ(7, EntropyTrackerPeer::packets_entropy_size(tracker));
-
- EXPECT_EQ(2 ^ 5 ^ 17, tracker.EntropyHash(5));
- EXPECT_EQ(2 ^ 5 ^ 17 ^ 23, tracker.EntropyHash(6));
- EXPECT_EQ(2 ^ 5 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
-
- EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 1));
- EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 2));
- EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 5));
- EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 6));
- EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 9));
-
- // Fill the gap at 4.
- tracker.RecordPacketEntropyHash(4, 2);
-
- EXPECT_EQ(3u, EntropyTrackerPeer::first_gap(tracker));
- EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
- EXPECT_EQ(7, EntropyTrackerPeer::packets_entropy_size(tracker));
-
- EXPECT_EQ(5, tracker.EntropyHash(4));
- EXPECT_EQ(5 ^ 17, tracker.EntropyHash(5));
- EXPECT_EQ(5 ^ 17 ^ 23, tracker.EntropyHash(6));
- EXPECT_EQ(5 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
-
- EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 3));
- EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 4));
- EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 5));
- EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 6));
- EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 9));
-
- // Fill the gap at 3. Entropy for packets 3 to 6 are forgotten.
- tracker.RecordPacketEntropyHash(3, 2);
-
- EXPECT_EQ(7u, EntropyTrackerPeer::first_gap(tracker));
- EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
- EXPECT_EQ(3, EntropyTrackerPeer::packets_entropy_size(tracker));
-
- EXPECT_EQ(2 ^ 5 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
-
- EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 3));
- EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 4));
- EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 5));
- EXPECT_FALSE(EntropyTrackerPeer::IsTrackingPacket(tracker, 6));
- EXPECT_TRUE(EntropyTrackerPeer::IsTrackingPacket(tracker, 9));
-
- // Fill in the rest.
- tracker.RecordPacketEntropyHash(7, 2);
- tracker.RecordPacketEntropyHash(8, 2);
-
- EXPECT_EQ(10u, EntropyTrackerPeer::first_gap(tracker));
- EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
- EXPECT_EQ(0, EntropyTrackerPeer::packets_entropy_size(tracker));
-
- EXPECT_EQ(2 ^ 5 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
-}
-
-TEST(EntropyTrackerTest, SetCumulativeEntropyUpTo) {
- QuicReceivedPacketManager::EntropyTracker tracker;
-
- tracker.RecordPacketEntropyHash(2, 5);
- tracker.RecordPacketEntropyHash(5, 17);
- tracker.RecordPacketEntropyHash(6, 23);
- tracker.RecordPacketEntropyHash(9, 42);
-
- EXPECT_EQ(1u, EntropyTrackerPeer::first_gap(tracker));
- EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
- EXPECT_EQ(9, EntropyTrackerPeer::packets_entropy_size(tracker));
-
- // Inform the tracker about value of the hash at a gap.
- tracker.SetCumulativeEntropyUpTo(3, 7);
- EXPECT_EQ(3u, EntropyTrackerPeer::first_gap(tracker));
- EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
- EXPECT_EQ(7, EntropyTrackerPeer::packets_entropy_size(tracker));
-
- EXPECT_EQ(7 ^ 17, tracker.EntropyHash(5));
- EXPECT_EQ(7 ^ 17 ^ 23, tracker.EntropyHash(6));
- EXPECT_EQ(7 ^ 17 ^ 23 ^ 42, tracker.EntropyHash(9));
-
- // Inform the tracker about value of the hash at a known location.
- tracker.SetCumulativeEntropyUpTo(6, 1);
- EXPECT_EQ(7u, EntropyTrackerPeer::first_gap(tracker));
- EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
- EXPECT_EQ(3, EntropyTrackerPeer::packets_entropy_size(tracker));
-
- EXPECT_EQ(1 ^ 23 ^ 42, tracker.EntropyHash(9));
-
- // Inform the tracker about value of the hash at the last location.
- tracker.SetCumulativeEntropyUpTo(9, 21);
- EXPECT_EQ(10u, EntropyTrackerPeer::first_gap(tracker));
- EXPECT_EQ(9u, EntropyTrackerPeer::largest_observed(tracker));
- EXPECT_EQ(0, EntropyTrackerPeer::packets_entropy_size(tracker));
-
- EXPECT_EQ(42 ^ 21, tracker.EntropyHash(9));
-}
-
-struct TestParams {
- explicit TestParams(QuicVersion version) : version(version) {}
-
- friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
- os << "{ version: " << QuicVersionToString(p.version) << " }";
- return os;
- }
-
- QuicVersion version;
-};
-
-vector<TestParams> GetTestParams() {
- vector<TestParams> params;
- QuicVersionVector all_supported_versions = QuicSupportedVersions();
- for (size_t i = 0; i < all_supported_versions.size(); ++i) {
- params.push_back(TestParams(all_supported_versions[i]));
- }
- return params;
-}
-
-class QuicReceivedPacketManagerTest
- : public ::testing::TestWithParam<TestParams> {
- protected:
- QuicReceivedPacketManagerTest() : received_manager_(&stats_) {
- received_manager_.SetVersion(GetParam().version);
- }
-
- void RecordPacketReceipt(QuicPacketNumber packet_number,
- QuicPacketEntropyHash entropy_hash) {
- RecordPacketReceipt(packet_number, entropy_hash, QuicTime::Zero());
- }
-
- void RecordPacketReceipt(QuicPacketNumber packet_number,
- QuicPacketEntropyHash entropy_hash,
- QuicTime receipt_time) {
- QuicPacketHeader header;
- header.packet_number = packet_number;
- header.entropy_hash = entropy_hash;
- received_manager_.RecordPacketReceived(0u, header, receipt_time);
- }
-
- QuicConnectionStats stats_;
- QuicReceivedPacketManager received_manager_;
-};
-
-INSTANTIATE_TEST_CASE_P(QuicReceivedPacketManagerTest,
- QuicReceivedPacketManagerTest,
- ::testing::ValuesIn(GetTestParams()));
-
-TEST_P(QuicReceivedPacketManagerTest, ReceivedPacketEntropyHash) {
- if (GetParam().version > QUIC_VERSION_33) {
- return;
- }
- vector<pair<QuicPacketNumber, QuicPacketEntropyHash>> entropies;
- entropies.push_back(std::make_pair(1, 12));
- entropies.push_back(std::make_pair(7, 1));
- entropies.push_back(std::make_pair(2, 33));
- entropies.push_back(std::make_pair(5, 3));
- entropies.push_back(std::make_pair(8, 34));
-
- for (size_t i = 0; i < entropies.size(); ++i) {
- RecordPacketReceipt(entropies[i].first, entropies[i].second);
- }
-
- std::sort(entropies.begin(), entropies.end());
-
- QuicPacketEntropyHash hash = 0;
- size_t index = 0;
- for (size_t i = 1; i <= (*entropies.rbegin()).first; ++i) {
- if (entropies[index].first == i) {
- hash ^= entropies[index].second;
- ++index;
- }
- if (i < 3)
- continue;
- EXPECT_EQ(hash, received_manager_.EntropyHash(i));
- }
- // Reorder by 5 when 2 is received after 7.
- EXPECT_EQ(5u, stats_.max_sequence_reordering);
- EXPECT_EQ(0, stats_.max_time_reordering_us);
- EXPECT_EQ(2u, stats_.packets_reordered);
-}
-
-TEST_P(QuicReceivedPacketManagerTest, EntropyHashBelowLeastObserved) {
- if (GetParam().version > QUIC_VERSION_33) {
- return;
- }
- EXPECT_EQ(0, received_manager_.EntropyHash(0));
- RecordPacketReceipt(4, 5);
- EXPECT_EQ(0, received_manager_.EntropyHash(3));
-}
-
-TEST_P(QuicReceivedPacketManagerTest, EntropyHashAboveLargestObserved) {
- if (GetParam().version > QUIC_VERSION_33) {
- return;
- }
- EXPECT_EQ(0, received_manager_.EntropyHash(0));
- RecordPacketReceipt(4, 5);
- EXPECT_EQ(0, received_manager_.EntropyHash(3));
-}
-
-TEST_P(QuicReceivedPacketManagerTest, SetCumulativeEntropyUpTo) {
- if (GetParam().version > QUIC_VERSION_33) {
- return;
- }
- vector<pair<QuicPacketNumber, QuicPacketEntropyHash>> entropies;
- entropies.push_back(std::make_pair(1, 12));
- entropies.push_back(std::make_pair(2, 1));
- entropies.push_back(std::make_pair(3, 33));
- entropies.push_back(std::make_pair(4, 3));
- entropies.push_back(std::make_pair(6, 34));
- entropies.push_back(std::make_pair(7, 29));
-
- QuicPacketEntropyHash entropy_hash = 0;
- for (size_t i = 0; i < entropies.size(); ++i) {
- RecordPacketReceipt(entropies[i].first, entropies[i].second);
- entropy_hash ^= entropies[i].second;
- }
- EXPECT_EQ(entropy_hash, received_manager_.EntropyHash(7));
-
- // Now set the entropy hash up to 5 to be 100.
- entropy_hash ^= 100;
- for (size_t i = 0; i < 4; ++i) {
- entropy_hash ^= entropies[i].second;
- }
- QuicReceivedPacketManagerPeer::SetCumulativeEntropyUpTo(&received_manager_, 5,
- 100);
- EXPECT_EQ(entropy_hash, received_manager_.EntropyHash(7));
-
- QuicReceivedPacketManagerPeer::SetCumulativeEntropyUpTo(&received_manager_, 1,
- 50);
- EXPECT_EQ(entropy_hash, received_manager_.EntropyHash(7));
-
- // No reordering.
- EXPECT_EQ(0u, stats_.max_sequence_reordering);
- EXPECT_EQ(0, stats_.max_time_reordering_us);
- EXPECT_EQ(0u, stats_.packets_reordered);
-}
-
-TEST_P(QuicReceivedPacketManagerTest, DontWaitForPacketsBefore) {
- QuicPacketHeader header;
- header.packet_number = 2u;
- received_manager_.RecordPacketReceived(0u, header, QuicTime::Zero());
- header.packet_number = 7u;
- received_manager_.RecordPacketReceived(0u, header, QuicTime::Zero());
- EXPECT_TRUE(received_manager_.IsAwaitingPacket(3u));
- EXPECT_TRUE(received_manager_.IsAwaitingPacket(6u));
- EXPECT_TRUE(QuicReceivedPacketManagerPeer::DontWaitForPacketsBefore(
- &received_manager_, 4));
- EXPECT_FALSE(received_manager_.IsAwaitingPacket(3u));
- EXPECT_TRUE(received_manager_.IsAwaitingPacket(6u));
-}
-
-TEST_P(QuicReceivedPacketManagerTest, GetUpdatedAckFrame) {
- QuicPacketHeader header;
- header.packet_number = 2u;
- QuicTime two_ms = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(2));
- EXPECT_FALSE(received_manager_.ack_frame_updated());
- received_manager_.RecordPacketReceived(0u, header, two_ms);
- EXPECT_TRUE(received_manager_.ack_frame_updated());
-
- QuicFrame ack = received_manager_.GetUpdatedAckFrame(QuicTime::Zero());
- EXPECT_FALSE(received_manager_.ack_frame_updated());
- // When UpdateReceivedPacketInfo with a time earlier than the time of the
- // largest observed packet, make sure that the delta is 0, not negative.
- EXPECT_EQ(QuicTime::Delta::Zero(), ack.ack_frame->ack_delay_time);
- EXPECT_EQ(1u, ack.ack_frame->received_packet_times.size());
-
- QuicTime four_ms = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(4));
- ack = received_manager_.GetUpdatedAckFrame(four_ms);
- EXPECT_FALSE(received_manager_.ack_frame_updated());
- // When UpdateReceivedPacketInfo after not having received a new packet,
- // the delta should still be accurate.
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(2),
- ack.ack_frame->ack_delay_time);
- // And received packet times won't have change.
- EXPECT_EQ(1u, ack.ack_frame->received_packet_times.size());
-
- header.packet_number = 999u;
- received_manager_.RecordPacketReceived(0u, header, two_ms);
- header.packet_number = 4u;
- received_manager_.RecordPacketReceived(0u, header, two_ms);
- header.packet_number = 1000u;
- received_manager_.RecordPacketReceived(0u, header, two_ms);
- EXPECT_TRUE(received_manager_.ack_frame_updated());
- ack = received_manager_.GetUpdatedAckFrame(two_ms);
- EXPECT_FALSE(received_manager_.ack_frame_updated());
- // UpdateReceivedPacketInfo should discard any times which can't be
- // expressed on the wire.
- EXPECT_EQ(2u, ack.ack_frame->received_packet_times.size());
-}
-
-TEST_P(QuicReceivedPacketManagerTest, UpdateReceivedConnectionStats) {
- EXPECT_FALSE(received_manager_.ack_frame_updated());
- RecordPacketReceipt(1, 0);
- EXPECT_TRUE(received_manager_.ack_frame_updated());
- RecordPacketReceipt(6, 0);
- RecordPacketReceipt(
- 2, 0, QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1)));
-
- EXPECT_EQ(4u, stats_.max_sequence_reordering);
- EXPECT_EQ(1000, stats_.max_time_reordering_us);
- EXPECT_EQ(1u, stats_.packets_reordered);
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_sent_entropy_manager.cc b/chromium/net/quic/quic_sent_entropy_manager.cc
deleted file mode 100644
index 7c76c5d8d72..00000000000
--- a/chromium/net/quic/quic_sent_entropy_manager.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_sent_entropy_manager.h"
-
-#include "base/logging.h"
-#include "net/base/linked_hash_map.h"
-
-using std::make_pair;
-using std::max;
-using std::min;
-
-namespace net {
-
-QuicSentEntropyManager::QuicSentEntropyManager() : map_offset_(1) {}
-
-QuicSentEntropyManager::~QuicSentEntropyManager() {}
-
-QuicPacketEntropyHash QuicSentEntropyManager::GetPacketEntropy(
- QuicPacketNumber packet_number) const {
- return packets_entropy_[packet_number - map_offset_];
-}
-
-QuicPacketNumber QuicSentEntropyManager::GetLargestPacketWithEntropy() const {
- return map_offset_ + packets_entropy_.size() - 1;
-}
-
-QuicPacketNumber QuicSentEntropyManager::GetSmallestPacketWithEntropy() const {
- return map_offset_;
-}
-
-void QuicSentEntropyManager::UpdateCumulativeEntropy(
- QuicPacketNumber packet_number,
- CumulativeEntropy* cumulative) const {
- while (cumulative->packet_number < packet_number) {
- ++cumulative->packet_number;
- cumulative->entropy ^= GetPacketEntropy(cumulative->packet_number);
- }
-}
-
-void QuicSentEntropyManager::RecordPacketEntropyHash(
- QuicPacketNumber packet_number,
- QuicPacketEntropyHash entropy_hash) {
- if (!packets_entropy_.empty()) {
- // Ensure packets always are recorded in order.
- // Every packet's entropy is recorded, even if it's not sent, so there
- // are not packet number gaps.
- DCHECK_EQ(GetLargestPacketWithEntropy() + 1, packet_number);
- }
- packets_entropy_.push_back(entropy_hash);
- DVLOG(2) << "Recorded packet number " << packet_number
- << " with entropy hash: " << static_cast<int>(entropy_hash);
-}
-
-QuicPacketEntropyHash QuicSentEntropyManager::GetCumulativeEntropy(
- QuicPacketNumber packet_number) {
- DCHECK_LE(last_cumulative_entropy_.packet_number, packet_number);
- DCHECK_GE(GetLargestPacketWithEntropy(), packet_number);
- // First the entropy for largest_observed packet number should be updated.
- UpdateCumulativeEntropy(packet_number, &last_cumulative_entropy_);
- return last_cumulative_entropy_.entropy;
-}
-
-bool QuicSentEntropyManager::IsValidEntropy(
- QuicPacketNumber largest_observed,
- const PacketNumberQueue& missing_packets,
- QuicPacketEntropyHash entropy_hash) {
- DCHECK_GE(largest_observed, last_valid_entropy_.packet_number);
- // Ensure the largest and smallest packet numbers are in range.
- if (largest_observed > GetLargestPacketWithEntropy()) {
- return false;
- }
- if (!missing_packets.Empty() &&
- missing_packets.Min() < GetSmallestPacketWithEntropy()) {
- return false;
- }
- // First the entropy for largest_observed packet number should be updated.
- UpdateCumulativeEntropy(largest_observed, &last_valid_entropy_);
-
- // Now XOR out all the missing entropies.
- QuicPacketEntropyHash expected_entropy_hash = last_valid_entropy_.entropy;
- for (QuicPacketNumber packet : missing_packets) {
- expected_entropy_hash ^= GetPacketEntropy(packet);
- }
- DLOG_IF(WARNING, entropy_hash != expected_entropy_hash)
- << "Invalid entropy hash: " << static_cast<int>(entropy_hash)
- << " expected entropy hash: " << static_cast<int>(expected_entropy_hash);
- return entropy_hash == expected_entropy_hash;
-}
-
-void QuicSentEntropyManager::ClearEntropyBefore(
- QuicPacketNumber packet_number) {
- // Don't discard entropy before updating the cumulative entropy used to
- // calculate EntropyHash and IsValidEntropy.
- if (last_cumulative_entropy_.packet_number < packet_number) {
- UpdateCumulativeEntropy(packet_number, &last_cumulative_entropy_);
- }
- if (last_valid_entropy_.packet_number < packet_number) {
- UpdateCumulativeEntropy(packet_number, &last_valid_entropy_);
- }
- while (map_offset_ < packet_number) {
- packets_entropy_.pop_front();
- ++map_offset_;
- }
- DVLOG(2) << "Cleared entropy before: " << packet_number;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_sent_entropy_manager.h b/chromium/net/quic/quic_sent_entropy_manager.h
deleted file mode 100644
index 9ea900562ea..00000000000
--- a/chromium/net/quic/quic_sent_entropy_manager.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2013 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.
-//
-// Manages the packet entropy calculation for both sent and received packets
-// for a connection.
-
-#ifndef NET_QUIC_QUIC_SENT_ENTROPY_MANAGER_H_
-#define NET_QUIC_QUIC_SENT_ENTROPY_MANAGER_H_
-
-#include <deque>
-
-#include "base/macros.h"
-#include "net/base/linked_hash_map.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-namespace test {
-class QuicConnectionPeer;
-} // namespace test
-
-// Records all sent packets by a connection to track the cumulative entropy of
-// sent packets. It is used by the connection to validate an ack
-// frame sent by the peer as a preventive measure against the optimistic ack
-// attack.
-class NET_EXPORT_PRIVATE QuicSentEntropyManager {
- public:
- QuicSentEntropyManager();
- virtual ~QuicSentEntropyManager();
-
- // Record |entropy_hash| for sent packet corresponding to |packet_number|.
- void RecordPacketEntropyHash(QuicPacketNumber packet_number,
- QuicPacketEntropyHash entropy_hash);
-
- // Retrieves the cumulative entropy up to |packet_number|.
- // Must always be called with a monotonically increasing |packet_number|.
- QuicPacketEntropyHash GetCumulativeEntropy(QuicPacketNumber packet_number);
-
- // Returns true if |entropy_hash| matches the expected sent entropy hash
- // up to |largest_observed| removing packet numbers from |missing_packets|.
- // Must always be called with a monotonically increasing |largest_observed|.
- bool IsValidEntropy(QuicPacketNumber largest_observed,
- const PacketNumberQueue& missing_packets,
- QuicPacketEntropyHash entropy_hash);
-
- // Removes unnecessary entries before |packet_number|.
- void ClearEntropyBefore(QuicPacketNumber packet_number);
-
- private:
- friend class test::QuicConnectionPeer;
-
- typedef std::deque<QuicPacketEntropyHash> SentEntropyMap;
-
- struct CumulativeEntropy {
- CumulativeEntropy() : packet_number(0), entropy(0) {}
-
- QuicPacketNumber packet_number;
- QuicPacketEntropyHash entropy;
- };
-
- // Convenience methods to get the largest and smallest packets with entropies.
- QuicPacketNumber GetLargestPacketWithEntropy() const;
- QuicPacketNumber GetSmallestPacketWithEntropy() const;
- // Convenience method to get the entropy hash for |packet_number|.
- QuicPacketEntropyHash GetPacketEntropy(QuicPacketNumber packet_number) const;
-
- // Update the cumulative entropy to |packet_number|.
- void UpdateCumulativeEntropy(QuicPacketNumber packet_number,
- CumulativeEntropy* cumulative) const;
-
- // Maps packet numbers to the sent entropy hash for the packet number.
- SentEntropyMap packets_entropy_;
- QuicPacketNumber map_offset_;
-
- // Cache the cumulative entropy for IsValidEntropy.
- CumulativeEntropy last_valid_entropy_;
-
- // Cache the cumulative entropy for the packet number used by EntropyHash.
- CumulativeEntropy last_cumulative_entropy_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicSentEntropyManager);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_SENT_ENTROPY_MANAGER_H_
diff --git a/chromium/net/quic/quic_sent_entropy_manager_test.cc b/chromium/net/quic/quic_sent_entropy_manager_test.cc
deleted file mode 100644
index a73185dcb0a..00000000000
--- a/chromium/net/quic/quic_sent_entropy_manager_test.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_sent_entropy_manager.h"
-
-#include <algorithm>
-#include <vector>
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::make_pair;
-using std::pair;
-
-namespace net {
-namespace test {
-namespace {
-
-class QuicSentEntropyManagerTest : public ::testing::Test {
- protected:
- QuicSentEntropyManager entropy_manager_;
-};
-
-TEST_F(QuicSentEntropyManagerTest, SentEntropyHash) {
- EXPECT_EQ(0, entropy_manager_.GetCumulativeEntropy(0));
-
- QuicPacketEntropyHash entropies[4] = {12, 1, 33, 3};
- for (size_t i = 0; i < arraysize(entropies); ++i) {
- entropy_manager_.RecordPacketEntropyHash(i + 1, entropies[i]);
- }
-
- QuicPacketEntropyHash hash = 0;
- for (size_t i = 0; i < arraysize(entropies); ++i) {
- hash ^= entropies[i];
- EXPECT_EQ(hash, entropy_manager_.GetCumulativeEntropy(i + 1));
- }
-}
-
-TEST_F(QuicSentEntropyManagerTest, IsValidEntropy) {
- QuicPacketEntropyHash entropies[10] = {12, 1, 33, 3, 32,
- 100, 28, 42, 22, 255};
- for (size_t i = 0; i < arraysize(entropies); ++i) {
- entropy_manager_.RecordPacketEntropyHash(i + 1, entropies[i]);
- }
-
- PacketNumberQueue missing_packets;
- missing_packets.Add(1);
- missing_packets.Add(4);
- missing_packets.Add(7, 9);
-
- QuicPacketEntropyHash entropy_hash = 0;
- for (size_t i = 0; i < arraysize(entropies); ++i) {
- if (!missing_packets.Contains(i + 1)) {
- entropy_hash ^= entropies[i];
- }
- }
-
- EXPECT_TRUE(
- entropy_manager_.IsValidEntropy(10, missing_packets, entropy_hash));
-}
-
-TEST_F(QuicSentEntropyManagerTest, ClearEntropiesBefore) {
- QuicPacketEntropyHash entropies[10] = {12, 1, 33, 3, 32,
- 100, 28, 42, 22, 255};
-
- for (size_t i = 0; i < arraysize(entropies); ++i) {
- entropy_manager_.RecordPacketEntropyHash(i + 1, entropies[i]);
- }
-
- // Discard the first 5 entropies and ensure IsValidEntropy and EntropyHash
- // still return correct results.
- entropy_manager_.ClearEntropyBefore(5);
-
- PacketNumberQueue missing_packets;
- missing_packets.Add(7, 9);
-
- QuicPacketEntropyHash entropy_hash = 0;
- for (size_t i = 0; i < arraysize(entropies); ++i) {
- if (!missing_packets.Contains(i + 1)) {
- entropy_hash ^= entropies[i];
- }
- }
- EXPECT_TRUE(
- entropy_manager_.IsValidEntropy(10, missing_packets, entropy_hash));
-
- entropy_hash = 0;
- for (size_t i = 0; i < arraysize(entropies); ++i) {
- entropy_hash ^= entropies[i];
- }
- EXPECT_EQ(entropy_hash, entropy_manager_.GetCumulativeEntropy(10));
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_sent_packet_manager.cc b/chromium/net/quic/quic_sent_packet_manager.cc
deleted file mode 100644
index f6851203765..00000000000
--- a/chromium/net/quic/quic_sent_packet_manager.cc
+++ /dev/null
@@ -1,1026 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_sent_packet_manager.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "net/quic/congestion_control/general_loss_algorithm.h"
-#include "net/quic/congestion_control/pacing_sender.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_connection_stats.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils_chromium.h"
-
-using std::max;
-using std::min;
-using std::pair;
-
-namespace net {
-
-namespace {
-static const int64_t kDefaultRetransmissionTimeMs = 500;
-static const int64_t kMaxRetransmissionTimeMs = 60000;
-// Maximum number of exponential backoffs used for RTO timeouts.
-static const size_t kMaxRetransmissions = 10;
-// Maximum number of packets retransmitted upon an RTO.
-static const size_t kMaxRetransmissionsOnTimeout = 2;
-// Minimum number of consecutive RTOs before path is considered to be degrading.
-const size_t kMinTimeoutsBeforePathDegrading = 2;
-
-// Ensure the handshake timer isnt't faster than 10ms.
-// This limits the tenth retransmitted packet to 10s after the initial CHLO.
-static const int64_t kMinHandshakeTimeoutMs = 10;
-
-// Sends up to two tail loss probes before firing an RTO,
-// per draft RFC draft-dukkipati-tcpm-tcp-loss-probe.
-static const size_t kDefaultMaxTailLossProbes = 2;
-
-// Number of unpaced packets to send after quiescence.
-static const size_t kInitialUnpacedBurst = 10;
-
-bool HasCryptoHandshake(const TransmissionInfo& transmission_info) {
- DCHECK(!transmission_info.has_crypto_handshake ||
- !transmission_info.retransmittable_frames.empty());
- return transmission_info.has_crypto_handshake;
-}
-
-} // namespace
-
-#define ENDPOINT \
- (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ")
-
-QuicSentPacketManager::QuicSentPacketManager(
- Perspective perspective,
- QuicPathId path_id,
- const QuicClock* clock,
- QuicConnectionStats* stats,
- CongestionControlType congestion_control_type,
- LossDetectionType loss_type,
- MultipathDelegateInterface* delegate)
- : unacked_packets_(),
- perspective_(perspective),
- path_id_(path_id),
- clock_(clock),
- stats_(stats),
- delegate_(delegate),
- debug_delegate_(nullptr),
- network_change_visitor_(nullptr),
- initial_congestion_window_(kInitialCongestionWindow),
- send_algorithm_(
- SendAlgorithmInterface::Create(clock,
- &rtt_stats_,
- congestion_control_type,
- stats,
- initial_congestion_window_)),
- loss_algorithm_(new GeneralLossAlgorithm(loss_type)),
- n_connection_simulation_(false),
- receive_buffer_bytes_(kDefaultSocketReceiveBuffer),
- least_packet_awaited_by_peer_(1),
- first_rto_transmission_(0),
- consecutive_rto_count_(0),
- consecutive_tlp_count_(0),
- consecutive_crypto_retransmission_count_(0),
- pending_timer_transmission_count_(0),
- max_tail_loss_probes_(kDefaultMaxTailLossProbes),
- enable_half_rtt_tail_loss_probe_(false),
- using_pacing_(false),
- use_new_rto_(false),
- undo_pending_retransmits_(false),
- largest_newly_acked_(0),
- largest_mtu_acked_(0),
- handshake_confirmed_(false) {}
-
-QuicSentPacketManager::~QuicSentPacketManager() {}
-
-void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
- if (config.HasReceivedInitialRoundTripTimeUs() &&
- config.ReceivedInitialRoundTripTimeUs() > 0) {
- rtt_stats_.set_initial_rtt_us(
- max(kMinInitialRoundTripTimeUs,
- min(kMaxInitialRoundTripTimeUs,
- config.ReceivedInitialRoundTripTimeUs())));
- } else if (config.HasInitialRoundTripTimeUsToSend() &&
- config.GetInitialRoundTripTimeUsToSend() > 0) {
- rtt_stats_.set_initial_rtt_us(
- max(kMinInitialRoundTripTimeUs,
- min(kMaxInitialRoundTripTimeUs,
- config.GetInitialRoundTripTimeUsToSend())));
- }
- // TODO(ianswett): BBR is currently a server only feature.
- if (FLAGS_quic_allow_bbr && config.HasReceivedConnectionOptions() &&
- ContainsQuicTag(config.ReceivedConnectionOptions(), kTBBR)) {
- send_algorithm_.reset(SendAlgorithmInterface::Create(
- clock_, &rtt_stats_, kBBR, stats_, initial_congestion_window_));
- }
- if (config.HasReceivedConnectionOptions() &&
- ContainsQuicTag(config.ReceivedConnectionOptions(), kRENO)) {
- if (ContainsQuicTag(config.ReceivedConnectionOptions(), kBYTE)) {
- send_algorithm_.reset(SendAlgorithmInterface::Create(
- clock_, &rtt_stats_, kRenoBytes, stats_, initial_congestion_window_));
- } else {
- send_algorithm_.reset(SendAlgorithmInterface::Create(
- clock_, &rtt_stats_, kReno, stats_, initial_congestion_window_));
- }
- } else if (config.HasReceivedConnectionOptions() &&
- ContainsQuicTag(config.ReceivedConnectionOptions(), kBYTE)) {
- send_algorithm_.reset(SendAlgorithmInterface::Create(
- clock_, &rtt_stats_, kCubicBytes, stats_, initial_congestion_window_));
- }
- if (!FLAGS_quic_disable_pacing_for_perf_tests) {
- EnablePacing();
- }
-
- if (config.HasClientSentConnectionOption(k1CON, perspective_)) {
- send_algorithm_->SetNumEmulatedConnections(1);
- }
- if (config.HasClientSentConnectionOption(kNCON, perspective_)) {
- n_connection_simulation_ = true;
- }
- if (config.HasClientSentConnectionOption(kNTLP, perspective_)) {
- max_tail_loss_probes_ = 0;
- }
- if (config.HasClientSentConnectionOption(kTLPR, perspective_)) {
- enable_half_rtt_tail_loss_probe_ = true;
- }
- if (config.HasClientSentConnectionOption(kNRTO, perspective_)) {
- use_new_rto_ = true;
- }
- if (config.HasReceivedConnectionOptions() &&
- ContainsQuicTag(config.ReceivedConnectionOptions(), kTIME)) {
- loss_algorithm_.reset(new GeneralLossAlgorithm(kTime));
- }
- if (config.HasReceivedConnectionOptions() &&
- ContainsQuicTag(config.ReceivedConnectionOptions(), kATIM)) {
- loss_algorithm_.reset(new GeneralLossAlgorithm(kAdaptiveTime));
- }
- if (FLAGS_quic_loss_recovery_use_largest_acked &&
- config.HasClientSentConnectionOption(kUNDO, perspective_)) {
- undo_pending_retransmits_ = true;
- }
- if (!FLAGS_quic_ignore_srbf && config.HasReceivedSocketReceiveBuffer()) {
- receive_buffer_bytes_ =
- max(kMinSocketReceiveBuffer,
- static_cast<QuicByteCount>(config.ReceivedSocketReceiveBuffer()));
- QuicByteCount max_cwnd_bytes = static_cast<QuicByteCount>(
- receive_buffer_bytes_ * kConservativeReceiveBufferFraction);
- send_algorithm_->SetMaxCongestionWindow(max_cwnd_bytes);
- }
- send_algorithm_->SetFromConfig(config, perspective_);
-
- if (network_change_visitor_ != nullptr) {
- network_change_visitor_->OnCongestionChange();
- }
-}
-
-void QuicSentPacketManager::ResumeConnectionState(
- const CachedNetworkParameters& cached_network_params,
- bool max_bandwidth_resumption) {
- if (cached_network_params.has_min_rtt_ms()) {
- uint32_t initial_rtt_us =
- kNumMicrosPerMilli * cached_network_params.min_rtt_ms();
- rtt_stats_.set_initial_rtt_us(
- max(kMinInitialRoundTripTimeUs,
- min(kMaxInitialRoundTripTimeUs, initial_rtt_us)));
- }
- send_algorithm_->ResumeConnectionState(cached_network_params,
- max_bandwidth_resumption);
-}
-
-void QuicSentPacketManager::SetNumOpenStreams(size_t num_streams) {
- if (n_connection_simulation_) {
- // Ensure the number of connections is between 1 and 5.
- send_algorithm_->SetNumEmulatedConnections(
- min<size_t>(5, max<size_t>(1, num_streams)));
- }
-}
-
-void QuicSentPacketManager::SetMaxPacingRate(QuicBandwidth max_pacing_rate) {
- if (using_pacing_) {
- static_cast<PacingSender*>(send_algorithm_.get())
- ->SetMaxPacingRate(max_pacing_rate);
- }
-}
-
-void QuicSentPacketManager::SetHandshakeConfirmed() {
- handshake_confirmed_ = true;
-}
-
-void QuicSentPacketManager::OnIncomingAck(const QuicAckFrame& ack_frame,
- QuicTime ack_receive_time) {
- DCHECK_LE(ack_frame.largest_observed, unacked_packets_.largest_sent_packet());
- QuicByteCount bytes_in_flight = unacked_packets_.bytes_in_flight();
- UpdatePacketInformationReceivedByPeer(ack_frame);
- bool rtt_updated = MaybeUpdateRTT(ack_frame, ack_receive_time);
- DCHECK_GE(ack_frame.largest_observed, unacked_packets_.largest_observed());
- unacked_packets_.IncreaseLargestObserved(ack_frame.largest_observed);
-
- HandleAckForSentPackets(ack_frame);
- InvokeLossDetection(ack_receive_time);
- // Ignore losses in RTO mode.
- if (consecutive_rto_count_ > 0 && !use_new_rto_) {
- packets_lost_.clear();
- }
- MaybeInvokeCongestionEvent(rtt_updated, bytes_in_flight);
- unacked_packets_.RemoveObsoletePackets();
-
- sustained_bandwidth_recorder_.RecordEstimate(
- send_algorithm_->InRecovery(), send_algorithm_->InSlowStart(),
- send_algorithm_->BandwidthEstimate(), ack_receive_time, clock_->WallNow(),
- rtt_stats_.smoothed_rtt());
-
- // Anytime we are making forward progress and have a new RTT estimate, reset
- // the backoff counters.
- if (rtt_updated) {
- if (consecutive_rto_count_ > 0) {
- // If the ack acknowledges data sent prior to the RTO,
- // the RTO was spurious.
- if (ack_frame.largest_observed < first_rto_transmission_) {
- // Replace SRTT with latest_rtt and increase the variance to prevent
- // a spurious RTO from happening again.
- rtt_stats_.ExpireSmoothedMetrics();
- } else {
- if (!use_new_rto_) {
- send_algorithm_->OnRetransmissionTimeout(true);
- }
- }
- }
- // Reset all retransmit counters any time a new packet is acked.
- consecutive_rto_count_ = 0;
- consecutive_tlp_count_ = 0;
- consecutive_crypto_retransmission_count_ = 0;
- }
- // TODO(ianswett): Consider replacing the pending_retransmissions_ with a
- // fast way to retrieve the next pending retransmission, if there are any.
- // A single packet number indicating all packets below that are lost should
- // be all the state that is necessary.
- while (undo_pending_retransmits_ && !pending_retransmissions_.empty() &&
- pending_retransmissions_.front().first > largest_newly_acked_ &&
- pending_retransmissions_.front().second == LOSS_RETRANSMISSION) {
- // Cancel any pending retransmissions larger than largest_newly_acked_.
- unacked_packets_.RestoreToInFlight(pending_retransmissions_.front().first);
- pending_retransmissions_.erase(pending_retransmissions_.begin());
- }
-
- if (debug_delegate_ != nullptr) {
- debug_delegate_->OnIncomingAck(ack_frame, ack_receive_time,
- unacked_packets_.largest_observed(),
- rtt_updated, GetLeastUnacked(path_id_));
- }
-}
-
-void QuicSentPacketManager::UpdatePacketInformationReceivedByPeer(
- const QuicAckFrame& ack_frame) {
- if (ack_frame.packets.Empty()) {
- least_packet_awaited_by_peer_ = ack_frame.largest_observed + 1;
- } else {
- least_packet_awaited_by_peer_ = ack_frame.packets.Min();
- }
-}
-
-void QuicSentPacketManager::MaybeInvokeCongestionEvent(
- bool rtt_updated,
- QuicByteCount bytes_in_flight) {
- if (!rtt_updated && packets_acked_.empty() && packets_lost_.empty()) {
- return;
- }
- send_algorithm_->OnCongestionEvent(rtt_updated, bytes_in_flight,
- packets_acked_, packets_lost_);
- packets_acked_.clear();
- packets_lost_.clear();
- if (network_change_visitor_ != nullptr) {
- network_change_visitor_->OnCongestionChange();
- }
-}
-
-void QuicSentPacketManager::HandleAckForSentPackets(
- const QuicAckFrame& ack_frame) {
- // Go through the packets we have not received an ack for and see if this
- // incoming_ack shows they've been seen by the peer.
- QuicTime::Delta ack_delay_time = ack_frame.ack_delay_time;
- QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
- for (QuicUnackedPacketMap::iterator it = unacked_packets_.begin();
- it != unacked_packets_.end(); ++it, ++packet_number) {
- if (packet_number > ack_frame.largest_observed) {
- // These packets are still in flight.
- break;
- }
-
- if ((ack_frame.missing && ack_frame.packets.Contains(packet_number)) ||
- (!ack_frame.missing && !ack_frame.packets.Contains(packet_number))) {
- // Packet is still missing.
- continue;
- }
- // Packet was acked, so remove it from our unacked packet list.
- DVLOG(1) << ENDPOINT << "Got an ack for packet " << packet_number;
- // If data is associated with the most recent transmission of this
- // packet, then inform the caller.
- if (it->in_flight) {
- packets_acked_.push_back(std::make_pair(packet_number, it->bytes_sent));
- } else if (FLAGS_quic_loss_recovery_use_largest_acked &&
- !it->is_unackable) {
- largest_newly_acked_ = packet_number;
- }
- MarkPacketHandled(packet_number, &(*it), ack_delay_time);
- }
-}
-
-bool QuicSentPacketManager::HasRetransmittableFrames(
- QuicPathId,
- QuicPacketNumber packet_number) const {
- return unacked_packets_.HasRetransmittableFrames(packet_number);
-}
-
-void QuicSentPacketManager::RetransmitUnackedPackets(
- TransmissionType retransmission_type) {
- DCHECK(retransmission_type == ALL_UNACKED_RETRANSMISSION ||
- retransmission_type == ALL_INITIAL_RETRANSMISSION);
- QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
- for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
- it != unacked_packets_.end(); ++it, ++packet_number) {
- if (!it->retransmittable_frames.empty() &&
- (retransmission_type == ALL_UNACKED_RETRANSMISSION ||
- it->encryption_level == ENCRYPTION_INITIAL)) {
- MarkForRetransmission(packet_number, retransmission_type);
- }
- }
-}
-
-void QuicSentPacketManager::NeuterUnencryptedPackets() {
- QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
- for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
- it != unacked_packets_.end(); ++it, ++packet_number) {
- if (!it->retransmittable_frames.empty() &&
- it->encryption_level == ENCRYPTION_NONE) {
- // Once you're forward secure, no unencrypted packets will be sent, crypto
- // or otherwise. Unencrypted packets are neutered and abandoned, to ensure
- // they are not retransmitted or considered lost from a congestion control
- // perspective.
- if (delegate_ != nullptr) {
- delegate_->OnUnencryptedPacketsNeutered(path_id_, packet_number);
- } else {
- pending_retransmissions_.erase(packet_number);
- }
- unacked_packets_.RemoveFromInFlight(packet_number);
- unacked_packets_.RemoveRetransmittability(packet_number);
- }
- }
-}
-
-void QuicSentPacketManager::MarkForRetransmission(
- QuicPacketNumber packet_number,
- TransmissionType transmission_type) {
- const TransmissionInfo& transmission_info =
- unacked_packets_.GetTransmissionInfo(packet_number);
- QUIC_BUG_IF(transmission_info.retransmittable_frames.empty());
- // Both TLP and the new RTO leave the packets in flight and let the loss
- // detection decide if packets are lost.
- if (transmission_type != TLP_RETRANSMISSION &&
- transmission_type != RTO_RETRANSMISSION) {
- unacked_packets_.RemoveFromInFlight(packet_number);
- }
- if (delegate_ != nullptr) {
- delegate_->OnRetransmissionMarked(path_id_, packet_number,
- transmission_type);
- } else {
- // TODO(ianswett): Currently the RTO can fire while there are pending NACK
- // retransmissions for the same data, which is not ideal.
- if (ContainsKey(pending_retransmissions_, packet_number)) {
- return;
- }
-
- pending_retransmissions_[packet_number] = transmission_type;
- }
-}
-
-void QuicSentPacketManager::RecordOneSpuriousRetransmission(
- const TransmissionInfo& info) {
- stats_->bytes_spuriously_retransmitted += info.bytes_sent;
- ++stats_->packets_spuriously_retransmitted;
- if (debug_delegate_ != nullptr) {
- debug_delegate_->OnSpuriousPacketRetransmission(info.transmission_type,
- info.bytes_sent);
- }
-}
-
-void QuicSentPacketManager::RecordSpuriousRetransmissions(
- const TransmissionInfo& info,
- QuicPacketNumber acked_packet_number) {
- QuicPacketNumber retransmission = info.retransmission;
- while (retransmission != 0) {
- const TransmissionInfo& retransmit_info =
- unacked_packets_.GetTransmissionInfo(retransmission);
- retransmission = retransmit_info.retransmission;
- RecordOneSpuriousRetransmission(retransmit_info);
- }
- // Only inform the loss detection of spurious retransmits it caused.
- if (unacked_packets_.GetTransmissionInfo(info.retransmission)
- .transmission_type == LOSS_RETRANSMISSION) {
- loss_algorithm_->SpuriousRetransmitDetected(
- unacked_packets_, clock_->Now(), rtt_stats_, info.retransmission);
- }
-}
-
-bool QuicSentPacketManager::HasPendingRetransmissions() const {
- return !pending_retransmissions_.empty();
-}
-
-PendingRetransmission QuicSentPacketManager::NextPendingRetransmission() {
- QUIC_BUG_IF(pending_retransmissions_.empty())
- << "Unexpected call to PendingRetransmissions() with empty pending "
- << "retransmission list. Corrupted memory usage imminent.";
- QuicPacketNumber packet_number = pending_retransmissions_.begin()->first;
- TransmissionType transmission_type = pending_retransmissions_.begin()->second;
- if (unacked_packets_.HasPendingCryptoPackets()) {
- // Ensure crypto packets are retransmitted before other packets.
- for (const auto& pair : pending_retransmissions_) {
- if (HasCryptoHandshake(
- unacked_packets_.GetTransmissionInfo(pair.first))) {
- packet_number = pair.first;
- transmission_type = pair.second;
- break;
- }
- }
- }
- DCHECK(unacked_packets_.IsUnacked(packet_number)) << packet_number;
- const TransmissionInfo& transmission_info =
- unacked_packets_.GetTransmissionInfo(packet_number);
- DCHECK(!transmission_info.retransmittable_frames.empty());
-
- return PendingRetransmission(path_id_, packet_number, transmission_type,
- transmission_info.retransmittable_frames,
- transmission_info.has_crypto_handshake,
- transmission_info.num_padding_bytes,
- transmission_info.encryption_level,
- transmission_info.packet_number_length);
-}
-
-QuicPacketNumber QuicSentPacketManager::GetNewestRetransmission(
- QuicPacketNumber packet_number,
- const TransmissionInfo& transmission_info) const {
- QuicPacketNumber retransmission = transmission_info.retransmission;
- while (retransmission != 0) {
- packet_number = retransmission;
- retransmission =
- unacked_packets_.GetTransmissionInfo(retransmission).retransmission;
- }
- return packet_number;
-}
-
-void QuicSentPacketManager::MarkPacketNotRetransmittable(
- QuicPacketNumber packet_number,
- QuicTime::Delta ack_delay_time) {
- if (!unacked_packets_.IsUnacked(packet_number)) {
- return;
- }
-
- const TransmissionInfo& transmission_info =
- unacked_packets_.GetTransmissionInfo(packet_number);
- QuicPacketNumber newest_transmission =
- GetNewestRetransmission(packet_number, transmission_info);
- // We do not need to retransmit this packet anymore.
- if (delegate_ != nullptr) {
- delegate_->OnPacketMarkedNotRetransmittable(path_id_, newest_transmission,
- ack_delay_time);
- } else {
- pending_retransmissions_.erase(newest_transmission);
- }
-
- unacked_packets_.NotifyAndClearListeners(newest_transmission, ack_delay_time);
- unacked_packets_.RemoveRetransmittability(packet_number);
-}
-
-void QuicSentPacketManager::MarkPacketHandled(QuicPacketNumber packet_number,
- TransmissionInfo* info,
- QuicTime::Delta ack_delay_time) {
- QuicPacketNumber newest_transmission =
- GetNewestRetransmission(packet_number, *info);
- // Remove the most recent packet, if it is pending retransmission.
- if (delegate_ != nullptr) {
- delegate_->OnPacketMarkedHandled(path_id_, newest_transmission,
- ack_delay_time);
- } else {
- pending_retransmissions_.erase(newest_transmission);
- }
-
- // The AckListener needs to be notified about the most recent
- // transmission, since that's the one only one it tracks.
- if (newest_transmission == packet_number) {
- unacked_packets_.NotifyAndClearListeners(&info->ack_listeners,
- ack_delay_time);
- } else {
- unacked_packets_.NotifyAndClearListeners(newest_transmission,
- ack_delay_time);
- RecordSpuriousRetransmissions(*info, packet_number);
- // Remove the most recent packet from flight if it's a crypto handshake
- // packet, since they won't be acked now that one has been processed.
- // Other crypto handshake packets won't be in flight, only the newest
- // transmission of a crypto packet is in flight at once.
- // TODO(ianswett): Instead of handling all crypto packets special,
- // only handle nullptr encrypted packets in a special way.
- const TransmissionInfo& newest_transmission_info =
- unacked_packets_.GetTransmissionInfo(newest_transmission);
- if (HasCryptoHandshake(newest_transmission_info)) {
- unacked_packets_.RemoveFromInFlight(newest_transmission);
- }
- }
-
- if (FLAGS_quic_no_mtu_discovery_ack_listener &&
- network_change_visitor_ != nullptr &&
- info->bytes_sent > largest_mtu_acked_) {
- largest_mtu_acked_ = info->bytes_sent;
- network_change_visitor_->OnPathMtuIncreased(largest_mtu_acked_);
- }
- unacked_packets_.RemoveFromInFlight(info);
- unacked_packets_.RemoveRetransmittability(info);
- if (FLAGS_quic_loss_recovery_use_largest_acked) {
- info->is_unackable = true;
- }
-}
-
-bool QuicSentPacketManager::IsUnacked(QuicPathId,
- QuicPacketNumber packet_number) const {
- return unacked_packets_.IsUnacked(packet_number);
-}
-
-bool QuicSentPacketManager::HasUnackedPackets() const {
- return unacked_packets_.HasUnackedPackets();
-}
-
-QuicPacketNumber QuicSentPacketManager::GetLeastUnacked(QuicPathId) const {
- return unacked_packets_.GetLeastUnacked();
-}
-
-bool QuicSentPacketManager::OnPacketSent(
- SerializedPacket* serialized_packet,
- QuicPathId /*original_path_id*/,
- QuicPacketNumber original_packet_number,
- QuicTime sent_time,
- TransmissionType transmission_type,
- HasRetransmittableData has_retransmittable_data) {
- QuicPacketNumber packet_number = serialized_packet->packet_number;
- DCHECK_LT(0u, packet_number);
- DCHECK(!unacked_packets_.IsUnacked(packet_number));
- QUIC_BUG_IF(serialized_packet->encrypted_length == 0)
- << "Cannot send empty packets.";
-
- if (delegate_ == nullptr && original_packet_number != 0) {
- if (!pending_retransmissions_.erase(original_packet_number) &&
- !FLAGS_quic_always_write_queued_retransmissions) {
- QUIC_BUG << "Expected packet number to be in "
- << "pending_retransmissions_. packet_number: "
- << original_packet_number;
- }
- }
-
- if (pending_timer_transmission_count_ > 0) {
- --pending_timer_transmission_count_;
- }
-
- // TODO(ianswett): Remove sent_time, because it's unused.
- const bool in_flight = send_algorithm_->OnPacketSent(
- sent_time, unacked_packets_.bytes_in_flight(), packet_number,
- serialized_packet->encrypted_length, has_retransmittable_data);
-
- unacked_packets_.AddSentPacket(serialized_packet, original_packet_number,
- transmission_type, sent_time, in_flight);
- // Reset the retransmission timer anytime a pending packet is sent.
- return in_flight;
-}
-
-void QuicSentPacketManager::OnRetransmissionTimeout() {
- DCHECK(unacked_packets_.HasInFlightPackets());
- DCHECK_EQ(0u, pending_timer_transmission_count_);
- // Handshake retransmission, timer based loss detection, TLP, and RTO are
- // implemented with a single alarm. The handshake alarm is set when the
- // handshake has not completed, the loss alarm is set when the loss detection
- // algorithm says to, and the TLP and RTO alarms are set after that.
- // The TLP alarm is always set to run for under an RTO.
- switch (GetRetransmissionMode()) {
- case HANDSHAKE_MODE:
- ++stats_->crypto_retransmit_count;
- RetransmitCryptoPackets();
- return;
- case LOSS_MODE: {
- ++stats_->loss_timeout_count;
- QuicByteCount bytes_in_flight = unacked_packets_.bytes_in_flight();
- InvokeLossDetection(clock_->Now());
- MaybeInvokeCongestionEvent(false, bytes_in_flight);
- return;
- }
- case TLP_MODE:
- // If no tail loss probe can be sent, because there are no retransmittable
- // packets, execute a conventional RTO to abandon old packets.
- ++stats_->tlp_count;
- ++consecutive_tlp_count_;
- pending_timer_transmission_count_ = 1;
- // TLPs prefer sending new data instead of retransmitting data, so
- // give the connection a chance to write before completing the TLP.
- return;
- case RTO_MODE:
- ++stats_->rto_count;
- RetransmitRtoPackets();
- if (network_change_visitor_ != nullptr &&
- consecutive_rto_count_ == kMinTimeoutsBeforePathDegrading) {
- network_change_visitor_->OnPathDegrading();
- }
- return;
- }
-}
-
-void QuicSentPacketManager::RetransmitCryptoPackets() {
- DCHECK_EQ(HANDSHAKE_MODE, GetRetransmissionMode());
- ++consecutive_crypto_retransmission_count_;
- bool packet_retransmitted = false;
- QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
- for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
- it != unacked_packets_.end(); ++it, ++packet_number) {
- // Only retransmit frames which are in flight, and therefore have been sent.
- if (!it->in_flight || it->retransmittable_frames.empty() ||
- !it->has_crypto_handshake) {
- continue;
- }
- packet_retransmitted = true;
- MarkForRetransmission(packet_number, HANDSHAKE_RETRANSMISSION);
- ++pending_timer_transmission_count_;
- }
- DCHECK(packet_retransmitted) << "No crypto packets found to retransmit.";
-}
-
-bool QuicSentPacketManager::MaybeRetransmitTailLossProbe() {
- if (pending_timer_transmission_count_ == 0) {
- return false;
- }
- QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
- for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
- it != unacked_packets_.end(); ++it, ++packet_number) {
- // Only retransmit frames which are in flight, and therefore have been sent.
- if (!it->in_flight || it->retransmittable_frames.empty()) {
- continue;
- }
- if (!handshake_confirmed_) {
- DCHECK(!it->has_crypto_handshake);
- }
- MarkForRetransmission(packet_number, TLP_RETRANSMISSION);
- return true;
- }
- DLOG(ERROR)
- << "No retransmittable packets, so RetransmitOldestPacket failed.";
- return false;
-}
-
-void QuicSentPacketManager::RetransmitRtoPackets() {
- QUIC_BUG_IF(pending_timer_transmission_count_ > 0)
- << "Retransmissions already queued:" << pending_timer_transmission_count_;
- // Mark two packets for retransmission.
- QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked();
- for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
- it != unacked_packets_.end(); ++it, ++packet_number) {
- if (!it->retransmittable_frames.empty() &&
- pending_timer_transmission_count_ < kMaxRetransmissionsOnTimeout) {
- MarkForRetransmission(packet_number, RTO_RETRANSMISSION);
- ++pending_timer_transmission_count_;
- }
- // Abandon non-retransmittable data that's in flight to ensure it doesn't
- // fill up the congestion window.
- const bool has_retransmissions = it->retransmission != 0;
- if (it->retransmittable_frames.empty() && it->in_flight &&
- !has_retransmissions) {
- // Log only for non-retransmittable data.
- // Retransmittable data is marked as lost during loss detection, and will
- // be logged later.
- unacked_packets_.RemoveFromInFlight(packet_number);
- if (debug_delegate_ != nullptr) {
- debug_delegate_->OnPacketLoss(packet_number, RTO_RETRANSMISSION,
- clock_->Now());
- }
- }
- }
- if (pending_timer_transmission_count_ > 0) {
- if (consecutive_rto_count_ == 0) {
- first_rto_transmission_ = unacked_packets_.largest_sent_packet() + 1;
- }
- ++consecutive_rto_count_;
- }
-}
-
-QuicSentPacketManager::RetransmissionTimeoutMode
-QuicSentPacketManager::GetRetransmissionMode() const {
- DCHECK(unacked_packets_.HasInFlightPackets());
- if (!handshake_confirmed_ && unacked_packets_.HasPendingCryptoPackets()) {
- return HANDSHAKE_MODE;
- }
- if (loss_algorithm_->GetLossTimeout() != QuicTime::Zero()) {
- return LOSS_MODE;
- }
- if (consecutive_tlp_count_ < max_tail_loss_probes_) {
- if (unacked_packets_.HasUnackedRetransmittableFrames()) {
- return TLP_MODE;
- }
- }
- return RTO_MODE;
-}
-
-void QuicSentPacketManager::InvokeLossDetection(QuicTime time) {
- if (FLAGS_quic_loss_recovery_use_largest_acked && !packets_acked_.empty()) {
- DCHECK_LE(packets_acked_.front().first, packets_acked_.back().first);
- largest_newly_acked_ = packets_acked_.back().first;
- }
- loss_algorithm_->DetectLosses(unacked_packets_, time, rtt_stats_,
- largest_newly_acked_, &packets_lost_);
- for (const pair<QuicPacketNumber, QuicByteCount>& pair : packets_lost_) {
- ++stats_->packets_lost;
- if (debug_delegate_ != nullptr) {
- debug_delegate_->OnPacketLoss(pair.first, LOSS_RETRANSMISSION, time);
- }
-
- // TODO(ianswett): This could be optimized.
- if (unacked_packets_.HasRetransmittableFrames(pair.first)) {
- MarkForRetransmission(pair.first, LOSS_RETRANSMISSION);
- } else {
- // Since we will not retransmit this, we need to remove it from
- // unacked_packets_. This is either the current transmission of
- // a packet whose previous transmission has been acked or a packet that
- // has been TLP retransmitted.
- unacked_packets_.RemoveFromInFlight(pair.first);
- }
- }
-}
-
-bool QuicSentPacketManager::MaybeUpdateRTT(const QuicAckFrame& ack_frame,
- QuicTime ack_receive_time) {
- // We rely on ack_delay_time to compute an RTT estimate, so we
- // only update rtt when the largest observed gets acked.
- // NOTE: If ack is a truncated ack, then the largest observed is in fact
- // unacked, and may cause an RTT sample to be taken.
- if (!unacked_packets_.IsUnacked(ack_frame.largest_observed)) {
- return false;
- }
- // We calculate the RTT based on the highest ACKed packet number, the lower
- // packet numbers will include the ACK aggregation delay.
- const TransmissionInfo& transmission_info =
- unacked_packets_.GetTransmissionInfo(ack_frame.largest_observed);
- // Ensure the packet has a valid sent time.
- if (transmission_info.sent_time == QuicTime::Zero()) {
- QUIC_BUG << "Acked packet has zero sent time, largest_observed:"
- << ack_frame.largest_observed;
- return false;
- }
-
- QuicTime::Delta send_delta =
- ack_receive_time.Subtract(transmission_info.sent_time);
- const int kMaxSendDeltaSeconds = 30;
- if (FLAGS_quic_socket_walltimestamps &&
- send_delta.ToSeconds() > kMaxSendDeltaSeconds) {
- // send_delta can be very high if local clock is changed mid-connection.
- LOG(WARNING) << "Excessive send delta: " << send_delta.ToSeconds()
- << ", setting to: " << kMaxSendDeltaSeconds;
- send_delta = QuicTime::Delta::FromSeconds(kMaxSendDeltaSeconds);
- }
- rtt_stats_.UpdateRtt(send_delta, ack_frame.ack_delay_time, ack_receive_time);
-
- return true;
-}
-
-QuicTime::Delta QuicSentPacketManager::TimeUntilSend(
- QuicTime now,
- HasRetransmittableData retransmittable,
- QuicPathId* path_id) {
- QuicTime::Delta delay = QuicTime::Delta::Infinite();
- // The TLP logic is entirely contained within QuicSentPacketManager, so the
- // send algorithm does not need to be consulted.
- if (pending_timer_transmission_count_ > 0) {
- delay = QuicTime::Delta::Zero();
- } else {
- delay =
- send_algorithm_->TimeUntilSend(now, unacked_packets_.bytes_in_flight());
- }
- if (!delay.IsInfinite()) {
- *path_id = path_id_;
- }
- return delay;
-}
-
-const QuicTime QuicSentPacketManager::GetRetransmissionTime() const {
- // Don't set the timer if there are no packets in flight or we've already
- // queued a tlp transmission and it hasn't been sent yet.
- if (!unacked_packets_.HasInFlightPackets() ||
- pending_timer_transmission_count_ > 0) {
- return QuicTime::Zero();
- }
- switch (GetRetransmissionMode()) {
- case HANDSHAKE_MODE:
- return clock_->ApproximateNow().Add(GetCryptoRetransmissionDelay());
- case LOSS_MODE:
- return loss_algorithm_->GetLossTimeout();
- case TLP_MODE: {
- // TODO(ianswett): When CWND is available, it would be preferable to
- // set the timer based on the earliest retransmittable packet.
- // Base the updated timer on the send time of the last packet.
- const QuicTime sent_time = unacked_packets_.GetLastPacketSentTime();
- const QuicTime tlp_time = sent_time.Add(GetTailLossProbeDelay());
- // Ensure the TLP timer never gets set to a time in the past.
- return QuicTime::Max(clock_->ApproximateNow(), tlp_time);
- }
- case RTO_MODE: {
- // The RTO is based on the first outstanding packet.
- const QuicTime sent_time = unacked_packets_.GetLastPacketSentTime();
- QuicTime rto_time = sent_time.Add(GetRetransmissionDelay());
- // Wait for TLP packets to be acked before an RTO fires.
- QuicTime tlp_time =
- unacked_packets_.GetLastPacketSentTime().Add(GetTailLossProbeDelay());
- return QuicTime::Max(tlp_time, rto_time);
- }
- }
- DCHECK(false);
- return QuicTime::Zero();
-}
-
-const QuicTime::Delta QuicSentPacketManager::GetCryptoRetransmissionDelay()
- const {
- // This is equivalent to the TailLossProbeDelay, but slightly more aggressive
- // because crypto handshake messages don't incur a delayed ack time.
- QuicTime::Delta srtt = rtt_stats_.smoothed_rtt();
- if (srtt.IsZero()) {
- srtt = QuicTime::Delta::FromMicroseconds(rtt_stats_.initial_rtt_us());
- }
- int64_t delay_ms = max(kMinHandshakeTimeoutMs,
- static_cast<int64_t>(1.5 * srtt.ToMilliseconds()));
- return QuicTime::Delta::FromMilliseconds(
- delay_ms << consecutive_crypto_retransmission_count_);
-}
-
-const QuicTime::Delta QuicSentPacketManager::GetTailLossProbeDelay() const {
- QuicTime::Delta srtt = rtt_stats_.smoothed_rtt();
- if (srtt.IsZero()) {
- srtt = QuicTime::Delta::FromMicroseconds(rtt_stats_.initial_rtt_us());
- }
- if (enable_half_rtt_tail_loss_probe_ && consecutive_tlp_count_ == 0u) {
- return QuicTime::Delta::FromMilliseconds(
- max(kMinTailLossProbeTimeoutMs,
- static_cast<int64_t>(0.5 * srtt.ToMilliseconds())));
- }
- if (!unacked_packets_.HasMultipleInFlightPackets()) {
- return QuicTime::Delta::Max(
- srtt.Multiply(2),
- srtt.Multiply(1.5).Add(
- QuicTime::Delta::FromMilliseconds(kMinRetransmissionTimeMs / 2)));
- }
- return QuicTime::Delta::FromMilliseconds(
- max(kMinTailLossProbeTimeoutMs,
- static_cast<int64_t>(2 * srtt.ToMilliseconds())));
-}
-
-const QuicTime::Delta QuicSentPacketManager::GetRetransmissionDelay() const {
- QuicTime::Delta retransmission_delay = send_algorithm_->RetransmissionDelay();
- if (retransmission_delay.IsZero()) {
- // We are in the initial state, use default timeout values.
- retransmission_delay =
- QuicTime::Delta::FromMilliseconds(kDefaultRetransmissionTimeMs);
- } else if (retransmission_delay.ToMilliseconds() < kMinRetransmissionTimeMs) {
- retransmission_delay =
- QuicTime::Delta::FromMilliseconds(kMinRetransmissionTimeMs);
- }
-
- // Calculate exponential back off.
- retransmission_delay = retransmission_delay.Multiply(
- 1 << min<size_t>(consecutive_rto_count_, kMaxRetransmissions));
-
- if (retransmission_delay.ToMilliseconds() > kMaxRetransmissionTimeMs) {
- return QuicTime::Delta::FromMilliseconds(kMaxRetransmissionTimeMs);
- }
- return retransmission_delay;
-}
-
-const RttStats* QuicSentPacketManager::GetRttStats() const {
- return &rtt_stats_;
-}
-
-QuicBandwidth QuicSentPacketManager::BandwidthEstimate() const {
- // TODO(ianswett): Remove BandwidthEstimate from SendAlgorithmInterface
- // and implement the logic here.
- return send_algorithm_->BandwidthEstimate();
-}
-
-const QuicSustainedBandwidthRecorder&
-QuicSentPacketManager::SustainedBandwidthRecorder() const {
- return sustained_bandwidth_recorder_;
-}
-
-QuicPacketCount QuicSentPacketManager::EstimateMaxPacketsInFlight(
- QuicByteCount max_packet_length) const {
- return send_algorithm_->GetCongestionWindow() / max_packet_length;
-}
-
-QuicPacketCount QuicSentPacketManager::GetCongestionWindowInTcpMss() const {
- return send_algorithm_->GetCongestionWindow() / kDefaultTCPMSS;
-}
-
-QuicByteCount QuicSentPacketManager::GetCongestionWindowInBytes() const {
- return send_algorithm_->GetCongestionWindow();
-}
-
-QuicPacketCount QuicSentPacketManager::GetSlowStartThresholdInTcpMss() const {
- return send_algorithm_->GetSlowStartThreshold() / kDefaultTCPMSS;
-}
-
-void QuicSentPacketManager::CancelRetransmissionsForStream(
- QuicStreamId stream_id) {
- unacked_packets_.CancelRetransmissionsForStream(stream_id);
- if (delegate_ != nullptr) {
- return;
- }
- PendingRetransmissionMap::iterator it = pending_retransmissions_.begin();
- while (it != pending_retransmissions_.end()) {
- if (HasRetransmittableFrames(path_id_, it->first)) {
- ++it;
- continue;
- }
- it = pending_retransmissions_.erase(it);
- }
-}
-
-void QuicSentPacketManager::EnablePacing() {
- // TODO(ianswett): Replace with a method which wraps the send algorithm in a
- // pacer every time a new algorithm is set.
- if (using_pacing_) {
- return;
- }
-
- // Set up a pacing sender with a 1 millisecond alarm granularity, the same as
- // the default granularity of the Linux kernel's FQ qdisc.
- using_pacing_ = true;
- send_algorithm_.reset(new PacingSender(send_algorithm_.release(),
- QuicTime::Delta::FromMilliseconds(1),
- kInitialUnpacedBurst));
-}
-
-void QuicSentPacketManager::OnConnectionMigration(QuicPathId,
- PeerAddressChangeType type) {
- if (type == PORT_CHANGE || type == IPV4_SUBNET_CHANGE) {
- // Rtt and cwnd do not need to be reset when the peer address change is
- // considered to be caused by NATs.
- return;
- }
- consecutive_rto_count_ = 0;
- consecutive_tlp_count_ = 0;
- rtt_stats_.OnConnectionMigration();
- send_algorithm_->OnConnectionMigration();
-}
-
-bool QuicSentPacketManager::IsHandshakeConfirmed() const {
- return handshake_confirmed_;
-}
-
-void QuicSentPacketManager::SetDebugDelegate(DebugDelegate* debug_delegate) {
- debug_delegate_ = debug_delegate;
-}
-
-QuicPacketNumber QuicSentPacketManager::GetLargestObserved(QuicPathId) const {
- return unacked_packets_.largest_observed();
-}
-
-QuicPacketNumber QuicSentPacketManager::GetLargestSentPacket(QuicPathId) const {
- return unacked_packets_.largest_sent_packet();
-}
-
-// Remove this method when deprecating QUIC_VERSION_33.
-QuicPacketNumber QuicSentPacketManager::GetLeastPacketAwaitedByPeer(
- QuicPathId) const {
- return least_packet_awaited_by_peer_;
-}
-
-void QuicSentPacketManager::SetNetworkChangeVisitor(
- NetworkChangeVisitor* visitor) {
- DCHECK(!network_change_visitor_);
- DCHECK(visitor);
- network_change_visitor_ = visitor;
-}
-
-bool QuicSentPacketManager::InSlowStart() const {
- return send_algorithm_->InSlowStart();
-}
-
-size_t QuicSentPacketManager::GetConsecutiveRtoCount() const {
- return consecutive_rto_count_;
-}
-
-size_t QuicSentPacketManager::GetConsecutiveTlpCount() const {
- return consecutive_tlp_count_;
-}
-
-TransmissionInfo* QuicSentPacketManager::GetMutableTransmissionInfo(
- QuicPacketNumber packet_number) {
- return unacked_packets_.GetMutableTransmissionInfo(packet_number);
-}
-
-void QuicSentPacketManager::RemoveObsoletePackets() {
- unacked_packets_.RemoveObsoletePackets();
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_sent_packet_manager.h b/chromium/net/quic/quic_sent_packet_manager.h
deleted file mode 100644
index 7243881dd02..00000000000
--- a/chromium/net/quic/quic_sent_packet_manager.h
+++ /dev/null
@@ -1,412 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_SENT_PACKET_MANAGER_H_
-#define NET_QUIC_QUIC_SENT_PACKET_MANAGER_H_
-
-#include <stddef.h>
-
-#include <map>
-#include <memory>
-#include <set>
-#include <utility>
-#include <vector>
-
-#include "base/macros.h"
-#include "net/base/linked_hash_map.h"
-#include "net/quic/congestion_control/loss_detection_interface.h"
-#include "net/quic/congestion_control/rtt_stats.h"
-#include "net/quic/congestion_control/send_algorithm_interface.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_sent_packet_manager_interface.h"
-#include "net/quic/quic_unacked_packet_map.h"
-
-namespace net {
-
-namespace test {
-class QuicConnectionPeer;
-class QuicSentPacketManagerPeer;
-} // namespace test
-
-class QuicClock;
-class QuicConfig;
-struct QuicConnectionStats;
-
-// Class which tracks the set of packets sent on a QUIC connection and contains
-// a send algorithm to decide when to send new packets. It keeps track of any
-// retransmittable data associated with each packet. If a packet is
-// retransmitted, it will keep track of each version of a packet so that if a
-// previous transmission is acked, the data will not be retransmitted.
-class NET_EXPORT_PRIVATE QuicSentPacketManager
- : public QuicSentPacketManagerInterface {
- public:
- // A delegate interface which manages pending retransmissions.
- class MultipathDelegateInterface {
- public:
- virtual ~MultipathDelegateInterface() {}
-
- // Called when unencrypted |packet_number| is requested to be neutered.
- virtual void OnUnencryptedPacketsNeutered(
- QuicPathId path_id,
- QuicPacketNumber packet_number) = 0;
- // Called when |packet_number| is requested to be retransmitted.
- virtual void OnRetransmissionMarked(QuicPathId path_id,
- QuicPacketNumber packet_number,
- TransmissionType transmission_type) = 0;
- // Called when |packet_number| is marked as not retransmittable.
- virtual void OnPacketMarkedNotRetransmittable(
- QuicPathId path_id,
- QuicPacketNumber packet_number,
- QuicTime::Delta delta_largest_observed) = 0;
- // Called when any transmission of |packet_number| is handled.
- virtual void OnPacketMarkedHandled(
- QuicPathId path_id,
- QuicPacketNumber packet_number,
- QuicTime::Delta delta_largest_observed) = 0;
- };
-
- QuicSentPacketManager(Perspective perspective,
- QuicPathId path_id,
- const QuicClock* clock,
- QuicConnectionStats* stats,
- CongestionControlType congestion_control_type,
- LossDetectionType loss_type,
- MultipathDelegateInterface* delegate);
- ~QuicSentPacketManager() override;
-
- // Start implementation of QuicSentPacketManagerInterface.
- void SetFromConfig(const QuicConfig& config) override;
-
- // Pass the CachedNetworkParameters to the send algorithm.
- void ResumeConnectionState(
- const CachedNetworkParameters& cached_network_params,
- bool max_bandwidth_resumption) override;
-
- void SetNumOpenStreams(size_t num_streams) override;
-
- void SetMaxPacingRate(QuicBandwidth max_pacing_rate) override;
-
- void SetHandshakeConfirmed() override;
-
- // Processes the incoming ack.
- void OnIncomingAck(const QuicAckFrame& ack_frame,
- QuicTime ack_receive_time) override;
-
- // Returns true if packet |packet_number| is unacked.
- bool IsUnacked(QuicPathId, QuicPacketNumber packet_number) const override;
-
- // Requests retransmission of all unacked packets of |retransmission_type|.
- // The behavior of this method depends on the value of |retransmission_type|:
- // ALL_UNACKED_RETRANSMISSION - All unacked packets will be retransmitted.
- // This can happen, for example, after a version negotiation packet has been
- // received and all packets needs to be retransmitted with the new version.
- // ALL_INITIAL_RETRANSMISSION - Only initially encrypted packets will be
- // retransmitted. This can happen, for example, when a CHLO has been rejected
- // and the previously encrypted data needs to be encrypted with a new key.
- void RetransmitUnackedPackets(TransmissionType retransmission_type) override;
-
- // Retransmits the oldest pending packet there is still a tail loss probe
- // pending. Invoked after OnRetransmissionTimeout.
- bool MaybeRetransmitTailLossProbe() override;
-
- // Removes the retransmittable frames from all unencrypted packets to ensure
- // they don't get retransmitted.
- void NeuterUnencryptedPackets() override;
-
- // Returns true if the unacked packet |packet_number| has retransmittable
- // frames. This will only return false if the packet has been acked, if a
- // previous transmission of this packet was ACK'd, or if this packet has been
- // retransmitted as with different packet number.
- bool HasRetransmittableFrames(QuicPathId,
- QuicPacketNumber packet_number) const override;
-
- // Returns true if there are pending retransmissions.
- // Not const because retransmissions may be cancelled before returning.
- bool HasPendingRetransmissions() const override;
-
- // Retrieves the next pending retransmission. You must ensure that
- // there are pending retransmissions prior to calling this function.
- PendingRetransmission NextPendingRetransmission() override;
-
- bool HasUnackedPackets() const override;
-
- // Returns the smallest packet number of a serialized packet which has not
- // been acked by the peer.
- QuicPacketNumber GetLeastUnacked(QuicPathId) const override;
-
- // Called when we have sent bytes to the peer. This informs the manager both
- // the number of bytes sent and if they were retransmitted. Returns true if
- // the sender should reset the retransmission timer.
- bool OnPacketSent(SerializedPacket* serialized_packet,
- QuicPathId /*original_path_id*/,
- QuicPacketNumber original_packet_number,
- QuicTime sent_time,
- TransmissionType transmission_type,
- HasRetransmittableData has_retransmittable_data) override;
-
- // Called when the retransmission timer expires.
- void OnRetransmissionTimeout() override;
-
- // Calculate the time until we can send the next packet to the wire.
- // Note 1: When kUnknownWaitTime is returned, there is no need to poll
- // TimeUntilSend again until we receive an OnIncomingAckFrame event.
- // Note 2: Send algorithms may or may not use |retransmit| in their
- // calculations.
- QuicTime::Delta TimeUntilSend(QuicTime now,
- HasRetransmittableData retransmittable,
- QuicPathId* path_id) override;
-
- // Returns the current delay for the retransmission timer, which may send
- // either a tail loss probe or do a full RTO. Returns QuicTime::Zero() if
- // there are no retransmittable packets.
- const QuicTime GetRetransmissionTime() const override;
-
- const RttStats* GetRttStats() const override;
-
- // Returns the estimated bandwidth calculated by the congestion algorithm.
- QuicBandwidth BandwidthEstimate() const override;
-
- const QuicSustainedBandwidthRecorder& SustainedBandwidthRecorder()
- const override;
-
- // Returns the size of the current congestion window in number of
- // kDefaultTCPMSS-sized segments. Note, this is not the *available* window.
- // Some send algorithms may not use a congestion window and will return 0.
- QuicPacketCount GetCongestionWindowInTcpMss() const override;
-
- // Returns the number of packets of length |max_packet_length| which fit in
- // the current congestion window. More packets may end up in flight if the
- // congestion window has been recently reduced, of if non-full packets are
- // sent.
- QuicPacketCount EstimateMaxPacketsInFlight(
- QuicByteCount max_packet_length) const override;
-
- // Returns the size of the current congestion window size in bytes.
- QuicByteCount GetCongestionWindowInBytes() const override;
-
- // Returns the size of the slow start congestion window in nume of 1460 byte
- // TCP segments, aka ssthresh. Some send algorithms do not define a slow
- // start threshold and will return 0.
- QuicPacketCount GetSlowStartThresholdInTcpMss() const override;
-
- // No longer retransmit data for |stream_id|.
- void CancelRetransmissionsForStream(QuicStreamId stream_id) override;
-
- // Called when peer address changes and the connection migrates.
- void OnConnectionMigration(QuicPathId, PeerAddressChangeType type) override;
-
- bool IsHandshakeConfirmed() const override;
-
- void SetDebugDelegate(DebugDelegate* debug_delegate) override;
-
- QuicPacketNumber GetLargestObserved(QuicPathId) const override;
-
- QuicPacketNumber GetLargestSentPacket(QuicPathId) const override;
-
- QuicPacketNumber GetLeastPacketAwaitedByPeer(QuicPathId) const override;
-
- void SetNetworkChangeVisitor(NetworkChangeVisitor* visitor) override;
-
- bool InSlowStart() const override;
-
- size_t GetConsecutiveRtoCount() const override;
-
- size_t GetConsecutiveTlpCount() const override;
-
- private:
- friend class test::QuicConnectionPeer;
- friend class test::QuicSentPacketManagerPeer;
-
- // The retransmission timer is a single timer which switches modes depending
- // upon connection state.
- enum RetransmissionTimeoutMode {
- // A conventional TCP style RTO.
- RTO_MODE,
- // A tail loss probe. By default, QUIC sends up to two before RTOing.
- TLP_MODE,
- // Retransmission of handshake packets prior to handshake completion.
- HANDSHAKE_MODE,
- // Re-invoke the loss detection when a packet is not acked before the
- // loss detection algorithm expects.
- LOSS_MODE,
- };
-
- typedef linked_hash_map<QuicPacketNumber, TransmissionType>
- PendingRetransmissionMap;
-
- // Updates the least_packet_awaited_by_peer.
- void UpdatePacketInformationReceivedByPeer(const QuicAckFrame& ack_frame);
-
- // Process the incoming ack looking for newly ack'd data packets.
- void HandleAckForSentPackets(const QuicAckFrame& ack_frame);
-
- // Returns the current retransmission mode.
- RetransmissionTimeoutMode GetRetransmissionMode() const;
-
- // Retransmits all crypto stream packets.
- void RetransmitCryptoPackets();
-
- // Retransmits two packets for an RTO and removes any non-retransmittable
- // packets from flight.
- void RetransmitRtoPackets();
-
- // Returns the timer for retransmitting crypto handshake packets.
- const QuicTime::Delta GetCryptoRetransmissionDelay() const;
-
- // Returns the timer for a new tail loss probe.
- const QuicTime::Delta GetTailLossProbeDelay() const;
-
- // Returns the retransmission timeout, after which a full RTO occurs.
- const QuicTime::Delta GetRetransmissionDelay() const;
-
- // Returns the newest transmission associated with a packet.
- QuicPacketNumber GetNewestRetransmission(
- QuicPacketNumber packet_number,
- const TransmissionInfo& transmission_info) const;
-
- // Update the RTT if the ack is for the largest acked packet number.
- // Returns true if the rtt was updated.
- bool MaybeUpdateRTT(const QuicAckFrame& ack_frame, QuicTime ack_receive_time);
-
- // Invokes the loss detection algorithm and loses and retransmits packets if
- // necessary.
- void InvokeLossDetection(QuicTime time);
-
- // Invokes OnCongestionEvent if |rtt_updated| is true, there are pending acks,
- // or pending losses. Clears pending acks and pending losses afterwards.
- // |bytes_in_flight| is the number of bytes in flight before the losses or
- // acks.
- void MaybeInvokeCongestionEvent(bool rtt_updated,
- QuicByteCount bytes_in_flight);
-
- // Called when frames of |packet_number| has been received but the packet
- // itself has not been received by the peer. Currently, this method is not
- // used.
- // TODO(fayang): Update the comment when multipath sent packet manager is
- // landed.
- // The packet needs no longer to be retransmitted, but the packet remains
- // pending if it is and the congestion control does not consider the packet
- // acked.
- void MarkPacketNotRetransmittable(QuicPacketNumber packet_number,
- QuicTime::Delta ack_delay_time);
-
- // Removes the retransmittability and in flight properties from the packet at
- // |info| due to receipt by the peer.
- void MarkPacketHandled(QuicPacketNumber packet_number,
- TransmissionInfo* info,
- QuicTime::Delta ack_delay_time);
-
- // Request that |packet_number| be retransmitted after the other pending
- // retransmissions. Does not add it to the retransmissions if it's already
- // a pending retransmission.
- void MarkForRetransmission(QuicPacketNumber packet_number,
- TransmissionType transmission_type);
-
- // Notify observers that packet with TransmissionInfo |info| is a spurious
- // retransmission. It is caller's responsibility to guarantee the packet with
- // TransmissionInfo |info| is a spurious retransmission before calling this
- // function.
- void RecordOneSpuriousRetransmission(const TransmissionInfo& info);
-
- // Notify observers about spurious retransmits of packet with TransmissionInfo
- // |info|.
- void RecordSpuriousRetransmissions(const TransmissionInfo& info,
- QuicPacketNumber acked_packet_number);
-
- // Returns mutable TransmissionInfo associated with |packet_number|, which
- // must be unacked.
- TransmissionInfo* GetMutableTransmissionInfo(QuicPacketNumber packet_number);
-
- // Remove any packets no longer needed for retransmission, congestion, or
- // RTT measurement purposes.
- void RemoveObsoletePackets();
-
- // Enables pacing if it has not already been enabled.
- void EnablePacing();
-
- // Newly serialized retransmittable packets are added to this map, which
- // contains owning pointers to any contained frames. If a packet is
- // retransmitted, this map will contain entries for both the old and the new
- // packet. The old packet's retransmittable frames entry will be nullptr,
- // while the new packet's entry will contain the frames to retransmit.
- // If the old packet is acked before the new packet, then the old entry will
- // be removed from the map and the new entry's retransmittable frames will be
- // set to nullptr.
- QuicUnackedPacketMap unacked_packets_;
-
- // Pending retransmissions which have not been packetized and sent yet.
- PendingRetransmissionMap pending_retransmissions_;
-
- // Tracks if the connection was created by the server or the client.
- Perspective perspective_;
-
- QuicPathId path_id_;
-
- const QuicClock* clock_;
- QuicConnectionStats* stats_;
-
- // Pending retransmissions are managed by delegate_ if it is not null.
- MultipathDelegateInterface* delegate_; // Not owned.
-
- DebugDelegate* debug_delegate_;
- NetworkChangeVisitor* network_change_visitor_;
- const QuicPacketCount initial_congestion_window_;
- RttStats rtt_stats_;
- std::unique_ptr<SendAlgorithmInterface> send_algorithm_;
- std::unique_ptr<LossDetectionInterface> loss_algorithm_;
- bool n_connection_simulation_;
-
- // Receiver side buffer in bytes.
- QuicByteCount receive_buffer_bytes_;
-
- // Least packet number which the peer is still waiting for.
- QuicPacketNumber least_packet_awaited_by_peer_;
-
- // Tracks the first RTO packet. If any packet before that packet gets acked,
- // it indicates the RTO was spurious and should be reversed(F-RTO).
- QuicPacketNumber first_rto_transmission_;
- // Number of times the RTO timer has fired in a row without receiving an ack.
- size_t consecutive_rto_count_;
- // Number of times the tail loss probe has been sent.
- size_t consecutive_tlp_count_;
- // Number of times the crypto handshake has been retransmitted.
- size_t consecutive_crypto_retransmission_count_;
- // Number of pending transmissions of TLP, RTO, or crypto packets.
- size_t pending_timer_transmission_count_;
- // Maximum number of tail loss probes to send before firing an RTO.
- size_t max_tail_loss_probes_;
- // If true, send the TLP at 0.5 RTT.
- bool enable_half_rtt_tail_loss_probe_;
- bool using_pacing_;
- // If true, use the new RTO with loss based CWND reduction instead of the send
- // algorithms's OnRetransmissionTimeout to reduce the congestion window.
- bool use_new_rto_;
- // If true, cancel pending retransmissions if they're larger than
- // largest_newly_acked.
- bool undo_pending_retransmits_;
-
- // Vectors packets acked and lost as a result of the last congestion event.
- SendAlgorithmInterface::CongestionVector packets_acked_;
- SendAlgorithmInterface::CongestionVector packets_lost_;
- // Largest newly acknowledged packet.
- QuicPacketNumber largest_newly_acked_;
- // Largest packet in bytes ever acknowledged.
- QuicPacketLength largest_mtu_acked_;
-
- // Set to true after the crypto handshake has successfully completed. After
- // this is true we no longer use HANDSHAKE_MODE, and further frames sent on
- // the crypto stream (i.e. SCUP messages) are treated like normal
- // retransmittable frames.
- bool handshake_confirmed_;
-
- // Records bandwidth from server to client in normal operation, over periods
- // of time with no loss events.
- QuicSustainedBandwidthRecorder sustained_bandwidth_recorder_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicSentPacketManager);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_SENT_PACKET_MANAGER_H_
diff --git a/chromium/net/quic/quic_sent_packet_manager_interface.h b/chromium/net/quic/quic_sent_packet_manager_interface.h
deleted file mode 100644
index e60f8ef24b9..00000000000
--- a/chromium/net/quic/quic_sent_packet_manager_interface.h
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_SENT_PACKET_MANAGER_INTERFACE_H_
-#define NET_QUIC_QUIC_SENT_PACKET_MANAGER_INTERFACE_H_
-
-#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_sustained_bandwidth_recorder.h"
-
-namespace net {
-
-class QuicConfig;
-class RttStats;
-
-class NET_EXPORT_PRIVATE QuicSentPacketManagerInterface {
- public:
- // Interface which gets callbacks from the QuicSentPacketManager at
- // interesting points. Implementations must not mutate the state of
- // the packet manager or connection as a result of these callbacks.
- class NET_EXPORT_PRIVATE DebugDelegate {
- public:
- virtual ~DebugDelegate() {}
-
- // Called when a spurious retransmission is detected.
- virtual void OnSpuriousPacketRetransmission(
- TransmissionType transmission_type,
- QuicByteCount byte_size) {}
-
- virtual void OnIncomingAck(const QuicAckFrame& ack_frame,
- QuicTime ack_receive_time,
- QuicPacketNumber largest_observed,
- bool rtt_updated,
- QuicPacketNumber least_unacked_sent_packet) {}
-
- virtual void OnPacketLoss(QuicPacketNumber lost_packet_number,
- TransmissionType transmission_type,
- QuicTime detection_time) {}
- };
-
- // Interface which gets callbacks from the QuicSentPacketManager when
- // network-related state changes. Implementations must not mutate the
- // state of the packet manager as a result of these callbacks.
- class NET_EXPORT_PRIVATE NetworkChangeVisitor {
- public:
- virtual ~NetworkChangeVisitor() {}
-
- // Called when congestion window or RTT may have changed.
- virtual void OnCongestionChange() = 0;
-
- // Called with the path may be degrading. Note that the path may only be
- // temporarily degrading.
- // TODO(jri): With multipath, this method should probably have a path_id
- // parameter, and should maybe result in the path being marked as inactive.
- virtual void OnPathDegrading() = 0;
-
- // Called when the Path MTU may have increased.
- virtual void OnPathMtuIncreased(QuicPacketLength packet_size) = 0;
- };
-
- virtual ~QuicSentPacketManagerInterface() {}
-
- virtual void SetFromConfig(const QuicConfig& config) = 0;
-
- // Resumes connection state on the default path.
- virtual void ResumeConnectionState(
- const CachedNetworkParameters& cached_network_params,
- bool max_bandwidth_resumption) = 0;
-
- // Sets number of active streams of all paths.
- virtual void SetNumOpenStreams(size_t num_streams) = 0;
-
- // Sets max pacing rate of the default path.
- virtual void SetMaxPacingRate(QuicBandwidth max_pacing_rate) = 0;
-
- // Indicates the handshake has completed, so no handshake packets need to be
- // retransmitted.
- virtual void SetHandshakeConfirmed() = 0;
-
- virtual void OnIncomingAck(const QuicAckFrame& ack_frame,
- QuicTime ack_receive_time) = 0;
-
- virtual bool IsUnacked(QuicPathId path_id,
- QuicPacketNumber packet_number) const = 0;
-
- virtual bool HasRetransmittableFrames(
- QuicPathId path_id,
- QuicPacketNumber packet_number) const = 0;
-
- // Requests retransmission of all unacked packets of |retransmission_type| on
- // the default path.
- virtual void RetransmitUnackedPackets(
- TransmissionType retransmission_type) = 0;
-
- // Retransmits the oldest pending packet on the path (on which retransmission
- // alarm fires) if there is still a tail loss probe pending. Invoked after
- // OnRetransmissionTimeout.
- virtual bool MaybeRetransmitTailLossProbe() = 0;
-
- // Removes the retransmittable frames from all unencrypted packets on the
- // default path to ensure they don't get retransmitted.
- virtual void NeuterUnencryptedPackets() = 0;
-
- virtual bool HasPendingRetransmissions() const = 0;
-
- virtual PendingRetransmission NextPendingRetransmission() = 0;
-
- // Returns true if the default path has unacked packets.
- virtual bool HasUnackedPackets() const = 0;
-
- virtual QuicPacketNumber GetLeastUnacked(QuicPathId path_id) const = 0;
-
- virtual bool OnPacketSent(
- SerializedPacket* serialized_packet,
- QuicPathId original_path_id,
- QuicPacketNumber original_packet_number,
- QuicTime sent_time,
- TransmissionType transmission_type,
- HasRetransmittableData has_retransmittable_data) = 0;
-
- virtual void OnRetransmissionTimeout() = 0;
-
- // Returns the earliest time we can send the next packet. Sets |path_id| to be
- // the path on which the next packet will be sent.
- virtual QuicTime::Delta TimeUntilSend(QuicTime now,
- HasRetransmittableData retransmittable,
- QuicPathId* path_id) = 0;
-
- // Returns the earliest retransmission time of all paths.
- // TODO(fayang): This method should not be const becasue the return value
- // depends upon the time it is invoked.
- virtual const QuicTime GetRetransmissionTime() const = 0;
-
- // Returns the rtt stats of the default path.
- virtual const RttStats* GetRttStats() const = 0;
-
- // Returns the estimated bandwidth on default path calculated by the
- // congestion algorithm.
- virtual QuicBandwidth BandwidthEstimate() const = 0;
-
- // Returns the sustained bandwidth recorder on the default path.
- virtual const QuicSustainedBandwidthRecorder& SustainedBandwidthRecorder()
- const = 0;
-
- // Returns the size of the current congestion window on default path in number
- // of kDefaultTCPMSS-sized segments.
- virtual QuicPacketCount GetCongestionWindowInTcpMss() const = 0;
-
- // Determines the number of packets of length |max_packet_length| which fit in
- // the congestion windows for all paths, and returns the max number of packets
- // across all paths.
- virtual QuicPacketCount EstimateMaxPacketsInFlight(
- QuicByteCount max_packet_length) const = 0;
-
- // Returns the size of the current congestion window size on the default path
- // in bytes.
- virtual QuicByteCount GetCongestionWindowInBytes() const = 0;
-
- // Returns the size of the slow start congestion window in number of 1460 byte
- // TCP segments on the default path.
- virtual QuicPacketCount GetSlowStartThresholdInTcpMss() const = 0;
-
- // No longer retransmit data for |stream_id| on all paths.
- virtual void CancelRetransmissionsForStream(QuicStreamId stream_id) = 0;
-
- // Called when peer address changes and the connection migrates on |path_id|.
- // TODO(fayang): Name of this method is confusing in multipath world because
- // this migration is path level. Need to rename this as OnPeerMigration.
- virtual void OnConnectionMigration(QuicPathId path_id,
- PeerAddressChangeType type) = 0;
-
- virtual bool IsHandshakeConfirmed() const = 0;
-
- virtual void SetDebugDelegate(DebugDelegate* debug_delegate) = 0;
-
- virtual QuicPacketNumber GetLargestObserved(QuicPathId path_id) const = 0;
-
- virtual QuicPacketNumber GetLargestSentPacket(QuicPathId path_id) const = 0;
-
- virtual QuicPacketNumber GetLeastPacketAwaitedByPeer(
- QuicPathId path_id) const = 0;
-
- virtual void SetNetworkChangeVisitor(NetworkChangeVisitor* visitor) = 0;
-
- // Returns true if the default path is in slow start.
- virtual bool InSlowStart() const = 0;
-
- // These two methods return the consecutive RTO or TLP count of the default
- // path.
- virtual size_t GetConsecutiveRtoCount() const = 0;
- virtual size_t GetConsecutiveTlpCount() const = 0;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_SENT_PACKET_MANAGER_INTERFACE_H_
diff --git a/chromium/net/quic/quic_sent_packet_manager_test.cc b/chromium/net/quic/quic_sent_packet_manager_test.cc
deleted file mode 100644
index 45cd30bf9d3..00000000000
--- a/chromium/net/quic/quic_sent_packet_manager_test.cc
+++ /dev/null
@@ -1,1801 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_sent_packet_manager.h"
-
-#include <memory>
-
-#include "base/stl_util.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/test_tools/quic_config_peer.h"
-#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::vector;
-using testing::AnyNumber;
-using testing::ElementsAre;
-using testing::IsEmpty;
-using testing::Not;
-using testing::Pair;
-using testing::Pointwise;
-using testing::Return;
-using testing::SetArgPointee;
-using testing::StrictMock;
-using testing::_;
-
-namespace net {
-namespace test {
-namespace {
-
-// Default packet length.
-const uint32_t kDefaultLength = 1000;
-
-// Stream ID for data sent in CreatePacket().
-const QuicStreamId kStreamId = 7;
-
-// Minimum number of consecutive RTOs before path is considered to be degrading.
-const size_t kMinTimeoutsBeforePathDegrading = 2;
-
-// Matcher to check the key of the key-value pair it receives as first argument
-// equals its second argument.
-MATCHER(KeyEq, "") {
- return std::tr1::get<0>(arg).first == std::tr1::get<1>(arg);
-}
-
-class MockDebugDelegate : public QuicSentPacketManagerInterface::DebugDelegate {
- public:
- MOCK_METHOD2(OnSpuriousPacketRetransmission,
- void(TransmissionType transmission_type,
- QuicByteCount byte_size));
- MOCK_METHOD3(OnPacketLoss,
- void(QuicPacketNumber lost_packet_number,
- TransmissionType transmission_type,
- QuicTime detection_time));
-};
-
-// Run tests with different ack frame packets set mode.
-struct TestParams {
- explicit TestParams(bool missing) : missing(missing) {}
-
- friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
- os << "{ ack frame packets set mode: " << p.missing << " }";
- return os;
- }
-
- bool missing;
-};
-
-vector<TestParams> GetTestParams() {
- vector<TestParams> params;
- for (bool missing : {true, false}) {
- params.push_back(TestParams(missing));
- }
- return params;
-}
-
-class QuicSentPacketManagerTest : public ::testing::TestWithParam<TestParams> {
- protected:
- QuicSentPacketManagerTest()
- : manager_(Perspective::IS_SERVER,
- kDefaultPathId,
- &clock_,
- &stats_,
- kCubic,
- kNack,
- /*delegate=*/nullptr),
- send_algorithm_(new StrictMock<MockSendAlgorithm>),
- network_change_visitor_(new StrictMock<MockNetworkChangeVisitor>) {
- QuicSentPacketManagerPeer::SetSendAlgorithm(&manager_, send_algorithm_);
- // Disable tail loss probes for most tests.
- QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 0);
- // Advance the time 1s so the send times are never QuicTime::Zero.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000));
- manager_.SetNetworkChangeVisitor(network_change_visitor_.get());
-
- EXPECT_CALL(*send_algorithm_, HasReliableBandwidthEstimate())
- .Times(AnyNumber());
- EXPECT_CALL(*send_algorithm_, BandwidthEstimate())
- .Times(AnyNumber())
- .WillRepeatedly(Return(QuicBandwidth::Zero()));
- EXPECT_CALL(*send_algorithm_, InSlowStart()).Times(AnyNumber());
- EXPECT_CALL(*send_algorithm_, InRecovery()).Times(AnyNumber());
- EXPECT_CALL(*network_change_visitor_, OnPathMtuIncreased(1000))
- .Times(AnyNumber());
- }
-
- ~QuicSentPacketManagerTest() override {
- STLDeleteElements(&packets_);
- }
-
- QuicByteCount BytesInFlight() {
- return QuicSentPacketManagerPeer::GetBytesInFlight(&manager_);
- }
- void VerifyUnackedPackets(QuicPacketNumber* packets, size_t num_packets) {
- if (num_packets == 0) {
- EXPECT_FALSE(manager_.HasUnackedPackets());
- EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetNumRetransmittablePackets(
- &manager_));
- return;
- }
-
- EXPECT_TRUE(manager_.HasUnackedPackets());
- EXPECT_EQ(packets[0], manager_.GetLeastUnacked(kDefaultPathId));
- for (size_t i = 0; i < num_packets; ++i) {
- EXPECT_TRUE(manager_.IsUnacked(kDefaultPathId, packets[i])) << packets[i];
- }
- }
-
- void VerifyRetransmittablePackets(QuicPacketNumber* packets,
- size_t num_packets) {
- EXPECT_EQ(
- num_packets,
- QuicSentPacketManagerPeer::GetNumRetransmittablePackets(&manager_));
- for (size_t i = 0; i < num_packets; ++i) {
- EXPECT_TRUE(manager_.HasRetransmittableFrames(kDefaultPathId, packets[i]))
- << " packets[" << i << "]:" << packets[i];
- }
- }
-
- void ExpectAck(QuicPacketNumber largest_observed) {
- EXPECT_CALL(
- *send_algorithm_,
- OnCongestionEvent(true, _, ElementsAre(Pair(largest_observed, _)),
- IsEmpty()));
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- }
-
- void ExpectUpdatedRtt(QuicPacketNumber largest_observed) {
- EXPECT_CALL(*send_algorithm_,
- OnCongestionEvent(true, _, IsEmpty(), IsEmpty()));
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- }
-
- void ExpectAckAndLoss(bool rtt_updated,
- QuicPacketNumber largest_observed,
- QuicPacketNumber lost_packet) {
- EXPECT_CALL(*send_algorithm_,
- OnCongestionEvent(rtt_updated, _,
- ElementsAre(Pair(largest_observed, _)),
- ElementsAre(Pair(lost_packet, _))));
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- }
-
- // |packets_acked| and |packets_lost| should be in packet number order.
- void ExpectAcksAndLosses(bool rtt_updated,
- QuicPacketNumber* packets_acked,
- size_t num_packets_acked,
- QuicPacketNumber* packets_lost,
- size_t num_packets_lost) {
- vector<QuicPacketNumber> ack_vector;
- for (size_t i = 0; i < num_packets_acked; ++i) {
- ack_vector.push_back(packets_acked[i]);
- }
- vector<QuicPacketNumber> lost_vector;
- for (size_t i = 0; i < num_packets_lost; ++i) {
- lost_vector.push_back(packets_lost[i]);
- }
- EXPECT_CALL(
- *send_algorithm_,
- OnCongestionEvent(rtt_updated, _, Pointwise(KeyEq(), ack_vector),
- Pointwise(KeyEq(), lost_vector)));
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange())
- .Times(AnyNumber());
- }
-
- void RetransmitAndSendPacket(QuicPacketNumber old_packet_number,
- QuicPacketNumber new_packet_number) {
- RetransmitAndSendPacket(old_packet_number, new_packet_number,
- TLP_RETRANSMISSION);
- }
-
- void RetransmitAndSendPacket(QuicPacketNumber old_packet_number,
- QuicPacketNumber new_packet_number,
- TransmissionType transmission_type) {
- QuicSentPacketManagerPeer::MarkForRetransmission(
- &manager_, kDefaultPathId, old_packet_number, transmission_type);
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- PendingRetransmission next_retransmission =
- manager_.NextPendingRetransmission();
- EXPECT_EQ(old_packet_number, next_retransmission.packet_number);
- EXPECT_EQ(transmission_type, next_retransmission.transmission_type);
-
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, BytesInFlight(), new_packet_number,
- kDefaultLength, HAS_RETRANSMITTABLE_DATA))
- .WillOnce(Return(true));
- SerializedPacket packet(CreatePacket(new_packet_number, false));
- manager_.OnPacketSent(&packet, packet.path_id, old_packet_number,
- clock_.Now(), transmission_type,
- HAS_RETRANSMITTABLE_DATA);
- EXPECT_TRUE(QuicSentPacketManagerPeer::IsRetransmission(
- &manager_, packet.path_id, new_packet_number));
- }
-
- SerializedPacket CreateDataPacket(QuicPacketNumber packet_number) {
- return CreatePacket(packet_number, true);
- }
-
- SerializedPacket CreatePacket(QuicPacketNumber packet_number,
- bool retransmittable) {
- SerializedPacket packet(kDefaultPathId, packet_number,
- PACKET_6BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
- 0u, false, false);
- if (retransmittable) {
- packet.retransmittable_frames.push_back(
- QuicFrame(new QuicStreamFrame(kStreamId, false, 0, StringPiece())));
- }
- return packet;
- }
-
- void SendDataPacket(QuicPacketNumber packet_number) {
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, BytesInFlight(), packet_number, _, _))
- .Times(1)
- .WillOnce(Return(true));
- SerializedPacket packet(CreateDataPacket(packet_number));
- manager_.OnPacketSent(&packet, kInvalidPathId, 0, clock_.Now(),
- NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
- }
-
- void SendCryptoPacket(QuicPacketNumber packet_number) {
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, BytesInFlight(), packet_number, kDefaultLength,
- HAS_RETRANSMITTABLE_DATA))
- .Times(1)
- .WillOnce(Return(true));
- SerializedPacket packet(CreateDataPacket(packet_number));
- packet.retransmittable_frames.push_back(
- QuicFrame(new QuicStreamFrame(1, false, 0, StringPiece())));
- packet.has_crypto_handshake = IS_HANDSHAKE;
- manager_.OnPacketSent(&packet, kInvalidPathId, 0, clock_.Now(),
- NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
- }
-
- void SendAckPacket(QuicPacketNumber packet_number) {
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, BytesInFlight(), packet_number, kDefaultLength,
- NO_RETRANSMITTABLE_DATA))
- .Times(1)
- .WillOnce(Return(false));
- SerializedPacket packet(CreatePacket(packet_number, false));
- manager_.OnPacketSent(&packet, kInvalidPathId, 0, clock_.Now(),
- NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA);
- }
-
- // Based on QuicConnection's WritePendingRetransmissions.
- void RetransmitNextPacket(QuicPacketNumber retransmission_packet_number) {
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, _, retransmission_packet_number, kDefaultLength,
- HAS_RETRANSMITTABLE_DATA))
- .Times(1)
- .WillOnce(Return(true));
- const PendingRetransmission pending = manager_.NextPendingRetransmission();
- SerializedPacket packet(CreatePacket(retransmission_packet_number, false));
- manager_.OnPacketSent(&packet, pending.path_id, pending.packet_number,
- clock_.Now(), pending.transmission_type,
- HAS_RETRANSMITTABLE_DATA);
- }
-
- // Initialize a frame acknowledging all packets up to largest_observed.
- const QuicAckFrame InitAckFrame(QuicPacketNumber largest_observed) {
- QuicAckFrame frame(MakeAckFrame(largest_observed));
- frame.missing = GetParam().missing;
- if (!GetParam().missing) {
- if (largest_observed > 0) {
- frame.packets.Add(1, largest_observed + 1);
- }
- }
- return frame;
- }
-
- // Explicitly nack packet [lower, higher).
- void NackPackets(QuicPacketNumber lower,
- QuicPacketNumber higher,
- QuicAckFrame* frame) {
- if (frame->missing) {
- frame->packets.Add(lower, higher);
- } else {
- frame->packets.Remove(lower, higher);
- }
- }
-
- QuicSentPacketManager manager_;
- vector<QuicEncryptedPacket*> packets_;
- MockClock clock_;
- QuicConnectionStats stats_;
- MockSendAlgorithm* send_algorithm_;
- std::unique_ptr<MockNetworkChangeVisitor> network_change_visitor_;
-};
-
-INSTANTIATE_TEST_CASE_P(QuicSentPacketManagerTest,
- QuicSentPacketManagerTest,
- ::testing::ValuesIn(GetTestParams()));
-
-TEST_P(QuicSentPacketManagerTest, IsUnacked) {
- VerifyUnackedPackets(nullptr, 0);
- SendDataPacket(1);
-
- QuicPacketNumber unacked[] = {1};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- QuicPacketNumber retransmittable[] = {1};
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
-}
-
-TEST_P(QuicSentPacketManagerTest, IsUnAckedRetransmit) {
- SendDataPacket(1);
- RetransmitAndSendPacket(1, 2);
-
- EXPECT_TRUE(QuicSentPacketManagerPeer::IsRetransmission(&manager_,
- kDefaultPathId, 2));
- QuicPacketNumber unacked[] = {1, 2};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- QuicPacketNumber retransmittable[] = {2};
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
-}
-
-TEST_P(QuicSentPacketManagerTest, RetransmitThenAck) {
- SendDataPacket(1);
- RetransmitAndSendPacket(1, 2);
-
- // Ack 2 but not 1.
- QuicAckFrame ack_frame = InitAckFrame(2);
- NackPackets(1, 2, &ack_frame);
- ExpectAck(2);
- manager_.OnIncomingAck(ack_frame, clock_.Now());
-
- // Packet 1 is unacked, pending, but not retransmittable.
- QuicPacketNumber unacked[] = {1};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
- VerifyRetransmittablePackets(nullptr, 0);
-}
-
-TEST_P(QuicSentPacketManagerTest, RetransmitThenAckBeforeSend) {
- SendDataPacket(1);
- QuicSentPacketManagerPeer::MarkForRetransmission(&manager_, kDefaultPathId, 1,
- TLP_RETRANSMISSION);
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
-
- // Ack 1.
- QuicAckFrame ack_frame = InitAckFrame(1);
- ExpectAck(1);
- manager_.OnIncomingAck(ack_frame, clock_.Now());
-
- // There should no longer be a pending retransmission.
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
-
- // No unacked packets remain.
- VerifyUnackedPackets(nullptr, 0);
- VerifyRetransmittablePackets(nullptr, 0);
- EXPECT_EQ(0u, stats_.packets_spuriously_retransmitted);
-}
-
-TEST_P(QuicSentPacketManagerTest, RetransmitThenStopRetransmittingBeforeSend) {
- SendDataPacket(1);
- QuicSentPacketManagerPeer::MarkForRetransmission(&manager_, kDefaultPathId, 1,
- TLP_RETRANSMISSION);
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
-
- manager_.CancelRetransmissionsForStream(kStreamId);
-
- // There should no longer be a pending retransmission.
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
-
- QuicPacketNumber unacked[] = {1};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyRetransmittablePackets(nullptr, 0);
- EXPECT_EQ(0u, stats_.packets_spuriously_retransmitted);
-}
-
-TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPrevious) {
- SendDataPacket(1);
- RetransmitAndSendPacket(1, 2);
- QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(15);
- clock_.AdvanceTime(rtt);
-
- // Ack 1 but not 2.
- ExpectAck(1);
- QuicAckFrame ack_frame = InitAckFrame(1);
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
-
- // 2 remains unacked, but no packets have retransmittable data.
- QuicPacketNumber unacked[] = {2};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
- VerifyRetransmittablePackets(nullptr, 0);
-
- EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted);
-}
-
-TEST_P(QuicSentPacketManagerTest, RetransmitThenAckPreviousThenNackRetransmit) {
- SendDataPacket(1);
- RetransmitAndSendPacket(1, 2);
- QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(15);
- clock_.AdvanceTime(rtt);
-
- // First, ACK packet 1 which makes packet 2 non-retransmittable.
- ExpectAck(1);
- QuicAckFrame ack_frame = InitAckFrame(1);
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
-
- SendDataPacket(3);
- SendDataPacket(4);
- SendDataPacket(5);
- clock_.AdvanceTime(rtt);
-
- // Next, NACK packet 2 three times.
- ack_frame = InitAckFrame(3);
- NackPackets(2, 3, &ack_frame);
- ExpectAck(3);
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
-
- ack_frame = InitAckFrame(4);
- NackPackets(2, 3, &ack_frame);
- ExpectAck(4);
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
-
- ack_frame = InitAckFrame(5);
- NackPackets(2, 3, &ack_frame);
- ExpectAckAndLoss(true, 5, 2);
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
-
- // No packets remain unacked.
- VerifyUnackedPackets(nullptr, 0);
- EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
- VerifyRetransmittablePackets(nullptr, 0);
-
- // Verify that the retransmission alarm would not fire,
- // since there is no retransmittable data outstanding.
- EXPECT_EQ(QuicTime::Zero(), manager_.GetRetransmissionTime());
-}
-
-TEST_P(QuicSentPacketManagerTest,
- DISABLED_RetransmitTwiceThenAckPreviousBeforeSend) {
- SendDataPacket(1);
- RetransmitAndSendPacket(1, 2);
-
- // Fire the RTO, which will mark 2 for retransmission (but will not send it).
- EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- manager_.OnRetransmissionTimeout();
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
-
- // Ack 1 but not 2, before 2 is able to be sent.
- // Since 1 has been retransmitted, it has already been lost, and so the
- // send algorithm is not informed that it has been ACK'd.
- QuicAckFrame ack_frame = InitAckFrame(1);
- ExpectUpdatedRtt(1);
- EXPECT_CALL(*send_algorithm_, RevertRetransmissionTimeout());
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
-
- // Since 2 was marked for retransmit, when 1 is acked, 2 is kept for RTT.
- QuicPacketNumber unacked[] = {2};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
- VerifyRetransmittablePackets(nullptr, 0);
-
- // Verify that the retransmission alarm would not fire,
- // since there is no retransmittable data outstanding.
- EXPECT_EQ(QuicTime::Zero(), manager_.GetRetransmissionTime());
-}
-
-TEST_P(QuicSentPacketManagerTest, RetransmitTwiceThenAckFirst) {
- StrictMock<MockDebugDelegate> debug_delegate;
- EXPECT_CALL(debug_delegate, OnSpuriousPacketRetransmission(TLP_RETRANSMISSION,
- kDefaultLength))
- .Times(2);
- manager_.SetDebugDelegate(&debug_delegate);
-
- SendDataPacket(1);
- RetransmitAndSendPacket(1, 2);
- RetransmitAndSendPacket(2, 3);
- QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(15);
- clock_.AdvanceTime(rtt);
-
- // Ack 1 but not 2 or 3.
- ExpectAck(1);
- QuicAckFrame ack_frame = InitAckFrame(1);
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
-
- // 2 and 3 remain unacked, but no packets have retransmittable data.
- QuicPacketNumber unacked[] = {2, 3};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
- VerifyRetransmittablePackets(nullptr, 0);
-
- // Ensure packet 2 is lost when 4 is sent and 3 and 4 are acked.
- SendDataPacket(4);
- ack_frame = InitAckFrame(4);
- NackPackets(2, 3, &ack_frame);
- QuicPacketNumber acked[] = {3, 4};
- ExpectAcksAndLosses(true, acked, arraysize(acked), nullptr, 0);
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
-
- QuicPacketNumber unacked2[] = {2};
- VerifyUnackedPackets(unacked2, arraysize(unacked2));
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
-
- SendDataPacket(5);
- ack_frame = InitAckFrame(5);
- NackPackets(2, 3, &ack_frame);
- ExpectAckAndLoss(true, 5, 2);
- EXPECT_CALL(debug_delegate, OnPacketLoss(2, LOSS_RETRANSMISSION, _));
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
-
- VerifyUnackedPackets(nullptr, 0);
- EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
- EXPECT_EQ(2u, stats_.packets_spuriously_retransmitted);
-}
-
-TEST_P(QuicSentPacketManagerTest, AckOriginalTransmission) {
- MockLossAlgorithm* loss_algorithm = new MockLossAlgorithm();
- QuicSentPacketManagerPeer::SetLossAlgorithm(&manager_, loss_algorithm);
-
- SendDataPacket(1);
- RetransmitAndSendPacket(1, 2);
-
- // Ack original transmission, but that wasn't lost via fast retransmit,
- // so no call on OnSpuriousRetransmission is expected.
- {
- QuicAckFrame ack_frame = InitAckFrame(1);
- ExpectAck(1);
- EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
- manager_.OnIncomingAck(ack_frame, clock_.Now());
- }
-
- SendDataPacket(3);
- SendDataPacket(4);
- // Ack 4, which causes 3 to be retransmitted.
- {
- QuicAckFrame ack_frame = InitAckFrame(4);
- NackPackets(2, 4, &ack_frame);
- ExpectAck(4);
- EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
- manager_.OnIncomingAck(ack_frame, clock_.Now());
- RetransmitAndSendPacket(3, 5, LOSS_RETRANSMISSION);
- }
-
- // Ack 3, which causes SpuriousRetransmitDetected to be called.
- {
- QuicAckFrame ack_frame = InitAckFrame(4);
- NackPackets(2, 3, &ack_frame);
- EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
- EXPECT_CALL(*loss_algorithm, SpuriousRetransmitDetected(_, _, _, 5));
- manager_.OnIncomingAck(ack_frame, clock_.Now());
- }
-}
-
-TEST_P(QuicSentPacketManagerTest, AckPreviousTransmissionThenTruncatedAck) {
- FLAGS_quic_loss_recovery_use_largest_acked = false;
- if (!GetParam().missing) {
- return;
- }
- SendDataPacket(1);
- RetransmitAndSendPacket(1, 2);
- RetransmitAndSendPacket(2, 3);
- RetransmitAndSendPacket(3, 4);
- SendDataPacket(5);
- SendDataPacket(6);
- SendDataPacket(7);
- SendDataPacket(8);
- SendDataPacket(9);
-
- // Ack previous transmission
- {
- QuicAckFrame ack_frame = InitAckFrame(2);
- NackPackets(1, 2, &ack_frame);
- ExpectAck(2);
- manager_.OnIncomingAck(ack_frame, clock_.Now());
- EXPECT_TRUE(manager_.IsUnacked(kDefaultPathId, 4));
- }
-
- // Truncated ack with 4 NACKs
- {
- QuicAckFrame ack_frame = InitAckFrame(6);
- NackPackets(3, 7, &ack_frame);
- ack_frame.is_truncated = true;
- ExpectAckAndLoss(true, 1, 3);
- manager_.OnIncomingAck(ack_frame, clock_.Now());
- }
-
- // High water mark will be raised.
- QuicPacketNumber unacked[] = {4, 5, 6, 7, 8, 9};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- QuicPacketNumber retransmittable[] = {5, 6, 7, 8, 9};
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
-}
-
-TEST_P(QuicSentPacketManagerTest, GetLeastUnacked) {
- EXPECT_EQ(1u, manager_.GetLeastUnacked(kDefaultPathId));
-}
-
-TEST_P(QuicSentPacketManagerTest, GetLeastUnackedUnacked) {
- SendDataPacket(1);
- EXPECT_EQ(1u, manager_.GetLeastUnacked(kDefaultPathId));
-}
-
-TEST_P(QuicSentPacketManagerTest, AckAckAndUpdateRtt) {
- SendDataPacket(1);
- SendAckPacket(2);
-
- // Now ack the ack and expect an RTT update.
- QuicAckFrame ack_frame = InitAckFrame(2);
- ack_frame.ack_delay_time = QuicTime::Delta::FromMilliseconds(5);
-
- ExpectAck(1);
- manager_.OnIncomingAck(ack_frame, clock_.Now());
-
- SendAckPacket(3);
-
- // Now ack the ack and expect only an RTT update.
- ack_frame = InitAckFrame(3);
- ExpectUpdatedRtt(3);
- manager_.OnIncomingAck(ack_frame, clock_.Now());
-}
-
-TEST_P(QuicSentPacketManagerTest, Rtt) {
- QuicPacketNumber packet_number = 1;
- QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(15);
- SendDataPacket(packet_number);
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
-
- ExpectAck(packet_number);
- QuicAckFrame ack_frame = InitAckFrame(packet_number);
- ack_frame.ack_delay_time = QuicTime::Delta::FromMilliseconds(5);
- manager_.OnIncomingAck(ack_frame, clock_.Now());
- EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
-}
-
-TEST_P(QuicSentPacketManagerTest, RttWithInvalidDelta) {
- // Expect that the RTT is equal to the local time elapsed, since the
- // ack_delay_time is larger than the local time elapsed
- // and is hence invalid.
- QuicPacketNumber packet_number = 1;
- QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(10);
- SendDataPacket(packet_number);
- clock_.AdvanceTime(expected_rtt);
-
- ExpectAck(packet_number);
- QuicAckFrame ack_frame = InitAckFrame(packet_number);
- ack_frame.ack_delay_time = QuicTime::Delta::FromMilliseconds(11);
- manager_.OnIncomingAck(ack_frame, clock_.Now());
- EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
-}
-
-TEST_P(QuicSentPacketManagerTest, RttWithInfiniteDelta) {
- // Expect that the RTT is equal to the local time elapsed, since the
- // ack_delay_time is infinite, and is hence invalid.
- QuicPacketNumber packet_number = 1;
- QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(10);
- SendDataPacket(packet_number);
- clock_.AdvanceTime(expected_rtt);
-
- ExpectAck(packet_number);
- QuicAckFrame ack_frame = InitAckFrame(packet_number);
- ack_frame.ack_delay_time = QuicTime::Delta::Infinite();
- manager_.OnIncomingAck(ack_frame, clock_.Now());
- EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
-}
-
-TEST_P(QuicSentPacketManagerTest, RttZeroDelta) {
- // Expect that the RTT is the time between send and receive since the
- // ack_delay_time is zero.
- QuicPacketNumber packet_number = 1;
- QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(10);
- SendDataPacket(packet_number);
- clock_.AdvanceTime(expected_rtt);
-
- ExpectAck(packet_number);
- QuicAckFrame ack_frame = InitAckFrame(packet_number);
- ack_frame.ack_delay_time = QuicTime::Delta::Zero();
- manager_.OnIncomingAck(ack_frame, clock_.Now());
- EXPECT_EQ(expected_rtt, manager_.GetRttStats()->latest_rtt());
-}
-
-TEST_P(QuicSentPacketManagerTest, TailLossProbeTimeout) {
- QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2);
-
- // Send 1 packet.
- QuicPacketNumber packet_number = 1;
- SendDataPacket(packet_number);
-
- QuicPathId path_id = kInvalidPathId;
- // The first tail loss probe retransmits 1 packet.
- manager_.OnRetransmissionTimeout();
- EXPECT_EQ(
- QuicTime::Delta::Zero(),
- manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- manager_.MaybeRetransmitTailLossProbe();
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- RetransmitNextPacket(2);
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
-
- // The second tail loss probe retransmits 1 packet.
- manager_.OnRetransmissionTimeout();
- EXPECT_EQ(
- QuicTime::Delta::Zero(),
- manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- manager_.MaybeRetransmitTailLossProbe();
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- RetransmitNextPacket(3);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillOnce(Return(QuicTime::Delta::Infinite()));
- EXPECT_EQ(
- QuicTime::Delta::Infinite(),
- manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
-
- // Ack the third and ensure the first two are still pending.
- ExpectAck(3);
-
- QuicAckFrame ack_frame = InitAckFrame(3);
- NackPackets(1, 3, &ack_frame);
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
-
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
-
- // Acking two more packets will lose both of them due to nacks.
- SendDataPacket(4);
- SendDataPacket(5);
- ack_frame = InitAckFrame(5);
- NackPackets(1, 3, &ack_frame);
- QuicPacketNumber acked[] = {4, 5};
- QuicPacketNumber lost[] = {1, 2};
- ExpectAcksAndLosses(true, acked, arraysize(acked), lost, arraysize(lost));
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
-
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
- EXPECT_EQ(2u, stats_.tlp_count);
- EXPECT_EQ(0u, stats_.rto_count);
-}
-
-TEST_P(QuicSentPacketManagerTest, TailLossProbeThenRTO) {
- QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2);
-
- // Send 100 packets.
- const size_t kNumSentPackets = 100;
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
- QuicTime rto_packet_time = clock_.Now();
- // Advance the time.
- clock_.AdvanceTime(manager_.GetRetransmissionTime().Subtract(clock_.Now()));
-
- // The first tail loss probe retransmits 1 packet.
- manager_.OnRetransmissionTimeout();
- QuicPathId path_id = kInvalidPathId;
- EXPECT_EQ(
- QuicTime::Delta::Zero(),
- manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- manager_.MaybeRetransmitTailLossProbe();
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- RetransmitNextPacket(101);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillOnce(Return(QuicTime::Delta::Infinite()));
- EXPECT_EQ(
- QuicTime::Delta::Infinite(),
- manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- clock_.AdvanceTime(manager_.GetRetransmissionTime().Subtract(clock_.Now()));
-
- // The second tail loss probe retransmits 1 packet.
- manager_.OnRetransmissionTimeout();
- EXPECT_EQ(
- QuicTime::Delta::Zero(),
- manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- EXPECT_TRUE(manager_.MaybeRetransmitTailLossProbe());
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- RetransmitNextPacket(102);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillOnce(Return(QuicTime::Delta::Infinite()));
- EXPECT_EQ(
- QuicTime::Delta::Infinite(),
- manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
-
- // Ensure the RTO is set based on the correct packet.
- rto_packet_time = clock_.Now();
- EXPECT_CALL(*send_algorithm_, RetransmissionDelay())
- .WillOnce(Return(QuicTime::Delta::FromSeconds(1)));
- EXPECT_EQ(rto_packet_time.Add(QuicTime::Delta::FromSeconds(1)),
- manager_.GetRetransmissionTime());
-
- // Advance the time enough to ensure all packets are RTO'd.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000));
-
- manager_.OnRetransmissionTimeout();
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- EXPECT_EQ(2u, stats_.tlp_count);
- EXPECT_EQ(1u, stats_.rto_count);
-
- // Send and Ack the RTO and ensure OnRetransmissionTimeout is called.
- EXPECT_EQ(102 * kDefaultLength,
- QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
-
- RetransmitNextPacket(103);
- QuicAckFrame ack_frame = InitAckFrame(103);
- NackPackets(0, 103, &ack_frame);
- EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
- EXPECT_CALL(*send_algorithm_,
- OnCongestionEvent(true, _, ElementsAre(Pair(103, _)), _));
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
- // All packets before 103 should be lost.
- EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
-}
-
-TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeout) {
- // Send 2 crypto packets and 3 data packets.
- const size_t kNumSentCryptoPackets = 2;
- for (size_t i = 1; i <= kNumSentCryptoPackets; ++i) {
- SendCryptoPacket(i);
- }
- const size_t kNumSentDataPackets = 3;
- for (size_t i = 1; i <= kNumSentDataPackets; ++i) {
- SendDataPacket(kNumSentCryptoPackets + i);
- }
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-
- // The first retransmits 2 packets.
- QuicPathId path_id = kInvalidPathId;
- manager_.OnRetransmissionTimeout();
- EXPECT_EQ(
- QuicTime::Delta::Zero(),
- manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
- RetransmitNextPacket(6);
- RetransmitNextPacket(7);
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-
- // The second retransmits 2 packets.
- manager_.OnRetransmissionTimeout();
- EXPECT_EQ(
- QuicTime::Delta::Zero(),
- manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
- RetransmitNextPacket(8);
- RetransmitNextPacket(9);
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-
- // 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);
- QuicAckFrame ack_frame = InitAckFrame(9);
- NackPackets(1, 3, &ack_frame);
- NackPackets(6, 8, &ack_frame);
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
-
- EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-}
-
-TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutVersionNegotiation) {
- // Send 2 crypto packets and 3 data packets.
- const size_t kNumSentCryptoPackets = 2;
- for (size_t i = 1; i <= kNumSentCryptoPackets; ++i) {
- SendCryptoPacket(i);
- }
- const size_t kNumSentDataPackets = 3;
- for (size_t i = 1; i <= kNumSentDataPackets; ++i) {
- SendDataPacket(kNumSentCryptoPackets + i);
- }
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-
- // The first retransmission timeout retransmits 2 crypto packets.
- manager_.OnRetransmissionTimeout();
- RetransmitNextPacket(6);
- RetransmitNextPacket(7);
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-
- // Now act like a version negotiation packet arrived, which would cause all
- // unacked packets to be retransmitted.
- manager_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION);
-
- // Ensure the first two pending packets are the crypto retransmits.
- ASSERT_TRUE(manager_.HasPendingRetransmissions());
- EXPECT_EQ(6u, manager_.NextPendingRetransmission().packet_number);
- RetransmitNextPacket(8);
- EXPECT_EQ(7u, manager_.NextPendingRetransmission().packet_number);
- RetransmitNextPacket(9);
-
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- // Send 3 more data packets and ensure the least unacked is raised.
- RetransmitNextPacket(10);
- RetransmitNextPacket(11);
- RetransmitNextPacket(12);
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
-
- EXPECT_EQ(1u, manager_.GetLeastUnacked(kDefaultPathId));
- // 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);
- QuicAckFrame ack_frame = InitAckFrame(9);
- for (QuicPacketNumber i = 1; i < 8; ++i) {
- NackPackets(i, i + 1, &ack_frame);
- }
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
- EXPECT_EQ(10u, manager_.GetLeastUnacked(kDefaultPathId));
-}
-
-TEST_P(QuicSentPacketManagerTest, CryptoHandshakeSpuriousRetransmission) {
- // Send 1 crypto packet.
- SendCryptoPacket(1);
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-
- // Retransmit the crypto packet as 2.
- manager_.OnRetransmissionTimeout();
- RetransmitNextPacket(2);
-
- // Retransmit the crypto packet as 3.
- manager_.OnRetransmissionTimeout();
- RetransmitNextPacket(3);
-
- // Now ack the second crypto packet, and ensure the first gets removed, but
- // the third does not.
- ExpectUpdatedRtt(2);
- QuicAckFrame ack_frame = InitAckFrame(2);
- NackPackets(1, 2, &ack_frame);
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
-
- EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
- QuicPacketNumber unacked[] = {3};
- VerifyUnackedPackets(unacked, arraysize(unacked));
-}
-
-TEST_P(QuicSentPacketManagerTest, CryptoHandshakeTimeoutUnsentDataPacket) {
- // Send 2 crypto packets and 1 data packet.
- const size_t kNumSentCryptoPackets = 2;
- for (size_t i = 1; i <= kNumSentCryptoPackets; ++i) {
- SendCryptoPacket(i);
- }
- SendDataPacket(3);
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-
- // Retransmit 2 crypto packets, but not the serialized packet.
- manager_.OnRetransmissionTimeout();
- RetransmitNextPacket(4);
- RetransmitNextPacket(5);
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-}
-
-TEST_P(QuicSentPacketManagerTest,
- CryptoHandshakeRetransmissionThenRetransmitAll) {
- // Send 1 crypto packet.
- SendCryptoPacket(1);
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-
- // Retransmit the crypto packet as 2.
- manager_.OnRetransmissionTimeout();
- RetransmitNextPacket(2);
-
- // Now retransmit all the unacked packets, which occurs when there is a
- // version negotiation.
- manager_.RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION);
- QuicPacketNumber unacked[] = {1, 2};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
- EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
-}
-
-TEST_P(QuicSentPacketManagerTest,
- CryptoHandshakeRetransmissionThenNeuterAndAck) {
- // Send 1 crypto packet.
- SendCryptoPacket(1);
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-
- // Retransmit the crypto packet as 2.
- manager_.OnRetransmissionTimeout();
- RetransmitNextPacket(2);
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-
- // Retransmit the crypto packet as 3.
- manager_.OnRetransmissionTimeout();
- RetransmitNextPacket(3);
- EXPECT_TRUE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
-
- // Now neuter all unacked unencrypted packets, which occurs when the
- // connection goes forward secure.
- manager_.NeuterUnencryptedPackets();
- EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
- QuicPacketNumber unacked[] = {1, 2, 3};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyRetransmittablePackets(nullptr, 0);
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- EXPECT_FALSE(QuicSentPacketManagerPeer::HasUnackedCryptoPackets(&manager_));
- EXPECT_FALSE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_));
-
- // Ensure both packets get discarded when packet 2 is acked.
- QuicAckFrame ack_frame = InitAckFrame(3);
- NackPackets(1, 3, &ack_frame);
- ExpectUpdatedRtt(3);
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
- VerifyUnackedPackets(nullptr, 0);
- VerifyRetransmittablePackets(nullptr, 0);
-}
-
-TEST_P(QuicSentPacketManagerTest, RetransmissionTimeout) {
- StrictMock<MockDebugDelegate> debug_delegate;
- manager_.SetDebugDelegate(&debug_delegate);
-
- // Send 100 packets.
- const size_t kNumSentPackets = 100;
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
-
- EXPECT_FALSE(manager_.MaybeRetransmitTailLossProbe());
- manager_.OnRetransmissionTimeout();
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- EXPECT_EQ(100 * kDefaultLength,
- QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
- RetransmitNextPacket(101);
- RetransmitNextPacket(102);
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
-
- // Ack a retransmission.
- QuicAckFrame ack_frame = InitAckFrame(102);
- NackPackets(0, 102, &ack_frame);
- ack_frame.ack_delay_time = QuicTime::Delta::Zero();
- // Ensure no packets are lost.
- EXPECT_CALL(*send_algorithm_,
- OnCongestionEvent(true, _, ElementsAre(Pair(102, _)),
- /*lost_packets=*/IsEmpty()));
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
- // RTO's use loss detection instead of immediately declaring retransmitted
- // packets lost.
- for (int i = 1; i <= 99; ++i) {
- EXPECT_CALL(debug_delegate, OnPacketLoss(i, LOSS_RETRANSMISSION, _));
- }
- manager_.OnIncomingAck(ack_frame, clock_.Now());
-}
-
-TEST_P(QuicSentPacketManagerTest, NewRetransmissionTimeout) {
- QuicConfig client_config;
- QuicTagVector options;
- options.push_back(kNRTO);
- QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT);
- client_config.SetConnectionOptionsToSend(options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- EXPECT_CALL(*send_algorithm_, PacingRate(_))
- .WillRepeatedly(Return(QuicBandwidth::Zero()));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(10 * kDefaultTCPMSS));
- manager_.SetFromConfig(client_config);
- EXPECT_TRUE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
-
- // Send 100 packets.
- const size_t kNumSentPackets = 100;
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
-
- EXPECT_FALSE(manager_.MaybeRetransmitTailLossProbe());
- manager_.OnRetransmissionTimeout();
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- EXPECT_EQ(100 * kDefaultLength,
- QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
- RetransmitNextPacket(101);
- RetransmitNextPacket(102);
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
-
- // Ack a retransmission and expect no call to OnRetransmissionTimeout.
- QuicAckFrame ack_frame = InitAckFrame(102);
- NackPackets(0, 102, &ack_frame);
- ack_frame.ack_delay_time = QuicTime::Delta::Zero();
- // This will include packets in the lost packet map.
- EXPECT_CALL(*send_algorithm_,
- OnCongestionEvent(true, _, ElementsAre(Pair(102, _)),
- /*lost_packets=*/Not(IsEmpty())));
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- manager_.OnIncomingAck(ack_frame, clock_.Now());
-}
-
-TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckSecond) {
- // Send 1 packet.
- SendDataPacket(1);
-
- manager_.OnRetransmissionTimeout();
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- EXPECT_EQ(kDefaultLength,
- QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
- RetransmitNextPacket(2);
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
-
- // Rto a second time.
- EXPECT_CALL(*network_change_visitor_, OnPathDegrading());
- manager_.OnRetransmissionTimeout();
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- EXPECT_EQ(2 * kDefaultLength,
- QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
- RetransmitNextPacket(3);
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
-
- // Ack a retransmission and ensure OnRetransmissionTimeout is called.
- EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
- QuicAckFrame ack_frame = InitAckFrame(2);
- NackPackets(1, 2, &ack_frame);
- ack_frame.ack_delay_time = QuicTime::Delta::Zero();
- ExpectAck(2);
- manager_.OnIncomingAck(ack_frame, clock_.Now());
-
- // The original packet and newest should be outstanding.
- EXPECT_EQ(2 * kDefaultLength,
- QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
-}
-
-TEST_P(QuicSentPacketManagerTest, TwoRetransmissionTimeoutsAckFirst) {
- // Send 1 packet.
- SendDataPacket(1);
-
- manager_.OnRetransmissionTimeout();
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- EXPECT_EQ(kDefaultLength,
- QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
- RetransmitNextPacket(2);
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
-
- // Rto a second time.
- EXPECT_CALL(*network_change_visitor_, OnPathDegrading());
- manager_.OnRetransmissionTimeout();
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- EXPECT_EQ(2 * kDefaultLength,
- QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
- RetransmitNextPacket(3);
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
-
- // Ack a retransmission and ensure OnRetransmissionTimeout is called.
- EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true));
- QuicAckFrame ack_frame = InitAckFrame(3);
- NackPackets(1, 3, &ack_frame);
- ack_frame.ack_delay_time = QuicTime::Delta::Zero();
- ExpectAck(3);
- manager_.OnIncomingAck(ack_frame, clock_.Now());
-
- // The first two packets should still be outstanding.
- EXPECT_EQ(2 * kDefaultLength,
- QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
-}
-
-TEST_P(QuicSentPacketManagerTest, OnPathDegrading) {
- SendDataPacket(1);
- QuicTime::Delta delay = QuicTime::Delta::FromMilliseconds(500);
- EXPECT_CALL(*send_algorithm_, RetransmissionDelay())
- .WillRepeatedly(Return(delay));
- for (size_t i = 1; i < kMinTimeoutsBeforePathDegrading; ++i) {
- manager_.OnRetransmissionTimeout();
- RetransmitNextPacket(i + 2);
- }
- // Next RTO should cause network_change_visitor_'s OnPathDegrading method
- // to be called.
- EXPECT_CALL(*network_change_visitor_, OnPathDegrading());
- manager_.OnRetransmissionTimeout();
-}
-
-TEST_P(QuicSentPacketManagerTest, GetTransmissionTime) {
- EXPECT_EQ(QuicTime::Zero(), manager_.GetRetransmissionTime());
-}
-
-TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeCryptoHandshake) {
- SendCryptoPacket(1);
-
- // Check the min.
- RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
- rtt_stats->set_initial_rtt_us(1 * kNumMicrosPerMilli);
- EXPECT_EQ(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(10)),
- manager_.GetRetransmissionTime());
-
- // Test with a standard smoothed RTT.
- rtt_stats->set_initial_rtt_us(100 * kNumMicrosPerMilli);
-
- QuicTime::Delta srtt =
- QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
- QuicTime expected_time = clock_.Now().Add(srtt.Multiply(1.5));
- EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
-
- // Retransmit the packet by invoking the retransmission timeout.
- clock_.AdvanceTime(srtt.Multiply(1.5));
- manager_.OnRetransmissionTimeout();
- RetransmitNextPacket(2);
-
- // The retransmission time should now be twice as far in the future.
- expected_time = clock_.Now().Add(srtt.Multiply(2).Multiply(1.5));
- EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
-}
-
-TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeTailLossProbe) {
- QuicSentPacketManagerPeer::SetMaxTailLossProbes(&manager_, 2);
- SendDataPacket(1);
- SendDataPacket(2);
-
- // Check the min.
- RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
- rtt_stats->set_initial_rtt_us(1 * kNumMicrosPerMilli);
- EXPECT_EQ(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(10)),
- manager_.GetRetransmissionTime());
-
- // Test with a standard smoothed RTT.
- rtt_stats->set_initial_rtt_us(100 * kNumMicrosPerMilli);
- QuicTime::Delta srtt =
- QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
- QuicTime::Delta expected_tlp_delay = srtt.Multiply(2);
- QuicTime expected_time = clock_.Now().Add(expected_tlp_delay);
- EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
-
- // Retransmit the packet by invoking the retransmission timeout.
- clock_.AdvanceTime(expected_tlp_delay);
- manager_.OnRetransmissionTimeout();
- QuicPathId path_id = kInvalidPathId;
- EXPECT_EQ(
- QuicTime::Delta::Zero(),
- manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- EXPECT_TRUE(manager_.MaybeRetransmitTailLossProbe());
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- RetransmitNextPacket(3);
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillOnce(Return(QuicTime::Delta::Infinite()));
- EXPECT_EQ(
- QuicTime::Delta::Infinite(),
- manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
-
- expected_time = clock_.Now().Add(expected_tlp_delay);
- EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
-}
-
-TEST_P(QuicSentPacketManagerTest, GetTransmissionTimeSpuriousRTO) {
- const_cast<RttStats*>(manager_.GetRttStats())
- ->UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- SendDataPacket(1);
- SendDataPacket(2);
- SendDataPacket(3);
- SendDataPacket(4);
-
- QuicTime::Delta expected_rto_delay = QuicTime::Delta::FromMilliseconds(500);
- EXPECT_CALL(*send_algorithm_, RetransmissionDelay())
- .WillRepeatedly(Return(expected_rto_delay));
- QuicTime expected_time = clock_.Now().Add(expected_rto_delay);
- EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
-
- // Retransmit the packet by invoking the retransmission timeout.
- clock_.AdvanceTime(expected_rto_delay);
- manager_.OnRetransmissionTimeout();
- // All packets are still considered inflight.
- EXPECT_EQ(4 * kDefaultLength,
- QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
- RetransmitNextPacket(5);
- RetransmitNextPacket(6);
- // All previous packets are inflight, plus two rto retransmissions.
- EXPECT_EQ(6 * kDefaultLength,
- QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
-
- // The delay should double the second time.
- expected_time = clock_.Now().Add(expected_rto_delay).Add(expected_rto_delay);
- // Once we always base the timer on the right edge, leaving the older packets
- // in flight doesn't change the timeout.
- EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
-
- // Ack a packet before the first RTO and ensure the RTO timeout returns to the
- // original value and OnRetransmissionTimeout is not called or reverted.
- QuicAckFrame ack_frame = InitAckFrame(2);
- NackPackets(1, 2, &ack_frame);
- ExpectAck(2);
- manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow());
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- EXPECT_EQ(5 * kDefaultLength,
- QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
-
- // Wait 2RTTs from now for the RTO, since it's the max of the RTO time
- // and the TLP time. In production, there would always be two TLP's first.
- // Since retransmission was spurious, smoothed_rtt_ is expired, and replaced
- // by the latest RTT sample of 500ms.
- expected_time = clock_.Now().Add(QuicTime::Delta::FromMilliseconds(1000));
- // Once we always base the timer on the right edge, leaving the older packets
- // in flight doesn't change the timeout.
- EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
-}
-
-TEST_P(QuicSentPacketManagerTest, GetTransmissionDelayMin) {
- SendDataPacket(1);
- EXPECT_CALL(*send_algorithm_, RetransmissionDelay())
- .WillRepeatedly(Return(QuicTime::Delta::FromMilliseconds(1)));
- QuicTime::Delta delay = QuicTime::Delta::FromMilliseconds(200);
-
- // If the delay is smaller than the min, ensure it exponentially backs off
- // from the min.
- EXPECT_CALL(*network_change_visitor_, OnPathDegrading());
- for (int i = 0; i < 5; ++i) {
- EXPECT_EQ(delay,
- QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_));
- delay = delay.Add(delay);
- manager_.OnRetransmissionTimeout();
- RetransmitNextPacket(i + 2);
- }
-}
-
-TEST_P(QuicSentPacketManagerTest, GetTransmissionDelayMax) {
- EXPECT_CALL(*send_algorithm_, RetransmissionDelay())
- .WillOnce(Return(QuicTime::Delta::FromSeconds(500)));
-
- EXPECT_EQ(QuicTime::Delta::FromSeconds(60),
- QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_));
-}
-
-TEST_P(QuicSentPacketManagerTest, GetTransmissionDelay) {
- SendDataPacket(1);
- QuicTime::Delta delay = QuicTime::Delta::FromMilliseconds(500);
- EXPECT_CALL(*send_algorithm_, RetransmissionDelay())
- .WillRepeatedly(Return(delay));
-
- // Delay should back off exponentially.
- EXPECT_CALL(*network_change_visitor_, OnPathDegrading());
- for (int i = 0; i < 5; ++i) {
- EXPECT_EQ(delay,
- QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_));
- delay = delay.Add(delay);
- manager_.OnRetransmissionTimeout();
- RetransmitNextPacket(i + 2);
- }
-}
-
-TEST_P(QuicSentPacketManagerTest, GetLossDelay) {
- MockLossAlgorithm* loss_algorithm = new MockLossAlgorithm();
- QuicSentPacketManagerPeer::SetLossAlgorithm(&manager_, loss_algorithm);
-
- EXPECT_CALL(*loss_algorithm, GetLossTimeout())
- .WillRepeatedly(Return(QuicTime::Zero()));
- SendDataPacket(1);
- SendDataPacket(2);
-
- // Handle an ack which causes the loss algorithm to be evaluated and
- // set the loss timeout.
- ExpectAck(2);
- EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
- QuicAckFrame ack_frame = InitAckFrame(2);
- NackPackets(1, 2, &ack_frame);
- manager_.OnIncomingAck(ack_frame, clock_.Now());
-
- QuicTime timeout(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(10)));
- EXPECT_CALL(*loss_algorithm, GetLossTimeout())
- .WillRepeatedly(Return(timeout));
- EXPECT_EQ(timeout, manager_.GetRetransmissionTime());
-
- // Fire the retransmission timeout and ensure the loss detection algorithm
- // is invoked.
- EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
- manager_.OnRetransmissionTimeout();
-}
-
-TEST_P(QuicSentPacketManagerTest, NegotiateTimeLossDetectionFromOptions) {
- EXPECT_EQ(kNack, QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_)
- ->GetLossDetectionType());
-
- QuicConfig config;
- QuicTagVector options;
- options.push_back(kTIME);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- manager_.SetFromConfig(config);
-
- EXPECT_EQ(kTime, QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_)
- ->GetLossDetectionType());
-}
-
-TEST_P(QuicSentPacketManagerTest, NegotiateCongestionControlFromOptions) {
- FLAGS_quic_allow_bbr = true;
- QuicConfig config;
- QuicTagVector options;
-
- options.push_back(kRENO);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- manager_.SetFromConfig(config);
- EXPECT_EQ(kReno, QuicSentPacketManagerPeer::GetSendAlgorithm(manager_)
- ->GetCongestionControlType());
-
-// TODO(rtenneti): Enable the following code after BBR code is checked in.
-#if 0
- options.clear();
- options.push_back(kTBBR);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- manager_.SetFromConfig(config);
- EXPECT_EQ(kBBR, QuicSentPacketManagerPeer::GetSendAlgorithm(
- manager_)->GetCongestionControlType());
-#endif
-
- options.clear();
- options.push_back(kBYTE);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- manager_.SetFromConfig(config);
- EXPECT_EQ(kCubicBytes, QuicSentPacketManagerPeer::GetSendAlgorithm(manager_)
- ->GetCongestionControlType());
-
- options.clear();
- options.push_back(kRENO);
- options.push_back(kBYTE);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- manager_.SetFromConfig(config);
- EXPECT_EQ(kRenoBytes, QuicSentPacketManagerPeer::GetSendAlgorithm(manager_)
- ->GetCongestionControlType());
-}
-
-TEST_P(QuicSentPacketManagerTest, NegotiateNumConnectionsFromOptions) {
- QuicConfig config;
- QuicTagVector options;
-
- options.push_back(k1CON);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(1));
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- manager_.SetFromConfig(config);
-
- QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT);
- QuicConfig client_config;
- client_config.SetConnectionOptionsToSend(options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(1));
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- manager_.SetFromConfig(client_config);
-}
-
-TEST_P(QuicSentPacketManagerTest, NegotiateNConnectionFromOptions) {
- // By default, changing the number of open streams does nothing.
- manager_.SetNumOpenStreams(5);
-
- QuicConfig config;
- QuicTagVector options;
-
- options.push_back(kNCON);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- manager_.SetFromConfig(config);
-
- EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(5));
- manager_.SetNumOpenStreams(5);
-}
-
-TEST_P(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtServer) {
- QuicConfig config;
- QuicTagVector options;
-
- options.push_back(kNTLP);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- manager_.SetFromConfig(config);
- EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_));
-}
-
-TEST_P(QuicSentPacketManagerTest, NegotiateNoTLPFromOptionsAtClient) {
- QuicConfig client_config;
- QuicTagVector options;
-
- options.push_back(kNTLP);
- 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(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_));
-}
-
-TEST_P(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtServer) {
- QuicConfig config;
- QuicTagVector options;
-
- options.push_back(kTLPR);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- manager_.SetFromConfig(config);
- EXPECT_TRUE(
- QuicSentPacketManagerPeer::GetEnableHalfRttTailLossProbe(&manager_));
-}
-
-TEST_P(QuicSentPacketManagerTest, NegotiateTLPRttFromOptionsAtClient) {
- QuicConfig client_config;
- QuicTagVector options;
-
- options.push_back(kTLPR);
- 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_TRUE(
- QuicSentPacketManagerPeer::GetEnableHalfRttTailLossProbe(&manager_));
-}
-
-TEST_P(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtServer) {
- EXPECT_FALSE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
- QuicConfig config;
- QuicTagVector options;
-
- options.push_back(kNRTO);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- manager_.SetFromConfig(config);
- EXPECT_TRUE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
-}
-
-TEST_P(QuicSentPacketManagerTest, NegotiateNewRTOFromOptionsAtClient) {
- EXPECT_FALSE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
- QuicConfig client_config;
- QuicTagVector options;
-
- options.push_back(kNRTO);
- 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_TRUE(QuicSentPacketManagerPeer::GetUseNewRto(&manager_));
-}
-
-TEST_P(QuicSentPacketManagerTest, NegotiateUndoFromOptionsAtServer) {
- FLAGS_quic_loss_recovery_use_largest_acked = true;
- EXPECT_FALSE(QuicSentPacketManagerPeer::GetUndoRetransmits(&manager_));
- QuicConfig config;
- QuicTagVector options;
-
- options.push_back(kUNDO);
- QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- manager_.SetFromConfig(config);
- EXPECT_TRUE(QuicSentPacketManagerPeer::GetUndoRetransmits(&manager_));
-
- // Ensure undo works as intended.
- // Send 5 packets, mark the first 4 for retransmission, and then cancel
- // them when 1 is acked.
- EXPECT_CALL(*send_algorithm_, PacingRate(_))
- .WillRepeatedly(Return(QuicBandwidth::Zero()));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(10 * kDefaultTCPMSS));
- const size_t kNumSentPackets = 5;
- for (size_t i = 1; i <= kNumSentPackets; ++i) {
- SendDataPacket(i);
- }
- MockLossAlgorithm* loss_algorithm = new MockLossAlgorithm();
- QuicSentPacketManagerPeer::SetLossAlgorithm(&manager_, loss_algorithm);
- EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _));
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- SendAlgorithmInterface::CongestionVector lost_packets;
- for (size_t i = 1; i < kNumSentPackets; ++i) {
- lost_packets.push_back(std::make_pair(i, kMaxPacketSize));
- }
- EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _))
- .WillOnce(SetArgPointee<4>(lost_packets));
- QuicAckFrame ack_frame = InitAckFrame(kNumSentPackets);
- NackPackets(1, kNumSentPackets, &ack_frame);
- // Congestion block the sending right before losing the packets.
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillRepeatedly(Return(QuicTime::Delta::Infinite()));
- manager_.OnIncomingAck(ack_frame, clock_.Now());
- EXPECT_TRUE(manager_.HasPendingRetransmissions());
- EXPECT_EQ(0u, BytesInFlight());
-
- // Ack 1 and ensure the retransmissions are cancelled and put back in flight.
- EXPECT_CALL(*loss_algorithm, DetectLosses(_, _, _, _, _));
- ack_frame = InitAckFrame(5);
- NackPackets(2, kNumSentPackets, &ack_frame);
- manager_.OnIncomingAck(ack_frame, clock_.Now());
- EXPECT_FALSE(manager_.HasPendingRetransmissions());
- EXPECT_EQ(3u * kDefaultLength, BytesInFlight());
-}
-
-TEST_P(QuicSentPacketManagerTest, NegotiateUndoFromOptionsAtClient) {
- FLAGS_quic_loss_recovery_use_largest_acked = true;
- EXPECT_FALSE(QuicSentPacketManagerPeer::GetUndoRetransmits(&manager_));
- QuicConfig client_config;
- QuicTagVector options;
-
- options.push_back(kUNDO);
- 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_TRUE(QuicSentPacketManagerPeer::GetUndoRetransmits(&manager_));
-}
-
-TEST_P(QuicSentPacketManagerTest,
- NegotiateConservativeReceiveWindowFromOptions) {
- ValueRestore<bool> old_flag(&FLAGS_quic_ignore_srbf, false);
- EXPECT_EQ(kDefaultSocketReceiveBuffer,
- QuicSentPacketManagerPeer::GetReceiveWindow(&manager_));
-
- // Try to set a size below the minimum and ensure it gets set to the min.
- QuicConfig client_config;
- QuicConfigPeer::SetReceivedSocketReceiveBuffer(&client_config, 1024);
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- EXPECT_CALL(*send_algorithm_,
- SetMaxCongestionWindow(kMinSocketReceiveBuffer * 0.6));
- EXPECT_CALL(*send_algorithm_, PacingRate(_))
- .WillRepeatedly(Return(QuicBandwidth::Zero()));
- EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
- .WillOnce(Return(10 * kDefaultTCPMSS));
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- manager_.SetFromConfig(client_config);
-
- EXPECT_EQ(kMinSocketReceiveBuffer,
- QuicSentPacketManagerPeer::GetReceiveWindow(&manager_));
-
- // Ensure the smaller send window only allows 16 packets to be sent.
- QuicPathId path_id = kInvalidPathId;
- for (QuicPacketNumber i = 1; i <= 16; ++i) {
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillOnce(Return(QuicTime::Delta::Zero()));
- EXPECT_EQ(QuicTime::Delta::Zero(),
- manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA,
- &path_id));
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, BytesInFlight(), i, kDefaultLength,
- HAS_RETRANSMITTABLE_DATA))
- .WillOnce(Return(true));
- SerializedPacket packet(CreatePacket(i, true));
- manager_.OnPacketSent(&packet, kInvalidPathId, 0, clock_.Now(),
- NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
- }
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillOnce(Return(QuicTime::Delta::Infinite()));
- EXPECT_EQ(
- QuicTime::Delta::Infinite(),
- manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
-}
-
-TEST_P(QuicSentPacketManagerTest, ReceiveWindowLimited) {
- ValueRestore<bool> old_flag(&FLAGS_quic_ignore_srbf, false);
- EXPECT_EQ(kDefaultSocketReceiveBuffer,
- QuicSentPacketManagerPeer::GetReceiveWindow(&manager_));
-
- // Ensure the smaller send window only allows 256 * 0.95 packets to be sent.
- QuicPathId path_id = kInvalidPathId;
- for (QuicPacketNumber i = 1; i <= 244; ++i) {
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillOnce(Return(QuicTime::Delta::Zero()));
- EXPECT_EQ(QuicTime::Delta::Zero(),
- manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA,
- &path_id));
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, BytesInFlight(), i, kDefaultLength,
- HAS_RETRANSMITTABLE_DATA))
- .WillOnce(Return(true));
- SerializedPacket packet(CreatePacket(i, true));
- manager_.OnPacketSent(&packet, kInvalidPathId, 0, clock_.Now(),
- NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
- }
- EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
- .WillOnce(Return(QuicTime::Delta::Infinite()));
- EXPECT_EQ(
- QuicTime::Delta::Infinite(),
- manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
-}
-
-TEST_P(QuicSentPacketManagerTest, UseInitialRoundTripTimeToSend) {
- uint32_t initial_rtt_us = 325000;
- EXPECT_NE(initial_rtt_us,
- manager_.GetRttStats()->smoothed_rtt().ToMicroseconds());
-
- QuicConfig config;
- config.SetInitialRoundTripTimeUsToSend(initial_rtt_us);
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
- EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
- manager_.SetFromConfig(config);
-
- EXPECT_EQ(0, manager_.GetRttStats()->smoothed_rtt().ToMicroseconds());
- EXPECT_EQ(initial_rtt_us, manager_.GetRttStats()->initial_rtt_us());
-}
-
-TEST_P(QuicSentPacketManagerTest, ResumeConnectionState) {
- // The sent packet manager should use the RTT from CachedNetworkParameters if
- // it is provided.
- const int kRttMs = 1234;
- CachedNetworkParameters cached_network_params;
- cached_network_params.set_min_rtt_ms(kRttMs);
-
- EXPECT_CALL(*send_algorithm_, ResumeConnectionState(_, false));
- manager_.ResumeConnectionState(cached_network_params, false);
- EXPECT_EQ(kRttMs * kNumMicrosPerMilli,
- static_cast<uint64_t>(manager_.GetRttStats()->initial_rtt_us()));
-}
-
-TEST_P(QuicSentPacketManagerTest, ConnectionMigrationUnspecifiedChange) {
- RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
- int64_t default_init_rtt = rtt_stats->initial_rtt_us();
- rtt_stats->set_initial_rtt_us(default_init_rtt * 2);
- EXPECT_EQ(2 * default_init_rtt, rtt_stats->initial_rtt_us());
-
- QuicSentPacketManagerPeer::SetConsecutiveRtoCount(&manager_, 1);
- EXPECT_EQ(1u, manager_.GetConsecutiveRtoCount());
- QuicSentPacketManagerPeer::SetConsecutiveTlpCount(&manager_, 2);
- EXPECT_EQ(2u, manager_.GetConsecutiveTlpCount());
-
- EXPECT_CALL(*send_algorithm_, OnConnectionMigration());
- manager_.OnConnectionMigration(kDefaultPathId, UNSPECIFIED_CHANGE);
-
- EXPECT_EQ(default_init_rtt, rtt_stats->initial_rtt_us());
- EXPECT_EQ(0u, manager_.GetConsecutiveRtoCount());
- EXPECT_EQ(0u, manager_.GetConsecutiveTlpCount());
-}
-
-TEST_P(QuicSentPacketManagerTest, ConnectionMigrationIPSubnetChange) {
- RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
- int64_t default_init_rtt = rtt_stats->initial_rtt_us();
- rtt_stats->set_initial_rtt_us(default_init_rtt * 2);
- EXPECT_EQ(2 * default_init_rtt, rtt_stats->initial_rtt_us());
-
- QuicSentPacketManagerPeer::SetConsecutiveRtoCount(&manager_, 1);
- EXPECT_EQ(1u, manager_.GetConsecutiveRtoCount());
- QuicSentPacketManagerPeer::SetConsecutiveTlpCount(&manager_, 2);
- EXPECT_EQ(2u, manager_.GetConsecutiveTlpCount());
-
- manager_.OnConnectionMigration(kDefaultPathId, IPV4_SUBNET_CHANGE);
-
- EXPECT_EQ(2 * default_init_rtt, rtt_stats->initial_rtt_us());
- EXPECT_EQ(1u, manager_.GetConsecutiveRtoCount());
- EXPECT_EQ(2u, manager_.GetConsecutiveTlpCount());
-}
-
-TEST_P(QuicSentPacketManagerTest, ConnectionMigrationPortChange) {
- RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
- int64_t default_init_rtt = rtt_stats->initial_rtt_us();
- rtt_stats->set_initial_rtt_us(default_init_rtt * 2);
- EXPECT_EQ(2 * default_init_rtt, rtt_stats->initial_rtt_us());
-
- QuicSentPacketManagerPeer::SetConsecutiveRtoCount(&manager_, 1);
- EXPECT_EQ(1u, manager_.GetConsecutiveRtoCount());
- QuicSentPacketManagerPeer::SetConsecutiveTlpCount(&manager_, 2);
- EXPECT_EQ(2u, manager_.GetConsecutiveTlpCount());
-
- manager_.OnConnectionMigration(kDefaultPathId, PORT_CHANGE);
-
- EXPECT_EQ(2 * default_init_rtt, rtt_stats->initial_rtt_us());
- EXPECT_EQ(1u, manager_.GetConsecutiveRtoCount());
- EXPECT_EQ(2u, manager_.GetConsecutiveTlpCount());
-}
-
-TEST_P(QuicSentPacketManagerTest, PathMtuIncreased) {
- FLAGS_quic_no_mtu_discovery_ack_listener = true;
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), 1, _, _))
- .Times(1)
- .WillOnce(Return(true));
- SerializedPacket packet(kDefaultPathId, 1, PACKET_6BYTE_PACKET_NUMBER,
- nullptr, kDefaultLength + 100, 0u, false, false);
- manager_.OnPacketSent(&packet, kInvalidPathId, 0, clock_.Now(),
- NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
-
- // Ack the large packet and expect the path MTU to increase.
- ExpectAck(1);
- EXPECT_CALL(*network_change_visitor_,
- OnPathMtuIncreased(kDefaultLength + 100));
- QuicAckFrame ack_frame = InitAckFrame(1);
- manager_.OnIncomingAck(ack_frame, clock_.Now());
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_server_id.cc b/chromium/net/quic/quic_server_id.cc
deleted file mode 100644
index b810bb3745b..00000000000
--- a/chromium/net/quic/quic_server_id.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_server_id.h"
-
-#include <tuple>
-
-#include "base/logging.h"
-#include "net/base/host_port_pair.h"
-#include "net/base/port_util.h"
-#include "url/gurl.h"
-
-using std::string;
-
-namespace net {
-
-QuicServerId::QuicServerId() : privacy_mode_(PRIVACY_MODE_DISABLED) {}
-
-QuicServerId::QuicServerId(const HostPortPair& host_port_pair,
- PrivacyMode privacy_mode)
- : host_port_pair_(host_port_pair), privacy_mode_(privacy_mode) {}
-
-QuicServerId::QuicServerId(const string& host, uint16_t port)
- : host_port_pair_(host, port), privacy_mode_(PRIVACY_MODE_DISABLED) {}
-
-QuicServerId::QuicServerId(const string& host,
- uint16_t port,
- PrivacyMode privacy_mode)
- : host_port_pair_(host, port), privacy_mode_(privacy_mode) {}
-
-QuicServerId::~QuicServerId() {}
-
-bool QuicServerId::operator<(const QuicServerId& other) const {
- return std::tie(host_port_pair_, privacy_mode_) <
- std::tie(other.host_port_pair_, other.privacy_mode_);
-}
-
-bool QuicServerId::operator==(const QuicServerId& other) const {
- return privacy_mode_ == other.privacy_mode_ &&
- host_port_pair_.Equals(other.host_port_pair_);
-}
-
-// static
-QuicServerId QuicServerId::FromString(const std::string& str) {
- GURL url(str);
- if (!url.is_valid())
- return QuicServerId();
- return QuicServerId(HostPortPair::FromURL(url), url.path() == "/private"
- ? PRIVACY_MODE_ENABLED
- : PRIVACY_MODE_DISABLED);
-}
-
-string QuicServerId::ToString() const {
- return "https://" + host_port_pair_.ToString() +
- (privacy_mode_ == PRIVACY_MODE_ENABLED ? "/private" : "");
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_server_id_test.cc b/chromium/net/quic/quic_server_id_test.cc
deleted file mode 100644
index 5c88067cd90..00000000000
--- a/chromium/net/quic/quic_server_id_test.cc
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_server_id.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::string;
-
-namespace net {
-
-namespace {
-
-TEST(QuicServerIdTest, ToString) {
- HostPortPair google_host_port_pair("google.com", 10);
-
- QuicServerId google_server_id(google_host_port_pair, PRIVACY_MODE_DISABLED);
- string google_server_id_str = google_server_id.ToString();
- EXPECT_EQ("https://google.com:10", google_server_id_str);
-
- QuicServerId private_server_id(google_host_port_pair, PRIVACY_MODE_ENABLED);
- string private_server_id_str = private_server_id.ToString();
- EXPECT_EQ("https://google.com:10/private", private_server_id_str);
-}
-
-TEST(QuicServerIdTest, LessThan) {
- QuicServerId a_10_https(HostPortPair("a.com", 10), PRIVACY_MODE_DISABLED);
- QuicServerId a_11_https(HostPortPair("a.com", 11), PRIVACY_MODE_DISABLED);
- QuicServerId b_10_https(HostPortPair("b.com", 10), PRIVACY_MODE_DISABLED);
- QuicServerId b_11_https(HostPortPair("b.com", 11), PRIVACY_MODE_DISABLED);
-
- QuicServerId a_10_https_private(HostPortPair("a.com", 10),
- PRIVACY_MODE_ENABLED);
- QuicServerId a_11_https_private(HostPortPair("a.com", 11),
- PRIVACY_MODE_ENABLED);
- QuicServerId b_10_https_private(HostPortPair("b.com", 10),
- PRIVACY_MODE_ENABLED);
- QuicServerId b_11_https_private(HostPortPair("b.com", 11),
- PRIVACY_MODE_ENABLED);
-
- // Test combinations of host, port, and privacy being same on left and
- // right side of less than.
- EXPECT_FALSE(a_10_https < a_10_https);
- EXPECT_TRUE(a_10_https < a_10_https_private);
- EXPECT_FALSE(a_10_https_private < a_10_https);
- EXPECT_FALSE(a_10_https_private < a_10_https_private);
-
- // Test with either host, port or https being different on left and right side
- // of less than.
- PrivacyMode left_privacy;
- PrivacyMode right_privacy;
- for (int i = 0; i < 4; i++) {
- left_privacy = static_cast<PrivacyMode>(i / 2);
- right_privacy = static_cast<PrivacyMode>(i % 2);
- QuicServerId a_10_https_left_private(HostPortPair("a.com", 10),
- left_privacy);
- QuicServerId a_10_https_right_private(HostPortPair("a.com", 10),
- right_privacy);
- QuicServerId a_11_https_left_private(HostPortPair("a.com", 11),
- left_privacy);
- QuicServerId a_11_https_right_private(HostPortPair("a.com", 11),
- right_privacy);
-
- QuicServerId b_10_https_left_private(HostPortPair("b.com", 10),
- left_privacy);
- QuicServerId b_10_https_right_private(HostPortPair("b.com", 10),
- right_privacy);
- QuicServerId b_11_https_left_private(HostPortPair("b.com", 11),
- left_privacy);
- QuicServerId b_11_https_right_private(HostPortPair("b.com", 11),
- right_privacy);
-
- EXPECT_TRUE(a_10_https_left_private < a_11_https_right_private);
- EXPECT_TRUE(a_10_https_left_private < b_10_https_right_private);
- EXPECT_TRUE(a_10_https_left_private < b_11_https_right_private);
- EXPECT_FALSE(a_11_https_left_private < a_10_https_right_private);
- EXPECT_FALSE(a_11_https_left_private < b_10_https_right_private);
- EXPECT_TRUE(a_11_https_left_private < b_11_https_right_private);
- EXPECT_FALSE(b_10_https_left_private < a_10_https_right_private);
- EXPECT_TRUE(b_10_https_left_private < a_11_https_right_private);
- EXPECT_TRUE(b_10_https_left_private < b_11_https_right_private);
- EXPECT_FALSE(b_11_https_left_private < a_10_https_right_private);
- EXPECT_FALSE(b_11_https_left_private < a_11_https_right_private);
- EXPECT_FALSE(b_11_https_left_private < b_10_https_right_private);
- }
-}
-
-TEST(QuicServerIdTest, Equals) {
- PrivacyMode left_privacy;
- PrivacyMode right_privacy;
- for (int i = 0; i < 2; i++) {
- left_privacy = right_privacy = static_cast<PrivacyMode>(i);
- QuicServerId a_10_https_right_private(HostPortPair("a.com", 10),
- right_privacy);
- QuicServerId a_11_https_right_private(HostPortPair("a.com", 11),
- right_privacy);
- QuicServerId b_10_https_right_private(HostPortPair("b.com", 10),
- right_privacy);
- QuicServerId b_11_https_right_private(HostPortPair("b.com", 11),
- right_privacy);
-
- QuicServerId new_a_10_https_left_private(HostPortPair("a.com", 10),
- left_privacy);
- QuicServerId new_a_11_https_left_private(HostPortPair("a.com", 11),
- left_privacy);
- QuicServerId new_b_10_https_left_private(HostPortPair("b.com", 10),
- left_privacy);
- QuicServerId new_b_11_https_left_private(HostPortPair("b.com", 11),
- left_privacy);
-
- EXPECT_EQ(new_a_10_https_left_private, a_10_https_right_private);
- EXPECT_EQ(new_a_11_https_left_private, a_11_https_right_private);
- EXPECT_EQ(new_b_10_https_left_private, b_10_https_right_private);
- EXPECT_EQ(new_b_11_https_left_private, b_11_https_right_private);
- }
-
- for (int i = 0; i < 2; i++) {
- right_privacy = static_cast<PrivacyMode>(i);
- QuicServerId a_10_https_right_private(HostPortPair("a.com", 10),
- right_privacy);
- QuicServerId a_11_https_right_private(HostPortPair("a.com", 11),
- right_privacy);
- QuicServerId b_10_https_right_private(HostPortPair("b.com", 10),
- right_privacy);
- QuicServerId b_11_https_right_private(HostPortPair("b.com", 11),
- right_privacy);
-
- QuicServerId new_a_10_https_left_private(HostPortPair("a.com", 10),
- PRIVACY_MODE_DISABLED);
-
- EXPECT_FALSE(new_a_10_https_left_private == a_11_https_right_private);
- EXPECT_FALSE(new_a_10_https_left_private == b_10_https_right_private);
- EXPECT_FALSE(new_a_10_https_left_private == b_11_https_right_private);
- }
- QuicServerId a_10_https_private(HostPortPair("a.com", 10),
- PRIVACY_MODE_ENABLED);
- QuicServerId new_a_10_https_no_private(HostPortPair("a.com", 10),
- PRIVACY_MODE_DISABLED);
- EXPECT_FALSE(new_a_10_https_no_private == a_10_https_private);
-}
-
-} // namespace
-
-} // namespace net
diff --git a/chromium/net/quic/quic_server_session_base.cc b/chromium/net/quic/quic_server_session_base.cc
deleted file mode 100644
index 03e13e2e5a4..00000000000
--- a/chromium/net/quic/quic_server_session_base.cc
+++ /dev/null
@@ -1,257 +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/quic_server_session_base.h"
-
-#include "base/logging.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_spdy_session.h"
-#include "net/quic/reliable_quic_stream.h"
-
-using std::string;
-
-namespace net {
-
-QuicServerSessionBase::QuicServerSessionBase(
- const QuicConfig& config,
- QuicConnection* connection,
- Visitor* visitor,
- Helper* helper,
- const QuicCryptoServerConfig* crypto_config,
- QuicCompressedCertsCache* compressed_certs_cache)
- : QuicSpdySession(connection, config),
- crypto_config_(crypto_config),
- compressed_certs_cache_(compressed_certs_cache),
- visitor_(visitor),
- helper_(helper),
- bandwidth_resumption_enabled_(false),
- bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
- last_scup_time_(QuicTime::Zero()),
- last_scup_packet_number_(0),
- server_push_enabled_(false) {}
-
-QuicServerSessionBase::~QuicServerSessionBase() {}
-
-void QuicServerSessionBase::Initialize() {
- crypto_stream_.reset(
- CreateQuicCryptoServerStream(crypto_config_, compressed_certs_cache_));
- QuicSpdySession::Initialize();
-}
-
-void QuicServerSessionBase::OnConfigNegotiated() {
- QuicSession::OnConfigNegotiated();
-
- if (!config()->HasReceivedConnectionOptions()) {
- return;
- }
-
- // Enable bandwidth resumption if peer sent correct connection options.
- const bool last_bandwidth_resumption =
- ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE);
- const bool max_bandwidth_resumption =
- ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWMX);
- bandwidth_resumption_enabled_ =
- last_bandwidth_resumption || max_bandwidth_resumption;
- server_push_enabled_ =
- ContainsQuicTag(config()->ReceivedConnectionOptions(), kSPSH);
-
- // If the client has provided a bandwidth estimate from the same serving
- // region as this server, then decide whether to use the data for bandwidth
- // resumption.
- const CachedNetworkParameters* cached_network_params =
- crypto_stream_->PreviousCachedNetworkParams();
- if (cached_network_params != nullptr &&
- cached_network_params->serving_region() == serving_region_) {
- // Log the received connection parameters, regardless of how they
- // get used for bandwidth resumption.
- connection()->OnReceiveConnectionState(*cached_network_params);
-
- if (bandwidth_resumption_enabled_) {
- // Only do bandwidth resumption if estimate is recent enough.
- const int64_t seconds_since_estimate =
- connection()->clock()->WallNow().ToUNIXSeconds() -
- cached_network_params->timestamp();
- if (seconds_since_estimate <= kNumSecondsPerHour) {
- connection()->ResumeConnectionState(*cached_network_params,
- max_bandwidth_resumption);
- }
- }
- }
-}
-
-void QuicServerSessionBase::OnConnectionClosed(QuicErrorCode error,
- const string& error_details,
- ConnectionCloseSource source) {
- QuicSession::OnConnectionClosed(error, error_details, source);
- // In the unlikely event we get a connection close while doing an asynchronous
- // crypto event, make sure we cancel the callback.
- if (crypto_stream_.get() != nullptr) {
- crypto_stream_->CancelOutstandingCallbacks();
- }
- visitor_->OnConnectionClosed(connection()->connection_id(), error,
- error_details);
-}
-
-void QuicServerSessionBase::OnWriteBlocked() {
- QuicSession::OnWriteBlocked();
- visitor_->OnWriteBlocked(connection());
-}
-
-void QuicServerSessionBase::OnCongestionWindowChange(QuicTime now) {
- if (!bandwidth_resumption_enabled_) {
- return;
- }
- // Only send updates when the application has no data to write.
- if (HasDataToWrite()) {
- return;
- }
-
- // If not enough time has passed since the last time we sent an update to the
- // client, or not enough packets have been sent, then return early.
- const QuicSentPacketManagerInterface& sent_packet_manager =
- connection()->sent_packet_manager();
- int64_t srtt_ms =
- sent_packet_manager.GetRttStats()->smoothed_rtt().ToMilliseconds();
- int64_t now_ms = now.Subtract(last_scup_time_).ToMilliseconds();
- int64_t packets_since_last_scup =
- connection()->packet_number_of_last_sent_packet() -
- last_scup_packet_number_;
- if (now_ms < (kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms) ||
- now_ms < kMinIntervalBetweenServerConfigUpdatesMs ||
- packets_since_last_scup < kMinPacketsBetweenServerConfigUpdates) {
- return;
- }
-
- // If the bandwidth recorder does not have a valid estimate, return early.
- const QuicSustainedBandwidthRecorder& bandwidth_recorder =
- sent_packet_manager.SustainedBandwidthRecorder();
- if (!bandwidth_recorder.HasEstimate()) {
- return;
- }
-
- // The bandwidth recorder has recorded at least one sustained bandwidth
- // estimate. Check that it's substantially different from the last one that
- // we sent to the client, and if so, send the new one.
- QuicBandwidth new_bandwidth_estimate = bandwidth_recorder.BandwidthEstimate();
-
- int64_t bandwidth_delta =
- std::abs(new_bandwidth_estimate.ToBitsPerSecond() -
- bandwidth_estimate_sent_to_client_.ToBitsPerSecond());
-
- // Define "substantial" difference as a 50% increase or decrease from the
- // last estimate.
- bool substantial_difference =
- bandwidth_delta >
- 0.5 * bandwidth_estimate_sent_to_client_.ToBitsPerSecond();
- if (!substantial_difference) {
- return;
- }
-
- bandwidth_estimate_sent_to_client_ = new_bandwidth_estimate;
- DVLOG(1) << "Server: sending new bandwidth estimate (KBytes/s): "
- << bandwidth_estimate_sent_to_client_.ToKBytesPerSecond();
-
- // Include max bandwidth in the update.
- QuicBandwidth max_bandwidth_estimate =
- bandwidth_recorder.MaxBandwidthEstimate();
- int32_t max_bandwidth_timestamp = bandwidth_recorder.MaxBandwidthTimestamp();
-
- // Fill the proto before passing it to the crypto stream to send.
- const int32_t bw_estimate_bytes_per_second =
- BandwidthToCachedParameterBytesPerSecond(
- bandwidth_estimate_sent_to_client_);
- const int32_t max_bw_estimate_bytes_per_second =
- BandwidthToCachedParameterBytesPerSecond(max_bandwidth_estimate);
- QUIC_BUG_IF(max_bw_estimate_bytes_per_second < 0)
- << max_bw_estimate_bytes_per_second;
- QUIC_BUG_IF(bw_estimate_bytes_per_second < 0) << bw_estimate_bytes_per_second;
-
- CachedNetworkParameters cached_network_params;
- cached_network_params.set_bandwidth_estimate_bytes_per_second(
- bw_estimate_bytes_per_second);
- cached_network_params.set_max_bandwidth_estimate_bytes_per_second(
- max_bw_estimate_bytes_per_second);
- cached_network_params.set_max_bandwidth_timestamp_seconds(
- max_bandwidth_timestamp);
- cached_network_params.set_min_rtt_ms(
- sent_packet_manager.GetRttStats()->min_rtt().ToMilliseconds());
- cached_network_params.set_previous_connection_state(
- bandwidth_recorder.EstimateRecordedDuringSlowStart()
- ? CachedNetworkParameters::SLOW_START
- : CachedNetworkParameters::CONGESTION_AVOIDANCE);
- cached_network_params.set_timestamp(
- connection()->clock()->WallNow().ToUNIXSeconds());
- if (!serving_region_.empty()) {
- cached_network_params.set_serving_region(serving_region_);
- }
-
- crypto_stream_->SendServerConfigUpdate(&cached_network_params);
-
- connection()->OnSendConnectionState(cached_network_params);
-
- last_scup_time_ = now;
- last_scup_packet_number_ = connection()->packet_number_of_last_sent_packet();
-}
-
-QuicConnectionId QuicServerSessionBase::GenerateConnectionIdForReject(
- QuicConnectionId connection_id) {
- return helper_->GenerateConnectionIdForReject(connection_id);
-}
-
-bool QuicServerSessionBase::CanAcceptClientHello(
- const CryptoHandshakeMessage& message,
- string* error_details) {
- return helper_->CanAcceptClientHello(message, connection()->self_address(),
- error_details);
-}
-
-bool QuicServerSessionBase::ShouldCreateIncomingDynamicStream(QuicStreamId id) {
- if (!connection()->connected()) {
- QUIC_BUG << "ShouldCreateIncomingDynamicStream called when disconnected";
- return false;
- }
-
- if (id % 2 == 0) {
- DVLOG(1) << "Invalid incoming even stream_id:" << id;
- connection()->CloseConnection(
- QUIC_INVALID_STREAM_ID, "Client created even numbered stream",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return false;
- }
- return true;
-}
-
-bool QuicServerSessionBase::ShouldCreateOutgoingDynamicStream() {
- if (!connection()->connected()) {
- QUIC_BUG << "ShouldCreateOutgoingDynamicStream called when disconnected";
- return false;
- }
- if (!crypto_stream_->encryption_established()) {
- QUIC_BUG << "Encryption not established so no outgoing stream created.";
- return false;
- }
- if (GetNumOpenOutgoingStreams() >= max_open_outgoing_streams()) {
- VLOG(1) << "No more streams should be created. "
- << "Already " << GetNumOpenOutgoingStreams() << " open.";
- return false;
- }
- return true;
-}
-
-QuicCryptoServerStreamBase* QuicServerSessionBase::GetCryptoStream() {
- return crypto_stream_.get();
-}
-
-int32_t QuicServerSessionBase::BandwidthToCachedParameterBytesPerSecond(
- const QuicBandwidth& bandwidth) {
- int64_t bytes_per_second = bandwidth.ToBytesPerSecond();
- return (bytes_per_second > static_cast<int64_t>(INT32_MAX)
- ? INT32_MAX
- : static_cast<int32_t>(bytes_per_second));
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_server_session_base.h b/chromium/net/quic/quic_server_session_base.h
deleted file mode 100644
index 49f93e811de..00000000000
--- a/chromium/net/quic/quic_server_session_base.h
+++ /dev/null
@@ -1,189 +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.
-//
-// A server specific QuicSession subclass.
-
-#ifndef NET_QUIC_QUIC_SERVER_SESSION_BASE_H_
-#define NET_QUIC_QUIC_SERVER_SESSION_BASE_H_
-
-#include <stdint.h>
-
-#include <cstdint>
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "net/quic/crypto/quic_compressed_certs_cache.h"
-#include "net/quic/quic_crypto_server_stream.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_spdy_session.h"
-
-namespace net {
-
-class QuicBlockedWriterInterface;
-class QuicConfig;
-class QuicConnection;
-class QuicCryptoServerConfig;
-class ReliableQuicStream;
-
-namespace test {
-class QuicServerSessionBasePeer;
-class QuicSimpleServerSessionPeer;
-} // namespace test
-
-class NET_EXPORT_PRIVATE QuicServerSessionBase : public QuicSpdySession {
- public:
- // An interface from the session to the entity owning the session.
- // This lets the session notify its owner (the Dispatcher) when the connection
- // is closed, blocked, or added/removed from the time-wait std::list.
- class Visitor {
- public:
- virtual ~Visitor() {}
-
- // Called when the connection is closed.
- virtual void OnConnectionClosed(QuicConnectionId connection_id,
- QuicErrorCode error,
- const std::string& error_details) = 0;
-
- // Called when the session has become write blocked.
- virtual void OnWriteBlocked(QuicBlockedWriterInterface* blocked_writer) = 0;
-
- // Called after the given connection is added to the time-wait std::list.
- virtual void OnConnectionAddedToTimeWaitList(
- QuicConnectionId connection_id) = 0;
- };
-
- // Provides helper functions for the session.
- class Helper {
- public:
- virtual ~Helper() {}
-
- // Given the current connection_id, generates a new ConnectionId to
- // be returned with a stateless reject.
- virtual QuicConnectionId GenerateConnectionIdForReject(
- QuicConnectionId connection_id) const = 0;
-
- // Returns true if |message|, which was received on |self_address| is
- // acceptable according to the visitor's policy. Otherwise, returns false
- // and populates |error_details|.
- virtual bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
- const IPEndPoint& self_address,
- std::string* error_details) const = 0;
- };
-
- // |crypto_config| must outlive the session.
- QuicServerSessionBase(const QuicConfig& config,
- QuicConnection* connection,
- Visitor* visitor,
- Helper* helper,
- const QuicCryptoServerConfig* crypto_config,
- QuicCompressedCertsCache* compressed_certs_cache);
-
- // Override the base class to notify the owner of the connection close.
- void OnConnectionClosed(QuicErrorCode error,
- const std::string& error_details,
- ConnectionCloseSource source) override;
- void OnWriteBlocked() override;
-
- // Sends a server config update to the client, containing new bandwidth
- // estimate.
- void OnCongestionWindowChange(QuicTime now) override;
-
- ~QuicServerSessionBase() override;
-
- void Initialize() override;
-
- const QuicCryptoServerStreamBase* crypto_stream() const {
- return crypto_stream_.get();
- }
-
- // Override base class to process bandwidth related config received from
- // client.
- void OnConfigNegotiated() override;
-
- void set_serving_region(const std::string& serving_region) {
- serving_region_ = serving_region;
- }
-
- bool server_push_enabled() const { return server_push_enabled_; }
-
- // Delegates to the helper's GenerateConnectionIdForReject method.
- QuicConnectionId GenerateConnectionIdForReject(
- QuicConnectionId connection_id);
-
- // Delegates to the helper's CanAcceptClientHello method.
- bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
- std::string* error_details);
-
- protected:
- // QuicSession methods(override them with return type of QuicSpdyStream*):
- QuicCryptoServerStreamBase* GetCryptoStream() override;
-
- // If an outgoing stream can be created, return true.
- // Return false when connection is closed or forward secure encryption hasn't
- // established yet or number of server initiated streams already reaches the
- // upper limit.
- bool ShouldCreateOutgoingDynamicStream() override;
-
- // If we should create an incoming stream, returns true. Otherwise
- // does error handling, including communicating the error to the client and
- // possibly closing the connection, and returns false.
- bool ShouldCreateIncomingDynamicStream(QuicStreamId id) override;
-
- virtual QuicCryptoServerStreamBase* CreateQuicCryptoServerStream(
- const QuicCryptoServerConfig* crypto_config,
- QuicCompressedCertsCache* compressed_certs_cache) = 0;
-
- const QuicCryptoServerConfig* crypto_config() { return crypto_config_; }
-
- void set_server_push_enabled(bool enable) { server_push_enabled_ = enable; }
-
- private:
- friend class test::QuicServerSessionBasePeer;
- friend class test::QuicSimpleServerSessionPeer;
-
- const QuicCryptoServerConfig* crypto_config_;
-
- // The cache which contains most recently compressed certs.
- // Owned by QuicDispatcher.
- QuicCompressedCertsCache* compressed_certs_cache_;
-
- std::unique_ptr<QuicCryptoServerStreamBase> crypto_stream_;
- Visitor* visitor_;
- Helper* helper_;
-
- // Whether bandwidth resumption is enabled for this connection.
- bool bandwidth_resumption_enabled_;
-
- // The most recent bandwidth estimate sent to the client.
- QuicBandwidth bandwidth_estimate_sent_to_client_;
-
- // Text describing server location. Sent to the client as part of the bandwith
- // estimate in the source-address token. Optional, can be left empty.
- std::string serving_region_;
-
- // Time at which we send the last SCUP to the client.
- QuicTime last_scup_time_;
-
- // Number of packets sent to the peer, at the time we last sent a SCUP.
- int64_t last_scup_packet_number_;
-
- // Converts QuicBandwidth to an int32 bytes/second that can be
- // stored in CachedNetworkParameters. TODO(jokulik): This function
- // should go away once we fix http://b//27897982
- int32_t BandwidthToCachedParameterBytesPerSecond(
- const QuicBandwidth& bandwidth);
-
- // Set during handshake. If true, resources in x-associated-content and link
- // headers will be pushed. see: go/gfe_server_push.
- bool server_push_enabled_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicServerSessionBase);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_SERVER_SESSION_BASE_H_
diff --git a/chromium/net/quic/quic_server_session_base_test.cc b/chromium/net/quic/quic_server_session_base_test.cc
deleted file mode 100644
index 96479f12512..00000000000
--- a/chromium/net/quic/quic_server_session_base_test.cc
+++ /dev/null
@@ -1,573 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_server_session_base.h"
-
-#include <cstdint>
-#include <memory>
-
-#include "base/macros.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_crypto_server_stream.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/quic/test_tools/quic_config_peer.h"
-#include "net/quic/test_tools/quic_connection_peer.h"
-#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
-#include "net/quic/test_tools/quic_session_peer.h"
-#include "net/quic/test_tools/quic_spdy_session_peer.h"
-#include "net/quic/test_tools/quic_spdy_stream_peer.h"
-#include "net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/test/gtest_util.h"
-#include "net/tools/quic/quic_simple_server_stream.h"
-#include "net/tools/quic/test_tools/mock_quic_server_session_visitor.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using net::test::CryptoTestUtils;
-using net::test::MockQuicConnection;
-using net::test::MockQuicConnectionHelper;
-using net::test::QuicConfigPeer;
-using net::test::QuicConnectionPeer;
-using net::test::QuicSpdyStreamPeer;
-using net::test::QuicSentPacketManagerPeer;
-using net::test::QuicSessionPeer;
-using net::test::QuicSpdySessionPeer;
-using net::test::QuicSustainedBandwidthRecorderPeer;
-using net::test::SupportedVersions;
-using net::test::ValueRestore;
-using net::test::kClientDataStreamId1;
-using net::test::kClientDataStreamId2;
-using net::test::kClientDataStreamId3;
-using net::test::kInitialSessionFlowControlWindowForTest;
-using net::test::kInitialStreamFlowControlWindowForTest;
-using std::string;
-using testing::StrictMock;
-using testing::_;
-
-namespace net {
-namespace test {
-
-class QuicServerSessionBasePeer {
- public:
- static ReliableQuicStream* GetOrCreateDynamicStream(QuicServerSessionBase* s,
- QuicStreamId id) {
- return s->GetOrCreateDynamicStream(id);
- }
- static void SetCryptoStream(QuicServerSessionBase* s,
- QuicCryptoServerStream* crypto_stream) {
- s->crypto_stream_.reset(crypto_stream);
- s->static_streams()[kCryptoStreamId] = crypto_stream;
- }
- static bool IsBandwidthResumptionEnabled(QuicServerSessionBase* s) {
- return s->bandwidth_resumption_enabled_;
- }
-};
-
-namespace {
-
-class TestServerSession : public QuicServerSessionBase {
- public:
- TestServerSession(const QuicConfig& config,
- QuicConnection* connection,
- QuicServerSessionBase::Visitor* visitor,
- QuicServerSessionBase::Helper* helper,
- const QuicCryptoServerConfig* crypto_config,
- QuicCompressedCertsCache* compressed_certs_cache)
- : QuicServerSessionBase(config,
- connection,
- visitor,
- helper,
- crypto_config,
- compressed_certs_cache) {}
-
- ~TestServerSession() override{};
-
- protected:
- QuicSpdyStream* CreateIncomingDynamicStream(QuicStreamId id) override {
- if (!ShouldCreateIncomingDynamicStream(id)) {
- return nullptr;
- }
- QuicSpdyStream* stream = new QuicSimpleServerStream(id, this);
- ActivateStream(stream);
- return stream;
- }
-
- QuicSpdyStream* CreateOutgoingDynamicStream(SpdyPriority priority) override {
- if (!ShouldCreateOutgoingDynamicStream()) {
- return nullptr;
- }
-
- QuicSpdyStream* stream =
- new QuicSimpleServerStream(GetNextOutgoingStreamId(), this);
- stream->SetPriority(priority);
- ActivateStream(stream);
- return stream;
- }
-
- QuicCryptoServerStreamBase* CreateQuicCryptoServerStream(
- const QuicCryptoServerConfig* crypto_config,
- QuicCompressedCertsCache* compressed_certs_cache) override {
- return new QuicCryptoServerStream(
- crypto_config, compressed_certs_cache,
- FLAGS_enable_quic_stateless_reject_support, this);
- }
-};
-
-const size_t kMaxStreamsForTest = 10;
-
-class QuicServerSessionBaseTest : public ::testing::TestWithParam<QuicVersion> {
- protected:
- QuicServerSessionBaseTest()
- : crypto_config_(QuicCryptoServerConfig::TESTING,
- QuicRandom::GetInstance(),
- CryptoTestUtils::ProofSourceForTesting()),
- compressed_certs_cache_(
- QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) {
- FLAGS_quic_always_log_bugs_for_tests = true;
- config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, kMaxStreamsForTest);
- config_.SetMaxIncomingDynamicStreamsToSend(kMaxStreamsForTest);
- QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams(&config_,
- kMaxStreamsForTest);
- config_.SetInitialStreamFlowControlWindowToSend(
- kInitialStreamFlowControlWindowForTest);
- config_.SetInitialSessionFlowControlWindowToSend(
- kInitialSessionFlowControlWindowForTest);
-
- connection_ = new StrictMock<MockQuicConnection>(
- &helper_, &alarm_factory_, Perspective::IS_SERVER,
- SupportedVersions(GetParam()));
- session_.reset(new TestServerSession(config_, connection_, &owner_,
- &session_helper_, &crypto_config_,
- &compressed_certs_cache_));
- MockClock clock;
- handshake_message_.reset(crypto_config_.AddDefaultConfig(
- QuicRandom::GetInstance(), &clock,
- QuicCryptoServerConfig::ConfigOptions()));
- session_->Initialize();
- visitor_ = QuicConnectionPeer::GetVisitor(connection_);
- }
-
- StrictMock<MockQuicServerSessionVisitor> owner_;
- StrictMock<MockQuicServerSessionHelper> session_helper_;
- MockQuicConnectionHelper helper_;
- MockAlarmFactory alarm_factory_;
- StrictMock<MockQuicConnection>* connection_;
- QuicConfig config_;
- QuicCryptoServerConfig crypto_config_;
- QuicCompressedCertsCache compressed_certs_cache_;
- std::unique_ptr<TestServerSession> session_;
- std::unique_ptr<CryptoHandshakeMessage> handshake_message_;
- QuicConnectionVisitorInterface* visitor_;
-};
-
-// Compares CachedNetworkParameters.
-MATCHER_P(EqualsProto, network_params, "") {
- CachedNetworkParameters reference(network_params);
- return (arg->bandwidth_estimate_bytes_per_second() ==
- reference.bandwidth_estimate_bytes_per_second() &&
- arg->bandwidth_estimate_bytes_per_second() ==
- reference.bandwidth_estimate_bytes_per_second() &&
- arg->max_bandwidth_estimate_bytes_per_second() ==
- reference.max_bandwidth_estimate_bytes_per_second() &&
- arg->max_bandwidth_timestamp_seconds() ==
- reference.max_bandwidth_timestamp_seconds() &&
- arg->min_rtt_ms() == reference.min_rtt_ms() &&
- arg->previous_connection_state() ==
- reference.previous_connection_state());
-}
-
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicServerSessionBaseTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
-
-TEST_P(QuicServerSessionBaseTest, ServerPushDisabledByDefault) {
- // Without the client explicitly sending kSPSH, server push will be disabled
- // at the server.
- EXPECT_FALSE(
- session_->config()->HasReceivedConnectionOptions() &&
- ContainsQuicTag(session_->config()->ReceivedConnectionOptions(), kSPSH));
- session_->OnConfigNegotiated();
- EXPECT_FALSE(session_->server_push_enabled());
-}
-
-TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) {
- // Open a stream, then reset it.
- // Send two bytes of payload to open it.
- QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT"));
- session_->OnStreamFrame(data1);
- EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
-
- // Send a reset (and expect the peer to send a RST in response).
- QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM,
- 0);
- EXPECT_CALL(*connection_,
- SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0));
- visitor_->OnRstStream(rst1);
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
-
- // Send the same two bytes of payload in a new packet.
- visitor_->OnStreamFrame(data1);
-
- // The stream should not be re-opened.
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
- EXPECT_TRUE(connection_->connected());
-}
-
-TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) {
- // Send a reset (and expect the peer to send a RST in response).
- QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM,
- 0);
- EXPECT_CALL(*connection_,
- SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0));
- visitor_->OnRstStream(rst1);
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
-
- // Send two bytes of payload.
- QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT"));
- visitor_->OnStreamFrame(data1);
-
- // The stream should never be opened, now that the reset is received.
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
- EXPECT_TRUE(connection_->connected());
-}
-
-TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) {
- // Send (empty) compressed headers followed by two bytes of data.
- QuicStreamFrame frame1(kClientDataStreamId1, false, 0,
- StringPiece("\1\0\0\0\0\0\0\0HT"));
- QuicStreamFrame frame2(kClientDataStreamId2, false, 0,
- StringPiece("\2\0\0\0\0\0\0\0HT"));
- visitor_->OnStreamFrame(frame1);
- visitor_->OnStreamFrame(frame2);
- EXPECT_EQ(2u, session_->GetNumOpenIncomingStreams());
-
- // Send a reset (and expect the peer to send a RST in response).
- QuicRstStreamFrame rst(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM, 0);
- EXPECT_CALL(*connection_,
- SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0));
- visitor_->OnRstStream(rst);
-
- // If we were tracking, we'd probably want to reject this because it's data
- // past the reset point of stream 3. As it's a closed stream we just drop the
- // data on the floor, but accept the packet because it has data for stream 5.
- QuicStreamFrame frame3(kClientDataStreamId1, false, 2, StringPiece("TP"));
- QuicStreamFrame frame4(kClientDataStreamId2, false, 2, StringPiece("TP"));
- visitor_->OnStreamFrame(frame3);
- visitor_->OnStreamFrame(frame4);
- // The stream should never be opened, now that the reset is received.
- EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
- EXPECT_TRUE(connection_->connected());
-}
-
-TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) {
- // Test that the server refuses if a client attempts to open too many data
- // streams. The server accepts slightly more than the negotiated stream limit
- // to deal with rare cases where a client FIN/RST is lost.
-
- if (GetParam() <= QUIC_VERSION_34) {
- EXPECT_EQ(kMaxStreamsForTest, session_->max_open_incoming_streams());
- }
-
- // The slightly increased stream limit is set during config negotiation. It
- // is either an increase of 10 over negotiated limit, or a fixed percentage
- // scaling, whichever is larger. Test both before continuing.
- session_->OnConfigNegotiated();
- EXPECT_LT(kMaxStreamsMultiplier * kMaxStreamsForTest,
- kMaxStreamsForTest + kMaxStreamsMinimumIncrement);
- EXPECT_EQ(kMaxStreamsForTest + kMaxStreamsMinimumIncrement,
- session_->max_open_incoming_streams());
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
- QuicStreamId stream_id = kClientDataStreamId1;
- // Open the max configured number of streams, should be no problem.
- for (size_t i = 0; i < kMaxStreamsForTest; ++i) {
- EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
- session_.get(), stream_id));
- stream_id += 2;
- }
-
- // Open more streams: server should accept slightly more than the limit.
- for (size_t i = 0; i < kMaxStreamsMinimumIncrement; ++i) {
- EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
- session_.get(), stream_id));
- stream_id += 2;
- }
-
- // Now violate the server's internal stream limit.
- stream_id += 2;
- if (connection_->version() <= QUIC_VERSION_27) {
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_TOO_MANY_OPEN_STREAMS, _, _));
- EXPECT_CALL(*connection_, SendRstStream(_, _, _)).Times(0);
- } else {
- EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
- EXPECT_CALL(*connection_, SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0));
- }
- // Even if the connection remains open, the stream creation should fail.
- EXPECT_FALSE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
- session_.get(), stream_id));
-}
-
-TEST_P(QuicServerSessionBaseTest, MaxAvailableStreams) {
- // Test that the server closes the connection if a client makes too many data
- // streams available. The server accepts slightly more than the negotiated
- // stream limit to deal with rare cases where a client FIN/RST is lost.
-
- if (GetParam() <= QUIC_VERSION_34) {
- // The slightly increased stream limit is set during config negotiation.
- EXPECT_EQ(kMaxStreamsForTest, session_->max_open_incoming_streams());
- }
- session_->OnConfigNegotiated();
- const size_t kAvailableStreamLimit = session_->MaxAvailableStreams();
- EXPECT_EQ(
- session_->max_open_incoming_streams() * kMaxAvailableStreamsMultiplier,
- session_->MaxAvailableStreams());
- // The protocol specification requires that there can be at least 10 times
- // as many available streams as the connection's maximum open streams.
- EXPECT_LE(10 * kMaxStreamsForTest, kAvailableStreamLimit);
-
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
- EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
- session_.get(), kClientDataStreamId1));
-
- // Establish available streams up to the server's limit.
- const int kLimitingStreamId =
- kClientDataStreamId1 + (kAvailableStreamLimit)*2 + 2;
- EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
- session_.get(), kLimitingStreamId));
-
- // A further available stream will result in connection close.
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_TOO_MANY_AVAILABLE_STREAMS, _, _));
- // This forces stream kLimitingStreamId + 2 to become available, which
- // violates the quota.
- EXPECT_FALSE(QuicServerSessionBasePeer::GetOrCreateDynamicStream(
- session_.get(), kLimitingStreamId + 4));
-}
-
-TEST_P(QuicServerSessionBaseTest, EnableServerPushThroughConnectionOption) {
- // Assume server received server push connection option.
- QuicTagVector copt;
- copt.push_back(kSPSH);
- QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
- session_->OnConfigNegotiated();
- EXPECT_TRUE(session_->server_push_enabled());
-}
-
-TEST_P(QuicServerSessionBaseTest, GetEvenIncomingError) {
- // Incoming streams on the server session must be odd.
- EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _));
- EXPECT_EQ(nullptr, QuicServerSessionBasePeer::GetOrCreateDynamicStream(
- session_.get(), 4));
-}
-
-TEST_P(QuicServerSessionBaseTest, GetStreamDisconnected) {
- // Don't create new streams if the connection is disconnected.
- QuicConnectionPeer::TearDownLocalConnectionState(connection_);
- EXPECT_DFATAL(
- QuicServerSessionBasePeer::GetOrCreateDynamicStream(session_.get(), 5),
- "ShouldCreateIncomingDynamicStream called when disconnected");
-}
-
-class MockQuicCryptoServerStream : public QuicCryptoServerStream {
- public:
- explicit MockQuicCryptoServerStream(
- const QuicCryptoServerConfig* crypto_config,
- QuicCompressedCertsCache* compressed_certs_cache,
- QuicServerSessionBase* session)
- : QuicCryptoServerStream(crypto_config,
- compressed_certs_cache,
- FLAGS_enable_quic_stateless_reject_support,
- session) {}
- ~MockQuicCryptoServerStream() override {}
-
- MOCK_METHOD1(SendServerConfigUpdate,
- void(const CachedNetworkParameters* cached_network_parameters));
-
- void set_encryption_established(bool has_established) {
- encryption_established_ = has_established;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockQuicCryptoServerStream);
-};
-
-TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) {
- // Test that bandwidth estimate updates are sent to the client, only when
- // bandwidth resumption is enabled, the bandwidth estimate has changed
- // sufficiently, enough time has passed,
- // and we don't have any other data to write.
-
- // Client has sent kBWRE connection option to trigger bandwidth resumption.
- // Disable this flag because if connection uses multipath sent packet manager,
- // static_cast here does not work.
- FLAGS_quic_enable_multipath = false;
- QuicTagVector copt;
- copt.push_back(kBWRE);
- QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
- session_->OnConfigNegotiated();
- EXPECT_TRUE(
- QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
-
- int32_t bandwidth_estimate_kbytes_per_second = 123;
- int32_t max_bandwidth_estimate_kbytes_per_second = 134;
- int32_t max_bandwidth_estimate_timestamp = 1122334455;
- const string serving_region = "not a real region";
- session_->set_serving_region(serving_region);
-
- MockQuicCryptoServerStream* crypto_stream = new MockQuicCryptoServerStream(
- &crypto_config_, &compressed_certs_cache_, session_.get());
- QuicServerSessionBasePeer::SetCryptoStream(session_.get(), crypto_stream);
-
- // Set some initial bandwidth values.
- QuicSentPacketManager* sent_packet_manager =
- static_cast<QuicSentPacketManager*>(
- QuicConnectionPeer::GetSentPacketManager(session_->connection()));
- QuicSustainedBandwidthRecorder& bandwidth_recorder =
- QuicSentPacketManagerPeer::GetBandwidthRecorder(sent_packet_manager);
- // Seed an rtt measurement equal to the initial default rtt.
- RttStats* rtt_stats =
- const_cast<RttStats*>(sent_packet_manager->GetRttStats());
- rtt_stats->UpdateRtt(
- QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us()),
- QuicTime::Delta::Zero(), QuicTime::Zero());
- QuicSustainedBandwidthRecorderPeer::SetBandwidthEstimate(
- &bandwidth_recorder, bandwidth_estimate_kbytes_per_second);
- QuicSustainedBandwidthRecorderPeer::SetMaxBandwidthEstimate(
- &bandwidth_recorder, max_bandwidth_estimate_kbytes_per_second,
- max_bandwidth_estimate_timestamp);
- // Queue up some pending data.
- session_->MarkConnectionLevelWriteBlocked(kCryptoStreamId);
- EXPECT_TRUE(session_->HasDataToWrite());
-
- // There will be no update sent yet - not enough time has passed.
- QuicTime now = QuicTime::Zero();
- session_->OnCongestionWindowChange(now);
-
- // Bandwidth estimate has now changed sufficiently but not enough time has
- // passed to send a Server Config Update.
- bandwidth_estimate_kbytes_per_second =
- bandwidth_estimate_kbytes_per_second * 1.6;
- session_->OnCongestionWindowChange(now);
-
- // Bandwidth estimate has now changed sufficiently and enough time has passed,
- // but not enough packets have been sent.
- int64_t srtt_ms =
- sent_packet_manager->GetRttStats()->smoothed_rtt().ToMilliseconds();
- now = now.Add(QuicTime::Delta::FromMilliseconds(
- kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms));
- session_->OnCongestionWindowChange(now);
-
- // The connection no longer has pending data to be written.
- session_->OnCanWrite();
- EXPECT_FALSE(session_->HasDataToWrite());
- session_->OnCongestionWindowChange(now);
-
- // Bandwidth estimate has now changed sufficiently, enough time has passed,
- // and enough packets have been sent.
- QuicConnectionPeer::SetPacketNumberOfLastSentPacket(
- session_->connection(), kMinPacketsBetweenServerConfigUpdates);
-
- // Verify that the proto has exactly the values we expect.
- CachedNetworkParameters expected_network_params;
- expected_network_params.set_bandwidth_estimate_bytes_per_second(
- bandwidth_recorder.BandwidthEstimate().ToBytesPerSecond());
- expected_network_params.set_max_bandwidth_estimate_bytes_per_second(
- bandwidth_recorder.MaxBandwidthEstimate().ToBytesPerSecond());
- expected_network_params.set_max_bandwidth_timestamp_seconds(
- bandwidth_recorder.MaxBandwidthTimestamp());
- expected_network_params.set_min_rtt_ms(session_->connection()
- ->sent_packet_manager()
- .GetRttStats()
- ->min_rtt()
- .ToMilliseconds());
- expected_network_params.set_previous_connection_state(
- CachedNetworkParameters::CONGESTION_AVOIDANCE);
- expected_network_params.set_timestamp(
- session_->connection()->clock()->WallNow().ToUNIXSeconds());
- expected_network_params.set_serving_region(serving_region);
-
- EXPECT_CALL(*crypto_stream,
- SendServerConfigUpdate(EqualsProto(expected_network_params)))
- .Times(1);
- EXPECT_CALL(*connection_, OnSendConnectionState(_)).Times(1);
- session_->OnCongestionWindowChange(now);
-}
-
-TEST_P(QuicServerSessionBaseTest, BandwidthResumptionExperiment) {
- // Test that if a client provides a CachedNetworkParameters with the same
- // serving region as the current server, and which was made within an hour of
- // now, that this data is passed down to the send algorithm.
-
- // Client has sent kBWRE connection option to trigger bandwidth resumption.
- QuicTagVector copt;
- copt.push_back(kBWRE);
- QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
-
- const string kTestServingRegion = "a serving region";
- session_->set_serving_region(kTestServingRegion);
-
- // Set the time to be one hour + one second from the 0 baseline.
- connection_->AdvanceTime(
- QuicTime::Delta::FromSeconds(kNumSecondsPerHour + 1));
-
- QuicCryptoServerStream* crypto_stream = static_cast<QuicCryptoServerStream*>(
- QuicSessionPeer::GetCryptoStream(session_.get()));
-
- // No effect if no CachedNetworkParameters provided.
- EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(0);
- session_->OnConfigNegotiated();
-
- // No effect if CachedNetworkParameters provided, but different serving
- // regions.
- CachedNetworkParameters cached_network_params;
- cached_network_params.set_bandwidth_estimate_bytes_per_second(1);
- cached_network_params.set_serving_region("different serving region");
- crypto_stream->SetPreviousCachedNetworkParams(cached_network_params);
- EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(0);
- session_->OnConfigNegotiated();
-
- // Same serving region, but timestamp is too old, should have no effect.
- cached_network_params.set_serving_region(kTestServingRegion);
- cached_network_params.set_timestamp(0);
- crypto_stream->SetPreviousCachedNetworkParams(cached_network_params);
- EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(0);
- session_->OnConfigNegotiated();
-
- // Same serving region, and timestamp is recent: estimate is stored.
- cached_network_params.set_timestamp(
- connection_->clock()->WallNow().ToUNIXSeconds());
- crypto_stream->SetPreviousCachedNetworkParams(cached_network_params);
- EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(1);
- session_->OnConfigNegotiated();
-}
-
-TEST_P(QuicServerSessionBaseTest, BandwidthMaxEnablesResumption) {
- EXPECT_FALSE(
- QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
-
- // Client has sent kBWMX connection option to trigger bandwidth resumption.
- QuicTagVector copt;
- copt.push_back(kBWMX);
- QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
- session_->OnConfigNegotiated();
- EXPECT_TRUE(
- QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
-}
-
-TEST_P(QuicServerSessionBaseTest, NoBandwidthResumptionByDefault) {
- EXPECT_FALSE(
- QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
- session_->OnConfigNegotiated();
- EXPECT_FALSE(
- QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get()));
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_session.cc b/chromium/net/quic/quic_session.cc
deleted file mode 100644
index b232a1e71f6..00000000000
--- a/chromium/net/quic/quic_session.cc
+++ /dev/null
@@ -1,842 +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/quic_session.h"
-
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "net/quic/crypto/proof_verifier.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_flow_controller.h"
-#include "net/ssl/ssl_info.h"
-
-using base::IntToString;
-using base::StringPiece;
-using std::make_pair;
-using std::map;
-using std::max;
-using std::string;
-using std::vector;
-using net::SpdyPriority;
-
-namespace net {
-
-#define ENDPOINT \
- (perspective() == Perspective::IS_SERVER ? "Server: " : " Client: ")
-
-QuicSession::QuicSession(QuicConnection* connection, const QuicConfig& config)
- : connection_(connection),
- config_(config),
- max_open_outgoing_streams_(kDefaultMaxStreamsPerConnection),
- max_open_incoming_streams_(config_.GetMaxIncomingDynamicStreamsToSend()),
- next_outgoing_stream_id_(perspective() == Perspective::IS_SERVER ? 2 : 3),
- largest_peer_created_stream_id_(
- perspective() == Perspective::IS_SERVER ? 1 : 0),
- num_dynamic_incoming_streams_(0),
- num_draining_incoming_streams_(0),
- num_locally_closed_incoming_streams_highest_offset_(0),
- error_(QUIC_NO_ERROR),
- flow_controller_(connection_.get(),
- 0,
- perspective(),
- kMinimumFlowControlSendWindow,
- config_.GetInitialSessionFlowControlWindowToSend(),
- FLAGS_quic_enable_autotune_by_default
- ? perspective() == Perspective::IS_SERVER
- : false),
- currently_writing_stream_id_(0) {}
-
-void QuicSession::Initialize() {
- connection_->set_visitor(this);
- connection_->SetFromConfig(config_);
-
- DCHECK_EQ(kCryptoStreamId, GetCryptoStream()->id());
- static_stream_map_[kCryptoStreamId] = GetCryptoStream();
-}
-
-QuicSession::~QuicSession() {
- STLDeleteElements(&closed_streams_);
- STLDeleteValues(&dynamic_stream_map_);
-
- DLOG_IF(WARNING, num_locally_closed_incoming_streams_highest_offset() >
- max_open_incoming_streams_)
- << "Surprisingly high number of locally closed peer initiated streams"
- "still waiting for final byte offset: "
- << num_locally_closed_incoming_streams_highest_offset();
- DLOG_IF(WARNING, GetNumLocallyClosedOutgoingStreamsHighestOffset() >
- max_open_outgoing_streams_)
- << "Surprisingly high number of locally closed self initiated streams"
- "still waiting for final byte offset: "
- << GetNumLocallyClosedOutgoingStreamsHighestOffset();
-}
-
-void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) {
- // TODO(rch) deal with the error case of stream id 0.
- QuicStreamId stream_id = frame.stream_id;
- ReliableQuicStream* stream = GetOrCreateStream(stream_id);
- if (!stream) {
- // The stream no longer exists, but we may still be interested in the
- // final stream byte offset sent by the peer. A frame with a FIN can give
- // us this offset.
- if (frame.fin) {
- QuicStreamOffset final_byte_offset = frame.offset + frame.data_length;
- UpdateFlowControlOnFinalReceivedByteOffset(stream_id, final_byte_offset);
- }
- return;
- }
- stream->OnStreamFrame(frame);
-}
-
-void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
- if (ContainsKey(static_stream_map_, frame.stream_id)) {
- connection()->CloseConnection(
- QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
-
- ReliableQuicStream* stream = GetOrCreateDynamicStream(frame.stream_id);
- if (!stream) {
- HandleRstOnValidNonexistentStream(frame);
- return; // Errors are handled by GetOrCreateStream.
- }
-
- stream->OnStreamReset(frame);
-}
-
-void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) {
- DCHECK(frame.last_good_stream_id < next_outgoing_stream_id_);
-}
-
-void QuicSession::OnConnectionClosed(QuicErrorCode error,
- const string& /*error_details*/,
- ConnectionCloseSource source) {
- DCHECK(!connection_->connected());
- if (error_ == QUIC_NO_ERROR) {
- error_ = error;
- }
-
- while (!dynamic_stream_map_.empty()) {
- StreamMap::iterator it = dynamic_stream_map_.begin();
- QuicStreamId id = it->first;
- it->second->OnConnectionClosed(error, source);
- // The stream should call CloseStream as part of OnConnectionClosed.
- if (dynamic_stream_map_.find(id) != dynamic_stream_map_.end()) {
- QUIC_BUG << ENDPOINT << "Stream failed to close under OnConnectionClosed";
- CloseStream(id);
- }
- }
-}
-
-void QuicSession::OnSuccessfulVersionNegotiation(
- const QuicVersion& /*version*/) {}
-
-void QuicSession::OnPathDegrading() {}
-
-void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
- // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
- // assume that it still exists.
- QuicStreamId stream_id = frame.stream_id;
- if (stream_id == kConnectionLevelId) {
- // This is a window update that applies to the connection, rather than an
- // individual stream.
- DVLOG(1) << ENDPOINT << "Received connection level flow control window "
- "update with byte offset: "
- << frame.byte_offset;
- flow_controller_.UpdateSendWindowOffset(frame.byte_offset);
- return;
- }
- ReliableQuicStream* stream = GetOrCreateStream(stream_id);
- if (stream) {
- stream->OnWindowUpdateFrame(frame);
- }
-}
-
-void QuicSession::OnBlockedFrame(const QuicBlockedFrame& frame) {
- // TODO(rjshade): Compare our flow control receive windows for specified
- // streams: if we have a large window then maybe something
- // had gone wrong with the flow control accounting.
- DVLOG(1) << ENDPOINT
- << "Received BLOCKED frame with stream id: " << frame.stream_id;
-}
-
-void QuicSession::OnCanWrite() {
- // 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
- // connections.
- size_t num_writes = write_blocked_streams_.NumBlockedStreams();
- if (flow_controller_.IsBlocked()) {
- // If we are connection level flow control blocked, then only allow the
- // crypto and headers streams to try writing as all other streams will be
- // blocked.
- num_writes = 0;
- if (write_blocked_streams_.crypto_stream_blocked()) {
- num_writes += 1;
- }
- if (write_blocked_streams_.headers_stream_blocked()) {
- num_writes += 1;
- }
- }
- if (num_writes == 0) {
- return;
- }
-
- QuicConnection::ScopedPacketBundler ack_bundler(
- connection_.get(), QuicConnection::SEND_ACK_IF_QUEUED);
- for (size_t i = 0; i < num_writes; ++i) {
- if (!(write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
- write_blocked_streams_.HasWriteBlockedDataStreams())) {
- // Writing one stream removed another!? Something's broken.
- QUIC_BUG << "WriteBlockedStream is missing";
- connection_->CloseConnection(QUIC_INTERNAL_ERROR,
- "WriteBlockedStream is missing",
- ConnectionCloseBehavior::SILENT_CLOSE);
- return;
- }
- if (!connection_->CanWriteStreamData()) {
- return;
- }
- currently_writing_stream_id_ = write_blocked_streams_.PopFront();
- ReliableQuicStream* stream =
- GetOrCreateStream(currently_writing_stream_id_);
- if (stream != nullptr && !stream->flow_controller()->IsBlocked()) {
- // If the stream can't write all bytes it'll re-add itself to the blocked
- // list.
- stream->OnCanWrite();
- }
- currently_writing_stream_id_ = 0;
- }
-}
-
-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() ||
- (!flow_controller_.IsBlocked() &&
- write_blocked_streams_.HasWriteBlockedDataStreams());
-}
-
-bool QuicSession::HasPendingHandshake() const {
- return write_blocked_streams_.crypto_stream_blocked();
-}
-
-bool QuicSession::HasOpenDynamicStreams() const {
- return (dynamic_stream_map_.size() - draining_streams_.size() +
- locally_closed_streams_highest_offset_.size()) > 0;
-}
-
-void QuicSession::ProcessUdpPacket(const IPEndPoint& self_address,
- const IPEndPoint& peer_address,
- const QuicReceivedPacket& packet) {
- connection_->ProcessUdpPacket(self_address, peer_address, packet);
-}
-
-QuicConsumedData QuicSession::WritevData(
- ReliableQuicStream* stream,
- QuicStreamId id,
- QuicIOVector iov,
- QuicStreamOffset offset,
- bool fin,
- QuicAckListenerInterface* ack_notifier_delegate) {
- // This check is an attempt to deal with potential memory corruption
- // in which |id| ends up set to 1 (the crypto stream id). If this happen
- // it might end up resulting in unencrypted stream data being sent.
- // While this is impossible to avoid given sufficient corruption, this
- // seems like a reasonable mitigation.
- if (id == kCryptoStreamId && stream != GetCryptoStream()) {
- QUIC_BUG << "Stream id mismatch";
- connection_->CloseConnection(
- QUIC_INTERNAL_ERROR,
- "Non-crypto stream attempted to write data as crypto stream.",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return QuicConsumedData(0, false);
- }
- if (!IsEncryptionEstablished() && id != kCryptoStreamId) {
- // Do not let streams write without encryption. The calling stream will end
- // up write blocked until OnCanWrite is next called.
- return QuicConsumedData(0, false);
- }
- QuicConsumedData data =
- connection_->SendStreamData(id, iov, offset, fin, ack_notifier_delegate);
- write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed);
- return data;
-}
-
-void QuicSession::SendRstStream(QuicStreamId id,
- QuicRstStreamErrorCode error,
- QuicStreamOffset bytes_written) {
- if (ContainsKey(static_stream_map_, id)) {
- QUIC_BUG << "Cannot send RST for a static stream with ID " << id;
- return;
- }
-
- if (connection()->connected()) {
- // Only send a RST_STREAM frame if still connected.
- connection_->SendRstStream(id, error, bytes_written);
- }
- CloseStreamInner(id, true);
-}
-
-void QuicSession::SendGoAway(QuicErrorCode error_code, const string& reason) {
- if (goaway_sent()) {
- return;
- }
-
- connection_->SendGoAway(error_code, largest_peer_created_stream_id_, reason);
-}
-
-void QuicSession::CloseStream(QuicStreamId stream_id) {
- CloseStreamInner(stream_id, false);
-}
-
-void QuicSession::InsertLocallyClosedStreamsHighestOffset(
- const QuicStreamId id,
- QuicStreamOffset offset) {
- locally_closed_streams_highest_offset_[id] = offset;
- if (IsIncomingStream(id)) {
- ++num_locally_closed_incoming_streams_highest_offset_;
- }
-}
-
-void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) {
- DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
-
- StreamMap::iterator it = dynamic_stream_map_.find(stream_id);
- if (it == dynamic_stream_map_.end()) {
- // When CloseStreamInner has been called recursively (via
- // ReliableQuicStream::OnClose), the stream will already have been deleted
- // from stream_map_, so return immediately.
- DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id;
- return;
- }
- ReliableQuicStream* stream = it->second;
-
- // Tell the stream that a RST has been sent.
- if (locally_reset) {
- stream->set_rst_sent(true);
- }
-
- closed_streams_.push_back(it->second);
-
- // If we haven't received a FIN or RST for this stream, we need to keep track
- // of the how many bytes the stream's flow controller believes it has
- // received, for accurate connection level flow control accounting.
- if (!stream->HasFinalReceivedByteOffset()) {
- InsertLocallyClosedStreamsHighestOffset(
- stream_id, stream->flow_controller()->highest_received_byte_offset());
- }
-
- dynamic_stream_map_.erase(it);
- if (IsIncomingStream(stream_id)) {
- --num_dynamic_incoming_streams_;
- }
-
- if (draining_streams_.find(stream_id) != draining_streams_.end() &&
- IsIncomingStream(stream_id)) {
- --num_draining_incoming_streams_;
- }
- draining_streams_.erase(stream_id);
-
- stream->OnClose();
- // Decrease the number of streams being emulated when a new one is opened.
- connection_->SetNumOpenStreams(dynamic_stream_map_.size());
-}
-
-void QuicSession::UpdateFlowControlOnFinalReceivedByteOffset(
- QuicStreamId stream_id,
- QuicStreamOffset final_byte_offset) {
- map<QuicStreamId, QuicStreamOffset>::iterator it =
- locally_closed_streams_highest_offset_.find(stream_id);
- if (it == locally_closed_streams_highest_offset_.end()) {
- return;
- }
-
- DVLOG(1) << ENDPOINT << "Received final byte offset " << final_byte_offset
- << " for stream " << stream_id;
- QuicByteCount offset_diff = final_byte_offset - it->second;
- if (flow_controller_.UpdateHighestReceivedOffset(
- flow_controller_.highest_received_byte_offset() + offset_diff)) {
- // If the final offset violates flow control, close the connection now.
- if (flow_controller_.FlowControlViolation()) {
- connection_->CloseConnection(
- QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
- "Connection level flow control violation",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
- }
-
- flow_controller_.AddBytesConsumed(offset_diff);
- locally_closed_streams_highest_offset_.erase(it);
- if (IsIncomingStream(stream_id)) {
- --num_locally_closed_incoming_streams_highest_offset_;
- }
-}
-
-bool QuicSession::IsEncryptionEstablished() {
- return GetCryptoStream()->encryption_established();
-}
-
-bool QuicSession::IsCryptoHandshakeConfirmed() {
- return GetCryptoStream()->handshake_confirmed();
-}
-
-void QuicSession::OnConfigNegotiated() {
- connection_->SetFromConfig(config_);
-
- const QuicVersion version = connection()->version();
- uint32_t max_streams = 0;
- if (version > QUIC_VERSION_34 &&
- config_.HasReceivedMaxIncomingDynamicStreams()) {
- max_streams = config_.ReceivedMaxIncomingDynamicStreams();
- } else {
- max_streams = config_.MaxStreamsPerConnection();
- }
- set_max_open_outgoing_streams(max_streams);
- if (!FLAGS_quic_enable_autotune_by_default &&
- perspective() == Perspective::IS_SERVER) {
- if (config_.HasReceivedConnectionOptions()) {
- if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kAFCW)) {
- // The following variations change the initial receive flow control
- // window sizes.
- if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW5)) {
- AdjustInitialFlowControlWindows(32 * 1024);
- }
- if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW6)) {
- AdjustInitialFlowControlWindows(64 * 1024);
- }
- if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW7)) {
- AdjustInitialFlowControlWindows(128 * 1024);
- }
- EnableAutoTuneReceiveWindow();
- }
- }
- }
-
- if (version <= QUIC_VERSION_34) {
- // A small number of additional incoming streams beyond the limit should be
- // allowed. This helps avoid early connection termination when FIN/RSTs for
- // old streams are lost or arrive out of order.
- // Use a minimum number of additional streams, or a percentage increase,
- // whichever is larger.
- uint32_t max_incoming_streams =
- max(max_streams + kMaxStreamsMinimumIncrement,
- static_cast<uint32_t>(max_streams * kMaxStreamsMultiplier));
- set_max_open_incoming_streams(max_incoming_streams);
- } else {
- uint32_t max_incoming_streams_to_send =
- config_.GetMaxIncomingDynamicStreamsToSend();
- uint32_t max_incoming_streams =
- max(max_incoming_streams_to_send + kMaxStreamsMinimumIncrement,
- static_cast<uint32_t>(max_incoming_streams_to_send *
- kMaxStreamsMultiplier));
- set_max_open_incoming_streams(max_incoming_streams);
- }
-
- if (config_.HasReceivedInitialStreamFlowControlWindowBytes()) {
- // Streams which were created before the SHLO was received (0-RTT
- // requests) are now informed of the peer's initial flow control window.
- OnNewStreamFlowControlWindow(
- config_.ReceivedInitialStreamFlowControlWindowBytes());
- }
- if (config_.HasReceivedInitialSessionFlowControlWindowBytes()) {
- OnNewSessionFlowControlWindow(
- config_.ReceivedInitialSessionFlowControlWindowBytes());
- }
-}
-
-// TODO(ckrasic): remove the following two methods when deprecating
-// FLAGS_quic_enable_autotune_by_default.
-void QuicSession::EnableAutoTuneReceiveWindow() {
- DVLOG(1) << ENDPOINT << "Enable auto tune receive windows";
- flow_controller_.set_auto_tune_receive_window(true);
- // Inform all existing streams about the new window.
- for (auto const& kv : static_stream_map_) {
- kv.second->flow_controller()->set_auto_tune_receive_window(true);
- }
- for (auto const& kv : dynamic_stream_map_) {
- kv.second->flow_controller()->set_auto_tune_receive_window(true);
- }
-}
-
-void QuicSession::AdjustInitialFlowControlWindows(size_t stream_window) {
- const float session_window_multiplier =
- config_.GetInitialStreamFlowControlWindowToSend()
- ? static_cast<float>(
- config_.GetInitialSessionFlowControlWindowToSend()) /
- config_.GetInitialStreamFlowControlWindowToSend()
- : 1.0;
- DVLOG(1) << ENDPOINT << "Set stream receive window to " << stream_window;
- config_.SetInitialStreamFlowControlWindowToSend(stream_window);
- // Reduce the session window as well, motivation is reducing resource waste
- // and denial of service vulnerability, as with the stream window. Session
- // size is set according to the ratio between session and stream window size
- // previous to auto-tuning. Note that the ratio may change dynamically, since
- // auto-tuning acts independently for each flow controller.
- size_t session_window = session_window_multiplier * stream_window;
- DVLOG(1) << ENDPOINT << "Set session receive window to " << session_window;
- config_.SetInitialSessionFlowControlWindowToSend(session_window);
- flow_controller_.UpdateReceiveWindowSize(session_window);
- // Inform all existing streams about the new window.
- for (auto const& kv : static_stream_map_) {
- kv.second->flow_controller()->UpdateReceiveWindowSize(stream_window);
- }
- for (auto const& kv : dynamic_stream_map_) {
- kv.second->flow_controller()->UpdateReceiveWindowSize(stream_window);
- }
-}
-
-void QuicSession::HandleFrameOnNonexistentOutgoingStream(
- QuicStreamId stream_id) {
- DCHECK(!IsClosedStream(stream_id));
- // Received a frame for a locally-created stream that is not currently
- // active. This is an error.
- connection()->CloseConnection(
- QUIC_INVALID_STREAM_ID, "Data for nonexistent stream",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-}
-
-void QuicSession::HandleRstOnValidNonexistentStream(
- const QuicRstStreamFrame& frame) {
- // If the stream is neither originally in active streams nor created in
- // GetOrCreateDynamicStream(), it could be a closed stream in which case its
- // final received byte offset need to be updated.
- if (IsClosedStream(frame.stream_id)) {
- // The RST frame contains the final byte offset for the stream: we can now
- // update the connection level flow controller if needed.
- UpdateFlowControlOnFinalReceivedByteOffset(frame.stream_id,
- frame.byte_offset);
- }
-}
-
-void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
- if (new_window < kMinimumFlowControlSendWindow) {
- LOG(ERROR) << "Peer sent us an invalid stream flow control send window: "
- << new_window
- << ", below default: " << kMinimumFlowControlSendWindow;
- if (connection_->connected()) {
- connection_->CloseConnection(
- QUIC_FLOW_CONTROL_INVALID_WINDOW, "New stream window too low",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- }
- return;
- }
-
- // Inform all existing streams about the new window.
- for (auto const& kv : static_stream_map_) {
- kv.second->UpdateSendWindowOffset(new_window);
- }
- for (auto const& kv : dynamic_stream_map_) {
- kv.second->UpdateSendWindowOffset(new_window);
- }
-}
-
-void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) {
- if (new_window < kMinimumFlowControlSendWindow) {
- LOG(ERROR) << "Peer sent us an invalid session flow control send window: "
- << new_window
- << ", below default: " << kMinimumFlowControlSendWindow;
- if (connection_->connected()) {
- connection_->CloseConnection(
- QUIC_FLOW_CONTROL_INVALID_WINDOW, "New connection window too low",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- }
- return;
- }
-
- flow_controller_.UpdateSendWindowOffset(new_window);
-}
-
-void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
- switch (event) {
- // TODO(satyamshekhar): Move the logic of setting the encrypter/decrypter
- // to QuicSession since it is the glue.
- case ENCRYPTION_FIRST_ESTABLISHED:
- // Given any streams blocked by encryption a chance to write.
- OnCanWrite();
- break;
-
- case ENCRYPTION_REESTABLISHED:
- // Retransmit originally packets that were sent, since they can't be
- // decrypted by the peer.
- connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION);
- // Given any streams blocked by encryption a chance to write.
- OnCanWrite();
- break;
-
- case HANDSHAKE_CONFIRMED:
- QUIC_BUG_IF(!config_.negotiated())
- << ENDPOINT << "Handshake confirmed without parameter negotiation.";
- // Discard originally encrypted packets, since they can't be decrypted by
- // the peer.
- connection_->NeuterUnencryptedPackets();
- break;
-
- default:
- LOG(ERROR) << ENDPOINT << "Got unknown handshake event: " << event;
- }
-}
-
-void QuicSession::OnCryptoHandshakeMessageSent(
- const CryptoHandshakeMessage& /*message*/) {}
-
-void QuicSession::OnCryptoHandshakeMessageReceived(
- const CryptoHandshakeMessage& /*message*/) {}
-
-QuicConfig* QuicSession::config() {
- return &config_;
-}
-
-void QuicSession::ActivateStream(ReliableQuicStream* stream) {
- DVLOG(1) << ENDPOINT << "num_streams: " << dynamic_stream_map_.size()
- << ". activating " << stream->id();
- DCHECK(!ContainsKey(dynamic_stream_map_, stream->id()));
- DCHECK(!ContainsKey(static_stream_map_, stream->id()));
- dynamic_stream_map_[stream->id()] = stream;
- if (IsIncomingStream(stream->id())) {
- ++num_dynamic_incoming_streams_;
- }
- // Increase the number of streams being emulated when a new one is opened.
- connection_->SetNumOpenStreams(dynamic_stream_map_.size());
-}
-
-QuicStreamId QuicSession::GetNextOutgoingStreamId() {
- QuicStreamId id = next_outgoing_stream_id_;
- next_outgoing_stream_id_ += 2;
- return id;
-}
-
-ReliableQuicStream* QuicSession::GetOrCreateStream(
- const QuicStreamId stream_id) {
- StreamMap::iterator it = static_stream_map_.find(stream_id);
- if (it != static_stream_map_.end()) {
- return it->second;
- }
- return GetOrCreateDynamicStream(stream_id);
-}
-
-void QuicSession::StreamDraining(QuicStreamId stream_id) {
- DCHECK(ContainsKey(dynamic_stream_map_, stream_id));
- if (!ContainsKey(draining_streams_, stream_id)) {
- draining_streams_.insert(stream_id);
- if (IsIncomingStream(stream_id)) {
- ++num_draining_incoming_streams_;
- }
- }
-}
-
-bool QuicSession::MaybeIncreaseLargestPeerStreamId(
- const QuicStreamId stream_id) {
- if (stream_id <= largest_peer_created_stream_id_) {
- return true;
- }
-
- // Check if the new number of available streams would cause the number of
- // available streams to exceed the limit. Note that the peer can create
- // only alternately-numbered streams.
- size_t additional_available_streams =
- (stream_id - largest_peer_created_stream_id_) / 2 - 1;
- size_t new_num_available_streams =
- GetNumAvailableStreams() + additional_available_streams;
- if (new_num_available_streams > MaxAvailableStreams()) {
- DVLOG(1) << "Failed to create a new incoming stream with id:" << stream_id
- << ". There are already " << GetNumAvailableStreams()
- << " streams available, which would become "
- << new_num_available_streams << ", which exceeds the limit "
- << MaxAvailableStreams() << ".";
- string details = IntToString(new_num_available_streams) + " above " +
- IntToString(MaxAvailableStreams());
- connection()->CloseConnection(
- QUIC_TOO_MANY_AVAILABLE_STREAMS, details.c_str(),
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return false;
- }
- for (QuicStreamId id = largest_peer_created_stream_id_ + 2; id < stream_id;
- id += 2) {
- available_streams_.insert(id);
- }
- largest_peer_created_stream_id_ = stream_id;
-
- return true;
-}
-
-bool QuicSession::ShouldYield(QuicStreamId stream_id) {
- if (stream_id == currently_writing_stream_id_) {
- return false;
- }
- return write_blocked_streams()->ShouldYield(stream_id);
-}
-
-ReliableQuicStream* QuicSession::GetOrCreateDynamicStream(
- const QuicStreamId stream_id) {
- DCHECK(!ContainsKey(static_stream_map_, stream_id))
- << "Attempt to call GetOrCreateDynamicStream for a static stream";
-
- StreamMap::iterator it = dynamic_stream_map_.find(stream_id);
- if (it != dynamic_stream_map_.end()) {
- return it->second;
- }
-
- if (IsClosedStream(stream_id)) {
- return nullptr;
- }
-
- if (!IsIncomingStream(stream_id)) {
- HandleFrameOnNonexistentOutgoingStream(stream_id);
- return nullptr;
- }
-
- available_streams_.erase(stream_id);
-
- if (!MaybeIncreaseLargestPeerStreamId(stream_id)) {
- return nullptr;
- }
- // Check if the new number of open streams would cause the number of
- // open streams to exceed the limit.
- if (GetNumOpenIncomingStreams() >= max_open_incoming_streams()) {
- if (connection()->version() <= QUIC_VERSION_27) {
- connection()->CloseConnection(
- QUIC_TOO_MANY_OPEN_STREAMS, "Old style stream rejection",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- } else {
- // Refuse to open the stream.
- SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0);
- }
- return nullptr;
- }
-
- return CreateIncomingDynamicStream(stream_id);
-}
-
-void QuicSession::set_max_open_incoming_streams(
- size_t max_open_incoming_streams) {
- DVLOG(1) << "Setting max_open_incoming_streams_ to "
- << max_open_incoming_streams;
- max_open_incoming_streams_ = max_open_incoming_streams;
- DVLOG(1) << "MaxAvailableStreams() became " << MaxAvailableStreams();
-}
-
-void QuicSession::set_max_open_outgoing_streams(
- size_t max_open_outgoing_streams) {
- DVLOG(1) << "Setting max_open_outgoing_streams_ to "
- << max_open_outgoing_streams;
- max_open_outgoing_streams_ = max_open_outgoing_streams;
-}
-
-bool QuicSession::goaway_sent() const {
- return connection_->goaway_sent();
-}
-
-bool QuicSession::goaway_received() const {
- return connection_->goaway_received();
-}
-
-bool QuicSession::IsClosedStream(QuicStreamId id) {
- DCHECK_NE(0u, id);
- if (IsOpenStream(id)) {
- // Stream is active
- return false;
- }
- if (!IsIncomingStream(id)) {
- // Locally created streams are strictly in-order. If the id is in the
- // range of created streams and it's not active, it must have been closed.
- return id < next_outgoing_stream_id_;
- }
- // For peer created streams, we also need to consider available streams.
- return id <= largest_peer_created_stream_id_ &&
- !ContainsKey(available_streams_, id);
-}
-
-bool QuicSession::IsOpenStream(QuicStreamId id) {
- DCHECK_NE(0u, id);
- if (ContainsKey(static_stream_map_, id) ||
- ContainsKey(dynamic_stream_map_, id)) {
- // Stream is active
- return true;
- }
- return false;
-}
-
-size_t QuicSession::GetNumOpenIncomingStreams() const {
- return num_dynamic_incoming_streams_ - num_draining_incoming_streams_ +
- num_locally_closed_incoming_streams_highest_offset_;
-}
-
-size_t QuicSession::GetNumOpenOutgoingStreams() const {
- return GetNumDynamicOutgoingStreams() - GetNumDrainingOutgoingStreams() +
- GetNumLocallyClosedOutgoingStreamsHighestOffset();
-}
-
-size_t QuicSession::GetNumActiveStreams() const {
- return dynamic_stream_map_.size() - draining_streams_.size();
-}
-
-size_t QuicSession::GetNumAvailableStreams() const {
- return available_streams_.size();
-}
-
-void QuicSession::MarkConnectionLevelWriteBlocked(QuicStreamId id) {
- QUIC_BUG_IF(GetOrCreateStream(id) == nullptr) << "Marking unknown stream "
- << id << " blocked.";
-
- write_blocked_streams_.AddStream(id);
-}
-
-bool QuicSession::HasDataToWrite() const {
- return write_blocked_streams_.HasWriteBlockedCryptoOrHeadersStream() ||
- write_blocked_streams_.HasWriteBlockedDataStreams() ||
- connection_->HasQueuedData();
-}
-
-void QuicSession::PostProcessAfterData() {
- STLDeleteElements(&closed_streams_);
- closed_streams_.clear();
-}
-
-size_t QuicSession::GetNumDynamicOutgoingStreams() const {
- return dynamic_stream_map_.size() - num_dynamic_incoming_streams_;
-}
-
-size_t QuicSession::GetNumDrainingOutgoingStreams() const {
- return draining_streams_.size() - num_draining_incoming_streams_;
-}
-
-size_t QuicSession::GetNumLocallyClosedOutgoingStreamsHighestOffset() const {
- return locally_closed_streams_highest_offset_.size() -
- num_locally_closed_incoming_streams_highest_offset_;
-}
-
-bool QuicSession::IsConnectionFlowControlBlocked() const {
- return flow_controller_.IsBlocked();
-}
-
-bool QuicSession::IsStreamFlowControlBlocked() {
- for (auto const& kv : static_stream_map_) {
- if (kv.second->flow_controller()->IsBlocked()) {
- return true;
- }
- }
- for (auto const& kv : dynamic_stream_map_) {
- if (kv.second->flow_controller()->IsBlocked()) {
- return true;
- }
- }
- return false;
-}
-
-size_t QuicSession::MaxAvailableStreams() const {
- return max_open_incoming_streams_ * kMaxAvailableStreamsMultiplier;
-}
-
-bool QuicSession::IsIncomingStream(QuicStreamId id) const {
- return id % 2 != next_outgoing_stream_id_ % 2;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_session.h b/chromium/net/quic/quic_session.h
deleted file mode 100644
index 46c22d3c343..00000000000
--- a/chromium/net/quic/quic_session.h
+++ /dev/null
@@ -1,417 +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.
-//
-// A QuicSession, which demuxes a single connection to individual streams.
-
-#ifndef NET_QUIC_QUIC_SESSION_H_
-#define NET_QUIC_QUIC_SESSION_H_
-
-#include <stddef.h>
-
-#include <map>
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_crypto_stream.h"
-#include "net/quic/quic_packet_creator.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_write_blocked_list.h"
-#include "net/quic/reliable_quic_stream.h"
-
-namespace net {
-
-class QuicCryptoStream;
-class QuicFlowController;
-class ReliableQuicStream;
-
-namespace test {
-class QuicSessionPeer;
-} // namespace test
-
-class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
- public:
- // CryptoHandshakeEvent enumerates the events generated by a QuicCryptoStream.
- enum CryptoHandshakeEvent {
- // ENCRYPTION_FIRST_ESTABLISHED indicates that a full client hello has been
- // sent by a client and that subsequent packets will be encrypted. (Client
- // only.)
- ENCRYPTION_FIRST_ESTABLISHED,
- // ENCRYPTION_REESTABLISHED indicates that a client hello was rejected by
- // the server and thus the encryption key has been updated. Therefore the
- // connection should resend any packets that were sent under
- // ENCRYPTION_INITIAL. (Client only.)
- ENCRYPTION_REESTABLISHED,
- // HANDSHAKE_CONFIRMED, in a client, indicates the the server has accepted
- // our handshake. In a server it indicates that a full, valid client hello
- // has been received. (Client and server.)
- HANDSHAKE_CONFIRMED,
- };
-
- // Takes ownership of |connection|.
- QuicSession(QuicConnection* connection, const QuicConfig& config);
-
- ~QuicSession() override;
-
- virtual void Initialize();
-
- // QuicConnectionVisitorInterface methods:
- void OnStreamFrame(const QuicStreamFrame& frame) override;
- void OnRstStream(const QuicRstStreamFrame& frame) override;
- void OnGoAway(const QuicGoAwayFrame& frame) override;
- void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override;
- void OnBlockedFrame(const QuicBlockedFrame& frame) override;
- void OnConnectionClosed(QuicErrorCode error,
- const std::string& error_details,
- ConnectionCloseSource source) override;
- void OnWriteBlocked() override {}
- void OnSuccessfulVersionNegotiation(const QuicVersion& version) override;
- void OnCanWrite() override;
- void OnCongestionWindowChange(QuicTime /*now*/) override {}
- void OnConnectionMigration(PeerAddressChangeType type) override {}
- // Deletes streams that are safe to be deleted now that it's safe to do so (no
- // other operations are being done on the streams at this time).
- void PostProcessAfterData() override;
- bool WillingAndAbleToWrite() const override;
- bool HasPendingHandshake() const override;
- bool HasOpenDynamicStreams() const override;
- void OnPathDegrading() override;
-
- // Called on every incoming packet. Passes |packet| through to |connection_|.
- virtual void ProcessUdpPacket(const IPEndPoint& self_address,
- const IPEndPoint& peer_address,
- const QuicReceivedPacket& packet);
-
- // Called by streams when they want to write data to the peer.
- // Returns a pair with the number of bytes consumed from data, and a boolean
- // indicating if the fin bit was consumed. This does not indicate the data
- // has been sent on the wire: it may have been turned into a packet and queued
- // if the socket was unexpectedly blocked.
- // If provided, |ack_notifier_delegate| will be registered to be notified when
- // we have seen ACKs for all packets resulting from this call.
- virtual QuicConsumedData WritevData(
- ReliableQuicStream* stream,
- QuicStreamId id,
- QuicIOVector iov,
- QuicStreamOffset offset,
- bool fin,
- QuicAckListenerInterface* ack_notifier_delegate);
-
- // Called by streams when they want to close the stream in both directions.
- virtual void SendRstStream(QuicStreamId id,
- QuicRstStreamErrorCode error,
- QuicStreamOffset bytes_written);
-
- // Called when the session wants to go away and not accept any new streams.
- void SendGoAway(QuicErrorCode error_code, const std::string& reason);
-
- // Removes the stream associated with 'stream_id' from the active stream map.
- virtual void CloseStream(QuicStreamId stream_id);
-
- // Returns true if outgoing packets will be encrypted, even if the server
- // hasn't confirmed the handshake yet.
- virtual bool IsEncryptionEstablished();
-
- // For a client, returns true if the server has confirmed our handshake. For
- // a server, returns true if a full, valid client hello has been received.
- virtual bool IsCryptoHandshakeConfirmed();
-
- // Called by the QuicCryptoStream when a new QuicConfig has been negotiated.
- virtual void OnConfigNegotiated();
-
- // Called by the QuicCryptoStream when the handshake enters a new state.
- //
- // Clients will call this function in the order:
- // ENCRYPTION_FIRST_ESTABLISHED
- // zero or more ENCRYPTION_REESTABLISHED
- // HANDSHAKE_CONFIRMED
- //
- // Servers will simply call it once with HANDSHAKE_CONFIRMED.
- virtual void OnCryptoHandshakeEvent(CryptoHandshakeEvent event);
-
- // Called by the QuicCryptoStream when a handshake message is sent.
- virtual void OnCryptoHandshakeMessageSent(
- const CryptoHandshakeMessage& message);
-
- // Called by the QuicCryptoStream when a handshake message is received.
- virtual void OnCryptoHandshakeMessageReceived(
- const CryptoHandshakeMessage& message);
-
- // Returns mutable config for this session. Returned config is owned
- // by QuicSession.
- QuicConfig* config();
-
- // Returns true if the stream existed previously and has been closed.
- // Returns false if the stream is still active or if the stream has
- // not yet been created.
- bool IsClosedStream(QuicStreamId id);
-
- QuicConnection* connection() { return connection_.get(); }
- const QuicConnection* connection() const { return connection_.get(); }
- size_t num_active_requests() const { return dynamic_stream_map_.size(); }
- const IPEndPoint& peer_address() const { return connection_->peer_address(); }
- QuicConnectionId connection_id() const {
- return connection_->connection_id();
- }
-
- // Returns the number of currently open streams, excluding the reserved
- // headers and crypto streams, and never counting unfinished streams.
- virtual size_t GetNumActiveStreams() const;
-
- // Returns the number of currently open peer initiated streams, excluding the
- // reserved headers and crypto streams.
- virtual size_t GetNumOpenIncomingStreams() const;
-
- // Returns the number of currently open self initiated streams, excluding the
- // reserved headers and crypto streams.
- virtual size_t GetNumOpenOutgoingStreams() const;
-
- // Returns the number of "available" streams, the stream ids less than
- // largest_peer_created_stream_id_ that have not yet been opened.
- virtual size_t GetNumAvailableStreams() const;
-
- // Add the stream to the session's write-blocked list because it is blocked by
- // connection-level flow control but not by its own stream-level flow control.
- // The stream will be given a chance to write when a connection-level
- // WINDOW_UPDATE arrives.
- void MarkConnectionLevelWriteBlocked(QuicStreamId id);
-
- // Returns true if the session has data to be sent, either queued in the
- // connection, or in a write-blocked stream.
- bool HasDataToWrite() const;
-
- bool goaway_sent() const;
-
- bool goaway_received() const;
-
- QuicErrorCode error() const { return error_; }
-
- Perspective perspective() const { return connection_->perspective(); }
-
- QuicFlowController* flow_controller() { return &flow_controller_; }
-
- // Returns true if connection is flow controller blocked.
- bool IsConnectionFlowControlBlocked() const;
-
- // Returns true if any stream is flow controller blocked.
- bool IsStreamFlowControlBlocked();
-
- size_t max_open_incoming_streams() const {
- return max_open_incoming_streams_;
- }
-
- size_t max_open_outgoing_streams() const {
- return max_open_outgoing_streams_;
- }
-
- size_t MaxAvailableStreams() const;
-
- // Returns existing static or dynamic stream with id = |stream_id|. If no
- // such stream exists, and |stream_id| is a peer-created dynamic stream id,
- // then a new stream is created and returned. In all other cases, nullptr is
- // returned.
- ReliableQuicStream* GetOrCreateStream(const QuicStreamId stream_id);
-
- // Mark a stream as draining.
- virtual void StreamDraining(QuicStreamId id);
-
- // Returns true if this stream should yield writes to another blocked stream.
- bool ShouldYield(QuicStreamId stream_id);
-
- protected:
- typedef std::unordered_map<QuicStreamId, ReliableQuicStream*> StreamMap;
-
- // Creates a new stream to handle a peer-initiated stream.
- // Caller does not own the returned stream.
- // Returns nullptr and does error handling if the stream can not be created.
- virtual ReliableQuicStream* CreateIncomingDynamicStream(QuicStreamId id) = 0;
-
- // Create a new stream to handle a locally-initiated stream.
- // Caller does not own the returned stream.
- // Returns nullptr if max streams have already been opened.
- virtual ReliableQuicStream* CreateOutgoingDynamicStream(
- SpdyPriority priority) = 0;
-
- // Return the reserved crypto stream.
- virtual QuicCryptoStream* GetCryptoStream() = 0;
-
- // Adds |stream| to the dynamic stream map.
- // Takes ownership of |stream|.
- virtual void ActivateStream(ReliableQuicStream* stream);
-
- // Returns the stream ID for a new outgoing stream, and increments the
- // underlying counter.
- QuicStreamId GetNextOutgoingStreamId();
-
- // Returns existing stream with id = |stream_id|. If no such stream exists,
- // and |stream_id| is a peer-created id, then a new stream is created and
- // returned. However if |stream_id| is a locally-created id and no such stream
- // exists, the connection is closed.
- // Caller does not own the returned stream.
- ReliableQuicStream* GetOrCreateDynamicStream(QuicStreamId stream_id);
-
- // Performs the work required to close |stream_id|. If |locally_reset|
- // then the stream has been reset by this endpoint, not by the peer.
- virtual void CloseStreamInner(QuicStreamId stream_id, bool locally_reset);
-
- // When a stream is closed locally, it may not yet know how many bytes the
- // peer sent on that stream.
- // When this data arrives (via stream frame w. FIN, or RST) this method
- // is called, and correctly updates the connection level flow controller.
- void UpdateFlowControlOnFinalReceivedByteOffset(
- QuicStreamId id,
- QuicStreamOffset final_byte_offset);
-
- // Return true if given stream is peer initiated.
- bool IsIncomingStream(QuicStreamId id) const;
-
- StreamMap& static_streams() { return static_stream_map_; }
- const StreamMap& static_streams() const { return static_stream_map_; }
-
- StreamMap& dynamic_streams() { return dynamic_stream_map_; }
- const StreamMap& dynamic_streams() const { return dynamic_stream_map_; }
-
- std::vector<ReliableQuicStream*>* closed_streams() {
- return &closed_streams_;
- }
-
- void set_max_open_incoming_streams(size_t max_open_incoming_streams);
- void set_max_open_outgoing_streams(size_t max_open_outgoing_streams);
-
- void set_largest_peer_created_stream_id(
- QuicStreamId largest_peer_created_stream_id) {
- largest_peer_created_stream_id_ = largest_peer_created_stream_id;
- }
- void set_error(QuicErrorCode error) { error_ = error; }
- QuicWriteBlockedList* write_blocked_streams() {
- return &write_blocked_streams_;
- }
-
- size_t GetNumDynamicOutgoingStreams() const;
-
- size_t GetNumDrainingOutgoingStreams() const;
-
- size_t num_locally_closed_incoming_streams_highest_offset() const {
- return num_locally_closed_incoming_streams_highest_offset_;
- }
-
- size_t GetNumLocallyClosedOutgoingStreamsHighestOffset() const;
-
- // Returns true if the stream is still active.
- bool IsOpenStream(QuicStreamId id);
-
- QuicStreamId next_outgoing_stream_id() const {
- return next_outgoing_stream_id_;
- }
-
- // Close connection when receive a frame for a locally-created nonexistant
- // stream.
- // Prerequisite: IsClosedStream(stream_id) == false
- // Server session might need to override this method to allow server push
- // stream to be promised before creating an active stream.
- virtual void HandleFrameOnNonexistentOutgoingStream(QuicStreamId stream_id);
-
- bool MaybeIncreaseLargestPeerStreamId(const QuicStreamId stream_id);
-
- void InsertLocallyClosedStreamsHighestOffset(const QuicStreamId id,
- QuicStreamOffset offset);
- // If stream is a locally closed stream, this RST will update FIN offset.
- // Otherwise stream is a preserved stream and the behavior of it depends on
- // derived class's own implementation.
- virtual void HandleRstOnValidNonexistentStream(
- const QuicRstStreamFrame& frame);
-
- private:
- friend class test::QuicSessionPeer;
-
- // Called in OnConfigNegotiated when we receive a new stream level flow
- // control window in a negotiated config. Closes the connection if invalid.
- void OnNewStreamFlowControlWindow(QuicStreamOffset new_window);
-
- // Called in OnConfigNegotiated when we receive a new connection level flow
- // control window in a negotiated config. Closes the connection if invalid.
- void OnNewSessionFlowControlWindow(QuicStreamOffset new_window);
-
- // Called in OnConfigNegotiated when auto-tuning is enabled for flow
- // control receive windows.
- void EnableAutoTuneReceiveWindow();
-
- // Called in OnConfigNegotiated for finch trials to measure performance of
- // starting with smaller flow control receive windows and auto-tuning.
- void AdjustInitialFlowControlWindows(size_t stream_window);
-
- // 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>
- locally_closed_streams_highest_offset_;
-
- std::unique_ptr<QuicConnection> connection_;
-
- std::vector<ReliableQuicStream*> closed_streams_;
-
- QuicConfig config_;
-
- // The maximum number of outgoing streams this connection can open.
- size_t max_open_outgoing_streams_;
-
- // The maximum number of incoming streams this connection will allow.
- size_t max_open_incoming_streams_;
-
- // Static streams, such as crypto and header streams. Owned by child classes
- // that create these streams.
- StreamMap static_stream_map_;
-
- // Map from StreamId to pointers to streams. Owns the streams.
- StreamMap dynamic_stream_map_;
-
- // The ID to use for the next outgoing stream.
- QuicStreamId next_outgoing_stream_id_;
-
- // Set of stream ids that are less than the largest stream id that has been
- // received, but are nonetheless available to be created.
- std::unordered_set<QuicStreamId> available_streams_;
-
- // Set of stream ids that are "draining" -- a FIN has been sent and received,
- // but the stream object still exists because not all the received data has
- // been consumed.
- std::unordered_set<QuicStreamId> draining_streams_;
-
- // A list of streams which need to write more data.
- QuicWriteBlockedList write_blocked_streams_;
-
- QuicStreamId largest_peer_created_stream_id_;
-
- // A counter for peer initiated streams which are in the dynamic_stream_map_.
- size_t num_dynamic_incoming_streams_;
-
- // A counter for peer initiated streams which are in the draining_streams_.
- size_t num_draining_incoming_streams_;
-
- // A counter for peer initiated streams which are in the
- // locally_closed_streams_highest_offset_.
- size_t num_locally_closed_incoming_streams_highest_offset_;
-
- // The latched error with which the connection was closed.
- QuicErrorCode error_;
-
- // Used for connection-level flow control.
- QuicFlowController flow_controller_;
-
- // The stream id which was last popped in OnCanWrite, or 0, if not under the
- // call stack of OnCanWrite.
- QuicStreamId currently_writing_stream_id_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicSession);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_SESSION_H_
diff --git a/chromium/net/quic/quic_session_test.cc b/chromium/net/quic/quic_session_test.cc
deleted file mode 100644
index 9ad209c98fd..00000000000
--- a/chromium/net/quic/quic_session_test.cc
+++ /dev/null
@@ -1,1187 +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/quic_session.h"
-
-#include <set>
-#include <utility>
-
-#include "base/rand_util.h"
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "build/build_config.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/quic_crypto_stream.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/reliable_quic_stream.h"
-#include "net/quic/test_tools/quic_config_peer.h"
-#include "net/quic/test_tools/quic_connection_peer.h"
-#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_spdy_session_peer.h"
-#include "net/quic/test_tools/quic_spdy_stream_peer.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/quic/test_tools/reliable_quic_stream_peer.h"
-#include "net/spdy/spdy_framer.h"
-#include "net/test/gtest_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gmock_mutant.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::set;
-using std::string;
-using std::vector;
-using testing::CreateFunctor;
-using testing::InSequence;
-using testing::Invoke;
-using testing::Return;
-using testing::StrictMock;
-using testing::_;
-
-namespace net {
-namespace test {
-namespace {
-
-const SpdyPriority kHighestPriority = kV3HighestPriority;
-
-class TestCryptoStream : public QuicCryptoStream {
- public:
- explicit TestCryptoStream(QuicSession* session) : QuicCryptoStream(session) {}
-
- void OnHandshakeMessage(const CryptoHandshakeMessage& /*message*/) override {
- encryption_established_ = true;
- handshake_confirmed_ = true;
- CryptoHandshakeMessage msg;
- string error_details;
- session()->config()->SetInitialStreamFlowControlWindowToSend(
- kInitialStreamFlowControlWindowForTest);
- session()->config()->SetInitialSessionFlowControlWindowToSend(
- kInitialSessionFlowControlWindowForTest);
- session()->config()->ToHandshakeMessage(&msg);
- const QuicErrorCode error =
- session()->config()->ProcessPeerHello(msg, CLIENT, &error_details);
- EXPECT_EQ(QUIC_NO_ERROR, error);
- session()->OnConfigNegotiated();
- session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
- }
-
- MOCK_METHOD0(OnCanWrite, void());
-};
-
-class TestHeadersStream : public QuicHeadersStream {
- public:
- explicit TestHeadersStream(QuicSpdySession* session)
- : QuicHeadersStream(session) {}
-
- MOCK_METHOD0(OnCanWrite, void());
-};
-
-class TestStream : public QuicSpdyStream {
- public:
- TestStream(QuicStreamId id, QuicSpdySession* session)
- : QuicSpdyStream(id, session) {}
-
- using ReliableQuicStream::CloseWriteSide;
-
- void OnDataAvailable() override {}
-
- MOCK_METHOD0(OnCanWrite, void());
-};
-
-// Poor man's functor for use as callback in a mock.
-class StreamBlocker {
- public:
- StreamBlocker(QuicSession* session, QuicStreamId stream_id)
- : session_(session), stream_id_(stream_id) {}
-
- void MarkConnectionLevelWriteBlocked() {
- session_->MarkConnectionLevelWriteBlocked(stream_id_);
- }
-
- private:
- QuicSession* const session_;
- const QuicStreamId stream_id_;
-};
-
-class TestSession : public QuicSpdySession {
- public:
- explicit TestSession(QuicConnection* connection)
- : QuicSpdySession(connection, DefaultQuicConfig()),
- crypto_stream_(this),
- writev_consumes_all_data_(false) {
- Initialize();
- }
-
- TestCryptoStream* GetCryptoStream() override { return &crypto_stream_; }
-
- TestStream* CreateOutgoingDynamicStream(SpdyPriority priority) override {
- TestStream* stream = new TestStream(GetNextOutgoingStreamId(), this);
- stream->SetPriority(priority);
- ActivateStream(stream);
- return stream;
- }
-
- TestStream* CreateIncomingDynamicStream(QuicStreamId id) override {
- // Enforce the limit on the number of open streams.
- if (GetNumOpenIncomingStreams() + 1 > max_open_incoming_streams()) {
- connection()->CloseConnection(
- QUIC_TOO_MANY_OPEN_STREAMS, "Too many streams!",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return nullptr;
- } else {
- TestStream* stream = new TestStream(id, this);
- ActivateStream(stream);
- return stream;
- }
- }
-
- bool ShouldCreateIncomingDynamicStream(QuicStreamId /*id*/) override {
- return true;
- }
-
- bool ShouldCreateOutgoingDynamicStream() override { return true; }
-
- bool IsClosedStream(QuicStreamId id) {
- return QuicSession::IsClosedStream(id);
- }
-
- ReliableQuicStream* GetOrCreateDynamicStream(QuicStreamId stream_id) {
- return QuicSpdySession::GetOrCreateDynamicStream(stream_id);
- }
-
- QuicConsumedData WritevData(
- ReliableQuicStream* stream,
- QuicStreamId id,
- QuicIOVector data,
- QuicStreamOffset offset,
- bool fin,
- QuicAckListenerInterface* ack_notifier_delegate) override {
- QuicConsumedData consumed(data.total_length, fin);
- if (!writev_consumes_all_data_) {
- consumed = QuicSession::WritevData(stream, id, data, offset, fin,
- ack_notifier_delegate);
- }
- QuicSessionPeer::GetWriteBlockedStreams(this)->UpdateBytesForStream(
- id, consumed.bytes_consumed);
- return consumed;
- }
-
- void set_writev_consumes_all_data(bool val) {
- writev_consumes_all_data_ = val;
- }
-
- QuicConsumedData SendStreamData(ReliableQuicStream* stream) {
- struct iovec iov;
- return WritevData(stream, stream->id(), MakeIOVector("not empty", &iov), 0,
- true, nullptr);
- }
-
- QuicConsumedData SendLargeFakeData(ReliableQuicStream* stream, int bytes) {
- DCHECK(writev_consumes_all_data_);
- struct iovec iov;
- iov.iov_base = nullptr; // should not be read.
- iov.iov_len = static_cast<size_t>(bytes);
- return WritevData(stream, stream->id(), QuicIOVector(&iov, 1, bytes), 0,
- true, nullptr);
- }
-
- using QuicSession::PostProcessAfterData;
-
- private:
- StrictMock<TestCryptoStream> crypto_stream_;
-
- bool writev_consumes_all_data_;
-};
-
-class QuicSessionTestBase : public ::testing::TestWithParam<QuicVersion> {
- protected:
- explicit QuicSessionTestBase(Perspective perspective)
- : connection_(
- new StrictMock<MockQuicConnection>(&helper_,
- &alarm_factory_,
- perspective,
- SupportedVersions(GetParam()))),
- session_(connection_) {
- FLAGS_quic_always_log_bugs_for_tests = true;
- session_.config()->SetInitialStreamFlowControlWindowToSend(
- kInitialStreamFlowControlWindowForTest);
- session_.config()->SetInitialSessionFlowControlWindowToSend(
- kInitialSessionFlowControlWindowForTest);
- headers_[":host"] = "www.google.com";
- headers_[":path"] = "/index.hml";
- headers_[":scheme"] = "http";
- headers_["cookie"] =
- "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; "
- "__utmc=160408618; "
- "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX"
- "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX"
- "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT"
- "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0"
- "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh"
- "1zFMi5vzcns38-8_Sns; "
- "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-"
- "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339"
- "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c"
- "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%"
- "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4"
- "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1"
- "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP"
- "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6"
- "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b"
- "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6"
- "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG"
- "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk"
- "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn"
- "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
- "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
- connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
- // TODO(ianswett): Fix QuicSessionTests so they don't attempt to write
- // non-crypto stream data at ENCRYPTION_NONE.
- FLAGS_quic_never_write_unencrypted_data = false;
- }
-
- void CheckClosedStreams() {
- for (QuicStreamId i = kCryptoStreamId; i < 100; i++) {
- if (!ContainsKey(closed_streams_, i)) {
- EXPECT_FALSE(session_.IsClosedStream(i)) << " stream id: " << i;
- } else {
- EXPECT_TRUE(session_.IsClosedStream(i)) << " stream id: " << i;
- }
- }
- }
-
- void CloseStream(QuicStreamId id) {
- EXPECT_CALL(*connection_, SendRstStream(id, _, _));
- session_.CloseStream(id);
- closed_streams_.insert(id);
- }
-
- QuicVersion version() const { return connection_->version(); }
-
- MockQuicConnectionHelper helper_;
- MockAlarmFactory alarm_factory_;
- StrictMock<MockQuicConnection>* connection_;
- TestSession session_;
- set<QuicStreamId> closed_streams_;
- SpdyHeaderBlock headers_;
-};
-
-class QuicSessionTestServer : public QuicSessionTestBase {
- protected:
- QuicSessionTestServer() : QuicSessionTestBase(Perspective::IS_SERVER) {}
-};
-
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicSessionTestServer,
- ::testing::ValuesIn(QuicSupportedVersions()));
-
-TEST_P(QuicSessionTestServer, PeerAddress) {
- EXPECT_EQ(IPEndPoint(Loopback4(), kTestPort), session_.peer_address());
-}
-
-TEST_P(QuicSessionTestServer, IsCryptoHandshakeConfirmed) {
- EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed());
- CryptoHandshakeMessage message;
- session_.GetCryptoStream()->OnHandshakeMessage(message);
- EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed());
-}
-
-TEST_P(QuicSessionTestServer, IsClosedStreamDefault) {
- // Ensure that no streams are initially closed.
- for (QuicStreamId i = kCryptoStreamId; i < 100; i++) {
- EXPECT_FALSE(session_.IsClosedStream(i)) << "stream id: " << i;
- }
-}
-
-TEST_P(QuicSessionTestServer, AvailableStreams) {
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(9) != nullptr);
- // Both 5 and 7 should be available.
- EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 5));
- EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 7));
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(7) != nullptr);
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(5) != nullptr);
-}
-
-TEST_P(QuicSessionTestServer, IsClosedStreamLocallyCreated) {
- TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- EXPECT_EQ(2u, stream2->id());
- TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- EXPECT_EQ(4u, stream4->id());
-
- CheckClosedStreams();
- CloseStream(4);
- CheckClosedStreams();
- CloseStream(2);
- CheckClosedStreams();
-}
-
-TEST_P(QuicSessionTestServer, IsClosedStreamPeerCreated) {
- QuicStreamId stream_id1 = kClientDataStreamId1;
- QuicStreamId stream_id2 = kClientDataStreamId2;
- session_.GetOrCreateDynamicStream(stream_id1);
- session_.GetOrCreateDynamicStream(stream_id2);
-
- CheckClosedStreams();
- CloseStream(stream_id1);
- CheckClosedStreams();
- CloseStream(stream_id2);
- // Create a stream, and make another available.
- ReliableQuicStream* stream3 =
- session_.GetOrCreateDynamicStream(stream_id2 + 4);
- CheckClosedStreams();
- // Close one, but make sure the other is still not closed
- CloseStream(stream3->id());
- CheckClosedStreams();
-}
-
-TEST_P(QuicSessionTestServer, MaximumAvailableOpenedStreams) {
- QuicStreamId stream_id = kClientDataStreamId1;
- session_.GetOrCreateDynamicStream(stream_id);
- EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
- EXPECT_NE(nullptr,
- session_.GetOrCreateDynamicStream(
- stream_id + 2 * (session_.max_open_incoming_streams() - 1)));
-}
-
-TEST_P(QuicSessionTestServer, TooManyAvailableStreams) {
- QuicStreamId stream_id1 = kClientDataStreamId1;
- QuicStreamId stream_id2;
- EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id1));
- // A stream ID which is too large to create.
- stream_id2 = stream_id1 + 2 * session_.MaxAvailableStreams() + 4;
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_TOO_MANY_AVAILABLE_STREAMS, _, _));
- EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream(stream_id2));
-}
-
-TEST_P(QuicSessionTestServer, ManyAvailableStreams) {
- // When max_open_streams_ is 200, should be able to create 200 streams
- // out-of-order, that is, creating the one with the largest stream ID first.
- QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200);
- QuicStreamId stream_id = kClientDataStreamId1;
- // Create one stream.
- session_.GetOrCreateDynamicStream(stream_id);
- EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
- // Create the largest stream ID of a threatened total of 200 streams.
- session_.GetOrCreateDynamicStream(stream_id + 2 * (200 - 1));
-}
-
-TEST_P(QuicSessionTestServer, DebugDFatalIfMarkingClosedStreamWriteBlocked) {
- TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- QuicStreamId closed_stream_id = stream2->id();
- // Close the stream.
- EXPECT_CALL(*connection_, SendRstStream(closed_stream_id, _, _));
- stream2->Reset(QUIC_BAD_APPLICATION_PAYLOAD);
- EXPECT_DEBUG_DFATAL(
- session_.MarkConnectionLevelWriteBlocked(closed_stream_id),
- "Marking unknown stream 2 blocked.");
-}
-
-TEST_P(QuicSessionTestServer, OnCanWrite) {
- TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
-
- session_.MarkConnectionLevelWriteBlocked(stream2->id());
- session_.MarkConnectionLevelWriteBlocked(stream6->id());
- session_.MarkConnectionLevelWriteBlocked(stream4->id());
-
- InSequence s;
- StreamBlocker stream2_blocker(&session_, stream2->id());
-
- // Reregister, to test the loop limit.
- EXPECT_CALL(*stream2, OnCanWrite())
- .WillOnce(Invoke(&stream2_blocker,
- &StreamBlocker::MarkConnectionLevelWriteBlocked));
- // 2 will get called a second time as it didn't finish its block
- EXPECT_CALL(*stream2, OnCanWrite());
- EXPECT_CALL(*stream6, OnCanWrite());
- // 4 will not get called, as we exceeded the loop limit.
- session_.OnCanWrite();
- EXPECT_TRUE(session_.WillingAndAbleToWrite());
-}
-
-TEST_P(QuicSessionTestServer, TestBatchedWrites) {
- TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
-
- session_.set_writev_consumes_all_data(true);
- session_.MarkConnectionLevelWriteBlocked(stream2->id());
- session_.MarkConnectionLevelWriteBlocked(stream4->id());
-
- StreamBlocker stream2_blocker(&session_, stream2->id());
- StreamBlocker stream4_blocker(&session_, stream4->id());
- StreamBlocker stream6_blocker(&session_, stream6->id());
- // With two sessions blocked, we should get two write calls. They should both
- // go to the first stream as it will only write 6k and mark itself blocked
- // again.
- InSequence s;
- EXPECT_CALL(*stream2, OnCanWrite())
- .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor(
- &TestSession::SendLargeFakeData,
- base::Unretained(&session_), stream2, 6000))),
- Invoke(&stream2_blocker,
- &StreamBlocker::MarkConnectionLevelWriteBlocked)));
- EXPECT_CALL(*stream2, OnCanWrite())
- .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor(
- &TestSession::SendLargeFakeData,
- base::Unretained(&session_), stream2, 6000))),
- Invoke(&stream2_blocker,
- &StreamBlocker::MarkConnectionLevelWriteBlocked)));
- session_.OnCanWrite();
-
- // We should get one more call for stream2, at which point it has used its
- // write quota and we move over to stream 4.
- EXPECT_CALL(*stream2, OnCanWrite())
- .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor(
- &TestSession::SendLargeFakeData,
- base::Unretained(&session_), stream2, 6000))),
- Invoke(&stream2_blocker,
- &StreamBlocker::MarkConnectionLevelWriteBlocked)));
- EXPECT_CALL(*stream4, OnCanWrite())
- .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor(
- &TestSession::SendLargeFakeData,
- base::Unretained(&session_), stream4, 6000))),
- Invoke(&stream4_blocker,
- &StreamBlocker::MarkConnectionLevelWriteBlocked)));
- session_.OnCanWrite();
-
- // Now let stream 4 do the 2nd of its 3 writes, but add a block for a high
- // priority stream 6. 4 should be preempted. 6 will write but *not* block so
- // will cede back to 4.
- stream6->SetPriority(kHighestPriority);
- EXPECT_CALL(*stream4, OnCanWrite())
- .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor(
- &TestSession::SendLargeFakeData,
- base::Unretained(&session_), stream4, 6000))),
- Invoke(&stream4_blocker,
- &StreamBlocker::MarkConnectionLevelWriteBlocked),
- Invoke(&stream6_blocker,
- &StreamBlocker::MarkConnectionLevelWriteBlocked)));
- EXPECT_CALL(*stream6, OnCanWrite())
- .WillOnce(testing::IgnoreResult(
- Invoke(CreateFunctor(&TestSession::SendLargeFakeData,
- base::Unretained(&session_), stream4, 6000))));
- session_.OnCanWrite();
-
- // Stream4 alread did 6k worth of writes, so after doing another 12k it should
- // cede and 2 should resume.
- EXPECT_CALL(*stream4, OnCanWrite())
- .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor(
- &TestSession::SendLargeFakeData,
- base::Unretained(&session_), stream4, 12000))),
- Invoke(&stream4_blocker,
- &StreamBlocker::MarkConnectionLevelWriteBlocked)));
- EXPECT_CALL(*stream2, OnCanWrite())
- .WillOnce(DoAll(testing::IgnoreResult(Invoke(CreateFunctor(
- &TestSession::SendLargeFakeData,
- base::Unretained(&session_), stream2, 6000))),
- Invoke(&stream2_blocker,
- &StreamBlocker::MarkConnectionLevelWriteBlocked)));
- session_.OnCanWrite();
-}
-
-TEST_P(QuicSessionTestServer, OnCanWriteBundlesStreams) {
- // Encryption needs to be established before data can be sent.
- CryptoHandshakeMessage msg;
- session_.GetCryptoStream()->OnHandshakeMessage(msg);
-
- // Drive congestion control manually.
- MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>;
- QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm);
-
- TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
-
- session_.MarkConnectionLevelWriteBlocked(stream2->id());
- session_.MarkConnectionLevelWriteBlocked(stream6->id());
- session_.MarkConnectionLevelWriteBlocked(stream4->id());
-
- EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _))
- .WillRepeatedly(Return(QuicTime::Delta::Zero()));
- EXPECT_CALL(*send_algorithm, GetCongestionWindow())
- .WillRepeatedly(Return(kMaxPacketSize * 10));
- EXPECT_CALL(*stream2, OnCanWrite())
- .WillOnce(testing::IgnoreResult(
- Invoke(CreateFunctor(&TestSession::SendStreamData,
- base::Unretained(&session_), stream2))));
- EXPECT_CALL(*stream4, OnCanWrite())
- .WillOnce(testing::IgnoreResult(
- Invoke(CreateFunctor(&TestSession::SendStreamData,
- base::Unretained(&session_), stream4))));
- EXPECT_CALL(*stream6, OnCanWrite())
- .WillOnce(testing::IgnoreResult(
- Invoke(CreateFunctor(&TestSession::SendStreamData,
- base::Unretained(&session_), stream6))));
-
- // Expect that we only send one packet, the writes from different streams
- // should be bundled together.
- MockPacketWriter* writer = static_cast<MockPacketWriter*>(
- QuicConnectionPeer::GetWriter(session_.connection()));
- EXPECT_CALL(*writer, WritePacket(_, _, _, _, _))
- .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
- EXPECT_CALL(*send_algorithm, OnPacketSent(_, _, _, _, _));
- session_.OnCanWrite();
- EXPECT_FALSE(session_.WillingAndAbleToWrite());
-}
-
-TEST_P(QuicSessionTestServer, OnCanWriteCongestionControlBlocks) {
- InSequence s;
-
- // Drive congestion control manually.
- MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>;
- QuicConnectionPeer::SetSendAlgorithm(session_.connection(), send_algorithm);
-
- TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
-
- session_.MarkConnectionLevelWriteBlocked(stream2->id());
- session_.MarkConnectionLevelWriteBlocked(stream6->id());
- session_.MarkConnectionLevelWriteBlocked(stream4->id());
-
- StreamBlocker stream2_blocker(&session_, stream2->id());
- EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _))
- .WillOnce(Return(QuicTime::Delta::Zero()));
- EXPECT_CALL(*stream2, OnCanWrite());
- EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _))
- .WillOnce(Return(QuicTime::Delta::Zero()));
- EXPECT_CALL(*stream6, OnCanWrite());
- EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _))
- .WillOnce(Return(QuicTime::Delta::Infinite()));
- // stream4->OnCanWrite is not called.
-
- session_.OnCanWrite();
- EXPECT_TRUE(session_.WillingAndAbleToWrite());
-
- // Still congestion-control blocked.
- EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _))
- .WillOnce(Return(QuicTime::Delta::Infinite()));
- session_.OnCanWrite();
- EXPECT_TRUE(session_.WillingAndAbleToWrite());
-
- // stream4->OnCanWrite is called once the connection stops being
- // congestion-control blocked.
- EXPECT_CALL(*send_algorithm, TimeUntilSend(_, _))
- .WillOnce(Return(QuicTime::Delta::Zero()));
- EXPECT_CALL(*stream4, OnCanWrite());
- session_.OnCanWrite();
- EXPECT_FALSE(session_.WillingAndAbleToWrite());
-}
-
-TEST_P(QuicSessionTestServer, BufferedHandshake) {
- EXPECT_FALSE(session_.HasPendingHandshake()); // Default value.
-
- // Test that blocking other streams does not change our status.
- TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- StreamBlocker stream2_blocker(&session_, stream2->id());
- stream2_blocker.MarkConnectionLevelWriteBlocked();
- EXPECT_FALSE(session_.HasPendingHandshake());
-
- TestStream* stream3 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- StreamBlocker stream3_blocker(&session_, stream3->id());
- stream3_blocker.MarkConnectionLevelWriteBlocked();
- EXPECT_FALSE(session_.HasPendingHandshake());
-
- // Blocking (due to buffering of) the Crypto stream is detected.
- session_.MarkConnectionLevelWriteBlocked(kCryptoStreamId);
- EXPECT_TRUE(session_.HasPendingHandshake());
-
- TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- StreamBlocker stream4_blocker(&session_, stream4->id());
- stream4_blocker.MarkConnectionLevelWriteBlocked();
- EXPECT_TRUE(session_.HasPendingHandshake());
-
- InSequence s;
- // Force most streams to re-register, which is common scenario when we block
- // the Crypto stream, and only the crypto stream can "really" write.
-
- // Due to prioritization, we *should* be asked to write the crypto stream
- // first.
- // Don't re-register the crypto stream (which signals complete writing).
- TestCryptoStream* crypto_stream = session_.GetCryptoStream();
- EXPECT_CALL(*crypto_stream, OnCanWrite());
-
- EXPECT_CALL(*stream2, OnCanWrite());
- EXPECT_CALL(*stream3, OnCanWrite());
- EXPECT_CALL(*stream4, OnCanWrite())
- .WillOnce(Invoke(&stream4_blocker,
- &StreamBlocker::MarkConnectionLevelWriteBlocked));
-
- session_.OnCanWrite();
- EXPECT_TRUE(session_.WillingAndAbleToWrite());
- EXPECT_FALSE(session_.HasPendingHandshake()); // Crypto stream wrote.
-}
-
-TEST_P(QuicSessionTestServer, OnCanWriteWithClosedStream) {
- TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
-
- session_.MarkConnectionLevelWriteBlocked(stream2->id());
- session_.MarkConnectionLevelWriteBlocked(stream6->id());
- session_.MarkConnectionLevelWriteBlocked(stream4->id());
- CloseStream(stream6->id());
-
- InSequence s;
- EXPECT_CALL(*stream2, OnCanWrite());
- EXPECT_CALL(*stream4, OnCanWrite());
- session_.OnCanWrite();
- EXPECT_FALSE(session_.WillingAndAbleToWrite());
-}
-
-TEST_P(QuicSessionTestServer, OnCanWriteLimitsNumWritesIfFlowControlBlocked) {
- // Ensure connection level flow control blockage.
- QuicFlowControllerPeer::SetSendWindowOffset(session_.flow_controller(), 0);
- EXPECT_TRUE(session_.flow_controller()->IsBlocked());
- EXPECT_TRUE(session_.IsConnectionFlowControlBlocked());
- EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
-
- // Mark the crypto and headers streams as write blocked, we expect them to be
- // allowed to write later.
- session_.MarkConnectionLevelWriteBlocked(kCryptoStreamId);
- session_.MarkConnectionLevelWriteBlocked(kHeadersStreamId);
-
- // Create a data stream, and although it is write blocked we never expect it
- // to be allowed to write as we are connection level flow control blocked.
- TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- session_.MarkConnectionLevelWriteBlocked(stream->id());
- EXPECT_CALL(*stream, OnCanWrite()).Times(0);
-
- // The crypto and headers streams should be called even though we are
- // connection flow control blocked.
- TestCryptoStream* crypto_stream = session_.GetCryptoStream();
- EXPECT_CALL(*crypto_stream, OnCanWrite());
- TestHeadersStream* headers_stream = new TestHeadersStream(&session_);
- QuicSpdySessionPeer::SetHeadersStream(&session_, headers_stream);
- EXPECT_CALL(*headers_stream, OnCanWrite());
-
- session_.OnCanWrite();
- EXPECT_FALSE(session_.WillingAndAbleToWrite());
-}
-
-TEST_P(QuicSessionTestServer, SendGoAway) {
- MockPacketWriter* writer = static_cast<MockPacketWriter*>(
- QuicConnectionPeer::GetWriter(session_.connection()));
- EXPECT_CALL(*writer, WritePacket(_, _, _, _, _))
- .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0)));
- EXPECT_CALL(*connection_, SendGoAway(_, _, _))
- .WillOnce(Invoke(connection_, &MockQuicConnection::ReallySendGoAway));
- session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away.");
- EXPECT_TRUE(session_.goaway_sent());
-
- const QuicStreamId kTestStreamId = 5u;
- EXPECT_CALL(*connection_,
- SendRstStream(kTestStreamId, QUIC_STREAM_PEER_GOING_AWAY, 0))
- .Times(0);
- EXPECT_TRUE(session_.GetOrCreateDynamicStream(kTestStreamId));
-}
-
-TEST_P(QuicSessionTestServer, IncreasedTimeoutAfterCryptoHandshake) {
- EXPECT_EQ(kInitialIdleTimeoutSecs + 3,
- QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
- CryptoHandshakeMessage msg;
- session_.GetCryptoStream()->OnHandshakeMessage(msg);
- EXPECT_EQ(kMaximumIdleTimeoutSecs + 3,
- QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
-}
-
-TEST_P(QuicSessionTestServer, RstStreamBeforeHeadersDecompressed) {
- // Send two bytes of payload.
- QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT"));
- session_.OnStreamFrame(data1);
- EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams());
-
- EXPECT_CALL(*connection_, SendRstStream(kClientDataStreamId1, _, _));
- QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM,
- 0);
- session_.OnRstStream(rst1);
- EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
- // Connection should remain alive.
- EXPECT_TRUE(connection_->connected());
-}
-
-TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedStream) {
- // Test that if a stream is flow control blocked, then on receipt of the SHLO
- // containing a suitable send window offset, the stream becomes unblocked.
-
- // Ensure that Writev consumes all the data it is given (simulate no socket
- // blocking).
- session_.set_writev_consumes_all_data(true);
-
- // Create a stream, and send enough data to make it flow control blocked.
- TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- string body(kMinimumFlowControlSendWindow, '.');
- EXPECT_FALSE(stream2->flow_controller()->IsBlocked());
- EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
- EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
- EXPECT_CALL(*connection_, SendBlocked(stream2->id()));
- EXPECT_CALL(*connection_, SendBlocked(0));
- stream2->WriteOrBufferBody(body, false, nullptr);
- EXPECT_TRUE(stream2->flow_controller()->IsBlocked());
- EXPECT_TRUE(session_.IsConnectionFlowControlBlocked());
- EXPECT_TRUE(session_.IsStreamFlowControlBlocked());
-
- // The handshake message will call OnCanWrite, so the stream can resume
- // writing.
- EXPECT_CALL(*stream2, OnCanWrite());
- // Now complete the crypto handshake, resulting in an increased flow control
- // send window.
- CryptoHandshakeMessage msg;
- session_.GetCryptoStream()->OnHandshakeMessage(msg);
-
- // Stream is now unblocked.
- EXPECT_FALSE(stream2->flow_controller()->IsBlocked());
- EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
- EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
-}
-
-TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedCryptoStream) {
- // Test that if the crypto stream is flow control blocked, then if the SHLO
- // contains a larger send window offset, the stream becomes unblocked.
- session_.set_writev_consumes_all_data(true);
- TestCryptoStream* crypto_stream = session_.GetCryptoStream();
- EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked());
- EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
- EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
- QuicHeadersStream* headers_stream =
- QuicSpdySessionPeer::GetHeadersStream(&session_);
- EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked());
- EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
- EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
- // Write until the crypto stream is flow control blocked.
- EXPECT_CALL(*connection_, SendBlocked(kCryptoStreamId));
- for (QuicStreamId i = 0;
- !crypto_stream->flow_controller()->IsBlocked() && i < 1000u; i++) {
- EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
- EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
- QuicConfig config;
- CryptoHandshakeMessage crypto_message;
- config.ToHandshakeMessage(&crypto_message);
- crypto_stream->SendHandshakeMessage(crypto_message);
- }
- EXPECT_TRUE(crypto_stream->flow_controller()->IsBlocked());
- EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked());
- EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
- EXPECT_TRUE(session_.IsStreamFlowControlBlocked());
- EXPECT_FALSE(session_.HasDataToWrite());
- EXPECT_TRUE(crypto_stream->HasBufferedData());
-
- // The handshake message will call OnCanWrite, so the stream can
- // resume writing.
- EXPECT_CALL(*crypto_stream, OnCanWrite());
- // Now complete the crypto handshake, resulting in an increased flow control
- // send window.
- CryptoHandshakeMessage msg;
- session_.GetCryptoStream()->OnHandshakeMessage(msg);
-
- // Stream is now unblocked and will no longer have buffered data.
- EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked());
- EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
- EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
-}
-
-#if !defined(OS_IOS)
-// This test is failing flakily for iOS bots.
-// http://crbug.com/425050
-// NOTE: It's not possible to use the standard MAYBE_ convention to disable
-// this test on iOS because when this test gets instantiated it ends up with
-// various names that are dependent on the parameters passed.
-TEST_P(QuicSessionTestServer,
- HandshakeUnblocksFlowControlBlockedHeadersStream) {
- // Test that if the header stream is flow control blocked, then if the SHLO
- // contains a larger send window offset, the stream becomes unblocked.
- session_.set_writev_consumes_all_data(true);
- TestCryptoStream* crypto_stream = session_.GetCryptoStream();
- EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked());
- EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
- EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
- QuicHeadersStream* headers_stream =
- QuicSpdySessionPeer::GetHeadersStream(&session_);
- EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked());
- EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
- EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
- QuicStreamId stream_id = 5;
- // Write until the header stream is flow control blocked.
- EXPECT_CALL(*connection_, SendBlocked(kHeadersStreamId));
- SpdyHeaderBlock headers;
- while (!headers_stream->flow_controller()->IsBlocked() && stream_id < 2000) {
- EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
- EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
- headers["header"] = base::Uint64ToString(base::RandUint64()) +
- base::Uint64ToString(base::RandUint64()) +
- base::Uint64ToString(base::RandUint64());
- headers_stream->WriteHeaders(stream_id, headers.Clone(), true, 0, nullptr);
- stream_id += 2;
- }
- // Write once more to ensure that the headers stream has buffered data. The
- // random headers may have exactly filled the flow control window.
- headers_stream->WriteHeaders(stream_id, std::move(headers), true, 0, nullptr);
- EXPECT_TRUE(headers_stream->HasBufferedData());
-
- EXPECT_TRUE(headers_stream->flow_controller()->IsBlocked());
- EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked());
- EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
- EXPECT_TRUE(session_.IsStreamFlowControlBlocked());
- EXPECT_FALSE(session_.HasDataToWrite());
-
- // Now complete the crypto handshake, resulting in an increased flow control
- // send window.
- CryptoHandshakeMessage msg;
- session_.GetCryptoStream()->OnHandshakeMessage(msg);
-
- // Stream is now unblocked and will no longer have buffered data.
- EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked());
- EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
- EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
- EXPECT_FALSE(headers_stream->HasBufferedData());
-}
-#endif // !defined(OS_IOS)
-
-TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstOutOfOrder) {
- // Test that when we receive an out of order stream RST we correctly adjust
- // our connection level flow control receive window.
- // On close, the stream should mark as consumed all bytes between the highest
- // byte consumed so far and the final byte offset from the RST frame.
- TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority);
-
- const QuicStreamOffset kByteOffset =
- 1 + kInitialSessionFlowControlWindowForTest / 2;
-
- // Expect no stream WINDOW_UPDATE frames, as stream read side closed.
- EXPECT_CALL(*connection_, SendWindowUpdate(stream->id(), _)).Times(0);
- // We do expect a connection level WINDOW_UPDATE when the stream is reset.
- EXPECT_CALL(*connection_,
- SendWindowUpdate(
- 0, kInitialSessionFlowControlWindowForTest + kByteOffset));
-
- EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _));
- QuicRstStreamFrame rst_frame(stream->id(), QUIC_STREAM_CANCELLED,
- kByteOffset);
- session_.OnRstStream(rst_frame);
- session_.PostProcessAfterData();
- EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed());
-}
-
-TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingFinAndLocalReset) {
- // Test the situation where we receive a FIN on a stream, and before we fully
- // consume all the data from the sequencer buffer we locally RST the stream.
- // The bytes between highest consumed byte, and the final byte offset that we
- // determined when the FIN arrived, should be marked as consumed at the
- // connection level flow controller when the stream is reset.
- TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority);
-
- const QuicStreamOffset kByteOffset =
- kInitialSessionFlowControlWindowForTest / 2 - 1;
- QuicStreamFrame frame(stream->id(), true, kByteOffset, ".");
- session_.OnStreamFrame(frame);
- session_.PostProcessAfterData();
- EXPECT_TRUE(connection_->connected());
-
- EXPECT_EQ(0u, stream->flow_controller()->bytes_consumed());
- EXPECT_EQ(kByteOffset + frame.data_length,
- stream->flow_controller()->highest_received_byte_offset());
-
- // Reset stream locally.
- EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _));
- stream->Reset(QUIC_STREAM_CANCELLED);
- EXPECT_EQ(kByteOffset + frame.data_length,
- session_.flow_controller()->bytes_consumed());
-}
-
-TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingFinAfterRst) {
- // Test that when we RST the stream (and tear down stream state), and then
- // receive a FIN from the peer, we correctly adjust our connection level flow
- // control receive window.
-
- // Connection starts with some non-zero highest received byte offset,
- // due to other active streams.
- const uint64_t kInitialConnectionBytesConsumed = 567;
- const uint64_t kInitialConnectionHighestReceivedOffset = 1234;
- EXPECT_LT(kInitialConnectionBytesConsumed,
- kInitialConnectionHighestReceivedOffset);
- session_.flow_controller()->UpdateHighestReceivedOffset(
- kInitialConnectionHighestReceivedOffset);
- session_.flow_controller()->AddBytesConsumed(kInitialConnectionBytesConsumed);
-
- // Reset our stream: this results in the stream being closed locally.
- TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _));
- stream->Reset(QUIC_STREAM_CANCELLED);
-
- // Now receive a response from the peer with a FIN. We should handle this by
- // adjusting the connection level flow control receive window to take into
- // account the total number of bytes sent by the peer.
- const QuicStreamOffset kByteOffset = 5678;
- string body = "hello";
- QuicStreamFrame frame(stream->id(), true, kByteOffset, StringPiece(body));
- session_.OnStreamFrame(frame);
-
- QuicStreamOffset total_stream_bytes_sent_by_peer =
- kByteOffset + body.length();
- EXPECT_EQ(kInitialConnectionBytesConsumed + total_stream_bytes_sent_by_peer,
- session_.flow_controller()->bytes_consumed());
- EXPECT_EQ(
- kInitialConnectionHighestReceivedOffset + total_stream_bytes_sent_by_peer,
- session_.flow_controller()->highest_received_byte_offset());
-}
-
-TEST_P(QuicSessionTestServer, ConnectionFlowControlAccountingRstAfterRst) {
- // Test that when we RST the stream (and tear down stream state), and then
- // receive a RST from the peer, we correctly adjust our connection level flow
- // control receive window.
-
- // Connection starts with some non-zero highest received byte offset,
- // due to other active streams.
- const uint64_t kInitialConnectionBytesConsumed = 567;
- const uint64_t kInitialConnectionHighestReceivedOffset = 1234;
- EXPECT_LT(kInitialConnectionBytesConsumed,
- kInitialConnectionHighestReceivedOffset);
- session_.flow_controller()->UpdateHighestReceivedOffset(
- kInitialConnectionHighestReceivedOffset);
- session_.flow_controller()->AddBytesConsumed(kInitialConnectionBytesConsumed);
-
- // Reset our stream: this results in the stream being closed locally.
- TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _));
- stream->Reset(QUIC_STREAM_CANCELLED);
- EXPECT_TRUE(ReliableQuicStreamPeer::read_side_closed(stream));
-
- // Now receive a RST from the peer. We should handle this by adjusting the
- // connection level flow control receive window to take into account the total
- // number of bytes sent by the peer.
- const QuicStreamOffset kByteOffset = 5678;
- QuicRstStreamFrame rst_frame(stream->id(), QUIC_STREAM_CANCELLED,
- kByteOffset);
- session_.OnRstStream(rst_frame);
-
- EXPECT_EQ(kInitialConnectionBytesConsumed + kByteOffset,
- session_.flow_controller()->bytes_consumed());
- EXPECT_EQ(kInitialConnectionHighestReceivedOffset + kByteOffset,
- session_.flow_controller()->highest_received_byte_offset());
-}
-
-TEST_P(QuicSessionTestServer, InvalidStreamFlowControlWindowInHandshake) {
- // Test that receipt of an invalid (< default) stream flow control window from
- // the peer results in the connection being torn down.
- const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1;
- QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(session_.config(),
- kInvalidWindow);
-
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _));
- session_.OnConfigNegotiated();
-}
-
-TEST_P(QuicSessionTestServer, InvalidSessionFlowControlWindowInHandshake) {
- // Test that receipt of an invalid (< default) session flow control window
- // from the peer results in the connection being torn down.
- const uint32_t kInvalidWindow = kMinimumFlowControlSendWindow - 1;
- QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(session_.config(),
- kInvalidWindow);
-
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_FLOW_CONTROL_INVALID_WINDOW, _, _));
- session_.OnConfigNegotiated();
-}
-
-TEST_P(QuicSessionTestServer, FlowControlWithInvalidFinalOffset) {
- // Test that if we receive a stream RST with a highest byte offset that
- // violates flow control, that we close the connection.
- const uint64_t kLargeOffset = kInitialSessionFlowControlWindowForTest + 1;
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _))
- .Times(2);
-
- // Check that stream frame + FIN results in connection close.
- TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _));
- stream->Reset(QUIC_STREAM_CANCELLED);
- QuicStreamFrame frame(stream->id(), true, kLargeOffset, StringPiece());
- session_.OnStreamFrame(frame);
-
- // Check that RST results in connection close.
- QuicRstStreamFrame rst_frame(stream->id(), QUIC_STREAM_CANCELLED,
- kLargeOffset);
- session_.OnRstStream(rst_frame);
-}
-
-TEST_P(QuicSessionTestServer, WindowUpdateUnblocksHeadersStream) {
- // Test that a flow control blocked headers stream gets unblocked on recipt of
- // a WINDOW_UPDATE frame.
-
- // Set the headers stream to be flow control blocked.
- QuicHeadersStream* headers_stream =
- QuicSpdySessionPeer::GetHeadersStream(&session_);
- QuicFlowControllerPeer::SetSendWindowOffset(headers_stream->flow_controller(),
- 0);
- EXPECT_TRUE(headers_stream->flow_controller()->IsBlocked());
- EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
- EXPECT_TRUE(session_.IsStreamFlowControlBlocked());
-
- // Unblock the headers stream by supplying a WINDOW_UPDATE.
- QuicWindowUpdateFrame window_update_frame(headers_stream->id(),
- 2 * kMinimumFlowControlSendWindow);
- session_.OnWindowUpdateFrame(window_update_frame);
- EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked());
- EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
- EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
-}
-
-TEST_P(QuicSessionTestServer, TooManyUnfinishedStreamsCauseServerRejectStream) {
- // If a buggy/malicious peer creates too many streams that are not ended
- // with a FIN or RST then we send a connection close or an RST to
- // refuse streams.
- const QuicStreamId kMaxStreams = 5;
- QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams);
- const QuicStreamId kFirstStreamId = kClientDataStreamId1;
- const QuicStreamId kFinalStreamId = kClientDataStreamId1 + 2 * kMaxStreams;
-
- // Create kMaxStreams data streams, and close them all without receiving a
- // FIN or a RST_STREAM from the client.
- for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += 2) {
- QuicStreamFrame data1(i, false, 0, StringPiece("HT"));
- session_.OnStreamFrame(data1);
- // EXPECT_EQ(1u, session_.GetNumOpenStreams());
- EXPECT_CALL(*connection_, SendRstStream(i, _, _));
- session_.CloseStream(i);
- }
-
- if (GetParam() <= QUIC_VERSION_27) {
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_TOO_MANY_OPEN_STREAMS, _, _));
- EXPECT_CALL(*connection_, SendRstStream(kFinalStreamId, _, _)).Times(0);
- } else {
- EXPECT_CALL(*connection_,
- SendRstStream(kFinalStreamId, QUIC_REFUSED_STREAM, _))
- .Times(1);
- }
- // Create one more data streams to exceed limit of open stream.
- QuicStreamFrame data1(kFinalStreamId, false, 0, StringPiece("HT"));
- session_.OnStreamFrame(data1);
-
- // Called after any new data is received by the session, and triggers the
- // call to close the connection.
- session_.PostProcessAfterData();
-}
-
-TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) {
- // Verify that a draining stream (which has received a FIN but not consumed
- // it) does not count against the open quota (because it is closed from the
- // protocol point of view).
- if (GetParam() <= QUIC_VERSION_27) {
- EXPECT_CALL(*connection_, CloseConnection(QUIC_TOO_MANY_OPEN_STREAMS, _, _))
- .Times(0);
- } else {
- EXPECT_CALL(*connection_, SendRstStream(_, QUIC_REFUSED_STREAM, _))
- .Times(0);
- }
- const QuicStreamId kMaxStreams = 5;
- QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams);
-
- // Create kMaxStreams + 1 data streams, and mark them draining.
- const QuicStreamId kFirstStreamId = kClientDataStreamId1;
- const QuicStreamId kFinalStreamId =
- kClientDataStreamId1 + 2 * kMaxStreams + 1;
- for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += 2) {
- QuicStreamFrame data1(i, true, 0, StringPiece("HT"));
- session_.OnStreamFrame(data1);
- EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams());
- session_.StreamDraining(i);
- EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
- }
-
- // Called after any new data is received by the session, and triggers the call
- // to close the connection.
- session_.PostProcessAfterData();
-}
-
-TEST_P(QuicSessionTestServer, TestMaxIncomingAndOutgoingStreamsAllowed) {
- // Tests that on server side, the value of max_open_incoming/outgoing streams
- // are setup correctly during negotiation.
- // The value for outgoing stream is limited to negotiated value and for
- // incoming stream it is set to be larger than that.
- session_.OnConfigNegotiated();
- // The max number of open outgoing streams is less than that of incoming
- // streams, and it should be same as negotiated value.
- EXPECT_LT(session_.max_open_outgoing_streams(),
- session_.max_open_incoming_streams());
- EXPECT_EQ(session_.max_open_outgoing_streams(),
- kDefaultMaxStreamsPerConnection);
- EXPECT_GT(session_.max_open_incoming_streams(),
- kDefaultMaxStreamsPerConnection);
-}
-
-class QuicSessionTestClient : public QuicSessionTestBase {
- protected:
- QuicSessionTestClient() : QuicSessionTestBase(Perspective::IS_CLIENT) {}
-};
-
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicSessionTestClient,
- ::testing::ValuesIn(QuicSupportedVersions()));
-
-TEST_P(QuicSessionTestClient, AvailableStreamsClient) {
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(6) != nullptr);
- // Both 2 and 4 should be available.
- EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 2));
- EXPECT_TRUE(QuicSessionPeer::IsStreamAvailable(&session_, 4));
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(2) != nullptr);
- ASSERT_TRUE(session_.GetOrCreateDynamicStream(4) != nullptr);
- // And 5 should be not available.
- EXPECT_FALSE(QuicSessionPeer::IsStreamAvailable(&session_, 5));
-}
-
-TEST_P(QuicSessionTestClient, RecordFinAfterReadSideClosed) {
- // Verify that an incoming FIN is recorded in a stream object even if the read
- // side has been closed. This prevents an entry from being made in
- // locally_closed_streams_highest_offset_ (which will never be deleted).
- TestStream* stream = session_.CreateOutgoingDynamicStream(kDefaultPriority);
- QuicStreamId stream_id = stream->id();
-
- // Close the read side manually.
- ReliableQuicStreamPeer::CloseReadSide(stream);
-
- // Receive a stream data frame with FIN.
- QuicStreamFrame frame(stream_id, true, 0, StringPiece());
- session_.OnStreamFrame(frame);
- EXPECT_TRUE(stream->fin_received());
-
- // Reset stream locally.
- EXPECT_CALL(*connection_, SendRstStream(stream->id(), _, _));
- stream->Reset(QUIC_STREAM_CANCELLED);
- EXPECT_TRUE(ReliableQuicStreamPeer::read_side_closed(stream));
-
- // Allow the session to delete the stream object.
- session_.PostProcessAfterData();
- EXPECT_TRUE(connection_->connected());
- EXPECT_TRUE(QuicSessionPeer::IsStreamClosed(&session_, stream_id));
- EXPECT_FALSE(QuicSessionPeer::IsStreamCreated(&session_, stream_id));
-
- // The stream is not waiting for the arrival of the peer's final offset as it
- // was received with the FIN earlier.
- EXPECT_EQ(
- 0u,
- QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(&session_).size());
-}
-
-TEST_P(QuicSessionTestClient, TestMaxIncomingAndOutgoingStreamsAllowed) {
- // Tests that on client side, the value of max_open_incoming/outgoing streams
- // are setup correctly during negotiation.
- // When flag is true, the value for outgoing stream is limited to negotiated
- // value and for incoming stream it is set to be larger than that.
- session_.OnConfigNegotiated();
- EXPECT_LT(session_.max_open_outgoing_streams(),
- session_.max_open_incoming_streams());
- EXPECT_EQ(session_.max_open_outgoing_streams(),
- kDefaultMaxStreamsPerConnection);
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_simple_buffer_allocator.cc b/chromium/net/quic/quic_simple_buffer_allocator.cc
deleted file mode 100644
index efee2ccc98b..00000000000
--- a/chromium/net/quic/quic_simple_buffer_allocator.cc
+++ /dev/null
@@ -1,21 +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/quic_simple_buffer_allocator.h"
-
-namespace net {
-
-char* SimpleBufferAllocator::New(size_t size) {
- return new char[size];
-}
-
-char* SimpleBufferAllocator::New(size_t size, bool /* flag_enable */) {
- return New(size);
-}
-
-void SimpleBufferAllocator::Delete(char* buffer) {
- delete[] buffer;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_simple_buffer_allocator.h b/chromium/net/quic/quic_simple_buffer_allocator.h
deleted file mode 100644
index dfb0fffa2e8..00000000000
--- a/chromium/net/quic/quic_simple_buffer_allocator.h
+++ /dev/null
@@ -1,21 +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.
-
-#ifndef NET_QUIC_SIMPLE_BUFFER_ALLOCATOR_H_
-#define NET_QUIC_SIMPLE_BUFFER_ALLOCATOR_H_
-
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-class NET_EXPORT_PRIVATE SimpleBufferAllocator : public QuicBufferAllocator {
- public:
- char* New(size_t size) override;
- char* New(size_t size, bool flag_enable) override;
- void Delete(char* buffer) override;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_SIMPLE_BUFFER_ALLOCATOR_H_
diff --git a/chromium/net/quic/quic_simple_buffer_allocator_test.cc b/chromium/net/quic/quic_simple_buffer_allocator_test.cc
deleted file mode 100644
index 3129b9608c8..00000000000
--- a/chromium/net/quic/quic_simple_buffer_allocator_test.cc
+++ /dev/null
@@ -1,35 +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/quic_simple_buffer_allocator.h"
-
-#include "net/quic/quic_protocol.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::Eq;
-
-namespace net {
-namespace {
-
-TEST(SimpleBufferAllocatorTest, NewDelete) {
- SimpleBufferAllocator alloc;
- char* buf = alloc.New(4);
- EXPECT_NE(nullptr, buf);
- alloc.Delete(buf);
-}
-
-TEST(SimpleBufferAllocatorTest, DeleteNull) {
- SimpleBufferAllocator alloc;
- alloc.Delete(nullptr);
-}
-
-TEST(SimpleBufferAllocatorTest, StoreInUniqueStreamBuffer) {
- SimpleBufferAllocator alloc;
- UniqueStreamBuffer buf = NewStreamBuffer(&alloc, 4);
- buf.reset();
-}
-
-} // namespace
-} // namespace net
diff --git a/chromium/net/quic/quic_socket_address_coder.cc b/chromium/net/quic/quic_socket_address_coder.cc
deleted file mode 100644
index f0d213edef0..00000000000
--- a/chromium/net/quic/quic_socket_address_coder.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_socket_address_coder.h"
-
-#include "net/base/ip_address.h"
-#include "net/base/sys_addrinfo.h"
-
-using std::string;
-
-namespace net {
-
-namespace {
-
-// For convenience, the values of these constants match the values of AF_INET
-// and AF_INET6 on Linux.
-const uint16_t kIPv4 = 2;
-const uint16_t kIPv6 = 10;
-
-} // namespace
-
-QuicSocketAddressCoder::QuicSocketAddressCoder() {}
-
-QuicSocketAddressCoder::QuicSocketAddressCoder(const IPEndPoint& address)
- : address_(address) {}
-
-QuicSocketAddressCoder::~QuicSocketAddressCoder() {}
-
-string QuicSocketAddressCoder::Encode() const {
- string serialized;
- uint16_t address_family;
- switch (address_.GetSockAddrFamily()) {
- case AF_INET:
- address_family = kIPv4;
- break;
- case AF_INET6:
- address_family = kIPv6;
- break;
- default:
- return serialized;
- }
- serialized.append(reinterpret_cast<const char*>(&address_family),
- sizeof(address_family));
- serialized.append(IPAddressToPackedString(address_.address()));
- uint16_t port = address_.port();
- serialized.append(reinterpret_cast<const char*>(&port), sizeof(port));
- return serialized;
-}
-
-bool QuicSocketAddressCoder::Decode(const char* data, size_t length) {
- uint16_t address_family;
- if (length < sizeof(address_family)) {
- return false;
- }
- memcpy(&address_family, data, sizeof(address_family));
- data += sizeof(address_family);
- length -= sizeof(address_family);
-
- size_t ip_length;
- switch (address_family) {
- case kIPv4:
- ip_length = IPAddress::kIPv4AddressSize;
- break;
- case kIPv6:
- ip_length = IPAddress::kIPv6AddressSize;
- break;
- default:
- return false;
- }
- if (length < ip_length) {
- return false;
- }
- std::vector<uint8_t> ip(ip_length);
- memcpy(&ip[0], data, ip_length);
- data += ip_length;
- length -= ip_length;
-
- uint16_t port;
- if (length != sizeof(port)) {
- return false;
- }
- memcpy(&port, data, length);
-
- address_ = IPEndPoint(IPAddress(ip), port);
- return true;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_socket_address_coder_test.cc b/chromium/net/quic/quic_socket_address_coder_test.cc
deleted file mode 100644
index babc00090cf..00000000000
--- a/chromium/net/quic/quic_socket_address_coder_test.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_socket_address_coder.h"
-
-#include "net/base/sys_addrinfo.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::string;
-
-namespace net {
-namespace test {
-
-TEST(QuicSocketAddressCoderTest, EncodeIPv4) {
- IPAddress ip;
- ASSERT_TRUE(ip.AssignFromIPLiteral("4.31.198.44"));
- QuicSocketAddressCoder coder(IPEndPoint(ip, 0x1234));
- string serialized = coder.Encode();
- string expected("\x02\x00\x04\x1f\xc6\x2c\x34\x12", 8);
- EXPECT_EQ(expected, serialized);
-}
-
-TEST(QuicSocketAddressCoderTest, EncodeIPv6) {
- IPAddress ip;
- ASSERT_TRUE(ip.AssignFromIPLiteral("2001:700:300:1800::f"));
- QuicSocketAddressCoder coder(IPEndPoint(ip, 0x5678));
- string serialized = coder.Encode();
- string expected(
- "\x0a\x00"
- "\x20\x01\x07\x00\x03\x00\x18\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x0f"
- "\x78\x56",
- 20);
- EXPECT_EQ(expected, serialized);
-}
-
-TEST(QuicSocketAddressCoderTest, DecodeIPv4) {
- string serialized("\x02\x00\x04\x1f\xc6\x2c\x34\x12", 8);
- QuicSocketAddressCoder coder;
- ASSERT_TRUE(coder.Decode(serialized.data(), serialized.length()));
- EXPECT_EQ(AF_INET, ConvertAddressFamily(GetAddressFamily(coder.ip())));
- string expected_addr("\x04\x1f\xc6\x2c", 4);
- EXPECT_EQ(expected_addr, IPAddressToPackedString(coder.ip()));
- EXPECT_EQ(0x1234, coder.port());
-}
-
-TEST(QuicSocketAddressCoderTest, DecodeIPv6) {
- string serialized(
- "\x0a\x00"
- "\x20\x01\x07\x00\x03\x00\x18\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x0f"
- "\x78\x56",
- 20);
- QuicSocketAddressCoder coder;
- ASSERT_TRUE(coder.Decode(serialized.data(), serialized.length()));
- EXPECT_EQ(AF_INET6, ConvertAddressFamily(GetAddressFamily(coder.ip())));
- string expected_addr(
- "\x20\x01\x07\x00\x03\x00\x18\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x0f",
- 16);
- EXPECT_EQ(expected_addr, IPAddressToPackedString(coder.ip()));
- EXPECT_EQ(0x5678, coder.port());
-}
-
-TEST(QuicSocketAddressCoderTest, DecodeBad) {
- string serialized(
- "\x0a\x00"
- "\x20\x01\x07\x00\x03\x00\x18\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x0f"
- "\x78\x56",
- 20);
- QuicSocketAddressCoder coder;
- EXPECT_TRUE(coder.Decode(serialized.data(), serialized.length()));
- // Append junk.
- serialized.push_back('\0');
- EXPECT_FALSE(coder.Decode(serialized.data(), serialized.length()));
- // Undo.
- serialized.resize(20);
- EXPECT_TRUE(coder.Decode(serialized.data(), serialized.length()));
-
- // Set an unknown address family.
- serialized[0] = '\x03';
- EXPECT_FALSE(coder.Decode(serialized.data(), serialized.length()));
- // Undo.
- serialized[0] = '\x0a';
- EXPECT_TRUE(coder.Decode(serialized.data(), serialized.length()));
-
- // Truncate.
- size_t len = serialized.length();
- for (size_t i = 0; i < len; i++) {
- ASSERT_FALSE(serialized.empty());
- serialized.erase(serialized.length() - 1);
- EXPECT_FALSE(coder.Decode(serialized.data(), serialized.length()));
- }
- EXPECT_TRUE(serialized.empty());
-}
-
-TEST(QuicSocketAddressCoderTest, EncodeAndDecode) {
- struct {
- const char* ip_literal;
- uint16_t port;
- } test_case[] = {
- {"93.184.216.119", 0x1234},
- {"199.204.44.194", 80},
- {"149.20.4.69", 443},
- {"127.0.0.1", 8080},
- {"2001:700:300:1800::", 0x5678},
- {"::1", 65534},
- };
-
- for (size_t i = 0; i < arraysize(test_case); i++) {
- IPAddress ip;
- ASSERT_TRUE(ip.AssignFromIPLiteral(test_case[i].ip_literal));
- QuicSocketAddressCoder encoder(IPEndPoint(ip, test_case[i].port));
- string serialized = encoder.Encode();
-
- QuicSocketAddressCoder decoder;
- ASSERT_TRUE(decoder.Decode(serialized.data(), serialized.length()));
- EXPECT_EQ(encoder.ip(), decoder.ip());
- EXPECT_EQ(encoder.port(), decoder.port());
- }
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_spdy_session.cc b/chromium/net/quic/quic_spdy_session.cc
deleted file mode 100644
index ef0a422031c..00000000000
--- a/chromium/net/quic/quic_spdy_session.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-// 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.
-
-#include "net/quic/quic_spdy_session.h"
-
-#include <utility>
-
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_headers_stream.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-
-QuicSpdySession::QuicSpdySession(QuicConnection* connection,
- const QuicConfig& config)
- : QuicSession(connection, config) {}
-
-QuicSpdySession::~QuicSpdySession() {
- // Set the streams' session pointers in closed and dynamic stream lists
- // to null to avoid subsequent use of this session.
- for (auto* stream : *closed_streams()) {
- static_cast<QuicSpdyStream*>(stream)->ClearSession();
- }
- for (auto const& kv : dynamic_streams()) {
- static_cast<QuicSpdyStream*>(kv.second)->ClearSession();
- }
-}
-
-void QuicSpdySession::Initialize() {
- QuicSession::Initialize();
-
- if (perspective() == Perspective::IS_SERVER) {
- set_largest_peer_created_stream_id(kHeadersStreamId);
- } else {
- QuicStreamId headers_stream_id = GetNextOutgoingStreamId();
- DCHECK_EQ(headers_stream_id, kHeadersStreamId);
- }
-
- headers_stream_.reset(new QuicHeadersStream(this));
- DCHECK_EQ(kHeadersStreamId, headers_stream_->id());
- static_streams()[kHeadersStreamId] = headers_stream_.get();
-}
-
-void QuicSpdySession::OnStreamHeaders(QuicStreamId stream_id,
- StringPiece headers_data) {
- QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
- if (!stream) {
- // It's quite possible to receive headers after a stream has been reset.
- return;
- }
- stream->OnStreamHeaders(headers_data);
-}
-
-void QuicSpdySession::OnStreamHeadersPriority(QuicStreamId stream_id,
- SpdyPriority priority) {
- QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
- if (!stream) {
- // It's quite possible to receive headers after a stream has been reset.
- return;
- }
- stream->OnStreamHeadersPriority(priority);
-}
-
-void QuicSpdySession::OnStreamHeadersComplete(QuicStreamId stream_id,
- bool fin,
- size_t frame_len) {
- QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
- if (!stream) {
- // It's quite possible to receive headers after a stream has been reset.
- return;
- }
- stream->OnStreamHeadersComplete(fin, frame_len);
-}
-
-void QuicSpdySession::OnStreamHeaderList(QuicStreamId stream_id,
- bool fin,
- size_t frame_len,
- const QuicHeaderList& header_list) {
- QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
- if (!stream) {
- // It's quite possible to receive headers after a stream has been reset.
- return;
- }
- stream->OnStreamHeaderList(fin, frame_len, header_list);
-}
-
-size_t QuicSpdySession::WriteHeaders(
- QuicStreamId id,
- SpdyHeaderBlock headers,
- bool fin,
- SpdyPriority priority,
- QuicAckListenerInterface* ack_notifier_delegate) {
- return headers_stream_->WriteHeaders(id, std::move(headers), fin, priority,
- ack_notifier_delegate);
-}
-
-void QuicSpdySession::OnHeadersHeadOfLineBlocking(QuicTime::Delta delta) {
- // Implemented in Chromium for stats tracking.
-}
-
-void QuicSpdySession::RegisterStreamPriority(QuicStreamId id,
- SpdyPriority priority) {
- write_blocked_streams()->RegisterStream(id, priority);
-}
-
-void QuicSpdySession::UnregisterStreamPriority(QuicStreamId id) {
- write_blocked_streams()->UnregisterStream(id);
-}
-
-void QuicSpdySession::UpdateStreamPriority(QuicStreamId id,
- SpdyPriority new_priority) {
- write_blocked_streams()->UpdateStreamPriority(id, new_priority);
-}
-
-QuicSpdyStream* QuicSpdySession::GetSpdyDataStream(
- const QuicStreamId stream_id) {
- return static_cast<QuicSpdyStream*>(GetOrCreateDynamicStream(stream_id));
-}
-
-void QuicSpdySession::OnPromiseHeaders(QuicStreamId stream_id,
- StringPiece headers_data) {
- string error = "OnPromiseHeaders should be overriden in client code.";
- QUIC_BUG << error;
- connection()->CloseConnection(QUIC_INTERNAL_ERROR, error,
- ConnectionCloseBehavior::SILENT_CLOSE);
-}
-
-void QuicSpdySession::OnPromiseHeadersComplete(QuicStreamId stream_id,
- QuicStreamId promised_stream_id,
- size_t frame_len) {
- string error = "OnPromiseHeadersComplete should be overriden in client code.";
- QUIC_BUG << error;
- connection()->CloseConnection(QUIC_INTERNAL_ERROR, error,
- ConnectionCloseBehavior::SILENT_CLOSE);
-}
-
-void QuicSpdySession::OnPromiseHeaderList(QuicStreamId stream_id,
- QuicStreamId promised_stream_id,
- size_t frame_len,
- const QuicHeaderList& header_list) {
- string error = "OnPromiseHeaderList should be overriden in client code.";
- QUIC_BUG << error;
- connection()->CloseConnection(QUIC_INTERNAL_ERROR, error,
- ConnectionCloseBehavior::SILENT_CLOSE);
-}
-
-void QuicSpdySession::OnConfigNegotiated() {
- QuicSession::OnConfigNegotiated();
- if (FLAGS_quic_disable_hpack_dynamic_table &&
- config()->HasClientSentConnectionOption(kDHDT, perspective())) {
- headers_stream_->DisableHpackDynamicTable();
- }
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_spdy_session.h b/chromium/net/quic/quic_spdy_session.h
deleted file mode 100644
index f08ad4c7492..00000000000
--- a/chromium/net/quic/quic_spdy_session.h
+++ /dev/null
@@ -1,129 +0,0 @@
-// 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.
-
-#ifndef NET_QUIC_QUIC_SPDY_SESSION_H_
-#define NET_QUIC_QUIC_SPDY_SESSION_H_
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "net/quic/quic_header_list.h"
-#include "net/quic/quic_headers_stream.h"
-#include "net/quic/quic_session.h"
-#include "net/quic/quic_spdy_stream.h"
-
-namespace net {
-
-namespace test {
-class QuicSpdySessionPeer;
-} // namespace test
-
-// A QUIC session with a headers stream.
-class NET_EXPORT_PRIVATE QuicSpdySession : public QuicSession {
- public:
- QuicSpdySession(QuicConnection* connection, const QuicConfig& config);
-
- ~QuicSpdySession() override;
-
- void Initialize() override;
-
- // Called by |headers_stream_| when headers have been received for a stream.
- virtual void OnStreamHeaders(QuicStreamId stream_id,
- base::StringPiece headers_data);
- // Called by |headers_stream_| when headers with a priority have been
- // received for this stream. This method will only be called for server
- // streams.
- virtual void OnStreamHeadersPriority(QuicStreamId stream_id,
- SpdyPriority priority);
- // Called by |headers_stream_| when headers have been completely received
- // for a stream. |fin| will be true if the fin flag was set in the headers
- // frame.
- virtual void OnStreamHeadersComplete(QuicStreamId stream_id,
- bool fin,
- size_t frame_len);
-
- // Called by |headers_stream_| when headers have been completely received
- // for a stream. |fin| will be true if the fin flag was set in the headers
- // frame.
- virtual void OnStreamHeaderList(QuicStreamId stream_id,
- bool fin,
- size_t frame_len,
- const QuicHeaderList& header_list);
-
- // Called by |headers_stream_| when push promise headers have been
- // received for a stream.
- virtual void OnPromiseHeaders(QuicStreamId stream_id,
- base::StringPiece headers_data);
-
- // Called by |headers_stream_| when push promise headers have been
- // completely received. |fin| will be true if the fin flag was set
- // in the headers.
- virtual void OnPromiseHeadersComplete(QuicStreamId stream_id,
- QuicStreamId promised_stream_id,
- size_t frame_len);
-
- // Called by |headers_stream_| when push promise headers have been
- // completely received. |fin| will be true if the fin flag was set
- // in the headers.
- virtual void OnPromiseHeaderList(QuicStreamId stream_id,
- QuicStreamId promised_stream_id,
- size_t frame_len,
- const QuicHeaderList& header_list);
-
- // Writes |headers| for the stream |id| to the dedicated headers stream.
- // If |fin| is true, then no more data will be sent for the stream |id|.
- // If provided, |ack_notifier_delegate| will be registered to be notified when
- // we have seen ACKs for all packets resulting from this call.
- virtual size_t WriteHeaders(QuicStreamId id,
- SpdyHeaderBlock headers,
- bool fin,
- SpdyPriority priority,
- QuicAckListenerInterface* ack_notifier_delegate);
-
- QuicHeadersStream* headers_stream() { return headers_stream_.get(); }
-
- // Called when Head of Line Blocking happens in the headers stream.
- // |delta| indicates how long that piece of data has been blocked.
- 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);
- // Called by the stream on deletion to clear priority crom the write blocked
- // list.
- 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);
-
- void OnConfigNegotiated() override;
-
- protected:
- // Override CreateIncomingDynamicStream() and CreateOutgoingDynamicStream()
- // with QuicSpdyStream return type to make sure that all data streams are
- // QuicSpdyStreams.
- QuicSpdyStream* CreateIncomingDynamicStream(QuicStreamId id) override = 0;
- QuicSpdyStream* CreateOutgoingDynamicStream(SpdyPriority priority) override =
- 0;
-
- QuicSpdyStream* GetSpdyDataStream(const QuicStreamId stream_id);
-
- // If an incoming stream can be created, return true.
- virtual bool ShouldCreateIncomingDynamicStream(QuicStreamId id) = 0;
-
- // If an outgoing stream can be created, return true.
- virtual bool ShouldCreateOutgoingDynamicStream() = 0;
-
- private:
- friend class test::QuicSpdySessionPeer;
-
- std::unique_ptr<QuicHeadersStream> headers_stream_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicSpdySession);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_SPDY_SESSION_H_
diff --git a/chromium/net/quic/quic_spdy_stream.cc b/chromium/net/quic/quic_spdy_stream.cc
deleted file mode 100644
index 7b1b3ee85e1..00000000000
--- a/chromium/net/quic/quic_spdy_stream.cc
+++ /dev/null
@@ -1,405 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_spdy_stream.h"
-
-#include <utility>
-
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_spdy_session.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/quic_write_blocked_list.h"
-#include "net/quic/spdy_utils.h"
-
-using base::IntToString;
-using base::StringPiece;
-using std::min;
-using std::string;
-
-namespace net {
-
-#define ENDPOINT \
- (session()->perspective() == Perspective::IS_SERVER ? "Server: " : "Client:" \
- " ")
-
-QuicSpdyStream::QuicSpdyStream(QuicStreamId id, QuicSpdySession* spdy_session)
- : ReliableQuicStream(id, spdy_session),
- spdy_session_(spdy_session),
- visitor_(nullptr),
- headers_decompressed_(false),
- priority_(kDefaultPriority),
- trailers_decompressed_(false),
- trailers_delivered_(false) {
- DCHECK_NE(kCryptoStreamId, id);
- // Don't receive any callbacks from the sequencer until headers
- // are complete.
- sequencer()->SetBlockedUntilFlush();
- spdy_session_->RegisterStreamPriority(id, priority_);
-}
-
-QuicSpdyStream::~QuicSpdyStream() {
- if (spdy_session_ != nullptr) {
- spdy_session_->UnregisterStreamPriority(id());
- }
-}
-
-void QuicSpdyStream::CloseWriteSide() {
- if (version() > QUIC_VERSION_28 && !fin_received() && !rst_received() &&
- sequencer()->ignore_read_data() && !rst_sent()) {
- DCHECK(fin_sent());
- // Tell the peer to stop sending further data.
- DVLOG(1) << ENDPOINT << "Send QUIC_STREAM_NO_ERROR on stream " << id();
- Reset(QUIC_STREAM_NO_ERROR);
- }
-
- ReliableQuicStream::CloseWriteSide();
-}
-
-void QuicSpdyStream::StopReading() {
- if (version() > QUIC_VERSION_28 && !fin_received() && !rst_received() &&
- write_side_closed() && !rst_sent()) {
- DCHECK(fin_sent());
- // Tell the peer to stop sending further data.
- DVLOG(1) << ENDPOINT << "Send QUIC_STREAM_NO_ERROR on stream " << id();
- Reset(QUIC_STREAM_NO_ERROR);
- }
- ReliableQuicStream::StopReading();
-}
-
-size_t QuicSpdyStream::WriteHeaders(
- SpdyHeaderBlock header_block,
- bool fin,
- QuicAckListenerInterface* ack_notifier_delegate) {
- size_t bytes_written = spdy_session_->WriteHeaders(
- id(), std::move(header_block), fin, priority_, ack_notifier_delegate);
- if (fin) {
- // TODO(rch): Add test to ensure fin_sent_ is set whenever a fin is sent.
- set_fin_sent(true);
- CloseWriteSide();
- }
- return bytes_written;
-}
-
-void QuicSpdyStream::WriteOrBufferBody(
- const string& data,
- bool fin,
- QuicAckListenerInterface* ack_notifier_delegate) {
- WriteOrBufferData(data, fin, ack_notifier_delegate);
-}
-
-size_t QuicSpdyStream::WriteTrailers(
- SpdyHeaderBlock trailer_block,
- QuicAckListenerInterface* ack_notifier_delegate) {
- if (fin_sent()) {
- QUIC_BUG << "Trailers cannot be sent after a FIN.";
- return 0;
- }
-
- // The header block must contain the final offset for this stream, as the
- // trailers may be processed out of order at the peer.
- DVLOG(1) << "Inserting trailer: (" << kFinalOffsetHeaderKey << ", "
- << stream_bytes_written() + queued_data_bytes() << ")";
- trailer_block.insert(std::make_pair(
- kFinalOffsetHeaderKey,
- IntToString(stream_bytes_written() + queued_data_bytes())));
-
- // Write the trailing headers with a FIN, and close stream for writing:
- // trailers are the last thing to be sent on a stream.
- const bool kFin = true;
- size_t bytes_written = spdy_session_->WriteHeaders(
- id(), std::move(trailer_block), kFin, priority_, ack_notifier_delegate);
- set_fin_sent(kFin);
-
- // Trailers are the last thing to be sent on a stream, but if there is still
- // queued data then CloseWriteSide() will cause it never to be sent.
- if (queued_data_bytes() == 0) {
- CloseWriteSide();
- }
-
- return bytes_written;
-}
-
-size_t QuicSpdyStream::Readv(const struct iovec* iov, size_t iov_len) {
- DCHECK(FinishedReadingHeaders());
- return sequencer()->Readv(iov, iov_len);
-}
-
-int QuicSpdyStream::GetReadableRegions(iovec* iov, size_t iov_len) const {
- DCHECK(FinishedReadingHeaders());
- return sequencer()->GetReadableRegions(iov, iov_len);
-}
-
-void QuicSpdyStream::MarkConsumed(size_t num_bytes) {
- DCHECK(FinishedReadingHeaders());
- return sequencer()->MarkConsumed(num_bytes);
-}
-
-bool QuicSpdyStream::IsDoneReading() const {
- bool done_reading_headers = FinishedReadingHeaders();
- bool done_reading_body = sequencer()->IsClosed();
- bool done_reading_trailers = FinishedReadingTrailers();
- return done_reading_headers && done_reading_body && done_reading_trailers;
-}
-
-bool QuicSpdyStream::HasBytesToRead() const {
- bool headers_to_read = !decompressed_headers_.empty();
- bool body_to_read = sequencer()->HasBytesToRead();
- bool trailers_to_read = !decompressed_trailers_.empty();
- return headers_to_read || body_to_read || trailers_to_read;
-}
-
-void QuicSpdyStream::MarkHeadersConsumed(size_t bytes_consumed) {
- decompressed_headers_.erase(0, bytes_consumed);
- if (FinishedReadingHeaders()) {
- sequencer()->SetUnblocked();
- }
-}
-
-void QuicSpdyStream::MarkTrailersConsumed(size_t bytes_consumed) {
- decompressed_trailers_.erase(0, bytes_consumed);
-}
-
-void QuicSpdyStream::MarkTrailersDelivered() {
- trailers_delivered_ = true;
-}
-
-void QuicSpdyStream::ConsumeHeaderList() {
- header_list_.Clear();
- if (FinishedReadingHeaders()) {
- sequencer()->SetUnblocked();
- }
-}
-
-void QuicSpdyStream::SetPriority(SpdyPriority priority) {
- DCHECK_EQ(0u, stream_bytes_written());
- spdy_session_->UpdateStreamPriority(id(), priority);
- priority_ = priority;
-}
-
-void QuicSpdyStream::OnStreamHeaders(StringPiece headers_data) {
- if (!headers_decompressed_) {
- headers_data.AppendToString(&decompressed_headers_);
- } else {
- DCHECK(!trailers_decompressed_);
- headers_data.AppendToString(&decompressed_trailers_);
- }
-}
-
-void QuicSpdyStream::OnStreamHeadersPriority(SpdyPriority priority) {
- DCHECK_EQ(Perspective::IS_SERVER, session()->connection()->perspective());
- SetPriority(priority);
-}
-
-void QuicSpdyStream::OnStreamHeadersComplete(bool fin, size_t frame_len) {
- if (!headers_decompressed_) {
- OnInitialHeadersComplete(fin, frame_len);
- } else {
- OnTrailingHeadersComplete(fin, frame_len);
- }
-}
-
-void QuicSpdyStream::OnStreamHeaderList(bool fin,
- size_t frame_len,
- const QuicHeaderList& header_list) {
- if (!headers_decompressed_) {
- OnInitialHeadersComplete(fin, frame_len, header_list);
- } else {
- OnTrailingHeadersComplete(fin, frame_len, header_list);
- }
-}
-
-void QuicSpdyStream::OnInitialHeadersComplete(bool fin, size_t /*frame_len*/) {
- headers_decompressed_ = true;
- if (fin) {
- OnStreamFrame(QuicStreamFrame(id(), fin, 0, StringPiece()));
- }
- if (FinishedReadingHeaders()) {
- sequencer()->SetUnblocked();
- }
-}
-
-void QuicSpdyStream::OnInitialHeadersComplete(
- bool fin,
- size_t /*frame_len*/,
- const QuicHeaderList& header_list) {
- headers_decompressed_ = true;
- header_list_ = header_list;
- if (fin) {
- OnStreamFrame(QuicStreamFrame(id(), fin, 0, StringPiece()));
- }
- if (FinishedReadingHeaders()) {
- sequencer()->SetUnblocked();
- }
-}
-
-void QuicSpdyStream::OnPromiseHeaders(StringPiece headers_data) {
- headers_data.AppendToString(&decompressed_headers_);
-}
-
-void QuicSpdyStream::OnPromiseHeadersComplete(
- QuicStreamId /* promised_stream_id */,
- size_t /* frame_len */) {
- // To be overridden in QuicSpdyClientStream. Not supported on
- // server side.
- session()->connection()->CloseConnection(
- QUIC_INVALID_HEADERS_STREAM_DATA, "Promise headers received by server",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
-}
-
-void QuicSpdyStream::OnPromiseHeaderList(
- QuicStreamId /* promised_id */,
- size_t /* frame_len */,
- const QuicHeaderList& /*header_list */) {
- // To be overridden in QuicSpdyClientStream. Not supported on
- // server side.
- session()->connection()->CloseConnection(
- QUIC_INVALID_HEADERS_STREAM_DATA, "Promise headers received by server",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
-}
-
-void QuicSpdyStream::OnTrailingHeadersComplete(bool fin, size_t /*frame_len*/) {
- DCHECK(!trailers_decompressed_);
- if (fin_received()) {
- DLOG(ERROR) << "Received Trailers after FIN, on stream: " << id();
- session()->connection()->CloseConnection(
- QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers after fin",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
- if (!fin) {
- DLOG(ERROR) << "Trailers must have FIN set, on stream: " << id();
- session()->connection()->CloseConnection(
- QUIC_INVALID_HEADERS_STREAM_DATA, "Fin missing from trailers",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
-
- size_t final_byte_offset = 0;
- if (!SpdyUtils::ParseTrailers(decompressed_trailers().data(),
- decompressed_trailers().length(),
- &final_byte_offset, &received_trailers_)) {
- DLOG(ERROR) << "Trailers are malformed: " << id();
- session()->connection()->CloseConnection(
- QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers are malformed",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
-
- // The data on this stream ends at |final_byte_offset|.
- DVLOG(1) << "Stream ends at byte offset: " << final_byte_offset
- << " currently read: " << stream_bytes_read();
-
- OnStreamFrame(QuicStreamFrame(id(), fin, final_byte_offset, StringPiece()));
- trailers_decompressed_ = true;
-}
-
-void QuicSpdyStream::OnTrailingHeadersComplete(
- bool fin,
- size_t /*frame_len*/,
- const QuicHeaderList& header_list) {
- DCHECK(!trailers_decompressed_);
- if (fin_received()) {
- DLOG(ERROR) << "Received Trailers after FIN, on stream: " << id();
- session()->connection()->CloseConnection(
- QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers after fin",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
- if (!fin) {
- DLOG(ERROR) << "Trailers must have FIN set, on stream: " << id();
- session()->connection()->CloseConnection(
- QUIC_INVALID_HEADERS_STREAM_DATA, "Fin missing from trailers",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
-
- size_t final_byte_offset = 0;
- if (!SpdyUtils::CopyAndValidateTrailers(header_list, &final_byte_offset,
- &received_trailers_)) {
- DLOG(ERROR) << "Trailers are malformed: " << id();
- session()->connection()->CloseConnection(
- QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers are malformed",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- return;
- }
- OnStreamFrame(QuicStreamFrame(id(), fin, final_byte_offset, StringPiece()));
- trailers_decompressed_ = true;
-}
-
-void QuicSpdyStream::OnStreamReset(const QuicRstStreamFrame& frame) {
- if (frame.error_code != QUIC_STREAM_NO_ERROR ||
- version() <= QUIC_VERSION_28) {
- ReliableQuicStream::OnStreamReset(frame);
- return;
- }
- DVLOG(1) << "Received QUIC_STREAM_NO_ERROR, not discarding response";
- set_rst_received(true);
- MaybeIncreaseHighestReceivedOffset(frame.byte_offset);
- set_stream_error(frame.error_code);
- CloseWriteSide();
-}
-
-void QuicSpdyStream::OnClose() {
- ReliableQuicStream::OnClose();
-
- if (visitor_) {
- Visitor* visitor = visitor_;
- // Calling Visitor::OnClose() may result the destruction of the visitor,
- // so we need to ensure we don't call it again.
- visitor_ = nullptr;
- visitor->OnClose(this);
- }
-}
-
-bool QuicSpdyStream::FinishedReadingHeaders() const {
- return headers_decompressed_ && decompressed_headers_.empty() &&
- header_list_.empty();
-}
-
-bool QuicSpdyStream::ParseHeaderStatusCode(const SpdyHeaderBlock& header,
- int* status_code) const {
- SpdyHeaderBlock::const_iterator it = header.find(":status");
- if (it == header.end()) {
- return false;
- }
- const StringPiece status(it->second);
- if (status.size() != 3) {
- return false;
- }
- // First character must be an integer in range [1,5].
- if (status[0] < '1' || status[0] > '5') {
- return false;
- }
- // The remaining two characters must be integers.
- if (!isdigit(status[1]) || !isdigit(status[2])) {
- return false;
- }
- return StringToInt(status, status_code);
-}
-
-bool QuicSpdyStream::FinishedReadingTrailers() const {
- // If no further trailing headers are expected, and the decompressed trailers
- // (if any) have been consumed, then reading of trailers is finished.
- if (!fin_received()) {
- return false;
- } else if (!trailers_decompressed_) {
- return true;
- } else {
- return trailers_delivered_ && decompressed_trailers_.empty();
- }
-}
-
-SpdyPriority QuicSpdyStream::priority() const {
- return priority_;
-}
-
-void QuicSpdyStream::ClearSession() {
- spdy_session_ = nullptr;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_spdy_stream.h b/chromium/net/quic/quic_spdy_stream.h
deleted file mode 100644
index 86d69a8ede4..00000000000
--- a/chromium/net/quic/quic_spdy_stream.h
+++ /dev/null
@@ -1,250 +0,0 @@
-// Copyright 2013 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.
-//
-// The base class for streams which deliver data to/from an application.
-// In each direction, the data on such a stream first contains compressed
-// headers then body data.
-
-#ifndef NET_QUIC_QUIC_SPDY_STREAM_H_
-#define NET_QUIC_QUIC_SPDY_STREAM_H_
-
-#include <stddef.h>
-#include <sys/types.h>
-
-#include <list>
-#include <string>
-
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "net/base/iovec.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_header_list.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_stream_sequencer.h"
-#include "net/quic/reliable_quic_stream.h"
-#include "net/spdy/spdy_framer.h"
-
-namespace net {
-
-namespace test {
-class QuicSpdyStreamPeer;
-class ReliableQuicStreamPeer;
-} // namespace test
-
-class QuicSpdySession;
-
-// This is somewhat arbitrary. It's possible, but unlikely, we will either fail
-// to set a priority client-side, or cancel a stream before stripping the
-// priority from the wire server-side. In either case, start out with a
-// priority in the middle.
-const SpdyPriority kDefaultPriority = 3;
-
-// A QUIC stream that can send and receive HTTP2 (SPDY) headers.
-class NET_EXPORT_PRIVATE QuicSpdyStream : public ReliableQuicStream {
- public:
- // Visitor receives callbacks from the stream.
- class NET_EXPORT_PRIVATE Visitor {
- public:
- Visitor() {}
-
- // Called when the stream is closed.
- virtual void OnClose(QuicSpdyStream* stream) = 0;
-
- // Allows subclasses to override and do work.
- virtual void OnPromiseHeadersComplete(QuicStreamId promised_id,
- size_t frame_len) {}
-
- protected:
- virtual ~Visitor() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Visitor);
- };
-
- QuicSpdyStream(QuicStreamId id, QuicSpdySession* spdy_session);
- ~QuicSpdyStream() override;
-
- // Override the base class to send QUIC_STREAM_NO_ERROR to the peer
- // when the stream has not received all the data.
- void CloseWriteSide() override;
- void StopReading() override;
-
- // ReliableQuicStream implementation
- void OnClose() override;
-
- // Called by the session when decompressed headers data is received
- // for this stream.
- // May be called multiple times, with each call providing additional headers
- // data until OnStreamHeadersComplete is called.
- virtual void OnStreamHeaders(base::StringPiece headers_data);
-
- // Called by the session when headers with a priority have been received
- // for this stream. This method will only be called for server streams.
- virtual void OnStreamHeadersPriority(SpdyPriority priority);
-
- // Called by the session when decompressed headers have been completely
- // delivered to this stream. If |fin| is true, then this stream
- // should be closed; no more data will be sent by the peer.
- virtual void OnStreamHeadersComplete(bool fin, size_t frame_len);
-
- // Called by the session when decompressed headers have been completely
- // delivered to this stream. If |fin| is true, then this stream
- // should be closed; no more data will be sent by the peer.
- virtual void OnStreamHeaderList(bool fin,
- size_t frame_len,
- const QuicHeaderList& header_list);
-
- // Called by the session when decompressed PUSH_PROMISE headers data
- // is received for this stream.
- // May be called multiple times, with each call providing additional headers
- // data until OnPromiseHeadersComplete is called.
- virtual void OnPromiseHeaders(base::StringPiece headers_data);
-
- // Called by the session when decompressed push promise headers have
- // been completely delivered to this stream.
- virtual void OnPromiseHeadersComplete(QuicStreamId promised_id,
- size_t frame_len);
-
- // Called by the session when decompressed push promise headers have
- // been completely delivered to this stream.
- virtual void OnPromiseHeaderList(QuicStreamId promised_id,
- size_t frame_len,
- const QuicHeaderList& header_list);
-
- // Override the base class to not discard response when receiving
- // QUIC_STREAM_NO_ERROR on QUIC_VERSION_29 and later versions.
- void OnStreamReset(const QuicRstStreamFrame& frame) override;
-
- // Writes the headers contained in |header_block| to the dedicated
- // headers stream.
- virtual size_t WriteHeaders(SpdyHeaderBlock header_block,
- bool fin,
- QuicAckListenerInterface* ack_notifier_delegate);
-
- // Sends |data| to the peer, or buffers if it can't be sent immediately.
- void WriteOrBufferBody(const std::string& data,
- bool fin,
- QuicAckListenerInterface* ack_notifier_delegate);
-
- // Writes the trailers contained in |trailer_block| to the dedicated
- // headers stream. Trailers will always have the FIN set.
- virtual size_t WriteTrailers(SpdyHeaderBlock trailer_block,
- QuicAckListenerInterface* ack_notifier_delegate);
-
- // Marks |bytes_consumed| of the headers data as consumed.
- void MarkHeadersConsumed(size_t bytes_consumed);
-
- // Marks |bytes_consumed| of the trailers data as consumed.
- void MarkTrailersConsumed(size_t bytes_consumed);
-
- // Marks the trailers as consumed.
- void MarkTrailersDelivered();
-
- // Clears |header_list_|.
- void ConsumeHeaderList();
-
- // This block of functions wraps the sequencer's functions of the same
- // name. These methods return uncompressed data until that has
- // been fully processed. Then they simply delegate to the sequencer.
- virtual size_t Readv(const struct iovec* iov, size_t iov_len);
- virtual int GetReadableRegions(iovec* iov, size_t iov_len) const;
- void MarkConsumed(size_t num_bytes);
-
- // Returns true if header contains a valid 3-digit status and parse the status
- // code to |status_code|.
- bool ParseHeaderStatusCode(const SpdyHeaderBlock& header,
- int* status_code) const;
-
- // Returns true when all data has been read from the peer, including the fin.
- bool IsDoneReading() const;
- bool HasBytesToRead() const;
-
- void set_visitor(Visitor* visitor) { visitor_ = visitor; }
-
- bool headers_decompressed() const { return headers_decompressed_; }
-
- const std::string& decompressed_headers() const {
- return decompressed_headers_;
- }
-
- const QuicHeaderList& header_list() const { return header_list_; }
-
- bool trailers_decompressed() const { return trailers_decompressed_; }
-
- const std::string& decompressed_trailers() const {
- return decompressed_trailers_;
- }
-
- // Returns whatever trailers have been received for this stream.
- const SpdyHeaderBlock& received_trailers() const {
- return received_trailers_;
- }
-
- virtual SpdyPriority priority() const;
-
- // Sets priority_ to priority. This should only be called before bytes are
- // written to the server.
- void SetPriority(SpdyPriority priority);
-
- // Called when owning session is getting deleted to avoid subsequent
- // use of the spdy_session_ member.
- void ClearSession();
-
- protected:
- // Called by OnStreamHeadersComplete depending on which type (initial or
- // trailing) headers are expected next.
- virtual void OnInitialHeadersComplete(bool fin, size_t frame_len);
- virtual void OnTrailingHeadersComplete(bool fin, size_t frame_len);
- virtual void OnInitialHeadersComplete(bool fin,
- size_t frame_len,
- const QuicHeaderList& header_list);
- virtual void OnTrailingHeadersComplete(bool fin,
- size_t frame_len,
- const QuicHeaderList& header_list);
- QuicSpdySession* spdy_session() const { return spdy_session_; }
- Visitor* visitor() { return visitor_; }
-
- // Returns true if headers have been fully read and consumed.
- bool FinishedReadingHeaders() const;
-
- private:
- friend class test::QuicSpdyStreamPeer;
- friend class test::ReliableQuicStreamPeer;
- friend class QuicStreamUtils;
-
- // Returns true if trailers have been fully read and consumed.
- bool FinishedReadingTrailers() const;
-
- QuicSpdySession* spdy_session_;
-
- Visitor* visitor_;
- // True if the headers have been completely decompressed.
- bool headers_decompressed_;
- // The priority of the stream, once parsed.
- SpdyPriority priority_;
- // Contains a copy of the decompressed headers until they are consumed
- // via ProcessData or Readv.
- std::string decompressed_headers_;
- // Contains a copy of the decompressed header (name, value) pairs until they
- // are consumed via Readv.
- QuicHeaderList header_list_;
-
- // True if the trailers have been completely decompressed.
- bool trailers_decompressed_;
- // True if the trailers have been consumed.
- bool trailers_delivered_;
- // Contains a copy of the decompressed trailers until they are consumed
- // via ProcessData or Readv.
- std::string decompressed_trailers_;
- // The parsed trailers received from the peer.
- SpdyHeaderBlock received_trailers_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicSpdyStream);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_SPDY_STREAM_H_
diff --git a/chromium/net/quic/quic_spdy_stream_test.cc b/chromium/net/quic/quic_spdy_stream_test.cc
deleted file mode 100644
index a869ded8911..00000000000
--- a/chromium/net/quic/quic_spdy_stream_test.cc
+++ /dev/null
@@ -1,999 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_spdy_stream.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/strings/string_number_conversions.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/quic_write_blocked_list.h"
-#include "net/quic/spdy_utils.h"
-#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_test_utils.h"
-#include "net/quic/test_tools/reliable_quic_stream_peer.h"
-#include "net/test/gtest_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using base::StringPiece;
-using std::min;
-using std::string;
-using testing::AnyNumber;
-using testing::Invoke;
-using testing::Return;
-using testing::StrictMock;
-using testing::_;
-
-namespace net {
-namespace test {
-namespace {
-
-const bool kShouldProcessData = true;
-
-class TestStream : public QuicSpdyStream {
- public:
- TestStream(QuicStreamId id,
- QuicSpdySession* session,
- bool should_process_data)
- : QuicSpdyStream(id, session),
- should_process_data_(should_process_data) {}
-
- void OnDataAvailable() override {
- if (!should_process_data_) {
- return;
- }
- char buffer[2048];
- struct iovec vec;
- vec.iov_base = buffer;
- vec.iov_len = arraysize(buffer);
- size_t bytes_read = Readv(&vec, 1);
- data_ += string(buffer, bytes_read);
- }
-
- using ReliableQuicStream::WriteOrBufferData;
- using ReliableQuicStream::CloseWriteSide;
-
- const string& data() const { return data_; }
-
- private:
- bool should_process_data_;
- string data_;
-};
-
-class QuicSpdyStreamTest : public ::testing::TestWithParam<QuicVersion> {
- public:
- QuicSpdyStreamTest() {
- FLAGS_quic_always_log_bugs_for_tests = true;
- headers_[":host"] = "www.google.com";
- headers_[":path"] = "/index.hml";
- headers_[":scheme"] = "https";
- headers_["cookie"] =
- "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; "
- "__utmc=160408618; "
- "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX"
- "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX"
- "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT"
- "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0"
- "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh"
- "1zFMi5vzcns38-8_Sns; "
- "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-"
- "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339"
- "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c"
- "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%"
- "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4"
- "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1"
- "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP"
- "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6"
- "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b"
- "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6"
- "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG"
- "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk"
- "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn"
- "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
- "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
- }
-
- void Initialize(bool stream_should_process_data) {
- connection_ = new testing::StrictMock<MockQuicConnection>(
- &helper_, &alarm_factory_, Perspective::IS_SERVER,
- SupportedVersions(GetParam()));
- session_.reset(new testing::StrictMock<MockQuicSpdySession>(connection_));
- stream_ = new TestStream(kClientDataStreamId1, session_.get(),
- stream_should_process_data);
- session_->ActivateStream(stream_);
- stream2_ = new TestStream(kClientDataStreamId2, session_.get(),
- stream_should_process_data);
- session_->ActivateStream(stream2_);
- }
-
- protected:
- MockQuicConnectionHelper helper_;
- MockAlarmFactory alarm_factory_;
- MockQuicConnection* connection_;
- std::unique_ptr<MockQuicSpdySession> session_;
-
- // Owned by the |session_|.
- TestStream* stream_;
- TestStream* stream2_;
-
- SpdyHeaderBlock headers_;
-};
-
-INSTANTIATE_TEST_CASE_P(Tests,
- QuicSpdyStreamTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
-
-TEST_P(QuicSpdyStreamTest, ProcessHeaders) {
- Initialize(kShouldProcessData);
-
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeadersPriority(kV3HighestPriority);
- stream_->OnStreamHeaders(headers);
- EXPECT_EQ("", stream_->data());
- EXPECT_EQ(headers, stream_->decompressed_headers());
- stream_->OnStreamHeadersComplete(false, headers.size());
- EXPECT_EQ(kV3HighestPriority, stream_->priority());
- EXPECT_EQ("", stream_->data());
- EXPECT_EQ(headers, stream_->decompressed_headers());
- EXPECT_FALSE(stream_->IsDoneReading());
-}
-
-TEST_P(QuicSpdyStreamTest, ProcessHeaderList) {
- Initialize(kShouldProcessData);
-
- size_t total_bytes = 0;
- QuicHeaderList headers;
- for (auto p : headers_) {
- headers.OnHeader(p.first, p.second);
- total_bytes += p.first.size() + p.second.size();
- }
- stream_->OnStreamHeadersPriority(kV3HighestPriority);
- stream_->OnStreamHeaderList(false, total_bytes, headers);
- EXPECT_EQ("", stream_->data());
- EXPECT_FALSE(stream_->header_list().empty());
- EXPECT_FALSE(stream_->IsDoneReading());
-}
-
-TEST_P(QuicSpdyStreamTest, ProcessHeadersWithFin) {
- Initialize(kShouldProcessData);
-
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeadersPriority(kV3HighestPriority);
- stream_->OnStreamHeaders(headers);
- EXPECT_EQ("", stream_->data());
- EXPECT_EQ(headers, stream_->decompressed_headers());
- stream_->OnStreamHeadersComplete(true, headers.size());
- EXPECT_EQ(kV3HighestPriority, stream_->priority());
- EXPECT_EQ("", stream_->data());
- EXPECT_EQ(headers, stream_->decompressed_headers());
- EXPECT_FALSE(stream_->IsDoneReading());
- EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
-}
-
-TEST_P(QuicSpdyStreamTest, ProcessHeaderListWithFin) {
- Initialize(kShouldProcessData);
-
- size_t total_bytes = 0;
- QuicHeaderList headers;
- for (auto p : headers_) {
- headers.OnHeader(p.first, p.second);
- total_bytes += p.first.size() + p.second.size();
- }
- stream_->OnStreamHeadersPriority(kV3HighestPriority);
- stream_->OnStreamHeaderList(true, total_bytes, headers);
- EXPECT_EQ("", stream_->data());
- EXPECT_FALSE(stream_->header_list().empty());
- EXPECT_FALSE(stream_->IsDoneReading());
- EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
-}
-
-TEST_P(QuicSpdyStreamTest, ParseHeaderStatusCode) {
- // A valid status code should be 3-digit integer. The first digit should be in
- // the range of [1, 5]. All the others are invalid.
- Initialize(kShouldProcessData);
- int status_code = 0;
-
- // Valid status code.
- headers_.ReplaceOrAppendHeader(":status", "404");
- EXPECT_TRUE(stream_->ParseHeaderStatusCode(headers_, &status_code));
- EXPECT_EQ(404, status_code);
-
- // Invalid status codes.
- headers_.ReplaceOrAppendHeader(":status", "010");
- EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
-
- headers_.ReplaceOrAppendHeader(":status", "600");
- EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
-
- headers_.ReplaceOrAppendHeader(":status", "200 ok");
- EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
-
- headers_.ReplaceOrAppendHeader(":status", "2000");
- EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
-
- headers_.ReplaceOrAppendHeader(":status", "+200");
- EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
-
- headers_.ReplaceOrAppendHeader(":status", "+20");
- EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
-
- // Leading or trailing spaces are also invalid.
- headers_.ReplaceOrAppendHeader(":status", " 200");
- EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
-
- headers_.ReplaceOrAppendHeader(":status", "200 ");
- EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
-
- headers_.ReplaceOrAppendHeader(":status", " 200 ");
- EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
-
- headers_.ReplaceOrAppendHeader(":status", " ");
- EXPECT_FALSE(stream_->ParseHeaderStatusCode(headers_, &status_code));
-}
-
-TEST_P(QuicSpdyStreamTest, MarkHeadersConsumed) {
- Initialize(kShouldProcessData);
-
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- string body = "this is the body";
-
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(false, headers.size());
- EXPECT_EQ(headers, stream_->decompressed_headers());
-
- headers.erase(0, 10);
- stream_->MarkHeadersConsumed(10);
- EXPECT_EQ(headers, stream_->decompressed_headers());
-
- stream_->MarkHeadersConsumed(headers.length());
- EXPECT_EQ("", stream_->decompressed_headers());
-}
-
-TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBody) {
- Initialize(kShouldProcessData);
-
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- string body = "this is the body";
-
- stream_->OnStreamHeaders(headers);
- EXPECT_EQ("", stream_->data());
- EXPECT_EQ(headers, stream_->decompressed_headers());
- stream_->OnStreamHeadersComplete(false, headers.size());
- EXPECT_EQ(headers, stream_->decompressed_headers());
- stream_->MarkHeadersConsumed(headers.length());
- QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
- stream_->OnStreamFrame(frame);
- EXPECT_EQ("", stream_->decompressed_headers());
- EXPECT_EQ(body, stream_->data());
-}
-
-TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyFragments) {
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- string body = "this is the body";
-
- for (size_t fragment_size = 1; fragment_size < body.size(); ++fragment_size) {
- Initialize(kShouldProcessData);
- for (size_t offset = 0; offset < headers.size(); offset += fragment_size) {
- size_t remaining_data = headers.size() - offset;
- StringPiece fragment(headers.data() + offset,
- min(fragment_size, remaining_data));
- stream_->OnStreamHeaders(fragment);
- }
- stream_->OnStreamHeadersComplete(false, headers.size());
- ASSERT_EQ(headers, stream_->decompressed_headers()) << "fragment_size: "
- << fragment_size;
- stream_->MarkHeadersConsumed(headers.length());
- for (size_t offset = 0; offset < body.size(); offset += fragment_size) {
- size_t remaining_data = body.size() - offset;
- StringPiece fragment(body.data() + offset,
- min(fragment_size, remaining_data));
- QuicStreamFrame frame(kClientDataStreamId1, false, offset,
- StringPiece(fragment));
- stream_->OnStreamFrame(frame);
- }
- ASSERT_EQ(body, stream_->data()) << "fragment_size: " << fragment_size;
- }
-}
-
-TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyFragmentsSplit) {
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- string body = "this is the body";
-
- for (size_t split_point = 1; split_point < body.size() - 1; ++split_point) {
- Initialize(kShouldProcessData);
- StringPiece headers1(headers.data(), split_point);
- stream_->OnStreamHeaders(headers1);
-
- StringPiece headers2(headers.data() + split_point,
- headers.size() - split_point);
- stream_->OnStreamHeaders(headers2);
- stream_->OnStreamHeadersComplete(false, headers.size());
- ASSERT_EQ(headers, stream_->decompressed_headers()) << "split_point: "
- << split_point;
- stream_->MarkHeadersConsumed(headers.length());
-
- StringPiece fragment1(body.data(), split_point);
- QuicStreamFrame frame1(kClientDataStreamId1, false, 0,
- StringPiece(fragment1));
- stream_->OnStreamFrame(frame1);
-
- StringPiece fragment2(body.data() + split_point, body.size() - split_point);
- QuicStreamFrame frame2(kClientDataStreamId1, false, split_point,
- StringPiece(fragment2));
- stream_->OnStreamFrame(frame2);
-
- ASSERT_EQ(body, stream_->data()) << "split_point: " << split_point;
- }
-}
-
-TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyReadv) {
- Initialize(!kShouldProcessData);
-
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- string body = "this is the body";
-
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(false, headers.size());
- QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
- stream_->OnStreamFrame(frame);
- stream_->MarkHeadersConsumed(headers.length());
-
- char buffer[2048];
- ASSERT_LT(body.length(), arraysize(buffer));
- struct iovec vec;
- vec.iov_base = buffer;
- vec.iov_len = arraysize(buffer);
-
- size_t bytes_read = stream_->Readv(&vec, 1);
- EXPECT_EQ(body.length(), bytes_read);
- EXPECT_EQ(body, string(buffer, bytes_read));
-}
-
-TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyMarkConsumed) {
- Initialize(!kShouldProcessData);
-
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- string body = "this is the body";
-
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(false, headers.size());
- QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
- stream_->OnStreamFrame(frame);
- stream_->MarkHeadersConsumed(headers.length());
-
- struct iovec vec;
-
- EXPECT_EQ(1, stream_->GetReadableRegions(&vec, 1));
- EXPECT_EQ(body.length(), vec.iov_len);
- EXPECT_EQ(body, string(static_cast<char*>(vec.iov_base), vec.iov_len));
-
- stream_->MarkConsumed(body.length());
- EXPECT_EQ(body.length(), stream_->flow_controller()->bytes_consumed());
-}
-
-TEST_P(QuicSpdyStreamTest, ProcessHeadersAndBodyIncrementalReadv) {
- Initialize(!kShouldProcessData);
-
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- string body = "this is the body";
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(false, headers.size());
- QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
- stream_->OnStreamFrame(frame);
- stream_->MarkHeadersConsumed(headers.length());
-
- char buffer[1];
- struct iovec vec;
- vec.iov_base = buffer;
- vec.iov_len = arraysize(buffer);
-
- for (size_t i = 0; i < body.length(); ++i) {
- size_t bytes_read = stream_->Readv(&vec, 1);
- ASSERT_EQ(1u, bytes_read);
- EXPECT_EQ(body.data()[i], buffer[0]);
- }
-}
-
-TEST_P(QuicSpdyStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) {
- Initialize(!kShouldProcessData);
-
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- string body = "this is the body";
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(false, headers.size());
- QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
- stream_->OnStreamFrame(frame);
- stream_->MarkHeadersConsumed(headers.length());
-
- char buffer1[1];
- char buffer2[1];
- struct iovec vec[2];
- vec[0].iov_base = buffer1;
- vec[0].iov_len = arraysize(buffer1);
- vec[1].iov_base = buffer2;
- vec[1].iov_len = arraysize(buffer2);
-
- for (size_t i = 0; i < body.length(); i += 2) {
- size_t bytes_read = stream_->Readv(vec, 2);
- ASSERT_EQ(2u, bytes_read) << i;
- ASSERT_EQ(body.data()[i], buffer1[0]) << i;
- ASSERT_EQ(body.data()[i + 1], buffer2[0]) << i;
- }
-}
-
-TEST_P(QuicSpdyStreamTest, StreamFlowControlBlocked) {
- // Tests that we send a BLOCKED frame to the peer when we attempt to write,
- // but are flow control blocked.
- Initialize(kShouldProcessData);
-
- // Set a small flow control limit.
- const uint64_t kWindow = 36;
- QuicFlowControllerPeer::SetSendWindowOffset(stream_->flow_controller(),
- kWindow);
- EXPECT_EQ(kWindow, QuicFlowControllerPeer::SendWindowOffset(
- stream_->flow_controller()));
-
- // Try to send more data than the flow control limit allows.
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- string body;
- const uint64_t kOverflow = 15;
- GenerateBody(&body, kWindow + kOverflow);
-
- EXPECT_CALL(*connection_, SendBlocked(kClientDataStreamId1));
- EXPECT_CALL(*session_, WritevData(stream_, kClientDataStreamId1, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(kWindow, true)));
- stream_->WriteOrBufferData(body, false, nullptr);
-
- // Should have sent as much as possible, resulting in no send window left.
- EXPECT_EQ(0u,
- QuicFlowControllerPeer::SendWindowSize(stream_->flow_controller()));
-
- // And we should have queued the overflowed data.
- EXPECT_EQ(kOverflow, ReliableQuicStreamPeer::SizeOfQueuedData(stream_));
-}
-
-TEST_P(QuicSpdyStreamTest, StreamFlowControlNoWindowUpdateIfNotConsumed) {
- // The flow control receive window decreases whenever we add new bytes to the
- // sequencer, whether they are consumed immediately or buffered. However we
- // only send WINDOW_UPDATE frames based on increasing number of bytes
- // consumed.
-
- // Don't process data - it will be buffered instead.
- Initialize(!kShouldProcessData);
-
- // Expect no WINDOW_UPDATE frames to be sent.
- EXPECT_CALL(*connection_, SendWindowUpdate(_, _)).Times(0);
-
- // Set a small flow control receive window.
- const uint64_t kWindow = 36;
- QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(),
- kWindow);
- QuicFlowControllerPeer::SetMaxReceiveWindow(stream_->flow_controller(),
- kWindow);
- EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowOffset(
- stream_->flow_controller()));
-
- // Stream receives enough data to fill a fraction of the receive window.
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- string body;
- GenerateBody(&body, kWindow / 3);
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(false, headers.size());
-
- QuicStreamFrame frame1(kClientDataStreamId1, false, 0, StringPiece(body));
- stream_->OnStreamFrame(frame1);
- EXPECT_EQ(kWindow - (kWindow / 3), QuicFlowControllerPeer::ReceiveWindowSize(
- stream_->flow_controller()));
-
- // Now receive another frame which results in the receive window being over
- // half full. This should all be buffered, decreasing the receive window but
- // not sending WINDOW_UPDATE.
- QuicStreamFrame frame2(kClientDataStreamId1, false, kWindow / 3,
- StringPiece(body));
- stream_->OnStreamFrame(frame2);
- EXPECT_EQ(
- kWindow - (2 * kWindow / 3),
- QuicFlowControllerPeer::ReceiveWindowSize(stream_->flow_controller()));
-}
-
-TEST_P(QuicSpdyStreamTest, StreamFlowControlWindowUpdate) {
- // Tests that on receipt of data, the stream updates its receive window offset
- // appropriately, and sends WINDOW_UPDATE frames when its receive window drops
- // too low.
- Initialize(kShouldProcessData);
-
- // Set a small flow control limit.
- const uint64_t kWindow = 36;
- QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(),
- kWindow);
- QuicFlowControllerPeer::SetMaxReceiveWindow(stream_->flow_controller(),
- kWindow);
- EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowOffset(
- stream_->flow_controller()));
-
- // Stream receives enough data to fill a fraction of the receive window.
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- string body;
- GenerateBody(&body, kWindow / 3);
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(false, headers.size());
- stream_->MarkHeadersConsumed(headers.length());
-
- QuicStreamFrame frame1(kClientDataStreamId1, false, 0, StringPiece(body));
- stream_->OnStreamFrame(frame1);
- EXPECT_EQ(kWindow - (kWindow / 3), QuicFlowControllerPeer::ReceiveWindowSize(
- stream_->flow_controller()));
-
- // Now receive another frame which results in the receive window being over
- // half full. This will trigger the stream to increase its receive window
- // offset and send a WINDOW_UPDATE. The result will be again an available
- // window of kWindow bytes.
- QuicStreamFrame frame2(kClientDataStreamId1, false, kWindow / 3,
- StringPiece(body));
- EXPECT_CALL(*connection_,
- SendWindowUpdate(kClientDataStreamId1,
- QuicFlowControllerPeer::ReceiveWindowOffset(
- stream_->flow_controller()) +
- 2 * kWindow / 3));
- stream_->OnStreamFrame(frame2);
- EXPECT_EQ(kWindow, QuicFlowControllerPeer::ReceiveWindowSize(
- stream_->flow_controller()));
-}
-
-TEST_P(QuicSpdyStreamTest, ConnectionFlowControlWindowUpdate) {
- // Tests that on receipt of data, the connection updates its receive window
- // offset appropriately, and sends WINDOW_UPDATE frames when its receive
- // window drops too low.
- Initialize(kShouldProcessData);
-
- // Set a small flow control limit for streams and connection.
- const uint64_t kWindow = 36;
- QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(),
- kWindow);
- QuicFlowControllerPeer::SetMaxReceiveWindow(stream_->flow_controller(),
- kWindow);
- QuicFlowControllerPeer::SetReceiveWindowOffset(stream2_->flow_controller(),
- kWindow);
- QuicFlowControllerPeer::SetMaxReceiveWindow(stream2_->flow_controller(),
- kWindow);
- QuicFlowControllerPeer::SetReceiveWindowOffset(session_->flow_controller(),
- kWindow);
- QuicFlowControllerPeer::SetMaxReceiveWindow(session_->flow_controller(),
- kWindow);
-
- // Supply headers to both streams so that they are happy to receive data.
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(false, headers.size());
- stream_->MarkHeadersConsumed(headers.length());
- stream2_->OnStreamHeaders(headers);
- stream2_->OnStreamHeadersComplete(false, headers.size());
- stream2_->MarkHeadersConsumed(headers.length());
-
- // Each stream gets a quarter window of data. This should not trigger a
- // WINDOW_UPDATE for either stream, nor for the connection.
- string body;
- GenerateBody(&body, kWindow / 4);
- QuicStreamFrame frame1(kClientDataStreamId1, false, 0, StringPiece(body));
- stream_->OnStreamFrame(frame1);
- QuicStreamFrame frame2(kClientDataStreamId2, false, 0, StringPiece(body));
- stream2_->OnStreamFrame(frame2);
-
- // Now receive a further single byte on one stream - again this does not
- // trigger a stream WINDOW_UPDATE, but now the connection flow control window
- // is over half full and thus a connection WINDOW_UPDATE is sent.
- EXPECT_CALL(*connection_, SendWindowUpdate(kClientDataStreamId1, _)).Times(0);
- EXPECT_CALL(*connection_, SendWindowUpdate(kClientDataStreamId2, _)).Times(0);
- EXPECT_CALL(*connection_,
- SendWindowUpdate(0, QuicFlowControllerPeer::ReceiveWindowOffset(
- session_->flow_controller()) +
- 1 + kWindow / 2));
- QuicStreamFrame frame3(kClientDataStreamId1, false, (kWindow / 4),
- StringPiece("a"));
- stream_->OnStreamFrame(frame3);
-}
-
-TEST_P(QuicSpdyStreamTest, StreamFlowControlViolation) {
- // Tests that on if the peer sends too much data (i.e. violates the flow
- // control protocol), then we terminate the connection.
-
- // Stream should not process data, so that data gets buffered in the
- // sequencer, triggering flow control limits.
- Initialize(!kShouldProcessData);
-
- // Set a small flow control limit.
- const uint64_t kWindow = 50;
- QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(),
- kWindow);
-
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(false, headers.size());
-
- // Receive data to overflow the window, violating flow control.
- string body;
- GenerateBody(&body, kWindow + 1);
- QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _));
- stream_->OnStreamFrame(frame);
-}
-
-TEST_P(QuicSpdyStreamTest, TestHandlingQuicRstStreamNoError) {
- Initialize(kShouldProcessData);
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(false, headers.size());
-
- if (GetParam() <= QUIC_VERSION_28) {
- EXPECT_CALL(*session_, SendRstStream(_, _, _));
- }
- stream_->OnStreamReset(
- QuicRstStreamFrame(stream_->id(), QUIC_STREAM_NO_ERROR, 0));
- EXPECT_TRUE(stream_->write_side_closed());
- if (GetParam() > QUIC_VERSION_28) {
- EXPECT_FALSE(stream_->reading_stopped());
- } else {
- EXPECT_TRUE(stream_->reading_stopped());
- }
-}
-
-TEST_P(QuicSpdyStreamTest, ConnectionFlowControlViolation) {
- // Tests that on if the peer sends too much data (i.e. violates the flow
- // control protocol), at the connection level (rather than the stream level)
- // then we terminate the connection.
-
- // Stream should not process data, so that data gets buffered in the
- // sequencer, triggering flow control limits.
- Initialize(!kShouldProcessData);
-
- // Set a small flow control window on streams, and connection.
- const uint64_t kStreamWindow = 50;
- const uint64_t kConnectionWindow = 10;
- QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(),
- kStreamWindow);
- QuicFlowControllerPeer::SetReceiveWindowOffset(session_->flow_controller(),
- kConnectionWindow);
-
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(false, headers.size());
-
- // Send enough data to overflow the connection level flow control window.
- string body;
- GenerateBody(&body, kConnectionWindow + 1);
- EXPECT_LT(body.size(), kStreamWindow);
- QuicStreamFrame frame(kClientDataStreamId1, false, 0, StringPiece(body));
-
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _));
- stream_->OnStreamFrame(frame);
-}
-
-TEST_P(QuicSpdyStreamTest, StreamFlowControlFinNotBlocked) {
- // An attempt to write a FIN with no data should not be flow control blocked,
- // even if the send window is 0.
-
- Initialize(kShouldProcessData);
-
- // Set a flow control limit of zero.
- QuicFlowControllerPeer::SetReceiveWindowOffset(stream_->flow_controller(), 0);
- EXPECT_EQ(0u, QuicFlowControllerPeer::ReceiveWindowOffset(
- stream_->flow_controller()));
-
- // Send a frame with a FIN but no data. This should not be blocked.
- string body = "";
- bool fin = true;
-
- EXPECT_CALL(*connection_, SendBlocked(kClientDataStreamId1)).Times(0);
- EXPECT_CALL(*session_, WritevData(stream_, kClientDataStreamId1, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(0, fin)));
-
- stream_->WriteOrBufferData(body, fin, nullptr);
-}
-
-TEST_P(QuicSpdyStreamTest, ReceivingTrailers) {
- // Test that receiving trailing headers from the peer works, and can be read
- // from the stream and consumed.
- Initialize(kShouldProcessData);
-
- // Receive initial headers.
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(false, headers.size());
- stream_->MarkHeadersConsumed(stream_->decompressed_headers().size());
-
- // Receive trailing headers.
- SpdyHeaderBlock trailers_block;
- trailers_block["key1"] = "value1";
- trailers_block["key2"] = "value2";
- trailers_block["key3"] = "value3";
- trailers_block[kFinalOffsetHeaderKey] = "0";
- string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
- stream_->OnStreamHeaders(trailers);
- stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size());
-
- // The trailers should be decompressed, and readable from the stream.
- EXPECT_TRUE(stream_->trailers_decompressed());
- const string decompressed_trailers = stream_->decompressed_trailers();
- EXPECT_EQ(trailers, decompressed_trailers);
-
- // Consuming the trailers erases them from the stream.
- stream_->MarkTrailersConsumed(decompressed_trailers.size());
- EXPECT_EQ("", stream_->decompressed_trailers());
-}
-
-TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutOffset) {
- // Test that receiving trailers without a final offset field is an error.
- Initialize(kShouldProcessData);
-
- // Receive initial headers.
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(false, headers.size());
- stream_->MarkHeadersConsumed(stream_->decompressed_headers().size());
-
- const string body = "this is the body";
- // Receive trailing headers, without kFinalOffsetHeaderKey.
- SpdyHeaderBlock trailers_block;
- trailers_block["key1"] = "value1";
- trailers_block["key2"] = "value2";
- trailers_block["key3"] = "value3";
- string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
- stream_->OnStreamHeaders(trailers);
-
- // Verify that the trailers block didn't contain a final offset.
- EXPECT_EQ("", trailers_block[kFinalOffsetHeaderKey].as_string());
-
- // Receipt of the malformed trailers will close the connection.
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _))
- .Times(1);
- stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size());
-}
-
-TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithoutFin) {
- // Test that received Trailers must always have the FIN set.
- Initialize(kShouldProcessData);
-
- // Receive initial headers.
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(false, headers.size());
-
- // Receive trailing headers with FIN deliberately set to false.
- SpdyHeaderBlock trailers_block;
- string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
- stream_->OnStreamHeaders(trailers);
-
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _))
- .Times(1);
- stream_->OnStreamHeadersComplete(/*fin=*/false, trailers.size());
-}
-
-TEST_P(QuicSpdyStreamTest, ReceivingTrailersAfterFin) {
- // If Trailers are sent, neither Headers nor Body should contain a FIN.
- Initialize(kShouldProcessData);
-
- // Receive initial headers with FIN set.
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(/*fin=*/true, headers.size());
-
- // Receive trailing headers after FIN already received.
- SpdyHeaderBlock trailers_block;
- string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
- stream_->OnStreamHeaders(trailers);
-
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _))
- .Times(1);
- stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size());
-}
-
-TEST_P(QuicSpdyStreamTest, ReceivingTrailersAfterBodyWithFin) {
- // If body data are received with a FIN, no trailers should then arrive.
- Initialize(kShouldProcessData);
-
- // Receive initial headers without FIN set.
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(/*fin=*/false, headers.size());
-
- // Receive body data, with FIN.
- QuicStreamFrame frame(kClientDataStreamId1, /*fin=*/true, 0, "body");
- stream_->OnStreamFrame(frame);
-
- // Receive trailing headers after FIN already received.
- SpdyHeaderBlock trailers_block;
- string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
- stream_->OnStreamHeaders(trailers);
-
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _))
- .Times(1);
- stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size());
-}
-
-TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithOffset) {
- // Test that when receiving trailing headers with an offset before response
- // body, stream is closed at the right offset.
- Initialize(kShouldProcessData);
-
- // Receive initial headers.
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(false, headers.size());
- stream_->MarkHeadersConsumed(stream_->decompressed_headers().size());
-
- const string body = "this is the body";
- // Receive trailing headers.
- SpdyHeaderBlock trailers_block;
- trailers_block["key1"] = "value1";
- trailers_block["key2"] = "value2";
- trailers_block["key3"] = "value3";
- trailers_block[kFinalOffsetHeaderKey] = base::IntToString(body.size());
- string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block);
- stream_->OnStreamHeaders(trailers);
- stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size());
-
- // The trailers should be decompressed, and readable from the stream.
- EXPECT_TRUE(stream_->trailers_decompressed());
- const string decompressed_trailers = stream_->decompressed_trailers();
- EXPECT_EQ(trailers, decompressed_trailers);
- // Consuming the trailers erases them from the stream.
- stream_->MarkTrailersConsumed(decompressed_trailers.size());
- stream_->MarkTrailersDelivered();
- EXPECT_EQ("", stream_->decompressed_trailers());
-
- EXPECT_FALSE(stream_->IsDoneReading());
- // Receive and consume body.
- QuicStreamFrame frame(kClientDataStreamId1, /*fin=*/false, 0, body);
- stream_->OnStreamFrame(frame);
- EXPECT_EQ(body, stream_->data());
- EXPECT_TRUE(stream_->IsDoneReading());
-}
-
-TEST_P(QuicSpdyStreamTest, ClosingStreamWithNoTrailers) {
- // Verify that a stream receiving headers, body, and no trailers is correctly
- // marked as done reading on consumption of headers and body.
- Initialize(kShouldProcessData);
-
- // Receive and consume initial headers with FIN not set.
- string headers = SpdyUtils::SerializeUncompressedHeaders(headers_);
- stream_->OnStreamHeaders(headers);
- stream_->OnStreamHeadersComplete(/*fin=*/false, headers.size());
- stream_->MarkHeadersConsumed(headers.size());
-
- // Receive and consume body with FIN set, and no trailers.
- const string kBody = string(1024, 'x');
- QuicStreamFrame frame(kClientDataStreamId1, /*fin=*/true, 0, kBody);
- stream_->OnStreamFrame(frame);
-
- EXPECT_TRUE(stream_->IsDoneReading());
-}
-
-TEST_P(QuicSpdyStreamTest, WritingTrailersSendsAFin) {
- // Test that writing trailers will send a FIN, as Trailers are the last thing
- // to be sent on a stream.
- Initialize(kShouldProcessData);
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .Times(AnyNumber())
- .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
-
- // Write the initial headers, without a FIN.
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _));
- stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
-
- // Writing trailers implicitly sends a FIN.
- SpdyHeaderBlock trailers;
- trailers["trailer key"] = "trailer value";
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _));
- stream_->WriteTrailers(std::move(trailers), nullptr);
- EXPECT_TRUE(stream_->fin_sent());
-}
-
-TEST_P(QuicSpdyStreamTest, WritingTrailersFinalOffset) {
- // Test that when writing trailers, the trailers that are actually sent to the
- // peer contain the final offset field indicating last byte of data.
- Initialize(kShouldProcessData);
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .Times(AnyNumber())
- .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
-
- // Write the initial headers.
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _));
- stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
-
- // Write non-zero body data to force a non-zero final offset.
- const int kBodySize = 1 * 1024; // 1 MB
- stream_->WriteOrBufferData(string(kBodySize, 'x'), false, nullptr);
-
- // The final offset field in the trailing headers is populated with the
- // number of body bytes written (including queued bytes).
- SpdyHeaderBlock trailers;
- trailers["trailer key"] = "trailer value";
- SpdyHeaderBlock trailers_with_offset(trailers.Clone());
- trailers_with_offset[kFinalOffsetHeaderKey] = base::IntToString(kBodySize);
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _));
- stream_->WriteTrailers(std::move(trailers), nullptr);
- EXPECT_EQ(trailers_with_offset, session_->GetWriteHeaders());
-}
-
-TEST_P(QuicSpdyStreamTest, WritingTrailersClosesWriteSide) {
- // Test that if trailers are written after all other data has been written
- // (headers and body), that this closes the stream for writing.
- Initialize(kShouldProcessData);
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .Times(AnyNumber())
- .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
-
- // Write the initial headers.
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _));
- stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
-
- // Write non-zero body data.
- const int kBodySize = 1 * 1024; // 1 MB
- stream_->WriteOrBufferData(string(kBodySize, 'x'), false, nullptr);
- EXPECT_EQ(0u, stream_->queued_data_bytes());
-
- // Headers and body have been fully written, there is no queued data. Writing
- // trailers marks the end of this stream, and thus the write side is closed.
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _));
- stream_->WriteTrailers(SpdyHeaderBlock(), nullptr);
- EXPECT_TRUE(stream_->write_side_closed());
-}
-
-TEST_P(QuicSpdyStreamTest, WritingTrailersWithQueuedBytes) {
- // Test that the stream is not closed for writing when trailers are sent
- // while there are still body bytes queued.
- Initialize(kShouldProcessData);
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .Times(AnyNumber())
- .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
-
- // Write the initial headers.
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _));
- stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr);
-
- // Write non-zero body data, but only consume partially, ensuring queueing.
- const int kBodySize = 1 * 1024; // 1 MB
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(kBodySize - 1, false)));
- stream_->WriteOrBufferData(string(kBodySize, 'x'), false, nullptr);
- EXPECT_EQ(1u, stream_->queued_data_bytes());
-
- // Writing trailers will send a FIN, but not close the write side of the
- // stream as there are queued bytes.
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _));
- stream_->WriteTrailers(SpdyHeaderBlock(), nullptr);
- EXPECT_TRUE(stream_->fin_sent());
- EXPECT_FALSE(stream_->write_side_closed());
-}
-
-TEST_P(QuicSpdyStreamTest, WritingTrailersAfterFIN) {
- // Test that it is not possible to write Trailers after a FIN has been sent.
- Initialize(kShouldProcessData);
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .Times(AnyNumber())
- .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
-
- // Write the initial headers, with a FIN.
- EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _));
- stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/true, nullptr);
- EXPECT_TRUE(stream_->fin_sent());
-
- // Writing Trailers should fail, as the FIN has already been sent.
- // populated with the number of body bytes written.
- EXPECT_DFATAL(stream_->WriteTrailers(SpdyHeaderBlock(), nullptr),
- "Trailers cannot be sent after a FIN");
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_stream_factory.cc b/chromium/net/quic/quic_stream_factory.cc
deleted file mode 100644
index 832cf909eb8..00000000000
--- a/chromium/net/quic/quic_stream_factory.cc
+++ /dev/null
@@ -1,1878 +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/quic_stream_factory.h"
-
-#include <openssl/aead.h>
-
-#include <algorithm>
-#include <tuple>
-#include <utility>
-
-#include "base/location.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/field_trial.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/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/trace_event/trace_event.h"
-#include "base/values.h"
-#include "crypto/openssl_util.h"
-#include "net/base/ip_address.h"
-#include "net/base/net_errors.h"
-#include "net/cert/cert_verifier.h"
-#include "net/cert/ct_verifier.h"
-#include "net/dns/host_resolver.h"
-#include "net/dns/single_request_host_resolver.h"
-#include "net/http/bidirectional_stream_impl.h"
-#include "net/quic/bidirectional_stream_quic_impl.h"
-#include "net/quic/crypto/channel_id_chromium.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/crypto/properties_based_quic_server_info.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/crypto/quic_server_info.h"
-#include "net/quic/port_suggester.h"
-#include "net/quic/quic_chromium_alarm_factory.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_chromium_packet_reader.h"
-#include "net/quic/quic_chromium_packet_writer.h"
-#include "net/quic/quic_client_promised_info.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_crypto_client_stream_factory.h"
-#include "net/quic/quic_flags.h"
-#include "net/socket/client_socket_factory.h"
-#include "net/socket/socket_performance_watcher.h"
-#include "net/socket/socket_performance_watcher_factory.h"
-#include "net/ssl/token_binding.h"
-#include "net/udp/udp_client_socket.h"
-
-using std::min;
-using NetworkHandle = net::NetworkChangeNotifier::NetworkHandle;
-
-namespace net {
-
-namespace {
-
-enum CreateSessionFailure {
- CREATION_ERROR_CONNECTING_SOCKET,
- CREATION_ERROR_SETTING_RECEIVE_BUFFER,
- CREATION_ERROR_SETTING_SEND_BUFFER,
- CREATION_ERROR_MAX
-};
-
-enum QuicConnectionMigrationStatus {
- MIGRATION_STATUS_NO_MIGRATABLE_STREAMS,
- MIGRATION_STATUS_ALREADY_MIGRATED,
- MIGRATION_STATUS_INTERNAL_ERROR,
- MIGRATION_STATUS_TOO_MANY_CHANGES,
- MIGRATION_STATUS_SUCCESS,
- MIGRATION_STATUS_NON_MIGRATABLE_STREAM,
- MIGRATION_STATUS_DISABLED,
- MIGRATION_STATUS_MAX
-};
-
-// The maximum receive window sizes for QUIC sessions and streams.
-const int32_t kQuicSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB
-const int32_t kQuicStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
-
-// Set the maximum number of undecryptable packets the connection will store.
-const int32_t kMaxUndecryptablePackets = 100;
-
-std::unique_ptr<base::Value> NetLogQuicConnectionMigrationTriggerCallback(
- std::string trigger,
- NetLogCaptureMode capture_mode) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetString("trigger", trigger);
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogQuicConnectionMigrationFailureCallback(
- QuicConnectionId connection_id,
- 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("reason", reason);
- return std::move(dict);
-}
-
-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));
- return std::move(dict);
-}
-
-// Helper class that is used to log a connection migration event.
-class ScopedConnectionMigrationEventLog {
- public:
- ScopedConnectionMigrationEventLog(NetLog* net_log, std::string trigger)
- : net_log_(BoundNetLog::Make(net_log,
- NetLog::SOURCE_QUIC_CONNECTION_MIGRATION)) {
- net_log_.BeginEvent(
- NetLog::TYPE_QUIC_CONNECTION_MIGRATION_TRIGGERED,
- base::Bind(&NetLogQuicConnectionMigrationTriggerCallback, trigger));
- }
-
- ~ScopedConnectionMigrationEventLog() {
- net_log_.EndEvent(NetLog::TYPE_QUIC_CONNECTION_MIGRATION_TRIGGERED);
- }
-
- const BoundNetLog& net_log() { return net_log_; }
-
- private:
- const BoundNetLog net_log_;
-};
-
-void HistogramCreateSessionFailure(enum CreateSessionFailure error) {
- UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error,
- CREATION_ERROR_MAX);
-}
-
-void HistogramAndLogMigrationFailure(const BoundNetLog& net_log,
- enum QuicConnectionMigrationStatus status,
- QuicConnectionId connection_id,
- std::string reason) {
- UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionMigration", status,
- MIGRATION_STATUS_MAX);
- net_log.AddEvent(NetLog::TYPE_QUIC_CONNECTION_MIGRATION_FAILURE,
- base::Bind(&NetLogQuicConnectionMigrationFailureCallback,
- connection_id, reason));
-}
-
-void HistogramMigrationStatus(enum QuicConnectionMigrationStatus status) {
- UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionMigration", status,
- MIGRATION_STATUS_MAX);
-}
-
-QuicConfig InitializeQuicConfig(const QuicTagVector& connection_options,
- int idle_connection_timeout_seconds) {
- DCHECK_GT(idle_connection_timeout_seconds, 0);
- QuicConfig config;
- config.SetIdleConnectionStateLifetime(
- QuicTime::Delta::FromSeconds(idle_connection_timeout_seconds),
- QuicTime::Delta::FromSeconds(idle_connection_timeout_seconds));
- config.SetConnectionOptionsToSend(connection_options);
- return config;
-}
-
-} // namespace
-
-// Responsible for creating a new QUIC session to the specified server, and
-// for notifying any associated requests when complete.
-class QuicStreamFactory::Job {
- public:
- Job(QuicStreamFactory* factory,
- HostResolver* host_resolver,
- const QuicSessionKey& key,
- bool was_alternative_service_recently_broken,
- int cert_verify_flags,
- QuicServerInfo* server_info,
- const BoundNetLog& net_log);
-
- // Creates a new job to handle the resumption of for connecting an
- // existing session.
- Job(QuicStreamFactory* factory,
- HostResolver* host_resolver,
- QuicChromiumClientSession* session,
- const QuicSessionKey& key);
-
- ~Job();
-
- int Run(const CompletionCallback& callback);
-
- int DoLoop(int rv);
- int DoResolveHost();
- int DoResolveHostComplete(int rv);
- int DoLoadServerInfo();
- int DoLoadServerInfoComplete(int rv);
- int DoConnect();
- int DoResumeConnect();
- int DoConnectComplete(int rv);
-
- void OnIOComplete(int rv);
-
- void RunAuxilaryJob();
-
- void Cancel();
-
- void CancelWaitForDataReadyCallback();
-
- const QuicSessionKey& key() const { return key_; }
-
- base::WeakPtr<Job> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
-
- private:
- enum IoState {
- STATE_NONE,
- STATE_RESOLVE_HOST,
- STATE_RESOLVE_HOST_COMPLETE,
- STATE_LOAD_SERVER_INFO,
- STATE_LOAD_SERVER_INFO_COMPLETE,
- STATE_CONNECT,
- STATE_RESUME_CONNECT,
- STATE_CONNECT_COMPLETE,
- };
- IoState io_state_;
-
- QuicStreamFactory* factory_;
- SingleRequestHostResolver host_resolver_;
- QuicSessionKey key_;
- int cert_verify_flags_;
- bool was_alternative_service_recently_broken_;
- std::unique_ptr<QuicServerInfo> server_info_;
- bool started_another_job_;
- const BoundNetLog net_log_;
- int num_sent_client_hellos_;
- QuicChromiumClientSession* session_;
- CompletionCallback callback_;
- AddressList address_list_;
- base::TimeTicks dns_resolution_start_time_;
- base::TimeTicks dns_resolution_end_time_;
- base::WeakPtrFactory<Job> weak_factory_;
- DISALLOW_COPY_AND_ASSIGN(Job);
-};
-
-QuicStreamFactory::Job::Job(QuicStreamFactory* factory,
- HostResolver* host_resolver,
- const QuicSessionKey& key,
- bool was_alternative_service_recently_broken,
- int cert_verify_flags,
- QuicServerInfo* server_info,
- const BoundNetLog& net_log)
- : io_state_(STATE_RESOLVE_HOST),
- factory_(factory),
- host_resolver_(host_resolver),
- key_(key),
- cert_verify_flags_(cert_verify_flags),
- was_alternative_service_recently_broken_(
- was_alternative_service_recently_broken),
- server_info_(server_info),
- started_another_job_(false),
- net_log_(net_log),
- num_sent_client_hellos_(0),
- session_(nullptr),
- weak_factory_(this) {}
-
-QuicStreamFactory::Job::Job(QuicStreamFactory* factory,
- HostResolver* host_resolver,
- QuicChromiumClientSession* session,
- const QuicSessionKey& key)
- : io_state_(STATE_RESUME_CONNECT),
- factory_(factory),
- host_resolver_(host_resolver), // unused
- key_(key),
- cert_verify_flags_(0), // unused
- was_alternative_service_recently_broken_(false), // unused
- started_another_job_(false), // unused
- net_log_(session->net_log()), // unused
- num_sent_client_hellos_(0),
- session_(session),
- weak_factory_(this) {}
-
-QuicStreamFactory::Job::~Job() {
- // If disk cache has a pending WaitForDataReadyCallback, cancel that callback.
- if (server_info_)
- server_info_->ResetWaitForDataReadyCallback();
-}
-
-int QuicStreamFactory::Job::Run(const CompletionCallback& callback) {
- int rv = DoLoop(OK);
- if (rv == ERR_IO_PENDING)
- callback_ = callback;
-
- return rv > 0 ? OK : rv;
-}
-
-int QuicStreamFactory::Job::DoLoop(int rv) {
- TRACE_EVENT0("net", "QuicStreamFactory::Job::DoLoop");
- do {
- IoState state = io_state_;
- io_state_ = STATE_NONE;
- switch (state) {
- case STATE_RESOLVE_HOST:
- CHECK_EQ(OK, rv);
- rv = DoResolveHost();
- break;
- case STATE_RESOLVE_HOST_COMPLETE:
- rv = DoResolveHostComplete(rv);
- break;
- case STATE_LOAD_SERVER_INFO:
- CHECK_EQ(OK, rv);
- rv = DoLoadServerInfo();
- break;
- case STATE_LOAD_SERVER_INFO_COMPLETE:
- rv = DoLoadServerInfoComplete(rv);
- break;
- case STATE_CONNECT:
- CHECK_EQ(OK, rv);
- rv = DoConnect();
- break;
- case STATE_RESUME_CONNECT:
- CHECK_EQ(OK, rv);
- rv = DoResumeConnect();
- break;
- case STATE_CONNECT_COMPLETE:
- rv = DoConnectComplete(rv);
- break;
- default:
- NOTREACHED() << "io_state_: " << io_state_;
- break;
- }
- } while (io_state_ != STATE_NONE && rv != ERR_IO_PENDING);
- return rv;
-}
-
-void QuicStreamFactory::Job::OnIOComplete(int rv) {
- rv = DoLoop(rv);
- if (rv != ERR_IO_PENDING && !callback_.is_null()) {
- callback_.Run(rv);
- }
-}
-
-void QuicStreamFactory::Job::RunAuxilaryJob() {
- int rv = Run(base::Bind(&QuicStreamFactory::OnJobComplete,
- base::Unretained(factory_), this));
- if (rv != ERR_IO_PENDING)
- factory_->OnJobComplete(this, rv);
-}
-
-void QuicStreamFactory::Job::Cancel() {
- callback_.Reset();
- if (session_)
- session_->connection()->CloseConnection(
- QUIC_CONNECTION_CANCELLED, "New job canceled.",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-}
-
-void QuicStreamFactory::Job::CancelWaitForDataReadyCallback() {
- // If we are waiting for WaitForDataReadyCallback, then cancel the callback.
- if (io_state_ != STATE_LOAD_SERVER_INFO_COMPLETE)
- return;
- server_info_->CancelWaitForDataReadyCallback();
- OnIOComplete(OK);
-}
-
-int QuicStreamFactory::Job::DoResolveHost() {
- // Start loading the data now, and wait for it after we resolve the host.
- if (server_info_) {
- server_info_->Start();
- }
-
- io_state_ = STATE_RESOLVE_HOST_COMPLETE;
- dns_resolution_start_time_ = base::TimeTicks::Now();
- return host_resolver_.Resolve(
- HostResolver::RequestInfo(key_.destination()), DEFAULT_PRIORITY,
- &address_list_,
- base::Bind(&QuicStreamFactory::Job::OnIOComplete, GetWeakPtr()),
- net_log_);
-}
-
-int QuicStreamFactory::Job::DoResolveHostComplete(int rv) {
- dns_resolution_end_time_ = base::TimeTicks::Now();
- UMA_HISTOGRAM_TIMES("Net.QuicSession.HostResolutionTime",
- dns_resolution_end_time_ - dns_resolution_start_time_);
- if (rv != OK)
- return rv;
-
- DCHECK(!factory_->HasActiveSession(key_.server_id()));
-
- // Inform the factory of this resolution, which will set up
- // a session alias, if possible.
- if (factory_->OnResolution(key_, address_list_)) {
- return OK;
- }
-
- if (server_info_)
- io_state_ = STATE_LOAD_SERVER_INFO;
- else
- io_state_ = STATE_CONNECT;
- return OK;
-}
-
-int QuicStreamFactory::Job::DoLoadServerInfo() {
- io_state_ = STATE_LOAD_SERVER_INFO_COMPLETE;
-
- DCHECK(server_info_);
-
- // To mitigate the effects of disk cache taking too long to load QUIC server
- // information, set up a timer to cancel WaitForDataReady's callback.
- if (factory_->load_server_info_timeout_srtt_multiplier_ > 0) {
- const int kMaxLoadServerInfoTimeoutMs = 50;
- // Wait for DiskCache a maximum of 50ms.
- int64_t load_server_info_timeout_ms =
- std::min(static_cast<int>(
- (factory_->load_server_info_timeout_srtt_multiplier_ *
- factory_->GetServerNetworkStatsSmoothedRttInMicroseconds(
- key_.server_id())) /
- 1000),
- kMaxLoadServerInfoTimeoutMs);
- if (load_server_info_timeout_ms > 0) {
- factory_->task_runner_->PostDelayedTask(
- FROM_HERE,
- base::Bind(&QuicStreamFactory::Job::CancelWaitForDataReadyCallback,
- GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(load_server_info_timeout_ms));
- }
- }
-
- int rv = server_info_->WaitForDataReady(
- base::Bind(&QuicStreamFactory::Job::OnIOComplete, GetWeakPtr()));
- if (rv == ERR_IO_PENDING && factory_->enable_connection_racing()) {
- // If we are waiting to load server config from the disk cache, then start
- // another job.
- started_another_job_ = true;
- factory_->CreateAuxilaryJob(key_, cert_verify_flags_, net_log_);
- }
- return rv;
-}
-
-int QuicStreamFactory::Job::DoLoadServerInfoComplete(int rv) {
- UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheWaitForDataReadyTime",
- base::TimeTicks::Now() - dns_resolution_end_time_);
-
- if (rv != OK)
- server_info_.reset();
-
- if (started_another_job_ &&
- (!server_info_ || server_info_->state().server_config.empty() ||
- !factory_->CryptoConfigCacheIsEmpty(key_.server_id()))) {
- // If we have started another job and if we didn't load the server config
- // from the disk cache or if we have received a new server config from the
- // server, then cancel the current job.
- io_state_ = STATE_NONE;
- return ERR_CONNECTION_CLOSED;
- }
-
- io_state_ = STATE_CONNECT;
- return OK;
-}
-
-int QuicStreamFactory::Job::DoConnect() {
- io_state_ = STATE_CONNECT_COMPLETE;
-
- int rv = factory_->CreateSession(
- key_, cert_verify_flags_, std::move(server_info_), address_list_,
- dns_resolution_end_time_, net_log_, &session_);
- if (rv != OK) {
- DCHECK(rv != ERR_IO_PENDING);
- DCHECK(!session_);
- return rv;
- }
-
- if (!session_->connection()->connected()) {
- return ERR_CONNECTION_CLOSED;
- }
-
- session_->StartReading();
- if (!session_->connection()->connected()) {
- return ERR_QUIC_PROTOCOL_ERROR;
- }
- bool require_confirmation = factory_->require_confirmation() ||
- was_alternative_service_recently_broken_;
-
- rv = session_->CryptoConnect(
- require_confirmation,
- base::Bind(&QuicStreamFactory::Job::OnIOComplete, GetWeakPtr()));
-
- if (!session_->connection()->connected() &&
- session_->error() == QUIC_PROOF_INVALID)
- return ERR_QUIC_HANDSHAKE_FAILED;
-
- return rv;
-}
-
-int QuicStreamFactory::Job::DoResumeConnect() {
- io_state_ = STATE_CONNECT_COMPLETE;
-
- int rv = session_->ResumeCryptoConnect(
- base::Bind(&QuicStreamFactory::Job::OnIOComplete, GetWeakPtr()));
-
- return rv;
-}
-
-int QuicStreamFactory::Job::DoConnectComplete(int rv) {
- if (session_ && session_->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- num_sent_client_hellos_ += session_->GetNumSentClientHellos();
- if (num_sent_client_hellos_ >= QuicCryptoClientStream::kMaxClientHellos) {
- return ERR_QUIC_HANDSHAKE_FAILED;
- }
- // The handshake was rejected statelessly, so create another connection
- // to resume the handshake.
- io_state_ = STATE_CONNECT;
- return OK;
- }
-
- if (rv != OK)
- return rv;
-
- DCHECK(!factory_->HasActiveSession(key_.server_id()));
- // There may well now be an active session for this IP. If so, use the
- // existing session instead.
- AddressList address(session_->connection()->peer_address());
- if (factory_->OnResolution(key_, address)) {
- session_->connection()->CloseConnection(
- QUIC_CONNECTION_IP_POOLED, "An active session exists for the given IP.",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- session_ = nullptr;
- return OK;
- }
-
- factory_->ActivateSession(key_, session_);
-
- return OK;
-}
-
-QuicStreamRequest::QuicStreamRequest(QuicStreamFactory* factory)
- : factory_(factory) {}
-
-QuicStreamRequest::~QuicStreamRequest() {
- if (factory_ && !callback_.is_null())
- factory_->CancelRequest(this);
-}
-
-int QuicStreamRequest::Request(const HostPortPair& destination,
- PrivacyMode privacy_mode,
- int cert_verify_flags,
- const GURL& url,
- base::StringPiece method,
- const BoundNetLog& net_log,
- const CompletionCallback& callback) {
- DCHECK(callback_.is_null());
- DCHECK(factory_);
- server_id_ = QuicServerId(HostPortPair::FromURL(url), privacy_mode);
-
- int rv = factory_->Create(server_id_, destination, cert_verify_flags, url,
- method, net_log, this);
- if (rv == ERR_IO_PENDING) {
- net_log_ = net_log;
- callback_ = callback;
- } else {
- factory_ = nullptr;
- }
- if (rv == OK)
- DCHECK(session_);
- return rv;
-}
-
-void QuicStreamRequest::SetSession(QuicChromiumClientSession* session) {
- DCHECK(session);
- session_ = session->GetWeakPtr();
-}
-
-void QuicStreamRequest::OnRequestComplete(int rv) {
- factory_ = nullptr;
- callback_.Run(rv);
-}
-
-base::TimeDelta QuicStreamRequest::GetTimeDelayForWaitingJob() const {
- if (!factory_)
- return base::TimeDelta();
- return factory_->GetTimeDelayForWaitingJob(server_id_);
-}
-
-std::unique_ptr<QuicHttpStream> QuicStreamRequest::CreateStream() {
- if (!session_)
- return nullptr;
- return base::WrapUnique(new QuicHttpStream(session_));
-}
-
-std::unique_ptr<BidirectionalStreamImpl>
-QuicStreamRequest::CreateBidirectionalStreamImpl() {
- if (!session_)
- return nullptr;
- return base::WrapUnique(new BidirectionalStreamQuicImpl(session_));
-}
-
-QuicStreamFactory::QuicStreamFactory(
- NetLog* net_log,
- HostResolver* host_resolver,
- SSLConfigService* ssl_config_service,
- ClientSocketFactory* client_socket_factory,
- HttpServerProperties* http_server_properties,
- CertVerifier* cert_verifier,
- CTPolicyEnforcer* ct_policy_enforcer,
- ChannelIDService* channel_id_service,
- TransportSecurityState* transport_security_state,
- CTVerifier* cert_transparency_verifier,
- SocketPerformanceWatcherFactory* socket_performance_watcher_factory,
- QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory,
- QuicRandom* random_generator,
- QuicClock* clock,
- size_t max_packet_length,
- const std::string& user_agent_id,
- const QuicVersionVector& supported_versions,
- bool enable_port_selection,
- bool always_require_handshake_confirmation,
- bool disable_connection_pooling,
- float load_server_info_timeout_srtt_multiplier,
- bool enable_connection_racing,
- bool enable_non_blocking_io,
- bool disable_disk_cache,
- bool prefer_aes,
- int max_number_of_lossy_connections,
- float packet_loss_threshold,
- int max_disabled_reasons,
- int threshold_public_resets_post_handshake,
- int threshold_timeouts_with_open_streams,
- int socket_receive_buffer_size,
- bool delay_tcp_race,
- int max_server_configs_stored_in_properties,
- bool close_sessions_on_ip_change,
- bool disable_quic_on_timeout_with_open_streams,
- int idle_connection_timeout_seconds,
- bool migrate_sessions_on_network_change,
- bool migrate_sessions_early,
- const QuicTagVector& connection_options,
- bool enable_token_binding)
- : require_confirmation_(true),
- net_log_(net_log),
- host_resolver_(host_resolver),
- client_socket_factory_(client_socket_factory),
- http_server_properties_(http_server_properties),
- transport_security_state_(transport_security_state),
- cert_transparency_verifier_(cert_transparency_verifier),
- quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory),
- random_generator_(random_generator),
- clock_(clock),
- max_packet_length_(max_packet_length),
- socket_performance_watcher_factory_(socket_performance_watcher_factory),
- config_(InitializeQuicConfig(connection_options,
- idle_connection_timeout_seconds)),
- crypto_config_(new ProofVerifierChromium(cert_verifier,
- ct_policy_enforcer,
- transport_security_state,
- cert_transparency_verifier)),
- supported_versions_(supported_versions),
- enable_port_selection_(enable_port_selection),
- always_require_handshake_confirmation_(
- always_require_handshake_confirmation),
- disable_connection_pooling_(disable_connection_pooling),
- load_server_info_timeout_srtt_multiplier_(
- load_server_info_timeout_srtt_multiplier),
- enable_connection_racing_(enable_connection_racing),
- enable_non_blocking_io_(enable_non_blocking_io),
- disable_disk_cache_(disable_disk_cache),
- prefer_aes_(prefer_aes),
- max_number_of_lossy_connections_(max_number_of_lossy_connections),
- packet_loss_threshold_(packet_loss_threshold),
- max_disabled_reasons_(max_disabled_reasons),
- num_public_resets_post_handshake_(0),
- num_timeouts_with_open_streams_(0),
- max_public_resets_post_handshake_(0),
- max_timeouts_with_open_streams_(0),
- threshold_timeouts_with_open_streams_(
- threshold_timeouts_with_open_streams),
- threshold_public_resets_post_handshake_(
- threshold_public_resets_post_handshake),
- socket_receive_buffer_size_(socket_receive_buffer_size),
- delay_tcp_race_(delay_tcp_race),
- yield_after_packets_(kQuicYieldAfterPacketsRead),
- yield_after_duration_(QuicTime::Delta::FromMilliseconds(
- kQuicYieldAfterDurationMilliseconds)),
- close_sessions_on_ip_change_(close_sessions_on_ip_change),
- migrate_sessions_on_network_change_(
- migrate_sessions_on_network_change &&
- NetworkChangeNotifier::AreNetworkHandlesSupported()),
- migrate_sessions_early_(migrate_sessions_early &&
- migrate_sessions_on_network_change_),
- port_seed_(random_generator_->RandUint64()),
- check_persisted_supports_quic_(true),
- has_initialized_data_(false),
- num_push_streams_created_(0),
- status_(OPEN),
- task_runner_(nullptr),
- ssl_config_service_(ssl_config_service),
- weak_factory_(this) {
- if (ssl_config_service_.get())
- ssl_config_service_->AddObserver(this);
- if (disable_quic_on_timeout_with_open_streams)
- threshold_timeouts_with_open_streams_ = 1;
- DCHECK(transport_security_state_);
- DCHECK(http_server_properties_);
- crypto_config_.set_user_agent_id(user_agent_id);
- crypto_config_.AddCanonicalSuffix(".c.youtube.com");
- crypto_config_.AddCanonicalSuffix(".ggpht.com");
- crypto_config_.AddCanonicalSuffix(".googlevideo.com");
- crypto_config_.AddCanonicalSuffix(".googleusercontent.com");
- // TODO(rtenneti): http://crbug.com/487355. Temporary fix for b/20760730 until
- // channel_id_service is supported in cronet.
- if (channel_id_service) {
- crypto_config_.SetChannelIDSource(
- new ChannelIDSourceChromium(channel_id_service));
- }
- if (enable_token_binding && channel_id_service)
- crypto_config_.tb_key_params.push_back(kP256);
- crypto::EnsureOpenSSLInit();
- bool has_aes_hardware_support = !!EVP_has_aes_hardware();
- UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.PreferAesGcm",
- has_aes_hardware_support);
- if (has_aes_hardware_support || prefer_aes_)
- crypto_config_.PreferAesGcm();
- // When disk cache is used to store the server configs, HttpCache code calls
- // |set_quic_server_info_factory| if |quic_server_info_factory_| wasn't
- // created.
- if (max_server_configs_stored_in_properties > 0) {
- quic_server_info_factory_.reset(
- new PropertiesBasedQuicServerInfoFactory(http_server_properties_));
- }
-
- // migrate_sessions_early should only be set to true if
- // migrate_sessions_on_network_change is set to true.
- if (migrate_sessions_early)
- DCHECK(migrate_sessions_on_network_change);
- // close_sessions_on_ip_change and migrate_sessions_on_network_change should
- // never be simultaneously set to true.
- DCHECK(!(close_sessions_on_ip_change && migrate_sessions_on_network_change));
-
- if (migrate_sessions_on_network_change_) {
- NetworkChangeNotifier::AddNetworkObserver(this);
- } else if (close_sessions_on_ip_change_) {
- NetworkChangeNotifier::AddIPAddressObserver(this);
- }
-}
-
-QuicStreamFactory::~QuicStreamFactory() {
- CloseAllSessions(ERR_ABORTED, QUIC_CONNECTION_CANCELLED);
- while (!all_sessions_.empty()) {
- delete all_sessions_.begin()->first;
- all_sessions_.erase(all_sessions_.begin());
- }
- while (!active_jobs_.empty()) {
- const QuicServerId server_id = active_jobs_.begin()->first;
- STLDeleteElements(&(active_jobs_[server_id]));
- active_jobs_.erase(server_id);
- }
- if (ssl_config_service_.get())
- ssl_config_service_->RemoveObserver(this);
- if (migrate_sessions_on_network_change_) {
- NetworkChangeNotifier::RemoveNetworkObserver(this);
- } else if (close_sessions_on_ip_change_) {
- NetworkChangeNotifier::RemoveIPAddressObserver(this);
- }
-}
-
-void QuicStreamFactory::set_require_confirmation(bool require_confirmation) {
- require_confirmation_ = require_confirmation;
- if (!(local_address_ == IPEndPoint())) {
- http_server_properties_->SetSupportsQuic(!require_confirmation,
- local_address_.address());
- }
-}
-
-bool QuicStreamFactory::ZeroRTTEnabledFor(const QuicServerId& quic_server_id) {
- return !(require_confirmation_ || CryptoConfigCacheIsEmpty(quic_server_id));
-}
-
-base::TimeDelta QuicStreamFactory::GetTimeDelayForWaitingJob(
- const QuicServerId& server_id) {
- if (!delay_tcp_race_ || require_confirmation_)
- return base::TimeDelta();
- int64_t srtt =
- 1.5 * GetServerNetworkStatsSmoothedRttInMicroseconds(server_id);
- // Picked 300ms based on mean time from
- // Net.QuicSession.HostResolution.HandshakeConfirmedTime histogram.
- const int kDefaultRTT = 300 * kNumMicrosPerMilli;
- if (!srtt)
- srtt = kDefaultRTT;
- return base::TimeDelta::FromMicroseconds(srtt);
-}
-
-void QuicStreamFactory::set_quic_server_info_factory(
- QuicServerInfoFactory* quic_server_info_factory) {
- quic_server_info_factory_.reset(quic_server_info_factory);
-}
-
-bool QuicStreamFactory::CanUseExistingSession(const QuicServerId& server_id,
- const HostPortPair& destination) {
- // TODO(zhongyi): delete active_sessions_.empty() checks once the
- // android crash issue(crbug.com/498823) is resolved.
- if (active_sessions_.empty())
- return false;
-
- if (ContainsKey(active_sessions_, server_id))
- return true;
-
- for (const auto& key_value : active_sessions_) {
- QuicChromiumClientSession* session = key_value.second;
- if (destination.Equals(all_sessions_[session].destination()) &&
- session->CanPool(server_id.host(), server_id.privacy_mode())) {
- return true;
- }
- }
-
- return false;
-}
-
-int QuicStreamFactory::Create(const QuicServerId& server_id,
- const HostPortPair& destination,
- int cert_verify_flags,
- const GURL& url,
- base::StringPiece method,
- const BoundNetLog& net_log,
- QuicStreamRequest* request) {
- DCHECK(server_id.host_port_pair().Equals(HostPortPair::FromURL(url)));
- // Enforce session affinity for promised streams.
- QuicClientPromisedInfo* promised =
- push_promise_index_.GetPromised(url.spec());
- if (promised) {
- QuicChromiumClientSession* session =
- static_cast<QuicChromiumClientSession*>(promised->session());
- DCHECK(session);
- if (session->server_id().privacy_mode() == server_id.privacy_mode()) {
- request->SetSession(session);
- ++num_push_streams_created_;
- return OK;
- }
- // This should happen extremely rarely (if ever), but if somehow a
- // request comes in with a mismatched privacy mode, consider the
- // promise borked.
- promised->Cancel();
- }
-
- // Use active session for |server_id| if such exists.
- // TODO(rtenneti): crbug.com/498823 - delete active_sessions_.empty() checks.
- if (!active_sessions_.empty()) {
- SessionMap::iterator it = active_sessions_.find(server_id);
- if (it != active_sessions_.end()) {
- QuicChromiumClientSession* session = it->second;
- request->SetSession(session);
- return OK;
- }
- }
-
- // Associate with active job to |server_id| if such exists.
- if (HasActiveJob(server_id)) {
- active_requests_[request] = server_id;
- job_requests_map_[server_id].insert(request);
- return ERR_IO_PENDING;
- }
-
- // Pool to active session to |destination| if possible.
- if (!active_sessions_.empty() && !disable_connection_pooling_) {
- for (const auto& key_value : active_sessions_) {
- QuicChromiumClientSession* session = key_value.second;
- if (destination.Equals(all_sessions_[session].destination()) &&
- session->CanPool(server_id.host(), server_id.privacy_mode())) {
- request->SetSession(session);
- return OK;
- }
- }
- }
-
- // TODO(rtenneti): |task_runner_| is used by the Job. Initialize task_runner_
- // in the constructor after WebRequestActionWithThreadsTest.* tests are fixed.
- if (!task_runner_)
- task_runner_ = base::ThreadTaskRunnerHandle::Get().get();
-
- QuicServerInfo* quic_server_info = nullptr;
- if (quic_server_info_factory_.get()) {
- bool load_from_disk_cache = !disable_disk_cache_;
- MaybeInitialize();
- if (!ContainsKey(quic_supported_servers_at_startup_, destination)) {
- // If there is no entry for QUIC, consider that as a new server and
- // don't wait for Cache thread to load the data for that server.
- load_from_disk_cache = false;
- }
- if (load_from_disk_cache && CryptoConfigCacheIsEmpty(server_id)) {
- quic_server_info = quic_server_info_factory_->GetForServer(server_id);
- }
- }
-
- QuicSessionKey key(destination, server_id);
- std::unique_ptr<Job> job(
- new Job(this, host_resolver_, key, WasQuicRecentlyBroken(server_id),
- cert_verify_flags, quic_server_info, net_log));
- int rv = job->Run(base::Bind(&QuicStreamFactory::OnJobComplete,
- base::Unretained(this), job.get()));
- if (rv == ERR_IO_PENDING) {
- active_requests_[request] = server_id;
- job_requests_map_[server_id].insert(request);
- active_jobs_[server_id].insert(job.release());
- return rv;
- }
- if (rv == OK) {
- // TODO(rtenneti): crbug.com/498823 - revert active_sessions_.empty()
- // related changes.
- if (active_sessions_.empty())
- return ERR_QUIC_PROTOCOL_ERROR;
- SessionMap::iterator it = active_sessions_.find(server_id);
- DCHECK(it != active_sessions_.end());
- if (it == active_sessions_.end())
- return ERR_QUIC_PROTOCOL_ERROR;
- QuicChromiumClientSession* session = it->second;
- request->SetSession(session);
- }
- return rv;
-}
-
-QuicStreamFactory::QuicSessionKey::QuicSessionKey(
- const HostPortPair& destination,
- const QuicServerId& server_id)
- : destination_(destination), server_id_(server_id) {}
-
-bool QuicStreamFactory::QuicSessionKey::operator<(
- const QuicSessionKey& other) const {
- return std::tie(destination_, server_id_) <
- std::tie(other.destination_, other.server_id_);
-}
-
-bool QuicStreamFactory::QuicSessionKey::operator==(
- const QuicSessionKey& other) const {
- return destination_.Equals(other.destination_) &&
- server_id_ == other.server_id_;
-}
-
-void QuicStreamFactory::CreateAuxilaryJob(const QuicSessionKey& key,
- int cert_verify_flags,
- const BoundNetLog& net_log) {
- Job* aux_job =
- new Job(this, host_resolver_, key, WasQuicRecentlyBroken(key.server_id()),
- cert_verify_flags, nullptr, net_log);
- active_jobs_[key.server_id()].insert(aux_job);
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&QuicStreamFactory::Job::RunAuxilaryJob,
- aux_job->GetWeakPtr()));
-}
-
-bool QuicStreamFactory::OnResolution(const QuicSessionKey& key,
- const AddressList& address_list) {
- const QuicServerId& server_id(key.server_id());
- DCHECK(!HasActiveSession(server_id));
- if (disable_connection_pooling_) {
- return false;
- }
- for (const IPEndPoint& address : address_list) {
- if (!ContainsKey(ip_aliases_, address))
- continue;
-
- const SessionSet& sessions = ip_aliases_[address];
- for (QuicChromiumClientSession* session : sessions) {
- if (!session->CanPool(server_id.host(), server_id.privacy_mode()))
- continue;
- active_sessions_[server_id] = session;
- session_aliases_[session].insert(key);
- return true;
- }
- }
- return false;
-}
-
-void QuicStreamFactory::OnJobComplete(Job* job, int rv) {
- // Copy |server_id|, because |job| might be destroyed before this method
- // returns.
- const QuicServerId server_id(job->key().server_id());
- if (rv != OK) {
- JobSet* jobs = &(active_jobs_[server_id]);
- if (jobs->size() > 1) {
- // If there is another pending job, then we can delete this job and let
- // the other job handle the request.
- job->Cancel();
- jobs->erase(job);
- delete job;
- return;
- }
- }
-
- if (rv == OK) {
- if (!always_require_handshake_confirmation_)
- set_require_confirmation(false);
-
- if (!job_requests_map_[server_id].empty()) {
- SessionMap::iterator session_it = active_sessions_.find(server_id);
- DCHECK(session_it != active_sessions_.end());
- QuicChromiumClientSession* session = session_it->second;
- for (QuicStreamRequest* request : job_requests_map_[server_id]) {
- DCHECK(request->server_id() == server_id);
- // Do not notify |request| yet.
- request->SetSession(session);
- }
- }
- }
-
- while (!job_requests_map_[server_id].empty()) {
- RequestSet::iterator it = job_requests_map_[server_id].begin();
- QuicStreamRequest* request = *it;
- job_requests_map_[server_id].erase(it);
- active_requests_.erase(request);
- // Even though we're invoking callbacks here, we don't need to worry
- // about |this| being deleted, because the factory is owned by the
- // profile which can not be deleted via callbacks.
- request->OnRequestComplete(rv);
- }
-
- for (Job* other_job : active_jobs_[server_id]) {
- if (other_job != job)
- other_job->Cancel();
- }
-
- STLDeleteElements(&(active_jobs_[server_id]));
- active_jobs_.erase(server_id);
- job_requests_map_.erase(server_id);
-}
-
-std::unique_ptr<QuicHttpStream> QuicStreamFactory::CreateFromSession(
- QuicChromiumClientSession* session) {
- return std::unique_ptr<QuicHttpStream>(
- new QuicHttpStream(session->GetWeakPtr()));
-}
-
-QuicChromiumClientSession::QuicDisabledReason
-QuicStreamFactory::QuicDisabledReason(uint16_t port) const {
- if (max_number_of_lossy_connections_ > 0 &&
- number_of_lossy_connections_.find(port) !=
- number_of_lossy_connections_.end() &&
- number_of_lossy_connections_.at(port) >=
- max_number_of_lossy_connections_) {
- return QuicChromiumClientSession::QUIC_DISABLED_BAD_PACKET_LOSS_RATE;
- }
- if (threshold_public_resets_post_handshake_ > 0 &&
- num_public_resets_post_handshake_ >=
- threshold_public_resets_post_handshake_) {
- return QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE;
- }
- if (threshold_timeouts_with_open_streams_ > 0 &&
- num_timeouts_with_open_streams_ >=
- threshold_timeouts_with_open_streams_) {
- return QuicChromiumClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS;
- }
- return QuicChromiumClientSession::QUIC_DISABLED_NOT;
-}
-
-const char* QuicStreamFactory::QuicDisabledReasonString() const {
- // TODO(ckrasic) - better solution for port/lossy connections?
- const uint16_t port = 443;
- switch (QuicDisabledReason(port)) {
- case QuicChromiumClientSession::QUIC_DISABLED_BAD_PACKET_LOSS_RATE:
- return "Bad packet loss rate.";
- case QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE:
- return "Public resets after successful handshakes.";
- case QuicChromiumClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS:
- return "Connection timeouts with streams open.";
- default:
- return "";
- }
-}
-
-bool QuicStreamFactory::IsQuicDisabled(uint16_t port) const {
- return status_ != OPEN;
-}
-
-bool QuicStreamFactory::OnHandshakeConfirmed(QuicChromiumClientSession* session,
- float packet_loss_rate) {
- DCHECK(session);
- uint16_t port = session->server_id().port();
- if (packet_loss_rate < packet_loss_threshold_) {
- number_of_lossy_connections_[port] = 0;
- return false;
- }
-
- // We mark it as recently broken, which means that 0-RTT will be disabled
- // but we'll still race.
- http_server_properties_->MarkAlternativeServiceRecentlyBroken(
- AlternativeService(QUIC, session->server_id().host(), port));
-
- bool was_quic_disabled = IsQuicDisabled(port);
- ++number_of_lossy_connections_[port];
-
- // Collect data for port 443 for packet loss events.
- if (port == 443 && max_number_of_lossy_connections_ > 0) {
- UMA_HISTOGRAM_SPARSE_SLOWLY(
- base::StringPrintf("Net.QuicStreamFactory.BadPacketLossEvents%d",
- max_number_of_lossy_connections_),
- std::min(number_of_lossy_connections_[port],
- max_number_of_lossy_connections_));
- }
-
- MaybeDisableQuic(port);
-
- bool is_quic_disabled = IsQuicDisabled(port);
- if (is_quic_disabled) {
- // Close QUIC connection if Quic is disabled for this port.
- session->CloseSessionOnErrorAndNotifyFactoryLater(
- ERR_ABORTED, QUIC_BAD_PACKET_LOSS_RATE);
-
- // If this bad packet loss rate disabled the QUIC, then record it.
- if (!was_quic_disabled)
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicStreamFactory.QuicIsDisabled", port);
- }
- return is_quic_disabled;
-}
-
-void QuicStreamFactory::OnTcpJobCompleted(bool succeeded) {
- if (status_ != CLOSED)
- return;
-
- // If QUIC connections are failing while TCP connections are working,
- // then stop using QUIC. On the other hand if both QUIC and TCP are
- // failing, then attempt to use QUIC again.
- if (succeeded) {
- status_ = DISABLED;
- return;
- }
-
- status_ = OPEN;
- num_timeouts_with_open_streams_ = 0;
-}
-
-void QuicStreamFactory::OnIdleSession(QuicChromiumClientSession* session) {}
-
-void QuicStreamFactory::OnSessionGoingAway(QuicChromiumClientSession* session) {
- const AliasSet& aliases = session_aliases_[session];
- for (AliasSet::const_iterator it = aliases.begin(); it != aliases.end();
- ++it) {
- const QuicServerId& server_id = it->server_id();
- DCHECK(active_sessions_.count(server_id));
- DCHECK_EQ(session, active_sessions_[server_id]);
- // Track sessions which have recently gone away so that we can disable
- // port suggestions.
- if (session->goaway_received()) {
- gone_away_aliases_.insert(*it);
- }
-
- active_sessions_.erase(server_id);
- ProcessGoingAwaySession(session, server_id, true);
- }
- ProcessGoingAwaySession(session, all_sessions_[session].server_id(), false);
- if (!aliases.empty()) {
- const IPEndPoint peer_address = session->connection()->peer_address();
- ip_aliases_[peer_address].erase(session);
- if (ip_aliases_[peer_address].empty()) {
- ip_aliases_.erase(peer_address);
- }
- }
- session_aliases_.erase(session);
-}
-
-void QuicStreamFactory::MaybeDisableQuic(QuicChromiumClientSession* session) {
- DCHECK(session);
- uint16_t port = session->server_id().port();
- if (IsQuicDisabled(port))
- return;
-
- // Expire the oldest disabled_reason if appropriate. This enforces that we
- // only consider the max_disabled_reasons_ most recent sessions.
- QuicChromiumClientSession::QuicDisabledReason disabled_reason;
- if (static_cast<int>(disabled_reasons_.size()) == max_disabled_reasons_) {
- disabled_reason = disabled_reasons_.front();
- disabled_reasons_.pop_front();
- if (disabled_reason ==
- QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE) {
- --num_public_resets_post_handshake_;
- } else if (disabled_reason == QuicChromiumClientSession::
- QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS) {
- --num_timeouts_with_open_streams_;
- }
- }
- disabled_reason = session->disabled_reason();
- disabled_reasons_.push_back(disabled_reason);
- if (disabled_reason ==
- QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE) {
- ++num_public_resets_post_handshake_;
- } else if (disabled_reason == QuicChromiumClientSession::
- QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS) {
- ++num_timeouts_with_open_streams_;
- }
- if (num_timeouts_with_open_streams_ > max_timeouts_with_open_streams_) {
- max_timeouts_with_open_streams_ = num_timeouts_with_open_streams_;
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicStreamFactory.TimeoutsWithOpenStreams",
- num_timeouts_with_open_streams_, 0, 20, 10);
- }
-
- if (num_public_resets_post_handshake_ > max_public_resets_post_handshake_) {
- max_public_resets_post_handshake_ = num_public_resets_post_handshake_;
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Net.QuicStreamFactory.PublicResetsPostHandshake",
- num_public_resets_post_handshake_, 0, 20, 10);
- }
-
- MaybeDisableQuic(port);
- if (IsQuicDisabled(port)) {
- if (disabled_reason ==
- QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE) {
- session->CloseSessionOnErrorAndNotifyFactoryLater(
- ERR_ABORTED, QUIC_PUBLIC_RESETS_POST_HANDSHAKE);
- } else if (disabled_reason == QuicChromiumClientSession::
- QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS) {
- session->CloseSessionOnErrorAndNotifyFactoryLater(
- ERR_ABORTED, QUIC_TIMEOUTS_WITH_OPEN_STREAMS);
- }
- UMA_HISTOGRAM_ENUMERATION("Net.QuicStreamFactory.DisabledReasons",
- disabled_reason,
- QuicChromiumClientSession::QUIC_DISABLED_MAX);
- }
-}
-
-void QuicStreamFactory::MaybeDisableQuic(uint16_t port) {
- if (status_ == DISABLED)
- return;
-
- QuicChromiumClientSession::QuicDisabledReason disabled_reason =
- QuicDisabledReason(port);
- if (disabled_reason == QuicChromiumClientSession::QUIC_DISABLED_NOT) {
- DCHECK_EQ(OPEN, status_);
- return;
- }
-
- if (disabled_reason ==
- QuicChromiumClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS) {
- // When QUIC there are too many timeouts with open stream, the factory
- // should be closed. When TCP jobs complete, they will move the factory
- // to either fully disabled or back to open.
- status_ = CLOSED;
- DCHECK(IsQuicDisabled(port));
- DCHECK_NE(QuicChromiumClientSession::QuicDisabledReason(port),
- QuicChromiumClientSession::QUIC_DISABLED_NOT);
- return;
- }
-
- status_ = DISABLED;
- DCHECK(IsQuicDisabled(port));
- DCHECK_NE(QuicChromiumClientSession::QuicDisabledReason(port),
- QuicChromiumClientSession::QUIC_DISABLED_NOT);
-}
-
-void QuicStreamFactory::OnSessionClosed(QuicChromiumClientSession* session) {
- DCHECK_EQ(0u, session->GetNumActiveStreams());
- MaybeDisableQuic(session);
- OnSessionGoingAway(session);
- delete session;
- all_sessions_.erase(session);
-}
-
-void QuicStreamFactory::OnSessionConnectTimeout(
- QuicChromiumClientSession* session) {
- const AliasSet& aliases = session_aliases_[session];
-
- if (aliases.empty()) {
- return;
- }
-
- for (const QuicSessionKey& key : aliases) {
- const QuicServerId& server_id = key.server_id();
- SessionMap::iterator session_it = active_sessions_.find(server_id);
- DCHECK(session_it != active_sessions_.end());
- DCHECK_EQ(session, session_it->second);
- active_sessions_.erase(session_it);
- }
-
- const IPEndPoint peer_address = session->connection()->peer_address();
- ip_aliases_[peer_address].erase(session);
- if (ip_aliases_[peer_address].empty()) {
- ip_aliases_.erase(peer_address);
- }
- QuicSessionKey key = *aliases.begin();
- session_aliases_.erase(session);
- Job* job = new Job(this, host_resolver_, session, key);
- active_jobs_[key.server_id()].insert(job);
- int rv = job->Run(base::Bind(&QuicStreamFactory::OnJobComplete,
- base::Unretained(this), job));
- DCHECK_EQ(ERR_IO_PENDING, rv);
-}
-
-void QuicStreamFactory::CancelRequest(QuicStreamRequest* request) {
- RequestMap::iterator request_it = active_requests_.find(request);
- DCHECK(request_it != active_requests_.end());
- const QuicServerId& server_id = request_it->second;
- job_requests_map_[server_id].erase(request);
- active_requests_.erase(request_it);
-}
-
-void QuicStreamFactory::CloseAllSessions(int error, QuicErrorCode quic_error) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.CloseAllSessionsError", -error);
- while (!active_sessions_.empty()) {
- size_t initial_size = active_sessions_.size();
- active_sessions_.begin()->second->CloseSessionOnError(error, quic_error);
- DCHECK_NE(initial_size, active_sessions_.size());
- }
- while (!all_sessions_.empty()) {
- size_t initial_size = all_sessions_.size();
- all_sessions_.begin()->first->CloseSessionOnError(error, quic_error);
- DCHECK_NE(initial_size, all_sessions_.size());
- }
- DCHECK(all_sessions_.empty());
-}
-
-std::unique_ptr<base::Value> QuicStreamFactory::QuicStreamFactoryInfoToValue()
- const {
- std::unique_ptr<base::ListValue> list(new base::ListValue());
-
- for (SessionMap::const_iterator it = active_sessions_.begin();
- it != active_sessions_.end(); ++it) {
- const QuicServerId& server_id = it->first;
- QuicChromiumClientSession* session = it->second;
- const AliasSet& aliases = session_aliases_.find(session)->second;
- // Only add a session to the list once.
- if (server_id == aliases.begin()->server_id()) {
- std::set<HostPortPair> hosts;
- for (AliasSet::const_iterator alias_it = aliases.begin();
- alias_it != aliases.end(); ++alias_it) {
- hosts.insert(alias_it->server_id().host_port_pair());
- }
- list->Append(session->GetInfoAsValue(hosts));
- }
- }
- return std::move(list);
-}
-
-void QuicStreamFactory::ClearCachedStatesInCryptoConfig() {
- crypto_config_.ClearCachedStates();
-}
-
-void QuicStreamFactory::OnIPAddressChanged() {
- num_timeouts_with_open_streams_ = 0;
- status_ = OPEN;
- CloseAllSessions(ERR_NETWORK_CHANGED, QUIC_IP_ADDRESS_CHANGED);
- set_require_confirmation(true);
-}
-
-void QuicStreamFactory::OnNetworkConnected(NetworkHandle network) {
- num_timeouts_with_open_streams_ = 0;
- status_ = OPEN;
-}
-
-void QuicStreamFactory::OnNetworkMadeDefault(NetworkHandle network) {}
-
-void QuicStreamFactory::OnNetworkDisconnected(NetworkHandle network) {
- ScopedConnectionMigrationEventLog scoped_event_log(net_log_,
- "OnNetworkDisconnected");
- MaybeMigrateOrCloseSessions(network, /*force_close=*/true,
- scoped_event_log.net_log());
- set_require_confirmation(true);
-}
-
-// This method is expected to only be called when migrating from Cellular to
-// WiFi on Android.
-void QuicStreamFactory::OnNetworkSoonToDisconnect(NetworkHandle network) {
- ScopedConnectionMigrationEventLog scoped_event_log(
- net_log_, "OnNetworkSoonToDisconnect");
- MaybeMigrateOrCloseSessions(network, /*force_close=*/false,
- scoped_event_log.net_log());
-}
-
-NetworkHandle QuicStreamFactory::FindAlternateNetwork(
- NetworkHandle old_network) {
- // Find a new network that sessions bound to |old_network| can be migrated to.
- NetworkChangeNotifier::NetworkList network_list;
- NetworkChangeNotifier::GetConnectedNetworks(&network_list);
- for (NetworkHandle new_network : network_list) {
- if (new_network != old_network) {
- return new_network;
- }
- }
- return NetworkChangeNotifier::kInvalidNetworkHandle;
-}
-
-void QuicStreamFactory::MaybeMigrateOrCloseSessions(
- NetworkHandle network,
- bool force_close,
- const BoundNetLog& bound_net_log) {
- DCHECK_NE(NetworkChangeNotifier::kInvalidNetworkHandle, network);
- NetworkHandle new_network = FindAlternateNetwork(network);
-
- QuicStreamFactory::SessionIdMap::iterator it = all_sessions_.begin();
- while (it != all_sessions_.end()) {
- QuicChromiumClientSession* session = it->first;
- ++it;
-
- if (session->GetDefaultSocket()->GetBoundNetwork() != network) {
- // If session is not bound to |network|, move on.
- HistogramAndLogMigrationFailure(
- bound_net_log, MIGRATION_STATUS_ALREADY_MIGRATED,
- session->connection_id(), "Not bound to network");
- continue;
- }
- if (session->GetNumActiveStreams() == 0) {
- // Close idle sessions.
- HistogramAndLogMigrationFailure(
- bound_net_log, MIGRATION_STATUS_NO_MIGRATABLE_STREAMS,
- session->connection_id(), "No active sessions");
- session->CloseSessionOnError(
- ERR_NETWORK_CHANGED, QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS);
- continue;
- }
- // If session has active streams, mark it as going away.
- OnSessionGoingAway(session);
-
- if (new_network == NetworkChangeNotifier::kInvalidNetworkHandle) {
- // No new network was found.
- // TODO (jri): Add histogram for this failure case.
- bound_net_log.AddEvent(
- NetLog::TYPE_QUIC_CONNECTION_MIGRATION_FAILURE,
- base::Bind(&NetLogQuicConnectionMigrationFailureCallback,
- session->connection_id(), "No new network"));
- if (force_close) {
- session->CloseSessionOnError(ERR_NETWORK_CHANGED,
- QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK);
- }
- continue;
- }
- if (session->config()->DisableConnectionMigration()) {
- // Do not migrate sessions where connection migration is disabled by
- // config.
- HistogramAndLogMigrationFailure(bound_net_log, MIGRATION_STATUS_DISABLED,
- session->connection_id(),
- "Migration disabled");
- if (force_close) {
- // Close sessions where connection migration is disabled.
- session->CloseSessionOnError(ERR_NETWORK_CHANGED,
- QUIC_IP_ADDRESS_CHANGED);
- }
- continue;
- }
- if (session->HasNonMigratableStreams()) {
- // Do not migrate sessions with non-migratable streams.
- HistogramAndLogMigrationFailure(
- bound_net_log, MIGRATION_STATUS_NON_MIGRATABLE_STREAM,
- session->connection_id(), "Non-migratable stream");
- if (force_close) {
- // Close sessions with non-migratable streams.
- session->CloseSessionOnError(
- ERR_NETWORK_CHANGED,
- QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM);
- }
- continue;
- }
-
- MigrateSessionToNetwork(session, new_network, bound_net_log);
- }
-}
-
-void QuicStreamFactory::MaybeMigrateSessionEarly(
- QuicChromiumClientSession* session) {
- ScopedConnectionMigrationEventLog scoped_event_log(net_log_,
- "EarlyMigration");
- if (!migrate_sessions_early_ || session->HasNonMigratableStreams() ||
- session->config()->DisableConnectionMigration()) {
- HistogramAndLogMigrationFailure(
- scoped_event_log.net_log(), MIGRATION_STATUS_DISABLED,
- session->connection_id(), "Early migration disabled");
- return;
- }
- NetworkHandle new_network =
- FindAlternateNetwork(session->GetDefaultSocket()->GetBoundNetwork());
- if (new_network == NetworkChangeNotifier::kInvalidNetworkHandle) {
- // No alternate network found.
- // TODO (jri): Add histogram for this failure case.
- scoped_event_log.net_log().AddEvent(
- NetLog::TYPE_QUIC_CONNECTION_MIGRATION_FAILURE,
- base::Bind(&NetLogQuicConnectionMigrationFailureCallback,
- session->connection_id(), "No new network"));
- return;
- }
- OnSessionGoingAway(session);
- MigrateSessionToNetwork(session, new_network, scoped_event_log.net_log());
-}
-
-void QuicStreamFactory::MigrateSessionToNetwork(
- QuicChromiumClientSession* session,
- NetworkHandle new_network,
- const BoundNetLog& bound_net_log) {
- // Use OS-specified port for socket (DEFAULT_BIND) instead of
- // using the PortSuggester since the connection is being migrated
- // and not being newly created.
- std::unique_ptr<DatagramClientSocket> socket(
- client_socket_factory_->CreateDatagramClientSocket(
- DatagramSocket::DEFAULT_BIND, RandIntCallback(),
- session->net_log().net_log(), session->net_log().source()));
- QuicConnection* connection = session->connection();
- if (ConfigureSocket(socket.get(), connection->peer_address(), new_network) !=
- OK) {
- session->CloseSessionOnError(ERR_NETWORK_CHANGED, QUIC_INTERNAL_ERROR);
- HistogramAndLogMigrationFailure(
- bound_net_log, MIGRATION_STATUS_INTERNAL_ERROR,
- session->connection_id(), "Socket configuration failed");
- return;
- }
- std::unique_ptr<QuicChromiumPacketReader> new_reader(
- new QuicChromiumPacketReader(socket.get(), clock_.get(), session,
- yield_after_packets_, yield_after_duration_,
- session->net_log()));
- std::unique_ptr<QuicPacketWriter> new_writer(
- new QuicChromiumPacketWriter(socket.get()));
-
- if (!session->MigrateToSocket(std::move(socket), std::move(new_reader),
- std::move(new_writer))) {
- session->CloseSessionOnError(ERR_NETWORK_CHANGED,
- QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES);
- HistogramAndLogMigrationFailure(
- bound_net_log, MIGRATION_STATUS_TOO_MANY_CHANGES,
- session->connection_id(), "Too many migrations");
- return;
- }
- HistogramMigrationStatus(MIGRATION_STATUS_SUCCESS);
- bound_net_log.AddEvent(
- NetLog::TYPE_QUIC_CONNECTION_MIGRATION_SUCCESS,
- base::Bind(&NetLogQuicConnectionMigrationSuccessCallback,
- session->connection_id()));
-}
-
-void QuicStreamFactory::OnSSLConfigChanged() {
- CloseAllSessions(ERR_CERT_DATABASE_CHANGED, QUIC_CONNECTION_CANCELLED);
-}
-
-void QuicStreamFactory::OnCertAdded(const X509Certificate* cert) {
- CloseAllSessions(ERR_CERT_DATABASE_CHANGED, QUIC_CONNECTION_CANCELLED);
-}
-
-void QuicStreamFactory::OnCACertChanged(const X509Certificate* cert) {
- // We should flush the sessions if we removed trust from a
- // cert, because a previously trusted server may have become
- // untrusted.
- //
- // We should not flush the sessions if we added trust to a cert.
- //
- // Since the OnCACertChanged method doesn't tell us what
- // kind of change it is, we have to flush the socket
- // pools to be safe.
- CloseAllSessions(ERR_CERT_DATABASE_CHANGED, QUIC_CONNECTION_CANCELLED);
-}
-
-bool QuicStreamFactory::HasActiveSession(const QuicServerId& server_id) const {
- // TODO(rtenneti): crbug.com/498823 - delete active_sessions_.empty() check.
- if (active_sessions_.empty())
- return false;
- return ContainsKey(active_sessions_, server_id);
-}
-
-bool QuicStreamFactory::HasActiveJob(const QuicServerId& server_id) const {
- return ContainsKey(active_jobs_, server_id);
-}
-
-int QuicStreamFactory::ConfigureSocket(DatagramClientSocket* socket,
- IPEndPoint addr,
- NetworkHandle network) {
- if (enable_non_blocking_io_ &&
- client_socket_factory_ == ClientSocketFactory::GetDefaultFactory()) {
-#if defined(OS_WIN)
- static_cast<UDPClientSocket*>(socket)->UseNonBlockingIO();
-#endif
- }
-
- int rv;
- if (migrate_sessions_on_network_change_) {
- // If caller leaves network unspecified, use current default network.
- if (network == NetworkChangeNotifier::kInvalidNetworkHandle) {
- rv = socket->ConnectUsingDefaultNetwork(addr);
- } else {
- rv = socket->ConnectUsingNetwork(network, addr);
- }
- } else {
- rv = socket->Connect(addr);
- }
- if (rv != OK) {
- HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET);
- return rv;
- }
-
- rv = socket->SetReceiveBufferSize(socket_receive_buffer_size_);
- if (rv != OK) {
- HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER);
- return rv;
- }
-
- // Set a buffer large enough to contain the initial CWND's worth of packet
- // to work around the problem with CHLO packets being sent out with the
- // wrong encryption level, when the send buffer is full.
- rv = socket->SetSendBufferSize(kMaxPacketSize * 20);
- if (rv != OK) {
- HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER);
- return rv;
- }
-
- socket->GetLocalAddress(&local_address_);
- if (check_persisted_supports_quic_) {
- check_persisted_supports_quic_ = false;
- IPAddress last_address;
- if (http_server_properties_->GetSupportsQuic(&last_address) &&
- last_address == local_address_.address()) {
- require_confirmation_ = false;
- }
- }
-
- return OK;
-}
-
-int QuicStreamFactory::CreateSession(
- const QuicSessionKey& key,
- int cert_verify_flags,
- std::unique_ptr<QuicServerInfo> server_info,
- const AddressList& address_list,
- base::TimeTicks dns_resolution_end_time,
- const BoundNetLog& net_log,
- QuicChromiumClientSession** session) {
- TRACE_EVENT0("net", "QuicStreamFactory::CreateSession");
- IPEndPoint addr = *address_list.begin();
- bool enable_port_selection = enable_port_selection_;
- if (enable_port_selection && ContainsKey(gone_away_aliases_, key)) {
- // Disable port selection when the server is going away.
- // There is no point in trying to return to the same server, if
- // that server is no longer handling requests.
- enable_port_selection = false;
- gone_away_aliases_.erase(key);
- }
- const QuicServerId& server_id = key.server_id();
- scoped_refptr<PortSuggester> port_suggester =
- new PortSuggester(server_id.host_port_pair(), port_seed_);
- DatagramSocket::BindType bind_type =
- enable_port_selection ? DatagramSocket::RANDOM_BIND
- : // Use our callback.
- DatagramSocket::DEFAULT_BIND; // Use OS to randomize.
-
- std::unique_ptr<DatagramClientSocket> socket(
- client_socket_factory_->CreateDatagramClientSocket(
- bind_type, base::Bind(&PortSuggester::SuggestPort, port_suggester),
- net_log.net_log(), net_log.source()));
-
- // Passing in kInvalidNetworkHandle binds socket to default network.
- int rv = ConfigureSocket(socket.get(), addr,
- NetworkChangeNotifier::kInvalidNetworkHandle);
- if (rv != OK) {
- return rv;
- }
-
- if (enable_port_selection) {
- DCHECK_LE(1u, port_suggester->call_count());
- } else {
- DCHECK_EQ(0u, port_suggester->call_count());
- }
-
- if (!helper_.get()) {
- helper_.reset(
- new QuicChromiumConnectionHelper(clock_.get(), random_generator_));
- }
-
- if (!alarm_factory_.get()) {
- alarm_factory_.reset(new QuicChromiumAlarmFactory(
- base::ThreadTaskRunnerHandle::Get().get(), clock_.get()));
- }
- QuicConnectionId connection_id = random_generator_->RandUint64();
- InitializeCachedStateInCryptoConfig(server_id, server_info, &connection_id);
-
- QuicChromiumPacketWriter* writer = new QuicChromiumPacketWriter(socket.get());
- QuicConnection* connection = new QuicConnection(
- connection_id, addr, helper_.get(), alarm_factory_.get(), writer,
- true /* owns_writer */, Perspective::IS_CLIENT, supported_versions_);
- writer->SetConnection(connection);
- connection->SetMaxPacketLength(max_packet_length_);
-
- QuicConfig config = config_;
- config.SetSocketReceiveBufferToSend(socket_receive_buffer_size_);
- config.set_max_undecryptable_packets(kMaxUndecryptablePackets);
- config.SetInitialSessionFlowControlWindowToSend(
- kQuicSessionMaxRecvWindowSize);
- config.SetInitialStreamFlowControlWindowToSend(kQuicStreamMaxRecvWindowSize);
- int64_t srtt = GetServerNetworkStatsSmoothedRttInMicroseconds(server_id);
- if (srtt > 0)
- config.SetInitialRoundTripTimeUsToSend(static_cast<uint32_t>(srtt));
- config.SetBytesForConnectionIdToSend(0);
-
- if (quic_server_info_factory_.get() && !server_info) {
- // Start the disk cache loading so that we can persist the newer QUIC server
- // information and/or inform the disk cache that we have reused
- // |server_info|.
- server_info.reset(quic_server_info_factory_->GetForServer(server_id));
- server_info->Start();
- }
-
- // Use the factory to create a new socket performance watcher, and pass the
- // ownership to QuicChromiumClientSession.
- std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher;
- if (socket_performance_watcher_factory_) {
- socket_performance_watcher =
- socket_performance_watcher_factory_->CreateSocketPerformanceWatcher(
- SocketPerformanceWatcherFactory::PROTOCOL_QUIC);
- }
-
- *session = new QuicChromiumClientSession(
- connection, std::move(socket), this, quic_crypto_client_stream_factory_,
- clock_.get(), transport_security_state_, std::move(server_info),
- server_id, yield_after_packets_, yield_after_duration_, cert_verify_flags,
- config, &crypto_config_, network_connection_.GetDescription(),
- dns_resolution_end_time, &push_promise_index_,
- base::ThreadTaskRunnerHandle::Get().get(),
- std::move(socket_performance_watcher), net_log.net_log());
-
- all_sessions_[*session] = key; // owning pointer
-
- (*session)->Initialize();
- bool closed_during_initialize = !ContainsKey(all_sessions_, *session) ||
- !(*session)->connection()->connected();
- UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ClosedDuringInitializeSession",
- closed_during_initialize);
- if (closed_during_initialize) {
- DLOG(DFATAL) << "Session closed during initialize";
- *session = nullptr;
- return ERR_CONNECTION_CLOSED;
- }
- return OK;
-}
-
-void QuicStreamFactory::ActivateSession(const QuicSessionKey& key,
- QuicChromiumClientSession* session) {
- const QuicServerId& server_id(key.server_id());
- DCHECK(!HasActiveSession(server_id));
- UMA_HISTOGRAM_COUNTS("Net.QuicActiveSessions", active_sessions_.size());
- active_sessions_[server_id] = session;
- session_aliases_[session].insert(key);
- const IPEndPoint peer_address = session->connection()->peer_address();
- DCHECK(!ContainsKey(ip_aliases_[peer_address], session));
- ip_aliases_[peer_address].insert(session);
-}
-
-int64_t QuicStreamFactory::GetServerNetworkStatsSmoothedRttInMicroseconds(
- const QuicServerId& server_id) const {
- url::SchemeHostPort server("https", server_id.host_port_pair().host(),
- server_id.host_port_pair().port());
- const ServerNetworkStats* stats =
- http_server_properties_->GetServerNetworkStats(server);
- if (stats == nullptr)
- return 0;
- return stats->srtt.InMicroseconds();
-}
-
-bool QuicStreamFactory::WasQuicRecentlyBroken(
- const QuicServerId& server_id) const {
- const AlternativeService alternative_service(QUIC,
- server_id.host_port_pair());
- return http_server_properties_->WasAlternativeServiceRecentlyBroken(
- alternative_service);
-}
-
-bool QuicStreamFactory::CryptoConfigCacheIsEmpty(
- const QuicServerId& server_id) {
- QuicCryptoClientConfig::CachedState* cached =
- crypto_config_.LookupOrCreate(server_id);
- return cached->IsEmpty();
-}
-
-void QuicStreamFactory::InitializeCachedStateInCryptoConfig(
- const QuicServerId& server_id,
- const std::unique_ptr<QuicServerInfo>& server_info,
- QuicConnectionId* connection_id) {
- QuicCryptoClientConfig::CachedState* cached =
- crypto_config_.LookupOrCreate(server_id);
- if (cached->has_server_designated_connection_id())
- *connection_id = cached->GetNextServerDesignatedConnectionId();
-
- if (!cached->IsEmpty())
- return;
-
- // |server_info| will be NULL, if a non-empty server config already exists in
- // the memory cache.
- if (!server_info)
- return;
-
- // TODO(rtenneti): Delete the following histogram after collecting stats.
- // If the AlternativeServiceMap contained an entry for this host, check if
- // the disk cache contained an entry for it.
- if (ContainsKey(quic_supported_servers_at_startup_,
- server_id.host_port_pair())) {
- UMA_HISTOGRAM_BOOLEAN("Net.QuicServerInfo.ExpectConfigMissingFromDiskCache",
- server_info->state().server_config.empty());
- }
-
- cached->Initialize(server_info->state().server_config,
- server_info->state().source_address_token,
- server_info->state().certs, server_info->state().cert_sct,
- server_info->state().chlo_hash,
- server_info->state().server_config_sig, clock_->WallNow());
-}
-
-void QuicStreamFactory::MaybeInitialize() {
- // We don't initialize data from HttpServerProperties in the constructor
- // because HttpServerProperties has not yet initialized. We're guaranteed
- // HttpServerProperties has been initialized by the first time a request is
- // made.
- if (has_initialized_data_)
- return;
-
- has_initialized_data_ = true;
- for (const std::pair<const url::SchemeHostPort, AlternativeServiceInfoVector>&
- key_value : http_server_properties_->alternative_service_map()) {
- HostPortPair host_port_pair(key_value.first.host(), key_value.first.port());
- for (const AlternativeServiceInfo& alternative_service_info :
- key_value.second) {
- if (alternative_service_info.alternative_service.protocol == QUIC) {
- quic_supported_servers_at_startup_.insert(host_port_pair);
- break;
- }
- }
- }
-
- if (http_server_properties_->max_server_configs_stored_in_properties() == 0)
- return;
- // Create a temporary QuicServerInfo object to deserialize and to populate the
- // in-memory crypto server config cache in the MRU order.
- std::unique_ptr<QuicServerInfo> server_info;
- CompletionCallback callback;
- // Get the list of servers to be deserialized first because WaitForDataReady
- // touches quic_server_info_map.
- const QuicServerInfoMap& quic_server_info_map =
- http_server_properties_->quic_server_info_map();
- std::vector<QuicServerId> server_list(quic_server_info_map.size());
- for (const auto& key_value : quic_server_info_map)
- server_list.push_back(key_value.first);
- for (auto it = server_list.rbegin(); it != server_list.rend(); ++it) {
- const QuicServerId& server_id = *it;
- server_info.reset(quic_server_info_factory_->GetForServer(server_id));
- if (server_info->WaitForDataReady(callback) == OK) {
- DVLOG(1) << "Initialized server config for: " << server_id.ToString();
- InitializeCachedStateInCryptoConfig(server_id, server_info, nullptr);
- }
- }
-}
-
-void QuicStreamFactory::ProcessGoingAwaySession(
- QuicChromiumClientSession* session,
- const QuicServerId& server_id,
- bool session_was_active) {
- if (!http_server_properties_)
- return;
-
- const QuicConnectionStats& stats = session->connection()->GetStats();
- const AlternativeService alternative_service(QUIC,
- server_id.host_port_pair());
- if (session->IsCryptoHandshakeConfirmed()) {
- http_server_properties_->ConfirmAlternativeService(alternative_service);
- ServerNetworkStats network_stats;
- network_stats.srtt = base::TimeDelta::FromMicroseconds(stats.srtt_us);
- network_stats.bandwidth_estimate = stats.estimated_bandwidth;
- url::SchemeHostPort server("https", server_id.host_port_pair().host(),
- server_id.host_port_pair().port());
- http_server_properties_->SetServerNetworkStats(server, network_stats);
- return;
- }
-
- UMA_HISTOGRAM_COUNTS("Net.QuicHandshakeNotConfirmedNumPacketsReceived",
- stats.packets_received);
-
- if (!session_was_active)
- return;
-
- // TODO(rch): In the special case where the session has received no
- // packets from the peer, we should consider blacklisting this
- // differently so that we still race TCP but we don't consider the
- // session connected until the handshake has been confirmed.
- HistogramBrokenAlternateProtocolLocation(
- BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_STREAM_FACTORY);
-
- // Since the session was active, there's no longer an
- // HttpStreamFactoryImpl::Job running which can mark it broken, unless the TCP
- // job also fails. So to avoid not using QUIC when we otherwise could, we mark
- // it as recently broken, which means that 0-RTT will be disabled but we'll
- // still race.
- http_server_properties_->MarkAlternativeServiceRecentlyBroken(
- alternative_service);
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_stream_factory.h b/chromium/net/quic/quic_stream_factory.h
deleted file mode 100644
index 77fb744d66c..00000000000
--- a/chromium/net/quic/quic_stream_factory.h
+++ /dev/null
@@ -1,597 +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.
-
-#ifndef NET_QUIC_QUIC_STREAM_FACTORY_H_
-#define NET_QUIC_QUIC_STREAM_FACTORY_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <deque>
-#include <list>
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/gtest_prod_util.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "net/base/address_list.h"
-#include "net/base/completion_callback.h"
-#include "net/base/host_port_pair.h"
-#include "net/base/network_change_notifier.h"
-#include "net/cert/cert_database.h"
-#include "net/http/http_server_properties.h"
-#include "net/http/http_stream_factory.h"
-#include "net/log/net_log.h"
-#include "net/proxy/proxy_server.h"
-#include "net/quic/network_connection.h"
-#include "net/quic/quic_chromium_client_session.h"
-#include "net/quic/quic_client_push_promise_index.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_crypto_stream.h"
-#include "net/quic/quic_http_stream.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_id.h"
-#include "net/ssl/ssl_config_service.h"
-
-namespace net {
-
-class CTPolicyEnforcer;
-class CertVerifier;
-class ChannelIDService;
-class ClientSocketFactory;
-class CTVerifier;
-class HostResolver;
-class HttpServerProperties;
-class QuicClock;
-class QuicChromiumAlarmFactory;
-class QuicChromiumConnectionHelper;
-class QuicCryptoClientStreamFactory;
-class QuicRandom;
-class QuicServerInfo;
-class QuicServerInfoFactory;
-class QuicStreamFactory;
-class SocketPerformanceWatcherFactory;
-class TransportSecurityState;
-class BidirectionalStreamImpl;
-
-namespace test {
-class QuicStreamFactoryPeer;
-} // namespace test
-
-// When a connection is idle for 30 seconds it will be closed.
-const int kIdleConnectionTimeoutSeconds = 30;
-
-// Encapsulates a pending request for a QuicHttpStream.
-// If the request is still pending when it is destroyed, it will
-// cancel the request with the factory.
-class NET_EXPORT_PRIVATE QuicStreamRequest {
- public:
- explicit QuicStreamRequest(QuicStreamFactory* factory);
- ~QuicStreamRequest();
-
- // |cert_verify_flags| is bitwise OR'd of CertVerifier::VerifyFlags and it is
- // passed to CertVerifier::Verify.
- // |destination| will be resolved and resulting IPEndPoint used to open a
- // QuicConnection. This can be different than HostPortPair::FromURL(url).
- int Request(const HostPortPair& destination,
- PrivacyMode privacy_mode,
- int cert_verify_flags,
- const GURL& url,
- base::StringPiece method,
- const BoundNetLog& net_log,
- const CompletionCallback& callback);
-
- void OnRequestComplete(int rv);
-
- // Helper method that calls |factory_|'s GetTimeDelayForWaitingJob(). It
- // returns the amount of time waiting job should be delayed.
- base::TimeDelta GetTimeDelayForWaitingJob() const;
-
- std::unique_ptr<QuicHttpStream> CreateStream();
-
- std::unique_ptr<BidirectionalStreamImpl> CreateBidirectionalStreamImpl();
-
- // Sets |session_|.
- void SetSession(QuicChromiumClientSession* session);
-
- const QuicServerId& server_id() const { return server_id_; }
-
- const BoundNetLog& net_log() const { return net_log_; }
-
- private:
- QuicStreamFactory* factory_;
- QuicServerId server_id_;
- BoundNetLog net_log_;
- CompletionCallback callback_;
- base::WeakPtr<QuicChromiumClientSession> session_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicStreamRequest);
-};
-
-// A factory for creating new QuicHttpStreams on top of a pool of
-// QuicChromiumClientSessions.
-class NET_EXPORT_PRIVATE QuicStreamFactory
- : public NetworkChangeNotifier::IPAddressObserver,
- public NetworkChangeNotifier::NetworkObserver,
- public SSLConfigService::Observer,
- public CertDatabase::Observer {
- public:
- // This class encompasses |destination| and |server_id|.
- // |destination| is a HostPortPair which is resolved
- // and a QuicConnection is made to the resulting IP address.
- // |server_id| identifies the origin of the request,
- // the crypto handshake advertises |server_id.host()| to the server,
- // and the certificate is also matched against |server_id.host()|.
- class NET_EXPORT_PRIVATE QuicSessionKey {
- public:
- QuicSessionKey() = default;
- QuicSessionKey(const HostPortPair& destination,
- const QuicServerId& server_id);
- ~QuicSessionKey() = default;
-
- // Needed to be an element of std::set.
- bool operator<(const QuicSessionKey& other) const;
- bool operator==(const QuicSessionKey& other) const;
-
- const HostPortPair& destination() const { return destination_; }
- const QuicServerId& server_id() const { return server_id_; }
-
- private:
- HostPortPair destination_;
- QuicServerId server_id_;
- };
-
- QuicStreamFactory(
- NetLog* net_log,
- HostResolver* host_resolver,
- SSLConfigService* ssl_config_service,
- ClientSocketFactory* client_socket_factory,
- HttpServerProperties* http_server_properties,
- CertVerifier* cert_verifier,
- CTPolicyEnforcer* ct_policy_enforcer,
- ChannelIDService* channel_id_service,
- TransportSecurityState* transport_security_state,
- CTVerifier* cert_transparency_verifier,
- SocketPerformanceWatcherFactory* socket_performance_watcher_factory,
- QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory,
- QuicRandom* random_generator,
- QuicClock* clock,
- size_t max_packet_length,
- const std::string& user_agent_id,
- const QuicVersionVector& supported_versions,
- bool enable_port_selection,
- bool always_require_handshake_confirmation,
- bool disable_connection_pooling,
- float load_server_info_timeout_srtt_multiplier,
- bool enable_connection_racing,
- bool enable_non_blocking_io,
- bool disable_disk_cache,
- bool prefer_aes,
- int max_number_of_lossy_connections,
- float packet_loss_threshold,
- int max_recent_disabled_reasons,
- int threshold_timeouts_with_streams_open,
- int threshold_public_resets_post_handshake,
- int socket_receive_buffer_size,
- bool delay_tcp_race,
- int max_server_configs_stored_in_properties,
- bool close_sessions_on_ip_change,
- bool disable_quic_on_timeout_with_open_streams,
- int idle_connection_timeout_seconds,
- bool migrate_sessions_on_network_change,
- bool migrate_sessions_early,
- const QuicTagVector& connection_options,
- bool enable_token_binding);
- ~QuicStreamFactory() override;
-
- // Returns true if there is an existing session for |server_id| or if the
- // request can be pooled to an existing session to the IP address of
- // |destination|.
- bool CanUseExistingSession(const QuicServerId& server_id,
- const HostPortPair& destination);
-
- // Creates a new QuicHttpStream to |host_port_pair| which will be
- // owned by |request|.
- // If a matching session already exists, this method will return OK. If no
- // matching session exists, this will return ERR_IO_PENDING and will invoke
- // OnRequestComplete asynchronously.
- int Create(const QuicServerId& server_id,
- const HostPortPair& destination,
- int cert_verify_flags,
- const GURL& url,
- base::StringPiece method,
- const BoundNetLog& net_log,
- QuicStreamRequest* request);
-
- // If |packet_loss_rate| is greater than or equal to |packet_loss_threshold_|
- // it marks QUIC as recently broken for the port of the session. Increments
- // |number_of_lossy_connections_| by port. If |number_of_lossy_connections_|
- // is greater than or equal to |max_number_of_lossy_connections_| then it
- // disables QUIC. If QUIC is disabled then it closes the connection.
- //
- // Returns true if QUIC is disabled for the port of the session.
- bool OnHandshakeConfirmed(QuicChromiumClientSession* session,
- float packet_loss_rate);
-
- // Called when a TCP job completes for an origin that QUIC potentially
- // could be used for.
- void OnTcpJobCompleted(bool succeeded);
-
- // Returns true if QUIC is disabled for this port.
- bool IsQuicDisabled(uint16_t port) const;
-
- // Returns reason QUIC is disabled for this port, or QUIC_DISABLED_NOT if not.
- QuicChromiumClientSession::QuicDisabledReason QuicDisabledReason(
- uint16_t port) const;
-
- // Returns reason QUIC is disabled as string for net-internals, or
- // returns empty string if QUIC is not disabled.
- const char* QuicDisabledReasonString() const;
-
- // Called by a session when it becomes idle.
- void OnIdleSession(QuicChromiumClientSession* session);
-
- // Called by a session when it is going away and no more streams should be
- // created on it.
- void OnSessionGoingAway(QuicChromiumClientSession* session);
-
- // Called by a session after it shuts down.
- void OnSessionClosed(QuicChromiumClientSession* session);
-
- // Called by a session whose connection has timed out.
- void OnSessionConnectTimeout(QuicChromiumClientSession* session);
-
- // Cancels a pending request.
- void CancelRequest(QuicStreamRequest* request);
-
- // Closes all current sessions with specified network and QUIC error codes.
- void CloseAllSessions(int error, QuicErrorCode quic_error);
-
- std::unique_ptr<base::Value> QuicStreamFactoryInfoToValue() const;
-
- // Delete all cached state objects in |crypto_config_|.
- void ClearCachedStatesInCryptoConfig();
-
- // Helper method that configures a DatagramClientSocket. Socket is
- // bound to the default network if the |network| param is
- // NetworkChangeNotifier::kInvalidNetworkHandle.
- // Returns net_error code.
- int ConfigureSocket(DatagramClientSocket* socket,
- IPEndPoint addr,
- NetworkChangeNotifier::NetworkHandle network);
-
- // Finds an alternative to |old_network| from the platform's list of connected
- // networks. Returns NetworkChangeNotifier::kInvalidNetworkHandle if no
- // alternative is found.
- NetworkChangeNotifier::NetworkHandle FindAlternateNetwork(
- NetworkChangeNotifier::NetworkHandle old_network);
-
- // Method that initiates migration of active sessions
- // currently bound to |network| to an alternate network, if one
- // exists. Idle sessions bound to |network| are closed. If there is
- // no alternate network to migrate active sessions onto, active
- // sessions are closed if |force_close| is true, and continue using
- // |network| otherwise. Sessions not bound to |network| are left unchanged.
- void MaybeMigrateOrCloseSessions(NetworkChangeNotifier::NetworkHandle network,
- bool force_close,
- const BoundNetLog& bound_net_log);
-
- // Method that initiates early migration of |session| if |session| is
- // active and if there is an alternate network than the one to which
- // |session| is currently bound.
- void MaybeMigrateSessionEarly(QuicChromiumClientSession* session);
-
- // Method that migrates |session| over to using |new_network|.
- void MigrateSessionToNetwork(QuicChromiumClientSession* session,
- NetworkChangeNotifier::NetworkHandle new_network,
- const BoundNetLog& bound_net_log);
-
- // NetworkChangeNotifier::IPAddressObserver methods:
-
- // Until the servers support roaming, close all connections when the local
- // IP address changes.
- void OnIPAddressChanged() override;
-
- // NetworkChangeNotifier::NetworkObserver methods:
- void OnNetworkConnected(
- NetworkChangeNotifier::NetworkHandle network) override;
- void OnNetworkDisconnected(
- NetworkChangeNotifier::NetworkHandle network) override;
- void OnNetworkSoonToDisconnect(
- NetworkChangeNotifier::NetworkHandle network) override;
- void OnNetworkMadeDefault(
- NetworkChangeNotifier::NetworkHandle network) override;
-
- // SSLConfigService::Observer methods:
-
- // We perform the same flushing as described above when SSL settings change.
- void OnSSLConfigChanged() override;
-
- // CertDatabase::Observer methods:
-
- // We close all sessions when certificate database is changed.
- void OnCertAdded(const X509Certificate* cert) override;
- void OnCACertChanged(const X509Certificate* cert) override;
-
- bool require_confirmation() const { return require_confirmation_; }
-
- void set_require_confirmation(bool require_confirmation);
-
- bool ZeroRTTEnabledFor(const QuicServerId& server_id);
-
- // It returns the amount of time waiting job should be delayed.
- base::TimeDelta GetTimeDelayForWaitingJob(const QuicServerId& server_id);
-
- QuicChromiumConnectionHelper* helper() { return helper_.get(); }
-
- QuicChromiumAlarmFactory* alarm_factory() { return alarm_factory_.get(); }
-
- bool enable_port_selection() const { return enable_port_selection_; }
-
- bool has_quic_server_info_factory() {
- return quic_server_info_factory_.get() != nullptr;
- }
-
- void set_quic_server_info_factory(
- QuicServerInfoFactory* quic_server_info_factory);
-
- bool enable_connection_racing() const { return enable_connection_racing_; }
- void set_enable_connection_racing(bool enable_connection_racing) {
- enable_connection_racing_ = enable_connection_racing;
- }
-
- int socket_receive_buffer_size() const { return socket_receive_buffer_size_; }
-
- bool delay_tcp_race() const { return delay_tcp_race_; }
-
- private:
- class Job;
- friend class test::QuicStreamFactoryPeer;
- FRIEND_TEST_ALL_PREFIXES(HttpStreamFactoryTest, QuicLossyProxyMarkedAsBad);
-
- typedef std::map<QuicServerId, QuicChromiumClientSession*> SessionMap;
- typedef std::map<QuicChromiumClientSession*, QuicSessionKey> SessionIdMap;
- typedef std::set<QuicSessionKey> AliasSet;
- typedef std::map<QuicChromiumClientSession*, AliasSet> SessionAliasMap;
- typedef std::set<QuicChromiumClientSession*> SessionSet;
- typedef std::map<IPEndPoint, SessionSet> IPAliasMap;
- typedef std::map<QuicServerId, QuicCryptoClientConfig*> CryptoConfigMap;
- typedef std::set<Job*> JobSet;
- typedef std::map<QuicServerId, JobSet> JobMap;
- typedef std::map<QuicStreamRequest*, QuicServerId> RequestMap;
- typedef std::set<QuicStreamRequest*> RequestSet;
- typedef std::map<QuicServerId, RequestSet> ServerIDRequestsMap;
- typedef std::deque<enum QuicChromiumClientSession::QuicDisabledReason>
- DisabledReasonsQueue;
-
- enum FactoryStatus {
- OPEN, // New streams may be created.
- CLOSED, // No new streams may be created temporarily.
- DISABLED // No more streams may be created until the network changes.
- };
-
- // Creates a job which doesn't wait for server config to be loaded from the
- // disk cache. This job is started via a PostTask.
- void CreateAuxilaryJob(const QuicSessionKey& key,
- int cert_verify_flags,
- const BoundNetLog& net_log);
-
- // Returns a newly created QuicHttpStream owned by the caller.
- std::unique_ptr<QuicHttpStream> CreateFromSession(
- QuicChromiumClientSession* session);
-
- bool OnResolution(const QuicSessionKey& key, const AddressList& address_list);
- void OnJobComplete(Job* job, int rv);
- bool HasActiveSession(const QuicServerId& server_id) const;
- bool HasActiveJob(const QuicServerId& server_id) const;
- int CreateSession(const QuicSessionKey& key,
- int cert_verify_flags,
- std::unique_ptr<QuicServerInfo> quic_server_info,
- const AddressList& address_list,
- base::TimeTicks dns_resolution_end_time,
- const BoundNetLog& net_log,
- QuicChromiumClientSession** session);
- void ActivateSession(const QuicSessionKey& key,
- QuicChromiumClientSession* session);
-
- // Returns |srtt| in micro seconds from ServerNetworkStats. Returns 0 if there
- // is no |http_server_properties_| or if |http_server_properties_| doesn't
- // have ServerNetworkStats for the given |server_id|.
- int64_t GetServerNetworkStatsSmoothedRttInMicroseconds(
- const QuicServerId& server_id) const;
-
- // Helper methods.
- bool WasQuicRecentlyBroken(const QuicServerId& server_id) const;
-
- bool CryptoConfigCacheIsEmpty(const QuicServerId& server_id);
-
- // Initializes the cached state associated with |server_id| in
- // |crypto_config_| with the information in |server_info|. Populates
- // |connection_id| with the next server designated connection id,
- // if any, and otherwise leaves it unchanged.
- void InitializeCachedStateInCryptoConfig(
- const QuicServerId& server_id,
- const std::unique_ptr<QuicServerInfo>& server_info,
- QuicConnectionId* connection_id);
-
- // Initialize |quic_supported_servers_at_startup_| with the list of servers
- // that supported QUIC at start up and also initialize in-memory cache of
- // QuicServerInfo objects from HttpServerProperties.
- void MaybeInitialize();
-
- void ProcessGoingAwaySession(QuicChromiumClientSession* session,
- const QuicServerId& server_id,
- bool was_session_active);
-
- // Collect stats from recent connections, possibly disabling Quic.
- void MaybeDisableQuic(QuicChromiumClientSession* session);
-
- void MaybeDisableQuic(uint16_t port);
-
- bool require_confirmation_;
- NetLog* net_log_;
- HostResolver* host_resolver_;
- ClientSocketFactory* client_socket_factory_;
- HttpServerProperties* http_server_properties_;
- TransportSecurityState* transport_security_state_;
- CTVerifier* cert_transparency_verifier_;
- std::unique_ptr<QuicServerInfoFactory> quic_server_info_factory_;
- QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory_;
- QuicRandom* random_generator_;
- std::unique_ptr<QuicClock> clock_;
- const size_t max_packet_length_;
-
- // Factory which is used to create socket performance watcher. A new watcher
- // is created for every QUIC connection.
- // |socket_performance_watcher_factory_| may be null.
- SocketPerformanceWatcherFactory* socket_performance_watcher_factory_;
-
- // The helper used for all connections.
- std::unique_ptr<QuicChromiumConnectionHelper> helper_;
-
- // The alarm factory used for all connections.
- std::unique_ptr<QuicChromiumAlarmFactory> alarm_factory_;
-
- // Contains owning pointers to all sessions that currently exist.
- SessionIdMap all_sessions_;
- // Contains non-owning pointers to currently active session
- // (not going away session, once they're implemented).
- SessionMap active_sessions_;
- // Map from session to set of aliases that this session is known by.
- SessionAliasMap session_aliases_;
- // Map from IP address to sessions which are connected to this address.
- IPAliasMap ip_aliases_;
-
- // Origins which have gone away recently.
- AliasSet gone_away_aliases_;
-
- const QuicConfig config_;
- QuicCryptoClientConfig crypto_config_;
-
- JobMap active_jobs_;
- ServerIDRequestsMap job_requests_map_;
- RequestMap active_requests_;
-
- QuicVersionVector supported_versions_;
-
- // Determine if we should consistently select a client UDP port. If false,
- // then we will just let the OS select a random client port for each new
- // connection.
- bool enable_port_selection_;
-
- // Set if we always require handshake confirmation. If true, this will
- // introduce at least one RTT for the handshake before the client sends data.
- bool always_require_handshake_confirmation_;
-
- // Set if we do not want connection pooling.
- bool disable_connection_pooling_;
-
- // Specifies the ratio between time to load QUIC server information from disk
- // cache to 'smoothed RTT'. This ratio is used to calculate the timeout in
- // milliseconds to wait for loading of QUIC server information. If we don't
- // want to timeout, set |load_server_info_timeout_srtt_multiplier_| to 0.
- float load_server_info_timeout_srtt_multiplier_;
-
- // Set if we want to race connections - one connection that sends
- // INCHOATE_HELLO and another connection that sends CHLO after loading server
- // config from the disk cache.
- bool enable_connection_racing_;
-
- // Set if experimental non-blocking IO should be used on windows sockets.
- bool enable_non_blocking_io_;
-
- // Set if we do not want to load server config from the disk cache.
- bool disable_disk_cache_;
-
- // Set if AES-GCM should be preferred, even if there is no hardware support.
- bool prefer_aes_;
-
- // Set if we want to disable QUIC when there is high packet loss rate.
- // Specifies the maximum number of connections with high packet loss in a row
- // after which QUIC will be disabled.
- int max_number_of_lossy_connections_;
- // Specifies packet loss rate in fraction after which a connection is closed
- // and is considered as a lossy connection.
- float packet_loss_threshold_;
- // Count number of lossy connections by port.
- std::map<uint16_t, int> number_of_lossy_connections_;
-
- // Keep track of stats for recently closed connections, using a
- // bounded queue.
- int max_disabled_reasons_;
- DisabledReasonsQueue disabled_reasons_;
- // Events that can trigger disabling QUIC
- int num_public_resets_post_handshake_;
- int num_timeouts_with_open_streams_;
- // Keep track the largest values for UMA histograms, that will help
- // determine good threshold values.
- int max_public_resets_post_handshake_;
- int max_timeouts_with_open_streams_;
- // Thresholds if greater than zero, determine when to
- int threshold_timeouts_with_open_streams_;
- int threshold_public_resets_post_handshake_;
-
- // Size of the UDP receive buffer.
- int socket_receive_buffer_size_;
-
- // Set if we do want to delay TCP connection when it is racing with QUIC.
- bool delay_tcp_race_;
-
- // If more than |yield_after_packets_| packets have been read or more than
- // |yield_after_duration_| time has passed, then
- // QuicChromiumPacketReader::StartReading() yields by doing a PostTask().
- int yield_after_packets_;
- QuicTime::Delta yield_after_duration_;
-
- // Set if all sessions should be closed when any local IP address changes.
- const bool close_sessions_on_ip_change_;
-
- // Set if migration should be attempted on active sessions when primary
- // interface changes.
- const bool migrate_sessions_on_network_change_;
-
- // Set if early migration should be attempted when the connection
- // experiences poor connectivity.
- const bool migrate_sessions_early_;
-
- // Each profile will (probably) have a unique port_seed_ value. This value
- // is used to help seed a pseudo-random number generator (PortSuggester) so
- // that we consistently (within this profile) suggest the same ephemeral
- // port when we re-connect to any given server/port. The differences between
- // profiles (probablistically) prevent two profiles from colliding in their
- // ephemeral port requests.
- uint64_t port_seed_;
-
- // Local address of socket that was created in CreateSession.
- IPEndPoint local_address_;
- bool check_persisted_supports_quic_;
- bool has_initialized_data_;
- std::set<HostPortPair> quic_supported_servers_at_startup_;
-
- NetworkConnection network_connection_;
-
- int num_push_streams_created_;
-
- QuicClientPushPromiseIndex push_promise_index_;
-
- // Current status of the factory's ability to create streams.
- FactoryStatus status_;
-
- base::TaskRunner* task_runner_;
-
- const scoped_refptr<SSLConfigService> ssl_config_service_;
-
- base::WeakPtrFactory<QuicStreamFactory> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicStreamFactory);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_STREAM_FACTORY_H_
diff --git a/chromium/net/quic/quic_stream_factory_test.cc b/chromium/net/quic/quic_stream_factory_test.cc
deleted file mode 100644
index c8da53ce761..00000000000
--- a/chromium/net/quic/quic_stream_factory_test.cc
+++ /dev/null
@@ -1,4420 +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/quic_stream_factory.h"
-
-#include <ostream>
-#include <utility>
-
-#include "base/run_loop.h"
-#include "base/strings/string_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "net/cert/cert_verifier.h"
-#include "net/cert/ct_policy_enforcer.h"
-#include "net/cert/multi_log_ct_verifier.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_response_info.h"
-#include "net/http/http_server_properties_impl.h"
-#include "net/http/http_util.h"
-#include "net/http/transport_security_state.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/crypto/properties_based_quic_server_info.h"
-#include "net/quic/crypto/quic_crypto_client_config.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/crypto/quic_server_info.h"
-#include "net/quic/quic_client_promised_info.h"
-#include "net/quic/quic_http_utils.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
-#include "net/quic/test_tools/mock_random.h"
-#include "net/quic/test_tools/quic_config_peer.h"
-#include "net/quic/test_tools/quic_stream_factory_peer.h"
-#include "net/quic/test_tools/quic_test_packet_maker.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/quic/test_tools/test_task_runner.h"
-#include "net/socket/socket_test_util.h"
-#include "net/spdy/spdy_session_test_util.h"
-#include "net/spdy/spdy_test_utils.h"
-#include "net/ssl/channel_id_service.h"
-#include "net/ssl/default_channel_id_store.h"
-#include "net/test/cert_test_util.h"
-#include "net/test/test_data_directory.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::string;
-using std::vector;
-
-namespace net {
-
-namespace {
-
-class MockSSLConfigService : public SSLConfigService {
- public:
- MockSSLConfigService() {}
-
- void GetSSLConfig(SSLConfig* config) override { *config = config_; }
-
- private:
- ~MockSSLConfigService() override {}
-
- SSLConfig config_;
-};
-
-} // namespace
-
-namespace test {
-
-namespace {
-
-enum DestinationType {
- // In pooling tests with two requests for different origins to the same
- // destination, the destination should be
- SAME_AS_FIRST, // the same as the first origin,
- SAME_AS_SECOND, // the same as the second origin, or
- DIFFERENT, // different from both.
-};
-
-const char kDefaultServerHostName[] = "www.example.org";
-const char kServer2HostName[] = "mail.example.org";
-const char kServer3HostName[] = "docs.example.org";
-const char kServer4HostName[] = "images.example.org";
-const char kDifferentHostname[] = "different.example.com";
-const int kDefaultServerPort = 443;
-const char kDefaultUrl[] = "https://www.example.org/";
-const char kServer2Url[] = "https://mail.example.org/";
-const char kServer3Url[] = "https://docs.example.org/";
-const char kServer4Url[] = "https://images.example.org/";
-
-// Run QuicStreamFactoryTest instances with all value combinations of version
-// and enable_connection_racting.
-struct TestParams {
- friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
- os << "{ version: " << QuicVersionToString(p.version)
- << ", enable_connection_racing: "
- << (p.enable_connection_racing ? "true" : "false") << " }";
- return os;
- }
-
- QuicVersion version;
- bool enable_connection_racing;
-};
-
-vector<TestParams> GetTestParams() {
- vector<TestParams> params;
- QuicVersionVector all_supported_versions = QuicSupportedVersions();
- for (const QuicVersion version : all_supported_versions) {
- params.push_back(TestParams{version, false});
- params.push_back(TestParams{version, true});
- }
- return params;
-}
-
-// Run QuicStreamFactoryWithDestinationTest instances with all value
-// combinations of version, enable_connection_racting, and destination_type.
-struct PoolingTestParams {
- friend std::ostream& operator<<(std::ostream& os,
- const PoolingTestParams& p) {
- os << "{ version: " << QuicVersionToString(p.version)
- << ", enable_connection_racing: "
- << (p.enable_connection_racing ? "true" : "false")
- << ", destination_type: ";
- switch (p.destination_type) {
- case SAME_AS_FIRST:
- os << "SAME_AS_FIRST";
- break;
- case SAME_AS_SECOND:
- os << "SAME_AS_SECOND";
- break;
- case DIFFERENT:
- os << "DIFFERENT";
- break;
- }
- os << " }";
- return os;
- }
-
- QuicVersion version;
- bool enable_connection_racing;
- DestinationType destination_type;
-};
-
-vector<PoolingTestParams> GetPoolingTestParams() {
- vector<PoolingTestParams> params;
- QuicVersionVector all_supported_versions = QuicSupportedVersions();
- for (const QuicVersion version : all_supported_versions) {
- params.push_back(PoolingTestParams{version, false, SAME_AS_FIRST});
- params.push_back(PoolingTestParams{version, false, SAME_AS_SECOND});
- params.push_back(PoolingTestParams{version, false, DIFFERENT});
- params.push_back(PoolingTestParams{version, true, SAME_AS_FIRST});
- params.push_back(PoolingTestParams{version, true, SAME_AS_SECOND});
- params.push_back(PoolingTestParams{version, true, DIFFERENT});
- }
- return params;
-}
-
-} // namespace
-
-class QuicHttpStreamPeer {
- public:
- static QuicChromiumClientSession* GetSession(QuicHttpStream* stream) {
- return stream->session_.get();
- }
-};
-
-class MockQuicServerInfo : public QuicServerInfo {
- public:
- explicit MockQuicServerInfo(const QuicServerId& server_id)
- : QuicServerInfo(server_id) {}
- ~MockQuicServerInfo() override {}
-
- void Start() override {}
-
- int WaitForDataReady(const CompletionCallback& callback) override {
- return ERR_IO_PENDING;
- }
-
- void ResetWaitForDataReadyCallback() override {}
-
- void CancelWaitForDataReadyCallback() override {}
-
- bool IsDataReady() override { return false; }
-
- bool IsReadyToPersist() override { return false; }
-
- void Persist() override {}
-
- void OnExternalCacheHit() override {}
-};
-
-class MockQuicServerInfoFactory : public QuicServerInfoFactory {
- public:
- MockQuicServerInfoFactory() {}
- ~MockQuicServerInfoFactory() override {}
-
- QuicServerInfo* GetForServer(const QuicServerId& server_id) override {
- return new MockQuicServerInfo(server_id);
- }
-};
-
-class MockNetworkChangeNotifier : public NetworkChangeNotifier {
- public:
- MockNetworkChangeNotifier() : force_network_handles_supported_(false) {}
-
- ConnectionType GetCurrentConnectionType() const override {
- return CONNECTION_UNKNOWN;
- }
-
- void ForceNetworkHandlesSupported() {
- force_network_handles_supported_ = true;
- }
-
- bool AreNetworkHandlesCurrentlySupported() const override {
- return force_network_handles_supported_;
- }
-
- void SetConnectedNetworksList(const NetworkList& network_list) {
- connected_networks_ = network_list;
- }
-
- void GetCurrentConnectedNetworks(NetworkList* network_list) const override {
- network_list->clear();
- *network_list = connected_networks_;
- }
-
- void NotifyNetworkSoonToDisconnect(
- NetworkChangeNotifier::NetworkHandle network) {
- NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChange(
- NetworkChangeNotifier::SOON_TO_DISCONNECT, network);
- // Spin the message loop so the notification is delivered.
- base::RunLoop().RunUntilIdle();
- }
-
- void NotifyNetworkDisconnected(NetworkChangeNotifier::NetworkHandle network) {
- NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChange(
- NetworkChangeNotifier::DISCONNECTED, network);
- // Spin the message loop so the notification is delivered.
- base::RunLoop().RunUntilIdle();
- }
-
- private:
- bool force_network_handles_supported_;
- NetworkChangeNotifier::NetworkList connected_networks_;
-};
-
-// Class to replace existing NetworkChangeNotifier singleton with a
-// MockNetworkChangeNotifier for a test. To use, simply create a
-// ScopedMockNetworkChangeNotifier object in the test.
-class ScopedMockNetworkChangeNotifier {
- public:
- ScopedMockNetworkChangeNotifier()
- : disable_network_change_notifier_for_tests_(
- new NetworkChangeNotifier::DisableForTest()),
- mock_network_change_notifier_(new MockNetworkChangeNotifier()) {}
-
- MockNetworkChangeNotifier* mock_network_change_notifier() {
- return mock_network_change_notifier_.get();
- }
-
- private:
- std::unique_ptr<NetworkChangeNotifier::DisableForTest>
- disable_network_change_notifier_for_tests_;
- std::unique_ptr<MockNetworkChangeNotifier> mock_network_change_notifier_;
-};
-
-class QuicStreamFactoryTestBase {
- protected:
- QuicStreamFactoryTestBase(QuicVersion version, bool enable_connection_racing)
- : ssl_config_service_(new MockSSLConfigService),
- random_generator_(0),
- clock_(new MockClock()),
- runner_(new TestTaskRunner(clock_)),
- version_(version),
- client_maker_(version_,
- 0,
- clock_,
- kDefaultServerHostName,
- Perspective::IS_CLIENT),
- server_maker_(version_,
- 0,
- clock_,
- kDefaultServerHostName,
- Perspective::IS_SERVER),
- cert_verifier_(CertVerifier::CreateDefault()),
- channel_id_service_(
- new ChannelIDService(new DefaultChannelIDStore(nullptr),
- base::ThreadTaskRunnerHandle::Get())),
- cert_transparency_verifier_(new MultiLogCTVerifier()),
- scoped_mock_network_change_notifier_(nullptr),
- factory_(nullptr),
- host_port_pair_(kDefaultServerHostName, kDefaultServerPort),
- url_(kDefaultUrl),
- url2_(kServer2Url),
- url3_(kServer3Url),
- url4_(kServer4Url),
- privacy_mode_(PRIVACY_MODE_DISABLED),
- enable_port_selection_(true),
- always_require_handshake_confirmation_(false),
- disable_connection_pooling_(false),
- load_server_info_timeout_srtt_multiplier_(0.0f),
- enable_connection_racing_(enable_connection_racing),
- enable_non_blocking_io_(true),
- disable_disk_cache_(false),
- prefer_aes_(false),
- max_number_of_lossy_connections_(0),
- packet_loss_threshold_(1.0f),
- max_disabled_reasons_(3),
- threshold_timeouts_with_open_streams_(2),
- threshold_public_resets_post_handshake_(2),
- receive_buffer_size_(0),
- delay_tcp_race_(true),
- close_sessions_on_ip_change_(false),
- disable_quic_on_timeout_with_open_streams_(false),
- idle_connection_timeout_seconds_(kIdleConnectionTimeoutSeconds),
- migrate_sessions_on_network_change_(false),
- migrate_sessions_early_(false) {
- clock_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
- }
-
- ~QuicStreamFactoryTestBase() {
- // If |factory_| was initialized, then it took over ownership of |clock_|.
- // If |factory_| was not initialized, then |clock_| needs to be destroyed.
- if (!factory_) {
- delete clock_;
- }
- }
-
- void Initialize() {
- DCHECK(!factory_);
- factory_.reset(new QuicStreamFactory(
- net_log_.net_log(), &host_resolver_, ssl_config_service_.get(),
- &socket_factory_, &http_server_properties_, cert_verifier_.get(),
- &ct_policy_enforcer_, channel_id_service_.get(),
- &transport_security_state_, cert_transparency_verifier_.get(),
- /*SocketPerformanceWatcherFactory*/ nullptr,
- &crypto_client_stream_factory_, &random_generator_, clock_,
- kDefaultMaxPacketSize, string(), SupportedVersions(version_),
- enable_port_selection_, always_require_handshake_confirmation_,
- disable_connection_pooling_, load_server_info_timeout_srtt_multiplier_,
- enable_connection_racing_, enable_non_blocking_io_, disable_disk_cache_,
- prefer_aes_, max_number_of_lossy_connections_, packet_loss_threshold_,
- max_disabled_reasons_, threshold_timeouts_with_open_streams_,
- threshold_public_resets_post_handshake_, receive_buffer_size_,
- delay_tcp_race_, /*max_server_configs_stored_in_properties*/ 0,
- close_sessions_on_ip_change_,
- disable_quic_on_timeout_with_open_streams_,
- idle_connection_timeout_seconds_, migrate_sessions_on_network_change_,
- migrate_sessions_early_, QuicTagVector(),
- /*enable_token_binding*/ false));
- factory_->set_require_confirmation(false);
- EXPECT_FALSE(factory_->has_quic_server_info_factory());
- factory_->set_quic_server_info_factory(new MockQuicServerInfoFactory());
- EXPECT_TRUE(factory_->has_quic_server_info_factory());
- }
-
- void InitializeConnectionMigrationTest(
- NetworkChangeNotifier::NetworkList connected_networks) {
- scoped_mock_network_change_notifier_.reset(
- new ScopedMockNetworkChangeNotifier());
- MockNetworkChangeNotifier* mock_ncn =
- scoped_mock_network_change_notifier_->mock_network_change_notifier();
- mock_ncn->ForceNetworkHandlesSupported();
- mock_ncn->SetConnectedNetworksList(connected_networks);
- migrate_sessions_on_network_change_ = true;
- migrate_sessions_early_ = true;
- Initialize();
- }
-
- bool HasActiveSession(const HostPortPair& host_port_pair) {
- QuicServerId server_id(host_port_pair, PRIVACY_MODE_DISABLED);
- return QuicStreamFactoryPeer::HasActiveSession(factory_.get(), server_id);
- }
-
- QuicChromiumClientSession* GetActiveSession(
- const HostPortPair& host_port_pair) {
- QuicServerId server_id(host_port_pair, PRIVACY_MODE_DISABLED);
- return QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server_id);
- }
-
- std::unique_ptr<QuicHttpStream> CreateFromSession(
- const HostPortPair& host_port_pair) {
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair);
- return QuicStreamFactoryPeer::CreateFromSession(factory_.get(), session);
- }
-
- int GetSourcePortForNewSession(const HostPortPair& destination) {
- return GetSourcePortForNewSessionInner(destination, false);
- }
-
- int GetSourcePortForNewSessionAndGoAway(const HostPortPair& destination) {
- return GetSourcePortForNewSessionInner(destination, true);
- }
-
- int GetSourcePortForNewSessionInner(const HostPortPair& destination,
- bool goaway_received) {
- // Should only be called if there is no active session for this destination.
- EXPECT_FALSE(HasActiveSession(destination));
- size_t socket_count = socket_factory_.udp_client_socket_ports().size();
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- QuicStreamRequest request(factory_.get());
- GURL url("https://" + destination.host() + "/");
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(destination, privacy_mode_,
- /*cert_verify_flags=*/0, url, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
- stream.reset();
-
- QuicChromiumClientSession* session = GetActiveSession(destination);
-
- if (socket_count + 1 != socket_factory_.udp_client_socket_ports().size()) {
- ADD_FAILURE();
- return 0;
- }
-
- if (goaway_received) {
- QuicGoAwayFrame goaway(QUIC_NO_ERROR, 1, "");
- session->connection()->OnGoAwayFrame(goaway);
- }
-
- factory_->OnSessionClosed(session);
- EXPECT_FALSE(HasActiveSession(destination));
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- return socket_factory_.udp_client_socket_ports()[socket_count];
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructClientConnectionClosePacket(
- QuicPacketNumber num) {
- return client_maker_.MakeConnectionClosePacket(num);
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructClientRstPacket() {
- QuicStreamId stream_id = kClientDataStreamId1;
- return client_maker_.MakeRstPacket(
- 1, true, stream_id,
- AdjustErrorForVersion(QUIC_RST_ACKNOWLEDGEMENT, version_));
- }
-
- static ProofVerifyDetailsChromium DefaultProofVerifyDetails() {
- // Load a certificate that is valid for *.example.org
- scoped_refptr<X509Certificate> test_cert(
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
- EXPECT_TRUE(test_cert.get());
- ProofVerifyDetailsChromium verify_details;
- verify_details.cert_verify_result.verified_cert = test_cert;
- verify_details.cert_verify_result.is_issued_by_known_root = true;
- return verify_details;
- }
-
- void NotifyIPAddressChanged() {
- NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
- // Spin the message loop so the notification is delivered.
- base::RunLoop().RunUntilIdle();
- }
-
- std::unique_ptr<QuicEncryptedPacket> ConstructGetRequestPacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool should_include_version,
- bool fin) {
- SpdyHeaderBlock headers =
- client_maker_.GetRequestHeaders("GET", "https", "/");
- SpdyPriority priority =
- ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY);
- 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::unique_ptr<QuicEncryptedPacket> ConstructOkResponsePacket(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id,
- bool should_include_version,
- bool fin) {
- SpdyHeaderBlock headers = server_maker_.GetResponseHeaders("200 OK");
- size_t spdy_headers_frame_len;
- return server_maker_.MakeResponseHeadersPacket(
- packet_number, stream_id, should_include_version, fin,
- std::move(headers), &spdy_headers_frame_len);
- }
-
- MockHostResolver host_resolver_;
- scoped_refptr<SSLConfigService> ssl_config_service_;
- MockClientSocketFactory socket_factory_;
- MockCryptoClientStreamFactory crypto_client_stream_factory_;
- MockRandom random_generator_;
- MockClock* clock_; // Owned by |factory_| once created.
- scoped_refptr<TestTaskRunner> runner_;
- QuicVersion version_;
- QuicTestPacketMaker client_maker_;
- QuicTestPacketMaker server_maker_;
- HttpServerPropertiesImpl http_server_properties_;
- std::unique_ptr<CertVerifier> cert_verifier_;
- std::unique_ptr<ChannelIDService> channel_id_service_;
- TransportSecurityState transport_security_state_;
- std::unique_ptr<CTVerifier> cert_transparency_verifier_;
- CTPolicyEnforcer ct_policy_enforcer_;
- std::unique_ptr<ScopedMockNetworkChangeNotifier>
- scoped_mock_network_change_notifier_;
- std::unique_ptr<QuicStreamFactory> factory_;
- HostPortPair host_port_pair_;
- GURL url_;
- GURL url2_;
- GURL url3_;
- GURL url4_;
-
- PrivacyMode privacy_mode_;
- BoundNetLog net_log_;
- TestCompletionCallback callback_;
-
- // Variables to configure QuicStreamFactory.
- bool enable_port_selection_;
- bool always_require_handshake_confirmation_;
- bool disable_connection_pooling_;
- double load_server_info_timeout_srtt_multiplier_;
- bool enable_connection_racing_;
- bool enable_non_blocking_io_;
- bool disable_disk_cache_;
- bool prefer_aes_;
- int max_number_of_lossy_connections_;
- double packet_loss_threshold_;
- int max_disabled_reasons_;
- int threshold_timeouts_with_open_streams_;
- int threshold_public_resets_post_handshake_;
- int receive_buffer_size_;
- bool delay_tcp_race_;
- bool close_sessions_on_ip_change_;
- bool disable_quic_on_timeout_with_open_streams_;
- int idle_connection_timeout_seconds_;
- bool migrate_sessions_on_network_change_;
- bool migrate_sessions_early_;
-};
-
-class QuicStreamFactoryTest : public QuicStreamFactoryTestBase,
- public ::testing::TestWithParam<TestParams> {
- protected:
- QuicStreamFactoryTest()
- : QuicStreamFactoryTestBase(GetParam().version,
- GetParam().enable_connection_racing) {}
-};
-
-INSTANTIATE_TEST_CASE_P(Version,
- QuicStreamFactoryTest,
- ::testing::ValuesIn(GetTestParams()));
-
-TEST_P(QuicStreamFactoryTest, Create) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // Will reset stream 3.
- stream = CreateFromSession(host_port_pair_);
- EXPECT_TRUE(stream.get());
-
- // TODO(rtenneti): We should probably have a tests that HTTP and HTTPS result
- // in streams on different sessions.
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- stream = request2.CreateStream(); // Will reset stream 5.
- stream.reset(); // Will reset stream 7.
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, CreateZeroRtt) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::ZERO_RTT);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, CreateZeroRttPost) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::ZERO_RTT);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "POST", net_log_,
- callback_.callback()));
-
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, GoAway) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
-
- session->OnGoAway(QuicGoAwayFrame());
-
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, GoAwayForConnectionMigrationWithPortOnly) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
-
- session->OnGoAway(
- QuicGoAwayFrame(QUIC_ERROR_MIGRATING_PORT, 0,
- "peer connection migration due to port change only"));
- NetErrorDetails details;
- EXPECT_FALSE(details.quic_port_migration_detected);
- session->PopulateNetErrorDetails(&details);
- EXPECT_TRUE(details.quic_port_migration_detected);
- details.quic_port_migration_detected = false;
- stream->PopulateNetErrorDetails(&details);
- EXPECT_TRUE(details.quic_port_migration_detected);
-
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, Pooling) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- HostPortPair server2(kServer2HostName, kDefaultServerPort);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- TestCompletionCallback callback;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback.callback()));
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- EXPECT_EQ(GetActiveSession(host_port_pair_), GetActiveSession(server2));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, NoPoolingIfDisabled) {
- disable_connection_pooling_ = true;
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data1(reads, arraysize(reads), nullptr, 0);
- SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data1);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- HostPortPair server2(kServer2HostName, kDefaultServerPort);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- TestCompletionCallback callback;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback.callback()));
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- EXPECT_NE(GetActiveSession(host_port_pair_), GetActiveSession(server2));
-
- EXPECT_TRUE(socket_data1.AllReadDataConsumed());
- EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, NoPoolingAfterGoAway) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data1(reads, arraysize(reads), nullptr, 0);
- SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data1);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- HostPortPair server2(kServer2HostName, kDefaultServerPort);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- TestCompletionCallback callback;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback.callback()));
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- factory_->OnSessionGoingAway(GetActiveSession(host_port_pair_));
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
- EXPECT_FALSE(HasActiveSession(server2));
-
- TestCompletionCallback callback3;
- QuicStreamRequest request3(factory_.get());
- EXPECT_EQ(OK, request3.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback3.callback()));
- std::unique_ptr<QuicHttpStream> stream3 = request3.CreateStream();
- EXPECT_TRUE(stream3.get());
-
- EXPECT_TRUE(HasActiveSession(server2));
-
- EXPECT_TRUE(socket_data1.AllReadDataConsumed());
- EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, HttpsPooling) {
- Initialize();
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- HostPortPair server1(kDefaultServerHostName, 443);
- HostPortPair server2(kServer2HostName, 443);
-
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(server1, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- TestCompletionCallback callback;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback_.callback()));
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- EXPECT_EQ(GetActiveSession(server1), GetActiveSession(server2));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, NoHttpsPoolingIfDisabled) {
- disable_connection_pooling_ = true;
- Initialize();
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data1(reads, arraysize(reads), nullptr, 0);
- SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data1);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- HostPortPair server1(kDefaultServerHostName, 443);
- HostPortPair server2(kServer2HostName, 443);
-
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(server1, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- TestCompletionCallback callback;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback_.callback()));
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- EXPECT_NE(GetActiveSession(server1), GetActiveSession(server2));
-
- EXPECT_TRUE(socket_data1.AllReadDataConsumed());
- EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, HttpsPoolingWithMatchingPins) {
- Initialize();
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- HostPortPair server1(kDefaultServerHostName, 443);
- HostPortPair server2(kServer2HostName, 443);
- uint8_t primary_pin = 1;
- uint8_t backup_pin = 2;
- test::AddPin(&transport_security_state_, kServer2HostName, primary_pin,
- backup_pin);
-
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- verify_details.cert_verify_result.public_key_hashes.push_back(
- test::GetTestHashValue(primary_pin));
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(server1, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- TestCompletionCallback callback;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback_.callback()));
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- EXPECT_EQ(GetActiveSession(server1), GetActiveSession(server2));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithMatchingPinsIfDisabled) {
- disable_connection_pooling_ = true;
- Initialize();
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data1(reads, arraysize(reads), nullptr, 0);
- SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data1);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- HostPortPair server1(kDefaultServerHostName, 443);
- HostPortPair server2(kServer2HostName, 443);
- uint8_t primary_pin = 1;
- uint8_t backup_pin = 2;
- test::AddPin(&transport_security_state_, kServer2HostName, primary_pin,
- backup_pin);
-
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- verify_details.cert_verify_result.public_key_hashes.push_back(
- test::GetTestHashValue(primary_pin));
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(server1, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- TestCompletionCallback callback;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback_.callback()));
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- EXPECT_NE(GetActiveSession(server1), GetActiveSession(server2));
-
- EXPECT_TRUE(socket_data1.AllReadDataConsumed());
- EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithDifferentPins) {
- Initialize();
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data1(reads, arraysize(reads), nullptr, 0);
- SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data1);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- HostPortPair server1(kDefaultServerHostName, 443);
- HostPortPair server2(kServer2HostName, 443);
- uint8_t primary_pin = 1;
- uint8_t backup_pin = 2;
- uint8_t bad_pin = 3;
- test::AddPin(&transport_security_state_, kServer2HostName, primary_pin,
- backup_pin);
-
- ProofVerifyDetailsChromium verify_details1 = DefaultProofVerifyDetails();
- verify_details1.cert_verify_result.public_key_hashes.push_back(
- test::GetTestHashValue(bad_pin));
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details1);
-
- ProofVerifyDetailsChromium verify_details2 = DefaultProofVerifyDetails();
- verify_details2.cert_verify_result.public_key_hashes.push_back(
- test::GetTestHashValue(primary_pin));
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2);
-
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(server1, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- TestCompletionCallback callback;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback_.callback()));
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- EXPECT_NE(GetActiveSession(server1), GetActiveSession(server2));
-
- EXPECT_TRUE(socket_data1.AllReadDataConsumed());
- EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, Goaway) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
- SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // Mark the session as going away. Ensure that while it is still alive
- // that it is no longer active.
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
- factory_->OnSessionGoingAway(session);
- EXPECT_EQ(true,
- QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
-
- // Create a new request for the same destination and verify that a
- // new session is created.
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request2.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
- EXPECT_NE(session, GetActiveSession(host_port_pair_));
- EXPECT_EQ(true,
- QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
-
- stream2.reset();
- stream.reset();
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, MaxOpenStream) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- QuicStreamId stream_id = kClientDataStreamId1;
- std::unique_ptr<QuicEncryptedPacket> client_rst(
- client_maker_.MakeRstPacket(1, true, stream_id, QUIC_STREAM_CANCELLED));
- MockWrite writes[] = {
- MockWrite(ASYNC, client_rst->data(), client_rst->length(), 0),
- };
- std::unique_ptr<QuicEncryptedPacket> server_rst(
- server_maker_.MakeRstPacket(1, false, stream_id, QUIC_STREAM_CANCELLED));
- MockRead reads[] = {
- MockRead(ASYNC, server_rst->data(), server_rst->length(), 1),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2)};
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- HttpRequestInfo request_info;
- vector<QuicHttpStream*> streams;
- // The MockCryptoClientStream sets max_open_streams to be
- // kDefaultMaxStreamsPerConnection / 2.
- for (size_t i = 0; i < kDefaultMaxStreamsPerConnection / 2; i++) {
- QuicStreamRequest request(factory_.get());
- int rv = request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback());
- if (i == 0) {
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback_.WaitForResult());
- } else {
- EXPECT_EQ(OK, rv);
- }
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream);
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
- net_log_, CompletionCallback()));
- streams.push_back(stream.release());
- }
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- CompletionCallback()));
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream);
- EXPECT_EQ(ERR_IO_PENDING,
- stream->InitializeStream(&request_info, DEFAULT_PRIORITY, net_log_,
- callback_.callback()));
-
- // Close the first stream.
- streams.front()->Close(false);
- // Trigger exchange of RSTs that in turn allow progress for the last
- // stream.
- EXPECT_EQ(OK, callback_.WaitForResult());
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-
- // Force close of the connection to suppress the generation of RST
- // packets when streams are torn down, which wouldn't be relevant to
- // this test anyway.
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
- session->connection()->CloseConnection(QUIC_PUBLIC_RESET, "test",
- ConnectionCloseBehavior::SILENT_CLOSE);
-
- STLDeleteElements(&streams);
-}
-
-TEST_P(QuicStreamFactoryTest, ResolutionErrorInCreate) {
- Initialize();
- SequencedSocketData socket_data(nullptr, 0, nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- host_resolver_.rules()->AddSimulatedFailure(kDefaultServerHostName);
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback_.WaitForResult());
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, ConnectErrorInCreate) {
- Initialize();
- MockConnect connect(SYNCHRONOUS, ERR_ADDRESS_IN_USE);
- SequencedSocketData socket_data(nullptr, 0, nullptr, 0);
- socket_data.set_connect_data(connect);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(ERR_ADDRESS_IN_USE, callback_.WaitForResult());
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, CancelCreate) {
- Initialize();
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
- {
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- }
-
- base::RunLoop().RunUntilIdle();
-
- std::unique_ptr<QuicHttpStream> stream(CreateFromSession(host_port_pair_));
- EXPECT_TRUE(stream.get());
- stream.reset();
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, CreateConsistentEphemeralPort) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- // Sequentially connect to the default host, then another host, and then the
- // default host. Verify that the default host gets a consistent ephemeral
- // port, that is different from the other host's connection.
-
- string other_server_name = kServer2HostName;
- EXPECT_NE(kDefaultServerHostName, other_server_name);
- HostPortPair host_port_pair2(other_server_name, kDefaultServerPort);
-
- int original_port = GetSourcePortForNewSession(host_port_pair_);
- EXPECT_NE(original_port, GetSourcePortForNewSession(host_port_pair2));
- EXPECT_EQ(original_port, GetSourcePortForNewSession(host_port_pair_));
-}
-
-TEST_P(QuicStreamFactoryTest, GoAwayDisablesConsistentEphemeralPort) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- // Get a session to the host using the port suggester.
- int original_port = GetSourcePortForNewSessionAndGoAway(host_port_pair_);
- // Verify that the port is different after the goaway.
- EXPECT_NE(original_port, GetSourcePortForNewSession(host_port_pair_));
- // Since the previous session did not goaway we should see the original port.
- EXPECT_EQ(original_port, GetSourcePortForNewSession(host_port_pair_));
-}
-
-TEST_P(QuicStreamFactoryTest, CloseAllSessions) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> rst(ConstructClientRstPacket());
- vector<MockWrite> writes;
- writes.push_back(MockWrite(ASYNC, rst->data(), rst->length(), 1));
- SequencedSocketData socket_data(reads, arraysize(reads),
- writes.empty() ? nullptr : &writes[0],
- writes.size());
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
- net_log_, CompletionCallback()));
-
- // Close the session and verify that stream saw the error.
- factory_->CloseAllSessions(ERR_INTERNET_DISCONNECTED, QUIC_INTERNAL_ERROR);
- EXPECT_EQ(ERR_INTERNET_DISCONNECTED,
- stream->ReadResponseHeaders(callback_.callback()));
-
- // Now attempting to request a stream to the same origin should create
- // a new session.
-
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request2.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- stream = request2.CreateStream();
- stream.reset(); // Will reset stream 3.
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, OnIPAddressChanged) {
- close_sessions_on_ip_change_ = true;
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> rst(ConstructClientRstPacket());
- vector<MockWrite> writes;
- writes.push_back(MockWrite(ASYNC, rst->data(), rst->length(), 1));
- SequencedSocketData socket_data(reads, arraysize(reads),
- writes.empty() ? nullptr : &writes[0],
- writes.size());
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
- net_log_, CompletionCallback()));
-
- // Change the IP address and verify that stream saw the error.
- NotifyIPAddressChanged();
- EXPECT_EQ(ERR_NETWORK_CHANGED,
- stream->ReadResponseHeaders(callback_.callback()));
- EXPECT_TRUE(factory_->require_confirmation());
-
- // Now attempting to request a stream to the same origin should create
- // a new session.
-
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request2.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- stream = request2.CreateStream();
- stream.reset(); // Will reset stream 3.
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeSoonToDisconnect) {
- InitializeConnectionMigrationTest(
- {kDefaultNetworkForTests, kNewNetworkForTests});
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> request_packet(
- ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
- MockWrite writes[] = {MockWrite(SYNCHRONOUS, request_packet->data(),
- request_packet->length(), 1)};
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // Cause QUIC stream to be created.
- HttpRequestInfo request_info;
- request_info.method = "GET";
- request_info.url = url_;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Send GET request on stream.
- HttpResponseInfo response;
- HttpRequestHeaders request_headers;
- EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
- callback_.callback()));
-
- // Set up second socket data provider that is used after migration.
- // The response to the earlier request is read on this new socket.
- std::unique_ptr<QuicEncryptedPacket> ping(
- client_maker_.MakePingPacket(2, /*include_version=*/true));
- MockWrite writes1[] = {
- MockWrite(SYNCHRONOUS, ping->data(), ping->length(), 0)};
- std::unique_ptr<QuicEncryptedPacket> response_headers_packet(
- ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
- MockRead reads1[] = {MockRead(ASYNC, response_headers_packet->data(),
- response_headers_packet->length(), 1),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2)};
- SequencedSocketData socket_data1(reads1, arraysize(reads1), writes1,
- arraysize(writes1));
- socket_factory_.AddSocketDataProvider(&socket_data1);
-
- // Trigger connection migration. This should cause a PING frame
- // to be emitted.
- scoped_mock_network_change_notifier_->mock_network_change_notifier()
- ->NotifyNetworkSoonToDisconnect(kDefaultNetworkForTests);
-
- // The session should now be marked as going away. Ensure that
- // while it is still alive, it is no longer active.
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
- EXPECT_EQ(1u, session->GetNumActiveStreams());
-
- // Verify that response headers on the migrated socket were delivered to the
- // stream.
- EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback()));
- EXPECT_EQ(200, response.headers->response_code());
-
- // Create a new request for the same destination and verify that a
- // new session is created.
- MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request2.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
- QuicChromiumClientSession* new_session = GetActiveSession(host_port_pair_);
- EXPECT_NE(session, new_session);
-
- // On a DISCONNECTED notification, nothing happens to the migrated
- // session, but the new session is closed since it has no open
- // streams.
- scoped_mock_network_change_notifier_->mock_network_change_notifier()
- ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_EQ(1u, session->GetNumActiveStreams());
- EXPECT_FALSE(
- QuicStreamFactoryPeer::IsLiveSession(factory_.get(), new_session));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data1.AllReadDataConsumed());
- EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnected) {
- InitializeConnectionMigrationTest(
- {kDefaultNetworkForTests, kNewNetworkForTests});
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> request_packet(
- ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
- MockWrite writes[] = {MockWrite(SYNCHRONOUS, request_packet->data(),
- request_packet->length(), 1)};
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // Cause QUIC stream to be created.
- HttpRequestInfo request_info;
- request_info.method = "GET";
- request_info.url = url_;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Send GET request on stream.
- HttpResponseInfo response_info;
- HttpRequestHeaders request_headers;
- EXPECT_EQ(OK, stream->SendRequest(request_headers, &response_info,
- callback_.callback()));
-
- // Set up second socket data provider that is used after migration.
- std::unique_ptr<QuicEncryptedPacket> ping(
- client_maker_.MakePingPacket(2, /*include_version=*/true));
- std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
- 3, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
- MockWrite writes1[] = {
- MockWrite(SYNCHRONOUS, ping->data(), ping->length(), 0)};
- std::unique_ptr<QuicEncryptedPacket> response_packet(
- ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
- MockRead reads1[] = {
- MockRead(ASYNC, response_packet->data(), response_packet->length(), 1),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2)};
- SequencedSocketData socket_data1(reads1, arraysize(reads1), writes1,
- arraysize(writes1));
- socket_factory_.AddSocketDataProvider(&socket_data1);
-
- // Trigger connection migration. This should cause a PING frame
- // to be emitted.
- scoped_mock_network_change_notifier_->mock_network_change_notifier()
- ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
-
- // The session should now be marked as going away. Ensure that
- // while it is still alive, it is no longer active.
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
- EXPECT_EQ(1u, session->GetNumActiveStreams());
-
- // Create a new request for the same destination and verify that a
- // new session is created.
- MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request2.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
- EXPECT_NE(session, GetActiveSession(host_port_pair_));
- EXPECT_EQ(true,
- QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data1.AllReadDataConsumed());
- EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeSoonToDisconnectNoNetworks) {
- NetworkChangeNotifier::NetworkList no_networks(0);
- InitializeConnectionMigrationTest(no_networks);
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
- 1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
- MockWrite writes[] = {
- MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 1),
- };
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // Cause QUIC stream to be created.
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
- EXPECT_EQ(1u, session->GetNumActiveStreams());
-
- // Trigger connection migration. Since there are no networks
- // to migrate to, this should cause the session to continue on the same
- // socket, but be marked as going away.
- scoped_mock_network_change_notifier_->mock_network_change_notifier()
- ->NotifyNetworkSoonToDisconnect(kDefaultNetworkForTests);
-
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
- EXPECT_EQ(1u, session->GetNumActiveStreams());
-
- stream.reset();
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedNoNetworks) {
- NetworkChangeNotifier::NetworkList no_networks(0);
- InitializeConnectionMigrationTest(no_networks);
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
- 1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT));
- MockWrite writes[] = {
- MockWrite(ASYNC, client_rst->data(), client_rst->length(), 1),
- };
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // Cause QUIC stream to be created.
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Trigger connection migration. Since there are no networks
- // to migrate to, this should cause a RST_STREAM frame to be emitted
- // and the session to be closed.
- scoped_mock_network_change_notifier_->mock_network_change_notifier()
- ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
-
- EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeSoonToDisconnectNoNewNetwork) {
- InitializeConnectionMigrationTest({kDefaultNetworkForTests});
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
- 1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
- MockWrite writes[] = {
- MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 1),
- };
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // Cause QUIC stream to be created.
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Trigger connection migration. Since there are no networks
- // to migrate to, this should cause session to be continue but be marked as
- // going away.
- scoped_mock_network_change_notifier_->mock_network_change_notifier()
- ->NotifyNetworkSoonToDisconnect(kDefaultNetworkForTests);
-
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
- EXPECT_EQ(1u, session->GetNumActiveStreams());
-
- stream.reset();
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedNoNewNetwork) {
- InitializeConnectionMigrationTest({kDefaultNetworkForTests});
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
- 1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT));
- MockWrite writes[] = {
- MockWrite(ASYNC, client_rst->data(), client_rst->length(), 1),
- };
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // Cause QUIC stream to be created.
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Trigger connection migration. Since there are no networks
- // to migrate to, this should cause a RST_STREAM frame to be emitted
- // with QUIC_RST_ACKNOWLEDGEMENT error code, and the session will be closed.
- scoped_mock_network_change_notifier_->mock_network_change_notifier()
- ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
-
- EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest,
- OnNetworkChangeSoonToDisconnectNonMigratableStream) {
- InitializeConnectionMigrationTest(
- {kDefaultNetworkForTests, kNewNetworkForTests});
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
- 1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
- MockWrite writes[] = {
- MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 1),
- };
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // 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,
- net_log_, CompletionCallback()));
-
- // Ensure that session is alive and active.
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Trigger connection migration. Since there is a non-migratable stream,
- // this should cause session to continue but be marked as going away.
- scoped_mock_network_change_notifier_->mock_network_change_notifier()
- ->NotifyNetworkSoonToDisconnect(kDefaultNetworkForTests);
-
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
- EXPECT_EQ(1u, session->GetNumActiveStreams());
-
- stream.reset();
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest,
- OnNetworkChangeSoonToDisconnectConnectionMigrationDisabled) {
- InitializeConnectionMigrationTest(
- {kDefaultNetworkForTests, kNewNetworkForTests});
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
- 1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
- MockWrite writes[] = {
- MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 1),
- };
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // Cause QUIC stream to be created.
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Set session config to have connection migration disabled.
- QuicConfigPeer::SetReceivedDisableConnectionMigration(session->config());
- EXPECT_TRUE(session->config()->DisableConnectionMigration());
-
- // Trigger connection migration. Since there is a non-migratable stream,
- // this should cause session to continue but be marked as going away.
- scoped_mock_network_change_notifier_->mock_network_change_notifier()
- ->NotifyNetworkSoonToDisconnect(kDefaultNetworkForTests);
-
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
- EXPECT_EQ(1u, session->GetNumActiveStreams());
-
- stream.reset();
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedNonMigratableStream) {
- InitializeConnectionMigrationTest(
- {kDefaultNetworkForTests, kNewNetworkForTests});
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
- 1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT));
- MockWrite writes[] = {
- MockWrite(ASYNC, client_rst->data(), client_rst->length(), 1),
- };
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // 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,
- net_log_, CompletionCallback()));
-
- // Ensure that session is alive and active.
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Trigger connection migration. Since there is a non-migratable stream,
- // this should cause a RST_STREAM frame to be emitted with
- // QUIC_RST_ACKNOWLEDGEMENT error code, and the session will be closed.
- scoped_mock_network_change_notifier_->mock_network_change_notifier()
- ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
-
- EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest,
- OnNetworkChangeDisconnectedConnectionMigrationDisabled) {
- InitializeConnectionMigrationTest(
- {kDefaultNetworkForTests, kNewNetworkForTests});
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
- 1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT));
- MockWrite writes[] = {
- MockWrite(ASYNC, client_rst->data(), client_rst->length(), 1),
- };
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // Cause QUIC stream to be created.
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Set session config to have connection migration disabled.
- QuicConfigPeer::SetReceivedDisableConnectionMigration(session->config());
- EXPECT_TRUE(session->config()->DisableConnectionMigration());
-
- // Trigger connection migration. Since there is a non-migratable stream,
- // this should cause a RST_STREAM frame to be emitted with
- // QUIC_RST_ACKNOWLEDGEMENT error code, and the session will be closed.
- scoped_mock_network_change_notifier_->mock_network_change_notifier()
- ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
-
- EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeSoonToDisconnectNoOpenStreams) {
- InitializeConnectionMigrationTest(
- {kDefaultNetworkForTests, kNewNetworkForTests});
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0u);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // Ensure that session is alive and active.
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Trigger connection migration. Since there are no active streams,
- // the session will be closed.
- scoped_mock_network_change_notifier_->mock_network_change_notifier()
- ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
-
- EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedNoOpenStreams) {
- InitializeConnectionMigrationTest(
- {kDefaultNetworkForTests, kNewNetworkForTests});
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0u);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // Ensure that session is alive and active.
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Trigger connection migration. Since there are no active streams,
- // the session will be closed.
- scoped_mock_network_change_notifier_->mock_network_change_notifier()
- ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
-
- EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, MigrateSessionEarly) {
- InitializeConnectionMigrationTest(
- {kDefaultNetworkForTests, kNewNetworkForTests});
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> request_packet(
- ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
- MockWrite writes[] = {MockWrite(SYNCHRONOUS, request_packet->data(),
- request_packet->length(), 1)};
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // Cause QUIC stream to be created.
- HttpRequestInfo request_info;
- request_info.method = "GET";
- request_info.url = url_;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Send GET request on stream.
- HttpResponseInfo response;
- HttpRequestHeaders request_headers;
- EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
- callback_.callback()));
-
- // Set up second socket data provider that is used after migration.
- // The response to the earlier request is read on this new socket.
- std::unique_ptr<QuicEncryptedPacket> ping(
- client_maker_.MakePingPacket(2, /*include_version=*/true));
- MockWrite writes1[] = {
- MockWrite(SYNCHRONOUS, ping->data(), ping->length(), 0)};
- std::unique_ptr<QuicEncryptedPacket> response_headers_packet(
- ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
- MockRead reads1[] = {MockRead(ASYNC, response_headers_packet->data(),
- response_headers_packet->length(), 1),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2)};
- SequencedSocketData socket_data1(reads1, arraysize(reads1), writes1,
- arraysize(writes1));
- socket_factory_.AddSocketDataProvider(&socket_data1);
-
- // Trigger early connection migration. This should cause a PING frame
- // to be emitted.
- session->OnPathDegrading();
-
- // Run the message loop so that data queued in the new socket is read by the
- // packet reader.
- base::RunLoop().RunUntilIdle();
-
- // The session should now be marked as going away. Ensure that
- // while it is still alive, it is no longer active.
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_FALSE(HasActiveSession(host_port_pair_));
- EXPECT_EQ(1u, session->GetNumActiveStreams());
-
- // Verify that response headers on the migrated socket were delivered to the
- // stream.
- EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback()));
- EXPECT_EQ(200, response.headers->response_code());
-
- // Create a new request for the same destination and verify that a
- // new session is created.
- MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request2.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
- QuicChromiumClientSession* new_session = GetActiveSession(host_port_pair_);
- EXPECT_NE(session, new_session);
-
- // On a SOON_TO_DISCONNECT notification, nothing happens to the
- // migrated session, but the new session is closed since it has no
- // open streams.
- scoped_mock_network_change_notifier_->mock_network_change_notifier()
- ->NotifyNetworkSoonToDisconnect(kDefaultNetworkForTests);
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_EQ(1u, session->GetNumActiveStreams());
- EXPECT_FALSE(
- QuicStreamFactoryPeer::IsLiveSession(factory_.get(), new_session));
-
- // On a DISCONNECTED notification, nothing happens to the migrated session.
- scoped_mock_network_change_notifier_->mock_network_change_notifier()
- ->NotifyNetworkDisconnected(kDefaultNetworkForTests);
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_EQ(1u, session->GetNumActiveStreams());
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data1.AllReadDataConsumed());
- EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyNoNewNetwork) {
- InitializeConnectionMigrationTest({kDefaultNetworkForTests});
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
- 1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
- MockWrite writes[] = {
- MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 1),
- };
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // Cause QUIC stream to be created.
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Trigger connection migration. Since there are no networks
- // to migrate to, this should cause session to be continue but be marked as
- // going away.
- session->OnPathDegrading();
-
- // Run the message loop so that data queued in the new socket is read by the
- // packet reader.
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
- EXPECT_EQ(1u, session->GetNumActiveStreams());
-
- stream.reset();
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyNonMigratableStream) {
- InitializeConnectionMigrationTest(
- {kDefaultNetworkForTests, kNewNetworkForTests});
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
- 1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
- MockWrite writes[] = {
- MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 1),
- };
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // 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,
- net_log_, CompletionCallback()));
-
- // Ensure that session is alive and active.
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Trigger connection migration. Since there is a non-migratable stream,
- // this should cause session to be continue without migrating.
- session->OnPathDegrading();
-
- // Run the message loop so that data queued in the new socket is read by the
- // packet reader.
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
- EXPECT_EQ(1u, session->GetNumActiveStreams());
-
- stream.reset();
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyConnectionMigrationDisabled) {
- InitializeConnectionMigrationTest(
- {kDefaultNetworkForTests, kNewNetworkForTests});
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
- 1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
- MockWrite writes[] = {
- MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 1),
- };
- SequencedSocketData socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // Create request and QuicHttpStream.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- // Cause QUIC stream to be created.
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, 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));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Set session config to have connection migration disabled.
- QuicConfigPeer::SetReceivedDisableConnectionMigration(session->config());
- EXPECT_TRUE(session->config()->DisableConnectionMigration());
-
- // Trigger connection migration. Since there is a non-migratable stream,
- // this should cause session to be continue without migrating.
- session->OnPathDegrading();
-
- // Run the message loop so that data queued in the new socket is read by the
- // packet reader.
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
- EXPECT_EQ(1u, session->GetNumActiveStreams());
-
- stream.reset();
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, OnSSLConfigChanged) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> rst(ConstructClientRstPacket());
- vector<MockWrite> writes;
- writes.push_back(MockWrite(ASYNC, rst->data(), rst->length(), 1));
- SequencedSocketData socket_data(reads, arraysize(reads),
- writes.empty() ? nullptr : &writes[0],
- writes.size());
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
- net_log_, CompletionCallback()));
-
- ssl_config_service_->NotifySSLConfigChange();
- EXPECT_EQ(ERR_CERT_DATABASE_CHANGED,
- stream->ReadResponseHeaders(callback_.callback()));
- EXPECT_FALSE(factory_->require_confirmation());
-
- // Now attempting to request a stream to the same origin should create
- // a new session.
-
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request2.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- stream = request2.CreateStream();
- stream.reset(); // Will reset stream 3.
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, OnCertAdded) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> rst(ConstructClientRstPacket());
- vector<MockWrite> writes;
- writes.push_back(MockWrite(ASYNC, rst->data(), rst->length(), 1));
- SequencedSocketData socket_data(reads, arraysize(reads),
- writes.empty() ? nullptr : &writes[0],
- writes.size());
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
- net_log_, CompletionCallback()));
-
- // Add a cert and verify that stream saw the event.
- factory_->OnCertAdded(nullptr);
- EXPECT_EQ(ERR_CERT_DATABASE_CHANGED,
- stream->ReadResponseHeaders(callback_.callback()));
- EXPECT_FALSE(factory_->require_confirmation());
-
- // Now attempting to request a stream to the same origin should create
- // a new session.
-
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request2.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- stream = request2.CreateStream();
- stream.reset(); // Will reset stream 3.
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, OnCACertChanged) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- std::unique_ptr<QuicEncryptedPacket> rst(ConstructClientRstPacket());
- vector<MockWrite> writes;
- writes.push_back(MockWrite(ASYNC, rst->data(), rst->length(), 1));
- SequencedSocketData socket_data(reads, arraysize(reads),
- writes.empty() ? nullptr : &writes[0],
- writes.size());
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
- net_log_, CompletionCallback()));
-
- // Change the CA cert and verify that stream saw the event.
- factory_->OnCACertChanged(nullptr);
- EXPECT_EQ(ERR_CERT_DATABASE_CHANGED,
- stream->ReadResponseHeaders(callback_.callback()));
- EXPECT_FALSE(factory_->require_confirmation());
-
- // Now attempting to request a stream to the same origin should create
- // a new session.
-
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request2.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- stream = request2.CreateStream();
- stream.reset(); // Will reset stream 3.
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, SharedCryptoConfig) {
- Initialize();
-
- vector<string> cannoncial_suffixes;
- cannoncial_suffixes.push_back(string(".c.youtube.com"));
- cannoncial_suffixes.push_back(string(".googlevideo.com"));
-
- for (unsigned i = 0; i < cannoncial_suffixes.size(); ++i) {
- string r1_host_name("r1");
- string r2_host_name("r2");
- r1_host_name.append(cannoncial_suffixes[i]);
- r2_host_name.append(cannoncial_suffixes[i]);
-
- HostPortPair host_port_pair1(r1_host_name, 80);
- QuicCryptoClientConfig* crypto_config =
- QuicStreamFactoryPeer::GetCryptoConfig(factory_.get());
- QuicServerId server_id1(host_port_pair1, privacy_mode_);
- QuicCryptoClientConfig::CachedState* cached1 =
- crypto_config->LookupOrCreate(server_id1);
- EXPECT_FALSE(cached1->proof_valid());
- EXPECT_TRUE(cached1->source_address_token().empty());
-
- // Mutate the cached1 to have different data.
- // TODO(rtenneti): mutate other members of CachedState.
- cached1->set_source_address_token(r1_host_name);
- cached1->SetProofValid();
-
- HostPortPair host_port_pair2(r2_host_name, 80);
- QuicServerId server_id2(host_port_pair2, privacy_mode_);
- QuicCryptoClientConfig::CachedState* cached2 =
- crypto_config->LookupOrCreate(server_id2);
- EXPECT_EQ(cached1->source_address_token(), cached2->source_address_token());
- EXPECT_TRUE(cached2->proof_valid());
- }
-}
-
-TEST_P(QuicStreamFactoryTest, CryptoConfigWhenProofIsInvalid) {
- Initialize();
- vector<string> cannoncial_suffixes;
- cannoncial_suffixes.push_back(string(".c.youtube.com"));
- cannoncial_suffixes.push_back(string(".googlevideo.com"));
-
- for (unsigned i = 0; i < cannoncial_suffixes.size(); ++i) {
- string r3_host_name("r3");
- string r4_host_name("r4");
- r3_host_name.append(cannoncial_suffixes[i]);
- r4_host_name.append(cannoncial_suffixes[i]);
-
- HostPortPair host_port_pair1(r3_host_name, 80);
- QuicCryptoClientConfig* crypto_config =
- QuicStreamFactoryPeer::GetCryptoConfig(factory_.get());
- QuicServerId server_id1(host_port_pair1, privacy_mode_);
- QuicCryptoClientConfig::CachedState* cached1 =
- crypto_config->LookupOrCreate(server_id1);
- EXPECT_FALSE(cached1->proof_valid());
- EXPECT_TRUE(cached1->source_address_token().empty());
-
- // Mutate the cached1 to have different data.
- // TODO(rtenneti): mutate other members of CachedState.
- cached1->set_source_address_token(r3_host_name);
- cached1->SetProofInvalid();
-
- HostPortPair host_port_pair2(r4_host_name, 80);
- QuicServerId server_id2(host_port_pair2, privacy_mode_);
- QuicCryptoClientConfig::CachedState* cached2 =
- crypto_config->LookupOrCreate(server_id2);
- EXPECT_NE(cached1->source_address_token(), cached2->source_address_token());
- EXPECT_TRUE(cached2->source_address_token().empty());
- EXPECT_FALSE(cached2->proof_valid());
- }
-}
-
-TEST_P(QuicStreamFactoryTest, RacingConnections) {
- disable_disk_cache_ = false;
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- if (!enable_connection_racing_)
- return;
-
- QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- const AlternativeService alternative_service1(QUIC, host_port_pair_.host(),
- host_port_pair_.port());
- AlternativeServiceInfoVector alternative_service_info_vector;
- base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
- alternative_service_info_vector.push_back(
- AlternativeServiceInfo(alternative_service1, expiration));
-
- http_server_properties_.SetAlternativeServices(
- url::SchemeHostPort(url_), alternative_service_info_vector);
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::ZERO_RTT);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- QuicServerId server_id(host_port_pair_, privacy_mode_);
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(2u, QuicStreamFactoryPeer::GetNumberOfActiveJobs(factory_.get(),
- server_id));
-
- runner_->RunNextTask();
-
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumberOfActiveJobs(factory_.get(),
- server_id));
-}
-
-TEST_P(QuicStreamFactoryTest, EnableNotLoadFromDiskCache) {
- disable_disk_cache_ = true;
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::ZERO_RTT);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- // If we are waiting for disk cache, we would have posted a task. Verify that
- // the CancelWaitForDataReady task hasn't been posted.
- ASSERT_EQ(0u, runner_->GetPostedTasks().size());
-
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, BadPacketLoss) {
- disable_disk_cache_ = false;
- max_number_of_lossy_connections_ = 2;
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
-
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
- EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- factory_.get(), host_port_pair_.port()));
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- SequencedSocketData socket_data2(nullptr, 0, nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- SequencedSocketData socket_data3(nullptr, 0, nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data3);
-
- SequencedSocketData socket_data4(nullptr, 0, nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data4);
-
- HostPortPair server2(kServer2HostName, kDefaultServerPort);
- HostPortPair server3(kServer3HostName, kDefaultServerPort);
- HostPortPair server4(kServer4HostName, kDefaultServerPort);
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::ZERO_RTT);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server3.host(), "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server4.host(), "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
-
- DVLOG(1) << "Create 1st session and test packet loss";
-
- // Set packet_loss_rate to a lower value than packet_loss_threshold.
- EXPECT_FALSE(
- factory_->OnHandshakeConfirmed(session, /*packet_loss_rate=*/0.9f));
- EXPECT_TRUE(session->connection()->connected());
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
- EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- factory_.get(), host_port_pair_.port()));
-
- // Set packet_loss_rate to a higher value than packet_loss_threshold only once
- // and that shouldn't close the session and it shouldn't disable QUIC.
- EXPECT_FALSE(
- factory_->OnHandshakeConfirmed(session, /*packet_loss_rate=*/1.0f));
- EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- factory_.get(), host_port_pair_.port()));
- EXPECT_TRUE(session->connection()->connected());
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Test N-in-a-row high packet loss connections.
-
- DVLOG(1) << "Create 2nd session and test packet loss";
-
- TestCompletionCallback callback2;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback2.callback()));
- QuicChromiumClientSession* session2 = GetActiveSession(server2);
-
- // If there is no packet loss during handshake confirmation, number of lossy
- // connections for the port should be 0.
- EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- factory_.get(), server2.port()));
- EXPECT_FALSE(
- factory_->OnHandshakeConfirmed(session2, /*packet_loss_rate=*/0.9f));
- EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- factory_.get(), server2.port()));
- EXPECT_FALSE(
- QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), server2.port()));
-
- // Set packet_loss_rate to a higher value than packet_loss_threshold only once
- // and that shouldn't close the session and it shouldn't disable QUIC.
- EXPECT_FALSE(
- factory_->OnHandshakeConfirmed(session2, /*packet_loss_rate=*/1.0f));
- EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- factory_.get(), server2.port()));
- EXPECT_TRUE(session2->connection()->connected());
- EXPECT_FALSE(
- QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), server2.port()));
- EXPECT_TRUE(HasActiveSession(server2));
-
- DVLOG(1) << "Create 3rd session which also has packet loss";
-
- TestCompletionCallback callback3;
- QuicStreamRequest request3(factory_.get());
- EXPECT_EQ(OK, request3.Request(server3, privacy_mode_,
- /*cert_verify_flags=*/0, url3_, "GET",
- net_log_, callback3.callback()));
- QuicChromiumClientSession* session3 = GetActiveSession(server3);
-
- DVLOG(1) << "Create 4th session with packet loss and test IsQuicDisabled()";
- TestCompletionCallback callback4;
- QuicStreamRequest request4(factory_.get());
- EXPECT_EQ(OK, request4.Request(server4, privacy_mode_,
- /*cert_verify_flags=*/0, url4_, "GET",
- net_log_, callback4.callback()));
- QuicChromiumClientSession* session4 = GetActiveSession(server4);
-
- // Set packet_loss_rate to higher value than packet_loss_threshold 2nd time in
- // a row and that should close the session and disable QUIC.
- EXPECT_TRUE(
- factory_->OnHandshakeConfirmed(session3, /*packet_loss_rate=*/1.0f));
- EXPECT_EQ(2, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- factory_.get(), server3.port()));
- EXPECT_FALSE(session3->connection()->connected());
- EXPECT_TRUE(
- QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), server3.port()));
- EXPECT_FALSE(HasActiveSession(server3));
-
- // Set packet_loss_rate to higher value than packet_loss_threshold 3rd time in
- // a row and IsQuicDisabled() should close the session.
- EXPECT_TRUE(
- factory_->OnHandshakeConfirmed(session4, /*packet_loss_rate=*/1.0f));
- EXPECT_EQ(3, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- factory_.get(), server4.port()));
- EXPECT_FALSE(session4->connection()->connected());
- EXPECT_TRUE(
- QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), server4.port()));
- EXPECT_FALSE(HasActiveSession(server4));
-
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
- std::unique_ptr<QuicHttpStream> stream3 = request3.CreateStream();
- EXPECT_TRUE(stream3.get());
- std::unique_ptr<QuicHttpStream> stream4 = request4.CreateStream();
- EXPECT_TRUE(stream4.get());
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data3.AllReadDataConsumed());
- EXPECT_TRUE(socket_data3.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data4.AllReadDataConsumed());
- EXPECT_TRUE(socket_data4.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, PublicResetPostHandshakeTwoOfTwo) {
- disable_disk_cache_ = false;
- threshold_public_resets_post_handshake_ = 2;
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
-
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
- EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- factory_.get(), host_port_pair_.port()));
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- HostPortPair server2(kServer2HostName, kDefaultServerPort);
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::CONFIRM_HANDSHAKE);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
-
- DVLOG(1) << "Created 1st session. Now trigger public reset post handshake";
- session->connection()->CloseConnection(QUIC_PUBLIC_RESET, "test",
- ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
-
- EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(
- factory_.get()));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- // Test two-in-a-row public reset post handshakes..
- DVLOG(1) << "Create 2nd session and trigger public reset post handshake";
- TestCompletionCallback callback2;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback2.callback()));
- QuicChromiumClientSession* session2 = GetActiveSession(server2);
-
- session2->connection()->CloseConnection(
- QUIC_PUBLIC_RESET, "test", ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop2;
- run_loop2.RunUntilIdle();
- EXPECT_EQ(2, QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(
- factory_.get()));
- EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
- EXPECT_EQ(
- QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE,
- factory_->QuicDisabledReason(host_port_pair_.port()));
-
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_FALSE(stream.get()); // Session is already closed.
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_FALSE(stream2.get()); // Session is already closed.
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, TimeoutsWithOpenStreamsTwoOfTwo) {
- disable_disk_cache_ = true;
- threshold_timeouts_with_open_streams_ = 2;
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
- EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- factory_.get(), host_port_pair_.port()));
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- HostPortPair server2(kServer2HostName, kDefaultServerPort);
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::CONFIRM_HANDSHAKE);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
-
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
- net_log_, CompletionCallback()));
-
- DVLOG(1)
- << "Created 1st session and initialized a stream. Now trigger timeout";
- session->connection()->CloseConnection(QUIC_NETWORK_IDLE_TIMEOUT, "test",
- ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
-
- EXPECT_EQ(
- 1, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(factory_.get()));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- // Test two-in-a-row timeouts with open streams.
- DVLOG(1) << "Create 2nd session and timeout with open stream";
- TestCompletionCallback callback2;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback2.callback()));
- QuicChromiumClientSession* session2 = GetActiveSession(server2);
-
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
- EXPECT_EQ(OK, stream2->InitializeStream(&request_info, 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
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop2;
- run_loop2.RunUntilIdle();
- EXPECT_EQ(
- 2, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(factory_.get()));
- EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
- EXPECT_EQ(QuicChromiumClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS,
- factory_->QuicDisabledReason(host_port_pair_.port()));
-
- // Verify that QUIC is un-disabled after a TCP job fails.
- factory_->OnTcpJobCompleted(/*succeeded=*/false);
- EXPECT_EQ(
- 0, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(factory_.get()));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, PublicResetPostHandshakeTwoOfThree) {
- disable_disk_cache_ = true;
- threshold_public_resets_post_handshake_ = 2;
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
- EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- factory_.get(), host_port_pair_.port()));
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- SequencedSocketData socket_data3(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data3);
-
- HostPortPair server2(kServer2HostName, kDefaultServerPort);
- HostPortPair server3(kServer3HostName, kDefaultServerPort);
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::CONFIRM_HANDSHAKE);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server3.host(), "192.168.0.1", "");
-
- // Test first and third out of three public reset post handshakes.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
-
- DVLOG(1) << "Created 1st session. Now trigger public reset post handshake";
- session->connection()->CloseConnection(QUIC_PUBLIC_RESET, "test",
- ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
-
- EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(
- factory_.get()));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- DVLOG(1) << "Create 2nd session without disable trigger";
- TestCompletionCallback callback2;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback2.callback()));
- QuicChromiumClientSession* session2 = GetActiveSession(server2);
-
- session2->connection()->CloseConnection(
- QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop2;
- run_loop2.RunUntilIdle();
- EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(
- factory_.get()));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- DVLOG(1) << "Create 3rd session with public reset post handshake,"
- << " will disable QUIC";
- TestCompletionCallback callback3;
- QuicStreamRequest request3(factory_.get());
- EXPECT_EQ(OK, request3.Request(server3, privacy_mode_,
- /*cert_verify_flags=*/0, url3_, "GET",
- net_log_, callback3.callback()));
- QuicChromiumClientSession* session3 = GetActiveSession(server3);
-
- session3->connection()->CloseConnection(
- QUIC_PUBLIC_RESET, "test", ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop3;
- run_loop3.RunUntilIdle();
- EXPECT_EQ(2, QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(
- factory_.get()));
- EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
- EXPECT_EQ(
- QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE,
- factory_->QuicDisabledReason(host_port_pair_.port()));
-
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_FALSE(stream.get()); // Session is already closed.
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_FALSE(stream2.get()); // Session is already closed.
- std::unique_ptr<QuicHttpStream> stream3 = request3.CreateStream();
- EXPECT_FALSE(stream3.get()); // Session is already closed.
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data3.AllReadDataConsumed());
- EXPECT_TRUE(socket_data3.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, TimeoutsWithOpenStreamsTwoOfThree) {
- disable_disk_cache_ = true;
- threshold_public_resets_post_handshake_ = 2;
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
-
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
- EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- factory_.get(), host_port_pair_.port()));
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // SequencedSocketData socket_data2(nullptr, 0, nullptr, 0);
- SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- SequencedSocketData socket_data3(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data3);
-
- HostPortPair server2(kServer2HostName, kDefaultServerPort);
- HostPortPair server3(kServer3HostName, kDefaultServerPort);
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::CONFIRM_HANDSHAKE);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server3.host(), "192.168.0.1", "");
-
- // Test first and third out of three timeouts with open streams.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
-
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
- net_log_, CompletionCallback()));
-
- DVLOG(1)
- << "Created 1st session and initialized a stream. Now trigger timeout";
- session->connection()->CloseConnection(QUIC_NETWORK_IDLE_TIMEOUT, "test",
- ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
-
- EXPECT_EQ(
- 1, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(factory_.get()));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- // Test two-in-a-row timeouts with open streams.
- DVLOG(1) << "Create 2nd session without timeout";
- TestCompletionCallback callback2;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback2.callback()));
- QuicChromiumClientSession* session2 = GetActiveSession(server2);
-
- session2->connection()->CloseConnection(
- QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop2;
- run_loop2.RunUntilIdle();
- EXPECT_EQ(
- 1, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(factory_.get()));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- DVLOG(1) << "Create 3rd session with timeout with open streams,"
- << " will disable QUIC";
-
- TestCompletionCallback callback3;
- QuicStreamRequest request3(factory_.get());
- EXPECT_EQ(OK, request3.Request(server3, privacy_mode_,
- /*cert_verify_flags=*/0, url3_, "GET",
- net_log_, callback3.callback()));
- QuicChromiumClientSession* session3 = GetActiveSession(server3);
-
- std::unique_ptr<QuicHttpStream> stream3 = request3.CreateStream();
- EXPECT_TRUE(stream3.get());
- EXPECT_EQ(OK, stream3->InitializeStream(&request_info, DEFAULT_PRIORITY,
- net_log_, CompletionCallback()));
- session3->connection()->CloseConnection(
- QUIC_NETWORK_IDLE_TIMEOUT, "test", ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop3;
- run_loop3.RunUntilIdle();
- EXPECT_EQ(
- 2, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(factory_.get()));
- EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
- EXPECT_EQ(QuicChromiumClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS,
- factory_->QuicDisabledReason(host_port_pair_.port()));
-
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_FALSE(stream2.get()); // Session is already closed.
-
- // Verify that QUIC is un-disabled after a network change.
- factory_->OnIPAddressChanged();
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
- EXPECT_EQ(
- 0, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(factory_.get()));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data3.AllReadDataConsumed());
- EXPECT_TRUE(socket_data3.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, DisableQuicWhenTimeoutsWithOpenStreams) {
- disable_disk_cache_ = true;
- disable_quic_on_timeout_with_open_streams_ = true;
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
-
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
- EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- factory_.get(), host_port_pair_.port()));
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::CONFIRM_HANDSHAKE);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
-
- // Test first timeouts with open streams will disable QUIC.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
-
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
- net_log_, CompletionCallback()));
-
- DVLOG(1)
- << "Created 1st session and initialized a stream. Now trigger timeout."
- << "Will disable QUIC.";
- session->connection()->CloseConnection(QUIC_NETWORK_IDLE_TIMEOUT, "test",
- ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
-
- EXPECT_EQ(
- 1, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(factory_.get()));
- EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- EXPECT_EQ(QuicChromiumClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS,
- factory_->QuicDisabledReason(host_port_pair_.port()));
-
- // Verify that QUIC is fully disabled after a TCP job succeeds.
- factory_->OnTcpJobCompleted(/*succeeded=*/true);
- EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- // Verify that QUIC stays disabled after a TCP job succeeds.
- factory_->OnTcpJobCompleted(/*succeeded=*/false);
- EXPECT_TRUE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, PublicResetPostHandshakeTwoOfFour) {
- disable_disk_cache_ = true;
- threshold_public_resets_post_handshake_ = 2;
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
-
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
- EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- factory_.get(), host_port_pair_.port()));
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- SequencedSocketData socket_data3(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data3);
-
- SequencedSocketData socket_data4(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data4);
-
- HostPortPair server2(kServer2HostName, kDefaultServerPort);
- HostPortPair server3(kServer3HostName, kDefaultServerPort);
- HostPortPair server4(kServer4HostName, kDefaultServerPort);
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::CONFIRM_HANDSHAKE);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server3.host(), "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server4.host(), "192.168.0.1", "");
-
- // Test first and fourth out of four public reset post handshakes.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
-
- DVLOG(1) << "Created 1st session. Now trigger public reset post handshake";
- session->connection()->CloseConnection(QUIC_PUBLIC_RESET, "test",
- ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
-
- EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(
- factory_.get()));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- DVLOG(1) << "Create 2nd and 3rd sessions without disable trigger";
- TestCompletionCallback callback2;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback2.callback()));
- QuicChromiumClientSession* session2 = GetActiveSession(server2);
-
- session2->connection()->CloseConnection(
- QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop2;
- run_loop2.RunUntilIdle();
- EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(
- factory_.get()));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- TestCompletionCallback callback3;
- QuicStreamRequest request3(factory_.get());
- EXPECT_EQ(OK, request3.Request(server3, privacy_mode_,
- /*cert_verify_flags=*/0, url3_, "GET",
- net_log_, callback3.callback()));
- QuicChromiumClientSession* session3 = GetActiveSession(server3);
-
- session3->connection()->CloseConnection(
- QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop3;
- run_loop3.RunUntilIdle();
- EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(
- factory_.get()));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- DVLOG(1) << "Create 4rd session with public reset post handshake,"
- << " will not disable QUIC";
- TestCompletionCallback callback4;
- QuicStreamRequest request4(factory_.get());
- EXPECT_EQ(OK, request4.Request(server4, privacy_mode_,
- /*cert_verify_flags=*/0, url4_, "GET",
- net_log_, callback4.callback()));
- QuicChromiumClientSession* session4 = GetActiveSession(server4);
-
- session4->connection()->CloseConnection(
- QUIC_PUBLIC_RESET, "test", ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop4;
- run_loop4.RunUntilIdle();
- EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(
- factory_.get()));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_FALSE(stream.get()); // Session is already closed.
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_FALSE(stream2.get()); // Session is already closed.
- std::unique_ptr<QuicHttpStream> stream3 = request3.CreateStream();
- EXPECT_FALSE(stream3.get()); // Session is already closed.
- std::unique_ptr<QuicHttpStream> stream4 = request4.CreateStream();
- EXPECT_FALSE(stream4.get()); // Session is already closed.
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data3.AllReadDataConsumed());
- EXPECT_TRUE(socket_data3.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data4.AllReadDataConsumed());
- EXPECT_TRUE(socket_data4.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, TimeoutsWithOpenStreamsTwoOfFour) {
- disable_disk_cache_ = true;
- threshold_public_resets_post_handshake_ = 2;
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
-
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
- EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- factory_.get(), host_port_pair_.port()));
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- // SequencedSocketData socket_data2(nullptr, 0, nullptr, 0);
- SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- SequencedSocketData socket_data3(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data3);
-
- SequencedSocketData socket_data4(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data4);
-
- HostPortPair server2(kServer2HostName, kDefaultServerPort);
- HostPortPair server3(kServer3HostName, kDefaultServerPort);
- HostPortPair server4(kServer4HostName, kDefaultServerPort);
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::CONFIRM_HANDSHAKE);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server3.host(), "192.168.0.1", "");
- host_resolver_.rules()->AddIPLiteralRule(server4.host(), "192.168.0.1", "");
-
- // Test first and fourth out of three timeouts with open streams.
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
-
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
- HttpRequestInfo request_info;
- EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
- net_log_, CompletionCallback()));
-
- DVLOG(1)
- << "Created 1st session and initialized a stream. Now trigger timeout";
- session->connection()->CloseConnection(QUIC_NETWORK_IDLE_TIMEOUT, "test",
- ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
-
- EXPECT_EQ(
- 1, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(factory_.get()));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- DVLOG(1) << "Create 2nd and 3rd sessions without timeout";
- TestCompletionCallback callback2;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
- /*cert_verify_flags=*/0, url2_, "GET",
- net_log_, callback2.callback()));
- QuicChromiumClientSession* session2 = GetActiveSession(server2);
-
- session2->connection()->CloseConnection(
- QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop2;
- run_loop2.RunUntilIdle();
- EXPECT_EQ(
- 1, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(factory_.get()));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- TestCompletionCallback callback3;
- QuicStreamRequest request3(factory_.get());
- EXPECT_EQ(OK, request3.Request(server3, privacy_mode_,
- /*cert_verify_flags=*/0, url3_, "GET",
- net_log_, callback3.callback()));
- QuicChromiumClientSession* session3 = GetActiveSession(server3);
-
- session3->connection()->CloseConnection(
- QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop3;
- run_loop3.RunUntilIdle();
- EXPECT_EQ(
- 1, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(factory_.get()));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- DVLOG(1) << "Create 4th session with timeout with open streams,"
- << " will not disable QUIC";
-
- TestCompletionCallback callback4;
- QuicStreamRequest request4(factory_.get());
- EXPECT_EQ(OK, request4.Request(server4, privacy_mode_,
- /*cert_verify_flags=*/0, url4_, "GET",
- net_log_, callback4.callback()));
- QuicChromiumClientSession* session4 = GetActiveSession(server4);
-
- std::unique_ptr<QuicHttpStream> stream4 = request4.CreateStream();
- EXPECT_TRUE(stream4.get());
- EXPECT_EQ(OK, stream4->InitializeStream(&request_info, DEFAULT_PRIORITY,
- net_log_, CompletionCallback()));
- session4->connection()->CloseConnection(
- QUIC_NETWORK_IDLE_TIMEOUT, "test", ConnectionCloseBehavior::SILENT_CLOSE);
- // Need to spin the loop now to ensure that
- // QuicStreamFactory::OnSessionClosed() runs.
- base::RunLoop run_loop4;
- run_loop4.RunUntilIdle();
- EXPECT_EQ(
- 1, QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(factory_.get()));
- EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(),
- host_port_pair_.port()));
-
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_FALSE(stream2.get()); // Session is already closed.
- std::unique_ptr<QuicHttpStream> stream3 = request3.CreateStream();
- EXPECT_FALSE(stream3.get()); // Session is already closed.
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data3.AllReadDataConsumed());
- EXPECT_TRUE(socket_data3.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data4.AllReadDataConsumed());
- EXPECT_TRUE(socket_data4.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, EnableDelayTcpRace) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- bool delay_tcp_race = QuicStreamFactoryPeer::GetDelayTcpRace(factory_.get());
- QuicStreamFactoryPeer::SetDelayTcpRace(factory_.get(), false);
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- ServerNetworkStats stats1;
- stats1.srtt = base::TimeDelta::FromMicroseconds(10);
- http_server_properties_.SetServerNetworkStats(url::SchemeHostPort(url_),
- stats1);
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::COLD_START);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "POST", net_log_,
- callback_.callback()));
-
- // If we don't delay TCP connection, then time delay should be 0.
- EXPECT_FALSE(factory_->delay_tcp_race());
- EXPECT_EQ(base::TimeDelta(), request.GetTimeDelayForWaitingJob());
-
- // Enable |delay_tcp_race_| param and verify delay is one RTT and that
- // server supports QUIC.
- QuicStreamFactoryPeer::SetDelayTcpRace(factory_.get(), true);
- EXPECT_TRUE(factory_->delay_tcp_race());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(15),
- request.GetTimeDelayForWaitingJob());
-
- // Confirm the handshake and verify that the stream is created.
- crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
- QuicSession::HANDSHAKE_CONFIRMED);
-
- EXPECT_EQ(OK, callback_.WaitForResult());
-
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- QuicStreamFactoryPeer::SetDelayTcpRace(factory_.get(), delay_tcp_race);
-}
-
-TEST_P(QuicStreamFactoryTest, MaybeInitialize) {
- idle_connection_timeout_seconds_ = 500;
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- const QuicConfig* config = QuicStreamFactoryPeer::GetConfig(factory_.get());
- EXPECT_EQ(500, config->IdleConnectionStateLifetime().ToSeconds());
-
- QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get());
-
- const AlternativeService alternative_service1(QUIC, host_port_pair_.host(),
- host_port_pair_.port());
- AlternativeServiceInfoVector alternative_service_info_vector;
- base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
- alternative_service_info_vector.push_back(
- AlternativeServiceInfo(alternative_service1, expiration));
- http_server_properties_.SetAlternativeServices(
- url::SchemeHostPort(url_), alternative_service_info_vector);
-
- HostPortPair host_port_pair2(kServer2HostName, kDefaultServerPort);
- url::SchemeHostPort server2("https", kServer2HostName, kDefaultServerPort);
- const AlternativeService alternative_service2(QUIC, host_port_pair2.host(),
- host_port_pair2.port());
- AlternativeServiceInfoVector alternative_service_info_vector2;
- alternative_service_info_vector2.push_back(
- AlternativeServiceInfo(alternative_service2, expiration));
- http_server_properties_.SetAlternativeServices(
- server2, alternative_service_info_vector2);
-
- http_server_properties_.SetMaxServerConfigsStoredInProperties(
- kMaxQuicServersToPersist);
-
- QuicServerId quic_server_id(kDefaultServerHostName, 80,
- PRIVACY_MODE_DISABLED);
- QuicServerInfoFactory* quic_server_info_factory =
- new PropertiesBasedQuicServerInfoFactory(&http_server_properties_);
- factory_->set_quic_server_info_factory(quic_server_info_factory);
-
- std::unique_ptr<QuicServerInfo> quic_server_info(
- quic_server_info_factory->GetForServer(quic_server_id));
-
- // Update quic_server_info's server_config and persist it.
- QuicServerInfo::State* state = quic_server_info->mutable_state();
- // Minimum SCFG that passes config validation checks.
- const char scfg[] = {// SCFG
- 0x53, 0x43, 0x46, 0x47,
- // num entries
- 0x01, 0x00,
- // padding
- 0x00, 0x00,
- // EXPY
- 0x45, 0x58, 0x50, 0x59,
- // EXPY end offset
- 0x08, 0x00, 0x00, 0x00,
- // Value
- '1', '2', '3', '4', '5', '6', '7', '8'};
-
- // Create temporary strings becasue Persist() clears string data in |state|.
- string server_config(reinterpret_cast<const char*>(&scfg), sizeof(scfg));
- string source_address_token("test_source_address_token");
- string cert_sct("test_cert_sct");
- string chlo_hash("test_chlo_hash");
- string signature("test_signature");
- string test_cert("test_cert");
- vector<string> certs;
- certs.push_back(test_cert);
- state->server_config = server_config;
- state->source_address_token = source_address_token;
- state->cert_sct = cert_sct;
- state->chlo_hash = chlo_hash;
- state->server_config_sig = signature;
- state->certs = certs;
-
- quic_server_info->Persist();
-
- QuicServerId quic_server_id2(kServer2HostName, 80, PRIVACY_MODE_DISABLED);
- std::unique_ptr<QuicServerInfo> quic_server_info2(
- quic_server_info_factory->GetForServer(quic_server_id2));
-
- // Update quic_server_info2's server_config and persist it.
- QuicServerInfo::State* state2 = quic_server_info2->mutable_state();
-
- // Minimum SCFG that passes config validation checks.
- const char scfg2[] = {// SCFG
- 0x53, 0x43, 0x46, 0x47,
- // num entries
- 0x01, 0x00,
- // padding
- 0x00, 0x00,
- // EXPY
- 0x45, 0x58, 0x50, 0x59,
- // EXPY end offset
- 0x08, 0x00, 0x00, 0x00,
- // Value
- '8', '7', '3', '4', '5', '6', '2', '1'};
-
- // Create temporary strings becasue Persist() clears string data in |state2|.
- string server_config2(reinterpret_cast<const char*>(&scfg2), sizeof(scfg2));
- string source_address_token2("test_source_address_token2");
- string cert_sct2("test_cert_sct2");
- string chlo_hash2("test_chlo_hash2");
- string signature2("test_signature2");
- string test_cert2("test_cert2");
- vector<string> certs2;
- certs2.push_back(test_cert2);
- state2->server_config = server_config2;
- state2->source_address_token = source_address_token2;
- state2->cert_sct = cert_sct2;
- state2->chlo_hash = chlo_hash2;
- state2->server_config_sig = signature2;
- state2->certs = certs2;
-
- quic_server_info2->Persist();
-
- QuicStreamFactoryPeer::MaybeInitialize(factory_.get());
- EXPECT_TRUE(QuicStreamFactoryPeer::HasInitializedData(factory_.get()));
-
- // Verify the MRU order is maintained.
- const QuicServerInfoMap& quic_server_info_map =
- http_server_properties_.quic_server_info_map();
- EXPECT_EQ(2u, quic_server_info_map.size());
- QuicServerInfoMap::const_iterator quic_server_info_map_it =
- quic_server_info_map.begin();
- EXPECT_EQ(quic_server_info_map_it->first, quic_server_id2);
- ++quic_server_info_map_it;
- EXPECT_EQ(quic_server_info_map_it->first, quic_server_id);
-
- EXPECT_TRUE(QuicStreamFactoryPeer::SupportsQuicAtStartUp(factory_.get(),
- host_port_pair_));
- EXPECT_FALSE(QuicStreamFactoryPeer::CryptoConfigCacheIsEmpty(factory_.get(),
- quic_server_id));
- QuicCryptoClientConfig* crypto_config =
- QuicStreamFactoryPeer::GetCryptoConfig(factory_.get());
- QuicCryptoClientConfig::CachedState* cached =
- crypto_config->LookupOrCreate(quic_server_id);
- EXPECT_FALSE(cached->server_config().empty());
- EXPECT_TRUE(cached->GetServerConfig());
- EXPECT_EQ(server_config, cached->server_config());
- EXPECT_EQ(source_address_token, cached->source_address_token());
- EXPECT_EQ(cert_sct, cached->cert_sct());
- EXPECT_EQ(chlo_hash, cached->chlo_hash());
- EXPECT_EQ(signature, cached->signature());
- ASSERT_EQ(1U, cached->certs().size());
- EXPECT_EQ(test_cert, cached->certs()[0]);
-
- EXPECT_TRUE(QuicStreamFactoryPeer::SupportsQuicAtStartUp(factory_.get(),
- host_port_pair2));
- EXPECT_FALSE(QuicStreamFactoryPeer::CryptoConfigCacheIsEmpty(
- factory_.get(), quic_server_id2));
- QuicCryptoClientConfig::CachedState* cached2 =
- crypto_config->LookupOrCreate(quic_server_id2);
- EXPECT_FALSE(cached2->server_config().empty());
- EXPECT_TRUE(cached2->GetServerConfig());
- EXPECT_EQ(server_config2, cached2->server_config());
- EXPECT_EQ(source_address_token2, cached2->source_address_token());
- EXPECT_EQ(cert_sct2, cached2->cert_sct());
- EXPECT_EQ(chlo_hash2, cached2->chlo_hash());
- EXPECT_EQ(signature2, cached2->signature());
- ASSERT_EQ(1U, cached->certs().size());
- EXPECT_EQ(test_cert2, cached2->certs()[0]);
-}
-
-TEST_P(QuicStreamFactoryTest, QuicDoingZeroRTT) {
- Initialize();
-
- factory_->set_require_confirmation(true);
- QuicServerId quic_server_id(host_port_pair_, PRIVACY_MODE_DISABLED);
- EXPECT_FALSE(factory_->ZeroRTTEnabledFor(quic_server_id));
-
- factory_->set_require_confirmation(false);
- EXPECT_FALSE(factory_->ZeroRTTEnabledFor(quic_server_id));
-
- // Load server config and verify QUIC will do 0RTT.
- QuicStreamFactoryPeer::CacheDummyServerConfig(factory_.get(), quic_server_id);
- EXPECT_TRUE(factory_->ZeroRTTEnabledFor(quic_server_id));
-}
-
-TEST_P(QuicStreamFactoryTest, YieldAfterPackets) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- QuicStreamFactoryPeer::SetYieldAfterPackets(factory_.get(), 0);
-
- std::unique_ptr<QuicEncryptedPacket> close_packet(
- ConstructClientConnectionClosePacket(0));
- vector<MockRead> reads;
- reads.push_back(
- MockRead(SYNCHRONOUS, close_packet->data(), close_packet->length(), 0));
- reads.push_back(MockRead(ASYNC, OK, 1));
- SequencedSocketData socket_data(&reads[0], reads.size(), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::ZERO_RTT);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
-
- // Set up the TaskObserver to verify QuicChromiumPacketReader::StartReading
- // posts a task.
- // TODO(rtenneti): Change SpdySessionTestTaskObserver to NetTestTaskObserver??
- SpdySessionTestTaskObserver observer("quic_chromium_packet_reader.cc",
- "StartReading");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- // Call run_loop so that QuicChromiumPacketReader::OnReadComplete() gets
- // called.
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
-
- // Verify task that the observer's executed_count is 1, which indicates
- // QuicChromiumPacketReader::StartReading() has posted only one task and
- // yielded the read.
- EXPECT_EQ(1u, observer.executed_count());
-
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_FALSE(stream.get()); // Session is already closed.
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, YieldAfterDuration) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- QuicStreamFactoryPeer::SetYieldAfterDuration(
- factory_.get(), QuicTime::Delta::FromMilliseconds(-1));
-
- std::unique_ptr<QuicEncryptedPacket> close_packet(
- ConstructClientConnectionClosePacket(0));
- vector<MockRead> reads;
- reads.push_back(
- MockRead(SYNCHRONOUS, close_packet->data(), close_packet->length(), 0));
- reads.push_back(MockRead(ASYNC, OK, 1));
- SequencedSocketData socket_data(&reads[0], reads.size(), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- crypto_client_stream_factory_.set_handshake_mode(
- MockCryptoClientStream::ZERO_RTT);
- host_resolver_.set_synchronous_mode(true);
- host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
- "192.168.0.1", "");
-
- // Set up the TaskObserver to verify QuicChromiumPacketReader::StartReading
- // posts a task.
- // TODO(rtenneti): Change SpdySessionTestTaskObserver to NetTestTaskObserver??
- SpdySessionTestTaskObserver observer("quic_chromium_packet_reader.cc",
- "StartReading");
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- // Call run_loop so that QuicChromiumPacketReader::OnReadComplete() gets
- // called.
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
-
- // Verify task that the observer's executed_count is 1, which indicates
- // QuicChromiumPacketReader::StartReading() has posted only one task and
- // yielded the read.
- EXPECT_EQ(1u, observer.executed_count());
-
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_FALSE(stream.get()); // Session is already closed.
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-TEST_P(QuicStreamFactoryTest, ServerPushSessionAffinity) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumPushStreamsCreated(factory_.get()));
-
- string url = "https://www.example.org/";
-
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
-
- QuicClientPromisedInfo promised(session, kServerDataStreamId1, kDefaultUrl);
- (*QuicStreamFactoryPeer::GetPushPromiseIndex(factory_.get())
- ->promised_by_url())[kDefaultUrl] = &promised;
-
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(1, QuicStreamFactoryPeer::GetNumPushStreamsCreated(factory_.get()));
-}
-
-TEST_P(QuicStreamFactoryTest, ServerPushPrivacyModeMismatch) {
- Initialize();
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
-
- std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
- 1, true, kServerDataStreamId1, QUIC_STREAM_CANCELLED));
- MockWrite writes[] = {
- MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 1),
- };
-
- SequencedSocketData socket_data1(reads, arraysize(reads), writes,
- arraysize(writes));
- SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
-
- socket_factory_.AddSocketDataProvider(&socket_data1);
- socket_factory_.AddSocketDataProvider(&socket_data2);
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request.Request(host_port_pair_, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
- EXPECT_TRUE(stream.get());
-
- EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumPushStreamsCreated(factory_.get()));
-
- string url = "https://www.example.org/";
- QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
-
- QuicClientPromisedInfo promised(session, kServerDataStreamId1, kDefaultUrl);
-
- QuicClientPushPromiseIndex* index =
- QuicStreamFactoryPeer::GetPushPromiseIndex(factory_.get());
-
- (*index->promised_by_url())[kDefaultUrl] = &promised;
- EXPECT_EQ(index->GetPromised(kDefaultUrl), &promised);
-
- // Doing the request should not use the push stream, but rather
- // cancel it because the privacy modes do not match.
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request2.Request(host_port_pair_, PRIVACY_MODE_ENABLED,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
-
- EXPECT_EQ(0, QuicStreamFactoryPeer::GetNumPushStreamsCreated(factory_.get()));
- EXPECT_EQ(index->GetPromised(kDefaultUrl), nullptr);
-
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- EXPECT_TRUE(socket_data1.AllReadDataConsumed());
- EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
- EXPECT_TRUE(socket_data2.AllReadDataConsumed());
- EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
-}
-
-// Pool to existing session with matching QuicServerId
-// even if destination is different.
-TEST_P(QuicStreamFactoryTest, PoolByOrigin) {
- Initialize();
-
- HostPortPair destination1("first.example.com", 443);
- HostPortPair destination2("second.example.com", 443);
-
- ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
- MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
- SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- QuicStreamRequest request1(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request1.Request(destination1, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream1 = request1.CreateStream();
- EXPECT_TRUE(stream1.get());
- EXPECT_TRUE(HasActiveSession(host_port_pair_));
-
- // Second request returns synchronously because it pools to existing session.
- TestCompletionCallback callback2;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(destination2, privacy_mode_,
- /*cert_verify_flags=*/0, url_, "GET", net_log_,
- callback2.callback()));
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- QuicChromiumClientSession* session1 =
- QuicHttpStreamPeer::GetSession(stream1.get());
- QuicChromiumClientSession* session2 =
- QuicHttpStreamPeer::GetSession(stream2.get());
- EXPECT_EQ(session1, session2);
- EXPECT_EQ(QuicServerId(host_port_pair_, privacy_mode_),
- session1->server_id());
-
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
-}
-
-class QuicStreamFactoryWithDestinationTest
- : public QuicStreamFactoryTestBase,
- public ::testing::TestWithParam<PoolingTestParams> {
- protected:
- QuicStreamFactoryWithDestinationTest()
- : QuicStreamFactoryTestBase(GetParam().version,
- GetParam().enable_connection_racing),
- destination_type_(GetParam().destination_type),
- hanging_read_(SYNCHRONOUS, ERR_IO_PENDING, 0) {}
-
- HostPortPair GetDestination() {
- switch (destination_type_) {
- case SAME_AS_FIRST:
- return origin1_;
- case SAME_AS_SECOND:
- return origin2_;
- case DIFFERENT:
- return HostPortPair(kDifferentHostname, 443);
- default:
- NOTREACHED();
- return HostPortPair();
- }
- }
-
- void AddHangingSocketData() {
- std::unique_ptr<SequencedSocketData> sequenced_socket_data(
- new SequencedSocketData(&hanging_read_, 1, nullptr, 0));
- socket_factory_.AddSocketDataProvider(sequenced_socket_data.get());
- sequenced_socket_data_vector_.push_back(std::move(sequenced_socket_data));
- }
-
- bool AllDataConsumed() {
- for (const auto& socket_data_ptr : sequenced_socket_data_vector_) {
- if (!socket_data_ptr->AllReadDataConsumed() ||
- !socket_data_ptr->AllWriteDataConsumed()) {
- return false;
- }
- }
- return true;
- }
-
- DestinationType destination_type_;
- HostPortPair origin1_;
- HostPortPair origin2_;
- MockRead hanging_read_;
- vector<std::unique_ptr<SequencedSocketData>> sequenced_socket_data_vector_;
-};
-
-INSTANTIATE_TEST_CASE_P(Version,
- QuicStreamFactoryWithDestinationTest,
- ::testing::ValuesIn(GetPoolingTestParams()));
-
-// A single QUIC request fails because the certificate does not match the origin
-// hostname, regardless of whether it matches the alternative service hostname.
-TEST_P(QuicStreamFactoryWithDestinationTest, InvalidCertificate) {
- if (destination_type_ == DIFFERENT)
- return;
-
- Initialize();
-
- GURL url("https://mail.example.com/");
- origin1_ = HostPortPair::FromURL(url);
-
- // Not used for requests, but this provides a test case where the certificate
- // is valid for the hostname of the alternative service.
- origin2_ = HostPortPair("mail.example.org", 433);
-
- HostPortPair destination = GetDestination();
-
- scoped_refptr<X509Certificate> cert(
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
- bool unused;
- ASSERT_FALSE(cert->VerifyNameMatch(origin1_.host(), &unused));
- ASSERT_TRUE(cert->VerifyNameMatch(origin2_.host(), &unused));
-
- 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);
-
- AddHangingSocketData();
-
- QuicStreamRequest request(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING, request.Request(destination, privacy_mode_,
- /*cert_verify_flags=*/0, url, "GET",
- net_log_, callback_.callback()));
-
- EXPECT_EQ(ERR_QUIC_HANDSHAKE_FAILED, callback_.WaitForResult());
-
- EXPECT_TRUE(AllDataConsumed());
-}
-
-// QuicStreamRequest is pooled based on |destination| if certificate matches.
-TEST_P(QuicStreamFactoryWithDestinationTest, SharedCertificate) {
- Initialize();
-
- GURL url1("https://www.example.org/");
- GURL url2("https://mail.example.org/");
- origin1_ = HostPortPair::FromURL(url1);
- origin2_ = HostPortPair::FromURL(url2);
-
- HostPortPair destination = GetDestination();
-
- scoped_refptr<X509Certificate> cert(
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
- bool unused;
- ASSERT_TRUE(cert->VerifyNameMatch(origin1_.host(), &unused));
- ASSERT_TRUE(cert->VerifyNameMatch(origin2_.host(), &unused));
- ASSERT_FALSE(cert->VerifyNameMatch(kDifferentHostname, &unused));
-
- 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);
-
- AddHangingSocketData();
-
- QuicStreamRequest request1(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request1.Request(destination, privacy_mode_,
- /*cert_verify_flags=*/0, url1, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream1 = request1.CreateStream();
- EXPECT_TRUE(stream1.get());
- EXPECT_TRUE(HasActiveSession(origin1_));
-
- // Second request returns synchronously because it pools to existing session.
- TestCompletionCallback callback2;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(OK, request2.Request(destination, privacy_mode_,
- /*cert_verify_flags=*/0, url2, "GET", net_log_,
- callback2.callback()));
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- QuicChromiumClientSession* session1 =
- QuicHttpStreamPeer::GetSession(stream1.get());
- QuicChromiumClientSession* session2 =
- QuicHttpStreamPeer::GetSession(stream2.get());
- EXPECT_EQ(session1, session2);
-
- EXPECT_EQ(QuicServerId(origin1_, privacy_mode_), session1->server_id());
-
- EXPECT_TRUE(AllDataConsumed());
-}
-
-// QuicStreamRequest is not pooled if PrivacyMode differs.
-TEST_P(QuicStreamFactoryWithDestinationTest, DifferentPrivacyMode) {
- Initialize();
-
- GURL url1("https://www.example.org/");
- GURL url2("https://mail.example.org/");
- origin1_ = HostPortPair::FromURL(url1);
- origin2_ = HostPortPair::FromURL(url2);
-
- HostPortPair destination = GetDestination();
-
- scoped_refptr<X509Certificate> cert(
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
- bool unused;
- ASSERT_TRUE(cert->VerifyNameMatch(origin1_.host(), &unused));
- ASSERT_TRUE(cert->VerifyNameMatch(origin2_.host(), &unused));
- ASSERT_FALSE(cert->VerifyNameMatch(kDifferentHostname, &unused));
-
- ProofVerifyDetailsChromium verify_details1;
- verify_details1.cert_verify_result.verified_cert = cert;
- verify_details1.cert_verify_result.is_issued_by_known_root = true;
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details1);
-
- ProofVerifyDetailsChromium verify_details2;
- verify_details2.cert_verify_result.verified_cert = cert;
- verify_details2.cert_verify_result.is_issued_by_known_root = true;
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2);
-
- AddHangingSocketData();
- AddHangingSocketData();
-
- QuicStreamRequest request1(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request1.Request(destination, PRIVACY_MODE_DISABLED,
- /*cert_verify_flags=*/0, url1, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream1 = request1.CreateStream();
- EXPECT_TRUE(stream1.get());
- EXPECT_TRUE(HasActiveSession(origin1_));
-
- TestCompletionCallback callback2;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request2.Request(destination, PRIVACY_MODE_ENABLED,
- /*cert_verify_flags=*/0, url2, "GET", net_log_,
- callback2.callback()));
- EXPECT_EQ(OK, callback2.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- // |request2| does not pool to the first session, because PrivacyMode does not
- // match. Instead, another session is opened to the same destination, but
- // with a different QuicServerId.
- QuicChromiumClientSession* session1 =
- QuicHttpStreamPeer::GetSession(stream1.get());
- QuicChromiumClientSession* session2 =
- QuicHttpStreamPeer::GetSession(stream2.get());
- EXPECT_NE(session1, session2);
-
- EXPECT_EQ(QuicServerId(origin1_, PRIVACY_MODE_DISABLED),
- session1->server_id());
- EXPECT_EQ(QuicServerId(origin2_, PRIVACY_MODE_ENABLED),
- session2->server_id());
-
- EXPECT_TRUE(AllDataConsumed());
-}
-
-// QuicStreamRequest is not pooled if certificate does not match its origin.
-TEST_P(QuicStreamFactoryWithDestinationTest, DisjointCertificate) {
- Initialize();
-
- GURL url1("https://news.example.org/");
- GURL url2("https://mail.example.com/");
- origin1_ = HostPortPair::FromURL(url1);
- origin2_ = HostPortPair::FromURL(url2);
-
- HostPortPair destination = GetDestination();
-
- scoped_refptr<X509Certificate> cert1(
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
- bool unused;
- ASSERT_TRUE(cert1->VerifyNameMatch(origin1_.host(), &unused));
- ASSERT_FALSE(cert1->VerifyNameMatch(origin2_.host(), &unused));
- ASSERT_FALSE(cert1->VerifyNameMatch(kDifferentHostname, &unused));
-
- ProofVerifyDetailsChromium verify_details1;
- verify_details1.cert_verify_result.verified_cert = cert1;
- verify_details1.cert_verify_result.is_issued_by_known_root = true;
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details1);
-
- scoped_refptr<X509Certificate> cert2(
- ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"));
- ASSERT_TRUE(cert2->VerifyNameMatch(origin2_.host(), &unused));
- ASSERT_FALSE(cert2->VerifyNameMatch(kDifferentHostname, &unused));
-
- ProofVerifyDetailsChromium verify_details2;
- verify_details2.cert_verify_result.verified_cert = cert2;
- verify_details2.cert_verify_result.is_issued_by_known_root = true;
- crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2);
-
- AddHangingSocketData();
- AddHangingSocketData();
-
- QuicStreamRequest request1(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request1.Request(destination, privacy_mode_,
- /*cert_verify_flags=*/0, url1, "GET", net_log_,
- callback_.callback()));
- EXPECT_EQ(OK, callback_.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream1 = request1.CreateStream();
- EXPECT_TRUE(stream1.get());
- EXPECT_TRUE(HasActiveSession(origin1_));
-
- TestCompletionCallback callback2;
- QuicStreamRequest request2(factory_.get());
- EXPECT_EQ(ERR_IO_PENDING,
- request2.Request(destination, privacy_mode_,
- /*cert_verify_flags=*/0, url2, "GET", net_log_,
- callback2.callback()));
- EXPECT_EQ(OK, callback2.WaitForResult());
- std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
- EXPECT_TRUE(stream2.get());
-
- // |request2| does not pool to the first session, because the certificate does
- // not match. Instead, another session is opened to the same destination, but
- // with a different QuicServerId.
- QuicChromiumClientSession* session1 =
- QuicHttpStreamPeer::GetSession(stream1.get());
- QuicChromiumClientSession* session2 =
- QuicHttpStreamPeer::GetSession(stream2.get());
- EXPECT_NE(session1, session2);
-
- EXPECT_EQ(QuicServerId(origin1_, privacy_mode_), session1->server_id());
- EXPECT_EQ(QuicServerId(origin2_, privacy_mode_), session2->server_id());
-
- EXPECT_TRUE(AllDataConsumed());
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_stream_sequencer.cc b/chromium/net/quic/quic_stream_sequencer.cc
deleted file mode 100644
index da26cc52fa9..00000000000
--- a/chromium/net/quic/quic_stream_sequencer.cc
+++ /dev/null
@@ -1,205 +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/quic_stream_sequencer.h"
-
-#include <algorithm>
-#include <limits>
-#include <string>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_stream_sequencer_buffer.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/reliable_quic_stream.h"
-
-using base::StringPiece;
-using std::min;
-using std::numeric_limits;
-using std::string;
-
-namespace net {
-
-QuicStreamSequencer::QuicStreamSequencer(ReliableQuicStream* quic_stream,
- const QuicClock* clock)
- : stream_(quic_stream),
- buffered_frames_(kStreamReceiveWindowLimit),
- close_offset_(numeric_limits<QuicStreamOffset>::max()),
- blocked_(false),
- num_frames_received_(0),
- num_duplicate_frames_received_(0),
- num_early_frames_received_(0),
- clock_(clock),
- ignore_read_data_(false) {}
-
-QuicStreamSequencer::~QuicStreamSequencer() {}
-
-void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) {
- ++num_frames_received_;
- const QuicStreamOffset byte_offset = frame.offset;
- const size_t data_len = frame.data_length;
-
- if (frame.fin) {
- CloseStreamAtOffset(frame.offset + data_len);
- if (data_len == 0) {
- return;
- }
- }
- size_t bytes_written;
- string error_details;
- QuicErrorCode result = buffered_frames_.OnStreamData(
- byte_offset, StringPiece(frame.data_buffer, frame.data_length),
- clock_->ApproximateNow(), &bytes_written, &error_details);
- if (result != QUIC_NO_ERROR) {
- string details = "Stream" + base::Uint64ToString(stream_->id()) + ": " +
- QuicUtils::ErrorToString(result) + ": " + error_details +
- "\nPeer Address: " +
- stream_->PeerAddressOfLatestPacket().ToString();
- DLOG(WARNING) << QuicUtils::ErrorToString(result);
- DLOG(WARNING) << details;
- stream_->CloseConnectionWithDetails(result, details);
- return;
- }
-
- if (bytes_written == 0) {
- ++num_duplicate_frames_received_;
- // Silently ignore duplicates.
- return;
- }
-
- if (byte_offset > buffered_frames_.BytesConsumed()) {
- ++num_early_frames_received_;
- }
-
- if (blocked_) {
- return;
- }
-
- if (byte_offset == buffered_frames_.BytesConsumed()) {
- if (ignore_read_data_) {
- FlushBufferedFrames();
- } else {
- stream_->OnDataAvailable();
- }
- }
-}
-
-void QuicStreamSequencer::CloseStreamAtOffset(QuicStreamOffset offset) {
- const QuicStreamOffset kMaxOffset = numeric_limits<QuicStreamOffset>::max();
-
- // If there is a scheduled close, the new offset should match it.
- if (close_offset_ != kMaxOffset && offset != close_offset_) {
- stream_->Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS);
- return;
- }
-
- close_offset_ = offset;
-
- MaybeCloseStream();
-}
-
-bool QuicStreamSequencer::MaybeCloseStream() {
- if (blocked_ || !IsClosed()) {
- return false;
- }
-
- DVLOG(1) << "Passing up termination, as we've processed "
- << buffered_frames_.BytesConsumed() << " of " << close_offset_
- << " bytes.";
- // This will cause the stream to consume the FIN.
- // Technically it's an error if |num_bytes_consumed| isn't exactly
- // equal to |close_offset|, but error handling seems silly at this point.
- if (ignore_read_data_) {
- // The sequencer is discarding stream data and must notify the stream on
- // receipt of a FIN because the consumer won't.
- stream_->OnFinRead();
- } else {
- stream_->OnDataAvailable();
- }
- buffered_frames_.Clear();
- return true;
-}
-
-int QuicStreamSequencer::GetReadableRegions(iovec* iov, size_t iov_len) const {
- DCHECK(!blocked_);
- return buffered_frames_.GetReadableRegions(iov, iov_len);
-}
-
-bool QuicStreamSequencer::GetReadableRegion(iovec* iov,
- QuicTime* timestamp) const {
- DCHECK(!blocked_);
- return buffered_frames_.GetReadableRegion(iov, timestamp);
-}
-
-int QuicStreamSequencer::Readv(const struct iovec* iov, size_t iov_len) {
- DCHECK(!blocked_);
- size_t bytes_read = buffered_frames_.Readv(iov, iov_len);
- stream_->AddBytesConsumed(bytes_read);
- return static_cast<int>(bytes_read);
-}
-
-bool QuicStreamSequencer::HasBytesToRead() const {
- return buffered_frames_.HasBytesToRead();
-}
-
-bool QuicStreamSequencer::IsClosed() const {
- return buffered_frames_.BytesConsumed() >= close_offset_;
-}
-
-void QuicStreamSequencer::MarkConsumed(size_t num_bytes_consumed) {
- DCHECK(!blocked_);
- bool result = buffered_frames_.MarkConsumed(num_bytes_consumed);
- if (!result) {
- QUIC_BUG << "Invalid argument to MarkConsumed."
- << " expect to consume: " << num_bytes_consumed
- << ", but not enough bytes available.";
- stream_->Reset(QUIC_ERROR_PROCESSING_STREAM);
- return;
- }
- stream_->AddBytesConsumed(num_bytes_consumed);
-}
-
-void QuicStreamSequencer::SetBlockedUntilFlush() {
- blocked_ = true;
-}
-
-void QuicStreamSequencer::SetUnblocked() {
- blocked_ = false;
- if (IsClosed() || HasBytesToRead()) {
- stream_->OnDataAvailable();
- }
-}
-
-void QuicStreamSequencer::StopReading() {
- if (ignore_read_data_) {
- return;
- }
- ignore_read_data_ = true;
- FlushBufferedFrames();
-}
-
-void QuicStreamSequencer::FlushBufferedFrames() {
- DCHECK(ignore_read_data_);
- size_t bytes_flushed = buffered_frames_.FlushBufferedFrames();
- DVLOG(1) << "Flushing buffered data at offset "
- << buffered_frames_.BytesConsumed() << " length " << bytes_flushed
- << " for stream " << stream_->id();
- stream_->AddBytesConsumed(bytes_flushed);
- MaybeCloseStream();
-}
-
-size_t QuicStreamSequencer::NumBytesBuffered() const {
- return buffered_frames_.BytesBuffered();
-}
-
-QuicStreamOffset QuicStreamSequencer::NumBytesConsumed() const {
- return buffered_frames_.BytesConsumed();
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_stream_sequencer.h b/chromium/net/quic/quic_stream_sequencer.h
deleted file mode 100644
index 3f37a7ec35f..00000000000
--- a/chromium/net/quic/quic_stream_sequencer.h
+++ /dev/null
@@ -1,147 +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.
-
-#ifndef NET_QUIC_QUIC_STREAM_SEQUENCER_H_
-#define NET_QUIC_QUIC_STREAM_SEQUENCER_H_
-
-#include <stddef.h>
-
-#include <map>
-
-#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_stream_sequencer_buffer.h"
-
-namespace net {
-
-namespace test {
-class QuicStreamSequencerPeer;
-} // namespace test
-
-class QuicClock;
-class QuicSession;
-class ReliableQuicStream;
-
-// Buffers frames until we have something which can be passed
-// up to the next layer.
-class NET_EXPORT_PRIVATE QuicStreamSequencer {
- public:
- QuicStreamSequencer(ReliableQuicStream* quic_stream, const QuicClock* clock);
- virtual ~QuicStreamSequencer();
-
- // If the frame is the next one we need in order to process in-order data,
- // ProcessData will be immediately called on the stream until all buffered
- // data is processed or the stream fails to consume data. Any unconsumed
- // data will be buffered. If the frame is not the next in line, it will be
- // buffered.
- void OnStreamFrame(const QuicStreamFrame& frame);
-
- // Once data is buffered, it's up to the stream to read it when the stream
- // can handle more data. The following three functions make that possible.
-
- // Fills in up to iov_len iovecs with the next readable regions. Returns the
- // number of iovs used. Non-destructive of the underlying data.
- int GetReadableRegions(iovec* iov, size_t iov_len) const;
-
- // Fills in one iovec with the next readable region. |timestamp| is
- // data arrived at the sequencer, and is used for measuring head of
- // line blocking (HOL). Returns false if there is no readable
- // region available.
- bool GetReadableRegion(iovec* iov, QuicTime* timestamp) const;
-
- // Copies the data into the iov_len buffers provided. Returns the number of
- // bytes read. Any buffered data no longer in use will be released.
- // TODO(rch): remove this method and instead implement it as a helper method
- // based on GetReadableRegions and MarkConsumed.
- int Readv(const struct iovec* iov, size_t iov_len);
-
- // Consumes |num_bytes| data. Used in conjunction with |GetReadableRegions|
- // to do zero-copy reads.
- void MarkConsumed(size_t num_bytes);
-
- // Returns true if the sequncer has bytes available for reading.
- bool HasBytesToRead() const;
-
- // Returns true if the sequencer has delivered the fin.
- bool IsClosed() const;
-
- // Calls |OnDataAvailable| on |stream_| if there is buffered data that can
- // be processed, and causes |OnDataAvailable| to be called as new data
- // arrives.
- void SetUnblocked();
-
- // Blocks processing of frames until |SetUnblocked| is called.
- void SetBlockedUntilFlush();
-
- // Sets the sequencer to discard all incoming data itself and not call
- // |stream_->OnDataAvailable()|. |stream_->OnFinRead()| will be called
- // automatically when the FIN is consumed (which may be immediately).
- void StopReading();
-
- // Number of bytes in the buffer right now.
- size_t NumBytesBuffered() const;
-
- // Number of bytes has been consumed.
- QuicStreamOffset NumBytesConsumed() const;
-
- int num_frames_received() const { return num_frames_received_; }
-
- int num_duplicate_frames_received() const {
- return num_duplicate_frames_received_;
- }
-
- int num_early_frames_received() const { return num_early_frames_received_; }
-
- bool ignore_read_data() const { return ignore_read_data_; }
-
- private:
- friend class test::QuicStreamSequencerPeer;
-
- // Deletes and records as consumed any buffered data that is now in-sequence.
- // (To be called only after StopReading has been called.)
- void FlushBufferedFrames();
-
- // Wait until we've seen 'offset' bytes, and then terminate the stream.
- void CloseStreamAtOffset(QuicStreamOffset offset);
-
- // If we've received a FIN and have processed all remaining data, then inform
- // the stream of FIN, and clear buffers.
- bool MaybeCloseStream();
-
- // The stream which owns this sequencer.
- ReliableQuicStream* stream_;
-
- // Stores received data in offset order.
- QuicStreamSequencerBuffer buffered_frames_;
-
- // The offset, if any, we got a stream termination for. When this many bytes
- // have been processed, the sequencer will be closed.
- QuicStreamOffset close_offset_;
-
- // If true, the sequencer is blocked from passing data to the stream and will
- // buffer all new incoming data until FlushBufferedFrames is called.
- bool blocked_;
-
- // Count of the number of frames received.
- int num_frames_received_;
-
- // Count of the number of duplicate frames received.
- int num_duplicate_frames_received_;
-
- // Count of the number of frames received before all previous frames were
- // received.
- int num_early_frames_received_;
-
- // Not owned.
- const QuicClock* clock_;
-
- // If true, all incoming data will be discarded.
- bool ignore_read_data_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicStreamSequencer);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_STREAM_SEQUENCER_H_
diff --git a/chromium/net/quic/quic_stream_sequencer_buffer.cc b/chromium/net/quic/quic_stream_sequencer_buffer.cc
deleted file mode 100644
index 352db230dc6..00000000000
--- a/chromium/net/quic/quic_stream_sequencer_buffer.cc
+++ /dev/null
@@ -1,505 +0,0 @@
-// 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.
-
-#include "net/quic/quic_stream_sequencer_buffer.h"
-
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "net/quic/quic_bug_tracker.h"
-
-using std::min;
-using std::string;
-
-namespace net {
-
-namespace {
-
-string RangeDebugString(QuicStreamOffset start, QuicStreamOffset end) {
- return string("[") + base::Uint64ToString(start) + ", " +
- base::Uint64ToString(end) + ") ";
-}
-
-} // namespace
-
-QuicStreamSequencerBuffer::Gap::Gap(QuicStreamOffset begin_offset,
- QuicStreamOffset end_offset)
- : begin_offset(begin_offset), end_offset(end_offset) {}
-
-QuicStreamSequencerBuffer::FrameInfo::FrameInfo()
- : length(1), timestamp(QuicTime::Zero()) {}
-
-QuicStreamSequencerBuffer::FrameInfo::FrameInfo(size_t length,
- QuicTime timestamp)
- : length(length), timestamp(timestamp) {}
-
-QuicStreamSequencerBuffer::QuicStreamSequencerBuffer(size_t max_capacity_bytes)
- : max_buffer_capacity_bytes_(max_capacity_bytes),
- blocks_count_(
- ceil(static_cast<double>(max_capacity_bytes) / kBlockSizeBytes)),
- total_bytes_read_(0),
- blocks_(blocks_count_) {
- Clear();
-}
-
-QuicStreamSequencerBuffer::~QuicStreamSequencerBuffer() {
- Clear();
-}
-
-void QuicStreamSequencerBuffer::Clear() {
- for (size_t i = 0; i < blocks_count_; ++i) {
- if (blocks_[i] != nullptr) {
- RetireBlock(i);
- }
- }
- 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())),
- frame_arrival_time_map_.clear();
-}
-
-void QuicStreamSequencerBuffer::RetireBlock(size_t idx) {
- DCHECK(blocks_[idx] != nullptr);
- delete blocks_[idx];
- blocks_[idx] = nullptr;
- DVLOG(1) << "Retired block with index: " << idx;
-}
-
-QuicErrorCode QuicStreamSequencerBuffer::OnStreamData(
- QuicStreamOffset starting_offset,
- base::StringPiece data,
- QuicTime timestamp,
- size_t* const bytes_buffered,
- std::string* error_details) {
- *bytes_buffered = 0;
- QuicStreamOffset offset = starting_offset;
- size_t size = data.size();
- if (size == 0) {
- *error_details = "Received empty stream frame without FIN.";
- return QUIC_EMPTY_STREAM_FRAME_NO_FIN;
- }
-
- // 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.
- std::list<Gap>::iterator current_gap = gaps_.begin();
- while (current_gap != gaps_.end() && current_gap->end_offset <= offset) {
- ++current_gap;
- }
-
- DCHECK(current_gap != gaps_.end());
-
- // "duplication": might duplicate with data alread filled,but also might
- // overlap across different base::StringPiece objects already written.
- // In both cases, don't write the data,
- // and allow the caller of this method to handle the result.
- if (offset < current_gap->begin_offset &&
- offset + size <= current_gap->begin_offset) {
- DVLOG(1) << "Duplicated data at offset: " << offset << " length: " << size;
- return QUIC_NO_ERROR;
- }
- if (offset < current_gap->begin_offset &&
- offset + size > current_gap->begin_offset) {
- // Beginning of new data overlaps data before current gap.
- *error_details =
- string("Beginning of received data overlaps with buffered data.\n") +
- "New frame range " + RangeDebugString(offset, offset + size) +
- " with first 128 bytes: " +
- string(data.data(), data.length() < 128 ? data.length() : 128) +
- "\nCurrently received frames: " + ReceivedFramesDebugString() +
- "\nCurrent gaps: " + GapsDebugString();
- return QUIC_OVERLAPPING_STREAM_DATA;
- }
- if (offset + size > current_gap->end_offset) {
- // End of new data overlaps with data after current gap.
- *error_details =
- string("End of received data overlaps with buffered data.\n") +
- "New frame range " + RangeDebugString(offset, offset + size) +
- " with first 128 bytes: " +
- string(data.data(), data.length() < 128 ? data.length() : 128) +
- "\nCurrently received frames: " + ReceivedFramesDebugString() +
- "\nCurrent gaps: " + GapsDebugString();
- return QUIC_OVERLAPPING_STREAM_DATA;
- }
-
- // Write beyond the current range this buffer is covering.
- if (offset + size > total_bytes_read_ + max_buffer_capacity_bytes_) {
- *error_details = "Received data beyond available range.";
- return QUIC_INTERNAL_ERROR;
- }
-
- size_t total_written = 0;
- size_t source_remaining = size;
- const char* source = data.data();
- // Write data block by block. If corresponding block has not created yet,
- // create it first.
- // Stop when all data are written or reaches the logical end of the buffer.
- while (source_remaining > 0) {
- const size_t write_block_num = GetBlockIndex(offset);
- const size_t write_block_offset = GetInBlockOffset(offset);
- DCHECK_GT(blocks_count_, write_block_num);
-
- size_t block_capacity = GetBlockCapacity(write_block_num);
- size_t bytes_avail = block_capacity - write_block_offset;
-
- // If this write meets the upper boundary of the buffer,
- // reduce the available free bytes.
- if (offset + bytes_avail > total_bytes_read_ + max_buffer_capacity_bytes_) {
- bytes_avail = total_bytes_read_ + max_buffer_capacity_bytes_ - offset;
- }
-
- if (blocks_[write_block_num] == nullptr) {
- // TODO(danzh): Investigate if using a freelist would improve performance.
- // Same as RetireBlock().
- blocks_[write_block_num] = new BufferBlock();
- }
-
- const size_t bytes_to_copy = min<size_t>(bytes_avail, source_remaining);
- char* dest = blocks_[write_block_num]->buffer + write_block_offset;
- DVLOG(1) << "Write at offset: " << offset << " length: " << bytes_to_copy;
- memcpy(dest, source, bytes_to_copy);
- source += bytes_to_copy;
- source_remaining -= bytes_to_copy;
- offset += bytes_to_copy;
- total_written += bytes_to_copy;
- }
-
- DCHECK_GT(total_written, 0u);
- *bytes_buffered = total_written;
- UpdateGapList(current_gap, starting_offset, total_written);
-
- frame_arrival_time_map_.insert(
- std::make_pair(starting_offset, FrameInfo(size, timestamp)));
- num_bytes_buffered_ += total_written;
- return QUIC_NO_ERROR;
-}
-
-inline void QuicStreamSequencerBuffer::UpdateGapList(
- std::list<Gap>::iterator gap_with_new_data_written,
- QuicStreamOffset start_offset,
- size_t bytes_written) {
- if (gap_with_new_data_written->begin_offset == start_offset &&
- gap_with_new_data_written->end_offset > start_offset + bytes_written) {
- // New data has been written into the left part of the buffer.
- gap_with_new_data_written->begin_offset = start_offset + bytes_written;
- } else if (gap_with_new_data_written->begin_offset < start_offset &&
- gap_with_new_data_written->end_offset ==
- start_offset + bytes_written) {
- // New data has been written into the right part of the buffer.
- gap_with_new_data_written->end_offset = start_offset;
- } else if (gap_with_new_data_written->begin_offset < start_offset &&
- gap_with_new_data_written->end_offset >
- start_offset + bytes_written) {
- // New data has been written into the middle of the buffer.
- auto current = gap_with_new_data_written++;
- QuicStreamOffset current_end = current->end_offset;
- current->end_offset = start_offset;
- gaps_.insert(gap_with_new_data_written,
- Gap(start_offset + bytes_written, current_end));
- } else if (gap_with_new_data_written->begin_offset == start_offset &&
- gap_with_new_data_written->end_offset ==
- start_offset + bytes_written) {
- // This gap has been filled with new data. So it's no longer a gap.
- gaps_.erase(gap_with_new_data_written);
- }
-}
-
-size_t QuicStreamSequencerBuffer::Readv(const iovec* dest_iov,
- size_t dest_count) {
- size_t bytes_read = 0;
- for (size_t i = 0; i < dest_count && ReadableBytes() > 0; ++i) {
- char* dest = reinterpret_cast<char*>(dest_iov[i].iov_base);
- size_t dest_remaining = dest_iov[i].iov_len;
- while (dest_remaining > 0 && ReadableBytes() > 0) {
- size_t block_idx = NextBlockToRead();
- size_t start_offset_in_block = ReadOffset();
- size_t block_capacity = GetBlockCapacity(block_idx);
- size_t bytes_available_in_block =
- min<size_t>(ReadableBytes(), block_capacity - start_offset_in_block);
- size_t bytes_to_copy =
- min<size_t>(bytes_available_in_block, dest_remaining);
- DCHECK_GT(bytes_to_copy, 0u);
- DCHECK_NE(static_cast<BufferBlock*>(nullptr), blocks_[block_idx]);
- memcpy(dest, blocks_[block_idx]->buffer + start_offset_in_block,
- bytes_to_copy);
- dest += bytes_to_copy;
- dest_remaining -= bytes_to_copy;
- num_bytes_buffered_ -= bytes_to_copy;
- total_bytes_read_ += bytes_to_copy;
- bytes_read += bytes_to_copy;
-
- // Retire the block if all the data is read out
- // and no other data is stored in this block.
- if (bytes_to_copy == bytes_available_in_block) {
- RetireBlockIfEmpty(block_idx);
- }
- }
- }
-
- if (bytes_read > 0) {
- UpdateFrameArrivalMap(total_bytes_read_);
- }
- return bytes_read;
-}
-
-int QuicStreamSequencerBuffer::GetReadableRegions(struct iovec* iov,
- int iov_count) const {
- DCHECK(iov != nullptr);
- DCHECK_GT(iov_count, 0);
-
- if (ReadableBytes() == 0) {
- iov[0].iov_base = nullptr;
- iov[0].iov_len = 0;
- return 0;
- }
-
- size_t start_block_idx = NextBlockToRead();
- QuicStreamOffset readable_offset_end = gaps_.front().begin_offset - 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);
-
- // If readable region is within one block, deal with it seperately.
- if (start_block_idx == end_block_idx && ReadOffset() <= end_block_offset) {
- iov[0].iov_base = blocks_[start_block_idx]->buffer + ReadOffset();
- iov[0].iov_len = ReadableBytes();
- DVLOG(1) << "Got only a single block with index: " << start_block_idx;
- return 1;
- }
-
- // Get first block
- iov[0].iov_base = blocks_[start_block_idx]->buffer + ReadOffset();
- iov[0].iov_len = GetBlockCapacity(start_block_idx) - ReadOffset();
- DVLOG(1) << "Got first block " << start_block_idx << " with len "
- << iov[0].iov_len;
- DCHECK_GT(readable_offset_end + 1, total_bytes_read_ + iov[0].iov_len)
- << "there should be more available data";
-
- // Get readable regions of the rest blocks till either 2nd to last block
- // before gap is met or |iov| is filled. For these blocks, one whole block is
- // a region.
- int iov_used = 1;
- size_t block_idx = (start_block_idx + iov_used) % blocks_count_;
- while (block_idx != end_block_idx && iov_used < iov_count) {
- DCHECK_NE(static_cast<BufferBlock*>(nullptr), blocks_[block_idx]);
- iov[iov_used].iov_base = blocks_[block_idx]->buffer;
- iov[iov_used].iov_len = GetBlockCapacity(block_idx);
- DVLOG(1) << "Got block with index: " << block_idx;
- ++iov_used;
- block_idx = (start_block_idx + iov_used) % blocks_count_;
- }
-
- // Deal with last block if |iov| can hold more.
- if (iov_used < iov_count) {
- DCHECK_NE(static_cast<BufferBlock*>(nullptr), blocks_[block_idx]);
- iov[iov_used].iov_base = blocks_[end_block_idx]->buffer;
- iov[iov_used].iov_len = end_block_offset + 1;
- DVLOG(1) << "Got last block with index: " << end_block_idx;
- ++iov_used;
- }
- return iov_used;
-}
-
-bool QuicStreamSequencerBuffer::GetReadableRegion(iovec* iov,
- QuicTime* timestamp) const {
- if (ReadableBytes() == 0) {
- iov[0].iov_base = nullptr;
- iov[0].iov_len = 0;
- return false;
- }
-
- size_t start_block_idx = NextBlockToRead();
- iov->iov_base = blocks_[start_block_idx]->buffer + ReadOffset();
- size_t readable_bytes_in_block = min<size_t>(
- GetBlockCapacity(start_block_idx) - ReadOffset(), ReadableBytes());
- size_t region_len = 0;
- auto iter = frame_arrival_time_map_.begin();
- *timestamp = iter->second.timestamp;
- DVLOG(1) << "Readable bytes in block: " << readable_bytes_in_block;
- for (; iter != frame_arrival_time_map_.end() &&
- region_len + iter->second.length <= readable_bytes_in_block;
- ++iter) {
- if (iter->second.timestamp != *timestamp) {
- // If reaches a frame arrive at another timestamp, stop expanding current
- // region.
- DVLOG(1) << "Meet frame with different timestamp.";
- break;
- }
- region_len += iter->second.length;
- DVLOG(1) << "Added bytes to region: " << iter->second.length;
- }
- if (iter == frame_arrival_time_map_.end() ||
- iter->second.timestamp == *timestamp) {
- // If encountered the end of readable bytes before reaching a different
- // timestamp.
- DVLOG(1) << "Got all readable bytes in first block.";
- region_len = readable_bytes_in_block;
- }
- iov->iov_len = region_len;
- return true;
-}
-
-bool QuicStreamSequencerBuffer::MarkConsumed(size_t bytes_used) {
- if (bytes_used > ReadableBytes()) {
- return false;
- }
- size_t bytes_to_consume = bytes_used;
- while (bytes_to_consume > 0) {
- size_t block_idx = NextBlockToRead();
- size_t offset_in_block = ReadOffset();
- size_t bytes_available = min<size_t>(
- ReadableBytes(), GetBlockCapacity(block_idx) - offset_in_block);
- size_t bytes_read = min<size_t>(bytes_to_consume, bytes_available);
- total_bytes_read_ += bytes_read;
- num_bytes_buffered_ -= bytes_read;
- bytes_to_consume -= bytes_read;
- // If advanced to the end of current block and end of buffer hasn't wrapped
- // to this block yet.
- if (bytes_available == bytes_read) {
- RetireBlockIfEmpty(block_idx);
- }
- }
- if (bytes_used > 0) {
- UpdateFrameArrivalMap(total_bytes_read_);
- }
- return true;
-}
-
-size_t QuicStreamSequencerBuffer::FlushBufferedFrames() {
- size_t prev_total_bytes_read = total_bytes_read_;
- total_bytes_read_ = gaps_.back().begin_offset;
- Clear();
- return total_bytes_read_ - prev_total_bytes_read;
-}
-
-size_t QuicStreamSequencerBuffer::ReadableBytes() const {
- return gaps_.front().begin_offset - total_bytes_read_;
-}
-
-bool QuicStreamSequencerBuffer::HasBytesToRead() const {
- return ReadableBytes() > 0;
-}
-
-QuicStreamOffset QuicStreamSequencerBuffer::BytesConsumed() const {
- return total_bytes_read_;
-}
-
-size_t QuicStreamSequencerBuffer::BytesBuffered() const {
- return num_bytes_buffered_;
-}
-
-size_t QuicStreamSequencerBuffer::GetBlockIndex(QuicStreamOffset offset) const {
- return (offset % max_buffer_capacity_bytes_) / kBlockSizeBytes;
-}
-
-size_t QuicStreamSequencerBuffer::GetInBlockOffset(
- QuicStreamOffset offset) const {
- return (offset % max_buffer_capacity_bytes_) % kBlockSizeBytes;
-}
-
-size_t QuicStreamSequencerBuffer::ReadOffset() const {
- return GetInBlockOffset(total_bytes_read_);
-}
-
-size_t QuicStreamSequencerBuffer::NextBlockToRead() const {
- return GetBlockIndex(total_bytes_read_);
-}
-
-void QuicStreamSequencerBuffer::RetireBlockIfEmpty(size_t block_index) {
- DCHECK(ReadableBytes() == 0 || GetInBlockOffset(total_bytes_read_) == 0)
- << "RetireBlockIfEmpty() should only be called when advancing to next "
- "block"
- " or a gap has been reached.";
- // If the whole buffer becomes empty, the last piece of data has been read.
- if (Empty()) {
- RetireBlock(block_index);
- return;
- }
-
- // 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) {
- return;
- }
-
- // 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_extends_to_infinity =
- (first_gap.end_offset != std::numeric_limits<QuicStreamOffset>::max());
- bool gap_ends_in_this_block =
- (GetBlockIndex(first_gap.end_offset) == block_index);
- if (gap_extends_to_infinity || gap_ends_in_this_block) {
- return;
- }
- }
- RetireBlock(block_index);
-}
-
-bool QuicStreamSequencerBuffer::Empty() const {
- return gaps_.size() == 1 && gaps_.front().begin_offset == total_bytes_read_;
-}
-
-size_t QuicStreamSequencerBuffer::GetBlockCapacity(size_t block_index) const {
- if ((block_index + 1) == blocks_count_) {
- size_t result = max_buffer_capacity_bytes_ % kBlockSizeBytes;
- if (result == 0) { // whole block
- result = kBlockSizeBytes;
- }
- return result;
- } else {
- return kBlockSizeBytes;
- }
-}
-
-void QuicStreamSequencerBuffer::UpdateFrameArrivalMap(QuicStreamOffset offset) {
- // Get the frame before which all frames should be removed.
- auto next_frame = frame_arrival_time_map_.upper_bound(offset);
- DCHECK(next_frame != frame_arrival_time_map_.begin());
- auto iter = frame_arrival_time_map_.begin();
- while (iter != next_frame) {
- auto erased = *iter;
- iter = frame_arrival_time_map_.erase(iter);
- DVLOG(1) << "Removed FrameInfo with offset: " << erased.first
- << " and length: " << erased.second.length;
- if (erased.first + erased.second.length > offset) {
- // If last frame is partially read out, update this FrameInfo and insert
- // it back.
- auto updated = std::make_pair(
- offset, FrameInfo(erased.first + erased.second.length - offset,
- erased.second.timestamp));
- DVLOG(1) << "Inserted FrameInfo with offset: " << updated.first
- << " and length: " << updated.second.length;
- frame_arrival_time_map_.insert(updated);
- }
- }
-}
-
-string QuicStreamSequencerBuffer::GapsDebugString() {
- string current_gaps_string;
- for (const Gap& gap : gaps_) {
- QuicStreamOffset current_gap_begin = gap.begin_offset;
- QuicStreamOffset current_gap_end = gap.end_offset;
- current_gaps_string += RangeDebugString(current_gap_begin, current_gap_end);
- }
- return current_gaps_string;
-}
-
-string QuicStreamSequencerBuffer::ReceivedFramesDebugString() {
- string current_frames_string;
- for (auto it : frame_arrival_time_map_) {
- QuicStreamOffset current_frame_begin_offset = it.first;
- QuicStreamOffset current_frame_end_offset =
- it.second.length + current_frame_begin_offset;
- current_frames_string +=
- RangeDebugString(current_frame_begin_offset, current_frame_end_offset);
- }
- return current_frames_string;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_stream_sequencer_buffer.h b/chromium/net/quic/quic_stream_sequencer_buffer.h
deleted file mode 100644
index f992ea25df7..00000000000
--- a/chromium/net/quic/quic_stream_sequencer_buffer.h
+++ /dev/null
@@ -1,246 +0,0 @@
-// 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.
-
-#ifndef NET_QUIC_QUIC_STREAM_SEQUENCER_BUFFER_H_
-#define NET_QUIC_QUIC_STREAM_SEQUENCER_BUFFER_H_
-
-// QuicStreamSequencerBuffer implements QuicStreamSequencerBufferInterface.
-// It 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.
-// - 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).
-// - Data can be read from the buffer if there is no gap before it,
-// and the buffer shrinks as the data are consumed.
-// - An upper limit on the number of blocks in the buffer provides an upper
-// bound on memory use.
-//
-// This class is thread-unsafe.
-//
-// QuicStreamSequencerBuffer maintains a concept of the readable region, which
-// contains all written data that has not been read.
-// It promises stability of the underlying memory addresses in the readable
-// region, so pointers into it can be maintained, and the offset of a pointer
-// from the start of the read region can be calculated.
-//
-// Expected Use:
-// QuicStreamSequencerBuffer buffer(2.5 * 8 * 1024);
-// std::string source(1024, 'a');
-// base::StringPiece std::string_piece(source.data(), source.size());
-// size_t written = 0;
-// buffer.OnStreamData(800, std::string_piece, GetEpollClockNow(), &written);
-// source = std::string{800, 'b'};
-// base::StringPiece std::string_piece1(source.data(), 800);
-// // Try to write to [1, 801), but should fail due to overlapping,
-// // res should be QUIC_INVALID_STREAM_DATA
-// auto res = buffer.OnStreamData(1, std::string_piece1, &written));
-// // write to [0, 800), res should be QUIC_NO_ERROR
-// auto res = buffer.OnStreamData(0, std::string_piece1, GetEpollClockNow(),
-// &written);
-//
-// // Read into a iovec array with total capacity of 120 bytes.
-// char dest[120];
-// iovec iovecs[3]{iovec{dest, 40}, iovec{dest + 40, 40},
-// iovec{dest + 80, 40}};
-// size_t read = buffer.Readv(iovecs, 3);
-//
-// // Get single readable region with timestamp.
-// QuicTime t;
-// iovec iov;
-// buffer.GetReadableRegion(iov, &t);
-//
-// // Get readable regions from [256, 1024) and consume some of it.
-// iovec iovs[2];
-// int iov_count = buffer.GetReadableRegions(iovs, 2);
-// // Consume some bytes in iovs, returning number of bytes having been
-// consumed.
-// size_t consumed = consume_iovs(iovs, iov_count);
-// buffer.MarkConsumed(consumed);
-
-#include <stddef.h>
-
-#include <functional>
-#include <list>
-#include <memory>
-
-#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-namespace test {
-class QuicStreamSequencerBufferPeer;
-} // namespace test
-
-class NET_EXPORT_PRIVATE QuicStreamSequencerBuffer {
- public:
- // A Gap indicates a missing chunk of bytes between
- // [begin_offset, end_offset) in the stream
- struct NET_EXPORT_PRIVATE Gap {
- Gap(QuicStreamOffset begin_offset, QuicStreamOffset end_offset);
- QuicStreamOffset begin_offset;
- QuicStreamOffset end_offset;
- };
-
- // A FrameInfo stores the length of a frame and the time it arrived.
- struct NET_EXPORT_PRIVATE FrameInfo {
- FrameInfo();
- FrameInfo(size_t length, QuicTime timestamp);
-
- size_t length;
- QuicTime timestamp;
- };
-
- // Size of blocks used by this buffer.
- // Choose 8K to make block large enough to hold multiple frames, each of
- // which could be up to 1.5 KB.
- static const size_t kBlockSizeBytes = 8 * 1024; // 8KB
-
- // The basic storage block used by this buffer.
- struct BufferBlock {
- char buffer[kBlockSizeBytes];
- };
-
- explicit QuicStreamSequencerBuffer(size_t max_capacity_bytes);
- ~QuicStreamSequencerBuffer();
-
- // Free the space used to buffer data.
- void Clear();
-
- // Returns true if there is nothing to read in this buffer.
- bool Empty() const;
-
- // Called to buffer new data received for this stream. If the data was
- // successfully buffered, returns QUIC_NO_ERROR and stores the number of
- // bytes buffered in |bytes_buffered|. Returns an error otherwise.
- // |timestamp| is the time the data arrived.
- QuicErrorCode OnStreamData(QuicStreamOffset offset,
- base::StringPiece data,
- QuicTime timestamp,
- size_t* bytes_buffered,
- std::string* error_details);
-
- // Reads from this buffer into given iovec array, up to number of iov_len
- // iovec objects and returns the number of bytes read.
- size_t Readv(const struct iovec* dest_iov, size_t dest_count);
-
- // Returns the readable region of valid data in iovec format. The readable
- // region is the buffer region where there is valid data not yet read by
- // client.
- // Returns the number of iovec entries in |iov| which were populated.
- // If the region is empty, one iovec entry with 0 length
- // is returned, and the function returns 0. If there are more readable
- // regions than iov_size, the function only processes the first
- // iov_size of them.
- int GetReadableRegions(struct iovec* iov, int iov_len) const;
-
- // Fills in one iovec with data which all arrived at the same time from the
- // next readable region.
- // Populates |timestamp| with the time that this data arrived.
- // Returns false if there is no readable region available.
- bool GetReadableRegion(iovec* iov, QuicTime* timestamp) const;
-
- // Called after GetReadableRegions() to free up |bytes_used| space if these
- // bytes are processed.
- // Pre-requisite: bytes_used <= available bytes to read.
- bool MarkConsumed(size_t bytes_buffered);
-
- // Deletes and records as consumed any buffered data and clear the buffer.
- // (To be called only after sequencer's StopReading has been called.)
- size_t FlushBufferedFrames();
-
- // Whether there are bytes can be read out.
- bool HasBytesToRead() const;
-
- // Count how many bytes have been consumed (read out of buffer).
- QuicStreamOffset BytesConsumed() const;
-
- // Count how many bytes are in buffer at this moment.
- size_t BytesBuffered() const;
-
- private:
- friend class test::QuicStreamSequencerBufferPeer;
-
- // Dispose the given buffer block.
- // After calling this method, blocks_[index] is set to nullptr
- // in order to indicate that no memory set is allocated for that block.
- void 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.
- // If the block at |block_index| contains no buffered data, then the block is
- // retired.
- void RetireBlockIfEmpty(size_t block_index);
-
- // Called within OnStreamData() to update the gap OnStreamData() writes into
- // (remove, split or change begin/end offset).
- void UpdateGapList(std::list<Gap>::iterator gap_with_new_data_written,
- QuicStreamOffset start_offset,
- size_t bytes_written);
-
- // Calculate the capacity of block at specified index.
- // Return value should be either kBlockSizeBytes for non-trailing blocks and
- // max_buffer_capacity % kBlockSizeBytes for trailing block.
- size_t GetBlockCapacity(size_t index) const;
-
- // Does not check if offset is within reasonable range.
- size_t GetBlockIndex(QuicStreamOffset offset) const;
-
- // Given an offset in the stream, return the offset from the beginning of the
- // block which contains this data.
- size_t GetInBlockOffset(QuicStreamOffset offset) const;
-
- // Get offset relative to index 0 in logical 1st block to start next read.
- size_t ReadOffset() const;
-
- // 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;
-
- // Called after Readv() and MarkConsumed() to keep frame_arrival_time_map_
- // up to date.
- // |offset| is the byte next read should start from. All frames before it
- // should be removed from the map.
- void UpdateFrameArrivalMap(QuicStreamOffset offset);
-
- // Return |gaps_| as a std::string: [1024, 1500) [1800, 2048)... for
- // debugging.
- std::string GapsDebugString();
-
- // Return all received frames as a std::string in same format as
- // GapsDebugString();
- std::string ReceivedFramesDebugString();
-
- // The maximum total capacity of this buffer in byte, as constructed.
- const size_t max_buffer_capacity_bytes_;
-
- // How many blocks this buffer would need when it reaches full capacity.
- const size_t blocks_count_;
-
- // Number of bytes read out of buffer.
- QuicStreamOffset total_bytes_read_;
-
- // Contains Gaps which represents currently missing data.
- std::list<Gap> gaps_;
-
- // An ordered, variable-length list of blocks, with the length limited
- // such that the number of blocks never exceeds blocks_count_.
- // Each list entry can hold up to kBlockSizeBytes bytes.
- std::vector<BufferBlock*> blocks_;
-
- // Number of bytes in buffer.
- size_t num_bytes_buffered_;
-
- // Stores all the buffered frames' start offset, length and arrival time.
- std::map<QuicStreamOffset, FrameInfo> frame_arrival_time_map_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicStreamSequencerBuffer);
-};
-} // namespace net
-
-#endif // NET_QUIC_QUIC_STREAM_SEQUENCER_BUFFER_H_
diff --git a/chromium/net/quic/quic_stream_sequencer_buffer_interface.h b/chromium/net/quic/quic_stream_sequencer_buffer_interface.h
deleted file mode 100644
index d5ad8fe49a8..00000000000
--- a/chromium/net/quic/quic_stream_sequencer_buffer_interface.h
+++ /dev/null
@@ -1,76 +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.
-
-#ifndef NET_QUIC_QUIC_STREAM_SEQUENCER_BUFFER_INTERFACE_H_
-#define NET_QUIC_QUIC_STREAM_SEQUENCER_BUFFER_INTERFACE_H_
-
-#include <stddef.h>
-
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-// The QuicStreamSequencer uses an implementation of this interface to store
-// received data.
-class NET_EXPORT_PRIVATE QuicStreamSequencerBufferInterface {
- public:
- virtual ~QuicStreamSequencerBufferInterface() {}
-
- // Free the space used to buffer data.
- virtual void Clear() = 0;
-
- // Returns true if there is nothing to read in this buffer.
- virtual bool Empty() const = 0;
-
- // Called to buffer new data received for this stream. If the data was
- // successfully buffered, returns QUIC_NO_ERROR and stores the number of
- // bytes buffered in |bytes_buffered|. Returns an error otherwise.
- // |timestamp| is the time the data arrived.
- virtual QuicErrorCode OnStreamData(QuicStreamOffset offset,
- base::StringPiece data,
- QuicTime timestamp,
- size_t* bytes_buffered) = 0;
-
- // Reads from this buffer into given iovec array, up to number of iov_len
- // iovec objects and returns the number of bytes read.
- virtual size_t Readv(const struct iovec* iov, size_t iov_len) = 0;
-
- // Returns the readable region of valid data in iovec format. The readable
- // region is the buffer region where there is valid data not yet read by
- // client.
- // Returns the number of iovec entries in |iov| which were populated.
- // If the region is empty, one iovec entry with 0 length
- // is returned, and the function returns 0. If there are more readable
- // regions than iov_size, the function only processes the first
- // iov_size of them.
- virtual int GetReadableRegions(struct iovec* iov, int iov_len) const = 0;
-
- // Fills in one iovec with data which all arrived at the same time from the
- // next readable region.
- // Populates |timestamp| with the time that this data arrived.
- // Returns false if there is no readable region available.
- virtual bool GetReadableRegion(iovec* iov, QuicTime* timestamp) const = 0;
-
- // Called after GetReadableRegions() to free up |bytes_used| space if these
- // bytes are processed.
- // Pre-requisite: bytes_used <= available bytes to read.
- virtual bool MarkConsumed(size_t bytes_used) = 0;
-
- // Deletes and records as consumed any buffered data and clear the buffer.
- // (To be called only after sequencer's StopReading has been called.)
- virtual size_t FlushBufferedFrames() = 0;
-
- // Whether there are bytes can be read out.
- virtual bool HasBytesToRead() const = 0;
-
- // Count how many bytes have been consumed (read out of buffer).
- virtual QuicStreamOffset BytesConsumed() const = 0;
-
- // Count how many bytes are in buffer at this moment.
- virtual size_t BytesBuffered() const = 0;
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_STREAM_SEQUENCER_BUFFER_INTERFACE_H_
diff --git a/chromium/net/quic/quic_stream_sequencer_buffer_test.cc b/chromium/net/quic/quic_stream_sequencer_buffer_test.cc
deleted file mode 100644
index 4a848322ec5..00000000000
--- a/chromium/net/quic/quic_stream_sequencer_buffer_test.cc
+++ /dev/null
@@ -1,1060 +0,0 @@
-// 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.
-#include "net/quic/quic_stream_sequencer_buffer.h"
-
-#include <algorithm>
-#include <limits>
-#include <map>
-#include <string>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/rand_util.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "net/test/gtest_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gmock_mutant.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::min;
-using std::string;
-
-namespace net {
-
-namespace test {
-
-char GetCharFromIOVecs(size_t offset, iovec iov[], size_t count) {
- size_t start_offset = 0;
- for (size_t i = 0; i < count; i++) {
- if (iov[i].iov_len == 0) {
- continue;
- }
- size_t end_offset = start_offset + iov[i].iov_len - 1;
- if (offset >= start_offset && offset <= end_offset) {
- const char* buf = reinterpret_cast<const char*>(iov[i].iov_base);
- return buf[offset - start_offset];
- }
- start_offset += iov[i].iov_len;
- }
- LOG(ERROR) << "Could not locate char at offset " << offset << " in " << count
- << " iovecs";
- for (size_t i = 0; i < count; ++i) {
- LOG(ERROR) << " iov[" << i << "].iov_len = " << iov[i].iov_len;
- }
- return '\0';
-}
-
-static const size_t kBlockSizeBytes =
- QuicStreamSequencerBuffer::kBlockSizeBytes;
-typedef QuicStreamSequencerBuffer::BufferBlock BufferBlock;
-typedef QuicStreamSequencerBuffer::Gap Gap;
-typedef QuicStreamSequencerBuffer::FrameInfo FrameInfo;
-
-class QuicStreamSequencerBufferPeer {
- public:
- explicit QuicStreamSequencerBufferPeer(QuicStreamSequencerBuffer* buffer)
- : buffer_(buffer) {}
-
- // Read from this buffer_->into the given destination buffer_-> up to the
- // size of the destination. Returns the number of bytes read. Reading from
- // an empty buffer_->returns 0.
- size_t Read(char* dest_buffer, size_t size) {
- iovec dest;
- dest.iov_base = dest_buffer, dest.iov_len = size;
- return buffer_->Readv(&dest, 1);
- }
-
- // If buffer is empty, the blocks_ array must be empty, which means all
- // blocks are deallocated.
- bool CheckEmptyInvariants() {
- return !buffer_->Empty() || IsBlockArrayEmpty();
- }
-
- bool IsBlockArrayEmpty() {
- size_t count = buffer_->blocks_count_;
- for (size_t i = 0; i < count; i++) {
- if (buffer_->blocks_[i] != nullptr) {
- return false;
- }
- }
- return true;
- }
-
- bool CheckInitialState() {
- EXPECT_TRUE(buffer_->Empty() && buffer_->total_bytes_read_ == 0 &&
- buffer_->num_bytes_buffered_ == 0);
- return CheckBufferInvariants();
- }
-
- bool CheckBufferInvariants() {
- QuicStreamOffset data_span =
- buffer_->gaps_.back().begin_offset - buffer_->total_bytes_read_;
- bool capacity_sane = data_span <= buffer_->max_buffer_capacity_bytes_ &&
- data_span >= buffer_->num_bytes_buffered_;
- if (!capacity_sane) {
- LOG(ERROR) << "data span is larger than capacity.";
- LOG(ERROR) << "total read: " << buffer_->total_bytes_read_
- << " last byte: " << buffer_->gaps_.back().begin_offset;
- }
- bool total_read_sane =
- buffer_->gaps_.front().begin_offset >= buffer_->total_bytes_read_;
- if (!total_read_sane) {
- LOG(ERROR) << "read across 1st gap.";
- }
- bool read_offset_sane = buffer_->ReadOffset() < kBlockSizeBytes;
- if (!capacity_sane) {
- LOG(ERROR) << "read offset go beyond 1st block";
- }
- bool block_match_capacity =
- (buffer_->max_buffer_capacity_bytes_ <=
- buffer_->blocks_count_ * kBlockSizeBytes) &&
- (buffer_->max_buffer_capacity_bytes_ >
- (buffer_->blocks_count_ - 1) * kBlockSizeBytes);
- if (!capacity_sane) {
- LOG(ERROR) << "block number not match capcaity.";
- }
- bool block_retired_when_empty = CheckEmptyInvariants();
- if (!block_retired_when_empty) {
- LOG(ERROR) << "block is not retired after use.";
- }
- return capacity_sane && total_read_sane && read_offset_sane &&
- block_match_capacity && block_retired_when_empty;
- }
-
- size_t GetInBlockOffset(QuicStreamOffset offset) {
- return buffer_->GetInBlockOffset(offset);
- }
-
- BufferBlock* GetBlock(size_t index) { return buffer_->blocks_[index]; }
-
- int GapSize() { return buffer_->gaps_.size(); }
-
- std::list<Gap> GetGaps() { return buffer_->gaps_; }
-
- size_t max_buffer_capacity() { return buffer_->max_buffer_capacity_bytes_; }
-
- size_t ReadableBytes() { return buffer_->ReadableBytes(); }
-
- std::map<QuicStreamOffset, FrameInfo>* frame_arrival_time_map() {
- return &(buffer_->frame_arrival_time_map_);
- }
-
- void set_total_bytes_read(QuicStreamOffset total_bytes_read) {
- buffer_->total_bytes_read_ = total_bytes_read;
- }
-
- void set_gaps(const std::list<Gap>& gaps) { buffer_->gaps_ = gaps; }
-
- private:
- QuicStreamSequencerBuffer* buffer_;
-};
-
-namespace {
-
-class QuicStreamSequencerBufferTest : public testing::Test {
- public:
- void SetUp() override { Initialize(); }
-
- void ResetMaxCapacityBytes(size_t max_capacity_bytes) {
- max_capacity_bytes_ = max_capacity_bytes;
- Initialize();
- }
-
- protected:
- void Initialize() {
- buffer_.reset(new QuicStreamSequencerBuffer(max_capacity_bytes_));
- helper_.reset(new QuicStreamSequencerBufferPeer(buffer_.get()));
- }
-
- // Use 2.5 here to make sure the buffer has more than one block and its end
- // doesn't align with the end of a block in order to test all the offset
- // calculation.
- size_t max_capacity_bytes_ = 2.5 * kBlockSizeBytes;
-
- MockClock clock_;
- std::unique_ptr<QuicStreamSequencerBuffer> buffer_;
- std::unique_ptr<QuicStreamSequencerBufferPeer> helper_;
- string error_details_;
-};
-
-TEST_F(QuicStreamSequencerBufferTest, InitializationWithDifferentSizes) {
- const size_t kCapacity = 2 * QuicStreamSequencerBuffer::kBlockSizeBytes;
- ResetMaxCapacityBytes(kCapacity);
- EXPECT_EQ(max_capacity_bytes_, helper_->max_buffer_capacity());
- EXPECT_TRUE(helper_->CheckInitialState());
-
- const size_t kCapacity1 = 8 * QuicStreamSequencerBuffer::kBlockSizeBytes;
- ResetMaxCapacityBytes(kCapacity1);
- EXPECT_EQ(kCapacity1, helper_->max_buffer_capacity());
- EXPECT_TRUE(helper_->CheckInitialState());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, ClearOnEmpty) {
- buffer_->Clear();
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, OnStreamData0length) {
- size_t written;
- QuicErrorCode error = buffer_->OnStreamData(800, "", clock_.ApproximateNow(),
- &written, &error_details_);
- EXPECT_EQ(error, QUIC_EMPTY_STREAM_FRAME_NO_FIN);
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithinBlock) {
- string source(1024, 'a');
- size_t written;
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- QuicTime t = clock_.ApproximateNow();
- EXPECT_EQ(QUIC_NO_ERROR,
- buffer_->OnStreamData(800, source, t, &written, &error_details_));
- BufferBlock* block_ptr = helper_->GetBlock(0);
- for (size_t i = 0; i < source.size(); ++i) {
- 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);
- auto* frame_map = helper_->frame_arrival_time_map();
- EXPECT_EQ(1u, frame_map->size());
- EXPECT_EQ(800u, frame_map->begin()->first);
- EXPECT_EQ(t, (*frame_map)[800].timestamp);
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithOverlap) {
- string source(1024, 'a');
- // Write something into [800, 1824)
- size_t written;
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- QuicTime t1 = clock_.ApproximateNow();
- 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();
- 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);
-}
-
-TEST_F(QuicStreamSequencerBufferTest,
- OnStreamDataOverlapAndDuplicateCornerCases) {
- string source(1024, 'a');
- // Write something into [800, 1824)
- size_t written;
- buffer_->OnStreamData(800, source, clock_.ApproximateNow(), &written,
- &error_details_);
- source = string(800, 'b');
- // 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,
- &error_details_));
- // write to [0, 800)
- EXPECT_EQ(QUIC_NO_ERROR,
- 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_));
- 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_));
- auto* frame_map = helper_->frame_arrival_time_map();
- EXPECT_EQ(3u, frame_map->size());
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithoutOverlap) {
- string source(1024, 'a');
- // Write something into [800, 1824).
- size_t written;
- EXPECT_EQ(QUIC_NO_ERROR,
- buffer_->OnStreamData(800, source, clock_.ApproximateNow(),
- &written, &error_details_));
- source = string(100, 'b');
- // Write something into [kBlockSizeBytes * 2 - 20, kBlockSizeBytes * 2 + 80).
- EXPECT_EQ(QUIC_NO_ERROR,
- buffer_->OnStreamData(kBlockSizeBytes * 2 - 20, source,
- clock_.ApproximateNow(), &written,
- &error_details_));
- EXPECT_EQ(3, helper_->GapSize());
- EXPECT_EQ(1024u + 100u, buffer_->BytesBuffered());
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-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())));
-
- // Three new out of order frames arrive.
- const size_t kBytesToWrite = 100;
- string source(kBytesToWrite, 'a');
- size_t written;
- // Frame [2^32 + 500, 2^32 + 600).
- QuicStreamOffset offset = pow(2, 32) + 500;
- EXPECT_EQ(QUIC_NO_ERROR,
- buffer_->OnStreamData(offset, source, clock_.ApproximateNow(),
- &written, &error_details_));
- EXPECT_EQ(2, helper_->GapSize());
-
- // Frame [2^32 + 700, 2^32 + 800).
- offset = pow(2, 32) + 700;
- EXPECT_EQ(QUIC_NO_ERROR,
- buffer_->OnStreamData(offset, source, clock_.ApproximateNow(),
- &written, &error_details_));
- EXPECT_EQ(3, helper_->GapSize());
-
- // Another frame [2^32 + 300, 2^32 + 400).
- offset = pow(2, 32) + 300;
- EXPECT_EQ(QUIC_NO_ERROR,
- buffer_->OnStreamData(offset, source, clock_.ApproximateNow(),
- &written, &error_details_));
- EXPECT_EQ(4, helper_->GapSize());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, OnStreamDataTillEnd) {
- // Write 50 bytes to the end.
- const size_t kBytesToWrite = 50;
- string source(kBytesToWrite, 'a');
- size_t written;
- EXPECT_EQ(QUIC_NO_ERROR,
- buffer_->OnStreamData(max_capacity_bytes_ - kBytesToWrite, source,
- clock_.ApproximateNow(), &written,
- &error_details_));
- EXPECT_EQ(50u, buffer_->BytesBuffered());
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, OnStreamDataTillEndCorner) {
- // Write 1 byte to the end.
- const size_t kBytesToWrite = 1;
- string source(kBytesToWrite, 'a');
- size_t written;
- EXPECT_EQ(QUIC_NO_ERROR,
- buffer_->OnStreamData(max_capacity_bytes_ - kBytesToWrite, source,
- clock_.ApproximateNow(), &written,
- &error_details_));
- EXPECT_EQ(1u, buffer_->BytesBuffered());
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, OnStreamDataBeyondCapacity) {
- string source(60, 'a');
- size_t written;
- EXPECT_EQ(QUIC_INTERNAL_ERROR,
- buffer_->OnStreamData(max_capacity_bytes_ - 50, source,
- clock_.ApproximateNow(), &written,
- &error_details_));
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-
- source = "b";
- EXPECT_EQ(QUIC_INTERNAL_ERROR,
- buffer_->OnStreamData(max_capacity_bytes_, source,
- clock_.ApproximateNow(), &written,
- &error_details_));
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-
- EXPECT_EQ(QUIC_INTERNAL_ERROR,
- buffer_->OnStreamData(max_capacity_bytes_ * 1000, source,
- clock_.ApproximateNow(), &written,
- &error_details_));
- EXPECT_TRUE(helper_->CheckBufferInvariants());
- EXPECT_EQ(0u, buffer_->BytesBuffered());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, Readv100Bytes) {
- string source(1024, 'a');
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- QuicTime t1 = clock_.ApproximateNow();
- // Write something into [kBlockSizeBytes, kBlockSizeBytes + 1024).
- size_t written;
- buffer_->OnStreamData(kBlockSizeBytes, source, t1, &written, &error_details_);
- EXPECT_FALSE(buffer_->HasBytesToRead());
- source = string(100, 'b');
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- QuicTime t2 = clock_.ApproximateNow();
- // Write something into [0, 100).
- buffer_->OnStreamData(0, source, t2, &written, &error_details_);
- EXPECT_TRUE(buffer_->HasBytesToRead());
- EXPECT_EQ(2u, helper_->frame_arrival_time_map()->size());
- // Read into a iovec array with total capacity of 120 bytes.
- char dest[120];
- iovec iovecs[3]{iovec{dest, 40}, iovec{dest + 40, 40}, iovec{dest + 80, 40}};
- size_t read = buffer_->Readv(iovecs, 3);
- EXPECT_EQ(100u, read);
- EXPECT_EQ(100u, buffer_->BytesConsumed());
- EXPECT_EQ(source, string(dest, read));
- EXPECT_EQ(1u, helper_->frame_arrival_time_map()->size());
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, ReadvAcrossBlocks) {
- string source(kBlockSizeBytes + 50, 'a');
- // Write 1st block to full and extand 50 bytes to next block.
- size_t written;
- buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
- &error_details_);
- EXPECT_EQ(source.size(), helper_->ReadableBytes());
- // Iteratively read 512 bytes from buffer_-> Overwrite dest[] each time.
- char dest[512];
- while (helper_->ReadableBytes()) {
- std::fill(dest, dest + 512, 0);
- iovec iovecs[2]{iovec{dest, 256}, iovec{dest + 256, 256}};
- buffer_->Readv(iovecs, 2);
- }
- // The last read only reads the rest 50 bytes in 2nd block.
- EXPECT_EQ(string(50, 'a'), string(dest, 50));
- EXPECT_EQ(0, dest[50]) << "Dest[50] shouln't be filled.";
- EXPECT_EQ(source.size(), buffer_->BytesConsumed());
- EXPECT_TRUE(buffer_->Empty());
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, ClearAfterRead) {
- string source(kBlockSizeBytes + 50, 'a');
- // Write 1st block to full with 'a'.
- size_t written;
- buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
- &error_details_);
- // Read first 512 bytes from buffer to make space at the beginning.
- char dest[512]{0};
- const iovec iov{dest, 512};
- buffer_->Readv(&iov, 1);
- // Clear() should make buffer empty while preserving BytesConsumed()
- buffer_->Clear();
- EXPECT_TRUE(buffer_->Empty());
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest,
- OnStreamDataAcrossLastBlockAndFillCapacity) {
- string source(kBlockSizeBytes + 50, 'a');
- // Write 1st block to full with 'a'.
- size_t written;
- buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
- &error_details_);
- // Read first 512 bytes from buffer to make space at the beginning.
- char dest[512]{0};
- const iovec iov{dest, 512};
- buffer_->Readv(&iov, 1);
- EXPECT_EQ(source.size(), written);
-
- // Write more than half block size of bytes in the last block with 'b', which
- // will wrap to the beginning and reaches the full capacity.
- source = string(0.5 * kBlockSizeBytes + 512, 'b');
- EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData(2 * kBlockSizeBytes, source,
- clock_.ApproximateNow(),
- &written, &error_details_));
- EXPECT_EQ(source.size(), written);
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest,
- OnStreamDataAcrossLastBlockAndExceedCapacity) {
- string source(kBlockSizeBytes + 50, 'a');
- // Write 1st block to full.
- size_t written;
- buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
- &error_details_);
- // Read first 512 bytes from buffer to make space at the beginning.
- char dest[512]{0};
- const iovec iov{dest, 512};
- buffer_->Readv(&iov, 1);
-
- // Try to write from [max_capacity_bytes_ - 0.5 * kBlockSizeBytes,
- // max_capacity_bytes_ + 512 + 1). But last bytes exceeds current capacity.
- source = string(0.5 * kBlockSizeBytes + 512 + 1, 'b');
- EXPECT_EQ(QUIC_INTERNAL_ERROR,
- buffer_->OnStreamData(2 * kBlockSizeBytes, source,
- clock_.ApproximateNow(), &written,
- &error_details_));
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, ReadvAcrossLastBlock) {
- // Write to full capacity and read out 512 bytes at beginning and continue
- // appending 256 bytes.
- string source(max_capacity_bytes_, 'a');
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- QuicTime t = clock_.ApproximateNow();
- size_t written;
- buffer_->OnStreamData(0, source, t, &written, &error_details_);
- char dest[512]{0};
- const iovec iov{dest, 512};
- buffer_->Readv(&iov, 1);
- source = string(256, 'b');
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- QuicTime t2 = clock_.ApproximateNow();
- buffer_->OnStreamData(max_capacity_bytes_, source, t2, &written,
- &error_details_);
- EXPECT_TRUE(helper_->CheckBufferInvariants());
- EXPECT_EQ(2u, helper_->frame_arrival_time_map()->size());
-
- // Read all data out.
- std::unique_ptr<char[]> dest1{new char[max_capacity_bytes_]};
- dest1[0] = 0;
- const iovec iov1{dest1.get(), max_capacity_bytes_};
- EXPECT_EQ(max_capacity_bytes_ - 512 + 256, buffer_->Readv(&iov1, 1));
- EXPECT_EQ(max_capacity_bytes_ + 256, buffer_->BytesConsumed());
- EXPECT_TRUE(buffer_->Empty());
- EXPECT_TRUE(helper_->CheckBufferInvariants());
- EXPECT_EQ(0u, helper_->frame_arrival_time_map()->size());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, ReadvEmpty) {
- char dest[512]{0};
- iovec iov{dest, 512};
- size_t read = buffer_->Readv(&iov, 1);
- EXPECT_EQ(0u, read);
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionsEmpty) {
- iovec iovs[2];
- int iov_count = buffer_->GetReadableRegions(iovs, 2);
- EXPECT_EQ(0, iov_count);
- EXPECT_EQ(nullptr, iovs[iov_count].iov_base);
- EXPECT_EQ(0u, iovs[iov_count].iov_len);
-}
-
-TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionsBlockedByGap) {
- // Write into [1, 1024).
- string source(1023, 'a');
- size_t written;
- buffer_->OnStreamData(1, source, clock_.ApproximateNow(), &written,
- &error_details_);
- // Try to get readable regions, but none is there.
- iovec iovs[2];
- int iov_count = buffer_->GetReadableRegions(iovs, 2);
- EXPECT_EQ(0, iov_count);
-}
-
-TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionsTillEndOfBlock) {
- // Write first block to full with [0, 256) 'a' and the rest 'b' then read out
- // [0, 256)
- string source(kBlockSizeBytes, 'a');
- size_t written;
- buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
- &error_details_);
- char dest[256];
- helper_->Read(dest, 256);
- // Get readable region from [256, 1024)
- iovec iovs[2];
- int iov_count = buffer_->GetReadableRegions(iovs, 2);
- EXPECT_EQ(1, iov_count);
- EXPECT_EQ(
- string(kBlockSizeBytes - 256, 'a'),
- string(reinterpret_cast<const char*>(iovs[0].iov_base), iovs[0].iov_len));
-}
-
-TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionsWithinOneBlock) {
- // Write into [0, 1024) and then read out [0, 256)
- string source(1024, 'a');
- size_t written;
- buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
- &error_details_);
- char dest[256];
- helper_->Read(dest, 256);
- // Get readable region from [256, 1024)
- iovec iovs[2];
- int iov_count = buffer_->GetReadableRegions(iovs, 2);
- EXPECT_EQ(1, iov_count);
- EXPECT_EQ(
- string(1024 - 256, 'a'),
- string(reinterpret_cast<const char*>(iovs[0].iov_base), iovs[0].iov_len));
-}
-
-TEST_F(QuicStreamSequencerBufferTest,
- GetReadableRegionsAcrossBlockWithLongIOV) {
- // Write into [0, 2 * kBlockSizeBytes + 1024) and then read out [0, 1024)
- string source(2 * kBlockSizeBytes + 1024, 'a');
- size_t written;
- buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
- &error_details_);
- char dest[1024];
- helper_->Read(dest, 1024);
-
- iovec iovs[4];
- int iov_count = buffer_->GetReadableRegions(iovs, 4);
- EXPECT_EQ(3, iov_count);
- EXPECT_EQ(kBlockSizeBytes - 1024, iovs[0].iov_len);
- EXPECT_EQ(kBlockSizeBytes, iovs[1].iov_len);
- EXPECT_EQ(1024u, iovs[2].iov_len);
-}
-
-TEST_F(QuicStreamSequencerBufferTest,
- GetReadableRegionsWithMultipleIOVsAcrossEnd) {
- // Write into [0, 2 * kBlockSizeBytes + 1024) and then read out [0, 1024)
- // and then append 1024 + 512 bytes.
- string source(2.5 * kBlockSizeBytes - 1024, 'a');
- size_t written;
- buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
- &error_details_);
- char dest[1024];
- helper_->Read(dest, 1024);
- // Write across the end.
- source = string(1024 + 512, 'b');
- buffer_->OnStreamData(2.5 * kBlockSizeBytes - 1024, source,
- clock_.ApproximateNow(), &written, &error_details_);
- // Use short iovec's.
- iovec iovs[2];
- int iov_count = buffer_->GetReadableRegions(iovs, 2);
- EXPECT_EQ(2, iov_count);
- EXPECT_EQ(kBlockSizeBytes - 1024, iovs[0].iov_len);
- EXPECT_EQ(kBlockSizeBytes, iovs[1].iov_len);
- // Use long iovec's and wrap the end of buffer.
- iovec iovs1[5];
- EXPECT_EQ(4, buffer_->GetReadableRegions(iovs1, 5));
- EXPECT_EQ(0.5 * kBlockSizeBytes, iovs1[2].iov_len);
- EXPECT_EQ(512u, iovs1[3].iov_len);
- EXPECT_EQ(string(512, 'b'),
- string(reinterpret_cast<const char*>(iovs1[3].iov_base),
- iovs1[3].iov_len));
-}
-
-TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionEmpty) {
- iovec iov;
- QuicTime t = QuicTime::Zero();
- EXPECT_FALSE(buffer_->GetReadableRegion(&iov, &t));
- EXPECT_EQ(nullptr, iov.iov_base);
- EXPECT_EQ(0u, iov.iov_len);
-}
-
-TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionBeforeGap) {
- // Write into [1, 1024).
- string source(1023, 'a');
- size_t written;
- buffer_->OnStreamData(1, source, clock_.ApproximateNow(), &written,
- &error_details_);
- // GetReadableRegion should return false because range [0,1) hasn't been
- // filled yet.
- iovec iov;
- QuicTime t = QuicTime::Zero();
- EXPECT_FALSE(buffer_->GetReadableRegion(&iov, &t));
-}
-
-TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionTillEndOfBlock) {
- // Write into [0, kBlockSizeBytes + 1) and then read out [0, 256)
- string source(kBlockSizeBytes + 1, 'a');
- size_t written;
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- QuicTime t = clock_.ApproximateNow();
- buffer_->OnStreamData(0, source, t, &written, &error_details_);
- char dest[256];
- helper_->Read(dest, 256);
- // Get readable region from [256, 1024)
- iovec iov;
- QuicTime t2 = QuicTime::Zero();
- EXPECT_TRUE(buffer_->GetReadableRegion(&iov, &t2));
- EXPECT_EQ(t, t2);
- EXPECT_EQ(string(kBlockSizeBytes - 256, 'a'),
- string(reinterpret_cast<const char*>(iov.iov_base), iov.iov_len));
-}
-
-TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionTillGap) {
- // Write into [0, kBlockSizeBytes - 1) and then read out [0, 256)
- string source(kBlockSizeBytes - 1, 'a');
- size_t written;
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- QuicTime t = clock_.ApproximateNow();
- buffer_->OnStreamData(0, source, t, &written, &error_details_);
- char dest[256];
- helper_->Read(dest, 256);
- // Get readable region from [256, 1023)
- iovec iov;
- QuicTime t2 = QuicTime::Zero();
- EXPECT_TRUE(buffer_->GetReadableRegion(&iov, &t2));
- EXPECT_EQ(t, t2);
- EXPECT_EQ(string(kBlockSizeBytes - 1 - 256, 'a'),
- string(reinterpret_cast<const char*>(iov.iov_base), iov.iov_len));
-}
-
-TEST_F(QuicStreamSequencerBufferTest, GetReadableRegionByArrivalTime) {
- // Write into [0, kBlockSizeBytes - 100) and then read out [0, 256)
- string source(kBlockSizeBytes - 100, 'a');
- size_t written;
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- QuicTime t = clock_.ApproximateNow();
- buffer_->OnStreamData(0, source, t, &written, &error_details_);
- char dest[256];
- helper_->Read(dest, 256);
- // Write into [kBlockSizeBytes - 100, kBlockSizeBytes - 50)] in same time
- string source2(50, 'b');
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- buffer_->OnStreamData(kBlockSizeBytes - 100, source2, t, &written,
- &error_details_);
-
- // Write into [kBlockSizeBytes - 50, kBlockSizeBytes)] in another time
- string source3(50, 'c');
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- QuicTime t3 = clock_.ApproximateNow();
- buffer_->OnStreamData(kBlockSizeBytes - 50, source3, t3, &written,
- &error_details_);
-
- // Get readable region from [256, 1024 - 50)
- iovec iov;
- QuicTime t4 = QuicTime::Zero();
- EXPECT_TRUE(buffer_->GetReadableRegion(&iov, &t4));
- EXPECT_EQ(t, t4);
- EXPECT_EQ(string(kBlockSizeBytes - 100 - 256, 'a') + source2,
- string(reinterpret_cast<const char*>(iov.iov_base), iov.iov_len));
-}
-
-TEST_F(QuicStreamSequencerBufferTest, MarkConsumedInOneBlock) {
- // Write into [0, 1024) and then read out [0, 256)
- string source(1024, 'a');
- size_t written;
- buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
- &error_details_);
- char dest[256];
- helper_->Read(dest, 256);
-
- EXPECT_TRUE(buffer_->MarkConsumed(512));
- EXPECT_EQ(256u + 512u, buffer_->BytesConsumed());
- EXPECT_EQ(256u, helper_->ReadableBytes());
- EXPECT_EQ(1u, helper_->frame_arrival_time_map()->size());
- buffer_->MarkConsumed(256);
- EXPECT_EQ(0u, helper_->frame_arrival_time_map()->size());
- EXPECT_TRUE(buffer_->Empty());
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, MarkConsumedNotEnoughBytes) {
- // Write into [0, 1024) and then read out [0, 256)
- string source(1024, 'a');
- size_t written;
- QuicTime t = clock_.ApproximateNow();
- buffer_->OnStreamData(0, source, t, &written, &error_details_);
- char dest[256];
- helper_->Read(dest, 256);
-
- // Consume 1st 512 bytes
- EXPECT_TRUE(buffer_->MarkConsumed(512));
- EXPECT_EQ(256u + 512u, buffer_->BytesConsumed());
- EXPECT_EQ(256u, helper_->ReadableBytes());
- // Try to consume one bytes more than available. Should return false.
- EXPECT_FALSE(buffer_->MarkConsumed(257));
- EXPECT_EQ(256u + 512u, buffer_->BytesConsumed());
- QuicTime t2 = QuicTime::Zero();
- iovec iov;
- EXPECT_TRUE(buffer_->GetReadableRegion(&iov, &t2));
- EXPECT_EQ(t, t2);
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, MarkConsumedAcrossBlock) {
- // Write into [0, 2 * kBlockSizeBytes + 1024) and then read out [0, 1024)
- string source(2 * kBlockSizeBytes + 1024, 'a');
- size_t written;
- buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
- &error_details_);
- char dest[1024];
- helper_->Read(dest, 1024);
-
- buffer_->MarkConsumed(2 * kBlockSizeBytes);
- EXPECT_EQ(source.size(), buffer_->BytesConsumed());
- EXPECT_TRUE(buffer_->Empty());
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, MarkConsumedAcrossEnd) {
- // Write into [0, 2.5 * kBlockSizeBytes - 1024) and then read out [0, 1024)
- // and then append 1024 + 512 bytes.
- string source(2.5 * kBlockSizeBytes - 1024, 'a');
- size_t written;
- buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
- &error_details_);
- char dest[1024];
- helper_->Read(dest, 1024);
- source = string(1024 + 512, 'b');
- buffer_->OnStreamData(2.5 * kBlockSizeBytes - 1024, source,
- clock_.ApproximateNow(), &written, &error_details_);
- EXPECT_EQ(1024u, buffer_->BytesConsumed());
-
- // Consume to the end of 2nd block.
- buffer_->MarkConsumed(2 * kBlockSizeBytes - 1024);
- EXPECT_EQ(2 * kBlockSizeBytes, buffer_->BytesConsumed());
- // Consume across the physical end of buffer
- buffer_->MarkConsumed(0.5 * kBlockSizeBytes + 500);
- EXPECT_EQ(max_capacity_bytes_ + 500, buffer_->BytesConsumed());
- EXPECT_EQ(12u, helper_->ReadableBytes());
- // Consume to the logical end of buffer
- buffer_->MarkConsumed(12);
- EXPECT_EQ(max_capacity_bytes_ + 512, buffer_->BytesConsumed());
- EXPECT_TRUE(buffer_->Empty());
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-TEST_F(QuicStreamSequencerBufferTest, FlushBufferedFrames) {
- // Write into [0, 2.5 * kBlockSizeBytes - 1024) and then read out [0, 1024).
- string source(max_capacity_bytes_ - 1024, 'a');
- size_t written;
- buffer_->OnStreamData(0, source, clock_.ApproximateNow(), &written,
- &error_details_);
- char dest[1024];
- helper_->Read(dest, 1024);
- EXPECT_EQ(1024u, buffer_->BytesConsumed());
- // Write [1024, 512) to the physical beginning.
- source = string(512, 'b');
- buffer_->OnStreamData(max_capacity_bytes_, source, clock_.ApproximateNow(),
- &written, &error_details_);
- EXPECT_EQ(512u, written);
- EXPECT_EQ(max_capacity_bytes_ - 1024 + 512, buffer_->FlushBufferedFrames());
- EXPECT_EQ(max_capacity_bytes_ + 512, buffer_->BytesConsumed());
- EXPECT_TRUE(buffer_->Empty());
- EXPECT_TRUE(helper_->CheckBufferInvariants());
- // Clear buffer at this point should still preserve BytesConsumed().
- buffer_->Clear();
- EXPECT_EQ(max_capacity_bytes_ + 512, buffer_->BytesConsumed());
- EXPECT_TRUE(helper_->CheckBufferInvariants());
-}
-
-class QuicStreamSequencerBufferRandomIOTest
- : public QuicStreamSequencerBufferTest {
- public:
- typedef std::pair<QuicStreamOffset, size_t> OffsetSizePair;
-
- void SetUp() override {
- // Test against a larger capacity then above tests. Also make sure the last
- // block is partially available to use.
- max_capacity_bytes_ = 6.25 * kBlockSizeBytes;
- // Stream to be buffered should be larger than the capacity to test wrap
- // around.
- bytes_to_buffer_ = 2 * max_capacity_bytes_;
- Initialize();
-
- uint32_t seed = base::RandInt(0, std::numeric_limits<int32_t>::max());
- LOG(INFO) << "RandomWriteAndProcessInPlace test seed is " << seed;
- rng_.set_seed(seed);
- }
-
- // Create an out-of-order source stream with given size to populate
- // shuffled_buf_.
- void CreateSourceAndShuffle(size_t max_chunk_size_bytes) {
- max_chunk_size_bytes_ = max_chunk_size_bytes;
- std::unique_ptr<OffsetSizePair[]> chopped_stream(
- new OffsetSizePair[bytes_to_buffer_]);
-
- // Split stream into small chunks with random length. chopped_stream will be
- // populated with segmented stream chunks.
- size_t start_chopping_offset = 0;
- size_t iterations = 0;
- while (start_chopping_offset < bytes_to_buffer_) {
- size_t max_chunk = min<size_t>(max_chunk_size_bytes_,
- bytes_to_buffer_ - start_chopping_offset);
- size_t chunk_size = rng_.RandUint64() % max_chunk + 1;
- chopped_stream[iterations] =
- OffsetSizePair(start_chopping_offset, chunk_size);
- start_chopping_offset += chunk_size;
- ++iterations;
- }
- DCHECK(start_chopping_offset == bytes_to_buffer_);
- size_t chunk_num = iterations;
-
- // Randomly change the sequence of in-ordered OffsetSizePairs to make a
- // out-of-order array of OffsetSizePairs.
- for (int i = chunk_num - 1; i >= 0; --i) {
- size_t random_idx = rng_.RandUint64() % (i + 1);
- DVLOG(1) << "chunk offset " << chopped_stream[random_idx].first
- << " size " << chopped_stream[random_idx].second;
- shuffled_buf_.push_front(chopped_stream[random_idx]);
- chopped_stream[random_idx] = chopped_stream[i];
- }
- }
-
- // Write the currently first chunk of data in the out-of-order stream into
- // QuicStreamSequencerBuffer. If current chuck cannot be written into buffer
- // because it goes beyond current capacity, move it to the end of
- // shuffled_buf_ and write it later.
- void WriteNextChunkToBuffer() {
- OffsetSizePair& chunk = shuffled_buf_.front();
- QuicStreamOffset offset = chunk.first;
- const size_t num_to_write = chunk.second;
- std::unique_ptr<char[]> write_buf{new char[max_chunk_size_bytes_]};
- for (size_t i = 0; i < num_to_write; ++i) {
- write_buf[i] = (offset + i) % 256;
- }
- base::StringPiece string_piece_w(write_buf.get(), num_to_write);
- size_t written;
- auto result =
- buffer_->OnStreamData(offset, string_piece_w, clock_.ApproximateNow(),
- &written, &error_details_);
- if (result == QUIC_NO_ERROR) {
- shuffled_buf_.pop_front();
- total_bytes_written_ += num_to_write;
- } else {
- // This chunk offset exceeds window size.
- shuffled_buf_.push_back(chunk);
- shuffled_buf_.pop_front();
- }
- DVLOG(1) << " write at offset: " << offset
- << " len to write: " << num_to_write << " write result: " << result
- << " left over: " << shuffled_buf_.size();
- }
-
- protected:
- std::list<OffsetSizePair> shuffled_buf_;
- size_t max_chunk_size_bytes_;
- QuicStreamOffset bytes_to_buffer_;
- size_t total_bytes_written_ = 0;
- size_t total_bytes_read_ = 0;
- SimpleRandom rng_;
-};
-
-TEST_F(QuicStreamSequencerBufferRandomIOTest, RandomWriteAndReadv) {
- // Set kMaxReadSize larger than kBlockSizeBytes to test both small and large
- // read.
- const size_t kMaxReadSize = kBlockSizeBytes * 2;
- // kNumReads is larger than 1 to test how multiple read destinations work.
- const size_t kNumReads = 2;
- // Since write and read operation have equal possibility to be called. Bytes
- // to be written into and read out of should roughly the same.
- const size_t kMaxWriteSize = kNumReads * kMaxReadSize;
- size_t iterations = 0;
-
- CreateSourceAndShuffle(kMaxWriteSize);
-
- while ((!shuffled_buf_.empty() || total_bytes_read_ < bytes_to_buffer_) &&
- iterations <= 2 * bytes_to_buffer_) {
- uint8_t next_action =
- shuffled_buf_.empty() ? uint8_t{1} : rng_.RandUint64() % 2;
- DVLOG(1) << "iteration: " << iterations;
- switch (next_action) {
- case 0: { // write
- WriteNextChunkToBuffer();
- ASSERT_TRUE(helper_->CheckBufferInvariants());
- break;
- }
- case 1: { // readv
- std::unique_ptr<char[][kMaxReadSize]> read_buf{
- new char[kNumReads][kMaxReadSize]};
- iovec dest_iov[kNumReads];
- size_t num_to_read = 0;
- for (size_t i = 0; i < kNumReads; ++i) {
- dest_iov[i].iov_base =
- reinterpret_cast<void*>(const_cast<char*>(read_buf[i]));
- dest_iov[i].iov_len = rng_.RandUint64() % kMaxReadSize;
- num_to_read += dest_iov[i].iov_len;
- }
- size_t actually_read = buffer_->Readv(dest_iov, kNumReads);
- ASSERT_LE(actually_read, num_to_read);
- DVLOG(1) << " read from offset: " << total_bytes_read_
- << " size: " << num_to_read
- << " actual read: " << actually_read;
- for (size_t i = 0; i < actually_read; ++i) {
- char ch = (i + total_bytes_read_) % 256;
- ASSERT_EQ(ch, GetCharFromIOVecs(i, dest_iov, kNumReads))
- << " at iteration " << iterations;
- }
- total_bytes_read_ += actually_read;
- ASSERT_EQ(total_bytes_read_, buffer_->BytesConsumed());
- ASSERT_TRUE(helper_->CheckBufferInvariants());
- break;
- }
- }
- ++iterations;
- ASSERT_LE(total_bytes_read_, total_bytes_written_);
- }
- EXPECT_LT(iterations, bytes_to_buffer_) << "runaway test";
- EXPECT_LE(bytes_to_buffer_, total_bytes_read_) << "iterations: "
- << iterations;
- EXPECT_LE(bytes_to_buffer_, total_bytes_written_);
-}
-
-TEST_F(QuicStreamSequencerBufferRandomIOTest, RandomWriteAndConsumeInPlace) {
- // The value 4 is chosen such that the max write size is no larger than the
- // maximum buffer capacity.
- const size_t kMaxNumReads = 4;
- // Adjust write amount be roughly equal to that GetReadableRegions() can get.
- const size_t kMaxWriteSize = kMaxNumReads * kBlockSizeBytes;
- ASSERT_LE(kMaxWriteSize, max_capacity_bytes_);
- size_t iterations = 0;
-
- CreateSourceAndShuffle(kMaxWriteSize);
-
- while ((!shuffled_buf_.empty() || total_bytes_read_ < bytes_to_buffer_) &&
- iterations <= 2 * bytes_to_buffer_) {
- uint8_t next_action =
- shuffled_buf_.empty() ? uint8_t{1} : rng_.RandUint64() % 2;
- DVLOG(1) << "iteration: " << iterations;
- switch (next_action) {
- case 0: { // write
- WriteNextChunkToBuffer();
- ASSERT_TRUE(helper_->CheckBufferInvariants());
- break;
- }
- case 1: { // GetReadableRegions and then MarkConsumed
- size_t num_read = rng_.RandUint64() % kMaxNumReads + 1;
- iovec dest_iov[kMaxNumReads];
- ASSERT_TRUE(helper_->CheckBufferInvariants());
- size_t actually_num_read =
- buffer_->GetReadableRegions(dest_iov, num_read);
- ASSERT_LE(actually_num_read, num_read);
- size_t avail_bytes = 0;
- for (size_t i = 0; i < actually_num_read; ++i) {
- avail_bytes += dest_iov[i].iov_len;
- }
- // process random number of bytes (check the value of each byte).
- size_t bytes_to_process = rng_.RandUint64() % (avail_bytes + 1);
- size_t bytes_processed = 0;
- for (size_t i = 0; i < actually_num_read; ++i) {
- size_t bytes_in_block = min<size_t>(
- bytes_to_process - bytes_processed, dest_iov[i].iov_len);
- if (bytes_in_block == 0) {
- break;
- }
- for (size_t j = 0; j < bytes_in_block; ++j) {
- ASSERT_LE(bytes_processed, bytes_to_process);
- char char_expected =
- (buffer_->BytesConsumed() + bytes_processed) % 256;
- ASSERT_EQ(char_expected,
- reinterpret_cast<const char*>(dest_iov[i].iov_base)[j])
- << " at iteration " << iterations;
- ++bytes_processed;
- }
- }
-
- buffer_->MarkConsumed(bytes_processed);
-
- DVLOG(1) << "iteration " << iterations << ": try to get " << num_read
- << " readable regions, actually get " << actually_num_read
- << " from offset: " << total_bytes_read_
- << "\nprocesse bytes: " << bytes_processed;
- total_bytes_read_ += bytes_processed;
- ASSERT_EQ(total_bytes_read_, buffer_->BytesConsumed());
- ASSERT_TRUE(helper_->CheckBufferInvariants());
- break;
- }
- }
- ++iterations;
- ASSERT_LE(total_bytes_read_, total_bytes_written_);
- }
- EXPECT_LT(iterations, bytes_to_buffer_) << "runaway test";
- EXPECT_LE(bytes_to_buffer_, total_bytes_read_) << "iterations: "
- << iterations;
- EXPECT_LE(bytes_to_buffer_, total_bytes_written_);
-}
-
-} // anonymous namespace
-
-} // namespace test
-
-} // namespace net
diff --git a/chromium/net/quic/quic_stream_sequencer_test.cc b/chromium/net/quic/quic_stream_sequencer_test.cc
deleted file mode 100644
index 67cd07d0968..00000000000
--- a/chromium/net/quic/quic_stream_sequencer_test.cc
+++ /dev/null
@@ -1,669 +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/quic_stream_sequencer.h"
-
-#include <algorithm>
-#include <cstdint>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/rand_util.h"
-#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/reliable_quic_stream.h"
-#include "net/quic/test_tools/mock_clock.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/include/gmock/gmock.h"
-#include "testing/gmock_mutant.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::StringPiece;
-using std::map;
-using std::min;
-using std::pair;
-using std::string;
-using std::vector;
-using testing::_;
-using testing::AnyNumber;
-using testing::CreateFunctor;
-using testing::InSequence;
-using testing::Return;
-using testing::StrEq;
-
-namespace net {
-namespace test {
-
-class MockStream : public ReliableQuicStream {
- public:
- MockStream(QuicSession* session, QuicStreamId id)
- : ReliableQuicStream(id, session) {}
-
- MOCK_METHOD0(OnFinRead, void());
- MOCK_METHOD0(OnDataAvailable, void());
- MOCK_METHOD2(CloseConnectionWithDetails,
- void(QuicErrorCode error, const string& details));
- MOCK_METHOD1(Reset, void(QuicRstStreamErrorCode error));
- MOCK_METHOD0(OnCanWrite, void());
- virtual bool IsFlowControlEnabled() const { return true; }
-
- const IPEndPoint& PeerAddressOfLatestPacket() const override {
- return peer_address_;
- }
-
- protected:
- IPEndPoint peer_address_ = IPEndPoint(net::test::Any4(), 65535);
-};
-
-namespace {
-
-static const char kPayload[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-
-class QuicStreamSequencerTest : public ::testing::Test {
- public:
- void ConsumeData(size_t num_bytes) {
- char buffer[1024];
- ASSERT_GT(arraysize(buffer), num_bytes);
- struct iovec iov;
- iov.iov_base = buffer;
- iov.iov_len = num_bytes;
- ASSERT_EQ(static_cast<int>(num_bytes), sequencer_->Readv(&iov, 1));
- }
-
- protected:
- QuicStreamSequencerTest()
- : connection_(new MockQuicConnection(&helper_,
- &alarm_factory_,
- Perspective::IS_CLIENT)),
- session_(connection_),
- stream_(&session_, 1),
- sequencer_(new QuicStreamSequencer(&stream_, &clock_)) {}
-
- // Verify that the data in first region match with the expected[0].
- bool VerifyReadableRegion(const vector<string>& expected) {
- iovec iovecs[1];
- if (sequencer_->GetReadableRegions(iovecs, 1)) {
- return (VerifyIovecs(iovecs, 1, vector<string>{expected[0]}));
- }
- return false;
- }
-
- // Verify that the data in each of currently readable regions match with each
- // item given in |expected|.
- bool VerifyReadableRegions(const vector<string>& expected) {
- iovec iovecs[5];
- size_t num_iovecs =
- sequencer_->GetReadableRegions(iovecs, arraysize(iovecs));
- return VerifyReadableRegion(expected) &&
- VerifyIovecs(iovecs, num_iovecs, expected);
- }
-
- bool VerifyIovecs(iovec* iovecs,
- size_t num_iovecs,
- const vector<string>& expected) {
- int start_position = 0;
- for (size_t i = 0; i < num_iovecs; ++i) {
- if (!VerifyIovec(iovecs[i],
- expected[0].substr(start_position, iovecs[i].iov_len))) {
- return false;
- }
- start_position += iovecs[i].iov_len;
- }
- return true;
- }
-
- bool VerifyIovec(const iovec& iovec, StringPiece expected) {
- if (iovec.iov_len != expected.length()) {
- LOG(ERROR) << "Invalid length: " << iovec.iov_len << " vs "
- << expected.length();
- return false;
- }
- if (memcmp(iovec.iov_base, expected.data(), expected.length()) != 0) {
- LOG(ERROR) << "Invalid data: " << static_cast<char*>(iovec.iov_base)
- << " vs " << expected;
- return false;
- }
- return true;
- }
-
- void OnFinFrame(QuicStreamOffset byte_offset, const char* data) {
- QuicStreamFrame frame;
- frame.stream_id = 1;
- frame.offset = byte_offset;
- frame.data_buffer = data;
- frame.data_length = strlen(data);
- frame.fin = true;
- sequencer_->OnStreamFrame(frame);
- }
-
- void OnFrame(QuicStreamOffset byte_offset, const char* data) {
- QuicStreamFrame frame;
- frame.stream_id = 1;
- frame.offset = byte_offset;
- frame.data_buffer = data;
- frame.data_length = strlen(data);
- frame.fin = false;
- sequencer_->OnStreamFrame(frame);
- }
-
- size_t NumBufferedBytes() {
- return QuicStreamSequencerPeer::GetNumBufferedBytes(sequencer_.get());
- }
-
- MockQuicConnectionHelper helper_;
- MockAlarmFactory alarm_factory_;
- MockQuicConnection* connection_;
- MockClock clock_;
- MockQuicSpdySession session_;
- testing::StrictMock<MockStream> stream_;
- std::unique_ptr<QuicStreamSequencer> sequencer_;
-};
-
-// TODO(rch): reorder these tests so they build on each other.
-
-TEST_F(QuicStreamSequencerTest, RejectOldFrame) {
- EXPECT_CALL(stream_, OnDataAvailable())
- .WillOnce(testing::Invoke(
- CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
- base::Unretained(this), 3)));
-
- OnFrame(0, "abc");
-
- EXPECT_EQ(0u, NumBufferedBytes());
- EXPECT_EQ(3u, sequencer_->NumBytesConsumed());
- EXPECT_EQ(3u, stream_.flow_controller()->bytes_consumed());
- // Ignore this - it matches a past packet number and we should not see it
- // again.
- OnFrame(0, "def");
- EXPECT_EQ(0u, NumBufferedBytes());
-}
-
-TEST_F(QuicStreamSequencerTest, RejectBufferedFrame) {
- EXPECT_CALL(stream_, OnDataAvailable());
-
- OnFrame(0, "abc");
- EXPECT_EQ(3u, NumBufferedBytes());
- EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
-
- // Ignore this - it matches a buffered frame.
- // Right now there's no checking that the payload is consistent.
- OnFrame(0, "def");
- EXPECT_EQ(3u, NumBufferedBytes());
-}
-
-TEST_F(QuicStreamSequencerTest, FullFrameConsumed) {
- EXPECT_CALL(stream_, OnDataAvailable())
- .WillOnce(testing::Invoke(
- CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
- base::Unretained(this), 3)));
-
- OnFrame(0, "abc");
- EXPECT_EQ(0u, NumBufferedBytes());
- EXPECT_EQ(3u, sequencer_->NumBytesConsumed());
-}
-
-TEST_F(QuicStreamSequencerTest, BlockedThenFullFrameConsumed) {
- sequencer_->SetBlockedUntilFlush();
-
- OnFrame(0, "abc");
- EXPECT_EQ(3u, NumBufferedBytes());
- EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
-
- EXPECT_CALL(stream_, OnDataAvailable())
- .WillOnce(testing::Invoke(
- CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
- base::Unretained(this), 3)));
- sequencer_->SetUnblocked();
- EXPECT_EQ(0u, NumBufferedBytes());
- EXPECT_EQ(3u, sequencer_->NumBytesConsumed());
-
- EXPECT_CALL(stream_, OnDataAvailable())
- .WillOnce(testing::Invoke(
- CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
- base::Unretained(this), 3)));
- EXPECT_FALSE(sequencer_->IsClosed());
- OnFinFrame(3, "def");
- EXPECT_TRUE(sequencer_->IsClosed());
-}
-
-TEST_F(QuicStreamSequencerTest, BlockedThenFullFrameAndFinConsumed) {
- sequencer_->SetBlockedUntilFlush();
-
- OnFinFrame(0, "abc");
- EXPECT_EQ(3u, NumBufferedBytes());
- EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
-
- EXPECT_CALL(stream_, OnDataAvailable())
- .WillOnce(testing::Invoke(
- CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
- base::Unretained(this), 3)));
- EXPECT_FALSE(sequencer_->IsClosed());
- sequencer_->SetUnblocked();
- EXPECT_TRUE(sequencer_->IsClosed());
- EXPECT_EQ(0u, NumBufferedBytes());
- EXPECT_EQ(3u, sequencer_->NumBytesConsumed());
-}
-
-TEST_F(QuicStreamSequencerTest, EmptyFrame) {
- EXPECT_CALL(stream_,
- CloseConnectionWithDetails(QUIC_EMPTY_STREAM_FRAME_NO_FIN, _));
- OnFrame(0, "");
- EXPECT_EQ(0u, NumBufferedBytes());
- EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
-}
-
-TEST_F(QuicStreamSequencerTest, EmptyFinFrame) {
- EXPECT_CALL(stream_, OnDataAvailable());
- OnFinFrame(0, "");
- EXPECT_EQ(0u, NumBufferedBytes());
- EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
-}
-
-TEST_F(QuicStreamSequencerTest, PartialFrameConsumed) {
- EXPECT_CALL(stream_, OnDataAvailable())
- .WillOnce(testing::Invoke(
- CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
- base::Unretained(this), 2)));
-
- OnFrame(0, "abc");
- EXPECT_EQ(1u, NumBufferedBytes());
- EXPECT_EQ(2u, sequencer_->NumBytesConsumed());
-}
-
-TEST_F(QuicStreamSequencerTest, NextxFrameNotConsumed) {
- EXPECT_CALL(stream_, OnDataAvailable());
-
- OnFrame(0, "abc");
- EXPECT_EQ(3u, NumBufferedBytes());
- EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
- EXPECT_EQ(0, sequencer_->num_early_frames_received());
-}
-
-TEST_F(QuicStreamSequencerTest, FutureFrameNotProcessed) {
- OnFrame(3, "abc");
- EXPECT_EQ(3u, NumBufferedBytes());
- EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
- EXPECT_EQ(1, sequencer_->num_early_frames_received());
-}
-
-TEST_F(QuicStreamSequencerTest, OutOfOrderFrameProcessed) {
- // Buffer the first
- OnFrame(6, "ghi");
- EXPECT_EQ(3u, NumBufferedBytes());
- EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
- EXPECT_EQ(3u, sequencer_->NumBytesBuffered());
- // Buffer the second
- OnFrame(3, "def");
- EXPECT_EQ(6u, NumBufferedBytes());
- EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
- EXPECT_EQ(6u, sequencer_->NumBytesBuffered());
-
- EXPECT_CALL(stream_, OnDataAvailable())
- .WillOnce(testing::Invoke(
- CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
- base::Unretained(this), 9)));
-
- // Now process all of them at once.
- OnFrame(0, "abc");
- EXPECT_EQ(9u, sequencer_->NumBytesConsumed());
- EXPECT_EQ(0u, sequencer_->NumBytesBuffered());
-
- EXPECT_EQ(0u, NumBufferedBytes());
-}
-
-TEST_F(QuicStreamSequencerTest, BasicHalfCloseOrdered) {
- InSequence s;
-
- EXPECT_CALL(stream_, OnDataAvailable())
- .WillOnce(testing::Invoke(
- CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
- base::Unretained(this), 3)));
- OnFinFrame(0, "abc");
-
- EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
-}
-
-TEST_F(QuicStreamSequencerTest, BasicHalfCloseUnorderedWithFlush) {
- OnFinFrame(6, "");
- EXPECT_EQ(6u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
-
- OnFrame(3, "def");
- EXPECT_CALL(stream_, OnDataAvailable())
- .WillOnce(testing::Invoke(
- CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
- base::Unretained(this), 6)));
- EXPECT_FALSE(sequencer_->IsClosed());
- OnFrame(0, "abc");
- EXPECT_TRUE(sequencer_->IsClosed());
-}
-
-TEST_F(QuicStreamSequencerTest, BasicHalfUnordered) {
- OnFinFrame(3, "");
- EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
-
- EXPECT_CALL(stream_, OnDataAvailable())
- .WillOnce(testing::Invoke(
- CreateFunctor(&QuicStreamSequencerTest::ConsumeData,
- base::Unretained(this), 3)));
- EXPECT_FALSE(sequencer_->IsClosed());
- OnFrame(0, "abc");
- EXPECT_TRUE(sequencer_->IsClosed());
-}
-
-TEST_F(QuicStreamSequencerTest, TerminateWithReadv) {
- char buffer[3];
-
- OnFinFrame(3, "");
- EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
-
- EXPECT_FALSE(sequencer_->IsClosed());
-
- EXPECT_CALL(stream_, OnDataAvailable());
- OnFrame(0, "abc");
-
- iovec iov = {&buffer[0], 3};
- int bytes_read = sequencer_->Readv(&iov, 1);
- EXPECT_EQ(3, bytes_read);
- EXPECT_TRUE(sequencer_->IsClosed());
-}
-
-TEST_F(QuicStreamSequencerTest, MutipleOffsets) {
- OnFinFrame(3, "");
- EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
-
- EXPECT_CALL(stream_, Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS));
- OnFinFrame(5, "");
- EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
-
- EXPECT_CALL(stream_, Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS));
- OnFinFrame(1, "");
- EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
-
- OnFinFrame(3, "");
- EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get()));
-}
-
-class QuicSequencerRandomTest : public QuicStreamSequencerTest {
- public:
- typedef pair<int, string> Frame;
- typedef vector<Frame> FrameList;
-
- void CreateFrames() {
- int payload_size = arraysize(kPayload) - 1;
- int remaining_payload = payload_size;
- while (remaining_payload != 0) {
- int size = min(OneToN(6), remaining_payload);
- int index = payload_size - remaining_payload;
- list_.push_back(std::make_pair(index, string(kPayload + index, size)));
- remaining_payload -= size;
- }
- }
-
- QuicSequencerRandomTest() { CreateFrames(); }
-
- int OneToN(int n) { return base::RandInt(1, n); }
-
- void ReadAvailableData() {
- // Read all available data
- char output[arraysize(kPayload) + 1];
- iovec iov;
- iov.iov_base = output;
- iov.iov_len = arraysize(output);
- int bytes_read = sequencer_->Readv(&iov, 1);
- EXPECT_NE(0, bytes_read);
- output_.append(output, bytes_read);
- }
-
- string output_;
- // Data which peek at using GetReadableRegion if we back up.
- string peeked_;
- FrameList list_;
-};
-
-// All frames are processed as soon as we have sequential data.
-// Infinite buffering, so all frames are acked right away.
-TEST_F(QuicSequencerRandomTest, RandomFramesNoDroppingNoBackup) {
- InSequence s;
- EXPECT_CALL(stream_, OnDataAvailable())
- .Times(AnyNumber())
- .WillRepeatedly(
- Invoke(this, &QuicSequencerRandomTest::ReadAvailableData));
-
- while (!list_.empty()) {
- int index = OneToN(list_.size()) - 1;
- LOG(ERROR) << "Sending index " << index << " " << list_[index].second;
- OnFrame(list_[index].first, list_[index].second.data());
-
- list_.erase(list_.begin() + index);
- }
-
- ASSERT_EQ(arraysize(kPayload) - 1, output_.size());
- EXPECT_EQ(kPayload, output_);
-}
-
-TEST_F(QuicSequencerRandomTest, RandomFramesNoDroppingBackup) {
- char buffer[10];
- iovec iov[2];
- iov[0].iov_base = &buffer[0];
- iov[0].iov_len = 5;
- iov[1].iov_base = &buffer[5];
- iov[1].iov_len = 5;
-
- EXPECT_CALL(stream_, OnDataAvailable()).Times(AnyNumber());
-
- while (output_.size() != arraysize(kPayload) - 1) {
- if (!list_.empty() && (base::RandUint64() % 2 == 0)) { // Send data
- int index = OneToN(list_.size()) - 1;
- OnFrame(list_[index].first, list_[index].second.data());
- list_.erase(list_.begin() + index);
- } else { // Read data
- bool has_bytes = sequencer_->HasBytesToRead();
- iovec peek_iov[20];
- int iovs_peeked = sequencer_->GetReadableRegions(peek_iov, 20);
- QuicTime timestamp = clock_.ApproximateNow();
- if (has_bytes) {
- ASSERT_LT(0, iovs_peeked);
- ASSERT_TRUE(sequencer_->GetReadableRegion(peek_iov, &timestamp));
- } else {
- ASSERT_EQ(0, iovs_peeked);
- ASSERT_FALSE(sequencer_->GetReadableRegion(peek_iov, &timestamp));
- }
- int total_bytes_to_peek = arraysize(buffer);
- for (int i = 0; i < iovs_peeked; ++i) {
- int bytes_to_peek = min<int>(peek_iov[i].iov_len, total_bytes_to_peek);
- peeked_.append(static_cast<char*>(peek_iov[i].iov_base), bytes_to_peek);
- total_bytes_to_peek -= bytes_to_peek;
- if (total_bytes_to_peek == 0) {
- break;
- }
- }
- int bytes_read = sequencer_->Readv(iov, 2);
- output_.append(buffer, bytes_read);
- ASSERT_EQ(output_.size(), peeked_.size());
- }
- }
- EXPECT_EQ(string(kPayload), output_);
- EXPECT_EQ(string(kPayload), peeked_);
-}
-
-// Same as above, just using a different method for reading.
-TEST_F(QuicStreamSequencerTest, MarkConsumed) {
- InSequence s;
- EXPECT_CALL(stream_, OnDataAvailable());
-
- OnFrame(0, "abc");
- OnFrame(3, "def");
- OnFrame(6, "ghi");
-
- // abcdefghi buffered.
- EXPECT_EQ(9u, sequencer_->NumBytesBuffered());
-
- // Peek into the data.
- vector<string> expected = {"abcdefghi"};
- ASSERT_TRUE(VerifyReadableRegions(expected));
-
- // Consume 1 byte.
- sequencer_->MarkConsumed(1);
- EXPECT_EQ(1u, stream_.flow_controller()->bytes_consumed());
- // Verify data.
- vector<string> expected2 = {"bcdefghi"};
- ASSERT_TRUE(VerifyReadableRegions(expected2));
- EXPECT_EQ(8u, sequencer_->NumBytesBuffered());
-
- // Consume 2 bytes.
- sequencer_->MarkConsumed(2);
- EXPECT_EQ(3u, stream_.flow_controller()->bytes_consumed());
- // Verify data.
- vector<string> expected3 = {"defghi"};
- ASSERT_TRUE(VerifyReadableRegions(expected3));
- EXPECT_EQ(6u, sequencer_->NumBytesBuffered());
-
- // Consume 5 bytes.
- sequencer_->MarkConsumed(5);
- EXPECT_EQ(8u, stream_.flow_controller()->bytes_consumed());
- // Verify data.
- vector<string> expected4{"i"};
- ASSERT_TRUE(VerifyReadableRegions(expected4));
- EXPECT_EQ(1u, sequencer_->NumBytesBuffered());
-}
-
-TEST_F(QuicStreamSequencerTest, MarkConsumedError) {
- EXPECT_CALL(stream_, OnDataAvailable());
-
- OnFrame(0, "abc");
- OnFrame(9, "jklmnopqrstuvwxyz");
-
- // Peek into the data. Only the first chunk should be readable because of the
- // missing data.
- vector<string> expected{"abc"};
- ASSERT_TRUE(VerifyReadableRegions(expected));
-
- // Now, attempt to mark consumed more data than was readable and expect the
- // stream to be closed.
- EXPECT_CALL(stream_, Reset(QUIC_ERROR_PROCESSING_STREAM));
- EXPECT_DFATAL(sequencer_->MarkConsumed(4),
- "Invalid argument to MarkConsumed."
- " expect to consume: 4, but not enough bytes available.");
-}
-
-TEST_F(QuicStreamSequencerTest, MarkConsumedWithMissingPacket) {
- InSequence s;
- EXPECT_CALL(stream_, OnDataAvailable());
-
- OnFrame(0, "abc");
- OnFrame(3, "def");
- // Missing packet: 6, ghi.
- OnFrame(9, "jkl");
-
- vector<string> expected = {"abcdef"};
- ASSERT_TRUE(VerifyReadableRegions(expected));
-
- sequencer_->MarkConsumed(6);
-}
-
-TEST_F(QuicStreamSequencerTest, DontAcceptOverlappingFrames) {
- // The peer should never send us non-identical stream frames which contain
- // overlapping byte ranges - if they do, we close the connection.
-
- QuicStreamFrame frame1(kClientDataStreamId1, false, 1, StringPiece("hello"));
- sequencer_->OnStreamFrame(frame1);
-
- QuicStreamFrame frame2(kClientDataStreamId1, false, 2, StringPiece("hello"));
- EXPECT_CALL(stream_,
- CloseConnectionWithDetails(QUIC_OVERLAPPING_STREAM_DATA, _))
- .Times(1);
- sequencer_->OnStreamFrame(frame2);
-}
-
-TEST_F(QuicStreamSequencerTest, InOrderTimestamps) {
- // This test verifies that timestamps returned by
- // GetReadableRegion() are in the correct sequence when frames
- // arrive at the sequencer in order.
- EXPECT_CALL(stream_, OnDataAvailable());
-
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
-
- // Buffer the first frame.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- QuicTime t1 = clock_.ApproximateNow();
- OnFrame(0, "abc");
- EXPECT_EQ(3u, NumBufferedBytes());
- EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
- EXPECT_EQ(3u, sequencer_->NumBytesBuffered());
- // Buffer the second frame.
- QuicTime t2 = clock_.ApproximateNow();
- OnFrame(3, "def");
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- EXPECT_EQ(6u, NumBufferedBytes());
- EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
- EXPECT_EQ(6u, sequencer_->NumBytesBuffered());
-
- iovec iovecs[1];
- QuicTime timestamp(QuicTime::Zero());
-
- EXPECT_TRUE(sequencer_->GetReadableRegion(iovecs, &timestamp));
- EXPECT_EQ(timestamp, t1);
- QuicStreamSequencerTest::ConsumeData(3);
- EXPECT_EQ(3u, NumBufferedBytes());
- EXPECT_EQ(3u, sequencer_->NumBytesConsumed());
- EXPECT_EQ(3u, sequencer_->NumBytesBuffered());
-
- EXPECT_TRUE(sequencer_->GetReadableRegion(iovecs, &timestamp));
- EXPECT_EQ(timestamp, t2);
- QuicStreamSequencerTest::ConsumeData(3);
- EXPECT_EQ(0u, NumBufferedBytes());
- EXPECT_EQ(6u, sequencer_->NumBytesConsumed());
- EXPECT_EQ(0u, sequencer_->NumBytesBuffered());
-}
-
-TEST_F(QuicStreamSequencerTest, OutOfOrderTimestamps) {
- // This test verifies that timestamps returned by
- // GetReadableRegion() are in the correct sequence when frames
- // arrive at the sequencer out of order.
- EXPECT_CALL(stream_, OnDataAvailable());
-
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
-
- // Buffer the first frame
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- QuicTime t1 = clock_.ApproximateNow();
- OnFrame(3, "def");
- EXPECT_EQ(3u, NumBufferedBytes());
- EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
- EXPECT_EQ(3u, sequencer_->NumBytesBuffered());
- // Buffer the second frame
- QuicTime t2 = clock_.ApproximateNow();
- OnFrame(0, "abc");
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
- EXPECT_EQ(6u, NumBufferedBytes());
- EXPECT_EQ(0u, sequencer_->NumBytesConsumed());
- EXPECT_EQ(6u, sequencer_->NumBytesBuffered());
-
- iovec iovecs[1];
- QuicTime timestamp(QuicTime::Zero());
-
- EXPECT_TRUE(sequencer_->GetReadableRegion(iovecs, &timestamp));
- EXPECT_EQ(timestamp, t2);
- QuicStreamSequencerTest::ConsumeData(3);
- EXPECT_EQ(3u, NumBufferedBytes());
- EXPECT_EQ(3u, sequencer_->NumBytesConsumed());
- EXPECT_EQ(3u, sequencer_->NumBytesBuffered());
-
- EXPECT_TRUE(sequencer_->GetReadableRegion(iovecs, &timestamp));
- EXPECT_EQ(timestamp, t1);
- QuicStreamSequencerTest::ConsumeData(3);
- EXPECT_EQ(0u, NumBufferedBytes());
- EXPECT_EQ(6u, sequencer_->NumBytesConsumed());
- EXPECT_EQ(0u, sequencer_->NumBytesBuffered());
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_sustained_bandwidth_recorder.cc b/chromium/net/quic/quic_sustained_bandwidth_recorder.cc
deleted file mode 100644
index 41aa51e7071..00000000000
--- a/chromium/net/quic/quic_sustained_bandwidth_recorder.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_sustained_bandwidth_recorder.h"
-
-#include "base/logging.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-QuicSustainedBandwidthRecorder::QuicSustainedBandwidthRecorder()
- : has_estimate_(false),
- is_recording_(false),
- bandwidth_estimate_recorded_during_slow_start_(false),
- bandwidth_estimate_(QuicBandwidth::Zero()),
- max_bandwidth_estimate_(QuicBandwidth::Zero()),
- max_bandwidth_timestamp_(0),
- start_time_(QuicTime::Zero()) {}
-
-void QuicSustainedBandwidthRecorder::RecordEstimate(bool in_recovery,
- bool in_slow_start,
- QuicBandwidth bandwidth,
- QuicTime estimate_time,
- QuicWallTime wall_time,
- QuicTime::Delta srtt) {
- if (in_recovery) {
- is_recording_ = false;
- DVLOG(1) << "Stopped recording at: " << estimate_time.ToDebuggingValue();
- return;
- }
-
- if (!is_recording_) {
- // This is the first estimate of a new recording period.
- start_time_ = estimate_time;
- is_recording_ = true;
- DVLOG(1) << "Started recording at: " << start_time_.ToDebuggingValue();
- return;
- }
-
- // If we have been recording for at least 3 * srtt, then record the latest
- // bandwidth estimate as a valid sustained bandwidth estimate.
- if (estimate_time.Subtract(start_time_) >= srtt.Multiply(3)) {
- has_estimate_ = true;
- bandwidth_estimate_recorded_during_slow_start_ = in_slow_start;
- bandwidth_estimate_ = bandwidth;
- DVLOG(1) << "New sustained bandwidth estimate (KBytes/s): "
- << bandwidth_estimate_.ToKBytesPerSecond();
- }
-
- // Check for an increase in max bandwidth.
- if (bandwidth > max_bandwidth_estimate_) {
- max_bandwidth_estimate_ = bandwidth;
- max_bandwidth_timestamp_ = wall_time.ToUNIXSeconds();
- DVLOG(1) << "New max bandwidth estimate (KBytes/s): "
- << max_bandwidth_estimate_.ToKBytesPerSecond();
- }
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_sustained_bandwidth_recorder.h b/chromium/net/quic/quic_sustained_bandwidth_recorder.h
deleted file mode 100644
index bc0d1b802ac..00000000000
--- a/chromium/net/quic/quic_sustained_bandwidth_recorder.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_SUSTAINED_BANDWIDTH_RECORDER_H_
-#define NET_QUIC_QUIC_SUSTAINED_BANDWIDTH_RECORDER_H_
-
-#include <stdint.h>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-namespace test {
-class QuicSustainedBandwidthRecorderPeer;
-} // namespace test
-
-// This class keeps track of a sustained bandwidth estimate to ultimately send
-// to the client in a server config update message. A sustained bandwidth
-// estimate is only marked as valid if the QuicSustainedBandwidthRecorder has
-// been given uninterrupted reliable estimates over a certain period of time.
-class NET_EXPORT_PRIVATE QuicSustainedBandwidthRecorder {
- public:
- QuicSustainedBandwidthRecorder();
-
- // As long as |in_recovery| is consistently false, multiple calls to this
- // method over a 3 * srtt period results in storage of a valid sustained
- // bandwidth estimate.
- // |time_now| is used as a max bandwidth timestamp if needed.
- void RecordEstimate(bool in_recovery,
- bool in_slow_start,
- QuicBandwidth bandwidth,
- QuicTime estimate_time,
- QuicWallTime wall_time,
- QuicTime::Delta srtt);
-
- bool HasEstimate() const { return has_estimate_; }
-
- QuicBandwidth BandwidthEstimate() const {
- DCHECK(has_estimate_);
- return bandwidth_estimate_;
- }
-
- QuicBandwidth MaxBandwidthEstimate() const {
- DCHECK(has_estimate_);
- return max_bandwidth_estimate_;
- }
-
- int64_t MaxBandwidthTimestamp() const {
- DCHECK(has_estimate_);
- return max_bandwidth_timestamp_;
- }
-
- bool EstimateRecordedDuringSlowStart() const {
- DCHECK(has_estimate_);
- return bandwidth_estimate_recorded_during_slow_start_;
- }
-
- private:
- friend class test::QuicSustainedBandwidthRecorderPeer;
-
- // True if we have been able to calculate sustained bandwidth, over at least
- // one recording period (3 * rtt).
- bool has_estimate_;
-
- // True if the last call to RecordEstimate had a reliable estimate.
- bool is_recording_;
-
- // True if the current sustained bandwidth estimate was generated while in
- // slow start.
- bool bandwidth_estimate_recorded_during_slow_start_;
-
- // The latest sustained bandwidth estimate.
- QuicBandwidth bandwidth_estimate_;
-
- // The maximum sustained bandwidth seen over the lifetime of the connection.
- QuicBandwidth max_bandwidth_estimate_;
-
- // Timestamp indicating when the max_bandwidth_estimate_ was seen.
- int64_t max_bandwidth_timestamp_;
-
- // Timestamp marking the beginning of the latest recording period.
- QuicTime start_time_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicSustainedBandwidthRecorder);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_SUSTAINED_BANDWIDTH_RECORDER_H_
diff --git a/chromium/net/quic/quic_sustained_bandwidth_recorder_test.cc b/chromium/net/quic/quic_sustained_bandwidth_recorder_test.cc
deleted file mode 100644
index 91cff412927..00000000000
--- a/chromium/net/quic/quic_sustained_bandwidth_recorder_test.cc
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_sustained_bandwidth_recorder.h"
-
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_time.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-namespace {
-
-TEST(QuicSustainedBandwidthRecorderTest, BandwidthEstimates) {
- QuicSustainedBandwidthRecorder recorder;
- EXPECT_FALSE(recorder.HasEstimate());
-
- QuicTime estimate_time = QuicTime::Zero();
- QuicWallTime wall_time = QuicWallTime::Zero();
- QuicTime::Delta srtt = QuicTime::Delta::FromMilliseconds(150);
- const int kBandwidthBitsPerSecond = 12345678;
- QuicBandwidth bandwidth =
- QuicBandwidth::FromBitsPerSecond(kBandwidthBitsPerSecond);
-
- bool in_recovery = false;
- bool in_slow_start = false;
-
- // This triggers recording, but should not yield a valid estimate yet.
- recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
- wall_time, srtt);
- EXPECT_FALSE(recorder.HasEstimate());
-
- // Send a second reading, again this should not result in a valid estimate,
- // as not enough time has passed.
- estimate_time = estimate_time.Add(srtt);
- recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
- wall_time, srtt);
- EXPECT_FALSE(recorder.HasEstimate());
-
- // Now 3 * kSRTT has elapsed since first recording, expect a valid estimate.
- estimate_time = estimate_time.Add(srtt);
- estimate_time = estimate_time.Add(srtt);
- recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
- wall_time, srtt);
- EXPECT_TRUE(recorder.HasEstimate());
- EXPECT_EQ(recorder.BandwidthEstimate(), bandwidth);
- EXPECT_EQ(recorder.BandwidthEstimate(), recorder.MaxBandwidthEstimate());
-
- // Resetting, and sending a different estimate will only change output after
- // a further 3 * kSRTT has passed.
- QuicBandwidth second_bandwidth =
- QuicBandwidth::FromBitsPerSecond(2 * kBandwidthBitsPerSecond);
- // Reset the recorder by passing in a measurement while in recovery.
- in_recovery = true;
- recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
- wall_time, srtt);
- in_recovery = false;
- recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
- wall_time, srtt);
- EXPECT_EQ(recorder.BandwidthEstimate(), bandwidth);
-
- estimate_time = estimate_time.Add(srtt.Multiply(3));
- const int64_t kSeconds = 556677;
- QuicWallTime second_bandwidth_wall_time =
- QuicWallTime::FromUNIXSeconds(kSeconds);
- recorder.RecordEstimate(in_recovery, in_slow_start, second_bandwidth,
- estimate_time, second_bandwidth_wall_time, srtt);
- EXPECT_EQ(recorder.BandwidthEstimate(), second_bandwidth);
- EXPECT_EQ(recorder.BandwidthEstimate(), recorder.MaxBandwidthEstimate());
- EXPECT_EQ(recorder.MaxBandwidthTimestamp(), kSeconds);
-
- // Reset again, this time recording a lower bandwidth than before.
- QuicBandwidth third_bandwidth =
- QuicBandwidth::FromBitsPerSecond(0.5 * kBandwidthBitsPerSecond);
- // Reset the recorder by passing in an unreliable measurement.
- recorder.RecordEstimate(in_recovery, in_slow_start, third_bandwidth,
- estimate_time, wall_time, srtt);
- recorder.RecordEstimate(in_recovery, in_slow_start, third_bandwidth,
- estimate_time, wall_time, srtt);
- EXPECT_EQ(recorder.BandwidthEstimate(), third_bandwidth);
-
- estimate_time = estimate_time.Add(srtt.Multiply(3));
- recorder.RecordEstimate(in_recovery, in_slow_start, third_bandwidth,
- estimate_time, wall_time, srtt);
- EXPECT_EQ(recorder.BandwidthEstimate(), third_bandwidth);
-
- // Max bandwidth should not have changed.
- EXPECT_LT(third_bandwidth, second_bandwidth);
- EXPECT_EQ(recorder.MaxBandwidthEstimate(), second_bandwidth);
- EXPECT_EQ(recorder.MaxBandwidthTimestamp(), kSeconds);
-}
-
-TEST(QuicSustainedBandwidthRecorderTest, SlowStart) {
- // Verify that slow start status is correctly recorded.
- QuicSustainedBandwidthRecorder recorder;
- EXPECT_FALSE(recorder.HasEstimate());
-
- QuicTime estimate_time = QuicTime::Zero();
- QuicWallTime wall_time = QuicWallTime::Zero();
- QuicTime::Delta srtt = QuicTime::Delta::FromMilliseconds(150);
- const int kBandwidthBitsPerSecond = 12345678;
- QuicBandwidth bandwidth =
- QuicBandwidth::FromBitsPerSecond(kBandwidthBitsPerSecond);
-
- bool in_recovery = false;
- bool in_slow_start = true;
-
- // This triggers recording, but should not yield a valid estimate yet.
- recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
- wall_time, srtt);
-
- // Now 3 * kSRTT has elapsed since first recording, expect a valid estimate.
- estimate_time = estimate_time.Add(srtt.Multiply(3));
- recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
- wall_time, srtt);
- EXPECT_TRUE(recorder.HasEstimate());
- EXPECT_TRUE(recorder.EstimateRecordedDuringSlowStart());
-
- // Now send another estimate, this time not in slow start.
- estimate_time = estimate_time.Add(srtt.Multiply(3));
- in_slow_start = false;
- recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
- wall_time, srtt);
- EXPECT_TRUE(recorder.HasEstimate());
- EXPECT_FALSE(recorder.EstimateRecordedDuringSlowStart());
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_time.cc b/chromium/net/quic/quic_time.cc
deleted file mode 100644
index 2b3684bdca5..00000000000
--- a/chromium/net/quic/quic_time.cc
+++ /dev/null
@@ -1,65 +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/quic_time.h"
-
-#include <limits>
-
-#include "base/logging.h"
-
-namespace net {
-
-uint64_t QuicWallTime::ToUNIXSeconds() const {
- return microseconds_ / 1000000;
-}
-
-uint64_t QuicWallTime::ToUNIXMicroseconds() const {
- return microseconds_;
-}
-
-bool QuicWallTime::IsAfter(QuicWallTime other) const {
- return microseconds_ > other.microseconds_;
-}
-
-bool QuicWallTime::IsBefore(QuicWallTime other) const {
- return microseconds_ < other.microseconds_;
-}
-
-bool QuicWallTime::IsZero() const {
- return microseconds_ == 0;
-}
-
-QuicTime::Delta QuicWallTime::AbsoluteDifference(QuicWallTime other) const {
- uint64_t d;
-
- if (microseconds_ > other.microseconds_) {
- d = microseconds_ - other.microseconds_;
- } else {
- d = other.microseconds_ - microseconds_;
- }
-
- if (d > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
- d = std::numeric_limits<int64_t>::max();
- }
- return QuicTime::Delta::FromMicroseconds(d);
-}
-
-QuicWallTime QuicWallTime::Add(QuicTime::Delta delta) const {
- uint64_t microseconds = microseconds_ + delta.ToMicroseconds();
- if (microseconds < microseconds_) {
- microseconds = std::numeric_limits<uint64_t>::max();
- }
- return QuicWallTime(microseconds);
-}
-
-// TODO(ianswett) Test this.
-QuicWallTime QuicWallTime::Subtract(QuicTime::Delta delta) const {
- uint64_t microseconds = microseconds_ - delta.ToMicroseconds();
- if (microseconds > microseconds_) {
- microseconds = 0;
- }
- return QuicWallTime(microseconds);
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_time.h b/chromium/net/quic/quic_time.h
deleted file mode 100644
index 63b2a342ea4..00000000000
--- a/chromium/net/quic/quic_time.h
+++ /dev/null
@@ -1,268 +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.
-//
-// QuicTime represents one point in time, stored in microsecond resolution.
-// QuicTime is monotonically increasing, even across system clock adjustments.
-// The epoch (time 0) of QuicTime is unspecified.
-//
-// This implementation wraps the classes base::TimeTicks and base::TimeDelta.
-
-#ifndef NET_QUIC_QUIC_TIME_H_
-#define NET_QUIC_QUIC_TIME_H_
-
-#include <stdint.h>
-
-#include "base/compiler_specific.h"
-#include "base/time/time.h"
-#include "net/base/net_export.h"
-
-#define QUICTIME_CONSTEXPR inline
-
-namespace net {
-
-static const int kNumSecondsPerMinute = 60;
-static const int kNumSecondsPerHour = kNumSecondsPerMinute * 60;
-static const uint64_t kNumMicrosPerSecond = base::Time::kMicrosecondsPerSecond;
-static const uint64_t kNumMicrosPerMilli =
- base::Time::kMicrosecondsPerMillisecond;
-
-// A QuicTime is a purely relative time. QuicTime values from different clocks
-// cannot be compared to each other. If you need an absolute time, see
-// QuicWallTime, below.
-class NET_EXPORT_PRIVATE QuicTime {
- public:
- // A QuicTime::Delta represents the signed difference between two points in
- // time, stored in microsecond resolution.
- class NET_EXPORT_PRIVATE Delta {
- public:
- explicit Delta(base::TimeDelta delta);
-
- // Create a object with an offset of 0.
- static QUICTIME_CONSTEXPR Delta Zero() { return Delta(0); }
-
- // Create a object with infinite offset time.
- static QUICTIME_CONSTEXPR Delta Infinite() {
- return Delta(kQuicInfiniteTimeUs);
- }
-
- // Converts a number of seconds to a time offset.
- static QUICTIME_CONSTEXPR Delta FromSeconds(int64_t secs) {
- return Delta(secs * 1000 * 1000);
- }
-
- // Converts a number of milliseconds to a time offset.
- static QUICTIME_CONSTEXPR Delta FromMilliseconds(int64_t ms) {
- return Delta(ms * 1000);
- }
-
- // Converts a number of microseconds to a time offset.
- static QUICTIME_CONSTEXPR Delta FromMicroseconds(int64_t us) {
- return Delta(us);
- }
-
- // Converts the time offset to a rounded number of seconds.
- inline int64_t ToSeconds() const { return time_offset_ / 1000 / 1000; }
-
- // Converts the time offset to a rounded number of milliseconds.
- inline int64_t ToMilliseconds() const { return time_offset_ / 1000; }
-
- // Converts the time offset to a rounded number of microseconds.
- inline int64_t ToMicroseconds() const { return time_offset_; }
-
- inline Delta Add(Delta delta) const WARN_UNUSED_RESULT {
- return Delta(time_offset_ + delta.time_offset_);
- }
-
- inline Delta Subtract(Delta delta) const WARN_UNUSED_RESULT {
- return Delta(time_offset_ - delta.time_offset_);
- }
-
- inline Delta Multiply(int i) const WARN_UNUSED_RESULT {
- return Delta(time_offset_ * i);
- }
-
- inline Delta Multiply(double d) const WARN_UNUSED_RESULT {
- return Delta(time_offset_ * d);
- }
-
- // Returns the larger delta of time1 and time2.
- static inline Delta Max(Delta delta1, Delta delta2) {
- return delta1 < delta2 ? delta2 : delta1;
- }
-
- // Returns the smaller delta of time1 and time2.
- static inline Delta Min(Delta delta1, Delta delta2) {
- return delta1 < delta2 ? delta1 : delta2;
- }
-
- inline bool IsZero() const { return time_offset_ == 0; }
-
- inline bool IsInfinite() const {
- return time_offset_ == kQuicInfiniteTimeUs;
- }
-
- private:
- base::TimeDelta delta_;
- friend inline bool operator==(QuicTime::Delta lhs, QuicTime::Delta rhs);
- friend inline bool operator<(QuicTime::Delta lhs, QuicTime::Delta rhs);
- friend inline QuicTime::Delta operator<<(QuicTime::Delta lhs, size_t rhs);
- friend inline QuicTime::Delta operator>>(QuicTime::Delta lhs, size_t rhs);
-
- // Highest number of microseconds that DateTimeOffset can hold.
- static const int64_t kQuicInfiniteTimeUs = INT64_C(0x7fffffffffffffff) / 10;
-
- explicit QUICTIME_CONSTEXPR Delta(int64_t time_offset)
- : time_offset_(time_offset) {}
-
- int64_t time_offset_;
- friend class QuicTime;
- friend class QuicClock;
- };
-
- explicit QuicTime(base::TimeTicks ticks) : time_(ticks.ToInternalValue()) {}
-
- // Creates a new QuicTime with an internal value of 0. IsInitialized()
- // will return false for these times.
- static QUICTIME_CONSTEXPR QuicTime Zero() { return QuicTime(0); }
-
- // Creates a new QuicTime with an infinite time.
- static QUICTIME_CONSTEXPR QuicTime Infinite() {
- return QuicTime(Delta::kQuicInfiniteTimeUs);
- }
-
- // Returns the later time of time1 and time2.
- static inline QuicTime Max(QuicTime time1, QuicTime time2) {
- return time1 < time2 ? time2 : time1;
- }
-
- // Produce the internal value to be used when logging. This value
- // represents the number of microseconds since some epoch. It may
- // be the UNIX epoch on some platforms. On others, it may
- // be a CPU ticks based value.
- inline int64_t ToDebuggingValue() const { return time_; }
-
- inline bool IsInitialized() const { return 0 != time_; }
-
- inline QuicTime Add(Delta delta) const WARN_UNUSED_RESULT {
- return QuicTime(time_ + delta.time_offset_);
- }
-
- inline QuicTime Subtract(Delta delta) const WARN_UNUSED_RESULT {
- return QuicTime(time_ - delta.time_offset_);
- }
-
- inline Delta Subtract(QuicTime other) const WARN_UNUSED_RESULT {
- return Delta(time_ - other.time_);
- }
-
- private:
- friend inline bool operator==(QuicTime lhs, QuicTime rhs);
- friend inline bool operator<(QuicTime lhs, QuicTime rhs);
- friend class QuicClock;
- friend class QuicClockTest;
-
- explicit QUICTIME_CONSTEXPR QuicTime(int64_t time) : time_(time) {}
-
- int64_t time_;
-};
-
-// A QuicWallTime represents an absolute time that is globally consistent. In
-// practice, clock-skew means that comparing values from different machines
-// requires some flexibility in interpretation.
-class NET_EXPORT_PRIVATE QuicWallTime {
- public:
- // FromUNIXSeconds constructs a QuicWallTime from a count of the seconds
- // since the UNIX epoch.
- static QUICTIME_CONSTEXPR QuicWallTime FromUNIXSeconds(uint64_t seconds) {
- return QuicWallTime(seconds * 1000000);
- }
-
- static QUICTIME_CONSTEXPR QuicWallTime
- FromUNIXMicroseconds(uint64_t microseconds) {
- return QuicWallTime(microseconds);
- }
-
- // Zero returns a QuicWallTime set to zero. IsZero will return true for this
- // value.
- static QUICTIME_CONSTEXPR QuicWallTime Zero() { return QuicWallTime(0); }
-
- // Returns the number of seconds since the UNIX epoch.
- uint64_t ToUNIXSeconds() const;
- // Returns the number of microseconds since the UNIX epoch.
- uint64_t ToUNIXMicroseconds() const;
-
- bool IsAfter(QuicWallTime other) const;
- bool IsBefore(QuicWallTime other) const;
-
- // IsZero returns true if this object is the result of calling |Zero|.
- bool IsZero() const;
-
- // AbsoluteDifference returns the absolute value of the time difference
- // between |this| and |other|.
- QuicTime::Delta AbsoluteDifference(QuicWallTime other) const;
-
- // Add returns a new QuicWallTime that represents the time of |this| plus
- // |delta|.
- QuicWallTime Add(QuicTime::Delta delta) const WARN_UNUSED_RESULT;
-
- // Subtract returns a new QuicWallTime that represents the time of |this|
- // minus |delta|.
- QuicWallTime Subtract(QuicTime::Delta delta) const WARN_UNUSED_RESULT;
-
- private:
- explicit QUICTIME_CONSTEXPR QuicWallTime(uint64_t microseconds)
- : microseconds_(microseconds) {}
-
- uint64_t microseconds_;
-};
-
-// Non-member relational operators for QuicTime::Delta.
-inline bool operator==(QuicTime::Delta lhs, QuicTime::Delta rhs) {
- return lhs.time_offset_ == rhs.time_offset_;
-}
-inline bool operator!=(QuicTime::Delta lhs, QuicTime::Delta rhs) {
- return !(lhs == rhs);
-}
-inline bool operator<(QuicTime::Delta lhs, QuicTime::Delta rhs) {
- return lhs.time_offset_ < rhs.time_offset_;
-}
-inline bool operator>(QuicTime::Delta lhs, QuicTime::Delta rhs) {
- return rhs < lhs;
-}
-inline bool operator<=(QuicTime::Delta lhs, QuicTime::Delta rhs) {
- return !(rhs < lhs);
-}
-inline bool operator>=(QuicTime::Delta lhs, QuicTime::Delta rhs) {
- return !(lhs < rhs);
-}
-inline QuicTime::Delta operator<<(QuicTime::Delta lhs, size_t rhs) {
- return QuicTime::Delta(lhs.time_offset_ << rhs);
-}
-inline QuicTime::Delta operator>>(QuicTime::Delta lhs, size_t rhs) {
- return QuicTime::Delta(lhs.time_offset_ >> rhs);
-}
-
-// Non-member relational operators for QuicTime.
-inline bool operator==(QuicTime lhs, QuicTime rhs) {
- return lhs.time_ == rhs.time_;
-}
-inline bool operator!=(QuicTime lhs, QuicTime rhs) {
- return !(lhs == rhs);
-}
-inline bool operator<(QuicTime lhs, QuicTime rhs) {
- return lhs.time_ < rhs.time_;
-}
-inline bool operator>(QuicTime lhs, QuicTime rhs) {
- return rhs < lhs;
-}
-inline bool operator<=(QuicTime lhs, QuicTime rhs) {
- return !(rhs < lhs);
-}
-inline bool operator>=(QuicTime lhs, QuicTime rhs) {
- return !(lhs < rhs);
-}
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_TIME_H_
diff --git a/chromium/net/quic/quic_time_test.cc b/chromium/net/quic/quic_time_test.cc
deleted file mode 100644
index 602de364583..00000000000
--- a/chromium/net/quic/quic_time_test.cc
+++ /dev/null
@@ -1,143 +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/quic_time.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-TEST(QuicTimeDeltaTest, Zero) {
- EXPECT_TRUE(QuicTime::Delta::Zero().IsZero());
- EXPECT_FALSE(QuicTime::Delta::Zero().IsInfinite());
- EXPECT_FALSE(QuicTime::Delta::FromMilliseconds(1).IsZero());
-}
-
-TEST(QuicTimeDeltaTest, Infinite) {
- EXPECT_TRUE(QuicTime::Delta::Infinite().IsInfinite());
- EXPECT_FALSE(QuicTime::Delta::Zero().IsInfinite());
- EXPECT_FALSE(QuicTime::Delta::FromMilliseconds(1).IsInfinite());
-}
-
-TEST(QuicTimeDeltaTest, FromTo) {
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(1),
- QuicTime::Delta::FromMicroseconds(1000));
- EXPECT_EQ(QuicTime::Delta::FromSeconds(1),
- QuicTime::Delta::FromMilliseconds(1000));
- EXPECT_EQ(QuicTime::Delta::FromSeconds(1),
- QuicTime::Delta::FromMicroseconds(1000000));
-
- EXPECT_EQ(1, QuicTime::Delta::FromMicroseconds(1000).ToMilliseconds());
- EXPECT_EQ(2, QuicTime::Delta::FromMilliseconds(2000).ToSeconds());
- EXPECT_EQ(1000, QuicTime::Delta::FromMilliseconds(1).ToMicroseconds());
- EXPECT_EQ(1, QuicTime::Delta::FromMicroseconds(1000).ToMilliseconds());
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(2000).ToMicroseconds(),
- QuicTime::Delta::FromSeconds(2).ToMicroseconds());
-}
-
-TEST(QuicTimeDeltaTest, Add) {
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2000),
- QuicTime::Delta::Zero().Add(QuicTime::Delta::FromMilliseconds(2)));
-}
-
-TEST(QuicTimeDeltaTest, Subtract) {
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(1000),
- QuicTime::Delta::FromMilliseconds(2).Subtract(
- QuicTime::Delta::FromMilliseconds(1)));
-}
-
-TEST(QuicTimeDeltaTest, Multiply) {
- int i = 2;
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(4000),
- QuicTime::Delta::FromMilliseconds(2).Multiply(i));
- double d = 2;
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(4000),
- QuicTime::Delta::FromMilliseconds(2).Multiply(d));
-}
-
-TEST(QuicTimeDeltaTest, Max) {
- EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2000),
- QuicTime::Delta::Max(QuicTime::Delta::FromMicroseconds(1000),
- QuicTime::Delta::FromMicroseconds(2000)));
-}
-
-TEST(QuicTimeDeltaTest, NotEqual) {
- EXPECT_TRUE(QuicTime::Delta::FromSeconds(0) !=
- QuicTime::Delta::FromSeconds(1));
- EXPECT_FALSE(QuicTime::Delta::FromSeconds(0) !=
- QuicTime::Delta::FromSeconds(0));
-}
-
-class QuicTimeTest : public ::testing::Test {
- protected:
- MockClock clock_;
-};
-
-TEST_F(QuicTimeTest, Initialized) {
- EXPECT_FALSE(QuicTime::Zero().IsInitialized());
- EXPECT_TRUE(QuicTime::Zero()
- .Add(QuicTime::Delta::FromMicroseconds(1))
- .IsInitialized());
-}
-
-TEST_F(QuicTimeTest, Add) {
- QuicTime time_1 = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1));
- QuicTime time_2 = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(2));
-
- QuicTime::Delta diff = time_2.Subtract(time_1);
-
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(1), diff);
- EXPECT_EQ(1000, diff.ToMicroseconds());
- EXPECT_EQ(1, diff.ToMilliseconds());
-}
-
-TEST_F(QuicTimeTest, Subtract) {
- QuicTime time_1 = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1));
- QuicTime time_2 = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(2));
-
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(1), time_2.Subtract(time_1));
-}
-
-TEST_F(QuicTimeTest, SubtractDelta) {
- QuicTime time = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(2));
- EXPECT_EQ(QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1)),
- time.Subtract(QuicTime::Delta::FromMilliseconds(1)));
-}
-
-TEST_F(QuicTimeTest, Max) {
- QuicTime time_1 = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1));
- QuicTime time_2 = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(2));
-
- EXPECT_EQ(time_2, QuicTime::Max(time_1, time_2));
-}
-
-TEST_F(QuicTimeTest, MockClock) {
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
-
- QuicTime now = clock_.ApproximateNow();
- QuicTime time = QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(1000));
-
- EXPECT_EQ(now, time);
-
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
- now = clock_.ApproximateNow();
-
- EXPECT_NE(now, time);
-
- time = time.Add(QuicTime::Delta::FromMilliseconds(1));
- EXPECT_EQ(now, time);
-}
-
-TEST_F(QuicTimeTest, LE) {
- const QuicTime zero = QuicTime::Zero();
- const QuicTime one = zero.Add(QuicTime::Delta::FromSeconds(1));
- EXPECT_TRUE(zero <= zero);
- EXPECT_TRUE(zero <= one);
- EXPECT_TRUE(one <= one);
- EXPECT_FALSE(one <= zero);
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_types.cc b/chromium/net/quic/quic_types.cc
deleted file mode 100644
index 3b982f1e502..00000000000
--- a/chromium/net/quic/quic_types.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_types.h"
-
-using std::ostream;
-
-namespace net {
-
-QuicConsumedData::QuicConsumedData(size_t bytes_consumed, bool fin_consumed)
- : bytes_consumed(bytes_consumed), fin_consumed(fin_consumed) {}
-
-ostream& operator<<(ostream& os, const QuicConsumedData& s) {
- os << "bytes_consumed: " << s.bytes_consumed
- << " fin_consumed: " << s.fin_consumed;
- return os;
-}
-
-WriteResult::WriteResult() : status(WRITE_STATUS_ERROR), bytes_written(0) {}
-
-WriteResult::WriteResult(WriteStatus status, int bytes_written_or_error_code)
- : status(status), bytes_written(bytes_written_or_error_code) {}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_unacked_packet_map.cc b/chromium/net/quic/quic_unacked_packet_map.cc
deleted file mode 100644
index d233ad2aa94..00000000000
--- a/chromium/net/quic/quic_unacked_packet_map.cc
+++ /dev/null
@@ -1,360 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_unacked_packet_map.h"
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_connection_stats.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/quic_utils_chromium.h"
-
-using std::max;
-
-namespace net {
-
-QuicUnackedPacketMap::QuicUnackedPacketMap()
- : largest_sent_packet_(0),
- largest_observed_(0),
- least_unacked_(1),
- bytes_in_flight_(0),
- pending_crypto_packet_count_(0) {}
-
-QuicUnackedPacketMap::~QuicUnackedPacketMap() {
- QuicPacketNumber index = least_unacked_;
- for (UnackedPacketMap::iterator it = unacked_packets_.begin();
- it != unacked_packets_.end(); ++it, ++index) {
- QuicUtils::DeleteFrames(&it->retransmittable_frames);
- }
-}
-
-void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet,
- QuicPacketNumber old_packet_number,
- TransmissionType transmission_type,
- QuicTime sent_time,
- bool set_in_flight) {
- QuicPacketNumber packet_number = packet->packet_number;
- QuicPacketLength bytes_sent = packet->encrypted_length;
- QUIC_BUG_IF(largest_sent_packet_ >= packet_number) << packet_number;
- DCHECK_GE(packet_number, least_unacked_ + unacked_packets_.size());
- while (least_unacked_ + unacked_packets_.size() < packet_number) {
- unacked_packets_.push_back(TransmissionInfo());
- unacked_packets_.back().is_unackable = true;
- }
-
- const bool has_crypto_handshake =
- packet->has_crypto_handshake == IS_HANDSHAKE;
- TransmissionInfo info(packet->encryption_level, packet->packet_number_length,
- transmission_type, sent_time, bytes_sent,
- has_crypto_handshake, packet->num_padding_bytes);
- if (old_packet_number > 0) {
- TransferRetransmissionInfo(old_packet_number, packet_number,
- transmission_type, &info);
- }
-
- largest_sent_packet_ = packet_number;
- if (set_in_flight) {
- bytes_in_flight_ += bytes_sent;
- info.in_flight = true;
- }
- unacked_packets_.push_back(info);
- // Swap the ack listeners and retransmittable frames to avoid allocations.
- // TODO(ianswett): Could use emplace_back when Chromium can.
- if (old_packet_number == 0) {
- if (has_crypto_handshake) {
- ++pending_crypto_packet_count_;
- }
-
- packet->retransmittable_frames.swap(
- unacked_packets_.back().retransmittable_frames);
- unacked_packets_.back().ack_listeners.swap(packet->listeners);
- }
-}
-
-void QuicUnackedPacketMap::RemoveObsoletePackets() {
- while (!unacked_packets_.empty()) {
- if (!IsPacketUseless(least_unacked_, unacked_packets_.front())) {
- break;
- }
-
- unacked_packets_.pop_front();
- ++least_unacked_;
- }
-}
-
-void QuicUnackedPacketMap::TransferRetransmissionInfo(
- QuicPacketNumber old_packet_number,
- QuicPacketNumber new_packet_number,
- TransmissionType transmission_type,
- TransmissionInfo* info) {
- if (old_packet_number < least_unacked_) {
- if (!FLAGS_quic_always_write_queued_retransmissions) {
- QUIC_BUG << "Old TransmissionInfo no longer exists for:"
- << old_packet_number << " least_unacked:" << least_unacked_;
- }
- // This can happen when a retransmission packet is queued because of write
- // blocked socket, and the original packet gets acked before the
- // retransmission gets sent.
- return;
- }
- if (old_packet_number > largest_sent_packet_) {
- QUIC_BUG << "Old TransmissionInfo never existed for :" << old_packet_number
- << " largest_sent:" << largest_sent_packet_;
- return;
- }
- DCHECK_GE(new_packet_number, least_unacked_ + unacked_packets_.size());
- DCHECK_NE(NOT_RETRANSMISSION, transmission_type);
-
- TransmissionInfo* transmission_info =
- &unacked_packets_.at(old_packet_number - least_unacked_);
- QuicFrames* frames = &transmission_info->retransmittable_frames;
- for (AckListenerWrapper& wrapper : transmission_info->ack_listeners) {
- wrapper.ack_listener->OnPacketRetransmitted(wrapper.length);
- }
-
- // Swap the frames and preserve num_padding_bytes and has_crypto_handshake.
- frames->swap(info->retransmittable_frames);
- info->has_crypto_handshake = transmission_info->has_crypto_handshake;
- transmission_info->has_crypto_handshake = false;
- info->num_padding_bytes = transmission_info->num_padding_bytes;
-
- // Transfer the AckListeners if any are present.
- info->ack_listeners.swap(transmission_info->ack_listeners);
- QUIC_BUG_IF(frames == nullptr)
- << "Attempt to retransmit packet with no "
- << "retransmittable frames: " << old_packet_number;
-
- // Don't link old transmissions to new ones when version or
- // encryption changes.
- if (transmission_type == ALL_INITIAL_RETRANSMISSION ||
- transmission_type == ALL_UNACKED_RETRANSMISSION) {
- transmission_info->is_unackable = true;
- } else {
- transmission_info->retransmission = new_packet_number;
- }
- // Proactively remove obsolete packets so the least unacked can be raised.
- RemoveObsoletePackets();
-}
-
-bool QuicUnackedPacketMap::HasRetransmittableFrames(
- QuicPacketNumber packet_number) const {
- DCHECK_GE(packet_number, least_unacked_);
- DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size());
- return !unacked_packets_[packet_number - least_unacked_]
- .retransmittable_frames.empty();
-}
-
-void QuicUnackedPacketMap::RemoveRetransmittability(TransmissionInfo* info) {
- while (info->retransmission != 0) {
- const QuicPacketNumber retransmission = info->retransmission;
- info->retransmission = 0;
- info = &unacked_packets_[retransmission - least_unacked_];
- }
- MaybeRemoveRetransmittableFrames(info);
-}
-
-void QuicUnackedPacketMap::RemoveRetransmittability(
- QuicPacketNumber packet_number) {
- DCHECK_GE(packet_number, least_unacked_);
- DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size());
- TransmissionInfo* info = &unacked_packets_[packet_number - least_unacked_];
- RemoveRetransmittability(info);
-}
-
-void QuicUnackedPacketMap::MaybeRemoveRetransmittableFrames(
- TransmissionInfo* transmission_info) {
- if (transmission_info->has_crypto_handshake) {
- DCHECK(!transmission_info->retransmittable_frames.empty());
- DCHECK_LT(0u, pending_crypto_packet_count_);
- --pending_crypto_packet_count_;
- transmission_info->has_crypto_handshake = false;
- }
- QuicUtils::DeleteFrames(&transmission_info->retransmittable_frames);
-}
-
-void QuicUnackedPacketMap::IncreaseLargestObserved(
- QuicPacketNumber largest_observed) {
- DCHECK_LE(largest_observed_, largest_observed);
- largest_observed_ = largest_observed;
-}
-
-bool QuicUnackedPacketMap::IsPacketUsefulForMeasuringRtt(
- QuicPacketNumber packet_number,
- const TransmissionInfo& info) const {
- // Packet can be used for RTT measurement if it may yet be acked as the
- // largest observed packet by the receiver.
- return !info.is_unackable && packet_number > largest_observed_;
-}
-
-bool QuicUnackedPacketMap::IsPacketUsefulForCongestionControl(
- const TransmissionInfo& info) const {
- // Packet contributes to congestion control if it is considered inflight.
- return info.in_flight;
-}
-
-bool QuicUnackedPacketMap::IsPacketUsefulForRetransmittableData(
- const TransmissionInfo& info) const {
- // Packet may have retransmittable frames, or the data may have been
- // retransmitted with a new packet number.
- return !info.retransmittable_frames.empty() ||
- // Allow for an extra 1 RTT before stopping to track old packets.
- info.retransmission > largest_observed_;
-}
-
-bool QuicUnackedPacketMap::IsPacketUseless(QuicPacketNumber packet_number,
- const TransmissionInfo& info) const {
- return !IsPacketUsefulForMeasuringRtt(packet_number, info) &&
- !IsPacketUsefulForCongestionControl(info) &&
- !IsPacketUsefulForRetransmittableData(info);
-}
-
-bool QuicUnackedPacketMap::IsUnacked(QuicPacketNumber packet_number) const {
- if (packet_number < least_unacked_ ||
- packet_number >= least_unacked_ + unacked_packets_.size()) {
- return false;
- }
- return !IsPacketUseless(packet_number,
- unacked_packets_[packet_number - least_unacked_]);
-}
-
-void QuicUnackedPacketMap::NotifyAndClearListeners(
- std::list<AckListenerWrapper>* ack_listeners,
- QuicTime::Delta ack_delay_time) {
- for (const AckListenerWrapper& wrapper : *ack_listeners) {
- wrapper.ack_listener->OnPacketAcked(wrapper.length, ack_delay_time);
- }
- ack_listeners->clear();
-}
-
-void QuicUnackedPacketMap::NotifyAndClearListeners(
- QuicPacketNumber packet_number,
- QuicTime::Delta ack_delay_time) {
- DCHECK_GE(packet_number, least_unacked_);
- DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size());
- TransmissionInfo* info = &unacked_packets_[packet_number - least_unacked_];
- NotifyAndClearListeners(&info->ack_listeners, ack_delay_time);
-}
-
-void QuicUnackedPacketMap::RemoveFromInFlight(TransmissionInfo* info) {
- if (info->in_flight) {
- QUIC_BUG_IF(bytes_in_flight_ < info->bytes_sent);
- bytes_in_flight_ -= info->bytes_sent;
- info->in_flight = false;
- }
-}
-
-void QuicUnackedPacketMap::RemoveFromInFlight(QuicPacketNumber packet_number) {
- DCHECK_GE(packet_number, least_unacked_);
- DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size());
- TransmissionInfo* info = &unacked_packets_[packet_number - least_unacked_];
- RemoveFromInFlight(info);
-}
-
-void QuicUnackedPacketMap::RestoreToInFlight(QuicPacketNumber packet_number) {
- DCHECK_GE(packet_number, least_unacked_);
- DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size());
- TransmissionInfo* info = &unacked_packets_[packet_number - least_unacked_];
- DCHECK(!info->is_unackable);
- bytes_in_flight_ += info->bytes_sent;
- info->in_flight = true;
-}
-
-void QuicUnackedPacketMap::CancelRetransmissionsForStream(
- QuicStreamId stream_id) {
- QuicPacketNumber packet_number = least_unacked_;
- for (UnackedPacketMap::iterator it = unacked_packets_.begin();
- it != unacked_packets_.end(); ++it, ++packet_number) {
- QuicFrames* frames = &it->retransmittable_frames;
- if (frames->empty()) {
- continue;
- }
- QuicUtils::RemoveFramesForStream(frames, stream_id);
- if (frames->empty()) {
- RemoveRetransmittability(packet_number);
- }
- }
-}
-
-bool QuicUnackedPacketMap::HasUnackedPackets() const {
- return !unacked_packets_.empty();
-}
-
-bool QuicUnackedPacketMap::HasInFlightPackets() const {
- return bytes_in_flight_ > 0;
-}
-
-const TransmissionInfo& QuicUnackedPacketMap::GetTransmissionInfo(
- QuicPacketNumber packet_number) const {
- return unacked_packets_[packet_number - least_unacked_];
-}
-
-TransmissionInfo* QuicUnackedPacketMap::GetMutableTransmissionInfo(
- QuicPacketNumber packet_number) {
- return &unacked_packets_[packet_number - least_unacked_];
-}
-
-QuicTime QuicUnackedPacketMap::GetLastPacketSentTime() const {
- UnackedPacketMap::const_reverse_iterator it = unacked_packets_.rbegin();
- while (it != unacked_packets_.rend()) {
- if (it->in_flight) {
- QUIC_BUG_IF(it->sent_time == QuicTime::Zero())
- << "Sent time can never be zero for a packet in flight.";
- return it->sent_time;
- }
- ++it;
- }
- QUIC_BUG << "GetLastPacketSentTime requires in flight packets.";
- return QuicTime::Zero();
-}
-
-size_t QuicUnackedPacketMap::GetNumUnackedPacketsDebugOnly() const {
- size_t unacked_packet_count = 0;
- QuicPacketNumber packet_number = least_unacked_;
- for (UnackedPacketMap::const_iterator it = unacked_packets_.begin();
- it != unacked_packets_.end(); ++it, ++packet_number) {
- if (!IsPacketUseless(packet_number, *it)) {
- ++unacked_packet_count;
- }
- }
- return unacked_packet_count;
-}
-
-bool QuicUnackedPacketMap::HasMultipleInFlightPackets() const {
- if (bytes_in_flight_ > kDefaultTCPMSS) {
- return true;
- }
- size_t num_in_flight = 0;
- for (UnackedPacketMap::const_reverse_iterator it = unacked_packets_.rbegin();
- it != unacked_packets_.rend(); ++it) {
- if (it->in_flight) {
- ++num_in_flight;
- }
- if (num_in_flight > 1) {
- return true;
- }
- }
- return false;
-}
-
-bool QuicUnackedPacketMap::HasPendingCryptoPackets() const {
- return pending_crypto_packet_count_ > 0;
-}
-
-bool QuicUnackedPacketMap::HasUnackedRetransmittableFrames() const {
- for (UnackedPacketMap::const_reverse_iterator it = unacked_packets_.rbegin();
- it != unacked_packets_.rend(); ++it) {
- if (it->in_flight && !it->retransmittable_frames.empty()) {
- return true;
- }
- }
- return false;
-}
-
-QuicPacketNumber QuicUnackedPacketMap::GetLeastUnacked() const {
- return least_unacked_;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_unacked_packet_map.h b/chromium/net/quic/quic_unacked_packet_map.h
deleted file mode 100644
index 4185a32a465..00000000000
--- a/chromium/net/quic/quic_unacked_packet_map.h
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_QUIC_QUIC_UNACKED_PACKET_MAP_H_
-#define NET_QUIC_QUIC_UNACKED_PACKET_MAP_H_
-
-#include <stddef.h>
-
-#include <deque>
-
-#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-class AckNotifierManager;
-
-// Class which tracks unacked packets for three purposes:
-// 1) Track retransmittable data, including multiple transmissions of frames.
-// 2) Track packets and bytes in flight for congestion control.
-// 3) Track sent time of packets to provide RTT measurements from acks.
-class NET_EXPORT_PRIVATE QuicUnackedPacketMap {
- public:
- QuicUnackedPacketMap();
- ~QuicUnackedPacketMap();
-
- // Adds |serialized_packet| to the map and marks it as sent at |sent_time|.
- // Marks the packet as in flight if |set_in_flight| is true.
- // Packets marked as in flight are expected to be marked as missing when they
- // don't arrive, indicating the need for retransmission.
- // |old_packet_number| is the packet number of the previous transmission,
- // or 0 if there was none.
- // Any AckNotifierWrappers in |serialized_packet| are swapped from the
- // serialized packet into the TransmissionInfo.
- void AddSentPacket(SerializedPacket* serialized_packet,
- QuicPacketNumber old_packet_number,
- TransmissionType transmission_type,
- QuicTime sent_time,
- bool set_in_flight);
-
- // Returns true if the packet |packet_number| is unacked.
- bool IsUnacked(QuicPacketNumber packet_number) const;
-
- // Notifies all the AckListeners attached to the |info| and
- // clears them to ensure they're not notified again.
- void NotifyAndClearListeners(std::list<AckListenerWrapper>* ack_listeners,
- QuicTime::Delta delta_largest_observed);
-
- // Notifies all the AckListeners attached to |newest_transmission|.
- void NotifyAndClearListeners(QuicPacketNumber newest_transmission,
- QuicTime::Delta delta_largest_observed);
-
- // Marks |info| as no longer in flight.
- void RemoveFromInFlight(TransmissionInfo* info);
-
- // Marks |packet_number| as no longer in flight.
- void RemoveFromInFlight(QuicPacketNumber packet_number);
-
- // Marks |packet_number| as in flight. Must not be unackable.
- void RestoreToInFlight(QuicPacketNumber packet_number);
-
- // No longer retransmit data for |stream_id|.
- void CancelRetransmissionsForStream(QuicStreamId stream_id);
-
- // Returns true if the unacked packet |packet_number| has retransmittable
- // frames. This will return false if the packet has been acked, if a
- // previous transmission of this packet was ACK'd, or if this packet has been
- // retransmitted as with different packet number, or if the packet never
- // had any retransmittable packets in the first place.
- bool HasRetransmittableFrames(QuicPacketNumber packet_number) const;
-
- // Returns true if there are any unacked packets.
- bool HasUnackedPackets() const;
-
- // Returns true if there are any unacked packets which have retransmittable
- // frames.
- bool HasUnackedRetransmittableFrames() const;
-
- // Returns the largest packet number that has been sent.
- QuicPacketNumber largest_sent_packet() const { return largest_sent_packet_; }
-
- // Returns the largest packet number that has been acked.
- QuicPacketNumber largest_observed() const { return largest_observed_; }
-
- // Returns the sum of bytes from all packets in flight.
- QuicByteCount bytes_in_flight() const { return bytes_in_flight_; }
-
- // Returns the smallest packet number of a serialized packet which has not
- // been acked by the peer. If there are no unacked packets, returns 0.
- QuicPacketNumber GetLeastUnacked() const;
-
- typedef std::deque<TransmissionInfo> UnackedPacketMap;
-
- typedef UnackedPacketMap::const_iterator const_iterator;
- typedef UnackedPacketMap::iterator iterator;
-
- const_iterator begin() const { return unacked_packets_.begin(); }
- const_iterator end() const { return unacked_packets_.end(); }
- iterator begin() { return unacked_packets_.begin(); }
- iterator end() { return unacked_packets_.end(); }
-
- // Returns true if there are unacked packets that are in flight.
- bool HasInFlightPackets() const;
-
- // Returns the TransmissionInfo associated with |packet_number|, which
- // must be unacked.
- const TransmissionInfo& GetTransmissionInfo(
- QuicPacketNumber packet_number) const;
-
- // Returns mutable TransmissionInfo associated with |packet_number|, which
- // must be unacked.
- TransmissionInfo* GetMutableTransmissionInfo(QuicPacketNumber packet_number);
-
- // Returns the time that the last unacked packet was sent.
- QuicTime GetLastPacketSentTime() const;
-
- // Returns the number of unacked packets.
- size_t GetNumUnackedPacketsDebugOnly() const;
-
- // Returns true if there are multiple packets in flight.
- bool HasMultipleInFlightPackets() const;
-
- // Returns true if there are any pending crypto packets.
- bool HasPendingCryptoPackets() const;
-
- // Removes any retransmittable frames from this transmission or an associated
- // transmission. It removes now useless transmissions, and disconnects any
- // other packets from other transmissions.
- void RemoveRetransmittability(TransmissionInfo* info);
-
- // Looks up the TransmissionInfo by |packet_number| and calls
- // RemoveRetransmittability.
- void RemoveRetransmittability(QuicPacketNumber packet_number);
-
- // Increases the largest observed. Any packets less or equal to
- // |largest_acked_packet| are discarded if they are only for the RTT purposes.
- void IncreaseLargestObserved(QuicPacketNumber largest_observed);
-
- // Remove any packets no longer needed for retransmission, congestion, or
- // RTT measurement purposes.
- void RemoveObsoletePackets();
-
- private:
- // Called when a packet is retransmitted with a new packet number.
- // |old_packet_number| will remain unacked, but will have no
- // retransmittable data associated with it. Retransmittable frames will be
- // transferred to |info| and all_transmissions will be populated.
- void TransferRetransmissionInfo(QuicPacketNumber old_packet_number,
- QuicPacketNumber new_packet_number,
- TransmissionType transmission_type,
- TransmissionInfo* info);
-
- void MaybeRemoveRetransmittableFrames(TransmissionInfo* transmission_info);
-
- // Returns true if packet may be useful for an RTT measurement.
- bool IsPacketUsefulForMeasuringRtt(QuicPacketNumber packet_number,
- const TransmissionInfo& info) const;
-
- // Returns true if packet may be useful for congestion control purposes.
- bool IsPacketUsefulForCongestionControl(const TransmissionInfo& info) const;
-
- // Returns true if packet may be associated with retransmittable data
- // directly or through retransmissions.
- bool IsPacketUsefulForRetransmittableData(const TransmissionInfo& info) const;
-
- // Returns true if the packet no longer has a purpose in the map.
- bool IsPacketUseless(QuicPacketNumber packet_number,
- const TransmissionInfo& info) const;
-
- QuicPacketNumber largest_sent_packet_;
- QuicPacketNumber largest_observed_;
-
- // Newly serialized retransmittable packets are added to this map, which
- // contains owning pointers to any contained frames. If a packet is
- // retransmitted, this map will contain entries for both the old and the new
- // packet. The old packet's retransmittable frames entry will be nullptr,
- // while the new packet's entry will contain the frames to retransmit.
- // If the old packet is acked before the new packet, then the old entry will
- // be removed from the map and the new entry's retransmittable frames will be
- // set to nullptr.
- UnackedPacketMap unacked_packets_;
- // The packet at the 0th index of unacked_packets_.
- QuicPacketNumber least_unacked_;
-
- QuicByteCount bytes_in_flight_;
- // Number of retransmittable crypto handshake packets.
- size_t pending_crypto_packet_count_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicUnackedPacketMap);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_UNACKED_PACKET_MAP_H_
diff --git a/chromium/net/quic/quic_unacked_packet_map_test.cc b/chromium/net/quic/quic_unacked_packet_map_test.cc
deleted file mode 100644
index 26a00435374..00000000000
--- a/chromium/net/quic/quic_unacked_packet_map_test.cc
+++ /dev/null
@@ -1,395 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_unacked_packet_map.h"
-
-#include "base/stl_util.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::min;
-using std::vector;
-
-namespace net {
-namespace test {
-namespace {
-
-// Default packet length.
-const uint32_t kDefaultLength = 1000;
-
-class QuicUnackedPacketMapTest : public ::testing::Test {
- protected:
- QuicUnackedPacketMapTest()
- : unacked_packets_(),
- now_(QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1000))) {}
-
- ~QuicUnackedPacketMapTest() override { STLDeleteElements(&packets_); }
-
- SerializedPacket CreateRetransmittablePacket(QuicPacketNumber packet_number) {
- return CreateRetransmittablePacketForStream(packet_number,
- kHeadersStreamId);
- }
-
- SerializedPacket CreateRetransmittablePacketForStream(
- QuicPacketNumber packet_number,
- QuicStreamId stream_id) {
- SerializedPacket packet(kDefaultPathId, packet_number,
- PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
- 0, false, false);
- QuicStreamFrame* frame = new QuicStreamFrame();
- frame->stream_id = stream_id;
- packet.retransmittable_frames.push_back(QuicFrame(frame));
- return packet;
- }
-
- SerializedPacket CreateNonRetransmittablePacket(
- QuicPacketNumber packet_number) {
- return SerializedPacket(kDefaultPathId, packet_number,
- PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
- 0, false, false);
- }
-
- void VerifyInFlightPackets(QuicPacketNumber* packets, size_t num_packets) {
- unacked_packets_.RemoveObsoletePackets();
- if (num_packets == 0) {
- EXPECT_FALSE(unacked_packets_.HasInFlightPackets());
- EXPECT_FALSE(unacked_packets_.HasMultipleInFlightPackets());
- return;
- }
- if (num_packets == 1) {
- EXPECT_TRUE(unacked_packets_.HasInFlightPackets());
- EXPECT_FALSE(unacked_packets_.HasMultipleInFlightPackets());
- ASSERT_TRUE(unacked_packets_.IsUnacked(packets[0]));
- EXPECT_TRUE(unacked_packets_.GetTransmissionInfo(packets[0]).in_flight);
- }
- for (size_t i = 0; i < num_packets; ++i) {
- ASSERT_TRUE(unacked_packets_.IsUnacked(packets[i]));
- EXPECT_TRUE(unacked_packets_.GetTransmissionInfo(packets[i]).in_flight);
- }
- size_t in_flight_count = 0;
- for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
- it != unacked_packets_.end(); ++it) {
- if (it->in_flight) {
- ++in_flight_count;
- }
- }
- EXPECT_EQ(num_packets, in_flight_count);
- }
-
- void VerifyUnackedPackets(QuicPacketNumber* packets, size_t num_packets) {
- unacked_packets_.RemoveObsoletePackets();
- if (num_packets == 0) {
- EXPECT_FALSE(unacked_packets_.HasUnackedPackets());
- EXPECT_FALSE(unacked_packets_.HasUnackedRetransmittableFrames());
- return;
- }
- EXPECT_TRUE(unacked_packets_.HasUnackedPackets());
- for (size_t i = 0; i < num_packets; ++i) {
- EXPECT_TRUE(unacked_packets_.IsUnacked(packets[i])) << packets[i];
- }
- EXPECT_EQ(num_packets, unacked_packets_.GetNumUnackedPacketsDebugOnly());
- }
-
- void VerifyRetransmittablePackets(QuicPacketNumber* packets,
- size_t num_packets) {
- unacked_packets_.RemoveObsoletePackets();
- size_t num_retransmittable_packets = 0;
- for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
- it != unacked_packets_.end(); ++it) {
- if (!it->retransmittable_frames.empty()) {
- ++num_retransmittable_packets;
- }
- }
- EXPECT_EQ(num_packets, num_retransmittable_packets);
- for (size_t i = 0; i < num_packets; ++i) {
- EXPECT_TRUE(unacked_packets_.HasRetransmittableFrames(packets[i]))
- << " packets[" << i << "]:" << packets[i];
- }
- }
- vector<QuicEncryptedPacket*> packets_;
- QuicUnackedPacketMap unacked_packets_;
- QuicTime now_;
-};
-
-TEST_F(QuicUnackedPacketMapTest, RttOnly) {
- // Acks are only tracked for RTT measurement purposes.
- SerializedPacket packet(CreateNonRetransmittablePacket(1));
- unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, false);
-
- QuicPacketNumber unacked[] = {1};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyInFlightPackets(nullptr, 0);
- VerifyRetransmittablePackets(nullptr, 0);
-
- unacked_packets_.IncreaseLargestObserved(1);
- VerifyUnackedPackets(nullptr, 0);
- VerifyInFlightPackets(nullptr, 0);
- VerifyRetransmittablePackets(nullptr, 0);
-}
-
-TEST_F(QuicUnackedPacketMapTest, RetransmittableInflightAndRtt) {
- // Simulate a retransmittable packet being sent and acked.
- SerializedPacket packet(CreateRetransmittablePacket(1));
- unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, true);
-
- QuicPacketNumber unacked[] = {1};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyInFlightPackets(unacked, arraysize(unacked));
- VerifyRetransmittablePackets(unacked, arraysize(unacked));
-
- unacked_packets_.RemoveRetransmittability(1);
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyInFlightPackets(unacked, arraysize(unacked));
- VerifyRetransmittablePackets(nullptr, 0);
-
- unacked_packets_.IncreaseLargestObserved(1);
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyInFlightPackets(unacked, arraysize(unacked));
- VerifyRetransmittablePackets(nullptr, 0);
-
- unacked_packets_.RemoveFromInFlight(1);
- VerifyUnackedPackets(nullptr, 0);
- VerifyInFlightPackets(nullptr, 0);
- VerifyRetransmittablePackets(nullptr, 0);
-}
-
-TEST_F(QuicUnackedPacketMapTest, StopRetransmission) {
- const QuicStreamId stream_id = 2;
- SerializedPacket packet(CreateRetransmittablePacketForStream(1, stream_id));
- unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, true);
-
- QuicPacketNumber unacked[] = {1};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyInFlightPackets(unacked, arraysize(unacked));
- QuicPacketNumber retransmittable[] = {1};
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
-
- unacked_packets_.CancelRetransmissionsForStream(stream_id);
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyInFlightPackets(unacked, arraysize(unacked));
- VerifyRetransmittablePackets(nullptr, 0);
-}
-
-TEST_F(QuicUnackedPacketMapTest, StopRetransmissionOnOtherStream) {
- const QuicStreamId stream_id = 2;
- SerializedPacket packet(CreateRetransmittablePacketForStream(1, stream_id));
- unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, now_, true);
-
- QuicPacketNumber unacked[] = {1};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyInFlightPackets(unacked, arraysize(unacked));
- QuicPacketNumber retransmittable[] = {1};
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
-
- // Stop retransmissions on another stream and verify the packet is unchanged.
- unacked_packets_.CancelRetransmissionsForStream(stream_id + 2);
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyInFlightPackets(unacked, arraysize(unacked));
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
-}
-
-TEST_F(QuicUnackedPacketMapTest, StopRetransmissionAfterRetransmission) {
- const QuicStreamId stream_id = 2;
- SerializedPacket packet1(CreateRetransmittablePacketForStream(1, stream_id));
- unacked_packets_.AddSentPacket(&packet1, 0, NOT_RETRANSMISSION, now_, true);
- SerializedPacket packet2(CreateNonRetransmittablePacket(2));
- unacked_packets_.AddSentPacket(&packet2, 1, LOSS_RETRANSMISSION, now_, true);
-
- QuicPacketNumber unacked[] = {1, 2};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyInFlightPackets(unacked, arraysize(unacked));
- QuicPacketNumber retransmittable[] = {2};
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
-
- unacked_packets_.CancelRetransmissionsForStream(stream_id);
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyInFlightPackets(unacked, arraysize(unacked));
- VerifyRetransmittablePackets(nullptr, 0);
-}
-
-TEST_F(QuicUnackedPacketMapTest, RetransmittedPacket) {
- // Simulate a retransmittable packet being sent, retransmitted, and the first
- // transmission being acked.
- SerializedPacket packet1(CreateRetransmittablePacket(1));
- unacked_packets_.AddSentPacket(&packet1, 0, NOT_RETRANSMISSION, now_, true);
- SerializedPacket packet2(CreateNonRetransmittablePacket(2));
- unacked_packets_.AddSentPacket(&packet2, 1, LOSS_RETRANSMISSION, now_, true);
-
- QuicPacketNumber unacked[] = {1, 2};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyInFlightPackets(unacked, arraysize(unacked));
- QuicPacketNumber retransmittable[] = {2};
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
-
- unacked_packets_.RemoveRetransmittability(1);
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyInFlightPackets(unacked, arraysize(unacked));
- VerifyRetransmittablePackets(nullptr, 0);
-
- unacked_packets_.IncreaseLargestObserved(2);
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyInFlightPackets(unacked, arraysize(unacked));
- VerifyRetransmittablePackets(nullptr, 0);
-
- unacked_packets_.RemoveFromInFlight(2);
- QuicPacketNumber unacked2[] = {1};
- VerifyUnackedPackets(unacked2, arraysize(unacked2));
- VerifyInFlightPackets(unacked2, arraysize(unacked2));
- VerifyRetransmittablePackets(nullptr, 0);
-
- unacked_packets_.RemoveFromInFlight(1);
- VerifyUnackedPackets(nullptr, 0);
- VerifyInFlightPackets(nullptr, 0);
- VerifyRetransmittablePackets(nullptr, 0);
-}
-
-TEST_F(QuicUnackedPacketMapTest, RetransmitThreeTimes) {
- // Simulate a retransmittable packet being sent and retransmitted twice.
- SerializedPacket packet1(CreateRetransmittablePacket(1));
- unacked_packets_.AddSentPacket(&packet1, 0, NOT_RETRANSMISSION, now_, true);
- SerializedPacket packet2(CreateRetransmittablePacket(2));
- unacked_packets_.AddSentPacket(&packet2, 0, NOT_RETRANSMISSION, now_, true);
-
- QuicPacketNumber unacked[] = {1, 2};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyInFlightPackets(unacked, arraysize(unacked));
- QuicPacketNumber retransmittable[] = {1, 2};
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
-
- // Early retransmit 1 as 3 and send new data as 4.
- unacked_packets_.IncreaseLargestObserved(2);
- unacked_packets_.RemoveFromInFlight(2);
- unacked_packets_.RemoveRetransmittability(2);
- unacked_packets_.RemoveFromInFlight(1);
- SerializedPacket packet3(CreateNonRetransmittablePacket(3));
- unacked_packets_.AddSentPacket(&packet3, 1, LOSS_RETRANSMISSION, now_, true);
- SerializedPacket packet4(CreateRetransmittablePacket(4));
- unacked_packets_.AddSentPacket(&packet4, 0, NOT_RETRANSMISSION, now_, true);
-
- QuicPacketNumber unacked2[] = {1, 3, 4};
- VerifyUnackedPackets(unacked2, arraysize(unacked2));
- QuicPacketNumber pending2[] = {3, 4};
- VerifyInFlightPackets(pending2, arraysize(pending2));
- QuicPacketNumber retransmittable2[] = {3, 4};
- VerifyRetransmittablePackets(retransmittable2, arraysize(retransmittable2));
-
- // Early retransmit 3 (formerly 1) as 5, and remove 1 from unacked.
- unacked_packets_.IncreaseLargestObserved(4);
- unacked_packets_.RemoveFromInFlight(4);
- unacked_packets_.RemoveRetransmittability(4);
- SerializedPacket packet5(CreateNonRetransmittablePacket(5));
- unacked_packets_.AddSentPacket(&packet5, 3, LOSS_RETRANSMISSION, now_, true);
- SerializedPacket packet6(CreateRetransmittablePacket(6));
- unacked_packets_.AddSentPacket(&packet6, 0, NOT_RETRANSMISSION, now_, true);
-
- QuicPacketNumber unacked3[] = {3, 5, 6};
- VerifyUnackedPackets(unacked3, arraysize(unacked3));
- QuicPacketNumber pending3[] = {3, 5, 6};
- VerifyInFlightPackets(pending3, arraysize(pending3));
- QuicPacketNumber retransmittable3[] = {5, 6};
- VerifyRetransmittablePackets(retransmittable3, arraysize(retransmittable3));
-
- // Early retransmit 5 as 7 and ensure in flight packet 3 is not removed.
- unacked_packets_.IncreaseLargestObserved(6);
- unacked_packets_.RemoveFromInFlight(6);
- unacked_packets_.RemoveRetransmittability(6);
- SerializedPacket packet7(CreateNonRetransmittablePacket(7));
- unacked_packets_.AddSentPacket(&packet7, 5, LOSS_RETRANSMISSION, now_, true);
-
- QuicPacketNumber unacked4[] = {3, 5, 7};
- VerifyUnackedPackets(unacked4, arraysize(unacked4));
- QuicPacketNumber pending4[] = {3, 5, 7};
- VerifyInFlightPackets(pending4, arraysize(pending4));
- QuicPacketNumber retransmittable4[] = {7};
- VerifyRetransmittablePackets(retransmittable4, 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));
-}
-
-TEST_F(QuicUnackedPacketMapTest, RetransmitFourTimes) {
- // Simulate a retransmittable packet being sent and retransmitted twice.
- SerializedPacket packet1(CreateRetransmittablePacket(1));
- unacked_packets_.AddSentPacket(&packet1, 0, NOT_RETRANSMISSION, now_, true);
- SerializedPacket packet2(CreateRetransmittablePacket(2));
- unacked_packets_.AddSentPacket(&packet2, 0, NOT_RETRANSMISSION, now_, true);
-
- QuicPacketNumber unacked[] = {1, 2};
- VerifyUnackedPackets(unacked, arraysize(unacked));
- VerifyInFlightPackets(unacked, arraysize(unacked));
- QuicPacketNumber retransmittable[] = {1, 2};
- VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable));
-
- // Early retransmit 1 as 3.
- unacked_packets_.IncreaseLargestObserved(2);
- unacked_packets_.RemoveFromInFlight(2);
- unacked_packets_.RemoveRetransmittability(2);
- unacked_packets_.RemoveFromInFlight(1);
- SerializedPacket packet3(CreateNonRetransmittablePacket(3));
- unacked_packets_.AddSentPacket(&packet3, 1, LOSS_RETRANSMISSION, now_, true);
-
- QuicPacketNumber unacked2[] = {1, 3};
- VerifyUnackedPackets(unacked2, arraysize(unacked2));
- QuicPacketNumber pending2[] = {3};
- VerifyInFlightPackets(pending2, arraysize(pending2));
- QuicPacketNumber retransmittable2[] = {3};
- VerifyRetransmittablePackets(retransmittable2, arraysize(retransmittable2));
-
- // TLP 3 (formerly 1) as 4, and don't remove 1 from unacked.
- SerializedPacket packet4(CreateNonRetransmittablePacket(4));
- unacked_packets_.AddSentPacket(&packet4, 3, TLP_RETRANSMISSION, now_, true);
- SerializedPacket packet5(CreateRetransmittablePacket(5));
- unacked_packets_.AddSentPacket(&packet5, 0, NOT_RETRANSMISSION, now_, true);
-
- QuicPacketNumber unacked3[] = {1, 3, 4, 5};
- VerifyUnackedPackets(unacked3, arraysize(unacked3));
- QuicPacketNumber pending3[] = {3, 4, 5};
- VerifyInFlightPackets(pending3, arraysize(pending3));
- QuicPacketNumber retransmittable3[] = {4, 5};
- VerifyRetransmittablePackets(retransmittable3, arraysize(retransmittable3));
-
- // Early retransmit 4 as 6 and ensure in flight packet 3 is removed.
- unacked_packets_.IncreaseLargestObserved(5);
- unacked_packets_.RemoveFromInFlight(5);
- unacked_packets_.RemoveRetransmittability(5);
- unacked_packets_.RemoveFromInFlight(3);
- unacked_packets_.RemoveFromInFlight(4);
- SerializedPacket packet6(CreateNonRetransmittablePacket(6));
- unacked_packets_.AddSentPacket(&packet6, 4, LOSS_RETRANSMISSION, now_, true);
-
- QuicPacketNumber unacked4[] = {4, 6};
- VerifyUnackedPackets(unacked4, arraysize(unacked4));
- QuicPacketNumber pending4[] = {6};
- VerifyInFlightPackets(pending4, arraysize(pending4));
- QuicPacketNumber retransmittable4[] = {6};
- VerifyRetransmittablePackets(retransmittable4, arraysize(retransmittable4));
-}
-
-TEST_F(QuicUnackedPacketMapTest, SendWithGap) {
- // Simulate a retransmittable packet being sent, retransmitted, and the first
- // transmission being acked.
- SerializedPacket packet1(CreateRetransmittablePacket(1));
- unacked_packets_.AddSentPacket(&packet1, 0, NOT_RETRANSMISSION, now_, true);
- SerializedPacket packet3(CreateRetransmittablePacket(3));
- unacked_packets_.AddSentPacket(&packet3, 0, NOT_RETRANSMISSION, now_, true);
- SerializedPacket packet5(CreateNonRetransmittablePacket(5));
- unacked_packets_.AddSentPacket(&packet5, 3, LOSS_RETRANSMISSION, now_, true);
-
- EXPECT_EQ(1u, unacked_packets_.GetLeastUnacked());
- EXPECT_TRUE(unacked_packets_.IsUnacked(1));
- EXPECT_FALSE(unacked_packets_.IsUnacked(2));
- EXPECT_TRUE(unacked_packets_.IsUnacked(3));
- EXPECT_FALSE(unacked_packets_.IsUnacked(4));
- EXPECT_TRUE(unacked_packets_.IsUnacked(5));
- EXPECT_EQ(5u, unacked_packets_.largest_sent_packet());
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_utils.cc b/chromium/net/quic/quic_utils.cc
deleted file mode 100644
index 1af16db853c..00000000000
--- a/chromium/net/quic/quic_utils.cc
+++ /dev/null
@@ -1,586 +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/quic_utils.h"
-
-#include <ctype.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <vector>
-
-#include "base/containers/adapters.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/stringprintf.h"
-#include "net/base/ip_address.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_write_blocked_list.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-namespace {
-
-// We know that >= GCC 4.8 and Clang have a __uint128_t intrinsic. Other
-// compilers don't necessarily, notably MSVC.
-#if defined(__x86_64__) && \
- ((defined(__GNUC__) && \
- (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || \
- defined(__clang__))
-#define QUIC_UTIL_HAS_UINT128 1
-#endif
-
-#ifdef QUIC_UTIL_HAS_UINT128
-uint128 IncrementalHashFast(uint128 uhash, const char* data, size_t len) {
- // This code ends up faster than the naive implementation for 2 reasons:
- // 1. uint128 from base/int128.h is sufficiently complicated that the compiler
- // cannot transform the multiplication by kPrime into a shift-multiply-add;
- // it has go through all of the instructions for a 128-bit multiply.
- // 2. Because there are so fewer instructions (around 13), the hot loop fits
- // nicely in the instruction queue of many Intel CPUs.
- // kPrime = 309485009821345068724781371
- static const __uint128_t kPrime =
- (static_cast<__uint128_t>(16777216) << 64) + 315;
- __uint128_t xhash = (static_cast<__uint128_t>(Uint128High64(uhash)) << 64) +
- Uint128Low64(uhash);
- const uint8_t* octets = reinterpret_cast<const uint8_t*>(data);
- for (size_t i = 0; i < len; ++i) {
- xhash = (xhash ^ octets[i]) * kPrime;
- }
- return uint128(static_cast<uint64_t>(xhash >> 64),
- static_cast<uint64_t>(xhash & UINT64_C(0xFFFFFFFFFFFFFFFF)));
-}
-#endif
-
-#ifndef QUIC_UTIL_HAS_UINT128
-// Slow implementation of IncrementalHash. In practice, only used by Chromium.
-uint128 IncrementalHashSlow(uint128 hash, const char* data, size_t len) {
- // kPrime = 309485009821345068724781371
- static const uint128 kPrime(16777216, 315);
- const uint8_t* octets = reinterpret_cast<const uint8_t*>(data);
- for (size_t i = 0; i < len; ++i) {
- hash = hash ^ uint128(0, octets[i]);
- hash = hash * kPrime;
- }
- return hash;
-}
-#endif
-
-uint128 IncrementalHash(uint128 hash, const char* data, size_t len) {
-#ifdef QUIC_UTIL_HAS_UINT128
- return IncrementalHashFast(hash, data, len);
-#else
- return IncrementalHashSlow(hash, data, len);
-#endif
-}
-
-bool IsInitializedIPEndPoint(const IPEndPoint& address) {
- return address.address().IsValid();
-}
-
-} // namespace
-
-// static
-uint64_t QuicUtils::FNV1a_64_Hash(const char* data, int len) {
- static const uint64_t kOffset = UINT64_C(14695981039346656037);
- static const uint64_t kPrime = UINT64_C(1099511628211);
-
- const uint8_t* octets = reinterpret_cast<const uint8_t*>(data);
-
- uint64_t hash = kOffset;
-
- for (int i = 0; i < len; ++i) {
- hash = hash ^ octets[i];
- hash = hash * kPrime;
- }
-
- return hash;
-}
-
-// static
-uint128 QuicUtils::FNV1a_128_Hash(const char* data, int len) {
- return FNV1a_128_Hash_Two(data, len, nullptr, 0);
-}
-
-// static
-uint128 QuicUtils::FNV1a_128_Hash_Two(const char* data1,
- int len1,
- const char* data2,
- int len2) {
- // The two constants are defined as part of the hash algorithm.
- // see http://www.isthe.com/chongo/tech/comp/fnv/
- // kOffset = 144066263297769815596495629667062367629
- const uint128 kOffset(UINT64_C(7809847782465536322),
- UINT64_C(7113472399480571277));
-
- uint128 hash = IncrementalHash(kOffset, data1, len1);
- if (data2 == nullptr) {
- return hash;
- }
- return IncrementalHash(hash, data2, len2);
-}
-
-// static
-bool QuicUtils::FindMutualTag(const QuicTagVector& our_tags_vector,
- const QuicTag* their_tags,
- size_t num_their_tags,
- Priority priority,
- QuicTag* out_result,
- size_t* out_index) {
- if (our_tags_vector.empty()) {
- return false;
- }
- const size_t num_our_tags = our_tags_vector.size();
- const QuicTag* our_tags = &our_tags_vector[0];
-
- size_t num_priority_tags, num_inferior_tags;
- const QuicTag* priority_tags;
- const QuicTag* inferior_tags;
- if (priority == LOCAL_PRIORITY) {
- num_priority_tags = num_our_tags;
- priority_tags = our_tags;
- num_inferior_tags = num_their_tags;
- inferior_tags = their_tags;
- } else {
- num_priority_tags = num_their_tags;
- priority_tags = their_tags;
- num_inferior_tags = num_our_tags;
- inferior_tags = our_tags;
- }
-
- for (size_t i = 0; i < num_priority_tags; i++) {
- for (size_t j = 0; j < num_inferior_tags; j++) {
- if (priority_tags[i] == inferior_tags[j]) {
- *out_result = priority_tags[i];
- if (out_index) {
- if (priority == LOCAL_PRIORITY) {
- *out_index = j;
- } else {
- *out_index = i;
- }
- }
- return true;
- }
- }
- }
-
- return false;
-}
-
-// static
-void QuicUtils::SerializeUint128Short(uint128 v, uint8_t* out) {
- const uint64_t lo = Uint128Low64(v);
- const uint64_t hi = Uint128High64(v);
- // This assumes that the system is little-endian.
- memcpy(out, &lo, sizeof(lo));
- memcpy(out + sizeof(lo), &hi, sizeof(hi) / 2);
-}
-
-#define RETURN_STRING_LITERAL(x) \
- case x: \
- return #x;
-
-// static
-const char* QuicUtils::StreamErrorToString(QuicRstStreamErrorCode error) {
- switch (error) {
- RETURN_STRING_LITERAL(QUIC_STREAM_NO_ERROR);
- RETURN_STRING_LITERAL(QUIC_STREAM_CONNECTION_ERROR);
- RETURN_STRING_LITERAL(QUIC_ERROR_PROCESSING_STREAM);
- RETURN_STRING_LITERAL(QUIC_MULTIPLE_TERMINATION_OFFSETS);
- RETURN_STRING_LITERAL(QUIC_BAD_APPLICATION_PAYLOAD);
- RETURN_STRING_LITERAL(QUIC_STREAM_PEER_GOING_AWAY);
- RETURN_STRING_LITERAL(QUIC_STREAM_CANCELLED);
- RETURN_STRING_LITERAL(QUIC_RST_ACKNOWLEDGEMENT);
- RETURN_STRING_LITERAL(QUIC_REFUSED_STREAM);
- RETURN_STRING_LITERAL(QUIC_STREAM_LAST_ERROR);
- RETURN_STRING_LITERAL(QUIC_INVALID_PROMISE_URL);
- RETURN_STRING_LITERAL(QUIC_UNAUTHORIZED_PROMISE_URL);
- RETURN_STRING_LITERAL(QUIC_DUPLICATE_PROMISE_URL);
- RETURN_STRING_LITERAL(QUIC_PROMISE_VARY_MISMATCH);
- RETURN_STRING_LITERAL(QUIC_INVALID_PROMISE_METHOD);
- }
- // Return a default value so that we return this when |error| doesn't match
- // any of the QuicRstStreamErrorCodes. This can happen when the RstStream
- // frame sent by the peer (attacker) has invalid error code.
- return "INVALID_RST_STREAM_ERROR_CODE";
-}
-
-// static
-const char* QuicUtils::ErrorToString(QuicErrorCode error) {
- switch (error) {
- RETURN_STRING_LITERAL(QUIC_NO_ERROR);
- RETURN_STRING_LITERAL(QUIC_INTERNAL_ERROR);
- RETURN_STRING_LITERAL(QUIC_STREAM_DATA_AFTER_TERMINATION);
- RETURN_STRING_LITERAL(QUIC_INVALID_PACKET_HEADER);
- RETURN_STRING_LITERAL(QUIC_INVALID_FRAME_DATA);
- RETURN_STRING_LITERAL(QUIC_MISSING_PAYLOAD);
- RETURN_STRING_LITERAL(QUIC_INVALID_FEC_DATA);
- RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_DATA);
- RETURN_STRING_LITERAL(QUIC_OVERLAPPING_STREAM_DATA);
- RETURN_STRING_LITERAL(QUIC_UNENCRYPTED_STREAM_DATA);
- RETURN_STRING_LITERAL(QUIC_INVALID_RST_STREAM_DATA);
- RETURN_STRING_LITERAL(QUIC_INVALID_CONNECTION_CLOSE_DATA);
- RETURN_STRING_LITERAL(QUIC_INVALID_GOAWAY_DATA);
- RETURN_STRING_LITERAL(QUIC_INVALID_WINDOW_UPDATE_DATA);
- RETURN_STRING_LITERAL(QUIC_INVALID_BLOCKED_DATA);
- RETURN_STRING_LITERAL(QUIC_INVALID_STOP_WAITING_DATA);
- RETURN_STRING_LITERAL(QUIC_INVALID_PATH_CLOSE_DATA);
- RETURN_STRING_LITERAL(QUIC_INVALID_ACK_DATA);
- RETURN_STRING_LITERAL(QUIC_INVALID_VERSION_NEGOTIATION_PACKET);
- RETURN_STRING_LITERAL(QUIC_INVALID_PUBLIC_RST_PACKET);
- RETURN_STRING_LITERAL(QUIC_DECRYPTION_FAILURE);
- RETURN_STRING_LITERAL(QUIC_ENCRYPTION_FAILURE);
- RETURN_STRING_LITERAL(QUIC_PACKET_TOO_LARGE);
- RETURN_STRING_LITERAL(QUIC_PEER_GOING_AWAY);
- RETURN_STRING_LITERAL(QUIC_HANDSHAKE_FAILED);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_TAGS_OUT_OF_ORDER);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_TOO_MANY_ENTRIES);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_TOO_MANY_REJECTS);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_INVALID_VALUE_LENGTH)
- RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_INTERNAL_ERROR);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_VERSION_NOT_SUPPORTED);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_NO_SUPPORT);
- RETURN_STRING_LITERAL(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
- RETURN_STRING_LITERAL(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND);
- RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_ID);
- RETURN_STRING_LITERAL(QUIC_INVALID_PRIORITY);
- RETURN_STRING_LITERAL(QUIC_TOO_MANY_OPEN_STREAMS);
- RETURN_STRING_LITERAL(QUIC_PUBLIC_RESET);
- RETURN_STRING_LITERAL(QUIC_INVALID_VERSION);
- RETURN_STRING_LITERAL(QUIC_INVALID_HEADER_ID);
- RETURN_STRING_LITERAL(QUIC_INVALID_NEGOTIATED_VALUE);
- RETURN_STRING_LITERAL(QUIC_DECOMPRESSION_FAILURE);
- RETURN_STRING_LITERAL(QUIC_NETWORK_IDLE_TIMEOUT);
- RETURN_STRING_LITERAL(QUIC_HANDSHAKE_TIMEOUT);
- RETURN_STRING_LITERAL(QUIC_ERROR_MIGRATING_ADDRESS);
- RETURN_STRING_LITERAL(QUIC_ERROR_MIGRATING_PORT);
- RETURN_STRING_LITERAL(QUIC_PACKET_WRITE_ERROR);
- RETURN_STRING_LITERAL(QUIC_PACKET_READ_ERROR);
- RETURN_STRING_LITERAL(QUIC_EMPTY_STREAM_FRAME_NO_FIN);
- RETURN_STRING_LITERAL(QUIC_INVALID_HEADERS_STREAM_DATA);
- RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA);
- RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA);
- RETURN_STRING_LITERAL(QUIC_FLOW_CONTROL_INVALID_WINDOW);
- RETURN_STRING_LITERAL(QUIC_CONNECTION_IP_POOLED);
- RETURN_STRING_LITERAL(QUIC_PROOF_INVALID);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_DUPLICATE_TAG);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_SERVER_CONFIG_EXPIRED);
- RETURN_STRING_LITERAL(QUIC_INVALID_CHANNEL_ID_SIGNATURE);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE);
- RETURN_STRING_LITERAL(QUIC_VERSION_NEGOTIATION_MISMATCH);
- RETURN_STRING_LITERAL(QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS);
- RETURN_STRING_LITERAL(QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS);
- RETURN_STRING_LITERAL(QUIC_CONNECTION_CANCELLED);
- RETURN_STRING_LITERAL(QUIC_BAD_PACKET_LOSS_RATE);
- RETURN_STRING_LITERAL(QUIC_PUBLIC_RESETS_POST_HANDSHAKE);
- RETURN_STRING_LITERAL(QUIC_TIMEOUTS_WITH_OPEN_STREAMS);
- RETURN_STRING_LITERAL(QUIC_FAILED_TO_SERIALIZE_PACKET);
- RETURN_STRING_LITERAL(QUIC_TOO_MANY_AVAILABLE_STREAMS);
- RETURN_STRING_LITERAL(QUIC_UNENCRYPTED_FEC_DATA);
- RETURN_STRING_LITERAL(QUIC_BAD_MULTIPATH_FLAG);
- RETURN_STRING_LITERAL(QUIC_IP_ADDRESS_CHANGED);
- RETURN_STRING_LITERAL(QUIC_CONNECTION_MIGRATION_NO_MIGRATABLE_STREAMS);
- RETURN_STRING_LITERAL(QUIC_CONNECTION_MIGRATION_TOO_MANY_CHANGES);
- RETURN_STRING_LITERAL(QUIC_CONNECTION_MIGRATION_NO_NEW_NETWORK);
- RETURN_STRING_LITERAL(QUIC_CONNECTION_MIGRATION_NON_MIGRATABLE_STREAM);
- RETURN_STRING_LITERAL(QUIC_TOO_MANY_RTOS);
- RETURN_STRING_LITERAL(QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA);
- RETURN_STRING_LITERAL(QUIC_MAYBE_CORRUPTED_MEMORY);
- RETURN_STRING_LITERAL(QUIC_CRYPTO_CHLO_TOO_LARGE);
- 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.
- }
- // Return a default value so that we return this when |error| doesn't match
- // any of the QuicErrorCodes. This can happen when the ConnectionClose
- // frame sent by the peer (attacker) has invalid error code.
- return "INVALID_ERROR_CODE";
-}
-
-// static
-const char* QuicUtils::EncryptionLevelToString(EncryptionLevel level) {
- switch (level) {
- RETURN_STRING_LITERAL(ENCRYPTION_NONE);
- RETURN_STRING_LITERAL(ENCRYPTION_INITIAL);
- RETURN_STRING_LITERAL(ENCRYPTION_FORWARD_SECURE);
- RETURN_STRING_LITERAL(NUM_ENCRYPTION_LEVELS);
- }
- return "INVALID_ENCRYPTION_LEVEL";
-}
-
-// static
-const char* QuicUtils::TransmissionTypeToString(TransmissionType type) {
- switch (type) {
- RETURN_STRING_LITERAL(NOT_RETRANSMISSION);
- RETURN_STRING_LITERAL(HANDSHAKE_RETRANSMISSION);
- RETURN_STRING_LITERAL(LOSS_RETRANSMISSION);
- RETURN_STRING_LITERAL(ALL_UNACKED_RETRANSMISSION);
- RETURN_STRING_LITERAL(ALL_INITIAL_RETRANSMISSION);
- RETURN_STRING_LITERAL(RTO_RETRANSMISSION);
- RETURN_STRING_LITERAL(TLP_RETRANSMISSION);
- }
- return "INVALID_TRANSMISSION_TYPE";
-}
-
-// static
-string QuicUtils::TagToString(QuicTag tag) {
- char chars[sizeof tag];
- bool ascii = true;
- const QuicTag orig_tag = tag;
-
- for (size_t i = 0; i < arraysize(chars); i++) {
- chars[i] = static_cast<char>(tag);
- if ((chars[i] == 0 || chars[i] == '\xff') && i == arraysize(chars) - 1) {
- chars[i] = ' ';
- }
- if (!isprint(static_cast<unsigned char>(chars[i]))) {
- ascii = false;
- break;
- }
- tag >>= 8;
- }
-
- if (ascii) {
- return string(chars, sizeof(chars));
- }
-
- return base::UintToString(orig_tag);
-}
-
-// static
-QuicTagVector QuicUtils::ParseQuicConnectionOptions(
- const std::string& connection_options) {
- QuicTagVector options;
- // Tokens are expected to be no more than 4 characters long, but we
- // handle overflow gracefully.
- for (const base::StringPiece& token :
- base::SplitStringPiece(connection_options, ",", base::TRIM_WHITESPACE,
- base::SPLIT_WANT_ALL)) {
- uint32_t option = 0;
- for (char token_char : base::Reversed(token)) {
- option <<= 8;
- option |= static_cast<unsigned char>(token_char);
- }
- options.push_back(option);
- }
- return options;
-}
-
-// static
-string QuicUtils::StringToHexASCIIDump(StringPiece in_buffer) {
- int offset = 0;
- const int kBytesPerLine = 16; // Max bytes dumped per line
- const char* buf = in_buffer.data();
- int bytes_remaining = in_buffer.size();
- string s; // our output
- const char* p = buf;
- while (bytes_remaining > 0) {
- const int line_bytes = std::min(bytes_remaining, kBytesPerLine);
- base::StringAppendF(&s, "0x%04x: ", offset); // Do the line header
- for (int i = 0; i < kBytesPerLine; ++i) {
- if (i < line_bytes) {
- base::StringAppendF(&s, "%02x", static_cast<unsigned char>(p[i]));
- } else {
- s += " "; // two-space filler instead of two-space hex digits
- }
- if (i % 2)
- s += ' ';
- }
- s += ' ';
- for (int i = 0; i < line_bytes; ++i) { // Do the ASCII dump
- s += (p[i] > 32 && p[i] < 127) ? p[i] : '.';
- }
-
- bytes_remaining -= line_bytes;
- offset += line_bytes;
- p += line_bytes;
- s += '\n';
- }
- return s;
-}
-
-string QuicUtils::PeerAddressChangeTypeToString(PeerAddressChangeType type) {
- switch (type) {
- RETURN_STRING_LITERAL(NO_CHANGE);
- RETURN_STRING_LITERAL(PORT_CHANGE);
- RETURN_STRING_LITERAL(IPV4_SUBNET_CHANGE);
- RETURN_STRING_LITERAL(IPV4_TO_IPV6_CHANGE);
- RETURN_STRING_LITERAL(IPV6_TO_IPV4_CHANGE);
- RETURN_STRING_LITERAL(IPV6_TO_IPV6_CHANGE);
- RETURN_STRING_LITERAL(UNSPECIFIED_CHANGE);
- }
- return "INVALID_PEER_ADDRESS_CHANGE_TYPE";
-}
-
-// static
-void QuicUtils::DeleteFrames(QuicFrames* frames) {
- for (QuicFrame& frame : *frames) {
- switch (frame.type) {
- // Frames smaller than a pointer are inlined, so don't need to be deleted.
- case PADDING_FRAME:
- case MTU_DISCOVERY_FRAME:
- case PING_FRAME:
- break;
- case STREAM_FRAME:
- delete frame.stream_frame;
- break;
- case ACK_FRAME:
- delete frame.ack_frame;
- break;
- case STOP_WAITING_FRAME:
- delete frame.stop_waiting_frame;
- break;
- case RST_STREAM_FRAME:
- delete frame.rst_stream_frame;
- break;
- case CONNECTION_CLOSE_FRAME:
- delete frame.connection_close_frame;
- break;
- case GOAWAY_FRAME:
- delete frame.goaway_frame;
- break;
- case BLOCKED_FRAME:
- delete frame.blocked_frame;
- break;
- case WINDOW_UPDATE_FRAME:
- delete frame.window_update_frame;
- break;
- case PATH_CLOSE_FRAME:
- delete frame.path_close_frame;
- break;
- case NUM_FRAME_TYPES:
- DCHECK(false) << "Cannot delete type: " << frame.type;
- }
- }
- frames->clear();
-}
-
-// static
-void QuicUtils::RemoveFramesForStream(QuicFrames* frames,
- QuicStreamId stream_id) {
- QuicFrames::iterator it = frames->begin();
- while (it != frames->end()) {
- if (it->type != STREAM_FRAME || it->stream_frame->stream_id != stream_id) {
- ++it;
- continue;
- }
- delete it->stream_frame;
- it = frames->erase(it);
- }
-}
-
-// static
-void QuicUtils::ClearSerializedPacket(SerializedPacket* serialized_packet) {
- if (!serialized_packet->retransmittable_frames.empty()) {
- DeleteFrames(&serialized_packet->retransmittable_frames);
- }
- serialized_packet->encrypted_buffer = nullptr;
- serialized_packet->encrypted_length = 0;
-}
-
-// static
-uint64_t QuicUtils::PackPathIdAndPacketNumber(QuicPathId path_id,
- QuicPacketNumber packet_number) {
- // Setting the nonce below relies on QuicPathId and QuicPacketNumber being
- // specific sizes.
- static_assert(sizeof(path_id) == 1, "Size of QuicPathId changed.");
- static_assert(sizeof(packet_number) == 8,
- "Size of QuicPacketNumber changed.");
- // Use path_id and lower 7 bytes of packet_number as lower 8 bytes of nonce.
- uint64_t path_id_packet_number =
- (static_cast<uint64_t>(path_id) << 56) | packet_number;
- DCHECK(path_id != kDefaultPathId || path_id_packet_number == packet_number);
- return path_id_packet_number;
-}
-
-// static
-char* QuicUtils::CopyBuffer(const SerializedPacket& packet) {
- char* dst_buffer = new char[packet.encrypted_length];
- memcpy(dst_buffer, packet.encrypted_buffer, packet.encrypted_length);
- return dst_buffer;
-}
-
-// static
-PeerAddressChangeType QuicUtils::DetermineAddressChangeType(
- const IPEndPoint& old_address,
- const IPEndPoint& new_address) {
- if (!IsInitializedIPEndPoint(old_address) ||
- !IsInitializedIPEndPoint(new_address) || old_address == new_address) {
- return NO_CHANGE;
- }
-
- if (old_address.address() == new_address.address()) {
- return PORT_CHANGE;
- }
-
- bool old_ip_is_ipv4 = old_address.address().IsIPv4();
- bool migrating_ip_is_ipv4 = new_address.address().IsIPv4();
- if (old_ip_is_ipv4 && !migrating_ip_is_ipv4) {
- return IPV4_TO_IPV6_CHANGE;
- }
-
- if (!old_ip_is_ipv4) {
- return migrating_ip_is_ipv4 ? IPV6_TO_IPV4_CHANGE : IPV6_TO_IPV6_CHANGE;
- }
-
- if (IPAddressMatchesPrefix(old_address.address(), new_address.address(),
- 24)) {
- // Subnet part does not change (here, we use /24), which is considered to be
- // caused by NATs.
- return IPV4_SUBNET_CHANGE;
- }
-
- return UNSPECIFIED_CHANGE;
-}
-
-string QuicUtils::HexEncode(const char* data, size_t length) {
- return HexEncode(StringPiece(data, length));
-}
-
-string QuicUtils::HexEncode(StringPiece data) {
- return ::base::HexEncode(data.data(), data.size());
-}
-
-string QuicUtils::HexDecode(const char* data, size_t length) {
- return HexDecode(StringPiece(data, length));
-}
-
-string QuicUtils::HexDecode(StringPiece data) {
- if (data.empty())
- return "";
- std::vector<uint8_t> v;
- if (!base::HexStringToBytes(data.as_string(), &v))
- return "";
- string out;
- if (!v.empty())
- out.assign(reinterpret_cast<const char*>(&v[0]), v.size());
- return out;
-}
-
-string QuicUtils::BinaryToAscii(StringPiece binary) {
- string out = "";
- for (const unsigned char c : binary) {
- // Leading space.
- out += " ";
- if (isprint(c)) {
- out += c;
- } else {
- out += '.';
- }
- }
- return out;
-}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_utils.h b/chromium/net/quic/quic_utils.h
deleted file mode 100644
index 69e83726ea7..00000000000
--- a/chromium/net/quic/quic_utils.h
+++ /dev/null
@@ -1,165 +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.
-//
-// Some helpers for quic.
-
-#ifndef NET_QUIC_QUIC_UTILS_H_
-#define NET_QUIC_QUIC_UTILS_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "net/base/int128.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_protocol.h"
-
-#ifdef _MSC_VER
-// MSVC 2013 and prior don't have alignof or aligned(); they have __alignof and
-// a __declspec instead.
-#define QUIC_ALIGN_OF __alignof
-#define QUIC_ALIGNED(X) __declspec(align(X))
-#else
-#define QUIC_ALIGN_OF alignof
-#define QUIC_ALIGNED(X) __attribute__((aligned(X)))
-#endif // _MSC_VER
-
-namespace net {
-
-class NET_EXPORT_PRIVATE QuicUtils {
- public:
- enum Priority {
- LOCAL_PRIORITY,
- PEER_PRIORITY,
- };
-
- // Returns the 64 bit FNV1a hash of the data. See
- // http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param
- static uint64_t FNV1a_64_Hash(const char* data, int len);
-
- // returns the 128 bit FNV1a hash of the data. See
- // http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param
- static uint128 FNV1a_128_Hash(const char* data1, int len1);
-
- // returns the 128 bit FNV1a hash of the two sequences of data. See
- // http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param
- static uint128 FNV1a_128_Hash_Two(const char* data1,
- int len1,
- const char* data2,
- int len2);
-
- // FindMutualTag sets |out_result| to the first tag in the priority list that
- // is also in the other list and returns true. If there is no intersection it
- // returns false.
- //
- // Which list has priority is determined by |priority|.
- //
- // If |out_index| is non-nullptr and a match is found then the index of that
- // match in |their_tags| is written to |out_index|.
- static bool FindMutualTag(const QuicTagVector& our_tags,
- const QuicTag* their_tags,
- size_t num_their_tags,
- Priority priority,
- QuicTag* out_result,
- size_t* out_index);
-
- // SerializeUint128 writes the first 96 bits of |v| in little-endian form
- // to |out|.
- static void SerializeUint128Short(uint128 v, uint8_t* out);
-
- // Returns the name of the QuicRstStreamErrorCode as a char*
- static const char* StreamErrorToString(QuicRstStreamErrorCode error);
-
- // Returns the name of the QuicErrorCode as a char*
- static const char* ErrorToString(QuicErrorCode error);
-
- // Returns the level of encryption as a char*
- static const char* EncryptionLevelToString(EncryptionLevel level);
-
- // Returns TransmissionType as a char*
- static const char* TransmissionTypeToString(TransmissionType type);
-
- // TagToString is a utility function for pretty-printing handshake messages
- // that converts a tag to a string. It will try to maintain the human friendly
- // name if possible (i.e. kABCD -> "ABCD"), or will just treat it as a number
- // if not.
- static std::string TagToString(QuicTag tag);
-
- // Returns the list of QUIC tags represented by the comma separated
- // string in |connection_options|.
- static QuicTagVector ParseQuicConnectionOptions(
- const std::string& connection_options);
-
- // Given a binary buffer, return a hex+ASCII dump in the style of
- // tcpdump's -X and -XX options:
- // "0x0000: 0090 69bd 5400 000d 610f 0189 0800 4500 ..i.T...a.....E.\n"
- // "0x0010: 001c fb98 4000 4001 7e18 d8ef 2301 455d ....@.@.~...#.E]\n"
- // "0x0020: 7fe2 0800 6bcb 0bc6 806e ....k....n\n"
- static std::string StringToHexASCIIDump(base::StringPiece in_buffer);
-
- // Returns PeerAddressChangeType as a std::string.
- static std::string PeerAddressChangeTypeToString(PeerAddressChangeType type);
-
- static char* AsChars(unsigned char* data) {
- return reinterpret_cast<char*>(data);
- }
-
- // Deletes all the sub-frames contained in |frames|.
- static void DeleteFrames(QuicFrames* frames);
-
- // Deletes all the QuicStreamFrames for the specified |stream_id|.
- static void RemoveFramesForStream(QuicFrames* frames, QuicStreamId stream_id);
-
- // Deletes and clears all the frames and the packet from serialized packet.
- static void ClearSerializedPacket(SerializedPacket* serialized_packet);
-
- // Returns a packed representation of |path_id| and |packet_number| in which
- // the highest byte is set to |path_id| and the lower 7 bytes are the lower
- // 7 bytes of |packet_number|.
- static uint64_t PackPathIdAndPacketNumber(QuicPathId path_id,
- QuicPacketNumber packet_number);
-
- // Allocates a new char[] of size |packet.encrypted_length| and copies in
- // |packet.encrypted_buffer|.
- static char* CopyBuffer(const SerializedPacket& packet);
-
- // Determines and returns change type of address change from |old_address| to
- // |new_address|.
- static PeerAddressChangeType DetermineAddressChangeType(
- const IPEndPoint& old_address,
- const IPEndPoint& new_address);
-
- // This converts 'num' bytes of binary to a 2*'num'-character hexadecimal
- // representation. Return value: 2*'num' characters of ascii std::string.
- static std::string HexEncode(const char* data, size_t length);
- static std::string HexEncode(base::StringPiece data);
-
- // This converts 2*'num' hexadecimal characters to 'num' binary data.
- // Return value: 'num' bytes of binary data (via the 'to' argument).
- static std::string HexDecode(const char* data, size_t length);
- static std::string HexDecode(base::StringPiece data);
-
- // Converts binary data into an ASCII string. Each character in the resulting
- // string is preceeded by a space, and replaced with a '.' if not printable.
- static std::string BinaryToAscii(base::StringPiece binary);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(QuicUtils);
-};
-
-// Utility function that returns an QuicIOVector object wrapped around |str|.
-// |str|'s data is stored in |iov|.
-inline QuicIOVector MakeIOVector(base::StringPiece str, struct iovec* iov) {
- iov->iov_base = const_cast<char*>(str.data());
- iov->iov_len = static_cast<size_t>(str.size());
- QuicIOVector quic_iov(iov, 1, str.size());
- return quic_iov;
-}
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_UTILS_H_
diff --git a/chromium/net/quic/quic_utils_chromium_test.cc b/chromium/net/quic/quic_utils_chromium_test.cc
deleted file mode 100644
index b9620cfaf4a..00000000000
--- a/chromium/net/quic/quic_utils_chromium_test.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_utils_chromium.h"
-
-#include <map>
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-using std::map;
-
-namespace net {
-namespace test {
-namespace {
-
-TEST(QuicUtilsChromiumTest, FindOrNullTest) {
- map<int, int> m;
- m[0] = 2;
-
- // Check FindOrNull
- int* p1 = FindOrNull(m, 0);
- CHECK_EQ(*p1, 2);
- ++(*p1);
- const map<int, int>& const_m = m;
- const int* p2 = FindOrNull(const_m, 0);
- CHECK_EQ(*p2, 3);
- CHECK(FindOrNull(m, 1) == nullptr);
-}
-
-TEST(QuicUtilsChromiumTest, FindOrDieTest) {
- std::map<int, int> m;
- m[10] = 15;
- EXPECT_EQ(15, FindOrDie(m, 10));
- // TODO(rtenneti): Use the latest DEATH macros after merging with latest rch's
- // changes.
- // ASSERT_DEATH(FindOrDie(m, 8), "Map key not found: 8");
-
- // Make sure the non-const reference returning version works.
- FindOrDie(m, 10) = 20;
- EXPECT_EQ(20, FindOrDie(m, 10));
-
- // Make sure we can lookup values in a const map.
- const map<int, int>& const_m = m;
- EXPECT_EQ(20, FindOrDie(const_m, 10));
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_utils_test.cc b/chromium/net/quic/quic_utils_test.cc
deleted file mode 100644
index 7412a24052d..00000000000
--- a/chromium/net/quic/quic_utils_test.cc
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_utils.h"
-
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/quic_flags.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-namespace test {
-namespace {
-
-// A test string and a hex+ASCII dump of the same string.
-const unsigned char kString[] = {
- 0x00, 0x90, 0x69, 0xbd, 0x54, 0x00, 0x00, 0x0d, 0x61, 0x0f, 0x01,
- 0x89, 0x08, 0x00, 0x45, 0x00, 0x00, 0x1c, 0xfb, 0x98, 0x40, 0x00,
- 0x40, 0x01, 0x7e, 0x18, 0xd8, 0xef, 0x23, 0x01, 0x45, 0x5d, 0x7f,
- 0xe2, 0x08, 0x00, 0x6b, 0xcb, 0x0b, 0xc6, 0x80, 0x6e};
-
-const unsigned char kHexDump[] =
- "0x0000: 0090 69bd 5400 000d 610f 0189 0800 4500 ..i.T...a.....E.\n"
- "0x0010: 001c fb98 4000 4001 7e18 d8ef 2301 455d ....@.@.~...#.E]\n"
- "0x0020: 7fe2 0800 6bcb 0bc6 806e ....k....n\n";
-
-TEST(QuicUtilsTest, StreamErrorToString) {
- EXPECT_STREQ("QUIC_BAD_APPLICATION_PAYLOAD",
- QuicUtils::StreamErrorToString(QUIC_BAD_APPLICATION_PAYLOAD));
-}
-
-TEST(QuicUtilsTest, ErrorToString) {
- EXPECT_STREQ("QUIC_NO_ERROR", QuicUtils::ErrorToString(QUIC_NO_ERROR));
-}
-
-TEST(QuicUtilsTest, StringToHexASCIIDumpArgTypes) {
- // Verify that char*, string and StringPiece are all valid argument types.
- struct {
- const string input;
- const string expected;
- } tests[] = {
- {
- "", "",
- },
- {
- "A", "0x0000: 41 A\n",
- },
- {
- "AB", "0x0000: 4142 AB\n",
- },
- {
- "ABC", "0x0000: 4142 43 ABC\n",
- },
- {
- "original",
- "0x0000: 6f72 6967 696e 616c original\n",
- },
- };
-
- for (size_t i = 0; i < arraysize(tests); ++i) {
- EXPECT_EQ(tests[i].expected,
- QuicUtils::StringToHexASCIIDump(tests[i].input.c_str()));
- EXPECT_EQ(tests[i].expected,
- QuicUtils::StringToHexASCIIDump(tests[i].input));
- EXPECT_EQ(tests[i].expected,
- QuicUtils::StringToHexASCIIDump(StringPiece(tests[i].input)));
- }
-}
-
-TEST(QuicUtilsTest, StringToHexASCIIDumpSuccess) {
- EXPECT_EQ(string(reinterpret_cast<const char*>(kHexDump)),
- QuicUtils::StringToHexASCIIDump(string(
- reinterpret_cast<const char*>(kString), sizeof(kString))));
-}
-
-TEST(QuicUtilsTest, TagToString) {
- EXPECT_EQ("SCFG", QuicUtils::TagToString(kSCFG));
- EXPECT_EQ("SNO ", QuicUtils::TagToString(kServerNonceTag));
- EXPECT_EQ("CRT ", QuicUtils::TagToString(kCertificateTag));
- EXPECT_EQ("CHLO", QuicUtils::TagToString(MakeQuicTag('C', 'H', 'L', 'O')));
- // A tag that contains a non-printing character will be printed as a decimal
- // number.
- EXPECT_EQ("525092931",
- QuicUtils::TagToString(MakeQuicTag('C', 'H', 'L', '\x1f')));
-}
-
-TEST(QuicUtilsTest, ParseQuicConnectionOptions) {
- QuicTagVector empty_options = QuicUtils::ParseQuicConnectionOptions("");
- EXPECT_EQ(0ul, empty_options.size());
-
- QuicTagVector parsed_options =
- QuicUtils::ParseQuicConnectionOptions("TIMER,TBBR,REJ");
- QuicTagVector expected_options;
- expected_options.push_back(kTIME);
- expected_options.push_back(kTBBR);
- expected_options.push_back(kREJ);
- EXPECT_EQ(expected_options, parsed_options);
-}
-
-TEST(QuicUtilsTest, DetermineAddressChangeType) {
- const string kIPv4String1 = "1.2.3.4";
- const string kIPv4String2 = "1.2.3.5";
- const string kIPv4String3 = "1.1.3.5";
- const string kIPv6String1 = "2001:700:300:1800::f";
- const string kIPv6String2 = "2001:700:300:1800:1:1:1:f";
- IPEndPoint old_address;
- IPEndPoint new_address;
- IPAddress address;
-
- EXPECT_EQ(NO_CHANGE,
- QuicUtils::DetermineAddressChangeType(old_address, new_address));
- ASSERT_TRUE(address.AssignFromIPLiteral(kIPv4String1));
- old_address = IPEndPoint(address, 1234);
- EXPECT_EQ(NO_CHANGE,
- QuicUtils::DetermineAddressChangeType(old_address, new_address));
- new_address = IPEndPoint(address, 1234);
- EXPECT_EQ(NO_CHANGE,
- QuicUtils::DetermineAddressChangeType(old_address, new_address));
-
- new_address = IPEndPoint(address, 5678);
- EXPECT_EQ(PORT_CHANGE,
- QuicUtils::DetermineAddressChangeType(old_address, new_address));
- ASSERT_TRUE(address.AssignFromIPLiteral(kIPv6String1));
- old_address = IPEndPoint(address, 1234);
- new_address = IPEndPoint(address, 5678);
- EXPECT_EQ(PORT_CHANGE,
- QuicUtils::DetermineAddressChangeType(old_address, new_address));
-
- ASSERT_TRUE(address.AssignFromIPLiteral(kIPv4String1));
- old_address = IPEndPoint(address, 1234);
- ASSERT_TRUE(address.AssignFromIPLiteral(kIPv6String1));
- new_address = IPEndPoint(address, 1234);
- EXPECT_EQ(IPV4_TO_IPV6_CHANGE,
- QuicUtils::DetermineAddressChangeType(old_address, new_address));
-
- old_address = IPEndPoint(address, 1234);
- ASSERT_TRUE(address.AssignFromIPLiteral(kIPv4String1));
- new_address = IPEndPoint(address, 1234);
- EXPECT_EQ(IPV6_TO_IPV4_CHANGE,
- QuicUtils::DetermineAddressChangeType(old_address, new_address));
-
- ASSERT_TRUE(address.AssignFromIPLiteral(kIPv6String2));
- new_address = IPEndPoint(address, 1234);
- EXPECT_EQ(IPV6_TO_IPV6_CHANGE,
- QuicUtils::DetermineAddressChangeType(old_address, new_address));
-
- ASSERT_TRUE(address.AssignFromIPLiteral(kIPv4String1));
- old_address = IPEndPoint(address, 1234);
- ASSERT_TRUE(address.AssignFromIPLiteral(kIPv4String2));
- new_address = IPEndPoint(address, 1234);
- EXPECT_EQ(IPV4_SUBNET_CHANGE,
- QuicUtils::DetermineAddressChangeType(old_address, new_address));
- ASSERT_TRUE(address.AssignFromIPLiteral(kIPv4String3));
- new_address = IPEndPoint(address, 1234);
- EXPECT_EQ(UNSPECIFIED_CHANGE,
- QuicUtils::DetermineAddressChangeType(old_address, new_address));
-}
-
-uint128 IncrementalHashReference(const void* data, size_t len) {
- // The two constants are defined as part of the hash algorithm.
- // see http://www.isthe.com/chongo/tech/comp/fnv/
- // hash = 144066263297769815596495629667062367629
- uint128 hash =
- uint128(UINT64_C(7809847782465536322), UINT64_C(7113472399480571277));
- // kPrime = 309485009821345068724781371
- const uint128 kPrime(16777216, 315);
- const uint8_t* octets = reinterpret_cast<const uint8_t*>(data);
- for (size_t i = 0; i < len; ++i) {
- hash = hash ^ uint128(0, octets[i]);
- hash = hash * kPrime;
- }
- return hash;
-}
-
-TEST(QuicUtilsHashTest, ReferenceTest) {
- std::vector<uint8_t> data(32);
- for (size_t i = 0; i < data.size(); ++i) {
- data[i] = i % 255;
- }
- EXPECT_EQ(IncrementalHashReference(data.data(), data.size()),
- QuicUtils::FNV1a_128_Hash(
- reinterpret_cast<const char*>(data.data()), data.size()));
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/quic_write_blocked_list.cc b/chromium/net/quic/quic_write_blocked_list.cc
deleted file mode 100644
index ebe2ebfeeca..00000000000
--- a/chromium/net/quic/quic_write_blocked_list.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/quic/quic_write_blocked_list.h"
-
-namespace net {
-
-QuicWriteBlockedList::QuicWriteBlockedList()
- : last_priority_popped_(0),
- crypto_stream_blocked_(false),
- headers_stream_blocked_(false) {
- memset(batch_write_stream_id_, 0, sizeof(batch_write_stream_id_));
- memset(bytes_left_for_batch_write_, 0, sizeof(bytes_left_for_batch_write_));
-}
-
-QuicWriteBlockedList::~QuicWriteBlockedList() {}
-
-} // namespace net
diff --git a/chromium/net/quic/quic_write_blocked_list.h b/chromium/net/quic/quic_write_blocked_list.h
deleted file mode 100644
index e99eaa76525..00000000000
--- a/chromium/net/quic/quic_write_blocked_list.h
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-#ifndef NET_QUIC_QUIC_WRITE_BLOCKED_LIST_H_
-#define NET_QUIC_QUIC_WRITE_BLOCKED_LIST_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <set>
-
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/spdy/priority_write_scheduler.h"
-
-namespace net {
-
-// Keeps tracks of the QUIC streams that have data to write, sorted by
-// priority. QUIC stream priority order is:
-// Crypto stream > Headers stream > Data streams by requested priority.
-class NET_EXPORT_PRIVATE QuicWriteBlockedList {
- private:
- typedef PriorityWriteScheduler<QuicStreamId> QuicPriorityWriteScheduler;
-
- public:
- QuicWriteBlockedList();
- ~QuicWriteBlockedList();
-
- bool HasWriteBlockedDataStreams() const {
- return priority_write_scheduler_.HasReadyStreams();
- }
-
- bool HasWriteBlockedCryptoOrHeadersStream() const {
- return crypto_stream_blocked_ || headers_stream_blocked_;
- }
-
- size_t NumBlockedStreams() const {
- size_t num_blocked = priority_write_scheduler_.NumReadyStreams();
- if (crypto_stream_blocked_) {
- ++num_blocked;
- }
- if (headers_stream_blocked_) {
- ++num_blocked;
- }
-
- return num_blocked;
- }
-
- bool ShouldYield(QuicStreamId id) const {
- if (id == kCryptoStreamId) {
- return false; // The crypto stream yields to none.
- }
- if (crypto_stream_blocked_) {
- return true; // If the crypto stream is blocked, all other streams yield.
- }
- if (id == kHeadersStreamId) {
- return false; // The crypto stream isn't blocked so headers won't yield.
- }
- if (headers_stream_blocked_) {
- return true; // All data streams yield to the headers stream.
- }
-
- return priority_write_scheduler_.ShouldYield(id);
- }
-
- // Pops the highest priorty stream, special casing crypto and headers streams.
- // Latches the most recently popped data stream for batch writing purposes.
- QuicStreamId PopFront() {
- if (crypto_stream_blocked_) {
- crypto_stream_blocked_ = false;
- return kCryptoStreamId;
- }
-
- if (headers_stream_blocked_) {
- headers_stream_blocked_ = false;
- return kHeadersStreamId;
- }
-
- const auto id_and_precedence =
- priority_write_scheduler_.PopNextReadyStreamAndPrecedence();
- const QuicStreamId id = std::get<0>(id_and_precedence);
- const SpdyPriority priority =
- std::get<1>(id_and_precedence).spdy3_priority();
-
- if (!priority_write_scheduler_.HasReadyStreams()) {
- // If no streams are blocked, don't bother latching. This stream will be
- // the first popped for its priority anyway.
- batch_write_stream_id_[priority] = 0;
- last_priority_popped_ = priority;
- } else if (batch_write_stream_id_[priority] != id) {
- // If newly latching this batch write stream, let it write 16k.
- batch_write_stream_id_[priority] = id;
- bytes_left_for_batch_write_[priority] = 16000;
- last_priority_popped_ = priority;
- }
-
- return id;
- }
-
- void RegisterStream(QuicStreamId stream_id, SpdyPriority priority) {
- priority_write_scheduler_.RegisterStream(stream_id,
- SpdyStreamPrecedence(priority));
- }
-
- void UnregisterStream(QuicStreamId stream_id) {
- priority_write_scheduler_.UnregisterStream(stream_id);
- }
-
- void UpdateStreamPriority(QuicStreamId stream_id, SpdyPriority new_priority) {
- priority_write_scheduler_.UpdateStreamPrecedence(
- stream_id, SpdyStreamPrecedence(new_priority));
- }
-
- void UpdateBytesForStream(QuicStreamId stream_id, size_t bytes) {
- if (batch_write_stream_id_[last_priority_popped_] == stream_id) {
- // If this was the last data stream popped by PopFront, update the
- // bytes remaining in its batch write.
- bytes_left_for_batch_write_[last_priority_popped_] -=
- static_cast<int32_t>(bytes);
- }
- }
-
- // Pushes a stream to the back of the list for its priority level *unless*
- // it is latched for doing batched writes in which case it goes to the front
- // of the list for its priority level.
- // Headers and crypto streams are special cased to always resume first.
- void AddStream(QuicStreamId stream_id) {
- if (stream_id == kCryptoStreamId) {
- // TODO(avd) Add DCHECK(!crypto_stream_blocked_)
- crypto_stream_blocked_ = true;
- return;
- }
-
- if (stream_id == kHeadersStreamId) {
- // TODO(avd) Add DCHECK(!headers_stream_blocked_);
- headers_stream_blocked_ = true;
- return;
- }
- bool push_front =
- stream_id == batch_write_stream_id_[last_priority_popped_] &&
- bytes_left_for_batch_write_[last_priority_popped_] > 0;
- priority_write_scheduler_.MarkStreamReady(stream_id, push_front);
-
- return;
- }
-
- bool crypto_stream_blocked() const { return crypto_stream_blocked_; }
- bool headers_stream_blocked() const { return headers_stream_blocked_; }
-
- private:
- QuicPriorityWriteScheduler priority_write_scheduler_;
-
- // If performing batch writes, this will be the stream ID of the stream doing
- // batch writes for this priority level. We will allow this stream to write
- // until it has written kBatchWriteSize bytes, it has no more data to write,
- // or a higher priority stream preempts.
- QuicStreamId batch_write_stream_id_[kV3LowestPriority + 1];
- // Set to kBatchWriteSize when we set a new batch_write_stream_id_ for a given
- // priority. This is decremented with each write the stream does until it is
- // done with its batch write.
- int32_t bytes_left_for_batch_write_[kV3LowestPriority + 1];
- // Tracks the last priority popped for UpdateBytesForStream.
- SpdyPriority last_priority_popped_;
-
- bool crypto_stream_blocked_;
- bool headers_stream_blocked_;
-
- DISALLOW_COPY_AND_ASSIGN(QuicWriteBlockedList);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_QUIC_WRITE_BLOCKED_LIST_H_
diff --git a/chromium/net/quic/quic_write_blocked_list_test.cc b/chromium/net/quic/quic_write_blocked_list_test.cc
deleted file mode 100644
index 23009c06853..00000000000
--- a/chromium/net/quic/quic_write_blocked_list_test.cc
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-#include "net/quic/quic_write_blocked_list.h"
-
-#include "net/quic/test_tools/quic_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using net::kV3LowestPriority;
-using net::kV3HighestPriority;
-
-namespace net {
-namespace test {
-namespace {
-
-TEST(QuicWriteBlockedListTest, PriorityOrder) {
- QuicWriteBlockedList write_blocked_list;
-
- // Mark streams blocked in roughly reverse priority order, and
- // verify that streams are sorted.
- write_blocked_list.RegisterStream(40, kV3LowestPriority);
- write_blocked_list.RegisterStream(23, kV3HighestPriority);
- write_blocked_list.RegisterStream(17, kV3HighestPriority);
- write_blocked_list.RegisterStream(kHeadersStreamId, kV3HighestPriority);
- write_blocked_list.RegisterStream(kCryptoStreamId, kV3HighestPriority);
-
- write_blocked_list.AddStream(40);
- write_blocked_list.AddStream(23);
- write_blocked_list.AddStream(17);
- write_blocked_list.AddStream(kHeadersStreamId);
- write_blocked_list.AddStream(kCryptoStreamId);
-
- EXPECT_EQ(5u, write_blocked_list.NumBlockedStreams());
- EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
- EXPECT_TRUE(write_blocked_list.HasWriteBlockedDataStreams());
- // The Crypto stream is highest priority.
- EXPECT_EQ(kCryptoStreamId, write_blocked_list.PopFront());
- // Followed by the Headers stream.
- EXPECT_EQ(kHeadersStreamId, write_blocked_list.PopFront());
- // Streams with same priority are popped in the order they were inserted.
- EXPECT_EQ(23u, write_blocked_list.PopFront());
- EXPECT_EQ(17u, write_blocked_list.PopFront());
- // Low priority stream appears last.
- EXPECT_EQ(40u, write_blocked_list.PopFront());
-
- EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams());
- EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
- EXPECT_FALSE(write_blocked_list.HasWriteBlockedDataStreams());
-}
-
-TEST(QuicWriteBlockedListTest, CryptoStream) {
- QuicWriteBlockedList write_blocked_list;
- write_blocked_list.RegisterStream(kCryptoStreamId, kV3HighestPriority);
- write_blocked_list.AddStream(kCryptoStreamId);
-
- EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams());
- EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
- EXPECT_EQ(kCryptoStreamId, write_blocked_list.PopFront());
- EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams());
- EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
-}
-
-TEST(QuicWriteBlockedListTest, HeadersStream) {
- QuicWriteBlockedList write_blocked_list;
- write_blocked_list.RegisterStream(kHeadersStreamId, kV3HighestPriority);
- write_blocked_list.AddStream(kHeadersStreamId);
-
- EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams());
- EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
- EXPECT_EQ(kHeadersStreamId, write_blocked_list.PopFront());
- EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams());
- EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
-}
-
-TEST(QuicWriteBlockedListTest, VerifyHeadersStream) {
- QuicWriteBlockedList write_blocked_list;
- write_blocked_list.RegisterStream(5, kV3HighestPriority);
- write_blocked_list.RegisterStream(kHeadersStreamId, kV3HighestPriority);
- write_blocked_list.AddStream(5);
- write_blocked_list.AddStream(kHeadersStreamId);
-
- EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams());
- EXPECT_TRUE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
- EXPECT_TRUE(write_blocked_list.HasWriteBlockedDataStreams());
- // In newer QUIC versions, there is a headers stream which is
- // higher priority than data streams.
- EXPECT_EQ(kHeadersStreamId, write_blocked_list.PopFront());
- EXPECT_EQ(5u, write_blocked_list.PopFront());
- EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams());
- EXPECT_FALSE(write_blocked_list.HasWriteBlockedCryptoOrHeadersStream());
- EXPECT_FALSE(write_blocked_list.HasWriteBlockedDataStreams());
-}
-
-TEST(QuicWriteBlockedListTest, NoDuplicateEntries) {
- // Test that QuicWriteBlockedList doesn't allow duplicate entries.
- QuicWriteBlockedList write_blocked_list;
-
- // Try to add a stream to the write blocked list multiple times at the same
- // priority.
- const QuicStreamId kBlockedId = kClientDataStreamId1;
- write_blocked_list.RegisterStream(kBlockedId, kV3HighestPriority);
- write_blocked_list.AddStream(kBlockedId);
- write_blocked_list.AddStream(kBlockedId);
- write_blocked_list.AddStream(kBlockedId);
-
- // This should only result in one blocked stream being added.
- EXPECT_EQ(1u, write_blocked_list.NumBlockedStreams());
- EXPECT_TRUE(write_blocked_list.HasWriteBlockedDataStreams());
-
- // There should only be one stream to pop off the front.
- EXPECT_EQ(kBlockedId, write_blocked_list.PopFront());
- EXPECT_EQ(0u, write_blocked_list.NumBlockedStreams());
- EXPECT_FALSE(write_blocked_list.HasWriteBlockedDataStreams());
-}
-
-TEST(QuicWriteBlockedListTest, BatchingWrites) {
- QuicWriteBlockedList write_blocked_list;
-
- const QuicStreamId id1 = kClientDataStreamId1;
- const QuicStreamId id2 = kClientDataStreamId2;
- const QuicStreamId id3 = kClientDataStreamId2 + 2;
- write_blocked_list.RegisterStream(id1, kV3LowestPriority);
- write_blocked_list.RegisterStream(id2, kV3LowestPriority);
- write_blocked_list.RegisterStream(id3, kV3HighestPriority);
-
- write_blocked_list.AddStream(id1);
- write_blocked_list.AddStream(id2);
- EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams());
-
- // The first stream we push back should stay at the front until 16k is
- // written.
- EXPECT_EQ(id1, write_blocked_list.PopFront());
- write_blocked_list.UpdateBytesForStream(id1, 15999);
- write_blocked_list.AddStream(id1);
- EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams());
- EXPECT_EQ(id1, write_blocked_list.PopFront());
-
- // Once 16k is written the first stream will yield to the next.
- write_blocked_list.UpdateBytesForStream(id1, 1);
- write_blocked_list.AddStream(id1);
- EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams());
- EXPECT_EQ(id2, write_blocked_list.PopFront());
-
- // Set the new stream to have written all but one byte.
- write_blocked_list.UpdateBytesForStream(id2, 15999);
- write_blocked_list.AddStream(id2);
- EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams());
-
- // Ensure higher priority streams are popped first.
- write_blocked_list.AddStream(id3);
- EXPECT_EQ(id3, write_blocked_list.PopFront());
-
- // Higher priority streams will always be popped first, even if using their
- // byte quota
- write_blocked_list.UpdateBytesForStream(id3, 20000);
- write_blocked_list.AddStream(id3);
- EXPECT_EQ(id3, write_blocked_list.PopFront());
-
- // Once the higher priority stream is out of the way, id2 will resume its 16k
- // write, with only 1 byte remaining of its guaranteed write allocation.
- EXPECT_EQ(id2, write_blocked_list.PopFront());
- write_blocked_list.AddStream(id2);
- write_blocked_list.UpdateBytesForStream(id2, 1);
- write_blocked_list.AddStream(id2);
- EXPECT_EQ(2u, write_blocked_list.NumBlockedStreams());
- EXPECT_EQ(id1, write_blocked_list.PopFront());
-}
-
-TEST(QuicWriteBlockedListTest, Ceding) {
- QuicWriteBlockedList write_blocked_list;
-
- write_blocked_list.RegisterStream(15, kV3HighestPriority);
- write_blocked_list.RegisterStream(16, kV3HighestPriority);
- write_blocked_list.RegisterStream(5, 5);
- write_blocked_list.RegisterStream(4, 5);
- write_blocked_list.RegisterStream(7, 7);
- write_blocked_list.RegisterStream(kHeadersStreamId, kV3HighestPriority);
- write_blocked_list.RegisterStream(kCryptoStreamId, kV3HighestPriority);
-
- // When nothing is on the list, nothing yields.
- EXPECT_FALSE(write_blocked_list.ShouldYield(5));
-
- write_blocked_list.AddStream(5);
- // 5 should not yield to itself.
- EXPECT_FALSE(write_blocked_list.ShouldYield(5));
- // 4 and 7 are equal or lower priority and should yield to 5.
- EXPECT_TRUE(write_blocked_list.ShouldYield(4));
- EXPECT_TRUE(write_blocked_list.ShouldYield(7));
- // 15, headers and crypto should preempt 5.
- EXPECT_FALSE(write_blocked_list.ShouldYield(15));
- EXPECT_FALSE(write_blocked_list.ShouldYield(kHeadersStreamId));
- EXPECT_FALSE(write_blocked_list.ShouldYield(kCryptoStreamId));
-
- // Block a high priority stream.
- write_blocked_list.AddStream(15);
- // 16 should yield (same priority) but headers and crypto will still not.
- EXPECT_TRUE(write_blocked_list.ShouldYield(16));
- EXPECT_FALSE(write_blocked_list.ShouldYield(kHeadersStreamId));
- EXPECT_FALSE(write_blocked_list.ShouldYield(kCryptoStreamId));
-
- // Block the headers stream. All streams but crypto and headers should yield.
- write_blocked_list.AddStream(kHeadersStreamId);
- EXPECT_TRUE(write_blocked_list.ShouldYield(16));
- EXPECT_TRUE(write_blocked_list.ShouldYield(15));
- EXPECT_FALSE(write_blocked_list.ShouldYield(kHeadersStreamId));
- EXPECT_FALSE(write_blocked_list.ShouldYield(kCryptoStreamId));
-
- // Block the crypto stream. All streams but crypto should yield.
- write_blocked_list.AddStream(kCryptoStreamId);
- EXPECT_TRUE(write_blocked_list.ShouldYield(16));
- EXPECT_TRUE(write_blocked_list.ShouldYield(15));
- EXPECT_TRUE(write_blocked_list.ShouldYield(kHeadersStreamId));
- EXPECT_FALSE(write_blocked_list.ShouldYield(kCryptoStreamId));
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/reliable_quic_stream.cc b/chromium/net/quic/reliable_quic_stream.cc
deleted file mode 100644
index c7d3b6acc67..00000000000
--- a/chromium/net/quic/reliable_quic_stream.cc
+++ /dev/null
@@ -1,466 +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/reliable_quic_stream.h"
-
-#include "base/logging.h"
-#include "net/quic/iovector.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_flow_controller.h"
-#include "net/quic/quic_session.h"
-#include "net/quic/quic_write_blocked_list.h"
-
-using base::StringPiece;
-using std::min;
-using std::string;
-
-namespace net {
-
-#define ENDPOINT \
- (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ")
-
-namespace {
-
-struct iovec MakeIovec(StringPiece data) {
- struct iovec iov = {const_cast<char*>(data.data()),
- static_cast<size_t>(data.size())};
- return iov;
-}
-
-size_t GetInitialStreamFlowControlWindowToSend(QuicSession* session) {
- return session->config()->GetInitialStreamFlowControlWindowToSend();
-}
-
-size_t GetReceivedFlowControlWindow(QuicSession* session) {
- if (session->config()->HasReceivedInitialStreamFlowControlWindowBytes()) {
- return session->config()->ReceivedInitialStreamFlowControlWindowBytes();
- }
-
- return kMinimumFlowControlSendWindow;
-}
-
-} // namespace
-
-ReliableQuicStream::PendingData::PendingData(
- string data_in,
- QuicAckListenerInterface* ack_listener_in)
- : data(data_in), offset(0), ack_listener(ack_listener_in) {}
-
-ReliableQuicStream::PendingData::~PendingData() {}
-
-ReliableQuicStream::ReliableQuicStream(QuicStreamId id, QuicSession* session)
- : queued_data_bytes_(0),
- sequencer_(this, session->connection()->clock()),
- id_(id),
- session_(session),
- stream_bytes_read_(0),
- stream_bytes_written_(0),
- stream_error_(QUIC_STREAM_NO_ERROR),
- connection_error_(QUIC_NO_ERROR),
- read_side_closed_(false),
- write_side_closed_(false),
- fin_buffered_(false),
- fin_sent_(false),
- fin_received_(false),
- rst_sent_(false),
- rst_received_(false),
- perspective_(session_->perspective()),
- flow_controller_(session_->connection(),
- id_,
- perspective_,
- GetReceivedFlowControlWindow(session),
- GetInitialStreamFlowControlWindowToSend(session),
- session_->flow_controller()->auto_tune_receive_window()),
- connection_flow_controller_(session_->flow_controller()),
- stream_contributes_to_connection_flow_control_(true) {
- SetFromConfig();
-}
-
-ReliableQuicStream::~ReliableQuicStream() {}
-
-void ReliableQuicStream::SetFromConfig() {}
-
-void ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) {
- DCHECK_EQ(frame.stream_id, id_);
-
- DCHECK(!(read_side_closed_ && write_side_closed_));
-
- if (frame.fin) {
- fin_received_ = true;
- if (fin_sent_) {
- session_->StreamDraining(id_);
- }
- }
-
- if (read_side_closed_) {
- DVLOG(1) << ENDPOINT << "Ignoring data in frame " << frame.stream_id;
- // The subclass does not want to read data: blackhole the data.
- return;
- }
-
- // This count includes duplicate data received.
- size_t frame_payload_size = frame.data_length;
- stream_bytes_read_ += frame_payload_size;
-
- // Flow control is interested in tracking highest received offset.
- // Only interested in received frames that carry data.
- if ((!FLAGS_quic_ignore_zero_length_frames || frame_payload_size > 0) &&
- MaybeIncreaseHighestReceivedOffset(frame.offset + frame_payload_size)) {
- // As the highest received offset has changed, check to see if this is a
- // violation of flow control.
- if (flow_controller_.FlowControlViolation() ||
- connection_flow_controller_->FlowControlViolation()) {
- CloseConnectionWithDetails(
- QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
- "Flow control violation after increasing offset");
- return;
- }
- }
-
- sequencer_.OnStreamFrame(frame);
-}
-
-int ReliableQuicStream::num_frames_received() const {
- return sequencer_.num_frames_received();
-}
-
-int ReliableQuicStream::num_early_frames_received() const {
- return sequencer_.num_early_frames_received();
-}
-
-int ReliableQuicStream::num_duplicate_frames_received() const {
- return sequencer_.num_duplicate_frames_received();
-}
-
-void ReliableQuicStream::OnStreamReset(const QuicRstStreamFrame& frame) {
- rst_received_ = true;
- MaybeIncreaseHighestReceivedOffset(frame.byte_offset);
-
- stream_error_ = frame.error_code;
- CloseWriteSide();
- CloseReadSide();
-}
-
-void ReliableQuicStream::OnConnectionClosed(QuicErrorCode error,
- ConnectionCloseSource /*source*/) {
- if (read_side_closed_ && write_side_closed_) {
- return;
- }
- if (error != QUIC_NO_ERROR) {
- stream_error_ = QUIC_STREAM_CONNECTION_ERROR;
- connection_error_ = error;
- }
-
- CloseWriteSide();
- CloseReadSide();
-}
-
-void ReliableQuicStream::OnFinRead() {
- DCHECK(sequencer_.IsClosed());
- // OnFinRead can be called due to a FIN flag in a headers block, so there may
- // have been no OnStreamFrame call with a FIN in the frame.
- fin_received_ = true;
- // If fin_sent_ is true, then CloseWriteSide has already been called, and the
- // stream will be destroyed by CloseReadSide, so don't need to call
- // StreamDraining.
- CloseReadSide();
-}
-
-void ReliableQuicStream::Reset(QuicRstStreamErrorCode error) {
- stream_error_ = error;
- // Sending a RstStream results in calling CloseStream.
- session()->SendRstStream(id(), error, stream_bytes_written_);
- rst_sent_ = true;
-}
-
-void ReliableQuicStream::CloseConnectionWithDetails(QuicErrorCode error,
- const string& details) {
- session()->connection()->CloseConnection(
- error, details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-}
-
-void ReliableQuicStream::WriteOrBufferData(
- StringPiece data,
- bool fin,
- QuicAckListenerInterface* ack_listener) {
- if (data.empty() && !fin) {
- QUIC_BUG << "data.empty() && !fin";
- return;
- }
-
- if (fin_buffered_) {
- QUIC_BUG << "Fin already buffered";
- return;
- }
- if (write_side_closed_) {
- DLOG(ERROR) << ENDPOINT << "Attempt to write when the write side is closed";
- return;
- }
-
- QuicConsumedData consumed_data(0, false);
- fin_buffered_ = fin;
-
- if (queued_data_.empty()) {
- struct iovec iov(MakeIovec(data));
- consumed_data = WritevData(&iov, 1, fin, ack_listener);
- DCHECK_LE(consumed_data.bytes_consumed, data.length());
- }
-
- // If there's unconsumed data or an unconsumed fin, queue it.
- if (consumed_data.bytes_consumed < data.length() ||
- (fin && !consumed_data.fin_consumed)) {
- StringPiece remainder(data.substr(consumed_data.bytes_consumed));
- queued_data_bytes_ += remainder.size();
- queued_data_.emplace_back(remainder.as_string(), ack_listener);
- }
-}
-
-void ReliableQuicStream::OnCanWrite() {
- bool fin = false;
- while (!queued_data_.empty()) {
- PendingData* pending_data = &queued_data_.front();
- QuicAckListenerInterface* ack_listener = pending_data->ack_listener.get();
- if (queued_data_.size() == 1 && fin_buffered_) {
- fin = true;
- }
- if (pending_data->offset > 0 &&
- pending_data->offset >= pending_data->data.size()) {
- // This should be impossible because offset tracks the amount of
- // pending_data written thus far.
- QUIC_BUG << "Pending offset is beyond available data. offset: "
- << pending_data->offset << " vs: " << pending_data->data.size();
- return;
- }
- size_t remaining_len = pending_data->data.size() - pending_data->offset;
- struct iovec iov = {
- const_cast<char*>(pending_data->data.data()) + pending_data->offset,
- remaining_len};
- QuicConsumedData consumed_data = WritevData(&iov, 1, fin, ack_listener);
- queued_data_bytes_ -= consumed_data.bytes_consumed;
- if (consumed_data.bytes_consumed == remaining_len &&
- fin == consumed_data.fin_consumed) {
- queued_data_.pop_front();
- } else {
- if (consumed_data.bytes_consumed > 0) {
- pending_data->offset += consumed_data.bytes_consumed;
- }
- break;
- }
- }
-}
-
-void ReliableQuicStream::MaybeSendBlocked() {
- flow_controller_.MaybeSendBlocked();
- if (!stream_contributes_to_connection_flow_control_) {
- return;
- }
- connection_flow_controller_->MaybeSendBlocked();
- // If the stream is blocked by connection-level flow control but not by
- // stream-level flow control, add the stream to the write blocked list so that
- // the stream will be given a chance to write when a connection-level
- // WINDOW_UPDATE arrives.
- if (connection_flow_controller_->IsBlocked() &&
- !flow_controller_.IsBlocked()) {
- session_->MarkConnectionLevelWriteBlocked(id());
- }
-}
-
-QuicConsumedData ReliableQuicStream::WritevData(
- const struct iovec* iov,
- int iov_count,
- bool fin,
- QuicAckListenerInterface* ack_listener) {
- if (write_side_closed_) {
- DLOG(ERROR) << ENDPOINT << "Attempt to write when the write side is closed";
- return QuicConsumedData(0, false);
- }
-
- // How much data was provided.
- size_t write_length = TotalIovecLength(iov, iov_count);
-
- // A FIN with zero data payload should not be flow control blocked.
- bool fin_with_zero_data = (fin && write_length == 0);
-
- // How much data flow control permits to be written.
- QuicByteCount send_window = flow_controller_.SendWindowSize();
- if (stream_contributes_to_connection_flow_control_) {
- send_window =
- min(send_window, connection_flow_controller_->SendWindowSize());
- }
-
- if (FLAGS_quic_cede_correctly && session_->ShouldYield(id())) {
- session_->MarkConnectionLevelWriteBlocked(id());
- return QuicConsumedData(0, false);
- }
-
- if (send_window == 0 && !fin_with_zero_data) {
- // Quick return if nothing can be sent.
- MaybeSendBlocked();
- return QuicConsumedData(0, false);
- }
-
- if (write_length > send_window) {
- // Don't send the FIN unless all the data will be sent.
- fin = false;
-
- // Writing more data would be a violation of flow control.
- write_length = static_cast<size_t>(send_window);
- }
-
- QuicConsumedData consumed_data = session()->WritevData(
- this, id(), QuicIOVector(iov, iov_count, write_length),
- stream_bytes_written_, fin, ack_listener);
- stream_bytes_written_ += consumed_data.bytes_consumed;
-
- AddBytesSent(consumed_data.bytes_consumed);
-
- // The write may have generated a write error causing this stream to be
- // closed. If so, simply return without marking the stream write blocked.
- if (write_side_closed_) {
- return consumed_data;
- }
-
- if (consumed_data.bytes_consumed == write_length) {
- if (!fin_with_zero_data) {
- MaybeSendBlocked();
- }
- if (fin && consumed_data.fin_consumed) {
- fin_sent_ = true;
- if (fin_received_) {
- session_->StreamDraining(id_);
- }
- CloseWriteSide();
- } else if (fin && !consumed_data.fin_consumed) {
- session_->MarkConnectionLevelWriteBlocked(id());
- }
- } else {
- session_->MarkConnectionLevelWriteBlocked(id());
- }
- return consumed_data;
-}
-
-void ReliableQuicStream::CloseReadSide() {
- if (read_side_closed_) {
- return;
- }
- DVLOG(1) << ENDPOINT << "Done reading from stream " << id();
-
- read_side_closed_ = true;
- if (write_side_closed_) {
- DVLOG(1) << ENDPOINT << "Closing stream: " << id();
- session_->CloseStream(id());
- }
-}
-
-void ReliableQuicStream::CloseWriteSide() {
- if (write_side_closed_) {
- return;
- }
- DVLOG(1) << ENDPOINT << "Done writing to stream " << id();
-
- write_side_closed_ = true;
- if (read_side_closed_) {
- DVLOG(1) << ENDPOINT << "Closing stream: " << id();
- session_->CloseStream(id());
- }
-}
-
-bool ReliableQuicStream::HasBufferedData() const {
- return !queued_data_.empty();
-}
-
-QuicVersion ReliableQuicStream::version() const {
- return session_->connection()->version();
-}
-
-void ReliableQuicStream::StopReading() {
- DVLOG(1) << ENDPOINT << "Stop reading from stream " << id();
- sequencer_.StopReading();
-}
-
-const IPEndPoint& ReliableQuicStream::PeerAddressOfLatestPacket() const {
- return session_->connection()->last_packet_source_address();
-}
-
-void ReliableQuicStream::OnClose() {
- CloseReadSide();
- CloseWriteSide();
-
- if (!fin_sent_ && !rst_sent_) {
- // For flow control accounting, tell the peer how many bytes have been
- // written on this stream before termination. Done here if needed, using a
- // RST_STREAM frame.
- DVLOG(1) << ENDPOINT << "Sending RST_STREAM in OnClose: " << id();
- session_->SendRstStream(id(), QUIC_RST_ACKNOWLEDGEMENT,
- stream_bytes_written_);
- rst_sent_ = true;
- }
-
- // The stream is being closed and will not process any further incoming bytes.
- // As there may be more bytes in flight, to ensure that both endpoints have
- // the same connection level flow control state, mark all unreceived or
- // buffered bytes as consumed.
- QuicByteCount bytes_to_consume =
- flow_controller_.highest_received_byte_offset() -
- flow_controller_.bytes_consumed();
- AddBytesConsumed(bytes_to_consume);
-}
-
-void ReliableQuicStream::OnWindowUpdateFrame(
- const QuicWindowUpdateFrame& frame) {
- if (flow_controller_.UpdateSendWindowOffset(frame.byte_offset)) {
- // Writing can be done again!
- // TODO(rjshade): This does not respect priorities (e.g. multiple
- // outstanding POSTs are unblocked on arrival of
- // SHLO with initial window).
- // As long as the connection is not flow control blocked, write on!
- OnCanWrite();
- }
-}
-
-bool ReliableQuicStream::MaybeIncreaseHighestReceivedOffset(
- QuicStreamOffset new_offset) {
- uint64_t increment =
- new_offset - flow_controller_.highest_received_byte_offset();
- if (!flow_controller_.UpdateHighestReceivedOffset(new_offset)) {
- return false;
- }
-
- // If |new_offset| increased the stream flow controller's highest received
- // offset, increase the connection flow controller's value by the incremental
- // difference.
- if (stream_contributes_to_connection_flow_control_) {
- connection_flow_controller_->UpdateHighestReceivedOffset(
- connection_flow_controller_->highest_received_byte_offset() +
- increment);
- }
- return true;
-}
-
-void ReliableQuicStream::AddBytesSent(QuicByteCount bytes) {
- flow_controller_.AddBytesSent(bytes);
- if (stream_contributes_to_connection_flow_control_) {
- connection_flow_controller_->AddBytesSent(bytes);
- }
-}
-
-void ReliableQuicStream::AddBytesConsumed(QuicByteCount bytes) {
- // Only adjust stream level flow controller if still reading.
- if (!read_side_closed_) {
- flow_controller_.AddBytesConsumed(bytes);
- }
-
- if (stream_contributes_to_connection_flow_control_) {
- connection_flow_controller_->AddBytesConsumed(bytes);
- }
-}
-
-void ReliableQuicStream::UpdateSendWindowOffset(QuicStreamOffset new_window) {
- if (flow_controller_.UpdateSendWindowOffset(new_window)) {
- OnCanWrite();
- }
-}
-
-} // namespace net
diff --git a/chromium/net/quic/reliable_quic_stream.h b/chromium/net/quic/reliable_quic_stream.h
deleted file mode 100644
index da320363d36..00000000000
--- a/chromium/net/quic/reliable_quic_stream.h
+++ /dev/null
@@ -1,304 +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.
-//
-// The base class for client/server reliable streams.
-
-// It does not contain the entire interface needed by an application to interact
-// with a QUIC stream. Some parts of the interface must be obtained by
-// accessing the owning session object. A subclass of ReliableQuicStream
-// connects the object and the application that generates and consumes the data
-// of the stream.
-
-// The ReliableQuicStream object has a dependent QuicStreamSequencer object,
-// which is given the stream frames as they arrive, and provides stream data in
-// order by invoking ProcessRawData().
-
-#ifndef NET_QUIC_RELIABLE_QUIC_STREAM_H_
-#define NET_QUIC_RELIABLE_QUIC_STREAM_H_
-
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <list>
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/strings/string_piece.h"
-#include "net/base/iovec.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_flow_controller.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_stream_sequencer.h"
-#include "net/quic/quic_types.h"
-
-namespace net {
-
-namespace test {
-class ReliableQuicStreamPeer;
-} // namespace test
-
-class QuicSession;
-
-class NET_EXPORT_PRIVATE ReliableQuicStream {
- public:
- ReliableQuicStream(QuicStreamId id, QuicSession* session);
-
- virtual ~ReliableQuicStream();
-
- // Not in use currently.
- void SetFromConfig();
-
- // Called by the session when a (potentially duplicate) stream frame has been
- // received for this stream.
- virtual void OnStreamFrame(const QuicStreamFrame& frame);
-
- // Called by the session when the connection becomes writeable to allow the
- // stream to write any pending data.
- virtual void OnCanWrite();
-
- // Called by the session just before the object is destroyed.
- // The object should not be accessed after OnClose is called.
- // Sends a RST_STREAM with code QUIC_RST_ACKNOWLEDGEMENT if neither a FIN nor
- // a RST_STREAM has been sent.
- virtual void OnClose();
-
- // Called by the session when the endpoint receives a RST_STREAM from the
- // peer.
- virtual void OnStreamReset(const QuicRstStreamFrame& frame);
-
- // Called by the session when the endpoint receives or sends a connection
- // close, and should immediately close the stream.
- virtual void OnConnectionClosed(QuicErrorCode error,
- ConnectionCloseSource source);
-
- // Called by the stream subclass after it has consumed the final incoming
- // data.
- void OnFinRead();
-
- // Called when new data is available from the sequencer. Subclasses must
- // actively retrieve the data using the sequencer's Readv() or
- // GetReadableRegions() method.
- virtual void OnDataAvailable() = 0;
-
- // Called by the subclass or the sequencer to reset the stream from this
- // end.
- virtual void Reset(QuicRstStreamErrorCode error);
-
- // Called by the subclass or the sequencer to close the entire connection from
- // this end.
- virtual void CloseConnectionWithDetails(QuicErrorCode error,
- const std::string& details);
-
- QuicStreamId id() const { return id_; }
-
- QuicRstStreamErrorCode stream_error() const { return stream_error_; }
- QuicErrorCode connection_error() const { return connection_error_; }
-
- bool reading_stopped() const {
- return sequencer_.ignore_read_data() || read_side_closed_;
- }
- bool write_side_closed() const { return write_side_closed_; }
-
- bool rst_received() { return rst_received_; }
- bool rst_sent() { return rst_sent_; }
- bool fin_received() { return fin_received_; }
- bool fin_sent() { return fin_sent_; }
-
- uint64_t queued_data_bytes() const { return queued_data_bytes_; }
-
- uint64_t stream_bytes_read() const { return stream_bytes_read_; }
- uint64_t stream_bytes_written() const { return stream_bytes_written_; }
-
- void set_fin_sent(bool fin_sent) { fin_sent_ = fin_sent; }
- void set_fin_received(bool fin_received) { fin_received_ = fin_received; }
- void set_rst_sent(bool rst_sent) { rst_sent_ = rst_sent; }
-
- void set_rst_received(bool rst_received) { rst_received_ = rst_received; }
- void set_stream_error(QuicRstStreamErrorCode error) { stream_error_ = error; }
-
- // Adjust the flow control window according to new offset in |frame|.
- virtual void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame);
-
- // Used in Chrome.
- int num_frames_received() const;
- int num_early_frames_received() const;
- int num_duplicate_frames_received() const;
-
- QuicFlowController* flow_controller() { return &flow_controller_; }
-
- // Called when endpoint receives a frame which could increase the highest
- // offset.
- // Returns true if the highest offset did increase.
- bool MaybeIncreaseHighestReceivedOffset(QuicStreamOffset new_offset);
- // Called when bytes are sent to the peer.
- void AddBytesSent(QuicByteCount bytes);
- // Called by the stream sequencer as bytes are consumed from the buffer.
- // If the receive window has dropped below the threshold, then send a
- // WINDOW_UPDATE frame.
- void AddBytesConsumed(QuicByteCount bytes);
-
- // Updates the flow controller's send window offset and calls OnCanWrite if
- // it was blocked before.
- void UpdateSendWindowOffset(QuicStreamOffset new_offset);
-
- // Returns true if the stream has received either a RST_STREAM or a FIN -
- // either of which gives a definitive number of bytes which the peer has
- // sent. If this is not true on deletion of the stream object, the session
- // must keep track of the stream's byte offset until a definitive final value
- // arrives.
- bool HasFinalReceivedByteOffset() const {
- return fin_received_ || rst_received_;
- }
-
- // Returns true if the stream has queued data waiting to write.
- bool HasBufferedData() const;
-
- // Returns the version of QUIC being used for this stream.
- QuicVersion version() const;
-
- bool fin_received() const { return fin_received_; }
-
- // Sets the sequencer to consume all incoming data itself and not call
- // OnDataAvailable().
- // When the FIN is received, the stream will be notified automatically (via
- // OnFinRead()) (which may happen during the call of StopReading()).
- // TODO(dworley): There should be machinery to send a RST_STREAM/NO_ERROR and
- // stop sending stream-level flow-control updates when this end sends FIN.
- virtual void StopReading();
-
- // Get peer IP of the lastest packet which connection is dealing/delt with.
- virtual const IPEndPoint& PeerAddressOfLatestPacket() const;
-
- protected:
- // Sends as much of 'data' to the connection as the connection will consume,
- // and then buffers any remaining data in queued_data_.
- // If fin is true: if it is immediately passed on to the session,
- // write_side_closed() becomes true, otherwise fin_buffered_ becomes true.
- void WriteOrBufferData(base::StringPiece data,
- bool fin,
- QuicAckListenerInterface* ack_listener);
-
- // Sends as many bytes in the first |count| buffers of |iov| to the connection
- // as the connection will consume.
- // If |ack_listener| is provided, then it will be notified once all
- // the ACKs for this write have been received.
- // Returns the number of bytes consumed by the connection.
- QuicConsumedData WritevData(const struct iovec* iov,
- int iov_count,
- bool fin,
- QuicAckListenerInterface* ack_listener);
-
- // Close the write side of the socket. Further writes will fail.
- // Can be called by the subclass or internally.
- // Does not send a FIN. May cause the stream to be closed.
- virtual void CloseWriteSide();
-
- bool fin_buffered() const { return fin_buffered_; }
-
- const QuicSession* session() const { return session_; }
- QuicSession* session() { return session_; }
-
- const QuicStreamSequencer* sequencer() const { return &sequencer_; }
- QuicStreamSequencer* sequencer() { return &sequencer_; }
-
- void DisableConnectionFlowControlForThisStream() {
- stream_contributes_to_connection_flow_control_ = false;
- }
-
- private:
- friend class test::ReliableQuicStreamPeer;
- friend class QuicStreamUtils;
-
- // Close the read side of the socket. May cause the stream to be closed.
- // Subclasses and consumers should use StopReading to terminate reading early.
- void CloseReadSide();
-
- // Subclasses and consumers should use reading_stopped.
- bool read_side_closed() const { return read_side_closed_; }
-
- struct PendingData {
- PendingData(std::string data_in, QuicAckListenerInterface* ack_listener_in);
- ~PendingData();
-
- // Pending data to be written.
- std::string data;
- // Index of the first byte in data still to be written.
- size_t offset;
- // AckListener that should be notified when the pending data is acked.
- // Can be nullptr.
- scoped_refptr<QuicAckListenerInterface> ack_listener;
- };
-
- // Calls MaybeSendBlocked on the stream's flow controller and the connection
- // level flow controller. If the stream is flow control blocked by the
- // connection-level flow controller but not by the stream-level flow
- // controller, marks this stream as connection-level write blocked.
- void MaybeSendBlocked();
-
- std::list<PendingData> queued_data_;
- // How many bytes are queued?
- uint64_t queued_data_bytes_;
-
- QuicStreamSequencer sequencer_;
- QuicStreamId id_;
- // Pointer to the owning QuicSession object.
- QuicSession* session_;
- // Bytes read and written refer to payload bytes only: they do not include
- // framing, encryption overhead etc.
- uint64_t stream_bytes_read_;
- uint64_t stream_bytes_written_;
-
- // Stream error code received from a RstStreamFrame or error code sent by the
- // visitor or sequencer in the RstStreamFrame.
- QuicRstStreamErrorCode stream_error_;
- // Connection error code due to which the stream was closed. |stream_error_|
- // is set to |QUIC_STREAM_CONNECTION_ERROR| when this happens and consumers
- // should check |connection_error_|.
- QuicErrorCode connection_error_;
-
- // True if the read side is closed and further frames should be rejected.
- bool read_side_closed_;
- // True if the write side is closed, and further writes should fail.
- bool write_side_closed_;
-
- // True if the subclass has written a FIN with WriteOrBufferData, but it was
- // buffered in queued_data_ rather than being sent to the session.
- bool fin_buffered_;
- // True if a FIN has been sent to the session.
- bool fin_sent_;
-
- // True if this stream has received (and the sequencer has accepted) a
- // StreamFrame with the FIN set.
- bool fin_received_;
-
- // True if an RST_STREAM has been sent to the session.
- // In combination with fin_sent_, used to ensure that a FIN and/or a
- // RST_STREAM is always sent to terminate the stream.
- bool rst_sent_;
-
- // True if this stream has received a RST_STREAM frame.
- bool rst_received_;
-
- // Tracks if the session this stream is running under was created by a
- // server or a client.
- Perspective perspective_;
-
- QuicFlowController flow_controller_;
-
- // The connection level flow controller. Not owned.
- QuicFlowController* connection_flow_controller_;
-
- // Special streams, such as the crypto and headers streams, do not respect
- // connection level flow control limits (but are stream level flow control
- // limited).
- bool stream_contributes_to_connection_flow_control_;
-
- DISALLOW_COPY_AND_ASSIGN(ReliableQuicStream);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_RELIABLE_QUIC_STREAM_H_
diff --git a/chromium/net/quic/reliable_quic_stream_test.cc b/chromium/net/quic/reliable_quic_stream_test.cc
deleted file mode 100644
index 6f07cbff914..00000000000
--- a/chromium/net/quic/reliable_quic_stream_test.cc
+++ /dev/null
@@ -1,723 +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/reliable_quic_stream.h"
-
-#include <memory>
-
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/quic_write_blocked_list.h"
-#include "net/quic/spdy_utils.h"
-#include "net/quic/test_tools/quic_config_peer.h"
-#include "net/quic/test_tools/quic_connection_peer.h"
-#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_test_utils.h"
-#include "net/quic/test_tools/reliable_quic_stream_peer.h"
-#include "net/test/gtest_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gmock_mutant.h"
-
-using base::StringPiece;
-using std::min;
-using std::string;
-using testing::AnyNumber;
-using testing::AtLeast;
-using testing::CreateFunctor;
-using testing::InSequence;
-using testing::Invoke;
-using testing::DoAll;
-using testing::Return;
-using testing::StrictMock;
-using testing::WithArgs;
-using testing::_;
-
-namespace net {
-namespace test {
-namespace {
-
-const char kData1[] = "FooAndBar";
-const char kData2[] = "EepAndBaz";
-const size_t kDataLen = 9;
-const bool kShouldProcessData = true;
-const bool kShouldNotProcessData = false;
-
-class TestStream : public ReliableQuicStream {
- public:
- TestStream(QuicStreamId id, QuicSession* session, bool should_process_data)
- : ReliableQuicStream(id, session),
- should_process_data_(should_process_data) {}
-
- void OnDataAvailable() override {}
-
- uint32_t ProcessRawData(const char* data, uint32_t data_len) {
- EXPECT_NE(0u, data_len);
- DVLOG(1) << "ProcessData data_len: " << data_len;
- data_ += string(data, data_len);
- return should_process_data_ ? data_len : 0;
- }
-
- using ReliableQuicStream::WriteOrBufferData;
- using ReliableQuicStream::CloseWriteSide;
- using ReliableQuicStream::OnClose;
-
- private:
- bool should_process_data_;
- string data_;
-};
-
-class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> {
- public:
- ReliableQuicStreamTest()
- : initial_flow_control_window_bytes_(kMaxPacketSize),
- zero_(QuicTime::Delta::Zero()),
- supported_versions_(QuicSupportedVersions()) {
- headers_[":host"] = "www.google.com";
- headers_[":path"] = "/index.hml";
- headers_[":scheme"] = "https";
- headers_["cookie"] =
- "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; "
- "__utmc=160408618; "
- "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX"
- "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX"
- "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT"
- "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0"
- "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh"
- "1zFMi5vzcns38-8_Sns; "
- "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-"
- "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339"
- "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c"
- "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%"
- "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4"
- "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1"
- "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP"
- "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6"
- "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b"
- "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6"
- "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG"
- "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk"
- "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn"
- "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
- "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
- }
-
- void Initialize(bool stream_should_process_data) {
- connection_ = new StrictMock<MockQuicConnection>(
- &helper_, &alarm_factory_, Perspective::IS_SERVER, supported_versions_);
- session_.reset(new StrictMock<MockQuicSession>(connection_));
-
- // New streams rely on having the peer's flow control receive window
- // negotiated in the config.
- QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(
- session_->config(), initial_flow_control_window_bytes_);
-
- stream_ = new TestStream(kTestStreamId, session_.get(),
- stream_should_process_data);
- // session_ now owns stream_.
- session_->ActivateStream(stream_);
- // Ignore resetting when session_ is terminated.
- EXPECT_CALL(*session_, SendRstStream(kTestStreamId, _, _))
- .Times(AnyNumber());
- write_blocked_list_ =
- QuicSessionPeer::GetWriteBlockedStreams(session_.get());
- write_blocked_list_->RegisterStream(kTestStreamId, kV3HighestPriority);
- }
-
- bool fin_sent() { return ReliableQuicStreamPeer::FinSent(stream_); }
- bool rst_sent() { return ReliableQuicStreamPeer::RstSent(stream_); }
-
- void set_initial_flow_control_window_bytes(uint32_t val) {
- initial_flow_control_window_bytes_ = val;
- }
-
- bool HasWriteBlockedStreams() {
- return write_blocked_list_->HasWriteBlockedCryptoOrHeadersStream() ||
- write_blocked_list_->HasWriteBlockedDataStreams();
- }
-
- QuicConsumedData CloseStreamOnWriteError(
- ReliableQuicStream* /*stream*/,
- QuicStreamId id,
- QuicIOVector /*iov*/,
- QuicStreamOffset /*offset*/,
- bool /*fin*/,
- QuicAckListenerInterface* /*ack_notifier_delegate*/) {
- session_->CloseStream(id);
- return QuicConsumedData(1, false);
- }
-
- protected:
- MockQuicConnectionHelper helper_;
- MockAlarmFactory alarm_factory_;
- MockQuicConnection* connection_;
- std::unique_ptr<MockQuicSession> session_;
- TestStream* stream_;
- SpdyHeaderBlock headers_;
- QuicWriteBlockedList* write_blocked_list_;
- uint32_t initial_flow_control_window_bytes_;
- QuicTime::Delta zero_;
- QuicVersionVector supported_versions_;
- const QuicStreamId kTestStreamId = 5u;
-};
-
-TEST_F(ReliableQuicStreamTest, WriteAllData) {
- Initialize(kShouldProcessData);
-
- size_t length =
- 1 + QuicPacketCreator::StreamFramePacketOverhead(
- connection_->version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId, !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER, 0u);
- connection_->SetMaxPacketLength(length);
-
- EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(kDataLen, true)));
- stream_->WriteOrBufferData(kData1, false, nullptr);
- EXPECT_FALSE(HasWriteBlockedStreams());
-}
-
-TEST_F(ReliableQuicStreamTest, NoBlockingIfNoDataOrFin) {
- Initialize(kShouldProcessData);
-
- // Write no data and no fin. If we consume nothing we should not be write
- // blocked.
- EXPECT_DFATAL(stream_->WriteOrBufferData(StringPiece(), false, nullptr), "");
- EXPECT_FALSE(HasWriteBlockedStreams());
-}
-
-TEST_F(ReliableQuicStreamTest, BlockIfOnlySomeDataConsumed) {
- Initialize(kShouldProcessData);
-
- // 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)));
- stream_->WriteOrBufferData(StringPiece(kData1, 2), false, nullptr);
- ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
- EXPECT_EQ(1u, stream_->queued_data_bytes());
-}
-
-TEST_F(ReliableQuicStreamTest, BlockIfFinNotConsumedWithData) {
- Initialize(kShouldProcessData);
-
- // Write some data and no fin. If we consume all the data but not the fin,
- // we should be write blocked because the fin was not consumed.
- // (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)));
- stream_->WriteOrBufferData(StringPiece(kData1, 2), true, nullptr);
- ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
-}
-
-TEST_F(ReliableQuicStreamTest, BlockIfSoloFinNotConsumed) {
- Initialize(kShouldProcessData);
-
- // Write no data and a fin. If we consume nothing we should be write blocked,
- // as the fin was not consumed.
- EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(0, false)));
- stream_->WriteOrBufferData(StringPiece(), true, nullptr);
- ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams());
-}
-
-TEST_F(ReliableQuicStreamTest, CloseOnPartialWrite) {
- Initialize(kShouldProcessData);
-
- // Write some data and no fin. However, while writing the data
- // close the stream and verify that MarkConnectionLevelWriteBlocked does not
- // crash with an unknown stream.
- EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
- .WillOnce(Invoke(this, &ReliableQuicStreamTest::CloseStreamOnWriteError));
- stream_->WriteOrBufferData(StringPiece(kData1, 2), false, nullptr);
- ASSERT_EQ(0u, write_blocked_list_->NumBlockedStreams());
-}
-
-TEST_F(ReliableQuicStreamTest, WriteOrBufferData) {
- Initialize(kShouldProcessData);
-
- EXPECT_FALSE(HasWriteBlockedStreams());
- size_t length =
- 1 + QuicPacketCreator::StreamFramePacketOverhead(
- connection_->version(), PACKET_8BYTE_CONNECTION_ID,
- !kIncludeVersion, !kIncludePathId, !kIncludeDiversificationNonce,
- PACKET_6BYTE_PACKET_NUMBER, 0u);
- connection_->SetMaxPacketLength(length);
-
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(kDataLen - 1, false)));
- stream_->WriteOrBufferData(kData1, false, nullptr);
- EXPECT_TRUE(HasWriteBlockedStreams());
-
- // Queue a bytes_consumed write.
- stream_->WriteOrBufferData(kData2, false, nullptr);
-
- // Make sure we get the tail of the first write followed by the bytes_consumed
- InSequence s;
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(1, false)));
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(kDataLen - 2, false)));
- stream_->OnCanWrite();
-
- // And finally the end of the bytes_consumed.
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(2, true)));
- stream_->OnCanWrite();
-}
-
-TEST_F(ReliableQuicStreamTest, ConnectionCloseAfterStreamClose) {
- Initialize(kShouldProcessData);
-
- ReliableQuicStreamPeer::CloseReadSide(stream_);
- stream_->CloseWriteSide();
- EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error());
- EXPECT_EQ(QUIC_NO_ERROR, stream_->connection_error());
- stream_->OnConnectionClosed(QUIC_INTERNAL_ERROR,
- ConnectionCloseSource::FROM_SELF);
- EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error());
- EXPECT_EQ(QUIC_NO_ERROR, stream_->connection_error());
-}
-
-TEST_F(ReliableQuicStreamTest, RstAlwaysSentIfNoFinSent) {
- // For flow control accounting, a stream must send either a FIN or a RST frame
- // before termination.
- // Test that if no FIN has been sent, we send a RST.
-
- Initialize(kShouldProcessData);
- EXPECT_FALSE(fin_sent());
- EXPECT_FALSE(rst_sent());
-
- // Write some data, with no FIN.
- EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(1, false)));
- stream_->WriteOrBufferData(StringPiece(kData1, 1), false, nullptr);
- EXPECT_FALSE(fin_sent());
- EXPECT_FALSE(rst_sent());
-
- // Now close the stream, and expect that we send a RST.
- EXPECT_CALL(*session_, SendRstStream(_, _, _));
- stream_->OnClose();
- EXPECT_FALSE(fin_sent());
- EXPECT_TRUE(rst_sent());
-}
-
-TEST_F(ReliableQuicStreamTest, RstNotSentIfFinSent) {
- // For flow control accounting, a stream must send either a FIN or a RST frame
- // before termination.
- // Test that if a FIN has been sent, we don't also send a RST.
-
- Initialize(kShouldProcessData);
- EXPECT_FALSE(fin_sent());
- EXPECT_FALSE(rst_sent());
-
- // Write some data, with FIN.
- EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(1, true)));
- stream_->WriteOrBufferData(StringPiece(kData1, 1), true, nullptr);
- EXPECT_TRUE(fin_sent());
- EXPECT_FALSE(rst_sent());
-
- // Now close the stream, and expect that we do not send a RST.
- stream_->OnClose();
- EXPECT_TRUE(fin_sent());
- EXPECT_FALSE(rst_sent());
-}
-
-TEST_F(ReliableQuicStreamTest, OnlySendOneRst) {
- // For flow control accounting, a stream must send either a FIN or a RST frame
- // before termination.
- // Test that if a stream sends a RST, it doesn't send an additional RST during
- // OnClose() (this shouldn't be harmful, but we shouldn't do it anyway...)
-
- Initialize(kShouldProcessData);
- EXPECT_FALSE(fin_sent());
- EXPECT_FALSE(rst_sent());
-
- // Reset the stream.
- const int expected_resets = 1;
- EXPECT_CALL(*session_, SendRstStream(_, _, _)).Times(expected_resets);
- stream_->Reset(QUIC_STREAM_CANCELLED);
- EXPECT_FALSE(fin_sent());
- EXPECT_TRUE(rst_sent());
-
- // Now close the stream (any further resets being sent would break the
- // expectation above).
- stream_->OnClose();
- EXPECT_FALSE(fin_sent());
- EXPECT_TRUE(rst_sent());
-}
-
-TEST_F(ReliableQuicStreamTest, StreamFlowControlMultipleWindowUpdates) {
- set_initial_flow_control_window_bytes(1000);
-
- Initialize(kShouldProcessData);
-
- // If we receive multiple WINDOW_UPDATES (potentially out of order), then we
- // want to make sure we latch the largest offset we see.
-
- // Initially should be default.
- EXPECT_EQ(
- initial_flow_control_window_bytes_,
- QuicFlowControllerPeer::SendWindowOffset(stream_->flow_controller()));
-
- // Check a single WINDOW_UPDATE results in correct offset.
- QuicWindowUpdateFrame window_update_1(stream_->id(), 1234);
- stream_->OnWindowUpdateFrame(window_update_1);
- EXPECT_EQ(
- window_update_1.byte_offset,
- QuicFlowControllerPeer::SendWindowOffset(stream_->flow_controller()));
-
- // Now send a few more WINDOW_UPDATES and make sure that only the largest is
- // remembered.
- QuicWindowUpdateFrame window_update_2(stream_->id(), 1);
- QuicWindowUpdateFrame window_update_3(stream_->id(), 9999);
- QuicWindowUpdateFrame window_update_4(stream_->id(), 5678);
- stream_->OnWindowUpdateFrame(window_update_2);
- stream_->OnWindowUpdateFrame(window_update_3);
- stream_->OnWindowUpdateFrame(window_update_4);
- EXPECT_EQ(
- window_update_3.byte_offset,
- QuicFlowControllerPeer::SendWindowOffset(stream_->flow_controller()));
-}
-
-// TODO(ianswett): It's not clear this method is still needed now that
-// ProxyAckNotifierDelegate has been removed.
-void SaveAckListener(scoped_refptr<QuicAckListenerInterface>* listener_out,
- QuicAckListenerInterface* listener) {
- *listener_out = (listener);
-}
-
-TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithQuicAckNotifier) {
- Initialize(kShouldProcessData);
-
- scoped_refptr<MockAckListener> delegate(new StrictMock<MockAckListener>);
-
- const int kDataSize = 16 * 1024;
- const string kData(kDataSize, 'a');
-
- const int kFirstWriteSize = 100;
- const int kSecondWriteSize = 50;
- const int kLastWriteSize = kDataSize - kFirstWriteSize - kSecondWriteSize;
-
- // Set a large flow control send window so this doesn't interfere with test.
- stream_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
- session_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
-
- scoped_refptr<QuicAckListenerInterface> ack_listener;
-
- EXPECT_CALL(*session_, WritevData(_, kTestStreamId, _, _, _, _))
- .WillOnce(DoAll(
- WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &ack_listener))),
- Return(QuicConsumedData(kFirstWriteSize, false))));
- stream_->WriteOrBufferData(kData, false, delegate.get());
- EXPECT_TRUE(HasWriteBlockedStreams());
-
- EXPECT_CALL(*session_,
- WritevData(stream_, kTestStreamId, _, _, _, ack_listener.get()))
- .WillOnce(Return(QuicConsumedData(kSecondWriteSize, false)));
- stream_->OnCanWrite();
-
- // No ack expected for an empty write.
- EXPECT_CALL(*session_,
- WritevData(stream_, kTestStreamId, _, _, _, ack_listener.get()))
- .WillOnce(Return(QuicConsumedData(0, false)));
- stream_->OnCanWrite();
-
- EXPECT_CALL(*session_,
- WritevData(stream_, kTestStreamId, _, _, _, ack_listener.get()))
- .WillOnce(Return(QuicConsumedData(kLastWriteSize, false)));
- stream_->OnCanWrite();
-}
-
-// Verify delegate behavior when packets are acked before the WritevData call
-// that sends out the last byte.
-TEST_F(ReliableQuicStreamTest, WriteOrBufferDataAckNotificationBeforeFlush) {
- Initialize(kShouldProcessData);
-
- scoped_refptr<MockAckListener> ack_listener(new StrictMock<MockAckListener>);
-
- const int kDataSize = 16 * 1024;
- const string kData(kDataSize, 'a');
-
- const int kInitialWriteSize = 100;
-
- // Set a large flow control send window so this doesn't interfere with test.
- stream_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
- session_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
-
- scoped_refptr<QuicAckListenerInterface> proxy_delegate;
-
- EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
- .WillOnce(DoAll(
- WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))),
- Return(QuicConsumedData(kInitialWriteSize, false))));
- stream_->WriteOrBufferData(kData, false, ack_listener.get());
- EXPECT_TRUE(HasWriteBlockedStreams());
-
- EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
- .WillOnce(DoAll(
- WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))),
- Return(QuicConsumedData(kDataSize - kInitialWriteSize, false))));
- stream_->OnCanWrite();
-}
-
-// Verify delegate behavior when WriteOrBufferData does not buffer.
-TEST_F(ReliableQuicStreamTest, WriteAndBufferDataWithAckNotiferNoBuffer) {
- Initialize(kShouldProcessData);
-
- scoped_refptr<MockAckListener> delegate(new StrictMock<MockAckListener>);
-
- scoped_refptr<QuicAckListenerInterface> proxy_delegate;
-
- EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
- .WillOnce(DoAll(
- WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))),
- Return(QuicConsumedData(kDataLen, true))));
- stream_->WriteOrBufferData(kData1, true, delegate.get());
- EXPECT_FALSE(HasWriteBlockedStreams());
-}
-
-// Verify delegate behavior when WriteOrBufferData buffers all the data.
-TEST_F(ReliableQuicStreamTest, BufferOnWriteAndBufferDataWithAckNotifer) {
- Initialize(kShouldProcessData);
-
- scoped_refptr<MockAckListener> delegate(new StrictMock<MockAckListener>);
-
- scoped_refptr<QuicAckListenerInterface> proxy_delegate;
-
- EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(0, false)));
- stream_->WriteOrBufferData(kData1, true, delegate.get());
- EXPECT_TRUE(HasWriteBlockedStreams());
-
- EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
- .WillOnce(DoAll(
- WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))),
- Return(QuicConsumedData(kDataLen, true))));
- stream_->OnCanWrite();
-}
-
-// Verify delegate behavior when WriteOrBufferData when the FIN is
-// sent out in a different packet.
-TEST_F(ReliableQuicStreamTest, WriteAndBufferDataWithAckNotiferOnlyFinRemains) {
- Initialize(kShouldProcessData);
-
- scoped_refptr<MockAckListener> delegate(new StrictMock<MockAckListener>);
-
- scoped_refptr<QuicAckListenerInterface> proxy_delegate;
-
- EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
- .WillOnce(DoAll(
- WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))),
- Return(QuicConsumedData(kDataLen, false))));
- stream_->WriteOrBufferData(kData1, true, delegate.get());
- EXPECT_TRUE(HasWriteBlockedStreams());
-
- EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
- .WillOnce(DoAll(
- WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))),
- Return(QuicConsumedData(0, true))));
- stream_->OnCanWrite();
-}
-
-// Verify that when we receive a packet which violates flow control (i.e. sends
-// too much data on the stream) that the stream sequencer never sees this frame,
-// as we check for violation and close the connection early.
-TEST_F(ReliableQuicStreamTest,
- StreamSequencerNeverSeesPacketsViolatingFlowControl) {
- Initialize(kShouldProcessData);
-
- // Receive a stream frame that violates flow control: the byte offset is
- // higher than the receive window offset.
- QuicStreamFrame frame(stream_->id(), false,
- kInitialSessionFlowControlWindowForTest + 1,
- StringPiece("."));
- EXPECT_GT(frame.offset, QuicFlowControllerPeer::ReceiveWindowOffset(
- stream_->flow_controller()));
-
- // Stream should not accept the frame, and the connection should be closed.
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _));
- stream_->OnStreamFrame(frame);
-}
-
-// Verify that after the consumer calls StopReading(), the stream still sends
-// flow control updates.
-TEST_F(ReliableQuicStreamTest, StopReadingSendsFlowControl) {
- Initialize(kShouldProcessData);
-
- stream_->StopReading();
-
- // Connection should not get terminated due to flow control errors.
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _))
- .Times(0);
- EXPECT_CALL(*connection_, SendWindowUpdate(_, _)).Times(AtLeast(1));
-
- string data(1000, 'x');
- for (QuicStreamOffset offset = 0;
- offset < 2 * kInitialStreamFlowControlWindowForTest;
- offset += data.length()) {
- QuicStreamFrame frame(stream_->id(), false, offset, data);
- stream_->OnStreamFrame(frame);
- }
- EXPECT_LT(
- kInitialStreamFlowControlWindowForTest,
- QuicFlowControllerPeer::ReceiveWindowOffset(stream_->flow_controller()));
-}
-
-TEST_F(ReliableQuicStreamTest, FinalByteOffsetFromFin) {
- Initialize(kShouldProcessData);
-
- EXPECT_FALSE(stream_->HasFinalReceivedByteOffset());
-
- QuicStreamFrame stream_frame_no_fin(stream_->id(), false, 1234,
- StringPiece("."));
- stream_->OnStreamFrame(stream_frame_no_fin);
- EXPECT_FALSE(stream_->HasFinalReceivedByteOffset());
-
- QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234,
- StringPiece("."));
- stream_->OnStreamFrame(stream_frame_with_fin);
- EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
-}
-
-TEST_F(ReliableQuicStreamTest, FinalByteOffsetFromRst) {
- Initialize(kShouldProcessData);
-
- EXPECT_FALSE(stream_->HasFinalReceivedByteOffset());
- QuicRstStreamFrame rst_frame(stream_->id(), QUIC_STREAM_CANCELLED, 1234);
- stream_->OnStreamReset(rst_frame);
- EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
-}
-
-TEST_F(ReliableQuicStreamTest, FinalByteOffsetFromZeroLengthStreamFrame) {
- // When receiving Trailers, an empty stream frame is created with the FIN set,
- // and is passed to OnStreamFrame. The Trailers may be sent in advance of
- // queued body bytes being sent, and thus the final byte offset may exceed
- // current flow control limits. Flow control should only be concerned with
- // data that has actually been sent/received, so verify that flow control
- // ignores such a stream frame.
- Initialize(kShouldProcessData);
-
- EXPECT_FALSE(stream_->HasFinalReceivedByteOffset());
- const QuicStreamOffset kByteOffsetExceedingFlowControlWindow =
- kInitialSessionFlowControlWindowForTest + 1;
- const QuicStreamOffset current_stream_flow_control_offset =
- QuicFlowControllerPeer::ReceiveWindowOffset(stream_->flow_controller());
- const QuicStreamOffset current_connection_flow_control_offset =
- QuicFlowControllerPeer::ReceiveWindowOffset(session_->flow_controller());
- ASSERT_GT(kByteOffsetExceedingFlowControlWindow,
- current_stream_flow_control_offset);
- ASSERT_GT(kByteOffsetExceedingFlowControlWindow,
- current_connection_flow_control_offset);
- QuicStreamFrame zero_length_stream_frame_with_fin(
- stream_->id(), /*fin=*/true, kByteOffsetExceedingFlowControlWindow,
- StringPiece());
- EXPECT_EQ(0, zero_length_stream_frame_with_fin.data_length);
-
- if (FLAGS_quic_ignore_zero_length_frames) {
- EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
- } else {
- EXPECT_CALL(*connection_,
- CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _))
- .Times(1);
- }
- stream_->OnStreamFrame(zero_length_stream_frame_with_fin);
- EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
-
- if (FLAGS_quic_ignore_zero_length_frames) {
- // The flow control receive offset values should not have changed.
- EXPECT_EQ(current_stream_flow_control_offset,
- QuicFlowControllerPeer::ReceiveWindowOffset(
- stream_->flow_controller()));
- EXPECT_EQ(current_connection_flow_control_offset,
- QuicFlowControllerPeer::ReceiveWindowOffset(
- session_->flow_controller()));
- }
-}
-
-TEST_F(ReliableQuicStreamTest, SetDrainingIncomingOutgoing) {
- // Don't have incoming data consumed.
- Initialize(kShouldNotProcessData);
-
- // Incoming data with FIN.
- QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234,
- StringPiece("."));
- stream_->OnStreamFrame(stream_frame_with_fin);
- // The FIN has been received but not consumed.
- EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
- EXPECT_FALSE(ReliableQuicStreamPeer::read_side_closed(stream_));
- EXPECT_FALSE(stream_->reading_stopped());
-
- EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
-
- // Outgoing data with FIN.
- EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(2, true)));
- stream_->WriteOrBufferData(StringPiece(kData1, 2), true, nullptr);
- EXPECT_TRUE(stream_->write_side_closed());
-
- EXPECT_EQ(1u, QuicSessionPeer::GetDrainingStreams(session_.get())
- ->count(kTestStreamId));
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
-}
-
-TEST_F(ReliableQuicStreamTest, SetDrainingOutgoingIncoming) {
- // Don't have incoming data consumed.
- Initialize(kShouldNotProcessData);
-
- // Outgoing data with FIN.
- EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _, _))
- .WillOnce(Return(QuicConsumedData(2, true)));
- stream_->WriteOrBufferData(StringPiece(kData1, 2), true, nullptr);
- EXPECT_TRUE(stream_->write_side_closed());
-
- EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
-
- // Incoming data with FIN.
- QuicStreamFrame stream_frame_with_fin(stream_->id(), true, 1234,
- StringPiece("."));
- stream_->OnStreamFrame(stream_frame_with_fin);
- // The FIN has been received but not consumed.
- EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
- EXPECT_FALSE(ReliableQuicStreamPeer::read_side_closed(stream_));
- EXPECT_FALSE(stream_->reading_stopped());
-
- EXPECT_EQ(1u, QuicSessionPeer::GetDrainingStreams(session_.get())
- ->count(kTestStreamId));
- EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
-}
-
-TEST_F(ReliableQuicStreamTest, EarlyResponseFinHandling) {
- // Verify that if the server completes the response before reading the end of
- // the request, the received FIN is recorded.
-
- Initialize(kShouldProcessData);
- EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
- EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
- .WillRepeatedly(Invoke(MockQuicSession::ConsumeAllData));
-
- // Receive data for the request.
- QuicStreamFrame frame1(stream_->id(), false, 0, StringPiece("Start"));
- stream_->OnStreamFrame(frame1);
- // When QuicSimpleServerStream sends the response, it calls
- // ReliableQuicStream::CloseReadSide() first.
- ReliableQuicStreamPeer::CloseReadSide(stream_);
- // Send data and FIN for the response.
- stream_->WriteOrBufferData(kData1, false, nullptr);
- EXPECT_TRUE(ReliableQuicStreamPeer::read_side_closed(stream_));
- // Receive remaining data and FIN for the request.
- QuicStreamFrame frame2(stream_->id(), true, 0, StringPiece("End"));
- stream_->OnStreamFrame(frame2);
- EXPECT_TRUE(stream_->fin_received());
- EXPECT_TRUE(stream_->HasFinalReceivedByteOffset());
-}
-
-} // namespace
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/spdy_utils.cc b/chromium/net/quic/spdy_utils.cc
deleted file mode 100644
index 0b74cb6f69d..00000000000
--- a/chromium/net/quic/spdy_utils.cc
+++ /dev/null
@@ -1,253 +0,0 @@
-// Copyright (c) 2013 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/spdy_utils.h"
-
-#include <memory>
-#include <vector>
-
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "net/spdy/spdy_frame_builder.h"
-#include "net/spdy/spdy_framer.h"
-#include "net/spdy/spdy_protocol.h"
-#include "url/gurl.h"
-
-using base::StringPiece;
-using std::string;
-using std::vector;
-
-namespace net {
-
-// static
-string SpdyUtils::SerializeUncompressedHeaders(const SpdyHeaderBlock& headers) {
- SpdyMajorVersion spdy_version = HTTP2;
-
- size_t length = SpdyFramer::GetSerializedLength(spdy_version, &headers);
- SpdyFrameBuilder builder(length, spdy_version);
- SpdyFramer framer(spdy_version);
- framer.SerializeHeaderBlockWithoutCompression(&builder, headers);
- SpdySerializedFrame block(builder.take());
- return string(block.data(), length);
-}
-
-// static
-bool SpdyUtils::ParseHeaders(const char* data,
- uint32_t data_len,
- int64_t* content_length,
- SpdyHeaderBlock* headers) {
- SpdyFramer framer(HTTP2);
- if (!framer.ParseHeaderBlockInBuffer(data, data_len, headers) ||
- headers->empty()) {
- return false; // Headers were invalid.
- }
-
- if (ContainsKey(*headers, "content-length")) {
- // Check whether multiple values are consistent.
- base::StringPiece content_length_header = (*headers)["content-length"];
- vector<string> values =
- base::SplitString(content_length_header, base::StringPiece("\0", 1),
- base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- for (const string& value : values) {
- int64_t new_value;
- if (!base::StringToInt64(value, &new_value) || new_value < 0) {
- return false;
- }
- if (*content_length < 0) {
- *content_length = new_value;
- continue;
- }
- if (new_value != *content_length) {
- return false;
- }
- }
- }
-
- return true;
-}
-
-// static
-bool SpdyUtils::ParseTrailers(const char* data,
- uint32_t data_len,
- size_t* final_byte_offset,
- SpdyHeaderBlock* trailers) {
- SpdyFramer framer(HTTP2);
- if (!framer.ParseHeaderBlockInBuffer(data, data_len, trailers) ||
- trailers->empty()) {
- DVLOG(1) << "Request Trailers are invalid.";
- return false; // Trailers were invalid.
- }
-
- // Pull out the final offset pseudo header which indicates the number of
- // response body bytes expected.
- auto it = trailers->find(kFinalOffsetHeaderKey);
- if (it == trailers->end() ||
- !base::StringToSizeT(it->second, final_byte_offset)) {
- DVLOG(1) << "Required key '" << kFinalOffsetHeaderKey << "' not present";
- return false;
- }
- // The final offset header is no longer needed.
- trailers->erase(it->first);
-
- // Trailers must not have empty keys, and must not contain pseudo headers.
- for (const auto& trailer : *trailers) {
- base::StringPiece key = trailer.first;
- base::StringPiece value = trailer.second;
- if (key.starts_with(":")) {
- DVLOG(1) << "Trailers must not contain pseudo-header: '" << key << "','"
- << value << "'.";
- return false;
- }
-
- // TODO(rjshade): Check for other forbidden keys, following the HTTP/2 spec.
- }
-
- DVLOG(1) << "Successfully parsed Trailers.";
- return true;
-}
-
-bool SpdyUtils::CopyAndValidateHeaders(const QuicHeaderList& header_list,
- int64_t* content_length,
- SpdyHeaderBlock* headers) {
- for (const auto& p : header_list) {
- const string& name = p.first;
- if (name.empty()) {
- DVLOG(1) << "Header name must not be empty.";
- return false;
- }
-
- auto iter = headers->find(name);
- if (iter == headers->end()) {
- (*headers)[name] = p.second;
- } else {
- // This header had multiple values, so it must be reconstructed.
- StringPiece v = iter->second;
- string s(v.data(), v.length());
- if (name == "cookie") {
- // Obeys section 8.1.2.5 in RFC 7540 for cookie reconstruction.
- s.append("; ");
- } else {
- StringPiece("\0", 1).AppendToString(&s);
- }
- s.append(p.second);
- headers->ReplaceOrAppendHeader(name, s);
- }
- }
-
- if (ContainsKey(*headers, "content-length")) {
- // Check whether multiple values are consistent.
- StringPiece content_length_header = (*headers)["content-length"];
- vector<string> values =
- base::SplitString(content_length_header, base::StringPiece("\0", 1),
- base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- for (const string& value : values) {
- int64_t new_value;
- if (!base::StringToInt64(value, &new_value) || new_value < 0) {
- DLOG(ERROR) << "Content length was either unparseable or negative.";
- return false;
- }
- if (*content_length < 0) {
- *content_length = new_value;
- continue;
- }
- if (new_value != *content_length) {
- DLOG(ERROR) << "Parsed content length " << new_value << " is "
- << "inconsistent with previously detected content length "
- << *content_length;
- return false;
- }
- }
- }
-
- DVLOG(1) << "Successfully parsed headers: " << headers->DebugString();
- return true;
-}
-
-bool SpdyUtils::CopyAndValidateTrailers(const QuicHeaderList& header_list,
- size_t* final_byte_offset,
- SpdyHeaderBlock* trailers) {
- bool found_final_byte_offset = false;
- for (const auto& p : header_list) {
- const string& name = p.first;
-
- // Pull out the final offset pseudo header which indicates the number of
- // response body bytes expected.
- int offset;
- if (!found_final_byte_offset && name == kFinalOffsetHeaderKey &&
- base::StringToInt(p.second, &offset)) {
- *final_byte_offset = offset;
- found_final_byte_offset = true;
- continue;
- }
-
- if (name.empty() || name[0] == ':') {
- DVLOG(1) << "Trailers must not be empty, and must not contain pseudo-"
- << "headers. Found: '" << name << "'";
- return false;
- }
-
- if (std::any_of(name.begin(), name.end(), base::IsAsciiUpper<char>)) {
- DVLOG(1) << "Malformed header: Header name " << name
- << " contains upper-case characters.";
- return false;
- }
-
- if (trailers->find(name) != trailers->end()) {
- DVLOG(1) << "Duplicate header '" << name << "' found in trailers.";
- return false;
- }
-
- (*trailers)[name] = p.second;
- }
-
- if (!found_final_byte_offset) {
- DVLOG(1) << "Required key '" << kFinalOffsetHeaderKey << "' not present";
- return false;
- }
-
- // TODO(rjshade): Check for other forbidden keys, following the HTTP/2 spec.
-
- DVLOG(1) << "Successfully parsed Trailers: " << trailers->DebugString();
- return true;
-}
-
-// static
-string SpdyUtils::GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers) {
- SpdyHeaderBlock::const_iterator it = headers.find(":scheme");
- if (it == headers.end()) {
- return "";
- }
- std::string url = it->second.as_string();
-
- url.append("://");
-
- it = headers.find(":authority");
- if (it == headers.end()) {
- return "";
- }
- url.append(it->second.as_string());
-
- it = headers.find(":path");
- if (it == headers.end()) {
- return "";
- }
- url.append(it->second.as_string());
- return url;
-}
-
-// static
-string SpdyUtils::GetHostNameFromHeaderBlock(const SpdyHeaderBlock& headers) {
- return GURL(GetUrlFromHeaderBlock(headers)).host();
-}
-
-// static
-bool SpdyUtils::UrlIsValid(const SpdyHeaderBlock& headers) {
- string url(GetUrlFromHeaderBlock(headers));
- return url != "" && GURL(url).is_valid();
-}
-
-} // namespace net
diff --git a/chromium/net/quic/spdy_utils.h b/chromium/net/quic/spdy_utils.h
deleted file mode 100644
index 6a9b15e375e..00000000000
--- a/chromium/net/quic/spdy_utils.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (c) 2013 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_SPDY_UTILS_H_
-#define NET_QUIC_SPDY_UTILS_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <map>
-#include <string>
-
-#include "base/macros.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_header_list.h"
-#include "net/quic/quic_protocol.h"
-#include "net/spdy/spdy_framer.h"
-
-namespace net {
-
-class NET_EXPORT_PRIVATE SpdyUtils {
- public:
- static std::string SerializeUncompressedHeaders(
- const SpdyHeaderBlock& headers);
-
- // Parses |data| as a std::string containing serialized HTTP/2 HEADERS frame,
- // populating |headers| with the key->value std:pairs found.
- // |content_length| will be populated with the value of the content-length
- // header if one or more are present.
- // Returns true on success, false if parsing fails, or invalid keys are found.
- static bool ParseHeaders(const char* data,
- uint32_t data_len,
- int64_t* content_length,
- SpdyHeaderBlock* headers);
-
- // Parses |data| as a std::string containing serialized HTTP/2 HEADERS frame,
- // populating |trailers| with the key->value std:pairs found.
- // The final offset header will be excluded from |trailers|, and instead the
- // value will be copied to |final_byte_offset|.
- // Returns true on success, false if parsing fails, or invalid keys are found.
- static bool ParseTrailers(const char* data,
- uint32_t data_len,
- size_t* final_byte_offset,
- SpdyHeaderBlock* trailers);
-
- // Copies a list of headers to a SpdyHeaderBlock. Performs similar validation
- // to SpdyFramer::ParseHeaderBlockInBuffer and ParseHeaders, above.
- static bool CopyAndValidateHeaders(const QuicHeaderList& header_list,
- int64_t* content_length,
- SpdyHeaderBlock* headers);
-
- // Copies a list of headers to a SpdyHeaderBlock. Performs similar validation
- // to SpdyFramer::ParseHeaderBlockInBuffer and ParseTrailers, above.
- static bool CopyAndValidateTrailers(const QuicHeaderList& header_list,
- size_t* final_byte_offset,
- SpdyHeaderBlock* trailers);
-
- // Returns URL composed from scheme, authority, and path header
- // values, or empty string if any of those fields are missing.
- static std::string GetUrlFromHeaderBlock(const net::SpdyHeaderBlock& headers);
-
- // Returns hostname, or empty std::string if missing.
- static std::string GetHostNameFromHeaderBlock(const SpdyHeaderBlock& headers);
-
- // Returns true if result of |GetUrlFromHeaderBlock()| is non-empty
- // and is a well-formed URL.
- static bool UrlIsValid(const net::SpdyHeaderBlock& headers);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SpdyUtils);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_SPDY_UTILS_H_
diff --git a/chromium/net/quic/spdy_utils_test.cc b/chromium/net/quic/spdy_utils_test.cc
deleted file mode 100644
index 35093af511a..00000000000
--- a/chromium/net/quic/spdy_utils_test.cc
+++ /dev/null
@@ -1,359 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-#include "net/quic/spdy_utils.h"
-
-#include "base/macros.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
-#include "net/test/gtest_util.h"
-
-using base::StringPiece;
-using std::string;
-using testing::UnorderedElementsAre;
-using testing::Pair;
-
-namespace net {
-namespace test {
-
-TEST(SpdyUtilsTest, SerializeAndParseHeaders) {
- // Creates a SpdyHeaderBlock with some key->value pairs, serializes it, then
- // parses the serialized output and verifies that the end result is the same
- // as the headers that the test started with.
-
- SpdyHeaderBlock input_headers;
- input_headers[":pseudo1"] = "pseudo value1";
- input_headers[":pseudo2"] = "pseudo value2";
- input_headers["key1"] = "value1";
- const int64_t kContentLength = 1234;
- input_headers["content-length"] = base::Int64ToString(kContentLength);
- input_headers["key2"] = "value2";
-
- // Serialize the header block.
- string serialized_headers =
- SpdyUtils::SerializeUncompressedHeaders(input_headers);
-
- // Take the serialized header block, and parse back into SpdyHeaderBlock.
- SpdyHeaderBlock output_headers;
- int64_t content_length = -1;
- ASSERT_TRUE(SpdyUtils::ParseHeaders(serialized_headers.data(),
- serialized_headers.size(),
- &content_length, &output_headers));
-
- // Should be back to the original headers.
- EXPECT_EQ(content_length, kContentLength);
- EXPECT_EQ(output_headers, input_headers);
-}
-
-TEST(SpdyUtilsTest, SerializeAndParseHeadersLargeContentLength) {
- // Creates a SpdyHeaderBlock with some key->value pairs, serializes it, then
- // parses the serialized output and verifies that the end result is the same
- // as the headers that the test started with.
-
- SpdyHeaderBlock input_headers;
- input_headers[":pseudo1"] = "pseudo value1";
- input_headers[":pseudo2"] = "pseudo value2";
- input_headers["key1"] = "value1";
- const int64_t kContentLength = 12345678900;
- input_headers["content-length"] = base::Int64ToString(kContentLength);
- input_headers["key2"] = "value2";
-
- // Serialize the header block.
- string serialized_headers =
- SpdyUtils::SerializeUncompressedHeaders(input_headers);
-
- // Take the serialized header block, and parse back into SpdyHeaderBlock.
- SpdyHeaderBlock output_headers;
- int64_t content_length = -1;
- ASSERT_TRUE(SpdyUtils::ParseHeaders(serialized_headers.data(),
- serialized_headers.size(),
- &content_length, &output_headers));
-
- // Should be back to the original headers.
- EXPECT_EQ(content_length, kContentLength);
- EXPECT_EQ(output_headers, input_headers);
-}
-
-TEST(SpdyUtilsTest, SerializeAndParseValidTrailers) {
- // Creates a SpdyHeaderBlock with some valid Trailers key->value pairs,
- // serializes it, then parses the serialized output and verifies that the end
- // result is the same as the trailers that the test started with.
- SpdyHeaderBlock input_trailers;
- const size_t kFinalOffset = 5678;
- input_trailers[kFinalOffsetHeaderKey] = base::IntToString(kFinalOffset);
- input_trailers["key1"] = "value1";
- input_trailers["key2"] = "value2";
-
- // Serialize the trailers.
- string serialized_trailers =
- SpdyUtils::SerializeUncompressedHeaders(input_trailers);
-
- // Take the serialized trailers, and parse back into a SpdyHeaderBlock.
- SpdyHeaderBlock output_trailers;
- size_t final_byte_offset = 0;
- EXPECT_TRUE(SpdyUtils::ParseTrailers(serialized_trailers.data(),
- serialized_trailers.size(),
- &final_byte_offset, &output_trailers));
-
- // Should be back to the original trailers, without the final offset header.
- EXPECT_EQ(final_byte_offset, kFinalOffset);
- input_trailers.erase(kFinalOffsetHeaderKey);
- EXPECT_EQ(output_trailers, input_trailers);
-}
-
-TEST(SpdyUtilsTest, SerializeAndParseTrailersWithoutFinalOffset) {
- // Verifies that parsing fails if Trailers are missing a final offset header.
-
- SpdyHeaderBlock input_trailers;
- input_trailers["key1"] = "value1";
- input_trailers["key2"] = "value2";
-
- // Serialize the trailers.
- string serialized_trailers =
- SpdyUtils::SerializeUncompressedHeaders(input_trailers);
-
- // Parsing the serialized trailers fails because of the missing final offset.
- SpdyHeaderBlock output_trailers;
- size_t final_byte_offset = 0;
- EXPECT_FALSE(SpdyUtils::ParseTrailers(serialized_trailers.data(),
- serialized_trailers.size(),
- &final_byte_offset, &output_trailers));
- EXPECT_EQ(final_byte_offset, 0u);
-}
-
-TEST(SpdyUtilsTest, SerializeAndParseTrailersWithPseudoHeaders) {
- // Verifies that parsing fails if Trailers include pseudo-headers.
-
- SpdyHeaderBlock input_trailers;
- input_trailers[kFinalOffsetHeaderKey] = "12345";
- input_trailers[":disallowed-pseudo-header"] = "pseudo value";
- input_trailers["key1"] = "value1";
- input_trailers["key2"] = "value2";
-
- // Serialize the trailers.
- string serialized_trailers =
- SpdyUtils::SerializeUncompressedHeaders(input_trailers);
-
- // Parsing the serialized trailers fails because of the extra pseudo header.
- SpdyHeaderBlock output_trailers;
- size_t final_byte_offset = 0;
- EXPECT_FALSE(SpdyUtils::ParseTrailers(serialized_trailers.data(),
- serialized_trailers.size(),
- &final_byte_offset, &output_trailers));
-}
-static std::unique_ptr<QuicHeaderList> FromList(
- const QuicHeaderList::ListType& src) {
- std::unique_ptr<QuicHeaderList> headers(new QuicHeaderList);
- headers->OnHeaderBlockStart();
- for (const auto& p : src) {
- headers->OnHeader(p.first, p.second);
- }
- headers->OnHeaderBlockEnd(0);
- return headers;
-}
-
-TEST(SpdyUtilsTest, CopyAndValidateHeaders) {
- auto headers = FromList({// All cookie crumbs are joined.
- {"cookie", " part 1"},
- {"cookie", "part 2 "},
- {"cookie", "part3"},
-
- // Already-delimited headers are passed through.
- {"passed-through", string("foo\0baz", 7)},
-
- // Other headers are joined on \0.
- {"joined", "value 1"},
- {"joined", "value 2"},
-
- // Empty headers remain empty.
- {"empty", ""},
-
- // Joined empty headers work as expected.
- {"empty-joined", ""},
- {"empty-joined", "foo"},
- {"empty-joined", ""},
- {"empty-joined", ""},
-
- // Non-continguous cookie crumb.
- {"cookie", " fin!"}});
-
- int64_t content_length = -1;
- SpdyHeaderBlock block;
- ASSERT_TRUE(
- SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
- EXPECT_THAT(block, UnorderedElementsAre(
- Pair("cookie", " part 1; part 2 ; part3; fin!"),
- Pair("passed-through", StringPiece("foo\0baz", 7)),
- Pair("joined", StringPiece("value 1\0value 2", 15)),
- Pair("empty", ""),
- Pair("empty-joined", StringPiece("\0foo\0\0", 6))));
- EXPECT_EQ(-1, content_length);
-}
-
-TEST(SpdyUtilsTest, CopyAndValidateHeadersEmptyName) {
- auto headers = FromList({{"foo", "foovalue"}, {"", "barvalue"}, {"baz", ""}});
- int64_t content_length = -1;
- SpdyHeaderBlock block;
- ASSERT_FALSE(
- SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
-}
-
-TEST(SpdyUtilsTest, CopyAndValidateHeadersMultipleContentLengths) {
- auto headers = FromList({{"content-length", "9"},
- {"foo", "foovalue"},
- {"content-length", "9"},
- {"bar", "barvalue"},
- {"baz", ""}});
- int64_t content_length = -1;
- SpdyHeaderBlock block;
- ASSERT_TRUE(
- SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
- EXPECT_THAT(block, UnorderedElementsAre(
- Pair("foo", "foovalue"), Pair("bar", "barvalue"),
- Pair("content-length", StringPiece("9"
- "\0"
- "9",
- 3)),
- Pair("baz", "")));
- EXPECT_EQ(9, content_length);
-}
-
-TEST(SpdyUtilsTest, CopyAndValidateHeadersInconsistentContentLengths) {
- auto headers = FromList({{"content-length", "9"},
- {"foo", "foovalue"},
- {"content-length", "8"},
- {"bar", "barvalue"},
- {"baz", ""}});
- int64_t content_length = -1;
- SpdyHeaderBlock block;
- ASSERT_FALSE(
- SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
-}
-
-TEST(SpdyUtilsTest, CopyAndValidateHeadersLargeContentLength) {
- auto headers = FromList({{"content-length", "9000000000"},
- {"foo", "foovalue"},
- {"bar", "barvalue"},
- {"baz", ""}});
- int64_t content_length = -1;
- SpdyHeaderBlock block;
- ASSERT_TRUE(
- SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
- EXPECT_THAT(block, UnorderedElementsAre(
- Pair("foo", "foovalue"), Pair("bar", "barvalue"),
- Pair("content-length", StringPiece("9000000000")),
- Pair("baz", "")));
- EXPECT_EQ(9000000000, content_length);
-}
-
-TEST(SpdyUtilsTest, CopyAndValidateHeadersMultipleValues) {
- auto headers = FromList({{"foo", "foovalue"},
- {"bar", "barvalue"},
- {"baz", ""},
- {"foo", "boo"},
- {"baz", "buzz"}});
- int64_t content_length = -1;
- SpdyHeaderBlock block;
- ASSERT_TRUE(
- SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
- EXPECT_THAT(
- block, UnorderedElementsAre(Pair("foo", StringPiece("foovalue\0boo", 12)),
- Pair("bar", "barvalue"),
- Pair("baz", StringPiece("\0buzz", 5))));
- EXPECT_EQ(-1, content_length);
-}
-
-TEST(SpdyUtilsTest, CopyAndValidateHeadersMoreThanTwoValues) {
- auto headers = FromList({{"set-cookie", "value1"},
- {"set-cookie", "value2"},
- {"set-cookie", "value3"}});
- int64_t content_length = -1;
- SpdyHeaderBlock block;
- ASSERT_TRUE(
- SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
- EXPECT_THAT(block,
- UnorderedElementsAre(Pair(
- "set-cookie", StringPiece("value1\0value2\0value3", 20))));
- EXPECT_EQ(-1, content_length);
-}
-
-TEST(SpdyUtilsTest, CopyAndValidateHeadersCookie) {
- auto headers = FromList({{"foo", "foovalue"},
- {"bar", "barvalue"},
- {"cookie", "value1"},
- {"baz", ""}});
- int64_t content_length = -1;
- SpdyHeaderBlock block;
- ASSERT_TRUE(
- SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
- EXPECT_THAT(block, UnorderedElementsAre(
- Pair("foo", "foovalue"), Pair("bar", "barvalue"),
- Pair("cookie", "value1"), Pair("baz", "")));
- EXPECT_EQ(-1, content_length);
-}
-
-TEST(SpdyUtilsTest, CopyAndValidateHeadersMultipleCookies) {
- auto headers = FromList({{"foo", "foovalue"},
- {"bar", "barvalue"},
- {"cookie", "value1"},
- {"baz", ""},
- {"cookie", "value2"}});
- int64_t content_length = -1;
- SpdyHeaderBlock block;
- ASSERT_TRUE(
- SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
- EXPECT_THAT(block, UnorderedElementsAre(
- Pair("foo", "foovalue"), Pair("bar", "barvalue"),
- Pair("cookie", "value1; value2"), Pair("baz", "")));
- EXPECT_EQ(-1, content_length);
-}
-
-TEST(SpdyUtilsTest, GetUrlFromHeaderBlock) {
- SpdyHeaderBlock headers;
- EXPECT_EQ(SpdyUtils::GetUrlFromHeaderBlock(headers), "");
- headers[":scheme"] = "https";
- EXPECT_EQ(SpdyUtils::GetUrlFromHeaderBlock(headers), "");
- headers[":authority"] = "www.google.com";
- EXPECT_EQ(SpdyUtils::GetUrlFromHeaderBlock(headers), "");
- headers[":path"] = "/index.html";
- EXPECT_EQ(SpdyUtils::GetUrlFromHeaderBlock(headers),
- "https://www.google.com/index.html");
- headers["key1"] = "value1";
- headers["key2"] = "value2";
- EXPECT_EQ(SpdyUtils::GetUrlFromHeaderBlock(headers),
- "https://www.google.com/index.html");
-}
-
-TEST(SpdyUtilsTest, GetHostNameFromHeaderBlock) {
- SpdyHeaderBlock headers;
- EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "");
- headers[":scheme"] = "https";
- EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "");
- headers[":authority"] = "www.google.com";
- EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "");
- headers[":path"] = "/index.html";
- EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "www.google.com");
- headers["key1"] = "value1";
- headers["key2"] = "value2";
- EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "www.google.com");
- headers[":authority"] = "www.google.com:6666";
- EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "www.google.com");
- headers[":authority"] = "192.168.1.1";
- EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "192.168.1.1");
- headers[":authority"] = "192.168.1.1:6666";
- EXPECT_EQ(SpdyUtils::GetHostNameFromHeaderBlock(headers), "192.168.1.1");
-}
-
-TEST(SpdyUtilsTest, UrlIsValid) {
- SpdyHeaderBlock headers;
- EXPECT_FALSE(SpdyUtils::UrlIsValid(headers));
- headers[":scheme"] = "https";
- EXPECT_FALSE(SpdyUtils::UrlIsValid(headers));
- headers[":authority"] = "www.google.com";
- EXPECT_FALSE(SpdyUtils::UrlIsValid(headers));
- headers[":path"] = "/index.html";
- EXPECT_TRUE(SpdyUtils::UrlIsValid(headers));
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/test_tools/crypto_test_utils.cc b/chromium/net/quic/test_tools/crypto_test_utils.cc
index aaafbbc4fe0..ab907cdbbc1 100644
--- a/chromium/net/quic/test_tools/crypto_test_utils.cc
+++ b/chromium/net/quic/test_tools/crypto_test_utils.cc
@@ -17,19 +17,20 @@
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
#include "crypto/secure_hash.h"
-#include "net/quic/crypto/channel_id.h"
-#include "net/quic/crypto/common_cert_set.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_crypto_client_stream.h"
-#include "net/quic/quic_crypto_server_stream.h"
-#include "net/quic/quic_crypto_stream.h"
-#include "net/quic/quic_server_id.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/channel_id.h"
+#include "net/quic/core/crypto/common_cert_set.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/crypto_server_config_protobuf.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_crypto_client_stream.h"
+#include "net/quic/core/quic_crypto_server_stream.h"
+#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/test_tools/quic_connection_peer.h"
#include "net/quic/test_tools/quic_framer_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
@@ -261,13 +262,127 @@ class TestChannelIDSource : public ChannelIDSource {
} // anonymous namespace
-CryptoTestUtils::FakeServerOptions::FakeServerOptions()
- : token_binding_enabled(false) {}
+CryptoTestUtils::FakeServerOptions::FakeServerOptions() {}
+
+CryptoTestUtils::FakeServerOptions::~FakeServerOptions() {}
CryptoTestUtils::FakeClientOptions::FakeClientOptions()
- : channel_id_enabled(false),
- channel_id_source_async(false),
- token_binding_enabled(false) {}
+ : channel_id_enabled(false), channel_id_source_async(false) {}
+
+CryptoTestUtils::FakeClientOptions::~FakeClientOptions() {}
+
+namespace {
+// This class is used by GenerateFullCHLO() to extract SCID and STK from
+// REJ/SREJ and to construct a full CHLO with these fields and given inchoate
+// CHLO.
+class FullChloGenerator {
+ public:
+ FullChloGenerator(QuicCryptoServerConfig* crypto_config,
+ IPAddress server_ip,
+ IPEndPoint client_addr,
+ const QuicClock* clock,
+ QuicCryptoProof* proof,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ CryptoHandshakeMessage* out)
+ : crypto_config_(crypto_config),
+ server_ip_(server_ip),
+ client_addr_(client_addr),
+ clock_(clock),
+ proof_(proof),
+ compressed_certs_cache_(compressed_certs_cache),
+ out_(out) {}
+
+ class ValidateClientHelloCallback : public ValidateClientHelloResultCallback {
+ public:
+ explicit ValidateClientHelloCallback(FullChloGenerator* generator)
+ : generator_(generator) {}
+ void Run(scoped_refptr<ValidateClientHelloResultCallback::Result> result,
+ std::unique_ptr<ProofSource::Details> /* details */) override {
+ generator_->ValidateClientHelloDone(std::move(result));
+ }
+
+ private:
+ FullChloGenerator* generator_;
+ };
+
+ std::unique_ptr<ValidateClientHelloCallback>
+ GetValidateClientHelloCallback() {
+ return std::unique_ptr<ValidateClientHelloCallback>(
+ new ValidateClientHelloCallback(this));
+ }
+
+ private:
+ void ValidateClientHelloDone(
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result) {
+ result_ = result;
+ crypto_config_->ProcessClientHello(
+ result_, /*reject_only=*/false, /*connection_id=*/1, server_ip_,
+ client_addr_, AllSupportedVersions().front(), AllSupportedVersions(),
+ /*use_stateless_rejects=*/true, /*server_designated_connection_id=*/0,
+ clock_, QuicRandom::GetInstance(), compressed_certs_cache_, &params_,
+ proof_, /*total_framing_overhead=*/50, kDefaultMaxPacketSize,
+ GetProcessClientHelloCallback());
+ }
+
+ class ProcessClientHelloCallback : public ProcessClientHelloResultCallback {
+ public:
+ explicit ProcessClientHelloCallback(FullChloGenerator* generator)
+ : generator_(generator) {}
+ void Run(
+ QuicErrorCode error,
+ const string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> message,
+ std::unique_ptr<DiversificationNonce> diversification_nonce) override {
+ generator_->ProcessClientHelloDone(std::move(message));
+ }
+
+ private:
+ FullChloGenerator* generator_;
+ };
+
+ std::unique_ptr<ProcessClientHelloCallback> GetProcessClientHelloCallback() {
+ return std::unique_ptr<ProcessClientHelloCallback>(
+ new ProcessClientHelloCallback(this));
+ }
+
+ void ProcessClientHelloDone(std::unique_ptr<CryptoHandshakeMessage> rej) {
+ // Verify output is a REJ or SREJ.
+ EXPECT_THAT(rej->tag(),
+ testing::AnyOf(testing::Eq(kSREJ), testing::Eq(kREJ)));
+
+ VLOG(1) << "Extract valid STK and SCID from\n" << rej->DebugString();
+ StringPiece srct;
+ ASSERT_TRUE(rej->GetStringPiece(kSourceAddressTokenTag, &srct));
+
+ StringPiece scfg;
+ ASSERT_TRUE(rej->GetStringPiece(kSCFG, &scfg));
+ std::unique_ptr<CryptoHandshakeMessage> server_config(
+ CryptoFramer::ParseMessage(scfg));
+
+ StringPiece scid;
+ ASSERT_TRUE(server_config->GetStringPiece(kSCID, &scid));
+
+ *out_ = result_->client_hello;
+ out_->SetStringPiece(kSCID, scid);
+ out_->SetStringPiece(kSourceAddressTokenTag, srct);
+ uint64_t xlct = CryptoTestUtils::LeafCertHashForTesting();
+ out_->SetValue(kXLCT, xlct);
+ }
+
+ protected:
+ QuicCryptoServerConfig* crypto_config_;
+ IPAddress server_ip_;
+ IPEndPoint client_addr_;
+ const QuicClock* clock_;
+ QuicCryptoProof* proof_;
+ QuicCompressedCertsCache* compressed_certs_cache_;
+ CryptoHandshakeMessage* out_;
+
+ QuicCryptoNegotiatedParameters params_;
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result_;
+};
+
+} // namespace
// static
int CryptoTestUtils::HandshakeWithFakeServer(
@@ -327,8 +442,8 @@ int CryptoTestUtils::HandshakeWithFakeClient(
}
crypto_config.SetChannelIDSource(source);
}
- if (options.token_binding_enabled) {
- crypto_config.tb_key_params.push_back(kP256);
+ if (!options.token_binding_params.empty()) {
+ crypto_config.tb_key_params = options.token_binding_params;
}
TestQuicSpdyClientSession client_session(client_conn, DefaultQuicConfig(),
server_id, &crypto_config);
@@ -342,18 +457,21 @@ int CryptoTestUtils::HandshakeWithFakeClient(
client_conn, client_session.GetCryptoStream(), server_conn, server,
async_channel_id_source);
- CompareClientAndServerKeys(client_session.GetCryptoStream(), server);
-
- if (options.channel_id_enabled) {
- std::unique_ptr<ChannelIDKey> channel_id_key;
- QuicAsyncStatus status = crypto_config.channel_id_source()->GetChannelIDKey(
- server_id.host(), &channel_id_key, nullptr);
- EXPECT_EQ(QUIC_SUCCESS, status);
- EXPECT_EQ(channel_id_key->SerializeKey(),
- server->crypto_negotiated_params().channel_id);
- EXPECT_EQ(
- options.channel_id_source_async,
- client_session.GetCryptoStream()->WasChannelIDSourceCallbackRun());
+ if (server->handshake_confirmed() && server->encryption_established()) {
+ CompareClientAndServerKeys(client_session.GetCryptoStream(), server);
+
+ if (options.channel_id_enabled) {
+ std::unique_ptr<ChannelIDKey> channel_id_key;
+ QuicAsyncStatus status =
+ crypto_config.channel_id_source()->GetChannelIDKey(
+ server_id.host(), &channel_id_key, nullptr);
+ EXPECT_EQ(QUIC_SUCCESS, status);
+ EXPECT_EQ(channel_id_key->SerializeKey(),
+ server->crypto_negotiated_params().channel_id);
+ EXPECT_EQ(
+ options.channel_id_source_async,
+ client_session.GetCryptoStream()->WasChannelIDSourceCallbackRun());
+ }
}
return client_session.GetCryptoStream()->num_sent_client_hellos();
@@ -368,7 +486,7 @@ void CryptoTestUtils::SetupCryptoServerConfigForTest(
const FakeServerOptions& fake_options) {
QuicCryptoServerConfig::ConfigOptions options;
options.channel_id_enabled = true;
- options.token_binding_enabled = fake_options.token_binding_enabled;
+ options.token_binding_params = fake_options.token_binding_params;
std::unique_ptr<CryptoHandshakeMessage> scfg(
crypto_config->AddDefaultConfig(rand, clock, options));
}
@@ -455,9 +573,8 @@ uint64_t CryptoTestUtils::LeafCertHashForTesting() {
string cert_sct;
std::unique_ptr<ProofSource> proof_source(
CryptoTestUtils::ProofSourceForTesting());
- if (!proof_source->GetProof(server_ip, "", "",
- QuicSupportedVersions().front(), "", false,
- &chain, &sig, &cert_sct) ||
+ if (!proof_source->GetProof(server_ip, "", "", AllSupportedVersions().front(),
+ "", &chain, &sig, &cert_sct) ||
chain->certs.empty()) {
DCHECK(false) << "Proof generation failed";
return 0;
@@ -555,6 +672,8 @@ void CryptoTestUtils::FillInDummyReject(CryptoHandshakeMessage* rej,
// clang-format on
rej->SetValue(kSCFG, scfg);
rej->SetStringPiece(kServerNonceTag, "SERVER_NONCE");
+ int64_t ttl = 2 * 24 * 60 * 60;
+ rej->SetValue(kSTTL, ttl);
vector<QuicTag> reject_reasons;
reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE);
rej->SetVector(kRREJ, reject_reasons);
@@ -815,6 +934,8 @@ void CryptoTestUtils::MovePackets(PacketSavingConnection* source_conn,
StringPiece(stream_frame->data_buffer, stream_frame->data_length)));
ASSERT_FALSE(crypto_visitor.error());
}
+ QuicConnectionPeer::SetCurrentPacket(
+ dest_conn, source_conn->encrypted_packets_[index]->AsStringPiece());
}
*inout_packet_index = index;
@@ -825,6 +946,77 @@ void CryptoTestUtils::MovePackets(PacketSavingConnection* source_conn,
for (const CryptoHandshakeMessage& message : crypto_visitor.messages()) {
dest_stream->OnHandshakeMessage(message);
}
+ QuicConnectionPeer::SetCurrentPacket(dest_conn, StringPiece(nullptr, 0));
+}
+
+CryptoHandshakeMessage CryptoTestUtils::GenerateDefaultInchoateCHLO(
+ const QuicClock* clock,
+ QuicVersion version,
+ QuicCryptoServerConfig* crypto_config) {
+ // clang-format off
+ return CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "PUBS", CryptoTestUtils::GenerateClientPublicValuesHex().c_str(),
+ "NONC", CryptoTestUtils::GenerateClientNonceHex(clock,
+ crypto_config).c_str(),
+ "VER\0", QuicUtils::TagToString(
+ QuicVersionToQuicTag(version)).c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+}
+
+string CryptoTestUtils::GenerateClientNonceHex(
+ const QuicClock* clock,
+ QuicCryptoServerConfig* crypto_config) {
+ net::QuicCryptoServerConfig::ConfigOptions old_config_options;
+ net::QuicCryptoServerConfig::ConfigOptions new_config_options;
+ old_config_options.id = "old-config-id";
+ delete crypto_config->AddDefaultConfig(net::QuicRandom::GetInstance(), clock,
+ old_config_options);
+ std::unique_ptr<QuicServerConfigProtobuf> primary_config(
+ crypto_config->GenerateConfig(net::QuicRandom::GetInstance(), clock,
+ new_config_options));
+ primary_config->set_primary_time(clock->WallNow().ToUNIXSeconds());
+ std::unique_ptr<net::CryptoHandshakeMessage> msg(
+ crypto_config->AddConfig(primary_config.get(), clock->WallNow()));
+ StringPiece orbit;
+ CHECK(msg->GetStringPiece(net::kORBT, &orbit));
+ string nonce;
+ net::CryptoUtils::GenerateNonce(
+ clock->WallNow(), net::QuicRandom::GetInstance(),
+ StringPiece(reinterpret_cast<const char*>(orbit.data()),
+ sizeof(orbit.size())),
+ &nonce);
+ return ("#" + net::QuicUtils::HexEncode(nonce));
+}
+
+string CryptoTestUtils::GenerateClientPublicValuesHex() {
+ char public_value[32];
+ memset(public_value, 42, sizeof(public_value));
+ return ("#" + net::QuicUtils::HexEncode(public_value, sizeof(public_value)));
+}
+
+// static
+void CryptoTestUtils::GenerateFullCHLO(
+ const CryptoHandshakeMessage& inchoate_chlo,
+ QuicCryptoServerConfig* crypto_config,
+ IPAddress server_ip,
+ IPEndPoint client_addr,
+ QuicVersion version,
+ const QuicClock* clock,
+ QuicCryptoProof* proof,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ CryptoHandshakeMessage* out) {
+ // Pass a inchoate CHLO.
+ FullChloGenerator generator(crypto_config, server_ip, client_addr, clock,
+ proof, compressed_certs_cache, out);
+ crypto_config->ValidateClientHello(
+ inchoate_chlo, client_addr.address(), server_ip, version, clock, proof,
+ generator.GetValidateClientHelloCallback());
}
} // namespace test
diff --git a/chromium/net/quic/test_tools/crypto_test_utils.h b/chromium/net/quic/test_tools/crypto_test_utils.h
index b453cecf4f8..1e9a3dc8eaf 100644
--- a/chromium/net/quic/test_tools/crypto_test_utils.h
+++ b/chromium/net/quic/test_tools/crypto_test_utils.h
@@ -15,9 +15,9 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/string_piece.h"
-#include "net/quic/crypto/crypto_framer.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/crypto/crypto_framer.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/quic/test_tools/quic_test_utils.h"
namespace net {
@@ -60,16 +60,17 @@ class CryptoTestUtils {
// server in HandshakeWithFakeServer.
struct FakeServerOptions {
FakeServerOptions();
+ ~FakeServerOptions();
- // If token_binding_enabled is true, then the server will attempt to
- // negotiate Token Binding.
- bool token_binding_enabled;
+ // The Token Binding params that the server supports and will negotiate.
+ QuicTagVector token_binding_params;
};
// FakeClientOptions bundles together a number of options for configuring
// HandshakeWithFakeClient.
struct FakeClientOptions {
FakeClientOptions();
+ ~FakeClientOptions();
// If channel_id_enabled is true then the client will attempt to send a
// ChannelID.
@@ -79,9 +80,8 @@ class CryptoTestUtils {
// ChannelIDSource for testing. Ignored if channel_id_enabled is false.
bool channel_id_source_async;
- // If token_binding_enabled is true, then the client will attempt to
- // negotiate Token Binding.
- bool token_binding_enabled;
+ // The Token Binding params that the client supports and will negotiate.
+ QuicTagVector token_binding_params;
};
// returns: the number of client hellos that the client sent.
@@ -142,14 +142,14 @@ class CryptoTestUtils {
static std::string GetValueForTag(const CryptoHandshakeMessage& message,
QuicTag tag);
- // Returns a |ProofSource| that serves up test certificates.
- static ProofSource* ProofSourceForTesting();
+ // Returns a new |ProofSource| that serves up test certificates.
+ static std::unique_ptr<ProofSource> ProofSourceForTesting();
// Returns a |ProofVerifier| that uses the QUIC testing root CA.
- static ProofVerifier* ProofVerifierForTesting();
+ static std::unique_ptr<ProofVerifier> ProofVerifierForTesting();
// Returns a real ProofVerifier (not a fake proof verifier) for testing.
- static ProofVerifier* RealProofVerifierForTesting();
+ static std::unique_ptr<ProofVerifier> RealProofVerifierForTesting();
// Returns a hash of the leaf test certificate.
static uint64_t LeafCertHashForTesting();
@@ -205,10 +205,36 @@ class CryptoTestUtils {
PacketSavingConnection* dest_conn,
Perspective dest_perspective);
+ // Return an inchoate CHLO with some basic tag value std:pairs.
+ static CryptoHandshakeMessage GenerateDefaultInchoateCHLO(
+ const QuicClock* clock,
+ QuicVersion version,
+ QuicCryptoServerConfig* crypto_config);
+
+ // Takes a inchoate CHLO, returns a full CHLO in |out| which can pass
+ // |crypto_config|'s validation.
+ static void GenerateFullCHLO(const CryptoHandshakeMessage& inchoate_chlo,
+ QuicCryptoServerConfig* crypto_config,
+ IPAddress server_ip,
+ IPEndPoint client_addr,
+ QuicVersion version,
+ const QuicClock* clock,
+ QuicCryptoProof* proof,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ CryptoHandshakeMessage* out);
+
private:
static void CompareClientAndServerKeys(QuicCryptoClientStream* client,
QuicCryptoServerStream* server);
+ // Return a CHLO nonce in hexadecimal.
+ static std::string GenerateClientNonceHex(
+ const QuicClock* clock,
+ QuicCryptoServerConfig* crypto_config);
+
+ // Return a CHLO PUBS in hexadecimal.
+ static std::string GenerateClientPublicValuesHex();
+
DISALLOW_COPY_AND_ASSIGN(CryptoTestUtils);
};
diff --git a/chromium/net/quic/test_tools/crypto_test_utils_chromium.cc b/chromium/net/quic/test_tools/crypto_test_utils_chromium.cc
deleted file mode 100644
index 1e944e04a84..00000000000
--- a/chromium/net/quic/test_tools/crypto_test_utils_chromium.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2013 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 <memory>
-#include <utility>
-
-#include "base/callback_helpers.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/stl_util.h"
-#include "base/strings/stringprintf.h"
-#include "net/base/net_errors.h"
-#include "net/base/test_completion_callback.h"
-#include "net/cert/cert_status_flags.h"
-#include "net/cert/cert_verifier.h"
-#include "net/cert/cert_verify_result.h"
-#include "net/cert/ct_policy_enforcer.h"
-#include "net/cert/ct_verifier.h"
-#include "net/cert/mock_cert_verifier.h"
-#include "net/cert/multi_log_ct_verifier.h"
-#include "net/cert/test_root_certs.h"
-#include "net/cert/x509_certificate.h"
-#include "net/cert/x509_util.h"
-#include "net/http/transport_security_state.h"
-#include "net/log/net_log.h"
-#include "net/quic/crypto/crypto_utils.h"
-#include "net/quic/crypto/proof_source_chromium.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/test_tools/crypto_test_utils.h"
-#include "net/ssl/ssl_config_service.h"
-#include "net/test/cert_test_util.h"
-#include "net/test/test_data_directory.h"
-
-using base::StringPiece;
-using base::StringPrintf;
-using std::string;
-using std::vector;
-
-namespace net {
-
-namespace test {
-
-namespace {
-
-class TestProofVerifierChromium : public ProofVerifierChromium {
- public:
- TestProofVerifierChromium(
- std::unique_ptr<CertVerifier> cert_verifier,
- std::unique_ptr<TransportSecurityState> transport_security_state,
- std::unique_ptr<CTVerifier> cert_transparency_verifier,
- std::unique_ptr<CTPolicyEnforcer> ct_policy_enforcer,
- const std::string& cert_file)
- : ProofVerifierChromium(cert_verifier.get(),
- ct_policy_enforcer.get(),
- transport_security_state.get(),
- cert_transparency_verifier.get()),
- cert_verifier_(std::move(cert_verifier)),
- transport_security_state_(std::move(transport_security_state)),
- cert_transparency_verifier_(std::move(cert_transparency_verifier)),
- ct_policy_enforcer_(std::move(ct_policy_enforcer)) {
- // Load and install the root for the validated chain.
- scoped_refptr<X509Certificate> root_cert =
- ImportCertFromFile(GetTestCertsDirectory(), cert_file);
- scoped_root_.Reset(root_cert.get());
- }
-
- ~TestProofVerifierChromium() override {}
-
- CertVerifier* cert_verifier() { return cert_verifier_.get(); }
-
- private:
- ScopedTestRoot scoped_root_;
- std::unique_ptr<CertVerifier> cert_verifier_;
- std::unique_ptr<TransportSecurityState> transport_security_state_;
- std::unique_ptr<CTVerifier> cert_transparency_verifier_;
- std::unique_ptr<CTPolicyEnforcer> ct_policy_enforcer_;
-};
-
-} // namespace
-
-// static
-ProofSource* CryptoTestUtils::ProofSourceForTesting() {
- 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")));
- return source;
-}
-
-// static
-ProofVerifier* ProofVerifierForTestingInternal(bool use_real_proof_verifier) {
- // TODO(rch): use a real cert verifier?
- 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");
- cert_verifier->AddResultForCertAndHost(verify_result.verified_cert.get(),
- "test.example.com", verify_result, OK);
- if (use_real_proof_verifier) {
- return new TestProofVerifierChromium(
- std::move(cert_verifier), base::WrapUnique(new TransportSecurityState),
- base::WrapUnique(new MultiLogCTVerifier),
- base::WrapUnique(new CTPolicyEnforcer), "quic_root.crt");
- }
- return new TestProofVerifierChromium(
- std::move(cert_verifier), base::WrapUnique(new TransportSecurityState),
- base::WrapUnique(new MultiLogCTVerifier),
- base::WrapUnique(new CTPolicyEnforcer), "quic_root.crt");
-}
-
-// static
-ProofVerifier* CryptoTestUtils::ProofVerifierForTesting() {
- return ProofVerifierForTestingInternal(/*use_real_proof_verifier=*/false);
-}
-
-// static
-ProofVerifier* CryptoTestUtils::RealProofVerifierForTesting() {
- return ProofVerifierForTestingInternal(/*use_real_proof_verifier=*/true);
-}
-
-// static
-ProofVerifyContext* CryptoTestUtils::ProofVerifyContextForTesting() {
- return new ProofVerifyContextChromium(/*cert_verify_flags=*/0, BoundNetLog());
-}
-
-} // namespace test
-
-} // namespace net
diff --git a/chromium/net/quic/test_tools/crypto_test_utils_test.cc b/chromium/net/quic/test_tools/crypto_test_utils_test.cc
new file mode 100644
index 00000000000..fa62570c987
--- /dev/null
+++ b/chromium/net/quic/test_tools/crypto_test_utils_test.cc
@@ -0,0 +1,169 @@
+// 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/test_tools/crypto_test_utils.h"
+
+#include "net/quic/core/crypto/crypto_server_config_protobuf.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+
+namespace net {
+namespace test {
+
+class ShloVerifier {
+ public:
+ ShloVerifier(QuicCryptoServerConfig* crypto_config,
+ IPAddress server_ip,
+ IPEndPoint client_addr,
+ const QuicClock* clock,
+ QuicCryptoProof* proof,
+ QuicCompressedCertsCache* compressed_certs_cache)
+ : crypto_config_(crypto_config),
+ server_ip_(server_ip),
+ client_addr_(client_addr),
+ clock_(clock),
+ proof_(proof),
+ compressed_certs_cache_(compressed_certs_cache) {}
+
+ class ValidateClientHelloCallback : public ValidateClientHelloResultCallback {
+ public:
+ explicit ValidateClientHelloCallback(ShloVerifier* shlo_verifier)
+ : shlo_verifier_(shlo_verifier) {}
+ void Run(scoped_refptr<ValidateClientHelloResultCallback::Result> result,
+ std::unique_ptr<ProofSource::Details> /* details */) override {
+ shlo_verifier_->ValidateClientHelloDone(result);
+ }
+
+ private:
+ ShloVerifier* shlo_verifier_;
+ };
+
+ std::unique_ptr<ValidateClientHelloCallback>
+ GetValidateClientHelloCallback() {
+ return std::unique_ptr<ValidateClientHelloCallback>(
+ new ValidateClientHelloCallback(this));
+ }
+
+ private:
+ void ValidateClientHelloDone(
+ const scoped_refptr<ValidateClientHelloResultCallback::Result>& result) {
+ result_ = result;
+ crypto_config_->ProcessClientHello(
+ result_, /*reject_only=*/false, /*connection_id=*/1, server_ip_,
+ client_addr_, AllSupportedVersions().front(), AllSupportedVersions(),
+ /*use_stateless_rejects=*/true, /*server_designated_connection_id=*/0,
+ clock_, QuicRandom::GetInstance(), compressed_certs_cache_, &params_,
+ proof_, /*total_framing_overhead=*/50, kDefaultMaxPacketSize,
+ GetProcessClientHelloCallback());
+ }
+
+ class ProcessClientHelloCallback : public ProcessClientHelloResultCallback {
+ public:
+ explicit ProcessClientHelloCallback(ShloVerifier* shlo_verifier)
+ : shlo_verifier_(shlo_verifier) {}
+ void Run(
+ QuicErrorCode error,
+ const string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> message,
+ std::unique_ptr<DiversificationNonce> diversification_nonce) override {
+ shlo_verifier_->ProcessClientHelloDone(std::move(message));
+ }
+
+ private:
+ ShloVerifier* shlo_verifier_;
+ };
+
+ std::unique_ptr<ProcessClientHelloCallback> GetProcessClientHelloCallback() {
+ return std::unique_ptr<ProcessClientHelloCallback>(
+ new ProcessClientHelloCallback(this));
+ }
+
+ void ProcessClientHelloDone(std::unique_ptr<CryptoHandshakeMessage> message) {
+ // Verify output is a SHLO.
+ EXPECT_EQ(message->tag(), kSHLO) << "Fail to pass validation. Get "
+ << message->DebugString();
+ }
+
+ QuicCryptoServerConfig* crypto_config_;
+ IPAddress server_ip_;
+ IPEndPoint client_addr_;
+ const QuicClock* clock_;
+ QuicCryptoProof* proof_;
+ QuicCompressedCertsCache* compressed_certs_cache_;
+
+ QuicCryptoNegotiatedParameters params_;
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result_;
+};
+
+TEST(CryptoTestUtilsTest, TestGenerateFullCHLO) {
+ MockClock clock;
+ QuicCryptoServerConfig crypto_config(
+ QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(),
+ CryptoTestUtils::ProofSourceForTesting());
+ IPAddress server_ip;
+ IPEndPoint client_addr(IPAddress::IPv4Localhost(), 1);
+ QuicCryptoProof proof;
+ QuicCompressedCertsCache compressed_certs_cache(
+ QuicCompressedCertsCache::kQuicCompressedCertsCacheSize);
+ CryptoHandshakeMessage full_chlo;
+
+ QuicCryptoServerConfig::ConfigOptions old_config_options;
+ old_config_options.id = "old-config-id";
+ delete crypto_config.AddDefaultConfig(QuicRandom::GetInstance(), &clock,
+ old_config_options);
+ QuicCryptoServerConfig::ConfigOptions new_config_options;
+ std::unique_ptr<QuicServerConfigProtobuf> primary_config(
+ crypto_config.GenerateConfig(QuicRandom::GetInstance(), &clock,
+ new_config_options));
+ primary_config->set_primary_time(clock.WallNow().ToUNIXSeconds());
+ std::unique_ptr<CryptoHandshakeMessage> msg(
+ crypto_config.AddConfig(primary_config.get(), clock.WallNow()));
+ StringPiece orbit;
+ ASSERT_TRUE(msg->GetStringPiece(kORBT, &orbit));
+ string nonce;
+ CryptoUtils::GenerateNonce(
+ clock.WallNow(), QuicRandom::GetInstance(),
+ StringPiece(reinterpret_cast<const char*>(orbit.data()),
+ sizeof(orbit.size())),
+ &nonce);
+ string nonce_hex = "#" + QuicUtils::HexEncode(nonce);
+
+ char public_value[32];
+ memset(public_value, 42, sizeof(public_value));
+ string pub_hex =
+ "#" + QuicUtils::HexEncode(public_value, sizeof(public_value));
+
+ QuicVersion version(AllSupportedVersions().front());
+ // clang-format off
+ CryptoHandshakeMessage inchoate_chlo = CryptoTestUtils::Message(
+ "CHLO",
+ "PDMD", "X509",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "COPT", "SREJ",
+ "PUBS", pub_hex.c_str(),
+ "NONC", nonce_hex.c_str(),
+ "VER\0", QuicUtils::TagToString(QuicVersionToQuicTag(version)).c_str(),
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+
+ CryptoTestUtils::GenerateFullCHLO(inchoate_chlo, &crypto_config, server_ip,
+ client_addr, version, &clock, &proof,
+ &compressed_certs_cache, &full_chlo);
+ // Verify that full_chlo can pass crypto_config's verification.
+ ShloVerifier shlo_verifier(&crypto_config, server_ip, client_addr, &clock,
+ &proof, &compressed_certs_cache);
+ crypto_config.ValidateClientHello(
+ full_chlo, client_addr.address(), server_ip, version, &clock, &proof,
+ shlo_verifier.GetValidateClientHelloCallback());
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/test_tools/delayed_verify_strike_register_client.h b/chromium/net/quic/test_tools/delayed_verify_strike_register_client.h
index 8d14647b6c0..cb87f2fc979 100644
--- a/chromium/net/quic/test_tools/delayed_verify_strike_register_client.h
+++ b/chromium/net/quic/test_tools/delayed_verify_strike_register_client.h
@@ -12,7 +12,7 @@
#include "base/macros.h"
#include "base/strings/string_piece.h"
-#include "net/quic/crypto/local_strike_register_client.h"
+#include "net/quic/core/crypto/local_strike_register_client.h"
namespace net {
namespace test {
diff --git a/chromium/net/quic/test_tools/mock_clock.cc b/chromium/net/quic/test_tools/mock_clock.cc
index 63e088a0f14..524f4341bec 100644
--- a/chromium/net/quic/test_tools/mock_clock.cc
+++ b/chromium/net/quic/test_tools/mock_clock.cc
@@ -11,7 +11,7 @@ MockClock::MockClock() : now_(QuicTime::Zero()) {}
MockClock::~MockClock() {}
void MockClock::AdvanceTime(QuicTime::Delta delta) {
- now_ = now_.Add(delta);
+ now_ = now_ + delta;
}
QuicTime MockClock::Now() const {
@@ -23,14 +23,13 @@ QuicTime MockClock::ApproximateNow() const {
}
QuicWallTime MockClock::WallNow() const {
- return QuicWallTime::FromUNIXSeconds(
- now_.Subtract(QuicTime::Zero()).ToSeconds());
+ return QuicWallTime::FromUNIXSeconds((now_ - QuicTime::Zero()).ToSeconds());
}
base::TimeTicks MockClock::NowInTicks() const {
base::TimeTicks ticks;
return ticks + base::TimeDelta::FromMicroseconds(
- now_.Subtract(QuicTime::Zero()).ToMicroseconds());
+ (now_ - QuicTime::Zero()).ToMicroseconds());
}
} // namespace net
diff --git a/chromium/net/quic/test_tools/mock_clock.h b/chromium/net/quic/test_tools/mock_clock.h
index 93647246837..01a48bf2fa0 100644
--- a/chromium/net/quic/test_tools/mock_clock.h
+++ b/chromium/net/quic/test_tools/mock_clock.h
@@ -5,12 +5,11 @@
#ifndef NET_QUIC_TEST_TOOLS_MOCK_CLOCK_H_
#define NET_QUIC_TEST_TOOLS_MOCK_CLOCK_H_
-#include "net/quic/quic_clock.h"
-
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/time/time.h"
+#include "net/quic/core/quic_clock.h"
namespace net {
diff --git a/chromium/net/quic/test_tools/mock_crypto_client_stream.cc b/chromium/net/quic/test_tools/mock_crypto_client_stream.cc
index 8698ec48572..d53f681fe78 100644
--- a/chromium/net/quic/test_tools/mock_crypto_client_stream.cc
+++ b/chromium/net/quic/test_tools/mock_crypto_client_stream.cc
@@ -4,9 +4,9 @@
#include "net/quic/test_tools/mock_crypto_client_stream.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/quic_client_session_base.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_client_session_base.h"
#include "net/quic/test_tools/quic_config_peer.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -18,6 +18,7 @@ MockCryptoClientStream::MockCryptoClientStream(
const QuicServerId& server_id,
QuicClientSessionBase* session,
ProofVerifyContext* verify_context,
+ const QuicConfig& config,
QuicCryptoClientConfig* crypto_config,
HandshakeMode handshake_mode,
const ProofVerifyDetailsChromium* proof_verify_details)
@@ -28,7 +29,8 @@ MockCryptoClientStream::MockCryptoClientStream(
session),
handshake_mode_(handshake_mode),
server_id_(server_id),
- proof_verify_details_(proof_verify_details) {}
+ proof_verify_details_(proof_verify_details),
+ config_(config) {}
MockCryptoClientStream::~MockCryptoClientStream() {}
@@ -118,7 +120,7 @@ void MockCryptoClientStream::SetConfigNegotiated() {
cgst.push_back(kTBBR);
#endif
cgst.push_back(kQBIC);
- QuicConfig config;
+ QuicConfig config(config_);
config.SetIdleConnectionStateLifetime(
QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs),
QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs));
diff --git a/chromium/net/quic/test_tools/mock_crypto_client_stream.h b/chromium/net/quic/test_tools/mock_crypto_client_stream.h
index 89d671e63ad..7c8b9fb1099 100644
--- a/chromium/net/quic/test_tools/mock_crypto_client_stream.h
+++ b/chromium/net/quic/test_tools/mock_crypto_client_stream.h
@@ -8,13 +8,13 @@
#include <string>
#include "base/macros.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/quic_client_session_base.h"
-#include "net/quic/quic_crypto_client_stream.h"
-#include "net/quic/quic_server_id.h"
-#include "net/quic/quic_session.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/quic_client_session_base.h"
+#include "net/quic/core/quic_crypto_client_stream.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/quic_session.h"
namespace net {
@@ -41,6 +41,7 @@ class MockCryptoClientStream : public QuicCryptoClientStream {
const QuicServerId& server_id,
QuicClientSessionBase* session,
ProofVerifyContext* verify_context,
+ const QuicConfig& config,
QuicCryptoClientConfig* crypto_config,
HandshakeMode handshake_mode,
const ProofVerifyDetailsChromium* proof_verify_details_);
@@ -63,6 +64,7 @@ class MockCryptoClientStream : public QuicCryptoClientStream {
const QuicServerId server_id_;
const ProofVerifyDetailsChromium* proof_verify_details_;
+ const QuicConfig config_;
DISALLOW_COPY_AND_ASSIGN(MockCryptoClientStream);
};
diff --git a/chromium/net/quic/test_tools/mock_crypto_client_stream_factory.cc b/chromium/net/quic/test_tools/mock_crypto_client_stream_factory.cc
index 3e78666d68e..dfda4db7a36 100644
--- a/chromium/net/quic/test_tools/mock_crypto_client_stream_factory.cc
+++ b/chromium/net/quic/test_tools/mock_crypto_client_stream_factory.cc
@@ -5,8 +5,8 @@
#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
#include "base/lazy_instance.h"
-#include "net/quic/quic_chromium_client_session.h"
-#include "net/quic/quic_crypto_client_stream.h"
+#include "net/quic/chromium/quic_chromium_client_session.h"
+#include "net/quic/core/quic_crypto_client_stream.h"
using std::string;
@@ -16,7 +16,12 @@ MockCryptoClientStreamFactory::~MockCryptoClientStreamFactory() {}
MockCryptoClientStreamFactory::MockCryptoClientStreamFactory()
: handshake_mode_(MockCryptoClientStream::CONFIRM_HANDSHAKE),
- last_stream_(nullptr) {}
+ last_stream_(nullptr),
+ config_(new QuicConfig()) {}
+
+void MockCryptoClientStreamFactory::SetConfig(const QuicConfig& config) {
+ config_.reset(new QuicConfig(config));
+}
QuicCryptoClientStream*
MockCryptoClientStreamFactory::CreateQuicCryptoClientStream(
@@ -29,9 +34,9 @@ MockCryptoClientStreamFactory::CreateQuicCryptoClientStream(
proof_verify_details = proof_verify_details_queue_.front();
proof_verify_details_queue_.pop();
}
- last_stream_ =
- new MockCryptoClientStream(server_id, session, nullptr, crypto_config,
- handshake_mode_, proof_verify_details);
+ last_stream_ = new MockCryptoClientStream(
+ server_id, session, nullptr, *(config_.get()), crypto_config,
+ handshake_mode_, proof_verify_details);
return last_stream_;
}
diff --git a/chromium/net/quic/test_tools/mock_crypto_client_stream_factory.h b/chromium/net/quic/test_tools/mock_crypto_client_stream_factory.h
index 0ac955a39fb..6f645dac6ed 100644
--- a/chromium/net/quic/test_tools/mock_crypto_client_stream_factory.h
+++ b/chromium/net/quic/test_tools/mock_crypto_client_stream_factory.h
@@ -9,9 +9,9 @@
#include <string>
#include "base/macros.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/quic_crypto_client_stream_factory.h"
-#include "net/quic/quic_server_id.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/core/quic_crypto_client_stream_factory.h"
+#include "net/quic/core/quic_server_id.h"
#include "net/quic/test_tools/mock_crypto_client_stream.h"
namespace net {
@@ -42,10 +42,14 @@ class MockCryptoClientStreamFactory : public QuicCryptoClientStreamFactory {
MockCryptoClientStream* last_stream() const { return last_stream_; }
+ // Sets initial config for new sessions.
+ void SetConfig(const QuicConfig& config);
+
private:
MockCryptoClientStream::HandshakeMode handshake_mode_;
MockCryptoClientStream* last_stream_;
std::queue<const ProofVerifyDetailsChromium*> proof_verify_details_queue_;
+ std::unique_ptr<QuicConfig> config_;
DISALLOW_COPY_AND_ASSIGN(MockCryptoClientStreamFactory);
};
diff --git a/chromium/net/quic/test_tools/mock_quic_client_promised_info.h b/chromium/net/quic/test_tools/mock_quic_client_promised_info.h
index 40da296de8a..98643d7c0aa 100644
--- a/chromium/net/quic/test_tools/mock_quic_client_promised_info.h
+++ b/chromium/net/quic/test_tools/mock_quic_client_promised_info.h
@@ -8,8 +8,8 @@
#include <string>
#include "base/macros.h"
-#include "net/quic/quic_client_promised_info.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_client_promised_info.h"
+#include "net/quic/core/quic_protocol.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace net {
diff --git a/chromium/net/quic/test_tools/mock_quic_dispatcher.cc b/chromium/net/quic/test_tools/mock_quic_dispatcher.cc
index 7e051ea1d1b..a8add6553c0 100644
--- a/chromium/net/quic/test_tools/mock_quic_dispatcher.cc
+++ b/chromium/net/quic/test_tools/mock_quic_dispatcher.cc
@@ -12,15 +12,16 @@ namespace test {
MockQuicDispatcher::MockQuicDispatcher(
const QuicConfig& config,
const QuicCryptoServerConfig* crypto_config,
+ QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
- std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
std::unique_ptr<QuicAlarmFactory> alarm_factory)
- : QuicDispatcher(config,
- crypto_config,
- QuicSupportedVersions(),
- std::move(helper),
- std::move(session_helper),
- std::move(alarm_factory)) {}
+ : QuicSimpleDispatcher(config,
+ crypto_config,
+ version_manager,
+ std::move(helper),
+ std::move(session_helper),
+ std::move(alarm_factory)) {}
MockQuicDispatcher::~MockQuicDispatcher() {}
diff --git a/chromium/net/quic/test_tools/mock_quic_dispatcher.h b/chromium/net/quic/test_tools/mock_quic_dispatcher.h
index a8f9e9e003d..e4c41a64962 100644
--- a/chromium/net/quic/test_tools/mock_quic_dispatcher.h
+++ b/chromium/net/quic/test_tools/mock_quic_dispatcher.h
@@ -7,22 +7,23 @@
#include "base/macros.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_protocol.h"
-#include "net/tools/quic/quic_dispatcher.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/tools/quic/quic_simple_dispatcher.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace net {
namespace test {
-class MockQuicDispatcher : public QuicDispatcher {
+class MockQuicDispatcher : public QuicSimpleDispatcher {
public:
MockQuicDispatcher(
const QuicConfig& config,
const QuicCryptoServerConfig* crypto_config,
+ QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
- std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
std::unique_ptr<QuicAlarmFactory> alarm_factory);
~MockQuicDispatcher() override;
diff --git a/chromium/net/quic/test_tools/mock_quic_spdy_client_stream.h b/chromium/net/quic/test_tools/mock_quic_spdy_client_stream.h
index 7164679ecee..399c2a80402 100644
--- a/chromium/net/quic/test_tools/mock_quic_spdy_client_stream.h
+++ b/chromium/net/quic/test_tools/mock_quic_spdy_client_stream.h
@@ -6,7 +6,7 @@
#define NET_QUIC_TEST_TOOLS_MOCK_QUIC_SPDY_CLIENT_STREAM_H_
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
#include "testing/gmock/include/gmock/gmock.h"
// #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/net/quic/test_tools/mock_random.h b/chromium/net/quic/test_tools/mock_random.h
index 0394cb946b8..a3ed228146d 100644
--- a/chromium/net/quic/test_tools/mock_random.h
+++ b/chromium/net/quic/test_tools/mock_random.h
@@ -10,7 +10,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "net/quic/crypto/quic_random.h"
+#include "net/quic/core/crypto/quic_random.h"
namespace net {
namespace test {
diff --git a/chromium/net/quic/test_tools/quic_buffered_packet_store_peer.cc b/chromium/net/quic/test_tools/quic_buffered_packet_store_peer.cc
new file mode 100644
index 00000000000..d4db6866cb4
--- /dev/null
+++ b/chromium/net/quic/test_tools/quic_buffered_packet_store_peer.cc
@@ -0,0 +1,25 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/test_tools/quic_buffered_packet_store_peer.h"
+
+#include "net/quic/core/quic_buffered_packet_store.h"
+
+namespace net {
+namespace test {
+
+// static
+QuicAlarm* QuicBufferedPacketStorePeer::expiration_alarm(
+ QuicBufferedPacketStore* store) {
+ return store->expiration_alarm_.get();
+}
+
+// static
+void QuicBufferedPacketStorePeer::set_clock(QuicBufferedPacketStore* store,
+ const QuicClock* clock) {
+ store->clock_ = clock;
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/test_tools/quic_buffered_packet_store_peer.h b/chromium/net/quic/test_tools/quic_buffered_packet_store_peer.h
new file mode 100644
index 00000000000..efa4b03459e
--- /dev/null
+++ b/chromium/net/quic/test_tools/quic_buffered_packet_store_peer.h
@@ -0,0 +1,33 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_TEST_TOOLS_QUIC_BUFFERED_PACKET_STORE_PEER_H_
+#define NET_QUIC_TEST_TOOLS_QUIC_BUFFERED_PACKET_STORE_PEER_H_
+
+#include <memory>
+
+#include "net/quic/core/quic_alarm.h"
+#include "net/quic/core/quic_clock.h"
+
+namespace net {
+
+class QuicBufferedPacketStore;
+
+namespace test {
+
+class QuicBufferedPacketStorePeer {
+ public:
+ static QuicAlarm* expiration_alarm(QuicBufferedPacketStore* store);
+
+ static void set_clock(QuicBufferedPacketStore* store, const QuicClock* clock);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicBufferedPacketStorePeer);
+};
+
+} // namespace test
+
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_QUIC_BUFFERED_PACKET_STORE_PEER_H_
diff --git a/chromium/net/quic/test_tools/quic_chromium_client_session_peer.cc b/chromium/net/quic/test_tools/quic_chromium_client_session_peer.cc
deleted file mode 100644
index cf5a27a2a7c..00000000000
--- a/chromium/net/quic/test_tools/quic_chromium_client_session_peer.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2013 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/test_tools/quic_chromium_client_session_peer.h"
-
-#include "net/quic/quic_chromium_client_session.h"
-
-namespace net {
-namespace test {
-
-// static
-void QuicChromiumClientSessionPeer::SetMaxOpenStreams(
- QuicChromiumClientSession* session,
- size_t max_streams,
- size_t default_streams) {
- session->config()->SetMaxStreamsPerConnection(max_streams, default_streams);
-}
-
-// static
-void QuicChromiumClientSessionPeer::SetChannelIDSent(
- QuicChromiumClientSession* session,
- bool channel_id_sent) {
- session->crypto_stream_->channel_id_sent_ = channel_id_sent;
-}
-
-// static
-void QuicChromiumClientSessionPeer::SetHostname(
- QuicChromiumClientSession* session,
- const std::string& hostname) {
- QuicServerId server_id(hostname, session->server_id_.port(),
- session->server_id_.privacy_mode());
- session->server_id_ = server_id;
-}
-
-} // namespace test
-} // namespace net
diff --git a/chromium/net/quic/test_tools/quic_chromium_client_session_peer.h b/chromium/net/quic/test_tools/quic_chromium_client_session_peer.h
deleted file mode 100644
index 2736ec78c80..00000000000
--- a/chromium/net/quic/test_tools/quic_chromium_client_session_peer.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2013 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_TEST_TOOLS_QUIC_CHROMIUM_CLIENT_SESSION_PEER_H_
-#define NET_QUIC_TEST_TOOLS_QUIC_CHROMIUM_CLIENT_SESSION_PEER_H_
-
-#include <stddef.h>
-
-#include <string>
-
-#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
-
-namespace net {
-
-class QuicChromiumClientSession;
-
-namespace test {
-
-class QuicChromiumClientSessionPeer {
- public:
- static void SetMaxOpenStreams(QuicChromiumClientSession* session,
- size_t max_streams,
- size_t default_streams);
-
- static void SetChannelIDSent(QuicChromiumClientSession* session,
- bool channel_id_sent);
-
- static void SetHostname(QuicChromiumClientSession* session,
- const std::string& hostname);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(QuicChromiumClientSessionPeer);
-};
-
-} // namespace test
-} // namespace net
-
-#endif // NET_QUIC_TEST_TOOLS_QUIC_CHROMIUM_CLIENT_SESSION_PEER_H_
diff --git a/chromium/net/quic/test_tools/quic_config_peer.cc b/chromium/net/quic/test_tools/quic_config_peer.cc
index 8a094d6ebd5..d9144172b6a 100644
--- a/chromium/net/quic/test_tools/quic_config_peer.cc
+++ b/chromium/net/quic/test_tools/quic_config_peer.cc
@@ -4,7 +4,7 @@
#include "net/quic/test_tools/quic_config_peer.h"
-#include "net/quic/quic_config.h"
+#include "net/quic/core/quic_config.h"
namespace net {
namespace test {
@@ -58,5 +58,22 @@ void QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams(
config->max_incoming_dynamic_streams_.SetReceivedValue(max_streams);
}
+// static
+void QuicConfigPeer::SetConnectionOptionsToSend(QuicConfig* config,
+ const QuicTagVector& options) {
+ config->SetConnectionOptionsToSend(options);
+}
+
+// static
+void QuicConfigPeer::SetReceivedForceHolBlocking(QuicConfig* config) {
+ config->force_hol_blocking_.SetReceivedValue(1);
+}
+
+// static
+void QuicConfigPeer::SetReceivedAlternateServerAddress(QuicConfig* config,
+ IPEndPoint addr) {
+ config->alternate_server_address_.SetReceivedValue(addr);
+}
+
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/test_tools/quic_config_peer.h b/chromium/net/quic/test_tools/quic_config_peer.h
index 33b9560721e..0742f3529d9 100644
--- a/chromium/net/quic/test_tools/quic_config_peer.h
+++ b/chromium/net/quic/test_tools/quic_config_peer.h
@@ -8,8 +8,8 @@
#include <stdint.h>
#include "base/macros.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
@@ -38,6 +38,14 @@ class QuicConfigPeer {
static void SetReceivedMaxIncomingDynamicStreams(QuicConfig* config,
uint32_t max_streams);
+ static void SetConnectionOptionsToSend(QuicConfig* config,
+ const QuicTagVector& options);
+
+ static void SetReceivedForceHolBlocking(QuicConfig* config);
+
+ static void SetReceivedAlternateServerAddress(QuicConfig* config,
+ IPEndPoint addr);
+
private:
DISALLOW_COPY_AND_ASSIGN(QuicConfigPeer);
};
diff --git a/chromium/net/quic/test_tools/quic_connection_peer.cc b/chromium/net/quic/test_tools/quic_connection_peer.cc
index c9a8901b67e..24118ddcf18 100644
--- a/chromium/net/quic/test_tools/quic_connection_peer.cc
+++ b/chromium/net/quic/test_tools/quic_connection_peer.cc
@@ -5,9 +5,10 @@
#include "net/quic/test_tools/quic_connection_peer.h"
#include "base/stl_util.h"
-#include "net/quic/congestion_control/send_algorithm_interface.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/quic_received_packet_manager.h"
+#include "net/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/quic/core/quic_multipath_sent_packet_manager.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/core/quic_received_packet_manager.h"
#include "net/quic/test_tools/quic_framer_peer.h"
#include "net/quic/test_tools/quic_packet_generator_peer.h"
#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
@@ -23,10 +24,17 @@ void QuicConnectionPeer::SendAck(QuicConnection* connection) {
// static
void QuicConnectionPeer::SetSendAlgorithm(
QuicConnection* connection,
+ QuicPathId path_id,
SendAlgorithmInterface* send_algorithm) {
- // TODO(fayang): Remove this method when there is a MockSentPacketManager.
- static_cast<QuicSentPacketManager*>(connection->sent_packet_manager_.get())
- ->send_algorithm_.reset(send_algorithm);
+ GetSentPacketManager(connection, path_id)->SetSendAlgorithm(send_algorithm);
+}
+
+// static
+void QuicConnectionPeer::SetLossAlgorithm(
+ QuicConnection* connection,
+ QuicPathId path_id,
+ LossDetectionInterface* loss_algorithm) {
+ GetSentPacketManager(connection, path_id)->loss_algorithm_ = loss_algorithm;
}
// static
@@ -63,8 +71,14 @@ QuicPacketGenerator* QuicConnectionPeer::GetPacketGenerator(
// static
QuicSentPacketManager* QuicConnectionPeer::GetSentPacketManager(
- QuicConnection* connection) {
- // TODO(fayang): Remove this method when there is a MockSentPacketManager.
+ QuicConnection* connection,
+ QuicPathId path_id) {
+ if (FLAGS_quic_enable_multipath) {
+ return static_cast<QuicSentPacketManager*>(
+ static_cast<QuicMultipathSentPacketManager*>(
+ connection->sent_packet_manager_.get())
+ ->MaybeGetSentPacketManagerForPath(path_id));
+ }
return static_cast<QuicSentPacketManager*>(
connection->sent_packet_manager_.get());
}
@@ -144,6 +158,13 @@ void QuicConnectionPeer::SwapCrypters(QuicConnection* connection,
}
// static
+void QuicConnectionPeer::SetCurrentPacket(QuicConnection* connection,
+ base::StringPiece current_packet) {
+ connection->current_packet_data_ = current_packet.data();
+ connection->last_size_ = current_packet.size();
+}
+
+// static
QuicConnectionHelperInterface* QuicConnectionPeer::GetHelper(
QuicConnection* connection) {
return connection->helper_;
@@ -278,5 +299,14 @@ void QuicConnectionPeer::SetAckDecimationDelay(QuicConnection* connection,
connection->ack_decimation_delay_ = ack_decimation_delay;
}
+// static
+bool QuicConnectionPeer::HasRetransmittableFrames(
+ QuicConnection* connection,
+ QuicPathId path_id,
+ QuicPacketNumber packet_number) {
+ return QuicSentPacketManagerPeer::HasRetransmittableFrames(
+ GetSentPacketManager(connection, path_id), packet_number);
+}
+
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/test_tools/quic_connection_peer.h b/chromium/net/quic/test_tools/quic_connection_peer.h
index 30af9148930..dc35c9e9fac 100644
--- a/chromium/net/quic/test_tools/quic_connection_peer.h
+++ b/chromium/net/quic/test_tools/quic_connection_peer.h
@@ -7,9 +7,9 @@
#include "base/macros.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_connection_stats.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_connection_stats.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
@@ -35,9 +35,16 @@ class QuicConnectionPeer {
public:
static void SendAck(QuicConnection* connection);
+ // Sets send algorithm of |path_id|.
static void SetSendAlgorithm(QuicConnection* connection,
+ QuicPathId path_id,
SendAlgorithmInterface* send_algorithm);
+ // Sets loss algorithm of |path_id|.
+ static void SetLossAlgorithm(QuicConnection* connection,
+ QuicPathId path_id,
+ LossDetectionInterface* loss_algorithm);
+
static const QuicFrame GetUpdatedAckFrame(QuicConnection* connection);
static void PopulateStopWaitingFrame(QuicConnection* connection,
@@ -49,8 +56,9 @@ class QuicConnectionPeer {
static QuicPacketGenerator* GetPacketGenerator(QuicConnection* connection);
- static QuicSentPacketManager* GetSentPacketManager(
- QuicConnection* connection);
+ // Returns sent packet manager of |path_id|.
+ static QuicSentPacketManager* GetSentPacketManager(QuicConnection* connection,
+ QuicPathId path_id);
static QuicTime::Delta GetNetworkTimeout(QuicConnection* connection);
@@ -83,6 +91,9 @@ class QuicConnectionPeer {
static void SwapCrypters(QuicConnection* connection, QuicFramer* framer);
+ static void SetCurrentPacket(QuicConnection* connection,
+ base::StringPiece current_packet);
+
static QuicConnectionHelperInterface* GetHelper(QuicConnection* connection);
static QuicAlarmFactory* GetAlarmFactory(QuicConnection* connection);
@@ -123,6 +134,9 @@ class QuicConnectionPeer {
QuicConnection::AckMode ack_mode);
static void SetAckDecimationDelay(QuicConnection* connection,
float ack_decimation_delay);
+ static bool HasRetransmittableFrames(QuicConnection* connection,
+ QuicPathId path_id,
+ QuicPacketNumber packet_number);
private:
DISALLOW_COPY_AND_ASSIGN(QuicConnectionPeer);
diff --git a/chromium/net/quic/test_tools/quic_crypto_server_config_peer.cc b/chromium/net/quic/test_tools/quic_crypto_server_config_peer.cc
index 28c67306469..619a6516002 100644
--- a/chromium/net/quic/test_tools/quic_crypto_server_config_peer.cc
+++ b/chromium/net/quic/test_tools/quic_crypto_server_config_peer.cc
@@ -18,6 +18,10 @@ using std::vector;
namespace net {
namespace test {
+ProofSource* QuicCryptoServerConfigPeer::GetProofSource() {
+ return server_config_->proof_source_.get();
+}
+
scoped_refptr<QuicCryptoServerConfig::Config>
QuicCryptoServerConfigPeer::GetPrimaryConfig() {
base::AutoLock locked(server_config_->configs_lock_);
@@ -175,15 +179,15 @@ void QuicCryptoServerConfigPeer::SelectNewPrimaryConfig(int seconds) {
QuicWallTime::FromUNIXSeconds(seconds));
}
-const string QuicCryptoServerConfigPeer::CompressChain(
+string QuicCryptoServerConfigPeer::CompressChain(
QuicCompressedCertsCache* compressed_certs_cache,
const scoped_refptr<ProofSource::Chain>& chain,
const string& client_common_set_hashes,
const string& client_cached_cert_hashes,
const CommonCertSets* common_sets) {
- return server_config_->CompressChain(compressed_certs_cache, chain,
- client_common_set_hashes,
- client_cached_cert_hashes, common_sets);
+ return QuicCryptoServerConfig::CompressChain(
+ compressed_certs_cache, chain, client_common_set_hashes,
+ client_cached_cert_hashes, common_sets);
}
uint32_t QuicCryptoServerConfigPeer::source_address_token_future_secs() {
diff --git a/chromium/net/quic/test_tools/quic_crypto_server_config_peer.h b/chromium/net/quic/test_tools/quic_crypto_server_config_peer.h
index 1341a494577..461b6db721f 100644
--- a/chromium/net/quic/test_tools/quic_crypto_server_config_peer.h
+++ b/chromium/net/quic/test_tools/quic_crypto_server_config_peer.h
@@ -5,7 +5,7 @@
#ifndef NET_QUIC_TEST_TOOLS_QUIC_CRYPTO_SERVER_CONFIG_PEER_H_
#define NET_QUIC_TEST_TOOLS_QUIC_CRYPTO_SERVER_CONFIG_PEER_H_
-#include "net/quic/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
namespace net {
namespace test {
@@ -17,6 +17,9 @@ class QuicCryptoServerConfigPeer {
const QuicCryptoServerConfig* server_config)
: server_config_(server_config) {}
+ // Returns the proof source.
+ ProofSource* GetProofSource();
+
// Returns the primary config.
scoped_refptr<QuicCryptoServerConfig::Config> GetPrimaryConfig();
@@ -81,7 +84,7 @@ class QuicCryptoServerConfigPeer {
void SelectNewPrimaryConfig(int seconds);
- const std::string CompressChain(
+ static std::string CompressChain(
QuicCompressedCertsCache* compressed_certs_cache,
const scoped_refptr<ProofSource::Chain>& chain,
const std::string& client_common_set_hashes,
diff --git a/chromium/net/quic/test_tools/quic_flow_controller_peer.cc b/chromium/net/quic/test_tools/quic_flow_controller_peer.cc
index 0e32fed10b0..5fc7d4295fc 100644
--- a/chromium/net/quic/test_tools/quic_flow_controller_peer.cc
+++ b/chromium/net/quic/test_tools/quic_flow_controller_peer.cc
@@ -6,8 +6,8 @@
#include <list>
-#include "net/quic/quic_flow_controller.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_flow_controller.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
namespace test {
diff --git a/chromium/net/quic/test_tools/quic_flow_controller_peer.h b/chromium/net/quic/test_tools/quic_flow_controller_peer.h
index 59ef7c2c68f..7788980c6a8 100644
--- a/chromium/net/quic/test_tools/quic_flow_controller_peer.h
+++ b/chromium/net/quic/test_tools/quic_flow_controller_peer.h
@@ -6,7 +6,7 @@
#define NET_QUIC_TEST_TOOLS_QUIC_FLOW_CONTROLLER_PEER_H_
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
diff --git a/chromium/net/quic/test_tools/quic_framer_peer.cc b/chromium/net/quic/test_tools/quic_framer_peer.cc
index aadecb6b73d..f884e7bf6a7 100644
--- a/chromium/net/quic/test_tools/quic_framer_peer.cc
+++ b/chromium/net/quic/test_tools/quic_framer_peer.cc
@@ -5,8 +5,8 @@
#include "net/quic/test_tools/quic_framer_peer.h"
#include "base/stl_util.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
namespace test {
@@ -35,6 +35,12 @@ void QuicFramerPeer::SetLastPacketNumber(QuicFramer* framer,
}
// static
+void QuicFramerPeer::SetLargestPacketNumber(QuicFramer* framer,
+ QuicPacketNumber packet_number) {
+ framer->largest_packet_number_ = packet_number;
+}
+
+// static
void QuicFramerPeer::SetPerspective(QuicFramer* framer,
Perspective perspective) {
framer->perspective_ = perspective;
@@ -78,7 +84,7 @@ QuicPathId QuicFramerPeer::GetLastPathId(QuicFramer* framer) {
// static
bool QuicFramerPeer::IsPathClosed(QuicFramer* framer, QuicPathId path_id) {
- return ContainsKey(framer->closed_paths_, path_id);
+ return base::ContainsKey(framer->closed_paths_, path_id);
}
} // namespace test
diff --git a/chromium/net/quic/test_tools/quic_framer_peer.h b/chromium/net/quic/test_tools/quic_framer_peer.h
index 8d14c05a3ef..3ab38304ff6 100644
--- a/chromium/net/quic/test_tools/quic_framer_peer.h
+++ b/chromium/net/quic/test_tools/quic_framer_peer.h
@@ -6,9 +6,9 @@
#define NET_QUIC_TEST_TOOLS_QUIC_FRAMER_PEER_H_
#include "base/macros.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
@@ -25,6 +25,8 @@ class QuicFramerPeer {
QuicConnectionId connection_id);
static void SetLastPacketNumber(QuicFramer* framer,
QuicPacketNumber packet_number);
+ static void SetLargestPacketNumber(QuicFramer* framer,
+ QuicPacketNumber packet_number);
static void SetPerspective(QuicFramer* framer, Perspective perspective);
// SwapCrypters exchanges the state of the crypters of |framer1| with
diff --git a/chromium/net/quic/test_tools/quic_headers_stream_peer.cc b/chromium/net/quic/test_tools/quic_headers_stream_peer.cc
new file mode 100644
index 00000000000..1e8e65bf0f3
--- /dev/null
+++ b/chromium/net/quic/test_tools/quic_headers_stream_peer.cc
@@ -0,0 +1,19 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/test_tools/quic_headers_stream_peer.h"
+
+#include "net/quic/core/quic_headers_stream.h"
+
+namespace net {
+namespace test {
+
+// static
+const SpdyFramer& QuicHeadersStreamPeer::GetSpdyFramer(
+ QuicHeadersStream* stream) {
+ return stream->spdy_framer_;
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/test_tools/quic_headers_stream_peer.h b/chromium/net/quic/test_tools/quic_headers_stream_peer.h
new file mode 100644
index 00000000000..998f3e970c1
--- /dev/null
+++ b/chromium/net/quic/test_tools/quic_headers_stream_peer.h
@@ -0,0 +1,28 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_TEST_TOOLS_QUIC_HEADERS_STREAM_PEER_H_
+#define NET_QUIC_TEST_TOOLS_QUIC_HEADERS_STREAM_PEER_H_
+
+#include "net/spdy/spdy_framer.h"
+
+namespace net {
+
+class QuicHeadersStream;
+
+namespace test {
+
+class QuicHeadersStreamPeer {
+ public:
+ static const SpdyFramer& GetSpdyFramer(QuicHeadersStream* stream);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicHeadersStreamPeer);
+};
+
+} // namespace test
+
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_QUIC_HEADERS_STREAM_PEER_H_
diff --git a/chromium/net/quic/test_tools/quic_multipath_sent_packet_manager_peer.cc b/chromium/net/quic/test_tools/quic_multipath_sent_packet_manager_peer.cc
new file mode 100644
index 00000000000..5115cc4b43a
--- /dev/null
+++ b/chromium/net/quic/test_tools/quic_multipath_sent_packet_manager_peer.cc
@@ -0,0 +1,29 @@
+// 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/test_tools/quic_multipath_sent_packet_manager_peer.h"
+
+namespace net {
+namespace test {
+
+// static
+void QuicMultipathSentPacketManagerPeer::AddPathWithCloseState(
+ QuicMultipathSentPacketManager* multipath_manager,
+ QuicSentPacketManagerInterface* manager) {
+ multipath_manager->path_managers_info_.push_back(
+ QuicMultipathSentPacketManager::PathSentPacketManagerInfo(
+ manager, QuicMultipathSentPacketManager::CLOSING));
+}
+
+// static
+void QuicMultipathSentPacketManagerPeer::AddPathWithActiveState(
+ QuicMultipathSentPacketManager* multipath_manager,
+ QuicSentPacketManagerInterface* manager) {
+ multipath_manager->path_managers_info_.push_back(
+ QuicMultipathSentPacketManager::PathSentPacketManagerInfo(
+ manager, QuicMultipathSentPacketManager::ACTIVE));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/test_tools/quic_multipath_sent_packet_manager_peer.h b/chromium/net/quic/test_tools/quic_multipath_sent_packet_manager_peer.h
new file mode 100644
index 00000000000..21477452e22
--- /dev/null
+++ b/chromium/net/quic/test_tools/quic_multipath_sent_packet_manager_peer.h
@@ -0,0 +1,31 @@
+// 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.
+
+#ifndef NET_QUIC_TEST_TOOLS_QUIC_MULTIPATH_SENT_PACKET_MANAGER_PEER_H_
+#define NET_QUIC_TEST_TOOLS_QUIC_MULTIPATH_SENT_PACKET_MANAGER_PEER_H_
+
+#include "base/macros.h"
+#include "net/quic/core/quic_multipath_sent_packet_manager.h"
+#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
+
+namespace net {
+namespace test {
+
+class QuicMultipathSentPacketManagerPeer {
+ public:
+ // Add a path |manager| with close state.
+ static void AddPathWithCloseState(
+ QuicMultipathSentPacketManager* multipath_manager,
+ QuicSentPacketManagerInterface* manager);
+
+ // Add a path |manager| with active state.
+ static void AddPathWithActiveState(
+ QuicMultipathSentPacketManager* multipath_manager,
+ QuicSentPacketManagerInterface* manager);
+};
+
+} // namespace test
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_QUIC_MULTIPATH_SENT_PACKET_MANAGER_PEER_H_
diff --git a/chromium/net/quic/test_tools/quic_packet_creator_peer.cc b/chromium/net/quic/test_tools/quic_packet_creator_peer.cc
index 90821dd194c..dacf23393e3 100644
--- a/chromium/net/quic/test_tools/quic_packet_creator_peer.cc
+++ b/chromium/net/quic/test_tools/quic_packet_creator_peer.cc
@@ -4,7 +4,7 @@
#include "net/quic/test_tools/quic_packet_creator_peer.h"
-#include "net/quic/quic_packet_creator.h"
+#include "net/quic/core/quic_packet_creator.h"
namespace net {
namespace test {
@@ -40,19 +40,6 @@ void QuicPacketCreatorPeer::SetPacketNumberLength(
}
// static
-void QuicPacketCreatorPeer::SetNextPacketNumberLength(
- QuicPacketCreator* creator,
- QuicPacketNumberLength next_packet_number_length) {
- creator->next_packet_number_length_ = next_packet_number_length;
-}
-
-// static
-QuicPacketNumberLength QuicPacketCreatorPeer::NextPacketNumberLength(
- QuicPacketCreator* creator) {
- return creator->next_packet_number_length_;
-}
-
-// static
QuicPacketNumberLength QuicPacketCreatorPeer::GetPacketNumberLength(
QuicPacketCreator* creator) {
return creator->packet_.packet_number_length;
diff --git a/chromium/net/quic/test_tools/quic_packet_creator_peer.h b/chromium/net/quic/test_tools/quic_packet_creator_peer.h
index 7c56c456f39..645d1a80b2c 100644
--- a/chromium/net/quic/test_tools/quic_packet_creator_peer.h
+++ b/chromium/net/quic/test_tools/quic_packet_creator_peer.h
@@ -8,7 +8,7 @@
#include <stddef.h>
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
class QuicPacketCreator;
@@ -29,11 +29,6 @@ class QuicPacketCreatorPeer {
QuicPacketNumberLength packet_number_length);
static QuicPacketNumberLength GetPacketNumberLength(
QuicPacketCreator* creator);
- static void SetNextPacketNumberLength(
- QuicPacketCreator* creator,
- QuicPacketNumberLength next_packet_number_length);
- static QuicPacketNumberLength NextPacketNumberLength(
- QuicPacketCreator* creator);
static void SetPacketNumber(QuicPacketCreator* creator, QuicPacketNumber s);
static void FillPacketHeader(QuicPacketCreator* creator,
QuicPacketHeader* header);
diff --git a/chromium/net/quic/test_tools/quic_packet_generator_peer.cc b/chromium/net/quic/test_tools/quic_packet_generator_peer.cc
index ad0693a355f..2311c598286 100644
--- a/chromium/net/quic/test_tools/quic_packet_generator_peer.cc
+++ b/chromium/net/quic/test_tools/quic_packet_generator_peer.cc
@@ -4,8 +4,8 @@
#include "net/quic/test_tools/quic_packet_generator_peer.h"
-#include "net/quic/quic_packet_creator.h"
-#include "net/quic/quic_packet_generator.h"
+#include "net/quic/core/quic_packet_creator.h"
+#include "net/quic/core/quic_packet_generator.h"
namespace net {
namespace test {
diff --git a/chromium/net/quic/test_tools/quic_packet_generator_peer.h b/chromium/net/quic/test_tools/quic_packet_generator_peer.h
index 246684f732a..2aaa263b9bf 100644
--- a/chromium/net/quic/test_tools/quic_packet_generator_peer.h
+++ b/chromium/net/quic/test_tools/quic_packet_generator_peer.h
@@ -6,7 +6,7 @@
#define NET_QUIC_TEST_TOOLS_QUIC_PACKET_GENERATOR_PEER_H_
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
diff --git a/chromium/net/quic/test_tools/quic_received_packet_manager_peer.cc b/chromium/net/quic/test_tools/quic_received_packet_manager_peer.cc
index e6d1a3eb438..c990cc3ac09 100644
--- a/chromium/net/quic/test_tools/quic_received_packet_manager_peer.cc
+++ b/chromium/net/quic/test_tools/quic_received_packet_manager_peer.cc
@@ -4,8 +4,8 @@
#include "net/quic/test_tools/quic_received_packet_manager_peer.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_received_packet_manager.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_received_packet_manager.h"
namespace net {
namespace test {
diff --git a/chromium/net/quic/test_tools/quic_received_packet_manager_peer.h b/chromium/net/quic/test_tools/quic_received_packet_manager_peer.h
index 10612612270..90dfd3a1d6f 100644
--- a/chromium/net/quic/test_tools/quic_received_packet_manager_peer.h
+++ b/chromium/net/quic/test_tools/quic_received_packet_manager_peer.h
@@ -6,7 +6,7 @@
#define NET_QUIC_TEST_TOOLS_QUIC_RECEIVED_PACKET_MANAGER_PEER_H_
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
diff --git a/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.cc b/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.cc
index 7dc83ca0b46..572f7da0a3b 100644
--- a/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.cc
+++ b/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.cc
@@ -5,11 +5,11 @@
#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
#include "base/stl_util.h"
-#include "net/quic/congestion_control/loss_detection_interface.h"
-#include "net/quic/congestion_control/send_algorithm_interface.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_sent_packet_manager.h"
+#include "net/quic/core/congestion_control/loss_detection_interface.h"
+#include "net/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_sent_packet_manager.h"
namespace net {
namespace test {
@@ -68,20 +68,20 @@ SendAlgorithmInterface* QuicSentPacketManagerPeer::GetSendAlgorithm(
void QuicSentPacketManagerPeer::SetSendAlgorithm(
QuicSentPacketManager* sent_packet_manager,
SendAlgorithmInterface* send_algorithm) {
- sent_packet_manager->send_algorithm_.reset(send_algorithm);
+ sent_packet_manager->SetSendAlgorithm(send_algorithm);
}
// static
const LossDetectionInterface* QuicSentPacketManagerPeer::GetLossAlgorithm(
QuicSentPacketManager* sent_packet_manager) {
- return sent_packet_manager->loss_algorithm_.get();
+ return sent_packet_manager->loss_algorithm_;
}
// static
void QuicSentPacketManagerPeer::SetLossAlgorithm(
QuicSentPacketManager* sent_packet_manager,
LossDetectionInterface* loss_detector) {
- sent_packet_manager->loss_algorithm_.reset(loss_detector);
+ sent_packet_manager->loss_algorithm_ = loss_detector;
}
// static
@@ -106,8 +106,8 @@ bool QuicSentPacketManagerPeer::IsRetransmission(
QuicSentPacketManager* sent_packet_manager,
QuicPathId path_id,
QuicPacketNumber packet_number) {
- DCHECK(sent_packet_manager->HasRetransmittableFrames(path_id, packet_number));
- if (!sent_packet_manager->HasRetransmittableFrames(path_id, packet_number)) {
+ DCHECK(HasRetransmittableFrames(sent_packet_manager, packet_number));
+ if (!HasRetransmittableFrames(sent_packet_manager, packet_number)) {
return false;
}
for (auto transmission_info : sent_packet_manager->unacked_packets_) {
@@ -192,5 +192,20 @@ bool QuicSentPacketManagerPeer::UsingPacing(
return sent_packet_manager->using_pacing_;
}
+// static
+bool QuicSentPacketManagerPeer::IsUnacked(
+ QuicSentPacketManager* sent_packet_manager,
+ QuicPacketNumber packet_number) {
+ return sent_packet_manager->unacked_packets_.IsUnacked(packet_number);
+}
+
+// static
+bool QuicSentPacketManagerPeer::HasRetransmittableFrames(
+ QuicSentPacketManager* sent_packet_manager,
+ QuicPacketNumber packet_number) {
+ return sent_packet_manager->unacked_packets_.HasRetransmittableFrames(
+ packet_number);
+}
+
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.h b/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.h
index a583dbf85ed..c7351f6ce38 100644
--- a/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.h
+++ b/chromium/net/quic/test_tools/quic_sent_packet_manager_peer.h
@@ -8,8 +8,8 @@
#include <stddef.h>
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_sent_packet_manager.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_sent_packet_manager.h"
namespace net {
@@ -93,6 +93,13 @@ class QuicSentPacketManagerPeer {
static bool UsingPacing(const QuicSentPacketManager* sent_packet_manager);
+ static bool IsUnacked(QuicSentPacketManager* sent_packet_manager,
+ QuicPacketNumber packet_number);
+
+ static bool HasRetransmittableFrames(
+ QuicSentPacketManager* sent_packet_manager,
+ QuicPacketNumber packet_number);
+
private:
DISALLOW_COPY_AND_ASSIGN(QuicSentPacketManagerPeer);
};
diff --git a/chromium/net/quic/test_tools/quic_session_peer.cc b/chromium/net/quic/test_tools/quic_session_peer.cc
index 14c14755297..b4d49f768b9 100644
--- a/chromium/net/quic/test_tools/quic_session_peer.cc
+++ b/chromium/net/quic/test_tools/quic_session_peer.cc
@@ -5,8 +5,8 @@
#include "net/quic/test_tools/quic_session_peer.h"
#include "base/stl_util.h"
-#include "net/quic/quic_session.h"
-#include "net/quic/reliable_quic_stream.h"
+#include "net/quic/core/quic_session.h"
+#include "net/quic/core/reliable_quic_stream.h"
using std::map;
@@ -61,7 +61,8 @@ QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(QuicSession* session) {
}
// static
-QuicSession::StreamMap& QuicSessionPeer::static_streams(QuicSession* session) {
+QuicSession::StaticStreamMap& QuicSessionPeer::static_streams(
+ QuicSession* session) {
return session->static_streams();
}
@@ -86,13 +87,13 @@ bool QuicSessionPeer::IsStreamClosed(QuicSession* session, QuicStreamId id) {
// static
bool QuicSessionPeer::IsStreamCreated(QuicSession* session, QuicStreamId id) {
DCHECK_NE(0u, id);
- return ContainsKey(session->dynamic_streams(), id);
+ return base::ContainsKey(session->dynamic_streams(), id);
}
// static
bool QuicSessionPeer::IsStreamAvailable(QuicSession* session, QuicStreamId id) {
DCHECK_NE(0u, id);
- return ContainsKey(session->available_streams_, id);
+ return base::ContainsKey(session->available_streams_, id);
}
// static
diff --git a/chromium/net/quic/test_tools/quic_session_peer.h b/chromium/net/quic/test_tools/quic_session_peer.h
index 19dd88d6467..6edb50f462b 100644
--- a/chromium/net/quic/test_tools/quic_session_peer.h
+++ b/chromium/net/quic/test_tools/quic_session_peer.h
@@ -10,9 +10,9 @@
#include <map>
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_session.h"
-#include "net/quic/quic_write_blocked_list.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_session.h"
+#include "net/quic/core/quic_write_blocked_list.h"
namespace net {
@@ -38,7 +38,7 @@ class QuicSessionPeer {
QuicStreamId stream_id);
static std::map<QuicStreamId, QuicStreamOffset>&
GetLocallyClosedStreamsHighestOffset(QuicSession* session);
- static QuicSession::StreamMap& static_streams(QuicSession* session);
+ static QuicSession::StaticStreamMap& static_streams(QuicSession* session);
static std::unordered_set<QuicStreamId>* GetDrainingStreams(
QuicSession* session);
static void ActivateStream(QuicSession* session, ReliableQuicStream* stream);
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 e13e477b05c..ad760e62906 100644
--- a/chromium/net/quic/test_tools/quic_spdy_session_peer.cc
+++ b/chromium/net/quic/test_tools/quic_spdy_session_peer.cc
@@ -4,7 +4,7 @@
#include "net/quic/test_tools/quic_spdy_session_peer.h"
-#include "net/quic/quic_spdy_session.h"
+#include "net/quic/core/quic_spdy_session.h"
namespace net {
namespace test {
@@ -22,5 +22,11 @@ void QuicSpdySessionPeer::SetHeadersStream(QuicSpdySession* session,
session->static_streams()[headers_stream->id()] = headers_stream;
}
+// static
+void QuicSpdySessionPeer::SetForceHolBlocking(QuicSpdySession* session,
+ bool value) {
+ session->force_hol_blocking_ = value;
+}
+
} // namespace test
} // namespace net
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 d6597c7572d..9cb9cfd554b 100644
--- a/chromium/net/quic/test_tools/quic_spdy_session_peer.h
+++ b/chromium/net/quic/test_tools/quic_spdy_session_peer.h
@@ -6,8 +6,8 @@
#define NET_QUIC_TEST_TOOLS_QUIC_SPDY_SESSION_PEER_H_
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_write_blocked_list.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_write_blocked_list.h"
namespace net {
@@ -21,6 +21,7 @@ class QuicSpdySessionPeer {
static QuicHeadersStream* GetHeadersStream(QuicSpdySession* session);
static void SetHeadersStream(QuicSpdySession* session,
QuicHeadersStream* headers_stream);
+ static void SetForceHolBlocking(QuicSpdySession* session, bool value);
private:
DISALLOW_COPY_AND_ASSIGN(QuicSpdySessionPeer);
diff --git a/chromium/net/quic/test_tools/quic_spdy_stream_peer.cc b/chromium/net/quic/test_tools/quic_spdy_stream_peer.cc
index 953f9111e70..5acc7cf6f71 100644
--- a/chromium/net/quic/test_tools/quic_spdy_stream_peer.cc
+++ b/chromium/net/quic/test_tools/quic_spdy_stream_peer.cc
@@ -4,7 +4,7 @@
#include "net/quic/test_tools/quic_spdy_stream_peer.h"
-#include "net/quic/quic_spdy_stream.h"
+#include "net/quic/core/quic_spdy_stream.h"
namespace net {
namespace test {
diff --git a/chromium/net/quic/test_tools/quic_stream_factory_peer.cc b/chromium/net/quic/test_tools/quic_stream_factory_peer.cc
index d891cfe67fe..0ea8fcd2729 100644
--- a/chromium/net/quic/test_tools/quic_stream_factory_peer.cc
+++ b/chromium/net/quic/test_tools/quic_stream_factory_peer.cc
@@ -7,11 +7,14 @@
#include <string>
#include <vector>
-#include "net/quic/crypto/quic_crypto_client_config.h"
-#include "net/quic/quic_chromium_client_session.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_http_stream.h"
-#include "net/quic/quic_stream_factory.h"
+#include "net/cert/x509_certificate.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"
+#include "net/quic/core/crypto/quic_crypto_client_config.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/test_data_directory.h"
using std::string;
using std::vector;
@@ -33,6 +36,12 @@ bool QuicStreamFactoryPeer::HasActiveSession(QuicStreamFactory* factory,
return factory->HasActiveSession(server_id);
}
+bool QuicStreamFactoryPeer::HasActiveCertVerifierJob(
+ QuicStreamFactory* factory,
+ const QuicServerId& server_id) {
+ return factory->HasActiveCertVerifierJob(server_id);
+}
+
QuicChromiumClientSession* QuicStreamFactoryPeer::GetActiveSession(
QuicStreamFactory* factory,
const QuicServerId& server_id) {
@@ -62,15 +71,13 @@ void QuicStreamFactoryPeer::SetTaskRunner(QuicStreamFactory* factory,
factory->task_runner_ = task_runner;
}
-int QuicStreamFactoryPeer::GetNumberOfLossyConnections(
- QuicStreamFactory* factory,
- uint16_t port) {
- return factory->number_of_lossy_connections_[port];
+QuicTime::Delta QuicStreamFactoryPeer::GetPingTimeout(
+ QuicStreamFactory* factory) {
+ return factory->ping_timeout_;
}
-bool QuicStreamFactoryPeer::IsQuicDisabled(QuicStreamFactory* factory,
- uint16_t port) {
- return factory->IsQuicDisabled(port);
+bool QuicStreamFactoryPeer::IsQuicDisabled(QuicStreamFactory* factory) {
+ return factory->IsQuicDisabled();
}
bool QuicStreamFactoryPeer::GetDelayTcpRace(QuicStreamFactory* factory) {
@@ -82,6 +89,25 @@ void QuicStreamFactoryPeer::SetDelayTcpRace(QuicStreamFactory* factory,
factory->delay_tcp_race_ = delay_tcp_race;
}
+bool QuicStreamFactoryPeer::GetRaceCertVerification(
+ QuicStreamFactory* factory) {
+ return factory->race_cert_verification_;
+}
+
+void QuicStreamFactoryPeer::SetRaceCertVerification(
+ QuicStreamFactory* factory,
+ bool race_cert_verification) {
+ factory->race_cert_verification_ = race_cert_verification;
+}
+
+QuicAsyncStatus QuicStreamFactoryPeer::StartCertVerifyJob(
+ QuicStreamFactory* factory,
+ const QuicServerId& server_id,
+ int cert_verify_flags,
+ const NetLogWithSource& net_log) {
+ return factory->StartCertVerifyJob(server_id, cert_verify_flags, net_log);
+}
+
void QuicStreamFactoryPeer::SetYieldAfterPackets(QuicStreamFactory* factory,
int yield_after_packets) {
factory->yield_after_packets_ = yield_after_packets;
@@ -99,16 +125,6 @@ size_t QuicStreamFactoryPeer::GetNumberOfActiveJobs(
return (factory->active_jobs_[server_id]).size();
}
-int QuicStreamFactoryPeer::GetNumTimeoutsWithOpenStreams(
- QuicStreamFactory* factory) {
- return factory->num_timeouts_with_open_streams_;
-}
-
-int QuicStreamFactoryPeer::GetNumPublicResetsPostHandshake(
- QuicStreamFactory* factory) {
- return factory->num_public_resets_post_handshake_;
-}
-
void QuicStreamFactoryPeer::MaybeInitialize(QuicStreamFactory* factory) {
factory->MaybeInitialize();
}
@@ -119,8 +135,8 @@ bool QuicStreamFactoryPeer::HasInitializedData(QuicStreamFactory* factory) {
bool QuicStreamFactoryPeer::SupportsQuicAtStartUp(QuicStreamFactory* factory,
HostPortPair host_port_pair) {
- return ContainsKey(factory->quic_supported_servers_at_startup_,
- host_port_pair);
+ return base::ContainsKey(factory->quic_supported_servers_at_startup_,
+ host_port_pair);
}
bool QuicStreamFactoryPeer::CryptoConfigCacheIsEmpty(
@@ -149,16 +165,23 @@ void QuicStreamFactoryPeer::CacheDummyServerConfig(
string server_config(reinterpret_cast<const char*>(&scfg), sizeof(scfg));
string source_address_token("test_source_address_token");
string signature("test_signature");
- string test_cert("test_cert");
+
vector<string> certs;
- certs.push_back(test_cert);
+ // Load a certificate that is valid for *.example.org
+ scoped_refptr<X509Certificate> cert(
+ ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
+ DCHECK(cert);
+ std::string der_bytes;
+ DCHECK(X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_bytes));
+ certs.push_back(der_bytes);
QuicCryptoClientConfig* crypto_config = &factory->crypto_config_;
QuicCryptoClientConfig::CachedState* cached =
crypto_config->LookupOrCreate(quic_server_id);
QuicClock clock;
cached->Initialize(server_config, source_address_token, certs, "", "",
- signature, clock.WallNow());
+ signature, clock.WallNow(), QuicWallTime::Zero());
+ DCHECK(!cached->certs().empty());
}
QuicClientPushPromiseIndex* QuicStreamFactoryPeer::GetPushPromiseIndex(
diff --git a/chromium/net/quic/test_tools/quic_stream_factory_peer.h b/chromium/net/quic/test_tools/quic_stream_factory_peer.h
index bf18a18cd18..38916b11aaf 100644
--- a/chromium/net/quic/test_tools/quic_stream_factory_peer.h
+++ b/chromium/net/quic/test_tools/quic_stream_factory_peer.h
@@ -12,12 +12,13 @@
#include "base/task_runner.h"
#include "net/base/host_port_pair.h"
#include "net/base/privacy_mode.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_id.h"
-#include "net/quic/quic_time.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/quic_time.h"
namespace net {
+class NetLogWithSource;
class QuicConfig;
class QuicCryptoClientConfig;
class QuicHttpStream;
@@ -36,6 +37,9 @@ class QuicStreamFactoryPeer {
static bool HasActiveSession(QuicStreamFactory* factory,
const QuicServerId& server_id);
+ static bool HasActiveCertVerifierJob(QuicStreamFactory* factory,
+ const QuicServerId& server_id);
+
static QuicChromiumClientSession* GetActiveSession(
QuicStreamFactory* factory,
const QuicServerId& server_id);
@@ -50,15 +54,24 @@ class QuicStreamFactoryPeer {
static void SetTaskRunner(QuicStreamFactory* factory,
base::TaskRunner* task_runner);
- static int GetNumberOfLossyConnections(QuicStreamFactory* factory,
- uint16_t port);
+ static QuicTime::Delta GetPingTimeout(QuicStreamFactory* factory);
- static bool IsQuicDisabled(QuicStreamFactory* factory, uint16_t port);
+ static bool IsQuicDisabled(QuicStreamFactory* factory);
static bool GetDelayTcpRace(QuicStreamFactory* factory);
static void SetDelayTcpRace(QuicStreamFactory* factory, bool delay_tcp_race);
+ static bool GetRaceCertVerification(QuicStreamFactory* factory);
+
+ static void SetRaceCertVerification(QuicStreamFactory* factory,
+ bool race_cert_verification);
+
+ static QuicAsyncStatus StartCertVerifyJob(QuicStreamFactory* factory,
+ const QuicServerId& server_id,
+ int cert_verify_flags,
+ const NetLogWithSource& net_log);
+
static void SetYieldAfterPackets(QuicStreamFactory* factory,
int yield_after_packets);
@@ -68,10 +81,6 @@ class QuicStreamFactoryPeer {
static size_t GetNumberOfActiveJobs(QuicStreamFactory* factory,
const QuicServerId& server_id);
- static int GetNumTimeoutsWithOpenStreams(QuicStreamFactory* factory);
-
- static int GetNumPublicResetsPostHandshake(QuicStreamFactory* factory);
-
static void MaybeInitialize(QuicStreamFactory* factory);
static bool HasInitializedData(QuicStreamFactory* factory);
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
new file mode 100644
index 00000000000..bc0bf437d83
--- /dev/null
+++ b/chromium/net/quic/test_tools/quic_stream_sequencer_buffer_peer.cc
@@ -0,0 +1,142 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/test_tools/quic_stream_sequencer_buffer_peer.h"
+
+#include "net/quic/core/quic_flags.h"
+#include "net/test/gtest_util.h"
+
+typedef net::QuicStreamSequencerBuffer::BufferBlock BufferBlock;
+typedef net::QuicStreamSequencerBuffer::FrameInfo FrameInfo;
+typedef net::QuicStreamSequencerBuffer::Gap Gap;
+
+static const size_t kBlockSizeBytes =
+ net::QuicStreamSequencerBuffer::kBlockSizeBytes;
+
+namespace net {
+namespace test {
+
+QuicStreamSequencerBufferPeer::QuicStreamSequencerBufferPeer(
+ QuicStreamSequencerBuffer* buffer)
+ : buffer_(buffer) {}
+
+// Read from this buffer_ into the given destination buffer_ up to the
+// size of the destination. Returns the number of bytes read. Reading from
+// an empty buffer_->returns 0.
+size_t QuicStreamSequencerBufferPeer::Read(char* dest_buffer, size_t size) {
+ iovec dest;
+ dest.iov_base = dest_buffer, dest.iov_len = size;
+ size_t bytes_read;
+ std::string error_details;
+ EXPECT_EQ(QUIC_NO_ERROR,
+ buffer_->Readv(&dest, 1, &bytes_read, &error_details));
+ return bytes_read;
+}
+
+// If buffer is empty, the blocks_ array must be empty, which means all
+// blocks are deallocated.
+bool QuicStreamSequencerBufferPeer::CheckEmptyInvariants() {
+ return !buffer_->Empty() || IsBlockArrayEmpty();
+}
+
+bool QuicStreamSequencerBufferPeer::IsBlockArrayEmpty() {
+ if (FLAGS_quic_reduce_sequencer_buffer_memory_life_time && // NOLINT
+ buffer_->blocks_ == nullptr) {
+ return true;
+ }
+
+ size_t count = buffer_->blocks_count_;
+ for (size_t i = 0; i < count; i++) {
+ if (buffer_->blocks_[i] != nullptr) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool QuicStreamSequencerBufferPeer::CheckInitialState() {
+ EXPECT_TRUE(buffer_->Empty() && buffer_->total_bytes_read_ == 0 &&
+ buffer_->num_bytes_buffered_ == 0);
+ return CheckBufferInvariants();
+}
+
+bool QuicStreamSequencerBufferPeer::CheckBufferInvariants() {
+ QuicStreamOffset data_span =
+ buffer_->gaps_.back().begin_offset - buffer_->total_bytes_read_;
+ bool capacity_sane = data_span <= buffer_->max_buffer_capacity_bytes_ &&
+ data_span >= buffer_->num_bytes_buffered_;
+ if (!capacity_sane) {
+ LOG(ERROR) << "data span is larger than capacity.";
+ LOG(ERROR) << "total read: " << buffer_->total_bytes_read_
+ << " last byte: " << buffer_->gaps_.back().begin_offset;
+ }
+ bool total_read_sane =
+ buffer_->gaps_.front().begin_offset >= buffer_->total_bytes_read_;
+ if (!total_read_sane) {
+ LOG(ERROR) << "read across 1st gap.";
+ }
+ bool read_offset_sane = buffer_->ReadOffset() < kBlockSizeBytes;
+ if (!capacity_sane) {
+ LOG(ERROR) << "read offset go beyond 1st block";
+ }
+ bool block_match_capacity = (buffer_->max_buffer_capacity_bytes_ <=
+ buffer_->blocks_count_ * kBlockSizeBytes) &&
+ (buffer_->max_buffer_capacity_bytes_ >
+ (buffer_->blocks_count_ - 1) * kBlockSizeBytes);
+ if (!capacity_sane) {
+ LOG(ERROR) << "block number not match capcaity.";
+ }
+ bool block_retired_when_empty = CheckEmptyInvariants();
+ if (!block_retired_when_empty) {
+ LOG(ERROR) << "block is not retired after use.";
+ }
+ return capacity_sane && total_read_sane && read_offset_sane &&
+ block_match_capacity && block_retired_when_empty;
+}
+
+size_t QuicStreamSequencerBufferPeer::GetInBlockOffset(
+ QuicStreamOffset offset) {
+ return buffer_->GetInBlockOffset(offset);
+}
+
+BufferBlock* QuicStreamSequencerBufferPeer::GetBlock(size_t index) {
+ return buffer_->blocks_[index];
+}
+
+int QuicStreamSequencerBufferPeer::GapSize() {
+ return buffer_->gaps_.size();
+}
+
+std::list<Gap> QuicStreamSequencerBufferPeer::GetGaps() {
+ return buffer_->gaps_;
+}
+
+size_t QuicStreamSequencerBufferPeer::max_buffer_capacity() {
+ return buffer_->max_buffer_capacity_bytes_;
+}
+
+size_t QuicStreamSequencerBufferPeer::ReadableBytes() {
+ return buffer_->ReadableBytes();
+}
+
+std::map<QuicStreamOffset, FrameInfo>*
+QuicStreamSequencerBufferPeer::frame_arrival_time_map() {
+ return &(buffer_->frame_arrival_time_map_);
+}
+
+void QuicStreamSequencerBufferPeer::set_total_bytes_read(
+ QuicStreamOffset total_bytes_read) {
+ buffer_->total_bytes_read_ = total_bytes_read;
+}
+
+void QuicStreamSequencerBufferPeer::set_gaps(const std::list<Gap>& gaps) {
+ buffer_->gaps_ = gaps;
+}
+
+bool QuicStreamSequencerBufferPeer::IsBufferAllocated() {
+ return buffer_->blocks_ != nullptr;
+}
+
+} // 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
new file mode 100644
index 00000000000..68944f52dce
--- /dev/null
+++ b/chromium/net/quic/test_tools/quic_stream_sequencer_buffer_peer.h
@@ -0,0 +1,63 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_TEST_TOOLS_QUIC_STREAM_SEQUENCER_BUFFER_PEER_H_
+#define NET_QUIC_TEST_TOOLS_QUIC_STREAM_SEQUENCER_BUFFER_PEER_H_
+
+#include "net/quic/core/quic_stream_sequencer_buffer.h"
+
+namespace net {
+
+namespace test {
+
+class QuicStreamSequencerBufferPeer {
+ public:
+ explicit QuicStreamSequencerBufferPeer(
+ net::QuicStreamSequencerBuffer* buffer);
+
+ // Read from this buffer_ into the given destination buffer_ up to the
+ // size of the destination. Returns the number of bytes read. Reading from
+ // an empty buffer_->returns 0.
+ size_t Read(char* dest_buffer, size_t size);
+
+ // If buffer is empty, the blocks_ array must be empty, which means all
+ // blocks are deallocated.
+ bool CheckEmptyInvariants();
+
+ bool IsBlockArrayEmpty();
+
+ bool CheckInitialState();
+
+ bool CheckBufferInvariants();
+
+ size_t GetInBlockOffset(QuicStreamOffset offset);
+
+ net::QuicStreamSequencerBuffer::BufferBlock* GetBlock(size_t index);
+
+ int GapSize();
+
+ std::list<net::QuicStreamSequencerBuffer::Gap> GetGaps();
+
+ size_t max_buffer_capacity();
+
+ size_t ReadableBytes();
+
+ std::map<QuicStreamOffset, net::QuicStreamSequencerBuffer::FrameInfo>*
+ frame_arrival_time_map();
+
+ void set_total_bytes_read(QuicStreamOffset total_bytes_read);
+
+ void set_gaps(const std::list<net::QuicStreamSequencerBuffer::Gap>& gaps);
+
+ bool IsBufferAllocated();
+
+ private:
+ net::QuicStreamSequencerBuffer* buffer_;
+ DISALLOW_COPY_AND_ASSIGN(QuicStreamSequencerBufferPeer);
+};
+
+} // namespace test
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_QUIC_STREAM_SEQUENCER_BUFFER_PEER_H_
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 739db22b4f2..d78543b0465 100644
--- a/chromium/net/quic/test_tools/quic_stream_sequencer_peer.cc
+++ b/chromium/net/quic/test_tools/quic_stream_sequencer_peer.cc
@@ -4,7 +4,8 @@
#include "net/quic/test_tools/quic_stream_sequencer_peer.h"
-#include "net/quic/quic_stream_sequencer.h"
+#include "net/quic/core/quic_stream_sequencer.h"
+#include "net/quic/test_tools/quic_stream_sequencer_buffer_peer.h"
using std::map;
using std::string;
@@ -24,5 +25,12 @@ QuicStreamOffset QuicStreamSequencerPeer::GetCloseOffset(
return sequencer->close_offset_;
}
+// static
+bool QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(
+ QuicStreamSequencer* sequencer) {
+ QuicStreamSequencerBufferPeer buffer_peer(&(sequencer->buffered_frames_));
+ return buffer_peer.IsBufferAllocated();
+}
+
} // 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 f5307e1f53a..aa8773cb8b5 100644
--- a/chromium/net/quic/test_tools/quic_stream_sequencer_peer.h
+++ b/chromium/net/quic/test_tools/quic_stream_sequencer_peer.h
@@ -8,7 +8,7 @@
#include <stddef.h>
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
@@ -22,6 +22,8 @@ class QuicStreamSequencerPeer {
static QuicStreamOffset GetCloseOffset(QuicStreamSequencer* sequencer);
+ static bool IsUnderlyingBufferAllocated(QuicStreamSequencer* sequencer);
+
private:
DISALLOW_COPY_AND_ASSIGN(QuicStreamSequencerPeer);
};
diff --git a/chromium/net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.cc b/chromium/net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.cc
index 6779aeac434..6a70fa9310a 100644
--- a/chromium/net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.cc
+++ b/chromium/net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.cc
@@ -4,8 +4,8 @@
#include "net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_sustained_bandwidth_recorder.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_sustained_bandwidth_recorder.h"
namespace net {
namespace test {
diff --git a/chromium/net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h b/chromium/net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h
index 186dbb65102..4a0669a6405 100644
--- a/chromium/net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h
+++ b/chromium/net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h
@@ -8,7 +8,7 @@
#include <stdint.h>
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
diff --git a/chromium/net/quic/test_tools/quic_test_packet_maker.cc b/chromium/net/quic/test_tools/quic_test_packet_maker.cc
index 73d6fec01cc..7590208e097 100644
--- a/chromium/net/quic/test_tools/quic_test_packet_maker.cc
+++ b/chromium/net/quic/test_tools/quic_test_packet_maker.cc
@@ -8,9 +8,9 @@
#include <utility>
#include "base/memory/ptr_util.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_http_utils.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_http_utils.h"
+#include "net/quic/core/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
using std::make_pair;
@@ -296,6 +296,7 @@ std::unique_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeDataPacket(
base::StringPiece data) {
InitializeHeader(packet_number, should_include_version);
QuicStreamFrame frame(stream_id, fin, offset, data);
+ DVLOG(1) << "Adding frame: " << frame;
return MakePacket(header_, QuicFrame(&frame));
}
@@ -314,8 +315,8 @@ QuicTestPacketMaker::MakeMultipleDataFramesPacket(
std::vector<std::unique_ptr<QuicStreamFrame>> stream_frames;
for (size_t i = 0; i < data_writes.size(); ++i) {
bool is_fin = fin && (i == data_writes.size() - 1);
- stream_frames.push_back(base::WrapUnique(new QuicStreamFrame(
- stream_id, is_fin, offset, base::StringPiece(data_writes[i]))));
+ stream_frames.push_back(base::MakeUnique<QuicStreamFrame>(
+ stream_id, is_fin, offset, base::StringPiece(data_writes[i])));
offset += data_writes[i].length();
}
for (const auto& stream_frame : stream_frames) {
@@ -399,8 +400,8 @@ QuicTestPacketMaker::MakeRequestHeadersAndMultipleDataFramesPacket(
std::vector<std::unique_ptr<QuicStreamFrame>> stream_frames;
for (size_t i = 0; i < data_writes.size(); ++i) {
bool is_fin = fin && (i == data_writes.size() - 1);
- stream_frames.push_back(base::WrapUnique(new QuicStreamFrame(
- stream_id, is_fin, offset, base::StringPiece(data_writes[i]))));
+ stream_frames.push_back(base::MakeUnique<QuicStreamFrame>(
+ stream_id, is_fin, offset, base::StringPiece(data_writes[i])));
offset += data_writes[i].length();
}
for (const auto& stream_frame : stream_frames) {
@@ -518,6 +519,24 @@ std::unique_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakePushPromisePacket(
}
}
+std::unique_ptr<QuicReceivedPacket> QuicTestPacketMaker::MakeForceHolDataPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool should_include_version,
+ bool fin,
+ QuicStreamOffset* offset,
+ base::StringPiece data) {
+ SpdyDataIR spdy_data(stream_id, data);
+ spdy_data.set_fin(fin);
+ SpdySerializedFrame spdy_frame(
+ spdy_request_framer_.SerializeFrame(spdy_data));
+ InitializeHeader(packet_number, should_include_version);
+ QuicStreamFrame quic_frame(kHeadersStreamId, false, *offset,
+ StringPiece(spdy_frame.data(), spdy_frame.size()));
+ *offset += spdy_frame.size();
+ return MakePacket(header_, QuicFrame(&quic_frame));
+}
+
// If |offset| is provided, will use the value when creating the packet.
// Will also update the value after packet creation.
std::unique_ptr<QuicReceivedPacket>
@@ -610,7 +629,7 @@ SpdyHeaderBlock QuicTestPacketMaker::GetResponseHeaders(
const std::string& alt_svc) {
SpdyHeaderBlock headers;
headers[":status"] = status;
- headers["Alt-Svc"] = alt_svc;
+ headers["alt-svc"] = alt_svc;
headers["content-type"] = "text/plain";
return headers;
}
diff --git a/chromium/net/quic/test_tools/quic_test_packet_maker.h b/chromium/net/quic/test_tools/quic_test_packet_maker.h
index 1668072cd04..995b74841f6 100644
--- a/chromium/net/quic/test_tools/quic_test_packet_maker.h
+++ b/chromium/net/quic/test_tools/quic_test_packet_maker.h
@@ -15,7 +15,7 @@
#include "base/macros.h"
#include "net/base/request_priority.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/quic/test_tools/mock_clock.h"
#include "net/quic/test_tools/mock_random.h"
#include "net/spdy/spdy_framer.h"
@@ -90,6 +90,13 @@ class QuicTestPacketMaker {
bool fin,
QuicStreamOffset offset,
base::StringPiece data);
+ std::unique_ptr<QuicReceivedPacket> MakeForceHolDataPacket(
+ QuicPacketNumber packet_number,
+ QuicStreamId stream_id,
+ bool should_include_version,
+ bool fin,
+ QuicStreamOffset* offset,
+ base::StringPiece data);
std::unique_ptr<QuicReceivedPacket> MakeMultipleDataFramesPacket(
QuicPacketNumber packet_number,
QuicStreamId stream_id,
diff --git a/chromium/net/quic/test_tools/quic_test_utils.cc b/chromium/net/quic/test_tools/quic_test_utils.cc
index fd5aa947142..28f7115655e 100644
--- a/chromium/net/quic/test_tools/quic_test_utils.cc
+++ b/chromium/net/quic/test_tools/quic_test_utils.cc
@@ -9,16 +9,16 @@
#include "base/sha1.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
-#include "net/quic/crypto/crypto_framer.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/crypto_utils.h"
-#include "net/quic/crypto/null_encrypter.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/quic_data_writer.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_packet_creator.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/crypto_framer.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/crypto_utils.h"
+#include "net/quic/core/crypto/null_encrypter.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_data_writer.h"
+#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/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/spdy/spdy_frame_builder.h"
@@ -97,6 +97,18 @@ QuicPacket* BuildUnsizedDataPacket(QuicFramer* framer,
header.public_header.packet_number_length);
}
+QuicFlagSaver::QuicFlagSaver() {
+#define QUIC_FLAG(type, flag, value) CHECK_EQ(value, flag);
+#include "net/quic/core/quic_flags_list.h"
+#undef QUIC_FLAG
+}
+
+QuicFlagSaver::~QuicFlagSaver() {
+#define QUIC_FLAG(type, flag, value) flag = value;
+#include "net/quic/core/quic_flags_list.h"
+#undef QUIC_FLAG
+}
+
uint64_t SimpleRandom::RandUint64() {
unsigned char hash[base::kSHA1Length];
base::SHA1HashBytes(reinterpret_cast<unsigned char*>(&seed_), sizeof(seed_),
@@ -105,6 +117,22 @@ uint64_t SimpleRandom::RandUint64() {
return seed_;
}
+void SimpleRandom::RandBytes(void* data, size_t len) {
+ uint8_t* real_data = static_cast<uint8_t*>(data);
+ for (size_t offset = 0; offset < len; offset++) {
+ real_data[offset] = RandUint64() & 0xff;
+ }
+}
+
+void SimpleRandom::Reseed(const void* additional_entropy, size_t len) {
+ const uint8_t* real_entropy = static_cast<const uint8_t*>(additional_entropy);
+ for (size_t offset = 0; offset < len; offset++) {
+ // Note: this is not actually a well-established way to incorporate new
+ // entropy, but good enough for tests.
+ seed_ *= real_entropy[len];
+ }
+}
+
MockFramerVisitor::MockFramerVisitor() {
// By default, we want to accept packets.
ON_CALL(*this, OnProtocolVersionMismatch(_))
@@ -251,7 +279,7 @@ MockQuicConnection::MockQuicConnection(MockQuicConnectionHelper* helper,
helper,
alarm_factory,
perspective,
- QuicSupportedVersions()) {}
+ AllSupportedVersions()) {}
MockQuicConnection::MockQuicConnection(IPEndPoint address,
MockQuicConnectionHelper* helper,
@@ -262,7 +290,7 @@ MockQuicConnection::MockQuicConnection(IPEndPoint address,
helper,
alarm_factory,
perspective,
- QuicSupportedVersions()) {}
+ AllSupportedVersions()) {}
MockQuicConnection::MockQuicConnection(QuicConnectionId connection_id,
MockQuicConnectionHelper* helper,
@@ -273,7 +301,7 @@ MockQuicConnection::MockQuicConnection(QuicConnectionId connection_id,
helper,
alarm_factory,
perspective,
- QuicSupportedVersions()) {}
+ CurrentSupportedVersions()) {}
MockQuicConnection::MockQuicConnection(
MockQuicConnectionHelper* helper,
@@ -329,7 +357,7 @@ PacketSavingConnection::PacketSavingConnection(
supported_versions) {}
PacketSavingConnection::~PacketSavingConnection() {
- STLDeleteElements(&encrypted_packets_);
+ base::STLDeleteElements(&encrypted_packets_);
}
void PacketSavingConnection::SendOrQueuePacket(SerializedPacket* packet) {
@@ -350,7 +378,9 @@ MockQuicSession::MockQuicSession(QuicConnection* connection)
.WillByDefault(testing::Return(QuicConsumedData(0, false)));
}
-MockQuicSession::~MockQuicSession() {}
+MockQuicSession::~MockQuicSession() {
+ delete connection();
+}
// static
QuicConsumedData MockQuicSession::ConsumeAllData(
@@ -371,7 +401,9 @@ MockQuicSpdySession::MockQuicSpdySession(QuicConnection* connection)
.WillByDefault(testing::Return(QuicConsumedData(0, false)));
}
-MockQuicSpdySession::~MockQuicSpdySession() {}
+MockQuicSpdySession::~MockQuicSpdySession() {
+ delete connection();
+}
TestQuicSpdyServerSession::TestQuicSpdyServerSession(
QuicConnection* connection,
@@ -392,7 +424,9 @@ TestQuicSpdyServerSession::TestQuicSpdyServerSession(
.WillByDefault(testing::Return(true));
}
-TestQuicSpdyServerSession::~TestQuicSpdyServerSession() {}
+TestQuicSpdyServerSession::~TestQuicSpdyServerSession() {
+ delete connection();
+}
QuicCryptoServerStreamBase*
TestQuicSpdyServerSession::CreateQuicCryptoServerStream(
@@ -400,7 +434,7 @@ TestQuicSpdyServerSession::CreateQuicCryptoServerStream(
QuicCompressedCertsCache* compressed_certs_cache) {
return new QuicCryptoServerStream(crypto_config, compressed_certs_cache,
FLAGS_enable_quic_stateless_reject_support,
- this);
+ this, &helper_);
}
QuicCryptoServerStream* TestQuicSpdyServerSession::GetCryptoStream() {
@@ -502,11 +536,11 @@ IPAddress TestPeerIPAddress() {
}
QuicVersion QuicVersionMax() {
- return QuicSupportedVersions().front();
+ return AllSupportedVersions().front();
}
QuicVersion QuicVersionMin() {
- return QuicSupportedVersions().back();
+ return AllSupportedVersions().back();
}
IPAddress Loopback4() {
@@ -601,8 +635,9 @@ QuicEncryptedPacket* ConstructEncryptedPacket(
QuicFrame frame(&stream_frame);
QuicFrames frames;
frames.push_back(frame);
- QuicFramer framer(versions != nullptr ? *versions : QuicSupportedVersions(),
- QuicTime::Zero(), perspective);
+ QuicFramer framer(
+ versions != nullptr ? *versions : CurrentSupportedVersions(),
+ QuicTime::Zero(), perspective);
std::unique_ptr<QuicPacket> packet(
BuildUnsizedDataPacket(&framer, header, frames));
@@ -651,7 +686,7 @@ QuicEncryptedPacket* ConstructMisFramedEncryptedPacket(
QuicFrame frame(&stream_frame);
QuicFrames frames;
frames.push_back(frame);
- QuicFramer framer(versions != nullptr ? *versions : QuicSupportedVersions(),
+ QuicFramer framer(versions != nullptr ? *versions : AllSupportedVersions(),
QuicTime::Zero(), perspective);
std::unique_ptr<QuicPacket> packet(
@@ -730,7 +765,7 @@ static QuicPacket* ConstructPacketFromHandshakeMessage(
CryptoFramer crypto_framer;
std::unique_ptr<QuicData> data(
crypto_framer.ConstructHandshakeMessage(message));
- QuicFramer quic_framer(QuicSupportedVersions(), QuicTime::Zero(),
+ QuicFramer quic_framer(AllSupportedVersions(), QuicTime::Zero(),
Perspective::IS_CLIENT);
QuicPacketHeader header;
@@ -832,6 +867,14 @@ MockReceivedPacketManager::MockReceivedPacketManager(QuicConnectionStats* stats)
MockReceivedPacketManager::~MockReceivedPacketManager() {}
+MockSentPacketManager::MockSentPacketManager() {}
+
+MockSentPacketManager::~MockSentPacketManager() {}
+
+MockConnectionCloseDelegate::MockConnectionCloseDelegate() {}
+
+MockConnectionCloseDelegate::~MockConnectionCloseDelegate() {}
+
void CreateClientSessionForTest(QuicServerId server_id,
bool supports_stateless_rejects,
QuicTime::Delta connection_start_time,
diff --git a/chromium/net/quic/test_tools/quic_test_utils.h b/chromium/net/quic/test_tools/quic_test_utils.h
index dd0d83d2b21..767c38481db 100644
--- a/chromium/net/quic/test_tools/quic_test_utils.h
+++ b/chromium/net/quic/test_tools/quic_test_utils.h
@@ -19,16 +19,16 @@
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "net/base/ip_address.h"
-#include "net/quic/congestion_control/loss_detection_interface.h"
-#include "net/quic/congestion_control/send_algorithm_interface.h"
-#include "net/quic/quic_client_push_promise_index.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_sent_packet_manager_interface.h"
-#include "net/quic/quic_server_session_base.h"
-#include "net/quic/quic_session.h"
-#include "net/quic/quic_simple_buffer_allocator.h"
+#include "net/quic/core/congestion_control/loss_detection_interface.h"
+#include "net/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/quic/core/quic_client_push_promise_index.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_sent_packet_manager_interface.h"
+#include "net/quic/core/quic_server_session_base.h"
+#include "net/quic/core/quic_session.h"
+#include "net/quic/core/quic_simple_buffer_allocator.h"
#include "net/quic/test_tools/mock_clock.h"
#include "net/quic/test_tools/mock_random.h"
#include "net/spdy/spdy_framer.h"
@@ -39,12 +39,18 @@
using base::StringPiece;
+// EXPECT_QUIC_BUG is like EXPECT_DFATAL, except it ensures that no DFATAL
+// logging is skipped due to exponential backoff.
+//
+// For external QUIC, EXPECT_QUIC_BUG should be #defined to EXPECT_DFATAL.
+#define EXPECT_QUIC_BUG EXPECT_DFATAL
+
namespace net {
namespace test {
static const QuicConnectionId kTestConnectionId = 42;
-static const uint16_t kTestPort = 123;
+static const uint16_t kTestPort = 12345;
static const uint32_t kInitialStreamFlowControlWindowForTest =
1024 * 1024; // 1 MB
static const uint32_t kInitialSessionFlowControlWindowForTest =
@@ -76,7 +82,7 @@ IPAddress Any4();
void GenerateBody(std::string* body, int length);
// Create an encrypted packet for testing.
-// If versions == nullptr, uses &QuicSupportedVersions().
+// 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(
@@ -93,7 +99,7 @@ QuicEncryptedPacket* ConstructEncryptedPacket(
Perspective perspective);
// Create an encrypted packet for testing.
-// If versions == nullptr, uses &QuicSupportedVersions().
+// 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(
@@ -209,31 +215,28 @@ QuicPacket* BuildUnsizedDataPacket(QuicFramer* framer,
const QuicFrames& frames,
size_t packet_size);
-template <typename SaveType>
-class ValueRestore {
+// When constructed, checks that all QUIC flags have their correct default
+// values and when destructed, restores those values.
+class QuicFlagSaver {
public:
- ValueRestore(SaveType* name, SaveType value) : name_(name), value_(*name) {
- *name_ = value;
- }
- ~ValueRestore() { *name_ = value_; }
-
- private:
- SaveType* name_;
- SaveType value_;
-
- DISALLOW_COPY_AND_ASSIGN(ValueRestore);
+ QuicFlagSaver();
+ ~QuicFlagSaver();
};
// Simple random number generator used to compute random numbers suitable
// for pseudo-randomly dropping packets in tests. It works by computing
// the sha1 hash of the current seed, and using the first 64 bits as
// the next random number, and the next seed.
-class SimpleRandom {
+class SimpleRandom : public QuicRandom {
public:
SimpleRandom() : seed_(0) {}
+ ~SimpleRandom() override {}
// Returns a random number in the range [0, kuint64max].
- uint64_t RandUint64();
+ uint64_t RandUint64() override;
+
+ void RandBytes(void* data, size_t len) override;
+ void Reseed(const void* additional_entropy, size_t len) override;
void set_seed(uint64_t seed) { seed_ = seed; }
@@ -432,8 +435,10 @@ class MockQuicConnection : public QuicConnection {
void(QuicErrorCode error,
const std::string& details,
ConnectionCloseBehavior connection_close_behavior));
- MOCK_METHOD2(SendConnectionClosePacket,
- void(QuicErrorCode error, const std::string& details));
+ MOCK_METHOD3(SendConnectionClosePacket,
+ void(QuicErrorCode error,
+ const std::string& details,
+ AckBundling ack_mode));
MOCK_METHOD3(SendRstStream,
void(QuicStreamId id,
QuicRstStreamErrorCode error,
@@ -498,6 +503,7 @@ class PacketSavingConnection : public MockQuicConnection {
class MockQuicSession : public QuicSession {
public:
+ // Takes ownership of |connection|.
explicit MockQuicSession(QuicConnection* connection);
~MockQuicSession() override;
@@ -554,6 +560,7 @@ class MockQuicSession : public QuicSession {
class MockQuicSpdySession : public QuicSpdySession {
public:
+ // Takes ownership of |connection|.
explicit MockQuicSpdySession(QuicConnection* connection);
~MockQuicSpdySession() override;
@@ -625,6 +632,9 @@ class MockQuicSpdySession : public QuicSpdySession {
SpdyPriority priority,
QuicAckListenerInterface* ack_notifier_delegate));
MOCK_METHOD1(OnHeadersHeadOfLineBlocking, void(QuicTime::Delta delta));
+ MOCK_METHOD4(
+ OnStreamFrameData,
+ void(QuicStreamId stream_id, const char* data, size_t len, bool fin));
using QuicSession::ActivateStream;
@@ -637,6 +647,7 @@ class MockQuicSpdySession : public QuicSpdySession {
class TestQuicSpdyServerSession : public QuicServerSessionBase {
public:
+ // Takes ownership of |connection|.
TestQuicSpdyServerSession(QuicConnection* connection,
const QuicConfig& config,
const QuicCryptoServerConfig* crypto_config,
@@ -652,11 +663,11 @@ class TestQuicSpdyServerSession : public QuicServerSessionBase {
QuicCryptoServerStream* GetCryptoStream() override;
- MockQuicServerSessionHelper* helper() { return &helper_; }
+ MockQuicCryptoServerStreamHelper* helper() { return &helper_; }
private:
MockQuicServerSessionVisitor visitor_;
- MockQuicServerSessionHelper helper_;
+ MockQuicCryptoServerStreamHelper helper_;
DISALLOW_COPY_AND_ASSIGN(TestQuicSpdyServerSession);
};
@@ -745,14 +756,15 @@ class MockSendAlgorithm : public SendAlgorithmInterface {
MOCK_CONST_METHOD0(BandwidthEstimate, QuicBandwidth(void));
MOCK_CONST_METHOD0(HasReliableBandwidthEstimate, bool());
MOCK_METHOD1(OnRttUpdated, void(QuicPacketNumber));
- MOCK_CONST_METHOD0(RetransmissionDelay, QuicTime::Delta(void));
MOCK_CONST_METHOD0(GetCongestionWindow, QuicByteCount());
+ MOCK_CONST_METHOD0(GetDebugState, std::string());
MOCK_CONST_METHOD0(InSlowStart, bool());
MOCK_CONST_METHOD0(InRecovery, bool());
MOCK_CONST_METHOD0(GetSlowStartThreshold, QuicByteCount());
MOCK_CONST_METHOD0(GetCongestionControlType, CongestionControlType());
MOCK_METHOD2(ResumeConnectionState,
void(const CachedNetworkParameters&, bool));
+ MOCK_METHOD1(OnApplicationLimited, void(QuicByteCount));
private:
DISALLOW_COPY_AND_ASSIGN(MockSendAlgorithm);
@@ -851,6 +863,8 @@ class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor {
TransmissionType,
QuicTime));
+ MOCK_METHOD0(OnPingSent, void());
+
MOCK_METHOD3(OnPacketReceived,
void(const IPEndPoint&,
const IPEndPoint&,
@@ -885,10 +899,8 @@ class MockReceivedPacketManager : public QuicReceivedPacketManager {
explicit MockReceivedPacketManager(QuicConnectionStats* stats);
~MockReceivedPacketManager() override;
- MOCK_METHOD3(RecordPacketReceived,
- void(QuicByteCount bytes,
- const QuicPacketHeader& header,
- QuicTime receipt_time));
+ MOCK_METHOD2(RecordPacketReceived,
+ void(const QuicPacketHeader& header, QuicTime receipt_time));
MOCK_METHOD1(IsMissing, bool(QuicPacketNumber packet_number));
MOCK_METHOD1(IsAwaitingPacket, bool(QuicPacketNumber packet_number));
MOCK_METHOD1(UpdatePacketInformationSentByPeer,
@@ -897,6 +909,71 @@ class MockReceivedPacketManager : public QuicReceivedPacketManager {
MOCK_CONST_METHOD0(ack_frame_updated, bool(void));
};
+class MockSentPacketManager : public QuicSentPacketManagerInterface {
+ public:
+ MockSentPacketManager();
+ ~MockSentPacketManager() override;
+
+ MOCK_METHOD1(SetFromConfig, void(const QuicConfig&));
+ MOCK_METHOD2(ResumeConnectionState,
+ void(const CachedNetworkParameters&, bool));
+ MOCK_METHOD1(SetNumOpenStreams, void(size_t));
+ MOCK_METHOD1(SetMaxPacingRate, void(QuicBandwidth));
+ MOCK_METHOD0(SetHandshakeConfirmed, void(void));
+ MOCK_METHOD2(OnIncomingAck, void(const QuicAckFrame&, QuicTime));
+ MOCK_METHOD1(RetransmitUnackedPackets, void(TransmissionType));
+ MOCK_METHOD0(MaybeRetransmitTailLossProbe, bool(void));
+ MOCK_METHOD0(NeuterUnencryptedPackets, void(void));
+ MOCK_CONST_METHOD0(HasPendingRetransmissions, bool(void));
+ MOCK_METHOD0(NextPendingRetransmission, PendingRetransmission(void));
+ MOCK_CONST_METHOD0(HasUnackedPackets, bool(void));
+ MOCK_CONST_METHOD1(GetLeastUnacked, QuicPacketNumber(QuicPathId));
+ MOCK_METHOD6(OnPacketSent,
+ bool(SerializedPacket*,
+ QuicPathId,
+ QuicPacketNumber,
+ QuicTime,
+ TransmissionType,
+ HasRetransmittableData));
+ MOCK_METHOD0(OnRetransmissionTimeout, void(void));
+ MOCK_METHOD2(TimeUntilSend, QuicTime::Delta(QuicTime, QuicPathId*));
+ MOCK_CONST_METHOD0(GetRetransmissionTime, const QuicTime(void));
+ MOCK_CONST_METHOD0(GetRttStats, const RttStats*(void));
+ MOCK_CONST_METHOD0(BandwidthEstimate, QuicBandwidth(void));
+ MOCK_CONST_METHOD0(SustainedBandwidthRecorder,
+ const QuicSustainedBandwidthRecorder*(void));
+ MOCK_CONST_METHOD0(GetCongestionWindowInTcpMss, QuicPacketCount(void));
+ MOCK_CONST_METHOD1(EstimateMaxPacketsInFlight,
+ QuicPacketCount(QuicByteCount));
+ MOCK_CONST_METHOD0(GetCongestionWindowInBytes, QuicByteCount(void));
+ MOCK_CONST_METHOD0(GetSlowStartThresholdInTcpMss, QuicPacketCount(void));
+ MOCK_CONST_METHOD0(GetDebugState, std::string());
+ MOCK_METHOD1(CancelRetransmissionsForStream, void(QuicStreamId));
+ MOCK_METHOD2(OnConnectionMigration, void(QuicPathId, PeerAddressChangeType));
+ MOCK_CONST_METHOD0(IsHandshakeConfirmed, bool(void));
+ MOCK_METHOD1(SetDebugDelegate, void(DebugDelegate*));
+ MOCK_CONST_METHOD1(GetLargestObserved, QuicPacketNumber(QuicPathId));
+ MOCK_CONST_METHOD1(GetLargestSentPacket, QuicPacketNumber(QuicPathId));
+ MOCK_CONST_METHOD1(GetLeastPacketAwaitedByPeer, QuicPacketNumber(QuicPathId));
+ MOCK_METHOD1(SetNetworkChangeVisitor, void(NetworkChangeVisitor*));
+ MOCK_CONST_METHOD0(InSlowStart, bool(void));
+ MOCK_CONST_METHOD0(GetConsecutiveRtoCount, size_t(void));
+ MOCK_CONST_METHOD0(GetConsecutiveTlpCount, size_t(void));
+ MOCK_METHOD0(OnApplicationLimited, void(void));
+};
+
+class MockConnectionCloseDelegate
+ : public QuicConnectionCloseDelegateInterface {
+ public:
+ MockConnectionCloseDelegate();
+ ~MockConnectionCloseDelegate() override;
+
+ MOCK_METHOD3(OnUnrecoverableError,
+ void(QuicErrorCode,
+ const std::string&,
+ ConnectionCloseSource source));
+};
+
// Creates a client session for testing.
//
// server_id: The server id associated with this stream.
@@ -953,6 +1030,22 @@ void CreateServerSessionForTest(
// kClientDataStreamId1 etc. above.
QuicStreamId QuicClientDataStreamId(int i);
+// Verifies that the relative error of |actual| with respect to |expected| is
+// no more than |margin|.
+
+template <typename T>
+void ExpectApproxEq(T expected, T actual, float relative_margin) {
+ // If |relative_margin| > 1 and T is an unsigned type, the comparison will
+ // underflow.
+ ASSERT_LE(relative_margin, 1);
+ ASSERT_GE(relative_margin, 0);
+
+ T absolute_margin = expected * relative_margin;
+
+ EXPECT_GE(expected + absolute_margin, actual);
+ EXPECT_LE(expected - absolute_margin, actual);
+}
+
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/test_tools/quic_test_utils_test.cc b/chromium/net/quic/test_tools/quic_test_utils_test.cc
new file mode 100644
index 00000000000..6d4fb2766a6
--- /dev/null
+++ b/chromium/net/quic/test_tools/quic_test_utils_test.cc
@@ -0,0 +1,41 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/test_tools/quic_test_utils.h"
+
+#include "testing/gtest/include/gtest/gtest-spi.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+TEST(QuicTestUtilsTest, BasicApproxEq) {
+ ExpectApproxEq(10, 10, 1e-6f);
+ ExpectApproxEq(1000, 1001, 0.01f);
+ EXPECT_NONFATAL_FAILURE(ExpectApproxEq(1000, 1100, 0.01f), "");
+
+ ExpectApproxEq(64, 31, 0.55f);
+ EXPECT_NONFATAL_FAILURE(ExpectApproxEq(31, 64, 0.55f), "");
+}
+
+TEST(QuicTestUtilsTest, QuicTimeDelta) {
+ ExpectApproxEq(QuicTime::Delta::FromMicroseconds(1000),
+ QuicTime::Delta::FromMicroseconds(1003), 0.01f);
+ EXPECT_NONFATAL_FAILURE(
+ ExpectApproxEq(QuicTime::Delta::FromMicroseconds(1000),
+ QuicTime::Delta::FromMicroseconds(1200), 0.01f),
+ "");
+}
+
+TEST(QuicTestUtilsTest, QuicBandwidth) {
+ ExpectApproxEq(QuicBandwidth::FromBytesPerSecond(1000),
+ QuicBandwidth::FromBitsPerSecond(8005), 0.01f);
+ EXPECT_NONFATAL_FAILURE(
+ ExpectApproxEq(QuicBandwidth::FromBytesPerSecond(1000),
+ QuicBandwidth::FromBitsPerSecond(9005), 0.01f),
+ "");
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/quic/test_tools/reliable_quic_stream_peer.cc b/chromium/net/quic/test_tools/reliable_quic_stream_peer.cc
index 2b419bfd93a..f8003138bcd 100644
--- a/chromium/net/quic/test_tools/reliable_quic_stream_peer.cc
+++ b/chromium/net/quic/test_tools/reliable_quic_stream_peer.cc
@@ -6,7 +6,7 @@
#include <list>
-#include "net/quic/reliable_quic_stream.h"
+#include "net/quic/core/reliable_quic_stream.h"
using base::StringPiece;
@@ -93,5 +93,11 @@ void ReliableQuicStreamPeer::WriteOrBufferData(
stream->WriteOrBufferData(data, fin, ack_notifier_delegate);
}
+// static
+net::QuicStreamSequencer* ReliableQuicStreamPeer::sequencer(
+ ReliableQuicStream* stream) {
+ return &(stream->sequencer_);
+}
+
} // namespace test
} // namespace net
diff --git a/chromium/net/quic/test_tools/reliable_quic_stream_peer.h b/chromium/net/quic/test_tools/reliable_quic_stream_peer.h
index 04bbe7b4cce..522049e09fa 100644
--- a/chromium/net/quic/test_tools/reliable_quic_stream_peer.h
+++ b/chromium/net/quic/test_tools/reliable_quic_stream_peer.h
@@ -9,7 +9,8 @@
#include "base/macros.h"
#include "base/strings/string_piece.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_stream_sequencer.h"
namespace net {
@@ -44,6 +45,8 @@ class ReliableQuicStreamPeer {
bool fin,
QuicAckListenerInterface* ack_notifier_delegate);
+ static net::QuicStreamSequencer* sequencer(ReliableQuicStream* stream);
+
private:
DISALLOW_COPY_AND_ASSIGN(ReliableQuicStreamPeer);
};
diff --git a/chromium/net/quic/test_tools/rtt_stats_peer.h b/chromium/net/quic/test_tools/rtt_stats_peer.h
index fed235b60e5..296be82416a 100644
--- a/chromium/net/quic/test_tools/rtt_stats_peer.h
+++ b/chromium/net/quic/test_tools/rtt_stats_peer.h
@@ -6,8 +6,8 @@
#define NET_QUIC_TEST_TOOLS_RTT_STATS_PEER_H_
#include "base/macros.h"
-#include "net/quic/congestion_control/rtt_stats.h"
-#include "net/quic/quic_time.h"
+#include "net/quic/core/congestion_control/rtt_stats.h"
+#include "net/quic/core/quic_time.h"
namespace net {
namespace test {
diff --git a/chromium/net/quic/test_tools/simple_quic_framer.cc b/chromium/net/quic/test_tools/simple_quic_framer.cc
index 5fc13a30c34..2dcd179b28a 100644
--- a/chromium/net/quic/test_tools/simple_quic_framer.cc
+++ b/chromium/net/quic/test_tools/simple_quic_framer.cc
@@ -8,8 +8,8 @@
#include "base/macros.h"
#include "base/stl_util.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
using base::StringPiece;
using std::string;
@@ -23,8 +23,8 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface {
SimpleFramerVisitor() : error_(QUIC_NO_ERROR) {}
~SimpleFramerVisitor() override {
- STLDeleteElements(&stream_frames_);
- STLDeleteElements(&stream_data_);
+ base::STLDeleteElements(&stream_frames_);
+ base::STLDeleteElements(&stream_data_);
}
void OnError(QuicFramer* framer) override { error_ = framer->error(); }
@@ -163,7 +163,7 @@ class SimpleFramerVisitor : public QuicFramerVisitorInterface {
};
SimpleQuicFramer::SimpleQuicFramer()
- : framer_(QuicSupportedVersions(),
+ : framer_(AllSupportedVersions(),
QuicTime::Zero(),
Perspective::IS_SERVER) {}
diff --git a/chromium/net/quic/test_tools/simple_quic_framer.h b/chromium/net/quic/test_tools/simple_quic_framer.h
index 2247aef51f3..026c7a82025 100644
--- a/chromium/net/quic/test_tools/simple_quic_framer.h
+++ b/chromium/net/quic/test_tools/simple_quic_framer.h
@@ -12,8 +12,8 @@
#include "base/macros.h"
#include "base/strings/string_piece.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
diff --git a/chromium/net/quic/test_tools/simulator/README.md b/chromium/net/quic/test_tools/simulator/README.md
new file mode 100644
index 00000000000..02ffa0a1c37
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/README.md
@@ -0,0 +1,98 @@
+# QUIC network simulator
+
+This directory contains a discrete event network simulator which QUIC code uses
+for testing congestion control and other transmission control code that requires
+a network simulation for tests on QuicConnection level of abstraction.
+
+## Actors
+
+The core of the simulator is the Simulator class, which maintains a virtual
+clock and an event queue. Any object in a simulation that needs to schedule
+events has to subclass Actor. Subclassing Actor involves:
+
+1. Calling the `Actor::Actor(Simulator*, std::string)` constructor to establish
+ the name of the object and the simulator it is associated with.
+2. Calling `Schedule(QuicTime)` to schedule the time at which `Act()` method is
+ called. `Schedule` will only cause the object to be rescheduled if the time
+ for which it is currently scheduled is later than the new time.
+3. Implementing `Act()` method with the relevant logic. The actor will be
+ removed from the event queue right before `Act()` is called.
+
+Here is a simple example of an object that outputs simulation time into the log
+every 100 ms.
+
+```c++
+class LogClock : public Actor {
+ public:
+ LogClock(Simulator* simulator, std::string name) : Actor(simulator, name) {
+ Schedule(clock_->Now());
+ }
+ ~LogClock() override {}
+
+ void Act() override {
+ VLOG(1) << "The current time is " << clock_->Now().ToDebuggingValue();
+ Schedule(clock_->Now() + QuicTime::Delta::FromMilliseconds(100));
+ }
+};
+```
+
+A QuicAlarm object can be used to schedule events in the simulation using
+`Simulator::GetAlarmFactory()`.
+
+## Ports
+
+The simulated network transfers packets, which are modelled as an instance of
+struct `Packet`. A packet consists of source and destination address (which are
+just plain strings), a transmission timestamp and the UDP-layer payload.
+
+The simulation uses the push model: any object that wishes to transfer a packet
+to another component in the simulation has to explicitly do it itself. Any
+object that can accept a packet is called a *port*. There are two types of
+ports: unconstrained ports, which can always accept packets, and constrained
+ports, which signal when they can accept a new packet.
+
+An endpoint is an object that is connected to the network and can both receive
+and send packets. In our model, the endpoint always receives packets as an
+unconstrained port (*RX port*), and always writes packets to a constrained port
+(*TX port*).
+
+## Links
+
+The `SymmetricLink` class models a symmetric duplex links with finite bandwidth
+and propagation delay. It consists of a pair of identical `OneWayLink`s, which
+accept packets as a constrained port (where constrain comes from the finiteness
+of bandwidth) and outputs them into an unconstrained port. Two endpoints
+connected via a `SymmetricLink` look like this:
+
+```none
+ Endpoint A Endpoint B
++-----------+ SymmetricLink +-----------+
+| | +------------------------------+ | |
+| +---------+ | +------------------------+ | +---------+ |
+| | RX port <-----| OneWayLink *<-----| TX port | |
+| +---------+ | +------------------------+ | +---------+ |
+| | | | | |
+| +---------+ | +------------------------+ | +---------+ |
+| | TX port |----->* OneWayLink |-----> RX port | |
+| +---------+ | +------------------------+ | +---------+ |
+| | +------------------------------+ | |
++-----------+ +-----------+
+
+ ( -->* denotes constrained port)
+```
+
+In most common scenario, one of the endpoints is going to be a QUIC endpoint,
+and another is going to be a switch port.
+
+## Other objects
+
+Besides `SymmetricLink`, the simulator provides the following objects:
+
+* `Queue` allows to convert a constrained port into an unconstrained one by
+ buffering packets upon arrival. The queue has a finite size, and once the
+ queue is full, the packets are silently dropped.
+* `Switch` simulates a multi-port learning switch with a fixed queue for each
+ output port.
+* `QuicEndpoint` allows QuicConnection to be run over the simulated network.
+* `QuicEndpointMultiplexer` allows multiple connections to share the same
+ network endpoint.
diff --git a/chromium/net/quic/test_tools/simulator/actor.cc b/chromium/net/quic/test_tools/simulator/actor.cc
new file mode 100644
index 00000000000..0fdf26fc99d
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/actor.cc
@@ -0,0 +1,29 @@
+// 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/test_tools/simulator/actor.h"
+#include "net/quic/test_tools/simulator/simulator.h"
+
+namespace net {
+namespace simulator {
+
+Actor::Actor(Simulator* simulator, std::string name)
+ : simulator_(simulator),
+ clock_(simulator->GetClock()),
+ name_(std::move(name)) {
+ simulator->AddActor(this);
+}
+
+Actor::~Actor() {}
+
+void Actor::Schedule(QuicTime next_tick) {
+ simulator_->Schedule(this, next_tick);
+}
+
+void Actor::Unschedule() {
+ simulator_->Unschedule(this);
+}
+
+} // namespace simulator
+} // namespace net
diff --git a/chromium/net/quic/test_tools/simulator/actor.h b/chromium/net/quic/test_tools/simulator/actor.h
new file mode 100644
index 00000000000..f74b712bb23
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/actor.h
@@ -0,0 +1,67 @@
+// 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.
+
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_ACTOR_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_ACTOR_H_
+
+#include <string>
+
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_time.h"
+
+namespace net {
+namespace simulator {
+
+class Simulator;
+struct ScheduledActor;
+
+// Actor is the base class for all participants of the simulation which can
+// schedule events to be triggered at the specified time. Every actor has a
+// name assigned to it, which can be used for debugging and addressing purposes.
+//
+// The Actor object is scheduled as follows:
+// 1. Every Actor object appears at most once in the event queue, for one
+// specific time.
+// 2. Actor is scheduled by calling Schedule() method.
+// 3. If Schedule() method is called with multiple different times specified,
+// Act() method will be called at the earliest time specified.
+// 4. Before Act() is called, the Actor is removed from the event queue. Act()
+// will not be called again unless Schedule() is called.
+class Actor {
+ public:
+ Actor(Simulator* simulator, std::string name);
+ virtual ~Actor();
+
+ // Trigger all the events the actor can potentially handle at this point.
+ // Before Act() is called, the actor is removed from the event queue, and has
+ // to schedule the next call manually.
+ virtual void Act() = 0;
+
+ inline std::string name() const { return name_; }
+ inline Simulator* simulator() const { return simulator_; }
+
+ protected:
+ // Calls Schedule() on the associated simulator.
+ void Schedule(QuicTime next_tick);
+
+ // Calls Unschedule() on the associated simulator.
+ void Unschedule();
+
+ Simulator* simulator_;
+ const QuicClock* clock_;
+ std::string name_;
+
+ private:
+ // Since the Actor object registers itself with a simulator using a pointer to
+ // itself, do not allow it to be moved.
+ Actor(Actor&&) = delete;
+ Actor& operator=(Actor&&) = delete;
+
+ DISALLOW_COPY_AND_ASSIGN(Actor);
+};
+
+} // namespace simulator
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_SIMULATOR_ACTOR_H_
diff --git a/chromium/net/quic/test_tools/simulator/alarm_factory.cc b/chromium/net/quic/test_tools/simulator/alarm_factory.cc
new file mode 100644
index 00000000000..7c895570d7f
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/alarm_factory.cc
@@ -0,0 +1,82 @@
+// 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 "base/strings/stringprintf.h"
+#include "net/quic/core/quic_alarm.h"
+#include "net/quic/test_tools/simulator/alarm_factory.h"
+
+using base::StringPrintf;
+
+namespace net {
+namespace simulator {
+
+// Alarm is an implementation of QuicAlarm which can schedule alarms in the
+// simulation timeline.
+class Alarm : public QuicAlarm {
+ public:
+ Alarm(Simulator* simulator,
+ std::string name,
+ QuicArenaScopedPtr<QuicAlarm::Delegate> delegate)
+ : QuicAlarm(std::move(delegate)), adapter_(simulator, name, this) {}
+ ~Alarm() override {}
+
+ void SetImpl() override {
+ DCHECK(deadline().IsInitialized());
+ adapter_.Set(deadline());
+ }
+
+ void CancelImpl() override { adapter_.Cancel(); }
+
+ private:
+ // An adapter class triggering a QuicAlarm using a simulation time system.
+ // An adapter is required here because neither Actor nor QuicAlarm are pure
+ // interfaces.
+ class Adapter : public Actor {
+ public:
+ Adapter(Simulator* simulator, std::string name, Alarm* parent)
+ : Actor(simulator, name), parent_(parent) {}
+ ~Adapter() override {}
+
+ void Set(QuicTime time) { Schedule(time); }
+ void Cancel() { Unschedule(); }
+
+ void Act() override {
+ DCHECK(clock_->Now() == parent_->deadline());
+ parent_->Fire();
+ }
+
+ private:
+ Alarm* parent_;
+ };
+ Adapter adapter_;
+};
+
+AlarmFactory::AlarmFactory(Simulator* simulator, std::string name)
+ : simulator_(simulator), name_(std::move(name)), counter_(0) {}
+
+AlarmFactory::~AlarmFactory() {}
+
+std::string AlarmFactory::GetNewAlarmName() {
+ ++counter_;
+ return StringPrintf("%s (alarm %i)", name_.c_str(), counter_);
+}
+
+QuicAlarm* AlarmFactory::CreateAlarm(QuicAlarm::Delegate* delegate) {
+ return new Alarm(simulator_, GetNewAlarmName(),
+ QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate));
+}
+
+QuicArenaScopedPtr<QuicAlarm> AlarmFactory::CreateAlarm(
+ QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+ QuicConnectionArena* arena) {
+ if (arena != nullptr) {
+ return arena->New<Alarm>(simulator_, GetNewAlarmName(),
+ std::move(delegate));
+ }
+ return QuicArenaScopedPtr<QuicAlarm>(
+ new Alarm(simulator_, GetNewAlarmName(), std::move(delegate)));
+}
+
+} // namespace simulator
+} // namespace net
diff --git a/chromium/net/quic/test_tools/simulator/alarm_factory.h b/chromium/net/quic/test_tools/simulator/alarm_factory.h
new file mode 100644
index 00000000000..284da2b688c
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/alarm_factory.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_ALARM_FACTORY_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_ALARM_FACTORY_H_
+
+#include "net/quic/core/quic_alarm_factory.h"
+#include "net/quic/test_tools/simulator/actor.h"
+
+namespace net {
+namespace simulator {
+
+// AlarmFactory allows to schedule QuicAlarms using the simulation event queue.
+class AlarmFactory : public QuicAlarmFactory {
+ public:
+ AlarmFactory(Simulator* simulator, std::string name);
+ ~AlarmFactory() override;
+
+ QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override;
+ QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
+ QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+ QuicConnectionArena* arena) override;
+
+ private:
+ // Automatically generate a name for a new alarm.
+ std::string GetNewAlarmName();
+
+ Simulator* simulator_;
+ std::string name_;
+ int counter_;
+
+ DISALLOW_COPY_AND_ASSIGN(AlarmFactory);
+};
+
+} // namespace simulator
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_SIMULATOR_ALARM_FACTORY_H_
diff --git a/chromium/net/quic/test_tools/simulator/link.cc b/chromium/net/quic/test_tools/simulator/link.cc
new file mode 100644
index 00000000000..bf87f918d5f
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/link.cc
@@ -0,0 +1,116 @@
+// 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 "base/strings/stringprintf.h"
+#include "net/quic/test_tools/simulator/link.h"
+#include "net/quic/test_tools/simulator/simulator.h"
+
+using base::StringPrintf;
+
+namespace net {
+namespace simulator {
+
+// Parameters for random noise delay.
+const uint64_t kMaxRandomDelayUs = 10;
+
+OneWayLink::OneWayLink(Simulator* simulator,
+ std::string name,
+ UnconstrainedPortInterface* sink,
+ QuicBandwidth bandwidth,
+ QuicTime::Delta propagation_delay)
+ : Actor(simulator, name),
+ sink_(sink),
+ bandwidth_(bandwidth),
+ propagation_delay_(propagation_delay),
+ next_write_at_(QuicTime::Zero()) {}
+
+OneWayLink::~OneWayLink() {}
+
+OneWayLink::QueuedPacket::QueuedPacket(std::unique_ptr<Packet> packet,
+ QuicTime dequeue_time)
+ : packet(std::move(packet)), dequeue_time(dequeue_time) {}
+
+OneWayLink::QueuedPacket::~QueuedPacket() {}
+
+void OneWayLink::AcceptPacket(std::unique_ptr<Packet> packet) {
+ DCHECK(TimeUntilAvailable().IsZero());
+ QuicTime::Delta transfer_time = bandwidth_.TransferTime(packet->size);
+ next_write_at_ = clock_->Now() + transfer_time;
+
+ packets_in_transit_.emplace(
+ std::move(packet),
+ next_write_at_ + propagation_delay_ + GetRandomDelay(transfer_time));
+ ScheduleNextPacketDeparture();
+}
+
+QuicTime::Delta OneWayLink::TimeUntilAvailable() {
+ const QuicTime now = clock_->Now();
+ if (next_write_at_ <= now) {
+ return QuicTime::Delta::Zero();
+ }
+
+ return next_write_at_ - now;
+}
+
+void OneWayLink::Act() {
+ DCHECK(!packets_in_transit_.empty());
+ DCHECK(packets_in_transit_.front().dequeue_time >= clock_->Now());
+
+ sink_->AcceptPacket(std::move(packets_in_transit_.front().packet));
+ packets_in_transit_.pop();
+
+ ScheduleNextPacketDeparture();
+}
+
+void OneWayLink::ScheduleNextPacketDeparture() {
+ if (packets_in_transit_.empty()) {
+ return;
+ }
+
+ Schedule(packets_in_transit_.front().dequeue_time);
+}
+
+QuicTime::Delta OneWayLink::GetRandomDelay(QuicTime::Delta transfer_time) {
+ QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(
+ simulator_->GetRandomGenerator()->RandUint64() % (kMaxRandomDelayUs + 1));
+ // Have an upper bound on the delay to ensure packets do not go out of order.
+ delta = std::min(delta, transfer_time * 0.5);
+ return delta;
+}
+
+SymmetricLink::SymmetricLink(Simulator* simulator,
+ std::string name,
+ UnconstrainedPortInterface* sink_a,
+ UnconstrainedPortInterface* sink_b,
+ QuicBandwidth bandwidth,
+ QuicTime::Delta propagation_delay)
+ : a_to_b_link_(simulator,
+ StringPrintf("%s (A-to-B)", name.c_str()),
+ sink_b,
+ bandwidth,
+ propagation_delay),
+ b_to_a_link_(simulator,
+ StringPrintf("%s (B-to-A)", name.c_str()),
+ sink_a,
+ bandwidth,
+ propagation_delay) {}
+
+SymmetricLink::SymmetricLink(Endpoint* endpoint_a,
+ Endpoint* endpoint_b,
+ QuicBandwidth bandwidth,
+ QuicTime::Delta propagation_delay)
+ : SymmetricLink(endpoint_a->simulator(),
+ StringPrintf("Link [%s]<->[%s]",
+ endpoint_a->name().c_str(),
+ endpoint_b->name().c_str()),
+ endpoint_a->GetRxPort(),
+ endpoint_b->GetRxPort(),
+ bandwidth,
+ propagation_delay) {
+ endpoint_a->SetTxPort(&a_to_b_link_);
+ endpoint_b->SetTxPort(&b_to_a_link_);
+}
+
+} // namespace simulator
+} // namespace net
diff --git a/chromium/net/quic/test_tools/simulator/link.h b/chromium/net/quic/test_tools/simulator/link.h
new file mode 100644
index 00000000000..8df241dab2a
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/link.h
@@ -0,0 +1,100 @@
+// 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.
+
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_LINK_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_LINK_H_
+
+#include <queue>
+#include <utility>
+
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/test_tools/simulator/actor.h"
+#include "net/quic/test_tools/simulator/port.h"
+
+namespace net {
+namespace simulator {
+
+// A reliable simplex link between two endpoints with constrained bandwidth. A
+// few microseconds of random delay are added for every packet to avoid
+// synchronization issues.
+class OneWayLink : public Actor, public ConstrainedPortInterface {
+ public:
+ OneWayLink(Simulator* simulator,
+ std::string name,
+ UnconstrainedPortInterface* sink,
+ QuicBandwidth bandwidth,
+ QuicTime::Delta propagation_delay);
+ ~OneWayLink() override;
+
+ void AcceptPacket(std::unique_ptr<Packet> packet) override;
+ QuicTime::Delta TimeUntilAvailable() override;
+ void Act() override;
+
+ inline QuicBandwidth bandwidth() const { return bandwidth_; }
+ inline QuicTime::Delta propagation_delay() const {
+ return propagation_delay_;
+ }
+
+ private:
+ struct QueuedPacket {
+ std::unique_ptr<Packet> packet;
+ QuicTime dequeue_time;
+
+ QueuedPacket(std::unique_ptr<Packet> packet, QuicTime dequeue_time);
+ ~QueuedPacket();
+ };
+
+ // Schedule the next packet to be egressed out of the link if there are
+ // packets on the link.
+ void ScheduleNextPacketDeparture();
+
+ // Get the value of a random delay imposed on each packet in order to avoid
+ // artifical synchronization artifacts during the simulation.
+ QuicTime::Delta GetRandomDelay(QuicTime::Delta transfer_time);
+
+ UnconstrainedPortInterface* sink_;
+ std::queue<QueuedPacket> packets_in_transit_;
+
+ const QuicBandwidth bandwidth_;
+ const QuicTime::Delta propagation_delay_;
+
+ QuicTime next_write_at_;
+
+ DISALLOW_COPY_AND_ASSIGN(OneWayLink);
+};
+
+// A full-duplex link between two endpoints, functionally equivalent to two
+// OneWayLink objects tied together.
+class SymmetricLink {
+ public:
+ SymmetricLink(Simulator* simulator,
+ std::string name,
+ UnconstrainedPortInterface* sink_a,
+ UnconstrainedPortInterface* sink_b,
+ QuicBandwidth bandwidth,
+ QuicTime::Delta propagation_delay);
+ SymmetricLink(Endpoint* endpoint_a,
+ Endpoint* endpoint_b,
+ QuicBandwidth bandwidth,
+ QuicTime::Delta propagation_delay);
+
+ inline ConstrainedPortInterface* GetTxPortForA() { return &a_to_b_link_; }
+ inline ConstrainedPortInterface* GetTxPortForB() { return &b_to_a_link_; }
+
+ inline QuicBandwidth bandwidth() { return a_to_b_link_.bandwidth(); }
+ inline QuicTime::Delta propagation_delay() {
+ return a_to_b_link_.propagation_delay();
+ }
+
+ private:
+ OneWayLink a_to_b_link_;
+ OneWayLink b_to_a_link_;
+
+ DISALLOW_COPY_AND_ASSIGN(SymmetricLink);
+};
+
+} // namespace simulator
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_SIMULATOR_LINK_H_
diff --git a/chromium/net/quic/test_tools/simulator/port.cc b/chromium/net/quic/test_tools/simulator/port.cc
new file mode 100644
index 00000000000..11e4edae8ee
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/port.cc
@@ -0,0 +1,21 @@
+// 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/test_tools/simulator/port.h"
+
+namespace net {
+namespace simulator {
+
+Packet::Packet()
+ : source(), destination(), tx_timestamp(QuicTime::Zero()), size(0) {}
+
+Packet::~Packet() {}
+
+Packet::Packet(const Packet& packet) = default;
+
+Endpoint::Endpoint(Simulator* simulator, std::string name)
+ : Actor(simulator, name) {}
+
+} // namespace simulator
+} // namespace net
diff --git a/chromium/net/quic/test_tools/simulator/port.h b/chromium/net/quic/test_tools/simulator/port.h
new file mode 100644
index 00000000000..62c47f2b0bd
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/port.h
@@ -0,0 +1,66 @@
+// 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.
+
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_PORT_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_PORT_H_
+
+#include <string>
+#include <utility>
+
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/test_tools/simulator/actor.h"
+
+namespace net {
+namespace simulator {
+
+struct Packet {
+ Packet();
+ ~Packet();
+ Packet(const Packet& packet);
+
+ std::string source;
+ std::string destination;
+ QuicTime tx_timestamp;
+
+ std::string contents;
+ QuicByteCount size;
+};
+
+// An interface for anything that accepts packets at arbitrary rate.
+class UnconstrainedPortInterface {
+ public:
+ virtual ~UnconstrainedPortInterface() {}
+ virtual void AcceptPacket(std::unique_ptr<Packet> packet) = 0;
+};
+
+// An interface for any device that accepts packets at a specific rate.
+// Typically one would use a Queue object in order to write into a constrained
+// port.
+class ConstrainedPortInterface {
+ public:
+ virtual ~ConstrainedPortInterface() {}
+
+ // Accept a packet for a port. TimeUntilAvailable() must be zero before this
+ // method is called.
+ virtual void AcceptPacket(std::unique_ptr<Packet> packet) = 0;
+
+ // Time until write for the next port is available. Cannot be infinite.
+ virtual QuicTime::Delta TimeUntilAvailable() = 0;
+};
+
+// A convenience class for any network endpoints, i.e. the objects which can
+// both accept and send packets.
+class Endpoint : public Actor {
+ public:
+ virtual UnconstrainedPortInterface* GetRxPort() = 0;
+ virtual void SetTxPort(ConstrainedPortInterface* port) = 0;
+
+ protected:
+ Endpoint(Simulator* simulator, std::string name);
+};
+
+} // namespace simulator
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_SIMULATOR_PORT_H_
diff --git a/chromium/net/quic/test_tools/simulator/queue.cc b/chromium/net/quic/test_tools/simulator/queue.cc
new file mode 100644
index 00000000000..05704430b78
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/queue.cc
@@ -0,0 +1,64 @@
+// 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/test_tools/simulator/queue.h"
+
+namespace net {
+namespace simulator {
+
+Queue::ListenerInterface::~ListenerInterface() {}
+
+Queue::Queue(Simulator* simulator, std::string name, QuicByteCount capacity)
+ : Actor(simulator, name),
+ capacity_(capacity),
+ bytes_queued_(0),
+ listener_(nullptr) {}
+Queue::~Queue() {}
+
+void Queue::set_tx_port(ConstrainedPortInterface* port) {
+ tx_port_ = port;
+}
+
+void Queue::AcceptPacket(std::unique_ptr<Packet> packet) {
+ if (packet->size + bytes_queued_ > capacity_) {
+ DVLOG(1) << "Queue [" << name() << "] has received a packet from ["
+ << packet->source << "] to [" << packet->destination
+ << "] which is over capacity. Dropping it.";
+ DVLOG(1) << "Queue size: " << bytes_queued_ << " out of " << capacity_
+ << ". Packet size: " << packet->size;
+ return;
+ }
+
+ bytes_queued_ += packet->size;
+ queue_.emplace(std::move(packet));
+ ScheduleNextPacketDequeue();
+}
+
+void Queue::Act() {
+ DCHECK(!queue_.empty());
+ if (tx_port_->TimeUntilAvailable().IsZero()) {
+ DCHECK(bytes_queued_ >= queue_.front()->size);
+ bytes_queued_ -= queue_.front()->size;
+
+ tx_port_->AcceptPacket(std::move(queue_.front()));
+ queue_.pop();
+ if (listener_ != nullptr) {
+ listener_->OnPacketDequeued();
+ }
+ }
+
+ ScheduleNextPacketDequeue();
+}
+
+void Queue::ScheduleNextPacketDequeue() {
+ if (queue_.empty()) {
+ DCHECK_EQ(bytes_queued_, 0u);
+ return;
+ }
+
+ Schedule(clock_->Now() + tx_port_->TimeUntilAvailable());
+}
+
+} // namespace simulator
+} // namespace net
diff --git a/chromium/net/quic/test_tools/simulator/queue.h b/chromium/net/quic/test_tools/simulator/queue.h
new file mode 100644
index 00000000000..b7048930f1a
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/queue.h
@@ -0,0 +1,59 @@
+// 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.
+
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_QUEUE_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_QUEUE_H_
+
+#include "net/quic/test_tools/simulator/link.h"
+
+namespace net {
+namespace simulator {
+
+// A finitely sized queue which egresses packets onto a constrained link. The
+// capacity of the queue is measured in bytes as opposed to packets.
+class Queue : public Actor, public UnconstrainedPortInterface {
+ public:
+ class ListenerInterface {
+ public:
+ virtual ~ListenerInterface();
+
+ // Called whenever a packet is removed from the queue.
+ virtual void OnPacketDequeued() = 0;
+ };
+
+ Queue(Simulator* simulator, std::string name, QuicByteCount capacity);
+ ~Queue() override;
+
+ void set_tx_port(ConstrainedPortInterface* port);
+
+ void AcceptPacket(std::unique_ptr<Packet> packet) override;
+
+ void Act() override;
+
+ inline QuicByteCount capacity() const { return capacity_; }
+ inline QuicByteCount bytes_queued() const { return bytes_queued_; }
+ inline QuicPacketCount packets_queued() const { return queue_.size(); }
+
+ inline void set_listener_interface(ListenerInterface* listener) {
+ listener_ = listener;
+ }
+
+ private:
+ void ScheduleNextPacketDequeue();
+
+ const QuicByteCount capacity_;
+ QuicByteCount bytes_queued_;
+
+ ConstrainedPortInterface* tx_port_;
+ std::queue<std::unique_ptr<Packet>> queue_;
+
+ ListenerInterface* listener_;
+
+ DISALLOW_COPY_AND_ASSIGN(Queue);
+};
+
+} // namespace simulator
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_SIMULATOR_QUEUE_H_
diff --git a/chromium/net/quic/test_tools/simulator/quic_endpoint.cc b/chromium/net/quic/test_tools/simulator/quic_endpoint.cc
new file mode 100644
index 00000000000..a65b5713739
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/quic_endpoint.cc
@@ -0,0 +1,272 @@
+// 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/test_tools/simulator/quic_endpoint.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/sha1.h"
+#include "base/strings/stringprintf.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/test_tools/simulator/simulator.h"
+
+using base::StringPrintf;
+
+namespace net {
+namespace simulator {
+
+const QuicStreamId kDataStream = 3;
+const QuicByteCount kWriteChunkSize = 128 * 1024;
+const char kStreamDataContents = 'Q';
+
+// Takes a SHA-1 hash of the name and converts it into five 32-bit integers.
+static std::vector<uint32_t> HashNameIntoFive32BitIntegers(std::string name) {
+ const std::string hash = base::SHA1HashString(name);
+
+ std::vector<uint32_t> output;
+ uint32_t current_number = 0;
+ for (size_t i = 0; i < hash.size(); i++) {
+ current_number = (current_number << 8) + hash[i];
+ if (i % 4 == 3) {
+ output.push_back(i);
+ current_number = 0;
+ }
+ }
+
+ return output;
+}
+
+IPEndPoint GetAddressFromName(std::string name) {
+ const std::vector<uint32_t> hash = HashNameIntoFive32BitIntegers(name);
+
+ // Generate a random port between 1025 and 65535.
+ const uint16_t port = 1025 + hash[0] % (65535 - 1025 + 1);
+
+ // Generate a random 10.x.x.x address, where x is between 1 and 254.
+ std::vector<uint8_t> ip_address;
+ ip_address.push_back(10);
+ for (size_t i = 1; i <= 4; i++) {
+ ip_address.push_back(1 + hash[i] % 254);
+ }
+
+ return IPEndPoint(IPAddress(ip_address), port);
+}
+
+QuicEndpoint::QuicEndpoint(Simulator* simulator,
+ std::string name,
+ std::string peer_name,
+ Perspective perspective,
+ QuicConnectionId connection_id)
+ : Endpoint(simulator, name),
+ peer_name_(peer_name),
+ writer_(this),
+ nic_tx_queue_(simulator,
+ StringPrintf("%s (TX Queue)", name.c_str()),
+ kMaxPacketSize * kTxQueueSize),
+ connection_(connection_id,
+ GetAddressFromName(peer_name),
+ simulator,
+ simulator->GetAlarmFactory(),
+ &writer_,
+ false,
+ perspective,
+ CurrentSupportedVersions()),
+ bytes_to_transfer_(0),
+ bytes_transferred_(0),
+ write_blocked_count_(0),
+ wrong_data_received_(false),
+ transmission_buffer_(new char[kWriteChunkSize]) {
+ nic_tx_queue_.set_listener_interface(this);
+
+ connection_.SetSelfAddress(GetAddressFromName(name));
+ connection_.set_visitor(this);
+ connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, new NullEncrypter());
+ connection_.SetDecrypter(ENCRYPTION_FORWARD_SECURE, new NullDecrypter());
+ connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+
+ // Configure the connection as if it received a handshake. This is important
+ // primarily because
+ // - this enables pacing, and
+ // - this sets the non-handshake timeouts.
+ std::string error;
+ CryptoHandshakeMessage peer_hello;
+ peer_hello.SetValue(kICSL,
+ static_cast<uint32_t>(kMaximumIdleTimeoutSecs - 1));
+ QuicConfig config;
+ QuicErrorCode error_code = config.ProcessPeerHello(
+ peer_hello, perspective == Perspective::IS_CLIENT ? SERVER : CLIENT,
+ &error);
+ DCHECK_EQ(error_code, QUIC_NO_ERROR) << "Configuration failed: " << error;
+ connection_.SetFromConfig(config);
+}
+
+QuicEndpoint::~QuicEndpoint() {}
+
+void QuicEndpoint::AddBytesToTransfer(QuicByteCount bytes) {
+ if (bytes_to_transfer_ > 0) {
+ Schedule(clock_->Now());
+ }
+
+ bytes_to_transfer_ += bytes;
+ WriteStreamData();
+}
+
+void QuicEndpoint::AcceptPacket(std::unique_ptr<Packet> packet) {
+ if (packet->destination != name_) {
+ return;
+ }
+
+ QuicReceivedPacket received_packet(packet->contents.data(),
+ packet->contents.size(), clock_->Now());
+ connection_.ProcessUdpPacket(connection_.self_address(),
+ connection_.peer_address(), received_packet);
+}
+
+UnconstrainedPortInterface* QuicEndpoint::GetRxPort() {
+ return this;
+}
+
+void QuicEndpoint::SetTxPort(ConstrainedPortInterface* port) {
+ // Any egress done by the endpoint is actually handled by a queue on an NIC.
+ nic_tx_queue_.set_tx_port(port);
+}
+
+void QuicEndpoint::OnPacketDequeued() {
+ if (writer_.IsWriteBlocked() &&
+ (nic_tx_queue_.capacity() - nic_tx_queue_.bytes_queued()) >=
+ kMaxPacketSize) {
+ writer_.SetWritable();
+ connection_.OnCanWrite();
+ }
+}
+
+void QuicEndpoint::OnStreamFrame(const QuicStreamFrame& frame) {
+ // Verify that the data received always matches the output of DataAtOffset().
+ DCHECK(frame.stream_id == kDataStream);
+ for (size_t i = 0; i < frame.data_length; i++) {
+ if (frame.data_buffer[i] != kStreamDataContents) {
+ wrong_data_received_ = true;
+ }
+ }
+}
+void QuicEndpoint::OnCanWrite() {
+ WriteStreamData();
+}
+bool QuicEndpoint::WillingAndAbleToWrite() const {
+ return bytes_to_transfer_ != 0;
+}
+bool QuicEndpoint::HasPendingHandshake() const {
+ return false;
+}
+bool QuicEndpoint::HasOpenDynamicStreams() const {
+ return true;
+}
+
+QuicEndpoint::Writer::Writer(QuicEndpoint* endpoint)
+ : endpoint_(endpoint), is_blocked_(false) {}
+
+QuicEndpoint::Writer::~Writer() {}
+
+WriteResult QuicEndpoint::Writer::WritePacket(const char* buffer,
+ size_t buf_len,
+ const IPAddress& self_address,
+ const IPEndPoint& peer_address,
+ PerPacketOptions* options) {
+ DCHECK(!IsWriteBlocked());
+ DCHECK(options == nullptr);
+ DCHECK(buf_len <= kMaxPacketSize);
+
+ // Instead of losing a packet, become write-blocked when the egress queue is
+ // full.
+ if (endpoint_->nic_tx_queue_.packets_queued() > kTxQueueSize) {
+ is_blocked_ = true;
+ endpoint_->write_blocked_count_++;
+ return WriteResult(WRITE_STATUS_BLOCKED, 0);
+ }
+
+ auto packet = base::MakeUnique<Packet>();
+ packet->source = endpoint_->name();
+ packet->destination = endpoint_->peer_name_;
+ packet->tx_timestamp = endpoint_->clock_->Now();
+
+ packet->contents = std::string(buffer, buf_len);
+ packet->size = buf_len;
+
+ endpoint_->nic_tx_queue_.AcceptPacket(std::move(packet));
+
+ return WriteResult(WRITE_STATUS_OK, buf_len);
+}
+
+bool QuicEndpoint::Writer::IsWriteBlockedDataBuffered() const {
+ return false;
+}
+bool QuicEndpoint::Writer::IsWriteBlocked() const {
+ return is_blocked_;
+}
+void QuicEndpoint::Writer::SetWritable() {
+ is_blocked_ = false;
+}
+QuicByteCount QuicEndpoint::Writer::GetMaxPacketSize(
+ const IPEndPoint& /*peer_address*/) const {
+ return kMaxPacketSize;
+}
+
+void QuicEndpoint::WriteStreamData() {
+ // Instantiate a bundler which would normally be here due to QuicSession.
+ QuicConnection::ScopedPacketBundler packet_bundler(&connection_,
+ QuicConnection::SEND_ACK);
+
+ while (bytes_to_transfer_ > 0) {
+ // Transfer data in chunks of size at most |kWriteChunkSize|.
+ const size_t transmission_size =
+ std::min(kWriteChunkSize, bytes_to_transfer_);
+ memset(transmission_buffer_.get(), kStreamDataContents, transmission_size);
+
+ iovec iov;
+ iov.iov_base = transmission_buffer_.get();
+ iov.iov_len = transmission_size;
+
+ QuicIOVector io_vector(&iov, 1, transmission_size);
+ QuicConsumedData consumed_data = connection_.SendStreamData(
+ kDataStream, io_vector, bytes_transferred_, false, nullptr);
+
+ DCHECK(consumed_data.bytes_consumed <= transmission_size);
+ bytes_transferred_ += consumed_data.bytes_consumed;
+ bytes_to_transfer_ -= consumed_data.bytes_consumed;
+ if (consumed_data.bytes_consumed != transmission_size) {
+ return;
+ }
+ }
+}
+
+QuicEndpointMultiplexer::QuicEndpointMultiplexer(
+ std::string name,
+ std::initializer_list<QuicEndpoint*> endpoints)
+ : Endpoint((*endpoints.begin())->simulator(), name) {
+ for (QuicEndpoint* endpoint : endpoints) {
+ mapping_.insert(std::make_pair(endpoint->name(), endpoint));
+ }
+}
+
+QuicEndpointMultiplexer::~QuicEndpointMultiplexer() {}
+
+void QuicEndpointMultiplexer::AcceptPacket(std::unique_ptr<Packet> packet) {
+ auto key_value_pair_it = mapping_.find(packet->destination);
+ if (key_value_pair_it == mapping_.end()) {
+ return;
+ }
+
+ key_value_pair_it->second->GetRxPort()->AcceptPacket(std::move(packet));
+}
+UnconstrainedPortInterface* QuicEndpointMultiplexer::GetRxPort() {
+ return this;
+}
+void QuicEndpointMultiplexer::SetTxPort(ConstrainedPortInterface* port) {
+ for (auto& key_value_pair : mapping_) {
+ key_value_pair.second->SetTxPort(port);
+ }
+}
+
+} // namespace simulator
+} // namespace net
diff --git a/chromium/net/quic/test_tools/simulator/quic_endpoint.h b/chromium/net/quic/test_tools/simulator/quic_endpoint.h
new file mode 100644
index 00000000000..d6a64d72ee7
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/quic_endpoint.h
@@ -0,0 +1,169 @@
+// 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.
+
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_QUIC_ENDPOINT_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_QUIC_ENDPOINT_H_
+
+#include "net/quic/core/crypto/null_decrypter.h"
+#include "net/quic/core/crypto/null_encrypter.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/test_tools/simulator/link.h"
+#include "net/quic/test_tools/simulator/queue.h"
+#include "net/tools/quic/quic_default_packet_writer.h"
+
+namespace net {
+namespace simulator {
+
+// Size of the TX queue used by the kernel/NIC. 1000 is the Linux
+// kernel default.
+const QuicByteCount kTxQueueSize = 1000;
+
+// Generate a random local network host-port tuple based on the name of the
+// endpoint.
+IPEndPoint GetAddressFromName(std::string name);
+
+// A QUIC connection endpoint. Wraps around QuicConnection. In order to
+// initiate a transfer, the caller has to call AddBytesToTransfer(). The data
+// transferred is always the same and is always transferred on a single stream.
+// The endpoint receives all packets addressed to it, and verifies that the data
+// received is what it's supposed to be.
+class QuicEndpoint : public Endpoint,
+ public UnconstrainedPortInterface,
+ public Queue::ListenerInterface,
+ public QuicConnectionVisitorInterface {
+ public:
+ QuicEndpoint(Simulator* simulator,
+ std::string name,
+ std::string peer_name,
+ Perspective perspective,
+ QuicConnectionId connection_id);
+ ~QuicEndpoint() override;
+
+ inline QuicConnection* connection() { return &connection_; }
+ inline QuicByteCount bytes_to_transfer() const { return bytes_to_transfer_; }
+ inline QuicByteCount bytes_transferred() const { return bytes_transferred_; }
+ inline QuicByteCount bytes_received() {
+ return connection_.GetStats().stream_bytes_received;
+ }
+ inline size_t write_blocked_count() { return write_blocked_count_; }
+ inline bool wrong_data_received() const { return wrong_data_received_; }
+
+ // Send |bytes| bytes. Initiates the transfer if one is not already in
+ // progress.
+ void AddBytesToTransfer(QuicByteCount bytes);
+
+ // UnconstrainedPortInterface method. Called whenever the endpoint receives a
+ // packet.
+ void AcceptPacket(std::unique_ptr<Packet> packet) override;
+
+ // Begin Endpoint implementation.
+ UnconstrainedPortInterface* GetRxPort() override;
+ void SetTxPort(ConstrainedPortInterface* port) override;
+ // End Endpoint implementation.
+
+ // Actor method.
+ void Act() override {}
+
+ // Queue::ListenerInterface method.
+ void OnPacketDequeued() override;
+
+ // Begin QuicConnectionVisitorInterface implementation.
+ void OnStreamFrame(const QuicStreamFrame& frame) override;
+ void OnCanWrite() override;
+ bool WillingAndAbleToWrite() const override;
+ bool HasPendingHandshake() const override;
+ bool HasOpenDynamicStreams() const override;
+
+ void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override {}
+ void OnBlockedFrame(const QuicBlockedFrame& frame) override {}
+ void OnRstStream(const QuicRstStreamFrame& frame) override {}
+ void OnGoAway(const QuicGoAwayFrame& frame) override {}
+ void OnConnectionClosed(QuicErrorCode error,
+ const std::string& error_details,
+ ConnectionCloseSource source) override {}
+ void OnWriteBlocked() override {}
+ void OnSuccessfulVersionNegotiation(const QuicVersion& version) override {}
+ void OnCongestionWindowChange(QuicTime now) override {}
+ void OnConnectionMigration(PeerAddressChangeType type) override {}
+ void OnPathDegrading() override {}
+ void PostProcessAfterData() override {}
+ // End QuicConnectionVisitorInterface implementation.
+
+ private:
+ // A Writer object that writes into the |nic_tx_queue_|.
+ class Writer : public QuicPacketWriter {
+ public:
+ explicit Writer(QuicEndpoint* endpoint);
+ ~Writer() override;
+
+ WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const IPAddress& self_address,
+ const IPEndPoint& peer_address,
+ PerPacketOptions* options) override;
+ bool IsWriteBlockedDataBuffered() const override;
+ bool IsWriteBlocked() const override;
+ void SetWritable() override;
+ QuicByteCount GetMaxPacketSize(
+ const IPEndPoint& peer_address) const override;
+
+ private:
+ QuicEndpoint* endpoint_;
+
+ bool is_blocked_;
+ };
+
+ // Write stream data until |bytes_to_transfer_| is zero or the connection is
+ // write-blocked.
+ void WriteStreamData();
+
+ std::string peer_name_;
+
+ Writer writer_;
+ // The queue for the outgoing packets. In reality, this might be either on
+ // the network card, or in the kernel, but for concreteness we assume it's on
+ // the network card.
+ Queue nic_tx_queue_;
+ QuicConnection connection_;
+
+ QuicByteCount bytes_to_transfer_;
+ QuicByteCount bytes_transferred_;
+
+ // Counts the number of times the writer became write-blocked.
+ size_t write_blocked_count_;
+
+ // Set to true if the endpoint receives stream data different from what it
+ // expects.
+ bool wrong_data_received_;
+
+ std::unique_ptr<char[]> transmission_buffer_;
+};
+
+// Multiplexes multiple connections at the same host on the network.
+class QuicEndpointMultiplexer : public Endpoint,
+ public UnconstrainedPortInterface {
+ public:
+ QuicEndpointMultiplexer(std::string name,
+ std::initializer_list<QuicEndpoint*> endpoints);
+ ~QuicEndpointMultiplexer() override;
+
+ // Receives a packet and passes it to the specified endpoint if that endpoint
+ // is one of the endpoints being multiplexed, otherwise ignores the packet.
+ void AcceptPacket(std::unique_ptr<Packet> packet) override;
+ UnconstrainedPortInterface* GetRxPort() override;
+
+ // Sets the egress port for all the endpoints being multiplexed.
+ void SetTxPort(ConstrainedPortInterface* port) override;
+
+ void Act() override{};
+
+ private:
+ std::unordered_map<std::string, QuicEndpoint*> mapping_;
+};
+
+} // namespace simulator
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_SIMULATOR_QUIC_ENDPOINT_H_
diff --git a/chromium/net/quic/test_tools/simulator/quic_endpoint_test.cc b/chromium/net/quic/test_tools/simulator/quic_endpoint_test.cc
new file mode 100644
index 00000000000..f4704108304
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/quic_endpoint_test.cc
@@ -0,0 +1,190 @@
+// 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/test_tools/simulator/quic_endpoint.h"
+
+#include "base/memory/ptr_util.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/simulator/simulator.h"
+#include "net/quic/test_tools/simulator/switch.h"
+
+#include "net/test/gtest_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::NiceMock;
+using ::testing::Return;
+
+namespace net {
+namespace simulator {
+
+const QuicBandwidth kDefaultBandwidth =
+ QuicBandwidth::FromKBitsPerSecond(10 * 1000);
+const QuicTime::Delta kDefaultPropagationDelay =
+ QuicTime::Delta::FromMilliseconds(20);
+const QuicByteCount kDefaultBdp = kDefaultBandwidth * kDefaultPropagationDelay;
+
+// A simple test harness where all hosts are connected to a switch with
+// identical links.
+class QuicEndpointTest : public ::testing::Test {
+ public:
+ QuicEndpointTest()
+ : simulator_(), switch_(&simulator_, "Switch", 8, kDefaultBdp * 2) {}
+
+ protected:
+ Simulator simulator_;
+ Switch switch_;
+
+ std::unique_ptr<SymmetricLink> Link(Endpoint* a, Endpoint* b) {
+ return base::MakeUnique<SymmetricLink>(a, b, kDefaultBandwidth,
+ kDefaultPropagationDelay);
+ }
+};
+
+// Test transmission from one host to another.
+TEST_F(QuicEndpointTest, OneWayTransmission) {
+ QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B",
+ Perspective::IS_CLIENT, 42);
+ QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A",
+ Perspective::IS_SERVER, 42);
+ auto link_a = Link(&endpoint_a, switch_.port(1));
+ auto link_b = Link(&endpoint_b, switch_.port(2));
+
+ // First transmit a small, packet-size chunk of data.
+ endpoint_a.AddBytesToTransfer(600);
+ QuicTime end_time =
+ simulator_.GetClock()->Now() + QuicTime::Delta::FromMilliseconds(1000);
+ simulator_.RunUntil(
+ [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });
+
+ EXPECT_EQ(600u, endpoint_a.bytes_transferred());
+ ASSERT_EQ(600u, endpoint_b.bytes_received());
+ EXPECT_FALSE(endpoint_a.wrong_data_received());
+ EXPECT_FALSE(endpoint_b.wrong_data_received());
+
+ // After a small chunk succeeds, try to transfer 2 MiB.
+ endpoint_a.AddBytesToTransfer(2 * 1024 * 1024);
+ end_time = simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(5);
+ simulator_.RunUntil(
+ [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });
+
+ const QuicByteCount total_bytes_transferred = 600 + 2 * 1024 * 1024;
+ EXPECT_EQ(total_bytes_transferred, endpoint_a.bytes_transferred());
+ EXPECT_EQ(total_bytes_transferred, endpoint_b.bytes_received());
+ EXPECT_EQ(0u, endpoint_a.write_blocked_count());
+ EXPECT_FALSE(endpoint_a.wrong_data_received());
+ EXPECT_FALSE(endpoint_b.wrong_data_received());
+}
+
+// Test the situation in which the writer becomes write-blocked.
+TEST_F(QuicEndpointTest, WriteBlocked) {
+ QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B",
+ Perspective::IS_CLIENT, 42);
+ QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A",
+ Perspective::IS_SERVER, 42);
+ auto link_a = Link(&endpoint_a, switch_.port(1));
+ auto link_b = Link(&endpoint_b, switch_.port(2));
+
+ // Will be owned by the sent packet manager.
+ auto* sender = new NiceMock<test::MockSendAlgorithm>();
+ EXPECT_CALL(*sender, TimeUntilSend(_, _))
+ .WillRepeatedly(Return(QuicTime::Delta::Zero()));
+ EXPECT_CALL(*sender, PacingRate(_))
+ .WillRepeatedly(Return(10 * kDefaultBandwidth));
+ EXPECT_CALL(*sender, BandwidthEstimate())
+ .WillRepeatedly(Return(10 * kDefaultBandwidth));
+ EXPECT_CALL(*sender, GetCongestionWindow())
+ .WillRepeatedly(
+ Return(kMaxPacketSize * kDefaultMaxCongestionWindowPackets));
+ test::QuicConnectionPeer::SetSendAlgorithm(endpoint_a.connection(),
+ kDefaultPathId, sender);
+
+ // First transmit a small, packet-size chunk of data.
+ QuicByteCount bytes_to_transfer = 3 * 1024 * 1024;
+ endpoint_a.AddBytesToTransfer(bytes_to_transfer);
+ QuicTime end_time =
+ simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(30);
+ simulator_.RunUntil([this, &endpoint_b, bytes_to_transfer, end_time]() {
+ return endpoint_b.bytes_received() == bytes_to_transfer ||
+ simulator_.GetClock()->Now() >= end_time;
+ });
+
+ EXPECT_EQ(bytes_to_transfer, endpoint_a.bytes_transferred());
+ EXPECT_EQ(bytes_to_transfer, endpoint_b.bytes_received());
+ EXPECT_GT(endpoint_a.write_blocked_count(), 0u);
+ EXPECT_FALSE(endpoint_a.wrong_data_received());
+ EXPECT_FALSE(endpoint_b.wrong_data_received());
+}
+
+// Test transmission of 1 MiB of data between two hosts simultaneously in both
+// directions.
+TEST_F(QuicEndpointTest, TwoWayTransmission) {
+ QuicEndpoint endpoint_a(&simulator_, "Endpoint A", "Endpoint B",
+ Perspective::IS_CLIENT, 42);
+ QuicEndpoint endpoint_b(&simulator_, "Endpoint B", "Endpoint A",
+ Perspective::IS_SERVER, 42);
+ auto link_a = Link(&endpoint_a, switch_.port(1));
+ auto link_b = Link(&endpoint_b, switch_.port(2));
+
+ endpoint_a.AddBytesToTransfer(1024 * 1024);
+ endpoint_b.AddBytesToTransfer(1024 * 1024);
+ QuicTime end_time =
+ simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(5);
+ simulator_.RunUntil(
+ [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });
+
+ EXPECT_EQ(1024u * 1024u, endpoint_a.bytes_transferred());
+ EXPECT_EQ(1024u * 1024u, endpoint_b.bytes_transferred());
+ EXPECT_EQ(1024u * 1024u, endpoint_a.bytes_received());
+ EXPECT_EQ(1024u * 1024u, endpoint_b.bytes_received());
+ EXPECT_FALSE(endpoint_a.wrong_data_received());
+ EXPECT_FALSE(endpoint_b.wrong_data_received());
+}
+
+// Simulate three hosts trying to send data to a fourth one simultaneously.
+TEST_F(QuicEndpointTest, Competition) {
+ auto endpoint_a = base::MakeUnique<QuicEndpoint>(
+ &simulator_, "Endpoint A", "Endpoint D (A)", Perspective::IS_CLIENT, 42);
+ auto endpoint_b = base::MakeUnique<QuicEndpoint>(
+ &simulator_, "Endpoint B", "Endpoint D (B)", Perspective::IS_CLIENT, 43);
+ auto endpoint_c = base::MakeUnique<QuicEndpoint>(
+ &simulator_, "Endpoint C", "Endpoint D (C)", Perspective::IS_CLIENT, 44);
+ auto endpoint_d_a = base::MakeUnique<QuicEndpoint>(
+ &simulator_, "Endpoint D (A)", "Endpoint A", Perspective::IS_SERVER, 42);
+ auto endpoint_d_b = base::MakeUnique<QuicEndpoint>(
+ &simulator_, "Endpoint D (B)", "Endpoint B", Perspective::IS_SERVER, 43);
+ auto endpoint_d_c = base::MakeUnique<QuicEndpoint>(
+ &simulator_, "Endpoint D (C)", "Endpoint C", Perspective::IS_SERVER, 44);
+ QuicEndpointMultiplexer endpoint_d(
+ "Endpoint D",
+ {endpoint_d_a.get(), endpoint_d_b.get(), endpoint_d_c.get()});
+
+ auto link_a = Link(endpoint_a.get(), switch_.port(1));
+ auto link_b = Link(endpoint_b.get(), switch_.port(2));
+ auto link_c = Link(endpoint_c.get(), switch_.port(3));
+ auto link_d = Link(&endpoint_d, switch_.port(4));
+
+ endpoint_a->AddBytesToTransfer(2 * 1024 * 1024);
+ endpoint_b->AddBytesToTransfer(2 * 1024 * 1024);
+ endpoint_c->AddBytesToTransfer(2 * 1024 * 1024);
+ QuicTime end_time =
+ simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(8);
+ simulator_.RunUntil(
+ [this, end_time]() { return simulator_.GetClock()->Now() >= end_time; });
+
+ for (QuicEndpoint* endpoint :
+ {endpoint_a.get(), endpoint_b.get(), endpoint_c.get()}) {
+ EXPECT_EQ(2u * 1024u * 1024u, endpoint->bytes_transferred());
+ EXPECT_GE(endpoint->connection()->GetStats().packets_lost, 0u);
+ }
+ for (QuicEndpoint* endpoint :
+ {endpoint_d_a.get(), endpoint_d_b.get(), endpoint_d_c.get()}) {
+ EXPECT_EQ(2u * 1024u * 1024u, endpoint->bytes_received());
+ EXPECT_FALSE(endpoint->wrong_data_received());
+ }
+}
+
+} // namespace simulator
+} // namespace net
diff --git a/chromium/net/quic/test_tools/simulator/simulator.cc b/chromium/net/quic/test_tools/simulator/simulator.cc
new file mode 100644
index 00000000000..2cb15da21df
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/simulator.cc
@@ -0,0 +1,146 @@
+// 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 "base/memory/ptr_util.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/test_tools/simulator/simulator.h"
+
+namespace net {
+namespace simulator {
+
+Simulator::Simulator()
+ : random_generator_(nullptr),
+ alarm_factory_(this, "Default Alarm Manager"),
+ run_for_should_stop_(false) {
+ run_for_alarm_.reset(
+ alarm_factory_.CreateAlarm(new RunForDelegate(&run_for_should_stop_)));
+}
+
+Simulator::~Simulator() {}
+
+Simulator::Clock::Clock() : now_(kStartTime) {}
+
+QuicTime Simulator::Clock::ApproximateNow() const {
+ return now_;
+}
+
+QuicTime Simulator::Clock::Now() const {
+ return now_;
+}
+
+QuicWallTime Simulator::Clock::WallNow() const {
+ return QuicWallTime::FromUNIXMicroseconds(
+ (now_ - QuicTime::Zero()).ToMicroseconds());
+}
+
+void Simulator::AddActor(Actor* actor) {
+ auto emplace_times_result =
+ scheduled_times_.insert(std::make_pair(actor, QuicTime::Infinite()));
+ auto emplace_names_result = actor_names_.insert(actor->name());
+
+ // Ensure that the object was actually placed into the map.
+ DCHECK(emplace_times_result.second);
+ DCHECK(emplace_names_result.second);
+}
+
+void Simulator::Schedule(Actor* actor, QuicTime new_time) {
+ auto scheduled_time_it = scheduled_times_.find(actor);
+ DCHECK(scheduled_time_it != scheduled_times_.end());
+ QuicTime scheduled_time = scheduled_time_it->second;
+
+ if (scheduled_time <= new_time) {
+ return;
+ }
+
+ if (scheduled_time != QuicTime::Infinite()) {
+ Unschedule(actor);
+ }
+
+ scheduled_time_it->second = new_time;
+ schedule_.insert(std::make_pair(new_time, actor));
+}
+
+void Simulator::Unschedule(Actor* actor) {
+ auto scheduled_time_it = scheduled_times_.find(actor);
+ DCHECK(scheduled_time_it != scheduled_times_.end());
+ QuicTime scheduled_time = scheduled_time_it->second;
+
+ DCHECK(scheduled_time != QuicTime::Infinite());
+ auto range = schedule_.equal_range(scheduled_time);
+ for (auto it = range.first; it != range.second; ++it) {
+ if (it->second == actor) {
+ schedule_.erase(it);
+ scheduled_time_it->second = QuicTime::Infinite();
+ return;
+ }
+ }
+ DCHECK(false);
+}
+
+const QuicClock* Simulator::GetClock() const {
+ return &clock_;
+}
+
+QuicRandom* Simulator::GetRandomGenerator() {
+ if (random_generator_ == nullptr) {
+ random_generator_ = QuicRandom::GetInstance();
+ }
+
+ return random_generator_;
+}
+
+QuicBufferAllocator* Simulator::GetBufferAllocator() {
+ return &buffer_allocator_;
+}
+
+QuicAlarmFactory* Simulator::GetAlarmFactory() {
+ return &alarm_factory_;
+}
+
+Simulator::RunForDelegate::RunForDelegate(bool* run_for_should_stop)
+ : run_for_should_stop_(run_for_should_stop) {}
+
+void Simulator::RunForDelegate::OnAlarm() {
+ *run_for_should_stop_ = true;
+}
+
+void Simulator::RunFor(QuicTime::Delta time_span) {
+ DCHECK(!run_for_alarm_->IsSet());
+
+ // RunFor() ensures that the simulation stops at the exact time specified by
+ // scheduling an alarm at that point and using that alarm to abort the
+ // simulation. An alarm is necessary because otherwise it is possible that
+ // nothing is scheduled at |end_time|, so the simulation will either go
+ // further than requested or stop before reaching |end_time|.
+ const QuicTime end_time = clock_.Now() + time_span;
+ run_for_alarm_->Set(end_time);
+ run_for_should_stop_ = false;
+ bool simulation_result = RunUntil([this]() { return run_for_should_stop_; });
+
+ DCHECK(simulation_result);
+ DCHECK(clock_.Now() == end_time);
+}
+
+void Simulator::HandleNextScheduledActor() {
+ const auto current_event_it = schedule_.begin();
+ QuicTime event_time = current_event_it->first;
+ Actor* actor = current_event_it->second;
+ DVLOG(3) << "At t = " << event_time.ToDebuggingValue() << ", calling "
+ << actor->name();
+
+ Unschedule(actor);
+
+ if (clock_.Now() > event_time) {
+ QUIC_BUG << "Error: event registered by [" << actor->name()
+ << "] requires travelling back in time. Current time: "
+ << clock_.Now().ToDebuggingValue()
+ << ", scheduled time: " << event_time.ToDebuggingValue();
+ }
+ clock_.now_ = event_time;
+
+ actor->Act();
+}
+
+} // namespace simulator
+} // namespace net
diff --git a/chromium/net/quic/test_tools/simulator/simulator.h b/chromium/net/quic/test_tools/simulator/simulator.h
new file mode 100644
index 00000000000..da485d25bb3
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/simulator.h
@@ -0,0 +1,155 @@
+// 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.
+
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_SIMULATOR_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_SIMULATOR_H_
+
+#include <map>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_simple_buffer_allocator.h"
+#include "net/quic/test_tools/simulator/actor.h"
+#include "net/quic/test_tools/simulator/alarm_factory.h"
+
+namespace net {
+namespace simulator {
+
+// Simulator is responsible for scheduling actors in the simulation and
+// providing basic utility interfaces (clock, alarms, RNG and others).
+class Simulator : public QuicConnectionHelperInterface {
+ public:
+ Simulator();
+ ~Simulator() override;
+
+ // Register an actor with the simulator. Returns a handle which the actor can
+ // use to schedule and unschedule itself.
+ void AddActor(Actor* actor);
+
+ // Schedule the specified actor. This method will ensure that |actor| is
+ // called at |new_time| at latest. If Schedule() is called multiple times
+ // before the Actor is called, Act() is called exactly once, at the earliest
+ // time requested, and the Actor has to reschedule itself manually for the
+ // subsequent times if they are still necessary.
+ void Schedule(Actor* actor, QuicTime new_time);
+
+ // Remove the specified actor from the schedule.
+ void Unschedule(Actor* actor);
+
+ // Begin QuicConnectionHelperInterface implementation.
+ const QuicClock* GetClock() const override;
+ QuicRandom* GetRandomGenerator() override;
+ QuicBufferAllocator* GetBufferAllocator() override;
+ // End QuicConnectionHelperInterface implementation.
+
+ QuicAlarmFactory* GetAlarmFactory();
+
+ inline void set_random_generator(QuicRandom* random) {
+ random_generator_ = random;
+ }
+
+ // Run the simulation until either no actors are scheduled or
+ // |termination_predicate| returns true. Returns true if terminated due to
+ // predicate, and false otherwise.
+ template <class TerminationPredicate>
+ bool RunUntil(TerminationPredicate termination_predicate);
+
+ // Same as RunUntil, except this function also accepts a |deadline|, and will
+ // return false if the deadline is exceeded.
+ template <class TerminationPredicate>
+ bool RunUntilOrTimeout(TerminationPredicate termination_predicate,
+ QuicTime::Delta deadline);
+
+ // Runs the simulation for exactly the specified |time_span|.
+ void RunFor(QuicTime::Delta time_span);
+
+ private:
+ class Clock : public QuicClock {
+ public:
+ // Do not start at zero as certain code can treat zero as an invalid
+ // timestamp.
+ const QuicTime kStartTime =
+ QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(1);
+
+ Clock();
+
+ QuicTime ApproximateNow() const override;
+ QuicTime Now() const override;
+ QuicWallTime WallNow() const override;
+
+ QuicTime now_;
+ };
+
+ // The delegate used for RunFor().
+ class RunForDelegate : public QuicAlarm::Delegate {
+ public:
+ explicit RunForDelegate(bool* run_for_should_stop);
+ void OnAlarm() override;
+
+ private:
+ // Pointer to |run_for_should_stop_| in the parent simulator.
+ bool* run_for_should_stop_;
+ };
+
+ // Finds the next scheduled actor, advances time to the schedule time and
+ // notifies the actor.
+ void HandleNextScheduledActor();
+
+ Clock clock_;
+ QuicRandom* random_generator_;
+ SimpleBufferAllocator buffer_allocator_;
+ AlarmFactory alarm_factory_;
+
+ // Alarm for RunFor() method.
+ std::unique_ptr<QuicAlarm> run_for_alarm_;
+ // Flag used to stop simulations ran via RunFor().
+ bool run_for_should_stop_;
+
+ // Schedule of when the actors will be executed via an Act() call. The
+ // schedule is subject to the following invariants:
+ // - An actor cannot be scheduled for a later time than it's currently in the
+ // schedule.
+ // - An actor is removed from schedule either immediately before Act() is
+ // called or by explicitly calling Unschedule().
+ // - Each Actor appears in the map at most once.
+ std::multimap<QuicTime, Actor*> schedule_;
+ // For each actor, maintain the time it is scheduled at. The value for
+ // unscheduled actors is QuicTime::Infinite().
+ std::unordered_map<Actor*, QuicTime> scheduled_times_;
+ std::unordered_set<std::string> actor_names_;
+
+ DISALLOW_COPY_AND_ASSIGN(Simulator);
+};
+
+template <class TerminationPredicate>
+bool Simulator::RunUntil(TerminationPredicate termination_predicate) {
+ while (!schedule_.empty()) {
+ if (termination_predicate()) {
+ return true;
+ }
+ HandleNextScheduledActor();
+ }
+ return false;
+}
+
+template <class TerminationPredicate>
+bool Simulator::RunUntilOrTimeout(TerminationPredicate termination_predicate,
+ QuicTime::Delta timeout) {
+ QuicTime end_time = clock_.Now() + timeout;
+ bool return_value = RunUntil([end_time, &termination_predicate, this]() {
+ return termination_predicate() || clock_.Now() >= end_time;
+ });
+
+ if (clock_.Now() >= end_time) {
+ return false;
+ }
+ return return_value;
+}
+
+} // namespace simulator
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_SIMULATOR_SIMULATOR_H_
diff --git a/chromium/net/quic/test_tools/simulator/simulator_test.cc b/chromium/net/quic/test_tools/simulator/simulator_test.cc
new file mode 100644
index 00000000000..75a19e58ea3
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/simulator_test.cc
@@ -0,0 +1,564 @@
+// 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/test_tools/simulator/simulator.h"
+
+#include "base/memory/ptr_util.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/quic/test_tools/simulator/alarm_factory.h"
+#include "net/quic/test_tools/simulator/link.h"
+#include "net/quic/test_tools/simulator/queue.h"
+#include "net/quic/test_tools/simulator/switch.h"
+
+#include "net/test/gtest_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace simulator {
+
+// A simple counter that increments its value by 1 every specified period.
+class Counter : public Actor {
+ public:
+ Counter(Simulator* simulator, std::string name, QuicTime::Delta period)
+ : Actor(simulator, name), value_(-1), period_(period) {
+ Schedule(clock_->Now());
+ }
+ ~Counter() override {}
+
+ inline int get_value() const { return value_; }
+
+ void Act() override {
+ ++value_;
+ DVLOG(1) << name_ << " has value " << value_ << " at time "
+ << clock_->Now().ToDebuggingValue();
+ Schedule(clock_->Now() + period_);
+ }
+
+ private:
+ int value_;
+ QuicTime::Delta period_;
+};
+
+// Test that the basic event handling works.
+TEST(SimulatorTest, Counters) {
+ Simulator simulator;
+ Counter fast_counter(&simulator, "fast_counter",
+ QuicTime::Delta::FromSeconds(3));
+ Counter slow_counter(&simulator, "slow_counter",
+ QuicTime::Delta::FromSeconds(10));
+
+ simulator.RunUntil(
+ [&slow_counter]() { return slow_counter.get_value() >= 10; });
+
+ EXPECT_EQ(10, slow_counter.get_value());
+ EXPECT_EQ(10 * 10 / 3, fast_counter.get_value());
+}
+
+// A port which counts the number of packets received on it, both total and
+// per-destination.
+class CounterPort : public UnconstrainedPortInterface {
+ public:
+ CounterPort() { Reset(); }
+ ~CounterPort() override {}
+
+ inline QuicByteCount bytes() const { return bytes_; }
+ inline QuicPacketCount packets() const { return packets_; }
+
+ void AcceptPacket(std::unique_ptr<Packet> packet) override {
+ bytes_ += packet->size;
+ packets_ += 1;
+
+ per_destination_packet_counter_[packet->destination] += 1;
+ }
+
+ void Reset() {
+ bytes_ = 0;
+ packets_ = 0;
+ per_destination_packet_counter_.clear();
+ }
+
+ QuicPacketCount CountPacketsForDestination(std::string destination) const {
+ auto result_it = per_destination_packet_counter_.find(destination);
+ if (result_it == per_destination_packet_counter_.cend()) {
+ return 0;
+ }
+ return result_it->second;
+ }
+
+ private:
+ QuicByteCount bytes_;
+ QuicPacketCount packets_;
+
+ std::unordered_map<std::string, QuicPacketCount>
+ per_destination_packet_counter_;
+};
+
+// Sends the packet to the specified destination at the uplink rate. Provides a
+// CounterPort as an Rx interface.
+class LinkSaturator : public Endpoint {
+ public:
+ LinkSaturator(Simulator* simulator,
+ std::string name,
+ QuicByteCount packet_size,
+ std::string destination)
+ : Endpoint(simulator, name),
+ packet_size_(packet_size),
+ destination_(std::move(destination)),
+ bytes_transmitted_(0),
+ packets_transmitted_(0) {
+ Schedule(clock_->Now());
+ }
+
+ void Act() override {
+ if (tx_port_->TimeUntilAvailable().IsZero()) {
+ auto packet = base::MakeUnique<Packet>();
+ packet->source = name_;
+ packet->destination = destination_;
+ packet->tx_timestamp = clock_->Now();
+ packet->size = packet_size_;
+
+ tx_port_->AcceptPacket(std::move(packet));
+
+ bytes_transmitted_ += packet_size_;
+ packets_transmitted_ += 1;
+ }
+
+ Schedule(clock_->Now() + tx_port_->TimeUntilAvailable());
+ }
+
+ UnconstrainedPortInterface* GetRxPort() override {
+ return static_cast<UnconstrainedPortInterface*>(&rx_port_);
+ }
+
+ void SetTxPort(ConstrainedPortInterface* port) override { tx_port_ = port; }
+
+ CounterPort* counter() { return &rx_port_; }
+
+ inline QuicByteCount bytes_transmitted() const { return bytes_transmitted_; }
+ inline QuicPacketCount packets_transmitted() const {
+ return packets_transmitted_;
+ }
+
+ private:
+ QuicByteCount packet_size_;
+ std::string destination_;
+
+ ConstrainedPortInterface* tx_port_;
+ CounterPort rx_port_;
+
+ QuicByteCount bytes_transmitted_;
+ QuicPacketCount packets_transmitted_;
+};
+
+// Saturate a symmetric link and verify that the number of packets sent and
+// received is correct.
+TEST(SimulatorTest, DirectLinkSaturation) {
+ Simulator simulator;
+ LinkSaturator saturator_a(&simulator, "Saturator A", 1000, "Saturator B");
+ LinkSaturator saturator_b(&simulator, "Saturator B", 100, "Saturator A");
+ SymmetricLink link(&saturator_a, &saturator_b,
+ QuicBandwidth::FromKBytesPerSecond(1000),
+ QuicTime::Delta::FromMilliseconds(100) +
+ QuicTime::Delta::FromMicroseconds(1));
+
+ const QuicTime start_time = simulator.GetClock()->Now();
+ const QuicTime after_first_50_ms =
+ start_time + QuicTime::Delta::FromMilliseconds(50);
+ simulator.RunUntil([&simulator, after_first_50_ms]() {
+ return simulator.GetClock()->Now() >= after_first_50_ms;
+ });
+ EXPECT_LE(1000u * 50u, saturator_a.bytes_transmitted());
+ EXPECT_GE(1000u * 51u, saturator_a.bytes_transmitted());
+ EXPECT_LE(1000u * 50u, saturator_b.bytes_transmitted());
+ EXPECT_GE(1000u * 51u, saturator_b.bytes_transmitted());
+ EXPECT_LE(50u, saturator_a.packets_transmitted());
+ EXPECT_GE(51u, saturator_a.packets_transmitted());
+ EXPECT_LE(500u, saturator_b.packets_transmitted());
+ EXPECT_GE(501u, saturator_b.packets_transmitted());
+ EXPECT_EQ(0u, saturator_a.counter()->bytes());
+ EXPECT_EQ(0u, saturator_b.counter()->bytes());
+
+ simulator.RunUntil([&saturator_a, &saturator_b]() {
+ if (saturator_a.counter()->packets() > 1000 ||
+ saturator_b.counter()->packets() > 100) {
+ ADD_FAILURE() << "The simulation did not arrive at the expected "
+ "termination contidition. Saturator A counter: "
+ << saturator_a.counter()->packets()
+ << ", saturator B counter: "
+ << saturator_b.counter()->packets();
+ return true;
+ }
+
+ return saturator_a.counter()->packets() == 1000 &&
+ saturator_b.counter()->packets() == 100;
+ });
+ EXPECT_EQ(201u, saturator_a.packets_transmitted());
+ EXPECT_EQ(2001u, saturator_b.packets_transmitted());
+ EXPECT_EQ(201u * 1000, saturator_a.bytes_transmitted());
+ EXPECT_EQ(2001u * 100, saturator_b.bytes_transmitted());
+
+ EXPECT_EQ(1000u,
+ saturator_a.counter()->CountPacketsForDestination("Saturator A"));
+ EXPECT_EQ(100u,
+ saturator_b.counter()->CountPacketsForDestination("Saturator B"));
+ EXPECT_EQ(0u,
+ saturator_a.counter()->CountPacketsForDestination("Saturator B"));
+ EXPECT_EQ(0u,
+ saturator_b.counter()->CountPacketsForDestination("Saturator A"));
+
+ const QuicTime end_time = simulator.GetClock()->Now();
+ const QuicBandwidth observed_bandwidth = QuicBandwidth::FromBytesAndTimeDelta(
+ saturator_a.bytes_transmitted(), end_time - start_time);
+ test::ExpectApproxEq(link.bandwidth(), observed_bandwidth, 0.01f);
+}
+
+// Accepts packets and stores them internally.
+class PacketAcceptor : public ConstrainedPortInterface {
+ public:
+ void AcceptPacket(std::unique_ptr<Packet> packet) override {
+ packets_.emplace_back(std::move(packet));
+ }
+
+ QuicTime::Delta TimeUntilAvailable() override {
+ return QuicTime::Delta::Zero();
+ }
+
+ std::vector<std::unique_ptr<Packet>>* packets() { return &packets_; }
+
+ private:
+ std::vector<std::unique_ptr<Packet>> packets_;
+};
+
+// Ensure the queue behaves correctly with accepting packets.
+TEST(SimulatorTest, Queue) {
+ Simulator simulator;
+ Queue queue(&simulator, "Queue", 1000);
+ PacketAcceptor acceptor;
+ queue.set_tx_port(&acceptor);
+
+ EXPECT_EQ(0u, queue.bytes_queued());
+ EXPECT_EQ(0u, queue.packets_queued());
+ EXPECT_EQ(0u, acceptor.packets()->size());
+
+ auto first_packet = base::MakeUnique<Packet>();
+ first_packet->size = 600;
+ queue.AcceptPacket(std::move(first_packet));
+ EXPECT_EQ(600u, queue.bytes_queued());
+ EXPECT_EQ(1u, queue.packets_queued());
+ EXPECT_EQ(0u, acceptor.packets()->size());
+
+ // The second packet does not fit and is dropped.
+ auto second_packet = base::MakeUnique<Packet>();
+ second_packet->size = 500;
+ queue.AcceptPacket(std::move(second_packet));
+ EXPECT_EQ(600u, queue.bytes_queued());
+ EXPECT_EQ(1u, queue.packets_queued());
+ EXPECT_EQ(0u, acceptor.packets()->size());
+
+ auto third_packet = base::MakeUnique<Packet>();
+ third_packet->size = 400;
+ queue.AcceptPacket(std::move(third_packet));
+ EXPECT_EQ(1000u, queue.bytes_queued());
+ EXPECT_EQ(2u, queue.packets_queued());
+ EXPECT_EQ(0u, acceptor.packets()->size());
+
+ // Run until there is nothing scheduled, so that the queue can deplete.
+ simulator.RunUntil([]() { return false; });
+ EXPECT_EQ(0u, queue.bytes_queued());
+ EXPECT_EQ(0u, queue.packets_queued());
+ ASSERT_EQ(2u, acceptor.packets()->size());
+ EXPECT_EQ(600u, acceptor.packets()->at(0)->size);
+ EXPECT_EQ(400u, acceptor.packets()->at(1)->size);
+}
+
+// Simulate a situation where the bottleneck link is 10 times slower than the
+// uplink, and they are separated by a queue.
+TEST(SimulatorTest, QueueBottleneck) {
+ const QuicBandwidth local_bandwidth =
+ QuicBandwidth::FromKBytesPerSecond(1000);
+ const QuicBandwidth bottleneck_bandwidth = 0.1f * local_bandwidth;
+ const QuicTime::Delta local_propagation_delay =
+ QuicTime::Delta::FromMilliseconds(1);
+ const QuicTime::Delta bottleneck_propagation_delay =
+ QuicTime::Delta::FromMilliseconds(20);
+ const QuicByteCount bdp =
+ bottleneck_bandwidth *
+ (local_propagation_delay + bottleneck_propagation_delay);
+
+ Simulator simulator;
+ LinkSaturator saturator(&simulator, "Saturator", 1000, "Counter");
+ ASSERT_GE(bdp, 1000u);
+ Queue queue(&simulator, "Queue", bdp);
+ CounterPort counter;
+
+ OneWayLink local_link(&simulator, "Local link", &queue, local_bandwidth,
+ local_propagation_delay);
+ OneWayLink bottleneck_link(&simulator, "Bottleneck link", &counter,
+ bottleneck_bandwidth,
+ bottleneck_propagation_delay);
+ saturator.SetTxPort(&local_link);
+ queue.set_tx_port(&bottleneck_link);
+
+ const QuicPacketCount packets_received = 1000;
+ simulator.RunUntil([&counter, packets_received]() {
+ return counter.packets() == packets_received;
+ });
+ const double loss_ratio =
+ 1 -
+ static_cast<double>(packets_received) / saturator.packets_transmitted();
+ EXPECT_NEAR(loss_ratio, 0.9, 0.001);
+}
+
+// Verify that the queue of exactly one packet allows the transmission to
+// actually go through.
+TEST(SimulatorTest, OnePacketQueue) {
+ const QuicBandwidth local_bandwidth =
+ QuicBandwidth::FromKBytesPerSecond(1000);
+ const QuicBandwidth bottleneck_bandwidth = 0.1f * local_bandwidth;
+ const QuicTime::Delta local_propagation_delay =
+ QuicTime::Delta::FromMilliseconds(1);
+ const QuicTime::Delta bottleneck_propagation_delay =
+ QuicTime::Delta::FromMilliseconds(20);
+
+ Simulator simulator;
+ LinkSaturator saturator(&simulator, "Saturator", 1000, "Counter");
+ Queue queue(&simulator, "Queue", 1000);
+ CounterPort counter;
+
+ OneWayLink local_link(&simulator, "Local link", &queue, local_bandwidth,
+ local_propagation_delay);
+ OneWayLink bottleneck_link(&simulator, "Bottleneck link", &counter,
+ bottleneck_bandwidth,
+ bottleneck_propagation_delay);
+ saturator.SetTxPort(&local_link);
+ queue.set_tx_port(&bottleneck_link);
+
+ const QuicPacketCount packets_received = 10;
+ // The deadline here is to prevent this tests from looping infinitely in case
+ // the packets never reach the receiver.
+ const QuicTime deadline =
+ simulator.GetClock()->Now() + QuicTime::Delta::FromSeconds(10);
+ simulator.RunUntil([&simulator, &counter, packets_received, deadline]() {
+ return counter.packets() == packets_received ||
+ simulator.GetClock()->Now() > deadline;
+ });
+ ASSERT_EQ(packets_received, counter.packets());
+}
+
+// Simulate a network where three endpoints are connected to a switch and they
+// are sending traffic in circle (1 -> 2, 2 -> 3, 3 -> 1).
+TEST(SimulatorTest, SwitchedNetwork) {
+ const QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond(10000);
+ const QuicTime::Delta base_propagation_delay =
+ QuicTime::Delta::FromMilliseconds(50);
+
+ Simulator simulator;
+ LinkSaturator saturator1(&simulator, "Saturator 1", 1000, "Saturator 2");
+ LinkSaturator saturator2(&simulator, "Saturator 2", 1000, "Saturator 3");
+ LinkSaturator saturator3(&simulator, "Saturator 3", 1000, "Saturator 1");
+ Switch network_switch(&simulator, "Switch", 8,
+ bandwidth * base_propagation_delay * 10);
+
+ // For determinicity, make it so that the first packet will arrive from
+ // Saturator 1, then from Saturator 2, and then from Saturator 3.
+ SymmetricLink link1(&saturator1, network_switch.port(1), bandwidth,
+ base_propagation_delay);
+ SymmetricLink link2(&saturator2, network_switch.port(2), bandwidth,
+ base_propagation_delay * 2);
+ SymmetricLink link3(&saturator3, network_switch.port(3), bandwidth,
+ base_propagation_delay * 3);
+
+ const QuicTime start_time = simulator.GetClock()->Now();
+ const QuicPacketCount bytes_received = 64 * 1000;
+ simulator.RunUntil([&saturator1, bytes_received]() {
+ return saturator1.counter()->bytes() >= bytes_received;
+ });
+ const QuicTime end_time = simulator.GetClock()->Now();
+
+ const QuicBandwidth observed_bandwidth = QuicBandwidth::FromBytesAndTimeDelta(
+ bytes_received, end_time - start_time);
+ const double bandwidth_ratio =
+ static_cast<double>(observed_bandwidth.ToBitsPerSecond()) /
+ bandwidth.ToBitsPerSecond();
+ EXPECT_NEAR(1, bandwidth_ratio, 0.1);
+
+ const double normalized_received_packets_for_saturator_2 =
+ static_cast<double>(saturator2.counter()->packets()) /
+ saturator1.counter()->packets();
+ const double normalized_received_packets_for_saturator_3 =
+ static_cast<double>(saturator3.counter()->packets()) /
+ saturator1.counter()->packets();
+ EXPECT_NEAR(1, normalized_received_packets_for_saturator_2, 0.1);
+ EXPECT_NEAR(1, normalized_received_packets_for_saturator_3, 0.1);
+
+ // Since Saturator 1 has its packet arrive first into the switch, switch will
+ // always know how to route traffic to it.
+ EXPECT_EQ(0u,
+ saturator2.counter()->CountPacketsForDestination("Saturator 1"));
+ EXPECT_EQ(0u,
+ saturator3.counter()->CountPacketsForDestination("Saturator 1"));
+
+ // Packets from the other saturators will be broadcast at least once.
+ EXPECT_EQ(1u,
+ saturator1.counter()->CountPacketsForDestination("Saturator 2"));
+ EXPECT_EQ(1u,
+ saturator3.counter()->CountPacketsForDestination("Saturator 2"));
+ EXPECT_EQ(1u,
+ saturator1.counter()->CountPacketsForDestination("Saturator 3"));
+ EXPECT_EQ(1u,
+ saturator2.counter()->CountPacketsForDestination("Saturator 3"));
+}
+
+// Toggle an alarm on and off at the specified interval. Assumes that alarm is
+// initially set and unsets it almost immediately after the object is
+// instantiated.
+class AlarmToggler : public Actor {
+ public:
+ AlarmToggler(Simulator* simulator,
+ std::string name,
+ QuicAlarm* alarm,
+ QuicTime::Delta interval)
+ : Actor(simulator, name),
+ alarm_(alarm),
+ interval_(interval),
+ deadline_(alarm->deadline()),
+ times_set_(0),
+ times_cancelled_(0) {
+ EXPECT_TRUE(alarm->IsSet());
+ EXPECT_GE(alarm->deadline(), clock_->Now());
+ Schedule(clock_->Now());
+ }
+
+ void Act() override {
+ if (deadline_ <= clock_->Now()) {
+ return;
+ }
+
+ if (alarm_->IsSet()) {
+ alarm_->Cancel();
+ times_cancelled_++;
+ } else {
+ alarm_->Set(deadline_);
+ times_set_++;
+ }
+
+ Schedule(clock_->Now() + interval_);
+ }
+
+ inline int times_set() { return times_set_; }
+ inline int times_cancelled() { return times_cancelled_; }
+
+ private:
+ QuicAlarm* alarm_;
+ QuicTime::Delta interval_;
+ QuicTime deadline_;
+
+ // Counts the number of times the alarm was set.
+ int times_set_;
+ // Counts the number of times the alarm was cancelled.
+ int times_cancelled_;
+};
+
+// Counts the number of times an alarm has fired.
+class CounterDelegate : public QuicAlarm::Delegate {
+ public:
+ explicit CounterDelegate(size_t* counter) : counter_(counter) {}
+
+ void OnAlarm() override { *counter_ += 1; }
+
+ private:
+ size_t* counter_;
+};
+
+// Verifies that the alarms work correctly, even when they are repeatedly
+// toggled.
+TEST(SimulatorTest, Alarms) {
+ Simulator simulator;
+ QuicAlarmFactory* alarm_factory = simulator.GetAlarmFactory();
+
+ size_t fast_alarm_counter = 0;
+ size_t slow_alarm_counter = 0;
+ std::unique_ptr<QuicAlarm> alarm_fast(
+ alarm_factory->CreateAlarm(new CounterDelegate(&fast_alarm_counter)));
+ std::unique_ptr<QuicAlarm> alarm_slow(
+ alarm_factory->CreateAlarm(new CounterDelegate(&slow_alarm_counter)));
+
+ const QuicTime start_time = simulator.GetClock()->Now();
+ alarm_fast->Set(start_time + QuicTime::Delta::FromMilliseconds(100));
+ alarm_slow->Set(start_time + QuicTime::Delta::FromMilliseconds(750));
+ AlarmToggler toggler(&simulator, "Toggler", alarm_slow.get(),
+ QuicTime::Delta::FromMilliseconds(100));
+
+ const QuicTime end_time =
+ start_time + QuicTime::Delta::FromMilliseconds(1000);
+ EXPECT_FALSE(simulator.RunUntil([&simulator, end_time]() {
+ return simulator.GetClock()->Now() >= end_time;
+ }));
+ EXPECT_EQ(1u, slow_alarm_counter);
+ EXPECT_EQ(1u, fast_alarm_counter);
+
+ EXPECT_EQ(4, toggler.times_set());
+ EXPECT_EQ(4, toggler.times_cancelled());
+}
+
+// Verifies that a cancelled alarm is never fired.
+TEST(SimulatorTest, AlarmCancelling) {
+ Simulator simulator;
+ QuicAlarmFactory* alarm_factory = simulator.GetAlarmFactory();
+
+ size_t alarm_counter = 0;
+ std::unique_ptr<QuicAlarm> alarm(
+ alarm_factory->CreateAlarm(new CounterDelegate(&alarm_counter)));
+
+ const QuicTime start_time = simulator.GetClock()->Now();
+ const QuicTime alarm_at = start_time + QuicTime::Delta::FromMilliseconds(300);
+ const QuicTime end_time = start_time + QuicTime::Delta::FromMilliseconds(400);
+
+ alarm->Set(alarm_at);
+ alarm->Cancel();
+ EXPECT_FALSE(alarm->IsSet());
+
+ EXPECT_FALSE(simulator.RunUntil([&simulator, end_time]() {
+ return simulator.GetClock()->Now() >= end_time;
+ }));
+
+ EXPECT_FALSE(alarm->IsSet());
+ EXPECT_EQ(0u, alarm_counter);
+}
+
+// Tests Simulator::RunUntilOrTimeout() interface.
+TEST(SimulatorTest, RunUntilOrTimeout) {
+ Simulator simulator;
+ bool simulation_result;
+
+ // Count the number of seconds since the beginning of the simulation.
+ Counter counter(&simulator, "counter", QuicTime::Delta::FromSeconds(1));
+
+ // Ensure that the counter reaches the value of 10 given a 20 second deadline.
+ simulation_result = simulator.RunUntilOrTimeout(
+ [&counter]() { return counter.get_value() == 10; },
+ QuicTime::Delta::FromSeconds(20));
+ ASSERT_TRUE(simulation_result);
+
+ // Ensure that the counter will not reach the value of 100 given that the
+ // starting value is 10 and the deadline is 20 seconds.
+ simulation_result = simulator.RunUntilOrTimeout(
+ [&counter]() { return counter.get_value() == 100; },
+ QuicTime::Delta::FromSeconds(20));
+ ASSERT_FALSE(simulation_result);
+}
+
+// Tests Simulator::RunFor() interface.
+TEST(SimulatorTest, RunFor) {
+ Simulator simulator;
+
+ Counter counter(&simulator, "counter", QuicTime::Delta::FromSeconds(3));
+
+ simulator.RunFor(QuicTime::Delta::FromSeconds(100));
+
+ EXPECT_EQ(33, counter.get_value());
+}
+
+} // namespace simulator
+} // namespace net
diff --git a/chromium/net/quic/test_tools/simulator/switch.cc b/chromium/net/quic/test_tools/simulator/switch.cc
new file mode 100644
index 00000000000..6490274cb9a
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/switch.cc
@@ -0,0 +1,87 @@
+// 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 <cinttypes>
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/stringprintf.h"
+#include "net/quic/test_tools/simulator/switch.h"
+
+using base::StringPrintf;
+
+namespace net {
+namespace simulator {
+
+Switch::Switch(Simulator* simulator,
+ std::string name,
+ SwitchPortNumber port_count,
+ QuicByteCount queue_capacity) {
+ for (size_t port_number = 1; port_number <= port_count; port_number++) {
+ ports_.emplace_back(
+ simulator, StringPrintf("%s (port %zu)", name.c_str(), port_number),
+ this, port_number, queue_capacity);
+ }
+}
+
+Switch::~Switch() {}
+
+Switch::Port::Port(Simulator* simulator,
+ std::string name,
+ Switch* parent,
+ SwitchPortNumber port_number,
+ QuicByteCount queue_capacity)
+ : Endpoint(simulator, name),
+ parent_(parent),
+ port_number_(port_number),
+ connected_(false),
+ queue_(simulator,
+ StringPrintf("%s (queue)", name.c_str()),
+ queue_capacity) {}
+
+void Switch::Port::AcceptPacket(std::unique_ptr<Packet> packet) {
+ parent_->DispatchPacket(port_number_, std::move(packet));
+}
+
+void Switch::Port::EnqueuePacket(std::unique_ptr<Packet> packet) {
+ queue_.AcceptPacket(std::move(packet));
+}
+
+UnconstrainedPortInterface* Switch::Port::GetRxPort() {
+ return this;
+}
+
+void Switch::Port::SetTxPort(ConstrainedPortInterface* port) {
+ queue_.set_tx_port(port);
+ connected_ = true;
+}
+
+void Switch::Port::Act() {}
+
+void Switch::DispatchPacket(SwitchPortNumber port_number,
+ std::unique_ptr<Packet> packet) {
+ Port* source_port = &ports_[port_number - 1];
+ const auto source_mapping_it = switching_table_.find(packet->source);
+ if (source_mapping_it == switching_table_.end()) {
+ switching_table_.insert(std::make_pair(packet->source, source_port));
+ }
+
+ const auto destination_mapping_it =
+ switching_table_.find(packet->destination);
+ if (destination_mapping_it != switching_table_.end()) {
+ destination_mapping_it->second->EnqueuePacket(std::move(packet));
+ return;
+ }
+
+ // If no mapping is available yet, broadcast the packet to all ports
+ // different from the source.
+ for (Port& egress_port : ports_) {
+ if (!egress_port.connected()) {
+ continue;
+ }
+ egress_port.EnqueuePacket(base::MakeUnique<Packet>(*packet));
+ }
+}
+
+} // namespace simulator
+} // namespace net
diff --git a/chromium/net/quic/test_tools/simulator/switch.h b/chromium/net/quic/test_tools/simulator/switch.h
new file mode 100644
index 00000000000..c6177c5e414
--- /dev/null
+++ b/chromium/net/quic/test_tools/simulator/switch.h
@@ -0,0 +1,86 @@
+// 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.
+
+#ifndef NET_QUIC_TEST_TOOLS_SIMULATOR_SWITCH_H_
+#define NET_QUIC_TEST_TOOLS_SIMULATOR_SWITCH_H_
+
+#include <unordered_map>
+
+#include "net/quic/test_tools/simulator/queue.h"
+
+namespace net {
+namespace simulator {
+
+typedef size_t SwitchPortNumber;
+
+// Simulates a network switch with simple persistent learning scheme and queues
+// on every output port.
+class Switch {
+ public:
+ Switch(Simulator* simulator,
+ std::string name,
+ SwitchPortNumber port_count,
+ QuicByteCount queue_capacity);
+ ~Switch();
+
+ // Returns Endpoint associated with the port under number |port_number|. Just
+ // like on most real switches, port numbering starts with 1.
+ inline Endpoint* port(SwitchPortNumber port_number) {
+ DCHECK_NE(port_number, 0u);
+ return &ports_[port_number - 1];
+ }
+
+ inline const Queue* port_queue(SwitchPortNumber port_number) {
+ return ports_[port_number - 1].queue();
+ }
+
+ private:
+ class Port : public Endpoint, public UnconstrainedPortInterface {
+ public:
+ Port(Simulator* simulator,
+ std::string name,
+ Switch* parent,
+ SwitchPortNumber port_number,
+ QuicByteCount queue_capacity);
+ Port(Port&&) = delete;
+ ~Port() override {}
+
+ // Accepts packet to be routed into the switch.
+ void AcceptPacket(std::unique_ptr<Packet> packet) override;
+ // Enqueue packet to be routed out of the switch.
+ void EnqueuePacket(std::unique_ptr<Packet> packet);
+
+ UnconstrainedPortInterface* GetRxPort() override;
+ void SetTxPort(ConstrainedPortInterface* port) override;
+
+ void Act() override;
+
+ inline bool connected() const { return connected_; }
+ inline const Queue* queue() const { return &queue_; }
+
+ private:
+ Switch* parent_;
+ SwitchPortNumber port_number_;
+ bool connected_;
+
+ Queue queue_;
+
+ DISALLOW_COPY_AND_ASSIGN(Port);
+ };
+
+ // Sends the packet to the appropriate port, or to all ports if the
+ // appropriate port is not known.
+ void DispatchPacket(SwitchPortNumber port_number,
+ std::unique_ptr<Packet> packet);
+
+ std::deque<Port> ports_;
+ std::unordered_map<std::string, Port*> switching_table_;
+
+ DISALLOW_COPY_AND_ASSIGN(Switch);
+};
+
+} // namespace simulator
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_SIMULATOR_SWITCH_H_
diff --git a/chromium/net/sdch/sdch_owner.cc b/chromium/net/sdch/sdch_owner.cc
index 5dc949a3e2f..047e6665e31 100644
--- a/chromium/net/sdch/sdch_owner.cc
+++ b/chromium/net/sdch/sdch_owner.cc
@@ -10,6 +10,7 @@
#include "base/debug/alias.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/memory_coordinator_client_registry.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
@@ -17,6 +18,8 @@
#include "base/values.h"
#include "net/base/sdch_manager.h"
#include "net/base/sdch_net_log_params.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
namespace net {
@@ -309,6 +312,7 @@ SdchOwner::SdchOwner(SdchManager* sdch_manager, URLRequestContext* context)
creation_time_(clock_->Now()) {
manager_->AddObserver(this);
InitializePrefStore(pref_store_);
+ base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this);
}
SdchOwner::~SdchOwner() {
@@ -337,6 +341,7 @@ SdchOwner::~SdchOwner() {
val / object_lifetime);
}
}
+ base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(this);
}
void SdchOwner::EnablePersistentStorage(
@@ -364,7 +369,7 @@ void SdchOwner::OnDictionaryFetched(base::Time last_used,
int use_count,
const std::string& dictionary_text,
const GURL& dictionary_url,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
bool was_from_cache) {
struct DictionaryItem {
base::Time last_used;
@@ -419,7 +424,7 @@ void SdchOwner::OnDictionaryFetched(base::Time last_used,
max_total_dictionary_size_) {
RecordDictionaryFate(DICTIONARY_FATE_FETCH_IGNORED_NO_SPACE);
SdchManager::SdchErrorRecovery(SDCH_DICTIONARY_NO_ROOM);
- net_log.AddEvent(NetLog::TYPE_SDCH_DICTIONARY_ERROR,
+ net_log.AddEvent(NetLogEventType::SDCH_DICTIONARY_ERROR,
base::Bind(&NetLogSdchDictionaryFetchProblemCallback,
SDCH_DICTIONARY_NO_ROOM, dictionary_url, true));
return;
@@ -434,7 +439,7 @@ void SdchOwner::OnDictionaryFetched(base::Time last_used,
if (rv != SDCH_OK) {
RecordDictionaryFate(DICTIONARY_FATE_FETCH_MANAGER_REFUSED);
SdchManager::SdchErrorRecovery(rv);
- net_log.AddEvent(NetLog::TYPE_SDCH_DICTIONARY_ERROR,
+ net_log.AddEvent(NetLogEventType::SDCH_DICTIONARY_ERROR,
base::Bind(&NetLogSdchDictionaryFetchProblemCallback, rv,
dictionary_url, true));
return;
@@ -672,7 +677,28 @@ void SdchOwner::SetFetcherForTesting(
void SdchOwner::OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel level) {
DCHECK_NE(base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, level);
+ ClearData();
+}
+
+void SdchOwner::OnMemoryStateChange(base::MemoryState state) {
+ // TODO(hajimehoshi): When the state changes, adjust the sizes of the caches
+ // to reduce the limits. SdchOwner doesn't have the ability to limit at
+ // present.
+ switch (state) {
+ case base::MemoryState::NORMAL:
+ break;
+ case base::MemoryState::THROTTLED:
+ ClearData();
+ break;
+ case base::MemoryState::SUSPENDED:
+ // Note: Not supported at present. Fall through.
+ case base::MemoryState::UNKNOWN:
+ NOTREACHED();
+ break;
+ }
+}
+void SdchOwner::ClearData() {
for (DictionaryPreferenceIterator it(pref_store_); !it.IsAtEnd();
it.Advance()) {
int new_uses = it.use_count() - use_counts_at_load_[it.server_hash()];
diff --git a/chromium/net/sdch/sdch_owner.h b/chromium/net/sdch/sdch_owner.h
index e6af26642f1..bf208f63aac 100644
--- a/chromium/net/sdch/sdch_owner.h
+++ b/chromium/net/sdch/sdch_owner.h
@@ -12,8 +12,10 @@
#include <string>
#include "base/macros.h"
+#include "base/memory/memory_coordinator_client.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/ref_counted.h"
+#include "net/base/net_export.h"
#include "net/base/sdch_observer.h"
#include "net/url_request/sdch_dictionary_fetcher.h"
@@ -24,6 +26,7 @@ class Clock;
}
namespace net {
+class NetLogWithSource;
class SdchManager;
class URLRequestContext;
@@ -31,7 +34,8 @@ class URLRequestContext;
// exposes interface for setting SDCH policy. It should be instantiated by
// the net/ embedder.
// TODO(rdsmith): Implement dictionary prioritization.
-class NET_EXPORT SdchOwner : public SdchObserver {
+class NET_EXPORT SdchOwner : public SdchObserver,
+ public base::MemoryCoordinatorClient {
public:
// Abstact storage interface for storing settings that allows the embedder
// to provide the appropriate storage backend.
@@ -128,7 +132,7 @@ class NET_EXPORT SdchOwner : public SdchObserver {
int use_count,
const std::string& dictionary_text,
const GURL& dictionary_url,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
bool was_from_cache);
void SetClockForTesting(std::unique_ptr<base::Clock> clock);
@@ -156,9 +160,15 @@ class NET_EXPORT SdchOwner : public SdchObserver {
DictionaryInfo& operator=(const DictionaryInfo& rhs) = default;
};
+ // base::MemoryCoordinatorClient implementation:
+ void OnMemoryStateChange(base::MemoryState state) override;
+
void OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel level);
+ // Clears data to save memory usage.
+ void ClearData();
+
// Schedule loading of all dictionaries described in |persisted_info|.
// Returns false and does not schedule a load if |persisted_info| has an
// unsupported version or no dictionaries key. Skips any dictionaries that are
diff --git a/chromium/net/sdch/sdch_owner_unittest.cc b/chromium/net/sdch/sdch_owner_unittest.cc
index 4a05a5960a4..29880efd7c4 100644
--- a/chromium/net/sdch/sdch_owner_unittest.cc
+++ b/chromium/net/sdch/sdch_owner_unittest.cc
@@ -18,7 +18,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "net/base/sdch_manager.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_error_job.h"
@@ -264,7 +264,7 @@ class MockSdchDictionaryFetcher : public SdchDictionaryFetcher {
bool CompletePendingRequest(const GURL& dictionary_url,
const std::string& dictionary_text,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
bool was_from_cache) {
for (std::vector<PendingRequest>::iterator it = requests_.begin();
it != requests_.end(); ++it) {
@@ -324,7 +324,7 @@ class SdchOwnerTest : public testing::Test {
SdchManager& sdch_manager() { return sdch_manager_; }
SdchOwner& sdch_owner() { return *(sdch_owner_.get()); }
- BoundNetLog& bound_net_log() { return net_log_; }
+ NetLogWithSource& net_log() { return net_log_; }
int JobsRecentlyCreated() {
int result = error_jobs_created - last_jobs_created_;
@@ -397,7 +397,7 @@ class SdchOwnerTest : public testing::Test {
private:
int last_jobs_created_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
int dictionary_creation_index_;
// The dependencies of these objects (sdch_owner_ -> {sdch_manager_,
@@ -426,8 +426,7 @@ TEST_F(SdchOwnerTest, OnGetDictionary_Fetching) {
GURL dict_url2(std::string(generic_url) + "/d2");
std::string dictionary1(NewSdchDictionary(kMaxSizeForTesting / 2));
sdch_owner().OnDictionaryFetched(base::Time::Now(), base::Time::Now(), 1,
- dictionary1, dict_url1, bound_net_log(),
- false);
+ dictionary1, dict_url1, net_log(), false);
EXPECT_EQ(0, JobsRecentlyCreated());
SignalGetDictionaryAndClearJobs(request_url, dict_url2);
EXPECT_EQ(1, JobsRecentlyCreated());
@@ -437,8 +436,7 @@ TEST_F(SdchOwnerTest, OnGetDictionary_Fetching) {
std::string dictionary2(NewSdchDictionary(
(kMaxSizeForTesting / 2 - kMinFetchSpaceForTesting / 2)));
sdch_owner().OnDictionaryFetched(base::Time::Now(), base::Time::Now(), 1,
- dictionary2, dict_url2, bound_net_log(),
- false);
+ dictionary2, dict_url2, net_log(), false);
EXPECT_EQ(0, JobsRecentlyCreated());
SignalGetDictionaryAndClearJobs(request_url, dict_url3);
EXPECT_EQ(0, JobsRecentlyCreated());
@@ -842,7 +840,7 @@ class SdchOwnerPersistenceTest : public ::testing::Test {
}
protected:
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
std::unique_ptr<SdchManager> manager_;
MockSdchDictionaryFetcher* fetcher_;
std::unique_ptr<SdchOwner> owner_;
diff --git a/chromium/net/server/http_server.cc b/chromium/net/server/http_server.cc
index ecda01701cd..cf79aed9745 100644
--- a/chromium/net/server/http_server.cc
+++ b/chromium/net/server/http_server.cc
@@ -12,7 +12,6 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -45,8 +44,6 @@ HttpServer::HttpServer(std::unique_ptr<ServerSocket> server_socket,
}
HttpServer::~HttpServer() {
- STLDeleteContainerPairSecondPointers(
- id_to_connection_.begin(), id_to_connection_.end());
}
void HttpServer::AcceptWebSocket(
@@ -108,18 +105,20 @@ void HttpServer::Send500(int connection_id, const std::string& message) {
}
void HttpServer::Close(int connection_id) {
- HttpConnection* connection = FindConnection(connection_id);
- if (connection == NULL)
+ auto it = id_to_connection_.find(connection_id);
+ if (it == id_to_connection_.end())
return;
- id_to_connection_.erase(connection_id);
+ std::unique_ptr<HttpConnection> connection = std::move(it->second);
+ id_to_connection_.erase(it);
delegate_->OnClose(connection_id);
// The call stack might have callbacks which still have the pointer of
// connection. Instead of referencing connection with ID all the time,
// destroys the connection in next run loop to make sure any pending
// callbacks in the call stack return.
- base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, connection);
+ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE,
+ connection.release());
}
int HttpServer::GetLocalAddress(IPEndPoint* address) {
@@ -161,9 +160,10 @@ int HttpServer::HandleAcceptResult(int rv) {
return rv;
}
- HttpConnection* connection =
- new HttpConnection(++last_id_, std::move(accepted_socket_));
- id_to_connection_[connection->id()] = connection;
+ std::unique_ptr<HttpConnection> connection_ptr =
+ base::MakeUnique<HttpConnection>(++last_id_, std::move(accepted_socket_));
+ HttpConnection* connection = connection_ptr.get();
+ id_to_connection_[connection->id()] = std::move(connection_ptr);
delegate_->OnConnect(connection->id());
if (!HasClosedConnection(connection))
DoReadLoop(connection);
@@ -232,6 +232,13 @@ int HttpServer::HandleReadResult(HttpConnection* connection, int rv) {
size_t pos = 0;
if (!ParseHeaders(read_buf->StartOfBuffer(), read_buf->GetSize(),
&request, &pos)) {
+ // An error has occured. Close the connection.
+ Close(connection->id());
+ return ERR_CONNECTION_CLOSED;
+ } else if (!pos) {
+ // If pos is 0, all the data in read_buf has been consumed, but the
+ // headers have not been fully parsed yet. Continue parsing when more data
+ // rolls in.
break;
}
@@ -239,8 +246,7 @@ int HttpServer::HandleReadResult(HttpConnection* connection, int rv) {
connection->socket()->GetPeerAddress(&request.peer);
if (request.HasHeaderValue("connection", "upgrade")) {
- connection->SetWebSocket(
- base::WrapUnique(new WebSocket(this, connection)));
+ connection->SetWebSocket(base::MakeUnique<WebSocket>(this, connection));
read_buf->DidConsume(pos);
delegate_->OnWebSocketRequest(connection->id(), request);
if (HasClosedConnection(connection))
@@ -406,8 +412,10 @@ bool HttpServer::ParseHeaders(const char* data,
buffer.clear();
break;
case ST_PROTO:
- // TODO(mbelshe): Deal better with parsing protocol.
- DCHECK(buffer == "HTTP/1.1");
+ if (buffer != "HTTP/1.1") {
+ LOG(ERROR) << "Cannot handle request with protocol: " << buffer;
+ next_state = ST_ERR;
+ }
buffer.clear();
break;
case ST_NAME:
@@ -449,15 +457,17 @@ bool HttpServer::ParseHeaders(const char* data,
}
}
}
- // No more characters, but we haven't finished parsing yet.
- return false;
+ // No more characters, but we haven't finished parsing yet. Signal this to
+ // the caller by setting |pos| to zero.
+ pos = 0;
+ return true;
}
HttpConnection* HttpServer::FindConnection(int connection_id) {
- IdToConnectionMap::iterator it = id_to_connection_.find(connection_id);
+ auto it = id_to_connection_.find(connection_id);
if (it == id_to_connection_.end())
- return NULL;
- return it->second;
+ return nullptr;
+ return it->second.get();
}
// This is called after any delegate callbacks are called to check if Close()
diff --git a/chromium/net/server/http_server.h b/chromium/net/server/http_server.h
index a0062d6821b..c8ba46a5e8f 100644
--- a/chromium/net/server/http_server.h
+++ b/chromium/net/server/http_server.h
@@ -82,8 +82,6 @@ class HttpServer {
private:
friend class HttpServerTest;
- typedef std::map<int, HttpConnection*> IdToConnectionMap;
-
void DoAcceptLoop();
void OnAcceptCompleted(int rv);
int HandleAcceptResult(int rv);
@@ -98,7 +96,9 @@ class HttpServer {
// Expects the raw data to be stored in recv_data_. If parsing is successful,
// will remove the data parsed from recv_data_, leaving only the unused
- // recv data.
+ // recv data. If all data has been consumed successfully, but the headers are
+ // not fully parsed, *pos will be set to zero. Returns false if an error is
+ // encountered while parsing, true otherwise.
bool ParseHeaders(const char* data,
size_t data_len,
HttpServerRequestInfo* info,
@@ -114,7 +114,7 @@ class HttpServer {
HttpServer::Delegate* const delegate_;
int last_id_;
- IdToConnectionMap id_to_connection_;
+ std::map<int, std::unique_ptr<HttpConnection>> id_to_connection_;
base::WeakPtrFactory<HttpServer> weak_ptr_factory_;
diff --git a/chromium/net/server/http_server_unittest.cc b/chromium/net/server/http_server_unittest.cc
index 2f573cf29c1..87c2784da62 100644
--- a/chromium/net/server/http_server_unittest.cc
+++ b/chromium/net/server/http_server_unittest.cc
@@ -36,17 +36,22 @@
#include "net/base/test_completion_callback.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.h"
#include "net/server/http_server_request_info.h"
#include "net/socket/tcp_client_socket.h"
#include "net/socket/tcp_server_socket.h"
+#include "net/test/gtest_util.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -79,7 +84,7 @@ class TestHttpClient {
int ConnectAndWait(const IPEndPoint& address) {
AddressList addresses(address);
- NetLog::Source source;
+ NetLogSource source;
socket_.reset(new TCPClientSocket(addresses, NULL, NULL, source));
base::RunLoop run_loop;
@@ -128,6 +133,8 @@ class TestHttpClient {
return true;
}
+ TCPClientSocket& socket() { return *socket_; }
+
private:
void OnConnect(const base::Closure& quit_loop, int result) {
connect_result_ = result;
@@ -188,13 +195,16 @@ class HttpServerTest : public testing::Test,
void SetUp() override {
std::unique_ptr<ServerSocket> server_socket(
- new TCPServerSocket(NULL, NetLog::Source()));
+ new TCPServerSocket(NULL, NetLogSource()));
server_socket->ListenWithAddressAndPort("127.0.0.1", 0, 1);
server_.reset(new HttpServer(std::move(server_socket), this));
- ASSERT_EQ(OK, server_->GetLocalAddress(&server_address_));
+ ASSERT_THAT(server_->GetLocalAddress(&server_address_), IsOk());
}
- void OnConnect(int connection_id) override {}
+ void OnConnect(int connection_id) override {
+ DCHECK(connection_map_.find(connection_id) == connection_map_.end());
+ connection_map_[connection_id] = true;
+ }
void OnHttpRequest(int connection_id,
const HttpServerRequestInfo& info) override {
@@ -212,7 +222,10 @@ class HttpServerTest : public testing::Test,
NOTREACHED();
}
- void OnClose(int connection_id) override {}
+ void OnClose(int connection_id) override {
+ DCHECK(connection_map_.find(connection_id) != connection_map_.end());
+ connection_map_[connection_id] = false;
+ }
bool RunUntilRequestsReceived(size_t count) {
quit_after_request_count_ = count;
@@ -239,11 +252,15 @@ class HttpServerTest : public testing::Test,
server_->HandleAcceptResult(OK);
}
+ std::unordered_map<int, bool>& connection_map() { return connection_map_; }
+
protected:
std::unique_ptr<HttpServer> server_;
IPEndPoint server_address_;
base::Closure run_loop_quit_func_;
std::vector<std::pair<HttpServerRequestInfo, int> > requests_;
+ std::unordered_map<int /* connection_id */, bool /* connected */>
+ connection_map_;
private:
size_t quit_after_request_count_;
@@ -268,7 +285,7 @@ class WebSocketTest : public HttpServerTest {
TEST_F(HttpServerTest, Request) {
TestHttpClient client;
- ASSERT_EQ(OK, client.ConnectAndWait(server_address_));
+ ASSERT_THAT(client.ConnectAndWait(server_address_), IsOk());
client.Send("GET /test HTTP/1.1\r\n\r\n");
ASSERT_TRUE(RunUntilRequestsReceived(1));
ASSERT_EQ("GET", GetRequest(0).method);
@@ -281,7 +298,7 @@ TEST_F(HttpServerTest, Request) {
TEST_F(HttpServerTest, RequestWithHeaders) {
TestHttpClient client;
- ASSERT_EQ(OK, client.ConnectAndWait(server_address_));
+ ASSERT_THAT(client.ConnectAndWait(server_address_), IsOk());
const char* const kHeaders[][3] = {
{"Header", ": ", "1"},
{"HeaderWithNoWhitespace", ":", "1"},
@@ -311,7 +328,7 @@ TEST_F(HttpServerTest, RequestWithHeaders) {
TEST_F(HttpServerTest, RequestWithDuplicateHeaders) {
TestHttpClient client;
- ASSERT_EQ(OK, client.ConnectAndWait(server_address_));
+ ASSERT_THAT(client.ConnectAndWait(server_address_), IsOk());
const char* const kHeaders[][3] = {
{"FirstHeader", ": ", "1"},
{"DuplicateHeader", ": ", "2"},
@@ -339,7 +356,7 @@ TEST_F(HttpServerTest, RequestWithDuplicateHeaders) {
TEST_F(HttpServerTest, HasHeaderValueTest) {
TestHttpClient client;
- ASSERT_EQ(OK, client.ConnectAndWait(server_address_));
+ ASSERT_THAT(client.ConnectAndWait(server_address_), IsOk());
const char* const kHeaders[] = {
"Header: Abcd",
"HeaderWithNoWhitespace:E",
@@ -376,7 +393,7 @@ TEST_F(HttpServerTest, HasHeaderValueTest) {
TEST_F(HttpServerTest, RequestWithBody) {
TestHttpClient client;
- ASSERT_EQ(OK, client.ConnectAndWait(server_address_));
+ ASSERT_THAT(client.ConnectAndWait(server_address_), IsOk());
std::string body = "a" + std::string(1 << 10, 'b') + "c";
client.Send(base::StringPrintf(
"GET /test HTTP/1.1\r\n"
@@ -393,7 +410,7 @@ TEST_F(HttpServerTest, RequestWithBody) {
TEST_F(WebSocketTest, RequestWebSocket) {
TestHttpClient client;
- ASSERT_EQ(OK, client.ConnectAndWait(server_address_));
+ ASSERT_THAT(client.ConnectAndWait(server_address_), IsOk());
client.Send(
"GET /test HTTP/1.1\r\n"
"Upgrade: WebSocket\r\n"
@@ -440,7 +457,7 @@ TEST_F(HttpServerTest, RequestWithTooLargeBody) {
TEST_F(HttpServerTest, Send200) {
TestHttpClient client;
- ASSERT_EQ(OK, client.ConnectAndWait(server_address_));
+ ASSERT_THAT(client.ConnectAndWait(server_address_), IsOk());
client.Send("GET /test HTTP/1.1\r\n\r\n");
ASSERT_TRUE(RunUntilRequestsReceived(1));
server_->Send200(GetConnectionId(0), "Response!", "text/plain");
@@ -455,7 +472,7 @@ TEST_F(HttpServerTest, Send200) {
TEST_F(HttpServerTest, SendRaw) {
TestHttpClient client;
- ASSERT_EQ(OK, client.ConnectAndWait(server_address_));
+ ASSERT_THAT(client.ConnectAndWait(server_address_), IsOk());
client.Send("GET /test HTTP/1.1\r\n\r\n");
ASSERT_TRUE(RunUntilRequestsReceived(1));
server_->SendRaw(GetConnectionId(0), "Raw Data ");
@@ -468,6 +485,38 @@ TEST_F(HttpServerTest, SendRaw) {
ASSERT_EQ(expected_response, response);
}
+TEST_F(HttpServerTest, WrongProtocolRequest) {
+ const char* const kBadProtocolRequests[] = {
+ "GET /test HTTP/1.0\r\n\r\n",
+ "GET /test foo\r\n\r\n",
+ "GET /test \r\n\r\n",
+ };
+
+ for (size_t i = 0; i < arraysize(kBadProtocolRequests); ++i) {
+ TestHttpClient client;
+ ASSERT_THAT(client.ConnectAndWait(server_address_), IsOk());
+
+ client.Send(kBadProtocolRequests[i]);
+ ASSERT_FALSE(RunUntilRequestsReceived(1));
+
+ // Assert that the delegate was updated properly.
+ ASSERT_EQ(1u, connection_map().size());
+ ASSERT_FALSE(connection_map().begin()->second);
+
+ // Assert that the socket was opened...
+ ASSERT_TRUE(client.socket().WasEverUsed());
+
+ // ...then closed when the server disconnected. Verify that the socket was
+ // closed by checking that a Read() fails.
+ std::string response;
+ ASSERT_FALSE(client.Read(&response, 1u));
+ ASSERT_EQ(std::string(), response);
+
+ // Reset the state of the connection map.
+ connection_map().clear();
+ }
+}
+
class MockStreamSocket : public StreamSocket {
public:
MockStreamSocket()
@@ -495,7 +544,7 @@ class MockStreamSocket : public StreamSocket {
int GetLocalAddress(IPEndPoint* address) const override {
return ERR_NOT_IMPLEMENTED;
}
- const BoundNetLog& NetLog() const override { return net_log_; }
+ const NetLogWithSource& NetLog() const override { return net_log_; }
void SetSubresourceSpeculation() override {}
void SetOmniboxSpeculation() override {}
bool WasEverUsed() const override { return true; }
@@ -563,7 +612,7 @@ class MockStreamSocket : public StreamSocket {
int read_buf_len_;
CompletionCallback read_callback_;
std::string pending_read_data_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
DISALLOW_COPY_AND_ASSIGN(MockStreamSocket);
};
@@ -589,7 +638,7 @@ TEST_F(HttpServerTest, MultipleRequestsOnSameConnection) {
// The idea behind this test is that requests with or without bodies should
// not break parsing of the next request.
TestHttpClient client;
- ASSERT_EQ(OK, client.ConnectAndWait(server_address_));
+ ASSERT_THAT(client.ConnectAndWait(server_address_), IsOk());
std::string body = "body";
client.Send(base::StringPrintf(
"GET /test HTTP/1.1\r\n"
@@ -636,6 +685,7 @@ TEST_F(HttpServerTest, MultipleRequestsOnSameConnection) {
class CloseOnConnectHttpServerTest : public HttpServerTest {
public:
void OnConnect(int connection_id) override {
+ HttpServerTest::OnConnect(connection_id);
connection_ids_.push_back(connection_id);
server_->Close(connection_id);
}
@@ -646,7 +696,7 @@ class CloseOnConnectHttpServerTest : public HttpServerTest {
TEST_F(CloseOnConnectHttpServerTest, ServerImmediatelyClosesConnection) {
TestHttpClient client;
- ASSERT_EQ(OK, client.ConnectAndWait(server_address_));
+ ASSERT_THAT(client.ConnectAndWait(server_address_), IsOk());
client.Send("GET / HTTP/1.1\r\n\r\n");
ASSERT_FALSE(RunUntilRequestsReceived(1));
ASSERT_EQ(1ul, connection_ids_.size());
diff --git a/chromium/net/server/web_socket_encoder.cc b/chromium/net/server/web_socket_encoder.cc
index 60a9a47021c..693de733b69 100644
--- a/chromium/net/server/web_socket_encoder.cc
+++ b/chromium/net/server/web_socket_encoder.cc
@@ -219,10 +219,10 @@ std::unique_ptr<WebSocketEncoder> WebSocketEncoder::CreateServer(
}
DCHECK(response.IsValidAsResponse());
DCHECK(offer.IsCompatibleWith(response));
- auto deflater = base::WrapUnique(
- new WebSocketDeflater(response.server_context_take_over_mode()));
- auto inflater = base::WrapUnique(
- new WebSocketInflater(kInflaterChunkSize, kInflaterChunkSize));
+ auto deflater = base::MakeUnique<WebSocketDeflater>(
+ response.server_context_take_over_mode());
+ auto inflater = base::MakeUnique<WebSocketInflater>(kInflaterChunkSize,
+ kInflaterChunkSize);
if (!deflater->Initialize(response.PermissiveServerMaxWindowBits()) ||
!inflater->Initialize(response.PermissiveClientMaxWindowBits())) {
// For some reason we cannot accept the parameters.
@@ -265,10 +265,10 @@ std::unique_ptr<WebSocketEncoder> WebSocketEncoder::CreateClient(
return base::WrapUnique(new WebSocketEncoder(FOR_CLIENT, nullptr, nullptr));
}
- auto deflater = base::WrapUnique(
- new WebSocketDeflater(params.client_context_take_over_mode()));
- auto inflater = base::WrapUnique(
- new WebSocketInflater(kInflaterChunkSize, kInflaterChunkSize));
+ auto deflater = base::MakeUnique<WebSocketDeflater>(
+ params.client_context_take_over_mode());
+ auto inflater = base::MakeUnique<WebSocketInflater>(kInflaterChunkSize,
+ kInflaterChunkSize);
if (!deflater->Initialize(params.PermissiveClientMaxWindowBits()) ||
!inflater->Initialize(params.PermissiveServerMaxWindowBits())) {
// TODO (yhirano): Fail the connection.
diff --git a/chromium/net/socket/OWNERS b/chromium/net/socket/OWNERS
new file mode 100644
index 00000000000..df81ef063bc
--- /dev/null
+++ b/chromium/net/socket/OWNERS
@@ -0,0 +1,2 @@
+# WebSocket
+per-file websocket*=file://net/websockets/OWNERS
diff --git a/chromium/net/socket/client_socket_factory.cc b/chromium/net/socket/client_socket_factory.cc
index 42daa5a5200..172903ad2ec 100644
--- a/chromium/net/socket/client_socket_factory.cc
+++ b/chromium/net/socket/client_socket_factory.cc
@@ -48,7 +48,7 @@ class DefaultClientSocketFactory : public ClientSocketFactory,
DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
NetLog* net_log,
- const NetLog::Source& source) override {
+ const NetLogSource& source) override {
return std::unique_ptr<DatagramClientSocket>(
new UDPClientSocket(bind_type, rand_int_cb, net_log, source));
}
@@ -57,7 +57,7 @@ class DefaultClientSocketFactory : public ClientSocketFactory,
const AddressList& addresses,
std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
NetLog* net_log,
- const NetLog::Source& source) override {
+ const NetLogSource& source) override {
return std::unique_ptr<StreamSocket>(new TCPClientSocket(
addresses, std::move(socket_performance_watcher), net_log, source));
}
diff --git a/chromium/net/socket/client_socket_factory.h b/chromium/net/socket/client_socket_factory.h
index 5fdb36585d7..185d305fc55 100644
--- a/chromium/net/socket/client_socket_factory.h
+++ b/chromium/net/socket/client_socket_factory.h
@@ -10,7 +10,6 @@
#include "net/base/net_export.h"
#include "net/base/rand_callback.h"
-#include "net/log/net_log.h"
#include "net/socket/socket_performance_watcher.h"
#include "net/udp/datagram_socket.h"
@@ -20,6 +19,8 @@ class AddressList;
class ClientSocketHandle;
class DatagramClientSocket;
class HostPortPair;
+class NetLog;
+struct NetLogSource;
class SSLClientSocket;
struct SSLClientSocketContext;
struct SSLConfig;
@@ -31,19 +32,19 @@ class NET_EXPORT ClientSocketFactory {
public:
virtual ~ClientSocketFactory() {}
- // |source| is the NetLog::Source for the entity trying to create the socket,
+ // |source| is the NetLogSource for the entity trying to create the socket,
// if it has one.
virtual std::unique_ptr<DatagramClientSocket> CreateDatagramClientSocket(
DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
NetLog* net_log,
- const NetLog::Source& source) = 0;
+ const NetLogSource& source) = 0;
virtual std::unique_ptr<StreamSocket> CreateTransportClientSocket(
const AddressList& addresses,
std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
NetLog* net_log,
- const NetLog::Source& source) = 0;
+ const NetLogSource& source) = 0;
// It is allowed to pass in a |transport_socket| that is not obtained from a
// socket pool. The caller could create a ClientSocketHandle directly and call
diff --git a/chromium/net/socket/client_socket_handle.cc b/chromium/net/socket/client_socket_handle.cc
index 77026d5af2f..f171552e4c2 100644
--- a/chromium/net/socket/client_socket_handle.cc
+++ b/chromium/net/socket/client_socket_handle.cc
@@ -12,6 +12,7 @@
#include "base/logging.h"
#include "base/trace_event/trace_event.h"
#include "net/base/net_errors.h"
+#include "net/log/net_log_event_type.h"
#include "net/socket/client_socket_pool.h"
namespace net {
@@ -41,7 +42,7 @@ void ClientSocketHandle::ResetInternal(bool cancel) {
CHECK(pool_);
if (is_initialized()) {
if (socket_) {
- socket_->NetLog().EndEvent(NetLog::TYPE_SOCKET_IN_USE);
+ socket_->NetLog().EndEvent(NetLogEventType::SOCKET_IN_USE);
// Release the socket back to the ClientSocketPool so it can be
// deleted or reused.
pool_->ReleaseSocket(group_name_, std::move(socket_), pool_id_);
@@ -167,9 +168,8 @@ void ClientSocketHandle::HandleInitCompletion(int result) {
// release() socket. It ends up working though, since those methods are being
// used to layer sockets (and the destination sources are the same).
DCHECK(socket_.get());
- socket_->NetLog().BeginEvent(
- NetLog::TYPE_SOCKET_IN_USE,
- requesting_source_.ToEventParametersCallback());
+ socket_->NetLog().BeginEvent(NetLogEventType::SOCKET_IN_USE,
+ requesting_source_.ToEventParametersCallback());
}
} // namespace net
diff --git a/chromium/net/socket/client_socket_handle.h b/chromium/net/socket/client_socket_handle.h
index 89e4d0fef87..cf9e8d022ee 100644
--- a/chromium/net/socket/client_socket_handle.h
+++ b/chromium/net/socket/client_socket_handle.h
@@ -20,7 +20,8 @@
#include "net/base/net_export.h"
#include "net/base/request_priority.h"
#include "net/http/http_response_info.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/client_socket_pool.h"
#include "net/socket/connection_attempts.h"
#include "net/socket/stream_socket.h"
@@ -82,7 +83,7 @@ class NET_EXPORT ClientSocketHandle {
ClientSocketPool::RespectLimits respect_limits,
const CompletionCallback& callback,
PoolType* pool,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// An initialized handle can be reset, which causes it to return to the
// un-initialized state. This releases the underlying socket, which in the
@@ -219,7 +220,7 @@ class NET_EXPORT ClientSocketHandle {
base::TimeTicks init_time_;
base::TimeDelta setup_time_;
- NetLog::Source requesting_source_;
+ NetLogSource requesting_source_;
// Timing information is set when a connection is successfully established.
LoadTimingInfo::ConnectTiming connect_timing_;
@@ -236,7 +237,7 @@ int ClientSocketHandle::Init(
ClientSocketPool::RespectLimits respect_limits,
const CompletionCallback& callback,
PoolType* pool,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
requesting_source_ = net_log.source();
CHECK(!group_name.empty());
diff --git a/chromium/net/socket/client_socket_pool.h b/chromium/net/socket/client_socket_pool.h
index b59f6049da8..15dbe5f02d6 100644
--- a/chromium/net/socket/client_socket_pool.h
+++ b/chromium/net/socket/client_socket_pool.h
@@ -25,6 +25,7 @@ class DictionaryValue;
namespace net {
class ClientSocketHandle;
+class NetLogWithSource;
class StreamSocket;
// ClientSocketPools are layered. This defines an interface for lower level
@@ -106,7 +107,7 @@ class NET_EXPORT ClientSocketPool : public LowerLayeredPool {
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) = 0;
+ const NetLogWithSource& net_log) = 0;
// RequestSockets is used to request that |num_sockets| be connected in the
// connection group for |group_name|. If the connection group already has
@@ -121,7 +122,7 @@ class NET_EXPORT ClientSocketPool : public LowerLayeredPool {
virtual void RequestSockets(const std::string& group_name,
const void* params,
int num_sockets,
- const BoundNetLog& net_log) = 0;
+ const NetLogWithSource& net_log) = 0;
// Called to cancel a RequestSocket call that returned ERR_IO_PENDING. The
// same handle parameter must be passed to this method as was passed to the
@@ -197,7 +198,7 @@ void RequestSocketsForPool(
const std::string& group_name,
const scoped_refptr<typename PoolType::SocketParams>& params,
int num_sockets,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
pool->RequestSockets(group_name, &params, num_sockets, net_log);
}
diff --git a/chromium/net/socket/client_socket_pool_base.cc b/chromium/net/socket/client_socket_pool_base.cc
index 9a9a166615c..4e88c745acf 100644
--- a/chromium/net/socket/client_socket_pool_base.cc
+++ b/chromium/net/socket/client_socket_pool_base.cc
@@ -13,7 +13,6 @@
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -21,6 +20,8 @@
#include "base/values.h"
#include "net/base/net_errors.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
using base::TimeDelta;
@@ -39,7 +40,7 @@ ConnectJob::ConnectJob(const std::string& group_name,
RequestPriority priority,
ClientSocketPool::RespectLimits respect_limits,
Delegate* delegate,
- const BoundNetLog& net_log)
+ const NetLogWithSource& net_log)
: group_name_(group_name),
timeout_duration_(timeout_duration),
priority_(priority),
@@ -49,12 +50,12 @@ ConnectJob::ConnectJob(const std::string& group_name,
idle_(true) {
DCHECK(!group_name.empty());
DCHECK(delegate);
- net_log.BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB,
+ net_log.BeginEvent(NetLogEventType::SOCKET_POOL_CONNECT_JOB,
NetLog::StringCallback("group_name", &group_name_));
}
ConnectJob::~ConnectJob() {
- net_log().EndEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB);
+ net_log().EndEvent(NetLogEventType::SOCKET_POOL_CONNECT_JOB);
}
std::unique_ptr<StreamSocket> ConnectJob::PassSocket() {
@@ -81,7 +82,7 @@ int ConnectJob::Connect() {
void ConnectJob::SetSocket(std::unique_ptr<StreamSocket> socket) {
if (socket) {
- net_log().AddEvent(NetLog::TYPE_CONNECT_JOB_SET_SOCKET,
+ net_log().AddEvent(NetLogEventType::CONNECT_JOB_SET_SOCKET,
socket->NetLog().source().ToEventParametersCallback());
}
socket_ = std::move(socket);
@@ -104,20 +105,20 @@ void ConnectJob::ResetTimer(base::TimeDelta remaining_time) {
void ConnectJob::LogConnectStart() {
connect_timing_.connect_start = base::TimeTicks::Now();
- net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT);
+ net_log().BeginEvent(NetLogEventType::SOCKET_POOL_CONNECT_JOB_CONNECT);
}
void ConnectJob::LogConnectCompletion(int net_error) {
connect_timing_.connect_end = base::TimeTicks::Now();
net_log().EndEventWithNetErrorCode(
- NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT, net_error);
+ NetLogEventType::SOCKET_POOL_CONNECT_JOB_CONNECT, net_error);
}
void ConnectJob::OnTimeout() {
// Make sure the socket is NULL before calling into |delegate|.
SetSocket(std::unique_ptr<StreamSocket>());
- net_log_.AddEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_TIMED_OUT);
+ net_log_.AddEvent(NetLogEventType::SOCKET_POOL_CONNECT_JOB_TIMED_OUT);
NotifyDelegateOfCompletion(ERR_TIMED_OUT);
}
@@ -130,7 +131,7 @@ ClientSocketPoolBaseHelper::Request::Request(
RequestPriority priority,
ClientSocketPool::RespectLimits respect_limits,
Flags flags,
- const BoundNetLog& net_log)
+ const NetLogWithSource& net_log)
: handle_(handle),
callback_(callback),
priority_(priority),
@@ -240,7 +241,7 @@ bool ClientSocketPoolBaseHelper::IsStalled() const {
void ClientSocketPoolBaseHelper::AddLowerLayeredPool(
LowerLayeredPool* lower_pool) {
DCHECK(pool_);
- CHECK(!ContainsKey(lower_pools_, lower_pool));
+ CHECK(!base::ContainsKey(lower_pools_, lower_pool));
lower_pools_.insert(lower_pool);
lower_pool->AddHigherLayeredPool(pool_);
}
@@ -248,14 +249,14 @@ void ClientSocketPoolBaseHelper::AddLowerLayeredPool(
void ClientSocketPoolBaseHelper::AddHigherLayeredPool(
HigherLayeredPool* higher_pool) {
CHECK(higher_pool);
- CHECK(!ContainsKey(higher_pools_, higher_pool));
+ CHECK(!base::ContainsKey(higher_pools_, higher_pool));
higher_pools_.insert(higher_pool);
}
void ClientSocketPoolBaseHelper::RemoveHigherLayeredPool(
HigherLayeredPool* higher_pool) {
CHECK(higher_pool);
- CHECK(ContainsKey(higher_pools_, higher_pool));
+ CHECK(base::ContainsKey(higher_pools_, higher_pool));
higher_pools_.erase(higher_pool);
}
@@ -268,12 +269,13 @@ int ClientSocketPoolBaseHelper::RequestSocket(
// Cleanup any timed-out idle sockets.
CleanupIdleSockets(false);
- request->net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL);
+ request->net_log().BeginEvent(NetLogEventType::SOCKET_POOL);
Group* group = GetOrCreateGroup(group_name);
int rv = RequestSocketInternal(group_name, *request);
if (rv != ERR_IO_PENDING) {
- request->net_log().EndEventWithNetErrorCode(NetLog::TYPE_SOCKET_POOL, rv);
+ request->net_log().EndEventWithNetErrorCode(NetLogEventType::SOCKET_POOL,
+ rv);
CHECK(!request->handle()->is_initialized());
request.reset();
} else {
@@ -307,8 +309,9 @@ void ClientSocketPoolBaseHelper::RequestSockets(
num_sockets = max_sockets_per_group_;
}
- request.net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECTING_N_SOCKETS,
- NetLog::IntCallback("num_sockets", num_sockets));
+ request.net_log().BeginEvent(
+ NetLogEventType::SOCKET_POOL_CONNECTING_N_SOCKETS,
+ NetLog::IntCallback("num_sockets", num_sockets));
Group* group = GetOrCreateGroup(group_name);
@@ -322,11 +325,11 @@ void ClientSocketPoolBaseHelper::RequestSockets(
rv = RequestSocketInternal(group_name, request);
if (rv < 0 && rv != ERR_IO_PENDING) {
// We're encountering a synchronous error. Give up.
- if (!ContainsKey(group_map_, group_name))
+ if (!base::ContainsKey(group_map_, group_name))
deleted_group = true;
break;
}
- if (!ContainsKey(group_map_, group_name)) {
+ if (!base::ContainsKey(group_map_, group_name)) {
// Unexpected. The group should only be getting deleted on synchronous
// error.
NOTREACHED();
@@ -341,7 +344,7 @@ void ClientSocketPoolBaseHelper::RequestSockets(
if (rv == ERR_IO_PENDING)
rv = OK;
request.net_log().EndEventWithNetErrorCode(
- NetLog::TYPE_SOCKET_POOL_CONNECTING_N_SOCKETS, rv);
+ NetLogEventType::SOCKET_POOL_CONNECTING_N_SOCKETS, rv);
}
int ClientSocketPoolBaseHelper::RequestSocketInternal(
@@ -371,7 +374,7 @@ int ClientSocketPoolBaseHelper::RequestSocketInternal(
// reuse that socket then if we needed one and wouldn't make it down to this
// layer.
request.net_log().AddEvent(
- NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS_PER_GROUP);
+ NetLogEventType::SOCKET_POOL_STALLED_MAX_SOCKETS_PER_GROUP);
return ERR_IO_PENDING;
}
@@ -389,7 +392,8 @@ int ClientSocketPoolBaseHelper::RequestSocketInternal(
} else {
// We could check if we really have a stalled group here, but it requires
// a scan of all groups, so just flip a flag here, and do the check later.
- request.net_log().AddEvent(NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS);
+ request.net_log().AddEvent(
+ NetLogEventType::SOCKET_POOL_STALLED_MAX_SOCKETS);
return ERR_IO_PENDING;
}
}
@@ -502,8 +506,9 @@ bool ClientSocketPoolBaseHelper::AssignIdleSocketToRequest(
// static
void ClientSocketPoolBaseHelper::LogBoundConnectJobToRequest(
- const NetLog::Source& connect_job_source, const Request& request) {
- request.net_log().AddEvent(NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
+ const NetLogSource& connect_job_source,
+ const Request& request) {
+ request.net_log().AddEvent(NetLogEventType::SOCKET_POOL_BOUND_TO_CONNECT_JOB,
connect_job_source.ToEventParametersCallback());
}
@@ -522,7 +527,7 @@ void ClientSocketPoolBaseHelper::CancelRequest(
return;
}
- CHECK(ContainsKey(group_map_, group_name));
+ CHECK(base::ContainsKey(group_map_, group_name));
Group* group = GetOrCreateGroup(group_name);
@@ -530,21 +535,21 @@ void ClientSocketPoolBaseHelper::CancelRequest(
std::unique_ptr<const Request> request =
group->FindAndRemovePendingRequest(handle);
if (request) {
- request->net_log().AddEvent(NetLog::TYPE_CANCELLED);
- request->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL);
+ request->net_log().AddEvent(NetLogEventType::CANCELLED);
+ request->net_log().EndEvent(NetLogEventType::SOCKET_POOL);
// We let the job run, unless we're at the socket limit and there is
// not another request waiting on the job.
if (group->jobs().size() > group->pending_request_count() &&
ReachedMaxSocketsLimit()) {
- RemoveConnectJob(*group->jobs().begin(), group);
+ RemoveConnectJob(group->jobs().begin()->get(), group);
CheckForStalledSocketGroups();
}
}
}
bool ClientSocketPoolBaseHelper::HasGroup(const std::string& group_name) const {
- return ContainsKey(group_map_, group_name);
+ return base::ContainsKey(group_map_, group_name);
}
void ClientSocketPoolBaseHelper::CloseIdleSockets() {
@@ -563,7 +568,7 @@ int ClientSocketPoolBaseHelper::IdleSocketCountInGroup(
LoadState ClientSocketPoolBaseHelper::GetLoadState(
const std::string& group_name,
const ClientSocketHandle* handle) const {
- if (ContainsKey(pending_callback_map_, handle))
+ if (base::ContainsKey(pending_callback_map_, handle))
return LOAD_STATE_CONNECTING;
GroupMap::const_iterator group_it = group_map_.find(group_name);
@@ -629,8 +634,7 @@ ClientSocketPoolBaseHelper::GetInfoAsValue(const std::string& name,
group_dict->Set("idle_sockets", idle_socket_list);
base::ListValue* connect_jobs_list = new base::ListValue();
- std::list<ConnectJob*>::const_iterator job = group->jobs().begin();
- for (job = group->jobs().begin(); job != group->jobs().end(); job++) {
+ for (auto job = group->jobs().begin(); job != group->jobs().end(); job++) {
int source_id = (*job)->net_log().source().id;
connect_jobs_list->AppendInteger(source_id);
}
@@ -856,7 +860,7 @@ void ClientSocketPoolBaseHelper::OnConnectJobComplete(
// Copies of these are needed because |job| may be deleted before they are
// accessed.
- BoundNetLog job_log = job->net_log();
+ NetLogWithSource job_log = job->net_log();
LoadTimingInfo::ConnectTiming connect_timing = job->connect_timing();
// RemoveConnectJob(job, _) must be called by all branches below;
@@ -871,7 +875,7 @@ void ClientSocketPoolBaseHelper::OnConnectJobComplete(
HandOutSocket(std::move(socket), ClientSocketHandle::UNUSED,
connect_timing, request->handle(), base::TimeDelta(), group,
request->net_log());
- request->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL);
+ request->net_log().EndEvent(NetLogEventType::SOCKET_POOL);
InvokeUserCallbackLater(request->handle(), request->callback(), result);
} else {
AddIdleSocket(std::move(socket), group);
@@ -893,8 +897,8 @@ void ClientSocketPoolBaseHelper::OnConnectJobComplete(
connect_timing, request->handle(), base::TimeDelta(),
group, request->net_log());
}
- request->net_log().EndEventWithNetErrorCode(
- NetLog::TYPE_SOCKET_POOL, result);
+ request->net_log().EndEventWithNetErrorCode(NetLogEventType::SOCKET_POOL,
+ result);
InvokeUserCallbackLater(request->handle(), request->callback(), result);
} else {
RemoveConnectJob(job, group);
@@ -928,7 +932,7 @@ void ClientSocketPoolBaseHelper::RemoveConnectJob(ConnectJob* job,
void ClientSocketPoolBaseHelper::OnAvailableSocketSlot(
const std::string& group_name, Group* group) {
- DCHECK(ContainsKey(group_map_, group_name));
+ DCHECK(base::ContainsKey(group_map_, group_name));
if (group->IsEmpty()) {
RemoveGroup(group_name);
} else if (group->has_pending_requests()) {
@@ -956,7 +960,8 @@ void ClientSocketPoolBaseHelper::ProcessPendingRequest(
if (group->IsEmpty())
RemoveGroup(group_name);
- request->net_log().EndEventWithNetErrorCode(NetLog::TYPE_SOCKET_POOL, rv);
+ request->net_log().EndEventWithNetErrorCode(NetLogEventType::SOCKET_POOL,
+ rv);
InvokeUserCallbackLater(request->handle(), request->callback(), rv);
}
}
@@ -968,7 +973,7 @@ void ClientSocketPoolBaseHelper::HandOutSocket(
ClientSocketHandle* handle,
base::TimeDelta idle_time,
Group* group,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
DCHECK(socket);
handle->SetSocket(std::move(socket));
handle->set_reuse_type(reuse_type);
@@ -978,7 +983,7 @@ void ClientSocketPoolBaseHelper::HandOutSocket(
if (reuse_type == ClientSocketHandle::REUSED_IDLE) {
net_log.AddEvent(
- NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET,
+ NetLogEventType::SOCKET_POOL_REUSED_AN_EXISTING_SOCKET,
NetLog::IntCallback("idle_ms",
static_cast<int>(idle_time.InMilliseconds())));
@@ -994,7 +999,7 @@ void ClientSocketPoolBaseHelper::HandOutSocket(
}
net_log.AddEvent(
- NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
+ NetLogEventType::SOCKET_POOL_BOUND_TO_SOCKET,
handle->socket()->NetLog().source().ToEventParametersCallback());
handed_out_socket_count_++;
@@ -1110,7 +1115,7 @@ bool ClientSocketPoolBaseHelper::CloseOneIdleConnectionInHigherLayeredPool() {
void ClientSocketPoolBaseHelper::InvokeUserCallbackLater(
ClientSocketHandle* handle, const CompletionCallback& callback, int rv) {
- CHECK(!ContainsKey(pending_callback_map_, handle));
+ CHECK(!base::ContainsKey(pending_callback_map_, handle));
pending_callback_map_[handle] = CallbackResultPair(callback, rv);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&ClientSocketPoolBaseHelper::InvokeUserCallback,
@@ -1184,16 +1189,20 @@ void ClientSocketPoolBaseHelper::Group::AddJob(std::unique_ptr<ConnectJob> job,
if (is_preconnect)
++unassigned_job_count_;
- jobs_.push_back(job.release());
+ jobs_.push_back(std::move(job));
}
void ClientSocketPoolBaseHelper::Group::RemoveJob(ConnectJob* job) {
- std::unique_ptr<ConnectJob> owned_job(job);
SanityCheck();
// Check that |job| is in the list.
- DCHECK_EQ(*std::find(jobs_.begin(), jobs_.end(), job), job);
- jobs_.remove(job);
+ auto it = std::find_if(jobs_.begin(), jobs_.end(),
+ [job](const std::unique_ptr<ConnectJob>& ptr) {
+ return ptr.get() == job;
+ });
+ DCHECK(it != jobs_.end());
+ std::unique_ptr<ConnectJob> owned_job = std::move(*it);
+ jobs_.erase(it);
size_t job_count = jobs_.size();
if (job_count < unassigned_job_count_)
unassigned_job_count_ = job_count;
@@ -1229,7 +1238,7 @@ void ClientSocketPoolBaseHelper::Group::OnBackupJobTimerFired(
std::unique_ptr<ConnectJob> backup_job =
pool->connect_job_factory_->NewConnectJob(
group_name, *pending_requests_.FirstMax().value(), pool);
- backup_job->net_log().AddEvent(NetLog::TYPE_BACKUP_CONNECT_JOB_CREATED);
+ backup_job->net_log().AddEvent(NetLogEventType::BACKUP_CONNECT_JOB_CREATED);
int rv = backup_job->Connect();
pool->connecting_socket_count_++;
ConnectJob* raw_backup_job = backup_job.get();
@@ -1246,7 +1255,7 @@ void ClientSocketPoolBaseHelper::Group::RemoveAllJobs() {
SanityCheck();
// Delete active jobs.
- STLDeleteElements(&jobs_);
+ jobs_.clear();
unassigned_job_count_ = 0;
// Stop backup job timer.
diff --git a/chromium/net/socket/client_socket_pool_base.h b/chromium/net/socket/client_socket_pool_base.h
index a5e17b38036..024e9bf13a6 100644
--- a/chromium/net/socket/client_socket_pool_base.h
+++ b/chromium/net/socket/client_socket_pool_base.h
@@ -49,14 +49,19 @@
#include "net/base/network_change_notifier.h"
#include "net/base/priority_queue.h"
#include "net/base/request_priority.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool.h"
#include "net/socket/stream_socket.h"
+namespace base {
+class DictionaryValue;
+}
+
namespace net {
class ClientSocketHandle;
+struct NetLogSource;
// ConnectJob provides an abstract interface for "connecting" a socket.
// The connection may involve host resolution, tcp connection, ssl connection,
@@ -84,12 +89,12 @@ class NET_EXPORT_PRIVATE ConnectJob {
RequestPriority priority,
ClientSocketPool::RespectLimits respect_limits,
Delegate* delegate,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
virtual ~ConnectJob();
// Accessors
const std::string& group_name() const { return group_name_; }
- const BoundNetLog& net_log() { return net_log_; }
+ const NetLogWithSource& net_log() { return net_log_; }
// Releases ownership of the underlying socket to the caller.
// Returns the released socket, or NULL if there was a connection
@@ -115,7 +120,7 @@ class NET_EXPORT_PRIVATE ConnectJob {
return connect_timing_;
}
- const BoundNetLog& net_log() const { return net_log_; }
+ const NetLogWithSource& net_log() const { return net_log_; }
protected:
RequestPriority priority() const { return priority_; }
@@ -148,7 +153,7 @@ class NET_EXPORT_PRIVATE ConnectJob {
base::OneShotTimer timer_;
Delegate* delegate_;
std::unique_ptr<StreamSocket> socket_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
// A ConnectJob is idle until Connect() has been called.
bool idle_;
@@ -181,7 +186,7 @@ class NET_EXPORT_PRIVATE ClientSocketPoolBaseHelper
RequestPriority priority,
ClientSocketPool::RespectLimits respect_limits,
Flags flags,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
virtual ~Request();
@@ -192,7 +197,7 @@ class NET_EXPORT_PRIVATE ClientSocketPoolBaseHelper
return respect_limits_;
}
Flags flags() const { return flags_; }
- const BoundNetLog& net_log() const { return net_log_; }
+ const NetLogWithSource& net_log() const { return net_log_; }
// TODO(eroman): Temporary until crbug.com/467797 is solved.
void CrashIfInvalid() const;
@@ -210,7 +215,7 @@ class NET_EXPORT_PRIVATE ClientSocketPoolBaseHelper
const RequestPriority priority_;
const ClientSocketPool::RespectLimits respect_limits_;
const Flags flags_;
- const BoundNetLog net_log_;
+ const NetLogWithSource net_log_;
// TODO(eroman): Temporary until crbug.com/467797 is solved.
Liveness liveness_ = ALIVE;
@@ -380,6 +385,8 @@ class NET_EXPORT_PRIVATE ClientSocketPoolBaseHelper
// |active_socket_count| tracks the number of sockets held by clients.
class Group {
public:
+ using JobList = std::list<std::unique_ptr<ConnectJob>>;
+
Group();
~Group();
@@ -464,7 +471,7 @@ class NET_EXPORT_PRIVATE ClientSocketPoolBaseHelper
void DecrementActiveSocketCount() { active_socket_count_--; }
int unassigned_job_count() const { return unassigned_job_count_; }
- const std::list<ConnectJob*>& jobs() const { return jobs_; }
+ const JobList& jobs() const { return jobs_; }
const std::list<IdleSocket>& idle_sockets() const { return idle_sockets_; }
int active_socket_count() const { return active_socket_count_; }
std::list<IdleSocket>* mutable_idle_sockets() { return &idle_sockets_; }
@@ -493,7 +500,7 @@ class NET_EXPORT_PRIVATE ClientSocketPoolBaseHelper
size_t unassigned_job_count_;
std::list<IdleSocket> idle_sockets_;
- std::list<ConnectJob*> jobs_;
+ JobList jobs_;
RequestQueue pending_requests_;
int active_socket_count_; // number of active sockets used by clients
// A timer for when to start the backup job.
@@ -547,7 +554,7 @@ class NET_EXPORT_PRIVATE ClientSocketPoolBaseHelper
ClientSocketHandle* handle,
base::TimeDelta time_idle,
Group* group,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Adds |socket| to the list of idle sockets for |group|.
void AddIdleSocket(std::unique_ptr<StreamSocket> socket, Group* group);
@@ -574,7 +581,8 @@ class NET_EXPORT_PRIVATE ClientSocketPoolBaseHelper
bool AssignIdleSocketToRequest(const Request& request, Group* group);
static void LogBoundConnectJobToRequest(
- const NetLog::Source& connect_job_source, const Request& request);
+ const NetLogSource& connect_job_source,
+ const Request& request);
// Same as CloseOneIdleSocket() except it won't close an idle socket in
// |group|. If |group| is NULL, it is ignored. Returns true if it closed a
@@ -668,7 +676,7 @@ class ClientSocketPoolBase {
ClientSocketPool::RespectLimits respect_limits,
internal::ClientSocketPoolBaseHelper::Flags flags,
const scoped_refptr<SocketParams>& params,
- const BoundNetLog& net_log)
+ const NetLogWithSource& net_log)
: internal::ClientSocketPoolBaseHelper::Request(handle,
callback,
priority,
@@ -741,7 +749,7 @@ class ClientSocketPoolBase {
ClientSocketPool::RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
std::unique_ptr<const Request> request(new Request(
handle, callback, priority, respect_limits,
internal::ClientSocketPoolBaseHelper::NORMAL, params, net_log));
@@ -754,7 +762,7 @@ class ClientSocketPoolBase {
void RequestSockets(const std::string& group_name,
const scoped_refptr<SocketParams>& params,
int num_sockets,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
const Request request(nullptr /* no handle */, CompletionCallback(), IDLE,
ClientSocketPool::RespectLimits::ENABLED,
internal::ClientSocketPoolBaseHelper::NO_IDLE_SOCKETS,
diff --git a/chromium/net/socket/client_socket_pool_base_unittest.cc b/chromium/net/socket/client_socket_pool_base_unittest.cc
index 21269bbc589..404c4f99a74 100644
--- a/chromium/net/socket/client_socket_pool_base_unittest.cc
+++ b/chromium/net/socket/client_socket_pool_base_unittest.cc
@@ -32,6 +32,9 @@
#include "net/base/test_completion_callback.h"
#include "net/http/http_response_headers.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_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"
@@ -41,10 +44,14 @@
#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/udp/datagram_client_socket.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
using ::testing::Invoke;
using ::testing::Return;
@@ -64,7 +71,7 @@ void TestLoadTimingInfoConnectedReused(const ClientSocketHandle& handle) {
EXPECT_TRUE(handle.GetLoadTimingInfo(true, &load_timing_info));
EXPECT_EQ(true, load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
@@ -81,7 +88,7 @@ void TestLoadTimingInfoConnectedNotReused(const ClientSocketHandle& handle) {
EXPECT_TRUE(handle.GetLoadTimingInfo(false, &load_timing_info));
EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
ExpectConnectTimingHasTimes(load_timing_info.connect_timing,
CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
@@ -100,7 +107,7 @@ void TestLoadTimingInfoNotConnected(const ClientSocketHandle& handle) {
EXPECT_FALSE(handle.GetLoadTimingInfo(false, &load_timing_info));
EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_EQ(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_EQ(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
@@ -121,7 +128,7 @@ class MockClientSocket : public StreamSocket {
explicit MockClientSocket(net::NetLog* net_log)
: connected_(false),
has_unread_data_(false),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)),
+ net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::SOCKET)),
was_used_to_convey_data_(false) {}
// Sets whether the socket has unread data. If true, the next call to Read()
@@ -171,7 +178,7 @@ class MockClientSocket : public StreamSocket {
return ERR_UNEXPECTED;
}
- const BoundNetLog& NetLog() const override { return net_log_; }
+ const NetLogWithSource& NetLog() const override { return net_log_; }
void SetSubresourceSpeculation() override {}
void SetOmniboxSpeculation() override {}
@@ -192,7 +199,7 @@ class MockClientSocket : public StreamSocket {
private:
bool connected_;
bool has_unread_data_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
bool was_used_to_convey_data_;
DISALLOW_COPY_AND_ASSIGN(MockClientSocket);
@@ -208,7 +215,7 @@ class MockClientSocketFactory : public ClientSocketFactory {
DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
NetLog* net_log,
- const NetLog::Source& source) override {
+ const NetLogSource& source) override {
NOTREACHED();
return std::unique_ptr<DatagramClientSocket>();
}
@@ -218,7 +225,7 @@ class MockClientSocketFactory : public ClientSocketFactory {
std::unique_ptr<
SocketPerformanceWatcher> /* socket_performance_watcher */,
NetLog* /* net_log */,
- const NetLog::Source& /*source*/) override {
+ const NetLogSource& /*source*/) override {
allocation_count_++;
return std::unique_ptr<StreamSocket>();
}
@@ -275,12 +282,13 @@ class TestConnectJob : public ConnectJob {
ConnectJob::Delegate* delegate,
MockClientSocketFactory* client_socket_factory,
NetLog* net_log)
- : ConnectJob(group_name,
- timeout_duration,
- request.priority(),
- request.respect_limits(),
- delegate,
- BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
+ : ConnectJob(
+ group_name,
+ timeout_duration,
+ request.priority(),
+ request.respect_limits(),
+ delegate,
+ NetLogWithSource::Make(net_log, NetLogSourceType::CONNECT_JOB)),
job_type_(job_type),
client_socket_factory_(client_socket_factory),
load_state_(LOAD_STATE_IDLE),
@@ -313,7 +321,7 @@ class TestConnectJob : public ConnectJob {
int ConnectInternal() override {
AddressList ignored;
client_socket_factory_->CreateTransportClientSocket(ignored, NULL, NULL,
- NetLog::Source());
+ NetLogSource());
SetSocket(std::unique_ptr<StreamSocket>(
new MockClientSocket(net_log().net_log())));
switch (job_type_) {
@@ -504,7 +512,7 @@ class TestClientSocketPool : public ClientSocketPool {
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
const scoped_refptr<TestSocketParams>* casted_socket_params =
static_cast<const scoped_refptr<TestSocketParams>*>(params);
return base_.RequestSocket(group_name, *casted_socket_params, priority,
@@ -514,7 +522,7 @@ class TestClientSocketPool : public ClientSocketPool {
void RequestSockets(const std::string& group_name,
const void* params,
int num_sockets,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
const scoped_refptr<TestSocketParams>* casted_params =
static_cast<const scoped_refptr<TestSocketParams>*>(params);
@@ -742,12 +750,13 @@ TEST_F(ClientSocketPoolBaseTest, ConnectJob_NoTimeoutOnSynchronousCompletion) {
TestClientSocketPoolBase::Request request(
&ignored, CompletionCallback(), DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- internal::ClientSocketPoolBaseHelper::NORMAL, params_, BoundNetLog());
+ internal::ClientSocketPoolBaseHelper::NORMAL, params_,
+ NetLogWithSource());
std::unique_ptr<TestConnectJob> job(
new TestConnectJob(TestConnectJob::kMockJob, "a", request,
base::TimeDelta::FromMicroseconds(1), &delegate,
&client_socket_factory_, NULL));
- EXPECT_EQ(OK, job->Connect());
+ EXPECT_THAT(job->Connect(), IsOk());
}
TEST_F(ClientSocketPoolBaseTest, ConnectJob_TimedOut) {
@@ -758,7 +767,8 @@ TEST_F(ClientSocketPoolBaseTest, ConnectJob_TimedOut) {
TestClientSocketPoolBase::Request request(
&ignored, CompletionCallback(), DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- internal::ClientSocketPoolBaseHelper::NORMAL, params_, BoundNetLog());
+ internal::ClientSocketPoolBaseHelper::NORMAL, params_,
+ NetLogWithSource());
// Deleted by TestConnectJobDelegate.
TestConnectJob* job =
new TestConnectJob(TestConnectJob::kMockPendingJob,
@@ -768,28 +778,28 @@ TEST_F(ClientSocketPoolBaseTest, ConnectJob_TimedOut) {
&delegate,
&client_socket_factory_,
&log);
- ASSERT_EQ(ERR_IO_PENDING, job->Connect());
+ ASSERT_THAT(job->Connect(), IsError(ERR_IO_PENDING));
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
- EXPECT_EQ(ERR_TIMED_OUT, delegate.WaitForResult());
+ EXPECT_THAT(delegate.WaitForResult(), IsError(ERR_TIMED_OUT));
TestNetLogEntry::List entries;
log.GetEntries(&entries);
EXPECT_EQ(6u, entries.size());
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 0,
+ NetLogEventType::SOCKET_POOL_CONNECT_JOB));
EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB));
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 1, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT));
+ entries, 1, NetLogEventType::SOCKET_POOL_CONNECT_JOB_CONNECT));
+ EXPECT_TRUE(LogContainsEvent(entries, 2,
+ NetLogEventType::CONNECT_JOB_SET_SOCKET,
+ NetLogEventPhase::NONE));
EXPECT_TRUE(LogContainsEvent(
- entries, 2, NetLog::TYPE_CONNECT_JOB_SET_SOCKET,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEvent(
- entries, 3, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_TIMED_OUT,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 4, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT));
+ entries, 3, NetLogEventType::SOCKET_POOL_CONNECT_JOB_TIMED_OUT,
+ NetLogEventPhase::NONE));
EXPECT_TRUE(LogContainsEndEvent(
- entries, 5, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB));
+ entries, 4, NetLogEventType::SOCKET_POOL_CONNECT_JOB_CONNECT));
+ EXPECT_TRUE(LogContainsEndEvent(entries, 5,
+ NetLogEventType::SOCKET_POOL_CONNECT_JOB));
}
TEST_F(ClientSocketPoolBaseTest, BasicSynchronous) {
@@ -814,16 +824,14 @@ TEST_F(ClientSocketPoolBaseTest, BasicSynchronous) {
log.GetEntries(&entries);
EXPECT_EQ(4u, entries.size());
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_SOCKET_POOL));
- EXPECT_TRUE(LogContainsEvent(
- entries, 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
- NetLog::PHASE_NONE));
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 0, NetLogEventType::SOCKET_POOL));
EXPECT_TRUE(LogContainsEvent(
- entries, 2, NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 3, NetLog::TYPE_SOCKET_POOL));
+ entries, 1, NetLogEventType::SOCKET_POOL_BOUND_TO_CONNECT_JOB,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEvent(entries, 2,
+ NetLogEventType::SOCKET_POOL_BOUND_TO_SOCKET,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEndEvent(entries, 3, NetLogEventType::SOCKET_POOL));
}
TEST_F(ClientSocketPoolBaseTest, InitConnectionFailure) {
@@ -852,13 +860,11 @@ TEST_F(ClientSocketPoolBaseTest, InitConnectionFailure) {
log.GetEntries(&entries);
EXPECT_EQ(3u, entries.size());
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_SOCKET_POOL));
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 0, NetLogEventType::SOCKET_POOL));
EXPECT_TRUE(LogContainsEvent(
- entries, 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 2, NetLog::TYPE_SOCKET_POOL));
+ entries, 1, NetLogEventType::SOCKET_POOL_BOUND_TO_CONNECT_JOB,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEndEvent(entries, 2, NetLogEventType::SOCKET_POOL));
}
TEST_F(ClientSocketPoolBaseTest, TotalLimit) {
@@ -866,18 +872,18 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimit) {
// TODO(eroman): Check that the NetLog contains this event.
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("b", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("c", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("d", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("b", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("c", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("d", DEFAULT_PRIORITY), IsOk());
EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
EXPECT_EQ(requests_size() - kDefaultMaxSockets, completion_count());
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("e", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("f", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("g", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("e", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("f", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("g", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
@@ -903,17 +909,17 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimitReachedNewGroup) {
// TODO(eroman): Check that the NetLog contains this event.
// Reach all limits: max total sockets, and max sockets per group.
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("b", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("b", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("b", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("b", DEFAULT_PRIORITY), IsOk());
EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
EXPECT_EQ(requests_size() - kDefaultMaxSockets, completion_count());
// Now create a new group and verify that we don't starve it.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("c", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
@@ -934,17 +940,17 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimitReachedNewGroup) {
TEST_F(ClientSocketPoolBaseTest, TotalLimitRespectsPriority) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- EXPECT_EQ(OK, StartRequest("b", LOWEST));
- EXPECT_EQ(OK, StartRequest("a", MEDIUM));
- EXPECT_EQ(OK, StartRequest("b", HIGHEST));
- EXPECT_EQ(OK, StartRequest("a", LOWEST));
+ EXPECT_THAT(StartRequest("b", LOWEST), IsOk());
+ EXPECT_THAT(StartRequest("a", MEDIUM), IsOk());
+ EXPECT_THAT(StartRequest("b", HIGHEST), IsOk());
+ EXPECT_THAT(StartRequest("a", LOWEST), IsOk());
EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", LOWEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("b", HIGHEST));
+ EXPECT_THAT(StartRequest("c", LOWEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", MEDIUM), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("b", HIGHEST), IsError(ERR_IO_PENDING));
ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
@@ -969,17 +975,17 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimitRespectsPriority) {
TEST_F(ClientSocketPoolBaseTest, TotalLimitRespectsGroupLimit) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- EXPECT_EQ(OK, StartRequest("a", LOWEST));
- EXPECT_EQ(OK, StartRequest("a", LOW));
- EXPECT_EQ(OK, StartRequest("b", HIGHEST));
- EXPECT_EQ(OK, StartRequest("b", MEDIUM));
+ EXPECT_THAT(StartRequest("a", LOWEST), IsOk());
+ EXPECT_THAT(StartRequest("a", LOW), IsOk());
+ EXPECT_THAT(StartRequest("b", HIGHEST), IsOk());
+ EXPECT_THAT(StartRequest("b", MEDIUM), IsOk());
EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("b", HIGHEST));
+ EXPECT_THAT(StartRequest("c", MEDIUM), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOW), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("b", HIGHEST), IsError(ERR_IO_PENDING));
ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
@@ -1009,13 +1015,13 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimitRespectsGroupLimit) {
TEST_F(ClientSocketPoolBaseTest, TotalLimitCountsConnectingSockets) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("b", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("c", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("b", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("c", DEFAULT_PRIORITY), IsOk());
// Create one asynchronous request.
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("d", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("d", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
// We post all of our delayed tasks with a 2ms delay. I.e. they don't
// actually become pending until 2ms after they have been created. In order
@@ -1026,7 +1032,7 @@ TEST_F(ClientSocketPoolBaseTest, TotalLimitCountsConnectingSockets) {
// The next synchronous request should wait for its turn.
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("e", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("e", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
@@ -1047,17 +1053,17 @@ TEST_F(ClientSocketPoolBaseTest, CorrectlyCountStalledGroups) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("b", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("b", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("c", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
@@ -1079,15 +1085,16 @@ TEST_F(ClientSocketPoolBaseTest, StallAndThenCancelAndTriggerAvailableSocket) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
ClientSocketHandle handles[4];
for (size_t i = 0; i < arraysize(handles); ++i) {
TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- handles[i].Init("b", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handles[i].Init("b", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback.callback(), pool_.get(), NetLogWithSource()));
}
// One will be stalled, cancel all the handles now.
@@ -1105,20 +1112,21 @@ 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(), BoundNetLog()));
+ EXPECT_EQ(OK,
+ handles[i].Init(base::IntToString(i), params_, DEFAULT_PRIORITY,
+ 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,
- ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ stalled_handle.Init("foo", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback.callback(), pool_.get(),
+ NetLogWithSource()));
// Cancel the stalled request.
stalled_handle.Reset();
@@ -1141,22 +1149,22 @@ TEST_F(ClientSocketPoolBaseTest, CancelPendingSocketAtSocketLimit) {
ClientSocketHandle handles[kDefaultMaxSockets];
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(), BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handles[i].Init(base::IntToString(i), params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback.callback(), pool_.get(),
+ NetLogWithSource()));
}
// Force a stalled group.
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
ClientSocketHandle stalled_handle;
TestCompletionCallback callback;
- EXPECT_EQ(
- ERR_IO_PENDING,
- stalled_handle.Init("foo", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ stalled_handle.Init("foo", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback.callback(), pool_.get(),
+ NetLogWithSource()));
// Since it is stalled, it should have no connect jobs.
EXPECT_EQ(0, pool_->NumConnectJobsInGroup("foo"));
@@ -1170,7 +1178,7 @@ TEST_F(ClientSocketPoolBaseTest, CancelPendingSocketAtSocketLimit) {
EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("foo"));
// The stalled socket should connect.
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(kDefaultMaxSockets + 1,
client_socket_factory_.allocation_count());
@@ -1195,11 +1203,11 @@ TEST_F(ClientSocketPoolBaseTest, WaitForStalledSocketAtSocketLimit) {
ClientSocketHandle handles[kDefaultMaxSockets];
for (int i = 0; i < kDefaultMaxSockets; ++i) {
TestCompletionCallback callback;
- EXPECT_EQ(
- OK, handles[i].Init(base::StringPrintf("Take 2: %d", i), params_,
- DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(OK, handles[i].Init(base::StringPrintf("Take 2: %d", i),
+ params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback.callback(), pool_.get(),
+ NetLogWithSource()));
}
EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
@@ -1207,11 +1215,11 @@ TEST_F(ClientSocketPoolBaseTest, WaitForStalledSocketAtSocketLimit) {
EXPECT_FALSE(pool_->IsStalled());
// Now we will hit the socket limit.
- EXPECT_EQ(
- ERR_IO_PENDING,
- stalled_handle.Init("foo", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ stalled_handle.Init("foo", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback.callback(), pool_.get(),
+ NetLogWithSource()));
EXPECT_TRUE(pool_->IsStalled());
// Dropping out of scope will close all handles and return them to idle.
@@ -1219,7 +1227,7 @@ TEST_F(ClientSocketPoolBaseTest, WaitForStalledSocketAtSocketLimit) {
// But if we wait for it, the released idle sockets will be closed in
// preference of the waiting request.
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(kDefaultMaxSockets + 1, client_socket_factory_.allocation_count());
EXPECT_EQ(3, pool_->IdleSocketCount());
@@ -1234,9 +1242,10 @@ TEST_F(ClientSocketPoolBaseTest, CloseIdleSocketAtSocketLimitDeleteGroup) {
for (int i = 0; i < kDefaultMaxSockets; ++i) {
ClientSocketHandle handle;
TestCompletionCallback callback;
- EXPECT_EQ(OK, handle.Init(base::IntToString(i), params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ OK, handle.Init(base::IntToString(i), params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback.callback(), pool_.get(), NetLogWithSource()));
}
// Flush all the DoReleaseSocket tasks.
@@ -1251,9 +1260,10 @@ TEST_F(ClientSocketPoolBaseTest, CloseIdleSocketAtSocketLimitDeleteGroup) {
// "0" is special here, since it should be the first entry in the sorted map,
// 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,
- ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(OK,
+ handle.Init("0", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback.callback(), pool_.get(), NetLogWithSource()));
EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
EXPECT_EQ(kDefaultMaxSockets - 1, pool_->IdleSocketCount());
@@ -1262,14 +1272,14 @@ TEST_F(ClientSocketPoolBaseTest, CloseIdleSocketAtSocketLimitDeleteGroup) {
TEST_F(ClientSocketPoolBaseTest, PendingRequests) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", IDLE));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("a", IDLE), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", MEDIUM), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOW), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE);
@@ -1294,18 +1304,18 @@ TEST_F(ClientSocketPoolBaseTest, PendingRequests) {
TEST_F(ClientSocketPoolBaseTest, PendingRequests_NoKeepAlive) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", MEDIUM), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOW), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
for (size_t i = kDefaultMaxSocketsPerGroup; i < requests_size(); ++i)
- EXPECT_EQ(OK, request(i)->WaitForResult());
+ EXPECT_THAT(request(i)->WaitForResult(), IsOk());
EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
@@ -1325,7 +1335,7 @@ TEST_F(ClientSocketPoolBaseTest, CancelRequestClearGroup) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
handle.Reset();
}
@@ -1339,7 +1349,7 @@ TEST_F(ClientSocketPoolBaseTest, ConnectCancelConnect) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
handle.Reset();
@@ -1347,9 +1357,9 @@ TEST_F(ClientSocketPoolBaseTest, ConnectCancelConnect) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog()));
+ callback2.callback(), pool_.get(), NetLogWithSource()));
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_FALSE(callback.have_result());
handle.Reset();
@@ -1358,13 +1368,13 @@ TEST_F(ClientSocketPoolBaseTest, ConnectCancelConnect) {
TEST_F(ClientSocketPoolBaseTest, CancelRequest) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", MEDIUM), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOW), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
// Cancel a request.
size_t index_to_cancel = kDefaultMaxSocketsPerGroup + 2;
@@ -1402,7 +1412,7 @@ void RequestSocketOnComplete(ClientSocketHandle* handle,
TestConnectJob::JobType next_job_type,
const CompletionCallback& nested_callback,
int first_request_result) {
- EXPECT_EQ(OK, first_request_result);
+ EXPECT_THAT(first_request_result, IsOk());
test_connect_job_factory->set_job_type(next_job_type);
@@ -1415,7 +1425,7 @@ void RequestSocketOnComplete(ClientSocketHandle* handle,
TestCompletionCallback callback;
int rv = handle->Init("a", params, LOWEST,
ClientSocketPool::RespectLimits::ENABLED,
- nested_callback, pool, BoundNetLog());
+ nested_callback, pool, NetLogWithSource());
if (rv != ERR_IO_PENDING) {
DCHECK_EQ(TestConnectJob::kMockJob, next_job_type);
nested_callback.Run(rv);
@@ -1438,10 +1448,10 @@ TEST_F(ClientSocketPoolBaseTest, RequestPendingJobTwice) {
base::Bind(&RequestSocketOnComplete, &handle, pool_.get(),
connect_job_factory_, TestConnectJob::kMockPendingJob,
second_result_callback.callback()),
- pool_.get(), BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ pool_.get(), NetLogWithSource());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_EQ(OK, second_result_callback.WaitForResult());
+ EXPECT_THAT(second_result_callback.WaitForResult(), IsOk());
}
// Tests the case where a second socket is requested in a completion callback,
@@ -1458,10 +1468,10 @@ TEST_F(ClientSocketPoolBaseTest, RequestPendingJobThenSynchronous) {
base::Bind(&RequestSocketOnComplete, &handle, pool_.get(),
connect_job_factory_, TestConnectJob::kMockPendingJob,
second_result_callback.callback()),
- pool_.get(), BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ pool_.get(), NetLogWithSource());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_EQ(OK, second_result_callback.WaitForResult());
+ EXPECT_THAT(second_result_callback.WaitForResult(), IsOk());
}
// Make sure that pending requests get serviced after active requests get
@@ -1471,13 +1481,13 @@ TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestWithPendingRequests) {
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
// Now, kDefaultMaxSocketsPerGroup requests should be active.
// Let's cancel them.
@@ -1488,7 +1498,7 @@ TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestWithPendingRequests) {
// Let's wait for the rest to complete now.
for (size_t i = kDefaultMaxSocketsPerGroup; i < requests_size(); ++i) {
- EXPECT_EQ(OK, request(i)->WaitForResult());
+ EXPECT_THAT(request(i)->WaitForResult(), IsOk());
request(i)->handle()->Reset();
}
@@ -1508,10 +1518,10 @@ TEST_F(ClientSocketPoolBaseTest, FailingActiveRequestWithPendingRequests) {
// Queue up all the requests
for (size_t i = 0; i < kNumberOfRequests; ++i)
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
for (size_t i = 0; i < kNumberOfRequests; ++i)
- EXPECT_EQ(ERR_CONNECTION_FAILED, request(i)->WaitForResult());
+ EXPECT_THAT(request(i)->WaitForResult(), IsError(ERR_CONNECTION_FAILED));
}
TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestThenRequestSocket) {
@@ -1523,17 +1533,17 @@ TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestThenRequestSocket) {
TestCompletionCallback callback;
int rv = handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Cancel the active request.
handle.Reset();
rv = handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_FALSE(handle.is_reused());
TestLoadTimingInfoConnectedNotReused(handle);
@@ -1548,18 +1558,18 @@ TEST_F(ClientSocketPoolBaseTest, GroupWithPendingRequestsIsNotEmpty) {
const RequestPriority kHighPriority = HIGHEST;
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
// This is going to be a pending request in an otherwise empty group.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
// Reach the maximum socket limit.
- EXPECT_EQ(OK, StartRequest("b", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("b", DEFAULT_PRIORITY), IsOk());
// Create a stalled group with high priorities.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", kHighPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", kHighPriority));
+ EXPECT_THAT(StartRequest("c", kHighPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("c", kHighPriority), IsError(ERR_IO_PENDING));
// Release the first two sockets from "a". Because this is a keepalive,
// the first release will unblock the pending request for "a". The
@@ -1587,11 +1597,11 @@ TEST_F(ClientSocketPoolBaseTest, BasicAsynchronous) {
int rv = handle.Init("a", params_, LOWEST,
ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), pool_.get(), log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
TestLoadTimingInfoNotConnected(handle);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfoConnectedNotReused(handle);
@@ -1603,16 +1613,14 @@ TEST_F(ClientSocketPoolBaseTest, BasicAsynchronous) {
log.GetEntries(&entries);
EXPECT_EQ(4u, entries.size());
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_SOCKET_POOL));
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 0, NetLogEventType::SOCKET_POOL));
EXPECT_TRUE(LogContainsEvent(
- entries, 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEvent(
- entries, 2, NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 3, NetLog::TYPE_SOCKET_POOL));
+ entries, 1, NetLogEventType::SOCKET_POOL_BOUND_TO_CONNECT_JOB,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEvent(entries, 2,
+ NetLogEventType::SOCKET_POOL_BOUND_TO_SOCKET,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEndEvent(entries, 3, NetLogEventType::SOCKET_POOL));
}
TEST_F(ClientSocketPoolBaseTest,
@@ -1633,7 +1641,7 @@ TEST_F(ClientSocketPoolBaseTest,
ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), pool_.get(), log.bound()));
EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_ssl_error());
EXPECT_TRUE(handle.ssl_error_response_info().headers.get() == NULL);
@@ -1641,13 +1649,11 @@ TEST_F(ClientSocketPoolBaseTest,
log.GetEntries(&entries);
EXPECT_EQ(3u, entries.size());
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_SOCKET_POOL));
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 0, NetLogEventType::SOCKET_POOL));
EXPECT_TRUE(LogContainsEvent(
- entries, 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 2, NetLog::TYPE_SOCKET_POOL));
+ entries, 1, NetLogEventType::SOCKET_POOL_BOUND_TO_CONNECT_JOB,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEndEvent(entries, 2, NetLogEventType::SOCKET_POOL));
}
// Check that an async ConnectJob failure does not result in creation of a new
@@ -1657,11 +1663,11 @@ TEST_F(ClientSocketPoolBaseTest, AsyncFailureWithPendingRequestWithJob) {
CreatePool(2, 2);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
- EXPECT_EQ(ERR_CONNECTION_FAILED, request(0)->WaitForResult());
- EXPECT_EQ(ERR_CONNECTION_FAILED, request(1)->WaitForResult());
+ EXPECT_THAT(request(0)->WaitForResult(), IsError(ERR_CONNECTION_FAILED));
+ EXPECT_THAT(request(1)->WaitForResult(), IsError(ERR_CONNECTION_FAILED));
EXPECT_EQ(2, client_socket_factory_.allocation_count());
}
@@ -1680,19 +1686,20 @@ TEST_F(ClientSocketPoolBaseTest, TwoRequestsCancelOne) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
BoundTestNetLog log2;
- EXPECT_EQ(ERR_IO_PENDING,
- handle2.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle2.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback2.callback(), pool_.get(), NetLogWithSource()));
handle.Reset();
// At this point, request 2 is just waiting for the connect job to finish.
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
handle2.Reset();
// Now request 2 has actually finished.
@@ -1704,10 +1711,10 @@ TEST_F(ClientSocketPoolBaseTest, CancelRequestLimitsJobs) {
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
+ EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOW), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", MEDIUM), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
EXPECT_EQ(kDefaultMaxSocketsPerGroup, pool_->NumConnectJobsInGroup("a"));
(*requests())[2]->handle()->Reset();
@@ -1732,11 +1739,11 @@ 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(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, req1.WaitForResult());
+ int rv = req1.handle()->Init(
+ "a", params_, DEFAULT_PRIORITY, ClientSocketPool::RespectLimits::ENABLED,
+ req1.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(req1.WaitForResult(), IsOk());
// Job 1 finished OK. Start job 2 (also async OK). Request 3 is pending
// without a job.
@@ -1745,13 +1752,13 @@ TEST_F(ClientSocketPoolBaseTest, ReleaseSockets) {
TestSocketRequest req2(&request_order, &completion_count);
rv = req2.handle()->Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- req2.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ 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,
ClientSocketPool::RespectLimits::ENABLED,
- req3.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ req3.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Both Requests 2 and 3 are pending. We release socket 1 which should
// service request 2. Request 3 should still be waiting.
@@ -1759,13 +1766,13 @@ TEST_F(ClientSocketPoolBaseTest, ReleaseSockets) {
// Run the released socket wakeups.
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(req2.handle()->socket());
- EXPECT_EQ(OK, req2.WaitForResult());
+ EXPECT_THAT(req2.WaitForResult(), IsOk());
EXPECT_FALSE(req3.handle()->socket());
// Signal job 2, which should service request 3.
client_socket_factory_.SignalJobs();
- EXPECT_EQ(OK, req3.WaitForResult());
+ EXPECT_THAT(req3.WaitForResult(), IsOk());
ASSERT_EQ(3U, request_order.size());
EXPECT_EQ(&req1, request_order[0]);
@@ -1784,16 +1791,16 @@ 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(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = req1.handle()->Init(
+ "a", params_, DEFAULT_PRIORITY, 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,
ClientSocketPool::RespectLimits::ENABLED,
- req2.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ req2.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// The pending job is sync.
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
@@ -1801,12 +1808,12 @@ TEST_F(ClientSocketPoolBaseTest, PendingJobCompletionOrder) {
TestSocketRequest req3(&request_order, &completion_count);
rv = req3.handle()->Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- req3.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ req3.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_EQ(ERR_CONNECTION_FAILED, req1.WaitForResult());
- EXPECT_EQ(OK, req2.WaitForResult());
- EXPECT_EQ(ERR_CONNECTION_FAILED, req3.WaitForResult());
+ EXPECT_THAT(req1.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
+ EXPECT_THAT(req2.WaitForResult(), IsOk());
+ EXPECT_THAT(req3.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
ASSERT_EQ(3U, request_order.size());
EXPECT_EQ(&req1, request_order[0]);
@@ -1823,8 +1830,8 @@ TEST_F(ClientSocketPoolBaseTest, LoadStateOneRequest) {
TestCompletionCallback callback;
int rv = handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(LOAD_STATE_CONNECTING, handle.GetLoadState());
client_socket_factory_.SetJobLoadState(0, LOAD_STATE_SSL_HANDSHAKE);
@@ -1844,16 +1851,16 @@ TEST_F(ClientSocketPoolBaseTest, LoadStateTwoRequests) {
TestCompletionCallback callback;
int rv = handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
client_socket_factory_.SetJobLoadState(0, LOAD_STATE_RESOLVING_HOST);
ClientSocketHandle handle2;
TestCompletionCallback callback2;
rv = handle2.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback2.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
client_socket_factory_.SetJobLoadState(1, LOAD_STATE_RESOLVING_HOST);
// Check that both handles report the state of the first job.
@@ -1877,15 +1884,15 @@ TEST_F(ClientSocketPoolBaseTest, LoadStateTwoRequestsChangeSecondRequestState) {
TestCompletionCallback callback;
int rv = handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ClientSocketHandle handle2;
TestCompletionCallback callback2;
rv = handle2.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback2.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
client_socket_factory_.SetJobLoadState(1, LOAD_STATE_RESOLVING_HOST);
EXPECT_EQ(LOAD_STATE_CONNECTING, handle.GetLoadState());
@@ -1894,7 +1901,7 @@ TEST_F(ClientSocketPoolBaseTest, LoadStateTwoRequestsChangeSecondRequestState) {
// First job connects and the first request gets the socket. The
// second handle switches to the state of the remaining ConnectJob.
client_socket_factory_.SignalJob(0);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(LOAD_STATE_RESOLVING_HOST, handle2.GetLoadState());
}
@@ -1907,8 +1914,8 @@ TEST_F(ClientSocketPoolBaseTest, LoadStateGroupLimit) {
TestCompletionCallback callback;
int rv = handle.Init("a", params_, MEDIUM,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(LOAD_STATE_CONNECTING, handle.GetLoadState());
// Request another socket from the same pool, buth with a higher priority.
@@ -1917,8 +1924,8 @@ TEST_F(ClientSocketPoolBaseTest, LoadStateGroupLimit) {
TestCompletionCallback callback2;
rv = handle2.Init("a", params_, HIGHEST,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback2.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET, handle.GetLoadState());
EXPECT_EQ(LOAD_STATE_CONNECTING, handle2.GetLoadState());
@@ -1930,7 +1937,7 @@ TEST_F(ClientSocketPoolBaseTest, LoadStateGroupLimit) {
EXPECT_EQ(LOAD_STATE_SSL_HANDSHAKE, handle2.GetLoadState());
client_socket_factory_.SignalJob(0);
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_EQ(LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET, handle.GetLoadState());
// Closing the second socket should cause the stalled handle to finally get a
@@ -1949,16 +1956,16 @@ TEST_F(ClientSocketPoolBaseTest, LoadStatePoolLimit) {
TestCompletionCallback callback;
int rv = handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Request for socket from another pool.
ClientSocketHandle handle2;
TestCompletionCallback callback2;
rv = handle2.Init("b", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback2.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Request another socket from the first pool. Request should stall at the
// socket pool limit.
@@ -1966,8 +1973,8 @@ TEST_F(ClientSocketPoolBaseTest, LoadStatePoolLimit) {
TestCompletionCallback callback3;
rv = handle3.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback2.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// The third handle should remain stalled as the other sockets in its group
// goes through the connect process.
@@ -1980,7 +1987,7 @@ TEST_F(ClientSocketPoolBaseTest, LoadStatePoolLimit) {
EXPECT_EQ(LOAD_STATE_WAITING_FOR_STALLED_SOCKET_POOL, handle3.GetLoadState());
client_socket_factory_.SignalJob(0);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(LOAD_STATE_WAITING_FOR_STALLED_SOCKET_POOL, handle3.GetLoadState());
// Closing a socket should allow the stalled handle to finally get a new
@@ -1999,7 +2006,7 @@ TEST_F(ClientSocketPoolBaseTest, Recoverable) {
EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
}
@@ -2014,9 +2021,9 @@ TEST_F(ClientSocketPoolBaseTest, AsyncRecoverable) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
- EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_PROXY_AUTH_REQUESTED));
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
}
@@ -2031,7 +2038,7 @@ TEST_F(ClientSocketPoolBaseTest, AdditionalErrorStateSynchronous) {
EXPECT_EQ(ERR_CONNECTION_FAILED,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_TRUE(handle.is_ssl_error());
@@ -2048,9 +2055,9 @@ TEST_F(ClientSocketPoolBaseTest, AdditionalErrorStateAsynchronous) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_TRUE(handle.is_ssl_error());
@@ -2070,10 +2077,10 @@ TEST_F(ClientSocketPoolBaseTest, CleanupTimedOutIdleSocketsReuse) {
TestCompletionCallback callback;
int rv = handle.Init("a", params_, LOWEST,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
- ASSERT_EQ(OK, callback.WaitForResult());
+ ASSERT_THAT(callback.WaitForResult(), IsOk());
// Use and release the socket.
EXPECT_EQ(1, handle.socket()->Write(NULL, 1, CompletionCallback()));
@@ -2089,7 +2096,7 @@ TEST_F(ClientSocketPoolBaseTest, CleanupTimedOutIdleSocketsReuse) {
rv = handle.Init("a", params_, LOWEST,
ClientSocketPool::RespectLimits::ENABLED,
CompletionCallback(), pool_.get(), log.bound());
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
EXPECT_TRUE(handle.is_reused());
TestLoadTimingInfoConnectedReused(handle);
@@ -2100,7 +2107,7 @@ TEST_F(ClientSocketPoolBaseTest, CleanupTimedOutIdleSocketsReuse) {
TestNetLogEntry::List entries;
log.GetEntries(&entries);
EXPECT_TRUE(LogContainsEntryWithType(
- entries, 1, NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET));
+ entries, 1, NetLogEventType::SOCKET_POOL_REUSED_AN_EXISTING_SOCKET));
}
#if defined(OS_IOS)
@@ -2126,16 +2133,16 @@ TEST_F(ClientSocketPoolBaseTest, MAYBE_CleanupTimedOutIdleSocketsNoReuse) {
TestCompletionCallback callback;
int rv = handle.Init("a", params_, LOWEST,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
ClientSocketHandle handle2;
TestCompletionCallback callback2;
rv = handle2.Init("a", params_, LOWEST,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ callback2.callback(), pool_.get(), NetLogWithSource());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle2));
// Cancel one of the requests. Wait for the other, which will get the first
@@ -2144,7 +2151,7 @@ TEST_F(ClientSocketPoolBaseTest, MAYBE_CleanupTimedOutIdleSocketsNoReuse) {
// just posts a DoReleaseSocket() task).
handle.Reset();
- ASSERT_EQ(OK, callback2.WaitForResult());
+ ASSERT_THAT(callback2.WaitForResult(), IsOk());
// Use the socket.
EXPECT_EQ(1, handle2.socket()->Write(NULL, 1, CompletionCallback()));
handle2.Reset();
@@ -2166,8 +2173,8 @@ TEST_F(ClientSocketPoolBaseTest, MAYBE_CleanupTimedOutIdleSocketsNoReuse) {
rv = handle.Init("a", params_, LOWEST,
ClientSocketPool::RespectLimits::ENABLED,
callback3.callback(), pool_.get(), log.bound());
- ASSERT_EQ(ERR_IO_PENDING, rv);
- ASSERT_EQ(OK, callback3.WaitForResult());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
+ ASSERT_THAT(callback3.WaitForResult(), IsOk());
EXPECT_FALSE(handle.is_reused());
// Make sure the idle socket is closed.
@@ -2178,7 +2185,7 @@ TEST_F(ClientSocketPoolBaseTest, MAYBE_CleanupTimedOutIdleSocketsNoReuse) {
TestNetLogEntry::List entries;
log.GetEntries(&entries);
EXPECT_FALSE(LogContainsEntryWithType(
- entries, 1, NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET));
+ entries, 1, NetLogEventType::SOCKET_POOL_REUSED_AN_EXISTING_SOCKET));
}
// Make sure that we process all pending requests even when we're stalling
@@ -2197,29 +2204,29 @@ TEST_F(ClientSocketPoolBaseTest, MultipleReleasingDisconnectedSockets) {
TestCompletionCallback callback;
int rv = handle.Init("a", params_, LOWEST,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(OK, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
ClientSocketHandle handle2;
TestCompletionCallback callback2;
rv = handle2.Init("a", params_, LOWEST,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(OK, rv);
+ callback2.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
ClientSocketHandle handle3;
TestCompletionCallback callback3;
rv = handle3.Init("a", params_, LOWEST,
ClientSocketPool::RespectLimits::ENABLED,
- callback3.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback3.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ClientSocketHandle handle4;
TestCompletionCallback callback4;
rv = handle4.Init("a", params_, LOWEST,
ClientSocketPool::RespectLimits::ENABLED,
- callback4.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback4.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Release two disconnected sockets.
@@ -2228,9 +2235,9 @@ TEST_F(ClientSocketPoolBaseTest, MultipleReleasingDisconnectedSockets) {
handle2.socket()->Disconnect();
handle2.Reset();
- EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_THAT(callback3.WaitForResult(), IsOk());
EXPECT_FALSE(handle3.is_reused());
- EXPECT_EQ(OK, callback4.WaitForResult());
+ EXPECT_THAT(callback4.WaitForResult(), IsOk());
EXPECT_FALSE(handle4.is_reused());
}
@@ -2256,26 +2263,26 @@ TEST_F(ClientSocketPoolBaseTest, SocketLimitReleasingSockets) {
EXPECT_EQ(OK, handle_a[i].Init("a", params_, LOWEST,
ClientSocketPool::RespectLimits::ENABLED,
callback_a[i].callback(), pool_.get(),
- BoundNetLog()));
+ NetLogWithSource()));
EXPECT_EQ(OK, handle_b[i].Init("b", params_, LOWEST,
ClientSocketPool::RespectLimits::ENABLED,
callback_b[i].callback(), pool_.get(),
- BoundNetLog()));
+ NetLogWithSource()));
}
// Make 4 pending requests, 2 per group.
for (int i = 2; i < 4; ++i) {
- EXPECT_EQ(
- ERR_IO_PENDING,
- handle_a[i].Init("a", params_, LOWEST,
- ClientSocketPool::RespectLimits::ENABLED,
- callback_a[i].callback(), pool_.get(), BoundNetLog()));
- EXPECT_EQ(
- ERR_IO_PENDING,
- handle_b[i].Init("b", params_, LOWEST,
- ClientSocketPool::RespectLimits::ENABLED,
- callback_b[i].callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle_a[i].Init("a", params_, LOWEST,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback_a[i].callback(), pool_.get(),
+ NetLogWithSource()));
+ EXPECT_EQ(ERR_IO_PENDING,
+ handle_b[i].Init("b", params_, LOWEST,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback_b[i].callback(), pool_.get(),
+ NetLogWithSource()));
}
// Release b's socket first. The order is important, because in
@@ -2297,8 +2304,8 @@ TEST_F(ClientSocketPoolBaseTest, SocketLimitReleasingSockets) {
handle_a[1].Reset();
for (int i = 2; i < 4; ++i) {
- EXPECT_EQ(OK, callback_b[i].WaitForResult());
- EXPECT_EQ(OK, callback_a[i].WaitForResult());
+ EXPECT_THAT(callback_b[i].WaitForResult(), IsOk());
+ EXPECT_THAT(callback_a[i].WaitForResult(), IsOk());
}
}
@@ -2308,21 +2315,21 @@ TEST_F(ClientSocketPoolBaseTest,
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsError(ERR_IO_PENDING));
- EXPECT_EQ(OK, (*requests())[0]->WaitForResult());
- EXPECT_EQ(OK, (*requests())[1]->WaitForResult());
+ EXPECT_THAT((*requests())[0]->WaitForResult(), IsOk());
+ EXPECT_THAT((*requests())[1]->WaitForResult(), IsOk());
EXPECT_EQ(2u, completion_count());
// Releases one connection.
EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::NO_KEEP_ALIVE));
- EXPECT_EQ(OK, (*requests())[2]->WaitForResult());
+ EXPECT_THAT((*requests())[2]->WaitForResult(), IsOk());
EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::NO_KEEP_ALIVE));
- EXPECT_EQ(OK, (*requests())[3]->WaitForResult());
+ EXPECT_THAT((*requests())[3]->WaitForResult(), IsOk());
EXPECT_EQ(4u, completion_count());
EXPECT_EQ(1, GetOrderOfRequest(1));
@@ -2362,7 +2369,7 @@ class TestReleasingSocketRequest : public TestCompletionCallbackBase {
EXPECT_EQ(expected_result_,
handle2_.Init("a", con_params, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback2_.callback(), pool_, BoundNetLog()));
+ callback2_.callback(), pool_, NetLogWithSource()));
}
TestClientSocketPool* const pool_;
@@ -2378,9 +2385,9 @@ class TestReleasingSocketRequest : public TestCompletionCallbackBase {
TEST_F(ClientSocketPoolBaseTest, AdditionalErrorSocketsDontUseSlot) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- EXPECT_EQ(OK, StartRequest("b", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("b", DEFAULT_PRIORITY));
+ EXPECT_THAT(StartRequest("b", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("a", DEFAULT_PRIORITY), IsOk());
+ EXPECT_THAT(StartRequest("b", DEFAULT_PRIORITY), IsOk());
EXPECT_EQ(static_cast<int>(requests_size()),
client_socket_factory_.allocation_count());
@@ -2388,14 +2395,15 @@ TEST_F(ClientSocketPoolBaseTest, AdditionalErrorSocketsDontUseSlot) {
connect_job_factory_->set_job_type(
TestConnectJob::kMockPendingAdditionalErrorStateJob);
TestReleasingSocketRequest req(pool_.get(), OK, false);
- EXPECT_EQ(ERR_IO_PENDING,
- req.handle()->Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- req.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ req.handle()->Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ req.callback(), pool_.get(), NetLogWithSource()));
// The next job should complete synchronously
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
- EXPECT_EQ(ERR_CONNECTION_FAILED, req.WaitForResult());
+ EXPECT_THAT(req.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
EXPECT_FALSE(req.handle()->is_initialized());
EXPECT_FALSE(req.handle()->socket());
EXPECT_TRUE(req.handle()->is_ssl_error());
@@ -2419,7 +2427,7 @@ TEST_F(ClientSocketPoolBaseTest, CallbackThatReleasesPool) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
pool_->FlushWithError(ERR_NETWORK_CHANGED);
@@ -2436,8 +2444,8 @@ TEST_F(ClientSocketPoolBaseTest, DoNotReuseSocketAfterFlush) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
+ callback.callback(), pool_.get(), NetLogWithSource()));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(ClientSocketHandle::UNUSED, handle.reuse_type());
pool_->FlushWithError(ERR_NETWORK_CHANGED);
@@ -2448,8 +2456,8 @@ TEST_F(ClientSocketPoolBaseTest, DoNotReuseSocketAfterFlush) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
+ callback.callback(), pool_.get(), NetLogWithSource()));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_EQ(ClientSocketHandle::UNUSED, handle.reuse_type());
}
@@ -2477,10 +2485,11 @@ class ConnectWithinCallback : public TestCompletionCallbackBase {
private:
void OnComplete(int result) {
SetResult(result);
- EXPECT_EQ(ERR_IO_PENDING,
- handle_.Init(group_name_, params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- nested_callback_.callback(), pool_, BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle_.Init(group_name_, params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ nested_callback_.callback(), pool_, NetLogWithSource()));
}
const std::string group_name_;
@@ -2504,14 +2513,14 @@ TEST_F(ClientSocketPoolBaseTest, AbortAllRequestsOnFlush) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
// Second job will be started during the first callback, and will
// asynchronously complete with OK.
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
pool_->FlushWithError(ERR_NETWORK_CHANGED);
- EXPECT_EQ(ERR_NETWORK_CHANGED, callback.WaitForResult());
- EXPECT_EQ(OK, callback.WaitForNestedResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_NETWORK_CHANGED));
+ EXPECT_THAT(callback.WaitForNestedResult(), IsOk());
}
// Cancel a pending socket request while we're at max sockets,
@@ -2529,17 +2538,17 @@ TEST_F(ClientSocketPoolBaseTest, BackupSocketCancelAtMaxSockets) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("bar", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
// Start (MaxSockets - 1) connected sockets to reach max sockets.
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
ClientSocketHandle handles[kDefaultMaxSockets];
for (int i = 1; i < kDefaultMaxSockets; ++i) {
TestCompletionCallback callback;
- EXPECT_EQ(OK,
- handles[i].Init("bar", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(OK, handles[i].Init("bar", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback.callback(), pool_.get(),
+ NetLogWithSource()));
}
base::RunLoop().RunUntilIdle();
@@ -2567,7 +2576,7 @@ TEST_F(ClientSocketPoolBaseTest, CancelBackupSocketAfterCancelingAllRequests) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("bar", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
ASSERT_TRUE(pool_->HasGroup("bar"));
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("bar"));
EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("bar"));
@@ -2595,21 +2604,22 @@ TEST_F(ClientSocketPoolBaseTest, CancelBackupSocketAfterFinishingAllRequests) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("bar", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
ClientSocketHandle handle2;
TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING,
- handle2.Init("bar", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle2.Init("bar", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback2.callback(), pool_.get(), NetLogWithSource()));
ASSERT_TRUE(pool_->HasGroup("bar"));
EXPECT_EQ(2, pool_->NumConnectJobsInGroup("bar"));
// Cancel request 1 and then complete request 2. With the requests finished,
// the backup timer should be cancelled.
handle.Reset();
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
// Wait for the backup timer to fire (add some slop to ensure it fires)
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(
ClientSocketPool::kMaxConnectRetryIntervalMs / 2 * 3));
@@ -2629,8 +2639,8 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingWaitingForConnect) {
EXPECT_EQ(ERR_IO_PENDING,
handle1.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
+ callback.callback(), pool_.get(), NetLogWithSource()));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// No idle sockets, no pending jobs.
EXPECT_EQ(0, pool_->IdleSocketCount());
@@ -2642,7 +2652,7 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingWaitingForConnect) {
EXPECT_EQ(ERR_IO_PENDING,
handle2.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
// No idle sockets, and one connecting job.
EXPECT_EQ(0, pool_->IdleSocketCount());
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
@@ -2658,7 +2668,7 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingWaitingForConnect) {
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
// The second socket connected, even though it was a Waiting Job.
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// And we can see there is still one job waiting.
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
@@ -2681,8 +2691,8 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtGroupCapacity) {
EXPECT_EQ(ERR_IO_PENDING,
handle1.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
+ callback.callback(), pool_.get(), NetLogWithSource()));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// No idle sockets, no pending jobs.
EXPECT_EQ(0, pool_->IdleSocketCount());
@@ -2694,7 +2704,7 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtGroupCapacity) {
EXPECT_EQ(ERR_IO_PENDING,
handle2.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
// No idle sockets, and one connecting job.
EXPECT_EQ(0, pool_->IdleSocketCount());
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
@@ -2710,7 +2720,7 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtGroupCapacity) {
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
// The second socket connected, even though it was a Waiting Job.
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// And we can see there is still one job waiting.
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
@@ -2735,8 +2745,8 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtStall) {
EXPECT_EQ(ERR_IO_PENDING,
handle1.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
+ callback.callback(), pool_.get(), NetLogWithSource()));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// No idle sockets, no pending jobs.
EXPECT_EQ(0, pool_->IdleSocketCount());
@@ -2748,7 +2758,7 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtStall) {
EXPECT_EQ(ERR_IO_PENDING,
handle2.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
// No idle sockets, and one connecting job.
EXPECT_EQ(0, pool_->IdleSocketCount());
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
@@ -2764,7 +2774,7 @@ TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtStall) {
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
// The second socket connected, even though it was a Waiting Job.
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// And we can see there is still one job waiting.
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
@@ -2789,10 +2799,11 @@ TEST_F(ClientSocketPoolBaseTest, SynchronouslyProcessOnePendingRequest) {
ClientSocketHandle handle1;
TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING,
- handle1.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback1.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle1.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback1.callback(), pool_.get(), NetLogWithSource()));
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
// Make the second request synchronously fail. This should make the Group
@@ -2802,15 +2813,16 @@ TEST_F(ClientSocketPoolBaseTest, SynchronouslyProcessOnePendingRequest) {
TestCompletionCallback callback2;
// It'll be ERR_IO_PENDING now, but the TestConnectJob will synchronously fail
// when created.
- EXPECT_EQ(ERR_IO_PENDING,
- handle2.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle2.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback2.callback(), pool_.get(), NetLogWithSource()));
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback1.WaitForResult());
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback2.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
+ EXPECT_THAT(callback2.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
EXPECT_FALSE(pool_->HasGroup("a"));
}
@@ -2821,27 +2833,30 @@ TEST_F(ClientSocketPoolBaseTest, PreferUsedSocketToUnusedSocket) {
ClientSocketHandle handle1;
TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING,
- handle1.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback1.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle1.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback1.callback(), pool_.get(), NetLogWithSource()));
ClientSocketHandle handle2;
TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING,
- handle2.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle2.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback2.callback(), pool_.get(), NetLogWithSource()));
ClientSocketHandle handle3;
TestCompletionCallback callback3;
- EXPECT_EQ(ERR_IO_PENDING,
- handle3.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback3.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle3.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback3.callback(), pool_.get(), NetLogWithSource()));
- EXPECT_EQ(OK, callback1.WaitForResult());
- EXPECT_EQ(OK, callback2.WaitForResult());
- EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
+ EXPECT_THAT(callback3.WaitForResult(), IsOk());
// Use the socket.
EXPECT_EQ(1, handle1.socket()->Write(NULL, 1, CompletionCallback()));
@@ -2851,15 +2866,18 @@ TEST_F(ClientSocketPoolBaseTest, PreferUsedSocketToUnusedSocket) {
handle2.Reset();
handle3.Reset();
- EXPECT_EQ(OK, handle1.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback1.callback(), pool_.get(), BoundNetLog()));
- EXPECT_EQ(OK, handle2.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog()));
- EXPECT_EQ(OK, handle3.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback3.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ OK, handle1.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback1.callback(), pool_.get(), NetLogWithSource()));
+ EXPECT_EQ(
+ OK, handle2.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback2.callback(), pool_.get(), NetLogWithSource()));
+ EXPECT_EQ(
+ OK, handle3.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback3.callback(), pool_.get(), NetLogWithSource()));
EXPECT_TRUE(handle1.socket()->WasEverUsed());
EXPECT_TRUE(handle2.socket()->WasEverUsed());
@@ -2870,7 +2888,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSockets) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 2, NetLogWithSource());
ASSERT_TRUE(pool_->HasGroup("a"));
EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
@@ -2879,24 +2897,26 @@ TEST_F(ClientSocketPoolBaseTest, RequestSockets) {
ClientSocketHandle handle1;
TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING,
- handle1.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback1.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle1.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback1.callback(), pool_.get(), NetLogWithSource()));
ClientSocketHandle handle2;
TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING,
- handle2.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle2.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback2.callback(), pool_.get(), NetLogWithSource()));
EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- EXPECT_EQ(OK, callback1.WaitForResult());
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
handle1.Reset();
handle2.Reset();
@@ -2911,17 +2931,18 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsWhenAlreadyHaveAConnectJob) {
ClientSocketHandle handle1;
TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING,
- handle1.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback1.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle1.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback1.callback(), pool_.get(), NetLogWithSource()));
ASSERT_TRUE(pool_->HasGroup("a"));
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 2, NetLogWithSource());
EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(1, pool_->NumUnassignedConnectJobsInGroup("a"));
@@ -2929,17 +2950,18 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsWhenAlreadyHaveAConnectJob) {
ClientSocketHandle handle2;
TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING,
- handle2.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle2.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback2.callback(), pool_.get(), NetLogWithSource()));
EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- EXPECT_EQ(OK, callback1.WaitForResult());
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
handle1.Reset();
handle2.Reset();
@@ -2955,39 +2977,42 @@ TEST_F(ClientSocketPoolBaseTest,
ClientSocketHandle handle1;
TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING,
- handle1.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback1.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle1.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback1.callback(), pool_.get(), NetLogWithSource()));
ClientSocketHandle handle2;
TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING,
- handle2.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle2.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback2.callback(), pool_.get(), NetLogWithSource()));
ClientSocketHandle handle3;
TestCompletionCallback callback3;
- EXPECT_EQ(ERR_IO_PENDING,
- handle3.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback3.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle3.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback3.callback(), pool_.get(), NetLogWithSource()));
ASSERT_TRUE(pool_->HasGroup("a"));
EXPECT_EQ(3, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 2, NetLogWithSource());
EXPECT_EQ(3, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- EXPECT_EQ(OK, callback1.WaitForResult());
- EXPECT_EQ(OK, callback2.WaitForResult());
- EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsOk());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
+ EXPECT_THAT(callback3.WaitForResult(), IsOk());
handle1.Reset();
handle2.Reset();
handle3.Reset();
@@ -3003,8 +3028,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsAtMaxSocketLimit) {
ASSERT_FALSE(pool_->HasGroup("a"));
- pool_->RequestSockets("a", &params_, kDefaultMaxSockets,
- BoundNetLog());
+ pool_->RequestSockets("a", &params_, kDefaultMaxSockets, NetLogWithSource());
ASSERT_TRUE(pool_->HasGroup("a"));
EXPECT_EQ(kDefaultMaxSockets, pool_->NumConnectJobsInGroup("a"));
@@ -3012,8 +3036,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsAtMaxSocketLimit) {
ASSERT_FALSE(pool_->HasGroup("b"));
- pool_->RequestSockets("b", &params_, kDefaultMaxSockets,
- BoundNetLog());
+ pool_->RequestSockets("b", &params_, kDefaultMaxSockets, NetLogWithSource());
ASSERT_FALSE(pool_->HasGroup("b"));
}
@@ -3025,7 +3048,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsHitMaxSocketLimit) {
ASSERT_FALSE(pool_->HasGroup("a"));
pool_->RequestSockets("a", &params_, kDefaultMaxSockets - 1,
- BoundNetLog());
+ NetLogWithSource());
ASSERT_TRUE(pool_->HasGroup("a"));
EXPECT_EQ(kDefaultMaxSockets - 1, pool_->NumConnectJobsInGroup("a"));
@@ -3035,8 +3058,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsHitMaxSocketLimit) {
ASSERT_FALSE(pool_->HasGroup("b"));
- pool_->RequestSockets("b", &params_, kDefaultMaxSockets,
- BoundNetLog());
+ pool_->RequestSockets("b", &params_, kDefaultMaxSockets, NetLogWithSource());
ASSERT_TRUE(pool_->HasGroup("b"));
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("b"));
@@ -3049,11 +3071,12 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsCountIdleSockets) {
ClientSocketHandle handle1;
TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING,
- handle1.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback1.callback(), pool_.get(), BoundNetLog()));
- ASSERT_EQ(OK, callback1.WaitForResult());
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle1.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback1.callback(), pool_.get(), NetLogWithSource()));
+ ASSERT_THAT(callback1.WaitForResult(), IsOk());
handle1.Reset();
ASSERT_TRUE(pool_->HasGroup("a"));
@@ -3061,7 +3084,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsCountIdleSockets) {
EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 2, NetLogWithSource());
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(1, pool_->NumUnassignedConnectJobsInGroup("a"));
@@ -3074,11 +3097,12 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsCountActiveSockets) {
ClientSocketHandle handle1;
TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING,
- handle1.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback1.callback(), pool_.get(), BoundNetLog()));
- ASSERT_EQ(OK, callback1.WaitForResult());
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle1.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback1.callback(), pool_.get(), NetLogWithSource()));
+ ASSERT_THAT(callback1.WaitForResult(), IsOk());
ASSERT_TRUE(pool_->HasGroup("a"));
EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
@@ -3086,7 +3110,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsCountActiveSockets) {
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
EXPECT_EQ(1, pool_->NumActiveSocketsInGroup("a"));
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 2, NetLogWithSource());
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(1, pool_->NumUnassignedConnectJobsInGroup("a"));
@@ -3099,7 +3123,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsSynchronous) {
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
pool_->RequestSockets("a", &params_, kDefaultMaxSocketsPerGroup,
- BoundNetLog());
+ NetLogWithSource());
ASSERT_TRUE(pool_->HasGroup("a"));
EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
@@ -3107,7 +3131,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsSynchronous) {
EXPECT_EQ(kDefaultMaxSocketsPerGroup, pool_->IdleSocketCountInGroup("a"));
pool_->RequestSockets("b", &params_, kDefaultMaxSocketsPerGroup,
- BoundNetLog());
+ NetLogWithSource());
EXPECT_EQ(0, pool_->NumConnectJobsInGroup("b"));
EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("b"));
@@ -3119,14 +3143,14 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsSynchronousError) {
connect_job_factory_->set_job_type(TestConnectJob::kMockFailingJob);
pool_->RequestSockets("a", &params_, kDefaultMaxSocketsPerGroup,
- BoundNetLog());
+ NetLogWithSource());
ASSERT_FALSE(pool_->HasGroup("a"));
connect_job_factory_->set_job_type(
TestConnectJob::kMockAdditionalErrorStateJob);
pool_->RequestSockets("a", &params_, kDefaultMaxSocketsPerGroup,
- BoundNetLog());
+ NetLogWithSource());
ASSERT_FALSE(pool_->HasGroup("a"));
}
@@ -3135,34 +3159,35 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsMultipleTimesDoesNothing) {
CreatePool(4, 4);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 2, NetLogWithSource());
ASSERT_TRUE(pool_->HasGroup("a"));
EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(2, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 2, NetLogWithSource());
EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(2, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
ClientSocketHandle handle1;
TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING,
- handle1.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback1.callback(), pool_.get(), BoundNetLog()));
- ASSERT_EQ(OK, callback1.WaitForResult());
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle1.Init("a", params_, DEFAULT_PRIORITY,
+ 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,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog());
+ callback2.callback(), pool_.get(), NetLogWithSource());
if (rv != OK) {
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
}
EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
@@ -3177,7 +3202,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsMultipleTimesDoesNothing) {
EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(2, pool_->IdleSocketCountInGroup("a"));
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 2, NetLogWithSource());
EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(2, pool_->IdleSocketCountInGroup("a"));
@@ -3187,24 +3212,24 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsDifferentNumSockets) {
CreatePool(4, 4);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- pool_->RequestSockets("a", &params_, 1, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 1, NetLogWithSource());
ASSERT_TRUE(pool_->HasGroup("a"));
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(1, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 2, NetLogWithSource());
EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(2, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- pool_->RequestSockets("a", &params_, 3, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 3, NetLogWithSource());
EXPECT_EQ(3, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(3, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- pool_->RequestSockets("a", &params_, 1, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 1, NetLogWithSource());
EXPECT_EQ(3, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(3, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
@@ -3214,7 +3239,7 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectJobsTakenByNormalRequests) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- pool_->RequestSockets("a", &params_, 1, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 1, NetLogWithSource());
ASSERT_TRUE(pool_->HasGroup("a"));
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
@@ -3223,16 +3248,17 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectJobsTakenByNormalRequests) {
ClientSocketHandle handle1;
TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING,
- handle1.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback1.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle1.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback1.callback(), pool_.get(), NetLogWithSource()));
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- ASSERT_EQ(OK, callback1.WaitForResult());
+ ASSERT_THAT(callback1.WaitForResult(), IsOk());
// Make sure if a preconnected socket is not fully connected when a request
// starts, it has a connect start time.
@@ -3247,7 +3273,7 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectJobsTakenByNormalRequests) {
TEST_F(ClientSocketPoolBaseTest, ConnectedPreconnectJobsHaveNoConnectTimes) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
- pool_->RequestSockets("a", &params_, 1, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 1, NetLogWithSource());
ASSERT_TRUE(pool_->HasGroup("a"));
EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
@@ -3256,9 +3282,10 @@ TEST_F(ClientSocketPoolBaseTest, ConnectedPreconnectJobsHaveNoConnectTimes) {
ClientSocketHandle handle;
TestCompletionCallback callback;
- EXPECT_EQ(OK, handle.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(OK,
+ handle.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback.callback(), pool_.get(), NetLogWithSource()));
// Make sure the idle socket was used.
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
@@ -3281,29 +3308,32 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectClosesIdleSocketRemovesGroup) {
// Set up one idle socket in "a".
ClientSocketHandle handle1;
TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING,
- handle1.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback1.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle1.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback1.callback(), pool_.get(), NetLogWithSource()));
- ASSERT_EQ(OK, callback1.WaitForResult());
+ ASSERT_THAT(callback1.WaitForResult(), IsOk());
handle1.Reset();
EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
// Set up two active sockets in "b".
ClientSocketHandle handle2;
TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING,
- handle1.Init("b", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback1.callback(), pool_.get(), BoundNetLog()));
- EXPECT_EQ(ERR_IO_PENDING,
- handle2.Init("b", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle1.Init("b", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback1.callback(), pool_.get(), NetLogWithSource()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle2.Init("b", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback2.callback(), pool_.get(), NetLogWithSource()));
- ASSERT_EQ(OK, callback1.WaitForResult());
- ASSERT_EQ(OK, callback2.WaitForResult());
+ ASSERT_THAT(callback1.WaitForResult(), IsOk());
+ ASSERT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("b"));
EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("b"));
EXPECT_EQ(2, pool_->NumActiveSocketsInGroup("b"));
@@ -3313,7 +3343,7 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectClosesIdleSocketRemovesGroup) {
// Requesting 2 preconnected sockets for "a" should fail to allocate any more
// sockets for "a", and "b" should still have 2 active sockets.
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 2, NetLogWithSource());
EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
@@ -3331,7 +3361,7 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectClosesIdleSocketRemovesGroup) {
EXPECT_EQ(2, pool_->IdleSocketCountInGroup("b"));
EXPECT_EQ(0, pool_->NumActiveSocketsInGroup("b"));
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 2, NetLogWithSource());
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(1, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
@@ -3350,7 +3380,7 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectWithoutBackupJob) {
connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
connect_job_factory_->set_timeout_duration(
base::TimeDelta::FromMilliseconds(500));
- pool_->RequestSockets("a", &params_, 1, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 1, NetLogWithSource());
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(1, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
@@ -3372,7 +3402,7 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectWithBackupJob) {
// Make the ConnectJob hang forever.
connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
- pool_->RequestSockets("a", &params_, 1, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 1, NetLogWithSource());
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(1, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
@@ -3385,13 +3415,13 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectWithBackupJob) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ callback.callback(), pool_.get(), NetLogWithSource()));
// Timer has started, but the backup connect job shouldn't be created yet.
EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
EXPECT_EQ(0, pool_->NumActiveSocketsInGroup("a"));
- ASSERT_EQ(OK, callback.WaitForResult());
+ ASSERT_THAT(callback.WaitForResult(), IsOk());
// The hung connect job should still be there, but everything else should be
// complete.
@@ -3407,7 +3437,7 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectWithUnreadData) {
CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockUnreadDataJob);
- pool_->RequestSockets("a", &params_, 1, BoundNetLog());
+ pool_->RequestSockets("a", &params_, 1, NetLogWithSource());
ASSERT_TRUE(pool_->HasGroup("a"));
EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
@@ -3419,9 +3449,10 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectWithUnreadData) {
connect_job_factory_->set_job_type(TestConnectJob::kMockFailingJob);
ClientSocketHandle handle;
TestCompletionCallback callback;
- EXPECT_EQ(OK, handle.Init("a", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(OK,
+ handle.Init("a", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback.callback(), pool_.get(), NetLogWithSource()));
ASSERT_TRUE(pool_->HasGroup("a"));
EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
@@ -3456,14 +3487,14 @@ class MockLayeredPool : public HigherLayeredPool {
scoped_refptr<TestSocketParams> params(new TestSocketParams());
return handle_.Init(group_name_, params, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback_.callback(), pool, BoundNetLog());
+ callback_.callback(), pool, NetLogWithSource());
}
int RequestSocketWithoutLimits(TestClientSocketPool* pool) {
scoped_refptr<TestSocketParams> params(new TestSocketParams());
return handle_.Init(group_name_, params, MAXIMUM_PRIORITY,
ClientSocketPool::RespectLimits::DISABLED,
- callback_.callback(), pool, BoundNetLog());
+ callback_.callback(), pool, NetLogWithSource());
}
bool ReleaseOneConnection() {
@@ -3494,7 +3525,7 @@ TEST_F(ClientSocketPoolBaseTest, FailToCloseIdleSocketsNotHeldByLayeredPool) {
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
MockLayeredPool mock_layered_pool(pool_.get(), "foo");
- EXPECT_EQ(OK, mock_layered_pool.RequestSocket(pool_.get()));
+ EXPECT_THAT(mock_layered_pool.RequestSocket(pool_.get()), IsOk());
EXPECT_CALL(mock_layered_pool, CloseOneIdleConnection())
.WillOnce(Return(false));
EXPECT_FALSE(pool_->CloseOneIdleConnectionInHigherLayeredPool());
@@ -3505,7 +3536,7 @@ TEST_F(ClientSocketPoolBaseTest, ForciblyCloseIdleSocketsHeldByLayeredPool) {
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
MockLayeredPool mock_layered_pool(pool_.get(), "foo");
- EXPECT_EQ(OK, mock_layered_pool.RequestSocket(pool_.get()));
+ EXPECT_THAT(mock_layered_pool.RequestSocket(pool_.get()), IsOk());
EXPECT_CALL(mock_layered_pool, CloseOneIdleConnection())
.WillOnce(Invoke(&mock_layered_pool,
&MockLayeredPool::ReleaseOneConnection));
@@ -3519,7 +3550,7 @@ TEST_F(ClientSocketPoolBaseTest, CloseIdleSocketsHeldByLayeredPoolWhenNeeded) {
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
MockLayeredPool mock_layered_pool(pool_.get(), "foo");
- EXPECT_EQ(OK, mock_layered_pool.RequestSocket(pool_.get()));
+ EXPECT_THAT(mock_layered_pool.RequestSocket(pool_.get()), IsOk());
EXPECT_CALL(mock_layered_pool, CloseOneIdleConnection())
.WillOnce(Invoke(&mock_layered_pool,
&MockLayeredPool::ReleaseOneConnection));
@@ -3528,8 +3559,8 @@ TEST_F(ClientSocketPoolBaseTest, CloseIdleSocketsHeldByLayeredPoolWhenNeeded) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
+ callback.callback(), pool_.get(), NetLogWithSource()));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
}
// Same as above, but the idle socket is in the same group as the stalled
@@ -3546,12 +3577,13 @@ TEST_F(ClientSocketPoolBaseTest,
// has the maximum number of connections already, it's not stalled).
ClientSocketHandle handle1;
TestCompletionCallback callback1;
- EXPECT_EQ(OK, handle1.Init("group1", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback1.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ OK, handle1.Init("group1", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback1.callback(), pool_.get(), NetLogWithSource()));
MockLayeredPool mock_layered_pool(pool_.get(), "group2");
- EXPECT_EQ(OK, mock_layered_pool.RequestSocket(pool_.get()));
+ EXPECT_THAT(mock_layered_pool.RequestSocket(pool_.get()), IsOk());
EXPECT_CALL(mock_layered_pool, CloseOneIdleConnection())
.WillOnce(Invoke(&mock_layered_pool,
&MockLayeredPool::ReleaseOneConnection));
@@ -3560,8 +3592,8 @@ TEST_F(ClientSocketPoolBaseTest,
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("group2", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool_.get(), BoundNetLog()));
- EXPECT_EQ(OK, callback2.WaitForResult());
+ callback2.callback(), pool_.get(), NetLogWithSource()));
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
}
// Tests the case when an idle socket can be closed when a new request is
@@ -3578,12 +3610,13 @@ TEST_F(ClientSocketPoolBaseTest,
ClientSocketHandle handle1;
TestCompletionCallback callback1;
- EXPECT_EQ(OK, handle1.Init("group1", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback1.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ OK, handle1.Init("group1", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback1.callback(), pool_.get(), NetLogWithSource()));
MockLayeredPool mock_layered_pool(pool_.get(), "group2");
- EXPECT_EQ(OK, mock_layered_pool.RequestSocket(pool_.get()));
+ EXPECT_THAT(mock_layered_pool.RequestSocket(pool_.get()), IsOk());
EXPECT_CALL(mock_layered_pool, CloseOneIdleConnection())
.WillRepeatedly(Invoke(&mock_layered_pool,
&MockLayeredPool::ReleaseOneConnection));
@@ -3592,10 +3625,11 @@ TEST_F(ClientSocketPoolBaseTest,
// The third request is made when the socket pool is in a stalled state.
ClientSocketHandle handle3;
TestCompletionCallback callback3;
- EXPECT_EQ(ERR_IO_PENDING,
- handle3.Init("group3", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback3.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle3.Init("group3", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback3.callback(), pool_.get(), NetLogWithSource()));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(callback3.have_result());
@@ -3606,16 +3640,17 @@ TEST_F(ClientSocketPoolBaseTest,
mock_layered_pool.set_can_release_connection(true);
ClientSocketHandle handle4;
TestCompletionCallback callback4;
- EXPECT_EQ(ERR_IO_PENDING,
- handle4.Init("group3", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback4.callback(), pool_.get(), BoundNetLog()));
- EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle4.Init("group3", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback4.callback(), pool_.get(), NetLogWithSource()));
+ EXPECT_THAT(callback3.WaitForResult(), IsOk());
EXPECT_FALSE(callback4.have_result());
// Closing a handle should free up another socket slot.
handle1.Reset();
- EXPECT_EQ(OK, callback4.WaitForResult());
+ EXPECT_THAT(callback4.WaitForResult(), IsOk());
}
// Tests the case when an idle socket can be closed when a new request is
@@ -3636,12 +3671,13 @@ TEST_F(ClientSocketPoolBaseTest,
ClientSocketHandle handle1;
TestCompletionCallback callback1;
- EXPECT_EQ(OK, handle1.Init("group1", params_, DEFAULT_PRIORITY,
- ClientSocketPool::RespectLimits::ENABLED,
- callback1.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ OK, handle1.Init("group1", params_, DEFAULT_PRIORITY,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback1.callback(), pool_.get(), NetLogWithSource()));
MockLayeredPool mock_layered_pool(pool_.get(), "group2");
- EXPECT_EQ(OK, mock_layered_pool.RequestSocket(pool_.get()));
+ EXPECT_THAT(mock_layered_pool.RequestSocket(pool_.get()), IsOk());
EXPECT_CALL(mock_layered_pool, CloseOneIdleConnection())
.WillRepeatedly(Invoke(&mock_layered_pool,
&MockLayeredPool::ReleaseOneConnection));
@@ -3650,10 +3686,11 @@ TEST_F(ClientSocketPoolBaseTest,
// The third request is made when the socket pool is in a stalled state.
ClientSocketHandle handle3;
TestCompletionCallback callback3;
- EXPECT_EQ(ERR_IO_PENDING,
- handle3.Init("group3", params_, MEDIUM,
- ClientSocketPool::RespectLimits::ENABLED,
- callback3.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle3.Init("group3", params_, MEDIUM,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback3.callback(), pool_.get(), NetLogWithSource()));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(callback3.have_result());
@@ -3663,16 +3700,17 @@ TEST_F(ClientSocketPoolBaseTest,
mock_layered_pool.set_can_release_connection(true);
ClientSocketHandle handle4;
TestCompletionCallback callback4;
- EXPECT_EQ(ERR_IO_PENDING,
- handle4.Init("group3", params_, HIGHEST,
- ClientSocketPool::RespectLimits::ENABLED,
- callback4.callback(), pool_.get(), BoundNetLog()));
- EXPECT_EQ(OK, callback4.WaitForResult());
+ EXPECT_EQ(
+ ERR_IO_PENDING,
+ handle4.Init("group3", params_, HIGHEST,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback4.callback(), pool_.get(), NetLogWithSource()));
+ EXPECT_THAT(callback4.WaitForResult(), IsOk());
EXPECT_FALSE(callback3.have_result());
// Closing a handle should free up another socket slot.
handle1.Reset();
- EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_THAT(callback3.WaitForResult(), IsOk());
}
TEST_F(ClientSocketPoolBaseTest,
@@ -3681,12 +3719,13 @@ TEST_F(ClientSocketPoolBaseTest,
connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
MockLayeredPool mock_layered_pool1(pool_.get(), "foo");
- EXPECT_EQ(OK, mock_layered_pool1.RequestSocket(pool_.get()));
+ EXPECT_THAT(mock_layered_pool1.RequestSocket(pool_.get()), IsOk());
EXPECT_CALL(mock_layered_pool1, CloseOneIdleConnection())
.WillRepeatedly(Invoke(&mock_layered_pool1,
&MockLayeredPool::ReleaseOneConnection));
MockLayeredPool mock_layered_pool2(pool_.get(), "bar");
- EXPECT_EQ(OK, mock_layered_pool2.RequestSocketWithoutLimits(pool_.get()));
+ EXPECT_THAT(mock_layered_pool2.RequestSocketWithoutLimits(pool_.get()),
+ IsOk());
EXPECT_CALL(mock_layered_pool2, CloseOneIdleConnection())
.WillRepeatedly(Invoke(&mock_layered_pool2,
&MockLayeredPool::ReleaseOneConnection));
@@ -3695,8 +3734,8 @@ TEST_F(ClientSocketPoolBaseTest,
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
+ callback.callback(), pool_.get(), NetLogWithSource()));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
}
// Test that when a socket pool and group are at their limits, a request
@@ -3726,7 +3765,7 @@ TEST_F(ClientSocketPoolBaseTest, IgnoreLimits) {
ClientSocketPool::RespectLimits::DISABLED));
ASSERT_EQ(1, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(OK, request(2)->WaitForResult());
+ EXPECT_THAT(request(2)->WaitForResult(), IsOk());
EXPECT_FALSE(request(1)->have_result());
}
@@ -3761,7 +3800,7 @@ TEST_F(ClientSocketPoolBaseTest, IgnoreLimitsCancelOtherJob) {
request(1)->handle()->Reset();
ASSERT_EQ(1, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(OK, request(2)->WaitForResult());
+ EXPECT_THAT(request(2)->WaitForResult(), IsOk());
EXPECT_FALSE(request(1)->have_result());
}
diff --git a/chromium/net/socket/client_socket_pool_manager.cc b/chromium/net/socket/client_socket_pool_manager.cc
index 3b38b2bd378..8482dc2b166 100644
--- a/chromium/net/socket/client_socket_pool_manager.cc
+++ b/chromium/net/socket/client_socket_pool_manager.cc
@@ -77,7 +77,7 @@ int InitSocketPoolHelper(ClientSocketPoolManager::SocketGroupType group_type,
const SSLConfig& ssl_config_for_proxy,
bool force_tunnel,
PrivacyMode privacy_mode,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
int num_preconnect_streams,
ClientSocketHandle* socket_handle,
HttpNetworkSession::SocketPoolType socket_pool_type,
@@ -357,7 +357,7 @@ int InitSocketHandleForHttpRequest(
const SSLConfig& ssl_config_for_origin,
const SSLConfig& ssl_config_for_proxy,
PrivacyMode privacy_mode,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
ClientSocketHandle* socket_handle,
const OnHostResolutionCallback& resolution_callback,
const CompletionCallback& callback) {
@@ -382,7 +382,7 @@ int InitSocketHandleForWebSocketRequest(
const SSLConfig& ssl_config_for_origin,
const SSLConfig& ssl_config_for_proxy,
PrivacyMode privacy_mode,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
ClientSocketHandle* socket_handle,
const OnHostResolutionCallback& resolution_callback,
const CompletionCallback& callback) {
@@ -395,16 +395,15 @@ int InitSocketHandleForWebSocketRequest(
resolution_callback, callback);
}
-int InitSocketHandleForRawConnect(
- const HostPortPair& host_port_pair,
- HttpNetworkSession* session,
- const ProxyInfo& proxy_info,
- const SSLConfig& ssl_config_for_origin,
- const SSLConfig& ssl_config_for_proxy,
- PrivacyMode privacy_mode,
- const BoundNetLog& net_log,
- ClientSocketHandle* socket_handle,
- const CompletionCallback& callback) {
+int InitSocketHandleForRawConnect(const HostPortPair& host_port_pair,
+ HttpNetworkSession* session,
+ const ProxyInfo& proxy_info,
+ const SSLConfig& ssl_config_for_origin,
+ const SSLConfig& ssl_config_for_proxy,
+ PrivacyMode privacy_mode,
+ const NetLogWithSource& net_log,
+ ClientSocketHandle* socket_handle,
+ const CompletionCallback& callback) {
DCHECK(socket_handle);
HttpRequestHeaders request_extra_headers;
int request_load_flags = 0;
@@ -424,7 +423,7 @@ int InitSocketHandleForTlsConnect(const HostPortPair& endpoint,
const SSLConfig& ssl_config_for_origin,
const SSLConfig& ssl_config_for_proxy,
PrivacyMode privacy_mode,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
ClientSocketHandle* socket_handle,
const CompletionCallback& callback) {
DCHECK(socket_handle);
@@ -452,7 +451,7 @@ int PreconnectSocketsForHttpRequest(
const SSLConfig& ssl_config_for_origin,
const SSLConfig& ssl_config_for_proxy,
PrivacyMode privacy_mode,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
int num_preconnect_streams) {
return InitSocketPoolHelper(
group_type, endpoint, request_extra_headers, request_load_flags,
diff --git a/chromium/net/socket/client_socket_pool_manager.h b/chromium/net/socket/client_socket_pool_manager.h
index 66c26f503ca..6f1d4078a35 100644
--- a/chromium/net/socket/client_socket_pool_manager.h
+++ b/chromium/net/socket/client_socket_pool_manager.h
@@ -22,15 +22,15 @@ class Value;
namespace net {
-typedef base::Callback<int(const AddressList&, const BoundNetLog& net_log)>
-OnHostResolutionCallback;
+typedef base::Callback<int(const AddressList&, const NetLogWithSource& net_log)>
+ OnHostResolutionCallback;
-class BoundNetLog;
class ClientSocketHandle;
class HostPortPair;
class HttpNetworkSession;
class HttpProxyClientSocketPool;
class HttpRequestHeaders;
+class NetLogWithSource;
class ProxyInfo;
class TransportClientSocketPool;
class SOCKSClientSocketPool;
@@ -108,7 +108,7 @@ int InitSocketHandleForHttpRequest(
const SSLConfig& ssl_config_for_origin,
const SSLConfig& ssl_config_for_proxy,
PrivacyMode privacy_mode,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
ClientSocketHandle* socket_handle,
const OnHostResolutionCallback& resolution_callback,
const CompletionCallback& callback);
@@ -134,7 +134,7 @@ int InitSocketHandleForWebSocketRequest(
const SSLConfig& ssl_config_for_origin,
const SSLConfig& ssl_config_for_proxy,
PrivacyMode privacy_mode,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
ClientSocketHandle* socket_handle,
const OnHostResolutionCallback& resolution_callback,
const CompletionCallback& callback);
@@ -150,7 +150,7 @@ NET_EXPORT int InitSocketHandleForRawConnect(
const SSLConfig& ssl_config_for_origin,
const SSLConfig& ssl_config_for_proxy,
PrivacyMode privacy_mode,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
ClientSocketHandle* socket_handle,
const CompletionCallback& callback);
@@ -165,7 +165,7 @@ NET_EXPORT int InitSocketHandleForTlsConnect(
const SSLConfig& ssl_config_for_origin,
const SSLConfig& ssl_config_for_proxy,
PrivacyMode privacy_mode,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
ClientSocketHandle* socket_handle,
const CompletionCallback& callback);
@@ -183,7 +183,7 @@ int PreconnectSocketsForHttpRequest(
const SSLConfig& ssl_config_for_origin,
const SSLConfig& ssl_config_for_proxy,
PrivacyMode privacy_mode,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
int num_preconnect_streams);
} // namespace net
diff --git a/chromium/net/socket/client_socket_pool_manager_impl.cc b/chromium/net/socket/client_socket_pool_manager_impl.cc
index 305f05ecd46..a701c596647 100644
--- a/chromium/net/socket/client_socket_pool_manager_impl.cc
+++ b/chromium/net/socket/client_socket_pool_manager_impl.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/values.h"
#include "net/http/http_network_session.h"
#include "net/http/http_proxy_client_socket_pool.h"
@@ -89,8 +90,8 @@ ClientSocketPoolManagerImpl::ClientSocketPoolManagerImpl(
ssl_session_cache_shard,
socket_factory,
transport_socket_pool_.get(),
- NULL /* no socks proxy */,
- NULL /* no http proxy */,
+ nullptr /* no socks proxy */,
+ nullptr /* no http proxy */,
ssl_config_service,
net_log)) {
CertDatabase::GetInstance()->AddObserver(this);
@@ -212,11 +213,13 @@ SOCKSClientSocketPool* ClientSocketPoolManagerImpl::GetSocketPoolForSOCKSProxy(
const HostPortPair& socks_proxy) {
SOCKSSocketPoolMap::const_iterator it = socks_socket_pools_.find(socks_proxy);
if (it != socks_socket_pools_.end()) {
- DCHECK(ContainsKey(transport_socket_pools_for_socks_proxies_, socks_proxy));
- return it->second;
+ DCHECK(base::ContainsKey(transport_socket_pools_for_socks_proxies_,
+ socks_proxy));
+ return it->second.get();
}
- DCHECK(!ContainsKey(transport_socket_pools_for_socks_proxies_, socks_proxy));
+ DCHECK(!base::ContainsKey(transport_socket_pools_for_socks_proxies_,
+ socks_proxy));
int sockets_per_proxy_server = max_sockets_per_proxy_server(pool_type_);
int sockets_per_group = std::min(sockets_per_proxy_server,
max_sockets_per_group(pool_type_));
@@ -224,19 +227,19 @@ SOCKSClientSocketPool* ClientSocketPoolManagerImpl::GetSocketPoolForSOCKSProxy(
std::pair<TransportSocketPoolMap::iterator, bool> tcp_ret =
transport_socket_pools_for_socks_proxies_.insert(std::make_pair(
socks_proxy,
- new TransportClientSocketPool(sockets_per_proxy_server,
- sockets_per_group, host_resolver_,
- socket_factory_, nullptr, net_log_)));
+ base::MakeUnique<TransportClientSocketPool>(
+ sockets_per_proxy_server, sockets_per_group, host_resolver_,
+ socket_factory_, nullptr, net_log_)));
DCHECK(tcp_ret.second);
std::pair<SOCKSSocketPoolMap::iterator, bool> ret =
socks_socket_pools_.insert(std::make_pair(
socks_proxy,
- new SOCKSClientSocketPool(sockets_per_proxy_server, sockets_per_group,
- host_resolver_, tcp_ret.first->second,
- nullptr, net_log_)));
+ base::MakeUnique<SOCKSClientSocketPool>(
+ sockets_per_proxy_server, sockets_per_group, host_resolver_,
+ tcp_ret.first->second.get(), nullptr, net_log_)));
- return ret.first->second;
+ return ret.first->second.get();
}
HttpProxyClientSocketPool*
@@ -245,15 +248,19 @@ ClientSocketPoolManagerImpl::GetSocketPoolForHTTPProxy(
HTTPProxySocketPoolMap::const_iterator it =
http_proxy_socket_pools_.find(http_proxy);
if (it != http_proxy_socket_pools_.end()) {
- DCHECK(ContainsKey(transport_socket_pools_for_http_proxies_, http_proxy));
- DCHECK(ContainsKey(transport_socket_pools_for_https_proxies_, http_proxy));
- DCHECK(ContainsKey(ssl_socket_pools_for_https_proxies_, http_proxy));
- return it->second;
+ DCHECK(base::ContainsKey(transport_socket_pools_for_http_proxies_,
+ http_proxy));
+ DCHECK(base::ContainsKey(transport_socket_pools_for_https_proxies_,
+ http_proxy));
+ DCHECK(base::ContainsKey(ssl_socket_pools_for_https_proxies_, http_proxy));
+ return it->second.get();
}
- DCHECK(!ContainsKey(transport_socket_pools_for_http_proxies_, http_proxy));
- DCHECK(!ContainsKey(transport_socket_pools_for_https_proxies_, http_proxy));
- DCHECK(!ContainsKey(ssl_socket_pools_for_https_proxies_, http_proxy));
+ DCHECK(
+ !base::ContainsKey(transport_socket_pools_for_http_proxies_, http_proxy));
+ DCHECK(!base::ContainsKey(transport_socket_pools_for_https_proxies_,
+ http_proxy));
+ DCHECK(!base::ContainsKey(ssl_socket_pools_for_https_proxies_, http_proxy));
int sockets_per_proxy_server = max_sockets_per_proxy_server(pool_type_);
int sockets_per_group = std::min(sockets_per_proxy_server,
@@ -262,7 +269,7 @@ ClientSocketPoolManagerImpl::GetSocketPoolForHTTPProxy(
std::pair<TransportSocketPoolMap::iterator, bool> tcp_http_ret =
transport_socket_pools_for_http_proxies_.insert(std::make_pair(
http_proxy,
- new TransportClientSocketPool(
+ base::MakeUnique<TransportClientSocketPool>(
sockets_per_proxy_server, sockets_per_group, host_resolver_,
socket_factory_, socket_performance_watcher_factory_, net_log_)));
DCHECK(tcp_http_ret.second);
@@ -270,7 +277,7 @@ ClientSocketPoolManagerImpl::GetSocketPoolForHTTPProxy(
std::pair<TransportSocketPoolMap::iterator, bool> tcp_https_ret =
transport_socket_pools_for_https_proxies_.insert(std::make_pair(
http_proxy,
- new TransportClientSocketPool(
+ base::MakeUnique<TransportClientSocketPool>(
sockets_per_proxy_server, sockets_per_group, host_resolver_,
socket_factory_, socket_performance_watcher_factory_, net_log_)));
DCHECK(tcp_https_ret.second);
@@ -278,28 +285,24 @@ ClientSocketPoolManagerImpl::GetSocketPoolForHTTPProxy(
std::pair<SSLSocketPoolMap::iterator, bool> ssl_https_ret =
ssl_socket_pools_for_https_proxies_.insert(std::make_pair(
http_proxy,
- new SSLClientSocketPool(
+ base::MakeUnique<SSLClientSocketPool>(
sockets_per_proxy_server, sockets_per_group, cert_verifier_,
channel_id_service_, transport_security_state_,
cert_transparency_verifier_, ct_policy_enforcer_,
ssl_session_cache_shard_, socket_factory_,
- tcp_https_ret.first->second /* https proxy */,
- NULL /* no socks proxy */, NULL /* no http proxy */,
+ tcp_https_ret.first->second.get() /* https proxy */,
+ nullptr /* no socks proxy */, nullptr /* no http proxy */,
ssl_config_service_.get(), net_log_)));
DCHECK(tcp_https_ret.second);
std::pair<HTTPProxySocketPoolMap::iterator, bool> ret =
- http_proxy_socket_pools_.insert(
- std::make_pair(
- http_proxy,
- new HttpProxyClientSocketPool(
- sockets_per_proxy_server,
- sockets_per_group,
- tcp_http_ret.first->second,
- ssl_https_ret.first->second,
- net_log_)));
-
- return ret.first->second;
+ http_proxy_socket_pools_.insert(std::make_pair(
+ http_proxy, base::MakeUnique<HttpProxyClientSocketPool>(
+ sockets_per_proxy_server, sockets_per_group,
+ tcp_http_ret.first->second.get(),
+ ssl_https_ret.first->second.get(), net_log_)));
+
+ return ret.first->second.get();
}
SSLClientSocketPool* ClientSocketPoolManagerImpl::GetSocketPoolForSSLWithProxy(
@@ -307,27 +310,26 @@ SSLClientSocketPool* ClientSocketPoolManagerImpl::GetSocketPoolForSSLWithProxy(
SSLSocketPoolMap::const_iterator it =
ssl_socket_pools_for_proxies_.find(proxy_server);
if (it != ssl_socket_pools_for_proxies_.end())
- return it->second;
+ return it->second.get();
int sockets_per_proxy_server = max_sockets_per_proxy_server(pool_type_);
int sockets_per_group = std::min(sockets_per_proxy_server,
max_sockets_per_group(pool_type_));
- SSLClientSocketPool* new_pool = new SSLClientSocketPool(
- sockets_per_proxy_server, sockets_per_group, cert_verifier_,
- channel_id_service_, transport_security_state_,
- cert_transparency_verifier_, ct_policy_enforcer_,
- ssl_session_cache_shard_, socket_factory_,
- NULL, /* no tcp pool, we always go through a proxy */
- GetSocketPoolForSOCKSProxy(proxy_server),
- GetSocketPoolForHTTPProxy(proxy_server), ssl_config_service_.get(),
- net_log_);
-
std::pair<SSLSocketPoolMap::iterator, bool> ret =
- ssl_socket_pools_for_proxies_.insert(std::make_pair(proxy_server,
- new_pool));
+ ssl_socket_pools_for_proxies_.insert(std::make_pair(
+ proxy_server,
+ base::MakeUnique<SSLClientSocketPool>(
+ sockets_per_proxy_server, sockets_per_group, cert_verifier_,
+ channel_id_service_, transport_security_state_,
+ cert_transparency_verifier_, ct_policy_enforcer_,
+ ssl_session_cache_shard_, socket_factory_,
+ nullptr, /* no tcp pool, we always go through a proxy */
+ GetSocketPoolForSOCKSProxy(proxy_server),
+ GetSocketPoolForHTTPProxy(proxy_server),
+ ssl_config_service_.get(), net_log_)));
- return ret.first->second;
+ return ret.first->second.get();
}
std::unique_ptr<base::Value>
diff --git a/chromium/net/socket/client_socket_pool_manager_impl.h b/chromium/net/socket/client_socket_pool_manager_impl.h
index 3fae145a304..a6b18385e48 100644
--- a/chromium/net/socket/client_socket_pool_manager_impl.h
+++ b/chromium/net/socket/client_socket_pool_manager_impl.h
@@ -12,7 +12,6 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/stl_util.h"
#include "base/threading/non_thread_safe.h"
#include "net/cert/cert_database.h"
#include "net/http/http_network_session.h"
@@ -34,23 +33,6 @@ class SSLConfigService;
class TransportClientSocketPool;
class TransportSecurityState;
-namespace internal {
-
-// A helper class for auto-deleting Values in the destructor.
-template <typename Key, typename Value>
-class OwnedPoolMap : public std::map<Key, Value> {
- public:
- OwnedPoolMap() {
- static_assert(std::is_pointer<Value>::value, "value must be a pointer");
- }
-
- ~OwnedPoolMap() {
- STLDeleteValues(this);
- }
-};
-
-} // namespace internal
-
class ClientSocketPoolManagerImpl : public base::NonThreadSafe,
public ClientSocketPoolManager,
public CertDatabase::Observer {
@@ -94,14 +76,14 @@ class ClientSocketPoolManagerImpl : public base::NonThreadSafe,
void OnCACertChanged(const X509Certificate* cert) override;
private:
- typedef internal::OwnedPoolMap<HostPortPair, TransportClientSocketPool*>
- TransportSocketPoolMap;
- typedef internal::OwnedPoolMap<HostPortPair, SOCKSClientSocketPool*>
- SOCKSSocketPoolMap;
- typedef internal::OwnedPoolMap<HostPortPair, HttpProxyClientSocketPool*>
- HTTPProxySocketPoolMap;
- typedef internal::OwnedPoolMap<HostPortPair, SSLClientSocketPool*>
- SSLSocketPoolMap;
+ using TransportSocketPoolMap =
+ std::map<HostPortPair, std::unique_ptr<TransportClientSocketPool>>;
+ using SOCKSSocketPoolMap =
+ std::map<HostPortPair, std::unique_ptr<SOCKSClientSocketPool>>;
+ using HTTPProxySocketPoolMap =
+ std::map<HostPortPair, std::unique_ptr<HttpProxyClientSocketPool>>;
+ using SSLSocketPoolMap =
+ std::map<HostPortPair, std::unique_ptr<SSLClientSocketPool>>;
NetLog* const net_log_;
ClientSocketFactory* const socket_factory_;
diff --git a/chromium/net/socket/fuzzed_socket.cc b/chromium/net/socket/fuzzed_socket.cc
index 11db43a36d8..40c0adfee26 100644
--- a/chromium/net/socket/fuzzed_socket.cc
+++ b/chromium/net/socket/fuzzed_socket.cc
@@ -9,9 +9,10 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/test/fuzzed_data_provider.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "net/base/fuzzed_data_provider.h"
#include "net/base/io_buffer.h"
+#include "net/log/net_log_source_type.h"
namespace net {
@@ -32,10 +33,10 @@ const Error kReadWriteErrors[] = {ERR_CONNECTION_CLOSED, ERR_FAILED,
} // namespace
-FuzzedSocket::FuzzedSocket(FuzzedDataProvider* data_provider,
+FuzzedSocket::FuzzedSocket(base::FuzzedDataProvider* data_provider,
net::NetLog* net_log)
: data_provider_(data_provider),
- bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)),
+ net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::SOCKET)),
remote_address_(IPEndPoint(IPAddress::IPv4Localhost(), 80)),
weak_factory_(this) {}
@@ -206,8 +207,8 @@ int FuzzedSocket::GetLocalAddress(IPEndPoint* address) const {
return OK;
}
-const BoundNetLog& FuzzedSocket::NetLog() const {
- return bound_net_log_;
+const NetLogWithSource& FuzzedSocket::NetLog() const {
+ return net_log_;
}
void FuzzedSocket::SetSubresourceSpeculation() {}
diff --git a/chromium/net/socket/fuzzed_socket.h b/chromium/net/socket/fuzzed_socket.h
index 90325547e7b..491b339e382 100644
--- a/chromium/net/socket/fuzzed_socket.h
+++ b/chromium/net/socket/fuzzed_socket.h
@@ -13,14 +13,18 @@
#include "net/base/completion_callback.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/stream_socket.h"
+namespace base {
+class FuzzedDataProvider;
+}
+
namespace net {
-class FuzzedDataProvider;
class IPEndPoint;
class IOBuffer;
+class NetLog;
// A StreamSocket that uses a FuzzedDataProvider to generate responses. Writes
// can succeed synchronously or asynchronously, can write some or all of the
@@ -38,7 +42,7 @@ class FuzzedSocket : public StreamSocket {
public:
// |data_provider| is used as to determine behavior of the FuzzedSocket. It
// must remain valid until after the FuzzedSocket is destroyed.
- FuzzedSocket(FuzzedDataProvider* data_provider, net::NetLog* net_log);
+ FuzzedSocket(base::FuzzedDataProvider* data_provider, net::NetLog* net_log);
~FuzzedSocket() override;
// If set to true, the socket will fuzz the result of the Connect() call.
@@ -70,7 +74,7 @@ class FuzzedSocket : public StreamSocket {
bool IsConnectedAndIdle() const override;
int GetPeerAddress(IPEndPoint* address) const override;
int GetLocalAddress(IPEndPoint* address) const override;
- const BoundNetLog& NetLog() const override;
+ const NetLogWithSource& NetLog() const override;
void SetSubresourceSpeculation() override;
void SetOmniboxSpeculation() override;
bool WasEverUsed() const override;
@@ -92,7 +96,7 @@ class FuzzedSocket : public StreamSocket {
void OnWriteComplete(const CompletionCallback& callback, int result);
void OnConnectComplete(const CompletionCallback& callback, int result);
- FuzzedDataProvider* data_provider_;
+ base::FuzzedDataProvider* data_provider_;
// If true, the result of the Connect() call is fuzzed - it can succeed or
// fail with a variety of connection errors, and it can complete synchronously
@@ -115,7 +119,7 @@ class FuzzedSocket : public StreamSocket {
int64_t total_bytes_read_ = 0;
int64_t total_bytes_written_ = 0;
- BoundNetLog bound_net_log_;
+ NetLogWithSource net_log_;
IPEndPoint remote_address_;
diff --git a/chromium/net/socket/fuzzed_socket_factory.cc b/chromium/net/socket/fuzzed_socket_factory.cc
index f77e36e2701..3b4746c49e2 100644
--- a/chromium/net/socket/fuzzed_socket_factory.cc
+++ b/chromium/net/socket/fuzzed_socket_factory.cc
@@ -6,11 +6,12 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
+#include "base/test/fuzzed_data_provider.h"
#include "net/base/address_list.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/base/network_change_notifier.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/connection_attempts.h"
#include "net/socket/fuzzed_socket.h"
@@ -19,6 +20,8 @@
namespace net {
+class NetLog;
+
namespace {
// SSLClientSocket implementation that always fails to connect.
@@ -61,7 +64,7 @@ class FailingSSLClientSocket : public SSLClientSocket {
return ERR_SOCKET_NOT_CONNECTED;
}
- const BoundNetLog& NetLog() const override { return net_log_; }
+ const NetLogWithSource& NetLog() const override { return net_log_; }
void SetSubresourceSpeculation() override {}
void SetOmniboxSpeculation() override {}
@@ -99,17 +102,14 @@ class FailingSSLClientSocket : public SSLClientSocket {
// SSLClientSocket implementation:
void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override {}
- NextProtoStatus GetNextProto(std::string* proto) const override {
- return NextProtoStatus::kNextProtoUnsupported;
- }
-
ChannelIDService* GetChannelIDService() const override {
NOTREACHED();
return nullptr;
}
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) override {
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) override {
NOTREACHED();
return ERR_UNEXPECTED;
}
@@ -120,14 +120,15 @@ class FailingSSLClientSocket : public SSLClientSocket {
}
private:
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
DISALLOW_COPY_AND_ASSIGN(FailingSSLClientSocket);
};
} // namespace
-FuzzedSocketFactory::FuzzedSocketFactory(FuzzedDataProvider* data_provider)
+FuzzedSocketFactory::FuzzedSocketFactory(
+ base::FuzzedDataProvider* data_provider)
: data_provider_(data_provider) {}
FuzzedSocketFactory::~FuzzedSocketFactory() {}
@@ -137,15 +138,15 @@ FuzzedSocketFactory::CreateDatagramClientSocket(
DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
NetLog* net_log,
- const NetLog::Source& source) {
- return base::WrapUnique(new FuzzedDatagramClientSocket(data_provider_));
+ const NetLogSource& source) {
+ return base::MakeUnique<FuzzedDatagramClientSocket>(data_provider_);
}
std::unique_ptr<StreamSocket> FuzzedSocketFactory::CreateTransportClientSocket(
const AddressList& addresses,
std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
NetLog* net_log,
- const NetLog::Source& source) {
+ const NetLogSource& source) {
std::unique_ptr<FuzzedSocket> socket(
new FuzzedSocket(data_provider_, net_log));
socket->set_fuzz_connect_result(true);
@@ -159,7 +160,7 @@ std::unique_ptr<SSLClientSocket> FuzzedSocketFactory::CreateSSLClientSocket(
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
const SSLClientSocketContext& context) {
- return base::WrapUnique(new FailingSSLClientSocket());
+ return base::MakeUnique<FailingSSLClientSocket>();
}
void FuzzedSocketFactory::ClearSSLSessionCache() {}
diff --git a/chromium/net/socket/fuzzed_socket_factory.h b/chromium/net/socket/fuzzed_socket_factory.h
index 0f567adc8bc..c0f668cb3eb 100644
--- a/chromium/net/socket/fuzzed_socket_factory.h
+++ b/chromium/net/socket/fuzzed_socket_factory.h
@@ -10,9 +10,11 @@
#include "base/macros.h"
#include "net/socket/client_socket_factory.h"
-namespace net {
-
+namespace base {
class FuzzedDataProvider;
+}
+
+namespace net {
// A socket factory that creates FuzzedSockets that share the same
// FuzzedDataProvider. To behave consistently, the read operations on all
@@ -30,20 +32,20 @@ class FuzzedSocketFactory : public ClientSocketFactory {
// creates. Other objects can also continue to consume |data_provider|, as
// long as their calls into it are made on the CLientSocketFactory's thread
// and the calls are deterministic.
- explicit FuzzedSocketFactory(FuzzedDataProvider* data_provider);
+ explicit FuzzedSocketFactory(base::FuzzedDataProvider* data_provider);
~FuzzedSocketFactory() override;
std::unique_ptr<DatagramClientSocket> CreateDatagramClientSocket(
DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
NetLog* net_log,
- const NetLog::Source& source) override;
+ const NetLogSource& source) override;
std::unique_ptr<StreamSocket> CreateTransportClientSocket(
const AddressList& addresses,
std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
NetLog* net_log,
- const NetLog::Source& source) override;
+ const NetLogSource& source) override;
std::unique_ptr<SSLClientSocket> CreateSSLClientSocket(
std::unique_ptr<ClientSocketHandle> transport_socket,
@@ -54,7 +56,7 @@ class FuzzedSocketFactory : public ClientSocketFactory {
void ClearSSLSessionCache() override;
private:
- FuzzedDataProvider* data_provider_;
+ base::FuzzedDataProvider* data_provider_;
DISALLOW_COPY_AND_ASSIGN(FuzzedSocketFactory);
};
diff --git a/chromium/net/socket/mock_client_socket_pool_manager.cc b/chromium/net/socket/mock_client_socket_pool_manager.cc
index 668c303e84d..3f33b64533b 100644
--- a/chromium/net/socket/mock_client_socket_pool_manager.cc
+++ b/chromium/net/socket/mock_client_socket_pool_manager.cc
@@ -27,20 +27,20 @@ void MockClientSocketPoolManager::SetSSLSocketPool(
void MockClientSocketPoolManager::SetSocketPoolForSOCKSProxy(
const HostPortPair& socks_proxy,
- SOCKSClientSocketPool* pool) {
- socks_socket_pools_[socks_proxy] = pool;
+ std::unique_ptr<SOCKSClientSocketPool> pool) {
+ socks_socket_pools_[socks_proxy] = std::move(pool);
}
void MockClientSocketPoolManager::SetSocketPoolForHTTPProxy(
const HostPortPair& http_proxy,
- HttpProxyClientSocketPool* pool) {
- http_proxy_socket_pools_[http_proxy] = pool;
+ std::unique_ptr<HttpProxyClientSocketPool> pool) {
+ http_proxy_socket_pools_[http_proxy] = std::move(pool);
}
void MockClientSocketPoolManager::SetSocketPoolForSSLWithProxy(
const HostPortPair& proxy_server,
- SSLClientSocketPool* pool) {
- ssl_socket_pools_for_proxies_[proxy_server] = pool;
+ std::unique_ptr<SSLClientSocketPool> pool) {
+ ssl_socket_pools_for_proxies_[proxy_server] = std::move(pool);
}
void MockClientSocketPoolManager::FlushSocketPoolsWithError(int error) {
@@ -64,8 +64,8 @@ SOCKSClientSocketPool* MockClientSocketPoolManager::GetSocketPoolForSOCKSProxy(
const HostPortPair& socks_proxy) {
SOCKSSocketPoolMap::const_iterator it = socks_socket_pools_.find(socks_proxy);
if (it != socks_socket_pools_.end())
- return it->second;
- return NULL;
+ return it->second.get();
+ return nullptr;
}
HttpProxyClientSocketPool*
@@ -74,8 +74,8 @@ MockClientSocketPoolManager::GetSocketPoolForHTTPProxy(
HTTPProxySocketPoolMap::const_iterator it =
http_proxy_socket_pools_.find(http_proxy);
if (it != http_proxy_socket_pools_.end())
- return it->second;
- return NULL;
+ return it->second.get();
+ return nullptr;
}
SSLClientSocketPool* MockClientSocketPoolManager::GetSocketPoolForSSLWithProxy(
@@ -83,8 +83,8 @@ SSLClientSocketPool* MockClientSocketPoolManager::GetSocketPoolForSSLWithProxy(
SSLSocketPoolMap::const_iterator it =
ssl_socket_pools_for_proxies_.find(proxy_server);
if (it != ssl_socket_pools_for_proxies_.end())
- return it->second;
- return NULL;
+ return it->second.get();
+ return nullptr;
}
std::unique_ptr<base::Value>
diff --git a/chromium/net/socket/mock_client_socket_pool_manager.h b/chromium/net/socket/mock_client_socket_pool_manager.h
index 919ef32f3aa..379065a8321 100644
--- a/chromium/net/socket/mock_client_socket_pool_manager.h
+++ b/chromium/net/socket/mock_client_socket_pool_manager.h
@@ -20,11 +20,12 @@ class MockClientSocketPoolManager : public ClientSocketPoolManager {
void SetTransportSocketPool(TransportClientSocketPool* pool);
void SetSSLSocketPool(SSLClientSocketPool* pool);
void SetSocketPoolForSOCKSProxy(const HostPortPair& socks_proxy,
- SOCKSClientSocketPool* pool);
- void SetSocketPoolForHTTPProxy(const HostPortPair& http_proxy,
- HttpProxyClientSocketPool* pool);
+ std::unique_ptr<SOCKSClientSocketPool> pool);
+ void SetSocketPoolForHTTPProxy(
+ const HostPortPair& http_proxy,
+ std::unique_ptr<HttpProxyClientSocketPool> pool);
void SetSocketPoolForSSLWithProxy(const HostPortPair& proxy_server,
- SSLClientSocketPool* pool);
+ std::unique_ptr<SSLClientSocketPool> pool);
// ClientSocketPoolManager methods:
void FlushSocketPoolsWithError(int error) override;
@@ -40,14 +41,14 @@ class MockClientSocketPoolManager : public ClientSocketPoolManager {
std::unique_ptr<base::Value> SocketPoolInfoToValue() const override;
private:
- typedef internal::OwnedPoolMap<HostPortPair, TransportClientSocketPool*>
- TransportSocketPoolMap;
- typedef internal::OwnedPoolMap<HostPortPair, SOCKSClientSocketPool*>
- SOCKSSocketPoolMap;
- typedef internal::OwnedPoolMap<HostPortPair, HttpProxyClientSocketPool*>
- HTTPProxySocketPoolMap;
- typedef internal::OwnedPoolMap<HostPortPair, SSLClientSocketPool*>
- SSLSocketPoolMap;
+ using TransportSocketPoolMap =
+ std::map<HostPortPair, std::unique_ptr<TransportClientSocketPool>>;
+ using SOCKSSocketPoolMap =
+ std::map<HostPortPair, std::unique_ptr<SOCKSClientSocketPool>>;
+ using HTTPProxySocketPoolMap =
+ std::map<HostPortPair, std::unique_ptr<HttpProxyClientSocketPool>>;
+ using SSLSocketPoolMap =
+ std::map<HostPortPair, std::unique_ptr<SSLClientSocketPool>>;
std::unique_ptr<TransportClientSocketPool> transport_socket_pool_;
std::unique_ptr<SSLClientSocketPool> ssl_socket_pool_;
diff --git a/chromium/net/socket/next_proto.cc b/chromium/net/socket/next_proto.cc
deleted file mode 100644
index fcca6718097..00000000000
--- a/chromium/net/socket/next_proto.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/socket/next_proto.h"
-
-namespace net {
-
-bool NextProtoIsSPDY(NextProto next_proto) {
- return next_proto >= kProtoSPDYMinimumVersion &&
- next_proto <= kProtoSPDYMaximumVersion;
-}
-
-} // namespace net
diff --git a/chromium/net/socket/next_proto.h b/chromium/net/socket/next_proto.h
index 8b6c394e45d..d864c66f4d5 100644
--- a/chromium/net/socket/next_proto.h
+++ b/chromium/net/socket/next_proto.h
@@ -7,45 +7,21 @@
#include <vector>
-#include "net/base/net_export.h"
-
namespace net {
-// Next Protocol Negotiation (NPN), if successful, results in agreement on an
-// application-level string that specifies the application level protocol to
-// use over the TLS connection. NextProto enumerates the application level
-// protocols that we recognize. Do not change or reuse values, because they
-// are used to collect statistics on UMA. Also, values must be in [0,499),
-// because of the way TLS protocol negotiation extension information is added to
-// UMA histogram.
-const int kProtoSPDYHistogramOffset = 100;
+// This enum is used in Net.SSLNegotiatedAlpnProtocol histogram.
+// Do not change or re-use values.
enum NextProto {
kProtoUnknown = 0,
kProtoHTTP11 = 1,
- kProtoMinimumVersion = kProtoHTTP11,
-
- kProtoSPDY31 = 102,
- kProtoSPDYMinimumVersion = kProtoSPDY31,
- // kProtoHTTP2_14 = 103, // HTTP/2 draft-14
- // kProtoHTTP2_15 = 104, // HTTP/2 draft-15
- // kProtoHTTP2_16 = 105, // HTTP/2 draft-16
- // kProtoHTTP2_17 = 106, // HTTP/2 draft-17
- kProtoHTTP2 = 107, // HTTP/2, see https://tools.ietf.org/html/rfc7540.
- kProtoSPDYMaximumVersion = kProtoHTTP2,
-
- kProtoQUIC1SPDY3 = 200,
-
- kProtoMaximumVersion = kProtoQUIC1SPDY3,
+ kProtoHTTP2 = 2,
+ kProtoQUIC1SPDY3 = 3,
+ kProtoLast = kProtoQUIC1SPDY3
};
// List of protocols to use for NPN, used for configuring HttpNetworkSessions.
typedef std::vector<NextProto> NextProtoVector;
-// Convenience functions to create NextProtoVector.
-
-// Returns true if |next_proto| is a version of SPDY or HTTP/2.
-bool NextProtoIsSPDY(NextProto next_proto);
-
} // namespace net
#endif // NET_SOCKET_NEXT_PROTO_H_
diff --git a/chromium/net/socket/sequenced_socket_data_unittest.cc b/chromium/net/socket/sequenced_socket_data_unittest.cc
index e72c01c1271..ea77f0a3e00 100644
--- a/chromium/net/socket/sequenced_socket_data_unittest.cc
+++ b/chromium/net/socket/sequenced_socket_data_unittest.cc
@@ -10,13 +10,19 @@
#include "base/run_loop.h"
#include "net/base/io_buffer.h"
#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_test_util.h"
#include "net/socket/transport_client_socket_pool.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest-spi.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsError;
+using net::test::IsOk;
+
//-----------------------------------------------------------------------------
namespace net {
@@ -264,7 +270,7 @@ void SequencedSocketDataTest::Initialize(MockRead* reads,
endpoint_.ToString(), tcp_params_, LOWEST,
ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(),
reinterpret_cast<TransportClientSocketPool*>(&socket_pool_),
- BoundNetLog()));
+ NetLogWithSource()));
sock_ = connection_.socket();
}
@@ -381,7 +387,8 @@ void SequencedSocketDataTest::ReentrantAsyncWriteCallback(
EXPECT_EQ(expected_rv, rv);
scoped_refptr<IOBuffer> write_buf(new IOBuffer(len));
memcpy(write_buf->data(), data, len);
- EXPECT_EQ(ERR_IO_PENDING, sock_->Write(write_buf.get(), len, callback));
+ EXPECT_THAT(sock_->Write(write_buf.get(), len, callback),
+ IsError(ERR_IO_PENDING));
}
void SequencedSocketDataTest::FailingCompletionCallback(int rv) {
diff --git a/chromium/net/socket/socket_net_log_params.cc b/chromium/net/socket/socket_net_log_params.cc
index d53bd8a6286..ef05939dc3f 100644
--- a/chromium/net/socket/socket_net_log_params.cc
+++ b/chromium/net/socket/socket_net_log_params.cc
@@ -10,6 +10,7 @@
#include "base/values.h"
#include "net/base/host_port_pair.h"
#include "net/base/ip_endpoint.h"
+#include "net/log/net_log_capture_mode.h"
namespace net {
@@ -55,22 +56,22 @@ std::unique_ptr<base::Value> NetLogSourceAddressCallback(
} // namespace
-NetLog::ParametersCallback CreateNetLogSocketErrorCallback(int net_error,
- int os_error) {
+NetLogParametersCallback CreateNetLogSocketErrorCallback(int net_error,
+ int os_error) {
return base::Bind(&NetLogSocketErrorCallback, net_error, os_error);
}
-NetLog::ParametersCallback CreateNetLogHostPortPairCallback(
+NetLogParametersCallback CreateNetLogHostPortPairCallback(
const HostPortPair* host_and_port) {
return base::Bind(&NetLogHostPortPairCallback, host_and_port);
}
-NetLog::ParametersCallback CreateNetLogIPEndPointCallback(
+NetLogParametersCallback CreateNetLogIPEndPointCallback(
const IPEndPoint* address) {
return base::Bind(&NetLogIPEndPointCallback, address);
}
-NetLog::ParametersCallback CreateNetLogSourceAddressCallback(
+NetLogParametersCallback CreateNetLogSourceAddressCallback(
const struct sockaddr* net_address,
socklen_t address_len) {
return base::Bind(&NetLogSourceAddressCallback, net_address, address_len);
diff --git a/chromium/net/socket/socket_net_log_params.h b/chromium/net/socket/socket_net_log_params.h
index b432667d4a6..c1c2c4347cd 100644
--- a/chromium/net/socket/socket_net_log_params.h
+++ b/chromium/net/socket/socket_net_log_params.h
@@ -6,7 +6,7 @@
#define NET_SOCKET_SOCKET_NET_LOG_PARAMS_H_
#include "net/base/sys_addrinfo.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_parameters_callback.h"
namespace net {
@@ -14,22 +14,22 @@ class HostPortPair;
class IPEndPoint;
// Creates a NetLog callback for socket error events.
-NetLog::ParametersCallback CreateNetLogSocketErrorCallback(int net_error,
- int os_error);
+NetLogParametersCallback CreateNetLogSocketErrorCallback(int net_error,
+ int os_error);
// Creates a NetLog callback for a HostPortPair.
// |host_and_port| must remain valid for the lifetime of the returned callback.
-NetLog::ParametersCallback CreateNetLogHostPortPairCallback(
+NetLogParametersCallback CreateNetLogHostPortPairCallback(
const HostPortPair* host_and_port);
// Creates a NetLog callback for an IPEndPoint.
// |address| must remain valid for the lifetime of the returned callback.
-NetLog::ParametersCallback CreateNetLogIPEndPointCallback(
+NetLogParametersCallback CreateNetLogIPEndPointCallback(
const IPEndPoint* address);
// Creates a NetLog callback for the source sockaddr on connect events.
// |net_address| must remain valid for the lifetime of the returned callback.
-NetLog::ParametersCallback CreateNetLogSourceAddressCallback(
+NetLogParametersCallback CreateNetLogSourceAddressCallback(
const struct sockaddr* net_address,
socklen_t address_len);
diff --git a/chromium/net/socket/socket_posix.cc b/chromium/net/socket/socket_posix.cc
index 43742fad2e4..a86bf855b32 100644
--- a/chromium/net/socket/socket_posix.cc
+++ b/chromium/net/socket/socket_posix.cc
@@ -187,6 +187,25 @@ int SocketPosix::Connect(const SockaddrStorage& address,
return MapSystemError(errno);
}
+ // There is a race-condition in the above code if the kernel receive a RST
+ // packet for the "connect" call before the registration of the socket file
+ // descriptor to the message loop pump. On most platform it is benign as the
+ // message loop pump is awakened for that socket in an error state, but on
+ // iOS this does not happens. Check the status of the socket at this point
+ // and if in error, consider the connection as failed.
+ int os_error = 0;
+ socklen_t len = sizeof(os_error);
+ if (getsockopt(socket_fd_, SOL_SOCKET, SO_ERROR, &os_error, &len) == 0) {
+ // TCPSocketPosix expects errno to be set.
+ errno = os_error;
+ }
+
+ rv = MapConnectError(errno);
+ if (rv != OK && rv != ERR_IO_PENDING) {
+ write_socket_watcher_.StopWatchingFileDescriptor();
+ return rv;
+ }
+
write_callback_ = callback;
waiting_connect_ = true;
return ERR_IO_PENDING;
diff --git a/chromium/net/socket/socket_posix.h b/chromium/net/socket/socket_posix.h
index 956552abb89..e308f1b26ec 100644
--- a/chromium/net/socket/socket_posix.h
+++ b/chromium/net/socket/socket_posix.h
@@ -13,6 +13,7 @@
#include "base/message_loop/message_loop.h"
#include "base/threading/thread_checker.h"
#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
#include "net/socket/socket_descriptor.h"
namespace net {
diff --git a/chromium/net/socket/socket_test_util.cc b/chromium/net/socket/socket_test_util.cc
index 57cc3606c8b..15c26f8c028 100644
--- a/chromium/net/socket/socket_test_util.cc
+++ b/chromium/net/socket/socket_test_util.cc
@@ -26,6 +26,8 @@
#include "net/http/http_network_session.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
#include "net/socket/socket.h"
#include "net/socket/websocket_endpoint_lock_manager.h"
#include "net/ssl/ssl_cert_request_info.h"
@@ -282,7 +284,7 @@ void StaticSocketDataProvider::Reset() {
SSLSocketDataProvider::SSLSocketDataProvider(IoMode mode, int result)
: connect(mode, result),
- next_proto_status(SSLClientSocket::kNextProtoUnsupported),
+ next_proto(kProtoUnknown),
client_cert_sent(false),
cert_request_info(NULL),
channel_id_sent(false),
@@ -300,11 +302,6 @@ SSLSocketDataProvider::SSLSocketDataProvider(
SSLSocketDataProvider::~SSLSocketDataProvider() {
}
-void SSLSocketDataProvider::SetNextProto(NextProto proto) {
- next_proto_status = SSLClientSocket::kNextProtoNegotiated;
- next_proto = SSLClientSocket::NextProtoToString(proto);
-}
-
SequencedSocketData::SequencedSocketData(MockRead* reads,
size_t reads_count,
MockWrite* writes,
@@ -715,7 +712,7 @@ MockClientSocketFactory::CreateDatagramClientSocket(
DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
NetLog* net_log,
- const NetLog::Source& source) {
+ const NetLogSource& source) {
SocketDataProvider* data_provider = mock_data_.GetNext();
std::unique_ptr<MockUDPClientSocket> socket(
new MockUDPClientSocket(data_provider, net_log));
@@ -731,7 +728,7 @@ MockClientSocketFactory::CreateTransportClientSocket(
const AddressList& addresses,
std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
NetLog* net_log,
- const NetLog::Source& source) {
+ const NetLogSource& source) {
SocketDataProvider* data_provider = mock_data_.GetNext();
std::unique_ptr<MockTCPClientSocket> socket(
new MockTCPClientSocket(addresses, net_log, data_provider));
@@ -759,10 +756,8 @@ std::unique_ptr<SSLClientSocket> MockClientSocketFactory::CreateSSLClientSocket(
void MockClientSocketFactory::ClearSSLSessionCache() {
}
-MockClientSocket::MockClientSocket(const BoundNetLog& net_log)
- : connected_(false),
- net_log_(net_log),
- weak_factory_(this) {
+MockClientSocket::MockClientSocket(const NetLogWithSource& net_log)
+ : connected_(false), net_log_(net_log), weak_factory_(this) {
peer_addr_ = IPEndPoint(IPAddress(192, 0, 2, 33), 0);
}
@@ -798,10 +793,18 @@ int MockClientSocket::GetLocalAddress(IPEndPoint* address) const {
return OK;
}
-const BoundNetLog& MockClientSocket::NetLog() const {
+const NetLogWithSource& MockClientSocket::NetLog() const {
return net_log_;
}
+bool MockClientSocket::WasNpnNegotiated() const {
+ return false;
+}
+
+NextProto MockClientSocket::GetNegotiatedProtocol() const {
+ return kProtoUnknown;
+}
+
void MockClientSocket::GetConnectionAttempts(ConnectionAttempts* out) const {
out->clear();
}
@@ -829,8 +832,9 @@ ChannelIDService* MockClientSocket::GetChannelIDService() const {
return NULL;
}
-Error MockClientSocket::GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) {
+Error MockClientSocket::GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) {
NOTREACHED();
return ERR_NOT_IMPLEMENTED;
}
@@ -840,12 +844,6 @@ crypto::ECPrivateKey* MockClientSocket::GetChannelIDKey() const {
return NULL;
}
-SSLClientSocket::NextProtoStatus MockClientSocket::GetNextProto(
- std::string* proto) const {
- proto->clear();
- return SSLClientSocket::kNextProtoUnsupported;
-}
-
MockClientSocket::~MockClientSocket() {}
void MockClientSocket::RunCallbackAsync(const CompletionCallback& callback,
@@ -864,7 +862,7 @@ void MockClientSocket::RunCallback(const CompletionCallback& callback,
MockTCPClientSocket::MockTCPClientSocket(const AddressList& addresses,
net::NetLog* net_log,
SocketDataProvider* data)
- : MockClientSocket(BoundNetLog::Make(net_log, NetLog::SOURCE_NONE)),
+ : MockClientSocket(NetLogWithSource::Make(net_log, NetLogSourceType::NONE)),
addresses_(addresses),
data_(data),
read_offset_(0),
@@ -1029,10 +1027,6 @@ void MockTCPClientSocket::EnableTCPFastOpenIfSupported() {
data_->OnEnableTCPFastOpenIfSupported();
}
-bool MockTCPClientSocket::WasNpnNegotiated() const {
- return false;
-}
-
bool MockTCPClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
return false;
}
@@ -1140,7 +1134,8 @@ MockSSLClientSocket::MockSSLClientSocket(
const SSLConfig& ssl_config,
SSLSocketDataProvider* data)
: MockClientSocket(
- // Have to use the right BoundNetLog for LoadTimingInfo regression
+ // Have to use the right NetLogWithSource for LoadTimingInfo
+ // regression
// tests.
transport_socket->socket()->NetLog()),
transport_(std::move(transport_socket)),
@@ -1200,6 +1195,14 @@ int MockSSLClientSocket::GetPeerAddress(IPEndPoint* address) const {
return transport_->socket()->GetPeerAddress(address);
}
+bool MockSSLClientSocket::WasNpnNegotiated() const {
+ return data_->next_proto != kProtoUnknown;
+}
+
+NextProto MockSSLClientSocket::GetNegotiatedProtocol() const {
+ return data_->next_proto;
+}
+
bool MockSSLClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
ssl_info->Reset();
ssl_info->cert = data_->cert;
@@ -1223,19 +1226,13 @@ void MockSSLClientSocket::GetSSLCertRequestInfo(
}
}
-SSLClientSocket::NextProtoStatus MockSSLClientSocket::GetNextProto(
- std::string* proto) const {
- *proto = data_->next_proto;
- return data_->next_proto_status;
-}
-
ChannelIDService* MockSSLClientSocket::GetChannelIDService() const {
return data_->channel_id_service;
}
-Error MockSSLClientSocket::GetSignedEKMForTokenBinding(
- crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) {
+Error MockSSLClientSocket::GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) {
out->push_back('A');
return OK;
}
@@ -1263,7 +1260,7 @@ MockUDPClientSocket::MockUDPClientSocket(SocketDataProvider* data,
network_(NetworkChangeNotifier::kInvalidNetworkHandle),
pending_read_buf_(NULL),
pending_read_buf_len_(0),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_NONE)),
+ net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::NONE)),
weak_factory_(this) {
DCHECK(data_);
data_->Initialize(this);
@@ -1336,6 +1333,10 @@ int MockUDPClientSocket::SetSendBufferSize(int32_t size) {
return OK;
}
+int MockUDPClientSocket::SetDoNotFragment() {
+ return OK;
+}
+
void MockUDPClientSocket::Close() {
connected_ = false;
}
@@ -1350,7 +1351,9 @@ int MockUDPClientSocket::GetLocalAddress(IPEndPoint* address) const {
return OK;
}
-const BoundNetLog& MockUDPClientSocket::NetLog() const {
+void MockUDPClientSocket::UseNonBlockingIO() {}
+
+const NetLogWithSource& MockUDPClientSocket::NetLog() const {
return net_log_;
}
@@ -1625,11 +1628,11 @@ int MockTransportClientSocketPool::RequestSocket(
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
last_request_priority_ = priority;
std::unique_ptr<StreamSocket> socket =
client_socket_factory_->CreateTransportClientSocket(
- AddressList(), NULL, net_log.net_log(), NetLog::Source());
+ AddressList(), NULL, net_log.net_log(), NetLogSource());
MockConnectJob* job = new MockConnectJob(std::move(socket), handle, callback);
job_list_.push_back(base::WrapUnique(job));
handle->set_pool_id(1);
@@ -1674,7 +1677,7 @@ int MockSOCKSClientSocketPool::RequestSocket(const std::string& group_name,
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
return transport_pool_->RequestSocket(group_name, socket_params, priority,
respect_limits, handle, callback,
net_log);
diff --git a/chromium/net/socket/socket_test_util.h b/chromium/net/socket/socket_test_util.h
index de8ba34376b..4cc20d6296f 100644
--- a/chromium/net/socket/socket_test_util.h
+++ b/chromium/net/socket/socket_test_util.h
@@ -29,7 +29,7 @@
#include "net/base/test_completion_callback.h"
#include "net/http/http_auth_controller.h"
#include "net/http/http_proxy_client_socket_pool.h"
-#include "net/log/net_log.h"
+#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/connection_attempts.h"
@@ -48,6 +48,8 @@ class RunLoop;
namespace net {
+class NetLog;
+
const NetworkChangeNotifier::NetworkHandle kDefaultNetworkForTests = 1;
const NetworkChangeNotifier::NetworkHandle kNewNetworkForTests = 2;
@@ -354,11 +356,8 @@ struct SSLSocketDataProvider {
SSLSocketDataProvider(const SSLSocketDataProvider& other);
~SSLSocketDataProvider();
- void SetNextProto(NextProto proto);
-
MockConnect connect;
- SSLClientSocket::NextProtoStatus next_proto_status;
- std::string next_proto;
+ NextProto next_proto;
NextProtoVector next_protos_expected_in_ssl_config;
bool client_cert_sent;
SSLCertRequestInfo* cert_request_info;
@@ -520,12 +519,12 @@ class MockClientSocketFactory : public ClientSocketFactory {
DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
NetLog* net_log,
- const NetLog::Source& source) override;
+ const NetLogSource& source) override;
std::unique_ptr<StreamSocket> CreateTransportClientSocket(
const AddressList& addresses,
std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
NetLog* net_log,
- const NetLog::Source& source) override;
+ const NetLogSource& source) override;
std::unique_ptr<SSLClientSocket> CreateSSLClientSocket(
std::unique_ptr<ClientSocketHandle> transport_socket,
const HostPortPair& host_and_port,
@@ -547,9 +546,10 @@ class MockClientSocketFactory : public ClientSocketFactory {
class MockClientSocket : public SSLClientSocket {
public:
- // The BoundNetLog is needed to test LoadTimingInfo, which uses NetLog IDs as
+ // The NetLogWithSource is needed to test LoadTimingInfo, which uses NetLog
+ // IDs as
// unique socket IDs.
- explicit MockClientSocket(const BoundNetLog& net_log);
+ explicit MockClientSocket(const NetLogWithSource& net_log);
// Socket implementation.
int Read(IOBuffer* buf,
@@ -568,9 +568,11 @@ class MockClientSocket : public SSLClientSocket {
bool IsConnectedAndIdle() const override;
int GetPeerAddress(IPEndPoint* address) const override;
int GetLocalAddress(IPEndPoint* address) const override;
- const BoundNetLog& NetLog() const override;
+ const NetLogWithSource& NetLog() const override;
void SetSubresourceSpeculation() override {}
void SetOmniboxSpeculation() override {}
+ bool WasNpnNegotiated() const override;
+ NextProto GetNegotiatedProtocol() const override;
void GetConnectionAttempts(ConnectionAttempts* out) const override;
void ClearConnectionAttempts() override {}
void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
@@ -583,10 +585,10 @@ class MockClientSocket : public SSLClientSocket {
const base::StringPiece& context,
unsigned char* out,
unsigned int outlen) override;
- NextProtoStatus GetNextProto(std::string* proto) const override;
ChannelIDService* GetChannelIDService() const override;
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) override;
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) override;
crypto::ECPrivateKey* GetChannelIDKey() const override;
protected:
@@ -600,7 +602,7 @@ class MockClientSocket : public SSLClientSocket {
// Address of the "remote" peer we're connected to.
IPEndPoint peer_addr_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
private:
base::WeakPtrFactory<MockClientSocket> weak_factory_;
@@ -633,7 +635,6 @@ class MockTCPClientSocket : public MockClientSocket, public AsyncSocket {
int GetPeerAddress(IPEndPoint* address) const override;
bool WasEverUsed() const override;
void EnableTCPFastOpenIfSupported() override;
- bool WasNpnNegotiated() const override;
bool GetSSLInfo(SSLInfo* ssl_info) override;
void GetConnectionAttempts(ConnectionAttempts* out) const override;
void ClearConnectionAttempts() override;
@@ -696,14 +697,15 @@ class MockSSLClientSocket : public MockClientSocket, public AsyncSocket {
bool IsConnectedAndIdle() const override;
bool WasEverUsed() const override;
int GetPeerAddress(IPEndPoint* address) const override;
+ bool WasNpnNegotiated() const override;
+ NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(SSLInfo* ssl_info) override;
// SSLClientSocket implementation.
void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) override;
- NextProtoStatus GetNextProto(std::string* proto) const override;
-
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) override;
// This MockSocket does not implement the manual async IO feature.
void OnReadComplete(const MockRead& data) override;
void OnWriteComplete(int rv) override;
@@ -740,12 +742,14 @@ class MockUDPClientSocket : public DatagramClientSocket, public AsyncSocket {
const CompletionCallback& callback) override;
int SetReceiveBufferSize(int32_t size) override;
int SetSendBufferSize(int32_t size) override;
+ int SetDoNotFragment() override;
// DatagramSocket implementation.
void Close() override;
int GetPeerAddress(IPEndPoint* address) const override;
int GetLocalAddress(IPEndPoint* address) const override;
- const BoundNetLog& NetLog() const override;
+ void UseNonBlockingIO() override;
+ const NetLogWithSource& NetLog() const override;
// DatagramClientSocket implementation.
int Connect(const IPEndPoint& address) override;
@@ -788,7 +792,7 @@ class MockUDPClientSocket : public DatagramClientSocket, public AsyncSocket {
CompletionCallback pending_read_callback_;
CompletionCallback pending_write_callback_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
base::WeakPtrFactory<MockUDPClientSocket> weak_factory_;
@@ -844,7 +848,7 @@ class ClientSocketPoolTest {
requests_.push_back(base::WrapUnique(request));
int rv = request->handle()->Init(group_name, socket_params, priority,
respect_limits, request->callback(),
- socket_pool, BoundNetLog());
+ socket_pool, NetLogWithSource());
if (rv != ERR_IO_PENDING)
request_order_.push_back(request);
return rv;
@@ -933,7 +937,7 @@ class MockTransportClientSocketPool : public TransportClientSocketPool {
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void CancelRequest(const std::string& group_name,
ClientSocketHandle* handle) override;
@@ -966,7 +970,7 @@ class MockSOCKSClientSocketPool : public SOCKSClientSocketPool {
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void CancelRequest(const std::string& group_name,
ClientSocketHandle* handle) override;
diff --git a/chromium/net/socket/socks5_client_socket.cc b/chromium/net/socket/socks5_client_socket.cc
index ae362ceb4ce..9259296fa92 100644
--- a/chromium/net/socket/socks5_client_socket.cc
+++ b/chromium/net/socket/socks5_client_socket.cc
@@ -14,6 +14,7 @@
#include "base/trace_event/trace_event.h"
#include "net/base/io_buffer.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
#include "net/socket/client_socket_handle.h"
namespace net {
@@ -57,7 +58,7 @@ int SOCKS5ClientSocket::Connect(const CompletionCallback& callback) {
if (completed_handshake_)
return OK;
- net_log_.BeginEvent(NetLog::TYPE_SOCKS5_CONNECT);
+ net_log_.BeginEvent(NetLogEventType::SOCKS5_CONNECT);
next_state_ = STATE_GREET_WRITE;
buffer_.clear();
@@ -66,7 +67,7 @@ int SOCKS5ClientSocket::Connect(const CompletionCallback& callback) {
if (rv == ERR_IO_PENDING) {
user_callback_ = callback;
} else {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SOCKS5_CONNECT, rv);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::SOCKS5_CONNECT, rv);
}
return rv;
}
@@ -89,7 +90,7 @@ bool SOCKS5ClientSocket::IsConnectedAndIdle() const {
return completed_handshake_ && transport_->socket()->IsConnectedAndIdle();
}
-const BoundNetLog& SOCKS5ClientSocket::NetLog() const {
+const NetLogWithSource& SOCKS5ClientSocket::NetLog() const {
return net_log_;
}
@@ -202,7 +203,7 @@ void SOCKS5ClientSocket::OnIOComplete(int result) {
DCHECK_NE(STATE_NONE, next_state_);
int rv = DoLoop(result);
if (rv != ERR_IO_PENDING) {
- net_log_.EndEvent(NetLog::TYPE_SOCKS5_CONNECT);
+ net_log_.EndEvent(NetLogEventType::SOCKS5_CONNECT);
DoCallback(rv);
}
}
@@ -226,41 +227,43 @@ int SOCKS5ClientSocket::DoLoop(int last_io_result) {
switch (state) {
case STATE_GREET_WRITE:
DCHECK_EQ(OK, rv);
- net_log_.BeginEvent(NetLog::TYPE_SOCKS5_GREET_WRITE);
+ net_log_.BeginEvent(NetLogEventType::SOCKS5_GREET_WRITE);
rv = DoGreetWrite();
break;
case STATE_GREET_WRITE_COMPLETE:
rv = DoGreetWriteComplete(rv);
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SOCKS5_GREET_WRITE, rv);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::SOCKS5_GREET_WRITE,
+ rv);
break;
case STATE_GREET_READ:
DCHECK_EQ(OK, rv);
- net_log_.BeginEvent(NetLog::TYPE_SOCKS5_GREET_READ);
+ net_log_.BeginEvent(NetLogEventType::SOCKS5_GREET_READ);
rv = DoGreetRead();
break;
case STATE_GREET_READ_COMPLETE:
rv = DoGreetReadComplete(rv);
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SOCKS5_GREET_READ, rv);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::SOCKS5_GREET_READ,
+ rv);
break;
case STATE_HANDSHAKE_WRITE:
DCHECK_EQ(OK, rv);
- net_log_.BeginEvent(NetLog::TYPE_SOCKS5_HANDSHAKE_WRITE);
+ net_log_.BeginEvent(NetLogEventType::SOCKS5_HANDSHAKE_WRITE);
rv = DoHandshakeWrite();
break;
case STATE_HANDSHAKE_WRITE_COMPLETE:
rv = DoHandshakeWriteComplete(rv);
net_log_.EndEventWithNetErrorCode(
- NetLog::TYPE_SOCKS5_HANDSHAKE_WRITE, rv);
+ NetLogEventType::SOCKS5_HANDSHAKE_WRITE, rv);
break;
case STATE_HANDSHAKE_READ:
DCHECK_EQ(OK, rv);
- net_log_.BeginEvent(NetLog::TYPE_SOCKS5_HANDSHAKE_READ);
+ net_log_.BeginEvent(NetLogEventType::SOCKS5_HANDSHAKE_READ);
rv = DoHandshakeRead();
break;
case STATE_HANDSHAKE_READ_COMPLETE:
rv = DoHandshakeReadComplete(rv);
net_log_.EndEventWithNetErrorCode(
- NetLog::TYPE_SOCKS5_HANDSHAKE_READ, rv);
+ NetLogEventType::SOCKS5_HANDSHAKE_READ, rv);
break;
default:
NOTREACHED() << "bad state";
@@ -277,7 +280,7 @@ int SOCKS5ClientSocket::DoGreetWrite() {
// Since we only have 1 byte to send the hostname length in, if the
// URL has a hostname longer than 255 characters we can't send it.
if (0xFF < host_request_info_.hostname().size()) {
- net_log_.AddEvent(NetLog::TYPE_SOCKS_HOSTNAME_TOO_BIG);
+ net_log_.AddEvent(NetLogEventType::SOCKS_HOSTNAME_TOO_BIG);
return ERR_SOCKS_CONNECTION_FAILED;
}
@@ -324,7 +327,8 @@ int SOCKS5ClientSocket::DoGreetReadComplete(int result) {
return result;
if (result == 0) {
- net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTEDLY_CLOSED_DURING_GREETING);
+ net_log_.AddEvent(
+ NetLogEventType::SOCKS_UNEXPECTEDLY_CLOSED_DURING_GREETING);
return ERR_SOCKS_CONNECTION_FAILED;
}
@@ -337,12 +341,12 @@ int SOCKS5ClientSocket::DoGreetReadComplete(int result) {
// Got the greet data.
if (buffer_[0] != kSOCKS5Version) {
- net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTED_VERSION,
+ net_log_.AddEvent(NetLogEventType::SOCKS_UNEXPECTED_VERSION,
NetLog::IntCallback("version", buffer_[0]));
return ERR_SOCKS_CONNECTION_FAILED;
}
if (buffer_[1] != 0x00) {
- net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTED_AUTH,
+ net_log_.AddEvent(NetLogEventType::SOCKS_UNEXPECTED_AUTH,
NetLog::IntCallback("method", buffer_[1]));
return ERR_SOCKS_CONNECTION_FAILED;
}
@@ -434,7 +438,8 @@ int SOCKS5ClientSocket::DoHandshakeReadComplete(int result) {
// The underlying socket closed unexpectedly.
if (result == 0) {
- net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTEDLY_CLOSED_DURING_HANDSHAKE);
+ net_log_.AddEvent(
+ NetLogEventType::SOCKS_UNEXPECTEDLY_CLOSED_DURING_HANDSHAKE);
return ERR_SOCKS_CONNECTION_FAILED;
}
@@ -445,12 +450,12 @@ int SOCKS5ClientSocket::DoHandshakeReadComplete(int result) {
// and accordingly increase them
if (bytes_received_ == kReadHeaderSize) {
if (buffer_[0] != kSOCKS5Version || buffer_[2] != kNullByte) {
- net_log_.AddEvent(NetLog::TYPE_SOCKS_UNEXPECTED_VERSION,
+ net_log_.AddEvent(NetLogEventType::SOCKS_UNEXPECTED_VERSION,
NetLog::IntCallback("version", buffer_[0]));
return ERR_SOCKS_CONNECTION_FAILED;
}
if (buffer_[1] != 0x00) {
- net_log_.AddEvent(NetLog::TYPE_SOCKS_SERVER_ERROR,
+ net_log_.AddEvent(NetLogEventType::SOCKS_SERVER_ERROR,
NetLog::IntCallback("error_code", buffer_[1]));
return ERR_SOCKS_CONNECTION_FAILED;
}
@@ -469,7 +474,7 @@ int SOCKS5ClientSocket::DoHandshakeReadComplete(int result) {
else if (address_type == kEndPointResolvedIPv6)
read_header_size += sizeof(struct in6_addr) - 1;
else {
- net_log_.AddEvent(NetLog::TYPE_SOCKS_UNKNOWN_ADDRESS_TYPE,
+ net_log_.AddEvent(NetLogEventType::SOCKS_UNKNOWN_ADDRESS_TYPE,
NetLog::IntCallback("address_type", buffer_[3]));
return ERR_SOCKS_CONNECTION_FAILED;
}
diff --git a/chromium/net/socket/socks5_client_socket.h b/chromium/net/socket/socks5_client_socket.h
index c65ddc28f93..268fbfbd05a 100644
--- a/chromium/net/socket/socks5_client_socket.h
+++ b/chromium/net/socket/socks5_client_socket.h
@@ -16,15 +16,15 @@
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
#include "net/base/net_errors.h"
+#include "net/base/net_export.h"
#include "net/dns/host_resolver.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/stream_socket.h"
#include "url/gurl.h"
namespace net {
class ClientSocketHandle;
-class BoundNetLog;
// This StreamSocket is used to setup a SOCKSv5 handshake with a socks proxy.
// Currently no SOCKSv5 authentication is supported.
@@ -49,7 +49,7 @@ class NET_EXPORT_PRIVATE SOCKS5ClientSocket : public StreamSocket {
void Disconnect() override;
bool IsConnected() const override;
bool IsConnectedAndIdle() const override;
- const BoundNetLog& NetLog() const override;
+ const NetLogWithSource& NetLog() const override;
void SetSubresourceSpeculation() override;
void SetOmniboxSpeculation() override;
bool WasEverUsed() const override;
@@ -153,7 +153,7 @@ class NET_EXPORT_PRIVATE SOCKS5ClientSocket : public StreamSocket {
HostResolver::RequestInfo host_request_info_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
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 3c0864c75ed..272e37dfdea 100644
--- a/chromium/net/socket/socks5_client_socket_fuzzer.cc
+++ b/chromium/net/socket/socks5_client_socket_fuzzer.cc
@@ -8,8 +8,8 @@
#include <memory>
#include "base/logging.h"
+#include "base/test/fuzzed_data_provider.h"
#include "net/base/address_list.h"
-#include "net/base/fuzzed_data_provider.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/log/test_net_log.h"
@@ -26,7 +26,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Use a test NetLog, to exercise logging code.
net::TestNetLog test_net_log;
- net::FuzzedDataProvider data_provider(data, size);
+ base::FuzzedDataProvider data_provider(data, size);
net::TestCompletionCallback callback;
std::unique_ptr<net::FuzzedSocket> fuzzed_socket(
diff --git a/chromium/net/socket/socks5_client_socket_unittest.cc b/chromium/net/socket/socks5_client_socket_unittest.cc
index a32f449fac3..4cf98cffe42 100644
--- a/chromium/net/socket/socks5_client_socket_unittest.cc
+++ b/chromium/net/socket/socks5_client_socket_unittest.cc
@@ -15,20 +15,27 @@
#include "net/base/test_completion_callback.h"
#include "net/base/winsock_init.h"
#include "net/dns/mock_host_resolver.h"
-#include "net/log/net_log.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/client_socket_factory.h"
#include "net/socket/socket_test_util.h"
#include "net/socket/tcp_client_socket.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsError;
+using net::test::IsOk;
+
//-----------------------------------------------------------------------------
namespace net {
+class NetLog;
+
namespace {
// Base class to test SOCKS5ClientSocket
@@ -75,15 +82,13 @@ void SOCKS5ClientSocketTest::SetUp() {
// Resolve the "localhost" AddressList used by the TCP connection to connect.
HostResolver::RequestInfo info(HostPortPair("www.socks-proxy.com", 1080));
TestCompletionCallback callback;
- int rv = host_resolver_->Resolve(info,
- DEFAULT_PRIORITY,
- &address_list_,
- callback.callback(),
- NULL,
- BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ std::unique_ptr<HostResolver::Request> request;
+ int rv = host_resolver_->Resolve(info, DEFAULT_PRIORITY, &address_list_,
+ callback.callback(), &request,
+ NetLogWithSource());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
}
std::unique_ptr<SOCKS5ClientSocket> SOCKS5ClientSocketTest::BuildMockSocket(
@@ -100,9 +105,9 @@ std::unique_ptr<SOCKS5ClientSocket> SOCKS5ClientSocketTest::BuildMockSocket(
tcp_sock_ = new MockTCPClientSocket(address_list_, net_log, data_.get());
int rv = tcp_sock_->Connect(callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(tcp_sock_->IsConnected());
std::unique_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
@@ -148,35 +153,35 @@ TEST_F(SOCKS5ClientSocketTest, CompleteHandshake) {
EXPECT_FALSE(user_sock_->IsConnected());
int rv = user_sock_->Connect(callback_.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(user_sock_->IsConnected());
TestNetLogEntry::List net_log_entries;
net_log_.GetEntries(&net_log_entries);
EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
- NetLog::TYPE_SOCKS5_CONNECT));
+ NetLogEventType::SOCKS5_CONNECT));
rv = callback_.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(user_sock_->IsConnected());
net_log_.GetEntries(&net_log_entries);
EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
- NetLog::TYPE_SOCKS5_CONNECT));
+ NetLogEventType::SOCKS5_CONNECT));
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());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback_.WaitForResult();
EXPECT_EQ(static_cast<int>(payload_write.size()), rv);
buffer = new IOBuffer(payload_read.size());
rv =
user_sock_->Read(buffer.get(), payload_read.size(), callback_.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback_.WaitForResult();
EXPECT_EQ(static_cast<int>(payload_read.size()), rv);
EXPECT_EQ(payload_read, std::string(buffer->data(), payload_read.size()));
@@ -216,7 +221,7 @@ TEST_F(SOCKS5ClientSocketTest, ConnectAndDisconnectTwice) {
hostname, 80, NULL);
int rv = user_sock_->Connect(callback_.callback());
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(user_sock_->IsConnected());
user_sock_->Disconnect();
@@ -241,7 +246,7 @@ TEST_F(SOCKS5ClientSocketTest, LargeHostNameFails) {
// the transport socket first) because the hostname is too long.
TestCompletionCallback callback;
int rv = user_sock_->Connect(callback.callback());
- EXPECT_EQ(ERR_SOCKS_CONNECTION_FAILED, rv);
+ EXPECT_THAT(rv, IsError(ERR_SOCKS_CONNECTION_FAILED));
}
TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) {
@@ -273,20 +278,20 @@ TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) {
data_writes, arraysize(data_writes),
hostname, 80, &net_log_);
int rv = user_sock_->Connect(callback_.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestNetLogEntry::List net_log_entries;
net_log_.GetEntries(&net_log_entries);
EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
- NetLog::TYPE_SOCKS5_CONNECT));
+ NetLogEventType::SOCKS5_CONNECT));
rv = callback_.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(user_sock_->IsConnected());
net_log_.GetEntries(&net_log_entries);
EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
- NetLog::TYPE_SOCKS5_CONNECT));
+ NetLogEventType::SOCKS5_CONNECT));
}
// Test for partial greet response read
@@ -304,18 +309,18 @@ TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) {
data_writes, arraysize(data_writes),
hostname, 80, &net_log_);
int rv = user_sock_->Connect(callback_.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestNetLogEntry::List net_log_entries;
net_log_.GetEntries(&net_log_entries);
EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
- NetLog::TYPE_SOCKS5_CONNECT));
+ NetLogEventType::SOCKS5_CONNECT));
rv = callback_.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(user_sock_->IsConnected());
net_log_.GetEntries(&net_log_entries);
EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
- NetLog::TYPE_SOCKS5_CONNECT));
+ NetLogEventType::SOCKS5_CONNECT));
}
// Test for partial handshake request write.
@@ -334,17 +339,17 @@ TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) {
data_writes, arraysize(data_writes),
hostname, 80, &net_log_);
int rv = user_sock_->Connect(callback_.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestNetLogEntry::List net_log_entries;
net_log_.GetEntries(&net_log_entries);
EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
- NetLog::TYPE_SOCKS5_CONNECT));
+ NetLogEventType::SOCKS5_CONNECT));
rv = callback_.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(user_sock_->IsConnected());
net_log_.GetEntries(&net_log_entries);
EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
- NetLog::TYPE_SOCKS5_CONNECT));
+ NetLogEventType::SOCKS5_CONNECT));
}
// Test for partial handshake response read
@@ -365,17 +370,17 @@ TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) {
data_writes, arraysize(data_writes),
hostname, 80, &net_log_);
int rv = user_sock_->Connect(callback_.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestNetLogEntry::List net_log_entries;
net_log_.GetEntries(&net_log_entries);
EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
- NetLog::TYPE_SOCKS5_CONNECT));
+ NetLogEventType::SOCKS5_CONNECT));
rv = callback_.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(user_sock_->IsConnected());
net_log_.GetEntries(&net_log_entries);
EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
- NetLog::TYPE_SOCKS5_CONNECT));
+ NetLogEventType::SOCKS5_CONNECT));
}
}
diff --git a/chromium/net/socket/socks_client_socket.cc b/chromium/net/socket/socks_client_socket.cc
index b5d5ce02e10..8cbd379ef7b 100644
--- a/chromium/net/socket/socks_client_socket.cc
+++ b/chromium/net/socket/socks_client_socket.cc
@@ -12,6 +12,7 @@
#include "base/sys_byteorder.h"
#include "net/base/io_buffer.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
#include "net/socket/client_socket_handle.h"
namespace net {
@@ -88,20 +89,20 @@ int SOCKSClientSocket::Connect(const CompletionCallback& callback) {
next_state_ = STATE_RESOLVE_HOST;
- net_log_.BeginEvent(NetLog::TYPE_SOCKS_CONNECT);
+ net_log_.BeginEvent(NetLogEventType::SOCKS_CONNECT);
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING) {
user_callback_ = callback;
} else {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SOCKS_CONNECT, rv);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::SOCKS_CONNECT, rv);
}
return rv;
}
void SOCKSClientSocket::Disconnect() {
completed_handshake_ = false;
- host_resolver_.Cancel();
+ request_.reset();
transport_->socket()->Disconnect();
// Reset other states to make sure they aren't mistakenly used later.
@@ -118,7 +119,7 @@ bool SOCKSClientSocket::IsConnectedAndIdle() const {
return completed_handshake_ && transport_->socket()->IsConnectedAndIdle();
}
-const BoundNetLog& SOCKSClientSocket::NetLog() const {
+const NetLogWithSource& SOCKSClientSocket::NetLog() const {
return net_log_;
}
@@ -232,7 +233,7 @@ void SOCKSClientSocket::OnIOComplete(int result) {
DCHECK_NE(STATE_NONE, next_state_);
int rv = DoLoop(result);
if (rv != ERR_IO_PENDING) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SOCKS_CONNECT, rv);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::SOCKS_CONNECT, rv);
DoCallback(rv);
}
}
@@ -289,12 +290,10 @@ int SOCKSClientSocket::DoResolveHost() {
// SOCKS4 only supports IPv4 addresses, so only try getting the IPv4
// addresses for the target host.
host_request_info_.set_address_family(ADDRESS_FAMILY_IPV4);
- return host_resolver_.Resolve(
- host_request_info_,
- priority_,
- &addresses_,
+ return host_resolver_->Resolve(
+ host_request_info_, priority_, &addresses_,
base::Bind(&SOCKSClientSocket::OnIOComplete, base::Unretained(this)),
- net_log_);
+ &request_, net_log_);
}
int SOCKSClientSocket::DoResolveHostComplete(int result) {
diff --git a/chromium/net/socket/socks_client_socket.h b/chromium/net/socket/socks_client_socket.h
index d6702631c99..0f6d189cc43 100644
--- a/chromium/net/socket/socks_client_socket.h
+++ b/chromium/net/socket/socks_client_socket.h
@@ -17,15 +17,14 @@
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
#include "net/base/net_errors.h"
+#include "net/base/net_export.h"
#include "net/dns/host_resolver.h"
-#include "net/dns/single_request_host_resolver.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/stream_socket.h"
namespace net {
class ClientSocketHandle;
-class BoundNetLog;
// The SOCKS client socket implementation
class NET_EXPORT_PRIVATE SOCKSClientSocket : public StreamSocket {
@@ -47,7 +46,7 @@ class NET_EXPORT_PRIVATE SOCKSClientSocket : public StreamSocket {
void Disconnect() override;
bool IsConnected() const override;
bool IsConnectedAndIdle() const override;
- const BoundNetLog& NetLog() const override;
+ const NetLogWithSource& NetLog() const override;
void SetSubresourceSpeculation() override;
void SetOmniboxSpeculation() override;
bool WasEverUsed() const override;
@@ -131,12 +130,13 @@ class NET_EXPORT_PRIVATE SOCKSClientSocket : public StreamSocket {
bool was_ever_used_;
// Used to resolve the hostname to which the SOCKS proxy will connect.
- SingleRequestHostResolver host_resolver_;
+ HostResolver* host_resolver_;
+ std::unique_ptr<HostResolver::Request> request_;
AddressList addresses_;
HostResolver::RequestInfo host_request_info_;
RequestPriority priority_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
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 dc8f7f2f09f..dd02f51fe67 100644
--- a/chromium/net/socket/socks_client_socket_fuzzer.cc
+++ b/chromium/net/socket/socks_client_socket_fuzzer.cc
@@ -8,8 +8,8 @@
#include <memory>
#include "base/logging.h"
+#include "base/test/fuzzed_data_provider.h"
#include "net/base/address_list.h"
-#include "net/base/fuzzed_data_provider.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/dns/host_resolver.h"
@@ -27,7 +27,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Use a test NetLog, to exercise logging code.
net::TestNetLog test_net_log;
- net::FuzzedDataProvider data_provider(data, size);
+ base::FuzzedDataProvider data_provider(data, size);
// Determine if the DNS lookup returns synchronously or asynchronously,
// succeeds or fails, and returns an IPv4 or IPv6 address.
diff --git a/chromium/net/socket/socks_client_socket_pool.cc b/chromium/net/socket/socks_client_socket_pool.cc
index 4fae68cad4a..0e2464d7944 100644
--- a/chromium/net/socket/socks_client_socket_pool.cc
+++ b/chromium/net/socket/socks_client_socket_pool.cc
@@ -11,6 +11,8 @@
#include "base/time/time.h"
#include "base/values.h"
#include "net/base/net_errors.h"
+#include "net/log/net_log_source_type.h"
+#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/client_socket_pool_base.h"
@@ -20,6 +22,8 @@
namespace net {
+class NetLog;
+
SOCKSSocketParams::SOCKSSocketParams(
const scoped_refptr<TransportSocketParams>& proxy_server,
bool socks_v5,
@@ -45,12 +49,13 @@ SOCKSConnectJob::SOCKSConnectJob(
HostResolver* host_resolver,
Delegate* delegate,
NetLog* net_log)
- : ConnectJob(group_name,
- timeout_duration,
- priority,
- respect_limits,
- delegate,
- BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
+ : ConnectJob(
+ group_name,
+ timeout_duration,
+ priority,
+ respect_limits,
+ delegate,
+ NetLogWithSource::Make(net_log, NetLogSourceType::CONNECT_JOB)),
socks_params_(socks_params),
transport_pool_(transport_pool),
resolver_(host_resolver),
@@ -213,7 +218,7 @@ int SOCKSClientSocketPool::RequestSocket(const std::string& group_name,
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
const scoped_refptr<SOCKSSocketParams>* casted_socket_params =
static_cast<const scoped_refptr<SOCKSSocketParams>*>(socket_params);
@@ -221,11 +226,10 @@ int SOCKSClientSocketPool::RequestSocket(const std::string& group_name,
respect_limits, handle, callback, net_log);
}
-void SOCKSClientSocketPool::RequestSockets(
- const std::string& group_name,
- const void* params,
- int num_sockets,
- const BoundNetLog& net_log) {
+void SOCKSClientSocketPool::RequestSockets(const std::string& group_name,
+ const void* params,
+ int num_sockets,
+ const NetLogWithSource& net_log) {
const scoped_refptr<SOCKSSocketParams>* casted_params =
static_cast<const scoped_refptr<SOCKSSocketParams>*>(params);
diff --git a/chromium/net/socket/socks_client_socket_pool.h b/chromium/net/socket/socks_client_socket_pool.h
index b1371bba143..6d47ab4726d 100644
--- a/chromium/net/socket/socks_client_socket_pool.h
+++ b/chromium/net/socket/socks_client_socket_pool.h
@@ -13,6 +13,7 @@
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "net/base/host_port_pair.h"
+#include "net/base/net_export.h"
#include "net/dns/host_resolver.h"
#include "net/socket/client_socket_pool.h"
#include "net/socket/client_socket_pool_base.h"
@@ -124,12 +125,12 @@ class NET_EXPORT_PRIVATE SOCKSClientSocketPool
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void RequestSockets(const std::string& group_name,
const void* params,
int num_sockets,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void CancelRequest(const std::string& group_name,
ClientSocketHandle* handle) override;
diff --git a/chromium/net/socket/socks_client_socket_pool_unittest.cc b/chromium/net/socket/socks_client_socket_pool_unittest.cc
index 2434574a439..5331739b007 100644
--- a/chromium/net/socket/socks_client_socket_pool_unittest.cc
+++ b/chromium/net/socket/socks_client_socket_pool_unittest.cc
@@ -13,11 +13,18 @@
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/dns/mock_host_resolver.h"
+#include "net/log/net_log_source.h"
+#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_test_util.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -32,7 +39,7 @@ void TestLoadTimingInfo(const ClientSocketHandle& handle) {
EXPECT_TRUE(handle.GetLoadTimingInfo(false, &load_timing_info));
// None of these tests use a NetLog.
- EXPECT_EQ(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_EQ(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
EXPECT_FALSE(load_timing_info.socket_reused);
@@ -132,8 +139,8 @@ TEST_F(SOCKSClientSocketPoolTest, Simple) {
ClientSocketHandle handle;
int rv = handle.Init("a", CreateSOCKSv5Params(), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- CompletionCallback(), &pool_, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ CompletionCallback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfo(handle);
@@ -150,9 +157,10 @@ TEST_F(SOCKSClientSocketPoolTest, SetSocketRequestPriorityOnInit) {
data.data_provider());
ClientSocketHandle handle;
- EXPECT_EQ(OK, handle.Init("a", CreateSOCKSv5Params(), priority,
- ClientSocketPool::RespectLimits::ENABLED,
- CompletionCallback(), &pool_, BoundNetLog()));
+ EXPECT_EQ(OK,
+ handle.Init("a", CreateSOCKSv5Params(), priority,
+ ClientSocketPool::RespectLimits::ENABLED,
+ CompletionCallback(), &pool_, NetLogWithSource()));
EXPECT_EQ(priority, transport_socket_pool_.last_request_priority());
handle.socket()->Disconnect();
}
@@ -172,7 +180,7 @@ TEST_F(SOCKSClientSocketPoolTest, SetResolvePriorityOnInit) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", CreateSOCKSv4Params(), priority,
ClientSocketPool::RespectLimits::ENABLED,
- CompletionCallback(), &pool_, BoundNetLog()));
+ CompletionCallback(), &pool_, NetLogWithSource()));
EXPECT_EQ(priority, transport_socket_pool_.last_request_priority());
EXPECT_EQ(priority, host_resolver_.last_request_priority());
EXPECT_TRUE(handle.socket() == NULL);
@@ -187,12 +195,12 @@ TEST_F(SOCKSClientSocketPoolTest, Async) {
ClientSocketHandle handle;
int rv = handle.Init("a", CreateSOCKSv5Params(), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfo(handle);
@@ -207,8 +215,8 @@ TEST_F(SOCKSClientSocketPoolTest, TransportConnectError) {
ClientSocketHandle handle;
int rv = handle.Init("a", CreateSOCKSv5Params(), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- CompletionCallback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, rv);
+ CompletionCallback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_PROXY_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
}
@@ -222,12 +230,12 @@ TEST_F(SOCKSClientSocketPoolTest, AsyncTransportConnectError) {
ClientSocketHandle handle;
int rv = handle.Init("a", CreateSOCKSv5Params(), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_PROXY_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
}
@@ -245,8 +253,8 @@ TEST_F(SOCKSClientSocketPoolTest, SOCKSConnectError) {
EXPECT_EQ(0, transport_socket_pool_.release_count());
int rv = handle.Init("a", CreateSOCKSv5Params(), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- CompletionCallback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_SOCKS_CONNECTION_FAILED, rv);
+ CompletionCallback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_SOCKS_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_EQ(1, transport_socket_pool_.release_count());
@@ -266,12 +274,12 @@ TEST_F(SOCKSClientSocketPoolTest, AsyncSOCKSConnectError) {
EXPECT_EQ(0, transport_socket_pool_.release_count());
int rv = handle.Init("a", CreateSOCKSv5Params(), LOW,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(ERR_SOCKS_CONNECTION_FAILED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_SOCKS_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_EQ(1, transport_socket_pool_.release_count());
@@ -287,10 +295,10 @@ TEST_F(SOCKSClientSocketPoolTest, CancelDuringTransportConnect) {
EXPECT_EQ(0, transport_socket_pool_.cancel_count());
int rv = StartRequestV5("a", LOW);
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = StartRequestV5("a", LOW);
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
pool_.CancelRequest("a", (*requests())[0]->handle());
pool_.CancelRequest("a", (*requests())[1]->handle());
@@ -322,10 +330,10 @@ TEST_F(SOCKSClientSocketPoolTest, CancelDuringSOCKSConnect) {
EXPECT_EQ(0, transport_socket_pool_.cancel_count());
EXPECT_EQ(0, transport_socket_pool_.release_count());
int rv = StartRequestV5("a", LOW);
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = StartRequestV5("a", LOW);
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
pool_.CancelRequest("a", (*requests())[0]->handle());
pool_.CancelRequest("a", (*requests())[1]->handle());
diff --git a/chromium/net/socket/socks_client_socket_unittest.cc b/chromium/net/socket/socks_client_socket_unittest.cc
index 764c71bcf33..63183845e69 100644
--- a/chromium/net/socket/socks_client_socket_unittest.cc
+++ b/chromium/net/socket/socks_client_socket_unittest.cc
@@ -13,20 +13,27 @@
#include "net/base/winsock_init.h"
#include "net/dns/host_resolver.h"
#include "net/dns/mock_host_resolver.h"
-#include "net/log/net_log.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/client_socket_factory.h"
#include "net/socket/socket_test_util.h"
#include "net/socket/tcp_client_socket.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsError;
+using net::test::IsOk;
+
//-----------------------------------------------------------------------------
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 };
@@ -80,9 +87,9 @@ std::unique_ptr<SOCKSClientSocket> SOCKSClientSocketTest::BuildMockSocket(
tcp_sock_ = new MockTCPClientSocket(address_list_, net_log, data_.get());
int rv = tcp_sock_->Connect(callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(tcp_sock_->IsConnected());
std::unique_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
@@ -106,35 +113,48 @@ class HangingHostResolverWithCancel : public HostResolver {
RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) override {
+ std::unique_ptr<Request>* out_req,
+ const NetLogWithSource& net_log) override {
DCHECK(addresses);
DCHECK_EQ(false, callback.is_null());
EXPECT_FALSE(HasOutstandingRequest());
- outstanding_request_ = reinterpret_cast<RequestHandle>(1);
- *out_req = outstanding_request_;
+ outstanding_request_ = new RequestImpl(this);
+ out_req->reset(outstanding_request_);
return ERR_IO_PENDING;
}
int ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
NOTIMPLEMENTED();
return ERR_UNEXPECTED;
}
- void CancelRequest(RequestHandle req) override {
+ void RemoveRequest(Request* req) {
EXPECT_TRUE(HasOutstandingRequest());
EXPECT_EQ(outstanding_request_, req);
- outstanding_request_ = NULL;
+ outstanding_request_ = nullptr;
}
- bool HasOutstandingRequest() {
- return outstanding_request_ != NULL;
- }
+ bool HasOutstandingRequest() { return outstanding_request_ != nullptr; }
private:
- RequestHandle outstanding_request_;
+ class RequestImpl : public HostResolver::Request {
+ public:
+ RequestImpl(HangingHostResolverWithCancel* resolver)
+ : resolver_(resolver) {}
+ ~RequestImpl() override {
+ DCHECK(resolver_);
+ resolver_->RemoveRequest(this);
+ }
+
+ void ChangeRequestPriority(RequestPriority priority) override {}
+
+ private:
+ HangingHostResolverWithCancel* resolver_;
+ };
+
+ Request* outstanding_request_;
DISALLOW_COPY_AND_ASSIGN(HangingHostResolverWithCancel);
};
@@ -163,33 +183,32 @@ TEST_F(SOCKSClientSocketTest, CompleteHandshake) {
EXPECT_FALSE(user_sock_->IsConnected());
int rv = user_sock_->Connect(callback_.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestNetLogEntry::List entries;
log.GetEntries(&entries);
EXPECT_TRUE(
- LogContainsBeginEvent(entries, 0, NetLog::TYPE_SOCKS_CONNECT));
+ LogContainsBeginEvent(entries, 0, NetLogEventType::SOCKS_CONNECT));
EXPECT_FALSE(user_sock_->IsConnected());
rv = callback_.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(user_sock_->IsConnected());
log.GetEntries(&entries);
- EXPECT_TRUE(LogContainsEndEvent(
- entries, -1, NetLog::TYPE_SOCKS_CONNECT));
+ EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLogEventType::SOCKS_CONNECT));
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());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback_.WaitForResult();
EXPECT_EQ(static_cast<int>(payload_write.size()), rv);
buffer = new IOBuffer(payload_read.size());
rv =
user_sock_->Read(buffer.get(), payload_read.size(), callback_.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback_.WaitForResult();
EXPECT_EQ(static_cast<int>(payload_read.size()), rv);
EXPECT_EQ(payload_read, std::string(buffer->data(), payload_read.size()));
@@ -235,20 +254,20 @@ TEST_F(SOCKSClientSocketTest, HandshakeFailures) {
&log);
int rv = user_sock_->Connect(callback_.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestNetLogEntry::List entries;
log.GetEntries(&entries);
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_SOCKS_CONNECT));
+ EXPECT_TRUE(
+ LogContainsBeginEvent(entries, 0, NetLogEventType::SOCKS_CONNECT));
rv = callback_.WaitForResult();
EXPECT_EQ(tests[i].fail_code, rv);
EXPECT_FALSE(user_sock_->IsConnected());
EXPECT_TRUE(tcp_sock_->IsConnected());
log.GetEntries(&entries);
- EXPECT_TRUE(LogContainsEndEvent(
- entries, -1, NetLog::TYPE_SOCKS_CONNECT));
+ EXPECT_TRUE(
+ LogContainsEndEvent(entries, -1, NetLogEventType::SOCKS_CONNECT));
}
}
@@ -272,18 +291,17 @@ TEST_F(SOCKSClientSocketTest, PartialServerReads) {
&log);
int rv = user_sock_->Connect(callback_.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestNetLogEntry::List entries;
log.GetEntries(&entries);
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_SOCKS_CONNECT));
+ EXPECT_TRUE(
+ LogContainsBeginEvent(entries, 0, NetLogEventType::SOCKS_CONNECT));
rv = callback_.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(user_sock_->IsConnected());
log.GetEntries(&entries);
- EXPECT_TRUE(LogContainsEndEvent(
- entries, -1, NetLog::TYPE_SOCKS_CONNECT));
+ EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLogEventType::SOCKS_CONNECT));
}
// Tests scenario when the client sends the handshake request in
@@ -310,18 +328,17 @@ TEST_F(SOCKSClientSocketTest, PartialClientWrites) {
&log);
int rv = user_sock_->Connect(callback_.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestNetLogEntry::List entries;
log.GetEntries(&entries);
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_SOCKS_CONNECT));
+ EXPECT_TRUE(
+ LogContainsBeginEvent(entries, 0, NetLogEventType::SOCKS_CONNECT));
rv = callback_.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(user_sock_->IsConnected());
log.GetEntries(&entries);
- EXPECT_TRUE(LogContainsEndEvent(
- entries, -1, NetLog::TYPE_SOCKS_CONNECT));
+ EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLogEventType::SOCKS_CONNECT));
}
// Tests the case when the server sends a smaller sized handshake data
@@ -342,18 +359,17 @@ TEST_F(SOCKSClientSocketTest, FailedSocketRead) {
&log);
int rv = user_sock_->Connect(callback_.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestNetLogEntry::List entries;
log.GetEntries(&entries);
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_SOCKS_CONNECT));
+ EXPECT_TRUE(
+ LogContainsBeginEvent(entries, 0, NetLogEventType::SOCKS_CONNECT));
rv = callback_.WaitForResult();
- EXPECT_EQ(ERR_CONNECTION_CLOSED, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_CLOSED));
EXPECT_FALSE(user_sock_->IsConnected());
log.GetEntries(&entries);
- EXPECT_TRUE(LogContainsEndEvent(
- entries, -1, NetLog::TYPE_SOCKS_CONNECT));
+ EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLogEventType::SOCKS_CONNECT));
}
// Tries to connect to an unknown hostname. Should fail rather than
@@ -372,18 +388,17 @@ TEST_F(SOCKSClientSocketTest, FailedDNS) {
&log);
int rv = user_sock_->Connect(callback_.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TestNetLogEntry::List entries;
log.GetEntries(&entries);
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_SOCKS_CONNECT));
+ EXPECT_TRUE(
+ LogContainsBeginEvent(entries, 0, NetLogEventType::SOCKS_CONNECT));
rv = callback_.WaitForResult();
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
+ EXPECT_THAT(rv, IsError(ERR_NAME_NOT_RESOLVED));
EXPECT_FALSE(user_sock_->IsConnected());
log.GetEntries(&entries);
- EXPECT_TRUE(LogContainsEndEvent(
- entries, -1, NetLog::TYPE_SOCKS_CONNECT));
+ EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLogEventType::SOCKS_CONNECT));
}
// Calls Disconnect() while a host resolve is in progress. The outstanding host
@@ -404,7 +419,7 @@ TEST_F(SOCKSClientSocketTest, DisconnectWhileHostResolveInProgress) {
// Start connecting (will get stuck waiting for the host to resolve).
int rv = user_sock_->Connect(callback_.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(user_sock_->IsConnected());
EXPECT_FALSE(user_sock_->IsConnectedAndIdle());
diff --git a/chromium/net/socket/ssl_client_socket.cc b/chromium/net/socket/ssl_client_socket.cc
index 3c3858e3ae3..52146afabd1 100644
--- a/chromium/net/socket/ssl_client_socket.cc
+++ b/chromium/net/socket/ssl_client_socket.cc
@@ -4,9 +4,11 @@
#include "net/socket/ssl_client_socket.h"
+#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/strings/string_util.h"
+#include "build/build_config.h"
#include "crypto/ec_private_key.h"
#include "net/base/net_errors.h"
#include "net/socket/ssl_client_socket_impl.h"
@@ -15,19 +17,21 @@
namespace net {
+namespace {
+#if !defined(OS_NACL)
+const base::Feature kPostQuantumExperiment{"SSLPostQuantumExperiment",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+} // namespace
+
SSLClientSocket::SSLClientSocket()
: signed_cert_timestamps_received_(false),
- stapled_ocsp_response_received_(false),
- negotiation_extension_(kExtensionUnknown) {
-}
+ stapled_ocsp_response_received_(false) {}
// static
-NextProto SSLClientSocket::NextProtoFromString(
- const std::string& proto_string) {
+NextProto SSLClientSocket::NextProtoFromString(base::StringPiece proto_string) {
if (proto_string == "http1.1" || proto_string == "http/1.1") {
return kProtoHTTP11;
- } else if (proto_string == "spdy/3.1") {
- return kProtoSPDY31;
} else if (proto_string == "h2") {
return kProtoHTTP2;
} else if (proto_string == "quic/1+spdy/3") {
@@ -42,8 +46,6 @@ const char* SSLClientSocket::NextProtoToString(NextProto next_proto) {
switch (next_proto) {
case kProtoHTTP11:
return "http/1.1";
- case kProtoSPDY31:
- return "spdy/3.1";
case kProtoHTTP2:
return "h2";
case kProtoQUIC1SPDY3:
@@ -55,20 +57,6 @@ const char* SSLClientSocket::NextProtoToString(NextProto next_proto) {
}
// static
-const char* SSLClientSocket::NextProtoStatusToString(
- const SSLClientSocket::NextProtoStatus status) {
- switch (status) {
- case kNextProtoUnsupported:
- return "unsupported";
- case kNextProtoNegotiated:
- return "negotiated";
- case kNextProtoNoOverlap:
- return "no-overlap";
- }
- return NULL;
-}
-
-// static
void SSLClientSocket::SetSSLKeyLogFile(
const base::FilePath& path,
const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
@@ -79,18 +67,6 @@ void SSLClientSocket::SetSSLKeyLogFile(
#endif
}
-bool SSLClientSocket::WasNpnNegotiated() const {
- std::string unused_proto;
- return GetNextProto(&unused_proto) == kNextProtoNegotiated;
-}
-
-NextProto SSLClientSocket::GetNegotiatedProtocol() const {
- std::string proto;
- if (GetNextProto(&proto) != kNextProtoNegotiated)
- return kProtoUnknown;
- return NextProtoFromString(proto);
-}
-
bool SSLClientSocket::IgnoreCertError(int error, int load_flags) {
if (error == OK)
return true;
@@ -98,65 +74,13 @@ bool SSLClientSocket::IgnoreCertError(int error, int load_flags) {
IsCertificateError(error);
}
-void SSLClientSocket::RecordNegotiationExtension() {
- if (negotiation_extension_ == kExtensionUnknown)
- return;
- std::string proto;
- SSLClientSocket::NextProtoStatus status = GetNextProto(&proto);
- if (status == kNextProtoUnsupported)
- return;
- // Convert protocol into numerical value for histogram.
- NextProto protocol_negotiated = SSLClientSocket::NextProtoFromString(proto);
- base::HistogramBase::Sample sample =
- static_cast<base::HistogramBase::Sample>(protocol_negotiated);
- // In addition to the protocol negotiated, we want to record which TLS
- // extension was used, and in case of NPN, whether there was overlap between
- // server and client list of supported protocols.
- if (negotiation_extension_ == kExtensionNPN) {
- if (status == kNextProtoNoOverlap) {
- sample += 1000;
- } else {
- sample += 500;
- }
- } else {
- DCHECK_EQ(kExtensionALPN, negotiation_extension_);
- }
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLProtocolNegotiation", sample);
-}
-
-// static
-void SSLClientSocket::RecordChannelIDSupport(
- ChannelIDService* channel_id_service,
- bool negotiated_channel_id,
- bool channel_id_enabled) {
- // Since this enum is used for a histogram, do not change or re-use values.
- enum {
- DISABLED = 0,
- CLIENT_ONLY = 1,
- CLIENT_AND_SERVER = 2,
- // CLIENT_NO_ECC is unused now.
- // CLIENT_BAD_SYSTEM_TIME is unused now.
- CLIENT_BAD_SYSTEM_TIME = 4,
- CLIENT_NO_CHANNEL_ID_SERVICE = 5,
- CHANNEL_ID_USAGE_MAX
- } supported = DISABLED;
- if (negotiated_channel_id) {
- supported = CLIENT_AND_SERVER;
- } else if (channel_id_enabled) {
- if (!channel_id_service)
- supported = CLIENT_NO_CHANNEL_ID_SERVICE;
- else
- supported = CLIENT_ONLY;
- }
- UMA_HISTOGRAM_ENUMERATION("DomainBoundCerts.Support", supported,
- CHANNEL_ID_USAGE_MAX);
-}
-
// static
-bool SSLClientSocket::IsChannelIDEnabled(
- const SSLConfig& ssl_config,
- ChannelIDService* channel_id_service) {
- return ssl_config.channel_id_enabled && channel_id_service;
+bool SSLClientSocket::IsPostQuantumExperimentEnabled() {
+#if !defined(OS_NACL)
+ return base::FeatureList::IsEnabled(kPostQuantumExperiment);
+#else
+ return false;
+#endif
}
// static
@@ -166,11 +90,11 @@ std::vector<uint8_t> SSLClientSocket::SerializeNextProtos(
for (const NextProto next_proto : next_protos) {
const std::string proto = NextProtoToString(next_proto);
if (proto.size() > 255) {
- LOG(WARNING) << "Ignoring overlong NPN/ALPN protocol: " << proto;
+ LOG(WARNING) << "Ignoring overlong ALPN protocol: " << proto;
continue;
}
if (proto.size() == 0) {
- LOG(WARNING) << "Ignoring empty NPN/ALPN protocol";
+ LOG(WARNING) << "Ignoring empty ALPN protocol";
continue;
}
wire_protos.push_back(proto.size());
diff --git a/chromium/net/socket/ssl_client_socket.h b/chromium/net/socket/ssl_client_socket.h
index 494c6cbf4a6..0249e8466eb 100644
--- a/chromium/net/socket/ssl_client_socket.h
+++ b/chromium/net/socket/ssl_client_socket.h
@@ -10,11 +10,14 @@
#include <string>
#include "base/gtest_prod_util.h"
+#include "base/strings/string_piece.h"
#include "net/base/completion_callback.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
+#include "net/base/net_export.h"
#include "net/socket/ssl_socket.h"
#include "net/socket/stream_socket.h"
+#include "net/ssl/token_binding.h"
namespace base {
class FilePath;
@@ -75,49 +78,15 @@ class NET_EXPORT SSLClientSocket : public SSLSocket {
public:
SSLClientSocket();
- // Next Protocol Negotiation (NPN) allows a TLS client and server to come to
- // an agreement about the application level protocol to speak over a
- // connection.
- enum NextProtoStatus {
- // WARNING: These values are serialized to disk. Don't change them.
-
- kNextProtoUnsupported = 0, // The server doesn't support NPN.
- kNextProtoNegotiated = 1, // We agreed on a protocol.
- kNextProtoNoOverlap = 2, // No protocols in common. We requested
- // the first protocol in our list.
- };
-
- // TLS extension used to negotiate protocol.
- enum SSLNegotiationExtension {
- kExtensionUnknown,
- kExtensionALPN,
- kExtensionNPN,
- };
-
- // StreamSocket:
- bool WasNpnNegotiated() const override;
- NextProto GetNegotiatedProtocol() const override;
-
// Gets the SSL CertificateRequest info of the socket after Connect failed
// with ERR_SSL_CLIENT_AUTH_CERT_NEEDED.
virtual void GetSSLCertRequestInfo(
SSLCertRequestInfo* cert_request_info) = 0;
- // Get the application level protocol that we negotiated with the server.
- // *proto is set to the resulting protocol (n.b. that the string may have
- // embedded NULs).
- // kNextProtoUnsupported: *proto is cleared.
- // kNextProtoNegotiated: *proto is set to the negotiated protocol.
- // kNextProtoNoOverlap: *proto is set to the first protocol in the
- // supported list.
- virtual NextProtoStatus GetNextProto(std::string* proto) const = 0;
-
- static NextProto NextProtoFromString(const std::string& proto_string);
+ static NextProto NextProtoFromString(base::StringPiece proto_string);
static const char* NextProtoToString(NextProto next_proto);
- static const char* NextProtoStatusToString(const NextProtoStatus status);
-
// Log SSL key material to |path| on |task_runner|. Must be called before any
// SSLClientSockets are created.
//
@@ -141,22 +110,24 @@ class NET_EXPORT SSLClientSocket : public SSLSocket {
// channel ids are not supported.
virtual ChannelIDService* GetChannelIDService() const = 0;
- // Signs the EKM value for Token Binding with |*key| and puts it in |*out|.
- // Returns a net error code.
- virtual Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) = 0;
+ // Generates the signature used in Token Binding using key |*key| and for a
+ // Token Binding of type |tb_type|, putting the signature in |*out|. Returns a
+ // net error code.
+ virtual Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) = 0;
// This method is only for debugging crbug.com/548423 and will be removed when
// that bug is closed. This returns the channel ID key that was used when
// establishing the connection (or NULL if no channel ID was used).
virtual crypto::ECPrivateKey* GetChannelIDKey() const = 0;
- protected:
- void set_negotiation_extension(
- SSLNegotiationExtension negotiation_extension) {
- negotiation_extension_ = negotiation_extension;
- }
+ // Returns true if the CECPQ1 (experimental post-quantum) experiment is
+ // enabled. This should be removed after the experiment is ended, around
+ // 2017-18.
+ static bool IsPostQuantumExperimentEnabled();
+ protected:
void set_signed_cert_timestamps_received(
bool signed_cert_timestamps_received) {
signed_cert_timestamps_received_ = signed_cert_timestamps_received;
@@ -166,21 +137,6 @@ class NET_EXPORT SSLClientSocket : public SSLSocket {
stapled_ocsp_response_received_ = stapled_ocsp_response_received;
}
- // Record which TLS extension was used to negotiate protocol and protocol
- // chosen in a UMA histogram.
- void RecordNegotiationExtension();
-
- // Records histograms for channel id support during full handshakes - resumed
- // handshakes are ignored.
- static void RecordChannelIDSupport(ChannelIDService* channel_id_service,
- bool negotiated_channel_id,
- bool channel_id_enabled);
-
- // Returns whether TLS channel ID is enabled.
- static bool IsChannelIDEnabled(
- const SSLConfig& ssl_config,
- ChannelIDService* channel_id_service);
-
// Serialize |next_protos| in the wire format for ALPN and NPN: protocols are
// listed in order, each prefixed by a one-byte length.
static std::vector<uint8_t> SerializeNextProtos(
@@ -202,8 +158,6 @@ class NET_EXPORT SSLClientSocket : public SSLSocket {
bool signed_cert_timestamps_received_;
// True if a stapled OCSP response was received.
bool stapled_ocsp_response_received_;
- // Protocol negotiation extension used.
- SSLNegotiationExtension negotiation_extension_;
};
} // namespace net
diff --git a/chromium/net/socket/ssl_client_socket_impl.cc b/chromium/net/socket/ssl_client_socket_impl.cc
index d1edfbb5e5f..8d435163449 100644
--- a/chromium/net/socket/ssl_client_socket_impl.cc
+++ b/chromium/net/socket/ssl_client_socket_impl.cc
@@ -17,10 +17,10 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
-#include "base/feature_list.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
+#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/profiler/scoped_tracker.h"
@@ -44,6 +44,9 @@
#include "net/cert/x509_certificate_net_log_param.h"
#include "net/cert/x509_util_openssl.h"
#include "net/http/transport_security_state.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_parameters_callback.h"
#include "net/ssl/scoped_openssl_types.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/ssl/ssl_cipher_suite_names.h"
@@ -69,26 +72,17 @@ namespace {
// overlap with any value of the net::Error range, including net::OK).
const int kNoPendingResult = 1;
-// If a client doesn't have a list of protocols that it supports, but
-// the server supports NPN, choosing "http/1.1" is the best answer.
-const char kDefaultSupportedNPNProtocol[] = "http/1.1";
-
// Default size of the internal BoringSSL buffers.
-const int KDefaultOpenSSLBufferSize = 17 * 1024;
+const int kDefaultOpenSSLBufferSize = 17 * 1024;
// TLS extension number use for Token Binding.
const unsigned int kTbExtNum = 24;
// Token Binding ProtocolVersions supported.
const uint8_t kTbProtocolVersionMajor = 0;
-const uint8_t kTbProtocolVersionMinor = 6;
+const uint8_t kTbProtocolVersionMinor = 10;
const uint8_t kTbMinProtocolVersionMajor = 0;
-const uint8_t kTbMinProtocolVersionMinor = 6;
-
-#if !defined(OS_NACL)
-const base::Feature kPostQuantumExperiment{"SSLPostQuantumExperiment",
- base::FEATURE_DISABLED_BY_DEFAULT};
-#endif
+const uint8_t kTbMinProtocolVersionMinor = 10;
bool EVP_MDToPrivateKeyHash(const EVP_MD* md, SSLPrivateKey::Hash* hash) {
switch (EVP_MD_type(md)) {
@@ -197,9 +191,8 @@ std::unique_ptr<base::Value> NetLogSSLInfoCallback(
dict->SetInteger("cipher_suite", SSLConnectionStatusToCipherSuite(
ssl_info.connection_status));
- std::string next_proto;
- socket->GetNextProto(&next_proto);
- dict->SetString("next_proto", next_proto);
+ dict->SetString("next_proto", SSLClientSocket::NextProtoToString(
+ socket->GetNegotiatedProtocol()));
return std::move(dict);
}
@@ -253,10 +246,6 @@ class SSLClientSocketImpl::SSLContext {
// is currently not sent on the network.
// TODO(haavardm): Remove setting quiet shutdown once 118366 is fixed.
SSL_CTX_set_quiet_shutdown(ssl_ctx_.get(), 1);
- // Note that SSL_OP_DISABLE_NPN is used to disable NPN if
- // ssl_config_.next_proto is empty.
- SSL_CTX_set_next_proto_select_cb(ssl_ctx_.get(), SelectNextProtoCallback,
- NULL);
// Disable the internal session cache. Session caching is handled
// externally (i.e. by SSLClientSessionCache).
@@ -264,6 +253,8 @@ class SSLClientSocketImpl::SSLContext {
ssl_ctx_.get(), SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL);
SSL_CTX_sess_set_new_cb(ssl_ctx_.get(), NewSessionCallback);
+ SSL_CTX_set_grease_enabled(ssl_ctx_.get(), 1);
+
if (!SSL_CTX_add_client_custom_ext(ssl_ctx_.get(), kTbExtNum,
&TokenBindingAddCallback,
&TokenBindingFreeCallback, nullptr,
@@ -321,16 +312,6 @@ class SSLClientSocketImpl::SSLContext {
return socket->CertVerifyCallback(store_ctx);
}
- static int SelectNextProtoCallback(SSL* ssl,
- unsigned char** out,
- unsigned char* outlen,
- const unsigned char* in,
- unsigned int inlen,
- void* arg) {
- SSLClientSocketImpl* socket = GetInstance()->GetClientSocketFromSSL(ssl);
- return socket->SelectNextProtoCallback(out, outlen, in, inlen);
- }
-
static int NewSessionCallback(SSL* ssl, SSL_SESSION* session) {
SSLClientSocketImpl* socket = GetInstance()->GetClientSocketFromSSL(ssl);
return socket->NewSessionCallback(session);
@@ -346,25 +327,25 @@ class SSLClientSocketImpl::SSLContext {
return socket->PrivateKeyMaxSignatureLenCallback();
}
- static ssl_private_key_result_t PrivateKeySignCallback(SSL* ssl,
- uint8_t* out,
- size_t* out_len,
- size_t max_out,
- const EVP_MD* md,
- const uint8_t* in,
- size_t in_len) {
- SSLClientSocketImpl* socket = GetInstance()->GetClientSocketFromSSL(ssl);
- return socket->PrivateKeySignCallback(out, out_len, max_out, md, in,
- in_len);
- }
-
- static ssl_private_key_result_t PrivateKeySignCompleteCallback(
+ static ssl_private_key_result_t PrivateKeySignDigestCallback(
SSL* ssl,
uint8_t* out,
size_t* out_len,
- size_t max_out) {
+ size_t max_out,
+ const EVP_MD* md,
+ const uint8_t* in,
+ size_t in_len) {
+ SSLClientSocketImpl* socket = GetInstance()->GetClientSocketFromSSL(ssl);
+ return socket->PrivateKeySignDigestCallback(out, out_len, max_out, md, in,
+ in_len);
+ }
+
+ static ssl_private_key_result_t PrivateKeyCompleteCallback(SSL* ssl,
+ uint8_t* out,
+ size_t* out_len,
+ size_t max_out) {
SSLClientSocketImpl* socket = GetInstance()->GetClientSocketFromSSL(ssl);
- return socket->PrivateKeySignCompleteCallback(out, out_len, max_out);
+ return socket->PrivateKeyCompleteCallback(out, out_len, max_out);
}
#if !defined(OS_NACL)
@@ -391,12 +372,15 @@ class SSLClientSocketImpl::SSLContext {
SSLClientSessionCache session_cache_;
};
+// TODO(davidben): Switch from sign_digest to sign.
const SSL_PRIVATE_KEY_METHOD
SSLClientSocketImpl::SSLContext::kPrivateKeyMethod = {
&SSLClientSocketImpl::SSLContext::PrivateKeyTypeCallback,
&SSLClientSocketImpl::SSLContext::PrivateKeyMaxSignatureLenCallback,
- &SSLClientSocketImpl::SSLContext::PrivateKeySignCallback,
- &SSLClientSocketImpl::SSLContext::PrivateKeySignCompleteCallback,
+ nullptr /* sign */,
+ &SSLClientSocketImpl::SSLContext::PrivateKeySignDigestCallback,
+ nullptr /* decrypt */,
+ &SSLClientSocketImpl::SSLContext::PrivateKeyCompleteCallback,
};
// PeerCertificateChain is a helper object which extracts the certificate
@@ -452,29 +436,33 @@ void SSLClientSocketImpl::PeerCertificateChain::Reset(STACK_OF(X509) * chain) {
scoped_refptr<X509Certificate>
SSLClientSocketImpl::PeerCertificateChain::AsOSChain() const {
-#if defined(USE_OPENSSL_CERTS)
- // When OSCertHandle is typedef'ed to X509, this implementation does a short
- // cut to avoid converting back and forth between DER and the X509 struct.
- X509Certificate::OSCertHandles intermediates;
- for (size_t i = 1; i < sk_X509_num(openssl_chain_.get()); ++i) {
- intermediates.push_back(sk_X509_value(openssl_chain_.get(), i));
- }
-
- return X509Certificate::CreateFromHandle(
- sk_X509_value(openssl_chain_.get(), 0), intermediates);
-#else
// DER-encode the chain and convert to a platform certificate handle.
- std::vector<base::StringPiece> der_chain;
+ std::vector<std::string> chain;
+ chain.reserve(sk_X509_num(openssl_chain_.get()));
for (size_t i = 0; i < sk_X509_num(openssl_chain_.get()); ++i) {
X509* x = sk_X509_value(openssl_chain_.get(), i);
- base::StringPiece der;
- if (!x509_util::GetDER(x, &der))
- return NULL;
- der_chain.push_back(der);
+ // Note: This intentionally avoids using x509_util::GetDER(), which may
+ // cache the encoded DER on |x|, as |x| is shared with the underlying
+ // socket (SSL*) this chain belongs to. As the DER will only be used
+ // once in //net, within this code, this avoids needlessly caching
+ // additional data. See https://crbug.com/642082
+ int len = i2d_X509(x, nullptr);
+ if (len < 0)
+ return nullptr;
+ std::string cert;
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(base::WriteInto(&cert, len + 1));
+ len = i2d_X509(x, &ptr);
+ if (len < 0) {
+ NOTREACHED();
+ return nullptr;
+ }
+ chain.push_back(std::move(cert));
}
+ std::vector<base::StringPiece> stringpiece_chain;
+ for (const auto& cert : chain)
+ stringpiece_chain.push_back(cert);
- return X509Certificate::CreateFromDERCertChain(der_chain);
-#endif
+ return X509Certificate::CreateFromDERCertChain(stringpiece_chain);
}
// static
@@ -503,7 +491,7 @@ SSLClientSocketImpl::SSLClientSocketImpl(
channel_id_service_(context.channel_id_service),
tb_was_negotiated_(false),
tb_negotiated_param_(TB_PARAM_ECDSAP256),
- tb_signed_ekm_map_(10),
+ tb_signature_map_(10),
ssl_(NULL),
transport_bio_(NULL),
transport_(std::move(transport_socket)),
@@ -512,10 +500,10 @@ SSLClientSocketImpl::SSLClientSocketImpl(
ssl_session_cache_shard_(context.ssl_session_cache_shard),
next_handshake_state_(STATE_NONE),
disconnected_(false),
- npn_status_(kNextProtoUnsupported),
+ negotiated_protocol_(kProtoUnknown),
channel_id_sent_(false),
- session_pending_(false),
certificate_verified_(false),
+ certificate_requested_(false),
signature_result_(kNoPendingResult),
transport_security_state_(context.transport_security_state),
policy_enforcer_(context.ct_policy_enforcer),
@@ -547,26 +535,20 @@ void SSLClientSocketImpl::GetSSLCertRequestInfo(
cert_request_info->cert_key_types = cert_key_types_;
}
-SSLClientSocket::NextProtoStatus SSLClientSocketImpl::GetNextProto(
- std::string* proto) const {
- *proto = npn_proto_;
- return npn_status_;
-}
-
ChannelIDService* SSLClientSocketImpl::GetChannelIDService() const {
return channel_id_service_;
}
-Error SSLClientSocketImpl::GetSignedEKMForTokenBinding(
- crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) {
+Error SSLClientSocketImpl::GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) {
// The same key will be used across multiple requests to sign the same value,
// so the signature is cached.
std::string raw_public_key;
if (!key->ExportRawPublicKey(&raw_public_key))
return ERR_FAILED;
- SignedEkmMap::iterator it = tb_signed_ekm_map_.Get(raw_public_key);
- if (it != tb_signed_ekm_map_.end()) {
+ auto it = tb_signature_map_.Get(std::make_pair(tb_type, raw_public_key));
+ if (it != tb_signature_map_.end()) {
*out = it->second;
return OK;
}
@@ -580,13 +562,13 @@ Error SSLClientSocketImpl::GetSignedEKMForTokenBinding(
return ERR_FAILED;
}
- if (!SignTokenBindingEkm(
+ if (!CreateTokenBindingSignature(
base::StringPiece(reinterpret_cast<char*>(tb_ekm_buf),
sizeof(tb_ekm_buf)),
- key, out))
+ tb_type, key, out))
return ERR_FAILED;
- tb_signed_ekm_map_.Put(raw_public_key, *out);
+ tb_signature_map_.Put(std::make_pair(tb_type, raw_public_key), *out);
return OK;
}
@@ -604,17 +586,14 @@ int SSLClientSocketImpl::ExportKeyingMaterial(const base::StringPiece& label,
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- int rv = SSL_export_keying_material(
- ssl_, out, outlen, label.data(), label.size(),
- reinterpret_cast<const unsigned char*>(context.data()), context.length(),
- has_context ? 1 : 0);
-
- if (rv != 1) {
- int ssl_error = SSL_get_error(ssl_, rv);
- LOG(ERROR) << "Failed to export keying material;"
- << " returned " << rv << ", SSL error code " << ssl_error;
- return MapOpenSSLError(ssl_error, err_tracer);
+ if (!SSL_export_keying_material(
+ ssl_, out, outlen, label.data(), label.size(),
+ reinterpret_cast<const unsigned char*>(context.data()),
+ context.length(), has_context ? 1 : 0)) {
+ LOG(ERROR) << "Failed to export keying material.";
+ return ERR_FAILED;
}
+
return OK;
}
@@ -627,7 +606,7 @@ int SSLClientSocketImpl::Connect(const CompletionCallback& callback) {
// https://crbug.com/499289.
CHECK(!disconnected_);
- net_log_.BeginEvent(NetLog::TYPE_SSL_CONNECT);
+ net_log_.BeginEvent(NetLogEventType::SSL_CONNECT);
// Set up new ssl object.
int rv = Init();
@@ -700,13 +679,13 @@ void SSLClientSocketImpl::Disconnect() {
start_cert_verification_time_ = base::TimeTicks();
- npn_status_ = kNextProtoUnsupported;
- npn_proto_.clear();
+ negotiated_protocol_ = kProtoUnknown;
channel_id_sent_ = false;
tb_was_negotiated_ = false;
- session_pending_ = false;
+ pending_session_ = nullptr;
certificate_verified_ = false;
+ certificate_requested_ = false;
channel_id_request_.Cancel();
signature_result_ = kNoPendingResult;
@@ -753,7 +732,7 @@ int SSLClientSocketImpl::GetLocalAddress(IPEndPoint* addressList) const {
return transport_->socket()->GetLocalAddress(addressList);
}
-const BoundNetLog& SSLClientSocketImpl::NetLog() const {
+const NetLogWithSource& SSLClientSocketImpl::NetLog() const {
return net_log_;
}
@@ -777,6 +756,14 @@ bool SSLClientSocketImpl::WasEverUsed() const {
return was_ever_used_;
}
+bool SSLClientSocketImpl::WasNpnNegotiated() const {
+ return negotiated_protocol_ != kProtoUnknown;
+}
+
+NextProto SSLClientSocketImpl::GetNegotiatedProtocol() const {
+ return negotiated_protocol_;
+}
+
bool SSLClientSocketImpl::GetSSLInfo(SSLInfo* ssl_info) {
ssl_info->Reset();
if (server_cert_chain_->empty())
@@ -795,14 +782,15 @@ bool SSLClientSocketImpl::GetSSLInfo(SSLInfo* ssl_info) {
ssl_info->token_binding_negotiated = tb_was_negotiated_;
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;
AddCTInfoToSSLInfo(ssl_info);
const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl_);
CHECK(cipher);
ssl_info->security_bits = SSL_CIPHER_get_bits(cipher, NULL);
- ssl_info->key_exchange_info =
- SSL_SESSION_get_key_exchange_info(SSL_get_session(ssl_));
+ // Historically, the "group" was known as "curve".
+ ssl_info->key_exchange_group = SSL_get_curve_id(ssl_);
SSLConnectionStatusSetCipherSuite(
static_cast<uint16_t>(SSL_CIPHER_get_id(cipher)),
@@ -813,9 +801,6 @@ bool SSLClientSocketImpl::GetSSLInfo(SSLInfo* ssl_info) {
if (!SSL_get_secure_renegotiation_support(ssl_))
ssl_info->connection_status |= SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION;
- if (ssl_config_.version_fallback)
- ssl_info->connection_status |= SSL_CONNECTION_VERSION_FALLBACK;
-
ssl_info->handshake_type = SSL_session_reused(ssl_)
? SSLInfo::HANDSHAKE_RESUME
: SSLInfo::HANDSHAKE_FULL;
@@ -914,10 +899,35 @@ int SSLClientSocketImpl::Init() {
if (session)
SSL_set_session(ssl_, session.get());
+ // Get read and write buffer sizes from field trials, if possible. If values
+ // not present, use default. Also make sure values are in reasonable range.
+ int send_buffer_size = kDefaultOpenSSLBufferSize;
+#if !defined(OS_NACL)
+ int override_send_buffer_size;
+ if (base::StringToInt(base::FieldTrialList::FindFullName("SSLBufferSizeSend"),
+ &override_send_buffer_size)) {
+ send_buffer_size = override_send_buffer_size;
+ send_buffer_size = std::max(send_buffer_size, 1000);
+ send_buffer_size =
+ std::min(send_buffer_size, 2 * kDefaultOpenSSLBufferSize);
+ }
+#endif // !defined(OS_NACL)
send_buffer_ = new GrowableIOBuffer();
- send_buffer_->SetCapacity(KDefaultOpenSSLBufferSize);
+ send_buffer_->SetCapacity(send_buffer_size);
+
+ int recv_buffer_size = kDefaultOpenSSLBufferSize;
+#if !defined(OS_NACL)
+ int override_recv_buffer_size;
+ if (base::StringToInt(base::FieldTrialList::FindFullName("SSLBufferSizeRecv"),
+ &override_recv_buffer_size)) {
+ recv_buffer_size = override_recv_buffer_size;
+ recv_buffer_size = std::max(recv_buffer_size, 1000);
+ recv_buffer_size =
+ std::min(recv_buffer_size, 2 * kDefaultOpenSSLBufferSize);
+ }
+#endif // !defined(OS_NACL)
recv_buffer_ = new GrowableIOBuffer();
- recv_buffer_->SetCapacity(KDefaultOpenSSLBufferSize);
+ recv_buffer_->SetCapacity(recv_buffer_size);
BIO* ssl_bio = NULL;
@@ -939,8 +949,10 @@ int SSLClientSocketImpl::Init() {
DCHECK_LT(SSL3_VERSION, ssl_config_.version_min);
DCHECK_LT(SSL3_VERSION, ssl_config_.version_max);
- SSL_set_min_version(ssl_, ssl_config_.version_min);
- SSL_set_max_version(ssl_, ssl_config_.version_max);
+ if (!SSL_set_min_proto_version(ssl_, ssl_config_.version_min) ||
+ !SSL_set_max_proto_version(ssl_, ssl_config_.version_max)) {
+ return ERR_UNEXPECTED;
+ }
// OpenSSL defaults some options to on, others to off. To avoid ambiguity,
// set everything we care about to an absolute value.
@@ -962,8 +974,6 @@ int SSLClientSocketImpl::Init() {
mode.ConfigureFlag(SSL_MODE_ENABLE_FALSE_START,
ssl_config_.false_start_enabled);
- mode.ConfigureFlag(SSL_MODE_SEND_FALLBACK_SCSV, ssl_config_.version_fallback);
-
SSL_set_mode(ssl_, mode.set_mask);
SSL_clear_mode(ssl_, mode.clear_mask);
@@ -973,8 +983,7 @@ int SSLClientSocketImpl::Init() {
// supported. As DHE is being deprecated, don't add a cipher only to remove it
// immediately.
std::string command;
-#if !defined(OS_NACL)
- if (base::FeatureList::IsEnabled(kPostQuantumExperiment)) {
+ if (SSLClientSocket::IsPostQuantumExperimentEnabled()) {
// These are experimental, non-standard ciphersuites. They are part of an
// experiment in post-quantum cryptography. They're not intended to
// represent a de-facto standard, and will be removed from BoringSSL in
@@ -993,7 +1002,6 @@ int SSLClientSocketImpl::Init() {
"CECPQ1-ECDSA-AES256-GCM-SHA384:");
}
}
-#endif
command.append("ALL:!SHA256:!SHA384:!DHE-RSA-AES256-GCM-SHA384:!aPSK:!RC4");
if (ssl_config_.require_ecdhe)
@@ -1022,7 +1030,7 @@ int SSLClientSocketImpl::Init() {
<< rv;
// TLS channel ids.
- if (IsChannelIDEnabled(ssl_config_, channel_id_service_)) {
+ if (IsChannelIDEnabled()) {
SSL_enable_tls_channel_id(ssl_);
}
@@ -1033,9 +1041,6 @@ int SSLClientSocketImpl::Init() {
wire_protos.size());
}
- if (ssl_config_.npn_protos.empty())
- SSL_set_options(ssl_, SSL_OP_DISABLE_NPN);
-
if (ssl_config_.signed_cert_timestamps_enabled) {
SSL_enable_signed_cert_timestamps(ssl_);
SSL_enable_ocsp_stapling(ssl_);
@@ -1131,7 +1136,7 @@ int SSLClientSocketImpl::DoHandshake() {
}
OpenSSLErrorInfo error_info;
- net_error = MapOpenSSLErrorWithDetails(ssl_error, err_tracer, &error_info);
+ net_error = MapLastOpenSSLError(ssl_error, err_tracer, &error_info);
if (net_error == ERR_IO_PENDING) {
// If not done, stay in this state
next_handshake_state_ = STATE_HANDSHAKE;
@@ -1141,7 +1146,7 @@ int SSLClientSocketImpl::DoHandshake() {
LOG(ERROR) << "handshake failed; returned " << rv << ", SSL error code "
<< ssl_error << ", net_error " << net_error;
net_log_.AddEvent(
- NetLog::TYPE_SSL_HANDSHAKE_ERROR,
+ NetLogEventType::SSL_HANDSHAKE_ERROR,
CreateNetLogOpenSSLErrorCallback(net_error, ssl_error, error_info));
}
@@ -1153,11 +1158,6 @@ int SSLClientSocketImpl::DoHandshakeComplete(int result) {
if (result < 0)
return result;
- if (ssl_config_.version_fallback &&
- ssl_config_.version_max < ssl_config_.version_fallback_min) {
- return ERR_SSL_FALLBACK_BEYOND_MINIMUM_VERSION;
- }
-
// DHE is offered on the deprecated cipher fallback and then rejected
// afterwards. This is to aid in diagnosing connection failures because a
// server requires DHE ciphers.
@@ -1169,36 +1169,35 @@ int SSLClientSocketImpl::DoHandshakeComplete(int result) {
}
// Check that if token binding was negotiated, then extended master secret
- // must also be negotiated.
- if (tb_was_negotiated_ && !SSL_get_extms_support(ssl_))
+ // and renegotiation indication must also be negotiated.
+ if (tb_was_negotiated_ &&
+ !(SSL_get_extms_support(ssl_) &&
+ SSL_get_secure_renegotiation_support(ssl_))) {
return ERR_SSL_PROTOCOL_ERROR;
-
- // SSL handshake is completed. If NPN wasn't negotiated, see if ALPN was.
- if (npn_status_ == kNextProtoUnsupported) {
- const uint8_t* alpn_proto = NULL;
- unsigned alpn_len = 0;
- SSL_get0_alpn_selected(ssl_, &alpn_proto, &alpn_len);
- if (alpn_len > 0) {
- npn_proto_.assign(reinterpret_cast<const char*>(alpn_proto), alpn_len);
- npn_status_ = kNextProtoNegotiated;
- set_negotiation_extension(kExtensionALPN);
- }
}
- RecordNegotiationExtension();
- RecordChannelIDSupport(channel_id_service_, channel_id_sent_,
- ssl_config_.channel_id_enabled);
+ const uint8_t* alpn_proto = NULL;
+ unsigned alpn_len = 0;
+ SSL_get0_alpn_selected(ssl_, &alpn_proto, &alpn_len);
+ if (alpn_len > 0) {
+ base::StringPiece proto(reinterpret_cast<const char*>(alpn_proto),
+ alpn_len);
+ negotiated_protocol_ = NextProtoFromString(proto);
+ }
- // Only record OCSP histograms if OCSP was requested.
- if (ssl_config_.signed_cert_timestamps_enabled ||
- cert_verifier_->SupportsOCSPStapling()) {
- const uint8_t* ocsp_response;
- size_t ocsp_response_len;
- SSL_get0_ocsp_response(ssl_, &ocsp_response, &ocsp_response_len);
+ RecordNegotiatedProtocol();
+ RecordChannelIDSupport();
- set_stapled_ocsp_response_received(ocsp_response_len != 0);
- UMA_HISTOGRAM_BOOLEAN("Net.OCSPResponseStapled", ocsp_response_len != 0);
+ const uint8_t* ocsp_response_raw;
+ size_t ocsp_response_len;
+ SSL_get0_ocsp_response(ssl_, &ocsp_response_raw, &ocsp_response_len);
+ std::string ocsp_response;
+ if (ocsp_response_len > 0) {
+ ocsp_response_.assign(reinterpret_cast<const char*>(ocsp_response_raw),
+ ocsp_response_len);
}
+ set_stapled_ocsp_response_received(ocsp_response_len != 0);
+ UMA_HISTOGRAM_BOOLEAN("Net.OCSPResponseStapled", ocsp_response_len != 0);
const uint8_t* sct_list;
size_t sct_list_len;
@@ -1208,10 +1207,10 @@ int SSLClientSocketImpl::DoHandshakeComplete(int result) {
if (IsRenegotiationAllowed())
SSL_set_renegotiate_mode(ssl_, ssl_renegotiate_freely);
- uint8_t server_key_exchange_hash = SSL_get_server_key_exchange_hash(ssl_);
- if (server_key_exchange_hash != TLSEXT_hash_none) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLServerKeyExchangeHash",
- server_key_exchange_hash);
+ uint16_t signature_algorithm = SSL_get_peer_signature_algorithm(ssl_);
+ if (signature_algorithm != 0) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLSignatureAlgorithm",
+ signature_algorithm);
}
// Verify the certificate.
@@ -1221,9 +1220,9 @@ int SSLClientSocketImpl::DoHandshakeComplete(int result) {
}
int SSLClientSocketImpl::DoChannelIDLookup() {
- NetLog::ParametersCallback callback = base::Bind(
+ NetLogParametersCallback callback = base::Bind(
&NetLogChannelIDLookupCallback, base::Unretained(channel_id_service_));
- net_log_.BeginEvent(NetLog::TYPE_SSL_GET_CHANNEL_ID, callback);
+ net_log_.BeginEvent(NetLogEventType::SSL_GET_CHANNEL_ID, callback);
next_handshake_state_ = STATE_CHANNEL_ID_LOOKUP_COMPLETE;
return channel_id_service_->GetOrCreateChannelID(
host_and_port_.host(), &channel_id_key_,
@@ -1233,7 +1232,7 @@ int SSLClientSocketImpl::DoChannelIDLookup() {
}
int SSLClientSocketImpl::DoChannelIDLookupComplete(int result) {
- net_log_.EndEvent(NetLog::TYPE_SSL_GET_CHANNEL_ID,
+ net_log_.EndEvent(NetLogEventType::SSL_GET_CHANNEL_ID,
base::Bind(&NetLogChannelIDLookupCompleteCallback,
channel_id_key_.get(), result));
if (result < 0)
@@ -1243,11 +1242,9 @@ int SSLClientSocketImpl::DoChannelIDLookupComplete(int result) {
// type.
DCHECK(channel_id_key_);
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- int rv = SSL_set1_tls_channel_id(ssl_, channel_id_key_->key());
- if (!rv) {
+ if (!SSL_set1_tls_channel_id(ssl_, channel_id_key_->key())) {
LOG(ERROR) << "Failed to set Channel ID.";
- int err = SSL_get_error(ssl_, rv);
- return MapOpenSSLError(err, err_tracer);
+ return ERR_FAILED;
}
// Return to the handshake.
@@ -1265,39 +1262,25 @@ int SSLClientSocketImpl::DoVerifyCert(int result) {
// OpenSSL decoded the certificate, but the platform certificate
// implementation could not. This is treated as a fatal SSL-level protocol
// error rather than a certificate error. See https://crbug.com/91341.
- if (!server_cert_.get())
+ if (!server_cert_)
return ERR_SSL_SERVER_CERT_BAD_FORMAT;
// If the certificate is bad and has been previously accepted, use
// the previous status and bypass the error.
- base::StringPiece der_cert;
- if (!x509_util::GetDER(server_cert_chain_->Get(0), &der_cert)) {
- NOTREACHED();
- return ERR_CERT_INVALID;
- }
CertStatus cert_status;
- if (ssl_config_.IsAllowedBadCert(der_cert, &cert_status)) {
+ if (ssl_config_.IsAllowedBadCert(server_cert_.get(), &cert_status)) {
server_cert_verify_result_.Reset();
server_cert_verify_result_.cert_status = cert_status;
server_cert_verify_result_.verified_cert = server_cert_;
return OK;
}
- std::string ocsp_response;
- if (cert_verifier_->SupportsOCSPStapling()) {
- const uint8_t* ocsp_response_raw;
- size_t ocsp_response_len;
- SSL_get0_ocsp_response(ssl_, &ocsp_response_raw, &ocsp_response_len);
- ocsp_response.assign(reinterpret_cast<const char*>(ocsp_response_raw),
- ocsp_response_len);
- }
-
start_cert_verification_time_ = base::TimeTicks::Now();
return cert_verifier_->Verify(
CertVerifier::RequestParams(server_cert_, host_and_port_.host(),
ssl_config_.GetCertVerifyFlags(),
- ocsp_response, CertificateList()),
+ ocsp_response_, CertificateList()),
// TODO(davidben): Route the CRLSet through SSLConfig so
// SSLClientSocket doesn't depend on SSLConfigService.
SSLConfigService::GetCRLSet().get(), &server_cert_verify_result_,
@@ -1352,6 +1335,11 @@ int SSLClientSocketImpl::DoVerifyCertComplete(int result) {
DCHECK(!certificate_verified_);
certificate_verified_ = true;
MaybeCacheSession();
+ SSLInfo ssl_info;
+ bool ok = GetSSLInfo(&ssl_info);
+ DCHECK(ok);
+ transport_security_state_->CheckExpectStaple(host_and_port_, ssl_info,
+ ocsp_response_);
}
completed_connect_ = true;
@@ -1372,7 +1360,7 @@ void SSLClientSocketImpl::UpdateServerCert() {
server_cert_chain_->Reset(SSL_get_peer_cert_chain(ssl_));
server_cert_ = server_cert_chain_->AsOSChain();
if (server_cert_.get()) {
- net_log_.AddEvent(NetLog::TYPE_SSL_CERTIFICATES_RECEIVED,
+ net_log_.AddEvent(NetLogEventType::SSL_CERTIFICATES_RECEIVED,
base::Bind(&NetLogX509CertificateCallback,
base::Unretained(server_cert_.get())));
}
@@ -1499,11 +1487,11 @@ int SSLClientSocketImpl::DoPayloadRead() {
rv = pending_read_error_;
pending_read_error_ = kNoPendingResult;
if (rv == 0) {
- net_log_.AddByteTransferEvent(NetLog::TYPE_SSL_SOCKET_BYTES_RECEIVED, rv,
- user_read_buf_->data());
+ net_log_.AddByteTransferEvent(NetLogEventType::SSL_SOCKET_BYTES_RECEIVED,
+ rv, user_read_buf_->data());
} else {
net_log_.AddEvent(
- NetLog::TYPE_SSL_READ_ERROR,
+ NetLogEventType::SSL_READ_ERROR,
CreateNetLogOpenSSLErrorCallback(rv, pending_read_ssl_error_,
pending_read_error_info_));
}
@@ -1545,7 +1533,7 @@ int SSLClientSocketImpl::DoPayloadRead() {
DCHECK_NE(kNoPendingResult, signature_result_);
pending_read_error_ = ERR_IO_PENDING;
} else {
- pending_read_error_ = MapOpenSSLErrorWithDetails(
+ pending_read_error_ = MapLastOpenSSLError(
pending_read_ssl_error_, err_tracer, &pending_read_error_info_);
}
@@ -1577,11 +1565,11 @@ int SSLClientSocketImpl::DoPayloadRead() {
}
if (rv >= 0) {
- net_log_.AddByteTransferEvent(NetLog::TYPE_SSL_SOCKET_BYTES_RECEIVED, rv,
- user_read_buf_->data());
+ net_log_.AddByteTransferEvent(NetLogEventType::SSL_SOCKET_BYTES_RECEIVED,
+ rv, user_read_buf_->data());
} else if (rv != ERR_IO_PENDING) {
net_log_.AddEvent(
- NetLog::TYPE_SSL_READ_ERROR,
+ NetLogEventType::SSL_READ_ERROR,
CreateNetLogOpenSSLErrorCallback(rv, pending_read_ssl_error_,
pending_read_error_info_));
pending_read_ssl_error_ = SSL_ERROR_NONE;
@@ -1595,7 +1583,7 @@ int SSLClientSocketImpl::DoPayloadWrite() {
int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_);
if (rv >= 0) {
- net_log_.AddByteTransferEvent(NetLog::TYPE_SSL_SOCKET_BYTES_SENT, rv,
+ net_log_.AddByteTransferEvent(NetLogEventType::SSL_SOCKET_BYTES_SENT, rv,
user_write_buf_->data());
return rv;
}
@@ -1604,12 +1592,11 @@ int SSLClientSocketImpl::DoPayloadWrite() {
if (ssl_error == SSL_ERROR_WANT_PRIVATE_KEY_OPERATION)
return ERR_IO_PENDING;
OpenSSLErrorInfo error_info;
- int net_error =
- MapOpenSSLErrorWithDetails(ssl_error, err_tracer, &error_info);
+ int net_error = MapLastOpenSSLError(ssl_error, err_tracer, &error_info);
if (net_error != ERR_IO_PENDING) {
net_log_.AddEvent(
- NetLog::TYPE_SSL_WRITE_ERROR,
+ NetLogEventType::SSL_WRITE_ERROR,
CreateNetLogOpenSSLErrorCallback(net_error, ssl_error, error_info));
}
return net_error;
@@ -1767,15 +1754,6 @@ int SSLClientSocketImpl::TransportReadComplete(int result) {
}
int SSLClientSocketImpl::VerifyCT() {
- const uint8_t* ocsp_response_raw;
- size_t ocsp_response_len;
- SSL_get0_ocsp_response(ssl_, &ocsp_response_raw, &ocsp_response_len);
- std::string ocsp_response;
- if (ocsp_response_len > 0) {
- ocsp_response.assign(reinterpret_cast<const char*>(ocsp_response_raw),
- ocsp_response_len);
- }
-
const uint8_t* sct_list_raw;
size_t sct_list_len;
SSL_get0_signed_cert_timestamp_list(ssl_, &sct_list_raw, &sct_list_len);
@@ -1787,19 +1765,23 @@ 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,
+ server_cert_verify_result_.verified_cert.get(), ocsp_response_, sct_list,
&ct_verify_result_, net_log_);
ct_verify_result_.ct_policies_applied = true;
ct_verify_result_.ev_policy_compliance =
ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY;
+
+ SCTList verified_scts =
+ ct::SCTsMatchingStatus(ct_verify_result_.scts, ct::SCT_STATUS_OK);
+
if (server_cert_verify_result_.cert_status & CERT_STATUS_IS_EV) {
scoped_refptr<ct::EVCertsWhitelist> ev_whitelist =
SSLConfigService::GetEVCertsWhitelist();
ct::EVPolicyCompliance ev_policy_compliance =
policy_enforcer_->DoesConformToCTEVPolicy(
server_cert_verify_result_.verified_cert.get(), ev_whitelist.get(),
- ct_verify_result_.verified_scts, net_log_);
+ verified_scts, net_log_);
ct_verify_result_.ev_policy_compliance = ev_policy_compliance;
if (ev_policy_compliance !=
ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY &&
@@ -1814,11 +1796,13 @@ int SSLClientSocketImpl::VerifyCT() {
}
ct_verify_result_.cert_policy_compliance =
policy_enforcer_->DoesConformToCertPolicy(
- server_cert_verify_result_.verified_cert.get(),
- ct_verify_result_.verified_scts, net_log_);
+ server_cert_verify_result_.verified_cert.get(), verified_scts,
+ net_log_);
if (ct_verify_result_.cert_policy_compliance !=
ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS &&
+ ct_verify_result_.cert_policy_compliance !=
+ ct::CertPolicyCompliance::CERT_POLICY_BUILD_NOT_TIMELY &&
transport_security_state_->ShouldRequireCT(
host_and_port_.host(), server_cert_verify_result_.verified_cert.get(),
server_cert_verify_result_.public_key_hashes)) {
@@ -1833,7 +1817,8 @@ int SSLClientSocketImpl::VerifyCT() {
int SSLClientSocketImpl::ClientCertRequestCallback(SSL* ssl) {
DCHECK(ssl == ssl_);
- net_log_.AddEvent(NetLog::TYPE_SSL_CLIENT_CERT_REQUESTED);
+ net_log_.AddEvent(NetLogEventType::SSL_CLIENT_CERT_REQUESTED);
+ certificate_requested_ = true;
// Clear any currently configured certificates.
SSL_certs_clear(ssl_);
@@ -1929,14 +1914,14 @@ int SSLClientSocketImpl::ClientCertRequestCallback(SSL* ssl) {
SSL_set_private_key_digest_prefs(ssl_, digests.data(), digests.size());
int cert_count = 1 + sk_X509_num(chain.get());
- net_log_.AddEvent(NetLog::TYPE_SSL_CLIENT_CERT_PROVIDED,
+ net_log_.AddEvent(NetLogEventType::SSL_CLIENT_CERT_PROVIDED,
NetLog::IntCallback("cert_count", cert_count));
return 1;
}
#endif // defined(OS_IOS)
// Send no client certificate.
- net_log_.AddEvent(NetLog::TYPE_SSL_CLIENT_CERT_PROVIDED,
+ net_log_.AddEvent(NetLogEventType::SSL_CLIENT_CERT_PROVIDED,
NetLog::IntCallback("cert_count", 0));
return 1;
}
@@ -1968,55 +1953,6 @@ int SSLClientSocketImpl::CertVerifyCallback(X509_STORE_CTX* store_ctx) {
return 1;
}
-// SelectNextProtoCallback is called by OpenSSL during the handshake. If the
-// server supports NPN, selects a protocol from the list that the server
-// provides. According to third_party/boringssl/src/ssl/ssl_lib.c, the
-// callback can assume that |in| is syntactically valid.
-int SSLClientSocketImpl::SelectNextProtoCallback(unsigned char** out,
- unsigned char* outlen,
- const unsigned char* in,
- unsigned int inlen) {
- if (ssl_config_.npn_protos.empty()) {
- *out = reinterpret_cast<uint8_t*>(
- const_cast<char*>(kDefaultSupportedNPNProtocol));
- *outlen = arraysize(kDefaultSupportedNPNProtocol) - 1;
- npn_status_ = kNextProtoUnsupported;
- return SSL_TLSEXT_ERR_OK;
- }
-
- // Assume there's no overlap between our protocols and the server's list.
- npn_status_ = kNextProtoNoOverlap;
-
- // For each protocol in server preference order, see if we support it.
- for (unsigned int i = 0; i < inlen; i += in[i] + 1) {
- for (NextProto next_proto : ssl_config_.npn_protos) {
- const std::string proto = NextProtoToString(next_proto);
- if (in[i] == proto.size() &&
- memcmp(&in[i + 1], proto.data(), in[i]) == 0) {
- // We found a match.
- *out = const_cast<unsigned char*>(in) + i + 1;
- *outlen = in[i];
- npn_status_ = kNextProtoNegotiated;
- break;
- }
- }
- if (npn_status_ == kNextProtoNegotiated)
- break;
- }
-
- // If we didn't find a protocol, we select the last one from our list.
- if (npn_status_ == kNextProtoNoOverlap) {
- // NextProtoToString returns a pointer to a static string.
- const char* proto = NextProtoToString(ssl_config_.npn_protos.back());
- *out = reinterpret_cast<unsigned char*>(const_cast<char*>(proto));
- *outlen = strlen(proto);
- }
-
- npn_proto_.assign(reinterpret_cast<const char*>(*out), *outlen);
- set_negotiation_extension(kExtensionNPN);
- return SSL_TLSEXT_ERR_OK;
-}
-
long SSLClientSocketImpl::MaybeReplayTransportError(BIO* bio,
int cmd,
const char* argp,
@@ -2068,25 +2004,18 @@ void SSLClientSocketImpl::MaybeCacheSession() {
// Only cache the session once both a new session has been established and the
// certificate has been verified. Due to False Start, these events may happen
// in either order.
- if (!session_pending_ || !certificate_verified_)
+ if (!pending_session_ || !certificate_verified_)
return;
SSLContext::GetInstance()->session_cache()->Insert(GetSessionCacheKey(),
- SSL_get_session(ssl_));
- session_pending_ = false;
+ pending_session_.get());
+ pending_session_ = nullptr;
}
int SSLClientSocketImpl::NewSessionCallback(SSL_SESSION* session) {
- DCHECK_EQ(session, SSL_get_session(ssl_));
-
- // Only sessions from the initial handshake get cached. Note this callback may
- // be signaled on abbreviated handshakes if the ticket was renewed.
- session_pending_ = true;
+ // OpenSSL passes a reference to |session|.
+ pending_session_.reset(session);
MaybeCacheSession();
-
- // OpenSSL passes a reference to |session|, but the session cache does not
- // take this reference, so release it.
- SSL_SESSION_free(session);
return 1;
}
@@ -2099,23 +2028,6 @@ std::string SSLClientSocketImpl::GetSessionCacheKey() const {
result.append("/");
result.append(ssl_session_cache_shard_);
- // Shard the session cache based on maximum protocol version. This causes
- // fallback connections to use a separate session cache.
- result.append("/");
- switch (ssl_config_.version_max) {
- case SSL_PROTOCOL_VERSION_TLS1:
- result.append("tls1");
- break;
- case SSL_PROTOCOL_VERSION_TLS1_1:
- result.append("tls1.1");
- break;
- case SSL_PROTOCOL_VERSION_TLS1_2:
- result.append("tls1.2");
- break;
- default:
- NOTREACHED();
- }
-
result.append("/");
if (ssl_config_.deprecated_cipher_suites_enabled)
result.append("deprecated");
@@ -2131,12 +2043,11 @@ bool SSLClientSocketImpl::IsRenegotiationAllowed() const {
if (tb_was_negotiated_)
return false;
- if (npn_status_ == kNextProtoUnsupported)
+ if (negotiated_protocol_ == kProtoUnknown)
return ssl_config_.renego_allowed_default;
- NextProto next_proto = NextProtoFromString(npn_proto_);
for (NextProto allowed : ssl_config_.renego_allowed_for_protos) {
- if (next_proto == allowed)
+ if (negotiated_protocol_ == allowed)
return true;
}
return false;
@@ -2157,7 +2068,7 @@ size_t SSLClientSocketImpl::PrivateKeyMaxSignatureLenCallback() {
return ssl_config_.client_private_key->GetMaxSignatureLengthInBytes();
}
-ssl_private_key_result_t SSLClientSocketImpl::PrivateKeySignCallback(
+ssl_private_key_result_t SSLClientSocketImpl::PrivateKeySignDigestCallback(
uint8_t* out,
size_t* out_len,
size_t max_out,
@@ -2175,19 +2086,19 @@ ssl_private_key_result_t SSLClientSocketImpl::PrivateKeySignCallback(
}
net_log_.BeginEvent(
- NetLog::TYPE_SSL_PRIVATE_KEY_OPERATION,
+ NetLogEventType::SSL_PRIVATE_KEY_OP,
base::Bind(&NetLogPrivateKeyOperationCallback,
ssl_config_.client_private_key->GetType(), hash));
signature_result_ = ERR_IO_PENDING;
ssl_config_.client_private_key->SignDigest(
hash, base::StringPiece(reinterpret_cast<const char*>(in), in_len),
- base::Bind(&SSLClientSocketImpl::OnPrivateKeySignComplete,
+ base::Bind(&SSLClientSocketImpl::OnPrivateKeyComplete,
weak_factory_.GetWeakPtr()));
return ssl_private_key_retry;
}
-ssl_private_key_result_t SSLClientSocketImpl::PrivateKeySignCompleteCallback(
+ssl_private_key_result_t SSLClientSocketImpl::PrivateKeyCompleteCallback(
uint8_t* out,
size_t* out_len,
size_t max_out) {
@@ -2210,15 +2121,14 @@ ssl_private_key_result_t SSLClientSocketImpl::PrivateKeySignCompleteCallback(
return ssl_private_key_success;
}
-void SSLClientSocketImpl::OnPrivateKeySignComplete(
+void SSLClientSocketImpl::OnPrivateKeyComplete(
Error error,
const std::vector<uint8_t>& signature) {
DCHECK_EQ(ERR_IO_PENDING, signature_result_);
DCHECK(signature_.empty());
DCHECK(ssl_config_.client_private_key);
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_PRIVATE_KEY_OPERATION,
- error);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::SSL_PRIVATE_KEY_OP, error);
signature_result_ = error;
if (signature_result_ == OK)
@@ -2315,12 +2225,77 @@ int SSLClientSocketImpl::TokenBindingParse(const uint8_t* contents,
void SSLClientSocketImpl::LogConnectEndEvent(int rv) {
if (rv != OK) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_CONNECT, rv);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::SSL_CONNECT, rv);
return;
}
- net_log_.EndEvent(NetLog::TYPE_SSL_CONNECT,
+ net_log_.EndEvent(NetLogEventType::SSL_CONNECT,
base::Bind(&NetLogSSLInfoCallback, base::Unretained(this)));
}
+void SSLClientSocketImpl::RecordNegotiatedProtocol() const {
+ UMA_HISTOGRAM_ENUMERATION("Net.SSLNegotiatedAlpnProtocol",
+ negotiated_protocol_, kProtoLast + 1);
+}
+
+void SSLClientSocketImpl::RecordChannelIDSupport() const {
+ // Since this enum is used for a histogram, do not change or re-use values.
+ enum {
+ DISABLED = 0,
+ CLIENT_ONLY = 1,
+ CLIENT_AND_SERVER = 2,
+ // CLIENT_NO_ECC is unused now.
+ // CLIENT_BAD_SYSTEM_TIME is unused now.
+ CLIENT_BAD_SYSTEM_TIME = 4,
+ CLIENT_NO_CHANNEL_ID_SERVICE = 5,
+ CHANNEL_ID_USAGE_MAX
+ } supported = DISABLED;
+ if (channel_id_sent_) {
+ supported = CLIENT_AND_SERVER;
+ } else if (ssl_config_.channel_id_enabled) {
+ if (!channel_id_service_)
+ supported = CLIENT_NO_CHANNEL_ID_SERVICE;
+ else
+ supported = CLIENT_ONLY;
+ }
+ UMA_HISTOGRAM_ENUMERATION("DomainBoundCerts.Support", supported,
+ CHANNEL_ID_USAGE_MAX);
+}
+
+bool SSLClientSocketImpl::IsChannelIDEnabled() const {
+ return ssl_config_.channel_id_enabled && channel_id_service_;
+}
+
+int SSLClientSocketImpl::MapLastOpenSSLError(
+ int ssl_error,
+ const crypto::OpenSSLErrStackTracer& tracer,
+ OpenSSLErrorInfo* info) {
+ int net_error = MapOpenSSLErrorWithDetails(ssl_error, tracer, info);
+
+ if (ssl_error == SSL_ERROR_SSL &&
+ ERR_GET_LIB(info->error_code) == ERR_LIB_SSL) {
+ // TLS does not provide an alert for missing client certificates, so most
+ // servers send a generic handshake_failure alert. Detect this case by
+ // checking if we have received a CertificateRequest but sent no
+ // certificate. See https://crbug.com/646567.
+ if (ERR_GET_REASON(info->error_code) ==
+ SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE &&
+ certificate_requested_ && ssl_config_.send_client_cert &&
+ !ssl_config_.client_cert) {
+ net_error = ERR_BAD_SSL_CLIENT_AUTH_CERT;
+ }
+
+ // Per spec, access_denied is only for client-certificate-based access
+ // control, but some buggy firewalls use it when blocking a page. To avoid a
+ // confusing error, map it to a generic protocol error if no
+ // CertificateRequest was sent. See https://crbug.com/630883.
+ if (ERR_GET_REASON(info->error_code) == SSL_R_TLSV1_ALERT_ACCESS_DENIED &&
+ !certificate_requested_) {
+ net_error = ERR_SSL_PROTOCOL_ERROR;
+ }
+ }
+
+ return net_error;
+}
+
} // namespace net
diff --git a/chromium/net/socket/ssl_client_socket_impl.h b/chromium/net/socket/ssl_client_socket_impl.h
index 3b861aa643b..5c9b2945312 100644
--- a/chromium/net/socket/ssl_client_socket_impl.h
+++ b/chromium/net/socket/ssl_client_socket_impl.h
@@ -24,10 +24,12 @@
#include "net/cert/cert_verifier.h"
#include "net/cert/cert_verify_result.h"
#include "net/cert/ct_verify_result.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/ssl_client_socket.h"
#include "net/ssl/channel_id_service.h"
#include "net/ssl/openssl_ssl_util.h"
+#include "net/ssl/scoped_openssl_types.h"
#include "net/ssl/ssl_client_cert_type.h"
#include "net/ssl/ssl_config_service.h"
@@ -36,6 +38,10 @@ class FilePath;
class SequencedTaskRunner;
}
+namespace crypto {
+class OpenSSLErrStackTracer;
+}
+
namespace net {
class CertVerifier;
@@ -43,7 +49,9 @@ class CTVerifier;
class SSLCertRequestInfo;
class SSLInfo;
-using SignedEkmMap = base::MRUCache<std::string, std::vector<uint8_t>>;
+using TokenBindingSignatureMap =
+ base::MRUCache<std::pair<TokenBindingType, std::string>,
+ std::vector<uint8_t>>;
class SSLClientSocketImpl : public SSLClientSocket {
public:
@@ -72,10 +80,10 @@ class SSLClientSocketImpl : public SSLClientSocket {
// SSLClientSocket implementation.
void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
- NextProtoStatus GetNextProto(std::string* proto) const override;
ChannelIDService* GetChannelIDService() const override;
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) override;
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) override;
crypto::ECPrivateKey* GetChannelIDKey() const override;
// SSLSocket implementation.
@@ -92,10 +100,12 @@ class SSLClientSocketImpl : public SSLClientSocket {
bool IsConnectedAndIdle() const override;
int GetPeerAddress(IPEndPoint* address) const override;
int GetLocalAddress(IPEndPoint* address) const override;
- const BoundNetLog& NetLog() const override;
+ const NetLogWithSource& NetLog() const override;
void SetSubresourceSpeculation() override;
void SetOmniboxSpeculation() override;
bool WasEverUsed() const override;
+ bool WasNpnNegotiated() const override;
+ NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(SSLInfo* ssl_info) override;
void GetConnectionAttempts(ConnectionAttempts* out) const override;
void ClearConnectionAttempts() override {}
@@ -164,12 +174,6 @@ class SSLClientSocketImpl : public SSLClientSocket {
// certificates don't change during renegotiation.
int CertVerifyCallback(X509_STORE_CTX* store_ctx);
- // Callback from the SSL layer to check which NPN protocol we are supporting
- int SelectNextProtoCallback(unsigned char** out,
- unsigned char* outlen,
- const unsigned char* in,
- unsigned int inlen);
-
// Called during an operation on |transport_bio_|'s peer. Checks saved
// transport error state and, if appropriate, returns an error through
// OpenSSL's error system.
@@ -217,18 +221,17 @@ class SSLClientSocketImpl : public SSLClientSocket {
// Callbacks for operations with the private key.
int PrivateKeyTypeCallback();
size_t PrivateKeyMaxSignatureLenCallback();
- ssl_private_key_result_t PrivateKeySignCallback(uint8_t* out,
- size_t* out_len,
- size_t max_out,
- const EVP_MD* md,
- const uint8_t* in,
- size_t in_len);
- ssl_private_key_result_t PrivateKeySignCompleteCallback(uint8_t* out,
- size_t* out_len,
- size_t max_out);
-
- void OnPrivateKeySignComplete(Error error,
- const std::vector<uint8_t>& signature);
+ ssl_private_key_result_t PrivateKeySignDigestCallback(uint8_t* out,
+ size_t* out_len,
+ size_t max_out,
+ const EVP_MD* md,
+ 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);
int TokenBindingAdd(const uint8_t** out,
size_t* out_len,
@@ -239,6 +242,23 @@ class SSLClientSocketImpl : public SSLClientSocket {
void LogConnectEndEvent(int rv);
+ // Record whether ALPN was used, and if so, the negotiated protocol,
+ // in a UMA histogram.
+ void RecordNegotiatedProtocol() const;
+
+ // Records histograms for channel id support during full handshakes - resumed
+ // handshakes are ignored.
+ void RecordChannelIDSupport() const;
+
+ // Returns whether TLS channel ID is enabled.
+ bool IsChannelIDEnabled() const;
+
+ // Returns the net error corresponding to the most recent OpenSSL
+ // error. ssl_error is the output of SSL_get_error.
+ int MapLastOpenSSLError(int ssl_error,
+ const crypto::OpenSSLErrStackTracer& tracer,
+ OpenSSLErrorInfo* info);
+
bool transport_send_busy_;
bool transport_recv_busy_;
@@ -287,6 +307,7 @@ class SSLClientSocketImpl : public SSLClientSocket {
std::unique_ptr<PeerCertificateChain> server_cert_chain_;
scoped_refptr<X509Certificate> server_cert_;
CertVerifyResult server_cert_verify_result_;
+ std::string ocsp_response_;
bool completed_connect_;
// Set when Read() or Write() successfully reads or writes data to or from the
@@ -312,7 +333,7 @@ class SSLClientSocketImpl : public SSLClientSocket {
ChannelIDService* channel_id_service_;
bool tb_was_negotiated_;
TokenBindingParam tb_negotiated_param_;
- SignedEkmMap tb_signed_ekm_map_;
+ TokenBindingSignatureMap tb_signature_map_;
// OpenSSL stuff
SSL* ssl_;
@@ -340,18 +361,18 @@ class SSLClientSocketImpl : public SSLClientSocket {
// True if the socket has been disconnected.
bool disconnected_;
- NextProtoStatus npn_status_;
- std::string npn_proto_;
+ NextProto negotiated_protocol_;
// Written by the |channel_id_service_|.
std::unique_ptr<crypto::ECPrivateKey> channel_id_key_;
// True if a channel ID was sent.
bool channel_id_sent_;
- // True if the current session was newly-established, but the certificate had
- // not yet been verified externally, so it cannot be inserted into the cache
- // until later.
- bool session_pending_;
+ // If non-null, the newly-established to be inserted into the session cache
+ // once certificate verification is done.
+ ScopedSSL_SESSION pending_session_;
// True if the initial handshake's certificate has been verified.
bool certificate_verified_;
+ // Set to true if a CertificateRequest was received.
+ bool certificate_requested_;
// The request handle for |channel_id_service_|.
ChannelIDService::Request channel_id_request_;
@@ -370,7 +391,7 @@ class SSLClientSocketImpl : public SSLClientSocket {
// True if PKP is bypassed due to a local trust anchor.
bool pkp_bypassed_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
base::WeakPtrFactory<SSLClientSocketImpl> weak_factory_;
};
diff --git a/chromium/net/socket/ssl_client_socket_pool.cc b/chromium/net/socket/ssl_client_socket_pool.cc
index e60c880e9f3..2efa40434b6 100644
--- a/chromium/net/socket/ssl_client_socket_pool.cc
+++ b/chromium/net/socket/ssl_client_socket_pool.cc
@@ -4,6 +4,8 @@
#include "net/socket/ssl_client_socket_pool.h"
+#include <openssl/ssl.h>
+
#include <utility>
#include "base/bind.h"
@@ -18,18 +20,21 @@
#include "net/base/net_errors.h"
#include "net/http/http_proxy_client_socket.h"
#include "net/http/http_proxy_client_socket_pool.h"
+#include "net/log/net_log_source_type.h"
+#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/socks_client_socket_pool.h"
#include "net/socket/ssl_client_socket.h"
#include "net/socket/transport_client_socket_pool.h"
#include "net/ssl/ssl_cert_request_info.h"
-#include "net/ssl/ssl_cipher_suite_names.h"
#include "net/ssl/ssl_connection_status_flags.h"
#include "net/ssl/ssl_info.h"
namespace net {
+class NetLog;
+
SSLSocketParams::SSLSocketParams(
const scoped_refptr<TransportSocketParams>& direct_params,
const scoped_refptr<SOCKSSocketParams>& socks_proxy_params,
@@ -104,12 +109,13 @@ SSLConnectJob::SSLConnectJob(const std::string& group_name,
const SSLClientSocketContext& context,
Delegate* delegate,
NetLog* net_log)
- : ConnectJob(group_name,
- timeout_duration,
- priority,
- respect_limits,
- delegate,
- BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
+ : ConnectJob(
+ group_name,
+ timeout_duration,
+ priority,
+ respect_limits,
+ delegate,
+ NetLogWithSource::Make(net_log, NetLogSourceType::CONNECT_JOB)),
params_(params),
transport_pool_(transport_pool),
socks_pool_(socks_pool),
@@ -334,10 +340,10 @@ int SSLConnectJob::DoSSLConnectComplete(int result) {
server_address_ = IPEndPoint();
}
- // If we want SPDY over ALPN/NPN, make sure it succeeded.
+ // If we want SPDY over ALPN, make sure it succeeded.
if (params_->expect_spdy() &&
- !NextProtoIsSPDY(ssl_socket_->GetNegotiatedProtocol())) {
- return ERR_NPN_NEGOTIATION_FAILED;
+ ssl_socket_->GetNegotiatedProtocol() != kProtoHTTP2) {
+ return ERR_ALPN_NEGOTIATION_FAILED;
}
if (result == OK ||
@@ -371,22 +377,12 @@ int SSLConnectJob::DoSSLConnectComplete(int result) {
SSLConnectionStatusToCipherSuite(ssl_info.connection_status);
UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSL_CipherSuite", cipher_suite);
- const char *str, *cipher_str, *mac_str;
- bool is_aead;
- SSLCipherSuiteToStrings(&str, &cipher_str, &mac_str, &is_aead,
- cipher_suite);
- // UMA_HISTOGRAM_... macros cache the Histogram instance and thus only work
- // if the histogram name is constant, so don't generate it dynamically.
- if (strncmp(str, "DHE_", 4) == 0) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSL_KeyExchange.DHE",
- ssl_info.key_exchange_info);
- } else if (strncmp(str, "ECDHE_", 6) == 0) {
+ const SSL_CIPHER* cipher = SSL_get_cipher_by_value(cipher_suite);
+ bool is_cecpq1 = cipher && SSL_CIPHER_is_CECPQ1(cipher);
+
+ if (ssl_info.key_exchange_group != 0) {
UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSL_KeyExchange.ECDHE",
- ssl_info.key_exchange_info);
- } else if (strncmp(str, "CECPQ1_", 7) == 0) {
- // Nothing.
- } else {
- DCHECK_EQ(0, strcmp(str, "RSA"));
+ ssl_info.key_exchange_group);
}
if (ssl_info.handshake_type == SSLInfo::HANDSHAKE_RESUME) {
@@ -427,6 +423,27 @@ int SSLConnectJob::DoSSLConnectComplete(int result) {
base::TimeDelta::FromMilliseconds(1),
base::TimeDelta::FromMinutes(1),
100);
+
+ // These are hosts that we expect to always offer CECPQ1. Connections
+ // to them, whether or not this browser is in the experiment group, form
+ // the basis of our comparisons.
+ bool cecpq1_expected_to_be_offered =
+ ssl_info.is_issued_by_known_root &&
+ (host == "play.google.com" || host == "checkout.google.com" ||
+ host == "wallet.google.com");
+ if (cecpq1_expected_to_be_offered) {
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "Net.SSL_Connection_Latency_PostQuantumSupported_Full_Handshake",
+ connect_duration, base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMinutes(1), 100);
+ if (SSLClientSocket::IsPostQuantumExperimentEnabled()) {
+ // But don't trust that these hosts offer CECPQ1: make sure. If
+ // we're doing everything right on the server side, |is_cecpq1|
+ // should always be true if we get here, modulo MITM.
+ UMA_HISTOGRAM_BOOLEAN("Net.SSL_Connection_PostQuantum_Negotiated",
+ is_cecpq1);
+ }
+ }
}
}
}
@@ -570,7 +587,7 @@ int SSLClientSocketPool::RequestSocket(const std::string& group_name,
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
const scoped_refptr<SSLSocketParams>* casted_socket_params =
static_cast<const scoped_refptr<SSLSocketParams>*>(socket_params);
@@ -578,11 +595,10 @@ int SSLClientSocketPool::RequestSocket(const std::string& group_name,
respect_limits, handle, callback, net_log);
}
-void SSLClientSocketPool::RequestSockets(
- const std::string& group_name,
- const void* params,
- int num_sockets,
- const BoundNetLog& net_log) {
+void SSLClientSocketPool::RequestSockets(const std::string& group_name,
+ const void* params,
+ int num_sockets,
+ const NetLogWithSource& net_log) {
const scoped_refptr<SSLSocketParams>* casted_params =
static_cast<const scoped_refptr<SSLSocketParams>*>(params);
diff --git a/chromium/net/socket/ssl_client_socket_pool.h b/chromium/net/socket/ssl_client_socket_pool.h
index 3dc03e5b84b..e7b7e8c9259 100644
--- a/chromium/net/socket/ssl_client_socket_pool.h
+++ b/chromium/net/socket/ssl_client_socket_pool.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
+#include "net/base/net_export.h"
#include "net/base/privacy_mode.h"
#include "net/http/http_response_info.h"
#include "net/socket/client_socket_pool.h"
@@ -207,12 +208,12 @@ class NET_EXPORT_PRIVATE SSLClientSocketPool
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void RequestSockets(const std::string& group_name,
const void* params,
int num_sockets,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void CancelRequest(const std::string& group_name,
ClientSocketHandle* handle) override;
diff --git a/chromium/net/socket/ssl_client_socket_pool_unittest.cc b/chromium/net/socket/ssl_client_socket_pool_unittest.cc
index 710527c9319..3a8537f1421 100644
--- a/chromium/net/socket/ssl_client_socket_pool_unittest.cc
+++ b/chromium/net/socket/ssl_client_socket_pool_unittest.cc
@@ -24,6 +24,8 @@
#include "net/http/http_response_headers.h"
#include "net/http/http_server_properties_impl.h"
#include "net/http/transport_security_state.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_service.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/next_proto.h"
@@ -32,9 +34,14 @@
#include "net/spdy/spdy_session_pool.h"
#include "net/spdy/spdy_test_util_common.h"
#include "net/ssl/ssl_config_service_defaults.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_certificate_data.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -51,7 +58,7 @@ void TestLoadTimingInfo(const ClientSocketHandle& handle) {
EXPECT_FALSE(load_timing_info.socket_reused);
// None of these tests use a NetLog.
- EXPECT_EQ(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_EQ(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
ExpectConnectTimingHasTimes(
load_timing_info.connect_timing,
@@ -66,7 +73,7 @@ void TestLoadTimingInfoNoDns(const ClientSocketHandle& handle) {
EXPECT_TRUE(handle.GetLoadTimingInfo(false, &load_timing_info));
// None of these tests use a NetLog.
- EXPECT_EQ(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_EQ(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
EXPECT_FALSE(load_timing_info.socket_reused);
@@ -75,9 +82,7 @@ void TestLoadTimingInfoNoDns(const ClientSocketHandle& handle) {
ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
}
-class SSLClientSocketPoolTest
- : public testing::Test,
- public ::testing::WithParamInterface<NextProto> {
+class SSLClientSocketPoolTest : public testing::Test {
protected:
SSLClientSocketPoolTest()
: cert_verifier_(new MockCertVerifier),
@@ -173,7 +178,6 @@ class SSLClientSocketPoolTest
params.ssl_config_service = ssl_config_service_.get();
params.http_auth_handler_factory = http_auth_handler_factory_.get();
params.http_server_properties = http_server_properties_.get();
- params.spdy_default_protocol = GetParam();
return new HttpNetworkSession(params);
}
@@ -206,12 +210,7 @@ class SSLClientSocketPoolTest
std::unique_ptr<SSLClientSocketPool> pool_;
};
-INSTANTIATE_TEST_CASE_P(NextProto,
- SSLClientSocketPoolTest,
- testing::Values(kProtoSPDY31,
- kProtoHTTP2));
-
-TEST_P(SSLClientSocketPoolTest, TCPFail) {
+TEST_F(SSLClientSocketPoolTest, TCPFail) {
StaticSocketDataProvider data;
data.set_connect_data(MockConnect(SYNCHRONOUS, ERR_CONNECTION_FAILED));
socket_factory_.AddSocketDataProvider(&data);
@@ -223,16 +222,17 @@ TEST_P(SSLClientSocketPoolTest, TCPFail) {
ClientSocketHandle handle;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- CompletionCallback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_CONNECTION_FAILED, rv);
+ CompletionCallback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_FALSE(handle.is_ssl_error());
ASSERT_EQ(1u, handle.connection_attempts().size());
- EXPECT_EQ(ERR_CONNECTION_FAILED, handle.connection_attempts()[0].result);
+ EXPECT_THAT(handle.connection_attempts()[0].result,
+ IsError(ERR_CONNECTION_FAILED));
}
-TEST_P(SSLClientSocketPoolTest, TCPFailAsync) {
+TEST_F(SSLClientSocketPoolTest, TCPFailAsync) {
StaticSocketDataProvider data;
data.set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_FAILED));
socket_factory_.AddSocketDataProvider(&data);
@@ -245,20 +245,21 @@ TEST_P(SSLClientSocketPoolTest, TCPFailAsync) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_FALSE(handle.is_ssl_error());
ASSERT_EQ(1u, handle.connection_attempts().size());
- EXPECT_EQ(ERR_CONNECTION_FAILED, handle.connection_attempts()[0].result);
+ EXPECT_THAT(handle.connection_attempts()[0].result,
+ IsError(ERR_CONNECTION_FAILED));
}
-TEST_P(SSLClientSocketPoolTest, BasicDirect) {
+TEST_F(SSLClientSocketPoolTest, BasicDirect) {
StaticSocketDataProvider data;
data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
socket_factory_.AddSocketDataProvider(&data);
@@ -273,8 +274,8 @@ TEST_P(SSLClientSocketPoolTest, BasicDirect) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(OK, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfo(handle);
@@ -283,7 +284,7 @@ TEST_P(SSLClientSocketPoolTest, BasicDirect) {
// Make sure that SSLConnectJob passes on its priority to its
// socket request on Init (for the DIRECT case).
-TEST_P(SSLClientSocketPoolTest, SetSocketRequestPriorityOnInitDirect) {
+TEST_F(SSLClientSocketPoolTest, SetSocketRequestPriorityOnInitDirect) {
CreatePool(true /* tcp pool */, false, false);
scoped_refptr<SSLSocketParams> params =
SSLParams(ProxyServer::SCHEME_DIRECT, false);
@@ -298,15 +299,16 @@ TEST_P(SSLClientSocketPoolTest, SetSocketRequestPriorityOnInitDirect) {
ClientSocketHandle handle;
TestCompletionCallback callback;
- EXPECT_EQ(OK, handle.Init("a", params, priority,
- ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(
+ OK, handle.Init("a", params, priority,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback.callback(), pool_.get(), NetLogWithSource()));
EXPECT_EQ(priority, transport_socket_pool_.last_request_priority());
handle.socket()->Disconnect();
}
}
-TEST_P(SSLClientSocketPoolTest, BasicDirectAsync) {
+TEST_F(SSLClientSocketPoolTest, BasicDirectAsync) {
StaticSocketDataProvider data;
socket_factory_.AddSocketDataProvider(&data);
SSLSocketDataProvider ssl(ASYNC, OK);
@@ -320,18 +322,18 @@ TEST_P(SSLClientSocketPoolTest, BasicDirectAsync) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfo(handle);
}
-TEST_P(SSLClientSocketPoolTest, DirectCertError) {
+TEST_F(SSLClientSocketPoolTest, DirectCertError) {
StaticSocketDataProvider data;
socket_factory_.AddSocketDataProvider(&data);
SSLSocketDataProvider ssl(ASYNC, ERR_CERT_COMMON_NAME_INVALID);
@@ -345,18 +347,18 @@ TEST_P(SSLClientSocketPoolTest, DirectCertError) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CERT_COMMON_NAME_INVALID));
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfo(handle);
}
-TEST_P(SSLClientSocketPoolTest, DirectSSLError) {
+TEST_F(SSLClientSocketPoolTest, DirectSSLError) {
StaticSocketDataProvider data;
socket_factory_.AddSocketDataProvider(&data);
SSLSocketDataProvider ssl(ASYNC, ERR_SSL_PROTOCOL_ERROR);
@@ -370,22 +372,22 @@ TEST_P(SSLClientSocketPoolTest, DirectSSLError) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(ERR_SSL_PROTOCOL_ERROR, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_SSL_PROTOCOL_ERROR));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_TRUE(handle.is_ssl_error());
}
-TEST_P(SSLClientSocketPoolTest, DirectWithNPN) {
+TEST_F(SSLClientSocketPoolTest, DirectWithNPN) {
StaticSocketDataProvider data;
socket_factory_.AddSocketDataProvider(&data);
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(kProtoHTTP11);
+ ssl.next_proto = kProtoHTTP11;
socket_factory_.AddSSLSocketDataProvider(&ssl);
CreatePool(true /* tcp pool */, false, false);
@@ -396,12 +398,12 @@ TEST_P(SSLClientSocketPoolTest, DirectWithNPN) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfo(handle);
@@ -409,11 +411,11 @@ TEST_P(SSLClientSocketPoolTest, DirectWithNPN) {
EXPECT_TRUE(ssl_socket->WasNpnNegotiated());
}
-TEST_P(SSLClientSocketPoolTest, DirectNoSPDY) {
+TEST_F(SSLClientSocketPoolTest, DirectNoSPDY) {
StaticSocketDataProvider data;
socket_factory_.AddSocketDataProvider(&data);
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(kProtoHTTP11);
+ ssl.next_proto = kProtoHTTP11;
socket_factory_.AddSSLSocketDataProvider(&ssl);
CreatePool(true /* tcp pool */, false, false);
@@ -424,22 +426,22 @@ TEST_P(SSLClientSocketPoolTest, DirectNoSPDY) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(ERR_NPN_NEGOTIATION_FAILED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_ALPN_NEGOTIATION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_TRUE(handle.is_ssl_error());
}
-TEST_P(SSLClientSocketPoolTest, DirectGotSPDY) {
+TEST_F(SSLClientSocketPoolTest, DirectGotSPDY) {
StaticSocketDataProvider data;
socket_factory_.AddSocketDataProvider(&data);
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetParam());
+ ssl.next_proto = kProtoHTTP2;
socket_factory_.AddSSLSocketDataProvider(&ssl);
CreatePool(true /* tcp pool */, false, false);
@@ -450,28 +452,26 @@ TEST_P(SSLClientSocketPoolTest, DirectGotSPDY) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfo(handle);
SSLClientSocket* ssl_socket = static_cast<SSLClientSocket*>(handle.socket());
EXPECT_TRUE(ssl_socket->WasNpnNegotiated());
- std::string proto;
- ssl_socket->GetNextProto(&proto);
- EXPECT_EQ(GetParam(), SSLClientSocket::NextProtoFromString(proto));
+ EXPECT_EQ(kProtoHTTP2, ssl_socket->GetNegotiatedProtocol());
}
-TEST_P(SSLClientSocketPoolTest, DirectGotBonusSPDY) {
+TEST_F(SSLClientSocketPoolTest, DirectGotBonusSPDY) {
StaticSocketDataProvider data;
socket_factory_.AddSocketDataProvider(&data);
SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.SetNextProto(GetParam());
+ ssl.next_proto = kProtoHTTP2;
socket_factory_.AddSSLSocketDataProvider(&ssl);
CreatePool(true /* tcp pool */, false, false);
@@ -482,24 +482,22 @@ TEST_P(SSLClientSocketPoolTest, DirectGotBonusSPDY) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfo(handle);
SSLClientSocket* ssl_socket = static_cast<SSLClientSocket*>(handle.socket());
EXPECT_TRUE(ssl_socket->WasNpnNegotiated());
- std::string proto;
- ssl_socket->GetNextProto(&proto);
- EXPECT_EQ(GetParam(), SSLClientSocket::NextProtoFromString(proto));
+ EXPECT_EQ(kProtoHTTP2, ssl_socket->GetNegotiatedProtocol());
}
-TEST_P(SSLClientSocketPoolTest, SOCKSFail) {
+TEST_F(SSLClientSocketPoolTest, SOCKSFail) {
StaticSocketDataProvider data;
data.set_connect_data(MockConnect(SYNCHRONOUS, ERR_CONNECTION_FAILED));
socket_factory_.AddSocketDataProvider(&data);
@@ -512,14 +510,14 @@ TEST_P(SSLClientSocketPoolTest, SOCKSFail) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_CONNECTION_FAILED, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_FALSE(handle.is_ssl_error());
}
-TEST_P(SSLClientSocketPoolTest, SOCKSFailAsync) {
+TEST_F(SSLClientSocketPoolTest, SOCKSFailAsync) {
StaticSocketDataProvider data;
data.set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_FAILED));
socket_factory_.AddSocketDataProvider(&data);
@@ -532,18 +530,18 @@ TEST_P(SSLClientSocketPoolTest, SOCKSFailAsync) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_FALSE(handle.is_ssl_error());
}
-TEST_P(SSLClientSocketPoolTest, SOCKSBasic) {
+TEST_F(SSLClientSocketPoolTest, SOCKSBasic) {
StaticSocketDataProvider data;
data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
socket_factory_.AddSocketDataProvider(&data);
@@ -558,8 +556,8 @@ TEST_P(SSLClientSocketPoolTest, SOCKSBasic) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(OK, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
// SOCKS5 generally has no DNS times, but the mock SOCKS5 sockets used here
@@ -569,7 +567,7 @@ TEST_P(SSLClientSocketPoolTest, SOCKSBasic) {
// Make sure that SSLConnectJob passes on its priority to its
// transport socket on Init (for the SOCKS_PROXY case).
-TEST_P(SSLClientSocketPoolTest, SetTransportPriorityOnInitSOCKS) {
+TEST_F(SSLClientSocketPoolTest, SetTransportPriorityOnInitSOCKS) {
StaticSocketDataProvider data;
data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
socket_factory_.AddSocketDataProvider(&data);
@@ -582,13 +580,14 @@ TEST_P(SSLClientSocketPoolTest, SetTransportPriorityOnInitSOCKS) {
ClientSocketHandle handle;
TestCompletionCallback callback;
- EXPECT_EQ(OK, handle.Init("a", params, HIGHEST,
- ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(OK,
+ handle.Init("a", params, HIGHEST,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback.callback(), pool_.get(), NetLogWithSource()));
EXPECT_EQ(HIGHEST, transport_socket_pool_.last_request_priority());
}
-TEST_P(SSLClientSocketPoolTest, SOCKSBasicAsync) {
+TEST_F(SSLClientSocketPoolTest, SOCKSBasicAsync) {
StaticSocketDataProvider data;
socket_factory_.AddSocketDataProvider(&data);
SSLSocketDataProvider ssl(ASYNC, OK);
@@ -602,12 +601,12 @@ TEST_P(SSLClientSocketPoolTest, SOCKSBasicAsync) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
// SOCKS5 generally has no DNS times, but the mock SOCKS5 sockets used here
@@ -615,7 +614,7 @@ TEST_P(SSLClientSocketPoolTest, SOCKSBasicAsync) {
TestLoadTimingInfo(handle);
}
-TEST_P(SSLClientSocketPoolTest, HttpProxyFail) {
+TEST_F(SSLClientSocketPoolTest, HttpProxyFail) {
StaticSocketDataProvider data;
data.set_connect_data(MockConnect(SYNCHRONOUS, ERR_CONNECTION_FAILED));
socket_factory_.AddSocketDataProvider(&data);
@@ -628,14 +627,14 @@ TEST_P(SSLClientSocketPoolTest, HttpProxyFail) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_PROXY_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_FALSE(handle.is_ssl_error());
}
-TEST_P(SSLClientSocketPoolTest, HttpProxyFailAsync) {
+TEST_F(SSLClientSocketPoolTest, HttpProxyFailAsync) {
StaticSocketDataProvider data;
data.set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_FAILED));
socket_factory_.AddSocketDataProvider(&data);
@@ -648,18 +647,18 @@ TEST_P(SSLClientSocketPoolTest, HttpProxyFailAsync) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_PROXY_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_FALSE(handle.is_ssl_error());
}
-TEST_P(SSLClientSocketPoolTest, HttpProxyBasic) {
+TEST_F(SSLClientSocketPoolTest, HttpProxyBasic) {
MockWrite writes[] = {
MockWrite(SYNCHRONOUS,
"CONNECT host:80 HTTP/1.1\r\n"
@@ -686,8 +685,8 @@ TEST_P(SSLClientSocketPoolTest, HttpProxyBasic) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(OK, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfoNoDns(handle);
@@ -695,7 +694,7 @@ TEST_P(SSLClientSocketPoolTest, HttpProxyBasic) {
// Make sure that SSLConnectJob passes on its priority to its
// transport socket on Init (for the HTTP_PROXY case).
-TEST_P(SSLClientSocketPoolTest, SetTransportPriorityOnInitHTTP) {
+TEST_F(SSLClientSocketPoolTest, SetTransportPriorityOnInitHTTP) {
MockWrite writes[] = {
MockWrite(SYNCHRONOUS,
"CONNECT host:80 HTTP/1.1\r\n"
@@ -720,13 +719,14 @@ TEST_P(SSLClientSocketPoolTest, SetTransportPriorityOnInitHTTP) {
ClientSocketHandle handle;
TestCompletionCallback callback;
- EXPECT_EQ(OK, handle.Init("a", params, HIGHEST,
- ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog()));
+ EXPECT_EQ(OK,
+ handle.Init("a", params, HIGHEST,
+ ClientSocketPool::RespectLimits::ENABLED,
+ callback.callback(), pool_.get(), NetLogWithSource()));
EXPECT_EQ(HIGHEST, transport_socket_pool_.last_request_priority());
}
-TEST_P(SSLClientSocketPoolTest, HttpProxyBasicAsync) {
+TEST_F(SSLClientSocketPoolTest, HttpProxyBasicAsync) {
MockWrite writes[] = {
MockWrite(
"CONNECT host:80 HTTP/1.1\r\n"
@@ -752,18 +752,18 @@ TEST_P(SSLClientSocketPoolTest, HttpProxyBasicAsync) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfoNoDns(handle);
}
-TEST_P(SSLClientSocketPoolTest, NeedProxyAuth) {
+TEST_F(SSLClientSocketPoolTest, NeedProxyAuth) {
MockWrite writes[] = {
MockWrite(
"CONNECT host:80 HTTP/1.1\r\n"
@@ -790,12 +790,12 @@ TEST_P(SSLClientSocketPoolTest, NeedProxyAuth) {
TestCompletionCallback callback;
int rv =
handle.Init("a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), pool_.get(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), pool_.get(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_PROXY_AUTH_REQUESTED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_FALSE(handle.is_ssl_error());
@@ -807,7 +807,7 @@ TEST_P(SSLClientSocketPoolTest, NeedProxyAuth) {
EXPECT_FALSE(tunnel_handle->socket()->IsConnected());
}
-TEST_P(SSLClientSocketPoolTest, IPPooling) {
+TEST_F(SSLClientSocketPoolTest, IPPooling) {
const int kTestPort = 80;
struct TestHosts {
std::string name;
@@ -821,6 +821,7 @@ TEST_P(SSLClientSocketPoolTest, IPPooling) {
};
host_resolver_.set_synchronous_mode(true);
+ std::unique_ptr<HostResolver::Request> req[arraysize(test_hosts)];
for (size_t i = 0; i < arraysize(test_hosts); i++) {
host_resolver_.rules()->AddIPLiteralRule(
test_hosts[i].name, test_hosts[i].iplist, std::string());
@@ -828,12 +829,8 @@ TEST_P(SSLClientSocketPoolTest, IPPooling) {
// This test requires that the HostResolver cache be populated. Normal
// code would have done this already, but we do it manually.
HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
- host_resolver_.Resolve(info,
- DEFAULT_PRIORITY,
- &test_hosts[i].addresses,
- CompletionCallback(),
- NULL,
- BoundNetLog());
+ host_resolver_.Resolve(info, DEFAULT_PRIORITY, &test_hosts[i].addresses,
+ CompletionCallback(), &req[i], NetLogWithSource());
// Setup a SpdySessionKey
test_hosts[i].key = SpdySessionKey(
@@ -849,12 +846,12 @@ TEST_P(SSLClientSocketPoolTest, IPPooling) {
SSLSocketDataProvider ssl(ASYNC, OK);
ssl.cert = X509Certificate::CreateFromBytes(
reinterpret_cast<const char*>(webkit_der), sizeof(webkit_der));
- ssl.SetNextProto(GetParam());
+ ssl.next_proto = kProtoHTTP2;
socket_factory_.AddSSLSocketDataProvider(&ssl);
CreatePool(true /* tcp pool */, false, false);
- base::WeakPtr<SpdySession> spdy_session =
- CreateSecureSpdySession(session_.get(), test_hosts[0].key, BoundNetLog());
+ base::WeakPtr<SpdySession> spdy_session = CreateSecureSpdySession(
+ session_.get(), test_hosts[0].key, NetLogWithSource());
EXPECT_TRUE(
HasSpdySession(session_->spdy_session_pool(), test_hosts[0].key));
@@ -881,6 +878,7 @@ void SSLClientSocketPoolTest::TestIPPoolingDisabled(
TestCompletionCallback callback;
int rv;
+ std::unique_ptr<HostResolver::Request> req[arraysize(test_hosts)];
for (size_t i = 0; i < arraysize(test_hosts); i++) {
host_resolver_.rules()->AddIPLiteralRule(
test_hosts[i].name, test_hosts[i].iplist, std::string());
@@ -888,13 +886,10 @@ void SSLClientSocketPoolTest::TestIPPoolingDisabled(
// This test requires that the HostResolver cache be populated. Normal
// code would have done this already, but we do it manually.
HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
- rv = host_resolver_.Resolve(info,
- DEFAULT_PRIORITY,
- &test_hosts[i].addresses,
- callback.callback(),
- NULL,
- BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ rv = host_resolver_.Resolve(info, DEFAULT_PRIORITY,
+ &test_hosts[i].addresses, callback.callback(),
+ &req[i], NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
// Setup a SpdySessionKey
test_hosts[i].key = SpdySessionKey(
@@ -910,8 +905,8 @@ void SSLClientSocketPoolTest::TestIPPoolingDisabled(
socket_factory_.AddSSLSocketDataProvider(ssl);
CreatePool(true /* tcp pool */, false, false);
- base::WeakPtr<SpdySession> spdy_session =
- CreateSecureSpdySession(session_.get(), test_hosts[0].key, BoundNetLog());
+ base::WeakPtr<SpdySession> spdy_session = CreateSecureSpdySession(
+ session_.get(), test_hosts[0].key, NetLogWithSource());
EXPECT_TRUE(
HasSpdySession(session_->spdy_session_pool(), test_hosts[0].key));
@@ -923,20 +918,20 @@ void SSLClientSocketPoolTest::TestIPPoolingDisabled(
// Verifies that an SSL connection with client authentication disables SPDY IP
// pooling.
-TEST_P(SSLClientSocketPoolTest, IPPoolingClientCert) {
+TEST_F(SSLClientSocketPoolTest, IPPoolingClientCert) {
SSLSocketDataProvider ssl(ASYNC, OK);
ssl.cert = X509Certificate::CreateFromBytes(
reinterpret_cast<const char*>(webkit_der), sizeof(webkit_der));
ssl.client_cert_sent = true;
- ssl.SetNextProto(GetParam());
+ ssl.next_proto = kProtoHTTP2;
TestIPPoolingDisabled(&ssl);
}
// Verifies that an SSL connection with channel ID disables SPDY IP pooling.
-TEST_P(SSLClientSocketPoolTest, IPPoolingChannelID) {
+TEST_F(SSLClientSocketPoolTest, IPPoolingChannelID) {
SSLSocketDataProvider ssl(ASYNC, OK);
ssl.channel_id_sent = true;
- ssl.SetNextProto(GetParam());
+ ssl.next_proto = kProtoHTTP2;
TestIPPoolingDisabled(&ssl);
}
diff --git a/chromium/net/socket/ssl_client_socket_unittest.cc b/chromium/net/socket/ssl_client_socket_unittest.cc
index 2ac6959c9bd..2284ee36410 100644
--- a/chromium/net/socket/ssl_client_socket_unittest.cc
+++ b/chromium/net/socket/ssl_client_socket_unittest.cc
@@ -38,7 +38,8 @@
#include "net/der/tag.h"
#include "net/dns/host_resolver.h"
#include "net/http/transport_security_state.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
#include "net/log/test_net_log.h"
#include "net/log/test_net_log_entry.h"
#include "net/log/test_net_log_util.h"
@@ -54,18 +55,24 @@
#include "net/ssl/ssl_info.h"
#include "net/ssl/test_ssl_private_key.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/spawned_test_server/spawned_test_server.h"
#include "net/test/test_data_directory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsError;
+using net::test::IsOk;
+
using testing::_;
using testing::Return;
using testing::Truly;
namespace net {
+class NetLogWithSource;
+
namespace {
// WrappedStreamSocket is a base class that wraps an existing StreamSocket,
@@ -95,7 +102,9 @@ class WrappedStreamSocket : public StreamSocket {
int GetLocalAddress(IPEndPoint* address) const override {
return transport_->GetLocalAddress(address);
}
- const BoundNetLog& NetLog() const override { return transport_->NetLog(); }
+ const NetLogWithSource& NetLog() const override {
+ return transport_->NetLog();
+ }
void SetSubresourceSpeculation() override {
transport_->SetSubresourceSpeculation();
}
@@ -283,8 +292,8 @@ void ReadBufferingStreamSocket::OnReadCompleted(int result) {
// Simulates synchronously receiving an error during Read() or Write()
class SynchronousErrorStreamSocket : public WrappedStreamSocket {
public:
- explicit SynchronousErrorStreamSocket(
- std::unique_ptr<StreamSocket> transport);
+ explicit SynchronousErrorStreamSocket(std::unique_ptr<StreamSocket> transport)
+ : WrappedStreamSocket(std::move(transport)) {}
~SynchronousErrorStreamSocket() override {}
// Socket implementation:
@@ -316,23 +325,15 @@ class SynchronousErrorStreamSocket : public WrappedStreamSocket {
}
private:
- bool have_read_error_;
- int pending_read_error_;
+ bool have_read_error_ = false;
+ int pending_read_error_ = OK;
- bool have_write_error_;
- int pending_write_error_;
+ bool have_write_error_ = false;
+ int pending_write_error_ = OK;
DISALLOW_COPY_AND_ASSIGN(SynchronousErrorStreamSocket);
};
-SynchronousErrorStreamSocket::SynchronousErrorStreamSocket(
- std::unique_ptr<StreamSocket> transport)
- : WrappedStreamSocket(std::move(transport)),
- have_read_error_(false),
- pending_read_error_(OK),
- have_write_error_(false),
- pending_write_error_(OK) {}
-
int SynchronousErrorStreamSocket::Read(IOBuffer* buf,
int buf_len,
const CompletionCallback& callback) {
@@ -355,7 +356,8 @@ int SynchronousErrorStreamSocket::Write(IOBuffer* buf,
// semantics).
class FakeBlockingStreamSocket : public WrappedStreamSocket {
public:
- explicit FakeBlockingStreamSocket(std::unique_ptr<StreamSocket> transport);
+ explicit FakeBlockingStreamSocket(std::unique_ptr<StreamSocket> transport)
+ : WrappedStreamSocket(std::move(transport)) {}
~FakeBlockingStreamSocket() override {}
// Socket implementation:
@@ -376,6 +378,10 @@ class FakeBlockingStreamSocket : public WrappedStreamSocket {
void BlockReadResult();
void UnblockReadResult();
+ // Replaces the pending read with |data|. Returns true on success or false if
+ // the caller's reads were too small.
+ bool ReplaceReadResult(const std::string& data);
+
// Waits for the blocked Read() call to be complete at the underlying
// transport.
void WaitForReadResult();
@@ -395,24 +401,30 @@ class FakeBlockingStreamSocket : public WrappedStreamSocket {
// Handles completion from the underlying transport read.
void OnReadCompleted(int result);
+ // Finishes the current read.
+ void ReturnReadResult();
+
// True if read callbacks are blocked.
- bool should_block_read_;
+ bool should_block_read_ = false;
// The buffer for the pending read, or NULL if not consumed.
scoped_refptr<IOBuffer> pending_read_buf_;
+ // The size of the pending read buffer, or -1 if not set.
+ int pending_read_buf_len_ = -1;
+
// The user callback for the pending read call.
CompletionCallback pending_read_callback_;
// The result for the blocked read callback, or ERR_IO_PENDING if not
// completed.
- int pending_read_result_;
+ int pending_read_result_ = ERR_IO_PENDING;
// WaitForReadResult() wait loop.
std::unique_ptr<base::RunLoop> read_loop_;
// True if write calls are blocked.
- bool should_block_write_;
+ bool should_block_write_ = false;
// The buffer for the pending write, or NULL if not scheduled.
scoped_refptr<IOBuffer> pending_write_buf_;
@@ -421,20 +433,12 @@ class FakeBlockingStreamSocket : public WrappedStreamSocket {
CompletionCallback pending_write_callback_;
// The length for the pending write, or -1 if not scheduled.
- int pending_write_len_;
+ int pending_write_len_ = -1;
// WaitForWrite() wait loop.
std::unique_ptr<base::RunLoop> write_loop_;
};
-FakeBlockingStreamSocket::FakeBlockingStreamSocket(
- std::unique_ptr<StreamSocket> transport)
- : WrappedStreamSocket(std::move(transport)),
- should_block_read_(false),
- pending_read_result_(ERR_IO_PENDING),
- should_block_write_(false),
- pending_write_len_(-1) {}
-
int FakeBlockingStreamSocket::Read(IOBuffer* buf,
int len,
const CompletionCallback& callback) {
@@ -445,16 +449,16 @@ int FakeBlockingStreamSocket::Read(IOBuffer* buf,
int rv = transport_->Read(buf, len, base::Bind(
&FakeBlockingStreamSocket::OnReadCompleted, base::Unretained(this)));
- if (rv == ERR_IO_PENDING) {
+ if (rv == ERR_IO_PENDING || should_block_read_) {
// Save the callback to be called later.
pending_read_buf_ = buf;
+ pending_read_buf_len_ = len;
pending_read_callback_ = callback;
- } else if (should_block_read_) {
- // Save the callback and read result to be called later.
- pending_read_buf_ = buf;
- pending_read_callback_ = callback;
- OnReadCompleted(rv);
- rv = ERR_IO_PENDING;
+ // Save the read result.
+ if (rv != ERR_IO_PENDING) {
+ OnReadCompleted(rv);
+ rv = ERR_IO_PENDING;
+ }
}
return rv;
}
@@ -492,15 +496,23 @@ void FakeBlockingStreamSocket::UnblockReadResult() {
DCHECK(should_block_read_);
should_block_read_ = false;
- // If the operation is still pending in the underlying transport, immediately
- // return - OnReadCompleted() will handle invoking the callback once the
- // transport has completed.
- if (pending_read_result_ == ERR_IO_PENDING)
- return;
- int result = pending_read_result_;
- pending_read_buf_ = nullptr;
- pending_read_result_ = ERR_IO_PENDING;
- base::ResetAndReturn(&pending_read_callback_).Run(result);
+ // If the operation has since completed, return the result to the caller.
+ if (pending_read_result_ != ERR_IO_PENDING)
+ ReturnReadResult();
+}
+
+bool FakeBlockingStreamSocket::ReplaceReadResult(const std::string& data) {
+ DCHECK(should_block_read_);
+ DCHECK_NE(ERR_IO_PENDING, pending_read_result_);
+ DCHECK(pending_read_buf_);
+ DCHECK_NE(-1, pending_read_buf_len_);
+
+ if (static_cast<size_t>(pending_read_buf_len_) < data.size())
+ return false;
+
+ memcpy(pending_read_buf_->data(), data.data(), data.size());
+ pending_read_result_ = data.size();
+ return true;
}
void FakeBlockingStreamSocket::WaitForReadResult() {
@@ -556,20 +568,24 @@ void FakeBlockingStreamSocket::OnReadCompleted(int result) {
DCHECK_EQ(ERR_IO_PENDING, pending_read_result_);
DCHECK(!pending_read_callback_.is_null());
- if (should_block_read_) {
- // Store the result so that the callback can be invoked once Unblock() is
- // called.
- pending_read_result_ = result;
+ pending_read_result_ = result;
- // Stop the WaitForReadResult() call if any.
+ if (should_block_read_) {
+ // Defer the result until UnblockReadResult is called.
if (read_loop_)
read_loop_->Quit();
- } else {
- // Either the Read() was never blocked or UnblockReadResult() was called
- // before the Read() completed. Either way, return the result to the caller.
- pending_read_buf_ = nullptr;
- base::ResetAndReturn(&pending_read_callback_).Run(result);
+ return;
}
+
+ ReturnReadResult();
+}
+
+void FakeBlockingStreamSocket::ReturnReadResult() {
+ int result = pending_read_result_;
+ pending_read_result_ = ERR_IO_PENDING;
+ pending_read_buf_ = nullptr;
+ pending_read_buf_len_ = -1;
+ base::ResetAndReturn(&pending_read_callback_).Run(result);
}
// CountingStreamSocket wraps an existing StreamSocket and maintains a count of
@@ -686,11 +702,12 @@ class AsyncFailingChannelIDStore : public ChannelIDStore {
// anything.
class MockCTVerifier : public CTVerifier {
public:
- MOCK_METHOD5(Verify, int(X509Certificate*,
- const std::string&,
- const std::string&,
- ct::CTVerifyResult*,
- const BoundNetLog&));
+ MOCK_METHOD5(Verify,
+ int(X509Certificate*,
+ const std::string&,
+ const std::string&,
+ ct::CTVerifyResult*,
+ const NetLogWithSource&));
MOCK_METHOD1(SetObserver, void(CTVerifier::Observer*));
};
@@ -700,12 +717,12 @@ class MockCTPolicyEnforcer : public CTPolicyEnforcer {
MOCK_METHOD3(DoesConformToCertPolicy,
ct::CertPolicyCompliance(X509Certificate* cert,
const ct::SCTList&,
- const BoundNetLog&));
+ const NetLogWithSource&));
MOCK_METHOD4(DoesConformToCTEVPolicy,
ct::EVPolicyCompliance(X509Certificate* cert,
const ct::EVCertsWhitelist*,
const ct::SCTList&,
- const BoundNetLog&));
+ const NetLogWithSource&));
};
class MockRequireCTDelegate : public TransportSecurityState::RequireCTDelegate {
@@ -793,7 +810,7 @@ class SSLClientSocketTest : public PlatformTest {
bool CreateAndConnectSSLClientSocket(const SSLConfig& ssl_config,
int* result) {
std::unique_ptr<StreamSocket> transport(
- new TCPClientSocket(addr_, NULL, &log_, NetLog::Source()));
+ new TCPClientSocket(addr_, NULL, &log_, NetLogSource()));
int rv = callback_.GetResult(transport->Connect(callback_.callback()));
if (rv != OK) {
LOG(ERROR) << "Could not connect to SpawnedTestServer";
@@ -858,9 +875,9 @@ class SSLClientSocketCertRequestInfoTest : public SSLClientSocketTest {
TestCompletionCallback callback;
TestNetLog log;
std::unique_ptr<StreamSocket> transport(
- new TCPClientSocket(addr, NULL, &log, NetLog::Source()));
+ new TCPClientSocket(addr, NULL, &log, NetLogSource()));
int rv = callback.GetResult(transport->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
std::move(transport), spawned_test_server.host_port_pair(),
@@ -868,7 +885,7 @@ class SSLClientSocketCertRequestInfoTest : public SSLClientSocketTest {
EXPECT_FALSE(sock->IsConnected());
rv = callback.GetResult(sock->Connect(callback.callback()));
- EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
scoped_refptr<SSLCertRequestInfo> request_info = new SSLCertRequestInfo();
sock->GetSSLCertRequestInfo(request_info.get());
@@ -904,11 +921,11 @@ class SSLClientSocketFalseStartTest : public SSLClientSocketTest {
CHECK(spawned_test_server());
std::unique_ptr<StreamSocket> real_transport(
- new TCPClientSocket(addr(), NULL, NULL, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
std::unique_ptr<FakeBlockingStreamSocket> transport(
new FakeBlockingStreamSocket(std::move(real_transport)));
int rv = callback->GetResult(transport->Connect(callback->callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
FakeBlockingStreamSocket* raw_transport = transport.get();
std::unique_ptr<SSLClientSocket> sock = CreateSSLClientSocket(
@@ -919,7 +936,7 @@ class SSLClientSocketFalseStartTest : public SSLClientSocketTest {
// (ServerHello, etc.)
raw_transport->BlockReadResult();
rv = sock->Connect(callback->callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
raw_transport->WaitForReadResult();
// Release the ServerHello and wait for the client to write
@@ -958,7 +975,7 @@ class SSLClientSocketFalseStartTest : public SSLClientSocketTest {
// state machine sometimes lives on a separate thread, so this thread may
// not yet have processed the signal that the handshake has completed.
int rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock->IsConnected());
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
@@ -1015,6 +1032,25 @@ class SSLClientSocketChannelIDTest : public SSLClientSocketTest {
std::unique_ptr<ChannelIDService> channel_id_service_;
};
+// Returns a serialized unencrypted TLS 1.2 alert record for the given alert
+// value.
+std::string FormatTLS12Alert(uint8_t alert) {
+ std::string ret;
+ // ContentType.alert
+ ret.push_back(21);
+ // Record-layer version. Assume TLS 1.2.
+ ret.push_back(0x03);
+ ret.push_back(0x03);
+ // Record length.
+ ret.push_back(0);
+ ret.push_back(2);
+ // AlertLevel.fatal.
+ ret.push_back(2);
+ // The alert itself.
+ ret.push_back(alert);
+ return ret;
+}
+
} // namespace
TEST_F(SSLClientSocketTest, Connect) {
@@ -1023,9 +1059,9 @@ TEST_F(SSLClientSocketTest, Connect) {
TestCompletionCallback callback;
TestNetLog log;
std::unique_ptr<StreamSocket> transport(
- new TCPClientSocket(addr(), NULL, &log, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, &log, NetLogSource()));
int rv = callback.GetResult(transport->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
std::move(transport), spawned_test_server()->host_port_pair(),
@@ -1037,13 +1073,13 @@ TEST_F(SSLClientSocketTest, Connect) {
TestNetLogEntry::List entries;
log.GetEntries(&entries);
- EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLogEventType::SSL_CONNECT));
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock->IsConnected());
log.GetEntries(&entries);
- EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLog::TYPE_SSL_CONNECT));
+ EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLogEventType::SSL_CONNECT));
sock->Disconnect();
EXPECT_FALSE(sock->IsConnected());
@@ -1058,7 +1094,7 @@ TEST_F(SSLClientSocketTest, ConnectExpired) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
- EXPECT_EQ(ERR_CERT_DATE_INVALID, rv);
+ EXPECT_THAT(rv, IsError(ERR_CERT_DATE_INVALID));
// Rather than testing whether or not the underlying socket is connected,
// test that the handshake has finished. This is because it may be
@@ -1066,7 +1102,7 @@ TEST_F(SSLClientSocketTest, ConnectExpired) {
// the user may take indefinitely long to respond.
TestNetLogEntry::List entries;
log_.GetEntries(&entries);
- EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLog::TYPE_SSL_CONNECT));
+ EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLogEventType::SSL_CONNECT));
}
TEST_F(SSLClientSocketTest, ConnectMismatched) {
@@ -1078,7 +1114,7 @@ TEST_F(SSLClientSocketTest, ConnectMismatched) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
- EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, rv);
+ EXPECT_THAT(rv, IsError(ERR_CERT_COMMON_NAME_INVALID));
// Rather than testing whether or not the underlying socket is connected,
// test that the handshake has finished. This is because it may be
@@ -1086,7 +1122,7 @@ TEST_F(SSLClientSocketTest, ConnectMismatched) {
// the user may take indefinitely long to respond.
TestNetLogEntry::List entries;
log_.GetEntries(&entries);
- EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLog::TYPE_SSL_CONNECT));
+ EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLogEventType::SSL_CONNECT));
}
#if defined(OS_WIN)
@@ -1101,7 +1137,7 @@ TEST_F(SSLClientSocketTest, ConnectBadValidity) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(ERR_SSL_SERVER_CERT_BAD_FORMAT, rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_SERVER_CERT_BAD_FORMAT));
EXPECT_FALSE(IsCertificateError(rv));
SSLInfo ssl_info;
@@ -1119,11 +1155,11 @@ TEST_F(SSLClientSocketTest, ConnectClientAuthCertRequested) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
- EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
TestNetLogEntry::List entries;
log_.GetEntries(&entries);
- EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLog::TYPE_SSL_CONNECT));
+ EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLogEventType::SSL_CONNECT));
EXPECT_FALSE(sock_->IsConnected());
}
@@ -1144,7 +1180,7 @@ TEST_F(SSLClientSocketTest, ConnectClientAuthSendNullCert) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// We responded to the server's certificate request with a Certificate
// message with no client certificate in it. ssl_info.client_cert_sent
@@ -1169,11 +1205,11 @@ TEST_F(SSLClientSocketTest, Read) {
TestCompletionCallback callback;
std::unique_ptr<StreamSocket> transport(
- new TCPClientSocket(addr(), NULL, NULL, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
EXPECT_EQ(0, transport->GetTotalReceivedBytes());
int rv = callback.GetResult(transport->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
std::move(transport), spawned_test_server()->host_port_pair(),
@@ -1181,7 +1217,7 @@ TEST_F(SSLClientSocketTest, Read) {
EXPECT_EQ(0, sock->GetTotalReceivedBytes());
rv = callback.GetResult(sock->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Number of network bytes received should increase because of SSL socket
// establishment.
@@ -1219,18 +1255,17 @@ TEST_F(SSLClientSocketTest, Read) {
}
// Tests that SSLClientSocket properly handles when the underlying transport
-// synchronously fails a transport read in during the handshake. The error code
-// should be preserved so SSLv3 fallback logic can condition on it.
+// synchronously fails a transport read in during the handshake.
TEST_F(SSLClientSocketTest, Connect_WithSynchronousError) {
ASSERT_TRUE(StartTestServer(SpawnedTestServer::SSLOptions()));
TestCompletionCallback callback;
std::unique_ptr<StreamSocket> real_transport(
- new TCPClientSocket(addr(), NULL, NULL, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
std::unique_ptr<SynchronousErrorStreamSocket> transport(
new SynchronousErrorStreamSocket(std::move(real_transport)));
int rv = callback.GetResult(transport->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Disable TLS False Start to avoid handshake non-determinism.
SSLConfig ssl_config;
@@ -1244,7 +1279,7 @@ TEST_F(SSLClientSocketTest, Connect_WithSynchronousError) {
raw_transport->SetNextWriteError(ERR_CONNECTION_RESET);
rv = callback.GetResult(sock->Connect(callback.callback()));
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
EXPECT_FALSE(sock->IsConnected());
}
@@ -1257,11 +1292,11 @@ TEST_F(SSLClientSocketTest, Read_WithSynchronousError) {
TestCompletionCallback callback;
std::unique_ptr<StreamSocket> real_transport(
- new TCPClientSocket(addr(), NULL, NULL, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
std::unique_ptr<SynchronousErrorStreamSocket> transport(
new SynchronousErrorStreamSocket(std::move(real_transport)));
int rv = callback.GetResult(transport->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Disable TLS False Start to avoid handshake non-determinism.
SSLConfig ssl_config;
@@ -1273,7 +1308,7 @@ TEST_F(SSLClientSocketTest, Read_WithSynchronousError) {
ssl_config));
rv = callback.GetResult(sock->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock->IsConnected());
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
@@ -1295,7 +1330,7 @@ TEST_F(SSLClientSocketTest, Read_WithSynchronousError) {
// rv != ERR_IO_PENDING is insufficient, as ERR_IO_PENDING is a legitimate
// result when using a dedicated task runner for NSS.
rv = callback.GetResult(sock->Read(buf.get(), 4096, callback.callback()));
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
}
// Tests that the SSLClientSocket properly handles when the underlying transport
@@ -1307,7 +1342,7 @@ TEST_F(SSLClientSocketTest, Write_WithSynchronousError) {
TestCompletionCallback callback;
std::unique_ptr<StreamSocket> real_transport(
- new TCPClientSocket(addr(), NULL, NULL, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
// Note: |error_socket|'s ownership is handed to |transport|, but a pointer
// is retained in order to configure additional errors.
std::unique_ptr<SynchronousErrorStreamSocket> error_socket(
@@ -1317,7 +1352,7 @@ TEST_F(SSLClientSocketTest, Write_WithSynchronousError) {
new FakeBlockingStreamSocket(std::move(error_socket)));
FakeBlockingStreamSocket* raw_transport = transport.get();
int rv = callback.GetResult(transport->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Disable TLS False Start to avoid handshake non-determinism.
SSLConfig ssl_config;
@@ -1328,7 +1363,7 @@ TEST_F(SSLClientSocketTest, Write_WithSynchronousError) {
ssl_config));
rv = callback.GetResult(sock->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock->IsConnected());
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
@@ -1352,7 +1387,7 @@ TEST_F(SSLClientSocketTest, Write_WithSynchronousError) {
scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
rv = sock->Read(buf.get(), 4096, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Now unblock the outgoing request, having it fail with the connection
// being reset.
@@ -1362,7 +1397,7 @@ TEST_F(SSLClientSocketTest, Write_WithSynchronousError) {
// checking that rv != ERR_IO_PENDING is insufficient, as ERR_IO_PENDING
// is a legitimate result when using a dedicated task runner for NSS.
rv = callback.GetResult(rv);
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
}
// If there is a Write failure at the transport with no follow-up Read, although
@@ -1374,7 +1409,7 @@ TEST_F(SSLClientSocketTest, Write_WithSynchronousErrorNoRead) {
TestCompletionCallback callback;
std::unique_ptr<StreamSocket> real_transport(
- new TCPClientSocket(addr(), NULL, NULL, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
// Note: intermediate sockets' ownership are handed to |sock|, but a pointer
// is retained in order to query them.
std::unique_ptr<SynchronousErrorStreamSocket> error_socket(
@@ -1384,7 +1419,7 @@ TEST_F(SSLClientSocketTest, Write_WithSynchronousErrorNoRead) {
new CountingStreamSocket(std::move(error_socket)));
CountingStreamSocket* raw_counting_socket = counting_socket.get();
int rv = callback.GetResult(counting_socket->Connect(callback.callback()));
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
// Disable TLS False Start to avoid handshake non-determinism.
SSLConfig ssl_config;
@@ -1395,7 +1430,7 @@ TEST_F(SSLClientSocketTest, Write_WithSynchronousErrorNoRead) {
ssl_config));
rv = callback.GetResult(sock->Connect(callback.callback()));
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
ASSERT_TRUE(sock->IsConnected());
// Simulate an unclean/forcible shutdown on the underlying socket.
@@ -1434,14 +1469,14 @@ TEST_F(SSLClientSocketTest, Read_FullDuplex) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Issue a "hanging" Read first.
TestCompletionCallback callback;
scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
rv = sock_->Read(buf.get(), 4096, callback.callback());
// We haven't written the request, so there should be no response yet.
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
// Write the request.
// The request is padded with a User-Agent header to a size that causes the
@@ -1474,7 +1509,7 @@ TEST_F(SSLClientSocketTest, Read_DeleteWhilePendingFullDuplex) {
TestCompletionCallback callback;
std::unique_ptr<StreamSocket> real_transport(
- new TCPClientSocket(addr(), NULL, NULL, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
// Note: |error_socket|'s ownership is handed to |transport|, but a pointer
// is retained in order to configure additional errors.
std::unique_ptr<SynchronousErrorStreamSocket> error_socket(
@@ -1485,7 +1520,7 @@ TEST_F(SSLClientSocketTest, Read_DeleteWhilePendingFullDuplex) {
FakeBlockingStreamSocket* raw_transport = transport.get();
int rv = callback.GetResult(transport->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Disable TLS False Start to avoid handshake non-determinism.
SSLConfig ssl_config;
@@ -1496,7 +1531,7 @@ TEST_F(SSLClientSocketTest, Read_DeleteWhilePendingFullDuplex) {
ssl_config);
rv = callback.GetResult(sock->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock->IsConnected());
std::string request_text = "GET / HTTP/1.1\r\nUser-Agent: long browser name ";
@@ -1521,7 +1556,7 @@ TEST_F(SSLClientSocketTest, Read_DeleteWhilePendingFullDuplex) {
rv = raw_sock->Read(read_buf.get(), 4096, read_callback.callback());
// Ensure things didn't complete synchronously, otherwise |sock| is invalid.
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
ASSERT_FALSE(read_callback.have_result());
// Attempt to write the remaining data. OpenSSL will return that its blocked
@@ -1529,7 +1564,7 @@ TEST_F(SSLClientSocketTest, Read_DeleteWhilePendingFullDuplex) {
rv = raw_sock->Write(request_buffer.get(),
request_buffer->BytesRemaining(),
callback.callback());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
ASSERT_FALSE(callback.have_result());
// Now unblock Write(), which will invoke OnSendComplete and (eventually)
@@ -1538,7 +1573,7 @@ TEST_F(SSLClientSocketTest, Read_DeleteWhilePendingFullDuplex) {
raw_transport->UnblockWrite();
rv = read_callback.WaitForResult();
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
// The Write callback should not have been called.
EXPECT_FALSE(callback.have_result());
@@ -1553,7 +1588,7 @@ TEST_F(SSLClientSocketTest, Read_WithWriteError) {
TestCompletionCallback callback;
std::unique_ptr<StreamSocket> real_transport(
- new TCPClientSocket(addr(), NULL, NULL, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
// Note: |error_socket|'s ownership is handed to |transport|, but a pointer
// is retained in order to configure additional errors.
std::unique_ptr<SynchronousErrorStreamSocket> error_socket(
@@ -1564,7 +1599,7 @@ TEST_F(SSLClientSocketTest, Read_WithWriteError) {
FakeBlockingStreamSocket* raw_transport = transport.get();
int rv = callback.GetResult(transport->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Disable TLS False Start to avoid handshake non-determinism.
SSLConfig ssl_config;
@@ -1575,7 +1610,7 @@ TEST_F(SSLClientSocketTest, Read_WithWriteError) {
ssl_config));
rv = callback.GetResult(sock->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock->IsConnected());
// Send a request so there is something to read from the socket.
@@ -1594,7 +1629,7 @@ TEST_F(SSLClientSocketTest, Read_WithWriteError) {
raw_transport->BlockReadResult();
scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
rv = sock->Read(buf.get(), 4096, read_callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Perform another write, but have it fail. Write a request larger than the
// internal socket buffers so that the request hits the underlying transport
@@ -1626,7 +1661,7 @@ TEST_F(SSLClientSocketTest, Read_WithWriteError) {
}
} while (rv > 0);
- EXPECT_EQ(ERR_CONNECTION_RESET, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
// Release the read.
raw_transport->UnblockReadResult();
@@ -1643,11 +1678,11 @@ TEST_F(SSLClientSocketTest, Connect_WithZeroReturn) {
TestCompletionCallback callback;
std::unique_ptr<StreamSocket> real_transport(
- new TCPClientSocket(addr(), NULL, NULL, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
std::unique_ptr<SynchronousErrorStreamSocket> transport(
new SynchronousErrorStreamSocket(std::move(real_transport)));
int rv = callback.GetResult(transport->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
SynchronousErrorStreamSocket* raw_transport = transport.get();
std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
@@ -1657,7 +1692,7 @@ TEST_F(SSLClientSocketTest, Connect_WithZeroReturn) {
raw_transport->SetNextReadError(0);
rv = callback.GetResult(sock->Connect(callback.callback()));
- EXPECT_EQ(ERR_CONNECTION_CLOSED, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_CLOSED));
EXPECT_FALSE(sock->IsConnected());
}
@@ -1669,11 +1704,11 @@ TEST_F(SSLClientSocketTest, Read_WithZeroReturn) {
TestCompletionCallback callback;
std::unique_ptr<StreamSocket> real_transport(
- new TCPClientSocket(addr(), NULL, NULL, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
std::unique_ptr<SynchronousErrorStreamSocket> transport(
new SynchronousErrorStreamSocket(std::move(real_transport)));
int rv = callback.GetResult(transport->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Disable TLS False Start to ensure the handshake has completed.
SSLConfig ssl_config;
@@ -1685,7 +1720,7 @@ TEST_F(SSLClientSocketTest, Read_WithZeroReturn) {
ssl_config));
rv = callback.GetResult(sock->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock->IsConnected());
raw_transport->SetNextReadError(0);
@@ -1702,7 +1737,7 @@ TEST_F(SSLClientSocketTest, Read_WithAsyncZeroReturn) {
TestCompletionCallback callback;
std::unique_ptr<StreamSocket> real_transport(
- new TCPClientSocket(addr(), NULL, NULL, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
std::unique_ptr<SynchronousErrorStreamSocket> error_socket(
new SynchronousErrorStreamSocket(std::move(real_transport)));
SynchronousErrorStreamSocket* raw_error_socket = error_socket.get();
@@ -1710,7 +1745,7 @@ TEST_F(SSLClientSocketTest, Read_WithAsyncZeroReturn) {
new FakeBlockingStreamSocket(std::move(error_socket)));
FakeBlockingStreamSocket* raw_transport = transport.get();
int rv = callback.GetResult(transport->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Disable TLS False Start to ensure the handshake has completed.
SSLConfig ssl_config;
@@ -1721,14 +1756,14 @@ TEST_F(SSLClientSocketTest, Read_WithAsyncZeroReturn) {
ssl_config));
rv = callback.GetResult(sock->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock->IsConnected());
raw_error_socket->SetNextReadError(0);
raw_transport->BlockReadResult();
scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
rv = sock->Read(buf.get(), 4096, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
raw_transport->UnblockReadResult();
rv = callback.GetResult(rv);
@@ -1744,7 +1779,7 @@ TEST_F(SSLClientSocketTest, Read_WithFatalAlert) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Receive the fatal alert.
TestCompletionCallback callback;
@@ -1758,7 +1793,7 @@ TEST_F(SSLClientSocketTest, Read_SmallChunks) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
scoped_refptr<IOBuffer> request_buffer(
@@ -1783,19 +1818,19 @@ TEST_F(SSLClientSocketTest, Read_ManySmallRecords) {
TestCompletionCallback callback;
std::unique_ptr<StreamSocket> real_transport(
- new TCPClientSocket(addr(), NULL, NULL, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
std::unique_ptr<ReadBufferingStreamSocket> transport(
new ReadBufferingStreamSocket(std::move(real_transport)));
ReadBufferingStreamSocket* raw_transport = transport.get();
int rv = callback.GetResult(transport->Connect(callback.callback()));
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
std::move(transport), spawned_test_server()->host_port_pair(),
SSLConfig()));
rv = callback.GetResult(sock->Connect(callback.callback()));
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
ASSERT_TRUE(sock->IsConnected());
const char request_text[] = "GET /ssl-many-small-records HTTP/1.0\r\n\r\n";
@@ -1829,7 +1864,7 @@ TEST_F(SSLClientSocketTest, Read_Interrupted) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
scoped_refptr<IOBuffer> request_buffer(
@@ -1854,16 +1889,16 @@ TEST_F(SSLClientSocketTest, Read_FullLogging) {
TestNetLog log;
log.SetCaptureMode(NetLogCaptureMode::IncludeSocketBytes());
std::unique_ptr<StreamSocket> transport(
- new TCPClientSocket(addr(), NULL, &log, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, &log, NetLogSource()));
int rv = callback.GetResult(transport->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
std::move(transport), spawned_test_server()->host_port_pair(),
SSLConfig()));
rv = callback.GetResult(sock->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock->IsConnected());
const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
@@ -1878,7 +1913,8 @@ TEST_F(SSLClientSocketTest, Read_FullLogging) {
TestNetLogEntry::List entries;
log.GetEntries(&entries);
size_t last_index = ExpectLogContainsSomewhereAfter(
- entries, 5, NetLog::TYPE_SSL_SOCKET_BYTES_SENT, NetLog::PHASE_NONE);
+ entries, 5, NetLogEventType::SSL_SOCKET_BYTES_SENT,
+ NetLogEventPhase::NONE);
scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
for (;;) {
@@ -1888,11 +1924,9 @@ TEST_F(SSLClientSocketTest, Read_FullLogging) {
break;
log.GetEntries(&entries);
- last_index =
- ExpectLogContainsSomewhereAfter(entries,
- last_index + 1,
- NetLog::TYPE_SSL_SOCKET_BYTES_RECEIVED,
- NetLog::PHASE_NONE);
+ last_index = ExpectLogContainsSomewhereAfter(
+ entries, last_index + 1, NetLogEventType::SSL_SOCKET_BYTES_RECEIVED,
+ NetLogEventPhase::NONE);
}
}
@@ -1925,14 +1959,14 @@ TEST_F(SSLClientSocketTest, PrematureApplicationData) {
std::unique_ptr<StreamSocket> transport(
new MockTCPClientSocket(addr(), NULL, &data));
int rv = callback.GetResult(transport->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
std::move(transport), spawned_test_server()->host_port_pair(),
SSLConfig()));
rv = callback.GetResult(sock->Connect(callback.callback()));
- EXPECT_EQ(ERR_SSL_PROTOCOL_ERROR, rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_PROTOCOL_ERROR));
}
TEST_F(SSLClientSocketTest, CipherSuiteDisables) {
@@ -1956,7 +1990,7 @@ TEST_F(SSLClientSocketTest, CipherSuiteDisables) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(ERR_SSL_VERSION_OR_CIPHER_MISMATCH, rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_VERSION_OR_CIPHER_MISMATCH));
}
// When creating an SSLClientSocket, it is allowed to pass in a
@@ -1968,9 +2002,9 @@ TEST_F(SSLClientSocketTest, ClientSocketHandleNotFromPool) {
TestCompletionCallback callback;
std::unique_ptr<StreamSocket> transport(
- new TCPClientSocket(addr(), NULL, NULL, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
int rv = callback.GetResult(transport->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
std::unique_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle());
socket_handle->SetSocket(std::move(transport));
@@ -1981,7 +2015,7 @@ TEST_F(SSLClientSocketTest, ClientSocketHandleNotFromPool) {
EXPECT_FALSE(sock->IsConnected());
rv = callback.GetResult(sock->Connect(callback.callback()));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
// Verifies that SSLClientSocket::ExportKeyingMaterial return a success
@@ -1991,7 +2025,7 @@ TEST_F(SSLClientSocketTest, ExportKeyingMaterial) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock_->IsConnected());
const int kKeyingMaterialSize = 32;
@@ -2035,10 +2069,10 @@ TEST(SSLClientSocket, ClearSessionCache) {
TEST(SSLClientSocket, SerializeNextProtos) {
NextProtoVector next_protos;
next_protos.push_back(kProtoHTTP11);
- next_protos.push_back(kProtoSPDY31);
+ next_protos.push_back(kProtoHTTP2);
static std::vector<uint8_t> serialized =
SSLClientSocket::SerializeNextProtos(next_protos);
- ASSERT_EQ(18u, serialized.size());
+ ASSERT_EQ(12u, serialized.size());
EXPECT_EQ(8, serialized[0]); // length("http/1.1")
EXPECT_EQ('h', serialized[1]);
EXPECT_EQ('t', serialized[2]);
@@ -2048,15 +2082,9 @@ TEST(SSLClientSocket, SerializeNextProtos) {
EXPECT_EQ('1', serialized[6]);
EXPECT_EQ('.', serialized[7]);
EXPECT_EQ('1', serialized[8]);
- EXPECT_EQ(8, serialized[9]); // length("spdy/3.1")
- EXPECT_EQ('s', serialized[10]);
- EXPECT_EQ('p', serialized[11]);
- EXPECT_EQ('d', serialized[12]);
- EXPECT_EQ('y', serialized[13]);
- EXPECT_EQ('/', serialized[14]);
- EXPECT_EQ('3', serialized[15]);
- EXPECT_EQ('.', serialized[16]);
- EXPECT_EQ('1', serialized[17]);
+ EXPECT_EQ(2, serialized[9]); // length("h2")
+ EXPECT_EQ('h', serialized[10]);
+ EXPECT_EQ('2', serialized[11]);
}
// Test that the server certificates are properly retrieved from the underlying
@@ -2074,7 +2102,7 @@ TEST_F(SSLClientSocketTest, VerifyServerChainProperlyOrdered) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
- EXPECT_EQ(ERR_CERT_INVALID, rv);
+ EXPECT_THAT(rv, IsError(ERR_CERT_INVALID));
EXPECT_TRUE(sock_->IsConnected());
// When given option CERT_CHAIN_WRONG_ROOT, SpawnedTestServer will present
@@ -2142,6 +2170,8 @@ TEST_F(SSLClientSocketTest, VerifyReturnChainProperlyOrdered) {
X509Certificate::FORMAT_AUTO);
ASSERT_EQ(3U, certs.size());
+ 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());
@@ -2167,18 +2197,19 @@ TEST_F(SSLClientSocketTest, VerifyReturnChainProperlyOrdered) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock_->IsConnected());
TestNetLogEntry::List entries;
log_.GetEntries(&entries);
- EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLog::TYPE_SSL_CONNECT));
+ EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLogEventType::SSL_CONNECT));
SSLInfo ssl_info;
- sock_->GetSSLInfo(&ssl_info);
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
// 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();
ASSERT_EQ(2U, intermediates.size());
@@ -2190,6 +2221,7 @@ TEST_F(SSLClientSocketTest, VerifyReturnChainProperlyOrdered) {
certs[2]->os_cert_handle()));
// 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();
ASSERT_EQ(3U, served_intermediates.size());
@@ -2287,7 +2319,7 @@ TEST_F(SSLClientSocketTest, ConnectSignedCertTimestampsEnabledTLSExtension) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock_->signed_cert_timestamps_received_);
}
@@ -2305,7 +2337,7 @@ TEST_F(SSLClientSocketTest, EVCertStatusMaintainedNoCTVerifier) {
// No verifier to skip CT and policy checks.
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
SSLInfo result;
ASSERT_TRUE(sock_->GetSSLInfo(&result));
@@ -2341,7 +2373,7 @@ TEST_F(SSLClientSocketTest, EVCertStatusMaintainedForCompliantCert) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
SSLInfo result;
ASSERT_TRUE(sock_->GetSSLInfo(&result));
@@ -2377,7 +2409,7 @@ TEST_F(SSLClientSocketTest, EVCertStatusRemovedForNonCompliantCert) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
SSLInfo result;
ASSERT_TRUE(sock_->GetSSLInfo(&result));
@@ -2430,7 +2462,7 @@ TEST_F(SSLClientSocketTest, ConnectSignedCertTimestampsEnabledOCSP) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock_->stapled_ocsp_response_received_);
}
@@ -2446,7 +2478,7 @@ TEST_F(SSLClientSocketTest, ConnectSignedCertTimestampsDisabled) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_FALSE(sock_->signed_cert_timestamps_received_);
}
@@ -2492,16 +2524,17 @@ TEST_F(SSLClientSocketTest, ReusableAfterWrite) {
TestCompletionCallback callback;
std::unique_ptr<StreamSocket> real_transport(
- new TCPClientSocket(addr(), NULL, NULL, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
std::unique_ptr<FakeBlockingStreamSocket> transport(
new FakeBlockingStreamSocket(std::move(real_transport)));
FakeBlockingStreamSocket* raw_transport = transport.get();
- ASSERT_EQ(OK, callback.GetResult(transport->Connect(callback.callback())));
+ ASSERT_THAT(callback.GetResult(transport->Connect(callback.callback())),
+ IsOk());
std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
std::move(transport), spawned_test_server()->host_port_pair(),
SSLConfig()));
- ASSERT_EQ(OK, callback.GetResult(sock->Connect(callback.callback())));
+ ASSERT_THAT(callback.GetResult(sock->Connect(callback.callback())), IsOk());
// Block any application data from reaching the network.
raw_transport->BlockWrite();
@@ -2534,26 +2567,27 @@ TEST_F(SSLClientSocketTest, SessionResumption) {
SSLConfig ssl_config;
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
SSLInfo ssl_info;
ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
// The next connection should resume.
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
sock_.reset();
// Using a different HostPortPair uses a different session cache key.
std::unique_ptr<StreamSocket> transport(
- new TCPClientSocket(addr(), NULL, &log_, NetLog::Source()));
+ new TCPClientSocket(addr(), NULL, &log_, NetLogSource()));
TestCompletionCallback callback;
- ASSERT_EQ(OK, callback.GetResult(transport->Connect(callback.callback())));
+ ASSERT_THAT(callback.GetResult(transport->Connect(callback.callback())),
+ IsOk());
std::unique_ptr<SSLClientSocket> sock = CreateSSLClientSocket(
std::move(transport), HostPortPair("example.com", 443), ssl_config);
- ASSERT_EQ(OK, callback.GetResult(sock->Connect(callback.callback())));
+ ASSERT_THAT(callback.GetResult(sock->Connect(callback.callback())), IsOk());
ASSERT_TRUE(sock->GetSSLInfo(&ssl_info));
EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
sock.reset();
@@ -2562,9 +2596,39 @@ TEST_F(SSLClientSocketTest, SessionResumption) {
// After clearing the session cache, the next handshake doesn't resume.
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
+ EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
+}
+
+// Tests that ALPN works with session resumption.
+TEST_F(SSLClientSocketTest, SessionResumptionAlpn) {
+ SpawnedTestServer::SSLOptions ssl_options;
+ ssl_options.alpn_protocols.push_back("h2");
+ ssl_options.alpn_protocols.push_back("http/1.1");
+ ASSERT_TRUE(StartTestServer(ssl_options));
+
+ // First, perform a full handshake.
+ SSLConfig ssl_config;
+ // Disable TLS False Start to ensure the handshake has completed.
+ ssl_config.false_start_enabled = false;
+ ssl_config.alpn_protos.push_back(kProtoHTTP2);
+ int rv;
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+ ASSERT_THAT(rv, IsOk());
+ SSLInfo ssl_info;
ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
+ EXPECT_EQ(kProtoHTTP2, sock_->GetNegotiatedProtocol());
+
+ // The next connection should resume; ALPN should be renegotiated.
+ ssl_config.alpn_protos.clear();
+ ssl_config.alpn_protos.push_back(kProtoHTTP11);
+ ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+ ASSERT_THAT(rv, IsOk());
+ ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
+ EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
+ EXPECT_EQ(kProtoHTTP11, sock_->GetNegotiatedProtocol());
}
// Tests that connections with certificate errors do not add entries to the
@@ -2578,74 +2642,18 @@ TEST_F(SSLClientSocketTest, CertificateErrorNoResume) {
SSLConfig ssl_config;
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- ASSERT_EQ(ERR_CERT_COMMON_NAME_INVALID, rv);
+ ASSERT_THAT(rv, IsError(ERR_CERT_COMMON_NAME_INVALID));
cert_verifier_->set_default_result(OK);
// The next connection should perform a full handshake.
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
SSLInfo ssl_info;
ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
}
-// Tests that session caches are sharded by max_version.
-TEST_F(SSLClientSocketTest, FallbackShardSessionCache) {
- ASSERT_TRUE(StartTestServer(SpawnedTestServer::SSLOptions()));
-
- // Prepare a normal and fallback SSL config.
- SSLConfig ssl_config;
- SSLConfig fallback_ssl_config;
- fallback_ssl_config.version_max = SSL_PROTOCOL_VERSION_TLS1;
- fallback_ssl_config.version_fallback_min = SSL_PROTOCOL_VERSION_TLS1;
- fallback_ssl_config.version_fallback = true;
-
- // Connect with a fallback config from the test server to add an entry to the
- // session cache.
- int rv;
- ASSERT_TRUE(CreateAndConnectSSLClientSocket(fallback_ssl_config, &rv));
- EXPECT_EQ(OK, rv);
- SSLInfo ssl_info;
- EXPECT_TRUE(sock_->GetSSLInfo(&ssl_info));
- EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
- EXPECT_EQ(SSL_CONNECTION_VERSION_TLS1,
- SSLConnectionStatusToVersion(ssl_info.connection_status));
-
- // A non-fallback connection needs a full handshake.
- ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
- EXPECT_TRUE(sock_->GetSSLInfo(&ssl_info));
- EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
- EXPECT_EQ(SSL_CONNECTION_VERSION_TLS1_2,
- SSLConnectionStatusToVersion(ssl_info.connection_status));
-
- // Note: if the server (correctly) declines to resume a TLS 1.0 session at TLS
- // 1.2, the above test would not be sufficient to prove the session caches are
- // sharded. Implementations vary here, so, to avoid being sensitive to this,
- // attempt to resume with two more connections.
-
- // The non-fallback connection added a > TLS 1.0 entry to the session cache.
- ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
- EXPECT_TRUE(sock_->GetSSLInfo(&ssl_info));
- EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
- // This does not check for equality because TLS 1.2 support is conditional on
- // system NSS features.
- EXPECT_LT(SSL_CONNECTION_VERSION_TLS1,
- SSLConnectionStatusToVersion(ssl_info.connection_status));
-
- // The fallback connection still resumes from its session cache. It cannot
- // offer the > TLS 1.0 session, so this must have been the session from the
- // first fallback connection.
- ASSERT_TRUE(CreateAndConnectSSLClientSocket(fallback_ssl_config, &rv));
- EXPECT_EQ(OK, rv);
- EXPECT_TRUE(sock_->GetSSLInfo(&ssl_info));
- EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
- EXPECT_EQ(SSL_CONNECTION_VERSION_TLS1,
- SSLConnectionStatusToVersion(ssl_info.connection_status));
-}
-
// Test that DHE is removed but gives a dedicated error. Also test that the
// dhe_enabled option can restore it.
TEST_F(SSLClientSocketTest, DHE) {
@@ -2658,22 +2666,22 @@ TEST_F(SSLClientSocketTest, DHE) {
SSLConfig ssl_config;
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(ERR_SSL_VERSION_OR_CIPHER_MISMATCH, rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_VERSION_OR_CIPHER_MISMATCH));
ssl_config.dhe_enabled = true;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(ERR_SSL_VERSION_OR_CIPHER_MISMATCH, rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_VERSION_OR_CIPHER_MISMATCH));
// Enabling deprecated ciphers gives DHE a dedicated error code.
ssl_config.dhe_enabled = false;
ssl_config.deprecated_cipher_suites_enabled = true;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(ERR_SSL_OBSOLETE_CIPHER, rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_OBSOLETE_CIPHER));
// Enabling both deprecated ciphers and DHE restores it.
ssl_config.dhe_enabled = true;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
}
// Tests that enabling deprecated ciphers shards the session cache.
@@ -2688,20 +2696,20 @@ TEST_F(SSLClientSocketTest, DeprecatedShardSessionCache) {
// Connect with deprecated ciphers enabled to warm the session cache cache.
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(deprecated_ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
SSLInfo ssl_info;
EXPECT_TRUE(sock_->GetSSLInfo(&ssl_info));
EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
// Test that re-connecting with deprecated ciphers enabled still resumes.
ASSERT_TRUE(CreateAndConnectSSLClientSocket(deprecated_ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock_->GetSSLInfo(&ssl_info));
EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
// However, a normal connection needs a full handshake.
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock_->GetSSLInfo(&ssl_info));
EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
@@ -2710,19 +2718,19 @@ TEST_F(SSLClientSocketTest, DeprecatedShardSessionCache) {
// Now make a normal connection to prime the session cache.
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock_->GetSSLInfo(&ssl_info));
EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
// A normal connection should be able to resume.
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock_->GetSSLInfo(&ssl_info));
EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
// However, enabling deprecated ciphers connects fresh.
ASSERT_TRUE(CreateAndConnectSSLClientSocket(deprecated_ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock_->GetSSLInfo(&ssl_info));
EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
}
@@ -2737,7 +2745,7 @@ TEST_F(SSLClientSocketTest, RequireECDHE) {
config.require_ecdhe = true;
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(config, &rv));
- EXPECT_EQ(ERR_SSL_VERSION_OR_CIPHER_MISMATCH, rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_VERSION_OR_CIPHER_MISMATCH));
}
TEST_F(SSLClientSocketTest, TokenBindingEnabled) {
@@ -2750,7 +2758,7 @@ TEST_F(SSLClientSocketTest, TokenBindingEnabled) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
SSLInfo info;
EXPECT_TRUE(sock_->GetSSLInfo(&info));
EXPECT_TRUE(info.token_binding_negotiated);
@@ -2768,7 +2776,7 @@ TEST_F(SSLClientSocketTest, TokenBindingFailsWithEmsDisabled) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(ERR_SSL_PROTOCOL_ERROR, rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_PROTOCOL_ERROR));
}
TEST_F(SSLClientSocketTest, TokenBindingEnabledWithoutServerSupport) {
@@ -2780,32 +2788,27 @@ TEST_F(SSLClientSocketTest, TokenBindingEnabledWithoutServerSupport) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
SSLInfo info;
EXPECT_TRUE(sock_->GetSSLInfo(&info));
EXPECT_FALSE(info.token_binding_negotiated);
}
-// In tests requiring NPN, client_config.alpn_protos and
-// client_config.npn_protos both need to be set when using NSS, otherwise NPN is
-// disabled due to quirks of the implementation.
-
TEST_F(SSLClientSocketFalseStartTest, FalseStartEnabled) {
- // False Start requires NPN/ALPN, ECDHE, and an AEAD.
+ // False Start requires ALPN, ECDHE, and an AEAD.
SpawnedTestServer::SSLOptions server_options;
server_options.key_exchanges =
SpawnedTestServer::SSLOptions::KEY_EXCHANGE_ECDHE_RSA;
server_options.bulk_ciphers =
SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM;
- server_options.npn_protocols.push_back(std::string("http/1.1"));
+ server_options.alpn_protocols.push_back("http/1.1");
SSLConfig client_config;
- client_config.npn_protos.push_back(kProtoHTTP11);
- ASSERT_NO_FATAL_FAILURE(
- TestFalseStart(server_options, client_config, true));
+ client_config.alpn_protos.push_back(kProtoHTTP11);
+ ASSERT_NO_FATAL_FAILURE(TestFalseStart(server_options, client_config, true));
}
-// Test that False Start is disabled without NPN.
-TEST_F(SSLClientSocketFalseStartTest, NoNPN) {
+// Test that False Start is disabled without ALPN.
+TEST_F(SSLClientSocketFalseStartTest, NoAlpn) {
SpawnedTestServer::SSLOptions server_options;
server_options.key_exchanges =
SpawnedTestServer::SSLOptions::KEY_EXCHANGE_ECDHE_RSA;
@@ -2813,7 +2816,6 @@ TEST_F(SSLClientSocketFalseStartTest, NoNPN) {
SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM;
SSLConfig client_config;
client_config.alpn_protos.clear();
- client_config.npn_protos.clear();
ASSERT_NO_FATAL_FAILURE(
TestFalseStart(server_options, client_config, false));
}
@@ -2825,9 +2827,9 @@ TEST_F(SSLClientSocketFalseStartTest, RSA) {
SpawnedTestServer::SSLOptions::KEY_EXCHANGE_RSA;
server_options.bulk_ciphers =
SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM;
- server_options.npn_protocols.push_back(std::string("http/1.1"));
+ server_options.alpn_protocols.push_back("http/1.1");
SSLConfig client_config;
- client_config.npn_protos.push_back(kProtoHTTP11);
+ client_config.alpn_protos.push_back(kProtoHTTP11);
ASSERT_NO_FATAL_FAILURE(
TestFalseStart(server_options, client_config, false));
}
@@ -2839,9 +2841,9 @@ TEST_F(SSLClientSocketFalseStartTest, DHE_RSA) {
SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA;
server_options.bulk_ciphers =
SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM;
- server_options.npn_protocols.push_back(std::string("http/1.1"));
+ server_options.alpn_protocols.push_back("http/1.1");
SSLConfig client_config;
- client_config.npn_protos.push_back(kProtoHTTP11);
+ client_config.alpn_protos.push_back(kProtoHTTP11);
// DHE is only advertised when deprecated ciphers are enabled.
client_config.deprecated_cipher_suites_enabled = true;
ASSERT_NO_FATAL_FAILURE(TestFalseStart(server_options, client_config, false));
@@ -2854,9 +2856,9 @@ TEST_F(SSLClientSocketFalseStartTest, NoAEAD) {
SpawnedTestServer::SSLOptions::KEY_EXCHANGE_ECDHE_RSA;
server_options.bulk_ciphers =
SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128;
- server_options.npn_protocols.push_back(std::string("http/1.1"));
+ server_options.alpn_protocols.push_back("http/1.1");
SSLConfig client_config;
- client_config.npn_protos.push_back(kProtoHTTP11);
+ client_config.alpn_protos.push_back(kProtoHTTP11);
ASSERT_NO_FATAL_FAILURE(TestFalseStart(server_options, client_config, false));
}
@@ -2868,9 +2870,9 @@ TEST_F(SSLClientSocketFalseStartTest, SessionResumption) {
SpawnedTestServer::SSLOptions::KEY_EXCHANGE_ECDHE_RSA;
server_options.bulk_ciphers =
SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM;
- server_options.npn_protocols.push_back(std::string("http/1.1"));
+ server_options.alpn_protocols.push_back("http/1.1");
SSLConfig client_config;
- client_config.npn_protos.push_back(kProtoHTTP11);
+ client_config.alpn_protos.push_back(kProtoHTTP11);
// Let a full handshake complete with False Start.
ASSERT_NO_FATAL_FAILURE(
@@ -2879,7 +2881,7 @@ TEST_F(SSLClientSocketFalseStartTest, SessionResumption) {
// Make a second connection.
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(client_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// It should resume the session.
SSLInfo ssl_info;
@@ -2896,11 +2898,11 @@ TEST_F(SSLClientSocketFalseStartTest, NoSessionResumptionBeforeFinished) {
SpawnedTestServer::SSLOptions::KEY_EXCHANGE_ECDHE_RSA;
server_options.bulk_ciphers =
SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM;
- server_options.npn_protocols.push_back(std::string("http/1.1"));
+ server_options.alpn_protocols.push_back("http/1.1");
ASSERT_TRUE(StartTestServer(server_options));
SSLConfig client_config;
- client_config.npn_protos.push_back(kProtoHTTP11);
+ client_config.alpn_protos.push_back(kProtoHTTP11);
// Start a handshake up to the server Finished message.
TestCompletionCallback callback;
@@ -2910,7 +2912,7 @@ TEST_F(SSLClientSocketFalseStartTest, NoSessionResumptionBeforeFinished) {
client_config, &callback, &raw_transport1, &sock1));
// Although raw_transport1 has the server Finished blocked, the handshake
// still completes.
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// Continue to block the client (|sock1|) from processing the Finished
// message, but allow it to arrive on the socket. This ensures that, from the
@@ -2923,7 +2925,7 @@ TEST_F(SSLClientSocketFalseStartTest, NoSessionResumptionBeforeFinished) {
// doesn't come in one Read.
scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
int rv = sock1->Read(buf.get(), 4096, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
raw_transport1->WaitForReadResult();
// Drop the old socket. This is needed because the Python test server can't
@@ -2932,7 +2934,7 @@ TEST_F(SSLClientSocketFalseStartTest, NoSessionResumptionBeforeFinished) {
// Start a second connection.
ASSERT_TRUE(CreateAndConnectSSLClientSocket(client_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// No session resumption because the first connection never received a server
// Finished message.
@@ -2950,11 +2952,11 @@ TEST_F(SSLClientSocketFalseStartTest, NoSessionResumptionBadFinished) {
SpawnedTestServer::SSLOptions::KEY_EXCHANGE_ECDHE_RSA;
server_options.bulk_ciphers =
SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM;
- server_options.npn_protocols.push_back(std::string("http/1.1"));
+ server_options.alpn_protocols.push_back("http/1.1");
ASSERT_TRUE(StartTestServer(server_options));
SSLConfig client_config;
- client_config.npn_protos.push_back(kProtoHTTP11);
+ client_config.alpn_protos.push_back(kProtoHTTP11);
// Start a handshake up to the server Finished message.
TestCompletionCallback callback;
@@ -2964,7 +2966,7 @@ TEST_F(SSLClientSocketFalseStartTest, NoSessionResumptionBadFinished) {
client_config, &callback, &raw_transport1, &sock1));
// Although raw_transport1 has the server Finished blocked, the handshake
// still completes.
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// Continue to block the client (|sock1|) from processing the Finished
// message, but allow it to arrive on the socket. This ensures that, from the
@@ -2976,7 +2978,7 @@ TEST_F(SSLClientSocketFalseStartTest, NoSessionResumptionBadFinished) {
// the socket.
scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
int rv = sock1->Read(buf.get(), 4096, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
raw_transport1->WaitForReadResult();
// The server's second leg, or part of it, is now received but not yet sent to
@@ -2987,7 +2989,7 @@ TEST_F(SSLClientSocketFalseStartTest, NoSessionResumptionBadFinished) {
// Unblock the Finished message. |sock1->Read| should now fail.
raw_transport1->UnblockReadResult();
- EXPECT_EQ(ERR_SSL_PROTOCOL_ERROR, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsError(ERR_SSL_PROTOCOL_ERROR));
// Drop the old socket. This is needed because the Python test server can't
// service two sockets in parallel.
@@ -2995,7 +2997,7 @@ TEST_F(SSLClientSocketFalseStartTest, NoSessionResumptionBadFinished) {
// Start a second connection.
ASSERT_TRUE(CreateAndConnectSSLClientSocket(client_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// No session resumption because the first connection never received a server
// Finished message.
@@ -3017,7 +3019,7 @@ TEST_F(SSLClientSocketChannelIDTest, SendChannelID) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock_->IsConnected());
SSLInfo ssl_info;
ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
@@ -3063,7 +3065,7 @@ TEST_F(SSLClientSocketChannelIDTest, FailingChannelIDAsync) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(ERR_UNEXPECTED, rv);
+ EXPECT_THAT(rv, IsError(ERR_UNEXPECTED));
EXPECT_FALSE(sock_->IsConnected());
}
@@ -3093,100 +3095,37 @@ TEST_F(SSLClientSocketChannelIDTest, ChannelIDShardSessionCache) {
EXPECT_TRUE(ssl_info.channel_id_sent);
}
-TEST_F(SSLClientSocketTest, NPN) {
- SpawnedTestServer::SSLOptions server_options;
- server_options.npn_protocols.push_back(std::string("spdy/3.1"));
- server_options.npn_protocols.push_back(std::string("h2"));
- ASSERT_TRUE(StartTestServer(server_options));
-
- SSLConfig client_config;
- client_config.npn_protos.push_back(kProtoHTTP2);
- client_config.npn_protos.push_back(kProtoHTTP11);
-
- int rv;
- ASSERT_TRUE(CreateAndConnectSSLClientSocket(client_config, &rv));
- EXPECT_EQ(OK, rv);
-
- std::string proto;
- EXPECT_EQ(SSLClientSocket::kNextProtoNegotiated, sock_->GetNextProto(&proto));
- EXPECT_EQ("h2", proto);
-}
-
-// In case of no overlap between client and server list, SSLClientSocket should
-// fall back to last one on the client list.
-TEST_F(SSLClientSocketTest, NPNNoOverlap) {
- SpawnedTestServer::SSLOptions server_options;
- server_options.npn_protocols.push_back(std::string("http/1.1"));
- ASSERT_TRUE(StartTestServer(server_options));
-
- SSLConfig client_config;
- client_config.npn_protos.push_back(kProtoSPDY31);
- client_config.npn_protos.push_back(kProtoHTTP2);
-
- int rv;
- ASSERT_TRUE(CreateAndConnectSSLClientSocket(client_config, &rv));
- EXPECT_EQ(OK, rv);
-
- std::string proto;
- EXPECT_EQ(SSLClientSocket::kNextProtoNoOverlap, sock_->GetNextProto(&proto));
- EXPECT_EQ("h2", proto);
-}
-
-// Server preference should be respected. The list is in decreasing order of
-// preference.
-TEST_F(SSLClientSocketTest, NPNServerPreference) {
- SpawnedTestServer::SSLOptions server_options;
- server_options.npn_protocols.push_back(std::string("spdy/3.1"));
- server_options.npn_protocols.push_back(std::string("h2"));
- ASSERT_TRUE(StartTestServer(server_options));
-
- SSLConfig client_config;
- client_config.npn_protos.push_back(kProtoHTTP2);
- client_config.npn_protos.push_back(kProtoSPDY31);
-
- int rv;
- ASSERT_TRUE(CreateAndConnectSSLClientSocket(client_config, &rv));
- EXPECT_EQ(OK, rv);
-
- std::string proto;
- EXPECT_EQ(SSLClientSocket::kNextProtoNegotiated, sock_->GetNextProto(&proto));
- EXPECT_EQ("spdy/3.1", proto);
-}
-
-// If npn_protos.empty(), then NPN should be disabled, even if
-// !alpn_protos.empty(). Tlslite does not support ALPN, therefore if NPN is
-// disabled in the client, no protocol should be negotiated.
-TEST_F(SSLClientSocketTest, NPNClientDisabled) {
+// Server preference should win in ALPN.
+TEST_F(SSLClientSocketTest, Alpn) {
SpawnedTestServer::SSLOptions server_options;
- server_options.npn_protocols.push_back(std::string("http/1.1"));
+ server_options.alpn_protocols.push_back("h2");
+ server_options.alpn_protocols.push_back("http/1.1");
ASSERT_TRUE(StartTestServer(server_options));
SSLConfig client_config;
client_config.alpn_protos.push_back(kProtoHTTP11);
+ client_config.alpn_protos.push_back(kProtoHTTP2);
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(client_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- std::string proto;
- EXPECT_EQ(SSLClientSocket::kNextProtoUnsupported,
- sock_->GetNextProto(&proto));
+ EXPECT_EQ(kProtoHTTP2, sock_->GetNegotiatedProtocol());
}
-TEST_F(SSLClientSocketTest, NPNServerDisabled) {
+// If the server supports ALPN but the client does not, then ALPN is not used.
+TEST_F(SSLClientSocketTest, AlpnClientDisabled) {
SpawnedTestServer::SSLOptions server_options;
+ server_options.alpn_protocols.push_back("foo");
ASSERT_TRUE(StartTestServer(server_options));
SSLConfig client_config;
- client_config.npn_protos.push_back(kProtoHTTP11);
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(client_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- std::string proto;
- EXPECT_EQ(SSLClientSocket::kNextProtoUnsupported,
- sock_->GetNextProto(&proto));
+ EXPECT_EQ(kProtoUnknown, sock_->GetNegotiatedProtocol());
}
namespace {
@@ -3228,7 +3167,7 @@ TEST_F(SSLClientSocketTest, NoCert) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
- EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
EXPECT_FALSE(sock_->IsConnected());
}
@@ -3250,7 +3189,7 @@ TEST_F(SSLClientSocketTest, SendEmptyCert) {
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock_->IsConnected());
SSLInfo ssl_info;
@@ -3272,16 +3211,13 @@ TEST_F(SSLClientSocketTest, SendGoodCert) {
SSLConfig ssl_config;
ssl_config.send_client_cert = true;
ssl_config.client_cert = ImportCertFromFile(certs_dir, "client_1.pem");
-
- // This is required to ensure that signing works with the client
- // certificate's private key.
ssl_config.client_private_key =
LoadPrivateKeyOpenSSL(certs_dir.AppendASCII("client_1.key"));
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock_->IsConnected());
SSLInfo ssl_info;
@@ -3329,7 +3265,7 @@ TEST_F(SSLClientSocketTest, PKPBypassedSet) {
SSLInfo ssl_info;
ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(sock_->IsConnected());
EXPECT_TRUE(ssl_info.pkp_bypassed);
@@ -3363,7 +3299,7 @@ TEST_F(SSLClientSocketTest, PKPEnforced) {
SSLInfo ssl_info;
ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
- EXPECT_EQ(ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN, rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN));
EXPECT_TRUE(ssl_info.cert_status & CERT_STATUS_PINNED_KEY_MISSING);
EXPECT_TRUE(sock_->IsConnected());
@@ -3407,7 +3343,7 @@ TEST_F(SSLClientSocketTest, CTIsRequired) {
SSLInfo ssl_info;
ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
- EXPECT_EQ(ERR_CERTIFICATE_TRANSPARENCY_REQUIRED, rv);
+ EXPECT_THAT(rv, IsError(ERR_CERTIFICATE_TRANSPARENCY_REQUIRED));
EXPECT_TRUE(ssl_info.cert_status &
CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED);
EXPECT_TRUE(sock_->IsConnected());
@@ -3458,11 +3394,286 @@ TEST_F(SSLClientSocketTest, PKPMoreImportantThanCT) {
SSLInfo ssl_info;
ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info));
- EXPECT_EQ(ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN, rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN));
EXPECT_TRUE(ssl_info.cert_status & CERT_STATUS_PINNED_KEY_MISSING);
EXPECT_TRUE(ssl_info.cert_status &
CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED);
EXPECT_TRUE(sock_->IsConnected());
}
+// Test that handshake_failure alerts at the ServerHello are mapped to
+// ERR_SSL_VERSION_OR_CIPHER_MISMATCH.
+TEST_F(SSLClientSocketTest, HandshakeFailureServerHello) {
+ ASSERT_TRUE(StartTestServer(SpawnedTestServer::SSLOptions()));
+
+ TestCompletionCallback callback;
+ std::unique_ptr<StreamSocket> real_transport(
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
+ std::unique_ptr<FakeBlockingStreamSocket> transport(
+ new FakeBlockingStreamSocket(std::move(real_transport)));
+ FakeBlockingStreamSocket* raw_transport = transport.get();
+ int rv = callback.GetResult(transport->Connect(callback.callback()));
+ ASSERT_THAT(rv, IsOk());
+
+ std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+ std::move(transport), spawned_test_server()->host_port_pair(),
+ SSLConfig()));
+
+ // Connect. Stop before the client processes ServerHello.
+ raw_transport->BlockReadResult();
+ rv = sock->Connect(callback.callback());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
+ raw_transport->WaitForReadResult();
+
+ // Replace it with an alert.
+ raw_transport->ReplaceReadResult(
+ FormatTLS12Alert(40 /* AlertDescription.handshake_failure */));
+ raw_transport->UnblockReadResult();
+
+ rv = callback.GetResult(rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_VERSION_OR_CIPHER_MISMATCH));
+}
+
+// Test that handshake_failure alerts after the ServerHello but without a
+// CertificateRequest are mapped to ERR_SSL_PROTOCOL_ERROR.
+TEST_F(SSLClientSocketTest, HandshakeFailureNoClientCerts) {
+ ASSERT_TRUE(StartTestServer(SpawnedTestServer::SSLOptions()));
+
+ TestCompletionCallback callback;
+ std::unique_ptr<StreamSocket> real_transport(
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
+ std::unique_ptr<FakeBlockingStreamSocket> transport(
+ new FakeBlockingStreamSocket(std::move(real_transport)));
+ FakeBlockingStreamSocket* raw_transport = transport.get();
+ int rv = callback.GetResult(transport->Connect(callback.callback()));
+ ASSERT_THAT(rv, IsOk());
+
+ std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+ std::move(transport), spawned_test_server()->host_port_pair(),
+ SSLConfig()));
+
+ // Connect. Stop before the client processes ServerHello.
+ raw_transport->BlockReadResult();
+ rv = sock->Connect(callback.callback());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
+ raw_transport->WaitForReadResult();
+
+ // Release the ServerHello and wait for the client to write its second flight.
+ raw_transport->BlockWrite();
+ raw_transport->UnblockReadResult();
+ raw_transport->WaitForWrite();
+
+ // Wait for the server's final flight.
+ raw_transport->BlockReadResult();
+ raw_transport->UnblockWrite();
+ raw_transport->WaitForReadResult();
+
+ // Replace it with an alert.
+ raw_transport->ReplaceReadResult(
+ FormatTLS12Alert(40 /* AlertDescription.handshake_failure */));
+ raw_transport->UnblockReadResult();
+
+ rv = callback.GetResult(rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_PROTOCOL_ERROR));
+}
+
+// Test that handshake_failure alerts after the ServerHello map to
+// ERR_BAD_SSL_CLIENT_AUTH_CERT if a client certificate was requested but not
+// supplied. TLS does not have an alert for this case, so handshake_failure is
+// common. See https://crbug.com/646567.
+TEST_F(SSLClientSocketTest, LateHandshakeFailureMissingClientCerts) {
+ // Request a client certificate.
+ SpawnedTestServer::SSLOptions ssl_options;
+ ssl_options.request_client_certificate = true;
+ ASSERT_TRUE(StartTestServer(ssl_options));
+
+ TestCompletionCallback callback;
+ std::unique_ptr<StreamSocket> real_transport(
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
+ std::unique_ptr<FakeBlockingStreamSocket> transport(
+ new FakeBlockingStreamSocket(std::move(real_transport)));
+ FakeBlockingStreamSocket* raw_transport = transport.get();
+ int rv = callback.GetResult(transport->Connect(callback.callback()));
+ ASSERT_THAT(rv, IsOk());
+
+ // Send no client certificate.
+ SSLConfig config;
+ config.send_client_cert = true;
+ std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+ std::move(transport), spawned_test_server()->host_port_pair(), config));
+
+ // Connect. Stop before the client processes ServerHello.
+ raw_transport->BlockReadResult();
+ rv = sock->Connect(callback.callback());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
+ raw_transport->WaitForReadResult();
+
+ // Release the ServerHello and wait for the client to write its second flight.
+ raw_transport->BlockWrite();
+ raw_transport->UnblockReadResult();
+ raw_transport->WaitForWrite();
+
+ // Wait for the server's final flight.
+ raw_transport->BlockReadResult();
+ raw_transport->UnblockWrite();
+ raw_transport->WaitForReadResult();
+
+ // Replace it with an alert.
+ raw_transport->ReplaceReadResult(
+ FormatTLS12Alert(40 /* AlertDescription.handshake_failure */));
+ raw_transport->UnblockReadResult();
+
+ rv = callback.GetResult(rv);
+ EXPECT_THAT(rv, IsError(ERR_BAD_SSL_CLIENT_AUTH_CERT));
+}
+
+// Test that handshake_failure alerts after the ServerHello map to
+// ERR_SSL_PROTOCOL_ERROR if received after sending a client certificate. It is
+// assumed servers will send a more appropriate alert in this case.
+TEST_F(SSLClientSocketTest, LateHandshakeFailureSendClientCerts) {
+ // Request a client certificate.
+ SpawnedTestServer::SSLOptions ssl_options;
+ ssl_options.request_client_certificate = true;
+ ASSERT_TRUE(StartTestServer(ssl_options));
+
+ TestCompletionCallback callback;
+ std::unique_ptr<StreamSocket> real_transport(
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
+ std::unique_ptr<FakeBlockingStreamSocket> transport(
+ new FakeBlockingStreamSocket(std::move(real_transport)));
+ FakeBlockingStreamSocket* raw_transport = transport.get();
+ int rv = callback.GetResult(transport->Connect(callback.callback()));
+ ASSERT_THAT(rv, IsOk());
+
+ // Send a client certificate.
+ base::FilePath certs_dir = GetTestCertsDirectory();
+ SSLConfig config;
+ config.send_client_cert = true;
+ config.client_cert = ImportCertFromFile(certs_dir, "client_1.pem");
+ config.client_private_key =
+ LoadPrivateKeyOpenSSL(certs_dir.AppendASCII("client_1.key"));
+ std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+ std::move(transport), spawned_test_server()->host_port_pair(), config));
+
+ // Connect. Stop before the client processes ServerHello.
+ raw_transport->BlockReadResult();
+ rv = sock->Connect(callback.callback());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
+ raw_transport->WaitForReadResult();
+
+ // Release the ServerHello and wait for the client to write its second flight.
+ raw_transport->BlockWrite();
+ raw_transport->UnblockReadResult();
+ raw_transport->WaitForWrite();
+
+ // Wait for the server's final flight.
+ raw_transport->BlockReadResult();
+ raw_transport->UnblockWrite();
+ raw_transport->WaitForReadResult();
+
+ // Replace it with an alert.
+ raw_transport->ReplaceReadResult(
+ FormatTLS12Alert(40 /* AlertDescription.handshake_failure */));
+ raw_transport->UnblockReadResult();
+
+ rv = callback.GetResult(rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_PROTOCOL_ERROR));
+}
+
+// Test that access_denied alerts are mapped to ERR_SSL_PROTOCOL_ERROR if
+// received on a connection not requesting client certificates. This is an
+// incorrect use of the alert but is common. See https://crbug.com/630883.
+TEST_F(SSLClientSocketTest, AccessDeniedNoClientCerts) {
+ ASSERT_TRUE(StartTestServer(SpawnedTestServer::SSLOptions()));
+
+ TestCompletionCallback callback;
+ std::unique_ptr<StreamSocket> real_transport(
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
+ std::unique_ptr<FakeBlockingStreamSocket> transport(
+ new FakeBlockingStreamSocket(std::move(real_transport)));
+ FakeBlockingStreamSocket* raw_transport = transport.get();
+ int rv = callback.GetResult(transport->Connect(callback.callback()));
+ ASSERT_THAT(rv, IsOk());
+
+ std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+ std::move(transport), spawned_test_server()->host_port_pair(),
+ SSLConfig()));
+
+ // Connect. Stop before the client processes ServerHello.
+ raw_transport->BlockReadResult();
+ rv = sock->Connect(callback.callback());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
+ raw_transport->WaitForReadResult();
+
+ // Release the ServerHello and wait for the client to write its second flight.
+ raw_transport->BlockWrite();
+ raw_transport->UnblockReadResult();
+ raw_transport->WaitForWrite();
+
+ // Wait for the server's final flight.
+ raw_transport->BlockReadResult();
+ raw_transport->UnblockWrite();
+ raw_transport->WaitForReadResult();
+
+ // Replace it with an alert.
+ raw_transport->ReplaceReadResult(
+ FormatTLS12Alert(49 /* AlertDescription.access_denied */));
+ raw_transport->UnblockReadResult();
+
+ rv = callback.GetResult(rv);
+ EXPECT_THAT(rv, IsError(ERR_SSL_PROTOCOL_ERROR));
+}
+
+// Test that access_denied alerts are mapped to ERR_BAD_SSL_CLIENT_AUTH_CERT if
+// received on a connection requesting client certificates.
+TEST_F(SSLClientSocketTest, AccessDeniedClientCerts) {
+ // Request a client certificate.
+ SpawnedTestServer::SSLOptions ssl_options;
+ ssl_options.request_client_certificate = true;
+ ASSERT_TRUE(StartTestServer(ssl_options));
+
+ TestCompletionCallback callback;
+ std::unique_ptr<StreamSocket> real_transport(
+ new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
+ std::unique_ptr<FakeBlockingStreamSocket> transport(
+ new FakeBlockingStreamSocket(std::move(real_transport)));
+ FakeBlockingStreamSocket* raw_transport = transport.get();
+ int rv = callback.GetResult(transport->Connect(callback.callback()));
+ ASSERT_THAT(rv, IsOk());
+
+ // Send a client certificate.
+ base::FilePath certs_dir = GetTestCertsDirectory();
+ SSLConfig config;
+ config.send_client_cert = true;
+ config.client_cert = ImportCertFromFile(certs_dir, "client_1.pem");
+ config.client_private_key =
+ LoadPrivateKeyOpenSSL(certs_dir.AppendASCII("client_1.key"));
+ std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+ std::move(transport), spawned_test_server()->host_port_pair(), config));
+
+ // Connect. Stop before the client processes ServerHello.
+ raw_transport->BlockReadResult();
+ rv = sock->Connect(callback.callback());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
+ raw_transport->WaitForReadResult();
+
+ // Release the ServerHello and wait for the client to write its second flight.
+ raw_transport->BlockWrite();
+ raw_transport->UnblockReadResult();
+ raw_transport->WaitForWrite();
+
+ // Wait for the server's final flight.
+ raw_transport->BlockReadResult();
+ raw_transport->UnblockWrite();
+ raw_transport->WaitForReadResult();
+
+ // Replace it with an alert.
+ raw_transport->ReplaceReadResult(
+ FormatTLS12Alert(49 /* AlertDescription.access_denied */));
+ raw_transport->UnblockReadResult();
+
+ rv = callback.GetResult(rv);
+ EXPECT_THAT(rv, IsError(ERR_BAD_SSL_CLIENT_AUTH_CERT));
+}
+
} // namespace net
diff --git a/chromium/net/socket/ssl_server_socket_impl.cc b/chromium/net/socket/ssl_server_socket_impl.cc
index 0bc3da7c59b..56ba598bbe9 100644
--- a/chromium/net/socket/ssl_server_socket_impl.cc
+++ b/chromium/net/socket/ssl_server_socket_impl.cc
@@ -18,6 +18,8 @@
#include "net/cert/cert_verify_result.h"
#include "net/cert/client_cert_verifier.h"
#include "net/cert/x509_util_openssl.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/ssl/openssl_ssl_util.h"
#include "net/ssl/ssl_connection_status_flags.h"
#include "net/ssl/ssl_info.h"
@@ -85,7 +87,7 @@ class SSLServerSocketImpl : public SSLServerSocket {
bool IsConnectedAndIdle() const override;
int GetPeerAddress(IPEndPoint* address) const override;
int GetLocalAddress(IPEndPoint* address) const override;
- const BoundNetLog& NetLog() const override;
+ const NetLogWithSource& NetLog() const override;
void SetSubresourceSpeculation() override;
void SetOmniboxSpeculation() override;
bool WasEverUsed() const override;
@@ -137,7 +139,7 @@ class SSLServerSocketImpl : public SSLServerSocket {
scoped_refptr<DrainableIOBuffer> send_buffer_;
scoped_refptr<IOBuffer> recv_buffer_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
CompletionCallback user_handshake_callback_;
CompletionCallback user_read_callback_;
@@ -201,13 +203,14 @@ SSLServerSocketImpl::~SSLServerSocketImpl() {
}
int SSLServerSocketImpl::Handshake(const CompletionCallback& callback) {
- net_log_.BeginEvent(NetLog::TYPE_SSL_SERVER_HANDSHAKE);
+ net_log_.BeginEvent(NetLogEventType::SSL_SERVER_HANDSHAKE);
// Set up new ssl object.
int rv = Init();
if (rv != OK) {
LOG(ERROR) << "Failed to initialize OpenSSL: rv=" << rv;
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_SERVER_HANDSHAKE, rv);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::SSL_SERVER_HANDSHAKE,
+ rv);
return rv;
}
@@ -219,7 +222,8 @@ int SSLServerSocketImpl::Handshake(const CompletionCallback& callback) {
if (rv == ERR_IO_PENDING) {
user_handshake_callback_ = callback;
} else {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_SERVER_HANDSHAKE, rv);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::SSL_SERVER_HANDSHAKE,
+ rv);
}
return rv > OK ? OK : rv;
@@ -334,7 +338,7 @@ int SSLServerSocketImpl::GetLocalAddress(IPEndPoint* address) const {
return transport_socket_->GetLocalAddress(address);
}
-const BoundNetLog& SSLServerSocketImpl::NetLog() const {
+const NetLogWithSource& SSLServerSocketImpl::NetLog() const {
return net_log_;
}
@@ -439,7 +443,7 @@ void SSLServerSocketImpl::OnHandshakeIOComplete(int result) {
if (rv == ERR_IO_PENDING)
return;
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_SERVER_HANDSHAKE, rv);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::SSL_SERVER_HANDSHAKE, rv);
if (!user_handshake_callback_.is_null())
DoHandshakeCallback(rv);
}
@@ -608,7 +612,7 @@ int SSLServerSocketImpl::DoPayloadRead() {
MapOpenSSLErrorWithDetails(ssl_error, err_tracer, &error_info);
if (net_error != ERR_IO_PENDING) {
net_log_.AddEvent(
- NetLog::TYPE_SSL_READ_ERROR,
+ NetLogEventType::SSL_READ_ERROR,
CreateNetLogOpenSSLErrorCallback(net_error, ssl_error, error_info));
}
return net_error;
@@ -626,7 +630,7 @@ int SSLServerSocketImpl::DoPayloadWrite() {
MapOpenSSLErrorWithDetails(ssl_error, err_tracer, &error_info);
if (net_error != ERR_IO_PENDING) {
net_log_.AddEvent(
- NetLog::TYPE_SSL_WRITE_ERROR,
+ NetLogEventType::SSL_WRITE_ERROR,
CreateNetLogOpenSSLErrorCallback(net_error, ssl_error, error_info));
}
return net_error;
@@ -733,7 +737,7 @@ int SSLServerSocketImpl::DoHandshake() {
LOG(ERROR) << "handshake failed; returned " << rv << ", SSL error code "
<< ssl_error << ", net_error " << net_error;
net_log_.AddEvent(
- NetLog::TYPE_SSL_HANDSHAKE_ERROR,
+ NetLogEventType::SSL_HANDSHAKE_ERROR,
CreateNetLogOpenSSLErrorCallback(net_error, ssl_error, error_info));
}
}
diff --git a/chromium/net/socket/ssl_server_socket_impl.h b/chromium/net/socket/ssl_server_socket_impl.h
index 19a47971941..94fd6b594f7 100644
--- a/chromium/net/socket/ssl_server_socket_impl.h
+++ b/chromium/net/socket/ssl_server_socket_impl.h
@@ -12,7 +12,6 @@
#include "base/macros.h"
#include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
-#include "net/log/net_log.h"
#include "net/socket/ssl_server_socket.h"
#include "net/ssl/scoped_openssl_types.h"
#include "net/ssl/ssl_server_config.h"
diff --git a/chromium/net/socket/ssl_server_socket_unittest.cc b/chromium/net/socket/ssl_server_socket_unittest.cc
index 92481a8e782..52e4ab33446 100644
--- a/chromium/net/socket/ssl_server_socket_unittest.cc
+++ b/chromium/net/socket/ssl_server_socket_unittest.cc
@@ -55,7 +55,7 @@
#include "net/cert/mock_client_cert_verifier.h"
#include "net/cert/x509_certificate.h"
#include "net/http/transport_security_state.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/socket_test_util.h"
#include "net/socket/ssl_client_socket.h"
@@ -69,10 +69,15 @@
#include "net/ssl/ssl_server_config.h"
#include "net/ssl/test_ssl_private_key.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -92,7 +97,7 @@ class MockCTVerifier : public CTVerifier {
const std::string& stapled_ocsp_response,
const std::string& sct_list_from_tls_extension,
ct::CTVerifyResult* result,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
return net::OK;
}
@@ -106,7 +111,7 @@ class MockCTPolicyEnforcer : public CTPolicyEnforcer {
ct::CertPolicyCompliance DoesConformToCertPolicy(
X509Certificate* cert,
const SCTList& verified_scts,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
return ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS;
}
@@ -114,7 +119,7 @@ class MockCTPolicyEnforcer : public CTPolicyEnforcer {
X509Certificate* cert,
const ct::EVCertsWhitelist* ev_whitelist,
const SCTList& verified_scts,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
return ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS;
}
};
@@ -288,7 +293,7 @@ class FakeSocket : public StreamSocket {
return OK;
}
- const BoundNetLog& NetLog() const override { return net_log_; }
+ const NetLogWithSource& NetLog() const override { return net_log_; }
void SetSubresourceSpeculation() override {}
void SetOmniboxSpeculation() override {}
@@ -315,7 +320,7 @@ class FakeSocket : public StreamSocket {
}
private:
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
FakeDataChannel* incoming_;
FakeDataChannel* outgoing_;
@@ -390,13 +395,8 @@ class SSLServerSocketTest : public PlatformTest {
client_ssl_config_.channel_id_enabled = false;
// Certificate provided by the host doesn't need authority.
- SSLConfig::CertAndStatus cert_and_status;
- cert_and_status.cert_status = CERT_STATUS_AUTHORITY_INVALID;
- std::string server_cert_der;
- ASSERT_TRUE(X509Certificate::GetDEREncoded(server_cert_->os_cert_handle(),
- &server_cert_der));
- cert_and_status.der_cert = server_cert_der;
- client_ssl_config_.allowed_bad_certs.push_back(cert_and_status);
+ client_ssl_config_.allowed_bad_certs.emplace_back(
+ server_cert_, CERT_STATUS_AUTHORITY_INVALID);
}
protected:
@@ -450,8 +450,9 @@ class SSLServerSocketTest : public PlatformTest {
ReadTestKey(private_key_file_name);
ASSERT_TRUE(key);
- client_ssl_config_.client_private_key = WrapOpenSSLPrivateKey(
- crypto::ScopedEVP_PKEY(EVP_PKEY_up_ref(key->key())));
+ EVP_PKEY_up_ref(key->key());
+ client_ssl_config_.client_private_key =
+ WrapOpenSSLPrivateKey(crypto::ScopedEVP_PKEY(key->key()));
}
void ConfigureClientCertsForServer() {
@@ -541,8 +542,8 @@ TEST_F(SSLServerSocketTest, Handshake) {
client_ret = connect_callback.GetResult(client_ret);
server_ret = handshake_callback.GetResult(server_ret);
- ASSERT_EQ(OK, client_ret);
- ASSERT_EQ(OK, server_ret);
+ ASSERT_THAT(client_ret, IsOk());
+ ASSERT_THAT(server_ret, IsOk());
// Make sure the cert status is expected.
SSLInfo ssl_info;
@@ -576,8 +577,8 @@ TEST_F(SSLServerSocketTest, HandshakeCached) {
client_ret = connect_callback.GetResult(client_ret);
server_ret = handshake_callback.GetResult(server_ret);
- ASSERT_EQ(OK, client_ret);
- ASSERT_EQ(OK, server_ret);
+ ASSERT_THAT(client_ret, IsOk());
+ ASSERT_THAT(server_ret, IsOk());
// Make sure the cert status is expected.
SSLInfo ssl_info;
@@ -598,8 +599,8 @@ TEST_F(SSLServerSocketTest, HandshakeCached) {
client_ret2 = connect_callback2.GetResult(client_ret2);
server_ret2 = handshake_callback2.GetResult(server_ret2);
- ASSERT_EQ(OK, client_ret2);
- ASSERT_EQ(OK, server_ret2);
+ ASSERT_THAT(client_ret2, IsOk());
+ ASSERT_THAT(server_ret2, IsOk());
// Make sure the cert status is expected.
SSLInfo ssl_info2;
@@ -624,8 +625,8 @@ TEST_F(SSLServerSocketTest, HandshakeCachedContextSwitch) {
client_ret = connect_callback.GetResult(client_ret);
server_ret = handshake_callback.GetResult(server_ret);
- ASSERT_EQ(OK, client_ret);
- ASSERT_EQ(OK, server_ret);
+ ASSERT_THAT(client_ret, IsOk());
+ ASSERT_THAT(server_ret, IsOk());
// Make sure the cert status is expected.
SSLInfo ssl_info;
@@ -648,8 +649,8 @@ TEST_F(SSLServerSocketTest, HandshakeCachedContextSwitch) {
client_ret2 = connect_callback2.GetResult(client_ret2);
server_ret2 = handshake_callback2.GetResult(server_ret2);
- ASSERT_EQ(OK, client_ret2);
- ASSERT_EQ(OK, server_ret2);
+ ASSERT_THAT(client_ret2, IsOk());
+ ASSERT_THAT(server_ret2, IsOk());
// Make sure the cert status is expected.
SSLInfo ssl_info2;
@@ -681,8 +682,8 @@ TEST_F(SSLServerSocketTest, HandshakeWithClientCert) {
client_ret = connect_callback.GetResult(client_ret);
server_ret = handshake_callback.GetResult(server_ret);
- ASSERT_EQ(OK, client_ret);
- ASSERT_EQ(OK, server_ret);
+ ASSERT_THAT(client_ret, IsOk());
+ ASSERT_THAT(server_ret, IsOk());
// Make sure the cert status is expected.
SSLInfo ssl_info;
@@ -715,8 +716,8 @@ TEST_F(SSLServerSocketTest, HandshakeWithClientCertCached) {
client_ret = connect_callback.GetResult(client_ret);
server_ret = handshake_callback.GetResult(server_ret);
- ASSERT_EQ(OK, client_ret);
- ASSERT_EQ(OK, server_ret);
+ ASSERT_THAT(client_ret, IsOk());
+ ASSERT_THAT(server_ret, IsOk());
// Make sure the cert status is expected.
SSLInfo ssl_info;
@@ -741,8 +742,8 @@ TEST_F(SSLServerSocketTest, HandshakeWithClientCertCached) {
client_ret2 = connect_callback2.GetResult(client_ret2);
server_ret2 = handshake_callback2.GetResult(server_ret2);
- ASSERT_EQ(OK, client_ret2);
- ASSERT_EQ(OK, server_ret2);
+ ASSERT_THAT(client_ret2, IsOk());
+ ASSERT_THAT(server_ret2, IsOk());
// Make sure the cert status is expected.
SSLInfo ssl_info2;
@@ -785,7 +786,7 @@ TEST_F(SSLServerSocketTest, HandshakeWithClientCertRequiredNotSupplied) {
client_socket_->Disconnect();
- EXPECT_EQ(ERR_FAILED, handshake_callback.GetResult(server_ret));
+ EXPECT_THAT(handshake_callback.GetResult(server_ret), IsError(ERR_FAILED));
}
TEST_F(SSLServerSocketTest, HandshakeWithClientCertRequiredNotSuppliedCached) {
@@ -818,7 +819,7 @@ TEST_F(SSLServerSocketTest, HandshakeWithClientCertRequiredNotSuppliedCached) {
client_socket_->Disconnect();
- EXPECT_EQ(ERR_FAILED, handshake_callback.GetResult(server_ret));
+ EXPECT_THAT(handshake_callback.GetResult(server_ret), IsError(ERR_FAILED));
server_socket_->Disconnect();
// Below, check that the cache didn't store the result of a failed handshake.
@@ -840,7 +841,7 @@ TEST_F(SSLServerSocketTest, HandshakeWithClientCertRequiredNotSuppliedCached) {
client_socket_->Disconnect();
- EXPECT_EQ(ERR_FAILED, handshake_callback2.GetResult(server_ret2));
+ EXPECT_THAT(handshake_callback2.GetResult(server_ret2), IsError(ERR_FAILED));
}
TEST_F(SSLServerSocketTest, HandshakeWithWrongClientCertSupplied) {
@@ -919,9 +920,9 @@ TEST_F(SSLServerSocketTest, DataTransfer) {
ASSERT_TRUE(server_ret == OK || server_ret == ERR_IO_PENDING);
client_ret = connect_callback.GetResult(client_ret);
- ASSERT_EQ(OK, client_ret);
+ ASSERT_THAT(client_ret, IsOk());
server_ret = handshake_callback.GetResult(server_ret);
- ASSERT_EQ(OK, server_ret);
+ ASSERT_THAT(server_ret, IsOk());
const int kReadBufSize = 1024;
scoped_refptr<StringIOBuffer> write_buf =
@@ -1003,9 +1004,9 @@ TEST_F(SSLServerSocketTest, ClientWriteAfterServerClose) {
ASSERT_TRUE(server_ret == OK || server_ret == ERR_IO_PENDING);
client_ret = connect_callback.GetResult(client_ret);
- ASSERT_EQ(OK, client_ret);
+ ASSERT_THAT(client_ret, IsOk());
server_ret = handshake_callback.GetResult(server_ret);
- ASSERT_EQ(OK, server_ret);
+ ASSERT_THAT(server_ret, IsOk());
scoped_refptr<StringIOBuffer> write_buf = new StringIOBuffer("testing123");
@@ -1053,10 +1054,10 @@ TEST_F(SSLServerSocketTest, ExportKeyingMaterial) {
ASSERT_TRUE(server_ret == OK || server_ret == ERR_IO_PENDING);
if (client_ret == ERR_IO_PENDING) {
- ASSERT_EQ(OK, connect_callback.WaitForResult());
+ ASSERT_THAT(connect_callback.WaitForResult(), IsOk());
}
if (server_ret == ERR_IO_PENDING) {
- ASSERT_EQ(OK, handshake_callback.WaitForResult());
+ ASSERT_THAT(handshake_callback.WaitForResult(), IsOk());
}
const int kKeyingMaterialSize = 32;
@@ -1065,12 +1066,12 @@ TEST_F(SSLServerSocketTest, ExportKeyingMaterial) {
unsigned char server_out[kKeyingMaterialSize];
int rv = server_socket_->ExportKeyingMaterial(
kKeyingLabel, false, kKeyingContext, server_out, sizeof(server_out));
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
unsigned char client_out[kKeyingMaterialSize];
rv = client_socket_->ExportKeyingMaterial(kKeyingLabel, false, kKeyingContext,
client_out, sizeof(client_out));
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
EXPECT_EQ(0, memcmp(server_out, client_out, sizeof(server_out)));
const char kKeyingLabelBad[] = "EXPERIMENTAL-server-socket-test-bad";
@@ -1114,8 +1115,8 @@ TEST_F(SSLServerSocketTest, RequireEcdheFlag) {
client_ret = connect_callback.GetResult(client_ret);
server_ret = handshake_callback.GetResult(server_ret);
- ASSERT_EQ(ERR_SSL_VERSION_OR_CIPHER_MISMATCH, client_ret);
- ASSERT_EQ(ERR_SSL_VERSION_OR_CIPHER_MISMATCH, 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/ssl_socket.h b/chromium/net/socket/ssl_socket.h
index bd813c35fea..61410da3b9d 100644
--- a/chromium/net/socket/ssl_socket.h
+++ b/chromium/net/socket/ssl_socket.h
@@ -6,6 +6,7 @@
#define NET_SOCKET_SSL_SOCKET_H_
#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
#include "net/socket/stream_socket.h"
namespace net {
diff --git a/chromium/net/socket/stream_socket.h b/chromium/net/socket/stream_socket.h
index 98efcdafb9b..4ed735af04f 100644
--- a/chromium/net/socket/stream_socket.h
+++ b/chromium/net/socket/stream_socket.h
@@ -8,7 +8,7 @@
#include <stdint.h>
#include "base/macros.h"
-#include "net/log/net_log.h"
+#include "net/base/net_export.h"
#include "net/socket/connection_attempts.h"
#include "net/socket/next_proto.h"
#include "net/socket/socket.h"
@@ -17,6 +17,7 @@ namespace net {
class AddressList;
class IPEndPoint;
+class NetLogWithSource;
class SSLInfo;
class NET_EXPORT_PRIVATE StreamSocket : public Socket {
@@ -66,7 +67,7 @@ class NET_EXPORT_PRIVATE StreamSocket : public Socket {
virtual int GetLocalAddress(IPEndPoint* address) const = 0;
// Gets the NetLog for this socket.
- virtual const BoundNetLog& NetLog() const = 0;
+ virtual const NetLogWithSource& NetLog() const = 0;
// Set the annotation to indicate this socket was created for speculative
// reasons. This call is generally forwarded to a basic TCPClientSocket*,
diff --git a/chromium/net/socket/tcp_client_socket.cc b/chromium/net/socket/tcp_client_socket.cc
index 1c292bb8073..f8f61229529 100644
--- a/chromium/net/socket/tcp_client_socket.cc
+++ b/chromium/net/socket/tcp_client_socket.cc
@@ -18,11 +18,13 @@
namespace net {
+class NetLogWithSource;
+
TCPClientSocket::TCPClientSocket(
const AddressList& addresses,
std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
net::NetLog* net_log,
- const net::NetLog::Source& source)
+ const net::NetLogSource& source)
: socket_performance_watcher_(socket_performance_watcher.get()),
socket_(new TCPSocket(std::move(socket_performance_watcher),
net_log,
@@ -235,7 +237,7 @@ int TCPClientSocket::GetLocalAddress(IPEndPoint* address) const {
return socket_->GetLocalAddress(address);
}
-const BoundNetLog& TCPClientSocket::NetLog() const {
+const NetLogWithSource& TCPClientSocket::NetLog() const {
return socket_->net_log();
}
diff --git a/chromium/net/socket/tcp_client_socket.h b/chromium/net/socket/tcp_client_socket.h
index bf41545d180..295e8b68113 100644
--- a/chromium/net/socket/tcp_client_socket.h
+++ b/chromium/net/socket/tcp_client_socket.h
@@ -14,13 +14,14 @@
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
-#include "net/log/net_log.h"
#include "net/socket/connection_attempts.h"
#include "net/socket/stream_socket.h"
#include "net/socket/tcp_socket.h"
namespace net {
+class NetLog;
+struct NetLogSource;
class SocketPerformanceWatcher;
// A client socket that uses TCP as the transport layer.
@@ -33,7 +34,7 @@ class NET_EXPORT TCPClientSocket : public StreamSocket {
const AddressList& addresses,
std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
net::NetLog* net_log,
- const net::NetLog::Source& source);
+ const net::NetLogSource& source);
// Adopts the given, connected socket and then acts as if Connect() had been
// called. This function is used by TCPServerSocket and for testing.
@@ -52,7 +53,7 @@ class NET_EXPORT TCPClientSocket : public StreamSocket {
bool IsConnectedAndIdle() const override;
int GetPeerAddress(IPEndPoint* address) const override;
int GetLocalAddress(IPEndPoint* address) const override;
- const BoundNetLog& NetLog() const override;
+ const NetLogWithSource& NetLog() const override;
void SetSubresourceSpeculation() override;
void SetOmniboxSpeculation() override;
bool WasEverUsed() const override;
diff --git a/chromium/net/socket/tcp_client_socket_unittest.cc b/chromium/net/socket/tcp_client_socket_unittest.cc
index d8499b44c5c..c774346657e 100644
--- a/chromium/net/socket/tcp_client_socket_unittest.cc
+++ b/chromium/net/socket/tcp_client_socket_unittest.cc
@@ -14,10 +14,16 @@
#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/tcp_server_socket.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace base {
class TimeDelta;
}
@@ -31,31 +37,32 @@ namespace {
TEST(TCPClientSocketTest, BindLoopbackToLoopback) {
IPAddress lo_address = IPAddress::IPv4Localhost();
- TCPServerSocket server(NULL, NetLog::Source());
- ASSERT_EQ(OK, server.Listen(IPEndPoint(lo_address, 0), 1));
+ TCPServerSocket server(NULL, NetLogSource());
+ ASSERT_THAT(server.Listen(IPEndPoint(lo_address, 0), 1), IsOk());
IPEndPoint server_address;
- ASSERT_EQ(OK, server.GetLocalAddress(&server_address));
+ ASSERT_THAT(server.GetLocalAddress(&server_address), IsOk());
TCPClientSocket socket(AddressList(server_address), NULL, NULL,
- NetLog::Source());
+ NetLogSource());
- EXPECT_EQ(OK, socket.Bind(IPEndPoint(lo_address, 0)));
+ EXPECT_THAT(socket.Bind(IPEndPoint(lo_address, 0)), IsOk());
IPEndPoint local_address_result;
- EXPECT_EQ(OK, socket.GetLocalAddress(&local_address_result));
+ EXPECT_THAT(socket.GetLocalAddress(&local_address_result), IsOk());
EXPECT_EQ(lo_address, local_address_result.address());
TestCompletionCallback connect_callback;
- EXPECT_EQ(ERR_IO_PENDING, socket.Connect(connect_callback.callback()));
+ EXPECT_THAT(socket.Connect(connect_callback.callback()),
+ IsError(ERR_IO_PENDING));
TestCompletionCallback accept_callback;
std::unique_ptr<StreamSocket> accepted_socket;
int result = server.Accept(&accepted_socket, accept_callback.callback());
if (result == ERR_IO_PENDING)
result = accept_callback.WaitForResult();
- ASSERT_EQ(OK, result);
+ ASSERT_THAT(result, IsOk());
- EXPECT_EQ(OK, connect_callback.WaitForResult());
+ EXPECT_THAT(connect_callback.WaitForResult(), IsOk());
EXPECT_TRUE(socket.IsConnected());
socket.Disconnect();
@@ -69,9 +76,9 @@ TEST(TCPClientSocketTest, BindLoopbackToLoopback) {
TEST(TCPClientSocketTest, BindLoopbackToExternal) {
IPAddress external_ip(72, 14, 213, 105);
TCPClientSocket socket(AddressList::CreateFromIPAddress(external_ip, 80),
- NULL, NULL, NetLog::Source());
+ NULL, NULL, NetLogSource());
- EXPECT_EQ(OK, socket.Bind(IPEndPoint(IPAddress::IPv4Localhost(), 0)));
+ EXPECT_THAT(socket.Bind(IPEndPoint(IPAddress::IPv4Localhost(), 0)), IsOk());
TestCompletionCallback connect_callback;
int result = socket.Connect(connect_callback.callback());
@@ -86,7 +93,7 @@ TEST(TCPClientSocketTest, BindLoopbackToExternal) {
// Bind a socket to the IPv4 loopback interface and try to connect to
// the IPv6 loopback interface, verify that connection fails.
TEST(TCPClientSocketTest, BindLoopbackToIPv6) {
- TCPServerSocket server(NULL, NetLog::Source());
+ TCPServerSocket server(NULL, NetLogSource());
int listen_result =
server.Listen(IPEndPoint(IPAddress::IPv6Localhost(), 0), 1);
if (listen_result != OK) {
@@ -96,11 +103,11 @@ TEST(TCPClientSocketTest, BindLoopbackToIPv6) {
}
IPEndPoint server_address;
- ASSERT_EQ(OK, server.GetLocalAddress(&server_address));
+ ASSERT_THAT(server.GetLocalAddress(&server_address), IsOk());
TCPClientSocket socket(AddressList(server_address), NULL, NULL,
- NetLog::Source());
+ NetLogSource());
- EXPECT_EQ(OK, socket.Bind(IPEndPoint(IPAddress::IPv4Localhost(), 0)));
+ EXPECT_THAT(socket.Bind(IPEndPoint(IPAddress::IPv4Localhost(), 0)), IsOk());
TestCompletionCallback connect_callback;
int result = socket.Connect(connect_callback.callback());
@@ -150,9 +157,9 @@ TEST(TCPClientSocketTest, MAYBE_TestSocketPerformanceWatcher) {
TCPClientSocket socket(
AddressList::CreateFromIPAddressList(ip_list, "example.com"),
- std::move(watcher), NULL, NetLog::Source());
+ std::move(watcher), NULL, NetLogSource());
- EXPECT_EQ(OK, socket.Bind(IPEndPoint(IPAddress::IPv4Localhost(), 0)));
+ EXPECT_THAT(socket.Bind(IPEndPoint(IPAddress::IPv4Localhost(), 0)), IsOk());
TestCompletionCallback connect_callback;
diff --git a/chromium/net/socket/tcp_server_socket.cc b/chromium/net/socket/tcp_server_socket.cc
index d617fa596c4..22211cd9496 100644
--- a/chromium/net/socket/tcp_server_socket.cc
+++ b/chromium/net/socket/tcp_server_socket.cc
@@ -14,7 +14,7 @@
namespace net {
-TCPServerSocket::TCPServerSocket(NetLog* net_log, const NetLog::Source& source)
+TCPServerSocket::TCPServerSocket(NetLog* net_log, const NetLogSource& source)
: socket_(nullptr, net_log, source), pending_accept_(false) {}
TCPServerSocket::~TCPServerSocket() {
diff --git a/chromium/net/socket/tcp_server_socket.h b/chromium/net/socket/tcp_server_socket.h
index 993d4bafdc7..546f48df521 100644
--- a/chromium/net/socket/tcp_server_socket.h
+++ b/chromium/net/socket/tcp_server_socket.h
@@ -10,15 +10,17 @@
#include "base/macros.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_export.h"
-#include "net/log/net_log.h"
#include "net/socket/server_socket.h"
#include "net/socket/tcp_socket.h"
namespace net {
+class NetLog;
+struct NetLogSource;
+
class NET_EXPORT TCPServerSocket : public ServerSocket {
public:
- TCPServerSocket(NetLog* net_log, const NetLog::Source& source);
+ TCPServerSocket(NetLog* net_log, const NetLogSource& source);
~TCPServerSocket() override;
// net::ServerSocket implementation.
diff --git a/chromium/net/socket/tcp_server_socket_unittest.cc b/chromium/net/socket/tcp_server_socket_unittest.cc
index a0d6c49c98c..2f7ea3808ae 100644
--- a/chromium/net/socket/tcp_server_socket_unittest.cc
+++ b/chromium/net/socket/tcp_server_socket_unittest.cc
@@ -16,10 +16,15 @@
#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/tcp_client_socket.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -27,14 +32,12 @@ const int kListenBacklog = 5;
class TCPServerSocketTest : public PlatformTest {
protected:
- TCPServerSocketTest()
- : socket_(NULL, NetLog::Source()) {
- }
+ TCPServerSocketTest() : socket_(NULL, NetLogSource()) {}
void SetUpIPv4() {
IPEndPoint address(IPAddress::IPv4Localhost(), 0);
- ASSERT_EQ(OK, socket_.Listen(address, kListenBacklog));
- ASSERT_EQ(OK, socket_.GetLocalAddress(&local_address_));
+ ASSERT_THAT(socket_.Listen(address, kListenBacklog), IsOk());
+ ASSERT_THAT(socket_.GetLocalAddress(&local_address_), IsOk());
}
void SetUpIPv6(bool* success) {
@@ -45,13 +48,13 @@ class TCPServerSocketTest : public PlatformTest {
"disabled. Skipping the test";
return;
}
- ASSERT_EQ(OK, socket_.GetLocalAddress(&local_address_));
+ ASSERT_THAT(socket_.GetLocalAddress(&local_address_), IsOk());
*success = true;
}
static IPEndPoint GetPeerAddress(StreamSocket* socket) {
IPEndPoint address;
- EXPECT_EQ(OK, socket->GetPeerAddress(&address));
+ EXPECT_THAT(socket->GetPeerAddress(&address), IsOk());
return address;
}
@@ -68,7 +71,7 @@ TEST_F(TCPServerSocketTest, Accept) {
TestCompletionCallback connect_callback;
TCPClientSocket connecting_socket(local_address_list(), NULL, NULL,
- NetLog::Source());
+ NetLogSource());
connecting_socket.Connect(connect_callback.callback());
TestCompletionCallback accept_callback;
@@ -76,7 +79,7 @@ TEST_F(TCPServerSocketTest, Accept) {
int result = socket_.Accept(&accepted_socket, accept_callback.callback());
if (result == ERR_IO_PENDING)
result = accept_callback.WaitForResult();
- ASSERT_EQ(OK, result);
+ ASSERT_THAT(result, IsOk());
ASSERT_TRUE(accepted_socket.get() != NULL);
@@ -84,7 +87,7 @@ TEST_F(TCPServerSocketTest, Accept) {
EXPECT_EQ(GetPeerAddress(accepted_socket.get()).address(),
local_address_.address());
- EXPECT_EQ(OK, connect_callback.WaitForResult());
+ EXPECT_THAT(connect_callback.WaitForResult(), IsOk());
}
// Test Accept() callback.
@@ -99,11 +102,11 @@ TEST_F(TCPServerSocketTest, AcceptAsync) {
TestCompletionCallback connect_callback;
TCPClientSocket connecting_socket(local_address_list(), NULL, NULL,
- NetLog::Source());
+ NetLogSource());
connecting_socket.Connect(connect_callback.callback());
- EXPECT_EQ(OK, connect_callback.WaitForResult());
- EXPECT_EQ(OK, accept_callback.WaitForResult());
+ EXPECT_THAT(connect_callback.WaitForResult(), IsOk());
+ EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
EXPECT_TRUE(accepted_socket != NULL);
@@ -124,24 +127,24 @@ TEST_F(TCPServerSocketTest, Accept2Connections) {
TestCompletionCallback connect_callback;
TCPClientSocket connecting_socket(local_address_list(), NULL, NULL,
- NetLog::Source());
+ NetLogSource());
connecting_socket.Connect(connect_callback.callback());
TestCompletionCallback connect_callback2;
TCPClientSocket connecting_socket2(local_address_list(), NULL, NULL,
- NetLog::Source());
+ NetLogSource());
connecting_socket2.Connect(connect_callback2.callback());
- EXPECT_EQ(OK, accept_callback.WaitForResult());
+ EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
TestCompletionCallback accept_callback2;
std::unique_ptr<StreamSocket> accepted_socket2;
int result = socket_.Accept(&accepted_socket2, accept_callback2.callback());
if (result == ERR_IO_PENDING)
result = accept_callback2.WaitForResult();
- ASSERT_EQ(OK, result);
+ ASSERT_THAT(result, IsOk());
- EXPECT_EQ(OK, connect_callback.WaitForResult());
+ EXPECT_THAT(connect_callback.WaitForResult(), IsOk());
EXPECT_TRUE(accepted_socket != NULL);
EXPECT_TRUE(accepted_socket2 != NULL);
@@ -161,7 +164,7 @@ TEST_F(TCPServerSocketTest, AcceptIPv6) {
TestCompletionCallback connect_callback;
TCPClientSocket connecting_socket(local_address_list(), NULL, NULL,
- NetLog::Source());
+ NetLogSource());
connecting_socket.Connect(connect_callback.callback());
TestCompletionCallback accept_callback;
@@ -169,7 +172,7 @@ TEST_F(TCPServerSocketTest, AcceptIPv6) {
int result = socket_.Accept(&accepted_socket, accept_callback.callback());
if (result == ERR_IO_PENDING)
result = accept_callback.WaitForResult();
- ASSERT_EQ(OK, result);
+ ASSERT_THAT(result, IsOk());
ASSERT_TRUE(accepted_socket.get() != NULL);
@@ -177,7 +180,7 @@ TEST_F(TCPServerSocketTest, AcceptIPv6) {
EXPECT_EQ(GetPeerAddress(accepted_socket.get()).address(),
local_address_.address());
- EXPECT_EQ(OK, connect_callback.WaitForResult());
+ EXPECT_THAT(connect_callback.WaitForResult(), IsOk());
}
TEST_F(TCPServerSocketTest, AcceptIO) {
@@ -185,13 +188,13 @@ TEST_F(TCPServerSocketTest, AcceptIO) {
TestCompletionCallback connect_callback;
TCPClientSocket connecting_socket(local_address_list(), NULL, NULL,
- NetLog::Source());
+ NetLogSource());
connecting_socket.Connect(connect_callback.callback());
TestCompletionCallback accept_callback;
std::unique_ptr<StreamSocket> accepted_socket;
int result = socket_.Accept(&accepted_socket, accept_callback.callback());
- ASSERT_EQ(OK, accept_callback.GetResult(result));
+ ASSERT_THAT(accept_callback.GetResult(result), IsOk());
ASSERT_TRUE(accepted_socket.get() != NULL);
@@ -199,7 +202,7 @@ TEST_F(TCPServerSocketTest, AcceptIO) {
EXPECT_EQ(GetPeerAddress(accepted_socket.get()).address(),
local_address_.address());
- EXPECT_EQ(OK, connect_callback.WaitForResult());
+ EXPECT_THAT(connect_callback.WaitForResult(), IsOk());
const std::string message("test message");
std::vector<char> buffer(message.size());
diff --git a/chromium/net/socket/tcp_socket_posix.cc b/chromium/net/socket/tcp_socket_posix.cc
index 9750aa11162..2707b29dd4f 100644
--- a/chromium/net/socket/tcp_socket_posix.cc
+++ b/chromium/net/socket/tcp_socket_posix.cc
@@ -14,7 +14,6 @@
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/posix/eintr_wrapper.h"
-#include "base/profiler/scoped_tracker.h"
#include "base/task_runner_util.h"
#include "base/threading/worker_pool.h"
#include "base/time/default_tick_clock.h"
@@ -25,6 +24,10 @@
#include "net/base/network_activity_monitor.h"
#include "net/base/network_change_notifier.h"
#include "net/base/sockaddr_storage.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
#include "net/socket/socket_net_log_params.h"
#include "net/socket/socket_posix.h"
@@ -140,7 +143,7 @@ void CheckSupportAndMaybeEnableTCPFastOpen(bool user_enabled) {
TCPSocketPosix::TCPSocketPosix(
std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
NetLog* net_log,
- const NetLog::Source& source)
+ const NetLogSource& source)
: socket_performance_watcher_(std::move(socket_performance_watcher)),
tick_clock_(new base::DefaultTickClock()),
rtt_notifications_minimum_interval_(base::TimeDelta::FromSeconds(1)),
@@ -149,13 +152,13 @@ TCPSocketPosix::TCPSocketPosix(
tcp_fastopen_connected_(false),
tcp_fastopen_status_(TCP_FASTOPEN_STATUS_UNKNOWN),
logging_multiple_connect_attempts_(false),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
- net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
+ net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::SOCKET)) {
+ net_log_.BeginEvent(NetLogEventType::SOCKET_ALIVE,
source.ToEventParametersCallback());
}
TCPSocketPosix::~TCPSocketPosix() {
- net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
+ net_log_.EndEvent(NetLogEventType::SOCKET_ALIVE);
Close();
}
@@ -209,7 +212,7 @@ int TCPSocketPosix::Accept(std::unique_ptr<TCPSocketPosix>* tcp_socket,
DCHECK(socket_);
DCHECK(!accept_socket_);
- net_log_.BeginEvent(NetLog::TYPE_TCP_ACCEPT);
+ net_log_.BeginEvent(NetLogEventType::TCP_ACCEPT);
int rv = socket_->Accept(
&accept_socket_,
@@ -227,7 +230,7 @@ int TCPSocketPosix::Connect(const IPEndPoint& address,
if (!logging_multiple_connect_attempts_)
LogConnectBegin(AddressList(address));
- net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
+ net_log_.BeginEvent(NetLogEventType::TCP_CONNECT_ATTEMPT,
CreateNetLogIPEndPointCallback(&address));
SockaddrStorage storage;
@@ -503,10 +506,10 @@ int TCPSocketPosix::HandleAcceptCompleted(
rv = BuildTcpSocketPosix(tcp_socket, address);
if (rv == OK) {
- net_log_.EndEvent(NetLog::TYPE_TCP_ACCEPT,
+ net_log_.EndEvent(NetLogEventType::TCP_ACCEPT,
CreateNetLogIPEndPointCallback(address));
} else {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, rv);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::TCP_ACCEPT, rv);
}
return rv;
@@ -539,10 +542,10 @@ void TCPSocketPosix::ConnectCompleted(const CompletionCallback& callback,
int TCPSocketPosix::HandleConnectCompleted(int rv) {
// Log the end of this attempt (and any OS error it threw).
if (rv != OK) {
- net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
+ net_log_.EndEvent(NetLogEventType::TCP_CONNECT_ATTEMPT,
NetLog::IntCallback("os_error", errno));
} else {
- net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT);
+ net_log_.EndEvent(NetLogEventType::TCP_CONNECT_ATTEMPT);
NotifySocketPerformanceWatcher();
}
@@ -557,13 +560,13 @@ int TCPSocketPosix::HandleConnectCompleted(int rv) {
}
void TCPSocketPosix::LogConnectBegin(const AddressList& addresses) const {
- net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT,
+ net_log_.BeginEvent(NetLogEventType::TCP_CONNECT,
addresses.CreateNetLogCallback());
}
void TCPSocketPosix::LogConnectEnd(int net_error) const {
if (net_error != OK) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, net_error);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::TCP_CONNECT, net_error);
return;
}
@@ -572,13 +575,13 @@ void TCPSocketPosix::LogConnectEnd(int net_error) const {
if (rv != OK) {
PLOG(ERROR) << "GetLocalAddress() [rv: " << rv << "] error: ";
NOTREACHED();
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, rv);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::TCP_CONNECT, rv);
return;
}
- net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT,
- CreateNetLogSourceAddressCallback(storage.addr,
- storage.addr_len));
+ net_log_.EndEvent(
+ NetLogEventType::TCP_CONNECT,
+ CreateNetLogSourceAddressCallback(storage.addr, storage.addr_len));
}
void TCPSocketPosix::ReadCompleted(const scoped_refptr<IOBuffer>& buf,
@@ -607,7 +610,7 @@ int TCPSocketPosix::HandleReadCompleted(IOBuffer* buf, int rv) {
}
if (rv < 0) {
- net_log_.AddEvent(NetLog::TYPE_SOCKET_READ_ERROR,
+ net_log_.AddEvent(NetLogEventType::SOCKET_READ_ERROR,
CreateNetLogSocketErrorCallback(rv, errno));
return rv;
}
@@ -616,7 +619,7 @@ int TCPSocketPosix::HandleReadCompleted(IOBuffer* buf, int rv) {
if (rv > 0)
NotifySocketPerformanceWatcher();
- net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, rv,
+ net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, rv,
buf->data());
NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(rv);
@@ -643,7 +646,7 @@ int TCPSocketPosix::HandleWriteCompleted(IOBuffer* buf, int rv) {
tcp_fastopen_status_ = TCP_FASTOPEN_ERROR;
g_tcp_fastopen_has_failed = true;
}
- net_log_.AddEvent(NetLog::TYPE_SOCKET_WRITE_ERROR,
+ net_log_.AddEvent(NetLogEventType::SOCKET_WRITE_ERROR,
CreateNetLogSocketErrorCallback(rv, errno));
return rv;
}
@@ -652,7 +655,7 @@ int TCPSocketPosix::HandleWriteCompleted(IOBuffer* buf, int rv) {
if (rv > 0)
NotifySocketPerformanceWatcher();
- net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, rv,
+ net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_SENT, rv,
buf->data());
NetworkActivityMonitor::GetInstance()->IncrementBytesSent(rv);
return rv;
@@ -721,11 +724,6 @@ int TCPSocketPosix::TcpFastOpenWrite(IOBuffer* buf,
void TCPSocketPosix::NotifySocketPerformanceWatcher() {
#if defined(TCP_INFO)
- // TODO(tbansal): Remove ScopedTracker once crbug.com/590254 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "590254 TCPSocketPosix::NotifySocketPerformanceWatcher"));
-
const base::TimeTicks now_ticks = tick_clock_->NowTicks();
// Do not notify |socket_performance_watcher_| if the last notification was
// recent than |rtt_notifications_minimum_interval_| ago. This helps in
diff --git a/chromium/net/socket/tcp_socket_posix.h b/chromium/net/socket/tcp_socket_posix.h
index 4d157e7ee9e..fda90fcfd95 100644
--- a/chromium/net/socket/tcp_socket_posix.h
+++ b/chromium/net/socket/tcp_socket_posix.h
@@ -16,7 +16,7 @@
#include "net/base/address_family.h"
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/socket_performance_watcher.h"
namespace base {
@@ -29,6 +29,8 @@ class AddressList;
class IOBuffer;
class IPEndPoint;
class SocketPosix;
+class NetLog;
+struct NetLogSource;
class NET_EXPORT TCPSocketPosix {
public:
@@ -37,7 +39,7 @@ class NET_EXPORT TCPSocketPosix {
TCPSocketPosix(
std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
NetLog* net_log,
- const NetLog::Source& source);
+ const NetLogSource& source);
virtual ~TCPSocketPosix();
int Open(AddressFamily family);
@@ -97,9 +99,9 @@ class NET_EXPORT TCPSocketPosix {
//
// TCPClientSocket may attempt to connect to multiple addresses until it
// succeeds in establishing a connection. The corresponding log will have
- // multiple NetLog::TYPE_TCP_CONNECT_ATTEMPT entries nested within a
- // NetLog::TYPE_TCP_CONNECT. These methods set the start/end of
- // NetLog::TYPE_TCP_CONNECT.
+ // multiple NetLogEventType::TCP_CONNECT_ATTEMPT entries nested within a
+ // NetLogEventType::TCP_CONNECT. These methods set the start/end of
+ // NetLogEventType::TCP_CONNECT.
//
// TODO(yzshen): Change logging format and let TCPClientSocket log the
// start/end of a series of connect attempts itself.
@@ -108,7 +110,7 @@ class NET_EXPORT TCPSocketPosix {
void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock);
- const BoundNetLog& net_log() const { return net_log_; }
+ const NetLogWithSource& net_log() const { return net_log_; }
private:
// States that using a socket with TCP FastOpen can lead to.
@@ -246,7 +248,7 @@ class NET_EXPORT TCPSocketPosix {
bool logging_multiple_connect_attempts_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
DISALLOW_COPY_AND_ASSIGN(TCPSocketPosix);
};
diff --git a/chromium/net/socket/tcp_socket_unittest.cc b/chromium/net/socket/tcp_socket_unittest.cc
index b24d104fd69..b783e94b601 100644
--- a/chromium/net/socket/tcp_socket_unittest.cc
+++ b/chromium/net/socket/tcp_socket_unittest.cc
@@ -17,15 +17,19 @@
#include "net/base/address_list.h"
#include "net/base/io_buffer.h"
#include "net/base/ip_endpoint.h"
-#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/base/sockaddr_storage.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/tcp_client_socket.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -64,13 +68,14 @@ const int kListenBacklog = 5;
class TCPSocketTest : public PlatformTest {
protected:
- TCPSocketTest() : socket_(NULL, NULL, NetLog::Source()) {}
+ TCPSocketTest() : socket_(NULL, NULL, NetLogSource()) {}
void SetUpListenIPv4() {
- ASSERT_EQ(OK, socket_.Open(ADDRESS_FAMILY_IPV4));
- ASSERT_EQ(OK, socket_.Bind(IPEndPoint(IPAddress::IPv4Localhost(), 0)));
- ASSERT_EQ(OK, socket_.Listen(kListenBacklog));
- ASSERT_EQ(OK, socket_.GetLocalAddress(&local_address_));
+ ASSERT_THAT(socket_.Open(ADDRESS_FAMILY_IPV4), IsOk());
+ ASSERT_THAT(socket_.Bind(IPEndPoint(IPAddress::IPv4Localhost(), 0)),
+ IsOk());
+ ASSERT_THAT(socket_.Listen(kListenBacklog), IsOk());
+ ASSERT_THAT(socket_.GetLocalAddress(&local_address_), IsOk());
}
void SetUpListenIPv6(bool* success) {
@@ -83,7 +88,7 @@ class TCPSocketTest : public PlatformTest {
"disabled. Skipping the test";
return;
}
- ASSERT_EQ(OK, socket_.GetLocalAddress(&local_address_));
+ ASSERT_THAT(socket_.GetLocalAddress(&local_address_), IsOk());
*success = true;
}
@@ -97,11 +102,11 @@ class TCPSocketTest : public PlatformTest {
TestCompletionCallback connect_callback;
TCPClientSocket connecting_socket(local_address_list(), NULL, NULL,
- NetLog::Source());
+ NetLogSource());
connecting_socket.Connect(connect_callback.callback());
- EXPECT_EQ(OK, connect_callback.WaitForResult());
- EXPECT_EQ(OK, accept_callback.WaitForResult());
+ EXPECT_THAT(connect_callback.WaitForResult(), IsOk());
+ EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
EXPECT_TRUE(accepted_socket.get());
@@ -138,11 +143,11 @@ class TCPSocketTest : public PlatformTest {
new TestSocketPerformanceWatcher(should_notify_updated_rtt));
TestSocketPerformanceWatcher* watcher_ptr = watcher.get();
- TCPSocket connecting_socket(std::move(watcher), NULL, NetLog::Source());
+ TCPSocket connecting_socket(std::move(watcher), NULL, NetLogSource());
connecting_socket.SetTickClockForTesting(std::move(tick_clock));
int result = connecting_socket.Open(ADDRESS_FAMILY_IPV4);
- ASSERT_EQ(OK, result);
+ ASSERT_THAT(result, IsOk());
connecting_socket.Connect(local_address_, connect_callback.callback());
TestCompletionCallback accept_callback;
@@ -150,14 +155,14 @@ class TCPSocketTest : public PlatformTest {
IPEndPoint accepted_address;
result = socket_.Accept(&accepted_socket, &accepted_address,
accept_callback.callback());
- ASSERT_EQ(OK, accept_callback.GetResult(result));
+ ASSERT_THAT(accept_callback.GetResult(result), IsOk());
ASSERT_TRUE(accepted_socket.get());
// Both sockets should be on the loopback network interface.
EXPECT_EQ(accepted_address.address(), local_address_.address());
- ASSERT_EQ(OK, connect_callback.WaitForResult());
+ ASSERT_THAT(connect_callback.WaitForResult(), IsOk());
for (size_t i = 0; i < num_messages; ++i) {
tick_clock_ptr->Advance(advance_ticks);
@@ -206,7 +211,7 @@ TEST_F(TCPSocketTest, Accept) {
// TODO(yzshen): Switch to use TCPSocket when it supports client socket
// operations.
TCPClientSocket connecting_socket(local_address_list(), NULL, NULL,
- NetLog::Source());
+ NetLogSource());
connecting_socket.Connect(connect_callback.callback());
TestCompletionCallback accept_callback;
@@ -216,14 +221,14 @@ TEST_F(TCPSocketTest, Accept) {
accept_callback.callback());
if (result == ERR_IO_PENDING)
result = accept_callback.WaitForResult();
- ASSERT_EQ(OK, result);
+ ASSERT_THAT(result, IsOk());
EXPECT_TRUE(accepted_socket.get());
// Both sockets should be on the loopback network interface.
EXPECT_EQ(accepted_address.address(), local_address_.address());
- EXPECT_EQ(OK, connect_callback.WaitForResult());
+ EXPECT_THAT(connect_callback.WaitForResult(), IsOk());
}
// Test Accept() callback.
@@ -237,15 +242,15 @@ TEST_F(TCPSocketTest, AcceptAsync) {
TEST_F(TCPSocketTest, AcceptForAdoptedListenSocket) {
// Create a socket to be used with AdoptListenSocket.
SOCKET existing_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- ASSERT_EQ(OK, socket_.AdoptListenSocket(existing_socket));
+ ASSERT_THAT(socket_.AdoptListenSocket(existing_socket), IsOk());
IPEndPoint address(IPAddress::IPv4Localhost(), 0);
SockaddrStorage storage;
ASSERT_TRUE(address.ToSockAddr(storage.addr, &storage.addr_len));
ASSERT_EQ(0, bind(existing_socket, storage.addr, storage.addr_len));
- ASSERT_EQ(OK, socket_.Listen(kListenBacklog));
- ASSERT_EQ(OK, socket_.GetLocalAddress(&local_address_));
+ ASSERT_THAT(socket_.Listen(kListenBacklog), IsOk());
+ ASSERT_THAT(socket_.GetLocalAddress(&local_address_), IsOk());
TestAcceptAsync();
}
@@ -265,15 +270,15 @@ TEST_F(TCPSocketTest, Accept2Connections) {
TestCompletionCallback connect_callback;
TCPClientSocket connecting_socket(local_address_list(), NULL, NULL,
- NetLog::Source());
+ NetLogSource());
connecting_socket.Connect(connect_callback.callback());
TestCompletionCallback connect_callback2;
TCPClientSocket connecting_socket2(local_address_list(), NULL, NULL,
- NetLog::Source());
+ NetLogSource());
connecting_socket2.Connect(connect_callback2.callback());
- EXPECT_EQ(OK, accept_callback.WaitForResult());
+ EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
TestCompletionCallback accept_callback2;
std::unique_ptr<TCPSocket> accepted_socket2;
@@ -283,10 +288,10 @@ TEST_F(TCPSocketTest, Accept2Connections) {
accept_callback2.callback());
if (result == ERR_IO_PENDING)
result = accept_callback2.WaitForResult();
- ASSERT_EQ(OK, result);
+ ASSERT_THAT(result, IsOk());
- EXPECT_EQ(OK, connect_callback.WaitForResult());
- EXPECT_EQ(OK, connect_callback2.WaitForResult());
+ EXPECT_THAT(connect_callback.WaitForResult(), IsOk());
+ EXPECT_THAT(connect_callback2.WaitForResult(), IsOk());
EXPECT_TRUE(accepted_socket.get());
EXPECT_TRUE(accepted_socket2.get());
@@ -305,7 +310,7 @@ TEST_F(TCPSocketTest, AcceptIPv6) {
TestCompletionCallback connect_callback;
TCPClientSocket connecting_socket(local_address_list(), NULL, NULL,
- NetLog::Source());
+ NetLogSource());
connecting_socket.Connect(connect_callback.callback());
TestCompletionCallback accept_callback;
@@ -315,23 +320,23 @@ TEST_F(TCPSocketTest, AcceptIPv6) {
accept_callback.callback());
if (result == ERR_IO_PENDING)
result = accept_callback.WaitForResult();
- ASSERT_EQ(OK, result);
+ ASSERT_THAT(result, IsOk());
EXPECT_TRUE(accepted_socket.get());
// Both sockets should be on the loopback network interface.
EXPECT_EQ(accepted_address.address(), local_address_.address());
- EXPECT_EQ(OK, connect_callback.WaitForResult());
+ EXPECT_THAT(connect_callback.WaitForResult(), IsOk());
}
TEST_F(TCPSocketTest, ReadWrite) {
ASSERT_NO_FATAL_FAILURE(SetUpListenIPv4());
TestCompletionCallback connect_callback;
- TCPSocket connecting_socket(NULL, NULL, NetLog::Source());
+ TCPSocket connecting_socket(NULL, NULL, NetLogSource());
int result = connecting_socket.Open(ADDRESS_FAMILY_IPV4);
- ASSERT_EQ(OK, result);
+ ASSERT_THAT(result, IsOk());
connecting_socket.Connect(local_address_, connect_callback.callback());
TestCompletionCallback accept_callback;
@@ -339,14 +344,14 @@ TEST_F(TCPSocketTest, ReadWrite) {
IPEndPoint accepted_address;
result = socket_.Accept(&accepted_socket, &accepted_address,
accept_callback.callback());
- ASSERT_EQ(OK, accept_callback.GetResult(result));
+ ASSERT_THAT(accept_callback.GetResult(result), IsOk());
ASSERT_TRUE(accepted_socket.get());
// Both sockets should be on the loopback network interface.
EXPECT_EQ(accepted_address.address(), local_address_.address());
- EXPECT_EQ(OK, connect_callback.WaitForResult());
+ EXPECT_THAT(connect_callback.WaitForResult(), IsOk());
const std::string message("test message");
std::vector<char> buffer(message.size());
diff --git a/chromium/net/socket/tcp_socket_win.cc b/chromium/net/socket/tcp_socket_win.cc
index d4fba8d4720..d879a5ee95e 100644
--- a/chromium/net/socket/tcp_socket_win.cc
+++ b/chromium/net/socket/tcp_socket_win.cc
@@ -24,6 +24,10 @@
#include "net/base/sockaddr_storage.h"
#include "net/base/winsock_init.h"
#include "net/base/winsock_util.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
#include "net/socket/socket_descriptor.h"
#include "net/socket/socket_net_log_params.h"
@@ -244,7 +248,7 @@ void TCPSocketWin::Core::WriteDelegate::OnObjectSignaled(
TCPSocketWin::TCPSocketWin(
std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
net::NetLog* net_log,
- const net::NetLog::Source& source)
+ const net::NetLogSource& source)
: socket_(INVALID_SOCKET),
socket_performance_watcher_(std::move(socket_performance_watcher)),
accept_event_(WSA_INVALID_EVENT),
@@ -255,15 +259,15 @@ TCPSocketWin::TCPSocketWin(
waiting_write_(false),
connect_os_error_(0),
logging_multiple_connect_attempts_(false),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
- net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
+ net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::SOCKET)) {
+ net_log_.BeginEvent(NetLogEventType::SOCKET_ALIVE,
source.ToEventParametersCallback());
EnsureWinsockInit();
}
TCPSocketWin::~TCPSocketWin() {
Close();
- net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
+ net_log_.EndEvent(NetLogEventType::SOCKET_ALIVE);
}
int TCPSocketWin::Open(AddressFamily family) {
@@ -371,7 +375,7 @@ int TCPSocketWin::Accept(std::unique_ptr<TCPSocketWin>* socket,
DCHECK(!callback.is_null());
DCHECK(accept_callback_.is_null());
- net_log_.BeginEvent(NetLog::TYPE_TCP_ACCEPT);
+ net_log_.BeginEvent(NetLogEventType::TCP_ACCEPT);
int result = AcceptInternal(socket, address);
@@ -504,7 +508,7 @@ int TCPSocketWin::Write(IOBuffer* buf,
<< " bytes, but " << rv << " bytes reported.";
return ERR_WINSOCK_UNEXPECTED_WRITTEN_BYTES;
}
- net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, rv,
+ net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_SENT, rv,
buf->data());
NetworkActivityMonitor::GetInstance()->IncrementBytesSent(rv);
return rv;
@@ -513,7 +517,7 @@ int TCPSocketWin::Write(IOBuffer* buf,
int os_error = WSAGetLastError();
if (os_error != WSA_IO_PENDING) {
int net_error = MapSystemError(os_error);
- net_log_.AddEvent(NetLog::TYPE_SOCKET_WRITE_ERROR,
+ net_log_.AddEvent(NetLogEventType::SOCKET_WRITE_ERROR,
CreateNetLogSocketErrorCallback(net_error, os_error));
return net_error;
}
@@ -606,7 +610,7 @@ void TCPSocketWin::Close() {
if (socket_ != INVALID_SOCKET) {
// Only log the close event if there's actually a socket to close.
- net_log_.AddEvent(NetLog::EventType::TYPE_SOCKET_CLOSED);
+ net_log_.AddEvent(NetLogEventType::SOCKET_CLOSED);
// Note: don't use CancelIo to cancel pending IO because it doesn't work
// when there is a Winsock layered service provider.
@@ -688,7 +692,7 @@ int TCPSocketWin::AcceptInternal(std::unique_ptr<TCPSocketWin>* socket,
if (new_socket < 0) {
int net_error = MapSystemError(WSAGetLastError());
if (net_error != ERR_IO_PENDING)
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, net_error);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::TCP_ACCEPT, net_error);
return net_error;
}
@@ -698,19 +702,20 @@ int TCPSocketWin::AcceptInternal(std::unique_ptr<TCPSocketWin>* socket,
if (closesocket(new_socket) < 0)
PLOG(ERROR) << "closesocket";
int net_error = ERR_ADDRESS_INVALID;
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, net_error);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::TCP_ACCEPT, net_error);
return net_error;
}
std::unique_ptr<TCPSocketWin> tcp_socket(
new TCPSocketWin(NULL, net_log_.net_log(), net_log_.source()));
int adopt_result = tcp_socket->AdoptConnectedSocket(new_socket, ip_end_point);
if (adopt_result != OK) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, adopt_result);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::TCP_ACCEPT,
+ adopt_result);
return adopt_result;
}
*socket = std::move(tcp_socket);
*address = ip_end_point;
- net_log_.EndEvent(NetLog::TYPE_TCP_ACCEPT,
+ net_log_.EndEvent(NetLogEventType::TCP_ACCEPT,
CreateNetLogIPEndPointCallback(&ip_end_point));
return OK;
}
@@ -744,7 +749,7 @@ int TCPSocketWin::DoConnect() {
DCHECK_EQ(connect_os_error_, 0);
DCHECK(!core_.get());
- net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
+ net_log_.BeginEvent(NetLogEventType::TCP_CONNECT_ATTEMPT,
CreateNetLogIPEndPointCallback(peer_address_.get()));
core_ = new Core(this);
@@ -804,10 +809,10 @@ void TCPSocketWin::DoConnectComplete(int result) {
int os_error = connect_os_error_;
connect_os_error_ = 0;
if (result != OK) {
- net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
+ net_log_.EndEvent(NetLogEventType::TCP_CONNECT_ATTEMPT,
NetLog::IntCallback("os_error", os_error));
} else {
- net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT);
+ net_log_.EndEvent(NetLogEventType::TCP_CONNECT_ATTEMPT);
}
if (!logging_multiple_connect_attempts_)
@@ -815,13 +820,13 @@ void TCPSocketWin::DoConnectComplete(int result) {
}
void TCPSocketWin::LogConnectBegin(const AddressList& addresses) {
- net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT,
+ net_log_.BeginEvent(NetLogEventType::TCP_CONNECT,
addresses.CreateNetLogCallback());
}
void TCPSocketWin::LogConnectEnd(int net_error) {
if (net_error != OK) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, net_error);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::TCP_CONNECT, net_error);
return;
}
@@ -833,12 +838,12 @@ void TCPSocketWin::LogConnectEnd(int net_error) {
LOG(ERROR) << "getsockname() [rv: " << rv
<< "] error: " << WSAGetLastError();
NOTREACHED();
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, rv);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::TCP_CONNECT, rv);
return;
}
net_log_.EndEvent(
- NetLog::TYPE_TCP_CONNECT,
+ NetLogEventType::TCP_CONNECT,
CreateNetLogSourceAddressCallback(
reinterpret_cast<const struct sockaddr*>(&source_address),
sizeof(source_address)));
@@ -856,13 +861,12 @@ int TCPSocketWin::DoRead(IOBuffer* buf, int buf_len,
int os_error = WSAGetLastError();
if (os_error != WSAEWOULDBLOCK) {
int net_error = MapSystemError(os_error);
- net_log_.AddEvent(
- NetLog::TYPE_SOCKET_READ_ERROR,
- CreateNetLogSocketErrorCallback(net_error, os_error));
+ net_log_.AddEvent(NetLogEventType::SOCKET_READ_ERROR,
+ CreateNetLogSocketErrorCallback(net_error, os_error));
return net_error;
}
} else {
- net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, rv,
+ net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, rv,
buf->data());
NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(rv);
return rv;
@@ -929,7 +933,7 @@ void TCPSocketWin::DidCompleteWrite() {
if (!ok) {
int os_error = WSAGetLastError();
rv = MapSystemError(os_error);
- net_log_.AddEvent(NetLog::TYPE_SOCKET_WRITE_ERROR,
+ net_log_.AddEvent(NetLogEventType::SOCKET_WRITE_ERROR,
CreateNetLogSocketErrorCallback(rv, os_error));
} else {
rv = static_cast<int>(num_bytes);
@@ -941,8 +945,8 @@ void TCPSocketWin::DidCompleteWrite() {
<< " bytes reported.";
rv = ERR_WINSOCK_UNEXPECTED_WRITTEN_BYTES;
} else {
- net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, num_bytes,
- core_->write_iobuffer_->data());
+ net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_SENT,
+ num_bytes, core_->write_iobuffer_->data());
NetworkActivityMonitor::GetInstance()->IncrementBytesSent(num_bytes);
}
}
diff --git a/chromium/net/socket/tcp_socket_win.h b/chromium/net/socket/tcp_socket_win.h
index 63491f67f4c..54e115b38f3 100644
--- a/chromium/net/socket/tcp_socket_win.h
+++ b/chromium/net/socket/tcp_socket_win.h
@@ -18,7 +18,7 @@
#include "net/base/address_family.h"
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/socket_performance_watcher.h"
namespace net {
@@ -26,6 +26,8 @@ namespace net {
class AddressList;
class IOBuffer;
class IPEndPoint;
+class NetLog;
+struct NetLogSource;
class NET_EXPORT TCPSocketWin : NON_EXPORTED_BASE(public base::NonThreadSafe),
public base::win::ObjectWatcher::Delegate {
@@ -33,7 +35,7 @@ class NET_EXPORT TCPSocketWin : NON_EXPORTED_BASE(public base::NonThreadSafe),
TCPSocketWin(
std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
NetLog* net_log,
- const NetLog::Source& source);
+ const NetLogSource& source);
~TCPSocketWin() override;
int Open(AddressFamily family);
@@ -99,16 +101,16 @@ class NET_EXPORT TCPSocketWin : NON_EXPORTED_BASE(public base::NonThreadSafe),
//
// TCPClientSocket may attempt to connect to multiple addresses until it
// succeeds in establishing a connection. The corresponding log will have
- // multiple NetLog::TYPE_TCP_CONNECT_ATTEMPT entries nested within a
- // NetLog::TYPE_TCP_CONNECT. These methods set the start/end of
- // NetLog::TYPE_TCP_CONNECT.
+ // multiple NetLogEventType::TCP_CONNECT_ATTEMPT entries nested within a
+ // NetLogEventType::TCP_CONNECT. These methods set the start/end of
+ // NetLogEventType::TCP_CONNECT.
//
// TODO(yzshen): Change logging format and let TCPClientSocket log the
// start/end of a series of connect attempts itself.
void StartLoggingMultipleConnectAttempts(const AddressList& addresses);
void EndLoggingMultipleConnectAttempts(int net_error);
- const BoundNetLog& net_log() const { return net_log_; }
+ const NetLogWithSource& net_log() const { return net_log_; }
private:
class Core;
@@ -164,7 +166,7 @@ class NET_EXPORT TCPSocketWin : NON_EXPORTED_BASE(public base::NonThreadSafe),
bool logging_multiple_connect_attempts_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
DISALLOW_COPY_AND_ASSIGN(TCPSocketWin);
};
diff --git a/chromium/net/socket/transport_client_socket_pool.cc b/chromium/net/socket/transport_client_socket_pool.cc
index 88d51e239ba..26fcb1d374a 100644
--- a/chromium/net/socket/transport_client_socket_pool.cc
+++ b/chromium/net/socket/transport_client_socket_pool.cc
@@ -21,6 +21,9 @@
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source_type.h"
+#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/client_socket_pool_base.h"
@@ -101,12 +104,13 @@ TransportConnectJob::TransportConnectJob(
HostResolver* host_resolver,
Delegate* delegate,
NetLog* net_log)
- : ConnectJob(group_name,
- timeout_duration,
- priority,
- respect_limits,
- delegate,
- BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
+ : ConnectJob(
+ group_name,
+ timeout_duration,
+ priority,
+ respect_limits,
+ delegate,
+ NetLogWithSource::Make(net_log, NetLogSourceType::CONNECT_JOB)),
params_(params),
resolver_(host_resolver),
client_socket_factory_(client_socket_factory),
@@ -117,7 +121,7 @@ TransportConnectJob::TransportConnectJob(
TransportConnectJob::~TransportConnectJob() {
// We don't worry about cancelling the host resolution and TCP connect, since
- // ~SingleRequestHostResolver and ~StreamSocket will take care of it.
+ // ~HostResolver::Request and ~StreamSocket will take care of it.
}
LoadState TransportConnectJob::GetLoadState() const {
@@ -268,10 +272,10 @@ int TransportConnectJob::DoResolveHost() {
next_state_ = STATE_RESOLVE_HOST_COMPLETE;
connect_timing_.dns_start = base::TimeTicks::Now();
- return resolver_.Resolve(
+ return resolver_->Resolve(
params_->destination(), priority(), &addresses_,
base::Bind(&TransportConnectJob::OnIOComplete, base::Unretained(this)),
- net_log());
+ &request_, net_log());
}
int TransportConnectJob::DoResolveHostComplete(int result) {
@@ -556,7 +560,7 @@ int TransportClientSocketPool::RequestSocket(const std::string& group_name,
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
const scoped_refptr<TransportSocketParams>* casted_params =
static_cast<const scoped_refptr<TransportSocketParams>*>(params);
@@ -567,12 +571,12 @@ int TransportClientSocketPool::RequestSocket(const std::string& group_name,
}
void TransportClientSocketPool::NetLogTcpClientSocketPoolRequestedSocket(
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const scoped_refptr<TransportSocketParams>* casted_params) {
if (net_log.IsCapturing()) {
// TODO(eroman): Split out the host and port parameters.
net_log.AddEvent(
- NetLog::TYPE_TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKET,
+ NetLogEventType::TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKET,
CreateNetLogHostPortPairCallback(
&casted_params->get()->destination().host_port_pair()));
}
@@ -582,14 +586,14 @@ void TransportClientSocketPool::RequestSockets(
const std::string& group_name,
const void* params,
int num_sockets,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
const scoped_refptr<TransportSocketParams>* casted_params =
static_cast<const scoped_refptr<TransportSocketParams>*>(params);
if (net_log.IsCapturing()) {
// TODO(eroman): Split out the host and port parameters.
net_log.AddEvent(
- NetLog::TYPE_TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKETS,
+ NetLogEventType::TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKETS,
CreateNetLogHostPortPairCallback(
&casted_params->get()->destination().host_port_pair()));
}
diff --git a/chromium/net/socket/transport_client_socket_pool.h b/chromium/net/socket/transport_client_socket_pool.h
index 3ae91c5002e..5e2ba45e952 100644
--- a/chromium/net/socket/transport_client_socket_pool.h
+++ b/chromium/net/socket/transport_client_socket_pool.h
@@ -13,8 +13,8 @@
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "net/base/host_port_pair.h"
+#include "net/base/net_export.h"
#include "net/dns/host_resolver.h"
-#include "net/dns/single_request_host_resolver.h"
#include "net/socket/client_socket_pool.h"
#include "net/socket/client_socket_pool_base.h"
#include "net/socket/connection_attempts.h"
@@ -23,9 +23,11 @@ namespace net {
class ClientSocketFactory;
class SocketPerformanceWatcherFactory;
+class NetLog;
+class NetLogWithSource;
-typedef base::Callback<int(const AddressList&, const BoundNetLog& net_log)>
-OnHostResolutionCallback;
+typedef base::Callback<int(const AddressList&, const NetLogWithSource& net_log)>
+ OnHostResolutionCallback;
class NET_EXPORT_PRIVATE TransportSocketParams
: public base::RefCounted<TransportSocketParams> {
@@ -164,7 +166,8 @@ class NET_EXPORT_PRIVATE TransportConnectJob : public ConnectJob {
void CopyConnectionAttemptsFromSockets();
scoped_refptr<TransportSocketParams> params_;
- SingleRequestHostResolver resolver_;
+ HostResolver* resolver_;
+ std::unique_ptr<HostResolver::Request> request_;
ClientSocketFactory* const client_socket_factory_;
State next_state_;
@@ -215,11 +218,11 @@ class NET_EXPORT_PRIVATE TransportClientSocketPool : public ClientSocketPool {
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void RequestSockets(const std::string& group_name,
const void* params,
int num_sockets,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void CancelRequest(const std::string& group_name,
ClientSocketHandle* handle) override;
void ReleaseSocket(const std::string& group_name,
@@ -245,7 +248,7 @@ class NET_EXPORT_PRIVATE TransportClientSocketPool : public ClientSocketPool {
protected:
// Methods shared with WebSocketTransportClientSocketPool
void NetLogTcpClientSocketPoolRequestedSocket(
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const scoped_refptr<TransportSocketParams>* casted_params);
private:
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 3dbffa61559..4482fad7935 100644
--- a/chromium/net/socket/transport_client_socket_pool_test_util.cc
+++ b/chromium/net/socket/transport_client_socket_pool_test_util.cc
@@ -19,6 +19,9 @@
#include "net/base/ip_endpoint.h"
#include "net/base/load_timing_info.h"
#include "net/base/load_timing_info_test_util.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/ssl_client_socket.h"
#include "net/udp/datagram_client_socket.h"
@@ -40,7 +43,7 @@ class MockConnectClientSocket : public StreamSocket {
MockConnectClientSocket(const AddressList& addrlist, net::NetLog* net_log)
: connected_(false),
addrlist_(addrlist),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {}
+ net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::SOCKET)) {}
// StreamSocket implementation.
int Connect(const CompletionCallback& callback) override {
@@ -64,7 +67,7 @@ class MockConnectClientSocket : public StreamSocket {
SetIPv6Address(address);
return OK;
}
- const BoundNetLog& NetLog() const override { return net_log_; }
+ const NetLogWithSource& NetLog() const override { return net_log_; }
void SetSubresourceSpeculation() override {}
void SetOmniboxSpeculation() override {}
@@ -100,7 +103,7 @@ class MockConnectClientSocket : public StreamSocket {
private:
bool connected_;
const AddressList addrlist_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
DISALLOW_COPY_AND_ASSIGN(MockConnectClientSocket);
};
@@ -109,7 +112,7 @@ class MockFailingClientSocket : public StreamSocket {
public:
MockFailingClientSocket(const AddressList& addrlist, net::NetLog* net_log)
: addrlist_(addrlist),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {}
+ net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::SOCKET)) {}
// StreamSocket implementation.
int Connect(const CompletionCallback& callback) override {
@@ -126,7 +129,7 @@ class MockFailingClientSocket : public StreamSocket {
int GetLocalAddress(IPEndPoint* address) const override {
return ERR_UNEXPECTED;
}
- const BoundNetLog& NetLog() const override { return net_log_; }
+ const NetLogWithSource& NetLog() const override { return net_log_; }
void SetSubresourceSpeculation() override {}
void SetOmniboxSpeculation() override {}
@@ -164,7 +167,7 @@ class MockFailingClientSocket : public StreamSocket {
private:
const AddressList addrlist_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
DISALLOW_COPY_AND_ASSIGN(MockFailingClientSocket);
};
@@ -179,7 +182,7 @@ class MockTriggerableClientSocket : public StreamSocket {
: should_connect_(should_connect),
is_connected_(false),
addrlist_(addrlist),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)),
+ net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::SOCKET)),
weak_factory_(this) {}
// Call this method to get a closure which will trigger the connect callback
@@ -252,7 +255,7 @@ class MockTriggerableClientSocket : public StreamSocket {
SetIPv6Address(address);
return OK;
}
- const BoundNetLog& NetLog() const override { return net_log_; }
+ const NetLogWithSource& NetLog() const override { return net_log_; }
void SetSubresourceSpeculation() override {}
void SetOmniboxSpeculation() override {}
@@ -298,7 +301,7 @@ class MockTriggerableClientSocket : public StreamSocket {
bool should_connect_;
bool is_connected_;
const AddressList addrlist_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
CompletionCallback callback_;
ConnectionAttempts connection_attempts_;
@@ -316,7 +319,7 @@ void TestLoadTimingInfoConnectedReused(const ClientSocketHandle& handle) {
EXPECT_TRUE(handle.GetLoadTimingInfo(true, &load_timing_info));
EXPECT_TRUE(load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
@@ -329,7 +332,7 @@ void TestLoadTimingInfoConnectedNotReused(const ClientSocketHandle& handle) {
EXPECT_TRUE(handle.GetLoadTimingInfo(false, &load_timing_info));
EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
ExpectConnectTimingHasTimes(load_timing_info.connect_timing,
CONNECT_TIMING_HAS_DNS_TIMES);
@@ -364,7 +367,7 @@ MockTransportClientSocketFactory::CreateDatagramClientSocket(
DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
NetLog* net_log,
- const NetLog::Source& source) {
+ const NetLogSource& source) {
NOTREACHED();
return std::unique_ptr<DatagramClientSocket>();
}
@@ -374,7 +377,7 @@ MockTransportClientSocketFactory::CreateTransportClientSocket(
const AddressList& addresses,
std::unique_ptr<SocketPerformanceWatcher> /* socket_performance_watcher */,
NetLog* /* net_log */,
- const NetLog::Source& /* source */) {
+ const NetLogSource& /* source */) {
allocation_count_++;
ClientSocketType type = client_socket_type_;
diff --git a/chromium/net/socket/transport_client_socket_pool_test_util.h b/chromium/net/socket/transport_client_socket_pool_test_util.h
index 97702a87a40..a15b400ee44 100644
--- a/chromium/net/socket/transport_client_socket_pool_test_util.h
+++ b/chromium/net/socket/transport_client_socket_pool_test_util.h
@@ -17,7 +17,6 @@
#include "base/macros.h"
#include "base/time/time.h"
#include "net/base/address_list.h"
-#include "net/log/net_log.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/socket_performance_watcher.h"
@@ -27,6 +26,7 @@ namespace net {
class ClientSocketHandle;
class IPEndPoint;
+class NetLog;
// Make sure |handle| sets load times correctly when it has been assigned a
// reused socket. Uses gtest expectations.
@@ -77,14 +77,14 @@ class MockTransportClientSocketFactory : public ClientSocketFactory {
DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
NetLog* net_log,
- const NetLog::Source& source) override;
+ const NetLogSource& source) override;
std::unique_ptr<StreamSocket> CreateTransportClientSocket(
const AddressList& addresses,
std::unique_ptr<
SocketPerformanceWatcher> /* socket_performance_watcher */,
NetLog* /* net_log */,
- const NetLog::Source& /* source */) override;
+ const NetLogSource& /* source */) override;
std::unique_ptr<SSLClientSocket> CreateSSLClientSocket(
std::unique_ptr<ClientSocketHandle> transport_socket,
diff --git a/chromium/net/socket/transport_client_socket_pool_unittest.cc b/chromium/net/socket/transport_client_socket_pool_unittest.cc
index ddfe941e6c8..cbe31e1fb01 100644
--- a/chromium/net/socket/transport_client_socket_pool_unittest.cc
+++ b/chromium/net/socket/transport_client_socket_pool_unittest.cc
@@ -18,13 +18,19 @@
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/dns/mock_host_resolver.h"
+#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_test_util.h"
#include "net/socket/stream_socket.h"
#include "net/socket/transport_client_socket_pool_test_util.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
using internal::ClientSocketPoolBaseHelper;
@@ -177,12 +183,12 @@ TEST_F(TransportClientSocketPoolTest, Basic) {
ClientSocketHandle handle;
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfoConnectedNotReused(handle);
@@ -199,7 +205,7 @@ TEST_F(TransportClientSocketPoolTest, SetResolvePriorityOnInit) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, priority,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog()));
+ callback.callback(), &pool_, NetLogWithSource()));
EXPECT_EQ(priority, host_resolver_->last_request_priority());
}
}
@@ -215,11 +221,12 @@ TEST_F(TransportClientSocketPoolTest, InitHostResolutionFailure) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", dest, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog()));
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback.WaitForResult());
+ callback.callback(), &pool_, NetLogWithSource()));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED));
ASSERT_EQ(1u, handle.connection_attempts().size());
EXPECT_TRUE(handle.connection_attempts()[0].endpoint.address().empty());
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, handle.connection_attempts()[0].result);
+ EXPECT_THAT(handle.connection_attempts()[0].result,
+ IsError(ERR_NAME_NOT_RESOLVED));
}
TEST_F(TransportClientSocketPoolTest, InitConnectionFailure) {
@@ -230,51 +237,53 @@ TEST_F(TransportClientSocketPoolTest, InitConnectionFailure) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog()));
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
+ callback.callback(), &pool_, NetLogWithSource()));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
ASSERT_EQ(1u, handle.connection_attempts().size());
EXPECT_EQ("127.0.0.1:80",
handle.connection_attempts()[0].endpoint.ToString());
- EXPECT_EQ(ERR_CONNECTION_FAILED, handle.connection_attempts()[0].result);
+ EXPECT_THAT(handle.connection_attempts()[0].result,
+ IsError(ERR_CONNECTION_FAILED));
// Make the host resolutions complete synchronously this time.
host_resolver_->set_synchronous_mode(true);
EXPECT_EQ(ERR_CONNECTION_FAILED,
handle.Init("a", params_, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog()));
+ callback.callback(), &pool_, NetLogWithSource()));
ASSERT_EQ(1u, handle.connection_attempts().size());
EXPECT_EQ("127.0.0.1:80",
handle.connection_attempts()[0].endpoint.ToString());
- EXPECT_EQ(ERR_CONNECTION_FAILED, handle.connection_attempts()[0].result);
+ EXPECT_THAT(handle.connection_attempts()[0].result,
+ IsError(ERR_CONNECTION_FAILED));
}
TEST_F(TransportClientSocketPoolTest, PendingRequests) {
// First request finishes asynchronously.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, (*requests())[0]->WaitForResult());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT((*requests())[0]->WaitForResult(), IsOk());
// Make all subsequent host resolutions complete synchronously.
host_resolver_->set_synchronous_mode(true);
// Rest of them finish synchronously, until we reach the per-group limit.
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
// The rest are pending since we've used all active sockets.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
+ EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", MEDIUM), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOW), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", MEDIUM), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", MEDIUM), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE);
@@ -309,34 +318,34 @@ TEST_F(TransportClientSocketPoolTest, PendingRequests) {
TEST_F(TransportClientSocketPoolTest, PendingRequests_NoKeepAlive) {
// First request finishes asynchronously.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, (*requests())[0]->WaitForResult());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT((*requests())[0]->WaitForResult(), IsOk());
// Make all subsequent host resolutions complete synchronously.
host_resolver_->set_synchronous_mode(true);
// Rest of them finish synchronously, until we reach the per-group limit.
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
// The rest are pending since we've used all active sockets.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
// The pending requests should finish successfully.
- EXPECT_EQ(OK, (*requests())[6]->WaitForResult());
- EXPECT_EQ(OK, (*requests())[7]->WaitForResult());
- EXPECT_EQ(OK, (*requests())[8]->WaitForResult());
- EXPECT_EQ(OK, (*requests())[9]->WaitForResult());
- EXPECT_EQ(OK, (*requests())[10]->WaitForResult());
+ EXPECT_THAT((*requests())[6]->WaitForResult(), IsOk());
+ EXPECT_THAT((*requests())[7]->WaitForResult(), IsOk());
+ EXPECT_THAT((*requests())[8]->WaitForResult(), IsOk());
+ EXPECT_THAT((*requests())[9]->WaitForResult(), IsOk());
+ EXPECT_THAT((*requests())[10]->WaitForResult(), IsOk());
EXPECT_EQ(static_cast<int>(requests()->size()),
client_socket_factory_.allocation_count());
@@ -354,7 +363,7 @@ TEST_F(TransportClientSocketPoolTest, CancelRequestClearGroup) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog()));
+ callback.callback(), &pool_, NetLogWithSource()));
handle.Reset();
}
@@ -367,15 +376,15 @@ TEST_F(TransportClientSocketPoolTest, TwoRequestsCancelOne) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog()));
+ callback.callback(), &pool_, NetLogWithSource()));
EXPECT_EQ(ERR_IO_PENDING,
handle2.Init("a", params_, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), &pool_, BoundNetLog()));
+ callback2.callback(), &pool_, NetLogWithSource()));
handle.Reset();
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
handle2.Reset();
}
@@ -387,7 +396,7 @@ TEST_F(TransportClientSocketPoolTest, ConnectCancelConnect) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog()));
+ callback.callback(), &pool_, NetLogWithSource()));
handle.Reset();
@@ -395,7 +404,7 @@ TEST_F(TransportClientSocketPoolTest, ConnectCancelConnect) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), &pool_, BoundNetLog()));
+ callback2.callback(), &pool_, NetLogWithSource()));
host_resolver_->set_synchronous_mode(true);
// At this point, handle has two ConnectingSockets out for it. Due to the
@@ -407,7 +416,7 @@ TEST_F(TransportClientSocketPoolTest, ConnectCancelConnect) {
// If the first one is not cancelled, it will advance the load state, and
// then the second one will crash.
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_FALSE(callback.have_result());
handle.Reset();
@@ -415,29 +424,29 @@ TEST_F(TransportClientSocketPoolTest, ConnectCancelConnect) {
TEST_F(TransportClientSocketPoolTest, CancelRequest) {
// First request finishes asynchronously.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, (*requests())[0]->WaitForResult());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT((*requests())[0]->WaitForResult(), IsOk());
// Make all subsequent host resolutions complete synchronously.
host_resolver_->set_synchronous_mode(true);
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
// Reached per-group limit, queue up requests.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
+ EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", MEDIUM), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", MEDIUM), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOW), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOW), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOW), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
// Cancel a request.
size_t index_to_cancel = kMaxSocketsPerGroup + 2;
@@ -490,7 +499,7 @@ class RequestSocketCallback : public TestCompletionCallbackBase {
private:
void OnComplete(int result) {
SetResult(result);
- ASSERT_EQ(OK, result);
+ ASSERT_THAT(result, IsOk());
if (!within_callback_) {
// Don't allow reuse of the socket. Disconnect it and then release it and
@@ -508,8 +517,8 @@ class RequestSocketCallback : public TestCompletionCallbackBase {
TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT));
int rv = handle_->Init("a", dest, LOWEST,
ClientSocketPool::RespectLimits::ENABLED,
- callback(), pool_, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ callback(), pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
}
}
@@ -529,14 +538,14 @@ TEST_F(TransportClientSocketPoolTest, RequestTwice) {
TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT));
int rv =
handle.Init("a", dest, LOWEST, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ 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
// synchronously this time.
host_resolver_->set_synchronous_mode(true);
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
handle.Reset();
}
@@ -548,15 +557,15 @@ TEST_F(TransportClientSocketPoolTest, CancelActiveRequestWithPendingRequests) {
MockTransportClientSocketFactory::MOCK_PENDING_CLIENT_SOCKET);
// Queue up all the requests
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
// Now, kMaxSocketsPerGroup requests should be active. Let's cancel them.
ASSERT_LE(kMaxSocketsPerGroup, static_cast<int>(requests()->size()));
@@ -565,7 +574,7 @@ TEST_F(TransportClientSocketPoolTest, CancelActiveRequestWithPendingRequests) {
// Let's wait for the rest to complete now.
for (size_t i = kMaxSocketsPerGroup; i < requests()->size(); ++i) {
- EXPECT_EQ(OK, (*requests())[i]->WaitForResult());
+ EXPECT_THAT((*requests())[i]->WaitForResult(), IsOk());
(*requests())[i]->handle()->Reset();
}
@@ -582,10 +591,11 @@ TEST_F(TransportClientSocketPoolTest, FailingActiveRequestWithPendingRequests) {
// Queue up all the requests
for (int i = 0; i < kNumRequests; i++)
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
for (int i = 0; i < kNumRequests; i++)
- EXPECT_EQ(ERR_CONNECTION_FAILED, (*requests())[i]->WaitForResult());
+ EXPECT_THAT((*requests())[i]->WaitForResult(),
+ IsError(ERR_CONNECTION_FAILED));
}
TEST_F(TransportClientSocketPoolTest, IdleSocketLoadTiming) {
@@ -593,12 +603,12 @@ TEST_F(TransportClientSocketPoolTest, IdleSocketLoadTiming) {
ClientSocketHandle handle;
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfoConnectedNotReused(handle);
@@ -611,8 +621,8 @@ TEST_F(TransportClientSocketPoolTest, IdleSocketLoadTiming) {
EXPECT_EQ(1, pool_.IdleSocketCount());
rv = handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ callback.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ(0, pool_.IdleSocketCount());
TestLoadTimingInfoConnectedReused(handle);
}
@@ -622,12 +632,12 @@ TEST_F(TransportClientSocketPoolTest, ResetIdleSocketsOnIPAddressChange) {
ClientSocketHandle handle;
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
@@ -679,8 +689,8 @@ TEST_F(TransportClientSocketPoolTest, BackupSocketConnect) {
ClientSocketHandle handle;
int rv =
handle.Init("b", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -694,7 +704,7 @@ TEST_F(TransportClientSocketPoolTest, BackupSocketConnect) {
// Let the appropriate socket connect.
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
@@ -722,8 +732,8 @@ TEST_F(TransportClientSocketPoolTest, BackupSocketCancel) {
ClientSocketHandle handle;
int rv =
handle.Init("c", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -769,8 +779,8 @@ TEST_F(TransportClientSocketPoolTest, BackupSocketFailAfterStall) {
ClientSocketHandle handle;
int rv =
handle.Init("b", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -788,11 +798,12 @@ TEST_F(TransportClientSocketPoolTest, BackupSocketFailAfterStall) {
// Let the appropriate socket connect.
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
ASSERT_EQ(1u, handle.connection_attempts().size());
- EXPECT_EQ(ERR_CONNECTION_FAILED, handle.connection_attempts()[0].result);
+ EXPECT_THAT(handle.connection_attempts()[0].result,
+ IsError(ERR_CONNECTION_FAILED));
EXPECT_EQ(0, pool_.IdleSocketCount());
handle.Reset();
@@ -820,8 +831,8 @@ TEST_F(TransportClientSocketPoolTest, BackupSocketFailAfterDelay) {
ClientSocketHandle handle;
int rv =
handle.Init("b", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
@@ -839,11 +850,12 @@ TEST_F(TransportClientSocketPoolTest, BackupSocketFailAfterDelay) {
// Let the appropriate socket connect.
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
ASSERT_EQ(1u, handle.connection_attempts().size());
- EXPECT_EQ(ERR_CONNECTION_FAILED, handle.connection_attempts()[0].result);
+ EXPECT_THAT(handle.connection_attempts()[0].result,
+ IsError(ERR_CONNECTION_FAILED));
handle.Reset();
// Reset for the next case.
@@ -876,12 +888,12 @@ TEST_F(TransportClientSocketPoolTest, IPv6FallbackSocketIPv4FinishesFirst) {
ClientSocketHandle handle;
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
IPEndPoint endpoint;
@@ -892,7 +904,7 @@ TEST_F(TransportClientSocketPoolTest, IPv6FallbackSocketIPv4FinishesFirst) {
ConnectionAttempts attempts;
handle.socket()->GetConnectionAttempts(&attempts);
ASSERT_EQ(1u, attempts.size());
- EXPECT_EQ(ERR_CONNECTION_FAILED, attempts[0].result);
+ EXPECT_THAT(attempts[0].result, IsError(ERR_CONNECTION_FAILED));
EXPECT_TRUE(attempts[0].endpoint.address().IsIPv6());
EXPECT_EQ(2, client_socket_factory_.allocation_count());
@@ -927,12 +939,12 @@ TEST_F(TransportClientSocketPoolTest, IPv6FallbackSocketIPv6FinishesFirst) {
ClientSocketHandle handle;
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
IPEndPoint endpoint;
@@ -944,7 +956,7 @@ TEST_F(TransportClientSocketPoolTest, IPv6FallbackSocketIPv6FinishesFirst) {
ConnectionAttempts attempts;
handle.socket()->GetConnectionAttempts(&attempts);
ASSERT_EQ(1u, attempts.size());
- EXPECT_EQ(ERR_CONNECTION_FAILED, attempts[0].result);
+ EXPECT_THAT(attempts[0].result, IsError(ERR_CONNECTION_FAILED));
EXPECT_TRUE(attempts[0].endpoint.address().IsIPv4());
EXPECT_EQ(2, client_socket_factory_.allocation_count());
@@ -968,12 +980,12 @@ TEST_F(TransportClientSocketPoolTest, IPv6NoIPv4AddressesToFallbackTo) {
ClientSocketHandle handle;
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
IPEndPoint endpoint;
@@ -1000,12 +1012,12 @@ TEST_F(TransportClientSocketPoolTest, IPv4HasNoFallback) {
ClientSocketHandle handle;
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
IPEndPoint endpoint;
@@ -1033,8 +1045,8 @@ TEST_F(TransportClientSocketPoolTest, TCPFastOpenOnIPv4WithNoFallback) {
// Enable TCP FastOpen in TransportSocketParams.
scoped_refptr<TransportSocketParams> params = CreateParamsForTCPFastOpen();
handle.Init("a", params, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(OK, callback.WaitForResult());
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(socket_data.IsUsingTCPFastOpen());
}
@@ -1059,8 +1071,8 @@ TEST_F(TransportClientSocketPoolTest, TCPFastOpenOnIPv6WithNoFallback) {
// Enable TCP FastOpen in TransportSocketParams.
scoped_refptr<TransportSocketParams> params = CreateParamsForTCPFastOpen();
handle.Init("a", params, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(OK, callback.WaitForResult());
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(socket_data.IsUsingTCPFastOpen());
}
@@ -1089,8 +1101,8 @@ TEST_F(TransportClientSocketPoolTest,
// Enable TCP FastOpen in TransportSocketParams.
scoped_refptr<TransportSocketParams> params = CreateParamsForTCPFastOpen();
handle.Init("a", params, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(OK, callback.WaitForResult());
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// Verify that the socket used is connected to the fallback IPv4 address.
IPEndPoint endpoint;
handle.socket()->GetPeerAddress(&endpoint);
@@ -1121,8 +1133,8 @@ TEST_F(TransportClientSocketPoolTest,
// Enable TCP FastOpen in TransportSocketParams.
scoped_refptr<TransportSocketParams> params = CreateParamsForTCPFastOpen();
handle.Init("a", params, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(OK, callback.WaitForResult());
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
IPEndPoint endpoint;
handle.socket()->GetPeerAddress(&endpoint);
// Verify that the socket used is connected to the IPv6 address.
diff --git a/chromium/net/socket/transport_client_socket_unittest.cc b/chromium/net/socket/transport_client_socket_unittest.cc
index eb45e6d89bf..7db6db47036 100644
--- a/chromium/net/socket/transport_client_socket_unittest.cc
+++ b/chromium/net/socket/transport_client_socket_unittest.cc
@@ -14,16 +14,23 @@
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/dns/mock_host_resolver.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.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/client_socket_factory.h"
#include "net/socket/tcp_client_socket.h"
#include "net/socket/tcp_server_socket.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -53,7 +60,7 @@ class TransportClientSocketTest
}
void AcceptCallback(int res) {
- ASSERT_EQ(OK, res);
+ ASSERT_THAT(res, IsOk());
connect_loop_.Quit();
}
@@ -97,11 +104,11 @@ void TransportClientSocketTest::SetUp() {
::testing::TestWithParam<ClientSocketTestTypes>::SetUp();
// Open a server socket on an ephemeral port.
- listen_sock_.reset(new TCPServerSocket(NULL, NetLog::Source()));
+ listen_sock_.reset(new TCPServerSocket(NULL, NetLogSource()));
IPEndPoint local_address(IPAddress::IPv4Localhost(), 0);
- ASSERT_EQ(OK, listen_sock_->Listen(local_address, 1));
+ ASSERT_THAT(listen_sock_->Listen(local_address, 1), IsOk());
// Get the server's address (including the actual port number).
- ASSERT_EQ(OK, listen_sock_->GetLocalAddress(&local_address));
+ ASSERT_THAT(listen_sock_->GetLocalAddress(&local_address), IsOk());
listen_port_ = local_address.port();
listen_sock_->Accept(&connected_sock_,
base::Bind(&TransportClientSocketTest::AcceptCallback,
@@ -112,13 +119,14 @@ void TransportClientSocketTest::SetUp() {
std::unique_ptr<HostResolver> resolver(new MockHostResolver());
HostResolver::RequestInfo info(HostPortPair("localhost", listen_port_));
TestCompletionCallback callback;
+ std::unique_ptr<HostResolver::Request> request;
int rv = resolver->Resolve(info, DEFAULT_PRIORITY, &addr, callback.callback(),
- NULL, BoundNetLog());
+ &request, NetLogWithSource());
CHECK_EQ(ERR_IO_PENDING, rv);
rv = callback.WaitForResult();
CHECK_EQ(rv, OK);
sock_ = socket_factory_->CreateTransportClientSocket(addr, NULL, &net_log_,
- NetLog::Source());
+ NetLogSource());
}
int TransportClientSocketTest::DrainClientSocket(
@@ -146,7 +154,7 @@ void TransportClientSocketTest::EstablishConnection(
// Wait for |listen_sock_| to accept a connection.
connect_loop_.Run();
// Now wait for the client socket to accept the connection.
- EXPECT_EQ(OK, callback->GetResult(rv));
+ EXPECT_THAT(callback->GetResult(rv), IsOk());
}
void TransportClientSocketTest::SendRequestAndResponse() {
@@ -236,9 +244,9 @@ TEST_P(TransportClientSocketTest, Connect) {
TestNetLogEntry::List net_log_entries;
net_log_.GetEntries(&net_log_entries);
EXPECT_TRUE(
- LogContainsBeginEvent(net_log_entries, 0, NetLog::TYPE_SOCKET_ALIVE));
+ LogContainsBeginEvent(net_log_entries, 0, NetLogEventType::SOCKET_ALIVE));
EXPECT_TRUE(
- LogContainsBeginEvent(net_log_entries, 1, NetLog::TYPE_TCP_CONNECT));
+ LogContainsBeginEvent(net_log_entries, 1, NetLogEventType::TCP_CONNECT));
// Now wait for the client socket to accept the connection.
if (rv != OK) {
ASSERT_EQ(rv, ERR_IO_PENDING);
@@ -249,7 +257,7 @@ TEST_P(TransportClientSocketTest, Connect) {
EXPECT_TRUE(sock_->IsConnected());
net_log_.GetEntries(&net_log_entries);
EXPECT_TRUE(
- LogContainsEndEvent(net_log_entries, -1, NetLog::TYPE_TCP_CONNECT));
+ LogContainsEndEvent(net_log_entries, -1, NetLogEventType::TCP_CONNECT));
sock_->Disconnect();
EXPECT_FALSE(sock_->IsConnected());
@@ -332,7 +340,7 @@ TEST_P(TransportClientSocketTest, Read) {
// then close the server socket, and note the close.
int rv = sock_->Read(buf.get(), 4096, callback.callback());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
CloseServerSocket();
EXPECT_EQ(0, callback.WaitForResult());
}
@@ -359,7 +367,7 @@ TEST_P(TransportClientSocketTest, Read_SmallChunks) {
// then close the server socket, and note the close.
int rv = sock_->Read(buf.get(), 1, callback.callback());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
CloseServerSocket();
EXPECT_EQ(0, callback.WaitForResult());
}
@@ -388,7 +396,7 @@ TEST_P(TransportClientSocketTest, FullDuplex_ReadFirst) {
const int kBufLen = 4096;
scoped_refptr<IOBuffer> buf(new IOBuffer(kBufLen));
int rv = sock_->Read(buf.get(), kBufLen, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
const int kWriteBufLen = 64 * 1024;
scoped_refptr<IOBuffer> request_buffer(new IOBuffer(kWriteBufLen));
diff --git a/chromium/net/socket/unix_domain_client_socket_posix.cc b/chromium/net/socket/unix_domain_client_socket_posix.cc
index bf86475768c..3615f2cbf69 100644
--- a/chromium/net/socket/unix_domain_client_socket_posix.cc
+++ b/chromium/net/socket/unix_domain_client_socket_posix.cc
@@ -118,7 +118,7 @@ int UnixDomainClientSocket::GetLocalAddress(IPEndPoint* address) const {
return ERR_ADDRESS_INVALID;
}
-const BoundNetLog& UnixDomainClientSocket::NetLog() const {
+const NetLogWithSource& UnixDomainClientSocket::NetLog() const {
return net_log_;
}
diff --git a/chromium/net/socket/unix_domain_client_socket_posix.h b/chromium/net/socket/unix_domain_client_socket_posix.h
index e7b033a71c3..b5af84546f3 100644
--- a/chromium/net/socket/unix_domain_client_socket_posix.h
+++ b/chromium/net/socket/unix_domain_client_socket_posix.h
@@ -13,7 +13,7 @@
#include "base/macros.h"
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/socket_descriptor.h"
#include "net/socket/stream_socket.h"
@@ -48,7 +48,7 @@ class NET_EXPORT UnixDomainClientSocket : public StreamSocket {
bool IsConnectedAndIdle() const override;
int GetPeerAddress(IPEndPoint* address) const override;
int GetLocalAddress(IPEndPoint* address) const override;
- const BoundNetLog& NetLog() const override;
+ const NetLogWithSource& NetLog() const override;
void SetSubresourceSpeculation() override;
void SetOmniboxSpeculation() override;
bool WasEverUsed() const override;
@@ -81,7 +81,7 @@ class NET_EXPORT UnixDomainClientSocket : public StreamSocket {
std::unique_ptr<SocketPosix> socket_;
// This net log is just to comply StreamSocket::NetLog(). It throws away
// everything.
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
DISALLOW_COPY_AND_ASSIGN(UnixDomainClientSocket);
};
diff --git a/chromium/net/socket/unix_domain_client_socket_posix_unittest.cc b/chromium/net/socket/unix_domain_client_socket_posix_unittest.cc
index 4cccfc283bb..0e80a61281d 100644
--- a/chromium/net/socket/unix_domain_client_socket_posix_unittest.cc
+++ b/chromium/net/socket/unix_domain_client_socket_posix_unittest.cc
@@ -19,8 +19,13 @@
#include "net/base/test_completion_callback.h"
#include "net/socket/socket_posix.h"
#include "net/socket/unix_domain_server_socket_posix.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -120,7 +125,7 @@ class UnixDomainClientSocketTest : public testing::Test {
protected:
UnixDomainClientSocketTest() {
EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
- socket_path_ = temp_dir_.path().Append(kSocketFilename).value();
+ socket_path_ = temp_dir_.GetPath().Append(kSocketFilename).value();
}
base::ScopedTempDir temp_dir_;
@@ -132,7 +137,7 @@ TEST_F(UnixDomainClientSocketTest, Connect) {
UnixDomainServerSocket server_socket(CreateAuthCallback(true),
kUseAbstractNamespace);
- EXPECT_EQ(OK, server_socket.BindAndListen(socket_path_, /*backlog=*/1));
+ EXPECT_THAT(server_socket.BindAndListen(socket_path_, /*backlog=*/1), IsOk());
std::unique_ptr<StreamSocket> accepted_socket;
TestCompletionCallback accept_callback;
@@ -143,12 +148,12 @@ TEST_F(UnixDomainClientSocketTest, Connect) {
UnixDomainClientSocket client_socket(socket_path_, kUseAbstractNamespace);
EXPECT_FALSE(client_socket.IsConnected());
- EXPECT_EQ(OK, ConnectSynchronously(&client_socket));
+ EXPECT_THAT(ConnectSynchronously(&client_socket), IsOk());
EXPECT_TRUE(client_socket.IsConnected());
// Server has not yet been notified of the connection.
EXPECT_FALSE(accepted_socket);
- EXPECT_EQ(OK, accept_callback.WaitForResult());
+ EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
EXPECT_TRUE(accepted_socket);
EXPECT_TRUE(accepted_socket->IsConnected());
}
@@ -158,7 +163,7 @@ TEST_F(UnixDomainClientSocketTest, ConnectWithSocketDescriptor) {
UnixDomainServerSocket server_socket(CreateAuthCallback(true),
kUseAbstractNamespace);
- EXPECT_EQ(OK, server_socket.BindAndListen(socket_path_, /*backlog=*/1));
+ EXPECT_THAT(server_socket.BindAndListen(socket_path_, /*backlog=*/1), IsOk());
SocketDescriptor accepted_socket_fd = kInvalidSocket;
TestCompletionCallback accept_callback;
@@ -170,12 +175,12 @@ TEST_F(UnixDomainClientSocketTest, ConnectWithSocketDescriptor) {
UnixDomainClientSocket client_socket(socket_path_, kUseAbstractNamespace);
EXPECT_FALSE(client_socket.IsConnected());
- EXPECT_EQ(OK, ConnectSynchronously(&client_socket));
+ EXPECT_THAT(ConnectSynchronously(&client_socket), IsOk());
EXPECT_TRUE(client_socket.IsConnected());
// Server has not yet been notified of the connection.
EXPECT_EQ(kInvalidSocket, accepted_socket_fd);
- EXPECT_EQ(OK, accept_callback.WaitForResult());
+ EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
EXPECT_NE(kInvalidSocket, accepted_socket_fd);
SocketDescriptor client_socket_fd = client_socket.ReleaseConnectedSocket();
@@ -210,7 +215,7 @@ TEST_F(UnixDomainClientSocketTest, ConnectWithAbstractNamespace) {
#if defined(OS_ANDROID) || defined(OS_LINUX)
UnixDomainServerSocket server_socket(CreateAuthCallback(true),
kUseAbstractNamespace);
- EXPECT_EQ(OK, server_socket.BindAndListen(socket_path_, /*backlog=*/1));
+ EXPECT_THAT(server_socket.BindAndListen(socket_path_, /*backlog=*/1), IsOk());
std::unique_ptr<StreamSocket> accepted_socket;
TestCompletionCallback accept_callback;
@@ -218,16 +223,17 @@ TEST_F(UnixDomainClientSocketTest, ConnectWithAbstractNamespace) {
server_socket.Accept(&accepted_socket, accept_callback.callback()));
EXPECT_FALSE(accepted_socket);
- EXPECT_EQ(OK, ConnectSynchronously(&client_socket));
+ EXPECT_THAT(ConnectSynchronously(&client_socket), IsOk());
EXPECT_TRUE(client_socket.IsConnected());
// Server has not yet beend notified of the connection.
EXPECT_FALSE(accepted_socket);
- EXPECT_EQ(OK, accept_callback.WaitForResult());
+ EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
EXPECT_TRUE(accepted_socket);
EXPECT_TRUE(accepted_socket->IsConnected());
#else
- EXPECT_EQ(ERR_ADDRESS_INVALID, ConnectSynchronously(&client_socket));
+ EXPECT_THAT(ConnectSynchronously(&client_socket),
+ IsError(ERR_ADDRESS_INVALID));
#endif
}
@@ -236,7 +242,8 @@ TEST_F(UnixDomainClientSocketTest, ConnectToNonExistentSocket) {
UnixDomainClientSocket client_socket(socket_path_, kUseAbstractNamespace);
EXPECT_FALSE(client_socket.IsConnected());
- EXPECT_EQ(ERR_FILE_NOT_FOUND, ConnectSynchronously(&client_socket));
+ EXPECT_THAT(ConnectSynchronously(&client_socket),
+ IsError(ERR_FILE_NOT_FOUND));
}
TEST_F(UnixDomainClientSocketTest,
@@ -248,23 +255,25 @@ TEST_F(UnixDomainClientSocketTest,
TestCompletionCallback connect_callback;
#if defined(OS_ANDROID) || defined(OS_LINUX)
- EXPECT_EQ(ERR_CONNECTION_REFUSED, ConnectSynchronously(&client_socket));
+ EXPECT_THAT(ConnectSynchronously(&client_socket),
+ IsError(ERR_CONNECTION_REFUSED));
#else
- EXPECT_EQ(ERR_ADDRESS_INVALID, ConnectSynchronously(&client_socket));
+ EXPECT_THAT(ConnectSynchronously(&client_socket),
+ IsError(ERR_ADDRESS_INVALID));
#endif
}
TEST_F(UnixDomainClientSocketTest, DisconnectFromClient) {
UnixDomainServerSocket server_socket(CreateAuthCallback(true), false);
- EXPECT_EQ(OK, server_socket.BindAndListen(socket_path_, /*backlog=*/1));
+ EXPECT_THAT(server_socket.BindAndListen(socket_path_, /*backlog=*/1), IsOk());
std::unique_ptr<StreamSocket> accepted_socket;
TestCompletionCallback accept_callback;
EXPECT_EQ(ERR_IO_PENDING,
server_socket.Accept(&accepted_socket, accept_callback.callback()));
UnixDomainClientSocket client_socket(socket_path_, false);
- EXPECT_EQ(OK, ConnectSynchronously(&client_socket));
+ EXPECT_THAT(ConnectSynchronously(&client_socket), IsOk());
- EXPECT_EQ(OK, accept_callback.WaitForResult());
+ EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
EXPECT_TRUE(accepted_socket->IsConnected());
EXPECT_TRUE(client_socket.IsConnected());
@@ -289,15 +298,15 @@ TEST_F(UnixDomainClientSocketTest, DisconnectFromClient) {
TEST_F(UnixDomainClientSocketTest, DisconnectFromServer) {
UnixDomainServerSocket server_socket(CreateAuthCallback(true), false);
- EXPECT_EQ(OK, server_socket.BindAndListen(socket_path_, /*backlog=*/1));
+ EXPECT_THAT(server_socket.BindAndListen(socket_path_, /*backlog=*/1), IsOk());
std::unique_ptr<StreamSocket> accepted_socket;
TestCompletionCallback accept_callback;
EXPECT_EQ(ERR_IO_PENDING,
server_socket.Accept(&accepted_socket, accept_callback.callback()));
UnixDomainClientSocket client_socket(socket_path_, false);
- EXPECT_EQ(OK, ConnectSynchronously(&client_socket));
+ EXPECT_THAT(ConnectSynchronously(&client_socket), IsOk());
- EXPECT_EQ(OK, accept_callback.WaitForResult());
+ EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
EXPECT_TRUE(accepted_socket->IsConnected());
EXPECT_TRUE(client_socket.IsConnected());
@@ -322,15 +331,15 @@ TEST_F(UnixDomainClientSocketTest, DisconnectFromServer) {
TEST_F(UnixDomainClientSocketTest, ReadAfterWrite) {
UnixDomainServerSocket server_socket(CreateAuthCallback(true), false);
- EXPECT_EQ(OK, server_socket.BindAndListen(socket_path_, /*backlog=*/1));
+ EXPECT_THAT(server_socket.BindAndListen(socket_path_, /*backlog=*/1), IsOk());
std::unique_ptr<StreamSocket> accepted_socket;
TestCompletionCallback accept_callback;
EXPECT_EQ(ERR_IO_PENDING,
server_socket.Accept(&accepted_socket, accept_callback.callback()));
UnixDomainClientSocket client_socket(socket_path_, false);
- EXPECT_EQ(OK, ConnectSynchronously(&client_socket));
+ EXPECT_THAT(ConnectSynchronously(&client_socket), IsOk());
- EXPECT_EQ(OK, accept_callback.WaitForResult());
+ EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
EXPECT_TRUE(accepted_socket->IsConnected());
EXPECT_TRUE(client_socket.IsConnected());
@@ -391,15 +400,15 @@ TEST_F(UnixDomainClientSocketTest, ReadAfterWrite) {
TEST_F(UnixDomainClientSocketTest, ReadBeforeWrite) {
UnixDomainServerSocket server_socket(CreateAuthCallback(true), false);
- EXPECT_EQ(OK, server_socket.BindAndListen(socket_path_, /*backlog=*/1));
+ EXPECT_THAT(server_socket.BindAndListen(socket_path_, /*backlog=*/1), IsOk());
std::unique_ptr<StreamSocket> accepted_socket;
TestCompletionCallback accept_callback;
EXPECT_EQ(ERR_IO_PENDING,
server_socket.Accept(&accepted_socket, accept_callback.callback()));
UnixDomainClientSocket client_socket(socket_path_, false);
- EXPECT_EQ(OK, ConnectSynchronously(&client_socket));
+ EXPECT_THAT(ConnectSynchronously(&client_socket), IsOk());
- EXPECT_EQ(OK, accept_callback.WaitForResult());
+ EXPECT_THAT(accept_callback.WaitForResult(), IsOk());
EXPECT_TRUE(accepted_socket->IsConnected());
EXPECT_TRUE(client_socket.IsConnected());
diff --git a/chromium/net/socket/unix_domain_server_socket_posix_unittest.cc b/chromium/net/socket/unix_domain_server_socket_posix_unittest.cc
index f44e544e761..870a2613167 100644
--- a/chromium/net/socket/unix_domain_server_socket_posix_unittest.cc
+++ b/chromium/net/socket/unix_domain_server_socket_posix_unittest.cc
@@ -16,8 +16,13 @@
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/socket/unix_domain_client_socket_posix.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -43,7 +48,7 @@ class UnixDomainServerSocketTest : public testing::Test {
protected:
UnixDomainServerSocketTest() {
EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
- socket_path_ = temp_dir_.path().Append(kSocketFilename).value();
+ socket_path_ = temp_dir_.GetPath().Append(kSocketFilename).value();
}
base::ScopedTempDir temp_dir_;
@@ -63,7 +68,8 @@ TEST_F(UnixDomainServerSocketTest, ListenWithInvalidPathWithAbstractNamespace) {
UnixDomainServerSocket server_socket(CreateAuthCallback(true),
kUseAbstractNamespace);
#if defined(OS_ANDROID) || defined(OS_LINUX)
- EXPECT_EQ(OK, server_socket.BindAndListen(kInvalidSocketPath, /*backlog=*/1));
+ EXPECT_THAT(server_socket.BindAndListen(kInvalidSocketPath, /*backlog=*/1),
+ IsOk());
#else
EXPECT_EQ(ERR_ADDRESS_INVALID,
server_socket.BindAndListen(kInvalidSocketPath, /*backlog=*/1));
@@ -76,7 +82,7 @@ TEST_F(UnixDomainServerSocketTest, ListenAgainAfterFailureWithInvalidPath) {
kUseAbstractNamespace);
EXPECT_EQ(ERR_FILE_NOT_FOUND,
server_socket.BindAndListen(kInvalidSocketPath, /*backlog=*/1));
- EXPECT_EQ(OK, server_socket.BindAndListen(socket_path_, /*backlog=*/1));
+ EXPECT_THAT(server_socket.BindAndListen(socket_path_, /*backlog=*/1), IsOk());
}
TEST_F(UnixDomainServerSocketTest, AcceptWithForbiddenUser) {
@@ -84,7 +90,7 @@ TEST_F(UnixDomainServerSocketTest, AcceptWithForbiddenUser) {
UnixDomainServerSocket server_socket(CreateAuthCallback(false),
kUseAbstractNamespace);
- EXPECT_EQ(OK, server_socket.BindAndListen(socket_path_, /*backlog=*/1));
+ EXPECT_THAT(server_socket.BindAndListen(socket_path_, /*backlog=*/1), IsOk());
std::unique_ptr<StreamSocket> accepted_socket;
TestCompletionCallback accept_callback;
@@ -99,7 +105,7 @@ TEST_F(UnixDomainServerSocketTest, AcceptWithForbiddenUser) {
TestCompletionCallback connect_callback;
int rv = connect_callback.GetResult(
client_socket.Connect(connect_callback.callback()));
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
// Try to read from the socket.
const int read_buffer_size = 10;
@@ -124,13 +130,13 @@ TEST_F(UnixDomainServerSocketTest, UnimplementedMethodsFail) {
kUseAbstractNamespace);
IPEndPoint ep;
- EXPECT_EQ(ERR_NOT_IMPLEMENTED, server_socket.Listen(ep, 0));
+ EXPECT_THAT(server_socket.Listen(ep, 0), IsError(ERR_NOT_IMPLEMENTED));
EXPECT_EQ(ERR_NOT_IMPLEMENTED,
server_socket.ListenWithAddressAndPort(kInvalidSocketPath,
0,
/*backlog=*/1));
- EXPECT_EQ(ERR_ADDRESS_INVALID, server_socket.GetLocalAddress(&ep));
+ EXPECT_THAT(server_socket.GetLocalAddress(&ep), IsError(ERR_ADDRESS_INVALID));
}
// Normal cases including read/write are tested by UnixDomainClientSocketTest.
diff --git a/chromium/net/socket/websocket_endpoint_lock_manager.cc b/chromium/net/socket/websocket_endpoint_lock_manager.cc
index 52cf5342a24..bd6a2210c26 100644
--- a/chromium/net/socket/websocket_endpoint_lock_manager.cc
+++ b/chromium/net/socket/websocket_endpoint_lock_manager.cc
@@ -12,7 +12,6 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/net_errors.h"
-#include "net/log/net_log.h"
namespace net {
@@ -79,7 +78,7 @@ void WebSocketEndpointLockManager::UnlockSocket(StreamSocket* socket) {
<< socket_lock_info_map_.size() << " socket(s) left)";
socket_lock_info_map_.erase(socket_it);
DCHECK_EQ(socket, lock_info_it->second.socket);
- lock_info_it->second.socket = NULL;
+ lock_info_it->second.socket = nullptr;
UnlockEndpointAfterDelay(lock_info_it->first);
}
@@ -103,7 +102,7 @@ base::TimeDelta WebSocketEndpointLockManager::SetUnlockDelayForTesting(
return old_delay;
}
-WebSocketEndpointLockManager::LockInfo::LockInfo() : socket(NULL) {}
+WebSocketEndpointLockManager::LockInfo::LockInfo() : socket(nullptr) {}
WebSocketEndpointLockManager::LockInfo::~LockInfo() {
DCHECK(!socket);
}
@@ -166,7 +165,7 @@ void WebSocketEndpointLockManager::EraseSocket(
<< socket_lock_info_map_.size() << " socket(s) left)";
size_t erased = socket_lock_info_map_.erase(lock_info_it->second.socket);
DCHECK_EQ(1U, erased);
- lock_info_it->second.socket = NULL;
+ lock_info_it->second.socket = nullptr;
}
} // namespace net
diff --git a/chromium/net/socket/websocket_endpoint_lock_manager_unittest.cc b/chromium/net/socket/websocket_endpoint_lock_manager_unittest.cc
index 640d8b3bd5d..7a79247d726 100644
--- a/chromium/net/socket/websocket_endpoint_lock_manager_unittest.cc
+++ b/chromium/net/socket/websocket_endpoint_lock_manager_unittest.cc
@@ -11,11 +11,16 @@
#include "base/time/time.h"
#include "net/base/ip_address.h"
#include "net/base/net_errors.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/next_proto.h"
#include "net/socket/socket_test_util.h"
#include "net/socket/stream_socket.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -42,7 +47,7 @@ class FakeStreamSocket : public StreamSocket {
int GetLocalAddress(IPEndPoint* address) const override { return ERR_FAILED; }
- const BoundNetLog& NetLog() const override { return bound_net_log_; }
+ const NetLogWithSource& NetLog() const override { return net_log_; }
void SetSubresourceSpeculation() override { return; }
void SetOmniboxSpeculation() override { return; }
@@ -86,7 +91,7 @@ class FakeStreamSocket : public StreamSocket {
int SetSendBufferSize(int32_t size) override { return ERR_FAILED; }
private:
- BoundNetLog bound_net_log_;
+ NetLogWithSource net_log_;
DISALLOW_COPY_AND_ASSIGN(FakeStreamSocket);
};
@@ -159,7 +164,7 @@ TEST_F(WebSocketEndpointLockManagerTest, GetInstanceWorks) {
TEST_F(WebSocketEndpointLockManagerTest, LockEndpointReturnsOkOnce) {
FakeWaiter waiters[2];
- EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiters[0]));
+ EXPECT_THAT(instance()->LockEndpoint(DummyEndpoint(), &waiters[0]), IsOk());
EXPECT_EQ(ERR_IO_PENDING,
instance()->LockEndpoint(DummyEndpoint(), &waiters[1]));
@@ -168,7 +173,7 @@ TEST_F(WebSocketEndpointLockManagerTest, LockEndpointReturnsOkOnce) {
TEST_F(WebSocketEndpointLockManagerTest, GotEndpointLockNotCalledOnOk) {
FakeWaiter waiter;
- EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiter));
+ EXPECT_THAT(instance()->LockEndpoint(DummyEndpoint(), &waiter), IsOk());
RunUntilIdle();
EXPECT_FALSE(waiter.called());
@@ -177,7 +182,7 @@ TEST_F(WebSocketEndpointLockManagerTest, GotEndpointLockNotCalledOnOk) {
TEST_F(WebSocketEndpointLockManagerTest, GotEndpointLockNotCalledImmediately) {
FakeWaiter waiters[2];
- EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiters[0]));
+ EXPECT_THAT(instance()->LockEndpoint(DummyEndpoint(), &waiters[0]), IsOk());
EXPECT_EQ(ERR_IO_PENDING,
instance()->LockEndpoint(DummyEndpoint(), &waiters[1]));
RunUntilIdle();
@@ -188,7 +193,7 @@ TEST_F(WebSocketEndpointLockManagerTest, GotEndpointLockNotCalledImmediately) {
TEST_F(WebSocketEndpointLockManagerTest, GotEndpointLockCalledWhenUnlocked) {
FakeWaiter waiters[2];
- EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiters[0]));
+ EXPECT_THAT(instance()->LockEndpoint(DummyEndpoint(), &waiters[0]), IsOk());
EXPECT_EQ(ERR_IO_PENDING,
instance()->LockEndpoint(DummyEndpoint(), &waiters[1]));
instance()->UnlockEndpoint(DummyEndpoint());
@@ -201,7 +206,8 @@ TEST_F(WebSocketEndpointLockManagerTest, GotEndpointLockCalledWhenUnlocked) {
TEST_F(WebSocketEndpointLockManagerTest,
EndpointUnlockedIfWaiterAlreadyDeleted) {
FakeWaiter first_lock_holder;
- EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &first_lock_holder));
+ EXPECT_THAT(instance()->LockEndpoint(DummyEndpoint(), &first_lock_holder),
+ IsOk());
{
FakeWaiter short_lived_waiter;
@@ -213,7 +219,8 @@ TEST_F(WebSocketEndpointLockManagerTest,
RunUntilIdle();
FakeWaiter second_lock_holder;
- EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &second_lock_holder));
+ EXPECT_THAT(instance()->LockEndpoint(DummyEndpoint(), &second_lock_holder),
+ IsOk());
UnlockDummyEndpoint(1);
}
@@ -221,7 +228,7 @@ TEST_F(WebSocketEndpointLockManagerTest,
TEST_F(WebSocketEndpointLockManagerTest, RememberSocketWorks) {
FakeWaiter waiters[2];
FakeStreamSocket dummy_socket;
- EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiters[0]));
+ EXPECT_THAT(instance()->LockEndpoint(DummyEndpoint(), &waiters[0]), IsOk());
EXPECT_EQ(ERR_IO_PENDING,
instance()->LockEndpoint(DummyEndpoint(), &waiters[1]));
@@ -239,7 +246,7 @@ TEST_F(WebSocketEndpointLockManagerTest, SocketAssociationForgottenOnUnlock) {
FakeWaiter waiter;
FakeStreamSocket dummy_socket;
- EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiter));
+ EXPECT_THAT(instance()->LockEndpoint(DummyEndpoint(), &waiter), IsOk());
instance()->RememberSocket(&dummy_socket, DummyEndpoint());
instance()->UnlockEndpoint(DummyEndpoint());
RunUntilIdle();
@@ -251,7 +258,7 @@ TEST_F(WebSocketEndpointLockManagerTest, SocketAssociationForgottenOnUnlock) {
TEST_F(WebSocketEndpointLockManagerTest, NextWaiterCanCallRememberSocketAgain) {
FakeWaiter waiters[2];
FakeStreamSocket dummy_sockets[2];
- EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiters[0]));
+ EXPECT_THAT(instance()->LockEndpoint(DummyEndpoint(), &waiters[0]), IsOk());
EXPECT_EQ(ERR_IO_PENDING,
instance()->LockEndpoint(DummyEndpoint(), &waiters[1]));
@@ -270,7 +277,7 @@ TEST_F(WebSocketEndpointLockManagerTest,
FakeWaiter waiters[3];
FakeStreamSocket dummy_socket;
- EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiters[0]));
+ EXPECT_THAT(instance()->LockEndpoint(DummyEndpoint(), &waiters[0]), IsOk());
EXPECT_EQ(ERR_IO_PENDING,
instance()->LockEndpoint(DummyEndpoint(), &waiters[1]));
EXPECT_EQ(ERR_IO_PENDING,
@@ -288,7 +295,7 @@ TEST_F(WebSocketEndpointLockManagerTest,
// UnlockEndpoint() should always be asynchronous.
TEST_F(WebSocketEndpointLockManagerTest, UnlockEndpointIsAsynchronous) {
FakeWaiter waiters[2];
- EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &waiters[0]));
+ EXPECT_THAT(instance()->LockEndpoint(DummyEndpoint(), &waiters[0]), IsOk());
EXPECT_EQ(ERR_IO_PENDING,
instance()->LockEndpoint(DummyEndpoint(), &waiters[1]));
@@ -315,7 +322,7 @@ TEST_F(WebSocketEndpointLockManagerTest, UnlockEndpointIsDelayed) {
instance()->SetUnlockDelayForTesting(unlock_delay);
FakeWaiter fake_waiter;
BlockingWaiter blocking_waiter;
- EXPECT_EQ(OK, instance()->LockEndpoint(DummyEndpoint(), &fake_waiter));
+ EXPECT_THAT(instance()->LockEndpoint(DummyEndpoint(), &fake_waiter), IsOk());
EXPECT_EQ(ERR_IO_PENDING,
instance()->LockEndpoint(DummyEndpoint(), &blocking_waiter));
diff --git a/chromium/net/socket/websocket_transport_client_socket_pool.cc b/chromium/net/socket/websocket_transport_client_socket_pool.cc
index 6bc70c227c9..987723c2032 100644
--- a/chromium/net/socket/websocket_transport_client_socket_pool.cc
+++ b/chromium/net/socket/websocket_transport_client_socket_pool.cc
@@ -18,7 +18,9 @@
#include "base/trace_event/trace_event.h"
#include "base/values.h"
#include "net/base/net_errors.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool_base.h"
#include "net/socket/websocket_endpoint_lock_manager.h"
@@ -38,13 +40,14 @@ WebSocketTransportConnectJob::WebSocketTransportConnectJob(
ClientSocketHandle* handle,
Delegate* delegate,
NetLog* pool_net_log,
- const BoundNetLog& request_net_log)
- : ConnectJob(group_name,
- timeout_duration,
- priority,
- respect_limits,
- delegate,
- BoundNetLog::Make(pool_net_log, NetLog::SOURCE_CONNECT_JOB)),
+ const NetLogWithSource& request_net_log)
+ : ConnectJob(
+ group_name,
+ timeout_duration,
+ priority,
+ respect_limits,
+ delegate,
+ NetLogWithSource::Make(pool_net_log, NetLogSourceType::CONNECT_JOB)),
params_(params),
resolver_(host_resolver),
client_socket_factory_(client_socket_factory),
@@ -112,11 +115,11 @@ int WebSocketTransportConnectJob::DoResolveHost() {
next_state_ = STATE_RESOLVE_HOST_COMPLETE;
connect_timing_.dns_start = base::TimeTicks::Now();
- return resolver_.Resolve(
+ return resolver_->Resolve(
params_->destination(), priority(), &addresses_,
base::Bind(&WebSocketTransportConnectJob::OnIOComplete,
base::Unretained(this)),
- net_log());
+ &request_, net_log());
}
int WebSocketTransportConnectJob::DoResolveHostComplete(int result) {
@@ -284,7 +287,7 @@ WebSocketTransportClientSocketPool::WebSocketTransportClientSocketPool(
max_sockets_per_group,
host_resolver,
client_socket_factory,
- NULL,
+ nullptr,
net_log),
connect_job_delegate_(this),
pool_net_log_(net_log),
@@ -321,7 +324,7 @@ int WebSocketTransportClientSocketPool::RequestSocket(
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& request_net_log) {
+ const NetLogWithSource& request_net_log) {
DCHECK(params);
const scoped_refptr<TransportSocketParams>& casted_params =
*static_cast<const scoped_refptr<TransportSocketParams>*>(params);
@@ -331,11 +334,11 @@ int WebSocketTransportClientSocketPool::RequestSocket(
CHECK(!callback.is_null());
CHECK(handle);
- request_net_log.BeginEvent(NetLog::TYPE_SOCKET_POOL);
+ request_net_log.BeginEvent(NetLogEventType::SOCKET_POOL);
if (ReachedMaxSocketsLimit() &&
respect_limits == ClientSocketPool::RespectLimits::ENABLED) {
- request_net_log.AddEvent(NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS);
+ request_net_log.AddEvent(NetLogEventType::SOCKET_POOL_STALLED_MAX_SOCKETS);
// TODO(ricea): Use emplace_back when C++11 becomes allowed.
StalledRequest request(
casted_params, priority, handle, callback, request_net_log);
@@ -359,44 +362,30 @@ int WebSocketTransportClientSocketPool::RequestSocket(
ConnectionTimeout(), callback, client_socket_factory_, host_resolver_,
handle, &connect_job_delegate_, pool_net_log_, request_net_log));
- int rv = connect_job->Connect();
+ int result = connect_job->Connect();
+
// Regardless of the outcome of |connect_job|, it will always be bound to
// |handle|, since this pool uses early-binding. So the binding is logged
// here, without waiting for the result.
request_net_log.AddEvent(
- NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
+ NetLogEventType::SOCKET_POOL_BOUND_TO_CONNECT_JOB,
connect_job->net_log().source().ToEventParametersCallback());
- if (rv == OK) {
- HandOutSocket(connect_job->PassSocket(),
- connect_job->connect_timing(),
- handle,
- request_net_log);
- request_net_log.EndEvent(NetLog::TYPE_SOCKET_POOL);
- } else if (rv == ERR_IO_PENDING) {
+
+ if (result == ERR_IO_PENDING) {
// TODO(ricea): Implement backup job timer?
AddJob(handle, std::move(connect_job));
} else {
- std::unique_ptr<StreamSocket> error_socket;
- connect_job->GetAdditionalErrorState(handle);
- error_socket = connect_job->PassSocket();
- if (error_socket) {
- HandOutSocket(std::move(error_socket), connect_job->connect_timing(),
- handle, request_net_log);
- }
+ TryHandOutSocket(result, connect_job.get());
}
- if (rv != ERR_IO_PENDING) {
- request_net_log.EndEventWithNetErrorCode(NetLog::TYPE_SOCKET_POOL, rv);
- }
-
- return rv;
+ return result;
}
void WebSocketTransportClientSocketPool::RequestSockets(
const std::string& group_name,
const void* params,
int num_sockets,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
NOTIMPLEMENTED();
}
@@ -411,8 +400,8 @@ void WebSocketTransportClientSocketPool::CancelRequest(
ReleaseSocket(handle->group_name(), std::move(socket), handle->id());
if (!DeleteJob(handle))
pending_callbacks_.erase(handle);
- if (!ReachedMaxSocketsLimit() && !stalled_request_queue_.empty())
- ActivateStalledRequest();
+
+ ActivateStalledRequest();
}
void WebSocketTransportClientSocketPool::ReleaseSocket(
@@ -422,11 +411,13 @@ void WebSocketTransportClientSocketPool::ReleaseSocket(
WebSocketEndpointLockManager::GetInstance()->UnlockSocket(socket.get());
CHECK_GT(handed_out_socket_count_, 0);
--handed_out_socket_count_;
- if (!ReachedMaxSocketsLimit() && !stalled_request_queue_.empty())
- ActivateStalledRequest();
+
+ ActivateStalledRequest();
}
void WebSocketTransportClientSocketPool::FlushWithError(int error) {
+ DCHECK_NE(error, OK);
+
// Sockets which are in LOAD_STATE_CONNECTING are in danger of unlocking
// sockets waiting for the endpoint lock. If they connected synchronously,
// then OnConnectJobComplete(). The |flushing_| flag tells this object to
@@ -439,7 +430,7 @@ void WebSocketTransportClientSocketPool::FlushWithError(int error) {
++it) {
InvokeUserCallbackLater(
it->second->handle(), it->second->callback(), error);
- delete it->second, it->second = NULL;
+ delete it->second, it->second = nullptr;
}
pending_connects_.clear();
for (StalledRequestQueue::iterator it = stalled_request_queue_.begin();
@@ -503,46 +494,68 @@ bool WebSocketTransportClientSocketPool::IsStalled() const {
return !stalled_request_queue_.empty();
}
-void WebSocketTransportClientSocketPool::OnConnectJobComplete(
+bool WebSocketTransportClientSocketPool::TryHandOutSocket(
int result,
WebSocketTransportConnectJob* job) {
- DCHECK_NE(ERR_IO_PENDING, result);
+ DCHECK_NE(result, ERR_IO_PENDING);
std::unique_ptr<StreamSocket> socket = job->PassSocket();
+ ClientSocketHandle* const handle = job->handle();
+ NetLogWithSource request_net_log = job->request_net_log();
+ LoadTimingInfo::ConnectTiming connect_timing = job->connect_timing();
+
+ if (result == OK) {
+ DCHECK(socket);
+
+ HandOutSocket(std::move(socket), connect_timing, handle, request_net_log);
+
+ request_net_log.EndEvent(NetLogEventType::SOCKET_POOL);
+
+ return true;
+ }
+
+ bool handed_out_socket = false;
+
+ // If we got a socket, it must contain error information so pass that
+ // up so that the caller can retrieve it.
+ job->GetAdditionalErrorState(handle);
+ if (socket) {
+ HandOutSocket(std::move(socket), connect_timing, handle, request_net_log);
+ handed_out_socket = true;
+ }
+
+ request_net_log.EndEventWithNetErrorCode(NetLogEventType::SOCKET_POOL,
+ result);
+
+ return handed_out_socket;
+}
+
+void WebSocketTransportClientSocketPool::OnConnectJobComplete(
+ int result,
+ WebSocketTransportConnectJob* job) {
+ DCHECK_NE(ERR_IO_PENDING, result);
// See comment in FlushWithError.
if (flushing_) {
+ std::unique_ptr<StreamSocket> socket = job->PassSocket();
WebSocketEndpointLockManager::GetInstance()->UnlockSocket(socket.get());
return;
}
- BoundNetLog request_net_log = job->request_net_log();
+ bool handed_out_socket = TryHandOutSocket(result, job);
+
CompletionCallback callback = job->callback();
- LoadTimingInfo::ConnectTiming connect_timing = job->connect_timing();
ClientSocketHandle* const handle = job->handle();
- bool handed_out_socket = false;
- if (result == OK) {
- DCHECK(socket.get());
- handed_out_socket = true;
- HandOutSocket(std::move(socket), connect_timing, handle, request_net_log);
- request_net_log.EndEvent(NetLog::TYPE_SOCKET_POOL);
- } else {
- // If we got a socket, it must contain error information so pass that
- // up so that the caller can retrieve it.
- job->GetAdditionalErrorState(handle);
- if (socket.get()) {
- handed_out_socket = true;
- HandOutSocket(std::move(socket), connect_timing, handle, request_net_log);
- }
- request_net_log.EndEventWithNetErrorCode(NetLog::TYPE_SOCKET_POOL, result);
- }
bool delete_succeeded = DeleteJob(handle);
DCHECK(delete_succeeded);
- if (!handed_out_socket && !stalled_request_queue_.empty() &&
- !ReachedMaxSocketsLimit())
+
+ job = nullptr;
+
+ if (!handed_out_socket)
ActivateStalledRequest();
+
InvokeUserCallbackLater(handle, callback, result);
}
@@ -576,16 +589,17 @@ void WebSocketTransportClientSocketPool::HandOutSocket(
std::unique_ptr<StreamSocket> socket,
const LoadTimingInfo::ConnectTiming& connect_timing,
ClientSocketHandle* handle,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
DCHECK(socket);
- handle->SetSocket(std::move(socket));
DCHECK_EQ(ClientSocketHandle::UNUSED, handle->reuse_type());
DCHECK_EQ(0, handle->idle_time().InMicroseconds());
+
+ handle->SetSocket(std::move(socket));
handle->set_pool_id(0);
handle->set_connect_timing(connect_timing);
net_log.AddEvent(
- NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
+ NetLogEventType::SOCKET_POOL_BOUND_TO_SOCKET,
handle->socket()->NetLog().source().ToEventParametersCallback());
++handed_out_socket_count_;
@@ -609,7 +623,7 @@ bool WebSocketTransportClientSocketPool::DeleteJob(ClientSocketHandle* handle) {
// (usually because of a failure) then it can trigger that job to be
// deleted. |it| remains valid because std::map guarantees that erase() does
// not invalid iterators to other entries.
- delete it->second, it->second = NULL;
+ delete it->second, it->second = nullptr;
DCHECK(pending_connects_.find(handle) == it);
pending_connects_.erase(it);
return true;
@@ -624,8 +638,6 @@ WebSocketTransportClientSocketPool::LookupConnectJob(
}
void WebSocketTransportClientSocketPool::ActivateStalledRequest() {
- DCHECK(!stalled_request_queue_.empty());
- DCHECK(!ReachedMaxSocketsLimit());
// Usually we will only be able to activate one stalled request at a time,
// however if all the connects fail synchronously for some reason, we may be
// able to clear the whole queue at once.
@@ -633,11 +645,13 @@ void WebSocketTransportClientSocketPool::ActivateStalledRequest() {
StalledRequest request(stalled_request_queue_.front());
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);
+
// ActivateStalledRequest() never returns synchronously, so it is never
// called re-entrantly.
if (rv != ERR_IO_PENDING)
@@ -674,7 +688,7 @@ WebSocketTransportClientSocketPool::StalledRequest::StalledRequest(
RequestPriority priority,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log)
+ const NetLogWithSource& net_log)
: params(params),
priority(priority),
handle(handle),
diff --git a/chromium/net/socket/websocket_transport_client_socket_pool.h b/chromium/net/socket/websocket_transport_client_socket_pool.h
index 20cd8ac72b6..1301945a844 100644
--- a/chromium/net/socket/websocket_transport_client_socket_pool.h
+++ b/chromium/net/socket/websocket_transport_client_socket_pool.h
@@ -17,11 +17,15 @@
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "net/base/net_export.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/client_socket_pool.h"
#include "net/socket/client_socket_pool_base.h"
#include "net/socket/transport_client_socket_pool.h"
+namespace base {
+class DictionaryValue;
+}
+
namespace net {
class ClientSocketFactory;
@@ -52,7 +56,7 @@ class NET_EXPORT_PRIVATE WebSocketTransportConnectJob : public ConnectJob {
ClientSocketHandle* handle,
Delegate* delegate,
NetLog* pool_net_log,
- const BoundNetLog& request_net_log);
+ const NetLogWithSource& request_net_log);
~WebSocketTransportConnectJob() override;
// Unlike normal socket pools, the WebSocketTransportClientPool uses
@@ -62,7 +66,7 @@ class NET_EXPORT_PRIVATE WebSocketTransportConnectJob : public ConnectJob {
// Stash the callback from RequestSocket() here for convenience.
const CompletionCallback& callback() const { return callback_; }
- const BoundNetLog& request_net_log() const { return request_net_log_; }
+ const NetLogWithSource& request_net_log() const { return request_net_log_; }
// ConnectJob methods.
LoadState GetLoadState() const override;
@@ -103,7 +107,8 @@ class NET_EXPORT_PRIVATE WebSocketTransportConnectJob : public ConnectJob {
int ConnectInternal() override;
scoped_refptr<TransportSocketParams> params_;
- SingleRequestHostResolver resolver_;
+ HostResolver* resolver_;
+ std::unique_ptr<HostResolver::Request> request_;
ClientSocketFactory* const client_socket_factory_;
State next_state_;
@@ -120,7 +125,7 @@ class NET_EXPORT_PRIVATE WebSocketTransportConnectJob : public ConnectJob {
TransportConnectJob::RaceResult race_result_;
ClientSocketHandle* const handle_;
CompletionCallback callback_;
- BoundNetLog request_net_log_;
+ NetLogWithSource request_net_log_;
bool had_ipv4_;
bool had_ipv6_;
@@ -153,11 +158,11 @@ class NET_EXPORT_PRIVATE WebSocketTransportClientSocketPool
RespectLimits respect_limits,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void RequestSockets(const std::string& group_name,
const void* params,
int num_sockets,
- const BoundNetLog& net_log) override;
+ const NetLogWithSource& net_log) override;
void CancelRequest(const std::string& group_name,
ClientSocketHandle* handle) override;
void ReleaseSocket(const std::string& group_name,
@@ -199,16 +204,18 @@ class NET_EXPORT_PRIVATE WebSocketTransportClientSocketPool
RequestPriority priority,
ClientSocketHandle* handle,
const CompletionCallback& callback,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
StalledRequest(const StalledRequest& other);
~StalledRequest();
const scoped_refptr<TransportSocketParams> params;
const RequestPriority priority;
ClientSocketHandle* const handle;
const CompletionCallback callback;
- const BoundNetLog net_log;
+ const NetLogWithSource net_log;
};
+
friend class ConnectJobDelegate;
+
typedef std::map<const ClientSocketHandle*, WebSocketTransportConnectJob*>
PendingConnectsMap;
// This is a list so that we can remove requests from the middle, and also
@@ -218,6 +225,10 @@ class NET_EXPORT_PRIVATE WebSocketTransportClientSocketPool
typedef std::map<const ClientSocketHandle*, StalledRequestQueue::iterator>
StalledRequestMap;
+ // Tries to hand out the socket connected by |job|. |result| must be (async)
+ // result of WebSocketTransportConnectJob::Connect(). Returns true iff it has
+ // handed out a socket.
+ bool TryHandOutSocket(int result, WebSocketTransportConnectJob* job);
void OnConnectJobComplete(int result, WebSocketTransportConnectJob* job);
void InvokeUserCallbackLater(ClientSocketHandle* handle,
const CompletionCallback& callback,
@@ -229,7 +240,7 @@ class NET_EXPORT_PRIVATE WebSocketTransportClientSocketPool
void HandOutSocket(std::unique_ptr<StreamSocket> socket,
const LoadTimingInfo::ConnectTiming& connect_timing,
ClientSocketHandle* handle,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
void AddJob(ClientSocketHandle* handle,
std::unique_ptr<WebSocketTransportConnectJob> connect_job);
bool DeleteJob(ClientSocketHandle* handle);
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 b11de000818..231a8b6f7f3 100644
--- a/chromium/net/socket/websocket_transport_client_socket_pool_unittest.cc
+++ b/chromium/net/socket/websocket_transport_client_socket_pool_unittest.cc
@@ -29,8 +29,13 @@
#include "net/socket/stream_socket.h"
#include "net/socket/transport_client_socket_pool_test_util.h"
#include "net/socket/websocket_endpoint_lock_manager.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -62,7 +67,7 @@ class WebSocketTransportClientSocketPoolTest : public ::testing::Test {
kMaxSocketsPerGroup,
host_resolver_.get(),
&client_socket_factory_,
- NULL) {}
+ nullptr) {}
~WebSocketTransportClientSocketPoolTest() override {
RunUntilIdle();
@@ -122,12 +127,12 @@ TEST_F(WebSocketTransportClientSocketPoolTest, Basic) {
ClientSocketHandle handle;
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfoConnectedNotReused(handle);
@@ -143,7 +148,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest, SetResolvePriorityOnInit) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, priority,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog()));
+ callback.callback(), &pool_, NetLogWithSource()));
EXPECT_EQ(priority, host_resolver_->last_request_priority());
}
}
@@ -159,8 +164,8 @@ TEST_F(WebSocketTransportClientSocketPoolTest, InitHostResolutionFailure) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", dest, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog()));
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback.WaitForResult());
+ callback.callback(), &pool_, NetLogWithSource()));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED));
}
TEST_F(WebSocketTransportClientSocketPoolTest, InitConnectionFailure) {
@@ -171,31 +176,31 @@ TEST_F(WebSocketTransportClientSocketPoolTest, InitConnectionFailure) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog()));
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
+ callback.callback(), &pool_, NetLogWithSource()));
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
// Make the host resolutions complete synchronously this time.
host_resolver_->set_synchronous_mode(true);
EXPECT_EQ(ERR_CONNECTION_FAILED,
handle.Init("a", params_, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog()));
+ callback.callback(), &pool_, NetLogWithSource()));
}
TEST_F(WebSocketTransportClientSocketPoolTest, PendingRequestsFinishFifo) {
// First request finishes asynchronously.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, request(0)->WaitForResult());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(request(0)->WaitForResult(), IsOk());
// Make all subsequent host resolutions complete synchronously.
host_resolver_->set_synchronous_mode(true);
// Rest of them wait for the first socket to be released.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE);
@@ -218,27 +223,27 @@ TEST_F(WebSocketTransportClientSocketPoolTest, PendingRequestsFinishFifo) {
TEST_F(WebSocketTransportClientSocketPoolTest, PendingRequests_NoKeepAlive) {
// First request finishes asynchronously.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, request(0)->WaitForResult());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(request(0)->WaitForResult(), IsOk());
// Make all subsequent host resolutions complete synchronously.
host_resolver_->set_synchronous_mode(true);
// Rest of them wait for the first socket to be released.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
// The pending requests should finish successfully.
- EXPECT_EQ(OK, request(1)->WaitForResult());
- EXPECT_EQ(OK, request(2)->WaitForResult());
- EXPECT_EQ(OK, request(3)->WaitForResult());
- EXPECT_EQ(OK, request(4)->WaitForResult());
- EXPECT_EQ(OK, request(5)->WaitForResult());
+ EXPECT_THAT(request(1)->WaitForResult(), IsOk());
+ EXPECT_THAT(request(2)->WaitForResult(), IsOk());
+ EXPECT_THAT(request(3)->WaitForResult(), IsOk());
+ EXPECT_THAT(request(4)->WaitForResult(), IsOk());
+ EXPECT_THAT(request(5)->WaitForResult(), IsOk());
EXPECT_EQ(static_cast<int>(requests()->size()),
client_socket_factory_.allocation_count());
@@ -256,7 +261,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest, CancelRequestClearGroup) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog()));
+ callback.callback(), &pool_, NetLogWithSource()));
handle.Reset();
}
@@ -269,15 +274,15 @@ TEST_F(WebSocketTransportClientSocketPoolTest, TwoRequestsCancelOne) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog()));
+ callback.callback(), &pool_, NetLogWithSource()));
EXPECT_EQ(ERR_IO_PENDING,
handle2.Init("a", params_, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), &pool_, BoundNetLog()));
+ callback2.callback(), &pool_, NetLogWithSource()));
handle.Reset();
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
handle2.Reset();
}
@@ -289,7 +294,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest, ConnectCancelConnect) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog()));
+ callback.callback(), &pool_, NetLogWithSource()));
handle.Reset();
@@ -297,7 +302,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest, ConnectCancelConnect) {
EXPECT_EQ(ERR_IO_PENDING,
handle.Init("a", params_, kDefaultPriority,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), &pool_, BoundNetLog()));
+ callback2.callback(), &pool_, NetLogWithSource()));
host_resolver_->set_synchronous_mode(true);
// At this point, handle has two ConnectingSockets out for it. Due to the
@@ -309,7 +314,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest, ConnectCancelConnect) {
// If the first one is not cancelled, it will advance the load state, and
// then the second one will crash.
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_FALSE(callback.have_result());
handle.Reset();
@@ -317,17 +322,17 @@ TEST_F(WebSocketTransportClientSocketPoolTest, ConnectCancelConnect) {
TEST_F(WebSocketTransportClientSocketPoolTest, CancelRequest) {
// First request finishes asynchronously.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, request(0)->WaitForResult());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(request(0)->WaitForResult(), IsOk());
// Make all subsequent host resolutions complete synchronously.
host_resolver_->set_synchronous_mode(true);
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
// Cancel a request.
const size_t index_to_cancel = 2;
@@ -360,7 +365,7 @@ void RequestSocketOnComplete(ClientSocketHandle* handle,
WebSocketTransportClientSocketPool* pool,
const CompletionCallback& nested_callback,
int first_request_result) {
- EXPECT_EQ(OK, first_request_result);
+ EXPECT_THAT(first_request_result, IsOk());
// Don't allow reuse of the socket. Disconnect it and then release it.
handle->socket()->Disconnect();
@@ -371,8 +376,8 @@ void RequestSocketOnComplete(ClientSocketHandle* handle,
TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT));
int rv =
handle->Init("a", dest, LOWEST, ClientSocketPool::RespectLimits::ENABLED,
- nested_callback, pool, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ nested_callback, pool, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
if (ERR_IO_PENDING != rv)
nested_callback.Run(rv);
}
@@ -393,9 +398,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, RequestTwice) {
handle.Init("a", dest, LOWEST, ClientSocketPool::RespectLimits::ENABLED,
base::Bind(&RequestSocketOnComplete, &handle, &pool_,
second_result_callback.callback()),
- &pool_, BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, second_result_callback.WaitForResult());
+ &pool_, NetLogWithSource());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(second_result_callback.WaitForResult(), IsOk());
handle.Reset();
}
@@ -408,15 +413,15 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
MockTransportClientSocketFactory::MOCK_PENDING_CLIENT_SOCKET);
// Queue up all the requests
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
// Now, kMaxSocketsPerGroup requests should be active. Let's cancel them.
ASSERT_LE(kMaxSocketsPerGroup, static_cast<int>(requests()->size()));
@@ -425,7 +430,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
// Let's wait for the rest to complete now.
for (size_t i = kMaxSocketsPerGroup; i < requests()->size(); ++i) {
- EXPECT_EQ(OK, request(i)->WaitForResult());
+ EXPECT_THAT(request(i)->WaitForResult(), IsOk());
request(i)->handle()->Reset();
}
@@ -443,17 +448,17 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
// Queue up all the requests
for (int i = 0; i < kNumRequests; i++)
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
for (int i = 0; i < kNumRequests; i++)
- EXPECT_EQ(ERR_CONNECTION_FAILED, request(i)->WaitForResult());
+ EXPECT_THAT(request(i)->WaitForResult(), IsError(ERR_CONNECTION_FAILED));
}
// The lock on the endpoint is released when a ClientSocketHandle is reset.
TEST_F(WebSocketTransportClientSocketPoolTest, LockReleasedOnHandleReset) {
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, request(0)->WaitForResult());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(request(0)->WaitForResult(), IsOk());
EXPECT_FALSE(request(1)->handle()->is_initialized());
request(0)->handle()->Reset();
RunUntilIdle();
@@ -466,11 +471,11 @@ TEST_F(WebSocketTransportClientSocketPoolTest, LockReleasedOnHandleDelete) {
std::unique_ptr<ClientSocketHandle> handle(new ClientSocketHandle);
int rv =
handle->Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool_, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool_, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_FALSE(request(0)->handle()->is_initialized());
handle.reset();
RunUntilIdle();
@@ -481,9 +486,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, LockReleasedOnHandleDelete) {
// explicitly released.
TEST_F(WebSocketTransportClientSocketPoolTest,
ConnectionProceedsOnExplicitRelease) {
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(OK, request(0)->WaitForResult());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(request(0)->WaitForResult(), IsOk());
EXPECT_FALSE(request(1)->handle()->is_initialized());
WebSocketTransportClientSocketPool::UnlockEndpoint(request(0)->handle());
RunUntilIdle();
@@ -501,22 +506,20 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
client_socket_factory_.set_client_socket_types(case_types,
arraysize(case_types));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
RunUntilIdle();
pool_.CancelRequest("a", request(0)->handle());
- EXPECT_EQ(OK, request(1)->WaitForResult());
+ EXPECT_THAT(request(1)->WaitForResult(), IsOk());
}
// Test the case of the IPv6 address stalling, and falling back to the IPv4
// socket which finishes first.
TEST_F(WebSocketTransportClientSocketPoolTest,
IPv6FallbackSocketIPv4FinishesFirst) {
- WebSocketTransportClientSocketPool pool(kMaxSockets,
- kMaxSocketsPerGroup,
+ WebSocketTransportClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup,
host_resolver_.get(),
- &client_socket_factory_,
- NULL);
+ &client_socket_factory_, nullptr);
MockTransportClientSocketFactory::ClientSocketType case_types[] = {
// This is the IPv6 socket.
@@ -534,12 +537,12 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
ClientSocketHandle handle;
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
IPEndPoint endpoint;
@@ -553,11 +556,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
// finish first.
TEST_F(WebSocketTransportClientSocketPoolTest,
IPv6FallbackSocketIPv6FinishesFirst) {
- WebSocketTransportClientSocketPool pool(kMaxSockets,
- kMaxSocketsPerGroup,
+ WebSocketTransportClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup,
host_resolver_.get(),
- &client_socket_factory_,
- NULL);
+ &client_socket_factory_, nullptr);
MockTransportClientSocketFactory::ClientSocketType case_types[] = {
// This is the IPv6 socket.
@@ -577,12 +578,12 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
ClientSocketHandle handle;
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
IPEndPoint endpoint;
@@ -593,11 +594,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
TEST_F(WebSocketTransportClientSocketPoolTest,
IPv6NoIPv4AddressesToFallbackTo) {
- WebSocketTransportClientSocketPool pool(kMaxSockets,
- kMaxSocketsPerGroup,
+ WebSocketTransportClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup,
host_resolver_.get(),
- &client_socket_factory_,
- NULL);
+ &client_socket_factory_, nullptr);
client_socket_factory_.set_default_client_socket_type(
MockTransportClientSocketFactory::MOCK_DELAYED_CLIENT_SOCKET);
@@ -610,12 +609,12 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
ClientSocketHandle handle;
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
IPEndPoint endpoint;
@@ -625,11 +624,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
}
TEST_F(WebSocketTransportClientSocketPoolTest, IPv4HasNoFallback) {
- WebSocketTransportClientSocketPool pool(kMaxSockets,
- kMaxSocketsPerGroup,
+ WebSocketTransportClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup,
host_resolver_.get(),
- &client_socket_factory_,
- NULL);
+ &client_socket_factory_, nullptr);
client_socket_factory_.set_default_client_socket_type(
MockTransportClientSocketFactory::MOCK_DELAYED_CLIENT_SOCKET);
@@ -641,12 +638,12 @@ TEST_F(WebSocketTransportClientSocketPoolTest, IPv4HasNoFallback) {
ClientSocketHandle handle;
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
IPEndPoint endpoint;
@@ -658,11 +655,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, IPv4HasNoFallback) {
// If all IPv6 addresses fail to connect synchronously, then IPv4 connections
// proceeed immediately.
TEST_F(WebSocketTransportClientSocketPoolTest, IPv6InstantFail) {
- WebSocketTransportClientSocketPool pool(kMaxSockets,
- kMaxSocketsPerGroup,
+ WebSocketTransportClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup,
host_resolver_.get(),
- &client_socket_factory_,
- NULL);
+ &client_socket_factory_, nullptr);
MockTransportClientSocketFactory::ClientSocketType case_types[] = {
// First IPv6 socket.
@@ -683,8 +678,8 @@ TEST_F(WebSocketTransportClientSocketPoolTest, IPv6InstantFail) {
ClientSocketHandle handle;
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(OK, rv);
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(rv, IsOk());
ASSERT_TRUE(handle.socket());
IPEndPoint endpoint;
@@ -695,11 +690,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, IPv6InstantFail) {
// If all IPv6 addresses fail before the IPv4 fallback timeout, then the IPv4
// connections proceed immediately.
TEST_F(WebSocketTransportClientSocketPoolTest, IPv6RapidFail) {
- WebSocketTransportClientSocketPool pool(kMaxSockets,
- kMaxSocketsPerGroup,
+ WebSocketTransportClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup,
host_resolver_.get(),
- &client_socket_factory_,
- NULL);
+ &client_socket_factory_, nullptr);
MockTransportClientSocketFactory::ClientSocketType case_types[] = {
// First IPv6 socket.
@@ -720,12 +713,12 @@ TEST_F(WebSocketTransportClientSocketPoolTest, IPv6RapidFail) {
ClientSocketHandle handle;
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.socket());
base::TimeTicks start(base::TimeTicks::Now());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_LT(base::TimeTicks::Now() - start,
base::TimeDelta::FromMilliseconds(
TransportConnectJob::kIPv6FallbackTimerInMs));
@@ -740,11 +733,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, IPv6RapidFail) {
// can only happen if the sockets are different types, since sockets of the same
// type do not race).
TEST_F(WebSocketTransportClientSocketPoolTest, FirstSuccessWins) {
- WebSocketTransportClientSocketPool pool(kMaxSockets,
- kMaxSocketsPerGroup,
+ WebSocketTransportClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup,
host_resolver_.get(),
- &client_socket_factory_,
- NULL);
+ &client_socket_factory_, nullptr);
client_socket_factory_.set_default_client_socket_type(
MockTransportClientSocketFactory::MOCK_TRIGGERABLE_CLIENT_SOCKET);
@@ -757,8 +748,8 @@ TEST_F(WebSocketTransportClientSocketPoolTest, FirstSuccessWins) {
ClientSocketHandle handle;
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
ASSERT_FALSE(handle.socket());
base::Closure ipv6_connect_trigger =
@@ -769,7 +760,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest, FirstSuccessWins) {
ipv4_connect_trigger.Run();
ipv6_connect_trigger.Run();
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
ASSERT_TRUE(handle.socket());
IPEndPoint endpoint;
@@ -779,11 +770,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, FirstSuccessWins) {
// We should not report failure until all connections have failed.
TEST_F(WebSocketTransportClientSocketPoolTest, LastFailureWins) {
- WebSocketTransportClientSocketPool pool(kMaxSockets,
- kMaxSocketsPerGroup,
+ WebSocketTransportClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup,
host_resolver_.get(),
- &client_socket_factory_,
- NULL);
+ &client_socket_factory_, nullptr);
client_socket_factory_.set_default_client_socket_type(
MockTransportClientSocketFactory::MOCK_DELAYED_FAILING_CLIENT_SOCKET);
@@ -810,10 +799,10 @@ TEST_F(WebSocketTransportClientSocketPoolTest, LastFailureWins) {
base::TimeTicks start(base::TimeTicks::Now());
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
EXPECT_GE(base::TimeTicks::Now() - start, delay * 5);
}
@@ -822,11 +811,9 @@ TEST_F(WebSocketTransportClientSocketPoolTest, LastFailureWins) {
// because it takes 4 minutes. Run with --gtest_also_run_disabled_tests if you
// want to run it.
TEST_F(WebSocketTransportClientSocketPoolTest, DISABLED_OverallTimeoutApplies) {
- WebSocketTransportClientSocketPool pool(kMaxSockets,
- kMaxSocketsPerGroup,
+ WebSocketTransportClientSocketPool pool(kMaxSockets, kMaxSocketsPerGroup,
host_resolver_.get(),
- &client_socket_factory_,
- NULL);
+ &client_socket_factory_, nullptr);
const base::TimeDelta connect_job_timeout = pool.ConnectionTimeout();
client_socket_factory_.set_default_client_socket_type(
@@ -848,25 +835,25 @@ TEST_F(WebSocketTransportClientSocketPoolTest, DISABLED_OverallTimeoutApplies) {
int rv =
handle.Init("a", params_, LOW, ClientSocketPool::RespectLimits::ENABLED,
- callback.callback(), &pool, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ callback.callback(), &pool, NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_EQ(ERR_TIMED_OUT, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_TIMED_OUT));
}
TEST_F(WebSocketTransportClientSocketPoolTest, MaxSocketsEnforced) {
host_resolver_->set_synchronous_mode(true);
for (int i = 0; i < kMaxSockets; ++i) {
- ASSERT_EQ(OK, StartRequest("a", kDefaultPriority));
+ ASSERT_THAT(StartRequest("a", kDefaultPriority), IsOk());
WebSocketTransportClientSocketPool::UnlockEndpoint(request(i)->handle());
RunUntilIdle();
}
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
}
TEST_F(WebSocketTransportClientSocketPoolTest, MaxSocketsEnforcedWhenPending) {
for (int i = 0; i < kMaxSockets + 1; ++i) {
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
}
// Now there are 32 sockets waiting to connect, and one stalled.
for (int i = 0; i < kMaxSockets; ++i) {
@@ -884,12 +871,12 @@ TEST_F(WebSocketTransportClientSocketPoolTest, MaxSocketsEnforcedWhenPending) {
TEST_F(WebSocketTransportClientSocketPoolTest, StalledSocketReleased) {
host_resolver_->set_synchronous_mode(true);
for (int i = 0; i < kMaxSockets; ++i) {
- ASSERT_EQ(OK, StartRequest("a", kDefaultPriority));
+ ASSERT_THAT(StartRequest("a", kDefaultPriority), IsOk());
WebSocketTransportClientSocketPool::UnlockEndpoint(request(i)->handle());
RunUntilIdle();
}
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
ReleaseOneConnection(ClientSocketPoolTest::NO_KEEP_ALIVE);
EXPECT_TRUE(request(kMaxSockets)->handle()->is_initialized());
EXPECT_TRUE(request(kMaxSockets)->handle()->socket());
@@ -897,18 +884,18 @@ TEST_F(WebSocketTransportClientSocketPoolTest, StalledSocketReleased) {
TEST_F(WebSocketTransportClientSocketPoolTest, IsStalledTrueWhenStalled) {
for (int i = 0; i < kMaxSockets + 1; ++i) {
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
}
- EXPECT_EQ(OK, request(0)->WaitForResult());
+ EXPECT_THAT(request(0)->WaitForResult(), IsOk());
EXPECT_TRUE(pool_.IsStalled());
}
TEST_F(WebSocketTransportClientSocketPoolTest,
CancellingPendingSocketUnstallsStalledSocket) {
for (int i = 0; i < kMaxSockets + 1; ++i) {
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
}
- EXPECT_EQ(OK, request(0)->WaitForResult());
+ EXPECT_THAT(request(0)->WaitForResult(), IsOk());
request(1)->handle()->Reset();
RunUntilIdle();
EXPECT_FALSE(pool_.IsStalled());
@@ -917,7 +904,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
TEST_F(WebSocketTransportClientSocketPoolTest,
LoadStateOfStalledSocketIsWaitingForAvailableSocket) {
for (int i = 0; i < kMaxSockets + 1; ++i) {
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
}
EXPECT_EQ(LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET,
pool_.GetLoadState("a", request(kMaxSockets)->handle()));
@@ -926,7 +913,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
TEST_F(WebSocketTransportClientSocketPoolTest,
CancellingStalledSocketUnstallsPool) {
for (int i = 0; i < kMaxSockets + 1; ++i) {
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
}
request(kMaxSockets)->handle()->Reset();
RunUntilIdle();
@@ -935,28 +922,28 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
TEST_F(WebSocketTransportClientSocketPoolTest,
FlushWithErrorFlushesPendingConnections) {
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
pool_.FlushWithError(ERR_FAILED);
- EXPECT_EQ(ERR_FAILED, request(0)->WaitForResult());
+ EXPECT_THAT(request(0)->WaitForResult(), IsError(ERR_FAILED));
}
TEST_F(WebSocketTransportClientSocketPoolTest,
FlushWithErrorFlushesStalledConnections) {
for (int i = 0; i < kMaxSockets + 1; ++i) {
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
}
pool_.FlushWithError(ERR_FAILED);
- EXPECT_EQ(ERR_FAILED, request(kMaxSockets)->WaitForResult());
+ EXPECT_THAT(request(kMaxSockets)->WaitForResult(), IsError(ERR_FAILED));
}
TEST_F(WebSocketTransportClientSocketPoolTest,
AfterFlushWithErrorCanMakeNewConnections) {
for (int i = 0; i < kMaxSockets + 1; ++i) {
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
}
pool_.FlushWithError(ERR_FAILED);
host_resolver_->set_synchronous_mode(true);
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
}
// Deleting pending connections can release the lock on the endpoint, which can
@@ -975,14 +962,14 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
client_socket_factory_.set_default_client_socket_type(
MockTransportClientSocketFactory::MOCK_CLIENT_SOCKET);
for (int i = 0; i < kMaxSockets; ++i) {
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
}
// Now we have one socket in STATE_TRANSPORT_CONNECT and the rest in
// STATE_OBTAIN_LOCK. If any of the sockets in STATE_OBTAIN_LOCK is given the
// lock, they will synchronously connect.
pool_.FlushWithError(ERR_FAILED);
for (int i = 0; i < kMaxSockets; ++i) {
- EXPECT_EQ(ERR_FAILED, request(i)->WaitForResult());
+ EXPECT_THAT(request(i)->WaitForResult(), IsError(ERR_FAILED));
}
}
@@ -1014,7 +1001,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
"1.1.1.1",
i + 1),
std::string());
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
}
// Now we have |kMaxSockets| IPv6 sockets stalled in connect. No IPv4 sockets
// are started yet.
@@ -1024,7 +1011,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
// connect, and |kMaxSockets - 1| IPv4 sockets waiting for the endpoint lock.
pool_.FlushWithError(ERR_FAILED);
for (int i = 0; i < kMaxSockets; ++i) {
- EXPECT_EQ(ERR_FAILED, request(i)->WaitForResult());
+ EXPECT_THAT(request(i)->WaitForResult(), IsError(ERR_FAILED));
}
}
@@ -1038,14 +1025,14 @@ TEST_F(WebSocketTransportClientSocketPoolTest,
MockTransportClientSocketFactory::MOCK_STALLED_CLIENT_SOCKET};
client_socket_factory_.set_client_socket_types(socket_types,
arraysize(socket_types));
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
// Socket has been "handed out".
EXPECT_TRUE(request(0)->handle()->socket());
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
// Now we have one socket handed out, and one pending.
pool_.FlushWithError(ERR_FAILED);
- EXPECT_EQ(ERR_FAILED, request(1)->WaitForResult());
+ EXPECT_THAT(request(1)->WaitForResult(), IsError(ERR_FAILED));
// Socket owned by ClientSocketHandle is unaffected:
EXPECT_TRUE(request(0)->handle()->socket());
// Return it to the pool (which deletes it).
@@ -1063,7 +1050,7 @@ TEST_F(WebSocketTransportClientSocketPoolTest, CancelRequestReclaimsSockets) {
client_socket_factory_.set_client_socket_types(socket_types,
arraysize(socket_types));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
base::Closure connect_trigger =
client_socket_factory_.WaitForTriggerableSocketCreation();
@@ -1075,23 +1062,23 @@ TEST_F(WebSocketTransportClientSocketPoolTest, CancelRequestReclaimsSockets) {
RunUntilIdle();
// We should now be able to create a new connection without blocking on the
// endpoint lock.
- EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
}
// A handshake completing and then the WebSocket closing should only release one
// Endpoint, not two.
TEST_F(WebSocketTransportClientSocketPoolTest, EndpointLockIsOnlyReleasedOnce) {
host_resolver_->set_synchronous_mode(true);
- ASSERT_EQ(OK, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
+ ASSERT_THAT(StartRequest("a", kDefaultPriority), IsOk());
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
+ EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
// First socket completes handshake.
WebSocketTransportClientSocketPool::UnlockEndpoint(request(0)->handle());
RunUntilIdle();
// First socket is closed.
request(0)->handle()->Reset();
// Second socket should have been released.
- EXPECT_EQ(OK, request(1)->WaitForResult());
+ EXPECT_THAT(request(1)->WaitForResult(), IsOk());
// Third socket should still be waiting for endpoint.
ASSERT_FALSE(request(2)->handle()->is_initialized());
EXPECT_EQ(LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET,
diff --git a/chromium/net/socket/websocket_transport_connect_sub_job.cc b/chromium/net/socket/websocket_transport_connect_sub_job.cc
index b618589363b..97d36596656 100644
--- a/chromium/net/socket/websocket_transport_connect_sub_job.cc
+++ b/chromium/net/socket/websocket_transport_connect_sub_job.cc
@@ -7,7 +7,7 @@
#include "base/logging.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/websocket_endpoint_lock_manager.h"
@@ -70,7 +70,7 @@ ClientSocketFactory* WebSocketTransportConnectSubJob::client_socket_factory()
return parent_job_->client_socket_factory_;
}
-const BoundNetLog& WebSocketTransportConnectSubJob::net_log() const {
+const NetLogWithSource& WebSocketTransportConnectSubJob::net_log() const {
return parent_job_->net_log();
}
diff --git a/chromium/net/socket/websocket_transport_connect_sub_job.h b/chromium/net/socket/websocket_transport_connect_sub_job.h
index f7ff53393c2..958eaa7a556 100644
--- a/chromium/net/socket/websocket_transport_connect_sub_job.h
+++ b/chromium/net/socket/websocket_transport_connect_sub_job.h
@@ -19,9 +19,9 @@
namespace net {
-class BoundNetLog;
class ClientSocketFactory;
class IPEndPoint;
+class NetLogWithSource;
class StreamSocket;
// Attempts to connect to a subset of the addresses required by a
@@ -67,7 +67,7 @@ class WebSocketTransportConnectSubJob
ClientSocketFactory* client_socket_factory() const;
- const BoundNetLog& net_log() const;
+ const NetLogWithSource& net_log() const;
const IPEndPoint& CurrentAddress() const;
diff --git a/chromium/net/spdy/bidirectional_stream_spdy_impl.cc b/chromium/net/spdy/bidirectional_stream_spdy_impl.cc
index 6a394c2ff61..44ccc3a3287 100644
--- a/chromium/net/spdy/bidirectional_stream_spdy_impl.cc
+++ b/chromium/net/spdy/bidirectional_stream_spdy_impl.cc
@@ -38,15 +38,17 @@ BidirectionalStreamSpdyImpl::BidirectionalStreamSpdyImpl(
closed_stream_status_(ERR_FAILED),
closed_stream_received_bytes_(0),
closed_stream_sent_bytes_(0),
+ closed_has_load_timing_info_(false),
weak_factory_(this) {}
BidirectionalStreamSpdyImpl::~BidirectionalStreamSpdyImpl() {
- Cancel();
+ // Sends a RST to the remote if the stream is destroyed before it completes.
+ ResetStream();
}
void BidirectionalStreamSpdyImpl::Start(
const BidirectionalStreamRequestInfo* request_info,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
bool /*send_request_headers_automatically*/,
BidirectionalStreamImpl::Delegate* delegate,
std::unique_ptr<base::Timer> timer) {
@@ -151,15 +153,6 @@ void BidirectionalStreamSpdyImpl::SendvData(
end_stream ? NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND);
}
-void BidirectionalStreamSpdyImpl::Cancel() {
- if (delegate_) {
- delegate_ = nullptr;
- // Cancel any pending callback.
- weak_factory_.InvalidateWeakPtrs();
- }
- ResetStream();
-}
-
NextProto BidirectionalStreamSpdyImpl::GetProtocol() const {
return negotiated_protocol_;
}
@@ -184,10 +177,27 @@ int64_t BidirectionalStreamSpdyImpl::GetTotalSentBytes() const {
return stream_->raw_sent_bytes();
}
+bool BidirectionalStreamSpdyImpl::GetLoadTimingInfo(
+ LoadTimingInfo* load_timing_info) const {
+ if (stream_closed_) {
+ if (!closed_has_load_timing_info_)
+ return false;
+ *load_timing_info = closed_load_timing_info_;
+ return true;
+ }
+
+ // If |stream_| isn't created or has ID 0, return false. This is to match
+ // the implementation in SpdyHttpStream.
+ if (!stream_ || stream_->stream_id() == 0)
+ return false;
+
+ return stream_->GetLoadTimingInfo(load_timing_info);
+}
+
void BidirectionalStreamSpdyImpl::OnRequestHeadersSent() {
DCHECK(stream_);
- negotiated_protocol_ = stream_->GetProtocol();
+ negotiated_protocol_ = kProtoHTTP2;
if (delegate_)
delegate_->OnStreamReady(/*request_headers_sent=*/true);
}
@@ -246,6 +256,8 @@ void BidirectionalStreamSpdyImpl::OnClose(int status) {
closed_stream_status_ = status;
closed_stream_received_bytes_ = stream_->raw_received_bytes();
closed_stream_sent_bytes_ = stream_->raw_sent_bytes();
+ closed_has_load_timing_info_ =
+ stream_->GetLoadTimingInfo(&closed_load_timing_info_);
if (status != OK) {
NotifyError(status);
@@ -260,15 +272,14 @@ void BidirectionalStreamSpdyImpl::OnClose(int status) {
}
int BidirectionalStreamSpdyImpl::SendRequestHeadersHelper() {
- std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
+ SpdyHeaderBlock headers;
HttpRequestInfo http_request_info;
http_request_info.url = request_info_->url;
http_request_info.method = request_info_->method;
http_request_info.extra_headers = request_info_->extra_headers;
CreateSpdyHeadersFromHttpRequest(
- http_request_info, http_request_info.extra_headers,
- stream_->GetProtocolVersion(), true, headers.get());
+ http_request_info, http_request_info.extra_headers, true, &headers);
return stream_->SendRequestHeaders(std::move(headers),
request_info_->end_stream_on_headers
? NO_MORE_DATA_TO_SEND
diff --git a/chromium/net/spdy/bidirectional_stream_spdy_impl.h b/chromium/net/spdy/bidirectional_stream_spdy_impl.h
index b40c1ff9aaf..1e5e782bbbf 100644
--- a/chromium/net/spdy/bidirectional_stream_spdy_impl.h
+++ b/chromium/net/spdy/bidirectional_stream_spdy_impl.h
@@ -13,6 +13,8 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "net/base/load_timing_info.h"
+#include "net/base/net_export.h"
#include "net/http/bidirectional_stream_impl.h"
#include "net/http/bidirectional_stream_request_info.h"
#include "net/http/http_request_info.h"
@@ -26,8 +28,8 @@ class Timer;
namespace net {
-class BoundNetLog;
class IOBuffer;
+class NetLogWithSource;
class SpdyHeaderBlock;
class NET_EXPORT_PRIVATE BidirectionalStreamSpdyImpl
@@ -41,7 +43,7 @@ class NET_EXPORT_PRIVATE BidirectionalStreamSpdyImpl
// BidirectionalStreamImpl implementation:
void Start(const BidirectionalStreamRequestInfo* request_info,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
bool send_request_headers_automatically,
BidirectionalStreamImpl::Delegate* delegate,
std::unique_ptr<base::Timer> timer) override;
@@ -53,10 +55,10 @@ class NET_EXPORT_PRIVATE BidirectionalStreamSpdyImpl
void SendvData(const std::vector<scoped_refptr<IOBuffer>>& buffers,
const std::vector<int>& lengths,
bool end_stream) override;
- void Cancel() override;
NextProto GetProtocol() const override;
int64_t GetTotalReceivedBytes() const override;
int64_t GetTotalSentBytes() const override;
+ bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
// SpdyStream::Delegate implementation:
void OnRequestHeadersSent() override;
@@ -104,6 +106,11 @@ class NET_EXPORT_PRIVATE BidirectionalStreamSpdyImpl
// After |stream_| has been closed, this keeps track of the total number of
// bytes sent over the network for |stream_| while it was open.
int64_t closed_stream_sent_bytes_;
+ // True if |stream_| has LoadTimingInfo when it is closed.
+ bool closed_has_load_timing_info_;
+ // LoadTimingInfo populated when |stream_| is closed.
+ LoadTimingInfo closed_load_timing_info_;
+
// This is the combined buffer of buffers passed in through SendvData.
// Keep a reference here so it is alive until OnDataSent is invoked.
scoped_refptr<IOBuffer> pending_combined_buffer_;
diff --git a/chromium/net/spdy/bidirectional_stream_spdy_impl_unittest.cc b/chromium/net/spdy/bidirectional_stream_spdy_impl_unittest.cc
index 86ffbfda8e0..bee61f0a6f6 100644
--- a/chromium/net/spdy/bidirectional_stream_spdy_impl_unittest.cc
+++ b/chromium/net/spdy/bidirectional_stream_spdy_impl_unittest.cc
@@ -14,19 +14,26 @@
#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "base/timer/mock_timer.h"
+#include "net/base/load_timing_info.h"
+#include "net/base/load_timing_info_test_util.h"
#include "net/base/net_errors.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_source.h"
#include "net/log/test_net_log.h"
#include "net/socket/socket_test_util.h"
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_test_util_common.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -36,6 +43,28 @@ const size_t kBodyDataSize = arraysize(kBodyData);
// Size of the buffer to be allocated for each read.
const size_t kReadBufferSize = 4096;
+// Tests the load timing of a stream that's connected and is not the first
+// request sent on a connection.
+void TestLoadTimingReused(const LoadTimingInfo& load_timing_info) {
+ EXPECT_TRUE(load_timing_info.socket_reused);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
+
+ ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
+ ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
+}
+
+// Tests the load timing of a stream that's connected and using a fresh
+// connection.
+void TestLoadTimingNotReused(const LoadTimingInfo& load_timing_info) {
+ EXPECT_FALSE(load_timing_info.socket_reused);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
+
+ ExpectConnectTimingHasTimes(
+ load_timing_info.connect_timing,
+ CONNECT_TIMING_HAS_SSL_TIMES | CONNECT_TIMING_HAS_DNS_TIMES);
+ ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
+}
+
class TestDelegateBase : public BidirectionalStreamImpl::Delegate {
public:
TestDelegateBase(base::WeakPtr<SpdySession> session,
@@ -103,10 +132,10 @@ class TestDelegateBase : public BidirectionalStreamImpl::Delegate {
}
void Start(const BidirectionalStreamRequestInfo* request,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
stream_->Start(request, net_log,
/*send_request_headers_automatically=*/false, this,
- base::WrapUnique(new base::Timer(false, false)));
+ base::MakeUnique<base::Timer>(false, false));
not_expect_callback_ = false;
}
@@ -130,6 +159,9 @@ class TestDelegateBase : public BidirectionalStreamImpl::Delegate {
loop_.reset(new base::RunLoop);
}
+ // Wait until the stream reaches completion.
+ void WaitUntilCompletion() { loop_->Run(); }
+
// Starts or continues read data from |stream_| until there is no more
// byte can be read synchronously.
void StartOrContinueReading() {
@@ -154,10 +186,16 @@ class TestDelegateBase : public BidirectionalStreamImpl::Delegate {
NextProto GetProtocol() const { return stream_->GetProtocol(); }
int64_t GetTotalReceivedBytes() const {
- return stream_->GetTotalReceivedBytes();
+ return stream_->GetTotalReceivedBytes();
}
- int64_t GetTotalSentBytes() const { return stream_->GetTotalSentBytes(); }
+ int64_t GetTotalSentBytes() const {
+ return stream_->GetTotalSentBytes();
+ }
+
+ bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
+ return stream_->GetLoadTimingInfo(load_timing_info);
+ }
// Const getters for internal states.
const std::string& data_received() const { return data_received_; }
@@ -174,9 +212,6 @@ class TestDelegateBase : public BidirectionalStreamImpl::Delegate {
do_not_start_read_ = do_not_start_read;
}
- // Cancels |stream_|.
- void CancelStream() { stream_->Cancel(); }
-
private:
std::unique_ptr<BidirectionalStreamSpdyImpl> stream_;
scoped_refptr<IOBuffer> read_buf_;
@@ -202,13 +237,11 @@ class TestDelegateBase : public BidirectionalStreamImpl::Delegate {
class BidirectionalStreamSpdyImplTest : public testing::Test {
public:
BidirectionalStreamSpdyImplTest()
- : spdy_util_(kProtoHTTP2, true),
- session_deps_(kProtoHTTP2),
- default_url_(kDefaultUrl),
+ : default_url_(kDefaultUrl),
host_port_pair_(HostPortPair::FromURL(default_url_)),
key_(host_port_pair_, ProxyServer::Direct(), PRIVACY_MODE_DISABLED),
ssl_data_(SSLSocketDataProvider(ASYNC, OK)) {
- ssl_data_.SetNextProto(kProtoHTTP2);
+ ssl_data_.next_proto = kProtoHTTP2;
ssl_data_.cert = ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
}
@@ -250,82 +283,120 @@ class BidirectionalStreamSpdyImplTest : public testing::Test {
SSLSocketDataProvider ssl_data_;
};
-TEST_F(BidirectionalStreamSpdyImplTest, SendDataAfterStreamFailed) {
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
- kDefaultUrl, 1, kBodyDataSize * 3, LOW, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> rst(
- spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
-
+TEST_F(BidirectionalStreamSpdyImplTest, SimplePostRequest) {
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
+ kDefaultUrl, 1, kBodyDataSize, LOW, nullptr, 0));
+ SpdySerializedFrame data_frame(spdy_util_.ConstructSpdyDataFrame(
+ 1, kBodyData, kBodyDataSize, /*fin=*/true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
+ CreateMockWrite(req, 0), CreateMockWrite(data_frame, 3),
};
-
- const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
-
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
+ SpdySerializedFrame response_body_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, /*fin=*/true));
MockRead reads[] = {
- CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3),
+ CreateMockRead(resp, 1),
+ MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
+ CreateMockRead(response_body_frame, 4), MockRead(ASYNC, 0, 5),
};
-
InitSession(reads, arraysize(reads), writes, arraysize(writes));
BidirectionalStreamRequestInfo request_info;
request_info.method = "POST";
request_info.url = default_url_;
request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
- base::SizeTToString(kBodyDataSize * 3));
+ base::SizeTToString(kBodyDataSize));
scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
std::unique_ptr<TestDelegateBase> delegate(
new TestDelegateBase(session_, read_buffer.get(), kReadBufferSize));
delegate->SetRunUntilCompletion(true);
delegate->Start(&request_info, net_log_.bound());
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(delegate->on_failed_called());
+ sequenced_data_->RunUntilPaused();
- // Try to send data after OnFailed(), should not get called back.
- scoped_refptr<StringIOBuffer> buf(new StringIOBuffer("dummy"));
- delegate->SendData(buf.get(), buf->size(), false);
+ scoped_refptr<StringIOBuffer> write_buffer(
+ new StringIOBuffer(std::string(kBodyData, kBodyDataSize)));
+ delegate->SendData(write_buffer.get(), write_buffer->size(), true);
+ sequenced_data_->Resume();
base::RunLoop().RunUntilIdle();
+ delegate->WaitUntilCompletion();
+ LoadTimingInfo load_timing_info;
+ EXPECT_TRUE(delegate->GetLoadTimingInfo(&load_timing_info));
+ TestLoadTimingNotReused(load_timing_info);
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate->error());
- EXPECT_EQ(0, delegate->on_data_read_count());
- EXPECT_EQ(0, delegate->on_data_sent_count());
+ EXPECT_EQ(1, delegate->on_data_read_count());
+ EXPECT_EQ(1, delegate->on_data_sent_count());
EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- // BidirectionalStreamSpdyStreamJob does not count the bytes sent for |rst|
- // because it is sent after SpdyStream::Delegate::OnClose is called.
- EXPECT_EQ(CountWriteBytes(writes, 1), delegate->GetTotalSentBytes());
+ EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
+ delegate->GetTotalSentBytes());
EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
delegate->GetTotalReceivedBytes());
}
-TEST_F(BidirectionalStreamSpdyImplTest, SendDataAfterCancelStream) {
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
+TEST_F(BidirectionalStreamSpdyImplTest, LoadTimingTwoRequests) {
+ SpdySerializedFrame req(
+ spdy_util_.ConstructSpdyGet(nullptr, 0, /*stream_id=*/1, LOW, true));
+ SpdySerializedFrame req2(
+ spdy_util_.ConstructSpdyGet(nullptr, 0, /*stream_id=*/3, LOW, true));
+ MockWrite writes[] = {
+ CreateMockWrite(req, 0), CreateMockWrite(req2, 2),
+ };
+ SpdySerializedFrame resp(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, /*stream_id=*/1));
+ SpdySerializedFrame resp2(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, /*stream_id=*/3));
+ SpdySerializedFrame resp_body(
+ spdy_util_.ConstructSpdyDataFrame(/*stream_id=*/1, /*fin=*/true));
+ SpdySerializedFrame resp_body2(
+ spdy_util_.ConstructSpdyDataFrame(/*stream_id=*/3, /*fin=*/true));
+ MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(resp_body, 3),
+ CreateMockRead(resp2, 4), CreateMockRead(resp_body2, 5),
+ MockRead(ASYNC, 0, 6)};
+ InitSession(reads, arraysize(reads), writes, arraysize(writes));
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
- kDefaultUrl, 1, kBodyDataSize * 3, LOWEST, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> data_frame(
- framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
- std::unique_ptr<SpdySerializedFrame> rst(
- spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
+ BidirectionalStreamRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = default_url_;
+ request_info.end_stream_on_headers = true;
+
+ scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
+ scoped_refptr<IOBuffer> read_buffer2(new IOBuffer(kReadBufferSize));
+ std::unique_ptr<TestDelegateBase> delegate(
+ new TestDelegateBase(session_, read_buffer.get(), kReadBufferSize));
+ std::unique_ptr<TestDelegateBase> delegate2(
+ new TestDelegateBase(session_, read_buffer2.get(), kReadBufferSize));
+ delegate->SetRunUntilCompletion(true);
+ delegate2->SetRunUntilCompletion(true);
+ delegate->Start(&request_info, net_log_.bound());
+ delegate2->Start(&request_info, net_log_.bound());
+
+ base::RunLoop().RunUntilIdle();
+ delegate->WaitUntilCompletion();
+ delegate2->WaitUntilCompletion();
+ LoadTimingInfo load_timing_info;
+ EXPECT_TRUE(delegate->GetLoadTimingInfo(&load_timing_info));
+ TestLoadTimingNotReused(load_timing_info);
+ LoadTimingInfo load_timing_info2;
+ EXPECT_TRUE(delegate2->GetLoadTimingInfo(&load_timing_info2));
+ TestLoadTimingReused(load_timing_info2);
+}
+
+TEST_F(BidirectionalStreamSpdyImplTest, SendDataAfterStreamFailed) {
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
+ kDefaultUrl, 1, kBodyDataSize * 3, LOW, nullptr, 0));
+ SpdySerializedFrame rst(
+ spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*data_frame, 3),
- CreateMockWrite(*rst, 5),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> response_body_frame(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
+ const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
+ SpdySerializedFrame resp(
+ spdy_util_.ConstructSpdyGetReply(kExtraHeaders, 1, 1));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
- MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause.
- MockRead(ASYNC, 0, 6),
+ CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3),
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
@@ -333,40 +404,32 @@ TEST_F(BidirectionalStreamSpdyImplTest, SendDataAfterCancelStream) {
BidirectionalStreamRequestInfo request_info;
request_info.method = "POST";
request_info.url = default_url_;
- request_info.priority = LOWEST;
request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
base::SizeTToString(kBodyDataSize * 3));
scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
std::unique_ptr<TestDelegateBase> delegate(
new TestDelegateBase(session_, read_buffer.get(), kReadBufferSize));
- delegate->set_do_not_start_read(true);
+ delegate->SetRunUntilCompletion(true);
delegate->Start(&request_info, net_log_.bound());
- // Send the request and receive response headers.
- sequenced_data_->RunUntilPaused();
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
-
- // Send a DATA frame.
- scoped_refptr<StringIOBuffer> buf(
- new StringIOBuffer(std::string(kBodyData, kBodyDataSize)));
- delegate->SendData(buf.get(), buf->size(), false);
- sequenced_data_->Resume();
- base::RunLoop().RunUntilIdle();
- // Cancel the stream.
- delegate->CancelStream();
- sequenced_data_->Resume();
base::RunLoop().RunUntilIdle();
- // Try to send data after Cancel(), should not get called back.
+ EXPECT_TRUE(delegate->on_failed_called());
+
+ // Try to send data after OnFailed(), should not get called back.
+ scoped_refptr<StringIOBuffer> buf(new StringIOBuffer("dummy"));
delegate->SendData(buf.get(), buf->size(), false);
base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(delegate->on_failed_called());
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
+ EXPECT_THAT(delegate->error(), IsError(ERR_SPDY_PROTOCOL_ERROR));
EXPECT_EQ(0, delegate->on_data_read_count());
+ EXPECT_EQ(0, delegate->on_data_sent_count());
EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- EXPECT_EQ(0, delegate->GetTotalSentBytes());
- EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
+ // BidirectionalStreamSpdyStreamJob does not count the bytes sent for |rst|
+ // because it is sent after SpdyStream::Delegate::OnClose is called.
+ EXPECT_EQ(CountWriteBytes(writes, 1), delegate->GetTotalSentBytes());
+ EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
+ delegate->GetTotalReceivedBytes());
}
} // namespace net
diff --git a/chromium/net/spdy/buffered_spdy_framer.cc b/chromium/net/spdy/buffered_spdy_framer.cc
index 0a48f163e64..9148fe43066 100644
--- a/chromium/net/spdy/buffered_spdy_framer.cc
+++ b/chromium/net/spdy/buffered_spdy_framer.cc
@@ -22,23 +22,8 @@ size_t kHeaderBufferMaxSize = 256 * 1024;
} // namespace
-SpdyMajorVersion NextProtoToSpdyMajorVersion(NextProto next_proto) {
- switch (next_proto) {
- case kProtoSPDY31:
- return SPDY3;
- case kProtoHTTP2:
- return HTTP2;
- case kProtoUnknown:
- case kProtoHTTP11:
- case kProtoQUIC1SPDY3:
- break;
- }
- NOTREACHED();
- return HTTP2;
-}
-
-BufferedSpdyFramer::BufferedSpdyFramer(SpdyMajorVersion version)
- : spdy_framer_(version),
+BufferedSpdyFramer::BufferedSpdyFramer()
+ : spdy_framer_(HTTP2),
visitor_(NULL),
header_buffer_valid_(false),
header_stream_id_(SpdyFramer::kInvalidStream),
@@ -68,17 +53,7 @@ void BufferedSpdyFramer::OnSynStream(SpdyStreamId stream_id,
SpdyPriority priority,
bool fin,
bool unidirectional) {
- frames_received_++;
- DCHECK(!control_frame_fields_.get());
- control_frame_fields_.reset(new ControlFrameFields());
- control_frame_fields_->type = SYN_STREAM;
- control_frame_fields_->stream_id = stream_id;
- control_frame_fields_->associated_stream_id = associated_stream_id;
- control_frame_fields_->priority = priority;
- control_frame_fields_->fin = fin;
- control_frame_fields_->unidirectional = unidirectional;
-
- InitHeaderStreaming(stream_id);
+ NOTREACHED();
}
void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id,
@@ -106,14 +81,7 @@ void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id,
void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id,
bool fin) {
- frames_received_++;
- DCHECK(!control_frame_fields_.get());
- control_frame_fields_.reset(new ControlFrameFields());
- control_frame_fields_->type = SYN_REPLY;
- control_frame_fields_->stream_id = stream_id;
- control_frame_fields_->fin = fin;
-
- InitHeaderStreaming(stream_id);
+ NOTREACHED();
}
bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id,
@@ -135,17 +103,10 @@ bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id,
DCHECK(control_frame_fields_.get());
switch (control_frame_fields_->type) {
case SYN_STREAM:
- visitor_->OnSynStream(control_frame_fields_->stream_id,
- control_frame_fields_->associated_stream_id,
- control_frame_fields_->priority,
- control_frame_fields_->fin,
- control_frame_fields_->unidirectional,
- headers);
+ NOTREACHED();
break;
case SYN_REPLY:
- visitor_->OnSynReply(control_frame_fields_->stream_id,
- control_frame_fields_->fin,
- headers);
+ NOTREACHED();
break;
case HEADERS:
visitor_->OnHeaders(control_frame_fields_->stream_id,
@@ -153,13 +114,12 @@ bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id,
control_frame_fields_->weight,
control_frame_fields_->parent_stream_id,
control_frame_fields_->exclusive,
- control_frame_fields_->fin, headers);
+ control_frame_fields_->fin, std::move(headers));
break;
case PUSH_PROMISE:
- DCHECK_LT(SPDY3, protocol_version());
visitor_->OnPushPromise(control_frame_fields_->stream_id,
control_frame_fields_->promised_stream_id,
- headers);
+ std::move(headers));
break;
default:
DCHECK(false) << "Unexpect control frame type: "
@@ -213,7 +173,7 @@ void BufferedSpdyFramer::OnStreamPadding(SpdyStreamId stream_id, size_t len) {
SpdyHeadersHandlerInterface* BufferedSpdyFramer::OnHeaderFrameStart(
SpdyStreamId stream_id) {
- coalescer_.reset(new HeaderCoalescer(protocol_version()));
+ coalescer_.reset(new HeaderCoalescer());
return coalescer_.get();
}
@@ -227,29 +187,23 @@ void BufferedSpdyFramer::OnHeaderFrameEnd(SpdyStreamId stream_id,
DCHECK(control_frame_fields_.get());
switch (control_frame_fields_->type) {
case SYN_STREAM:
- visitor_->OnSynStream(
- control_frame_fields_->stream_id,
- control_frame_fields_->associated_stream_id,
- control_frame_fields_->priority, control_frame_fields_->fin,
- control_frame_fields_->unidirectional, coalescer_->headers());
+ NOTREACHED();
break;
case SYN_REPLY:
- visitor_->OnSynReply(control_frame_fields_->stream_id,
- control_frame_fields_->fin, coalescer_->headers());
+ NOTREACHED();
break;
case HEADERS:
- visitor_->OnHeaders(control_frame_fields_->stream_id,
- control_frame_fields_->has_priority,
- control_frame_fields_->weight,
- control_frame_fields_->parent_stream_id,
- control_frame_fields_->exclusive,
- control_frame_fields_->fin, coalescer_->headers());
+ visitor_->OnHeaders(
+ control_frame_fields_->stream_id, control_frame_fields_->has_priority,
+ control_frame_fields_->weight,
+ control_frame_fields_->parent_stream_id,
+ control_frame_fields_->exclusive, control_frame_fields_->fin,
+ coalescer_->release_headers());
break;
case PUSH_PROMISE:
- DCHECK_LT(SPDY3, protocol_version());
visitor_->OnPushPromise(control_frame_fields_->stream_id,
control_frame_fields_->promised_stream_id,
- coalescer_->headers());
+ coalescer_->release_headers());
break;
default:
DCHECK(false) << "Unexpect control frame type: "
@@ -317,7 +271,6 @@ void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id,
void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id,
SpdyStreamId promised_stream_id,
bool end) {
- DCHECK_LT(SPDY3, protocol_version());
frames_received_++;
DCHECK(!control_frame_fields_.get());
control_frame_fields_.reset(new ControlFrameFields());
@@ -343,14 +296,14 @@ bool BufferedSpdyFramer::OnUnknownFrame(SpdyStreamId stream_id,
return visitor_->OnUnknownFrame(stream_id, frame_type);
}
-SpdyMajorVersion BufferedSpdyFramer::protocol_version() {
- return spdy_framer_.protocol_version();
-}
-
size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) {
return spdy_framer_.ProcessInput(data, len);
}
+void BufferedSpdyFramer::UpdateHeaderDecoderTableSize(uint32_t value) {
+ spdy_framer_.UpdateHeaderDecoderTableSize(value);
+}
+
void BufferedSpdyFramer::Reset() {
spdy_framer_.Reset();
}
@@ -372,33 +325,6 @@ bool BufferedSpdyFramer::HasError() {
}
// TODO(jgraettinger): Eliminate uses of this method (prefer
-// SpdySynStreamIR).
-SpdySerializedFrame* BufferedSpdyFramer::CreateSynStream(
- SpdyStreamId stream_id,
- SpdyStreamId associated_stream_id,
- SpdyPriority priority,
- SpdyControlFlags flags,
- SpdyHeaderBlock headers) {
- SpdySynStreamIR syn_stream(stream_id, std::move(headers));
- syn_stream.set_associated_to_stream_id(associated_stream_id);
- syn_stream.set_priority(priority);
- syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0);
- syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0);
- return new SpdySerializedFrame(spdy_framer_.SerializeSynStream(syn_stream));
-}
-
-// TODO(jgraettinger): Eliminate uses of this method (prefer
-// SpdySynReplyIR).
-SpdySerializedFrame* BufferedSpdyFramer::CreateSynReply(
- SpdyStreamId stream_id,
- SpdyControlFlags flags,
- SpdyHeaderBlock headers) {
- SpdySynReplyIR syn_reply(stream_id, std::move(headers));
- syn_reply.set_fin(flags & CONTROL_FLAG_FIN);
- return new SpdySerializedFrame(spdy_framer_.SerializeSynReply(syn_reply));
-}
-
-// TODO(jgraettinger): Eliminate uses of this method (prefer
// SpdyRstStreamIR).
SpdySerializedFrame* BufferedSpdyFramer::CreateRstStream(
SpdyStreamId stream_id,
diff --git a/chromium/net/spdy/buffered_spdy_framer.h b/chromium/net/spdy/buffered_spdy_framer.h
index 8f04d9ecb2c..44daff3e85f 100644
--- a/chromium/net/spdy/buffered_spdy_framer.h
+++ b/chromium/net/spdy/buffered_spdy_framer.h
@@ -13,7 +13,6 @@
#include "base/macros.h"
#include "net/base/net_export.h"
-#include "net/socket/next_proto.h"
#include "net/spdy/header_coalescer.h"
#include "net/spdy/spdy_alt_svc_wire_format.h"
#include "net/spdy/spdy_framer.h"
@@ -22,11 +21,6 @@
namespace net {
-// Returns the SPDY major version corresponding to the given NextProto
-// value, which must represent a SPDY-like protocol.
-NET_EXPORT_PRIVATE SpdyMajorVersion NextProtoToSpdyMajorVersion(
- NextProto next_proto);
-
class NET_EXPORT_PRIVATE BufferedSpdyFramerVisitorInterface {
public:
BufferedSpdyFramerVisitorInterface() {}
@@ -38,19 +32,6 @@ class NET_EXPORT_PRIVATE BufferedSpdyFramerVisitorInterface {
virtual void OnStreamError(SpdyStreamId stream_id,
const std::string& description) = 0;
- // Called after all the header data for SYN_STREAM control frame is received.
- virtual void OnSynStream(SpdyStreamId stream_id,
- SpdyStreamId associated_stream_id,
- SpdyPriority priority,
- bool fin,
- bool unidirectional,
- const SpdyHeaderBlock& headers) = 0;
-
- // Called after all the header data for SYN_REPLY control frame is received.
- virtual void OnSynReply(SpdyStreamId stream_id,
- bool fin,
- const SpdyHeaderBlock& headers) = 0;
-
// Called after all the header data for HEADERS control frame is received.
virtual void OnHeaders(SpdyStreamId stream_id,
bool has_priority,
@@ -58,7 +39,7 @@ class NET_EXPORT_PRIVATE BufferedSpdyFramerVisitorInterface {
SpdyStreamId parent_stream_id,
bool exclusive,
bool fin,
- const SpdyHeaderBlock& headers) = 0;
+ SpdyHeaderBlock headers) = 0;
// Called when a data frame header is received.
virtual void OnDataFrameHeader(SpdyStreamId stream_id,
@@ -116,7 +97,7 @@ class NET_EXPORT_PRIVATE BufferedSpdyFramerVisitorInterface {
// Called when a PUSH_PROMISE frame has been parsed.
virtual void OnPushPromise(SpdyStreamId stream_id,
SpdyStreamId promised_stream_id,
- const SpdyHeaderBlock& headers) = 0;
+ SpdyHeaderBlock headers) = 0;
// Called when an ALTSVC frame has been parsed.
virtual void OnAltSvc(
@@ -140,7 +121,7 @@ class NET_EXPORT_PRIVATE BufferedSpdyFramerVisitorInterface {
class NET_EXPORT_PRIVATE BufferedSpdyFramer
: public SpdyFramerVisitorInterface {
public:
- explicit BufferedSpdyFramer(SpdyMajorVersion version);
+ BufferedSpdyFramer();
~BufferedSpdyFramer() override;
// Sets callbacks to be called from the buffered spdy framer. A visitor must
@@ -205,20 +186,12 @@ class NET_EXPORT_PRIVATE BufferedSpdyFramer
// SpdyFramer methods.
size_t ProcessInput(const char* data, size_t len);
- SpdyMajorVersion protocol_version();
+ void UpdateHeaderDecoderTableSize(uint32_t value);
void Reset();
SpdyFramer::SpdyError error_code() const;
SpdyFramer::SpdyState state() const;
bool MessageFullyRead();
bool HasError();
- SpdySerializedFrame* CreateSynStream(SpdyStreamId stream_id,
- SpdyStreamId associated_stream_id,
- SpdyPriority priority,
- SpdyControlFlags flags,
- SpdyHeaderBlock headers);
- SpdySerializedFrame* CreateSynReply(SpdyStreamId stream_id,
- SpdyControlFlags flags,
- SpdyHeaderBlock headers);
SpdySerializedFrame* CreateRstStream(SpdyStreamId stream_id,
SpdyRstStreamStatus status) const;
SpdySerializedFrame* CreateSettings(const SettingsMap& values) const;
@@ -251,8 +224,8 @@ class NET_EXPORT_PRIVATE BufferedSpdyFramer
return spdy_framer_.GetDataFrameMinimumSize();
}
- size_t GetControlFrameHeaderSize() const {
- return spdy_framer_.GetControlFrameHeaderSize();
+ size_t GetFrameHeaderSize() const {
+ return spdy_framer_.GetFrameHeaderSize();
}
size_t GetSynStreamMinimumSize() const {
diff --git a/chromium/net/spdy/buffered_spdy_framer_unittest.cc b/chromium/net/spdy/buffered_spdy_framer_unittest.cc
index 3e96481df23..0a851fe83c4 100644
--- a/chromium/net/spdy/buffered_spdy_framer_unittest.cc
+++ b/chromium/net/spdy/buffered_spdy_framer_unittest.cc
@@ -16,12 +16,10 @@ namespace {
class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface {
public:
- explicit TestBufferedSpdyVisitor(SpdyMajorVersion spdy_version)
- : buffered_spdy_framer_(spdy_version),
+ explicit TestBufferedSpdyVisitor()
+ : buffered_spdy_framer_(),
error_count_(0),
setting_count_(0),
- syn_frame_count_(0),
- syn_reply_frame_count_(0),
headers_frame_count_(0),
push_promise_frame_count_(0),
goaway_count_(0),
@@ -41,38 +39,17 @@ class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface {
error_count_++;
}
- void OnSynStream(SpdyStreamId stream_id,
- SpdyStreamId associated_stream_id,
- SpdyPriority priority,
- bool fin,
- bool unidirectional,
- const SpdyHeaderBlock& headers) override {
- header_stream_id_ = stream_id;
- EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream);
- syn_frame_count_++;
- headers_ = headers.Clone();
- }
-
- void OnSynReply(SpdyStreamId stream_id,
- bool fin,
- const SpdyHeaderBlock& headers) override {
- header_stream_id_ = stream_id;
- EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream);
- syn_reply_frame_count_++;
- headers_ = headers.Clone();
- }
-
void OnHeaders(SpdyStreamId stream_id,
bool has_priority,
int weight,
SpdyStreamId parent_stream_id,
bool exclusive,
bool fin,
- const SpdyHeaderBlock& headers) override {
+ SpdyHeaderBlock headers) override {
header_stream_id_ = stream_id;
EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream);
headers_frame_count_++;
- headers_ = headers.Clone();
+ headers_ = std::move(headers);
}
void OnDataFrameHeader(SpdyStreamId stream_id,
@@ -126,13 +103,13 @@ class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface {
void OnPushPromise(SpdyStreamId stream_id,
SpdyStreamId promised_stream_id,
- const SpdyHeaderBlock& headers) override {
+ SpdyHeaderBlock headers) override {
header_stream_id_ = stream_id;
EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream);
push_promise_frame_count_++;
promised_stream_id_ = promised_stream_id;
EXPECT_NE(promised_stream_id_, SpdyFramer::kInvalidStream);
- headers_ = headers.Clone();
+ headers_ = std::move(headers);
}
void OnAltSvc(SpdyStreamId stream_id,
@@ -174,8 +151,6 @@ class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface {
// Counters from the visitor callbacks.
int error_count_;
int setting_count_;
- int syn_frame_count_;
- int syn_reply_frame_count_;
int headers_frame_count_;
int push_promise_frame_count_;
int goaway_count_;
@@ -185,8 +160,7 @@ class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface {
SpdyStreamId header_stream_id_;
SpdyStreamId promised_stream_id_;
- // Headers from OnSyn, OnSynReply, OnHeaders and OnPushPromise for
- // verification.
+ // Headers from OnHeaders and OnPushPromise for verification.
SpdyHeaderBlock headers_;
// OnGoAway parameters.
@@ -202,27 +176,15 @@ class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface {
} // namespace
-class BufferedSpdyFramerTest
- : public PlatformTest,
- public ::testing::WithParamInterface<NextProto> {
- protected:
- SpdyMajorVersion spdy_version() {
- return NextProtoToSpdyMajorVersion(GetParam());
- }
-};
-
-INSTANTIATE_TEST_CASE_P(NextProto,
- BufferedSpdyFramerTest,
- testing::Values(kProtoSPDY31,
- kProtoHTTP2));
+class BufferedSpdyFramerTest : public PlatformTest {};
-TEST_P(BufferedSpdyFramerTest, OnSetting) {
- SpdyFramer framer(spdy_version());
+TEST_F(BufferedSpdyFramerTest, OnSetting) {
+ SpdyFramer framer(HTTP2);
SpdySettingsIR settings_ir;
settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, false, false, 2);
settings_ir.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, false, false, 3);
SpdySerializedFrame control_frame(framer.SerializeSettings(settings_ir));
- TestBufferedSpdyVisitor visitor(spdy_version());
+ TestBufferedSpdyVisitor visitor;
visitor.SimulateInFramer(
reinterpret_cast<unsigned char*>(control_frame.data()),
@@ -231,39 +193,11 @@ TEST_P(BufferedSpdyFramerTest, OnSetting) {
EXPECT_EQ(2, visitor.setting_count_);
}
-TEST_P(BufferedSpdyFramerTest, ReadSynStreamHeaderBlock) {
- if (spdy_version() > SPDY3) {
- // SYN_STREAM not supported in SPDY>3.
- return;
- }
- SpdyHeaderBlock headers;
- headers["aa"] = "vv";
- headers["bb"] = "ww";
- BufferedSpdyFramer framer(spdy_version());
- std::unique_ptr<SpdySerializedFrame> control_frame(
- framer.CreateSynStream(1, // stream_id
- 0, // associated_stream_id
- 1, // priority
- CONTROL_FLAG_NONE, headers.Clone()));
- EXPECT_TRUE(control_frame.get() != NULL);
-
- TestBufferedSpdyVisitor visitor(spdy_version());
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(control_frame.get()->data()),
- control_frame.get()->size());
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, visitor.syn_frame_count_);
- EXPECT_EQ(0, visitor.syn_reply_frame_count_);
- EXPECT_EQ(0, visitor.headers_frame_count_);
- EXPECT_EQ(0, visitor.push_promise_frame_count_);
- EXPECT_EQ(headers, visitor.headers_);
-}
-
-TEST_P(BufferedSpdyFramerTest, HeaderListTooLarge) {
+TEST_F(BufferedSpdyFramerTest, HeaderListTooLarge) {
SpdyHeaderBlock headers;
std::string long_header_value(256 * 1024, 'x');
headers["foo"] = long_header_value;
- BufferedSpdyFramer framer(spdy_version());
+ BufferedSpdyFramer framer;
std::unique_ptr<SpdySerializedFrame> control_frame(
framer.CreateHeaders(1, // stream_id
CONTROL_FLAG_NONE,
@@ -271,55 +205,22 @@ TEST_P(BufferedSpdyFramerTest, HeaderListTooLarge) {
std::move(headers)));
EXPECT_TRUE(control_frame);
- TestBufferedSpdyVisitor visitor(spdy_version());
+ TestBufferedSpdyVisitor visitor;
visitor.SimulateInFramer(
reinterpret_cast<unsigned char*>(control_frame.get()->data()),
control_frame.get()->size());
EXPECT_EQ(1, visitor.error_count_);
- EXPECT_EQ(0, visitor.syn_frame_count_);
- EXPECT_EQ(0, visitor.syn_reply_frame_count_);
EXPECT_EQ(0, visitor.headers_frame_count_);
EXPECT_EQ(0, visitor.push_promise_frame_count_);
EXPECT_EQ(SpdyHeaderBlock(), visitor.headers_);
}
-TEST_P(BufferedSpdyFramerTest, ReadSynReplyHeaderBlock) {
- if (spdy_version() > SPDY3) {
- // SYN_REPLY not supported in SPDY>3.
- return;
- }
+TEST_F(BufferedSpdyFramerTest, ReadHeadersHeaderBlock) {
SpdyHeaderBlock headers;
headers["alpha"] = "beta";
headers["gamma"] = "delta";
- BufferedSpdyFramer framer(spdy_version());
- std::unique_ptr<SpdySerializedFrame> control_frame(
- framer.CreateSynReply(1, // stream_id
- CONTROL_FLAG_NONE, headers.Clone()));
- EXPECT_TRUE(control_frame.get() != NULL);
-
- TestBufferedSpdyVisitor visitor(spdy_version());
- visitor.SimulateInFramer(
- reinterpret_cast<unsigned char*>(control_frame.get()->data()),
- control_frame.get()->size());
- EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(0, visitor.syn_frame_count_);
- EXPECT_EQ(0, visitor.push_promise_frame_count_);
- if (spdy_version() < HTTP2) {
- EXPECT_EQ(1, visitor.syn_reply_frame_count_);
- EXPECT_EQ(0, visitor.headers_frame_count_);
- } else {
- EXPECT_EQ(0, visitor.syn_reply_frame_count_);
- EXPECT_EQ(1, visitor.headers_frame_count_);
- }
- EXPECT_EQ(headers, visitor.headers_);
-}
-
-TEST_P(BufferedSpdyFramerTest, ReadHeadersHeaderBlock) {
- SpdyHeaderBlock headers;
- headers["alpha"] = "beta";
- headers["gamma"] = "delta";
- BufferedSpdyFramer framer(spdy_version());
+ BufferedSpdyFramer framer;
std::unique_ptr<SpdySerializedFrame> control_frame(
framer.CreateHeaders(1, // stream_id
CONTROL_FLAG_NONE,
@@ -327,36 +228,30 @@ TEST_P(BufferedSpdyFramerTest, ReadHeadersHeaderBlock) {
headers.Clone()));
EXPECT_TRUE(control_frame.get() != NULL);
- TestBufferedSpdyVisitor visitor(spdy_version());
+ TestBufferedSpdyVisitor visitor;
visitor.SimulateInFramer(
reinterpret_cast<unsigned char*>(control_frame.get()->data()),
control_frame.get()->size());
EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(0, visitor.syn_frame_count_);
- EXPECT_EQ(0, visitor.syn_reply_frame_count_);
EXPECT_EQ(1, visitor.headers_frame_count_);
EXPECT_EQ(0, visitor.push_promise_frame_count_);
EXPECT_EQ(headers, visitor.headers_);
}
-TEST_P(BufferedSpdyFramerTest, ReadPushPromiseHeaderBlock) {
- if (spdy_version() < HTTP2)
- return;
+TEST_F(BufferedSpdyFramerTest, ReadPushPromiseHeaderBlock) {
SpdyHeaderBlock headers;
headers["alpha"] = "beta";
headers["gamma"] = "delta";
- BufferedSpdyFramer framer(spdy_version());
+ BufferedSpdyFramer framer;
std::unique_ptr<SpdySerializedFrame> control_frame(
framer.CreatePushPromise(1, 2, headers.Clone()));
EXPECT_TRUE(control_frame.get() != NULL);
- TestBufferedSpdyVisitor visitor(spdy_version());
+ TestBufferedSpdyVisitor visitor;
visitor.SimulateInFramer(
reinterpret_cast<unsigned char*>(control_frame.get()->data()),
control_frame.get()->size());
EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(0, visitor.syn_frame_count_);
- EXPECT_EQ(0, visitor.syn_reply_frame_count_);
EXPECT_EQ(0, visitor.headers_frame_count_);
EXPECT_EQ(1, visitor.push_promise_frame_count_);
EXPECT_EQ(headers, visitor.headers_);
@@ -364,14 +259,12 @@ TEST_P(BufferedSpdyFramerTest, ReadPushPromiseHeaderBlock) {
EXPECT_EQ(2u, visitor.promised_stream_id_);
}
-TEST_P(BufferedSpdyFramerTest, GoAwayDebugData) {
- if (spdy_version() < HTTP2)
- return;
- BufferedSpdyFramer framer(spdy_version());
+TEST_F(BufferedSpdyFramerTest, GoAwayDebugData) {
+ BufferedSpdyFramer framer;
std::unique_ptr<SpdySerializedFrame> goaway_frame(
framer.CreateGoAway(2u, GOAWAY_FRAME_SIZE_ERROR, "foo"));
- TestBufferedSpdyVisitor visitor(spdy_version());
+ TestBufferedSpdyVisitor visitor;
visitor.SimulateInFramer(
reinterpret_cast<unsigned char*>(goaway_frame.get()->data()),
goaway_frame.get()->size());
@@ -382,10 +275,7 @@ TEST_P(BufferedSpdyFramerTest, GoAwayDebugData) {
EXPECT_EQ("foo", visitor.goaway_debug_data_);
}
-TEST_P(BufferedSpdyFramerTest, OnAltSvc) {
- if (spdy_version() < HTTP2)
- return;
-
+TEST_F(BufferedSpdyFramerTest, OnAltSvc) {
const SpdyStreamId altsvc_stream_id(1);
const char altsvc_origin[] = "https://www.example.org";
SpdyAltSvcIR altsvc_ir(altsvc_stream_id);
@@ -394,10 +284,10 @@ TEST_P(BufferedSpdyFramerTest, OnAltSvc) {
SpdyAltSvcWireFormat::VersionVector());
altsvc_ir.add_altsvc(alternative_service);
altsvc_ir.set_origin(altsvc_origin);
- BufferedSpdyFramer framer(spdy_version());
+ BufferedSpdyFramer framer;
SpdySerializedFrame altsvc_frame(framer.SerializeFrame(altsvc_ir));
- TestBufferedSpdyVisitor visitor(spdy_version());
+ TestBufferedSpdyVisitor visitor;
visitor.SimulateInFramer(
reinterpret_cast<unsigned char*>(altsvc_frame.data()),
altsvc_frame.size());
diff --git a/chromium/net/spdy/header_coalescer.cc b/chromium/net/spdy/header_coalescer.cc
index d4faa4fc056..199fabf445c 100644
--- a/chromium/net/spdy/header_coalescer.cc
+++ b/chromium/net/spdy/header_coalescer.cc
@@ -4,6 +4,8 @@
#include "net/spdy/header_coalescer.h"
+#include <utility>
+
#include "base/strings/string_util.h"
namespace net {
@@ -29,7 +31,7 @@ void HeaderCoalescer::OnHeader(base::StringPiece key, base::StringPiece value) {
}
if (key[0] == ':') {
- if (protocol_version_ == HTTP2 && regular_header_seen_) {
+ if (regular_header_seen_) {
error_seen_ = true;
return;
}
@@ -37,6 +39,13 @@ void HeaderCoalescer::OnHeader(base::StringPiece key, base::StringPiece value) {
regular_header_seen_ = true;
}
+ // End of line delimiter is forbidden according to RFC 7230 Section 3.2.
+ // Line folding, RFC 7230 Section 3.2.4., is a special case of this.
+ if (value.find("\r\n") != base::StringPiece::npos) {
+ error_seen_ = true;
+ return;
+ }
+
auto iter = headers_.find(key);
if (iter == headers_.end()) {
headers_[key] = value;
@@ -55,4 +64,10 @@ void HeaderCoalescer::OnHeader(base::StringPiece key, base::StringPiece value) {
}
}
+SpdyHeaderBlock HeaderCoalescer::release_headers() {
+ DCHECK(headers_valid_);
+ headers_valid_ = false;
+ return std::move(headers_);
+}
+
} // namespace net
diff --git a/chromium/net/spdy/header_coalescer.h b/chromium/net/spdy/header_coalescer.h
index 07cd3889a34..fe30a2896a9 100644
--- a/chromium/net/spdy/header_coalescer.h
+++ b/chromium/net/spdy/header_coalescer.h
@@ -8,30 +8,30 @@
#include "net/base/net_export.h"
#include "net/spdy/spdy_header_block.h"
#include "net/spdy/spdy_headers_handler_interface.h"
-#include "net/spdy/spdy_protocol.h"
namespace net {
class NET_EXPORT_PRIVATE HeaderCoalescer : public SpdyHeadersHandlerInterface {
public:
- explicit HeaderCoalescer(const SpdyMajorVersion& protocol_version)
- : protocol_version_(protocol_version) {}
+ HeaderCoalescer() {}
void OnHeaderBlockStart() override {}
void OnHeader(base::StringPiece key, base::StringPiece value) override;
void OnHeaderBlockEnd(size_t uncompressed_header_bytes) override {}
+ void OnHeaderBlockEnd(size_t uncompressed_header_bytes,
+ size_t compressed_header_bytes) override {}
- const SpdyHeaderBlock& headers() const { return headers_; }
+ SpdyHeaderBlock release_headers();
bool error_seen() const { return error_seen_; }
private:
SpdyHeaderBlock headers_;
+ bool headers_valid_ = true;
size_t header_list_size_ = 0;
bool error_seen_ = false;
bool regular_header_seen_ = false;
- SpdyMajorVersion protocol_version_;
};
} // namespace net
diff --git a/chromium/net/spdy/header_coalescer_test.cc b/chromium/net/spdy/header_coalescer_test.cc
new file mode 100644
index 00000000000..986e7753210
--- /dev/null
+++ b/chromium/net/spdy/header_coalescer_test.cc
@@ -0,0 +1,80 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "header_coalescer.h"
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::ElementsAre;
+using ::testing::Pair;
+
+namespace net {
+namespace test {
+
+class HeaderCoalescerTest : public ::testing::Test {
+ public:
+ protected:
+ HeaderCoalescer header_coalescer_;
+};
+
+TEST_F(HeaderCoalescerTest, CorrectHeaders) {
+ header_coalescer_.OnHeader(":foo", "bar");
+ header_coalescer_.OnHeader("baz", "qux");
+ EXPECT_FALSE(header_coalescer_.error_seen());
+
+ SpdyHeaderBlock header_block = header_coalescer_.release_headers();
+ EXPECT_THAT(header_block,
+ ElementsAre(Pair(":foo", "bar"), Pair("baz", "qux")));
+}
+
+TEST_F(HeaderCoalescerTest, EmptyHeaderKey) {
+ EXPECT_FALSE(header_coalescer_.error_seen());
+ header_coalescer_.OnHeader("", "foo");
+ EXPECT_TRUE(header_coalescer_.error_seen());
+}
+
+TEST_F(HeaderCoalescerTest, HeaderBlockTooLarge) {
+ // 3 byte key, 256 * 1024 - 40 byte value, 32 byte overhead:
+ // less than 256 * 1024 bytes in total.
+ std::string data(256 * 1024 - 40, 'a');
+ header_coalescer_.OnHeader("foo", data);
+ EXPECT_FALSE(header_coalescer_.error_seen());
+
+ // Another 3 + 3 + 32 bytes: too large.
+ header_coalescer_.OnHeader("bar", "baz");
+ EXPECT_TRUE(header_coalescer_.error_seen());
+}
+
+TEST_F(HeaderCoalescerTest, PseudoHeadersMustNotFollowRegularHeaders) {
+ header_coalescer_.OnHeader("foo", "bar");
+ EXPECT_FALSE(header_coalescer_.error_seen());
+ header_coalescer_.OnHeader(":baz", "qux");
+ EXPECT_TRUE(header_coalescer_.error_seen());
+}
+
+TEST_F(HeaderCoalescerTest, Append) {
+ header_coalescer_.OnHeader("foo", "bar");
+ header_coalescer_.OnHeader("cookie", "baz");
+ header_coalescer_.OnHeader("foo", "quux");
+ header_coalescer_.OnHeader("cookie", "qux");
+ EXPECT_FALSE(header_coalescer_.error_seen());
+
+ SpdyHeaderBlock header_block = header_coalescer_.release_headers();
+ EXPECT_THAT(header_block,
+ ElementsAre(Pair("foo", base::StringPiece("bar\0quux", 8)),
+ Pair("cookie", "baz; qux")));
+}
+
+TEST_F(HeaderCoalescerTest, CRLFInHeaderValue) {
+ EXPECT_FALSE(header_coalescer_.error_seen());
+ header_coalescer_.OnHeader("foo", "bar\r\nbaz");
+ EXPECT_TRUE(header_coalescer_.error_seen());
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/spdy/hpack/hpack_constants.h b/chromium/net/spdy/hpack/hpack_constants.h
index 27799aeeb1d..8718ffe0629 100644
--- a/chromium/net/spdy/hpack/hpack_constants.h
+++ b/chromium/net/spdy/hpack/hpack_constants.h
@@ -46,12 +46,6 @@ class HpackStaticTable;
// Defined in RFC 7540 section 6.5.2.
const uint32_t kDefaultHeaderTableSizeSetting = 4096;
-// Maximum amount of encoded header buffer HpackDecoder will retain before
-// returning an error.
-// TODO(rjshade): Remove when deprecating
-// FLAGS_chromium_http2_flag_remove_hpack_decode_buffer_size_limit.
-const uint32_t kMaxDecodeBufferSize = 256 * 1024;
-
// 6.2: Flag for a string literal that is stored unmodified (i.e.,
// without Huffman encoding).
const HpackPrefix kStringLiteralIdentityEncoded = {0x0, 1};
diff --git a/chromium/net/spdy/hpack/hpack_decoder.cc b/chromium/net/spdy/hpack/hpack_decoder.cc
index 1352dc3517b..16c7918e6ac 100644
--- a/chromium/net/spdy/hpack/hpack_decoder.cc
+++ b/chromium/net/spdy/hpack/hpack_decoder.cc
@@ -8,24 +8,19 @@
#include "base/logging.h"
#include "net/spdy/hpack/hpack_constants.h"
-#include "net/spdy/hpack/hpack_output_stream.h"
+#include "net/spdy/hpack/hpack_entry.h"
+#include "net/spdy/spdy_flags.h"
namespace net {
using base::StringPiece;
using std::string;
-namespace {
-
-const char kCookieKey[] = "cookie";
-
-} // namespace
-
HpackDecoder::HpackDecoder()
: handler_(nullptr),
total_header_bytes_(0),
- header_block_started_(false),
- total_parsed_bytes_(0) {}
+ total_parsed_bytes_(0),
+ header_block_started_(false) {}
HpackDecoder::~HpackDecoder() {}
@@ -43,6 +38,9 @@ bool HpackDecoder::HandleControlFrameHeadersData(const char* headers_data,
size_t headers_data_length) {
if (!header_block_started_) {
decoded_block_.clear();
+ header_block_started_ = true;
+ size_updates_allowed_ = true;
+ size_updates_seen_ = 0;
if (handler_ != nullptr) {
handler_->OnHeaderBlockStart();
}
@@ -50,27 +48,22 @@ bool HpackDecoder::HandleControlFrameHeadersData(const char* headers_data,
size_t new_size = headers_block_buffer_.size() + headers_data_length;
if (max_decode_buffer_size_bytes_ > 0 &&
new_size > max_decode_buffer_size_bytes_) {
+ DVLOG(1) << "max_decode_buffer_size_bytes_ < new_size: "
+ << max_decode_buffer_size_bytes_ << " < " << new_size;
return false;
}
headers_block_buffer_.insert(headers_block_buffer_.end(), headers_data,
headers_data + headers_data_length);
- // Parse as many data in buffer as possible. And remove the parsed data
- // from buffer.
+ // Parse as many whole HPACK entries in the buffer as possible,
+ // and then remove the parsed data from the buffer.
HpackInputStream input_stream(headers_block_buffer_);
-
- // If this is the start of the header block, process table size updates.
- if (!header_block_started_) {
- if (!DecodeAtMostTwoHeaderTableSizeUpdates(&input_stream)) {
- return false;
- }
- input_stream.MarkCurrentPosition();
- }
while (input_stream.HasMoreData()) {
if (!DecodeNextOpcodeWrapper(&input_stream)) {
if (input_stream.NeedMoreData()) {
break;
}
+ DVLOG(1) << "!DecodeNextOpcodeWrapper";
return false;
}
}
@@ -78,7 +71,7 @@ bool HpackDecoder::HandleControlFrameHeadersData(const char* headers_data,
DCHECK_GE(headers_block_buffer_.size(), parsed_bytes);
headers_block_buffer_.erase(0, parsed_bytes);
total_parsed_bytes_ += parsed_bytes;
- header_block_started_ = true;
+
return true;
}
@@ -90,11 +83,17 @@ bool HpackDecoder::HandleControlFrameHeadersComplete(size_t* compressed_len) {
// Data in headers_block_buffer_ should have been parsed by
// HandleControlFrameHeadersData and removed.
if (headers_block_buffer_.size() > 0) {
+ DVLOG(1) << "headers_block_buffer_.size() should be zero, but is "
+ << headers_block_buffer_.size();
return false;
}
if (handler_ != nullptr) {
- handler_->OnHeaderBlockEnd(total_header_bytes_);
+ if (FLAGS_chromium_http2_flag_log_compressed_size) {
+ handler_->OnHeaderBlockEnd(total_header_bytes_, total_parsed_bytes_);
+ } else {
+ handler_->OnHeaderBlockEnd(total_header_bytes_);
+ }
}
headers_block_buffer_.clear();
total_parsed_bytes_ = 0;
@@ -103,7 +102,7 @@ bool HpackDecoder::HandleControlFrameHeadersComplete(size_t* compressed_len) {
return true;
}
-const SpdyHeaderBlock& HpackDecoder::decoded_block() {
+const SpdyHeaderBlock& HpackDecoder::decoded_block() const {
return decoded_block_;
}
@@ -119,20 +118,11 @@ void HpackDecoder::set_max_decode_buffer_size_bytes(
bool HpackDecoder::HandleHeaderRepresentation(StringPiece name,
StringPiece value) {
+ size_updates_allowed_ = false;
total_header_bytes_ += name.size() + value.size();
if (handler_ == nullptr) {
- auto it = decoded_block_.find(name);
- if (it == decoded_block_.end()) {
- // This is a new key.
- decoded_block_[name] = value;
- } else {
- // The key already exists, append |value| with appropriate delimiter.
- string new_value = it->second.as_string();
- new_value.append((name == kCookieKey) ? "; " : string(1, '\0'));
- value.AppendToString(&new_value);
- decoded_block_.ReplaceOrAppendHeader(name, new_value);
- }
+ decoded_block_.AppendValueOrAddHeader(name, value);
} else {
DCHECK(decoded_block_.empty());
handler_->OnHeader(name, value);
@@ -170,42 +160,30 @@ bool HpackDecoder::DecodeNextOpcode(HpackInputStream* input_stream) {
// Implements 7.3: Header Table Size Update.
if (input_stream->MatchPrefixAndConsume(kHeaderTableSizeUpdateOpcode)) {
// Header table size updates cannot appear mid-block.
- return false;
+ return DecodeNextHeaderTableSizeUpdate(input_stream);
}
// Unrecognized opcode.
return false;
}
-// Process 0, 1, or 2 Table Size Updates.
-bool HpackDecoder::DecodeAtMostTwoHeaderTableSizeUpdates(
- HpackInputStream* input_stream) {
- // Implements 7.3: Header Table Size Update.
- if (input_stream->HasMoreData() &&
- input_stream->MatchPrefixAndConsume(kHeaderTableSizeUpdateOpcode)) {
- // One table size update, decode it.
- if (DecodeNextHeaderTableSizeUpdate(input_stream)) {
- // Check for a second table size update.
- if (input_stream->HasMoreData() &&
- input_stream->MatchPrefixAndConsume(kHeaderTableSizeUpdateOpcode)) {
- // Second update found, return the result of decode.
- return DecodeNextHeaderTableSizeUpdate(input_stream);
- }
- } else {
- // Decoding the first table size update failed.
- return false;
- }
- }
- // No table size updates in this block.
- return true;
-}
-
bool HpackDecoder::DecodeNextHeaderTableSizeUpdate(
HpackInputStream* input_stream) {
uint32_t size = 0;
if (!input_stream->DecodeNextUint32(&size)) {
return false;
}
+ if (!size_updates_allowed_) {
+ DVLOG(1) << "Size updates not allowed after header entries.";
+ return false;
+ }
+ ++size_updates_seen_;
+ if (size_updates_seen_ > 2) {
+ DVLOG(1) << "Too many size updates at the start of the block.";
+ return false;
+ }
if (size > header_table_.settings_size_bound()) {
+ DVLOG(1) << "Size (" << size << ") exceeds SETTINGS limit ("
+ << header_table_.settings_size_bound() << ")";
return false;
}
header_table_.SetMaxSize(size);
@@ -220,6 +198,7 @@ bool HpackDecoder::DecodeNextIndexedHeader(HpackInputStream* input_stream) {
const HpackEntry* entry = header_table_.GetByIndex(index);
if (entry == NULL) {
+ DVLOG(1) << "Index " << index << " is not valid.";
return false;
}
@@ -263,6 +242,7 @@ bool HpackDecoder::DecodeNextName(HpackInputStream* input_stream,
const HpackEntry* entry = header_table_.GetByIndex(index_or_zero);
if (entry == NULL) {
+ DVLOG(1) << "index " << index_or_zero << " is not valid.";
return false;
}
if (entry->IsStatic()) {
diff --git a/chromium/net/spdy/hpack/hpack_decoder.h b/chromium/net/spdy/hpack/hpack_decoder.h
index 6af2721a9d9..172892ffa50 100644
--- a/chromium/net/spdy/hpack/hpack_decoder.h
+++ b/chromium/net/spdy/hpack/hpack_decoder.h
@@ -2,13 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_SPDY_HPACK_DECODER_H_
-#define NET_SPDY_HPACK_DECODER_H_
+#ifndef NET_SPDY_HPACK_HPACK_DECODER_H_
+#define NET_SPDY_HPACK_HPACK_DECODER_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
+#include <memory>
#include <string>
#include <vector>
@@ -37,7 +38,7 @@ class NET_EXPORT_PRIVATE HpackDecoder : public HpackDecoderInterface {
HpackDecoder();
~HpackDecoder() override;
- // Called upon acknowledgement of SETTINGS_HEADER_TABLE_SIZE.
+ // Called upon sending a SETTINGS_HEADER_TABLE_SIZE value.
void ApplyHeaderTableSizeSetting(size_t size_setting) override;
// If a SpdyHeadersHandlerInterface is provided, HpackDecoder will emit
@@ -68,7 +69,7 @@ class NET_EXPORT_PRIVATE HpackDecoder : public HpackDecoderInterface {
// call to HandleControlFrameHeadersData().
// TODO(birenroy): Remove this method when all users of HpackDecoder specify
// a SpdyHeadersHandlerInterface.
- const SpdyHeaderBlock& decoded_block() override;
+ const SpdyHeaderBlock& decoded_block() const override;
void SetHeaderTableDebugVisitor(
std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor)
@@ -94,6 +95,21 @@ class NET_EXPORT_PRIVATE HpackDecoder : public HpackDecoderInterface {
bool HandleHeaderRepresentation(base::StringPiece name,
base::StringPiece value);
+ // Handlers for decoding HPACK opcodes and header representations
+ // (or parts thereof). These methods return true on success and
+ // false on error.
+ bool DecodeNextOpcodeWrapper(HpackInputStream* input_stream);
+ bool DecodeNextOpcode(HpackInputStream* input_stream);
+ bool DecodeNextHeaderTableSizeUpdate(HpackInputStream* input_stream);
+ bool DecodeNextIndexedHeader(HpackInputStream* input_stream);
+ bool DecodeNextLiteralHeader(HpackInputStream* input_stream,
+ bool should_index);
+ bool DecodeNextName(HpackInputStream* input_stream,
+ base::StringPiece* next_name);
+ bool DecodeNextStringLiteral(HpackInputStream* input_stream,
+ bool is_header_key, // As distinct from a value.
+ base::StringPiece* output);
+
HpackHeaderTable header_table_;
// TODO(jgraettinger): Buffer for headers data, and storage for the last-
@@ -109,36 +125,30 @@ class NET_EXPORT_PRIVATE HpackDecoder : public HpackDecoderInterface {
SpdyHeadersHandlerInterface* handler_;
size_t total_header_bytes_;
- // Flag to keep track of having seen the header block start.
- bool header_block_started_;
+ // How much encoded data this decoder is willing to buffer.
+ size_t max_decode_buffer_size_bytes_ = 32 * 1024; // 32 KB
// Total bytes have been removed from headers_block_buffer_.
// Its value is updated during incremental decoding.
uint32_t total_parsed_bytes_;
- // How much encoded data this decoder is willing to buffer.
- // Defaults to 256 KB.
- size_t max_decode_buffer_size_bytes_ = kMaxDecodeBufferSize;
+ // Flag to keep track of having seen the header block start.
+ bool header_block_started_;
- // Handlers for decoding HPACK opcodes and header representations
- // (or parts thereof). These methods return true on success and
- // false on error.
- bool DecodeNextOpcodeWrapper(HpackInputStream* input_stream);
- bool DecodeNextOpcode(HpackInputStream* input_stream);
- bool DecodeAtMostTwoHeaderTableSizeUpdates(HpackInputStream* input_stream);
- bool DecodeNextHeaderTableSizeUpdate(HpackInputStream* input_stream);
- bool DecodeNextIndexedHeader(HpackInputStream* input_stream);
- bool DecodeNextLiteralHeader(HpackInputStream* input_stream,
- bool should_index);
- bool DecodeNextName(HpackInputStream* input_stream,
- base::StringPiece* next_name);
- bool DecodeNextStringLiteral(HpackInputStream* input_stream,
- bool is_header_key, // As distinct from a value.
- base::StringPiece* output);
+ // Number of dynamic table size updates seen at the start; a max of two
+ // are permitted.
+ uint8_t size_updates_seen_;
+
+ // Are dynamic table size updates allowed at this point in decoding? True
+ // at the start, but not once we've seen a header entry.
+ bool size_updates_allowed_;
+
+ // Saved value of --gfe2_reloadable_flag_add_hpack_incremental_decode.
+ bool incremental_decode_;
DISALLOW_COPY_AND_ASSIGN(HpackDecoder);
};
} // namespace net
-#endif // NET_SPDY_HPACK_DECODER_H_
+#endif // NET_SPDY_HPACK_HPACK_DECODER_H_
diff --git a/chromium/net/spdy/hpack/hpack_decoder_interface.h b/chromium/net/spdy/hpack/hpack_decoder_interface.h
index 1a7cdd7c9b6..dfc6f82caaf 100644
--- a/chromium/net/spdy/hpack/hpack_decoder_interface.h
+++ b/chromium/net/spdy/hpack/hpack_decoder_interface.h
@@ -51,14 +51,12 @@ class NET_EXPORT_PRIVATE HpackDecoderInterface {
// call to HandleControlFrameHeadersData().
// TODO(birenroy): Remove this method when all users of HpackDecoder specify
// a SpdyHeadersHandlerInterface.
- virtual const SpdyHeaderBlock& decoded_block() = 0;
+ virtual const SpdyHeaderBlock& decoded_block() const = 0;
virtual void SetHeaderTableDebugVisitor(
std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) = 0;
- // How much encoded data this decoder is willing to buffer. Defaults to 32 KB.
- // See FLAGS_gfe2_reloadable_flag_remove_hpack_decode_buffer_size_limit, which
- // is increasing this to twice the decoded limit.
+ // Set how much encoded data this decoder is willing to buffer.
virtual void set_max_decode_buffer_size_bytes(
size_t max_decode_buffer_size_bytes) = 0;
};
diff --git a/chromium/net/spdy/hpack/hpack_decoder_test.cc b/chromium/net/spdy/hpack/hpack_decoder_test.cc
index 8657a354ca4..b6bbcbe2740 100644
--- a/chromium/net/spdy/hpack/hpack_decoder_test.cc
+++ b/chromium/net/spdy/hpack/hpack_decoder_test.cc
@@ -35,9 +35,6 @@ class HpackDecoderPeer {
return decoder_->DecodeNextName(in, out);
}
HpackHeaderTable* header_table() { return &decoder_->header_table_; }
- const SpdyHeaderBlock& decoded_block() const {
- return decoder_->decoded_block_;
- }
bool DecodeNextStringLiteral(HpackInputStream* in,
bool is_header_key,
@@ -88,7 +85,7 @@ class HpackDecoderTest : public ::testing::TestWithParam<bool> {
if (handler_exists_) {
return handler_.decoded_block();
} else {
- return decoder_peer_.decoded_block();
+ return decoder_.decoded_block();
}
}
@@ -138,11 +135,7 @@ TEST_P(HpackDecoderTest, AddHeaderDataWithHandleControlFrameHeadersData) {
second_input.size()));
// A string which would push the buffer over the threshold is refused.
const int kThirdInputSize =
- ((FLAGS_chromium_http2_flag_remove_hpack_decode_buffer_size_limit
- ? kMaxBufferSizeBytes
- : kMaxDecodeBufferSize) -
- (first_input.size() + second_input.size())) +
- 1;
+ kMaxBufferSizeBytes - (first_input.size() + second_input.size()) + 1;
string third_input = string(kThirdInputSize, 'y');
ASSERT_GT(first_input.size() + second_input.size() + third_input.size(),
kMaxBufferSizeBytes);
diff --git a/chromium/net/spdy/hpack/hpack_encoder.cc b/chromium/net/spdy/hpack/hpack_encoder.cc
index 59198a7c5e9..7362bb1acc6 100644
--- a/chromium/net/spdy/hpack/hpack_encoder.cc
+++ b/chromium/net/spdy/hpack/hpack_encoder.cc
@@ -8,6 +8,7 @@
#include <limits>
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "net/spdy/hpack/hpack_constants.h"
#include "net/spdy/hpack/hpack_header_table.h"
#include "net/spdy/hpack/hpack_huffman_table.h"
@@ -18,18 +19,82 @@ namespace net {
using base::StringPiece;
using std::string;
+class HpackEncoder::RepresentationIterator {
+ public:
+ // |pseudo_headers| and |regular_headers| must outlive the iterator.
+ RepresentationIterator(const Representations& pseudo_headers,
+ const Representations& regular_headers)
+ : pseudo_begin_(pseudo_headers.begin()),
+ pseudo_end_(pseudo_headers.end()),
+ regular_begin_(regular_headers.begin()),
+ regular_end_(regular_headers.end()) {}
+
+ // |headers| must outlive the iterator.
+ explicit RepresentationIterator(const Representations& headers)
+ : pseudo_begin_(headers.begin()),
+ pseudo_end_(headers.end()),
+ regular_begin_(headers.end()),
+ regular_end_(headers.end()) {}
+
+ bool HasNext() {
+ return pseudo_begin_ != pseudo_end_ || regular_begin_ != regular_end_;
+ }
+
+ const Representation Next() {
+ if (pseudo_begin_ != pseudo_end_) {
+ return *pseudo_begin_++;
+ } else {
+ return *regular_begin_++;
+ }
+ }
+
+ private:
+ Representations::const_iterator pseudo_begin_;
+ Representations::const_iterator pseudo_end_;
+ Representations::const_iterator regular_begin_;
+ Representations::const_iterator regular_end_;
+};
+
+namespace {
+
+// The default header listener.
+void NoOpListener(StringPiece /*name*/, StringPiece /*value*/) {}
+
+// The default HPACK indexing policy.
+bool DefaultPolicy(StringPiece name, StringPiece /* value */) {
+ if (name.empty()) {
+ return false;
+ }
+ // :authority is always present and rarely changes, and has moderate
+ // length, therefore it makes a lot of sense to index (insert in the
+ // dynamic table).
+ if (name[0] == kPseudoHeaderPrefix) {
+ return name == ":authority";
+ }
+ return true;
+}
+
+} // namespace
+
HpackEncoder::HpackEncoder(const HpackHuffmanTable& table)
: output_stream_(),
huffman_table_(table),
min_table_size_setting_received_(std::numeric_limits<size_t>::max()),
+ listener_(NoOpListener),
+ should_index_(DefaultPolicy),
allow_huffman_compression_(true),
should_emit_table_size_(false) {}
HpackEncoder::~HpackEncoder() {}
+void HpackEncoder::EncodeHeaderSet(const Representations& representations,
+ string* output) {
+ RepresentationIterator iter(representations);
+ EncodeRepresentations(&iter, output);
+}
+
bool HpackEncoder::EncodeHeaderSet(const SpdyHeaderBlock& header_set,
string* output) {
- MaybeEmitTableSize();
// Separate header set into pseudo-headers and regular headers.
Representations pseudo_headers;
Representations regular_headers;
@@ -48,42 +113,10 @@ bool HpackEncoder::EncodeHeaderSet(const SpdyHeaderBlock& header_set,
}
}
- // Encode pseudo-headers.
- bool found_authority = false;
- for (const auto& header : pseudo_headers) {
- const HpackEntry* entry =
- header_table_.GetByNameAndValue(header.first, header.second);
- if (entry != NULL) {
- EmitIndex(entry);
- } else {
- // :authority is always present and rarely changes, and has moderate
- // length, therefore it makes a lot of sense to index (insert in the
- // header table).
- if (!found_authority && header.first == ":authority") {
- // Note that there can only be one ":authority" header, because
- // |header_set| is a map.
- found_authority = true;
- EmitIndexedLiteral(header);
- } else {
- // Most common pseudo-header fields are represented in the static table,
- // while uncommon ones are small, so do not index them.
- EmitNonIndexedLiteral(header);
- }
- }
+ {
+ RepresentationIterator iter(pseudo_headers, regular_headers);
+ EncodeRepresentations(&iter, output);
}
-
- // Encode regular headers.
- for (const auto& header : regular_headers) {
- const HpackEntry* entry =
- header_table_.GetByNameAndValue(header.first, header.second);
- if (entry != NULL) {
- EmitIndex(entry);
- } else {
- EmitIndexedLiteral(header);
- }
- }
-
- output_stream_.TakeString(output);
return true;
}
@@ -93,6 +126,7 @@ bool HpackEncoder::EncodeHeaderSetWithoutCompression(
allow_huffman_compression_ = false;
MaybeEmitTableSize();
for (const auto& header : header_set) {
+ listener_(header.first, header.second);
// Note that cookies are not crumbled in this case.
EmitNonIndexedLiteral(header);
}
@@ -113,6 +147,26 @@ void HpackEncoder::ApplyHeaderTableSizeSetting(size_t size_setting) {
should_emit_table_size_ = true;
}
+void HpackEncoder::EncodeRepresentations(RepresentationIterator* iter,
+ string* output) {
+ MaybeEmitTableSize();
+ while (iter->HasNext()) {
+ const auto header = iter->Next();
+ listener_(header.first, header.second);
+ const HpackEntry* entry =
+ header_table_.GetByNameAndValue(header.first, header.second);
+ if (entry != nullptr) {
+ EmitIndex(entry);
+ } else if (should_index_(header.first, header.second)) {
+ EmitIndexedLiteral(header);
+ } else {
+ EmitNonIndexedLiteral(header);
+ }
+ }
+
+ output_stream_.TakeString(output);
+}
+
void HpackEncoder::EmitIndex(const HpackEntry* entry) {
output_stream_.AppendPrefix(kIndexedOpcode);
output_stream_.AppendUint32(header_table_.IndexOf(entry));
@@ -133,7 +187,7 @@ void HpackEncoder::EmitNonIndexedLiteral(const Representation& representation) {
void HpackEncoder::EmitLiteral(const Representation& representation) {
const HpackEntry* name_entry = header_table_.GetByName(representation.first);
- if (name_entry != NULL) {
+ if (name_entry != nullptr) {
output_stream_.AppendUint32(header_table_.IndexOf(name_entry));
} else {
output_stream_.AppendUint32(0);
@@ -162,6 +216,9 @@ void HpackEncoder::MaybeEmitTableSize() {
return;
}
const size_t current_size = CurrentHeaderTableSizeSetting();
+ DVLOG(1) << "MaybeEmitTableSize current_size=" << current_size;
+ DVLOG(1) << "MaybeEmitTableSize min_table_size_setting_received_="
+ << min_table_size_setting_received_;
if (min_table_size_setting_received_ < current_size) {
output_stream_.AppendPrefix(kHeaderTableSizeUpdateOpcode);
output_stream_.AppendUint32(min_table_size_setting_received_);
@@ -183,7 +240,7 @@ void HpackEncoder::CookieToCrumbs(const Representation& cookie,
StringPiece::size_type first = cookie_value.find_first_not_of(" \t");
StringPiece::size_type last = cookie_value.find_last_not_of(" \t");
if (first == StringPiece::npos) {
- cookie_value.clear();
+ cookie_value = StringPiece();
} else {
cookie_value = cookie_value.substr(first, (last - first) + 1);
}
@@ -220,4 +277,101 @@ void HpackEncoder::DecomposeRepresentation(const Representation& header_field,
}
}
+// static
+void HpackEncoder::GatherRepresentation(const Representation& header_field,
+ Representations* out) {
+ out->push_back(std::make_pair(header_field.first, header_field.second));
+}
+
+// Iteratively encodes a SpdyHeaderBlock.
+class HpackEncoder::Encoderator : public ProgressiveEncoder {
+ public:
+ Encoderator(const SpdyHeaderBlock& header_set,
+ HpackEncoder* encoder,
+ bool use_compression);
+
+ // Encoderator is neither copyable nor movable.
+ Encoderator(const Encoderator&) = delete;
+ Encoderator& operator=(const Encoderator&) = delete;
+
+ // Returns true iff more remains to encode.
+ bool HasNext() const override { return has_next_; }
+
+ // Encodes up to max_encoded_bytes of the current header block into the
+ // given output string.
+ void Next(size_t max_encoded_bytes, string* output) override;
+
+ private:
+ HpackEncoder* encoder_;
+ std::unique_ptr<RepresentationIterator> header_it_;
+ Representations pseudo_headers_;
+ Representations regular_headers_;
+ bool has_next_;
+ bool use_compression_;
+};
+
+HpackEncoder::Encoderator::Encoderator(const SpdyHeaderBlock& header_set,
+ HpackEncoder* encoder,
+ bool use_compression)
+ : encoder_(encoder), has_next_(true), use_compression_(use_compression) {
+ // Separate header set into pseudo-headers and regular headers.
+ bool found_cookie = false;
+ for (const auto& header : header_set) {
+ if (!found_cookie && header.first == "cookie") {
+ // Note that there can only be one "cookie" header, because header_set
+ // is a map.
+ found_cookie = true;
+ use_compression_ ? CookieToCrumbs(header, &regular_headers_)
+ : GatherRepresentation(header, &regular_headers_);
+ } else if (!header.first.empty() &&
+ header.first[0] == kPseudoHeaderPrefix) {
+ use_compression_ ? DecomposeRepresentation(header, &pseudo_headers_)
+ : GatherRepresentation(header, &pseudo_headers_);
+ } else {
+ use_compression_ ? DecomposeRepresentation(header, &regular_headers_)
+ : GatherRepresentation(header, &regular_headers_);
+ }
+ }
+ header_it_ = base::MakeUnique<RepresentationIterator>(pseudo_headers_,
+ regular_headers_);
+
+ encoder_->MaybeEmitTableSize();
+}
+
+void HpackEncoder::Encoderator::Next(size_t max_encoded_bytes, string* output) {
+ SPDY_BUG_IF(!has_next_)
+ << "Encoderator::Next called with nothing left to encode.";
+
+ // Encode up to max_encoded_bytes of headers.
+ while (header_it_->HasNext() &&
+ encoder_->output_stream_.size() <= max_encoded_bytes) {
+ const Representation header = header_it_->Next();
+ encoder_->listener_(header.first, header.second);
+ if (use_compression_) {
+ const HpackEntry* entry = encoder_->header_table_.GetByNameAndValue(
+ header.first, header.second);
+ if (entry != nullptr) {
+ encoder_->EmitIndex(entry);
+ } else if (encoder_->should_index_(header.first, header.second)) {
+ encoder_->EmitIndexedLiteral(header);
+ } else {
+ encoder_->EmitNonIndexedLiteral(header);
+ }
+ } else {
+ encoder_->allow_huffman_compression_ = false;
+ encoder_->EmitNonIndexedLiteral(header);
+ encoder_->allow_huffman_compression_ = true;
+ }
+ }
+
+ has_next_ = encoder_->output_stream_.size() > max_encoded_bytes;
+ encoder_->output_stream_.BoundedTakeString(max_encoded_bytes, output);
+}
+
+std::unique_ptr<HpackEncoder::ProgressiveEncoder> HpackEncoder::EncodeHeaderSet(
+ const SpdyHeaderBlock& header_set,
+ bool use_compression) {
+ return base::MakeUnique<Encoderator>(header_set, this, use_compression);
+}
+
} // namespace net
diff --git a/chromium/net/spdy/hpack/hpack_encoder.h b/chromium/net/spdy/hpack/hpack_encoder.h
index cfa6e0853eb..b2778afedbe 100644
--- a/chromium/net/spdy/hpack/hpack_encoder.h
+++ b/chromium/net/spdy/hpack/hpack_encoder.h
@@ -2,12 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_SPDY_HPACK_ENCODER_H_
-#define NET_SPDY_HPACK_ENCODER_H_
+#ifndef NET_SPDY_HPACK_HPACK_ENCODER_H_
+#define NET_SPDY_HPACK_HPACK_ENCODER_H_
#include <stddef.h>
+#include <functional>
#include <map>
+#include <memory>
#include <string>
#include <utility>
#include <vector>
@@ -32,13 +34,28 @@ class HpackEncoderPeer;
class NET_EXPORT_PRIVATE HpackEncoder {
public:
- friend class test::HpackEncoderPeer;
+ using Representation = std::pair<base::StringPiece, base::StringPiece>;
+ using Representations = std::vector<Representation>;
+
+ // Callers may provide a HeaderListener to be informed of header name-value
+ // pairs processed by this encoder.
+ typedef std::function<void(base::StringPiece, base::StringPiece)>
+ HeaderListener;
+
+ // An indexing policy should return true if the provided header name-value
+ // pair should be inserted into the HPACK dynamic table.
+ using IndexingPolicy =
+ std::function<bool(base::StringPiece, base::StringPiece)>;
// |table| is an initialized HPACK Huffman table, having an
// externally-managed lifetime which spans beyond HpackEncoder.
explicit HpackEncoder(const HpackHuffmanTable& table);
~HpackEncoder();
+ // Encodes a sequence of Representations into the given string.
+ void EncodeHeaderSet(const Representations& representations,
+ std::string* output);
+
// Encodes the given header set into the given string. Returns
// whether or not the encoding was successful.
bool EncodeHeaderSet(const SpdyHeaderBlock& header_set, std::string* output);
@@ -49,6 +66,24 @@ class NET_EXPORT_PRIVATE HpackEncoder {
bool EncodeHeaderSetWithoutCompression(const SpdyHeaderBlock& header_set,
std::string* output);
+ class NET_EXPORT_PRIVATE ProgressiveEncoder {
+ public:
+ virtual ~ProgressiveEncoder() {}
+
+ // Returns true iff more remains to encode.
+ virtual bool HasNext() const = 0;
+
+ // Encodes up to max_encoded_bytes of the current header block into the
+ // given output string.
+ virtual void Next(size_t max_encoded_bytes, std::string* output) = 0;
+ };
+
+ // Returns a ProgressiveEncoder which must be outlived by both the given
+ // SpdyHeaderBlock and this object.
+ std::unique_ptr<ProgressiveEncoder> EncodeHeaderSet(
+ const SpdyHeaderBlock& header_set,
+ bool use_compression);
+
// Called upon a change to SETTINGS_HEADER_TABLE_SIZE. Specifically, this
// is to be called after receiving (and sending an acknowledgement for) a
// SETTINGS_HEADER_TABLE_SIZE update from the remote decoding endpoint.
@@ -58,14 +93,27 @@ class NET_EXPORT_PRIVATE HpackEncoder {
return header_table_.settings_size_bound();
}
+ // This HpackEncoder will use |policy| to determine whether to insert header
+ // name-value pairs into the dynamic table.
+ void SetIndexingPolicy(IndexingPolicy policy) { should_index_ = policy; }
+
+ // |listener| will be invoked for each header name-value pair processed by
+ // this encoder.
+ void SetHeaderListener(HeaderListener listener) { listener_ = listener; }
+
void SetHeaderTableDebugVisitor(
std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) {
header_table_.set_debug_visitor(std::move(visitor));
}
private:
- typedef std::pair<base::StringPiece, base::StringPiece> Representation;
- typedef std::vector<Representation> Representations;
+ friend class test::HpackEncoderPeer;
+
+ class RepresentationIterator;
+ class Encoderator;
+
+ // Encodes a sequence of header name-value pairs as a single header block.
+ void EncodeRepresentations(RepresentationIterator* iter, std::string* output);
// Emits a static/dynamic indexed representation (Section 7.1).
void EmitIndex(const HpackEntry* entry);
@@ -90,11 +138,17 @@ class NET_EXPORT_PRIVATE HpackEncoder {
static void DecomposeRepresentation(const Representation& header_field,
Representations* out);
+ // Gathers headers without crumbling. Used when compression is not enabled.
+ static void GatherRepresentation(const Representation& header_field,
+ Representations* out);
+
HpackHeaderTable header_table_;
HpackOutputStream output_stream_;
const HpackHuffmanTable& huffman_table_;
size_t min_table_size_setting_received_;
+ HeaderListener listener_;
+ IndexingPolicy should_index_;
bool allow_huffman_compression_;
bool should_emit_table_size_;
@@ -103,4 +157,4 @@ class NET_EXPORT_PRIVATE HpackEncoder {
} // namespace net
-#endif // NET_SPDY_HPACK_ENCODER_H_
+#endif // NET_SPDY_HPACK_HPACK_ENCODER_H_
diff --git a/chromium/net/spdy/hpack/hpack_encoder_test.cc b/chromium/net/spdy/hpack/hpack_encoder_test.cc
index 10fd6087da0..fd4861c4935 100644
--- a/chromium/net/spdy/hpack/hpack_encoder_test.cc
+++ b/chromium/net/spdy/hpack/hpack_encoder_test.cc
@@ -7,6 +7,8 @@
#include <map>
#include <string>
+#include "base/rand_util.h"
+#include "net/base/arena.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -14,6 +16,8 @@ namespace net {
using base::StringPiece;
using std::string;
+using std::vector;
+using std::pair;
using testing::ElementsAre;
namespace test {
@@ -66,6 +70,39 @@ class HpackEncoderPeer {
}
}
+ // TODO(dahollings): Remove or clean up these methods when deprecating
+ // non-incremental encoding path.
+ static bool EncodeHeaderSet(HpackEncoder* encoder,
+ const SpdyHeaderBlock& header_set,
+ string* output,
+ bool use_compression,
+ bool use_incremental) {
+ if (use_incremental) {
+ return EncodeIncremental(encoder, header_set, output, use_compression);
+ } else {
+ return use_compression ? encoder->EncodeHeaderSet(header_set, output)
+ : encoder->EncodeHeaderSetWithoutCompression(
+ header_set, output);
+ }
+ }
+
+ static bool EncodeIncremental(HpackEncoder* encoder,
+ const SpdyHeaderBlock& header_set,
+ string* output,
+ bool use_compression) {
+ std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoderator =
+ encoder->EncodeHeaderSet(header_set, use_compression);
+ string output_buffer;
+ encoderator->Next(base::RandInt(0, 15), &output_buffer);
+ while (encoderator->HasNext()) {
+ string second_buffer;
+ encoderator->Next(base::RandInt(0, 15), &second_buffer);
+ output_buffer.append(second_buffer);
+ }
+ *output = std::move(output_buffer);
+ return true;
+ }
+
private:
HpackEncoder* encoder_;
};
@@ -76,17 +113,21 @@ namespace {
using std::map;
using testing::ElementsAre;
+using testing::Pair;
-class HpackEncoderTest : public ::testing::Test {
+class HpackEncoderTest : public ::testing::TestWithParam<bool> {
protected:
typedef test::HpackEncoderPeer::Representations Representations;
HpackEncoderTest()
: encoder_(ObtainHpackHuffmanTable()),
peer_(&encoder_),
- static_(peer_.table()->GetByIndex(1)) {}
+ static_(peer_.table()->GetByIndex(1)),
+ headers_storage_(1024 /* block size */) {}
void SetUp() override {
+ use_incremental_ = GetParam();
+
// Populate dynamic entries into the table fixture. For simplicity each
// entry has name.size() + value.size() == 10.
key_1_ = peer_.table()->TryAddEntry("key1", "value1");
@@ -101,6 +142,14 @@ class HpackEncoderTest : public ::testing::Test {
peer_.set_allow_huffman_compression(false);
}
+ void SaveHeaders(StringPiece name, StringPiece value) {
+ StringPiece n(headers_storage_.Memdup(name.data(), name.size()),
+ name.size());
+ StringPiece v(headers_storage_.Memdup(value.data(), value.size()),
+ value.size());
+ headers_observed_.push_back(make_pair(n, v));
+ }
+
void ExpectIndex(size_t index) {
expected_.AppendPrefix(kIndexedOpcode);
expected_.AppendUint32(index);
@@ -139,7 +188,16 @@ class HpackEncoderTest : public ::testing::Test {
void CompareWithExpectedEncoding(const SpdyHeaderBlock& header_set) {
string expected_out, actual_out;
expected_.TakeString(&expected_out);
- EXPECT_TRUE(encoder_.EncodeHeaderSet(header_set, &actual_out));
+ EXPECT_TRUE(test::HpackEncoderPeer::EncodeHeaderSet(
+ &encoder_, header_set, &actual_out, true, use_incremental_));
+ EXPECT_EQ(expected_out, actual_out);
+ }
+ void CompareWithExpectedEncodingWithoutCompression(
+ const SpdyHeaderBlock& header_set) {
+ string expected_out, actual_out;
+ expected_.TakeString(&expected_out);
+ EXPECT_TRUE(test::HpackEncoderPeer::EncodeHeaderSet(
+ &encoder_, header_set, &actual_out, false, use_incremental_));
EXPECT_EQ(expected_out, actual_out);
}
size_t IndexOf(const HpackEntry* entry) {
@@ -155,18 +213,30 @@ class HpackEncoderTest : public ::testing::Test {
const HpackEntry* cookie_a_;
const HpackEntry* cookie_c_;
+ UnsafeArena headers_storage_;
+ vector<pair<StringPiece, StringPiece>> headers_observed_;
+
HpackOutputStream expected_;
+ bool use_incremental_;
};
-TEST_F(HpackEncoderTest, SingleDynamicIndex) {
+INSTANTIATE_TEST_CASE_P(HpackEncoderTests, HpackEncoderTest, ::testing::Bool());
+
+TEST_P(HpackEncoderTest, SingleDynamicIndex) {
+ encoder_.SetHeaderListener([this](StringPiece name, StringPiece value) {
+ this->SaveHeaders(name, value);
+ });
+
ExpectIndex(IndexOf(key_2_));
SpdyHeaderBlock headers;
headers[key_2_->name().as_string()] = key_2_->value().as_string();
CompareWithExpectedEncoding(headers);
+ EXPECT_THAT(headers_observed_,
+ ElementsAre(Pair(key_2_->name(), key_2_->value())));
}
-TEST_F(HpackEncoderTest, SingleStaticIndex) {
+TEST_P(HpackEncoderTest, SingleStaticIndex) {
ExpectIndex(IndexOf(static_));
SpdyHeaderBlock headers;
@@ -174,7 +244,7 @@ TEST_F(HpackEncoderTest, SingleStaticIndex) {
CompareWithExpectedEncoding(headers);
}
-TEST_F(HpackEncoderTest, SingleStaticIndexTooLarge) {
+TEST_P(HpackEncoderTest, SingleStaticIndexTooLarge) {
peer_.table()->SetMaxSize(1); // Also evicts all fixtures.
ExpectIndex(IndexOf(static_));
@@ -185,7 +255,7 @@ TEST_F(HpackEncoderTest, SingleStaticIndexTooLarge) {
EXPECT_EQ(0u, peer_.table_peer().dynamic_entries()->size());
}
-TEST_F(HpackEncoderTest, SingleLiteralWithIndexName) {
+TEST_P(HpackEncoderTest, SingleLiteralWithIndexName) {
ExpectIndexedLiteral(key_2_, "value3");
SpdyHeaderBlock headers;
@@ -198,7 +268,7 @@ TEST_F(HpackEncoderTest, SingleLiteralWithIndexName) {
EXPECT_EQ(new_entry->value(), "value3");
}
-TEST_F(HpackEncoderTest, SingleLiteralWithLiteralName) {
+TEST_P(HpackEncoderTest, SingleLiteralWithLiteralName) {
ExpectIndexedLiteral("key3", "value3");
SpdyHeaderBlock headers;
@@ -210,7 +280,7 @@ TEST_F(HpackEncoderTest, SingleLiteralWithLiteralName) {
EXPECT_EQ(new_entry->value(), "value3");
}
-TEST_F(HpackEncoderTest, SingleLiteralTooLarge) {
+TEST_P(HpackEncoderTest, SingleLiteralTooLarge) {
peer_.table()->SetMaxSize(1); // Also evicts all fixtures.
ExpectIndexedLiteral("key3", "value3");
@@ -224,7 +294,7 @@ TEST_F(HpackEncoderTest, SingleLiteralTooLarge) {
EXPECT_EQ(0u, peer_.table_peer().dynamic_entries()->size());
}
-TEST_F(HpackEncoderTest, EmitThanEvict) {
+TEST_P(HpackEncoderTest, EmitThanEvict) {
// |key_1_| is toggled and placed into the reference set,
// and then immediately evicted by "key3".
ExpectIndex(IndexOf(key_1_));
@@ -236,7 +306,7 @@ TEST_F(HpackEncoderTest, EmitThanEvict) {
CompareWithExpectedEncoding(headers);
}
-TEST_F(HpackEncoderTest, CookieHeaderIsCrumbled) {
+TEST_P(HpackEncoderTest, CookieHeaderIsCrumbled) {
ExpectIndex(IndexOf(cookie_a_));
ExpectIndex(IndexOf(cookie_c_));
ExpectIndexedLiteral(peer_.table()->GetByName("cookie"), "e=ff");
@@ -246,7 +316,7 @@ TEST_F(HpackEncoderTest, CookieHeaderIsCrumbled) {
CompareWithExpectedEncoding(headers);
}
-TEST_F(HpackEncoderTest, StringsDynamicallySelectHuffmanCoding) {
+TEST_P(HpackEncoderTest, StringsDynamicallySelectHuffmanCoding) {
peer_.set_allow_huffman_compression(true);
// Compactable string. Uses Huffman coding.
@@ -267,7 +337,11 @@ TEST_F(HpackEncoderTest, StringsDynamicallySelectHuffmanCoding) {
EXPECT_EQ(expected_out, actual_out);
}
-TEST_F(HpackEncoderTest, EncodingWithoutCompression) {
+TEST_P(HpackEncoderTest, EncodingWithoutCompression) {
+ encoder_.SetHeaderListener([this](StringPiece name, StringPiece value) {
+ this->SaveHeaders(name, value);
+ });
+
// Implementation should internally disable.
peer_.set_allow_huffman_compression(true);
@@ -280,13 +354,19 @@ TEST_F(HpackEncoderTest, EncodingWithoutCompression) {
headers["cookie"] = "foo=bar; baz=bing";
headers["hello"] = "goodbye";
- string expected_out, actual_out;
- expected_.TakeString(&expected_out);
- encoder_.EncodeHeaderSetWithoutCompression(headers, &actual_out);
- EXPECT_EQ(expected_out, actual_out);
+ CompareWithExpectedEncodingWithoutCompression(headers);
+
+ EXPECT_THAT(headers_observed_,
+ ElementsAre(Pair(":path", "/index.html"),
+ Pair("cookie", "foo=bar; baz=bing"),
+ Pair("hello", "goodbye")));
}
-TEST_F(HpackEncoderTest, MultipleEncodingPasses) {
+TEST_P(HpackEncoderTest, MultipleEncodingPasses) {
+ encoder_.SetHeaderListener([this](StringPiece name, StringPiece value) {
+ this->SaveHeaders(name, value);
+ });
+
// Pass 1.
{
SpdyHeaderBlock headers;
@@ -339,9 +419,22 @@ TEST_F(HpackEncoderTest, MultipleEncodingPasses) {
CompareWithExpectedEncoding(headers);
}
+
+ // clang-format off
+ EXPECT_THAT(headers_observed_,
+ ElementsAre(Pair("key1", "value1"),
+ Pair("cookie", "a=bb"),
+ Pair("key2", "value2"),
+ Pair("cookie", "c=dd"),
+ Pair("cookie", "e=ff"),
+ Pair("key2", "value2"),
+ Pair("cookie", "a=bb"),
+ Pair("cookie", "b=cc"),
+ Pair("cookie", "c=dd")));
+ // clang-format on
}
-TEST_F(HpackEncoderTest, PseudoHeadersFirst) {
+TEST_P(HpackEncoderTest, PseudoHeadersFirst) {
SpdyHeaderBlock headers;
// A pseudo-header that should not be indexed.
headers[":path"] = "/spam/eggs.html";
@@ -364,7 +457,7 @@ TEST_F(HpackEncoderTest, PseudoHeadersFirst) {
CompareWithExpectedEncoding(headers);
}
-TEST_F(HpackEncoderTest, CookieToCrumbs) {
+TEST_P(HpackEncoderTest, CookieToCrumbs) {
test::HpackEncoderPeer peer(NULL);
std::vector<StringPiece> out;
@@ -398,7 +491,7 @@ TEST_F(HpackEncoderTest, CookieToCrumbs) {
EXPECT_THAT(out, ElementsAre("foo=1", "bar=2 ", "bar=3"));
}
-TEST_F(HpackEncoderTest, DecomposeRepresentation) {
+TEST_P(HpackEncoderTest, DecomposeRepresentation) {
test::HpackEncoderPeer peer(NULL);
std::vector<StringPiece> out;
@@ -423,7 +516,7 @@ TEST_F(HpackEncoderTest, DecomposeRepresentation) {
// Test that encoded headers do not have \0-delimited multiple values, as this
// became disallowed in HTTP/2 draft-14.
-TEST_F(HpackEncoderTest, CrumbleNullByteDelimitedValue) {
+TEST_P(HpackEncoderTest, CrumbleNullByteDelimitedValue) {
SpdyHeaderBlock headers;
// A header field to be crumbled: "spam: foo\0bar".
headers["spam"] = string("foo\0bar", 7);
@@ -437,7 +530,7 @@ TEST_F(HpackEncoderTest, CrumbleNullByteDelimitedValue) {
CompareWithExpectedEncoding(headers);
}
-TEST_F(HpackEncoderTest, HeaderTableSizeUpdate) {
+TEST_P(HpackEncoderTest, HeaderTableSizeUpdate) {
encoder_.ApplyHeaderTableSizeSetting(1024);
ExpectHeaderTableSizeUpdate(1024);
ExpectIndexedLiteral("key3", "value3");
@@ -451,7 +544,7 @@ TEST_F(HpackEncoderTest, HeaderTableSizeUpdate) {
EXPECT_EQ(new_entry->value(), "value3");
}
-TEST_F(HpackEncoderTest, HeaderTableSizeUpdateWithMin) {
+TEST_P(HpackEncoderTest, HeaderTableSizeUpdateWithMin) {
const size_t starting_size = peer_.table()->settings_size_bound();
encoder_.ApplyHeaderTableSizeSetting(starting_size - 2);
encoder_.ApplyHeaderTableSizeSetting(starting_size - 1);
@@ -470,7 +563,7 @@ TEST_F(HpackEncoderTest, HeaderTableSizeUpdateWithMin) {
EXPECT_EQ(new_entry->value(), "value3");
}
-TEST_F(HpackEncoderTest, HeaderTableSizeUpdateWithExistingSize) {
+TEST_P(HpackEncoderTest, HeaderTableSizeUpdateWithExistingSize) {
encoder_.ApplyHeaderTableSizeSetting(peer_.table()->settings_size_bound());
// No encoded size update.
ExpectIndexedLiteral("key3", "value3");
@@ -484,7 +577,7 @@ TEST_F(HpackEncoderTest, HeaderTableSizeUpdateWithExistingSize) {
EXPECT_EQ(new_entry->value(), "value3");
}
-TEST_F(HpackEncoderTest, HeaderTableSizeUpdatesWithGreaterSize) {
+TEST_P(HpackEncoderTest, HeaderTableSizeUpdatesWithGreaterSize) {
const size_t starting_size = peer_.table()->settings_size_bound();
encoder_.ApplyHeaderTableSizeSetting(starting_size + 1);
encoder_.ApplyHeaderTableSizeSetting(starting_size + 2);
diff --git a/chromium/net/spdy/hpack/hpack_header_table.cc b/chromium/net/spdy/hpack/hpack_header_table.cc
index 7043ae8ec66..6599b660400 100644
--- a/chromium/net/spdy/hpack/hpack_header_table.cc
+++ b/chromium/net/spdy/hpack/hpack_header_table.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "net/spdy/hpack/hpack_constants.h"
#include "net/spdy/hpack/hpack_static_table.h"
+#include "net/spdy/spdy_flags.h"
namespace net {
@@ -125,7 +126,11 @@ void HpackHeaderTable::SetMaxSize(size_t max_size) {
void HpackHeaderTable::SetSettingsHeaderTableSize(size_t settings_size) {
settings_size_bound_ = settings_size;
- if (settings_size_bound_ < max_size_) {
+ if (!FLAGS_chromium_reloadable_flag_increase_hpack_table_size) {
+ if (settings_size_bound_ < max_size_) {
+ SetMaxSize(settings_size_bound_);
+ }
+ } else {
SetMaxSize(settings_size_bound_);
}
}
diff --git a/chromium/net/spdy/hpack/hpack_header_table_test.cc b/chromium/net/spdy/hpack/hpack_header_table_test.cc
index b79b7a717f9..3a470365f04 100644
--- a/chromium/net/spdy/hpack/hpack_header_table_test.cc
+++ b/chromium/net/spdy/hpack/hpack_header_table_test.cc
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "net/spdy/hpack/hpack_constants.h"
#include "net/spdy/hpack/hpack_entry.h"
+#include "net/spdy/spdy_flags.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -258,6 +259,41 @@ TEST_F(HpackHeaderTableTest, EntryIndexing) {
}
TEST_F(HpackHeaderTableTest, SetSizes) {
+ FLAGS_chromium_reloadable_flag_increase_hpack_table_size = true;
+ string key = "key", value = "value";
+ const HpackEntry* entry1 = table_.TryAddEntry(key, value);
+ const HpackEntry* entry2 = table_.TryAddEntry(key, value);
+ const HpackEntry* entry3 = table_.TryAddEntry(key, value);
+
+ // Set exactly large enough. No Evictions.
+ size_t max_size = entry1->Size() + entry2->Size() + entry3->Size();
+ table_.SetMaxSize(max_size);
+ EXPECT_EQ(3u, peer_.dynamic_entries().size());
+
+ // Set just too small. One eviction.
+ max_size = entry1->Size() + entry2->Size() + entry3->Size() - 1;
+ table_.SetMaxSize(max_size);
+ EXPECT_EQ(2u, peer_.dynamic_entries().size());
+
+ // Changing SETTINGS_HEADER_TABLE_SIZE.
+ EXPECT_EQ(kDefaultHeaderTableSizeSetting, table_.settings_size_bound());
+ // In production, the size passed to SetSettingsHeaderTableSize is never
+ // larger than table_.settings_size_bound().
+ table_.SetSettingsHeaderTableSize(kDefaultHeaderTableSizeSetting * 3 + 1);
+ EXPECT_EQ(kDefaultHeaderTableSizeSetting * 3 + 1, table_.max_size());
+
+ // SETTINGS_HEADER_TABLE_SIZE upper-bounds |table_.max_size()|,
+ // and will force evictions.
+ max_size = entry3->Size() - 1;
+ table_.SetSettingsHeaderTableSize(max_size);
+ EXPECT_EQ(max_size, table_.max_size());
+ EXPECT_EQ(max_size, table_.settings_size_bound());
+ EXPECT_EQ(0u, peer_.dynamic_entries().size());
+}
+
+TEST_F(HpackHeaderTableTest, SetSizesOld) {
+ FLAGS_chromium_reloadable_flag_increase_hpack_table_size = false;
+
string key = "key", value = "value";
const HpackEntry* entry1 = table_.TryAddEntry(key, value);
const HpackEntry* entry2 = table_.TryAddEntry(key, value);
diff --git a/chromium/net/spdy/hpack/hpack_huffman_decoder.cc b/chromium/net/spdy/hpack/hpack_huffman_decoder.cc
index 30f4ee3c467..f305a664e07 100644
--- a/chromium/net/spdy/hpack/hpack_huffman_decoder.cc
+++ b/chromium/net/spdy/hpack/hpack_huffman_decoder.cc
@@ -303,8 +303,7 @@ char HpackHuffmanDecoder::CanonicalToSource(HuffmanWord canonical) {
// strings, and a later portion dealing with the last few bytes of strings.
// TODO(jamessynge): Determine if that is worth it by adding some counters to
// measure the distribution of string sizes seen in practice.
-bool HpackHuffmanDecoder::DecodeString(HpackInputStream* in,
- std::string* out) {
+bool HpackHuffmanDecoder::DecodeString(HpackInputStream* in, std::string* out) {
out->clear();
// Load |bits| with the leading bits of the input stream, left justified
@@ -335,7 +334,7 @@ bool HpackHuffmanDecoder::DecodeString(HpackInputStream* in,
const HuffmanCodeLength code_length = CodeLengthOfPrefix(bits);
DCHECK_LE(kMinCodeLength, code_length);
DCHECK_LE(code_length, kMaxCodeLength);
- DVLOG(1) << "bits: 0b" << std::bitset<32>(bits)
+ DVLOG(2) << "bits: 0b" << std::bitset<32>(bits)
<< " (avail=" << bits_available << ")"
<< " prefix length: " << code_length
<< (code_length > bits_available ? " *****" : "");
@@ -393,7 +392,7 @@ bool HpackHuffmanDecoder::DecodeString(HpackInputStream* in,
// if we got any bits.
peeked_success = in->PeekBits(&bits_available, &bits);
}
- DLOG_IF(WARNING, (VLOG_IS_ON(1) && bits_available < 32 && !peeked_success))
+ DLOG_IF(WARNING, (VLOG_IS_ON(2) && bits_available < 32 && !peeked_success))
<< "no more peeking possible";
}
}
diff --git a/chromium/net/spdy/hpack/hpack_huffman_decoder.h b/chromium/net/spdy/hpack/hpack_huffman_decoder.h
index 302e6c97a48..50c3dc4c558 100644
--- a/chromium/net/spdy/hpack/hpack_huffman_decoder.h
+++ b/chromium/net/spdy/hpack/hpack_huffman_decoder.h
@@ -35,8 +35,7 @@ class NET_EXPORT_PRIVATE HpackHuffmanDecoder {
// DecodeString() halts when |in| runs out of input, in which case true is
// returned. It also halts (returning false) if an invalid Huffman code
// prefix is read.
- static bool DecodeString(HpackInputStream* in,
- std::string* out);
+ static bool DecodeString(HpackInputStream* in, std::string* out);
private:
friend class test::HpackHuffmanDecoderPeer;
diff --git a/chromium/net/spdy/hpack/hpack_huffman_table.cc b/chromium/net/spdy/hpack/hpack_huffman_table.cc
index 8a6b7235570..0e3ca1b060e 100644
--- a/chromium/net/spdy/hpack/hpack_huffman_table.cc
+++ b/chromium/net/spdy/hpack/hpack_huffman_table.cc
@@ -266,7 +266,6 @@ size_t HpackHuffmanTable::EncodedSize(StringPiece in) const {
}
bool HpackHuffmanTable::GenericDecodeString(HpackInputStream* in,
- size_t out_capacity,
string* out) const {
// Number of decode iterations required for a 32-bit code.
const int kDecodeIterations = static_cast<int>(
@@ -304,10 +303,6 @@ bool HpackHuffmanTable::GenericDecodeString(HpackInputStream* in,
// The input is an invalid prefix, larger than any prefix in the table.
return false;
} else {
- if (out->size() == out_capacity) {
- // This code would cause us to overflow |out_capacity|.
- return false;
- }
if (entry.symbol_id < 256) {
// Assume symbols >= 256 are used for padding.
out->push_back(static_cast<char>(entry.symbol_id));
diff --git a/chromium/net/spdy/hpack/hpack_huffman_table.h b/chromium/net/spdy/hpack/hpack_huffman_table.h
index 6fd60e43d39..c02e175e81b 100644
--- a/chromium/net/spdy/hpack/hpack_huffman_table.h
+++ b/chromium/net/spdy/hpack/hpack_huffman_table.h
@@ -92,7 +92,6 @@ class NET_EXPORT_PRIVATE HpackHuffmanTable {
// DEPRECATED: HpackHuffmanDecoder is now used for decoding strings encoded
// according to the Huffman Table in the HPACK spec.
bool GenericDecodeString(HpackInputStream* in,
- size_t out_capacity,
std::string* out) const;
private:
diff --git a/chromium/net/spdy/hpack/hpack_huffman_table_test.cc b/chromium/net/spdy/hpack/hpack_huffman_table_test.cc
index fda6c5e8e4f..adff4c683a5 100644
--- a/chromium/net/spdy/hpack/hpack_huffman_table_test.cc
+++ b/chromium/net/spdy/hpack/hpack_huffman_table_test.cc
@@ -240,8 +240,7 @@ TEST_F(GenericHuffmanTableTest, ValidateInternalsWithSmallCode) {
string buffer_out;
HpackInputStream input_stream(buffer_in);
- EXPECT_TRUE(
- table_.GenericDecodeString(&input_stream, input.size(), &buffer_out));
+ EXPECT_TRUE(table_.GenericDecodeString(&input_stream, &buffer_out));
EXPECT_EQ(buffer_out, input);
}
@@ -299,14 +298,13 @@ TEST_F(GenericHuffmanTableTest, DecodeWithBadInput) {
EXPECT_TRUE(table_.Initialize(code, arraysize(code)));
string buffer;
- const size_t capacity = 4;
{
// This example works: (2) 00 (3) 010 (2) 00 (6) 100110 (pad) 100.
char input_storage[] = {bits8("00010001"), bits8("00110100")};
StringPiece input(input_storage, arraysize(input_storage));
HpackInputStream input_stream(input);
- EXPECT_TRUE(table_.GenericDecodeString(&input_stream, capacity, &buffer));
+ EXPECT_TRUE(table_.GenericDecodeString(&input_stream, &buffer));
EXPECT_EQ(buffer, "\x02\x03\x02\x06");
}
{
@@ -316,29 +314,17 @@ TEST_F(GenericHuffmanTableTest, DecodeWithBadInput) {
StringPiece input(input_storage, arraysize(input_storage));
HpackInputStream input_stream(input);
- EXPECT_FALSE(table_.GenericDecodeString(&input_stream, capacity, &buffer));
+ EXPECT_FALSE(table_.GenericDecodeString(&input_stream, &buffer));
EXPECT_EQ(buffer, "\x02\x03\x02");
}
{
- // Repeat the shortest 0b00 code to overflow |buffer|. Expect to fail.
- std::vector<char> input_storage(1 + capacity / 4, '\0');
- StringPiece input(&input_storage[0], input_storage.size());
-
- HpackInputStream input_stream(input);
- EXPECT_FALSE(table_.GenericDecodeString(&input_stream, capacity, &buffer));
-
- std::vector<char> expected(capacity, '\x02');
- EXPECT_THAT(buffer, ElementsAreArray(expected));
- EXPECT_EQ(capacity, buffer.size());
- }
- {
// Expect to fail if more than a byte of unconsumed input remains.
// (6) 100110 (8 truncated) 1001110000
char input_storage[] = {bits8("10011010"), bits8("01110000")};
StringPiece input(input_storage, arraysize(input_storage));
HpackInputStream input_stream(input);
- EXPECT_FALSE(table_.GenericDecodeString(&input_stream, capacity, &buffer));
+ EXPECT_FALSE(table_.GenericDecodeString(&input_stream, &buffer));
EXPECT_EQ(buffer, "\x06");
}
}
@@ -353,13 +339,11 @@ class HpackHuffmanTableTest : public GenericHuffmanTableTest {
EXPECT_TRUE(table_.IsInitialized());
}
- void DecodeStringTwice(const string& encoded,
- size_t out_capacity,
- string* out) {
+ void DecodeStringTwice(const string& encoded, string* out) {
// First decode with HpackHuffmanTable.
{
HpackInputStream input_stream(encoded);
- EXPECT_TRUE(table_.GenericDecodeString(&input_stream, out_capacity, out));
+ EXPECT_TRUE(table_.GenericDecodeString(&input_stream, out));
}
// And decode again with the fixed decoder, confirming that the result is
// the same.
@@ -392,7 +376,7 @@ TEST_F(HpackHuffmanTableTest, SpecRequestExamples) {
for (size_t i = 0; i != arraysize(test_table); i += 2) {
const string& encodedFixture(test_table[i]);
const string& decodedFixture(test_table[i + 1]);
- DecodeStringTwice(encodedFixture, decodedFixture.size(), &buffer);
+ DecodeStringTwice(encodedFixture, &buffer);
EXPECT_EQ(decodedFixture, buffer);
buffer = EncodeString(decodedFixture);
EXPECT_EQ(encodedFixture, buffer);
@@ -417,7 +401,7 @@ TEST_F(HpackHuffmanTableTest, SpecResponseExamples) {
for (size_t i = 0; i != arraysize(test_table); i += 2) {
const string& encodedFixture(test_table[i]);
const string& decodedFixture(test_table[i + 1]);
- DecodeStringTwice(encodedFixture, decodedFixture.size(), &buffer);
+ DecodeStringTwice(encodedFixture, &buffer);
EXPECT_EQ(decodedFixture, buffer);
buffer = EncodeString(decodedFixture);
EXPECT_EQ(encodedFixture, buffer);
@@ -431,8 +415,7 @@ TEST_F(HpackHuffmanTableTest, RoundTripIndividualSymbols) {
StringPiece input(storage, arraysize(storage));
string buffer_in = EncodeString(input);
string buffer_out;
-
- DecodeStringTwice(buffer_in, input.size(), &buffer_out);
+ DecodeStringTwice(buffer_in, &buffer_out);
EXPECT_EQ(input, buffer_out);
}
}
@@ -447,7 +430,7 @@ TEST_F(HpackHuffmanTableTest, RoundTripSymbolSequence) {
string buffer_in = EncodeString(input);
string buffer_out;
- DecodeStringTwice(buffer_in, input.size(), &buffer_out);
+ DecodeStringTwice(buffer_in, &buffer_out);
EXPECT_EQ(input, buffer_out);
}
diff --git a/chromium/net/spdy/hpack/hpack_input_stream.cc b/chromium/net/spdy/hpack/hpack_input_stream.cc
index 751f6c64d0e..6008d5cdbc7 100644
--- a/chromium/net/spdy/hpack/hpack_input_stream.cc
+++ b/chromium/net/spdy/hpack/hpack_input_stream.cc
@@ -153,7 +153,7 @@ bool HpackInputStream::DecodeNextHuffmanString(string* str) {
return false;
}
- HpackInputStream bounded_reader(StringPiece(buffer_.data(), encoded_size));
+ HpackInputStream bounded_reader(buffer_.substr(0, encoded_size));
buffer_.remove_prefix(encoded_size);
parsed_bytes_current_ += encoded_size;
diff --git a/chromium/net/spdy/hpack/hpack_output_stream.cc b/chromium/net/spdy/hpack/hpack_output_stream.cc
index 18aa4e6fb00..6337d7d42e8 100644
--- a/chromium/net/spdy/hpack/hpack_output_stream.cc
+++ b/chromium/net/spdy/hpack/hpack_output_stream.cc
@@ -4,6 +4,8 @@
#include "net/spdy/hpack/hpack_output_stream.h"
+#include <utility>
+
#include "base/logging.h"
namespace net {
@@ -72,4 +74,22 @@ void HpackOutputStream::TakeString(string* output) {
bit_offset_ = 0;
}
+void HpackOutputStream::BoundedTakeString(size_t max_size, string* output) {
+ if (buffer_.size() > max_size) {
+ // Save off overflow bytes to temporary string (causes a copy).
+ string overflow(buffer_.data() + max_size, buffer_.size() - max_size);
+
+ // Resize buffer down to the given limit.
+ buffer_.resize(max_size);
+
+ // Give buffer to output string.
+ *output = std::move(buffer_);
+
+ // Reset to contain overflow.
+ buffer_ = std::move(overflow);
+ } else {
+ TakeString(output);
+ }
+}
+
} // namespace net
diff --git a/chromium/net/spdy/hpack/hpack_output_stream.h b/chromium/net/spdy/hpack/hpack_output_stream.h
index 0c5a013a950..4451a88def2 100644
--- a/chromium/net/spdy/hpack/hpack_output_stream.h
+++ b/chromium/net/spdy/hpack/hpack_output_stream.h
@@ -49,15 +49,22 @@ class NET_EXPORT_PRIVATE HpackOutputStream {
// boundary after this function is called.
void AppendUint32(uint32_t I);
- // Swaps the interal buffer with |output|.
+ // Swaps the internal buffer with |output|, then resets state.
void TakeString(std::string* output);
+ // Gives up to |max_size| bytes of the internal buffer to |output|. Resets
+ // internal state with the overflow.
+ void BoundedTakeString(size_t max_size, std::string* output);
+
+ // Size in bytes of stream's internal buffer.
+ size_t size() const { return buffer_.size(); }
+
private:
// The internal bit buffer.
std::string buffer_;
// If 0, the buffer ends on a byte boundary. If non-zero, the buffer
- // ends on the most significant nth bit. Guaranteed to be < 8.
+ // ends on the nth most significant bit. Guaranteed to be < 8.
size_t bit_offset_;
DISALLOW_COPY_AND_ASSIGN(HpackOutputStream);
diff --git a/chromium/net/spdy/hpack/hpack_output_stream_test.cc b/chromium/net/spdy/hpack/hpack_output_stream_test.cc
index 939dd9d8d03..aa0964048b2 100644
--- a/chromium/net/spdy/hpack/hpack_output_stream_test.cc
+++ b/chromium/net/spdy/hpack/hpack_output_stream_test.cc
@@ -254,6 +254,25 @@ TEST(HpackOutputStreamTest, AppendBytes) {
EXPECT_EQ("buffer1buffer2", str);
}
+TEST(HpackOutputStreamTest, BoundedTakeString) {
+ HpackOutputStream output_stream;
+
+ output_stream.AppendBytes("buffer12");
+ output_stream.AppendBytes("buffer456");
+
+ string str;
+ output_stream.BoundedTakeString(9, &str);
+ EXPECT_EQ("buffer12b", str);
+
+ output_stream.AppendBits(0x7f, 7);
+ output_stream.AppendUint32(0x11);
+ output_stream.BoundedTakeString(9, &str);
+ EXPECT_EQ("uffer456\xff", str);
+
+ output_stream.BoundedTakeString(9, &str);
+ EXPECT_EQ("\x10", str);
+}
+
} // namespace
} // namespace net
diff --git a/chromium/net/spdy/hpack/hpack_round_trip_test.cc b/chromium/net/spdy/hpack/hpack_round_trip_test.cc
index 07ab6990c9d..b932cffa99b 100644
--- a/chromium/net/spdy/hpack/hpack_round_trip_test.cc
+++ b/chromium/net/spdy/hpack/hpack_round_trip_test.cc
@@ -4,7 +4,6 @@
#include <cmath>
#include <ctime>
-#include <map>
#include <string>
#include <vector>
@@ -18,13 +17,14 @@
namespace net {
namespace test {
-using std::map;
using std::string;
-using std::vector;
namespace {
-class HpackRoundTripTest : public ::testing::Test {
+// Supports testing with the input split at every byte boundary.
+enum InputSizeParam { ALL_INPUT, ONE_BYTE, ZERO_THEN_ONE_BYTE };
+
+class HpackRoundTripTest : public ::testing::TestWithParam<InputSizeParam> {
protected:
HpackRoundTripTest() : encoder_(ObtainHpackHuffmanTable()), decoder_() {}
@@ -38,9 +38,32 @@ class HpackRoundTripTest : public ::testing::Test {
string encoded;
encoder_.EncodeHeaderSet(header_set, &encoded);
- bool success =
- decoder_.HandleControlFrameHeadersData(encoded.data(), encoded.size());
- success &= decoder_.HandleControlFrameHeadersComplete(nullptr);
+ bool success = true;
+ if (GetParam() == ALL_INPUT) {
+ // Pass all the input to the decoder at once.
+ success = decoder_.HandleControlFrameHeadersData(encoded.data(),
+ encoded.size());
+ } else if (GetParam() == ONE_BYTE) {
+ // Pass the input to the decoder one byte at a time.
+ const char* data = encoded.data();
+ for (size_t ndx = 0; ndx < encoded.size() && success; ++ndx) {
+ success = decoder_.HandleControlFrameHeadersData(data + ndx, 1);
+ }
+ } else if (GetParam() == ZERO_THEN_ONE_BYTE) {
+ // Pass the input to the decoder one byte at a time, but before each
+ // byte pass an empty buffer.
+ const char* data = encoded.data();
+ for (size_t ndx = 0; ndx < encoded.size() && success; ++ndx) {
+ success = (decoder_.HandleControlFrameHeadersData(data + ndx, 0) &&
+ decoder_.HandleControlFrameHeadersData(data + ndx, 1));
+ }
+ } else {
+ ADD_FAILURE() << "Unknown param: " << GetParam();
+ }
+
+ if (success) {
+ success = decoder_.HandleControlFrameHeadersComplete(nullptr);
+ }
EXPECT_EQ(header_set, decoder_.decoded_block());
return success;
@@ -54,7 +77,13 @@ class HpackRoundTripTest : public ::testing::Test {
HpackDecoder decoder_;
};
-TEST_F(HpackRoundTripTest, ResponseFixtures) {
+INSTANTIATE_TEST_CASE_P(Tests,
+ HpackRoundTripTest,
+ ::testing::Values(ALL_INPUT,
+ ONE_BYTE,
+ ZERO_THEN_ONE_BYTE));
+
+TEST_P(HpackRoundTripTest, ResponseFixtures) {
{
SpdyHeaderBlock headers;
headers[":status"] = "302";
@@ -86,7 +115,7 @@ TEST_F(HpackRoundTripTest, ResponseFixtures) {
}
}
-TEST_F(HpackRoundTripTest, RequestFixtures) {
+TEST_P(HpackRoundTripTest, RequestFixtures) {
{
SpdyHeaderBlock headers;
headers[":authority"] = "www.example.com";
@@ -119,11 +148,11 @@ TEST_F(HpackRoundTripTest, RequestFixtures) {
}
}
-TEST_F(HpackRoundTripTest, RandomizedExamples) {
+TEST_P(HpackRoundTripTest, RandomizedExamples) {
// Grow vectors of names & values, which are seeded with fixtures and then
// expanded with dynamically generated data. Samples are taken using the
// exponential distribution.
- vector<string> pseudo_header_names, random_header_names;
+ std::vector<string> pseudo_header_names, random_header_names;
pseudo_header_names.push_back(":authority");
pseudo_header_names.push_back(":path");
pseudo_header_names.push_back(":status");
@@ -131,7 +160,7 @@ TEST_F(HpackRoundTripTest, RandomizedExamples) {
// TODO(jgraettinger): Enable "cookie" as a name fixture. Crumbs may be
// reconstructed in any order, which breaks the simple validation used here.
- vector<string> values;
+ std::vector<string> values;
values.push_back("/");
values.push_back("/index.html");
values.push_back("200");
diff --git a/chromium/net/spdy/hpack/hpack_static_table.h b/chromium/net/spdy/hpack/hpack_static_table.h
index 42798bfc959..ad22097408c 100644
--- a/chromium/net/spdy/hpack/hpack_static_table.h
+++ b/chromium/net/spdy/hpack/hpack_static_table.h
@@ -7,6 +7,7 @@
#include <stddef.h>
+#include "net/base/net_export.h"
#include "net/spdy/hpack/hpack_header_table.h"
namespace net {
diff --git a/chromium/net/spdy/hpack/hpack_static_table_test.cc b/chromium/net/spdy/hpack/hpack_static_table_test.cc
index c0753498327..00d397868aa 100644
--- a/chromium/net/spdy/hpack/hpack_static_table_test.cc
+++ b/chromium/net/spdy/hpack/hpack_static_table_test.cc
@@ -7,7 +7,6 @@
#include <set>
#include <vector>
-#include "net/base/net_export.h"
#include "net/spdy/hpack/hpack_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/net/spdy/http2_priority_dependencies.h b/chromium/net/spdy/http2_priority_dependencies.h
index 8f4ced01167..fbf099c55aa 100644
--- a/chromium/net/spdy/http2_priority_dependencies.h
+++ b/chromium/net/spdy/http2_priority_dependencies.h
@@ -8,6 +8,7 @@
#include <list>
#include <map>
+#include "net/base/net_export.h"
#include "net/spdy/spdy_protocol.h"
namespace net {
diff --git a/chromium/net/spdy/http2_write_scheduler.h b/chromium/net/spdy/http2_write_scheduler.h
index 1fd29620e8f..d8bd3ea1f71 100644
--- a/chromium/net/spdy/http2_write_scheduler.h
+++ b/chromium/net/spdy/http2_write_scheduler.h
@@ -22,7 +22,7 @@
#include "base/containers/linked_list.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/stl_util.h"
+#include "base/memory/ptr_util.h"
#include "net/spdy/spdy_bug_tracker.h"
#include "net/spdy/spdy_protocol.h"
#include "net/spdy/write_scheduler.h"
@@ -81,7 +81,6 @@ class Http2PriorityWriteScheduler : public WriteScheduler<StreamIdType> {
struct StreamInfo;
using StreamInfoVector = std::vector<StreamInfo*>;
- using StreamInfoMap = std::unordered_map<StreamIdType, StreamInfo*>;
struct StreamInfo : public base::LinkNode<StreamInfo> {
// ID for this stream.
@@ -167,8 +166,8 @@ class Http2PriorityWriteScheduler : public WriteScheduler<StreamIdType> {
// Pointee owned by all_stream_infos_.
StreamInfo* root_stream_info_;
// Maps from stream IDs to StreamInfo objects.
- StreamInfoMap all_stream_infos_;
- STLValueDeleter<StreamInfoMap> all_stream_infos_deleter_;
+ std::unordered_map<StreamIdType, std::unique_ptr<StreamInfo>>
+ all_stream_infos_;
// Queue containing all ready streams, ordered with streams of higher
// priority before streams of lower priority, and, among streams of equal
// priority, streams with lower ordinal before those with higher
@@ -188,15 +187,15 @@ class Http2PriorityWriteScheduler : public WriteScheduler<StreamIdType> {
};
template <typename StreamIdType>
-Http2PriorityWriteScheduler<StreamIdType>::Http2PriorityWriteScheduler()
- : all_stream_infos_deleter_(&all_stream_infos_) {
- root_stream_info_ = new StreamInfo();
- root_stream_info_->id = kHttp2RootStreamId;
- root_stream_info_->weight = kHttp2DefaultStreamWeight;
- root_stream_info_->parent = nullptr;
- root_stream_info_->priority = 1.0;
- root_stream_info_->ready = false;
- all_stream_infos_[kHttp2RootStreamId] = root_stream_info_;
+Http2PriorityWriteScheduler<StreamIdType>::Http2PriorityWriteScheduler() {
+ std::unique_ptr<StreamInfo> root_stream_info = base::MakeUnique<StreamInfo>();
+ root_stream_info_ = root_stream_info.get();
+ root_stream_info->id = kHttp2RootStreamId;
+ root_stream_info->weight = kHttp2DefaultStreamWeight;
+ root_stream_info->parent = nullptr;
+ root_stream_info->priority = 1.0;
+ root_stream_info->ready = false;
+ all_stream_infos_[kHttp2RootStreamId] = std::move(root_stream_info);
}
template <typename StreamIdType>
@@ -207,7 +206,7 @@ int Http2PriorityWriteScheduler<StreamIdType>::num_streams() const {
template <typename StreamIdType>
bool Http2PriorityWriteScheduler<StreamIdType>::StreamRegistered(
StreamIdType stream_id) const {
- return ContainsKey(all_stream_infos_, stream_id);
+ return base::ContainsKey(all_stream_infos_, stream_id);
}
template <typename StreamIdType>
@@ -224,30 +223,32 @@ void Http2PriorityWriteScheduler<StreamIdType>::RegisterStream(
StreamInfo* parent = FindStream(precedence.parent_id());
if (parent == nullptr) {
- SPDY_BUG << "Parent stream " << precedence.parent_id() << " not registered";
+ // parent_id may legitimately not be registered yet--see b/15676312.
+ DVLOG(1) << "Parent stream " << precedence.parent_id() << " not registered";
parent = root_stream_info_;
}
- StreamInfo* new_stream_info = new StreamInfo;
- new_stream_info->id = stream_id;
- new_stream_info->weight = precedence.weight();
- new_stream_info->parent = parent;
- all_stream_infos_[stream_id] = new_stream_info;
+ std::unique_ptr<StreamInfo> new_stream_info = base::MakeUnique<StreamInfo>();
+ StreamInfo* new_stream_info_ptr = new_stream_info.get();
+ new_stream_info_ptr->id = stream_id;
+ new_stream_info_ptr->weight = precedence.weight();
+ new_stream_info_ptr->parent = parent;
+ all_stream_infos_[stream_id] = std::move(new_stream_info);
if (precedence.is_exclusive()) {
// Move the parent's current children below the new stream.
using std::swap;
- swap(new_stream_info->children, parent->children);
- new_stream_info->total_child_weights = parent->total_child_weights;
+ swap(new_stream_info_ptr->children, parent->children);
+ new_stream_info_ptr->total_child_weights = parent->total_child_weights;
// Update each child's parent.
- for (StreamInfo* child : new_stream_info->children) {
- child->parent = new_stream_info;
+ for (StreamInfo* child : new_stream_info_ptr->children) {
+ child->parent = new_stream_info_ptr;
}
// Clear parent's old child data.
DCHECK(parent->children.empty());
parent->total_child_weights = 0;
}
// Add new stream to parent.
- parent->children.push_back(new_stream_info);
+ parent->children.push_back(new_stream_info_ptr);
parent->total_child_weights += precedence.weight();
// Update all priorities under parent, since addition of a stream affects
@@ -255,7 +256,7 @@ void Http2PriorityWriteScheduler<StreamIdType>::RegisterStream(
UpdatePrioritiesUnder(parent);
// Stream starts with ready == false, so no need to schedule it yet.
- DCHECK(!new_stream_info->ready);
+ DCHECK(!new_stream_info_ptr->ready);
}
template <typename StreamIdType>
@@ -266,7 +267,7 @@ void Http2PriorityWriteScheduler<StreamIdType>::UnregisterStream(
return;
}
// Remove the stream from table.
- typename StreamInfoMap::iterator it = all_stream_infos_.find(stream_id);
+ auto it = all_stream_infos_.find(stream_id);
if (it == all_stream_infos_.end()) {
SPDY_BUG << "Stream " << stream_id << " not registered";
return;
@@ -309,7 +310,9 @@ Http2PriorityWriteScheduler<StreamIdType>::GetStreamPrecedence(
StreamIdType stream_id) const {
const StreamInfo* stream_info = FindStream(stream_id);
if (stream_info == nullptr) {
- SPDY_BUG << "Stream " << stream_id << " not registered";
+ // Unknown streams tolerated due to b/15676312. However, return lowest
+ // weight.
+ DVLOG(1) << "Stream " << stream_id << " not registered";
return StreamPrecedenceType(kHttp2RootStreamId, kHttp2MinStreamWeight,
false);
}
@@ -345,7 +348,8 @@ void Http2PriorityWriteScheduler<StreamIdType>::UpdateStreamPrecedence(
StreamInfo* stream_info = FindStream(stream_id);
if (stream_info == nullptr) {
- SPDY_BUG << "Stream " << stream_id << " not registered";
+ // TODO(mpw): add to all_stream_infos_ on demand--see b/15676312.
+ DVLOG(1) << "Stream " << stream_id << " not registered";
return;
}
UpdateStreamParent(stream_info, precedence.parent_id(),
@@ -380,7 +384,8 @@ void Http2PriorityWriteScheduler<StreamIdType>::UpdateStreamParent(
}
StreamInfo* new_parent = FindStream(parent_id);
if (new_parent == nullptr) {
- SPDY_BUG << "Parent stream " << parent_id << " not registered";
+ // parent_id may legitimately not be registered yet--see b/15676312.
+ DVLOG(1) << "Parent stream " << parent_id << " not registered";
return;
}
@@ -570,15 +575,15 @@ template <typename StreamIdType>
const typename Http2PriorityWriteScheduler<StreamIdType>::StreamInfo*
Http2PriorityWriteScheduler<StreamIdType>::FindStream(
StreamIdType stream_id) const {
- typename StreamInfoMap::const_iterator it = all_stream_infos_.find(stream_id);
- return it == all_stream_infos_.end() ? nullptr : it->second;
+ auto it = all_stream_infos_.find(stream_id);
+ return it == all_stream_infos_.end() ? nullptr : it->second.get();
}
template <typename StreamIdType>
typename Http2PriorityWriteScheduler<StreamIdType>::StreamInfo*
Http2PriorityWriteScheduler<StreamIdType>::FindStream(StreamIdType stream_id) {
- typename StreamInfoMap::iterator it = all_stream_infos_.find(stream_id);
- return it == all_stream_infos_.end() ? nullptr : it->second;
+ auto it = all_stream_infos_.find(stream_id);
+ return it == all_stream_infos_.end() ? nullptr : it->second.get();
}
template <typename StreamIdType>
@@ -682,7 +687,7 @@ bool Http2PriorityWriteScheduler<StreamIdType>::ValidateInvariantsForTests()
++total_streams;
++streams_visited;
StreamIdType stream_id = kv.first;
- const StreamInfo& stream_info = *kv.second;
+ const StreamInfo& stream_info = *kv.second.get();
// Verify each StreamInfo mapped under the proper stream ID.
if (stream_id != stream_info.id) {
diff --git a/chromium/net/spdy/http2_write_scheduler_test.cc b/chromium/net/spdy/http2_write_scheduler_test.cc
index 08ee5bb1ddf..62fc4e902d4 100644
--- a/chromium/net/spdy/http2_write_scheduler_test.cc
+++ b/chromium/net/spdy/http2_write_scheduler_test.cc
@@ -90,9 +90,7 @@ TEST_F(Http2PriorityWriteSchedulerTest, RegisterAndUnregisterStreams) {
EXPECT_EQ(kHttp2RootStreamId, scheduler_.GetStreamPrecedence(13).parent_id());
// The parent stream 19 doesn't exist, so this should use 0 as parent stream:
- EXPECT_SPDY_BUG(
- scheduler_.RegisterStream(7, SpdyStreamPrecedence(19, 70, false)),
- "Parent stream 19 not registered");
+ scheduler_.RegisterStream(7, SpdyStreamPrecedence(19, 70, false));
EXPECT_TRUE(scheduler_.StreamRegistered(7));
EXPECT_EQ(0u, scheduler_.GetStreamPrecedence(7).parent_id());
// Now stream 7 already exists, so this should fail:
@@ -125,44 +123,37 @@ TEST_F(Http2PriorityWriteSchedulerTest, RegisterStreamWithSpdy3Priority) {
}
TEST_F(Http2PriorityWriteSchedulerTest, GetStreamWeight) {
- EXPECT_SPDY_BUG(EXPECT_EQ(kHttp2MinStreamWeight,
- scheduler_.GetStreamPrecedence(3).weight()),
- "Stream 3 not registered");
+ // Unknown streams tolerated due to b/15676312.
+ EXPECT_EQ(kHttp2MinStreamWeight, scheduler_.GetStreamPrecedence(3).weight());
scheduler_.RegisterStream(3, SpdyStreamPrecedence(0, 130, true));
EXPECT_EQ(130, scheduler_.GetStreamPrecedence(3).weight());
scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(0, 50, true));
EXPECT_EQ(50, scheduler_.GetStreamPrecedence(3).weight());
scheduler_.UnregisterStream(3);
- EXPECT_SPDY_BUG(EXPECT_EQ(kHttp2MinStreamWeight,
- scheduler_.GetStreamPrecedence(3).weight()),
- "Stream 3 not registered");
+ EXPECT_EQ(kHttp2MinStreamWeight, scheduler_.GetStreamPrecedence(3).weight());
}
TEST_F(Http2PriorityWriteSchedulerTest, GetStreamPriority) {
- EXPECT_SPDY_BUG(EXPECT_EQ(kV3LowestPriority,
- scheduler_.GetStreamPrecedence(3).spdy3_priority()),
- "Stream 3 not registered");
+ // Unknown streams tolerated due to b/15676312.
+ EXPECT_EQ(kV3LowestPriority,
+ scheduler_.GetStreamPrecedence(3).spdy3_priority());
scheduler_.RegisterStream(3, SpdyStreamPrecedence(0, 130, true));
EXPECT_EQ(3, scheduler_.GetStreamPrecedence(3).spdy3_priority());
scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(0, 50, true));
EXPECT_EQ(5, scheduler_.GetStreamPrecedence(3).spdy3_priority());
scheduler_.UnregisterStream(3);
- EXPECT_SPDY_BUG(EXPECT_EQ(kV3LowestPriority,
- scheduler_.GetStreamPrecedence(3).spdy3_priority()),
- "Stream 3 not registered");
+ EXPECT_EQ(kV3LowestPriority,
+ scheduler_.GetStreamPrecedence(3).spdy3_priority());
}
TEST_F(Http2PriorityWriteSchedulerTest, GetStreamParent) {
- EXPECT_SPDY_BUG(EXPECT_EQ(kHttp2RootStreamId,
- scheduler_.GetStreamPrecedence(3).parent_id()),
- "Stream 3 not registered");
+ // Unknown streams tolerated due to b/15676312.
+ EXPECT_EQ(kHttp2RootStreamId, scheduler_.GetStreamPrecedence(3).parent_id());
scheduler_.RegisterStream(2, SpdyStreamPrecedence(0, 20, false));
scheduler_.RegisterStream(3, SpdyStreamPrecedence(2, 30, false));
EXPECT_EQ(2u, scheduler_.GetStreamPrecedence(3).parent_id());
scheduler_.UnregisterStream(3);
- EXPECT_SPDY_BUG(EXPECT_EQ(kHttp2RootStreamId,
- scheduler_.GetStreamPrecedence(3).parent_id()),
- "Stream 3 not registered");
+ EXPECT_EQ(kHttp2RootStreamId, scheduler_.GetStreamPrecedence(3).parent_id());
}
TEST_F(Http2PriorityWriteSchedulerTest, GetStreamChildren) {
@@ -182,9 +173,13 @@ TEST_F(Http2PriorityWriteSchedulerTest, UpdateStreamWeight) {
EXPECT_SPDY_BUG(
scheduler_.UpdateStreamPrecedence(0, SpdyStreamPrecedence(0, 10, false)),
"Cannot set precedence of root stream");
- EXPECT_SPDY_BUG(
- scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(0, 10, false)),
- "Stream 3 not registered");
+
+ // For the moment, updating stream precedence on a non-registered stream
+ // should have no effect. In the future, it will lazily cause the stream to
+ // be registered (b/15676312).
+ scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(0, 10, false));
+ EXPECT_FALSE(scheduler_.StreamRegistered(3));
+
scheduler_.RegisterStream(3, SpdyStreamPrecedence(0, 10, false));
scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(0, 20, false));
EXPECT_EQ(20, scheduler_.GetStreamPrecedence(3).weight());
@@ -201,9 +196,6 @@ TEST_F(Http2PriorityWriteSchedulerTest, UpdateStreamWeight) {
ASSERT_TRUE(peer_.ValidateInvariants());
scheduler_.UnregisterStream(3);
- EXPECT_SPDY_BUG(
- scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(0, 10, false)),
- "Stream 3 not registered");
}
// Basic case of reparenting a subtree.
@@ -257,18 +249,28 @@ TEST_F(Http2PriorityWriteSchedulerTest, UpdateStreamParentNonexistent) {
scheduler_.RegisterStream(1, SpdyStreamPrecedence(0, 100, false));
scheduler_.RegisterStream(2, SpdyStreamPrecedence(0, 100, false));
for (bool exclusive : {true, false}) {
- EXPECT_SPDY_BUG(scheduler_.UpdateStreamPrecedence(
- 1, SpdyStreamPrecedence(3, 100, exclusive)),
- "Parent stream 3 not registered");
- EXPECT_SPDY_BUG(scheduler_.UpdateStreamPrecedence(
- 4, SpdyStreamPrecedence(2, 100, exclusive)),
- "Stream 4 not registered");
- EXPECT_SPDY_BUG(scheduler_.UpdateStreamPrecedence(
- 3, SpdyStreamPrecedence(4, 100, exclusive)),
- "Stream 3 not registered");
+ // For the moment, updating stream precedence on a non-registered stream or
+ // attempting to set parent to a nonexistent stream should have no
+ // effect. In the future, it will lazily cause the stream(s) to be
+ // registered (b/15676312).
+
+ // No-op: parent stream 3 not registered
+ scheduler_.UpdateStreamPrecedence(1,
+ SpdyStreamPrecedence(3, 100, exclusive));
+
+ // No-op: stream 4 not registered
+ scheduler_.UpdateStreamPrecedence(4,
+ SpdyStreamPrecedence(2, 100, exclusive));
+
+ // No-op: stream 3 not registered
+ scheduler_.UpdateStreamPrecedence(3,
+ SpdyStreamPrecedence(4, 100, exclusive));
+
EXPECT_THAT(scheduler_.GetStreamChildren(0), UnorderedElementsAre(1, 2));
EXPECT_THAT(scheduler_.GetStreamChildren(1), IsEmpty());
EXPECT_THAT(scheduler_.GetStreamChildren(2), IsEmpty());
+ EXPECT_FALSE(scheduler_.StreamRegistered(3));
+ EXPECT_FALSE(scheduler_.StreamRegistered(4));
}
ASSERT_TRUE(peer_.ValidateInvariants());
}
diff --git a/chromium/net/spdy/priority_write_scheduler.h b/chromium/net/spdy/priority_write_scheduler.h
index 5072f6866b9..2a8276c16c0 100644
--- a/chromium/net/spdy/priority_write_scheduler.h
+++ b/chromium/net/spdy/priority_write_scheduler.h
@@ -47,10 +47,11 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> {
const StreamPrecedenceType& precedence) override {
SPDY_BUG_IF(!precedence.is_spdy3_priority()) << "Expected SPDY priority";
- // parent_id not used here, but may as well validate it
+ // parent_id not used here, but may as well validate it. However,
+ // parent_id may legitimately not be registered yet--see b/15676312.
StreamIdType parent_id = precedence.parent_id();
- SPDY_BUG_IF(parent_id != kHttp2RootStreamId && !StreamRegistered(parent_id))
- << "Stream " << parent_id << " not registered";
+ DVLOG_IF(1, parent_id != kHttp2RootStreamId && !StreamRegistered(parent_id))
+ << "Parent stream " << parent_id << " not registered";
if (stream_id == kHttp2RootStreamId) {
SPDY_BUG << "Stream " << kHttp2RootStreamId << " already registered";
@@ -85,7 +86,7 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> {
StreamIdType stream_id) const override {
auto it = stream_infos_.find(stream_id);
if (it == stream_infos_.end()) {
- SPDY_BUG << "Stream " << stream_id << " not registered";
+ DVLOG(1) << "Stream " << stream_id << " not registered";
return StreamPrecedenceType(kV3LowestPriority);
}
return StreamPrecedenceType(it->second.priority);
@@ -95,14 +96,16 @@ class PriorityWriteScheduler : public WriteScheduler<StreamIdType> {
const StreamPrecedenceType& precedence) override {
SPDY_BUG_IF(!precedence.is_spdy3_priority()) << "Expected SPDY priority";
- // parent_id not used here, but may as well validate it
+ // parent_id not used here, but may as well validate it. However,
+ // parent_id may legitimately not be registered yet--see b/15676312.
StreamIdType parent_id = precedence.parent_id();
- SPDY_BUG_IF(parent_id != kHttp2RootStreamId && !StreamRegistered(parent_id))
- << "Stream " << parent_id << " not registered";
+ DVLOG_IF(1, parent_id != kHttp2RootStreamId && !StreamRegistered(parent_id))
+ << "Parent stream " << parent_id << " not registered";
auto it = stream_infos_.find(stream_id);
if (it == stream_infos_.end()) {
- SPDY_BUG << "Stream " << stream_id << " not registered";
+ // TODO(mpw): add to stream_infos_ on demand--see b/15676312.
+ DVLOG(1) << "Stream " << stream_id << " not registered";
return;
}
StreamInfo& stream_info = it->second;
diff --git a/chromium/net/spdy/priority_write_scheduler_test.cc b/chromium/net/spdy/priority_write_scheduler_test.cc
index 9df27fde132..2a47f889647 100644
--- a/chromium/net/spdy/priority_write_scheduler_test.cc
+++ b/chromium/net/spdy/priority_write_scheduler_test.cc
@@ -83,16 +83,21 @@ TEST_F(PriorityWriteSchedulerTest, RegisterStreamWithHttp2StreamDependency) {
EXPECT_TRUE(scheduler_.GetStreamPrecedence(1).is_spdy3_priority());
EXPECT_EQ(3, scheduler_.GetStreamPrecedence(1).spdy3_priority());
+ // Registering stream with a non-existent parent stream is permissible, but
+ // parent stream will always be reset to 0.
EXPECT_SPDY_BUG(
scheduler_.RegisterStream(2, SpdyStreamPrecedence(3, 123, false)),
"Expected SPDY priority");
EXPECT_TRUE(scheduler_.StreamRegistered(2));
+ EXPECT_FALSE(scheduler_.StreamRegistered(3));
+ EXPECT_EQ(kHttp2RootStreamId, scheduler_.GetStreamPrecedence(2).parent_id());
}
TEST_F(PriorityWriteSchedulerTest, GetStreamPrecedence) {
- EXPECT_SPDY_BUG(EXPECT_EQ(kV3LowestPriority,
- scheduler_.GetStreamPrecedence(1).spdy3_priority()),
- "Stream 1 not registered");
+ // Unknown streams tolerated due to b/15676312. However, return lowest
+ // priority.
+ EXPECT_EQ(kV3LowestPriority,
+ scheduler_.GetStreamPrecedence(1).spdy3_priority());
scheduler_.RegisterStream(1, SpdyStreamPrecedence(3));
EXPECT_TRUE(scheduler_.GetStreamPrecedence(1).is_spdy3_priority());
@@ -121,9 +126,8 @@ TEST_F(PriorityWriteSchedulerTest, GetStreamPrecedence) {
EXPECT_EQ(6, scheduler_.GetStreamPrecedence(1).spdy3_priority());
scheduler_.UnregisterStream(1);
- EXPECT_SPDY_BUG(EXPECT_EQ(kV3LowestPriority,
- scheduler_.GetStreamPrecedence(1).spdy3_priority()),
- "Stream 1 not registered");
+ EXPECT_EQ(kV3LowestPriority,
+ scheduler_.GetStreamPrecedence(1).spdy3_priority());
}
TEST_F(PriorityWriteSchedulerTest, PopNextReadyStreamAndPrecedence) {
@@ -135,15 +139,16 @@ TEST_F(PriorityWriteSchedulerTest, PopNextReadyStreamAndPrecedence) {
}
TEST_F(PriorityWriteSchedulerTest, UpdateStreamPrecedence) {
- // Updating priority of unregistered stream should have no effect.
- EXPECT_SPDY_BUG(EXPECT_EQ(kV3LowestPriority,
- scheduler_.GetStreamPrecedence(3).spdy3_priority()),
- "Stream 3 not registered");
- EXPECT_SPDY_BUG(scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(1)),
- "Stream 3 not registered");
- EXPECT_SPDY_BUG(EXPECT_EQ(kV3LowestPriority,
- scheduler_.GetStreamPrecedence(3).spdy3_priority()),
- "Stream 3 not registered");
+ // For the moment, updating stream precedence on a non-registered stream
+ // should have no effect. In the future, it will lazily cause the stream to
+ // be registered (b/15676312).
+ EXPECT_EQ(kV3LowestPriority,
+ scheduler_.GetStreamPrecedence(3).spdy3_priority());
+ EXPECT_FALSE(scheduler_.StreamRegistered(3));
+ scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(1));
+ EXPECT_FALSE(scheduler_.StreamRegistered(3));
+ EXPECT_EQ(kV3LowestPriority,
+ scheduler_.GetStreamPrecedence(3).spdy3_priority());
scheduler_.RegisterStream(3, SpdyStreamPrecedence(1));
EXPECT_EQ(1, scheduler_.GetStreamPrecedence(3).spdy3_priority());
@@ -172,15 +177,15 @@ TEST_F(PriorityWriteSchedulerTest, UpdateStreamPrecedence) {
EXPECT_EQ(4u, scheduler_.PopNextReadyStream());
scheduler_.UnregisterStream(3);
- EXPECT_SPDY_BUG(scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(1)),
- "Stream 3 not registered");
}
TEST_F(PriorityWriteSchedulerTest,
UpdateStreamPrecedenceWithHttp2StreamDependency) {
+ // Unknown streams tolerated due to b/15676312, but should have no effect.
EXPECT_SPDY_BUG(
scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(0, 100, false)),
"Expected SPDY priority");
+ EXPECT_FALSE(scheduler_.StreamRegistered(3));
scheduler_.RegisterStream(3, SpdyStreamPrecedence(3));
EXPECT_SPDY_BUG(
@@ -192,7 +197,8 @@ TEST_F(PriorityWriteSchedulerTest,
scheduler_.UnregisterStream(3);
EXPECT_SPDY_BUG(
scheduler_.UpdateStreamPrecedence(3, SpdyStreamPrecedence(0, 100, false)),
- "Stream 3 not registered");
+ "Expected SPDY priority");
+ EXPECT_FALSE(scheduler_.StreamRegistered(3));
}
TEST_F(PriorityWriteSchedulerTest, MarkStreamReadyBack) {
diff --git a/chromium/net/spdy/spdy_deframer_visitor.cc b/chromium/net/spdy/spdy_deframer_visitor.cc
new file mode 100644
index 00000000000..e99114fba71
--- /dev/null
+++ b/chromium/net/spdy/spdy_deframer_visitor.cc
@@ -0,0 +1,1112 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/spdy/spdy_deframer_visitor.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+#include <limits>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "net/spdy/hpack/hpack_constants.h"
+#include "net/spdy/mock_spdy_framer_visitor.h"
+#include "net/spdy/spdy_frame_builder.h"
+#include "net/spdy/spdy_frame_reader.h"
+#include "net/spdy/spdy_protocol.h"
+#include "net/spdy/spdy_test_utils.h"
+
+using ::base::MakeUnique;
+using ::base::StringPiece;
+using ::std::string;
+using ::testing::AssertionFailure;
+using ::testing::AssertionResult;
+using ::testing::AssertionSuccess;
+
+namespace net {
+namespace test {
+
+// Specify whether to process headers as request or response in visitor-related
+// params.
+enum class HeaderDirection { REQUEST, RESPONSE };
+
+// Types of HTTP/2 frames, per RFC 7540.
+// TODO(jamessynge): Switch to using //net/http2/http2_constants.h when ready.
+enum Http2FrameType {
+ DATA = 0,
+ HEADERS = 1,
+ PRIORITY = 2,
+ RST_STREAM = 3,
+ SETTINGS = 4,
+ PUSH_PROMISE = 5,
+ PING = 6,
+ GOAWAY = 7,
+ WINDOW_UPDATE = 8,
+ CONTINUATION = 9,
+ ALTSVC = 10,
+
+ // Not a frame type.
+ UNSET = -1,
+ UNKNOWN = -2,
+};
+
+// TODO(jamessynge): Switch to using //net/http2/http2_constants.h when ready.
+const char* Http2FrameTypeToString(Http2FrameType v) {
+ switch (v) {
+ case DATA:
+ return "DATA";
+ case HEADERS:
+ return "HEADERS";
+ case PRIORITY:
+ return "PRIORITY";
+ case RST_STREAM:
+ return "RST_STREAM";
+ case SETTINGS:
+ return "SETTINGS";
+ case PUSH_PROMISE:
+ return "PUSH_PROMISE";
+ case PING:
+ return "PING";
+ case GOAWAY:
+ return "GOAWAY";
+ case WINDOW_UPDATE:
+ return "WINDOW_UPDATE";
+ case CONTINUATION:
+ return "CONTINUATION";
+ case ALTSVC:
+ return "ALTSVC";
+ case UNSET:
+ return "UNSET";
+ case UNKNOWN:
+ return "UNKNOWN";
+ default:
+ return "Invalid Http2FrameType";
+ }
+}
+
+// TODO(jamessynge): Switch to using //net/http2/http2_constants.h when ready.
+inline std::ostream& operator<<(std::ostream& out, Http2FrameType v) {
+ return out << Http2FrameTypeToString(v);
+}
+
+// Flag bits in the flag field of the common header of HTTP/2 frames
+// (see https://httpwg.github.io/specs/rfc7540.html#FrameHeader for details on
+// the fixed 9-octet header structure shared by all frames).
+// Flag bits are only valid for specified frame types.
+// TODO(jamessynge): Switch to using //net/http2/http2_constants.h when ready.
+enum Http2HeaderFlag {
+ NO_FLAGS = 0,
+
+ END_STREAM_FLAG = 0x1,
+ ACK_FLAG = 0x1,
+ END_HEADERS_FLAG = 0x4,
+ PADDED_FLAG = 0x8,
+ PRIORITY_FLAG = 0x20,
+};
+
+// Returns name of frame type.
+// TODO(jamessynge): Switch to using //net/http2/http2_constants.h when ready.
+const char* Http2FrameTypeToString(Http2FrameType v);
+
+void SpdyDeframerVisitorInterface::OnPingAck(
+ std::unique_ptr<SpdyPingIR> frame) {
+ OnPing(std::move(frame));
+}
+
+void SpdyDeframerVisitorInterface::OnSettingsAck(
+ std::unique_ptr<SpdySettingsIR> frame) {
+ OnSettings(std::move(frame), nullptr);
+}
+
+class SpdyTestDeframerImpl : public SpdyTestDeframer,
+ public SpdyHeadersHandlerInterface {
+ public:
+ explicit SpdyTestDeframerImpl(
+ std::unique_ptr<SpdyDeframerVisitorInterface> listener)
+ : listener_(std::move(listener)) {
+ CHECK(listener_);
+ }
+ ~SpdyTestDeframerImpl() override {}
+
+ bool AtFrameEnd() override;
+
+ // Callbacks defined in SpdyFramerVisitorInterface. These are in the
+ // alphabetical order for ease of navigation, and are not in same order
+ // as in SpdyFramerVisitorInterface.
+ void OnAltSvc(SpdyStreamId stream_id,
+ StringPiece origin,
+ const SpdyAltSvcWireFormat::AlternativeServiceVector&
+ altsvc_vector) override;
+ void OnBlocked(SpdyStreamId stream_id) override;
+ void OnContinuation(SpdyStreamId stream_id, bool end) override;
+ SpdyHeadersHandlerInterface* OnHeaderFrameStart(
+ SpdyStreamId stream_id) override;
+ void OnHeaderFrameEnd(SpdyStreamId stream_id, bool end_headers) override;
+ bool OnControlFrameHeaderData(SpdyStreamId stream_id,
+ const char* header_data,
+ size_t header_data_len) override;
+ void OnDataFrameHeader(SpdyStreamId stream_id,
+ size_t length,
+ bool fin) override;
+ void OnError(SpdyFramer* framer) override;
+ void OnGoAway(SpdyStreamId last_accepted_stream_id,
+ SpdyGoAwayStatus status) override;
+ bool OnGoAwayFrameData(const char* goaway_data, size_t len) override;
+ void OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ int weight,
+ SpdyStreamId parent_stream_id,
+ bool exclusive,
+ bool fin,
+ bool end) override;
+ void OnPing(SpdyPingId unique_id, bool is_ack) override;
+ void OnPriority(SpdyStreamId stream_id,
+ SpdyStreamId parent_stream_id,
+ int weight,
+ bool exclusive) override;
+ void OnPushPromise(SpdyStreamId stream_id,
+ SpdyStreamId promised_stream_id,
+ bool end) override;
+ void OnRstStream(SpdyStreamId stream_id, SpdyRstStreamStatus status) override;
+ bool OnRstStreamFrameData(const char* rst_stream_data, size_t len) override;
+ void OnSetting(SpdySettingsIds id, uint8_t flags, uint32_t value) override;
+ void OnSettings(bool clear_persisted) override;
+ void OnSettingsAck() override;
+ void OnSettingsEnd() override;
+ void OnStreamFrameData(SpdyStreamId stream_id,
+ const char* data,
+ size_t len) override;
+ void OnStreamEnd(SpdyStreamId stream_id) override;
+ void OnStreamPadding(SpdyStreamId stream_id, size_t len) override;
+ void OnSynReply(SpdyStreamId stream_id, bool fin) override;
+ void OnSynStream(SpdyStreamId stream_id,
+ SpdyStreamId associated_stream_id,
+ SpdyPriority priority,
+ bool fin,
+ bool unidirectional) override;
+ bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override;
+ void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override;
+
+ // Callbacks defined in SpdyHeadersHandlerInterface.
+
+ void OnHeaderBlockStart() override;
+ void OnHeader(StringPiece key, StringPiece value) override;
+ void OnHeaderBlockEnd(size_t header_bytes_parsed) override;
+ void OnHeaderBlockEnd(size_t header_bytes_parsed,
+ size_t compressed_header_bytes_parsed) override;
+
+ protected:
+ void AtDataEnd();
+ void AtGoAwayEnd();
+ void AtHeadersEnd();
+ void AtPushPromiseEnd();
+
+ // Per-physical frame state.
+ // Frame type of the frame currently being processed.
+ Http2FrameType frame_type_ = UNSET;
+ // Stream id of the frame currently being processed.
+ SpdyStreamId stream_id_;
+ // Did the most recent frame header include the END_HEADERS flag?
+ bool end_ = false;
+ // Did the most recent frame header include the ack flag?
+ bool ack_ = false;
+
+ // Per-HPACK block state. Only valid while processing a HEADERS or
+ // PUSH_PROMISE frame, and its CONTINUATION frames.
+ // Did the most recent HEADERS or PUSH_PROMISE include the END_STREAM flag?
+ // Note that this does not necessarily indicate that the current frame is
+ // the last frame for the stream (may be followed by CONTINUATION frames,
+ // may only half close).
+ bool fin_ = false;
+ bool got_hpack_end_ = false;
+
+ std::unique_ptr<string> data_;
+
+ // Total length of the data frame.
+ size_t data_len_ = 0;
+
+ // Amount of skipped padding (i.e. total length of padding, including Pad
+ // Length field).
+ size_t padding_len_ = 0;
+
+ std::unique_ptr<string> goaway_description_;
+ std::unique_ptr<StringPairVector> headers_;
+ std::unique_ptr<SettingVector> settings_;
+ std::unique_ptr<TestHeadersHandler> headers_handler_;
+
+ std::unique_ptr<SpdyGoAwayIR> goaway_ir_;
+ std::unique_ptr<SpdyHeadersIR> headers_ir_;
+ std::unique_ptr<SpdyPushPromiseIR> push_promise_ir_;
+ std::unique_ptr<SpdySettingsIR> settings_ir_;
+
+ private:
+ std::unique_ptr<SpdyDeframerVisitorInterface> listener_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpdyTestDeframerImpl);
+};
+
+// static
+std::unique_ptr<SpdyTestDeframer> SpdyTestDeframer::CreateConverter(
+ std::unique_ptr<SpdyDeframerVisitorInterface> listener) {
+ return MakeUnique<SpdyTestDeframerImpl>(std::move(listener));
+}
+
+void SpdyTestDeframerImpl::AtDataEnd() {
+ DVLOG(1) << "AtDataEnd";
+ CHECK_EQ(data_len_, padding_len_ + data_->size());
+ auto ptr = MakeUnique<SpdyDataIR>(stream_id_, std::move(*data_));
+ CHECK_EQ(0u, data_->size());
+ data_.reset();
+
+ CHECK_LE(0u, padding_len_);
+ CHECK_LE(padding_len_, 256u);
+ if (padding_len_ > 0) {
+ ptr->set_padding_len(padding_len_);
+ }
+ padding_len_ = 0;
+
+ ptr->set_fin(fin_);
+ listener_->OnData(std::move(ptr));
+ frame_type_ = UNSET;
+ fin_ = false;
+ data_len_ = 0;
+}
+
+void SpdyTestDeframerImpl::AtGoAwayEnd() {
+ DVLOG(1) << "AtDataEnd";
+ CHECK_EQ(frame_type_, GOAWAY);
+ CHECK(goaway_description_);
+ if (goaway_description_->empty()) {
+ listener_->OnGoAway(std::move(goaway_ir_));
+ } else {
+ listener_->OnGoAway(MakeUnique<SpdyGoAwayIR>(
+ goaway_ir_->last_good_stream_id(), goaway_ir_->status(),
+ std::move(*goaway_description_)));
+ CHECK_EQ(0u, goaway_description_->size());
+ }
+ goaway_description_.reset();
+ goaway_ir_.reset();
+ frame_type_ = UNSET;
+}
+
+void SpdyTestDeframerImpl::AtHeadersEnd() {
+ DVLOG(1) << "AtDataEnd";
+ CHECK(frame_type_ == HEADERS || frame_type_ == CONTINUATION)
+ << " frame_type_=" << Http2FrameTypeToString(frame_type_);
+ CHECK(end_) << " frame_type_=" << Http2FrameTypeToString(frame_type_);
+ CHECK(got_hpack_end_);
+
+ CHECK(headers_ir_);
+ CHECK(headers_);
+ CHECK(headers_handler_);
+
+ CHECK_LE(0u, padding_len_);
+ CHECK_LE(padding_len_, 256u);
+ if (padding_len_ > 0) {
+ headers_ir_->set_padding_len(padding_len_);
+ }
+ padding_len_ = 0;
+
+ headers_ir_->set_header_block(headers_handler_->decoded_block().Clone());
+ headers_handler_.reset();
+ listener_->OnHeaders(std::move(headers_ir_), std::move(headers_));
+
+ frame_type_ = UNSET;
+ fin_ = false;
+ end_ = false;
+ got_hpack_end_ = false;
+}
+
+void SpdyTestDeframerImpl::AtPushPromiseEnd() {
+ DVLOG(1) << "AtDataEnd";
+ CHECK(frame_type_ == PUSH_PROMISE || frame_type_ == CONTINUATION)
+ << " frame_type_=" << Http2FrameTypeToString(frame_type_);
+ CHECK(end_) << " frame_type_=" << Http2FrameTypeToString(frame_type_);
+
+ CHECK(push_promise_ir_);
+ CHECK(headers_);
+ CHECK(headers_handler_);
+
+ CHECK_EQ(headers_ir_.get(), nullptr);
+
+ CHECK_LE(0u, padding_len_);
+ CHECK_LE(padding_len_, 256u);
+ if (padding_len_ > 0) {
+ push_promise_ir_->set_padding_len(padding_len_);
+ }
+ padding_len_ = 0;
+
+ push_promise_ir_->set_header_block(headers_handler_->decoded_block().Clone());
+ headers_handler_.reset();
+ listener_->OnPushPromise(std::move(push_promise_ir_), std::move(headers_));
+
+ frame_type_ = UNSET;
+ end_ = false;
+}
+
+bool SpdyTestDeframerImpl::AtFrameEnd() {
+ bool incomplete_logical_header = false;
+ // The caller says that the SpdyFrame has reached the end of the frame,
+ // so if we have any accumulated data, flush it.
+ switch (frame_type_) {
+ case DATA:
+ AtDataEnd();
+ break;
+
+ case GOAWAY:
+ AtGoAwayEnd();
+ break;
+
+ case HEADERS:
+ if (end_) {
+ AtHeadersEnd();
+ } else {
+ incomplete_logical_header = true;
+ }
+ break;
+
+ case PUSH_PROMISE:
+ if (end_) {
+ AtPushPromiseEnd();
+ } else {
+ incomplete_logical_header = true;
+ }
+ break;
+
+ case CONTINUATION:
+ if (end_) {
+ if (headers_ir_) {
+ AtHeadersEnd();
+ } else if (push_promise_ir_) {
+ AtPushPromiseEnd();
+ } else {
+ LOG(FATAL) << "Where is the SpdyFrameIR for the headers!";
+ }
+ } else {
+ incomplete_logical_header = true;
+ }
+ break;
+
+ case UNSET:
+ // Except for the frame types above, the others don't leave any record
+ // in the state of this object. Make sure nothing got left by accident.
+ CHECK_EQ(data_.get(), nullptr);
+ CHECK_EQ(goaway_description_.get(), nullptr);
+ CHECK_EQ(goaway_ir_.get(), nullptr);
+ CHECK_EQ(headers_.get(), nullptr);
+ CHECK_EQ(headers_handler_.get(), nullptr);
+ CHECK_EQ(headers_ir_.get(), nullptr);
+ CHECK_EQ(push_promise_ir_.get(), nullptr);
+ CHECK_EQ(settings_.get(), nullptr);
+ CHECK_EQ(settings_ir_.get(), nullptr);
+ break;
+
+ default:
+ SPDY_BUG << "Expected UNSET, instead frame_type_==" << frame_type_;
+ return false;
+ }
+ frame_type_ = UNSET;
+ stream_id_ = 0;
+ end_ = false;
+ ack_ = false;
+ if (!incomplete_logical_header) {
+ fin_ = false;
+ }
+ return true;
+}
+
+// Overridden methods from SpdyFramerVisitorInterface in alpha order...
+
+void SpdyTestDeframerImpl::OnAltSvc(
+ SpdyStreamId stream_id,
+ StringPiece origin,
+ const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) {
+ DVLOG(1) << "OnAltSvc stream_id: " << stream_id;
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ CHECK_GT(stream_id, 0u);
+ auto ptr = MakeUnique<SpdyAltSvcIR>(stream_id);
+ ptr->set_origin(origin.as_string());
+ for (auto& altsvc : altsvc_vector) {
+ ptr->add_altsvc(altsvc);
+ }
+ listener_->OnAltSvc(std::move(ptr));
+}
+
+// Frame type BLOCKED was removed in draft 12 of HTTP/2. The intent appears to
+// have been to support debugging; it is not expected to be seen except if the
+// peer "thinks" that a bug exists in the flow control such that the peer can't
+// send because the receiver hasn't sent WINDOW_UPDATE frames. Since we might
+// be talking to multiple backends, it is quite plausible that one backend
+// is unable to take more input from the client (hence no WINDOW_UPDATE), yet
+// other backends can take more input.
+void SpdyTestDeframerImpl::OnBlocked(SpdyStreamId stream_id) {
+ LOG(FATAL) << "OnBlocked stream_id: " << stream_id;
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ CHECK_GT(stream_id, 0u);
+ frame_type_ = UNSET;
+ stream_id_ = stream_id;
+}
+
+// A CONTINUATION frame contains a Header Block Fragment, and immediately
+// follows another frame that contains a Header Block Fragment (HEADERS,
+// PUSH_PROMISE or CONTINUATION). The last such frame has the END flag set.
+// SpdyFramer ensures that the behavior is correct before calling the visitor.
+void SpdyTestDeframerImpl::OnContinuation(SpdyStreamId stream_id, bool end) {
+ DVLOG(1) << "OnContinuation stream_id: " << stream_id;
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ CHECK_GT(stream_id, 0u);
+ CHECK_NE(nullptr, headers_.get());
+ frame_type_ = CONTINUATION;
+
+ stream_id_ = stream_id;
+ end_ = end;
+}
+
+// Called with the decompressed contents of headers, in zero or more pieces
+// (i.e. an empty headers frame doesn't have any non-zero length data).
+// Note that the end of the headers is indicated by header_data==nullptr
+// AND header_data_len==0, even if there were no non-zero pieces.
+// SpdyHeadersBlockParser decodes these.
+// Returning false kills the connection (SpdyFramer enters state SPDY_ERROR).
+bool SpdyTestDeframerImpl::OnControlFrameHeaderData(SpdyStreamId stream_id,
+ const char* header_data,
+ size_t header_data_len) {
+ DVLOG(1) << "OnControlFrameHeaderData stream_id: " << stream_id
+ << " len: " << header_data_len;
+ CHECK(frame_type_ == HEADERS || frame_type_ == CONTINUATION ||
+ frame_type_ == PUSH_PROMISE)
+ << " frame_type_=" << Http2FrameTypeToString(frame_type_);
+ CHECK_EQ(stream_id_, stream_id);
+ LOG(FATAL) << "Must call SpdyFramer::set_use_new_methods_for_test(true)";
+ return true;
+}
+
+// Note that length includes the padding length (0 to 256, when the optional
+// padding length field is counted). Padding comes after the payload, both
+// for DATA frames and for control frames.
+void SpdyTestDeframerImpl::OnDataFrameHeader(SpdyStreamId stream_id,
+ size_t length,
+ bool fin) {
+ DVLOG(1) << "OnDataFrameHeader stream_id: " << stream_id;
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ CHECK_GT(stream_id, 0u);
+ CHECK_EQ(data_.get(), nullptr);
+ frame_type_ = DATA;
+
+ stream_id_ = stream_id;
+ fin_ = fin;
+ data_len_ = length;
+ data_.reset(new string());
+}
+
+// The SpdyFramer will not process any more data at this point.
+void SpdyTestDeframerImpl::OnError(SpdyFramer* framer) {
+ DVLOG(1) << "SpdyFramer detected an error in the stream: "
+ << SpdyFramer::ErrorCodeToString(framer->error_code())
+ << " frame_type_: " << Http2FrameTypeToString(frame_type_);
+ listener_->OnError(framer, this);
+}
+
+// Received a GOAWAY frame from the peer. The last stream id it accepted from us
+// is |last_accepted_stream_id|. |status| is a protocol defined error code.
+// The frame may also contain data. After this OnGoAwayFrameData will be called
+// for any non-zero amount of data, and after that it will be called with len==0
+// to indicate the end of the GOAWAY frame.
+void SpdyTestDeframerImpl::OnGoAway(SpdyStreamId last_good_stream_id,
+ SpdyGoAwayStatus status) {
+ DVLOG(1) << "OnGoAway last_good_stream_id: " << last_good_stream_id
+ << " status: " << status;
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ frame_type_ = GOAWAY;
+ goaway_ir_ = MakeUnique<SpdyGoAwayIR>(last_good_stream_id, status, "");
+ goaway_description_.reset(new string());
+}
+
+// If len==0 then we've reached the end of the GOAWAY frame.
+bool SpdyTestDeframerImpl::OnGoAwayFrameData(const char* goaway_data,
+ size_t len) {
+ DVLOG(1) << "OnGoAwayFrameData";
+ CHECK_EQ(frame_type_, GOAWAY) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ CHECK(goaway_description_);
+ StringPiece(goaway_data, len).AppendToString(goaway_description_.get());
+ return true;
+}
+
+SpdyHeadersHandlerInterface* SpdyTestDeframerImpl::OnHeaderFrameStart(
+ SpdyStreamId stream_id) {
+ return this;
+}
+
+void SpdyTestDeframerImpl::OnHeaderFrameEnd(SpdyStreamId stream_id,
+ bool end_headers) {
+ DVLOG(1) << "OnHeaderFrameEnd stream_id: " << stream_id
+ << " end_headers: " << (end_headers ? "true" : "false");
+}
+
+// Received the fixed portion of a HEADERS frame. Called before the variable
+// length (including zero length) Header Block Fragment is processed. If fin
+// is true then there will be no DATA or trailing HEADERS after this HEADERS
+// frame.
+// If end is true, then there will be no CONTINUATION frame(s) following this
+// frame; else if true then there will be CONTINATION frames(s) immediately
+// following this frame, terminated by a CONTINUATION frame with end==true.
+void SpdyTestDeframerImpl::OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ int weight,
+ SpdyStreamId parent_stream_id,
+ bool exclusive,
+ bool fin,
+ bool end) {
+ DVLOG(1) << "OnHeaders stream_id: " << stream_id;
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ CHECK_GT(stream_id, 0u);
+ frame_type_ = HEADERS;
+
+ stream_id_ = stream_id;
+ fin_ = fin;
+ end_ = end;
+
+ headers_.reset(new StringPairVector());
+ headers_handler_.reset(new TestHeadersHandler());
+ headers_ir_ = MakeUnique<SpdyHeadersIR>(stream_id);
+ headers_ir_->set_fin(fin);
+ if (has_priority) {
+ headers_ir_->set_has_priority(true);
+ headers_ir_->set_weight(weight);
+ headers_ir_->set_parent_stream_id(parent_stream_id);
+ headers_ir_->set_exclusive(exclusive);
+ }
+}
+
+// The HTTP/2 protocol refers to the payload, |unique_id| here, as 8 octets of
+// opaque data that is to be echoed back to the sender, with the ACK bit added.
+// It isn't defined as a counter,
+// or frame id, as the SpdyPingId naming might imply.
+// Responding to a PING is supposed to be at the highest priority.
+void SpdyTestDeframerImpl::OnPing(uint64_t unique_id, bool is_ack) {
+ DVLOG(1) << "OnPing unique_id: " << unique_id
+ << " is_ack: " << (is_ack ? "true" : "false");
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ auto ptr = MakeUnique<SpdyPingIR>(unique_id);
+ if (is_ack) {
+ ptr->set_is_ack(is_ack);
+ listener_->OnPingAck(std::move(ptr));
+ } else {
+ listener_->OnPing(std::move(ptr));
+ }
+}
+
+void SpdyTestDeframerImpl::OnPriority(SpdyStreamId stream_id,
+ SpdyStreamId parent_stream_id,
+ int weight,
+ bool exclusive) {
+ DVLOG(1) << "OnPriority stream_id: " << stream_id;
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ CHECK_GT(stream_id, 0u);
+
+ listener_->OnPriority(MakeUnique<SpdyPriorityIR>(stream_id, parent_stream_id,
+ weight, exclusive));
+}
+
+void SpdyTestDeframerImpl::OnPushPromise(SpdyStreamId stream_id,
+ SpdyStreamId promised_stream_id,
+ bool end) {
+ DVLOG(1) << "OnPushPromise stream_id: " << stream_id;
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ CHECK_GT(stream_id, 0u);
+
+ frame_type_ = PUSH_PROMISE;
+ stream_id_ = stream_id;
+ end_ = end;
+
+ headers_.reset(new StringPairVector());
+ headers_handler_.reset(new TestHeadersHandler());
+ push_promise_ir_ =
+ MakeUnique<SpdyPushPromiseIR>(stream_id, promised_stream_id);
+}
+
+// Closes the specified stream. After this the sender may still send PRIORITY
+// frames for this stream, which we can ignore.
+void SpdyTestDeframerImpl::OnRstStream(SpdyStreamId stream_id,
+ SpdyRstStreamStatus status) {
+ DVLOG(1) << "OnRstStream stream_id: " << stream_id
+ << " status: " << status;
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ CHECK_GT(stream_id, 0u);
+
+ listener_->OnRstStream(MakeUnique<SpdyRstStreamIR>(stream_id, status));
+}
+
+// The HTTP/2 spec states that there is no data in the frame other that the
+// SpdyRstStreamStatus passed to OnRstStream, so it appears that SpdyFramer's
+// comments w.r.t. this method are obsolete. We still receive a zero length
+// invocation when RST_STREAM frame processing completes.
+bool SpdyTestDeframerImpl::OnRstStreamFrameData(const char* rst_stream_data,
+ size_t len) {
+ DVLOG(1) << "OnRstStreamFrameData";
+ CHECK_EQ(0u, len);
+ return true;
+}
+
+// Called for an individual setting. There is no negotiation, the sender is
+// stating the value that the sender is using.
+void SpdyTestDeframerImpl::OnSetting(SpdySettingsIds id,
+ uint8_t flags,
+ uint32_t value) {
+ DVLOG(1) << "OnSetting id: " << id << std::hex << " flags: " << flags
+ << " value: " << value;
+ CHECK_EQ(frame_type_, SETTINGS) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ CHECK(settings_);
+ settings_->push_back(std::make_pair(id, value));
+ settings_ir_->AddSetting(id, true, true, value);
+}
+
+// Called at the start of a SETTINGS frame with setting entries, but not the
+// (required) ACK of a SETTINGS frame. There is no stream_id because
+// the settings apply to the entire connection, not to an individual stream.
+// The |clear_persisted| flag is a pre-HTTP/2 remnant.
+void SpdyTestDeframerImpl::OnSettings(bool /*clear_persisted*/) {
+ DVLOG(1) << "OnSettings";
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ CHECK_EQ(nullptr, settings_ir_.get());
+ CHECK_EQ(nullptr, settings_.get());
+ frame_type_ = SETTINGS;
+ ack_ = false;
+
+ settings_.reset(new SettingVector());
+ settings_ir_.reset(new SpdySettingsIR());
+}
+
+void SpdyTestDeframerImpl::OnSettingsAck() {
+ DVLOG(1) << "OnSettingsAck";
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ auto ptr = MakeUnique<SpdySettingsIR>();
+ ptr->set_is_ack(true);
+ listener_->OnSettingsAck(std::move(ptr));
+}
+
+void SpdyTestDeframerImpl::OnSettingsEnd() {
+ DVLOG(1) << "OnSettingsEnd";
+ CHECK_EQ(frame_type_, SETTINGS) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ CHECK(!ack_);
+ CHECK_NE(nullptr, settings_ir_.get());
+ CHECK_NE(nullptr, settings_.get());
+ listener_->OnSettings(std::move(settings_ir_), std::move(settings_));
+ frame_type_ = UNSET;
+}
+
+// Called for a zero length DATA frame with the END_STREAM flag set, or at the
+// end a complete HPACK block (and its padding) that started with a HEADERS
+// frame with the END_STREAM flag set. Doesn't apply to PUSH_PROMISE frames
+// because they don't have END_STREAM flags.
+void SpdyTestDeframerImpl::OnStreamEnd(SpdyStreamId stream_id) {
+ DVLOG(1) << "OnStreamEnd stream_id: " << stream_id;
+ CHECK_EQ(stream_id_, stream_id);
+ CHECK(frame_type_ == DATA || frame_type_ == HEADERS ||
+ frame_type_ == CONTINUATION)
+ << " frame_type_=" << Http2FrameTypeToString(frame_type_);
+ CHECK(fin_);
+}
+
+// The data arg points into the non-padding payload of a DATA frame.
+// This must be a DATA frame (i.e. this method will not be
+// called for HEADERS or CONTINUATION frames).
+// This method may be called multiple times for a single DATA frame, depending
+// upon buffer boundaries.
+void SpdyTestDeframerImpl::OnStreamFrameData(SpdyStreamId stream_id,
+ const char* data,
+ size_t len) {
+ DVLOG(1) << "OnStreamFrameData stream_id: " << stream_id
+ << " len: " << len;
+ CHECK_EQ(stream_id_, stream_id);
+ CHECK_EQ(frame_type_, DATA);
+ StringPiece(data, len).AppendToString(data_.get());
+}
+
+// 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
+// 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;
+ CHECK(frame_type_ == DATA || frame_type_ == HEADERS ||
+ frame_type_ == PUSH_PROMISE)
+ << " frame_type_=" << Http2FrameTypeToString(frame_type_);
+ CHECK_EQ(stream_id_, stream_id);
+ CHECK_LE(1u, len);
+ CHECK_GE(255u, len);
+ padding_len_ += len;
+ CHECK_LE(padding_len_, 256u) << "len=" << len;
+}
+
+// Obsolete.
+void SpdyTestDeframerImpl::OnSynStream(SpdyStreamId stream_id,
+ SpdyStreamId associated_stream_id,
+ SpdyPriority priority,
+ bool fin,
+ bool unidirectional) {
+ DVLOG(1) << "OnSynStream stream_id: " << stream_id;
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ frame_type_ = UNKNOWN;
+ stream_id_ = stream_id;
+ fin_ = fin;
+ LOG(DFATAL) << "SYN_STREAM is not a valid HTTP/2 frame type.";
+}
+
+// Obsolete.
+void SpdyTestDeframerImpl::OnSynReply(SpdyStreamId stream_id, bool fin) {
+ DVLOG(1) << "OnSynReply stream_id: " << stream_id;
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ frame_type_ = UNKNOWN;
+ stream_id_ = stream_id;
+ fin_ = fin;
+ LOG(DFATAL) << "SYN_REPLY is not a valid HTTP/2 frame type.";
+}
+
+// WINDOW_UPDATE is supposed to be hop-by-hop, according to the spec.
+// stream_id is 0 if the update applies to the connection, else stream_id
+// will be the id of a stream previously seen, which maybe half or fully
+// closed.
+void SpdyTestDeframerImpl::OnWindowUpdate(SpdyStreamId stream_id,
+ int delta_window_size) {
+ DVLOG(1) << "OnWindowUpdate stream_id: " << stream_id
+ << " delta_window_size: " << delta_window_size;
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ CHECK_NE(0, delta_window_size);
+
+ listener_->OnWindowUpdate(
+ MakeUnique<SpdyWindowUpdateIR>(stream_id, delta_window_size));
+}
+
+// Return true to indicate that the stream_id is valid; if not valid then
+// SpdyFramer considers the connection corrupted. Requires keeping track
+// of the set of currently open streams. For now we'll assume that unknown
+// frame types are unsupported.
+bool SpdyTestDeframerImpl::OnUnknownFrame(SpdyStreamId stream_id,
+ int frame_type) {
+ DVLOG(1) << "OnAltSvc stream_id: " << stream_id;
+ CHECK_EQ(frame_type_, UNSET) << " frame_type_="
+ << Http2FrameTypeToString(frame_type_);
+ frame_type_ = UNKNOWN;
+
+ stream_id_ = stream_id;
+ return false;
+}
+
+// Callbacks defined in SpdyHeadersHandlerInterface.
+
+void SpdyTestDeframerImpl::OnHeaderBlockStart() {
+ CHECK(frame_type_ == HEADERS || frame_type_ == PUSH_PROMISE)
+ << " frame_type_=" << Http2FrameTypeToString(frame_type_);
+ CHECK(headers_);
+ CHECK_EQ(0u, headers_->size());
+ got_hpack_end_ = false;
+}
+
+void SpdyTestDeframerImpl::OnHeader(StringPiece key, StringPiece value) {
+ CHECK(frame_type_ == HEADERS || frame_type_ == CONTINUATION ||
+ frame_type_ == PUSH_PROMISE)
+ << " frame_type_=" << Http2FrameTypeToString(frame_type_);
+ CHECK(!got_hpack_end_);
+ CHECK(headers_);
+ headers_->emplace_back(key.as_string(), value.as_string());
+ CHECK(headers_handler_);
+ headers_handler_->OnHeader(key, value);
+}
+
+void SpdyTestDeframerImpl::OnHeaderBlockEnd(size_t header_bytes_parsed) {
+ CHECK(headers_);
+ CHECK(frame_type_ == HEADERS || frame_type_ == CONTINUATION ||
+ frame_type_ == PUSH_PROMISE)
+ << " frame_type_=" << Http2FrameTypeToString(frame_type_);
+ CHECK(end_);
+ CHECK(!got_hpack_end_);
+ got_hpack_end_ = true;
+}
+
+void SpdyTestDeframerImpl::OnHeaderBlockEnd(
+ size_t /* header_bytes_parsed */,
+ size_t /* compressed_header_bytes_parsed */) {
+ CHECK(headers_);
+ CHECK(frame_type_ == HEADERS || frame_type_ == CONTINUATION ||
+ frame_type_ == PUSH_PROMISE)
+ << " frame_type_=" << Http2FrameTypeToString(frame_type_);
+ CHECK(end_);
+ CHECK(!got_hpack_end_);
+ got_hpack_end_ = true;
+}
+
+class LoggingSpdyDeframerDelegate : public SpdyDeframerVisitorInterface {
+ public:
+ explicit LoggingSpdyDeframerDelegate(
+ std::unique_ptr<SpdyDeframerVisitorInterface> wrapped)
+ : wrapped_(std::move(wrapped)) {
+ if (!wrapped_) {
+ wrapped_ = MakeUnique<SpdyDeframerVisitorInterface>();
+ }
+ }
+ ~LoggingSpdyDeframerDelegate() override {}
+
+ void OnAltSvc(std::unique_ptr<SpdyAltSvcIR> frame) override {
+ DVLOG(1) << "LoggingSpdyDeframerDelegate::OnAltSvc";
+ wrapped_->OnAltSvc(std::move(frame));
+ }
+ void OnData(std::unique_ptr<SpdyDataIR> frame) override {
+ DVLOG(1) << "LoggingSpdyDeframerDelegate::OnData";
+ wrapped_->OnData(std::move(frame));
+ }
+ void OnGoAway(std::unique_ptr<SpdyGoAwayIR> frame) override {
+ DVLOG(1) << "LoggingSpdyDeframerDelegate::OnGoAway";
+ wrapped_->OnGoAway(std::move(frame));
+ }
+
+ // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which
+ // significantly modifies the headers, so the actual header entries (name
+ // and value strings) are provided in a vector.
+ void OnHeaders(std::unique_ptr<SpdyHeadersIR> frame,
+ std::unique_ptr<StringPairVector> headers) override {
+ DVLOG(1) << "LoggingSpdyDeframerDelegate::OnHeaders";
+ wrapped_->OnHeaders(std::move(frame), std::move(headers));
+ }
+
+ void OnPing(std::unique_ptr<SpdyPingIR> frame) override {
+ DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPing";
+ wrapped_->OnPing(std::move(frame));
+ }
+ void OnPingAck(std::unique_ptr<SpdyPingIR> frame) override {
+ DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPingAck";
+ wrapped_->OnPingAck(std::move(frame));
+ }
+
+ void OnPriority(std::unique_ptr<SpdyPriorityIR> frame) override {
+ DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPriority";
+ wrapped_->OnPriority(std::move(frame));
+ }
+
+ // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which
+ // significantly modifies the headers, so the actual header entries (name
+ // and value strings) are provided in a vector.
+ void OnPushPromise(std::unique_ptr<SpdyPushPromiseIR> frame,
+ std::unique_ptr<StringPairVector> headers) override {
+ DVLOG(1) << "LoggingSpdyDeframerDelegate::OnPushPromise";
+ wrapped_->OnPushPromise(std::move(frame), std::move(headers));
+ }
+
+ void OnRstStream(std::unique_ptr<SpdyRstStreamIR> frame) override {
+ DVLOG(1) << "LoggingSpdyDeframerDelegate::OnRstStream";
+ wrapped_->OnRstStream(std::move(frame));
+ }
+
+ // SpdySettingsIR has a map for settings, so loses info about the order of
+ // settings, and whether the same setting appeared more than once, so the
+ // the actual settings (parameter and value) are provided in a vector.
+ void OnSettings(std::unique_ptr<SpdySettingsIR> frame,
+ std::unique_ptr<SettingVector> settings) override {
+ DVLOG(1) << "LoggingSpdyDeframerDelegate::OnSettings";
+ wrapped_->OnSettings(std::move(frame), std::move(settings));
+ }
+
+ // A settings frame with an ACK has no content, but for uniformity passing
+ // a frame with the ACK flag set.
+ void OnSettingsAck(std::unique_ptr<SpdySettingsIR> frame) override {
+ DVLOG(1) << "LoggingSpdyDeframerDelegate::OnSettingsAck";
+ wrapped_->OnSettingsAck(std::move(frame));
+ }
+
+ void OnWindowUpdate(std::unique_ptr<SpdyWindowUpdateIR> frame) override {
+ DVLOG(1) << "LoggingSpdyDeframerDelegate::OnWindowUpdate";
+ wrapped_->OnWindowUpdate(std::move(frame));
+ }
+
+ // The SpdyFramer will not process any more data at this point.
+ void OnError(SpdyFramer* framer, SpdyTestDeframer* deframer) override {
+ DVLOG(1) << "LoggingSpdyDeframerDelegate::OnError";
+ wrapped_->OnError(framer, deframer);
+ }
+
+ private:
+ std::unique_ptr<SpdyDeframerVisitorInterface> wrapped_;
+};
+
+// static
+std::unique_ptr<SpdyDeframerVisitorInterface>
+SpdyDeframerVisitorInterface::LogBeforeVisiting(
+ std::unique_ptr<SpdyDeframerVisitorInterface> wrapped_listener) {
+ return MakeUnique<LoggingSpdyDeframerDelegate>(std::move(wrapped_listener));
+}
+
+CollectedFrame::CollectedFrame() {}
+
+CollectedFrame::CollectedFrame(CollectedFrame&& other)
+ : frame_ir(std::move(other.frame_ir)),
+ headers(std::move(other.headers)),
+ settings(std::move(other.settings)),
+ error_reported(other.error_reported) {}
+
+CollectedFrame::~CollectedFrame() {}
+
+CollectedFrame& CollectedFrame::operator=(CollectedFrame&& other) {
+ frame_ir = std::move(other.frame_ir);
+ headers = std::move(other.headers);
+ settings = std::move(other.settings);
+ error_reported = other.error_reported;
+ return *this;
+}
+
+AssertionResult CollectedFrame::VerifyHasHeaders(
+ const StringPairVector& expected_headers) const {
+ if (headers.get() == nullptr)
+ return AssertionFailure();
+ if (*headers != expected_headers)
+ return AssertionFailure();
+
+ return AssertionSuccess();
+}
+
+AssertionResult CollectedFrame::VerifyHasSettings(
+ const SettingVector& expected_settings) const {
+ if (settings.get() == nullptr)
+ return AssertionFailure();
+ if (*settings != expected_settings)
+ return AssertionFailure();
+
+ return AssertionSuccess();
+}
+
+DeframerCallbackCollector::DeframerCallbackCollector(
+ std::vector<CollectedFrame>* collected_frames)
+ : collected_frames_(collected_frames) {
+ CHECK(collected_frames);
+}
+
+void DeframerCallbackCollector::OnAltSvc(
+ std::unique_ptr<SpdyAltSvcIR> frame_ir) {
+ CollectedFrame cf;
+ cf.frame_ir = std::move(frame_ir);
+ collected_frames_->push_back(std::move(cf));
+}
+void DeframerCallbackCollector::OnData(std::unique_ptr<SpdyDataIR> frame_ir) {
+ CollectedFrame cf;
+ cf.frame_ir = std::move(frame_ir);
+ collected_frames_->push_back(std::move(cf));
+}
+void DeframerCallbackCollector::OnGoAway(
+ std::unique_ptr<SpdyGoAwayIR> frame_ir) {
+ CollectedFrame cf;
+ cf.frame_ir = std::move(frame_ir);
+ collected_frames_->push_back(std::move(cf));
+}
+
+// SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which
+// significantly modifies the headers, so the actual header entries (name
+// and value strings) are provided in a vector.
+void DeframerCallbackCollector::OnHeaders(
+ std::unique_ptr<SpdyHeadersIR> frame_ir,
+ std::unique_ptr<StringPairVector> headers) {
+ CollectedFrame cf;
+ cf.frame_ir = std::move(frame_ir);
+ cf.headers = std::move(headers);
+ collected_frames_->push_back(std::move(cf));
+}
+
+void DeframerCallbackCollector::OnPing(std::unique_ptr<SpdyPingIR> frame_ir) {
+ EXPECT_TRUE(frame_ir && !frame_ir->is_ack());
+ CollectedFrame cf;
+ cf.frame_ir = std::move(frame_ir);
+ collected_frames_->push_back(std::move(cf));
+}
+
+void DeframerCallbackCollector::OnPingAck(
+ std::unique_ptr<SpdyPingIR> frame_ir) {
+ EXPECT_TRUE(frame_ir && frame_ir->is_ack());
+ CollectedFrame cf;
+ cf.frame_ir = std::move(frame_ir);
+ collected_frames_->push_back(std::move(cf));
+}
+
+void DeframerCallbackCollector::OnPriority(
+ std::unique_ptr<SpdyPriorityIR> frame_ir) {
+ CollectedFrame cf;
+ cf.frame_ir = std::move(frame_ir);
+ collected_frames_->push_back(std::move(cf));
+}
+
+// SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which
+// significantly modifies the headers, so the actual header entries (name
+// and value strings) are provided in a vector.
+void DeframerCallbackCollector::OnPushPromise(
+ std::unique_ptr<SpdyPushPromiseIR> frame_ir,
+ std::unique_ptr<StringPairVector> headers) {
+ CollectedFrame cf;
+ cf.frame_ir = std::move(frame_ir);
+ cf.headers = std::move(headers);
+ collected_frames_->push_back(std::move(cf));
+}
+
+void DeframerCallbackCollector::OnRstStream(
+ std::unique_ptr<SpdyRstStreamIR> frame_ir) {
+ CollectedFrame cf;
+ cf.frame_ir = std::move(frame_ir);
+ collected_frames_->push_back(std::move(cf));
+}
+
+// SpdySettingsIR has a map for settings, so loses info about the order of
+// settings, and whether the same setting appeared more than once, so the
+// the actual settings (parameter and value) are provided in a vector.
+void DeframerCallbackCollector::OnSettings(
+ std::unique_ptr<SpdySettingsIR> frame_ir,
+ std::unique_ptr<SettingVector> settings) {
+ EXPECT_TRUE(frame_ir && !frame_ir->is_ack());
+ CollectedFrame cf;
+ cf.frame_ir = std::move(frame_ir);
+ cf.settings = std::move(settings);
+ collected_frames_->push_back(std::move(cf));
+}
+
+// A settings frame_ir with an ACK has no content, but for uniformity passing
+// a frame_ir with the ACK flag set.
+void DeframerCallbackCollector::OnSettingsAck(
+ std::unique_ptr<SpdySettingsIR> frame_ir) {
+ EXPECT_TRUE(frame_ir && frame_ir->is_ack());
+ CollectedFrame cf;
+ cf.frame_ir = std::move(frame_ir);
+ collected_frames_->push_back(std::move(cf));
+}
+
+void DeframerCallbackCollector::OnWindowUpdate(
+ std::unique_ptr<SpdyWindowUpdateIR> frame_ir) {
+ CollectedFrame cf;
+ cf.frame_ir = std::move(frame_ir);
+ collected_frames_->push_back(std::move(cf));
+}
+
+// The SpdyFramer will not process any more data at this point.
+void DeframerCallbackCollector::OnError(SpdyFramer* framer,
+ SpdyTestDeframer* deframer) {
+ CollectedFrame cf;
+ cf.error_reported = true;
+ collected_frames_->push_back(std::move(cf));
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/spdy/spdy_deframer_visitor.h b/chromium/net/spdy/spdy_deframer_visitor.h
new file mode 100644
index 00000000000..66c3c777f7c
--- /dev/null
+++ b/chromium/net/spdy/spdy_deframer_visitor.h
@@ -0,0 +1,250 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_SPDY_SPDY_DEFRAMER_VISITOR_H_
+#define NET_SPDY_SPDY_DEFRAMER_VISITOR_H_
+
+// Supports testing by converting callbacks to SpdyFramerVisitorInterface into
+// callbacks to SpdyDeframerVisitorInterface, whose arguments are generally
+// SpdyFrameIR instances. This enables a test client or test backend to operate
+// at a level between the low-level callbacks of SpdyFramerVisitorInterface and
+// the much higher level of entire messages (i.e. headers, body, trailers).
+// Where possible the converter (SpdyTestDeframer) tries to preserve information
+// that might be useful to tests (e.g. the order of headers or the amount of
+// padding); the design also aims to allow tests to be concise, ideally
+// supporting gMock style EXPECT_CALL(visitor, OnHeaders(...matchers...))
+// without too much boilerplate.
+//
+// Only supports HTTP/2 for the moment.
+//
+// Example of usage:
+//
+// SpdyFramer framer(HTTP2);
+//
+// // Need to call SpdyTestDeframer::AtFrameEnd() after processing each
+// // frame, so tell SpdyFramer to stop after each.
+// framer.set_process_single_input_frame(true);
+//
+// // Need the new OnHeader callbacks.
+// framer.set_use_new_methods_for_test(true);
+//
+// // Create your visitor, a subclass of SpdyDeframerVisitorInterface.
+// // For example, using DeframerCallbackCollector to collect frames:
+// std::vector<CollectedFrame> collected_frames;
+// auto your_visitor = gtl::MakeUnique<DeframerCallbackCollector>(
+// &collected_frames);
+//
+// // Transfer ownership of your visitor to the converter, which ensures that
+// // your visitor stays alive while the converter needs to call it.
+// auto the_deframer = SpdyTestDeframer::CreateConverter(
+// std::move(your_visitor));
+//
+// // Tell the framer to notify SpdyTestDeframer of the decoded frame
+// // details.
+// framer.set_visitor(the_deframer.get());
+//
+// // Process frames.
+// StringPiece input = ...
+// while (!input.empty() && !framer.HasError()) {
+// size_t consumed = framer.ProcessInput(input.data(), input.size());
+// input.remove_prefix(consumed);
+// if (framer.state() == SpdyFramer::SPDY_READY_FOR_FRAME) {
+// the_deframer->AtFrameEnd();
+// }
+// }
+//
+// // Make sure that the correct frames were received. For example:
+// ASSERT_EQ(collected_frames.size(), 3);
+//
+// SpdyDataIR expected1(7 /*stream_id*/, "Data Payload");
+// expected1.set_padding_len(17);
+// EXPECT_TRUE(collected_frames[0].VerifyEquals(expected1));
+//
+// // Repeat for the other frames.
+//
+// Note that you could also seed the subclass of SpdyDeframerVisitorInterface
+// with the expected frames, which it would pop-off the list as its expectations
+// are met.
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "net/spdy/spdy_framer.h"
+#include "net/spdy/spdy_protocol.h"
+#include "net/spdy/spdy_protocol_test_utils.h"
+#include "net/spdy/spdy_test_utils.h"
+
+namespace net {
+namespace test {
+
+// Non-lossy representation of a SETTINGS frame payload.
+typedef std::vector<std::pair<SpdySettingsIds, uint32_t>> SettingVector;
+
+// StringPairVector is used to record information lost by SpdyHeaderBlock, in
+// particular the order of each header entry, though it doesn't expose the
+// inner details of the HPACK block, such as the type of encoding selected
+// for each header entry, nor dynamic table size changes.
+typedef std::pair<std::string, std::string> StringPair;
+typedef std::vector<StringPair> StringPairVector;
+
+// Forward decl.
+class SpdyTestDeframer;
+
+// Note that this only roughly captures the frames, as padding bytes are lost,
+// continuation frames are combined with their leading HEADERS or PUSH_PROMISE,
+// the details of the HPACK encoding are lost, leaving
+// only the list of header entries (name and value strings). If really helpful,
+// we could add a SpdyRawDeframerVisitorInterface that gets the HPACK bytes,
+// and receives continuation frames. For more info we'd need to improve
+// SpdyFramerVisitorInterface.
+class SpdyDeframerVisitorInterface {
+ public:
+ virtual ~SpdyDeframerVisitorInterface() {}
+
+ // Wrap a visitor in another SpdyDeframerVisitorInterface that will
+ // DVLOG each call, and will then forward the calls to the wrapped visitor
+ // (if provided; nullptr is OK). Takes ownership of the wrapped visitor.
+ static std::unique_ptr<SpdyDeframerVisitorInterface> LogBeforeVisiting(
+ std::unique_ptr<SpdyDeframerVisitorInterface> wrapped_visitor);
+
+ virtual void OnAltSvc(std::unique_ptr<SpdyAltSvcIR> frame) {}
+ virtual void OnData(std::unique_ptr<SpdyDataIR> frame) {}
+ virtual void OnGoAway(std::unique_ptr<SpdyGoAwayIR> frame) {}
+
+ // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which
+ // significantly modifies the headers, so the actual header entries (name
+ // and value strings) are provided in a vector.
+ virtual void OnHeaders(std::unique_ptr<SpdyHeadersIR> frame,
+ std::unique_ptr<StringPairVector> headers) {}
+
+ virtual void OnPing(std::unique_ptr<SpdyPingIR> frame) {}
+ virtual void OnPingAck(std::unique_ptr<SpdyPingIR> frame);
+ virtual void OnPriority(std::unique_ptr<SpdyPriorityIR> frame) {}
+
+ // SpdyHeadersIR and SpdyPushPromiseIR each has a SpdyHeaderBlock which
+ // significantly modifies the headers, so the actual header entries (name
+ // and value strings) are provided in a vector.
+ virtual void OnPushPromise(std::unique_ptr<SpdyPushPromiseIR> frame,
+ std::unique_ptr<StringPairVector> headers) {}
+
+ virtual void OnRstStream(std::unique_ptr<SpdyRstStreamIR> frame) {}
+
+ // SpdySettingsIR has a map for settings, so loses info about the order of
+ // settings, and whether the same setting appeared more than once, so the
+ // the actual settings (parameter and value) are provided in a vector.
+ virtual void OnSettings(std::unique_ptr<SpdySettingsIR> frame,
+ std::unique_ptr<SettingVector> settings) {}
+
+ // A settings frame with an ACK has no content, but for uniformity passing
+ // a frame with the ACK flag set.
+ virtual void OnSettingsAck(std::unique_ptr<SpdySettingsIR> frame);
+
+ virtual void OnWindowUpdate(std::unique_ptr<SpdyWindowUpdateIR> frame) {}
+
+ // The SpdyFramer will not process any more data at this point.
+ virtual void OnError(SpdyFramer* framer, SpdyTestDeframer* deframer) {}
+};
+
+class SpdyTestDeframer : public SpdyFramerVisitorInterface {
+ public:
+ ~SpdyTestDeframer() override {}
+
+ // Creates a SpdyFramerVisitorInterface that builds SpdyFrameIR concrete
+ // instances based on the callbacks it receives; when an entire frame is
+ // decoded/reconstructed it calls the passed in SpdyDeframerVisitorInterface.
+ // Transfers ownership of visitor to the new SpdyTestDeframer, which ensures
+ // that it continues to exist while the SpdyTestDeframer exists.
+ static std::unique_ptr<SpdyTestDeframer> CreateConverter(
+ std::unique_ptr<SpdyDeframerVisitorInterface> visitor);
+
+ // Call to notify the deframer that the SpdyFramer has returned after reaching
+ // the end of decoding a frame. This is used to flush info about some frame
+ // types where we don't get a clear end signal; others are flushed (i.e. the
+ // appropriate call to the SpdyDeframerVisitorInterface method is invoked)
+ // as they're decoded by SpdyFramer and it calls the deframer. See the
+ // example in the comments at the top of this file.
+ virtual bool AtFrameEnd() = 0;
+
+ protected:
+ SpdyTestDeframer() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SpdyTestDeframer);
+};
+
+// CollectedFrame holds the result of one call to SpdyDeframerVisitorInterface,
+// as recorded by DeframerCallbackCollector.
+struct CollectedFrame {
+ CollectedFrame();
+ CollectedFrame(CollectedFrame&& other);
+ ~CollectedFrame();
+ CollectedFrame& operator=(CollectedFrame&& other);
+
+ // Compare a SpdyFrameIR sub-class instance, expected_ir, against the
+ // collected SpdyFrameIR.
+ template <class T,
+ typename X =
+ typename std::enable_if<std::is_base_of<SpdyFrameIR, T>::value>>
+ ::testing::AssertionResult VerifyHasFrame(const T& expected_ir) const {
+ return VerifySpdyFrameIREquals(expected_ir, frame_ir.get())
+ ? ::testing::AssertionSuccess()
+ : ::testing::AssertionFailure();
+ }
+
+ // Compare the collected headers against a StringPairVector. Ignores
+ // this->frame_ir.
+ ::testing::AssertionResult VerifyHasHeaders(
+ const StringPairVector& expected_headers) const;
+
+ // Compare the collected settings (parameter and value pairs) against
+ // expected_settings. Ignores this->frame_ir.
+ ::testing::AssertionResult VerifyHasSettings(
+ const SettingVector& expected_settings) const;
+
+ std::unique_ptr<SpdyFrameIR> frame_ir;
+ std::unique_ptr<StringPairVector> headers;
+ std::unique_ptr<SettingVector> settings;
+ bool error_reported = false;
+};
+
+// Creates a CollectedFrame instance for each callback, storing it in the
+// vector provided to the constructor.
+class DeframerCallbackCollector : public SpdyDeframerVisitorInterface {
+ public:
+ explicit DeframerCallbackCollector(
+ std::vector<CollectedFrame>* collected_frames);
+ ~DeframerCallbackCollector() override {}
+
+ void OnAltSvc(std::unique_ptr<SpdyAltSvcIR> frame_ir) override;
+ void OnData(std::unique_ptr<SpdyDataIR> frame_ir) override;
+ void OnGoAway(std::unique_ptr<SpdyGoAwayIR> frame_ir) override;
+ void OnHeaders(std::unique_ptr<SpdyHeadersIR> frame_ir,
+ std::unique_ptr<StringPairVector> headers) override;
+ void OnPing(std::unique_ptr<SpdyPingIR> frame_ir) override;
+ void OnPingAck(std::unique_ptr<SpdyPingIR> frame_ir) override;
+ void OnPriority(std::unique_ptr<SpdyPriorityIR> frame_ir) override;
+ void OnPushPromise(std::unique_ptr<SpdyPushPromiseIR> frame_ir,
+ std::unique_ptr<StringPairVector> headers) override;
+ void OnRstStream(std::unique_ptr<SpdyRstStreamIR> frame_ir) override;
+ void OnSettings(std::unique_ptr<SpdySettingsIR> frame_ir,
+ std::unique_ptr<SettingVector> settings) override;
+ void OnSettingsAck(std::unique_ptr<SpdySettingsIR> frame_ir) override;
+ void OnWindowUpdate(std::unique_ptr<SpdyWindowUpdateIR> frame_ir) override;
+ void OnError(SpdyFramer* framer, SpdyTestDeframer* deframer) override;
+
+ private:
+ std::vector<CollectedFrame>* collected_frames_;
+};
+
+} // namespace test
+} // namespace net
+
+#endif // NET_SPDY_SPDY_DEFRAMER_VISITOR_H_
diff --git a/chromium/net/spdy/spdy_deframer_visitor_test.cc b/chromium/net/spdy/spdy_deframer_visitor_test.cc
new file mode 100644
index 00000000000..9b1a1f29e52
--- /dev/null
+++ b/chromium/net/spdy/spdy_deframer_visitor_test.cc
@@ -0,0 +1,273 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/spdy/spdy_deframer_visitor.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+#include <limits>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/rand_util.h"
+#include "base/strings/string_piece.h"
+#include "net/spdy/hpack/hpack_constants.h"
+#include "net/spdy/mock_spdy_framer_visitor.h"
+#include "net/spdy/spdy_frame_builder.h"
+#include "net/spdy/spdy_frame_reader.h"
+#include "net/spdy/spdy_protocol.h"
+#include "net/spdy/spdy_protocol_test_utils.h"
+#include "net/spdy/spdy_test_utils.h"
+
+using ::base::MakeUnique;
+using ::std::string;
+
+namespace net {
+namespace test {
+namespace {
+
+class SpdyDeframerVisitorTest : public ::testing::Test {
+ protected:
+ SpdyDeframerVisitorTest() : encoder_(HTTP2), decoder_(HTTP2) {
+ decoder_.set_process_single_input_frame(true);
+ decoder_.set_use_new_methods_for_test(true);
+ auto collector = MakeUnique<DeframerCallbackCollector>(&collected_frames_);
+ auto log_and_collect =
+ SpdyDeframerVisitorInterface::LogBeforeVisiting(std::move(collector));
+ deframer_ = SpdyTestDeframer::CreateConverter(std::move(log_and_collect));
+ decoder_.set_visitor(deframer_.get());
+ }
+
+ bool DeframeInput(const char* input, size_t size) {
+ size_t input_remaining = size;
+ while (input_remaining > 0 &&
+ decoder_.error_code() == SpdyFramer::SPDY_NO_ERROR) {
+ // To make the tests more interesting, we feed random (and small) chunks
+ // into the framer. This simulates getting strange-sized reads from
+ // the socket.
+ const size_t kMaxReadSize = 32;
+ size_t bytes_read =
+ (base::RandGenerator(std::min(input_remaining, kMaxReadSize))) + 1;
+ size_t bytes_processed = decoder_.ProcessInput(input, bytes_read);
+ input_remaining -= bytes_processed;
+ input += bytes_processed;
+ if (decoder_.state() == SpdyFramer::SPDY_READY_FOR_FRAME) {
+ deframer_->AtFrameEnd();
+ }
+ }
+ return (input_remaining == 0 &&
+ decoder_.error_code() == SpdyFramer::SPDY_NO_ERROR);
+ }
+
+ SpdySerializedFrame SerializeFrame(const SpdyFrameIR& frame) {
+ return encoder_.SerializeFrame(frame);
+ }
+
+ string SerializeFrames(
+ const std::vector<std::unique_ptr<SpdyFrameIR>>& frames) {
+ string result;
+ for (const auto& frame_ptr : frames) {
+ auto sf = SerializeFrame(*frame_ptr);
+ base::StringPiece(sf.data(), sf.size()).AppendToString(&result);
+ }
+ return result;
+ }
+
+ // bool
+
+ SpdyFramer encoder_;
+ SpdyFramer decoder_;
+ std::vector<CollectedFrame> collected_frames_;
+ std::unique_ptr<SpdyTestDeframer> deframer_;
+};
+
+TEST_F(SpdyDeframerVisitorTest, DataFrame) {
+ const char kFrameData[] = {
+ 0x00, 0x00, 0x0d, // Length = 13.
+ 0x00, // DATA
+ 0x08, // PADDED
+ 0x00, 0x00, 0x00, 0x01, // Stream 1
+ 0x07, // Pad length field.
+ 'h', 'e', 'l', 'l', // Data
+ 'o', // More Data
+ 0x00, 0x00, 0x00, 0x00, // Padding
+ 0x00, 0x00, 0x00 // More Padding
+ };
+
+ EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData));
+ ASSERT_EQ(1u, collected_frames_.size());
+ const CollectedFrame& cf0 = collected_frames_[0];
+ ASSERT_NE(cf0.frame_ir, nullptr);
+
+ SpdyDataIR expected_ir(1, "hello");
+ expected_ir.set_padding_len(8);
+ EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+}
+
+TEST_F(SpdyDeframerVisitorTest, HeaderFrameWithContinuation) {
+ const char kFrameData[] = {
+ 0x00, 0x00, 0x05, // Payload Length: 5
+ 0x01, // Type: HEADERS
+ 0x09, // Flags: PADDED | END_STREAM
+ 0x00, 0x00, 0x00, 0x01, // Stream: 1
+ 0x04, // Padding Length: 4
+ 0x00, 0x00, 0x00, 0x00, // Padding
+ /* Second Frame */
+ 0x00, 0x00, 0x12, // Payload Length: 18
+ 0x09, // Type: CONTINUATION
+ 0x04, // Flags: END_HEADERS
+ 0x00, 0x00, 0x00, 0x01, // Stream: 1
+ 0x00, // Unindexed, literal name & value
+ 0x03, 0x62, 0x61, 0x72, // Name len and name (3, "bar")
+ 0x03, 0x66, 0x6f, 0x6f, // Value len and value (3, "foo")
+ 0x00, // Unindexed, literal name & value
+ 0x03, 0x66, 0x6f, 0x6f, // Name len and name (3, "foo")
+ 0x03, 0x62, 0x61, 0x72, // Value len and value (3, "bar")
+ };
+
+ EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData));
+ ASSERT_EQ(1u, collected_frames_.size());
+ const CollectedFrame& cf0 = collected_frames_[0];
+
+ StringPairVector headers;
+ headers.push_back({"bar", "foo"});
+ headers.push_back({"foo", "bar"});
+
+ EXPECT_TRUE(cf0.VerifyHasHeaders(headers));
+
+ SpdyHeadersIR expected_ir(1);
+ // Yet again SpdyFramerVisitorInterface is lossy: it doesn't call OnPadding
+ // for HEADERS, just for DATA. Sigh.
+ // expected_ir.set_padding_len(5);
+ expected_ir.set_fin(true);
+ for (const auto& nv : headers) {
+ expected_ir.SetHeader(nv.first, nv.second);
+ }
+
+ EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+
+ // Confirm that mismatches are also detected.
+ headers.push_back({"baz", "bing"});
+ EXPECT_FALSE(cf0.VerifyHasHeaders(headers));
+ EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+
+ headers.pop_back();
+ EXPECT_TRUE(cf0.VerifyHasHeaders(headers));
+ EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+
+ expected_ir.SetHeader("baz", "bing");
+ EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir));
+ EXPECT_TRUE(cf0.VerifyHasHeaders(headers));
+}
+
+TEST_F(SpdyDeframerVisitorTest, PriorityFrame) {
+ const char kFrameData[] = {
+ 0x00, 0x00, 0x05, // Length: 5
+ 0x02, // Type: PRIORITY
+ 0x00, // Flags: none
+ 0x00, 0x00, 0x00, 0x65, // Stream: 101
+ 0x80u, 0x00, 0x00, 0x01, // Parent: 1 (Exclusive)
+ 0x10, // Weight: 17
+ };
+
+ EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData));
+ ASSERT_EQ(1u, collected_frames_.size());
+ const CollectedFrame& cf0 = collected_frames_[0];
+
+ SpdyPriorityIR expected_ir(101, 1, 17, true);
+ EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+
+ // Confirm that mismatches are also detected.
+ expected_ir.set_weight(16);
+ EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir));
+ expected_ir.set_weight(17);
+ EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+
+ expected_ir.set_parent_stream_id(50);
+ EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir));
+ expected_ir.set_parent_stream_id(1);
+ EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+
+ expected_ir.set_stream_id(201);
+ EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir));
+ expected_ir.set_stream_id(101);
+ EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+
+ expected_ir.set_exclusive(false);
+ EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir));
+ expected_ir.set_exclusive(true);
+ EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+}
+
+TEST_F(SpdyDeframerVisitorTest, DISABLED_RstStreamFrame) {
+ // TODO(jamessynge): Please implement.
+}
+
+TEST_F(SpdyDeframerVisitorTest, SettingsFrame) {
+ // Settings frame with two entries for the same parameter but with different
+ // values. The last one will be in the decoded SpdySettingsIR, but the vector
+ // of settings will have both, in the same order.
+ const char kFrameData[] = {
+ 0x00, 0x00, 0x0c, // Length
+ 0x04, // Type (SETTINGS)
+ 0x00, // Flags
+ 0x00, 0x00, 0x00, 0x00, // Stream id (must be zero)
+ 0x00, 0x04, // Setting id (SETTINGS_INITIAL_WINDOW_SIZE)
+ 0x0a, 0x0b, 0x0c, 0x0d, // Setting value
+ 0x00, 0x04, // Setting id (SETTINGS_INITIAL_WINDOW_SIZE)
+ 0x00, 0x00, 0x00, 0xffu // Setting value
+ };
+
+ EXPECT_TRUE(DeframeInput(kFrameData, sizeof kFrameData));
+ ASSERT_EQ(1u, collected_frames_.size());
+ const CollectedFrame& cf0 = collected_frames_[0];
+ ASSERT_NE(cf0.frame_ir, nullptr);
+
+ SpdySettingsIR expected_ir;
+ expected_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, true, true, 255);
+ EXPECT_TRUE(cf0.VerifyHasFrame(expected_ir));
+
+ SettingVector expected_settings;
+ expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 0x0a0b0c0d});
+ expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 255});
+
+ EXPECT_TRUE(cf0.VerifyHasSettings(expected_settings));
+
+ // Confirm that mismatches are also detected.
+ expected_settings.push_back({SETTINGS_INITIAL_WINDOW_SIZE, 65536});
+ EXPECT_FALSE(cf0.VerifyHasSettings(expected_settings));
+
+ expected_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, true, true, 65536);
+ EXPECT_FALSE(cf0.VerifyHasFrame(expected_ir));
+
+ SpdySettingsIR unexpected_ir;
+ unexpected_ir.set_is_ack(true);
+ EXPECT_FALSE(cf0.VerifyHasFrame(unexpected_ir));
+}
+
+TEST_F(SpdyDeframerVisitorTest, DISABLED_PushPromiseFrame) {
+ // TODO(jamessynge): Please implement.
+}
+
+TEST_F(SpdyDeframerVisitorTest, DISABLED_PingFrame) {
+ // TODO(jamessynge): Please implement.
+}
+
+TEST_F(SpdyDeframerVisitorTest, DISABLED_GoAwayFrame) {
+ // TODO(jamessynge): Please implement.
+}
+
+TEST_F(SpdyDeframerVisitorTest, DISABLED_WindowUpdateFrame) {
+ // TODO(jamessynge): Please implement.
+}
+
+TEST_F(SpdyDeframerVisitorTest, DISABLED_AltSvcFrame) {
+ // TODO(jamessynge): Please implement.
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/chromium/net/spdy/spdy_flags.cc b/chromium/net/spdy/spdy_flags.cc
index 15fa1af8d51..8e99ff50574 100644
--- a/chromium/net/spdy/spdy_flags.cc
+++ b/chromium/net/spdy/spdy_flags.cc
@@ -4,12 +4,20 @@
#include "net/spdy/spdy_flags.h"
-// When true, remove hardcoded HPACK size limit on buffered encoded data.
-bool FLAGS_chromium_http2_flag_remove_hpack_decode_buffer_size_limit = true;
+namespace net {
+
+// Log compressed size of HTTP/2 requests.
+bool FLAGS_chromium_http2_flag_log_compressed_size = true;
+
+// If true, SpdyFramer uses the new visitor methods OnHeaderFrameStart and
+// OnHeaderFrameEnd. Fourth attempt.
+bool FLAGS_chromium_http2_flag_spdy_framer_use_new_methods4 = true;
+
+// If true, increase HPACK table size up to optimal size kOptTableSize if
+// clients allow it.
+bool FLAGS_chromium_reloadable_flag_increase_hpack_table_size = false;
// Use NestedSpdyFramerDecoder.
bool FLAGS_use_nested_spdy_framer_decoder = false;
-// Enforce the limit we advertise on frame payload size with
-// GOAWAY_FRAME_SIZE_ERROR.
-bool FLAGS_chromium_http2_flag_enforce_max_frame_size = false;
+} // namespace net
diff --git a/chromium/net/spdy/spdy_flags.h b/chromium/net/spdy/spdy_flags.h
index 2cb7dd238f3..44234afb7b1 100644
--- a/chromium/net/spdy/spdy_flags.h
+++ b/chromium/net/spdy/spdy_flags.h
@@ -7,9 +7,15 @@
#include "net/base/net_export.h"
+namespace net {
+
+NET_EXPORT_PRIVATE extern bool FLAGS_chromium_http2_flag_log_compressed_size;
+NET_EXPORT_PRIVATE extern bool
+ FLAGS_chromium_http2_flag_spdy_framer_use_new_methods4;
NET_EXPORT_PRIVATE extern bool
- FLAGS_chromium_http2_flag_remove_hpack_decode_buffer_size_limit;
+ FLAGS_chromium_reloadable_flag_increase_hpack_table_size;
NET_EXPORT_PRIVATE extern bool FLAGS_use_nested_spdy_framer_decoder;
-NET_EXPORT_PRIVATE extern bool FLAGS_chromium_http2_flag_enforce_max_frame_size;
+
+} // namespace net
#endif // NET_SPDY_SPDY_FLAGS_H_
diff --git a/chromium/net/spdy/spdy_frame_builder.cc b/chromium/net/spdy/spdy_frame_builder.cc
index 91a48b12a95..d6918b7c7d1 100644
--- a/chromium/net/spdy/spdy_frame_builder.cc
+++ b/chromium/net/spdy/spdy_frame_builder.cc
@@ -67,13 +67,13 @@ bool SpdyFrameBuilder::WriteControlFrameHeader(const SpdyFramer& framer,
DCHECK(SpdyConstants::IsValidFrameType(
version_, SpdyConstants::SerializeFrameType(version_, type)));
bool success = true;
- FlagsAndLength flags_length = CreateFlagsAndLength(
- flags, capacity_ - framer.GetControlFrameHeaderSize());
+ FlagsAndLength flags_length =
+ CreateFlagsAndLength(flags, capacity_ - framer.GetFrameHeaderSize());
success &= WriteUInt16(kControlFlagMask | kSpdy3Version);
success &= WriteUInt16(
SpdyConstants::SerializeFrameType(framer.protocol_version(), type));
success &= WriteBytes(&flags_length, sizeof(flags_length));
- DCHECK_EQ(framer.GetControlFrameHeaderSize(), length());
+ DCHECK_EQ(framer.GetFrameHeaderSize(), length());
return success;
}
@@ -106,10 +106,12 @@ bool SpdyFrameBuilder::BeginNewFrame(const SpdyFramer& framer,
DCHECK_EQ(0u, stream_id & ~kStreamIdMask);
DCHECK_EQ(HTTP2, framer.protocol_version());
bool success = true;
+ size_t frame_header_length =
+ SpdyConstants::GetFrameHeaderSize(framer.protocol_version());
if (length_ > 0) {
// Update length field for previous frame.
- OverwriteLength(framer, length_ - framer.GetPrefixLength(type));
- SPDY_BUG_IF(SpdyConstants::GetFrameMaximumSize(version_) < length_)
+ OverwriteLength(framer, length_ - frame_header_length);
+ SPDY_BUG_IF(framer.GetFrameMaximumSize() < length_)
<< "Frame length " << length_
<< " is longer than the maximum allowed length.";
}
@@ -121,9 +123,8 @@ bool SpdyFrameBuilder::BeginNewFrame(const SpdyFramer& framer,
// the length will get overwritten when we begin the next frame.
// Don't check for length limits here because this may be larger than the
// actual frame length.
- success &= WriteUInt24(capacity_ - offset_ - framer.GetPrefixLength(type));
- success &= WriteUInt8(
- SpdyConstants::SerializeFrameType(version_, type));
+ success &= WriteUInt24(capacity_ - offset_ - frame_header_length);
+ success &= WriteUInt8(SpdyConstants::SerializeFrameType(version_, type));
success &= WriteUInt8(flags);
success &= WriteUInt32(stream_id);
DCHECK_EQ(framer.GetDataFrameMinimumSize(), length_);
@@ -163,18 +164,16 @@ bool SpdyFrameBuilder::WriteBytes(const void* data, uint32_t data_len) {
}
bool SpdyFrameBuilder::RewriteLength(const SpdyFramer& framer) {
- return OverwriteLength(framer,
- length_ - framer.GetControlFrameHeaderSize());
+ return OverwriteLength(framer, length_ - framer.GetFrameHeaderSize());
}
bool SpdyFrameBuilder::OverwriteLength(const SpdyFramer& framer,
size_t length) {
if (version_ == SPDY3) {
- DCHECK_LE(length,
- SpdyConstants::GetFrameMaximumSize(version_) -
- framer.GetFrameMinimumSize());
+ DCHECK_GE(framer.GetFrameMaximumSize() - framer.GetFrameMinimumSize(),
+ length);
} else {
- DCHECK_LE(length, SpdyConstants::GetFrameMaximumSize(version_));
+ DCHECK_GE(framer.GetFrameMaximumSize(), length);
}
bool success = false;
const size_t old_length = length_;
diff --git a/chromium/net/spdy/spdy_frame_builder.h b/chromium/net/spdy/spdy_frame_builder.h
index 86c8ee001e6..47ec816cc68 100644
--- a/chromium/net/spdy/spdy_frame_builder.h
+++ b/chromium/net/spdy/spdy_frame_builder.h
@@ -77,9 +77,9 @@ class NET_EXPORT_PRIVATE SpdyFrameBuilder {
// Takes the buffer from the SpdyFrameBuilder.
SpdySerializedFrame take() {
if (version_ == HTTP2) {
- SPDY_BUG_IF(SpdyConstants::GetFrameMaximumSize(version_) < length_)
+ SPDY_BUG_IF(SpdyConstants::GetMaxFrameSizeLimit(version_) < length_)
<< "Frame length " << length_
- << " is longer than the maximum allowed length.";
+ << " is longer than the maximum possible allowed length.";
}
SpdySerializedFrame rv(buffer_.release(), length(), true);
capacity_ = 0;
diff --git a/chromium/net/spdy/spdy_framer.cc b/chromium/net/spdy/spdy_framer.cc
index 0901fe4c38b..ca1494f52c0 100644
--- a/chromium/net/spdy/spdy_framer.cc
+++ b/chromium/net/spdy/spdy_framer.cc
@@ -17,8 +17,9 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
-#include "net/quic/quic_flags.h"
+#include "net/quic/core/quic_flags.h"
#include "net/spdy/hpack/hpack_constants.h"
#include "net/spdy/spdy_bitmasks.h"
#include "net/spdy/spdy_bug_tracker.h"
@@ -90,6 +91,17 @@ void UnpackStreamDependencyValues(uint32_t packed,
*parent_stream_id = packed & 0x7fffffff;
}
+// Creates a SpdyFramerDecoderAdapter if flags indicate that one should be
+// used. This code is isolated to hopefully make merging into Chromium easier.
+std::unique_ptr<SpdyFramerDecoderAdapter> DecoderAdapterFactory(
+ SpdyFramer* outer) {
+ if (FLAGS_use_nested_spdy_framer_decoder) {
+ DVLOG(1) << "Creating NestedSpdyFramerDecoder.";
+ return CreateNestedSpdyFramerDecoder(outer);
+ }
+ return nullptr;
+}
+
struct DictionaryIds {
DictionaryIds()
: v3_dictionary_id(
@@ -119,6 +131,7 @@ const size_t SpdyFramer::kHeaderDataChunkMaxSize = 1024;
// limit on control frame size for legacy reasons and to
// mitigate DOS attacks.
const size_t SpdyFramer::kMaxControlFrameSize = (1 << 14) - 1;
+const size_t SpdyFramer::kMaxDataPayloadSendSize = 1 << 14;
// The size of the control frame buffer. Must be >= the minimum size of the
// largest control frame, which is SYN_STREAM. See GetSynStreamMinimumSize() for
// calculation details.
@@ -171,7 +184,8 @@ bool SpdyFramerVisitorInterface::OnRstStreamFrameData(
return true;
}
-SpdyFramer::SpdyFramer(SpdyMajorVersion version, bool choose_decoder)
+SpdyFramer::SpdyFramer(SpdyMajorVersion version,
+ SpdyFramer::DecoderAdapterFactoryFn adapter_factory)
: current_frame_buffer_(kControlFrameBufferSize),
expect_continuation_(0),
visitor_(NULL),
@@ -191,16 +205,13 @@ SpdyFramer::SpdyFramer(SpdyMajorVersion version, bool choose_decoder)
"Our send limit should be at most our receive limit");
Reset();
- if (choose_decoder && version == HTTP2) {
- // Another case will be added, hence the nested if blocks...
- if (FLAGS_use_nested_spdy_framer_decoder) {
- DVLOG(1) << "Creating NestedSpdyFramerDecoder.";
- decoder_adapter_.reset(CreateNestedSpdyFramerDecoder(this));
- }
+ if (version == HTTP2 && adapter_factory != nullptr) {
+ decoder_adapter_ = adapter_factory(this);
}
}
-SpdyFramer::SpdyFramer(SpdyMajorVersion version) : SpdyFramer(version, true) {}
+SpdyFramer::SpdyFramer(SpdyMajorVersion version)
+ : SpdyFramer(version, &DecoderAdapterFactory) {}
SpdyFramer::~SpdyFramer() {
if (header_compressor_.get()) {
@@ -278,8 +289,8 @@ size_t SpdyFramer::GetDataFrameMinimumSize() const {
}
// Size, in bytes, of the control frame header.
-size_t SpdyFramer::GetControlFrameHeaderSize() const {
- return SpdyConstants::GetControlFrameHeaderSize(protocol_version_);
+size_t SpdyFramer::GetFrameHeaderSize() const {
+ return SpdyConstants::GetFrameHeaderSize(protocol_version_);
}
size_t SpdyFramer::GetSynStreamMinimumSize() const {
@@ -289,18 +300,17 @@ size_t SpdyFramer::GetSynStreamMinimumSize() const {
// Calculated as:
// control frame header + 2 * 4 (stream IDs) + 1 (priority)
// + 1 (unused)
- return GetControlFrameHeaderSize() + 10;
+ return GetFrameHeaderSize() + 10;
} else {
- return GetControlFrameHeaderSize() +
- kPriorityDependencyPayloadSize +
- kPriorityWeightPayloadSize;
+ return GetFrameHeaderSize() + kPriorityDependencyPayloadSize +
+ kPriorityWeightPayloadSize;
}
}
size_t SpdyFramer::GetSynReplyMinimumSize() const {
// Size, in bytes, of a SYN_REPLY frame not including the variable-length
// header block.
- size_t size = GetControlFrameHeaderSize();
+ size_t size = GetFrameHeaderSize();
if (protocol_version_ == SPDY3) {
// Calculated as:
// control frame header + 4 (stream IDs)
@@ -316,11 +326,11 @@ size_t SpdyFramer::GetRstStreamMinimumSize() const {
if (protocol_version_ == SPDY3) {
// Calculated as:
// control frame header + 4 (stream id) + 4 (status code)
- return GetControlFrameHeaderSize() + 8;
+ return GetFrameHeaderSize() + 8;
} else {
// Calculated as:
// frame prefix + 4 (status code)
- return GetControlFrameHeaderSize() + 4;
+ return GetFrameHeaderSize() + 4;
}
}
@@ -329,9 +339,9 @@ size_t SpdyFramer::GetSettingsMinimumSize() const {
// from the variable-length value block. Calculated as:
// control frame header + 4 (number of ID/value pairs)
if (protocol_version_ == SPDY3) {
- return GetControlFrameHeaderSize() + 4;
+ return GetFrameHeaderSize() + 4;
} else {
- return GetControlFrameHeaderSize();
+ return GetFrameHeaderSize();
}
}
@@ -340,24 +350,24 @@ size_t SpdyFramer::GetPingSize() const {
if (protocol_version_ == SPDY3) {
// Calculated as:
// control frame header + 4 (id)
- return GetControlFrameHeaderSize() + 4;
+ return GetFrameHeaderSize() + 4;
} else {
// Calculated as:
// control frame header + 8 (id)
- return GetControlFrameHeaderSize() + 8;
+ return GetFrameHeaderSize() + 8;
}
}
size_t SpdyFramer::GetGoAwayMinimumSize() const {
// Size, in bytes, of this GOAWAY frame. Calculated as:
// Control frame header + last stream id (4 bytes) + error code (4 bytes).
- return GetControlFrameHeaderSize() + 8;
+ return GetFrameHeaderSize() + 8;
}
size_t SpdyFramer::GetHeadersMinimumSize() const {
// Size, in bytes, of a HEADERS frame not including the variable-length
// header block.
- size_t size = GetControlFrameHeaderSize();
+ size_t size = GetFrameHeaderSize();
if (protocol_version_ == SPDY3) {
// Calculated as:
// control frame header + 4 (stream IDs)
@@ -372,11 +382,11 @@ size_t SpdyFramer::GetWindowUpdateSize() const {
if (protocol_version_ == SPDY3) {
// Calculated as:
// control frame header + 4 (stream id) + 4 (delta)
- return GetControlFrameHeaderSize() + 8;
+ return GetFrameHeaderSize() + 8;
} else {
// Calculated as:
// frame prefix + 4 (delta)
- return GetControlFrameHeaderSize() + 4;
+ return GetFrameHeaderSize() + 4;
}
}
@@ -384,20 +394,20 @@ size_t SpdyFramer::GetBlockedSize() const {
DCHECK_EQ(HTTP2, protocol_version_);
// Size, in bytes, of a BLOCKED frame.
// The BLOCKED frame has no payload beyond the control frame header.
- return GetControlFrameHeaderSize();
+ return GetFrameHeaderSize();
}
size_t SpdyFramer::GetPushPromiseMinimumSize() const {
DCHECK_EQ(HTTP2, protocol_version_);
// Size, in bytes, of a PUSH_PROMISE frame, sans the embedded header block.
- // Calculated as frame prefix + 4 (promised stream id).
- return GetControlFrameHeaderSize() + 4;
+ // Calculated as frame prefix + 4 (promised stream id)
+ return GetFrameHeaderSize() + 4;
}
size_t SpdyFramer::GetContinuationMinimumSize() const {
// Size, in bytes, of a CONTINUATION frame not including the variable-length
// headers fragments.
- return GetControlFrameHeaderSize();
+ return GetFrameHeaderSize();
}
size_t SpdyFramer::GetAltSvcMinimumSize() const {
@@ -406,30 +416,35 @@ size_t SpdyFramer::GetAltSvcMinimumSize() const {
// gives a lower bound on the frame size rather than a true minimum; the
// actual frame should always be larger than this.
// Calculated as frame prefix + 2 (origin_len).
- return GetControlFrameHeaderSize() + 2;
+ return GetFrameHeaderSize() + 2;
}
size_t SpdyFramer::GetPrioritySize() const {
// Size, in bytes, of a PRIORITY frame.
- return GetControlFrameHeaderSize() +
- kPriorityDependencyPayloadSize +
- kPriorityWeightPayloadSize;
+ return GetFrameHeaderSize() + kPriorityDependencyPayloadSize +
+ kPriorityWeightPayloadSize;
}
size_t SpdyFramer::GetFrameMinimumSize() const {
- return std::min(GetDataFrameMinimumSize(), GetControlFrameHeaderSize());
+ return GetFrameHeaderSize();
}
size_t SpdyFramer::GetFrameMaximumSize() const {
- return SpdyConstants::GetFrameMaximumSize(protocol_version_);
+ if (protocol_version_ == HTTP2) {
+ return send_frame_size_limit_ +
+ SpdyConstants::GetFrameHeaderSize(protocol_version_);
+ } else {
+ return SpdyConstants::GetMaxFrameSizeLimit(protocol_version_);
+ }
}
size_t SpdyFramer::GetDataFrameMaximumPayload() const {
- return GetFrameMaximumSize() - GetDataFrameMinimumSize();
-}
-
-size_t SpdyFramer::GetPrefixLength(SpdyFrameType type) const {
- return SpdyConstants::GetPrefixLength(type, protocol_version_);
+ if (protocol_version_ == HTTP2) {
+ return std::min(kMaxDataPayloadSendSize,
+ GetFrameMaximumSize() - GetDataFrameMinimumSize());
+ } else {
+ return GetFrameMaximumSize() - GetDataFrameMinimumSize();
+ }
}
const char* SpdyFramer::StateToString(int state) {
@@ -827,7 +842,7 @@ SpdyFrameType SpdyFramer::ValidateFrameHeader(bool is_control_frame,
}
}
- if (enforce_max_frame_size_ && protocol_version_ == HTTP2 &&
+ if (protocol_version_ == HTTP2 &&
payload_length_field > recv_frame_size_limit_) {
set_error(SPDY_OVERSIZED_PAYLOAD);
}
@@ -843,13 +858,12 @@ size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
size_t original_len = len;
// Update current frame buffer as needed.
- if (current_frame_buffer_.len() < GetControlFrameHeaderSize()) {
- size_t bytes_desired =
- GetControlFrameHeaderSize() - current_frame_buffer_.len();
+ if (current_frame_buffer_.len() < GetFrameHeaderSize()) {
+ size_t bytes_desired = GetFrameHeaderSize() - current_frame_buffer_.len();
UpdateCurrentFrameBuffer(&data, &len, bytes_desired);
}
- if (current_frame_buffer_.len() < GetControlFrameHeaderSize()) {
+ if (current_frame_buffer_.len() < GetFrameHeaderSize()) {
// Not enough information to do anything meaningful.
return original_len - len;
}
@@ -909,11 +923,7 @@ size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
control_frame_type_field !=
SpdyConstants::SerializeFrameType(protocol_version_, DATA);
- if (is_control_frame) {
- current_frame_length_ = length_field + GetControlFrameHeaderSize();
- } else {
- current_frame_length_ = length_field + GetDataFrameMinimumSize();
- }
+ current_frame_length_ = length_field + GetFrameHeaderSize();
successful_read = reader.ReadUInt8(&current_frame_flags_);
DCHECK(successful_read);
@@ -924,9 +934,7 @@ size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
remaining_data_length_ = current_frame_length_ - reader.GetBytesConsumed();
}
- DCHECK_EQ(is_control_frame ? GetControlFrameHeaderSize()
- : GetDataFrameMinimumSize(),
- reader.GetBytesConsumed());
+ DCHECK_EQ(GetFrameHeaderSize(), reader.GetBytesConsumed());
DCHECK_EQ(current_frame_length_,
remaining_data_length_ + reader.GetBytesConsumed());
@@ -945,6 +953,10 @@ size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
}
}
+ // If we're here, then we have the common header all received.
+ visitor_->OnCommonHeader(current_frame_stream_id_, remaining_data_length_,
+ control_frame_type_field, current_frame_flags_);
+
current_frame_type_ = ValidateFrameHeader(
is_control_frame, control_frame_type_field, remaining_data_length_);
@@ -952,16 +964,7 @@ size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
return original_len - len;
}
- // if we're here, then we have the common header all received.
if (!is_control_frame) {
- if (protocol_version_ == HTTP2) {
- // Catch bogus tests sending oversized DATA frames.
- // TODO(dahollings): Remove this SPDY_BUG when deprecating
- // --gfe2_reloadable_flag_enforce_max_frame_size.
- SPDY_BUG_IF(GetFrameMaximumSize() < current_frame_length_)
- << "DATA frame too large for HTTP/2.";
- }
-
uint8_t valid_data_flags = 0;
if (protocol_version_ == SPDY3) {
valid_data_flags = DATA_FLAG_FIN;
@@ -994,7 +997,7 @@ size_t SpdyFramer::ProcessCommonHeader(const char* data, size_t len) {
void SpdyFramer::ProcessControlFrameHeader(int control_frame_type_field) {
DCHECK_EQ(SPDY_NO_ERROR, error_code_);
- DCHECK_LE(GetControlFrameHeaderSize(), current_frame_buffer_.len());
+ DCHECK_LE(GetFrameHeaderSize(), current_frame_buffer_.len());
// Do some sanity checking on the control frame sizes and flags.
switch (current_frame_type_) {
@@ -1030,8 +1033,8 @@ void SpdyFramer::ProcessControlFrameHeader(int control_frame_type_field) {
// Size of each key/value pair in bytes.
size_t setting_size = SpdyConstants::GetSettingSize(protocol_version_);
if (current_frame_length_ < GetSettingsMinimumSize() ||
- (current_frame_length_ - GetControlFrameHeaderSize())
- % setting_size != values_prefix_size) {
+ (current_frame_length_ - GetFrameHeaderSize()) % setting_size !=
+ values_prefix_size) {
DLOG(WARNING) << "Invalid length for SETTINGS frame: "
<< current_frame_length_;
set_error(SPDY_INVALID_CONTROL_FRAME_SIZE);
@@ -1194,10 +1197,10 @@ void SpdyFramer::ProcessControlFrameHeader(int control_frame_type_field) {
return;
}
- if ((!enforce_max_frame_size_ || protocol_version_ == SPDY3) &&
+ if (protocol_version_ == SPDY3 &&
current_frame_length_ >
kSpdyInitialFrameSizeLimit +
- SpdyConstants::GetControlFrameHeaderSize(protocol_version_)) {
+ SpdyConstants::GetFrameHeaderSize(protocol_version_)) {
DLOG(WARNING) << "Received control frame of type " << current_frame_type_
<< " with way too big of a payload: "
<< current_frame_length_;
@@ -1507,7 +1510,7 @@ size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
if (remaining_control_header_ == 0) {
SpdyFrameReader reader(current_frame_buffer_.data(),
current_frame_buffer_.len());
- reader.Seek(GetControlFrameHeaderSize()); // Seek past frame header.
+ reader.Seek(GetFrameHeaderSize()); // Seek past frame header.
switch (current_frame_type_) {
case SYN_STREAM:
@@ -1693,7 +1696,7 @@ size_t SpdyFramer::ProcessControlFrameBeforeHeaderBlock(const char* data,
#endif
}
- if (current_frame_type_ != CONTINUATION) {
+ if (use_new_methods_ && current_frame_type_ != CONTINUATION) {
header_handler_ = visitor_->OnHeaderFrameStart(current_frame_stream_id_);
if (header_handler_ == nullptr) {
SPDY_BUG << "visitor_->OnHeaderFrameStart returned nullptr";
@@ -1763,18 +1766,34 @@ size_t SpdyFramer::ProcessControlFrameHeaderBlock(const char* data,
size_t compressed_len = 0;
if (GetHpackDecoder()->HandleControlFrameHeadersComplete(
&compressed_len)) {
- visitor_->OnHeaderFrameEnd(current_frame_stream_id_, true);
- if (state_ == SPDY_ERROR) {
- return data_len;
+ if (use_new_methods_) {
+ visitor_->OnHeaderFrameEnd(current_frame_stream_id_, true);
+ if (state_ == SPDY_ERROR) {
+ return data_len;
+ }
+ } else {
+ // TODO(jgraettinger): To be removed with migration to
+ // SpdyHeadersHandlerInterface. Serializes the HPACK block as a
+ // SPDY3 block, delivered via reentrant call to
+ // ProcessControlFrameHeaderBlock().
+ DeliverHpackBlockAsSpdy3Block(compressed_len);
+ return process_bytes;
}
} else {
set_error(SPDY_DECOMPRESS_FAILURE);
processed_successfully = false;
}
} else {
- visitor_->OnHeaderFrameEnd(current_frame_stream_id_, true);
- if (state_ == SPDY_ERROR) {
- return data_len;
+ if (use_new_methods_) {
+ visitor_->OnHeaderFrameEnd(current_frame_stream_id_, true);
+ if (state_ == SPDY_ERROR) {
+ return data_len;
+ }
+ } else {
+ // The complete header block has been delivered. We send a zero-length
+ // OnControlFrameHeaderData() to indicated this.
+ visitor_->OnControlFrameHeaderData(current_frame_stream_id_, nullptr,
+ 0);
}
}
}
@@ -1970,7 +1989,7 @@ size_t SpdyFramer::ProcessControlFramePayload(const char* data, size_t len) {
if (remaining_data_length_ == 0) {
SpdyFrameReader reader(current_frame_buffer_.data(),
current_frame_buffer_.len());
- reader.Seek(GetControlFrameHeaderSize()); // Skip frame header.
+ reader.Seek(GetFrameHeaderSize()); // Skip frame header.
// Use frame-specific handlers.
switch (current_frame_type_) {
@@ -2065,7 +2084,7 @@ size_t SpdyFramer::ProcessGoAwayFramePayload(const char* data, size_t len) {
// Parse out the last good stream id.
SpdyFrameReader reader(current_frame_buffer_.data(),
current_frame_buffer_.len());
- reader.Seek(GetControlFrameHeaderSize()); // Seek past frame header.
+ reader.Seek(GetFrameHeaderSize()); // Seek past frame header.
bool successful_read = reader.ReadUInt31(&current_frame_stream_id_);
DCHECK(successful_read);
@@ -2129,7 +2148,7 @@ size_t SpdyFramer::ProcessRstStreamFramePayload(const char* data, size_t len) {
// Parse out the last good stream id.
SpdyFrameReader reader(current_frame_buffer_.data(),
current_frame_buffer_.len());
- reader.Seek(GetControlFrameHeaderSize()); // Seek past frame header.
+ reader.Seek(GetFrameHeaderSize()); // Seek past frame header.
if (protocol_version_ == SPDY3) {
bool successful_read = reader.ReadUInt31(&current_frame_stream_id_);
DCHECK(successful_read);
@@ -2181,7 +2200,7 @@ size_t SpdyFramer::ProcessAltSvcFramePayload(const char* data, size_t len) {
len = std::min(len, remaining_data_length_);
if (altsvc_scratch_ == nullptr) {
- size_t capacity = current_frame_length_ - GetControlFrameHeaderSize();
+ size_t capacity = current_frame_length_ - GetFrameHeaderSize();
altsvc_scratch_.reset(new CharBuffer(capacity));
}
altsvc_scratch_->CopyFrom(data, len);
@@ -2371,6 +2390,61 @@ bool SpdyFramer::ParseHeaderBlockInBuffer(const char* header_data,
return true;
}
+SpdyFramer::SpdyHeaderFrameIterator::SpdyHeaderFrameIterator(
+ SpdyFramer* framer,
+ std::unique_ptr<SpdyHeadersIR> headers_ir)
+ : headers_ir_(std::move(headers_ir)),
+ framer_(framer),
+ debug_total_size_(0),
+ is_first_frame_(true),
+ has_next_frame_(true) {
+ encoder_ = framer_->GetHpackEncoder()->EncodeHeaderSet(
+ headers_ir_->header_block(), framer_->enable_compression_);
+}
+
+SpdyFramer::SpdyHeaderFrameIterator::~SpdyHeaderFrameIterator() {}
+
+SpdySerializedFrame SpdyFramer::SpdyHeaderFrameIterator::NextFrame() {
+ if (!has_next_frame_) {
+ SPDY_BUG << "SpdyFramer::SpdyHeaderFrameIterator::NextFrame called without "
+ << "a next frame.";
+ return SpdySerializedFrame();
+ }
+
+ size_t size_without_block =
+ is_first_frame_ ? framer_->GetHeaderFrameSizeSansBlock(*headers_ir_)
+ : framer_->GetContinuationMinimumSize();
+ auto encoding = base::MakeUnique<string>();
+ encoder_->Next(kMaxControlFrameSize - size_without_block, encoding.get());
+ has_next_frame_ = encoder_->HasNext();
+
+ if (framer_->debug_visitor_ != nullptr) {
+ debug_total_size_ += size_without_block;
+ debug_total_size_ += encoding->size();
+ if (!has_next_frame_) {
+ // HTTP2 uses HPACK for header compression. However, continue to
+ // use GetSerializedLength() for an apples-to-apples comparision of
+ // compression performance between HPACK and SPDY w/ deflate.
+ size_t debug_payload_len =
+ framer_->GetSerializedLength(HTTP2, &headers_ir_->header_block());
+ framer_->debug_visitor_->OnSendCompressedFrame(headers_ir_->stream_id(),
+ HEADERS, debug_payload_len,
+ debug_total_size_);
+ }
+ }
+
+ if (is_first_frame_) {
+ is_first_frame_ = false;
+ headers_ir_->set_end_headers(!has_next_frame_);
+ return framer_->SerializeHeadersGivenEncoding(*headers_ir_, *encoding);
+ } else {
+ SpdyContinuationIR continuation_ir(headers_ir_->stream_id());
+ continuation_ir.set_end_headers(!has_next_frame_);
+ continuation_ir.take_encoding(std::move(encoding));
+ return framer_->SerializeContinuation(continuation_ir);
+ }
+}
+
SpdySerializedFrame SpdyFramer::SerializeData(const SpdyDataIR& data_ir) const {
uint8_t flags = DATA_FLAG_NONE;
if (data_ir.fin()) {
@@ -2378,10 +2452,10 @@ SpdySerializedFrame SpdyFramer::SerializeData(const SpdyDataIR& data_ir) const {
}
if (protocol_version_ == SPDY3) {
- const size_t size = GetDataFrameMinimumSize() + data_ir.data().length();
+ const size_t size = GetDataFrameMinimumSize() + data_ir.data_len();
SpdyFrameBuilder builder(size, protocol_version_);
builder.WriteDataFrameHeader(*this, data_ir.stream_id(), flags);
- builder.WriteBytes(data_ir.data().data(), data_ir.data().length());
+ builder.WriteBytes(data_ir.data(), data_ir.data_len());
DCHECK_EQ(size, builder.length());
return builder.take();
} else {
@@ -2391,15 +2465,15 @@ SpdySerializedFrame SpdyFramer::SerializeData(const SpdyDataIR& data_ir) const {
++num_padding_fields;
}
- const size_t size_with_padding = num_padding_fields +
- data_ir.data().length() + data_ir.padding_payload_len() +
- GetDataFrameMinimumSize();
+ const size_t size_with_padding = num_padding_fields + data_ir.data_len() +
+ data_ir.padding_payload_len() +
+ GetDataFrameMinimumSize();
SpdyFrameBuilder builder(size_with_padding, protocol_version_);
builder.WriteDataFrameHeader(*this, data_ir.stream_id(), flags);
if (data_ir.padded()) {
builder.WriteUInt8(data_ir.padding_payload_len() & 0xff);
}
- builder.WriteBytes(data_ir.data().data(), data_ir.data().length());
+ builder.WriteBytes(data_ir.data(), data_ir.data_len());
if (data_ir.padding_payload_len() > 0) {
string padding(data_ir.padding_payload_len(), 0);
builder.WriteBytes(padding.data(), padding.length());
@@ -2432,10 +2506,10 @@ SpdySerializedFrame SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthField(
if (data_ir.padded()) {
builder.WriteUInt8(data_ir.padding_payload_len() & 0xff);
}
- builder.OverwriteLength(*this, num_padding_fields +
- data_ir.data().length() + data_ir.padding_payload_len());
+ builder.OverwriteLength(*this, num_padding_fields + data_ir.data_len() +
+ data_ir.padding_payload_len());
} else {
- builder.OverwriteLength(*this, data_ir.data().length());
+ builder.OverwriteLength(*this, data_ir.data_len());
}
DCHECK_EQ(frame_size, builder.length());
return builder.take();
@@ -2843,35 +2917,50 @@ SpdySerializedFrame SpdyFramer::SerializePushPromise(
return builder.take();
}
-// TODO(jgraettinger): This implementation is incorrect. The continuation
-// frame continues a previously-begun HPACK encoding; it doesn't begin a
-// new one. Figure out whether it makes sense to keep SerializeContinuation().
-SpdySerializedFrame SpdyFramer::SerializeContinuation(
- const SpdyContinuationIR& continuation) {
- CHECK_EQ(HTTP2, protocol_version_);
- uint8_t flags = 0;
- if (continuation.end_headers()) {
- flags |= HEADERS_FLAG_END_HEADERS;
+SpdySerializedFrame SpdyFramer::SerializeHeadersGivenEncoding(
+ const SpdyHeadersIR& headers,
+ const string& encoding) const {
+ DCHECK_EQ(HTTP2, protocol_version_);
+
+ size_t frame_size = GetHeaderFrameSizeSansBlock(headers) + encoding.size();
+ SpdyFrameBuilder builder(frame_size, protocol_version_);
+ builder.BeginNewFrame(*this, HEADERS, SerializeHeaderFrameFlags(headers),
+ headers.stream_id());
+ DCHECK_EQ(GetFrameHeaderSize(), builder.length());
+
+ if (headers.padded()) {
+ builder.WriteUInt8(headers.padding_payload_len());
}
- // The size of this frame, including variable-length name-value block.
- size_t size = GetContinuationMinimumSize();
- string hpack_encoding;
- if (enable_compression_) {
- GetHpackEncoder()->EncodeHeaderSet(continuation.header_block(),
- &hpack_encoding);
- } else {
- GetHpackEncoder()->EncodeHeaderSetWithoutCompression(
- continuation.header_block(), &hpack_encoding);
+ if (headers.has_priority()) {
+ int weight = ClampHttp2Weight(headers.weight());
+ builder.WriteUInt32(PackStreamDependencyValues(headers.exclusive(),
+ headers.parent_stream_id()));
+ // Per RFC 7540 section 6.3, serialized weight value is actual value - 1.
+ builder.WriteUInt8(weight - 1);
}
- size += hpack_encoding.size();
- SpdyFrameBuilder builder(size, protocol_version_);
- builder.BeginNewFrame(*this, CONTINUATION, flags,
- continuation.stream_id());
- DCHECK_EQ(GetContinuationMinimumSize(), builder.length());
+ builder.WriteBytes(&encoding[0], encoding.size());
- builder.WriteBytes(&hpack_encoding[0], hpack_encoding.size());
+ if (headers.padding_payload_len() > 0) {
+ string padding(headers.padding_payload_len(), 0);
+ builder.WriteBytes(padding.data(), padding.length());
+ }
+ return builder.take();
+}
+
+SpdySerializedFrame SpdyFramer::SerializeContinuation(
+ const SpdyContinuationIR& continuation) const {
+ DCHECK_EQ(HTTP2, protocol_version_);
+
+ const string& encoding = continuation.encoding();
+ size_t frame_size = GetContinuationMinimumSize() + encoding.size();
+ SpdyFrameBuilder builder(frame_size, protocol_version_);
+ uint8_t flags = continuation.end_headers() ? HEADERS_FLAG_END_HEADERS : 0;
+ builder.BeginNewFrame(*this, CONTINUATION, flags, continuation.stream_id());
+ DCHECK_EQ(GetFrameHeaderSize(), builder.length());
+
+ builder.WriteBytes(&encoding[0], encoding.size());
return builder.take();
}
@@ -2997,6 +3086,40 @@ size_t SpdyFramer::GetNumberRequiredContinuationFrames(size_t size) {
return (overflow - 1) / payload_size + 1;
}
+size_t SpdyFramer::GetHeaderFrameSizeSansBlock(
+ const SpdyHeadersIR& header_ir) const {
+ size_t min_size = GetFrameHeaderSize();
+
+ if (header_ir.padded()) {
+ min_size += 1;
+ min_size += header_ir.padding_payload_len();
+ }
+
+ if (header_ir.has_priority()) {
+ min_size += 5;
+ }
+
+ return min_size;
+}
+
+uint8_t SpdyFramer::SerializeHeaderFrameFlags(
+ const SpdyHeadersIR& header_ir) const {
+ uint8_t flags = 0;
+ if (header_ir.fin()) {
+ flags |= CONTROL_FLAG_FIN;
+ }
+ if (header_ir.end_headers()) {
+ flags |= HEADERS_FLAG_END_HEADERS;
+ }
+ if (header_ir.padded()) {
+ flags |= HEADERS_FLAG_PADDED;
+ }
+ if (header_ir.has_priority()) {
+ flags |= HEADERS_FLAG_PRIORITY;
+ }
+ return flags;
+}
+
void SpdyFramer::WritePayloadWithContinuation(SpdyFrameBuilder* builder,
const string& hpack_encoding,
SpdyStreamId stream_id,
@@ -3027,8 +3150,8 @@ void SpdyFramer::WritePayloadWithContinuation(SpdyFrameBuilder* builder,
builder->WriteBytes(padding.data(), padding.length());
}
if (bytes_remaining > 0) {
- builder->OverwriteLength(
- *this, kMaxControlFrameSize - GetControlFrameHeaderSize());
+ builder->OverwriteLength(*this,
+ kMaxControlFrameSize - GetFrameHeaderSize());
}
// Tack on CONTINUATION frames for the overflow.
@@ -3178,11 +3301,17 @@ bool SpdyFramer::IncrementallyDecompressControlFrameHeaderData(
if ((rv == Z_OK) || input_exhausted) {
size_t decompressed_len = arraysize(buffer) - decomp->avail_out;
if (decompressed_len > 0) {
- processed_successfully = header_parser_->HandleControlFrameHeadersData(
- stream_id, buffer, decompressed_len);
- if (header_parser_->get_error() ==
- SpdyHeadersBlockParser::NEED_MORE_DATA) {
- processed_successfully = true;
+ if (use_new_methods_) {
+ processed_successfully =
+ header_parser_->HandleControlFrameHeadersData(stream_id, buffer,
+ decompressed_len);
+ if (header_parser_->get_error() ==
+ SpdyHeadersBlockParser::NEED_MORE_DATA) {
+ processed_successfully = true;
+ }
+ } else {
+ processed_successfully = visitor_->OnControlFrameHeaderData(
+ stream_id, buffer, decompressed_len);
}
}
if (!processed_successfully) {
@@ -3204,10 +3333,16 @@ bool SpdyFramer::IncrementallyDeliverControlFrameHeaderData(
bool read_successfully = true;
while (read_successfully && len > 0) {
size_t bytes_to_deliver = std::min(len, kHeaderDataChunkMaxSize);
- read_successfully = header_parser_->HandleControlFrameHeadersData(
- stream_id, data, bytes_to_deliver);
- if (header_parser_->get_error() == SpdyHeadersBlockParser::NEED_MORE_DATA) {
- read_successfully = true;
+ if (use_new_methods_) {
+ read_successfully = header_parser_->HandleControlFrameHeadersData(
+ stream_id, data, bytes_to_deliver);
+ if (header_parser_->get_error() ==
+ SpdyHeadersBlockParser::NEED_MORE_DATA) {
+ read_successfully = true;
+ }
+ } else {
+ read_successfully =
+ visitor_->OnControlFrameHeaderData(stream_id, data, bytes_to_deliver);
}
data += bytes_to_deliver;
len -= bytes_to_deliver;
@@ -3222,7 +3357,11 @@ bool SpdyFramer::IncrementallyDeliverControlFrameHeaderData(
void SpdyFramer::SetDecoderHeaderTableDebugVisitor(
std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) {
- GetHpackDecoder()->SetHeaderTableDebugVisitor(std::move(visitor));
+ if (decoder_adapter_ != nullptr) {
+ decoder_adapter_->SetDecoderHeaderTableDebugVisitor(std::move(visitor));
+ } else {
+ GetHpackDecoder()->SetHeaderTableDebugVisitor(std::move(visitor));
+ }
}
void SpdyFramer::SetEncoderHeaderTableDebugVisitor(
@@ -3234,6 +3373,10 @@ void SpdyFramer::UpdateHeaderEncoderTableSize(uint32_t value) {
GetHpackEncoder()->ApplyHeaderTableSizeSetting(value);
}
+void SpdyFramer::UpdateHeaderDecoderTableSize(uint32_t value) {
+ GetHpackDecoder()->ApplyHeaderTableSizeSetting(value);
+}
+
size_t SpdyFramer::header_encoder_table_size() const {
if (hpack_encoder_ == nullptr) {
return kDefaultHeaderTableSizeSetting;
diff --git a/chromium/net/spdy/spdy_framer.h b/chromium/net/spdy/spdy_framer.h
index 0809b662d8e..7fd04e4a836 100644
--- a/chromium/net/spdy/spdy_framer.h
+++ b/chromium/net/spdy/spdy_framer.h
@@ -105,6 +105,13 @@ class NET_EXPORT_PRIVATE SpdyFramerVisitorInterface {
// Called if an error is detected in the SpdySerializedFrame protocol.
virtual void OnError(SpdyFramer* framer) = 0;
+ // Called when the common header for a frame is received. Validating the
+ // common header occurs in later processing.
+ virtual void OnCommonHeader(SpdyStreamId stream_id,
+ size_t length,
+ uint8_t type,
+ uint8_t flags) {}
+
// Called when a data frame header is received. The frame's data
// payload will be provided via subsequent calls to
// OnStreamFrameData().
@@ -355,6 +362,11 @@ class NET_EXPORT_PRIVATE SpdyFramer {
LAST_ERROR, // Must be the last entry in the enum.
};
+ // Typedef for a function used to create SpdyFramerDecoderAdapter's.
+ // Defined in support of evaluating an alternate HTTP/2 decoder.
+ typedef std::unique_ptr<SpdyFramerDecoderAdapter> (*DecoderAdapterFactoryFn)(
+ SpdyFramer* outer);
+
// Constant for invalid (or unknown) stream IDs.
static const SpdyStreamId kInvalidStream;
@@ -377,8 +389,9 @@ class NET_EXPORT_PRIVATE SpdyFramer {
explicit SpdyFramer(SpdyMajorVersion version);
// Used recursively from the above constructor in order to support
- // instantiating a SpdyFramerDecoderAdapter selected via flags.
- SpdyFramer(SpdyMajorVersion version, bool choose_decoder);
+ // instantiating a SpdyFramerDecoderAdapter selected via flags or some other
+ // means.
+ SpdyFramer(SpdyMajorVersion version, DecoderAdapterFactoryFn adapter_factory);
virtual ~SpdyFramer();
@@ -422,6 +435,33 @@ class NET_EXPORT_PRIVATE SpdyFramer {
size_t header_length,
SpdyHeaderBlock* block) const;
+ // Iteratively converts a SpdyHeadersIR (with a possibly huge SpdyHeaderBlock)
+ // into an appropriate sequence of SpdySerializedFrames.
+ class NET_EXPORT_PRIVATE SpdyHeaderFrameIterator {
+ public:
+ SpdyHeaderFrameIterator(SpdyFramer* framer,
+ std::unique_ptr<SpdyHeadersIR> headers_ir);
+ ~SpdyHeaderFrameIterator();
+
+ // SpdyHeaderFrameIterator is neither copyable nor movable.
+ SpdyHeaderFrameIterator(const SpdyHeaderFrameIterator&) = delete;
+ SpdyHeaderFrameIterator& operator=(const SpdyHeaderFrameIterator&) = delete;
+
+ SpdySerializedFrame NextFrame();
+ bool HasNextFrame() const { return has_next_frame_; }
+
+ private:
+ std::unique_ptr<SpdyHeadersIR> headers_ir_;
+ std::unique_ptr<HpackEncoder::ProgressiveEncoder> encoder_;
+ SpdyFramer* framer_;
+
+ // Field for debug reporting.
+ size_t debug_total_size_;
+
+ bool is_first_frame_;
+ bool has_next_frame_;
+ };
+
// Serialize a data frame.
SpdySerializedFrame SerializeData(const SpdyDataIR& data) const;
// Serializes the data frame header and optionally padding length fields,
@@ -476,11 +516,8 @@ class NET_EXPORT_PRIVATE SpdyFramer {
// Serializes a CONTINUATION frame. The CONTINUATION frame is used
// to continue a sequence of header block fragments.
- // TODO(jgraettinger): This implementation is incorrect. The continuation
- // frame continues a previously-begun HPACK encoding; it doesn't begin a
- // new one. Figure out whether it makes sense to keep SerializeContinuation().
SpdySerializedFrame SerializeContinuation(
- const SpdyContinuationIR& continuation);
+ const SpdyContinuationIR& continuation) const;
// Serializes an ALTSVC frame. The ALTSVC frame advertises the
// availability of an alternative service to the client.
@@ -509,6 +546,10 @@ class NET_EXPORT_PRIVATE SpdyFramer {
enable_compression_ = value;
}
+ void SetHpackIndexingPolicy(HpackEncoder::IndexingPolicy policy) {
+ GetHpackEncoder()->SetIndexingPolicy(std::move(policy));
+ }
+
// Used only in log messages.
void set_display_protocol(const std::string& protocol) {
display_protocol_ = protocol;
@@ -519,19 +560,19 @@ class NET_EXPORT_PRIVATE SpdyFramer {
max_decode_buffer_size_bytes);
}
+ size_t send_frame_size_limit() const { return send_frame_size_limit_; }
+
+ void set_send_frame_size_limit(size_t send_frame_size_limit) {
+ send_frame_size_limit_ = send_frame_size_limit;
+ }
+
void set_recv_frame_size_limit(size_t recv_frame_size_limit) {
recv_frame_size_limit_ = recv_frame_size_limit;
}
- void SetDecoderHeaderTableDebugVisitor(
- std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor);
-
- void SetEncoderHeaderTableDebugVisitor(
- std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor);
-
// Returns the (minimum) size of frames (sans variable-length portions).
size_t GetDataFrameMinimumSize() const;
- size_t GetControlFrameHeaderSize() const;
+ size_t GetFrameHeaderSize() const;
size_t GetSynStreamMinimumSize() const;
size_t GetSynReplyMinimumSize() const;
size_t GetRstStreamMinimumSize() const;
@@ -555,9 +596,6 @@ class NET_EXPORT_PRIVATE SpdyFramer {
// Returns the maximum payload size of a DATA frame.
size_t GetDataFrameMaximumPayload() const;
- // Returns the prefix length for the given frame type.
- size_t GetPrefixLength(SpdyFrameType type) const;
-
// For debugging.
static const char* StateToString(int state);
static const char* ErrorCodeToString(int error_code);
@@ -585,9 +623,23 @@ class NET_EXPORT_PRIVATE SpdyFramer {
// Updates the maximum size of the header encoder compression table.
void UpdateHeaderEncoderTableSize(uint32_t value);
+ // Updates the maximum size of the header decoder compression table.
+ void UpdateHeaderDecoderTableSize(uint32_t value);
+
// Returns the maximum size of the header encoder compression table.
size_t header_encoder_table_size() const;
+ void SetDecoderHeaderTableDebugVisitor(
+ std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor);
+
+ void SetEncoderHeaderTableDebugVisitor(
+ std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor);
+
+ // For testing support (i.e. for clients and backends),
+ // allow overriding the flag on a per framer basis.
+ void set_use_new_methods_for_test(bool v) { use_new_methods_ = v; }
+ bool use_new_methods_for_test() const { return use_new_methods_; }
+
protected:
friend class BufferedSpdyFramer;
friend class HttpNetworkLayer; // This is temporary for the server.
@@ -724,6 +776,19 @@ class NET_EXPORT_PRIVATE SpdyFramer {
void SerializeHeaderBlock(SpdyFrameBuilder* builder,
const SpdyFrameWithHeaderBlockIR& frame);
+ // Serializes a HEADERS frame from the given SpdyHeadersIR and encoded header
+ // block. Does not need or use the SpdyHeaderBlock inside SpdyHeadersIR.
+ SpdySerializedFrame SerializeHeadersGivenEncoding(
+ const SpdyHeadersIR& headers,
+ const std::string& encoding) const;
+
+ // Calculates the number of bytes required to serialize a SpdyHeadersIR, not
+ // including the bytes to be used for the encoded header set.
+ size_t GetHeaderFrameSizeSansBlock(const SpdyHeadersIR& header_ir) const;
+
+ // Serializes the flags octet for a given SpdyHeadersIR.
+ uint8_t SerializeHeaderFrameFlags(const SpdyHeadersIR& header_ir) const;
+
// Set the error code and moves the framer into the error state.
void set_error(SpdyError error);
@@ -739,6 +804,8 @@ class NET_EXPORT_PRIVATE SpdyFramer {
// removed) if necessary later down the line.
// TODO(diannahu): Rename to make it clear that this limit is for sending.
static const size_t kMaxControlFrameSize;
+ // The maximum size for the payload of DATA frames to send.
+ static const size_t kMaxDataPayloadSendSize;
SpdyState state_;
SpdyState previous_state_;
@@ -757,8 +824,12 @@ class NET_EXPORT_PRIVATE SpdyFramer {
// are part of the frame's payload, and not the frame's headers.
size_t remaining_control_header_;
- // The limit on HTTP/2 payload size as specified in the
- // SETTINGS_MAX_FRAME_SIZE advertised to peer
+ // The limit on the size of sent HTTP/2 payloads as specified in the
+ // SETTINGS_MAX_FRAME_SIZE received from peer.
+ size_t send_frame_size_limit_ = kSpdyInitialFrameSizeLimit;
+
+ // The limit on the size of received HTTP/2 payloads as specified in the
+ // SETTINGS_MAX_FRAME_SIZE advertised to peer.
size_t recv_frame_size_limit_ = kSpdyInitialFrameSizeLimit;
CharBuffer current_frame_buffer_;
@@ -837,8 +908,8 @@ class NET_EXPORT_PRIVATE SpdyFramer {
// rather than reading all available input.
bool process_single_input_frame_ = false;
- bool enforce_max_frame_size_ =
- FLAGS_chromium_http2_flag_enforce_max_frame_size;
+ bool use_new_methods_ =
+ FLAGS_chromium_http2_flag_spdy_framer_use_new_methods4;
};
} // namespace net
diff --git a/chromium/net/spdy/spdy_framer_decoder_adapter.cc b/chromium/net/spdy/spdy_framer_decoder_adapter.cc
index a94fc050986..949cbdfa8ba 100644
--- a/chromium/net/spdy/spdy_framer_decoder_adapter.cc
+++ b/chromium/net/spdy/spdy_framer_decoder_adapter.cc
@@ -16,7 +16,7 @@
#elif defined(COMPILER_MSVC)
#define PRETTY_THIS base::StringPrintf("%s@%p ", __FUNCSIG__, this)
#else
-#define PRETTY_THIS base::StringPrintf("%s@%p ", __FUNCTION__, this)
+#define PRETTY_THIS base::StringPrintf("%s@%p ", __func__, this)
#endif
namespace net {
@@ -197,7 +197,7 @@ class NestedSpdyFramerDecoder : public SpdyFramerDecoderAdapter {
public:
explicit NestedSpdyFramerDecoder(SpdyFramer* outer)
- : framer_(HTTP2, false), outer_(outer) {
+ : framer_(HTTP2, nullptr), outer_(outer) {
DVLOG(1) << PRETTY_THIS;
}
~NestedSpdyFramerDecoder() override { DVLOG(1) << PRETTY_THIS; }
@@ -218,6 +218,13 @@ class NestedSpdyFramerDecoder : public SpdyFramerDecoderAdapter {
framer_.set_debug_visitor(debug_visitor);
}
+ // Passes the call on to the wrapped SpdyFramer.
+ void SetDecoderHeaderTableDebugVisitor(
+ std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor)
+ override {
+ framer_.SetDecoderHeaderTableDebugVisitor(std::move(visitor));
+ }
+
// Passes the call on to the base adapter class and wrapped SpdyFramer.
void set_process_single_input_frame(bool v) override {
SpdyFramerDecoderAdapter::set_process_single_input_frame(v);
@@ -226,6 +233,12 @@ class NestedSpdyFramerDecoder : public SpdyFramerDecoderAdapter {
size_t ProcessInput(const char* data, size_t len) override {
DVLOG(2) << "ProcessInput(data, " << len << ")";
+ const bool use_new_methods = outer_->use_new_methods_for_test();
+ if (framer_.use_new_methods_for_test() != use_new_methods) {
+ DVLOG(1) << "Overriding use_new_methods_ in nested framer, setting="
+ << (use_new_methods ? "true" : "false");
+ framer_.set_use_new_methods_for_test(use_new_methods);
+ }
size_t result = framer_.ProcessInput(data, len);
DVLOG(2) << "ProcessInput(data, " << len << ") returning " << result;
return result;
@@ -247,8 +260,10 @@ class NestedSpdyFramerDecoder : public SpdyFramerDecoderAdapter {
std::unique_ptr<SpdyFramerVisitorAdapter> visitor_adapter_;
};
-SpdyFramerDecoderAdapter* CreateNestedSpdyFramerDecoder(SpdyFramer* outer) {
- return new NestedSpdyFramerDecoder(outer);
+std::unique_ptr<SpdyFramerDecoderAdapter> CreateNestedSpdyFramerDecoder(
+ SpdyFramer* outer) {
+ return std::unique_ptr<SpdyFramerDecoderAdapter>(
+ new NestedSpdyFramerDecoder(outer));
}
} // namespace net
diff --git a/chromium/net/spdy/spdy_framer_decoder_adapter.h b/chromium/net/spdy/spdy_framer_decoder_adapter.h
index 9e2a4a34bc6..c20bb8de6e5 100644
--- a/chromium/net/spdy/spdy_framer_decoder_adapter.h
+++ b/chromium/net/spdy/spdy_framer_decoder_adapter.h
@@ -7,7 +7,10 @@
#include <stddef.h>
+#include <memory>
+
#include "base/strings/string_piece.h"
+#include "net/spdy/hpack/hpack_header_table.h"
#include "net/spdy/spdy_alt_svc_wire_format.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_headers_handler_interface.h"
@@ -37,6 +40,10 @@ class SpdyFramerDecoderAdapter {
return debug_visitor_;
}
+ // Set debug callbacks to be called from the HPACK decoder.
+ virtual void SetDecoderHeaderTableDebugVisitor(
+ std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) = 0;
+
// Sets whether or not ProcessInput returns after finishing a frame, or
// continues processing additional frames. Normally ProcessInput processes
// all input, but this method enables the caller (and visitor) to work with
@@ -74,8 +81,11 @@ class SpdyFramerDecoderAdapter {
// Create an instance of NestedSpdyFramerDecoder, which implements
// SpdyFramerDecoderAdapter, delegating to a SpdyFramer instance that will
-// actually perform the decoding (when requested via ProcessInput).
-SpdyFramerDecoderAdapter* CreateNestedSpdyFramerDecoder(SpdyFramer* outer);
+// actually perform the decoding (when requested via ProcessInput). This allows
+// us to test the SpdyFramerDecoderAdapter mechanism without changing the type
+// of decoder that is used.
+std::unique_ptr<SpdyFramerDecoderAdapter> CreateNestedSpdyFramerDecoder(
+ SpdyFramer* outer);
// SpdyFramerVisitorInterface::OnError needs the original SpdyFramer* to
// pass to the visitor (really a listener). This implementation takes care of
diff --git a/chromium/net/spdy/spdy_framer_test.cc b/chromium/net/spdy/spdy_framer_test.cc
index 0c8b071d14e..bbfd0259ee4 100644
--- a/chromium/net/spdy/spdy_framer_test.cc
+++ b/chromium/net/spdy/spdy_framer_test.cc
@@ -16,8 +16,9 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
-#include "net/quic/quic_flags.h"
+#include "net/quic/core/quic_flags.h"
#include "net/spdy/hpack/hpack_constants.h"
#include "net/spdy/mock_spdy_framer_visitor.h"
#include "net/spdy/spdy_flags.h"
@@ -388,6 +389,29 @@ class SpdyFramerTestUtil {
DISALLOW_COPY_AND_ASSIGN(SpdyFramerTestUtil);
};
+MATCHER_P(IsFrameUnionOf, frame_list, "") {
+ size_t size_verified = 0;
+ for (const auto& frame : *frame_list) {
+ if (arg.size() >= size_verified + frame.size()) {
+ if (!memcmp(arg.data() + size_verified, frame.data(), frame.size())) {
+ size_verified += frame.size();
+ } else {
+ CompareCharArraysWithHexError(
+ "Header serialization methods should be equivalent: ",
+ reinterpret_cast<unsigned char*>(arg.data() + size_verified),
+ frame.size(), reinterpret_cast<unsigned char*>(frame.data()),
+ frame.size());
+ return false;
+ }
+ } else {
+ LOG(FATAL) << "Incremental header serialization should not lead to a "
+ << "higher total frame length than non-incremental method.";
+ return false;
+ }
+ }
+ return size_verified == arg.size();
+}
+
class SpdyFramerPeer {
public:
static size_t ControlFrameBufferSize() {
@@ -400,6 +424,46 @@ class SpdyFramerPeer {
static void SetError(SpdyFramer* framer, SpdyFramer::SpdyError error) {
framer->set_error(error);
}
+
+ // TODO(dahollings): Remove these methods when deprecating non-incremental
+ // header serialization path.
+ static std::unique_ptr<SpdyHeadersIR> CloneSpdyHeadersIR(
+ const SpdyHeadersIR& headers) {
+ auto newHeaders = base::MakeUnique<SpdyHeadersIR>(
+ headers.stream_id(), headers.header_block().Clone());
+ newHeaders->set_fin(headers.fin());
+ newHeaders->set_has_priority(headers.has_priority());
+ newHeaders->set_weight(headers.weight());
+ newHeaders->set_parent_stream_id(headers.parent_stream_id());
+ newHeaders->set_exclusive(headers.exclusive());
+ if (headers.padded()) {
+ newHeaders->set_padding_len(headers.padding_payload_len() + 1);
+ }
+ newHeaders->set_end_headers(headers.end_headers());
+ return newHeaders;
+ }
+
+ static SpdySerializedFrame SerializeHeaders(SpdyFramer* framer,
+ const SpdyHeadersIR& headers) {
+ SpdySerializedFrame serialized_headers_old_version =
+ framer->SerializeHeaders(headers);
+ if (framer->protocol_version() == HTTP2) {
+ framer->hpack_encoder_.reset(nullptr);
+ auto saved_debug_visitor = framer->debug_visitor_;
+ framer->debug_visitor_ = nullptr;
+
+ std::vector<SpdySerializedFrame> frame_list;
+ SpdyFramer::SpdyHeaderFrameIterator it(framer,
+ CloneSpdyHeadersIR(headers));
+ while (it.HasNextFrame()) {
+ frame_list.push_back(it.NextFrame());
+ }
+ framer->debug_visitor_ = saved_debug_visitor;
+
+ EXPECT_THAT(serialized_headers_old_version, IsFrameUnionOf(&frame_list));
+ }
+ return serialized_headers_old_version;
+ }
};
class TestSpdyVisitor : public SpdyFramerVisitorInterface,
@@ -886,7 +950,7 @@ TEST_P(SpdyFramerTest, HeaderBlockWithEmptyCookie) {
SpdyHeadersIR headers(1);
headers.SetHeader("cookie",
"=; key=value; ; = ; foo; bar=; ; = ; k2=v2 ; =");
- SpdySerializedFrame frame(framer.SerializeHeaders(headers));
+ SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(&framer, headers));
TestSpdyVisitor visitor(spdy_version_);
visitor.use_compression_ = true;
@@ -909,7 +973,7 @@ TEST_P(SpdyFramerTest, HeaderBlockInBuffer) {
headers.SetHeader("alpha", "beta");
headers.SetHeader("gamma", "charlie");
headers.SetHeader("cookie", "key1=value1; key2=value2");
- SpdySerializedFrame frame(framer.SerializeHeaders(headers));
+ SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(&framer, headers));
TestSpdyVisitor visitor(spdy_version_);
visitor.use_compression_ = false;
@@ -929,7 +993,7 @@ TEST_P(SpdyFramerTest, UndersizedHeaderBlockInBuffer) {
SpdyHeadersIR headers(1);
headers.SetHeader("alpha", "beta");
headers.SetHeader("gamma", "charlie");
- SpdySerializedFrame frame(framer.SerializeHeaders(headers));
+ SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(&framer, headers));
TestSpdyVisitor visitor(spdy_version_);
visitor.use_compression_ = false;
@@ -958,7 +1022,8 @@ TEST_P(SpdyFramerTest, HeaderStreamDependencyValues) {
headers.set_has_priority(true);
headers.set_parent_stream_id(parent_stream_id);
headers.set_exclusive(exclusive);
- SpdySerializedFrame frame(framer.SerializeHeaders(headers));
+ SpdySerializedFrame frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers));
TestSpdyVisitor visitor(spdy_version_);
visitor.use_compression_ = false;
@@ -1004,8 +1069,6 @@ TEST_P(SpdyFramerTest, AcceptMaxFrameSizeSetting) {
// Test that if we receive a frame with payload length larger than the
// advertised max size, we set an error of SPDY_INVALID_CONTROL_FRAME_SIZE.
TEST_P(SpdyFramerTest, ExceedMaxFrameSizeSetting) {
- FLAGS_chromium_http2_flag_enforce_max_frame_size = true;
-
if (!IsHttp2()) {
return;
}
@@ -1033,36 +1096,6 @@ TEST_P(SpdyFramerTest, ExceedMaxFrameSizeSetting) {
<< SpdyFramer::ErrorCodeToString(framer.error_code());
}
-// Test demonstrating pre-flag behavior
-TEST_P(SpdyFramerTest, ExceedMaxFrameSizeSettingFlagOff) {
- FLAGS_chromium_http2_flag_enforce_max_frame_size = false;
-
- if (!IsHttp2()) {
- return;
- }
-
- testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
- SpdyFramer framer(spdy_version_);
- framer.set_visitor(&visitor);
-
- // DATA frame with too large payload length.
- unsigned char kH2FrameData[] = {
- 0x00, 0x40, 0x01, // Length: 2^14 + 1
- 0x00, // Type: HEADERS
- 0x00, // Flags: None
- 0x00, 0x00, 0x00, 0x01, // Stream: 1
- 0x00, 0x00, 0x00, 0x00, // Junk payload
- };
-
- SpdySerializedFrame frame(reinterpret_cast<char*>(kH2FrameData),
- sizeof(kH2FrameData), false);
- EXPECT_CALL(visitor, OnDataFrameHeader(1, _, false));
- EXPECT_CALL(visitor, OnStreamFrameData(1, _, 4));
- EXPECT_SPDY_BUG(framer.ProcessInput(frame.data(), frame.size()),
- "DATA frame too large for HTTP/2.");
- EXPECT_FALSE(framer.HasError());
-}
-
// Test that if we receive a DATA frame with padding length larger than the
// payload length, we set an error of SPDY_INVALID_PADDING
TEST_P(SpdyFramerTest, OversizedDataPaddingError) {
@@ -1261,9 +1294,9 @@ TEST_P(SpdyFramerTest, HeadersWithStreamIdZero) {
SpdyFramer framer(spdy_version_);
framer.set_visitor(&visitor);
- SpdyHeadersIR headers_ir(0);
- headers_ir.SetHeader("alpha", "beta");
- SpdySerializedFrame frame(framer.SerializeHeaders(headers_ir));
+ SpdyHeadersIR headers(0);
+ headers.SetHeader("alpha", "beta");
+ SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(&framer, headers));
// We shouldn't have to read the whole frame before we signal an error.
EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
@@ -1397,8 +1430,9 @@ TEST_P(SpdyFramerTest, ContinuationWithStreamIdZero) {
framer.set_visitor(&visitor);
SpdyContinuationIR continuation(0);
- continuation.SetHeader("bar", "foo");
- continuation.SetHeader("foo", "bar");
+ auto some_nonsense_encoding =
+ base::MakeUnique<string>("some nonsense encoding");
+ continuation.take_encoding(std::move(some_nonsense_encoding));
continuation.set_end_headers(true);
SpdySerializedFrame frame(framer.SerializeContinuation(continuation));
@@ -1620,7 +1654,8 @@ TEST_P(SpdyFramerTest, CompressEmptyHeaders) {
SpdyFramer framer(spdy_version_);
framer.set_enable_compression(true);
- SpdySerializedFrame frame1(framer.SerializeHeaders(headers));
+ SpdySerializedFrame frame1(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers));
}
TEST_P(SpdyFramerTest, Basic) {
@@ -1995,9 +2030,9 @@ TEST_P(SpdyFramerTest, HeaderCompression) {
// Verify we can decompress the stream even if handed over to the
// framer 1 byte at a time.
TEST_P(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) {
- SpdyFramer send_framer(spdy_version_);
+ SpdyFramer framer(spdy_version_);
- send_framer.set_enable_compression(true);
+ framer.set_enable_compression(true);
const char kHeader1[] = "header1";
const char kHeader2[] = "header2";
@@ -2007,12 +2042,13 @@ TEST_P(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) {
SpdyHeadersIR headers(1);
headers.SetHeader(kHeader1, kValue1);
headers.SetHeader(kHeader2, kValue2);
- SpdySerializedFrame headers_frame(send_framer.SerializeHeaders(headers));
+ SpdySerializedFrame headers_frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers));
const char bytes[] = "this is a test test test test test!";
SpdyDataIR data_ir(1, StringPiece(bytes, arraysize(bytes)));
data_ir.set_fin(true);
- SpdySerializedFrame send_frame(send_framer.SerializeData(data_ir));
+ SpdySerializedFrame send_frame(framer.SerializeData(data_ir));
// Run the inputs through the framer.
TestSpdyVisitor visitor(spdy_version_);
@@ -3107,10 +3143,11 @@ TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
};
// frame-format on
- SpdyHeadersIR headers_ir(1);
- headers_ir.SetHeader("bar", "foo");
- headers_ir.SetHeader("foo", "bar");
- SpdySerializedFrame frame(framer.SerializeHeaders(headers_ir));
+ SpdyHeadersIR headers(1);
+ headers.SetHeader("bar", "foo");
+ headers.SetHeader("foo", "bar");
+ SpdySerializedFrame frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers));
if (IsSpdy3()) {
CompareFrame(kDescription, frame, kV3FrameData, arraysize(kV3FrameData));
} else {
@@ -3156,11 +3193,12 @@ TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
0x62, 0x61, 0x72, // bar
};
// frame-format on
- SpdyHeadersIR headers_ir(0x7fffffff);
- headers_ir.set_fin(true);
- headers_ir.SetHeader("", "foo");
- headers_ir.SetHeader("foo", "bar");
- SpdySerializedFrame frame(framer.SerializeHeaders(headers_ir));
+ SpdyHeadersIR headers(0x7fffffff);
+ headers.set_fin(true);
+ headers.SetHeader("", "foo");
+ headers.SetHeader("foo", "bar");
+ SpdySerializedFrame frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers));
if (IsSpdy3()) {
CompareFrame(kDescription, frame, kV3FrameData, arraysize(kV3FrameData));
} else {
@@ -3210,7 +3248,8 @@ TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
headers_ir.set_fin(true);
headers_ir.SetHeader("bar", "foo");
headers_ir.SetHeader("foo", "");
- SpdySerializedFrame frame(framer.SerializeHeaders(headers_ir));
+ SpdySerializedFrame frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers_ir));
if (IsSpdy3()) {
CompareFrame(kDescription, frame, kV3FrameData, arraysize(kV3FrameData));
} else {
@@ -3249,7 +3288,8 @@ TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
headers_ir.set_weight(220);
headers_ir.SetHeader("bar", "foo");
headers_ir.SetHeader("foo", "");
- SpdySerializedFrame frame(framer.SerializeHeaders(headers_ir));
+ SpdySerializedFrame frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers_ir));
if (IsSpdy3()) {
// HEADERS with priority not supported.
} else {
@@ -3291,7 +3331,8 @@ TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
headers_ir.set_parent_stream_id(0);
headers_ir.SetHeader("bar", "foo");
headers_ir.SetHeader("foo", "");
- SpdySerializedFrame frame(framer.SerializeHeaders(headers_ir));
+ SpdySerializedFrame frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers_ir));
if (IsSpdy3()) {
// HEADERS with priority not supported.
} else {
@@ -3333,7 +3374,8 @@ TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
headers_ir.set_parent_stream_id(0x7fffffff);
headers_ir.SetHeader("bar", "foo");
headers_ir.SetHeader("foo", "");
- SpdySerializedFrame frame(framer.SerializeHeaders(headers_ir));
+ SpdySerializedFrame frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers_ir));
if (IsSpdy3()) {
// HEADERS with priority not supported.
} else {
@@ -3373,7 +3415,8 @@ TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
headers_ir.SetHeader("", "foo");
headers_ir.SetHeader("foo", "bar");
headers_ir.set_padding_len(6);
- SpdySerializedFrame frame(framer.SerializeHeaders(headers_ir));
+ SpdySerializedFrame frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers_ir));
if (IsSpdy3()) {
// Padding is not supported.
} else {
@@ -3429,7 +3472,8 @@ TEST_P(SpdyFramerTest, CreateHeadersCompressed) {
SpdyHeadersIR headers_ir(1);
headers_ir.SetHeader("bar", "foo");
headers_ir.SetHeader("foo", "bar");
- SpdySerializedFrame frame(framer.SerializeHeaders(headers_ir));
+ SpdySerializedFrame frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers_ir));
const unsigned char* frame_data =
reinterpret_cast<const unsigned char*>(frame.data());
if (IsSpdy3()) {
@@ -3748,10 +3792,17 @@ TEST_P(SpdyFramerTest, CreateContinuationUncompressed) {
};
// frame-format on
+ SpdyHeaderBlock header_block;
+ header_block["bar"] = "foo";
+ header_block["foo"] = "bar";
+ auto buffer = base::MakeUnique<string>();
+ HpackEncoder encoder(ObtainHpackHuffmanTable());
+ encoder.EncodeHeaderSetWithoutCompression(header_block, buffer.get());
+
SpdyContinuationIR continuation(42);
- continuation.SetHeader("bar", "foo");
- continuation.SetHeader("foo", "bar");
+ continuation.take_encoding(std::move(buffer));
continuation.set_end_headers(true);
+
SpdySerializedFrame frame(framer.SerializeContinuation(continuation));
CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData));
}
@@ -4004,7 +4055,8 @@ TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlock) {
SpdyHeadersIR headers_ir(1);
headers_ir.SetHeader("alpha", "beta");
headers_ir.SetHeader("gamma", "delta");
- SpdySerializedFrame control_frame(framer.SerializeHeaders(headers_ir));
+ SpdySerializedFrame control_frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers_ir));
TestSpdyVisitor visitor(spdy_version_);
visitor.use_compression_ = true;
visitor.SimulateInFramer(
@@ -4023,7 +4075,8 @@ TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlockWithHalfClose) {
headers_ir.set_fin(true);
headers_ir.SetHeader("alpha", "beta");
headers_ir.SetHeader("gamma", "delta");
- SpdySerializedFrame control_frame(framer.SerializeHeaders(headers_ir));
+ SpdySerializedFrame control_frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers_ir));
TestSpdyVisitor visitor(spdy_version_);
visitor.use_compression_ = true;
visitor.SimulateInFramer(
@@ -4087,8 +4140,8 @@ TEST_P(SpdyFramerTest, ControlFrameTooLarge) {
SpdySerializedFrame control_frame(framer.SerializeSynStream(syn_stream));
const size_t kBigValueSize =
TestSpdyVisitor::received_control_frame_max_size() +
- SpdyConstants::GetControlFrameHeaderSize(spdy_version_) -
- control_frame.size() + 1;
+ SpdyConstants::GetFrameHeaderSize(spdy_version_) - control_frame.size() +
+ 1;
// Create a frame at exatly that size.
string big_value(kBigValueSize, 'x');
@@ -4100,7 +4153,7 @@ TEST_P(SpdyFramerTest, ControlFrameTooLarge) {
"Serializing frame over-capacity.");
}
EXPECT_EQ(TestSpdyVisitor::received_control_frame_max_size() +
- SpdyConstants::GetControlFrameHeaderSize(spdy_version_) + 1,
+ SpdyConstants::GetFrameHeaderSize(spdy_version_) + 1,
control_frame.size());
TestSpdyVisitor visitor(spdy_version_);
@@ -4131,7 +4184,8 @@ TEST_P(SpdyFramerTest, TooLargeHeadersFrameUsesContinuation) {
const size_t kBigValueSize = TestSpdyVisitor::sent_control_frame_max_size();
string big_value(kBigValueSize, 'x');
headers.SetHeader("aa", big_value);
- SpdySerializedFrame control_frame(framer.SerializeHeaders(headers));
+ SpdySerializedFrame control_frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers));
EXPECT_GT(control_frame.size(),
TestSpdyVisitor::sent_control_frame_max_size());
@@ -4146,6 +4200,72 @@ TEST_P(SpdyFramerTest, TooLargeHeadersFrameUsesContinuation) {
EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
}
+TEST_P(SpdyFramerTest, MultipleContinuationFramesWithIterator) {
+ if (!IsHttp2()) {
+ return;
+ }
+
+ SpdyFramer framer(spdy_version_);
+ framer.set_enable_compression(false);
+ auto headers = base::MakeUnique<SpdyHeadersIR>(1);
+ headers->set_padding_len(256);
+
+ // Exact payload length will change with HPACK, but this should be long
+ // enough to cause an overflow.
+ const size_t kBigValueSize = TestSpdyVisitor::sent_control_frame_max_size();
+ string big_valuex(kBigValueSize, 'x');
+ headers->SetHeader("aa", big_valuex);
+ string big_valuez(kBigValueSize, 'z');
+ headers->SetHeader("bb", big_valuez);
+
+ SpdyFramer::SpdyHeaderFrameIterator frame_it(&framer, std::move(headers));
+
+ EXPECT_TRUE(frame_it.HasNextFrame());
+ SpdySerializedFrame headers_frame(frame_it.NextFrame());
+ EXPECT_EQ(headers_frame.size(),
+ TestSpdyVisitor::sent_control_frame_max_size());
+
+ TestSpdyVisitor visitor(spdy_version_);
+ visitor.SimulateInFramer(
+ reinterpret_cast<unsigned char*>(headers_frame.data()),
+ headers_frame.size());
+ EXPECT_TRUE(visitor.header_buffer_valid_);
+ EXPECT_EQ(0, visitor.error_count_);
+ EXPECT_EQ(1, visitor.headers_frame_count_);
+ EXPECT_EQ(0, visitor.continuation_count_);
+ EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
+
+ EXPECT_TRUE(frame_it.HasNextFrame());
+ SpdySerializedFrame first_cont_frame(frame_it.NextFrame());
+ EXPECT_EQ(first_cont_frame.size(),
+ TestSpdyVisitor::sent_control_frame_max_size());
+
+ visitor.SimulateInFramer(
+ reinterpret_cast<unsigned char*>(first_cont_frame.data()),
+ first_cont_frame.size());
+ EXPECT_TRUE(visitor.header_buffer_valid_);
+ EXPECT_EQ(0, visitor.error_count_);
+ EXPECT_EQ(1, visitor.headers_frame_count_);
+ EXPECT_EQ(1, visitor.continuation_count_);
+ EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
+
+ EXPECT_TRUE(frame_it.HasNextFrame());
+ SpdySerializedFrame second_cont_frame(frame_it.NextFrame());
+ EXPECT_LT(second_cont_frame.size(),
+ TestSpdyVisitor::sent_control_frame_max_size());
+
+ visitor.SimulateInFramer(
+ reinterpret_cast<unsigned char*>(second_cont_frame.data()),
+ second_cont_frame.size());
+ EXPECT_TRUE(visitor.header_buffer_valid_);
+ EXPECT_EQ(0, visitor.error_count_);
+ EXPECT_EQ(1, visitor.headers_frame_count_);
+ EXPECT_EQ(2, visitor.continuation_count_);
+ EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
+
+ EXPECT_FALSE(frame_it.HasNextFrame());
+}
+
TEST_P(SpdyFramerTest, TooLargePushPromiseFrameUsesContinuation) {
if (!IsHttp2()) {
return;
@@ -4189,7 +4309,8 @@ TEST_P(SpdyFramerTest, ControlFrameMuchTooLarge) {
SpdyHeadersIR headers(1);
headers.set_fin(true);
headers.SetHeader("aa", big_value);
- SpdySerializedFrame control_frame(framer.SerializeHeaders(headers));
+ SpdySerializedFrame control_frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers));
TestSpdyVisitor visitor(spdy_version_);
visitor.set_header_buffer_size(kHeaderBufferSize);
visitor.use_compression_ = true;
@@ -4243,9 +4364,9 @@ TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) {
// HTTP/2 GOAWAY frames are only bound by a minimal length, since they may
// carry opaque data. Verify that minimal length is tested.
- ASSERT_GT(framer.GetGoAwayMinimumSize(), framer.GetControlFrameHeaderSize());
+ ASSERT_GT(framer.GetGoAwayMinimumSize(), framer.GetFrameHeaderSize());
const size_t less_than_min_length =
- framer.GetGoAwayMinimumSize() - framer.GetControlFrameHeaderSize() - 1;
+ framer.GetGoAwayMinimumSize() - framer.GetFrameHeaderSize() - 1;
ASSERT_LE(less_than_min_length, std::numeric_limits<unsigned char>::max());
const unsigned char kH2Len = static_cast<unsigned char>(less_than_min_length);
const unsigned char kH2FrameData[] = {
@@ -4257,7 +4378,7 @@ TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) {
0x00, 0x00, 0x00, // Truncated Status Field
};
const size_t pad_length =
- length + framer.GetControlFrameHeaderSize() -
+ length + framer.GetFrameHeaderSize() -
(IsSpdy3() ? sizeof(kV3FrameData) : sizeof(kH2FrameData));
string pad(pad_length, 'A');
TestSpdyVisitor visitor(spdy_version_);
@@ -4286,7 +4407,7 @@ TEST_P(SpdyFramerTest, ReadZeroLenSettingsFrame) {
visitor.use_compression_ = false;
visitor.SimulateInFramer(
reinterpret_cast<unsigned char*>(control_frame.data()),
- framer.GetControlFrameHeaderSize());
+ framer.GetFrameHeaderSize());
if (IsSpdy3()) {
// Should generate an error, since zero-len settings frames are unsupported.
EXPECT_EQ(1, visitor.error_count_);
@@ -4312,7 +4433,7 @@ TEST_P(SpdyFramerTest, ReadBogusLenSettingsFrame) {
visitor.use_compression_ = false;
visitor.SimulateInFramer(
reinterpret_cast<unsigned char*>(control_frame.data()),
- framer.GetControlFrameHeaderSize() + kNewLength);
+ framer.GetFrameHeaderSize() + kNewLength);
// Should generate an error, since its not possible to have a
// settings frame of length kNewLength.
EXPECT_EQ(1, visitor.error_count_);
@@ -5042,7 +5163,7 @@ TEST_P(SpdyFramerTest, SizesTest) {
SpdyFramer framer(spdy_version_);
if (IsSpdy3()) {
EXPECT_EQ(8u, framer.GetDataFrameMinimumSize());
- EXPECT_EQ(8u, framer.GetControlFrameHeaderSize());
+ EXPECT_EQ(8u, framer.GetFrameHeaderSize());
EXPECT_EQ(18u, framer.GetSynStreamMinimumSize());
EXPECT_EQ(12u, framer.GetSynReplyMinimumSize());
EXPECT_EQ(16u, framer.GetRstStreamMinimumSize());
@@ -5056,7 +5177,7 @@ TEST_P(SpdyFramerTest, SizesTest) {
EXPECT_EQ(16777215u, framer.GetDataFrameMaximumPayload());
} else {
EXPECT_EQ(9u, framer.GetDataFrameMinimumSize());
- EXPECT_EQ(9u, framer.GetControlFrameHeaderSize());
+ EXPECT_EQ(9u, framer.GetFrameHeaderSize());
EXPECT_EQ(14u, framer.GetSynStreamMinimumSize());
EXPECT_EQ(9u, framer.GetSynReplyMinimumSize());
EXPECT_EQ(13u, framer.GetRstStreamMinimumSize());
@@ -5554,7 +5675,8 @@ TEST_P(SpdyFramerTest, HeadersFrameFlags) {
headers_ir.set_exclusive(true);
}
headers_ir.SetHeader("foo", "bar");
- SpdySerializedFrame frame(framer.SerializeHeaders(headers_ir));
+ SpdySerializedFrame frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers_ir));
uint8_t set_flags = flags;
if (IsHttp2()) {
// TODO(jgraettinger): Add padding to SpdyHeadersIR,
@@ -5716,11 +5838,11 @@ TEST_P(SpdyFramerTest, ContinuationFrameFlags) {
SpdyHeadersIR headers_ir(42);
headers_ir.SetHeader("foo", "bar");
- SpdySerializedFrame frame0(framer.SerializeHeaders(headers_ir));
+ SpdySerializedFrame frame0(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers_ir));
SetFrameFlags(&frame0, 0, spdy_version_);
SpdyContinuationIR continuation(42);
- continuation.SetHeader("foo", "bar");
SpdySerializedFrame frame(framer.SerializeContinuation(continuation));
SetFrameFlags(&frame, flags, spdy_version_);
@@ -5760,8 +5882,8 @@ TEST_P(SpdyFramerTest, EmptySynStream) {
syn_stream.set_priority(1);
SpdySerializedFrame frame(framer.SerializeSynStream(syn_stream));
// Adjust size to remove the header block.
- SetFrameLength(&frame, framer.GetSynStreamMinimumSize() -
- framer.GetControlFrameHeaderSize(),
+ SetFrameLength(&frame,
+ framer.GetSynStreamMinimumSize() - framer.GetFrameHeaderSize(),
spdy_version_);
EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(1, SYN_STREAM, _));
@@ -6238,7 +6360,8 @@ TEST_P(SpdyFramerTest, ProcessAllInput) {
headers.SetHeader("alpha", "beta");
headers.SetHeader("gamma", "charlie");
headers.SetHeader("cookie", "key1=value1; key2=value2");
- SpdySerializedFrame headers_frame(framer.SerializeHeaders(headers));
+ SpdySerializedFrame headers_frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers));
const char four_score[] = "Four score and seven years ago";
SpdyDataIR four_score_ir(1, four_score);
@@ -6290,7 +6413,8 @@ TEST_P(SpdyFramerTest, ProcessAtMostOneFrame) {
headers.SetHeader("alpha", "beta");
headers.SetHeader("gamma", "charlie");
headers.SetHeader("cookie", "key1=value1; key2=value2");
- SpdySerializedFrame headers_frame(framer.SerializeHeaders(headers));
+ SpdySerializedFrame headers_frame(
+ SpdyFramerPeer::SerializeHeaders(&framer, headers));
// Put them in a single buffer (new variables here to make it easy to
// change the order and type of frames).
diff --git a/chromium/net/spdy/spdy_header_block.cc b/chromium/net/spdy/spdy_header_block.cc
index 09640c83ed6..20ddee48f2f 100644
--- a/chromium/net/spdy/spdy_header_block.cc
+++ b/chromium/net/spdy/spdy_header_block.cc
@@ -4,16 +4,17 @@
#include "net/spdy/spdy_header_block.h"
+#include <string.h>
+
#include <algorithm>
-#include <ios>
#include <utility>
-#include <vector>
#include "base/logging.h"
#include "base/macros.h"
#include "base/values.h"
#include "net/base/arena.h"
#include "net/http/http_log_util.h"
+#include "net/log/net_log_capture_mode.h"
using base::StringPiece;
using std::dec;
@@ -28,6 +29,8 @@ namespace {
// SpdyHeaderBlock::Storage allocates blocks of this size by default.
const size_t kDefaultStorageBlockSize = 2048;
+const char kCookieKey[] = "cookie";
+
} // namespace
// This class provides a backing store for StringPieces. It previously used
@@ -47,6 +50,24 @@ class SpdyHeaderBlock::Storage {
return StringPiece(arena_.Memdup(s.data(), s.size()), s.size());
}
+ // Given value, a string already in the arena, perform a realloc and append
+ // separator and more to the end of the value's new location. If value is the
+ // most recently added string (via Write), then UnsafeArena will not copy the
+ // existing value but instead will increase the space reserved for value.
+ StringPiece Realloc(StringPiece value,
+ StringPiece separator,
+ StringPiece more) {
+ size_t total_length = value.size() + separator.size() + more.size();
+ char* ptr = const_cast<char*>(value.data());
+ ptr = arena_.Realloc(ptr, value.size(), total_length);
+ StringPiece result(ptr, total_length);
+ ptr += value.size();
+ memcpy(ptr, separator.data(), separator.size());
+ ptr += separator.size();
+ memcpy(ptr, more.data(), more.size());
+ return result;
+ }
+
// If |s| points to the most recent allocation from arena_, the arena will
// reclaim the memory. Otherwise, this method is a no-op.
void Rewind(const StringPiece s) {
@@ -118,21 +139,18 @@ SpdyHeaderBlock::StringPieceProxy::operator StringPiece() const {
: lookup_result_->second;
}
-SpdyHeaderBlock::SpdyHeaderBlock() : storage_(new Storage) {}
+SpdyHeaderBlock::SpdyHeaderBlock() {}
-SpdyHeaderBlock::SpdyHeaderBlock(SpdyHeaderBlock&& other)
- : storage_(std::move(other.storage_)) {
- // |block_| is linked_hash_map, which does not have move constructor.
+SpdyHeaderBlock::SpdyHeaderBlock(SpdyHeaderBlock&& other) {
block_.swap(other.block_);
+ storage_.swap(other.storage_);
}
SpdyHeaderBlock::~SpdyHeaderBlock() {}
SpdyHeaderBlock& SpdyHeaderBlock::operator=(SpdyHeaderBlock&& other) {
- storage_ = std::move(other.storage_);
- // |block_| is linked_hash_map, which does not have move assignment
- // operator.
block_.swap(other.block_);
+ storage_.swap(other.storage_);
return *this;
}
@@ -167,7 +185,7 @@ string SpdyHeaderBlock::DebugString() const {
void SpdyHeaderBlock::clear() {
block_.clear();
- storage_->Clear();
+ storage_.reset();
}
void SpdyHeaderBlock::insert(
@@ -183,14 +201,14 @@ SpdyHeaderBlock::StringPieceProxy SpdyHeaderBlock::operator[](
if (iter == block_.end()) {
// We write the key first, to assure that the StringPieceProxy has a
// reference to a valid StringPiece in its operator=.
- out_key = storage_->Write(key);
- DVLOG(2) << "Key written as: " << hex
- << static_cast<const void*>(key.data()) << ", " << dec
+ out_key = GetStorage()->Write(key);
+ DVLOG(2) << "Key written as: " << std::hex
+ << static_cast<const void*>(key.data()) << ", " << std::dec
<< key.size();
} else {
out_key = iter->first;
}
- return StringPieceProxy(&block_, storage_.get(), iter, out_key);
+ return StringPieceProxy(&block_, GetStorage(), iter, out_key);
}
StringPiece SpdyHeaderBlock::GetHeader(const StringPiece key) const {
@@ -207,13 +225,36 @@ void SpdyHeaderBlock::ReplaceOrAppendHeader(const StringPiece key,
AppendHeader(key, value);
} else {
DVLOG(1) << "Updating key: " << iter->first << " with value: " << value;
- iter->second = storage_->Write(value);
+ iter->second = GetStorage()->Write(value);
}
}
+void SpdyHeaderBlock::AppendValueOrAddHeader(const StringPiece key,
+ const StringPiece value) {
+ 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;
+ StringPiece separator("", 1);
+ if (key == kCookieKey) {
+ separator = "; ";
+ }
+ iter->second = GetStorage()->Realloc(iter->second, separator, value);
+}
+
void SpdyHeaderBlock::AppendHeader(const StringPiece key,
const StringPiece value) {
- block_.insert(make_pair(storage_->Write(key), storage_->Write(value)));
+ block_.emplace(GetStorage()->Write(key), GetStorage()->Write(value));
+}
+
+SpdyHeaderBlock::Storage* SpdyHeaderBlock::GetStorage() {
+ if (!storage_) {
+ storage_.reset(new Storage);
+ }
+ return storage_.get();
}
std::unique_ptr<base::Value> SpdyHeaderBlockNetLogCallback(
diff --git a/chromium/net/spdy/spdy_header_block.h b/chromium/net/spdy/spdy_header_block.h
index 0afde3159f5..b0d57341cff 100644
--- a/chromium/net/spdy/spdy_header_block.h
+++ b/chromium/net/spdy/spdy_header_block.h
@@ -7,6 +7,7 @@
#include <stddef.h>
+#include <list>
#include <map>
#include <memory>
#include <string>
@@ -17,11 +18,17 @@
#include "net/base/net_export.h"
#include "net/log/net_log.h"
+namespace base {
+class Value;
+}
+
namespace net {
// Allows arg-dependent lookup to work for logging's operator<<.
using ::operator<<;
+class NetLogCaptureMode;
+
namespace test {
class StringPieceProxyPeer;
}
@@ -83,11 +90,24 @@ class NET_EXPORT SpdyHeaderBlock {
// Clears both our MapType member and the memory used to hold headers.
void clear();
- // These methods copy data into our backing storage.
+ // The next few methods copy data into our backing storage.
+
+ // If key already exists in the block, replaces the value of that key. Else
+ // adds a new header to the end of the block.
void insert(const MapType::value_type& value);
+
+ // If key already exists in the block, replaces the value of that key. Else
+ // adds a new header to the end of the block.
void ReplaceOrAppendHeader(const base::StringPiece key,
const base::StringPiece value);
+ // If a header with the key is already present, then append the value to the
+ // existing header value, NUL ("\0") separated unless the key is cookie, in
+ // which case the separator is "; ".
+ // If there is no such key, a new header with the key and value is added.
+ void AppendValueOrAddHeader(const base::StringPiece key,
+ const base::StringPiece value);
+
// Allows either lookup or mutation of the value associated with a key.
StringPieceProxy operator[](const base::StringPiece key);
@@ -141,7 +161,10 @@ class NET_EXPORT SpdyHeaderBlock {
private:
void Write(const base::StringPiece s);
void AppendHeader(const base::StringPiece key, const base::StringPiece value);
+ Storage* GetStorage();
+ // StringPieces 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_;
};
diff --git a/chromium/net/spdy/spdy_header_block_test.cc b/chromium/net/spdy/spdy_header_block_test.cc
index b4273af5c77..e57f00b119d 100644
--- a/chromium/net/spdy/spdy_header_block_test.cc
+++ b/chromium/net/spdy/spdy_header_block_test.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/values.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
#include "net/spdy/spdy_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -76,24 +76,24 @@ TEST(SpdyHeaderBlockTest, KeyMemoryReclaimedOnLookup) {
// This test verifies that headers can be set in a variety of ways.
TEST(SpdyHeaderBlockTest, AddHeaders) {
- SpdyHeaderBlock block1;
- block1["foo"] = string(300, 'x');
- block1["bar"] = "baz";
- block1.ReplaceOrAppendHeader("qux", "qux1");
- block1["qux"] = "qux2";
- block1.insert(make_pair("key", "value"));
-
- EXPECT_EQ(Pair("foo", string(300, 'x')), *block1.find("foo"));
- EXPECT_EQ("baz", block1["bar"]);
- EXPECT_EQ("baz", block1.GetHeader("bar"));
+ SpdyHeaderBlock block;
+ block["foo"] = string(300, 'x');
+ block["bar"] = "baz";
+ block.ReplaceOrAppendHeader("qux", "qux1");
+ block["qux"] = "qux2";
+ block.insert(std::make_pair("key", "value"));
+
+ EXPECT_EQ(Pair("foo", string(300, 'x')), *block.find("foo"));
+ EXPECT_EQ("baz", block["bar"]);
+ EXPECT_EQ("baz", block.GetHeader("bar"));
string qux("qux");
- EXPECT_EQ("qux2", block1[qux]);
- EXPECT_EQ("qux2", block1.GetHeader(qux));
- EXPECT_EQ(Pair("key", "value"), *block1.find("key"));
+ EXPECT_EQ("qux2", block[qux]);
+ EXPECT_EQ("qux2", block.GetHeader(qux));
+ EXPECT_EQ(Pair("key", "value"), *block.find("key"));
- block1.erase("key");
- EXPECT_EQ(block1.end(), block1.find("key"));
- EXPECT_EQ("", block1.GetHeader("key"));
+ block.erase("key");
+ EXPECT_EQ(block.end(), block.find("key"));
+ EXPECT_EQ("", block.GetHeader("key"));
}
// This test verifies that SpdyHeaderBlock can be copied using Clone().
@@ -141,5 +141,66 @@ TEST(SpdyHeaderBlockTest, Equality) {
EXPECT_NE(block1, block2);
}
+// Test that certain methods do not crash on moved-from instances.
+TEST(SpdyHeaderBlockTest, MovedFromIsValid) {
+ SpdyHeaderBlock block1;
+ block1["foo"] = "bar";
+
+ SpdyHeaderBlock block2(std::move(block1));
+ EXPECT_THAT(block2, ElementsAre(Pair("foo", "bar")));
+
+ block1.ReplaceOrAppendHeader("baz", "qux");
+
+ SpdyHeaderBlock block3(std::move(block1));
+
+ block1["foo"] = "bar";
+
+ SpdyHeaderBlock block4(std::move(block1));
+
+ block1.clear();
+ EXPECT_TRUE(block1.empty());
+
+ block1["foo"] = "bar";
+ EXPECT_THAT(block1, ElementsAre(Pair("foo", "bar")));
+}
+
+// This test verifies that headers can be appended to no matter how they were
+// added originally.
+TEST(SpdyHeaderBlockTest, AppendHeaders) {
+ SpdyHeaderBlock block;
+ block["foo"] = "foo";
+ block.AppendValueOrAddHeader("foo", "bar");
+ EXPECT_EQ(Pair("foo", string("foo\0bar", 7)), *block.find("foo"));
+
+ block.insert(std::make_pair("foo", "baz"));
+ EXPECT_EQ("baz", block["foo"]);
+ EXPECT_EQ(Pair("foo", "baz"), *block.find("foo"));
+
+ // Try all four methods of adding an entry.
+ block["cookie"] = "key1=value1";
+ block.AppendValueOrAddHeader("h1", "h1v1");
+ block.insert(std::make_pair("h2", "h2v1"));
+ block.ReplaceOrAppendHeader("h3", "h3v1");
+
+ block.AppendValueOrAddHeader("h3", "h3v2");
+ block.AppendValueOrAddHeader("h2", "h2v2");
+ block.AppendValueOrAddHeader("h1", "h1v2");
+ block.AppendValueOrAddHeader("cookie", "key2=value2");
+
+ block.ReplaceOrAppendHeader("h4", "h4v1");
+
+ block.AppendValueOrAddHeader("cookie", "key3=value3");
+ block.AppendValueOrAddHeader("h1", "h1v3");
+ block.AppendValueOrAddHeader("h2", "h2v3");
+ block.AppendValueOrAddHeader("h3", "h3v3");
+
+ EXPECT_EQ("key1=value1; key2=value2; key3=value3", block["cookie"]);
+ EXPECT_EQ("baz", block["foo"]);
+ EXPECT_EQ(string("h1v1\0h1v2\0h1v3", 14), block["h1"]);
+ EXPECT_EQ(string("h2v1\0h2v2\0h2v3", 14), block["h2"]);
+ EXPECT_EQ(string("h3v1\0h3v2\0h3v3", 14), block["h3"]);
+ EXPECT_EQ("h4v1", block["h4"]);
+}
+
} // namespace test
} // namespace net
diff --git a/chromium/net/spdy/spdy_headers_block_parser.cc b/chromium/net/spdy/spdy_headers_block_parser.cc
index d5f03413a18..6eb16fbe438 100644
--- a/chromium/net/spdy/spdy_headers_block_parser.cc
+++ b/chromium/net/spdy/spdy_headers_block_parser.cc
@@ -6,6 +6,7 @@
#include "base/sys_byteorder.h"
#include "net/spdy/spdy_bug_tracker.h"
+#include "net/spdy/spdy_flags.h"
namespace net {
namespace {
@@ -113,7 +114,16 @@ bool SpdyHeadersBlockParser::HandleControlFrameHeadersData(
next_state = READING_KEY_LEN;
} else {
next_state = READING_HEADER_BLOCK_LEN;
- handler_->OnHeaderBlockEnd(total_bytes_received_);
+ if (FLAGS_chromium_http2_flag_log_compressed_size) {
+ // We reach here in two cases: 1) Spdy3 or 2) HTTP/2 without hpack
+ // encoding. For the first case, we just log the uncompressed size
+ // since we are going to deprecate Spdy3 soon. For the second case,
+ // the compressed size is the same as the uncompressed size.
+ handler_->OnHeaderBlockEnd(total_bytes_received_,
+ total_bytes_received_);
+ } else {
+ handler_->OnHeaderBlockEnd(total_bytes_received_);
+ }
stream_id_ = kInvalidStreamId;
// Expect to have consumed all buffer.
if (reader.Available() != 0) {
diff --git a/chromium/net/spdy/spdy_headers_block_parser_test.cc b/chromium/net/spdy/spdy_headers_block_parser_test.cc
index 2f80fdc3f81..ad603539033 100644
--- a/chromium/net/spdy/spdy_headers_block_parser_test.cc
+++ b/chromium/net/spdy/spdy_headers_block_parser_test.cc
@@ -9,11 +9,14 @@
#include "base/strings/string_number_conversions.h"
#include "base/sys_byteorder.h"
+#include "net/spdy/spdy_flags.h"
#include "net/spdy/spdy_test_utils.h"
#include "net/test/gtest_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using testing::_;
+
namespace net {
using base::IntToString;
@@ -27,6 +30,7 @@ class MockSpdyHeadersHandler : public SpdyHeadersHandlerInterface {
public:
MOCK_METHOD0(OnHeaderBlockStart, void());
MOCK_METHOD1(OnHeaderBlockEnd, void(size_t bytes));
+ MOCK_METHOD2(OnHeaderBlockEnd, void(size_t bytes, size_t compressed_bytes));
MOCK_METHOD2(OnHeader, void(StringPiece key, StringPiece value));
};
@@ -118,8 +122,11 @@ TEST_P(SpdyHeadersBlockParserTest, BasicTest) {
StringPiece(expect_value))).Times(1);
string headers(CreateHeaders(1, false));
- EXPECT_CALL(handler_, OnHeaderBlockEnd(headers.length())).Times(1);
-
+ if (FLAGS_chromium_http2_flag_log_compressed_size) {
+ EXPECT_CALL(handler_, OnHeaderBlockEnd(headers.length(), _)).Times(1);
+ } else {
+ EXPECT_CALL(handler_, OnHeaderBlockEnd(headers.length())).Times(1);
+ }
EXPECT_TRUE(parser_->
HandleControlFrameHeadersData(1, headers.c_str(), headers.length()));
EXPECT_EQ(SpdyHeadersBlockParser::NO_PARSER_ERROR, parser_->get_error());
@@ -136,7 +143,11 @@ TEST_P(SpdyHeadersBlockParserTest, NullsSupportedTest) {
StringPiece(expect_value))).Times(1);
string headers(CreateHeaders(1, true));
- EXPECT_CALL(handler_, OnHeaderBlockEnd(headers.length())).Times(1);
+ if (FLAGS_chromium_http2_flag_log_compressed_size) {
+ EXPECT_CALL(handler_, OnHeaderBlockEnd(headers.length(), _)).Times(1);
+ } else {
+ EXPECT_CALL(handler_, OnHeaderBlockEnd(headers.length())).Times(1);
+ }
EXPECT_TRUE(parser_->
HandleControlFrameHeadersData(1, headers.c_str(), headers.length()));
@@ -163,7 +174,11 @@ TEST_P(SpdyHeadersBlockParserTest, MultipleBlocksAndHeadersWithPartialData) {
StringPiece(retained_arguments[2 * j]),
StringPiece(retained_arguments[2 * j + 1]))).Times(1);
}
- EXPECT_CALL(handler_, OnHeaderBlockEnd(headers.length())).Times(1);
+ if (FLAGS_chromium_http2_flag_log_compressed_size) {
+ EXPECT_CALL(handler_, OnHeaderBlockEnd(headers.length(), _)).Times(1);
+ } else {
+ EXPECT_CALL(handler_, OnHeaderBlockEnd(headers.length())).Times(1);
+ }
}
// Parse the header blocks, feeding the parser one byte at a time.
for (int i = 1; i <= kNumHeaderBlocks; i++) {
@@ -190,7 +205,11 @@ TEST_P(SpdyHeadersBlockParserTest, HandlesEmptyCallsTest) {
StringPiece(expect_value))).Times(1);
string headers(CreateHeaders(1, false));
- EXPECT_CALL(handler_, OnHeaderBlockEnd(headers.length())).Times(1);
+ if (FLAGS_chromium_http2_flag_log_compressed_size) {
+ EXPECT_CALL(handler_, OnHeaderBlockEnd(headers.length(), _)).Times(1);
+ } else {
+ EXPECT_CALL(handler_, OnHeaderBlockEnd(headers.length())).Times(1);
+ }
// Send a header in pieces with intermediate empty calls.
for (string::iterator it = headers.begin(); it != headers.end(); ++it) {
@@ -236,7 +255,11 @@ TEST_P(SpdyHeadersBlockParserTest, ExtraDataTest) {
StringPiece(expect_value))).Times(1);
string headers = CreateHeaders(1, false) + "foobar";
- EXPECT_CALL(handler_, OnHeaderBlockEnd(headers.length())).Times(1);
+ if (FLAGS_chromium_http2_flag_log_compressed_size) {
+ EXPECT_CALL(handler_, OnHeaderBlockEnd(headers.length(), _)).Times(1);
+ } else {
+ EXPECT_CALL(handler_, OnHeaderBlockEnd(headers.length())).Times(1);
+ }
EXPECT_FALSE(parser_->HandleControlFrameHeadersData(1, headers.c_str(),
headers.length()));
diff --git a/chromium/net/spdy/spdy_headers_handler_interface.h b/chromium/net/spdy/spdy_headers_handler_interface.h
index 99944c67afb..e4652ddef8b 100644
--- a/chromium/net/spdy/spdy_headers_handler_interface.h
+++ b/chromium/net/spdy/spdy_headers_handler_interface.h
@@ -27,10 +27,18 @@ class NET_EXPORT_PRIVATE SpdyHeadersHandlerInterface {
// values for a given key will be emitted as multiple calls to OnHeader.
virtual void OnHeader(base::StringPiece key, base::StringPiece value) = 0;
+ // TODO(yasong): deprecate this method with
+ // --gfe2_reloadable_flag_log_compressed_size.
// A callback method which notifies when the parser finishes handling a
- // header block (i.e. the containing frame has the END_STREAM flag set).
+ // header block (i.e. the containing frame has the END_HEADERS flag set).
// Also indicates the total number of bytes in this block.
virtual void OnHeaderBlockEnd(size_t uncompressed_header_bytes) = 0;
+
+ // A callback method which notifies when the parser finishes handling a
+ // header block (i.e. the containing frame has the END_HEADERS flag set).
+ // Also indicates the total number of bytes in this block.
+ virtual void OnHeaderBlockEnd(size_t uncompressed_header_bytes,
+ size_t compressed_header_bytes) = 0;
};
} // namespace net
diff --git a/chromium/net/spdy/spdy_http_stream.cc b/chromium/net/spdy/spdy_http_stream.cc
index abeffb6dc3d..5f0da2f16fd 100644
--- a/chromium/net/spdy/spdy_http_stream.cc
+++ b/chromium/net/spdy/spdy_http_stream.cc
@@ -21,7 +21,8 @@
#include "net/http/http_request_headers.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_info.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/spdy/spdy_header_block.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/spdy/spdy_protocol.h"
@@ -48,8 +49,8 @@ SpdyHttpStream::SpdyHttpStream(const base::WeakPtr<SpdySession>& spdy_session,
buffered_read_callback_pending_(false),
more_read_data_pending_(false),
direct_(direct),
- was_npn_negotiated_(false),
- protocol_negotiated_(kProtoUnknown),
+ was_alpn_negotiated_(false),
+ negotiated_protocol_(kProtoUnknown),
weak_factory_(this) {
DCHECK(spdy_session_.get());
}
@@ -63,7 +64,7 @@ SpdyHttpStream::~SpdyHttpStream() {
int SpdyHttpStream::InitializeStream(const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& stream_net_log,
+ const NetLogWithSource& stream_net_log,
const CompletionCallback& callback) {
DCHECK(!stream_);
if (!spdy_session_)
@@ -79,9 +80,7 @@ int SpdyHttpStream::InitializeStream(const HttpRequestInfo* request_info,
// |stream_| may be NULL even if OK was returned.
if (stream_.get()) {
DCHECK_EQ(stream_->type(), SPDY_PUSH_STREAM);
- stream_->SetDelegate(this);
- stream_->GetSSLInfo(&ssl_info_, &was_npn_negotiated_,
- &protocol_negotiated_);
+ InitializeStreamHelper();
return OK;
}
}
@@ -94,22 +93,12 @@ int SpdyHttpStream::InitializeStream(const HttpRequestInfo* request_info,
if (rv == OK) {
stream_ = stream_request_.ReleaseStream();
- stream_->SetDelegate(this);
- stream_->GetSSLInfo(&ssl_info_, &was_npn_negotiated_,
- &protocol_negotiated_);
+ InitializeStreamHelper();
}
return rv;
}
-UploadProgress SpdyHttpStream::GetUploadProgress() const {
- if (!request_info_ || !HasUploadData())
- return UploadProgress();
-
- return UploadProgress(request_info_->upload_data_stream->position(),
- request_info_->upload_data_stream->size());
-}
-
int SpdyHttpStream::ReadResponseHeaders(const CompletionCallback& callback) {
CHECK(!callback.is_null());
if (stream_closed_)
@@ -280,13 +269,12 @@ int SpdyHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
return ERR_IO_PENDING;
}
- std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
- CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers,
- stream_->GetProtocolVersion(), direct_,
- headers.get());
+ SpdyHeaderBlock headers;
+ CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers, direct_,
+ &headers);
stream_->net_log().AddEvent(
- NetLog::TYPE_HTTP_TRANSACTION_HTTP2_SEND_REQUEST_HEADERS,
- base::Bind(&SpdyHeaderBlockNetLogCallback, headers.get()));
+ NetLogEventType::HTTP_TRANSACTION_HTTP2_SEND_REQUEST_HEADERS,
+ base::Bind(&SpdyHeaderBlockNetLogCallback, &headers));
result = stream_->SendRequestHeaders(
std::move(headers),
HasUploadData() ? MORE_DATA_TO_SEND : NO_MORE_DATA_TO_SEND);
@@ -325,8 +313,7 @@ SpdyResponseHeadersStatus SpdyHttpStream::OnResponseHeadersUpdated(
response_info_ = push_response_info_.get();
}
- if (!SpdyHeadersToHttpResponse(
- response_headers, stream_->GetProtocolVersion(), response_info_)) {
+ if (!SpdyHeadersToHttpResponse(response_headers, response_info_)) {
// We do not have complete headers yet.
return RESPONSE_HEADERS_ARE_INCOMPLETE;
}
@@ -335,12 +322,12 @@ SpdyResponseHeadersStatus SpdyHttpStream::OnResponseHeadersUpdated(
response_headers_status_ = RESPONSE_HEADERS_ARE_COMPLETE;
// Don't store the SSLInfo in the response here, HttpNetworkTransaction
// will take care of that part.
- response_info_->was_npn_negotiated = was_npn_negotiated_;
- response_info_->npn_negotiated_protocol =
- SSLClientSocket::NextProtoToString(protocol_negotiated_);
+ response_info_->was_alpn_negotiated = was_alpn_negotiated_;
+ response_info_->alpn_negotiated_protocol =
+ SSLClientSocket::NextProtoToString(negotiated_protocol_);
response_info_->request_time = stream_->GetRequestTime();
response_info_->connection_info =
- HttpResponseInfo::ConnectionInfoFromNextProto(stream_->GetProtocol());
+ HttpResponseInfo::ConnectionInfoFromNextProto(kProtoHTTP2);
response_info_->vary_data
.Init(*request_info_, *response_info_->headers.get());
@@ -428,9 +415,7 @@ void SpdyHttpStream::OnStreamCreated(
int rv) {
if (rv == OK) {
stream_ = stream_request_.ReleaseStream();
- stream_->SetDelegate(this);
- stream_->GetSSLInfo(&ssl_info_, &was_npn_negotiated_,
- &protocol_negotiated_);
+ InitializeStreamHelper();
}
callback.Run(rv);
}
@@ -454,6 +439,13 @@ void SpdyHttpStream::ReadAndSendRequestBodyData() {
OnRequestBodyReadCompleted(rv);
}
+void SpdyHttpStream::InitializeStreamHelper() {
+ stream_->SetDelegate(this);
+ stream_->GetSSLInfo(&ssl_info_);
+ was_alpn_negotiated_ = stream_->WasNpnNegotiated();
+ negotiated_protocol_ = stream_->GetNegotiatedProtocol();
+}
+
void SpdyHttpStream::ResetStreamInternal() {
spdy_session_->ResetStream(stream()->stream_id(), RST_STREAM_INTERNAL_ERROR,
std::string());
@@ -560,13 +552,13 @@ void SpdyHttpStream::DoRequestCallback(int rv) {
void SpdyHttpStream::MaybeDoRequestCallback(int rv) {
CHECK_NE(ERR_IO_PENDING, rv);
- if (!request_callback_.is_null())
+ if (request_callback_)
base::ResetAndReturn(&request_callback_).Run(rv);
}
void SpdyHttpStream::MaybePostRequestCallback(int rv) {
CHECK_NE(ERR_IO_PENDING, rv);
- if (!request_callback_.is_null())
+ if (request_callback_)
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&SpdyHttpStream::MaybeDoRequestCallback,
weak_factory_.GetWeakPtr(), rv));
@@ -599,9 +591,10 @@ bool SpdyHttpStream::GetRemoteEndpoint(IPEndPoint* endpoint) {
return spdy_session_->GetPeerAddress(endpoint) == OK;
}
-Error SpdyHttpStream::GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) {
- return spdy_session_->GetSignedEKMForTokenBinding(key, out);
+Error SpdyHttpStream::GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) {
+ return spdy_session_->GetTokenBindingSignature(key, tb_type, out);
}
void SpdyHttpStream::Drain(HttpNetworkSession* session) {
diff --git a/chromium/net/spdy/spdy_http_stream.h b/chromium/net/spdy/spdy_http_stream.h
index fcf3d4e74de..8266c143c0d 100644
--- a/chromium/net/spdy/spdy_http_stream.h
+++ b/chromium/net/spdy/spdy_http_stream.h
@@ -13,8 +13,8 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
#include "net/http/http_stream.h"
-#include "net/log/net_log.h"
#include "net/spdy/spdy_read_queue.h"
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_stream.h"
@@ -46,13 +46,12 @@ class NET_EXPORT_PRIVATE SpdyHttpStream : public SpdyStream::Delegate,
int InitializeStream(const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback) override;
int SendRequest(const HttpRequestHeaders& headers,
HttpResponseInfo* response,
const CompletionCallback& callback) override;
- UploadProgress GetUploadProgress() const override;
int ReadResponseHeaders(const CompletionCallback& callback) override;
int ReadResponseBody(IOBuffer* buf,
int buf_len,
@@ -80,8 +79,9 @@ class NET_EXPORT_PRIVATE SpdyHttpStream : public SpdyStream::Delegate,
void GetSSLInfo(SSLInfo* ssl_info) override;
void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
bool GetRemoteEndpoint(IPEndPoint* endpoint) override;
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) override;
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) override;
void Drain(HttpNetworkSession* session) override;
void PopulateNetErrorDetails(NetErrorDetails* details) override;
void SetPriority(RequestPriority priority) override;
@@ -96,6 +96,10 @@ class NET_EXPORT_PRIVATE SpdyHttpStream : public SpdyStream::Delegate,
void OnClose(int status) override;
private:
+ // Helper function used to initialize private members and to set delegate on
+ // stream when stream is created.
+ void InitializeStreamHelper();
+
// Helper function used for resetting stream from inside the stream.
void ResetStreamInternal();
@@ -155,7 +159,7 @@ class NET_EXPORT_PRIVATE SpdyHttpStream : public SpdyStream::Delegate,
const HttpRequestInfo* request_info_;
// |response_info_| is the HTTP response data object which is filled in
- // when a SYN_REPLY comes in for the stream.
+ // when a response HEADERS comes in for the stream.
// It is not owned by this stream object, or point to |push_response_info_|.
HttpResponseInfo* response_info_;
@@ -189,8 +193,8 @@ class NET_EXPORT_PRIVATE SpdyHttpStream : public SpdyStream::Delegate,
bool direct_;
SSLInfo ssl_info_;
- bool was_npn_negotiated_;
- NextProto protocol_negotiated_;
+ bool was_alpn_negotiated_;
+ NextProto negotiated_protocol_;
base::WeakPtrFactory<SpdyHttpStream> weak_factory_;
diff --git a/chromium/net/spdy/spdy_http_stream_unittest.cc b/chromium/net/spdy/spdy_http_stream_unittest.cc
index 0168084afd7..aca52c6bd58 100644
--- a/chromium/net/spdy/spdy_http_stream_unittest.cc
+++ b/chromium/net/spdy/spdy_http_stream_unittest.cc
@@ -21,32 +21,27 @@
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
-#include "net/socket/next_proto.h"
#include "net/socket/socket_test_util.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_test_util_common.h"
#include "net/ssl/default_channel_id_store.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
-enum TestCase {
- // Test using the SPDY/3.1 protocol.
- kTestCaseSPDY31,
-
- // Test using the HTTP/2 protocol, without specifying a stream
- // dependency based on the RequestPriority.
- kTestCaseHTTP2NoPriorityDependencies,
-
- // Test using the HTTP/2 protocol, specifying a stream
- // dependency based on the RequestPriority.
- kTestCaseHTTP2PriorityDependencies
-};
-
// Tests the load timing of a stream that's connected and is not the first
// request sent on a connection.
void TestLoadTimingReused(const HttpStream& stream) {
@@ -54,7 +49,7 @@ void TestLoadTimingReused(const HttpStream& stream) {
EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info));
EXPECT_TRUE(load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
@@ -67,10 +62,11 @@ void TestLoadTimingNotReused(const HttpStream& stream) {
EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info));
EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
- ExpectConnectTimingHasTimes(load_timing_info.connect_timing,
- CONNECT_TIMING_HAS_DNS_TIMES);
+ ExpectConnectTimingHasTimes(
+ load_timing_info.connect_timing,
+ CONNECT_TIMING_HAS_DNS_TIMES | CONNECT_TIMING_HAS_SSL_TIMES);
ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
}
@@ -85,7 +81,7 @@ class ReadErrorUploadDataStream : public UploadDataStream {
void CompleteRead() { UploadDataStream::OnReadCompleted(ERR_FAILED); }
// UploadDataStream implementation:
- int InitInternal() override { return OK; }
+ int InitInternal(const NetLogWithSource& net_log) override { return OK; }
int ReadInternal(IOBuffer* buf, int buf_len) override {
if (async_ == FailureMode::ASYNC) {
@@ -127,30 +123,19 @@ class CancelStreamCallback : public TestCompletionCallbackBase {
} // namespace
-class SpdyHttpStreamTest : public testing::Test,
- public testing::WithParamInterface<TestCase> {
+class SpdyHttpStreamTest : public testing::Test {
public:
SpdyHttpStreamTest()
- : spdy_util_(GetProtocol(), GetDependenciesFromPriority()),
- session_deps_(GetProtocol()),
- host_port_pair_(HostPortPair::FromURL(GURL(kDefaultUrl))),
- key_(host_port_pair_, ProxyServer::Direct(), PRIVACY_MODE_DISABLED) {
- session_deps_.enable_priority_dependencies = GetDependenciesFromPriority();
+ : host_port_pair_(HostPortPair::FromURL(GURL(kDefaultUrl))),
+ key_(host_port_pair_, ProxyServer::Direct(), PRIVACY_MODE_DISABLED),
+ ssl_(SYNCHRONOUS, OK) {
session_deps_.net_log = &net_log_;
spdy_util_.set_default_url(GURL("http://www.example.org/"));
}
- ~SpdyHttpStreamTest() {}
+ ~SpdyHttpStreamTest() override {}
protected:
- NextProto GetProtocol() const {
- return GetParam() == kTestCaseSPDY31 ? kProtoSPDY31 : kProtoHTTP2;
- }
-
- bool GetDependenciesFromPriority() const {
- return GetParam() == kTestCaseHTTP2PriorityDependencies;
- }
-
void TearDown() override {
crypto::ECSignatureCreator::SetFactoryForTesting(nullptr);
base::RunLoop().RunUntilIdle();
@@ -166,9 +151,14 @@ class SpdyHttpStreamTest : public testing::Test,
sequenced_data_.reset(
new SequencedSocketData(reads, reads_count, writes, writes_count));
session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get());
+
+ ssl_.cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
+ ASSERT_TRUE(ssl_.cert);
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_);
+
http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
session_ =
- CreateInsecureSpdySession(http_session_.get(), key_, BoundNetLog());
+ CreateSecureSpdySession(http_session_.get(), key_, NetLogWithSource());
}
void TestSendCredentials(
@@ -187,42 +177,18 @@ class SpdyHttpStreamTest : public testing::Test,
private:
MockECSignatureCreatorFactory ec_signature_creator_factory_;
+ SSLSocketDataProvider ssl_;
};
-INSTANTIATE_TEST_CASE_P(ProtoPlusDepend,
- SpdyHttpStreamTest,
- testing::Values(kTestCaseSPDY31,
- kTestCaseHTTP2NoPriorityDependencies,
- kTestCaseHTTP2PriorityDependencies));
-
-// SpdyHttpStream::GetUploadProgress() should still work even before the
-// stream is initialized.
-TEST_P(SpdyHttpStreamTest, GetUploadProgressBeforeInitialization) {
- MockRead reads[] = {
- MockRead(ASYNC, 0, 0) // EOF
- };
-
- InitSession(reads, arraysize(reads), nullptr, 0);
-
- SpdyHttpStream stream(session_, false);
- UploadProgress progress = stream.GetUploadProgress();
- EXPECT_EQ(0u, progress.size());
- EXPECT_EQ(0u, progress.position());
-
- // Pump the event loop so |reads| is consumed before the function returns.
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_P(SpdyHttpStreamTest, SendRequest) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyHttpStreamTest, SendRequest) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*req.get(), 0),
+ CreateMockWrite(req, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp, 1), MockRead(SYNCHRONOUS, 0, 2) // EOF
+ CreateMockRead(resp, 1), MockRead(SYNCHRONOUS, 0, 2) // EOF
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
@@ -233,7 +199,7 @@ TEST_P(SpdyHttpStreamTest, SendRequest) {
TestCompletionCallback callback;
HttpResponseInfo response;
HttpRequestHeaders headers;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
std::unique_ptr<SpdyHttpStream> http_stream(
new SpdyHttpStream(session_, true));
// Make sure getting load timing information the stream early does not crash.
@@ -266,35 +232,27 @@ TEST_P(SpdyHttpStreamTest, SendRequest) {
// stream has been closed.
TestLoadTimingNotReused(*http_stream);
- EXPECT_EQ(static_cast<int64_t>(req->size()),
- http_stream->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(resp->size()),
+ EXPECT_EQ(static_cast<int64_t>(req.size()), http_stream->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(resp.size()),
http_stream->GetTotalReceivedBytes());
}
-TEST_P(SpdyHttpStreamTest, LoadTimingTwoRequests) {
- std::unique_ptr<SpdySerializedFrame> req1(
+TEST_F(SpdyHttpStreamTest, LoadTimingTwoRequests) {
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
- CreateMockWrite(*req2, 1),
+ CreateMockWrite(req1, 0), CreateMockWrite(req2, 1),
};
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body1(
- spdy_util_.ConstructSpdyBodyFrame(1, "", 0, true));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 3));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(3, "", 0, true));
+ SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, "", 0, true));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, "", 0, true));
MockRead reads[] = {
- CreateMockRead(*resp1, 2),
- CreateMockRead(*body1, 3),
- CreateMockRead(*resp2, 4),
- CreateMockRead(*body2, 5),
- MockRead(ASYNC, 0, 6) // EOF
+ CreateMockRead(resp1, 2), CreateMockRead(body1, 3),
+ CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
+ MockRead(ASYNC, 0, 6) // EOF
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
@@ -318,10 +276,9 @@ TEST_P(SpdyHttpStreamTest, LoadTimingTwoRequests) {
new SpdyHttpStream(session_, true));
// First write.
- ASSERT_EQ(OK,
- http_stream1->InitializeStream(&request1, DEFAULT_PRIORITY,
- BoundNetLog(),
- CompletionCallback()));
+ ASSERT_EQ(OK, http_stream1->InitializeStream(&request1, DEFAULT_PRIORITY,
+ NetLogWithSource(),
+ CompletionCallback()));
EXPECT_EQ(ERR_IO_PENDING, http_stream1->SendRequest(headers1, &response1,
callback1.callback()));
EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
@@ -335,10 +292,9 @@ TEST_P(SpdyHttpStreamTest, LoadTimingTwoRequests) {
EXPECT_FALSE(http_stream2->GetLoadTimingInfo(&load_timing_info2));
// Second write.
- ASSERT_EQ(OK,
- http_stream2->InitializeStream(&request2, DEFAULT_PRIORITY,
- BoundNetLog(),
- CompletionCallback()));
+ ASSERT_EQ(OK, http_stream2->InitializeStream(&request2, DEFAULT_PRIORITY,
+ NetLogWithSource(),
+ CompletionCallback()));
EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers2, &response2,
callback2.callback()));
EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
@@ -357,42 +313,37 @@ TEST_P(SpdyHttpStreamTest, LoadTimingTwoRequests) {
// Stream 1 has been read to completion.
TestLoadTimingNotReused(*http_stream1);
- EXPECT_EQ(static_cast<int64_t>(req1->size()),
+ EXPECT_EQ(static_cast<int64_t>(req1.size()),
http_stream1->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(resp1->size() + body1->size()),
+ EXPECT_EQ(static_cast<int64_t>(resp1.size() + body1.size()),
http_stream1->GetTotalReceivedBytes());
// Stream 2 still has queued body data.
TestLoadTimingReused(*http_stream2);
- EXPECT_EQ(static_cast<int64_t>(req2->size()),
+ EXPECT_EQ(static_cast<int64_t>(req2.size()),
http_stream2->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(resp2->size() + body2->size()),
+ EXPECT_EQ(static_cast<int64_t>(resp2.size() + body2.size()),
http_stream2->GetTotalReceivedBytes());
}
-TEST_P(SpdyHttpStreamTest, SendChunkedPost) {
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
-
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> body(
- framer.CreateDataFrame(1, kUploadData, kUploadDataSize, DATA_FLAG_FIN));
+TEST_F(SpdyHttpStreamTest, SendChunkedPost) {
+ SpdySerializedFrame req(spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, kUploadData,
+ kUploadDataSize,
+ /*fin=*/true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), // request
- CreateMockWrite(*body, 1) // POST upload frame
+ CreateMockWrite(req, 0), // request
+ CreateMockWrite(body, 1) // POST upload frame
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(nullptr, 0));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
MockRead reads[] = {
- CreateMockRead(*resp, 2),
- CreateMockRead(*body, 3),
+ CreateMockRead(resp, 2), CreateMockRead(body, 3),
MockRead(SYNCHRONOUS, 0, 4) // EOF
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
- EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
ChunkedUploadDataStream upload_stream(0);
const int kFirstChunkSize = kUploadDataSize/2;
@@ -405,12 +356,14 @@ TEST_P(SpdyHttpStreamTest, SendChunkedPost) {
request.url = GURL("http://www.example.org/");
request.upload_data_stream = &upload_stream;
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
TestCompletionCallback callback;
HttpResponseInfo response;
HttpRequestHeaders headers;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
SpdyHttpStream http_stream(session_, true);
ASSERT_EQ(
OK,
@@ -421,11 +374,11 @@ TEST_P(SpdyHttpStreamTest, SendChunkedPost) {
headers, &response, callback.callback()));
EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
- EXPECT_EQ(static_cast<int64_t>(req->size() + body->size()),
+ EXPECT_EQ(static_cast<int64_t>(req.size() + body.size()),
http_stream.GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(resp->size() + body->size()),
+ EXPECT_EQ(static_cast<int64_t>(resp.size() + body.size()),
http_stream.GetTotalReceivedBytes());
// Because the server closed the connection, we there shouldn't be a session
@@ -434,26 +387,22 @@ TEST_P(SpdyHttpStreamTest, SendChunkedPost) {
}
// This unittest tests the request callback is properly called and handled.
-TEST_P(SpdyHttpStreamTest, SendChunkedPostLastEmpty) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> chunk(
- spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
+TEST_F(SpdyHttpStreamTest, SendChunkedPostLastEmpty) {
+ SpdySerializedFrame req(spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
+ SpdySerializedFrame chunk(
+ spdy_util_.ConstructSpdyDataFrame(1, nullptr, 0, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), // request
- CreateMockWrite(*chunk, 1),
+ CreateMockWrite(req, 0), // request
+ CreateMockWrite(chunk, 1),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(nullptr, 0));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
MockRead reads[] = {
- CreateMockRead(*resp, 2),
- CreateMockRead(*chunk, 3),
+ CreateMockRead(resp, 2), CreateMockRead(chunk, 3),
MockRead(SYNCHRONOUS, 0, 4) // EOF
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
- EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
ChunkedUploadDataStream upload_stream(0);
upload_stream.AppendData(nullptr, 0, true);
@@ -463,12 +412,14 @@ TEST_P(SpdyHttpStreamTest, SendChunkedPostLastEmpty) {
request.url = GURL("http://www.example.org/");
request.upload_data_stream = &upload_stream;
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
TestCompletionCallback callback;
HttpResponseInfo response;
HttpRequestHeaders headers;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
SpdyHttpStream http_stream(session_, true);
ASSERT_EQ(OK, http_stream.InitializeStream(&request, DEFAULT_PRIORITY,
net_log, CompletionCallback()));
@@ -476,11 +427,11 @@ TEST_P(SpdyHttpStreamTest, SendChunkedPostLastEmpty) {
http_stream.SendRequest(headers, &response, callback.callback()));
EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
- EXPECT_EQ(static_cast<int64_t>(req->size() + chunk->size()),
+ EXPECT_EQ(static_cast<int64_t>(req.size() + chunk.size()),
http_stream.GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(resp->size() + chunk->size()),
+ EXPECT_EQ(static_cast<int64_t>(resp.size() + chunk.size()),
http_stream.GetTotalReceivedBytes());
// Because the server closed the connection, there shouldn't be a session
@@ -488,26 +439,22 @@ TEST_P(SpdyHttpStreamTest, SendChunkedPostLastEmpty) {
EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
}
-TEST_P(SpdyHttpStreamTest, ConnectionClosedDuringChunkedPost) {
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
-
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> body(
- framer.CreateDataFrame(1, kUploadData, kUploadDataSize, DATA_FLAG_NONE));
+TEST_F(SpdyHttpStreamTest, ConnectionClosedDuringChunkedPost) {
+ SpdySerializedFrame req(spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, kUploadData,
+ kUploadDataSize,
+ /*fin=*/false));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), // Request
- CreateMockWrite(*body, 1) // First POST upload frame
+ CreateMockWrite(req, 0), // Request
+ CreateMockWrite(body, 1) // First POST upload frame
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(nullptr, 0));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
MockRead reads[] = {
MockRead(ASYNC, ERR_CONNECTION_CLOSED, 2) // Server hangs up early.
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
- EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
ChunkedUploadDataStream upload_stream(0);
// Append first chunk.
@@ -518,12 +465,14 @@ TEST_P(SpdyHttpStreamTest, ConnectionClosedDuringChunkedPost) {
request.url = GURL("http://www.example.org/");
request.upload_data_stream = &upload_stream;
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
TestCompletionCallback callback;
HttpResponseInfo response;
HttpRequestHeaders headers;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
SpdyHttpStream http_stream(session_, true);
ASSERT_EQ(OK, http_stream.InitializeStream(&request, DEFAULT_PRIORITY,
net_log, CompletionCallback()));
@@ -532,9 +481,9 @@ TEST_P(SpdyHttpStreamTest, ConnectionClosedDuringChunkedPost) {
http_stream.SendRequest(headers, &response, callback.callback()));
EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
- EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
- EXPECT_EQ(static_cast<int64_t>(req->size() + body->size()),
+ EXPECT_EQ(static_cast<int64_t>(req.size() + body.size()),
http_stream.GetTotalSentBytes());
EXPECT_EQ(0, http_stream.GetTotalReceivedBytes());
@@ -549,38 +498,31 @@ TEST_P(SpdyHttpStreamTest, ConnectionClosedDuringChunkedPost) {
base::RunLoop().RunUntilIdle();
// The total sent and received bytes should be unchanged.
- EXPECT_EQ(static_cast<int64_t>(req->size() + body->size()),
+ EXPECT_EQ(static_cast<int64_t>(req.size() + body.size()),
http_stream.GetTotalSentBytes());
EXPECT_EQ(0, http_stream.GetTotalReceivedBytes());
}
// Test to ensure the SpdyStream state machine does not get confused when a
// chunk becomes available while a write is pending.
-TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPost) {
+TEST_F(SpdyHttpStreamTest, DelayedSendChunkedPost) {
const char kUploadData1[] = "12345678";
const int kUploadData1Size = arraysize(kUploadData1)-1;
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> chunk1(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
- std::unique_ptr<SpdySerializedFrame> chunk2(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame req(spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
+ SpdySerializedFrame chunk1(spdy_util_.ConstructSpdyDataFrame(1, false));
+ SpdySerializedFrame chunk2(spdy_util_.ConstructSpdyDataFrame(
1, kUploadData1, kUploadData1Size, false));
- std::unique_ptr<SpdySerializedFrame> chunk3(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame chunk3(spdy_util_.ConstructSpdyDataFrame(1, true));
MockWrite writes[] = {
- CreateMockWrite(*req.get(), 0),
- CreateMockWrite(*chunk1, 1), // POST upload frames
- CreateMockWrite(*chunk2, 2),
- CreateMockWrite(*chunk3, 3),
+ CreateMockWrite(req, 0),
+ CreateMockWrite(chunk1, 1), // POST upload frames
+ CreateMockWrite(chunk2, 2), CreateMockWrite(chunk3, 3),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(nullptr, 0));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
MockRead reads[] = {
- CreateMockRead(*resp, 4),
- CreateMockRead(*chunk1, 5),
- CreateMockRead(*chunk2, 6),
- CreateMockRead(*chunk3, 7),
- MockRead(ASYNC, 0, 8) // EOF
+ CreateMockRead(resp, 4), CreateMockRead(chunk1, 5),
+ CreateMockRead(chunk2, 6), CreateMockRead(chunk3, 7),
+ MockRead(ASYNC, 0, 8) // EOF
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
@@ -592,10 +534,12 @@ TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPost) {
request.url = GURL("http://www.example.org/");
request.upload_data_stream = &upload_stream;
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
upload_stream.AppendData(kUploadData, kUploadDataSize, false);
- BoundNetLog net_log;
+ NetLogWithSource net_log;
std::unique_ptr<SpdyHttpStream> http_stream(
new SpdyHttpStream(session_, true));
ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
@@ -621,17 +565,17 @@ TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPost) {
// Finish writing all the chunks and do all reads.
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(callback.have_result());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
- EXPECT_EQ(static_cast<int64_t>(req->size() + chunk1->size() + chunk2->size() +
- chunk3->size()),
+ EXPECT_EQ(static_cast<int64_t>(req.size() + chunk1.size() + chunk2.size() +
+ chunk3.size()),
http_stream->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(resp->size() + chunk1->size() +
- chunk2->size() + chunk3->size()),
+ EXPECT_EQ(static_cast<int64_t>(resp.size() + chunk1.size() + chunk2.size() +
+ chunk3.size()),
http_stream->GetTotalReceivedBytes());
// Check response headers.
- ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
+ ASSERT_THAT(http_stream->ReadResponseHeaders(callback.callback()), IsOk());
// Check |chunk1| response.
scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
@@ -660,25 +604,19 @@ TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPost) {
// Test that the SpdyStream state machine can handle sending a final empty data
// frame when uploading a chunked data stream.
-TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithEmptyFinalDataFrame) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> chunk1(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
- std::unique_ptr<SpdySerializedFrame> chunk2(
- spdy_util_.ConstructSpdyBodyFrame(1, "", 0, true));
+TEST_F(SpdyHttpStreamTest, DelayedSendChunkedPostWithEmptyFinalDataFrame) {
+ SpdySerializedFrame req(spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
+ SpdySerializedFrame chunk1(spdy_util_.ConstructSpdyDataFrame(1, false));
+ SpdySerializedFrame chunk2(spdy_util_.ConstructSpdyDataFrame(1, "", 0, true));
MockWrite writes[] = {
- CreateMockWrite(*req.get(), 0),
- CreateMockWrite(*chunk1, 1), // POST upload frames
- CreateMockWrite(*chunk2, 2),
+ CreateMockWrite(req, 0),
+ CreateMockWrite(chunk1, 1), // POST upload frames
+ CreateMockWrite(chunk2, 2),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(nullptr, 0));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
MockRead reads[] = {
- CreateMockRead(*resp, 3),
- CreateMockRead(*chunk1, 4),
- CreateMockRead(*chunk2, 5),
- MockRead(ASYNC, 0, 6) // EOF
+ CreateMockRead(resp, 3), CreateMockRead(chunk1, 4),
+ CreateMockRead(chunk2, 5), MockRead(ASYNC, 0, 6) // EOF
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
@@ -690,10 +628,12 @@ TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithEmptyFinalDataFrame) {
request.url = GURL("http://www.example.org/");
request.upload_data_stream = &upload_stream;
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
upload_stream.AppendData(kUploadData, kUploadDataSize, false);
- BoundNetLog net_log;
+ NetLogWithSource net_log;
std::unique_ptr<SpdyHttpStream> http_stream(
new SpdyHttpStream(session_, true));
ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
@@ -712,7 +652,7 @@ TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithEmptyFinalDataFrame) {
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(callback.have_result());
- EXPECT_EQ(static_cast<int64_t>(req->size() + chunk1->size()),
+ EXPECT_EQ(static_cast<int64_t>(req.size() + chunk1.size()),
http_stream->GetTotalSentBytes());
EXPECT_EQ(0, http_stream->GetTotalReceivedBytes());
@@ -722,16 +662,15 @@ TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithEmptyFinalDataFrame) {
// Finish writing the final frame, and perform all reads.
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(callback.have_result());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// Check response headers.
- ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
+ ASSERT_THAT(http_stream->ReadResponseHeaders(callback.callback()), IsOk());
- EXPECT_EQ(static_cast<int64_t>(req->size() + chunk1->size() + chunk2->size()),
+ EXPECT_EQ(static_cast<int64_t>(req.size() + chunk1.size() + chunk2.size()),
http_stream->GetTotalSentBytes());
- EXPECT_EQ(
- static_cast<int64_t>(resp->size() + chunk1->size() + chunk2->size()),
- http_stream->GetTotalReceivedBytes());
+ EXPECT_EQ(static_cast<int64_t>(resp.size() + chunk1.size() + chunk2.size()),
+ http_stream->GetTotalReceivedBytes());
// Check |chunk1| response.
scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
@@ -751,21 +690,16 @@ TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithEmptyFinalDataFrame) {
// Test that the SpdyStream state machine handles a chunked upload with no
// payload. Unclear if this is a case worth supporting.
-TEST_P(SpdyHttpStreamTest, ChunkedPostWithEmptyPayload) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> chunk(
- spdy_util_.ConstructSpdyBodyFrame(1, "", 0, true));
+TEST_F(SpdyHttpStreamTest, ChunkedPostWithEmptyPayload) {
+ SpdySerializedFrame req(spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
+ SpdySerializedFrame chunk(spdy_util_.ConstructSpdyDataFrame(1, "", 0, true));
MockWrite writes[] = {
- CreateMockWrite(*req.get(), 0),
- CreateMockWrite(*chunk, 1),
+ CreateMockWrite(req, 0), CreateMockWrite(chunk, 1),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(nullptr, 0));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
MockRead reads[] = {
- CreateMockRead(*resp, 2),
- CreateMockRead(*chunk, 3),
- MockRead(ASYNC, 0, 4) // EOF
+ CreateMockRead(resp, 2), CreateMockRead(chunk, 3),
+ MockRead(ASYNC, 0, 4) // EOF
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
@@ -777,10 +711,12 @@ TEST_P(SpdyHttpStreamTest, ChunkedPostWithEmptyPayload) {
request.url = GURL("http://www.example.org/");
request.upload_data_stream = &upload_stream;
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
upload_stream.AppendData("", 0, true);
- BoundNetLog net_log;
+ NetLogWithSource net_log;
std::unique_ptr<SpdyHttpStream> http_stream(
new SpdyHttpStream(session_, true));
ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
@@ -798,15 +734,15 @@ TEST_P(SpdyHttpStreamTest, ChunkedPostWithEmptyPayload) {
// Complete writing request, followed by a FIN.
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(callback.have_result());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
- EXPECT_EQ(static_cast<int64_t>(req->size() + chunk->size()),
+ EXPECT_EQ(static_cast<int64_t>(req.size() + chunk.size()),
http_stream->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(resp->size() + chunk->size()),
+ EXPECT_EQ(static_cast<int64_t>(resp.size() + chunk.size()),
http_stream->GetTotalReceivedBytes());
// Check response headers.
- ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
+ ASSERT_THAT(http_stream->ReadResponseHeaders(callback.callback()), IsOk());
// Check |chunk| response.
scoped_refptr<IOBuffer> buf(new IOBuffer(1));
@@ -819,18 +755,16 @@ TEST_P(SpdyHttpStreamTest, ChunkedPostWithEmptyPayload) {
}
// Test case for bug: http://code.google.com/p/chromium/issues/detail?id=50058
-TEST_P(SpdyHttpStreamTest, SpdyURLTest) {
+TEST_F(SpdyHttpStreamTest, SpdyURLTest) {
const char* const full_url = "http://www.example.org/foo?query=what#anchor";
const char* const base_url = "http://www.example.org/foo?query=what";
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdyGet(base_url, 1, LOWEST));
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyGet(base_url, 1, LOWEST));
MockWrite writes[] = {
- CreateMockWrite(*req.get(), 0),
+ CreateMockWrite(req, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp, 1), MockRead(SYNCHRONOUS, 0, 2) // EOF
+ CreateMockRead(resp, 1), MockRead(SYNCHRONOUS, 0, 2) // EOF
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
@@ -841,7 +775,7 @@ TEST_P(SpdyHttpStreamTest, SpdyURLTest) {
TestCompletionCallback callback;
HttpResponseInfo response;
HttpRequestHeaders headers;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
std::unique_ptr<SpdyHttpStream> http_stream(
new SpdyHttpStream(session_, true));
ASSERT_EQ(OK,
@@ -855,9 +789,8 @@ TEST_P(SpdyHttpStreamTest, SpdyURLTest) {
callback.WaitForResult();
- EXPECT_EQ(static_cast<int64_t>(req->size()),
- http_stream->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(resp->size()),
+ EXPECT_EQ(static_cast<int64_t>(req.size()), http_stream->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(resp.size()),
http_stream->GetTotalReceivedBytes());
// Because we abandoned the stream, we don't expect to find a session in the
@@ -867,24 +800,18 @@ TEST_P(SpdyHttpStreamTest, SpdyURLTest) {
// Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be
// made available is handled correctly.
-TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> chunk1(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+TEST_F(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) {
+ SpdySerializedFrame req(spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
+ SpdySerializedFrame chunk1(spdy_util_.ConstructSpdyDataFrame(1, true));
MockWrite writes[] = {
- CreateMockWrite(*req.get(), 0),
- CreateMockWrite(*chunk1, 1),
+ CreateMockWrite(req, 0), CreateMockWrite(chunk1, 1),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> window_update(
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
+ SpdySerializedFrame window_update(
spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize));
MockRead reads[] = {
- CreateMockRead(*window_update, 2),
- MockRead(ASYNC, ERR_IO_PENDING, 3),
- CreateMockRead(*resp, 4),
- CreateMockRead(*chunk1, 5),
+ CreateMockRead(window_update, 2), MockRead(ASYNC, ERR_IO_PENDING, 3),
+ CreateMockRead(resp, 4), CreateMockRead(chunk1, 5),
MockRead(ASYNC, 0, 6) // EOF
};
@@ -897,9 +824,11 @@ TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) {
request.url = GURL("http://www.example.org/");
request.upload_data_stream = &upload_stream;
- ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
- BoundNetLog net_log;
+ NetLogWithSource net_log;
std::unique_ptr<SpdyHttpStream> http_stream(
new SpdyHttpStream(session_, true));
ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
@@ -918,47 +847,43 @@ TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) {
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(callback.have_result());
- EXPECT_EQ(static_cast<int64_t>(req->size()),
- http_stream->GetTotalSentBytes());
+ EXPECT_EQ(static_cast<int64_t>(req.size()), http_stream->GetTotalSentBytes());
EXPECT_EQ(0, http_stream->GetTotalReceivedBytes());
upload_stream.AppendData(kUploadData, kUploadDataSize, true);
-
// Verify that the window size has decreased.
ASSERT_TRUE(http_stream->stream() != nullptr);
- EXPECT_NE(static_cast<int>(
- SpdySession::GetDefaultInitialWindowSize(session_->protocol())),
+ EXPECT_NE(static_cast<int>(kDefaultInitialWindowSize),
http_stream->stream()->send_window_size());
// Read window update.
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(callback.have_result());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
- EXPECT_EQ(static_cast<int64_t>(req->size() + chunk1->size()),
+ EXPECT_EQ(static_cast<int64_t>(req.size() + chunk1.size()),
http_stream->GetTotalSentBytes());
// The window update is not counted in the total received bytes.
EXPECT_EQ(0, http_stream->GetTotalReceivedBytes());
// Verify the window update.
ASSERT_TRUE(http_stream->stream() != nullptr);
- EXPECT_EQ(static_cast<int>(
- SpdySession::GetDefaultInitialWindowSize(session_->protocol())),
+ EXPECT_EQ(static_cast<int>(kDefaultInitialWindowSize),
http_stream->stream()->send_window_size());
// Read rest of data.
sequenced_data_->Resume();
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(static_cast<int64_t>(req->size() + chunk1->size()),
+ EXPECT_EQ(static_cast<int64_t>(req.size() + chunk1.size()),
http_stream->GetTotalSentBytes());
- EXPECT_EQ(static_cast<int64_t>(resp->size() + chunk1->size()),
+ EXPECT_EQ(static_cast<int64_t>(resp.size() + chunk1.size()),
http_stream->GetTotalReceivedBytes());
// Check response headers.
- ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
+ ASSERT_THAT(http_stream->ReadResponseHeaders(callback.callback()), IsOk());
// Check |chunk1| response.
scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
@@ -971,34 +896,33 @@ TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) {
ASSERT_EQ(200, response.headers->response_code());
}
-TEST_P(SpdyHttpStreamTest, DataReadErrorSynchronous) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
+TEST_F(SpdyHttpStreamTest, DataReadErrorSynchronous) {
+ SpdySerializedFrame req(spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
// Server receives RST_STREAM_INTERNAL_ERROR on client's internal failure.
// The failure is a reading error in this case caused by
// UploadDataStream::Read().
- std::unique_ptr<SpdySerializedFrame> rst_frame(
+ SpdySerializedFrame rst_frame(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_INTERNAL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*req, 0, SYNCHRONOUS), // Request
- CreateMockWrite(*rst_frame, 1, SYNCHRONOUS) // Reset frame
+ CreateMockWrite(req, 0, SYNCHRONOUS), // Request
+ CreateMockWrite(rst_frame, 1, SYNCHRONOUS) // Reset frame
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(nullptr, 0));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
MockRead reads[] = {
- CreateMockRead(*resp, 2), MockRead(SYNCHRONOUS, 0, 3),
+ CreateMockRead(resp, 2), MockRead(SYNCHRONOUS, 0, 3),
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
- EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
ReadErrorUploadDataStream upload_data_stream(
ReadErrorUploadDataStream::FailureMode::SYNC);
- ASSERT_EQ(OK, upload_data_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_data_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
HttpRequestInfo request;
request.method = "POST";
@@ -1008,47 +932,46 @@ TEST_P(SpdyHttpStreamTest, DataReadErrorSynchronous) {
TestCompletionCallback callback;
HttpResponseInfo response;
HttpRequestHeaders headers;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
SpdyHttpStream http_stream(session_, true);
ASSERT_EQ(OK, http_stream.InitializeStream(&request, DEFAULT_PRIORITY,
net_log, CompletionCallback()));
int result = http_stream.SendRequest(headers, &response, callback.callback());
- EXPECT_EQ(ERR_FAILED, callback.GetResult(result));
+ EXPECT_THAT(callback.GetResult(result), IsError(ERR_FAILED));
// Because the server has not closed the connection yet, there shouldn't be
// a stream but a session in the pool
EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
}
-TEST_P(SpdyHttpStreamTest, DataReadErrorAsynchronous) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
+TEST_F(SpdyHttpStreamTest, DataReadErrorAsynchronous) {
+ SpdySerializedFrame req(spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
// Server receives RST_STREAM_INTERNAL_ERROR on client's internal failure.
// The failure is a reading error in this case caused by
// UploadDataStream::Read().
- std::unique_ptr<SpdySerializedFrame> rst_frame(
+ SpdySerializedFrame rst_frame(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_INTERNAL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), // Request
- CreateMockWrite(*rst_frame, 1) // Reset frame
+ CreateMockWrite(req, 0), // Request
+ CreateMockWrite(rst_frame, 1) // Reset frame
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(nullptr, 0));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
MockRead reads[] = {
MockRead(ASYNC, 0, 2),
};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
- EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
ReadErrorUploadDataStream upload_data_stream(
ReadErrorUploadDataStream::FailureMode::ASYNC);
- ASSERT_EQ(OK, upload_data_stream.Init(TestCompletionCallback().callback()));
+ ASSERT_THAT(upload_data_stream.Init(TestCompletionCallback().callback(),
+ NetLogWithSource()),
+ IsOk());
HttpRequestInfo request;
request.method = "POST";
@@ -1058,14 +981,14 @@ TEST_P(SpdyHttpStreamTest, DataReadErrorAsynchronous) {
TestCompletionCallback callback;
HttpResponseInfo response;
HttpRequestHeaders headers;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
SpdyHttpStream http_stream(session_, true);
ASSERT_EQ(OK, http_stream.InitializeStream(&request, DEFAULT_PRIORITY,
net_log, CompletionCallback()));
int result = http_stream.SendRequest(headers, &response, callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(ERR_FAILED, callback.GetResult(result));
+ EXPECT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(callback.GetResult(result), IsError(ERR_FAILED));
// Because the server has closed the connection, there shouldn't be a session
// in the pool anymore.
@@ -1073,15 +996,14 @@ TEST_P(SpdyHttpStreamTest, DataReadErrorAsynchronous) {
}
// Regression test for https://crbug.com/622447.
-TEST_P(SpdyHttpStreamTest, RequestCallbackCancelsStream) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> chunk(
- spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+TEST_F(SpdyHttpStreamTest, RequestCallbackCancelsStream) {
+ SpdySerializedFrame req(spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
+ SpdySerializedFrame chunk(
+ spdy_util_.ConstructSpdyDataFrame(1, nullptr, 0, true));
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
- MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*chunk, 1),
- CreateMockWrite(*rst, 2)};
+ MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(chunk, 1),
+ CreateMockWrite(rst, 2)};
MockRead reads[] = {MockRead(ASYNC, 0, 3)};
InitSession(reads, arraysize(reads), writes, arraysize(writes));
@@ -1092,13 +1014,16 @@ TEST_P(SpdyHttpStreamTest, RequestCallbackCancelsStream) {
request.upload_data_stream = &upload_stream;
TestCompletionCallback upload_callback;
- ASSERT_EQ(OK, upload_stream.Init(upload_callback.callback()));
+ ASSERT_THAT(
+ upload_stream.Init(upload_callback.callback(), NetLogWithSource()),
+ IsOk());
upload_stream.AppendData("", 0, true);
- BoundNetLog net_log;
+ NetLogWithSource net_log;
SpdyHttpStream http_stream(session_, true);
- ASSERT_EQ(OK, http_stream.InitializeStream(&request, DEFAULT_PRIORITY,
- net_log, CompletionCallback()));
+ ASSERT_THAT(http_stream.InitializeStream(&request, DEFAULT_PRIORITY, net_log,
+ CompletionCallback()),
+ IsOk());
CancelStreamCallback callback(&http_stream);
HttpRequestHeaders headers;
@@ -1110,7 +1035,7 @@ TEST_P(SpdyHttpStreamTest, RequestCallbackCancelsStream) {
EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
// The callback cancels |http_stream|.
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
}
diff --git a/chromium/net/spdy/spdy_http_utils.cc b/chromium/net/spdy/spdy_http_utils.cc
index 573bce18b8f..1213f1ca8c2 100644
--- a/chromium/net/spdy/spdy_http_utils.cc
+++ b/chromium/net/spdy/spdy_http_utils.cc
@@ -39,31 +39,13 @@ void AddSpdyHeader(const std::string& name,
} // namespace
bool SpdyHeadersToHttpResponse(const SpdyHeaderBlock& headers,
- SpdyMajorVersion protocol_version,
HttpResponseInfo* response) {
- std::string status_key = (protocol_version >= SPDY3) ? ":status" : "status";
- std::string version_key =
- (protocol_version >= SPDY3) ? ":version" : "version";
- std::string version;
- std::string status;
-
- // The "status" header is required. "version" is required below HTTP/2.
- SpdyHeaderBlock::const_iterator it;
- it = headers.find(status_key);
+ // The ":status" header is required.
+ SpdyHeaderBlock::const_iterator it = headers.find(":status");
if (it == headers.end())
return false;
- status = it->second.as_string();
-
- if (protocol_version >= HTTP2) {
- version = "HTTP/1.1";
- } else {
- it = headers.find(version_key);
- if (it == headers.end())
- return false;
- version = it->second.as_string();
- }
- std::string raw_headers(version);
- raw_headers.push_back(' ');
+ std::string status = it->second.as_string();
+ std::string raw_headers("HTTP/1.1 ");
raw_headers.append(status);
raw_headers.push_back('\0');
for (it = headers.begin(); it != headers.end(); ++it) {
@@ -103,34 +85,15 @@ bool SpdyHeadersToHttpResponse(const SpdyHeaderBlock& headers,
void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info,
const HttpRequestHeaders& request_headers,
- SpdyMajorVersion protocol_version,
bool direct,
SpdyHeaderBlock* headers) {
- static const char kHttpProtocolVersion[] = "HTTP/1.1";
- switch (protocol_version) {
- case SPDY3:
- (*headers)[":version"] = kHttpProtocolVersion;
- (*headers)[":method"] = info.method;
- (*headers)[":host"] = GetHostAndOptionalPort(info.url);
- if (info.method == "CONNECT") {
- (*headers)[":path"] = GetHostAndPort(info.url);
- } else {
- (*headers)[":scheme"] = info.url.scheme();
- (*headers)[":path"] = info.url.PathForRequest();
- }
- break;
- case HTTP2:
- (*headers)[":method"] = info.method;
- if (info.method == "CONNECT") {
- (*headers)[":authority"] = GetHostAndPort(info.url);
- } else {
- (*headers)[":authority"] = GetHostAndOptionalPort(info.url);
- (*headers)[":scheme"] = info.url.scheme();
- (*headers)[":path"] = info.url.PathForRequest();
- }
- break;
- default:
- NOTREACHED();
+ (*headers)[":method"] = info.method;
+ if (info.method == "CONNECT") {
+ (*headers)[":authority"] = GetHostAndPort(info.url);
+ } else {
+ (*headers)[":authority"] = GetHostAndOptionalPort(info.url);
+ (*headers)[":scheme"] = info.url.scheme();
+ (*headers)[":path"] = info.url.PathForRequest();
}
HttpRequestHeaders::Iterator it(request_headers);
@@ -147,23 +110,14 @@ void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info,
void CreateSpdyHeadersFromHttpResponse(
const HttpResponseHeaders& response_headers,
- SpdyMajorVersion protocol_version,
SpdyHeaderBlock* headers) {
- std::string status_key = (protocol_version >= SPDY3) ? ":status" : "status";
- std::string version_key =
- (protocol_version >= SPDY3) ? ":version" : "version";
-
const std::string status_line = response_headers.GetStatusLine();
std::string::const_iterator after_version =
std::find(status_line.begin(), status_line.end(), ' ');
- if (protocol_version < HTTP2) {
- (*headers)[version_key] = std::string(status_line.begin(), after_version);
- }
-
// Get status code only.
std::string::const_iterator after_status =
std::find(after_version + 1, status_line.end(), ' ');
- (*headers)[status_key] = std::string(after_version + 1, after_status);
+ (*headers)[":status"] = std::string(after_version + 1, after_status);
size_t iter = 0;
std::string raw_name, value;
@@ -177,16 +131,14 @@ static_assert(HIGHEST - LOWEST < 4 && HIGHEST - MINIMUM_PRIORITY < 5,
"request priority incompatible with spdy");
SpdyPriority ConvertRequestPriorityToSpdyPriority(
- const RequestPriority priority,
- SpdyMajorVersion protocol_version) {
+ const RequestPriority priority) {
DCHECK_GE(priority, MINIMUM_PRIORITY);
DCHECK_LE(priority, MAXIMUM_PRIORITY);
return static_cast<SpdyPriority>(MAXIMUM_PRIORITY - priority);
}
-NET_EXPORT_PRIVATE RequestPriority ConvertSpdyPriorityToRequestPriority(
- SpdyPriority priority,
- SpdyMajorVersion protocol_version) {
+NET_EXPORT_PRIVATE RequestPriority
+ConvertSpdyPriorityToRequestPriority(SpdyPriority priority) {
// Handle invalid values gracefully.
// Note that SpdyPriority is not an enum, hence the magic constants.
return (priority >= 5) ?
@@ -209,15 +161,14 @@ NET_EXPORT_PRIVATE void ConvertHeaderBlockToHttpRequestHeaders(
}
}
-GURL GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers,
- SpdyMajorVersion protocol_version) {
+GURL GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers) {
SpdyHeaderBlock::const_iterator it = headers.find(":scheme");
if (it == headers.end())
return GURL();
std::string url = it->second.as_string();
url.append("://");
- it = headers.find(protocol_version >= HTTP2 ? ":authority" : ":host");
+ it = headers.find(":authority");
if (it == headers.end())
return GURL();
url.append(it->second.as_string());
diff --git a/chromium/net/spdy/spdy_http_utils.h b/chromium/net/spdy/spdy_http_utils.h
index b33a91a2215..6989ad5e41e 100644
--- a/chromium/net/spdy/spdy_http_utils.h
+++ b/chromium/net/spdy/spdy_http_utils.h
@@ -26,21 +26,18 @@ class HttpResponseHeaders;
// incomplete (e.g. missing 'status' or 'version').
NET_EXPORT bool SpdyHeadersToHttpResponse(
const SpdyHeaderBlock& headers,
- SpdyMajorVersion protocol_version,
HttpResponseInfo* response);
// Create a SpdyHeaderBlock from HttpRequestInfo and HttpRequestHeaders.
NET_EXPORT void CreateSpdyHeadersFromHttpRequest(
const HttpRequestInfo& info,
const HttpRequestHeaders& request_headers,
- SpdyMajorVersion protocol_version,
bool direct,
SpdyHeaderBlock* headers);
// Create a SpdyHeaderBlock from HttpResponseHeaders.
NET_EXPORT void CreateSpdyHeadersFromHttpResponse(
const HttpResponseHeaders& response_headers,
- SpdyMajorVersion protocol_version,
SpdyHeaderBlock* headers);
// Create HttpRequestHeaders from SpdyHeaderBlock.
@@ -50,16 +47,13 @@ NET_EXPORT void ConvertHeaderBlockToHttpRequestHeaders(
// Returns the URL associated with the |headers| by assembling the
// scheme, host and path from the protocol specific keys.
-NET_EXPORT GURL GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers,
- SpdyMajorVersion protocol_version);
+NET_EXPORT GURL GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers);
-NET_EXPORT SpdyPriority ConvertRequestPriorityToSpdyPriority(
- RequestPriority priority,
- SpdyMajorVersion protocol_version);
+NET_EXPORT SpdyPriority
+ConvertRequestPriorityToSpdyPriority(RequestPriority priority);
-NET_EXPORT RequestPriority ConvertSpdyPriorityToRequestPriority(
- SpdyPriority priority,
- SpdyMajorVersion protocol_version);
+NET_EXPORT RequestPriority
+ConvertSpdyPriorityToRequestPriority(SpdyPriority priority);
} // namespace net
diff --git a/chromium/net/spdy/spdy_http_utils_unittest.cc b/chromium/net/spdy/spdy_http_utils_unittest.cc
index a53e33145d2..999a03a4454 100644
--- a/chromium/net/spdy/spdy_http_utils_unittest.cc
+++ b/chromium/net/spdy/spdy_http_utils_unittest.cc
@@ -22,43 +22,26 @@ bool kDirect = true;
} // namespace
TEST(SpdyHttpUtilsTest, ConvertRequestPriorityToSpdy3Priority) {
- EXPECT_EQ(0, ConvertRequestPriorityToSpdyPriority(HIGHEST, SPDY3));
- EXPECT_EQ(1, ConvertRequestPriorityToSpdyPriority(MEDIUM, SPDY3));
- EXPECT_EQ(2, ConvertRequestPriorityToSpdyPriority(LOW, SPDY3));
- EXPECT_EQ(3, ConvertRequestPriorityToSpdyPriority(LOWEST, SPDY3));
- EXPECT_EQ(4, ConvertRequestPriorityToSpdyPriority(IDLE, SPDY3));
+ EXPECT_EQ(0, ConvertRequestPriorityToSpdyPriority(HIGHEST));
+ EXPECT_EQ(1, ConvertRequestPriorityToSpdyPriority(MEDIUM));
+ EXPECT_EQ(2, ConvertRequestPriorityToSpdyPriority(LOW));
+ EXPECT_EQ(3, ConvertRequestPriorityToSpdyPriority(LOWEST));
+ EXPECT_EQ(4, ConvertRequestPriorityToSpdyPriority(IDLE));
}
TEST(SpdyHttpUtilsTest, ConvertSpdy3PriorityToRequestPriority) {
- EXPECT_EQ(HIGHEST, ConvertSpdyPriorityToRequestPriority(0, SPDY3));
- EXPECT_EQ(MEDIUM, ConvertSpdyPriorityToRequestPriority(1, SPDY3));
- EXPECT_EQ(LOW, ConvertSpdyPriorityToRequestPriority(2, SPDY3));
- EXPECT_EQ(LOWEST, ConvertSpdyPriorityToRequestPriority(3, SPDY3));
- EXPECT_EQ(IDLE, ConvertSpdyPriorityToRequestPriority(4, SPDY3));
+ EXPECT_EQ(HIGHEST, ConvertSpdyPriorityToRequestPriority(0));
+ EXPECT_EQ(MEDIUM, ConvertSpdyPriorityToRequestPriority(1));
+ EXPECT_EQ(LOW, ConvertSpdyPriorityToRequestPriority(2));
+ EXPECT_EQ(LOWEST, ConvertSpdyPriorityToRequestPriority(3));
+ EXPECT_EQ(IDLE, ConvertSpdyPriorityToRequestPriority(4));
// These are invalid values, but we should still handle them
// gracefully.
for (int i = 5; i < std::numeric_limits<uint8_t>::max(); ++i) {
- EXPECT_EQ(IDLE, ConvertSpdyPriorityToRequestPriority(i, SPDY3));
+ EXPECT_EQ(IDLE, ConvertSpdyPriorityToRequestPriority(i));
}
}
-TEST(SpdyHttpUtilsTest, CreateSpdyHeadersFromHttpRequestSPDY3) {
- GURL url("https://www.google.com/index.html");
- HttpRequestInfo request;
- request.method = "GET";
- request.url = url;
- request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, "Chrome/1.1");
- SpdyHeaderBlock headers;
- CreateSpdyHeadersFromHttpRequest(request, request.extra_headers, SPDY3,
- kDirect, &headers);
- EXPECT_EQ("GET", headers[":method"]);
- EXPECT_EQ("https", headers[":scheme"]);
- EXPECT_EQ("www.google.com", headers[":host"]);
- EXPECT_EQ("/index.html", headers[":path"]);
- EXPECT_EQ("HTTP/1.1", headers[":version"]);
- EXPECT_EQ("Chrome/1.1", headers["user-agent"]);
-}
-
TEST(SpdyHttpUtilsTest, CreateSpdyHeadersFromHttpRequestHTTP2) {
GURL url("https://www.google.com/index.html");
HttpRequestInfo request;
@@ -66,8 +49,8 @@ TEST(SpdyHttpUtilsTest, CreateSpdyHeadersFromHttpRequestHTTP2) {
request.url = url;
request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, "Chrome/1.1");
SpdyHeaderBlock headers;
- CreateSpdyHeadersFromHttpRequest(request, request.extra_headers, HTTP2,
- kDirect, &headers);
+ CreateSpdyHeadersFromHttpRequest(request, request.extra_headers, kDirect,
+ &headers);
EXPECT_EQ("GET", headers[":method"]);
EXPECT_EQ("https", headers[":scheme"]);
EXPECT_EQ("www.google.com", headers[":authority"]);
@@ -76,23 +59,6 @@ TEST(SpdyHttpUtilsTest, CreateSpdyHeadersFromHttpRequestHTTP2) {
EXPECT_EQ("Chrome/1.1", headers["user-agent"]);
}
-TEST(SpdyHttpUtilsTest, CreateSpdyHeadersFromHttpRequestProxySPDY3) {
- GURL url("https://www.google.com/index.html");
- HttpRequestInfo request;
- request.method = "GET";
- request.url = url;
- request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, "Chrome/1.1");
- SpdyHeaderBlock headers;
- CreateSpdyHeadersFromHttpRequest(request, request.extra_headers, SPDY3,
- !kDirect, &headers);
- EXPECT_EQ("GET", headers[":method"]);
- EXPECT_EQ("https", headers[":scheme"]);
- EXPECT_EQ("www.google.com", headers[":host"]);
- EXPECT_EQ("/index.html", headers[":path"]);
- EXPECT_EQ("HTTP/1.1", headers[":version"]);
- EXPECT_EQ("Chrome/1.1", headers["user-agent"]);
-}
-
TEST(SpdyHttpUtilsTest, CreateSpdyHeadersFromHttpRequestProxyHTTP2) {
GURL url("https://www.google.com/index.html");
HttpRequestInfo request;
@@ -100,8 +66,8 @@ TEST(SpdyHttpUtilsTest, CreateSpdyHeadersFromHttpRequestProxyHTTP2) {
request.url = url;
request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, "Chrome/1.1");
SpdyHeaderBlock headers;
- CreateSpdyHeadersFromHttpRequest(request, request.extra_headers, HTTP2,
- !kDirect, &headers);
+ CreateSpdyHeadersFromHttpRequest(request, request.extra_headers, !kDirect,
+ &headers);
EXPECT_EQ("GET", headers[":method"]);
EXPECT_EQ("https", headers[":scheme"]);
EXPECT_EQ("www.google.com", headers[":authority"]);
@@ -110,23 +76,6 @@ TEST(SpdyHttpUtilsTest, CreateSpdyHeadersFromHttpRequestProxyHTTP2) {
EXPECT_EQ("Chrome/1.1", headers["user-agent"]);
}
-TEST(SpdyHttpUtilsTest, CreateSpdyHeadersFromHttpRequestConnectSPDY3) {
- GURL url("https://www.google.com/index.html");
- HttpRequestInfo request;
- request.method = "CONNECT";
- request.url = url;
- request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, "Chrome/1.1");
- SpdyHeaderBlock headers;
- CreateSpdyHeadersFromHttpRequest(request, request.extra_headers, SPDY3,
- kDirect, &headers);
- EXPECT_EQ("CONNECT", headers[":method"]);
- EXPECT_TRUE(headers.end() == headers.find(":scheme"));
- EXPECT_EQ("www.google.com", headers[":host"]);
- EXPECT_EQ("www.google.com:443", headers[":path"]);
- EXPECT_EQ("HTTP/1.1", headers[":version"]);
- EXPECT_EQ("Chrome/1.1", headers["user-agent"]);
-}
-
TEST(SpdyHttpUtilsTest, CreateSpdyHeadersFromHttpRequestConnectHTTP2) {
GURL url("https://www.google.com/index.html");
HttpRequestInfo request;
@@ -134,8 +83,8 @@ TEST(SpdyHttpUtilsTest, CreateSpdyHeadersFromHttpRequestConnectHTTP2) {
request.url = url;
request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, "Chrome/1.1");
SpdyHeaderBlock headers;
- CreateSpdyHeadersFromHttpRequest(request, request.extra_headers, HTTP2,
- kDirect, &headers);
+ CreateSpdyHeadersFromHttpRequest(request, request.extra_headers, kDirect,
+ &headers);
EXPECT_EQ("CONNECT", headers[":method"]);
EXPECT_TRUE(headers.end() == headers.find(":scheme"));
EXPECT_EQ("www.google.com:443", headers[":authority"]);
diff --git a/chromium/net/spdy/spdy_network_transaction_unittest.cc b/chromium/net/spdy/spdy_network_transaction_unittest.cc
index 2ec46b880b1..8105580521e 100644
--- a/chromium/net/spdy/spdy_network_transaction_unittest.cc
+++ b/chromium/net/spdy/spdy_network_transaction_unittest.cc
@@ -30,6 +30,8 @@
#include "net/http/http_network_transaction.h"
#include "net/http/http_server_properties.h"
#include "net/http/http_transaction_test_util.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
#include "net/log/test_net_log_entry.h"
#include "net/log/test_net_log_util.h"
@@ -45,11 +47,15 @@
#include "net/spdy/spdy_test_utils.h"
#include "net/ssl/ssl_connection_status_flags.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/platform_test.h"
+using net::test::IsError;
+using net::test::IsOk;
+
//-----------------------------------------------------------------------------
namespace net {
@@ -61,62 +67,15 @@ using testing::Eq;
const int32_t kBufferSize = SpdyHttpStream::kRequestBodyBufferSize;
-struct SpdyNetworkTransactionTestParams {
- SpdyNetworkTransactionTestParams()
- : protocol(kProtoSPDY31),
- priority_to_dependency(false) {}
-
- SpdyNetworkTransactionTestParams(NextProto protocol,
- bool priority_to_dependency)
- : protocol(protocol),
- priority_to_dependency(priority_to_dependency) {}
-
- friend std::ostream& operator<<(std::ostream& os,
- const SpdyNetworkTransactionTestParams& p) {
- os << "{ protocol: " << SSLClientSocket::NextProtoToString(p.protocol)
- << ", priority_to_dependency: " << p.priority_to_dependency << " }";
- return os;
- }
-
- NextProto protocol;
- bool priority_to_dependency;
-};
-
-void UpdateSpdySessionDependencies(SpdyNetworkTransactionTestParams test_params,
- SpdySessionDependencies* session_deps) {
- session_deps->enable_priority_dependencies =
- test_params.priority_to_dependency;
-}
-
-std::unique_ptr<SpdySessionDependencies> CreateSpdySessionDependencies(
- SpdyNetworkTransactionTestParams test_params) {
- std::unique_ptr<SpdySessionDependencies> session_deps(
- new SpdySessionDependencies(test_params.protocol));
- UpdateSpdySessionDependencies(test_params, session_deps.get());
- return session_deps;
-}
-
-std::unique_ptr<SpdySessionDependencies> CreateSpdySessionDependencies(
- SpdyNetworkTransactionTestParams test_params,
- std::unique_ptr<ProxyService> proxy_service) {
- std::unique_ptr<SpdySessionDependencies> session_deps(
- new SpdySessionDependencies(test_params.protocol,
- std::move(proxy_service)));
- UpdateSpdySessionDependencies(test_params, session_deps.get());
- return session_deps;
-}
-
} // namespace
-class SpdyNetworkTransactionTest
- : public ::testing::TestWithParam<SpdyNetworkTransactionTestParams> {
+class SpdyNetworkTransactionTest : public ::testing::Test {
protected:
SpdyNetworkTransactionTest()
: default_url_(kDefaultUrl),
- host_port_pair_(HostPortPair::FromURL(default_url_)),
- spdy_util_(GetParam().protocol, GetParam().priority_to_dependency) {}
+ host_port_pair_(HostPortPair::FromURL(default_url_)) {}
- virtual ~SpdyNetworkTransactionTest() {
+ ~SpdyNetworkTransactionTest() override {
// UploadDataStream may post a deletion tasks back to the message loop on
// destruction.
upload_data_stream_.reset();
@@ -143,19 +102,16 @@ class SpdyNetworkTransactionTest
NormalSpdyTransactionHelper(
const HttpRequestInfo& request,
RequestPriority priority,
- const BoundNetLog& log,
- SpdyNetworkTransactionTestParams test_params,
+ const NetLogWithSource& log,
std::unique_ptr<SpdySessionDependencies> session_deps)
: request_(request),
priority_(priority),
session_deps_(session_deps.get() == NULL
- ? CreateSpdySessionDependencies(test_params)
+ ? base::MakeUnique<SpdySessionDependencies>()
: std::move(session_deps)),
session_(
SpdySessionDependencies::SpdyCreateSession(session_deps_.get())),
- log_(log),
- test_params_(test_params),
- spdy_enabled_(true) {}
+ log_(log) {}
~NormalSpdyTransactionHelper() {
// Any test which doesn't close the socket by sending it an EOF will
@@ -169,18 +125,7 @@ class SpdyNetworkTransactionTest
session()->spdy_session_pool()->CloseAllSessions();
}
- void SetSpdyDisabled() {
- spdy_enabled_ = false;
- }
-
void RunPreTestSetup() {
- if (!session_deps_.get())
- session_deps_ = CreateSpdySessionDependencies(test_params_);
- if (!session_.get()) {
- session_ = SpdySessionDependencies::SpdyCreateSession(
- session_deps_.get());
- }
-
// We're now ready to use SSL-npn SPDY.
trans_.reset(new HttpNetworkTransaction(priority_, session_.get()));
}
@@ -211,27 +156,11 @@ class SpdyNetworkTransactionTest
const HttpResponseInfo* response = trans_->GetResponseInfo();
ASSERT_TRUE(response);
ASSERT_TRUE(response->headers);
- if (HttpStreamFactory::spdy_enabled()) {
- EXPECT_EQ(
- HttpResponseInfo::ConnectionInfoFromNextProto(
- test_params_.protocol),
- response->connection_info);
- } else {
- EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
- response->connection_info);
- }
- if (spdy_enabled_) {
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_npn_negotiated);
- } else {
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_FALSE(response->was_fetched_via_spdy);
- // If SPDY is disabled, an HTTP request should not be diverted
- // over an SSL session.
- EXPECT_EQ(request_.url.SchemeIs("https"),
- response->was_npn_negotiated);
- }
+ EXPECT_EQ(HttpResponseInfo::ConnectionInfoFromNextProto(kProtoHTTP2),
+ response->connection_info);
+ EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
+ EXPECT_TRUE(response->was_fetched_via_spdy);
+ EXPECT_TRUE(response->was_alpn_negotiated);
EXPECT_EQ("127.0.0.1", response->socket_address.host());
EXPECT_EQ(443, response->socket_address.port());
output_.status_line = response->headers->GetStatusLine();
@@ -295,10 +224,8 @@ class SpdyNetworkTransactionTest
SocketDataProvider* data,
std::unique_ptr<SSLSocketDataProvider> ssl_provider) {
data_vector_.push_back(data);
- if (ssl_provider->next_proto_status ==
- SSLClientSocket::kNextProtoUnsupported) {
- ssl_provider->SetNextProto(test_params_.protocol);
- }
+ if (ssl_provider->next_proto == kProtoUnknown)
+ ssl_provider->next_proto = kProtoHTTP2;
session_deps_->socket_factory->AddSSLSocketDataProvider(
ssl_provider.get());
@@ -307,20 +234,12 @@ class SpdyNetworkTransactionTest
session_deps_->socket_factory->AddSocketDataProvider(data);
}
- void SetSession(std::unique_ptr<HttpNetworkSession> session) {
- session_ = std::move(session);
- }
HttpNetworkTransaction* trans() { return trans_.get(); }
void ResetTrans() { trans_.reset(); }
- TransactionHelperResult& output() { return output_; }
+ const TransactionHelperResult& output() { return output_; }
const HttpRequestInfo& request() const { return request_; }
HttpNetworkSession* session() const { return session_.get(); }
- std::unique_ptr<SpdySessionDependencies>& session_deps() {
- return session_deps_;
- }
- SpdyNetworkTransactionTestParams test_params() const {
- return test_params_;
- }
+ SpdySessionDependencies* session_deps() { return session_deps_.get(); }
private:
typedef std::vector<SocketDataProvider*> DataVector;
@@ -331,16 +250,11 @@ class SpdyNetworkTransactionTest
std::unique_ptr<SpdySessionDependencies> session_deps_;
std::unique_ptr<HttpNetworkSession> session_;
TransactionHelperResult output_;
- std::unique_ptr<SocketDataProvider> first_transaction_;
SSLVector ssl_vector_;
TestCompletionCallback callback_;
std::unique_ptr<HttpNetworkTransaction> trans_;
- std::unique_ptr<HttpNetworkTransaction> trans_http_;
DataVector data_vector_;
- AlternateVector alternate_vector_;
- const BoundNetLog log_;
- SpdyNetworkTransactionTestParams test_params_;
- bool spdy_enabled_;
+ const NetLogWithSource log_;
};
void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
@@ -379,8 +293,8 @@ class SpdyNetworkTransactionTest
const HttpRequestInfo& CreatePostRequest() {
if (!post_request_initialized_) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(base::WrapUnique(
- new UploadBytesElementReader(kUploadData, kUploadDataSize)));
+ element_readers.push_back(base::MakeUnique<UploadBytesElementReader>(
+ kUploadData, kUploadDataSize));
upload_data_stream_.reset(
new ElementsUploadDataStream(std::move(element_readers), 0));
@@ -395,14 +309,14 @@ class SpdyNetworkTransactionTest
const HttpRequestInfo& CreateFilePostRequest() {
if (!post_request_initialized_) {
base::FilePath file_path;
- CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
+ CHECK(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
CHECK_EQ(static_cast<int>(kUploadDataSize),
base::WriteFile(file_path, kUploadData, kUploadDataSize));
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(base::WrapUnique(new UploadFileElementReader(
+ element_readers.push_back(base::MakeUnique<UploadFileElementReader>(
base::ThreadTaskRunnerHandle::Get().get(), file_path, 0,
- kUploadDataSize, base::Time())));
+ kUploadDataSize, base::Time()));
upload_data_stream_.reset(
new ElementsUploadDataStream(std::move(element_readers), 0));
@@ -419,15 +333,15 @@ class SpdyNetworkTransactionTest
return post_request_;
base::FilePath file_path;
- CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
+ CHECK(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
CHECK_EQ(static_cast<int>(kUploadDataSize),
base::WriteFile(file_path, kUploadData, kUploadDataSize));
CHECK(base::MakeFileUnreadable(file_path));
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(base::WrapUnique(new UploadFileElementReader(
+ element_readers.push_back(base::MakeUnique<UploadFileElementReader>(
base::ThreadTaskRunnerHandle::Get().get(), file_path, 0,
- kUploadDataSize, base::Time())));
+ kUploadDataSize, base::Time()));
upload_data_stream_.reset(
new ElementsUploadDataStream(std::move(element_readers), 0));
@@ -445,19 +359,19 @@ class SpdyNetworkTransactionTest
CHECK_LT(kFileRangeOffset + kFileRangeLength, kUploadDataSize);
base::FilePath file_path;
- CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
+ CHECK(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
CHECK_EQ(static_cast<int>(kUploadDataSize),
base::WriteFile(file_path, kUploadData, kUploadDataSize));
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(base::WrapUnique(
- new UploadBytesElementReader(kUploadData, kFileRangeOffset)));
- element_readers.push_back(base::WrapUnique(new UploadFileElementReader(
+ element_readers.push_back(base::MakeUnique<UploadBytesElementReader>(
+ kUploadData, kFileRangeOffset));
+ element_readers.push_back(base::MakeUnique<UploadFileElementReader>(
base::ThreadTaskRunnerHandle::Get().get(), file_path,
- kFileRangeOffset, kFileRangeLength, base::Time())));
- element_readers.push_back(base::WrapUnique(new UploadBytesElementReader(
+ kFileRangeOffset, kFileRangeLength, base::Time()));
+ element_readers.push_back(base::MakeUnique<UploadBytesElementReader>(
kUploadData + kFileRangeOffset + kFileRangeLength,
- kUploadDataSize - (kFileRangeOffset + kFileRangeLength))));
+ kUploadDataSize - (kFileRangeOffset + kFileRangeLength)));
upload_data_stream_.reset(
new ElementsUploadDataStream(std::move(element_readers), 0));
@@ -512,7 +426,7 @@ class SpdyNetworkTransactionTest
const GURL& url = helper.request().url;
SpdySessionKey key(HostPortPair::FromURL(url), ProxyServer::Direct(),
PRIVACY_MODE_DISABLED);
- BoundNetLog log;
+ NetLogWithSource log;
HttpNetworkSession* session = helper.session();
base::WeakPtr<SpdySession> spdy_session =
session->spdy_session_pool()->FindAvailableSession(key, url, log);
@@ -526,7 +440,7 @@ class SpdyNetworkTransactionTest
HttpResponseInfo* push_response,
const std::string& expected) {
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(data);
@@ -534,17 +448,16 @@ class SpdyNetworkTransactionTest
// Start the transaction with basic parameters.
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
// Request the pushed path.
- std::unique_ptr<HttpNetworkTransaction> trans2(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
- rv = trans2->Start(
- &CreateGetPushRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
+ rv = trans2.Start(&CreateGetPushRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
base::RunLoop().RunUntilIdle();
// The data for the pushed path may be coming in more than 1 frame. Compile
@@ -552,7 +465,7 @@ class SpdyNetworkTransactionTest
// Read the server push body.
std::string result2;
- ReadResult(trans2.get(), &result2);
+ ReadResult(&trans2, &result2);
// Read the response body.
std::string result;
ReadResult(trans, &result);
@@ -567,7 +480,7 @@ class SpdyNetworkTransactionTest
EXPECT_TRUE(load_timing_info.push_end.is_null());
LoadTimingInfo load_timing_info2;
- EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2));
+ EXPECT_TRUE(trans2.GetLoadTimingInfo(&load_timing_info2));
EXPECT_FALSE(load_timing_info2.push_start.is_null());
EXPECT_FALSE(load_timing_info2.push_end.is_null());
@@ -577,10 +490,10 @@ class SpdyNetworkTransactionTest
<< "||||| Expected data: "
<< expected;
- // Verify the SYN_REPLY.
+ // Verify the response HEADERS.
// Copy the response info, because trans goes away.
*response = *trans->GetResponseInfo();
- *push_response = *trans2->GetResponseInfo();
+ *push_response = *trans2.GetResponseInfo();
VerifyStreamsClosed(helper);
}
@@ -593,15 +506,14 @@ class SpdyNetworkTransactionTest
static void StartTransactionCallback(HttpNetworkSession* session,
GURL url,
int result) {
- std::unique_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, session);
TestCompletionCallback callback;
HttpRequestInfo request;
request.method = "GET";
request.url = url;
request.load_flags = 0;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
callback.WaitForResult();
}
@@ -630,70 +542,50 @@ class SpdyNetworkTransactionTest
base::ScopedTempDir temp_dir_;
};
-//-----------------------------------------------------------------------------
-// All tests are run with three different connection types: SPDY after NPN
-// negotiation, SPDY without SSL, and SPDY with SSL.
-//
-// TODO(akalin): Use ::testing::Combine() when we are able to use
-// <tr1/tuple>.
-INSTANTIATE_TEST_CASE_P(
- Spdy,
- SpdyNetworkTransactionTest,
- ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY31, false),
- SpdyNetworkTransactionTestParams(kProtoSPDY31, true),
- SpdyNetworkTransactionTestParams(kProtoHTTP2, false),
- SpdyNetworkTransactionTestParams(kProtoHTTP2, true)));
-
// Verify HttpNetworkTransaction constructor.
-TEST_P(SpdyNetworkTransactionTest, Constructor) {
- std::unique_ptr<SpdySessionDependencies> session_deps(
- CreateSpdySessionDependencies(GetParam()));
+TEST_F(SpdyNetworkTransactionTest, Constructor) {
+ auto session_deps = base::MakeUnique<SpdySessionDependencies>();
std::unique_ptr<HttpNetworkSession> session(
SpdySessionDependencies::SpdyCreateSession(session_deps.get()));
- std::unique_ptr<HttpTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ auto trans =
+ base::MakeUnique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
}
-TEST_P(SpdyNetworkTransactionTest, Get) {
+TEST_F(SpdyNetworkTransactionTest, Get) {
// Construct the request.
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- MockWrite writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite writes[] = {CreateMockWrite(req, 0)};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
MockRead(ASYNC, 0, 3) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
}
-TEST_P(SpdyNetworkTransactionTest, GetAtEachPriority) {
+TEST_F(SpdyNetworkTransactionTest, GetAtEachPriority) {
for (RequestPriority p = MINIMUM_PRIORITY; p <= MAXIMUM_PRIORITY;
p = RequestPriority(p + 1)) {
- SpdyTestUtil spdy_test_util(GetParam().protocol,
- GetParam().priority_to_dependency);
+ SpdyTestUtil spdy_test_util;
// Construct the request.
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, p, true));
- MockWrite writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite writes[] = {CreateMockWrite(req, 0)};
SpdyPriority spdy_prio = 0;
- EXPECT_TRUE(
- GetSpdyPriority(spdy_test_util.spdy_version(), *req, &spdy_prio));
+ EXPECT_TRUE(GetSpdyPriority(req, &spdy_prio));
// this repeats the RequestPriority-->SpdyPriority mapping from
// SpdyFramer::ConvertRequestPriorityToSpdyPriority to make
// sure it's being done right.
@@ -717,13 +609,11 @@ TEST_P(SpdyNetworkTransactionTest, GetAtEachPriority) {
FAIL();
}
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_test_util.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_test_util.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(
+ spdy_test_util.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame body(spdy_test_util.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
MockRead(ASYNC, 0, 3) // EOF
};
@@ -731,11 +621,10 @@ TEST_P(SpdyNetworkTransactionTest, GetAtEachPriority) {
arraysize(writes));
HttpRequestInfo http_req = CreateGetRequest();
- NormalSpdyTransactionHelper helper(http_req, p, BoundNetLog(),
- GetParam(), NULL);
+ NormalSpdyTransactionHelper helper(http_req, p, NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
}
@@ -751,50 +640,36 @@ TEST_P(SpdyNetworkTransactionTest, GetAtEachPriority) {
// TODO(gavinp): create a working generalized TransactionHelper that
// can allow multiple streams in flight.
-TEST_P(SpdyNetworkTransactionTest, ThreeGets) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, ThreeGets) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
- std::unique_ptr<SpdySerializedFrame> fbody(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
-
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
+ SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
+
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(3, false));
- std::unique_ptr<SpdySerializedFrame> fbody2(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
-
- std::unique_ptr<SpdySerializedFrame> req3(
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
+ SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
+
+ SpdySerializedFrame req3(
spdy_util_.ConstructSpdyGet(nullptr, 0, 5, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp3(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
- std::unique_ptr<SpdySerializedFrame> body3(
- spdy_util_.ConstructSpdyBodyFrame(5, false));
- std::unique_ptr<SpdySerializedFrame> fbody3(
- spdy_util_.ConstructSpdyBodyFrame(5, true));
+ SpdySerializedFrame resp3(spdy_util_.ConstructSpdyGetReply(NULL, 0, 5));
+ SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, false));
+ SpdySerializedFrame fbody3(spdy_util_.ConstructSpdyDataFrame(5, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
- CreateMockWrite(*req2, 3),
- CreateMockWrite(*req3, 6),
+ CreateMockWrite(req, 0), CreateMockWrite(req2, 3),
+ CreateMockWrite(req3, 6),
};
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
- CreateMockRead(*resp2, 4),
- CreateMockRead(*body2, 5),
- CreateMockRead(*resp3, 7),
- CreateMockRead(*body3, 8),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
+ CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
+ CreateMockRead(resp3, 7), CreateMockRead(body3, 8),
- CreateMockRead(*fbody, 9),
- CreateMockRead(*fbody2, 10),
- CreateMockRead(*fbody3, 11),
+ CreateMockRead(fbody, 9), CreateMockRead(fbody2, 10),
+ CreateMockRead(fbody3, 11),
MockRead(ASYNC, 0, 12), // EOF
};
@@ -802,10 +677,10 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGets) {
SequencedSocketData data_placeholder1(NULL, 0, NULL, 0);
SequencedSocketData data_placeholder2(NULL, 0, NULL, 0);
- BoundNetLog log;
+ NetLogWithSource log;
TransactionHelperResult out;
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
// We require placeholder data because three get requests are sent out at
@@ -813,12 +688,9 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGets) {
// on will negotiate SPDY and will be used for all requests.
helper.AddData(&data_placeholder1);
helper.AddData(&data_placeholder2);
- std::unique_ptr<HttpNetworkTransaction> trans1(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
- std::unique_ptr<HttpNetworkTransaction> trans2(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
- std::unique_ptr<HttpNetworkTransaction> trans3(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
+ HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
+ HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
+ HttpNetworkTransaction trans3(DEFAULT_PRIORITY, helper.session());
TestCompletionCallback callback1;
TestCompletionCallback callback2;
@@ -828,64 +700,55 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGets) {
HttpRequestInfo httpreq2 = CreateGetRequest();
HttpRequestInfo httpreq3 = CreateGetRequest();
- out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
- out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
- out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
+ out.rv = trans1.Start(&httpreq1, callback1.callback(), log);
+ ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
+ out.rv = trans2.Start(&httpreq2, callback2.callback(), log);
+ ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
+ out.rv = trans3.Start(&httpreq3, callback3.callback(), log);
+ ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
out.rv = callback1.WaitForResult();
- ASSERT_EQ(OK, out.rv);
+ ASSERT_THAT(out.rv, IsOk());
out.rv = callback3.WaitForResult();
- ASSERT_EQ(OK, out.rv);
+ ASSERT_THAT(out.rv, IsOk());
- const HttpResponseInfo* response1 = trans1->GetResponseInfo();
+ const HttpResponseInfo* response1 = trans1.GetResponseInfo();
EXPECT_TRUE(response1->headers);
EXPECT_TRUE(response1->was_fetched_via_spdy);
out.status_line = response1->headers->GetStatusLine();
out.response_info = *response1;
- trans2->GetResponseInfo();
+ trans2.GetResponseInfo();
- out.rv = ReadTransaction(trans1.get(), &out.response_data);
+ out.rv = ReadTransaction(&trans1, &out.response_data);
helper.VerifyDataConsumed();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!hello!", out.response_data);
}
-TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBinding) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, TwoGetsLateBinding) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
- std::unique_ptr<SpdySerializedFrame> fbody(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
-
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
+ SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
+
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(3, false));
- std::unique_ptr<SpdySerializedFrame> fbody2(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
+ SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*req2, 3),
+ CreateMockWrite(req, 0), CreateMockWrite(req2, 3),
};
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
- CreateMockRead(*resp2, 4),
- CreateMockRead(*body2, 5),
- CreateMockRead(*fbody, 6),
- CreateMockRead(*fbody2, 7),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
+ CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
+ CreateMockRead(fbody, 6), CreateMockRead(fbody2, 7),
MockRead(ASYNC, 0, 8), // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
@@ -894,20 +757,18 @@ TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBinding) {
SequencedSocketData data_placeholder(NULL, 0, NULL, 0);
data_placeholder.set_connect_data(never_finishing_connect);
- BoundNetLog log;
+ NetLogWithSource log;
TransactionHelperResult out;
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
// We require placeholder data because two requests are sent out at
// the same time which results in two sockets being connected. The first
// on will negotiate SPDY and will be used for all requests.
helper.AddData(&data_placeholder);
- std::unique_ptr<HttpNetworkTransaction> trans1(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
- std::unique_ptr<HttpNetworkTransaction> trans2(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
+ HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
+ HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
TestCompletionCallback callback1;
TestCompletionCallback callback2;
@@ -915,68 +776,59 @@ TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBinding) {
HttpRequestInfo httpreq1 = CreateGetRequest();
HttpRequestInfo httpreq2 = CreateGetRequest();
- out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
- out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
+ out.rv = trans1.Start(&httpreq1, callback1.callback(), log);
+ ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
+ out.rv = trans2.Start(&httpreq2, callback2.callback(), log);
+ ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
out.rv = callback1.WaitForResult();
- ASSERT_EQ(OK, out.rv);
+ ASSERT_THAT(out.rv, IsOk());
out.rv = callback2.WaitForResult();
- ASSERT_EQ(OK, out.rv);
+ ASSERT_THAT(out.rv, IsOk());
- const HttpResponseInfo* response1 = trans1->GetResponseInfo();
+ const HttpResponseInfo* response1 = trans1.GetResponseInfo();
EXPECT_TRUE(response1->headers);
EXPECT_TRUE(response1->was_fetched_via_spdy);
out.status_line = response1->headers->GetStatusLine();
out.response_info = *response1;
- out.rv = ReadTransaction(trans1.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
+ out.rv = ReadTransaction(&trans1, &out.response_data);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!hello!", out.response_data);
- const HttpResponseInfo* response2 = trans2->GetResponseInfo();
+ const HttpResponseInfo* response2 = trans2.GetResponseInfo();
EXPECT_TRUE(response2->headers);
EXPECT_TRUE(response2->was_fetched_via_spdy);
out.status_line = response2->headers->GetStatusLine();
out.response_info = *response2;
- out.rv = ReadTransaction(trans2.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
+ out.rv = ReadTransaction(&trans2, &out.response_data);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!hello!", out.response_data);
helper.VerifyDataConsumed();
}
-TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
- std::unique_ptr<SpdySerializedFrame> fbody(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
-
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
+ SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
+
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(3, false));
- std::unique_ptr<SpdySerializedFrame> fbody2(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
+ SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*req2, 3),
+ CreateMockWrite(req, 0), CreateMockWrite(req2, 3),
};
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
- CreateMockRead(*resp2, 4),
- CreateMockRead(*body2, 5),
- CreateMockRead(*fbody, 6),
- CreateMockRead(*fbody2, 7),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
+ CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
+ CreateMockRead(fbody, 6), CreateMockRead(fbody2, 7),
MockRead(ASYNC, 0, 8), // EOF
};
SequencedSocketData preconnect_data(reads, arraysize(reads), writes,
@@ -987,10 +839,10 @@ TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) {
SequencedSocketData data_placeholder(NULL, 0, NULL, 0);
data_placeholder.set_connect_data(never_finishing_connect);
- BoundNetLog log;
+ NetLogWithSource log;
TransactionHelperResult out;
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&preconnect_data);
// We require placeholder data because 3 connections are attempted (first is
@@ -998,10 +850,8 @@ TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) {
helper.AddData(&data_placeholder);
helper.AddData(&data_placeholder);
- std::unique_ptr<HttpNetworkTransaction> trans1(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
- std::unique_ptr<HttpNetworkTransaction> trans2(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
+ HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
+ HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
TestCompletionCallback callback1;
TestCompletionCallback callback2;
@@ -1014,33 +864,33 @@ TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) {
http_stream_factory->PreconnectStreams(1, httpreq);
- out.rv = trans1->Start(&httpreq, callback1.callback(), log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
- out.rv = trans2->Start(&httpreq, callback2.callback(), log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
+ out.rv = trans1.Start(&httpreq, callback1.callback(), log);
+ ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
+ out.rv = trans2.Start(&httpreq, callback2.callback(), log);
+ ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
out.rv = callback1.WaitForResult();
- ASSERT_EQ(OK, out.rv);
+ ASSERT_THAT(out.rv, IsOk());
out.rv = callback2.WaitForResult();
- ASSERT_EQ(OK, out.rv);
+ ASSERT_THAT(out.rv, IsOk());
- const HttpResponseInfo* response1 = trans1->GetResponseInfo();
+ const HttpResponseInfo* response1 = trans1.GetResponseInfo();
EXPECT_TRUE(response1->headers);
EXPECT_TRUE(response1->was_fetched_via_spdy);
out.status_line = response1->headers->GetStatusLine();
out.response_info = *response1;
- out.rv = ReadTransaction(trans1.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
+ out.rv = ReadTransaction(&trans1, &out.response_data);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!hello!", out.response_data);
- const HttpResponseInfo* response2 = trans2->GetResponseInfo();
+ const HttpResponseInfo* response2 = trans2.GetResponseInfo();
EXPECT_TRUE(response2->headers);
EXPECT_TRUE(response2->was_fetched_via_spdy);
out.status_line = response2->headers->GetStatusLine();
out.response_info = *response2;
- out.rv = ReadTransaction(trans2.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
+ out.rv = ReadTransaction(&trans2, &out.response_data);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!hello!", out.response_data);
@@ -1052,84 +902,69 @@ TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) {
// the first transaction completion, and sets a maximum concurrent
// stream limit of 1. This means that our IO loop exists after the
// second transaction completes, so we can assert on read_index().
-TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
+TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
// Construct the request.
// Each request fully completes before the next starts.
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
- std::unique_ptr<SpdySerializedFrame> fbody(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
+ SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
spdy_util_.UpdateWithStreamDestruction(1);
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(3, false));
- std::unique_ptr<SpdySerializedFrame> fbody2(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
+ SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
spdy_util_.UpdateWithStreamDestruction(3);
- std::unique_ptr<SpdySerializedFrame> req3(
+ SpdySerializedFrame req3(
spdy_util_.ConstructSpdyGet(nullptr, 0, 5, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp3(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
- std::unique_ptr<SpdySerializedFrame> body3(
- spdy_util_.ConstructSpdyBodyFrame(5, false));
- std::unique_ptr<SpdySerializedFrame> fbody3(
- spdy_util_.ConstructSpdyBodyFrame(5, true));
+ SpdySerializedFrame resp3(spdy_util_.ConstructSpdyGetReply(NULL, 0, 5));
+ SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, false));
+ SpdySerializedFrame fbody3(spdy_util_.ConstructSpdyDataFrame(5, true));
SettingsMap settings;
const uint32_t max_concurrent_streams = 1;
settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
- std::unique_ptr<SpdySerializedFrame> settings_frame(
+ SpdySerializedFrame settings_frame(
spdy_util_.ConstructSpdySettings(settings));
- std::unique_ptr<SpdySerializedFrame> settings_ack(
- spdy_util_.ConstructSpdySettingsAck());
+ SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
- CreateMockWrite(*settings_ack, 5),
- CreateMockWrite(*req2, 6),
- CreateMockWrite(*req3, 10),
+ CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
+ CreateMockWrite(req2, 6), CreateMockWrite(req3, 10),
};
MockRead reads[] = {
- CreateMockRead(*settings_frame, 1),
- CreateMockRead(*resp, 2),
- CreateMockRead(*body, 3),
- CreateMockRead(*fbody, 4),
- CreateMockRead(*resp2, 7),
- CreateMockRead(*body2, 8),
- CreateMockRead(*fbody2, 9),
- CreateMockRead(*resp3, 11),
- CreateMockRead(*body3, 12),
- CreateMockRead(*fbody3, 13),
+ CreateMockRead(settings_frame, 1),
+ CreateMockRead(resp, 2),
+ CreateMockRead(body, 3),
+ CreateMockRead(fbody, 4),
+ CreateMockRead(resp2, 7),
+ CreateMockRead(body2, 8),
+ CreateMockRead(fbody2, 9),
+ CreateMockRead(resp3, 11),
+ CreateMockRead(body3, 12),
+ CreateMockRead(fbody3, 13),
MockRead(ASYNC, 0, 14), // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- BoundNetLog log;
+ NetLogWithSource log;
TransactionHelperResult out;
{
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
- std::unique_ptr<HttpNetworkTransaction> trans1(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
- std::unique_ptr<HttpNetworkTransaction> trans2(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
- std::unique_ptr<HttpNetworkTransaction> trans3(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
+ HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
+ HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
+ HttpNetworkTransaction trans3(DEFAULT_PRIORITY, helper.session());
TestCompletionCallback callback1;
TestCompletionCallback callback2;
@@ -1139,53 +974,53 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
HttpRequestInfo httpreq2 = CreateGetRequest();
HttpRequestInfo httpreq3 = CreateGetRequest();
- out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
+ out.rv = trans1.Start(&httpreq1, callback1.callback(), log);
ASSERT_EQ(out.rv, ERR_IO_PENDING);
// Run transaction 1 through quickly to force a read of our SETTINGS
// frame.
out.rv = callback1.WaitForResult();
- ASSERT_EQ(OK, out.rv);
+ ASSERT_THAT(out.rv, IsOk());
- out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
+ out.rv = trans2.Start(&httpreq2, callback2.callback(), log);
ASSERT_EQ(out.rv, ERR_IO_PENDING);
- out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
+ out.rv = trans3.Start(&httpreq3, callback3.callback(), log);
ASSERT_EQ(out.rv, ERR_IO_PENDING);
out.rv = callback2.WaitForResult();
- ASSERT_EQ(OK, out.rv);
+ ASSERT_THAT(out.rv, IsOk());
out.rv = callback3.WaitForResult();
- ASSERT_EQ(OK, out.rv);
+ ASSERT_THAT(out.rv, IsOk());
- const HttpResponseInfo* response1 = trans1->GetResponseInfo();
+ const HttpResponseInfo* response1 = trans1.GetResponseInfo();
ASSERT_TRUE(response1);
EXPECT_TRUE(response1->headers);
EXPECT_TRUE(response1->was_fetched_via_spdy);
out.status_line = response1->headers->GetStatusLine();
out.response_info = *response1;
- out.rv = ReadTransaction(trans1.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
+ out.rv = ReadTransaction(&trans1, &out.response_data);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!hello!", out.response_data);
- const HttpResponseInfo* response2 = trans2->GetResponseInfo();
+ const HttpResponseInfo* response2 = trans2.GetResponseInfo();
out.status_line = response2->headers->GetStatusLine();
out.response_info = *response2;
- out.rv = ReadTransaction(trans2.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
+ out.rv = ReadTransaction(&trans2, &out.response_data);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!hello!", out.response_data);
- const HttpResponseInfo* response3 = trans3->GetResponseInfo();
+ const HttpResponseInfo* response3 = trans3.GetResponseInfo();
out.status_line = response3->headers->GetStatusLine();
out.response_info = *response3;
- out.rv = ReadTransaction(trans3.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
+ out.rv = ReadTransaction(&trans3, &out.response_data);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!hello!", out.response_data);
helper.VerifyDataConsumed();
}
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
}
// Similar to ThreeGetsWithMaxConcurrent above, however this test adds
@@ -1193,95 +1028,78 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
// different data ("hello!" vs "hello!hello!") and because of the
// user specified priority, we expect to see them inverted in
// the response from the server.
-TEST_P(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
+TEST_F(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
// Construct the request.
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
- std::unique_ptr<SpdySerializedFrame> fbody(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
+ SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
spdy_util_.UpdateWithStreamDestruction(1);
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(3, false));
- std::unique_ptr<SpdySerializedFrame> fbody2(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
+ SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
spdy_util_.UpdateWithStreamDestruction(3);
- std::unique_ptr<SpdySerializedFrame> req4(
+ SpdySerializedFrame req4(
spdy_util_.ConstructSpdyGet(nullptr, 0, 5, HIGHEST, true));
- std::unique_ptr<SpdySerializedFrame> resp4(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
- std::unique_ptr<SpdySerializedFrame> fbody4(
- spdy_util_.ConstructSpdyBodyFrame(5, true));
+ SpdySerializedFrame resp4(spdy_util_.ConstructSpdyGetReply(NULL, 0, 5));
+ SpdySerializedFrame fbody4(spdy_util_.ConstructSpdyDataFrame(5, true));
spdy_util_.UpdateWithStreamDestruction(5);
- std::unique_ptr<SpdySerializedFrame> req3(
+ SpdySerializedFrame req3(
spdy_util_.ConstructSpdyGet(nullptr, 0, 7, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp3(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 7));
- std::unique_ptr<SpdySerializedFrame> body3(
- spdy_util_.ConstructSpdyBodyFrame(7, false));
- std::unique_ptr<SpdySerializedFrame> fbody3(
- spdy_util_.ConstructSpdyBodyFrame(7, true));
+ SpdySerializedFrame resp3(spdy_util_.ConstructSpdyGetReply(NULL, 0, 7));
+ SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(7, false));
+ SpdySerializedFrame fbody3(spdy_util_.ConstructSpdyDataFrame(7, true));
SettingsMap settings;
const uint32_t max_concurrent_streams = 1;
settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
- std::unique_ptr<SpdySerializedFrame> settings_frame(
+ SpdySerializedFrame settings_frame(
spdy_util_.ConstructSpdySettings(settings));
- std::unique_ptr<SpdySerializedFrame> settings_ack(
- spdy_util_.ConstructSpdySettingsAck());
+ SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
- CreateMockWrite(*settings_ack, 5),
+ CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
// By making these synchronous, it guarantees that they are not *started*
// before their sequence number, which in turn verifies that only a single
// request is in-flight at a time.
- CreateMockWrite(*req2, 6, SYNCHRONOUS),
- CreateMockWrite(*req4, 10, SYNCHRONOUS),
- CreateMockWrite(*req3, 13, SYNCHRONOUS),
+ CreateMockWrite(req2, 6, SYNCHRONOUS),
+ CreateMockWrite(req4, 10, SYNCHRONOUS),
+ CreateMockWrite(req3, 13, SYNCHRONOUS),
};
MockRead reads[] = {
- CreateMockRead(*settings_frame, 1),
- CreateMockRead(*resp, 2),
- CreateMockRead(*body, 3),
- CreateMockRead(*fbody, 4),
- CreateMockRead(*resp2, 7),
- CreateMockRead(*body2, 8),
- CreateMockRead(*fbody2, 9),
- CreateMockRead(*resp4, 11),
- CreateMockRead(*fbody4, 12),
- CreateMockRead(*resp3, 14),
- CreateMockRead(*body3, 15),
- CreateMockRead(*fbody3, 16),
+ CreateMockRead(settings_frame, 1),
+ CreateMockRead(resp, 2),
+ CreateMockRead(body, 3),
+ CreateMockRead(fbody, 4),
+ CreateMockRead(resp2, 7),
+ CreateMockRead(body2, 8),
+ CreateMockRead(fbody2, 9),
+ CreateMockRead(resp4, 11),
+ CreateMockRead(fbody4, 12),
+ CreateMockRead(resp3, 14),
+ CreateMockRead(body3, 15),
+ CreateMockRead(fbody3, 16),
MockRead(ASYNC, 0, 17), // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- BoundNetLog log;
+ NetLogWithSource log;
TransactionHelperResult out;
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
- std::unique_ptr<HttpNetworkTransaction> trans1(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
- std::unique_ptr<HttpNetworkTransaction> trans2(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
- std::unique_ptr<HttpNetworkTransaction> trans3(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
- std::unique_ptr<HttpNetworkTransaction> trans4(
- new HttpNetworkTransaction(HIGHEST, helper.session()));
+ HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
+ HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
+ HttpNetworkTransaction trans3(DEFAULT_PRIORITY, helper.session());
+ HttpNetworkTransaction trans4(HIGHEST, helper.session());
TestCompletionCallback callback1;
TestCompletionCallback callback2;
@@ -1293,122 +1111,110 @@ TEST_P(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
HttpRequestInfo httpreq3 = CreateGetRequest();
HttpRequestInfo httpreq4 = CreateGetRequest();
- out.rv = trans1->Start(&httpreq1, callback1.callback(), log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
+ out.rv = trans1.Start(&httpreq1, callback1.callback(), log);
+ ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
// Run transaction 1 through quickly to force a read of our SETTINGS frame.
out.rv = callback1.WaitForResult();
- ASSERT_EQ(OK, out.rv);
+ ASSERT_THAT(out.rv, IsOk());
- out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
- out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
- out.rv = trans4->Start(&httpreq4, callback4.callback(), log);
- ASSERT_EQ(ERR_IO_PENDING, out.rv);
+ out.rv = trans2.Start(&httpreq2, callback2.callback(), log);
+ ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
+ out.rv = trans3.Start(&httpreq3, callback3.callback(), log);
+ ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
+ out.rv = trans4.Start(&httpreq4, callback4.callback(), log);
+ ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
out.rv = callback2.WaitForResult();
- ASSERT_EQ(OK, out.rv);
+ ASSERT_THAT(out.rv, IsOk());
out.rv = callback3.WaitForResult();
- ASSERT_EQ(OK, out.rv);
+ ASSERT_THAT(out.rv, IsOk());
- const HttpResponseInfo* response1 = trans1->GetResponseInfo();
+ const HttpResponseInfo* response1 = trans1.GetResponseInfo();
EXPECT_TRUE(response1->headers);
EXPECT_TRUE(response1->was_fetched_via_spdy);
out.status_line = response1->headers->GetStatusLine();
out.response_info = *response1;
- out.rv = ReadTransaction(trans1.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
+ out.rv = ReadTransaction(&trans1, &out.response_data);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!hello!", out.response_data);
- const HttpResponseInfo* response2 = trans2->GetResponseInfo();
+ const HttpResponseInfo* response2 = trans2.GetResponseInfo();
out.status_line = response2->headers->GetStatusLine();
out.response_info = *response2;
- out.rv = ReadTransaction(trans2.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
+ out.rv = ReadTransaction(&trans2, &out.response_data);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!hello!", out.response_data);
// notice: response3 gets two hellos, response4 gets one
// hello, so we know dequeuing priority was respected.
- const HttpResponseInfo* response3 = trans3->GetResponseInfo();
+ const HttpResponseInfo* response3 = trans3.GetResponseInfo();
out.status_line = response3->headers->GetStatusLine();
out.response_info = *response3;
- out.rv = ReadTransaction(trans3.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
+ out.rv = ReadTransaction(&trans3, &out.response_data);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!hello!", out.response_data);
out.rv = callback4.WaitForResult();
- EXPECT_EQ(OK, out.rv);
- const HttpResponseInfo* response4 = trans4->GetResponseInfo();
+ EXPECT_THAT(out.rv, IsOk());
+ const HttpResponseInfo* response4 = trans4.GetResponseInfo();
out.status_line = response4->headers->GetStatusLine();
out.response_info = *response4;
- out.rv = ReadTransaction(trans4.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
+ out.rv = ReadTransaction(&trans4, &out.response_data);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
helper.VerifyDataConsumed();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
}
// Similar to ThreeGetsMaxConcurrrent above, however, this test
// deletes a session in the middle of the transaction to ensure
// that we properly remove pendingcreatestream objects from
// the spdy_session
-TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
+TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
// Construct the request.
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
- std::unique_ptr<SpdySerializedFrame> fbody(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
+ SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
spdy_util_.UpdateWithStreamDestruction(1);
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(3, false));
- std::unique_ptr<SpdySerializedFrame> fbody2(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
+ SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
SettingsMap settings;
const uint32_t max_concurrent_streams = 1;
settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
- std::unique_ptr<SpdySerializedFrame> settings_frame(
+ SpdySerializedFrame settings_frame(
spdy_util_.ConstructSpdySettings(settings));
- std::unique_ptr<SpdySerializedFrame> settings_ack(
- spdy_util_.ConstructSpdySettingsAck());
+ SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
- CreateMockWrite(*settings_ack, 5),
- CreateMockWrite(*req2, 6),
+ CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
+ CreateMockWrite(req2, 6),
};
MockRead reads[] = {
- CreateMockRead(*settings_frame, 1),
- CreateMockRead(*resp, 2),
- CreateMockRead(*body, 3),
- CreateMockRead(*fbody, 4),
- CreateMockRead(*resp2, 7),
- CreateMockRead(*body2, 8),
- CreateMockRead(*fbody2, 9),
- MockRead(ASYNC, 0, 10), // EOF
+ CreateMockRead(settings_frame, 1), CreateMockRead(resp, 2),
+ CreateMockRead(body, 3), CreateMockRead(fbody, 4),
+ CreateMockRead(resp2, 7), CreateMockRead(body2, 8),
+ CreateMockRead(fbody2, 9), MockRead(ASYNC, 0, 10), // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- BoundNetLog log;
+ NetLogWithSource log;
TransactionHelperResult out;
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
std::unique_ptr<HttpNetworkTransaction> trans1(
@@ -1430,7 +1236,7 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
ASSERT_EQ(out.rv, ERR_IO_PENDING);
// Run transaction 1 through quickly to force a read of our SETTINGS frame.
out.rv = callback1.WaitForResult();
- ASSERT_EQ(OK, out.rv);
+ ASSERT_THAT(out.rv, IsOk());
out.rv = trans2->Start(&httpreq2, callback2.callback(), log);
ASSERT_EQ(out.rv, ERR_IO_PENDING);
@@ -1438,7 +1244,7 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
trans3.reset();
ASSERT_EQ(out.rv, ERR_IO_PENDING);
out.rv = callback2.WaitForResult();
- ASSERT_EQ(OK, out.rv);
+ ASSERT_THAT(out.rv, IsOk());
const HttpResponseInfo* response1 = trans1->GetResponseInfo();
ASSERT_TRUE(response1);
@@ -1447,7 +1253,7 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
out.status_line = response1->headers->GetStatusLine();
out.response_info = *response1;
out.rv = ReadTransaction(trans1.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!hello!", out.response_data);
@@ -1456,11 +1262,11 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
out.status_line = response2->headers->GetStatusLine();
out.response_info = *response2;
out.rv = ReadTransaction(trans2.get(), &out.response_data);
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!hello!", out.response_data);
helper.VerifyDataConsumed();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
}
namespace {
@@ -1496,53 +1302,47 @@ class KillerCallback : public TestCompletionCallbackBase {
// Similar to ThreeGetsMaxConcurrrentDelete above, however, this test
// closes the socket while we have a pending transaction waiting for
// a pending stream creation. http://crbug.com/52901
-TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) {
+TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) {
// Construct the request.
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
- std::unique_ptr<SpdySerializedFrame> fin_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
+ SpdySerializedFrame fin_body(spdy_util_.ConstructSpdyDataFrame(1, true));
spdy_util_.UpdateWithStreamDestruction(1);
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
SettingsMap settings;
const uint32_t max_concurrent_streams = 1;
settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
- std::unique_ptr<SpdySerializedFrame> settings_frame(
+ SpdySerializedFrame settings_frame(
spdy_util_.ConstructSpdySettings(settings));
- std::unique_ptr<SpdySerializedFrame> settings_ack(
- spdy_util_.ConstructSpdySettingsAck());
+ SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
- CreateMockWrite(*settings_ack, 5),
- CreateMockWrite(*req2, 6),
+ CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
+ CreateMockWrite(req2, 6),
};
MockRead reads[] = {
- CreateMockRead(*settings_frame, 1),
- CreateMockRead(*resp, 2),
- CreateMockRead(*body, 3),
- CreateMockRead(*fin_body, 4),
- CreateMockRead(*resp2, 7),
+ CreateMockRead(settings_frame, 1),
+ CreateMockRead(resp, 2),
+ CreateMockRead(body, 3),
+ CreateMockRead(fin_body, 4),
+ CreateMockRead(resp2, 7),
MockRead(ASYNC, ERR_CONNECTION_RESET, 8), // Abort!
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
SequencedSocketData data_placeholder(NULL, 0, NULL, 0);
- BoundNetLog log;
+ NetLogWithSource log;
TransactionHelperResult out;
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
// We require placeholder data because three get requests are sent out, so
@@ -1566,14 +1366,14 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) {
ASSERT_EQ(out.rv, ERR_IO_PENDING);
// Run transaction 1 through quickly to force a read of our SETTINGS frame.
out.rv = callback1.WaitForResult();
- ASSERT_EQ(OK, out.rv);
+ ASSERT_THAT(out.rv, IsOk());
out.rv = trans2.Start(&httpreq2, callback2.callback(), log);
ASSERT_EQ(out.rv, ERR_IO_PENDING);
out.rv = trans3->Start(&httpreq3, callback3.callback(), log);
ASSERT_EQ(out.rv, ERR_IO_PENDING);
out.rv = callback3.WaitForResult();
- ASSERT_EQ(ERR_ABORTED, out.rv);
+ ASSERT_THAT(out.rv, IsError(ERR_ABORTED));
const HttpResponseInfo* response1 = trans1.GetResponseInfo();
ASSERT_TRUE(response1);
@@ -1582,20 +1382,20 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) {
out.status_line = response1->headers->GetStatusLine();
out.response_info = *response1;
out.rv = ReadTransaction(&trans1, &out.response_data);
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
const HttpResponseInfo* response2 = trans2.GetResponseInfo();
ASSERT_TRUE(response2);
out.status_line = response2->headers->GetStatusLine();
out.response_info = *response2;
out.rv = ReadTransaction(&trans2, &out.response_data);
- EXPECT_EQ(ERR_CONNECTION_RESET, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_CONNECTION_RESET));
helper.VerifyDataConsumed();
}
// Test that a simple PUT request works.
-TEST_P(SpdyNetworkTransactionTest, Put) {
+TEST_F(SpdyNetworkTransactionTest, Put) {
// Setup the request
HttpRequestInfo request;
request.method = "PUT";
@@ -1603,34 +1403,31 @@ TEST_P(SpdyNetworkTransactionTest, Put) {
SpdyHeaderBlock put_headers(
spdy_util_.ConstructPutHeaderBlock(kDefaultUrl, 0));
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdySyn(1, std::move(put_headers), LOWEST, true));
+ SpdySerializedFrame req(
+ spdy_util_.ConstructSpdyHeaders(1, std::move(put_headers), LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
+ CreateMockWrite(req, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
MockRead(ASYNC, 0, 3) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
}
// Test that a simple HEAD request works.
-TEST_P(SpdyNetworkTransactionTest, Head) {
+TEST_F(SpdyNetworkTransactionTest, Head) {
// Setup the request
HttpRequestInfo request;
request.method = "HEAD";
@@ -1638,90 +1435,81 @@ TEST_P(SpdyNetworkTransactionTest, Head) {
SpdyHeaderBlock head_headers(
spdy_util_.ConstructHeadHeaderBlock(kDefaultUrl, 0));
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdySyn(1, std::move(head_headers), LOWEST, true));
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyHeaders(
+ 1, std::move(head_headers), LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
+ CreateMockWrite(req, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
MockRead(ASYNC, 0, 3) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
}
// Test that a simple POST works.
-TEST_P(SpdyNetworkTransactionTest, Post) {
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+TEST_F(SpdyNetworkTransactionTest, Post) {
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kUploadDataSize, LOWEST, NULL, 0));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*body, 1), // POST upload frame
+ CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(NULL, 0));
MockRead reads[] = {
- CreateMockRead(*resp, 2),
- CreateMockRead(*body, 3),
+ CreateMockRead(resp, 2), CreateMockRead(body, 3),
MockRead(ASYNC, 0, 4) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreatePostRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
}
// Test that a POST with a file works.
-TEST_P(SpdyNetworkTransactionTest, FilePost) {
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+TEST_F(SpdyNetworkTransactionTest, FilePost) {
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kUploadDataSize, LOWEST, NULL, 0));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*body, 1), // POST upload frame
+ CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(NULL, 0));
MockRead reads[] = {
- CreateMockRead(*resp, 2),
- CreateMockRead(*body, 3),
+ CreateMockRead(resp, 2), CreateMockRead(body, 3),
MockRead(ASYNC, 0, 4) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateFilePostRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
}
// Test that a POST with a unreadable file fails.
-TEST_P(SpdyNetworkTransactionTest, UnreadableFilePost) {
+TEST_F(SpdyNetworkTransactionTest, UnreadableFilePost) {
MockWrite writes[] = {
MockWrite(ASYNC, 0, 0) // EOF
};
@@ -1731,68 +1519,59 @@ TEST_P(SpdyNetworkTransactionTest, UnreadableFilePost) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateUnreadableFilePostRequest(),
- DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ DEFAULT_PRIORITY, NetLogWithSource(),
+ NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
helper.RunDefaultTest();
base::RunLoop().RunUntilIdle();
helper.VerifyDataNotConsumed();
- EXPECT_EQ(ERR_ACCESS_DENIED, helper.output().rv);
+ EXPECT_THAT(helper.output().rv, IsError(ERR_ACCESS_DENIED));
}
// Test that a complex POST works.
-TEST_P(SpdyNetworkTransactionTest, ComplexPost) {
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+TEST_F(SpdyNetworkTransactionTest, ComplexPost) {
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kUploadDataSize, LOWEST, NULL, 0));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*body, 1), // POST upload frame
+ CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(NULL, 0));
MockRead reads[] = {
- CreateMockRead(*resp, 2),
- CreateMockRead(*body, 3),
+ CreateMockRead(resp, 2), CreateMockRead(body, 3),
MockRead(ASYNC, 0, 4) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- NormalSpdyTransactionHelper helper(CreateComplexPostRequest(),
- DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NormalSpdyTransactionHelper helper(
+ CreateComplexPostRequest(), DEFAULT_PRIORITY, NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
}
// Test that a chunked POST works.
-TEST_P(SpdyNetworkTransactionTest, ChunkedPost) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+TEST_F(SpdyNetworkTransactionTest, ChunkedPost) {
+ SpdySerializedFrame req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*body, 1),
+ CreateMockWrite(req, 0), CreateMockWrite(body, 1),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(NULL, 0));
MockRead reads[] = {
- CreateMockRead(*resp, 2),
- CreateMockRead(*body, 3),
+ CreateMockRead(resp, 2), CreateMockRead(body, 3),
MockRead(ASYNC, 0, 4) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(),
- DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NormalSpdyTransactionHelper helper(
+ CreateChunkedPostRequest(), DEFAULT_PRIORITY, NetLogWithSource(), NULL);
// These chunks get merged into a single frame when being sent.
const int kFirstChunkSize = kUploadDataSize/2;
@@ -1802,42 +1581,32 @@ TEST_P(SpdyNetworkTransactionTest, ChunkedPost) {
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ(kUploadData, out.response_data);
}
// Test that a chunked POST works with chunks appended after transaction starts.
-TEST_P(SpdyNetworkTransactionTest, DelayedChunkedPost) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
- std::unique_ptr<SpdySerializedFrame> chunk1(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
- std::unique_ptr<SpdySerializedFrame> chunk2(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
- std::unique_ptr<SpdySerializedFrame> chunk3(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+TEST_F(SpdyNetworkTransactionTest, DelayedChunkedPost) {
+ SpdySerializedFrame req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
+ SpdySerializedFrame chunk1(spdy_util_.ConstructSpdyDataFrame(1, false));
+ SpdySerializedFrame chunk2(spdy_util_.ConstructSpdyDataFrame(1, false));
+ SpdySerializedFrame chunk3(spdy_util_.ConstructSpdyDataFrame(1, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
- CreateMockWrite(*chunk1, 1),
- CreateMockWrite(*chunk2, 2),
- CreateMockWrite(*chunk3, 3),
+ CreateMockWrite(req, 0), CreateMockWrite(chunk1, 1),
+ CreateMockWrite(chunk2, 2), CreateMockWrite(chunk3, 3),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(NULL, 0));
MockRead reads[] = {
- CreateMockRead(*resp, 4),
- CreateMockRead(*chunk1, 5),
- CreateMockRead(*chunk2, 6),
- CreateMockRead(*chunk3, 7),
+ CreateMockRead(resp, 4), CreateMockRead(chunk1, 5),
+ CreateMockRead(chunk2, 6), CreateMockRead(chunk3, 7),
MockRead(ASYNC, 0, 8) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(),
- DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NormalSpdyTransactionHelper helper(
+ CreateChunkedPostRequest(), DEFAULT_PRIORITY, NetLogWithSource(), NULL);
upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, false);
@@ -1859,14 +1628,13 @@ TEST_P(SpdyNetworkTransactionTest, DelayedChunkedPost) {
expected_response += kUploadData;
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ(expected_response, out.response_data);
}
// Test that a POST without any post data works.
-TEST_P(SpdyNetworkTransactionTest, NullPost) {
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
+TEST_F(SpdyNetworkTransactionTest, NullPost) {
// Setup the request
HttpRequestInfo request;
request.method = "POST";
@@ -1878,37 +1646,33 @@ TEST_P(SpdyNetworkTransactionTest, NullPost) {
// expected to be 0.
SpdyHeaderBlock req_block(
spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdySyn(1, std::move(req_block), LOWEST, true));
+ SpdySerializedFrame req(
+ spdy_util_.ConstructSpdyHeaders(1, std::move(req_block), LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
+ CreateMockWrite(req, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(NULL, 0));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
MockRead(ASYNC, 0, 3) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
}
// Test that a simple POST works.
-TEST_P(SpdyNetworkTransactionTest, EmptyPost) {
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
+TEST_F(SpdyNetworkTransactionTest, EmptyPost) {
// Create an empty UploadDataStream.
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
ElementsUploadDataStream stream(std::move(element_readers), 0);
@@ -1923,58 +1687,49 @@ TEST_P(SpdyNetworkTransactionTest, EmptyPost) {
SpdyHeaderBlock req_block(
spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kContentLength));
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdySyn(1, std::move(req_block), LOWEST, true));
+ SpdySerializedFrame req(
+ spdy_util_.ConstructSpdyHeaders(1, std::move(req_block), LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
+ CreateMockWrite(req, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(NULL, 0));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
MockRead(ASYNC, 0, 3) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
}
// While we're doing a post, the server sends the reply before upload completes.
-TEST_P(SpdyNetworkTransactionTest, ResponseBeforePostCompletes) {
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+TEST_F(SpdyNetworkTransactionTest, ResponseBeforePostCompletes) {
+ SpdySerializedFrame req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
- CreateMockWrite(*body, 3),
+ CreateMockWrite(req, 0), CreateMockWrite(body, 3),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(NULL, 0));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
- MockRead(ASYNC, 0, 4) // EOF
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
+ MockRead(ASYNC, 0, 4) // EOF
};
// Write the request headers, and read the complete response
// while still waiting for chunked request data.
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(),
- DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NormalSpdyTransactionHelper helper(
+ CreateChunkedPostRequest(), DEFAULT_PRIORITY, NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
@@ -1982,7 +1737,7 @@ TEST_P(SpdyNetworkTransactionTest, ResponseBeforePostCompletes) {
base::RunLoop().RunUntilIdle();
- // Process the request headers, SYN_REPLY, and response body.
+ // Process the request headers, response headers, and response body.
// The request body is still in flight.
const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
@@ -1990,10 +1745,10 @@ TEST_P(SpdyNetworkTransactionTest, ResponseBeforePostCompletes) {
// Finish sending the request body.
upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, true);
helper.WaitForCallbackToComplete();
- EXPECT_EQ(OK, helper.output().rv);
+ EXPECT_THAT(helper.output().rv, IsOk());
std::string response_body;
- EXPECT_EQ(OK, ReadTransaction(helper.trans(), &response_body));
+ EXPECT_THAT(ReadTransaction(helper.trans(), &response_body), IsOk());
EXPECT_EQ(kUploadData, response_body);
helper.VerifyDataConsumed();
}
@@ -2001,35 +1756,31 @@ TEST_P(SpdyNetworkTransactionTest, ResponseBeforePostCompletes) {
// The client upon cancellation tries to send a RST_STREAM frame. The mock
// socket causes the TCP write to return zero. This test checks that the client
// tries to queue up the RST_STREAM frame again.
-TEST_P(SpdyNetworkTransactionTest, SocketWriteReturnsZero) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, SocketWriteReturnsZero) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*req.get(), 0, SYNCHRONOUS),
- MockWrite(SYNCHRONOUS, 0, 0, 2),
- CreateMockWrite(*rst.get(), 3, SYNCHRONOUS),
+ CreateMockWrite(req, 0, SYNCHRONOUS), MockWrite(SYNCHRONOUS, 0, 0, 2),
+ CreateMockWrite(rst, 3, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp.get(), 1, ASYNC),
- MockRead(ASYNC, 0, 0, 4) // EOF
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, 0, 0, 4) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
- HttpNetworkTransaction* trans = helper.trans();
+ helper.StartDefaultTest();
+ EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
- TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ helper.WaitForCallbackToComplete();
+ EXPECT_THAT(helper.output().rv, IsOk());
helper.ResetTrans();
base::RunLoop().RunUntilIdle();
@@ -2038,64 +1789,61 @@ TEST_P(SpdyNetworkTransactionTest, SocketWriteReturnsZero) {
}
// Test that the transaction doesn't crash when we don't have a reply.
-TEST_P(SpdyNetworkTransactionTest, ResponseWithoutSynReply) {
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+TEST_F(SpdyNetworkTransactionTest, ResponseWithoutHeaders) {
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*body, 1), MockRead(ASYNC, 0, 3) // EOF
+ CreateMockRead(body, 1), MockRead(ASYNC, 0, 3) // EOF
};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_SPDY_PROTOCOL_ERROR));
}
// Test that the transaction doesn't crash when we get two replies on the same
// stream ID. See http://crbug.com/45639.
-TEST_P(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
};
- std::unique_ptr<SpdySerializedFrame> resp0(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp0(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp0, 1), CreateMockRead(*resp1, 2),
- CreateMockRead(*body, 3), MockRead(ASYNC, 0, 5) // EOF
+ CreateMockRead(resp0, 1), CreateMockRead(resp1, 2),
+ CreateMockRead(body, 3), MockRead(ASYNC, 0, 5) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
- int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv =
+ trans->Start(&helper.request(), callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response);
@@ -2103,78 +1851,71 @@ TEST_P(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
EXPECT_TRUE(response->was_fetched_via_spdy);
std::string response_data;
rv = ReadTransaction(trans, &response_data);
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv);
+ EXPECT_THAT(rv, IsError(ERR_SPDY_PROTOCOL_ERROR));
helper.VerifyDataConsumed();
}
-TEST_P(SpdyNetworkTransactionTest, ResetReplyWithTransferEncoding) {
+TEST_F(SpdyNetworkTransactionTest, ResetReplyWithTransferEncoding) {
// Construct the request.
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
};
const char* const headers[] = {
"transfer-encoding", "chunked"
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(headers, 1, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(headers, 1, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 3),
+ CreateMockRead(resp, 1), CreateMockRead(body, 3),
MockRead(ASYNC, 0, 4) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_SPDY_PROTOCOL_ERROR));
helper.session()->spdy_session_pool()->CloseAllSessions();
helper.VerifyDataConsumed();
}
-TEST_P(SpdyNetworkTransactionTest, ResetPushWithTransferEncoding) {
+TEST_F(SpdyNetworkTransactionTest, ResetPushWithTransferEncoding) {
// Construct the request.
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
const char* const headers[] = {
"transfer-encoding", "chunked"
};
- std::unique_ptr<SpdySerializedFrame> push(
+ SpdySerializedFrame push(
spdy_util_.ConstructSpdyPush(headers, arraysize(headers) / 2, 2, 1,
GetDefaultUrlWithPath("/1").c_str()));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*push, 2),
- CreateMockRead(*body, 3),
+ CreateMockRead(resp, 1), CreateMockRead(push, 2), CreateMockRead(body, 3),
MockRead(ASYNC, 0, 5) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
@@ -2182,38 +1923,37 @@ TEST_P(SpdyNetworkTransactionTest, ResetPushWithTransferEncoding) {
helper.VerifyDataConsumed();
}
-TEST_P(SpdyNetworkTransactionTest, CancelledTransaction) {
+TEST_F(SpdyNetworkTransactionTest, CancelledTransaction) {
// Construct the request.
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*req),
+ CreateMockWrite(req),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp),
- // This following read isn't used by the test, except during the
- // RunUntilIdle() call at the end since the SpdySession survives the
- // HttpNetworkTransaction and still tries to continue Read()'ing. Any
- // MockRead will do here.
- MockRead(ASYNC, 0, 0) // EOF
+ CreateMockRead(resp),
+ // This following read isn't used by the test, except during the
+ // RunUntilIdle() call at the end since the SpdySession survives the
+ // HttpNetworkTransaction and still tries to continue Read()'ing. Any
+ // MockRead will do here.
+ MockRead(ASYNC, 0, 0) // EOF
};
StaticSocketDataProvider data(reads, arraysize(reads),
writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
helper.ResetTrans(); // Cancel the transaction.
// Flush the MessageLoop while the SpdySessionDependencies (in particular, the
@@ -2223,37 +1963,34 @@ TEST_P(SpdyNetworkTransactionTest, CancelledTransaction) {
}
// Verify that the client sends a Rst Frame upon cancelling the stream.
-TEST_P(SpdyNetworkTransactionTest, CancelledTransactionSendRst) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, CancelledTransactionSendRst) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*req, 0, SYNCHRONOUS),
- CreateMockWrite(*rst, 2, SYNCHRONOUS),
+ CreateMockWrite(req, 0, SYNCHRONOUS),
+ CreateMockWrite(rst, 2, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC),
- MockRead(ASYNC, 0, 0, 3) // EOF
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, 0, 0, 3) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(),
- GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
helper.ResetTrans();
base::RunLoop().RunUntilIdle();
@@ -2264,11 +2001,11 @@ TEST_P(SpdyNetworkTransactionTest, CancelledTransactionSendRst) {
// Verify that the client can correctly deal with the user callback attempting
// to start another transaction on a session that is closing down. See
// http://crbug.com/47455
-TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- MockWrite writes[] = {CreateMockWrite(*req)};
- MockWrite writes2[] = {CreateMockWrite(*req, 0)};
+ MockWrite writes[] = {CreateMockWrite(req)};
+ MockWrite writes2[] = {CreateMockWrite(req, 0)};
// The indicated length of this frame is longer than its actual length. When
// the session receives an empty frame after this one, it shuts down the
@@ -2278,10 +2015,9 @@ TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
0x07, 'h', 'e', 'l', 'l', 'o', '!',
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
+ CreateMockRead(resp, 1),
MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
MockRead(ASYNC, reinterpret_cast<const char*>(kGetBodyFrame2),
arraysize(kGetBodyFrame2), 3),
@@ -2289,7 +2025,7 @@ TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
MockRead(ASYNC, 0, 0, 5), // EOF
};
MockRead reads2[] = {
- CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 0, 2), // EOF
+ CreateMockRead(resp, 1), MockRead(ASYNC, 0, 0, 2), // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
@@ -2297,7 +2033,7 @@ TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
arraysize(writes2));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
helper.AddData(&data2);
@@ -2305,8 +2041,9 @@ TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
// Start the transaction with basic parameters.
TestCompletionCallback callback;
- int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv =
+ trans->Start(&helper.request(), callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
const int kSize = 3000;
@@ -2315,7 +2052,7 @@ TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
buf.get(), kSize,
base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback,
helper.session(), default_url_));
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
// This forces an err_IO_pending, which sets the callback.
data.Resume();
data.RunUntilPaused();
@@ -2329,34 +2066,32 @@ TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
// Verify that the client can correctly deal with the user callback deleting the
// transaction. Failures will usually be valgrind errors. See
// http://crbug.com/46925
-TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- MockWrite writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite writes[] = {CreateMockWrite(req, 0)};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp.get(), 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
- CreateMockRead(*body.get(), 3),
- MockRead(ASYNC, 0, 0, 4), // EOF
+ CreateMockRead(resp, 1),
+ MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
+ CreateMockRead(body, 3), MockRead(ASYNC, 0, 0, 4), // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
HttpNetworkTransaction* trans = helper.trans();
// Start the transaction with basic parameters.
TestCompletionCallback callback;
- int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv =
+ trans->Start(&helper.request(), callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
// Setup a user callback which will delete the session, and clear out the
@@ -2368,7 +2103,7 @@ TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
kSize,
base::Bind(&SpdyNetworkTransactionTest::DeleteSessionCallback,
base::Unretained(&helper)));
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
data.Resume();
// Finish running rest of tasks.
@@ -2376,23 +2111,143 @@ TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
helper.VerifyDataConsumed();
}
+TEST_F(SpdyNetworkTransactionTest, TestRawHeaderSizeSuccessfullRequest) {
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
+ headers["user-agent"] = "";
+ headers["accept-encoding"] = "gzip, deflate";
+
+ SpdySerializedFrame req(
+ spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
+ MockWrite writes[] = {
+ CreateMockWrite(req, 0),
+ };
+
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+
+ SpdySerializedFrame response_body_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, "should not include", 18, true));
+
+ MockRead response_headers(CreateMockRead(resp, 1));
+ MockRead reads[] = {
+ response_headers, CreateMockRead(response_body_frame, 2),
+ MockRead(ASYNC, 0, 0, 3) // EOF
+ };
+ SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+
+ TestDelegate delegate;
+ SpdyURLRequestContext spdy_url_request_context;
+ TestNetworkDelegate network_delegate;
+ spdy_url_request_context.set_network_delegate(&network_delegate);
+ SSLSocketDataProvider ssl_data(ASYNC, OK);
+ ssl_data.next_proto = kProtoHTTP2;
+
+ std::unique_ptr<URLRequest> request(spdy_url_request_context.CreateRequest(
+ GURL(kDefaultUrl), DEFAULT_PRIORITY, &delegate));
+ spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(&ssl_data);
+ spdy_url_request_context.socket_factory().AddSocketDataProvider(&data);
+
+ request->Start();
+ base::RunLoop().Run();
+
+ EXPECT_LT(0, request->GetTotalSentBytes());
+ EXPECT_LT(0, request->GetTotalReceivedBytes());
+ EXPECT_EQ(network_delegate.total_network_bytes_sent(),
+ request->GetTotalSentBytes());
+ EXPECT_EQ(network_delegate.total_network_bytes_received(),
+ request->GetTotalReceivedBytes());
+ EXPECT_EQ(response_headers.data_len, request->raw_header_size());
+ EXPECT_TRUE(data.AllReadDataConsumed());
+ EXPECT_TRUE(data.AllWriteDataConsumed());
+}
+
+TEST_F(SpdyNetworkTransactionTest,
+ TestRawHeaderSizeSuccessfullPushHeadersFirst) {
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
+ headers["user-agent"] = "";
+ headers["accept-encoding"] = "gzip, deflate";
+
+ SpdySerializedFrame req(
+ spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
+ MockWrite writes[] = {
+ CreateMockWrite(req, 0),
+ };
+
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame response_body_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, "should not include", 18, true));
+
+ SpdyHeaderBlock push_headers;
+ spdy_util_.AddUrlToHeaderBlock(std::string(kDefaultUrl) + "b.dat",
+ &push_headers);
+
+ SpdySerializedFrame push_init_frame(
+ spdy_util_.ConstructInitialSpdyPushFrame(std::move(push_headers), 2, 1));
+
+ SpdySerializedFrame push_headers_frame(
+ spdy_util_.ConstructSpdyPushHeaders(2, nullptr, 0));
+
+ SpdySerializedFrame push_body_frame(spdy_util_.ConstructSpdyDataFrame(
+ 2, "should not include either", 25, false));
+
+ MockRead push_init_read(CreateMockRead(push_init_frame, 1));
+ MockRead response_headers(CreateMockRead(resp, 4));
+ // raw_header_size() will contain the size of the push promise frame
+ // initialization.
+ int expected_response_headers_size =
+ response_headers.data_len + push_init_read.data_len;
+
+ MockRead reads[] = {
+ push_init_read,
+ CreateMockRead(push_headers_frame, 2),
+ CreateMockRead(push_body_frame, 3),
+ response_headers,
+ CreateMockRead(response_body_frame, 5),
+ MockRead(ASYNC, 0, 6) // EOF
+ };
+
+ SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+
+ TestDelegate delegate;
+ SpdyURLRequestContext spdy_url_request_context;
+ TestNetworkDelegate network_delegate;
+ spdy_url_request_context.set_network_delegate(&network_delegate);
+ SSLSocketDataProvider ssl_data(ASYNC, OK);
+ ssl_data.next_proto = kProtoHTTP2;
+
+ std::unique_ptr<URLRequest> request(spdy_url_request_context.CreateRequest(
+ GURL(kDefaultUrl), DEFAULT_PRIORITY, &delegate));
+ spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(&ssl_data);
+ spdy_url_request_context.socket_factory().AddSocketDataProvider(&data);
+
+ request->Start();
+ base::RunLoop().Run();
+
+ EXPECT_LT(0, request->GetTotalSentBytes());
+ EXPECT_LT(0, request->GetTotalReceivedBytes());
+ EXPECT_EQ(network_delegate.total_network_bytes_sent(),
+ request->GetTotalSentBytes());
+ EXPECT_EQ(network_delegate.total_network_bytes_received(),
+ request->GetTotalReceivedBytes());
+ EXPECT_EQ(expected_response_headers_size, request->raw_header_size());
+ EXPECT_TRUE(data.AllReadDataConsumed());
+ EXPECT_TRUE(data.AllWriteDataConsumed());
+}
+
// Send a spdy request to www.example.org that gets redirected to www.foo.com.
-TEST_P(SpdyNetworkTransactionTest, DISABLED_RedirectGetRequest) {
+TEST_F(SpdyNetworkTransactionTest, DISABLED_RedirectGetRequest) {
SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
headers["user-agent"] = "";
headers["accept-encoding"] = "gzip, deflate";
// Setup writes/reads to www.example.org
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdySyn(1, std::move(headers), LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReplyRedirect(1));
+ SpdySerializedFrame req(
+ spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReplyRedirect(1));
MockWrite writes[] = {
- CreateMockWrite(*req, 1),
+ CreateMockWrite(req, 1),
};
MockRead reads[] = {
- CreateMockRead(*resp, 2),
- MockRead(ASYNC, 0, 0, 3) // EOF
+ CreateMockRead(resp, 2), MockRead(ASYNC, 0, 0, 3) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
@@ -2401,20 +2256,17 @@ TEST_P(SpdyNetworkTransactionTest, DISABLED_RedirectGetRequest) {
spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
headers2["user-agent"] = "";
headers2["accept-encoding"] = "gzip, deflate";
- std::unique_ptr<SpdySerializedFrame> req2(
- spdy_util_.ConstructSpdySyn(1, std::move(headers2), LOWEST, true));
+ SpdySerializedFrame req2(
+ spdy_util_.ConstructSpdyHeaders(1, std::move(headers2), LOWEST, true));
MockWrite writes2[] = {
- CreateMockWrite(*req2, 1),
+ CreateMockWrite(req2, 1),
};
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads2[] = {
- CreateMockRead(*resp2, 2),
- CreateMockRead(*body2, 3),
- MockRead(ASYNC, 0, 0, 4) // EOF
+ CreateMockRead(resp2, 2), CreateMockRead(body2, 3),
+ MockRead(ASYNC, 0, 0, 4) // EOF
};
SequencedSocketData data2(reads2, arraysize(reads2), writes2,
@@ -2423,7 +2275,7 @@ TEST_P(SpdyNetworkTransactionTest, DISABLED_RedirectGetRequest) {
// TODO(erikchen): Make test support SPDYSSL, SPDYNPN
TestDelegate d;
{
- SpdyURLRequestContext spdy_url_request_context(GetParam().protocol);
+ SpdyURLRequestContext spdy_url_request_context;
std::unique_ptr<URLRequest> r(spdy_url_request_context.CreateRequest(
default_url_, DEFAULT_PRIORITY, &d));
spdy_url_request_context.socket_factory().
@@ -2441,7 +2293,7 @@ TEST_P(SpdyNetworkTransactionTest, DISABLED_RedirectGetRequest) {
base::RunLoop().Run();
EXPECT_EQ(1, d.response_started_count());
EXPECT_FALSE(d.received_data_before_response());
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
+ EXPECT_EQ(OK, d.request_status());
std::string contents("hello!");
EXPECT_EQ(contents, d.data_received());
}
@@ -2453,33 +2305,28 @@ TEST_P(SpdyNetworkTransactionTest, DISABLED_RedirectGetRequest) {
// Send a spdy request to www.example.org. Get a pushed stream that redirects to
// www.foo.com.
-TEST_P(SpdyNetworkTransactionTest, DISABLED_RedirectServerPush) {
+TEST_F(SpdyNetworkTransactionTest, DISABLED_RedirectServerPush) {
SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
headers["user-agent"] = "";
headers["accept-encoding"] = "gzip, deflate";
// Setup writes/reads to www.example.org
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdySyn(1, std::move(headers), LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> rep(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame req(
+ spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame rep(spdy_util_.ConstructSpdyPush(
NULL, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str(),
"301 Moved Permanently", "http://www.foo.com/index.php"));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*req, 1),
- CreateMockWrite(*rst, 6),
+ CreateMockWrite(req, 1), CreateMockWrite(rst, 6),
};
MockRead reads[] = {
- CreateMockRead(*resp, 2),
- CreateMockRead(*rep, 3),
- CreateMockRead(*body, 4),
- MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause
- MockRead(ASYNC, 0, 0, 7) // EOF
+ CreateMockRead(resp, 2), CreateMockRead(rep, 3), CreateMockRead(body, 4),
+ MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause
+ MockRead(ASYNC, 0, 0, 7) // EOF
};
// Setup writes/reads to www.foo.com
@@ -2487,28 +2334,24 @@ TEST_P(SpdyNetworkTransactionTest, DISABLED_RedirectServerPush) {
spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
headers2["user-agent"] = "";
headers2["accept-encoding"] = "gzip, deflate";
- std::unique_ptr<SpdySerializedFrame> req2(
- spdy_util_.ConstructSpdySyn(1, std::move(headers2), LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame req2(
+ spdy_util_.ConstructSpdyHeaders(1, std::move(headers2), LOWEST, true));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(1, true));
MockWrite writes2[] = {
- CreateMockWrite(*req2, 1),
+ CreateMockWrite(req2, 1),
};
MockRead reads2[] = {
- CreateMockRead(*resp2, 2),
- CreateMockRead(*body2, 3),
- MockRead(ASYNC, 0, 0, 5) // EOF
+ CreateMockRead(resp2, 2), CreateMockRead(body2, 3),
+ MockRead(ASYNC, 0, 0, 5) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
SequencedSocketData data2(reads2, arraysize(reads2), writes2,
arraysize(writes2));
- // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
TestDelegate d;
TestDelegate d2;
- SpdyURLRequestContext spdy_url_request_context(GetParam().protocol);
+ SpdyURLRequestContext spdy_url_request_context;
{
std::unique_ptr<URLRequest> r(spdy_url_request_context.CreateRequest(
default_url_, DEFAULT_PRIORITY, &d));
@@ -2536,7 +2379,7 @@ TEST_P(SpdyNetworkTransactionTest, DISABLED_RedirectServerPush) {
base::RunLoop().Run();
EXPECT_EQ(1, d2.response_started_count());
EXPECT_FALSE(d2.received_data_before_response());
- EXPECT_EQ(URLRequestStatus::SUCCESS, r2->status().status());
+ EXPECT_EQ(OK, d2.request_status());
std::string contents2("hello!");
EXPECT_EQ(contents2, d2.data_received());
}
@@ -2546,28 +2389,26 @@ TEST_P(SpdyNetworkTransactionTest, DISABLED_RedirectServerPush) {
EXPECT_TRUE(data2.AllWriteDataConsumed());
}
-TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+TEST_F(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0),
+ CreateMockWrite(stream1_syn, 0),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush(
NULL, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
const char kPushedData[] = "pushed";
- std::unique_ptr<SpdySerializedFrame> stream2_body(
- spdy_util_.ConstructSpdyBodyFrame(2, kPushedData, strlen(kPushedData),
- true));
+ SpdySerializedFrame stream2_body(spdy_util_.ConstructSpdyDataFrame(
+ 2, kPushedData, strlen(kPushedData), true));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1),
- CreateMockRead(*stream2_syn, 2),
- CreateMockRead(*stream1_body, 3, SYNCHRONOUS),
- CreateMockRead(*stream2_body, 4),
+ CreateMockRead(stream1_reply, 1),
+ CreateMockRead(stream2_syn, 2),
+ CreateMockRead(stream1_body, 3, SYNCHRONOUS),
+ CreateMockRead(stream2_body, 4),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause
};
@@ -2580,7 +2421,7 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
&response2,
expected_push_result);
- // Verify the SYN_REPLY.
+ // Verify the response headers.
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
@@ -2589,28 +2430,26 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
}
-TEST_P(SpdyNetworkTransactionTest, ServerPushBeforeSynReply) {
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+TEST_F(SpdyNetworkTransactionTest, ServerPushBeforeHeaders) {
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0),
+ CreateMockWrite(stream1_syn, 0),
};
- std::unique_ptr<SpdySerializedFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush(
nullptr, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
const char kPushedData[] = "pushed";
- std::unique_ptr<SpdySerializedFrame> stream2_body(
- spdy_util_.ConstructSpdyBodyFrame(2, kPushedData, strlen(kPushedData),
- true));
+ SpdySerializedFrame stream2_body(spdy_util_.ConstructSpdyDataFrame(
+ 2, kPushedData, strlen(kPushedData), true));
MockRead reads[] = {
- CreateMockRead(*stream2_syn, 1),
- CreateMockRead(*stream1_reply, 2),
- CreateMockRead(*stream1_body, 3, SYNCHRONOUS),
- CreateMockRead(*stream2_body, 4),
+ CreateMockRead(stream2_syn, 1),
+ CreateMockRead(stream1_reply, 2),
+ CreateMockRead(stream1_body, 3, SYNCHRONOUS),
+ CreateMockRead(stream2_body, 4),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause
};
@@ -2623,7 +2462,7 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushBeforeSynReply) {
&response2,
expected_push_result);
- // Verify the SYN_REPLY.
+ // Verify the response headers.
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
@@ -2632,28 +2471,26 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushBeforeSynReply) {
EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
}
-TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) {
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+TEST_F(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) {
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0),
+ CreateMockWrite(stream1_syn, 0),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush(
NULL, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
const char kPushedData[] = "pushed";
- std::unique_ptr<SpdySerializedFrame> stream2_body(
- spdy_util_.ConstructSpdyBodyFrame(2, kPushedData, strlen(kPushedData),
- true));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream2_body(spdy_util_.ConstructSpdyDataFrame(
+ 2, kPushedData, strlen(kPushedData), true));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1),
- CreateMockRead(*stream2_syn, 2),
- CreateMockRead(*stream2_body, 3),
- CreateMockRead(*stream1_body, 4, SYNCHRONOUS),
+ CreateMockRead(stream1_reply, 1),
+ CreateMockRead(stream2_syn, 2),
+ CreateMockRead(stream2_body, 3),
+ CreateMockRead(stream1_body, 4, SYNCHRONOUS),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause
};
@@ -2666,7 +2503,7 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) {
&response2,
expected_push_result);
- // Verify the SYN_REPLY.
+ // Verify the response headers.
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
@@ -2675,32 +2512,31 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) {
EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
}
-TEST_P(SpdyNetworkTransactionTest, ServerPushServerAborted) {
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+TEST_F(SpdyNetworkTransactionTest, ServerPushServerAborted) {
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0),
+ CreateMockWrite(stream1_syn, 0),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush(
NULL, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
- std::unique_ptr<SpdySerializedFrame> stream2_rst(
+ SpdySerializedFrame stream2_rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1),
- CreateMockRead(*stream2_syn, 2),
- CreateMockRead(*stream2_rst, 3),
- CreateMockRead(*stream1_body, 4, SYNCHRONOUS),
+ CreateMockRead(stream1_reply, 1),
+ CreateMockRead(stream2_syn, 2),
+ CreateMockRead(stream2_rst, 3),
+ CreateMockRead(stream1_body, 4, SYNCHRONOUS),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
@@ -2709,17 +2545,17 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushServerAborted) {
// Start the transaction with basic parameters.
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Verify that we consumed all test data.
EXPECT_TRUE(data.AllReadDataConsumed());
EXPECT_TRUE(data.AllWriteDataConsumed());
- // Verify the SYN_REPLY.
+ // Verify the response headers.
HttpResponseInfo response = *trans->GetResponseInfo();
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
@@ -2727,33 +2563,31 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushServerAborted) {
// Verify that we don't leak streams and that we properly send a reset
// if the server pushes the same stream twice.
-TEST_P(SpdyNetworkTransactionTest, ServerPushDuplicate) {
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+TEST_F(SpdyNetworkTransactionTest, ServerPushDuplicate) {
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> stream3_rst(
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame stream3_rst(
spdy_util_.ConstructSpdyRstStream(4, RST_STREAM_PROTOCOL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*stream3_rst, 4),
+ CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream3_rst, 4),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush(
NULL, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
const char kPushedData[] = "pushed";
- std::unique_ptr<SpdySerializedFrame> stream2_body(
- spdy_util_.ConstructSpdyBodyFrame(2, kPushedData, strlen(kPushedData),
- true));
- std::unique_ptr<SpdySerializedFrame> stream3_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream2_body(spdy_util_.ConstructSpdyDataFrame(
+ 2, kPushedData, strlen(kPushedData), true));
+ SpdySerializedFrame stream3_syn(spdy_util_.ConstructSpdyPush(
NULL, 0, 4, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1),
- CreateMockRead(*stream2_syn, 2),
- CreateMockRead(*stream3_syn, 3),
- CreateMockRead(*stream1_body, 5),
- CreateMockRead(*stream2_body, 6),
+ CreateMockRead(stream1_reply, 1),
+ CreateMockRead(stream2_syn, 2),
+ CreateMockRead(stream3_syn, 3),
+ CreateMockRead(stream1_body, 5),
+ CreateMockRead(stream2_body, 6),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 7), // Force a pause
};
@@ -2766,7 +2600,7 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushDuplicate) {
&response2,
expected_push_result);
- // Verify the SYN_REPLY.
+ // Verify the response headers.
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
@@ -2775,41 +2609,39 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushDuplicate) {
EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
}
-TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) {
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+TEST_F(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) {
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0),
+ CreateMockWrite(stream1_syn, 0),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush(
NULL, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
static const char kPushedData[] = "pushed my darling hello my baby";
- std::unique_ptr<SpdySerializedFrame> stream2_body_base(
- spdy_util_.ConstructSpdyBodyFrame(2, kPushedData, strlen(kPushedData),
- true));
+ SpdySerializedFrame stream2_body_base(spdy_util_.ConstructSpdyDataFrame(
+ 2, kPushedData, strlen(kPushedData), true));
const size_t kChunkSize = strlen(kPushedData) / 4;
- std::unique_ptr<SpdySerializedFrame> stream2_body1(
- new SpdySerializedFrame(stream2_body_base->data(), kChunkSize, false));
- std::unique_ptr<SpdySerializedFrame> stream2_body2(new SpdySerializedFrame(
- stream2_body_base->data() + kChunkSize, kChunkSize, false));
- std::unique_ptr<SpdySerializedFrame> stream2_body3(new SpdySerializedFrame(
- stream2_body_base->data() + 2 * kChunkSize, kChunkSize, false));
- std::unique_ptr<SpdySerializedFrame> stream2_body4(new SpdySerializedFrame(
- stream2_body_base->data() + 3 * kChunkSize,
- stream2_body_base->size() - 3 * kChunkSize, false));
+ SpdySerializedFrame stream2_body1(stream2_body_base.data(), kChunkSize,
+ false);
+ SpdySerializedFrame stream2_body2(stream2_body_base.data() + kChunkSize,
+ kChunkSize, false);
+ SpdySerializedFrame stream2_body3(stream2_body_base.data() + 2 * kChunkSize,
+ kChunkSize, false);
+ SpdySerializedFrame stream2_body4(stream2_body_base.data() + 3 * kChunkSize,
+ stream2_body_base.size() - 3 * kChunkSize,
+ false);
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1),
- CreateMockRead(*stream2_syn, 2),
- CreateMockRead(*stream2_body1, 3),
- CreateMockRead(*stream2_body2, 4),
- CreateMockRead(*stream2_body3, 5),
- CreateMockRead(*stream2_body4, 6),
- CreateMockRead(*stream1_body, 7, SYNCHRONOUS),
+ CreateMockRead(stream1_reply, 1),
+ CreateMockRead(stream2_syn, 2),
+ CreateMockRead(stream2_body1, 3),
+ CreateMockRead(stream2_body2, 4),
+ CreateMockRead(stream2_body3, 5),
+ CreateMockRead(stream2_body4, 6),
+ CreateMockRead(stream1_body, 7, SYNCHRONOUS),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 8), // Force a pause
};
@@ -2819,7 +2651,7 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
RunServerPushTest(&data, &response, &response2, kPushedData);
- // Verify the SYN_REPLY.
+ // Verify the response headers.
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
@@ -2828,41 +2660,39 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) {
EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
}
-TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) {
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+TEST_F(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) {
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0),
+ CreateMockWrite(stream1_syn, 0),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush(
NULL, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
static const char kPushedData[] = "pushed my darling hello my baby";
- std::unique_ptr<SpdySerializedFrame> stream2_body_base(
- spdy_util_.ConstructSpdyBodyFrame(2, kPushedData, strlen(kPushedData),
- true));
+ SpdySerializedFrame stream2_body_base(spdy_util_.ConstructSpdyDataFrame(
+ 2, kPushedData, strlen(kPushedData), true));
const size_t kChunkSize = strlen(kPushedData) / 4;
- std::unique_ptr<SpdySerializedFrame> stream2_body1(
- new SpdySerializedFrame(stream2_body_base->data(), kChunkSize, false));
- std::unique_ptr<SpdySerializedFrame> stream2_body2(new SpdySerializedFrame(
- stream2_body_base->data() + kChunkSize, kChunkSize, false));
- std::unique_ptr<SpdySerializedFrame> stream2_body3(new SpdySerializedFrame(
- stream2_body_base->data() + 2 * kChunkSize, kChunkSize, false));
- std::unique_ptr<SpdySerializedFrame> stream2_body4(new SpdySerializedFrame(
- stream2_body_base->data() + 3 * kChunkSize,
- stream2_body_base->size() - 3 * kChunkSize, false));
+ SpdySerializedFrame stream2_body1(stream2_body_base.data(), kChunkSize,
+ false);
+ SpdySerializedFrame stream2_body2(stream2_body_base.data() + kChunkSize,
+ kChunkSize, false);
+ SpdySerializedFrame stream2_body3(stream2_body_base.data() + 2 * kChunkSize,
+ kChunkSize, false);
+ SpdySerializedFrame stream2_body4(stream2_body_base.data() + 3 * kChunkSize,
+ stream2_body_base.size() - 3 * kChunkSize,
+ false);
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1),
- CreateMockRead(*stream2_syn, 2),
- CreateMockRead(*stream2_body1, 3),
- CreateMockRead(*stream2_body2, 4),
- CreateMockRead(*stream2_body3, 5),
- CreateMockRead(*stream2_body4, 6),
- CreateMockRead(*stream1_body.get(), 7, SYNCHRONOUS),
+ CreateMockRead(stream1_reply, 1),
+ CreateMockRead(stream2_syn, 2),
+ CreateMockRead(stream2_body1, 3),
+ CreateMockRead(stream2_body2, 4),
+ CreateMockRead(stream2_body3, 5),
+ CreateMockRead(stream2_body4, 6),
+ CreateMockRead(stream1_body, 7, SYNCHRONOUS),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 8) // Force a pause.
};
@@ -2871,7 +2701,7 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
RunServerPushTest(&data, &response, &response2, kPushedData);
- // Verify the SYN_REPLY.
+ // Verify the response headers.
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
@@ -2880,33 +2710,26 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) {
EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
}
-TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) {
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) {
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> goaway;
- if (spdy_util_.spdy_version() == SPDY3) {
- goaway.reset(spdy_util_.ConstructSpdyGoAway(0, GOAWAY_PROTOCOL_ERROR,
- "Push on even stream id."));
- } else {
- goaway.reset(spdy_util_.ConstructSpdyGoAway(
- 0, GOAWAY_PROTOCOL_ERROR, "Framer error: 1 (INVALID_STREAM_ID)."));
- }
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
+ 0, GOAWAY_PROTOCOL_ERROR, "Framer error: 1 (INVALID_STREAM_ID)."));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*goaway, 3),
+ CreateMockWrite(stream1_syn, 0), CreateMockWrite(goaway, 3),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush(
NULL, 0, 2, 0, GetDefaultUrlWithPath("/foo.dat").c_str()));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1),
- CreateMockRead(*stream2_syn, 2),
+ CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
@@ -2915,47 +2738,45 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) {
// Start the transaction with basic parameters.
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Verify that we consumed all test data.
EXPECT_TRUE(data.AllReadDataConsumed());
EXPECT_TRUE(data.AllWriteDataConsumed());
- // Verify the SYN_REPLY.
+ // Verify the response headers.
HttpResponseInfo response = *trans->GetResponseInfo();
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
}
-TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) {
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) {
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> stream2_rst(
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame stream2_rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_INVALID_STREAM));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*stream2_rst, 3),
+ CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_rst, 3),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush(
NULL, 0, 2, 9, GetDefaultUrlWithPath("/foo.dat").c_str()));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1),
- CreateMockRead(*stream2_syn, 2),
- CreateMockRead(*stream1_body, 4),
+ CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
+ CreateMockRead(stream1_body, 4),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
@@ -2964,52 +2785,48 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) {
// Start the transaction with basic parameters.
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Verify that we consumed all test data.
EXPECT_TRUE(data.AllReadDataConsumed());
EXPECT_TRUE(data.AllWriteDataConsumed());
- // Verify the SYN_REPLY.
+ // Verify the response headers.
HttpResponseInfo response = *trans->GetResponseInfo();
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
}
-TEST_P(SpdyNetworkTransactionTest, ServerPushNoURL) {
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+TEST_F(SpdyNetworkTransactionTest, ServerPushNoURL) {
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> stream2_rst(
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame stream2_rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*stream2_rst, 3),
+ CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_rst, 3),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
SpdyHeaderBlock incomplete_headers;
incomplete_headers[spdy_util_.GetStatusKey()] = "200 OK";
- incomplete_headers[spdy_util_.GetVersionKey()] = "HTTP/1.1";
incomplete_headers["hello"] = "bye";
- std::unique_ptr<SpdySerializedFrame> stream2_syn(
- spdy_util_.ConstructInitialSpdyPushFrame(std::move(incomplete_headers), 2,
- 1));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructInitialSpdyPushFrame(
+ std::move(incomplete_headers), 2, 1));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1),
- CreateMockRead(*stream2_syn, 2),
- CreateMockRead(*stream1_body, 4),
+ CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
+ CreateMockRead(stream1_body, 4),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5) // Force a pause
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
@@ -3018,83 +2835,82 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushNoURL) {
// Start the transaction with basic parameters.
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Verify that we consumed all test data.
EXPECT_TRUE(data.AllReadDataConsumed());
EXPECT_TRUE(data.AllWriteDataConsumed());
- // Verify the SYN_REPLY.
+ // Verify the response headers.
HttpResponseInfo response = *trans->GetResponseInfo();
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
}
// PUSH_PROMISE on a server-initiated stream should trigger GOAWAY.
-TEST_P(SpdyNetworkTransactionTest, ServerPushOnPushedStream) {
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+TEST_F(SpdyNetworkTransactionTest, ServerPushOnPushedStream) {
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
2, GOAWAY_PROTOCOL_ERROR, "Push on even stream id."));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*goaway, 4),
+ CreateMockWrite(stream1_syn, 0), CreateMockWrite(goaway, 4),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush(
nullptr, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
- std::unique_ptr<SpdySerializedFrame> stream3_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream3_syn(spdy_util_.ConstructSpdyPush(
nullptr, 0, 4, 2, GetDefaultUrlWithPath("/bar.dat").c_str()));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1), CreateMockRead(*stream2_syn, 2),
- CreateMockRead(*stream3_syn, 3),
+ CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
+ CreateMockRead(stream3_syn, 3),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), nullptr);
+ NetLogWithSource(), nullptr);
helper.RunToCompletion(&data);
}
// PUSH_PROMISE on a closed client-initiated stream should trigger RST_STREAM.
-TEST_P(SpdyNetworkTransactionTest, ServerPushOnClosedStream) {
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+TEST_F(SpdyNetworkTransactionTest, ServerPushOnClosedStream) {
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_INVALID_STREAM));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*rst, 5),
+ CreateMockWrite(stream1_syn, 0), CreateMockWrite(rst, 5),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush(
nullptr, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1), CreateMockRead(*stream1_body, 2),
- CreateMockRead(*stream2_syn, 3), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
+ CreateMockRead(stream1_reply, 1), CreateMockRead(stream1_body, 2),
+ CreateMockRead(stream2_syn, 3), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), nullptr);
+ NetLogWithSource(), nullptr);
helper.RunPreTestSetup();
helper.AddData(&data);
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
- int rv =
- trans->Start(&CreateGetRequest(), callback.callback(), BoundNetLog());
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
rv = callback.GetResult(rv);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
HttpResponseInfo response = *trans->GetResponseInfo();
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
@@ -3106,62 +2922,59 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushOnClosedStream) {
// PUSH_PROMISE on a server-initiated stream should trigger GOAWAY even if
// stream is closed.
-TEST_P(SpdyNetworkTransactionTest, ServerPushOnClosedPushedStream) {
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+TEST_F(SpdyNetworkTransactionTest, ServerPushOnClosedPushedStream) {
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
2, GOAWAY_PROTOCOL_ERROR, "Push on even stream id."));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*goaway, 7),
+ CreateMockWrite(stream1_syn, 0), CreateMockWrite(goaway, 7),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream2_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructSpdyPush(
nullptr, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str()));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
const char kPushedData[] = "pushed";
- std::unique_ptr<SpdySerializedFrame> stream2_body(
- spdy_util_.ConstructSpdyBodyFrame(2, kPushedData, strlen(kPushedData),
- true));
- std::unique_ptr<SpdySerializedFrame> stream3_syn(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame stream2_body(spdy_util_.ConstructSpdyDataFrame(
+ 2, kPushedData, strlen(kPushedData), true));
+ SpdySerializedFrame stream3_syn(spdy_util_.ConstructSpdyPush(
nullptr, 0, 4, 2, GetDefaultUrlWithPath("/bar.dat").c_str()));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1), CreateMockRead(*stream2_syn, 2),
- CreateMockRead(*stream1_body, 3), CreateMockRead(*stream2_body, 4),
- MockRead(ASYNC, ERR_IO_PENDING, 5), CreateMockRead(*stream3_syn, 6),
+ CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
+ CreateMockRead(stream1_body, 3), CreateMockRead(stream2_body, 4),
+ MockRead(ASYNC, ERR_IO_PENDING, 5), CreateMockRead(stream3_syn, 6),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), nullptr);
+ NetLogWithSource(), nullptr);
helper.RunPreTestSetup();
helper.AddData(&data);
HttpNetworkTransaction* trans1 = helper.trans();
TestCompletionCallback callback1;
- int rv =
- trans1->Start(&CreateGetRequest(), callback1.callback(), BoundNetLog());
+ int rv = trans1->Start(&CreateGetRequest(), callback1.callback(),
+ NetLogWithSource());
rv = callback1.GetResult(rv);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
HttpResponseInfo response = *trans1->GetResponseInfo();
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
- std::unique_ptr<HttpNetworkTransaction> trans2(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
+ HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
TestCompletionCallback callback2;
- rv = trans2->Start(&CreateGetPushRequest(), callback2.callback(),
- BoundNetLog());
+ rv = trans2.Start(&CreateGetPushRequest(), callback2.callback(),
+ NetLogWithSource());
rv = callback2.GetResult(rv);
- EXPECT_EQ(OK, rv);
- response = *trans2->GetResponseInfo();
+ EXPECT_THAT(rv, IsOk());
+ response = *trans2.GetResponseInfo();
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
std::string result;
- ReadResult(trans2.get(), &result);
+ ReadResult(&trans2, &result);
EXPECT_EQ(kPushedData, result);
data.Resume();
@@ -3171,10 +2984,9 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushOnClosedPushedStream) {
EXPECT_TRUE(data.AllWriteDataConsumed());
}
-// Verify that various SynReply headers parse correctly through the
-// HTTP layer.
-TEST_P(SpdyNetworkTransactionTest, SynReplyHeaders) {
- struct SynReplyHeadersTests {
+// Verify that various response headers parse correctly through the HTTP layer.
+TEST_F(SpdyNetworkTransactionTest, ResponseHeaders) {
+ struct ResponseHeadersTests {
int num_headers;
const char* extra_headers[5];
SpdyHeaderBlock expected_headers;
@@ -3202,13 +3014,6 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeaders) {
test_cases[1].expected_headers["status"] = "200";
test_cases[2].expected_headers["status"] = "200";
- // HTTP/2 eliminates use of the :version header.
- if (GetParam().protocol == kProtoSPDY31) {
- test_cases[0].expected_headers["version"] = "HTTP/1.1";
- test_cases[1].expected_headers["version"] = "HTTP/1.1";
- test_cases[2].expected_headers["version"] = "HTTP/1.1";
- }
-
test_cases[0].expected_headers["hello"] = "bye";
test_cases[1].expected_headers["hello"] = "bye";
test_cases[2].expected_headers["hello"] = "bye";
@@ -3217,31 +3022,27 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeaders) {
test_cases[2].expected_headers["cookie"] = "val1,val2";
for (size_t i = 0; i < arraysize(test_cases); ++i) {
- SpdyTestUtil spdy_test_util(GetParam().protocol,
- GetParam().priority_to_dependency);
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdyTestUtil spdy_test_util;
+ SpdySerializedFrame req(
spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- MockWrite writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite writes[] = {CreateMockWrite(req, 0)};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_test_util.ConstructSpdyGetSynReply(test_cases[i].extra_headers,
- test_cases[i].num_headers, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_test_util.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_test_util.ConstructSpdyGetReply(
+ test_cases[i].extra_headers, test_cases[i].num_headers, 1));
+ SpdySerializedFrame body(spdy_test_util.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
MockRead(ASYNC, 0, 3) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes,
arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
@@ -3266,11 +3067,11 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeaders) {
}
}
-// Verify that various SynReply headers parse vary fields correctly
-// through the HTTP layer, and the response matches the request.
-TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
+// Verify that various response headers parse vary fields correctly through the
+// HTTP layer, and the response matches the request.
+TEST_F(SpdyNetworkTransactionTest, ResponseHeadersVary) {
// Modify the following data to change/add test cases:
- struct SynReplyTests {
+ struct ResponseTests {
bool vary_matches;
int num_headers[2];
const char* extra_headers[2][16];
@@ -3278,45 +3079,39 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
// Test the case of a multi-valued cookie. When the value is delimited
// with NUL characters, it needs to be unfolded into multiple headers.
{true,
- {1, 4},
+ {1, 3},
{{"cookie", "val1,val2", NULL},
{spdy_util_.GetStatusKey(), "200", spdy_util_.GetPathKey(),
- "/index.php", spdy_util_.GetVersionKey(), "HTTP/1.1", "vary", "cookie",
- NULL}}},
+ "/index.php", "vary", "cookie", NULL}}},
{// Multiple vary fields.
true,
- {2, 5},
+ {2, 4},
{{"friend", "barney", "enemy", "snaggletooth", NULL},
{spdy_util_.GetStatusKey(), "200", spdy_util_.GetPathKey(),
- "/index.php", spdy_util_.GetVersionKey(), "HTTP/1.1", "vary", "friend",
- "vary", "enemy", NULL}}},
+ "/index.php", "vary", "friend", "vary", "enemy", NULL}}},
{// Test a '*' vary field.
false,
- {1, 4},
+ {1, 3},
{{"cookie", "val1,val2", NULL},
{spdy_util_.GetStatusKey(), "200", spdy_util_.GetPathKey(),
- "/index.php", spdy_util_.GetVersionKey(), "HTTP/1.1", "vary", "*",
- NULL}}},
+ "/index.php", "vary", "*", NULL}}},
{// Multiple comma-separated vary fields.
true,
- {2, 4},
+ {2, 3},
{{"friend", "barney", "enemy", "snaggletooth", NULL},
{spdy_util_.GetStatusKey(), "200", spdy_util_.GetPathKey(),
- "/index.php", spdy_util_.GetVersionKey(), "HTTP/1.1", "vary",
- "friend,enemy", NULL}}}};
+ "/index.php", "vary", "friend,enemy", NULL}}}};
for (size_t i = 0; i < arraysize(test_cases); ++i) {
- SpdyTestUtil spdy_test_util(GetParam().protocol,
- GetParam().priority_to_dependency);
+ SpdyTestUtil spdy_test_util;
// Construct the request.
- std::unique_ptr<SpdySerializedFrame> frame_req(
- spdy_test_util.ConstructSpdyGet(test_cases[i].extra_headers[0],
- test_cases[i].num_headers[0], 1, LOWEST,
- true));
+ SpdySerializedFrame frame_req(spdy_test_util.ConstructSpdyGet(
+ test_cases[i].extra_headers[0], test_cases[i].num_headers[0], 1, LOWEST,
+ true));
MockWrite writes[] = {
- CreateMockWrite(*frame_req, 0),
+ CreateMockWrite(frame_req, 0),
};
// Construct the reply.
@@ -3328,14 +3123,12 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
std::string expected_reply =
spdy_test_util.ConstructSpdyReplyString(reply_headers);
- std::unique_ptr<SpdySerializedFrame> frame_reply(
+ SpdySerializedFrame frame_reply(
spdy_test_util.ConstructSpdyReply(1, std::move(reply_headers)));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_test_util.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame body(spdy_test_util.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*frame_reply, 1),
- CreateMockRead(*body, 2),
+ CreateMockRead(frame_reply, 1), CreateMockRead(body, 2),
MockRead(ASYNC, 0, 3) // EOF
};
@@ -3352,7 +3145,7 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
SequencedSocketData data(reads, arraysize(reads), writes,
arraysize(writes));
NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
@@ -3380,190 +3173,136 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
}
}
-// Verify that we don't crash on invalid SynReply responses.
-TEST_P(SpdyNetworkTransactionTest, InvalidSynReply) {
- struct InvalidSynReplyTests {
+// Verify that we don't crash on invalid response headers.
+TEST_F(SpdyNetworkTransactionTest, InvalidResponseHeaders) {
+ struct InvalidResponseHeadersTests {
int num_headers;
const char* headers[10];
} test_cases[] = {
- // SYN_REPLY missing status header
+ // Response headers missing status header
{
- 4,
- {spdy_util_.GetPathKey(), "/index.php", spdy_util_.GetVersionKey(),
- "HTTP/1.1", "cookie", "val1", "cookie", "val2", NULL},
+ 3,
+ {spdy_util_.GetPathKey(), "/index.php", "cookie", "val1", "cookie",
+ "val2", NULL},
},
- // SYN_REPLY missing version header
+ // Response headers missing version header
{
- 2, {spdy_util_.GetPathKey(), "/index.php", "status", "200", NULL},
+ 1, {spdy_util_.GetPathKey(), "/index.php", "status", "200", NULL},
},
- // SYN_REPLY with no headers
+ // Response headers with no headers
{
0, {NULL},
},
};
for (size_t i = 0; i < arraysize(test_cases); ++i) {
- SpdyTestUtil spdy_test_util(GetParam().protocol,
- GetParam().priority_to_dependency);
+ SpdyTestUtil spdy_test_util;
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_test_util.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
};
// Construct the reply.
SpdyHeaderBlock reply_headers;
AppendToHeaderBlock(
test_cases[i].headers, test_cases[i].num_headers, &reply_headers);
- std::unique_ptr<SpdySerializedFrame> resp(
+ SpdySerializedFrame resp(
spdy_test_util.ConstructSpdyReply(1, std::move(reply_headers)));
MockRead reads[] = {
- CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3) // EOF
+ CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes,
arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_SPDY_PROTOCOL_ERROR));
}
}
-TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionError) {
- if (spdy_util_.spdy_version() != SPDY3) {
- return;
- }
-
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, CorruptFrameSessionError) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> goaway(spdy_util_.ConstructSpdyGoAway(
- 0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE)."));
- MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 3),
- };
-
- // This is the length field that's too short.
- std::unique_ptr<SpdySerializedFrame> syn_reply_wrong_length(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- size_t right_size =
- syn_reply_wrong_length->size() -
- SpdyConstants::GetControlFrameHeaderSize(spdy_util_.spdy_version());
- size_t wrong_size = right_size - 4;
- test::SetFrameLength(syn_reply_wrong_length.get(),
- wrong_size,
- spdy_util_.spdy_version());
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- MockRead reads[] = {
- MockRead(ASYNC, syn_reply_wrong_length->data(),
- syn_reply_wrong_length->size(), 1),
- CreateMockRead(*body, 2),
- };
-
- SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), nullptr);
- helper.RunToCompletion(&data);
- TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
-}
-
-TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionErrorSpdy4) {
- if (spdy_util_.spdy_version() != HTTP2) {
- return;
- }
-
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
0, GOAWAY_COMPRESSION_ERROR, "Framer error: 6 (DECOMPRESS_FAILURE)."));
- MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2)};
+ MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(goaway, 2)};
// This is the length field that's too short.
- std::unique_ptr<SpdySerializedFrame> syn_reply_wrong_length(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame reply_wrong_length(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
size_t right_size =
- syn_reply_wrong_length->size() -
- SpdyConstants::GetControlFrameHeaderSize(spdy_util_.spdy_version());
+ reply_wrong_length.size() - SpdyConstants::GetFrameHeaderSize(HTTP2);
size_t wrong_size = right_size - 4;
- test::SetFrameLength(syn_reply_wrong_length.get(),
- wrong_size,
- spdy_util_.spdy_version());
+ test::SetFrameLength(&reply_wrong_length, wrong_size, HTTP2);
MockRead reads[] = {
- MockRead(ASYNC, syn_reply_wrong_length->data(),
- syn_reply_wrong_length->size() - 4, 1),
+ MockRead(ASYNC, reply_wrong_length.data(), reply_wrong_length.size() - 4,
+ 1),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_SPDY_COMPRESSION_ERROR));
}
-TEST_P(SpdyNetworkTransactionTest, GoAwayOnDecompressionFailure) {
- if (GetParam().protocol < kProtoHTTP2) {
- // Decompression failures are a stream error in SPDY3.
- return;
- }
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, GoAwayOnDecompressionFailure) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
0, GOAWAY_COMPRESSION_ERROR, "Framer error: 6 (DECOMPRESS_FAILURE)."));
- MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2)};
+ MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(goaway, 2)};
// Read HEADERS with corrupted payload.
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- memset(resp->data() + 12, 0xcf, resp->size() - 12);
- MockRead reads[] = {CreateMockRead(*resp, 1)};
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ memset(resp.data() + 12, 0xcf, resp.size() - 12);
+ MockRead reads[] = {CreateMockRead(resp, 1)};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- NormalSpdyTransactionHelper helper(
- CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
+ NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_SPDY_COMPRESSION_ERROR));
}
-TEST_P(SpdyNetworkTransactionTest, GoAwayOnFrameSizeError) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, GoAwayOnFrameSizeError) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
0, GOAWAY_FRAME_SIZE_ERROR,
"Framer error: 15 (INVALID_CONTROL_FRAME_SIZE)."));
- MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2)};
+ MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(goaway, 2)};
// Read WINDOW_UPDATE with incorrectly-sized payload.
- std::unique_ptr<SpdySerializedFrame> bad_window_update(
+ SpdySerializedFrame bad_window_update(
spdy_util_.ConstructSpdyWindowUpdate(1, 1));
- test::SetFrameLength(bad_window_update.get(),
- bad_window_update->size() - 1,
- spdy_util_.spdy_version());
- MockRead reads[] = {CreateMockRead(*bad_window_update, 1)};
+ test::SetFrameLength(&bad_window_update, bad_window_update.size() - 1, HTTP2);
+ MockRead reads[] = {CreateMockRead(bad_window_update, 1)};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- NormalSpdyTransactionHelper helper(
- CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
+ NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_SPDY_FRAME_SIZE_ERROR, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_SPDY_FRAME_SIZE_ERROR));
}
// Test that we shutdown correctly on write errors.
-TEST_P(SpdyNetworkTransactionTest, WriteError) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, WriteError) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
MockWrite writes[] = {
// We'll write 10 bytes successfully
- MockWrite(ASYNC, req->data(), 10, 1),
+ MockWrite(ASYNC, req.data(), 10, 1),
// Followed by ERROR!
MockWrite(ASYNC, ERR_FAILED, 2),
// Session drains and attempts to write a GOAWAY: Another ERROR!
@@ -3575,7 +3314,7 @@ TEST_P(SpdyNetworkTransactionTest, WriteError) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
EXPECT_TRUE(helper.StartDefaultTest());
@@ -3583,56 +3322,50 @@ TEST_P(SpdyNetworkTransactionTest, WriteError) {
EXPECT_TRUE(data.AllWriteDataConsumed());
EXPECT_TRUE(data.AllReadDataConsumed());
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_FAILED, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_FAILED));
}
// Test that partial writes work.
-TEST_P(SpdyNetworkTransactionTest, PartialWrite) {
- // Chop the SYN_STREAM frame into 5 chunks.
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, PartialWrite) {
+ // Chop the HEADERS frame into 5 chunks.
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
const int kChunks = 5;
- std::unique_ptr<MockWrite[]> writes(ChopWriteFrame(*req.get(), kChunks));
+ std::unique_ptr<MockWrite[]> writes(ChopWriteFrame(req, kChunks));
for (int i = 0; i < kChunks; ++i) {
writes[i].sequence_number = i;
}
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, kChunks),
- CreateMockRead(*body, kChunks + 1),
+ CreateMockRead(resp, kChunks), CreateMockRead(body, kChunks + 1),
MockRead(ASYNC, 0, kChunks + 2) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes.get(), kChunks);
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
}
// Test that the NetLog contains good data for a simple GET request.
-TEST_P(SpdyNetworkTransactionTest, NetLog) {
+TEST_F(SpdyNetworkTransactionTest, NetLog) {
static const char* const kExtraHeaders[] = {
"user-agent", "Chrome",
};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(kExtraHeaders, 1, 1, LOWEST, true));
- MockWrite writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite writes[] = {CreateMockWrite(req, 0)};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
MockRead(ASYNC, 0, 3) // EOF
};
@@ -3640,11 +3373,10 @@ TEST_P(SpdyNetworkTransactionTest, NetLog) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequestWithUserAgent(),
- DEFAULT_PRIORITY,
- log.bound(), GetParam(), NULL);
+ DEFAULT_PRIORITY, log.bound(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
@@ -3657,30 +3389,29 @@ TEST_P(SpdyNetworkTransactionTest, NetLog) {
EXPECT_LT(0u, entries.size());
int pos = 0;
- pos = ExpectLogContainsSomewhere(entries, 0,
- NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST,
- NetLog::PHASE_BEGIN);
- pos = ExpectLogContainsSomewhere(entries, pos + 1,
- NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST,
- NetLog::PHASE_END);
+ pos = ExpectLogContainsSomewhere(
+ entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST,
+ NetLogEventPhase::BEGIN);
+ pos = ExpectLogContainsSomewhere(
+ entries, pos + 1, NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST,
+ NetLogEventPhase::END);
+ pos = ExpectLogContainsSomewhere(
+ entries, pos + 1, NetLogEventType::HTTP_TRANSACTION_READ_HEADERS,
+ NetLogEventPhase::BEGIN);
+ pos = ExpectLogContainsSomewhere(
+ entries, pos + 1, NetLogEventType::HTTP_TRANSACTION_READ_HEADERS,
+ NetLogEventPhase::END);
pos = ExpectLogContainsSomewhere(entries, pos + 1,
- NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS,
- NetLog::PHASE_BEGIN);
+ NetLogEventType::HTTP_TRANSACTION_READ_BODY,
+ NetLogEventPhase::BEGIN);
pos = ExpectLogContainsSomewhere(entries, pos + 1,
- NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS,
- NetLog::PHASE_END);
- pos = ExpectLogContainsSomewhere(entries, pos + 1,
- NetLog::TYPE_HTTP_TRANSACTION_READ_BODY,
- NetLog::PHASE_BEGIN);
- pos = ExpectLogContainsSomewhere(entries, pos + 1,
- NetLog::TYPE_HTTP_TRANSACTION_READ_BODY,
- NetLog::PHASE_END);
+ NetLogEventType::HTTP_TRANSACTION_READ_BODY,
+ NetLogEventPhase::END);
// Check that we logged all the headers correctly
- const NetLog::EventType type = (GetParam().protocol == kProtoSPDY31)
- ? NetLog::TYPE_HTTP2_SESSION_SYN_STREAM
- : NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS;
- pos = ExpectLogContainsSomewhere(entries, 0, type, NetLog::PHASE_NONE);
+ pos = ExpectLogContainsSomewhere(entries, 0,
+ NetLogEventType::HTTP2_SESSION_SEND_HEADERS,
+ NetLogEventPhase::NONE);
base::ListValue* header_list;
ASSERT_TRUE(entries[pos].params.get());
@@ -3694,10 +3425,6 @@ TEST_P(SpdyNetworkTransactionTest, NetLog) {
default_url_.scheme());
expected.push_back(std::string(spdy_util_.GetMethodKey()) + ": GET");
expected.push_back("user-agent: Chrome");
- if (spdy_util_.spdy_version() < HTTP2) {
- // HTTP/2 eliminates use of the :version header.
- expected.push_back(std::string(spdy_util_.GetVersionKey()) + ": HTTP/1.1");
- }
EXPECT_EQ(expected.size(), header_list->GetSize());
for (std::vector<std::string>::const_iterator it = expected.begin();
it != expected.end();
@@ -3712,36 +3439,33 @@ TEST_P(SpdyNetworkTransactionTest, NetLog) {
// that when we read out the maximum amount of data (e.g. we received 50 bytes
// on the network, but issued a Read for only 5 of those bytes) that the data
// flow still works correctly.
-TEST_P(SpdyNetworkTransactionTest, BufferFull) {
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
-
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, BufferFull) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- MockWrite writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite writes[] = {CreateMockWrite(req, 0)};
// 2 data frames in a single read.
- std::unique_ptr<SpdySerializedFrame> data_frame_1(
- framer.CreateDataFrame(1, "goodby", 6, DATA_FLAG_NONE));
- std::unique_ptr<SpdySerializedFrame> data_frame_2(
- framer.CreateDataFrame(1, "e worl", 6, DATA_FLAG_NONE));
+ SpdySerializedFrame data_frame_1(
+ spdy_util_.ConstructSpdyDataFrame(1, "goodby", 6, /*fin=*/false));
+ SpdySerializedFrame data_frame_2(
+ spdy_util_.ConstructSpdyDataFrame(1, "e worl", 6, /*fin=*/false));
const SpdySerializedFrame* data_frames[2] = {
- data_frame_1.get(), data_frame_2.get(),
+ &data_frame_1, &data_frame_2,
};
char combined_data_frames[100];
int combined_data_frames_len =
CombineFrames(data_frames, arraysize(data_frames),
combined_data_frames, arraysize(combined_data_frames));
- std::unique_ptr<SpdySerializedFrame> last_frame(
- framer.CreateDataFrame(1, "d", 1, DATA_FLAG_FIN));
+ SpdySerializedFrame last_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, "d", 1, /*fin=*/true));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
+ CreateMockRead(resp, 1),
MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
MockRead(ASYNC, combined_data_frames, combined_data_frames_len, 3),
MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause
- CreateMockRead(*last_frame, 5),
+ CreateMockRead(last_frame, 5),
MockRead(ASYNC, 0, 6) // EOF
};
@@ -3750,13 +3474,13 @@ TEST_P(SpdyNetworkTransactionTest, BufferFull) {
TestCompletionCallback callback;
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
HttpNetworkTransaction* trans = helper.trans();
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TransactionHelperResult out = helper.output();
out.rv = callback.WaitForResult();
@@ -3797,7 +3521,7 @@ TEST_P(SpdyNetworkTransactionTest, BufferFull) {
// Verify that we consumed all test data.
helper.VerifyDataConsumed();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("goodbye world", out.response_data);
}
@@ -3805,30 +3529,26 @@ TEST_P(SpdyNetworkTransactionTest, BufferFull) {
// Verify that basic buffering works; when multiple data frames arrive
// at the same time, ensure that we don't notify a read completion for
// each data frame individually.
-TEST_P(SpdyNetworkTransactionTest, Buffering) {
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
-
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, Buffering) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- MockWrite writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite writes[] = {CreateMockWrite(req, 0)};
// 4 data frames in a single read.
- std::unique_ptr<SpdySerializedFrame> data_frame(
- framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
- std::unique_ptr<SpdySerializedFrame> data_frame_fin(
- framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN));
- const SpdySerializedFrame* data_frames[4] = {
- data_frame.get(), data_frame.get(), data_frame.get(),
- data_frame_fin.get()};
+ SpdySerializedFrame data_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, "message", 7, /*fin=*/false));
+ SpdySerializedFrame data_frame_fin(
+ spdy_util_.ConstructSpdyDataFrame(1, "message", 7, /*fin=*/true));
+ const SpdySerializedFrame* data_frames[4] = {&data_frame, &data_frame,
+ &data_frame, &data_frame_fin};
char combined_data_frames[100];
int combined_data_frames_len =
CombineFrames(data_frames, arraysize(data_frames),
combined_data_frames, arraysize(combined_data_frames));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
+ CreateMockRead(resp, 1),
MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
MockRead(ASYNC, combined_data_frames, combined_data_frames_len, 3),
MockRead(ASYNC, 0, 4) // EOF
@@ -3837,15 +3557,15 @@ TEST_P(SpdyNetworkTransactionTest, Buffering) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TransactionHelperResult out = helper.output();
out.rv = callback.WaitForResult();
@@ -3891,29 +3611,25 @@ TEST_P(SpdyNetworkTransactionTest, Buffering) {
// Verify that we consumed all test data.
helper.VerifyDataConsumed();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("messagemessagemessagemessage", out.response_data);
}
// Verify the case where we buffer data but read it after it has been buffered.
-TEST_P(SpdyNetworkTransactionTest, BufferedAll) {
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
-
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, BufferedAll) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- MockWrite writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite writes[] = {CreateMockWrite(req, 0)};
// 5 data frames in a single read.
- std::unique_ptr<SpdySerializedFrame> reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> data_frame(
- framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
- std::unique_ptr<SpdySerializedFrame> data_frame_fin(
- framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN));
- const SpdySerializedFrame* frames[5] = {reply.get(), data_frame.get(),
- data_frame.get(), data_frame.get(),
- data_frame_fin.get()};
+ SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame data_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, "message", 7, /*fin=*/false));
+ SpdySerializedFrame data_frame_fin(
+ spdy_util_.ConstructSpdyDataFrame(1, "message", 7, /*fin=*/true));
+ const SpdySerializedFrame* frames[5] = {&reply, &data_frame, &data_frame,
+ &data_frame, &data_frame_fin};
char combined_frames[200];
int combined_frames_len =
CombineFrames(frames, arraysize(frames),
@@ -3927,15 +3643,15 @@ TEST_P(SpdyNetworkTransactionTest, BufferedAll) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TransactionHelperResult out = helper.output();
out.rv = callback.WaitForResult();
@@ -3977,33 +3693,30 @@ TEST_P(SpdyNetworkTransactionTest, BufferedAll) {
// Verify that we consumed all test data.
helper.VerifyDataConsumed();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("messagemessagemessagemessage", out.response_data);
}
// Verify the case where we buffer data and close the connection.
-TEST_P(SpdyNetworkTransactionTest, BufferedClosed) {
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
-
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, BufferedClosed) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- MockWrite writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite writes[] = {CreateMockWrite(req, 0)};
// All data frames in a single read.
// NOTE: We don't FIN the stream.
- std::unique_ptr<SpdySerializedFrame> data_frame(
- framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
- const SpdySerializedFrame* data_frames[4] = {
- data_frame.get(), data_frame.get(), data_frame.get(), data_frame.get()};
+ SpdySerializedFrame data_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, "message", 7, /*fin=*/false));
+ const SpdySerializedFrame* data_frames[4] = {&data_frame, &data_frame,
+ &data_frame, &data_frame};
char combined_data_frames[100];
int combined_data_frames_len =
CombineFrames(data_frames, arraysize(data_frames),
combined_data_frames, arraysize(combined_data_frames));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
+ CreateMockRead(resp, 1),
MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a wait
MockRead(ASYNC, combined_data_frames, combined_data_frames_len, 3),
MockRead(ASYNC, 0, 4) // EOF
@@ -4012,16 +3725,16 @@ TEST_P(SpdyNetworkTransactionTest, BufferedClosed) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TransactionHelperResult out = helper.output();
out.rv = callback.WaitForResult();
@@ -4051,7 +3764,7 @@ TEST_P(SpdyNetworkTransactionTest, BufferedClosed) {
content.append(buf->data(), rv);
} else if (rv < 0) {
// This test intentionally closes the connection, and will get an error.
- EXPECT_EQ(ERR_CONNECTION_CLOSED, rv);
+ EXPECT_THAT(rv, IsError(ERR_CONNECTION_CLOSED));
break;
}
reads_completed++;
@@ -4070,40 +3783,36 @@ TEST_P(SpdyNetworkTransactionTest, BufferedClosed) {
}
// Verify the case where we buffer data and cancel the transaction.
-TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) {
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
-
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, BufferedCancelled) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
- MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4)};
+ MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 4)};
// NOTE: We don't FIN the stream.
- std::unique_ptr<SpdySerializedFrame> data_frame(
- framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
+ SpdySerializedFrame data_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, "message", 7, /*fin=*/false));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a wait
- CreateMockRead(*data_frame, 3),
- MockRead(ASYNC, 0, 5) // EOF
+ CreateMockRead(resp, 1),
+ MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a wait
+ CreateMockRead(data_frame, 3), MockRead(ASYNC, 0, 5) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
TransactionHelperResult out = helper.output();
out.rv = callback.WaitForResult();
@@ -4138,288 +3847,50 @@ TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) {
helper.VerifyDataConsumed();
}
-// Test that if the server requests persistence of settings, that we save
-// the settings in the HttpServerProperties.
-TEST_P(SpdyNetworkTransactionTest, SettingsSaved) {
- if (spdy_util_.spdy_version() >= HTTP2) {
- // HTTP/2 doesn't support settings persistence.
- return;
- }
- static const SpdyHeaderInfo kSynReplyInfo = {
- SYN_REPLY, // Syn Reply
- 1, // Stream ID
- 0, // Associated Stream ID
- ConvertRequestPriorityToSpdyPriority(LOWEST, spdy_util_.spdy_version()),
- 0, // Weight (unused)
- CONTROL_FLAG_NONE, // Control Flags
- RST_STREAM_INVALID, // Status
- NULL, // Data
- 0, // Data Length
- DATA_FLAG_NONE // Data Flags
- };
-
- BoundNetLog net_log;
- NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- net_log, GetParam(), NULL);
- helper.RunPreTestSetup();
-
- // Verify that no settings exist initially.
- url::SchemeHostPort spdy_server(default_url_);
- SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
- EXPECT_TRUE(spdy_session_pool->http_server_properties()
- ->GetSpdySettings(spdy_server)
- .empty());
-
- // Construct the request.
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- MockWrite writes[] = {CreateMockWrite(*req, 0)};
-
- // Construct the reply.
- SpdyHeaderBlock reply_headers;
- reply_headers[spdy_util_.GetStatusKey()] = "200";
- reply_headers[spdy_util_.GetVersionKey()] = "HTTP/1.1";
- std::unique_ptr<SpdySerializedFrame> reply(
- spdy_util_.ConstructSpdyFrame(kSynReplyInfo, std::move(reply_headers)));
-
- const SpdySettingsIds kSampleId1 = SETTINGS_UPLOAD_BANDWIDTH;
- unsigned int kSampleValue1 = 0x0a0a0a0a;
- const SpdySettingsIds kSampleId2 = SETTINGS_DOWNLOAD_BANDWIDTH;
- unsigned int kSampleValue2 = 0x0b0b0b0b;
- const SpdySettingsIds kSampleId3 = SETTINGS_ROUND_TRIP_TIME;
- unsigned int kSampleValue3 = 0x0c0c0c0c;
- std::unique_ptr<SpdySerializedFrame> settings_frame;
- {
- // Construct the SETTINGS frame.
- SettingsMap settings;
- // First add a persisted setting.
- settings[kSampleId1] =
- SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST, kSampleValue1);
- // Next add a non-persisted setting.
- settings[kSampleId2] =
- SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kSampleValue2);
- // Next add another persisted setting.
- settings[kSampleId3] =
- SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST, kSampleValue3);
- settings_frame.reset(spdy_util_.ConstructSpdySettings(settings));
- }
-
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- MockRead reads[] = {
- CreateMockRead(*reply, 1),
- CreateMockRead(*body, 2),
- CreateMockRead(*settings_frame, 3),
- MockRead(ASYNC, 0, 4) // EOF
- };
-
- SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- helper.AddData(&data);
- helper.RunDefaultTest();
- helper.VerifyDataConsumed();
- TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
- EXPECT_EQ("HTTP/1.1 200", out.status_line);
- EXPECT_EQ("hello!", out.response_data);
-
- {
- // Verify we had two persisted settings.
- const SettingsMap& settings_map =
- spdy_session_pool->http_server_properties()->GetSpdySettings(
- spdy_server);
- ASSERT_EQ(2u, settings_map.size());
-
- // Verify the first persisted setting.
- SettingsMap::const_iterator it1 = settings_map.find(kSampleId1);
- EXPECT_TRUE(it1 != settings_map.end());
- SettingsFlagsAndValue flags_and_value1 = it1->second;
- EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1.first);
- EXPECT_EQ(kSampleValue1, flags_and_value1.second);
-
- // Verify the second persisted setting.
- SettingsMap::const_iterator it3 = settings_map.find(kSampleId3);
- EXPECT_TRUE(it3 != settings_map.end());
- SettingsFlagsAndValue flags_and_value3 = it3->second;
- EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value3.first);
- EXPECT_EQ(kSampleValue3, flags_and_value3.second);
- }
-}
-
-// Test that when there are settings saved that they are sent back to the
-// server upon session establishment.
-TEST_P(SpdyNetworkTransactionTest, SettingsPlayback) {
- if (spdy_util_.spdy_version() >= HTTP2) {
- // HTTP/2 doesn't support settings persistence.
- return;
- }
- static const SpdyHeaderInfo kSynReplyInfo = {
- SYN_REPLY, // Syn Reply
- 1, // Stream ID
- 0, // Associated Stream ID
- ConvertRequestPriorityToSpdyPriority(LOWEST, spdy_util_.spdy_version()),
- 0, // Weight (unused)
- CONTROL_FLAG_NONE, // Control Flags
- RST_STREAM_INVALID, // Status
- NULL, // Data
- 0, // Data Length
- DATA_FLAG_NONE // Data Flags
- };
-
- BoundNetLog net_log;
- NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- net_log, GetParam(), NULL);
- helper.RunPreTestSetup();
-
- SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
-
- SpdySessionPoolPeer pool_peer(spdy_session_pool);
- pool_peer.SetEnableSendingInitialData(true);
-
- // Verify that no settings exist initially.
- url::SchemeHostPort spdy_server(default_url_);
- EXPECT_TRUE(spdy_session_pool->http_server_properties()
- ->GetSpdySettings(spdy_server)
- .empty());
-
- const SpdySettingsIds kSampleId1 = SETTINGS_MAX_CONCURRENT_STREAMS;
- unsigned int kSampleValue1 = 0x0a0a0a0a;
- const SpdySettingsIds kSampleId2 = SETTINGS_INITIAL_WINDOW_SIZE;
- unsigned int kSampleValue2 = 0x0c0c0c0c;
-
- // First add a persisted setting.
- spdy_session_pool->http_server_properties()->SetSpdySetting(
- spdy_server, kSampleId1, SETTINGS_FLAG_PLEASE_PERSIST, kSampleValue1);
-
- // Next add another persisted setting.
- spdy_session_pool->http_server_properties()->SetSpdySetting(
- spdy_server, kSampleId2, SETTINGS_FLAG_PLEASE_PERSIST, kSampleValue2);
-
- EXPECT_EQ(2u, spdy_session_pool->http_server_properties()
- ->GetSpdySettings(spdy_server)
- .size());
-
- // Construct the initial SETTINGS frame.
- SettingsMap initial_settings;
- initial_settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
- SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams);
- std::unique_ptr<SpdySerializedFrame> initial_settings_frame(
- spdy_util_.ConstructSpdySettings(initial_settings));
-
- // Construct the persisted SETTINGS frame.
- const SettingsMap& settings =
- spdy_session_pool->http_server_properties()->GetSpdySettings(spdy_server);
- std::unique_ptr<SpdySerializedFrame> settings_frame(
- spdy_util_.ConstructSpdySettings(settings));
-
- // Construct the request.
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
-
- MockWrite writes[] = {
- CreateMockWrite(*initial_settings_frame, 0),
- CreateMockWrite(*settings_frame, 1),
- CreateMockWrite(*req, 2),
- };
-
- // Construct the reply.
- SpdyHeaderBlock reply_headers;
- reply_headers[spdy_util_.GetStatusKey()] = "200";
- reply_headers[spdy_util_.GetVersionKey()] = "HTTP/1.1";
- std::unique_ptr<SpdySerializedFrame> reply(
- spdy_util_.ConstructSpdyFrame(kSynReplyInfo, std::move(reply_headers)));
-
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- MockRead reads[] = {
- CreateMockRead(*reply, 3),
- CreateMockRead(*body, 4),
- MockRead(ASYNC, 0, 5) // EOF
- };
-
- SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- helper.AddData(&data);
- helper.RunDefaultTest();
- helper.VerifyDataConsumed();
- TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
- EXPECT_EQ("HTTP/1.1 200", out.status_line);
- EXPECT_EQ("hello!", out.response_data);
-
- {
- // Verify we had two persisted settings.
- const SettingsMap& settings_map =
- spdy_session_pool->http_server_properties()->GetSpdySettings(
- spdy_server);
- ASSERT_EQ(2u, settings_map.size());
-
- // Verify the first persisted setting.
- SettingsMap::const_iterator it1 = settings_map.find(kSampleId1);
- EXPECT_TRUE(it1 != settings_map.end());
- SettingsFlagsAndValue flags_and_value1 = it1->second;
- EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1.first);
- EXPECT_EQ(kSampleValue1, flags_and_value1.second);
-
- // Verify the second persisted setting.
- SettingsMap::const_iterator it2 = settings_map.find(kSampleId2);
- EXPECT_TRUE(it2 != settings_map.end());
- SettingsFlagsAndValue flags_and_value2 = it2->second;
- EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value2.first);
- EXPECT_EQ(kSampleValue2, flags_and_value2.second);
- }
-}
-
-TEST_P(SpdyNetworkTransactionTest, GoAwayWithActiveStream) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, GoAwayWithActiveStream) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- MockWrite writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite writes[] = {CreateMockWrite(req, 0)};
- std::unique_ptr<SpdySerializedFrame> go_away(
- spdy_util_.ConstructSpdyGoAway());
+ SpdySerializedFrame go_away(spdy_util_.ConstructSpdyGoAway());
MockRead reads[] = {
- CreateMockRead(*go_away, 1),
+ CreateMockRead(go_away, 1),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.AddData(&data);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_ABORTED, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_ABORTED));
}
-TEST_P(SpdyNetworkTransactionTest, CloseWithActiveStream) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, CloseWithActiveStream) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- MockWrite writes[] = {CreateMockWrite(*req, 0)};
+ MockWrite writes[] = {CreateMockWrite(req, 0)};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp, 1), MockRead(SYNCHRONOUS, 0, 2) // EOF
+ CreateMockRead(resp, 1), MockRead(SYNCHRONOUS, 0, 2) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- BoundNetLog log;
+
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- log, GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
- HttpNetworkTransaction* trans = helper.trans();
-
- TestCompletionCallback callback;
- TransactionHelperResult out;
- out.rv = trans->Start(&CreateGetRequest(), callback.callback(), log);
+ helper.StartDefaultTest();
+ EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
- EXPECT_EQ(out.rv, ERR_IO_PENDING);
- out.rv = callback.WaitForResult();
- EXPECT_EQ(out.rv, ERR_CONNECTION_CLOSED);
+ helper.WaitForCallbackToComplete();
+ EXPECT_THAT(helper.output().rv, IsError(ERR_CONNECTION_CLOSED));
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
EXPECT_TRUE(response->headers);
EXPECT_TRUE(response->was_fetched_via_spdy);
- out.rv = ReadTransaction(trans, &out.response_data);
- EXPECT_EQ(ERR_CONNECTION_CLOSED, out.rv);
// Verify that we consumed all test data.
helper.VerifyDataConsumed();
@@ -4428,28 +3899,22 @@ TEST_P(SpdyNetworkTransactionTest, CloseWithActiveStream) {
// Retry with HTTP/1.1 when receiving HTTP_1_1_REQUIRED. Note that no actual
// protocol negotiation happens, instead this test forces protocols for both
// sockets.
-TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredRetry) {
- // HTTP_1_1_REQUIRED is only supported by HTTP/2.
- if (spdy_util_.spdy_version() < HTTP2)
- return;
-
+TEST_F(SpdyNetworkTransactionTest, HTTP11RequiredRetry) {
HttpRequestInfo request;
request.method = "GET";
request.url = default_url_;
- std::unique_ptr<SpdySessionDependencies> session_deps(
- CreateSpdySessionDependencies(GetParam()));
// Do not force SPDY so that second socket can negotiate HTTP/1.1.
- NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(),
- GetParam(), std::move(session_deps));
+ NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
+ NetLogWithSource(), nullptr);
// First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdySyn(1, std::move(headers), LOWEST, true));
- MockWrite writes0[] = {CreateMockWrite(*req, 0)};
- std::unique_ptr<SpdySerializedFrame> go_away(spdy_util_.ConstructSpdyGoAway(
+ SpdySerializedFrame req(
+ spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
+ MockWrite writes0[] = {CreateMockWrite(req, 0)};
+ SpdySerializedFrame go_away(spdy_util_.ConstructSpdyGoAway(
0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please."));
- MockRead reads0[] = {CreateMockRead(*go_away, 1)};
+ MockRead reads0[] = {CreateMockRead(go_away, 1)};
SequencedSocketData data0(reads0, arraysize(reads0), writes0,
arraysize(writes0));
@@ -4457,10 +3922,9 @@ TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredRetry) {
new SSLSocketDataProvider(ASYNC, OK));
// Expect HTTP/2 protocols too in SSLConfig.
ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoHTTP2);
- ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY31);
ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11);
// Force SPDY.
- ssl_provider0->SetNextProto(GetParam().protocol);
+ ssl_provider0->next_proto = kProtoHTTP2;
helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
// Second socket: falling back to HTTP/1.1.
@@ -4480,7 +3944,7 @@ TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredRetry) {
// Expect only HTTP/1.1 protocol in SSLConfig.
ssl_provider1->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11);
// Force HTTP/1.1.
- ssl_provider1->SetNextProto(kProtoHTTP11);
+ ssl_provider1->next_proto = kProtoHTTP11;
helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
HttpServerProperties* http_server_properties =
@@ -4500,41 +3964,35 @@ TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredRetry) {
EXPECT_FALSE(response->was_fetched_via_spdy);
EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
response->connection_info);
- EXPECT_TRUE(response->was_npn_negotiated);
+ EXPECT_TRUE(response->was_alpn_negotiated);
EXPECT_TRUE(request.url.SchemeIs("https"));
EXPECT_EQ("127.0.0.1", response->socket_address.host());
EXPECT_EQ(443, response->socket_address.port());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(helper.trans(), &response_data));
+ ASSERT_THAT(ReadTransaction(helper.trans(), &response_data), IsOk());
EXPECT_EQ("hello", response_data);
}
// Retry with HTTP/1.1 to the proxy when receiving HTTP_1_1_REQUIRED from the
// proxy. Note that no actual protocol negotiation happens, instead this test
// forces protocols for both sockets.
-TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredProxyRetry) {
- // HTTP_1_1_REQUIRED is only supported by HTTP/2.
- if (spdy_util_.spdy_version() < HTTP2)
- return;
-
+TEST_F(SpdyNetworkTransactionTest, HTTP11RequiredProxyRetry) {
HttpRequestInfo request;
request.method = "GET";
request.url = default_url_;
- std::unique_ptr<SpdySessionDependencies> session_deps(
- CreateSpdySessionDependencies(
- GetParam(),
- ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70")));
+ auto session_deps = base::MakeUnique<SpdySessionDependencies>(
+ ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70"));
// Do not force SPDY so that second socket can negotiate HTTP/1.1.
- NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(),
- GetParam(), std::move(session_deps));
+ NormalSpdyTransactionHelper helper(
+ request, DEFAULT_PRIORITY, NetLogWithSource(), std::move(session_deps));
// First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyConnect(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
nullptr, 0, 1, LOWEST, HostPortPair("www.example.org", 443)));
- MockWrite writes0[] = {CreateMockWrite(*req, 0)};
- std::unique_ptr<SpdySerializedFrame> go_away(spdy_util_.ConstructSpdyGoAway(
+ MockWrite writes0[] = {CreateMockWrite(req, 0)};
+ SpdySerializedFrame go_away(spdy_util_.ConstructSpdyGoAway(
0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please."));
- MockRead reads0[] = {CreateMockRead(*go_away, 1)};
+ MockRead reads0[] = {CreateMockRead(go_away, 1)};
SequencedSocketData data0(reads0, arraysize(reads0), writes0,
arraysize(writes0));
@@ -4542,10 +4000,9 @@ TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredProxyRetry) {
new SSLSocketDataProvider(ASYNC, OK));
// Expect HTTP/2 protocols too in SSLConfig.
ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoHTTP2);
- ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY31);
ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11);
// Force SPDY.
- ssl_provider0->SetNextProto(GetParam().protocol);
+ ssl_provider0->next_proto = kProtoHTTP2;
helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
// Second socket: retry using HTTP/1.1.
@@ -4575,7 +4032,7 @@ TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredProxyRetry) {
// Expect only HTTP/1.1 protocol in SSLConfig.
ssl_provider1->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11);
// Force HTTP/1.1.
- ssl_provider1->SetNextProto(kProtoHTTP11);
+ ssl_provider1->next_proto = kProtoHTTP11;
helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
// A third socket is needed for the tunnelled connection.
@@ -4602,23 +4059,22 @@ TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredProxyRetry) {
EXPECT_FALSE(response->was_fetched_via_spdy);
EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
response->connection_info);
- EXPECT_FALSE(response->was_npn_negotiated);
+ EXPECT_FALSE(response->was_alpn_negotiated);
EXPECT_TRUE(request.url.SchemeIs("https"));
EXPECT_EQ("127.0.0.1", response->socket_address.host());
EXPECT_EQ(70, response->socket_address.port());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(helper.trans(), &response_data));
+ ASSERT_THAT(ReadTransaction(helper.trans(), &response_data), IsOk());
EXPECT_EQ("hello", response_data);
}
// Test to make sure we can correctly connect through a proxy.
-TEST_P(SpdyNetworkTransactionTest, ProxyConnect) {
+TEST_F(SpdyNetworkTransactionTest, ProxyConnect) {
+ auto session_deps = base::MakeUnique<SpdySessionDependencies>(
+ ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
- helper.session_deps() = CreateSpdySessionDependencies(
- GetParam(), ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
- helper.SetSession(
- SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get()));
+ NetLogWithSource(),
+ std::move(session_deps));
helper.RunPreTestSetup();
HttpNetworkTransaction* trans = helper.trans();
@@ -4627,21 +4083,18 @@ TEST_P(SpdyNetworkTransactionTest, ProxyConnect) {
"Host: www.example.org:443\r\n"
"Proxy-Connection: keep-alive\r\n\r\n"};
const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, kConnect443, arraysize(kConnect443) - 1, 0),
- CreateMockWrite(*req, 2),
+ CreateMockWrite(req, 2),
};
MockRead reads[] = {
MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1),
- CreateMockRead(*resp, 3),
- CreateMockRead(*body.get(), 4),
+ CreateMockRead(resp, 3), CreateMockRead(body, 4),
MockRead(ASYNC, 0, 0, 5),
};
std::unique_ptr<SequencedSocketData> data(new SequencedSocketData(
@@ -4650,20 +4103,20 @@ TEST_P(SpdyNetworkTransactionTest, ProxyConnect) {
helper.AddData(data.get());
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
EXPECT_EQ(0, rv);
- // Verify the SYN_REPLY.
+ // Verify the response headers.
HttpResponseInfo response = *trans->GetResponseInfo();
ASSERT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans, &response_data));
+ ASSERT_THAT(ReadTransaction(trans, &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
helper.VerifyDataConsumed();
}
@@ -4671,39 +4124,33 @@ TEST_P(SpdyNetworkTransactionTest, ProxyConnect) {
// Test to make sure we can correctly connect through a proxy to
// www.example.org, if there already exists a direct spdy connection to
// www.example.org. See https://crbug.com/49874.
-TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
- // When setting up the first transaction, we store the SpdySessionPool so that
- // we can use the same pool in the second transaction.
- NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
-
+TEST_F(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
// Use a proxy service which returns a proxy fallback list from DIRECT to
// myproxy:70. For this test there will be no fallback, so it is equivalent
// to simply DIRECT. The reason for appending the second proxy is to verify
// that the session pool key used does is just "DIRECT".
- helper.session_deps() = CreateSpdySessionDependencies(
- GetParam(),
+ auto session_deps = base::MakeUnique<SpdySessionDependencies>(
ProxyService::CreateFixedFromPacResult("DIRECT; PROXY myproxy:70"));
- helper.SetSession(
- SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get()));
+ // When setting up the first transaction, we store the SpdySessionPool so that
+ // we can use the same pool in the second transaction.
+ NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
+ NetLogWithSource(),
+ std::move(session_deps));
SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
helper.RunPreTestSetup();
// Construct and send a simple GET request.
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
+ CreateMockWrite(req, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3), // Force a pause
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
@@ -4712,8 +4159,8 @@ TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
TestCompletionCallback callback;
TransactionHelperResult out;
- out.rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
+ out.rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
EXPECT_EQ(out.rv, ERR_IO_PENDING);
out.rv = callback.WaitForResult();
@@ -4723,7 +4170,7 @@ TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
EXPECT_TRUE(response->headers);
EXPECT_TRUE(response->was_fetched_via_spdy);
out.rv = ReadTransaction(trans, &out.response_data);
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
out.status_line = response->headers->GetStatusLine();
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
@@ -4740,8 +4187,7 @@ TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
// New SpdyTestUtil instance for the session that will be used for the
// proxy connection.
- SpdyTestUtil spdy_util_2(GetParam().protocol,
- GetParam().priority_to_dependency);
+ SpdyTestUtil spdy_util_2;
// Set up data for the proxy connection.
const char kConnect443[] = {
@@ -4749,21 +4195,18 @@ TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
"Host: www.example.org:443\r\n"
"Proxy-Connection: keep-alive\r\n\r\n"};
const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
- std::unique_ptr<SpdySerializedFrame> req2(spdy_util_2.ConstructSpdyGet(
+ SpdySerializedFrame req2(spdy_util_2.ConstructSpdyGet(
GetDefaultUrlWithPath("/foo.dat").c_str(), 1, LOWEST));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_2.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_2.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp2(spdy_util_2.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body2(spdy_util_2.ConstructSpdyDataFrame(1, true));
MockWrite writes2[] = {
MockWrite(SYNCHRONOUS, kConnect443, arraysize(kConnect443) - 1, 0),
- CreateMockWrite(*req2, 2),
+ CreateMockWrite(req2, 2),
};
MockRead reads2[] = {
MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1),
- CreateMockRead(*resp2, 3),
- CreateMockRead(*body2, 4),
+ CreateMockRead(resp2, 3), CreateMockRead(body2, 4),
MockRead(ASYNC, 0, 5) // EOF
};
@@ -4775,27 +4218,19 @@ TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
request_proxy.method = "GET";
request_proxy.url = GURL(GetDefaultUrlWithPath("/foo.dat"));
request_proxy.load_flags = 0;
- std::unique_ptr<SpdySessionDependencies> ssd_proxy(
- CreateSpdySessionDependencies(GetParam()));
- // Ensure that this transaction uses the same SpdySessionPool.
- std::unique_ptr<HttpNetworkSession> session_proxy(
- SpdySessionDependencies::SpdyCreateSession(ssd_proxy.get()));
- NormalSpdyTransactionHelper helper_proxy(request_proxy, DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
- HttpNetworkSessionPeer session_peer(session_proxy.get());
- std::unique_ptr<ProxyService> proxy_service(
+ auto session_deps_proxy = base::MakeUnique<SpdySessionDependencies>(
ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
- session_peer.SetProxyService(proxy_service.get());
- helper_proxy.session_deps().swap(ssd_proxy);
- helper_proxy.SetSession(std::move(session_proxy));
+ NormalSpdyTransactionHelper helper_proxy(request_proxy, DEFAULT_PRIORITY,
+ NetLogWithSource(),
+ std::move(session_deps_proxy));
helper_proxy.RunPreTestSetup();
helper_proxy.AddData(data_proxy.get());
HttpNetworkTransaction* trans_proxy = helper_proxy.trans();
TestCompletionCallback callback_proxy;
- int rv = trans_proxy->Start(
- &request_proxy, callback_proxy.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans_proxy->Start(&request_proxy, callback_proxy.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback_proxy.WaitForResult();
EXPECT_EQ(0, rv);
@@ -4804,7 +4239,7 @@ TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
EXPECT_EQ("HTTP/1.1 200", response_proxy.headers->GetStatusLine());
std::string response_data;
- ASSERT_EQ(OK, ReadTransaction(trans_proxy, &response_data));
+ ASSERT_THAT(ReadTransaction(trans_proxy, &response_data), IsOk());
EXPECT_EQ("hello!", response_data);
helper_proxy.VerifyDataConsumed();
@@ -4814,33 +4249,29 @@ TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
// on a new connection, if the connection was previously known to be good.
// This can happen when a server reboots without saying goodbye, or when
// we're behind a NAT that masked the RST.
-TEST_P(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) {
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+TEST_F(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) {
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
MockRead(ASYNC, ERR_IO_PENDING, 3),
MockRead(ASYNC, ERR_CONNECTION_RESET, 4),
};
MockRead reads2[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
MockRead(ASYNC, 0, 3) // EOF
};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
// In all cases the connection will be reset before req3 can be
// dispatched, destroying both streams.
spdy_util_.UpdateWithStreamDestruction(1);
- std::unique_ptr<SpdySerializedFrame> req3(
+ SpdySerializedFrame req3(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST, true));
- MockWrite writes1[] = {CreateMockWrite(*req, 0), CreateMockWrite(*req3, 5)};
- MockWrite writes2[] = {CreateMockWrite(*req, 0)};
+ MockWrite writes1[] = {CreateMockWrite(req, 0), CreateMockWrite(req3, 5)};
+ MockWrite writes2[] = {CreateMockWrite(req, 0)};
// This test has a couple of variants.
enum {
@@ -4860,19 +4291,18 @@ TEST_P(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) {
arraysize(writes2));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.AddData(&data1);
helper.AddData(&data2);
helper.RunPreTestSetup();
for (int i = 0; i < 2; ++i) {
- std::unique_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
+ HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
TestCompletionCallback callback;
- int rv = trans->Start(
- &helper.request(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans.Start(&helper.request(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// On the second transaction, we trigger the RST.
if (i == 1) {
if (variant == VARIANT_RST_DURING_READ_COMPLETION) {
@@ -4885,15 +4315,15 @@ TEST_P(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) {
data1.Resume();
}
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
+ const HttpResponseInfo* response = trans.GetResponseInfo();
ASSERT_TRUE(response);
EXPECT_TRUE(response->headers);
EXPECT_TRUE(response->was_fetched_via_spdy);
std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_EQ(OK, rv);
+ rv = ReadTransaction(&trans, &response_data);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
EXPECT_EQ("hello!", response_data);
base::RunLoop().RunUntilIdle();
@@ -4904,79 +4334,22 @@ TEST_P(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) {
}
}
-// Test that turning SPDY on and off works properly.
-TEST_P(SpdyNetworkTransactionTest, DISABLED_SpdyOnOffToggle) {
- HttpStreamFactory::set_spdy_enabled(true);
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- MockWrite spdy_writes[] = {CreateMockWrite(*req, 0)};
-
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- MockRead spdy_reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
- MockRead(ASYNC, 0, 3) // EOF
- };
-
- SequencedSocketData data(spdy_reads, arraysize(spdy_reads), spdy_writes,
- arraysize(spdy_writes));
- NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
- helper.RunToCompletion(&data);
- TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
- EXPECT_EQ("HTTP/1.1 200", out.status_line);
- EXPECT_EQ("hello!", out.response_data);
-
- HttpStreamFactory::set_spdy_enabled(false);
- MockWrite http_writes[] = {
- MockWrite(SYNCHRONOUS, 0,
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
-
- MockRead http_reads[] = {
- MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n\r\n"),
- MockRead(SYNCHRONOUS, 2, "hello from http"),
- MockRead(SYNCHRONOUS, OK, 3),
- };
- SequencedSocketData data2(http_reads, arraysize(http_reads), http_writes,
- arraysize(http_writes));
- NormalSpdyTransactionHelper helper2(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
- helper2.SetSpdyDisabled();
- helper2.RunToCompletion(&data2);
- TransactionHelperResult out2 = helper2.output();
- EXPECT_EQ(OK, out2.rv);
- EXPECT_EQ("HTTP/1.1 200 OK", out2.status_line);
- EXPECT_EQ("hello from http", out2.response_data);
-
- HttpStreamFactory::set_spdy_enabled(true);
-}
-
// Tests that Basic authentication works over SPDY
-TEST_P(SpdyNetworkTransactionTest, SpdyBasicAuth) {
- HttpStreamFactory::set_spdy_enabled(true);
-
+TEST_F(SpdyNetworkTransactionTest, SpdyBasicAuth) {
// The first request will be a bare GET, the second request will be a
// GET with an Authorization header.
- std::unique_ptr<SpdySerializedFrame> req_get(
+ SpdySerializedFrame req_get(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
// Will be refused for lack of auth.
spdy_util_.UpdateWithStreamDestruction(1);
const char* const kExtraAuthorizationHeaders[] = {
"authorization", "Basic Zm9vOmJhcg=="
};
- std::unique_ptr<SpdySerializedFrame> req_get_authorization(
- spdy_util_.ConstructSpdyGet(kExtraAuthorizationHeaders,
- arraysize(kExtraAuthorizationHeaders) / 2, 3,
- LOWEST, true));
+ SpdySerializedFrame req_get_authorization(spdy_util_.ConstructSpdyGet(
+ kExtraAuthorizationHeaders, arraysize(kExtraAuthorizationHeaders) / 2, 3,
+ LOWEST, true));
MockWrite spdy_writes[] = {
- CreateMockWrite(*req_get, 0), CreateMockWrite(*req_get_authorization, 3),
+ CreateMockWrite(req_get, 0), CreateMockWrite(req_get_authorization, 3),
};
// The first response is a 401 authentication challenge, and the second
@@ -4986,41 +4359,37 @@ TEST_P(SpdyNetworkTransactionTest, SpdyBasicAuth) {
"www-authenticate",
"Basic realm=\"MyRealm\""
};
- std::unique_ptr<SpdySerializedFrame> resp_authentication(
- spdy_util_.ConstructSpdySynReplyError(
- "401 Authentication Required", kExtraAuthenticationHeaders,
- arraysize(kExtraAuthenticationHeaders) / 2, 1));
- std::unique_ptr<SpdySerializedFrame> body_authentication(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> resp_data(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> body_data(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
+ SpdySerializedFrame resp_authentication(spdy_util_.ConstructSpdyReplyError(
+ "401 Authentication Required", kExtraAuthenticationHeaders,
+ arraysize(kExtraAuthenticationHeaders) / 2, 1));
+ SpdySerializedFrame body_authentication(
+ spdy_util_.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame resp_data(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame body_data(spdy_util_.ConstructSpdyDataFrame(3, true));
MockRead spdy_reads[] = {
- CreateMockRead(*resp_authentication, 1),
- CreateMockRead(*body_authentication, 2),
- CreateMockRead(*resp_data, 4),
- CreateMockRead(*body_data, 5),
+ CreateMockRead(resp_authentication, 1),
+ CreateMockRead(body_authentication, 2),
+ CreateMockRead(resp_data, 4),
+ CreateMockRead(body_data, 5),
MockRead(ASYNC, 0, 6),
};
SequencedSocketData data(spdy_reads, arraysize(spdy_reads), spdy_writes,
arraysize(spdy_writes));
HttpRequestInfo request(CreateGetRequest());
- BoundNetLog net_log;
NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
- net_log, GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
- HttpNetworkTransaction* trans = helper.trans();
- TestCompletionCallback callback;
- const int rv_start = trans->Start(&request, callback.callback(), net_log);
- EXPECT_EQ(ERR_IO_PENDING, rv_start);
- const int rv_start_complete = callback.WaitForResult();
- EXPECT_EQ(OK, rv_start_complete);
+ helper.StartDefaultTest();
+ EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
+
+ helper.WaitForCallbackToComplete();
+ EXPECT_THAT(helper.output().rv, IsOk());
// Make sure the response has an auth challenge.
+ HttpNetworkTransaction* trans = helper.trans();
const HttpResponseInfo* const response_start = trans->GetResponseInfo();
ASSERT_TRUE(response_start);
ASSERT_TRUE(response_start->headers);
@@ -5038,9 +4407,9 @@ TEST_P(SpdyNetworkTransactionTest, SpdyBasicAuth) {
TestCompletionCallback callback_restart;
const int rv_restart = trans->RestartWithAuth(
credentials, callback_restart.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv_restart);
+ EXPECT_THAT(rv_restart, IsError(ERR_IO_PENDING));
const int rv_restart_complete = callback_restart.WaitForResult();
- EXPECT_EQ(OK, rv_restart_complete);
+ EXPECT_THAT(rv_restart_complete, IsOk());
// TODO(cbentzel): This is actually the same response object as before, but
// data has changed.
const HttpResponseInfo* const response_restart = trans->GetResponseInfo();
@@ -5050,45 +4419,40 @@ TEST_P(SpdyNetworkTransactionTest, SpdyBasicAuth) {
EXPECT_TRUE(response_restart->auth_challenge.get() == NULL);
}
-TEST_P(SpdyNetworkTransactionTest, ServerPushWithHeaders) {
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+TEST_F(SpdyNetworkTransactionTest, ServerPushWithHeaders) {
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0),
+ CreateMockWrite(stream1_syn, 0),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
SpdyHeaderBlock initial_headers;
spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
&initial_headers);
- std::unique_ptr<SpdySerializedFrame> stream2_syn(
- spdy_util_.ConstructInitialSpdyPushFrame(std::move(initial_headers), 2,
- 1));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructInitialSpdyPushFrame(
+ std::move(initial_headers), 2, 1));
SpdyHeaderBlock late_headers;
late_headers[spdy_util_.GetStatusKey()] = "200";
- late_headers[spdy_util_.GetVersionKey()] = "HTTP/1.1";
late_headers["hello"] = "bye";
- std::unique_ptr<SpdySerializedFrame> stream2_headers(
- spdy_util_.ConstructSpdyResponseHeaders(2, std::move(late_headers),
- false));
+ SpdySerializedFrame stream2_headers(spdy_util_.ConstructSpdyResponseHeaders(
+ 2, std::move(late_headers), false));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
const char kPushedData[] = "pushed";
- std::unique_ptr<SpdySerializedFrame> stream2_body(
- spdy_util_.ConstructSpdyBodyFrame(2, kPushedData, strlen(kPushedData),
- true));
+ SpdySerializedFrame stream2_body(spdy_util_.ConstructSpdyDataFrame(
+ 2, kPushedData, strlen(kPushedData), true));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1),
- CreateMockRead(*stream2_syn, 2),
- CreateMockRead(*stream2_headers, 3),
- CreateMockRead(*stream1_body, 4, SYNCHRONOUS),
- CreateMockRead(*stream2_body, 5),
+ CreateMockRead(stream1_reply, 1),
+ CreateMockRead(stream2_syn, 2),
+ CreateMockRead(stream2_headers, 3),
+ CreateMockRead(stream1_body, 4, SYNCHRONOUS),
+ CreateMockRead(stream2_body, 5),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
};
@@ -5101,7 +4465,7 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithHeaders) {
&response2,
expected_push_result);
- // Verify the SYN_REPLY.
+ // Verify the response headers.
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
@@ -5110,40 +4474,35 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithHeaders) {
EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
}
-TEST_P(SpdyNetworkTransactionTest, ServerPushClaimBeforeHeaders) {
+TEST_F(SpdyNetworkTransactionTest, ServerPushClaimBeforeHeaders) {
// We push a stream and attempt to claim it before the headers come down.
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS),
+ CreateMockWrite(stream1_syn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
SpdyHeaderBlock initial_headers;
spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
&initial_headers);
- std::unique_ptr<SpdySerializedFrame> stream2_syn(
- spdy_util_.ConstructInitialSpdyPushFrame(std::move(initial_headers), 2,
- 1));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructInitialSpdyPushFrame(
+ std::move(initial_headers), 2, 1));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
SpdyHeaderBlock late_headers;
late_headers[spdy_util_.GetStatusKey()] = "200";
- late_headers[spdy_util_.GetVersionKey()] = "HTTP/1.1";
late_headers["hello"] = "bye";
- std::unique_ptr<SpdySerializedFrame> stream2_headers(
- spdy_util_.ConstructSpdyResponseHeaders(2, std::move(late_headers),
- false));
+ SpdySerializedFrame stream2_headers(spdy_util_.ConstructSpdyResponseHeaders(
+ 2, std::move(late_headers), false));
const char kPushedData[] = "pushed";
- std::unique_ptr<SpdySerializedFrame> stream2_body(
- spdy_util_.ConstructSpdyBodyFrame(2, kPushedData, strlen(kPushedData),
- true));
+ SpdySerializedFrame stream2_body(spdy_util_.ConstructSpdyDataFrame(
+ 2, kPushedData, strlen(kPushedData), true));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1), CreateMockRead(*stream2_syn, 2),
- CreateMockRead(*stream1_body, 3), MockRead(ASYNC, ERR_IO_PENDING, 4),
- CreateMockRead(*stream2_headers, 5), CreateMockRead(*stream2_body, 6),
- MockRead(ASYNC, ERR_IO_PENDING, 7), MockRead(ASYNC, 0, 8), // EOF
+ CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
+ CreateMockRead(stream1_body, 3), MockRead(ASYNC, ERR_IO_PENDING, 4),
+ CreateMockRead(stream2_headers, 5), CreateMockRead(stream2_body, 6),
+ MockRead(ASYNC, ERR_IO_PENDING, 7), MockRead(ASYNC, 0, 8), // EOF
};
HttpResponseInfo response;
@@ -5152,7 +4511,7 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushClaimBeforeHeaders) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.AddData(&data);
helper.RunPreTestSetup();
@@ -5160,29 +4519,28 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushClaimBeforeHeaders) {
// Start the transaction.
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ // Run until we've received the primary HEADERS, the pushed HEADERS,
// and the body of the primary stream, but before we've received the HEADERS
// for the pushed stream.
data.RunUntilPaused();
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// Request the pushed path. At this point, we've received the push, but the
// headers are not yet complete.
- std::unique_ptr<HttpNetworkTransaction> trans2(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
- rv = trans2->Start(
- &CreateGetPushRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
+ rv = trans2.Start(&CreateGetPushRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
data.Resume();
data.RunUntilPaused();
base::RunLoop().RunUntilIdle();
// Read the server push body.
std::string result2;
- ReadResult(trans2.get(), &result2);
+ ReadResult(&trans2, &result2);
// Read the response body.
std::string result;
ReadResult(trans, &result);
@@ -5194,14 +4552,14 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushClaimBeforeHeaders) {
<< "||||| Expected data: "
<< expected_push_result;
- // Verify the SYN_REPLY.
+ // Verify the response headers.
// Copy the response info, because trans goes away.
response = *trans->GetResponseInfo();
- response2 = *trans2->GetResponseInfo();
+ response2 = *trans2.GetResponseInfo();
VerifyStreamsClosed(helper);
- // Verify the SYN_REPLY.
+ // Verify the response headers.
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
@@ -5219,59 +4577,46 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushClaimBeforeHeaders) {
}
// TODO(baranovich): HTTP 2 does not allow multiple HEADERS frames
-TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
+TEST_F(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
// We push a stream and attempt to claim it before the headers come down.
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS),
+ CreateMockWrite(stream1_syn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
SpdyHeaderBlock initial_headers;
- if (spdy_util_.spdy_version() < HTTP2) {
- // In HTTP/2 PUSH_PROMISE headers won't show up in the response headers.
- initial_headers["alpha"] = "beta";
- }
spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
&initial_headers);
- std::unique_ptr<SpdySerializedFrame> stream2_syn(
- spdy_util_.ConstructInitialSpdyPushFrame(std::move(initial_headers), 2,
- 1));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructInitialSpdyPushFrame(
+ std::move(initial_headers), 2, 1));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
SpdyHeaderBlock middle_headers;
middle_headers["hello"] = "bye";
- std::unique_ptr<SpdySerializedFrame> stream2_headers1(
- spdy_util_.ConstructSpdyResponseHeaders(2, std::move(middle_headers),
- false));
+ SpdySerializedFrame stream2_headers1(spdy_util_.ConstructSpdyResponseHeaders(
+ 2, std::move(middle_headers), false));
SpdyHeaderBlock late_headers;
late_headers[spdy_util_.GetStatusKey()] = "200";
- if (spdy_util_.spdy_version() < HTTP2) {
- // HTTP/2 eliminates use of the :version header.
- late_headers[spdy_util_.GetVersionKey()] = "HTTP/1.1";
- }
- std::unique_ptr<SpdySerializedFrame> stream2_headers2(
- spdy_util_.ConstructSpdyResponseHeaders(2, std::move(late_headers),
- false));
+ SpdySerializedFrame stream2_headers2(spdy_util_.ConstructSpdyResponseHeaders(
+ 2, std::move(late_headers), false));
const char kPushedData[] = "pushed";
- std::unique_ptr<SpdySerializedFrame> stream2_body(
- spdy_util_.ConstructSpdyBodyFrame(2, kPushedData, strlen(kPushedData),
- true));
+ SpdySerializedFrame stream2_body(spdy_util_.ConstructSpdyDataFrame(
+ 2, kPushedData, strlen(kPushedData), true));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1), CreateMockRead(*stream2_syn, 2),
- CreateMockRead(*stream1_body, 3), MockRead(ASYNC, ERR_IO_PENDING, 4),
- CreateMockRead(*stream2_headers1, 5),
+ CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
+ CreateMockRead(stream1_body, 3), MockRead(ASYNC, ERR_IO_PENDING, 4),
+ CreateMockRead(stream2_headers1, 5),
// This is needed to work around https://crbug.com/571102.
- MockRead(ASYNC, ERR_IO_PENDING, 6), CreateMockRead(*stream2_headers2, 7),
- CreateMockRead(*stream2_body, 8), MockRead(ASYNC, ERR_IO_PENDING, 9),
+ MockRead(ASYNC, ERR_IO_PENDING, 6), CreateMockRead(stream2_headers2, 7),
+ CreateMockRead(stream2_body, 8), MockRead(ASYNC, ERR_IO_PENDING, 9),
MockRead(ASYNC, 0, 10), // EOF
};
@@ -5281,7 +4626,7 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.AddData(&data);
helper.RunPreTestSetup();
@@ -5289,10 +4634,10 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
// Start the transaction.
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ // Run until we've received the primary HEADERS, the pushed HEADERS,
// the first HEADERS frame, and the body of the primary stream, but before
// we've received the final HEADERS for the pushed stream.
data.RunUntilPaused();
@@ -5300,11 +4645,10 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
// Request the pushed path. At this point, we've received the push, but the
// headers are not yet complete.
- std::unique_ptr<HttpNetworkTransaction> trans2(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
- rv = trans2->Start(
- &CreateGetPushRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
+ rv = trans2.Start(&CreateGetPushRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
data.Resume();
data.RunUntilPaused();
base::RunLoop().RunUntilIdle();
@@ -5315,7 +4659,7 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
// Read the server push body.
std::string result2;
- ReadResult(trans2.get(), &result2);
+ ReadResult(&trans2, &result2);
// Read the response body.
std::string result;
ReadResult(trans, &result);
@@ -5323,14 +4667,14 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
// Verify that the received push data is same as the expected push data.
EXPECT_EQ(expected_push_result, result2);
- // Verify the SYN_REPLY.
+ // Verify the response headers.
// Copy the response info, because trans goes away.
response = *trans->GetResponseInfo();
- response2 = *trans2->GetResponseInfo();
+ response2 = *trans2.GetResponseInfo();
VerifyStreamsClosed(helper);
- // Verify the SYN_REPLY.
+ // Verify the response headers.
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
@@ -5339,8 +4683,6 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
// Verify we got all the headers from all header blocks.
- if (spdy_util_.spdy_version() < HTTP2)
- EXPECT_TRUE(response2.headers->HasHeaderValue("alpha", "beta"));
EXPECT_TRUE(response2.headers->HasHeaderValue("hello", "bye"));
EXPECT_TRUE(response2.headers->HasHeaderValue("status", "200"));
@@ -5353,49 +4695,45 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
EXPECT_TRUE(data.AllWriteDataConsumed());
}
-TEST_P(SpdyNetworkTransactionTest, ServerPushWithNoStatusHeaderFrames) {
+TEST_F(SpdyNetworkTransactionTest, ServerPushWithNoStatusHeaderFrames) {
// We push a stream and attempt to claim it before the headers come down.
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+ SpdySerializedFrame stream1_syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS),
+ CreateMockWrite(stream1_syn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
SpdyHeaderBlock initial_headers;
spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/foo.dat"),
&initial_headers);
- std::unique_ptr<SpdySerializedFrame> stream2_syn(
- spdy_util_.ConstructInitialSpdyPushFrame(std::move(initial_headers), 2,
- 1));
+ SpdySerializedFrame stream2_syn(spdy_util_.ConstructInitialSpdyPushFrame(
+ std::move(initial_headers), 2, 1));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
SpdyHeaderBlock middle_headers;
middle_headers["hello"] = "bye";
- std::unique_ptr<SpdySerializedFrame> stream2_headers1(
- spdy_util_.ConstructSpdyResponseHeaders(2, std::move(middle_headers),
- false));
+ SpdySerializedFrame stream2_headers1(spdy_util_.ConstructSpdyResponseHeaders(
+ 2, std::move(middle_headers), false));
const char kPushedData[] = "pushed";
- std::unique_ptr<SpdySerializedFrame> stream2_body(
- spdy_util_.ConstructSpdyBodyFrame(2, kPushedData, strlen(kPushedData),
- true));
+ SpdySerializedFrame stream2_body(spdy_util_.ConstructSpdyDataFrame(
+ 2, kPushedData, strlen(kPushedData), true));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1), CreateMockRead(*stream2_syn, 2),
- CreateMockRead(*stream1_body, 3), MockRead(ASYNC, ERR_IO_PENDING, 4),
- CreateMockRead(*stream2_headers1, 5), CreateMockRead(*stream2_body, 6),
- MockRead(ASYNC, ERR_IO_PENDING, 7), MockRead(ASYNC, 0, 8), // EOF
+ CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
+ CreateMockRead(stream1_body, 3), MockRead(ASYNC, ERR_IO_PENDING, 4),
+ CreateMockRead(stream2_headers1, 5), CreateMockRead(stream2_body, 6),
+ MockRead(ASYNC, ERR_IO_PENDING, 7), MockRead(ASYNC, 0, 8), // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.AddData(&data);
helper.RunPreTestSetup();
@@ -5403,10 +4741,10 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithNoStatusHeaderFrames) {
// Start the transaction.
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM,
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+ // Run until we've received the primary HEADERS, the pushed HEADERS,
// the first HEADERS frame, and the body of the primary stream, but before
// we've received the final HEADERS for the pushed stream.
data.RunUntilPaused();
@@ -5414,18 +4752,17 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithNoStatusHeaderFrames) {
// Request the pushed path. At this point, we've received the push, but the
// headers are not yet complete.
- std::unique_ptr<HttpNetworkTransaction> trans2(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
- rv = trans2->Start(
- &CreateGetPushRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
+ rv = trans2.Start(&CreateGetPushRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
data.Resume();
data.RunUntilPaused();
base::RunLoop().RunUntilIdle();
// Read the server push body.
std::string result2;
- ReadResult(trans2.get(), &result2);
+ ReadResult(&trans2, &result2);
// Read the response body.
std::string result;
ReadResult(trans, &result);
@@ -5434,13 +4771,13 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithNoStatusHeaderFrames) {
// Verify that we haven't received any push data.
EXPECT_EQ("", result2);
- // Verify the SYN_REPLY.
+ // Verify the response headers.
// Copy the response info, because trans goes away.
HttpResponseInfo response = *trans->GetResponseInfo();
VerifyStreamsClosed(helper);
- // Verify the SYN_REPLY.
+ // Verify the response headers.
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
@@ -5453,79 +4790,72 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithNoStatusHeaderFrames) {
EXPECT_TRUE(data.AllWriteDataConsumed());
}
-TEST_P(SpdyNetworkTransactionTest, SynReplyWithHeaders) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, ResponseHeadersTwice) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
SpdyHeaderBlock late_headers;
late_headers["hello"] = "bye";
- std::unique_ptr<SpdySerializedFrame> stream1_headers(
- spdy_util_.ConstructSpdyResponseHeaders(1, std::move(late_headers),
- false));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream1_headers(spdy_util_.ConstructSpdyResponseHeaders(
+ 1, std::move(late_headers), false));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1),
- CreateMockRead(*stream1_headers, 2),
- CreateMockRead(*stream1_body, 3),
- MockRead(ASYNC, 0, 5) // EOF
+ CreateMockRead(stream1_reply, 1), CreateMockRead(stream1_headers, 2),
+ CreateMockRead(stream1_body, 3), MockRead(ASYNC, 0, 5) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_SPDY_PROTOCOL_ERROR));
}
// Tests that receiving HEADERS, DATA, HEADERS, and DATA in that sequence will
// trigger a ERR_SPDY_PROTOCOL_ERROR because trailing HEADERS must not be
// followed by any DATA frames.
-TEST_P(SpdyNetworkTransactionTest, SyncReplyDataAfterTrailers) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdyNetworkTransactionTest, SyncReplyDataAfterTrailers) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 5),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 5),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
+ SpdySerializedFrame stream1_reply(
+ spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, false));
SpdyHeaderBlock late_headers;
late_headers["hello"] = "bye";
- std::unique_ptr<SpdySerializedFrame> stream1_headers(
- spdy_util_.ConstructSpdyResponseHeaders(1, std::move(late_headers),
- false));
- std::unique_ptr<SpdySerializedFrame> stream1_body2(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame stream1_headers(spdy_util_.ConstructSpdyResponseHeaders(
+ 1, std::move(late_headers), false));
+ SpdySerializedFrame stream1_body2(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1), CreateMockRead(*stream1_body, 2),
- CreateMockRead(*stream1_headers, 3), CreateMockRead(*stream1_body2, 4),
+ CreateMockRead(stream1_reply, 1), CreateMockRead(stream1_body, 2),
+ CreateMockRead(stream1_headers, 3), CreateMockRead(stream1_body2, 4),
MockRead(ASYNC, 0, 6) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_SPDY_PROTOCOL_ERROR));
}
-TEST_P(SpdyNetworkTransactionTest, ServerPushCrossOriginCorrectness) {
+TEST_F(SpdyNetworkTransactionTest, ServerPushCrossOriginCorrectness) {
// In this test we want to verify that we can't accidentally push content
// which can't be pushed by this content server.
// This test assumes that:
@@ -5551,34 +4881,32 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushCrossOriginCorrectness) {
const char* url_to_fetch = kTestCases[index];
const char* url_to_push = kTestCases[index + 1];
- SpdyTestUtil spdy_test_util(GetParam().protocol,
- GetParam().priority_to_dependency);
- std::unique_ptr<SpdySerializedFrame> stream1_syn(
+ SpdyTestUtil spdy_test_util;
+ SpdySerializedFrame stream1_syn(
spdy_test_util.ConstructSpdyGet(url_to_fetch, 1, LOWEST));
- std::unique_ptr<SpdySerializedFrame> stream1_body(
- spdy_test_util.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> push_rst(
+ SpdySerializedFrame stream1_body(
+ spdy_test_util.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame push_rst(
spdy_test_util.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
MockWrite writes[] = {
- CreateMockWrite(*stream1_syn, 0), CreateMockWrite(*push_rst, 3),
+ CreateMockWrite(stream1_syn, 0), CreateMockWrite(push_rst, 3),
};
- std::unique_ptr<SpdySerializedFrame> stream1_reply(
- spdy_test_util.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> stream2_syn(
+ SpdySerializedFrame stream1_reply(
+ spdy_test_util.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame stream2_syn(
spdy_test_util.ConstructSpdyPush(nullptr, 0, 2, 1, url_to_push));
const char kPushedData[] = "pushed";
- std::unique_ptr<SpdySerializedFrame> stream2_body(
- spdy_test_util.ConstructSpdyBodyFrame(2, kPushedData,
- strlen(kPushedData), true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame stream2_body(spdy_test_util.ConstructSpdyDataFrame(
+ 2, kPushedData, strlen(kPushedData), true));
+ SpdySerializedFrame rst(
spdy_test_util.ConstructSpdyRstStream(2, RST_STREAM_CANCEL));
MockRead reads[] = {
- CreateMockRead(*stream1_reply, 1),
- CreateMockRead(*stream2_syn, 2),
- CreateMockRead(*stream1_body, 4),
- CreateMockRead(*stream2_body, 5),
+ CreateMockRead(stream1_reply, 1),
+ CreateMockRead(stream2_syn, 2),
+ CreateMockRead(stream1_body, 4),
+ CreateMockRead(stream2_body, 5),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
};
@@ -5593,14 +4921,13 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushCrossOriginCorrectness) {
// Enable cross-origin push. Since we are not using a proxy, this should
// not actually enable cross-origin SPDY push.
- std::unique_ptr<SpdySessionDependencies> session_deps(
- CreateSpdySessionDependencies(GetParam()));
+ auto session_deps = base::MakeUnique<SpdySessionDependencies>();
std::unique_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate());
proxy_delegate->set_trusted_spdy_proxy(net::ProxyServer::FromURI(
"https://123.45.67.89:443", net::ProxyServer::SCHEME_HTTP));
session_deps->proxy_delegate.reset(proxy_delegate.release());
- NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(),
- GetParam(), std::move(session_deps));
+ NormalSpdyTransactionHelper helper(
+ request, DEFAULT_PRIORITY, NetLogWithSource(), std::move(session_deps));
helper.RunPreTestSetup();
helper.AddData(&data);
@@ -5609,8 +4936,8 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushCrossOriginCorrectness) {
// Start the transaction with basic parameters.
TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
// Read the response body.
@@ -5621,13 +4948,13 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushCrossOriginCorrectness) {
EXPECT_TRUE(data.AllReadDataConsumed());
EXPECT_TRUE(data.AllWriteDataConsumed());
- // Verify the SYN_REPLY.
+ // Verify the response headers.
// Copy the response info, because trans goes away.
response = *trans->GetResponseInfo();
VerifyStreamsClosed(helper);
- // Verify the SYN_REPLY.
+ // Verify the response headers.
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
}
@@ -5635,32 +4962,29 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushCrossOriginCorrectness) {
// Verify that push works cross origin as long as the certificate is valid for
// the pushed authority.
-TEST_P(SpdyNetworkTransactionTest, ServerPushValidCrossOrigin) {
+TEST_F(SpdyNetworkTransactionTest, ServerPushValidCrossOrigin) {
// "spdy_pooling.pem" is valid for both www.example.org and mail.example.org.
const char* url_to_fetch = "https://www.example.org";
const char* url_to_push = "https://mail.example.org";
- std::unique_ptr<SpdySerializedFrame> headers(
+ SpdySerializedFrame headers(
spdy_util_.ConstructSpdyGet(url_to_fetch, 1, LOWEST));
MockWrite writes[] = {
- CreateMockWrite(*headers, 0),
+ CreateMockWrite(headers, 0),
};
- std::unique_ptr<SpdySerializedFrame> reply(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> push(
+ SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame push(
spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, url_to_push));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
const char kPushedData[] = "pushed";
- std::unique_ptr<SpdySerializedFrame> pushed_body(
- spdy_util_.ConstructSpdyBodyFrame(2, kPushedData, strlen(kPushedData),
- true));
+ SpdySerializedFrame pushed_body(spdy_util_.ConstructSpdyDataFrame(
+ 2, kPushedData, strlen(kPushedData), true));
MockRead reads[] = {
- CreateMockRead(*reply, 1),
- CreateMockRead(*push, 2),
- CreateMockRead(*body, 3),
- CreateMockRead(*pushed_body, 4),
+ CreateMockRead(reply, 1),
+ CreateMockRead(push, 2),
+ CreateMockRead(body, 3),
+ CreateMockRead(pushed_body, 4),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),
};
@@ -5671,9 +4995,8 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushValidCrossOrigin) {
request.url = GURL(url_to_fetch);
request.load_flags = 0;
- BoundNetLog log;
- NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, log, GetParam(),
- nullptr);
+ NetLogWithSource log;
+ NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, log, nullptr);
helper.RunPreTestSetup();
helper.AddData(&data);
@@ -5681,7 +5004,7 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushValidCrossOrigin) {
TestCompletionCallback callback0;
int rv = trans0->Start(&request, callback0.callback(), log);
rv = callback0.GetResult(rv);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
@@ -5694,16 +5017,15 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushValidCrossOrigin) {
EXPECT_EQ(1u,
spdy_session->unclaimed_pushed_streams_.count(GURL(url_to_push)));
- std::unique_ptr<HttpNetworkTransaction> trans1(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
+ HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
HttpRequestInfo push_request;
push_request.method = "GET";
push_request.url = GURL(url_to_push);
push_request.load_flags = 0;
TestCompletionCallback callback1;
- rv = trans1->Start(&push_request, callback1.callback(), log);
+ rv = trans1.Start(&push_request, callback1.callback(), log);
rv = callback1.GetResult(rv);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(spdy_session->unclaimed_pushed_streams_.empty());
EXPECT_EQ(0u, spdy_session->unclaimed_pushed_streams_.size());
@@ -5719,71 +5041,63 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushValidCrossOrigin) {
ReadResult(trans0, &result0);
EXPECT_EQ("hello!", result0);
- HttpResponseInfo push_response = *trans1->GetResponseInfo();
+ HttpResponseInfo push_response = *trans1.GetResponseInfo();
EXPECT_TRUE(push_response.headers);
EXPECT_EQ("HTTP/1.1 200", push_response.headers->GetStatusLine());
std::string result1;
- ReadResult(trans1.get(), &result1);
+ ReadResult(&trans1, &result1);
EXPECT_EQ(kPushedData, result1);
}
// Verify that push works cross origin, even if there is already a connection
// open to origin of pushed resource.
-TEST_P(SpdyNetworkTransactionTest, ServerPushValidCrossOriginWithOpenSession) {
+TEST_F(SpdyNetworkTransactionTest, ServerPushValidCrossOriginWithOpenSession) {
const char* url_to_fetch0 = "https://mail.example.org/foo";
const char* url_to_fetch1 = "https://docs.example.org";
const char* url_to_push = "https://mail.example.org/bar";
- SpdyTestUtil spdy_util_0(GetParam().protocol,
- GetParam().priority_to_dependency);
+ SpdyTestUtil spdy_util_0;
- std::unique_ptr<SpdySerializedFrame> headers0(
+ SpdySerializedFrame headers0(
spdy_util_0.ConstructSpdyGet(url_to_fetch0, 1, LOWEST));
MockWrite writes0[] = {
- CreateMockWrite(*headers0, 0),
+ CreateMockWrite(headers0, 0),
};
- std::unique_ptr<SpdySerializedFrame> reply0(
- spdy_util_0.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame reply0(spdy_util_0.ConstructSpdyGetReply(nullptr, 0, 1));
const char kData0[] = "first";
- std::unique_ptr<SpdySerializedFrame> body0(
- spdy_util_0.ConstructSpdyBodyFrame(1, kData0, strlen(kData0), true));
- MockRead reads0[] = {
- CreateMockRead(*reply0, 1),
- CreateMockRead(*body0, 2),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)
- };
+ SpdySerializedFrame body0(
+ spdy_util_0.ConstructSpdyDataFrame(1, kData0, strlen(kData0), true));
+ MockRead reads0[] = {CreateMockRead(reply0, 1), CreateMockRead(body0, 2),
+ MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
SequencedSocketData data0(reads0, arraysize(reads0), writes0,
arraysize(writes0));
- SpdyTestUtil spdy_util_1(GetParam().protocol,
- GetParam().priority_to_dependency);
+ SpdyTestUtil spdy_util_1;
- std::unique_ptr<SpdySerializedFrame> headers1(
+ SpdySerializedFrame headers1(
spdy_util_1.ConstructSpdyGet(url_to_fetch1, 1, LOWEST));
MockWrite writes1[] = {
- CreateMockWrite(*headers1, 0),
+ CreateMockWrite(headers1, 0),
};
- std::unique_ptr<SpdySerializedFrame> reply1(
- spdy_util_1.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> push(
+ SpdySerializedFrame reply1(spdy_util_1.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame push(
spdy_util_1.ConstructSpdyPush(nullptr, 0, 2, 1, url_to_push));
const char kData1[] = "second";
- std::unique_ptr<SpdySerializedFrame> body1(
- spdy_util_1.ConstructSpdyBodyFrame(1, kData1, strlen(kData1), true));
+ SpdySerializedFrame body1(
+ spdy_util_1.ConstructSpdyDataFrame(1, kData1, strlen(kData1), true));
const char kPushedData[] = "pushed";
- std::unique_ptr<SpdySerializedFrame> pushed_body(
- spdy_util_1.ConstructSpdyBodyFrame(2, kPushedData, strlen(kPushedData),
- true));
+ SpdySerializedFrame pushed_body(spdy_util_1.ConstructSpdyDataFrame(
+ 2, kPushedData, strlen(kPushedData), true));
MockRead reads1[] = {
- CreateMockRead(*reply1, 1),
- CreateMockRead(*push, 2),
- CreateMockRead(*body1, 3),
- CreateMockRead(*pushed_body, 4),
+ CreateMockRead(reply1, 1),
+ CreateMockRead(push, 2),
+ CreateMockRead(body1, 3),
+ CreateMockRead(pushed_body, 4),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),
};
@@ -5796,9 +5110,8 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushValidCrossOriginWithOpenSession) {
request0.url = GURL(url_to_fetch0);
request0.load_flags = 0;
- BoundNetLog log;
- NormalSpdyTransactionHelper helper(request0, DEFAULT_PRIORITY, log,
- GetParam(), nullptr);
+ NetLogWithSource log;
+ NormalSpdyTransactionHelper helper(request0, DEFAULT_PRIORITY, log, nullptr);
helper.RunPreTestSetup();
// "spdy_pooling.pem" is valid for www.example.org, but not for
@@ -5820,21 +5133,20 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushValidCrossOriginWithOpenSession) {
TestCompletionCallback callback0;
int rv = trans0->Start(&request0, callback0.callback(), log);
rv = callback0.GetResult(rv);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Request |url_to_fetch1|, during which docs.example.org pushes
// |url_to_push|, which happens to be for www.example.org, to which there is
// already an open connection.
- std::unique_ptr<HttpNetworkTransaction> trans1(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
+ HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
HttpRequestInfo request1;
request1.method = "GET";
request1.url = GURL(url_to_fetch1);
request1.load_flags = 0;
TestCompletionCallback callback1;
- rv = trans1->Start(&request1, callback1.callback(), log);
+ rv = trans1.Start(&request1, callback1.callback(), log);
rv = callback1.GetResult(rv);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
HostPortPair host_port_pair0("mail.example.org", 443);
@@ -5858,16 +5170,15 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushValidCrossOriginWithOpenSession) {
spdy_session1->unclaimed_pushed_streams_.count(GURL(url_to_push)));
// Request |url_to_push|, which should be served from the pushed resource.
- std::unique_ptr<HttpNetworkTransaction> trans2(
- new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
+ HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
HttpRequestInfo push_request;
push_request.method = "GET";
push_request.url = GURL(url_to_push);
push_request.load_flags = 0;
TestCompletionCallback callback2;
- rv = trans2->Start(&push_request, callback2.callback(), log);
+ rv = trans2.Start(&push_request, callback2.callback(), log);
rv = callback2.GetResult(rv);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(spdy_session0->unclaimed_pushed_streams_.empty());
EXPECT_EQ(0u, spdy_session0->unclaimed_pushed_streams_.size());
@@ -5886,53 +5197,49 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushValidCrossOriginWithOpenSession) {
ReadResult(trans0, &result0);
EXPECT_EQ(kData0, result0);
- HttpResponseInfo response1 = *trans1->GetResponseInfo();
+ HttpResponseInfo response1 = *trans1.GetResponseInfo();
EXPECT_TRUE(response1.headers);
EXPECT_EQ("HTTP/1.1 200", response1.headers->GetStatusLine());
std::string result1;
- ReadResult(trans1.get(), &result1);
+ ReadResult(&trans1, &result1);
EXPECT_EQ(kData1, result1);
- HttpResponseInfo push_response = *trans2->GetResponseInfo();
+ HttpResponseInfo push_response = *trans2.GetResponseInfo();
EXPECT_TRUE(push_response.headers);
EXPECT_EQ("HTTP/1.1 200", push_response.headers->GetStatusLine());
std::string result2;
- ReadResult(trans2.get(), &result2);
+ ReadResult(&trans2, &result2);
EXPECT_EQ(kPushedData, result2);
}
-TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidCrossOrigin) {
+TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidCrossOrigin) {
// "spdy_pooling.pem" is valid for www.example.org,
// but not for invalid.example.org.
const char* url_to_fetch = "https://www.example.org";
const char* url_to_push = "https://invalid.example.org";
- std::unique_ptr<SpdySerializedFrame> headers(
+ SpdySerializedFrame headers(
spdy_util_.ConstructSpdyGet(url_to_fetch, 1, LOWEST));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
MockWrite writes[] = {
- CreateMockWrite(*headers, 0),
- CreateMockWrite(*rst, 3),
+ CreateMockWrite(headers, 0), CreateMockWrite(rst, 3),
};
- std::unique_ptr<SpdySerializedFrame> reply(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> push(
+ SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame push(
spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, url_to_push));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
const char kPushedData[] = "pushed";
- std::unique_ptr<SpdySerializedFrame> pushed_body(
- spdy_util_.ConstructSpdyBodyFrame(2, kPushedData, strlen(kPushedData),
- true));
+ SpdySerializedFrame pushed_body(spdy_util_.ConstructSpdyDataFrame(
+ 2, kPushedData, strlen(kPushedData), true));
MockRead reads[] = {
- CreateMockRead(*reply, 1),
- CreateMockRead(*push, 2),
- CreateMockRead(*body, 4),
- CreateMockRead(*pushed_body, 5),
+ CreateMockRead(reply, 1),
+ CreateMockRead(push, 2),
+ CreateMockRead(body, 4),
+ CreateMockRead(pushed_body, 5),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
};
@@ -5943,42 +5250,38 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidCrossOrigin) {
request.url = GURL(url_to_fetch);
request.load_flags = 0;
- NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(),
- GetParam(), nullptr);
+ NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
+ NetLogWithSource(), nullptr);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
}
-TEST_P(SpdyNetworkTransactionTest, RetryAfterRefused) {
+TEST_F(SpdyNetworkTransactionTest, RetryAfterRefused) {
// Construct the request.
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
// Will be destroyed by the RST before stream 3 starts.
spdy_util_.UpdateWithStreamDestruction(1);
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*req2, 2),
+ CreateMockWrite(req, 0), CreateMockWrite(req2, 2),
};
- std::unique_ptr<SpdySerializedFrame> refused(
+ SpdySerializedFrame refused(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(3, true));
MockRead reads[] = {
- CreateMockRead(*refused, 1),
- CreateMockRead(*resp, 3),
- CreateMockRead(*body, 4),
- MockRead(ASYNC, 0, 5) // EOF
+ CreateMockRead(refused, 1), CreateMockRead(resp, 3),
+ CreateMockRead(body, 4), MockRead(ASYNC, 0, 5) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
@@ -5987,23 +5290,23 @@ TEST_P(SpdyNetworkTransactionTest, RetryAfterRefused) {
// Start the transaction with basic parameters.
TestCompletionCallback callback;
- int rv = trans->Start(
- &CreateGetRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&CreateGetRequest(), callback.callback(),
+ NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Verify that we consumed all test data.
EXPECT_TRUE(data.AllReadDataConsumed());
EXPECT_TRUE(data.AllWriteDataConsumed());
- // Verify the SYN_REPLY.
+ // Verify the response headers.
HttpResponseInfo response = *trans->GetResponseInfo();
EXPECT_TRUE(response.headers);
EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
}
-TEST_P(SpdyNetworkTransactionTest, OutOfOrderSynStream) {
+TEST_F(SpdyNetworkTransactionTest, OutOfOrderHeaders) {
// This first request will start to establish the SpdySession.
// Then we will start the second (MEDIUM priority) and then third
// (HIGHEST priority) request in such a way that the third will actually
@@ -6020,40 +5323,34 @@ TEST_P(SpdyNetworkTransactionTest, OutOfOrderSynStream) {
// req1 is alive when req2 is attempted (during but not after the
// |data.RunFor(2);| statement below) but not when req3 is attempted.
// The call to spdy_util_.UpdateWithStreamDestruction() reflects this.
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, HIGHEST, true));
spdy_util_.UpdateWithStreamDestruction(1);
- std::unique_ptr<SpdySerializedFrame> req3(
+ SpdySerializedFrame req3(
spdy_util_.ConstructSpdyGet(nullptr, 0, 5, MEDIUM, true));
MockWrite writes[] = {
- MockWrite(ASYNC, ERR_IO_PENDING, 0), CreateMockWrite(*req1, 1),
- CreateMockWrite(*req2, 5), CreateMockWrite(*req3, 6),
- };
-
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body1(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
- std::unique_ptr<SpdySerializedFrame> resp3(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
- std::unique_ptr<SpdySerializedFrame> body3(
- spdy_util_.ConstructSpdyBodyFrame(5, true));
+ MockWrite(ASYNC, ERR_IO_PENDING, 0), CreateMockWrite(req1, 1),
+ CreateMockWrite(req2, 5), CreateMockWrite(req3, 6),
+ };
+
+ SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(NULL, 0, 3));
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
+ SpdySerializedFrame resp3(spdy_util_.ConstructSpdyGetReply(NULL, 0, 5));
+ SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, true));
MockRead reads[] = {
- CreateMockRead(*resp1, 2), MockRead(ASYNC, ERR_IO_PENDING, 3),
- CreateMockRead(*body1, 4), CreateMockRead(*resp2, 7),
- CreateMockRead(*body2, 8), CreateMockRead(*resp3, 9),
- CreateMockRead(*body3, 10), MockRead(ASYNC, 0, 11) // EOF
+ CreateMockRead(resp1, 2), MockRead(ASYNC, ERR_IO_PENDING, 3),
+ CreateMockRead(body1, 4), CreateMockRead(resp2, 7),
+ CreateMockRead(body2, 8), CreateMockRead(resp3, 9),
+ CreateMockRead(body3, 10), MockRead(ASYNC, 0, 11) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
NormalSpdyTransactionHelper helper(CreateGetRequest(), LOWEST,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
@@ -6061,8 +5358,8 @@ TEST_P(SpdyNetworkTransactionTest, OutOfOrderSynStream) {
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
HttpRequestInfo info1 = CreateGetRequest();
- int rv = trans->Start(&info1, callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv = trans->Start(&info1, callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Run the message loop, but do not allow the write to complete.
// This leaves the SpdySession with a write pending, which prevents
@@ -6072,38 +5369,34 @@ TEST_P(SpdyNetworkTransactionTest, OutOfOrderSynStream) {
// Now, start both new transactions
HttpRequestInfo info2 = CreateGetRequest();
TestCompletionCallback callback2;
- std::unique_ptr<HttpNetworkTransaction> trans2(
- new HttpNetworkTransaction(MEDIUM, helper.session()));
- rv = trans2->Start(&info2, callback2.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ HttpNetworkTransaction trans2(MEDIUM, helper.session());
+ rv = trans2.Start(&info2, callback2.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
base::RunLoop().RunUntilIdle();
HttpRequestInfo info3 = CreateGetRequest();
TestCompletionCallback callback3;
- std::unique_ptr<HttpNetworkTransaction> trans3(
- new HttpNetworkTransaction(HIGHEST, helper.session()));
- rv = trans3->Start(&info3, callback3.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ HttpNetworkTransaction trans3(HIGHEST, helper.session());
+ rv = trans3.Start(&info3, callback3.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
base::RunLoop().RunUntilIdle();
- // We now have two SYN_STREAM frames queued up which will be
+ // We now have two HEADERS frames queued up which will be
// dequeued only once the first write completes, which we
// now allow to happen.
ASSERT_TRUE(data.IsPaused());
data.Resume();
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// And now we can allow everything else to run to completion.
data.Resume();
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(OK, callback2.WaitForResult());
- EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
+ EXPECT_THAT(callback3.WaitForResult(), IsOk());
helper.VerifyDataConsumed();
}
-// The tests below are only for SPDY/3 and above.
-
// Test that sent data frames and received WINDOW_UPDATE frames change
// the send_window_size_ correctly.
@@ -6114,7 +5407,7 @@ TEST_P(SpdyNetworkTransactionTest, OutOfOrderSynStream) {
// stream is created, succeeds and schedules another read. This way reads
// and writes are interleaved; after doing a full frame write, SpdyStream
// will break out of DoLoop and will read and process a WINDOW_UPDATE.
-// Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away
+// Once our WINDOW_UPDATE is read, we cannot send HEADERS right away
// since request has not been completely written, therefore we feed
// enough number of WINDOW_UPDATEs to finish the first read and cause a
// write, leading to a complete write of request body; after that we send
@@ -6125,41 +5418,40 @@ TEST_P(SpdyNetworkTransactionTest, OutOfOrderSynStream) {
// all these tests using it. Right now we are working around the
// limitations as described above and it's not deterministic, tests may
// fail under specific circumstances.
-TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) {
+TEST_F(SpdyNetworkTransactionTest, WindowUpdateReceived) {
static int kFrameCount = 2;
std::unique_ptr<std::string> content(
new std::string(kMaxSpdyFrameChunkSize, 'a'));
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, NULL, 0));
- std::unique_ptr<SpdySerializedFrame> body(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(
1, content->c_str(), content->size(), false));
- std::unique_ptr<SpdySerializedFrame> body_end(
- spdy_util_.ConstructSpdyBodyFrame(1, content->c_str(), content->size(),
- true));
+ SpdySerializedFrame body_end(spdy_util_.ConstructSpdyDataFrame(
+ 1, content->c_str(), content->size(), true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
- CreateMockWrite(*body, 1),
- CreateMockWrite(*body_end, 2),
+ CreateMockWrite(req, 0), CreateMockWrite(body, 1),
+ CreateMockWrite(body_end, 2),
};
static const int32_t kDeltaWindowSize = 0xff;
static const int kDeltaCount = 4;
- std::unique_ptr<SpdySerializedFrame> window_update(
+ SpdySerializedFrame window_update(
spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
- std::unique_ptr<SpdySerializedFrame> window_update_dummy(
+ SpdySerializedFrame window_update_dummy(
spdy_util_.ConstructSpdyWindowUpdate(2, kDeltaWindowSize));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(NULL, 0));
MockRead reads[] = {
- CreateMockRead(*window_update_dummy, 3),
- CreateMockRead(*window_update_dummy, 4),
- CreateMockRead(*window_update_dummy, 5),
- CreateMockRead(*window_update, 6), // Four updates, therefore window
- CreateMockRead(*window_update, 7), // size should increase by
- CreateMockRead(*window_update, 8), // kDeltaWindowSize * 4
- CreateMockRead(*window_update, 9), CreateMockRead(*resp, 10),
- MockRead(ASYNC, ERR_IO_PENDING, 11), CreateMockRead(*body_end, 12),
+ CreateMockRead(window_update_dummy, 3),
+ CreateMockRead(window_update_dummy, 4),
+ CreateMockRead(window_update_dummy, 5),
+ CreateMockRead(window_update, 6), // Four updates, therefore window
+ CreateMockRead(window_update, 7), // size should increase by
+ CreateMockRead(window_update, 8), // kDeltaWindowSize * 4
+ CreateMockRead(window_update, 9),
+ CreateMockRead(resp, 10),
+ MockRead(ASYNC, ERR_IO_PENDING, 11),
+ CreateMockRead(body_end, 12),
MockRead(ASYNC, 0, 13) // EOF
};
@@ -6179,16 +5471,17 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) {
request.upload_data_stream = &upload_data_stream;
NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.AddData(&data);
helper.RunPreTestSetup();
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
- int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
+ int rv =
+ trans->Start(&helper.request(), callback.callback(), NetLogWithSource());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
data.RunUntilPaused();
base::RunLoop().RunUntilIdle();
@@ -6196,8 +5489,7 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) {
SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
ASSERT_TRUE(stream);
ASSERT_TRUE(stream->stream());
- EXPECT_EQ(static_cast<int>(
- SpdySession::GetDefaultInitialWindowSize(GetParam().protocol)) +
+ EXPECT_EQ(static_cast<int>(kDefaultInitialWindowSize) +
kDeltaWindowSize * kDeltaCount -
kMaxSpdyFrameChunkSize * kFrameCount,
stream->stream()->send_window_size());
@@ -6206,20 +5498,18 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) {
base::RunLoop().RunUntilIdle();
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
helper.VerifyDataConsumed();
}
// Test that received data frames and sent WINDOW_UPDATE frames change
// the recv_window_size_ correctly.
-TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
- const int32_t default_initial_window_size =
- SpdySession::GetDefaultInitialWindowSize(GetParam().protocol);
+TEST_F(SpdyNetworkTransactionTest, WindowUpdateSent) {
// Session level maximum window size that is more than twice the default
// initial window size so that an initial window update is sent.
const int32_t session_max_recv_window_size = 5 * 64 * 1024;
- ASSERT_LT(2 * default_initial_window_size, session_max_recv_window_size);
+ ASSERT_LT(2 * kDefaultInitialWindowSize, session_max_recv_window_size);
// Stream level maximum window size that is less than the session level
// maximum window size so that we test for confusion between the two.
const int32_t stream_max_recv_window_size = 4 * 64 * 1024;
@@ -6244,45 +5534,44 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
stream_max_recv_window_size / 2 + kChunkSize;
SettingsMap initial_settings;
+ initial_settings[SETTINGS_HEADER_TABLE_SIZE] =
+ SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxHeaderTableSize);
initial_settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams);
initial_settings[SETTINGS_INITIAL_WINDOW_SIZE] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, stream_max_recv_window_size);
- std::unique_ptr<SpdySerializedFrame> initial_settings_frame(
+ SpdySerializedFrame initial_settings_frame(
spdy_util_.ConstructSpdySettings(initial_settings));
- std::unique_ptr<SpdySerializedFrame> initial_window_update(
+ SpdySerializedFrame initial_window_update(
spdy_util_.ConstructSpdyWindowUpdate(
kSessionFlowControlStreamId,
- session_max_recv_window_size - default_initial_window_size));
- std::unique_ptr<SpdySerializedFrame> req(
+ session_max_recv_window_size - kDefaultInitialWindowSize));
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> session_window_update(
+ SpdySerializedFrame session_window_update(
spdy_util_.ConstructSpdyWindowUpdate(0, session_window_update_delta));
- std::unique_ptr<SpdySerializedFrame> stream_window_update(
+ SpdySerializedFrame stream_window_update(
spdy_util_.ConstructSpdyWindowUpdate(1, stream_window_update_delta));
std::vector<MockWrite> writes;
- if (GetParam().protocol == kProtoHTTP2) {
- writes.push_back(MockWrite(ASYNC, kHttp2ConnectionHeaderPrefix,
- kHttp2ConnectionHeaderPrefixSize, 0));
- }
- writes.push_back(CreateMockWrite(*initial_settings_frame, writes.size()));
- writes.push_back(CreateMockWrite(*initial_window_update, writes.size()));
- writes.push_back(CreateMockWrite(*req, writes.size()));
+ writes.push_back(MockWrite(ASYNC, kHttp2ConnectionHeaderPrefix,
+ kHttp2ConnectionHeaderPrefixSize, 0));
+ writes.push_back(CreateMockWrite(initial_settings_frame, writes.size()));
+ writes.push_back(CreateMockWrite(initial_window_update, writes.size()));
+ writes.push_back(CreateMockWrite(req, writes.size()));
std::vector<MockRead> reads;
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- reads.push_back(CreateMockRead(*resp, writes.size() + reads.size()));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ reads.push_back(CreateMockRead(resp, writes.size() + reads.size()));
- std::vector<std::unique_ptr<SpdySerializedFrame>> body_frames;
+ std::vector<SpdySerializedFrame> body_frames;
const std::string body_data(kChunkSize, 'x');
for (size_t remaining = kTargetSize; remaining != 0;) {
size_t frame_size = std::min(remaining, body_data.size());
- body_frames.push_back(base::WrapUnique(spdy_util_.ConstructSpdyBodyFrame(
- 1, body_data.data(), frame_size, false)));
+ body_frames.push_back(spdy_util_.ConstructSpdyDataFrame(1, body_data.data(),
+ frame_size, false));
reads.push_back(
- CreateMockRead(*body_frames.back(), writes.size() + reads.size()));
+ CreateMockRead(body_frames.back(), writes.size() + reads.size()));
remaining -= frame_size;
}
// Yield.
@@ -6290,15 +5579,15 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
MockRead(SYNCHRONOUS, ERR_IO_PENDING, writes.size() + reads.size()));
writes.push_back(
- CreateMockWrite(*session_window_update, writes.size() + reads.size()));
+ CreateMockWrite(session_window_update, writes.size() + reads.size()));
writes.push_back(
- CreateMockWrite(*stream_window_update, writes.size() + reads.size()));
+ CreateMockWrite(stream_window_update, writes.size() + reads.size()));
SequencedSocketData data(reads.data(), reads.size(), writes.data(),
writes.size());
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.AddData(&data);
helper.RunPreTestSetup();
@@ -6310,11 +5599,12 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
- int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
+ int rv =
+ trans->Start(&helper.request(), callback.callback(), NetLogWithSource());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
SpdyHttpStream* stream =
static_cast<SpdyHttpStream*>(trans->stream_.get());
@@ -6346,34 +5636,32 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
}
// Test that WINDOW_UPDATE frame causing overflow is handled correctly.
-TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
+TEST_F(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
// Number of full frames we hope to write (but will not, used to
// set content-length header correctly)
static int kFrameCount = 3;
std::unique_ptr<std::string> content(
new std::string(kMaxSpdyFrameChunkSize, 'a'));
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, NULL, 0));
- std::unique_ptr<SpdySerializedFrame> body(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(
1, content->c_str(), content->size(), false));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
// We're not going to write a data frame with FIN, we'll receive a bad
// WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
- CreateMockWrite(*body, 2),
- CreateMockWrite(*rst, 3),
+ CreateMockWrite(req, 0), CreateMockWrite(body, 2),
+ CreateMockWrite(rst, 3),
};
static const int32_t kDeltaWindowSize = 0x7fffffff; // cause an overflow
- std::unique_ptr<SpdySerializedFrame> window_update(
+ SpdySerializedFrame window_update(
spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
MockRead reads[] = {
- CreateMockRead(*window_update, 1),
- MockRead(ASYNC, 0, 4) // EOF
+ CreateMockRead(window_update, 1), MockRead(ASYNC, 0, 4) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
@@ -6392,18 +5680,19 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
request.upload_data_stream = &upload_data_stream;
NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
- int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
+ int rv =
+ trans->Start(&helper.request(), callback.callback(), NetLogWithSource());
+ ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(callback.have_result());
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsError(ERR_SPDY_PROTOCOL_ERROR));
helper.VerifyDataConsumed();
}
@@ -6422,9 +5711,8 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
// ensure that last data frame is still there and stream has stalled.
// After that, next read is artifically enforced, which causes a
// WINDOW_UPDATE to be read and I/O process resumes.
-TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
- const int32_t initial_window_size =
- SpdySession::GetDefaultInitialWindowSize(GetParam().protocol);
+TEST_F(SpdyNetworkTransactionTest, FlowControlStallResume) {
+ const int32_t initial_window_size = kDefaultInitialWindowSize;
// Number of upload data buffers we need to send to zero out the window size
// is the minimal number of upload buffers takes to be bigger than
// |initial_window_size|.
@@ -6439,21 +5727,21 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
// Construct content for a data frame of maximum size.
std::string content(kMaxSpdyFrameChunkSize, 'a');
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1,
/*content_length=*/kBufferSize * num_upload_buffers + kUploadDataSize,
LOWEST, NULL, 0));
// Full frames.
- std::unique_ptr<SpdySerializedFrame> body1(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(
1, content.c_str(), content.size(), false));
// Last frame in each upload data buffer.
- std::unique_ptr<SpdySerializedFrame> body2(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(
1, content.c_str(), kBufferSize % kMaxSpdyFrameChunkSize, false));
// The very last frame before the stalled frames.
- std::unique_ptr<SpdySerializedFrame> body3(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(
1, content.c_str(),
initial_window_size % kBufferSize % kMaxSpdyFrameChunkSize, false));
@@ -6463,29 +5751,28 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
// we need one additional frame to send the rest of 'a'.
std::string last_body(kBufferSize * num_upload_buffers - initial_window_size,
'a');
- std::unique_ptr<SpdySerializedFrame> body4(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame body4(spdy_util_.ConstructSpdyDataFrame(
1, last_body.c_str(), last_body.size(), false));
// Also send a "hello!" after WINDOW_UPDATE.
- std::unique_ptr<SpdySerializedFrame> body5(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame body5(spdy_util_.ConstructSpdyDataFrame(1, true));
// Fill in mock writes.
size_t i = 0;
std::vector<MockWrite> writes;
- writes.push_back(CreateMockWrite(*req, i++));
+ writes.push_back(CreateMockWrite(req, i++));
for (size_t j = 0; j < num_upload_buffers; j++) {
for (size_t k = 0; k < num_frames_in_one_upload_buffer; k++) {
if (k == num_frames_in_one_upload_buffer - 1 &&
kBufferSize % kMaxSpdyFrameChunkSize != 0) {
if (j == num_upload_buffers - 1 &&
(initial_window_size % kBufferSize != 0)) {
- writes.push_back(CreateMockWrite(*body3, i++));
+ writes.push_back(CreateMockWrite(body3, i++));
} else {
- writes.push_back(CreateMockWrite(*body2, i++));
+ writes.push_back(CreateMockWrite(body2, i++));
}
} else {
- writes.push_back(CreateMockWrite(*body1, i++));
+ writes.push_back(CreateMockWrite(body1, i++));
}
}
}
@@ -6496,26 +5783,24 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, i++));
// Construct read frame for window updates that gives enough space to upload
// the rest of the data.
- std::unique_ptr<SpdySerializedFrame> session_window_update(
+ SpdySerializedFrame session_window_update(
spdy_util_.ConstructSpdyWindowUpdate(0,
kUploadDataSize + last_body.size()));
- std::unique_ptr<SpdySerializedFrame> window_update(
- spdy_util_.ConstructSpdyWindowUpdate(1,
- kUploadDataSize + last_body.size()));
+ SpdySerializedFrame window_update(spdy_util_.ConstructSpdyWindowUpdate(
+ 1, kUploadDataSize + last_body.size()));
- reads.push_back(CreateMockRead(*session_window_update, i++));
- reads.push_back(CreateMockRead(*window_update, i++));
+ reads.push_back(CreateMockRead(session_window_update, i++));
+ reads.push_back(CreateMockRead(window_update, i++));
// Stalled frames which can be sent after receiving window updates.
if (last_body.size() > 0)
- writes.push_back(CreateMockWrite(*body4, i++));
- writes.push_back(CreateMockWrite(*body5, i++));
-
- std::unique_ptr<SpdySerializedFrame> reply(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
- reads.push_back(CreateMockRead(*reply, i++));
- reads.push_back(CreateMockRead(*body2, i++));
- reads.push_back(CreateMockRead(*body5, i++));
+ writes.push_back(CreateMockWrite(body4, i++));
+ writes.push_back(CreateMockWrite(body5, i++));
+
+ SpdySerializedFrame reply(spdy_util_.ConstructSpdyPostReply(NULL, 0));
+ reads.push_back(CreateMockRead(reply, i++));
+ reads.push_back(CreateMockRead(body2, i++));
+ reads.push_back(CreateMockRead(body5, i++));
reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
SequencedSocketData data(reads.data(), reads.size(), writes.data(),
@@ -6532,16 +5817,17 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
request.method = "POST";
request.url = default_url_;
request.upload_data_stream = &upload_data_stream;
- NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(),
- GetParam(), NULL);
+ NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
+ NetLogWithSource(), NULL);
helper.AddData(&data);
helper.RunPreTestSetup();
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
- int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv =
+ trans->Start(&helper.request(), callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
base::RunLoop().RunUntilIdle(); // Write as much as we can.
@@ -6571,9 +5857,8 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
// Test we correctly handle the case where the SETTINGS frame results in
// unstalling the send window.
-TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
- const int32_t initial_window_size =
- SpdySession::GetDefaultInitialWindowSize(GetParam().protocol);
+TEST_F(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
+ const int32_t initial_window_size = kDefaultInitialWindowSize;
// Number of upload data buffers we need to send to zero out the window size
// is the minimal number of upload buffers takes to be bigger than
// |initial_window_size|.
@@ -6588,21 +5873,21 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
// Construct content for a data frame of maximum size.
std::string content(kMaxSpdyFrameChunkSize, 'a');
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1,
/*content_length=*/kBufferSize * num_upload_buffers + kUploadDataSize,
LOWEST, NULL, 0));
// Full frames.
- std::unique_ptr<SpdySerializedFrame> body1(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(
1, content.c_str(), content.size(), false));
// Last frame in each upload data buffer.
- std::unique_ptr<SpdySerializedFrame> body2(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(
1, content.c_str(), kBufferSize % kMaxSpdyFrameChunkSize, false));
// The very last frame before the stalled frames.
- std::unique_ptr<SpdySerializedFrame> body3(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(
1, content.c_str(),
initial_window_size % kBufferSize % kMaxSpdyFrameChunkSize, false));
@@ -6612,29 +5897,28 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
// we need one additional frame to send the rest of 'a'.
std::string last_body(kBufferSize * num_upload_buffers - initial_window_size,
'a');
- std::unique_ptr<SpdySerializedFrame> body4(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame body4(spdy_util_.ConstructSpdyDataFrame(
1, last_body.c_str(), last_body.size(), false));
// Also send a "hello!" after WINDOW_UPDATE.
- std::unique_ptr<SpdySerializedFrame> body5(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame body5(spdy_util_.ConstructSpdyDataFrame(1, true));
// Fill in mock writes.
size_t i = 0;
std::vector<MockWrite> writes;
- writes.push_back(CreateMockWrite(*req, i++));
+ writes.push_back(CreateMockWrite(req, i++));
for (size_t j = 0; j < num_upload_buffers; j++) {
for (size_t k = 0; k < num_frames_in_one_upload_buffer; k++) {
if (k == num_frames_in_one_upload_buffer - 1 &&
kBufferSize % kMaxSpdyFrameChunkSize != 0) {
if (j == num_upload_buffers - 1 &&
(initial_window_size % kBufferSize != 0)) {
- writes.push_back(CreateMockWrite(*body3, i++));
+ writes.push_back(CreateMockWrite(body3, i++));
} else {
- writes.push_back(CreateMockWrite(*body2, i++));
+ writes.push_back(CreateMockWrite(body2, i++));
}
} else {
- writes.push_back(CreateMockWrite(*body1, i++));
+ writes.push_back(CreateMockWrite(body1, i++));
}
}
}
@@ -6649,30 +5933,28 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
SettingsMap settings;
settings[SETTINGS_INITIAL_WINDOW_SIZE] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, initial_window_size * 2);
- std::unique_ptr<SpdySerializedFrame> settings_frame_large(
+ SpdySerializedFrame settings_frame_large(
spdy_util_.ConstructSpdySettings(settings));
- reads.push_back(CreateMockRead(*settings_frame_large, i++));
+ reads.push_back(CreateMockRead(settings_frame_large, i++));
- std::unique_ptr<SpdySerializedFrame> session_window_update(
+ SpdySerializedFrame session_window_update(
spdy_util_.ConstructSpdyWindowUpdate(0,
last_body.size() + kUploadDataSize));
- reads.push_back(CreateMockRead(*session_window_update, i++));
+ reads.push_back(CreateMockRead(session_window_update, i++));
- std::unique_ptr<SpdySerializedFrame> settings_ack(
- spdy_util_.ConstructSpdySettingsAck());
- writes.push_back(CreateMockWrite(*settings_ack, i++));
+ SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
+ writes.push_back(CreateMockWrite(settings_ack, i++));
// Stalled frames which can be sent after |settings_ack|.
if (last_body.size() > 0)
- writes.push_back(CreateMockWrite(*body4, i++));
- writes.push_back(CreateMockWrite(*body5, i++));
-
- std::unique_ptr<SpdySerializedFrame> reply(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
- reads.push_back(CreateMockRead(*reply, i++));
- reads.push_back(CreateMockRead(*body2, i++));
- reads.push_back(CreateMockRead(*body5, i++));
+ writes.push_back(CreateMockWrite(body4, i++));
+ writes.push_back(CreateMockWrite(body5, i++));
+
+ SpdySerializedFrame reply(spdy_util_.ConstructSpdyPostReply(NULL, 0));
+ reads.push_back(CreateMockRead(reply, i++));
+ reads.push_back(CreateMockRead(body2, i++));
+ reads.push_back(CreateMockRead(body5, i++));
reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
// Force all writes to happen before any read, last write will not
@@ -6692,15 +5974,16 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
request.url = default_url_;
request.upload_data_stream = &upload_data_stream;
NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
- int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv =
+ trans->Start(&helper.request(), callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
data.RunUntilPaused(); // Write as much as we can.
base::RunLoop().RunUntilIdle();
@@ -6737,9 +6020,8 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
// Test we correctly handle the case where the SETTINGS frame results in a
// negative send window size.
-TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
- const int32_t initial_window_size =
- SpdySession::GetDefaultInitialWindowSize(GetParam().protocol);
+TEST_F(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
+ const int32_t initial_window_size = kDefaultInitialWindowSize;
// Number of upload data buffers we need to send to zero out the window size
// is the minimal number of upload buffers takes to be bigger than
// |initial_window_size|.
@@ -6754,21 +6036,21 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
// Construct content for a data frame of maximum size.
std::string content(kMaxSpdyFrameChunkSize, 'a');
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1,
/*content_length=*/kBufferSize * num_upload_buffers + kUploadDataSize,
LOWEST, NULL, 0));
// Full frames.
- std::unique_ptr<SpdySerializedFrame> body1(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(
1, content.c_str(), content.size(), false));
// Last frame in each upload data buffer.
- std::unique_ptr<SpdySerializedFrame> body2(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(
1, content.c_str(), kBufferSize % kMaxSpdyFrameChunkSize, false));
// The very last frame before the stalled frames.
- std::unique_ptr<SpdySerializedFrame> body3(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(
1, content.c_str(),
initial_window_size % kBufferSize % kMaxSpdyFrameChunkSize, false));
@@ -6778,29 +6060,28 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
// we need one additional frame to send the rest of 'a'.
std::string last_body(kBufferSize * num_upload_buffers - initial_window_size,
'a');
- std::unique_ptr<SpdySerializedFrame> body4(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame body4(spdy_util_.ConstructSpdyDataFrame(
1, last_body.c_str(), last_body.size(), false));
// Also send a "hello!" after WINDOW_UPDATE.
- std::unique_ptr<SpdySerializedFrame> body5(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame body5(spdy_util_.ConstructSpdyDataFrame(1, true));
// Fill in mock writes.
size_t i = 0;
std::vector<MockWrite> writes;
- writes.push_back(CreateMockWrite(*req, i++));
+ writes.push_back(CreateMockWrite(req, i++));
for (size_t j = 0; j < num_upload_buffers; j++) {
for (size_t k = 0; k < num_frames_in_one_upload_buffer; k++) {
if (k == num_frames_in_one_upload_buffer - 1 &&
kBufferSize % kMaxSpdyFrameChunkSize != 0) {
if (j == num_upload_buffers - 1 &&
(initial_window_size % kBufferSize != 0)) {
- writes.push_back(CreateMockWrite(*body3, i++));
+ writes.push_back(CreateMockWrite(body3, i++));
} else {
- writes.push_back(CreateMockWrite(*body2, i++));
+ writes.push_back(CreateMockWrite(body2, i++));
}
} else {
- writes.push_back(CreateMockWrite(*body1, i++));
+ writes.push_back(CreateMockWrite(body1, i++));
}
}
}
@@ -6814,33 +6095,31 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
SettingsMap new_settings;
new_settings[SETTINGS_INITIAL_WINDOW_SIZE] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, initial_window_size / 2);
- std::unique_ptr<SpdySerializedFrame> settings_frame_small(
+ SpdySerializedFrame settings_frame_small(
spdy_util_.ConstructSpdySettings(new_settings));
// Construct read frames for WINDOW_UPDATE that makes the send_window_size
// positive.
- std::unique_ptr<SpdySerializedFrame> session_window_update_init_size(
+ SpdySerializedFrame session_window_update_init_size(
spdy_util_.ConstructSpdyWindowUpdate(0, initial_window_size));
- std::unique_ptr<SpdySerializedFrame> window_update_init_size(
+ SpdySerializedFrame window_update_init_size(
spdy_util_.ConstructSpdyWindowUpdate(1, initial_window_size));
- reads.push_back(CreateMockRead(*settings_frame_small, i++));
- reads.push_back(CreateMockRead(*session_window_update_init_size, i++));
- reads.push_back(CreateMockRead(*window_update_init_size, i++));
+ reads.push_back(CreateMockRead(settings_frame_small, i++));
+ reads.push_back(CreateMockRead(session_window_update_init_size, i++));
+ reads.push_back(CreateMockRead(window_update_init_size, i++));
- std::unique_ptr<SpdySerializedFrame> settings_ack(
- spdy_util_.ConstructSpdySettingsAck());
- writes.push_back(CreateMockWrite(*settings_ack, i++));
+ SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
+ writes.push_back(CreateMockWrite(settings_ack, i++));
// Stalled frames which can be sent after |settings_ack|.
if (last_body.size() > 0)
- writes.push_back(CreateMockWrite(*body4, i++));
- writes.push_back(CreateMockWrite(*body5, i++));
-
- std::unique_ptr<SpdySerializedFrame> reply(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
- reads.push_back(CreateMockRead(*reply, i++));
- reads.push_back(CreateMockRead(*body2, i++));
- reads.push_back(CreateMockRead(*body5, i++));
+ writes.push_back(CreateMockWrite(body4, i++));
+ writes.push_back(CreateMockWrite(body5, i++));
+
+ SpdySerializedFrame reply(spdy_util_.ConstructSpdyPostReply(NULL, 0));
+ reads.push_back(CreateMockRead(reply, i++));
+ reads.push_back(CreateMockRead(body2, i++));
+ reads.push_back(CreateMockRead(body5, i++));
reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
// Force all writes to happen before any read, last write will not
@@ -6860,15 +6139,16 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
request.url = default_url_;
request.upload_data_stream = &upload_data_stream;
NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
- BoundNetLog(), GetParam(), NULL);
+ NetLogWithSource(), NULL);
helper.RunPreTestSetup();
helper.AddData(&data);
HttpNetworkTransaction* trans = helper.trans();
TestCompletionCallback callback;
- int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv =
+ trans->Start(&helper.request(), callback.callback(), NetLogWithSource());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
data.RunUntilPaused(); // Write as much as we can.
base::RunLoop().RunUntilIdle();
@@ -6897,63 +6177,62 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
helper.VerifyDataConsumed();
}
-TEST_P(SpdyNetworkTransactionTest, GoAwayOnOddPushStreamId) {
+TEST_F(SpdyNetworkTransactionTest, GoAwayOnOddPushStreamId) {
SpdyHeaderBlock push_headers;
spdy_util_.AddUrlToHeaderBlock("http://www.example.org/a.dat", &push_headers);
- std::unique_ptr<SpdySerializedFrame> push(
+ SpdySerializedFrame push(
spdy_util_.ConstructInitialSpdyPushFrame(std::move(push_headers), 3, 1));
- MockRead reads[] = {CreateMockRead(*push, 1)};
+ MockRead reads[] = {CreateMockRead(push, 1)};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
0, GOAWAY_PROTOCOL_ERROR, "Odd push stream id."));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2),
+ CreateMockWrite(req, 0), CreateMockWrite(goaway, 2),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- NormalSpdyTransactionHelper helper(
- CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
+ NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_SPDY_PROTOCOL_ERROR));
}
-TEST_P(SpdyNetworkTransactionTest,
+TEST_F(SpdyNetworkTransactionTest,
GoAwayOnPushStreamIdLesserOrEqualThanLastAccepted) {
- std::unique_ptr<SpdySerializedFrame> push_a(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush(
NULL, 0, 4, 1, GetDefaultUrlWithPath("/a.dat").c_str()));
SpdyHeaderBlock push_b_headers;
spdy_util_.AddUrlToHeaderBlock(GetDefaultUrlWithPath("/b.dat"),
&push_b_headers);
- std::unique_ptr<SpdySerializedFrame> push_b(
- spdy_util_.ConstructInitialSpdyPushFrame(std::move(push_b_headers), 2,
- 1));
+ SpdySerializedFrame push_b(spdy_util_.ConstructInitialSpdyPushFrame(
+ std::move(push_b_headers), 2, 1));
MockRead reads[] = {
- CreateMockRead(*push_a, 1), CreateMockRead(*push_b, 2),
+ CreateMockRead(push_a, 1), CreateMockRead(push_b, 2),
};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
4, GOAWAY_PROTOCOL_ERROR,
"New push stream id must be greater than the last accepted."));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 3),
+ CreateMockWrite(req, 0), CreateMockWrite(goaway, 3),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- NormalSpdyTransactionHelper helper(
- CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
+ NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
+ NetLogWithSource(), NULL);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_SPDY_PROTOCOL_ERROR));
}
// Regression test for https://crbug.com/493348: request header exceeds 16 kB
// and thus sent in multiple frames when using HTTP/2.
-TEST_P(SpdyNetworkTransactionTest, LargeRequest) {
+TEST_F(SpdyNetworkTransactionTest, LargeRequest) {
const std::string kKey("foo");
const std::string kValue(1 << 15, 'z');
@@ -6964,40 +6243,37 @@ TEST_P(SpdyNetworkTransactionTest, LargeRequest) {
SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
headers[kKey] = kValue;
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdySyn(1, std::move(headers), LOWEST, true));
+ SpdySerializedFrame req(
+ spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
+ CreateMockWrite(req, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
MockRead(ASYNC, 0, 3) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
- NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(),
- GetParam(), nullptr);
+ NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
+ NetLogWithSource(), nullptr);
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
}
// Regression test for https://crbug.com/535629: response header exceeds 16 kB.
-TEST_P(SpdyNetworkTransactionTest, LargeResponseHeader) {
+TEST_F(SpdyNetworkTransactionTest, LargeResponseHeader) {
SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdySyn(1, std::move(headers), LOWEST, true));
+ SpdySerializedFrame req(
+ spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
+ CreateMockWrite(req, 0),
};
// HPACK decoder implementation limits string literal length to 16 kB.
@@ -7007,88 +6283,51 @@ TEST_P(SpdyNetworkTransactionTest, LargeResponseHeader) {
const std::string kValue(16 * 1024, 'b');
response_headers[1] = kValue.data();
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(response_headers, 1, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(
+ spdy_util_.ConstructSpdyGetReply(response_headers, 1, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp, 1), CreateMockRead(*body, 2),
+ CreateMockRead(resp, 1), CreateMockRead(body, 2),
MockRead(ASYNC, 0, 3) // EOF
};
HttpRequestInfo request;
request.method = "GET";
request.url = default_url_;
- NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(),
- GetParam(), nullptr);
+ NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
+ NetLogWithSource(), nullptr);
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
helper.RunToCompletion(&data);
TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
+ EXPECT_THAT(out.rv, IsOk());
EXPECT_EQ("HTTP/1.1 200", out.status_line);
EXPECT_EQ("hello!", out.response_data);
ASSERT_TRUE(out.response_info.headers->HasHeaderValue(kKey, kValue));
}
-class SpdyNetworkTransactionNoTLSUsageCheckTest
- : public SpdyNetworkTransactionTest {
- protected:
- void RunNoTLSUsageCheckTest(
- std::unique_ptr<SSLSocketDataProvider> ssl_provider) {
- // Construct the request.
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- MockWrite writes[] = {CreateMockWrite(*req, 0)};
-
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*body, 2),
- MockRead(ASYNC, 0, 3) // EOF
- };
-
- SequencedSocketData data(reads, arraysize(reads), writes,
- arraysize(writes));
- HttpRequestInfo request;
- request.method = "GET";
- request.url = default_url_;
- NormalSpdyTransactionHelper helper(
- request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
- helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
- TransactionHelperResult out = helper.output();
- EXPECT_EQ(OK, out.rv);
- EXPECT_EQ("HTTP/1.1 200", out.status_line);
- EXPECT_EQ("hello!", out.response_data);
- }
-};
-
-INSTANTIATE_TEST_CASE_P(
- Spdy,
- SpdyNetworkTransactionNoTLSUsageCheckTest,
- ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY31,
- false)));
+// End of line delimiter is forbidden according to RFC 7230 Section 3.2.
+TEST_F(SpdyNetworkTransactionTest, CRLFInHeaderValue) {
+ SpdySerializedFrame req(
+ spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
+ SpdySerializedFrame rst(
+ spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
+ MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 2)};
-TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest, TLSVersionTooOld) {
- std::unique_ptr<SSLSocketDataProvider> ssl_provider(
- new SSLSocketDataProvider(ASYNC, OK));
- SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3,
- &ssl_provider->connection_status);
+ const char* response_headers[] = {"folded", "foo\r\nbar"};
+ SpdySerializedFrame resp(
+ spdy_util_.ConstructSpdyGetReply(response_headers, 1, 1));
+ MockRead reads[] = {CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3)};
- RunNoTLSUsageCheckTest(std::move(ssl_provider));
-}
+ SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
-TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest, TLSCipherSuiteSucky) {
- std::unique_ptr<SSLSocketDataProvider> ssl_provider(
- new SSLSocketDataProvider(ASYNC, OK));
- // Set to TLS_RSA_WITH_NULL_MD5
- SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider->connection_status);
+ NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
+ NetLogWithSource(), nullptr);
+ helper.RunToCompletion(&data);
+ TransactionHelperResult out = helper.output();
- RunNoTLSUsageCheckTest(std::move(ssl_provider));
+ EXPECT_THAT(out.rv, IsError(ERR_SPDY_PROTOCOL_ERROR));
}
class SpdyNetworkTransactionTLSUsageCheckTest
@@ -7096,29 +6335,23 @@ class SpdyNetworkTransactionTLSUsageCheckTest
protected:
void RunTLSUsageCheckTest(
std::unique_ptr<SSLSocketDataProvider> ssl_provider) {
- std::unique_ptr<SpdySerializedFrame> goaway(
+ SpdySerializedFrame goaway(
spdy_util_.ConstructSpdyGoAway(0, GOAWAY_INADEQUATE_SECURITY, ""));
- MockWrite writes[] = {CreateMockWrite(*goaway)};
+ MockWrite writes[] = {CreateMockWrite(goaway)};
StaticSocketDataProvider data(NULL, 0, writes, arraysize(writes));
HttpRequestInfo request;
request.method = "GET";
request.url = default_url_;
- NormalSpdyTransactionHelper helper(
- request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
+ NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY,
+ NetLogWithSource(), NULL);
helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
TransactionHelperResult out = helper.output();
- EXPECT_EQ(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY, out.rv);
+ EXPECT_THAT(out.rv, IsError(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY));
}
};
-INSTANTIATE_TEST_CASE_P(
- Spdy,
- SpdyNetworkTransactionTLSUsageCheckTest,
- ::testing::Values(SpdyNetworkTransactionTestParams(kProtoHTTP2, false),
- SpdyNetworkTransactionTestParams(kProtoHTTP2, true)));
-
-TEST_P(SpdyNetworkTransactionTLSUsageCheckTest, TLSVersionTooOld) {
+TEST_F(SpdyNetworkTransactionTLSUsageCheckTest, TLSVersionTooOld) {
std::unique_ptr<SSLSocketDataProvider> ssl_provider(
new SSLSocketDataProvider(ASYNC, OK));
SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3,
@@ -7127,7 +6360,7 @@ TEST_P(SpdyNetworkTransactionTLSUsageCheckTest, TLSVersionTooOld) {
RunTLSUsageCheckTest(std::move(ssl_provider));
}
-TEST_P(SpdyNetworkTransactionTLSUsageCheckTest, TLSCipherSuiteSucky) {
+TEST_F(SpdyNetworkTransactionTLSUsageCheckTest, TLSCipherSuiteSucky) {
std::unique_ptr<SSLSocketDataProvider> ssl_provider(
new SSLSocketDataProvider(ASYNC, OK));
// Set to TLS_RSA_WITH_NULL_MD5
diff --git a/chromium/net/spdy/spdy_no_op_visitor.cc b/chromium/net/spdy/spdy_no_op_visitor.cc
new file mode 100644
index 00000000000..b9ac39580ac
--- /dev/null
+++ b/chromium/net/spdy/spdy_no_op_visitor.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/spdy/spdy_no_op_visitor.h"
+
+#include <type_traits>
+
+namespace net {
+namespace test {
+
+SpdyNoOpVisitor::SpdyNoOpVisitor() {
+ static_assert(std::is_abstract<SpdyNoOpVisitor>::value == false,
+ "Need to update SpdyNoOpVisitor.");
+}
+SpdyNoOpVisitor::~SpdyNoOpVisitor() {}
+
+net::SpdyHeadersHandlerInterface* SpdyNoOpVisitor::OnHeaderFrameStart(
+ SpdyStreamId stream_id) {
+ return this;
+}
+
+bool SpdyNoOpVisitor::OnControlFrameHeaderData(SpdyStreamId stream_id,
+ const char* header_data,
+ size_t header_data_len) {
+ return true;
+}
+
+bool SpdyNoOpVisitor::OnUnknownFrame(SpdyStreamId stream_id, int frame_type) {
+ return true;
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/spdy/spdy_no_op_visitor.h b/chromium/net/spdy/spdy_no_op_visitor.h
new file mode 100644
index 00000000000..5a1bdfa3445
--- /dev/null
+++ b/chromium/net/spdy/spdy_no_op_visitor.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SpdyNoOpVisitor implements several of the visitor and handler interfaces
+// to make it easier to write tests that need to provide instances. Other
+// interfaces can be added as needed.
+
+#ifndef NET_SPDY_SPDY_NO_OP_VISITOR_H_
+#define NET_SPDY_SPDY_NO_OP_VISITOR_H_
+
+#include "net/spdy/spdy_framer.h"
+#include "net/spdy/spdy_protocol.h"
+
+namespace net {
+namespace test {
+
+class SpdyNoOpVisitor : public SpdyFramerVisitorInterface,
+ public SpdyFramerDebugVisitorInterface,
+ public SpdyHeadersHandlerInterface {
+ public:
+ SpdyNoOpVisitor();
+ ~SpdyNoOpVisitor() override;
+
+ // SpdyFramerVisitorInterface methods:
+ void OnError(SpdyFramer* framer) override {}
+ void OnSynStream(SpdyStreamId stream_id,
+ SpdyStreamId associated_stream_id,
+ SpdyPriority priority,
+ bool fin,
+ bool unidirectional) override {}
+ void OnSynReply(SpdyStreamId stream_id, bool fin) override {}
+ net::SpdyHeadersHandlerInterface* OnHeaderFrameStart(
+ SpdyStreamId stream_id) override;
+ void OnHeaderFrameEnd(SpdyStreamId stream_id, bool end_headers) override {}
+ bool OnControlFrameHeaderData(SpdyStreamId stream_id,
+ const char* header_data,
+ size_t header_data_len) override;
+ void OnDataFrameHeader(SpdyStreamId stream_id,
+ size_t length,
+ bool fin) override {}
+ void OnStreamFrameData(SpdyStreamId stream_id,
+ const char* data,
+ size_t len) override {}
+ void OnStreamEnd(SpdyStreamId stream_id) override {}
+ void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {}
+ void OnRstStream(SpdyStreamId stream_id,
+ SpdyRstStreamStatus status) override {}
+ void OnSetting(SpdySettingsIds id, uint8_t flags, uint32_t value) override {}
+ void OnPing(SpdyPingId unique_id, bool is_ack) override {}
+ void OnSettingsEnd() override {}
+ void OnSettingsAck() override {}
+ void OnGoAway(SpdyStreamId last_accepted_stream_id,
+ SpdyGoAwayStatus status) override {}
+ void OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ int weight,
+ SpdyStreamId parent_stream_id,
+ bool exclusive,
+ bool fin,
+ bool end) override {}
+ void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override {}
+ void OnPushPromise(SpdyStreamId stream_id,
+ SpdyStreamId promised_stream_id,
+ bool end) override {}
+ void OnContinuation(SpdyStreamId stream_id, bool end) override {}
+ void OnAltSvc(SpdyStreamId stream_id,
+ base::StringPiece origin,
+ const SpdyAltSvcWireFormat::AlternativeServiceVector&
+ altsvc_vector) override {}
+ void OnPriority(SpdyStreamId stream_id,
+ SpdyStreamId parent_stream_id,
+ int weight,
+ bool exclusive) override {}
+ bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override;
+
+ // SpdyFramerDebugVisitorInterface methods:
+ void OnSendCompressedFrame(SpdyStreamId stream_id,
+ SpdyFrameType type,
+ size_t payload_len,
+ size_t frame_len) override {}
+ void OnReceiveCompressedFrame(SpdyStreamId stream_id,
+ SpdyFrameType type,
+ size_t frame_len) override {}
+
+ // SpdyHeadersHandlerInterface methods:
+ void OnHeaderBlockStart() override {}
+ void OnHeader(base::StringPiece key, base::StringPiece value) override {}
+ void OnHeaderBlockEnd(size_t uncompressed_header_bytes) override {}
+ void OnHeaderBlockEnd(size_t /* uncompressed_header_bytes */,
+ size_t /* compressed_header_bytes */) override {}
+};
+
+} // namespace test
+} // namespace net
+
+#endif // NET_SPDY_SPDY_NO_OP_VISITOR_H_
diff --git a/chromium/net/spdy/spdy_protocol.cc b/chromium/net/spdy/spdy_protocol.cc
index 8f3204e6cd9..e8dd952fcbc 100644
--- a/chromium/net/spdy/spdy_protocol.cc
+++ b/chromium/net/spdy/spdy_protocol.cc
@@ -691,47 +691,23 @@ int SpdyConstants::SerializeGoAwayStatus(SpdyMajorVersion version,
return -1;
}
-size_t SpdyConstants::GetDataFrameMinimumSize(SpdyMajorVersion version) {
- switch (version) {
- case SPDY3:
- return 8;
- case HTTP2:
- return 9;
- }
- SPDY_BUG << "Unhandled SPDY version.";
- return 0;
-}
-
-size_t SpdyConstants::GetControlFrameHeaderSize(SpdyMajorVersion version) {
+size_t SpdyConstants::GetFrameHeaderSize(SpdyMajorVersion version) {
switch (version) {
case SPDY3:
return 8;
case HTTP2:
return 9;
}
- SPDY_BUG << "Unhandled SPDY version.";
+ SPDY_BUG << "Unhandled SPDY version: " << version;
return 0;
}
-size_t SpdyConstants::GetPrefixLength(SpdyFrameType type,
- SpdyMajorVersion version) {
- if (type != DATA) {
- return GetControlFrameHeaderSize(version);
- } else {
- return GetDataFrameMinimumSize(version);
- }
+size_t SpdyConstants::GetDataFrameMinimumSize(SpdyMajorVersion version) {
+ return GetFrameHeaderSize(version);
}
-size_t SpdyConstants::GetFrameMaximumSize(SpdyMajorVersion version) {
- if (version == SPDY3) {
- // 24-bit length field plus eight-byte frame header.
- return ((1 << 24) - 1) + 8;
- } else {
- // Max payload of 2^14 plus nine-byte frame header.
- // TODO(dahollings): Change this to the actual spec
- // max of (1 << 24) - 1 + 9.
- return (1 << 14) + 9;
- }
+size_t SpdyConstants::GetMaxFrameSizeLimit(SpdyMajorVersion version) {
+ return kSpdyMaxFrameSizeLimit + GetFrameHeaderSize(version);
}
size_t SpdyConstants::GetSizeOfSizeField() {
@@ -774,7 +750,11 @@ SpdyFrameWithHeaderBlockIR::SpdyFrameWithHeaderBlockIR(
SpdyFrameWithHeaderBlockIR::~SpdyFrameWithHeaderBlockIR() {}
SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, base::StringPiece data)
- : SpdyFrameWithFinIR(stream_id), padded_(false), padding_payload_len_(0) {
+ : SpdyFrameWithFinIR(stream_id),
+ data_(nullptr),
+ data_len_(0),
+ padded_(false),
+ padding_payload_len_(0) {
SetDataDeep(data);
}
@@ -784,12 +764,17 @@ SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, const char* data)
SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id, std::string data)
: SpdyFrameWithFinIR(stream_id),
data_store_(base::MakeUnique<std::string>(std::move(data))),
- data_(*data_store_),
+ data_(data_store_->data()),
+ data_len_(data_store_->size()),
padded_(false),
padding_payload_len_(0) {}
SpdyDataIR::SpdyDataIR(SpdyStreamId stream_id)
- : SpdyFrameWithFinIR(stream_id), padded_(false), padding_payload_len_(0) {}
+ : SpdyFrameWithFinIR(stream_id),
+ data_(nullptr),
+ data_len_(0),
+ padded_(false),
+ padding_payload_len_(0) {}
SpdyDataIR::~SpdyDataIR() {}
@@ -857,6 +842,13 @@ SpdyGoAwayIR::SpdyGoAwayIR(SpdyStreamId last_good_stream_id,
SpdyGoAwayIR::~SpdyGoAwayIR() {}
+SpdyContinuationIR::SpdyContinuationIR(SpdyStreamId stream_id)
+ : SpdyFrameWithStreamIdIR(stream_id), end_headers_(false) {
+ encoding_ = base::MakeUnique<std::string>();
+}
+
+SpdyContinuationIR::~SpdyContinuationIR() {}
+
void SpdyGoAwayIR::Visit(SpdyFrameVisitor* visitor) const {
return visitor->VisitGoAway(*this);
}
diff --git a/chromium/net/spdy/spdy_protocol.h b/chromium/net/spdy/spdy_protocol.h
index ff492e293e8..922e649e33d 100644
--- a/chromium/net/spdy/spdy_protocol.h
+++ b/chromium/net/spdy/spdy_protocol.h
@@ -50,7 +50,7 @@ typedef uint32_t SpdyStreamId;
// flow control).
const SpdyStreamId kSessionFlowControlStreamId = 0;
-// The maxmium possible frame payload size allowed by the spec.
+// The maximum possible frame payload size allowed by the spec.
const uint32_t kSpdyMaxFrameSizeLimit = (1 << 24) - 1;
// The initial value for the maximum frame payload size as per the spec. This is
@@ -532,12 +532,11 @@ class NET_EXPORT_PRIVATE SpdyConstants {
// for this value as opposed to a constant.
static size_t GetDataFrameMinimumSize(SpdyMajorVersion version);
- // Size, in bytes, of the control frame header.
- static size_t GetControlFrameHeaderSize(SpdyMajorVersion version);
+ // Number of octets in the frame header.
+ static size_t GetFrameHeaderSize(SpdyMajorVersion version);
- static size_t GetPrefixLength(SpdyFrameType type, SpdyMajorVersion version);
-
- static size_t GetFrameMaximumSize(SpdyMajorVersion version);
+ // Maximum possible configurable size of a frame in octets.
+ static size_t GetMaxFrameSizeLimit(SpdyMajorVersion version);
// Returns the size of a header block size field. Valid only for SPDY 3.
static size_t GetSizeOfSizeField();
@@ -753,7 +752,8 @@ class NET_EXPORT_PRIVATE SpdyDataIR
~SpdyDataIR() override;
- base::StringPiece data() const { return data_; }
+ const char* data() const { return data_; }
+ size_t data_len() const { return data_len_; }
bool padded() const { return padded_; }
@@ -769,14 +769,24 @@ class NET_EXPORT_PRIVATE SpdyDataIR
// Deep-copy of data (keep private copy).
void SetDataDeep(base::StringPiece data) {
- data_store_.reset(new std::string(data.data(), data.length()));
- data_ = *(data_store_.get());
+ data_store_.reset(new std::string(data.data(), data.size()));
+ data_ = data_store_->data();
+ data_len_ = data.size();
}
// Shallow-copy of data (do not keep private copy).
void SetDataShallow(base::StringPiece data) {
data_store_.reset();
- data_ = data;
+ data_ = data.data();
+ data_len_ = data.size();
+ }
+
+ // Use this method if we don't have a contiguous buffer and only
+ // need a length.
+ void SetDataShallow(size_t len) {
+ data_store_.reset();
+ data_ = nullptr;
+ data_len_ = len;
}
void Visit(SpdyFrameVisitor* visitor) const override;
@@ -784,7 +794,8 @@ class NET_EXPORT_PRIVATE SpdyDataIR
private:
// Used to store data that this SpdyDataIR should own.
std::unique_ptr<std::string> data_store_;
- base::StringPiece data_;
+ const char* data_;
+ size_t data_len_;
bool padded_;
// padding_payload_len_ = desired padding length - len(padding length field).
@@ -993,6 +1004,8 @@ class NET_EXPORT_PRIVATE SpdyHeadersIR : public SpdyFrameWithHeaderBlockIR {
// The pad field takes one octet on the wire.
padding_payload_len_ = padding_len - 1;
}
+ bool end_headers() const { return end_headers_; }
+ void set_end_headers(bool end_headers) { end_headers_ = end_headers; }
private:
bool has_priority_ = false;
@@ -1001,6 +1014,7 @@ class NET_EXPORT_PRIVATE SpdyHeadersIR : public SpdyFrameWithHeaderBlockIR {
bool exclusive_ = false;
bool padded_ = false;
int padding_payload_len_ = 0;
+ bool end_headers_ = false;
DISALLOW_COPY_AND_ASSIGN(SpdyHeadersIR);
};
@@ -1072,23 +1086,22 @@ class NET_EXPORT_PRIVATE SpdyPushPromiseIR : public SpdyFrameWithHeaderBlockIR {
DISALLOW_COPY_AND_ASSIGN(SpdyPushPromiseIR);
};
-// TODO(jgraettinger): This representation needs review. SpdyContinuationIR
-// needs to frame a portion of a single, arbitrarily-broken encoded buffer.
-class NET_EXPORT_PRIVATE SpdyContinuationIR
- : public SpdyFrameWithHeaderBlockIR {
+class NET_EXPORT_PRIVATE SpdyContinuationIR : public SpdyFrameWithStreamIdIR {
public:
- explicit SpdyContinuationIR(SpdyStreamId stream_id)
- : SpdyContinuationIR(stream_id, SpdyHeaderBlock()) {}
- SpdyContinuationIR(SpdyStreamId stream_id, SpdyHeaderBlock header_block)
- : SpdyFrameWithHeaderBlockIR(stream_id, std::move(header_block)),
- end_headers_(false) {}
+ explicit SpdyContinuationIR(SpdyStreamId stream_id);
+ ~SpdyContinuationIR() override;
void Visit(SpdyFrameVisitor* visitor) const override;
bool end_headers() const { return end_headers_; }
void set_end_headers(bool end_headers) {end_headers_ = end_headers;}
+ const std::string& encoding() const { return *encoding_; }
+ void take_encoding(std::unique_ptr<std::string> encoding) {
+ encoding_ = std::move(encoding);
+ }
private:
+ std::unique_ptr<std::string> encoding_;
bool end_headers_;
DISALLOW_COPY_AND_ASSIGN(SpdyContinuationIR);
};
@@ -1196,6 +1209,23 @@ class SpdySerializedFrame {
// Returns the actual size of the underlying buffer.
size_t size() const { return size_; }
+ // Returns a buffer containing the contents of the frame, of which the caller
+ // takes ownership, and clears this SpdySerializedFrame.
+ char* ReleaseBuffer() {
+ char* buffer;
+ if (owns_buffer_) {
+ // If the buffer is owned, relinquish ownership to the caller.
+ buffer = frame_;
+ owns_buffer_ = false;
+ } else {
+ // Otherwise, we need to make a copy to give to the caller.
+ buffer = new char[size_];
+ memcpy(buffer, frame_, size_);
+ }
+ *this = SpdySerializedFrame();
+ return buffer;
+ }
+
protected:
char* frame_;
diff --git a/chromium/net/spdy/spdy_protocol_test.cc b/chromium/net/spdy/spdy_protocol_test.cc
index 9581e07d3fe..290009dc992 100644
--- a/chromium/net/spdy/spdy_protocol_test.cc
+++ b/chromium/net/spdy/spdy_protocol_test.cc
@@ -75,16 +75,16 @@ TEST(SpdyProtocolTest, IsValidHTTP2FrameStreamId) {
TEST(SpdyDataIRTest, Construct) {
// Confirm that it makes a string of zero length from a StringPiece(nullptr).
- base::StringPiece s1(nullptr);
+ base::StringPiece s1;
SpdyDataIR d1(1, s1);
- EXPECT_EQ(d1.data().size(), (uint64_t)0);
- EXPECT_NE(d1.data().data(), nullptr);
+ EXPECT_EQ(d1.data_len(), 0ul);
+ EXPECT_NE(d1.data(), nullptr);
// Confirms makes a copy of char array.
const char s2[] = "something";
SpdyDataIR d2(2, s2);
- EXPECT_EQ(d2.data(), s2);
- EXPECT_NE(d1.data().data(), s2);
+ EXPECT_EQ(base::StringPiece(d2.data(), d2.data_len()), s2);
+ EXPECT_NE(base::StringPiece(d1.data(), d1.data_len()), s2);
// Confirm copies a const string.
const std::string foo = "foo";
@@ -94,26 +94,19 @@ TEST(SpdyDataIRTest, Construct) {
// Confirm copies a non-const string.
std::string bar = "bar";
SpdyDataIR d4(4, bar);
- bar[0] = 'B';
- EXPECT_EQ("bar", d4.data());
+ EXPECT_EQ("bar", bar);
+ EXPECT_EQ("bar", base::StringPiece(d4.data(), d4.data_len()));
// Confirm moves an rvalue reference. Note that the test string "baz" is too
// short to trigger the move optimization, and instead a copy occurs.
- std::string baz = "The quick brown fox jumps over the lazy dog.";
- const char* baz_data = baz.data();
+ std::string baz = "the quick brown fox";
SpdyDataIR d5(5, std::move(baz));
EXPECT_EQ("", baz);
- EXPECT_EQ(d5.data(), "The quick brown fox jumps over the lazy dog.");
- EXPECT_EQ(d5.data().data(), baz_data);
-
- // Confirm that it makes a string of zero length from a nullptr.
- SpdyDataIR d6(6, nullptr);
- EXPECT_EQ(d6.data().size(), (uint64_t)0);
- EXPECT_NE(d6.data().data(), nullptr);
+ EXPECT_EQ(base::StringPiece(d5.data(), d5.data_len()), "the quick brown fox");
// Confirms makes a copy of string literal.
SpdyDataIR d7(7, "something else");
- EXPECT_EQ(d7.data(), "something else");
+ EXPECT_EQ(base::StringPiece(d7.data(), d7.data_len()), "something else");
}
TEST(SpdyProtocolTest, ClampSpdy3Priority) {
diff --git a/chromium/net/spdy/spdy_protocol_test_utils.cc b/chromium/net/spdy/spdy_protocol_test_utils.cc
new file mode 100644
index 00000000000..dd600ded2d5
--- /dev/null
+++ b/chromium/net/spdy/spdy_protocol_test_utils.cc
@@ -0,0 +1,191 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdint.h>
+
+#include "net/spdy/spdy_protocol_test_utils.h"
+
+namespace net {
+namespace test {
+
+// TODO(jamessynge): Where it makes sense in these functions, it would be nice
+// to make use of the existing gMock matchers here, instead of rolling our own.
+
+::testing::AssertionResult VerifySpdyFrameWithHeaderBlockIREquals(
+ const SpdyFrameWithHeaderBlockIR& expected,
+ const SpdyFrameWithHeaderBlockIR& actual) {
+ DVLOG(1) << "VerifySpdyFrameWithHeaderBlockIREquals";
+ if (actual.header_block() != expected.header_block())
+ return ::testing::AssertionFailure();
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyAltSvcIR& expected,
+ const SpdyAltSvcIR& actual) {
+ if (expected.stream_id() != actual.stream_id())
+ return ::testing::AssertionFailure();
+ if (expected.origin() != actual.origin())
+ return ::testing::AssertionFailure();
+ if (actual.altsvc_vector() != expected.altsvc_vector())
+ return ::testing::AssertionFailure();
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult VerifySpdyFrameIREquals(
+ const SpdyContinuationIR& expected,
+ const SpdyContinuationIR& actual) {
+ return ::testing::AssertionFailure()
+ << "VerifySpdyFrameIREquals SpdyContinuationIR not yet implemented";
+}
+
+::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyDataIR& expected,
+ const SpdyDataIR& actual) {
+ DVLOG(1) << "VerifySpdyFrameIREquals SpdyDataIR";
+ if (expected.stream_id() != actual.stream_id())
+ return ::testing::AssertionFailure();
+ if (expected.fin() != actual.fin())
+ return ::testing::AssertionFailure();
+ if (expected.data_len() != actual.data_len())
+ return ::testing::AssertionFailure();
+ if (expected.data() == nullptr && actual.data() != nullptr)
+ return ::testing::AssertionFailure();
+ if (base::StringPiece(expected.data(), expected.data_len()) !=
+ base::StringPiece(actual.data(), actual.data_len()))
+ return ::testing::AssertionFailure();
+ if (!VerifySpdyFrameWithPaddingIREquals(expected, actual))
+ return ::testing::AssertionFailure();
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyGoAwayIR& expected,
+ const SpdyGoAwayIR& actual) {
+ DVLOG(1) << "VerifySpdyFrameIREquals SpdyGoAwayIR";
+ if (expected.last_good_stream_id() != actual.last_good_stream_id())
+ return ::testing::AssertionFailure();
+ if (expected.status() != actual.status())
+ return ::testing::AssertionFailure();
+ if (expected.description() != actual.description())
+ return ::testing::AssertionFailure();
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult VerifySpdyFrameIREquals(
+ const SpdyHeadersIR& expected,
+ const SpdyHeadersIR& actual) {
+ DVLOG(1) << "VerifySpdyFrameIREquals SpdyHeadersIR";
+ if (expected.stream_id() != actual.stream_id())
+ return ::testing::AssertionFailure();
+ if (expected.fin() != actual.fin())
+ return ::testing::AssertionFailure();
+ if (!VerifySpdyFrameWithHeaderBlockIREquals(expected, actual))
+ return ::testing::AssertionFailure();
+ if (expected.has_priority() != actual.has_priority())
+ return ::testing::AssertionFailure();
+ if (expected.has_priority()) {
+ if (!VerifySpdyFrameWithPriorityIREquals(expected, actual))
+ return ::testing::AssertionFailure();
+ }
+ if (!VerifySpdyFrameWithPaddingIREquals(expected, actual))
+ return ::testing::AssertionFailure();
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyPingIR& expected,
+ const SpdyPingIR& actual) {
+ DVLOG(1) << "VerifySpdyFrameIREquals SpdyPingIR";
+ if (expected.id() != actual.id())
+ return ::testing::AssertionFailure();
+ if (expected.is_ack() != actual.is_ack())
+ return ::testing::AssertionFailure();
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult VerifySpdyFrameIREquals(
+ const SpdyPriorityIR& expected,
+ const SpdyPriorityIR& actual) {
+ DVLOG(1) << "VerifySpdyFrameIREquals SpdyPriorityIR";
+ if (expected.stream_id() != actual.stream_id())
+ return ::testing::AssertionFailure();
+ if (!VerifySpdyFrameWithPriorityIREquals(expected, actual))
+ return ::testing::AssertionFailure();
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult VerifySpdyFrameIREquals(
+ const SpdyPushPromiseIR& expected,
+ const SpdyPushPromiseIR& actual) {
+ DVLOG(1) << "VerifySpdyFrameIREquals SpdyPushPromiseIR";
+ if (expected.stream_id() != actual.stream_id())
+ return ::testing::AssertionFailure();
+ if (!VerifySpdyFrameWithPaddingIREquals(expected, actual))
+ return ::testing::AssertionFailure();
+ if (expected.promised_stream_id() != actual.promised_stream_id())
+ return ::testing::AssertionFailure();
+ if (!VerifySpdyFrameWithHeaderBlockIREquals(expected, actual))
+ return ::testing::AssertionFailure();
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult VerifySpdyFrameIREquals(
+ const SpdyRstStreamIR& expected,
+ const SpdyRstStreamIR& actual) {
+ DVLOG(1) << "VerifySpdyFrameIREquals SpdyRstStreamIR";
+ if (expected.stream_id() != actual.stream_id())
+ return ::testing::AssertionFailure();
+ if (expected.status() != actual.status())
+ return ::testing::AssertionFailure();
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult VerifySpdyFrameIREquals(
+ const SpdySettingsIR& expected,
+ const SpdySettingsIR& actual) {
+ DVLOG(1) << "VerifySpdyFrameIREquals SpdySettingsIR";
+ // Note, ignoring non-HTTP/2 fields such as clear_settings.
+ if (expected.is_ack() != actual.is_ack())
+ return ::testing::AssertionFailure();
+
+ if (expected.values().size() != actual.values().size())
+ return ::testing::AssertionFailure();
+ for (const auto& entry : expected.values()) {
+ const auto& param = entry.first;
+ auto actual_itr = actual.values().find(param);
+ if (actual_itr == actual.values().end()) {
+ DVLOG(1) << "actual doesn't contain param: " << param;
+ return ::testing::AssertionFailure();
+ }
+ uint32_t expected_value = entry.second.value;
+ uint32_t actual_value = actual_itr->second.value;
+ if (expected_value != actual_value) {
+ DVLOG(1) << "Values don't match for parameter: " << param;
+ return ::testing::AssertionFailure();
+ }
+ }
+
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult VerifySpdyFrameIREquals(
+ const SpdyWindowUpdateIR& expected,
+ const SpdyWindowUpdateIR& actual) {
+ DVLOG(1) << "VerifySpdyFrameIREquals SpdyWindowUpdateIR";
+ if (expected.stream_id() != actual.stream_id())
+ return ::testing::AssertionFailure();
+ if (expected.delta() != actual.delta())
+ return ::testing::AssertionFailure();
+
+ return ::testing::AssertionSuccess();
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/spdy/spdy_protocol_test_utils.h b/chromium/net/spdy/spdy_protocol_test_utils.h
new file mode 100644
index 00000000000..493345015fe
--- /dev/null
+++ b/chromium/net/spdy/spdy_protocol_test_utils.h
@@ -0,0 +1,160 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_SPDY_SPDY_PROTOCOL_TEST_UTILS_H_
+#define NET_SPDY_SPDY_PROTOCOL_TEST_UTILS_H_
+
+// These functions support tests that need to compare two concrete SpdyFrameIR
+// instances for equality. They return AssertionResult, so they may be used as
+// follows:
+//
+// SomeSpdyFrameIRSubClass expected_ir(...);
+// std::unique_ptr<SpdyFrameIR> collected_frame;
+// ... some test code that may fill in collected_frame ...
+// ASSERT_TRUE(VerifySpdyFrameIREquals(expected_ir, collected_frame.get()));
+//
+// TODO(jamessynge): Where it makes sense in these functions, it would be nice
+// to make use of the existing gMock matchers here, instead of rolling our own.
+
+#include <typeinfo>
+
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "net/spdy/spdy_protocol.h"
+#include "net/spdy/spdy_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace net {
+namespace test {
+
+// Verify the header entries in two SpdyFrameWithHeaderBlockIR instances
+// are the same.
+::testing::AssertionResult VerifySpdyFrameWithHeaderBlockIREquals(
+ const SpdyFrameWithHeaderBlockIR& expected,
+ const SpdyFrameWithHeaderBlockIR& actual);
+
+// Verify that the padding in two frames of type T is the same.
+template <class T>
+::testing::AssertionResult VerifySpdyFrameWithPaddingIREquals(const T& expected,
+ const T& actual) {
+ DVLOG(1) << "VerifySpdyFrameWithPaddingIREquals";
+ if (expected.padded() != actual.padded())
+ return ::testing::AssertionFailure();
+ if (expected.padded()) {
+ if (expected.padding_payload_len() != actual.padding_payload_len())
+ return ::testing::AssertionFailure();
+ }
+
+ return ::testing::AssertionSuccess();
+}
+
+// Verify the priority fields in two frames of type T are the same.
+template <class T>
+::testing::AssertionResult VerifySpdyFrameWithPriorityIREquals(
+ const T& expected,
+ const T& actual) {
+ DVLOG(1) << "VerifySpdyFrameWithPriorityIREquals";
+ if (expected.parent_stream_id() != actual.parent_stream_id())
+ return ::testing::AssertionFailure();
+ if (expected.weight() != actual.weight())
+ return ::testing::AssertionFailure();
+ if (expected.exclusive() != actual.exclusive())
+ return ::testing::AssertionFailure();
+
+ return ::testing::AssertionSuccess();
+}
+
+// Verify that two SpdyAltSvcIR frames are the same.
+::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyAltSvcIR& expected,
+ const SpdyAltSvcIR& actual);
+
+// VerifySpdyFrameIREquals for SpdyContinuationIR frames isn't really needed
+// because we don't really make use of SpdyContinuationIR, instead creating
+// SpdyHeadersIR or SpdyPushPromiseIR with the pre-encoding form of the HPACK
+// block (i.e. we don't yet have a CONTINUATION frame).
+//
+// ::testing::AssertionResult VerifySpdyFrameIREquals(
+// const SpdyContinuationIR& expected,
+// const SpdyContinuationIR& actual) {
+// return ::testing::AssertionFailure()
+// << "VerifySpdyFrameIREquals SpdyContinuationIR NYI";
+// }
+
+// Verify that two SpdyDataIR frames are the same.
+::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyDataIR& expected,
+ const SpdyDataIR& actual);
+
+// Verify that two SpdyGoAwayIR frames are the same.
+::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyGoAwayIR& expected,
+ const SpdyGoAwayIR& actual);
+
+// Verify that two SpdyHeadersIR frames are the same.
+::testing::AssertionResult VerifySpdyFrameIREquals(
+ const SpdyHeadersIR& expected,
+ const SpdyHeadersIR& actual);
+
+// Verify that two SpdyPingIR frames are the same.
+::testing::AssertionResult VerifySpdyFrameIREquals(const SpdyPingIR& expected,
+ const SpdyPingIR& actual);
+
+// Verify that two SpdyPriorityIR frames are the same.
+::testing::AssertionResult VerifySpdyFrameIREquals(
+ const SpdyPriorityIR& expected,
+ const SpdyPriorityIR& actual);
+
+// Verify that two SpdyPushPromiseIR frames are the same.
+::testing::AssertionResult VerifySpdyFrameIREquals(
+ const SpdyPushPromiseIR& expected,
+ const SpdyPushPromiseIR& actual);
+
+// Verify that two SpdyRstStreamIR frames are the same.
+::testing::AssertionResult VerifySpdyFrameIREquals(
+ const SpdyRstStreamIR& expected,
+ const SpdyRstStreamIR& actual);
+
+// Verify that two SpdySettingsIR frames are the same.
+::testing::AssertionResult VerifySpdyFrameIREquals(
+ const SpdySettingsIR& expected,
+ const SpdySettingsIR& actual);
+
+// Verify that two SpdyWindowUpdateIR frames are the same.
+::testing::AssertionResult VerifySpdyFrameIREquals(
+ const SpdyWindowUpdateIR& expected,
+ const SpdyWindowUpdateIR& actual);
+
+// Verify that either expected and actual are both nullptr, or that both are not
+// nullptr, and that actual is of type E, and that it matches expected.
+template <class E>
+::testing::AssertionResult VerifySpdyFrameIREquals(const E* expected,
+ const SpdyFrameIR* actual) {
+ if (expected == nullptr || actual == nullptr) {
+ DVLOG(1) << "VerifySpdyFrameIREquals one null";
+ if (expected != nullptr)
+ return ::testing::AssertionFailure();
+ if (actual != nullptr)
+ return ::testing::AssertionFailure();
+
+ return ::testing::AssertionSuccess();
+ }
+ DVLOG(1) << "VerifySpdyFrameIREquals not null";
+ const E* actual2 = reinterpret_cast<const E*>(actual);
+ if (actual2 == nullptr)
+ return ::testing::AssertionFailure();
+
+ return VerifySpdyFrameIREquals(*expected, *actual2);
+}
+
+// Verify that actual is not nullptr, that it is of type E and that it
+// matches expected.
+template <class E>
+::testing::AssertionResult VerifySpdyFrameIREquals(const E& expected,
+ const SpdyFrameIR* actual) {
+ DVLOG(1) << "VerifySpdyFrameIREquals";
+ return VerifySpdyFrameIREquals(&expected, actual);
+}
+
+} // namespace test
+} // namespace net
+
+#endif // NET_SPDY_SPDY_PROTOCOL_TEST_UTILS_H_
diff --git a/chromium/net/spdy/spdy_proxy_client_socket.cc b/chromium/net/spdy/spdy_proxy_client_socket.cc
index 36bdf392a1d..ea771b3cf82 100644
--- a/chromium/net/spdy/spdy_proxy_client_socket.cc
+++ b/chromium/net/spdy/spdy_proxy_client_socket.cc
@@ -23,6 +23,9 @@
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/http/proxy_connect_redirect_http_stream.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
#include "net/spdy/spdy_http_utils.h"
#include "url/gurl.h"
@@ -33,7 +36,7 @@ SpdyProxyClientSocket::SpdyProxyClientSocket(
const std::string& user_agent,
const HostPortPair& endpoint,
const HostPortPair& proxy_server,
- const BoundNetLog& source_net_log,
+ const NetLogWithSource& source_net_log,
HttpAuthController* auth_controller)
: next_state_(STATE_DISCONNECTED),
spdy_stream_(spdy_stream),
@@ -44,16 +47,16 @@ SpdyProxyClientSocket::SpdyProxyClientSocket(
write_buffer_len_(0),
was_ever_used_(false),
redirect_has_load_timing_info_(false),
- net_log_(BoundNetLog::Make(spdy_stream->net_log().net_log(),
- NetLog::SOURCE_PROXY_CLIENT_SOCKET)),
+ net_log_(NetLogWithSource::Make(spdy_stream->net_log().net_log(),
+ NetLogSourceType::PROXY_CLIENT_SOCKET)),
weak_factory_(this),
write_callback_weak_factory_(this) {
request_.method = "CONNECT";
request_.url = GURL("https://" + endpoint.ToString());
- net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
+ net_log_.BeginEvent(NetLogEventType::SOCKET_ALIVE,
source_net_log.source().ToEventParametersCallback());
net_log_.AddEvent(
- NetLog::TYPE_HTTP2_PROXY_CLIENT_SESSION,
+ NetLogEventType::HTTP2_PROXY_CLIENT_SESSION,
spdy_stream->net_log().source().ToEventParametersCallback());
spdy_stream_->SetDelegate(this);
@@ -62,7 +65,7 @@ SpdyProxyClientSocket::SpdyProxyClientSocket(
SpdyProxyClientSocket::~SpdyProxyClientSocket() {
Disconnect();
- net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
+ net_log_.EndEvent(NetLogEventType::SOCKET_ALIVE);
}
const HttpResponseInfo* SpdyProxyClientSocket::GetConnectResponseInfo() const {
@@ -86,14 +89,8 @@ bool SpdyProxyClientSocket::IsUsingSpdy() const {
return true;
}
-NextProto SpdyProxyClientSocket::GetProtocolNegotiated() const {
- // Save the negotiated protocol
- SSLInfo ssl_info;
- bool was_npn_negotiated;
- NextProto protocol_negotiated;
- spdy_stream_->GetSSLInfo(&ssl_info, &was_npn_negotiated,
- &protocol_negotiated);
- return protocol_negotiated;
+NextProto SpdyProxyClientSocket::GetProxyNegotiatedProtocol() const {
+ return spdy_stream_->GetNegotiatedProtocol();
}
HttpStream* SpdyProxyClientSocket::CreateConnectResponseStream() {
@@ -101,9 +98,9 @@ HttpStream* SpdyProxyClientSocket::CreateConnectResponseStream() {
redirect_has_load_timing_info_ ? &redirect_load_timing_info_ : NULL);
}
-// Sends a SYN_STREAM frame to the proxy with a CONNECT request
+// Sends a HEADERS frame to the proxy with a CONNECT request
// for the specified endpoint. Waits for the server to send back
-// a SYN_REPLY frame. OK will be returned if the status is 200.
+// a HEADERS frame. OK will be returned if the status is 200.
// ERR_TUNNEL_CONNECTION_FAILED will be returned for any other status.
// In any of these cases, Read() may be called to retrieve the HTTP
// response body. Any other return values should be considered fatal.
@@ -154,7 +151,7 @@ bool SpdyProxyClientSocket::IsConnectedAndIdle() const {
spdy_stream_->IsOpen();
}
-const BoundNetLog& SpdyProxyClientSocket::NetLog() const {
+const NetLogWithSource& SpdyProxyClientSocket::NetLog() const {
return net_log_;
}
@@ -179,10 +176,7 @@ NextProto SpdyProxyClientSocket::GetNegotiatedProtocol() const {
}
bool SpdyProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
- bool was_npn_negotiated;
- NextProto protocol_negotiated;
- return spdy_stream_->GetSSLInfo(ssl_info, &was_npn_negotiated,
- &protocol_negotiated);
+ return spdy_stream_->GetSSLInfo(ssl_info);
}
void SpdyProxyClientSocket::GetConnectionAttempts(
@@ -233,8 +227,8 @@ int SpdyProxyClientSocket::Write(IOBuffer* buf, int buf_len,
DCHECK(spdy_stream_.get());
spdy_stream_->SendData(buf, buf_len, MORE_DATA_TO_SEND);
- net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT,
- buf_len, buf->data());
+ net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_SENT, buf_len,
+ buf->data());
write_callback_ = callback;
write_buffer_len_ = buf_len;
return ERR_IO_PENDING;
@@ -301,24 +295,25 @@ int SpdyProxyClientSocket::DoLoop(int last_io_result) {
break;
case STATE_SEND_REQUEST:
DCHECK_EQ(OK, rv);
- net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST);
+ net_log_.BeginEvent(
+ NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST);
rv = DoSendRequest();
break;
case STATE_SEND_REQUEST_COMPLETE:
net_log_.EndEventWithNetErrorCode(
- NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
+ NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST, rv);
rv = DoSendRequestComplete(rv);
if (rv >= 0 || rv == ERR_IO_PENDING) {
// Emit extra event so can use the same events as
// HttpProxyClientSocket.
net_log_.BeginEvent(
- NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS);
+ NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS);
}
break;
case STATE_READ_REPLY_COMPLETE:
rv = DoReadReplyComplete(rv);
net_log_.EndEventWithNetErrorCode(
- NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
+ NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS, rv);
break;
default:
NOTREACHED() << "bad state";
@@ -360,14 +355,13 @@ int SpdyProxyClientSocket::DoSendRequest() {
&request_line, &request_.extra_headers);
net_log_.AddEvent(
- NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
base::Bind(&HttpRequestHeaders::NetLogCallback,
base::Unretained(&request_.extra_headers), &request_line));
- std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock());
- CreateSpdyHeadersFromHttpRequest(request_, request_.extra_headers,
- spdy_stream_->GetProtocolVersion(), true,
- headers.get());
+ SpdyHeaderBlock headers;
+ CreateSpdyHeadersFromHttpRequest(request_, request_.extra_headers, true,
+ &headers);
return spdy_stream_->SendRequestHeaders(std::move(headers),
MORE_DATA_TO_SEND);
@@ -377,14 +371,14 @@ int SpdyProxyClientSocket::DoSendRequestComplete(int result) {
if (result < 0)
return result;
- // Wait for SYN_REPLY frame from the server
+ // Wait for HEADERS frame from the server
next_state_ = STATE_READ_REPLY_COMPLETE;
return ERR_IO_PENDING;
}
int SpdyProxyClientSocket::DoReadReplyComplete(int result) {
// We enter this method directly from DoSendRequestComplete, since
- // we are notified by a callback when the SYN_REPLY frame arrives
+ // we are notified by a callback when the HEADERS frame arrives.
if (result < 0)
return result;
@@ -394,7 +388,7 @@ int SpdyProxyClientSocket::DoReadReplyComplete(int result) {
return ERR_TUNNEL_CONNECTION_FAILED;
net_log_.AddEvent(
- NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers));
switch (response_.headers->response_code()) {
@@ -451,8 +445,7 @@ SpdyResponseHeadersStatus SpdyProxyClientSocket::OnResponseHeadersUpdated(
return RESPONSE_HEADERS_ARE_COMPLETE;
// Save the response
- if (!SpdyHeadersToHttpResponse(
- response_headers, spdy_stream_->GetProtocolVersion(), &response_))
+ if (!SpdyHeadersToHttpResponse(response_headers, &response_))
return RESPONSE_HEADERS_ARE_INCOMPLETE;
OnIOComplete(OK);
@@ -462,12 +455,13 @@ SpdyResponseHeadersStatus SpdyProxyClientSocket::OnResponseHeadersUpdated(
// Called when data is received or on EOF (if |buffer| is NULL).
void SpdyProxyClientSocket::OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) {
if (buffer) {
- net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED,
+ net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED,
buffer->GetRemainingSize(),
buffer->GetRemainingData());
read_buffer_queue_.Enqueue(std::move(buffer));
} else {
- net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, 0, NULL);
+ net_log_.AddByteTransferEvent(NetLogEventType::SOCKET_BYTES_RECEIVED, 0,
+ NULL);
}
if (!read_callback_.is_null()) {
diff --git a/chromium/net/spdy/spdy_proxy_client_socket.h b/chromium/net/spdy/spdy_proxy_client_socket.h
index 09c10e402f4..645f5c56c7d 100644
--- a/chromium/net/spdy/spdy_proxy_client_socket.h
+++ b/chromium/net/spdy/spdy_proxy_client_socket.h
@@ -17,12 +17,13 @@
#include "net/base/completion_callback.h"
#include "net/base/host_port_pair.h"
#include "net/base/load_timing_info.h"
+#include "net/base/net_export.h"
#include "net/http/http_auth_controller.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_info.h"
#include "net/http/proxy_client_socket.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/spdy/spdy_http_stream.h"
#include "net/spdy/spdy_protocol.h"
#include "net/spdy/spdy_read_queue.h"
@@ -39,15 +40,15 @@ class SpdyStream;
class NET_EXPORT_PRIVATE SpdyProxyClientSocket : public ProxyClientSocket,
public SpdyStream::Delegate {
public:
- // Create a socket on top of the |spdy_stream| by sending a SYN_STREAM
- // CONNECT frame for |endpoint|. After the SYN_REPLY is received,
- // any data read/written to the socket will be transferred in data
- // frames. This object will set itself as |spdy_stream|'s delegate.
+ // Create a socket on top of the |spdy_stream| by sending a HEADERS CONNECT
+ // frame for |endpoint|. After the response HEADERS frame is received, any
+ // data read/written to the socket will be transferred in data frames. This
+ // object will set itself as |spdy_stream|'s delegate.
SpdyProxyClientSocket(const base::WeakPtr<SpdyStream>& spdy_stream,
const std::string& user_agent,
const HostPortPair& endpoint,
const HostPortPair& proxy_server,
- const BoundNetLog& source_net_log,
+ const NetLogWithSource& source_net_log,
HttpAuthController* auth_controller);
// On destruction Disconnect() is called.
@@ -59,14 +60,14 @@ class NET_EXPORT_PRIVATE SpdyProxyClientSocket : public ProxyClientSocket,
const scoped_refptr<HttpAuthController>& GetAuthController() const override;
int RestartWithAuth(const CompletionCallback& callback) override;
bool IsUsingSpdy() const override;
- NextProto GetProtocolNegotiated() const override;
+ NextProto GetProxyNegotiatedProtocol() const override;
// StreamSocket implementation.
int Connect(const CompletionCallback& callback) override;
void Disconnect() override;
bool IsConnected() const override;
bool IsConnectedAndIdle() const override;
- const BoundNetLog& NetLog() const override;
+ const NetLogWithSource& NetLog() const override;
void SetSubresourceSpeculation() override;
void SetOmniboxSpeculation() override;
bool WasEverUsed() const override;
@@ -169,7 +170,7 @@ class NET_EXPORT_PRIVATE SpdyProxyClientSocket : public ProxyClientSocket,
bool redirect_has_load_timing_info_;
LoadTimingInfo redirect_load_timing_info_;
- const BoundNetLog net_log_;
+ const NetLogWithSource net_log_;
// The default weak pointer factory.
base::WeakPtrFactory<SpdyProxyClientSocket> weak_factory_;
diff --git a/chromium/net/spdy/spdy_proxy_client_socket_unittest.cc b/chromium/net/spdy/spdy_proxy_client_socket_unittest.cc
index 0ea01fafb05..7c09e576b03 100644
--- a/chromium/net/spdy/spdy_proxy_client_socket_unittest.cc
+++ b/chromium/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -17,12 +17,12 @@
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.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/client_socket_factory.h"
-#include "net/socket/next_proto.h"
#include "net/socket/socket_test_util.h"
#include "net/socket/tcp_client_socket.h"
#include "net/spdy/buffered_spdy_framer.h"
@@ -30,26 +30,20 @@
#include "net/spdy/spdy_protocol.h"
#include "net/spdy/spdy_session_pool.h"
#include "net/spdy/spdy_test_util_common.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsError;
+using net::test::IsOk;
+
//-----------------------------------------------------------------------------
namespace {
-enum TestCase {
- // Test using the SPDY/3.1 protocol.
- kTestCaseSPDY31,
-
- // Test using the HTTP/2 protocol, without specifying a stream
- // dependency based on the RequestPriority.
- kTestCaseHTTP2NoPriorityDependencies,
-
- // Test using the HTTP/2 protocol, specifying a stream
- // dependency based on the RequestPriority.
- kTestCaseHTTP2PriorityDependencies
-};
-
static const char kRequestUrl[] = "https://www.google.com/";
static const char kOriginHost[] = "www.google.com";
static const int kOriginPort = 443;
@@ -78,29 +72,25 @@ static const char kRedirectUrl[] = "https://example.com/";
namespace net {
-class SpdyProxyClientSocketTest : public PlatformTest,
- public testing::WithParamInterface<TestCase> {
+class SpdyProxyClientSocketTest : public PlatformTest {
public:
SpdyProxyClientSocketTest();
- ~SpdyProxyClientSocketTest();
+ ~SpdyProxyClientSocketTest() override;
void TearDown() override;
protected:
- NextProto GetProtocol() const;
- bool GetDependenciesFromPriority() const;
-
void Initialize(MockRead* reads, size_t reads_count, MockWrite* writes,
size_t writes_count);
void PopulateConnectRequestIR(SpdyHeaderBlock* syn_ir);
void PopulateConnectReplyIR(SpdyHeaderBlock* block, const char* status);
- SpdySerializedFrame* ConstructConnectRequestFrame();
- SpdySerializedFrame* ConstructConnectAuthRequestFrame();
- SpdySerializedFrame* ConstructConnectReplyFrame();
- SpdySerializedFrame* ConstructConnectAuthReplyFrame();
- SpdySerializedFrame* ConstructConnectRedirectReplyFrame();
- SpdySerializedFrame* ConstructConnectErrorReplyFrame();
- SpdySerializedFrame* ConstructBodyFrame(const char* data, int length);
+ SpdySerializedFrame ConstructConnectRequestFrame();
+ SpdySerializedFrame ConstructConnectAuthRequestFrame();
+ SpdySerializedFrame ConstructConnectReplyFrame();
+ SpdySerializedFrame ConstructConnectAuthReplyFrame();
+ SpdySerializedFrame ConstructConnectRedirectReplyFrame();
+ SpdySerializedFrame ConstructConnectErrorReplyFrame();
+ SpdySerializedFrame ConstructBodyFrame(const char* data, int length);
scoped_refptr<IOBufferWithSize> CreateBuffer(const char* data, int size);
void AssertConnectSucceeds();
void AssertConnectFails(int result);
@@ -148,8 +138,6 @@ class SpdyProxyClientSocketTest : public PlatformTest,
SpdySessionDependencies session_deps_;
MockConnect connect_data_;
base::WeakPtr<SpdySession> spdy_session_;
- BufferedSpdyFramer framer_;
-
std::string user_agent_;
GURL url_;
HostPortPair proxy_host_port_;
@@ -160,18 +148,9 @@ class SpdyProxyClientSocketTest : public PlatformTest,
DISALLOW_COPY_AND_ASSIGN(SpdyProxyClientSocketTest);
};
-INSTANTIATE_TEST_CASE_P(ProtoPlusDepend,
- SpdyProxyClientSocketTest,
- testing::Values(kTestCaseSPDY31,
- kTestCaseHTTP2NoPriorityDependencies,
- kTestCaseHTTP2PriorityDependencies));
-
SpdyProxyClientSocketTest::SpdyProxyClientSocketTest()
- : spdy_util_(GetProtocol(), GetDependenciesFromPriority()),
- read_buf_(NULL),
- session_deps_(GetProtocol()),
+ : read_buf_(NULL),
connect_data_(SYNCHRONOUS, OK),
- framer_(spdy_util_.spdy_version()),
user_agent_(kUserAgent),
url_(kRequestUrl),
proxy_host_port_(kProxyHost, kProxyPort),
@@ -181,7 +160,6 @@ SpdyProxyClientSocketTest::SpdyProxyClientSocketTest()
proxy_,
PRIVACY_MODE_DISABLED) {
session_deps_.net_log = net_log_.bound().net_log();
- session_deps_.enable_priority_dependencies = GetDependenciesFromPriority();
}
SpdyProxyClientSocketTest::~SpdyProxyClientSocketTest() {
@@ -198,14 +176,6 @@ void SpdyProxyClientSocketTest::TearDown() {
PlatformTest::TearDown();
}
-NextProto SpdyProxyClientSocketTest::GetProtocol() const {
- return GetParam() == kTestCaseSPDY31 ? kProtoSPDY31 : kProtoHTTP2;
-}
-
-bool SpdyProxyClientSocketTest::GetDependenciesFromPriority() const {
- return GetParam() == kTestCaseHTTP2PriorityDependencies;
-}
-
void SpdyProxyClientSocketTest::Initialize(MockRead* reads,
size_t reads_count,
MockWrite* writes,
@@ -213,15 +183,20 @@ void SpdyProxyClientSocketTest::Initialize(MockRead* reads,
data_.reset(
new SequencedSocketData(reads, reads_count, writes, writes_count));
data_->set_connect_data(connect_data_);
-
session_deps_.socket_factory->AddSocketDataProvider(data_.get());
+
+ SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
+ ssl.cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
+ ASSERT_TRUE(ssl.cert);
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+
session_deps_.host_resolver->set_synchronous_mode(true);
session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
// Creates the SPDY session and stream.
- spdy_session_ = CreateInsecureSpdySession(
- session_.get(), endpoint_spdy_session_key_, BoundNetLog());
+ spdy_session_ = CreateSecureSpdySession(
+ session_.get(), endpoint_spdy_session_key_, NetLogWithSource());
base::WeakPtr<SpdyStream> spdy_stream(
CreateStreamSynchronously(
SPDY_BIDIRECTIONAL_STREAM, spdy_session_, url_, LOWEST,
@@ -245,12 +220,14 @@ scoped_refptr<IOBufferWithSize> SpdyProxyClientSocketTest::CreateBuffer(
}
void SpdyProxyClientSocketTest::AssertConnectSucceeds() {
- ASSERT_EQ(ERR_IO_PENDING, sock_->Connect(read_callback_.callback()));
- ASSERT_EQ(OK, read_callback_.WaitForResult());
+ ASSERT_THAT(sock_->Connect(read_callback_.callback()),
+ IsError(ERR_IO_PENDING));
+ ASSERT_THAT(read_callback_.WaitForResult(), IsOk());
}
void SpdyProxyClientSocketTest::AssertConnectFails(int result) {
- ASSERT_EQ(ERR_IO_PENDING, sock_->Connect(read_callback_.callback()));
+ ASSERT_THAT(sock_->Connect(read_callback_.callback()),
+ IsError(ERR_IO_PENDING));
ASSERT_EQ(result, read_callback_.WaitForResult());
}
@@ -319,52 +296,45 @@ void SpdyProxyClientSocketTest::AssertWriteLength(int len) {
void SpdyProxyClientSocketTest::PopulateConnectRequestIR(
SpdyHeaderBlock* block) {
- spdy_util_.MaybeAddVersionHeader(block);
(*block)[spdy_util_.GetMethodKey()] = "CONNECT";
- if (spdy_util_.spdy_version() == HTTP2) {
- (*block)[spdy_util_.GetHostKey()] = kOriginHostPort;
- } else {
- (*block)[spdy_util_.GetHostKey()] = kOriginHost;
- (*block)[spdy_util_.GetPathKey()] = kOriginHostPort;
- }
+ (*block)[spdy_util_.GetHostKey()] = kOriginHostPort;
(*block)["user-agent"] = kUserAgent;
}
void SpdyProxyClientSocketTest::PopulateConnectReplyIR(SpdyHeaderBlock* block,
const char* status) {
(*block)[spdy_util_.GetStatusKey()] = status;
- spdy_util_.MaybeAddVersionHeader(block);
}
-// Constructs a standard SPDY SYN_STREAM frame for a CONNECT request.
-SpdySerializedFrame* SpdyProxyClientSocketTest::ConstructConnectRequestFrame() {
+// Constructs a standard SPDY HEADERS frame for a CONNECT request.
+SpdySerializedFrame SpdyProxyClientSocketTest::ConstructConnectRequestFrame() {
SpdyHeaderBlock block;
PopulateConnectRequestIR(&block);
- return spdy_util_.ConstructSpdySyn(kStreamId, std::move(block), LOWEST,
- false);
+ return spdy_util_.ConstructSpdyHeaders(kStreamId, std::move(block), LOWEST,
+ false);
}
-// Constructs a SPDY SYN_STREAM frame for a CONNECT request which includes
+// Constructs a SPDY HEADERS frame for a CONNECT request which includes
// Proxy-Authorization headers.
-SpdySerializedFrame*
+SpdySerializedFrame
SpdyProxyClientSocketTest::ConstructConnectAuthRequestFrame() {
SpdyHeaderBlock block;
PopulateConnectRequestIR(&block);
block["proxy-authorization"] = "Basic Zm9vOmJhcg==";
- return spdy_util_.ConstructSpdySyn(kStreamId, std::move(block), LOWEST,
- false);
+ return spdy_util_.ConstructSpdyHeaders(kStreamId, std::move(block), LOWEST,
+ false);
}
-// Constructs a standard SPDY SYN_REPLY frame to match the SPDY CONNECT.
-SpdySerializedFrame* SpdyProxyClientSocketTest::ConstructConnectReplyFrame() {
+// Constructs a standard SPDY HEADERS frame to match the SPDY CONNECT.
+SpdySerializedFrame SpdyProxyClientSocketTest::ConstructConnectReplyFrame() {
SpdyHeaderBlock block;
PopulateConnectReplyIR(&block, "200");
return spdy_util_.ConstructSpdyReply(kStreamId, std::move(block));
}
-// Constructs a standard SPDY SYN_REPLY frame to match the SPDY CONNECT,
+// Constructs a standard SPDY HEADERS frame to match the SPDY CONNECT,
// including Proxy-Authenticate headers.
-SpdySerializedFrame*
+SpdySerializedFrame
SpdyProxyClientSocketTest::ConstructConnectAuthReplyFrame() {
SpdyHeaderBlock block;
PopulateConnectReplyIR(&block, "407");
@@ -372,8 +342,8 @@ SpdyProxyClientSocketTest::ConstructConnectAuthReplyFrame() {
return spdy_util_.ConstructSpdyReply(kStreamId, std::move(block));
}
-// Constructs a SPDY SYN_REPLY frame with an HTTP 302 redirect.
-SpdySerializedFrame*
+// Constructs a SPDY HEADERS frame with an HTTP 302 redirect.
+SpdySerializedFrame
SpdyProxyClientSocketTest::ConstructConnectRedirectReplyFrame() {
SpdyHeaderBlock block;
PopulateConnectReplyIR(&block, "302");
@@ -382,31 +352,32 @@ SpdyProxyClientSocketTest::ConstructConnectRedirectReplyFrame() {
return spdy_util_.ConstructSpdyReply(kStreamId, std::move(block));
}
-// Constructs a SPDY SYN_REPLY frame with an HTTP 500 error.
-SpdySerializedFrame*
+// Constructs a SPDY HEADERS frame with an HTTP 500 error.
+SpdySerializedFrame
SpdyProxyClientSocketTest::ConstructConnectErrorReplyFrame() {
SpdyHeaderBlock block;
PopulateConnectReplyIR(&block, "500");
return spdy_util_.ConstructSpdyReply(kStreamId, std::move(block));
}
-SpdySerializedFrame* SpdyProxyClientSocketTest::ConstructBodyFrame(
+SpdySerializedFrame SpdyProxyClientSocketTest::ConstructBodyFrame(
const char* data,
int length) {
- return framer_.CreateDataFrame(kStreamId, data, length, DATA_FLAG_NONE);
+ return spdy_util_.ConstructSpdyDataFrame(kStreamId, data, length,
+ /*fin=*/false);
}
// ----------- Connect
-TEST_P(SpdyProxyClientSocketTest, ConnectSendsCorrectRequest) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, ConnectSendsCorrectRequest) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -418,15 +389,15 @@ TEST_P(SpdyProxyClientSocketTest, ConnectSendsCorrectRequest) {
AssertConnectionEstablished();
}
-TEST_P(SpdyProxyClientSocketTest, ConnectWithAuthRequested) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, ConnectWithAuthRequested) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectAuthReplyFrame());
+ SpdySerializedFrame resp(ConstructConnectAuthReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -438,15 +409,15 @@ TEST_P(SpdyProxyClientSocketTest, ConnectWithAuthRequested) {
ASSERT_EQ(407, response->headers->response_code());
}
-TEST_P(SpdyProxyClientSocketTest, ConnectWithAuthCredentials) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectAuthRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, ConnectWithAuthCredentials) {
+ SpdySerializedFrame conn(ConstructConnectAuthRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -457,18 +428,17 @@ TEST_P(SpdyProxyClientSocketTest, ConnectWithAuthCredentials) {
AssertConnectionEstablished();
}
-TEST_P(SpdyProxyClientSocketTest, ConnectRedirects) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
- std::unique_ptr<SpdySerializedFrame> rst(
+TEST_F(SpdyProxyClientSocketTest, ConnectRedirects) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS), CreateMockWrite(*rst, 3),
+ CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- ConstructConnectRedirectReplyFrame());
+ SpdySerializedFrame resp(ConstructConnectRedirectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -491,13 +461,13 @@ TEST_P(SpdyProxyClientSocketTest, ConnectRedirects) {
base::RunLoop().RunUntilIdle();
}
-TEST_P(SpdyProxyClientSocketTest, ConnectFails) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, ConnectFails) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
MockRead reads[] = {
MockRead(ASYNC, 0, 1), // EOF
};
@@ -513,17 +483,17 @@ TEST_P(SpdyProxyClientSocketTest, ConnectFails) {
// ----------- WasEverUsed
-TEST_P(SpdyProxyClientSocketTest, WasEverUsedReturnsCorrectValues) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
- std::unique_ptr<SpdySerializedFrame> rst(
+TEST_F(SpdyProxyClientSocketTest, WasEverUsedReturnsCorrectValues) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS), CreateMockWrite(*rst, 3),
+ CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -540,52 +510,52 @@ TEST_P(SpdyProxyClientSocketTest, WasEverUsedReturnsCorrectValues) {
// ----------- GetPeerAddress
-TEST_P(SpdyProxyClientSocketTest, GetPeerAddressReturnsCorrectValues) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, GetPeerAddressReturnsCorrectValues) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
MockRead(ASYNC, 0, 3), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
IPEndPoint addr;
- EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, sock_->GetPeerAddress(&addr));
+ EXPECT_THAT(sock_->GetPeerAddress(&addr), IsError(ERR_SOCKET_NOT_CONNECTED));
AssertConnectSucceeds();
EXPECT_TRUE(sock_->IsConnected());
- EXPECT_EQ(OK, sock_->GetPeerAddress(&addr));
+ EXPECT_THAT(sock_->GetPeerAddress(&addr), IsOk());
ResumeAndRun();
EXPECT_FALSE(sock_->IsConnected());
- EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, sock_->GetPeerAddress(&addr));
+ EXPECT_THAT(sock_->GetPeerAddress(&addr), IsError(ERR_SOCKET_NOT_CONNECTED));
sock_->Disconnect();
- EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, sock_->GetPeerAddress(&addr));
+ EXPECT_THAT(sock_->GetPeerAddress(&addr), IsError(ERR_SOCKET_NOT_CONNECTED));
}
// ----------- Write
-TEST_P(SpdyProxyClientSocketTest, WriteSendsDataInDataFrame) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
- std::unique_ptr<SpdySerializedFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
- std::unique_ptr<SpdySerializedFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
+TEST_F(SpdyProxyClientSocketTest, WriteSendsDataInDataFrame) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
+ SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
+ SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
- CreateMockWrite(*msg1, 3, SYNCHRONOUS),
- CreateMockWrite(*msg2, 4, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
+ CreateMockWrite(msg1, 3, SYNCHRONOUS),
+ CreateMockWrite(msg2, 4, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -596,19 +566,19 @@ TEST_P(SpdyProxyClientSocketTest, WriteSendsDataInDataFrame) {
AssertAsyncWriteSucceeds(kMsg2, kLen2);
}
-TEST_P(SpdyProxyClientSocketTest, WriteSplitsLargeDataIntoMultipleFrames) {
+TEST_F(SpdyProxyClientSocketTest, WriteSplitsLargeDataIntoMultipleFrames) {
std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
- std::unique_ptr<SpdySerializedFrame> chunk(
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
+ SpdySerializedFrame chunk(
ConstructBodyFrame(chunk_data.data(), chunk_data.length()));
- MockWrite writes[] = {CreateMockWrite(*conn, 0, SYNCHRONOUS),
- CreateMockWrite(*chunk, 3, SYNCHRONOUS),
- CreateMockWrite(*chunk, 4, SYNCHRONOUS),
- CreateMockWrite(*chunk, 5, SYNCHRONOUS)};
+ MockWrite writes[] = {CreateMockWrite(conn, 0, SYNCHRONOUS),
+ CreateMockWrite(chunk, 3, SYNCHRONOUS),
+ CreateMockWrite(chunk, 4, SYNCHRONOUS),
+ CreateMockWrite(chunk, 5, SYNCHRONOUS)};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -626,17 +596,17 @@ TEST_P(SpdyProxyClientSocketTest, WriteSplitsLargeDataIntoMultipleFrames) {
// ----------- Read
-TEST_P(SpdyProxyClientSocketTest, ReadReadsDataInDataFrame) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, ReadReadsDataInDataFrame) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
- std::unique_ptr<SpdySerializedFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*msg1, 3, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(msg1, 3, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -648,19 +618,19 @@ TEST_P(SpdyProxyClientSocketTest, ReadReadsDataInDataFrame) {
AssertSyncReadEquals(kMsg1, kLen1);
}
-TEST_P(SpdyProxyClientSocketTest, ReadDataFromBufferedFrames) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, ReadDataFromBufferedFrames) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
- std::unique_ptr<SpdySerializedFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
- std::unique_ptr<SpdySerializedFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
+ SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*msg1, 3, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 4),
- CreateMockRead(*msg2, 5, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(msg1, 3, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 4),
+ CreateMockRead(msg2, 5, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -675,20 +645,20 @@ TEST_P(SpdyProxyClientSocketTest, ReadDataFromBufferedFrames) {
AssertSyncReadEquals(kMsg2, kLen2);
}
-TEST_P(SpdyProxyClientSocketTest, ReadDataMultipleBufferedFrames) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, ReadDataMultipleBufferedFrames) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
- std::unique_ptr<SpdySerializedFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
- std::unique_ptr<SpdySerializedFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
+ SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC),
+ CreateMockRead(resp, 1, ASYNC),
MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*msg1, 3, ASYNC),
- CreateMockRead(*msg2, 4, ASYNC),
+ CreateMockRead(msg1, 3, ASYNC),
+ CreateMockRead(msg2, 4, ASYNC),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),
};
@@ -703,21 +673,20 @@ TEST_P(SpdyProxyClientSocketTest, ReadDataMultipleBufferedFrames) {
AssertSyncReadEquals(kMsg2, kLen2);
}
-TEST_P(SpdyProxyClientSocketTest,
- LargeReadWillMergeDataFromDifferentFrames) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, LargeReadWillMergeDataFromDifferentFrames) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
- std::unique_ptr<SpdySerializedFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
- std::unique_ptr<SpdySerializedFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
+ SpdySerializedFrame msg3(ConstructBodyFrame(kMsg3, kLen3));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC),
+ CreateMockRead(resp, 1, ASYNC),
MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*msg3, 3, ASYNC),
- CreateMockRead(*msg3, 4, ASYNC),
+ CreateMockRead(msg3, 3, ASYNC),
+ CreateMockRead(msg3, 4, ASYNC),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),
};
@@ -733,23 +702,23 @@ TEST_P(SpdyProxyClientSocketTest,
AssertSyncReadEquals(kMsg33, kLen33);
}
-TEST_P(SpdyProxyClientSocketTest, MultipleShortReadsThenMoreRead) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, MultipleShortReadsThenMoreRead) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
- std::unique_ptr<SpdySerializedFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
- std::unique_ptr<SpdySerializedFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
- std::unique_ptr<SpdySerializedFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
+ SpdySerializedFrame msg3(ConstructBodyFrame(kMsg3, kLen3));
+ SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC),
+ CreateMockRead(resp, 1, ASYNC),
MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*msg1, 3, ASYNC),
- CreateMockRead(*msg3, 4, ASYNC),
- CreateMockRead(*msg3, 5, ASYNC),
- CreateMockRead(*msg2, 6, ASYNC),
+ CreateMockRead(msg1, 3, ASYNC),
+ CreateMockRead(msg3, 4, ASYNC),
+ CreateMockRead(msg3, 5, ASYNC),
+ CreateMockRead(msg2, 6, ASYNC),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 7),
};
@@ -767,22 +736,21 @@ TEST_P(SpdyProxyClientSocketTest, MultipleShortReadsThenMoreRead) {
AssertSyncReadEquals(kMsg2, kLen2);
}
-TEST_P(SpdyProxyClientSocketTest, ReadWillSplitDataFromLargeFrame) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, ReadWillSplitDataFromLargeFrame) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
- std::unique_ptr<SpdySerializedFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
- std::unique_ptr<SpdySerializedFrame> msg33(
- ConstructBodyFrame(kMsg33, kLen33));
- std::unique_ptr<SpdySerializedFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
+ SpdySerializedFrame msg33(ConstructBodyFrame(kMsg33, kLen33));
+ SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC),
+ CreateMockRead(resp, 1, ASYNC),
MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*msg1, 3, ASYNC),
- CreateMockRead(*msg33, 4, ASYNC),
+ CreateMockRead(msg1, 3, ASYNC),
+ CreateMockRead(msg33, 4, ASYNC),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),
};
@@ -800,18 +768,17 @@ TEST_P(SpdyProxyClientSocketTest, ReadWillSplitDataFromLargeFrame) {
AssertSyncReadEquals(kMsg3, kLen3);
}
-TEST_P(SpdyProxyClientSocketTest, MultipleReadsFromSameLargeFrame) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, MultipleReadsFromSameLargeFrame) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
- std::unique_ptr<SpdySerializedFrame> msg333(
- ConstructBodyFrame(kMsg333, kLen333));
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame msg333(ConstructBodyFrame(kMsg333, kLen333));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*msg333, 3, ASYNC),
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(msg333, 3, ASYNC),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
};
@@ -832,20 +799,20 @@ TEST_P(SpdyProxyClientSocketTest, MultipleReadsFromSameLargeFrame) {
ASSERT_TRUE(sock_->IsConnected());
}
-TEST_P(SpdyProxyClientSocketTest, ReadAuthResponseBody) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, ReadAuthResponseBody) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectAuthReplyFrame());
- std::unique_ptr<SpdySerializedFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
- std::unique_ptr<SpdySerializedFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
+ SpdySerializedFrame resp(ConstructConnectAuthReplyFrame());
+ SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
+ SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC),
+ CreateMockRead(resp, 1, ASYNC),
MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*msg1, 3, ASYNC),
- CreateMockRead(*msg2, 4, ASYNC),
+ CreateMockRead(msg1, 3, ASYNC),
+ CreateMockRead(msg2, 4, ASYNC),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),
};
@@ -860,20 +827,18 @@ TEST_P(SpdyProxyClientSocketTest, ReadAuthResponseBody) {
AssertSyncReadEquals(kMsg2, kLen2);
}
-TEST_P(SpdyProxyClientSocketTest, ReadErrorResponseBody) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, ReadErrorResponseBody) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectErrorReplyFrame());
- std::unique_ptr<SpdySerializedFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
- std::unique_ptr<SpdySerializedFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
+ SpdySerializedFrame resp(ConstructConnectErrorReplyFrame());
+ SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
+ SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC),
- CreateMockRead(*msg1, 2, ASYNC),
- CreateMockRead(*msg2, 3, ASYNC),
- MockRead(ASYNC, 0, 4), // EOF
+ CreateMockRead(resp, 1, ASYNC), CreateMockRead(msg1, 2, ASYNC),
+ CreateMockRead(msg2, 3, ASYNC), MockRead(ASYNC, 0, 4), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -883,23 +848,23 @@ TEST_P(SpdyProxyClientSocketTest, ReadErrorResponseBody) {
// ----------- Reads and Writes
-TEST_P(SpdyProxyClientSocketTest, AsyncReadAroundWrite) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
- std::unique_ptr<SpdySerializedFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
+TEST_F(SpdyProxyClientSocketTest, AsyncReadAroundWrite) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
+ SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
- CreateMockWrite(*msg2, 4, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
+ CreateMockWrite(msg2, 4, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
- std::unique_ptr<SpdySerializedFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
- std::unique_ptr<SpdySerializedFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
+ SpdySerializedFrame msg3(ConstructBodyFrame(kMsg3, kLen3));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC),
+ CreateMockRead(resp, 1, ASYNC),
MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*msg1, 3, ASYNC), // sync read
+ CreateMockRead(msg1, 3, ASYNC), // sync read
MockRead(ASYNC, ERR_IO_PENDING, 5),
- CreateMockRead(*msg3, 6, ASYNC), // async read
+ CreateMockRead(msg3, 6, ASYNC), // async read
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 7),
};
@@ -921,21 +886,21 @@ TEST_P(SpdyProxyClientSocketTest, AsyncReadAroundWrite) {
AssertReadReturns(kMsg3, kLen3);
}
-TEST_P(SpdyProxyClientSocketTest, AsyncWriteAroundReads) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
- std::unique_ptr<SpdySerializedFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
+TEST_F(SpdyProxyClientSocketTest, AsyncWriteAroundReads) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
+ SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
- MockWrite(ASYNC, ERR_IO_PENDING, 7), CreateMockWrite(*msg2, 8, ASYNC),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
+ MockWrite(ASYNC, ERR_IO_PENDING, 7), CreateMockWrite(msg2, 8, ASYNC),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
- std::unique_ptr<SpdySerializedFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
- std::unique_ptr<SpdySerializedFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
+ SpdySerializedFrame msg3(ConstructBodyFrame(kMsg3, kLen3));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*msg1, 3, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 4),
- CreateMockRead(*msg3, 5, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(msg1, 3, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 4),
+ CreateMockRead(msg3, 5, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -959,15 +924,15 @@ TEST_P(SpdyProxyClientSocketTest, AsyncWriteAroundReads) {
// ----------- Reading/Writing on Closed socket
// Reading from an already closed socket should return 0
-TEST_P(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsZero) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsZero) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
MockRead(ASYNC, 0, 3), // EOF
};
@@ -985,15 +950,15 @@ TEST_P(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsZero) {
}
// Read pending when socket is closed should return 0
-TEST_P(SpdyProxyClientSocketTest, PendingReadOnCloseReturnsZero) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, PendingReadOnCloseReturnsZero) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
MockRead(ASYNC, 0, 3), // EOF
};
@@ -1009,18 +974,17 @@ TEST_P(SpdyProxyClientSocketTest, PendingReadOnCloseReturnsZero) {
}
// Reading from a disconnected socket is an error
-TEST_P(SpdyProxyClientSocketTest,
- ReadOnDisconnectSocketReturnsNotConnected) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
- std::unique_ptr<SpdySerializedFrame> rst(
+TEST_F(SpdyProxyClientSocketTest, ReadOnDisconnectSocketReturnsNotConnected) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS), CreateMockWrite(*rst, 3),
+ CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -1038,17 +1002,17 @@ TEST_P(SpdyProxyClientSocketTest,
// Reading buffered data from an already closed socket should return
// buffered data, then 0.
-TEST_P(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsBufferedData) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsBufferedData) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
- std::unique_ptr<SpdySerializedFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*msg1, 3, ASYNC), MockRead(ASYNC, 0, 4), // EOF
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(msg1, 3, ASYNC), MockRead(ASYNC, 0, 4), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -1070,16 +1034,16 @@ TEST_P(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsBufferedData) {
}
// Calling Write() on a closed socket is an error
-TEST_P(SpdyProxyClientSocketTest, WriteOnClosedStream) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, WriteOnClosedStream) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
- std::unique_ptr<SpdySerializedFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
MockRead(ASYNC, 0, 3), // EOF
};
@@ -1095,18 +1059,18 @@ TEST_P(SpdyProxyClientSocketTest, WriteOnClosedStream) {
}
// Calling Write() on a disconnected socket is an error.
-TEST_P(SpdyProxyClientSocketTest, WriteOnDisconnectedSocket) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
- std::unique_ptr<SpdySerializedFrame> rst(
+TEST_F(SpdyProxyClientSocketTest, WriteOnDisconnectedSocket) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS), CreateMockWrite(*rst, 3),
+ CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
- std::unique_ptr<SpdySerializedFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -1125,16 +1089,16 @@ TEST_P(SpdyProxyClientSocketTest, WriteOnDisconnectedSocket) {
// If the socket is closed with a pending Write(), the callback
// should be called with ERR_CONNECTION_CLOSED.
-TEST_P(SpdyProxyClientSocketTest, WritePendingOnClose) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, WritePendingOnClose) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 3),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -1151,22 +1115,22 @@ TEST_P(SpdyProxyClientSocketTest, WritePendingOnClose) {
CloseSpdySession(ERR_ABORTED, std::string());
- EXPECT_EQ(ERR_CONNECTION_CLOSED, write_callback_.WaitForResult());
+ EXPECT_THAT(write_callback_.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
}
// If the socket is Disconnected with a pending Write(), the callback
// should not be called.
-TEST_P(SpdyProxyClientSocketTest, DisconnectWithWritePending) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
- std::unique_ptr<SpdySerializedFrame> rst(
+TEST_F(SpdyProxyClientSocketTest, DisconnectWithWritePending) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS), CreateMockWrite(*rst, 3),
+ CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -1190,17 +1154,17 @@ TEST_P(SpdyProxyClientSocketTest, DisconnectWithWritePending) {
// If the socket is Disconnected with a pending Read(), the callback
// should not be called.
-TEST_P(SpdyProxyClientSocketTest, DisconnectWithReadPending) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
- std::unique_ptr<SpdySerializedFrame> rst(
+TEST_F(SpdyProxyClientSocketTest, DisconnectWithReadPending) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS), CreateMockWrite(*rst, 3),
+ CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
+ CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -1224,18 +1188,18 @@ TEST_P(SpdyProxyClientSocketTest, DisconnectWithReadPending) {
// If the socket is Reset when both a read and write are pending,
// both should be called back.
-TEST_P(SpdyProxyClientSocketTest, RstWithReadAndWritePending) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, RstWithReadAndWritePending) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*rst, 3, ASYNC), MockRead(ASYNC, 0, 4) // EOF
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(rst, 3, ASYNC), MockRead(ASYNC, 0, 4) // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -1266,19 +1230,19 @@ TEST_P(SpdyProxyClientSocketTest, RstWithReadAndWritePending) {
// Makes sure the proxy client socket's source gets the expected NetLog events
// and only the expected NetLog events (No SpdySession events).
-TEST_P(SpdyProxyClientSocketTest, NetLog) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
- std::unique_ptr<SpdySerializedFrame> rst(
+TEST_F(SpdyProxyClientSocketTest, NetLog) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS), CreateMockWrite(*rst, 5),
+ CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 5),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
- std::unique_ptr<SpdySerializedFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*msg1, 3, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(msg1, 3, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -1289,35 +1253,38 @@ TEST_P(SpdyProxyClientSocketTest, NetLog) {
ResumeAndRun();
AssertSyncReadEquals(kMsg1, kLen1);
- NetLog::Source sock_source = sock_->NetLog().source();
+ NetLogSource sock_source = sock_->NetLog().source();
sock_.reset();
TestNetLogEntry::List entry_list;
net_log_.GetEntriesForSource(sock_source, &entry_list);
ASSERT_EQ(entry_list.size(), 10u);
- EXPECT_TRUE(LogContainsBeginEvent(entry_list, 0, NetLog::TYPE_SOCKET_ALIVE));
+ EXPECT_TRUE(
+ LogContainsBeginEvent(entry_list, 0, NetLogEventType::SOCKET_ALIVE));
EXPECT_TRUE(LogContainsEvent(entry_list, 1,
- NetLog::TYPE_HTTP2_PROXY_CLIENT_SESSION,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsBeginEvent(entry_list, 2,
- NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST));
- EXPECT_TRUE(LogContainsEvent(entry_list, 3,
- NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEndEvent(entry_list, 4,
- NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_SEND_REQUEST));
- EXPECT_TRUE(LogContainsBeginEvent(entry_list, 5,
- NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS));
- EXPECT_TRUE(LogContainsEvent(entry_list, 6,
- NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEndEvent(entry_list, 7,
- NetLog::TYPE_HTTP_TRANSACTION_TUNNEL_READ_HEADERS));
+ NetLogEventType::HTTP2_PROXY_CLIENT_SESSION,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsBeginEvent(
+ entry_list, 2, NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST));
+ EXPECT_TRUE(LogContainsEvent(
+ entry_list, 3, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEndEvent(
+ entry_list, 4, NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST));
+ EXPECT_TRUE(LogContainsBeginEvent(
+ entry_list, 5, NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS));
+ EXPECT_TRUE(LogContainsEvent(
+ entry_list, 6,
+ NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEndEvent(
+ entry_list, 7, NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS));
EXPECT_TRUE(LogContainsEvent(entry_list, 8,
- NetLog::TYPE_SOCKET_BYTES_RECEIVED,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEndEvent(entry_list, 9, NetLog::TYPE_SOCKET_ALIVE));
+ NetLogEventType::SOCKET_BYTES_RECEIVED,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(
+ LogContainsEndEvent(entry_list, 9, NetLogEventType::SOCKET_ALIVE));
// Let the RST_STREAM write while |rst| is in-scope.
base::RunLoop().RunUntilIdle();
@@ -1351,18 +1318,18 @@ class DeleteSockCallback : public TestCompletionCallbackBase {
// If the socket is Reset when both a read and write are pending, and the
// read callback causes the socket to be deleted, the write callback should
// not be called.
-TEST_P(SpdyProxyClientSocketTest, RstWithReadAndWritePendingDelete) {
- std::unique_ptr<SpdySerializedFrame> conn(ConstructConnectRequestFrame());
+TEST_F(SpdyProxyClientSocketTest, RstWithReadAndWritePendingDelete) {
+ SpdySerializedFrame conn(ConstructConnectRequestFrame());
MockWrite writes[] = {
- CreateMockWrite(*conn, 0, SYNCHRONOUS),
+ CreateMockWrite(conn, 0, SYNCHRONOUS),
};
- std::unique_ptr<SpdySerializedFrame> resp(ConstructConnectReplyFrame());
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame resp(ConstructConnectReplyFrame());
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockRead reads[] = {
- CreateMockRead(*resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*rst, 3, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
+ CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(rst, 3, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
diff --git a/chromium/net/spdy/spdy_read_queue.cc b/chromium/net/spdy/spdy_read_queue.cc
index 7948ff4480d..0c1eaf5d7b5 100644
--- a/chromium/net/spdy/spdy_read_queue.cc
+++ b/chromium/net/spdy/spdy_read_queue.cc
@@ -4,8 +4,10 @@
#include "net/spdy/spdy_read_queue.h"
+#include <algorithm>
+#include <utility>
+
#include "base/logging.h"
-#include "base/stl_util.h"
#include "net/spdy/spdy_buffer.h"
namespace net {
@@ -28,31 +30,30 @@ size_t SpdyReadQueue::GetTotalSize() const {
void SpdyReadQueue::Enqueue(std::unique_ptr<SpdyBuffer> buffer) {
DCHECK_GT(buffer->GetRemainingSize(), 0u);
total_size_ += buffer->GetRemainingSize();
- queue_.push_back(buffer.release());
+ queue_.push_back(std::move(buffer));
}
size_t SpdyReadQueue::Dequeue(char* out, size_t len) {
DCHECK_GT(len, 0u);
size_t bytes_copied = 0;
while (!queue_.empty() && bytes_copied < len) {
- SpdyBuffer* buffer = queue_.front();
+ SpdyBuffer* buffer = queue_.front().get();
size_t bytes_to_copy =
std::min(len - bytes_copied, buffer->GetRemainingSize());
memcpy(out + bytes_copied, buffer->GetRemainingData(), bytes_to_copy);
bytes_copied += bytes_to_copy;
- if (bytes_to_copy == buffer->GetRemainingSize()) {
- delete queue_.front();
+ if (bytes_to_copy == buffer->GetRemainingSize())
queue_.pop_front();
- } else {
+ else
buffer->Consume(bytes_to_copy);
- }
}
total_size_ -= bytes_copied;
return bytes_copied;
}
void SpdyReadQueue::Clear() {
- STLDeleteElements(&queue_);
+ queue_.clear();
+ total_size_ = 0;
}
} // namespace net
diff --git a/chromium/net/spdy/spdy_read_queue.h b/chromium/net/spdy/spdy_read_queue.h
index bf85afbb12c..87fc0ab4475 100644
--- a/chromium/net/spdy/spdy_read_queue.h
+++ b/chromium/net/spdy/spdy_read_queue.h
@@ -40,7 +40,9 @@ class NET_EXPORT_PRIVATE SpdyReadQueue {
void Clear();
private:
- std::deque<SpdyBuffer*> queue_;
+ // Class invariant:
+ // |total_size_| is the sum of GetRemainingSize() of |queue_|'s elements.
+ std::deque<std::unique_ptr<SpdyBuffer>> queue_;
size_t total_size_;
DISALLOW_COPY_AND_ASSIGN(SpdyReadQueue);
diff --git a/chromium/net/spdy/spdy_read_queue_unittest.cc b/chromium/net/spdy/spdy_read_queue_unittest.cc
index 468764dabad..a211af11a91 100644
--- a/chromium/net/spdy/spdy_read_queue_unittest.cc
+++ b/chromium/net/spdy/spdy_read_queue_unittest.cc
@@ -9,12 +9,14 @@
#include <memory>
#include <string>
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "net/spdy/spdy_buffer.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
-
+namespace test {
namespace {
const char kData[] = "SPDY read queue test data.\0Some more data.";
@@ -84,6 +86,17 @@ void RunEnqueueDequeueTest(size_t enqueue_max_buffer_size,
EXPECT_EQ(data, drained_data);
}
+void OnBufferDiscarded(bool* discarded,
+ size_t* discarded_bytes,
+ size_t delta,
+ SpdyBuffer::ConsumeSource consume_source) {
+ EXPECT_EQ(SpdyBuffer::DISCARD, consume_source);
+ *discarded = true;
+ *discarded_bytes = delta;
+}
+
+} // namespace
+
class SpdyReadQueueTest : public ::testing::Test {};
// Call RunEnqueueDequeueTest() with various buffer size combinatinos.
@@ -101,6 +114,26 @@ TEST_F(SpdyReadQueueTest, CoprimeBufferSizes) {
RunEnqueueDequeueTest(3, 2);
}
-} // namespace
+TEST_F(SpdyReadQueueTest, Clear) {
+ auto buffer = base::MakeUnique<SpdyBuffer>(kData, kDataSize);
+ bool discarded = false;
+ size_t discarded_bytes = 0;
+ buffer->AddConsumeCallback(
+ base::Bind(&OnBufferDiscarded, &discarded, &discarded_bytes));
+
+ SpdyReadQueue read_queue;
+ read_queue.Enqueue(std::move(buffer));
+
+ EXPECT_FALSE(discarded);
+ EXPECT_EQ(0u, discarded_bytes);
+ EXPECT_FALSE(read_queue.IsEmpty());
+
+ read_queue.Clear();
+
+ EXPECT_TRUE(discarded);
+ EXPECT_EQ(kDataSize, discarded_bytes);
+ EXPECT_TRUE(read_queue.IsEmpty());
+}
+} // namespace test
} // namespace net
diff --git a/chromium/net/spdy/spdy_session.cc b/chromium/net/spdy/spdy_session.cc
index 0e613264a0d..31d282ca888 100644
--- a/chromium/net/spdy/spdy_session.cc
+++ b/chromium/net/spdy/spdy_session.cc
@@ -38,6 +38,11 @@
#include "net/http/http_util.h"
#include "net/http/transport_security_state.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/proxy/proxy_server.h"
#include "net/socket/ssl_client_socket.h"
#include "net/spdy/spdy_buffer_producer.h"
@@ -61,22 +66,6 @@ const int kHungIntervalSeconds = 10;
// Minimum seconds that unclaimed pushed streams will be kept in memory.
const int kMinPushedStreamLifetimeSeconds = 300;
-std::unique_ptr<base::Value> NetLogSpdySynStreamSentCallback(
- const SpdyHeaderBlock* headers,
- bool fin,
- bool unidirectional,
- SpdyPriority spdy_priority,
- SpdyStreamId stream_id,
- NetLogCaptureMode capture_mode) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->Set("headers", ElideSpdyHeaderBlockForNetLog(*headers, capture_mode));
- dict->SetBoolean("fin", fin);
- dict->SetBoolean("unidirectional", unidirectional);
- dict->SetInteger("priority", static_cast<int>(spdy_priority));
- dict->SetInteger("stream_id", stream_id);
- return std::move(dict);
-}
-
std::unique_ptr<base::Value> NetLogSpdyHeadersSentCallback(
const SpdyHeaderBlock* headers,
bool fin,
@@ -99,25 +88,7 @@ std::unique_ptr<base::Value> NetLogSpdyHeadersSentCallback(
return std::move(dict);
}
-std::unique_ptr<base::Value> NetLogSpdySynStreamReceivedCallback(
- const SpdyHeaderBlock* headers,
- bool fin,
- bool unidirectional,
- SpdyPriority spdy_priority,
- SpdyStreamId stream_id,
- SpdyStreamId associated_stream,
- NetLogCaptureMode capture_mode) {
- std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->Set("headers", ElideSpdyHeaderBlockForNetLog(*headers, capture_mode));
- dict->SetBoolean("fin", fin);
- dict->SetBoolean("unidirectional", unidirectional);
- dict->SetInteger("priority", static_cast<int>(spdy_priority));
- dict->SetInteger("stream_id", stream_id);
- dict->SetInteger("associated_stream", associated_stream);
- return std::move(dict);
-}
-
-std::unique_ptr<base::Value> NetLogSpdySynReplyOrHeadersReceivedCallback(
+std::unique_ptr<base::Value> NetLogSpdyHeadersReceivedCallback(
const SpdyHeaderBlock* headers,
bool fin,
SpdyStreamId stream_id,
@@ -149,15 +120,13 @@ std::unique_ptr<base::Value> NetLogSpdySessionCallback(
}
std::unique_ptr<base::Value> NetLogSpdyInitializedCallback(
- NetLog::Source source,
- const NextProto protocol_version,
+ NetLogSource source,
NetLogCaptureMode /* capture_mode */) {
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
if (source.IsValid()) {
source.AddToEventParameters(dict.get());
}
- dict->SetString("protocol",
- SSLClientSocket::NextProtoToString(protocol_version));
+ dict->SetString("protocol", SSLClientSocket::NextProtoToString(kProtoHTTP2));
return std::move(dict);
}
@@ -173,13 +142,11 @@ std::unique_ptr<base::Value> NetLogSpdySettingsCallback(
std::unique_ptr<base::Value> NetLogSpdySettingCallback(
SpdySettingsIds id,
- const SpdyMajorVersion protocol_version,
SpdySettingsFlags flags,
uint32_t value,
NetLogCaptureMode /* capture_mode */) {
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
- dict->SetInteger("id",
- SpdyConstants::SerializeSettingId(protocol_version, id));
+ dict->SetInteger("id", SpdyConstants::SerializeSettingId(HTTP2, id));
dict->SetInteger("flags", flags);
dict->SetInteger("value", value);
return std::move(dict);
@@ -187,7 +154,6 @@ std::unique_ptr<base::Value> NetLogSpdySettingCallback(
std::unique_ptr<base::Value> NetLogSpdySendSettingsCallback(
const SettingsMap* settings,
- const SpdyMajorVersion protocol_version,
NetLogCaptureMode /* capture_mode */) {
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
std::unique_ptr<base::ListValue> settings_list(new base::ListValue());
@@ -198,7 +164,7 @@ std::unique_ptr<base::Value> NetLogSpdySendSettingsCallback(
const uint32_t value = it->second.second;
settings_list->AppendString(base::StringPrintf(
"[id:%u flags:%u value:%u]",
- SpdyConstants::SerializeSettingId(protocol_version, id), flags, value));
+ SpdyConstants::SerializeSettingId(HTTP2, id), flags, value));
}
dict->Set("settings", std::move(settings_list));
return std::move(dict);
@@ -472,26 +438,6 @@ SpdyGoAwayStatus MapNetErrorToGoAwayStatus(Error err) {
}
}
-void SplitPushedHeadersToRequestAndResponse(const SpdyHeaderBlock& headers,
- SpdyMajorVersion protocol_version,
- SpdyHeaderBlock* request_headers,
- SpdyHeaderBlock* response_headers) {
- DCHECK(response_headers);
- DCHECK(request_headers);
- for (SpdyHeaderBlock::const_iterator it = headers.begin();
- it != headers.end();
- ++it) {
- SpdyHeaderBlock* to_insert = response_headers;
- const char* host = protocol_version >= HTTP2 ? ":authority" : ":host";
- static const char scheme[] = ":scheme";
- static const char path[] = ":path";
- if (it->first == host || it->first == scheme || it->first == path) {
- to_insert = request_headers;
- }
- to_insert->insert(*it);
- }
-}
-
SpdyStreamRequest::SpdyStreamRequest() : weak_ptr_factory_(this) {
Reset();
}
@@ -500,13 +446,12 @@ SpdyStreamRequest::~SpdyStreamRequest() {
CancelRequest();
}
-int SpdyStreamRequest::StartRequest(
- SpdyStreamType type,
- const base::WeakPtr<SpdySession>& session,
- const GURL& url,
- RequestPriority priority,
- const BoundNetLog& net_log,
- const CompletionCallback& callback) {
+int SpdyStreamRequest::StartRequest(SpdyStreamType type,
+ const base::WeakPtr<SpdySession>& session,
+ const GURL& url,
+ RequestPriority priority,
+ const NetLogWithSource& net_log,
+ const CompletionCallback& callback) {
DCHECK(session);
DCHECK(!session_);
DCHECK(!stream_);
@@ -572,18 +517,16 @@ void SpdyStreamRequest::Reset() {
stream_.reset();
url_ = GURL();
priority_ = MINIMUM_PRIORITY;
- net_log_ = BoundNetLog();
+ net_log_ = NetLogWithSource();
callback_.Reset();
}
SpdySession::ActiveStreamInfo::ActiveStreamInfo()
- : stream(NULL),
- waiting_for_syn_reply(false) {}
+ : stream(NULL), waiting_for_reply_headers_frame(false) {}
SpdySession::ActiveStreamInfo::ActiveStreamInfo(SpdyStream* stream)
: stream(stream),
- waiting_for_syn_reply(stream->type() != SPDY_PUSH_STREAM) {
-}
+ waiting_for_reply_headers_frame(stream->type() != SPDY_PUSH_STREAM) {}
SpdySession::ActiveStreamInfo::~ActiveStreamInfo() {}
@@ -672,6 +615,8 @@ bool SpdySession::CanPool(TransportSecurityState* transport_security_state,
if (ssl_info.ct_cert_policy_compliance !=
ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS &&
+ ssl_info.ct_cert_policy_compliance !=
+ ct::CertPolicyCompliance::CERT_POLICY_BUILD_NOT_TIMELY &&
transport_security_state->ShouldRequireCT(
new_hostname, ssl_info.cert.get(), ssl_info.public_key_hashes)) {
return false;
@@ -683,11 +628,8 @@ bool SpdySession::CanPool(TransportSecurityState* transport_security_state,
SpdySession::SpdySession(const SpdySessionKey& spdy_session_key,
HttpServerProperties* http_server_properties,
TransportSecurityState* transport_security_state,
- bool verify_domain_authentication,
bool enable_sending_initial_data,
bool enable_ping_based_connection_checking,
- bool enable_priority_dependencies,
- NextProto default_protocol,
size_t session_max_recv_window_size,
size_t stream_max_recv_window_size,
TimeFunc time_func,
@@ -707,7 +649,6 @@ SpdySession::SpdySession(const SpdySessionKey& spdy_session_key,
in_flight_write_frame_type_(DATA),
in_flight_write_frame_size_(0),
is_secure_(false),
- certificate_error_code_(OK),
availability_state_(STATE_AVAILABLE),
read_state_(READ_STATE_DO_READ),
write_state_(WRITE_STATE_IDLE),
@@ -727,29 +668,25 @@ SpdySession::SpdySession(const SpdySessionKey& spdy_session_key,
last_activity_time_(time_func()),
last_compressed_frame_len_(0),
check_ping_status_pending_(false),
- send_connection_header_prefix_(false),
session_send_window_size_(0),
session_max_recv_window_size_(session_max_recv_window_size),
session_recv_window_size_(0),
session_unacked_recv_window_bytes_(0),
- stream_initial_send_window_size_(
- GetDefaultInitialWindowSize(default_protocol)),
+ stream_initial_send_window_size_(kDefaultInitialWindowSize),
stream_max_recv_window_size_(stream_max_recv_window_size),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_HTTP2_SESSION)),
- verify_domain_authentication_(verify_domain_authentication),
+ net_log_(
+ NetLogWithSource::Make(net_log, NetLogSourceType::HTTP2_SESSION)),
enable_sending_initial_data_(enable_sending_initial_data),
enable_ping_based_connection_checking_(
enable_ping_based_connection_checking),
- protocol_(default_protocol),
connection_at_risk_of_loss_time_(
base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)),
hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)),
proxy_delegate_(proxy_delegate),
time_func_(time_func),
- priority_dependencies_enabled_(enable_priority_dependencies),
weak_factory_(this) {
net_log_.BeginEvent(
- NetLog::TYPE_HTTP2_SESSION,
+ NetLogEventType::HTTP2_SESSION,
base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair()));
next_unclaimed_push_stream_sweep_time_ = time_func_() +
base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
@@ -768,57 +705,37 @@ SpdySession::~SpdySession() {
RecordHistograms();
- net_log_.EndEvent(NetLog::TYPE_HTTP2_SESSION);
+ net_log_.EndEvent(NetLogEventType::HTTP2_SESSION);
}
void SpdySession::InitializeWithSocket(
std::unique_ptr<ClientSocketHandle> connection,
SpdySessionPool* pool,
- bool is_secure,
- int certificate_error_code) {
+ bool is_secure) {
CHECK(!in_io_loop_);
DCHECK_EQ(availability_state_, STATE_AVAILABLE);
DCHECK_EQ(read_state_, READ_STATE_DO_READ);
DCHECK_EQ(write_state_, WRITE_STATE_IDLE);
DCHECK(!connection_);
- DCHECK(certificate_error_code == OK ||
- certificate_error_code < ERR_IO_PENDING);
// TODO(akalin): Check connection->is_initialized() instead. This
// requires re-working CreateFakeSpdySession(), though.
DCHECK(connection->socket());
connection_ = std::move(connection);
is_secure_ = is_secure;
- certificate_error_code_ = certificate_error_code;
-
- NextProto protocol_negotiated =
- connection_->socket()->GetNegotiatedProtocol();
- if (protocol_negotiated != kProtoUnknown) {
- protocol_ = protocol_negotiated;
- stream_initial_send_window_size_ = GetDefaultInitialWindowSize(protocol_);
- }
- DCHECK_GE(protocol_, kProtoSPDYMinimumVersion);
- DCHECK_LE(protocol_, kProtoSPDYMaximumVersion);
-
- if (protocol_ == kProtoHTTP2)
- send_connection_header_prefix_ = true;
- session_send_window_size_ = GetDefaultInitialWindowSize(protocol_);
- session_recv_window_size_ = GetDefaultInitialWindowSize(protocol_);
+ session_send_window_size_ = kDefaultInitialWindowSize;
+ session_recv_window_size_ = kDefaultInitialWindowSize;
- buffered_spdy_framer_.reset(
- new BufferedSpdyFramer(NextProtoToSpdyMajorVersion(protocol_)));
+ buffered_spdy_framer_.reset(new BufferedSpdyFramer());
buffered_spdy_framer_->set_visitor(this);
buffered_spdy_framer_->set_debug_visitor(this);
- UMA_HISTOGRAM_ENUMERATION(
- "Net.SpdyVersion3", protocol_ - kProtoSPDYHistogramOffset,
- kProtoSPDYMaximumVersion - kProtoSPDYHistogramOffset + 1);
+ buffered_spdy_framer_->UpdateHeaderDecoderTableSize(kMaxHeaderTableSize);
- net_log_.AddEvent(
- NetLog::TYPE_HTTP2_SESSION_INITIALIZED,
- base::Bind(&NetLogSpdyInitializedCallback,
- connection_->socket()->NetLog().source(), protocol_));
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_INITIALIZED,
+ base::Bind(&NetLogSpdyInitializedCallback,
+ connection_->socket()->NetLog().source()));
DCHECK_EQ(availability_state_, STATE_AVAILABLE);
connection_->AddHigherLayeredPool(this);
@@ -834,26 +751,20 @@ void SpdySession::InitializeWithSocket(
}
bool SpdySession::VerifyDomainAuthentication(const std::string& domain) {
- if (!verify_domain_authentication_)
- return true;
-
if (availability_state_ == STATE_DRAINING)
return false;
SSLInfo ssl_info;
- bool was_npn_negotiated;
- NextProto protocol_negotiated = kProtoUnknown;
- if (!GetSSLInfo(&ssl_info, &was_npn_negotiated, &protocol_negotiated))
+ if (!GetSSLInfo(&ssl_info))
return true; // This is not a secure session, so all domains are okay.
return CanPool(transport_security_state_, ssl_info,
host_port_pair().host(), domain);
}
-int SpdySession::GetPushStream(
- const GURL& url,
- base::WeakPtr<SpdyStream>* stream,
- const BoundNetLog& stream_net_log) {
+int SpdySession::GetPushStream(const GURL& url,
+ base::WeakPtr<SpdyStream>* stream,
+ const NetLogWithSource& stream_net_log) {
CHECK(!in_io_loop_);
stream->reset();
@@ -861,10 +772,6 @@ int SpdySession::GetPushStream(
if (availability_state_ == STATE_DRAINING)
return ERR_CONNECTION_CLOSED;
- Error err = TryAccessStream(url);
- if (err != OK)
- return err;
-
*stream = GetActivePushStream(url);
if (*stream) {
DCHECK_LT(streams_pushed_and_claimed_count_, streams_pushed_count_);
@@ -873,23 +780,8 @@ int SpdySession::GetPushStream(
return OK;
}
-// {,Try}CreateStream() and TryAccessStream() can be called with
-// |in_io_loop_| set if a stream is being created in response to
-// another being closed due to received data.
-
-Error SpdySession::TryAccessStream(const GURL& url) {
- if (is_secure_ && certificate_error_code_ != OK &&
- (url.SchemeIs("https") || url.SchemeIs("wss"))) {
- RecordProtocolErrorHistogram(
- PROTOCOL_ERROR_REQUEST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION);
- DoDrainSession(
- static_cast<Error>(certificate_error_code_),
- "Tried to get SPDY stream for secure content over an unauthenticated "
- "session.");
- return ERR_SPDY_PROTOCOL_ERROR;
- }
- return OK;
-}
+// {,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.
int SpdySession::TryCreateStream(
const base::WeakPtr<SpdyStreamRequest>& request,
@@ -902,17 +794,13 @@ int SpdySession::TryCreateStream(
if (availability_state_ == STATE_DRAINING)
return ERR_CONNECTION_CLOSED;
- Error err = TryAccessStream(request->url());
- if (err != OK)
- return err;
-
if ((active_streams_.size() + created_streams_.size() - num_pushed_streams_ <
max_concurrent_streams_)) {
return CreateStream(*request, stream);
}
stalled_streams_++;
- net_log().AddEvent(NetLog::TYPE_HTTP2_SESSION_STALLED_MAX_STREAMS);
+ net_log().AddEvent(NetLogEventType::HTTP2_SESSION_STALLED_MAX_STREAMS);
RequestPriority priority = request->priority();
CHECK_GE(priority, MINIMUM_PRIORITY);
CHECK_LE(priority, MAXIMUM_PRIORITY);
@@ -931,13 +819,6 @@ int SpdySession::CreateStream(const SpdyStreamRequest& request,
if (availability_state_ == STATE_DRAINING)
return ERR_CONNECTION_CLOSED;
- Error err = TryAccessStream(request.url());
- if (err != OK) {
- // This should have been caught in TryCreateStream().
- NOTREACHED();
- return err;
- }
-
DCHECK(connection_->socket());
UMA_HISTOGRAM_BOOLEAN("Net.SpdySession.CreateStreamWithSocketConnected",
connection_->socket()->IsConnected());
@@ -1031,24 +912,14 @@ void SpdySession::AddPooledAlias(const SpdySessionKey& alias_key) {
pooled_aliases_.insert(alias_key);
}
-SpdyMajorVersion SpdySession::GetProtocolVersion() const {
- DCHECK(buffered_spdy_framer_.get());
- return buffered_spdy_framer_->protocol_version();
-}
-
bool SpdySession::HasAcceptableTransportSecurity() const {
// If we're not even using TLS, we have no standards to meet.
if (!is_secure_) {
return true;
}
- // We don't enforce transport security standards for older SPDY versions.
- if (GetProtocolVersion() < HTTP2) {
- return true;
- }
-
SSLInfo ssl_info;
- CHECK(connection_->socket()->GetSSLInfo(&ssl_info));
+ CHECK(GetSSLInfo(&ssl_info));
// HTTP/2 requires TLS 1.2+
if (SSLConnectionStatusToVersion(ssl_info.connection_status) <
@@ -1082,13 +953,11 @@ void SpdySession::EnqueueStreamWrite(
const base::WeakPtr<SpdyStream>& stream,
SpdyFrameType frame_type,
std::unique_ptr<SpdyBufferProducer> producer) {
- DCHECK(frame_type == HEADERS ||
- frame_type == DATA ||
- frame_type == SYN_STREAM);
+ DCHECK(frame_type == HEADERS || frame_type == DATA);
EnqueueWrite(stream->priority(), frame_type, std::move(producer), stream);
}
-std::unique_ptr<SpdySerializedFrame> SpdySession::CreateSynStream(
+std::unique_ptr<SpdySerializedFrame> SpdySession::CreateHeaders(
SpdyStreamId stream_id,
RequestPriority priority,
SpdyControlFlags flags,
@@ -1100,56 +969,34 @@ std::unique_ptr<SpdySerializedFrame> SpdySession::CreateSynStream(
SendPrefacePingIfNoneInFlight();
DCHECK(buffered_spdy_framer_.get());
- SpdyPriority spdy_priority =
- ConvertRequestPriorityToSpdyPriority(priority, GetProtocolVersion());
+ SpdyPriority spdy_priority = ConvertRequestPriorityToSpdyPriority(priority);
std::unique_ptr<SpdySerializedFrame> syn_frame;
- if (GetProtocolVersion() <= SPDY3) {
- if (net_log().IsCapturing()) {
- net_log().AddEvent(NetLog::TYPE_HTTP2_SESSION_SYN_STREAM,
- base::Bind(&NetLogSpdySynStreamSentCallback, &block,
- (flags & CONTROL_FLAG_FIN) != 0,
- (flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0,
- spdy_priority, stream_id));
- }
+ bool has_priority = true;
+ int weight = Spdy3PriorityToHttp2Weight(spdy_priority);
+ SpdyStreamId dependent_stream_id = 0;
+ bool exclusive = false;
- SpdySynStreamIR syn_stream(stream_id, std::move(block));
- syn_stream.set_associated_to_stream_id(0);
- syn_stream.set_priority(spdy_priority);
- syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0);
- syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0);
- syn_frame.reset(new SpdySerializedFrame(
- buffered_spdy_framer_->SerializeFrame(syn_stream)));
+ priority_dependency_state_.OnStreamSynSent(stream_id, spdy_priority,
+ &dependent_stream_id, &exclusive);
- } else {
- bool has_priority = true;
- int weight = Spdy3PriorityToHttp2Weight(spdy_priority);
- SpdyStreamId dependent_stream_id = 0;
- bool exclusive = false;
-
- if (priority_dependencies_enabled_) {
- priority_dependency_state_.OnStreamSynSent(
- stream_id, spdy_priority, &dependent_stream_id, &exclusive);
- }
-
- if (net_log().IsCapturing()) {
- net_log().AddEvent(
- NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS,
- base::Bind(&NetLogSpdyHeadersSentCallback, &block,
- (flags & CONTROL_FLAG_FIN) != 0, stream_id, has_priority,
- weight, dependent_stream_id, exclusive));
- }
-
- SpdyHeadersIR headers(stream_id, std::move(block));
- headers.set_has_priority(has_priority);
- headers.set_weight(weight);
- headers.set_parent_stream_id(dependent_stream_id);
- headers.set_exclusive(exclusive);
- headers.set_fin((flags & CONTROL_FLAG_FIN) != 0);
- syn_frame.reset(new SpdySerializedFrame(
- buffered_spdy_framer_->SerializeFrame(headers)));
+ if (net_log().IsCapturing()) {
+ net_log().AddEvent(
+ NetLogEventType::HTTP2_SESSION_SEND_HEADERS,
+ base::Bind(&NetLogSpdyHeadersSentCallback, &block,
+ (flags & CONTROL_FLAG_FIN) != 0, stream_id, has_priority,
+ weight, dependent_stream_id, exclusive));
}
+ SpdyHeadersIR headers(stream_id, std::move(block));
+ headers.set_has_priority(has_priority);
+ headers.set_weight(weight);
+ headers.set_parent_stream_id(dependent_stream_id);
+ headers.set_exclusive(exclusive);
+ headers.set_fin((flags & CONTROL_FLAG_FIN) != 0);
+ syn_frame.reset(
+ new SpdySerializedFrame(buffered_spdy_framer_->SerializeFrame(headers)));
+
streams_initiated_count_++;
return syn_frame;
@@ -1209,7 +1056,7 @@ std::unique_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(
// might end up being stalled by the session also.
QueueSendStalledStream(*stream);
net_log().AddEvent(
- NetLog::TYPE_HTTP2_SESSION_STREAM_STALLED_BY_STREAM_SEND_WINDOW,
+ NetLogEventType::HTTP2_SESSION_STREAM_STALLED_BY_STREAM_SEND_WINDOW,
NetLog::IntCallback("stream_id", stream_id));
return std::unique_ptr<SpdyBuffer>();
}
@@ -1221,7 +1068,7 @@ std::unique_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(
stream->set_send_stalled_by_flow_control(true);
QueueSendStalledStream(*stream);
net_log().AddEvent(
- NetLog::TYPE_HTTP2_SESSION_STREAM_STALLED_BY_SESSION_SEND_WINDOW,
+ NetLogEventType::HTTP2_SESSION_STREAM_STALLED_BY_SESSION_SEND_WINDOW,
NetLog::IntCallback("stream_id", stream_id));
return std::unique_ptr<SpdyBuffer>();
}
@@ -1236,7 +1083,7 @@ std::unique_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(
flags = static_cast<SpdyDataFlags>(flags & ~DATA_FLAG_FIN);
if (net_log().IsCapturing()) {
- net_log().AddEvent(NetLog::TYPE_HTTP2_SESSION_SEND_DATA,
+ net_log().AddEvent(NetLogEventType::HTTP2_SESSION_SEND_DATA,
base::Bind(&NetLogSpdyDataCallback, stream_id,
effective_len, (flags & DATA_FLAG_FIN) != 0));
}
@@ -1307,7 +1154,7 @@ void SpdySession::ResetStream(SpdyStreamId stream_id,
}
bool SpdySession::IsStreamActive(SpdyStreamId stream_id) const {
- return ContainsKey(active_streams_, stream_id);
+ return base::ContainsKey(active_streams_, stream_id);
}
LoadState SpdySession::GetLoadState() const {
@@ -1323,8 +1170,7 @@ void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it,
std::unique_ptr<SpdyStream> owned_stream(it->second.stream);
active_streams_.erase(it);
- if (priority_dependencies_enabled_)
- priority_dependency_state_.OnStreamDestruction(owned_stream->stream_id());
+ priority_dependency_state_.OnStreamDestruction(owned_stream->stream_id());
// TODO(akalin): When SpdyStream was ref-counted (and
// |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this
@@ -1378,7 +1224,7 @@ void SpdySession::EnqueueResetStreamFrame(SpdyStreamId stream_id,
DCHECK_NE(stream_id, 0u);
net_log().AddEvent(
- NetLog::TYPE_HTTP2_SESSION_SEND_RST_STREAM,
+ NetLogEventType::HTTP2_SESSION_SEND_RST_STREAM,
base::Bind(&NetLogSpdyRstCallback, stream_id, status, &description));
DCHECK(buffered_spdy_framer_.get());
@@ -1390,11 +1236,6 @@ void SpdySession::EnqueueResetStreamFrame(SpdyStreamId stream_id,
}
void SpdySession::PumpReadLoop(ReadState expected_read_state, int result) {
- TRACE_EVENT0("net", "SpdySession::PumpReadLoop");
- // TODO(bnc): Remove ScopedTracker below once crbug.com/462774 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION("462774 SpdySession::PumpReadLoop"));
-
CHECK(!in_io_loop_);
if (availability_state_ == STATE_DRAINING) {
return;
@@ -1583,9 +1424,9 @@ int SpdySession::DoWrite() {
if (stream.get())
CHECK(!stream->IsClosed());
- // Activate the stream only when sending the SYN_STREAM frame to
+ // Activate the stream only when sending the HEADERS frame to
// guarantee monotonically-increasing stream IDs.
- if (frame_type == SYN_STREAM) {
+ if (frame_type == HEADERS) {
CHECK(stream.get());
CHECK_EQ(stream->stream_id(), 0u);
std::unique_ptr<SpdyStream> owned_stream =
@@ -1791,7 +1632,7 @@ void SpdySession::DoDrainSession(Error err, const std::string& description) {
error_on_close_ = err;
net_log_.AddEvent(
- NetLog::TYPE_HTTP2_SESSION_CLOSE,
+ NetLogEventType::HTTP2_SESSION_CLOSE,
base::Bind(&NetLogSpdySessionCloseCallback, err, &description));
UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SpdySession.ClosedOnError", -err);
@@ -1825,10 +1666,6 @@ void SpdySession::LogAbandonedActiveStream(ActiveStreamMap::const_iterator it,
DCHECK_GT(it->first, 0u);
LogAbandonedStream(it->second.stream, status);
++streams_abandoned_count_;
- if (it->second.stream->type() == SPDY_PUSH_STREAM &&
- unclaimed_pushed_streams_.find(it->second.stream->url()) !=
- unclaimed_pushed_streams_.end()) {
- }
}
SpdyStreamId SpdySession::GetNewStreamId() {
@@ -1873,7 +1710,7 @@ std::unique_ptr<base::Value> SpdySession::GetInfoAsValue() const {
dict->SetBoolean("is_secure", is_secure_);
- dict->SetString("protocol_negotiated",
+ dict->SetString("negotiated_protocol",
SSLClientSocket::NextProtoToString(
connection_->socket()->GetNegotiatedProtocol()));
@@ -2021,6 +1858,14 @@ void SpdySession::DeleteStream(std::unique_ptr<SpdyStream> stream, int status) {
}
}
+SpdyStreamId SpdySession::GetStreamIdForPush(const GURL& url) {
+ UnclaimedPushedStreamContainer::const_iterator unclaimed_it =
+ unclaimed_pushed_streams_.find(url);
+ if (unclaimed_it == unclaimed_pushed_streams_.end())
+ return 0;
+ return unclaimed_it->second.stream_id;
+}
+
base::WeakPtr<SpdyStream> SpdySession::GetActivePushStream(const GURL& url) {
UnclaimedPushedStreamContainer::const_iterator unclaimed_it =
unclaimed_pushed_streams_.find(url);
@@ -2036,7 +1881,7 @@ base::WeakPtr<SpdyStream> SpdySession::GetActivePushStream(const GURL& url) {
return base::WeakPtr<SpdyStream>();
}
- net_log_.AddEvent(NetLog::TYPE_HTTP2_STREAM_ADOPTED_PUSH_STREAM,
+ net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_ADOPTED_PUSH_STREAM,
base::Bind(&NetLogSpdyAdoptedPushStreamCallback,
active_it->second.stream->stream_id(), &url));
return active_it->second.stream->GetWeakPtr();
@@ -2047,23 +1892,28 @@ url::SchemeHostPort SpdySession::GetServer() {
host_port_pair().host(), host_port_pair().port());
}
-bool SpdySession::GetSSLInfo(SSLInfo* ssl_info,
- bool* was_npn_negotiated,
- NextProto* protocol_negotiated) {
- *was_npn_negotiated = connection_->socket()->WasNpnNegotiated();
- *protocol_negotiated = connection_->socket()->GetNegotiatedProtocol();
+bool SpdySession::GetSSLInfo(SSLInfo* ssl_info) const {
return connection_->socket()->GetSSLInfo(ssl_info);
}
-Error SpdySession::GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) {
+bool SpdySession::WasNpnNegotiated() const {
+ return connection_->socket()->WasNpnNegotiated();
+}
+
+NextProto SpdySession::GetNegotiatedProtocol() const {
+ return connection_->socket()->GetNegotiatedProtocol();
+}
+
+Error SpdySession::GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) {
if (!is_secure_) {
NOTREACHED();
return ERR_FAILED;
}
SSLClientSocket* ssl_socket =
static_cast<SSLClientSocket*>(connection_->socket());
- return ssl_socket->GetSignedEKMForTokenBinding(key, out);
+ return ssl_socket->GetTokenBindingSignature(key, tb_type, out);
}
void SpdySession::OnError(SpdyFramer::SpdyError error_code) {
@@ -2119,7 +1969,7 @@ void SpdySession::OnStreamFrameData(SpdyStreamId stream_id,
DCHECK_LT(len, 1u << 24);
if (net_log().IsCapturing()) {
net_log().AddEvent(
- NetLog::TYPE_HTTP2_SESSION_RECV_DATA,
+ NetLogEventType::HTTP2_SESSION_RECV_DATA,
base::Bind(&NetLogSpdyDataCallback, stream_id, len, false));
}
@@ -2152,8 +2002,8 @@ void SpdySession::OnStreamFrameData(SpdyStreamId stream_id,
stream->AddRawReceivedBytes(len);
- if (it->second.waiting_for_syn_reply) {
- const std::string& error = "Data received before SYN_REPLY.";
+ if (it->second.waiting_for_reply_headers_frame) {
+ const std::string& error = "DATA received before HEADERS.";
stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, error);
return;
@@ -2165,7 +2015,7 @@ void SpdySession::OnStreamFrameData(SpdyStreamId stream_id,
void SpdySession::OnStreamEnd(SpdyStreamId stream_id) {
CHECK(in_io_loop_);
if (net_log().IsCapturing()) {
- net_log().AddEvent(NetLog::TYPE_HTTP2_SESSION_RECV_DATA,
+ net_log().AddEvent(NetLogEventType::HTTP2_SESSION_RECV_DATA,
base::Bind(&NetLogSpdyDataCallback, stream_id, 0, true));
}
@@ -2185,8 +2035,8 @@ void SpdySession::OnStreamEnd(SpdyStreamId stream_id) {
SpdyStream* stream = it->second.stream;
CHECK_EQ(stream->stream_id(), stream_id);
- if (it->second.waiting_for_syn_reply) {
- const std::string& error = "Data received before SYN_REPLY.";
+ if (it->second.waiting_for_reply_headers_frame) {
+ const std::string& error = "DATA received before HEADERS.";
stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, error);
return;
@@ -2218,20 +2068,18 @@ void SpdySession::OnSettings(bool clear_persisted) {
http_server_properties_->ClearSpdySettings(GetServer());
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(NetLog::TYPE_HTTP2_SESSION_RECV_SETTINGS,
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTINGS,
base::Bind(&NetLogSpdySettingsCallback, host_port_pair(),
clear_persisted));
}
- if (GetProtocolVersion() >= HTTP2) {
- // Send an acknowledgment of the setting.
- SpdySettingsIR settings_ir;
- settings_ir.set_is_ack(true);
- EnqueueSessionWrite(
- HIGHEST, SETTINGS,
- std::unique_ptr<SpdySerializedFrame>(new SpdySerializedFrame(
- buffered_spdy_framer_->SerializeFrame(settings_ir))));
- }
+ // Send an acknowledgment of the setting.
+ SpdySettingsIR settings_ir;
+ settings_ir.set_is_ack(true);
+ EnqueueSessionWrite(
+ HIGHEST, SETTINGS,
+ std::unique_ptr<SpdySerializedFrame>(new SpdySerializedFrame(
+ buffered_spdy_framer_->SerializeFrame(settings_ir))));
}
void SpdySession::OnSetting(SpdySettingsIds id, uint8_t flags, uint32_t value) {
@@ -2243,9 +2091,8 @@ void SpdySession::OnSetting(SpdySettingsIds id, uint8_t flags, uint32_t value) {
received_settings_ = true;
// Log the setting.
- const SpdyMajorVersion protocol_version = GetProtocolVersion();
- net_log_.AddEvent(NetLog::TYPE_HTTP2_SESSION_RECV_SETTING,
- base::Bind(&NetLogSpdySettingCallback, id, protocol_version,
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTING,
+ base::Bind(&NetLogSpdySettingCallback, id,
static_cast<SpdySettingsFlags>(flags), value));
}
@@ -2254,7 +2101,7 @@ void SpdySession::OnSendCompressedFrame(
SpdyFrameType type,
size_t payload_len,
size_t frame_len) {
- if (type != SYN_STREAM && type != HEADERS)
+ if (type != HEADERS)
return;
DCHECK(buffered_spdy_framer_.get());
@@ -2311,47 +2158,6 @@ int SpdySession::OnInitialResponseHeadersReceived(
return rv;
}
-void SpdySession::OnSynStream(SpdyStreamId stream_id,
- SpdyStreamId associated_stream_id,
- SpdyPriority priority,
- bool fin,
- bool unidirectional,
- const SpdyHeaderBlock& headers) {
- CHECK(in_io_loop_);
-
- DCHECK_LE(GetProtocolVersion(), SPDY3);
-
- base::Time response_time = base::Time::Now();
- base::TimeTicks recv_first_byte_time = time_func_();
-
- if (net_log_.IsCapturing()) {
- net_log_.AddEvent(
- NetLog::TYPE_HTTP2_SESSION_PUSHED_SYN_STREAM,
- base::Bind(&NetLogSpdySynStreamReceivedCallback, &headers, fin,
- unidirectional, priority, stream_id, associated_stream_id));
- }
-
- // Split headers to simulate push promise and response.
- SpdyHeaderBlock request_headers;
- SpdyHeaderBlock response_headers;
- SplitPushedHeadersToRequestAndResponse(
- headers, GetProtocolVersion(), &request_headers, &response_headers);
-
- if (!TryCreatePushStream(
- stream_id, associated_stream_id, priority, request_headers))
- return;
-
- ActiveStreamMap::iterator active_it = active_streams_.find(stream_id);
- if (active_it == active_streams_.end()) {
- NOTREACHED();
- return;
- }
-
- OnInitialResponseHeadersReceived(response_headers, response_time,
- recv_first_byte_time,
- active_it->second.stream);
-}
-
void SpdySession::DeleteExpiredPushedStreams() {
if (unclaimed_pushed_streams_.empty())
return;
@@ -2389,64 +2195,19 @@ void SpdySession::DeleteExpiredPushedStreams() {
base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
}
-void SpdySession::OnSynReply(SpdyStreamId stream_id,
- bool fin,
- const SpdyHeaderBlock& headers) {
- CHECK(in_io_loop_);
-
- base::Time response_time = base::Time::Now();
- base::TimeTicks recv_first_byte_time = time_func_();
-
- if (net_log().IsCapturing()) {
- net_log().AddEvent(NetLog::TYPE_HTTP2_SESSION_SYN_REPLY,
- base::Bind(&NetLogSpdySynReplyOrHeadersReceivedCallback,
- &headers, fin, stream_id));
- }
-
- ActiveStreamMap::iterator it = active_streams_.find(stream_id);
- if (it == active_streams_.end()) {
- // NOTE: it may just be that the stream was cancelled.
- return;
- }
-
- SpdyStream* stream = it->second.stream;
- CHECK_EQ(stream->stream_id(), stream_id);
-
- stream->AddRawReceivedBytes(last_compressed_frame_len_);
- last_compressed_frame_len_ = 0;
-
- if (GetProtocolVersion() >= HTTP2) {
- const std::string& error = "HTTP/2 wasn't expecting SYN_REPLY.";
- stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
- ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, error);
- return;
- }
- if (!it->second.waiting_for_syn_reply) {
- const std::string& error =
- "Received duplicate SYN_REPLY for stream.";
- stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
- ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, error);
- return;
- }
- it->second.waiting_for_syn_reply = false;
-
- ignore_result(OnInitialResponseHeadersReceived(
- headers, response_time, recv_first_byte_time, stream));
-}
-
void SpdySession::OnHeaders(SpdyStreamId stream_id,
bool has_priority,
int weight,
SpdyStreamId parent_stream_id,
bool exclusive,
bool fin,
- const SpdyHeaderBlock& headers) {
+ SpdyHeaderBlock headers) {
CHECK(in_io_loop_);
if (net_log().IsCapturing()) {
- net_log().AddEvent(NetLog::TYPE_HTTP2_SESSION_RECV_HEADERS,
- base::Bind(&NetLogSpdySynReplyOrHeadersReceivedCallback,
- &headers, fin, stream_id));
+ net_log().AddEvent(NetLogEventType::HTTP2_SESSION_RECV_HEADERS,
+ base::Bind(&NetLogSpdyHeadersReceivedCallback, &headers,
+ fin, stream_id));
}
ActiveStreamMap::iterator it = active_streams_.find(stream_id);
@@ -2465,16 +2226,8 @@ void SpdySession::OnHeaders(SpdyStreamId stream_id,
base::Time response_time = base::Time::Now();
base::TimeTicks recv_first_byte_time = time_func_();
- if (it->second.waiting_for_syn_reply) {
- if (GetProtocolVersion() < HTTP2) {
- const std::string& error =
- "Was expecting SYN_REPLY, not HEADERS.";
- stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error);
- ResetStreamIterator(it, RST_STREAM_PROTOCOL_ERROR, error);
- return;
- }
-
- it->second.waiting_for_syn_reply = false;
+ if (it->second.waiting_for_reply_headers_frame) {
+ it->second.waiting_for_reply_headers_frame = false;
ignore_result(OnInitialResponseHeadersReceived(
headers, response_time, recv_first_byte_time, stream));
} else if (it->second.stream->IsReservedRemote()) {
@@ -2504,9 +2257,7 @@ void SpdySession::OnAltSvc(
if (!gurl.SchemeIs("https"))
return;
SSLInfo ssl_info;
- bool was_npn_negotiated;
- NextProto protocol_negotiated = kProtoUnknown;
- if (!GetSSLInfo(&ssl_info, &was_npn_negotiated, &protocol_negotiated))
+ if (!GetSSLInfo(&ssl_info))
return;
if (!CanPool(transport_security_state_, ssl_info, host_port_pair().host(),
gurl.host())) {
@@ -2562,7 +2313,7 @@ void SpdySession::OnRstStream(SpdyStreamId stream_id,
std::string description;
net_log().AddEvent(
- NetLog::TYPE_HTTP2_SESSION_RST_STREAM,
+ NetLogEventType::HTTP2_SESSION_RST_STREAM,
base::Bind(&NetLogSpdyRstCallback, stream_id, status, &description));
ActiveStreamMap::iterator it = active_streams_.find(stream_id);
@@ -2605,7 +2356,7 @@ void SpdySession::OnGoAway(SpdyStreamId last_accepted_stream_id,
// TODO(jgraettinger): UMA histogram on |status|.
net_log_.AddEvent(
- NetLog::TYPE_HTTP2_SESSION_GOAWAY,
+ NetLogEventType::HTTP2_SESSION_GOAWAY,
base::Bind(&NetLogSpdyGoAwayCallback, last_accepted_stream_id,
active_streams_.size(), unclaimed_pushed_streams_.size(),
status, debug_data));
@@ -2627,12 +2378,11 @@ void SpdySession::OnPing(SpdyPingId unique_id, bool is_ack) {
CHECK(in_io_loop_);
net_log_.AddEvent(
- NetLog::TYPE_HTTP2_SESSION_PING,
+ NetLogEventType::HTTP2_SESSION_PING,
base::Bind(&NetLogSpdyPingCallback, unique_id, is_ack, "received"));
// Send response to a PING from server.
- if ((protocol_ == kProtoHTTP2 && !is_ack) ||
- (protocol_ < kProtoHTTP2 && unique_id % 2 == 0)) {
+ if (!is_ack) {
WritePingFrame(unique_id, true);
return;
}
@@ -2657,7 +2407,7 @@ void SpdySession::OnWindowUpdate(SpdyStreamId stream_id,
int delta_window_size) {
CHECK(in_io_loop_);
- net_log_.AddEvent(NetLog::TYPE_HTTP2_SESSION_RECEIVED_WINDOW_UPDATE_FRAME,
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECEIVED_WINDOW_UPDATE_FRAME,
base::Bind(&NetLogSpdyWindowUpdateFrameCallback, stream_id,
delta_window_size));
@@ -2703,7 +2453,7 @@ void SpdySession::OnWindowUpdate(SpdyStreamId stream_id,
bool SpdySession::TryCreatePushStream(SpdyStreamId stream_id,
SpdyStreamId associated_stream_id,
SpdyPriority priority,
- const SpdyHeaderBlock& headers) {
+ SpdyHeaderBlock headers) {
// Server-initiated streams should have even sequence numbers.
if ((stream_id & 0x1) != 0) {
LOG(WARNING) << "Received invalid push stream id " << stream_id;
@@ -2728,9 +2478,8 @@ bool SpdySession::TryCreatePushStream(SpdyStreamId stream_id,
}
if (IsStreamActive(stream_id)) {
- // For SPDY3 and higher we should not get here, we'll start going away
- // earlier on |last_seen_push_stream_id_| check.
- CHECK_GT(SPDY3, GetProtocolVersion());
+ // We should not get here, we'll start going away earlier on
+ // |last_seen_push_stream_id_| check.
LOG(WARNING) << "Received push for active stream " << stream_id;
return false;
}
@@ -2738,7 +2487,7 @@ bool SpdySession::TryCreatePushStream(SpdyStreamId stream_id,
last_accepted_push_stream_id_ = stream_id;
RequestPriority request_priority =
- ConvertSpdyPriorityToRequestPriority(priority, GetProtocolVersion());
+ ConvertSpdyPriorityToRequestPriority(priority);
if (availability_state_ == STATE_GOING_AWAY) {
// TODO(akalin): This behavior isn't in the SPDY spec, although it
@@ -2753,7 +2502,6 @@ bool SpdySession::TryCreatePushStream(SpdyStreamId stream_id,
if (associated_stream_id == 0) {
// In HTTP/2 0 stream id in PUSH_PROMISE frame leads to framer error and
// session going away. We should never get here.
- CHECK_GT(HTTP2, GetProtocolVersion());
std::string description = base::StringPrintf(
"Received invalid associated stream id %d for pushed stream %d",
associated_stream_id,
@@ -2768,7 +2516,7 @@ bool SpdySession::TryCreatePushStream(SpdyStreamId stream_id,
// TODO(mbelshe): DCHECK that this is a GET method?
// Verify that the response had a URL for us.
- GURL gurl = GetUrlFromHeaderBlock(headers, GetProtocolVersion());
+ GURL gurl = GetUrlFromHeaderBlock(headers);
if (!gurl.is_valid()) {
EnqueueResetStreamFrame(stream_id,
request_priority,
@@ -2813,7 +2561,7 @@ bool SpdySession::TryCreatePushStream(SpdyStreamId stream_id,
GURL associated_url(associated_it->second.stream->GetUrlFromHeaders());
if (associated_url.SchemeIs("https")) {
SSLInfo ssl_info;
- CHECK(connection_->socket()->GetSSLInfo(&ssl_info));
+ CHECK(GetSSLInfo(&ssl_info));
if (!gurl.SchemeIs("https") ||
!CanPool(transport_security_state_, ssl_info, associated_url.host(),
gurl.host())) {
@@ -2857,7 +2605,7 @@ bool SpdySession::TryCreatePushStream(SpdyStreamId stream_id,
stream->set_stream_id(stream_id);
// In spdy4/http2 PUSH_PROMISE arrives on associated stream.
- if (associated_it != active_streams_.end() && GetProtocolVersion() >= HTTP2) {
+ if (associated_it != active_streams_.end()) {
associated_it->second.stream->AddRawReceivedBytes(
last_compressed_frame_len_);
} else {
@@ -2880,7 +2628,7 @@ bool SpdySession::TryCreatePushStream(SpdyStreamId stream_id,
return false;
}
- active_it->second.stream->OnPushPromiseHeadersReceived(headers);
+ active_it->second.stream->OnPushPromiseHeadersReceived(std::move(headers));
DCHECK(active_it->second.stream->IsReservedRemote());
num_pushed_streams_++;
return true;
@@ -2888,18 +2636,19 @@ bool SpdySession::TryCreatePushStream(SpdyStreamId stream_id,
void SpdySession::OnPushPromise(SpdyStreamId stream_id,
SpdyStreamId promised_stream_id,
- const SpdyHeaderBlock& headers) {
+ SpdyHeaderBlock headers) {
CHECK(in_io_loop_);
if (net_log_.IsCapturing()) {
- net_log_.AddEvent(NetLog::TYPE_HTTP2_SESSION_RECV_PUSH_PROMISE,
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_PUSH_PROMISE,
base::Bind(&NetLogSpdyPushPromiseReceivedCallback,
&headers, stream_id, promised_stream_id));
}
// Any priority will do.
// TODO(baranovich): pass parent stream id priority?
- if (!TryCreatePushStream(promised_stream_id, stream_id, 0, headers))
+ if (!TryCreatePushStream(promised_stream_id, stream_id, 0,
+ std::move(headers)))
return;
}
@@ -2915,25 +2664,22 @@ void SpdySession::SendStreamWindowUpdate(SpdyStreamId stream_id,
void SpdySession::SendInitialData() {
DCHECK(enable_sending_initial_data_);
- if (send_connection_header_prefix_) {
- DCHECK_EQ(protocol_, kProtoHTTP2);
- std::unique_ptr<SpdySerializedFrame> connection_header_prefix_frame(
- new SpdySerializedFrame(const_cast<char*>(kHttp2ConnectionHeaderPrefix),
- kHttp2ConnectionHeaderPrefixSize,
- false /* take_ownership */));
- // Count the prefix as part of the subsequent SETTINGS frame.
- EnqueueSessionWrite(HIGHEST, SETTINGS,
- std::move(connection_header_prefix_frame));
- }
+ std::unique_ptr<SpdySerializedFrame> connection_header_prefix_frame(
+ new SpdySerializedFrame(const_cast<char*>(kHttp2ConnectionHeaderPrefix),
+ kHttp2ConnectionHeaderPrefixSize,
+ false /* take_ownership */));
+ // Count the prefix as part of the subsequent SETTINGS frame.
+ EnqueueSessionWrite(HIGHEST, SETTINGS,
+ std::move(connection_header_prefix_frame));
// First, notify the server about the settings they should use when
// communicating with us.
SettingsMap settings_map;
- // Create a new settings frame notifying the server of our
- // max concurrent streams and initial window size.
+ settings_map[SETTINGS_HEADER_TABLE_SIZE] =
+ SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxHeaderTableSize);
settings_map[SETTINGS_MAX_CONCURRENT_STREAMS] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams);
- if (stream_max_recv_window_size_ != GetDefaultInitialWindowSize(protocol_)) {
+ if (stream_max_recv_window_size_ != kDefaultInitialWindowSize) {
settings_map[SETTINGS_INITIAL_WINDOW_SIZE] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, stream_max_recv_window_size_);
}
@@ -2951,38 +2697,11 @@ void SpdySession::SendInitialData() {
IncreaseRecvWindowSize(session_max_recv_window_size_ -
session_recv_window_size_);
}
-
- if (protocol_ == kProtoSPDY31) {
- // Finally, notify the server about the settings they have
- // previously told us to use when communicating with them (after
- // applying them).
- const SettingsMap& server_settings_map =
- http_server_properties_->GetSpdySettings(GetServer());
- if (server_settings_map.empty())
- return;
-
- SettingsMap::const_iterator it =
- server_settings_map.find(SETTINGS_CURRENT_CWND);
- uint32_t cwnd = (it != server_settings_map.end()) ? it->second.second : 0;
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwndSent", cwnd, 1, 200, 100);
-
- for (SettingsMap::const_iterator it = server_settings_map.begin();
- it != server_settings_map.end(); ++it) {
- const SpdySettingsIds new_id = it->first;
- const uint32_t new_val = it->second.second;
- HandleSetting(new_id, new_val);
- }
-
- SendSettings(server_settings_map);
- }
}
-
void SpdySession::SendSettings(const SettingsMap& settings) {
- const SpdyMajorVersion protocol_version = GetProtocolVersion();
- net_log_.AddEvent(
- NetLog::TYPE_HTTP2_SESSION_SEND_SETTINGS,
- base::Bind(&NetLogSpdySendSettingsCallback, &settings, protocol_version));
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_SETTINGS,
+ base::Bind(&NetLogSpdySendSettingsCallback, &settings));
// Create the SETTINGS frame and send it.
DCHECK(buffered_spdy_framer_.get());
std::unique_ptr<SpdySerializedFrame> settings_frame(
@@ -3001,7 +2720,7 @@ void SpdySession::HandleSetting(uint32_t id, uint32_t value) {
case SETTINGS_INITIAL_WINDOW_SIZE: {
if (value > static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
net_log().AddEvent(
- NetLog::TYPE_HTTP2_SESSION_INITIAL_WINDOW_SIZE_OUT_OF_RANGE,
+ NetLogEventType::HTTP2_SESSION_INITIAL_WINDOW_SIZE_OUT_OF_RANGE,
NetLog::IntCallback("initial_window_size", value));
return;
}
@@ -3012,7 +2731,7 @@ void SpdySession::HandleSetting(uint32_t id, uint32_t value) {
stream_initial_send_window_size_ = static_cast<int32_t>(value);
UpdateStreamsSendWindowSize(delta_window_size);
net_log().AddEvent(
- NetLog::TYPE_HTTP2_SESSION_UPDATE_STREAMS_SEND_WINDOW_SIZE,
+ NetLogEventType::HTTP2_SESSION_UPDATE_STREAMS_SEND_WINDOW_SIZE,
NetLog::IntCallback("delta_window_size", delta_window_size));
break;
}
@@ -3055,7 +2774,7 @@ void SpdySession::SendWindowUpdateFrame(SpdyStreamId stream_id,
CHECK_EQ(stream_id, kSessionFlowControlStreamId);
}
- net_log_.AddEvent(NetLog::TYPE_HTTP2_SESSION_SENT_WINDOW_UPDATE_FRAME,
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SENT_WINDOW_UPDATE_FRAME,
base::Bind(&NetLogSpdyWindowUpdateFrameCallback, stream_id,
delta_window_size));
@@ -3073,7 +2792,7 @@ void SpdySession::WritePingFrame(SpdyPingId unique_id, bool is_ack) {
if (net_log().IsCapturing()) {
net_log().AddEvent(
- NetLog::TYPE_HTTP2_SESSION_PING,
+ NetLogEventType::HTTP2_SESSION_PING,
base::Bind(&NetLogSpdyPingCallback, unique_id, is_ack, "sent"));
}
if (!is_ack) {
@@ -3140,24 +2859,19 @@ void SpdySession::RecordProtocolErrorHistogram(
void SpdySession::RecordHistograms() {
UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPerSession",
- streams_initiated_count_,
- 0, 300, 50);
+ streams_initiated_count_, 1, 300, 50);
UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedPerSession",
- streams_pushed_count_,
- 0, 300, 50);
+ streams_pushed_count_, 1, 300, 50);
UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedAndClaimedPerSession",
- streams_pushed_and_claimed_count_,
- 0, 300, 50);
+ streams_pushed_and_claimed_count_, 1, 300, 50);
UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsAbandonedPerSession",
- streams_abandoned_count_,
- 0, 300, 50);
+ streams_abandoned_count_, 1, 300, 50);
UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsSent",
sent_settings_ ? 1 : 0, 2);
UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsReceived",
received_settings_ ? 1 : 0, 2);
UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamStallsPerSession",
- stalled_streams_,
- 0, 300, 50);
+ stalled_streams_, 1, 300, 50);
UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionsWithStalls",
stalled_streams_ > 0 ? 1 : 0, 2);
@@ -3269,7 +2983,7 @@ void SpdySession::IncreaseSendWindowSize(int delta_window_size) {
session_send_window_size_ += delta_window_size;
- net_log_.AddEvent(NetLog::TYPE_HTTP2_SESSION_UPDATE_SEND_WINDOW,
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_UPDATE_SEND_WINDOW,
base::Bind(&NetLogSpdySessionWindowUpdateCallback,
delta_window_size, session_send_window_size_));
@@ -3289,7 +3003,7 @@ void SpdySession::DecreaseSendWindowSize(int32_t delta_window_size) {
session_send_window_size_ -= delta_window_size;
- net_log_.AddEvent(NetLog::TYPE_HTTP2_SESSION_UPDATE_SEND_WINDOW,
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_UPDATE_SEND_WINDOW,
base::Bind(&NetLogSpdySessionWindowUpdateCallback,
-delta_window_size, session_send_window_size_));
}
@@ -3315,7 +3029,7 @@ void SpdySession::IncreaseRecvWindowSize(int32_t delta_window_size) {
std::numeric_limits<int32_t>::max() - session_recv_window_size_);
session_recv_window_size_ += delta_window_size;
- net_log_.AddEvent(NetLog::TYPE_HTTP2_STREAM_UPDATE_RECV_WINDOW,
+ net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_UPDATE_RECV_WINDOW,
base::Bind(&NetLogSpdySessionWindowUpdateCallback,
delta_window_size, session_recv_window_size_));
@@ -3348,7 +3062,7 @@ void SpdySession::DecreaseRecvWindowSize(int32_t delta_window_size) {
}
session_recv_window_size_ -= delta_window_size;
- net_log_.AddEvent(NetLog::TYPE_HTTP2_SESSION_UPDATE_RECV_WINDOW,
+ net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_UPDATE_RECV_WINDOW,
base::Bind(&NetLogSpdySessionWindowUpdateCallback,
-delta_window_size, session_recv_window_size_));
}
diff --git a/chromium/net/spdy/spdy_session.h b/chromium/net/spdy/spdy_session.h
index 8f781a557d3..9d17aaec5e2 100644
--- a/chromium/net/spdy/spdy_session.h
+++ b/chromium/net/spdy/spdy_session.h
@@ -59,11 +59,18 @@ const int kMss = 1430;
// The 8 is the size of the SPDY frame header.
const int kMaxSpdyFrameChunkSize = (2 * kMss) - 8;
+// Default value of SETTINGS_INITIAL_WINDOW_SIZE per protocol specification.
+// A session is always created with this initial window size.
+const int32_t kDefaultInitialWindowSize = 65535;
+
// Maximum number of concurrent streams we will create, unless the server
// sends a SETTINGS frame with a different value.
const size_t kInitialMaxConcurrentStreams = 100;
-// Specifies the maxiumum concurrent streams server could send (via push).
+// Specifies the maximum HPACK dynamic table size the server is allowed to set.
+const int kMaxHeaderTableSize = 64 * 1024;
+
+// Specifies the maximum concurrent streams server could send (via push).
const int kMaxConcurrentPushedStreams = 1000;
// If more than this many bytes have been read or more than that many
@@ -76,8 +83,9 @@ const int kYieldAfterDurationMilliseconds = 20;
const SpdyStreamId kFirstStreamId = 1;
const SpdyStreamId kLastStreamId = 0x7fffffff;
-class BoundNetLog;
struct LoadTimingInfo;
+class NetLog;
+class NetLogWithSource;
class ProxyDelegate;
class SpdyStream;
class SSLInfo;
@@ -148,14 +156,6 @@ static_assert(17 == SpdyFramer::LAST_ERROR,
static_assert(17 == RST_STREAM_NUM_STATUS_CODES,
"SpdyProtocolErrorDetails / RstStreamStatus mismatch");
-// Splits pushed |headers| into request and response parts. Request headers are
-// the headers specifying resource URL.
-void NET_EXPORT_PRIVATE
- SplitPushedHeadersToRequestAndResponse(const SpdyHeaderBlock& headers,
- SpdyMajorVersion protocol_version,
- SpdyHeaderBlock* request_headers,
- SpdyHeaderBlock* response_headers);
-
// A helper class used to manage a request to create a stream.
class NET_EXPORT_PRIVATE SpdyStreamRequest {
public:
@@ -179,7 +179,7 @@ class NET_EXPORT_PRIVATE SpdyStreamRequest {
const base::WeakPtr<SpdySession>& session,
const GURL& url,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback);
// Cancels any pending stream creation request. May be called
@@ -208,7 +208,7 @@ class NET_EXPORT_PRIVATE SpdyStreamRequest {
SpdyStreamType type() const { return type_; }
const GURL& url() const { return url_; }
RequestPriority priority() const { return priority_; }
- const BoundNetLog& net_log() const { return net_log_; }
+ const NetLogWithSource& net_log() const { return net_log_; }
void Reset();
@@ -217,7 +217,7 @@ class NET_EXPORT_PRIVATE SpdyStreamRequest {
base::WeakPtr<SpdyStream> stream_;
GURL url_;
RequestPriority priority_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
CompletionCallback callback_;
base::WeakPtrFactory<SpdyStreamRequest> weak_ptr_factory_;
@@ -295,11 +295,8 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
SpdySession(const SpdySessionKey& spdy_session_key,
HttpServerProperties* http_server_properties,
TransportSecurityState* transport_security_state,
- bool verify_domain_authentication,
bool enable_sending_initial_data,
bool enable_ping_based_connection_checking,
- bool enable_priority_dependencies,
- NextProto default_protocol,
size_t session_max_recv_window_size,
size_t stream_max_recv_window_size,
TimeFunc time_func,
@@ -325,10 +322,9 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// okay to create a new stream (in which case |spdy_stream| is
// reset). Returns an error (not ERR_IO_PENDING) otherwise, and
// resets |spdy_stream|.
- int GetPushStream(
- const GURL& url,
- base::WeakPtr<SpdyStream>* spdy_stream,
- const BoundNetLog& stream_net_log);
+ int GetPushStream(const GURL& url,
+ base::WeakPtr<SpdyStream>* spdy_stream,
+ const NetLogWithSource& stream_net_log);
// Initialize the session with the given connection. |is_secure|
// must indicate whether |connection| uses an SSL socket or not; it
@@ -338,20 +334,12 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// |pool| is the SpdySessionPool that owns us. Its lifetime must
// strictly be greater than |this|.
//
- // |certificate_error_code| must either be OK or less than
- // ERR_IO_PENDING.
- //
// The session begins reading from |connection| on a subsequent event loop
// iteration, so the SpdySession may close immediately afterwards if the first
// read of |connection| fails.
void InitializeWithSocket(std::unique_ptr<ClientSocketHandle> connection,
SpdySessionPool* pool,
- bool is_secure,
- int certificate_error_code);
-
- // Returns the protocol used by this session. Always between
- // kProtoSPDYMinimumVersion and kProtoSPDYMaximumVersion.
- NextProto protocol() const { return protocol_; }
+ bool is_secure);
// Check to see if this SPDY session can support an additional domain.
// If the session is un-authenticated, then this call always returns true.
@@ -372,11 +360,11 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
SpdyFrameType frame_type,
std::unique_ptr<SpdyBufferProducer> producer);
- // Creates and returns a SYN frame for |stream_id|.
- std::unique_ptr<SpdySerializedFrame> CreateSynStream(SpdyStreamId stream_id,
- RequestPriority priority,
- SpdyControlFlags flags,
- SpdyHeaderBlock headers);
+ // Creates and returns a HEADERS frame for |stream_id|.
+ std::unique_ptr<SpdySerializedFrame> CreateHeaders(SpdyStreamId stream_id,
+ RequestPriority priority,
+ SpdyControlFlags flags,
+ SpdyHeaderBlock headers);
// Creates and returns a SpdyBuffer holding a data frame with the
// given data. May return NULL if stalled by flow control.
@@ -413,14 +401,21 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
url::SchemeHostPort GetServer();
// Fills SSL info in |ssl_info| and returns true when SSL is in use.
- bool GetSSLInfo(SSLInfo* ssl_info,
- bool* was_npn_negotiated,
- NextProto* protocol_negotiated);
+ bool GetSSLInfo(SSLInfo* ssl_info) const;
+
+ // Returns true if ALPN was negotiated for the underlying socket.
+ // TODO(bnc): Rename to WasAlpnNegotiated().
+ bool WasNpnNegotiated() const;
- // Signs the EKM value for Token Binding from the TLS layer using |*key| and
- // puts the result in |*out|. Returns OK or ERR_FAILED.
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out);
+ // Returns the protocol negotiated via ALPN for the underlying socket.
+ NextProto GetNegotiatedProtocol() const;
+
+ // Generates the signature used in Token Binding using |*key| and for a Token
+ // Binding of type |tb_type|, putting the signature in |*out|. Returns a net
+ // error code of OK or ERR_FAILED.
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out);
// Send a WINDOW_UPDATE frame for a stream. Called by a stream
// whenever receive window size is increased.
@@ -518,7 +513,7 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// session flow control.
bool IsSendStalled() const { return session_send_window_size_ == 0; }
- const BoundNetLog& net_log() const { return net_log_; }
+ const NetLogWithSource& net_log() const { return net_log_; }
int GetPeerAddress(IPEndPoint* address) const;
int GetLocalAddress(IPEndPoint* address) const;
@@ -531,14 +526,12 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
return pooled_aliases_;
}
- SpdyMajorVersion GetProtocolVersion() const;
-
size_t GetDataFrameMinimumSize() const {
return buffered_spdy_framer_->GetDataFrameMinimumSize();
}
- size_t GetControlFrameHeaderSize() const {
- return buffered_spdy_framer_->GetControlFrameHeaderSize();
+ size_t GetFrameHeaderSize() const {
+ return buffered_spdy_framer_->GetFrameHeaderSize();
}
size_t GetFrameMinimumSize() const {
@@ -553,12 +546,6 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
return buffered_spdy_framer_->GetDataFrameMaximumPayload();
}
- // Default value of SETTINGS_INITIAL_WINDOW_SIZE per protocol specification.
- // A session is always created with this initial window size.
- static int32_t GetDefaultInitialWindowSize(NextProto protocol) {
- return protocol < kProtoHTTP2 ? 65536 : 65535;
- }
-
// https://http2.github.io/http2-spec/#TLSUsage mandates minimum security
// standards for TLS.
bool HasAcceptableTransportSecurity() const;
@@ -623,7 +610,7 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
~ActiveStreamInfo();
SpdyStream* stream;
- bool waiting_for_syn_reply;
+ bool waiting_for_reply_headers_frame;
};
typedef std::map<SpdyStreamId, ActiveStreamInfo> ActiveStreamMap;
@@ -655,12 +642,6 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
WRITE_STATE_DO_WRITE_COMPLETE,
};
- // Checks whether a stream for the given |url| can be created or
- // retrieved from the set of unclaimed push streams. Returns OK if
- // so. Otherwise, the session is closed and an error <
- // ERR_IO_PENDING is returned.
- Error TryAccessStream(const GURL& url);
-
// 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
@@ -691,7 +672,7 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
bool TryCreatePushStream(SpdyStreamId stream_id,
SpdyStreamId associated_stream_id,
SpdyPriority priority,
- const SpdyHeaderBlock& headers);
+ SpdyHeaderBlock headers);
// Close the stream pointed to by the given iterator. Note that that
// stream may hold the last reference to the session.
@@ -822,6 +803,10 @@ 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);
+ // Returns the stream id of the push stream if it is not claimed yet, or 0
+ // otherwise.
+ SpdyStreamId GetStreamIdForPush(const GURL& url);
+
// 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.
@@ -892,23 +877,14 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override;
void OnPushPromise(SpdyStreamId stream_id,
SpdyStreamId promised_stream_id,
- const SpdyHeaderBlock& headers) override;
- void OnSynStream(SpdyStreamId stream_id,
- SpdyStreamId associated_stream_id,
- SpdyPriority priority,
- bool fin,
- bool unidirectional,
- const SpdyHeaderBlock& headers) override;
- void OnSynReply(SpdyStreamId stream_id,
- bool fin,
- const SpdyHeaderBlock& headers) override;
+ SpdyHeaderBlock headers) override;
void OnHeaders(SpdyStreamId stream_id,
bool has_priority,
int weight,
SpdyStreamId parent_stream_id,
bool exclusive,
bool fin,
- const SpdyHeaderBlock& headers) override;
+ SpdyHeaderBlock headers) override;
void OnAltSvc(SpdyStreamId stream_id,
base::StringPiece origin,
const SpdyAltSvcWireFormat::AlternativeServiceVector&
@@ -1093,9 +1069,6 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// Flag if we're using an SSL connection for this SpdySession.
bool is_secure_;
- // Certificate error code when using a secure connection.
- int certificate_error_code_;
-
// Spdy Frame state.
std::unique_ptr<BufferedSpdyFramer> buffered_spdy_framer_;
@@ -1152,9 +1125,6 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// status.
bool check_ping_status_pending_;
- // Whether to send the (HTTP/2) connection header prefix.
- bool send_connection_header_prefix_;
-
// Current send window size. Zero unless session flow control is turned on.
int32_t session_send_window_size_;
@@ -1190,17 +1160,12 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// in the past.
std::deque<SpdyStreamId> stream_send_unstall_queue_[NUM_PRIORITIES];
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
// Outside of tests, these should always be true.
- bool verify_domain_authentication_;
bool enable_sending_initial_data_;
bool enable_ping_based_connection_checking_;
- // The SPDY protocol used. Always between kProtoSPDYMinimumVersion and
- // kProtoSPDYMaximumVersion.
- NextProto protocol_;
-
// |connection_at_risk_of_loss_time_| is an optimization to avoid sending
// wasteful preface pings (when we just got some data).
//
@@ -1230,7 +1195,6 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
TimeFunc time_func_;
- const bool priority_dependencies_enabled_;
Http2PriorityDependencies priority_dependency_state_;
// Used for posting asynchronous IO tasks. We use this even though
diff --git a/chromium/net/spdy/spdy_session_key.h b/chromium/net/spdy/spdy_session_key.h
index a393ce00a15..b1da297d3b8 100644
--- a/chromium/net/spdy/spdy_session_key.h
+++ b/chromium/net/spdy/spdy_session_key.h
@@ -5,6 +5,7 @@
#ifndef NET_SPDY_SPDY_SESSION_KEY_H_
#define NET_SPDY_SPDY_SESSION_KEY_H_
+#include "net/base/net_export.h"
#include "net/base/privacy_mode.h"
#include "net/proxy/proxy_server.h"
diff --git a/chromium/net/spdy/spdy_session_pool.cc b/chromium/net/spdy/spdy_session_pool.cc
index dfac110810d..ea35c455c7b 100644
--- a/chromium/net/spdy/spdy_session_pool.cc
+++ b/chromium/net/spdy/spdy_session_pool.cc
@@ -15,6 +15,9 @@
#include "net/base/address_list.h"
#include "net/http/http_network_session.h"
#include "net/http/http_server_properties.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.h"
#include "net/spdy/spdy_session.h"
namespace net {
@@ -37,8 +40,6 @@ SpdySessionPool::SpdySessionPool(
HttpServerProperties* http_server_properties,
TransportSecurityState* transport_security_state,
bool enable_ping_based_connection_checking,
- bool enable_priority_dependencies,
- NextProto default_protocol,
size_t session_max_recv_window_size,
size_t stream_max_recv_window_size,
SpdySessionPool::TimeFunc time_func,
@@ -47,21 +48,13 @@ SpdySessionPool::SpdySessionPool(
transport_security_state_(transport_security_state),
ssl_config_service_(ssl_config_service),
resolver_(resolver),
- verify_domain_authentication_(true),
enable_sending_initial_data_(true),
enable_ping_based_connection_checking_(
enable_ping_based_connection_checking),
- enable_priority_dependencies_(enable_priority_dependencies),
- // TODO(akalin): Force callers to have a valid value of
- // |default_protocol_|.
- default_protocol_((default_protocol == kProtoUnknown) ? kProtoSPDY31
- : default_protocol),
session_max_recv_window_size_(session_max_recv_window_size),
stream_max_recv_window_size_(stream_max_recv_window_size),
time_func_(time_func),
proxy_delegate_(proxy_delegate) {
- DCHECK(default_protocol_ >= kProtoSPDYMinimumVersion &&
- default_protocol_ <= kProtoSPDYMaximumVersion);
NetworkChangeNotifier::AddIPAddressObserver(this);
if (ssl_config_service_.get())
ssl_config_service_->AddObserver(this);
@@ -86,33 +79,27 @@ SpdySessionPool::~SpdySessionPool() {
base::WeakPtr<SpdySession> SpdySessionPool::CreateAvailableSessionFromSocket(
const SpdySessionKey& key,
std::unique_ptr<ClientSocketHandle> connection,
- const BoundNetLog& net_log,
- int certificate_error_code,
+ const NetLogWithSource& net_log,
bool is_secure) {
TRACE_EVENT0("net", "SpdySessionPool::CreateAvailableSessionFromSocket");
- DCHECK_GE(default_protocol_, kProtoSPDYMinimumVersion);
- DCHECK_LE(default_protocol_, kProtoSPDYMaximumVersion);
UMA_HISTOGRAM_ENUMERATION(
"Net.SpdySessionGet", IMPORTED_FROM_SOCKET, SPDY_SESSION_GET_MAX);
std::unique_ptr<SpdySession> new_session(new SpdySession(
key, http_server_properties_, transport_security_state_,
- verify_domain_authentication_, enable_sending_initial_data_,
- enable_ping_based_connection_checking_, enable_priority_dependencies_,
- default_protocol_, session_max_recv_window_size_,
- stream_max_recv_window_size_, time_func_, proxy_delegate_,
- net_log.net_log()));
+ enable_sending_initial_data_, enable_ping_based_connection_checking_,
+ session_max_recv_window_size_, stream_max_recv_window_size_, time_func_,
+ proxy_delegate_, net_log.net_log()));
- new_session->InitializeWithSocket(std::move(connection), this, is_secure,
- certificate_error_code);
+ new_session->InitializeWithSocket(std::move(connection), this, is_secure);
base::WeakPtr<SpdySession> available_session = new_session->GetWeakPtr();
sessions_.insert(new_session.release());
MapKeyToAvailableSession(key, available_session);
net_log.AddEvent(
- NetLog::TYPE_HTTP2_SESSION_POOL_IMPORTED_SESSION_FROM_SOCKET,
+ NetLogEventType::HTTP2_SESSION_POOL_IMPORTED_SESSION_FROM_SOCKET,
available_session->net_log().source().ToEventParametersCallback());
// Look up the IP address for this session so that we can match
@@ -132,7 +119,7 @@ base::WeakPtr<SpdySession> SpdySessionPool::CreateAvailableSessionFromSocket(
base::WeakPtr<SpdySession> SpdySessionPool::FindAvailableSession(
const SpdySessionKey& key,
const GURL& url,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
UnclaimedPushedStreamMap::iterator url_it =
unclaimed_pushed_streams_.find(url);
if (!url.is_empty() && url_it != unclaimed_pushed_streams_.end()) {
@@ -167,7 +154,7 @@ base::WeakPtr<SpdySession> SpdySessionPool::FindAvailableSession(
UMA_HISTOGRAM_ENUMERATION(
"Net.SpdySessionGet", FOUND_EXISTING, SPDY_SESSION_GET_MAX);
net_log.AddEvent(
- NetLog::TYPE_HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION,
+ NetLogEventType::HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION,
it->second->net_log().source().ToEventParametersCallback());
return it->second;
}
@@ -206,7 +193,7 @@ base::WeakPtr<SpdySession> SpdySessionPool::FindAvailableSession(
const base::WeakPtr<SpdySession>& available_session =
available_session_it->second;
- DCHECK(ContainsKey(sessions_, available_session.get()));
+ DCHECK(base::ContainsKey(sessions_, available_session.get()));
// If the session is a secure one, we need to verify that the
// server is authenticated to serve traffic for |host_port_proxy_pair| too.
if (!available_session->VerifyDomainAuthentication(
@@ -220,7 +207,7 @@ base::WeakPtr<SpdySession> SpdySessionPool::FindAvailableSession(
FOUND_EXISTING_FROM_IP_POOL,
SPDY_SESSION_GET_MAX);
net_log.AddEvent(
- NetLog::TYPE_HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION_FROM_IP_POOL,
+ NetLogEventType::HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION_FROM_IP_POOL,
available_session->net_log().source().ToEventParametersCallback());
// Add this session to the map so that we can find it next time.
MapKeyToAvailableSession(key, available_session);
@@ -249,7 +236,7 @@ void SpdySessionPool::RemoveUnavailableSession(
DCHECK(!IsSessionAvailable(unavailable_session));
unavailable_session->net_log().AddEvent(
- NetLog::TYPE_HTTP2_SESSION_POOL_REMOVE_SESSION,
+ NetLogEventType::HTTP2_SESSION_POOL_REMOVE_SESSION,
unavailable_session->net_log().source().ToEventParametersCallback());
SessionSet::iterator it = sessions_.find(unavailable_session.get());
@@ -285,7 +272,7 @@ void SpdySessionPool::RegisterUnclaimedPushedStream(
base::WeakPtr<SpdySession> spdy_session) {
DCHECK(!url.is_empty());
// This SpdySessionPool must own |spdy_session|.
- DCHECK(ContainsKey(sessions_, spdy_session.get()));
+ DCHECK(base::ContainsKey(sessions_, spdy_session.get()));
UnclaimedPushedStreamMap::iterator url_it =
unclaimed_pushed_streams_.lower_bound(url);
if (url_it == unclaimed_pushed_streams_.end() || url_it->first != url) {
@@ -396,7 +383,7 @@ bool SpdySessionPool::IsSessionAvailable(
void SpdySessionPool::MapKeyToAvailableSession(
const SpdySessionKey& key,
const base::WeakPtr<SpdySession>& session) {
- DCHECK(ContainsKey(sessions_, session.get()));
+ DCHECK(base::ContainsKey(sessions_, session.get()));
std::pair<AvailableSessionMap::iterator, bool> result =
available_sessions_.insert(std::make_pair(key, session));
CHECK(result.second);
diff --git a/chromium/net/spdy/spdy_session_pool.h b/chromium/net/spdy/spdy_session_pool.h
index bdcb03b0ce6..d0bcc25d4f8 100644
--- a/chromium/net/spdy/spdy_session_pool.h
+++ b/chromium/net/spdy/spdy_session_pool.h
@@ -23,17 +23,16 @@
#include "net/cert/cert_database.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_server.h"
-#include "net/socket/next_proto.h"
#include "net/spdy/spdy_session_key.h"
#include "net/ssl/ssl_config_service.h"
namespace net {
class AddressList;
-class BoundNetLog;
class ClientSocketHandle;
class HostResolver;
class HttpServerProperties;
+class NetLogWithSource;
class ProxyDelegate;
class SpdySession;
class TransportSecurityState;
@@ -46,16 +45,11 @@ class NET_EXPORT SpdySessionPool
public:
typedef base::TimeTicks (*TimeFunc)(void);
- // |default_protocol| may be kProtoUnknown (e.g., if SPDY is
- // disabled), in which case it's set to a default value. Otherwise,
- // it must be a SPDY protocol.
SpdySessionPool(HostResolver* host_resolver,
SSLConfigService* ssl_config_service,
HttpServerProperties* http_server_properties,
TransportSecurityState* transport_security_state,
bool enable_ping_based_connection_checking,
- bool enable_priority_dependencies,
- NextProto default_protocol,
size_t session_max_recv_window_size,
size_t stream_max_recv_window_size,
SpdySessionPool::TimeFunc time_func,
@@ -71,14 +65,10 @@ class NET_EXPORT SpdySessionPool
// processing existing streams.
// Create a new SPDY session from an existing socket. There must
- // not already be a session for the given key. This pool must have
- // been constructed with a valid |default_protocol| value.
+ // not already be a session for the given key.
//
// |is_secure| can be false for testing or when SPDY is configured
- // to work with non-secure sockets. If |is_secure| is true,
- // |certificate_error_code| indicates that the certificate error
- // encountered when connecting the SSL socket, with OK meaning there
- // was no error.
+ // to work with non-secure sockets.
//
// Returns the new SpdySession. Note that the SpdySession begins reading from
// |connection| on a subsequent event loop iteration, so it may be closed
@@ -86,16 +76,16 @@ class NET_EXPORT SpdySessionPool
base::WeakPtr<SpdySession> CreateAvailableSessionFromSocket(
const SpdySessionKey& key,
std::unique_ptr<ClientSocketHandle> connection,
- const BoundNetLog& net_log,
- int certificate_error_code,
+ const NetLogWithSource& net_log,
bool is_secure);
// Return an available session for |key| that has an unclaimed push stream for
// |url| if such exists and |url| is not empty, or else an available session
// for |key| if such exists, or else nullptr.
- base::WeakPtr<SpdySession> FindAvailableSession(const SpdySessionKey& key,
- const GURL& url,
- const BoundNetLog& net_log);
+ base::WeakPtr<SpdySession> FindAvailableSession(
+ const SpdySessionKey& key,
+ const GURL& url,
+ const NetLogWithSource& net_log);
// Remove all mappings and aliases for the given session, which must
// still be available. Except for in tests, this must be called by
@@ -224,11 +214,8 @@ class NET_EXPORT SpdySessionPool
HostResolver* const resolver_;
// Defaults to true. May be controlled via SpdySessionPoolPeer for tests.
- bool verify_domain_authentication_;
bool enable_sending_initial_data_;
bool enable_ping_based_connection_checking_;
- const bool enable_priority_dependencies_;
- const NextProto default_protocol_;
size_t session_max_recv_window_size_;
size_t stream_max_recv_window_size_;
TimeFunc time_func_;
diff --git a/chromium/net/spdy/spdy_session_pool_unittest.cc b/chromium/net/spdy/spdy_session_pool_unittest.cc
index 978c288e769..c9810809a4d 100644
--- a/chromium/net/spdy/spdy_session_pool_unittest.cc
+++ b/chromium/net/spdy/spdy_session_pool_unittest.cc
@@ -9,21 +9,29 @@
#include <string>
#include <utility>
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "net/dns/host_cache.h"
#include "net/http/http_network_session.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/transport_client_socket_pool.h"
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_stream_test_util.h"
#include "net/spdy/spdy_test_util_common.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
-class SpdySessionPoolTest : public ::testing::Test,
- public ::testing::WithParamInterface<NextProto> {
+class SpdySessionPoolTest : public ::testing::Test {
protected:
// Used by RunIPPoolingTest().
enum SpdyPoolCloseSessionsType {
@@ -32,27 +40,29 @@ class SpdySessionPoolTest : public ::testing::Test,
SPDY_POOL_CLOSE_IDLE_SESSIONS,
};
- SpdySessionPoolTest()
- : session_deps_(GetParam()),
- spdy_session_pool_(NULL) {}
+ SpdySessionPoolTest() : spdy_session_pool_(NULL) {}
void CreateNetworkSession() {
http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
spdy_session_pool_ = http_session_->spdy_session_pool();
}
+ void AddSSLSocketData() {
+ auto ssl = base::MakeUnique<SSLSocketDataProvider>(SYNCHRONOUS, OK);
+ ssl->cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
+ ASSERT_TRUE(ssl->cert);
+ session_deps_.socket_factory->AddSSLSocketDataProvider(ssl.get());
+ ssl_data_vector_.push_back(std::move(ssl));
+ }
+
void RunIPPoolingTest(SpdyPoolCloseSessionsType close_sessions_type);
SpdySessionDependencies session_deps_;
std::unique_ptr<HttpNetworkSession> http_session_;
SpdySessionPool* spdy_session_pool_;
+ std::vector<std::unique_ptr<SSLSocketDataProvider>> ssl_data_vector_;
};
-INSTANTIATE_TEST_CASE_P(NextProto,
- SpdySessionPoolTest,
- testing::Values(kProtoSPDY31,
- kProtoHTTP2));
-
// A delegate that opens a new session when it is closed.
class SessionOpeningDelegate : public SpdyStream::Delegate {
public:
@@ -87,7 +97,7 @@ class SessionOpeningDelegate : public SpdyStream::Delegate {
// Set up a SpdyStream to create a new session when it is closed.
// CloseCurrentSessions should not close the newly-created session.
-TEST_P(SpdySessionPoolTest, CloseCurrentSessions) {
+TEST_F(SpdySessionPoolTest, CloseCurrentSessions) {
const char kTestHost[] = "www.foo.com";
const int kTestPort = 80;
@@ -114,8 +124,8 @@ TEST_P(SpdySessionPoolTest, CloseCurrentSessions) {
CreateNetworkSession();
// Setup the first session to the first host.
- base::WeakPtr<SpdySession> session =
- CreateInsecureSpdySession(http_session_.get(), test_key, BoundNetLog());
+ base::WeakPtr<SpdySession> session = CreateSecureSpdySession(
+ http_session_.get(), test_key, NetLogWithSource());
// Flush the SpdySession::OnReadComplete() task.
base::RunLoop().RunUntilIdle();
@@ -124,10 +134,9 @@ TEST_P(SpdySessionPoolTest, CloseCurrentSessions) {
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
// Set the stream to create a new session when it is closed.
- base::WeakPtr<SpdyStream> spdy_stream =
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
- session, GURL("http://www.foo.com"),
- MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
+ SPDY_BIDIRECTIONAL_STREAM, session, GURL("http://www.foo.com"), MEDIUM,
+ NetLogWithSource());
SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
spdy_stream->SetDelegate(&delegate);
@@ -137,7 +146,7 @@ TEST_P(SpdySessionPoolTest, CloseCurrentSessions) {
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
}
-TEST_P(SpdySessionPoolTest, CloseCurrentIdleSessions) {
+TEST_F(SpdySessionPoolTest, CloseCurrentIdleSessions) {
MockConnect connect_data(SYNCHRONOUS, OK);
MockRead reads[] = {
MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
@@ -149,54 +158,52 @@ TEST_P(SpdySessionPoolTest, CloseCurrentIdleSessions) {
data1.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+ AddSSLSocketData();
+ AddSSLSocketData();
+ AddSSLSocketData();
CreateNetworkSession();
// Set up session 1
- const std::string kTestHost1("http://www.a.com");
+ const std::string kTestHost1("http://www.example.org");
HostPortPair test_host_port_pair1(kTestHost1, 80);
SpdySessionKey key1(test_host_port_pair1, ProxyServer::Direct(),
PRIVACY_MODE_DISABLED);
base::WeakPtr<SpdySession> session1 =
- CreateInsecureSpdySession(http_session_.get(), key1, BoundNetLog());
+ CreateSecureSpdySession(http_session_.get(), key1, NetLogWithSource());
GURL url1(kTestHost1);
- base::WeakPtr<SpdyStream> spdy_stream1 =
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
- session1, url1, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
+ SPDY_BIDIRECTIONAL_STREAM, session1, url1, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
// Set up session 2
StaticSocketDataProvider data2(reads, arraysize(reads), nullptr, 0);
data2.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data2);
- const std::string kTestHost2("http://www.b.com");
+ const std::string kTestHost2("http://mail.example.org");
HostPortPair test_host_port_pair2(kTestHost2, 80);
SpdySessionKey key2(test_host_port_pair2, ProxyServer::Direct(),
PRIVACY_MODE_DISABLED);
base::WeakPtr<SpdySession> session2 =
- CreateInsecureSpdySession(http_session_.get(), key2, BoundNetLog());
+ CreateSecureSpdySession(http_session_.get(), key2, NetLogWithSource());
GURL url2(kTestHost2);
- base::WeakPtr<SpdyStream> spdy_stream2 =
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
- session2, url2, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
+ SPDY_BIDIRECTIONAL_STREAM, session2, url2, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream2);
// Set up session 3
StaticSocketDataProvider data3(reads, arraysize(reads), nullptr, 0);
data3.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data3);
- const std::string kTestHost3("http://www.c.com");
+ const std::string kTestHost3("http://mail.example.com");
HostPortPair test_host_port_pair3(kTestHost3, 80);
SpdySessionKey key3(test_host_port_pair3, ProxyServer::Direct(),
PRIVACY_MODE_DISABLED);
base::WeakPtr<SpdySession> session3 =
- CreateInsecureSpdySession(http_session_.get(), key3, BoundNetLog());
+ CreateSecureSpdySession(http_session_.get(), key3, NetLogWithSource());
GURL url3(kTestHost3);
- base::WeakPtr<SpdyStream> spdy_stream3 =
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
- session3, url3, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream3 = CreateStreamSynchronously(
+ SPDY_BIDIRECTIONAL_STREAM, session3, url3, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream3);
// All sessions are active and not closed
@@ -262,7 +269,7 @@ TEST_P(SpdySessionPoolTest, CloseCurrentIdleSessions) {
// Set up a SpdyStream to create a new session when it is closed.
// CloseAllSessions should close the newly-created session.
-TEST_P(SpdySessionPoolTest, CloseAllSessions) {
+TEST_F(SpdySessionPoolTest, CloseAllSessions) {
const char kTestHost[] = "www.foo.com";
const int kTestPort = 80;
@@ -289,8 +296,8 @@ TEST_P(SpdySessionPoolTest, CloseAllSessions) {
CreateNetworkSession();
// Setup the first session to the first host.
- base::WeakPtr<SpdySession> session =
- CreateInsecureSpdySession(http_session_.get(), test_key, BoundNetLog());
+ base::WeakPtr<SpdySession> session = CreateSecureSpdySession(
+ http_session_.get(), test_key, NetLogWithSource());
// Flush the SpdySession::OnReadComplete() task.
base::RunLoop().RunUntilIdle();
@@ -299,10 +306,9 @@ TEST_P(SpdySessionPoolTest, CloseAllSessions) {
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
// Set the stream to create a new session when it is closed.
- base::WeakPtr<SpdyStream> spdy_stream =
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
- session, GURL("http://www.foo.com"),
- MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
+ SPDY_BIDIRECTIONAL_STREAM, session, GURL("http://www.foo.com"), MEDIUM,
+ NetLogWithSource());
SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
spdy_stream->SetDelegate(&delegate);
@@ -329,21 +335,16 @@ void SpdySessionPoolTest::RunIPPoolingTest(
SpdySessionKey key;
AddressList addresses;
} test_hosts[] = {
- { "http:://www.foo.com",
- "www.foo.com",
- "192.0.2.33,192.168.0.1,192.168.0.5"
- },
- { "http://js.foo.com",
- "js.foo.com",
- "192.168.0.2,192.168.0.3,192.168.0.5,192.0.2.33"
- },
- { "http://images.foo.com",
- "images.foo.com",
- "192.168.0.4,192.168.0.3"
- },
+ {"http:://www.example.org", "www.example.org",
+ "192.0.2.33,192.168.0.1,192.168.0.5"},
+ {"http://mail.example.org", "mail.example.org",
+ "192.168.0.2,192.168.0.3,192.168.0.5,192.0.2.33"},
+ {"http://mail.example.com", "mail.example.com",
+ "192.168.0.4,192.168.0.3"},
};
session_deps_.host_resolver->set_synchronous_mode(true);
+ std::unique_ptr<HostResolver::Request> request[arraysize(test_hosts)];
for (size_t i = 0; i < arraysize(test_hosts); i++) {
session_deps_.host_resolver->rules()->AddIPLiteralRule(
test_hosts[i].name, test_hosts[i].iplist, std::string());
@@ -351,12 +352,9 @@ void SpdySessionPoolTest::RunIPPoolingTest(
// This test requires that the HostResolver cache be populated. Normal
// code would have done this already, but we do it manually.
HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
- session_deps_.host_resolver->Resolve(info,
- DEFAULT_PRIORITY,
- &test_hosts[i].addresses,
- CompletionCallback(),
- NULL,
- BoundNetLog());
+ session_deps_.host_resolver->Resolve(
+ info, DEFAULT_PRIORITY, &test_hosts[i].addresses, CompletionCallback(),
+ &request[i], NetLogWithSource());
// Setup a SpdySessionKey
test_hosts[i].key = SpdySessionKey(
@@ -373,14 +371,13 @@ void SpdySessionPoolTest::RunIPPoolingTest(
data1.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+ AddSSLSocketData();
CreateNetworkSession();
// Setup the first session to the first host.
- base::WeakPtr<SpdySession> session = CreateInsecureSpdySession(
- http_session_.get(), test_hosts[0].key, BoundNetLog());
+ base::WeakPtr<SpdySession> session = CreateSecureSpdySession(
+ http_session_.get(), test_hosts[0].key, NetLogWithSource());
// Flush the SpdySession::OnReadComplete() task.
base::RunLoop().RunUntilIdle();
@@ -404,8 +401,11 @@ void SpdySessionPoolTest::RunIPPoolingTest(
StaticSocketDataProvider data2(reads, arraysize(reads), NULL, 0);
data2.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&data2);
- base::WeakPtr<SpdySession> session2 = CreateInsecureSpdySession(
- http_session_.get(), test_hosts[2].key, BoundNetLog());
+
+ AddSSLSocketData();
+
+ base::WeakPtr<SpdySession> session2 = CreateSecureSpdySession(
+ http_session_.get(), test_hosts[2].key, NetLogWithSource());
// Verify that we have sessions for everything.
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
@@ -416,7 +416,7 @@ void SpdySessionPoolTest::RunIPPoolingTest(
// we got with host 0, and that is a different from host 2's session.
base::WeakPtr<SpdySession> session1 =
spdy_session_pool_->FindAvailableSession(
- test_hosts[1].key, GURL(test_hosts[1].url), BoundNetLog());
+ test_hosts[1].key, GURL(test_hosts[1].url), NetLogWithSource());
EXPECT_EQ(session.get(), session1.get());
EXPECT_NE(session2.get(), session1.get());
@@ -444,17 +444,16 @@ void SpdySessionPoolTest::RunIPPoolingTest(
break;
case SPDY_POOL_CLOSE_IDLE_SESSIONS:
GURL url(test_hosts[0].url);
- base::WeakPtr<SpdyStream> spdy_stream =
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
- session, url, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
+ SPDY_BIDIRECTIONAL_STREAM, session, url, MEDIUM, NetLogWithSource());
GURL url1(test_hosts[1].url);
base::WeakPtr<SpdyStream> spdy_stream1 =
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
- session1, url1, MEDIUM, BoundNetLog());
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session1, url1,
+ MEDIUM, NetLogWithSource());
GURL url2(test_hosts[2].url);
base::WeakPtr<SpdyStream> spdy_stream2 =
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
- session2, url2, MEDIUM, BoundNetLog());
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session2, url2,
+ MEDIUM, NetLogWithSource());
// Close streams to make spdy_session and spdy_session1 inactive.
session->CloseCreatedStream(spdy_stream, OK);
@@ -498,22 +497,22 @@ void SpdySessionPoolTest::RunIPPoolingTest(
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
}
-TEST_P(SpdySessionPoolTest, IPPooling) {
+TEST_F(SpdySessionPoolTest, IPPooling) {
RunIPPoolingTest(SPDY_POOL_CLOSE_SESSIONS_MANUALLY);
}
-TEST_P(SpdySessionPoolTest, IPPoolingCloseCurrentSessions) {
+TEST_F(SpdySessionPoolTest, IPPoolingCloseCurrentSessions) {
RunIPPoolingTest(SPDY_POOL_CLOSE_CURRENT_SESSIONS);
}
-TEST_P(SpdySessionPoolTest, IPPoolingCloseIdleSessions) {
+TEST_F(SpdySessionPoolTest, IPPoolingCloseIdleSessions) {
RunIPPoolingTest(SPDY_POOL_CLOSE_IDLE_SESSIONS);
}
// Construct a Pool with SpdySessions in various availability states. Simulate
// an IP address change. Ensure sessions gracefully shut down. Regression test
// for crbug.com/379469.
-TEST_P(SpdySessionPoolTest, IPAddressChanged) {
+TEST_F(SpdySessionPoolTest, IPAddressChanged) {
MockConnect connect_data(SYNCHRONOUS, OK);
session_deps_.host_resolver->set_synchronous_mode(true);
@@ -521,44 +520,40 @@ TEST_P(SpdySessionPoolTest, IPAddressChanged) {
// can ignore issues of how dependencies are set. We default to
// setting them (when doing the appropriate protocol) since that's
// where we're eventually headed for all HTTP/2 connections.
- session_deps_.enable_priority_dependencies = true;
- SpdyTestUtil spdy_util(GetParam(), /*enable_priority_dependencies*/ true);
+ SpdyTestUtil spdy_util;
MockRead reads[] = {
MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
};
- std::unique_ptr<SpdySerializedFrame> req(
- spdy_util.ConstructSpdyGet("http://www.a.com", 1, MEDIUM));
- MockWrite writes[] = {CreateMockWrite(*req, 1)};
+ SpdySerializedFrame req(
+ spdy_util.ConstructSpdyGet("http://www.example.org", 1, MEDIUM));
+ MockWrite writes[] = {CreateMockWrite(req, 1)};
StaticSocketDataProvider dataA(reads, arraysize(reads), writes,
arraysize(writes));
dataA.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&dataA);
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+ AddSSLSocketData();
CreateNetworkSession();
// Set up session A: Going away, but with an active stream.
- const std::string kTestHostA("http://www.a.com");
+ const std::string kTestHostA("http://www.example.org");
HostPortPair test_host_port_pairA(kTestHostA, 80);
SpdySessionKey keyA(
test_host_port_pairA, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
base::WeakPtr<SpdySession> sessionA =
- CreateInsecureSpdySession(http_session_.get(), keyA, BoundNetLog());
+ CreateSecureSpdySession(http_session_.get(), keyA, NetLogWithSource());
GURL urlA(kTestHostA);
base::WeakPtr<SpdyStream> spdy_streamA = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, sessionA, urlA, MEDIUM, BoundNetLog());
+ SPDY_BIDIRECTIONAL_STREAM, sessionA, urlA, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegateA(spdy_streamA);
spdy_streamA->SetDelegate(&delegateA);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util.ConstructGetHeaderBlock(urlA.spec())));
+ SpdyHeaderBlock headers(spdy_util.ConstructGetHeaderBlock(urlA.spec()));
spdy_streamA->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_streamA->HasUrlFromHeaders());
base::RunLoop().RunUntilIdle(); // Allow headers to write.
EXPECT_TRUE(delegateA.send_headers_completed());
@@ -572,17 +567,20 @@ TEST_P(SpdySessionPoolTest, IPAddressChanged) {
arraysize(writes));
dataB.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&dataB);
- const std::string kTestHostB("http://www.b.com");
+
+ AddSSLSocketData();
+
+ const std::string kTestHostB("http://mail.example.org");
HostPortPair test_host_port_pairB(kTestHostB, 80);
SpdySessionKey keyB(
test_host_port_pairB, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
base::WeakPtr<SpdySession> sessionB =
- CreateInsecureSpdySession(http_session_.get(), keyB, BoundNetLog());
+ CreateSecureSpdySession(http_session_.get(), keyB, NetLogWithSource());
EXPECT_TRUE(sessionB->IsAvailable());
GURL urlB(kTestHostB);
base::WeakPtr<SpdyStream> spdy_streamB = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, sessionB, urlB, MEDIUM, BoundNetLog());
+ SPDY_BIDIRECTIONAL_STREAM, sessionB, urlB, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegateB(spdy_streamB);
spdy_streamB->SetDelegate(&delegateB);
@@ -591,12 +589,15 @@ TEST_P(SpdySessionPoolTest, IPAddressChanged) {
arraysize(writes));
dataC.set_connect_data(connect_data);
session_deps_.socket_factory->AddSocketDataProvider(&dataC);
- const std::string kTestHostC("http://www.c.com");
+
+ AddSSLSocketData();
+
+ const std::string kTestHostC("http://mail.example.com");
HostPortPair test_host_port_pairC(kTestHostC, 80);
SpdySessionKey keyC(
test_host_port_pairC, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
base::WeakPtr<SpdySession> sessionC =
- CreateInsecureSpdySession(http_session_.get(), keyC, BoundNetLog());
+ CreateSecureSpdySession(http_session_.get(), keyC, NetLogWithSource());
sessionC->CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Error!");
EXPECT_TRUE(sessionC->IsDraining());
@@ -613,13 +614,13 @@ TEST_P(SpdySessionPoolTest, IPAddressChanged) {
EXPECT_FALSE(delegateA.StreamIsClosed());
EXPECT_TRUE(delegateB.StreamIsClosed()); // Created stream was closed.
- EXPECT_EQ(ERR_NETWORK_CHANGED, delegateB.WaitForClose());
+ EXPECT_THAT(delegateB.WaitForClose(), IsError(ERR_NETWORK_CHANGED));
sessionA->CloseSessionOnError(ERR_ABORTED, "Closing");
sessionB->CloseSessionOnError(ERR_ABORTED, "Closing");
EXPECT_TRUE(delegateA.StreamIsClosed());
- EXPECT_EQ(ERR_ABORTED, delegateA.WaitForClose());
+ EXPECT_THAT(delegateA.WaitForClose(), IsError(ERR_ABORTED));
#else
EXPECT_TRUE(sessionA->IsDraining());
EXPECT_TRUE(sessionB->IsDraining());
@@ -627,13 +628,13 @@ TEST_P(SpdySessionPoolTest, IPAddressChanged) {
// Both streams were closed with an error.
EXPECT_TRUE(delegateA.StreamIsClosed());
- EXPECT_EQ(ERR_NETWORK_CHANGED, delegateA.WaitForClose());
+ EXPECT_THAT(delegateA.WaitForClose(), IsError(ERR_NETWORK_CHANGED));
EXPECT_TRUE(delegateB.StreamIsClosed());
- EXPECT_EQ(ERR_NETWORK_CHANGED, delegateB.WaitForClose());
+ EXPECT_THAT(delegateB.WaitForClose(), IsError(ERR_NETWORK_CHANGED));
#endif // defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
}
-TEST_P(SpdySessionPoolTest, FindAvailableSession) {
+TEST_F(SpdySessionPoolTest, FindAvailableSession) {
SpdySessionKey key(HostPortPair("https://www.example.org", 443),
ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
@@ -648,7 +649,7 @@ TEST_P(SpdySessionPoolTest, FindAvailableSession) {
CreateNetworkSession();
base::WeakPtr<SpdySession> session =
- CreateInsecureSpdySession(http_session_.get(), key, BoundNetLog());
+ CreateSecureSpdySession(http_session_.get(), key, NetLogWithSource());
// Flush the SpdySession::OnReadComplete() task.
base::RunLoop().RunUntilIdle();
@@ -657,14 +658,14 @@ TEST_P(SpdySessionPoolTest, FindAvailableSession) {
// FindAvailableSession should return |session| if called with empty |url|.
base::WeakPtr<SpdySession> session1 =
- spdy_session_pool_->FindAvailableSession(key, GURL(), BoundNetLog());
+ spdy_session_pool_->FindAvailableSession(key, GURL(), NetLogWithSource());
EXPECT_EQ(session.get(), session1.get());
// FindAvailableSession should return |session| if called with |url| for which
// there is no pushed stream on any sessions owned by |spdy_session_pool_|.
base::WeakPtr<SpdySession> session2 =
spdy_session_pool_->FindAvailableSession(
- key, GURL("http://news.example.org/foo.html"), BoundNetLog());
+ key, GURL("http://news.example.org/foo.html"), NetLogWithSource());
EXPECT_EQ(session.get(), session2.get());
spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
diff --git a/chromium/net/spdy/spdy_session_unittest.cc b/chromium/net/spdy/spdy_session_unittest.cc
index 1aafe5ef60e..34b4270b244 100644
--- a/chromium/net/spdy/spdy_session_unittest.cc
+++ b/chromium/net/spdy/spdy_session_unittest.cc
@@ -20,12 +20,13 @@
#include "net/base/test_data_stream.h"
#include "net/base/test_proxy_delegate.h"
#include "net/cert/ct_policy_status.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.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/proxy/proxy_server.h"
#include "net/socket/client_socket_pool_manager.h"
-#include "net/socket/next_proto.h"
#include "net/socket/socket_test_util.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/spdy/spdy_session_pool.h"
@@ -35,27 +36,18 @@
#include "net/spdy/spdy_test_util_common.h"
#include "net/spdy/spdy_test_utils.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/platform_test.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
-enum TestCase {
- // Test using the SPDY/3.1 protocol.
- kTestCaseSPDY31,
-
- // Test using the HTTP/2 protocol, without specifying a stream
- // dependency based on the RequestPriority.
- kTestCaseHTTP2NoPriorityDependencies,
-
- // Test using the HTTP/2 protocol, specifying a stream
- // dependency based on the RequestPriority.
- kTestCaseHTTP2PriorityDependencies
-};
-
const char kHttpURLFromAnotherOrigin[] = "http://www.example2.org/a.dat";
const char kHttpsURLFromAnotherOrigin[] = "https://www.example2.org/b.dat";
@@ -88,8 +80,7 @@ class MockRequireCTDelegate : public TransportSecurityState::RequireCTDelegate {
} // namespace
-class SpdySessionTest : public PlatformTest,
- public ::testing::WithParamInterface<TestCase> {
+class SpdySessionTest : public PlatformTest {
public:
// Functions used with RunResumeAfterUnstallTest().
@@ -126,31 +117,20 @@ class SpdySessionTest : public PlatformTest,
}
protected:
- NextProto GetProtocol() const {
- return GetParam() == kTestCaseSPDY31 ? kProtoSPDY31 : kProtoHTTP2;
- }
-
- bool GetDependenciesFromPriority() const {
- return GetParam() == kTestCaseHTTP2PriorityDependencies;
- }
-
SpdySessionTest()
: old_max_group_sockets_(ClientSocketPoolManager::max_sockets_per_group(
HttpNetworkSession::NORMAL_SOCKET_POOL)),
old_max_pool_sockets_(ClientSocketPoolManager::max_sockets_per_pool(
HttpNetworkSession::NORMAL_SOCKET_POOL)),
- spdy_util_(GetProtocol(), GetDependenciesFromPriority()),
- session_deps_(GetProtocol()),
spdy_session_pool_(nullptr),
test_url_(kDefaultUrl),
test_server_(test_url_),
key_(HostPortPair::FromURL(test_url_),
ProxyServer::Direct(),
- PRIVACY_MODE_DISABLED) {
- session_deps_.enable_priority_dependencies = GetDependenciesFromPriority();
- }
+ PRIVACY_MODE_DISABLED),
+ ssl_(SYNCHRONOUS, OK) {}
- virtual ~SpdySessionTest() {
+ ~SpdySessionTest() override {
// Important to restore the per-pool limit first, since the pool limit must
// always be greater than group limit, and the tests reduce both limits.
ClientSocketPoolManager::set_max_sockets_per_pool(
@@ -179,6 +159,12 @@ class SpdySessionTest : public PlatformTest,
log_.bound());
}
+ void AddSSLSocketData() {
+ ssl_.cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
+ ASSERT_TRUE(ssl_.cert);
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_);
+ }
+
void CreateSecureSpdySession() {
DCHECK(!session_);
session_ =
@@ -226,18 +212,13 @@ class SpdySessionTest : public PlatformTest,
const GURL test_url_;
const url::SchemeHostPort test_server_;
SpdySessionKey key_;
+ SSLSocketDataProvider ssl_;
BoundTestNetLog log_;
};
-INSTANTIATE_TEST_CASE_P(ProtoPlusDepend,
- SpdySessionTest,
- testing::Values(kTestCaseSPDY31,
- kTestCaseHTTP2NoPriorityDependencies,
- kTestCaseHTTP2PriorityDependencies));
-
// Try to create a SPDY session that will fail during
// initialization. Nothing should blow up.
-TEST_P(SpdySessionTest, InitialReadError) {
+TEST_F(SpdySessionTest, InitialReadError) {
CreateNetworkSession();
session_ = TryCreateFakeSpdySessionExpectingFailure(spdy_session_pool_, key_,
@@ -282,7 +263,7 @@ class StreamRequestDestroyingCallback : public TestCompletionCallbackBase {
// streams, but have the callback for one destroy the second stream
// request. Close the session. Nothing should blow up. This is a
// regression test for http://crbug.com/250841 .
-TEST_P(SpdySessionTest, PendingStreamCancellingAnother) {
+TEST_F(SpdySessionTest, PendingStreamCancellingAnother) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {MockRead(ASYNC, 0, 0), };
@@ -290,13 +271,16 @@ TEST_P(SpdySessionTest, PendingStreamCancellingAnother) {
SequencedSocketData data(reads, arraysize(reads), nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
// Create the maximum number of concurrent streams.
for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) {
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream);
}
@@ -304,40 +288,40 @@ TEST_P(SpdySessionTest, PendingStreamCancellingAnother) {
std::unique_ptr<SpdyStreamRequest> request2(new SpdyStreamRequest);
StreamRequestDestroyingCallback callback1;
- ASSERT_EQ(
- ERR_IO_PENDING,
- request1.StartRequest(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
- MEDIUM, BoundNetLog(), callback1.MakeCallback()));
+ ASSERT_EQ(ERR_IO_PENDING,
+ request1.StartRequest(SPDY_BIDIRECTIONAL_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource(),
+ callback1.MakeCallback()));
// |callback2| is never called.
TestCompletionCallback callback2;
- ASSERT_EQ(ERR_IO_PENDING, request2->StartRequest(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
- MEDIUM, BoundNetLog(), callback2.callback()));
+ ASSERT_EQ(
+ ERR_IO_PENDING,
+ request2->StartRequest(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ MEDIUM, NetLogWithSource(), callback2.callback()));
callback1.SetRequestToDestroy(std::move(request2));
session_->CloseSessionOnError(ERR_ABORTED, "Aborting session");
- EXPECT_EQ(ERR_ABORTED, callback1.WaitForResult());
+ EXPECT_THAT(callback1.WaitForResult(), IsError(ERR_ABORTED));
}
// A session receiving a GOAWAY frame with no active streams should close.
-TEST_P(SpdySessionTest, GoAwayWithNoActiveStreams) {
+TEST_F(SpdySessionTest, GoAwayWithNoActiveStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> goaway(
- spdy_util_.ConstructSpdyGoAway(1));
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1));
MockRead reads[] = {
- CreateMockRead(*goaway, 0),
+ CreateMockRead(goaway, 0),
};
SequencedSocketData data(reads, arraysize(reads), nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
- CreateNetworkSession();
- CreateInsecureSpdySession();
+ AddSSLSocketData();
- EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
+ CreateNetworkSession();
+ CreateSecureSpdySession();
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
@@ -349,21 +333,22 @@ TEST_P(SpdySessionTest, GoAwayWithNoActiveStreams) {
// A session receiving a GOAWAY frame immediately with no active
// streams should then close.
-TEST_P(SpdySessionTest, GoAwayImmediatelyWithNoActiveStreams) {
+TEST_F(SpdySessionTest, GoAwayImmediatelyWithNoActiveStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> goaway(
- spdy_util_.ConstructSpdyGoAway(1));
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1));
MockRead reads[] = {
- CreateMockRead(*goaway, 0, SYNCHRONOUS), MockRead(ASYNC, 0, 1) // EOF
+ CreateMockRead(goaway, 0, SYNCHRONOUS), MockRead(ASYNC, 0, 1) // EOF
};
SequencedSocketData data(reads, arraysize(reads), nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- session_ = TryCreateInsecureSpdySessionExpectingFailure(
- http_session_.get(), key_, ERR_CONNECTION_CLOSED, BoundNetLog());
+ session_ = TryCreateSpdySessionExpectingFailure(
+ http_session_.get(), key_, ERR_CONNECTION_CLOSED, NetLogWithSource());
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(session_);
@@ -373,52 +358,46 @@ TEST_P(SpdySessionTest, GoAwayImmediatelyWithNoActiveStreams) {
// A session receiving a GOAWAY frame with active streams should close
// when the last active stream is closed.
-TEST_P(SpdySessionTest, GoAwayWithActiveStreams) {
+TEST_F(SpdySessionTest, GoAwayWithActiveStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> goaway(
- spdy_util_.ConstructSpdyGoAway(1));
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1));
MockRead reads[] = {
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*goaway, 3),
- MockRead(ASYNC, ERR_IO_PENDING, 4),
- MockRead(ASYNC, 0, 5) // EOF
+ MockRead(ASYNC, ERR_IO_PENDING, 2), CreateMockRead(goaway, 3),
+ MockRead(ASYNC, ERR_IO_PENDING, 4), MockRead(ASYNC, 0, 5) // EOF
};
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
- CreateMockWrite(*req2, 1),
+ CreateMockWrite(req1, 0), CreateMockWrite(req2, 1),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
- CreateNetworkSession();
- CreateInsecureSpdySession();
+ AddSSLSocketData();
- EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
+ CreateNetworkSession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
- base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream2 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate2(spdy_stream2);
spdy_stream2->SetDelegate(&delegate2);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
- std::unique_ptr<SpdyHeaderBlock> headers2(
- new SpdyHeaderBlock(headers->Clone()));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
+ SpdyHeaderBlock headers2(headers.Clone());
spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
base::RunLoop().RunUntilIdle();
@@ -450,37 +429,35 @@ TEST_P(SpdySessionTest, GoAwayWithActiveStreams) {
}
// Regression test for https://crbug.com/547130.
-TEST_P(SpdySessionTest, GoAwayWithActiveAndCreatedStream) {
+TEST_F(SpdySessionTest, GoAwayWithActiveAndCreatedStream) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> goaway(
- spdy_util_.ConstructSpdyGoAway(0));
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(0));
MockRead reads[] = {
- MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(*goaway, 2),
+ MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(goaway, 2),
};
// No |req2|, because the second stream will never get activated.
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
+ CreateMockWrite(req1, 0),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
- CreateNetworkSession();
- CreateInsecureSpdySession();
+ AddSSLSocketData();
- EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
+ CreateNetworkSession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
- std::unique_ptr<SpdyHeaderBlock> headers1(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers1), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
EXPECT_EQ(0u, spdy_stream1->stream_id());
@@ -490,8 +467,9 @@ TEST_P(SpdySessionTest, GoAwayWithActiveAndCreatedStream) {
EXPECT_TRUE(session_->IsStreamActive(1));
// Create stream corresponding to the next request.
- base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream2 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
EXPECT_EQ(0u, spdy_stream2->stream_id());
@@ -509,56 +487,48 @@ TEST_P(SpdySessionTest, GoAwayWithActiveAndCreatedStream) {
// Have a session receive two GOAWAY frames, with the last one causing
// the last active stream to be closed. The session should then be
// closed after the second GOAWAY frame.
-TEST_P(SpdySessionTest, GoAwayTwice) {
+TEST_F(SpdySessionTest, GoAwayTwice) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> goaway1(
- spdy_util_.ConstructSpdyGoAway(1));
- std::unique_ptr<SpdySerializedFrame> goaway2(
- spdy_util_.ConstructSpdyGoAway(0));
+ SpdySerializedFrame goaway1(spdy_util_.ConstructSpdyGoAway(1));
+ SpdySerializedFrame goaway2(spdy_util_.ConstructSpdyGoAway(0));
MockRead reads[] = {
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*goaway1, 3),
- MockRead(ASYNC, ERR_IO_PENDING, 4),
- CreateMockRead(*goaway2, 5),
- MockRead(ASYNC, ERR_IO_PENDING, 6),
- MockRead(ASYNC, 0, 7) // EOF
+ MockRead(ASYNC, ERR_IO_PENDING, 2), CreateMockRead(goaway1, 3),
+ MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(goaway2, 5),
+ MockRead(ASYNC, ERR_IO_PENDING, 6), MockRead(ASYNC, 0, 7) // EOF
};
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
- CreateMockWrite(*req2, 1),
+ CreateMockWrite(req1, 0), CreateMockWrite(req2, 1),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
- CreateNetworkSession();
- CreateInsecureSpdySession();
+ AddSSLSocketData();
- EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
+ CreateNetworkSession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
- base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream2 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate2(spdy_stream2);
spdy_stream2->SetDelegate(&delegate2);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
- std::unique_ptr<SpdyHeaderBlock> headers2(
- new SpdyHeaderBlock(headers->Clone()));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
+ SpdyHeaderBlock headers2(headers.Clone());
spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
base::RunLoop().RunUntilIdle();
@@ -588,52 +558,46 @@ TEST_P(SpdySessionTest, GoAwayTwice) {
// Have a session with active streams receive a GOAWAY frame and then
// close it. It should handle the close properly (i.e., not try to
// make itself unavailable in its pool twice).
-TEST_P(SpdySessionTest, GoAwayWithActiveStreamsThenClose) {
+TEST_F(SpdySessionTest, GoAwayWithActiveStreamsThenClose) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> goaway(
- spdy_util_.ConstructSpdyGoAway(1));
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1));
MockRead reads[] = {
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*goaway, 3),
- MockRead(ASYNC, ERR_IO_PENDING, 4),
- MockRead(ASYNC, 0, 5) // EOF
+ MockRead(ASYNC, ERR_IO_PENDING, 2), CreateMockRead(goaway, 3),
+ MockRead(ASYNC, ERR_IO_PENDING, 4), MockRead(ASYNC, 0, 5) // EOF
};
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
- CreateMockWrite(*req2, 1),
+ CreateMockWrite(req1, 0), CreateMockWrite(req2, 1),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
- CreateNetworkSession();
- CreateInsecureSpdySession();
+ AddSSLSocketData();
- EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
+ CreateNetworkSession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
- base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream2 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate2(spdy_stream2);
spdy_stream2->SetDelegate(&delegate2);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
- std::unique_ptr<SpdyHeaderBlock> headers2(
- new SpdyHeaderBlock(headers->Clone()));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
+ SpdyHeaderBlock headers2(headers.Clone());
spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
base::RunLoop().RunUntilIdle();
@@ -664,102 +628,96 @@ TEST_P(SpdySessionTest, GoAwayWithActiveStreamsThenClose) {
// Process a joint read buffer which causes the session to begin draining, and
// then processes a GOAWAY. The session should gracefully drain. Regression test
// for crbug.com/379469
-TEST_P(SpdySessionTest, GoAwayWhileDraining) {
+TEST_F(SpdySessionTest, GoAwayWhileDraining) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
+ CreateMockWrite(req, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> goaway(
- spdy_util_.ConstructSpdyGoAway(1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- size_t joint_size = goaway->size() * 2 + body->size();
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
+ size_t joint_size = goaway.size() * 2 + body.size();
// Compose interleaved |goaway| and |body| frames into a single read.
std::unique_ptr<char[]> buffer(new char[joint_size]);
{
size_t out = 0;
- memcpy(&buffer[out], goaway->data(), goaway->size());
- out += goaway->size();
- memcpy(&buffer[out], body->data(), body->size());
- out += body->size();
- memcpy(&buffer[out], goaway->data(), goaway->size());
- out += goaway->size();
+ memcpy(&buffer[out], goaway.data(), goaway.size());
+ out += goaway.size();
+ memcpy(&buffer[out], body.data(), body.size());
+ out += body.size();
+ memcpy(&buffer[out], goaway.data(), goaway.size());
+ out += goaway.size();
ASSERT_EQ(out, joint_size);
}
SpdySerializedFrame joint_frames(buffer.get(), joint_size, false);
MockRead reads[] = {
- CreateMockRead(*resp, 1), CreateMockRead(joint_frames, 2),
+ CreateMockRead(resp, 1), CreateMockRead(joint_frames, 2),
MockRead(ASYNC, 0, 3) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate(spdy_stream);
spdy_stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
base::RunLoop().RunUntilIdle();
// Stream and session closed gracefully.
EXPECT_TRUE(delegate.StreamIsClosed());
- EXPECT_EQ(OK, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsOk());
EXPECT_EQ(kUploadData, delegate.TakeReceivedData());
EXPECT_FALSE(session_);
}
// Try to create a stream after receiving a GOAWAY frame. It should
// fail.
-TEST_P(SpdySessionTest, CreateStreamAfterGoAway) {
+TEST_F(SpdySessionTest, CreateStreamAfterGoAway) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> goaway(
- spdy_util_.ConstructSpdyGoAway(1));
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1));
MockRead reads[] = {
- MockRead(ASYNC, ERR_IO_PENDING, 1),
- CreateMockRead(*goaway, 2),
- MockRead(ASYNC, ERR_IO_PENDING, 3),
- MockRead(ASYNC, 0, 4) // EOF
+ MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(goaway, 2),
+ MockRead(ASYNC, ERR_IO_PENDING, 3), MockRead(ASYNC, 0, 4) // EOF
};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
+ CreateMockWrite(req, 0),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
- CreateNetworkSession();
- CreateInsecureSpdySession();
+ AddSSLSocketData();
- EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
+ CreateNetworkSession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate(spdy_stream);
spdy_stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
base::RunLoop().RunUntilIdle();
@@ -776,9 +734,9 @@ TEST_P(SpdySessionTest, CreateStreamAfterGoAway) {
SpdyStreamRequest stream_request;
int rv = stream_request.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session_,
- test_url_, MEDIUM, BoundNetLog(),
+ test_url_, MEDIUM, NetLogWithSource(),
CompletionCallback());
- EXPECT_EQ(ERR_FAILED, rv);
+ EXPECT_THAT(rv, IsError(ERR_FAILED));
EXPECT_TRUE(session_);
data.Resume();
@@ -786,44 +744,40 @@ TEST_P(SpdySessionTest, CreateStreamAfterGoAway) {
EXPECT_FALSE(session_);
}
-// Receiving a SYN_STREAM frame after a GOAWAY frame should result in
+// Receiving a HEADERS frame after a GOAWAY frame should result in
// the stream being refused.
-TEST_P(SpdySessionTest, SynStreamAfterGoAway) {
+TEST_F(SpdySessionTest, HeadersAfterGoAway) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> goaway(
- spdy_util_.ConstructSpdyGoAway(1));
- std::unique_ptr<SpdySerializedFrame> push(
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1));
+ SpdySerializedFrame push(
spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kDefaultUrl));
MockRead reads[] = {
- MockRead(ASYNC, ERR_IO_PENDING, 1),
- CreateMockRead(*goaway, 2),
- MockRead(ASYNC, ERR_IO_PENDING, 3),
- CreateMockRead(*push, 4),
+ MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(goaway, 2),
+ MockRead(ASYNC, ERR_IO_PENDING, 3), CreateMockRead(push, 4),
MockRead(ASYNC, 0, 6) // EOF
};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
- MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*rst, 5)};
+ MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 5)};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
- CreateNetworkSession();
- CreateInsecureSpdySession();
+ AddSSLSocketData();
- EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
+ CreateNetworkSession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate(spdy_stream);
spdy_stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
base::RunLoop().RunUntilIdle();
@@ -838,7 +792,7 @@ TEST_P(SpdySessionTest, SynStreamAfterGoAway) {
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
EXPECT_TRUE(session_->IsStreamActive(1));
- // Read and process the SYN_STREAM frame, the subsequent RST_STREAM,
+ // Read and process the HEADERS frame, the subsequent RST_STREAM,
// and EOF.
data.Resume();
base::RunLoop().RunUntilIdle();
@@ -847,35 +801,34 @@ TEST_P(SpdySessionTest, SynStreamAfterGoAway) {
// A session observing a network change with active streams should close
// when the last active stream is closed.
-TEST_P(SpdySessionTest, NetworkChangeWithActiveStreams) {
+TEST_F(SpdySessionTest, NetworkChangeWithActiveStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {
MockRead(ASYNC, ERR_IO_PENDING, 1), MockRead(ASYNC, 0, 2) // EOF
};
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
+ CreateMockWrite(req1, 0),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
- CreateNetworkSession();
- CreateInsecureSpdySession();
+ AddSSLSocketData();
- EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
+ CreateNetworkSession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate(spdy_stream);
spdy_stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
base::RunLoop().RunUntilIdle();
@@ -908,30 +861,30 @@ TEST_P(SpdySessionTest, NetworkChangeWithActiveStreams) {
EXPECT_FALSE(session_);
}
-TEST_P(SpdySessionTest, ClientPing) {
+TEST_F(SpdySessionTest, ClientPing) {
session_deps_.enable_ping = true;
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> read_ping(
- spdy_util_.ConstructSpdyPing(1, true));
+ SpdySerializedFrame read_ping(spdy_util_.ConstructSpdyPing(1, true));
MockRead reads[] = {
- CreateMockRead(*read_ping, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(read_ping, 1), MockRead(ASYNC, ERR_IO_PENDING, 2),
MockRead(ASYNC, 0, 3) // EOF
};
- std::unique_ptr<SpdySerializedFrame> write_ping(
- spdy_util_.ConstructSpdyPing(1, false));
+ SpdySerializedFrame write_ping(spdy_util_.ConstructSpdyPing(1, false));
MockWrite writes[] = {
- CreateMockWrite(*write_ping, 0),
+ CreateMockWrite(write_ping, 0),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
test::StreamDelegateSendImmediate delegate(spdy_stream1, nullptr);
spdy_stream1->SetDelegate(&delegate);
@@ -956,35 +909,35 @@ TEST_P(SpdySessionTest, ClientPing) {
data.Resume();
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
EXPECT_FALSE(session_);
}
-TEST_P(SpdySessionTest, ServerPing) {
+TEST_F(SpdySessionTest, ServerPing) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> read_ping(
- spdy_util_.ConstructSpdyPing(2, false));
+ SpdySerializedFrame read_ping(spdy_util_.ConstructSpdyPing(2, false));
MockRead reads[] = {
- CreateMockRead(*read_ping),
- MockRead(SYNCHRONOUS, 0, 0) // EOF
+ CreateMockRead(read_ping), MockRead(SYNCHRONOUS, 0, 0) // EOF
};
- std::unique_ptr<SpdySerializedFrame> write_ping(
- spdy_util_.ConstructSpdyPing(2, true));
+ SpdySerializedFrame write_ping(spdy_util_.ConstructSpdyPing(2, true));
MockWrite writes[] = {
- CreateMockWrite(*write_ping),
+ CreateMockWrite(write_ping),
};
StaticSocketDataProvider data(
reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
test::StreamDelegateSendImmediate delegate(spdy_stream1, nullptr);
spdy_stream1->SetDelegate(&delegate);
@@ -1002,17 +955,15 @@ TEST_P(SpdySessionTest, ServerPing) {
// should handle this properly, i.e. another DoWriteLoop task should
// not be posted. This is a regression test for
// http://crbug.com/261043 .
-TEST_P(SpdySessionTest, PingAndWriteLoop) {
+TEST_F(SpdySessionTest, PingAndWriteLoop) {
session_deps_.enable_ping = true;
session_deps_.time_func = TheNearFuture;
- std::unique_ptr<SpdySerializedFrame> write_ping(
- spdy_util_.ConstructSpdyPing(1, false));
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame write_ping(spdy_util_.ConstructSpdyPing(1, false));
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
- CreateMockWrite(*write_ping, 1),
+ CreateMockWrite(req, 0), CreateMockWrite(write_ping, 1),
};
MockRead reads[] = {
@@ -1024,16 +975,18 @@ TEST_P(SpdySessionTest, PingAndWriteLoop) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, LOWEST, NetLogWithSource());
test::StreamDelegateDoNothing delegate(spdy_stream);
spdy_stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
// Shift time so that a ping will be sent out.
@@ -1047,7 +1000,7 @@ TEST_P(SpdySessionTest, PingAndWriteLoop) {
EXPECT_FALSE(session_);
}
-TEST_P(SpdySessionTest, StreamIdSpaceExhausted) {
+TEST_F(SpdySessionTest, StreamIdSpaceExhausted) {
const SpdyStreamId kLastStreamId = 0x7fffffff;
session_deps_.host_resolver->set_synchronous_mode(true);
@@ -1058,39 +1011,38 @@ TEST_P(SpdySessionTest, StreamIdSpaceExhausted) {
// stalled streams are aborted. Also verify the activated streams complete,
// at which point the session closes.
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, kLastStreamId - 2, MEDIUM, true));
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, kLastStreamId, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0), CreateMockWrite(*req2, 1),
+ CreateMockWrite(req1, 0), CreateMockWrite(req2, 1),
};
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, kLastStreamId - 2));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, kLastStreamId));
+ SpdySerializedFrame resp1(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, kLastStreamId - 2));
+ SpdySerializedFrame resp2(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, kLastStreamId));
- std::unique_ptr<SpdySerializedFrame> body1(
- spdy_util_.ConstructSpdyBodyFrame(kLastStreamId - 2, true));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(kLastStreamId, true));
+ SpdySerializedFrame body1(
+ spdy_util_.ConstructSpdyDataFrame(kLastStreamId - 2, true));
+ SpdySerializedFrame body2(
+ spdy_util_.ConstructSpdyDataFrame(kLastStreamId, true));
MockRead reads[] = {
- CreateMockRead(*resp1, 2),
- CreateMockRead(*resp2, 3),
- MockRead(ASYNC, ERR_IO_PENDING, 4),
- CreateMockRead(*body1, 5),
- CreateMockRead(*body2, 6),
- MockRead(ASYNC, 0, 7) // EOF
+ CreateMockRead(resp1, 2), CreateMockRead(resp2, 3),
+ MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(body1, 5),
+ CreateMockRead(body2, 6), MockRead(ASYNC, 0, 7) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
// Fix stream_hi_water_mark_ to allow for two stream activations.
session_->stream_hi_water_mark_ = kLastStreamId - 2;
@@ -1098,18 +1050,21 @@ TEST_P(SpdySessionTest, StreamIdSpaceExhausted) {
session_->max_concurrent_streams_ = 3;
// Create three streams synchronously, and begin a fourth (which is stalled).
- base::WeakPtr<SpdyStream> stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate1(stream1);
stream1->SetDelegate(&delegate1);
- base::WeakPtr<SpdyStream> stream2 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream2 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate2(stream2);
stream2->SetDelegate(&delegate2);
- base::WeakPtr<SpdyStream> stream3 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream3 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate3(stream3);
stream3->SetDelegate(&delegate3);
@@ -1118,7 +1073,7 @@ TEST_P(SpdySessionTest, StreamIdSpaceExhausted) {
EXPECT_EQ(
ERR_IO_PENDING,
request4.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_,
- MEDIUM, BoundNetLog(), callback4.callback()));
+ MEDIUM, NetLogWithSource(), callback4.callback()));
// Streams 1-3 were created. 4th is stalled. No streams are active yet.
EXPECT_EQ(0u, session_->num_active_streams());
@@ -1126,10 +1081,8 @@ TEST_P(SpdySessionTest, StreamIdSpaceExhausted) {
EXPECT_EQ(1u, session_->pending_create_stream_queue_size(MEDIUM));
// Activate stream 1. One ID remains available.
- stream1->SendRequestHeaders(
- std::unique_ptr<SpdyHeaderBlock>(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl))),
- NO_MORE_DATA_TO_SEND);
+ stream1->SendRequestHeaders(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl),
+ NO_MORE_DATA_TO_SEND);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(kLastStreamId - 2u, stream1->stream_id());
@@ -1138,10 +1091,8 @@ TEST_P(SpdySessionTest, StreamIdSpaceExhausted) {
EXPECT_EQ(1u, session_->pending_create_stream_queue_size(MEDIUM));
// Activate stream 2. ID space is exhausted.
- stream2->SendRequestHeaders(
- std::unique_ptr<SpdyHeaderBlock>(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl))),
- NO_MORE_DATA_TO_SEND);
+ stream2->SendRequestHeaders(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl),
+ NO_MORE_DATA_TO_SEND);
base::RunLoop().RunUntilIdle();
// Active streams remain active.
@@ -1150,17 +1101,17 @@ TEST_P(SpdySessionTest, StreamIdSpaceExhausted) {
// Session is going away. Created and stalled streams were aborted.
EXPECT_EQ(SpdySession::STATE_GOING_AWAY, session_->availability_state_);
- EXPECT_EQ(ERR_ABORTED, delegate3.WaitForClose());
- EXPECT_EQ(ERR_ABORTED, callback4.WaitForResult());
+ 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));
// Read responses on remaining active streams.
data.Resume();
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(OK, delegate1.WaitForClose());
+ EXPECT_THAT(delegate1.WaitForClose(), IsOk());
EXPECT_EQ(kUploadData, delegate1.TakeReceivedData());
- EXPECT_EQ(OK, delegate2.WaitForClose());
+ EXPECT_THAT(delegate2.WaitForClose(), IsOk());
EXPECT_EQ(kUploadData, delegate2.TakeReceivedData());
// Session was destroyed.
@@ -1168,68 +1119,56 @@ TEST_P(SpdySessionTest, StreamIdSpaceExhausted) {
}
// Regression test for https://crbug.com/481009.
-TEST_P(SpdySessionTest, MaxConcurrentStreamsZero) {
+TEST_F(SpdySessionTest, MaxConcurrentStreamsZero) {
session_deps_.host_resolver->set_synchronous_mode(true);
- int seq = 0;
- std::vector<MockRead> reads;
-
// Receive SETTINGS frame that sets max_concurrent_streams to zero.
SettingsMap settings_zero;
settings_zero[SETTINGS_MAX_CONCURRENT_STREAMS] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, 0);
- std::unique_ptr<SpdySerializedFrame> settings_frame_zero(
+ SpdySerializedFrame settings_frame_zero(
spdy_util_.ConstructSpdySettings(settings_zero));
- reads.push_back(CreateMockRead(*settings_frame_zero, seq++));
// Acknowledge it.
- std::vector<MockWrite> writes;
- std::unique_ptr<SpdySerializedFrame> settings_ack0;
- if (GetProtocol() == kProtoHTTP2) {
- settings_ack0.reset(spdy_util_.ConstructSpdySettingsAck());
- writes.push_back(CreateMockWrite(*settings_ack0, seq++));
- }
-
- // Pause.
- reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, seq++));
+ SpdySerializedFrame settings_ack0(spdy_util_.ConstructSpdySettingsAck());
// Receive SETTINGS frame that sets max_concurrent_streams to one.
SettingsMap settings_one;
settings_one[SETTINGS_MAX_CONCURRENT_STREAMS] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, 1);
- std::unique_ptr<SpdySerializedFrame> settings_frame_one(
+ SpdySerializedFrame settings_frame_one(
spdy_util_.ConstructSpdySettings(settings_one));
- reads.push_back(CreateMockRead(*settings_frame_one, seq++));
// Acknowledge it.
- std::unique_ptr<SpdySerializedFrame> settings_ack1;
- if (GetProtocol() == kProtoHTTP2) {
- settings_ack1.reset(spdy_util_.ConstructSpdySettingsAck());
- writes.push_back(CreateMockWrite(*settings_ack1, seq++));
- }
+ SpdySerializedFrame settings_ack1(spdy_util_.ConstructSpdySettingsAck());
// Request and response.
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
- writes.push_back(CreateMockWrite(*req, seq++));
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- reads.push_back(CreateMockRead(*resp, seq++));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- reads.push_back(CreateMockRead(*body, seq++));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
- reads.push_back(MockRead(ASYNC, 0, seq++));
+ MockRead reads[] = {CreateMockRead(settings_frame_zero, 0),
+ MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(settings_frame_one, 3),
+ CreateMockRead(resp, 6),
+ CreateMockRead(body, 7),
+ MockRead(ASYNC, 0, 8)};
- SequencedSocketData data(reads.data(), reads.size(), writes.data(),
- writes.size());
+ MockWrite writes[] = {CreateMockWrite(settings_ack0, 1),
+ CreateMockWrite(settings_ack1, 4),
+ CreateMockWrite(req, 5)};
+
+ SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
// Create session.
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
// Receive SETTINGS frame that sets max_concurrent_streams to zero.
base::RunLoop().RunUntilIdle();
@@ -1240,8 +1179,8 @@ TEST_P(SpdySessionTest, MaxConcurrentStreamsZero) {
TestCompletionCallback callback;
int rv =
request.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_,
- MEDIUM, BoundNetLog(), callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ MEDIUM, NetLogWithSource(), callback.callback());
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Stream is stalled.
EXPECT_EQ(1u, session_->pending_create_stream_queue_size(MEDIUM));
@@ -1256,18 +1195,16 @@ TEST_P(SpdySessionTest, MaxConcurrentStreamsZero) {
EXPECT_EQ(0u, session_->pending_create_stream_queue_size(MEDIUM));
EXPECT_EQ(1u, session_->num_created_streams());
- EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
// Send request.
base::WeakPtr<SpdyStream> stream = request.ReleaseStream();
test::StreamDelegateDoNothing delegate(stream);
stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(stream->HasUrlFromHeaders());
- EXPECT_EQ(OK, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsOk());
EXPECT_EQ("hello!", delegate.TakeReceivedData());
// Session is destroyed.
@@ -1277,7 +1214,7 @@ TEST_P(SpdySessionTest, MaxConcurrentStreamsZero) {
// Verifies that an unstalled pending stream creation racing with a new stream
// creation doesn't violate the maximum stream concurrency. Regression test for
// crbug.com/373858.
-TEST_P(SpdySessionTest, UnstallRacesWithStreamCreation) {
+TEST_F(SpdySessionTest, UnstallRacesWithStreamCreation) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {
@@ -1287,22 +1224,25 @@ TEST_P(SpdySessionTest, UnstallRacesWithStreamCreation) {
StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
// Fix max_concurrent_streams to allow for one open stream.
session_->max_concurrent_streams_ = 1;
// Create two streams: one synchronously, and one which stalls.
- base::WeakPtr<SpdyStream> stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
SpdyStreamRequest request2;
TestCompletionCallback callback2;
EXPECT_EQ(
ERR_IO_PENDING,
request2.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_,
- MEDIUM, BoundNetLog(), callback2.callback()));
+ MEDIUM, NetLogWithSource(), callback2.callback()));
EXPECT_EQ(1u, session_->num_created_streams());
EXPECT_EQ(1u, session_->pending_create_stream_queue_size(MEDIUM));
@@ -1315,8 +1255,9 @@ TEST_P(SpdySessionTest, UnstallRacesWithStreamCreation) {
EXPECT_EQ(0u, session_->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, BoundNetLog());
+ 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));
@@ -1333,50 +1274,48 @@ TEST_P(SpdySessionTest, UnstallRacesWithStreamCreation) {
EXPECT_EQ(1u, session_->num_created_streams());
EXPECT_EQ(0u, session_->pending_create_stream_queue_size(MEDIUM));
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
}
-TEST_P(SpdySessionTest, DeleteExpiredPushStreams) {
+TEST_F(SpdySessionTest, DeleteExpiredPushStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.time_func = TheNearFuture;
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
- MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*rst, 5)};
+ MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 5)};
- std::unique_ptr<SpdySerializedFrame> push_a(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush(
nullptr, 0, 2, 1, "https://www.example.org/a.dat"));
- std::unique_ptr<SpdySerializedFrame> push_a_body(
- spdy_util_.ConstructSpdyBodyFrame(2, false));
+ SpdySerializedFrame push_a_body(spdy_util_.ConstructSpdyDataFrame(2, false));
// In ascii "0" < "a". We use it to verify that we properly handle std::map
// iterators inside. See http://crbug.com/443490
- std::unique_ptr<SpdySerializedFrame> push_b(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame push_b(spdy_util_.ConstructSpdyPush(
nullptr, 0, 4, 1, "https://www.example.org/0.dat"));
MockRead reads[] = {
- CreateMockRead(*push_a, 1),
- CreateMockRead(*push_a_body, 2),
- MockRead(ASYNC, ERR_IO_PENDING, 3),
- CreateMockRead(*push_b, 4),
- MockRead(ASYNC, ERR_IO_PENDING, 6),
- MockRead(ASYNC, 0, 7) // EOF
+ CreateMockRead(push_a, 1), CreateMockRead(push_a_body, 2),
+ MockRead(ASYNC, ERR_IO_PENDING, 3), CreateMockRead(push_b, 4),
+ MockRead(ASYNC, ERR_IO_PENDING, 6), MockRead(ASYNC, 0, 7) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
// Process the principal request, and the first push stream request & body.
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate(spdy_stream);
spdy_stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
base::RunLoop().RunUntilIdle();
@@ -1387,12 +1326,11 @@ TEST_P(SpdySessionTest, DeleteExpiredPushStreams) {
GURL("https://www.example.org/a.dat")));
// Unclaimed push body consumed bytes from the session window.
- EXPECT_EQ(
- SpdySession::GetDefaultInitialWindowSize(GetProtocol()) - kUploadDataSize,
- session_->session_recv_window_size_);
+ EXPECT_EQ(kDefaultInitialWindowSize - kUploadDataSize,
+ session_->session_recv_window_size_);
EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_);
- // Shift time to expire the push stream. Read the second SYN_STREAM,
+ // Shift time to expire the push stream. Read the second HEADERS,
// and verify a RST_STREAM was written.
g_time_delta = base::TimeDelta::FromSeconds(301);
data.Resume();
@@ -1404,8 +1342,7 @@ TEST_P(SpdySessionTest, DeleteExpiredPushStreams) {
GURL("https://www.example.org/0.dat")));
// Verify that the session window reclaimed the evicted stream body.
- EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetProtocol()),
- session_->session_recv_window_size_);
+ EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_);
EXPECT_EQ(kUploadDataSize, session_->session_unacked_recv_window_bytes_);
// Read and process EOF.
@@ -1415,27 +1352,29 @@ TEST_P(SpdySessionTest, DeleteExpiredPushStreams) {
EXPECT_FALSE(session_);
}
-TEST_P(SpdySessionTest, FailedPing) {
+TEST_F(SpdySessionTest, FailedPing) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {
MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
};
- std::unique_ptr<SpdySerializedFrame> write_ping(
- spdy_util_.ConstructSpdyPing(1, false));
- std::unique_ptr<SpdySerializedFrame> goaway(
+ SpdySerializedFrame write_ping(spdy_util_.ConstructSpdyPing(1, false));
+ SpdySerializedFrame goaway(
spdy_util_.ConstructSpdyGoAway(0, GOAWAY_PROTOCOL_ERROR, "Failed ping."));
- MockWrite writes[] = {CreateMockWrite(*write_ping), CreateMockWrite(*goaway)};
+ MockWrite writes[] = {CreateMockWrite(write_ping), CreateMockWrite(goaway)};
StaticSocketDataProvider data(
reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
test::StreamDelegateSendImmediate delegate(spdy_stream1, nullptr);
spdy_stream1->SetDelegate(&delegate);
@@ -1472,150 +1411,58 @@ TEST_P(SpdySessionTest, FailedPing) {
// settings frame increasing the max concurrent streams by 1. Make
// sure nothing blows up. This is a regression test for
// http://crbug.com/57331 .
-TEST_P(SpdySessionTest, OnSettings) {
+TEST_F(SpdySessionTest, OnSettings) {
session_deps_.host_resolver->set_synchronous_mode(true);
const SpdySettingsIds kSpdySettingsIds = SETTINGS_MAX_CONCURRENT_STREAMS;
- int seq = 0;
- std::vector<MockWrite> writes;
- std::unique_ptr<SpdySerializedFrame> settings_ack(
- spdy_util_.ConstructSpdySettingsAck());
- if (GetProtocol() == kProtoHTTP2) {
- writes.push_back(CreateMockWrite(*settings_ack, ++seq));
- }
-
SettingsMap new_settings;
const uint32_t max_concurrent_streams = kInitialMaxConcurrentStreams + 1;
new_settings[kSpdySettingsIds] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
- std::unique_ptr<SpdySerializedFrame> settings_frame(
+ SpdySerializedFrame settings_frame(
spdy_util_.ConstructSpdySettings(new_settings));
MockRead reads[] = {
- CreateMockRead(*settings_frame, 0),
- MockRead(ASYNC, ERR_IO_PENDING, ++seq),
- MockRead(ASYNC, 0, ++seq),
+ CreateMockRead(settings_frame, 0), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ MockRead(ASYNC, 0, 3),
};
- SequencedSocketData data(reads, arraysize(reads), writes.data(),
- writes.size());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
-
- CreateNetworkSession();
- CreateInsecureSpdySession();
-
- // Create the maximum number of concurrent streams.
- for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) {
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
- ASSERT_TRUE(spdy_stream);
- }
-
- StreamReleaserCallback stream_releaser;
- SpdyStreamRequest request;
- ASSERT_EQ(ERR_IO_PENDING,
- request.StartRequest(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
- MEDIUM, BoundNetLog(),
- stream_releaser.MakeCallback(&request)));
-
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(OK, stream_releaser.WaitForResult());
-
- data.Resume();
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(session_);
-
- EXPECT_TRUE(data.AllWriteDataConsumed());
- EXPECT_TRUE(data.AllReadDataConsumed());
-}
-
-// Start with a persisted value for max concurrent streams. Receive a
-// settings frame increasing the max concurrent streams by 1 and which
-// also clears the persisted data. Verify that persisted data is
-// correct.
-TEST_P(SpdySessionTest, ClearSettings) {
- if (spdy_util_.spdy_version() >= HTTP2) {
- // HTTP/2 doesn't include settings persistence, or a CLEAR_SETTINGS flag.
- // Flag 0x1, CLEAR_SETTINGS in SPDY3, is instead settings ACK in HTTP/2.
- return;
- }
- session_deps_.host_resolver->set_synchronous_mode(true);
+ SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
+ MockWrite writes[] = {CreateMockWrite(settings_ack, 1)};
- SettingsMap new_settings;
- const uint32_t max_concurrent_streams = kInitialMaxConcurrentStreams + 1;
- new_settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
- SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
- std::unique_ptr<SpdySerializedFrame> settings_frame(
- spdy_util_.ConstructSpdySettings(new_settings));
- uint8_t flags = SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS;
- test::SetFrameFlags(settings_frame.get(), flags, spdy_util_.spdy_version());
- MockRead reads[] = {
- CreateMockRead(*settings_frame, 0),
- MockRead(ASYNC, ERR_IO_PENDING, 1),
- MockRead(ASYNC, 0, 2),
- };
-
- SequencedSocketData data(reads, arraysize(reads), nullptr, 0);
+ SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
- // Load a cert that is valid for:
- // www.example.org
- // mail.example.org
- // mail.example.com
- base::FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> test_cert(
- ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
- ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
-
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- ssl.cert = test_cert;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+ AddSSLSocketData();
CreateNetworkSession();
-
- // Initialize the SpdySetting with the default.
- spdy_session_pool_->http_server_properties()->SetSpdySetting(
- test_server_, SETTINGS_MAX_CONCURRENT_STREAMS,
- SETTINGS_FLAG_PLEASE_PERSIST, kInitialMaxConcurrentStreams);
-
- EXPECT_FALSE(spdy_session_pool_->http_server_properties()
- ->GetSpdySettings(test_server_)
- .empty());
-
CreateSecureSpdySession();
// Create the maximum number of concurrent streams.
for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) {
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream);
}
StreamReleaserCallback stream_releaser;
-
SpdyStreamRequest request;
ASSERT_EQ(ERR_IO_PENDING,
request.StartRequest(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
- MEDIUM, BoundNetLog(),
+ MEDIUM, NetLogWithSource(),
stream_releaser.MakeCallback(&request)));
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(OK, stream_releaser.WaitForResult());
-
- // Make sure that persisted data is cleared.
- EXPECT_TRUE(spdy_session_pool_->http_server_properties()
- ->GetSpdySettings(test_server_)
- .empty());
-
- // Make sure session's max_concurrent_streams is correct.
- EXPECT_EQ(kInitialMaxConcurrentStreams + 1,
- session_->max_concurrent_streams_);
+ EXPECT_THAT(stream_releaser.WaitForResult(), IsOk());
data.Resume();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(session_);
+
+ EXPECT_TRUE(data.AllWriteDataConsumed());
+ EXPECT_TRUE(data.AllReadDataConsumed());
}
// Start with max concurrent streams set to 1. Request two streams.
@@ -1623,7 +1470,7 @@ TEST_P(SpdySessionTest, ClearSettings) {
// should trigger the second stream creation. Then cancel that one
// immediately. Don't crash. This is a regression test for
// http://crbug.com/63532 .
-TEST_P(SpdySessionTest, CancelPendingCreateStream) {
+TEST_F(SpdySessionTest, CancelPendingCreateStream) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {
@@ -1633,6 +1480,8 @@ TEST_P(SpdySessionTest, CancelPendingCreateStream) {
StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
// Initialize the SpdySetting with 1 max concurrent streams.
@@ -1640,18 +1489,20 @@ TEST_P(SpdySessionTest, CancelPendingCreateStream) {
test_server_, SETTINGS_MAX_CONCURRENT_STREAMS,
SETTINGS_FLAG_PLEASE_PERSIST, 1);
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
// Leave room for only one more stream to be created.
for (size_t i = 0; i < kInitialMaxConcurrentStreams - 1; ++i) {
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream);
}
// Create 2 more streams. First will succeed. Second will be pending.
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
// Use scoped_ptr to let us invalidate the memory when we want to, to trigger
@@ -1659,9 +1510,10 @@ TEST_P(SpdySessionTest, CancelPendingCreateStream) {
std::unique_ptr<TestCompletionCallback> callback(new TestCompletionCallback);
SpdyStreamRequest request;
- ASSERT_EQ(ERR_IO_PENDING,
- request.StartRequest(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
- MEDIUM, BoundNetLog(), callback->callback()));
+ ASSERT_EQ(
+ ERR_IO_PENDING,
+ request.StartRequest(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ MEDIUM, NetLogWithSource(), callback->callback()));
// Release the first one, this will allow the second to be created.
spdy_stream1->Cancel();
@@ -1674,7 +1526,7 @@ TEST_P(SpdySessionTest, CancelPendingCreateStream) {
base::RunLoop().RunUntilIdle();
}
-TEST_P(SpdySessionTest, SendInitialDataOnNewSession) {
+TEST_F(SpdySessionTest, SendInitialDataOnNewSession) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {
@@ -1682,49 +1534,25 @@ TEST_P(SpdySessionTest, SendInitialDataOnNewSession) {
};
SettingsMap settings;
+ settings[SETTINGS_HEADER_TABLE_SIZE] =
+ SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxHeaderTableSize);
settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams);
- std::unique_ptr<SpdySerializedFrame> settings_frame(
+ SpdySerializedFrame settings_frame(
spdy_util_.ConstructSpdySettings(settings));
- std::vector<MockWrite> writes;
- if (GetProtocol() == kProtoHTTP2) {
- writes.push_back(
- MockWrite(ASYNC,
- kHttp2ConnectionHeaderPrefix,
- kHttp2ConnectionHeaderPrefixSize));
- }
- writes.push_back(CreateMockWrite(*settings_frame));
+ MockWrite writes[] = {MockWrite(ASYNC, kHttp2ConnectionHeaderPrefix,
+ kHttp2ConnectionHeaderPrefixSize),
+ CreateMockWrite(settings_frame)};
- SettingsMap server_settings;
- const uint32_t initial_max_concurrent_streams = 1;
- server_settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
- SettingsFlagsAndValue(SETTINGS_FLAG_PERSISTED,
- initial_max_concurrent_streams);
- std::unique_ptr<SpdySerializedFrame> server_settings_frame(
- spdy_util_.ConstructSpdySettings(server_settings));
- if (GetProtocol() == kProtoSPDY31) {
- writes.push_back(CreateMockWrite(*server_settings_frame));
- }
-
- StaticSocketDataProvider data(reads, arraysize(reads), writes.data(),
- writes.size());
+ StaticSocketDataProvider data(reads, arraysize(reads), writes,
+ arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
- // Load a cert that is valid for:
- // www.example.org
- // mail.example.org
- // mail.example.com
- base::FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> test_cert(
- ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
- ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
-
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- ssl.cert = test_cert;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+ AddSSLSocketData();
CreateNetworkSession();
+ const uint32_t initial_max_concurrent_streams = 1;
spdy_session_pool_->http_server_properties()->SetSpdySetting(
test_server_, SETTINGS_MAX_CONCURRENT_STREAMS,
SETTINGS_FLAG_PLEASE_PERSIST, initial_max_concurrent_streams);
@@ -1738,7 +1566,7 @@ TEST_P(SpdySessionTest, SendInitialDataOnNewSession) {
EXPECT_TRUE(data.AllWriteDataConsumed());
}
-TEST_P(SpdySessionTest, ClearSettingsStorageOnIPAddressChanged) {
+TEST_F(SpdySessionTest, ClearSettingsStorageOnIPAddressChanged) {
CreateNetworkSession();
HttpServerProperties* test_http_server_properties =
@@ -1754,7 +1582,7 @@ TEST_P(SpdySessionTest, ClearSettingsStorageOnIPAddressChanged) {
test_http_server_properties->GetSpdySettings(test_server_).size());
}
-TEST_P(SpdySessionTest, Initialize) {
+TEST_F(SpdySessionTest, Initialize) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {
@@ -1764,8 +1592,10 @@ TEST_P(SpdySessionTest, Initialize) {
StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
// Flush the read completion task.
@@ -1775,34 +1605,36 @@ TEST_P(SpdySessionTest, Initialize) {
log_.GetEntries(&entries);
EXPECT_LT(0u, entries.size());
- // Check that we logged TYPE_HTTP2_SESSION_INITIALIZED correctly.
+ // Check that we logged HTTP2_SESSION_INITIALIZED correctly.
int pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP2_SESSION_INITIALIZED, NetLog::PHASE_NONE);
+ entries, 0, NetLogEventType::HTTP2_SESSION_INITIALIZED,
+ NetLogEventPhase::NONE);
EXPECT_LT(0, pos);
TestNetLogEntry entry = entries[pos];
- NetLog::Source socket_source;
- EXPECT_TRUE(NetLog::Source::FromEventParameters(entry.params.get(),
- &socket_source));
+ NetLogSource socket_source;
+ EXPECT_TRUE(
+ NetLogSource::FromEventParameters(entry.params.get(), &socket_source));
EXPECT_TRUE(socket_source.IsValid());
EXPECT_NE(log_.bound().source().id, socket_source.id);
}
-TEST_P(SpdySessionTest, NetLogOnSessionGoaway) {
+TEST_F(SpdySessionTest, NetLogOnSessionGoaway) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> goaway(
+ SpdySerializedFrame goaway(
spdy_util_.ConstructSpdyGoAway(42, GOAWAY_ENHANCE_YOUR_CALM, "foo"));
MockRead reads[] = {
- CreateMockRead(*goaway),
- MockRead(SYNCHRONOUS, 0, 0) // EOF
+ CreateMockRead(goaway), MockRead(SYNCHRONOUS, 0, 0) // EOF
};
StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
// Flush the read completion task.
@@ -1816,38 +1648,37 @@ TEST_P(SpdySessionTest, NetLogOnSessionGoaway) {
log_.GetEntries(&entries);
EXPECT_LT(0u, entries.size());
- if (GetProtocol() == kProtoHTTP2) {
- int pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP2_SESSION_GOAWAY, NetLog::PHASE_NONE);
- TestNetLogEntry entry = entries[pos];
- int last_accepted_stream_id;
- ASSERT_TRUE(entry.GetIntegerValue("last_accepted_stream_id",
- &last_accepted_stream_id));
- EXPECT_EQ(42, last_accepted_stream_id);
- int active_streams;
- ASSERT_TRUE(entry.GetIntegerValue("active_streams", &active_streams));
- EXPECT_EQ(0, active_streams);
- int unclaimed_streams;
- ASSERT_TRUE(entry.GetIntegerValue("unclaimed_streams", &unclaimed_streams));
- EXPECT_EQ(0, unclaimed_streams);
- int status;
- ASSERT_TRUE(entry.GetIntegerValue("status", &status));
- EXPECT_EQ(GOAWAY_ENHANCE_YOUR_CALM, status);
- std::string debug_data;
- ASSERT_TRUE(entry.GetStringValue("debug_data", &debug_data));
- EXPECT_EQ("foo", debug_data);
- }
+ int pos = ExpectLogContainsSomewhere(entries, 0,
+ NetLogEventType::HTTP2_SESSION_GOAWAY,
+ NetLogEventPhase::NONE);
+ TestNetLogEntry entry = entries[pos];
+ int last_accepted_stream_id;
+ ASSERT_TRUE(entry.GetIntegerValue("last_accepted_stream_id",
+ &last_accepted_stream_id));
+ EXPECT_EQ(42, last_accepted_stream_id);
+ int active_streams;
+ ASSERT_TRUE(entry.GetIntegerValue("active_streams", &active_streams));
+ EXPECT_EQ(0, active_streams);
+ int unclaimed_streams;
+ ASSERT_TRUE(entry.GetIntegerValue("unclaimed_streams", &unclaimed_streams));
+ EXPECT_EQ(0, unclaimed_streams);
+ int status;
+ ASSERT_TRUE(entry.GetIntegerValue("status", &status));
+ EXPECT_EQ(GOAWAY_ENHANCE_YOUR_CALM, status);
+ std::string debug_data;
+ ASSERT_TRUE(entry.GetStringValue("debug_data", &debug_data));
+ EXPECT_EQ("foo", debug_data);
// Check that we logged SPDY_SESSION_CLOSE correctly.
- int pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP2_SESSION_CLOSE, NetLog::PHASE_NONE);
- TestNetLogEntry entry = entries[pos];
+ pos = ExpectLogContainsSomewhere(
+ entries, 0, NetLogEventType::HTTP2_SESSION_CLOSE, NetLogEventPhase::NONE);
+ entry = entries[pos];
int error_code = 0;
ASSERT_TRUE(entry.GetNetErrorCode(&error_code));
- EXPECT_EQ(OK, error_code);
+ EXPECT_THAT(error_code, IsOk());
}
-TEST_P(SpdySessionTest, NetLogOnSessionEOF) {
+TEST_F(SpdySessionTest, NetLogOnSessionEOF) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {
@@ -1857,8 +1688,10 @@ TEST_P(SpdySessionTest, NetLogOnSessionEOF) {
StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
// Flush the read completion task.
@@ -1874,23 +1707,23 @@ TEST_P(SpdySessionTest, NetLogOnSessionEOF) {
// Check that we logged SPDY_SESSION_CLOSE correctly.
int pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP2_SESSION_CLOSE, NetLog::PHASE_NONE);
+ entries, 0, NetLogEventType::HTTP2_SESSION_CLOSE, NetLogEventPhase::NONE);
if (pos < static_cast<int>(entries.size())) {
TestNetLogEntry entry = entries[pos];
int error_code = 0;
ASSERT_TRUE(entry.GetNetErrorCode(&error_code));
- EXPECT_EQ(ERR_CONNECTION_CLOSED, error_code);
+ EXPECT_THAT(error_code, IsError(ERR_CONNECTION_CLOSED));
} else {
ADD_FAILURE();
}
}
-TEST_P(SpdySessionTest, SynCompressionHistograms) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdySessionTest, SynCompressionHistograms) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
+ CreateMockWrite(req, 0),
};
MockRead reads[] = {
MockRead(ASYNC, ERR_IO_PENDING, 1), MockRead(ASYNC, 0, 2) // EOF
@@ -1898,41 +1731,27 @@ TEST_P(SpdySessionTest, SynCompressionHistograms) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate(spdy_stream);
spdy_stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
// Write request headers & capture resulting histogram update.
base::HistogramTester histogram_tester;
base::RunLoop().RunUntilIdle();
// Regression test of compression performance under the request fixture.
- switch (spdy_util_.spdy_version()) {
- case SPDY3:
-#if defined(USE_SYSTEM_ZLIB)
- histogram_tester.ExpectBucketCount(
- "Net.SpdySynStreamCompressionPercentage", 30, 1);
-#else
- histogram_tester.ExpectBucketCount(
- "Net.SpdySynStreamCompressionPercentage", 31, 1);
-#endif
- break;
- case HTTP2:
histogram_tester.ExpectBucketCount(
"Net.SpdySynStreamCompressionPercentage", 81, 1);
- break;
- default:
- NOTREACHED();
- }
// Read and process EOF.
EXPECT_TRUE(session_);
@@ -1941,34 +1760,29 @@ TEST_P(SpdySessionTest, SynCompressionHistograms) {
EXPECT_FALSE(session_);
}
-// Queue up a low-priority SYN_STREAM followed by a high-priority
+// Queue up a low-priority HEADERS followed by a high-priority
// one. The high priority one should still send first and receive
// first.
-TEST_P(SpdySessionTest, OutOfOrderSynStreams) {
+TEST_F(SpdySessionTest, OutOfOrderHeaders) {
// Construct the request.
- std::unique_ptr<SpdySerializedFrame> req_highest(
+ SpdySerializedFrame req_highest(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST, true));
- std::unique_ptr<SpdySerializedFrame> req_lowest(
+ SpdySerializedFrame req_lowest(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*req_highest, 0),
- CreateMockWrite(*req_lowest, 1),
+ CreateMockWrite(req_highest, 0), CreateMockWrite(req_lowest, 1),
};
- std::unique_ptr<SpdySerializedFrame> resp_highest(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body_highest(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> resp_lowest(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 3));
- std::unique_ptr<SpdySerializedFrame> body_lowest(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
+ SpdySerializedFrame resp_highest(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame body_highest(spdy_util_.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame resp_lowest(
+ spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
+ SpdySerializedFrame body_lowest(spdy_util_.ConstructSpdyDataFrame(3, true));
MockRead reads[] = {
- CreateMockRead(*resp_highest, 2),
- CreateMockRead(*body_highest, 3),
- CreateMockRead(*resp_lowest, 4),
- CreateMockRead(*body_lowest, 5),
- MockRead(ASYNC, 0, 6) // EOF
+ CreateMockRead(resp_highest, 2), CreateMockRead(body_highest, 3),
+ CreateMockRead(resp_lowest, 4), CreateMockRead(body_lowest, 5),
+ MockRead(ASYNC, 0, 6) // EOF
};
session_deps_.host_resolver->set_synchronous_mode(true);
@@ -1976,11 +1790,14 @@ TEST_P(SpdySessionTest, OutOfOrderSynStreams) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream_lowest = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream_lowest =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, LOWEST, NetLogWithSource());
ASSERT_TRUE(spdy_stream_lowest);
EXPECT_EQ(0u, spdy_stream_lowest->stream_id());
test::StreamDelegateDoNothing delegate_lowest(spdy_stream_lowest);
@@ -1988,7 +1805,7 @@ TEST_P(SpdySessionTest, OutOfOrderSynStreams) {
base::WeakPtr<SpdyStream> spdy_stream_highest =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
- test_url_, HIGHEST, BoundNetLog());
+ test_url_, HIGHEST, NetLogWithSource());
ASSERT_TRUE(spdy_stream_highest);
EXPECT_EQ(0u, spdy_stream_highest->stream_id());
test::StreamDelegateDoNothing delegate_highest(spdy_stream_highest);
@@ -1996,17 +1813,15 @@ TEST_P(SpdySessionTest, OutOfOrderSynStreams) {
// Queue the lower priority one first.
- std::unique_ptr<SpdyHeaderBlock> headers_lowest(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers_lowest(
+ spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream_lowest->SendRequestHeaders(std::move(headers_lowest),
NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream_lowest->HasUrlFromHeaders());
- std::unique_ptr<SpdyHeaderBlock> headers_highest(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers_highest(
+ spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream_highest->SendRequestHeaders(std::move(headers_highest),
NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream_highest->HasUrlFromHeaders());
base::RunLoop().RunUntilIdle();
@@ -2016,24 +1831,20 @@ TEST_P(SpdySessionTest, OutOfOrderSynStreams) {
EXPECT_EQ(1u, delegate_highest.stream_id());
}
-TEST_P(SpdySessionTest, CancelStream) {
+TEST_F(SpdySessionTest, CancelStream) {
// Request 1, at HIGHEST priority, will be cancelled before it writes data.
// Request 2, at LOWEST priority, will be a full request and will be id 1.
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*req2, 0),
+ CreateMockWrite(req2, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- CreateMockRead(*resp2, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*body2, 3),
- MockRead(ASYNC, 0, 4) // EOF
+ CreateMockRead(resp2, 1), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(body2, 3), MockRead(ASYNC, 0, 4) // EOF
};
session_deps_.host_resolver->set_synchronous_mode(true);
@@ -2041,33 +1852,32 @@ TEST_P(SpdySessionTest, CancelStream) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
base::WeakPtr<SpdyStream> spdy_stream1 =
CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
- test_url_, HIGHEST, BoundNetLog());
+ test_url_, HIGHEST, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
EXPECT_EQ(0u, spdy_stream1->stream_id());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
- base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream2 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, LOWEST, NetLogWithSource());
ASSERT_TRUE(spdy_stream2);
EXPECT_EQ(0u, spdy_stream2->stream_id());
test::StreamDelegateDoNothing delegate2(spdy_stream2);
spdy_stream2->SetDelegate(&delegate2);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
- std::unique_ptr<SpdyHeaderBlock> headers2(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers2(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
EXPECT_EQ(0u, spdy_stream1->stream_id());
@@ -2088,7 +1898,7 @@ TEST_P(SpdySessionTest, CancelStream) {
// Create two streams that are set to re-close themselves on close,
// and then close the session. Nothing should blow up. Also a
// regression test for http://crbug.com/139518 .
-TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedSelfClosingStreams) {
+TEST_F(SpdySessionTest, CloseSessionWithTwoCreatedSelfClosingStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
@@ -2103,16 +1913,20 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedSelfClosingStreams) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, HIGHEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ HIGHEST, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
EXPECT_EQ(0u, spdy_stream1->stream_id());
- base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream2 =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ LOWEST, NetLogWithSource());
ASSERT_TRUE(spdy_stream2);
EXPECT_EQ(0u, spdy_stream2->stream_id());
@@ -2122,15 +1936,11 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedSelfClosingStreams) {
test::ClosingDelegate delegate2(spdy_stream2);
spdy_stream2->SetDelegate(&delegate2);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
- std::unique_ptr<SpdyHeaderBlock> headers2(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers2(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
// Ensure that the streams have not yet been activated and assigned an id.
EXPECT_EQ(0u, spdy_stream1->stream_id());
@@ -2151,22 +1961,26 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedSelfClosingStreams) {
// Create two streams that are set to close each other on close, and
// then close the session. Nothing should blow up.
-TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedMutuallyClosingStreams) {
+TEST_F(SpdySessionTest, CloseSessionWithTwoCreatedMutuallyClosingStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
SequencedSocketData data(nullptr, 0, nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, HIGHEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ HIGHEST, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
EXPECT_EQ(0u, spdy_stream1->stream_id());
- base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream2 =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ LOWEST, NetLogWithSource());
ASSERT_TRUE(spdy_stream2);
EXPECT_EQ(0u, spdy_stream2->stream_id());
@@ -2178,15 +1992,11 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedMutuallyClosingStreams) {
test::ClosingDelegate delegate2(spdy_stream1);
spdy_stream2->SetDelegate(&delegate2);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
- std::unique_ptr<SpdyHeaderBlock> headers2(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers2(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
// Ensure that the streams have not yet been activated and assigned an id.
EXPECT_EQ(0u, spdy_stream1->stream_id());
@@ -2207,16 +2017,15 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedMutuallyClosingStreams) {
// Create two streams that are set to re-close themselves on close,
// activate them, and then close the session. Nothing should blow up.
-TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedSelfClosingStreams) {
+TEST_F(SpdySessionTest, CloseSessionWithTwoActivatedSelfClosingStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
- CreateMockWrite(*req2, 1),
+ CreateMockWrite(req1, 0), CreateMockWrite(req2, 1),
};
MockRead reads[] = {
@@ -2226,16 +2035,20 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedSelfClosingStreams) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
EXPECT_EQ(0u, spdy_stream1->stream_id());
- base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream2 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream2);
EXPECT_EQ(0u, spdy_stream2->stream_id());
@@ -2245,15 +2058,11 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedSelfClosingStreams) {
test::ClosingDelegate delegate2(spdy_stream2);
spdy_stream2->SetDelegate(&delegate2);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
- std::unique_ptr<SpdyHeaderBlock> headers2(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers2(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
// Ensure that the streams have not yet been activated and assigned an id.
EXPECT_EQ(0u, spdy_stream1->stream_id());
@@ -2281,16 +2090,15 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedSelfClosingStreams) {
// Create two streams that are set to close each other on close,
// activate them, and then close the session. Nothing should blow up.
-TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedMutuallyClosingStreams) {
+TEST_F(SpdySessionTest, CloseSessionWithTwoActivatedMutuallyClosingStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
- CreateMockWrite(*req2, 1),
+ CreateMockWrite(req1, 0), CreateMockWrite(req2, 1),
};
MockRead reads[] = {
@@ -2300,16 +2108,20 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedMutuallyClosingStreams) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
EXPECT_EQ(0u, spdy_stream1->stream_id());
- base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream2 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream2);
EXPECT_EQ(0u, spdy_stream2->stream_id());
@@ -2321,15 +2133,11 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedMutuallyClosingStreams) {
test::ClosingDelegate delegate2(spdy_stream1);
spdy_stream2->SetDelegate(&delegate2);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
- std::unique_ptr<SpdyHeaderBlock> headers2(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers2(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
// Ensure that the streams have not yet been activated and assigned an id.
EXPECT_EQ(0u, spdy_stream1->stream_id());
@@ -2375,21 +2183,20 @@ class SessionClosingDelegate : public test::StreamDelegateDoNothing {
// Close an activated stream that closes its session. Nothing should
// blow up. This is a regression test for https://crbug.com/263691.
-TEST_P(SpdySessionTest, CloseActivatedStreamThatClosesSession) {
+TEST_F(SpdySessionTest, CloseActivatedStreamThatClosesSession) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
- std::unique_ptr<SpdySerializedFrame> goaway(
+ SpdySerializedFrame goaway(
spdy_util_.ConstructSpdyGoAway(0, GOAWAY_PROTOCOL_ERROR, "Error"));
// The GOAWAY has higher-priority than the RST_STREAM, and is written first
// despite being queued second.
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
- CreateMockWrite(*goaway, 1),
- CreateMockWrite(*rst, 3),
+ CreateMockWrite(req, 0), CreateMockWrite(goaway, 1),
+ CreateMockWrite(rst, 3),
};
MockRead reads[] = {
@@ -2398,21 +2205,22 @@ TEST_P(SpdySessionTest, CloseActivatedStreamThatClosesSession) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream);
EXPECT_EQ(0u, spdy_stream->stream_id());
SessionClosingDelegate delegate(spdy_stream, session_);
spdy_stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
EXPECT_EQ(0u, spdy_stream->stream_id());
@@ -2433,24 +2241,13 @@ TEST_P(SpdySessionTest, CloseActivatedStreamThatClosesSession) {
EXPECT_TRUE(data.AllReadDataConsumed());
}
-TEST_P(SpdySessionTest, VerifyDomainAuthentication) {
+TEST_F(SpdySessionTest, VerifyDomainAuthentication) {
session_deps_.host_resolver->set_synchronous_mode(true);
SequencedSocketData data(nullptr, 0, nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
- // Load a cert that is valid for:
- // www.example.org
- // mail.example.org
- // mail.example.com
- base::FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> test_cert(
- ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
- ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
-
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- ssl.cert = test_cert;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+ AddSSLSocketData();
CreateNetworkSession();
CreateSecureSpdySession();
@@ -2461,25 +2258,14 @@ TEST_P(SpdySessionTest, VerifyDomainAuthentication) {
EXPECT_FALSE(session_->VerifyDomainAuthentication("mail.google.com"));
}
-TEST_P(SpdySessionTest, ConnectionPooledWithTlsChannelId) {
+TEST_F(SpdySessionTest, ConnectionPooledWithTlsChannelId) {
session_deps_.host_resolver->set_synchronous_mode(true);
SequencedSocketData data(nullptr, 0, nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
- // Load a cert that is valid for:
- // www.example.org
- // mail.example.org
- // mail.example.com
- base::FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> test_cert(
- ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
- ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
-
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- ssl.channel_id_sent = true;
- ssl.cert = test_cert;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+ ssl_.channel_id_sent = true;
+ AddSSLSocketData();
CreateNetworkSession();
CreateSecureSpdySession();
@@ -2490,7 +2276,7 @@ TEST_P(SpdySessionTest, ConnectionPooledWithTlsChannelId) {
EXPECT_FALSE(session_->VerifyDomainAuthentication("mail.google.com"));
}
-TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) {
+TEST_F(SpdySessionTest, CloseTwoStalledCreateStream) {
// TODO(rtenneti): Define a helper class/methods and move the common code in
// this file.
SettingsMap new_settings;
@@ -2499,51 +2285,42 @@ TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) {
new_settings[kSpdySettingsIds1] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
- std::unique_ptr<SpdySerializedFrame> settings_ack(
- spdy_util_.ConstructSpdySettingsAck());
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
spdy_util_.UpdateWithStreamDestruction(1);
- std::unique_ptr<SpdySerializedFrame> req2(
+ SpdySerializedFrame req2(
spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST, true));
spdy_util_.UpdateWithStreamDestruction(3);
- std::unique_ptr<SpdySerializedFrame> req3(
+ SpdySerializedFrame req3(
spdy_util_.ConstructSpdyGet(nullptr, 0, 5, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*settings_ack, 1),
- CreateMockWrite(*req1, 2),
- CreateMockWrite(*req2, 5),
- CreateMockWrite(*req3, 8),
+ CreateMockWrite(settings_ack, 1), CreateMockWrite(req1, 2),
+ CreateMockWrite(req2, 5), CreateMockWrite(req3, 8),
};
// Set up the socket so we read a SETTINGS frame that sets max concurrent
// streams to 1.
- std::unique_ptr<SpdySerializedFrame> settings_frame(
+ SpdySerializedFrame settings_frame(
spdy_util_.ConstructSpdySettings(new_settings));
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body1(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 3));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(3, true));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
+ SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
- std::unique_ptr<SpdySerializedFrame> resp3(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 5));
- std::unique_ptr<SpdySerializedFrame> body3(
- spdy_util_.ConstructSpdyBodyFrame(5, true));
+ SpdySerializedFrame resp3(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
+ SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, true));
MockRead reads[] = {
- CreateMockRead(*settings_frame, 0),
- CreateMockRead(*resp1, 3),
- CreateMockRead(*body1, 4),
- CreateMockRead(*resp2, 6),
- CreateMockRead(*body2, 7),
- CreateMockRead(*resp3, 9),
- CreateMockRead(*body3, 10),
+ CreateMockRead(settings_frame, 0),
+ CreateMockRead(resp1, 3),
+ CreateMockRead(body1, 4),
+ CreateMockRead(resp2, 6),
+ CreateMockRead(body2, 7),
+ CreateMockRead(resp3, 9),
+ CreateMockRead(body3, 10),
MockRead(ASYNC, ERR_IO_PENDING, 11),
MockRead(ASYNC, 0, 12) // EOF
};
@@ -2551,14 +2328,17 @@ TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
// Read the settings frame.
base::RunLoop().RunUntilIdle();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ 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);
@@ -2569,23 +2349,21 @@ TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) {
ASSERT_EQ(
ERR_IO_PENDING,
request2.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_,
- LOWEST, BoundNetLog(), callback2.callback()));
+ LOWEST, NetLogWithSource(), callback2.callback()));
TestCompletionCallback callback3;
SpdyStreamRequest request3;
ASSERT_EQ(
ERR_IO_PENDING,
request3.StartRequest(SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_,
- LOWEST, BoundNetLog(), callback3.callback()));
+ 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));
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
// Run until 1st stream is activated and then closed.
EXPECT_EQ(0u, delegate1.stream_id());
@@ -2607,10 +2385,8 @@ TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) {
base::WeakPtr<SpdyStream> stream2 = request2.ReleaseStream();
test::StreamDelegateDoNothing delegate2(stream2);
stream2->SetDelegate(&delegate2);
- std::unique_ptr<SpdyHeaderBlock> headers2(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers2(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
stream2->SendRequestHeaders(std::move(headers2), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(stream2->HasUrlFromHeaders());
// Run until 2nd stream is activated and then closed.
EXPECT_EQ(0u, delegate2.stream_id());
@@ -2632,10 +2408,8 @@ TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) {
base::WeakPtr<SpdyStream> stream3 = request3.ReleaseStream();
test::StreamDelegateDoNothing delegate3(stream3);
stream3->SetDelegate(&delegate3);
- std::unique_ptr<SpdyHeaderBlock> headers3(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers3(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
stream3->SendRequestHeaders(std::move(headers3), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(stream3->HasUrlFromHeaders());
// Run until 2nd stream is activated and then closed.
EXPECT_EQ(0u, delegate3.stream_id());
@@ -2651,7 +2425,7 @@ TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) {
base::RunLoop().RunUntilIdle();
}
-TEST_P(SpdySessionTest, CancelTwoStalledCreateStream) {
+TEST_F(SpdySessionTest, CancelTwoStalledCreateStream) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {
@@ -2661,32 +2435,38 @@ TEST_P(SpdySessionTest, CancelTwoStalledCreateStream) {
StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
// Leave room for only one more stream to be created.
for (size_t i = 0; i < kInitialMaxConcurrentStreams - 1; ++i) {
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream);
}
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ LOWEST, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
EXPECT_EQ(0u, spdy_stream1->stream_id());
TestCompletionCallback callback2;
SpdyStreamRequest request2;
- ASSERT_EQ(ERR_IO_PENDING, request2.StartRequest(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
- LOWEST, BoundNetLog(), callback2.callback()));
+ ASSERT_EQ(
+ ERR_IO_PENDING,
+ request2.StartRequest(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ LOWEST, NetLogWithSource(), callback2.callback()));
TestCompletionCallback callback3;
SpdyStreamRequest request3;
- ASSERT_EQ(ERR_IO_PENDING, request3.StartRequest(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
- LOWEST, BoundNetLog(), callback3.callback()));
+ ASSERT_EQ(
+ ERR_IO_PENDING,
+ 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());
@@ -2697,7 +2477,7 @@ TEST_P(SpdySessionTest, CancelTwoStalledCreateStream) {
spdy_stream1->Cancel();
EXPECT_FALSE(spdy_stream1);
- EXPECT_EQ(OK, callback2.WaitForResult());
+ 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));
@@ -2707,7 +2487,7 @@ TEST_P(SpdySessionTest, CancelTwoStalledCreateStream) {
spdy_stream2->Cancel();
EXPECT_FALSE(spdy_stream2);
- EXPECT_EQ(OK, callback3.WaitForResult());
+ 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));
@@ -2725,45 +2505,44 @@ TEST_P(SpdySessionTest, CancelTwoStalledCreateStream) {
// without yielding. This test makes 32k - 1 bytes of data available
// on the socket for reading. It then verifies that it has read all
// the available data without yielding.
-TEST_P(SpdySessionTest, ReadDataWithoutYielding) {
+TEST_F(SpdySessionTest, ReadDataWithoutYielding) {
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.time_func = InstantaneousReads;
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
+ BufferedSpdyFramer framer;
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
+ CreateMockWrite(req1, 0),
};
// Build buffer of size kYieldAfterBytesRead / 4
// (-spdy_data_frame_size).
ASSERT_EQ(32 * 1024, kYieldAfterBytesRead);
const int kPayloadSize =
- kYieldAfterBytesRead / 4 - framer.GetControlFrameHeaderSize();
+ kYieldAfterBytesRead / 4 - framer.GetFrameHeaderSize();
TestDataStream test_stream;
scoped_refptr<IOBuffer> payload(new IOBuffer(kPayloadSize));
char* payload_data = payload->data();
test_stream.GetBytes(payload_data, kPayloadSize);
- std::unique_ptr<SpdySerializedFrame> partial_data_frame(
- framer.CreateDataFrame(1, payload_data, kPayloadSize, DATA_FLAG_NONE));
- std::unique_ptr<SpdySerializedFrame> finish_data_frame(
- framer.CreateDataFrame(1, payload_data, kPayloadSize - 1, DATA_FLAG_FIN));
+ SpdySerializedFrame partial_data_frame(spdy_util_.ConstructSpdyDataFrame(
+ 1, payload_data, kPayloadSize, /*fin=*/false));
+ SpdySerializedFrame finish_data_frame(spdy_util_.ConstructSpdyDataFrame(
+ 1, payload_data, kPayloadSize - 1, /*fin=*/true));
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
// Write 1 byte less than kMaxReadBytes to check that DoRead reads up to 32k
// bytes.
MockRead reads[] = {
- CreateMockRead(*resp1, 1),
+ CreateMockRead(resp1, 1),
MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*partial_data_frame, 3),
- CreateMockRead(*partial_data_frame, 4, SYNCHRONOUS),
- CreateMockRead(*partial_data_frame, 5, SYNCHRONOUS),
- CreateMockRead(*finish_data_frame, 6, SYNCHRONOUS),
+ CreateMockRead(partial_data_frame, 3),
+ CreateMockRead(partial_data_frame, 4, SYNCHRONOUS),
+ CreateMockRead(partial_data_frame, 5, SYNCHRONOUS),
+ CreateMockRead(finish_data_frame, 6, SYNCHRONOUS),
MockRead(ASYNC, 0, 7) // EOF
};
@@ -2771,20 +2550,21 @@ TEST_P(SpdySessionTest, ReadDataWithoutYielding) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
EXPECT_EQ(0u, spdy_stream1->stream_id());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
- std::unique_ptr<SpdyHeaderBlock> headers1(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers1), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
// Set up the TaskObserver to verify SpdySession::DoReadLoop doesn't
// post a task.
@@ -2812,43 +2592,41 @@ TEST_P(SpdySessionTest, ReadDataWithoutYielding) {
// Test that SpdySession::DoReadLoop yields if more than
// |kYieldAfterDurationMilliseconds| has passed. This test uses a mock time
// function that makes the response frame look very slow to read.
-TEST_P(SpdySessionTest, TestYieldingSlowReads) {
+TEST_F(SpdySessionTest, TestYieldingSlowReads) {
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.time_func = SlowReads;
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
-
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
+ CreateMockWrite(req1, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp1, 1), MockRead(ASYNC, 0, 2) // EOF
+ CreateMockRead(resp1, 1), MockRead(ASYNC, 0, 2) // EOF
};
// Create SpdySession and SpdyStream and send the request.
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
EXPECT_EQ(0u, spdy_stream1->stream_id());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
- std::unique_ptr<SpdyHeaderBlock> headers1(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers1), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
// Set up the TaskObserver to verify that SpdySession::DoReadLoop posts a
// task.
@@ -2873,32 +2651,30 @@ TEST_P(SpdySessionTest, TestYieldingSlowReads) {
// Regression test for https://crbug.com/531570.
// Test the case where DoRead() takes long but returns synchronously.
-TEST_P(SpdySessionTest, TestYieldingSlowSynchronousReads) {
+TEST_F(SpdySessionTest, TestYieldingSlowSynchronousReads) {
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.time_func = SlowReads;
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
-
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
+ CreateMockWrite(req1, 0),
};
- std::unique_ptr<SpdySerializedFrame> partial_data_frame(
- framer.CreateDataFrame(1, "foo ", 4, DATA_FLAG_NONE));
- std::unique_ptr<SpdySerializedFrame> finish_data_frame(
- framer.CreateDataFrame(1, "bar", 3, DATA_FLAG_FIN));
+ SpdySerializedFrame partial_data_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, "foo ", 4, /*fin=*/false));
+ SpdySerializedFrame finish_data_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, "bar", 3, /*fin=*/true));
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp1, 1), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*partial_data_frame, 3, ASYNC),
- CreateMockRead(*partial_data_frame, 4, SYNCHRONOUS),
- CreateMockRead(*partial_data_frame, 5, SYNCHRONOUS),
- CreateMockRead(*finish_data_frame, 6, SYNCHRONOUS),
+ CreateMockRead(resp1, 1),
+ MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(partial_data_frame, 3, ASYNC),
+ CreateMockRead(partial_data_frame, 4, SYNCHRONOUS),
+ CreateMockRead(partial_data_frame, 5, SYNCHRONOUS),
+ CreateMockRead(finish_data_frame, 6, SYNCHRONOUS),
MockRead(ASYNC, 0, 7) // EOF
};
@@ -2906,20 +2682,21 @@ TEST_P(SpdySessionTest, TestYieldingSlowSynchronousReads) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
EXPECT_EQ(0u, spdy_stream1->stream_id());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
- std::unique_ptr<SpdyHeaderBlock> headers1(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers1), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
// Run until 1st read.
EXPECT_EQ(0u, delegate1.stream_id());
@@ -2941,45 +2718,44 @@ TEST_P(SpdySessionTest, TestYieldingSlowSynchronousReads) {
// for reading. It then verifies that DoRead has yielded even though
// there is data available for it to read (i.e, socket()->Read didn't
// return ERR_IO_PENDING during socket reads).
-TEST_P(SpdySessionTest, TestYieldingDuringReadData) {
+TEST_F(SpdySessionTest, TestYieldingDuringReadData) {
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.time_func = InstantaneousReads;
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
+ BufferedSpdyFramer framer;
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
+ CreateMockWrite(req1, 0),
};
// Build buffer of size kYieldAfterBytesRead / 4
// (-spdy_data_frame_size).
ASSERT_EQ(32 * 1024, kYieldAfterBytesRead);
const int kPayloadSize =
- kYieldAfterBytesRead / 4 - framer.GetControlFrameHeaderSize();
+ kYieldAfterBytesRead / 4 - framer.GetFrameHeaderSize();
TestDataStream test_stream;
scoped_refptr<IOBuffer> payload(new IOBuffer(kPayloadSize));
char* payload_data = payload->data();
test_stream.GetBytes(payload_data, kPayloadSize);
- std::unique_ptr<SpdySerializedFrame> partial_data_frame(
- framer.CreateDataFrame(1, payload_data, kPayloadSize, DATA_FLAG_NONE));
- std::unique_ptr<SpdySerializedFrame> finish_data_frame(
- framer.CreateDataFrame(1, "h", 1, DATA_FLAG_FIN));
+ SpdySerializedFrame partial_data_frame(spdy_util_.ConstructSpdyDataFrame(
+ 1, payload_data, kPayloadSize, /*fin=*/false));
+ SpdySerializedFrame finish_data_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, "h", 1, /*fin=*/true));
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
// Write 1 byte more than kMaxReadBytes to check that DoRead yields.
MockRead reads[] = {
- CreateMockRead(*resp1, 1),
+ CreateMockRead(resp1, 1),
MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*partial_data_frame, 3),
- CreateMockRead(*partial_data_frame, 4, SYNCHRONOUS),
- CreateMockRead(*partial_data_frame, 5, SYNCHRONOUS),
- CreateMockRead(*partial_data_frame, 6, SYNCHRONOUS),
- CreateMockRead(*finish_data_frame, 7, SYNCHRONOUS),
+ CreateMockRead(partial_data_frame, 3),
+ CreateMockRead(partial_data_frame, 4, SYNCHRONOUS),
+ CreateMockRead(partial_data_frame, 5, SYNCHRONOUS),
+ CreateMockRead(partial_data_frame, 6, SYNCHRONOUS),
+ CreateMockRead(finish_data_frame, 7, SYNCHRONOUS),
MockRead(ASYNC, 0, 8) // EOF
};
@@ -2987,20 +2763,21 @@ TEST_P(SpdySessionTest, TestYieldingDuringReadData) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
EXPECT_EQ(0u, spdy_stream1->stream_id());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
- std::unique_ptr<SpdyHeaderBlock> headers1(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers1), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
// Set up the TaskObserver to verify SpdySession::DoReadLoop posts a task.
SpdySessionTestTaskObserver observer("spdy_session.cc", "DoReadLoop");
@@ -3035,16 +2812,16 @@ TEST_P(SpdySessionTest, TestYieldingDuringReadData) {
// ERR_IO_PENDING (because of async read), so DoReadLoop() will
// yield. When we come back, DoRead() will read the results from the
// async read, and rest of the data synchronously.
-TEST_P(SpdySessionTest, TestYieldingDuringAsyncReadData) {
+TEST_F(SpdySessionTest, TestYieldingDuringAsyncReadData) {
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.time_func = InstantaneousReads;
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
+ BufferedSpdyFramer framer;
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
+ CreateMockWrite(req1, 0),
};
// Build buffer of size kYieldAfterBytesRead / 4
@@ -3052,7 +2829,7 @@ TEST_P(SpdySessionTest, TestYieldingDuringAsyncReadData) {
ASSERT_EQ(32 * 1024, kYieldAfterBytesRead);
TestDataStream test_stream;
const int kEightKPayloadSize =
- kYieldAfterBytesRead / 4 - framer.GetControlFrameHeaderSize();
+ kYieldAfterBytesRead / 4 - framer.GetFrameHeaderSize();
scoped_refptr<IOBuffer> eightk_payload(new IOBuffer(kEightKPayloadSize));
char* eightk_payload_data = eightk_payload->data();
test_stream.GetBytes(eightk_payload_data, kEightKPayloadSize);
@@ -3064,29 +2841,28 @@ TEST_P(SpdySessionTest, TestYieldingDuringAsyncReadData) {
char* twok_payload_data = twok_payload->data();
test_stream2.GetBytes(twok_payload_data, kTwoKPayloadSize);
- std::unique_ptr<SpdySerializedFrame> eightk_data_frame(framer.CreateDataFrame(
- 1, eightk_payload_data, kEightKPayloadSize, DATA_FLAG_NONE));
- std::unique_ptr<SpdySerializedFrame> twok_data_frame(framer.CreateDataFrame(
- 1, twok_payload_data, kTwoKPayloadSize, DATA_FLAG_NONE));
- std::unique_ptr<SpdySerializedFrame> finish_data_frame(
- framer.CreateDataFrame(1, "h", 1, DATA_FLAG_FIN));
+ SpdySerializedFrame eightk_data_frame(spdy_util_.ConstructSpdyDataFrame(
+ 1, eightk_payload_data, kEightKPayloadSize, /*fin=*/false));
+ SpdySerializedFrame twok_data_frame(spdy_util_.ConstructSpdyDataFrame(
+ 1, twok_payload_data, kTwoKPayloadSize, /*fin=*/false));
+ SpdySerializedFrame finish_data_frame(
+ spdy_util_.ConstructSpdyDataFrame(1, "h", 1, /*fin=*/true));
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp1, 1),
+ CreateMockRead(resp1, 1),
MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*eightk_data_frame, 3),
- CreateMockRead(*eightk_data_frame, 4, SYNCHRONOUS),
- CreateMockRead(*eightk_data_frame, 5, SYNCHRONOUS),
- CreateMockRead(*twok_data_frame, 6, SYNCHRONOUS),
- CreateMockRead(*eightk_data_frame, 7, ASYNC),
- CreateMockRead(*eightk_data_frame, 8, SYNCHRONOUS),
- CreateMockRead(*eightk_data_frame, 9, SYNCHRONOUS),
- CreateMockRead(*eightk_data_frame, 10, SYNCHRONOUS),
- CreateMockRead(*twok_data_frame, 11, SYNCHRONOUS),
- CreateMockRead(*finish_data_frame, 12, SYNCHRONOUS),
+ CreateMockRead(eightk_data_frame, 3),
+ CreateMockRead(eightk_data_frame, 4, SYNCHRONOUS),
+ CreateMockRead(eightk_data_frame, 5, SYNCHRONOUS),
+ CreateMockRead(twok_data_frame, 6, SYNCHRONOUS),
+ CreateMockRead(eightk_data_frame, 7, ASYNC),
+ CreateMockRead(eightk_data_frame, 8, SYNCHRONOUS),
+ CreateMockRead(eightk_data_frame, 9, SYNCHRONOUS),
+ CreateMockRead(eightk_data_frame, 10, SYNCHRONOUS),
+ CreateMockRead(twok_data_frame, 11, SYNCHRONOUS),
+ CreateMockRead(finish_data_frame, 12, SYNCHRONOUS),
MockRead(ASYNC, 0, 13) // EOF
};
@@ -3094,20 +2870,21 @@ TEST_P(SpdySessionTest, TestYieldingDuringAsyncReadData) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
EXPECT_EQ(0u, spdy_stream1->stream_id());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
- std::unique_ptr<SpdyHeaderBlock> headers1(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers1), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
// Set up the TaskObserver to monitor SpdySession::DoReadLoop
// posting of tasks.
@@ -3135,48 +2912,43 @@ TEST_P(SpdySessionTest, TestYieldingDuringAsyncReadData) {
// Send a GoAway frame when SpdySession is in DoReadLoop. Make sure
// nothing blows up.
-TEST_P(SpdySessionTest, GoAwayWhileInDoReadLoop) {
+TEST_F(SpdySessionTest, GoAwayWhileInDoReadLoop) {
session_deps_.host_resolver->set_synchronous_mode(true);
- BufferedSpdyFramer framer(spdy_util_.spdy_version());
-
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
+ CreateMockWrite(req1, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body1(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
- std::unique_ptr<SpdySerializedFrame> goaway(spdy_util_.ConstructSpdyGoAway());
+ SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway());
MockRead reads[] = {
- CreateMockRead(*resp1, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*body1, 3),
- CreateMockRead(*goaway, 4),
+ CreateMockRead(resp1, 1), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(body1, 3), CreateMockRead(goaway, 4),
};
// Create SpdySession and SpdyStream and send the request.
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
ASSERT_TRUE(spdy_stream1);
EXPECT_EQ(0u, spdy_stream1->stream_id());
- std::unique_ptr<SpdyHeaderBlock> headers1(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers1), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
// Run until 1st read.
EXPECT_EQ(0u, spdy_stream1->stream_id());
@@ -3196,7 +2968,7 @@ TEST_P(SpdySessionTest, GoAwayWhileInDoReadLoop) {
// flow control disabled for protocol version 2, with flow control
// enabled only for streams for protocol version 3, and with flow
// control enabled for streams and sessions for higher versions.
-TEST_P(SpdySessionTest, ProtocolNegotiation) {
+TEST_F(SpdySessionTest, ProtocolNegotiation) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {
@@ -3208,18 +2980,14 @@ TEST_P(SpdySessionTest, ProtocolNegotiation) {
CreateNetworkSession();
session_ = CreateFakeSpdySession(spdy_session_pool_, key_);
- EXPECT_EQ(spdy_util_.spdy_version(),
- session_->buffered_spdy_framer_->protocol_version());
- EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetProtocol()),
- session_->session_send_window_size_);
- EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetProtocol()),
- session_->session_recv_window_size_);
+ 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_);
}
// Tests the case of a non-SPDY request closing an idle SPDY session when no
// pointers to the idle session are currently held.
-TEST_P(SpdySessionTest, CloseOneIdleConnection) {
+TEST_F(SpdySessionTest, CloseOneIdleConnection) {
ClientSocketPoolManager::set_max_sockets_per_group(
HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
ClientSocketPoolManager::set_max_sockets_per_pool(
@@ -3232,6 +3000,8 @@ TEST_P(SpdySessionTest, CloseOneIdleConnection) {
session_deps_.socket_factory->AddSocketDataProvider(&data);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
TransportClientSocketPool* pool =
@@ -3239,7 +3009,7 @@ TEST_P(SpdySessionTest, CloseOneIdleConnection) {
HttpNetworkSession::NORMAL_SOCKET_POOL);
// Create an idle SPDY session.
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
EXPECT_FALSE(pool->IsStalled());
// Trying to create a new connection should cause the pool to be stalled, and
@@ -3253,12 +3023,12 @@ TEST_P(SpdySessionTest, CloseOneIdleConnection) {
EXPECT_EQ(ERR_IO_PENDING,
connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool, BoundNetLog()));
+ callback2.callback(), pool, NetLogWithSource()));
EXPECT_TRUE(pool->IsStalled());
// The socket pool should close the connection asynchronously and establish a
// new connection.
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_FALSE(pool->IsStalled());
EXPECT_FALSE(session_);
}
@@ -3266,7 +3036,7 @@ TEST_P(SpdySessionTest, CloseOneIdleConnection) {
// Tests the case of a non-SPDY request closing an idle SPDY session when no
// pointers to the idle session are currently held, in the case the SPDY session
// has an alias.
-TEST_P(SpdySessionTest, CloseOneIdleConnectionWithAlias) {
+TEST_F(SpdySessionTest, CloseOneIdleConnectionWithAlias) {
ClientSocketPoolManager::set_max_sockets_per_group(
HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
ClientSocketPoolManager::set_max_sockets_per_pool(
@@ -3279,11 +3049,13 @@ TEST_P(SpdySessionTest, CloseOneIdleConnectionWithAlias) {
session_deps_.socket_factory->AddSocketDataProvider(&data);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.host_resolver->rules()->AddIPLiteralRule(
- "1.com", "192.168.0.2", std::string());
+ "www.example.org", "192.168.0.2", std::string());
session_deps_.host_resolver->rules()->AddIPLiteralRule(
- "2.com", "192.168.0.2", std::string());
+ "mail.example.org", "192.168.0.2", std::string());
// Not strictly needed.
session_deps_.host_resolver->rules()->AddIPLiteralRule(
"3.com", "192.168.0.3", std::string());
@@ -3295,25 +3067,27 @@ TEST_P(SpdySessionTest, CloseOneIdleConnectionWithAlias) {
HttpNetworkSession::NORMAL_SOCKET_POOL);
// Create an idle SPDY session.
- SpdySessionKey key1(HostPortPair("1.com", 80), ProxyServer::Direct(),
- PRIVACY_MODE_DISABLED);
- base::WeakPtr<SpdySession> session1 = ::net::CreateInsecureSpdySession(
- http_session_.get(), key1, BoundNetLog());
+ SpdySessionKey key1(HostPortPair("www.example.org", 80),
+ ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
+ base::WeakPtr<SpdySession> session1 = ::net::CreateSecureSpdySession(
+ http_session_.get(), key1, NetLogWithSource());
EXPECT_FALSE(pool->IsStalled());
// Set up an alias for the idle SPDY session, increasing its ref count to 2.
- SpdySessionKey key2(HostPortPair("2.com", 80), ProxyServer::Direct(),
- PRIVACY_MODE_DISABLED);
+ SpdySessionKey key2(HostPortPair("mail.example.org", 80),
+ ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
HostResolver::RequestInfo info(key2.host_port_pair());
AddressList addresses;
+ std::unique_ptr<HostResolver::Request> request;
// Pre-populate the DNS cache, since a synchronous resolution is required in
// order to create the alias.
session_deps_.host_resolver->Resolve(info, DEFAULT_PRIORITY, &addresses,
- CompletionCallback(), nullptr,
- BoundNetLog());
+ CompletionCallback(), &request,
+ NetLogWithSource());
// Get a session for |key2|, which should return the session created earlier.
base::WeakPtr<SpdySession> session2 =
- spdy_session_pool_->FindAvailableSession(key2, GURL(), BoundNetLog());
+ spdy_session_pool_->FindAvailableSession(key2, GURL(),
+ NetLogWithSource());
ASSERT_EQ(session1.get(), session2.get());
EXPECT_FALSE(pool->IsStalled());
@@ -3328,12 +3102,12 @@ TEST_P(SpdySessionTest, CloseOneIdleConnectionWithAlias) {
EXPECT_EQ(ERR_IO_PENDING,
connection3->Init(host_port3.ToString(), params3, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback3.callback(), pool, BoundNetLog()));
+ callback3.callback(), pool, NetLogWithSource()));
EXPECT_TRUE(pool->IsStalled());
// The socket pool should close the connection asynchronously and establish a
// new connection.
- EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_THAT(callback3.WaitForResult(), IsOk());
EXPECT_FALSE(pool->IsStalled());
EXPECT_FALSE(session1);
EXPECT_FALSE(session2);
@@ -3341,7 +3115,7 @@ TEST_P(SpdySessionTest, CloseOneIdleConnectionWithAlias) {
// Tests that when a SPDY session becomes idle, it closes itself if there is
// a lower layer pool stalled on the per-pool socket limit.
-TEST_P(SpdySessionTest, CloseSessionOnIdleWhenPoolStalled) {
+TEST_F(SpdySessionTest, CloseSessionOnIdleWhenPoolStalled) {
ClientSocketPoolManager::set_max_sockets_per_group(
HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
ClientSocketPoolManager::set_max_sockets_per_pool(
@@ -3350,13 +3124,12 @@ TEST_P(SpdySessionTest, CloseSessionOnIdleWhenPoolStalled) {
MockRead reads[] = {
MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
};
- std::unique_ptr<SpdySerializedFrame> req1(
+ SpdySerializedFrame req1(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> cancel1(
+ SpdySerializedFrame cancel1(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*req1, 1),
- CreateMockWrite(*cancel1, 1),
+ CreateMockWrite(req1, 1), CreateMockWrite(cancel1, 1),
};
StaticSocketDataProvider data(reads, arraysize(reads),
writes, arraysize(writes));
@@ -3369,6 +3142,7 @@ TEST_P(SpdySessionTest, CloseSessionOnIdleWhenPoolStalled) {
0);
session_deps_.socket_factory->AddSocketDataProvider(&http_data);
+ AddSSLSocketData();
CreateNetworkSession();
@@ -3377,24 +3151,22 @@ TEST_P(SpdySessionTest, CloseSessionOnIdleWhenPoolStalled) {
HttpNetworkSession::NORMAL_SOCKET_POOL);
// Create a SPDY session.
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
EXPECT_FALSE(pool->IsStalled());
// Create a stream using the session, and send a request.
TestCompletionCallback callback1;
- base::WeakPtr<SpdyStream> spdy_stream1 =
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
- test_url_, DEFAULT_PRIORITY, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
+ SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, DEFAULT_PRIORITY,
+ NetLogWithSource());
ASSERT_TRUE(spdy_stream1.get());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
- std::unique_ptr<SpdyHeaderBlock> headers1(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers1(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
EXPECT_EQ(ERR_IO_PENDING, spdy_stream1->SendRequestHeaders(
std::move(headers1), NO_MORE_DATA_TO_SEND));
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
base::RunLoop().RunUntilIdle();
@@ -3409,7 +3181,7 @@ TEST_P(SpdySessionTest, CloseSessionOnIdleWhenPoolStalled) {
EXPECT_EQ(ERR_IO_PENDING,
connection2->Init(host_port2.ToString(), params2, DEFAULT_PRIORITY,
ClientSocketPool::RespectLimits::ENABLED,
- callback2.callback(), pool, BoundNetLog()));
+ callback2.callback(), pool, NetLogWithSource()));
EXPECT_TRUE(pool->IsStalled());
// Running the message loop should cause the socket pool to ask the SPDY
@@ -3425,12 +3197,12 @@ TEST_P(SpdySessionTest, CloseSessionOnIdleWhenPoolStalled) {
spdy_stream1->Cancel();
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(pool->IsStalled());
- EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_THAT(callback2.WaitForResult(), IsOk());
}
// Verify that SpdySessionKey and therefore SpdySession is different when
// privacy mode is enabled or disabled.
-TEST_P(SpdySessionTest, SpdySessionKeyPrivacyMode) {
+TEST_F(SpdySessionTest, SpdySessionKeyPrivacyMode) {
CreateNetworkSession();
HostPortPair host_port_pair("www.example.org", 443);
@@ -3477,9 +3249,9 @@ class StreamCreatingDelegate : public test::StreamDelegateDoNothing {
void OnClose(int status) override {
GURL url(kDefaultUrl);
- ignore_result(
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
- session_, url, MEDIUM, BoundNetLog()));
+ ignore_result(CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
+ session_, url, MEDIUM,
+ NetLogWithSource()));
}
private:
@@ -3489,41 +3261,40 @@ class StreamCreatingDelegate : public test::StreamDelegateDoNothing {
// Create another stream in response to a stream being reset. Nothing
// should blow up. This is a regression test for
// http://crbug.com/263690 .
-TEST_P(SpdySessionTest, CreateStreamOnStreamReset) {
+TEST_F(SpdySessionTest, CreateStreamOnStreamReset) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, MEDIUM, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
+ CreateMockWrite(req, 0),
};
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM));
MockRead reads[] = {
- MockRead(ASYNC, ERR_IO_PENDING, 1),
- CreateMockRead(*rst, 2),
- MockRead(ASYNC, ERR_IO_PENDING, 3),
- MockRead(ASYNC, 0, 4) // EOF
+ MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(rst, 2),
+ MockRead(ASYNC, ERR_IO_PENDING, 3), MockRead(ASYNC, 0, 4) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream);
EXPECT_EQ(0u, spdy_stream->stream_id());
StreamCreatingDelegate delegate(spdy_stream, session_);
spdy_stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
EXPECT_EQ(0u, spdy_stream->stream_id());
@@ -3546,7 +3317,7 @@ TEST_P(SpdySessionTest, CreateStreamOnStreamReset) {
EXPECT_FALSE(session_);
}
-TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) {
+TEST_F(SpdySessionTest, UpdateStreamsSendWindowSize) {
// Set SETTINGS_INITIAL_WINDOW_SIZE to a small number so that WINDOW_UPDATE
// gets sent.
SettingsMap new_settings;
@@ -3556,18 +3327,16 @@ TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) {
// Set up the socket so we read a SETTINGS frame that sets
// INITIAL_WINDOW_SIZE.
- std::unique_ptr<SpdySerializedFrame> settings_frame(
+ SpdySerializedFrame settings_frame(
spdy_util_.ConstructSpdySettings(new_settings));
MockRead reads[] = {
- CreateMockRead(*settings_frame, 0),
- MockRead(ASYNC, ERR_IO_PENDING, 1),
+ CreateMockRead(settings_frame, 0), MockRead(ASYNC, ERR_IO_PENDING, 1),
MockRead(ASYNC, 0, 2) // EOF
};
- std::unique_ptr<SpdySerializedFrame> settings_ack(
- spdy_util_.ConstructSpdySettingsAck());
+ SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
MockWrite writes[] = {
- CreateMockWrite(*settings_ack, 3),
+ CreateMockWrite(settings_ack, 3),
};
session_deps_.host_resolver->set_synchronous_mode(true);
@@ -3575,10 +3344,13 @@ TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ CreateSecureSpdySession();
+ base::WeakPtr<SpdyStream> spdy_stream1 =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream1);
TestCompletionCallback callback1;
EXPECT_NE(spdy_stream1->send_window_size(), window_size);
@@ -3592,8 +3364,9 @@ TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) {
spdy_stream1->Cancel();
EXPECT_FALSE(spdy_stream1);
- base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream2 =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ MEDIUM, NetLogWithSource());
ASSERT_TRUE(spdy_stream2);
EXPECT_EQ(spdy_stream2->send_window_size(), window_size);
spdy_stream2->Cancel();
@@ -3609,28 +3382,27 @@ TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) {
// adjust the session receive window size. In addition,
// SpdySession::IncreaseRecvWindowSize should trigger
// sending a WINDOW_UPDATE frame for a large enough delta.
-TEST_P(SpdySessionTest, AdjustRecvWindowSize) {
+TEST_F(SpdySessionTest, AdjustRecvWindowSize) {
session_deps_.host_resolver->set_synchronous_mode(true);
- const int32_t initial_window_size =
- SpdySession::GetDefaultInitialWindowSize(GetProtocol());
+ const int32_t initial_window_size = kDefaultInitialWindowSize;
const int32_t delta_window_size = 100;
MockRead reads[] = {
MockRead(ASYNC, ERR_IO_PENDING, 1), MockRead(ASYNC, 0, 2) // EOF
};
- std::unique_ptr<SpdySerializedFrame> window_update(
- spdy_util_.ConstructSpdyWindowUpdate(
- kSessionFlowControlStreamId,
- initial_window_size + delta_window_size));
+ SpdySerializedFrame window_update(spdy_util_.ConstructSpdyWindowUpdate(
+ kSessionFlowControlStreamId, initial_window_size + delta_window_size));
MockWrite writes[] = {
- CreateMockWrite(*window_update, 0),
+ CreateMockWrite(window_update, 0),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
EXPECT_EQ(initial_window_size, session_->session_recv_window_size_);
EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_);
@@ -3665,7 +3437,7 @@ TEST_P(SpdySessionTest, AdjustRecvWindowSize) {
// SpdySession::{Increase,Decrease}SendWindowSize should properly
// adjust the session send window size when the "enable_spdy_31" flag
// is set.
-TEST_P(SpdySessionTest, AdjustSendWindowSize) {
+TEST_F(SpdySessionTest, AdjustSendWindowSize) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {
@@ -3677,8 +3449,7 @@ TEST_P(SpdySessionTest, AdjustSendWindowSize) {
CreateNetworkSession();
session_ = CreateFakeSpdySession(spdy_session_pool_, key_);
- const int32_t initial_window_size =
- SpdySession::GetDefaultInitialWindowSize(GetProtocol());
+ const int32_t initial_window_size = kDefaultInitialWindowSize;
const int32_t delta_window_size = 100;
EXPECT_EQ(initial_window_size, session_->session_send_window_size_);
@@ -3694,30 +3465,28 @@ TEST_P(SpdySessionTest, AdjustSendWindowSize) {
// Incoming data for an inactive stream should not cause the session
// receive window size to decrease, but it should cause the unacked
// bytes to increase.
-TEST_P(SpdySessionTest, SessionFlowControlInactiveStream) {
+TEST_F(SpdySessionTest, SessionFlowControlInactiveStream) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyBodyFrame(1, false));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyDataFrame(1, false));
MockRead reads[] = {
- CreateMockRead(*resp, 0),
- MockRead(ASYNC, ERR_IO_PENDING, 1),
+ CreateMockRead(resp, 0), MockRead(ASYNC, ERR_IO_PENDING, 1),
MockRead(ASYNC, 0, 2) // EOF
};
SequencedSocketData data(reads, arraysize(reads), nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetProtocol()),
- session_->session_recv_window_size_);
+ EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_);
EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_);
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetProtocol()),
- session_->session_recv_window_size_);
+ EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_);
EXPECT_EQ(kUploadDataSize, session_->session_unacked_recv_window_bytes_);
EXPECT_TRUE(session_);
@@ -3728,35 +3497,30 @@ TEST_P(SpdySessionTest, SessionFlowControlInactiveStream) {
// The frame header is not included in flow control, but frame payload
// (including optional pad length and padding) is.
-TEST_P(SpdySessionTest, SessionFlowControlPadding) {
- // Padding only exists in HTTP/2.
- if (GetProtocol() < kProtoHTTP2)
- return;
-
+TEST_F(SpdySessionTest, SessionFlowControlPadding) {
session_deps_.host_resolver->set_synchronous_mode(true);
const int padding_length = 42;
- std::unique_ptr<SpdySerializedFrame> resp(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyDataFrame(
1, kUploadData, kUploadDataSize, false, padding_length));
MockRead reads[] = {
- CreateMockRead(*resp, 0),
- MockRead(ASYNC, ERR_IO_PENDING, 1),
+ CreateMockRead(resp, 0), MockRead(ASYNC, ERR_IO_PENDING, 1),
MockRead(ASYNC, 0, 2) // EOF
};
SequencedSocketData data(reads, arraysize(reads), nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetProtocol()),
- session_->session_recv_window_size_);
+ EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_);
EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_);
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetProtocol()),
- session_->session_recv_window_size_);
+ EXPECT_EQ(kDefaultInitialWindowSize, session_->session_recv_window_size_);
EXPECT_EQ(kUploadDataSize + padding_length,
session_->session_unacked_recv_window_bytes_);
@@ -3766,49 +3530,48 @@ TEST_P(SpdySessionTest, SessionFlowControlPadding) {
}
// Peer sends more data than stream level receiving flow control window.
-TEST_P(SpdySessionTest, StreamFlowControlTooMuchData) {
+TEST_F(SpdySessionTest, StreamFlowControlTooMuchData) {
const int32_t stream_max_recv_window_size = 1024;
const int32_t data_frame_size = 2 * stream_max_recv_window_size;
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
const std::string payload(data_frame_size, 'a');
- std::unique_ptr<SpdySerializedFrame> data_frame(
- spdy_util_.ConstructSpdyBodyFrame(1, payload.data(), data_frame_size,
- false));
+ SpdySerializedFrame data_frame(spdy_util_.ConstructSpdyDataFrame(
+ 1, payload.data(), data_frame_size, false));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*data_frame, 3),
- MockRead(ASYNC, ERR_IO_PENDING, 5),
+ CreateMockRead(resp, 1), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(data_frame, 3), MockRead(ASYNC, ERR_IO_PENDING, 5),
MockRead(ASYNC, 0, 6),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+
+ AddSSLSocketData();
+
CreateNetworkSession();
SpdySessionPoolPeer pool_peer(spdy_session_pool_);
pool_peer.SetStreamInitialRecvWindowSize(stream_max_recv_window_size);
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, LOWEST, NetLogWithSource());
EXPECT_EQ(stream_max_recv_window_size, spdy_stream->recv_window_size());
test::StreamDelegateDoNothing delegate(spdy_stream);
spdy_stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
EXPECT_EQ(ERR_IO_PENDING, spdy_stream->SendRequestHeaders(
std::move(headers), NO_MORE_DATA_TO_SEND));
@@ -3830,7 +3593,7 @@ TEST_P(SpdySessionTest, StreamFlowControlTooMuchData) {
// Regression test for a bug that was caused by including unsent WINDOW_UPDATE
// deltas in the receiving window size when checking incoming frames for flow
// control errors at session level.
-TEST_P(SpdySessionTest, SessionFlowControlTooMuchDataTwoDataFrames) {
+TEST_F(SpdySessionTest, SessionFlowControlTooMuchDataTwoDataFrames) {
const int32_t session_max_recv_window_size = 500;
const int32_t first_data_frame_size = 200;
const int32_t second_data_frame_size = 400;
@@ -3846,31 +3609,31 @@ TEST_P(SpdySessionTest, SessionFlowControlTooMuchDataTwoDataFrames) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
0, GOAWAY_FLOW_CONTROL_ERROR,
"delta_window_size is 400 in DecreaseRecvWindowSize, which is larger "
"than the receive window size of 500"));
MockWrite writes[] = {
- CreateMockWrite(*goaway, 4),
+ CreateMockWrite(goaway, 4),
};
const std::string first_data_frame(first_data_frame_size, 'a');
- std::unique_ptr<SpdySerializedFrame> first(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame first(spdy_util_.ConstructSpdyDataFrame(
1, first_data_frame.data(), first_data_frame_size, false));
const std::string second_data_frame(second_data_frame_size, 'b');
- std::unique_ptr<SpdySerializedFrame> second(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame second(spdy_util_.ConstructSpdyDataFrame(
1, second_data_frame.data(), second_data_frame_size, false));
MockRead reads[] = {
- CreateMockRead(*first, 0),
- MockRead(ASYNC, ERR_IO_PENDING, 1),
- CreateMockRead(*second, 2),
- MockRead(ASYNC, 0, 3),
+ CreateMockRead(first, 0), MockRead(ASYNC, ERR_IO_PENDING, 1),
+ CreateMockRead(second, 2), MockRead(ASYNC, 0, 3),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
// 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;
@@ -3892,7 +3655,7 @@ TEST_P(SpdySessionTest, SessionFlowControlTooMuchDataTwoDataFrames) {
// Regression test for a bug that was caused by including unsent WINDOW_UPDATE
// deltas in the receiving window size when checking incoming data frames for
// flow control errors at stream level.
-TEST_P(SpdySessionTest, StreamFlowControlTooMuchDataTwoDataFrames) {
+TEST_F(SpdySessionTest, StreamFlowControlTooMuchDataTwoDataFrames) {
const int32_t stream_max_recv_window_size = 500;
const int32_t first_data_frame_size = 200;
const int32_t second_data_frame_size = 400;
@@ -3905,48 +3668,46 @@ TEST_P(SpdySessionTest, StreamFlowControlTooMuchDataTwoDataFrames) {
ASSERT_LT(stream_max_recv_window_size,
first_data_frame_size + second_data_frame_size);
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 6),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 6),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
const std::string first_data_frame(first_data_frame_size, 'a');
- std::unique_ptr<SpdySerializedFrame> first(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame first(spdy_util_.ConstructSpdyDataFrame(
1, first_data_frame.data(), first_data_frame_size, false));
const std::string second_data_frame(second_data_frame_size, 'b');
- std::unique_ptr<SpdySerializedFrame> second(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame second(spdy_util_.ConstructSpdyDataFrame(
1, second_data_frame.data(), second_data_frame_size, false));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(*first, 3),
- MockRead(ASYNC, ERR_IO_PENDING, 4),
- CreateMockRead(*second, 5),
- MockRead(ASYNC, ERR_IO_PENDING, 7),
+ CreateMockRead(resp, 1), MockRead(ASYNC, ERR_IO_PENDING, 2),
+ CreateMockRead(first, 3), MockRead(ASYNC, ERR_IO_PENDING, 4),
+ CreateMockRead(second, 5), MockRead(ASYNC, ERR_IO_PENDING, 7),
MockRead(ASYNC, 0, 8),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
SpdySessionPoolPeer pool_peer(spdy_session_pool_);
pool_peer.SetStreamInitialRecvWindowSize(stream_max_recv_window_size);
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, LOWEST, NetLogWithSource());
test::StreamDelegateDoNothing delegate(spdy_stream);
spdy_stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
EXPECT_EQ(ERR_IO_PENDING, spdy_stream->SendRequestHeaders(
std::move(headers), NO_MORE_DATA_TO_SEND));
@@ -3995,31 +3756,26 @@ class DropReceivedDataDelegate : public test::StreamDelegateSendImmediate {
// Send data back and forth but use a delegate that drops its received
// data. The receive window should still increase to its original
// value, i.e. we shouldn't "leak" receive window bytes.
-TEST_P(SpdySessionTest, SessionFlowControlNoReceiveLeaks) {
+TEST_F(SpdySessionTest, SessionFlowControlNoReceiveLeaks) {
const int32_t kMsgDataSize = 100;
const std::string msg_data(kMsgDataSize, 'a');
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kMsgDataSize, MEDIUM, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> msg(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame msg(spdy_util_.ConstructSpdyDataFrame(
1, msg_data.data(), kMsgDataSize, false));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
- CreateMockWrite(*msg, 2),
+ CreateMockWrite(req, 0), CreateMockWrite(msg, 2),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> echo(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame echo(spdy_util_.ConstructSpdyDataFrame(
1, msg_data.data(), kMsgDataSize, false));
- std::unique_ptr<SpdySerializedFrame> window_update(
- spdy_util_.ConstructSpdyWindowUpdate(kSessionFlowControlStreamId,
- kMsgDataSize));
+ SpdySerializedFrame window_update(spdy_util_.ConstructSpdyWindowUpdate(
+ kSessionFlowControlStreamId, kMsgDataSize));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- CreateMockRead(*echo, 3),
- MockRead(ASYNC, ERR_IO_PENDING, 4),
- MockRead(ASYNC, 0, 5) // EOF
+ CreateMockRead(resp, 1), CreateMockRead(echo, 3),
+ MockRead(ASYNC, ERR_IO_PENDING, 4), MockRead(ASYNC, 0, 5) // EOF
};
// Create SpdySession and SpdyStream and send the request.
@@ -4027,25 +3783,26 @@ TEST_P(SpdySessionTest, SessionFlowControlNoReceiveLeaks) {
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ MEDIUM, NetLogWithSource());
ASSERT_TRUE(stream);
EXPECT_EQ(0u, stream->stream_id());
DropReceivedDataDelegate delegate(stream, msg_data);
stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kMsgDataSize)));
+ SpdyHeaderBlock headers(
+ spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kMsgDataSize));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
- const int32_t initial_window_size =
- SpdySession::GetDefaultInitialWindowSize(GetProtocol());
+ 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_);
@@ -4057,7 +3814,7 @@ TEST_P(SpdySessionTest, SessionFlowControlNoReceiveLeaks) {
stream->Close();
EXPECT_FALSE(stream);
- EXPECT_EQ(OK, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsOk());
EXPECT_EQ(initial_window_size, session_->session_recv_window_size_);
EXPECT_EQ(kMsgDataSize, session_->session_unacked_recv_window_bytes_);
@@ -4070,21 +3827,19 @@ TEST_P(SpdySessionTest, SessionFlowControlNoReceiveLeaks) {
// Send data back and forth but close the stream before its data frame
// can be written to the socket. The send window should then increase
// to its original value, i.e. we shouldn't "leak" send window bytes.
-TEST_P(SpdySessionTest, SessionFlowControlNoSendLeaks) {
+TEST_F(SpdySessionTest, SessionFlowControlNoSendLeaks) {
const int32_t kMsgDataSize = 100;
const std::string msg_data(kMsgDataSize, 'a');
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kMsgDataSize, MEDIUM, nullptr, 0));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
+ CreateMockWrite(req, 0),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
MockRead reads[] = {
- MockRead(ASYNC, ERR_IO_PENDING, 1),
- CreateMockRead(*resp, 2),
+ MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(resp, 2),
MockRead(ASYNC, 0, 3) // EOF
};
@@ -4093,25 +3848,26 @@ TEST_P(SpdySessionTest, SessionFlowControlNoSendLeaks) {
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ MEDIUM, NetLogWithSource());
ASSERT_TRUE(stream);
EXPECT_EQ(0u, stream->stream_id());
test::StreamDelegateSendImmediate delegate(stream, msg_data);
stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kMsgDataSize)));
+ SpdyHeaderBlock headers(
+ spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kMsgDataSize));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
- const int32_t initial_window_size =
- SpdySession::GetDefaultInitialWindowSize(GetProtocol());
+ const int32_t initial_window_size = kDefaultInitialWindowSize;
EXPECT_EQ(initial_window_size, session_->session_send_window_size_);
// Write request.
@@ -4132,7 +3888,7 @@ TEST_P(SpdySessionTest, SessionFlowControlNoSendLeaks) {
EXPECT_EQ(initial_window_size, session_->session_send_window_size_);
- EXPECT_EQ(OK, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsOk());
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(session_);
@@ -4143,32 +3899,29 @@ TEST_P(SpdySessionTest, SessionFlowControlNoSendLeaks) {
// Send data back and forth; the send and receive windows should
// change appropriately.
-TEST_P(SpdySessionTest, SessionFlowControlEndToEnd) {
+TEST_F(SpdySessionTest, SessionFlowControlEndToEnd) {
const int32_t kMsgDataSize = 100;
const std::string msg_data(kMsgDataSize, 'a');
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kMsgDataSize, MEDIUM, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> msg(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame msg(spdy_util_.ConstructSpdyDataFrame(
1, msg_data.data(), kMsgDataSize, false));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
- CreateMockWrite(*msg, 2),
+ CreateMockWrite(req, 0), CreateMockWrite(msg, 2),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> echo(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame echo(spdy_util_.ConstructSpdyDataFrame(
1, msg_data.data(), kMsgDataSize, false));
- std::unique_ptr<SpdySerializedFrame> window_update(
- spdy_util_.ConstructSpdyWindowUpdate(kSessionFlowControlStreamId,
- kMsgDataSize));
+ SpdySerializedFrame window_update(spdy_util_.ConstructSpdyWindowUpdate(
+ kSessionFlowControlStreamId, kMsgDataSize));
MockRead reads[] = {
- CreateMockRead(*resp, 1),
+ CreateMockRead(resp, 1),
MockRead(ASYNC, ERR_IO_PENDING, 3),
- CreateMockRead(*echo, 4),
+ CreateMockRead(echo, 4),
MockRead(ASYNC, ERR_IO_PENDING, 5),
- CreateMockRead(*window_update, 6),
+ CreateMockRead(window_update, 6),
MockRead(ASYNC, ERR_IO_PENDING, 7),
MockRead(ASYNC, 0, 8) // EOF
};
@@ -4178,25 +3931,26 @@ TEST_P(SpdySessionTest, SessionFlowControlEndToEnd) {
session_deps_.host_resolver->set_synchronous_mode(true);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream =
+ CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, session_, test_url_,
+ MEDIUM, NetLogWithSource());
ASSERT_TRUE(stream);
EXPECT_EQ(0u, stream->stream_id());
test::StreamDelegateSendImmediate delegate(stream, msg_data);
stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kMsgDataSize)));
+ SpdyHeaderBlock headers(
+ spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kMsgDataSize));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
- const int32_t initial_window_size =
- SpdySession::GetDefaultInitialWindowSize(GetProtocol());
+ 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_);
@@ -4239,7 +3993,7 @@ TEST_P(SpdySessionTest, SessionFlowControlEndToEnd) {
stream->Close();
EXPECT_FALSE(stream);
- EXPECT_EQ(OK, delegate.WaitForClose());
+ 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_);
@@ -4257,44 +4011,43 @@ void SpdySessionTest::RunResumeAfterUnstallTest(
const base::Callback<void(SpdyStream*, int32_t)>& unstall_function) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kBodyDataSize, LOWEST, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, true));
+ SpdySerializedFrame body(
+ spdy_util_.ConstructSpdyDataFrame(1, kBodyData, kBodyDataSize, true));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
- CreateMockWrite(*body, 1),
+ CreateMockWrite(req, 0), CreateMockWrite(body, 1),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> echo(
- spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, false));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame echo(
+ spdy_util_.ConstructSpdyDataFrame(1, kBodyData, kBodyDataSize, false));
MockRead reads[] = {
- CreateMockRead(*resp, 2), MockRead(ASYNC, 0, 3) // EOF
+ CreateMockRead(resp, 2), MockRead(ASYNC, 0, 3) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream);
test::StreamDelegateWithBody delegate(stream, kBodyDataStringPiece);
stream->SetDelegate(&delegate);
- EXPECT_FALSE(stream->HasUrlFromHeaders());
EXPECT_FALSE(stream->send_stalled_by_flow_control());
- std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)));
+ SpdyHeaderBlock headers(
+ spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec());
stall_function.Run(stream.get());
@@ -4307,7 +4060,7 @@ void SpdySessionTest::RunResumeAfterUnstallTest(
EXPECT_FALSE(stream->send_stalled_by_flow_control());
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
EXPECT_TRUE(delegate.send_headers_completed());
EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
@@ -4319,7 +4072,7 @@ void SpdySessionTest::RunResumeAfterUnstallTest(
// Run the resume-after-unstall test with all possible stall and
// unstall sequences.
-TEST_P(SpdySessionTest, ResumeAfterUnstallSession) {
+TEST_F(SpdySessionTest, ResumeAfterUnstallSession) {
RunResumeAfterUnstallTest(
base::Bind(&SpdySessionTest::StallSessionOnly,
base::Unretained(this)),
@@ -4329,7 +4082,7 @@ TEST_P(SpdySessionTest, ResumeAfterUnstallSession) {
// Equivalent to
// SpdyStreamTest.ResumeAfterSendWindowSizeIncrease.
-TEST_P(SpdySessionTest, ResumeAfterUnstallStream) {
+TEST_F(SpdySessionTest, ResumeAfterUnstallStream) {
RunResumeAfterUnstallTest(
base::Bind(&SpdySessionTest::StallStreamOnly,
base::Unretained(this)),
@@ -4337,7 +4090,7 @@ TEST_P(SpdySessionTest, ResumeAfterUnstallStream) {
base::Unretained(this)));
}
-TEST_P(SpdySessionTest, StallSessionStreamResumeAfterUnstallSessionStream) {
+TEST_F(SpdySessionTest, StallSessionStreamResumeAfterUnstallSessionStream) {
RunResumeAfterUnstallTest(
base::Bind(&SpdySessionTest::StallSessionStream,
base::Unretained(this)),
@@ -4345,7 +4098,7 @@ TEST_P(SpdySessionTest, StallSessionStreamResumeAfterUnstallSessionStream) {
base::Unretained(this)));
}
-TEST_P(SpdySessionTest, StallStreamSessionResumeAfterUnstallSessionStream) {
+TEST_F(SpdySessionTest, StallStreamSessionResumeAfterUnstallSessionStream) {
RunResumeAfterUnstallTest(
base::Bind(&SpdySessionTest::StallStreamSession,
base::Unretained(this)),
@@ -4353,7 +4106,7 @@ TEST_P(SpdySessionTest, StallStreamSessionResumeAfterUnstallSessionStream) {
base::Unretained(this)));
}
-TEST_P(SpdySessionTest, StallStreamSessionResumeAfterUnstallStreamSession) {
+TEST_F(SpdySessionTest, StallStreamSessionResumeAfterUnstallStreamSession) {
RunResumeAfterUnstallTest(
base::Bind(&SpdySessionTest::StallStreamSession,
base::Unretained(this)),
@@ -4361,7 +4114,7 @@ TEST_P(SpdySessionTest, StallStreamSessionResumeAfterUnstallStreamSession) {
base::Unretained(this)));
}
-TEST_P(SpdySessionTest, StallSessionStreamResumeAfterUnstallStreamSession) {
+TEST_F(SpdySessionTest, StallSessionStreamResumeAfterUnstallStreamSession) {
RunResumeAfterUnstallTest(
base::Bind(&SpdySessionTest::StallSessionStream,
base::Unretained(this)),
@@ -4372,79 +4125,72 @@ TEST_P(SpdySessionTest, StallSessionStreamResumeAfterUnstallStreamSession) {
// Cause a stall by reducing the flow control send window to 0. The
// streams should resume in priority order when that window is then
// increased.
-TEST_P(SpdySessionTest, ResumeByPriorityAfterSendWindowSizeIncrease) {
+TEST_F(SpdySessionTest, ResumeByPriorityAfterSendWindowSizeIncrease) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> req1(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req1(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kBodyDataSize, LOWEST, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> req2(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req2(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 3, kBodyDataSize, MEDIUM, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> body1(
- spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, true));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(3, kBodyData, kBodyDataSize, true));
+ SpdySerializedFrame body1(
+ spdy_util_.ConstructSpdyDataFrame(1, kBodyData, kBodyDataSize, true));
+ SpdySerializedFrame body2(
+ spdy_util_.ConstructSpdyDataFrame(3, kBodyData, kBodyDataSize, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
- CreateMockWrite(*req2, 1),
- CreateMockWrite(*body2, 2),
- CreateMockWrite(*body1, 3),
+ CreateMockWrite(req1, 0), CreateMockWrite(req2, 1),
+ CreateMockWrite(body2, 2), CreateMockWrite(body1, 3),
};
- std::unique_ptr<SpdySerializedFrame> resp1(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 3));
+ SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
MockRead reads[] = {
- CreateMockRead(*resp1, 4),
- CreateMockRead(*resp2, 5),
+ CreateMockRead(resp1, 4), CreateMockRead(resp2, 5),
MockRead(ASYNC, 0, 6) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream1);
test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
stream1->SetDelegate(&delegate1);
- EXPECT_FALSE(stream1->HasUrlFromHeaders());
-
- base::WeakPtr<SpdyStream> stream2 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream2 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, MEDIUM, NetLogWithSource());
ASSERT_TRUE(stream2);
test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece);
stream2->SetDelegate(&delegate2);
- EXPECT_FALSE(stream2->HasUrlFromHeaders());
-
EXPECT_FALSE(stream1->send_stalled_by_flow_control());
EXPECT_FALSE(stream2->send_stalled_by_flow_control());
StallSessionSend();
- std::unique_ptr<SpdyHeaderBlock> headers1(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)));
+ SpdyHeaderBlock headers1(
+ spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING, stream1->SendRequestHeaders(std::move(headers1),
MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream1->HasUrlFromHeaders());
EXPECT_EQ(kDefaultUrl, stream1->GetUrlFromHeaders().spec());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, stream1->stream_id());
EXPECT_TRUE(stream1->send_stalled_by_flow_control());
- std::unique_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)));
+ SpdyHeaderBlock headers2(
+ spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING, stream2->SendRequestHeaders(std::move(headers2),
MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream2->HasUrlFromHeaders());
EXPECT_EQ(kDefaultUrl, stream2->GetUrlFromHeaders().spec());
base::RunLoop().RunUntilIdle();
@@ -4470,8 +4216,8 @@ TEST_P(SpdySessionTest, ResumeByPriorityAfterSendWindowSizeIncrease) {
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose());
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose());
+ EXPECT_THAT(delegate1.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
+ EXPECT_THAT(delegate2.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
EXPECT_TRUE(delegate1.send_headers_completed());
EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status"));
@@ -4513,98 +4259,90 @@ class StreamClosingDelegate : public test::StreamDelegateWithBody {
// Cause a stall by reducing the flow control send window to
// 0. Unstalling the session should properly handle deleted streams.
-TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedStreams) {
+TEST_F(SpdySessionTest, SendWindowSizeIncreaseWithDeletedStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> req1(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req1(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kBodyDataSize, LOWEST, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> req2(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req2(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 3, kBodyDataSize, LOWEST, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> req3(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req3(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 5, kBodyDataSize, LOWEST, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> body2(
- spdy_util_.ConstructSpdyBodyFrame(3, kBodyData, kBodyDataSize, true));
+ SpdySerializedFrame body2(
+ spdy_util_.ConstructSpdyDataFrame(3, kBodyData, kBodyDataSize, true));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
- CreateMockWrite(*req2, 1),
- CreateMockWrite(*req3, 2),
- CreateMockWrite(*body2, 3),
+ CreateMockWrite(req1, 0), CreateMockWrite(req2, 1),
+ CreateMockWrite(req3, 2), CreateMockWrite(body2, 3),
};
- std::unique_ptr<SpdySerializedFrame> resp2(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 3));
+ SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
MockRead reads[] = {
- CreateMockRead(*resp2, 4),
- MockRead(ASYNC, ERR_IO_PENDING, 5),
+ CreateMockRead(resp2, 4), MockRead(ASYNC, ERR_IO_PENDING, 5),
MockRead(ASYNC, 0, 6) // EOF
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream1);
test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
stream1->SetDelegate(&delegate1);
- EXPECT_FALSE(stream1->HasUrlFromHeaders());
-
- base::WeakPtr<SpdyStream> stream2 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream2 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream2);
StreamClosingDelegate delegate2(stream2, kBodyDataStringPiece);
stream2->SetDelegate(&delegate2);
- EXPECT_FALSE(stream2->HasUrlFromHeaders());
-
- base::WeakPtr<SpdyStream> stream3 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream3 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream3);
test::StreamDelegateWithBody delegate3(stream3, kBodyDataStringPiece);
stream3->SetDelegate(&delegate3);
- EXPECT_FALSE(stream3->HasUrlFromHeaders());
-
EXPECT_FALSE(stream1->send_stalled_by_flow_control());
EXPECT_FALSE(stream2->send_stalled_by_flow_control());
EXPECT_FALSE(stream3->send_stalled_by_flow_control());
StallSessionSend();
- std::unique_ptr<SpdyHeaderBlock> headers1(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)));
+ SpdyHeaderBlock headers1(
+ spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING, stream1->SendRequestHeaders(std::move(headers1),
MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream1->HasUrlFromHeaders());
EXPECT_EQ(kDefaultUrl, stream1->GetUrlFromHeaders().spec());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, stream1->stream_id());
EXPECT_TRUE(stream1->send_stalled_by_flow_control());
- std::unique_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)));
+ SpdyHeaderBlock headers2(
+ spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING, stream2->SendRequestHeaders(std::move(headers2),
MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream2->HasUrlFromHeaders());
EXPECT_EQ(kDefaultUrl, stream2->GetUrlFromHeaders().spec());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(3u, stream2->stream_id());
EXPECT_TRUE(stream2->send_stalled_by_flow_control());
- std::unique_ptr<SpdyHeaderBlock> headers3(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)));
+ SpdyHeaderBlock headers3(
+ spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING, stream3->SendRequestHeaders(std::move(headers3),
MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream3->HasUrlFromHeaders());
EXPECT_EQ(kDefaultUrl, stream3->GetUrlFromHeaders().spec());
base::RunLoop().RunUntilIdle();
@@ -4640,9 +4378,9 @@ TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedStreams) {
EXPECT_FALSE(stream2);
EXPECT_FALSE(session_);
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose());
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose());
- EXPECT_EQ(OK, delegate3.WaitForClose());
+ EXPECT_THAT(delegate1.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
+ EXPECT_THAT(delegate2.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
+ EXPECT_THAT(delegate3.WaitForClose(), IsOk());
EXPECT_TRUE(delegate1.send_headers_completed());
EXPECT_EQ(std::string(), delegate1.TakeReceivedData());
@@ -4660,18 +4398,17 @@ TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedStreams) {
// Cause a stall by reducing the flow control send window to
// 0. Unstalling the session should properly handle the session itself
// being closed.
-TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) {
+TEST_F(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) {
session_deps_.host_resolver->set_synchronous_mode(true);
- std::unique_ptr<SpdySerializedFrame> req1(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req1(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 1, kBodyDataSize, LOWEST, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> req2(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req2(spdy_util_.ConstructSpdyPost(
kDefaultUrl, 3, kBodyDataSize, LOWEST, nullptr, 0));
- std::unique_ptr<SpdySerializedFrame> body1(
- spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, false));
+ SpdySerializedFrame body1(
+ spdy_util_.ConstructSpdyDataFrame(1, kBodyData, kBodyDataSize, false));
MockWrite writes[] = {
- CreateMockWrite(*req1, 0),
- CreateMockWrite(*req2, 1),
+ CreateMockWrite(req1, 0), CreateMockWrite(req2, 1),
};
MockRead reads[] = {
@@ -4681,48 +4418,46 @@ TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) {
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream1 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream1);
test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
stream1->SetDelegate(&delegate1);
- EXPECT_FALSE(stream1->HasUrlFromHeaders());
-
- base::WeakPtr<SpdyStream> stream2 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream2 =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream2);
test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece);
stream2->SetDelegate(&delegate2);
- EXPECT_FALSE(stream2->HasUrlFromHeaders());
-
EXPECT_FALSE(stream1->send_stalled_by_flow_control());
EXPECT_FALSE(stream2->send_stalled_by_flow_control());
StallSessionSend();
- std::unique_ptr<SpdyHeaderBlock> headers1(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)));
+ SpdyHeaderBlock headers1(
+ spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING, stream1->SendRequestHeaders(std::move(headers1),
MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream1->HasUrlFromHeaders());
EXPECT_EQ(kDefaultUrl, stream1->GetUrlFromHeaders().spec());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, stream1->stream_id());
EXPECT_TRUE(stream1->send_stalled_by_flow_control());
- std::unique_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize)));
+ SpdyHeaderBlock headers2(
+ spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize));
EXPECT_EQ(ERR_IO_PENDING, stream2->SendRequestHeaders(std::move(headers2),
MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream2->HasUrlFromHeaders());
EXPECT_EQ(kDefaultUrl, stream2->GetUrlFromHeaders().spec());
base::RunLoop().RunUntilIdle();
@@ -4743,8 +4478,8 @@ TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) {
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose());
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose());
+ EXPECT_THAT(delegate1.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
+ EXPECT_THAT(delegate2.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
EXPECT_TRUE(delegate1.send_headers_completed());
EXPECT_EQ(std::string(), delegate1.TakeReceivedData());
@@ -4755,41 +4490,40 @@ TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) {
EXPECT_TRUE(data.AllWriteDataConsumed());
}
-TEST_P(SpdySessionTest, GoAwayOnSessionFlowControlError) {
- std::unique_ptr<SpdySerializedFrame> req(
+TEST_F(SpdySessionTest, GoAwayOnSessionFlowControlError) {
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+ SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
0, GOAWAY_FLOW_CONTROL_ERROR,
"delta_window_size is 6 in DecreaseRecvWindowSize, which is larger than "
"the receive window size of 1"));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 4),
+ CreateMockWrite(req, 0), CreateMockWrite(goaway, 4),
};
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, true));
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+ SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
MockRead reads[] = {
- MockRead(ASYNC, ERR_IO_PENDING, 1),
- CreateMockRead(*resp, 2),
- CreateMockRead(*body, 3),
+ MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(resp, 2),
+ CreateMockRead(body, 3),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, LOWEST, NetLogWithSource());
ASSERT_TRUE(spdy_stream);
test::StreamDelegateDoNothing delegate(spdy_stream);
spdy_stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
// Write request.
@@ -4803,69 +4537,49 @@ TEST_P(SpdySessionTest, GoAwayOnSessionFlowControlError) {
data.Resume();
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(ERR_SPDY_FLOW_CONTROL_ERROR, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_FLOW_CONTROL_ERROR));
EXPECT_FALSE(session_);
}
-TEST_P(SpdySessionTest, SplitHeaders) {
- GURL kStreamUrl("https://www.example.org/foo.dat");
- SpdyHeaderBlock headers;
- spdy_util_.AddUrlToHeaderBlock(kStreamUrl.spec(), &headers);
- headers["alpha"] = "beta";
-
- SpdyHeaderBlock request_headers;
- SpdyHeaderBlock response_headers;
-
- SplitPushedHeadersToRequestAndResponse(
- headers, spdy_util_.spdy_version(), &request_headers, &response_headers);
-
- SpdyHeaderBlock::const_iterator it = response_headers.find("alpha");
- std::string alpha_val =
- (it == response_headers.end()) ? std::string() : it->second.as_string();
- EXPECT_EQ("beta", alpha_val);
-
- GURL request_url =
- GetUrlFromHeaderBlock(request_headers, spdy_util_.spdy_version());
- EXPECT_EQ(kStreamUrl, request_url);
-}
-
// Regression. Sorta. Push streams and client streams were sharing a single
// limit for a long time.
-TEST_P(SpdySessionTest, PushedStreamShouldNotCountToClientConcurrencyLimit) {
+TEST_F(SpdySessionTest, PushedStreamShouldNotCountToClientConcurrencyLimit) {
SettingsMap new_settings;
new_settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
SettingsFlagsAndValue(SETTINGS_FLAG_NONE, 2);
- std::unique_ptr<SpdySerializedFrame> settings_frame(
+ SpdySerializedFrame settings_frame(
spdy_util_.ConstructSpdySettings(new_settings));
- std::unique_ptr<SpdySerializedFrame> pushed(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame pushed(spdy_util_.ConstructSpdyPush(
nullptr, 0, 2, 1, "https://www.example.org/a.dat"));
MockRead reads[] = {
- CreateMockRead(*settings_frame, 0),
+ CreateMockRead(settings_frame, 0),
MockRead(ASYNC, ERR_IO_PENDING, 3),
- CreateMockRead(*pushed, 4),
+ CreateMockRead(pushed, 4),
MockRead(ASYNC, ERR_IO_PENDING, 5),
MockRead(ASYNC, 0, 6),
};
- std::unique_ptr<SpdySerializedFrame> settings_ack(
- spdy_util_.ConstructSpdySettingsAck());
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
MockWrite writes[] = {
- CreateMockWrite(*settings_ack, 1), CreateMockWrite(*req, 2),
+ CreateMockWrite(settings_ack, 1), CreateMockWrite(req, 2),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
// Read the settings frame.
base::RunLoop().RunUntilIdle();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ 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);
@@ -4876,10 +4590,8 @@ TEST_P(SpdySessionTest, PushedStreamShouldNotCountToClientConcurrencyLimit) {
EXPECT_EQ(0u, session_->num_pushed_streams());
EXPECT_EQ(0u, session_->num_active_pushed_streams());
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
// Run until 1st stream is activated.
EXPECT_EQ(0u, delegate1.stream_id());
@@ -4901,8 +4613,9 @@ TEST_P(SpdySessionTest, PushedStreamShouldNotCountToClientConcurrencyLimit) {
// 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
// create streams on the client.
- base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream2 =
+ 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());
@@ -4915,37 +4628,37 @@ TEST_P(SpdySessionTest, PushedStreamShouldNotCountToClientConcurrencyLimit) {
EXPECT_FALSE(session_);
}
-TEST_P(SpdySessionTest, RejectPushedStreamExceedingConcurrencyLimit) {
- std::unique_ptr<SpdySerializedFrame> push_a(spdy_util_.ConstructSpdyPush(
+TEST_F(SpdySessionTest, RejectPushedStreamExceedingConcurrencyLimit) {
+ SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush(
nullptr, 0, 2, 1, "https://www.example.org/a.dat"));
- std::unique_ptr<SpdySerializedFrame> push_b(spdy_util_.ConstructSpdyPush(
+ SpdySerializedFrame push_b(spdy_util_.ConstructSpdyPush(
nullptr, 0, 4, 1, "https://www.example.org/b.dat"));
MockRead reads[] = {
- MockRead(ASYNC, ERR_IO_PENDING, 1),
- CreateMockRead(*push_a, 2),
- MockRead(ASYNC, ERR_IO_PENDING, 3),
- CreateMockRead(*push_b, 4),
- MockRead(ASYNC, ERR_IO_PENDING, 6),
- MockRead(ASYNC, 0, 7),
+ MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(push_a, 2),
+ MockRead(ASYNC, ERR_IO_PENDING, 3), CreateMockRead(push_b, 4),
+ MockRead(ASYNC, ERR_IO_PENDING, 6), MockRead(ASYNC, 0, 7),
};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(4, RST_STREAM_REFUSED_STREAM));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 5),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 5),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
session_->set_max_concurrent_pushed_streams(1);
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ 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);
@@ -4956,10 +4669,8 @@ TEST_P(SpdySessionTest, RejectPushedStreamExceedingConcurrencyLimit) {
EXPECT_EQ(0u, session_->num_pushed_streams());
EXPECT_EQ(0u, session_->num_active_pushed_streams());
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
// Run until 1st stream is activated.
EXPECT_EQ(0u, delegate1.stream_id());
@@ -4994,7 +4705,7 @@ TEST_P(SpdySessionTest, RejectPushedStreamExceedingConcurrencyLimit) {
// Tests that HTTP SPDY push streams that advertise an origin different from the
// associated stream are accepted from a trusted SPDY proxy.
-TEST_P(SpdySessionTest, TrustedSpdyProxy) {
+TEST_F(SpdySessionTest, TrustedSpdyProxy) {
// Origin of kDefaultUrl should be different from the origin of
// kHttpURLFromAnotherOrigin and kHttpsURLFromAnotherOrigin.
ASSERT_NE(GURL(kDefaultUrl).host(), GURL(kHttpURLFromAnotherOrigin).host());
@@ -5002,28 +4713,26 @@ TEST_P(SpdySessionTest, TrustedSpdyProxy) {
// cross_origin_push contains HTTP resource for an origin different from the
// origin of kDefaultUrl, and should be accepted.
- std::unique_ptr<SpdySerializedFrame> cross_origin_push(
- spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1,
- kHttpURLFromAnotherOrigin));
+ SpdySerializedFrame cross_origin_push(spdy_util_.ConstructSpdyPush(
+ nullptr, 0, 2, 1, kHttpURLFromAnotherOrigin));
// cross_origin_https_push contains HTTPS resource, and should be refused.
- std::unique_ptr<SpdySerializedFrame> cross_origin_https_push(
- spdy_util_.ConstructSpdyPush(nullptr, 0, 4, 1,
- kHttpsURLFromAnotherOrigin));
+ SpdySerializedFrame cross_origin_https_push(spdy_util_.ConstructSpdyPush(
+ nullptr, 0, 4, 1, kHttpsURLFromAnotherOrigin));
MockRead reads[] = {
MockRead(ASYNC, ERR_IO_PENDING, 1),
- CreateMockRead(*cross_origin_push, 2),
+ CreateMockRead(cross_origin_push, 2),
MockRead(ASYNC, ERR_IO_PENDING, 3),
- CreateMockRead(*cross_origin_https_push, 4),
+ CreateMockRead(cross_origin_https_push, 4),
MockRead(ASYNC, ERR_IO_PENDING, 6),
MockRead(ASYNC, 0, 7),
};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(4, RST_STREAM_REFUSED_STREAM));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 5),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 5),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
@@ -5035,24 +4744,14 @@ TEST_P(SpdySessionTest, TrustedSpdyProxy) {
HostPortPair(GURL(kDefaultUrl).host(), 443)));
session_deps_.proxy_delegate.reset(proxy_delegate.release());
- // Load a cert that is valid for:
- // www.example.org
- // mail.example.org
- // mail.example.com
- base::FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> test_cert(
- ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
- ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
-
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- ssl.cert = test_cert;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+ AddSSLSocketData();
CreateNetworkSession();
CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, LOWEST, NetLogWithSource());
ASSERT_TRUE(spdy_stream);
EXPECT_EQ(0u, spdy_stream->stream_id());
test::StreamDelegateDoNothing delegate(spdy_stream);
@@ -5063,10 +4762,8 @@ TEST_P(SpdySessionTest, TrustedSpdyProxy) {
EXPECT_EQ(0u, session_->num_pushed_streams());
EXPECT_EQ(0u, session_->num_active_pushed_streams());
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
// Run until 1st stream is activated.
EXPECT_EQ(0u, delegate.stream_id());
@@ -5101,50 +4798,39 @@ TEST_P(SpdySessionTest, TrustedSpdyProxy) {
// Tests that if the SPDY trusted proxy is not set, then push streams that
// advertise an origin different from the associated stream are refused.
-TEST_P(SpdySessionTest, TrustedSpdyProxyNotSet) {
+TEST_F(SpdySessionTest, TrustedSpdyProxyNotSet) {
// Origin of kDefaultUrl should be different from the origin of
// kHttpURLFromAnotherOrigin.
ASSERT_NE(GURL(kDefaultUrl).host(), GURL(kHttpURLFromAnotherOrigin).host());
// cross_origin_push contains resource for an origin different from the
// origin of kDefaultUrl, and should be refused.
- std::unique_ptr<SpdySerializedFrame> cross_origin_push(
- spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1,
- kHttpURLFromAnotherOrigin));
+ SpdySerializedFrame cross_origin_push(spdy_util_.ConstructSpdyPush(
+ nullptr, 0, 2, 1, kHttpURLFromAnotherOrigin));
MockRead reads[] = {
- MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(*cross_origin_push, 2),
+ MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(cross_origin_push, 2),
MockRead(ASYNC, 0, 4),
};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 3),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 3),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
- // Load a cert that is valid for:
- // www.example.org
- // mail.example.org
- // mail.example.com
- base::FilePath certs_dir = GetTestCertsDirectory();
- scoped_refptr<X509Certificate> test_cert(
- ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
- ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
-
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- ssl.cert = test_cert;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+ AddSSLSocketData();
CreateNetworkSession();
CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream =
+ CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+ test_url_, LOWEST, NetLogWithSource());
ASSERT_TRUE(spdy_stream);
EXPECT_EQ(0u, spdy_stream->stream_id());
test::StreamDelegateDoNothing delegate(spdy_stream);
@@ -5155,10 +4841,8 @@ TEST_P(SpdySessionTest, TrustedSpdyProxyNotSet) {
EXPECT_EQ(0u, session_->num_pushed_streams());
EXPECT_EQ(0u, session_->num_active_pushed_streams());
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
// Run until 1st stream is activated.
EXPECT_EQ(0u, delegate.stream_id());
@@ -5175,48 +4859,43 @@ TEST_P(SpdySessionTest, TrustedSpdyProxyNotSet) {
EXPECT_FALSE(session_);
}
-TEST_P(SpdySessionTest, IgnoreReservedRemoteStreamsCount) {
- // Streams in reserved remote state exist only in HTTP/2.
- if (spdy_util_.spdy_version() < HTTP2)
- return;
-
- std::unique_ptr<SpdySerializedFrame> push_a(spdy_util_.ConstructSpdyPush(
+TEST_F(SpdySessionTest, IgnoreReservedRemoteStreamsCount) {
+ SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush(
nullptr, 0, 2, 1, "https://www.example.org/a.dat"));
SpdyHeaderBlock push_headers;
spdy_util_.AddUrlToHeaderBlock("https://www.example.org/b.dat",
&push_headers);
- std::unique_ptr<SpdySerializedFrame> push_b(
+ SpdySerializedFrame push_b(
spdy_util_.ConstructInitialSpdyPushFrame(std::move(push_headers), 4, 1));
- std::unique_ptr<SpdySerializedFrame> headers_b(
+ SpdySerializedFrame headers_b(
spdy_util_.ConstructSpdyPushHeaders(4, nullptr, 0));
MockRead reads[] = {
- MockRead(ASYNC, ERR_IO_PENDING, 1),
- CreateMockRead(*push_a, 2),
- MockRead(ASYNC, ERR_IO_PENDING, 3),
- CreateMockRead(*push_b, 4),
- MockRead(ASYNC, ERR_IO_PENDING, 5),
- CreateMockRead(*headers_b, 6),
- MockRead(ASYNC, ERR_IO_PENDING, 8),
- MockRead(ASYNC, 0, 9),
+ MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(push_a, 2),
+ MockRead(ASYNC, ERR_IO_PENDING, 3), CreateMockRead(push_b, 4),
+ MockRead(ASYNC, ERR_IO_PENDING, 5), CreateMockRead(headers_b, 6),
+ MockRead(ASYNC, ERR_IO_PENDING, 8), MockRead(ASYNC, 0, 9),
};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(4, RST_STREAM_REFUSED_STREAM));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 7),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 7),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
session_->set_max_concurrent_pushed_streams(1);
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ 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);
@@ -5227,10 +4906,8 @@ TEST_P(SpdySessionTest, IgnoreReservedRemoteStreamsCount) {
EXPECT_EQ(0u, session_->num_pushed_streams());
EXPECT_EQ(0u, session_->num_active_pushed_streams());
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
// Run until 1st stream is activated.
EXPECT_EQ(0u, delegate1.stream_id());
@@ -5272,43 +4949,39 @@ TEST_P(SpdySessionTest, IgnoreReservedRemoteStreamsCount) {
EXPECT_FALSE(session_);
}
-TEST_P(SpdySessionTest, CancelReservedStreamOnHeadersReceived) {
- // Streams in reserved remote state exist only in HTTP/2.
- if (spdy_util_.spdy_version() < HTTP2)
- return;
-
+TEST_F(SpdySessionTest, CancelReservedStreamOnHeadersReceived) {
const char kPushedUrl[] = "https://www.example.org/a.dat";
SpdyHeaderBlock push_headers;
spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_headers);
- std::unique_ptr<SpdySerializedFrame> push_promise(
+ SpdySerializedFrame push_promise(
spdy_util_.ConstructInitialSpdyPushFrame(std::move(push_headers), 2, 1));
- std::unique_ptr<SpdySerializedFrame> headers_frame(
+ 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, 3),
- CreateMockRead(*headers_frame, 4),
- MockRead(ASYNC, ERR_IO_PENDING, 6),
- MockRead(ASYNC, 0, 7),
+ MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(push_promise, 2),
+ MockRead(ASYNC, ERR_IO_PENDING, 3), CreateMockRead(headers_frame, 4),
+ MockRead(ASYNC, ERR_IO_PENDING, 6), MockRead(ASYNC, 0, 7),
};
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*req, 0), CreateMockWrite(*rst, 5),
+ CreateMockWrite(req, 0), CreateMockWrite(rst, 5),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, LOWEST, BoundNetLog());
+ 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);
@@ -5319,10 +4992,8 @@ TEST_P(SpdySessionTest, CancelReservedStreamOnHeadersReceived) {
EXPECT_EQ(0u, session_->num_pushed_streams());
EXPECT_EQ(0u, session_->num_active_pushed_streams());
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
// Run until 1st stream is activated.
EXPECT_EQ(0u, delegate1.stream_id());
@@ -5342,9 +5013,9 @@ TEST_P(SpdySessionTest, CancelReservedStreamOnHeadersReceived) {
EXPECT_EQ(0u, session_->num_active_pushed_streams());
base::WeakPtr<SpdyStream> pushed_stream;
- int rv =
- session_->GetPushStream(GURL(kPushedUrl), &pushed_stream, BoundNetLog());
- ASSERT_EQ(OK, rv);
+ int rv = session_->GetPushStream(GURL(kPushedUrl), &pushed_stream,
+ NetLogWithSource());
+ ASSERT_THAT(rv, IsOk());
ASSERT_TRUE(pushed_stream);
test::StreamDelegateCloseOnHeaders delegate2(pushed_stream);
pushed_stream->SetDelegate(&delegate2);
@@ -5365,7 +5036,7 @@ TEST_P(SpdySessionTest, CancelReservedStreamOnHeadersReceived) {
EXPECT_TRUE(data.AllReadDataConsumed());
}
-TEST_P(SpdySessionTest, RejectInvalidUnknownFrames) {
+TEST_F(SpdySessionTest, RejectInvalidUnknownFrames) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockRead reads[] = {
@@ -5375,8 +5046,10 @@ TEST_P(SpdySessionTest, RejectInvalidUnknownFrames) {
StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
CreateNetworkSession();
- CreateInsecureSpdySession();
+ CreateSecureSpdySession();
session_->stream_hi_water_mark_ = 5;
// Low client (odd) ids are fine.
@@ -5398,8 +5071,7 @@ class AltSvcFrameTest : public SpdySessionTest {
"alternative.example.org",
443,
86400,
- SpdyAltSvcWireFormat::VersionVector()),
- ssl_(SYNCHRONOUS, OK) {}
+ SpdyAltSvcWireFormat::VersionVector()) {}
void AddSocketData(const SpdyAltSvcIR& altsvc_ir) {
altsvc_frame_ = spdy_util_.SerializeFrame(altsvc_ir);
@@ -5411,18 +5083,9 @@ class AltSvcFrameTest : public SpdySessionTest {
session_deps_.socket_factory->AddSocketDataProvider(data_.get());
}
- void AddSSLSocketData() {
- // Load a cert that is valid for
- // www.example.org, mail.example.org, and mail.example.com.
- cert_ = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
- ASSERT_TRUE(cert_);
- ssl_.cert = cert_;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_);
- }
-
void CreateSecureSpdySession() {
session_ = ::net::CreateSecureSpdySession(http_session_.get(), key_,
- BoundNetLog());
+ NetLogWithSource());
}
SpdyAltSvcWireFormat::AlternativeService alternative_service_;
@@ -5431,15 +5094,9 @@ class AltSvcFrameTest : public SpdySessionTest {
SpdySerializedFrame altsvc_frame_;
std::vector<MockRead> reads_;
std::unique_ptr<SequencedSocketData> data_;
- scoped_refptr<X509Certificate> cert_;
- SSLSocketDataProvider ssl_;
};
-INSTANTIATE_TEST_CASE_P(HTTP2,
- AltSvcFrameTest,
- testing::Values(kTestCaseHTTP2PriorityDependencies));
-
-TEST_P(AltSvcFrameTest, ProcessAltSvcFrame) {
+TEST_F(AltSvcFrameTest, ProcessAltSvcFrame) {
const char origin[] = "https://mail.example.org";
SpdyAltSvcIR altsvc_ir(0);
altsvc_ir.add_altsvc(alternative_service_);
@@ -5468,7 +5125,7 @@ TEST_P(AltSvcFrameTest, ProcessAltSvcFrame) {
EXPECT_EQ(443u, altsvc_vector[0].port);
}
-TEST_P(AltSvcFrameTest, DoNotProcessAltSvcFrameOnInsecureSession) {
+TEST_F(AltSvcFrameTest, DoNotProcessAltSvcFrameOnInsecureSession) {
const char origin[] = "https://mail.example.org";
SpdyAltSvcIR altsvc_ir(0);
altsvc_ir.add_altsvc(alternative_service_);
@@ -5494,7 +5151,7 @@ TEST_P(AltSvcFrameTest, DoNotProcessAltSvcFrameOnInsecureSession) {
ASSERT_TRUE(altsvc_vector.empty());
}
-TEST_P(AltSvcFrameTest, DoNotProcessAltSvcFrameForOriginNotCoveredByCert) {
+TEST_F(AltSvcFrameTest, DoNotProcessAltSvcFrameForOriginNotCoveredByCert) {
const char origin[] = "https://invalid.example.org";
SpdyAltSvcIR altsvc_ir(0);
altsvc_ir.add_altsvc(alternative_service_);
@@ -5520,7 +5177,7 @@ TEST_P(AltSvcFrameTest, DoNotProcessAltSvcFrameForOriginNotCoveredByCert) {
ASSERT_TRUE(altsvc_vector.empty());
}
-TEST_P(AltSvcFrameTest, DoNotProcessAltSvcFrameWithEmptyOriginOnZeroStream) {
+TEST_F(AltSvcFrameTest, DoNotProcessAltSvcFrameWithEmptyOriginOnZeroStream) {
SpdyAltSvcIR altsvc_ir(0);
altsvc_ir.add_altsvc(alternative_service_);
AddSocketData(altsvc_ir);
@@ -5539,23 +5196,23 @@ TEST_P(AltSvcFrameTest, DoNotProcessAltSvcFrameWithEmptyOriginOnZeroStream) {
ASSERT_TRUE(altsvc_vector.empty());
}
-TEST_P(AltSvcFrameTest, ProcessAltSvcFrameOnActiveStream) {
+TEST_F(AltSvcFrameTest, ProcessAltSvcFrameOnActiveStream) {
SpdyAltSvcIR altsvc_ir(1);
altsvc_ir.add_altsvc(alternative_service_);
SpdySerializedFrame altsvc_frame(spdy_util_.SerializeFrame(altsvc_ir));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM));
MockRead reads[] = {
- CreateMockRead(altsvc_frame, 1), CreateMockRead(*rst, 2),
+ CreateMockRead(altsvc_frame, 1), CreateMockRead(rst, 2),
MockRead(ASYNC, 0, 3) // EOF
};
const char request_origin[] = "https://mail.example.org";
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(request_origin, 1, MEDIUM));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
+ CreateMockWrite(req, 0),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
@@ -5565,17 +5222,15 @@ TEST_P(AltSvcFrameTest, ProcessAltSvcFrameOnActiveStream) {
CreateNetworkSession();
CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 =
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
- GURL(request_origin), MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
+ SPDY_REQUEST_RESPONSE_STREAM, session_, GURL(request_origin), MEDIUM,
+ NetLogWithSource());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(request_origin)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(request_origin));
spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
base::RunLoop().RunUntilIdle();
@@ -5595,23 +5250,23 @@ TEST_P(AltSvcFrameTest, ProcessAltSvcFrameOnActiveStream) {
EXPECT_EQ(443u, altsvc_vector[0].port);
}
-TEST_P(AltSvcFrameTest, DoNotProcessAltSvcFrameOnStreamWithInsecureOrigin) {
+TEST_F(AltSvcFrameTest, DoNotProcessAltSvcFrameOnStreamWithInsecureOrigin) {
SpdyAltSvcIR altsvc_ir(1);
altsvc_ir.add_altsvc(alternative_service_);
SpdySerializedFrame altsvc_frame(spdy_util_.SerializeFrame(altsvc_ir));
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM));
MockRead reads[] = {
- CreateMockRead(altsvc_frame, 1), CreateMockRead(*rst, 2),
+ CreateMockRead(altsvc_frame, 1), CreateMockRead(rst, 2),
MockRead(ASYNC, 0, 3) // EOF
};
const char request_origin[] = "http://mail.example.org";
- std::unique_ptr<SpdySerializedFrame> req(
+ SpdySerializedFrame req(
spdy_util_.ConstructSpdyGet(request_origin, 1, MEDIUM));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
+ CreateMockWrite(req, 0),
};
SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
session_deps_.socket_factory->AddSocketDataProvider(&data);
@@ -5621,17 +5276,15 @@ TEST_P(AltSvcFrameTest, DoNotProcessAltSvcFrameOnStreamWithInsecureOrigin) {
CreateNetworkSession();
CreateSecureSpdySession();
- base::WeakPtr<SpdyStream> spdy_stream1 =
- CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
- GURL(request_origin), MEDIUM, BoundNetLog());
+ base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
+ SPDY_REQUEST_RESPONSE_STREAM, session_, GURL(request_origin), MEDIUM,
+ NetLogWithSource());
test::StreamDelegateDoNothing delegate1(spdy_stream1);
spdy_stream1->SetDelegate(&delegate1);
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(request_origin)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(request_origin));
spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND);
- EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
base::RunLoop().RunUntilIdle();
@@ -5648,7 +5301,7 @@ TEST_P(AltSvcFrameTest, DoNotProcessAltSvcFrameOnStreamWithInsecureOrigin) {
ASSERT_TRUE(altsvc_vector.empty());
}
-TEST_P(AltSvcFrameTest, DoNotProcessAltSvcFrameOnNonExistentStream) {
+TEST_F(AltSvcFrameTest, DoNotProcessAltSvcFrameOnNonExistentStream) {
SpdyAltSvcIR altsvc_ir(1);
altsvc_ir.add_altsvc(alternative_service_);
AddSocketData(altsvc_ir);
diff --git a/chromium/net/spdy/spdy_stream.cc b/chromium/net/spdy/spdy_stream.cc
index 09083a00f28..87e3aea75c9 100644
--- a/chromium/net/spdy/spdy_stream.cc
+++ b/chromium/net/spdy/spdy_stream.cc
@@ -18,6 +18,9 @@
#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
#include "net/spdy/spdy_buffer_producer.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/spdy/spdy_session.h"
@@ -50,7 +53,7 @@ std::unique_ptr<base::Value> NetLogSpdyStreamWindowUpdateCallback(
return std::move(dict);
}
-bool ContainsUppercaseAscii(const std::string& str) {
+bool ContainsUppercaseAscii(base::StringPiece str) {
return std::any_of(str.begin(), str.end(), base::IsAsciiUpper<char>);
}
@@ -58,15 +61,15 @@ bool ContainsUppercaseAscii(const std::string& str) {
void SpdyStream::Delegate::OnTrailers(const SpdyHeaderBlock& trailers) {}
-// A wrapper around a stream that calls into ProduceSynStreamFrame().
-class SpdyStream::SynStreamBufferProducer : public SpdyBufferProducer {
+// A wrapper around a stream that calls into ProduceHeadersFrame().
+class SpdyStream::HeadersBufferProducer : public SpdyBufferProducer {
public:
- SynStreamBufferProducer(const base::WeakPtr<SpdyStream>& stream)
+ HeadersBufferProducer(const base::WeakPtr<SpdyStream>& stream)
: stream_(stream) {
DCHECK(stream_.get());
}
- ~SynStreamBufferProducer() override {}
+ ~HeadersBufferProducer() override {}
std::unique_ptr<SpdyBuffer> ProduceBuffer() override {
if (!stream_.get()) {
@@ -75,7 +78,7 @@ class SpdyStream::SynStreamBufferProducer : public SpdyBufferProducer {
}
DCHECK_GT(stream_->stream_id(), 0u);
return std::unique_ptr<SpdyBuffer>(
- new SpdyBuffer(stream_->ProduceSynStreamFrame()));
+ new SpdyBuffer(stream_->ProduceHeadersFrame()));
}
private:
@@ -88,7 +91,7 @@ SpdyStream::SpdyStream(SpdyStreamType type,
RequestPriority priority,
int32_t initial_send_window_size,
int32_t max_recv_window_size,
- const BoundNetLog& net_log)
+ const NetLogWithSource& net_log)
: type_(type),
stream_id_(0),
url_(url),
@@ -100,6 +103,7 @@ SpdyStream::SpdyStream(SpdyStreamType type,
unacked_recv_window_bytes_(0),
session_(session),
delegate_(NULL),
+ request_headers_valid_(false),
pending_send_status_(MORE_DATA_TO_SEND),
request_time_(base::Time::Now()),
response_headers_status_(RESPONSE_HEADERS_ARE_INCOMPLETE),
@@ -199,16 +203,17 @@ void SpdyStream::PushedStreamReplay() {
}
}
-std::unique_ptr<SpdySerializedFrame> SpdyStream::ProduceSynStreamFrame() {
+std::unique_ptr<SpdySerializedFrame> SpdyStream::ProduceHeadersFrame() {
CHECK_EQ(io_state_, STATE_IDLE);
- CHECK(request_headers_);
+ CHECK(request_headers_valid_);
CHECK_GT(stream_id_, 0u);
SpdyControlFlags flags =
(pending_send_status_ == NO_MORE_DATA_TO_SEND) ?
CONTROL_FLAG_FIN : CONTROL_FLAG_NONE;
- std::unique_ptr<SpdySerializedFrame> frame(session_->CreateSynStream(
- stream_id_, priority_, flags, request_headers_->Clone()));
+ std::unique_ptr<SpdySerializedFrame> frame(session_->CreateHeaders(
+ stream_id_, priority_, flags, std::move(request_headers_)));
+ request_headers_valid_ = false;
send_time_ = base::TimeTicks::Now();
return frame;
}
@@ -277,7 +282,7 @@ void SpdyStream::IncreaseSendWindowSize(int32_t delta_window_size) {
send_window_size_ += delta_window_size;
net_log_.AddEvent(
- NetLog::TYPE_HTTP2_STREAM_UPDATE_SEND_WINDOW,
+ NetLogEventType::HTTP2_STREAM_UPDATE_SEND_WINDOW,
base::Bind(&NetLogSpdyStreamWindowUpdateCallback, stream_id_,
delta_window_size, send_window_size_));
@@ -300,7 +305,7 @@ void SpdyStream::DecreaseSendWindowSize(int32_t delta_window_size) {
send_window_size_ -= delta_window_size;
net_log_.AddEvent(
- NetLog::TYPE_HTTP2_STREAM_UPDATE_SEND_WINDOW,
+ NetLogEventType::HTTP2_STREAM_UPDATE_SEND_WINDOW,
base::Bind(&NetLogSpdyStreamWindowUpdateCallback, stream_id_,
-delta_window_size, send_window_size_));
}
@@ -329,7 +334,7 @@ void SpdyStream::IncreaseRecvWindowSize(int32_t delta_window_size) {
recv_window_size_ += delta_window_size;
net_log_.AddEvent(
- NetLog::TYPE_HTTP2_STREAM_UPDATE_RECV_WINDOW,
+ NetLogEventType::HTTP2_STREAM_UPDATE_RECV_WINDOW,
base::Bind(&NetLogSpdyStreamWindowUpdateCallback, stream_id_,
delta_window_size, recv_window_size_));
@@ -359,7 +364,7 @@ void SpdyStream::DecreaseRecvWindowSize(int32_t delta_window_size) {
recv_window_size_ -= delta_window_size;
net_log_.AddEvent(
- NetLog::TYPE_HTTP2_STREAM_UPDATE_RECV_WINDOW,
+ NetLogEventType::HTTP2_STREAM_UPDATE_RECV_WINDOW,
base::Bind(&NetLogSpdyStreamWindowUpdateCallback, stream_id_,
-delta_window_size, recv_window_size_));
}
@@ -463,14 +468,16 @@ int SpdyStream::OnAdditionalResponseHeadersReceived(
return MergeWithResponseHeaders(additional_response_headers);
}
-void SpdyStream::OnPushPromiseHeadersReceived(const SpdyHeaderBlock& headers) {
- CHECK(!request_headers_.get());
+void SpdyStream::OnPushPromiseHeadersReceived(SpdyHeaderBlock headers) {
+ CHECK(!request_headers_valid_);
CHECK_EQ(io_state_, STATE_IDLE);
CHECK_EQ(type_, SPDY_PUSH_STREAM);
DCHECK(!delegate_);
io_state_ = STATE_RESERVED_REMOTE;
- request_headers_.reset(new SpdyHeaderBlock(headers.Clone()));
+ request_headers_ = std::move(headers);
+ request_headers_valid_ = true;
+ url_from_header_block_ = GetUrlFromHeaderBlock(request_headers_);
}
void SpdyStream::OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) {
@@ -561,11 +568,10 @@ void SpdyStream::OnPaddingConsumed(size_t len) {
void SpdyStream::OnFrameWriteComplete(SpdyFrameType frame_type,
size_t frame_size) {
DCHECK_NE(type_, SPDY_PUSH_STREAM);
- CHECK(frame_type == SYN_STREAM ||
- frame_type == DATA) << frame_type;
+ CHECK(frame_type == HEADERS || frame_type == DATA) << frame_type;
- int result = (frame_type == SYN_STREAM) ?
- OnRequestHeadersSent() : OnDataSent(frame_size);
+ int result =
+ (frame_type == HEADERS) ? OnRequestHeadersSent() : OnDataSent(frame_size);
if (result == ERR_IO_PENDING) {
// The write operation hasn't completed yet.
return;
@@ -585,7 +591,7 @@ void SpdyStream::OnFrameWriteComplete(SpdyFrameType frame_type,
{
base::WeakPtr<SpdyStream> weak_this = GetWeakPtr();
write_handler_guard_ = true;
- if (frame_type == SYN_STREAM) {
+ if (frame_type == HEADERS) {
delegate_->OnRequestHeadersSent();
} else {
delegate_->OnDataSent();
@@ -631,12 +637,8 @@ int SpdyStream::OnDataSent(size_t frame_size) {
}
}
-SpdyMajorVersion SpdyStream::GetProtocolVersion() const {
- return session_->GetProtocolVersion();
-}
-
void SpdyStream::LogStreamError(int status, const std::string& description) {
- net_log_.AddEvent(NetLog::TYPE_HTTP2_STREAM_ERROR,
+ net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_ERROR,
base::Bind(&NetLogSpdyStreamErrorCallback, stream_id_,
status, &description));
}
@@ -684,19 +686,20 @@ base::WeakPtr<SpdyStream> SpdyStream::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
-int SpdyStream::SendRequestHeaders(
- std::unique_ptr<SpdyHeaderBlock> request_headers,
- SpdySendStatus send_status) {
+int SpdyStream::SendRequestHeaders(SpdyHeaderBlock request_headers,
+ SpdySendStatus send_status) {
CHECK_NE(type_, SPDY_PUSH_STREAM);
CHECK_EQ(pending_send_status_, MORE_DATA_TO_SEND);
- CHECK(!request_headers_);
+ CHECK(!request_headers_valid_);
CHECK(!pending_send_data_.get());
CHECK_EQ(io_state_, STATE_IDLE);
request_headers_ = std::move(request_headers);
+ request_headers_valid_ = true;
+ url_from_header_block_ = GetUrlFromHeaderBlock(request_headers_);
pending_send_status_ = send_status;
- session_->EnqueueStreamWrite(GetWeakPtr(), SYN_STREAM,
+ session_->EnqueueStreamWrite(GetWeakPtr(), HEADERS,
std::unique_ptr<SpdyBufferProducer>(
- new SynStreamBufferProducer(GetWeakPtr())));
+ new HeadersBufferProducer(GetWeakPtr())));
return ERR_IO_PENDING;
}
@@ -713,11 +716,16 @@ void SpdyStream::SendData(IOBuffer* data,
QueueNextDataFrame();
}
-bool SpdyStream::GetSSLInfo(SSLInfo* ssl_info,
- bool* was_npn_negotiated,
- NextProto* protocol_negotiated) {
- return session_->GetSSLInfo(
- ssl_info, was_npn_negotiated, protocol_negotiated);
+bool SpdyStream::GetSSLInfo(SSLInfo* ssl_info) const {
+ return session_->GetSSLInfo(ssl_info);
+}
+
+bool SpdyStream::WasNpnNegotiated() const {
+ return session_->WasNpnNegotiated();
+}
+
+NextProto SpdyStream::GetNegotiatedProtocol() const {
+ return session_->GetNegotiatedProtocol();
}
void SpdyStream::PossiblyResumeIfSendStalled() {
@@ -726,7 +734,7 @@ void SpdyStream::PossiblyResumeIfSendStalled() {
}
if (send_stalled_by_flow_control_ && !session_->IsSendStalled() &&
send_window_size_ > 0) {
- net_log_.AddEvent(NetLog::TYPE_HTTP2_STREAM_FLOW_CONTROL_UNSTALLED,
+ net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_FLOW_CONTROL_UNSTALLED,
NetLog::IntCallback("stream_id", stream_id_));
send_stalled_by_flow_control_ = false;
QueueNextDataFrame();
@@ -755,10 +763,6 @@ bool SpdyStream::IsReservedRemote() const {
return io_state_ == STATE_RESERVED_REMOTE;
}
-NextProto SpdyStream::GetProtocol() const {
- return session_->protocol();
-}
-
void SpdyStream::AddRawReceivedBytes(size_t received_bytes) {
raw_received_bytes_ += received_bytes;
}
@@ -781,17 +785,6 @@ bool SpdyStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
return result;
}
-GURL SpdyStream::GetUrlFromHeaders() const {
- if (!request_headers_)
- return GURL();
-
- return GetUrlFromHeaderBlock(*request_headers_, GetProtocolVersion());
-}
-
-bool SpdyStream::HasUrlFromHeaders() const {
- return !GetUrlFromHeaders().is_empty();
-}
-
void SpdyStream::UpdateHistograms() {
// We need at least the receive timers to be filled in, as otherwise
// metrics can be bogus.
@@ -881,15 +874,14 @@ int SpdyStream::MergeWithResponseHeaders(
for (SpdyHeaderBlock::const_iterator it = new_response_headers.begin();
it != new_response_headers.end(); ++it) {
// Disallow uppercase headers.
- if (ContainsUppercaseAscii(it->first.as_string())) {
+ if (ContainsUppercaseAscii(it->first)) {
session_->ResetStream(
stream_id_, RST_STREAM_PROTOCOL_ERROR,
"Upper case characters in header: " + it->first.as_string());
return ERR_SPDY_PROTOCOL_ERROR;
}
- SpdyHeaderBlock::iterator it2 =
- response_headers_.find(it->first.as_string());
+ SpdyHeaderBlock::iterator it2 = response_headers_.find(it->first);
// Disallow duplicate headers. This is just to be conservative.
if (it2 != response_headers_.end()) {
session_->ResetStream(stream_id_, RST_STREAM_PROTOCOL_ERROR,
diff --git a/chromium/net/spdy/spdy_stream.h b/chromium/net/spdy/spdy_stream.h
index 499372a9ca8..ffa3334799f 100644
--- a/chromium/net/spdy/spdy_stream.h
+++ b/chromium/net/spdy/spdy_stream.h
@@ -19,7 +19,8 @@
#include "net/base/io_buffer.h"
#include "net/base/net_export.h"
#include "net/base/request_priority.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
+#include "net/socket/next_proto.h"
#include "net/socket/ssl_client_socket.h"
#include "net/spdy/spdy_buffer.h"
#include "net/spdy/spdy_framer.h"
@@ -172,7 +173,7 @@ class NET_EXPORT_PRIVATE SpdyStream {
RequestPriority priority,
int32_t initial_send_window_size,
int32_t max_recv_window_size,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
~SpdyStream();
@@ -286,15 +287,14 @@ class NET_EXPORT_PRIVATE SpdyStream {
// writes.
bool WasEverUsed() const;
- const BoundNetLog& net_log() const { return net_log_; }
+ const NetLogWithSource& net_log() const { return net_log_; }
base::Time GetRequestTime() const;
void SetRequestTime(base::Time t);
- // Called at most once by the SpdySession when the initial response
- // headers have been received for this stream, i.e., a SYN_REPLY (or
- // SYN_STREAM for push streams) frame has been received. Returns a status
- // code; if it is an error, the stream was closed by this function.
+ // Called at most once by the SpdySession when the initial response headers
+ // have been received for this stream. Returns a status code; if it is an
+ // error, the stream was closed by this function.
int OnInitialResponseHeadersReceived(const SpdyHeaderBlock& response_headers,
base::Time response_time,
base::TimeTicks recv_first_byte_time);
@@ -308,7 +308,7 @@ class NET_EXPORT_PRIVATE SpdyStream {
// Called by the SpdySession when a frame carrying request headers opening a
// push stream is received. Stream transits to STATE_RESERVED_REMOTE state.
- void OnPushPromiseHeadersReceived(const SpdyHeaderBlock& headers);
+ void OnPushPromiseHeadersReceived(SpdyHeaderBlock headers);
// Called by the SpdySession when response data has been received
// for this stream. This callback may be called multiple times as
@@ -333,7 +333,7 @@ class NET_EXPORT_PRIVATE SpdyStream {
// of the HEADERS or PUSH_PROMISE frame and subsequent CONTINUATION frames.
void OnFrameWriteComplete(SpdyFrameType frame_type, size_t frame_size);
- // SYN_STREAM-specific write handler invoked by OnFrameWriteComplete().
+ // HEADERS-specific write handler invoked by OnFrameWriteComplete().
int OnRequestHeadersSent();
// DATA-specific write handler invoked by OnFrameWriteComplete().
@@ -373,7 +373,7 @@ class NET_EXPORT_PRIVATE SpdyStream {
// bidirectional streams; for request/response streams, it must be
// MORE_DATA_TO_SEND if the request has data to upload, or
// NO_MORE_DATA_TO_SEND if not.
- int SendRequestHeaders(std::unique_ptr<SpdyHeaderBlock> request_headers,
+ int SendRequestHeaders(SpdyHeaderBlock request_headers,
SpdySendStatus send_status);
// Sends a DATA frame. The delegate will be notified via
@@ -384,9 +384,14 @@ class NET_EXPORT_PRIVATE SpdyStream {
void SendData(IOBuffer* data, int length, SpdySendStatus send_status);
// Fills SSL info in |ssl_info| and returns true when SSL is in use.
- bool GetSSLInfo(SSLInfo* ssl_info,
- bool* was_npn_negotiated,
- NextProto* protocol_negotiated);
+ bool GetSSLInfo(SSLInfo* ssl_info) const;
+
+ // Returns true if ALPN was negotiated for the underlying socket.
+ // TODO(bnc): Rename to WasAlpnNegotiated().
+ bool WasNpnNegotiated() const;
+
+ // Returns the protocol negotiated via ALPN for the underlying socket.
+ NextProto GetNegotiatedProtocol() const;
// If the stream is stalled on sending data, but the session is not
// stalled on sending data and |send_window_size_| is positive, then
@@ -417,10 +422,6 @@ class NET_EXPORT_PRIVATE SpdyStream {
// yet.
bool IsReservedRemote() const;
- // Returns the protocol used by this stream. Always between
- // kProtoSPDYMinimumVersion and kProtoSPDYMaximumVersion.
- NextProto GetProtocol() const;
-
int response_status() const { return response_status_; }
void AddRawReceivedBytes(size_t received_bytes);
@@ -433,29 +434,16 @@ class NET_EXPORT_PRIVATE SpdyStream {
// Get the URL from the appropriate stream headers, or the empty
// GURL() if it is unknown.
- //
- // TODO(akalin): Figure out if we really need this function,
- // i.e. can we just use the URL this stream was created with and/or
- // one we receive headers validate that the URL from them is the
- // same.
- GURL GetUrlFromHeaders() const;
-
- // Returns whether the URL for this stream is known.
- //
- // TODO(akalin): Remove this, as it's only used in tests.
- bool HasUrlFromHeaders() const;
-
- SpdyMajorVersion GetProtocolVersion() const;
+ const GURL& GetUrlFromHeaders() const { return url_from_header_block_; }
private:
- class SynStreamBufferProducer;
- class HeaderBufferProducer;
+ class HeadersBufferProducer;
// SpdyStream states and transitions are modeled
// on the HTTP/2 stream state machine. All states and transitions
// are modeled, with the exceptions of RESERVED_LOCAL (the client
// cannot initate push streams), and the transition to OPEN due to
- // a remote SYN_STREAM (the client can only initate streams).
+ // a remote HEADERS (the client can only initate streams).
enum State {
STATE_IDLE,
STATE_OPEN,
@@ -479,14 +467,9 @@ class NET_EXPORT_PRIVATE SpdyStream {
// to have occurred, driving the state machine forward.
void PushedStreamReplay();
- // Produces the SYN_STREAM frame for the stream. The stream must
+ // Produces the HEADERS frame for the stream. The stream must
// already be activated.
- std::unique_ptr<SpdySerializedFrame> ProduceSynStreamFrame();
-
- // Produce the initial HEADER frame for the stream with the given
- // block. The stream must already be activated.
- std::unique_ptr<SpdySerializedFrame> ProduceHeaderFrame(
- std::unique_ptr<SpdyHeaderBlock> header_block);
+ std::unique_ptr<SpdySerializedFrame> ProduceHeadersFrame();
// Queues the send for next frame of the remaining data in
// |pending_send_data_|. Must be called only when
@@ -533,10 +516,11 @@ class NET_EXPORT_PRIVATE SpdyStream {
SpdyStream::Delegate* delegate_;
// The headers for the request to send.
- //
- // TODO(akalin): Hang onto this only until we send it. This
- // necessitates stashing the URL separately.
- std::unique_ptr<SpdyHeaderBlock> request_headers_;
+ bool request_headers_valid_;
+ SpdyHeaderBlock request_headers_;
+
+ // The URL from the request headers.
+ GURL url_from_header_block_;
// Data waiting to be sent, and the close state of the local endpoint
// after the data is fully written.
@@ -563,7 +547,7 @@ class NET_EXPORT_PRIVATE SpdyStream {
// Not valid until the stream is closed.
int response_status_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
base::TimeTicks send_time_;
base::TimeTicks recv_first_byte_time_;
diff --git a/chromium/net/spdy/spdy_stream_test_util.cc b/chromium/net/spdy/spdy_stream_test_util.cc
index cbc53c2db4c..9b250b2f074 100644
--- a/chromium/net/spdy/spdy_stream_test_util.cc
+++ b/chromium/net/spdy/spdy_stream_test_util.cc
@@ -92,9 +92,8 @@ std::string StreamDelegateBase::TakeReceivedData() {
size_t len = received_data_queue_.GetTotalSize();
std::string received_data(len, '\0');
if (len > 0) {
- EXPECT_EQ(
- len,
- received_data_queue_.Dequeue(string_as_array(&received_data), len));
+ EXPECT_EQ(len, received_data_queue_.Dequeue(
+ base::string_as_array(&received_data), len));
}
return received_data;
}
diff --git a/chromium/net/spdy/spdy_stream_unittest.cc b/chromium/net/spdy/spdy_stream_unittest.cc
index f21d14b692a..298b6a20c60 100644
--- a/chromium/net/spdy/spdy_stream_unittest.cc
+++ b/chromium/net/spdy/spdy_stream_unittest.cc
@@ -18,10 +18,10 @@
#include "base/strings/string_piece.h"
#include "net/base/completion_callback.h"
#include "net/base/request_priority.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/next_proto.h"
#include "net/socket/socket_test_util.h"
#include "net/spdy/buffered_spdy_framer.h"
#include "net/spdy/spdy_http_utils.h"
@@ -29,8 +29,15 @@
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_stream_test_util.h"
#include "net/spdy/spdy_test_util_common.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
// TODO(ukai): factor out common part with spdy_http_stream_unittest.cc
//
namespace net {
@@ -39,19 +46,6 @@ namespace test {
namespace {
-enum TestCase {
- // Test using the SPDY/3.1 protocol.
- kTestCaseSPDY31,
-
- // Test using the HTTP/2 protocol, without specifying a stream
- // dependency based on the RequestPriority.
- kTestCaseHTTP2NoPriorityDependencies,
-
- // Test using the HTTP/2 protocol, specifying a stream
- // dependency based on the RequestPriority.
- kTestCaseHTTP2PriorityDependencies
-};
-
const char kStreamUrl[] = "http://www.example.org/";
const char kPostBody[] = "\0hello!\xff";
const size_t kPostBodyLength = arraysize(kPostBody);
@@ -59,42 +53,28 @@ const base::StringPiece kPostBodyStringPiece(kPostBody, kPostBodyLength);
} // namespace
-class SpdyStreamTest : public ::testing::Test,
- public ::testing::WithParamInterface<TestCase> {
+class SpdyStreamTest : public ::testing::Test {
protected:
// A function that takes a SpdyStream and the number of bytes which
// will unstall the next frame completely.
typedef base::Callback<void(const base::WeakPtr<SpdyStream>&, int32_t)>
UnstallFunction;
- SpdyStreamTest()
- : spdy_util_(GetProtocol(), GetDependenciesFromPriority()),
- session_deps_(GetProtocol()),
- offset_(0) {
+ SpdyStreamTest() : offset_(0), ssl_(SYNCHRONOUS, OK) {
spdy_util_.set_default_url(GURL(kStreamUrl));
- session_deps_.enable_priority_dependencies = GetDependenciesFromPriority();
session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
}
- ~SpdyStreamTest() {
- }
+ ~SpdyStreamTest() override {}
base::WeakPtr<SpdySession> CreateDefaultSpdySession() {
SpdySessionKey key(HostPortPair("www.example.org", 80),
ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
- return CreateInsecureSpdySession(session_.get(), key, BoundNetLog());
+ return CreateSecureSpdySession(session_.get(), key, NetLogWithSource());
}
void TearDown() override { base::RunLoop().RunUntilIdle(); }
- NextProto GetProtocol() const {
- return GetParam() == kTestCaseSPDY31 ? kProtoSPDY31 : kProtoHTTP2;
- }
-
- bool GetDependenciesFromPriority() const {
- return GetParam() == kTestCaseHTTP2PriorityDependencies;
- }
-
void RunResumeAfterUnstallRequestResponseTest(
const UnstallFunction& unstall_function);
@@ -143,6 +123,14 @@ class SpdyStreamTest : public ::testing::Test,
session->InsertActivatedStream(std::move(activated));
}
+ void AddSSLSocketData() {
+ // Load a cert that is valid for
+ // www.example.org, mail.example.org, and mail.example.com.
+ ssl_.cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
+ ASSERT_TRUE(ssl_.cert);
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_);
+ }
+
SpdyTestUtil spdy_util_;
SpdySessionDependencies session_deps_;
std::unique_ptr<HttpNetworkSession> session_;
@@ -152,32 +140,26 @@ class SpdyStreamTest : public ::testing::Test,
std::vector<MockWrite> writes_;
std::vector<MockRead> reads_;
int offset_;
+ SSLSocketDataProvider ssl_;
};
-INSTANTIATE_TEST_CASE_P(ProtoPlusDepend,
- SpdyStreamTest,
- testing::Values(kTestCaseSPDY31,
- kTestCaseHTTP2NoPriorityDependencies,
- kTestCaseHTTP2PriorityDependencies));
-
-TEST_P(SpdyStreamTest, SendDataAfterOpen) {
+TEST_F(SpdyStreamTest, SendDataAfterOpen) {
GURL url(kStreamUrl);
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
- AddWrite(*req);
+ AddWrite(req);
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
- AddRead(*resp);
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(NULL, 0));
+ AddRead(resp);
- std::unique_ptr<SpdySerializedFrame> msg(
- spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
- AddWrite(*msg);
+ SpdySerializedFrame msg(
+ spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false));
+ AddWrite(msg);
- std::unique_ptr<SpdySerializedFrame> echo(
- spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
- AddRead(*echo);
+ SpdySerializedFrame echo(
+ spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false));
+ AddRead(echo);
AddReadEOF();
@@ -185,29 +167,28 @@ TEST_P(SpdyStreamTest, SendDataAfterOpen) {
GetNumWrites());
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
-
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
- base::WeakPtr<SpdyStream> stream =
- CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
+ SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream);
StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
stream->SetDelegate(&delegate);
- EXPECT_FALSE(stream->HasUrlFromHeaders());
+ EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
- std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)));
+ SpdyHeaderBlock headers(
+ spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
EXPECT_TRUE(delegate.send_headers_completed());
EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
@@ -236,31 +217,29 @@ class StreamDelegateWithTrailers : public test::StreamDelegateWithBody {
};
// Regression test for crbug.com/481033.
-TEST_P(SpdyStreamTest, Trailers) {
+TEST_F(SpdyStreamTest, Trailers) {
GURL url(kStreamUrl);
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
- AddWrite(*req);
+ AddWrite(req);
- std::unique_ptr<SpdySerializedFrame> msg(
- spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
- AddWrite(*msg);
+ SpdySerializedFrame msg(
+ spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true));
+ AddWrite(msg);
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
- AddRead(*resp);
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(NULL, 0));
+ AddRead(resp);
- std::unique_ptr<SpdySerializedFrame> echo(
- spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
- AddRead(*echo);
+ SpdySerializedFrame echo(
+ spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false));
+ AddRead(echo);
SpdyHeaderBlock late_headers;
late_headers["foo"] = "bar";
- std::unique_ptr<SpdySerializedFrame> trailers(
- spdy_util_.ConstructSpdyResponseHeaders(1, std::move(late_headers),
- false));
- AddRead(*trailers);
+ SpdySerializedFrame trailers(spdy_util_.ConstructSpdyResponseHeaders(
+ 1, std::move(late_headers), false));
+ AddRead(trailers);
AddReadEOF();
@@ -268,28 +247,28 @@ TEST_P(SpdyStreamTest, Trailers) {
GetNumWrites());
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
-
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
+ SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream);
StreamDelegateWithTrailers delegate(stream, kPostBodyStringPiece);
stream->SetDelegate(&delegate);
- EXPECT_FALSE(stream->HasUrlFromHeaders());
+ EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
- std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)));
+ SpdyHeaderBlock headers(
+ spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
EXPECT_TRUE(delegate.send_headers_completed());
EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
@@ -301,40 +280,40 @@ TEST_P(SpdyStreamTest, Trailers) {
EXPECT_TRUE(data.AllWriteDataConsumed());
}
-TEST_P(SpdyStreamTest, PushedStream) {
+TEST_F(SpdyStreamTest, PushedStream) {
AddReadEOF();
SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(),
GetNumWrites());
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
-
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
base::WeakPtr<SpdySession> spdy_session(CreateDefaultSpdySession());
// Conjure up a stream.
SpdyStreamRequest stream_request;
- int result = stream_request.StartRequest(SPDY_PUSH_STREAM, spdy_session,
- GURL(), DEFAULT_PRIORITY,
- BoundNetLog(), CompletionCallback());
- ASSERT_EQ(OK, result);
+ int result = stream_request.StartRequest(
+ SPDY_PUSH_STREAM, spdy_session, GURL(), DEFAULT_PRIORITY,
+ NetLogWithSource(), CompletionCallback());
+ ASSERT_THAT(result, IsOk());
base::WeakPtr<SpdyStream> stream = stream_request.ReleaseStream();
ActivatePushStream(spdy_session.get(), stream.get());
- EXPECT_FALSE(stream->HasUrlFromHeaders());
+ EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
// Set required request headers.
SpdyHeaderBlock request_headers;
spdy_util_.AddUrlToHeaderBlock(kStreamUrl, &request_headers);
- stream->OnPushPromiseHeadersReceived(request_headers);
+ stream->OnPushPromiseHeadersReceived(std::move(request_headers));
base::Time response_time = base::Time::Now();
base::TimeTicks first_byte_time = base::TimeTicks::Now();
// Send some basic response headers.
SpdyHeaderBlock response;
response[spdy_util_.GetStatusKey()] = "200";
- response[spdy_util_.GetVersionKey()] = "OK";
stream->OnInitialResponseHeadersReceived(response, response_time,
first_byte_time);
@@ -344,7 +323,6 @@ TEST_P(SpdyStreamTest, PushedStream) {
headers["alpha"] = "beta";
stream->OnAdditionalResponseHeadersReceived(headers);
- EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
StreamDelegateDoNothing delegate(stream->GetWeakPtr());
@@ -368,24 +346,23 @@ TEST_P(SpdyStreamTest, PushedStream) {
EXPECT_FALSE(spdy_session);
}
-TEST_P(SpdyStreamTest, StreamError) {
+TEST_F(SpdyStreamTest, StreamError) {
GURL url(kStreamUrl);
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
- AddWrite(*req);
+ AddWrite(req);
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- AddRead(*resp);
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ AddRead(resp);
- std::unique_ptr<SpdySerializedFrame> msg(
- spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
- AddWrite(*msg);
+ SpdySerializedFrame msg(
+ spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false));
+ AddWrite(msg);
- std::unique_ptr<SpdySerializedFrame> echo(
- spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
- AddRead(*echo);
+ SpdySerializedFrame echo(
+ spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false));
+ AddRead(echo);
AddReadEOF();
@@ -395,9 +372,10 @@ TEST_P(SpdyStreamTest, StreamError) {
GetNumWrites());
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
-
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
base::WeakPtr<SpdyStream> stream =
@@ -408,16 +386,15 @@ TEST_P(SpdyStreamTest, StreamError) {
StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
stream->SetDelegate(&delegate);
- EXPECT_FALSE(stream->HasUrlFromHeaders());
+ EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
- std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)));
+ SpdyHeaderBlock headers(
+ spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
const SpdyStreamId stream_id = delegate.stream_id();
@@ -434,7 +411,7 @@ TEST_P(SpdyStreamTest, StreamError) {
// Check that we logged SPDY_STREAM_ERROR correctly.
int pos = ExpectLogContainsSomewhere(
- entries, 0, NetLog::TYPE_HTTP2_STREAM_ERROR, NetLog::PHASE_NONE);
+ entries, 0, NetLogEventType::HTTP2_STREAM_ERROR, NetLogEventPhase::NONE);
int stream_id2;
ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id2));
@@ -444,27 +421,25 @@ TEST_P(SpdyStreamTest, StreamError) {
// Make sure that large blocks of data are properly split up into
// frame-sized chunks for a request/response (i.e., an HTTP-like)
// stream.
-TEST_P(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) {
+TEST_F(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) {
GURL url(kStreamUrl);
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
- AddWrite(*req);
+ AddWrite(req);
std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
- std::unique_ptr<SpdySerializedFrame> chunk(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame chunk(spdy_util_.ConstructSpdyDataFrame(
1, chunk_data.data(), chunk_data.length(), false));
- AddWrite(*chunk);
- AddWrite(*chunk);
+ AddWrite(chunk);
+ AddWrite(chunk);
- std::unique_ptr<SpdySerializedFrame> last_chunk(
- spdy_util_.ConstructSpdyBodyFrame(1, chunk_data.data(),
- chunk_data.length(), true));
- AddWrite(*last_chunk);
+ SpdySerializedFrame last_chunk(spdy_util_.ConstructSpdyDataFrame(
+ 1, chunk_data.data(), chunk_data.length(), true));
+ AddWrite(last_chunk);
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
- AddRead(*resp);
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(NULL, 0));
+ AddRead(resp);
AddReadEOF();
@@ -472,30 +447,29 @@ TEST_P(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) {
GetNumWrites());
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
-
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
- base::WeakPtr<SpdyStream> stream =
- CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
+ SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream);
std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
StreamDelegateWithBody delegate(stream, body_data);
stream->SetDelegate(&delegate);
- EXPECT_FALSE(stream->HasUrlFromHeaders());
+ EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
- std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)));
+ SpdyHeaderBlock headers(
+ spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
EXPECT_TRUE(delegate.send_headers_completed());
EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
@@ -506,23 +480,22 @@ TEST_P(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) {
// Make sure that large blocks of data are properly split up into
// frame-sized chunks for a bidirectional (i.e., non-HTTP-like)
// stream.
-TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
+TEST_F(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
GURL url(kStreamUrl);
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
- AddWrite(*req);
+ AddWrite(req);
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
- AddRead(*resp);
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(NULL, 0));
+ AddRead(resp);
std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
- std::unique_ptr<SpdySerializedFrame> chunk(spdy_util_.ConstructSpdyBodyFrame(
+ SpdySerializedFrame chunk(spdy_util_.ConstructSpdyDataFrame(
1, chunk_data.data(), chunk_data.length(), false));
- AddWrite(*chunk);
- AddWrite(*chunk);
- AddWrite(*chunk);
+ AddWrite(chunk);
+ AddWrite(chunk);
+ AddWrite(chunk);
AddReadEOF();
@@ -530,30 +503,29 @@ TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
GetNumWrites());
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
-
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
- base::WeakPtr<SpdyStream> stream =
- CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
+ SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream);
std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x');
StreamDelegateSendImmediate delegate(stream, body_data);
stream->SetDelegate(&delegate);
- EXPECT_FALSE(stream->HasUrlFromHeaders());
+ EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
- std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)));
+ SpdyHeaderBlock headers(
+ spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
EXPECT_TRUE(delegate.send_headers_completed());
EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey()));
@@ -563,21 +535,21 @@ TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) {
// Receiving a header with uppercase ASCII should result in a protocol
// error.
-TEST_P(SpdyStreamTest, UpperCaseHeaders) {
+TEST_F(SpdyStreamTest, UpperCaseHeaders) {
GURL url(kStreamUrl);
- std::unique_ptr<SpdySerializedFrame> syn(
+ SpdySerializedFrame syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- AddWrite(*syn);
+ AddWrite(syn);
const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
- std::unique_ptr<SpdySerializedFrame> reply(
- spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
- AddRead(*reply);
+ SpdySerializedFrame reply(
+ spdy_util_.ConstructSpdyGetReply(kExtraHeaders, 1, 1));
+ AddRead(reply);
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
- AddWrite(*rst);
+ AddWrite(rst);
AddReadEOF();
@@ -585,52 +557,49 @@ TEST_P(SpdyStreamTest, UpperCaseHeaders) {
GetNumWrites());
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
-
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
- base::WeakPtr<SpdyStream> stream =
- CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
+ SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream);
StreamDelegateDoNothing delegate(stream);
stream->SetDelegate(&delegate);
- EXPECT_FALSE(stream->HasUrlFromHeaders());
+ EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kStreamUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers),
NO_MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR));
}
// Receiving a header with uppercase ASCII should result in a protocol
// error even for a push stream.
-TEST_P(SpdyStreamTest, UpperCaseHeadersOnPush) {
+TEST_F(SpdyStreamTest, UpperCaseHeadersOnPush) {
GURL url(kStreamUrl);
- std::unique_ptr<SpdySerializedFrame> syn(
+ SpdySerializedFrame syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- AddWrite(*syn);
+ AddWrite(syn);
- std::unique_ptr<SpdySerializedFrame> reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- AddRead(*reply);
+ SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ AddRead(reply);
const char* const extra_headers[] = {"X-UpperCase", "yes"};
- std::unique_ptr<SpdySerializedFrame> push(
+ SpdySerializedFrame push(
spdy_util_.ConstructSpdyPush(extra_headers, 1, 2, 1, kStreamUrl));
- AddRead(*push);
+ AddRead(push);
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
- AddWrite(*rst);
+ AddWrite(rst);
AddReadPause();
@@ -640,69 +609,67 @@ TEST_P(SpdyStreamTest, UpperCaseHeadersOnPush) {
GetNumWrites());
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
-
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
- base::WeakPtr<SpdyStream> stream =
- CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
+ SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream);
StreamDelegateDoNothing delegate(stream);
stream->SetDelegate(&delegate);
- EXPECT_FALSE(stream->HasUrlFromHeaders());
+ EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kStreamUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers),
NO_MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
data.RunUntilPaused();
base::WeakPtr<SpdyStream> push_stream;
- EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
+ EXPECT_THAT(session->GetPushStream(url, &push_stream, NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(push_stream);
data.Resume();
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
}
// Receiving a header with uppercase ASCII in a HEADERS frame should
// result in a protocol error.
-TEST_P(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
+TEST_F(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
GURL url(kStreamUrl);
- std::unique_ptr<SpdySerializedFrame> syn(
+ SpdySerializedFrame syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- AddWrite(*syn);
+ AddWrite(syn);
- std::unique_ptr<SpdySerializedFrame> reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- AddRead(*reply);
+ SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ AddRead(reply);
- std::unique_ptr<SpdySerializedFrame> push(
+ SpdySerializedFrame push(
spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
- AddRead(*push);
+ AddRead(push);
AddReadPause();
SpdyHeaderBlock late_headers;
late_headers["X-UpperCase"] = "yes";
- std::unique_ptr<SpdySerializedFrame> headers_frame(
+ SpdySerializedFrame headers_frame(
spdy_util_.ConstructSpdyReply(2, std::move(late_headers)));
- AddRead(*headers_frame);
+ AddRead(headers_frame);
AddWritePause();
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
- AddWrite(*rst);
+ AddWrite(rst);
AddReadEOF();
@@ -710,75 +677,74 @@ TEST_P(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) {
GetNumWrites());
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
-
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
- base::WeakPtr<SpdyStream> stream =
- CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
+ SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream);
StreamDelegateDoNothing delegate(stream);
stream->SetDelegate(&delegate);
- EXPECT_FALSE(stream->HasUrlFromHeaders());
+ EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kStreamUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers),
NO_MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
data.RunUntilPaused();
base::WeakPtr<SpdyStream> push_stream;
- EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
+ EXPECT_THAT(session->GetPushStream(url, &push_stream, NetLogWithSource()),
+ IsOk());
EXPECT_TRUE(push_stream);
data.Resume();
data.RunUntilPaused();
- EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
+ EXPECT_THAT(session->GetPushStream(url, &push_stream, NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(push_stream);
data.Resume();
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
}
// Receiving a duplicate header in a HEADERS frame should result in a
// protocol error.
-TEST_P(SpdyStreamTest, DuplicateHeaders) {
+TEST_F(SpdyStreamTest, DuplicateHeaders) {
GURL url(kStreamUrl);
- std::unique_ptr<SpdySerializedFrame> syn(
+ SpdySerializedFrame syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- AddWrite(*syn);
+ AddWrite(syn);
- std::unique_ptr<SpdySerializedFrame> reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- AddRead(*reply);
+ SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ AddRead(reply);
- std::unique_ptr<SpdySerializedFrame> push(
+ SpdySerializedFrame push(
spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl));
- AddRead(*push);
+ AddRead(push);
AddReadPause();
SpdyHeaderBlock late_headers;
late_headers[spdy_util_.GetStatusKey()] = "500 Server Error";
- std::unique_ptr<SpdySerializedFrame> headers_frame(
+ SpdySerializedFrame headers_frame(
spdy_util_.ConstructSpdyReply(2, std::move(late_headers)));
- AddRead(*headers_frame);
+ AddRead(headers_frame);
AddReadPause();
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR));
- AddWrite(*rst);
+ AddWrite(rst);
AddReadEOF();
@@ -786,60 +752,60 @@ TEST_P(SpdyStreamTest, DuplicateHeaders) {
GetNumWrites());
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
-
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
- base::WeakPtr<SpdyStream> stream =
- CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
+ SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream);
StreamDelegateDoNothing delegate(stream);
stream->SetDelegate(&delegate);
- EXPECT_FALSE(stream->HasUrlFromHeaders());
+ EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kStreamUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers),
NO_MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
data.RunUntilPaused();
base::WeakPtr<SpdyStream> push_stream;
- EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
+ EXPECT_THAT(session->GetPushStream(url, &push_stream, NetLogWithSource()),
+ IsOk());
EXPECT_TRUE(push_stream);
data.Resume();
data.RunUntilPaused();
- EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog()));
+ EXPECT_THAT(session->GetPushStream(url, &push_stream, NetLogWithSource()),
+ IsOk());
EXPECT_FALSE(push_stream);
data.Resume();
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
}
// Call IncreaseSendWindowSize on a stream with a large enough delta
// to overflow an int32_t. The SpdyStream should handle that case
// gracefully.
-TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+TEST_F(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
- AddWrite(*req);
+ AddWrite(req);
AddReadPause();
// Triggered by the overflowing call to IncreaseSendWindowSize
// below.
- std::unique_ptr<SpdySerializedFrame> rst(
+ SpdySerializedFrame rst(
spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
- AddWrite(*rst);
+ AddWrite(rst);
AddReadEOF();
@@ -849,9 +815,10 @@ TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
GetNumWrites());
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
-
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
GURL url(kStreamUrl);
@@ -862,11 +829,10 @@ TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
stream->SetDelegate(&delegate);
- std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)));
+ SpdyHeaderBlock headers(
+ spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
data.RunUntilPaused();
@@ -881,7 +847,7 @@ TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
data.Resume();
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR));
}
// Functions used with
@@ -921,17 +887,16 @@ void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
const UnstallFunction& unstall_function) {
GURL url(kStreamUrl);
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
- AddWrite(*req);
+ AddWrite(req);
- std::unique_ptr<SpdySerializedFrame> body(
- spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true));
- AddWrite(*body);
+ SpdySerializedFrame body(
+ spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true));
+ AddWrite(body);
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- AddRead(*resp);
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ AddRead(resp);
AddReadEOF();
@@ -939,27 +904,26 @@ void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
GetNumWrites());
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
-
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
- base::WeakPtr<SpdyStream> stream =
- CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
+ SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream);
StreamDelegateWithBody delegate(stream, kPostBodyStringPiece);
stream->SetDelegate(&delegate);
- EXPECT_FALSE(stream->HasUrlFromHeaders());
+ EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
EXPECT_FALSE(stream->send_stalled_by_flow_control());
- std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)));
+ SpdyHeaderBlock headers(
+ spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
StallStream(stream);
@@ -972,7 +936,7 @@ void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
EXPECT_FALSE(stream->send_stalled_by_flow_control());
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
EXPECT_TRUE(delegate.send_headers_completed());
EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
@@ -980,12 +944,12 @@ void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest(
EXPECT_TRUE(data.AllWriteDataConsumed());
}
-TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
+TEST_F(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
RunResumeAfterUnstallRequestResponseTest(
base::Bind(&IncreaseStreamSendWindowSize));
}
-TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) {
+TEST_F(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) {
RunResumeAfterUnstallRequestResponseTest(
base::Bind(&AdjustStreamSendWindowSize));
}
@@ -997,23 +961,22 @@ void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
const UnstallFunction& unstall_function) {
GURL url(kStreamUrl);
- std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
+ SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0));
- AddWrite(*req);
+ AddWrite(req);
AddReadPause();
- std::unique_ptr<SpdySerializedFrame> resp(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- AddRead(*resp);
+ SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ AddRead(resp);
- std::unique_ptr<SpdySerializedFrame> msg(
- spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
- AddWrite(*msg);
+ SpdySerializedFrame msg(
+ spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false));
+ AddWrite(msg);
- std::unique_ptr<SpdySerializedFrame> echo(
- spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
- AddRead(*echo);
+ SpdySerializedFrame echo(
+ spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false));
+ AddRead(echo);
AddReadEOF();
@@ -1021,26 +984,25 @@ void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
GetNumWrites());
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
-
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
- base::WeakPtr<SpdyStream> stream =
- CreateStreamSynchronously(
- SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
+ SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream);
StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece);
stream->SetDelegate(&delegate);
- EXPECT_FALSE(stream->HasUrlFromHeaders());
+ EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
- std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock(
- spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)));
+ SpdyHeaderBlock headers(
+ spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength));
EXPECT_EQ(ERR_IO_PENDING,
stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
data.RunUntilPaused();
@@ -1058,7 +1020,7 @@ void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
EXPECT_FALSE(stream->send_stalled_by_flow_control());
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
EXPECT_TRUE(delegate.send_headers_completed());
EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
@@ -1067,35 +1029,34 @@ void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest(
EXPECT_TRUE(data.AllWriteDataConsumed());
}
-TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) {
+TEST_F(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) {
RunResumeAfterUnstallBidirectionalTest(
base::Bind(&IncreaseStreamSendWindowSize));
}
-TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) {
+TEST_F(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) {
RunResumeAfterUnstallBidirectionalTest(
base::Bind(&AdjustStreamSendWindowSize));
}
// Test calculation of amount of bytes received from network.
-TEST_P(SpdyStreamTest, ReceivedBytes) {
+TEST_F(SpdyStreamTest, ReceivedBytes) {
GURL url(kStreamUrl);
- std::unique_ptr<SpdySerializedFrame> syn(
+ SpdySerializedFrame syn(
spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
- AddWrite(*syn);
+ AddWrite(syn);
AddReadPause();
- std::unique_ptr<SpdySerializedFrame> reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- AddRead(*reply);
+ SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(NULL, 0, 1));
+ AddRead(reply);
AddReadPause();
- std::unique_ptr<SpdySerializedFrame> msg(
- spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false));
- AddRead(*msg);
+ SpdySerializedFrame msg(
+ spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false));
+ AddRead(msg);
AddReadPause();
@@ -1105,31 +1066,28 @@ TEST_P(SpdyStreamTest, ReceivedBytes) {
GetNumWrites());
MockConnect connect_data(SYNCHRONOUS, OK);
data.set_connect_data(connect_data);
-
session_deps_.socket_factory->AddSocketDataProvider(&data);
+ AddSSLSocketData();
+
base::WeakPtr<SpdySession> session(CreateDefaultSpdySession());
- base::WeakPtr<SpdyStream> stream =
- CreateStreamSynchronously(
- SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
+ base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
+ SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, NetLogWithSource());
ASSERT_TRUE(stream);
StreamDelegateDoNothing delegate(stream);
stream->SetDelegate(&delegate);
- EXPECT_FALSE(stream->HasUrlFromHeaders());
+ EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty());
- std::unique_ptr<SpdyHeaderBlock> headers(
- new SpdyHeaderBlock(spdy_util_.ConstructGetHeaderBlock(kStreamUrl)));
+ SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kStreamUrl));
EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers),
NO_MORE_DATA_TO_SEND));
- EXPECT_TRUE(stream->HasUrlFromHeaders());
EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec());
- int64_t reply_frame_len = reply->size();
- int64_t data_header_len = SpdyConstants::GetDataFrameMinimumSize(
- NextProtoToSpdyMajorVersion(GetProtocol()));
+ int64_t reply_frame_len = reply.size();
+ int64_t data_header_len = SpdyConstants::GetDataFrameMinimumSize(HTTP2);
int64_t data_frame_len = data_header_len + kPostBodyLength;
int64_t response_len = reply_frame_len + data_frame_len;
@@ -1151,7 +1109,7 @@ TEST_P(SpdyStreamTest, ReceivedBytes) {
// FIN
data.Resume();
- EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
+ EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
}
} // namespace test
diff --git a/chromium/net/spdy/spdy_test_util_common.cc b/chromium/net/spdy/spdy_test_util_common.cc
index 5ff57e89ac8..4f133519d15 100644
--- a/chromium/net/spdy/spdy_test_util_common.cc
+++ b/chromium/net/spdy/spdy_test_util_common.cc
@@ -16,12 +16,15 @@
#include "base/strings/string_split.h"
#include "net/base/host_port_pair.h"
#include "net/cert/ct_policy_enforcer.h"
+#include "net/cert/ct_policy_status.h"
#include "net/cert/mock_cert_verifier.h"
#include "net/cert/multi_log_ct_verifier.h"
#include "net/http/http_cache.h"
#include "net/http/http_network_session.h"
#include "net/http/http_network_transaction.h"
#include "net/http/http_server_properties_impl.h"
+#include "net/log/net_log_with_source.h"
+#include "net/socket/next_proto.h"
#include "net/socket/socket_test_util.h"
#include "net/socket/ssl_client_socket.h"
#include "net/socket/transport_client_socket_pool.h"
@@ -32,22 +35,21 @@
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_session_pool.h"
#include "net/spdy/spdy_stream.h"
+#include "net/test/gtest_util.h"
#include "net/url_request/url_request_job_factory_impl.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using net::test::IsOk;
namespace net {
namespace {
-bool next_proto_is_spdy(NextProto next_proto) {
- return next_proto >= kProtoSPDYMinimumVersion &&
- next_proto <= kProtoSPDYMaximumVersion;
-}
-
// Parses a URL into the scheme, host, and path components required for a
// SPDY request.
void ParseUrl(base::StringPiece url, std::string* scheme, std::string* host,
std::string* path) {
- GURL gurl(url.as_string());
+ GURL gurl(url);
path->assign(gurl.PathForRequest());
scheme->assign(gurl.scheme());
host->assign(gurl.host());
@@ -188,24 +190,13 @@ class PriorityGetter : public BufferedSpdyFramerVisitorInterface {
void OnError(SpdyFramer::SpdyError error_code) override {}
void OnStreamError(SpdyStreamId stream_id,
const std::string& description) override {}
- void OnSynStream(SpdyStreamId stream_id,
- SpdyStreamId associated_stream_id,
- SpdyPriority priority,
- bool fin,
- bool unidirectional,
- const SpdyHeaderBlock& headers) override {
- priority_ = priority;
- }
- void OnSynReply(SpdyStreamId stream_id,
- bool fin,
- const SpdyHeaderBlock& headers) override {}
void OnHeaders(SpdyStreamId stream_id,
bool has_priority,
int weight,
SpdyStreamId parent_stream_id,
bool exclusive,
bool fin,
- const SpdyHeaderBlock& headers) override {
+ SpdyHeaderBlock headers) override {
if (has_priority) {
priority_ = Http2WeightToSpdy3Priority(weight);
}
@@ -229,7 +220,7 @@ class PriorityGetter : public BufferedSpdyFramerVisitorInterface {
void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override {}
void OnPushPromise(SpdyStreamId stream_id,
SpdyStreamId promised_stream_id,
- const SpdyHeaderBlock& headers) override {}
+ SpdyHeaderBlock headers) override {}
void OnAltSvc(SpdyStreamId stream_id,
base::StringPiece origin,
const SpdyAltSvcWireFormat::AlternativeServiceVector&
@@ -244,10 +235,8 @@ class PriorityGetter : public BufferedSpdyFramerVisitorInterface {
} // namespace
-bool GetSpdyPriority(SpdyMajorVersion version,
- const SpdySerializedFrame& frame,
- SpdyPriority* priority) {
- BufferedSpdyFramer framer(version);
+bool GetSpdyPriority(const SpdySerializedFrame& frame, SpdyPriority* priority) {
+ BufferedSpdyFramer framer;
PriorityGetter priority_getter;
framer.set_visitor(&priority_getter);
size_t frame_size = frame.size();
@@ -263,7 +252,7 @@ base::WeakPtr<SpdyStream> CreateStreamSynchronously(
const base::WeakPtr<SpdySession>& session,
const GURL& url,
RequestPriority priority,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
SpdyStreamRequest stream_request;
int rv = stream_request.StartRequest(type, session, url, priority, net_log,
CompletionCallback());
@@ -331,11 +320,10 @@ MockECSignatureCreatorFactory::Create(crypto::ECPrivateKey* key) {
return base::MakeUnique<MockECSignatureCreator>(key);
}
-SpdySessionDependencies::SpdySessionDependencies(NextProto protocol)
- : SpdySessionDependencies(protocol, ProxyService::CreateDirect()) {}
+SpdySessionDependencies::SpdySessionDependencies()
+ : SpdySessionDependencies(ProxyService::CreateDirect()) {}
SpdySessionDependencies::SpdySessionDependencies(
- NextProto protocol,
std::unique_ptr<ProxyService> proxy_service)
: host_resolver(new MockCachingHostResolver),
cert_verifier(new MockCertVerifier),
@@ -352,20 +340,13 @@ SpdySessionDependencies::SpdySessionDependencies(
enable_ip_pooling(true),
enable_ping(false),
enable_user_alternate_protocol_ports(false),
- enable_npn(false),
- enable_priority_dependencies(true),
- enable_spdy31(true),
enable_quic(false),
- protocol(protocol),
- session_max_recv_window_size(
- SpdySession::GetDefaultInitialWindowSize(protocol)),
- stream_max_recv_window_size(
- SpdySession::GetDefaultInitialWindowSize(protocol)),
+ session_max_recv_window_size(kDefaultInitialWindowSize),
+ stream_max_recv_window_size(kDefaultInitialWindowSize),
time_func(&base::TimeTicks::Now),
enable_http2_alternative_service_with_different_host(false),
- net_log(NULL) {
- DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol;
-
+ net_log(nullptr),
+ http_09_on_non_default_ports_enabled(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
@@ -392,9 +373,6 @@ std::unique_ptr<HttpNetworkSession> SpdySessionDependencies::SpdyCreateSession(
// static
HttpNetworkSession::Params SpdySessionDependencies::CreateSessionParams(
SpdySessionDependencies* session_deps) {
- DCHECK(next_proto_is_spdy(session_deps->protocol)) <<
- "Invalid protocol: " << session_deps->protocol;
-
HttpNetworkSession::Params params;
params.host_resolver = session_deps->host_resolver.get();
params.cert_verifier = session_deps->cert_verifier.get();
@@ -412,12 +390,7 @@ HttpNetworkSession::Params SpdySessionDependencies::CreateSessionParams(
params.enable_spdy_ping_based_connection_checking = session_deps->enable_ping;
params.enable_user_alternate_protocol_ports =
session_deps->enable_user_alternate_protocol_ports;
- params.enable_npn = session_deps->enable_npn;
- params.enable_priority_dependencies =
- session_deps->enable_priority_dependencies;
- params.enable_spdy31 = session_deps->enable_spdy31;
params.enable_quic = session_deps->enable_quic;
- params.spdy_default_protocol = session_deps->protocol;
params.spdy_session_max_recv_window_size =
session_deps->session_max_recv_window_size;
params.spdy_stream_max_recv_window_size =
@@ -427,44 +400,85 @@ HttpNetworkSession::Params SpdySessionDependencies::CreateSessionParams(
params.enable_http2_alternative_service_with_different_host =
session_deps->enable_http2_alternative_service_with_different_host;
params.net_log = session_deps->net_log;
+ params.http_09_on_non_default_ports_enabled =
+ session_deps->http_09_on_non_default_ports_enabled;
return params;
}
-SpdyURLRequestContext::SpdyURLRequestContext(NextProto protocol)
- : storage_(this) {
- DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol;
+class AllowAnyCertCTPolicyEnforcer : public CTPolicyEnforcer {
+ public:
+ AllowAnyCertCTPolicyEnforcer(){};
+ ~AllowAnyCertCTPolicyEnforcer() override = default;
+
+ ct::CertPolicyCompliance DoesConformToCertPolicy(
+ X509Certificate* cert,
+ const SCTList& verified_scts,
+ const NetLogWithSource& net_log) override {
+ return ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS;
+ }
+
+ ct::EVPolicyCompliance DoesConformToCTEVPolicy(
+ X509Certificate* cert,
+ const ct::EVCertsWhitelist* ev_whitelist,
+ const SCTList& verified_scts,
+ const NetLogWithSource& net_log) override {
+ return ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS;
+ }
+};
+
+class IgnoresCTVerifier : public net::CTVerifier {
+ public:
+ IgnoresCTVerifier() = default;
+ ~IgnoresCTVerifier() override = default;
+
+ int Verify(net::X509Certificate* cert,
+ const std::string& stapled_ocsp_response,
+ const std::string& sct_list_from_tls_extension,
+ net::ct::CTVerifyResult* result,
+ const net::NetLogWithSource& net_log) override {
+ return net::OK;
+ }
+
+ void SetObserver(Observer* observer) override {}
+};
+SpdyURLRequestContext::SpdyURLRequestContext() : storage_(this) {
storage_.set_host_resolver(
std::unique_ptr<HostResolver>(new MockHostResolver));
storage_.set_cert_verifier(base::WrapUnique(new MockCertVerifier));
storage_.set_transport_security_state(
base::WrapUnique(new TransportSecurityState));
storage_.set_proxy_service(ProxyService::CreateDirect());
+ storage_.set_ct_policy_enforcer(
+ base::WrapUnique(new AllowAnyCertCTPolicyEnforcer()));
+ storage_.set_cert_transparency_verifier(
+ base::WrapUnique(new IgnoresCTVerifier()));
storage_.set_ssl_config_service(new SSLConfigServiceDefaults);
storage_.set_http_auth_handler_factory(
HttpAuthHandlerFactory::CreateDefault(host_resolver()));
storage_.set_http_server_properties(
std::unique_ptr<HttpServerProperties>(new HttpServerPropertiesImpl()));
- storage_.set_job_factory(base::WrapUnique(new URLRequestJobFactoryImpl()));
+ storage_.set_job_factory(base::MakeUnique<URLRequestJobFactoryImpl>());
HttpNetworkSession::Params params;
params.client_socket_factory = &socket_factory_;
params.host_resolver = host_resolver();
params.cert_verifier = cert_verifier();
params.transport_security_state = transport_security_state();
params.proxy_service = proxy_service();
+ params.ct_policy_enforcer = ct_policy_enforcer();
+ params.cert_transparency_verifier = cert_transparency_verifier();
params.ssl_config_service = ssl_config_service();
params.http_auth_handler_factory = http_auth_handler_factory();
params.enable_spdy_ping_based_connection_checking = false;
- params.spdy_default_protocol = protocol;
params.http_server_properties = http_server_properties();
storage_.set_http_network_session(
- base::WrapUnique(new HttpNetworkSession(params)));
+ base::MakeUnique<HttpNetworkSession>(params));
SpdySessionPoolPeer pool_peer(
storage_.http_network_session()->spdy_session_pool());
pool_peer.SetEnableSendingInitialData(false);
- storage_.set_http_transaction_factory(base::WrapUnique(
- new HttpCache(storage_.http_network_session(),
- HttpCache::DefaultBackend::InMemory(0), false)));
+ storage_.set_http_transaction_factory(base::MakeUnique<HttpCache>(
+ storage_.http_network_session(), HttpCache::DefaultBackend::InMemory(0),
+ false));
}
SpdyURLRequestContext::~SpdyURLRequestContext() {
@@ -473,7 +487,7 @@ SpdyURLRequestContext::~SpdyURLRequestContext() {
bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key) {
return static_cast<bool>(
- pool->FindAvailableSession(key, GURL(), BoundNetLog()));
+ pool->FindAvailableSession(key, GURL(), NetLogWithSource()));
}
namespace {
@@ -481,7 +495,7 @@ namespace {
base::WeakPtr<SpdySession> CreateSpdySessionHelper(
HttpNetworkSession* http_session,
const SpdySessionKey& key,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
Error expected_status,
bool is_secure) {
EXPECT_FALSE(HasSpdySession(http_session->spdy_session_pool(), key));
@@ -523,11 +537,11 @@ base::WeakPtr<SpdySession> CreateSpdySessionHelper(
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
base::WeakPtr<SpdySession> spdy_session =
http_session->spdy_session_pool()->CreateAvailableSessionFromSocket(
- key, std::move(connection), net_log, OK, is_secure);
+ key, std::move(connection), net_log, is_secure);
// Failure is reported asynchronously.
EXPECT_TRUE(spdy_session);
EXPECT_TRUE(HasSpdySession(http_session->spdy_session_pool(), key));
@@ -539,25 +553,25 @@ base::WeakPtr<SpdySession> CreateSpdySessionHelper(
base::WeakPtr<SpdySession> CreateInsecureSpdySession(
HttpNetworkSession* http_session,
const SpdySessionKey& key,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
return CreateSpdySessionHelper(http_session, key, net_log,
OK, false /* is_secure */);
}
-base::WeakPtr<SpdySession> TryCreateInsecureSpdySessionExpectingFailure(
+base::WeakPtr<SpdySession> TryCreateSpdySessionExpectingFailure(
HttpNetworkSession* http_session,
const SpdySessionKey& key,
Error expected_error,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
DCHECK_LT(expected_error, ERR_IO_PENDING);
- return CreateSpdySessionHelper(http_session, key, net_log,
- expected_error, false /* is_secure */);
+ return CreateSpdySessionHelper(http_session, key, net_log, expected_error,
+ true /* is_secure */);
}
base::WeakPtr<SpdySession> CreateSecureSpdySession(
HttpNetworkSession* http_session,
const SpdySessionKey& key,
- const BoundNetLog& net_log) {
+ const NetLogWithSource& net_log) {
return CreateSpdySessionHelper(http_session, key, net_log,
OK, true /* is_secure */);
}
@@ -568,7 +582,7 @@ namespace {
class FakeSpdySessionClientSocket : public MockClientSocket {
public:
explicit FakeSpdySessionClientSocket(int read_result)
- : MockClientSocket(BoundNetLog()), read_result_(read_result) {}
+ : MockClientSocket(NetLogWithSource()), read_result_(read_result) {}
~FakeSpdySessionClientSocket() override {}
@@ -630,7 +644,7 @@ base::WeakPtr<SpdySession> CreateFakeSpdySessionHelper(
expected_status == OK ? ERR_IO_PENDING : expected_status)));
base::WeakPtr<SpdySession> spdy_session =
pool->CreateAvailableSessionFromSocket(
- key, std::move(handle), BoundNetLog(), OK, true /* is_secure */);
+ key, std::move(handle), NetLogWithSource(), true /* is_secure */);
// Failure is reported asynchronously.
EXPECT_TRUE(spdy_session);
EXPECT_TRUE(HasSpdySession(pool, key));
@@ -659,10 +673,6 @@ void SpdySessionPoolPeer::RemoveAliases(const SpdySessionKey& key) {
pool_->RemoveAliases(key);
}
-void SpdySessionPoolPeer::DisableDomainAuthenticationVerification() {
- pool_->verify_domain_authentication_ = false;
-}
-
void SpdySessionPoolPeer::SetEnableSendingInitialData(bool enabled) {
pool_->enable_sending_initial_data_ = enabled;
}
@@ -675,16 +685,11 @@ void SpdySessionPoolPeer::SetStreamInitialRecvWindowSize(size_t window) {
pool_->stream_max_recv_window_size_ = window;
}
-SpdyTestUtil::SpdyTestUtil(NextProto protocol, bool dependency_priorities)
- : protocol_(protocol),
- spdy_version_(NextProtoToSpdyMajorVersion(protocol)),
- headerless_spdy_framer_(spdy_version_),
- request_spdy_framer_(spdy_version_),
- response_spdy_framer_(spdy_version_),
- default_url_(GURL(kDefaultUrl)),
- dependency_priorities_(dependency_priorities) {
- DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol;
-}
+SpdyTestUtil::SpdyTestUtil()
+ : headerless_spdy_framer_(HTTP2),
+ request_spdy_framer_(HTTP2),
+ response_spdy_framer_(HTTP2),
+ default_url_(GURL(kDefaultUrl)) {}
SpdyTestUtil::~SpdyTestUtil() {}
@@ -725,62 +730,14 @@ SpdyHeaderBlock SpdyTestUtil::ConstructPutHeaderBlock(
return ConstructHeaderBlock("PUT", url, &content_length);
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyFrame(
- const SpdyHeaderInfo& header_info,
- SpdyHeaderBlock headers) const {
- BufferedSpdyFramer framer(spdy_version_);
- SpdySerializedFrame* frame = NULL;
- switch (header_info.kind) {
- case DATA:
- frame = framer.CreateDataFrame(header_info.id, header_info.data,
- header_info.data_length,
- header_info.data_flags);
- break;
- case SYN_STREAM:
- frame = framer.CreateSynStream(
- header_info.id, header_info.assoc_id, header_info.priority,
- header_info.control_flags, std::move(headers));
- break;
- case SYN_REPLY:
- frame = framer.CreateSynReply(header_info.id, header_info.control_flags,
- std::move(headers));
- break;
- case RST_STREAM:
- frame = framer.CreateRstStream(header_info.id, header_info.status);
- break;
- case HEADERS:
- frame = framer.CreateHeaders(header_info.id, header_info.control_flags,
- header_info.weight, std::move(headers));
- break;
- default:
- ADD_FAILURE();
- break;
- }
- return frame;
-}
-
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyFrame(
- const SpdyHeaderInfo& header_info,
- const char* const extra_headers[],
- int extra_header_count,
- const char* const tail_headers[],
- int tail_header_count) const {
- SpdyHeaderBlock headers;
- AppendToHeaderBlock(extra_headers, extra_header_count, &headers);
- if (tail_headers && tail_header_count)
- AppendToHeaderBlock(tail_headers, tail_header_count, &headers);
- return ConstructSpdyFrame(header_info, std::move(headers));
-}
-
std::string SpdyTestUtil::ConstructSpdyReplyString(
const SpdyHeaderBlock& headers) const {
std::string reply_string;
for (SpdyHeaderBlock::const_iterator it = headers.begin();
it != headers.end(); ++it) {
std::string key = it->first.as_string();
- // Remove leading colon from "special" headers (for SPDY3 and
- // above).
- if (spdy_version() >= SPDY3 && key[0] == ':')
+ // Remove leading colon from pseudo headers.
+ if (key[0] == ':')
key = key.substr(1);
for (const std::string& value :
base::SplitString(it->second, base::StringPiece("\0", 1),
@@ -793,7 +750,7 @@ std::string SpdyTestUtil::ConstructSpdyReplyString(
// TODO(jgraettinger): Eliminate uses of this method in tests (prefer
// SpdySettingsIR).
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdySettings(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdySettings(
const SettingsMap& settings) {
SpdySettingsIR settings_ir;
for (SettingsMap::const_iterator it = settings.begin();
@@ -805,157 +762,128 @@ SpdySerializedFrame* SpdyTestUtil::ConstructSpdySettings(
(it->second.first & SETTINGS_FLAG_PERSISTED) != 0,
it->second.second);
}
- return new SpdySerializedFrame(
+ return SpdySerializedFrame(
headerless_spdy_framer_.SerializeFrame(settings_ir));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdySettingsAck() {
- char kEmptyWrite[] = "";
-
- if (spdy_version() > SPDY3) {
- SpdySettingsIR settings_ir;
- settings_ir.set_is_ack(true);
- return new SpdySerializedFrame(
- headerless_spdy_framer_.SerializeFrame(settings_ir));
- }
- // No settings ACK write occurs. Create an empty placeholder write.
- return new SpdySerializedFrame(kEmptyWrite, 0, false);
+SpdySerializedFrame SpdyTestUtil::ConstructSpdySettingsAck() {
+ SpdySettingsIR settings_ir;
+ settings_ir.set_is_ack(true);
+ return SpdySerializedFrame(
+ headerless_spdy_framer_.SerializeFrame(settings_ir));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyPing(uint32_t ping_id,
- bool is_ack) {
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyPing(uint32_t ping_id,
+ bool is_ack) {
SpdyPingIR ping_ir(ping_id);
ping_ir.set_is_ack(is_ack);
- return new SpdySerializedFrame(
- headerless_spdy_framer_.SerializeFrame(ping_ir));
+ return SpdySerializedFrame(headerless_spdy_framer_.SerializeFrame(ping_ir));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyGoAway() {
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyGoAway() {
return ConstructSpdyGoAway(0);
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyGoAway(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyGoAway(
SpdyStreamId last_good_stream_id) {
SpdyGoAwayIR go_ir(last_good_stream_id, GOAWAY_OK, "go away");
- return new SpdySerializedFrame(headerless_spdy_framer_.SerializeFrame(go_ir));
+ return SpdySerializedFrame(headerless_spdy_framer_.SerializeFrame(go_ir));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyGoAway(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyGoAway(
SpdyStreamId last_good_stream_id,
SpdyGoAwayStatus status,
const std::string& desc) {
SpdyGoAwayIR go_ir(last_good_stream_id, status, desc);
- return new SpdySerializedFrame(headerless_spdy_framer_.SerializeFrame(go_ir));
+ return SpdySerializedFrame(headerless_spdy_framer_.SerializeFrame(go_ir));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyWindowUpdate(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyWindowUpdate(
const SpdyStreamId stream_id,
uint32_t delta_window_size) {
SpdyWindowUpdateIR update_ir(stream_id, delta_window_size);
- return new SpdySerializedFrame(
- headerless_spdy_framer_.SerializeFrame(update_ir));
+ return SpdySerializedFrame(headerless_spdy_framer_.SerializeFrame(update_ir));
}
// TODO(jgraettinger): Eliminate uses of this method in tests (prefer
// SpdyRstStreamIR).
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyRstStream(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyRstStream(
SpdyStreamId stream_id,
SpdyRstStreamStatus status) {
SpdyRstStreamIR rst_ir(stream_id, status);
- return new SpdySerializedFrame(
+ return SpdySerializedFrame(
headerless_spdy_framer_.SerializeRstStream(rst_ir));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyGet(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyGet(
const char* const url,
SpdyStreamId stream_id,
RequestPriority request_priority) {
SpdyHeaderBlock block(ConstructGetHeaderBlock(url));
- return ConstructSpdySyn(stream_id, std::move(block), request_priority, true);
+ return ConstructSpdyHeaders(stream_id, std::move(block), request_priority,
+ true);
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyGet(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyGet(
const char* const extra_headers[],
int extra_header_count,
int stream_id,
RequestPriority request_priority,
bool direct) {
SpdyHeaderBlock block;
- MaybeAddVersionHeader(&block);
block[GetMethodKey()] = "GET";
AddUrlToHeaderBlock(default_url_.spec(), &block);
AppendToHeaderBlock(extra_headers, extra_header_count, &block);
- return ConstructSpdySyn(stream_id, std::move(block), request_priority, true);
+ return ConstructSpdyHeaders(stream_id, std::move(block), request_priority,
+ true);
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyConnect(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyConnect(
const char* const extra_headers[],
int extra_header_count,
int stream_id,
RequestPriority priority,
const HostPortPair& host_port_pair) {
SpdyHeaderBlock block;
- MaybeAddVersionHeader(&block);
block[GetMethodKey()] = "CONNECT";
- if (spdy_version() < HTTP2) {
- block[GetHostKey()] = (host_port_pair.port() == 443)
- ? host_port_pair.host()
- : host_port_pair.ToString();
- block[GetPathKey()] = host_port_pair.ToString();
- } else {
- block[GetHostKey()] = host_port_pair.ToString();
- }
+ block[GetHostKey()] = host_port_pair.ToString();
AppendToHeaderBlock(extra_headers, extra_header_count, &block);
- return ConstructSpdySyn(stream_id, std::move(block), priority, false);
+ return ConstructSpdyHeaders(stream_id, std::move(block), priority, false);
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyPush(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyPush(
const char* const extra_headers[],
int extra_header_count,
int stream_id,
int associated_stream_id,
const char* url) {
- if (spdy_version() < HTTP2) {
- SpdyHeaderBlock header_block;
- header_block["hello"] = "bye";
- header_block[GetStatusKey()] = "200";
- header_block[GetVersionKey()] = "HTTP/1.1";
- AddUrlToHeaderBlock(url, &header_block);
- AppendToHeaderBlock(extra_headers, extra_header_count, &header_block);
- SpdySynStreamIR syn_stream(stream_id, std::move(header_block));
- syn_stream.set_associated_to_stream_id(associated_stream_id);
- return new SpdySerializedFrame(
- response_spdy_framer_.SerializeFrame(syn_stream));
- } else {
- SpdyHeaderBlock push_promise_header_block;
- 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));
-
- SpdyHeaderBlock headers_header_block;
- headers_header_block[GetStatusKey()] = "200";
- headers_header_block["hello"] = "bye";
- AppendToHeaderBlock(extra_headers, extra_header_count,
- &headers_header_block);
- SpdyHeadersIR headers(stream_id, std::move(headers_header_block));
- SpdySerializedFrame headers_frame(
- response_spdy_framer_.SerializeFrame(headers));
-
- int joint_data_size = push_promise_frame.size() + headers_frame.size();
- std::unique_ptr<char[]> data(new char[joint_data_size]);
- const SpdySerializedFrame* frames[2] = {
- &push_promise_frame, &headers_frame,
- };
- int combined_size =
- CombineFrames(frames, arraysize(frames), data.get(), joint_data_size);
- DCHECK_EQ(combined_size, joint_data_size);
- return new SpdySerializedFrame(data.release(), joint_data_size, true);
- }
+ SpdyHeaderBlock push_promise_header_block;
+ 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));
+
+ SpdyHeaderBlock headers_header_block;
+ headers_header_block[GetStatusKey()] = "200";
+ headers_header_block["hello"] = "bye";
+ AppendToHeaderBlock(extra_headers, extra_header_count, &headers_header_block);
+ SpdyHeadersIR headers(stream_id, std::move(headers_header_block));
+ SpdySerializedFrame headers_frame(
+ response_spdy_framer_.SerializeFrame(headers));
+
+ int joint_data_size = push_promise_frame.size() + headers_frame.size();
+ std::unique_ptr<char[]> data(new char[joint_data_size]);
+ const SpdySerializedFrame* frames[2] = {
+ &push_promise_frame, &headers_frame,
+ };
+ int combined_size =
+ CombineFrames(frames, arraysize(frames), data.get(), joint_data_size);
+ DCHECK_EQ(combined_size, joint_data_size);
+ return SpdySerializedFrame(data.release(), joint_data_size, true);
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyPush(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyPush(
const char* const extra_headers[],
int extra_header_count,
int stream_id,
@@ -963,92 +891,68 @@ SpdySerializedFrame* SpdyTestUtil::ConstructSpdyPush(
const char* url,
const char* status,
const char* location) {
- if (spdy_version() < HTTP2) {
- SpdyHeaderBlock header_block;
- header_block["hello"] = "bye";
- header_block[GetStatusKey()] = status;
- header_block[GetVersionKey()] = "HTTP/1.1";
- header_block["location"] = location;
- AddUrlToHeaderBlock(url, &header_block);
- AppendToHeaderBlock(extra_headers, extra_header_count, &header_block);
- SpdySynStreamIR syn_stream(stream_id, std::move(header_block));
- syn_stream.set_associated_to_stream_id(associated_stream_id);
- return new SpdySerializedFrame(
- response_spdy_framer_.SerializeFrame(syn_stream));
- } else {
- SpdyHeaderBlock push_promise_header_block;
- 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));
-
- SpdyHeaderBlock headers_header_block;
- headers_header_block["hello"] = "bye";
- headers_header_block[GetStatusKey()] = status;
- headers_header_block["location"] = location;
- AppendToHeaderBlock(extra_headers, extra_header_count,
- &headers_header_block);
- SpdyHeadersIR headers(stream_id, std::move(headers_header_block));
- SpdySerializedFrame headers_frame(
- response_spdy_framer_.SerializeFrame(headers));
-
- int joint_data_size = push_promise_frame.size() + headers_frame.size();
- std::unique_ptr<char[]> data(new char[joint_data_size]);
- const SpdySerializedFrame* frames[2] = {
- &push_promise_frame, &headers_frame,
- };
- int combined_size =
- CombineFrames(frames, arraysize(frames), data.get(), joint_data_size);
- DCHECK_EQ(combined_size, joint_data_size);
- return new SpdySerializedFrame(data.release(), joint_data_size, true);
- }
+ SpdyHeaderBlock push_promise_header_block;
+ 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));
+
+ SpdyHeaderBlock headers_header_block;
+ headers_header_block["hello"] = "bye";
+ headers_header_block[GetStatusKey()] = status;
+ headers_header_block["location"] = location;
+ AppendToHeaderBlock(extra_headers, extra_header_count, &headers_header_block);
+ SpdyHeadersIR headers(stream_id, std::move(headers_header_block));
+ SpdySerializedFrame headers_frame(
+ response_spdy_framer_.SerializeFrame(headers));
+
+ int joint_data_size = push_promise_frame.size() + headers_frame.size();
+ std::unique_ptr<char[]> data(new char[joint_data_size]);
+ const SpdySerializedFrame* frames[2] = {
+ &push_promise_frame, &headers_frame,
+ };
+ int combined_size =
+ CombineFrames(frames, arraysize(frames), data.get(), joint_data_size);
+ DCHECK_EQ(combined_size, joint_data_size);
+ return SpdySerializedFrame(data.release(), joint_data_size, true);
}
-SpdySerializedFrame* SpdyTestUtil::ConstructInitialSpdyPushFrame(
+SpdySerializedFrame SpdyTestUtil::ConstructInitialSpdyPushFrame(
SpdyHeaderBlock headers,
int stream_id,
int associated_stream_id) {
- if (spdy_version() < HTTP2) {
- SpdySynStreamIR syn_stream(stream_id, std::move(headers));
- syn_stream.set_associated_to_stream_id(associated_stream_id);
- SetPriority(LOWEST, &syn_stream);
- return new SpdySerializedFrame(
- response_spdy_framer_.SerializeFrame(syn_stream));
- } else {
- SpdyPushPromiseIR push_promise(associated_stream_id, stream_id,
- std::move(headers));
- return new SpdySerializedFrame(
- response_spdy_framer_.SerializeFrame(push_promise));
- }
+ SpdyPushPromiseIR push_promise(associated_stream_id, stream_id,
+ std::move(headers));
+ return SpdySerializedFrame(
+ response_spdy_framer_.SerializeFrame(push_promise));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyPushHeaders(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyPushHeaders(
int stream_id,
const char* const extra_headers[],
int extra_header_count) {
SpdyHeaderBlock header_block;
header_block[GetStatusKey()] = "200";
- MaybeAddVersionHeader(&header_block);
AppendToHeaderBlock(extra_headers, extra_header_count, &header_block);
SpdyHeadersIR headers(stream_id, std::move(header_block));
- return new SpdySerializedFrame(response_spdy_framer_.SerializeFrame(headers));
+ return SpdySerializedFrame(response_spdy_framer_.SerializeFrame(headers));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyResponseHeaders(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyResponseHeaders(
int stream_id,
SpdyHeaderBlock headers,
bool fin) {
SpdyHeadersIR spdy_headers(stream_id, std::move(headers));
spdy_headers.set_fin(fin);
- return new SpdySerializedFrame(
+ return SpdySerializedFrame(
response_spdy_framer_.SerializeFrame(spdy_headers));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdySyn(int stream_id,
- SpdyHeaderBlock block,
- RequestPriority priority,
- bool fin) {
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyHeaders(int stream_id,
+ SpdyHeaderBlock block,
+ RequestPriority priority,
+ bool fin) {
// Get the stream id of the next highest priority request
// (most recent request of the same priority, or last request of
// an earlier priority).
@@ -1067,81 +971,60 @@ SpdySerializedFrame* SpdyTestUtil::ConstructSpdySyn(int stream_id,
priority_to_stream_id_list_[priority].push_back(stream_id);
- if (protocol_ < kProtoHTTP2) {
- SpdySynStreamIR syn_stream(stream_id, std::move(block));
- syn_stream.set_priority(
- ConvertRequestPriorityToSpdyPriority(priority, spdy_version()));
- syn_stream.set_fin(fin);
- return new SpdySerializedFrame(
- request_spdy_framer_.SerializeFrame(syn_stream));
- } else {
- SpdyHeadersIR headers(stream_id, std::move(block));
- headers.set_has_priority(true);
- headers.set_weight(Spdy3PriorityToHttp2Weight(
- ConvertRequestPriorityToSpdyPriority(priority, spdy_version())));
- if (dependency_priorities_) {
- headers.set_parent_stream_id(parent_stream_id);
- headers.set_exclusive(true);
- }
- headers.set_fin(fin);
- return new SpdySerializedFrame(
- request_spdy_framer_.SerializeFrame(headers));
- }
+ SpdyHeadersIR headers(stream_id, std::move(block));
+ headers.set_has_priority(true);
+ headers.set_weight(Spdy3PriorityToHttp2Weight(
+ ConvertRequestPriorityToSpdyPriority(priority)));
+ headers.set_parent_stream_id(parent_stream_id);
+ headers.set_exclusive(true);
+ headers.set_fin(fin);
+ return SpdySerializedFrame(request_spdy_framer_.SerializeFrame(headers));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyReply(int stream_id,
- SpdyHeaderBlock headers) {
- if (protocol_ < kProtoHTTP2) {
- SpdySynReplyIR syn_reply(stream_id, std::move(headers));
- return new SpdySerializedFrame(
- response_spdy_framer_.SerializeFrame(syn_reply));
- } else {
- SpdyHeadersIR reply(stream_id, std::move(headers));
- return new SpdySerializedFrame(response_spdy_framer_.SerializeFrame(reply));
- }
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyReply(int stream_id,
+ SpdyHeaderBlock headers) {
+ SpdyHeadersIR reply(stream_id, std::move(headers));
+ return SpdySerializedFrame(response_spdy_framer_.SerializeFrame(reply));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdySynReplyError(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyReplyError(
const char* const status,
const char* const* const extra_headers,
int extra_header_count,
int stream_id) {
SpdyHeaderBlock block;
block[GetStatusKey()] = status;
- MaybeAddVersionHeader(&block);
block["hello"] = "bye";
AppendToHeaderBlock(extra_headers, extra_header_count, &block);
return ConstructSpdyReply(stream_id, std::move(block));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyGetSynReplyRedirect(
- int stream_id) {
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyGetReplyRedirect(int stream_id) {
static const char* const kExtraHeaders[] = {
"location", "http://www.foo.com/index.php",
};
- return ConstructSpdySynReplyError("301 Moved Permanently", kExtraHeaders,
- arraysize(kExtraHeaders)/2, stream_id);
+ return ConstructSpdyReplyError("301 Moved Permanently", kExtraHeaders,
+ arraysize(kExtraHeaders) / 2, stream_id);
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdySynReplyError(int stream_id) {
- return ConstructSpdySynReplyError("500 Internal Server Error", NULL, 0, 1);
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyReplyError(int stream_id) {
+ return ConstructSpdyReplyError("500 Internal Server Error", NULL, 0, 1);
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyGetSynReply(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyGetReply(
const char* const extra_headers[],
int extra_header_count,
int stream_id) {
SpdyHeaderBlock block;
block[GetStatusKey()] = "200";
- MaybeAddVersionHeader(&block);
block["hello"] = "bye";
AppendToHeaderBlock(extra_headers, extra_header_count, &block);
return ConstructSpdyReply(stream_id, std::move(block));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyPost(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyPost(
const char* url,
SpdyStreamId stream_id,
int64_t content_length,
@@ -1150,63 +1033,61 @@ SpdySerializedFrame* SpdyTestUtil::ConstructSpdyPost(
int extra_header_count) {
SpdyHeaderBlock block(ConstructPostHeaderBlock(url, content_length));
AppendToHeaderBlock(extra_headers, extra_header_count, &block);
- return ConstructSpdySyn(stream_id, std::move(block), priority, false);
+ return ConstructSpdyHeaders(stream_id, std::move(block), priority, false);
}
-SpdySerializedFrame* SpdyTestUtil::ConstructChunkedSpdyPost(
+SpdySerializedFrame SpdyTestUtil::ConstructChunkedSpdyPost(
const char* const extra_headers[],
int extra_header_count) {
SpdyHeaderBlock block;
- MaybeAddVersionHeader(&block);
block[GetMethodKey()] = "POST";
AddUrlToHeaderBlock(default_url_.spec(), &block);
AppendToHeaderBlock(extra_headers, extra_header_count, &block);
- return ConstructSpdySyn(1, std::move(block), LOWEST, false);
+ return ConstructSpdyHeaders(1, std::move(block), LOWEST, false);
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyPostSynReply(
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyPostReply(
const char* const extra_headers[],
int extra_header_count) {
// TODO(jgraettinger): Remove this method.
- return ConstructSpdyGetSynReply(extra_headers, extra_header_count, 1);
+ return ConstructSpdyGetReply(extra_headers, extra_header_count, 1);
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyBodyFrame(int stream_id,
- bool fin) {
- SpdyFramer framer(spdy_version_);
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyDataFrame(int stream_id,
+ bool fin) {
+ SpdyFramer framer(HTTP2);
SpdyDataIR data_ir(stream_id,
base::StringPiece(kUploadData, kUploadDataSize));
data_ir.set_fin(fin);
- return new SpdySerializedFrame(framer.SerializeData(data_ir));
+ return SpdySerializedFrame(framer.SerializeData(data_ir));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyBodyFrame(int stream_id,
- const char* data,
- uint32_t len,
- bool fin) {
- SpdyFramer framer(spdy_version_);
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyDataFrame(int stream_id,
+ const char* data,
+ uint32_t len,
+ bool fin) {
+ SpdyFramer framer(HTTP2);
SpdyDataIR data_ir(stream_id, base::StringPiece(data, len));
data_ir.set_fin(fin);
- return new SpdySerializedFrame(framer.SerializeData(data_ir));
+ return SpdySerializedFrame(framer.SerializeData(data_ir));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructSpdyBodyFrame(int stream_id,
- const char* data,
- uint32_t len,
- bool fin,
- int padding_length) {
- SpdyFramer framer(spdy_version_);
+SpdySerializedFrame SpdyTestUtil::ConstructSpdyDataFrame(int stream_id,
+ const char* data,
+ uint32_t len,
+ bool fin,
+ int padding_length) {
+ SpdyFramer framer(HTTP2);
SpdyDataIR data_ir(stream_id, base::StringPiece(data, len));
data_ir.set_fin(fin);
data_ir.set_padding_len(padding_length);
- return new SpdySerializedFrame(framer.SerializeData(data_ir));
+ return SpdySerializedFrame(framer.SerializeData(data_ir));
}
-SpdySerializedFrame* SpdyTestUtil::ConstructWrappedSpdyFrame(
- const std::unique_ptr<SpdySerializedFrame>& frame,
+SpdySerializedFrame SpdyTestUtil::ConstructWrappedSpdyFrame(
+ const SpdySerializedFrame& frame,
int stream_id) {
- return ConstructSpdyBodyFrame(stream_id, frame->data(),
- frame->size(), false);
+ return ConstructSpdyDataFrame(stream_id, frame.data(), frame.size(), false);
}
SpdySerializedFrame SpdyTestUtil::SerializeFrame(const SpdyFrameIR& frame_ir) {
@@ -1236,20 +1117,13 @@ const char* SpdyTestUtil::GetStatusKey() const {
}
const char* SpdyTestUtil::GetHostKey() const {
- if (protocol_ < kProtoHTTP2)
- return ":host";
- else
- return ":authority";
+ return ":authority";
}
const char* SpdyTestUtil::GetSchemeKey() const {
return ":scheme";
}
-const char* SpdyTestUtil::GetVersionKey() const {
- return ":version";
-}
-
const char* SpdyTestUtil::GetPathKey() const {
return ":path";
}
@@ -1259,11 +1133,8 @@ SpdyHeaderBlock SpdyTestUtil::ConstructHeaderBlock(
base::StringPiece url,
int64_t* content_length) const {
std::string scheme, host, path;
- ParseUrl(url.data(), &scheme, &host, &path);
+ ParseUrl(url, &scheme, &host, &path);
SpdyHeaderBlock headers;
- if (include_version_header()) {
- headers[GetVersionKey()] = "HTTP/1.1";
- }
headers[GetMethodKey()] = method.as_string();
headers[GetHostKey()] = host.c_str();
headers[GetSchemeKey()] = scheme.c_str();
@@ -1275,16 +1146,4 @@ SpdyHeaderBlock SpdyTestUtil::ConstructHeaderBlock(
return headers;
}
-void SpdyTestUtil::MaybeAddVersionHeader(SpdyHeaderBlock* block) const {
- if (include_version_header()) {
- (*block)[GetVersionKey()] = "HTTP/1.1";
- }
-}
-
-void SpdyTestUtil::SetPriority(RequestPriority priority,
- SpdySynStreamIR* ir) const {
- ir->set_priority(ConvertRequestPriorityToSpdyPriority(
- priority, spdy_version()));
-}
-
} // namespace net
diff --git a/chromium/net/spdy/spdy_test_util_common.h b/chromium/net/spdy/spdy_test_util_common.h
index acfeaee3d7a..d5495dccad7 100644
--- a/chromium/net/spdy/spdy_test_util_common.h
+++ b/chromium/net/spdy/spdy_test_util_common.h
@@ -29,7 +29,6 @@
#include "net/http/transport_security_state.h"
#include "net/proxy/proxy_server.h"
#include "net/proxy/proxy_service.h"
-#include "net/socket/next_proto.h"
#include "net/socket/socket_test_util.h"
#include "net/spdy/spdy_protocol.h"
#include "net/ssl/ssl_config_service_defaults.h"
@@ -41,10 +40,10 @@ class GURL;
namespace net {
-class BoundNetLog;
class CTVerifier;
class CTPolicyEnforcer;
class HostPortPair;
+class NetLogWithSource;
class SpdySession;
class SpdySessionKey;
class SpdySessionPool;
@@ -97,9 +96,7 @@ int CombineFrames(const SpdySerializedFrame** frames,
// Returns the SpdyPriority embedded in the given frame. Returns true
// and fills in |priority| on success.
-bool GetSpdyPriority(SpdyMajorVersion version,
- const SpdySerializedFrame& frame,
- SpdyPriority* priority);
+bool GetSpdyPriority(const SpdySerializedFrame& frame, SpdyPriority* priority);
// Tries to create a stream in |session| synchronously. Returns NULL
// on failure.
@@ -108,7 +105,7 @@ base::WeakPtr<SpdyStream> CreateStreamSynchronously(
const base::WeakPtr<SpdySession>& session,
const GURL& url,
RequestPriority priority,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Helper class used by some tests to release a stream as soon as it's
// created.
@@ -175,11 +172,10 @@ class MockECSignatureCreatorFactory : public crypto::ECSignatureCreatorFactory {
// HttpNetworkTransaction.
struct SpdySessionDependencies {
// Default set of dependencies -- "null" proxy service.
- explicit SpdySessionDependencies(NextProto protocol);
+ SpdySessionDependencies();
// Custom proxy service dependency.
- SpdySessionDependencies(NextProto protocol,
- std::unique_ptr<ProxyService> proxy_service);
+ explicit SpdySessionDependencies(std::unique_ptr<ProxyService> proxy_service);
~SpdySessionDependencies();
@@ -203,22 +199,19 @@ struct SpdySessionDependencies {
bool enable_ip_pooling;
bool enable_ping;
bool enable_user_alternate_protocol_ports;
- bool enable_npn;
- bool enable_priority_dependencies;
- bool enable_spdy31;
bool enable_quic;
- NextProto protocol;
size_t session_max_recv_window_size;
size_t stream_max_recv_window_size;
SpdySession::TimeFunc time_func;
std::unique_ptr<ProxyDelegate> proxy_delegate;
bool enable_http2_alternative_service_with_different_host;
NetLog* net_log;
+ bool http_09_on_non_default_ports_enabled;
};
class SpdyURLRequestContext : public URLRequestContext {
public:
- explicit SpdyURLRequestContext(NextProto protocol);
+ SpdyURLRequestContext();
~SpdyURLRequestContext() override;
MockClientSocketFactory& socket_factory() { return socket_factory_; }
@@ -228,7 +221,8 @@ class SpdyURLRequestContext : public URLRequestContext {
URLRequestContextStorage storage_;
};
-// Equivalent to pool->GetIfExists(spdy_session_key, BoundNetLog()) != NULL.
+// Equivalent to pool->GetIfExists(spdy_session_key, NetLogWithSource()) !=
+// NULL.
bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key);
// Creates a SPDY session for the given key and puts it in the SPDY
@@ -237,23 +231,23 @@ bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key);
base::WeakPtr<SpdySession> CreateInsecureSpdySession(
HttpNetworkSession* http_session,
const SpdySessionKey& key,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Tries to create a SPDY session for the given key but expects the
// attempt to fail with the given error. A SPDY session for |key| must
// not already exist. The session will be created but close in the
// next event loop iteration.
-base::WeakPtr<SpdySession> TryCreateInsecureSpdySessionExpectingFailure(
+base::WeakPtr<SpdySession> TryCreateSpdySessionExpectingFailure(
HttpNetworkSession* http_session,
const SpdySessionKey& key,
Error expected_error,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Like CreateInsecureSpdySession(), but uses TLS.
base::WeakPtr<SpdySession> CreateSecureSpdySession(
HttpNetworkSession* http_session,
const SpdySessionKey& key,
- const BoundNetLog& net_log);
+ const NetLogWithSource& net_log);
// Creates an insecure SPDY session for the given key and puts it in
// |pool|. The returned session will neither receive nor send any
@@ -276,7 +270,6 @@ class SpdySessionPoolPeer {
explicit SpdySessionPoolPeer(SpdySessionPool* pool);
void RemoveAliases(const SpdySessionKey& key);
- void DisableDomainAuthenticationVerification();
void SetEnableSendingInitialData(bool enabled);
void SetSessionMaxRecvWindowSize(size_t window);
void SetStreamInitialRecvWindowSize(size_t window);
@@ -289,7 +282,7 @@ class SpdySessionPoolPeer {
class SpdyTestUtil {
public:
- explicit SpdyTestUtil(NextProto protocol, bool dependency_priorities);
+ SpdyTestUtil();
~SpdyTestUtil();
// Add the appropriate headers to put |url| into |block|.
@@ -305,208 +298,188 @@ class SpdyTestUtil {
SpdyHeaderBlock ConstructPutHeaderBlock(base::StringPiece url,
int64_t content_length) const;
- // Construct a SPDY frame. If it is a SYN_STREAM or SYN_REPLY frame (as
- // specified in header_info.kind), the provided headers are included in the
- // frame.
- SpdySerializedFrame* ConstructSpdyFrame(const SpdyHeaderInfo& header_info,
- SpdyHeaderBlock headers) const;
-
- // Construct a SPDY frame. If it is a SYN_STREAM or SYN_REPLY frame (as
- // specified in header_info.kind), the headers provided in extra_headers and
- // (if non-NULL) tail_headers are concatenated and included in the frame.
- // (extra_headers must always be non-NULL.)
- SpdySerializedFrame* ConstructSpdyFrame(const SpdyHeaderInfo& header_info,
- const char* const extra_headers[],
- int extra_header_count,
- const char* const tail_headers[],
- int tail_header_count) const;
-
// Construct an expected SPDY reply string from the given headers.
std::string ConstructSpdyReplyString(const SpdyHeaderBlock& headers) const;
// Construct an expected SPDY SETTINGS frame.
// |settings| are the settings to set.
// Returns the constructed frame. The caller takes ownership of the frame.
- SpdySerializedFrame* ConstructSpdySettings(const SettingsMap& settings);
+ SpdySerializedFrame ConstructSpdySettings(const SettingsMap& settings);
- // Constructs an expected SPDY SETTINGS acknowledgement frame, if the protocol
- // version is SPDY4 or higher, or an empty placeholder frame otherwise.
- SpdySerializedFrame* ConstructSpdySettingsAck();
+ // Constructs an expected SPDY SETTINGS acknowledgement frame.
+ SpdySerializedFrame ConstructSpdySettingsAck();
// Construct a SPDY PING frame.
// Returns the constructed frame. The caller takes ownership of the frame.
- SpdySerializedFrame* ConstructSpdyPing(uint32_t ping_id, bool is_ack);
+ SpdySerializedFrame ConstructSpdyPing(uint32_t ping_id, bool is_ack);
// Construct a SPDY GOAWAY frame with last_good_stream_id = 0.
// Returns the constructed frame. The caller takes ownership of the frame.
- SpdySerializedFrame* ConstructSpdyGoAway();
+ SpdySerializedFrame ConstructSpdyGoAway();
// Construct a SPDY GOAWAY frame with the specified last_good_stream_id.
// Returns the constructed frame. The caller takes ownership of the frame.
- SpdySerializedFrame* ConstructSpdyGoAway(SpdyStreamId last_good_stream_id);
+ SpdySerializedFrame ConstructSpdyGoAway(SpdyStreamId last_good_stream_id);
// Construct a SPDY GOAWAY frame with the specified last_good_stream_id,
// status, and description. Returns the constructed frame. The caller takes
// ownership of the frame.
- SpdySerializedFrame* ConstructSpdyGoAway(SpdyStreamId last_good_stream_id,
- SpdyGoAwayStatus status,
- const std::string& desc);
+ SpdySerializedFrame ConstructSpdyGoAway(SpdyStreamId last_good_stream_id,
+ SpdyGoAwayStatus status,
+ const std::string& desc);
// Construct a SPDY WINDOW_UPDATE frame.
// Returns the constructed frame. The caller takes ownership of the frame.
- SpdySerializedFrame* ConstructSpdyWindowUpdate(SpdyStreamId stream_id,
- uint32_t delta_window_size);
+ SpdySerializedFrame ConstructSpdyWindowUpdate(SpdyStreamId stream_id,
+ uint32_t delta_window_size);
// Construct a SPDY RST_STREAM frame.
// Returns the constructed frame. The caller takes ownership of the frame.
- SpdySerializedFrame* ConstructSpdyRstStream(SpdyStreamId stream_id,
- SpdyRstStreamStatus status);
+ SpdySerializedFrame ConstructSpdyRstStream(SpdyStreamId stream_id,
+ SpdyRstStreamStatus status);
- // Constructs a standard SPDY GET SYN frame for |url| with header compression.
+ // Constructs a standard SPDY GET HEADERS frame for |url| with header
+ // compression.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdySerializedFrame.
- SpdySerializedFrame* ConstructSpdyGet(const char* const url,
- SpdyStreamId stream_id,
- RequestPriority request_priority);
+ SpdySerializedFrame ConstructSpdyGet(const char* const url,
+ SpdyStreamId stream_id,
+ RequestPriority request_priority);
- // Constructs a standard SPDY GET SYN frame with header compression.
+ // Constructs a standard SPDY GET HEADERS frame with header compression.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls. If |direct| is false, the
// the full url will be used instead of simply the path.
// Returns a SpdySerializedFrame.
- SpdySerializedFrame* ConstructSpdyGet(const char* const extra_headers[],
+ SpdySerializedFrame ConstructSpdyGet(const char* const extra_headers[],
+ int extra_header_count,
+ int stream_id,
+ RequestPriority request_priority,
+ bool direct);
+
+ // Constructs a SPDY HEADERS frame for a CONNECT request.
+ SpdySerializedFrame ConstructSpdyConnect(const char* const extra_headers[],
+ int extra_header_count,
+ int stream_id,
+ RequestPriority priority,
+ const HostPortPair& host_port_pair);
+
+ // Constructs a SPDY PUSH_PROMISE frame.
+ // |extra_headers| are the extra header-value pairs, which typically
+ // will vary the most between calls.
+ // Returns a SpdySerializedFrame.
+ SpdySerializedFrame ConstructSpdyPush(const char* const extra_headers[],
+ int extra_header_count,
+ int stream_id,
+ int associated_stream_id,
+ const char* url);
+ SpdySerializedFrame ConstructSpdyPush(const char* const extra_headers[],
int extra_header_count,
int stream_id,
- RequestPriority request_priority,
- bool direct);
+ int associated_stream_id,
+ const char* url,
+ const char* status,
+ const char* location);
- // Constructs a standard SPDY SYN_STREAM frame for a CONNECT request.
- SpdySerializedFrame* ConstructSpdyConnect(const char* const extra_headers[],
- int extra_header_count,
- int stream_id,
- RequestPriority priority,
- const HostPortPair& host_port_pair);
+ SpdySerializedFrame ConstructInitialSpdyPushFrame(SpdyHeaderBlock headers,
+ int stream_id,
+ int associated_stream_id);
- // Constructs a standard SPDY push SYN frame.
- // |extra_headers| are the extra header-value pairs, which typically
- // will vary the most between calls.
- // Returns a SpdySerializedFrame.
- SpdySerializedFrame* ConstructSpdyPush(const char* const extra_headers[],
- int extra_header_count,
- int stream_id,
- int associated_stream_id,
- const char* url);
- SpdySerializedFrame* ConstructSpdyPush(const char* const extra_headers[],
- int extra_header_count,
- int stream_id,
- int associated_stream_id,
- const char* url,
- const char* status,
- const char* location);
-
- SpdySerializedFrame* ConstructInitialSpdyPushFrame(SpdyHeaderBlock headers,
- int stream_id,
- int associated_stream_id);
-
- SpdySerializedFrame* ConstructSpdyPushHeaders(
+ SpdySerializedFrame ConstructSpdyPushHeaders(
int stream_id,
const char* const extra_headers[],
int extra_header_count);
- // Constructs a SPDY header frame with the request header compression context
- // with END_STREAM flag set to |fin|.
- SpdySerializedFrame* ConstructSpdyResponseHeaders(int stream_id,
- SpdyHeaderBlock headers,
- bool fin);
+ // Constructs a HEADERS frame with the request header compression context with
+ // END_STREAM flag set to |fin|.
+ SpdySerializedFrame ConstructSpdyResponseHeaders(int stream_id,
+ SpdyHeaderBlock headers,
+ bool fin);
- // Construct a SPDY syn (HEADERS or SYN_STREAM, depending on protocol
- // version) carrying exactly the given headers and priority.
- SpdySerializedFrame* ConstructSpdySyn(int stream_id,
- SpdyHeaderBlock headers,
- RequestPriority priority,
- bool fin);
+ // Construct a HEADERS frame carrying exactly the given headers and priority.
+ SpdySerializedFrame ConstructSpdyHeaders(int stream_id,
+ SpdyHeaderBlock headers,
+ RequestPriority priority,
+ bool fin);
- // Construct a SPDY reply (HEADERS or SYN_REPLY, depending on protocol
- // version) carrying exactly the given headers, and the default priority
- // (or no priority, depending on protocol version).
- SpdySerializedFrame* ConstructSpdyReply(int stream_id,
- SpdyHeaderBlock headers);
+ // Construct a reply HEADERS frame carrying exactly the given headers and the
+ // default priority.
+ SpdySerializedFrame ConstructSpdyReply(int stream_id,
+ SpdyHeaderBlock headers);
- // Constructs a standard SPDY SYN_REPLY frame to match the SPDY GET.
+ // Constructs a standard SPDY HEADERS frame to match the SPDY GET.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdySerializedFrame.
- SpdySerializedFrame* ConstructSpdyGetSynReply(
- const char* const extra_headers[],
- int extra_header_count,
- int stream_id);
+ SpdySerializedFrame ConstructSpdyGetReply(const char* const extra_headers[],
+ int extra_header_count,
+ int stream_id);
- // Constructs a standard SPDY SYN_REPLY frame to match the SPDY GET.
+ // Constructs a standard SPDY HEADERS frame to match the SPDY GET.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdySerializedFrame.
- SpdySerializedFrame* ConstructSpdyGetSynReplyRedirect(int stream_id);
+ SpdySerializedFrame ConstructSpdyGetReplyRedirect(int stream_id);
- // Constructs a standard SPDY SYN_REPLY frame with an Internal Server
+ // Constructs a standard SPDY HEADERS frame with an Internal Server
// Error status code.
// Returns a SpdySerializedFrame.
- SpdySerializedFrame* ConstructSpdySynReplyError(int stream_id);
+ SpdySerializedFrame ConstructSpdyReplyError(int stream_id);
- // Constructs a standard SPDY SYN_REPLY frame with the specified status code.
+ // Constructs a standard SPDY HEADERS frame with the specified status code.
// Returns a SpdySerializedFrame.
- SpdySerializedFrame* ConstructSpdySynReplyError(
+ SpdySerializedFrame ConstructSpdyReplyError(
const char* const status,
const char* const* const extra_headers,
int extra_header_count,
int stream_id);
- // Constructs a standard SPDY POST SYN frame.
+ // Constructs a standard SPDY POST HEADERS frame.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdySerializedFrame.
- SpdySerializedFrame* ConstructSpdyPost(const char* url,
- SpdyStreamId stream_id,
- int64_t content_length,
- RequestPriority priority,
- const char* const extra_headers[],
- int extra_header_count);
-
- // Constructs a chunked transfer SPDY POST SYN frame.
+ SpdySerializedFrame ConstructSpdyPost(const char* url,
+ SpdyStreamId stream_id,
+ int64_t content_length,
+ RequestPriority priority,
+ const char* const extra_headers[],
+ int extra_header_count);
+
+ // Constructs a chunked transfer SPDY POST HEADERS frame.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdySerializedFrame.
- SpdySerializedFrame* ConstructChunkedSpdyPost(
+ SpdySerializedFrame ConstructChunkedSpdyPost(
const char* const extra_headers[],
int extra_header_count);
- // Constructs a standard SPDY SYN_REPLY frame to match the SPDY POST.
+ // Constructs a standard SPDY HEADERS frame to match the SPDY POST.
// |extra_headers| are the extra header-value pairs, which typically
// will vary the most between calls.
// Returns a SpdySerializedFrame.
- SpdySerializedFrame* ConstructSpdyPostSynReply(
- const char* const extra_headers[],
- int extra_header_count);
+ SpdySerializedFrame ConstructSpdyPostReply(const char* const extra_headers[],
+ int extra_header_count);
// Constructs a single SPDY data frame with the contents "hello!"
- SpdySerializedFrame* ConstructSpdyBodyFrame(int stream_id, bool fin);
+ SpdySerializedFrame ConstructSpdyDataFrame(int stream_id, bool fin);
// Constructs a single SPDY data frame with the given content.
- SpdySerializedFrame* ConstructSpdyBodyFrame(int stream_id,
- const char* data,
- uint32_t len,
- bool fin);
+ SpdySerializedFrame ConstructSpdyDataFrame(int stream_id,
+ const char* data,
+ uint32_t len,
+ bool fin);
// Constructs a single SPDY data frame with the given content and padding.
- SpdySerializedFrame* ConstructSpdyBodyFrame(int stream_id,
- const char* data,
- uint32_t len,
- bool fin,
- int padding_length);
+ SpdySerializedFrame ConstructSpdyDataFrame(int stream_id,
+ const char* data,
+ uint32_t len,
+ bool fin,
+ int padding_length);
// Wraps |frame| in the payload of a data frame in stream |stream_id|.
- SpdySerializedFrame* ConstructWrappedSpdyFrame(
- const std::unique_ptr<SpdySerializedFrame>& frame,
+ SpdySerializedFrame ConstructWrappedSpdyFrame(
+ const SpdySerializedFrame& frame,
int stream_id);
// Serialize a SpdyFrameIR with |headerless_spdy_framer_|.
@@ -517,23 +490,12 @@ class SpdyTestUtil {
// class of stream destruction.
void UpdateWithStreamDestruction(int stream_id);
- // For versions below SPDY4, adds the version HTTP/1.1 header.
- void MaybeAddVersionHeader(SpdyHeaderBlock* block) const;
-
- // Maps |priority| to SPDY version priority, and sets it on |frame_ir|.
- void SetPriority(RequestPriority priority, SpdySynStreamIR* frame_ir) const;
-
- NextProto protocol() const { return protocol_; }
- SpdyMajorVersion spdy_version() const { return spdy_version_; }
- bool include_version_header() const { return protocol_ < kProtoHTTP2; }
-
void set_default_url(const GURL& url) { default_url_ = url; }
const char* GetMethodKey() const;
const char* GetStatusKey() const;
const char* GetHostKey() const;
const char* GetSchemeKey() const;
- const char* GetVersionKey() const;
const char* GetPathKey() const;
private:
@@ -543,9 +505,6 @@ class SpdyTestUtil {
base::StringPiece url,
int64_t* content_length) const;
- const NextProto protocol_;
- const SpdyMajorVersion spdy_version_;
-
// Multiple SpdyFramers are required to keep track of header compression
// state.
// Use to serialize frames (request or response) without headers.
@@ -556,7 +515,6 @@ class SpdyTestUtil {
SpdyFramer response_spdy_framer_;
GURL default_url_;
- bool dependency_priorities_;
// Track a FIFO list of the stream_id of all created requests by priority.
std::map<int, std::vector<int>> priority_to_stream_id_list_;
diff --git a/chromium/net/spdy/spdy_test_utils.cc b/chromium/net/spdy/spdy_test_utils.cc
index 76ad5de4d54..610c09179d6 100644
--- a/chromium/net/spdy/spdy_test_utils.cc
+++ b/chromium/net/spdy/spdy_test_utils.cc
@@ -13,6 +13,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/sys_byteorder.h"
#include "net/http/transport_security_state.h"
+#include "net/spdy/spdy_flags.h"
#include "net/ssl/ssl_info.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -175,20 +176,18 @@ void TestHeadersHandler::OnHeaderBlockStart() {
void TestHeadersHandler::OnHeader(base::StringPiece name,
base::StringPiece value) {
- auto it = block_.find(name);
- if (it == block_.end()) {
- block_[name] = value;
- } else {
- string new_value = it->second.as_string();
- new_value.append((name == "cookie") ? "; " : string(1, '\0'));
- value.AppendToString(&new_value);
- block_.ReplaceOrAppendHeader(name, new_value);
- }
+ block_.AppendValueOrAddHeader(name, value);
}
void TestHeadersHandler::OnHeaderBlockEnd(size_t header_bytes_parsed) {
header_bytes_parsed_ = header_bytes_parsed;
}
+void TestHeadersHandler::OnHeaderBlockEnd(
+ size_t header_bytes_parsed,
+ size_t /* compressed_header_bytes_parsed */) {
+ header_bytes_parsed_ = header_bytes_parsed;
+}
+
} // namespace test
} // namespace net
diff --git a/chromium/net/spdy/spdy_test_utils.h b/chromium/net/spdy/spdy_test_utils.h
index 297fcd19e76..85b3e8c8d99 100644
--- a/chromium/net/spdy/spdy_test_utils.h
+++ b/chromium/net/spdy/spdy_test_utils.h
@@ -76,6 +76,9 @@ class TestHeadersHandler : public SpdyHeadersHandlerInterface {
void OnHeaderBlockEnd(size_t header_bytes_parsed) override;
+ void OnHeaderBlockEnd(size_t header_bytes_parsed,
+ size_t /* compressed_header_bytes_parsed */) override;
+
const SpdyHeaderBlock& decoded_block() const { return block_; }
size_t header_bytes_parsed() { return header_bytes_parsed_; }
diff --git a/chromium/net/spdy/spdy_write_queue.cc b/chromium/net/spdy/spdy_write_queue.cc
index b49573cdd6a..50df9440a77 100644
--- a/chromium/net/spdy/spdy_write_queue.cc
+++ b/chromium/net/spdy/spdy_write_queue.cc
@@ -5,31 +5,33 @@
#include "net/spdy/spdy_write_queue.h"
#include <cstddef>
+#include <utility>
#include <vector>
#include "base/logging.h"
-#include "base/stl_util.h"
#include "net/spdy/spdy_buffer.h"
#include "net/spdy/spdy_buffer_producer.h"
#include "net/spdy/spdy_stream.h"
namespace net {
-SpdyWriteQueue::PendingWrite::PendingWrite() : frame_producer(NULL) {}
+SpdyWriteQueue::PendingWrite::PendingWrite() {}
SpdyWriteQueue::PendingWrite::PendingWrite(
SpdyFrameType frame_type,
- SpdyBufferProducer* frame_producer,
+ std::unique_ptr<SpdyBufferProducer> frame_producer,
const base::WeakPtr<SpdyStream>& stream)
: frame_type(frame_type),
- frame_producer(frame_producer),
+ frame_producer(std::move(frame_producer)),
stream(stream),
- has_stream(stream.get() != NULL) {}
-
-SpdyWriteQueue::PendingWrite::PendingWrite(const PendingWrite& other) = default;
+ has_stream(stream.get() != nullptr) {}
SpdyWriteQueue::PendingWrite::~PendingWrite() {}
+SpdyWriteQueue::PendingWrite::PendingWrite(PendingWrite&& other) = default;
+SpdyWriteQueue::PendingWrite& SpdyWriteQueue::PendingWrite::operator=(
+ PendingWrite&& other) = default;
+
SpdyWriteQueue::SpdyWriteQueue() : removing_writes_(false) {}
SpdyWriteQueue::~SpdyWriteQueue() {
@@ -53,8 +55,7 @@ void SpdyWriteQueue::Enqueue(RequestPriority priority,
CHECK_LE(priority, MAXIMUM_PRIORITY);
if (stream.get())
DCHECK_EQ(stream->priority(), priority);
- queue_[priority].push_back(
- PendingWrite(frame_type, frame_producer.release(), stream));
+ queue_[priority].push_back({frame_type, std::move(frame_producer), stream});
}
bool SpdyWriteQueue::Dequeue(
@@ -64,10 +65,10 @@ bool SpdyWriteQueue::Dequeue(
CHECK(!removing_writes_);
for (int i = MAXIMUM_PRIORITY; i >= MINIMUM_PRIORITY; --i) {
if (!queue_[i].empty()) {
- PendingWrite pending_write = queue_[i].front();
+ PendingWrite pending_write = std::move(queue_[i].front());
queue_[i].pop_front();
*frame_type = pending_write.frame_type;
- frame_producer->reset(pending_write.frame_producer);
+ *frame_producer = std::move(pending_write.frame_producer);
*stream = pending_write.stream;
if (pending_write.has_stream)
DCHECK(stream->get());
@@ -92,74 +93,66 @@ void SpdyWriteQueue::RemovePendingWritesForStream(
for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
if (priority == i)
continue;
- for (std::deque<PendingWrite>::const_iterator it = queue_[i].begin();
- it != queue_[i].end(); ++it) {
+ for (auto it = queue_[i].begin(); it != queue_[i].end(); ++it)
DCHECK_NE(it->stream.get(), stream.get());
- }
}
#endif
// Defer deletion until queue iteration is complete, as
// SpdyBuffer::~SpdyBuffer() can result in callbacks into SpdyWriteQueue.
- std::vector<SpdyBufferProducer*> erased_buffer_producers;
+ std::vector<std::unique_ptr<SpdyBufferProducer>> erased_buffer_producers;
// Do the actual deletion and removal, preserving FIFO-ness.
- std::deque<PendingWrite>* queue = &queue_[priority];
- std::deque<PendingWrite>::iterator out_it = queue->begin();
- for (std::deque<PendingWrite>::const_iterator it = queue->begin();
- it != queue->end(); ++it) {
+ std::deque<PendingWrite>& queue = queue_[priority];
+ auto out_it = queue.begin();
+ for (auto it = queue.begin(); it != queue.end(); ++it) {
if (it->stream.get() == stream.get()) {
- erased_buffer_producers.push_back(it->frame_producer);
+ erased_buffer_producers.push_back(std::move(it->frame_producer));
} else {
- *out_it = *it;
+ *out_it = std::move(*it);
++out_it;
}
}
- queue->erase(out_it, queue->end());
+ queue.erase(out_it, queue.end());
removing_writes_ = false;
- STLDeleteElements(&erased_buffer_producers); // Invokes callbacks.
}
void SpdyWriteQueue::RemovePendingWritesForStreamsAfter(
SpdyStreamId last_good_stream_id) {
CHECK(!removing_writes_);
removing_writes_ = true;
- std::vector<SpdyBufferProducer*> erased_buffer_producers;
+ std::vector<std::unique_ptr<SpdyBufferProducer>> erased_buffer_producers;
for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
// Do the actual deletion and removal, preserving FIFO-ness.
- std::deque<PendingWrite>* queue = &queue_[i];
- std::deque<PendingWrite>::iterator out_it = queue->begin();
- for (std::deque<PendingWrite>::const_iterator it = queue->begin();
- it != queue->end(); ++it) {
+ std::deque<PendingWrite>& queue = queue_[i];
+ auto out_it = queue.begin();
+ for (auto it = queue.begin(); it != queue.end(); ++it) {
if (it->stream.get() && (it->stream->stream_id() > last_good_stream_id ||
it->stream->stream_id() == 0)) {
- erased_buffer_producers.push_back(it->frame_producer);
+ erased_buffer_producers.push_back(std::move(it->frame_producer));
} else {
- *out_it = *it;
+ *out_it = std::move(*it);
++out_it;
}
}
- queue->erase(out_it, queue->end());
+ queue.erase(out_it, queue.end());
}
removing_writes_ = false;
- STLDeleteElements(&erased_buffer_producers); // Invokes callbacks.
}
void SpdyWriteQueue::Clear() {
CHECK(!removing_writes_);
removing_writes_ = true;
- std::vector<SpdyBufferProducer*> erased_buffer_producers;
+ std::vector<std::unique_ptr<SpdyBufferProducer>> erased_buffer_producers;
for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
- for (std::deque<PendingWrite>::iterator it = queue_[i].begin();
- it != queue_[i].end(); ++it) {
- erased_buffer_producers.push_back(it->frame_producer);
+ for (auto it = queue_[i].begin(); it != queue_[i].end(); ++it) {
+ erased_buffer_producers.push_back(std::move(it->frame_producer));
}
queue_[i].clear();
}
removing_writes_ = false;
- STLDeleteElements(&erased_buffer_producers); // Invokes callbacks.
}
} // namespace net
diff --git a/chromium/net/spdy/spdy_write_queue.h b/chromium/net/spdy/spdy_write_queue.h
index ebc81579751..8ffef3b3a95 100644
--- a/chromium/net/spdy/spdy_write_queue.h
+++ b/chromium/net/spdy/spdy_write_queue.h
@@ -64,19 +64,20 @@ class NET_EXPORT_PRIVATE SpdyWriteQueue {
// A struct holding a frame producer and its associated stream.
struct PendingWrite {
SpdyFrameType frame_type;
- // This has to be a raw pointer since we store this in an STL
- // container.
- SpdyBufferProducer* frame_producer;
+ std::unique_ptr<SpdyBufferProducer> frame_producer;
base::WeakPtr<SpdyStream> stream;
// Whether |stream| was non-NULL when enqueued.
bool has_stream;
PendingWrite();
PendingWrite(SpdyFrameType frame_type,
- SpdyBufferProducer* frame_producer,
+ std::unique_ptr<SpdyBufferProducer> frame_producer,
const base::WeakPtr<SpdyStream>& stream);
- PendingWrite(const PendingWrite& other);
~PendingWrite();
+ PendingWrite(PendingWrite&& other);
+ PendingWrite& operator=(PendingWrite&& other);
+
+ DISALLOW_COPY_AND_ASSIGN(PendingWrite);
};
bool removing_writes_;
diff --git a/chromium/net/spdy/spdy_write_queue_unittest.cc b/chromium/net/spdy/spdy_write_queue_unittest.cc
index 9ffacc840a9..c3587ace569 100644
--- a/chromium/net/spdy/spdy_write_queue_unittest.cc
+++ b/chromium/net/spdy/spdy_write_queue_unittest.cc
@@ -13,7 +13,7 @@
#include "base/memory/ref_counted.h"
#include "base/strings/string_number_conversions.h"
#include "net/base/request_priority.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/spdy/spdy_buffer_producer.h"
#include "net/spdy/spdy_stream.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -95,9 +95,8 @@ int ProducerToInt(std::unique_ptr<SpdyBufferProducer> producer) {
// -- be careful to not call any functions that expect the session to
// be there.
SpdyStream* MakeTestStream(RequestPriority priority) {
- return new SpdyStream(
- SPDY_BIDIRECTIONAL_STREAM, base::WeakPtr<SpdySession>(),
- GURL(), priority, 0, 0, BoundNetLog());
+ return new SpdyStream(SPDY_BIDIRECTIONAL_STREAM, base::WeakPtr<SpdySession>(),
+ GURL(), priority, 0, 0, NetLogWithSource());
}
// Add some frame producers of different priority. The producers
@@ -115,9 +114,9 @@ TEST_F(SpdyWriteQueueTest, DequeuesByPriority) {
std::unique_ptr<SpdyStream> stream_highest(MakeTestStream(HIGHEST));
// A NULL stream should still work.
- write_queue.Enqueue(LOW, SYN_STREAM, std::move(producer_low),
+ write_queue.Enqueue(LOW, HEADERS, std::move(producer_low),
base::WeakPtr<SpdyStream>());
- write_queue.Enqueue(MEDIUM, SYN_REPLY, std::move(producer_medium),
+ write_queue.Enqueue(MEDIUM, HEADERS, std::move(producer_medium),
stream_medium->GetWeakPtr());
write_queue.Enqueue(HIGHEST, RST_STREAM, std::move(producer_highest),
stream_highest->GetWeakPtr());
@@ -131,12 +130,12 @@ TEST_F(SpdyWriteQueueTest, DequeuesByPriority) {
EXPECT_EQ(stream_highest.get(), stream.get());
ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
- EXPECT_EQ(SYN_REPLY, frame_type);
+ EXPECT_EQ(HEADERS, frame_type);
EXPECT_EQ("MEDIUM", ProducerToString(std::move(frame_producer)));
EXPECT_EQ(stream_medium.get(), stream.get());
ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
- EXPECT_EQ(SYN_STREAM, frame_type);
+ EXPECT_EQ(HEADERS, frame_type);
EXPECT_EQ("LOW", ProducerToString(std::move(frame_producer)));
EXPECT_EQ(nullptr, stream.get());
@@ -156,9 +155,9 @@ TEST_F(SpdyWriteQueueTest, DequeuesFIFO) {
std::unique_ptr<SpdyStream> stream2(MakeTestStream(DEFAULT_PRIORITY));
std::unique_ptr<SpdyStream> stream3(MakeTestStream(DEFAULT_PRIORITY));
- write_queue.Enqueue(DEFAULT_PRIORITY, SYN_STREAM, std::move(producer1),
+ write_queue.Enqueue(DEFAULT_PRIORITY, HEADERS, std::move(producer1),
stream1->GetWeakPtr());
- write_queue.Enqueue(DEFAULT_PRIORITY, SYN_REPLY, std::move(producer2),
+ write_queue.Enqueue(DEFAULT_PRIORITY, HEADERS, std::move(producer2),
stream2->GetWeakPtr());
write_queue.Enqueue(DEFAULT_PRIORITY, RST_STREAM, std::move(producer3),
stream3->GetWeakPtr());
@@ -167,12 +166,12 @@ TEST_F(SpdyWriteQueueTest, DequeuesFIFO) {
std::unique_ptr<SpdyBufferProducer> frame_producer;
base::WeakPtr<SpdyStream> stream;
ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
- EXPECT_EQ(SYN_STREAM, frame_type);
+ EXPECT_EQ(HEADERS, frame_type);
EXPECT_EQ(1, ProducerToInt(std::move(frame_producer)));
EXPECT_EQ(stream1.get(), stream.get());
ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
- EXPECT_EQ(SYN_REPLY, frame_type);
+ EXPECT_EQ(HEADERS, frame_type);
EXPECT_EQ(2, ProducerToInt(std::move(frame_producer)));
EXPECT_EQ(stream2.get(), stream.get());
@@ -196,7 +195,7 @@ TEST_F(SpdyWriteQueueTest, RemovePendingWritesForStream) {
for (int i = 0; i < 100; ++i) {
base::WeakPtr<SpdyStream> stream =
(((i % 3) == 0) ? stream1 : stream2)->GetWeakPtr();
- write_queue.Enqueue(DEFAULT_PRIORITY, SYN_STREAM, IntToProducer(i), stream);
+ write_queue.Enqueue(DEFAULT_PRIORITY, HEADERS, IntToProducer(i), stream);
}
write_queue.RemovePendingWritesForStream(stream2->GetWeakPtr());
@@ -206,7 +205,7 @@ TEST_F(SpdyWriteQueueTest, RemovePendingWritesForStream) {
std::unique_ptr<SpdyBufferProducer> frame_producer;
base::WeakPtr<SpdyStream> stream;
ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
- EXPECT_EQ(SYN_STREAM, frame_type);
+ EXPECT_EQ(HEADERS, frame_type);
EXPECT_EQ(i, ProducerToInt(std::move(frame_producer)));
EXPECT_EQ(stream1.get(), stream.get());
}
@@ -238,7 +237,7 @@ TEST_F(SpdyWriteQueueTest, RemovePendingWritesForStreamsAfter) {
};
for (int i = 0; i < 100; ++i) {
- write_queue.Enqueue(DEFAULT_PRIORITY, SYN_STREAM, IntToProducer(i),
+ write_queue.Enqueue(DEFAULT_PRIORITY, HEADERS, IntToProducer(i),
streams[i % arraysize(streams)]);
}
@@ -250,7 +249,7 @@ TEST_F(SpdyWriteQueueTest, RemovePendingWritesForStreamsAfter) {
base::WeakPtr<SpdyStream> stream;
ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream))
<< "Unable to Dequeue i: " << i;
- EXPECT_EQ(SYN_STREAM, frame_type);
+ EXPECT_EQ(HEADERS, frame_type);
EXPECT_EQ(i, ProducerToInt(std::move(frame_producer)));
EXPECT_EQ(stream1.get(), stream.get());
}
@@ -268,7 +267,7 @@ TEST_F(SpdyWriteQueueTest, Clear) {
SpdyWriteQueue write_queue;
for (int i = 0; i < 100; ++i) {
- write_queue.Enqueue(DEFAULT_PRIORITY, SYN_STREAM, IntToProducer(i),
+ write_queue.Enqueue(DEFAULT_PRIORITY, HEADERS, IntToProducer(i),
base::WeakPtr<SpdyStream>());
}
@@ -283,7 +282,7 @@ TEST_F(SpdyWriteQueueTest, Clear) {
TEST_F(SpdyWriteQueueTest, RequeingProducerWithoutReentrance) {
SpdyWriteQueue queue;
queue.Enqueue(
- DEFAULT_PRIORITY, SYN_STREAM,
+ DEFAULT_PRIORITY, HEADERS,
std::unique_ptr<SpdyBufferProducer>(new RequeingBufferProducer(&queue)),
base::WeakPtr<SpdyStream>());
{
@@ -309,7 +308,7 @@ TEST_F(SpdyWriteQueueTest, RequeingProducerWithoutReentrance) {
TEST_F(SpdyWriteQueueTest, ReentranceOnClear) {
SpdyWriteQueue queue;
queue.Enqueue(
- DEFAULT_PRIORITY, SYN_STREAM,
+ DEFAULT_PRIORITY, HEADERS,
std::unique_ptr<SpdyBufferProducer>(new RequeingBufferProducer(&queue)),
base::WeakPtr<SpdyStream>());
@@ -330,7 +329,7 @@ TEST_F(SpdyWriteQueueTest, ReentranceOnRemovePendingWritesAfter) {
SpdyWriteQueue queue;
queue.Enqueue(
- DEFAULT_PRIORITY, SYN_STREAM,
+ DEFAULT_PRIORITY, HEADERS,
std::unique_ptr<SpdyBufferProducer>(new RequeingBufferProducer(&queue)),
stream->GetWeakPtr());
@@ -351,7 +350,7 @@ TEST_F(SpdyWriteQueueTest, ReentranceOnRemovePendingWritesForStream) {
SpdyWriteQueue queue;
queue.Enqueue(
- DEFAULT_PRIORITY, SYN_STREAM,
+ DEFAULT_PRIORITY, HEADERS,
std::unique_ptr<SpdyBufferProducer>(new RequeingBufferProducer(&queue)),
stream->GetWeakPtr());
diff --git a/chromium/net/spdy/write_scheduler.h b/chromium/net/spdy/write_scheduler.h
index ebcefc2ae1d..3d24335708a 100644
--- a/chromium/net/spdy/write_scheduler.h
+++ b/chromium/net/spdy/write_scheduler.h
@@ -8,6 +8,7 @@
#include <tuple>
#include <vector>
+#include "net/base/net_export.h"
#include "net/spdy/spdy_protocol.h"
namespace net {
diff --git a/chromium/net/ssl/channel_id_service.cc b/chromium/net/ssl/channel_id_service.cc
index 500a7400a4f..53c3c636cd7 100644
--- a/chromium/net/ssl/channel_id_service.cc
+++ b/chromium/net/ssl/channel_id_service.cc
@@ -17,11 +17,11 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
#include "base/task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "crypto/ec_private_key.h"
@@ -285,7 +285,6 @@ ChannelIDService::ChannelIDService(
weak_ptr_factory_(this) {}
ChannelIDService::~ChannelIDService() {
- STLDeleteValues(&inflight_);
}
// static
@@ -303,7 +302,7 @@ int ChannelIDService::GetOrCreateChannelID(
std::unique_ptr<crypto::ECPrivateKey>* key,
const CompletionCallback& callback,
Request* out_req) {
- DVLOG(1) << __FUNCTION__ << " " << host;
+ DVLOG(1) << __func__ << " " << host;
DCHECK(CalledOnValidThread());
base::TimeTicks request_start = base::TimeTicks::Now();
@@ -344,7 +343,7 @@ int ChannelIDService::GetOrCreateChannelID(
}
// We are waiting for key generation. Create a job & request to track it.
ChannelIDServiceJob* job = new ChannelIDServiceJob(create_if_missing);
- inflight_[domain] = job;
+ inflight_[domain] = base::WrapUnique(job);
job->AddRequest(out_req);
out_req->RequestStarted(this, request_start, callback, key, job);
@@ -358,7 +357,7 @@ int ChannelIDService::GetChannelID(const std::string& host,
std::unique_ptr<crypto::ECPrivateKey>* key,
const CompletionCallback& callback,
Request* out_req) {
- DVLOG(1) << __FUNCTION__ << " " << host;
+ DVLOG(1) << __func__ << " " << host;
DCHECK(CalledOnValidThread());
base::TimeTicks request_start = base::TimeTicks::Now();
@@ -392,8 +391,7 @@ void ChannelIDService::GotChannelID(int err,
std::unique_ptr<crypto::ECPrivateKey> key) {
DCHECK(CalledOnValidThread());
- std::map<std::string, ChannelIDServiceJob*>::iterator j;
- j = inflight_.find(server_identifier);
+ auto j = inflight_.find(server_identifier);
if (j == inflight_.end()) {
NOTREACHED();
return;
@@ -450,17 +448,15 @@ void ChannelIDService::HandleResult(int error,
std::unique_ptr<crypto::ECPrivateKey> key) {
DCHECK(CalledOnValidThread());
- std::map<std::string, ChannelIDServiceJob*>::iterator j;
- j = inflight_.find(server_identifier);
+ auto j = inflight_.find(server_identifier);
if (j == inflight_.end()) {
NOTREACHED();
return;
}
- ChannelIDServiceJob* job = j->second;
+ std::unique_ptr<ChannelIDServiceJob> job = std::move(j->second);
inflight_.erase(j);
job->HandleResult(error, std::move(key));
- delete job;
}
bool ChannelIDService::JoinToInFlightRequest(
@@ -471,13 +467,12 @@ bool ChannelIDService::JoinToInFlightRequest(
const CompletionCallback& callback,
Request* out_req) {
ChannelIDServiceJob* job = NULL;
- std::map<std::string, ChannelIDServiceJob*>::const_iterator j =
- inflight_.find(domain);
+ auto j = inflight_.find(domain);
if (j != inflight_.end()) {
// A request for the same domain is in flight already. We'll attach our
// callback, but we'll also mark it as requiring a channel ID if one's
// mising.
- job = j->second;
+ job = j->second.get();
inflight_joins_++;
job->AddRequest(out_req, create_if_missing);
@@ -513,7 +508,7 @@ int ChannelIDService::LookupChannelID(
if (err == ERR_IO_PENDING) {
// We are waiting for async DB lookup. Create a job & request to track it.
ChannelIDServiceJob* job = new ChannelIDServiceJob(create_if_missing);
- inflight_[domain] = job;
+ inflight_[domain] = base::WrapUnique(job);
job->AddRequest(out_req);
out_req->RequestStarted(this, request_start, callback, key, job);
diff --git a/chromium/net/ssl/channel_id_service.h b/chromium/net/ssl/channel_id_service.h
index 767973cbcee..0134873d954 100644
--- a/chromium/net/ssl/channel_id_service.h
+++ b/chromium/net/ssl/channel_id_service.h
@@ -179,7 +179,7 @@ class NET_EXPORT ChannelIDService
// inflight_ maps from a server to an active generation which is taking
// place.
- std::map<std::string, ChannelIDServiceJob*> inflight_;
+ std::map<std::string, std::unique_ptr<ChannelIDServiceJob>> inflight_;
uint64_t requests_;
uint64_t key_store_hits_;
diff --git a/chromium/net/ssl/channel_id_service_unittest.cc b/chromium/net/ssl/channel_id_service_unittest.cc
index c1833fa2f4f..dbb41fc1dd5 100644
--- a/chromium/net/ssl/channel_id_service_unittest.cc
+++ b/chromium/net/ssl/channel_id_service_unittest.cc
@@ -23,8 +23,13 @@
#include "net/cert/x509_certificate.h"
#include "net/ssl/default_channel_id_store.h"
#include "net/test/channel_id_test_util.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -143,7 +148,7 @@ TEST_F(ChannelIDServiceTest, GetCacheMiss) {
std::unique_ptr<crypto::ECPrivateKey> key;
EXPECT_EQ(0, service_->channel_id_count());
error = service_->GetChannelID(host, &key, callback.callback(), &request);
- EXPECT_EQ(ERR_FILE_NOT_FOUND, error);
+ EXPECT_THAT(error, IsError(ERR_FILE_NOT_FOUND));
EXPECT_FALSE(request.is_active());
EXPECT_EQ(0, service_->channel_id_count());
EXPECT_FALSE(key);
@@ -161,10 +166,10 @@ TEST_F(ChannelIDServiceTest, CacheHit) {
EXPECT_EQ(0, service_->channel_id_count());
error = service_->GetOrCreateChannelID(host, &key1, callback.callback(),
&request);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request.is_active());
error = callback.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(1, service_->channel_id_count());
EXPECT_TRUE(key1);
EXPECT_FALSE(request.is_active());
@@ -174,7 +179,7 @@ TEST_F(ChannelIDServiceTest, CacheHit) {
error = service_->GetOrCreateChannelID(host, &key2, callback.callback(),
&request);
EXPECT_FALSE(request.is_active());
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(1, service_->channel_id_count());
EXPECT_TRUE(KeysEqual(key1.get(), key2.get()));
@@ -182,7 +187,7 @@ TEST_F(ChannelIDServiceTest, CacheHit) {
std::unique_ptr<crypto::ECPrivateKey> key3;
error = service_->GetChannelID(host, &key3, callback.callback(), &request);
EXPECT_FALSE(request.is_active());
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(1, service_->channel_id_count());
EXPECT_TRUE(KeysEqual(key1.get(), key3.get()));
@@ -201,30 +206,30 @@ TEST_F(ChannelIDServiceTest, StoreChannelIDs) {
EXPECT_EQ(0, service_->channel_id_count());
error = service_->GetOrCreateChannelID(host1, &key1, callback.callback(),
&request);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request.is_active());
error = callback.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(1, service_->channel_id_count());
std::string host2("www.verisign.com");
std::unique_ptr<crypto::ECPrivateKey> key2;
error = service_->GetOrCreateChannelID(host2, &key2, callback.callback(),
&request);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request.is_active());
error = callback.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(2, service_->channel_id_count());
std::string host3("www.twitter.com");
std::unique_ptr<crypto::ECPrivateKey> key3;
error = service_->GetOrCreateChannelID(host3, &key3, callback.callback(),
&request);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request.is_active());
error = callback.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(3, service_->channel_id_count());
EXPECT_FALSE(KeysEqual(key1.get(), key2.get()));
@@ -247,18 +252,18 @@ TEST_F(ChannelIDServiceTest, InflightJoin) {
error = service_->GetOrCreateChannelID(host, &key1, callback1.callback(),
&request1);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request1.is_active());
// Should join with the original request.
error = service_->GetOrCreateChannelID(host, &key2, callback2.callback(),
&request2);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request2.is_active());
error = callback1.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
error = callback2.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(2u, service_->requests());
EXPECT_EQ(0u, service_->key_store_hits());
@@ -281,17 +286,17 @@ TEST_F(ChannelIDServiceTest, InflightJoinGetOrCreateAndGet) {
error = service_->GetOrCreateChannelID(host, &key1, callback1.callback(),
&request1);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request1.is_active());
// Should join with the original request.
error = service_->GetChannelID(host, &key2, callback2.callback(), &request2);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request2.is_active());
error = callback1.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
error = callback2.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_TRUE(KeysEqual(key1.get(), key2.get()));
EXPECT_EQ(2u, service_->requests());
@@ -309,7 +314,7 @@ TEST_F(ChannelIDServiceTest, CancelRequest) {
error = service_->GetOrCreateChannelID(host, &key, base::Bind(&FailTest),
&request);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request.is_active());
request.Cancel();
EXPECT_FALSE(request.is_active());
@@ -333,7 +338,7 @@ TEST_F(ChannelIDServiceTest, CancelRequestByHandleDestruction) {
error = service_->GetOrCreateChannelID(host, &key, base::Bind(&FailTest),
request.get());
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request->is_active());
// Delete the Request object.
@@ -356,7 +361,7 @@ TEST_F(ChannelIDServiceTest, DestructionWithPendingRequest) {
error = service_->GetOrCreateChannelID(host, &key, base::Bind(&FailTest),
&request);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request.is_active());
// Cancel request and destroy the ChannelIDService.
@@ -388,7 +393,7 @@ TEST_F(ChannelIDServiceTest, RequestAfterPoolShutdown) {
error = service_->GetOrCreateChannelID(host, &key, base::Bind(&FailTest),
&request);
// If we got here without crashing or a valgrind error, it worked.
- ASSERT_EQ(ERR_INSUFFICIENT_RESOURCES, error);
+ ASSERT_THAT(error, IsError(ERR_INSUFFICIENT_RESOURCES));
EXPECT_FALSE(request.is_active());
}
@@ -413,29 +418,29 @@ TEST_F(ChannelIDServiceTest, SimultaneousCreation) {
error = service_->GetOrCreateChannelID(host1, &key1, callback1.callback(),
&request1);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request1.is_active());
error = service_->GetOrCreateChannelID(host2, &key2, callback2.callback(),
&request2);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request2.is_active());
error = service_->GetOrCreateChannelID(host3, &key3, callback3.callback(),
&request3);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request3.is_active());
error = callback1.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_TRUE(key1);
error = callback2.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_TRUE(key2);
error = callback3.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_TRUE(key3);
EXPECT_FALSE(KeysEqual(key1.get(), key2.get()));
@@ -462,13 +467,13 @@ TEST_F(ChannelIDServiceTest, AsyncStoreGetOrCreateNoChannelIDsInStore) {
EXPECT_EQ(0, service_->channel_id_count());
error =
service_->GetOrCreateChannelID(host, &key, callback.callback(), &request);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request.is_active());
mock_store->CallGetChannelIDCallbackWithResult(ERR_FILE_NOT_FOUND, nullptr);
error = callback.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(1, service_->channel_id_count());
EXPECT_TRUE(key);
EXPECT_FALSE(request.is_active());
@@ -490,13 +495,13 @@ TEST_F(ChannelIDServiceTest, AsyncStoreGetNoChannelIDsInStore) {
std::unique_ptr<crypto::ECPrivateKey> key;
EXPECT_EQ(0, service_->channel_id_count());
error = service_->GetChannelID(host, &key, callback.callback(), &request);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request.is_active());
mock_store->CallGetChannelIDCallbackWithResult(ERR_FILE_NOT_FOUND, nullptr);
error = callback.WaitForResult();
- EXPECT_EQ(ERR_FILE_NOT_FOUND, error);
+ EXPECT_THAT(error, IsError(ERR_FILE_NOT_FOUND));
EXPECT_EQ(0, service_->channel_id_count());
EXPECT_EQ(0u, service_->workers_created());
EXPECT_FALSE(key);
@@ -520,7 +525,7 @@ TEST_F(ChannelIDServiceTest, AsyncStoreGetOrCreateOneCertInStore) {
EXPECT_EQ(0, service_->channel_id_count());
error =
service_->GetOrCreateChannelID(host, &key, callback.callback(), &request);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request.is_active());
std::unique_ptr<crypto::ECPrivateKey> expected_key(
@@ -528,7 +533,7 @@ TEST_F(ChannelIDServiceTest, AsyncStoreGetOrCreateOneCertInStore) {
mock_store->CallGetChannelIDCallbackWithResult(OK, expected_key.get());
error = callback.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(1, service_->channel_id_count());
EXPECT_EQ(1u, service_->requests());
EXPECT_EQ(1u, service_->key_store_hits());
@@ -557,7 +562,7 @@ TEST_F(ChannelIDServiceTest, AsyncStoreGetOneCertInStore) {
std::string private_key, spki;
EXPECT_EQ(0, service_->channel_id_count());
error = service_->GetChannelID(host, &key, callback.callback(), &request);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request.is_active());
std::unique_ptr<crypto::ECPrivateKey> expected_key(
@@ -565,7 +570,7 @@ TEST_F(ChannelIDServiceTest, AsyncStoreGetOneCertInStore) {
mock_store->CallGetChannelIDCallbackWithResult(OK, expected_key.get());
error = callback.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
EXPECT_EQ(1, service_->channel_id_count());
EXPECT_EQ(1u, service_->requests());
EXPECT_EQ(1u, service_->key_store_hits());
@@ -592,7 +597,7 @@ TEST_F(ChannelIDServiceTest, AsyncStoreGetThenCreateNoCertsInStore) {
std::unique_ptr<crypto::ECPrivateKey> key1;
EXPECT_EQ(0, service_->channel_id_count());
error = service_->GetChannelID(host, &key1, callback1.callback(), &request1);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request1.is_active());
// Asynchronous get/create with no certs in the store.
@@ -602,7 +607,7 @@ TEST_F(ChannelIDServiceTest, AsyncStoreGetThenCreateNoCertsInStore) {
EXPECT_EQ(0, service_->channel_id_count());
error = service_->GetOrCreateChannelID(host, &key2, callback2.callback(),
&request2);
- EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_THAT(error, IsError(ERR_IO_PENDING));
EXPECT_TRUE(request2.is_active());
mock_store->CallGetChannelIDCallbackWithResult(ERR_FILE_NOT_FOUND, nullptr);
@@ -610,9 +615,9 @@ TEST_F(ChannelIDServiceTest, AsyncStoreGetThenCreateNoCertsInStore) {
// Even though the first request didn't ask to create a cert, it gets joined
// by the second, which does, so both succeed.
error = callback1.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
error = callback2.WaitForResult();
- EXPECT_EQ(OK, error);
+ EXPECT_THAT(error, IsOk());
// One cert is created, one request is joined.
EXPECT_EQ(2U, service_->requests());
diff --git a/chromium/net/ssl/client_cert_store_nss.cc b/chromium/net/ssl/client_cert_store_nss.cc
index e46458ad99e..dab47284180 100644
--- a/chromium/net/ssl/client_cert_store_nss.cc
+++ b/chromium/net/ssl/client_cert_store_nss.cc
@@ -10,6 +10,7 @@
#include <algorithm>
#include <memory>
#include <utility>
+#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -18,8 +19,10 @@
#include "base/strings/string_piece.h"
#include "base/threading/worker_pool.h"
#include "crypto/nss_crypto_module_delegate.h"
+#include "net/cert/scoped_nss_types.h"
#include "net/cert/x509_util.h"
#include "net/ssl/ssl_cert_request_info.h"
+#include "net/third_party/nss/ssl/cmpcert.h"
namespace net {
@@ -63,26 +66,6 @@ void ClientCertStoreNSS::FilterCertsOnWorkerThread(
filtered_certs->clear();
- // Create a "fake" CERTDistNames structure. No public API exists to create
- // one from a list of issuers.
- CERTDistNames ca_names;
- ca_names.arena = NULL;
- ca_names.nnames = 0;
- ca_names.names = NULL;
- ca_names.head = NULL;
-
- std::vector<SECItem> ca_names_items(request.cert_authorities.size());
- for (size_t i = 0; i < request.cert_authorities.size(); ++i) {
- const std::string& authority = request.cert_authorities[i];
- ca_names_items[i].type = siBuffer;
- ca_names_items[i].data =
- reinterpret_cast<unsigned char*>(const_cast<char*>(authority.data()));
- ca_names_items[i].len = static_cast<unsigned int>(authority.size());
- }
- ca_names.nnames = static_cast<int>(ca_names_items.size());
- if (!ca_names_items.empty())
- ca_names.names = &ca_names_items[0];
-
size_t num_raw = 0;
for (const auto& cert : certs) {
++num_raw;
@@ -96,16 +79,26 @@ void ClientCertStoreNSS::FilterCertsOnWorkerThread(
continue;
}
- // Check if the certificate issuer is allowed by the server.
- if (!request.cert_authorities.empty() &&
- NSS_CmpCertChainWCANames(handle, &ca_names) != SECSuccess) {
+ std::vector<ScopedCERTCertificate> intermediates;
+ if (!MatchClientCertificateIssuers(handle, request.cert_authorities,
+ &intermediates)) {
DVLOG(2) << "skipped non-matching cert: "
<< base::StringPiece(handle->nickname);
continue;
}
DVLOG(2) << "matched cert: " << base::StringPiece(handle->nickname);
- filtered_certs->push_back(cert);
+
+ X509Certificate::OSCertHandles intermediates_raw;
+ for (const auto& intermediate : intermediates) {
+ intermediates_raw.push_back(intermediate.get());
+ }
+
+ // Retain a copy of the intermediates. Some deployments expect the client to
+ // supply intermediates out of the local store. See
+ // https://crbug.com/548631.
+ filtered_certs->push_back(
+ X509Certificate::CreateFromHandle(handle, intermediates_raw));
}
DVLOG(2) << "num_raw:" << num_raw
<< " num_filtered:" << filtered_certs->size();
diff --git a/chromium/net/ssl/client_cert_store_nss_unittest.cc b/chromium/net/ssl/client_cert_store_nss_unittest.cc
index dbf06660bb0..bc222e87696 100644
--- a/chromium/net/ssl/client_cert_store_nss_unittest.cc
+++ b/chromium/net/ssl/client_cert_store_nss_unittest.cc
@@ -4,7 +4,21 @@
#include "net/ssl/client_cert_store_nss.h"
+#include <cert.h>
+#include <certt.h>
+#include <pk11pub.h>
+
+#include <memory>
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "crypto/scoped_test_nss_db.h"
+#include "net/cert/x509_certificate.h"
#include "net/ssl/client_cert_store_unittest-inl.h"
+#include "net/ssl/ssl_cert_request_info.h"
+#include "net/test/cert_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -27,4 +41,66 @@ INSTANTIATE_TYPED_TEST_CASE_P(NSS,
ClientCertStoreTest,
ClientCertStoreNSSTestDelegate);
+// Tests that ClientCertStoreNSS attempts to build a certificate chain by
+// querying NSS before return a certificate.
+TEST(ClientCertStoreNSSTest, BuildsCertificateChain) {
+ // Set up a test DB and import client_1.pem and client_1_ca.pem.
+ crypto::ScopedTestNSSDB test_db;
+ scoped_refptr<X509Certificate> client_1(ImportClientCertAndKeyFromFile(
+ GetTestCertsDirectory(), "client_1.pem", "client_1.pk8", test_db.slot()));
+ ASSERT_TRUE(client_1.get());
+ scoped_refptr<X509Certificate> client_1_ca(
+ ImportCertFromFile(GetTestCertsDirectory(), "client_1_ca.pem"));
+ ASSERT_TRUE(client_1_ca.get());
+ ASSERT_EQ(SECSuccess,
+ PK11_ImportCert(test_db.slot(), client_1_ca->os_cert_handle(),
+ CK_INVALID_HANDLE, "client_1_ca",
+ PR_FALSE /* includeTrust (unused) */));
+
+ std::unique_ptr<ClientCertStoreNSS> store(
+ new ClientCertStoreNSS(ClientCertStoreNSS::PasswordDelegateFactory()));
+
+ {
+ // Request certificates matching B CA, |client_1|'s issuer.
+ scoped_refptr<SSLCertRequestInfo> request(new SSLCertRequestInfo);
+ request->cert_authorities.push_back(std::string(
+ reinterpret_cast<const char*>(kAuthority1DN), sizeof(kAuthority1DN)));
+
+ CertificateList selected_certs;
+ base::RunLoop loop;
+ store->GetClientCerts(*request.get(), &selected_certs, loop.QuitClosure());
+ loop.Run();
+
+ // The result be |client_1| with no intermediates.
+ ASSERT_EQ(1u, selected_certs.size());
+ scoped_refptr<X509Certificate> selected_cert = selected_certs[0];
+ EXPECT_TRUE(X509Certificate::IsSameOSCert(client_1->os_cert_handle(),
+ selected_cert->os_cert_handle()));
+ ASSERT_EQ(0u, selected_cert->GetIntermediateCertificates().size());
+ }
+
+ {
+ // Request certificates matching C Root CA, |client_1_ca|'s issuer.
+ scoped_refptr<SSLCertRequestInfo> request(new SSLCertRequestInfo);
+ request->cert_authorities.push_back(
+ std::string(reinterpret_cast<const char*>(kAuthorityRootDN),
+ sizeof(kAuthorityRootDN)));
+
+ CertificateList selected_certs;
+ base::RunLoop loop;
+ store->GetClientCerts(*request.get(), &selected_certs, loop.QuitClosure());
+ loop.Run();
+
+ // The result be |client_1| with |client_1_ca| as an intermediate.
+ ASSERT_EQ(1u, selected_certs.size());
+ scoped_refptr<X509Certificate> selected_cert = selected_certs[0];
+ 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]));
+ }
+}
+
} // namespace net
diff --git a/chromium/net/ssl/client_cert_store_unittest-inl.h b/chromium/net/ssl/client_cert_store_unittest-inl.h
index 22a15fcaf95..b72ba254f84 100644
--- a/chromium/net/ssl/client_cert_store_unittest-inl.h
+++ b/chromium/net/ssl/client_cert_store_unittest-inl.h
@@ -22,14 +22,21 @@ namespace {
// "CN=B CA" - DER encoded DN of the issuer of client_1.pem
const unsigned char kAuthority1DN[] = {
- 0x30, 0x0f, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
- 0x04, 0x42, 0x20, 0x43, 0x41
+ 0x30, 0x0f, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55,
+ 0x04, 0x03, 0x0c, 0x04, 0x42, 0x20, 0x43, 0x41,
};
// "CN=E CA" - DER encoded DN of the issuer of client_2.pem
-unsigned char kAuthority2DN[] = {
- 0x30, 0x0f, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
- 0x04, 0x45, 0x20, 0x43, 0x41
+const unsigned char kAuthority2DN[] = {
+ 0x30, 0x0f, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55,
+ 0x04, 0x03, 0x0c, 0x04, 0x45, 0x20, 0x43, 0x41,
+};
+
+// "CN=C Root CA" - DER encoded DN of the issuer of client_1_ca.pem,
+// client_2_ca.pem, and client_3_ca.pem.
+const unsigned char kAuthorityRootDN[] = {
+ 0x30, 0x14, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x0c, 0x09, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
};
} // namespace
diff --git a/chromium/net/ssl/default_channel_id_store_unittest.cc b/chromium/net/ssl/default_channel_id_store_unittest.cc
index 9a74ee9fadb..9408d6eebf9 100644
--- a/chromium/net/ssl/default_channel_id_store_unittest.cc
+++ b/chromium/net/ssl/default_channel_id_store_unittest.cc
@@ -21,8 +21,13 @@
#include "crypto/ec_private_key.h"
#include "net/base/net_errors.h"
#include "net/test/channel_id_test_util.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -97,7 +102,7 @@ void MockPersistentStore::Load(const LoadedCallback& loaded_callback) {
for (it = channel_ids_.begin(); it != channel_ids_.end(); ++it) {
channel_ids->push_back(
- base::WrapUnique(new DefaultChannelIDStore::ChannelID(it->second)));
+ base::MakeUnique<DefaultChannelIDStore::ChannelID>(it->second));
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -140,13 +145,13 @@ TEST(DefaultChannelIDStoreTest, TestLoading) {
DefaultChannelIDStore store(persistent_store.get());
// Load has not occurred yet.
EXPECT_EQ(0, store.GetChannelIDCount());
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "verisign.com", base::Time(), crypto::ECPrivateKey::Create())));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "verisign.com", base::Time(), crypto::ECPrivateKey::Create()));
// Wait for load & queued set task.
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2, store.GetChannelIDCount());
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "twitter.com", base::Time(), crypto::ECPrivateKey::Create())));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "twitter.com", base::Time(), crypto::ECPrivateKey::Create()));
// Set should be synchronous now that load is done.
EXPECT_EQ(3, store.GetChannelIDCount());
}
@@ -180,12 +185,12 @@ TEST(DefaultChannelIDStoreTest, TestDuplicateChannelIds) {
std::unique_ptr<crypto::ECPrivateKey> key;
EXPECT_EQ(0, store.GetChannelIDCount());
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
"verisign.com", base::Time::FromInternalValue(123),
- crypto::ECPrivateKey::Create())));
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
+ crypto::ECPrivateKey::Create()));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
"verisign.com", base::Time::FromInternalValue(456),
- expected_key->Copy())));
+ expected_key->Copy()));
// Wait for load & queued set tasks.
base::RunLoop().RunUntilIdle();
@@ -217,7 +222,7 @@ TEST(DefaultChannelIDStoreTest, TestAsyncGet) {
EXPECT_EQ(1, store.GetChannelIDCount());
EXPECT_FALSE(key);
EXPECT_TRUE(helper.called_);
- EXPECT_EQ(OK, helper.err_);
+ EXPECT_THAT(helper.err_, IsOk());
EXPECT_EQ("verisign.com", helper.server_identifier_);
EXPECT_TRUE(KeysEqual(expected_key.get(), helper.key_.get()));
}
@@ -226,12 +231,12 @@ TEST(DefaultChannelIDStoreTest, TestDeleteAll) {
scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
DefaultChannelIDStore store(persistent_store.get());
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "verisign.com", base::Time(), crypto::ECPrivateKey::Create())));
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "google.com", base::Time(), crypto::ECPrivateKey::Create())));
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "harvard.com", base::Time(), crypto::ECPrivateKey::Create())));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "verisign.com", base::Time(), crypto::ECPrivateKey::Create()));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "google.com", base::Time(), crypto::ECPrivateKey::Create()));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "harvard.com", base::Time(), crypto::ECPrivateKey::Create()));
// Wait for load & queued set tasks.
base::RunLoop().RunUntilIdle();
@@ -246,12 +251,12 @@ TEST(DefaultChannelIDStoreTest, TestDeleteForDomains) {
scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
DefaultChannelIDStore store(persistent_store.get());
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "verisign.com", base::Time(), crypto::ECPrivateKey::Create())));
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "google.com", base::Time(), crypto::ECPrivateKey::Create())));
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "harvard.com", base::Time(), crypto::ECPrivateKey::Create())));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "verisign.com", base::Time(), crypto::ECPrivateKey::Create()));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "google.com", base::Time(), crypto::ECPrivateKey::Create()));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "harvard.com", base::Time(), crypto::ECPrivateKey::Create()));
// Wait for load & queued set tasks.
base::RunLoop().RunUntilIdle();
EXPECT_EQ(3, store.GetChannelIDCount());
@@ -310,13 +315,13 @@ TEST(DefaultChannelIDStoreTest, TestDelete) {
std::unique_ptr<crypto::ECPrivateKey> key;
EXPECT_EQ(0, store.GetChannelIDCount());
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "verisign.com", base::Time(), crypto::ECPrivateKey::Create())));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "verisign.com", base::Time(), crypto::ECPrivateKey::Create()));
// Wait for load & queued set task.
base::RunLoop().RunUntilIdle();
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "google.com", base::Time(), crypto::ECPrivateKey::Create())));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "google.com", base::Time(), crypto::ECPrivateKey::Create()));
EXPECT_EQ(2, store.GetChannelIDCount());
int delete_finished = 0;
@@ -375,11 +380,11 @@ TEST(DefaultChannelIDStoreTest, TestAsyncDelete) {
EXPECT_EQ(1, store.GetChannelIDCount());
EXPECT_FALSE(key);
EXPECT_TRUE(a_helper.called_);
- EXPECT_EQ(ERR_FILE_NOT_FOUND, a_helper.err_);
+ EXPECT_THAT(a_helper.err_, IsError(ERR_FILE_NOT_FOUND));
EXPECT_EQ("a.com", a_helper.server_identifier_);
EXPECT_FALSE(a_helper.key_);
EXPECT_TRUE(b_helper.called_);
- EXPECT_EQ(OK, b_helper.err_);
+ EXPECT_THAT(b_helper.err_, IsOk());
EXPECT_EQ("b.com", b_helper.server_identifier_);
EXPECT_TRUE(KeysEqual(expected_key.get(), b_helper.key_.get()));
}
@@ -389,14 +394,14 @@ TEST(DefaultChannelIDStoreTest, TestGetAll) {
DefaultChannelIDStore store(persistent_store.get());
EXPECT_EQ(0, store.GetChannelIDCount());
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "verisign.com", base::Time(), crypto::ECPrivateKey::Create())));
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "google.com", base::Time(), crypto::ECPrivateKey::Create())));
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "harvard.com", base::Time(), crypto::ECPrivateKey::Create())));
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "mit.com", base::Time(), crypto::ECPrivateKey::Create())));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "verisign.com", base::Time(), crypto::ECPrivateKey::Create()));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "google.com", base::Time(), crypto::ECPrivateKey::Create()));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "harvard.com", base::Time(), crypto::ECPrivateKey::Create()));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "mit.com", base::Time(), crypto::ECPrivateKey::Create()));
// Wait for load & queued set tasks.
base::RunLoop().RunUntilIdle();
@@ -416,10 +421,10 @@ TEST(DefaultChannelIDStoreTest, TestInitializeFrom) {
std::unique_ptr<crypto::ECPrivateKey> copied_key(
crypto::ECPrivateKey::Create());
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "preexisting.com", base::Time(), preexisting_key->Copy())));
- store.SetChannelID(base::WrapUnique(new ChannelIDStore::ChannelID(
- "both.com", base::Time(), crypto::ECPrivateKey::Create())));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "preexisting.com", base::Time(), preexisting_key->Copy()));
+ store.SetChannelID(base::MakeUnique<ChannelIDStore::ChannelID>(
+ "both.com", base::Time(), crypto::ECPrivateKey::Create()));
// Wait for load & queued set tasks.
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2, store.GetChannelIDCount());
diff --git a/chromium/net/ssl/openssl_client_key_store.cc b/chromium/net/ssl/openssl_client_key_store.cc
index 9b1b8767cf7..c92f941ddf9 100644
--- a/chromium/net/ssl/openssl_client_key_store.cc
+++ b/chromium/net/ssl/openssl_client_key_store.cc
@@ -5,122 +5,85 @@
#include "net/ssl/openssl_client_key_store.h"
#include <openssl/evp.h>
+#include <openssl/mem.h>
#include <openssl/x509.h>
-#include <algorithm>
-#include <memory>
+#include <utility>
#include "base/memory/singleton.h"
+#include "crypto/auto_cbb.h"
+#include "crypto/scoped_openssl_types.h"
#include "net/cert/x509_certificate.h"
+#include "net/ssl/ssl_private_key.h"
namespace net {
namespace {
-// Return the EVP_PKEY holding the public key of a given certificate.
-// |cert| is a certificate.
-// Returns a scoped EVP_PKEY for it.
-crypto::ScopedEVP_PKEY GetOpenSSLPublicKey(const X509Certificate* cert) {
- // X509_PUBKEY_get() increments the reference count of its result.
- // Unlike X509_get_X509_PUBKEY() which simply returns a direct pointer.
- EVP_PKEY* pkey =
- X509_PUBKEY_get(X509_get_X509_PUBKEY(cert->os_cert_handle()));
- if (!pkey)
+// Serializes the SubjectPublicKeyInfo for |cert|.
+bool GetCertificateSPKI(const X509Certificate* cert, std::string* spki) {
+ crypto::ScopedEVP_PKEY pkey(X509_get_pubkey(cert->os_cert_handle()));
+ if (!pkey) {
LOG(ERROR) << "Can't extract private key from certificate!";
- return crypto::ScopedEVP_PKEY(pkey);
-}
-
-} // namespace
-
-OpenSSLClientKeyStore::OpenSSLClientKeyStore() {
-}
-
-OpenSSLClientKeyStore::~OpenSSLClientKeyStore() {
-}
-
-OpenSSLClientKeyStore::KeyPair::KeyPair(EVP_PKEY* pub_key, EVP_PKEY* priv_key)
- : public_key(EVP_PKEY_up_ref(pub_key)),
- private_key(EVP_PKEY_up_ref(priv_key)) {
-}
-
-OpenSSLClientKeyStore::KeyPair::~KeyPair() {
-}
-
-OpenSSLClientKeyStore::KeyPair::KeyPair(const KeyPair& other)
- : public_key(EVP_PKEY_up_ref(other.public_key.get())),
- private_key(EVP_PKEY_up_ref(other.private_key.get())) {
-}
+ return false;
+ }
-void OpenSSLClientKeyStore::KeyPair::operator=(KeyPair other) {
- swap(other);
-}
+ crypto::AutoCBB cbb;
+ uint8_t* der;
+ size_t der_len;
+ if (!CBB_init(cbb.get(), 0) ||
+ !EVP_marshal_public_key(cbb.get(), pkey.get()) ||
+ !CBB_finish(cbb.get(), &der, &der_len)) {
+ return false;
+ }
-void OpenSSLClientKeyStore::KeyPair::swap(KeyPair& other) {
- using std::swap;
- swap(public_key, other.public_key);
- swap(private_key, other.private_key);
+ spki->assign(reinterpret_cast<char*>(der),
+ reinterpret_cast<char*>(der) + der_len);
+ OPENSSL_free(der);
+ return true;
}
-int OpenSSLClientKeyStore::FindKeyPairIndex(EVP_PKEY* public_key) {
- if (!public_key)
- return -1;
- for (size_t n = 0; n < pairs_.size(); ++n) {
- if (EVP_PKEY_cmp(pairs_[n].public_key.get(), public_key) == 1)
- return static_cast<int>(n);
- }
- return -1;
-}
+} // namespace
-void OpenSSLClientKeyStore::AddKeyPair(EVP_PKEY* pub_key,
- EVP_PKEY* private_key) {
- int index = FindKeyPairIndex(pub_key);
- if (index < 0)
- pairs_.push_back(KeyPair(pub_key, private_key));
+OpenSSLClientKeyStore* OpenSSLClientKeyStore::GetInstance() {
+ return base::Singleton<OpenSSLClientKeyStore>::get();
}
-// Common code for OpenSSLClientKeyStore. Shared by all OpenSSL-based
-// builds.
bool OpenSSLClientKeyStore::RecordClientCertPrivateKey(
const X509Certificate* client_cert,
- EVP_PKEY* private_key) {
- // Sanity check.
- if (!client_cert || !private_key)
- return false;
+ scoped_refptr<SSLPrivateKey> private_key) {
+ DCHECK(client_cert);
+ DCHECK(private_key);
- // Get public key from certificate.
- crypto::ScopedEVP_PKEY pub_key(GetOpenSSLPublicKey(client_cert));
- if (!pub_key.get())
+ std::string spki;
+ if (!GetCertificateSPKI(client_cert, &spki))
return false;
- AddKeyPair(pub_key.get(), private_key);
+ key_map_[spki] = std::move(private_key);
return true;
}
-crypto::ScopedEVP_PKEY OpenSSLClientKeyStore::FetchClientCertPrivateKey(
+scoped_refptr<SSLPrivateKey> OpenSSLClientKeyStore::FetchClientCertPrivateKey(
const X509Certificate* client_cert) {
- if (!client_cert)
- return crypto::ScopedEVP_PKEY();
+ DCHECK(client_cert);
- crypto::ScopedEVP_PKEY pub_key(GetOpenSSLPublicKey(client_cert));
- if (!pub_key.get())
- return crypto::ScopedEVP_PKEY();
+ std::string spki;
+ if (!GetCertificateSPKI(client_cert, &spki))
+ return nullptr;
- int index = FindKeyPairIndex(pub_key.get());
- if (index < 0)
- return crypto::ScopedEVP_PKEY();
+ auto iter = key_map_.find(spki);
+ if (iter == key_map_.end())
+ return nullptr;
- return crypto::ScopedEVP_PKEY(
- EVP_PKEY_up_ref(pairs_[index].private_key.get()));
+ return iter->second;
}
void OpenSSLClientKeyStore::Flush() {
- pairs_.clear();
+ key_map_.clear();
}
-OpenSSLClientKeyStore* OpenSSLClientKeyStore::GetInstance() {
- return base::Singleton<OpenSSLClientKeyStore>::get();
-}
-
-} // namespace net
+OpenSSLClientKeyStore::OpenSSLClientKeyStore() {}
+OpenSSLClientKeyStore::~OpenSSLClientKeyStore() {}
+} // namespace net
diff --git a/chromium/net/ssl/openssl_client_key_store.h b/chromium/net/ssl/openssl_client_key_store.h
index 63559ded766..9e1e1f4202d 100644
--- a/chromium/net/ssl/openssl_client_key_store.h
+++ b/chromium/net/ssl/openssl_client_key_store.h
@@ -5,19 +5,19 @@
#ifndef NET_SSL_OPENSSL_CLIENT_KEY_STORE_H_
#define NET_SSL_OPENSSL_CLIENT_KEY_STORE_H_
-#include <openssl/evp.h>
+#include <openssl/base.h>
-#include <memory>
-#include <vector>
+#include <map>
+#include <string>
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
-#include "crypto/openssl_util.h"
-#include "crypto/scoped_openssl_types.h"
#include "net/base/net_export.h"
namespace net {
+class SSLPrivateKey;
class X509Certificate;
// OpenSSLClientKeyStore implements an in-memory store for client
@@ -38,57 +38,29 @@ class NET_EXPORT OpenSSLClientKeyStore {
// when it is called later. The association is recorded in memory
// exclusively.
// |cert| is a handle to a certificate object.
- // |private_key| is an OpenSSL EVP_PKEY that corresponds to the
- // certificate's private key.
+ // |private_key| is an SSLPrivateKey that corresponds to the certificate's
+ // private key.
// Returns false if an error occured.
- // This function does not take ownership of the private_key, but may
- // increment its internal reference count.
bool RecordClientCertPrivateKey(const X509Certificate* cert,
- EVP_PKEY* private_key);
+ scoped_refptr<SSLPrivateKey> key);
// Given a certificate's |public_key|, return the corresponding private
// key that has been recorded previously by RecordClientCertPrivateKey().
// |cert| is a client certificate.
// Returns its matching private key on success, NULL otherwise.
- crypto::ScopedEVP_PKEY FetchClientCertPrivateKey(const X509Certificate* cert);
+ scoped_refptr<SSLPrivateKey> FetchClientCertPrivateKey(
+ const X509Certificate* cert);
// Flush all recorded keys.
void Flush();
- protected:
+ private:
OpenSSLClientKeyStore();
-
~OpenSSLClientKeyStore();
- // Adds a given public/private key pair.
- // |pub_key| and |private_key| can point to the same object.
- // This increments the reference count on both objects, caller
- // must still call EVP_PKEY_free on them.
- void AddKeyPair(EVP_PKEY* pub_key, EVP_PKEY* private_key);
-
- private:
- // KeyPair is an internal class used to hold a pair of private / public
- // EVP_PKEY objects, with appropriate ownership.
- class KeyPair {
- public:
- explicit KeyPair(EVP_PKEY* pub_key, EVP_PKEY* priv_key);
- KeyPair(const KeyPair& other);
- // Intentionally pass by value, in order to use the copy-and-swap idiom.
- void operator=(KeyPair other);
- void swap(KeyPair& other);
- ~KeyPair();
-
- crypto::ScopedEVP_PKEY public_key;
- crypto::ScopedEVP_PKEY private_key;
-
- private:
- KeyPair(); // intentionally not implemented.
- };
-
- // Returns the index of the keypair for |public_key|. or -1 if not found.
- int FindKeyPairIndex(EVP_PKEY* public_key);
-
- std::vector<KeyPair> pairs_;
+ // Maps from the serialized SubjectPublicKeyInfo structure to the
+ // corresponding private key.
+ std::map<std::string, scoped_refptr<net::SSLPrivateKey>> key_map_;
friend struct base::DefaultSingletonTraits<OpenSSLClientKeyStore>;
diff --git a/chromium/net/ssl/openssl_client_key_store_unittest.cc b/chromium/net/ssl/openssl_client_key_store_unittest.cc
index 2ab34495568..835fce3de18 100644
--- a/chromium/net/ssl/openssl_client_key_store_unittest.cc
+++ b/chromium/net/ssl/openssl_client_key_store_unittest.cc
@@ -4,8 +4,10 @@
#include "net/ssl/openssl_client_key_store.h"
+#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "crypto/scoped_openssl_types.h"
+#include "net/ssl/ssl_private_key.h"
#include "net/test/cert_test_util.h"
#include "net/test/test_data_directory.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -14,11 +16,6 @@ namespace net {
namespace {
-// Return the internal reference count of a given EVP_PKEY.
-int EVP_PKEY_get_refcount(EVP_PKEY* pkey) {
- return pkey->references;
-}
-
// A common test class to ensure that the store is flushed after
// each test.
class OpenSSLClientKeyStoreTest : public ::testing::Test {
@@ -36,6 +33,42 @@ class OpenSSLClientKeyStoreTest : public ::testing::Test {
OpenSSLClientKeyStore* store_;
};
+class MockSSLPrivateKey : public SSLPrivateKey {
+ public:
+ MockSSLPrivateKey() : on_destroyed_(nullptr) {}
+
+ void set_on_destroyed(bool* on_destroyed) { on_destroyed_ = on_destroyed; }
+
+ Type GetType() override {
+ NOTREACHED();
+ return Type::RSA;
+ }
+
+ std::vector<Hash> GetDigestPreferences() override {
+ NOTREACHED();
+ return {};
+ }
+
+ size_t GetMaxSignatureLengthInBytes() override {
+ NOTREACHED();
+ return 0;
+ }
+
+ void SignDigest(Hash hash,
+ const base::StringPiece& input,
+ const SignCallback& callback) override {
+ NOTREACHED();
+ }
+
+ private:
+ ~MockSSLPrivateKey() override {
+ if (on_destroyed_)
+ *on_destroyed_ = true;
+ }
+
+ bool* on_destroyed_;
+};
+
// Check that GetInstance() returns non-null
TEST_F(OpenSSLClientKeyStoreTest, GetInstance) {
ASSERT_TRUE(store_);
@@ -47,20 +80,16 @@ TEST_F(OpenSSLClientKeyStoreTest, Flush) {
scoped_refptr<X509Certificate> cert_1(
ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem"));
- ASSERT_TRUE(cert_1.get());
-
- crypto::ScopedEVP_PKEY priv_key(EVP_PKEY_new());
- ASSERT_TRUE(priv_key.get());
+ ASSERT_TRUE(cert_1);
- ASSERT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(),
- priv_key.get()));
+ EXPECT_TRUE(store_->RecordClientCertPrivateKey(
+ cert_1.get(), make_scoped_refptr(new MockSSLPrivateKey)));
store_->Flush();
// Retrieve the private key. This should fail because the store
// was flushed.
- crypto::ScopedEVP_PKEY pkey = store_->FetchClientCertPrivateKey(cert_1.get());
- ASSERT_FALSE(pkey.get());
+ EXPECT_FALSE(store_->FetchClientCertPrivateKey(cert_1.get()));
}
// Check that trying to retrieve the private key of an unknown certificate
@@ -70,12 +99,11 @@ TEST_F(OpenSSLClientKeyStoreTest, FetchEmptyPrivateKey) {
scoped_refptr<X509Certificate> cert_1(
ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem"));
- ASSERT_TRUE(cert_1.get());
+ ASSERT_TRUE(cert_1);
// Retrieve the private key now. This should fail because it was
// never recorded in the store.
- crypto::ScopedEVP_PKEY pkey = store_->FetchClientCertPrivateKey(cert_1.get());
- ASSERT_FALSE(pkey.get());
+ EXPECT_FALSE(store_->FetchClientCertPrivateKey(cert_1.get()));
}
// Check that any private key recorded through RecordClientCertPrivateKey
@@ -89,80 +117,55 @@ TEST_F(OpenSSLClientKeyStoreTest, RecordAndFetchPrivateKey) {
// JNI reference, with no way to access the real private key bits.
scoped_refptr<X509Certificate> cert_1(
ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem"));
- ASSERT_TRUE(cert_1.get());
-
- crypto::ScopedEVP_PKEY priv_key(EVP_PKEY_new());
- ASSERT_TRUE(priv_key.get());
- ASSERT_EQ(1, EVP_PKEY_get_refcount(priv_key.get()));
-
- // Add the key a first time, this should increment its reference count.
- ASSERT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(),
- priv_key.get()));
- ASSERT_EQ(2, EVP_PKEY_get_refcount(priv_key.get()));
-
- // Two successive calls with the same certificate / private key shall
- // also succeed, but the key's reference count should not be incremented.
- ASSERT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(),
- priv_key.get()));
- ASSERT_EQ(2, EVP_PKEY_get_refcount(priv_key.get()));
-
- // Retrieve the private key. This should increment the private key's
- // reference count.
- crypto::ScopedEVP_PKEY pkey2 =
+ ASSERT_TRUE(cert_1);
+
+ bool on_destroyed = false;
+ scoped_refptr<MockSSLPrivateKey> priv_key(new MockSSLPrivateKey);
+ priv_key->set_on_destroyed(&on_destroyed);
+
+ // Add a key twice.
+ EXPECT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(), priv_key));
+ EXPECT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(), priv_key));
+
+ // Retrieve the private key.
+ scoped_refptr<SSLPrivateKey> pkey2 =
store_->FetchClientCertPrivateKey(cert_1.get());
- ASSERT_EQ(pkey2.get(), priv_key.get());
- ASSERT_EQ(3, EVP_PKEY_get_refcount(priv_key.get()));
+ EXPECT_EQ(pkey2.get(), priv_key.get());
- // Flush the store explicitely, this should decrement the private
- // key's reference count.
+ // Flush the key store and release all references. At this point, the private
+ // key should be cleanly destroyed.
store_->Flush();
- ASSERT_EQ(2, EVP_PKEY_get_refcount(priv_key.get()));
+ priv_key = nullptr;
+ pkey2 = nullptr;
+ EXPECT_TRUE(on_destroyed);
}
// Same test, but with two certificates / private keys.
TEST_F(OpenSSLClientKeyStoreTest, RecordAndFetchTwoPrivateKeys) {
scoped_refptr<X509Certificate> cert_1(
ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem"));
- ASSERT_TRUE(cert_1.get());
+ ASSERT_TRUE(cert_1);
scoped_refptr<X509Certificate> cert_2(
ImportCertFromFile(GetTestCertsDirectory(), "client_2.pem"));
- ASSERT_TRUE(cert_2.get());
-
- crypto::ScopedEVP_PKEY priv_key1(EVP_PKEY_new());
- ASSERT_TRUE(priv_key1.get());
- ASSERT_EQ(1, EVP_PKEY_get_refcount(priv_key1.get()));
-
- crypto::ScopedEVP_PKEY priv_key2(EVP_PKEY_new());
- ASSERT_TRUE(priv_key2.get());
- ASSERT_EQ(1, EVP_PKEY_get_refcount(priv_key2.get()));
-
- ASSERT_NE(priv_key1.get(), priv_key2.get());
-
- // Add the key a first time, this shall succeed, and increment the
- // reference count.
- EXPECT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(),
- priv_key1.get()));
- EXPECT_TRUE(store_->RecordClientCertPrivateKey(cert_2.get(),
- priv_key2.get()));
- EXPECT_EQ(2, EVP_PKEY_get_refcount(priv_key1.get()));
- EXPECT_EQ(2, EVP_PKEY_get_refcount(priv_key2.get()));
-
- // Retrieve the private key now. This shall succeed and increment
- // the private key's reference count.
- crypto::ScopedEVP_PKEY fetch_key1 =
+ ASSERT_TRUE(cert_2);
+
+ scoped_refptr<SSLPrivateKey> priv_key1(new MockSSLPrivateKey);
+ scoped_refptr<SSLPrivateKey> priv_key2(new MockSSLPrivateKey);
+
+ EXPECT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(), priv_key1));
+ EXPECT_TRUE(store_->RecordClientCertPrivateKey(cert_2.get(), priv_key2));
+
+ scoped_refptr<SSLPrivateKey> fetch_key1 =
store_->FetchClientCertPrivateKey(cert_1.get());
- crypto::ScopedEVP_PKEY fetch_key2 =
+ scoped_refptr<SSLPrivateKey> fetch_key2 =
store_->FetchClientCertPrivateKey(cert_2.get());
- EXPECT_TRUE(fetch_key1.get());
- EXPECT_TRUE(fetch_key2.get());
+ EXPECT_TRUE(fetch_key1);
+ EXPECT_TRUE(fetch_key2);
EXPECT_EQ(fetch_key1.get(), priv_key1.get());
EXPECT_EQ(fetch_key2.get(), priv_key2.get());
-
- EXPECT_EQ(3, EVP_PKEY_get_refcount(priv_key1.get()));
- EXPECT_EQ(3, EVP_PKEY_get_refcount(priv_key2.get()));
}
} // namespace
diff --git a/chromium/net/ssl/openssl_ssl_util.cc b/chromium/net/ssl/openssl_ssl_util.cc
index af7082d6c4c..da97124adba 100644
--- a/chromium/net/ssl/openssl_ssl_util.cc
+++ b/chromium/net/ssl/openssl_ssl_util.cc
@@ -98,8 +98,6 @@ int MapOpenSSLErrorSSL(uint32_t error_code) {
// The only way that the certificate verify callback can fail is if
// the leaf certificate changed during a renegotiation.
return ERR_SSL_SERVER_CERT_CHANGED;
- case SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK:
- return ERR_SSL_INAPPROPRIATE_FALLBACK;
// SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE may be returned from the server after
// receiving ClientHello if there's no common supported cipher. Map that
// specific case to ERR_SSL_VERSION_OR_CIPHER_MISMATCH to match the NSS
@@ -198,7 +196,7 @@ int MapOpenSSLErrorWithDetails(int err,
}
}
-NetLog::ParametersCallback CreateNetLogOpenSSLErrorCallback(
+NetLogParametersCallback CreateNetLogOpenSSLErrorCallback(
int net_error,
int ssl_error,
const OpenSSLErrorInfo& error_info) {
@@ -214,6 +212,8 @@ int GetNetSSLVersion(SSL* ssl) {
return SSL_CONNECTION_VERSION_TLS1_1;
case TLS1_2_VERSION:
return SSL_CONNECTION_VERSION_TLS1_2;
+ case TLS1_3_VERSION:
+ return SSL_CONNECTION_VERSION_TLS1_3;
default:
NOTREACHED();
return SSL_CONNECTION_VERSION_UNKNOWN;
diff --git a/chromium/net/ssl/openssl_ssl_util.h b/chromium/net/ssl/openssl_ssl_util.h
index 545c95810e9..9082fdf3bbf 100644
--- a/chromium/net/ssl/openssl_ssl_util.h
+++ b/chromium/net/ssl/openssl_ssl_util.h
@@ -10,7 +10,7 @@
#include <openssl/ssl.h>
#include "net/cert/x509_certificate.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_parameters_callback.h"
#include "net/ssl/scoped_openssl_types.h"
namespace crypto {
@@ -68,7 +68,7 @@ int MapOpenSSLErrorWithDetails(int err,
OpenSSLErrorInfo* out_error_info);
// Creates NetLog callback for an OpenSSL error.
-NetLog::ParametersCallback CreateNetLogOpenSSLErrorCallback(
+NetLogParametersCallback CreateNetLogOpenSSLErrorCallback(
int net_error,
int ssl_error,
const OpenSSLErrorInfo& error_info);
diff --git a/chromium/net/ssl/signed_certificate_timestamp_and_status.cc b/chromium/net/ssl/signed_certificate_timestamp_and_status.cc
deleted file mode 100644
index 4cddf0470f3..00000000000
--- a/chromium/net/ssl/signed_certificate_timestamp_and_status.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2013 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/ssl/signed_certificate_timestamp_and_status.h"
-
-#include "net/cert/signed_certificate_timestamp.h"
-
-namespace net {
-
-SignedCertificateTimestampAndStatus::SignedCertificateTimestampAndStatus() {}
-
-SignedCertificateTimestampAndStatus::SignedCertificateTimestampAndStatus(
- const scoped_refptr<ct::SignedCertificateTimestamp>& sct,
- const ct::SCTVerifyStatus status)
- : sct(sct), status(status) {}
-
-SignedCertificateTimestampAndStatus::SignedCertificateTimestampAndStatus(
- const SignedCertificateTimestampAndStatus& other) = default;
-
-SignedCertificateTimestampAndStatus::~SignedCertificateTimestampAndStatus() {}
-
-} // namespace net
diff --git a/chromium/net/ssl/signed_certificate_timestamp_and_status.h b/chromium/net/ssl/signed_certificate_timestamp_and_status.h
deleted file mode 100644
index e546668a0b1..00000000000
--- a/chromium/net/ssl/signed_certificate_timestamp_and_status.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2013 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_SSL_SIGNED_CERTIFICATE_TIMESTAMP_AND_STATUS_H_
-#define NET_SSL_SIGNED_CERTIFICATE_TIMESTAMP_AND_STATUS_H_
-
-#include <vector>
-
-#include "base/memory/ref_counted.h"
-#include "net/base/net_export.h"
-#include "net/cert/sct_status_flags.h"
-#include "net/cert/signed_certificate_timestamp.h"
-
-namespace net {
-
-struct NET_EXPORT SignedCertificateTimestampAndStatus {
- SignedCertificateTimestampAndStatus();
-
- SignedCertificateTimestampAndStatus(
- const scoped_refptr<ct::SignedCertificateTimestamp>& sct,
- ct::SCTVerifyStatus status);
-
- SignedCertificateTimestampAndStatus(
- const SignedCertificateTimestampAndStatus& other);
-
- ~SignedCertificateTimestampAndStatus();
-
- scoped_refptr<ct::SignedCertificateTimestamp> sct;
- ct::SCTVerifyStatus status;
-};
-
-typedef std::vector<SignedCertificateTimestampAndStatus>
- SignedCertificateTimestampAndStatusList;
-
-} // namespace net
-
-#endif // NET_SSL_SIGNED_CERTIFICATE_TIMESTAMP_AND_STATUS_H_
diff --git a/chromium/net/ssl/ssl_cipher_suite_names.cc b/chromium/net/ssl/ssl_cipher_suite_names.cc
index 9f8f1fbeec1..ba2129aa067 100644
--- a/chromium/net/ssl/ssl_cipher_suite_names.cc
+++ b/chromium/net/ssl/ssl_cipher_suite_names.cc
@@ -206,11 +206,14 @@ const struct CipherSuite kCipherSuites[] = {
{0xcc14, 0x0e8f}, // TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 (non-standard)
{0xcca8, 0x108f}, // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
{0xcca9, 0x0e8f}, // TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
+ {0xccab, 0x148f}, // TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256
+ {0xd001, 0x146f}, // TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256
+ {0xd002, 0x1477}, // TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384
};
const struct {
char name[15];
-} kKeyExchangeNames[20] = {
+} kKeyExchangeNames[21] = {
{"NULL"}, // 0
{"RSA"}, // 1
{"RSA_EXPORT"}, // 2
@@ -231,6 +234,7 @@ const struct {
{"ECDH_anon"}, // 17
{"CECPQ1_RSA"}, // 18
{"CECPQ1_ECDSA"}, // 19
+ {"ECDHE_PSK"}, // 20
};
const struct {
@@ -301,6 +305,52 @@ bool GetCipherProperties(uint16_t cipher_suite,
return true;
}
+int ObsoleteSSLStatusForProtocol(int ssl_version) {
+ int obsolete_ssl = net::OBSOLETE_SSL_NONE;
+ if (ssl_version < net::SSL_CONNECTION_VERSION_TLS1_2)
+ obsolete_ssl |= net::OBSOLETE_SSL_MASK_PROTOCOL;
+ return obsolete_ssl;
+}
+
+int ObsoleteSSLStatusForCipherSuite(uint16_t cipher_suite) {
+ int obsolete_ssl = net::OBSOLETE_SSL_NONE;
+
+ int key_exchange, cipher, mac;
+ if (!GetCipherProperties(cipher_suite, &key_exchange, &cipher, &mac)) {
+ // Cannot determine/unknown cipher suite. Err on the side of caution.
+ obsolete_ssl |= net::OBSOLETE_SSL_MASK_KEY_EXCHANGE;
+ obsolete_ssl |= net::OBSOLETE_SSL_MASK_CIPHER;
+ return obsolete_ssl;
+ }
+
+ // Only allow ECDHE key exchanges.
+ switch (key_exchange) {
+ case 14: // ECDHE_ECDSA
+ case 16: // ECDHE_RSA
+ case 18: // CECPQ1_RSA
+ case 19: // CECPQ1_ECDSA
+ case 20: // ECDHE_PSK
+ break;
+ default:
+ obsolete_ssl |= net::OBSOLETE_SSL_MASK_KEY_EXCHANGE;
+ }
+
+ switch (cipher) {
+ case 13: // AES_128_GCM
+ case 14: // AES_256_GCM
+ case 17: // CHACHA20_POLY1305
+ break;
+ default:
+ obsolete_ssl |= net::OBSOLETE_SSL_MASK_CIPHER;
+ }
+
+ // Only AEADs allowed.
+ if (mac != kAEADMACValue)
+ obsolete_ssl |= net::OBSOLETE_SSL_MASK_CIPHER;
+
+ return obsolete_ssl;
+}
+
} // namespace
namespace net {
@@ -344,6 +394,9 @@ void SSLVersionToString(const char** name, int ssl_version) {
case SSL_CONNECTION_VERSION_TLS1_2:
*name = "TLS 1.2";
break;
+ case SSL_CONNECTION_VERSION_TLS1_3:
+ *name = "TLS 1.3";
+ break;
case SSL_CONNECTION_VERSION_QUIC:
*name = "QUIC";
break;
@@ -367,36 +420,16 @@ bool ParseSSLCipherString(const std::string& cipher_string,
return false;
}
-bool IsSecureTLSCipherSuite(uint16_t cipher_suite) {
- int key_exchange, cipher, mac;
- if (!GetCipherProperties(cipher_suite, &key_exchange, &cipher, &mac))
- return false;
-
- // Only allow ECDHE key exchanges.
- switch (key_exchange) {
- case 14: // ECDHE_ECDSA
- case 16: // ECDHE_RSA
- case 18: // CECPQ1_RSA
- case 19: // CECPQ1_ECDSA
- break;
- default:
- return false;
- }
+int ObsoleteSSLStatus(int connection_status) {
+ int obsolete_ssl = OBSOLETE_SSL_NONE;
- switch (cipher) {
- case 13: // AES_128_GCM
- case 14: // AES_256_GCM
- case 17: // CHACHA20_POLY1305
- break;
- default:
- return false;
- }
+ int ssl_version = SSLConnectionStatusToVersion(connection_status);
+ obsolete_ssl |= ObsoleteSSLStatusForProtocol(ssl_version);
- // Only AEADs allowed.
- if (mac != kAEADMACValue)
- return false;
+ uint16_t cipher_suite = SSLConnectionStatusToCipherSuite(connection_status);
+ obsolete_ssl |= ObsoleteSSLStatusForCipherSuite(cipher_suite);
- return true;
+ return obsolete_ssl;
}
bool IsTLSCipherSuiteAllowedByHTTP2(uint16_t cipher_suite) {
@@ -411,6 +444,7 @@ bool IsTLSCipherSuiteAllowedByHTTP2(uint16_t cipher_suite) {
case 16: // ECDHE_RSA
case 18: // CECPQ1_RSA
case 19: // CECPQ1_ECDSA
+ case 20: // ECDHE_PSK
break;
default:
return false;
@@ -432,18 +466,4 @@ bool IsTLSCipherSuiteAllowedByHTTP2(uint16_t cipher_suite) {
return true;
}
-const char* ECCurveName(uint16_t cipher_suite, int key_exchange_info) {
- int key_exchange, cipher, mac;
- if (!GetCipherProperties(cipher_suite, &key_exchange, &cipher, &mac))
- return nullptr;
- switch (key_exchange) {
- case 14: // ECDHE_ECDSA
- case 16: // ECDHE_RSA
- break;
- default:
- return nullptr;
- }
- return SSL_get_curve_name(key_exchange_info);
-}
-
} // namespace net
diff --git a/chromium/net/ssl/ssl_cipher_suite_names.h b/chromium/net/ssl/ssl_cipher_suite_names.h
index 4651eb188a7..7c1192b279b 100644
--- a/chromium/net/ssl/ssl_cipher_suite_names.h
+++ b/chromium/net/ssl/ssl_cipher_suite_names.h
@@ -47,26 +47,32 @@ NET_EXPORT void SSLVersionToString(const char** name, int ssl_version);
NET_EXPORT bool ParseSSLCipherString(const std::string& cipher_string,
uint16_t* cipher_suite);
-// |cipher_suite| is the IANA id for the cipher suite. What a "secure"
-// cipher suite is arbitrarily determined here. The intent is to indicate what
-// cipher suites meet modern security standards when backwards compatibility can
-// be ignored.
+// Mask definitions for an integer that holds obsolete SSL setting details.
+enum ObsoleteSSLMask {
+ OBSOLETE_SSL_NONE = 0, // Modern SSL
+ OBSOLETE_SSL_MASK_PROTOCOL = 1 << 0,
+ OBSOLETE_SSL_MASK_KEY_EXCHANGE = 1 << 1,
+ OBSOLETE_SSL_MASK_CIPHER = 1 << 2,
+};
+
+// Takes the given |connection_status| and returns a bitmask indicating which of
+// the protocol, key exchange, and cipher suite do not meet modern best-practice
+// security standards (when backwards compatibility can be ignored) - that is,
+// which ones are "obsolete".
+//
+// Currently, this function uses the following criteria to determine what is
+// obsolete:
//
-// Currently, this function follows these criteria:
-// 1) Only uses ECDHE-based key exchanges authenticated by a certificate
-// 2) Only uses AEADs
-NET_EXPORT bool IsSecureTLSCipherSuite(uint16_t cipher_suite);
+// - Protocol: less than TLS 1.2
+// - Key exchange: Does not use ECDHE-based key exchanges authenticated by a
+// certificate
+// - Cipher: not an AEAD cipher
+NET_EXPORT int ObsoleteSSLStatus(int connection_status);
// Returns true if |cipher_suite| is suitable for use with HTTP/2. See
// https://http2.github.io/http2-spec/#rfc.section.9.2.2.
NET_EXPORT bool IsTLSCipherSuiteAllowedByHTTP2(uint16_t cipher_suite);
-// Returns the static curve name of |key_exchange_info| if the |cipher_suite|
-// is an elliptic curve, and a name is known. Returns nullptr otherwise.
-// Only defined for OpenSSL, returns nullptr otherwise.
-NET_EXPORT const char* ECCurveName(uint16_t cipher_suite,
- int key_exchange_info);
-
} // namespace net
#endif // NET_SSL_SSL_CIPHER_SUITE_NAMES_H_
diff --git a/chromium/net/ssl/ssl_cipher_suite_names_unittest.cc b/chromium/net/ssl/ssl_cipher_suite_names_unittest.cc
index f8636771083..83eb55c6171 100644
--- a/chromium/net/ssl/ssl_cipher_suite_names_unittest.cc
+++ b/chromium/net/ssl/ssl_cipher_suite_names_unittest.cc
@@ -6,12 +6,37 @@
#include "base/macros.h"
#include "base/strings/stringprintf.h"
+#include "net/ssl/ssl_connection_status_flags.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
namespace {
+int kObsoleteVersion = SSL_CONNECTION_VERSION_TLS1;
+int kModernVersion = SSL_CONNECTION_VERSION_TLS1_2;
+
+uint16_t kModernCipherSuite =
+ 0xc02f; /* TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 */
+
+uint16_t kObsoleteCipherObsoleteKeyExchange =
+ 0x67; /* TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 */
+uint16_t kObsoleteCipherModernKeyExchange =
+ 0x9e; /* TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 */
+uint16_t kModernCipherObsoleteKeyExchange =
+ 0xc014; /* TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA */
+uint16_t kModernCipherModernKeyExchange =
+ 0xc02f; /* TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 */
+
+int MakeConnectionStatus(int version, uint16_t cipher_suite) {
+ int connection_status = 0;
+
+ SSLConnectionStatusSetVersion(version, &connection_status);
+ SSLConnectionStatusSetCipherSuite(cipher_suite, &connection_status);
+
+ return connection_status;
+}
+
TEST(CipherSuiteNamesTest, Basic) {
const char *key_exchange, *cipher, *mac;
bool is_aead;
@@ -70,38 +95,58 @@ TEST(CipherSuiteNamesTest, ParseSSLCipherStringFails) {
}
}
-TEST(CipherSuiteNamesTest, SecureCipherSuites) {
- // Picked some random cipher suites.
- EXPECT_FALSE(IsSecureTLSCipherSuite(0x0 /* TLS_NULL_WITH_NULL_NULL */));
- EXPECT_FALSE(
- IsSecureTLSCipherSuite(0x39 /* TLS_DHE_RSA_WITH_AES_256_CBC_SHA */));
- EXPECT_FALSE(IsSecureTLSCipherSuite(
- 0xc5 /* TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 */));
- EXPECT_FALSE(
- IsSecureTLSCipherSuite(0xc00f /* TLS_ECDH_RSA_WITH_AES_256_CBC_SHA */));
- EXPECT_FALSE(IsSecureTLSCipherSuite(
- 0xc083 /* TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 */));
- EXPECT_FALSE(
- IsSecureTLSCipherSuite(0x9e /* TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 */));
- EXPECT_FALSE(
- IsSecureTLSCipherSuite(0xc014 /* TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA */));
- EXPECT_FALSE(
- IsSecureTLSCipherSuite(0x9c /* TLS_RSA_WITH_AES_128_GCM_SHA256 */));
-
- // Non-existent cipher suite.
- EXPECT_FALSE(IsSecureTLSCipherSuite(0xffff)) << "Doesn't exist!";
+TEST(CipherSuiteNamesTest, ObsoleteSSLStatusProtocol) {
+ // Obsolete
+ EXPECT_EQ(OBSOLETE_SSL_MASK_PROTOCOL,
+ ObsoleteSSLStatus(MakeConnectionStatus(SSL_CONNECTION_VERSION_SSL2,
+ kModernCipherSuite)));
+ EXPECT_EQ(OBSOLETE_SSL_MASK_PROTOCOL,
+ ObsoleteSSLStatus(MakeConnectionStatus(SSL_CONNECTION_VERSION_SSL3,
+ kModernCipherSuite)));
+ EXPECT_EQ(OBSOLETE_SSL_MASK_PROTOCOL,
+ ObsoleteSSLStatus(MakeConnectionStatus(SSL_CONNECTION_VERSION_TLS1,
+ kModernCipherSuite)));
+ EXPECT_EQ(OBSOLETE_SSL_MASK_PROTOCOL,
+ ObsoleteSSLStatus(MakeConnectionStatus(
+ SSL_CONNECTION_VERSION_TLS1_1, kModernCipherSuite)));
+
+ // Modern
+ EXPECT_EQ(OBSOLETE_SSL_NONE,
+ ObsoleteSSLStatus(MakeConnectionStatus(
+ SSL_CONNECTION_VERSION_TLS1_2, kModernCipherSuite)));
+ EXPECT_EQ(OBSOLETE_SSL_NONE,
+ ObsoleteSSLStatus(MakeConnectionStatus(SSL_CONNECTION_VERSION_QUIC,
+ kModernCipherSuite)));
+}
- // Secure ones.
- EXPECT_TRUE(IsSecureTLSCipherSuite(
- 0xc02f /* TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 */));
- EXPECT_TRUE(IsSecureTLSCipherSuite(
- 0xcc13 /* ECDHE_RSA_WITH_CHACHA20_POLY1305 (non-standard) */));
- EXPECT_TRUE(IsSecureTLSCipherSuite(
- 0xcc14 /* ECDHE_ECDSA_WITH_CHACHA20_POLY1305 (non-standard) */));
- EXPECT_TRUE(IsSecureTLSCipherSuite(
- 0xcca8 /* ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 */));
- EXPECT_TRUE(IsSecureTLSCipherSuite(
- 0xcca9 /* ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 */));
+TEST(CipherSuiteNamesTest, ObsoleteSSLStatusProtocolAndCipherSuite) {
+ // Cartesian combos
+ // As above, some of these combinations can't happen in practice.
+ EXPECT_EQ(OBSOLETE_SSL_MASK_PROTOCOL | OBSOLETE_SSL_MASK_KEY_EXCHANGE |
+ OBSOLETE_SSL_MASK_CIPHER,
+ ObsoleteSSLStatus(MakeConnectionStatus(
+ kObsoleteVersion, kObsoleteCipherObsoleteKeyExchange)));
+ EXPECT_EQ(OBSOLETE_SSL_MASK_PROTOCOL | OBSOLETE_SSL_MASK_KEY_EXCHANGE,
+ ObsoleteSSLStatus(MakeConnectionStatus(
+ kObsoleteVersion, kObsoleteCipherModernKeyExchange)));
+ EXPECT_EQ(OBSOLETE_SSL_MASK_PROTOCOL | OBSOLETE_SSL_MASK_CIPHER,
+ ObsoleteSSLStatus(MakeConnectionStatus(
+ kObsoleteVersion, kModernCipherObsoleteKeyExchange)));
+ EXPECT_EQ(OBSOLETE_SSL_MASK_PROTOCOL,
+ ObsoleteSSLStatus(MakeConnectionStatus(
+ kObsoleteVersion, kModernCipherModernKeyExchange)));
+ EXPECT_EQ(OBSOLETE_SSL_MASK_KEY_EXCHANGE | OBSOLETE_SSL_MASK_CIPHER,
+ ObsoleteSSLStatus(MakeConnectionStatus(
+ kModernVersion, kObsoleteCipherObsoleteKeyExchange)));
+ EXPECT_EQ(OBSOLETE_SSL_MASK_KEY_EXCHANGE,
+ ObsoleteSSLStatus(MakeConnectionStatus(
+ kModernVersion, kObsoleteCipherModernKeyExchange)));
+ EXPECT_EQ(OBSOLETE_SSL_MASK_CIPHER,
+ ObsoleteSSLStatus(MakeConnectionStatus(
+ kModernVersion, kModernCipherObsoleteKeyExchange)));
+ EXPECT_EQ(OBSOLETE_SSL_NONE,
+ ObsoleteSSLStatus(MakeConnectionStatus(
+ kModernVersion, kModernCipherModernKeyExchange)));
}
TEST(CipherSuiteNamesTest, HTTP2CipherSuites) {
@@ -152,7 +197,10 @@ TEST(CipherSuiteNamesTest, CECPQ1) {
for (const uint16_t cipher_suite_id : kCECPQ1CipherSuites) {
SCOPED_TRACE(base::StringPrintf("cipher suite %x", cipher_suite_id));
EXPECT_TRUE(IsTLSCipherSuiteAllowedByHTTP2(cipher_suite_id));
- EXPECT_TRUE(IsSecureTLSCipherSuite(cipher_suite_id));
+
+ int connection_status =
+ MakeConnectionStatus(kModernVersion, cipher_suite_id);
+ EXPECT_EQ(OBSOLETE_SSL_NONE, ObsoleteSSLStatus(connection_status));
SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead,
cipher_suite_id);
EXPECT_TRUE(is_aead);
diff --git a/chromium/net/ssl/ssl_client_session_cache.cc b/chromium/net/ssl/ssl_client_session_cache.cc
index 82526a5ae4d..f1aa1d0e612 100644
--- a/chromium/net/ssl/ssl_client_session_cache.cc
+++ b/chromium/net/ssl/ssl_client_session_cache.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/memory/memory_coordinator_client_registry.h"
#include "base/time/clock.h"
#include "base/time/default_clock.h"
@@ -15,10 +16,15 @@ SSLClientSessionCache::SSLClientSessionCache(const Config& config)
: clock_(new base::DefaultClock),
config_(config),
cache_(config.max_entries),
- lookups_since_flush_(0) {}
+ lookups_since_flush_(0) {
+ memory_pressure_listener_.reset(new base::MemoryPressureListener(base::Bind(
+ &SSLClientSessionCache::OnMemoryPressure, base::Unretained(this))));
+ base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this);
+}
SSLClientSessionCache::~SSLClientSessionCache() {
Flush();
+ base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(this);
}
size_t SSLClientSessionCache::size() const {
@@ -42,7 +48,10 @@ ScopedSSL_SESSION SSLClientSessionCache::Lookup(const std::string& cache_key) {
cache_.Erase(iter);
return nullptr;
}
- return ScopedSSL_SESSION(SSL_SESSION_up_ref(iter->second->session.get()));
+
+ SSL_SESSION* session = iter->second->session.get();
+ SSL_SESSION_up_ref(session);
+ return ScopedSSL_SESSION(session);
}
void SSLClientSessionCache::Insert(const std::string& cache_key,
@@ -51,7 +60,8 @@ void SSLClientSessionCache::Insert(const std::string& cache_key,
// Make a new entry.
std::unique_ptr<CacheEntry> entry(new CacheEntry);
- entry->session.reset(SSL_SESSION_up_ref(session));
+ SSL_SESSION_up_ref(session);
+ entry->session.reset(session);
entry->creation_time = clock_->Now();
// Takes ownership.
@@ -91,4 +101,36 @@ void SSLClientSessionCache::FlushExpiredSessions() {
}
}
+void SSLClientSessionCache::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+ switch (memory_pressure_level) {
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+ break;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+ FlushExpiredSessions();
+ break;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+ Flush();
+ break;
+ }
+}
+
+void SSLClientSessionCache::OnMemoryStateChange(base::MemoryState state) {
+ // TODO(hajimehoshi): When the state changes, adjust the sizes of the caches
+ // to reduce the limits. SSLClientSessionCache doesn't have the ability to
+ // limit at present.
+ switch (state) {
+ case base::MemoryState::NORMAL:
+ break;
+ case base::MemoryState::THROTTLED:
+ Flush();
+ break;
+ case base::MemoryState::SUSPENDED:
+ // Note: Not supported at present. Fall through.
+ case base::MemoryState::UNKNOWN:
+ NOTREACHED();
+ break;
+ }
+}
+
} // namespace net
diff --git a/chromium/net/ssl/ssl_client_session_cache.h b/chromium/net/ssl/ssl_client_session_cache.h
index 149d4dc36d0..279561b89f2 100644
--- a/chromium/net/ssl/ssl_client_session_cache.h
+++ b/chromium/net/ssl/ssl_client_session_cache.h
@@ -11,8 +11,11 @@
#include <memory>
#include <string>
+#include "base/bind.h"
#include "base/containers/mru_cache.h"
#include "base/macros.h"
+#include "base/memory/memory_coordinator_client.h"
+#include "base/memory/memory_pressure_monitor.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
@@ -25,7 +28,7 @@ class Clock;
namespace net {
-class NET_EXPORT SSLClientSessionCache {
+class NET_EXPORT SSLClientSessionCache : public base::MemoryCoordinatorClient {
public:
struct Config {
// The maximum number of entries in the cache.
@@ -37,7 +40,7 @@ class NET_EXPORT SSLClientSessionCache {
};
explicit SSLClientSessionCache(const Config& config);
- ~SSLClientSessionCache();
+ ~SSLClientSessionCache() override;
size_t size() const;
@@ -68,12 +71,19 @@ class NET_EXPORT SSLClientSessionCache {
using CacheEntryMap =
base::HashingMRUCache<std::string, std::unique_ptr<CacheEntry>>;
+ // base::MemoryCoordinatorClient implementation:
+ void OnMemoryStateChange(base::MemoryState state) override;
+
// Returns true if |entry| is expired as of |now|.
bool IsExpired(CacheEntry* entry, const base::Time& now);
// Removes all expired sessions from the cache.
void FlushExpiredSessions();
+ // Clear cache on low memory notifications callback.
+ void OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
+
std::unique_ptr<base::Clock> clock_;
Config config_;
CacheEntryMap cache_;
@@ -84,6 +94,8 @@ class NET_EXPORT SSLClientSessionCache {
// classes in net.
base::Lock lock_;
+ std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
+
DISALLOW_COPY_AND_ASSIGN(SSLClientSessionCache);
};
diff --git a/chromium/net/ssl/ssl_client_session_cache_unittest.cc b/chromium/net/ssl/ssl_client_session_cache_unittest.cc
index 20d77a7cdb1..c3169a17e50 100644
--- a/chromium/net/ssl/ssl_client_session_cache_unittest.cc
+++ b/chromium/net/ssl/ssl_client_session_cache_unittest.cc
@@ -7,6 +7,7 @@
#include <openssl/ssl.h>
#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/simple_test_clock.h"
#include "net/ssl/scoped_openssl_types.h"
@@ -224,4 +225,49 @@ TEST(SSLClientSessionCacheTest, LookupExpirationCheck) {
EXPECT_EQ(0u, cache.size());
}
+// Test that SSL cache is flushed on low memory notifications
+TEST(SSLClientSessionCacheTest, TestFlushOnMemoryNotifications) {
+ // kExpirationCheckCount is set to a suitably large number so the automated
+ // pruning never triggers.
+ const size_t kExpirationCheckCount = 1000;
+ const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(1000);
+
+ SSLClientSessionCache::Config config;
+ config.expiration_check_count = kExpirationCheckCount;
+ config.timeout = kTimeout;
+ SSLClientSessionCache cache(config);
+ base::SimpleTestClock* clock = new base::SimpleTestClock;
+ cache.SetClockForTesting(base::WrapUnique(clock));
+
+ // Insert an entry into the session cache.
+ ScopedSSL_SESSION session1(SSL_SESSION_new());
+ cache.Insert("key1", session1.get());
+ EXPECT_EQ(session1.get(), cache.Lookup("key1").get());
+ EXPECT_EQ(1u, cache.size());
+
+ // Expire the session.
+ clock->Advance(kTimeout * 2);
+ // Add one more session.
+ ScopedSSL_SESSION session2(SSL_SESSION_new());
+ cache.Insert("key2", session2.get());
+ EXPECT_EQ(2u, cache.size());
+
+ // Fire a notification that will flush expired sessions.
+ base::MemoryPressureListener::NotifyMemoryPressure(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
+ base::RunLoop().RunUntilIdle();
+
+ // Expired session's cache should be flushed.
+ // Lookup returns nullptr, when cache entry not found.
+ EXPECT_FALSE(cache.Lookup("key1"));
+ EXPECT_TRUE(cache.Lookup("key2"));
+ EXPECT_EQ(1u, cache.size());
+
+ // Fire notification that will flush everything.
+ base::MemoryPressureListener::NotifyMemoryPressure(
+ base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0u, cache.size());
+}
+
} // namespace net
diff --git a/chromium/net/ssl/ssl_config.cc b/chromium/net/ssl/ssl_config.cc
index 00992aa9c45..7a4f3373bb4 100644
--- a/chromium/net/ssl/ssl_config.cc
+++ b/chromium/net/ssl/ssl_config.cc
@@ -12,18 +12,20 @@ const uint16_t kDefaultSSLVersionMin = SSL_PROTOCOL_VERSION_TLS1;
const uint16_t kDefaultSSLVersionMax = SSL_PROTOCOL_VERSION_TLS1_2;
-const uint16_t kDefaultSSLVersionFallbackMin = SSL_PROTOCOL_VERSION_TLS1_2;
-
-SSLConfig::CertAndStatus::CertAndStatus() : cert_status(0) {}
-
-SSLConfig::CertAndStatus::~CertAndStatus() {}
+SSLConfig::CertAndStatus::CertAndStatus() = default;
+SSLConfig::CertAndStatus::CertAndStatus(scoped_refptr<X509Certificate> cert_arg,
+ CertStatus status)
+ : cert(std::move(cert_arg)), cert_status(status) {}
+SSLConfig::CertAndStatus::CertAndStatus(const CertAndStatus& other)
+ : cert(other.cert), cert_status(other.cert_status) {}
+SSLConfig::CertAndStatus::~CertAndStatus() = default;
SSLConfig::SSLConfig()
: rev_checking_enabled(false),
rev_checking_required_local_anchors(false),
+ sha1_local_anchors_enabled(false),
version_min(kDefaultSSLVersionMin),
version_max(kDefaultSSLVersionMax),
- version_fallback_min(kDefaultSSLVersionFallbackMin),
deprecated_cipher_suites_enabled(false),
dhe_enabled(false),
channel_id_enabled(true),
@@ -32,7 +34,6 @@ SSLConfig::SSLConfig()
require_ecdhe(false),
send_client_cert(false),
verify_ev_cert(false),
- version_fallback(false),
cert_io_enabled(true),
renego_allowed_default(false) {}
@@ -42,18 +43,10 @@ SSLConfig::~SSLConfig() {}
bool SSLConfig::IsAllowedBadCert(X509Certificate* cert,
CertStatus* cert_status) const {
- std::string der_cert;
- if (!X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_cert))
- return false;
- return IsAllowedBadCert(der_cert, cert_status);
-}
-
-bool SSLConfig::IsAllowedBadCert(const base::StringPiece& der_cert,
- CertStatus* cert_status) const {
- for (size_t i = 0; i < allowed_bad_certs.size(); ++i) {
- if (der_cert == allowed_bad_certs[i].der_cert) {
+ for (const auto& allowed_bad_cert : allowed_bad_certs) {
+ if (cert->Equals(allowed_bad_cert.cert.get())) {
if (cert_status)
- *cert_status = allowed_bad_certs[i].cert_status;
+ *cert_status = allowed_bad_cert.cert_status;
return true;
}
}
@@ -70,6 +63,8 @@ int SSLConfig::GetCertVerifyFlags() const {
flags |= CertVerifier::VERIFY_CERT_IO_ENABLED;
if (rev_checking_required_local_anchors)
flags |= CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS;
+ if (sha1_local_anchors_enabled)
+ flags |= CertVerifier::VERIFY_ENABLE_SHA1_LOCAL_ANCHORS;
return flags;
}
diff --git a/chromium/net/ssl/ssl_config.h b/chromium/net/ssl/ssl_config.h
index 5b827865e70..0cc7f55201b 100644
--- a/chromium/net/ssl/ssl_config.h
+++ b/chromium/net/ssl/ssl_config.h
@@ -26,6 +26,7 @@ enum {
SSL_PROTOCOL_VERSION_TLS1 = 0x0301,
SSL_PROTOCOL_VERSION_TLS1_1 = 0x0302,
SSL_PROTOCOL_VERSION_TLS1_2 = 0x0303,
+ SSL_PROTOCOL_VERSION_TLS1_3 = 0x0304,
};
enum TokenBindingParam {
@@ -40,9 +41,6 @@ NET_EXPORT extern const uint16_t kDefaultSSLVersionMin;
// Default maximum protocol version.
NET_EXPORT extern const uint16_t kDefaultSSLVersionMax;
-// Default minimum protocol version that it's acceptable to fallback to.
-NET_EXPORT extern const uint16_t kDefaultSSLVersionFallbackMin;
-
// A collection of SSL-related configuration settings.
struct NET_EXPORT SSLConfig {
// Default to revocation checking.
@@ -55,11 +53,6 @@ struct NET_EXPORT SSLConfig {
// be NULL if user doesn't care about the cert status.
bool IsAllowedBadCert(X509Certificate* cert, CertStatus* cert_status) const;
- // Same as above except works with DER encoded certificates instead
- // of X509Certificate.
- bool IsAllowedBadCert(const base::StringPiece& der_cert,
- CertStatus* cert_status) const;
-
// Returns the set of flags to use for certificate verification, which is a
// bitwise OR of CertVerifier::VerifyFlags that represent this SSLConfig's
// configuration.
@@ -81,6 +74,10 @@ struct NET_EXPORT SSLConfig {
// certificate chain chains to a local (non-public) trust anchor.
bool rev_checking_required_local_anchors;
+ // sha1_local_anchors_enabled is true if SHA-1 signed certificates issued by a
+ // local (non-public) trust anchor should be allowed.
+ bool sha1_local_anchors_enabled;
+
// 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
@@ -88,12 +85,6 @@ struct NET_EXPORT SSLConfig {
uint16_t version_min;
uint16_t version_max;
- // version_fallback_min contains the minimum version that is acceptable to
- // fallback to. Versions before this may be tried to see whether they would
- // have succeeded and thus to give a better message to the user, but the
- // resulting connection won't be used in these cases.
- uint16_t version_fallback_min;
-
// Presorted list of cipher suites which should be explicitly prevented from
// being used in addition to those disabled by the net built-in policy.
//
@@ -136,10 +127,12 @@ struct NET_EXPORT SSLConfig {
struct NET_EXPORT CertAndStatus {
CertAndStatus();
+ CertAndStatus(scoped_refptr<X509Certificate> cert, CertStatus status);
+ CertAndStatus(const CertAndStatus&);
~CertAndStatus();
- std::string der_cert;
- CertStatus cert_status;
+ scoped_refptr<X509Certificate> cert;
+ CertStatus cert_status = 0;
};
// Add any known-bad SSL certificate (with its cert status) to
@@ -153,10 +146,6 @@ struct NET_EXPORT SSLConfig {
bool verify_ev_cert; // True if we should verify the certificate for EV.
- bool version_fallback; // True if we are falling back to an older protocol
- // version (one still needs to decrement
- // version_max).
-
// If cert_io_enabled is false, then certificate verification will not
// result in additional HTTP requests. (For example: to fetch missing
// intermediates or to perform OCSP/CRL fetches.) It also implies that online
@@ -169,16 +158,6 @@ struct NET_EXPORT SSLConfig {
// will be advertised in this order during TLS handshake.
NextProtoVector alpn_protos;
- // The list of application level protocols supported with NPN (Next Protocol
- // Negotiation). The last item on the list is selected if there is no overlap
- // between |npn_protos| and the protocols supported by the server, otherwise
- // server preference is observed and the order of |npn_protos| is irrelevant.
- // Note that due to NSS limitations, ports which use NSS will use
- // |alpn_protos| for both ALPN and NPN. However, if |npn_protos| is empty, NPN
- // will still be disabled.
- // TODO(bnc): Deprecate NPN, see https://crbug.com/526713.
- NextProtoVector npn_protos;
-
// True if renegotiation should be allowed for the default application-level
// protocol when the peer negotiates neither ALPN nor NPN.
bool renego_allowed_default;
diff --git a/chromium/net/ssl/ssl_connection_status_flags.h b/chromium/net/ssl/ssl_connection_status_flags.h
index c6c03059764..d3062724ef4 100644
--- a/chromium/net/ssl/ssl_connection_status_flags.h
+++ b/chromium/net/ssl/ssl_connection_status_flags.h
@@ -21,8 +21,7 @@ enum {
SSL_CONNECTION_COMPRESSION_SHIFT = 16,
SSL_CONNECTION_COMPRESSION_MASK = 3,
- // We fell back to an older protocol version for this connection.
- SSL_CONNECTION_VERSION_FALLBACK = 1 << 18,
+ // 1 << 18 was previously used for SSL_CONNECTION_VERSION_FALLBACK.
// The server doesn't support the renegotiation_info extension. If this bit
// is not set then either the extension isn't supported, or we don't have any
@@ -48,7 +47,7 @@ enum {
SSL_CONNECTION_VERSION_TLS1 = 3,
SSL_CONNECTION_VERSION_TLS1_1 = 4,
SSL_CONNECTION_VERSION_TLS1_2 = 5,
- // Reserve 6 for TLS 1.3.
+ SSL_CONNECTION_VERSION_TLS1_3 = 6,
SSL_CONNECTION_VERSION_QUIC = 7,
SSL_CONNECTION_VERSION_MAX,
};
diff --git a/chromium/net/ssl/ssl_info.cc b/chromium/net/ssl/ssl_info.cc
index 28e232733b1..a6232d0049b 100644
--- a/chromium/net/ssl/ssl_info.cc
+++ b/chromium/net/ssl/ssl_info.cc
@@ -4,11 +4,14 @@
#include "net/ssl/ssl_info.h"
+#include <openssl/ssl.h>
+
#include "base/pickle.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/ct_policy_status.h"
#include "net/cert/signed_certificate_timestamp.h"
#include "net/cert/x509_certificate.h"
+#include "net/ssl/ssl_connection_status_flags.h"
namespace net {
@@ -28,7 +31,7 @@ SSLInfo& SSLInfo::operator=(const SSLInfo& info) {
unverified_cert = info.unverified_cert;
cert_status = info.cert_status;
security_bits = info.security_bits;
- key_exchange_info = info.key_exchange_info;
+ key_exchange_group = info.key_exchange_group;
connection_status = info.connection_status;
is_issued_by_known_root = info.is_issued_by_known_root;
pkp_bypassed = info.pkp_bypassed;
@@ -43,7 +46,7 @@ SSLInfo& SSLInfo::operator=(const SSLInfo& info) {
ct_compliance_details_available = info.ct_compliance_details_available;
ct_ev_policy_compliance = info.ct_ev_policy_compliance;
ct_cert_policy_compliance = info.ct_cert_policy_compliance;
-
+ ocsp_result = info.ocsp_result;
return *this;
}
@@ -52,7 +55,7 @@ void SSLInfo::Reset() {
unverified_cert = NULL;
cert_status = 0;
security_bits = -1;
- key_exchange_info = 0;
+ key_exchange_group = 0;
connection_status = 0;
is_issued_by_known_root = false;
pkp_bypassed = false;
@@ -68,6 +71,7 @@ void SSLInfo::Reset() {
ct_ev_policy_compliance = ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY;
ct_cert_policy_compliance =
ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS;
+ ocsp_result = OCSPVerifyResult();
}
void SSLInfo::SetCertError(int error) {
@@ -76,18 +80,9 @@ void SSLInfo::SetCertError(int error) {
void SSLInfo::UpdateCertificateTransparencyInfo(
const ct::CTVerifyResult& ct_verify_result) {
- for (const auto& sct : ct_verify_result.verified_scts) {
- signed_certificate_timestamps.push_back(
- SignedCertificateTimestampAndStatus(sct, ct::SCT_STATUS_OK));
- }
- for (const auto& sct : ct_verify_result.invalid_scts) {
- signed_certificate_timestamps.push_back(
- SignedCertificateTimestampAndStatus(sct, ct::SCT_STATUS_INVALID));
- }
- for (const auto& sct : ct_verify_result.unknown_logs_scts) {
- signed_certificate_timestamps.push_back(
- SignedCertificateTimestampAndStatus(sct, ct::SCT_STATUS_LOG_UNKNOWN));
- }
+ signed_certificate_timestamps.insert(signed_certificate_timestamps.end(),
+ ct_verify_result.scts.begin(),
+ ct_verify_result.scts.end());
ct_compliance_details_available = ct_verify_result.ct_policies_applied;
ct_cert_policy_compliance = ct_verify_result.cert_policy_compliance;
diff --git a/chromium/net/ssl/ssl_info.h b/chromium/net/ssl/ssl_info.h
index d894f7c6b60..645e28d8dcc 100644
--- a/chromium/net/ssl/ssl_info.h
+++ b/chromium/net/ssl/ssl_info.h
@@ -5,15 +5,18 @@
#ifndef NET_SSL_SSL_INFO_H_
#define NET_SSL_SSL_INFO_H_
+#include <stdint.h>
+
#include <vector>
#include "base/memory/ref_counted.h"
#include "net/base/net_export.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/ct_verify_result.h"
+#include "net/cert/ocsp_verify_result.h"
#include "net/cert/sct_status_flags.h"
+#include "net/cert/signed_certificate_timestamp_and_status.h"
#include "net/cert/x509_cert_types.h"
-#include "net/ssl/signed_certificate_timestamp_and_status.h"
#include "net/ssl/ssl_config.h"
namespace net {
@@ -79,11 +82,9 @@ class NET_EXPORT SSLInfo {
// -1 means the security strength is unknown.
int security_bits;
- // Security information of the SSL connection handshake.
- // The meaning depends on the cipher used, see BoringSSL's |SSL_SESSION|'s
- // key_exchange_info for more information.
- // A zero indicates that the value is unknown.
- int key_exchange_info;
+ // The ID of the (EC)DH group used by the key exchange or zero if unknown
+ // (older cache entries may not store the value) or not applicable.
+ uint16_t key_exchange_group;
// Information about the SSL connection itself. See
// ssl_connection_status_flags.h for values. The protocol version,
@@ -144,6 +145,9 @@ class NET_EXPORT SSLInfo {
// not, why not. Only meaningful it |ct_compliance_details_available|
// is true.
ct::CertPolicyCompliance ct_cert_policy_compliance;
+
+ // OCSP stapling details.
+ OCSPVerifyResult ocsp_result;
};
} // namespace net
diff --git a/chromium/net/ssl/ssl_key_logger.cc b/chromium/net/ssl/ssl_key_logger.cc
index 42984dfaf37..2f394906f46 100644
--- a/chromium/net/ssl/ssl_key_logger.cc
+++ b/chromium/net/ssl/ssl_key_logger.cc
@@ -22,10 +22,10 @@ namespace net {
class SSLKeyLogger::Core {
public:
Core() { sequence_checker_.DetachFromSequence(); }
- ~Core() { DCHECK(sequence_checker_.CalledOnValidSequencedThread()); }
+ ~Core() { DCHECK(sequence_checker_.CalledOnValidSequence()); }
void OpenFile(const base::FilePath& path) {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
DCHECK(!file_);
file_.reset(base::OpenFile(path, "a"));
if (!file_)
@@ -33,7 +33,7 @@ class SSLKeyLogger::Core {
}
void WriteLine(const std::string& line) {
- DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
if (!file_)
return;
fprintf(file_.get(), "%s\n", line.c_str());
diff --git a/chromium/net/ssl/ssl_platform_key_android.cc b/chromium/net/ssl/ssl_platform_key_android.cc
index 800107a5dc4..b4cc1a792c0 100644
--- a/chromium/net/ssl/ssl_platform_key_android.cc
+++ b/chromium/net/ssl/ssl_platform_key_android.cc
@@ -2,31 +2,84 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/ssl/ssl_platform_key.h"
+#include "net/ssl/ssl_platform_key_android.h"
-#include <openssl/digest.h>
-#include <openssl/evp.h>
+#include <openssl/ecdsa.h>
+#include <openssl/rsa.h>
+#include <strings.h>
+#include <memory>
#include <utility>
+#include <vector>
+#include "base/android/build_info.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "crypto/scoped_openssl_types.h"
+#include "net/android/keystore.h"
+#include "net/android/legacy_openssl.h"
#include "net/base/net_errors.h"
#include "net/ssl/openssl_client_key_store.h"
+#include "net/ssl/ssl_platform_key.h"
#include "net/ssl/ssl_platform_key_task_runner.h"
-#include "net/ssl/ssl_private_key.h"
#include "net/ssl/threaded_ssl_private_key.h"
+using base::android::JavaRef;
+using base::android::ScopedJavaGlobalRef;
+using base::android::ScopedJavaLocalRef;
+
namespace net {
namespace {
+// On Android < 4.2, the libkeystore.so ENGINE uses CRYPTO_EX_DATA and is not
+// added to the global engine list. If all references to it are dropped, OpenSSL
+// will dlclose the module, leaving a dangling function pointer in the RSA
+// CRYPTO_EX_DATA class. To work around this, leak an extra reference to the
+// ENGINE we extract in GetRsaLegacyKey.
+//
+// In 4.2, this change avoids the problem:
+// https://android.googlesource.com/platform/libcore/+/106a8928fb4249f2f3d4dba1dddbe73ca5cb3d61
+//
+// https://crbug.com/381465
+class KeystoreEngineWorkaround {
+ public:
+ KeystoreEngineWorkaround() {}
+
+ void LeakEngine(const JavaRef<jobject>& key) {
+ if (!engine_.is_null())
+ return;
+ ScopedJavaLocalRef<jobject> engine =
+ android::GetOpenSSLEngineForPrivateKey(key);
+ if (engine.is_null()) {
+ NOTREACHED();
+ return;
+ }
+ engine_.Reset(engine);
+ }
+
+ private:
+ ScopedJavaGlobalRef<jobject> engine_;
+};
+
+void LeakEngine(const JavaRef<jobject>& private_key) {
+ static base::LazyInstance<KeystoreEngineWorkaround>::Leaky s_instance =
+ LAZY_INSTANCE_INITIALIZER;
+ s_instance.Get().LeakEngine(private_key);
+}
+
class SSLPlatformKeyAndroid : public ThreadedSSLPrivateKey::Delegate {
public:
- SSLPlatformKeyAndroid(crypto::ScopedEVP_PKEY key, SSLPrivateKey::Type type)
- : key_(std::move(key)), type_(type) {}
+ SSLPlatformKeyAndroid(SSLPrivateKey::Type type,
+ const JavaRef<jobject>& key,
+ size_t max_length,
+ android::AndroidRSA* legacy_rsa)
+ : type_(type), max_length_(max_length), legacy_rsa_(legacy_rsa) {
+ key_.Reset(key);
+ }
~SSLPlatformKeyAndroid() override {}
@@ -40,100 +93,176 @@ class SSLPlatformKeyAndroid : public ThreadedSSLPrivateKey::Delegate {
kHashes + arraysize(kHashes));
}
- size_t GetMaxSignatureLengthInBytes() override {
- return EVP_PKEY_size(key_.get());
- }
+ size_t GetMaxSignatureLengthInBytes() override { return max_length_; }
Error SignDigest(SSLPrivateKey::Hash hash,
- const base::StringPiece& input,
+ const base::StringPiece& input_in,
std::vector<uint8_t>* signature) override {
- crypto::ScopedEVP_PKEY_CTX ctx =
- crypto::ScopedEVP_PKEY_CTX(EVP_PKEY_CTX_new(key_.get(), NULL));
- if (!ctx)
- return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
- if (!EVP_PKEY_sign_init(ctx.get()))
- return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
+ base::StringPiece input = input_in;
+ // Prepend the DigestInfo for RSA.
+ crypto::ScopedOpenSSLBytes digest_info_storage;
if (type_ == SSLPrivateKey::Type::RSA) {
- const EVP_MD* digest = nullptr;
+ int hash_nid = NID_undef;
switch (hash) {
case SSLPrivateKey::Hash::MD5_SHA1:
- digest = EVP_md5_sha1();
+ hash_nid = NID_md5_sha1;
break;
case SSLPrivateKey::Hash::SHA1:
- digest = EVP_sha1();
+ hash_nid = NID_sha1;
break;
case SSLPrivateKey::Hash::SHA256:
- digest = EVP_sha256();
+ hash_nid = NID_sha256;
break;
case SSLPrivateKey::Hash::SHA384:
- digest = EVP_sha384();
+ hash_nid = NID_sha384;
break;
case SSLPrivateKey::Hash::SHA512:
- digest = EVP_sha512();
+ hash_nid = NID_sha512;
break;
- default:
- return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
}
- DCHECK(digest);
- if (!EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PADDING))
+ DCHECK_NE(NID_undef, hash_nid);
+
+ uint8_t* digest_info;
+ size_t digest_info_len;
+ int is_alloced;
+ if (!RSA_add_pkcs1_prefix(
+ &digest_info, &digest_info_len, &is_alloced, hash_nid,
+ reinterpret_cast<const uint8_t*>(input.data()), input.size())) {
return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
- if (!EVP_PKEY_CTX_set_signature_md(ctx.get(), digest))
+ }
+
+ if (is_alloced)
+ digest_info_storage.reset(digest_info);
+ input = base::StringPiece(reinterpret_cast<const char*>(digest_info),
+ digest_info_len);
+ }
+
+ // Pre-4.2 legacy codepath.
+ if (legacy_rsa_) {
+ signature->resize(max_length_);
+ int ret = legacy_rsa_->meth->rsa_priv_enc(
+ input.size(), reinterpret_cast<const uint8_t*>(input.data()),
+ signature->data(), legacy_rsa_, android::ANDROID_RSA_PKCS1_PADDING);
+ if (ret < 0) {
+ LOG(WARNING) << "Could not sign message with legacy RSA key!";
+ // System OpenSSL will use a separate error queue, so it is still
+ // necessary to push a new error.
+ //
+ // TODO(davidben): It would be good to also clear the system error queue
+ // if there were some way to convince Java to do it. (Without going
+ // through Java, it's difficult to get a handle on a system OpenSSL
+ // function; dlopen loads a second copy.)
return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
+ }
+ signature->resize(ret);
+ return OK;
}
- const uint8_t* input_ptr = reinterpret_cast<const uint8_t*>(input.data());
- size_t input_len = input.size();
- size_t sig_len = 0;
- if (!EVP_PKEY_sign(ctx.get(), NULL, &sig_len, input_ptr, input_len))
- return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
- signature->resize(sig_len);
- if (!EVP_PKEY_sign(ctx.get(), signature->data(), &sig_len, input_ptr,
- input_len)) {
+ if (!android::RawSignDigestWithPrivateKey(key_, input, signature)) {
+ LOG(WARNING) << "Could not sign message with private key!";
return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
}
-
- signature->resize(sig_len);
-
return OK;
}
private:
- crypto::ScopedEVP_PKEY key_;
SSLPrivateKey::Type type_;
+ ScopedJavaGlobalRef<jobject> key_;
+ size_t max_length_;
+ android::AndroidRSA* legacy_rsa_;
DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeyAndroid);
};
-scoped_refptr<SSLPrivateKey> WrapOpenSSLPrivateKey(crypto::ScopedEVP_PKEY key) {
- if (!key)
+// VectorBignumSize returns the number of bytes needed to represent the bignum
+// given in |v|, i.e. the length of |v| less any leading zero bytes.
+size_t VectorBignumSize(const std::vector<uint8_t>& v) {
+ size_t size = v.size();
+ // Ignore any leading zero bytes.
+ for (size_t i = 0; i < v.size() && v[i] == 0; i++) {
+ size--;
+ }
+ return size;
+}
+
+std::unique_ptr<SSLPlatformKeyAndroid> CreateRsaKey(
+ const JavaRef<jobject>& key) {
+ android::AndroidRSA* sys_rsa = nullptr;
+ const int kAndroid42ApiLevel = 17;
+ if (base::android::BuildInfo::GetInstance()->sdk_int() < kAndroid42ApiLevel) {
+ // Route around platform limitations: if Android < 4.2, then
+ // base::android::RawSignDigestWithPrivateKey() cannot work, so try to get
+ // the system OpenSSL's EVP_PKEY backing this PrivateKey object.
+ android::AndroidEVP_PKEY* sys_pkey =
+ android::GetOpenSSLSystemHandleForPrivateKey(key);
+ if (!sys_pkey)
+ return nullptr;
+
+ if (sys_pkey->type != android::ANDROID_EVP_PKEY_RSA) {
+ LOG(ERROR) << "Private key has wrong type!";
+ return nullptr;
+ }
+
+ sys_rsa = sys_pkey->pkey.rsa;
+ if (sys_rsa->engine) {
+ // |private_key| may not have an engine if the PrivateKey did not come
+ // from the key store, such as in unit tests.
+ if (strcmp(sys_rsa->engine->id, "keystore") == 0) {
+ LeakEngine(key);
+ } else {
+ NOTREACHED();
+ }
+ }
+ }
+
+ std::vector<uint8_t> modulus;
+ if (!android::GetRSAKeyModulus(key, &modulus)) {
+ LOG(ERROR) << "Failed to get private key modulus";
return nullptr;
+ }
- SSLPrivateKey::Type type;
- switch (EVP_PKEY_id(key.get())) {
- case EVP_PKEY_RSA:
- type = SSLPrivateKey::Type::RSA;
+ return base::MakeUnique<SSLPlatformKeyAndroid>(
+ SSLPrivateKey::Type::RSA, key, VectorBignumSize(modulus), sys_rsa);
+}
+
+std::unique_ptr<SSLPlatformKeyAndroid> CreateEcdsaKey(
+ const JavaRef<jobject>& key) {
+ std::vector<uint8_t> order;
+ if (!android::GetECKeyOrder(key, &order)) {
+ LOG(ERROR) << "Can't extract order parameter from EC private key";
+ return nullptr;
+ }
+
+ return base::MakeUnique<SSLPlatformKeyAndroid>(
+ SSLPrivateKey::Type::ECDSA, key,
+ ECDSA_SIG_max_len(VectorBignumSize(order)), nullptr);
+}
+
+} // namespace
+
+scoped_refptr<SSLPrivateKey> WrapJavaPrivateKey(const JavaRef<jobject>& key) {
+ std::unique_ptr<SSLPlatformKeyAndroid> delegate;
+ switch (android::GetPrivateKeyType(key)) {
+ case android::PRIVATE_KEY_TYPE_RSA:
+ delegate = CreateRsaKey(key);
break;
- case EVP_PKEY_EC:
- type = SSLPrivateKey::Type::ECDSA;
+ case android::PRIVATE_KEY_TYPE_ECDSA:
+ delegate = CreateEcdsaKey(key);
break;
default:
- LOG(ERROR) << "Unknown key type: " << EVP_PKEY_id(key.get());
+ LOG(WARNING) << "GetPrivateKeyType() returned invalid type";
return nullptr;
}
+
return make_scoped_refptr(new ThreadedSSLPrivateKey(
- base::WrapUnique(new SSLPlatformKeyAndroid(std::move(key), type)),
- GetSSLPlatformKeyTaskRunner()));
+ std::move(delegate), GetSSLPlatformKeyTaskRunner()));
}
-} // namespace
-
scoped_refptr<SSLPrivateKey> FetchClientCertPrivateKey(
X509Certificate* certificate) {
- crypto::ScopedEVP_PKEY key =
- OpenSSLClientKeyStore::GetInstance()->FetchClientCertPrivateKey(
- certificate);
- return WrapOpenSSLPrivateKey(std::move(key));
+ return OpenSSLClientKeyStore::GetInstance()->FetchClientCertPrivateKey(
+ certificate);
}
} // namespace net
diff --git a/chromium/net/ssl/ssl_platform_key_android.h b/chromium/net/ssl/ssl_platform_key_android.h
new file mode 100644
index 00000000000..95fe90a953a
--- /dev/null
+++ b/chromium/net/ssl/ssl_platform_key_android.h
@@ -0,0 +1,25 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_SSL_SSL_PLATFORM_KEY_ANDROID_H_
+#define NET_SSL_SSL_PLATFORM_KEY_ANDROID_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/memory/ref_counted.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+class SSLPrivateKey;
+
+// Returns a new SSLPrivateKey which uses |key| for signing operations or
+// nullptr on error. |key| must be a java.security.PrivateKey object.
+NET_EXPORT scoped_refptr<SSLPrivateKey> WrapJavaPrivateKey(
+ const base::android::JavaRef<jobject>& key);
+
+} // namespace net
+
+#endif // NET_SSL_SSL_PLATFORM_KEY_ANDROID_H_
diff --git a/chromium/net/ssl/ssl_platform_key_android_unittest.cc b/chromium/net/ssl/ssl_platform_key_android_unittest.cc
new file mode 100644
index 00000000000..260597aaf8d
--- /dev/null
+++ b/chromium/net/ssl/ssl_platform_key_android_unittest.cc
@@ -0,0 +1,354 @@
+// Copyright (c) 2013 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 <openssl/bytestring.h>
+#include <openssl/digest.h>
+#include <openssl/ecdsa.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "crypto/openssl_util.h"
+#include "net/android/keystore.h"
+#include "net/cert/x509_certificate.h"
+#include "net/ssl/ssl_platform_key_android.h"
+#include "net/ssl/ssl_private_key.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/jni/AndroidKeyStoreTestUtil_jni.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+typedef base::android::ScopedJavaLocalRef<jobject> ScopedJava;
+
+// Resize a string to |size| bytes of data, then return its data buffer
+// address cast as an 'unsigned char*', as expected by OpenSSL functions.
+// |str| the target string.
+// |size| the number of bytes to write into the string.
+// Return the string's new buffer in memory, as an 'unsigned char*'
+// pointer.
+unsigned char* OpenSSLWriteInto(std::string* str, size_t size) {
+ return reinterpret_cast<unsigned char*>(base::WriteInto(str, size + 1));
+}
+
+bool ReadTestFile(const char* filename, std::string* pkcs8) {
+ base::FilePath certs_dir = GetTestCertsDirectory();
+ base::FilePath file_path = certs_dir.AppendASCII(filename);
+ return base::ReadFileToString(file_path, pkcs8);
+}
+
+// Load a given private key file into an EVP_PKEY.
+// |filename| is the key file path.
+// Returns a new EVP_PKEY on success, NULL on failure.
+bssl::UniquePtr<EVP_PKEY> ImportPrivateKeyFile(const char* filename) {
+ std::string pkcs8;
+ if (!ReadTestFile(filename, &pkcs8))
+ return nullptr;
+
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ CBS cbs;
+ CBS_init(&cbs, reinterpret_cast<const uint8_t*>(pkcs8.data()), pkcs8.size());
+ bssl::UniquePtr<EVP_PKEY> pkey(EVP_parse_private_key(&cbs));
+ if (!pkey) {
+ LOG(ERROR) << "Could not load private key file: " << filename;
+ return nullptr;
+ }
+
+ return pkey;
+}
+
+// Imports the public key from the specified test certificate.
+bssl::UniquePtr<EVP_PKEY> ImportPublicKeyFromCertificateFile(
+ const char* filename) {
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+
+ scoped_refptr<X509Certificate> cert =
+ ImportCertFromFile(GetTestCertsDirectory(), filename);
+ if (!cert) {
+ LOG(ERROR) << "Could not open certificate file: " << filename;
+ return nullptr;
+ }
+
+ bssl::UniquePtr<EVP_PKEY> pkey(X509_get_pubkey(cert->os_cert_handle()));
+ if (!pkey) {
+ LOG(ERROR) << "Could not load public key from certificate: " << filename;
+ return nullptr;
+ }
+
+ return pkey;
+}
+
+// Retrieve a JNI local ref from encoded PKCS#8 data.
+ScopedJava GetPKCS8PrivateKeyJava(android::PrivateKeyType key_type,
+ const std::string& pkcs8_key) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jbyteArray> bytes(
+ base::android::ToJavaByteArray(
+ env, reinterpret_cast<const uint8_t*>(pkcs8_key.data()),
+ pkcs8_key.size()));
+
+ ScopedJava key(Java_AndroidKeyStoreTestUtil_createPrivateKeyFromPKCS8(
+ env, key_type, bytes));
+
+ return key;
+}
+
+const char kTestRsaKeyFile[] = "client_1.pk8";
+
+// Retrieve a JNI local ref for our test RSA key.
+ScopedJava GetRSATestKeyJava() {
+ std::string key;
+ if (!ReadTestFile(kTestRsaKeyFile, &key))
+ return ScopedJava();
+ return GetPKCS8PrivateKeyJava(android::PRIVATE_KEY_TYPE_RSA, key);
+}
+
+const char kTestEcdsaKeyFile[] = "client_4.pk8";
+const char kTestEcdsaCertificateFile[] = "client_4.pem";
+
+// Retrieve a JNI local ref for our test ECDSA key.
+ScopedJava GetECDSATestKeyJava() {
+ std::string key;
+ if (!ReadTestFile(kTestEcdsaKeyFile, &key))
+ return ScopedJava();
+ return GetPKCS8PrivateKeyJava(android::PRIVATE_KEY_TYPE_ECDSA, key);
+}
+
+// Call this function to verify that one message signed with our
+// test ECDSA private key is correct. Since ECDSA signing introduces
+// random elements in the signature, it is not possible to compare
+// signature bits directly. However, one can use the public key
+// to do the check.
+bool VerifyTestECDSASignature(const base::StringPiece& message,
+ const base::StringPiece& signature) {
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+
+ bssl::UniquePtr<EVP_PKEY> pkey =
+ ImportPublicKeyFromCertificateFile(kTestEcdsaCertificateFile);
+ if (!pkey)
+ return false;
+
+ EC_KEY* pub_key = EVP_PKEY_get0_EC_KEY(pkey.get());
+ if (!pub_key) {
+ LOG(ERROR) << "Could not get ECDSA public key";
+ return false;
+ }
+
+ const unsigned char* digest =
+ reinterpret_cast<const unsigned char*>(message.data());
+ int digest_len = static_cast<int>(message.size());
+ const unsigned char* sigbuf =
+ reinterpret_cast<const unsigned char*>(signature.data());
+ int siglen = static_cast<int>(signature.size());
+
+ if (!ECDSA_verify(0, digest, digest_len, sigbuf, siglen, pub_key)) {
+ LOG(ERROR) << "ECDSA_verify() failed";
+ return false;
+ }
+ return true;
+}
+
+// Sign a message with OpenSSL, return the result as a string.
+// |message| is the message to be signed.
+// |openssl_key| is an OpenSSL EVP_PKEY to use.
+// |result| receives the result.
+// Returns true on success, false otherwise.
+bool SignWithOpenSSL(int hash_nid,
+ const base::StringPiece& message,
+ EVP_PKEY* openssl_key,
+ std::string* result) {
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+
+ RSA* rsa = EVP_PKEY_get0_RSA(openssl_key);
+ if (!rsa) {
+ LOG(ERROR) << "Could not get RSA from EVP_PKEY";
+ return false;
+ }
+
+ const unsigned char* digest =
+ reinterpret_cast<const unsigned char*>(message.data());
+ unsigned int digest_len = static_cast<unsigned int>(message.size());
+
+ // With RSA, the signature will always be RSA_size() bytes.
+ size_t max_signature_size = static_cast<size_t>(RSA_size(rsa));
+ std::string signature;
+ unsigned char* p = OpenSSLWriteInto(&signature, max_signature_size);
+ unsigned int p_len = 0;
+ if (!RSA_sign(hash_nid, digest, digest_len, p, &p_len, rsa)) {
+ LOG(ERROR) << "RSA_sign() failed";
+ return false;
+ }
+
+ size_t signature_size = static_cast<size_t>(p_len);
+ if (signature_size == 0) {
+ LOG(ERROR) << "Signature is empty!";
+ return false;
+ }
+ if (signature_size > max_signature_size) {
+ LOG(ERROR) << "Signature size mismatch, actual " << signature_size
+ << ", expected <= " << max_signature_size;
+ return false;
+ }
+ signature.resize(signature_size);
+ result->swap(signature);
+ return true;
+}
+
+// Check that a generated signature for a given message matches
+// OpenSSL output byte-by-byte.
+// |message| is the input message.
+// |signature| is the generated signature for the message.
+// |openssl_key| is a raw EVP_PKEY for the same private key than the
+// one which was used to generate the signature.
+// Returns true on success, false otherwise.
+bool CompareSignatureWithOpenSSL(int hash_nid,
+ const base::StringPiece& message,
+ const base::StringPiece& signature,
+ EVP_PKEY* openssl_key) {
+ std::string openssl_signature;
+ if (!SignWithOpenSSL(hash_nid, message, openssl_key, &openssl_signature))
+ return false;
+
+ if (signature.size() != openssl_signature.size()) {
+ LOG(ERROR) << "Signature size mismatch, actual " << signature.size()
+ << ", expected " << openssl_signature.size();
+ return false;
+ }
+ for (size_t n = 0; n < signature.size(); ++n) {
+ if (openssl_signature[n] != signature[n]) {
+ LOG(ERROR) << "Signature byte mismatch at index " << n << "actual "
+ << signature[n] << ", expected " << openssl_signature[n];
+ LOG(ERROR) << "Actual signature : "
+ << base::HexEncode(signature.data(), signature.size());
+ LOG(ERROR) << "Expected signature: "
+ << base::HexEncode(openssl_signature.data(),
+ openssl_signature.size());
+ return false;
+ }
+ }
+ return true;
+}
+
+void OnSignComplete(base::RunLoop* loop,
+ Error* out_error,
+ std::string* out_signature,
+ Error error,
+ const std::vector<uint8_t>& signature) {
+ *out_error = error;
+ out_signature->assign(signature.begin(), signature.end());
+ loop->Quit();
+}
+
+void DoKeySigningWithWrapper(SSLPrivateKey* key,
+ SSLPrivateKey::Hash hash,
+ const base::StringPiece& message,
+ std::string* result) {
+ Error error;
+ base::RunLoop loop;
+
+ key->SignDigest(
+ hash, message,
+ base::Bind(OnSignComplete, base::Unretained(&loop),
+ base::Unretained(&error), base::Unretained(result)));
+ loop.Run();
+
+ ASSERT_EQ(OK, error);
+}
+
+static const struct {
+ const char* name;
+ int nid;
+ SSLPrivateKey::Hash hash;
+} kHashes[] = {
+ {"MD5-SHA1", NID_md5_sha1, SSLPrivateKey::Hash::MD5_SHA1},
+ {"SHA-1", NID_sha1, SSLPrivateKey::Hash::SHA1},
+ {"SHA-256", NID_sha256, SSLPrivateKey::Hash::SHA256},
+ {"SHA-384", NID_sha384, SSLPrivateKey::Hash::SHA384},
+ {"SHA-512", NID_sha512, SSLPrivateKey::Hash::SHA512},
+};
+
+} // namespace
+
+TEST(SSLPlatformKeyAndroid, RSA) {
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+
+ ScopedJava rsa_key = GetRSATestKeyJava();
+ ASSERT_FALSE(rsa_key.is_null());
+
+ scoped_refptr<SSLPrivateKey> wrapper_key = WrapJavaPrivateKey(rsa_key);
+ ASSERT_TRUE(wrapper_key);
+
+ bssl::UniquePtr<EVP_PKEY> openssl_key = ImportPrivateKeyFile(kTestRsaKeyFile);
+ ASSERT_TRUE(openssl_key);
+
+ // Check that the wrapper key returns the correct length and type.
+ EXPECT_EQ(SSLPrivateKey::Type::RSA, wrapper_key->GetType());
+ EXPECT_EQ(static_cast<size_t>(EVP_PKEY_size(openssl_key.get())),
+ wrapper_key->GetMaxSignatureLengthInBytes());
+
+ // Test signing against each hash.
+ for (const auto& hash : kHashes) {
+ SCOPED_TRACE(hash.name);
+
+ const EVP_MD* md = EVP_get_digestbynid(hash.nid);
+ ASSERT_TRUE(md);
+ std::string digest(EVP_MD_size(md), 'a');
+
+ std::string signature;
+ DoKeySigningWithWrapper(wrapper_key.get(), hash.hash, digest, &signature);
+ ASSERT_TRUE(CompareSignatureWithOpenSSL(hash.nid, digest, signature,
+ openssl_key.get()));
+ }
+}
+
+TEST(SSLPlatformKeyAndroid, ECDSA) {
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+
+ ScopedJava ecdsa_key = GetECDSATestKeyJava();
+ ASSERT_FALSE(ecdsa_key.is_null());
+
+ scoped_refptr<SSLPrivateKey> wrapper_key = WrapJavaPrivateKey(ecdsa_key);
+ ASSERT_TRUE(wrapper_key);
+
+ bssl::UniquePtr<EVP_PKEY> openssl_key =
+ ImportPrivateKeyFile(kTestEcdsaKeyFile);
+ ASSERT_TRUE(openssl_key);
+
+ // Check that the wrapper key returns the correct length and type.
+ EXPECT_EQ(SSLPrivateKey::Type::ECDSA, wrapper_key->GetType());
+ EXPECT_EQ(static_cast<size_t>(EVP_PKEY_size(openssl_key.get())),
+ wrapper_key->GetMaxSignatureLengthInBytes());
+
+ // Test signing against each hash.
+ for (const auto& hash : kHashes) {
+ // ECDSA does not sign MD5-SHA1.
+ if (hash.nid == NID_md5_sha1)
+ continue;
+
+ SCOPED_TRACE(hash.name);
+ const EVP_MD* md = EVP_get_digestbynid(hash.nid);
+ ASSERT_TRUE(md);
+ std::string digest(EVP_MD_size(md), 'a');
+
+ std::string signature;
+ DoKeySigningWithWrapper(wrapper_key.get(), hash.hash, digest, &signature);
+ ASSERT_TRUE(VerifyTestECDSASignature(digest, signature));
+ }
+}
+
+} // namespace net
diff --git a/chromium/net/ssl/ssl_platform_key_chromecast.cc b/chromium/net/ssl/ssl_platform_key_chromecast.cc
index 6ee005de84a..e07ace5fab6 100644
--- a/chromium/net/ssl/ssl_platform_key_chromecast.cc
+++ b/chromium/net/ssl/ssl_platform_key_chromecast.cc
@@ -128,7 +128,7 @@ scoped_refptr<SSLPrivateKey> FetchClientCertPrivateKey(
}
return make_scoped_refptr(new ThreadedSSLPrivateKey(
- base::WrapUnique(new SSLPlatformKeyChromecast(std::move(key))),
+ base::MakeUnique<SSLPlatformKeyChromecast>(std::move(key)),
GetSSLPlatformKeyTaskRunner()));
}
diff --git a/chromium/net/ssl/ssl_platform_key_mac.cc b/chromium/net/ssl/ssl_platform_key_mac.cc
index 35628f819cc..ce653d5c3c9 100644
--- a/chromium/net/ssl/ssl_platform_key_mac.cc
+++ b/chromium/net/ssl/ssl_platform_key_mac.cc
@@ -243,7 +243,7 @@ scoped_refptr<SSLPrivateKey> FetchClientCertPrivateKey(
return nullptr;
}
return make_scoped_refptr(new ThreadedSSLPrivateKey(
- base::WrapUnique(new SSLPlatformKeyMac(private_key.get(), cssm_key)),
+ base::MakeUnique<SSLPlatformKeyMac>(private_key.get(), cssm_key),
GetSSLPlatformKeyTaskRunner()));
}
diff --git a/chromium/net/ssl/ssl_platform_key_nss.cc b/chromium/net/ssl/ssl_platform_key_nss.cc
index fc05976e960..79db0d6e66a 100644
--- a/chromium/net/ssl/ssl_platform_key_nss.cc
+++ b/chromium/net/ssl/ssl_platform_key_nss.cc
@@ -183,7 +183,7 @@ scoped_refptr<SSLPrivateKey> FetchClientCertPrivateKey(
return nullptr;
}
return make_scoped_refptr(new ThreadedSSLPrivateKey(
- base::WrapUnique(new SSLPlatformKeyNSS(type, std::move(key))),
+ base::MakeUnique<SSLPlatformKeyNSS>(type, std::move(key)),
GetSSLPlatformKeyTaskRunner()));
}
diff --git a/chromium/net/ssl/ssl_platform_key_task_runner.cc b/chromium/net/ssl/ssl_platform_key_task_runner.cc
index 7611d60454d..2ef8469c15f 100644
--- a/chromium/net/ssl/ssl_platform_key_task_runner.cc
+++ b/chromium/net/ssl/ssl_platform_key_task_runner.cc
@@ -2,29 +2,30 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/lazy_instance.h"
#include "net/ssl/ssl_platform_key_task_runner.h"
+#include "base/lazy_instance.h"
+
namespace net {
-SSLPlatformKeyTaskRunner::SSLPlatformKeyTaskRunner() {
- worker_pool_ = new base::SequencedWorkerPool(1, "Platform Key Thread");
- task_runner_ = worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
- worker_pool_->GetSequenceToken(),
- base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+SSLPlatformKeyTaskRunner::SSLPlatformKeyTaskRunner()
+ : worker_thread_("Platform Key Thread") {
+ base::Thread::Options options;
+ options.joinable = false;
+ worker_thread_.StartWithOptions(options);
}
-SSLPlatformKeyTaskRunner::~SSLPlatformKeyTaskRunner() {}
+SSLPlatformKeyTaskRunner::~SSLPlatformKeyTaskRunner() = default;
-scoped_refptr<base::SequencedTaskRunner>
+scoped_refptr<base::SingleThreadTaskRunner>
SSLPlatformKeyTaskRunner::task_runner() {
- return task_runner_;
+ return worker_thread_.task_runner();
}
base::LazyInstance<SSLPlatformKeyTaskRunner>::Leaky g_platform_key_task_runner =
LAZY_INSTANCE_INITIALIZER;
-scoped_refptr<base::SequencedTaskRunner> GetSSLPlatformKeyTaskRunner() {
+scoped_refptr<base::SingleThreadTaskRunner> GetSSLPlatformKeyTaskRunner() {
return g_platform_key_task_runner.Get().task_runner();
}
diff --git a/chromium/net/ssl/ssl_platform_key_task_runner.h b/chromium/net/ssl/ssl_platform_key_task_runner.h
index 0c9b124f1fa..cb6b4b4c28c 100644
--- a/chromium/net/ssl/ssl_platform_key_task_runner.h
+++ b/chromium/net/ssl/ssl_platform_key_task_runner.h
@@ -6,27 +6,32 @@
#define NET_SSL_SSL_PLATFORM_KEY_TASK_RUNNER_H_
#include "base/macros.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
namespace net {
-// Serialize all the private key operations on a single background
-// thread to avoid problems with buggy smartcards.
+// Serialize all the private key operations on a single background thread to
+// avoid problems with buggy smartcards. Its underlying Thread is non-joinable
+// and as such provides TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN semantics.
class SSLPlatformKeyTaskRunner {
public:
SSLPlatformKeyTaskRunner();
~SSLPlatformKeyTaskRunner();
- scoped_refptr<base::SequencedTaskRunner> task_runner();
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner();
private:
- scoped_refptr<base::SequencedWorkerPool> worker_pool_;
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ base::Thread worker_thread_;
DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeyTaskRunner);
};
-scoped_refptr<base::SequencedTaskRunner> GetSSLPlatformKeyTaskRunner();
+scoped_refptr<base::SingleThreadTaskRunner> GetSSLPlatformKeyTaskRunner();
} // namespace net
diff --git a/chromium/net/ssl/ssl_platform_key_win.cc b/chromium/net/ssl/ssl_platform_key_win.cc
index 11c9d111a3d..0a3f89a968c 100644
--- a/chromium/net/ssl/ssl_platform_key_win.cc
+++ b/chromium/net/ssl/ssl_platform_key_win.cc
@@ -17,7 +17,6 @@
#include <openssl/evp.h>
#include <openssl/x509.h>
-#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/sequenced_task_runner.h"
@@ -35,42 +34,6 @@ namespace net {
namespace {
-using NCryptFreeObjectFunc = SECURITY_STATUS(WINAPI*)(NCRYPT_HANDLE);
-using NCryptSignHashFunc = SECURITY_STATUS(WINAPI*)(NCRYPT_KEY_HANDLE, // hKey
- VOID*, // pPaddingInfo
- BYTE*, // pbHashValue
- DWORD, // cbHashValue
- BYTE*, // pbSignature
- DWORD, // cbSignature
- DWORD*, // pcbResult
- DWORD); // dwFlags
-
-class CNGFunctions {
- public:
- CNGFunctions() : ncrypt_free_object_(nullptr), ncrypt_sign_hash_(nullptr) {
- HMODULE ncrypt = GetModuleHandle(L"ncrypt.dll");
- if (ncrypt != nullptr) {
- ncrypt_free_object_ = reinterpret_cast<NCryptFreeObjectFunc>(
- GetProcAddress(ncrypt, "NCryptFreeObject"));
- ncrypt_sign_hash_ = reinterpret_cast<NCryptSignHashFunc>(
- GetProcAddress(ncrypt, "NCryptSignHash"));
- }
- }
-
- NCryptFreeObjectFunc ncrypt_free_object() const {
- return ncrypt_free_object_;
- }
-
- NCryptSignHashFunc ncrypt_sign_hash() const { return ncrypt_sign_hash_; }
-
- private:
- NCryptFreeObjectFunc ncrypt_free_object_;
- NCryptSignHashFunc ncrypt_sign_hash_;
-};
-
-base::LazyInstance<CNGFunctions>::Leaky g_cng_functions =
- LAZY_INSTANCE_INITIALIZER;
-
class SSLPlatformKeyCAPI : public ThreadedSSLPrivateKey::Delegate {
public:
// Takes ownership of |provider|.
@@ -172,9 +135,7 @@ class SSLPlatformKeyCNG : public ThreadedSSLPrivateKey::Delegate {
size_t max_length)
: key_(key), type_(type), max_length_(max_length) {}
- ~SSLPlatformKeyCNG() override {
- g_cng_functions.Get().ncrypt_free_object()(key_);
- }
+ ~SSLPlatformKeyCNG() override { NCryptFreeObject(key_); }
SSLPrivateKey::Type GetType() override { return type_; }
@@ -230,7 +191,7 @@ class SSLPlatformKeyCNG : public ThreadedSSLPrivateKey::Delegate {
}
DWORD signature_len;
- SECURITY_STATUS status = g_cng_functions.Get().ncrypt_sign_hash()(
+ SECURITY_STATUS status = NCryptSignHash(
key_, padding_info,
const_cast<BYTE*>(reinterpret_cast<const BYTE*>(input.data())),
input.size(), nullptr, 0, &signature_len, flags);
@@ -239,7 +200,7 @@ class SSLPlatformKeyCNG : public ThreadedSSLPrivateKey::Delegate {
return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
}
signature->resize(signature_len);
- status = g_cng_functions.Get().ncrypt_sign_hash()(
+ status = NCryptSignHash(
key_, padding_info,
const_cast<BYTE*>(reinterpret_cast<const BYTE*>(input.data())),
input.size(), signature->data(), signature_len, &signature_len, flags);
diff --git a/chromium/net/ssl/ssl_server_config.cc b/chromium/net/ssl/ssl_server_config.cc
index f5041b672b1..0cdb9a1db94 100644
--- a/chromium/net/ssl/ssl_server_config.cc
+++ b/chromium/net/ssl/ssl_server_config.cc
@@ -11,7 +11,7 @@ namespace net {
SSLServerConfig::SSLServerConfig()
: version_min(kDefaultSSLVersionMin),
- version_max(SSL_PROTOCOL_VERSION_TLS1_2),
+ version_max(kDefaultSSLVersionMax),
require_ecdhe(false),
client_cert_type(NO_CLIENT_CERT),
client_cert_verifier(nullptr) {}
diff --git a/chromium/net/ssl/test_ssl_private_key.cc b/chromium/net/ssl/test_ssl_private_key.cc
index 6d420b0e4c6..f6fadbf6dfa 100644
--- a/chromium/net/ssl/test_ssl_private_key.cc
+++ b/chromium/net/ssl/test_ssl_private_key.cc
@@ -123,7 +123,7 @@ scoped_refptr<SSLPrivateKey> WrapOpenSSLPrivateKey(crypto::ScopedEVP_PKEY key) {
return nullptr;
}
return make_scoped_refptr(new ThreadedSSLPrivateKey(
- base::WrapUnique(new TestSSLPlatformKey(std::move(key), type)),
+ base::MakeUnique<TestSSLPlatformKey>(std::move(key), type),
GetSSLPlatformKeyTaskRunner()));
}
diff --git a/chromium/net/ssl/threaded_ssl_private_key.cc b/chromium/net/ssl/threaded_ssl_private_key.cc
index a1294fadc4c..42f01f6c0ed 100644
--- a/chromium/net/ssl/threaded_ssl_private_key.cc
+++ b/chromium/net/ssl/threaded_ssl_private_key.cc
@@ -9,7 +9,7 @@
#include "base/bind.h"
#include "base/location.h"
-#include "base/task_runner.h"
+#include "base/single_thread_task_runner.h"
#include "base/task_runner_util.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -50,7 +50,7 @@ class ThreadedSSLPrivateKey::Core
ThreadedSSLPrivateKey::ThreadedSSLPrivateKey(
std::unique_ptr<ThreadedSSLPrivateKey::Delegate> delegate,
- scoped_refptr<base::TaskRunner> task_runner)
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: core_(new Core(std::move(delegate))),
task_runner_(std::move(task_runner)),
weak_factory_(this) {}
diff --git a/chromium/net/ssl/threaded_ssl_private_key.h b/chromium/net/ssl/threaded_ssl_private_key.h
index c2fe2282a15..e2f79aa0b6b 100644
--- a/chromium/net/ssl/threaded_ssl_private_key.h
+++ b/chromium/net/ssl/threaded_ssl_private_key.h
@@ -18,7 +18,7 @@
#include "net/ssl/ssl_private_key.h"
namespace base {
-class TaskRunner;
+class SingleThreadTaskRunner;
}
namespace net {
@@ -52,8 +52,9 @@ class ThreadedSSLPrivateKey : public SSLPrivateKey {
DISALLOW_COPY_AND_ASSIGN(Delegate);
};
- ThreadedSSLPrivateKey(std::unique_ptr<Delegate> delegate,
- scoped_refptr<base::TaskRunner> task_runner);
+ ThreadedSSLPrivateKey(
+ std::unique_ptr<Delegate> delegate,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// SSLPrivateKey implementation.
Type GetType() override;
@@ -68,7 +69,7 @@ class ThreadedSSLPrivateKey : public SSLPrivateKey {
class Core;
scoped_refptr<Core> core_;
- scoped_refptr<base::TaskRunner> task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
base::WeakPtrFactory<ThreadedSSLPrivateKey> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ThreadedSSLPrivateKey);
diff --git a/chromium/net/ssl/token_binding.cc b/chromium/net/ssl/token_binding.cc
index 0c6dd81fafc..e584c566198 100644
--- a/chromium/net/ssl/token_binding.cc
+++ b/chromium/net/ssl/token_binding.cc
@@ -6,10 +6,12 @@
#include <openssl/bytestring.h>
#include <openssl/ec.h>
+#include <openssl/ec_key.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
#include "base/stl_util.h"
+#include "crypto/ec_private_key.h"
#include "crypto/scoped_openssl_types.h"
#include "net/base/net_errors.h"
#include "net/ssl/ssl_config.h"
@@ -18,16 +20,24 @@ namespace net {
namespace {
+const size_t kUncompressedPointLen = 65;
+
bool BuildTokenBindingID(crypto::ECPrivateKey* key, CBB* out) {
EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(key->key());
DCHECK(ec_key);
- CBB ec_point;
+ uint8_t point_buf[kUncompressedPointLen];
+ if (EC_POINT_point2oct(
+ EC_KEY_get0_group(ec_key), EC_KEY_get0_public_key(ec_key),
+ POINT_CONVERSION_UNCOMPRESSED, point_buf, kUncompressedPointLen,
+ NULL) != kUncompressedPointLen) {
+ return false;
+ }
+ CBB public_key, ec_point;
return CBB_add_u8(out, TB_PARAM_ECDSAP256) &&
- CBB_add_u8_length_prefixed(out, &ec_point) &&
- EC_POINT_point2cbb(&ec_point, EC_KEY_get0_group(ec_key),
- EC_KEY_get0_public_key(ec_key),
- POINT_CONVERSION_UNCOMPRESSED, nullptr) &&
+ CBB_add_u16_length_prefixed(out, &public_key) &&
+ CBB_add_u8_length_prefixed(&public_key, &ec_point) &&
+ CBB_add_bytes(&ec_point, point_buf + 1, kUncompressedPointLen - 1) &&
CBB_flush(out);
}
@@ -60,14 +70,26 @@ ECDSA_SIG* RawToECDSA_SIG(EC_KEY* ec, base::StringPiece sig) {
} // namespace
-bool SignTokenBindingEkm(base::StringPiece ekm,
- crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) {
- const uint8_t* ekm_data = reinterpret_cast<const uint8_t*>(ekm.data());
+bool CreateTokenBindingSignature(base::StringPiece ekm,
+ TokenBindingType type,
+ crypto::ECPrivateKey* key,
+ std::vector<uint8_t>* out) {
+ crypto::ScopedEVP_MD_CTX digest_ctx(EVP_MD_CTX_create());
+ uint8_t tb_type = static_cast<uint8_t>(type);
+ uint8_t key_type = static_cast<uint8_t>(TB_PARAM_ECDSAP256);
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ unsigned int digest_len;
+ if (!EVP_DigestInit(digest_ctx.get(), EVP_sha256()) ||
+ !EVP_DigestUpdate(digest_ctx.get(), &tb_type, 1) ||
+ !EVP_DigestUpdate(digest_ctx.get(), &key_type, 1) ||
+ !EVP_DigestUpdate(digest_ctx.get(), ekm.data(), ekm.size()) ||
+ !EVP_DigestFinal_ex(digest_ctx.get(), digest, &digest_len)) {
+ return false;
+ }
EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(key->key());
if (!ec_key)
return false;
- crypto::ScopedECDSA_SIG sig(ECDSA_do_sign(ekm_data, ekm.size(), ec_key));
+ crypto::ScopedECDSA_SIG sig(ECDSA_do_sign(digest, digest_len, ec_key));
if (!sig)
return false;
return ECDSA_SIGToRaw(sig.get(), ec_key, out);
@@ -129,7 +151,7 @@ TokenBinding::TokenBinding() {}
bool ParseTokenBindingMessage(base::StringPiece token_binding_message,
std::vector<TokenBinding>* token_bindings) {
- CBS tb_message, tb, ec_point, signature, extensions;
+ CBS tb_message, tb, public_key, ec_point, signature, extensions;
uint8_t tb_type, tb_param;
CBS_init(&tb_message,
reinterpret_cast<const uint8_t*>(token_binding_message.data()),
@@ -138,7 +160,9 @@ bool ParseTokenBindingMessage(base::StringPiece token_binding_message,
return false;
while (CBS_len(&tb)) {
if (!CBS_get_u8(&tb, &tb_type) || !CBS_get_u8(&tb, &tb_param) ||
- !CBS_get_u8_length_prefixed(&tb, &ec_point) ||
+ !CBS_get_u16_length_prefixed(&tb, &public_key) ||
+ !CBS_get_u8_length_prefixed(&public_key, &ec_point) ||
+ CBS_len(&public_key) != 0 ||
!CBS_get_u16_length_prefixed(&tb, &signature) ||
!CBS_get_u16_length_prefixed(&tb, &extensions) ||
tb_param != TB_PARAM_ECDSAP256 ||
@@ -159,20 +183,41 @@ bool ParseTokenBindingMessage(base::StringPiece token_binding_message,
return true;
}
-bool VerifyEKMSignature(base::StringPiece ec_point,
- base::StringPiece signature,
- base::StringPiece ekm) {
+bool VerifyTokenBindingSignature(base::StringPiece ec_point,
+ base::StringPiece signature,
+ TokenBindingType type,
+ base::StringPiece ekm) {
+ if (ec_point.size() != kUncompressedPointLen - 1)
+ return false;
+ uint8_t x9_62_ec_point[kUncompressedPointLen];
+ x9_62_ec_point[0] = 4;
+ memcpy(x9_62_ec_point + 1, ec_point.data(), kUncompressedPointLen - 1);
crypto::ScopedEC_Key key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
EC_KEY* keyp = key.get();
- const uint8_t* ec_point_data =
- reinterpret_cast<const uint8_t*>(ec_point.data());
- if (o2i_ECPublicKey(&keyp, &ec_point_data, ec_point.size()) != key.get())
+ crypto::ScopedEC_POINT pub_key(EC_POINT_new(EC_KEY_get0_group(keyp)));
+ if (!EC_POINT_oct2point(EC_KEY_get0_group(keyp), pub_key.get(),
+ x9_62_ec_point, kUncompressedPointLen, nullptr) ||
+ !EC_KEY_set_public_key(keyp, pub_key.get())) {
return false;
+ }
+
+ crypto::ScopedEVP_MD_CTX digest_ctx(EVP_MD_CTX_create());
+ uint8_t tb_type = static_cast<uint8_t>(type);
+ uint8_t key_type = static_cast<uint8_t>(TB_PARAM_ECDSAP256);
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ unsigned int digest_len;
+ if (!EVP_DigestInit(digest_ctx.get(), EVP_sha256()) ||
+ !EVP_DigestUpdate(digest_ctx.get(), &tb_type, 1) ||
+ !EVP_DigestUpdate(digest_ctx.get(), &key_type, 1) ||
+ !EVP_DigestUpdate(digest_ctx.get(), ekm.data(), ekm.size()) ||
+ !EVP_DigestFinal_ex(digest_ctx.get(), digest, &digest_len)) {
+ return false;
+ }
+
crypto::ScopedECDSA_SIG sig(RawToECDSA_SIG(keyp, signature));
if (!sig)
return false;
- return !!ECDSA_do_verify(reinterpret_cast<const uint8_t*>(ekm.data()),
- ekm.size(), sig.get(), keyp);
+ return !!ECDSA_do_verify(digest, digest_len, sig.get(), keyp);
}
} // namespace net
diff --git a/chromium/net/ssl/token_binding.h b/chromium/net/ssl/token_binding.h
index a98485095d0..445e4d6f4dd 100644
--- a/chromium/net/ssl/token_binding.h
+++ b/chromium/net/ssl/token_binding.h
@@ -9,10 +9,13 @@
#include <vector>
#include "base/strings/string_piece.h"
-#include "crypto/ec_private_key.h"
#include "net/base/net_errors.h"
#include "net/base/net_export.h"
+namespace crypto {
+class ECPrivateKey;
+}
+
namespace net {
enum class TokenBindingType {
@@ -20,12 +23,16 @@ enum class TokenBindingType {
REFERRED = 1,
};
-// Takes an exported keying material value |ekm| from the TLS layer and a token
-// binding key |key| and signs the EKM, putting the signature in |*out|. Returns
-// true on success or false if there's an error in the signing operations.
-bool SignTokenBindingEkm(base::StringPiece ekm,
- crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out);
+// Takes an exported keying material value |ekm| from the TLS layer, the type of
+// Token Binding |type|, and a token binding key |key| and concatenates the
+// Token Binding type, key type, and ekm. This concatenation is signed with
+// |key| in accordance with section 3.3 of draft-ietf-tokbind-protocol-10, with
+// the signature written to |*out|. Returns true on success or false if there's
+// an error in the signing operations.
+bool CreateTokenBindingSignature(base::StringPiece ekm,
+ TokenBindingType type,
+ crypto::ECPrivateKey* key,
+ std::vector<uint8_t>* out);
// Given a vector of serialized TokenBinding structs (as defined in
// draft-ietf-tokbind-protocol-04), this function combines them to form the
@@ -99,14 +106,15 @@ NET_EXPORT_PRIVATE bool ParseTokenBindingMessage(
base::StringPiece token_binding_message,
std::vector<TokenBinding>* token_bindings);
-// Takes an ECPoint |ec_point| from a TokenBindingID and |signature| from a
-// TokenBinding and verifies that |signature| is the signature of |ekm| using
-// |ec_point| as the public key. Returns true if the signature verifies and
-// false if it doesn't or some other error occurs in verification. This function
-// is only provided for testing.
-NET_EXPORT_PRIVATE bool VerifyEKMSignature(base::StringPiece ec_point,
- base::StringPiece signature,
- base::StringPiece ekm);
+// Takes an ECPoint |ec_point| from a TokenBindingID, |signature| from a
+// TokenBinding, and a Token Binding type |type| and verifies that |signature|
+// is the signature of |ekm| using |ec_point| as the public key. Returns true if
+// the signature verifies and false if it doesn't or some other error occurs in
+// verification. This function is only provided for testing.
+NET_EXPORT_PRIVATE bool VerifyTokenBindingSignature(base::StringPiece ec_point,
+ base::StringPiece signature,
+ TokenBindingType type,
+ base::StringPiece ekm);
} // namespace net
diff --git a/chromium/net/test/ct_test_util.cc b/chromium/net/test/ct_test_util.cc
index c22dd3a4ddb..c8b25f88ddf 100644
--- a/chromium/net/test/ct_test_util.cc
+++ b/chromium/net/test/ct_test_util.cc
@@ -179,7 +179,6 @@ void GetX509CertLogEntry(LogEntry* entry) {
}
void GetX509CertTreeLeaf(MerkleTreeLeaf* tree_leaf) {
- tree_leaf->log_id = HexToBytes(kTestKeyId);
tree_leaf->timestamp = base::Time::FromJsTime(kTestTimestamp);
GetX509CertLogEntry(&tree_leaf->log_entry);
tree_leaf->extensions = HexToBytes(kDefaultExtensions);
@@ -195,7 +194,6 @@ void GetPrecertLogEntry(LogEntry* entry) {
}
void GetPrecertTreeLeaf(MerkleTreeLeaf* tree_leaf) {
- tree_leaf->log_id = HexToBytes(kTestKeyId);
tree_leaf->timestamp = base::Time::FromJsTime(kTestTimestamp);
GetPrecertLogEntry(&tree_leaf->log_entry);
tree_leaf->extensions = HexToBytes(kDefaultExtensions);
@@ -401,15 +399,19 @@ std::string GetSCTListWithInvalidSCT() {
bool CheckForSingleVerifiedSCTInResult(const ct::CTVerifyResult& result,
const std::string& log_description) {
- return (result.verified_scts.size() == 1U) && result.invalid_scts.empty() &&
- result.unknown_logs_scts.empty() &&
- result.verified_scts[0]->log_description == log_description;
+ return (result.scts.size() == 1 &&
+ result.scts[0].status == ct::SCT_STATUS_OK &&
+ result.scts[0].sct->log_description == log_description);
}
bool CheckForSCTOrigin(const ct::CTVerifyResult& result,
ct::SignedCertificateTimestamp::Origin origin) {
- return (result.verified_scts.size() > 0) &&
- (result.verified_scts[0]->origin == origin);
+ for (const auto& sct_and_status : result.scts)
+ if (sct_and_status.status == SCT_STATUS_OK &&
+ sct_and_status.sct->origin == origin)
+ return true;
+
+ return false;
}
} // namespace ct
diff --git a/chromium/net/test/embedded_test_server/android/embedded_test_server_android.cc b/chromium/net/test/embedded_test_server/android/embedded_test_server_android.cc
index 3a43e497f67..0b25220c38c 100644
--- a/chromium/net/test/embedded_test_server/android/embedded_test_server_android.cc
+++ b/chromium/net/test/embedded_test_server/android/embedded_test_server_android.cc
@@ -12,10 +12,15 @@
#include "base/trace_event/trace_event.h"
#include "net/test/jni/EmbeddedTestServerImpl_jni.h"
+using base::android::JavaParamRef;
+using base::android::JavaRef;
+
namespace net {
namespace test_server {
-EmbeddedTestServerAndroid::EmbeddedTestServerAndroid(JNIEnv* env, jobject jobj)
+EmbeddedTestServerAndroid::EmbeddedTestServerAndroid(
+ JNIEnv* env,
+ const JavaRef<jobject>& jobj)
: weak_java_server_(env, jobj), test_server_() {
Java_EmbeddedTestServerImpl_setNativePtr(env, jobj,
reinterpret_cast<intptr_t>(this));
@@ -23,8 +28,7 @@ EmbeddedTestServerAndroid::EmbeddedTestServerAndroid(JNIEnv* env, jobject jobj)
EmbeddedTestServerAndroid::~EmbeddedTestServerAndroid() {
JNIEnv* env = base::android::AttachCurrentThread();
- Java_EmbeddedTestServerImpl_clearNativePtr(env,
- weak_java_server_.get(env).obj());
+ Java_EmbeddedTestServerImpl_clearNativePtr(env, weak_java_server_.get(env));
}
jboolean EmbeddedTestServerAndroid::Start(JNIEnv* env,
diff --git a/chromium/net/test/embedded_test_server/android/embedded_test_server_android.h b/chromium/net/test/embedded_test_server/android/embedded_test_server_android.h
index c0d1cec6008..1b73082997d 100644
--- a/chromium/net/test/embedded_test_server/android/embedded_test_server_android.h
+++ b/chromium/net/test/embedded_test_server/android/embedded_test_server_android.h
@@ -20,7 +20,8 @@ namespace test_server {
// The C++ side of the Java EmbeddedTestServer.
class EmbeddedTestServerAndroid {
public:
- EmbeddedTestServerAndroid(JNIEnv* env, jobject obj);
+ EmbeddedTestServerAndroid(JNIEnv* env,
+ const base::android::JavaRef<jobject>& obj);
~EmbeddedTestServerAndroid();
void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
diff --git a/chromium/net/test/embedded_test_server/default_handlers.cc b/chromium/net/test/embedded_test_server/default_handlers.cc
index 1b49ceb61ca..16c2487742e 100644
--- a/chromium/net/test/embedded_test_server/default_handlers.cc
+++ b/chromium/net/test/embedded_test_server/default_handlers.cc
@@ -17,6 +17,7 @@
#include "base/format_macros.h"
#include "base/macros.h"
#include "base/md5.h"
+#include "base/memory/ptr_util.h"
#include "base/path_service.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -159,6 +160,12 @@ std::unique_ptr<HttpResponse> HandleEchoAll(const HttpRequest& request) {
return std::move(http_response);
}
+// /echo-raw
+// Returns the query string as the raw response (no HTTP headers).
+std::unique_ptr<HttpResponse> HandleEchoRaw(const HttpRequest& request) {
+ return base::MakeUnique<RawHttpResponse>("", request.GetURL().query());
+}
+
// /set-cookie?COOKIES
// Sets response cookies to be COOKIES.
std::unique_ptr<HttpResponse> HandleSetCookie(const HttpRequest& request) {
@@ -601,6 +608,7 @@ void RegisterDefaultHandlers(EmbeddedTestServer* server) {
server->RegisterDefaultHandler(
PREFIXED_HANDLER("/echotitle", &HandleEchoTitle));
server->RegisterDefaultHandler(PREFIXED_HANDLER("/echoall", &HandleEchoAll));
+ server->RegisterDefaultHandler(PREFIXED_HANDLER("/echo-raw", &HandleEchoRaw));
server->RegisterDefaultHandler(
PREFIXED_HANDLER("/set-cookie", &HandleSetCookie));
server->RegisterDefaultHandler(
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 51596b1ad5e..7f861d674c0 100644
--- a/chromium/net/test/embedded_test_server/embedded_test_server.cc
+++ b/chromium/net/test/embedded_test_server/embedded_test_server.cc
@@ -11,11 +11,11 @@
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/process/process_metrics.h"
#include "base/run_loop.h"
-#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_restrictions.h"
@@ -25,6 +25,7 @@
#include "net/base/net_errors.h"
#include "net/cert/pem_tokenizer.h"
#include "net/cert/test_root_certs.h"
+#include "net/log/net_log_source.h"
#include "net/socket/ssl_server_socket.h"
#include "net/socket/stream_socket.h"
#include "net/socket/tcp_server_socket.h"
@@ -52,6 +53,7 @@ EmbeddedTestServer::EmbeddedTestServer(Type type)
DCHECK(thread_checker_.CalledOnValidThread());
if (is_using_ssl_) {
+ base::ThreadRestrictions::ScopedAllowIO allow_io_for_importing_test_cert;
TestRootCerts* root_certs = TestRootCerts::GetInstance();
base::FilePath certs_dir(GetTestCertsDirectory());
root_certs->AddFromFile(certs_dir.AppendASCII("root_ca_cert.pem"));
@@ -64,6 +66,13 @@ EmbeddedTestServer::~EmbeddedTestServer() {
if (Started() && !ShutdownAndWaitUntilComplete()) {
LOG(ERROR) << "EmbeddedTestServer failed to shut down.";
}
+
+ {
+ // Thread::Join induced by test code should cause an assert.
+ base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join;
+
+ io_thread_.reset();
+ }
}
void EmbeddedTestServer::SetConnectionListener(
@@ -83,7 +92,7 @@ bool EmbeddedTestServer::Start() {
bool EmbeddedTestServer::InitializeAndListen() {
DCHECK(!Started());
- listen_socket_.reset(new TCPServerSocket(nullptr, NetLog::Source()));
+ listen_socket_.reset(new TCPServerSocket(nullptr, NetLogSource()));
int result = listen_socket_->ListenWithAddressAndPort("127.0.0.1", 0, 10);
if (result) {
@@ -118,6 +127,7 @@ bool EmbeddedTestServer::InitializeAndListen() {
}
void EmbeddedTestServer::InitializeSSLServerContext() {
+ base::ThreadRestrictions::ScopedAllowIO allow_io_for_ssl_initialization;
base::FilePath certs_dir(GetTestCertsDirectory());
std::string cert_name = GetCertificateName();
@@ -161,8 +171,6 @@ void EmbeddedTestServer::ShutdownOnIOThread() {
DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
weak_factory_.InvalidateWeakPtrs();
listen_socket_.reset();
- STLDeleteContainerPairSecondPointers(connections_.begin(),
- connections_.end());
connections_.clear();
}
@@ -258,6 +266,8 @@ std::string EmbeddedTestServer::GetCertificateName() const {
scoped_refptr<X509Certificate> EmbeddedTestServer::GetCertificate() const {
DCHECK(is_using_ssl_);
base::FilePath certs_dir(GetTestCertsDirectory());
+
+ base::ThreadRestrictions::ScopedAllowIO allow_io_for_importing_test_cert;
return ImportCertFromFile(certs_dir, GetCertificateName());
}
@@ -332,8 +342,6 @@ bool EmbeddedTestServer::FlushAllSocketsAndConnectionsOnUIThread() {
}
void EmbeddedTestServer::FlushAllSocketsAndConnections() {
- STLDeleteContainerPairSecondPointers(connections_.begin(),
- connections_.end());
connections_.clear();
}
@@ -359,10 +367,12 @@ void EmbeddedTestServer::HandleAcceptResult(
if (is_using_ssl_)
socket = DoSSLUpgrade(std::move(socket));
- HttpConnection* http_connection = new HttpConnection(
- std::move(socket),
- base::Bind(&EmbeddedTestServer::HandleRequest, base::Unretained(this)));
- connections_[http_connection->socket_.get()] = http_connection;
+ std::unique_ptr<HttpConnection> http_connection_ptr =
+ base::MakeUnique<HttpConnection>(
+ std::move(socket), base::Bind(&EmbeddedTestServer::HandleRequest,
+ base::Unretained(this)));
+ HttpConnection* http_connection = http_connection_ptr.get();
+ connections_[http_connection->socket_.get()] = std::move(http_connection_ptr);
if (is_using_ssl_) {
SSLServerSocket* ssl_socket =
@@ -418,18 +428,16 @@ void EmbeddedTestServer::DidClose(HttpConnection* connection) {
DCHECK_EQ(1u, connections_.count(connection->socket_.get()));
connections_.erase(connection->socket_.get());
- delete connection;
}
HttpConnection* EmbeddedTestServer::FindConnection(StreamSocket* socket) {
DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
- std::map<StreamSocket*, HttpConnection*>::iterator it =
- connections_.find(socket);
+ auto it = connections_.find(socket);
if (it == connections_.end()) {
- return NULL;
+ return nullptr;
}
- return it->second;
+ return it->second.get();
}
bool EmbeddedTestServer::PostTaskToIOThreadAndWait(
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 3b9e253b906..350253ffeaf 100644
--- a/chromium/net/test/embedded_test_server/embedded_test_server.h
+++ b/chromium/net/test/embedded_test_server/embedded_test_server.h
@@ -20,7 +20,6 @@
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "base/threading/thread_checker.h"
-#include "crypto/rsa_private_key.h"
#include "net/base/address_list.h"
#include "net/base/host_port_pair.h"
#include "net/base/ip_endpoint.h"
@@ -63,7 +62,7 @@ struct HttpRequest;
// return std::unique_ptr<HttpResponse>();
//
// std::unique_ptr<BasicHttpResponse> http_response(new BasicHttpResponse());
-// http_response->set_code(test_server::SUCCESS);
+// http_response->set_code(net::HTTP_OK);
// http_response->set_content("hello");
// http_response->set_content_type("text/plain");
// return http_response;
@@ -278,8 +277,7 @@ class EmbeddedTestServer {
GURL base_url_;
IPEndPoint local_endpoint_;
- // Owns the HttpConnection objects.
- std::map<StreamSocket*, HttpConnection*> connections_;
+ std::map<StreamSocket*, std::unique_ptr<HttpConnection>> connections_;
// Vector of registered and default request handlers and monitors.
std::vector<HandleRequestCallback> request_handlers_;
diff --git a/chromium/net/test/embedded_test_server/embedded_test_server_unittest.cc b/chromium/net/test/embedded_test_server/embedded_test_server_unittest.cc
index 1949ee366d8..31c66f4489c 100644
--- a/chromium/net/test/embedded_test_server/embedded_test_server_unittest.cc
+++ b/chromium/net/test/embedded_test_server/embedded_test_server_unittest.cc
@@ -18,6 +18,7 @@
#include "crypto/nss_util.h"
#include "net/base/test_completion_callback.h"
#include "net/http/http_response_headers.h"
+#include "net/log/net_log_source.h"
#include "net/log/test_net_log.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/stream_socket.h"
@@ -25,16 +26,20 @@
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "net/test/embedded_test_server/request_handler_util.h"
+#include "net/test/gtest_util.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(USE_NSS_CERTS)
#include "net/cert_net/nss_ocsp.h"
#endif
+using net::test::IsOk;
+
namespace net {
namespace test_server {
@@ -299,9 +304,9 @@ TEST_P(EmbeddedTestServerTest, ConnectionListenerAccept) {
std::unique_ptr<StreamSocket> socket =
ClientSocketFactory::GetDefaultFactory()->CreateTransportClientSocket(
- address_list, NULL, &net_log, NetLog::Source());
+ address_list, NULL, &net_log, NetLogSource());
TestCompletionCallback callback;
- ASSERT_EQ(OK, callback.GetResult(socket->Connect(callback.callback())));
+ ASSERT_THAT(callback.GetResult(socket->Connect(callback.callback())), IsOk());
connection_listener_.WaitUntilFirstConnectionAccepted();
@@ -385,8 +390,8 @@ class CancelRequestDelegate : public TestDelegate {
CancelRequestDelegate() {}
~CancelRequestDelegate() override {}
- void OnResponseStarted(URLRequest* request) override {
- TestDelegate::OnResponseStarted(request);
+ void OnResponseStarted(URLRequest* request, int net_error) override {
+ TestDelegate::OnResponseStarted(request, net_error);
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, run_loop_.QuitClosure(), base::TimeDelta::FromSeconds(1));
}
@@ -555,7 +560,7 @@ class EmbeddedTestServerThreadingTestDelegate
fetcher->SetRequestContext(
new TestURLRequestContextGetter(loop->task_runner()));
fetcher->Start();
- loop->Run();
+ base::RunLoop().Run();
fetcher.reset();
// Shut down.
diff --git a/chromium/net/test/embedded_test_server/request_handler_util.cc b/chromium/net/test/embedded_test_server/request_handler_util.cc
index b555578f2a0..8982efb8c0a 100644
--- a/chromium/net/test/embedded_test_server/request_handler_util.cc
+++ b/chromium/net/test/embedded_test_server/request_handler_util.cc
@@ -200,8 +200,7 @@ std::unique_ptr<HttpResponse> HandleFileRequest(
if (!base::ReadFileToString(headers_path, &headers_contents))
return nullptr;
- return base::WrapUnique(
- new RawHttpResponse(headers_contents, file_contents));
+ return base::MakeUnique<RawHttpResponse>(headers_contents, file_contents);
}
std::unique_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
diff --git a/chromium/net/test/gtest_util.h b/chromium/net/test/gtest_util.h
index 2769c34d588..22d82b0bfa9 100644
--- a/chromium/net/test/gtest_util.h
+++ b/chromium/net/test/gtest_util.h
@@ -8,6 +8,7 @@
#define NET_TEST_GTEST_UTIL_H_
#include "base/test/mock_log.h"
+#include "net/base/net_errors.h"
#include "net/test/scoped_disable_exit_on_dfatal.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -15,27 +16,44 @@
namespace net {
namespace test {
+// A GMock matcher that checks whether the argument is the expected net::Error.
+// On failure, the expected and actual net::Error names will be printed.
+// Usage: EXPECT_THAT(foo(), IsError(net::ERR_INVALID_ARGUMENT));
+MATCHER_P(IsError,
+ expected,
+ std::string(negation ? "not " : "") + net::ErrorToString(expected)) {
+ if (arg <= 0)
+ *result_listener << net::ErrorToString(arg);
+ return arg == expected;
+}
+
+// Shorthand for IsError(net::OK).
+// Usage: EXPECT_THAT(foo(), IsOk());
+MATCHER(IsOk,
+ std::string(negation ? "not " : "") + net::ErrorToString(net::OK)) {
+ if (arg <= 0)
+ *result_listener << net::ErrorToString(arg);
+ return arg == net::OK;
+}
+
// Internal implementation for the EXPECT_DFATAL and ASSERT_DFATAL
// macros. Do not use this directly.
-#define GTEST_DFATAL_(statement, matcher, fail) \
- GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (true) { \
- ::base::test::MockLog gtest_log; \
- ::net::test::ScopedDisableExitOnDFatal gtest_disable_exit; \
- using ::testing::_; \
- EXPECT_CALL(gtest_log, Log(_, _, _, _, _)) \
- .WillRepeatedly(::testing::Return(false)); \
- EXPECT_CALL(gtest_log, Log(logging::LOG_DFATAL, _, _, _, matcher)) \
- .Times(::testing::AtLeast(1)) \
- .WillOnce(::testing::Return(false)); \
- gtest_log.StartCapturingLogs(); \
- { statement; } \
- gtest_log.StopCapturingLogs(); \
- if (!testing::Mock::VerifyAndClear(&gtest_log)) { \
- goto GTEST_CONCAT_TOKEN_(gtest_label_dfatal_, __LINE__); \
- } \
- } else \
- GTEST_CONCAT_TOKEN_(gtest_label_dfatal_, __LINE__) : fail("")
+#define GTEST_DFATAL_(statement, severity, matcher, fail) \
+ do { \
+ ::base::test::MockLog gtest_log; \
+ ::net::test::ScopedDisableExitOnDFatal gtest_disable_exit; \
+ using ::testing::_; \
+ EXPECT_CALL(gtest_log, Log(_, _, _, _, _)) \
+ .WillRepeatedly(::testing::Return(false)); \
+ EXPECT_CALL(gtest_log, Log(::logging::LOG_##severity, _, _, _, matcher)) \
+ .Times(::testing::AtLeast(1)) \
+ .WillOnce(::testing::Return(false)); \
+ gtest_log.StartCapturingLogs(); \
+ { statement; } \
+ gtest_log.StopCapturingLogs(); \
+ if (!testing::Mock::VerifyAndClear(&gtest_log)) \
+ fail(""); \
+ } while (false)
// The EXPECT_DFATAL and ASSERT_DFATAL macros are lightweight
// alternatives to EXPECT_DEBUG_DEATH and ASSERT_DEBUG_DEATH. They
@@ -51,10 +69,10 @@ namespace test {
// DFATAL log message, whereas the other variants assume a regex.
#define EXPECT_DFATAL_WITH(statement, matcher) \
- GTEST_DFATAL_(statement, matcher, GTEST_NONFATAL_FAILURE_)
+ GTEST_DFATAL_(statement, DFATAL, matcher, GTEST_NONFATAL_FAILURE_)
#define ASSERT_DFATAL_WITH(statement, matcher) \
- GTEST_DFATAL_(statement, matcher, GTEST_FATAL_FAILURE_)
+ GTEST_DFATAL_(statement, DFATAL, matcher, GTEST_FATAL_FAILURE_)
#define EXPECT_DFATAL(statement, regex) \
EXPECT_DFATAL_WITH(statement, ::testing::ContainsRegex(regex))
@@ -76,22 +94,46 @@ namespace test {
#else // NDEBUG
#define EXPECT_DEBUG_DFATAL(statement, regex) \
- GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (true) { \
+ do { \
(void)(regex); \
statement; \
- } else \
- GTEST_NONFATAL_FAILURE_("")
+ } while (false)
#define ASSERT_DEBUG_DFATAL(statement, regex) \
- GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (true) { \
+ do { \
(void)(regex); \
statement; \
- } else \
- GTEST_NONFATAL_FAILURE_("")
+ } while (false)
#endif // NDEBUG
+// The EXPECT_DCHECK and ASSERT_DCHECK macros are similar to EXPECT_DFATAL and
+// ASSERT_DFATAL. Use them in conjunction with DCHECK that produces no-op in opt
+// build and LOG_DCHECK (FATAL) if DCHECK_IS_ON().
+
+#if DCHECK_IS_ON()
+
+#define EXPECT_DCHECK(statement, regex) \
+ GTEST_DFATAL_(statement, DCHECK, ::testing::ContainsRegex(regex), \
+ GTEST_NONFATAL_FAILURE_)
+#define ASSERT_DCHECK(statement, regex) \
+ GTEST_DFATAL_(statement, DCHECK, ::testing::ContainsRegex(regex), \
+ GTEST_FATAL_FAILURE_)
+
+#else // DCHECK_IS_ON()
+
+#define EXPECT_DCHECK(statement, regex) \
+ do { \
+ (void)(regex); \
+ statement; \
+ } while (false)
+#define ASSERT_DCHECK(statement, regex) \
+ do { \
+ (void)(regex); \
+ statement; \
+ } while (false)
+
+#endif // DCHECK_IS_ON()
+
} // namespace test
} // namespace net
diff --git a/chromium/net/test/net_test_suite.cc b/chromium/net/test/net_test_suite.cc
index 8b0942b9303..d6eba562ba7 100644
--- a/chromium/net/test/net_test_suite.cc
+++ b/chromium/net/test/net_test_suite.cc
@@ -14,12 +14,6 @@
#include "net/cert_net/nss_ocsp.h"
#endif
-class StaticReset : public ::testing::EmptyTestEventListener {
- void OnTestStart(const ::testing::TestInfo& test_info) override {
- net::HttpStreamFactory::ResetStaticSettingsToInit();
- }
-};
-
NetTestSuite::NetTestSuite(int argc, char** argv)
: TestSuite(argc, argv) {
}
@@ -28,7 +22,6 @@ NetTestSuite::~NetTestSuite() {}
void NetTestSuite::Initialize() {
TestSuite::Initialize();
- ::testing::UnitTest::GetInstance()->listeners().Append(new StaticReset());
InitializeTestThread();
}
diff --git a/chromium/net/test/python_utils.cc b/chromium/net/test/python_utils.cc
index 208e1b924fc..5eb4d0fac09 100644
--- a/chromium/net/test/python_utils.cc
+++ b/chromium/net/test/python_utils.cc
@@ -24,6 +24,11 @@
const char kPythonPathEnv[] = "PYTHONPATH";
+void ClearPythonPath() {
+ std::unique_ptr<base::Environment> env(base::Environment::Create());
+ env->UnSetVar(kPythonPathEnv);
+}
+
void AppendToPythonPath(const base::FilePath& dir) {
std::unique_ptr<base::Environment> env(base::Environment::Create());
std::string old_path;
diff --git a/chromium/net/test/python_utils.h b/chromium/net/test/python_utils.h
index ca06021b729..c72c9445dcb 100644
--- a/chromium/net/test/python_utils.h
+++ b/chromium/net/test/python_utils.h
@@ -15,6 +15,9 @@ class FilePath;
// This is the python path variable name.
extern const char kPythonPathEnv[];
+// Clears the python path, this is useful for test hermeticity.
+void ClearPythonPath();
+
// Appends the dir to python path environment variable.
void AppendToPythonPath(const base::FilePath& dir);
diff --git a/chromium/net/test/python_utils_unittest.cc b/chromium/net/test/python_utils_unittest.cc
index 48eb9737675..91f742ac83a 100644
--- a/chromium/net/test/python_utils_unittest.cc
+++ b/chromium/net/test/python_utils_unittest.cc
@@ -15,6 +15,15 @@
#include "base/strings/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"
+TEST(PythonUtils, Clear) {
+ std::unique_ptr<base::Environment> env(base::Environment::Create());
+ env->SetVar(kPythonPathEnv, "foo");
+ EXPECT_TRUE(env->HasVar(kPythonPathEnv));
+
+ ClearPythonPath();
+ EXPECT_FALSE(env->HasVar(kPythonPathEnv));
+}
+
TEST(PythonUtils, Append) {
const base::FilePath::CharType kAppendDir1[] =
FILE_PATH_LITERAL("test/path_append1");
diff --git a/chromium/net/test/run_all_unittests.cc b/chromium/net/test/run_all_unittests.cc
index 371b55a2431..15116aa9b69 100644
--- a/chromium/net/test/run_all_unittests.cc
+++ b/chromium/net/test/run_all_unittests.cc
@@ -15,14 +15,8 @@
#if defined(OS_ANDROID)
#include "base/android/jni_android.h"
#include "base/android/jni_registrar.h"
-#include "base/test/test_file_util.h"
-#include "base/test/test_ui_thread_android.h"
#include "net/android/dummy_spnego_authenticator.h"
#include "net/android/net_jni_registrar.h"
-#if BUILDFLAG(USE_PLATFORM_ICU_ALTERNATIVES)
-#include "url/android/url_jni_registrar.h" // nogncheck
-#endif
-
#endif
#if !defined(OS_ANDROID) && !defined(OS_IOS)
@@ -41,11 +35,6 @@ int main(int argc, char** argv) {
{"DummySpnegoAuthenticator",
net::android::DummySpnegoAuthenticator::RegisterJni},
{"NetAndroid", net::android::RegisterJni},
- {"TestFileUtil", base::RegisterContentUriTestUtils},
- {"TestUiThreadAndroid", base::RegisterTestUiThreadAndroid},
-#if BUILDFLAG(USE_PLATFORM_ICU_ALTERNATIVES)
- {"UrlAndroid", url::android::RegisterJni},
-#endif
};
// Register JNI bindings for android. Doing it early as the test suite setup
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 bb4427ac451..87838c10a06 100644
--- a/chromium/net/test/spawned_test_server/base_test_server.cc
+++ b/chromium/net/test/spawned_test_server/base_test_server.cc
@@ -24,7 +24,7 @@
#include "net/cert/test_root_certs.h"
#include "net/cert/x509_certificate.h"
#include "net/dns/host_resolver.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "url/gurl.h"
namespace net {
@@ -123,11 +123,53 @@ std::unique_ptr<base::ListValue> GetTokenBindingParams(
return values;
}
+std::string OCSPStatusToString(
+ const BaseTestServer::SSLOptions::OCSPStatus& ocsp_status) {
+ switch (ocsp_status) {
+ case BaseTestServer::SSLOptions::OCSP_OK:
+ return "ok";
+ case BaseTestServer::SSLOptions::OCSP_REVOKED:
+ return "revoked";
+ case BaseTestServer::SSLOptions::OCSP_INVALID_RESPONSE:
+ return "invalid";
+ case BaseTestServer::SSLOptions::OCSP_UNAUTHORIZED:
+ return "unauthorized";
+ case BaseTestServer::SSLOptions::OCSP_UNKNOWN:
+ return "unknown";
+ case BaseTestServer::SSLOptions::OCSP_TRY_LATER:
+ return "later";
+ case BaseTestServer::SSLOptions::OCSP_INVALID_RESPONSE_DATA:
+ return "invalid_data";
+ case BaseTestServer::SSLOptions::OCSP_MISMATCHED_SERIAL:
+ return "mismatched_serial";
+ }
+ NOTREACHED();
+ return std::string();
+}
+
+std::string OCSPDateToString(
+ const BaseTestServer::SSLOptions::OCSPDate& ocsp_date) {
+ switch (ocsp_date) {
+ case BaseTestServer::SSLOptions::OCSP_DATE_VALID:
+ return "valid";
+ case BaseTestServer::SSLOptions::OCSP_DATE_OLD:
+ return "old";
+ case BaseTestServer::SSLOptions::OCSP_DATE_EARLY:
+ return "early";
+ case BaseTestServer::SSLOptions::OCSP_DATE_LONG:
+ return "long";
+ }
+ NOTREACHED();
+ return std::string();
+}
+
} // namespace
BaseTestServer::SSLOptions::SSLOptions()
: server_certificate(CERT_OK),
ocsp_status(OCSP_OK),
+ ocsp_date(OCSP_DATE_VALID),
+ ocsp_produced(OCSP_PRODUCED_VALID),
cert_serial(0),
request_client_certificate(false),
key_exchanges(SSLOptions::KEY_EXCHANGE_ANY),
@@ -146,6 +188,8 @@ BaseTestServer::SSLOptions::SSLOptions(
BaseTestServer::SSLOptions::ServerCertificate cert)
: server_certificate(cert),
ocsp_status(OCSP_OK),
+ ocsp_date(OCSP_DATE_VALID),
+ ocsp_produced(OCSP_PRODUCED_VALID),
cert_serial(0),
request_client_certificate(false),
key_exchanges(SSLOptions::KEY_EXCHANGE_ANY),
@@ -191,17 +235,48 @@ std::string BaseTestServer::SSLOptions::GetOCSPArgument() const {
if (server_certificate != CERT_AUTO)
return std::string();
- switch (ocsp_status) {
- case OCSP_OK:
- return "ok";
- case OCSP_REVOKED:
- return "revoked";
- case OCSP_INVALID:
- return "invalid";
- case OCSP_UNAUTHORIZED:
- return "unauthorized";
- case OCSP_UNKNOWN:
- return "unknown";
+ // |ocsp_responses| overrides when it is non-empty.
+ if (!ocsp_responses.empty()) {
+ std::string arg;
+ for (size_t i = 0; i < ocsp_responses.size(); i++) {
+ if (i != 0)
+ arg += ":";
+ arg += OCSPStatusToString(ocsp_responses[i].status);
+ }
+ return arg;
+ }
+
+ return OCSPStatusToString(ocsp_status);
+}
+
+std::string BaseTestServer::SSLOptions::GetOCSPDateArgument() const {
+ if (server_certificate != CERT_AUTO)
+ return std::string();
+
+ if (!ocsp_responses.empty()) {
+ std::string arg;
+ for (size_t i = 0; i < ocsp_responses.size(); i++) {
+ if (i != 0)
+ arg += ":";
+ arg += OCSPDateToString(ocsp_responses[i].date);
+ }
+ return arg;
+ }
+
+ return OCSPDateToString(ocsp_date);
+}
+
+std::string BaseTestServer::SSLOptions::GetOCSPProducedArgument() const {
+ if (server_certificate != CERT_AUTO)
+ return std::string();
+
+ switch (ocsp_produced) {
+ case OCSP_PRODUCED_VALID:
+ return "valid";
+ case OCSP_PRODUCED_BEFORE_CERT:
+ return "before";
+ case OCSP_PRODUCED_AFTER_CERT:
+ return "after";
default:
NOTREACHED();
return std::string();
@@ -277,12 +352,9 @@ bool BaseTestServer::GetAddressList(AddressList* address_list) const {
// IPv6 literal hostnames.
info.set_address_family(ADDRESS_FAMILY_IPV4);
TestCompletionCallback callback;
- int rv = resolver->Resolve(info,
- DEFAULT_PRIORITY,
- address_list,
- callback.callback(),
- NULL,
- BoundNetLog());
+ std::unique_ptr<HostResolver::Request> request;
+ int rv = resolver->Resolve(info, DEFAULT_PRIORITY, address_list,
+ callback.callback(), &request, NetLogWithSource());
if (rv == ERR_IO_PENDING)
rv = callback.WaitForResult();
if (rv != OK) {
@@ -524,6 +596,14 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const {
if (!ocsp_arg.empty())
arguments->SetString("ocsp", ocsp_arg);
+ std::string ocsp_date_arg = ssl_options_.GetOCSPDateArgument();
+ if (!ocsp_date_arg.empty())
+ arguments->SetString("ocsp-date", ocsp_date_arg);
+
+ std::string ocsp_produced_arg = ssl_options_.GetOCSPProducedArgument();
+ if (!ocsp_produced_arg.empty())
+ arguments->SetString("ocsp-produced", ocsp_produced_arg);
+
if (ssl_options_.cert_serial != 0) {
arguments->SetInteger("cert-serial", ssl_options_.cert_serial);
}
@@ -559,6 +639,13 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const {
arguments->Set("ocsp-server-unavailable",
base::Value::CreateNullValue());
}
+ if (!ssl_options_.alpn_protocols.empty()) {
+ std::unique_ptr<base::ListValue> alpn_protocols(new base::ListValue());
+ for (const std::string& proto : ssl_options_.alpn_protocols) {
+ alpn_protocols->AppendString(proto);
+ }
+ arguments->Set("alpn-protocols", std::move(alpn_protocols));
+ }
if (!ssl_options_.npn_protocols.empty()) {
std::unique_ptr<base::ListValue> npn_protocols(new base::ListValue());
for (const std::string& proto : ssl_options_.npn_protocols) {
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 48568010f65..24a119b6447 100644
--- a/chromium/net/test/spawned_test_server/base_test_server.h
+++ b/chromium/net/test/spawned_test_server/base_test_server.h
@@ -81,9 +81,37 @@ class BaseTestServer {
enum OCSPStatus {
OCSP_OK,
OCSP_REVOKED,
- OCSP_INVALID,
+ OCSP_INVALID_RESPONSE,
OCSP_UNAUTHORIZED,
OCSP_UNKNOWN,
+ OCSP_INVALID_RESPONSE_DATA,
+ OCSP_TRY_LATER,
+ OCSP_MISMATCHED_SERIAL,
+ };
+
+ // OCSPDate enumerates the date ranges for OCSP responses that the
+ // testserver can produce.
+ enum OCSPDate {
+ OCSP_DATE_VALID,
+ OCSP_DATE_OLD,
+ OCSP_DATE_EARLY,
+ OCSP_DATE_LONG,
+ };
+
+ // OCSPSingleResponse is used when specifying multiple stapled responses,
+ // each
+ // with their own CertStatus and date validity.
+ struct OCSPSingleResponse {
+ OCSPStatus status;
+ OCSPDate date;
+ };
+
+ // OCSPProduced enumerates the validity of the producedAt field in OCSP
+ // responses produced by the testserver.
+ enum OCSPProduced {
+ OCSP_PRODUCED_VALID,
+ OCSP_PRODUCED_BEFORE_CERT,
+ OCSP_PRODUCED_AFTER_CERT,
};
// Bitmask of key exchange algorithms that the test server supports and that
@@ -151,13 +179,35 @@ class BaseTestServer {
// the empty string if there is none.
std::string GetOCSPArgument() const;
+ // GetOCSPDateArgument returns the value of the OCSP date argument to
+ // testserver or the empty string if there is none.
+ std::string GetOCSPDateArgument() const;
+
+ // GetOCSPProducedArgument returns the value of the OCSP produced argument
+ // to testserver or the empty string if there is none.
+ std::string GetOCSPProducedArgument() const;
+
// The certificate to use when serving requests.
ServerCertificate server_certificate;
// If |server_certificate==CERT_AUTO| then this determines the type of OCSP
- // response returned.
+ // response returned. Ignored if |ocsp_responses| is non-empty.
OCSPStatus ocsp_status;
+ // If |server_certificate==CERT_AUTO| then this determines the date range
+ // set on the OCSP response returned. Ignore if |ocsp_responses| is
+ // non-empty.
+ OCSPDate ocsp_date;
+
+ // If |server_certificate==CERT_AUTO|, contains the status and validity for
+ // multiple stapled responeses. Overrides |ocsp_status| and |ocsp_date| when
+ // non-empty.
+ std::vector<OCSPSingleResponse> ocsp_responses;
+
+ // If |server_certificate==CERT_AUTO| then this determines the validity of
+ // the producedAt field on the returned OCSP response.
+ OCSPProduced ocsp_produced;
+
// If not zero, |cert_serial| will be the serial number of the
// auto-generated leaf certificate when |server_certificate==CERT_AUTO|.
uint64_t cert_serial;
@@ -227,6 +277,9 @@ class BaseTestServer {
// test server will continue to speak HTTP/1.1.
std::vector<std::string> npn_protocols;
+ // List of supported ALPN protocols.
+ std::vector<std::string> alpn_protocols;
+
// Whether to send a fatal alert immediately after completing the handshake.
bool alert_after_handshake;
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 77630b175ae..30211667249 100644
--- a/chromium/net/test/spawned_test_server/local_test_server.cc
+++ b/chromium/net/test/spawned_test_server/local_test_server.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
+#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "net/base/host_port_pair.h"
#include "net/base/net_errors.h"
@@ -94,6 +95,8 @@ bool LocalTestServer::Start() {
}
bool LocalTestServer::StartInBackground() {
+ base::ThreadRestrictions::ScopedAllowIO allow_io_from_test_code;
+
// Get path to Python server script.
base::FilePath testserver_path;
if (!GetTestServerPath(&testserver_path))
@@ -159,6 +162,8 @@ bool LocalTestServer::Init(const base::FilePath& document_root) {
}
bool LocalTestServer::SetPythonPath() const {
+ ClearPythonPath();
+
base::FilePath third_party_dir;
if (!PathService::Get(base::DIR_SOURCE_ROOT, &third_party_dir)) {
LOG(ERROR) << "Failed to get DIR_SOURCE_ROOT";
diff --git a/chromium/net/test/spawned_test_server/local_test_server_win.cc b/chromium/net/test/spawned_test_server/local_test_server_win.cc
index 3e87e997b84..6f325e064c0 100644
--- a/chromium/net/test/spawned_test_server/local_test_server_win.cc
+++ b/chromium/net/test/spawned_test_server/local_test_server_win.cc
@@ -13,6 +13,7 @@
#include "base/files/file_path.h"
#include "base/message_loop/message_loop.h"
#include "base/process/launch.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -51,7 +52,7 @@ bool ReadData(HANDLE read_fd,
// Prepare a timeout in case the server fails to start.
bool unblocked = false;
- thread.message_loop()->PostDelayedTask(
+ thread.task_runner()->PostDelayedTask(
FROM_HERE, base::Bind(UnblockPipe, write_fd, bytes_max, &unblocked),
TestTimeouts::action_max_timeout());
diff --git a/chromium/net/test/spawned_test_server/spawner_communicator.cc b/chromium/net/test/spawned_test_server/spawner_communicator.cc
index 05865d94efc..3a1566db4cf 100644
--- a/chromium/net/test/spawned_test_server/spawner_communicator.cc
+++ b/chromium/net/test/spawned_test_server/spawner_communicator.cc
@@ -162,9 +162,11 @@ void SpawnerCommunicator::SendCommandAndWaitForResult(
// Since the method will be blocked until SpawnerCommunicator gets result
// from the spawner server or timed-out. It's safe to use base::Unretained
// when using base::Bind.
- io_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
- &SpawnerCommunicator::SendCommandAndWaitForResultOnIOThread,
- base::Unretained(this), command, post_data, result_code, data_received));
+ io_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&SpawnerCommunicator::SendCommandAndWaitForResultOnIOThread,
+ base::Unretained(this), command, post_data, result_code,
+ data_received));
WaitForResponse();
}
@@ -226,12 +228,14 @@ void SpawnerCommunicator::OnTimeout(int id) {
if (!data->DoesRequestIdMatch(id))
return;
// Set the result code and cancel the timed-out task.
- data->SetResultCode(ERR_TIMED_OUT);
- cur_request_->Cancel();
- OnSpawnerCommandCompleted(cur_request_.get());
+ int result = cur_request_->CancelWithError(ERR_TIMED_OUT);
+ OnSpawnerCommandCompleted(cur_request_.get(), result);
}
-void SpawnerCommunicator::OnSpawnerCommandCompleted(URLRequest* request) {
+void SpawnerCommunicator::OnSpawnerCommandCompleted(URLRequest* request,
+ int net_error) {
+ DCHECK_NE(ERR_IO_PENDING, net_error);
+
if (!cur_request_.get())
return;
DCHECK_EQ(request, cur_request_.get());
@@ -240,13 +244,11 @@ void SpawnerCommunicator::OnSpawnerCommandCompleted(URLRequest* request) {
DCHECK(data);
// If request is faild,return the error code.
- if (!cur_request_->status().is_success())
- data->SetResultCode(cur_request_->status().error());
+ if (net_error != OK)
+ data->SetResultCode(net_error);
if (!data->IsResultOK()) {
- LOG(ERROR) << "request failed, status: "
- << static_cast<int>(request->status().status())
- << ", error: " << request->status().error();
+ LOG(ERROR) << "request failed, error: " << net_error;
// Clear the buffer of received data if any net error happened.
data->ClearReceivedData();
} else {
@@ -273,30 +275,35 @@ void SpawnerCommunicator::ReadResult(URLRequest* request) {
IOBuffer* buf = data->buf();
// Read as many bytes as are available synchronously.
while (true) {
- int num_bytes;
- if (!request->Read(buf, kBufferSize, &num_bytes)) {
- // Check whether the read failed synchronously.
- if (!request->status().is_io_pending())
- OnSpawnerCommandCompleted(request);
+ int rv = request->Read(buf, kBufferSize);
+ if (rv == ERR_IO_PENDING)
+ return;
+
+ if (rv < 0) {
+ OnSpawnerCommandCompleted(request, rv);
return;
}
- if (!data->ConsumeBytesRead(num_bytes)) {
- OnSpawnerCommandCompleted(request);
+
+ if (!data->ConsumeBytesRead(rv)) {
+ OnSpawnerCommandCompleted(request, rv);
return;
}
}
}
-void SpawnerCommunicator::OnResponseStarted(URLRequest* request) {
+void SpawnerCommunicator::OnResponseStarted(URLRequest* request,
+ int net_error) {
DCHECK_EQ(request, cur_request_.get());
+ DCHECK_NE(ERR_IO_PENDING, net_error);
+
SpawnerRequestData* data =
static_cast<SpawnerRequestData*>(cur_request_->GetUserData(this));
DCHECK(data);
data->IncreaseResponseStartedCount();
- if (!request->status().is_success()) {
- OnSpawnerCommandCompleted(request);
+ if (net_error != OK) {
+ OnSpawnerCommandCompleted(request, net_error);
return;
}
@@ -306,7 +313,7 @@ void SpawnerCommunicator::OnResponseStarted(URLRequest* request) {
<< request->response_headers()->GetStatusLine();
data->SetResultCode(ERR_FAILED);
request->Cancel();
- OnSpawnerCommandCompleted(request);
+ OnSpawnerCommandCompleted(request, ERR_ABORTED);
return;
}
@@ -314,6 +321,8 @@ void SpawnerCommunicator::OnResponseStarted(URLRequest* request) {
}
void SpawnerCommunicator::OnReadCompleted(URLRequest* request, int num_bytes) {
+ DCHECK_NE(ERR_IO_PENDING, num_bytes);
+
if (!cur_request_.get())
return;
DCHECK_EQ(request, cur_request_.get());
@@ -325,7 +334,9 @@ void SpawnerCommunicator::OnReadCompleted(URLRequest* request, int num_bytes) {
// Keep reading.
ReadResult(request);
} else {
- OnSpawnerCommandCompleted(request);
+ // |bytes_read| < 0
+ int net_error = num_bytes;
+ OnSpawnerCommandCompleted(request, net_error);
}
}
diff --git a/chromium/net/test/spawned_test_server/spawner_communicator.h b/chromium/net/test/spawned_test_server/spawner_communicator.h
index 445278257ab..e70b6eadb24 100644
--- a/chromium/net/test/spawned_test_server/spawner_communicator.h
+++ b/chromium/net/test/spawned_test_server/spawner_communicator.h
@@ -102,14 +102,14 @@ class SpawnerCommunicator : public URLRequest::Delegate {
std::string* data_received);
// URLRequest::Delegate methods. Called on the IO thread.
- void OnResponseStarted(URLRequest* request) override;
+ void OnResponseStarted(URLRequest* request, int net_error) override;
void OnReadCompleted(URLRequest* request, int num_bytes) override;
// Reads Result from the response. Called on the IO thread.
void ReadResult(URLRequest* request);
// Called on the IO thread upon completion of the spawner command.
- void OnSpawnerCommandCompleted(URLRequest* request);
+ void OnSpawnerCommandCompleted(URLRequest* request, int net_error);
// Callback on the IO thread for time-out task of request with id |id|.
void OnTimeout(int id);
diff --git a/chromium/net/test/test_data_directory.cc b/chromium/net/test/test_data_directory.cc
index aad3d07f243..b35392407bb 100644
--- a/chromium/net/test/test_data_directory.cc
+++ b/chromium/net/test/test_data_directory.cc
@@ -6,6 +6,7 @@
#include "base/base_paths.h"
#include "base/path_service.h"
+#include "base/threading/thread_restrictions.h"
namespace net {
@@ -16,7 +17,11 @@ const base::FilePath::CharType kCertificateRelativePath[] =
base::FilePath GetTestCertsDirectory() {
base::FilePath src_root;
- PathService::Get(base::DIR_SOURCE_ROOT, &src_root);
+ {
+ base::ThreadRestrictions::ScopedAllowIO allow_io_for_path_service;
+ PathService::Get(base::DIR_SOURCE_ROOT, &src_root);
+ }
+
return src_root.Append(kCertificateRelativePath);
}
diff --git a/chromium/net/test/url_request/url_request_hanging_read_job.cc b/chromium/net/test/url_request/url_request_hanging_read_job.cc
index 09a4c5c71b7..74c680f2418 100644
--- a/chromium/net/test/url_request/url_request_hanging_read_job.cc
+++ b/chromium/net/test/url_request/url_request_hanging_read_job.cc
@@ -101,9 +101,9 @@ void URLRequestHangingReadJob::AddUrlHandler() {
// Add |hostname| to URLRequestFilter for HTTP and HTTPS.
URLRequestFilter* filter = URLRequestFilter::GetInstance();
filter->AddHostnameInterceptor("http", kMockHostname,
- base::WrapUnique(new MockJobInterceptor()));
+ base::MakeUnique<MockJobInterceptor>());
filter->AddHostnameInterceptor("https", kMockHostname,
- base::WrapUnique(new MockJobInterceptor()));
+ base::MakeUnique<MockJobInterceptor>());
}
// static
diff --git a/chromium/net/test/url_request/url_request_hanging_read_job.h b/chromium/net/test/url_request/url_request_hanging_read_job.h
index 5e335bb333b..62213f29262 100644
--- a/chromium/net/test/url_request/url_request_hanging_read_job.h
+++ b/chromium/net/test/url_request/url_request_hanging_read_job.h
@@ -7,7 +7,6 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "net/base/net_export.h"
#include "net/url_request/url_request_job.h"
namespace net {
diff --git a/chromium/net/test/url_request/url_request_mock_data_job.cc b/chromium/net/test/url_request/url_request_mock_data_job.cc
index 8f2378b338c..8b67a984a53 100644
--- a/chromium/net/test/url_request/url_request_mock_data_job.cc
+++ b/chromium/net/test/url_request/url_request_mock_data_job.cc
@@ -183,9 +183,9 @@ void URLRequestMockDataJob::AddUrlHandlerForHostname(
// Add |hostname| to URLRequestFilter for HTTP and HTTPS.
URLRequestFilter* filter = URLRequestFilter::GetInstance();
filter->AddHostnameInterceptor("http", hostname,
- base::WrapUnique(new MockJobInterceptor()));
+ base::MakeUnique<MockJobInterceptor>());
filter->AddHostnameInterceptor("https", hostname,
- base::WrapUnique(new MockJobInterceptor()));
+ base::MakeUnique<MockJobInterceptor>());
}
// static
diff --git a/chromium/net/test/url_request/url_request_mock_data_job.h b/chromium/net/test/url_request/url_request_mock_data_job.h
index ae33dd7dadb..27f3a0953f0 100644
--- a/chromium/net/test/url_request/url_request_mock_data_job.h
+++ b/chromium/net/test/url_request/url_request_mock_data_job.h
@@ -10,7 +10,6 @@
#include <string>
#include "base/memory/weak_ptr.h"
-#include "net/base/net_export.h"
#include "net/url_request/url_request_job.h"
namespace net {
diff --git a/chromium/net/third_party/nss/README.chromium b/chromium/net/third_party/nss/README.chromium
index 2cf7c1bf64d..68395c729e2 100644
--- a/chromium/net/third_party/nss/README.chromium
+++ b/chromium/net/third_party/nss/README.chromium
@@ -5,7 +5,12 @@ Security Critical: Yes
License: MPL 2
License File: LICENSE
-This directory includes a file from NSS's libssl from the hg repo at:
+This directory includes a file derived from NSS's libssl, from the hg repo at:
https://hg.mozilla.org/projects/nss
The snapshot was updated to the hg tag: NSS_3_23_RTM
+
+Local Modifications:
+Files are forked from Mozilla's because of the heavy adaptations necessary.
+Differences are using Chromium libraries instead of Mozilla's, matching the
+Chromium style, and returning the certificate chain built.
diff --git a/chromium/net/third_party/nss/ssl/cmpcert.c b/chromium/net/third_party/nss/ssl/cmpcert.c
deleted file mode 100644
index e6edbee83e1..00000000000
--- a/chromium/net/third_party/nss/ssl/cmpcert.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * NSS utility functions
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <stdio.h>
-#include <string.h>
-#include "prerror.h"
-#include "secitem.h"
-#include "prnetdb.h"
-#include "cert.h"
-#include "nspr.h"
-#include "secder.h"
-#include "key.h"
-#include "nss.h"
-
-/*
- * Look to see if any of the signers in the cert chain for "cert" are found
- * in the list of caNames.
- * Returns SECSuccess if so, SECFailure if not.
- */
-SECStatus
-NSS_CmpCertChainWCANames(CERTCertificate *cert, CERTDistNames *caNames)
-{
- SECItem *caname;
- CERTCertificate *curcert;
- CERTCertificate *oldcert;
- PRInt32 contentlen;
- int j;
- int headerlen;
- int depth;
- SECStatus rv;
- SECItem issuerName;
- SECItem compatIssuerName;
-
- if (!cert || !caNames || !caNames->nnames || !caNames->names ||
- !caNames->names->data)
- return SECFailure;
- depth = 0;
- curcert = CERT_DupCertificate(cert);
-
- while (curcert) {
- issuerName = curcert->derIssuer;
-
- /* compute an alternate issuer name for compatibility with 2.0
- * enterprise server, which send the CA names without
- * the outer layer of DER header
- */
- rv = DER_Lengths(&issuerName, &headerlen, (PRUint32 *)&contentlen);
- if (rv == SECSuccess) {
- compatIssuerName.data = &issuerName.data[headerlen];
- compatIssuerName.len = issuerName.len - headerlen;
- } else {
- compatIssuerName.data = NULL;
- compatIssuerName.len = 0;
- }
-
- for (j = 0; j < caNames->nnames; j++) {
- caname = &caNames->names[j];
- if (SECITEM_CompareItem(&issuerName, caname) == SECEqual) {
- rv = SECSuccess;
- CERT_DestroyCertificate(curcert);
- goto done;
- } else if (SECITEM_CompareItem(&compatIssuerName, caname) == SECEqual) {
- rv = SECSuccess;
- CERT_DestroyCertificate(curcert);
- goto done;
- }
- }
- if ((depth <= 20) &&
- (SECITEM_CompareItem(&curcert->derIssuer, &curcert->derSubject) !=
- SECEqual)) {
- oldcert = curcert;
- curcert = CERT_FindCertByName(curcert->dbhandle,
- &curcert->derIssuer);
- CERT_DestroyCertificate(oldcert);
- depth++;
- } else {
- CERT_DestroyCertificate(curcert);
- curcert = NULL;
- }
- }
- rv = SECFailure;
-
-done:
- return rv;
-}
diff --git a/chromium/net/third_party/nss/ssl/cmpcert.cc b/chromium/net/third_party/nss/ssl/cmpcert.cc
new file mode 100644
index 00000000000..ebc8745a8df
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/cmpcert.cc
@@ -0,0 +1,58 @@
+/*
+ * NSS utility functions
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "net/third_party/nss/ssl/cmpcert.h"
+
+#include <secder.h>
+#include <secitem.h>
+
+#include "base/strings/string_piece.h"
+
+namespace net {
+
+bool MatchClientCertificateIssuers(
+ CERTCertificate* cert,
+ const std::vector<std::string>& cert_authorities,
+ std::vector<ScopedCERTCertificate>* intermediates) {
+ // Bound how many iterations to try.
+ static const int kMaxDepth = 20;
+
+ intermediates->clear();
+
+ // If no authorities are supplied, everything matches.
+ if (cert_authorities.empty())
+ return true;
+
+ CERTCertificate* curcert = cert;
+ while (intermediates->size() < kMaxDepth) {
+ base::StringPiece issuer(
+ reinterpret_cast<const char*>(curcert->derIssuer.data),
+ curcert->derIssuer.len);
+
+ // Check if |curcert| is signed by a valid CA.
+ for (const std::string& ca : cert_authorities) {
+ if (issuer == ca)
+ return true;
+ }
+
+ // Stop at self-issued certificates.
+ if (SECITEM_CompareItem(&curcert->derIssuer, &curcert->derSubject) ==
+ SECEqual) {
+ return false;
+ }
+
+ // Look the parent up in the database and keep searching.
+ curcert = CERT_FindCertByName(curcert->dbhandle, &curcert->derIssuer);
+ if (!curcert)
+ return false;
+ intermediates->emplace_back(curcert);
+ }
+
+ return false;
+}
+
+} // namespace net
diff --git a/chromium/net/third_party/nss/ssl/cmpcert.h b/chromium/net/third_party/nss/ssl/cmpcert.h
new file mode 100644
index 00000000000..d6bc2fb3056
--- /dev/null
+++ b/chromium/net/third_party/nss/ssl/cmpcert.h
@@ -0,0 +1,30 @@
+/*
+ * NSS utility functions
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef NET_THIRD_PARTY_NSS_SSL_CMPCERT_H_
+#define NET_THIRD_PARTY_NSS_SSL_CMPCERT_H_
+
+#include <cert.h>
+
+#include <string>
+#include <vector>
+
+#include "net/cert/scoped_nss_types.h"
+
+namespace net {
+
+// Checks if |cert| matches |cert_authorities|. If so, it sets |*intermediates|
+// to a list of intermediates to send and returns true. Otherwise, it returns
+// false.
+bool MatchClientCertificateIssuers(
+ CERTCertificate* cert,
+ const std::vector<std::string>& cert_authorities,
+ std::vector<ScopedCERTCertificate>* intermediates);
+
+} // namespace net
+
+#endif // NET_THIRD_PARTY_NSS_SSL_CMPCERT_H_
diff --git a/chromium/net/tools/DEPS b/chromium/net/tools/DEPS
index 4648a84aacb..3b22d6845ab 100644
--- a/chromium/net/tools/DEPS
+++ b/chromium/net/tools/DEPS
@@ -4,5 +4,4 @@ include_rules = [
skip_child_includes = [
"balsa",
- "flip_server",
]
diff --git a/chromium/net/tools/balsa/balsa_headers.cc b/chromium/net/tools/balsa/balsa_headers.cc
index 0ad88c5261b..abac006b479 100644
--- a/chromium/net/tools/balsa/balsa_headers.cc
+++ b/chromium/net/tools/balsa/balsa_headers.cc
@@ -770,6 +770,12 @@ void BalsaHeaders::DumpToString(std::string* str) const {
DumpHeadersToString(str);
}
+std::string BalsaHeaders::DebugString() const {
+ std::string s;
+ DumpToString(&s);
+ return s;
+}
+
void BalsaHeaders::DumpHeadersToString(std::string* str) const {
const base::StringPiece firstline = first_line();
// If the header is complete, then just dump them with the logical key value
diff --git a/chromium/net/tools/balsa/balsa_headers.h b/chromium/net/tools/balsa/balsa_headers.h
index a67e7435133..d796e9a86ac 100644
--- a/chromium/net/tools/balsa/balsa_headers.h
+++ b/chromium/net/tools/balsa/balsa_headers.h
@@ -828,6 +828,7 @@ class BalsaHeaders {
// object is not completely parsed, e.g., when there was an error in the
// middle of parsing.
void DumpToString(std::string* str) const;
+ std::string DebugString() const;
const base::StringPiece first_line() const {
DCHECK_GE(whitespace_4_idx_, non_whitespace_1_idx_);
diff --git a/chromium/net/tools/balsa/balsa_headers_token_utils.cc b/chromium/net/tools/balsa/balsa_headers_token_utils.cc
index c5dfeea3334..acf226fb224 100644
--- a/chromium/net/tools/balsa/balsa_headers_token_utils.cc
+++ b/chromium/net/tools/balsa/balsa_headers_token_utils.cc
@@ -96,7 +96,7 @@ void BalsaHeadersTokenUtils::TokenizeHeaderValue(
CHECK(tokens);
tokens->clear();
- // We may have more then 1 line with the same header key. Tokenize them all
+ // We may have more than 1 line with the same header key. Tokenize them all
// and stick all the tokens into the same list.
for (BalsaHeaders::const_header_lines_key_iterator header_line =
headers.GetIteratorForKey(key);
diff --git a/chromium/net/tools/cachetool/cachetool.cc b/chromium/net/tools/cachetool/cachetool.cc
index fde1ffce112..c5ac94fd314 100644
--- a/chromium/net/tools/cachetool/cachetool.cc
+++ b/chromium/net/tools/cachetool/cachetool.cc
@@ -9,6 +9,7 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
@@ -24,48 +25,295 @@ using disk_cache::Entry;
namespace {
-int kResponseInfoIndex = 0;
+constexpr int kResponseInfoIndex = 0;
-// Get the cache's size.
-bool GetSize(Backend* cache_backend) {
+const char* const kCommandNames[] = {
+ "stop", "get_size", "list_keys", "get_stream_for_key",
+ "delete_stream", "delete_key", "update_raw_headers",
+};
+
+// Prints the command line help.
+void PrintHelp() {
+ std::cout << "cachetool <cache_path> <cache_backend_type> <subcommand> "
+ << std::endl
+ << std::endl;
+ std::cout << "Available cache backend types: simple, blockfile" << std::endl;
+ std::cout << "Available subcommands:" << std::endl;
+ std::cout << " batch: Starts cachetool to process serialized commands "
+ << "passed down by the standard input and return commands output "
+ << "in the stdout until the stop command is received." << std::endl;
+ std::cout << " delete_key <key>: Delete key from cache." << std::endl;
+ std::cout << " delete_stream <key> <index>: Delete a particular stream of a"
+ << " given key." << std::endl;
+ std::cout << " get_size: Calculate the total size of the cache in bytes."
+ << std::endl;
+ std::cout << " get_stream <key> <index>: Print a particular stream for a"
+ << " given key." << std::endl;
+ std::cout << " list_keys: List all keys in the cache." << std::endl;
+ std::cout << " update_raw_headers <key>: Update stdin as the key's raw "
+ << "response headers." << std::endl;
+ std::cout << " stop: Verify that the cache can be opened and return, "
+ << "confirming the cache exists and is of the right type."
+ << std::endl;
+ std::cout << "Expected values of <index> are:" << std::endl;
+ std::cout << " 0 (HTTP response headers)" << std::endl;
+ std::cout << " 1 (transport encoded content)" << std::endl;
+ std::cout << " 2 (compiled content)" << std::endl;
+}
+
+// Generic command input/output.
+class CommandMarshal {
+ public:
+ CommandMarshal(Backend* cache_backend)
+ : command_failed_(false), cache_backend_(cache_backend){};
+ virtual ~CommandMarshal(){};
+
+ // Reads the next command's name to execute.
+ virtual std::string ReadCommandName() = 0;
+
+ // Reads the next parameter as an integer.
+ virtual int ReadInt() = 0;
+
+ // Reads the next parameter as stream index.
+ int ReadStreamIndex() {
+ if (has_failed())
+ return -1;
+ int index = ReadInt();
+ if (index < 0 || index > 2) {
+ ReturnFailure("Invalid stream index.");
+ return -1;
+ }
+ return index;
+ }
+
+ // Reads the next parameter as an string.
+ virtual std::string ReadString() = 0;
+
+ // Reads the next parameter from stdin as string.
+ virtual std::string ReadBufferedString() = 0;
+
+ // Communicates back an integer.
+ virtual void ReturnInt(int integer) = 0;
+
+ // Communicates back a string.
+ virtual void ReturnString(const std::string& string) = 0;
+
+ // Communicates back a buffer.
+ virtual void ReturnBuffer(net::GrowableIOBuffer* buffer) = 0;
+
+ // Communicates back command failure.
+ virtual void ReturnFailure(const std::string& error_msg) = 0;
+
+ // Communicates back command success.
+ virtual void ReturnSuccess() { DCHECK(!command_failed_); };
+
+ // Returns whether the command has failed.
+ inline bool has_failed() { return command_failed_; }
+
+ // Returns the opened cache backend.
+ Backend* cache_backend() { return cache_backend_; }
+
+ protected:
+ bool command_failed_;
+ Backend* const cache_backend_;
+};
+
+// Command line input/output that is user readable.
+class ProgramArgumentCommandMarshal final : public CommandMarshal {
+ public:
+ ProgramArgumentCommandMarshal(Backend* cache_backend,
+ base::CommandLine::StringVector args)
+ : CommandMarshal(cache_backend), command_line_args_(args), args_id_(0) {}
+
+ // Implements CommandMarshal.
+ std::string ReadCommandName() override {
+ if (args_id_ == 0)
+ return ReadString();
+ else if (args_id_ == command_line_args_.size())
+ return "stop";
+ else if (!has_failed())
+ ReturnFailure("Command line arguments to long.");
+ return "";
+ }
+
+ // Implements CommandMarshal.
+ int ReadInt() override {
+ std::string interger_str = ReadString();
+ int interger = -1;
+ if (!base::StringToInt(interger_str, &interger)) {
+ ReturnFailure("Couldn't parse integer.");
+ return 0;
+ }
+ return interger;
+ }
+
+ // Implements CommandMarshal.
+ std::string ReadString() override {
+ if (args_id_ < command_line_args_.size())
+ return command_line_args_[args_id_++];
+ if (!has_failed())
+ ReturnFailure("Command line arguments to short.");
+ return "";
+ }
+
+ // Implements CommandMarshal.
+ std::string ReadBufferedString() override {
+ std::ostringstream raw_headers_stream;
+ for (std::string line; std::getline(std::cin, line);)
+ raw_headers_stream << line << std::endl;
+ return raw_headers_stream.str();
+ }
+
+ // Implements CommandMarshal.
+ void ReturnInt(int integer) override {
+ DCHECK(!has_failed());
+ std::cout << integer << std::endl;
+ }
+
+ // Implements CommandMarshal.
+ void ReturnString(const std::string& string) override {
+ DCHECK(!has_failed());
+ std::cout << string << std::endl;
+ }
+
+ // Implements CommandMarshal.
+ void ReturnBuffer(net::GrowableIOBuffer* buffer) override {
+ DCHECK(!has_failed());
+ std::cout.write(buffer->data(), buffer->offset());
+ }
+
+ // Implements CommandMarshal.
+ void ReturnFailure(const std::string& error_msg) override {
+ DCHECK(!has_failed());
+ std::cerr << error_msg << std::endl;
+ command_failed_ = true;
+ }
+
+ private:
+ const base::CommandLine::StringVector command_line_args_;
+ size_t args_id_;
+};
+
+// Online command input/output that receives pickled commands from stdin and
+// returns their results back in stdout. Send the stop command to properly exit
+// cachetool's main loop.
+class StreamCommandMarshal final : public CommandMarshal {
+ public:
+ StreamCommandMarshal(Backend* cache_backend)
+ : CommandMarshal(cache_backend) {}
+
+ // Implements CommandMarshal.
+ std::string ReadCommandName() override {
+ if (has_failed())
+ return "";
+ std::cout.flush();
+ size_t command_id = static_cast<size_t>(std::cin.get());
+ if (command_id >= arraysize(kCommandNames)) {
+ ReturnFailure("Unknown command.");
+ return "";
+ }
+ return kCommandNames[command_id];
+ }
+
+ // Implements CommandMarshal.
+ int ReadInt() override {
+ if (has_failed())
+ return -1;
+ int integer = -1;
+ std::cin.read(reinterpret_cast<char*>(&integer), sizeof(integer));
+ return integer;
+ }
+
+ // Implements CommandMarshal.
+ std::string ReadString() override {
+ if (has_failed())
+ return "";
+ int string_size = ReadInt();
+ if (string_size <= 0) {
+ if (string_size < 0)
+ ReturnFailure("Size of string is negative.");
+ return "";
+ }
+ std::vector<char> tmp_buffer(string_size + 1);
+ std::cin.read(&tmp_buffer[0], string_size);
+ tmp_buffer[string_size] = 0;
+ return std::string(&tmp_buffer[0], string_size);
+ }
+
+ // Implements CommandMarshal.
+ std::string ReadBufferedString() override { return ReadString(); }
+
+ // Implements CommandMarshal.
+ void ReturnInt(int integer) override {
+ DCHECK(!command_failed_);
+ std::cout.write(reinterpret_cast<char*>(&integer), sizeof(integer));
+ }
+
+ // Implements CommandMarshal.
+ void ReturnString(const std::string& string) override {
+ ReturnInt(string.size());
+ std::cout.write(string.c_str(), string.size());
+ }
+
+ // Implements CommandMarshal.
+ void ReturnBuffer(net::GrowableIOBuffer* buffer) override {
+ ReturnInt(buffer->offset());
+ std::cout.write(buffer->StartOfBuffer(), buffer->offset());
+ }
+
+ // Implements CommandMarshal.
+ void ReturnFailure(const std::string& error_msg) override {
+ ReturnString(error_msg);
+ command_failed_ = true;
+ }
+
+ // Implements CommandMarshal.
+ void ReturnSuccess() override { ReturnInt(0); }
+};
+
+// Gets the cache's size.
+void GetSize(CommandMarshal* command_marshal) {
net::TestCompletionCallback cb;
- int rv = cache_backend->CalculateSizeOfAllEntries(cb.callback());
+ int rv = command_marshal->cache_backend()->CalculateSizeOfAllEntries(
+ cb.callback());
rv = cb.GetResult(rv);
- if (rv < 0) {
- std::cerr << "Couldn't get cache size." << std::endl;
- return false;
- }
- std::cout << rv << std::endl;
- return true;
+ if (rv < 0)
+ return command_marshal->ReturnFailure("Couldn't get cache size.");
+ command_marshal->ReturnSuccess();
+ command_marshal->ReturnInt(rv);
}
-// Print all of a cache's keys to stdout.
-bool ListKeys(Backend* cache_backend) {
+// Prints all of a cache's keys to stdout.
+bool ListKeys(CommandMarshal* command_marshal) {
std::unique_ptr<Backend::Iterator> entry_iterator =
- cache_backend->CreateIterator();
+ command_marshal->cache_backend()->CreateIterator();
Entry* entry = nullptr;
net::TestCompletionCallback cb;
int rv = entry_iterator->OpenNextEntry(&entry, cb.callback());
+ command_marshal->ReturnSuccess();
while (cb.GetResult(rv) == net::OK) {
std::string url = entry->GetKey();
- std::cout << url << std::endl;
+ command_marshal->ReturnString(url);
entry->Close();
entry = nullptr;
rv = entry_iterator->OpenNextEntry(&entry, cb.callback());
}
+ command_marshal->ReturnString("");
return true;
}
-// Get a key's stream to a buffer.
+// Gets a key's stream to a buffer.
scoped_refptr<net::GrowableIOBuffer> GetStreamForKeyBuffer(
- Backend* cache_backend,
+ CommandMarshal* command_marshal,
const std::string& key,
int index) {
+ DCHECK(!command_marshal->has_failed());
Entry* cache_entry;
net::TestCompletionCallback cb;
- int rv = cache_backend->OpenEntry(key, &cache_entry, cb.callback());
+ int rv = command_marshal->cache_backend()->OpenEntry(key, &cache_entry,
+ cb.callback());
if (cb.GetResult(rv) != net::OK) {
- std::cerr << "Couldn't find key's entry." << std::endl;
+ command_marshal->ReturnFailure("Couldn't find key's entry.");
return nullptr;
}
@@ -79,7 +327,7 @@ scoped_refptr<net::GrowableIOBuffer> GetStreamForKeyBuffer(
rv = cb.GetResult(rv);
if (rv < 0) {
cache_entry->Close();
- std::cerr << "Stream read error." << std::endl;
+ command_marshal->ReturnFailure("Stream read error.");
return nullptr;
}
buffer->set_offset(buffer->offset() + rv);
@@ -91,138 +339,134 @@ scoped_refptr<net::GrowableIOBuffer> GetStreamForKeyBuffer(
return buffer;
}
-// Print a key's stream to stdout.
-bool GetStreamForKey(Backend* cache_backend,
- const std::string& key,
- int index) {
+// Prints a key's stream to stdout.
+void GetStreamForKey(CommandMarshal* command_marshal) {
+ std::string key = command_marshal->ReadString();
+ int index = command_marshal->ReadInt();
+ if (command_marshal->has_failed())
+ return;
scoped_refptr<net::GrowableIOBuffer> buffer(
- GetStreamForKeyBuffer(cache_backend, key, index));
- if (!buffer)
- return false;
+ GetStreamForKeyBuffer(command_marshal, key, index));
+ if (command_marshal->has_failed())
+ return;
if (index == kResponseInfoIndex) {
net::HttpResponseInfo response_info;
bool truncated_response_info = false;
net::HttpCache::ParseResponseInfo(buffer->StartOfBuffer(), buffer->offset(),
&response_info, &truncated_response_info);
- if (truncated_response_info) {
- std::cerr << "Truncated HTTP response." << std::endl;
- return false;
- }
- std::cout << net::HttpUtil::ConvertHeadersBackToHTTPResponse(
- response_info.headers->raw_headers());
+ if (truncated_response_info)
+ return command_marshal->ReturnFailure("Truncated HTTP response.");
+ command_marshal->ReturnSuccess();
+ command_marshal->ReturnString(
+ net::HttpUtil::ConvertHeadersBackToHTTPResponse(
+ response_info.headers->raw_headers()));
} else {
- std::cout.write(buffer->StartOfBuffer(), buffer->offset());
+ command_marshal->ReturnSuccess();
+ command_marshal->ReturnBuffer(buffer.get());
}
- return true;
}
-// Set stdin as the key's raw response headers.
-bool UpdateRawResponseHeaders(Backend* cache_backend, const std::string& key) {
+// Sets stdin as the key's raw response headers.
+void UpdateRawResponseHeaders(CommandMarshal* command_marshal) {
+ std::string key = command_marshal->ReadString();
+ std::string raw_headers = command_marshal->ReadBufferedString();
+ if (command_marshal->has_failed())
+ return;
scoped_refptr<net::GrowableIOBuffer> buffer(
- GetStreamForKeyBuffer(cache_backend, key, kResponseInfoIndex));
- if (!buffer)
- return false;
+ GetStreamForKeyBuffer(command_marshal, key, kResponseInfoIndex));
+ if (command_marshal->has_failed())
+ return;
net::HttpResponseInfo response_info;
bool truncated_response_info = false;
net::HttpCache::ParseResponseInfo(buffer->StartOfBuffer(), buffer->offset(),
&response_info, &truncated_response_info);
- if (truncated_response_info) {
- std::cerr << "Truncated HTTP response." << std::endl;
- return false;
- }
- std::ostringstream raw_headers_stream;
- for (std::string line; std::getline(std::cin, line);)
- raw_headers_stream << line << std::endl;
- response_info.headers =
- new net::HttpResponseHeaders(raw_headers_stream.str());
+ if (truncated_response_info)
+ return command_marshal->ReturnFailure("Truncated HTTP response.");
+
+ response_info.headers = new net::HttpResponseHeaders(raw_headers);
scoped_refptr<net::PickledIOBuffer> data(new net::PickledIOBuffer());
response_info.Persist(data->pickle(), false, false);
data->Done();
Entry* cache_entry;
net::TestCompletionCallback cb;
- int rv = cache_backend->OpenEntry(key, &cache_entry, cb.callback());
+ int rv = command_marshal->cache_backend()->OpenEntry(key, &cache_entry,
+ cb.callback());
CHECK(cb.GetResult(rv) == net::OK);
int data_len = data->pickle()->size();
rv = cache_entry->WriteData(kResponseInfoIndex, 0, data.get(), data_len,
cb.callback(), true);
- if (cb.GetResult(rv) != data_len) {
- std::cerr << "Couldn't write headers." << std::endl;
- return false;
- }
+ if (cb.GetResult(rv) != data_len)
+ return command_marshal->ReturnFailure("Couldn't write headers.");
+ command_marshal->ReturnSuccess();
cache_entry->Close();
- return true;
}
-// Delete a specified key stream from the cache.
-bool DeleteStreamForKey(Backend* cache_backend,
- const std::string& key,
- int index) {
+// Deletes a specified key stream from the cache.
+void DeleteStreamForKey(CommandMarshal* command_marshal) {
+ std::string key = command_marshal->ReadString();
+ int index = command_marshal->ReadInt();
+ if (command_marshal->has_failed())
+ return;
Entry* cache_entry;
net::TestCompletionCallback cb;
- int rv = cache_backend->OpenEntry(key, &cache_entry, cb.callback());
- if (cb.GetResult(rv) != net::OK) {
- std::cerr << "Couldn't find key's entry." << std::endl;
- return false;
- }
+ int rv = command_marshal->cache_backend()->OpenEntry(key, &cache_entry,
+ cb.callback());
+ if (cb.GetResult(rv) != net::OK)
+ return command_marshal->ReturnFailure("Couldn't find key's entry.");
scoped_refptr<net::StringIOBuffer> buffer(new net::StringIOBuffer(""));
rv = cache_entry->WriteData(index, 0, buffer.get(), 0, cb.callback(), true);
- if (cb.GetResult(rv) != 0) {
- std::cerr << "Couldn't delete key stream." << std::endl;
- return false;
- }
+ if (cb.GetResult(rv) != net::OK)
+ return command_marshal->ReturnFailure("Couldn't delete key stream.");
+ command_marshal->ReturnSuccess();
cache_entry->Close();
- return true;
}
-// Delete a specified key from the cache.
-bool DeleteKey(Backend* cache_backend, const std::string& key) {
+// Deletes a specified key from the cache.
+void DeleteKey(CommandMarshal* command_marshal) {
+ std::string key = command_marshal->ReadString();
+ if (command_marshal->has_failed())
+ return;
net::TestCompletionCallback cb;
- int rv = cache_backend->DoomEntry(key, cb.callback());
- if (cb.GetResult(rv) != net::OK) {
- std::cerr << "Couldn't delete key." << std::endl;
- return false;
- }
- return true;
+ int rv = command_marshal->cache_backend()->DoomEntry(key, cb.callback());
+ if (cb.GetResult(rv) != net::OK)
+ command_marshal->ReturnFailure("Couldn't delete key.");
+ else
+ command_marshal->ReturnSuccess();
}
-// Parse stream index from command line argument string.
-int ParseStreamIndex(const std::string& index_arg) {
- int index = -1;
- if (!base::StringToInt(index_arg, &index)) {
- std::cerr << "<index> must be an integer." << std::endl;
- return -1;
- } else if (index < 0 || index > 2) {
- std::cerr << "Invalid stream index." << std::endl;
- return -1;
+// Executes all command from the |command_marshal|.
+bool ExecuteCommands(CommandMarshal* command_marshal) {
+ while (!command_marshal->has_failed()) {
+ std::string subcommand(command_marshal->ReadCommandName());
+ if (command_marshal->has_failed())
+ break;
+ if (subcommand == "stop") {
+ command_marshal->ReturnSuccess();
+ return true;
+ } else if (subcommand == "batch") {
+ StreamCommandMarshal stream_command_marshal(
+ command_marshal->cache_backend());
+ return ExecuteCommands(&stream_command_marshal);
+ } else if (subcommand == "delete_key") {
+ DeleteKey(command_marshal);
+ } else if (subcommand == "delete_stream") {
+ DeleteStreamForKey(command_marshal);
+ } else if (subcommand == "get_size") {
+ GetSize(command_marshal);
+ } else if (subcommand == "get_stream") {
+ GetStreamForKey(command_marshal);
+ } else if (subcommand == "list_keys") {
+ ListKeys(command_marshal);
+ } else if (subcommand == "update_raw_headers") {
+ UpdateRawResponseHeaders(command_marshal);
+ } else {
+ // The wrong subcommand is originated from the command line.
+ command_marshal->ReturnFailure("Unknown command.");
+ PrintHelp();
+ }
}
- return index;
-}
-
-// Print the command line help.
-void PrintHelp() {
- std::cout << "cachetool <cache_path> <cache_backend_type> <subcommand> ..."
- << std::endl
- << std::endl;
- std::cout << "Available cache backend types: simple, blockfile" << std::endl;
- std::cout << "Available subcommands:" << std::endl;
- std::cout << " delete_key <key>: Delete key from cache." << std::endl;
- std::cout << " delete_stream <key> <index>: Delete a particular stream of a"
- << " given key." << std::endl;
- std::cout << " get_size: Calculate the total size of the cache in bytes."
- << std::endl;
- std::cout << " get_stream <key> <index>: Print a particular stream for a"
- << " given key." << std::endl;
- std::cout << " list_keys: List all keys in the cache." << std::endl;
- std::cout << " update_raw_headers <key>: Update stdin as the key's raw "
- << "response headers." << std::endl;
- std::cout << " validate: Verify that the cache can be opened and return, "
- << "confirming the cache exists and is of the right type."
- << std::endl;
- std::cout << "Expected values of <index> are:" << std::endl;
- std::cout << " 0 (HTTP response headers)" << std::endl;
- std::cout << " 1 (transport encoded content)" << std::endl;
- std::cout << " 2 (compiled content)" << std::endl;
+ return false;
}
} // namespace
@@ -242,7 +486,6 @@ int main(int argc, char* argv[]) {
base::FilePath cache_path(args[0]);
std::string cache_backend_type(args[1]);
- std::string subcommand(args[2]);
net::BackendType backend_type;
if (cache_backend_type == "simple") {
@@ -265,34 +508,13 @@ int main(int argc, char* argv[]) {
return 1;
}
- bool successful_command;
- if (subcommand == "delete_key" && args.size() == 4) {
- successful_command = DeleteKey(cache_backend.get(), args[3]);
- } else if (subcommand == "delete_stream" && args.size() == 5) {
- int index = ParseStreamIndex(args[4]);
- if (index < 0)
- return 1;
- successful_command =
- DeleteStreamForKey(cache_backend.get(), args[3], index);
- } else if (subcommand == "get_size" && args.size() == 3) {
- successful_command = GetSize(cache_backend.get());
- } else if (subcommand == "get_stream" && args.size() == 5) {
- int index = ParseStreamIndex(args[4]);
- if (index < 0)
- return 1;
- successful_command = GetStreamForKey(cache_backend.get(), args[3], index);
- } else if (subcommand == "list_keys" && args.size() == 3) {
- successful_command = ListKeys(cache_backend.get());
- } else if (subcommand == "update_raw_headers" && args.size() == 4) {
- successful_command = UpdateRawResponseHeaders(cache_backend.get(), args[3]);
- } else if (subcommand == "validate" && args.size() == 3) {
- successful_command = true;
- } else {
- successful_command = false;
- PrintHelp();
- }
+ ProgramArgumentCommandMarshal program_argument_marshal(
+ cache_backend.get(),
+ base::CommandLine::StringVector(args.begin() + 2, args.end()));
+ bool successful_commands = ExecuteCommands(&program_argument_marshal);
+
base::RunLoop().RunUntilIdle();
cache_backend = nullptr;
base::RunLoop().RunUntilIdle();
- return !successful_command;
+ return !successful_commands;
}
diff --git a/chromium/net/tools/cert_verify_tool/cert_verify_tool.cc b/chromium/net/tools/cert_verify_tool/cert_verify_tool.cc
index 794fb5e2a3c..a9c21fc6952 100644
--- a/chromium/net/tools/cert_verify_tool/cert_verify_tool.cc
+++ b/chromium/net/tools/cert_verify_tool/cert_verify_tool.cc
@@ -11,22 +11,54 @@
#include "base/time/time.h"
#include "net/tools/cert_verify_tool/cert_verify_tool_util.h"
#include "net/tools/cert_verify_tool/verify_using_cert_verify_proc.h"
+#include "net/tools/cert_verify_tool/verify_using_path_builder.h"
namespace {
+const char kUsage[] =
+ " [flags] <target/chain>\n"
+ "\n"
+ " <target/chain> is a file containing certificates [1]. Minimally it\n"
+ " contains the target certificate. Optionally it may subsequently list\n"
+ " additional certificates needed to build a chain (this is equivalent to\n"
+ " specifying them through --intermediates)\n"
+ "\n"
+ "Flags:\n"
+ "\n"
+ " --hostname=<hostname>\n"
+ " The hostname required to match the end-entity certificate.\n"
+ " Required for the CertVerifyProc implementation.\n"
+ "\n"
+ " --roots=<certs path>\n"
+ " <certs path> is a file containing certificates [1] to interpret as\n"
+ " trust anchors (without any anchor constraints).\n"
+ "\n"
+ " --intermediates=<certs path>\n"
+ " <certs path> is a file containing certificates [1] for use when\n"
+ " path building is looking for intermediates.\n"
+ "\n"
+ " --time=<time>\n"
+ " Use <time> instead of the current system time. <time> is\n"
+ " interpreted in local time if a timezone is not specified.\n"
+ " Many common formats are supported, including:\n"
+ " 1994-11-15 12:45:26 GMT\n"
+ " Tue, 15 Nov 1994 12:45:26 GMT\n"
+ " Nov 15 12:45:26 1994 GMT\n"
+ "\n"
+ " --dump=<file prefix>\n"
+ " Dumps the verified chain to PEM files starting with\n"
+ " <file prefix>.\n"
+ "\n"
+ "\n"
+ "[1] A \"file containing certificates\" means a path to a file that can\n"
+ " either be:\n"
+ " * A binary file containing a single DER-encoded RFC 5280 Certificate\n"
+ " * A PEM file containing one or more CERTIFICATE blocks (DER-encoded\n"
+ " RFC 5280 Certificate)\n";
+
void PrintUsage(const char* argv0) {
- std::cerr << "Usage: " << argv0 << " [flags] <target/chain>\n";
- std::cerr << " <target/chain> should be a file containing a single DER cert "
- "or a PEM certificate chain (target first).\n";
- std::cerr << "Flags:\n";
- std::cerr << " --hostname=<hostname>\n";
- std::cerr << " --roots=<certs path>\n";
- std::cerr << " --intermediates=<certs path>\n";
- std::cerr << " <certs path> should be a file containing a single DER cert or "
- "one or more PEM CERTIFICATE blocks.\n";
- std::cerr << " --dump=<file prefix>\n";
- std::cerr << " Dumps the verified chain to PEM files starting with <file "
- "prefix>.\n";
+ std::cerr << "Usage: " << argv0 << kUsage;
+
// TODO(mattm): allow <certs path> to be a directory containing DER/PEM files?
// TODO(mattm): allow target to specify an HTTPS URL to check the cert of?
// TODO(mattm): allow target to be a verify_certificate_chain_unittest PEM
@@ -54,9 +86,16 @@ int main(int argc, char** argv) {
}
std::string hostname = command_line.GetSwitchValueASCII("hostname");
- if (hostname.empty()) {
- std::cerr << "ERROR: --hostname is required\n";
- return 1;
+
+ base::Time verify_time;
+ std::string time_flag = command_line.GetSwitchValueASCII("time");
+ if (!time_flag.empty()) {
+ if (!base::Time::FromString(time_flag.c_str(), &verify_time)) {
+ std::cerr << "Error parsing --time flag\n";
+ return 1;
+ }
+ } else {
+ verify_time = base::Time::Now();
}
base::FilePath roots_path = command_line.GetSwitchValuePath("roots");
@@ -74,7 +113,12 @@ int main(int argc, char** argv) {
ReadCertificatesFromFile(roots_path, &root_der_certs);
if (!intermediates_path.empty())
ReadCertificatesFromFile(intermediates_path, &intermediate_der_certs);
- ReadChainFromFile(target_path, &target_der_cert, &intermediate_der_certs);
+
+ if (!ReadChainFromFile(target_path, &target_der_cert,
+ &intermediate_der_certs)) {
+ std::cerr << "ERROR: Couldn't read certificate chain\n";
+ return 1;
+ }
if (target_der_cert.der_cert.empty()) {
std::cerr << "ERROR: no target cert\n";
@@ -82,9 +126,28 @@ int main(int argc, char** argv) {
}
std::cout << "CertVerifyProc:\n";
- bool verify_ok = VerifyUsingCertVerifyProc(target_der_cert, hostname,
- intermediate_der_certs,
- root_der_certs, dump_prefix_path);
+ bool cert_verify_proc_ok = true;
+ if (!time_flag.empty()) {
+ std::cerr << "ERROR: --time is not supported with CertVerifyProc, "
+ "skipping.\n";
+ } else if (hostname.empty()) {
+ std::cerr << "ERROR: --hostname is required for CertVerifyProc, skipping\n";
+ } else {
+ cert_verify_proc_ok = VerifyUsingCertVerifyProc(
+ target_der_cert, hostname, intermediate_der_certs, root_der_certs,
+ dump_prefix_path);
+ }
+
+ std::cout << "\nCertPathBuilder:\n";
+
+ if (!hostname.empty()) {
+ std::cerr
+ << "WARNING: --hostname is not yet verified with CertPathBuilder\n";
+ }
+
+ bool path_builder_ok =
+ VerifyUsingPathBuilder(target_der_cert, intermediate_der_certs,
+ root_der_certs, verify_time, dump_prefix_path);
- return verify_ok ? 0 : 1;
+ return (cert_verify_proc_ok && path_builder_ok) ? 0 : 1;
}
diff --git a/chromium/net/tools/cert_verify_tool/cert_verify_tool_util.cc b/chromium/net/tools/cert_verify_tool/cert_verify_tool_util.cc
index 420a79d84ae..055e911e9f9 100644
--- a/chromium/net/tools/cert_verify_tool/cert_verify_tool_util.cc
+++ b/chromium/net/tools/cert_verify_tool/cert_verify_tool_util.cc
@@ -60,17 +60,21 @@ bool ReadCertificatesFromFile(const base::FilePath& file_path,
return true;
}
-void ReadChainFromFile(const base::FilePath& file_path,
+bool ReadChainFromFile(const base::FilePath& file_path,
CertInput* target,
std::vector<CertInput>* intermediates) {
std::vector<CertInput> tmp_certs;
if (!ReadCertificatesFromFile(file_path, &tmp_certs))
- return;
+ return false;
+
+ if (tmp_certs.empty())
+ return true;
*target = tmp_certs.front();
intermediates->insert(intermediates->end(), ++tmp_certs.begin(),
tmp_certs.end());
+ return true;
}
bool WriteToFile(const base::FilePath& file_path, const std::string& data) {
diff --git a/chromium/net/tools/cert_verify_tool/cert_verify_tool_util.h b/chromium/net/tools/cert_verify_tool/cert_verify_tool_util.h
index fe077f65f5b..80327c701a9 100644
--- a/chromium/net/tools/cert_verify_tool/cert_verify_tool_util.h
+++ b/chromium/net/tools/cert_verify_tool/cert_verify_tool_util.h
@@ -32,8 +32,10 @@ bool ReadCertificatesFromFile(const base::FilePath& file_path,
// Parses |file_path| as a DER cert or PEM chain. If more than one cert is
// present, the first will be used as the target certificate and the rest will
-// be used as intermediates.
-void ReadChainFromFile(const base::FilePath& file_path,
+// be used as intermediates. Returns true on success. Note if the input
+// contains no certificates then the return value is true however
+// nothing is written to |target| or |intermediates|.
+bool ReadChainFromFile(const base::FilePath& file_path,
CertInput* target,
std::vector<CertInput>* intermediates);
diff --git a/chromium/net/tools/cert_verify_tool/verify_using_path_builder.cc b/chromium/net/tools/cert_verify_tool/verify_using_path_builder.cc
new file mode 100644
index 00000000000..206eb74b065
--- /dev/null
+++ b/chromium/net/tools/cert_verify_tool/verify_using_path_builder.cc
@@ -0,0 +1,273 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/tools/cert_verify_tool/verify_using_path_builder.h"
+
+#include <iostream>
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "crypto/sha2.h"
+#include "net/base/test_completion_callback.h"
+#include "net/cert/internal/cert_issuer_source_aia.h"
+#include "net/cert/internal/cert_issuer_source_static.h"
+#include "net/cert/internal/parse_name.h"
+#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/path_builder.h"
+#include "net/cert/internal/signature_policy.h"
+#include "net/cert/internal/trust_store_collection.h"
+#include "net/cert/internal/trust_store_in_memory.h"
+#include "net/cert_net/cert_net_fetcher_impl.h"
+#include "net/tools/cert_verify_tool/cert_verify_tool_util.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_builder.h"
+
+#if defined(USE_NSS_CERTS)
+#include "base/threading/thread_task_runner_handle.h"
+#include "net/cert/internal/trust_store_nss.h"
+#endif
+
+#if defined(OS_LINUX)
+#include "net/proxy/proxy_config.h"
+#include "net/proxy/proxy_config_service_fixed.h"
+#endif
+
+namespace {
+
+std::string GetUserAgent() {
+ return "cert_verify_tool/0.1";
+}
+
+// Converts a base::Time::Exploded to a net::der::GeneralizedTime.
+// TODO(mattm): This function exists in cast_cert_validator.cc also. Dedupe it?
+net::der::GeneralizedTime ConvertExplodedTime(
+ const base::Time::Exploded& exploded) {
+ net::der::GeneralizedTime result;
+ result.year = exploded.year;
+ result.month = exploded.month;
+ result.day = exploded.day_of_month;
+ result.hours = exploded.hour;
+ result.minutes = exploded.minute;
+ result.seconds = exploded.second;
+ return result;
+}
+
+bool AddPemEncodedCert(const net::ParsedCertificate* cert,
+ std::vector<std::string>* pem_encoded_chain) {
+ std::string der_cert;
+ cert->der_cert().AsStringPiece().CopyToString(&der_cert);
+ std::string pem;
+ if (!net::X509Certificate::GetPEMEncodedFromDER(der_cert, &pem)) {
+ std::cerr << "ERROR: GetPEMEncodedFromDER failed\n";
+ return false;
+ }
+ pem_encoded_chain->push_back(pem);
+ return true;
+}
+
+// Dumps a chain of ParsedCertificate objects to a PEM file.
+bool DumpParsedCertificateChain(const base::FilePath& file_path,
+ const net::CertPath& chain) {
+ std::vector<std::string> pem_encoded_chain;
+ for (const auto& cert : chain.certs) {
+ if (!AddPemEncodedCert(cert.get(), &pem_encoded_chain))
+ return false;
+ }
+
+ if (chain.trust_anchor && chain.trust_anchor->cert()) {
+ if (!AddPemEncodedCert(chain.trust_anchor->cert().get(),
+ &pem_encoded_chain))
+ return false;
+ }
+
+ return WriteToFile(file_path, base::JoinString(pem_encoded_chain, ""));
+}
+
+// Returns a hex-encoded sha256 of the DER-encoding of |cert|.
+std::string FingerPrintParsedCertificate(const net::ParsedCertificate* cert) {
+ std::string hash = crypto::SHA256HashString(cert->der_cert().AsStringPiece());
+ return base::HexEncode(hash.data(), hash.size());
+}
+
+std::string SubjectToString(const net::RDNSequence& parsed_subject) {
+ std::string subject_str;
+ if (!net::ConvertToRFC2253(parsed_subject, &subject_str))
+ return std::string();
+ return subject_str;
+}
+
+// Returns a textual representation of the Subject of |cert|.
+std::string SubjectFromParsedCertificate(const net::ParsedCertificate* cert) {
+ net::RDNSequence parsed_subject;
+ if (!net::ParseName(cert->tbs().subject_tlv, &parsed_subject))
+ return std::string();
+ return SubjectToString(parsed_subject);
+}
+
+// Returns a textual representation of the Subject of |trust_anchor|.
+std::string SubjectFromTrustAnchor(const net::TrustAnchor* trust_anchor) {
+ // If the cert is present, display the original subject from that rather than
+ // the normalized subject.
+ if (trust_anchor->cert())
+ return SubjectFromParsedCertificate(trust_anchor->cert().get());
+
+ net::RDNSequence parsed_subject;
+ if (!net::ParseNameValue(trust_anchor->normalized_subject(), &parsed_subject))
+ return std::string();
+ return SubjectToString(parsed_subject);
+}
+
+// Dumps a ResultPath to std::cout.
+void PrintResultPath(const net::CertPathBuilder::ResultPath* result_path,
+ size_t index,
+ bool is_best) {
+ std::cout << "path " << index << " "
+ << (result_path->valid ? "valid" : "invalid")
+ << (is_best ? " (best)" : "") << "\n";
+
+ // Print the certificate chain.
+ for (const auto& cert : result_path->path.certs) {
+ std::cout << " " << FingerPrintParsedCertificate(cert.get()) << " "
+ << SubjectFromParsedCertificate(cert.get()) << "\n";
+ }
+
+ // Print the trust anchor (if there was one).
+ const auto& trust_anchor = result_path->path.trust_anchor;
+ if (trust_anchor) {
+ std::string trust_anchor_cert_fingerprint = "<no cert>";
+ if (trust_anchor->cert()) {
+ trust_anchor_cert_fingerprint =
+ FingerPrintParsedCertificate(trust_anchor->cert().get());
+ }
+ std::cout << " " << trust_anchor_cert_fingerprint << " "
+ << SubjectFromTrustAnchor(trust_anchor.get()) << "\n";
+ }
+
+ // Print the errors.
+ if (!result_path->errors.empty()) {
+ std::cout << "Errors:\n";
+ std::cout << result_path->errors.ToDebugString() << "\n";
+ }
+}
+
+scoped_refptr<net::ParsedCertificate> ParseCertificate(const CertInput& input) {
+ net::CertErrors errors;
+ scoped_refptr<net::ParsedCertificate> cert =
+ net::ParsedCertificate::Create(input.der_cert, {}, &errors);
+ if (!cert) {
+ PrintCertError("ERROR: ParsedCertificate failed:", input);
+ std::cout << errors.ToDebugString() << "\n";
+ }
+
+ // TODO(crbug.com/634443): Print errors if there are any on success too (i.e.
+ // warnings).
+
+ return cert;
+}
+
+} // namespace
+
+// Verifies |target_der_cert| using CertPathBuilder.
+bool VerifyUsingPathBuilder(
+ const CertInput& target_der_cert,
+ const std::vector<CertInput>& intermediate_der_certs,
+ const std::vector<CertInput>& root_der_certs,
+ const base::Time at_time,
+ const base::FilePath& dump_prefix_path) {
+ base::Time::Exploded exploded_time;
+ at_time.UTCExplode(&exploded_time);
+ net::der::GeneralizedTime time = ConvertExplodedTime(exploded_time);
+
+ net::TrustStoreCollection trust_store;
+
+ net::TrustStoreInMemory trust_store_in_memory;
+ trust_store.AddTrustStoreSynchronousOnly(&trust_store_in_memory);
+ for (const auto& der_cert : root_der_certs) {
+ scoped_refptr<net::ParsedCertificate> cert = ParseCertificate(der_cert);
+ if (cert) {
+ trust_store_in_memory.AddTrustAnchor(
+ net::TrustAnchor::CreateFromCertificateNoConstraints(cert));
+ }
+ }
+
+#if defined(USE_NSS_CERTS)
+ net::TrustStoreNSS trust_store_nss(trustSSL,
+ base::ThreadTaskRunnerHandle::Get());
+ trust_store.SetPrimaryTrustStore(&trust_store_nss);
+#else
+ if (root_der_certs.empty()) {
+ std::cerr << "NOTE: CertPathBuilder does not currently use OS trust "
+ "settings (--roots must be specified).\n";
+ }
+#endif
+
+ net::CertIssuerSourceStatic intermediate_cert_issuer_source;
+ for (const auto& der_cert : intermediate_der_certs) {
+ scoped_refptr<net::ParsedCertificate> cert = ParseCertificate(der_cert);
+ if (cert)
+ intermediate_cert_issuer_source.AddCert(cert);
+ }
+
+ scoped_refptr<net::ParsedCertificate> target_cert =
+ ParseCertificate(target_der_cert);
+ if (!target_cert)
+ return false;
+
+ // Verify the chain.
+ net::SimpleSignaturePolicy signature_policy(2048);
+ net::CertPathBuilder::Result result;
+ net::CertPathBuilder path_builder(target_cert, &trust_store,
+ &signature_policy, time, &result);
+ path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source);
+
+ // TODO(mattm): add command line flags to configure using CertIssuerSourceAia
+ // (similar to VERIFY_CERT_IO_ENABLED flag for CertVerifyProc).
+ net::URLRequestContextBuilder url_request_context_builder;
+ url_request_context_builder.set_user_agent(GetUserAgent());
+#if defined(OS_LINUX)
+ // On Linux, use a fixed ProxyConfigService, since the default one
+ // depends on glib.
+ //
+ // TODO(akalin): Remove this once http://crbug.com/146421 is fixed.
+ url_request_context_builder.set_proxy_config_service(
+ base::MakeUnique<net::ProxyConfigServiceFixed>(net::ProxyConfig()));
+#endif
+ std::unique_ptr<net::URLRequestContext> url_request_context =
+ url_request_context_builder.Build();
+ net::CertNetFetcherImpl cert_net_fetcher(url_request_context.get());
+ net::CertIssuerSourceAia aia_cert_issuer_source(&cert_net_fetcher);
+ path_builder.AddCertIssuerSource(&aia_cert_issuer_source);
+
+ net::TestClosure callback;
+ net::CompletionStatus rv = path_builder.Run(callback.closure());
+
+ if (rv == net::CompletionStatus::ASYNC) {
+ DVLOG(1) << "waiting for async completion...";
+ callback.WaitForResult();
+ DVLOG(1) << "async completed.";
+ }
+
+ // TODO(crbug.com/634443): Display any errors/warnings associated with path
+ // building that were not part of a particular
+ // PathResult.
+ std::cout << "CertPathBuilder result: "
+ << (result.HasValidPath() ? "SUCCESS" : "FAILURE") << "\n";
+
+ for (size_t i = 0; i < result.paths.size(); ++i) {
+ PrintResultPath(result.paths[i].get(), i, i == result.best_result_index);
+ }
+
+ // TODO(mattm): add flag to dump all paths, not just the final one?
+ if (!dump_prefix_path.empty() && result.paths.size()) {
+ if (!DumpParsedCertificateChain(
+ dump_prefix_path.AddExtension(
+ FILE_PATH_LITERAL(".CertPathBuilder.pem")),
+ result.paths[result.best_result_index]->path)) {
+ return false;
+ }
+ }
+
+ return result.HasValidPath();
+}
diff --git a/chromium/net/tools/cert_verify_tool/verify_using_path_builder.h b/chromium/net/tools/cert_verify_tool/verify_using_path_builder.h
new file mode 100644
index 00000000000..56980a98d0a
--- /dev/null
+++ b/chromium/net/tools/cert_verify_tool/verify_using_path_builder.h
@@ -0,0 +1,29 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_TOOLS_CERT_VERIFY_TOOL_VERIFY_USING_PATH_BUILDER_H_
+#define NET_TOOLS_CERT_VERIFY_TOOL_VERIFY_USING_PATH_BUILDER_H_
+
+#include <string>
+#include <vector>
+
+namespace base {
+class FilePath;
+class Time;
+}
+
+struct CertInput;
+
+// Verifies |target_der_cert| using CertPathBuilder. Returns true if the
+// certificate verified successfully, false if it failed to verify or there was
+// some other error.
+// Informational messages will be printed to stdout/stderr as appropriate.
+bool VerifyUsingPathBuilder(
+ const CertInput& target_der_cert,
+ const std::vector<CertInput>& intermediate_der_certs,
+ const std::vector<CertInput>& root_der_certs,
+ const base::Time at_time,
+ const base::FilePath& dump_prefix_path);
+
+#endif // NET_TOOLS_CERT_VERIFY_TOOL_VERIFY_USING_PATH_BUILDER_H_
diff --git a/chromium/net/tools/epoll_server/epoll_server.cc b/chromium/net/tools/epoll_server/epoll_server.cc
index 7aec1138b41..042e40320c0 100644
--- a/chromium/net/tools/epoll_server/epoll_server.cc
+++ b/chromium/net/tools/epoll_server/epoll_server.cc
@@ -442,7 +442,7 @@ void EpollServer::VerifyReadyList() const {
void EpollServer::RegisterAlarm(int64_t timeout_time_in_us, AlarmCB* ac) {
CHECK(ac);
- if (ContainsKey(all_alarms_, ac)) {
+ if (base::ContainsKey(all_alarms_, ac)) {
LOG(FATAL) << "Alarm already exists " << ac;
}
VLOG(4) << "RegisteringAlarm at : " << timeout_time_in_us;
diff --git a/chromium/net/tools/flip_server/acceptor_thread.cc b/chromium/net/tools/flip_server/acceptor_thread.cc
deleted file mode 100644
index 22b94f3e53e..00000000000
--- a/chromium/net/tools/flip_server/acceptor_thread.cc
+++ /dev/null
@@ -1,206 +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/tools/flip_server/acceptor_thread.h"
-
-#include <errno.h>
-#include <netinet/in.h>
-#include <string.h> // For strerror
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <string>
-
-#include "net/socket/tcp_socket.h"
-#include "net/tools/flip_server/constants.h"
-#include "net/tools/flip_server/flip_config.h"
-#include "net/tools/flip_server/sm_connection.h"
-#include "net/tools/flip_server/spdy_ssl.h"
-#include "openssl/err.h"
-#include "openssl/ssl.h"
-
-namespace net {
-
-SMAcceptorThread::SMAcceptorThread(FlipAcceptor* acceptor,
- MemoryCache* memory_cache)
- : SimpleThread("SMAcceptorThread"),
- acceptor_(acceptor),
- ssl_state_(NULL),
- use_ssl_(false),
- idle_socket_timeout_s_(acceptor->idle_socket_timeout_s_),
- quitting_(false),
- memory_cache_(memory_cache) {
- if (!acceptor->ssl_cert_filename_.empty() &&
- !acceptor->ssl_key_filename_.empty()) {
- ssl_state_ = new SSLState;
- bool use_npn = true;
- if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) {
- use_npn = false;
- }
- InitSSL(ssl_state_,
- acceptor_->ssl_cert_filename_,
- acceptor_->ssl_key_filename_,
- use_npn,
- acceptor_->ssl_session_expiry_,
- acceptor_->ssl_disable_compression_);
- use_ssl_ = true;
- }
-}
-
-SMAcceptorThread::~SMAcceptorThread() {
- for (std::vector<SMConnection*>::iterator i =
- allocated_server_connections_.begin();
- i != allocated_server_connections_.end();
- ++i) {
- delete *i;
- }
- delete ssl_state_;
-}
-
-SMConnection* SMAcceptorThread::NewConnection() {
- SMConnection* server = SMConnection::NewSMConnection(
- &epoll_server_, ssl_state_, memory_cache_, acceptor_, "client_conn: ");
- allocated_server_connections_.push_back(server);
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Acceptor: Making new server.";
- return server;
-}
-
-SMConnection* SMAcceptorThread::FindOrMakeNewSMConnection() {
- if (unused_server_connections_.empty()) {
- return NewConnection();
- }
- SMConnection* server = unused_server_connections_.back();
- unused_server_connections_.pop_back();
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Acceptor: Reusing server.";
- return server;
-}
-
-void SMAcceptorThread::InitWorker() {
- epoll_server_.RegisterFD(acceptor_->listen_fd_, this, EPOLLIN | EPOLLET);
-}
-
-void SMAcceptorThread::HandleConnection(int server_fd,
- struct sockaddr_in* remote_addr) {
- if (acceptor_->disable_nagle_) {
- if (!SetTCPNoDelay(server_fd, /*no_delay=*/true)) {
- close(server_fd);
- LOG(FATAL) << "SetTCPNoDelay() failed on fd: " << server_fd;
- return;
- }
- }
-
- SMConnection* server_connection = FindOrMakeNewSMConnection();
- if (server_connection == NULL) {
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Acceptor: Closing fd " << server_fd;
- close(server_fd);
- return;
- }
- std::string remote_ip = inet_ntoa(remote_addr->sin_addr);
- server_connection->InitSMConnection(this,
- NULL,
- &epoll_server_,
- server_fd,
- std::string(),
- std::string(),
- remote_ip,
- use_ssl_);
- if (server_connection->initialized())
- active_server_connections_.push_back(server_connection);
-}
-
-void SMAcceptorThread::AcceptFromListenFD() {
- if (acceptor_->accepts_per_wake_ > 0) {
- for (int i = 0; i < acceptor_->accepts_per_wake_; ++i) {
- struct sockaddr address;
- socklen_t socklen = sizeof(address);
- int fd = accept(acceptor_->listen_fd_, &address, &socklen);
- if (fd == -1) {
- if (errno != 11) {
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Acceptor: accept fail("
- << acceptor_->listen_fd_ << "): " << errno << ": "
- << strerror(errno);
- }
- break;
- }
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << " Accepted connection";
- HandleConnection(fd, (struct sockaddr_in*)&address);
- }
- } else {
- while (true) {
- struct sockaddr address;
- socklen_t socklen = sizeof(address);
- int fd = accept(acceptor_->listen_fd_, &address, &socklen);
- if (fd == -1) {
- if (errno != 11) {
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Acceptor: accept fail("
- << acceptor_->listen_fd_ << "): " << errno << ": "
- << strerror(errno);
- }
- break;
- }
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Accepted connection";
- HandleConnection(fd, (struct sockaddr_in*)&address);
- }
- }
-}
-
-void SMAcceptorThread::HandleConnectionIdleTimeout() {
- static time_t oldest_time = time(NULL);
-
- int cur_time = time(NULL);
- // Only iterate the list if we speculate that a connection is ready to be
- // expired
- if ((cur_time - oldest_time) < idle_socket_timeout_s_)
- return;
-
- // TODO(mbelshe): This code could be optimized, active_server_connections_
- // is already in-order.
- std::list<SMConnection*>::iterator iter = active_server_connections_.begin();
- while (iter != active_server_connections_.end()) {
- SMConnection* conn = *iter;
- int elapsed_time = (cur_time - conn->last_read_time_);
- if (elapsed_time > idle_socket_timeout_s_) {
- conn->Cleanup("Connection idle timeout reached.");
- iter = active_server_connections_.erase(iter);
- continue;
- }
- if (conn->last_read_time_ < oldest_time)
- oldest_time = conn->last_read_time_;
- iter++;
- }
- if ((cur_time - oldest_time) >= idle_socket_timeout_s_)
- oldest_time = cur_time;
-}
-
-void SMAcceptorThread::Run() {
- while (!quitting_.HasBeenNotified()) {
- epoll_server_.set_timeout_in_us(10 * 1000); // 10 ms
- epoll_server_.WaitForEventsAndExecuteCallbacks();
- if (tmp_unused_server_connections_.size()) {
- VLOG(2) << "have " << tmp_unused_server_connections_.size()
- << " additional unused connections. Total = "
- << unused_server_connections_.size();
- unused_server_connections_.insert(unused_server_connections_.end(),
- tmp_unused_server_connections_.begin(),
- tmp_unused_server_connections_.end());
- tmp_unused_server_connections_.clear();
- }
- HandleConnectionIdleTimeout();
- }
-}
-
-void SMAcceptorThread::OnEvent(int fd, EpollEvent* event) {
- if (event->in_events | EPOLLIN) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT
- << "Acceptor: Accepting based upon epoll events";
- AcceptFromListenFD();
- }
-}
-
-void SMAcceptorThread::SMConnectionDone(SMConnection* sc) {
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Done with connection.";
- tmp_unused_server_connections_.push_back(sc);
-}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/acceptor_thread.h b/chromium/net/tools/flip_server/acceptor_thread.h
deleted file mode 100644
index 981a089035d..00000000000
--- a/chromium/net/tools/flip_server/acceptor_thread.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_ACCEPTOR_THREAD_H_
-#define NET_TOOLS_FLIP_SERVER_ACCEPTOR_THREAD_H_
-
-#include <list>
-#include <string>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/threading/simple_thread.h"
-#include "net/tools/epoll_server/epoll_server.h"
-#include "net/tools/flip_server/sm_interface.h"
-#include "openssl/ssl.h"
-
-struct sockaddr_in;
-
-namespace net {
-
-class FlipAcceptor;
-class MemoryCache;
-class SMConnection;
-struct SSLState;
-
-// TODO(mbelshe): Get rid of this class; we don't need a lock just to set
-// a bool cross threads - especially one which only is set once...
-class Notification {
- public:
- explicit Notification(bool value) : value_(value) {}
-
- void Notify() {
- base::AutoLock al(lock_);
- value_ = true;
- }
- bool HasBeenNotified() {
- base::AutoLock al(lock_);
- return value_;
- }
- bool value_;
- base::Lock lock_;
-};
-
-class SMAcceptorThread : public base::SimpleThread,
- public EpollCallbackInterface,
- public SMConnectionPoolInterface {
- public:
- SMAcceptorThread(FlipAcceptor* acceptor, MemoryCache* memory_cache);
- ~SMAcceptorThread() override;
-
- // EpollCallbackInteface interface
- void OnRegistration(EpollServer* eps, int fd, int event_mask) override {}
- void OnModification(int fd, int event_mask) override {}
- void OnEvent(int fd, EpollEvent* event) override;
- void OnUnregistration(int fd, bool replaced) override {}
- void OnShutdown(EpollServer* eps, int fd) override {}
-
- // SMConnectionPool interface
- void SMConnectionDone(SMConnection* sc) override;
-
- // TODO(mbelshe): figure out if we can move these to private functions.
- SMConnection* NewConnection();
- SMConnection* FindOrMakeNewSMConnection();
- void InitWorker();
- void HandleConnection(int server_fd, struct sockaddr_in* remote_addr);
- void AcceptFromListenFD();
-
- // Notify the Accept thread that it is time to terminate.
- void Quit() { quitting_.Notify(); }
-
- // Iterates through a list of active connections expiring any that have been
- // idle longer than the configured timeout.
- void HandleConnectionIdleTimeout();
-
- void Run() override;
-
- private:
- EpollServer epoll_server_;
- FlipAcceptor* acceptor_;
- SSLState* ssl_state_;
- bool use_ssl_;
- int idle_socket_timeout_s_;
-
- std::vector<SMConnection*> unused_server_connections_;
- std::vector<SMConnection*> tmp_unused_server_connections_;
- std::vector<SMConnection*> allocated_server_connections_;
- std::list<SMConnection*> active_server_connections_;
- Notification quitting_;
- MemoryCache* memory_cache_;
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_ACCEPTOR_THREAD_H_
diff --git a/chromium/net/tools/flip_server/constants.h b/chromium/net/tools/flip_server/constants.h
deleted file mode 100644
index 551650909c4..00000000000
--- a/chromium/net/tools/flip_server/constants.h
+++ /dev/null
@@ -1,25 +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.
-
-#ifndef NET_TOOLS_FLIP_SERVER_CONSTANTS_H_
-#define NET_TOOLS_FLIP_SERVER_CONSTANTS_H_
-
-#include "net/spdy/spdy_protocol.h"
-
-const int kMSS = 1460;
-const int kSSLOverhead = 25;
-const int kSpdyOverhead = 8;
-const int kInitialDataSendersThreshold = (2 * kMSS) - kSpdyOverhead;
-const int kSSLSegmentSize = (1 * kMSS) - kSSLOverhead;
-const int kSpdySegmentSize = kSSLSegmentSize - kSpdyOverhead;
-
-#define ACCEPTOR_CLIENT_IDENT \
- acceptor_->listen_ip_ << ":" << acceptor_->listen_port_ << " "
-
-#define IPV4_PRINTABLE_FORMAT(IP) (((IP)>>0)&0xff), (((IP)>>8)&0xff), \
- (((IP)>>16)&0xff), (((IP)>>24)&0xff)
-
-#define PIDFILE "/var/run/flip-server.pid"
-
-#endif // NET_TOOLS_FLIP_SERVER_CONSTANTS_H_
diff --git a/chromium/net/tools/flip_server/flip_config.cc b/chromium/net/tools/flip_server/flip_config.cc
deleted file mode 100644
index afc858ce165..00000000000
--- a/chromium/net/tools/flip_server/flip_config.cc
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/tools/flip_server/flip_config.h"
-
-#include <unistd.h>
-
-#include "base/files/file_util.h"
-#include "net/tools/flip_server/tcp_socket_util.h"
-
-namespace net {
-
-FlipAcceptor::FlipAcceptor(enum FlipHandlerType flip_handler_type,
- std::string listen_ip,
- std::string listen_port,
- std::string ssl_cert_filename,
- std::string ssl_key_filename,
- std::string http_server_ip,
- std::string http_server_port,
- std::string https_server_ip,
- std::string https_server_port,
- int spdy_only,
- int accept_backlog_size,
- bool disable_nagle,
- int accepts_per_wake,
- bool reuseport,
- bool wait_for_iface,
- void* memory_cache)
- : flip_handler_type_(flip_handler_type),
- listen_ip_(listen_ip),
- listen_port_(listen_port),
- ssl_cert_filename_(ssl_cert_filename),
- ssl_key_filename_(ssl_key_filename),
- http_server_ip_(http_server_ip),
- http_server_port_(http_server_port),
- https_server_ip_(https_server_ip),
- https_server_port_(https_server_port),
- spdy_only_(spdy_only),
- accept_backlog_size_(accept_backlog_size),
- disable_nagle_(disable_nagle),
- accepts_per_wake_(accepts_per_wake),
- memory_cache_(memory_cache),
- ssl_session_expiry_(300), // TODO(mbelshe): Hook these up!
- ssl_disable_compression_(false),
- idle_socket_timeout_s_(300) {
- VLOG(1) << "Attempting to listen on " << listen_ip_.c_str() << ":"
- << listen_port_.c_str();
- if (!https_server_ip_.size())
- https_server_ip_ = http_server_ip_;
- if (!https_server_port_.size())
- https_server_port_ = http_server_port_;
-
- while (1) {
- int ret = CreateTCPServerSocket(listen_ip_,
- listen_port_,
- true,
- accept_backlog_size_,
- true,
- reuseport,
- wait_for_iface,
- disable_nagle_,
- &listen_fd_);
- if (ret == 0) {
- break;
- } else if (ret == -3 && wait_for_iface) {
- // Binding error EADDRNOTAVAIL was encounted. We need
- // to wait for the interfaces to raised. try again.
- usleep(200000);
- } else {
- LOG(ERROR) << "Unable to create listening socket for: ret = " << ret
- << ": " << listen_ip_.c_str() << ":" << listen_port_.c_str();
- return;
- }
- }
-
- if (!base::SetNonBlocking(listen_fd_)) {
- LOG(FATAL) << "base::SetNonBlocking() failed: " << listen_fd_;
- }
-
- VLOG(1) << "Listening on socket: ";
- if (flip_handler_type == FLIP_HANDLER_PROXY)
- VLOG(1) << "\tType : Proxy";
- else if (FLIP_HANDLER_SPDY_SERVER)
- VLOG(1) << "\tType : SPDY Server";
- else if (FLIP_HANDLER_HTTP_SERVER)
- VLOG(1) << "\tType : HTTP Server";
- VLOG(1) << "\tIP : " << listen_ip_;
- VLOG(1) << "\tPort : " << listen_port_;
- VLOG(1) << "\tHTTP Server : " << http_server_ip_ << ":" << http_server_port_;
- VLOG(1) << "\tHTTPS Server : " << https_server_ip_ << ":"
- << https_server_port_;
- VLOG(1) << "\tSSL : " << (ssl_cert_filename.size() ? "true"
- : "false");
- VLOG(1) << "\tCertificate : " << ssl_cert_filename;
- VLOG(1) << "\tKey : " << ssl_key_filename;
- VLOG(1) << "\tSpdy Only : " << (spdy_only ? "true" : "false");
-}
-
-FlipAcceptor::~FlipAcceptor() {}
-
-FlipConfig::FlipConfig()
- : server_think_time_in_s_(0),
- log_destination_(logging::LOG_TO_SYSTEM_DEBUG_LOG),
- wait_for_iface_(false) {}
-
-FlipConfig::~FlipConfig() {}
-
-void FlipConfig::AddAcceptor(enum FlipHandlerType flip_handler_type,
- std::string listen_ip,
- std::string listen_port,
- std::string ssl_cert_filename,
- std::string ssl_key_filename,
- std::string http_server_ip,
- std::string http_server_port,
- std::string https_server_ip,
- std::string https_server_port,
- int spdy_only,
- int accept_backlog_size,
- bool disable_nagle,
- int accepts_per_wake,
- bool reuseport,
- bool wait_for_iface,
- void* memory_cache) {
- // TODO(mbelshe): create a struct FlipConfigArgs{} for the arguments.
- acceptors_.push_back(new FlipAcceptor(flip_handler_type,
- listen_ip,
- listen_port,
- ssl_cert_filename,
- ssl_key_filename,
- http_server_ip,
- http_server_port,
- https_server_ip,
- https_server_port,
- spdy_only,
- accept_backlog_size,
- disable_nagle,
- accepts_per_wake,
- reuseport,
- wait_for_iface,
- memory_cache));
-}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/flip_config.h b/chromium/net/tools/flip_server/flip_config.h
deleted file mode 100644
index 124a5b3158c..00000000000
--- a/chromium/net/tools/flip_server/flip_config.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_FLIP_CONFIG_H_
-#define NET_TOOLS_FLIP_SERVER_FLIP_CONFIG_H_
-
-#include <arpa/inet.h>
-
-#include <string>
-#include <vector>
-
-#include "base/logging.h"
-
-namespace net {
-
-enum FlipHandlerType {
- FLIP_HANDLER_PROXY,
- FLIP_HANDLER_SPDY_SERVER,
- FLIP_HANDLER_HTTP_SERVER
-};
-
-class FlipAcceptor {
- public:
- FlipAcceptor(enum FlipHandlerType flip_handler_type,
- std::string listen_ip,
- std::string listen_port,
- std::string ssl_cert_filename,
- std::string ssl_key_filename,
- std::string http_server_ip,
- std::string http_server_port,
- std::string https_server_ip,
- std::string https_server_port,
- int spdy_only,
- int accept_backlog_size,
- bool disable_nagle,
- int accepts_per_wake,
- bool reuseport,
- bool wait_for_iface,
- void* memory_cache);
- ~FlipAcceptor();
-
- enum FlipHandlerType flip_handler_type_;
- std::string listen_ip_;
- std::string listen_port_;
- std::string ssl_cert_filename_;
- std::string ssl_key_filename_;
- std::string http_server_ip_;
- std::string http_server_port_;
- std::string https_server_ip_;
- std::string https_server_port_;
- int spdy_only_;
- int accept_backlog_size_;
- bool disable_nagle_;
- int accepts_per_wake_;
- int listen_fd_;
- void* memory_cache_;
- int ssl_session_expiry_;
- bool ssl_disable_compression_;
- int idle_socket_timeout_s_;
-};
-
-class FlipConfig {
- public:
- FlipConfig();
- ~FlipConfig();
-
- void AddAcceptor(enum FlipHandlerType flip_handler_type,
- std::string listen_ip,
- std::string listen_port,
- std::string ssl_cert_filename,
- std::string ssl_key_filename,
- std::string http_server_ip,
- std::string http_server_port,
- std::string https_server_ip,
- std::string https_server_port,
- int spdy_only,
- int accept_backlog_size,
- bool disable_nagle,
- int accepts_per_wake,
- bool reuseport,
- bool wait_for_iface,
- void* memory_cache);
-
- std::vector<FlipAcceptor*> acceptors_;
- double server_think_time_in_s_;
- enum logging::LoggingDestination log_destination_;
- std::string log_filename_;
- bool wait_for_iface_;
- int ssl_session_expiry_;
- bool ssl_disable_compression_;
- int idle_socket_timeout_s_;
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_FLIP_CONFIG_H_
diff --git a/chromium/net/tools/flip_server/flip_in_mem_edsm_server.cc b/chromium/net/tools/flip_server/flip_in_mem_edsm_server.cc
deleted file mode 100644
index d14af00d1a1..00000000000
--- a/chromium/net/tools/flip_server/flip_in_mem_edsm_server.cc
+++ /dev/null
@@ -1,403 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/file.h>
-#include <sys/stat.h>
-
-#include <string>
-#include <vector>
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/strings/string_split.h"
-#include "base/synchronization/lock.h"
-#include "net/tools/flip_server/acceptor_thread.h"
-#include "net/tools/flip_server/constants.h"
-#include "net/tools/flip_server/flip_config.h"
-#include "net/tools/flip_server/output_ordering.h"
-#include "net/tools/flip_server/sm_connection.h"
-#include "net/tools/flip_server/sm_interface.h"
-#include "net/tools/flip_server/spdy_interface.h"
-#include "net/tools/flip_server/streamer_interface.h"
-
-// If true, then disables the nagle algorithm);
-bool FLAGS_disable_nagle = true;
-
-// The number of times that accept() will be called when the
-// alarm goes off when the accept_using_alarm flag is set to true.
-// If set to 0, accept() will be performed until the accept queue
-// is completely drained and the accept() call returns an error);
-int32_t FLAGS_accepts_per_wake = 0;
-
-// The size of the TCP accept backlog);
-int32_t FLAGS_accept_backlog_size = 1024;
-
-// If set to false a single socket will be used. If set to true
-// then a new socket will be created for each accept thread.
-// Note that this only works with kernels that support
-// SO_REUSEPORT);
-bool FLAGS_reuseport = false;
-
-// Flag to force spdy, even if NPN is not negotiated.
-bool FLAGS_force_spdy = false;
-
-// The amount of time the server delays before sending back the
-// reply);
-double FLAGS_server_think_time_in_s = 0;
-
-net::FlipConfig g_proxy_config;
-
-static bool GotQuitFromStdin() {
- // Make stdin nonblocking. Yes this is done each time. Oh well.
- fcntl(0, F_SETFL, O_NONBLOCK);
- char c;
- std::string maybequit;
- while (read(0, &c, 1) > 0) {
- maybequit += c;
- }
- if (maybequit.size()) {
- VLOG(1) << "scanning string: \"" << maybequit << "\"";
- }
- return (maybequit.size() > 1 &&
- (maybequit.c_str()[0] == 'q' || maybequit.c_str()[0] == 'Q'));
-}
-
-static bool g_want_exit = false;
-static bool g_want_log_close = false;
-static void SignalHandler(int signum) {
- switch (signum) {
- case SIGTERM:
- case SIGINT:
- g_want_exit = true;
- break;
- case SIGHUP:
- g_want_log_close = true;
- break;
- }
-}
-
-static int OpenPidFile(const char* pidfile) {
- int fd;
- struct stat pid_stat;
- int ret;
-
- fd = open(pidfile, O_RDWR | O_CREAT, 0600);
- if (fd == -1) {
- fprintf(stderr, "Could not open pid file '%s' for reading.\n", pidfile);
- exit(1);
- }
-
- ret = flock(fd, LOCK_EX | LOCK_NB);
- if (ret == -1) {
- if (errno == EWOULDBLOCK) {
- fprintf(stderr, "Flip server is already running.\n");
- } else {
- perror("Error getting lock on pid file");
- }
- exit(1);
- }
-
- if (fstat(fd, &pid_stat) == -1) {
- fprintf(
- stderr, "Could not stat pid file '%s': %s\n", pidfile, strerror(errno));
- exit(1);
- }
- if (pid_stat.st_size != 0) {
- if (ftruncate(fd, pid_stat.st_size) == -1) {
- fprintf(stderr,
- "Could not truncate pid file '%s': %s\n",
- pidfile,
- strerror(errno));
- exit(1);
- }
- }
-
- char pid_str[8];
- snprintf(pid_str, sizeof(pid_str), "%d", getpid());
- int bytes = static_cast<int>(strlen(pid_str));
- if (write(fd, pid_str, strlen(pid_str)) != bytes) {
- perror("Could not write pid file");
- close(fd);
- exit(1);
- }
-
- return fd;
-}
-
-int main(int argc, char** argv) {
- unsigned int i = 0;
- bool wait_for_iface = false;
- int pidfile_fd;
-
- signal(SIGPIPE, SIG_IGN);
- signal(SIGTERM, SignalHandler);
- signal(SIGINT, SignalHandler);
- signal(SIGHUP, SignalHandler);
-
- base::CommandLine::Init(argc, argv);
- base::CommandLine cl(argc, argv);
-
- if (cl.HasSwitch("help") || argc < 2) {
- printf("%s <options>\n", argv[0]);
- printf(" Proxy options:\n");
- printf(
- "\t--proxy<1..n>=\"<listen ip>,<listen port>,"
- "<ssl cert filename>,\n"
- "\t <ssl key filename>,<http server ip>,"
- "<http server port>,\n"
- "\t [https server ip],[https server port],"
- "<spdy only 0|1>\"\n"
- "\t * The https server ip and port may be left empty if they are"
- " the same as\n"
- "\t the http server fields.\n"
- "\t * spdy only prevents non-spdy https connections from being"
- " passed\n"
- "\t through the proxy listen ip:port.\n"
- "\t--forward-ip-header=<header name>\n"
- "\n Server options:\n"
- "\t--spdy-server=\"<listen ip>,<listen port>,[ssl cert filename],"
- "\n\t [ssl key filename]\"\n"
- "\t--http-server=\"<listen ip>,<listen port>,[ssl cert filename],"
- "\n\t [ssl key filename]\"\n"
- "\t * Leaving the ssl cert and key fields empty will disable ssl"
- " for the\n"
- "\t http and spdy flip servers\n"
- "\n Global options:\n"
- "\t--logdest=<file|system|both>\n"
- "\t--logfile=<logfile>\n"
- "\t--wait-for-iface\n"
- "\t * The flip server will block until the listen ip has been"
- " raised.\n"
- "\t--ssl-session-expiry=<seconds> (default is 300)\n"
- "\t--ssl-disable-compression\n"
- "\t--idle-timeout=<seconds> (default is 300)\n"
- "\t--pidfile=<filepath> (default /var/run/flip-server.pid)\n"
- "\t--help\n");
- exit(0);
- }
-
- if (cl.HasSwitch("pidfile")) {
- pidfile_fd = OpenPidFile(cl.GetSwitchValueASCII("pidfile").c_str());
- } else {
- pidfile_fd = OpenPidFile(PIDFILE);
- }
-
- net::OutputOrdering::set_server_think_time_in_s(FLAGS_server_think_time_in_s);
-
- if (cl.HasSwitch("forward-ip-header")) {
- net::SpdySM::set_forward_ip_header(
- cl.GetSwitchValueASCII("forward-ip-header"));
- net::StreamerSM::set_forward_ip_header(
- cl.GetSwitchValueASCII("forward-ip-header"));
- }
-
- if (cl.HasSwitch("logdest")) {
- std::string log_dest_value = cl.GetSwitchValueASCII("logdest");
- if (log_dest_value.compare("file") == 0) {
- g_proxy_config.log_destination_ = logging::LOG_TO_FILE;
- } else if (log_dest_value.compare("system") == 0) {
- g_proxy_config.log_destination_ = logging::LOG_TO_SYSTEM_DEBUG_LOG;
- } else if (log_dest_value.compare("both") == 0) {
- g_proxy_config.log_destination_ = logging::LOG_TO_ALL;
- } else {
- LOG(FATAL) << "Invalid logging destination value: " << log_dest_value;
- }
- } else {
- g_proxy_config.log_destination_ = logging::LOG_NONE;
- }
-
- if (cl.HasSwitch("logfile")) {
- g_proxy_config.log_filename_ = cl.GetSwitchValueASCII("logfile");
- if (g_proxy_config.log_destination_ == logging::LOG_NONE) {
- g_proxy_config.log_destination_ = logging::LOG_TO_FILE;
- }
- } else if ((g_proxy_config.log_destination_ & logging::LOG_TO_FILE) != 0) {
- LOG(FATAL) << "Logging destination requires a log file to be specified.";
- }
-
- if (cl.HasSwitch("wait-for-iface")) {
- wait_for_iface = true;
- }
-
- if (cl.HasSwitch("ssl-session-expiry")) {
- std::string session_expiry = cl.GetSwitchValueASCII("ssl-session-expiry");
- g_proxy_config.ssl_session_expiry_ = atoi(session_expiry.c_str());
- }
-
- if (cl.HasSwitch("ssl-disable-compression")) {
- g_proxy_config.ssl_disable_compression_ = true;
- }
-
- if (cl.HasSwitch("idle-timeout")) {
- g_proxy_config.idle_socket_timeout_s_ =
- atoi(cl.GetSwitchValueASCII("idle-timeout").c_str());
- }
-
- if (cl.HasSwitch("force_spdy"))
- net::SMConnection::set_force_spdy(true);
-
- logging::LoggingSettings settings;
- settings.logging_dest = g_proxy_config.log_destination_;
- settings.log_file = g_proxy_config.log_filename_.c_str();
- settings.lock_log = logging::DONT_LOCK_LOG_FILE;
- logging::InitLogging(settings);
-
- LOG(INFO) << "Flip SPDY proxy started with configuration:";
- LOG(INFO) << "Logging destination : " << g_proxy_config.log_destination_;
- LOG(INFO) << "Log file : " << g_proxy_config.log_filename_;
- LOG(INFO) << "Forward IP Header : "
- << (net::SpdySM::forward_ip_header().length()
- ? net::SpdySM::forward_ip_header()
- : "<disabled>");
- LOG(INFO) << "Wait for interfaces : " << (wait_for_iface ? "true"
- : "false");
- LOG(INFO) << "Accept backlog size : " << FLAGS_accept_backlog_size;
- LOG(INFO) << "Accepts per wake : " << FLAGS_accepts_per_wake;
- LOG(INFO) << "Disable nagle : " << (FLAGS_disable_nagle ? "true"
- : "false");
- LOG(INFO) << "Reuseport : " << (FLAGS_reuseport ? "true"
- : "false");
- LOG(INFO) << "Force SPDY : " << (FLAGS_force_spdy ? "true"
- : "false");
- LOG(INFO) << "SSL session expiry : "
- << g_proxy_config.ssl_session_expiry_;
- LOG(INFO) << "SSL disable compression : "
- << g_proxy_config.ssl_disable_compression_;
- LOG(INFO) << "Connection idle timeout : "
- << g_proxy_config.idle_socket_timeout_s_;
-
- // Proxy Acceptors
- while (true) {
- i += 1;
- std::stringstream name;
- name << "proxy" << i;
- if (!cl.HasSwitch(name.str())) {
- break;
- }
- std::string value = cl.GetSwitchValueASCII(name.str());
- std::vector<std::string> value_args = base::SplitString(
- value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- CHECK_EQ((unsigned int)9, value_args.size());
- int spdy_only = atoi(value_args[8].c_str());
- // If wait_for_iface is enabled, then this call will block
- // indefinitely until the interface is raised.
- g_proxy_config.AddAcceptor(net::FLIP_HANDLER_PROXY,
- value_args[0],
- value_args[1],
- value_args[2],
- value_args[3],
- value_args[4],
- value_args[5],
- value_args[6],
- value_args[7],
- spdy_only,
- FLAGS_accept_backlog_size,
- FLAGS_disable_nagle,
- FLAGS_accepts_per_wake,
- FLAGS_reuseport,
- wait_for_iface,
- NULL);
- }
-
- // Spdy Server Acceptor
- net::MemoryCache spdy_memory_cache;
- if (cl.HasSwitch("spdy-server")) {
- spdy_memory_cache.AddFiles();
- std::string value = cl.GetSwitchValueASCII("spdy-server");
- std::vector<std::string> value_args = base::SplitString(
- value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- while (value_args.size() < 4)
- value_args.push_back(std::string());
- g_proxy_config.AddAcceptor(net::FLIP_HANDLER_SPDY_SERVER,
- value_args[0],
- value_args[1],
- value_args[2],
- value_args[3],
- std::string(),
- std::string(),
- std::string(),
- std::string(),
- 0,
- FLAGS_accept_backlog_size,
- FLAGS_disable_nagle,
- FLAGS_accepts_per_wake,
- FLAGS_reuseport,
- wait_for_iface,
- &spdy_memory_cache);
- }
-
- // Spdy Server Acceptor
- net::MemoryCache http_memory_cache;
- if (cl.HasSwitch("http-server")) {
- http_memory_cache.AddFiles();
- std::string value = cl.GetSwitchValueASCII("http-server");
- std::vector<std::string> value_args = base::SplitString(
- value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- while (value_args.size() < 4)
- value_args.push_back(std::string());
- g_proxy_config.AddAcceptor(net::FLIP_HANDLER_HTTP_SERVER,
- value_args[0],
- value_args[1],
- value_args[2],
- value_args[3],
- std::string(),
- std::string(),
- std::string(),
- std::string(),
- 0,
- FLAGS_accept_backlog_size,
- FLAGS_disable_nagle,
- FLAGS_accepts_per_wake,
- FLAGS_reuseport,
- wait_for_iface,
- &http_memory_cache);
- }
-
- std::vector<net::SMAcceptorThread*> sm_worker_threads;
-
- for (i = 0; i < g_proxy_config.acceptors_.size(); i++) {
- net::FlipAcceptor* acceptor = g_proxy_config.acceptors_[i];
-
- sm_worker_threads.push_back(new net::SMAcceptorThread(
- acceptor, (net::MemoryCache*)acceptor->memory_cache_));
- // Note that spdy_memory_cache is not threadsafe, it is merely
- // thread compatible. Thus, if ever we are to spawn multiple threads,
- // we either must make the MemoryCache threadsafe, or use
- // a separate MemoryCache for each thread.
- //
- // The latter is what is currently being done as we spawn
- // a separate thread for each http and spdy server acceptor.
-
- sm_worker_threads.back()->InitWorker();
- sm_worker_threads.back()->Start();
- }
-
- while (!g_want_exit) {
- // Close logfile when HUP signal is received. Logging system will
- // automatically reopen on next log message.
- if (g_want_log_close) {
- g_want_log_close = false;
- VLOG(1) << "HUP received, reopening log file.";
- logging::CloseLogFile();
- }
- if (GotQuitFromStdin()) {
- for (unsigned int i = 0; i < sm_worker_threads.size(); ++i) {
- sm_worker_threads[i]->Quit();
- }
- for (unsigned int i = 0; i < sm_worker_threads.size(); ++i) {
- sm_worker_threads[i]->Join();
- }
- break;
- }
- usleep(1000 * 10); // 10 ms
- }
-
- unlink(PIDFILE);
- close(pidfile_fd);
- return 0;
-}
diff --git a/chromium/net/tools/flip_server/flip_test_utils.cc b/chromium/net/tools/flip_server/flip_test_utils.cc
deleted file mode 100644
index c99d7d63377..00000000000
--- a/chromium/net/tools/flip_server/flip_test_utils.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2013 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/flip_server/flip_test_utils.h"
-
-namespace net {
-
-MockSMInterface::MockSMInterface() {}
-
-MockSMInterface::~MockSMInterface() {}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/flip_test_utils.h b/chromium/net/tools/flip_server/flip_test_utils.h
deleted file mode 100644
index a4eab1bb7c0..00000000000
--- a/chromium/net/tools/flip_server/flip_test_utils.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2013 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_FLIP_SERVER_FLIP_TEST_UTILS_H_
-#define NET_TOOLS_FLIP_SERVER_FLIP_TEST_UTILS_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-
-#include "net/tools/flip_server/sm_interface.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-class MockSMInterface : public SMInterface {
- public:
- MockSMInterface();
- virtual ~MockSMInterface();
-
- MOCK_METHOD2(InitSMInterface, void(SMInterface*, int32_t));
- MOCK_METHOD8(InitSMConnection,
- void(SMConnectionPoolInterface*,
- SMInterface*,
- EpollServer*,
- int,
- std::string,
- std::string,
- std::string,
- bool));
- MOCK_METHOD2(ProcessReadInput, size_t(const char*, size_t));
- MOCK_METHOD2(ProcessWriteInput, size_t(const char*, size_t));
- MOCK_METHOD1(SetStreamID, void(uint32_t stream_id));
- MOCK_CONST_METHOD0(MessageFullyRead, bool());
- MOCK_CONST_METHOD0(Error, bool());
- MOCK_CONST_METHOD0(ErrorAsString, const char*());
- MOCK_METHOD0(Reset, void());
- MOCK_METHOD1(ResetForNewInterface, void(int32_t server_idx));
- MOCK_METHOD0(ResetForNewConnection, void());
- MOCK_METHOD0(Cleanup, void());
- MOCK_METHOD0(PostAcceptHook, int());
- MOCK_METHOD3(NewStream, void(uint32_t, uint32_t, const std::string&));
- MOCK_METHOD1(SendEOF, void(uint32_t stream_id));
- MOCK_METHOD1(SendErrorNotFound, void(uint32_t stream_id));
- MOCK_METHOD2(SendSynStream, size_t(uint32_t, const BalsaHeaders&));
- MOCK_METHOD2(SendSynReply, size_t(uint32_t, const BalsaHeaders&));
- MOCK_METHOD5(SendDataFrame,
- void(uint32_t, const char*, int64_t, uint32_t, bool));
- MOCK_METHOD0(GetOutput, void());
- MOCK_METHOD0(set_is_request, void());
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_FLIP_TEST_UTILS_H_
diff --git a/chromium/net/tools/flip_server/http_interface.cc b/chromium/net/tools/flip_server/http_interface.cc
deleted file mode 100644
index 8d5e1738788..00000000000
--- a/chromium/net/tools/flip_server/http_interface.cc
+++ /dev/null
@@ -1,343 +0,0 @@
-// Copyright (c) 2009 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/flip_server/http_interface.h"
-
-#include "net/tools/balsa/balsa_frame.h"
-#include "net/tools/flip_server/flip_config.h"
-#include "net/tools/flip_server/sm_connection.h"
-#include "net/tools/flip_server/spdy_util.h"
-#include "net/tools/flip_server/url_utilities.h"
-
-namespace net {
-
-HttpSM::HttpSM(SMConnection* connection,
- SMInterface* sm_spdy_interface,
- MemoryCache* memory_cache,
- FlipAcceptor* acceptor)
- : http_framer_(new BalsaFrame),
- stream_id_(0),
- server_idx_(-1),
- connection_(connection),
- sm_spdy_interface_(sm_spdy_interface),
- output_list_(connection->output_list()),
- output_ordering_(connection),
- memory_cache_(connection->memory_cache()),
- acceptor_(acceptor) {
- http_framer_->set_balsa_visitor(this);
- http_framer_->set_balsa_headers(&headers_);
- if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY)
- http_framer_->set_is_request(false);
-}
-HttpSM::~HttpSM() {
- Reset();
-}
-
-void HttpSM::ProcessBodyData(const char* input, size_t size) {
- if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process Body Data: stream "
- << stream_id_ << ": size " << size;
- sm_spdy_interface_->SendDataFrame(stream_id_, input, size, 0, false);
- }
-}
-
-void HttpSM::ProcessHeaders(const BalsaHeaders& headers) {
- if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) {
- std::string host =
- UrlUtilities::GetUrlHost(headers.GetHeader("Host").as_string());
- std::string method = headers.request_method().as_string();
- VLOG(1) << ACCEPTOR_CLIENT_IDENT
- << "Received Request: " << headers.request_uri().as_string() << " "
- << method;
- std::string filename =
- EncodeURL(headers.request_uri().as_string(), host, method);
- NewStream(stream_id_, 0, filename);
- stream_id_ += 2;
- } else {
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Received Response from "
- << connection_->server_ip_ << ":" << connection_->server_port_
- << " ";
- sm_spdy_interface_->SendSynReply(stream_id_, headers);
- }
-}
-
-void HttpSM::MessageDone() {
- if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone. Sending EOF: "
- << "stream " << stream_id_;
- sm_spdy_interface_->SendEOF(stream_id_);
- } else {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone.";
- }
-}
-
-void HttpSM::HandleHeaderError(BalsaFrame* framer) { HandleError(); }
-
-void HttpSM::HandleChunkingError(BalsaFrame* framer) { HandleError(); }
-
-void HttpSM::HandleBodyError(BalsaFrame* framer) { HandleError(); }
-
-void HttpSM::HandleError() {
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Error detected";
-}
-
-void HttpSM::AddToOutputOrder(const MemCacheIter& mci) {
- output_ordering_.AddToOutputOrder(mci);
-}
-
-void HttpSM::InitSMInterface(SMInterface* sm_spdy_interface,
- int32_t server_idx) {
- sm_spdy_interface_ = sm_spdy_interface;
- server_idx_ = server_idx;
-}
-
-void HttpSM::InitSMConnection(SMConnectionPoolInterface* connection_pool,
- SMInterface* sm_interface,
- EpollServer* epoll_server,
- int fd,
- std::string server_ip,
- std::string server_port,
- std::string remote_ip,
- bool use_ssl) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Initializing server "
- << "connection.";
- connection_->InitSMConnection(connection_pool,
- sm_interface,
- epoll_server,
- fd,
- server_ip,
- server_port,
- remote_ip,
- use_ssl);
-}
-
-size_t HttpSM::ProcessReadInput(const char* data, size_t len) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process read input: stream "
- << stream_id_;
- return http_framer_->ProcessInput(data, len);
-}
-
-size_t HttpSM::ProcessWriteInput(const char* data, size_t len) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process write input: size "
- << len << ": stream " << stream_id_;
- char* dataPtr = new char[len];
- memcpy(dataPtr, data, len);
- DataFrame* data_frame = new DataFrame;
- data_frame->data = dataPtr;
- data_frame->size = len;
- data_frame->delete_when_done = true;
- connection_->EnqueueDataFrame(data_frame);
- return len;
-}
-
-bool HttpSM::MessageFullyRead() const {
- return http_framer_->MessageFullyRead();
-}
-
-void HttpSM::SetStreamID(uint32_t stream_id) {
- stream_id_ = stream_id;
-}
-
-bool HttpSM::Error() const { return http_framer_->Error(); }
-
-const char* HttpSM::ErrorAsString() const {
- return BalsaFrameEnums::ErrorCodeToString(http_framer_->ErrorCode());
-}
-
-void HttpSM::Reset() {
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Reset: stream " << stream_id_;
- http_framer_->Reset();
-}
-
-void HttpSM::ResetForNewConnection() {
- if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Server connection closing "
- << "to: " << connection_->server_ip_ << ":"
- << connection_->server_port_ << " ";
- }
- // Message has not been fully read, either it is incomplete or the
- // server is closing the connection to signal message end.
- if (!MessageFullyRead()) {
- VLOG(2) << "HTTP response closed before end of file detected. "
- << "Sending EOF to spdy.";
- sm_spdy_interface_->SendEOF(stream_id_);
- }
- output_ordering_.Reset();
- http_framer_->Reset();
- if (sm_spdy_interface_) {
- sm_spdy_interface_->ResetForNewInterface(server_idx_);
- }
-}
-
-void HttpSM::Cleanup() {
- if (!(acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER)) {
- VLOG(2) << "HttpSM Request Fully Read; stream_id: " << stream_id_;
- connection_->Cleanup("request complete");
- }
-}
-
-int HttpSM::PostAcceptHook() { return 1; }
-
-void HttpSM::NewStream(uint32_t stream_id,
- uint32_t priority,
- const std::string& filename) {
- MemCacheIter mci;
- mci.stream_id = stream_id;
- mci.priority = priority;
- if (!memory_cache_->AssignFileData(filename, &mci)) {
- // error creating new stream.
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending ErrorNotFound";
- SendErrorNotFound(stream_id);
- } else {
- AddToOutputOrder(mci);
- }
-}
-
-void HttpSM::SendEOF(uint32_t stream_id) {
- SendEOFImpl(stream_id);
- if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
- sm_spdy_interface_->ResetForNewInterface(server_idx_);
- }
-}
-
-void HttpSM::SendErrorNotFound(uint32_t stream_id) {
- SendErrorNotFoundImpl(stream_id);
-}
-
-size_t HttpSM::SendSynStream(uint32_t stream_id, const BalsaHeaders& headers) {
- return 0;
-}
-
-size_t HttpSM::SendSynReply(uint32_t stream_id, const BalsaHeaders& headers) {
- return SendSynReplyImpl(stream_id, headers);
-}
-
-void HttpSM::SendDataFrame(uint32_t stream_id,
- const char* data,
- int64_t len,
- uint32_t flags,
- bool compress) {
- SendDataFrameImpl(stream_id, data, len, flags, compress);
-}
-
-void HttpSM::SendEOFImpl(uint32_t stream_id) {
- DataFrame* df = new DataFrame;
- df->data = "0\r\n\r\n";
- df->size = 5;
- df->delete_when_done = false;
- EnqueueDataFrame(df);
- if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) {
- Reset();
- }
-}
-
-void HttpSM::SendErrorNotFoundImpl(uint32_t stream_id) {
- BalsaHeaders my_headers;
- my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "404", "Not Found");
- my_headers.RemoveAllOfHeader("content-length");
- my_headers.AppendHeader("transfer-encoding", "chunked");
- SendSynReplyImpl(stream_id, my_headers);
- SendDataFrame(stream_id, "page not found", 14, 0, false);
- SendEOFImpl(stream_id);
- output_ordering_.RemoveStreamId(stream_id);
-}
-
-size_t HttpSM::SendSynReplyImpl(uint32_t stream_id,
- const BalsaHeaders& headers) {
- SimpleBuffer sb;
- headers.WriteHeaderAndEndingToBuffer(&sb);
- DataFrame* df = new DataFrame;
- df->size = sb.ReadableBytes();
- char* buffer = new char[df->size];
- df->data = buffer;
- df->delete_when_done = true;
- sb.Read(buffer, df->size);
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header "
- << stream_id_;
- size_t df_size = df->size;
- EnqueueDataFrame(df);
- return df_size;
-}
-
-size_t HttpSM::SendSynStreamImpl(uint32_t stream_id,
- const BalsaHeaders& headers) {
- SimpleBuffer sb;
- headers.WriteHeaderAndEndingToBuffer(&sb);
- DataFrame* df = new DataFrame;
- df->size = sb.ReadableBytes();
- char* buffer = new char[df->size];
- df->data = buffer;
- df->delete_when_done = true;
- sb.Read(buffer, df->size);
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header "
- << stream_id_;
- size_t df_size = df->size;
- EnqueueDataFrame(df);
- return df_size;
-}
-
-void HttpSM::SendDataFrameImpl(uint32_t stream_id,
- const char* data,
- int64_t len,
- uint32_t flags,
- bool compress) {
- char chunk_buf[128];
- snprintf(chunk_buf, sizeof(chunk_buf), "%x\r\n", (unsigned int)len);
- std::string chunk_description(chunk_buf);
- DataFrame* df = new DataFrame;
- df->size = chunk_description.size() + len + 2;
- char* buffer = new char[df->size];
- df->data = buffer;
- df->delete_when_done = true;
- memcpy(buffer, chunk_description.data(), chunk_description.size());
- memcpy(buffer + chunk_description.size(), data, len);
- memcpy(buffer + chunk_description.size() + len, "\r\n", 2);
- EnqueueDataFrame(df);
-}
-
-void HttpSM::EnqueueDataFrame(DataFrame* df) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Enqueue data frame: stream "
- << stream_id_;
- connection_->EnqueueDataFrame(df);
-}
-
-void HttpSM::GetOutput() {
- MemCacheIter* mci = output_ordering_.GetIter();
- if (mci == NULL) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput: nothing to "
- << "output!?: stream " << stream_id_;
- return;
- }
- if (!mci->transformed_header) {
- mci->bytes_sent =
- SendSynReply(mci->stream_id, *(mci->file_data->headers()));
- mci->transformed_header = true;
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput transformed "
- << "header stream_id: [" << mci->stream_id << "]";
- return;
- }
- if (mci->body_bytes_consumed >= mci->file_data->body().size()) {
- SendEOF(mci->stream_id);
- output_ordering_.RemoveStreamId(mci->stream_id);
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "GetOutput remove_stream_id: ["
- << mci->stream_id << "]";
- return;
- }
- size_t num_to_write =
- mci->file_data->body().size() - mci->body_bytes_consumed;
- if (num_to_write > mci->max_segment_size)
- num_to_write = mci->max_segment_size;
-
- SendDataFrame(mci->stream_id,
- mci->file_data->body().data() + mci->body_bytes_consumed,
- num_to_write,
- 0,
- true);
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput SendDataFrame["
- << mci->stream_id << "]: " << num_to_write;
- mci->body_bytes_consumed += num_to_write;
- mci->bytes_sent += num_to_write;
-}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/http_interface.h b/chromium/net/tools/flip_server/http_interface.h
deleted file mode 100644
index 8bd72aac1eb..00000000000
--- a/chromium/net/tools/flip_server/http_interface.h
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_HTTP_INTERFACE_H_
-#define NET_TOOLS_FLIP_SERVER_HTTP_INTERFACE_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "net/tools/balsa/balsa_headers.h"
-#include "net/tools/balsa/balsa_visitor_interface.h"
-#include "net/tools/flip_server/output_ordering.h"
-#include "net/tools/flip_server/sm_connection.h"
-#include "net/tools/flip_server/sm_interface.h"
-
-namespace net {
-
-class BalsaFrame;
-class DataFrame;
-class EpollServer;
-class FlipAcceptor;
-class MemoryCache;
-
-class HttpSM : public BalsaVisitorInterface, public SMInterface {
- public:
- HttpSM(SMConnection* connection,
- SMInterface* sm_spdy_interface,
- MemoryCache* memory_cache,
- FlipAcceptor* acceptor);
- ~HttpSM() override;
-
- private:
- // BalsaVisitorInterface:
- void ProcessBodyInput(const char* input, size_t size) override {}
- void ProcessBodyData(const char* input, size_t size) override;
- void ProcessHeaderInput(const char* input, size_t size) override {}
- void ProcessTrailerInput(const char* input, size_t size) override {}
- void ProcessHeaders(const BalsaHeaders& headers) override;
- void ProcessRequestFirstLine(const char* line_input,
- size_t line_length,
- const char* method_input,
- size_t method_length,
- const char* request_uri_input,
- size_t request_uri_length,
- const char* version_input,
- size_t version_length) override {}
- void ProcessResponseFirstLine(const char* line_input,
- size_t line_length,
- const char* version_input,
- size_t version_length,
- const char* status_input,
- size_t status_length,
- const char* reason_input,
- size_t reason_length) override {}
- void ProcessChunkLength(size_t chunk_length) override {}
- void ProcessChunkExtensions(const char* input, size_t size) override {}
- void HeaderDone() override {}
- void MessageDone() override;
- void HandleHeaderError(BalsaFrame* framer) override;
- void HandleHeaderWarning(BalsaFrame* framer) override {}
- void HandleChunkingError(BalsaFrame* framer) override;
- void HandleBodyError(BalsaFrame* framer) override;
-
- void HandleError();
-
- public:
- void AddToOutputOrder(const MemCacheIter& mci);
- BalsaFrame* spdy_framer() { return http_framer_.get(); }
- void set_is_request() override {}
- const OutputOrdering& output_ordering() const { return output_ordering_; }
-
- // SMInterface:
- void InitSMInterface(SMInterface* sm_spdy_interface,
- int32_t server_idx) override;
- void InitSMConnection(SMConnectionPoolInterface* connection_pool,
- SMInterface* sm_interface,
- EpollServer* epoll_server,
- int fd,
- std::string server_ip,
- std::string server_port,
- std::string remote_ip,
- bool use_ssl) override;
- size_t ProcessReadInput(const char* data, size_t len) override;
- size_t ProcessWriteInput(const char* data, size_t len) override;
- bool MessageFullyRead() const override;
- void SetStreamID(uint32_t stream_id) override;
- bool Error() const override;
- const char* ErrorAsString() const override;
- void Reset() override;
- void ResetForNewInterface(int32_t server_idx) override {}
- void ResetForNewConnection() override;
- void Cleanup() override;
- int PostAcceptHook() override;
-
- void NewStream(uint32_t stream_id,
- uint32_t priority,
- const std::string& filename) override;
- void SendEOF(uint32_t stream_id) override;
- void SendErrorNotFound(uint32_t stream_id) override;
- size_t SendSynStream(uint32_t stream_id,
- const BalsaHeaders& headers) override;
- size_t SendSynReply(uint32_t stream_id, const BalsaHeaders& headers) override;
- void SendDataFrame(uint32_t stream_id,
- const char* data,
- int64_t len,
- uint32_t flags,
- bool compress) override;
-
- private:
- void SendEOFImpl(uint32_t stream_id);
- void SendErrorNotFoundImpl(uint32_t stream_id);
- void SendOKResponseImpl(uint32_t stream_id, const std::string& output);
- size_t SendSynReplyImpl(uint32_t stream_id, const BalsaHeaders& headers);
- size_t SendSynStreamImpl(uint32_t stream_id, const BalsaHeaders& headers);
- void SendDataFrameImpl(uint32_t stream_id,
- const char* data,
- int64_t len,
- uint32_t flags,
- bool compress);
- void EnqueueDataFrame(DataFrame* df);
- void GetOutput() override;
-
- private:
- std::unique_ptr<BalsaFrame> http_framer_;
- BalsaHeaders headers_;
- uint32_t stream_id_;
- int32_t server_idx_;
-
- SMConnection* connection_;
- SMInterface* sm_spdy_interface_;
- OutputList* output_list_;
- OutputOrdering output_ordering_;
- MemoryCache* memory_cache_;
- FlipAcceptor* acceptor_;
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_HTTP_INTERFACE_H_
diff --git a/chromium/net/tools/flip_server/http_interface_test.cc b/chromium/net/tools/flip_server/http_interface_test.cc
deleted file mode 100644
index 9123f9f5fc7..00000000000
--- a/chromium/net/tools/flip_server/http_interface_test.cc
+++ /dev/null
@@ -1,491 +0,0 @@
-// Copyright 2013 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/flip_server/http_interface.h"
-
-#include <list>
-#include <memory>
-
-#include "base/stl_util.h"
-#include "base/strings/string_piece.h"
-#include "net/tools/balsa/balsa_enums.h"
-#include "net/tools/balsa/balsa_frame.h"
-#include "net/tools/balsa/balsa_headers.h"
-#include "net/tools/flip_server/flip_config.h"
-#include "net/tools/flip_server/flip_test_utils.h"
-#include "net/tools/flip_server/mem_cache.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-using ::base::StringPiece;
-using ::testing::_;
-using ::testing::InSequence;
-
-namespace {
-
-class MockSMConnection : public SMConnection {
- public:
- MockSMConnection(EpollServer* epoll_server,
- SSLState* ssl_state,
- MemoryCache* memory_cache,
- FlipAcceptor* acceptor,
- std::string log_prefix)
- : SMConnection(epoll_server,
- ssl_state,
- memory_cache,
- acceptor,
- log_prefix) {}
-
- MOCK_METHOD0(Cleanup, void());
- MOCK_METHOD8(InitSMConnection,
- void(SMConnectionPoolInterface*,
- SMInterface*,
- EpollServer*,
- int,
- std::string,
- std::string,
- std::string,
- bool));
-};
-
-class FlipHttpSMTest : public ::testing::Test {
- public:
- explicit FlipHttpSMTest(FlipHandlerType type = FLIP_HANDLER_PROXY) {
- SSLState* ssl_state = NULL;
- mock_another_interface_.reset(new MockSMInterface);
- memory_cache_.reset(new MemoryCache);
- acceptor_.reset(new FlipAcceptor(type,
- "127.0.0.1",
- "8941",
- "ssl_cert_filename",
- "ssl_key_filename",
- "127.0.0.1",
- "8942",
- "127.0.0.1",
- "8943",
- 1,
- 0,
- true,
- 1,
- false,
- true,
- NULL));
- epoll_server_.reset(new EpollServer);
- connection_.reset(new MockSMConnection(epoll_server_.get(),
- ssl_state,
- memory_cache_.get(),
- acceptor_.get(),
- "log_prefix"));
-
- interface_.reset(new HttpSM(connection_.get(),
- mock_another_interface_.get(),
- memory_cache_.get(),
- acceptor_.get()));
- }
-
- void TearDown() override {
- if (acceptor_->listen_fd_ >= 0) {
- epoll_server_->UnregisterFD(acceptor_->listen_fd_);
- close(acceptor_->listen_fd_);
- acceptor_->listen_fd_ = -1;
- }
- STLDeleteElements(connection_->output_list());
- }
-
- bool HasStream(uint32_t stream_id) {
- return interface_->output_ordering().ExistsInPriorityMaps(stream_id);
- }
-
- protected:
- std::unique_ptr<MockSMInterface> mock_another_interface_;
- std::unique_ptr<MemoryCache> memory_cache_;
- std::unique_ptr<FlipAcceptor> acceptor_;
- std::unique_ptr<EpollServer> epoll_server_;
- std::unique_ptr<MockSMConnection> connection_;
- std::unique_ptr<HttpSM> interface_;
-};
-
-class FlipHttpSMProxyTest : public FlipHttpSMTest {
- public:
- FlipHttpSMProxyTest() : FlipHttpSMTest(FLIP_HANDLER_PROXY) {}
- ~FlipHttpSMProxyTest() override {}
-};
-
-class FlipHttpSMHttpTest : public FlipHttpSMTest {
- public:
- FlipHttpSMHttpTest() : FlipHttpSMTest(FLIP_HANDLER_HTTP_SERVER) {}
- ~FlipHttpSMHttpTest() override {}
-};
-
-class FlipHttpSMSpdyTest : public FlipHttpSMTest {
- public:
- FlipHttpSMSpdyTest() : FlipHttpSMTest(FLIP_HANDLER_SPDY_SERVER) {}
- ~FlipHttpSMSpdyTest() override {}
-};
-
-TEST_F(FlipHttpSMTest, Construct) {
- ASSERT_FALSE(interface_->spdy_framer()->is_request());
-}
-
-TEST_F(FlipHttpSMTest, AddToOutputOrder) {
- uint32_t stream_id = 13;
- MemCacheIter mci;
- mci.stream_id = stream_id;
-
- {
- BalsaHeaders headers;
- std::string filename = "foobar";
- memory_cache_->InsertFile(&headers, filename, "");
- mci.file_data = memory_cache_->GetFileData(filename);
- }
-
- interface_->AddToOutputOrder(mci);
- ASSERT_TRUE(HasStream(stream_id));
-}
-
-TEST_F(FlipHttpSMTest, InitSMInterface) {
- std::unique_ptr<MockSMInterface> mock(new MockSMInterface);
- {
- InSequence s;
- EXPECT_CALL(*mock_another_interface_, SendEOF(_));
- EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_));
- EXPECT_CALL(*mock, SendEOF(_));
- EXPECT_CALL(*mock, ResetForNewInterface(_));
- }
-
- interface_->ResetForNewConnection();
- interface_->InitSMInterface(mock.get(), 0);
- interface_->ResetForNewConnection();
-}
-
-TEST_F(FlipHttpSMTest, InitSMConnection) {
- EXPECT_CALL(*connection_, InitSMConnection(_, _, _, _, _, _, _, _));
-
- interface_->InitSMConnection(NULL, NULL, NULL, 0, "", "", "", false);
-}
-
-TEST_F(FlipHttpSMTest, ProcessReadInput) {
- std::string data =
- "HTTP/1.1 200 OK\r\n"
- "Content-Length: 14\r\n\r\n"
- "hello, world\r\n";
- testing::MockFunction<void(int)> checkpoint; // NOLINT
- {
- InSequence s;
- EXPECT_CALL(*mock_another_interface_, SendSynReply(_, _));
- EXPECT_CALL(checkpoint, Call(0));
- EXPECT_CALL(*mock_another_interface_, SendDataFrame(_, _, _, _, _));
- EXPECT_CALL(*mock_another_interface_, SendEOF(_));
- }
-
- ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
- interface_->spdy_framer()->ParseState());
-
- size_t read = interface_->ProcessReadInput(data.data(), data.size());
- ASSERT_EQ(39u, read);
- checkpoint.Call(0);
- read += interface_->ProcessReadInput(&data.data()[read], data.size() - read);
- ASSERT_EQ(data.size(), read);
- ASSERT_EQ(BalsaFrameEnums::MESSAGE_FULLY_READ,
- interface_->spdy_framer()->ParseState());
- ASSERT_TRUE(interface_->MessageFullyRead());
-}
-
-TEST_F(FlipHttpSMTest, ProcessWriteInput) {
- std::string data = "hello, world";
- interface_->ProcessWriteInput(data.data(), data.size());
-
- ASSERT_EQ(1u, connection_->output_list()->size());
- std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
- DataFrame* df = *i++;
- ASSERT_EQ(data, StringPiece(df->data, df->size));
- ASSERT_EQ(connection_->output_list()->end(), i);
-}
-
-TEST_F(FlipHttpSMTest, Reset) {
- std::string data = "HTTP/1.1 200 OK\r\n\r\n";
- testing::MockFunction<void(int)> checkpoint; // NOLINT
- {
- InSequence s;
- EXPECT_CALL(*mock_another_interface_, SendSynReply(_, _));
- EXPECT_CALL(checkpoint, Call(0));
- }
-
- ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
- interface_->spdy_framer()->ParseState());
-
- interface_->ProcessReadInput(data.data(), data.size());
- checkpoint.Call(0);
- ASSERT_FALSE(interface_->MessageFullyRead());
- ASSERT_EQ(BalsaFrameEnums::READING_UNTIL_CLOSE,
- interface_->spdy_framer()->ParseState());
-
- interface_->Reset();
- ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
- interface_->spdy_framer()->ParseState());
-}
-
-TEST_F(FlipHttpSMTest, ResetForNewConnection) {
- std::string data = "HTTP/1.1 200 OK\r\n\r\n";
- testing::MockFunction<void(int)> checkpoint; // NOLINT
- {
- InSequence s;
- EXPECT_CALL(*mock_another_interface_, SendSynReply(_, _));
- EXPECT_CALL(checkpoint, Call(0));
- EXPECT_CALL(*mock_another_interface_, SendEOF(_));
- EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_));
- }
-
- ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
- interface_->spdy_framer()->ParseState());
-
- interface_->ProcessReadInput(data.data(), data.size());
- checkpoint.Call(0);
- ASSERT_FALSE(interface_->MessageFullyRead());
- ASSERT_EQ(BalsaFrameEnums::READING_UNTIL_CLOSE,
- interface_->spdy_framer()->ParseState());
-
- interface_->ResetForNewConnection();
- ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
- interface_->spdy_framer()->ParseState());
-}
-
-TEST_F(FlipHttpSMTest, NewStream) {
- uint32_t stream_id = 4;
- {
- BalsaHeaders headers;
- std::string filename = "foobar";
- memory_cache_->InsertFile(&headers, filename, "");
- }
-
- interface_->NewStream(stream_id, 1, "foobar");
- ASSERT_TRUE(HasStream(stream_id));
-}
-
-TEST_F(FlipHttpSMTest, NewStreamError) {
- std::string syn_reply =
- "HTTP/1.1 404 Not Found\r\n"
- "transfer-encoding: chunked\r\n\r\n";
- std::string body = "e\r\npage not found\r\n";
- uint32_t stream_id = 4;
-
- ASSERT_FALSE(HasStream(stream_id));
- interface_->NewStream(stream_id, 1, "foobar");
-
- ASSERT_EQ(3u, connection_->output_list()->size());
- std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
- DataFrame* df = *i++;
- ASSERT_EQ(syn_reply, StringPiece(df->data, df->size));
- df = *i++;
- ASSERT_EQ(body, StringPiece(df->data, df->size));
- df = *i++;
- ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size));
- ASSERT_FALSE(HasStream(stream_id));
-}
-
-TEST_F(FlipHttpSMTest, SendErrorNotFound) {
- std::string syn_reply =
- "HTTP/1.1 404 Not Found\r\n"
- "transfer-encoding: chunked\r\n\r\n";
- std::string body = "e\r\npage not found\r\n";
- uint32_t stream_id = 13;
- MemCacheIter mci;
- mci.stream_id = stream_id;
-
- {
- BalsaHeaders headers;
- std::string filename = "foobar";
- memory_cache_->InsertFile(&headers, filename, "");
- mci.file_data = memory_cache_->GetFileData(filename);
- }
-
- interface_->AddToOutputOrder(mci);
- ASSERT_TRUE(HasStream(stream_id));
- interface_->SendErrorNotFound(stream_id);
-
- ASSERT_EQ(3u, connection_->output_list()->size());
- std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
- DataFrame* df = *i++;
- ASSERT_EQ(syn_reply, StringPiece(df->data, df->size));
- df = *i++;
- ASSERT_EQ(body, StringPiece(df->data, df->size));
- df = *i++;
- ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size));
- ASSERT_FALSE(HasStream(stream_id));
-}
-
-TEST_F(FlipHttpSMTest, SendSynStream) {
- std::string expected =
- "GET / HTTP/1.0\r\n"
- "key1: value1\r\n\r\n";
- BalsaHeaders headers;
- headers.SetResponseFirstlineFromStringPieces("GET", "/path", "HTTP/1.0");
- headers.AppendHeader("key1", "value1");
- interface_->SendSynStream(18, headers);
-
- // TODO(yhirano): Is this behavior correct?
- ASSERT_EQ(0u, connection_->output_list()->size());
-}
-
-TEST_F(FlipHttpSMTest, SendSynReply) {
- std::string expected =
- "HTTP/1.1 200 OK\r\n"
- "key1: value1\r\n\r\n";
- BalsaHeaders headers;
- headers.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
- headers.AppendHeader("key1", "value1");
- interface_->SendSynReply(18, headers);
-
- ASSERT_EQ(1u, connection_->output_list()->size());
- DataFrame* df = connection_->output_list()->front();
- ASSERT_EQ(expected, StringPiece(df->data, df->size));
-}
-
-TEST_F(FlipHttpSMTest, SendDataFrame) {
- std::string data = "foo bar baz";
- interface_->SendDataFrame(12, data.data(), data.size(), 0, false);
-
- ASSERT_EQ(1u, connection_->output_list()->size());
- DataFrame* df = connection_->output_list()->front();
- ASSERT_EQ("b\r\nfoo bar baz\r\n", StringPiece(df->data, df->size));
-}
-
-TEST_F(FlipHttpSMProxyTest, ProcessBodyData) {
- BalsaVisitorInterface* visitor = interface_.get();
- std::string data = "hello, world";
- {
- InSequence s;
- EXPECT_CALL(*mock_another_interface_,
- SendDataFrame(0, data.data(), data.size(), 0, false));
- }
- visitor->ProcessBodyData(data.data(), data.size());
-}
-
-// --
-// FlipHttpSMProxyTest
-
-TEST_F(FlipHttpSMProxyTest, ProcessHeaders) {
- BalsaVisitorInterface* visitor = interface_.get();
- {
- InSequence s;
- EXPECT_CALL(*mock_another_interface_, SendSynReply(0, _));
- }
- BalsaHeaders headers;
- visitor->ProcessHeaders(headers);
-}
-
-TEST_F(FlipHttpSMProxyTest, MessageDone) {
- BalsaVisitorInterface* visitor = interface_.get();
- {
- InSequence s;
- EXPECT_CALL(*mock_another_interface_, SendEOF(0));
- }
- visitor->MessageDone();
-}
-
-TEST_F(FlipHttpSMProxyTest, Cleanup) {
- EXPECT_CALL(*connection_, Cleanup()).Times(0);
- interface_->Cleanup();
-}
-
-TEST_F(FlipHttpSMProxyTest, SendEOF) {
- {
- InSequence s;
- EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_));
- }
- interface_->SendEOF(32);
- ASSERT_EQ(1u, connection_->output_list()->size());
- DataFrame* df = connection_->output_list()->front();
- ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size));
-}
-
-// --
-// FlipHttpSMHttpTest
-
-TEST_F(FlipHttpSMHttpTest, ProcessHeaders) {
- BalsaVisitorInterface* visitor = interface_.get();
- {
- BalsaHeaders headers;
- std::string filename = "GET_/path/file";
- memory_cache_->InsertFile(&headers, filename, "");
- }
-
- BalsaHeaders headers;
- headers.AppendHeader("Host", "example.com");
- headers.SetRequestFirstlineFromStringPieces("GET", "/path/file", "HTTP/1.0");
- uint32_t stream_id = 133;
- interface_->SetStreamID(stream_id);
- ASSERT_FALSE(HasStream(stream_id));
- visitor->ProcessHeaders(headers);
- ASSERT_TRUE(HasStream(stream_id));
-}
-
-TEST_F(FlipHttpSMHttpTest, MessageDone) {
- BalsaVisitorInterface* visitor = interface_.get();
- {
- InSequence s;
- EXPECT_CALL(*mock_another_interface_, SendEOF(0)).Times(0);
- }
- visitor->MessageDone();
-}
-
-TEST_F(FlipHttpSMHttpTest, Cleanup) {
- EXPECT_CALL(*connection_, Cleanup()).Times(0);
- interface_->Cleanup();
-}
-
-TEST_F(FlipHttpSMHttpTest, SendEOF) {
- {
- InSequence s;
- EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_)).Times(0);
- }
- interface_->SendEOF(32);
- ASSERT_EQ(1u, connection_->output_list()->size());
- DataFrame* df = connection_->output_list()->front();
- ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size));
-}
-
-// --
-// FlipHttpSMSpdyTest
-
-TEST_F(FlipHttpSMSpdyTest, ProcessHeaders) {
- BalsaVisitorInterface* visitor = interface_.get();
- {
- InSequence s;
- EXPECT_CALL(*mock_another_interface_, SendSynReply(0, _));
- }
- BalsaHeaders headers;
- visitor->ProcessHeaders(headers);
-}
-
-TEST_F(FlipHttpSMSpdyTest, MessageDone) {
- BalsaVisitorInterface* visitor = interface_.get();
- {
- InSequence s;
- EXPECT_CALL(*mock_another_interface_, SendEOF(0)).Times(0);
- }
- visitor->MessageDone();
-}
-
-TEST_F(FlipHttpSMSpdyTest, Cleanup) {
- EXPECT_CALL(*connection_, Cleanup()).Times(0);
- interface_->Cleanup();
-}
-
-TEST_F(FlipHttpSMSpdyTest, SendEOF) {
- {
- InSequence s;
- EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_)).Times(0);
- }
- interface_->SendEOF(32);
- ASSERT_EQ(1u, connection_->output_list()->size());
- DataFrame* df = connection_->output_list()->front();
- ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size));
-}
-
-} // namespace
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/mem_cache.cc b/chromium/net/tools/flip_server/mem_cache.cc
deleted file mode 100644
index dae5d4026bc..00000000000
--- a/chromium/net/tools/flip_server/mem_cache.cc
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright (c) 2009 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/flip_server/mem_cache.h"
-
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <deque>
-#include <map>
-#include <string>
-
-#include "base/memory/ptr_util.h"
-#include "base/strings/string_util.h"
-#include "net/tools/balsa/balsa_frame.h"
-#include "net/tools/balsa/balsa_headers.h"
-#include "net/tools/flip_server/url_to_filename_encoder.h"
-#include "net/tools/flip_server/url_utilities.h"
-
-namespace {
-// The directory where cache locates);
-const char FLAGS_cache_base_dir[] = ".";
-} // namespace
-
-namespace net {
-
-void StoreBodyAndHeadersVisitor::ProcessBodyData(const char* input,
- size_t size) {
- body.append(input, size);
-}
-
-void StoreBodyAndHeadersVisitor::HandleHeaderError(BalsaFrame* framer) {
- HandleError();
-}
-
-void StoreBodyAndHeadersVisitor::HandleHeaderWarning(BalsaFrame* framer) {
- HandleError();
-}
-
-void StoreBodyAndHeadersVisitor::HandleChunkingError(BalsaFrame* framer) {
- HandleError();
-}
-
-void StoreBodyAndHeadersVisitor::HandleBodyError(BalsaFrame* framer) {
- HandleError();
-}
-
-FileData::FileData(const BalsaHeaders* headers,
- const std::string& filename,
- const std::string& body)
- : filename_(filename), body_(body) {
- if (headers) {
- headers_.reset(new BalsaHeaders);
- headers_->CopyFrom(*headers);
- }
-}
-
-FileData::FileData() {}
-
-FileData::~FileData() {}
-
-MemoryCache::MemoryCache() : cwd_(FLAGS_cache_base_dir) {}
-MemoryCache::~MemoryCache() {}
-
-void MemoryCache::AddFiles() {
- std::deque<std::string> paths;
- paths.push_back(cwd_ + "/GET_");
- DIR* current_dir = NULL;
- while (!paths.empty()) {
- while (current_dir == NULL && !paths.empty()) {
- std::string current_dir_name = paths.front();
- VLOG(1) << "Attempting to open dir: \"" << current_dir_name << "\"";
- current_dir = opendir(current_dir_name.c_str());
- paths.pop_front();
-
- if (current_dir == NULL) {
- perror("Unable to open directory. ");
- current_dir_name.clear();
- continue;
- }
-
- if (current_dir) {
- VLOG(1) << "Succeeded opening";
- for (struct dirent* dir_data = readdir(current_dir); dir_data != NULL;
- dir_data = readdir(current_dir)) {
- std::string current_entry_name =
- current_dir_name + "/" + dir_data->d_name;
- if (dir_data->d_type == DT_REG) {
- VLOG(1) << "Found file: " << current_entry_name;
- ReadAndStoreFileContents(current_entry_name.c_str());
- } else if (dir_data->d_type == DT_DIR) {
- VLOG(1) << "Found subdir: " << current_entry_name;
- if (std::string(dir_data->d_name) != "." &&
- std::string(dir_data->d_name) != "..") {
- VLOG(1) << "Adding to search path: " << current_entry_name;
- paths.push_front(current_entry_name);
- }
- }
- }
- VLOG(1) << "Oops, no data left. Closing dir.";
- closedir(current_dir);
- current_dir = NULL;
- }
- }
- }
-}
-
-void MemoryCache::ReadToString(const char* filename, std::string* output) {
- output->clear();
- int fd = open(filename, 0, "r");
- if (fd == -1)
- return;
- char buffer[4096];
- ssize_t read_status = read(fd, buffer, sizeof(buffer));
- while (read_status > 0) {
- output->append(buffer, static_cast<size_t>(read_status));
- do {
- read_status = read(fd, buffer, sizeof(buffer));
- } while (read_status <= 0 && errno == EINTR);
- }
- close(fd);
-}
-
-void MemoryCache::ReadAndStoreFileContents(const char* filename) {
- StoreBodyAndHeadersVisitor visitor;
- BalsaFrame framer;
- framer.set_balsa_visitor(&visitor);
- framer.set_balsa_headers(&(visitor.headers));
- std::string filename_contents;
- ReadToString(filename, &filename_contents);
-
- // Ugly hack to make everything look like 1.1.
- if (filename_contents.find("HTTP/1.0") == 0)
- filename_contents[7] = '1';
-
- size_t pos = 0;
- size_t old_pos = 0;
- while (true) {
- old_pos = pos;
- pos += framer.ProcessInput(filename_contents.data() + pos,
- filename_contents.size() - pos);
- if (framer.Error() || pos == old_pos) {
- LOG(ERROR) << "Unable to make forward progress, or error"
- " framing file: " << filename;
- if (framer.Error()) {
- LOG(INFO) << "********************************************ERROR!";
- return;
- }
- return;
- }
- if (framer.MessageFullyRead()) {
- // If no Content-Length or Transfer-Encoding was captured in the
- // file, then the rest of the data is the body. Many of the captures
- // from within Chrome don't have content-lengths.
- if (!visitor.body.length())
- visitor.body = filename_contents.substr(pos);
- break;
- }
- }
- visitor.headers.RemoveAllOfHeader("content-length");
- visitor.headers.RemoveAllOfHeader("transfer-encoding");
- visitor.headers.RemoveAllOfHeader("connection");
- visitor.headers.AppendHeader("transfer-encoding", "chunked");
- visitor.headers.AppendHeader("connection", "keep-alive");
-
-// Experiment with changing headers for forcing use of cached
-// versions of content.
-// TODO(mbelshe) REMOVE ME
-#if 0
- // TODO(mbelshe) append current date.
- visitor.headers.RemoveAllOfHeader("date");
- if (visitor.headers.HasHeader("expires")) {
- visitor.headers.RemoveAllOfHeader("expires");
- visitor.headers.AppendHeader("expires",
- "Fri, 30 Aug, 2019 12:00:00 GMT");
- }
-#endif
- DCHECK_GE(std::string(filename).size(), cwd_.size() + 1);
- DCHECK_EQ(std::string(filename).substr(0, cwd_.size()), cwd_);
- DCHECK_EQ(filename[cwd_.size()], '/');
- std::string filename_stripped = std::string(filename).substr(cwd_.size() + 1);
- LOG(INFO) << "Adding file (" << visitor.body.length()
- << " bytes): " << filename_stripped;
- size_t slash_pos = filename_stripped.find('/');
- if (slash_pos == std::string::npos) {
- slash_pos = filename_stripped.size();
- }
- InsertFile(
- &visitor.headers, filename_stripped.substr(0, slash_pos), visitor.body);
-}
-
-FileData* MemoryCache::GetFileData(const std::string& filename) {
- Files::iterator fi = files_.end();
- if (base::EndsWith(filename, ".html", base::CompareCase::SENSITIVE)) {
- fi = files_.find(filename.substr(0, filename.size() - 5) + ".http");
- }
- if (fi == files_.end())
- fi = files_.find(filename);
-
- if (fi == files_.end()) {
- return NULL;
- }
- return fi->second.get();
-}
-
-bool MemoryCache::AssignFileData(const std::string& filename,
- MemCacheIter* mci) {
- mci->file_data = GetFileData(filename);
- if (mci->file_data == NULL) {
- LOG(ERROR) << "Could not find file data for " << filename;
- return false;
- }
- return true;
-}
-
-void MemoryCache::InsertFile(const BalsaHeaders* headers,
- const std::string& filename,
- const std::string& body) {
- InsertFile(new FileData(headers, filename, body));
-}
-
-void MemoryCache::InsertFile(FileData* file_data) {
- Files::iterator it = files_.find(file_data->filename());
- if (it != files_.end()) {
- it->second.reset(file_data);
- } else {
- files_.insert(
- std::make_pair(file_data->filename(), base::WrapUnique(file_data)));
- }
-}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/mem_cache.h b/chromium/net/tools/flip_server/mem_cache.h
deleted file mode 100644
index f073cb6aa07..00000000000
--- a/chromium/net/tools/flip_server/mem_cache.h
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_MEM_CACHE_H_
-#define NET_TOOLS_FLIP_SERVER_MEM_CACHE_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "net/tools/balsa/balsa_headers.h"
-#include "net/tools/balsa/balsa_visitor_interface.h"
-#include "net/tools/flip_server/constants.h"
-
-namespace net {
-
-class StoreBodyAndHeadersVisitor : public BalsaVisitorInterface {
- public:
- void HandleError() { error_ = true; }
-
- // BalsaVisitorInterface:
- void ProcessBodyInput(const char* input, size_t size) override {}
- void ProcessBodyData(const char* input, size_t size) override;
- void ProcessHeaderInput(const char* input, size_t size) override {}
- void ProcessTrailerInput(const char* input, size_t size) override {}
- void ProcessHeaders(const BalsaHeaders& headers) override {
- // nothing to do here-- we're assuming that the BalsaFrame has
- // been handed our headers.
- }
- void ProcessRequestFirstLine(const char* line_input,
- size_t line_length,
- const char* method_input,
- size_t method_length,
- const char* request_uri_input,
- size_t request_uri_length,
- const char* version_input,
- size_t version_length) override {}
- void ProcessResponseFirstLine(const char* line_input,
- size_t line_length,
- const char* version_input,
- size_t version_length,
- const char* status_input,
- size_t status_length,
- const char* reason_input,
- size_t reason_length) override {}
- void ProcessChunkLength(size_t chunk_length) override {}
- void ProcessChunkExtensions(const char* input, size_t size) override {}
- void HeaderDone() override {}
- void MessageDone() override {}
- void HandleHeaderError(BalsaFrame* framer) override;
- void HandleHeaderWarning(BalsaFrame* framer) override;
- void HandleChunkingError(BalsaFrame* framer) override;
- void HandleBodyError(BalsaFrame* framer) override;
-
- BalsaHeaders headers;
- std::string body;
- bool error_;
-};
-
-class FileData {
- public:
- FileData();
- FileData(const BalsaHeaders* headers,
- const std::string& filename,
- const std::string& body);
- ~FileData();
-
- BalsaHeaders* headers() { return headers_.get(); }
- const BalsaHeaders* headers() const { return headers_.get(); }
-
- const std::string& filename() { return filename_; }
- const std::string& body() { return body_; }
-
- private:
- std::unique_ptr<BalsaHeaders> headers_;
- std::string filename_;
- std::string body_;
-
- DISALLOW_COPY_AND_ASSIGN(FileData);
-};
-
-class MemCacheIter {
- public:
- MemCacheIter()
- : file_data(NULL),
- priority(0),
- transformed_header(false),
- body_bytes_consumed(0),
- stream_id(0),
- max_segment_size(kInitialDataSendersThreshold),
- bytes_sent(0) {}
- explicit MemCacheIter(FileData* fd)
- : file_data(fd),
- priority(0),
- transformed_header(false),
- body_bytes_consumed(0),
- stream_id(0),
- max_segment_size(kInitialDataSendersThreshold),
- bytes_sent(0) {}
- FileData* file_data;
- int priority;
- bool transformed_header;
- size_t body_bytes_consumed;
- uint32_t stream_id;
- uint32_t max_segment_size;
- size_t bytes_sent;
-};
-
-class MemoryCache {
- public:
- using Files = std::map<std::string, std::unique_ptr<FileData>>;
-
- public:
- MemoryCache();
- virtual ~MemoryCache();
-
- void AddFiles();
-
- // virtual for unittests
- virtual void ReadToString(const char* filename, std::string* output);
-
- void ReadAndStoreFileContents(const char* filename);
-
- FileData* GetFileData(const std::string& filename);
-
- bool AssignFileData(const std::string& filename, MemCacheIter* mci);
-
- // For unittests
- void InsertFile(const BalsaHeaders* headers,
- const std::string& filename,
- const std::string& body);
-
- private:
- void InsertFile(FileData* file_data);
-
- Files files_;
- std::string cwd_;
-};
-
-class NotifierInterface {
- public:
- virtual ~NotifierInterface() {}
- virtual void Notify() = 0;
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_MEM_CACHE_H_
diff --git a/chromium/net/tools/flip_server/mem_cache_test.cc b/chromium/net/tools/flip_server/mem_cache_test.cc
deleted file mode 100644
index 0ddb74bc907..00000000000
--- a/chromium/net/tools/flip_server/mem_cache_test.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2013 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/flip_server/mem_cache.h"
-
-#include "net/tools/balsa/balsa_headers.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-namespace {
-
-class MemoryCacheWithFakeReadToString : public MemoryCache {
- public:
- ~MemoryCacheWithFakeReadToString() override {}
-
- void ReadToString(const char* filename, std::string* output) override {
- *output = data_map_[filename];
- }
-
- std::map<std::string, std::string> data_map_;
-};
-
-class FlipMemoryCacheTest : public ::testing::Test {
- public:
- FlipMemoryCacheTest() : mem_cache_(new MemoryCacheWithFakeReadToString) {}
-
- protected:
- std::unique_ptr<MemoryCacheWithFakeReadToString> mem_cache_;
-};
-
-TEST_F(FlipMemoryCacheTest, EmptyCache) {
- MemCacheIter mci;
- mci.stream_id = 0;
- ASSERT_EQ(NULL, mem_cache_->GetFileData("./foo"));
- ASSERT_EQ(NULL, mem_cache_->GetFileData("./bar"));
- ASSERT_FALSE(mem_cache_->AssignFileData("./hello", &mci));
-}
-
-TEST_F(FlipMemoryCacheTest, ReadAndStoreFileContents) {
- FileData* foo;
- FileData* hello;
-
- mem_cache_->data_map_["./foo"] = "bar";
- mem_cache_->data_map_["./hello"] =
- "HTTP/1.0 200 OK\r\n"
- "key1: value1\r\n"
- "key2: value2\r\n\r\n"
- "body: body\r\n";
- mem_cache_->ReadAndStoreFileContents("./foo");
- mem_cache_->ReadAndStoreFileContents("./hello");
-
- foo = mem_cache_->GetFileData("foo");
- hello = mem_cache_->GetFileData("hello");
-
- // "./foo" content is broken.
- ASSERT_EQ(NULL, foo);
- ASSERT_FALSE(NULL == hello);
- ASSERT_EQ(hello, mem_cache_->GetFileData("hello"));
-
- // "HTTP/1.0" is rewritten to "HTTP/1.1".
- ASSERT_EQ("HTTP/1.1", hello->headers()->response_version());
- ASSERT_EQ("200", hello->headers()->response_code());
- ASSERT_EQ("OK", hello->headers()->response_reason_phrase());
- ASSERT_EQ(4,
- std::distance(hello->headers()->header_lines_begin(),
- hello->headers()->header_lines_end()));
- ASSERT_TRUE(hello->headers()->HasHeader("key1"));
- ASSERT_TRUE(hello->headers()->HasHeader("key2"));
- ASSERT_TRUE(hello->headers()->HasHeader("transfer-encoding"));
- ASSERT_TRUE(hello->headers()->HasHeader("connection"));
- ASSERT_EQ("value1", hello->headers()->GetHeaderPosition("key1")->second);
- ASSERT_EQ("value2", hello->headers()->GetHeaderPosition("key2")->second);
- ASSERT_EQ("chunked",
- hello->headers()->GetHeaderPosition("transfer-encoding")->second);
- ASSERT_EQ("keep-alive",
- hello->headers()->GetHeaderPosition("connection")->second);
- ASSERT_EQ("body: body\r\n", hello->body());
- ASSERT_EQ("hello", hello->filename());
-}
-
-TEST_F(FlipMemoryCacheTest, GetFileDataForHtmlFile) {
- FileData* hello_html;
-
- mem_cache_->data_map_["./hello.http"] =
- "HTTP/1.0 200 OK\r\n"
- "key1: value1\r\n"
- "key2: value2\r\n\r\n"
- "body: body\r\n";
-
- mem_cache_->ReadAndStoreFileContents("./hello.http");
- hello_html = mem_cache_->GetFileData("hello.html");
- ASSERT_FALSE(NULL == hello_html);
- ASSERT_EQ(hello_html, mem_cache_->GetFileData("hello.http"));
-}
-
-} // namespace
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/output_ordering.cc b/chromium/net/tools/flip_server/output_ordering.cc
deleted file mode 100644
index 24e92c0c000..00000000000
--- a/chromium/net/tools/flip_server/output_ordering.cc
+++ /dev/null
@@ -1,180 +0,0 @@
-// Copyright (c) 2009 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/flip_server/output_ordering.h"
-
-#include <utility>
-
-#include "net/tools/flip_server/flip_config.h"
-#include "net/tools/flip_server/sm_connection.h"
-
-namespace net {
-
-OutputOrdering::PriorityMapPointer::PriorityMapPointer()
- : ring(NULL), alarm_enabled(false) {}
-
-OutputOrdering::PriorityMapPointer::PriorityMapPointer(
- const PriorityMapPointer& other) = default;
-
-OutputOrdering::PriorityMapPointer::~PriorityMapPointer() {}
-
-// static
-double OutputOrdering::server_think_time_in_s_ = 0.0;
-
-OutputOrdering::OutputOrdering(SMConnectionInterface* connection)
- : first_data_senders_threshold_(kInitialDataSendersThreshold),
- connection_(connection) {
- if (connection)
- epoll_server_ = connection->epoll_server();
-}
-
-OutputOrdering::~OutputOrdering() { Reset(); }
-
-void OutputOrdering::Reset() {
- while (!stream_ids_.empty()) {
- StreamIdToPriorityMap::iterator sitpmi = stream_ids_.begin();
- PriorityMapPointer& pmp = sitpmi->second;
- if (pmp.alarm_enabled) {
- epoll_server_->UnregisterAlarm(pmp.alarm_token);
- }
- stream_ids_.erase(sitpmi);
- }
- priority_map_.clear();
- first_data_senders_.clear();
-}
-
-bool OutputOrdering::ExistsInPriorityMaps(uint32_t stream_id) const {
- StreamIdToPriorityMap::const_iterator sitpmi = stream_ids_.find(stream_id);
- return sitpmi != stream_ids_.end();
-}
-
-OutputOrdering::BeginOutputtingAlarm::BeginOutputtingAlarm(
- OutputOrdering* oo,
- OutputOrdering::PriorityMapPointer* pmp,
- const MemCacheIter& mci)
- : output_ordering_(oo), pmp_(pmp), mci_(mci), epoll_server_(NULL) {}
-
-OutputOrdering::BeginOutputtingAlarm::~BeginOutputtingAlarm() {
- if (epoll_server_ && pmp_->alarm_enabled)
- epoll_server_->UnregisterAlarm(pmp_->alarm_token);
-}
-
-int64_t OutputOrdering::BeginOutputtingAlarm::OnAlarm() {
- OnUnregistration();
- output_ordering_->MoveToActive(pmp_, mci_);
- VLOG(2) << "ON ALARM! Should now start to output...";
- delete this;
- return 0;
-}
-
-void OutputOrdering::BeginOutputtingAlarm::OnRegistration(
- const EpollServer::AlarmRegToken& tok,
- EpollServer* eps) {
- epoll_server_ = eps;
- pmp_->alarm_token = tok;
- pmp_->alarm_enabled = true;
-}
-
-void OutputOrdering::BeginOutputtingAlarm::OnUnregistration() {
- pmp_->alarm_enabled = false;
- delete this;
-}
-
-void OutputOrdering::BeginOutputtingAlarm::OnShutdown(EpollServer* eps) {
- OnUnregistration();
-}
-
-void OutputOrdering::MoveToActive(PriorityMapPointer* pmp, MemCacheIter mci) {
- VLOG(2) << "Moving to active!";
- first_data_senders_.push_back(mci);
- pmp->ring = &first_data_senders_;
- pmp->it = first_data_senders_.end();
- --pmp->it;
- connection_->ReadyToSend();
-}
-
-void OutputOrdering::AddToOutputOrder(const MemCacheIter& mci) {
- if (ExistsInPriorityMaps(mci.stream_id))
- LOG(ERROR) << "OOps, already was inserted here?!";
-
- double think_time_in_s = server_think_time_in_s_;
- std::string x_server_latency =
- mci.file_data->headers()->GetHeader("X-Server-Latency").as_string();
- if (!x_server_latency.empty()) {
- char* endp;
- double tmp_think_time_in_s = strtod(x_server_latency.c_str(), &endp);
- if (endp != x_server_latency.c_str() + x_server_latency.size()) {
- LOG(ERROR) << "Unable to understand X-Server-Latency of: "
- << x_server_latency
- << " for resource: " << mci.file_data->filename().c_str();
- } else {
- think_time_in_s = tmp_think_time_in_s;
- }
- }
- StreamIdToPriorityMap::iterator sitpmi;
- sitpmi = stream_ids_.insert(std::pair<uint32_t, PriorityMapPointer>(
- mci.stream_id, PriorityMapPointer()))
- .first;
- PriorityMapPointer& pmp = sitpmi->second;
-
- BeginOutputtingAlarm* boa = new BeginOutputtingAlarm(this, &pmp, mci);
- VLOG(1) << "Server think time: " << think_time_in_s;
- epoll_server_->RegisterAlarmApproximateDelta(think_time_in_s * 1000000, boa);
-}
-
-void OutputOrdering::SpliceToPriorityRing(PriorityRing::iterator pri) {
- MemCacheIter& mci = *pri;
- PriorityMap::iterator pmi = priority_map_.find(mci.priority);
- if (pmi == priority_map_.end()) {
- pmi = priority_map_.insert(std::pair<uint32_t, PriorityRing>(
- mci.priority, PriorityRing()))
- .first;
- }
-
- pmi->second.splice(pmi->second.end(), first_data_senders_, pri);
- StreamIdToPriorityMap::iterator sitpmi = stream_ids_.find(mci.stream_id);
- sitpmi->second.ring = &(pmi->second);
-}
-
-MemCacheIter* OutputOrdering::GetIter() {
- while (!first_data_senders_.empty()) {
- MemCacheIter& mci = first_data_senders_.front();
- if (mci.bytes_sent >= first_data_senders_threshold_) {
- SpliceToPriorityRing(first_data_senders_.begin());
- } else {
- first_data_senders_.splice(first_data_senders_.end(),
- first_data_senders_,
- first_data_senders_.begin());
- mci.max_segment_size = kInitialDataSendersThreshold;
- return &mci;
- }
- }
- while (!priority_map_.empty()) {
- PriorityRing& first_ring = priority_map_.begin()->second;
- if (first_ring.empty()) {
- priority_map_.erase(priority_map_.begin());
- continue;
- }
- MemCacheIter& mci = first_ring.front();
- first_ring.splice(first_ring.end(), first_ring, first_ring.begin());
- mci.max_segment_size = kSpdySegmentSize;
- return &mci;
- }
- return NULL;
-}
-
-void OutputOrdering::RemoveStreamId(uint32_t stream_id) {
- StreamIdToPriorityMap::iterator sitpmi = stream_ids_.find(stream_id);
- if (sitpmi == stream_ids_.end())
- return;
-
- PriorityMapPointer& pmp = sitpmi->second;
- if (pmp.alarm_enabled)
- epoll_server_->UnregisterAlarm(pmp.alarm_token);
- else
- pmp.ring->erase(pmp.it);
- stream_ids_.erase(sitpmi);
-}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/output_ordering.h b/chromium/net/tools/flip_server/output_ordering.h
deleted file mode 100644
index ecd32a2ba47..00000000000
--- a/chromium/net/tools/flip_server/output_ordering.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_OUTPUT_ORDERING_H_
-#define NET_TOOLS_FLIP_SERVER_OUTPUT_ORDERING_H_
-
-#include <stdint.h>
-
-#include <list>
-#include <map>
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "net/tools/epoll_server/epoll_server.h"
-#include "net/tools/flip_server/constants.h"
-#include "net/tools/flip_server/mem_cache.h"
-
-namespace net {
-
-class SMConnectionInterface;
-
-class OutputOrdering {
- public:
- typedef std::list<MemCacheIter> PriorityRing;
- typedef std::map<uint32_t, PriorityRing> PriorityMap;
-
- struct PriorityMapPointer {
- PriorityMapPointer();
- PriorityMapPointer(const PriorityMapPointer& other);
- ~PriorityMapPointer();
- PriorityRing* ring;
- PriorityRing::iterator it;
- bool alarm_enabled;
- EpollServer::AlarmRegToken alarm_token;
- };
-
- typedef std::map<uint32_t, PriorityMapPointer> StreamIdToPriorityMap;
-
- StreamIdToPriorityMap stream_ids_;
- PriorityMap priority_map_;
- PriorityRing first_data_senders_;
- uint32_t first_data_senders_threshold_; // when you've passed this, you're no
- // longer a first_data_sender...
- SMConnectionInterface* connection_;
- EpollServer* epoll_server_;
-
- explicit OutputOrdering(SMConnectionInterface* connection);
- ~OutputOrdering();
- void Reset();
- bool ExistsInPriorityMaps(uint32_t stream_id) const;
-
- struct BeginOutputtingAlarm : public EpollAlarmCallbackInterface {
- public:
- BeginOutputtingAlarm(OutputOrdering* oo,
- OutputOrdering::PriorityMapPointer* pmp,
- const MemCacheIter& mci);
- ~BeginOutputtingAlarm() override;
-
- // EpollAlarmCallbackInterface:
- int64_t OnAlarm() override;
- void OnRegistration(const EpollServer::AlarmRegToken& tok,
- EpollServer* eps) override;
- void OnUnregistration() override;
- void OnShutdown(EpollServer* eps) override;
-
- private:
- OutputOrdering* output_ordering_;
- OutputOrdering::PriorityMapPointer* pmp_;
- MemCacheIter mci_;
- EpollServer* epoll_server_;
- };
-
- void MoveToActive(PriorityMapPointer* pmp, MemCacheIter mci);
- void AddToOutputOrder(const MemCacheIter& mci);
- void SpliceToPriorityRing(PriorityRing::iterator pri);
- MemCacheIter* GetIter();
- void RemoveStreamId(uint32_t stream_id);
-
- static double server_think_time_in_s() { return server_think_time_in_s_; }
- static void set_server_think_time_in_s(double value) {
- server_think_time_in_s_ = value;
- }
-
- private:
- static double server_think_time_in_s_;
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_OUTPUT_ORDERING_H_
diff --git a/chromium/net/tools/flip_server/ring_buffer.cc b/chromium/net/tools/flip_server/ring_buffer.cc
deleted file mode 100644
index 16c278bcdef..00000000000
--- a/chromium/net/tools/flip_server/ring_buffer.cc
+++ /dev/null
@@ -1,241 +0,0 @@
-// Copyright (c) 2009 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/flip_server/ring_buffer.h"
-#include "base/logging.h"
-
-namespace net {
-
-RingBuffer::RingBuffer(int buffer_size)
- : buffer_(new char[buffer_size]),
- buffer_size_(buffer_size),
- bytes_used_(0),
- read_idx_(0),
- write_idx_(0) {}
-
-RingBuffer::~RingBuffer() {}
-
-int RingBuffer::ReadableBytes() const { return bytes_used_; }
-
-int RingBuffer::BufferSize() const { return buffer_size_; }
-
-int RingBuffer::BytesFree() const { return BufferSize() - ReadableBytes(); }
-
-bool RingBuffer::Empty() const { return ReadableBytes() == 0; }
-
-bool RingBuffer::Full() const { return ReadableBytes() == BufferSize(); }
-
-// Returns the number of characters written.
-// Appends up-to-'size' bytes to the ringbuffer.
-int RingBuffer::Write(const char* bytes, int size) {
- CHECK_GE(size, 0);
-#if 1
- char* wptr;
- int wsize;
- GetWritablePtr(&wptr, &wsize);
- int bytes_remaining = size;
- int bytes_written = 0;
-
- while (wsize && bytes_remaining) {
- if (wsize > bytes_remaining) {
- wsize = bytes_remaining;
- }
- memcpy(wptr, bytes + bytes_written, wsize);
- bytes_written += wsize;
- bytes_remaining -= wsize;
- AdvanceWritablePtr(wsize);
- GetWritablePtr(&wptr, &wsize);
- }
- return bytes_written;
-#else
- const char* p = bytes;
-
- int bytes_to_write = size;
- int bytes_available = BytesFree();
- if (bytes_available < bytes_to_write) {
- bytes_to_write = bytes_available;
- }
- const char* end = bytes + bytes_to_write;
-
- while (p != end) {
- this->buffer_[this->write_idx_] = *p;
- ++p;
- ++this->write_idx_;
- if (this->write_idx_ >= this->buffer_size_) {
- this->write_idx_ = 0;
- }
- }
- bytes_used_ += bytes_to_write;
- return bytes_to_write;
-#endif
-}
-
-// Sets *ptr to the beginning of writable memory, and sets *size to the size
-// available for writing using this pointer.
-void RingBuffer::GetWritablePtr(char** ptr, int* size) const {
- *ptr = buffer_.get() + write_idx_;
-
- if (bytes_used_ == buffer_size_) {
- *size = 0;
- } else if (read_idx_ > write_idx_) {
- *size = read_idx_ - write_idx_;
- } else {
- *size = buffer_size_ - write_idx_;
- }
-}
-
-// Sets *ptr to the beginning of readable memory, and sets *size to the size
-// available for reading using this pointer.
-void RingBuffer::GetReadablePtr(char** ptr, int* size) const {
- *ptr = buffer_.get() + read_idx_;
-
- if (bytes_used_ == 0) {
- *size = 0;
- } else if (write_idx_ > read_idx_) {
- *size = write_idx_ - read_idx_;
- } else {
- *size = buffer_size_ - read_idx_;
- }
-}
-
-// returns the number of bytes read into
-int RingBuffer::Read(char* bytes, int size) {
- CHECK_GE(size, 0);
-#if 1
- char* rptr;
- int rsize;
- GetReadablePtr(&rptr, &rsize);
- int bytes_remaining = size;
- int bytes_read = 0;
-
- while (rsize && bytes_remaining) {
- if (rsize > bytes_remaining) {
- rsize = bytes_remaining;
- }
- memcpy(bytes + bytes_read, rptr, rsize);
- bytes_read += rsize;
- bytes_remaining -= rsize;
- AdvanceReadablePtr(rsize);
- GetReadablePtr(&rptr, &rsize);
- }
- return bytes_read;
-#else
- char* p = bytes;
- int bytes_to_read = size;
- int bytes_used = ReadableBytes();
- if (bytes_used < bytes_to_read) {
- bytes_to_read = bytes_used;
- }
- char* end = bytes + bytes_to_read;
-
- while (p != end) {
- *p = this->buffer_[this->read_idx_];
- ++p;
- ++this->read_idx_;
- if (this->read_idx_ >= this->buffer_size_) {
- this->read_idx_ = 0;
- }
- }
- this->bytes_used_ -= bytes_to_read;
- return bytes_to_read;
-#endif
-}
-
-void RingBuffer::Clear() {
- bytes_used_ = 0;
- write_idx_ = 0;
- read_idx_ = 0;
-}
-
-bool RingBuffer::Reserve(int size) {
- DCHECK_GT(size, 0);
- char* write_ptr = NULL;
- int write_size = 0;
- GetWritablePtr(&write_ptr, &write_size);
-
- if (write_size < size) {
- char* read_ptr = NULL;
- int read_size = 0;
- GetReadablePtr(&read_ptr, &read_size);
- if (size <= BytesFree()) {
- // The fact that the total Free size is big enough but writable size is
- // not means that the writeable region is broken into two pieces: only
- // possible if the read_idx < write_idx. If write_idx < read_idx, then
- // the writeable region must be contiguous: [write_idx, read_idx). There
- // is no work to be done for the latter.
- DCHECK_LE(read_idx_, write_idx_);
- DCHECK_EQ(read_size, ReadableBytes());
- if (read_idx_ < write_idx_) {
- // Writeable area fragmented, consolidate it.
- memmove(buffer_.get(), read_ptr, read_size);
- read_idx_ = 0;
- write_idx_ = read_size;
- } else if (read_idx_ == write_idx_) {
- // No unconsumed data in the buffer, simply reset the indexes.
- DCHECK_EQ(ReadableBytes(), 0);
- read_idx_ = 0;
- write_idx_ = 0;
- }
- } else {
- Resize(ReadableBytes() + size);
- }
- }
- DCHECK_LE(size, buffer_size_ - write_idx_);
- return true;
-}
-
-void RingBuffer::AdvanceReadablePtr(int amount_to_consume) {
- CHECK_GE(amount_to_consume, 0);
- if (amount_to_consume >= bytes_used_) {
- Clear();
- return;
- }
- read_idx_ += amount_to_consume;
- read_idx_ %= buffer_size_;
- bytes_used_ -= amount_to_consume;
-}
-
-void RingBuffer::AdvanceWritablePtr(int amount_to_produce) {
- CHECK_GE(amount_to_produce, 0);
- CHECK_LE(amount_to_produce, BytesFree());
- write_idx_ += amount_to_produce;
- write_idx_ %= buffer_size_;
- bytes_used_ += amount_to_produce;
-}
-
-void RingBuffer::Resize(int buffer_size) {
- CHECK_GE(buffer_size, 0);
- if (buffer_size == buffer_size_)
- return;
-
- char* new_buffer = new char[buffer_size];
- if (buffer_size < bytes_used_) {
- // consume the oldest data.
- AdvanceReadablePtr(bytes_used_ - buffer_size);
- }
-
- int bytes_written = 0;
- int bytes_used = bytes_used_;
- while (true) {
- int size;
- char* ptr;
- GetReadablePtr(&ptr, &size);
- if (size == 0)
- break;
- if (size > buffer_size) {
- size = buffer_size;
- }
- memcpy(new_buffer + bytes_written, ptr, size);
- bytes_written += size;
- AdvanceReadablePtr(size);
- }
- buffer_.reset(new_buffer);
-
- buffer_size_ = buffer_size;
- bytes_used_ = bytes_used;
- read_idx_ = 0;
- write_idx_ = bytes_used_ % buffer_size_;
-}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/ring_buffer.h b/chromium/net/tools/flip_server/ring_buffer.h
deleted file mode 100644
index 538595c657d..00000000000
--- a/chromium/net/tools/flip_server/ring_buffer.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_RING_BUFFER_H__
-#define NET_TOOLS_FLIP_SERVER_RING_BUFFER_H__
-
-#include <memory>
-
-#include "base/compiler_specific.h"
-#include "net/tools/balsa/buffer_interface.h"
-
-namespace net {
-
-// The ring buffer is a circular buffer, that is, reads or writes may wrap
-// around the end of the linear memory contained by the class (and back to
-// the beginning). This is a good choice when you want to use a fixed amount
-// of buffering and don't want to be moving memory around a lot.
-//
-// What is the penalty for using this over a normal, linear buffer?
-// Reading all the data may take two operations, and
-// writing all the data may take two operations.
-//
-// In the proxy, this class is used as a fixed size buffer between
-// clients and servers (so that the memory size is constrained).
-
-class RingBuffer : public BufferInterface {
- public:
- explicit RingBuffer(int buffer_size);
- ~RingBuffer() override;
-
- // Resize the buffer to the size specified here. If the buffer_size passed
- // in here is smaller than the amount of data in the buffer, then the oldest
- // data will be dropped, but all other data will be saved.
- // This means: If the buffer size is increasing, all data that was resident
- // in the buffer prior to this call will be resident after this call.
- void Resize(int buffer_size);
-
- // The following functions all override pure virtual functions
- // in BufferInterface. See buffer_interface.h for a description
- // of what they do if the function isn't documented here.
- int ReadableBytes() const override;
- int BufferSize() const override;
- int BytesFree() const override;
-
- bool Empty() const override;
- bool Full() const override;
-
- // returns the number of characters written.
- // appends up-to-'size' bytes to the ringbuffer.
- int Write(const char* bytes, int size) override;
-
- // Stores a pointer into the ring buffer in *ptr, and stores the number of
- // characters which are allowed to be written in *size.
- // If there are no writable bytes available, then *size will contain 0.
- void GetWritablePtr(char** ptr, int* size) const override;
-
- // Stores a pointer into the ring buffer in *ptr, and stores the number of
- // characters which are allowed to be read in *size.
- // If there are no readable bytes available, then *size will contain 0.
- void GetReadablePtr(char** ptr, int* size) const override;
-
- // Returns the number of bytes read into 'bytes'.
- int Read(char* bytes, int size) override;
-
- // Removes all data from the ring buffer.
- void Clear() override;
-
- // Reserves contiguous writable empty space in the buffer of size bytes.
- // Since the point of this class is to have a fixed size buffer, be careful
- // not to inadvertently resize the buffer using Reserve(). If the reserve
- // size is <= BytesFree(), it is guaranteed that the buffer size will not
- // change.
- // This can be an expensive operation, it may new a buffer copy all existing
- // data and delete the old data. Even if the existing buffer does not need
- // to be resized, unread data may still need to be non-destructively copied
- // to consolidate fragmented free space. If the size requested is less than
- // or equal to BytesFree(), it is guaranteed that the buffer size will not
- // change.
- bool Reserve(int size) override;
-
- // Removes the oldest 'amount_to_advance' characters.
- // If amount_to_consume > ReadableBytes(), this performs a Clear() instead.
- void AdvanceReadablePtr(int amount_to_advance) override;
-
- // Moves the internal pointers around such that the amount of data specified
- // here is expected to already be resident (as if it was Written).
- void AdvanceWritablePtr(int amount_to_advance) override;
-
- protected:
- int read_idx() const { return read_idx_; }
- int write_idx() const { return write_idx_; }
- int bytes_used() const { return bytes_used_; }
- int buffer_size() const { return buffer_size_; }
- const char* buffer() const { return buffer_.get(); }
-
- int set_read_idx(int idx) { return read_idx_ = idx; }
- int set_write_idx(int idx) { return write_idx_ = idx; }
-
- private:
- std::unique_ptr<char[]> buffer_;
- int buffer_size_;
- int bytes_used_;
- int read_idx_;
- int write_idx_;
-
- RingBuffer(const RingBuffer&);
- void operator=(const RingBuffer&);
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_RING_BUFFER_H__
diff --git a/chromium/net/tools/flip_server/run_all_tests.cc b/chromium/net/tools/flip_server/run_all_tests.cc
deleted file mode 100644
index 6acc286b9fd..00000000000
--- a/chromium/net/tools/flip_server/run_all_tests.cc
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2013 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/test/test_suite.h"
-#include "build/build_config.h"
-
-int main(int argc, char** argv) { return base::TestSuite(argc, argv).Run(); }
diff --git a/chromium/net/tools/flip_server/sm_connection.cc b/chromium/net/tools/flip_server/sm_connection.cc
deleted file mode 100644
index 9c232f97a74..00000000000
--- a/chromium/net/tools/flip_server/sm_connection.cc
+++ /dev/null
@@ -1,661 +0,0 @@
-// Copyright (c) 2009 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/flip_server/sm_connection.h"
-
-#include <errno.h>
-#include <netinet/tcp.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <list>
-#include <string>
-
-#include "net/tools/flip_server/constants.h"
-#include "net/tools/flip_server/flip_config.h"
-#include "net/tools/flip_server/http_interface.h"
-#include "net/tools/flip_server/spdy_interface.h"
-#include "net/tools/flip_server/spdy_ssl.h"
-#include "net/tools/flip_server/streamer_interface.h"
-#include "net/tools/flip_server/tcp_socket_util.h"
-
-namespace net {
-
-// static
-bool SMConnection::force_spdy_ = false;
-
-DataFrame::~DataFrame() {
- if (delete_when_done)
- delete[] data;
-}
-
-SMConnection::SMConnection(EpollServer* epoll_server,
- SSLState* ssl_state,
- MemoryCache* memory_cache,
- FlipAcceptor* acceptor,
- std::string log_prefix)
- : last_read_time_(0),
- fd_(-1),
- events_(0),
- registered_in_epoll_server_(false),
- initialized_(false),
- protocol_detected_(false),
- connection_complete_(false),
- connection_pool_(NULL),
- epoll_server_(epoll_server),
- ssl_state_(ssl_state),
- memory_cache_(memory_cache),
- acceptor_(acceptor),
- read_buffer_(kSpdySegmentSize * 40),
- sm_spdy_interface_(NULL),
- sm_http_interface_(NULL),
- sm_streamer_interface_(NULL),
- sm_interface_(NULL),
- log_prefix_(log_prefix),
- max_bytes_sent_per_dowrite_(4096),
- ssl_(NULL) {}
-
-SMConnection::~SMConnection() {
- if (initialized())
- Reset();
-}
-
-EpollServer* SMConnection::epoll_server() { return epoll_server_; }
-
-void SMConnection::ReadyToSend() {
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "Setting ready to send: EPOLLIN | EPOLLOUT";
- epoll_server_->SetFDReady(fd_, EPOLLIN | EPOLLOUT);
-}
-
-void SMConnection::EnqueueDataFrame(DataFrame* df) {
- output_list_.push_back(df);
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "EnqueueDataFrame: "
- << "size = " << df->size << ": Setting FD ready.";
- ReadyToSend();
-}
-
-void SMConnection::InitSMConnection(SMConnectionPoolInterface* connection_pool,
- SMInterface* sm_interface,
- EpollServer* epoll_server,
- int fd,
- std::string server_ip,
- std::string server_port,
- std::string remote_ip,
- bool use_ssl) {
- if (initialized_) {
- LOG(FATAL) << "Attempted to initialize already initialized server";
- return;
- }
-
- client_ip_ = remote_ip;
-
- if (fd == -1) {
- // If fd == -1, then we are initializing a new connection that will
- // connect to the backend.
- //
- // ret: -1 == error
- // 0 == connection in progress
- // 1 == connection complete
- // TODO(kelindsay): is_numeric_host_address value needs to be detected
- server_ip_ = server_ip;
- server_port_ = server_port;
- int ret = CreateTCPClientSocket(
- server_ip, server_port, true, acceptor_->disable_nagle_, &fd_);
-
- if (ret < 0) {
- LOG(ERROR) << "-1 Could not create connected socket";
- return;
- } else if (ret == 1) {
- DCHECK_NE(-1, fd_);
- connection_complete_ = true;
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "Connection complete to: " << server_ip_ << ":" << server_port_
- << " ";
- }
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "Connecting to server: " << server_ip_ << ":" << server_port_
- << " ";
- } else {
- // If fd != -1 then we are initializing a connection that has just been
- // accepted from the listen socket.
- connection_complete_ = true;
- if (epoll_server_ && registered_in_epoll_server_ && fd_ != -1) {
- epoll_server_->UnregisterFD(fd_);
- }
- if (fd_ != -1) {
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "Closing pre-existing fd";
- close(fd_);
- fd_ = -1;
- }
-
- fd_ = fd;
- }
-
- registered_in_epoll_server_ = false;
- // Set the last read time here as the idle checker will start from
- // now.
- last_read_time_ = time(NULL);
- initialized_ = true;
-
- connection_pool_ = connection_pool;
- epoll_server_ = epoll_server;
-
- if (sm_interface) {
- sm_interface_ = sm_interface;
- protocol_detected_ = true;
- }
-
- read_buffer_.Clear();
-
- epoll_server_->RegisterFD(fd_, this, EPOLLIN | EPOLLOUT | EPOLLET);
-
- if (use_ssl) {
- ssl_ = CreateSSLContext(ssl_state_->ssl_ctx);
- SSL_set_fd(ssl_, fd_);
- PrintSslError();
- }
-}
-
-void SMConnection::CorkSocket() {
- int state = 1;
- int rv = setsockopt(fd_, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
- if (rv < 0)
- VLOG(1) << "setsockopt(CORK): " << errno;
-}
-
-void SMConnection::UncorkSocket() {
- int state = 0;
- int rv = setsockopt(fd_, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
- if (rv < 0)
- VLOG(1) << "setsockopt(CORK): " << errno;
-}
-
-int SMConnection::Send(const char* data, int len, int flags) {
- int rv = 0;
- CorkSocket();
- if (ssl_) {
- ssize_t bytes_written = 0;
- // Write smallish chunks to SSL so that we don't have large
- // multi-packet TLS records to receive before being able to handle
- // the data. We don't have to be too careful here, because our data
- // frames are already getting chunked appropriately, and those are
- // the most likely "big" frames.
- while (len > 0) {
- const int kMaxTLSRecordSize = 1500;
- const char* ptr = &(data[bytes_written]);
- int chunksize = std::min(len, kMaxTLSRecordSize);
- rv = SSL_write(ssl_, ptr, chunksize);
- VLOG(2) << "SSLWrite(" << chunksize << " bytes): " << rv;
- if (rv <= 0) {
- switch (SSL_get_error(ssl_, rv)) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- case SSL_ERROR_WANT_ACCEPT:
- case SSL_ERROR_WANT_CONNECT:
- rv = -2;
- break;
- default:
- PrintSslError();
- break;
- }
- break;
- }
- bytes_written += rv;
- len -= rv;
- if (rv != chunksize)
- break; // If we couldn't write everything, we're implicitly stalled
- }
- // If we wrote some data, return that count. Otherwise
- // return the stall error.
- if (bytes_written > 0)
- rv = bytes_written;
- } else {
- rv = send(fd_, data, len, flags);
- }
- if (!(flags & MSG_MORE))
- UncorkSocket();
- return rv;
-}
-
-void SMConnection::OnRegistration(EpollServer* eps, int fd, int event_mask) {
- registered_in_epoll_server_ = true;
-}
-
-void SMConnection::OnEvent(int fd, EpollEvent* event) {
- events_ |= event->in_events;
- HandleEvents();
- if (events_) {
- event->out_ready_mask = events_;
- events_ = 0;
- }
-}
-
-void SMConnection::OnUnregistration(int fd, bool replaced) {
- registered_in_epoll_server_ = false;
-}
-
-void SMConnection::OnShutdown(EpollServer* eps, int fd) {
- Cleanup("OnShutdown");
- return;
-}
-
-void SMConnection::Cleanup(const char* cleanup) {
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "Cleanup: " << cleanup;
- if (!initialized_)
- return;
- Reset();
- if (connection_pool_)
- connection_pool_->SMConnectionDone(this);
- if (sm_interface_)
- sm_interface_->ResetForNewConnection();
- last_read_time_ = 0;
-}
-
-void SMConnection::HandleEvents() {
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "Received: " << EpollServer::EventMaskToString(events_).c_str();
-
- if (events_ & EPOLLIN) {
- if (!DoRead())
- goto handle_close_or_error;
- }
-
- if (events_ & EPOLLOUT) {
- // Check if we have connected or not
- if (connection_complete_ == false) {
- int sock_error;
- socklen_t sock_error_len = sizeof(sock_error);
- int ret =
- getsockopt(fd_, SOL_SOCKET, SO_ERROR, &sock_error, &sock_error_len);
- if (ret != 0) {
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "getsockopt error: " << errno << ": " << strerror(errno);
- goto handle_close_or_error;
- }
- if (sock_error == 0) {
- connection_complete_ = true;
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "Connection complete to " << server_ip_ << ":"
- << server_port_ << " ";
- } else if (sock_error == EINPROGRESS) {
- return;
- } else {
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "error connecting to server";
- goto handle_close_or_error;
- }
- }
- if (!DoWrite())
- goto handle_close_or_error;
- }
-
- if (events_ & (EPOLLHUP | EPOLLERR)) {
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "!!! Got HUP or ERR";
- goto handle_close_or_error;
- }
- return;
-
- handle_close_or_error:
- Cleanup("HandleEvents");
-}
-
-// Decide if SPDY was negotiated.
-bool SMConnection::WasSpdyNegotiated(SpdyMajorVersion* version_negotiated) {
- *version_negotiated = SPDY3;
- if (force_spdy())
- return true;
-
- // If this is an SSL connection, check if NPN specifies SPDY.
- if (ssl_) {
- const unsigned char* npn_proto;
- unsigned int npn_proto_len;
- SSL_get0_next_proto_negotiated(ssl_, &npn_proto, &npn_proto_len);
- if (npn_proto_len > 0) {
- std::string npn_proto_str((const char*)npn_proto, npn_proto_len);
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "NPN protocol detected: " << npn_proto_str;
- if (!strncmp(reinterpret_cast<const char*>(npn_proto),
- "spdy/3",
- npn_proto_len)) {
- *version_negotiated = SPDY3;
- return true;
- }
- if (!strncmp(reinterpret_cast<const char*>(npn_proto),
- "spdy/4a2",
- npn_proto_len)) {
- *version_negotiated = HTTP2;
- return true;
- }
- }
- }
-
- return false;
-}
-
-bool SMConnection::SetupProtocolInterfaces() {
- DCHECK(!protocol_detected_);
- protocol_detected_ = true;
-
- SpdyMajorVersion version;
- bool spdy_negotiated = WasSpdyNegotiated(&version);
- bool using_ssl = ssl_ != NULL;
-
- if (using_ssl)
- VLOG(1) << (SSL_session_reused(ssl_) ? "Resumed" : "Renegotiated")
- << " SSL Session.";
-
- if (acceptor_->spdy_only_ && !spdy_negotiated) {
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "SPDY proxy only, closing HTTPS connection.";
- return false;
- }
-
- switch (acceptor_->flip_handler_type_) {
- case FLIP_HANDLER_HTTP_SERVER: {
- DCHECK(!spdy_negotiated);
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << (sm_http_interface_ ? "Creating" : "Reusing")
- << " HTTP interface.";
- if (!sm_http_interface_)
- sm_http_interface_ = new HttpSM(this, NULL, memory_cache_, acceptor_);
- sm_interface_ = sm_http_interface_;
- break;
- }
- case FLIP_HANDLER_PROXY: {
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << (sm_streamer_interface_ ? "Creating" : "Reusing")
- << " PROXY Streamer interface.";
- if (!sm_streamer_interface_) {
- sm_streamer_interface_ =
- new StreamerSM(this, NULL, epoll_server_, acceptor_);
- sm_streamer_interface_->set_is_request();
- }
- sm_interface_ = sm_streamer_interface_;
- // If spdy is not negotiated, the streamer interface will proxy all
- // data to the origin server.
- if (!spdy_negotiated)
- break;
- }
- // Otherwise fall through into the case below.
- case FLIP_HANDLER_SPDY_SERVER: {
- DCHECK(spdy_negotiated);
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << (sm_spdy_interface_ ? "Creating" : "Reusing")
- << " SPDY interface.";
- if (sm_spdy_interface_)
- sm_spdy_interface_->CreateFramer(version);
- else
- sm_spdy_interface_ = new SpdySM(
- this, NULL, epoll_server_, memory_cache_, acceptor_, version);
- sm_interface_ = sm_spdy_interface_;
- break;
- }
- }
-
- CorkSocket();
- if (!sm_interface_->PostAcceptHook())
- return false;
-
- return true;
-}
-
-bool SMConnection::DoRead() {
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "DoRead()";
- while (!read_buffer_.Full()) {
- char* bytes;
- int size;
- if (fd_ == -1) {
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "DoRead(): fd_ == -1. Invalid FD. Returning false";
- return false;
- }
- read_buffer_.GetWritablePtr(&bytes, &size);
- ssize_t bytes_read = 0;
- if (ssl_) {
- bytes_read = SSL_read(ssl_, bytes, size);
- if (bytes_read < 0) {
- int err = SSL_get_error(ssl_, bytes_read);
- switch (err) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- case SSL_ERROR_WANT_ACCEPT:
- case SSL_ERROR_WANT_CONNECT:
- events_ &= ~EPOLLIN;
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "DoRead: SSL WANT_XXX: " << err;
- goto done;
- default:
- PrintSslError();
- goto error_or_close;
- }
- }
- } else {
- bytes_read = recv(fd_, bytes, size, MSG_DONTWAIT);
- }
- int stored_errno = errno;
- if (bytes_read == -1) {
- switch (stored_errno) {
- case EAGAIN:
- events_ &= ~EPOLLIN;
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "Got EAGAIN while reading";
- goto done;
- case EINTR:
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "Got EINTR while reading";
- continue;
- default:
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "While calling recv, got error: "
- << (ssl_ ? "(ssl error)" : strerror(stored_errno));
- goto error_or_close;
- }
- } else if (bytes_read > 0) {
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "read " << bytes_read
- << " bytes";
- last_read_time_ = time(NULL);
- // If the protocol hasn't been detected yet, set up the handlers
- // we'll need.
- if (!protocol_detected_) {
- if (!SetupProtocolInterfaces()) {
- LOG(ERROR) << "Error setting up protocol interfaces.";
- goto error_or_close;
- }
- }
- read_buffer_.AdvanceWritablePtr(bytes_read);
- if (!DoConsumeReadData())
- goto error_or_close;
- continue;
- } else { // bytes_read == 0
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "0 bytes read with recv call.";
- }
- goto error_or_close;
- }
- done:
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "DoRead done!";
- return true;
-
- error_or_close:
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "DoRead(): error_or_close. "
- << "Cleaning up, then returning false";
- Cleanup("DoRead");
- return false;
-}
-
-bool SMConnection::DoConsumeReadData() {
- char* bytes;
- int size;
- read_buffer_.GetReadablePtr(&bytes, &size);
- while (size != 0) {
- size_t bytes_consumed = sm_interface_->ProcessReadInput(bytes, size);
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "consumed "
- << bytes_consumed << " bytes";
- if (bytes_consumed == 0) {
- break;
- }
- read_buffer_.AdvanceReadablePtr(bytes_consumed);
- if (sm_interface_->MessageFullyRead()) {
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "HandleRequestFullyRead: Setting EPOLLOUT";
- HandleResponseFullyRead();
- events_ |= EPOLLOUT;
- } else if (sm_interface_->Error()) {
- LOG(ERROR) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "Framer error detected: Setting EPOLLOUT: "
- << sm_interface_->ErrorAsString();
- // this causes everything to be closed/cleaned up.
- events_ |= EPOLLOUT;
- return false;
- }
- read_buffer_.GetReadablePtr(&bytes, &size);
- }
- return true;
-}
-
-void SMConnection::HandleResponseFullyRead() { sm_interface_->Cleanup(); }
-
-bool SMConnection::DoWrite() {
- size_t bytes_sent = 0;
- int flags = MSG_NOSIGNAL | MSG_DONTWAIT;
- if (fd_ == -1) {
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "DoWrite: fd == -1. Returning false.";
- return false;
- }
- if (output_list_.empty()) {
- VLOG(2) << log_prefix_ << "DoWrite: Output list empty.";
- if (sm_interface_) {
- sm_interface_->GetOutput();
- }
- if (output_list_.empty()) {
- events_ &= ~EPOLLOUT;
- }
- }
- while (!output_list_.empty()) {
- VLOG(2) << log_prefix_
- << "DoWrite: Items in output list: " << output_list_.size();
- if (bytes_sent >= max_bytes_sent_per_dowrite_) {
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << " byte sent >= max bytes sent per write: Setting EPOLLOUT: "
- << bytes_sent;
- events_ |= EPOLLOUT;
- break;
- }
- if (sm_interface_ && output_list_.size() < 2) {
- sm_interface_->GetOutput();
- }
- DataFrame* data_frame = output_list_.front();
- const char* bytes = data_frame->data;
- int size = data_frame->size;
- bytes += data_frame->index;
- size -= data_frame->index;
- DCHECK_GE(size, 0);
- if (size <= 0) {
- output_list_.pop_front();
- delete data_frame;
- continue;
- }
-
- flags = MSG_NOSIGNAL | MSG_DONTWAIT;
- // Look for a queue size > 1 because |this| frame is remains on the list
- // until it has finished sending.
- if (output_list_.size() > 1) {
- VLOG(2) << log_prefix_ << "Outlist size: " << output_list_.size()
- << ": Adding MSG_MORE flag";
- flags |= MSG_MORE;
- }
- VLOG(2) << log_prefix_ << "Attempting to send " << size << " bytes.";
- ssize_t bytes_written = Send(bytes, size, flags);
- int stored_errno = errno;
- if (bytes_written == -1) {
- switch (stored_errno) {
- case EAGAIN:
- events_ &= ~EPOLLOUT;
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "Got EAGAIN while writing";
- goto done;
- case EINTR:
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "Got EINTR while writing";
- continue;
- default:
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "While calling send, got error: " << stored_errno << ": "
- << (ssl_ ? "" : strerror(stored_errno));
- goto error_or_close;
- }
- } else if (bytes_written > 0) {
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "Wrote: " << bytes_written << " bytes";
- data_frame->index += bytes_written;
- bytes_sent += bytes_written;
- continue;
- } else if (bytes_written == -2) {
- // -2 handles SSL_ERROR_WANT_* errors
- events_ &= ~EPOLLOUT;
- goto done;
- }
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "0 bytes written with send call.";
- goto error_or_close;
- }
- done:
- UncorkSocket();
- return true;
-
- error_or_close:
- VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "DoWrite: error_or_close. Returning false "
- << "after cleaning up";
- Cleanup("DoWrite");
- UncorkSocket();
- return false;
-}
-
-void SMConnection::Reset() {
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "Resetting";
- if (ssl_) {
- SSL_shutdown(ssl_);
- PrintSslError();
- SSL_free(ssl_);
- PrintSslError();
- ssl_ = NULL;
- }
- if (registered_in_epoll_server_) {
- epoll_server_->UnregisterFD(fd_);
- registered_in_epoll_server_ = false;
- }
- if (fd_ >= 0) {
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "Closing connection";
- close(fd_);
- fd_ = -1;
- }
- read_buffer_.Clear();
- initialized_ = false;
- protocol_detected_ = false;
- events_ = 0;
- for (std::list<DataFrame*>::iterator i = output_list_.begin();
- i != output_list_.end();
- ++i) {
- delete *i;
- }
- output_list_.clear();
-}
-
-// static
-SMConnection* SMConnection::NewSMConnection(EpollServer* epoll_server,
- SSLState* ssl_state,
- MemoryCache* memory_cache,
- FlipAcceptor* acceptor,
- std::string log_prefix) {
- return new SMConnection(
- epoll_server, ssl_state, memory_cache, acceptor, log_prefix);
-}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/sm_connection.h b/chromium/net/tools/flip_server/sm_connection.h
deleted file mode 100644
index b586a18b34b..00000000000
--- a/chromium/net/tools/flip_server/sm_connection.h
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_SM_CONNECTION_H_
-#define NET_TOOLS_FLIP_SERVER_SM_CONNECTION_H_
-
-#include <arpa/inet.h> // in_addr_t
-#include <stddef.h>
-#include <time.h>
-
-#include <list>
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "net/spdy/spdy_protocol.h"
-#include "net/tools/epoll_server/epoll_server.h"
-#include "net/tools/flip_server/mem_cache.h"
-#include "net/tools/flip_server/ring_buffer.h"
-#include "net/tools/flip_server/sm_interface.h"
-#include "openssl/ssl.h"
-
-namespace net {
-
-class FlipAcceptor;
-class MemoryCache;
-struct SSLState;
-class SpdySM;
-
-// A frame of data to be sent.
-class DataFrame {
- public:
- const char* data;
- size_t size;
- bool delete_when_done;
- size_t index;
- DataFrame() : data(NULL), size(0), delete_when_done(false), index(0) {}
- virtual ~DataFrame();
-};
-
-typedef std::list<DataFrame*> OutputList;
-
-class SMConnection : public SMConnectionInterface,
- public EpollCallbackInterface,
- public NotifierInterface {
- public:
- ~SMConnection() override;
-
- static SMConnection* NewSMConnection(EpollServer* epoll_server,
- SSLState* ssl_state,
- MemoryCache* memory_cache,
- FlipAcceptor* acceptor,
- std::string log_prefix);
-
- // TODO(mbelshe): Make these private.
- time_t last_read_time_;
- std::string server_ip_;
- std::string server_port_;
-
- EpollServer* epoll_server() override;
- OutputList* output_list() { return &output_list_; }
- MemoryCache* memory_cache() { return memory_cache_; }
- void ReadyToSend() override;
- void EnqueueDataFrame(DataFrame* df);
-
- int fd() const { return fd_; }
- bool initialized() const { return initialized_; }
- std::string client_ip() const { return client_ip_; }
-
- virtual void InitSMConnection(SMConnectionPoolInterface* connection_pool,
- SMInterface* sm_interface,
- EpollServer* epoll_server,
- int fd,
- std::string server_ip,
- std::string server_port,
- std::string remote_ip,
- bool use_ssl);
-
- void CorkSocket();
- void UncorkSocket();
-
- int Send(const char* data, int len, int flags);
-
- // EpollCallbackInterface interface.
- void OnRegistration(EpollServer* eps, int fd, int event_mask) override;
- void OnModification(int fd, int event_mask) override {}
- void OnEvent(int fd, EpollEvent* event) override;
- void OnUnregistration(int fd, bool replaced) override;
- void OnShutdown(EpollServer* eps, int fd) override;
-
- // NotifierInterface interface.
- void Notify() override {}
-
- void Cleanup(const char* cleanup);
-
- // Flag indicating if we should force spdy on all connections.
- static bool force_spdy() { return force_spdy_; }
- static void set_force_spdy(bool value) { force_spdy_ = value; }
-
- private:
- // Decide if SPDY was negotiated.
- bool WasSpdyNegotiated(SpdyMajorVersion* version_negotiated);
-
- // Initialize the protocol interfaces we'll need for this connection.
- // Returns true if successful, false otherwise.
- bool SetupProtocolInterfaces();
-
- bool DoRead();
- bool DoWrite();
- bool DoConsumeReadData();
- void Reset();
-
- void HandleEvents();
- void HandleResponseFullyRead();
-
- protected:
- friend std::ostream& operator<<(std::ostream& os, const SMConnection& c) {
- os << &c << "\n";
- return os;
- }
-
- SMConnection(EpollServer* epoll_server,
- SSLState* ssl_state,
- MemoryCache* memory_cache,
- FlipAcceptor* acceptor,
- std::string log_prefix);
-
- private:
- int fd_;
- int events_;
-
- bool registered_in_epoll_server_;
- bool initialized_;
- bool protocol_detected_;
- bool connection_complete_;
-
- SMConnectionPoolInterface* connection_pool_;
-
- EpollServer* epoll_server_;
- SSLState* ssl_state_;
- MemoryCache* memory_cache_;
- FlipAcceptor* acceptor_;
- std::string client_ip_;
-
- RingBuffer read_buffer_;
-
- OutputList output_list_;
- SpdySM* sm_spdy_interface_;
- SMInterface* sm_http_interface_;
- SMInterface* sm_streamer_interface_;
- SMInterface* sm_interface_;
- std::string log_prefix_;
-
- size_t max_bytes_sent_per_dowrite_;
-
- SSL* ssl_;
-
- static bool force_spdy_;
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_SM_CONNECTION_H_
diff --git a/chromium/net/tools/flip_server/sm_interface.h b/chromium/net/tools/flip_server/sm_interface.h
deleted file mode 100644
index bf2bc5ed06c..00000000000
--- a/chromium/net/tools/flip_server/sm_interface.h
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2009 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_FLIP_SERVER_SM_INTERFACE_H_
-#define NET_TOOLS_FLIP_SERVER_SM_INTERFACE_H_
-
-// State Machine Interfaces
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-
-#include "net/tools/balsa/balsa_headers.h"
-
-namespace net {
-
-class EpollServer;
-class SMConnectionPoolInterface;
-class SMConnection;
-
-class SMInterface {
- public:
- virtual void InitSMInterface(SMInterface* sm_other_interface,
- int32_t server_idx) = 0;
- virtual void InitSMConnection(SMConnectionPoolInterface* connection_pool,
- SMInterface* sm_interface,
- EpollServer* epoll_server,
- int fd,
- std::string server_ip,
- std::string server_port,
- std::string remote_ip,
- bool use_ssl) = 0;
- virtual size_t ProcessReadInput(const char* data, size_t len) = 0;
- virtual size_t ProcessWriteInput(const char* data, size_t len) = 0;
- virtual void SetStreamID(uint32_t stream_id) = 0;
- virtual bool MessageFullyRead() const = 0;
- virtual bool Error() const = 0;
- virtual const char* ErrorAsString() const = 0;
- virtual void Reset() = 0;
- virtual void ResetForNewInterface(int32_t server_idx) = 0;
- // ResetForNewConnection is used for interfaces which control SMConnection
- // objects. When called an interface may put its connection object into
- // a reusable instance pool. Currently this is what the HttpSM interface
- // does.
- virtual void ResetForNewConnection() = 0;
- virtual void Cleanup() = 0;
-
- virtual int PostAcceptHook() = 0;
-
- virtual void NewStream(uint32_t stream_id,
- uint32_t priority,
- const std::string& filename) = 0;
- virtual void SendEOF(uint32_t stream_id) = 0;
- virtual void SendErrorNotFound(uint32_t stream_id) = 0;
- virtual size_t SendSynStream(uint32_t stream_id,
- const BalsaHeaders& headers) = 0;
- virtual size_t SendSynReply(uint32_t stream_id,
- const BalsaHeaders& headers) = 0;
- virtual void SendDataFrame(uint32_t stream_id,
- const char* data,
- int64_t len,
- uint32_t flags,
- bool compress) = 0;
- virtual void GetOutput() = 0;
- virtual void set_is_request() = 0;
-
- virtual ~SMInterface() {}
-};
-
-class SMConnectionInterface {
- public:
- virtual ~SMConnectionInterface() {}
- virtual void ReadyToSend() = 0;
- virtual EpollServer* epoll_server() = 0;
-};
-
-class SMConnectionPoolInterface {
- public:
- virtual ~SMConnectionPoolInterface() {}
- virtual void SMConnectionDone(SMConnection* connection) = 0;
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_SM_INTERFACE_H_
diff --git a/chromium/net/tools/flip_server/spdy_interface.cc b/chromium/net/tools/flip_server/spdy_interface.cc
deleted file mode 100644
index 247cc2c546f..00000000000
--- a/chromium/net/tools/flip_server/spdy_interface.cc
+++ /dev/null
@@ -1,616 +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/tools/flip_server/spdy_interface.h"
-
-#include <algorithm>
-#include <string>
-#include <utility>
-
-#include "net/spdy/spdy_framer.h"
-#include "net/spdy/spdy_protocol.h"
-#include "net/tools/flip_server/constants.h"
-#include "net/tools/flip_server/flip_config.h"
-#include "net/tools/flip_server/http_interface.h"
-#include "net/tools/flip_server/spdy_util.h"
-#include "net/tools/flip_server/url_utilities.h"
-
-namespace net {
-
-// static
-std::string SpdySM::forward_ip_header_;
-
-class SpdyFrameDataFrame : public DataFrame {
- public:
- explicit SpdyFrameDataFrame(SpdySerializedFrame* spdy_frame)
- : frame(spdy_frame) {
- data = spdy_frame->data();
- size = spdy_frame->size();
- }
-
- ~SpdyFrameDataFrame() override { delete frame; }
-
- const SpdySerializedFrame* frame;
-};
-
-SpdySM::SpdySM(SMConnection* connection,
- SMInterface* sm_http_interface,
- EpollServer* epoll_server,
- MemoryCache* memory_cache,
- FlipAcceptor* acceptor,
- SpdyMajorVersion spdy_version)
- : buffered_spdy_framer_(new BufferedSpdyFramer(spdy_version)),
- valid_spdy_session_(false),
- connection_(connection),
- client_output_list_(connection->output_list()),
- client_output_ordering_(connection),
- next_outgoing_stream_id_(2),
- epoll_server_(epoll_server),
- acceptor_(acceptor),
- memory_cache_(memory_cache),
- close_on_error_(false) {
- buffered_spdy_framer_->set_visitor(this);
-}
-
-SpdySM::~SpdySM() { }
-
-void SpdySM::InitSMConnection(SMConnectionPoolInterface* connection_pool,
- SMInterface* sm_interface,
- EpollServer* epoll_server,
- int fd,
- std::string server_ip,
- std::string server_port,
- std::string remote_ip,
- bool use_ssl) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Initializing server connection.";
- connection_->InitSMConnection(connection_pool,
- sm_interface,
- epoll_server,
- fd,
- server_ip,
- server_port,
- remote_ip,
- use_ssl);
-}
-
-SMInterface* SpdySM::NewConnectionInterface() {
- SMConnection* server_connection =
- SMConnection::NewSMConnection(epoll_server_,
- NULL,
- memory_cache_,
- acceptor_,
- "http_conn: ");
- if (server_connection == NULL) {
- LOG(ERROR) << "SpdySM: Could not create server connection";
- return NULL;
- }
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Creating new HTTP interface";
- SMInterface* sm_http_interface =
- new HttpSM(server_connection, this, memory_cache_, acceptor_);
- return sm_http_interface;
-}
-
-SMInterface* SpdySM::FindOrMakeNewSMConnectionInterface(
- const std::string& server_ip,
- const std::string& server_port) {
- SMInterface* sm_http_interface;
- int32_t server_idx;
- if (unused_server_interface_list.empty()) {
- sm_http_interface = NewConnectionInterface();
- server_idx = server_interface_list.size();
- server_interface_list.push_back(sm_http_interface);
- VLOG(2) << ACCEPTOR_CLIENT_IDENT
- << "SpdySM: Making new server connection on index: " << server_idx;
- } else {
- server_idx = unused_server_interface_list.back();
- unused_server_interface_list.pop_back();
- sm_http_interface = server_interface_list.at(server_idx);
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Reusing connection on "
- << "index: " << server_idx;
- }
-
- sm_http_interface->InitSMInterface(this, server_idx);
- sm_http_interface->InitSMConnection(NULL,
- sm_http_interface,
- epoll_server_,
- -1,
- server_ip,
- server_port,
- std::string(),
- false);
-
- return sm_http_interface;
-}
-
-int SpdySM::SpdyHandleNewStream(SpdyStreamId stream_id,
- SpdyPriority priority,
- const SpdyHeaderBlock& headers,
- std::string& http_data,
- bool* is_https_scheme) {
- *is_https_scheme = false;
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnSyn(" << stream_id << ")";
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: # headers: " << headers.size();
-
- SpdyHeaderBlock::const_iterator method = headers.end();
- SpdyHeaderBlock::const_iterator host = headers.end();
- SpdyHeaderBlock::const_iterator path = headers.end();
- SpdyHeaderBlock::const_iterator scheme = headers.end();
- SpdyHeaderBlock::const_iterator version = headers.end();
- SpdyHeaderBlock::const_iterator url = headers.end();
-
- std::string path_string, host_string, version_string;
-
- method = headers.find(":method");
- host = headers.find(":host");
- path = headers.find(":path");
- scheme = headers.find(":scheme");
- if (method == headers.end() || host == headers.end() ||
- path == headers.end() || scheme == headers.end()) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: A mandatory header is "
- << "missing. Not creating stream";
- return 0;
- }
- host_string = host->second.as_string();
- path_string = path->second.as_string();
- version_string = "HTTP/1.1";
-
- if (scheme->second.compare("https") == 0) {
- *is_https_scheme = true;
- }
-
- if (acceptor_->flip_handler_type_ == FLIP_HANDLER_SPDY_SERVER) {
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Request: " << method->second
- << " " << path_string;
- std::string filename =
- EncodeURL(path_string, host_string, method->second.as_string());
- NewStream(stream_id, priority, filename);
- } else {
- http_data += method->second.as_string() + " " + path_string + " " +
- version_string + "\r\n";
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Request: " << method->second << " "
- << path_string << " " << version_string;
- http_data += "Host: " + (*is_https_scheme ?
- acceptor_->https_server_ip_ :
- acceptor_->http_server_ip_) + "\r\n";
- for (SpdyHeaderBlock::const_iterator i = headers.begin();
- i != headers.end(); ++i) {
- if ((i->first.size() > 0 && i->first[0] == ':') ||
- i->first == "host" ||
- i == method ||
- i == host ||
- i == path ||
- i == scheme ||
- i == version ||
- i == url) {
- // Ignore the entry.
- } else {
- http_data +=
- i->first.as_string() + ": " + i->second.as_string() + "\r\n";
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << i->first << ":" << i->second;
- }
- }
- if (forward_ip_header_.length()) {
- // X-Client-Cluster-IP header
- http_data += forward_ip_header_ + ": " +
- connection_->client_ip() + "\r\n";
- }
- http_data += "\r\n";
- }
-
- VLOG(3) << ACCEPTOR_CLIENT_IDENT << "SpdySM: HTTP Request:\n" << http_data;
- return 1;
-}
-
-void SpdySM::OnStreamFrameData(SpdyStreamId stream_id,
- const char* data,
- size_t len) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: StreamData(" << stream_id
- << ", [" << len << "])";
- StreamToSmif::iterator it = stream_to_smif_.find(stream_id);
- if (it == stream_to_smif_.end()) {
- VLOG(2) << "Dropping frame from unknown stream " << stream_id;
- if (!valid_spdy_session_)
- close_on_error_ = true;
- return;
- }
-
- SMInterface* interface = it->second;
- if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY)
- interface->ProcessWriteInput(data, len);
-}
-
-void SpdySM::OnStreamEnd(SpdyStreamId stream_id) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: StreamEnd(" << stream_id << ")";
- StreamToSmif::iterator it = stream_to_smif_.find(stream_id);
- if (it == stream_to_smif_.end()) {
- VLOG(2) << "Dropping frame from unknown stream " << stream_id;
- if (!valid_spdy_session_)
- close_on_error_ = true;
- return;
- }
-
- SMInterface* interface = it->second;
- if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY)
- interface->ProcessWriteInput(nullptr, 0);
-}
-
-void SpdySM::OnStreamPadding(SpdyStreamId stream_id, size_t len) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: StreamPadding(" << stream_id
- << ", [" << len << "])";
-}
-
-void SpdySM::OnSynStream(SpdyStreamId stream_id,
- SpdyStreamId associated_stream_id,
- SpdyPriority priority,
- bool fin,
- bool unidirectional,
- const SpdyHeaderBlock& headers) {
- std::string http_data;
- bool is_https_scheme;
- int ret = SpdyHandleNewStream(
- stream_id, priority, headers, http_data, &is_https_scheme);
- if (!ret) {
- LOG(ERROR) << "SpdySM: Could not convert spdy into http.";
- return;
- }
- // We've seen a valid looking SYN_STREAM, consider this to have
- // been a real spdy session.
- valid_spdy_session_ = true;
-
- if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
- std::string server_ip;
- std::string server_port;
- if (is_https_scheme) {
- server_ip = acceptor_->https_server_ip_;
- server_port = acceptor_->https_server_port_;
- } else {
- server_ip = acceptor_->http_server_ip_;
- server_port = acceptor_->http_server_port_;
- }
- SMInterface* sm_http_interface =
- FindOrMakeNewSMConnectionInterface(server_ip, server_port);
- stream_to_smif_[stream_id] = sm_http_interface;
- sm_http_interface->SetStreamID(stream_id);
- sm_http_interface->ProcessWriteInput(http_data.c_str(), http_data.size());
- }
-}
-
-void SpdySM::OnSynReply(SpdyStreamId stream_id,
- bool fin,
- const SpdyHeaderBlock& headers) {
- // TODO(willchan): if there is an error parsing headers, we
- // should send a RST_STREAM.
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnSynReply(" << stream_id << ")";
-}
-
-void SpdySM::OnHeaders(SpdyStreamId stream_id,
- bool has_priority,
- int weight,
- SpdyStreamId parent_stream_id,
- bool exclusive,
- bool fin,
- const SpdyHeaderBlock& headers) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnHeaders(" << stream_id << ")";
-}
-
-void SpdySM::OnRstStream(SpdyStreamId stream_id, SpdyRstStreamStatus status) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnRstStream(" << stream_id
- << ")";
- client_output_ordering_.RemoveStreamId(stream_id);
-}
-
-bool SpdySM::OnUnknownFrame(SpdyStreamId stream_id, int frame_type) {
- return false;
-}
-
-size_t SpdySM::ProcessReadInput(const char* data, size_t len) {
- DCHECK(buffered_spdy_framer_);
- return buffered_spdy_framer_->ProcessInput(data, len);
-}
-
-size_t SpdySM::ProcessWriteInput(const char* data, size_t len) { return 0; }
-
-bool SpdySM::MessageFullyRead() const {
- DCHECK(buffered_spdy_framer_);
- return buffered_spdy_framer_->MessageFullyRead();
-}
-
-bool SpdySM::Error() const {
- DCHECK(buffered_spdy_framer_);
- return close_on_error_ || buffered_spdy_framer_->HasError();
-}
-
-const char* SpdySM::ErrorAsString() const {
- DCHECK(Error());
- DCHECK(buffered_spdy_framer_);
- return SpdyFramer::ErrorCodeToString(buffered_spdy_framer_->error_code());
-}
-
-void SpdySM::ResetForNewInterface(int32_t server_idx) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Reset for new interface: "
- << "server_idx: " << server_idx;
- unused_server_interface_list.push_back(server_idx);
-}
-
-void SpdySM::ResetForNewConnection() {
- // seq_num is not cleared, intentionally.
- buffered_spdy_framer_.reset();
- valid_spdy_session_ = false;
- client_output_ordering_.Reset();
- next_outgoing_stream_id_ = 2;
-}
-
-// Send a settings frame
-int SpdySM::PostAcceptHook() {
- // We should have buffered_spdy_framer_ set after reuse
- DCHECK(buffered_spdy_framer_);
- SettingsMap settings;
- settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
- SettingsFlagsAndValue(SETTINGS_FLAG_NONE, 100);
- SpdySerializedFrame* settings_frame =
- buffered_spdy_framer_->CreateSettings(settings);
-
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Sending Settings Frame";
- EnqueueDataFrame(new SpdyFrameDataFrame(settings_frame));
- return 1;
-}
-
-void SpdySM::NewStream(uint32_t stream_id,
- uint32_t priority,
- const std::string& filename) {
- MemCacheIter mci;
- mci.stream_id = stream_id;
- mci.priority = priority;
- // TODO(yhirano): The program will crash when
- // acceptor_->flip_handler_type_ != FLIP_HANDLER_SPDY_SERVER.
- // It should be fixed or an assertion should be placed.
- if (acceptor_->flip_handler_type_ == FLIP_HANDLER_SPDY_SERVER) {
- if (!memory_cache_->AssignFileData(filename, &mci)) {
- // error creating new stream.
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Sending ErrorNotFound";
- SendErrorNotFound(stream_id);
- } else {
- AddToOutputOrder(mci);
- }
- } else {
- AddToOutputOrder(mci);
- }
-}
-
-void SpdySM::AddToOutputOrder(const MemCacheIter& mci) {
- client_output_ordering_.AddToOutputOrder(mci);
-}
-
-void SpdySM::SendEOF(uint32_t stream_id) {
- SendEOFImpl(stream_id);
-}
-
-void SpdySM::SendErrorNotFound(uint32_t stream_id) {
- SendErrorNotFoundImpl(stream_id);
-}
-
-size_t SpdySM::SendSynStream(uint32_t stream_id, const BalsaHeaders& headers) {
- return SendSynStreamImpl(stream_id, headers);
-}
-
-size_t SpdySM::SendSynReply(uint32_t stream_id, const BalsaHeaders& headers) {
- return SendSynReplyImpl(stream_id, headers);
-}
-
-void SpdySM::SendDataFrame(uint32_t stream_id,
- const char* data,
- int64_t len,
- uint32_t flags,
- bool compress) {
- SpdyDataFlags spdy_flags = static_cast<SpdyDataFlags>(flags);
- SendDataFrameImpl(stream_id, data, len, spdy_flags, compress);
-}
-
-void SpdySM::SendEOFImpl(uint32_t stream_id) {
- SendDataFrame(stream_id, NULL, 0, DATA_FLAG_FIN, false);
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending EOF: " << stream_id;
- KillStream(stream_id);
- stream_to_smif_.erase(stream_id);
-}
-
-void SpdySM::SendErrorNotFoundImpl(uint32_t stream_id) {
- BalsaHeaders my_headers;
- my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "404", "Not Found");
- SendSynReplyImpl(stream_id, my_headers);
- SendDataFrame(stream_id, "wtf?", 4, DATA_FLAG_FIN, false);
- client_output_ordering_.RemoveStreamId(stream_id);
-}
-
-void SpdySM::KillStream(uint32_t stream_id) {
- client_output_ordering_.RemoveStreamId(stream_id);
-}
-
-void SpdySM::CopyHeaders(SpdyHeaderBlock& dest, const BalsaHeaders& headers) {
- for (BalsaHeaders::const_header_lines_iterator hi =
- headers.header_lines_begin();
- hi != headers.header_lines_end();
- ++hi) {
- // It is illegal to send SPDY headers with empty value or header
- // names.
- if (!hi->first.length() || !hi->second.length())
- continue;
-
- // Key must be all lower case in SPDY headers.
- std::string key = hi->first.as_string();
- std::transform(key.begin(), key.end(), key.begin(), ::tolower);
- SpdyHeaderBlock::iterator fhi = dest.find(key);
- if (fhi == dest.end()) {
- dest[key] = hi->second.as_string();
- } else {
- dest[key] = (std::string(fhi->second.data(), fhi->second.size()) + "\0" +
- std::string(hi->second.data(), hi->second.size()));
- }
- }
-
- // These headers have no value
- dest.erase("X-Associated-Content"); // TODO(mbelshe): case-sensitive
- dest.erase("X-Original-Url"); // TODO(mbelshe): case-sensitive
-}
-
-size_t SpdySM::SendSynStreamImpl(uint32_t stream_id,
- const BalsaHeaders& headers) {
- SpdyHeaderBlock block;
- CopyHeaders(block, headers);
- block[":method"] = headers.request_method().as_string();
- block[":version"] = headers.request_version().as_string();
- if (headers.HasHeader("X-Original-Url")) {
- std::string original_url = headers.GetHeader("X-Original-Url").as_string();
- block[":path"] = UrlUtilities::GetUrlPath(original_url);
- block[":host"] = UrlUtilities::GetUrlPath(original_url);
- } else {
- block[":path"] = headers.request_uri().as_string();
- if (block.find("host") != block.end()) {
- block[":host"] = headers.GetHeader("Host").as_string();
- block.erase("host");
- }
- }
-
- DCHECK(buffered_spdy_framer_);
- SpdySerializedFrame* fsrcf = buffered_spdy_framer_->CreateSynStream(
- stream_id, 0, 0, CONTROL_FLAG_NONE, std::move(block));
- size_t df_size = fsrcf->size();
- EnqueueDataFrame(new SpdyFrameDataFrame(fsrcf));
-
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending SynStreamheader "
- << stream_id;
- return df_size;
-}
-
-size_t SpdySM::SendSynReplyImpl(uint32_t stream_id,
- const BalsaHeaders& headers) {
- SpdyHeaderBlock block;
- CopyHeaders(block, headers);
- block[":status"] = headers.response_code().as_string() + " " +
- headers.response_reason_phrase().as_string();
- block[":version"] = headers.response_version().as_string();
-
- DCHECK(buffered_spdy_framer_);
- SpdySerializedFrame* fsrcf = buffered_spdy_framer_->CreateSynReply(
- stream_id, CONTROL_FLAG_NONE, std::move(block));
- size_t df_size = fsrcf->size();
- EnqueueDataFrame(new SpdyFrameDataFrame(fsrcf));
-
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending SynReplyheader "
- << stream_id;
- return df_size;
-}
-
-void SpdySM::SendDataFrameImpl(uint32_t stream_id,
- const char* data,
- int64_t len,
- SpdyDataFlags flags,
- bool compress) {
- DCHECK(buffered_spdy_framer_);
- // TODO(mbelshe): We can't compress here - before going into the
- // priority queue. Compression needs to be done
- // with late binding.
- if (len == 0) {
- SpdySerializedFrame* fdf =
- buffered_spdy_framer_->CreateDataFrame(stream_id, data, len, flags);
- EnqueueDataFrame(new SpdyFrameDataFrame(fdf));
- return;
- }
-
- // Chop data frames into chunks so that one stream can't monopolize the
- // output channel.
- while (len > 0) {
- int64_t size = std::min(len, static_cast<int64_t>(kSpdySegmentSize));
- SpdyDataFlags chunk_flags = flags;
-
- // If we chunked this block, and the FIN flag was set, there is more
- // data coming. So, remove the flag.
- if ((size < len) && (flags & DATA_FLAG_FIN))
- chunk_flags = static_cast<SpdyDataFlags>(chunk_flags & ~DATA_FLAG_FIN);
-
- SpdySerializedFrame* fdf = buffered_spdy_framer_->CreateDataFrame(
- stream_id, data, size, chunk_flags);
- EnqueueDataFrame(new SpdyFrameDataFrame(fdf));
-
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending data frame "
- << stream_id << " [" << size << "] shrunk to "
- << (fdf->size() - kSpdyOverhead) << ", flags=" << flags;
-
- data += size;
- len -= size;
- }
-}
-
-void SpdySM::EnqueueDataFrame(DataFrame* df) {
- connection_->EnqueueDataFrame(df);
-}
-
-void SpdySM::GetOutput() {
- while (client_output_list_->size() < 2) {
- MemCacheIter* mci = client_output_ordering_.GetIter();
- if (mci == NULL) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT
- << "SpdySM: GetOutput: nothing to output!?";
- return;
- }
- if (!mci->transformed_header) {
- mci->transformed_header = true;
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: GetOutput transformed "
- << "header stream_id: [" << mci->stream_id << "]";
- if ((mci->stream_id % 2) == 0) {
- // this is a server initiated stream.
- // Ideally, we'd do a 'syn-push' here, instead of a syn-reply.
- BalsaHeaders headers;
- headers.CopyFrom(*(mci->file_data->headers()));
- headers.ReplaceOrAppendHeader("status", "200");
- headers.ReplaceOrAppendHeader("version", "http/1.1");
- headers.SetRequestFirstlineFromStringPieces(
- "PUSH", mci->file_data->filename(), "");
- mci->bytes_sent = SendSynStream(mci->stream_id, headers);
- } else {
- BalsaHeaders headers;
- headers.CopyFrom(*(mci->file_data->headers()));
- mci->bytes_sent = SendSynReply(mci->stream_id, headers);
- }
- return;
- }
- if (mci->body_bytes_consumed >= mci->file_data->body().size()) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: GetOutput "
- << "remove_stream_id: [" << mci->stream_id << "]";
- SendEOF(mci->stream_id);
- return;
- }
- size_t num_to_write =
- mci->file_data->body().size() - mci->body_bytes_consumed;
- if (num_to_write > mci->max_segment_size)
- num_to_write = mci->max_segment_size;
-
- bool should_compress = false;
- if (!mci->file_data->headers()->HasHeader("content-encoding")) {
- if (mci->file_data->headers()->HasHeader("content-type")) {
- std::string content_type =
- mci->file_data->headers()->GetHeader("content-type").as_string();
- if (content_type.find("image") == content_type.npos)
- should_compress = true;
- }
- }
-
- SendDataFrame(mci->stream_id,
- mci->file_data->body().data() + mci->body_bytes_consumed,
- num_to_write,
- 0,
- should_compress);
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: GetOutput SendDataFrame["
- << mci->stream_id << "]: " << num_to_write;
- mci->body_bytes_consumed += num_to_write;
- mci->bytes_sent += num_to_write;
- }
-}
-
-void SpdySM::CreateFramer(SpdyMajorVersion spdy_version) {
- DCHECK(!buffered_spdy_framer_);
- buffered_spdy_framer_.reset(new BufferedSpdyFramer(spdy_version));
- buffered_spdy_framer_->set_visitor(this);
-}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/spdy_interface.h b/chromium/net/tools/flip_server/spdy_interface.h
deleted file mode 100644
index 33f3abf873d..00000000000
--- a/chromium/net/tools/flip_server/spdy_interface.h
+++ /dev/null
@@ -1,238 +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.
-
-#ifndef NET_TOOLS_FLIP_SERVER_SPDY_INTERFACE_H_
-#define NET_TOOLS_FLIP_SERVER_SPDY_INTERFACE_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "net/spdy/buffered_spdy_framer.h"
-#include "net/spdy/spdy_alt_svc_wire_format.h"
-#include "net/spdy/spdy_protocol.h"
-#include "net/tools/balsa/balsa_headers.h"
-#include "net/tools/balsa/balsa_visitor_interface.h"
-#include "net/tools/flip_server/output_ordering.h"
-#include "net/tools/flip_server/sm_connection.h"
-#include "net/tools/flip_server/sm_interface.h"
-
-namespace net {
-
-class FlipAcceptor;
-class MemoryCache;
-
-class SpdySM : public BufferedSpdyFramerVisitorInterface, public SMInterface {
- public:
- SpdySM(SMConnection* connection,
- SMInterface* sm_http_interface,
- EpollServer* epoll_server,
- MemoryCache* memory_cache,
- FlipAcceptor* acceptor,
- SpdyMajorVersion spdy_version);
- ~SpdySM() override;
-
- void InitSMInterface(SMInterface* sm_http_interface,
- int32_t server_idx) override {}
-
- void InitSMConnection(SMConnectionPoolInterface* connection_pool,
- SMInterface* sm_interface,
- EpollServer* epoll_server,
- int fd,
- std::string server_ip,
- std::string server_port,
- std::string remote_ip,
- bool use_ssl) override;
-
- // Create new SPDY framer after reusing SpdySM and negotiating new version
- void CreateFramer(SpdyMajorVersion spdy_version);
-
- private:
- void set_is_request() override {}
- SMInterface* NewConnectionInterface();
- // virtual for tests
- virtual SMInterface* FindOrMakeNewSMConnectionInterface(
- const std::string& server_ip,
- const std::string& server_port);
- int SpdyHandleNewStream(SpdyStreamId stream_id,
- SpdyPriority priority,
- const SpdyHeaderBlock& headers,
- std::string& http_data,
- bool* is_https_scheme);
-
- // BufferedSpdyFramerVisitorInterface:
- void OnError(SpdyFramer::SpdyError error_code) override {}
- void OnStreamError(SpdyStreamId stream_id,
- const std::string& description) override {}
- // Called after all the header data for SYN_STREAM control frame is received.
- void OnSynStream(SpdyStreamId stream_id,
- SpdyStreamId associated_stream_id,
- SpdyPriority priority,
- bool fin,
- bool unidirectional,
- const SpdyHeaderBlock& headers) override;
-
- // Called after all the header data for SYN_REPLY control frame is received.
- void OnSynReply(SpdyStreamId stream_id,
- bool fin,
- const SpdyHeaderBlock& headers) override;
-
- // Called after all the header data for HEADERS control frame is received.
- void OnHeaders(SpdyStreamId stream_id,
- bool has_priority,
- int weight,
- SpdyStreamId parent_stream_id,
- bool exclusive,
- bool fin,
- const SpdyHeaderBlock& headers) override;
-
- // Called when data frame header is received.
- void OnDataFrameHeader(SpdyStreamId stream_id,
- size_t length,
- bool fin) override {}
-
- // Called when data is received.
- // |stream_id| The stream receiving data.
- // |data| A buffer containing the data received.
- // |len| The length of the data buffer.
- void OnStreamFrameData(SpdyStreamId stream_id,
- const char* data,
- size_t len) override;
-
- // Called when the other side has finished sending data on this stream.
- // |stream_id| The stream that was receivin data.
- void OnStreamEnd(SpdyStreamId stream_id) override;
-
- // Called when padding is received (padding length field or padding octets).
- // |stream_id| The stream receiving data.
- // |len| The number of padding octets.
- void OnStreamPadding(SpdyStreamId stream_id, size_t len) override;
-
- // Called when a SETTINGS frame is received.
- // |clear_persisted| True if the respective flag is set on the SETTINGS frame.
- void OnSettings(bool clear_persisted) override {}
-
- // Called when an individual setting within a SETTINGS frame has been parsed
- // and validated.
- void OnSetting(SpdySettingsIds id, uint8_t flags, uint32_t value) override {}
-
- // Called when a PING frame has been parsed.
- void OnPing(SpdyPingId unique_id, bool is_ack) override {}
-
- // Called when a RST_STREAM frame has been parsed.
- void OnRstStream(SpdyStreamId stream_id, SpdyRstStreamStatus status) override;
-
- // Called when a GOAWAY frame has been parsed.
- void OnGoAway(SpdyStreamId last_accepted_stream_id,
- SpdyGoAwayStatus status,
- base::StringPiece debug_data) override {}
-
- // Called when a WINDOW_UPDATE frame has been parsed.
- void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override {}
-
- // Called when a PUSH_PROMISE frame has been parsed.
- void OnPushPromise(SpdyStreamId stream_id,
- SpdyStreamId promised_stream_id,
- const SpdyHeaderBlock& headers) override {}
-
- // Called when an ALTSVC frame has been parsed.
- void OnAltSvc(SpdyStreamId stream_id,
- base::StringPiece origin,
- const SpdyAltSvcWireFormat::AlternativeServiceVector&
- altsvc_vector) override {}
-
- bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override;
-
- public:
- size_t ProcessReadInput(const char* data, size_t len) override;
- size_t ProcessWriteInput(const char* data, size_t len) override;
- bool MessageFullyRead() const override;
- void SetStreamID(uint32_t stream_id) override {}
- bool Error() const override;
- const char* ErrorAsString() const override;
- void Reset() override {}
- void ResetForNewInterface(int32_t server_idx) override;
- void ResetForNewConnection() override;
- // SMInterface's Cleanup is currently only called by SMConnection after a
- // protocol message as been fully read. Spdy's SMInterface does not need
- // to do any cleanup at this time.
- // TODO(klindsay) This method is probably not being used properly and
- // some logic review and method renaming is probably in order.
- void Cleanup() override {}
- // Send a settings frame
- int PostAcceptHook() override;
- void NewStream(uint32_t stream_id,
- uint32_t priority,
- const std::string& filename) override;
- void AddToOutputOrder(const MemCacheIter& mci);
- void SendEOF(uint32_t stream_id) override;
- void SendErrorNotFound(uint32_t stream_id) override;
- size_t SendSynStream(uint32_t stream_id,
- const BalsaHeaders& headers) override;
- size_t SendSynReply(uint32_t stream_id, const BalsaHeaders& headers) override;
- void SendDataFrame(uint32_t stream_id,
- const char* data,
- int64_t len,
- uint32_t flags,
- bool compress) override;
- BufferedSpdyFramer* spdy_framer() { return buffered_spdy_framer_.get(); }
-
- const OutputOrdering& output_ordering() const {
- return client_output_ordering_;
- }
-
- static std::string forward_ip_header() { return forward_ip_header_; }
- static void set_forward_ip_header(const std::string& value) {
- forward_ip_header_ = value;
- }
- SpdyMajorVersion spdy_version() const {
- DCHECK(buffered_spdy_framer_);
- return buffered_spdy_framer_->protocol_version();
- }
-
- private:
- void SendEOFImpl(uint32_t stream_id);
- void SendErrorNotFoundImpl(uint32_t stream_id);
- void KillStream(uint32_t stream_id);
- void CopyHeaders(SpdyHeaderBlock& dest, const BalsaHeaders& headers);
- size_t SendSynStreamImpl(uint32_t stream_id, const BalsaHeaders& headers);
- size_t SendSynReplyImpl(uint32_t stream_id, const BalsaHeaders& headers);
- void SendDataFrameImpl(uint32_t stream_id,
- const char* data,
- int64_t len,
- SpdyDataFlags flags,
- bool compress);
- void EnqueueDataFrame(DataFrame* df);
- void GetOutput() override;
-
- private:
- std::unique_ptr<BufferedSpdyFramer> buffered_spdy_framer_;
- bool valid_spdy_session_; // True if we have seen valid data on this session.
- // Use this to fail fast when junk is sent to our
- // port.
-
- SMConnection* connection_;
- OutputList* client_output_list_;
- OutputOrdering client_output_ordering_;
- uint32_t next_outgoing_stream_id_;
- EpollServer* epoll_server_;
- FlipAcceptor* acceptor_;
- MemoryCache* memory_cache_;
- std::vector<SMInterface*> server_interface_list;
- std::vector<int32_t> unused_server_interface_list;
- typedef std::map<uint32_t, SMInterface*> StreamToSmif;
- StreamToSmif stream_to_smif_;
- bool close_on_error_;
-
- static std::string forward_ip_header_;
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_SPDY_INTERFACE_H_
diff --git a/chromium/net/tools/flip_server/spdy_interface_test.cc b/chromium/net/tools/flip_server/spdy_interface_test.cc
deleted file mode 100644
index a62da42dd6b..00000000000
--- a/chromium/net/tools/flip_server/spdy_interface_test.cc
+++ /dev/null
@@ -1,642 +0,0 @@
-// Copyright 2013 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/flip_server/spdy_interface.h"
-
-#include <list>
-#include <memory>
-
-#include "base/strings/string_piece.h"
-#include "net/spdy/buffered_spdy_framer.h"
-#include "net/tools/balsa/balsa_enums.h"
-#include "net/tools/balsa/balsa_headers.h"
-#include "net/tools/flip_server/flip_config.h"
-#include "net/tools/flip_server/flip_test_utils.h"
-#include "net/tools/flip_server/mem_cache.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-using ::base::StringPiece;
-using ::testing::_;
-using ::testing::InSequence;
-using ::testing::InvokeWithoutArgs;
-using ::testing::Return;
-using ::testing::SaveArg;
-using ::testing::Values;
-
-inline bool operator==(StringPiece x,
- const SpdyHeaderBlock::StringPieceProxy& y) {
- return x == y.operator StringPiece();
-}
-
-namespace {
-
-struct StringSaver {
- public:
- StringSaver() : data(NULL), size(0) {}
- void Save() { string = std::string(data, size); }
-
- const char* data;
- size_t size;
- std::string string;
-};
-
-class SpdyFramerVisitor : public BufferedSpdyFramerVisitorInterface {
- public:
- virtual ~SpdyFramerVisitor() {}
- MOCK_METHOD1(OnError, void(SpdyFramer::SpdyError));
- MOCK_METHOD2(OnStreamError, void(SpdyStreamId, const std::string&));
- // SaveArg cannot be used on non-copyable types like SpdyHeaderBlock.
- void OnSynStream(SpdyStreamId stream_id,
- SpdyStreamId associated_stream_id,
- SpdyPriority priority,
- bool fin,
- bool unidirectional,
- const SpdyHeaderBlock& headers) override {
- actual_header_block_ = headers.Clone();
- OnSynStreamMock(stream_id, associated_stream_id, priority, fin,
- unidirectional, headers);
- }
- MOCK_METHOD6(OnSynStreamMock,
- void(SpdyStreamId,
- SpdyStreamId,
- SpdyPriority,
- bool,
- bool,
- const SpdyHeaderBlock&));
- void OnSynReply(SpdyStreamId stream_id,
- bool fin,
- const SpdyHeaderBlock& headers) override {
- actual_header_block_ = headers.Clone();
- OnSynReplyMock(stream_id, fin, headers);
- }
- MOCK_METHOD3(OnSynReplyMock,
- void(SpdyStreamId, bool, const SpdyHeaderBlock&));
- void OnHeaders(SpdyStreamId stream_id,
- bool has_priority,
- int weight,
- SpdyStreamId parent_stream_id,
- bool exclusive,
- bool fin,
- const SpdyHeaderBlock& headers) override {
- actual_header_block_ = headers.Clone();
- OnHeadersMock(stream_id, has_priority, weight, parent_stream_id, exclusive,
- fin, headers);
- }
- MOCK_METHOD7(OnHeadersMock,
- void(SpdyStreamId stream_id,
- bool has_priority,
- int weight,
- SpdyStreamId parent_stream_id,
- bool exclusive,
- bool fin,
- const SpdyHeaderBlock& headers));
- MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId, size_t, bool));
- MOCK_METHOD3(OnStreamFrameData, void(SpdyStreamId, const char*, size_t));
- MOCK_METHOD1(OnStreamEnd, void(SpdyStreamId));
- MOCK_METHOD2(OnStreamPadding, void(SpdyStreamId, size_t));
- MOCK_METHOD1(OnHeaderFrameStart,
- SpdyHeadersHandlerInterface*(SpdyStreamId stream_id));
- MOCK_METHOD2(OnHeaderFrameEnd,
- void(SpdyStreamId stream_id, bool end_headers));
- MOCK_METHOD1(OnSettings, void(bool clear_persisted));
- MOCK_METHOD3(OnSetting, void(SpdySettingsIds, uint8_t, uint32_t));
- MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack));
- MOCK_METHOD2(OnRstStream, void(SpdyStreamId, SpdyRstStreamStatus));
- MOCK_METHOD3(OnGoAway, void(SpdyStreamId, SpdyGoAwayStatus, StringPiece));
- MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId, int));
- MOCK_METHOD3(OnPushPromise,
- void(SpdyStreamId, SpdyStreamId, const SpdyHeaderBlock&));
- MOCK_METHOD3(OnAltSvc,
- void(SpdyStreamId,
- base::StringPiece,
- const SpdyAltSvcWireFormat::AlternativeServiceVector&));
- MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type));
-
- SpdyHeaderBlock actual_header_block_;
-};
-
-class FakeSMConnection : public SMConnection {
- public:
- FakeSMConnection(EpollServer* epoll_server,
- SSLState* ssl_state,
- MemoryCache* memory_cache,
- FlipAcceptor* acceptor,
- std::string log_prefix)
- : SMConnection(epoll_server,
- ssl_state,
- memory_cache,
- acceptor,
- log_prefix) {}
-
- MOCK_METHOD0(Cleanup, void());
- MOCK_METHOD8(InitSMConnection,
- void(SMConnectionPoolInterface*,
- SMInterface*,
- EpollServer*,
- int,
- std::string,
- std::string,
- std::string,
- bool));
-};
-
-// This class is almost SpdySM, except one function.
-// This class is the test target of tests in this file.
-class TestSpdySM : public SpdySM {
- public:
- virtual ~TestSpdySM() {}
- TestSpdySM(SMConnection* connection,
- SMInterface* sm_http_interface,
- EpollServer* epoll_server,
- MemoryCache* memory_cache,
- FlipAcceptor* acceptor,
- SpdyMajorVersion version)
- : SpdySM(connection,
- sm_http_interface,
- epoll_server,
- memory_cache,
- acceptor,
- version) {}
-
- MOCK_METHOD2(FindOrMakeNewSMConnectionInterface,
- SMInterface*(const std::string&, const std::string&));
-};
-
-class SpdySMTestBase : public ::testing::TestWithParam<SpdyMajorVersion> {
- public:
- explicit SpdySMTestBase(FlipHandlerType type) {
- SSLState* ssl_state = NULL;
- mock_another_interface_.reset(new MockSMInterface);
- memory_cache_.reset(new MemoryCache);
- acceptor_.reset(new FlipAcceptor(type,
- "127.0.0.1",
- "8941",
- "ssl_cert_filename",
- "ssl_key_filename",
- "127.0.0.1",
- "8942",
- "127.0.0.1",
- "8943",
- 1,
- 0,
- true,
- 1,
- false,
- true,
- NULL));
- epoll_server_.reset(new EpollServer);
- connection_.reset(new FakeSMConnection(epoll_server_.get(),
- ssl_state,
- memory_cache_.get(),
- acceptor_.get(),
- "log_prefix"));
-
- interface_.reset(new TestSpdySM(connection_.get(),
- mock_another_interface_.get(),
- epoll_server_.get(),
- memory_cache_.get(),
- acceptor_.get(),
- GetParam()));
-
- spdy_framer_.reset(new BufferedSpdyFramer(GetParam()));
- spdy_framer_visitor_.reset(new SpdyFramerVisitor);
- spdy_framer_->set_visitor(spdy_framer_visitor_.get());
- }
-
- virtual ~SpdySMTestBase() {
- if (acceptor_->listen_fd_ >= 0) {
- epoll_server_->UnregisterFD(acceptor_->listen_fd_);
- close(acceptor_->listen_fd_);
- acceptor_->listen_fd_ = -1;
- }
- OutputList& output_list = *connection_->output_list();
- for (OutputList::const_iterator i = output_list.begin();
- i != output_list.end();
- ++i) {
- delete *i;
- }
- output_list.clear();
- }
-
- bool HasStream(uint32_t stream_id) {
- return interface_->output_ordering().ExistsInPriorityMaps(stream_id);
- }
-
- protected:
- std::unique_ptr<MockSMInterface> mock_another_interface_;
- std::unique_ptr<MemoryCache> memory_cache_;
- std::unique_ptr<FlipAcceptor> acceptor_;
- std::unique_ptr<EpollServer> epoll_server_;
- std::unique_ptr<FakeSMConnection> connection_;
- std::unique_ptr<TestSpdySM> interface_;
- std::unique_ptr<BufferedSpdyFramer> spdy_framer_;
- std::unique_ptr<SpdyFramerVisitor> spdy_framer_visitor_;
-};
-
-class SpdySMProxyTest : public SpdySMTestBase {
- public:
- SpdySMProxyTest() : SpdySMTestBase(FLIP_HANDLER_PROXY) {}
- virtual ~SpdySMProxyTest() {}
-};
-
-class SpdySMServerTest : public SpdySMTestBase {
- public:
- SpdySMServerTest() : SpdySMTestBase(FLIP_HANDLER_SPDY_SERVER) {}
- virtual ~SpdySMServerTest() {}
-};
-
-INSTANTIATE_TEST_CASE_P(SpdySMProxyTest, SpdySMProxyTest, Values(SPDY3, HTTP2));
-INSTANTIATE_TEST_CASE_P(SpdySMServerTest, SpdySMServerTest, Values(HTTP2));
-
-TEST_P(SpdySMProxyTest, InitSMConnection) {
- {
- InSequence s;
- EXPECT_CALL(*connection_, InitSMConnection(_, _, _, _, _, _, _, _));
- }
- interface_->InitSMConnection(
- NULL, NULL, epoll_server_.get(), -1, "", "", "", false);
-}
-
-TEST_P(SpdySMProxyTest, OnStreamFrameData) {
- BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
- std::unique_ptr<MockSMInterface> mock_interface(new MockSMInterface);
- uint32_t stream_id = 92;
- uint32_t associated_id = 43;
- SpdyHeaderBlock block;
- testing::MockFunction<void(int)> checkpoint; // NOLINT
-
- std::unique_ptr<SpdySerializedFrame> frame(
- spdy_framer_->CreatePingFrame(12, false));
- block[":method"] = "GET";
- block[":host"] = "www.example.com";
- block[":path"] = "/path";
- block[":scheme"] = "http";
- block["foo"] = "bar";
- {
- InSequence s;
- EXPECT_CALL(*interface_,
- FindOrMakeNewSMConnectionInterface(_, _))
- .WillOnce(Return(mock_interface.get()));
- EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
- EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _)).Times(1);
- EXPECT_CALL(checkpoint, Call(0));
- EXPECT_CALL(*mock_interface,
- ProcessWriteInput(frame->data(), frame->size())).Times(1);
- }
-
- visitor->OnSynStream(stream_id, associated_id, 0, false, false, block);
- checkpoint.Call(0);
- visitor->OnStreamFrameData(stream_id, frame->data(), frame->size());
-}
-
-TEST_P(SpdySMProxyTest, OnRstStream) {
- BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
- uint32_t stream_id = 82;
- MemCacheIter mci;
- mci.stream_id = stream_id;
-
- {
- BalsaHeaders headers;
- std::string filename = "foobar";
- memory_cache_->InsertFile(&headers, filename, "");
- mci.file_data = memory_cache_->GetFileData(filename);
- }
-
- interface_->AddToOutputOrder(mci);
- ASSERT_TRUE(HasStream(stream_id));
- visitor->OnRstStream(stream_id, RST_STREAM_INVALID);
- ASSERT_FALSE(HasStream(stream_id));
-}
-
-TEST_P(SpdySMProxyTest, ProcessReadInput) {
- ASSERT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME,
- interface_->spdy_framer()->state());
- interface_->ProcessReadInput("", 1);
- ASSERT_EQ(SpdyFramer::SPDY_READING_COMMON_HEADER,
- interface_->spdy_framer()->state());
-}
-
-TEST_P(SpdySMProxyTest, ResetForNewConnection) {
- uint32_t stream_id = 13;
- MemCacheIter mci;
- mci.stream_id = stream_id;
- // incomplete input
- const char input[] = {'\0', '\0', '\0'};
-
- {
- BalsaHeaders headers;
- std::string filename = "foobar";
- memory_cache_->InsertFile(&headers, filename, "");
- mci.file_data = memory_cache_->GetFileData(filename);
- }
-
- interface_->AddToOutputOrder(mci);
- ASSERT_TRUE(HasStream(stream_id));
- interface_->ProcessReadInput(input, sizeof(input));
- ASSERT_NE(SpdyFramer::SPDY_READY_FOR_FRAME,
- interface_->spdy_framer()->state());
-
- interface_->ResetForNewConnection();
- ASSERT_FALSE(HasStream(stream_id));
- ASSERT_TRUE(interface_->spdy_framer() == NULL);
-}
-
-TEST_P(SpdySMProxyTest, CreateFramer) {
- interface_->ResetForNewConnection();
- interface_->CreateFramer(SPDY3);
- ASSERT_TRUE(interface_->spdy_framer() != NULL);
- ASSERT_EQ(interface_->spdy_version(), SPDY3);
-
- interface_->ResetForNewConnection();
- interface_->CreateFramer(HTTP2);
- ASSERT_TRUE(interface_->spdy_framer() != NULL);
- ASSERT_EQ(interface_->spdy_version(), HTTP2);
-}
-
-TEST_P(SpdySMProxyTest, PostAcceptHook) {
- interface_->PostAcceptHook();
-
- ASSERT_EQ(1u, connection_->output_list()->size());
- std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
- DataFrame* df = *i++;
-
- {
- InSequence s;
- EXPECT_CALL(*spdy_framer_visitor_, OnSettings(false));
- EXPECT_CALL(*spdy_framer_visitor_,
- OnSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 0u, 100u));
- }
- spdy_framer_->ProcessInput(df->data, df->size);
-}
-
-TEST_P(SpdySMProxyTest, NewStream) {
- // TODO(yhirano): SpdySM::NewStream leads to crash when
- // acceptor_->flip_handler_type_ != FLIP_HANDLER_SPDY_SERVER.
- // It should be fixed though I don't know the solution now.
-}
-
-TEST_P(SpdySMProxyTest, AddToOutputOrder) {
- uint32_t stream_id = 13;
- MemCacheIter mci;
- mci.stream_id = stream_id;
-
- {
- BalsaHeaders headers;
- std::string filename = "foobar";
- memory_cache_->InsertFile(&headers, filename, "");
- mci.file_data = memory_cache_->GetFileData(filename);
- }
-
- interface_->AddToOutputOrder(mci);
- ASSERT_TRUE(HasStream(stream_id));
-}
-
-TEST_P(SpdySMProxyTest, SendErrorNotFound) {
- uint32_t stream_id = 82;
- const char* actual_data;
- size_t actual_size;
- testing::MockFunction<void(int)> checkpoint; // NOLINT
-
- interface_->SendErrorNotFound(stream_id);
-
- ASSERT_EQ(2u, connection_->output_list()->size());
-
- {
- InSequence s;
- if (GetParam() < HTTP2) {
- EXPECT_CALL(*spdy_framer_visitor_, OnSynReplyMock(stream_id, false, _));
- } else {
- EXPECT_CALL(*spdy_framer_visitor_,
- OnHeadersMock(stream_id, /*has_priority=*/false, _, _, _,
- /*fin=*/false, _));
- }
- EXPECT_CALL(checkpoint, Call(0));
- EXPECT_CALL(*spdy_framer_visitor_,
- OnDataFrameHeader(stream_id, _, true));
- EXPECT_CALL(*spdy_framer_visitor_, OnStreamFrameData(stream_id, _, _))
- .Times(1)
- .WillOnce(DoAll(SaveArg<1>(&actual_data), SaveArg<2>(&actual_size)));
- EXPECT_CALL(*spdy_framer_visitor_, OnStreamFrameData(stream_id, NULL, 0))
- .Times(1);
- }
-
- std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
- DataFrame* df = *i++;
- spdy_framer_->ProcessInput(df->data, df->size);
- checkpoint.Call(0);
- df = *i++;
- spdy_framer_->ProcessInput(df->data, df->size);
-
- ASSERT_EQ(2, spdy_framer_->frames_received());
- ASSERT_EQ(2u, spdy_framer_visitor_->actual_header_block_.size());
- ASSERT_EQ("404 Not Found",
- spdy_framer_visitor_->actual_header_block_[":status"]);
- ASSERT_EQ("HTTP/1.1", spdy_framer_visitor_->actual_header_block_[":version"]);
- ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
-}
-
-TEST_P(SpdySMProxyTest, SendSynStream) {
- uint32_t stream_id = 82;
- BalsaHeaders headers;
- headers.AppendHeader("key1", "value1");
- headers.AppendHeader("Host", "www.example.com");
- headers.SetRequestFirstlineFromStringPieces("GET", "/path", "HTTP/1.1");
-
- interface_->SendSynStream(stream_id, headers);
-
- ASSERT_EQ(1u, connection_->output_list()->size());
- std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
- DataFrame* df = *i++;
-
- {
- InSequence s;
- EXPECT_CALL(*spdy_framer_visitor_,
- OnSynStreamMock(stream_id, 0, _, false, false, _));
- }
-
- spdy_framer_->ProcessInput(df->data, df->size);
- ASSERT_EQ(1, spdy_framer_->frames_received());
- ASSERT_EQ(5u, spdy_framer_visitor_->actual_header_block_.size());
- ASSERT_EQ("GET", spdy_framer_visitor_->actual_header_block_[":method"]);
- ASSERT_EQ("HTTP/1.1", spdy_framer_visitor_->actual_header_block_[":version"]);
- ASSERT_EQ("/path", spdy_framer_visitor_->actual_header_block_[":path"]);
- ASSERT_EQ("www.example.com",
- spdy_framer_visitor_->actual_header_block_[":host"]);
- ASSERT_EQ("value1", spdy_framer_visitor_->actual_header_block_["key1"]);
-}
-
-TEST_P(SpdySMProxyTest, SendSynReply) {
- uint32_t stream_id = 82;
- BalsaHeaders headers;
- headers.AppendHeader("key1", "value1");
- headers.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
-
- interface_->SendSynReply(stream_id, headers);
-
- ASSERT_EQ(1u, connection_->output_list()->size());
- std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
- DataFrame* df = *i++;
-
- {
- InSequence s;
- if (GetParam() < HTTP2) {
- EXPECT_CALL(*spdy_framer_visitor_, OnSynReplyMock(stream_id, false, _));
- } else {
- EXPECT_CALL(*spdy_framer_visitor_,
- OnHeadersMock(stream_id, /*has_priority=*/false, _, _, _,
- /*fin=*/false, _));
- }
- }
-
- spdy_framer_->ProcessInput(df->data, df->size);
- ASSERT_EQ(1, spdy_framer_->frames_received());
- ASSERT_EQ(3u, spdy_framer_visitor_->actual_header_block_.size());
- ASSERT_EQ("200 OK", spdy_framer_visitor_->actual_header_block_[":status"]);
- ASSERT_EQ("HTTP/1.1", spdy_framer_visitor_->actual_header_block_[":version"]);
- ASSERT_EQ("value1", spdy_framer_visitor_->actual_header_block_["key1"]);
-}
-
-TEST_P(SpdySMProxyTest, SendDataFrame) {
- uint32_t stream_id = 133;
- SpdyDataFlags flags = DATA_FLAG_NONE;
- const char* actual_data;
- size_t actual_size;
-
- interface_->SendDataFrame(stream_id, "hello", 5, flags, true);
-
- ASSERT_EQ(1u, connection_->output_list()->size());
- std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
- DataFrame* df = *i++;
-
- {
- InSequence s;
- EXPECT_CALL(*spdy_framer_visitor_,
- OnDataFrameHeader(stream_id, _, false));
- EXPECT_CALL(*spdy_framer_visitor_, OnStreamFrameData(stream_id, _, _))
- .WillOnce(DoAll(SaveArg<1>(&actual_data), SaveArg<2>(&actual_size)));
- }
-
- spdy_framer_->ProcessInput(df->data, df->size);
- ASSERT_EQ(1, spdy_framer_->frames_received());
- ASSERT_EQ("hello", StringPiece(actual_data, actual_size));
-}
-
-TEST_P(SpdySMProxyTest, SendLongDataFrame) {
- uint32_t stream_id = 133;
- SpdyDataFlags flags = DATA_FLAG_NONE;
- const char* actual_data;
- size_t actual_size;
-
- std::string data = std::string(kSpdySegmentSize, 'a') +
- std::string(kSpdySegmentSize, 'b') + "c";
- interface_->SendDataFrame(stream_id, data.data(), data.size(), flags, true);
-
- {
- InSequence s;
- for (int i = 0; i < 3; ++i) {
- EXPECT_CALL(*spdy_framer_visitor_,
- OnDataFrameHeader(stream_id, _, false));
- EXPECT_CALL(*spdy_framer_visitor_, OnStreamFrameData(stream_id, _, _))
- .WillOnce(
- DoAll(SaveArg<1>(&actual_data), SaveArg<2>(&actual_size)));
- }
- }
-
- ASSERT_EQ(3u, connection_->output_list()->size());
- std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
- DataFrame* df = *i++;
- spdy_framer_->ProcessInput(df->data, df->size);
- ASSERT_EQ(std::string(kSpdySegmentSize, 'a'),
- StringPiece(actual_data, actual_size));
-
- df = *i++;
- spdy_framer_->ProcessInput(df->data, df->size);
- ASSERT_EQ(std::string(kSpdySegmentSize, 'b'),
- StringPiece(actual_data, actual_size));
-
- df = *i++;
- spdy_framer_->ProcessInput(df->data, df->size);
- ASSERT_EQ("c", StringPiece(actual_data, actual_size));
-}
-
-TEST_P(SpdySMServerTest, OnSynStream) {
- BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
- uint32_t stream_id = 82;
- SpdyHeaderBlock spdy_headers;
- spdy_headers["url"] = "http://www.example.com/path";
- spdy_headers["method"] = "GET";
- spdy_headers["scheme"] = "http";
- spdy_headers["version"] = "HTTP/1.1";
-
- {
- BalsaHeaders headers;
- memory_cache_->InsertFile(&headers, "GET_/path", "");
- }
- visitor->OnSynStream(stream_id, 0, 0, true, true, spdy_headers);
- ASSERT_TRUE(HasStream(stream_id));
-}
-
-TEST_P(SpdySMServerTest, NewStream) {
- uint32_t stream_id = 13;
- std::string filename = "foobar";
-
- {
- BalsaHeaders headers;
- memory_cache_->InsertFile(&headers, filename, "");
- }
-
- interface_->NewStream(stream_id, 0, filename);
- ASSERT_TRUE(HasStream(stream_id));
-}
-
-TEST_P(SpdySMServerTest, NewStreamError) {
- uint32_t stream_id = 82;
- const char* actual_data;
- size_t actual_size;
- testing::MockFunction<void(int)> checkpoint; // NOLINT
-
- interface_->NewStream(stream_id, 0, "nonexistingfile");
-
- ASSERT_EQ(2u, connection_->output_list()->size());
-
- {
- InSequence s;
- if (GetParam() < HTTP2) {
- EXPECT_CALL(*spdy_framer_visitor_, OnSynReplyMock(stream_id, false, _));
- } else {
- EXPECT_CALL(*spdy_framer_visitor_,
- OnHeadersMock(stream_id, /*has_priority=*/false, _, _, _,
- /*fin=*/false, _));
- }
- EXPECT_CALL(checkpoint, Call(0));
- EXPECT_CALL(*spdy_framer_visitor_,
- OnDataFrameHeader(stream_id, _, true));
- EXPECT_CALL(*spdy_framer_visitor_, OnStreamFrameData(stream_id, _, _))
- .Times(1)
- .WillOnce(DoAll(SaveArg<1>(&actual_data), SaveArg<2>(&actual_size)));
- EXPECT_CALL(*spdy_framer_visitor_, OnStreamFrameData(stream_id, NULL, 0))
- .Times(1);
- }
-
- std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
- DataFrame* df = *i++;
- spdy_framer_->ProcessInput(df->data, df->size);
- checkpoint.Call(0);
- df = *i++;
- spdy_framer_->ProcessInput(df->data, df->size);
-
- ASSERT_EQ(2, spdy_framer_->frames_received());
- ASSERT_EQ(2u, spdy_framer_visitor_->actual_header_block_.size());
- ASSERT_EQ("404 Not Found",
- spdy_framer_visitor_->actual_header_block_["status"]);
- ASSERT_EQ("HTTP/1.1", spdy_framer_visitor_->actual_header_block_["version"]);
- ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
-}
-
-} // namespace
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/spdy_ssl.cc b/chromium/net/tools/flip_server/spdy_ssl.cc
deleted file mode 100644
index b2ce2bdfe4d..00000000000
--- a/chromium/net/tools/flip_server/spdy_ssl.cc
+++ /dev/null
@@ -1,114 +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/tools/flip_server/spdy_ssl.h"
-
-#include "base/logging.h"
-#include "openssl/err.h"
-#include "openssl/ssl.h"
-
-namespace net {
-
-// Each element consists of <the length of the string><string> .
-#define NEXT_PROTO_STRING \
- "\x08spdy/4a2" \
- "\x06spdy/3" \
- "\x06spdy/2" \
- "\x08http/1.1" \
- "\x08http/1.0"
-#define SSL_CIPHER_LIST "!aNULL:!ADH:!eNull:!LOW:!EXP:RC4+RSA:MEDIUM:HIGH"
-
-int ssl_set_npn_callback(SSL* s,
- const unsigned char** data,
- unsigned int* len,
- void* arg) {
- VLOG(1) << "SSL NPN callback: advertising protocols.";
- *data = (const unsigned char*)NEXT_PROTO_STRING;
- *len = strlen(NEXT_PROTO_STRING);
- return SSL_TLSEXT_ERR_OK;
-}
-
-void InitSSL(SSLState* state,
- std::string ssl_cert_name,
- std::string ssl_key_name,
- bool use_npn,
- int session_expiration_time,
- bool disable_ssl_compression) {
- SSL_library_init();
- PrintSslError();
-
- SSL_load_error_strings();
- PrintSslError();
-
- state->ssl_method = SSLv23_method();
- state->ssl_ctx = SSL_CTX_new(state->ssl_method);
- if (!state->ssl_ctx) {
- PrintSslError();
- LOG(FATAL) << "Unable to create SSL context";
- }
- // Disable SSLv2 support.
- SSL_CTX_set_options(state->ssl_ctx,
- SSL_OP_NO_SSLv2 | SSL_OP_CIPHER_SERVER_PREFERENCE);
- if (SSL_CTX_use_certificate_chain_file(state->ssl_ctx,
- ssl_cert_name.c_str()) <= 0) {
- PrintSslError();
- LOG(FATAL) << "Unable to use cert.pem as SSL cert.";
- }
- if (SSL_CTX_use_PrivateKey_file(
- state->ssl_ctx, ssl_key_name.c_str(), SSL_FILETYPE_PEM) <= 0) {
- PrintSslError();
- LOG(FATAL) << "Unable to use key.pem as SSL key.";
- }
- if (!SSL_CTX_check_private_key(state->ssl_ctx)) {
- PrintSslError();
- LOG(FATAL) << "The cert.pem and key.pem files don't match";
- }
- if (use_npn) {
- SSL_CTX_set_next_protos_advertised_cb(
- state->ssl_ctx, ssl_set_npn_callback, NULL);
- }
- VLOG(1) << "SSL CTX default cipher list: " << SSL_CIPHER_LIST;
- SSL_CTX_set_cipher_list(state->ssl_ctx, SSL_CIPHER_LIST);
-
- VLOG(1) << "SSL CTX session expiry: " << session_expiration_time
- << " seconds";
- SSL_CTX_set_timeout(state->ssl_ctx, session_expiration_time);
-
-#ifdef SSL_MODE_RELEASE_BUFFERS
- VLOG(1) << "SSL CTX: Setting Release Buffers mode.";
- SSL_CTX_set_mode(state->ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
-#endif
-
-#if !defined(OPENSSL_IS_BORINGSSL)
- // Proper methods to disable compression don't exist until 0.9.9+. For now
- // we must manipulate the stack of compression methods directly.
- if (disable_ssl_compression) {
- STACK_OF(SSL_COMP)* ssl_comp_methods = SSL_COMP_get_compression_methods();
- int num_methods = sk_SSL_COMP_num(ssl_comp_methods);
- int i;
- for (i = 0; i < num_methods; i++) {
- static_cast<void>(sk_SSL_COMP_delete(ssl_comp_methods, i));
- }
- }
-#endif
-}
-
-SSL* CreateSSLContext(SSL_CTX* ssl_ctx) {
- SSL* ssl = SSL_new(ssl_ctx);
- SSL_set_accept_state(ssl);
- PrintSslError();
- return ssl;
-}
-
-void PrintSslError() {
- char buf[128]; // this buffer must be at least 120 chars long.
- uint32_t error_num = ERR_get_error();
- while (error_num != 0) {
- ERR_error_string_n(error_num, buf, sizeof(buf));
- LOG(ERROR) << buf;
- error_num = ERR_get_error();
- }
-}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/spdy_ssl.h b/chromium/net/tools/flip_server/spdy_ssl.h
deleted file mode 100644
index 8b5573353fb..00000000000
--- a/chromium/net/tools/flip_server/spdy_ssl.h
+++ /dev/null
@@ -1,30 +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.
-
-#ifndef NET_TOOLS_FLIP_SERVER_SPDY_SSL_H_
-#define NET_TOOLS_FLIP_SERVER_SPDY_SSL_H_
-
-#include <string>
-
-#include "openssl/ssl.h"
-
-namespace net {
-
-struct SSLState {
- const SSL_METHOD* ssl_method;
- SSL_CTX* ssl_ctx;
-};
-
-void InitSSL(SSLState* state,
- std::string ssl_cert_name,
- std::string ssl_key_name,
- bool use_npn,
- int session_expiration_time,
- bool disable_ssl_compression);
-SSL* CreateSSLContext(SSL_CTX* ssl_ctx);
-void PrintSslError();
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_SPDY_SSL_H_
diff --git a/chromium/net/tools/flip_server/spdy_util.cc b/chromium/net/tools/flip_server/spdy_util.cc
deleted file mode 100644
index 34b6072cfa8..00000000000
--- a/chromium/net/tools/flip_server/spdy_util.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2009 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/flip_server/spdy_util.h"
-
-#include <string>
-
-#include "net/tools/flip_server/url_to_filename_encoder.h"
-
-namespace net {
-
-bool g_need_to_encode_url = false;
-
-// Encode the URL.
-std::string EncodeURL(const std::string& uri,
- const std::string& host,
- const std::string& method) {
- if (!g_need_to_encode_url) {
- // TODO(mbelshe): if uri is fully qualified, need to strip protocol/host.
- return std::string(method + "_" + uri);
- }
-
- std::string filename;
- if (uri[0] == '/') {
- // uri is not fully qualified.
- filename = UrlToFilenameEncoder::Encode(
- "http://" + host + uri, method + "_/", false);
- } else {
- filename = UrlToFilenameEncoder::Encode(uri, method + "_/", false);
- }
- return filename;
-}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/spdy_util.h b/chromium/net/tools/flip_server/spdy_util.h
deleted file mode 100644
index a418b3d0322..00000000000
--- a/chromium/net/tools/flip_server/spdy_util.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2009 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_FLIP_SERVER_SPDY_UTIL_H_
-#define NET_TOOLS_FLIP_SERVER_SPDY_UTIL_H_
-
-#include <string>
-
-namespace net {
-
-// Flag indicating if we need to encode urls into filenames (legacy).
-extern bool g_need_to_encode_url;
-
-// Encode the URL.
-std::string EncodeURL(const std::string& uri,
- const std::string& host,
- const std::string& method);
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_SPDY_UTIL_H_
diff --git a/chromium/net/tools/flip_server/streamer_interface.cc b/chromium/net/tools/flip_server/streamer_interface.cc
deleted file mode 100644
index 5f3d479ce04..00000000000
--- a/chromium/net/tools/flip_server/streamer_interface.cc
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright (c) 2009 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/flip_server/streamer_interface.h"
-
-#include <string>
-
-#include "net/tools/balsa/balsa_frame.h"
-#include "net/tools/flip_server/constants.h"
-#include "net/tools/flip_server/flip_config.h"
-#include "net/tools/flip_server/sm_connection.h"
-
-namespace net {
-
-std::string StreamerSM::forward_ip_header_;
-
-StreamerSM::StreamerSM(SMConnection* connection,
- SMInterface* sm_other_interface,
- EpollServer* epoll_server,
- FlipAcceptor* acceptor)
- : connection_(connection),
- sm_other_interface_(sm_other_interface),
- epoll_server_(epoll_server),
- acceptor_(acceptor),
- is_request_(false),
- http_framer_(new BalsaFrame) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Creating StreamerSM object";
- http_framer_->set_balsa_visitor(this);
- http_framer_->set_balsa_headers(&headers_);
- http_framer_->set_is_request(false);
-}
-
-StreamerSM::~StreamerSM() {
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Destroying StreamerSM object";
- Reset();
- delete http_framer_;
-}
-
-void StreamerSM::set_is_request() {
- is_request_ = true;
- http_framer_->set_is_request(true);
-}
-
-void StreamerSM::InitSMInterface(SMInterface* sm_other_interface,
- int32_t server_idx) {
- sm_other_interface_ = sm_other_interface;
-}
-
-void StreamerSM::InitSMConnection(SMConnectionPoolInterface* connection_pool,
- SMInterface* sm_interface,
- EpollServer* epoll_server,
- int fd,
- std::string server_ip,
- std::string server_port,
- std::string remote_ip,
- bool use_ssl) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "StreamerSM: Initializing server "
- << "connection.";
- connection_->InitSMConnection(connection_pool,
- sm_interface,
- epoll_server,
- fd,
- server_ip,
- server_port,
- remote_ip,
- use_ssl);
-}
-
-size_t StreamerSM::ProcessReadInput(const char* data, size_t len) {
- // For now we only want to parse http requests. Just stream responses
- if (is_request_) {
- return http_framer_->ProcessInput(data, len);
- } else {
- return sm_other_interface_->ProcessWriteInput(data, len);
- }
-}
-
-size_t StreamerSM::ProcessWriteInput(const char* data, size_t len) {
- char* dataPtr = new char[len];
- memcpy(dataPtr, data, len);
- DataFrame* df = new DataFrame;
- df->data = (const char*)dataPtr;
- df->size = len;
- df->delete_when_done = true;
- connection_->EnqueueDataFrame(df);
- return len;
-}
-
-bool StreamerSM::Error() const { return false; }
-
-const char* StreamerSM::ErrorAsString() const { return "(none)"; }
-
-bool StreamerSM::MessageFullyRead() const {
- if (is_request_) {
- return http_framer_->MessageFullyRead();
- } else {
- return false;
- }
-}
-
-void StreamerSM::Reset() {
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "StreamerSM: Reset";
- connection_->Cleanup("Server Reset");
- http_framer_->Reset();
-}
-
-void StreamerSM::ResetForNewConnection() {
- http_framer_->Reset();
- sm_other_interface_->Reset();
-}
-
-void StreamerSM::Cleanup() {
- if (is_request_)
- http_framer_->Reset();
-}
-
-int StreamerSM::PostAcceptHook() {
- if (!sm_other_interface_) {
- SMConnection* server_connection = SMConnection::NewSMConnection(
- epoll_server_, NULL, NULL, acceptor_, "server_conn: ");
- if (server_connection == NULL) {
- LOG(ERROR) << "StreamerSM: Could not create server conenction.";
- return 0;
- }
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "StreamerSM: Creating new server "
- << "connection.";
- sm_other_interface_ =
- new StreamerSM(server_connection, this, epoll_server_, acceptor_);
- sm_other_interface_->InitSMInterface(this, 0);
- }
- // The Streamer interface is used to stream HTTPS connections, so we
- // will always use the https_server_ip/port here.
- sm_other_interface_->InitSMConnection(NULL,
- sm_other_interface_,
- epoll_server_,
- -1,
- acceptor_->https_server_ip_,
- acceptor_->https_server_port_,
- std::string(),
- false);
-
- return 1;
-}
-
-size_t StreamerSM::SendSynStream(uint32_t stream_id,
- const BalsaHeaders& headers) {
- return 0;
-}
-
-size_t StreamerSM::SendSynReply(uint32_t stream_id,
- const BalsaHeaders& headers) {
- return 0;
-}
-
-void StreamerSM::ProcessBodyInput(const char* input, size_t size) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT
- << "StreamerHttpSM: Process Body Input Data: "
- << "size " << size;
- sm_other_interface_->ProcessWriteInput(input, size);
-}
-
-void StreamerSM::MessageDone() {
- if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "StreamerHttpSM: MessageDone.";
- // TODO(kelindsay): anything need to be done ehre?
- } else {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "StraemerHttpSM: MessageDone.";
- }
-}
-
-void StreamerSM::ProcessHeaders(const BalsaHeaders& headers) {
- VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpStreamerSM: Process Headers";
- BalsaHeaders mod_headers;
- mod_headers.CopyFrom(headers);
- if (forward_ip_header_.length()) {
- LOG(INFO) << "Adding forward header: " << forward_ip_header_;
- mod_headers.ReplaceOrAppendHeader(forward_ip_header_,
- connection_->client_ip());
- } else {
- LOG(INFO) << "NOT adding forward header.";
- }
- SimpleBuffer sb;
- char* buffer;
- int size;
- mod_headers.WriteHeaderAndEndingToBuffer(&sb);
- sb.GetReadablePtr(&buffer, &size);
- sm_other_interface_->ProcessWriteInput(buffer, size);
-}
-
-void StreamerSM::HandleHeaderError(BalsaFrame* framer) { HandleError(); }
-
-void StreamerSM::HandleChunkingError(BalsaFrame* framer) { HandleError(); }
-
-void StreamerSM::HandleBodyError(BalsaFrame* framer) { HandleError(); }
-
-void StreamerSM::HandleError() {
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Error detected";
-}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/streamer_interface.h b/chromium/net/tools/flip_server/streamer_interface.h
deleted file mode 100644
index f255427c053..00000000000
--- a/chromium/net/tools/flip_server/streamer_interface.h
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_STREAMER_INTERFACE_H_
-#define NET_TOOLS_FLIP_SERVER_STREAMER_INTERFACE_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "net/tools/balsa/balsa_headers.h"
-#include "net/tools/balsa/balsa_visitor_interface.h"
-#include "net/tools/flip_server/sm_interface.h"
-
-namespace net {
-
-class BalsaFrame;
-class FlipAcceptor;
-class MemCacheIter;
-class SMConnection;
-class EpollServer;
-
-class StreamerSM : public BalsaVisitorInterface, public SMInterface {
- public:
- StreamerSM(SMConnection* connection,
- SMInterface* sm_other_interface,
- EpollServer* epoll_server,
- FlipAcceptor* acceptor);
- ~StreamerSM() override;
-
- void AddToOutputOrder(const MemCacheIter& mci) {}
-
- void InitSMInterface(SMInterface* sm_other_interface,
- int32_t server_idx) override;
- void InitSMConnection(SMConnectionPoolInterface* connection_pool,
- SMInterface* sm_interface,
- EpollServer* epoll_server,
- int fd,
- std::string server_ip,
- std::string server_port,
- std::string remote_ip,
- bool use_ssl) override;
-
- size_t ProcessReadInput(const char* data, size_t len) override;
- size_t ProcessWriteInput(const char* data, size_t len) override;
- bool MessageFullyRead() const override;
- void SetStreamID(uint32_t stream_id) override {}
- bool Error() const override;
- const char* ErrorAsString() const override;
- void Reset() override;
- void ResetForNewInterface(int32_t server_idx) override {}
- void ResetForNewConnection() override;
- void Cleanup() override;
- int PostAcceptHook() override;
- void NewStream(uint32_t stream_id,
- uint32_t priority,
- const std::string& filename) override {}
- void SendEOF(uint32_t stream_id) override {}
- void SendErrorNotFound(uint32_t stream_id) override {}
- virtual void SendOKResponse(uint32_t stream_id, const std::string& output) {}
- size_t SendSynStream(uint32_t stream_id,
- const BalsaHeaders& headers) override;
- size_t SendSynReply(uint32_t stream_id, const BalsaHeaders& headers) override;
- void SendDataFrame(uint32_t stream_id,
- const char* data,
- int64_t len,
- uint32_t flags,
- bool compress) override {}
- void set_is_request() override;
- static std::string forward_ip_header() { return forward_ip_header_; }
- static void set_forward_ip_header(const std::string& value) {
- forward_ip_header_ = value;
- }
-
- private:
- void SendEOFImpl(uint32_t stream_id) {}
- void SendErrorNotFoundImpl(uint32_t stream_id) {}
- void SendOKResponseImpl(uint32_t stream_id, std::string* output) {}
- size_t SendSynReplyImpl(uint32_t stream_id, const BalsaHeaders& headers) {
- return 0;
- }
- size_t SendSynStreamImpl(uint32_t stream_id, const BalsaHeaders& headers) {
- return 0;
- }
- void SendDataFrameImpl(uint32_t stream_id,
- const char* data,
- int64_t len,
- uint32_t flags,
- bool compress) {}
- void GetOutput() override {}
-
- void ProcessBodyInput(const char* input, size_t size) override;
- void MessageDone() override;
- void ProcessHeaders(const BalsaHeaders& headers) override;
- void ProcessBodyData(const char* input, size_t size) override {}
- void ProcessHeaderInput(const char* input, size_t size) override {}
- void ProcessTrailerInput(const char* input, size_t size) override {}
- void ProcessRequestFirstLine(const char* line_input,
- size_t line_length,
- const char* method_input,
- size_t method_length,
- const char* request_uri_input,
- size_t request_uri_length,
- const char* version_input,
- size_t version_length) override {}
- void ProcessResponseFirstLine(const char* line_input,
- size_t line_length,
- const char* version_input,
- size_t version_length,
- const char* status_input,
- size_t status_length,
- const char* reason_input,
- size_t reason_length) override {}
- void ProcessChunkLength(size_t chunk_length) override {}
- void ProcessChunkExtensions(const char* input, size_t size) override {}
- void HeaderDone() override {}
- void HandleHeaderError(BalsaFrame* framer) override;
- void HandleHeaderWarning(BalsaFrame* framer) override {}
- void HandleChunkingError(BalsaFrame* framer) override;
- void HandleBodyError(BalsaFrame* framer) override;
- void HandleError();
-
- SMConnection* connection_;
- SMInterface* sm_other_interface_;
- EpollServer* epoll_server_;
- FlipAcceptor* acceptor_;
- bool is_request_;
- BalsaFrame* http_framer_;
- BalsaHeaders headers_;
- static std::string forward_ip_header_;
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_STREAMER_INTERFACE_H_
diff --git a/chromium/net/tools/flip_server/tcp_socket_util.cc b/chromium/net/tools/flip_server/tcp_socket_util.cc
deleted file mode 100644
index 00f9b7e59e0..00000000000
--- a/chromium/net/tools/flip_server/tcp_socket_util.cc
+++ /dev/null
@@ -1,276 +0,0 @@
-// Copyright (c) 2009 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/flip_server/tcp_socket_util.h"
-
-#include <arpa/inet.h>
-#include <errno.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "net/socket/tcp_socket.h"
-
-namespace net {
-
-namespace {
-
-// Used to ensure we delete the addrinfo structure alloc'd by getaddrinfo().
-class AddrinfoGuard {
- public:
- explicit AddrinfoGuard(struct addrinfo* addrinfo_ptr)
- : addrinfo_ptr_(addrinfo_ptr) {}
-
- ~AddrinfoGuard() { freeaddrinfo(addrinfo_ptr_); }
-
- private:
- struct addrinfo* addrinfo_ptr_;
-};
-
-// Summary:
-// Closes a socket, with option to attempt it multiple times.
-// Why do this? Well, if the system-call gets interrupted, close
-// can fail with EINTR. In that case you should just retry.. Unfortunately,
-// we can't be sure that errno is properly set since we're using a
-// multithreaded approach in the filter proxy, so we should just retry.
-// Args:
-// fd - the socket to close
-// tries - the number of tries to close the socket.
-// Returns:
-// true - if socket was closed
-// false - if socket was NOT closed.
-// Side-effects:
-// sets *fd to -1 if socket was closed.
-//
-bool CloseSocket(int* fd, int tries) {
- for (int i = 0; i < tries; ++i) {
- if (!close(*fd)) {
- *fd = -1;
- return true;
- }
- }
- return false;
-}
-
-} // namespace
-
-int CreateTCPServerSocket(const std::string& host,
- const std::string& port,
- bool is_numeric_host_address,
- int backlog,
- bool reuseaddr,
- bool reuseport,
- bool wait_for_iface,
- bool disable_nagle,
- int* listen_fd) {
- // start out by assuming things will fail.
- *listen_fd = -1;
-
- const char* node = NULL;
- const char* service = NULL;
-
- if (!host.empty())
- node = host.c_str();
- if (!port.empty())
- service = port.c_str();
-
- struct addrinfo* results = 0;
- struct addrinfo hints;
- memset(&hints, 0, sizeof(hints));
-
- if (is_numeric_host_address) {
- hints.ai_flags = AI_NUMERICHOST; // iff you know the name is numeric.
- }
- hints.ai_flags |= AI_PASSIVE;
-
- hints.ai_family = PF_INET;
- hints.ai_socktype = SOCK_STREAM;
-
- int err = 0;
- if ((err = getaddrinfo(node, service, &hints, &results))) {
- // gai_strerror -is- threadsafe, so we get to use it here.
- LOG(ERROR) << "getaddrinfo "
- << " for (" << host << ":" << port << ") " << gai_strerror(err)
- << "\n";
- return -1;
- }
- // this will delete the addrinfo memory when we return from this function.
- AddrinfoGuard addrinfo_guard(results);
-
- int sock =
- socket(results->ai_family, results->ai_socktype, results->ai_protocol);
- if (sock == -1) {
- LOG(ERROR) << "Unable to create socket for (" << host << ":" << port
- << "): " << strerror(errno) << "\n";
- return -1;
- }
-
- if (reuseaddr) {
- // set SO_REUSEADDR on the listening socket.
- int on = 1;
- int rc;
- rc = setsockopt(sock,
- SOL_SOCKET,
- SO_REUSEADDR,
- reinterpret_cast<char*>(&on),
- sizeof(on));
- if (rc < 0) {
- close(sock);
- LOG(FATAL) << "setsockopt() failed fd=" << listen_fd << "\n";
- }
- }
-#ifndef SO_REUSEPORT
-#define SO_REUSEPORT 15
-#endif
- if (reuseport) {
- // set SO_REUSEPORT on the listening socket.
- int on = 1;
- int rc;
- rc = setsockopt(sock,
- SOL_SOCKET,
- SO_REUSEPORT,
- reinterpret_cast<char*>(&on),
- sizeof(on));
- if (rc < 0) {
- close(sock);
- LOG(FATAL) << "setsockopt() failed fd=" << listen_fd << "\n";
- }
- }
-
- if (bind(sock, results->ai_addr, results->ai_addrlen)) {
- // If we are waiting for the interface to be raised, such as in an
- // HA environment, ignore reporting any errors.
- int saved_errno = errno;
- if (!wait_for_iface || errno != EADDRNOTAVAIL) {
- LOG(ERROR) << "Bind was unsuccessful for (" << host << ":" << port
- << "): " << strerror(errno) << "\n";
- }
- // if we knew that we were not multithreaded, we could do the following:
- // " : " << strerror(errno) << "\n";
- if (CloseSocket(&sock, 100)) {
- if (saved_errno == EADDRNOTAVAIL) {
- return -3;
- }
- return -2;
- } else {
- // couldn't even close the dang socket?!
- LOG(ERROR) << "Unable to close the socket.. Considering this a fatal "
- "error, and exiting\n";
- exit(EXIT_FAILURE);
- return -1;
- }
- }
-
- if (disable_nagle) {
- if (!SetTCPNoDelay(sock, /*no_delay=*/true)) {
- close(sock);
- LOG(FATAL) << "SetTCPNoDelay() failed on fd: " << sock;
- return -1;
- }
- }
-
- if (listen(sock, backlog)) {
- // listen was unsuccessful.
- LOG(ERROR) << "Listen was unsuccessful for (" << host << ":" << port
- << "): " << strerror(errno) << "\n";
- // if we knew that we were not multithreaded, we could do the following:
- // " : " << strerror(errno) << "\n";
-
- if (CloseSocket(&sock, 100)) {
- sock = -1;
- return -1;
- } else {
- // couldn't even close the dang socket?!
- LOG(FATAL) << "Unable to close the socket.. Considering this a fatal "
- "error, and exiting\n";
- }
- }
-
- // If we've gotten to here, Yeay! Success!
- *listen_fd = sock;
-
- return 0;
-}
-
-int CreateTCPClientSocket(const std::string& host,
- const std::string& port,
- bool is_numeric_host_address,
- bool disable_nagle,
- int* connect_fd) {
- const char* node = NULL;
- const char* service = NULL;
-
- *connect_fd = -1;
- if (!host.empty())
- node = host.c_str();
- if (!port.empty())
- service = port.c_str();
-
- struct addrinfo* results = 0;
- struct addrinfo hints;
- memset(&hints, 0, sizeof(hints));
-
- if (is_numeric_host_address)
- hints.ai_flags = AI_NUMERICHOST; // iff you know the name is numeric.
- hints.ai_flags |= AI_PASSIVE;
-
- hints.ai_family = PF_INET;
- hints.ai_socktype = SOCK_STREAM;
-
- int err = 0;
- if ((err = getaddrinfo(node, service, &hints, &results))) {
- // gai_strerror -is- threadsafe, so we get to use it here.
- LOG(ERROR) << "getaddrinfo for (" << node << ":" << service
- << "): " << gai_strerror(err);
- return -1;
- }
- // this will delete the addrinfo memory when we return from this function.
- AddrinfoGuard addrinfo_guard(results);
-
- int sock =
- socket(results->ai_family, results->ai_socktype, results->ai_protocol);
- if (sock == -1) {
- LOG(ERROR) << "Unable to create socket for (" << node << ":" << service
- << "): " << strerror(errno);
- return -1;
- }
-
- if (!base::SetNonBlocking(sock)) {
- LOG(FATAL) << "base::SetNonBlocking failed: " << sock;
- }
-
- if (disable_nagle) {
- if (!SetTCPNoDelay(sock, /*no_delay=*/true)) {
- close(sock);
- LOG(FATAL) << "SetTCPNoDelay() failed on fd: " << sock;
- return -1;
- }
- }
-
- int ret_val = 0;
- if (connect(sock, results->ai_addr, results->ai_addrlen)) {
- if (errno != EINPROGRESS) {
- LOG(ERROR) << "Connect was unsuccessful for (" << node << ":" << service
- << "): " << strerror(errno);
- close(sock);
- return -1;
- }
- } else {
- ret_val = 1;
- }
-
- // If we've gotten to here, Yeay! Success!
- *connect_fd = sock;
-
- return ret_val;
-}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/tcp_socket_util.h b/chromium/net/tools/flip_server/tcp_socket_util.h
deleted file mode 100644
index 4e2e910ef43..00000000000
--- a/chromium/net/tools/flip_server/tcp_socket_util.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2009 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_FLIP_SERVER_TCP_SOCKET_UTIL_H_
-#define NET_TOOLS_FLIP_SERVER_TCP_SOCKET_UTIL_H_
-
-#include <string>
-
-namespace net {
-
-// Summary:
-// creates a socket for listening, and bind()s and listen()s it.
-// Args:
-// host - hostname or numeric address, or empty-string if you want
-// to bind to listen on all addresses
-// port - a port number or service name. By service name I mean a
-// -real- service name, not a Google service name. I'd suggest
-// you just stick to a numeric representation like "80"
-// is_numeric_host_address -
-// if you know that the host address has already been looked-up,
-// and will be provided in numeric form like "130.207.244.244",
-// then you can set this to true, and it will save you the time
-// of a DNS lookup.
-// backlog - passed into listen. This is the number of pending incoming
-// connections a socket which is listening may have acquired before
-// the OS starts rejecting new incoming connections.
-// reuseaddr - if true sets SO_REUSEADDR on the listening socket
-// reuseport - if true sets SO_REUSEPORT on the listening socket
-// wait_for_iface - A boolean indicating that CreateTCPServerSocket should
-// block until the interface that it will bind to has been
-// raised. This is intended for HA environments.
-// disable_nagle - if true sets TCP_NODELAY on the listening socket.
-// listen_fd - this will be assigned a positive value if the socket is
-// successfully created, else it will be assigned -1.
-int CreateTCPServerSocket(const std::string& host,
- const std::string& port,
- bool is_numeric_host_address,
- int backlog,
- bool reuseaddr,
- bool reuseport,
- bool wait_for_iface,
- bool disable_nagle,
- int* listen_fd);
-
-int CreateTCPClientSocket(const std::string& host,
- const std::string& port,
- bool is_numeric_host_address,
- bool disable_nagle,
- int* connect_fd);
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_TCP_SOCKET_UTIL_H_
diff --git a/chromium/net/tools/flip_server/url_to_filename_encoder.cc b/chromium/net/tools/flip_server/url_to_filename_encoder.cc
deleted file mode 100644
index b5a01d18c37..00000000000
--- a/chromium/net/tools/flip_server/url_to_filename_encoder.cc
+++ /dev/null
@@ -1,275 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/tools/flip_server/url_to_filename_encoder.h"
-
-#include <stdlib.h>
-
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-
-using std::string;
-
-namespace {
-
-#ifdef WIN32
-#define strtoull _strtoui64
-#endif
-
-// A simple parser for long long values. Returns the parsed value if a
-// valid integer is found; else returns deflt
-// UInt64 and Int64 cannot handle decimal numbers with leading 0s.
-uint64_t ParseLeadingHex64Value(const char* str, uint64_t deflt) {
- char* error = NULL;
- const uint64_t value = strtoull(str, &error, 16);
- return (error == str) ? deflt : value;
-}
-
-} // namespace
-
-namespace net {
-
-// The escape character choice is made here -- all code and tests in this
-// directory are based off of this constant. However, our testdata
-// has tons of dependencies on this, so it cannot be changed without
-// re-running those tests and fixing them.
-const char UrlToFilenameEncoder::kEscapeChar = ',';
-const char UrlToFilenameEncoder::kTruncationChar = '-';
-const size_t UrlToFilenameEncoder::kMaximumSubdirectoryLength = 128;
-
-void UrlToFilenameEncoder::AppendSegment(string* segment, string* dest) {
- CHECK(!segment->empty());
- if ((*segment == ".") || (*segment == "..")) {
- dest->append(1, kEscapeChar);
- dest->append(*segment);
- segment->clear();
- } else {
- size_t segment_size = segment->size();
- if (segment_size > kMaximumSubdirectoryLength) {
- // We need to inject ",-" at the end of the segment to signify that
- // we are inserting an artificial '/'. This means we have to chop
- // off at least two characters to make room.
- segment_size = kMaximumSubdirectoryLength - 2;
-
- // But we don't want to break up an escape sequence that happens to lie at
- // the end. Escape sequences are at most 2 characters.
- if ((*segment)[segment_size - 1] == kEscapeChar) {
- segment_size -= 1;
- } else if ((*segment)[segment_size - 2] == kEscapeChar) {
- segment_size -= 2;
- }
- dest->append(segment->data(), segment_size);
- dest->append(1, kEscapeChar);
- dest->append(1, kTruncationChar);
- segment->erase(0, segment_size);
-
- // At this point, if we had segment_size=3, and segment="abcd",
- // then after this erase, we will have written "abc,-" and set segment="d"
- } else {
- dest->append(*segment);
- segment->clear();
- }
- }
-}
-
-void UrlToFilenameEncoder::EncodeSegment(const string& filename_prefix,
- const string& escaped_ending,
- char dir_separator,
- string* encoded_filename) {
- string filename_ending = UrlUtilities::Unescape(escaped_ending);
-
- char encoded[3];
- int encoded_len;
- string segment;
-
- // TODO(jmarantz): This code would be a bit simpler if we disallowed
- // Instaweb allowing filename_prefix to not end in "/". We could
- // then change the is routine to just take one input string.
- size_t start_of_segment = filename_prefix.find_last_of(dir_separator);
- if (start_of_segment == string::npos) {
- segment = filename_prefix;
- } else {
- segment = filename_prefix.substr(start_of_segment + 1);
- *encoded_filename = filename_prefix.substr(0, start_of_segment + 1);
- }
-
- size_t index = 0;
- // Special case the first / to avoid adding a leading kEscapeChar.
- if (!filename_ending.empty() && (filename_ending[0] == dir_separator)) {
- encoded_filename->append(segment);
- segment.clear();
- encoded_filename->append(1, dir_separator);
- ++index;
- }
-
- for (; index < filename_ending.length(); ++index) {
- unsigned char ch = static_cast<unsigned char>(filename_ending[index]);
-
- // Note: instead of outputing an empty segment, we let the second slash
- // be escaped below.
- if ((ch == dir_separator) && !segment.empty()) {
- AppendSegment(&segment, encoded_filename);
- encoded_filename->append(1, dir_separator);
- segment.clear();
- } else {
- // After removing unsafe chars the only safe ones are _.=+- and alphanums.
- if ((ch == '_') || (ch == '.') || (ch == '=') || (ch == '+') ||
- (ch == '-') || (('0' <= ch) && (ch <= '9')) ||
- (('A' <= ch) && (ch <= 'Z')) || (('a' <= ch) && (ch <= 'z'))) {
- encoded[0] = ch;
- encoded_len = 1;
- } else {
- encoded[0] = kEscapeChar;
- encoded[1] = ch / 16;
- encoded[1] += (encoded[1] >= 10) ? 'A' - 10 : '0';
- encoded[2] = ch % 16;
- encoded[2] += (encoded[2] >= 10) ? 'A' - 10 : '0';
- encoded_len = 3;
- }
- segment.append(encoded, encoded_len);
-
- // If segment is too big, we must chop it into chunks.
- if (segment.size() > kMaximumSubdirectoryLength) {
- AppendSegment(&segment, encoded_filename);
- encoded_filename->append(1, dir_separator);
- }
- }
- }
-
- // Append "," to the leaf filename so the leaf can also be a branch., e.g.
- // allow http://a/b/c and http://a/b/c/d to co-exist as files "/a/b/c," and
- // /a/b/c/d". So we will rename the "d" here to "d,". If doing that pushed
- // us over the 128 char limit, then we will need to append "/" and the
- // remaining chars.
- segment += kEscapeChar;
- AppendSegment(&segment, encoded_filename);
- if (!segment.empty()) {
- // The last overflow segment is special, because we appended in
- // kEscapeChar above. We won't need to check it again for size
- // or further escaping.
- encoded_filename->append(1, dir_separator);
- encoded_filename->append(segment);
- }
-}
-
-// Note: this decoder is not the exact inverse of the EncodeSegment above,
-// because it does not take into account a prefix.
-bool UrlToFilenameEncoder::Decode(const string& encoded_filename,
- char dir_separator,
- string* decoded_url) {
- enum State { kStart, kEscape, kFirstDigit, kTruncate, kEscapeDot };
- State state = kStart;
- char hex_buffer[3];
- hex_buffer[2] = '\0';
- for (size_t i = 0; i < encoded_filename.size(); ++i) {
- char ch = encoded_filename[i];
- switch (state) {
- case kStart:
- if (ch == kEscapeChar) {
- state = kEscape;
- } else if (ch == dir_separator) {
- decoded_url->append(1, '/'); // URLs only use '/' not '\\'
- } else {
- decoded_url->append(1, ch);
- }
- break;
- case kEscape:
- if (base::IsHexDigit(ch)) {
- hex_buffer[0] = ch;
- state = kFirstDigit;
- } else if (ch == kTruncationChar) {
- state = kTruncate;
- } else if (ch == '.') {
- decoded_url->append(1, '.');
- state = kEscapeDot; // Look for at most one more dot.
- } else if (ch == dir_separator) {
- // Consider url "//x". This was once encoded to "/,/x,".
- // This code is what skips the first Escape.
- decoded_url->append(1, '/'); // URLs only use '/' not '\\'
- state = kStart;
- } else {
- return false;
- }
- break;
- case kFirstDigit:
- if (base::IsHexDigit(ch)) {
- hex_buffer[1] = ch;
- uint64_t hex_value = ParseLeadingHex64Value(hex_buffer, 0);
- decoded_url->append(1, static_cast<char>(hex_value));
- state = kStart;
- } else {
- return false;
- }
- break;
- case kTruncate:
- if (ch == dir_separator) {
- // Skip this separator, it was only put in to break up long
- // path segments, but is not part of the URL.
- state = kStart;
- } else {
- return false;
- }
- break;
- case kEscapeDot:
- decoded_url->append(1, ch);
- state = kStart;
- break;
- }
- }
-
- // All legal encoded filenames end in kEscapeChar.
- return (state == kEscape);
-}
-
-// Escape the given input |path| and chop any individual components
-// of the path which are greater than kMaximumSubdirectoryLength characters
-// into two chunks.
-//
-// This legacy version has several issues with aliasing of different URLs,
-// inability to represent both /a/b/c and /a/b/c/d, and inability to decode
-// the filenames back into URLs.
-//
-// But there is a large body of slurped data which depends on this format,
-// so leave it as the default for spdy_in_mem_edsm_server.
-string UrlToFilenameEncoder::LegacyEscape(const string& path) {
- string output;
-
- // Note: We also chop paths into medium sized 'chunks'.
- // This is due to the incompetence of the windows
- // filesystem, which still hasn't figured out how
- // to deal with long filenames.
- int last_slash = 0;
- for (size_t index = 0; index < path.length(); index++) {
- char ch = path[index];
- if (ch == 0x5C)
- last_slash = index;
- if ((ch == 0x2D) || // hyphen
- (ch == 0x5C) || (ch == 0x5F) || // backslash, underscore
- ((0x30 <= ch) && (ch <= 0x39)) || // Digits [0-9]
- ((0x41 <= ch) && (ch <= 0x5A)) || // Uppercase [A-Z]
- ((0x61 <= ch) && (ch <= 0x7A))) { // Lowercase [a-z]
- output.append(&path[index], 1);
- } else {
- char encoded[3];
- encoded[0] = 'x';
- encoded[1] = ch / 16;
- encoded[1] += (encoded[1] >= 10) ? 'A' - 10 : '0';
- encoded[2] = ch % 16;
- encoded[2] += (encoded[2] >= 10) ? 'A' - 10 : '0';
- output.append(encoded, 3);
- }
- if (index - last_slash > kMaximumSubdirectoryLength) {
-#ifdef WIN32
- char slash = '\\';
-#else
- char slash = '/';
-#endif
- output.append(&slash, 1);
- last_slash = index;
- }
- }
- return output;
-}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/url_to_filename_encoder.h b/chromium/net/tools/flip_server/url_to_filename_encoder.h
deleted file mode 100644
index c68a9a1d4cc..00000000000
--- a/chromium/net/tools/flip_server/url_to_filename_encoder.h
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright (c) 2010 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.
-
-// URL filename encoder goals:
-//
-// 1. Allow URLs with arbitrary path-segment length, generating filenames
-// with a maximum of 128 characters.
-// 2. Provide a somewhat human readable filenames, for easy debugging flow.
-// 3. Provide reverse-mapping from filenames back to URLs.
-// 4. Be able to distinguish http://x from http://x/ from http://x/index.html.
-// Those can all be different URLs.
-// 5. Be able to represent http://a/b/c and http://a/b/c/d, a pattern seen
-// with Facebook Connect.
-//
-// We need an escape-character for representing characters that are legal
-// in URL paths, but not in filenames, such as '?'.
-//
-// We can pick any legal character as an escape, as long as we escape it too.
-// But as we have a goal of having filenames that humans can correlate with
-// URLs, we should pick one that doesn't show up frequently in URLs. Candidates
-// are ~`!@#$%^&()-=_+{}[],. but we would prefer to avoid characters that are
-// shell escapes or that various build tools use.
-//
-// .#&%-=_+ occur frequently in URLs.
-// <>:"/\|?* are illegal in Windows
-// See http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
-// ~`!$^&(){}[]'; are special to Unix shells
-// In addition, build tools do not like ^@#%
-//
-// Josh took a quick look at the frequency of some special characters in
-// Sadeesh's slurped directory from Fall 09 and found the following occurances:
-//
-// ^ 3 build tool doesn't like ^ in testdata filenames
-// @ 10 build tool doesn't like @ in testdata filenames
-// . 1676 too frequent in URLs
-// , 76 THE WINNER
-// # 0 build tool doesn't like it
-// & 487 Prefer to avoid shell escapes
-// % 374 g4 doesn't like it
-// = 579 very frequent in URLs -- leave unmodified
-// - 464 very frequent in URLs -- leave unmodified
-// _ 798 very frequent in URLs -- leave unmodified
-//
-//
-// The escaping algorithm is:
-// 1) Escape all unfriendly symbols as ,XX where XX is the hex code.
-// 2) Add a ',' at the end (We do not allow ',' at end of any directory name,
-// so this assures that e.g. /a and /a/b can coexist in the filesystem).
-// 3) Go through the path segment by segment (where a segment is one directory
-// or leaf in the path) and
-// 3a) If the segment is empty, escape the second slash. i.e. if it was
-// www.foo.com//a then we escape the second / like www.foo.com/,2Fa,
-// 3a) If it is "." or ".." prepend with ',' (so that we have a non-
-// empty and non-reserved filename).
-// 3b) If it is over 128 characters, break it up into smaller segments by
-// inserting ,-/ (Windows limits paths to 128 chars, other OSes also
-// have limits that would restrict us)
-//
-// For example:
-// URL File
-// / /,
-// /index.html /index.html,
-// /. /.,
-// /a/b /a/b,
-// /a/b/ /a/b/,
-// /a/b/c /a/b/c, Note: no prefix problem
-// /u?foo=bar /u,3Ffoo=bar,
-// // /,2F,
-// /./ /,./,
-// /../ /,../,
-// /, /,2C,
-// /,./ /,2C./,
-// /very...longname/ /very...long,-/name If very...long is about 126 long.
-
-// NOTE: we avoid using some classes here (like FilePath and GURL) because we
-// share this code with other projects externally.
-
-#ifndef NET_TOOLS_FLIP_SERVER_URL_TO_FILENAME_ENCODER_H_
-#define NET_TOOLS_FLIP_SERVER_URL_TO_FILENAME_ENCODER_H_
-
-#include <stddef.h>
-
-#include <string>
-
-#include "base/strings/string_util.h"
-#include "net/tools/flip_server/url_utilities.h"
-
-namespace net {
-
-// Helper class for converting a URL into a filename.
-class UrlToFilenameEncoder {
- public:
- // Given a |url| and a |base_path|, returns a filename which represents this
- // |url|. |url| may include URL escaping such as %21 for !
- // |legacy_escape| indicates that this function should use the old-style
- // of encoding.
- // TODO(mbelshe): delete the legacy_escape code.
- static std::string Encode(const std::string& url,
- std::string base_path,
- bool legacy_escape) {
- std::string filename;
- if (!legacy_escape) {
- std::string url_no_scheme = UrlUtilities::GetUrlHostPath(url);
- EncodeSegment(base_path, url_no_scheme, '/', &filename);
-#ifdef WIN32
- ReplaceAll(&filename, "/", "\\");
-#endif
- } else {
- std::string clean_url(url);
- if (clean_url.length() && clean_url.back() == '/')
- clean_url.append("index.html");
-
- std::string host = UrlUtilities::GetUrlHost(clean_url);
- filename.append(base_path);
- filename.append(host);
-#ifdef WIN32
- filename.append("\\");
-#else
- filename.append("/");
-#endif
-
- std::string url_filename = UrlUtilities::GetUrlPath(clean_url);
- // Strip the leading '/'.
- if (url_filename[0] == '/')
- url_filename = url_filename.substr(1);
-
- // Replace '/' with '\'.
- ConvertToSlashes(&url_filename);
-
- // Strip double back-slashes ("\\\\").
- StripDoubleSlashes(&url_filename);
-
- // Save path as filesystem-safe characters.
- url_filename = LegacyEscape(url_filename);
- filename.append(url_filename);
-
-#ifndef WIN32
- // Last step - convert to native slashes.
- const std::string slash("/");
- const std::string backslash("\\");
- ReplaceAll(&filename, backslash, slash);
-#endif
- }
-
- return filename;
- }
-
- // Rewrite HTML in a form that the SPDY in-memory server
- // can read.
- // |filename_prefix| is prepended without escaping.
- // |escaped_ending| is the URL to be encoded into a filename. It may have URL
- // escaped characters (like %21 for !).
- // |dir_separator| is "/" on Unix, "\" on Windows.
- // |encoded_filename| is the resultant filename.
- static void EncodeSegment(const std::string& filename_prefix,
- const std::string& escaped_ending,
- char dir_separator,
- std::string* encoded_filename);
-
- // Decodes a filename that was encoded with EncodeSegment,
- // yielding back the original URL.
- static bool Decode(const std::string& encoded_filename,
- char dir_separator,
- std::string* decoded_url);
-
- static const char kEscapeChar;
- static const char kTruncationChar;
- static const size_t kMaximumSubdirectoryLength;
-
- friend class UrlToFilenameEncoderTest;
-
- private:
- // Appends a segment of the path, special-casing "." and "..", and
- // ensuring that the segment does not exceed the path length. If it does,
- // it chops the end off the segment, writes the segment with a separator of
- // ",-/", and then rewrites segment to contain just the truncated piece so
- // it can be used in the next iteration.
- // |segment| is a read/write parameter containing segment to write
- // Note: this should not be called with empty segment.
- static void AppendSegment(std::string* segment, std::string* dest);
-
- // Allow reading of old slurped files.
- static std::string LegacyEscape(const std::string& path);
-
- // Replace all instances of |from| within |str| as |to|.
- static void ReplaceAll(std::string* str,
- const std::string& from,
- const std::string& to) {
- std::string::size_type pos(0);
- while ((pos = str->find(from, pos)) != std::string::npos) {
- str->replace(pos, from.size(), to);
- pos += from.size();
- }
- }
-
- // Replace all instances of "/" with "\" in |path|.
- static void ConvertToSlashes(std::string* path) {
- const std::string slash("/");
- const std::string backslash("\\");
- ReplaceAll(path, slash, backslash);
- }
-
- // Replace all instances of "\\" with "%5C%5C" in |path|.
- static void StripDoubleSlashes(std::string* path) {
- const std::string doubleslash("\\\\");
- const std::string escaped_doubleslash("%5C%5C");
- ReplaceAll(path, doubleslash, escaped_doubleslash);
- }
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_URL_TO_FILENAME_ENCODER_H_
diff --git a/chromium/net/tools/flip_server/url_to_filename_encoder_unittest.cc b/chromium/net/tools/flip_server/url_to_filename_encoder_unittest.cc
deleted file mode 100644
index 2662f756d2f..00000000000
--- a/chromium/net/tools/flip_server/url_to_filename_encoder_unittest.cc
+++ /dev/null
@@ -1,357 +0,0 @@
-// Copyright (c) 2010 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/flip_server/url_to_filename_encoder.h"
-
-#include <string>
-#include <vector>
-
-#include "base/strings/string_piece.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::StringPiece;
-using std::string;
-
-namespace net {
-
-#ifdef WIN32
-char kDirSeparator = '\\';
-char kOtherDirSeparator = '/';
-#else
-char kDirSeparator = '/';
-char kOtherDirSeparator = '\\';
-#endif
-
-class UrlToFilenameEncoderTest : public ::testing::Test {
- protected:
- UrlToFilenameEncoderTest()
- : escape_(1, UrlToFilenameEncoder::kEscapeChar),
- dir_sep_(1, kDirSeparator) {}
-
- void CheckSegmentLength(const StringPiece& escaped_word) {
- for (const base::StringPiece& component :
- base::SplitStringPiece(escaped_word, "/", base::KEEP_WHITESPACE,
- base::SPLIT_WANT_NONEMPTY)) {
- EXPECT_GE(UrlToFilenameEncoder::kMaximumSubdirectoryLength,
- component.size());
- }
- }
-
- void CheckValidChars(const StringPiece& escaped_word, char invalid_slash) {
- // These characters are invalid in Windows. We add in ', as that's pretty
- // inconvenient in a Unix filename.
- //
- // See http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
- const string kInvalidChars = "<>:\"|?*'";
- for (size_t i = 0; i < escaped_word.size(); ++i) {
- char c = escaped_word[i];
- EXPECT_EQ(string::npos, kInvalidChars.find(c));
- EXPECT_NE(invalid_slash, c);
- EXPECT_NE('\0', c); // only invalid character in Posix
- EXPECT_GT(0x7E, c); // only English printable characters
- }
- }
-
- void Validate(const string& in_word, const string& gold_word) {
- string escaped_word, url;
- UrlToFilenameEncoder::EncodeSegment(std::string(), in_word, '/',
- &escaped_word);
- EXPECT_EQ(gold_word, escaped_word);
- CheckSegmentLength(escaped_word);
- CheckValidChars(escaped_word, '\\');
- UrlToFilenameEncoder::Decode(escaped_word, '/', &url);
- EXPECT_EQ(in_word, url);
- }
-
- void ValidateAllSegmentsSmall(const string& in_word) {
- string escaped_word, url;
- UrlToFilenameEncoder::EncodeSegment(std::string(), in_word, '/',
- &escaped_word);
- CheckSegmentLength(escaped_word);
- CheckValidChars(escaped_word, '\\');
- UrlToFilenameEncoder::Decode(escaped_word, '/', &url);
- EXPECT_EQ(in_word, url);
- }
-
- void ValidateNoChange(const string& word) {
- // We always suffix the leaf with kEscapeChar, unless the leaf is empty.
- Validate(word, word + escape_);
- }
-
- void ValidateEscaped(unsigned char ch) {
- // We always suffix the leaf with kEscapeChar, unless the leaf is empty.
- char escaped[100];
- const char escape = UrlToFilenameEncoder::kEscapeChar;
- base::snprintf(escaped, sizeof(escaped), "%c%02X%c", escape, ch, escape);
- Validate(string(1, ch), escaped);
- }
-
- void ValidateUrl(const string& url,
- const string& base_path,
- bool legacy_escape,
- const string& gold_filename) {
- string encoded_filename =
- UrlToFilenameEncoder::Encode(url, base_path, legacy_escape);
- EXPECT_EQ(gold_filename, encoded_filename);
- if (!legacy_escape) {
- CheckSegmentLength(encoded_filename);
- CheckValidChars(encoded_filename, kOtherDirSeparator);
- string decoded_url;
- UrlToFilenameEncoder::Decode(encoded_filename, kDirSeparator,
- &decoded_url);
- if (url != decoded_url) {
- EXPECT_EQ(url, "http://" + decoded_url);
- }
- }
- }
-
- void ValidateUrlOldNew(const string& url,
- const string& gold_old_filename,
- const string& gold_new_filename) {
- ValidateUrl(url, std::string(), true, gold_old_filename);
- ValidateUrl(url, std::string(), false, gold_new_filename);
- }
-
- void ValidateEncodeSame(const string& url1, const string& url2) {
- string filename1 = UrlToFilenameEncoder::Encode(url1, std::string(), false);
- string filename2 = UrlToFilenameEncoder::Encode(url2, std::string(), false);
- EXPECT_EQ(filename1, filename2);
- }
-
- string escape_;
- string dir_sep_;
-};
-
-TEST_F(UrlToFilenameEncoderTest, DoesNotEscape) {
- ValidateNoChange(std::string());
- ValidateNoChange("abcdefg");
- ValidateNoChange("abcdefghijklmnopqrstuvwxyz");
- ValidateNoChange("ZYXWVUT");
- ValidateNoChange("ZYXWVUTSRQPONMLKJIHGFEDCBA");
- ValidateNoChange("01234567689");
- ValidateNoChange("_.=+-");
- ValidateNoChange(
- "abcdefghijklmnopqrstuvwxyzZYXWVUTSRQPONMLKJIHGFEDCBA"
- "01234567689_.=+-");
- ValidateNoChange("index.html");
- ValidateNoChange("/");
- ValidateNoChange("/.");
- ValidateNoChange(".");
- ValidateNoChange("..");
-}
-
-TEST_F(UrlToFilenameEncoderTest, Escapes) {
- const string bad_chars =
- "<>:\"\\|?*" // Illegal on Windows
- "~`!$^&(){}[]';" // Bad for Unix shells
- "^@" // Build tool doesn't like
- "#%" // Tool doesn't like
- ","; // The escape char has to be escaped
-
- for (size_t i = 0; i < bad_chars.size(); ++i) {
- ValidateEscaped(bad_chars[i]);
- }
-
- // Check non-printable characters.
- ValidateEscaped('\0');
- for (size_t i = 127; i < 256; ++i) {
- ValidateEscaped(static_cast<char>(i));
- }
-}
-
-TEST_F(UrlToFilenameEncoderTest, DoesEscapeCorrectly) {
- Validate("mysite.com&x", "mysite.com" + escape_ + "26x" + escape_);
- Validate("/./", "/" + escape_ + "./" + escape_);
- Validate("/../", "/" + escape_ + "../" + escape_);
- Validate("//", "/" + escape_ + "2F" + escape_);
- Validate("/./leaf", "/" + escape_ + "./leaf" + escape_);
- Validate("/../leaf", "/" + escape_ + "../leaf" + escape_);
- Validate("//leaf", "/" + escape_ + "2Fleaf" + escape_);
- Validate("mysite/u?param1=x&param2=y", "mysite/u" + escape_ + "3Fparam1=x" +
- escape_ + "26param2=y" + escape_);
- Validate("search?q=dogs&go=&form=QBLH&qs=n", // from Latency Labs bing test.
- "search" + escape_ + "3Fq=dogs" + escape_ + "26go=" + escape_ +
- "26form=QBLH" + escape_ + "26qs=n" + escape_);
- Validate("~joebob/my_neeto-website+with_stuff.asp?id=138&content=true",
- "" + escape_ + "7Ejoebob/my_neeto-website+with_stuff.asp" + escape_ +
- "3Fid=138" + escape_ + "26content=true" + escape_);
-}
-
-TEST_F(UrlToFilenameEncoderTest, EncodeUrlCorrectly) {
- ValidateUrlOldNew("http://www.google.com/index.html",
- "www.google.com" + dir_sep_ + "indexx2Ehtml",
- "www.google.com" + dir_sep_ + "index.html" + escape_);
- ValidateUrlOldNew("http://www.google.com/x/search?hl=en&q=dogs&oq=",
- "www.google.com" + dir_sep_ + "x" + dir_sep_ +
- "searchx3Fhlx3Denx26qx3Ddogsx26oqx3D",
-
- "www.google.com" + dir_sep_ + "x" + dir_sep_ + "search" +
- escape_ + "3Fhl=en" + escape_ + "26q=dogs" + escape_ +
- "26oq=" + escape_);
- ValidateUrlOldNew(
- "http://www.foo.com/a//",
- "www.foo.com" + dir_sep_ + "ax255Cx255Cindexx2Ehtml",
- "www.foo.com" + dir_sep_ + "a" + dir_sep_ + escape_ + "2F" + escape_);
-
- // From bug: Double slash preserved.
- ValidateUrl("http://www.foo.com/u?site=http://www.google.com/index.html",
- std::string(), false,
- "www.foo.com" + dir_sep_ + "u" + escape_ + "3Fsite=http" +
- escape_ + "3A" + dir_sep_ + escape_ + "2Fwww.google.com" +
- dir_sep_ + "index.html" + escape_);
- ValidateUrlOldNew(
- "http://blogutils.net/olct/online.php?"
- "site=http://thelwordfanfics.blogspot.&interval=600",
-
- "blogutils.net" + dir_sep_ + "olct" + dir_sep_ +
- "onlinex2Ephpx3F"
- "sitex3Dhttpx3Ax255Cx255Cthelwordfanficsx2Eblogspotx2Ex26intervalx3D6"
- "00",
-
- "blogutils.net" + dir_sep_ + "olct" + dir_sep_ + "online.php" + escape_ +
- "3Fsite=http" + escape_ + "3A" + dir_sep_ + escape_ +
- "2Fthelwordfanfics.blogspot." + escape_ + "26interval=600" + escape_);
-}
-
-// From bug: Escapes treated the same as normal char.
-TEST_F(UrlToFilenameEncoderTest, UnescapeUrlsBeforeEncode) {
- for (int i = 0; i < 128; ++i) {
- string unescaped(1, static_cast<char>(i));
- string escaped = base::StringPrintf("%%%02X", i);
- ValidateEncodeSame(unescaped, escaped);
- }
-
- ValidateEncodeSame(
- "http://www.blogger.com/navbar.g?bName=God!&Mode=FOO&searchRoot"
- "=http%3A%2F%2Fsurvivorscanthrive.blogspot.com%2Fsearch",
-
- "http://www.blogger.com/navbar.g?bName=God%21&Mode=FOO&searchRoot"
- "=http%3A%2F%2Fsurvivorscanthrive.blogspot.com%2Fsearch");
-}
-
-// From bug: Filename encoding is not prefix-free.
-TEST_F(UrlToFilenameEncoderTest, EscapeSecondSlash) {
- Validate("/", "/" + escape_);
- Validate("//", "/" + escape_ + "2F" + escape_);
- Validate("///", "/" + escape_ + "2F" + "/" + escape_);
-}
-
-TEST_F(UrlToFilenameEncoderTest, LongTail) {
- static char long_word[] =
- "~joebob/briggs/12345678901234567890123456789012345678901234567890"
- "1234567890123456789012345678901234567890123456789012345678901234567890"
- "1234567890123456789012345678901234567890123456789012345678901234567890"
- "1234567890123456789012345678901234567890123456789012345678901234567890"
- "1234567890123456789012345678901234567890123456789012345678901234567890"
- "1234567890123456789012345678901234567890123456789012345678901234567890";
-
- // the long lines in the string below are 64 characters, so we can see
- // the slashes every 128.
- string gold_long_word =
- escape_ +
- "7Ejoebob/briggs/"
- "1234567890123456789012345678901234567890123456789012345678901234"
- "56789012345678901234567890123456789012345678901234567890123456" +
- escape_ +
- "-/"
- "7890123456789012345678901234567890123456789012345678901234567890"
- "12345678901234567890123456789012345678901234567890123456789012" +
- escape_ +
- "-/"
- "3456789012345678901234567890123456789012345678901234567890123456"
- "78901234567890123456789012345678901234567890123456789012345678" +
- escape_ +
- "-/"
- "9012345678901234567890" +
- escape_;
- EXPECT_LT(UrlToFilenameEncoder::kMaximumSubdirectoryLength,
- sizeof(long_word));
- Validate(long_word, gold_long_word);
-}
-
-TEST_F(UrlToFilenameEncoderTest, LongTailQuestion) {
- // Here the '?' in the last path segment expands to @3F, making
- // it hit 128 chars before the input segment gets that big.
- static char long_word[] =
- "~joebob/briggs/1234567?1234567?1234567?1234567?1234567?"
- "1234567?1234567?1234567?1234567?1234567?1234567?1234567?"
- "1234567?1234567?1234567?1234567?1234567?1234567?1234567?"
- "1234567?1234567?1234567?1234567?1234567?1234567?1234567?"
- "1234567?1234567?1234567?1234567?1234567?1234567?1234567?"
- "1234567?1234567?1234567?1234567?1234567?1234567?1234567?";
-
- // Notice that at the end of the third segment, we avoid splitting
- // the (escape_ + "3F") that was generated from the "?", so that segment is
- // only 127 characters.
- string pattern = "1234567" + escape_ + "3F"; // 10 characters
- string gold_long_word =
- escape_ + "7Ejoebob/briggs/" + pattern + pattern + pattern + pattern +
- pattern + pattern +
- "1234"
- "567" +
- escape_ + "3F" + pattern + pattern + pattern + pattern + pattern +
- "123456" + escape_ +
- "-/"
- "7" +
- escape_ + "3F" + pattern + pattern + pattern + pattern + pattern +
- pattern + pattern + pattern + pattern + pattern + pattern + pattern +
- "12" + escape_ +
- "-/"
- "34567" +
- escape_ + "3F" + pattern + pattern + pattern + pattern + pattern +
- "1234567" + escape_ + "3F" + pattern + pattern + pattern + pattern +
- pattern + "1234567" + escape_ + "-/" + escape_ + "3F" + pattern +
- pattern + escape_;
- EXPECT_LT(UrlToFilenameEncoder::kMaximumSubdirectoryLength,
- sizeof(long_word));
- Validate(long_word, gold_long_word);
-}
-
-TEST_F(UrlToFilenameEncoderTest, CornerCasesNearMaxLenNoEscape) {
- // hit corner cases, +/- 4 characters from kMaxLen
- for (int i = -4; i <= 4; ++i) {
- string input;
- input.append(i + UrlToFilenameEncoder::kMaximumSubdirectoryLength, 'x');
- ValidateAllSegmentsSmall(input);
- }
-}
-
-TEST_F(UrlToFilenameEncoderTest, CornerCasesNearMaxLenWithEscape) {
- // hit corner cases, +/- 4 characters from kMaxLen. This time we
- // leave off the last 'x' and put in a '.', which ensures that we
- // are truncating with '/' *after* the expansion.
- for (int i = -4; i <= 4; ++i) {
- string input;
- input.append(i + UrlToFilenameEncoder::kMaximumSubdirectoryLength - 1, 'x');
- input.append(1, '.'); // this will expand to 3 characters.
- ValidateAllSegmentsSmall(input);
- }
-}
-
-TEST_F(UrlToFilenameEncoderTest, LeafBranchAlias) {
- Validate("/a/b/c", "/a/b/c" + escape_); // c is leaf file "c,"
- Validate("/a/b/c/d", "/a/b/c/d" + escape_); // c is directory "c"
- Validate("/a/b/c/d/", "/a/b/c/d/" + escape_);
-}
-
-TEST_F(UrlToFilenameEncoderTest, BackslashSeparator) {
- string long_word;
- string escaped_word;
- long_word.append(UrlToFilenameEncoder::kMaximumSubdirectoryLength + 1, 'x');
- UrlToFilenameEncoder::EncodeSegment(std::string(), long_word, '\\',
- &escaped_word);
-
- // check that one backslash, plus the escape ",-", and the ending , got added.
- EXPECT_EQ(long_word.size() + 4, escaped_word.size());
- ASSERT_LT(UrlToFilenameEncoder::kMaximumSubdirectoryLength,
- escaped_word.size());
- // Check that the backslash got inserted at the correct spot.
- EXPECT_EQ('\\',
- escaped_word[UrlToFilenameEncoder::kMaximumSubdirectoryLength]);
-}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/url_utilities.cc b/chromium/net/tools/flip_server/url_utilities.cc
deleted file mode 100644
index 735fb8e9069..00000000000
--- a/chromium/net/tools/flip_server/url_utilities.cc
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright (c) 2010 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/flip_server/url_utilities.h"
-
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-
-namespace net {
-
-std::string UrlUtilities::GetUrlHost(const std::string& url) {
- size_t b = url.find("//");
- if (b == std::string::npos)
- b = 0;
- else
- b += 2;
- size_t next_slash = url.find_first_of('/', b);
- size_t next_colon = url.find_first_of(':', b);
- if (next_slash != std::string::npos && next_colon != std::string::npos &&
- next_colon < next_slash) {
- return std::string(url, b, next_colon - b);
- }
- if (next_slash == std::string::npos) {
- if (next_colon != std::string::npos) {
- return std::string(url, b, next_colon - b);
- } else {
- next_slash = url.size();
- }
- }
- return std::string(url, b, next_slash - b);
-}
-
-std::string UrlUtilities::GetUrlHostPath(const std::string& url) {
- size_t b = url.find("//");
- if (b == std::string::npos)
- b = 0;
- else
- b += 2;
- return std::string(url, b);
-}
-
-std::string UrlUtilities::GetUrlPath(const std::string& url) {
- size_t b = url.find("//");
- if (b == std::string::npos)
- b = 0;
- else
- b += 2;
- b = url.find("/", b);
- if (b == std::string::npos)
- return "/";
-
- size_t e = url.find("#", b + 1);
- if (e != std::string::npos)
- return std::string(url, b, (e - b));
- return std::string(url, b);
-}
-
-namespace {
-
-// Parsing states for UrlUtilities::Unescape
-enum UnescapeState {
- NORMAL, // We are not in the middle of parsing an escape.
- ESCAPE1, // We just parsed % .
- ESCAPE2 // We just parsed %X for some hex digit X.
-};
-
-} // namespace
-
-std::string UrlUtilities::Unescape(const std::string& escaped_url) {
- std::string unescaped_url, escape_text;
- int escape_value;
- UnescapeState state = NORMAL;
- std::string::const_iterator iter = escaped_url.begin();
- while (iter < escaped_url.end()) {
- char c = *iter;
- switch (state) {
- case NORMAL:
- if (c == '%') {
- escape_text.clear();
- state = ESCAPE1;
- } else {
- unescaped_url.push_back(c);
- }
- ++iter;
- break;
- case ESCAPE1:
- if (base::IsHexDigit(c)) {
- escape_text.push_back(c);
- state = ESCAPE2;
- ++iter;
- } else {
- // Unexpected, % followed by non-hex chars, pass it through.
- unescaped_url.push_back('%');
- state = NORMAL;
- }
- break;
- case ESCAPE2:
- if (base::IsHexDigit(c)) {
- escape_text.push_back(c);
- bool ok = base::HexStringToInt(escape_text, &escape_value);
- DCHECK(ok);
- unescaped_url.push_back(static_cast<unsigned char>(escape_value));
- state = NORMAL;
- ++iter;
- } else {
- // Unexpected, % followed by non-hex chars, pass it through.
- unescaped_url.push_back('%');
- unescaped_url.append(escape_text);
- state = NORMAL;
- }
- break;
- }
- }
- // Unexpected, % followed by end of string, pass it through.
- if (state == ESCAPE1 || state == ESCAPE2) {
- unescaped_url.push_back('%');
- unescaped_url.append(escape_text);
- }
- return unescaped_url;
-}
-
-} // namespace net
diff --git a/chromium/net/tools/flip_server/url_utilities.h b/chromium/net/tools/flip_server/url_utilities.h
deleted file mode 100644
index 318c087a607..00000000000
--- a/chromium/net/tools/flip_server/url_utilities.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2010 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_FLIP_SERVER_URL_UTILITIES_H_
-#define NET_TOOLS_FLIP_SERVER_URL_UTILITIES_H_
-
-#include <string>
-
-namespace net {
-
-struct UrlUtilities {
- // Gets the host from an url, strips the port number as well if the url
- // has one.
- // For example: calling GetUrlHost(www.foo.com:8080/boo) returns www.foo.com
- static std::string GetUrlHost(const std::string& url);
-
- // Get the host + path portion of an url
- // e.g http://www.foo.com/path
- // returns www.foo.com/path
- static std::string GetUrlHostPath(const std::string& url);
-
- // Gets the path portion of an url.
- // e.g http://www.foo.com/path
- // returns /path
- static std::string GetUrlPath(const std::string& url);
-
- // Unescape a url, converting all %XX to the the actual char 0xXX.
- // For example, this will convert "foo%21bar" to "foo!bar".
- static std::string Unescape(const std::string& escaped_url);
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_URL_UTILITIES_H_
diff --git a/chromium/net/tools/flip_server/url_utilities_unittest.cc b/chromium/net/tools/flip_server/url_utilities_unittest.cc
deleted file mode 100644
index b766c6cf3ab..00000000000
--- a/chromium/net/tools/flip_server/url_utilities_unittest.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (c) 2010 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/flip_server/url_utilities.h"
-
-#include <string>
-
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-TEST(UrlUtilitiesTest, GetUrlHost) {
- EXPECT_EQ("www.foo.com", UrlUtilities::GetUrlHost("http://www.foo.com"));
- EXPECT_EQ("www.foo.com", UrlUtilities::GetUrlHost("http://www.foo.com:80"));
- EXPECT_EQ("www.foo.com", UrlUtilities::GetUrlHost("http://www.foo.com:80/"));
- EXPECT_EQ("www.foo.com", UrlUtilities::GetUrlHost("http://www.foo.com/news"));
- EXPECT_EQ("www.foo.com",
- UrlUtilities::GetUrlHost("www.foo.com:80/news?q=hello"));
- EXPECT_EQ("www.foo.com", UrlUtilities::GetUrlHost("www.foo.com/news?q=a:b"));
- EXPECT_EQ("www.foo.com", UrlUtilities::GetUrlHost("www.foo.com:80"));
-}
-
-TEST(UrlUtilitiesTest, GetUrlHostPath) {
- EXPECT_EQ("www.foo.com", UrlUtilities::GetUrlHostPath("http://www.foo.com"));
- EXPECT_EQ("www.foo.com:80",
- UrlUtilities::GetUrlHostPath("http://www.foo.com:80"));
- EXPECT_EQ("www.foo.com:80/",
- UrlUtilities::GetUrlHostPath("http://www.foo.com:80/"));
- EXPECT_EQ("www.foo.com/news",
- UrlUtilities::GetUrlHostPath("http://www.foo.com/news"));
- EXPECT_EQ("www.foo.com:80/news?q=hello",
- UrlUtilities::GetUrlHostPath("www.foo.com:80/news?q=hello"));
- EXPECT_EQ("www.foo.com/news?q=a:b",
- UrlUtilities::GetUrlHostPath("www.foo.com/news?q=a:b"));
- EXPECT_EQ("www.foo.com:80", UrlUtilities::GetUrlHostPath("www.foo.com:80"));
-}
-
-TEST(UrlUtilitiesTest, GetUrlPath) {
- EXPECT_EQ("/", UrlUtilities::GetUrlPath("http://www.foo.com"));
- EXPECT_EQ("/", UrlUtilities::GetUrlPath("http://www.foo.com:80"));
- EXPECT_EQ("/", UrlUtilities::GetUrlPath("http://www.foo.com:80/"));
- EXPECT_EQ("/news", UrlUtilities::GetUrlPath("http://www.foo.com/news"));
- EXPECT_EQ("/news?q=hello",
- UrlUtilities::GetUrlPath("www.foo.com:80/news?q=hello"));
- EXPECT_EQ("/news?q=a:b", UrlUtilities::GetUrlPath("www.foo.com/news?q=a:b"));
- EXPECT_EQ("/", UrlUtilities::GetUrlPath("www.foo.com:80"));
-}
-
-TEST(UrlUtilitiesTest, Unescape) {
- // Basic examples are left alone.
- EXPECT_EQ("http://www.foo.com", UrlUtilities::Unescape("http://www.foo.com"));
- EXPECT_EQ("www.foo.com:80/news?q=hello",
- UrlUtilities::Unescape("www.foo.com:80/news?q=hello"));
-
- // All chars can be unescaped.
- EXPECT_EQ("~`!@#$%^&*()_-+={[}]|\\:;\"'<,>.?/",
- UrlUtilities::Unescape("%7E%60%21%40%23%24%25%5E%26%2A%28%29%5F%2D"
- "%2B%3D%7B%5B%7D%5D%7C%5C%3A%3B%22%27%3C%2C"
- "%3E%2E%3F%2F"));
- for (int c = 0; c < 256; ++c) {
- std::string unescaped_char(1, static_cast<unsigned char>(c));
- std::string escaped_char = base::StringPrintf("%%%02X", c);
- EXPECT_EQ(unescaped_char, UrlUtilities::Unescape(escaped_char))
- << "escaped_char = " << escaped_char;
- escaped_char = base::StringPrintf("%%%02x", c);
- EXPECT_EQ(unescaped_char, UrlUtilities::Unescape(escaped_char))
- << "escaped_char = " << escaped_char;
- }
-
- // All non-% chars are left alone.
- EXPECT_EQ("~`!@#$^&*()_-+={[}]|\\:;\"'<,>.?/",
- UrlUtilities::Unescape("~`!@#$^&*()_-+={[}]|\\:;\"'<,>.?/"));
- for (int c = 0; c < 256; ++c) {
- if (c != '%') {
- std::string just_char(1, static_cast<unsigned char>(c));
- EXPECT_EQ(just_char, UrlUtilities::Unescape(just_char));
- }
- }
-
- // Some examples to unescape.
- EXPECT_EQ("Hello, world!", UrlUtilities::Unescape("Hello%2C world%21"));
-
- // Not actually escapes.
- EXPECT_EQ("%", UrlUtilities::Unescape("%"));
- EXPECT_EQ("%www", UrlUtilities::Unescape("%www"));
- EXPECT_EQ("%foo", UrlUtilities::Unescape("%foo"));
- EXPECT_EQ("%1", UrlUtilities::Unescape("%1"));
- EXPECT_EQ("%1x", UrlUtilities::Unescape("%1x"));
- EXPECT_EQ("%%", UrlUtilities::Unescape("%%"));
- // Escapes following non-escapes.
- EXPECT_EQ("%!", UrlUtilities::Unescape("%%21"));
- EXPECT_EQ("%2!", UrlUtilities::Unescape("%2%21"));
-}
-
-} // namespace net
diff --git a/chromium/net/tools/gdig/file_net_log.cc b/chromium/net/tools/gdig/file_net_log.cc
index 1281f8abbe2..0e55682e198 100644
--- a/chromium/net/tools/gdig/file_net_log.cc
+++ b/chromium/net/tools/gdig/file_net_log.cc
@@ -11,6 +11,7 @@
#include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
#include "base/values.h"
+#include "net/log/net_log_entry.h"
namespace net {
@@ -22,8 +23,8 @@ FileNetLogObserver::FileNetLogObserver(FILE* destination)
FileNetLogObserver::~FileNetLogObserver() {
}
-void FileNetLogObserver::OnAddEntry(const net::NetLog::Entry& entry) {
- // Only BoundNetLogs without a NetLog should have an invalid source.
+void FileNetLogObserver::OnAddEntry(const net::NetLogEntry& entry) {
+ // Only NetLogWithSources without a NetLog should have an invalid source.
DCHECK(entry.source().IsValid());
const char* source = NetLog::SourceTypeToString(entry.source().type);
diff --git a/chromium/net/tools/gdig/file_net_log.h b/chromium/net/tools/gdig/file_net_log.h
index b39111d7d46..4d52f1807a3 100644
--- a/chromium/net/tools/gdig/file_net_log.h
+++ b/chromium/net/tools/gdig/file_net_log.h
@@ -22,7 +22,7 @@ class FileNetLogObserver : public NetLog::ThreadSafeObserver {
~FileNetLogObserver() override;
// NetLog::ThreadSafeObserver implementation:
- void OnAddEntry(const net::NetLog::Entry& entry) override;
+ void OnAddEntry(const net::NetLogEntry& entry) override;
private:
FILE* const destination_;
diff --git a/chromium/net/tools/gdig/gdig.cc b/chromium/net/tools/gdig/gdig.cc
index f3d84e31b49..3eceb46ce82 100644
--- a/chromium/net/tools/gdig/gdig.cc
+++ b/chromium/net/tools/gdig/gdig.cc
@@ -35,6 +35,9 @@
#include "net/dns/host_cache.h"
#include "net/dns/host_resolver_impl.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_source_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/tools/gdig/file_net_log.h"
#if defined(OS_MACOSX)
@@ -231,6 +234,7 @@ class GDig {
std::unique_ptr<FileNetLogObserver> log_observer_;
std::unique_ptr<NetLog> log_;
std::unique_ptr<HostResolver> resolver_;
+ std::unique_ptr<HostResolver::Request> request_;
#if defined(OS_MACOSX)
// Without this there will be a mem leak on osx.
@@ -468,12 +472,8 @@ void GDig::ReplayNextEntry() {
++active_resolves_;
++replay_log_index_;
int ret = resolver_->Resolve(
- info,
- DEFAULT_PRIORITY,
- addrlist,
- callback,
- NULL,
- BoundNetLog::Make(log_.get(), net::NetLog::SOURCE_NONE));
+ info, DEFAULT_PRIORITY, addrlist, callback, &request_,
+ NetLogWithSource::Make(log_.get(), net::NetLogSourceType::NONE));
if (ret != ERR_IO_PENDING)
callback.Run(ret);
}
diff --git a/chromium/net/tools/get_server_time/get_server_time.cc b/chromium/net/tools/get_server_time/get_server_time.cc
index 6bb3471d162..75ca214f8a7 100644
--- a/chromium/net/tools/get_server_time/get_server_time.cc
+++ b/chromium/net/tools/get_server_time/get_server_time.cc
@@ -25,6 +25,7 @@
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
@@ -34,6 +35,7 @@
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_entry.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_context.h"
@@ -82,7 +84,8 @@ class QuitDelegate : public net::URLFetcherDelegate {
void OnURLFetchDownloadProgress(const net::URLFetcher* source,
int64_t current,
- int64_t total) override {
+ int64_t total,
+ int64_t current_network_bytes) override {
NOTREACHED();
}
@@ -108,7 +111,7 @@ class PrintingLogObserver : public net::NetLog::ThreadSafeObserver {
}
// NetLog::ThreadSafeObserver implementation:
- void OnAddEntry(const net::NetLog::Entry& entry) override {
+ void OnAddEntry(const net::NetLogEntry& entry) override {
// The log level of the entry is unknown, so just assume it maps
// to VLOG(1).
if (!VLOG_IS_ON(1))
@@ -145,7 +148,7 @@ std::unique_ptr<net::URLRequestContext> BuildURLRequestContext(
//
// TODO(akalin): Remove this once http://crbug.com/146421 is fixed.
builder.set_proxy_config_service(
- base::WrapUnique(new net::ProxyConfigServiceFixed(net::ProxyConfig())));
+ base::MakeUnique<net::ProxyConfigServiceFixed>(net::ProxyConfig()));
#endif
std::unique_ptr<net::URLRequestContext> context(builder.Build());
context->set_net_log(net_log);
@@ -252,7 +255,7 @@ int main(int argc, char* argv[]) {
start_ticks.ToInternalValue());
// |delegate| quits |main_loop| when the request is done.
- main_loop.Run();
+ base::RunLoop().Run();
const base::Time end_time = base::Time::Now();
const base::TimeTicks end_ticks = base::TimeTicks::Now();
diff --git a/chromium/net/tools/net_watcher/net_watcher.cc b/chromium/net/tools/net_watcher/net_watcher.cc
index b623954c6e6..02cb3987ace 100644
--- a/chromium/net/tools/net_watcher/net_watcher.cc
+++ b/chromium/net/tools/net_watcher/net_watcher.cc
@@ -3,6 +3,12 @@
// found in the LICENSE file.
// This is a small utility that watches for and logs network changes.
+// It prints out the current network connection type and proxy configuration
+// upon startup and then prints out changes as they happen.
+// It's useful for testing NetworkChangeNotifier and ProxyConfigService.
+// The only command line option supported is --ignore-netif which is followed
+// by a comma seperated list of network interfaces to ignore when computing
+// connection type; this option is only supported on linux.
#include <memory>
#include <string>
@@ -15,6 +21,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/strings/string_split.h"
#include "base/values.h"
#include "build/build_config.h"
@@ -23,10 +30,6 @@
#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_service.h"
-#if defined(USE_GLIB) && !defined(OS_CHROMEOS)
-#include <glib-object.h>
-#endif
-
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
#include "net/base/network_change_notifier_linux.h"
#endif
@@ -144,16 +147,6 @@ int main(int argc, char* argv[]) {
#if defined(OS_MACOSX)
base::mac::ScopedNSAutoreleasePool pool;
#endif
-#if defined(USE_GLIB) && !defined(OS_CHROMEOS)
- // 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 !GLIB_CHECK_VERSION(2, 35, 0)
- // Needed so ProxyConfigServiceLinux can use gconf.
- // Normally handled by BrowserMainLoop::InitializeToolkit().
- g_type_init();
-#endif
-#endif // defined(USE_GLIB) && !defined(OS_CHROMEOS)
base::AtExitManager exit_manager;
base::CommandLine::Init(argc, argv);
logging::LoggingSettings settings;
@@ -214,7 +207,7 @@ int main(int argc, char* argv[]) {
LOG(INFO) << "Watching for network events...";
// Start watching for events.
- network_loop.Run();
+ base::RunLoop().Run();
proxy_config_service->RemoveObserver(&net_watcher);
diff --git a/chromium/net/tools/quic/chlo_extractor.cc b/chromium/net/tools/quic/chlo_extractor.cc
index 55e68a09ccf..3e5ce787f7a 100644
--- a/chromium/net/tools/quic/chlo_extractor.cc
+++ b/chromium/net/tools/quic/chlo_extractor.cc
@@ -4,12 +4,13 @@
#include "net/tools/quic/chlo_extractor.h"
-#include "net/quic/crypto/crypto_framer.h"
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/quic_framer.h"
+#include "base/strings/string_util.h"
+#include "net/quic/core/crypto/crypto_framer.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_framer.h"
using base::StringPiece;
@@ -92,7 +93,7 @@ bool ChloFramerVisitor::OnPacketHeader(const QuicPacketHeader& header) {
bool ChloFramerVisitor::OnStreamFrame(const QuicStreamFrame& frame) {
StringPiece data(frame.data_buffer, frame.data_length);
if (frame.stream_id == kCryptoStreamId && frame.offset == 0 &&
- data.starts_with("CHLO")) {
+ base::StartsWith(data, "CHLO", base::CompareCase::INSENSITIVE_ASCII)) {
CryptoFramer crypto_framer;
crypto_framer.set_visitor(this);
if (!crypto_framer.ProcessInput(data)) {
@@ -148,7 +149,9 @@ void ChloFramerVisitor::OnError(CryptoFramer* framer) {}
void ChloFramerVisitor::OnHandshakeMessage(
const CryptoHandshakeMessage& message) {
- delegate_->OnChlo(framer_->version(), connection_id_, message);
+ if (delegate_ != nullptr) {
+ delegate_->OnChlo(framer_->version(), connection_id_, message);
+ }
found_chlo_ = true;
}
diff --git a/chromium/net/tools/quic/chlo_extractor.h b/chromium/net/tools/quic/chlo_extractor.h
index eefaae3f51d..7820bb596ca 100644
--- a/chromium/net/tools/quic/chlo_extractor.h
+++ b/chromium/net/tools/quic/chlo_extractor.h
@@ -5,8 +5,8 @@
#ifndef NET_TOOLS_QUIC_CHLO_EXTRACTOR_H_
#define NET_TOOLS_QUIC_CHLO_EXTRACTOR_H_
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/crypto/crypto_handshake_message.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
@@ -31,7 +31,7 @@ class ChloExtractor {
const QuicVersionVector& versions,
Delegate* delegate);
- ChloExtractor(ChloExtractor&) = delete;
+ ChloExtractor(const ChloExtractor&) = delete;
ChloExtractor operator=(const ChloExtractor&) = delete;
};
diff --git a/chromium/net/tools/quic/chlo_extractor_test.cc b/chromium/net/tools/quic/chlo_extractor_test.cc
index 320df5ae390..1be18208c91 100644
--- a/chromium/net/tools/quic/chlo_extractor_test.cc
+++ b/chromium/net/tools/quic/chlo_extractor_test.cc
@@ -4,7 +4,7 @@
#include "net/tools/quic/chlo_extractor.h"
-#include "net/quic/quic_framer.h"
+#include "net/quic/core/quic_framer.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
@@ -48,7 +48,7 @@ class ChloExtractorTest : public ::testing::Test {
header_.public_header.connection_id_length = PACKET_8BYTE_CONNECTION_ID;
header_.public_header.version_flag = true;
header_.public_header.versions =
- SupportedVersions(QuicSupportedVersions().front());
+ SupportedVersions(AllSupportedVersions().front());
header_.public_header.reset_flag = false;
header_.public_header.packet_number_length = PACKET_6BYTE_PACKET_NUMBER;
header_.packet_number = 1;
@@ -88,7 +88,7 @@ TEST_F(ChloExtractorTest, FindsValidChlo) {
string client_hello_str(
client_hello.GetSerialized().AsStringPiece().as_string());
// Construct a CHLO with each supported version
- for (QuicVersion version : QuicSupportedVersions()) {
+ for (QuicVersion version : AllSupportedVersions()) {
QuicVersionVector versions(SupportedVersions(version));
header_.public_header.versions = versions;
MakePacket(
@@ -111,7 +111,7 @@ TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongStream) {
MakePacket(
new QuicStreamFrame(kCryptoStreamId + 1, false, 0, client_hello_str));
EXPECT_FALSE(
- ChloExtractor::Extract(*packet_, QuicSupportedVersions(), &delegate_));
+ ChloExtractor::Extract(*packet_, AllSupportedVersions(), &delegate_));
}
TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongOffset) {
@@ -122,13 +122,13 @@ TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongOffset) {
client_hello.GetSerialized().AsStringPiece().as_string());
MakePacket(new QuicStreamFrame(kCryptoStreamId, false, 1, client_hello_str));
EXPECT_FALSE(
- ChloExtractor::Extract(*packet_, QuicSupportedVersions(), &delegate_));
+ ChloExtractor::Extract(*packet_, AllSupportedVersions(), &delegate_));
}
TEST_F(ChloExtractorTest, DoesNotFindInvalidChlo) {
MakePacket(new QuicStreamFrame(kCryptoStreamId, false, 0, "foo"));
EXPECT_FALSE(
- ChloExtractor::Extract(*packet_, QuicSupportedVersions(), &delegate_));
+ ChloExtractor::Extract(*packet_, AllSupportedVersions(), &delegate_));
}
} // namespace
diff --git a/chromium/net/tools/quic/crypto_message_printer_bin.cc b/chromium/net/tools/quic/crypto_message_printer_bin.cc
index e6813c4a3c6..11eb8f83410 100644
--- a/chromium/net/tools/quic/crypto_message_printer_bin.cc
+++ b/chromium/net/tools/quic/crypto_message_printer_bin.cc
@@ -10,8 +10,8 @@
#include <iostream>
#include "base/command_line.h"
-#include "net/quic/crypto/crypto_framer.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/crypto_framer.h"
+#include "net/quic/core/quic_utils.h"
using std::cerr;
using std::cout;
diff --git a/chromium/net/tools/quic/end_to_end_test.cc b/chromium/net/tools/quic/end_to_end_test.cc
index 7f4451c94cc..aca08397a96 100644
--- a/chromium/net/tools/quic/end_to_end_test.cc
+++ b/chromium/net/tools/quic/end_to_end_test.cc
@@ -18,22 +18,24 @@
#include "base/time/time.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
-#include "net/quic/crypto/null_encrypter.h"
-#include "net/quic/quic_client_session_base.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_packet_creator.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_id.h"
-#include "net/quic/quic_session.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/aes_128_gcm_12_encrypter.h"
+#include "net/quic/core/crypto/null_encrypter.h"
+#include "net/quic/core/quic_client_session_base.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_packet_creator.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/quic_session.h"
+#include "net/quic/core/quic_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/quic_config_peer.h"
#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/quic/test_tools/quic_flow_controller_peer.h"
#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
#include "net/quic/test_tools/quic_session_peer.h"
#include "net/quic/test_tools/quic_spdy_session_peer.h"
+#include "net/quic/test_tools/quic_stream_sequencer_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/reliable_quic_stream_peer.h"
#include "net/test/gtest_util.h"
@@ -47,6 +49,7 @@
#include "net/tools/quic/quic_spdy_client_stream.h"
#include "net/tools/quic/test_tools/http_message.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"
#include "net/tools/quic/test_tools/quic_dispatcher_peer.h"
#include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h"
@@ -71,7 +74,6 @@ using net::test::QuicSentPacketManagerPeer;
using net::test::QuicSessionPeer;
using net::test::QuicSpdySessionPeer;
using net::test::ReliableQuicStreamPeer;
-using net::test::ValueRestore;
using net::test::kClientDataStreamId1;
using net::test::kInitialSessionFlowControlWindowForTest;
using net::test::kInitialStreamFlowControlWindowForTest;
@@ -98,8 +100,11 @@ struct TestParams {
bool client_supports_stateless_rejects,
bool server_uses_stateless_rejects_if_peer_supported,
QuicTag congestion_control_tag,
- bool auto_tune_flow_control_window,
- bool disable_hpack_dynamic_table)
+ bool disable_hpack_dynamic_table,
+ bool force_hol_blocking,
+ bool use_cheap_stateless_reject,
+ bool buffer_packet_till_chlo,
+ bool small_client_mtu)
: client_supported_versions(client_supported_versions),
server_supported_versions(server_supported_versions),
negotiated_version(negotiated_version),
@@ -107,8 +112,11 @@ struct TestParams {
server_uses_stateless_rejects_if_peer_supported(
server_uses_stateless_rejects_if_peer_supported),
congestion_control_tag(congestion_control_tag),
- auto_tune_flow_control_window(auto_tune_flow_control_window),
- disable_hpack_dynamic_table(disable_hpack_dynamic_table) {}
+ disable_hpack_dynamic_table(disable_hpack_dynamic_table),
+ force_hol_blocking(force_hol_blocking),
+ use_cheap_stateless_reject(use_cheap_stateless_reject),
+ buffer_packet_till_chlo(buffer_packet_till_chlo),
+ small_client_mtu(small_client_mtu) {}
friend ostream& operator<<(ostream& os, const TestParams& p) {
os << "{ server_supported_versions: "
@@ -122,9 +130,11 @@ struct TestParams {
<< p.server_uses_stateless_rejects_if_peer_supported;
os << " congestion_control_tag: "
<< QuicUtils::TagToString(p.congestion_control_tag);
- os << " auto_tune_flow_control_window: " << p.auto_tune_flow_control_window;
- os << " disable_hpack_dynamic_table: " << p.disable_hpack_dynamic_table
- << " }";
+ os << " disable_hpack_dynamic_table: " << p.disable_hpack_dynamic_table;
+ os << " force_hol_blocking: " << p.force_hol_blocking;
+ os << " use_cheap_stateless_reject: " << p.use_cheap_stateless_reject;
+ os << " buffer_packet_till_chlo: " << p.buffer_packet_till_chlo;
+ os << " small_client_mtu: " << p.small_client_mtu << " }";
return os;
}
@@ -134,8 +144,11 @@ struct TestParams {
bool client_supports_stateless_rejects;
bool server_uses_stateless_rejects_if_peer_supported;
QuicTag congestion_control_tag;
- bool auto_tune_flow_control_window;
bool disable_hpack_dynamic_table;
+ bool force_hol_blocking;
+ bool use_cheap_stateless_reject;
+ bool buffer_packet_till_chlo;
+ bool small_client_mtu;
};
// Constructs various test permutations.
@@ -148,116 +161,157 @@ 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. :)
- QuicVersionVector all_supported_versions = QuicSupportedVersions();
+ QuicVersionVector all_supported_versions = AllSupportedVersions();
QuicVersionVector version_buckets[4];
for (const QuicVersion version : all_supported_versions) {
- if (version <= QUIC_VERSION_25) {
- // SPDY/4
+ if (version <= QUIC_VERSION_30) {
+ // Versions: 30
+ // v26 adds a hash of the expected leaf cert in the XLCT tag.
version_buckets[0].push_back(version);
} else if (version <= QUIC_VERSION_32) {
- // QUIC_VERSION_26 changes the kdf in a way that is incompatible with
- // version negotiation across the version 26 boundary.
+ // Versions: 31-32
+ // v31 adds a hash of the CHLO into the proof signature.
version_buckets[1].push_back(version);
} else if (version <= QUIC_VERSION_33) {
- // QUIC_VERSION_33 changes the kdf in a way that is incompatible with
- // version negotiation across the version 33 boundary, by using the
- // diversification nonce.
+ // Versions: 33
+ // v33 adds a diversification nonce into the hkdf.
version_buckets[2].push_back(version);
} else {
+ // Versions: 34+
// QUIC_VERSION_34 deprecates entropy and uses new ack and stop waiting
- // wire formats, so it is incompatible with version negotiation across the
- // version 34 boundary.
+ // wire formats.
version_buckets[3].push_back(version);
}
}
// This must be kept in sync with the number of nested for-loops below as it
// is used to prune the number of tests that are run.
- const int kMaxEnabledOptions = 5;
+ const int kMaxEnabledOptions = 7;
int max_enabled_options = 0;
vector<TestParams> params;
for (bool server_uses_stateless_rejects_if_peer_supported : {true, false}) {
for (bool client_supports_stateless_rejects : {true, false}) {
for (const QuicTag congestion_control_tag : {kRENO, kQBIC}) {
- for (bool auto_tune_flow_control_window : {true, false}) {
- for (bool disable_hpack_dynamic_table : {true, false}) {
- int enabled_options = 0;
- if (congestion_control_tag != kQBIC) {
- ++enabled_options;
- }
- if (auto_tune_flow_control_window) {
- ++enabled_options;
- }
- if (disable_hpack_dynamic_table) {
- ++enabled_options;
- }
- if (client_supports_stateless_rejects) {
- ++enabled_options;
- }
- if (server_uses_stateless_rejects_if_peer_supported) {
- ++enabled_options;
- }
- CHECK_GE(kMaxEnabledOptions, enabled_options);
- if (enabled_options > max_enabled_options) {
- max_enabled_options = enabled_options;
- }
-
- // Run tests with no options, a single option, or all the options
- // enabled to avoid a combinatorial explosion.
- if (enabled_options > 1 && enabled_options < kMaxEnabledOptions) {
- continue;
- }
-
- for (const QuicVersionVector& client_versions : version_buckets) {
- if (client_versions.front() < QUIC_VERSION_30 &&
- FLAGS_quic_disable_pre_30) {
- continue;
- }
- CHECK(!client_versions.empty());
- // Add an entry for server and client supporting all versions.
- params.push_back(TestParams(
- client_versions, all_supported_versions,
- client_versions.front(), client_supports_stateless_rejects,
- server_uses_stateless_rejects_if_peer_supported,
- congestion_control_tag, auto_tune_flow_control_window,
- disable_hpack_dynamic_table));
-
- // Run version negotiation tests tests with no options, or all
- // the options enabled to avoid a combinatorial explosion.
- if (enabled_options > 0 && enabled_options < kMaxEnabledOptions) {
- continue;
- }
-
- // Test client supporting all versions and server supporting 1
- // version. Simulate an old server and exercise version downgrade
- // in the client. Protocol negotiation should 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) {
- if (client_versions[i] < QUIC_VERSION_30 &&
- FLAGS_quic_disable_pre_30) {
- continue;
- }
- QuicVersionVector server_supported_versions;
- server_supported_versions.push_back(client_versions[i]);
- params.push_back(TestParams(
- client_versions, server_supported_versions,
- server_supported_versions.front(),
- client_supports_stateless_rejects,
- server_uses_stateless_rejects_if_peer_supported,
- congestion_control_tag, auto_tune_flow_control_window,
- disable_hpack_dynamic_table));
- }
- }
- }
- }
- }
- }
+ for (bool disable_hpack_dynamic_table : {false}) {
+ for (bool force_hol_blocking : {true, false}) {
+ for (bool use_cheap_stateless_reject : {true, false}) {
+ for (bool buffer_packet_till_chlo : {true, false}) {
+ for (bool small_client_mtu : {true, false}) {
+ if (!buffer_packet_till_chlo && use_cheap_stateless_reject) {
+ // Doing stateless reject while not buffering packet
+ // before CHLO is not allowed.
+ break;
+ }
+ int enabled_options = 0;
+ if (force_hol_blocking) {
+ ++enabled_options;
+ }
+ if (congestion_control_tag != kQBIC) {
+ ++enabled_options;
+ }
+ if (disable_hpack_dynamic_table) {
+ ++enabled_options;
+ }
+ if (client_supports_stateless_rejects) {
+ ++enabled_options;
+ }
+ if (server_uses_stateless_rejects_if_peer_supported) {
+ ++enabled_options;
+ }
+ if (buffer_packet_till_chlo) {
+ ++enabled_options;
+ }
+ if (use_cheap_stateless_reject) {
+ ++enabled_options;
+ }
+ if (small_client_mtu) {
+ ++enabled_options;
+ }
+ CHECK_GE(kMaxEnabledOptions, enabled_options);
+ if (enabled_options > max_enabled_options) {
+ max_enabled_options = enabled_options;
+ }
+
+ // Run tests with no options, a single option, or all the
+ // options enabled to avoid a combinatorial explosion.
+ if (enabled_options > 1 &&
+ enabled_options < kMaxEnabledOptions) {
+ continue;
+ }
+
+ for (const QuicVersionVector& client_versions :
+ version_buckets) {
+ CHECK(!client_versions.empty());
+ if (FilterSupportedVersions(client_versions).empty()) {
+ continue;
+ }
+ // Add an entry for server and client supporting all
+ // versions.
+ params.push_back(TestParams(
+ client_versions, all_supported_versions,
+ client_versions.front(),
+ client_supports_stateless_rejects,
+ server_uses_stateless_rejects_if_peer_supported,
+ congestion_control_tag, disable_hpack_dynamic_table,
+ force_hol_blocking, use_cheap_stateless_reject,
+ buffer_packet_till_chlo, small_client_mtu));
+
+ // Run version negotiation tests tests with no options, or
+ // all the options enabled to avoid a combinatorial
+ // explosion.
+ if (enabled_options > 1 &&
+ enabled_options < kMaxEnabledOptions) {
+ continue;
+ }
+
+ // Test client supporting all versions and server supporting
+ // 1 version. Simulate an old server and exercise version
+ // downgrade in the client. Protocol negotiation should
+ // 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) {
+ QuicVersionVector server_supported_versions;
+ server_supported_versions.push_back(client_versions[i]);
+ if (FilterSupportedVersions(server_supported_versions)
+ .empty()) {
+ continue;
+ }
+ params.push_back(TestParams(
+ client_versions, server_supported_versions,
+ server_supported_versions.front(),
+ client_supports_stateless_rejects,
+ server_uses_stateless_rejects_if_peer_supported,
+ congestion_control_tag, disable_hpack_dynamic_table,
+ force_hol_blocking, use_cheap_stateless_reject,
+ buffer_packet_till_chlo, small_client_mtu));
+ } // End of version for loop.
+ } // End of 2nd version for loop.
+ } // End of small_client_mtu loop.
+ } // End of buffer_packet_till_chlo loop.
+ } // End of use_cheap_stateless_reject for loop.
+ } // End of force_hol_blocking loop.
+ } // End of disable_hpack_dynamic_table for loop.
+ } // End of congestion_control_tag for loop.
+ } // End of client_supports_stateless_rejects for loop.
CHECK_EQ(kMaxEnabledOptions, max_enabled_options);
- }
+ } // End of server_uses_stateless_rejects_if_peer_supported for loop.
return params;
}
+class SmallMtuPacketReader : public QuicPacketReader {
+ public:
+ bool ReadAndDispatchPackets(int fd,
+ int port,
+ bool potentially_small_mtu,
+ const QuicClock& clock,
+ ProcessPacketInterface* processor,
+ QuicPacketCount* packets_dropped) override {
+ return QuicPacketReader::ReadAndDispatchPackets(fd, port, true, clock,
+ processor, packets_dropped);
+ }
+};
+
class ServerDelegate : public PacketDroppingTestWriter::Delegate {
public:
explicit ServerDelegate(QuicDispatcher* dispatcher)
@@ -287,7 +341,9 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
EndToEndTest()
: initialized_(false),
server_address_(IPEndPoint(Loopback4(), 0)),
- server_hostname_("example.com"),
+ server_hostname_("test.example.com"),
+ client_writer_(nullptr),
+ server_writer_(nullptr),
server_started_(false),
strike_register_no_startup_period_(false),
chlo_multiplier_(0),
@@ -328,10 +384,14 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
QuicInMemoryCachePeer::ResetForTests();
}
+ virtual void CreateClientWithWriter() {
+ client_.reset(CreateQuicClient(client_writer_));
+ }
+
QuicTestClient* CreateQuicClient(QuicPacketWriterWrapper* writer) {
- QuicTestClient* client =
- new QuicTestClient(server_address_, server_hostname_, client_config_,
- client_supported_versions_);
+ QuicTestClient* client = new QuicTestClient(
+ server_address_, server_hostname_, client_config_,
+ client_supported_versions_, CryptoTestUtils::ProofVerifierForTesting());
client->UseWriter(writer);
client->Connect();
return client;
@@ -395,29 +455,29 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
if (GetParam().client_supports_stateless_rejects) {
copt.push_back(kSREJ);
}
- if (GetParam().auto_tune_flow_control_window) {
- copt.push_back(kAFCW);
- copt.push_back(kIFW5);
- }
if (GetParam().disable_hpack_dynamic_table) {
copt.push_back(kDHDT);
}
+ if (GetParam().force_hol_blocking) {
+ client_config_.SetForceHolBlocking();
+ }
client_config_.SetConnectionOptionsToSend(copt);
// Start the server first, because CreateQuicClient() attempts
// to connect to the server.
StartServer();
- client_.reset(CreateQuicClient(client_writer_));
+ CreateClientWithWriter();
static EpollEvent event(EPOLLOUT, false);
- client_writer_->Initialize(
- reinterpret_cast<QuicEpollConnectionHelper*>(
- QuicConnectionPeer::GetHelper(
- client_->client()->session()->connection())),
- QuicConnectionPeer::GetAlarmFactory(
- client_->client()->session()->connection()),
- new ClientDelegate(client_->client()));
-
+ if (client_writer_ != nullptr) {
+ client_writer_->Initialize(
+ reinterpret_cast<QuicEpollConnectionHelper*>(
+ QuicConnectionPeer::GetHelper(
+ client_->client()->session()->connection())),
+ QuicConnectionPeer::GetAlarmFactory(
+ client_->client()->session()->connection()),
+ new ClientDelegate(client_->client()));
+ }
initialized_ = true;
return client_->client()->connected();
}
@@ -436,10 +496,22 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
}
void StartServer() {
- server_thread_.reset(new ServerThread(
+ FLAGS_quic_buffer_packet_till_chlo = GetParam().buffer_packet_till_chlo;
+ FLAGS_quic_use_cheap_stateless_rejects =
+ GetParam().use_cheap_stateless_reject;
+ if (!FLAGS_quic_buffer_packet_till_chlo) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = false;
+ }
+ auto test_server =
new QuicTestServer(CryptoTestUtils::ProofSourceForTesting(),
- server_config_, server_supported_versions_),
- server_address_, strike_register_no_startup_period_));
+ server_config_, server_supported_versions_);
+ if (GetParam().small_client_mtu) {
+ FLAGS_quic_enforce_mtu_limit = true;
+ QuicServerPeer::SetReader(test_server, new SmallMtuPacketReader);
+ server_writer_->set_max_allowed_packet_size(kMinimumSupportedPacketSize);
+ }
+ server_thread_.reset(new ServerThread(test_server, server_address_,
+ strike_register_no_startup_period_));
if (chlo_multiplier_ != 0) {
server_thread_->server()->SetChloMultiplier(chlo_multiplier_);
}
@@ -475,7 +547,7 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
}
void AddToCache(StringPiece path, int response_code, StringPiece body) {
- QuicInMemoryCache::GetInstance()->AddSimpleResponse("www.google.com", path,
+ QuicInMemoryCache::GetInstance()->AddSimpleResponse(server_hostname_, path,
response_code, body);
}
@@ -509,7 +581,7 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
void VerifyCleanConnection(bool had_packet_loss) {
QuicConnectionStats client_stats =
client_->client()->session()->connection()->GetStats();
- if (FLAGS_quic_reply_to_rej && !had_packet_loss) {
+ if (!had_packet_loss) {
EXPECT_EQ(0u, client_stats.packets_lost);
}
EXPECT_EQ(0u, client_stats.packets_discarded);
@@ -534,7 +606,7 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
ASSERT_EQ(1u, dispatcher->session_map().size());
QuicSession* session = dispatcher->session_map().begin()->second;
QuicConnectionStats server_stats = session->connection()->GetStats();
- if (FLAGS_quic_reply_to_rej && !had_packet_loss) {
+ if (!had_packet_loss) {
EXPECT_EQ(0u, server_stats.packets_lost);
}
EXPECT_EQ(0u, server_stats.packets_discarded);
@@ -562,6 +634,7 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
stream_factory_ = factory;
}
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
bool initialized_;
IPEndPoint server_address_;
string server_hostname_;
@@ -579,6 +652,7 @@ class EndToEndTest : public ::testing::TestWithParam<TestParams> {
size_t chlo_multiplier_;
QuicTestServer::StreamFactory* stream_factory_;
bool support_server_push_;
+ bool force_hol_blocking_;
};
// Run all end to end tests with all supported versions.
@@ -586,6 +660,27 @@ INSTANTIATE_TEST_CASE_P(EndToEndTests,
EndToEndTest,
::testing::ValuesIn(GetTestParams()));
+TEST_P(EndToEndTest, HandshakeSuccessful) {
+ ASSERT_TRUE(Initialize());
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+ QuicCryptoStream* crypto_stream =
+ QuicSessionPeer::GetCryptoStream(client_->client()->session());
+ QuicStreamSequencer* sequencer =
+ ReliableQuicStreamPeer::sequencer(crypto_stream);
+ EXPECT_NE(FLAGS_quic_release_crypto_stream_buffer &&
+ FLAGS_quic_reduce_sequencer_buffer_memory_life_time,
+ QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
+ server_thread_->Pause();
+ QuicDispatcher* dispatcher =
+ QuicServerPeer::GetDispatcher(server_thread_->server());
+ QuicSession* server_session = dispatcher->session_map().begin()->second;
+ crypto_stream = QuicSessionPeer::GetCryptoStream(server_session);
+ sequencer = ReliableQuicStreamPeer::sequencer(crypto_stream);
+ EXPECT_NE(FLAGS_quic_release_crypto_stream_buffer &&
+ FLAGS_quic_reduce_sequencer_buffer_memory_life_time,
+ QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer));
+}
+
TEST_P(EndToEndTest, SimpleRequestResponse) {
ASSERT_TRUE(Initialize());
@@ -1161,7 +1256,7 @@ TEST_P(EndToEndTest, DISABLED_MultipleTermination) {
ReliableQuicStreamPeer::SetWriteSideClosed(false,
client_->GetOrCreateStream());
- EXPECT_DFATAL(client_->SendData("eep", true), "Fin already buffered");
+ EXPECT_QUIC_BUG(client_->SendData("eep", true), "Fin already buffered");
}
TEST_P(EndToEndTest, Timeout) {
@@ -1203,15 +1298,9 @@ TEST_P(EndToEndTest, NegotiateMaxOpenStreams) {
}
client_->WaitForResponse();
- if (negotiated_version_ <= QUIC_VERSION_27) {
- EXPECT_FALSE(client_->connected());
- EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
- EXPECT_EQ(QUIC_TOO_MANY_OPEN_STREAMS, client_->connection_error());
- } else {
- EXPECT_TRUE(client_->connected());
- EXPECT_EQ(QUIC_REFUSED_STREAM, client_->stream_error());
- EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error());
- }
+ EXPECT_TRUE(client_->connected());
+ EXPECT_EQ(QUIC_REFUSED_STREAM, client_->stream_error());
+ EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error());
}
TEST_P(EndToEndTest, MaxIncomingDynamicStreamsLimitRespected) {
@@ -1279,7 +1368,7 @@ TEST_P(EndToEndTest, SetIndependentMaxIncomingDynamicStreamsLimits) {
}
TEST_P(EndToEndTest, NegotiateCongestionControl) {
- ValueRestore<bool> old_flag(&FLAGS_quic_allow_bbr, true);
+ FLAGS_quic_allow_bbr = true;
// Disable this flag because if connection uses multipath sent packet manager,
// static_cast here does not work.
FLAGS_quic_enable_multipath = false;
@@ -1292,7 +1381,9 @@ TEST_P(EndToEndTest, NegotiateCongestionControl) {
expected_congestion_control_type = kReno;
break;
case kTBBR:
- expected_congestion_control_type = kBBR;
+ // TODO(vasilvv): switch this back to kBBR when new BBR implementation is
+ // in.
+ expected_congestion_control_type = kCubic;
break;
case kQBIC:
expected_congestion_control_type = kCubic;
@@ -1301,11 +1392,13 @@ TEST_P(EndToEndTest, NegotiateCongestionControl) {
DLOG(FATAL) << "Unexpected congestion control tag";
}
+ server_thread_->Pause();
EXPECT_EQ(expected_congestion_control_type,
QuicSentPacketManagerPeer::GetSendAlgorithm(
*static_cast<const QuicSentPacketManager*>(
GetSentPacketManagerFromFirstServerSession()))
->GetCongestionControlType());
+ server_thread_->Resume();
}
TEST_P(EndToEndTest, LimitMaxOpenStreams) {
@@ -1619,10 +1712,8 @@ TEST_P(EndToEndTest, DifferentFlowControlWindows) {
set_client_initial_stream_flow_control_receive_window(kClientStreamIFCW);
set_client_initial_session_flow_control_receive_window(kClientSessionIFCW);
- uint32_t kServerStreamIFCW =
- GetParam().auto_tune_flow_control_window ? 32 * 1024 : 654321;
- uint32_t kServerSessionIFCW =
- GetParam().auto_tune_flow_control_window ? 48 * 1024 : 765432;
+ uint32_t kServerStreamIFCW = 32 * 1024;
+ uint32_t kServerSessionIFCW = 48 * 1024;
set_server_initial_stream_flow_control_receive_window(kServerStreamIFCW);
set_server_initial_session_flow_control_receive_window(kServerSessionIFCW);
@@ -1670,10 +1761,8 @@ TEST_P(EndToEndTest, DifferentFlowControlWindows) {
TEST_P(EndToEndTest, HeadersAndCryptoStreamsNoConnectionFlowControl) {
// The special headers and crypto streams should be subject to per-stream flow
// control limits, but should not be subject to connection level flow control
- const uint32_t kStreamIFCW =
- GetParam().auto_tune_flow_control_window ? 32 * 1024 : 123456;
- const uint32_t kSessionIFCW =
- GetParam().auto_tune_flow_control_window ? 48 * 1024 : 234567;
+ const uint32_t kStreamIFCW = 32 * 1024;
+ const uint32_t kSessionIFCW = 48 * 1024;
set_client_initial_stream_flow_control_receive_window(kStreamIFCW);
set_client_initial_session_flow_control_receive_window(kSessionIFCW);
set_server_initial_stream_flow_control_receive_window(kStreamIFCW);
@@ -1801,10 +1890,9 @@ class TestAckListener : public QuicAckListenerInterface {
class TestResponseListener : public QuicClient::ResponseListener {
public:
void OnCompleteResponse(QuicStreamId id,
- const BalsaHeaders& response_headers,
+ const SpdyHeaderBlock& response_headers,
const string& response_body) override {
- string debug_string;
- response_headers.DumpHeadersToString(&debug_string);
+ string debug_string = response_headers.DebugString();
DVLOG(1) << "response for stream " << id << " " << debug_string << "\n"
<< response_body;
}
@@ -1894,6 +1982,8 @@ TEST_P(EndToEndTest, ServerSendPublicReset) {
TEST_P(EndToEndTest, ServerSendPublicResetWithDifferentConnectionId) {
ASSERT_TRUE(Initialize());
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
// Send the public reset.
QuicConnectionId incorrect_connection_id =
client_->client()->session()->connection()->connection_id() + 1;
@@ -1957,6 +2047,8 @@ TEST_P(EndToEndTest, ClientSendPublicResetWithDifferentConnectionId) {
TEST_P(EndToEndTest, ServerSendVersionNegotiationWithDifferentConnectionId) {
ASSERT_TRUE(Initialize());
+ client_->client()->WaitForCryptoHandshakeConfirmed();
+
// Send the version negotiation packet.
QuicConnectionId incorrect_connection_id =
client_->client()->session()->connection()->connection_id() + 1;
@@ -2098,7 +2190,8 @@ class ServerStreamWithErrorResponseBody : public QuicSimpleServerStream {
ServerStreamWithErrorResponseBody(QuicStreamId id,
QuicSpdySession* session,
string response_body)
- : QuicSimpleServerStream(id, session), response_body_(response_body) {}
+ : QuicSimpleServerStream(id, session),
+ response_body_(std::move(response_body)) {}
~ServerStreamWithErrorResponseBody() override {}
@@ -2120,7 +2213,7 @@ class ServerStreamWithErrorResponseBody : public QuicSimpleServerStream {
class StreamWithErrorFactory : public QuicTestServer::StreamFactory {
public:
explicit StreamWithErrorFactory(string response_body)
- : response_body_(response_body) {}
+ : response_body_(std::move(response_body)) {}
~StreamWithErrorFactory() override {}
@@ -2390,7 +2483,6 @@ TEST_P(EndToEndTest, LargePostEarlyResponse) {
// POST to a URL that gets an early error response, after the headers are
// received and before the body is received.
HTTPMessage request(HttpConstants::HTTP_1_1, HttpConstants::POST, "/garbage");
- const uint32_t kBodySize = 2 * kWindowSize;
// Invalid content-length so the request will receive an early 500 response.
request.AddHeader("content-length", "-1");
request.set_skip_message_validation(true);
@@ -2404,28 +2496,11 @@ TEST_P(EndToEndTest, LargePostEarlyResponse) {
client_->WaitForInitialResponse();
EXPECT_EQ(500u, client_->response_headers()->parsed_response_code());
- if (negotiated_version_ > QUIC_VERSION_28) {
- // Receive the reset stream from server on early response.
- client_->WaitForResponseForMs(100);
- ReliableQuicStream* stream =
- client_->client()->session()->GetOrCreateStream(kClientDataStreamId1);
- // The stream is reset by server's reset stream.
- EXPECT_EQ(stream, nullptr);
- return;
- }
-
- // Send a body larger than the stream flow control window.
- string body;
- GenerateBody(&body, kBodySize);
- client_->SendData(body, true);
-
- // Run the client to let any buffered data be sent.
- // (This is OK despite already waiting for a response.)
- client_->WaitForResponse();
- // There should be no buffered data to write in the client's stream.
+ // Receive the reset stream from server on early response.
ReliableQuicStream* stream =
client_->client()->session()->GetOrCreateStream(kClientDataStreamId1);
- EXPECT_FALSE(stream != nullptr && stream->HasBufferedData());
+ // The stream is reset by server's reset stream.
+ EXPECT_EQ(stream, nullptr);
}
TEST_P(EndToEndTest, Trailers) {
@@ -2449,7 +2524,7 @@ TEST_P(EndToEndTest, Trailers) {
trailers["some-trailing-header"] = "trailing-header-value";
QuicInMemoryCache::GetInstance()->AddResponse(
- "www.google.com", "/trailer_url", std::move(headers), kBody,
+ server_hostname_, "/trailer_url", std::move(headers), kBody,
trailers.Clone());
EXPECT_EQ(kBody, client_->SendSynchronousRequest("/trailer_url"));
@@ -2462,7 +2537,6 @@ class EndToEndTestServerPush : public EndToEndTest {
const size_t kNumMaxStreams = 10;
EndToEndTestServerPush() : EndToEndTest() {
- FLAGS_quic_supports_push_promise = true;
client_config_.SetMaxStreamsPerConnection(kNumMaxStreams, kNumMaxStreams);
client_config_.SetMaxIncomingDynamicStreamsToSend(kNumMaxStreams);
server_config_.SetMaxStreamsPerConnection(kNumMaxStreams, kNumMaxStreams);
@@ -2531,7 +2605,9 @@ TEST_P(EndToEndTestServerPush, ServerPush) {
AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
push_urls, kNumResources, 0);
- client_->client()->set_response_listener(new TestResponseListener);
+ client_->client()->set_response_listener(
+ std::unique_ptr<QuicClientBase::ResponseListener>(
+ new TestResponseListener));
DVLOG(1) << "send request for /push_example";
EXPECT_EQ(kBody, client_->SendSynchronousRequest(
@@ -2567,7 +2643,9 @@ TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) {
};
AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
push_urls, kNumResources, 0);
- client_->client()->set_response_listener(new TestResponseListener);
+ client_->client()->set_response_listener(
+ std::unique_ptr<QuicClientBase::ResponseListener>(
+ new TestResponseListener));
// Send the first request: this will trigger the server to send all the push
// resources associated with this request, and these will be cached by the
@@ -2575,7 +2653,7 @@ TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) {
EXPECT_EQ(kBody, client_->SendSynchronousRequest(
"https://example.com/push_example"));
- for (string url : push_urls) {
+ for (const string& url : push_urls) {
// Sending subsequent requesets will not actually send anything on the wire,
// as the responses are already in the client's cache.
DVLOG(1) << "send request for pushed stream on url " << url;
@@ -2613,7 +2691,9 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) {
}
AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
push_urls, kNumResources, 0);
- client_->client()->set_response_listener(new TestResponseListener);
+ client_->client()->set_response_listener(
+ std::unique_ptr<QuicClientBase::ResponseListener>(
+ new TestResponseListener));
// Send the first request: this will trigger the server to send all the push
// resources associated with this request, and these will be cached by the
@@ -2669,7 +2749,9 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) {
AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
push_urls, kNumResources, kBodySize);
- client_->client()->set_response_listener(new TestResponseListener);
+ client_->client()->set_response_listener(
+ std::unique_ptr<QuicClientBase::ResponseListener>(
+ new TestResponseListener));
client_->SendRequest("https://example.com/push_example");
@@ -2715,7 +2797,10 @@ TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) {
EXPECT_EQ(12u, client_->num_responses());
}
+// TODO(ckrasic) - remove this when deprecating
+// FLAGS_quic_enable_server_push_by_default.
TEST_P(EndToEndTestServerPush, DisabledWithoutConnectionOption) {
+ FLAGS_quic_enable_server_push_by_default = false;
// Tests that server push won't be triggered when kSPSH is not set by client.
support_server_push_ = false;
ASSERT_TRUE(Initialize());
@@ -2730,7 +2815,9 @@ TEST_P(EndToEndTestServerPush, DisabledWithoutConnectionOption) {
};
AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody,
push_urls, kNumResources, 0);
- client_->client()->set_response_listener(new TestResponseListener);
+ client_->client()->set_response_listener(
+ std::unique_ptr<QuicClientBase::ResponseListener>(
+ new TestResponseListener));
EXPECT_EQ(kBody, client_->SendSynchronousRequest(
"https://example.com/push_example"));
@@ -2821,6 +2908,61 @@ TEST_P(EndToEndTest, DISABLED_TestHugeResponseWithPacketLoss) {
}
}
+class EndToEndBufferedPacketsTest : public EndToEndTest {
+ public:
+ EndToEndBufferedPacketsTest() : EndToEndTest() {
+ FLAGS_quic_buffer_packet_till_chlo = true;
+ }
+
+ void CreateClientWithWriter() override {
+ LOG(ERROR) << "create client with reorder_writer_ ";
+ reorder_writer_ = new PacketReorderingWriter();
+ client_.reset(EndToEndTest::CreateQuicClient(reorder_writer_));
+ }
+
+ void SetUp() override {
+ // Don't initialize client writer in base class.
+ server_writer_ = new PacketDroppingTestWriter();
+ }
+
+ protected:
+ PacketReorderingWriter* reorder_writer_;
+};
+
+INSTANTIATE_TEST_CASE_P(EndToEndBufferedPacketsTests,
+ EndToEndBufferedPacketsTest,
+ testing::ValuesIn(GetTestParams()));
+
+TEST_P(EndToEndBufferedPacketsTest, Buffer0RttRequest) {
+ ASSERT_TRUE(Initialize());
+ if (negotiated_version_ <= QUIC_VERSION_32) {
+ // Since no 0-rtt for v32 and under, and this test relies on 0-rtt, skip
+ // this test if QUIC doesn't do 0-rtt.
+ return;
+ }
+ // Finish one request to make sure handshake established.
+ client_->SendSynchronousRequest("/foo");
+ // Disconnect for next 0-rtt request.
+ client_->Disconnect();
+
+ // Client get valid STK now. Do a 0-rtt request.
+ // Buffer a CHLO till another packets sent out.
+ reorder_writer_->SetDelay(1);
+ // Only send out a CHLO.
+ client_->client()->Initialize();
+ client_->client()->StartConnect();
+ ASSERT_TRUE(client_->client()->connected());
+ // Send a request before handshake finishes.
+ HTTPMessage request(HttpConstants::HTTP_1_1, HttpConstants::GET, "/bar");
+ client_->SendMessage(request);
+ client_->WaitForResponse();
+ EXPECT_EQ(kBarResponseBody, client_->response_body());
+ QuicConnectionStats client_stats =
+ client_->client()->session()->connection()->GetStats();
+ EXPECT_EQ(0u, client_stats.packets_lost);
+ EXPECT_EQ(1, client_->client()->GetNumSentClientHellos());
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/chromium/net/tools/quic/quic_client.cc b/chromium/net/tools/quic/quic_client.cc
index 224859e0537..ebb701d8f67 100644
--- a/chromium/net/tools/quic/quic_client.cc
+++ b/chromium/net/tools/quic/quic_client.cc
@@ -13,14 +13,16 @@
#include "base/logging.h"
#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
#include "net/base/sockaddr_storage.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_data_reader.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_id.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_data_reader.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/tools/quic/quic_epoll_alarm_factory.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_socket_utils.h"
@@ -34,6 +36,7 @@
#define MMSG_MORE 0
using base::StringPiece;
+using base::StringToInt;
using std::string;
using std::vector;
@@ -41,46 +44,37 @@ namespace net {
const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
-void QuicClient::ClientQuicDataToResend::Resend() {
- client_->SendRequest(*headers_, body_, fin_);
- delete headers_;
- headers_ = nullptr;
-}
-
QuicClient::QuicClient(IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
EpollServer* epoll_server,
- ProofVerifier* proof_verifier)
+ std::unique_ptr<ProofVerifier> proof_verifier)
: QuicClient(server_address,
server_id,
supported_versions,
QuicConfig(),
epoll_server,
- proof_verifier) {}
+ std::move(proof_verifier)) {}
QuicClient::QuicClient(IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
const QuicConfig& config,
EpollServer* epoll_server,
- ProofVerifier* proof_verifier)
+ std::unique_ptr<ProofVerifier> proof_verifier)
: QuicClientBase(
server_id,
supported_versions,
config,
new QuicEpollConnectionHelper(epoll_server, QuicAllocator::SIMPLE),
new QuicEpollAlarmFactory(epoll_server),
- proof_verifier),
- server_address_(server_address),
- local_port_(0),
+ std::move(proof_verifier)),
epoll_server_(epoll_server),
- initialized_(false),
packets_dropped_(0),
overflow_supported_(false),
- store_response_(false),
- latest_response_code_(-1),
- packet_reader_(new QuicPacketReader()) {}
+ packet_reader_(new QuicPacketReader()) {
+ set_server_address(server_address);
+}
QuicClient::~QuicClient() {
if (connected()) {
@@ -89,70 +83,27 @@ QuicClient::~QuicClient() {
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
- STLDeleteElements(&data_to_resend_on_connect_);
- STLDeleteElements(&data_sent_before_handshake_);
-
CleanUpAllUDPSockets();
}
-bool QuicClient::Initialize() {
- QuicClientBase::Initialize();
-
- set_num_sent_client_hellos(0);
- set_num_stateless_rejects_received(0);
- set_connection_error(QUIC_NO_ERROR);
-
- // If an initial flow control window has not explicitly been set, then use the
- // same values that Chrome uses.
- const uint32_t kSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB
- const uint32_t kStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
- if (config()->GetInitialStreamFlowControlWindowToSend() ==
- kMinimumFlowControlSendWindow) {
- config()->SetInitialStreamFlowControlWindowToSend(kStreamMaxRecvWindowSize);
- }
- if (config()->GetInitialSessionFlowControlWindowToSend() ==
- kMinimumFlowControlSendWindow) {
- config()->SetInitialSessionFlowControlWindowToSend(
- kSessionMaxRecvWindowSize);
- }
-
+bool QuicClient::CreateUDPSocketAndBind(IPEndPoint server_address,
+ IPAddress bind_to_address,
+ int bind_to_port) {
epoll_server_->set_timeout_in_us(50 * 1000);
- if (!CreateUDPSocketAndBind()) {
- return false;
- }
-
- epoll_server_->RegisterFD(GetLatestFD(), this, kEpollFlags);
- initialized_ = true;
- return true;
-}
-
-QuicClient::QuicDataToResend::QuicDataToResend(BalsaHeaders* headers,
- StringPiece body,
- bool fin)
- : headers_(headers), body_(body), fin_(fin) {}
-
-QuicClient::QuicDataToResend::~QuicDataToResend() {
- if (headers_) {
- delete headers_;
- }
-}
-
-bool QuicClient::CreateUDPSocketAndBind() {
int fd =
- QuicSocketUtils::CreateUDPSocket(server_address_, &overflow_supported_);
+ QuicSocketUtils::CreateUDPSocket(server_address, &overflow_supported_);
if (fd < 0) {
return false;
}
IPEndPoint client_address;
- if (bind_to_address_.size() != 0) {
- client_address = IPEndPoint(bind_to_address_, local_port_);
- } else if (server_address_.GetSockAddrFamily() == AF_INET) {
- client_address = IPEndPoint(IPAddress::IPv4AllZeros(), local_port_);
+ if (bind_to_address.size() != 0) {
+ client_address = IPEndPoint(bind_to_address, bind_to_port);
+ } else if (server_address.GetSockAddrFamily() == AF_INET) {
+ client_address = IPEndPoint(IPAddress::IPv4AllZeros(), bind_to_port);
} else {
- IPAddress any6 = IPAddress::IPv6AllZeros();
- client_address = IPEndPoint(any6, local_port_);
+ client_address = IPEndPoint(IPAddress::IPv6AllZeros(), bind_to_port);
}
sockaddr_storage raw_addr;
@@ -174,92 +125,10 @@ bool QuicClient::CreateUDPSocketAndBind() {
fd_address_map_[fd] = client_address;
+ epoll_server_->RegisterFD(fd, this, kEpollFlags);
return true;
}
-bool QuicClient::Connect() {
- // Attempt multiple connects until the maximum number of client hellos have
- // been sent.
- while (!connected() &&
- GetNumSentClientHellos() <= QuicCryptoClientStream::kMaxClientHellos) {
- StartConnect();
- while (EncryptionBeingEstablished()) {
- WaitForEvents();
- }
- if (FLAGS_enable_quic_stateless_reject_support && connected() &&
- !data_to_resend_on_connect_.empty()) {
- // A connection has been established and there was previously queued data
- // to resend. Resend it and empty the queue.
- for (QuicDataToResend* data : data_to_resend_on_connect_) {
- data->Resend();
- }
- STLDeleteElements(&data_to_resend_on_connect_);
- }
- if (session() != nullptr &&
- session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- // We've successfully created a session but we're not connected, and there
- // is no stateless reject to recover from. Give up trying.
- break;
- }
- }
- if (!connected() &&
- GetNumSentClientHellos() > QuicCryptoClientStream::kMaxClientHellos &&
- session() != nullptr &&
- session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- // The overall connection failed due too many stateless rejects.
- set_connection_error(QUIC_CRYPTO_TOO_MANY_REJECTS);
- }
- return session()->connection()->connected();
-}
-
-void QuicClient::StartConnect() {
- DCHECK(initialized_);
- DCHECK(!connected());
-
- QuicPacketWriter* writer = CreateQuicPacketWriter();
-
- if (connected_or_attempting_connect()) {
- // Before we destroy the last session and create a new one, gather its stats
- // and update the stats for the overall connection.
- UpdateStats();
- if (session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- // If the last error was due to a stateless reject, queue up the data to
- // be resent on the next successful connection.
- // TODO(jokulik): I'm a little bit concerned about ordering here. Maybe
- // we should just maintain one queue?
- DCHECK(data_to_resend_on_connect_.empty());
- data_to_resend_on_connect_.swap(data_sent_before_handshake_);
- }
- }
-
- CreateQuicClientSession(new QuicConnection(
- GetNextConnectionId(), server_address_, helper(), alarm_factory(), writer,
- /* owns_writer= */ false, Perspective::IS_CLIENT, supported_versions()));
-
- // Reset |writer()| after |session()| so that the old writer outlives the old
- // session.
- set_writer(writer);
- session()->Initialize();
- session()->CryptoConnect();
- set_connected_or_attempting_connect(true);
-}
-
-void QuicClient::Disconnect() {
- DCHECK(initialized_);
-
- if (connected()) {
- session()->connection()->CloseConnection(
- QUIC_PEER_GOING_AWAY, "Client disconnecting",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- }
- STLDeleteElements(&data_to_resend_on_connect_);
- STLDeleteElements(&data_sent_before_handshake_);
-
- CleanUpAllUDPSockets();
-
- initialized_ = false;
-}
-
void QuicClient::CleanUpUDPSocket(int fd) {
CleanUpUDPSocketImpl(fd);
fd_address_map_.erase(fd);
@@ -280,121 +149,9 @@ void QuicClient::CleanUpUDPSocketImpl(int fd) {
}
}
-void QuicClient::SendRequest(const BalsaHeaders& headers,
- StringPiece body,
- bool fin) {
- QuicClientPushPromiseIndex::TryHandle* handle;
- QuicAsyncStatus rv = push_promise_index()->Try(
- SpdyBalsaUtils::RequestHeadersToSpdyHeaders(headers), this, &handle);
- if (rv == QUIC_SUCCESS)
- return;
-
- if (rv == QUIC_PENDING) {
- // May need to retry request if asynchronous rendezvous fails.
- auto* new_headers = new BalsaHeaders;
- new_headers->CopyFrom(headers);
- push_promise_data_to_resend_.reset(
- new ClientQuicDataToResend(new_headers, body, fin, this));
- return;
- }
-
- QuicSpdyClientStream* stream = CreateReliableClientStream();
- if (stream == nullptr) {
- QUIC_BUG << "stream creation failed!";
- return;
- }
- stream->SendRequest(SpdyBalsaUtils::RequestHeadersToSpdyHeaders(headers),
- body, fin);
- if (FLAGS_enable_quic_stateless_reject_support) {
- // Record this in case we need to resend.
- auto* new_headers = new BalsaHeaders;
- new_headers->CopyFrom(headers);
- auto* data_to_resend =
- new ClientQuicDataToResend(new_headers, body, fin, this);
- MaybeAddQuicDataToResend(data_to_resend);
- }
-}
-
-void QuicClient::MaybeAddQuicDataToResend(QuicDataToResend* data_to_resend) {
- DCHECK(FLAGS_enable_quic_stateless_reject_support);
- if (session()->IsCryptoHandshakeConfirmed()) {
- // The handshake is confirmed. No need to continue saving requests to
- // resend.
- STLDeleteElements(&data_sent_before_handshake_);
- delete data_to_resend;
- return;
- }
-
- // The handshake is not confirmed. Push the data onto the queue of data to
- // resend if statelessly rejected.
- data_sent_before_handshake_.push_back(data_to_resend);
-}
-
-void QuicClient::SendRequestAndWaitForResponse(const BalsaHeaders& headers,
- StringPiece body,
- bool fin) {
- SendRequest(headers, body, fin);
- while (WaitForEvents()) {
- }
-}
-
-void QuicClient::SendRequestsAndWaitForResponse(
- const vector<string>& url_list) {
- for (size_t i = 0; i < url_list.size(); ++i) {
- BalsaHeaders headers;
- headers.SetRequestFirstlineFromStringPieces("GET", url_list[i], "HTTP/1.1");
- SendRequest(headers, "", true);
- }
- while (WaitForEvents()) {
- }
-}
-
-QuicSpdyClientStream* QuicClient::CreateReliableClientStream() {
- QuicSpdyClientStream* stream = QuicClientBase::CreateReliableClientStream();
- if (stream) {
- stream->set_visitor(this);
- }
- return stream;
-}
-
-bool QuicClient::WaitForEvents() {
- DCHECK(connected());
-
- epoll_server_->WaitForEventsAndExecuteCallbacks();
+void QuicClient::RunEventLoop() {
base::RunLoop().RunUntilIdle();
-
- DCHECK(session() != nullptr);
- if (!connected() &&
- session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- DCHECK(FLAGS_enable_quic_stateless_reject_support);
- DVLOG(1) << "Detected stateless reject while waiting for events. "
- << "Attempting to reconnect.";
- Connect();
- }
-
- return session()->num_active_requests() != 0;
-}
-
-bool QuicClient::MigrateSocket(const IPAddress& new_host) {
- if (!connected()) {
- return false;
- }
-
- CleanUpUDPSocket(GetLatestFD());
-
- bind_to_address_ = new_host;
- if (!CreateUDPSocketAndBind()) {
- return false;
- }
-
- epoll_server_->RegisterFD(GetLatestFD(), this, kEpollFlags);
- session()->connection()->SetSelfAddress(GetLatestClientAddress());
-
- QuicPacketWriter* writer = CreateQuicPacketWriter();
- set_writer(writer);
- session()->connection()->SetQuicPacketWriter(writer, false);
-
- return true;
+ epoll_server_->WaitForEventsAndExecuteCallbacks();
}
void QuicClient::OnEvent(int fd, EpollEvent* event) {
@@ -405,7 +162,7 @@ void QuicClient::OnEvent(int fd, EpollEvent* event) {
while (connected() && more_to_read) {
more_to_read = packet_reader_->ReadAndDispatchPackets(
GetLatestFD(), QuicClient::GetLatestClientAddress().port(),
- *helper()->GetClock(), this,
+ false /* potentially_small_mtu */, *helper()->GetClock(), this,
overflow_supported_ ? &packets_dropped_ : nullptr);
}
}
@@ -418,71 +175,11 @@ void QuicClient::OnEvent(int fd, EpollEvent* event) {
}
}
-void QuicClient::OnClose(QuicSpdyStream* stream) {
- DCHECK(stream != nullptr);
- QuicSpdyClientStream* client_stream =
- static_cast<QuicSpdyClientStream*>(stream);
- BalsaHeaders response_headers;
- SpdyBalsaUtils::SpdyHeadersToResponseHeaders(
- client_stream->response_headers(), &response_headers);
-
- if (response_listener_.get() != nullptr) {
- response_listener_->OnCompleteResponse(stream->id(), response_headers,
- client_stream->data());
- }
-
- // Store response headers and body.
- if (store_response_) {
- latest_response_code_ = response_headers.parsed_response_code();
- response_headers.DumpHeadersToString(&latest_response_headers_);
- latest_response_body_ = client_stream->data();
- latest_response_trailers_ =
- client_stream->received_trailers().DebugString();
- }
-}
-
-bool QuicClient::CheckVary(const SpdyHeaderBlock& client_request,
- const SpdyHeaderBlock& promise_request,
- const SpdyHeaderBlock& promise_response) {
- return true;
-}
-
-void QuicClient::OnRendezvousResult(QuicSpdyStream* stream) {
- std::unique_ptr<ClientQuicDataToResend> data_to_resend =
- std::move(push_promise_data_to_resend_);
- if (stream) {
- stream->set_visitor(this);
- stream->OnDataAvailable();
- } else if (data_to_resend.get()) {
- data_to_resend->Resend();
- }
-}
-
-size_t QuicClient::latest_response_code() const {
- QUIC_BUG_IF(!store_response_) << "Response not stored!";
- return latest_response_code_;
-}
-
-const string& QuicClient::latest_response_headers() const {
- QUIC_BUG_IF(!store_response_) << "Response not stored!";
- return latest_response_headers_;
-}
-
-const string& QuicClient::latest_response_body() const {
- QUIC_BUG_IF(!store_response_) << "Response not stored!";
- return latest_response_body_;
-}
-
-const string& QuicClient::latest_response_trailers() const {
- QUIC_BUG_IF(!store_response_) << "Response not stored!";
- return latest_response_trailers_;
-}
-
QuicPacketWriter* QuicClient::CreateQuicPacketWriter() {
return new QuicDefaultPacketWriter(GetLatestFD());
}
-const IPEndPoint QuicClient::GetLatestClientAddress() const {
+IPEndPoint QuicClient::GetLatestClientAddress() const {
if (fd_address_map_.empty()) {
return IPEndPoint();
}
@@ -501,7 +198,7 @@ int QuicClient::GetLatestFD() const {
void QuicClient::ProcessPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
const QuicReceivedPacket& packet) {
- session()->connection()->ProcessUdpPacket(self_address, peer_address, packet);
+ session()->ProcessUdpPacket(self_address, peer_address, packet);
}
} // namespace net
diff --git a/chromium/net/tools/quic/quic_client.h b/chromium/net/tools/quic/quic_client.h
index 99e529c4a2b..567dc6c837c 100644
--- a/chromium/net/tools/quic/quic_client.h
+++ b/chromium/net/tools/quic/quic_client.h
@@ -17,10 +17,9 @@
#include "base/strings/string_piece.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_client_push_promise_index.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_spdy_stream.h"
-#include "net/tools/balsa/balsa_headers.h"
+#include "net/quic/core/quic_client_push_promise_index.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_spdy_stream.h"
#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_client_base.h"
#include "net/tools/quic/quic_client_session.h"
@@ -39,97 +38,24 @@ class QuicClientPeer;
class QuicClient : public QuicClientBase,
public EpollCallbackInterface,
- public QuicSpdyStream::Visitor,
- public ProcessPacketInterface,
- public QuicClientPushPromiseIndex::Delegate {
+ public ProcessPacketInterface {
public:
- class ResponseListener {
- public:
- ResponseListener() {}
- virtual ~ResponseListener() {}
- virtual void OnCompleteResponse(QuicStreamId id,
- const BalsaHeaders& response_headers,
- const std::string& response_body) = 0;
- };
-
- // The client uses these objects to keep track of any data to resend upon
- // receipt of a stateless reject. Recall that the client API allows callers
- // to optimistically send data to the server prior to handshake-confirmation.
- // If the client subsequently receives a stateless reject, it must tear down
- // its existing session, create a new session, and resend all previously sent
- // data. It uses these objects to keep track of all the sent data, and to
- // resend the data upon a subsequent connection.
- class QuicDataToResend {
- public:
- // Takes ownership of |headers|. |headers| may be null, since it's possible
- // to send data without headers.
- QuicDataToResend(BalsaHeaders* headers, base::StringPiece body, bool fin);
-
- virtual ~QuicDataToResend();
-
- // Must be overridden by specific classes with the actual method for
- // re-sending data.
- virtual void Resend() = 0;
-
- protected:
- BalsaHeaders* headers_;
- base::StringPiece body_;
- bool fin_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(QuicDataToResend);
- };
-
// Create a quic client, which will have events managed by an externally owned
// EpollServer.
QuicClient(IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
EpollServer* epoll_server,
- ProofVerifier* proof_verifier);
+ std::unique_ptr<ProofVerifier> proof_verifier);
QuicClient(IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
const QuicConfig& config,
EpollServer* epoll_server,
- ProofVerifier* proof_verifier);
+ std::unique_ptr<ProofVerifier> proof_verifier);
~QuicClient() override;
- // From QuicClientBase
- bool Initialize() override;
- bool WaitForEvents() override;
- QuicSpdyClientStream* CreateReliableClientStream() override;
-
- // "Connect" to the QUIC server, including performing synchronous crypto
- // handshake.
- bool Connect();
-
- // Start the crypto handshake. This can be done in place of the synchronous
- // Connect(), but callers are responsible for making sure the crypto handshake
- // completes.
- void StartConnect();
-
- // Disconnects from the QUIC server.
- void Disconnect();
-
- // Sends an HTTP request and does not wait for response before returning.
- void SendRequest(const BalsaHeaders& headers,
- base::StringPiece body,
- bool fin);
-
- // Sends an HTTP request and waits for response before returning.
- void SendRequestAndWaitForResponse(const BalsaHeaders& headers,
- base::StringPiece body,
- bool fin);
-
- // Sends a request simple GET for each URL in |url_list|, and then waits for
- // each to complete.
- void SendRequestsAndWaitForResponse(const std::vector<std::string>& url_list);
-
- // Migrate to a new socket during an active connection.
- bool MigrateSocket(const IPAddress& new_host);
-
// From EpollCallbackInterface
void OnRegistration(EpollServer* eps, int fd, int event_mask) override {}
void OnModification(int fd, int event_mask) override {}
@@ -140,65 +66,32 @@ class QuicClient : public QuicClientBase,
void OnUnregistration(int fd, bool replaced) override {}
void OnShutdown(EpollServer* eps, int fd) override {}
- // QuicSpdyStream::Visitor
- void OnClose(QuicSpdyStream* stream) override;
-
- bool CheckVary(const SpdyHeaderBlock& client_request,
- const SpdyHeaderBlock& promise_request,
- const SpdyHeaderBlock& promise_response) override;
- void OnRendezvousResult(QuicSpdyStream*) override;
-
- // If the crypto handshake has not yet been confirmed, adds the data to the
- // queue of data to resend if the client receives a stateless reject.
- // Otherwise, deletes the data. Takes ownerership of |data_to_resend|.
- void MaybeAddQuicDataToResend(QuicDataToResend* data_to_resend);
-
- // If the client has at least one UDP socket, return address of the latest
- // created one. Otherwise, return an empty socket address.
- const IPEndPoint GetLatestClientAddress() const;
-
// If the client has at least one UDP socket, return the latest created one.
// Otherwise, return -1.
int GetLatestFD() const;
- void set_bind_to_address(const IPAddress& address) {
- bind_to_address_ = address;
- }
-
- const IPAddress& bind_to_address() const { return bind_to_address_; }
-
- void set_local_port(int local_port) { local_port_ = local_port; }
-
- const IPEndPoint& server_address() const { return server_address_; }
-
- // Takes ownership of the listener.
- void set_response_listener(ResponseListener* listener) {
- response_listener_.reset(listener);
- }
-
- void set_store_response(bool val) { store_response_ = val; }
-
- size_t latest_response_code() const;
- const std::string& latest_response_headers() const;
- const std::string& latest_response_body() const;
- const std::string& latest_response_trailers() const;
+ // From QuicClientBase
+ IPEndPoint GetLatestClientAddress() const override;
- protected:
// Implements ProcessPacketInterface. This will be called for each received
// packet.
void ProcessPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
const QuicReceivedPacket& packet) override;
- virtual QuicPacketWriter* CreateQuicPacketWriter();
+ protected:
+ // From QuicClientBase
+ QuicPacketWriter* CreateQuicPacketWriter() override;
+ void RunEventLoop() override;
+ bool CreateUDPSocketAndBind(IPEndPoint server_address,
+ IPAddress bind_to_address,
+ int bind_to_port) override;
+ void CleanUpAllUDPSockets() override;
// If |fd| is an open UDP socket, unregister and close it. Otherwise, do
// nothing.
virtual void CleanUpUDPSocket(int fd);
- // Unregister and close all open UDP sockets.
- virtual void CleanUpAllUDPSockets();
-
EpollServer* epoll_server() { return epoll_server_; }
const linked_hash_map<int, IPEndPoint>& fd_address_map() const {
@@ -208,52 +101,9 @@ class QuicClient : public QuicClientBase,
private:
friend class net::test::QuicClientPeer;
- // Specific QuicClient class for storing data to resend.
- class ClientQuicDataToResend : public QuicDataToResend {
- public:
- // Takes ownership of |headers|.
- ClientQuicDataToResend(BalsaHeaders* headers,
- base::StringPiece body,
- bool fin,
- QuicClient* client)
- : QuicDataToResend(headers, body, fin), client_(client) {
- DCHECK(headers);
- DCHECK(client);
- }
-
- ~ClientQuicDataToResend() override {}
-
- void Resend() override;
-
- private:
- QuicClient* client_;
-
- DISALLOW_COPY_AND_ASSIGN(ClientQuicDataToResend);
- };
-
- // Used during initialization: creates the UDP socket FD, sets socket options,
- // and binds the socket to our address.
- bool CreateUDPSocketAndBind();
-
// Actually clean up |fd|.
void CleanUpUDPSocketImpl(int fd);
- // If the request URL matches a push promise, bypass sending the
- // request.
- bool MaybeHandlePromised(const BalsaHeaders& headers,
- const SpdyHeaderBlock& spdy_headers,
- base::StringPiece body,
- bool fin);
-
- // Address of the server.
- const IPEndPoint server_address_;
-
- // If initialized, the address to bind to.
- IPAddress bind_to_address_;
-
- // Local port to bind to. Initialize to 0.
- int local_port_;
-
// Listens for events on the client socket.
EpollServer* epoll_server_;
@@ -261,12 +111,6 @@ class QuicClient : public QuicClientBase,
// map, the order of socket creation can be recorded.
linked_hash_map<int, IPEndPoint> fd_address_map_;
- // Listens for full responses.
- std::unique_ptr<ResponseListener> response_listener_;
-
- // Tracks if the client is initialized to connect.
- bool initialized_;
-
// If overflow_supported_ is true, this will be the number of packets dropped
// during the lifetime of the server.
QuicPacketCount packets_dropped_;
@@ -275,33 +119,10 @@ class QuicClient : public QuicClientBase,
// because the socket would otherwise overflow.
bool overflow_supported_;
- // If true, store the latest response code, headers, and body.
- bool store_response_;
- // HTTP response code from most recent response.
- size_t latest_response_code_;
- // HTTP/2 headers from most recent response.
- std::string latest_response_headers_;
- // Body of most recent response.
- std::string latest_response_body_;
- // HTTP/2 trailers from most recent response.
- std::string latest_response_trailers_;
-
- // Keeps track of any data sent before the handshake.
- std::vector<QuicDataToResend*> data_sent_before_handshake_;
-
- // Once the client receives a stateless reject, keeps track of any data that
- // must be resent upon a subsequent successful connection.
- std::vector<QuicDataToResend*> data_to_resend_on_connect_;
-
// Point to a QuicPacketReader object on the heap. The reader allocates more
// space than allowed on the stack.
- //
- // TODO(rtenneti): Chromium code doesn't use |packet_reader_|. Add support for
- // QuicPacketReader
std::unique_ptr<QuicPacketReader> packet_reader_;
- std::unique_ptr<ClientQuicDataToResend> push_promise_data_to_resend_;
-
DISALLOW_COPY_AND_ASSIGN(QuicClient);
};
diff --git a/chromium/net/tools/quic/quic_client_base.cc b/chromium/net/tools/quic/quic_client_base.cc
index 211c54d8e98..14af28a5757 100644
--- a/chromium/net/tools/quic/quic_client_base.cc
+++ b/chromium/net/tools/quic/quic_client_base.cc
@@ -4,20 +4,42 @@
#include "net/tools/quic/quic_client_base.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_server_id.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/spdy_utils.h"
+
+using base::StringPiece;
+using base::StringToInt;
+using std::string;
+using std::vector;
namespace net {
+void QuicClientBase::ClientQuicDataToResend::Resend() {
+ client_->SendRequest(*headers_, body_, fin_);
+ headers_ = nullptr;
+}
+
+QuicClientBase::QuicDataToResend::QuicDataToResend(
+ std::unique_ptr<SpdyHeaderBlock> headers,
+ StringPiece body,
+ bool fin)
+ : headers_(std::move(headers)), body_(body), fin_(fin) {}
+
+QuicClientBase::QuicDataToResend::~QuicDataToResend() {}
+
QuicClientBase::QuicClientBase(const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
const QuicConfig& config,
QuicConnectionHelperInterface* helper,
QuicAlarmFactory* alarm_factory,
- ProofVerifier* proof_verifier)
+ std::unique_ptr<ProofVerifier> proof_verifier)
: server_id_(server_id),
+ initialized_(false),
+ local_port_(0),
config_(config),
- crypto_config_(proof_verifier),
+ crypto_config_(std::move(proof_verifier)),
helper_(helper),
alarm_factory_(alarm_factory),
supported_versions_(supported_versions),
@@ -25,18 +47,142 @@ QuicClientBase::QuicClientBase(const QuicServerId& server_id,
num_stateless_rejects_received_(0),
num_sent_client_hellos_(0),
connection_error_(QUIC_NO_ERROR),
- connected_or_attempting_connect_(false) {}
+ connected_or_attempting_connect_(false),
+ store_response_(false),
+ latest_response_code_(-1) {}
QuicClientBase::~QuicClientBase() {}
+void QuicClientBase::OnClose(QuicSpdyStream* stream) {
+ DCHECK(stream != nullptr);
+ QuicSpdyClientStream* client_stream =
+ static_cast<QuicSpdyClientStream*>(stream);
+
+ const SpdyHeaderBlock& response_headers = client_stream->response_headers();
+ if (response_listener_ != nullptr) {
+ response_listener_->OnCompleteResponse(stream->id(), response_headers,
+ client_stream->data());
+ }
+
+ // Store response headers and body.
+ if (store_response_) {
+ auto status = response_headers.find(":status");
+ if (status == response_headers.end() ||
+ !StringToInt(status->second, &latest_response_code_)) {
+ LOG(ERROR) << "Invalid response headers";
+ }
+ latest_response_headers_ = response_headers.DebugString();
+ latest_response_header_block_ = response_headers.Clone();
+ latest_response_body_ = client_stream->data();
+ latest_response_trailers_ =
+ client_stream->received_trailers().DebugString();
+ }
+}
+
bool QuicClientBase::Initialize() {
num_sent_client_hellos_ = 0;
num_stateless_rejects_received_ = 0;
connection_error_ = QUIC_NO_ERROR;
connected_or_attempting_connect_ = false;
+
+ // If an initial flow control window has not explicitly been set, then use the
+ // same values that Chrome uses.
+ const uint32_t kSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB
+ const uint32_t kStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
+ if (config()->GetInitialStreamFlowControlWindowToSend() ==
+ kMinimumFlowControlSendWindow) {
+ config()->SetInitialStreamFlowControlWindowToSend(kStreamMaxRecvWindowSize);
+ }
+ if (config()->GetInitialSessionFlowControlWindowToSend() ==
+ kMinimumFlowControlSendWindow) {
+ config()->SetInitialSessionFlowControlWindowToSend(
+ kSessionMaxRecvWindowSize);
+ }
+
+ if (!CreateUDPSocketAndBind(server_address_, bind_to_address_, local_port_)) {
+ return false;
+ }
+
+ initialized_ = true;
return true;
}
+bool QuicClientBase::Connect() {
+ // Attempt multiple connects until the maximum number of client hellos have
+ // been sent.
+ while (!connected() &&
+ GetNumSentClientHellos() <= QuicCryptoClientStream::kMaxClientHellos) {
+ StartConnect();
+ while (EncryptionBeingEstablished()) {
+ WaitForEvents();
+ }
+ if (FLAGS_enable_quic_stateless_reject_support && connected()) {
+ // Resend any previously queued data.
+ ResendSavedData();
+ }
+ if (session() != nullptr &&
+ session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
+ // We've successfully created a session but we're not connected, and there
+ // is no stateless reject to recover from. Give up trying.
+ break;
+ }
+ }
+ if (!connected() &&
+ GetNumSentClientHellos() > QuicCryptoClientStream::kMaxClientHellos &&
+ session() != nullptr &&
+ session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
+ // The overall connection failed due too many stateless rejects.
+ set_connection_error(QUIC_CRYPTO_TOO_MANY_REJECTS);
+ }
+ return session()->connection()->connected();
+}
+
+void QuicClientBase::StartConnect() {
+ DCHECK(initialized_);
+ DCHECK(!connected());
+
+ QuicPacketWriter* writer = CreateQuicPacketWriter();
+
+ if (connected_or_attempting_connect()) {
+ // If the last error was not a stateless reject, then the queued up data
+ // does not need to be resent.
+ if (session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
+ ClearDataToResend();
+ }
+ // Before we destroy the last session and create a new one, gather its stats
+ // and update the stats for the overall connection.
+ UpdateStats();
+ }
+
+ CreateQuicClientSession(new QuicConnection(
+ GetNextConnectionId(), server_address(), helper(), alarm_factory(),
+ writer,
+ /* owns_writer= */ false, Perspective::IS_CLIENT, supported_versions()));
+
+ // Reset |writer()| after |session()| so that the old writer outlives the old
+ // session.
+ set_writer(writer);
+ session()->Initialize();
+ session()->CryptoConnect();
+ set_connected_or_attempting_connect(true);
+}
+
+void QuicClientBase::Disconnect() {
+ DCHECK(initialized_);
+
+ if (connected()) {
+ session()->connection()->CloseConnection(
+ QUIC_PEER_GOING_AWAY, "Client disconnecting",
+ ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+ }
+
+ ClearDataToResend();
+
+ CleanUpAllUDPSockets();
+
+ initialized_ = false;
+}
+
ProofVerifier* QuicClientBase::proof_verifier() const {
return crypto_config_.proof_verifier();
}
@@ -56,12 +202,102 @@ bool QuicClientBase::EncryptionBeingEstablished() {
session_->connection()->connected();
}
+void QuicClientBase::SendRequest(const SpdyHeaderBlock& headers,
+ StringPiece body,
+ bool fin) {
+ QuicClientPushPromiseIndex::TryHandle* handle;
+ QuicAsyncStatus rv = push_promise_index()->Try(headers, this, &handle);
+ if (rv == QUIC_SUCCESS)
+ return;
+
+ if (rv == QUIC_PENDING) {
+ // May need to retry request if asynchronous rendezvous fails.
+ AddPromiseDataToResend(headers, body, fin);
+ return;
+ }
+
+ QuicSpdyClientStream* stream = CreateReliableClientStream();
+ if (stream == nullptr) {
+ QUIC_BUG << "stream creation failed!";
+ return;
+ }
+ stream->SendRequest(headers.Clone(), body, fin);
+ // Record this in case we need to resend.
+ MaybeAddDataToResend(headers, body, fin);
+}
+
+void QuicClientBase::SendRequestAndWaitForResponse(
+ const SpdyHeaderBlock& headers,
+ StringPiece body,
+ bool fin) {
+ SendRequest(headers, body, fin);
+ while (WaitForEvents()) {
+ }
+}
+
+void QuicClientBase::SendRequestsAndWaitForResponse(
+ const vector<string>& url_list) {
+ for (size_t i = 0; i < url_list.size(); ++i) {
+ SpdyHeaderBlock headers;
+ if (!SpdyUtils::PopulateHeaderBlockFromUrl(url_list[i], &headers)) {
+ QUIC_BUG << "Unable to create request";
+ continue;
+ }
+ SendRequest(headers, "", true);
+ }
+ while (WaitForEvents()) {
+ }
+}
+
QuicSpdyClientStream* QuicClientBase::CreateReliableClientStream() {
if (!connected()) {
return nullptr;
}
- return session_->CreateOutgoingDynamicStream(kDefaultPriority);
+ QuicSpdyClientStream* stream =
+ session_->CreateOutgoingDynamicStream(kDefaultPriority);
+ if (stream) {
+ stream->set_visitor(this);
+ }
+ return stream;
+}
+
+bool QuicClientBase::WaitForEvents() {
+ DCHECK(connected());
+
+ RunEventLoop();
+
+ DCHECK(session() != nullptr);
+ if (!connected() &&
+ session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
+ DCHECK(FLAGS_enable_quic_stateless_reject_support);
+ DVLOG(1) << "Detected stateless reject while waiting for events. "
+ << "Attempting to reconnect.";
+ Connect();
+ }
+
+ return session()->num_active_requests() != 0;
+}
+
+bool QuicClientBase::MigrateSocket(const IPAddress& new_host) {
+ if (!connected()) {
+ return false;
+ }
+
+ CleanUpAllUDPSockets();
+
+ set_bind_to_address(new_host);
+ if (!CreateUDPSocketAndBind(server_address_, bind_to_address_, local_port_)) {
+ return false;
+ }
+
+ session()->connection()->SetSelfAddress(GetLatestClientAddress());
+
+ QuicPacketWriter* writer = CreateQuicPacketWriter();
+ set_writer(writer);
+ session()->connection()->SetQuicPacketWriter(writer, false);
+
+ return true;
}
void QuicClientBase::WaitForStreamToClose(QuicStreamId id) {
@@ -122,7 +358,7 @@ QuicErrorCode QuicClientBase::connection_error() const {
if (connection_error_ != QUIC_NO_ERROR) {
return connection_error_;
}
- if (session_.get() == nullptr) {
+ if (session_ == nullptr) {
return QUIC_NO_ERROR;
}
return session_->error();
@@ -150,4 +386,97 @@ QuicConnectionId QuicClientBase::GenerateNewConnectionId() {
return QuicRandom::GetInstance()->RandUint64();
}
+void QuicClientBase::MaybeAddDataToResend(const SpdyHeaderBlock& headers,
+ StringPiece body,
+ bool fin) {
+ if (!FLAGS_enable_quic_stateless_reject_support) {
+ return;
+ }
+
+ if (session()->IsCryptoHandshakeConfirmed()) {
+ // The handshake is confirmed. No need to continue saving requests to
+ // resend.
+ data_to_resend_on_connect_.clear();
+ return;
+ }
+
+ // The handshake is not confirmed. Push the data onto the queue of data to
+ // resend if statelessly rejected.
+ std::unique_ptr<SpdyHeaderBlock> new_headers(
+ new SpdyHeaderBlock(headers.Clone()));
+ std::unique_ptr<QuicDataToResend> data_to_resend(
+ new ClientQuicDataToResend(std::move(new_headers), body, fin, this));
+ MaybeAddQuicDataToResend(std::move(data_to_resend));
+}
+
+void QuicClientBase::MaybeAddQuicDataToResend(
+ std::unique_ptr<QuicDataToResend> data_to_resend) {
+ data_to_resend_on_connect_.push_back(std::move(data_to_resend));
+}
+
+void QuicClientBase::ClearDataToResend() {
+ data_to_resend_on_connect_.clear();
+}
+
+void QuicClientBase::ResendSavedData() {
+ // Calling Resend will re-enqueue the data, so swap out
+ // data_to_resend_on_connect_ before iterating.
+ vector<std::unique_ptr<QuicDataToResend>> old_data;
+ old_data.swap(data_to_resend_on_connect_);
+ for (const auto& data : old_data) {
+ data->Resend();
+ }
+}
+
+void QuicClientBase::AddPromiseDataToResend(const SpdyHeaderBlock& headers,
+ StringPiece body,
+ bool fin) {
+ std::unique_ptr<SpdyHeaderBlock> new_headers(
+ new SpdyHeaderBlock(headers.Clone()));
+ push_promise_data_to_resend_.reset(
+ new ClientQuicDataToResend(std::move(new_headers), body, fin, this));
+}
+
+bool QuicClientBase::CheckVary(const SpdyHeaderBlock& client_request,
+ const SpdyHeaderBlock& promise_request,
+ const SpdyHeaderBlock& promise_response) {
+ return true;
+}
+
+void QuicClientBase::OnRendezvousResult(QuicSpdyStream* stream) {
+ std::unique_ptr<ClientQuicDataToResend> data_to_resend =
+ std::move(push_promise_data_to_resend_);
+ if (stream) {
+ stream->set_visitor(this);
+ stream->OnDataAvailable();
+ } else if (data_to_resend.get()) {
+ data_to_resend->Resend();
+ }
+}
+
+size_t QuicClientBase::latest_response_code() const {
+ QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ return latest_response_code_;
+}
+
+const string& QuicClientBase::latest_response_headers() const {
+ QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ return latest_response_headers_;
+}
+
+const SpdyHeaderBlock& QuicClientBase::latest_response_header_block() const {
+ QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ return latest_response_header_block_;
+}
+
+const string& QuicClientBase::latest_response_body() const {
+ QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ return latest_response_body_;
+}
+
+const string& QuicClientBase::latest_response_trailers() const {
+ QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ return latest_response_trailers_;
+}
+
} // namespace net
diff --git a/chromium/net/tools/quic/quic_client_base.h b/chromium/net/tools/quic/quic_client_base.h
index 3f9e514fb89..b32cd0a4c3c 100644
--- a/chromium/net/tools/quic/quic_client_base.h
+++ b/chromium/net/tools/quic/quic_client_base.h
@@ -13,16 +13,15 @@
#include "base/macros.h"
#include "net/base/ip_endpoint.h"
-#include "net/log/net_log.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/quic_crypto_client_config.h"
-#include "net/quic/quic_alarm_factory.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_client_push_promise_index.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/quic_crypto_client_config.h"
+#include "net/quic/core/quic_alarm_factory.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_client_push_promise_index.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_client_session.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
@@ -31,27 +30,96 @@ namespace net {
class ProofVerifier;
class QuicServerId;
-class QuicClientBase {
+class QuicClientBase : public QuicClientPushPromiseIndex::Delegate,
+ public QuicSpdyStream::Visitor {
public:
+ // A ResponseListener is notified when a complete response is received.
+ class ResponseListener {
+ public:
+ ResponseListener() {}
+ virtual ~ResponseListener() {}
+ virtual void OnCompleteResponse(QuicStreamId id,
+ const SpdyHeaderBlock& response_headers,
+ const std::string& response_body) = 0;
+ };
+
+ // The client uses these objects to keep track of any data to resend upon
+ // receipt of a stateless reject. Recall that the client API allows callers
+ // to optimistically send data to the server prior to handshake-confirmation.
+ // If the client subsequently receives a stateless reject, it must tear down
+ // its existing session, create a new session, and resend all previously sent
+ // data. It uses these objects to keep track of all the sent data, and to
+ // resend the data upon a subsequent connection.
+ class QuicDataToResend {
+ public:
+ // |headers| may be null, since it's possible to send data without headers.
+ QuicDataToResend(std::unique_ptr<SpdyHeaderBlock> headers,
+ base::StringPiece body,
+ bool fin);
+
+ virtual ~QuicDataToResend();
+
+ // Must be overridden by specific classes with the actual method for
+ // re-sending data.
+ virtual void Resend() = 0;
+
+ protected:
+ std::unique_ptr<SpdyHeaderBlock> headers_;
+ base::StringPiece body_;
+ bool fin_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicDataToResend);
+ };
+
QuicClientBase(const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
const QuicConfig& config,
QuicConnectionHelperInterface* helper,
QuicAlarmFactory* alarm_factory,
- ProofVerifier* proof_verifier);
+ std::unique_ptr<ProofVerifier> proof_verifier);
+
+ ~QuicClientBase() override;
- ~QuicClientBase();
+ // QuicSpdyStream::Visitor
+ void OnClose(QuicSpdyStream* stream) override;
// Initializes the client to create a connection. Should be called exactly
// once before calling StartConnect or Connect. Returns true if the
// initialization succeeds, false otherwise.
virtual bool Initialize();
+ // "Connect" to the QUIC server, including performing synchronous crypto
+ // handshake.
+ bool Connect();
+
+ // Start the crypto handshake. This can be done in place of the synchronous
+ // Connect(), but callers are responsible for making sure the crypto handshake
+ // completes.
+ void StartConnect();
+
+ // Disconnects from the QUIC server.
+ void Disconnect();
+
// Returns true if the crypto handshake has yet to establish encryption.
// Returns false if encryption is active (even if the server hasn't confirmed
// the handshake) or if the connection has been closed.
bool EncryptionBeingEstablished();
+ // Sends an HTTP request and does not wait for response before returning.
+ void SendRequest(const SpdyHeaderBlock& headers,
+ base::StringPiece body,
+ bool fin);
+
+ // Sends an HTTP request and waits for response before returning.
+ void SendRequestAndWaitForResponse(const SpdyHeaderBlock& headers,
+ base::StringPiece body,
+ bool fin);
+
+ // Sends a request simple GET for each URL in |url_list|, and then waits for
+ // each to complete.
+ void SendRequestsAndWaitForResponse(const std::vector<std::string>& url_list);
+
// Returns a newly created QuicSpdyClientStream, owned by the
// QuicSimpleClient.
virtual QuicSpdyClientStream* CreateReliableClientStream();
@@ -64,7 +132,10 @@ class QuicClientBase {
// Wait up to 50ms, and handle any events which occur.
// Returns true if there are any outstanding requests.
- virtual bool WaitForEvents() = 0;
+ bool WaitForEvents();
+
+ // Migrate to a new socket during an active connection.
+ bool MigrateSocket(const IPAddress& new_host);
QuicClientSession* session() { return session_.get(); }
@@ -88,6 +159,17 @@ class QuicClientBase {
crypto_config_.SetChannelIDSource(source);
}
+ // UseTokenBinding enables token binding negotiation in the client. This
+ // should only be called before the initial Connect(). The client will still
+ // need to check that token binding is negotiated with the server, and add
+ // token binding headers to requests if so. server, and add token binding
+ // headers to requests if so. The negotiated token binding parameters can be
+ // found on the QuicCryptoNegotiatedParameters object in
+ // token_binding_key_param.
+ void UseTokenBinding() {
+ crypto_config_.tb_key_params = QuicTagVector{kTB10};
+ }
+
const QuicVersionVector& supported_versions() const {
return supported_versions_;
}
@@ -164,10 +246,67 @@ class QuicClientBase {
return &push_promise_index_;
}
+ bool CheckVary(const SpdyHeaderBlock& client_request,
+ const SpdyHeaderBlock& promise_request,
+ const SpdyHeaderBlock& promise_response) override;
+ void OnRendezvousResult(QuicSpdyStream*) override;
+
+ // If the crypto handshake has not yet been confirmed, adds the data to the
+ // queue of data to resend if the client receives a stateless reject.
+ // Otherwise, deletes the data.
+ void MaybeAddQuicDataToResend(
+ std::unique_ptr<QuicDataToResend> data_to_resend);
+
+ void set_store_response(bool val) { store_response_ = val; }
+
+ size_t latest_response_code() const;
+ const std::string& latest_response_headers() const;
+ const SpdyHeaderBlock& latest_response_header_block() const;
+ const std::string& latest_response_body() const;
+ const std::string& latest_response_trailers() const;
+
+ void set_response_listener(std::unique_ptr<ResponseListener> listener) {
+ response_listener_ = std::move(listener);
+ }
+
+ void set_bind_to_address(IPAddress address) { bind_to_address_ = address; }
+
+ IPAddress bind_to_address() const { return bind_to_address_; }
+
+ void set_local_port(int local_port) { local_port_ = local_port; }
+
+ int local_port() const { return local_port_; }
+
+ const IPEndPoint& server_address() const { return server_address_; }
+
+ void set_server_address(const IPEndPoint& server_address) {
+ server_address_ = server_address;
+ }
+
protected:
+ // Creates a packet writer to be used for the next connection.
+ virtual QuicPacketWriter* CreateQuicPacketWriter() = 0;
+
+ // Takes ownership of |connection|.
virtual QuicClientSession* CreateQuicClientSession(
QuicConnection* connection);
+ // Runs one iteration of the event loop.
+ virtual void RunEventLoop() = 0;
+
+ // Used during initialization: creates the UDP socket FD, sets socket options,
+ // and binds the socket to our address.
+ virtual bool CreateUDPSocketAndBind(IPEndPoint server_address,
+ IPAddress bind_to_address,
+ int bind_to_port) = 0;
+
+ // Unregister and close all open UDP sockets.
+ virtual void CleanUpAllUDPSockets() = 0;
+
+ // If the client has at least one UDP socket, return address of the latest
+ // created one. Otherwise, return an empty socket address.
+ virtual IPEndPoint GetLatestClientAddress() const = 0;
+
// Generates the next ConnectionId for |server_id_|. By default, if the
// cached server config contains a server-designated ID, that ID will be
// returned. Otherwise, the next random ID will be returned.
@@ -181,6 +320,21 @@ class QuicClientBase {
// connection ID).
virtual QuicConnectionId GenerateNewConnectionId();
+ // If the crypto handshake has not yet been confirmed, adds the data to the
+ // queue of data to resend if the client receives a stateless reject.
+ // Otherwise, deletes the data.
+ void MaybeAddDataToResend(const SpdyHeaderBlock& headers,
+ base::StringPiece body,
+ bool fin);
+
+ void ClearDataToResend();
+
+ void ResendSavedData();
+
+ void AddPromiseDataToResend(const SpdyHeaderBlock& headers,
+ base::StringPiece body,
+ bool fin);
+
QuicConnectionHelperInterface* helper() { return helper_.get(); }
QuicAlarmFactory* alarm_factory() { return alarm_factory_.get(); }
@@ -194,24 +348,60 @@ class QuicClientBase {
}
private:
+ // Specific QuicClient class for storing data to resend.
+ class ClientQuicDataToResend : public QuicDataToResend {
+ public:
+ ClientQuicDataToResend(std::unique_ptr<SpdyHeaderBlock> headers,
+ base::StringPiece body,
+ bool fin,
+ QuicClientBase* client)
+ : QuicDataToResend(std::move(headers), body, fin), client_(client) {
+ DCHECK(headers_);
+ DCHECK(client);
+ }
+
+ ~ClientQuicDataToResend() override {}
+
+ void Resend() override;
+
+ private:
+ QuicClientBase* client_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientQuicDataToResend);
+ };
+
// |server_id_| is a tuple (hostname, port, is_https) of the server.
QuicServerId server_id_;
+ // Tracks if the client is initialized to connect.
+ bool initialized_;
+
+ // Address of the server.
+ IPEndPoint server_address_;
+
+ // If initialized, the address to bind to.
+ IPAddress bind_to_address_;
+
+ // Local port to bind to. Initialize to 0.
+ int local_port_;
+
// config_ and crypto_config_ contain configuration and cached state about
// servers.
QuicConfig config_;
QuicCryptoClientConfig crypto_config_;
- // Helper to be used by created connections. Needs to outlive |session_|.
+ // Helper to be used by created connections. Must outlive |session_|.
std::unique_ptr<QuicConnectionHelperInterface> helper_;
- // Helper to be used by created connections. Needs to outlive |session_|.
+ // Alarm factory to be used by created connections. Must outlive |session_|.
std::unique_ptr<QuicAlarmFactory> alarm_factory_;
- // Writer used to actually send packets to the wire. Needs to outlive
- // |session_|.
+ // Writer used to actually send packets to the wire. Must outlive |session_|.
std::unique_ptr<QuicPacketWriter> writer_;
+ // Index of pending promised streams. Must outlive |session_|.
+ QuicClientPushPromiseIndex push_promise_index_;
+
// Session which manages streams.
std::unique_ptr<QuicClientSession> session_;
@@ -247,7 +437,27 @@ class QuicClientBase {
// to the previous client-level connection.
bool connected_or_attempting_connect_;
- QuicClientPushPromiseIndex push_promise_index_;
+ // If true, store the latest response code, headers, and body.
+ bool store_response_;
+ // HTTP response code from most recent response.
+ int latest_response_code_;
+ // HTTP/2 headers from most recent response.
+ std::string latest_response_headers_;
+ // HTTP/2 headers from most recent response.
+ SpdyHeaderBlock latest_response_header_block_;
+ // Body of most recent response.
+ std::string latest_response_body_;
+ // HTTP/2 trailers from most recent response.
+ std::string latest_response_trailers_;
+
+ // Listens for full responses.
+ std::unique_ptr<ResponseListener> response_listener_;
+
+ // Keeps track of any data that must be resent upon a subsequent successful
+ // connection, in case the client receives a stateless reject.
+ std::vector<std::unique_ptr<QuicDataToResend>> data_to_resend_on_connect_;
+
+ std::unique_ptr<ClientQuicDataToResend> push_promise_data_to_resend_;
DISALLOW_COPY_AND_ASSIGN(QuicClientBase);
};
diff --git a/chromium/net/tools/quic/quic_client_bin.cc b/chromium/net/tools/quic/quic_client_bin.cc
index 26820af6e5d..07ff2fc5c98 100644
--- a/chromium/net/tools/quic/quic_client_bin.cc
+++ b/chromium/net/tools/quic/quic_client_bin.cc
@@ -55,12 +55,11 @@
#include "net/cert/cert_verifier.h"
#include "net/cert/multi_log_ct_verifier.h"
#include "net/http/transport_security_state.h"
-#include "net/log/net_log.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_id.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/quic_utils.h"
#include "net/spdy/spdy_header_block.h"
#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_client.h"
@@ -113,7 +112,7 @@ class FakeCertVerifier : public net::CertVerifier {
net::CertVerifyResult* verify_result,
const net::CompletionCallback& callback,
std::unique_ptr<Request>* out_req,
- const net::BoundNetLog& net_log) override {
+ const net::NetLogWithSource& net_log) override {
return net::OK;
}
@@ -239,7 +238,7 @@ int main(int argc, char* argv[]) {
net::EpollServer epoll_server;
net::QuicServerId server_id(url.host(), url.EffectiveIntPort(),
net::PRIVACY_MODE_DISABLED);
- net::QuicVersionVector versions = net::QuicSupportedVersions();
+ net::QuicVersionVector versions = net::AllSupportedVersions();
if (FLAGS_quic_version != -1) {
versions.clear();
versions.push_back(static_cast<net::QuicVersion>(FLAGS_quic_version));
@@ -254,11 +253,12 @@ int main(int argc, char* argv[]) {
transport_security_state.reset(new TransportSecurityState);
std::unique_ptr<CTVerifier> ct_verifier(new MultiLogCTVerifier());
std::unique_ptr<CTPolicyEnforcer> ct_policy_enforcer(new CTPolicyEnforcer());
- ProofVerifierChromium* proof_verifier = new ProofVerifierChromium(
- cert_verifier.get(), ct_policy_enforcer.get(),
- transport_security_state.get(), ct_verifier.get());
- net::QuicClient client(net::IPEndPoint(ip_addr, FLAGS_port), server_id,
- versions, &epoll_server, proof_verifier);
+ std::unique_ptr<net::ProofVerifierChromium> proof_verifier(
+ new ProofVerifierChromium(cert_verifier.get(), ct_policy_enforcer.get(),
+ transport_security_state.get(),
+ ct_verifier.get()));
+ net::QuicClient client(net::IPEndPoint(ip_addr, port), server_id, versions,
+ &epoll_server, std::move(proof_verifier));
client.set_initial_max_packet_length(
FLAGS_initial_mtu != 0 ? FLAGS_initial_mtu : net::kDefaultMaxPacketSize);
if (!client.Initialize()) {
@@ -312,11 +312,10 @@ int main(int argc, char* argv[]) {
// Make sure to store the response, for later output.
client.set_store_response(true);
-
// Send the request.
net::SpdyHeaderBlock header_block =
net::SpdyBalsaUtils::RequestHeadersToSpdyHeaders(headers);
- client.SendRequestAndWaitForResponse(headers, body, /*fin=*/true);
+ client.SendRequestAndWaitForResponse(header_block, body, /*fin=*/true);
// Print request and response details.
if (!FLAGS_quiet) {
@@ -324,9 +323,8 @@ int main(int argc, char* argv[]) {
cout << "headers:" << header_block.DebugString();
if (!FLAGS_body_hex.empty()) {
// Print the user provided hex, rather than binary body.
- cout << "body hex: " << FLAGS_body_hex << endl;
- cout << "body ascii: " << net::QuicUtils::BinaryToAscii(
- net::QuicUtils::HexDecode(FLAGS_body_hex))
+ cout << "body:\n"
+ << net::QuicUtils::HexDump(net::QuicUtils::HexDecode(FLAGS_body_hex))
<< endl;
} else {
cout << "body: " << body << endl;
@@ -337,10 +335,7 @@ int main(int argc, char* argv[]) {
string response_body = client.latest_response_body();
if (!FLAGS_body_hex.empty()) {
// Assume response is binary data.
- cout << "body hex: " << net::QuicUtils::HexEncode(response_body)
- << endl;
- cout << "body ascii: " << net::QuicUtils::BinaryToAscii(response_body)
- << endl;
+ cout << "body:\n" << net::QuicUtils::HexDump(response_body) << endl;
} else {
cout << "body: " << response_body << endl;
}
diff --git a/chromium/net/tools/quic/quic_client_session.cc b/chromium/net/tools/quic/quic_client_session.cc
index a0e11b1cfb4..48ed1d0950c 100644
--- a/chromium/net/tools/quic/quic_client_session.cc
+++ b/chromium/net/tools/quic/quic_client_session.cc
@@ -5,9 +5,11 @@
#include "net/tools/quic/quic_client_session.h"
#include "base/logging.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/quic_server_id.h"
+#include "net/log/net_log_with_source.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_server_id.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
using std::string;
@@ -90,7 +92,7 @@ int QuicClientSession::GetNumReceivedServerConfigUpdates() const {
bool QuicClientSession::ShouldCreateIncomingDynamicStream(QuicStreamId id) {
if (!connection()->connected()) {
- LOG(DFATAL) << "ShouldCreateIncomingDynamicStream called when disconnected";
+ QUIC_BUG << "ShouldCreateIncomingDynamicStream called when disconnected";
return false;
}
if (goaway_received() && respect_goaway_) {
@@ -121,7 +123,7 @@ QuicSpdyStream* QuicClientSession::CreateIncomingDynamicStream(
QuicCryptoClientStreamBase* QuicClientSession::CreateQuicCryptoStream() {
return new QuicCryptoClientStream(
- server_id_, this, new ProofVerifyContextChromium(0, BoundNetLog()),
+ server_id_, this, new ProofVerifyContextChromium(0, NetLogWithSource()),
crypto_config_, this);
}
diff --git a/chromium/net/tools/quic/quic_client_session.h b/chromium/net/tools/quic/quic_client_session.h
index fc5abbf12f6..af9ee0952f6 100644
--- a/chromium/net/tools/quic/quic_client_session.h
+++ b/chromium/net/tools/quic/quic_client_session.h
@@ -11,9 +11,9 @@
#include <string>
#include "base/macros.h"
-#include "net/quic/quic_client_session_base.h"
-#include "net/quic/quic_crypto_client_stream.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_client_session_base.h"
+#include "net/quic/core/quic_crypto_client_stream.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_spdy_client_stream.h"
namespace net {
@@ -24,7 +24,8 @@ class ReliableQuicStream;
class QuicClientSession : public QuicClientSessionBase {
public:
- // Caller retains ownership of |promised_by_url|.
+ // Takes ownership of |connection|. Caller retains ownership of
+ // |promised_by_url|.
QuicClientSession(const QuicConfig& config,
QuicConnection* connection,
const QuicServerId& server_id,
diff --git a/chromium/net/tools/quic/quic_client_session_test.cc b/chromium/net/tools/quic/quic_client_session_test.cc
index a38214c8b28..75d02cb8eea 100644
--- a/chromium/net/tools/quic/quic_client_session_test.cc
+++ b/chromium/net/tools/quic/quic_client_session_test.cc
@@ -8,9 +8,9 @@
#include "base/strings/stringprintf.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/spdy_utils.h"
+#include "net/quic/core/crypto/aes_128_gcm_12_encrypter.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/mock_quic_spdy_client_stream.h"
#include "net/quic/test_tools/quic_config_peer.h"
@@ -36,7 +36,6 @@ using net::test::QuicPacketCreatorPeer;
using net::test::QuicSpdySessionPeer;
using net::test::SupportedVersions;
using net::test::TestPeerIPAddress;
-using net::test::ValueRestore;
using net::test::kClientDataStreamId1;
using net::test::kServerDataStreamId1;
using net::test::kTestPort;
@@ -141,7 +140,7 @@ class QuicClientSessionTest : public ::testing::TestWithParam<QuicVersion> {
INSTANTIATE_TEST_CASE_P(Tests,
QuicClientSessionTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicClientSessionTest, CryptoConnect) {
CompleteCryptoHandshake();
diff --git a/chromium/net/tools/quic/quic_client_test.cc b/chromium/net/tools/quic/quic_client_test.cc
index dca06bddae2..dd360de33a7 100644
--- a/chromium/net/tools/quic/quic_client_test.cc
+++ b/chromium/net/tools/quic/quic_client_test.cc
@@ -43,7 +43,7 @@ QuicClient* CreateAndInitializeQuicClient(EpollServer* eps, uint16_t port) {
IPEndPoint server_address(IPEndPoint(net::test::Loopback4(), port));
QuicServerId server_id("hostname", server_address.port(),
PRIVACY_MODE_DISABLED);
- QuicVersionVector versions = QuicSupportedVersions();
+ QuicVersionVector versions = AllSupportedVersions();
QuicClient* client =
new QuicClient(server_address, server_id, versions, eps,
CryptoTestUtils::ProofVerifierForTesting());
@@ -54,7 +54,7 @@ QuicClient* CreateAndInitializeQuicClient(EpollServer* eps, uint16_t port) {
TEST(QuicClientTest, DoNotLeakFDs) {
// Create a ProofVerifier before counting the number of open FDs to work
// around some ASAN weirdness.
- delete CryptoTestUtils::ProofVerifierForTesting();
+ CryptoTestUtils::ProofVerifierForTesting().reset();
// Make sure that the QuicClient doesn't leak FDs. Doing so could cause port
// exhaustion in long running processes which repeatedly create clients.
@@ -81,7 +81,7 @@ TEST(QuicClientTest, DoNotLeakFDs) {
TEST(QuicClientTest, CreateAndCleanUpUDPSockets) {
// Create a ProofVerifier before counting the number of open FDs to work
// around some ASAN weirdness.
- delete CryptoTestUtils::ProofVerifierForTesting();
+ CryptoTestUtils::ProofVerifierForTesting().reset();
EpollServer eps;
int number_of_open_fds = NumOpenFDs();
diff --git a/chromium/net/tools/quic/quic_default_packet_writer.h b/chromium/net/tools/quic/quic_default_packet_writer.h
index 0a8f1093273..e695637b470 100644
--- a/chromium/net/tools/quic/quic_default_packet_writer.h
+++ b/chromium/net/tools/quic/quic_default_packet_writer.h
@@ -9,7 +9,8 @@
#include "base/macros.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_packet_writer.h"
+#include "net/base/net_export.h"
+#include "net/quic/core/quic_packet_writer.h"
namespace net {
@@ -17,7 +18,7 @@ struct WriteResult;
// Default packet writer which wraps QuicSocketUtils WritePacket.
-class QuicDefaultPacketWriter : public QuicPacketWriter {
+class NET_EXPORT_PRIVATE QuicDefaultPacketWriter : public QuicPacketWriter {
public:
explicit QuicDefaultPacketWriter(int fd);
~QuicDefaultPacketWriter() override;
diff --git a/chromium/net/tools/quic/quic_dispatcher.cc b/chromium/net/tools/quic/quic_dispatcher.cc
index 70f2af14411..b43b8e1664f 100644
--- a/chromium/net/tools/quic/quic_dispatcher.cc
+++ b/chromium/net/tools/quic/quic_dispatcher.cc
@@ -10,21 +10,28 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/stl_util.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
+
#include "net/tools/quic/chlo_extractor.h"
#include "net/tools/quic/quic_per_connection_packet_writer.h"
#include "net/tools/quic/quic_simple_server_session.h"
+#include "net/tools/quic/quic_simple_server_session.h"
#include "net/tools/quic/quic_time_wait_list_manager.h"
#include "net/tools/quic/stateless_rejector.h"
using base::StringPiece;
+using std::list;
using std::string;
namespace net {
+typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket;
+typedef QuicBufferedPacketStore::BufferedPacketList BufferedPacketList;
+typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult;
+
namespace {
// An alarm that informs the QuicDispatcher to delete old sessions.
@@ -150,7 +157,7 @@ class StatelessConnectionTerminator {
// to give the QuicDispatcher a chance to apply policy checks to the CHLO.
class ChloValidator : public ChloExtractor::Delegate {
public:
- ChloValidator(QuicServerSessionBase::Helper* helper,
+ ChloValidator(QuicCryptoServerStream::Helper* helper,
IPEndPoint self_address,
StatelessRejector* rejector)
: helper_(helper),
@@ -175,7 +182,7 @@ class ChloValidator : public ChloExtractor::Delegate {
const string& error_details() const { return error_details_; }
private:
- QuicServerSessionBase::Helper* helper_; // Unowned.
+ QuicCryptoServerStream::Helper* helper_; // Unowned.
IPEndPoint self_address_;
StatelessRejector* rejector_; // Unowned.
bool can_accept_;
@@ -187,9 +194,9 @@ class ChloValidator : public ChloExtractor::Delegate {
QuicDispatcher::QuicDispatcher(
const QuicConfig& config,
const QuicCryptoServerConfig* crypto_config,
- const QuicVersionVector& supported_versions,
+ QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
- std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
std::unique_ptr<QuicAlarmFactory> alarm_factory)
: config_(config),
crypto_config_(crypto_config),
@@ -200,20 +207,20 @@ QuicDispatcher::QuicDispatcher(
alarm_factory_(std::move(alarm_factory)),
delete_sessions_alarm_(
alarm_factory_->CreateAlarm(new DeleteSessionsAlarm(this))),
- supported_versions_(supported_versions),
- disable_quic_pre_30_(FLAGS_quic_disable_pre_30),
- allowed_supported_versions_(supported_versions),
+ buffered_packets_(this, helper_->GetClock(), alarm_factory_.get()),
current_packet_(nullptr),
- framer_(supported_versions,
+ version_manager_(version_manager),
+ framer_(GetSupportedVersions(),
/*unused*/ QuicTime::Zero(),
Perspective::IS_SERVER),
- last_error_(QUIC_NO_ERROR) {
+ last_error_(QUIC_NO_ERROR),
+ new_sessions_allowed_per_event_loop_(0u) {
framer_.set_visitor(this);
}
QuicDispatcher::~QuicDispatcher() {
- STLDeleteValues(&session_map_);
- STLDeleteElements(&closed_session_list_);
+ base::STLDeleteValues(&session_map_);
+ base::STLDeleteElements(&closed_session_list_);
}
void QuicDispatcher::InitializeWithWriter(QuicPacketWriter* writer) {
@@ -260,11 +267,18 @@ bool QuicDispatcher::OnUnauthenticatedPublicHeader(
QuicConnectionId connection_id = header.connection_id;
SessionMap::iterator it = session_map_.find(connection_id);
if (it != session_map_.end()) {
+ DCHECK(!buffered_packets_.HasBufferedPackets(connection_id));
it->second->ProcessUdpPacket(current_server_address_,
current_client_address_, *current_packet_);
return false;
}
+ if (FLAGS_quic_buffer_packets_after_chlo &&
+ buffered_packets_.HasChloForConnection(connection_id)) {
+ BufferEarlyPacket(connection_id);
+ return false;
+ }
+
if (!OnUnauthenticatedUnknownPublicHeader(header)) {
return false;
}
@@ -319,29 +333,35 @@ bool QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
return false;
}
- // Packet's connection ID is unknown.
- // Apply the validity checks.
+ // Packet's connection ID is unknown. Apply the validity checks.
QuicPacketFate fate = ValidityChecks(header);
if (fate == kFateProcess) {
- fate = MaybeRejectStatelessly(connection_id, header);
+ // Execute stateless rejection logic to determine the packet fate, then
+ // invoke ProcessUnauthenticatedHeaderFate.
+ MaybeRejectStatelessly(connection_id, header);
+ } else {
+ // If the fate is already known, process it without executing stateless
+ // rejection logic.
+ ProcessUnauthenticatedHeaderFate(fate, connection_id, header.packet_number);
}
+
+ return false;
+}
+
+void QuicDispatcher::ProcessUnauthenticatedHeaderFate(
+ QuicPacketFate fate,
+ QuicConnectionId connection_id,
+ QuicPacketNumber packet_number) {
switch (fate) {
case kFateProcess: {
- // Create a session and process the packet.
- QuicServerSessionBase* session =
- CreateQuicSession(connection_id, current_client_address_);
- DVLOG(1) << "Created new session for " << connection_id;
- session_map_.insert(std::make_pair(connection_id, session));
- session->ProcessUdpPacket(current_server_address_,
- current_client_address_, *current_packet_);
+ ProcessChlo();
break;
}
case kFateTimeWait:
// MaybeRejectStatelessly might have already added the connection to
// time wait, in which case it should not be added again.
if (!FLAGS_quic_use_cheap_stateless_rejects ||
- !time_wait_list_manager_->IsConnectionIdInTimeWait(
- header.public_header.connection_id)) {
+ !time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)) {
// Add this connection_id to the time-wait state, to safely reject
// future packets.
DVLOG(1) << "Adding connection ID " << connection_id
@@ -350,19 +370,20 @@ bool QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
connection_id, framer_.version(),
/*connection_rejected_statelessly=*/false, nullptr);
}
- DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(
- header.public_header.connection_id));
+ DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
time_wait_list_manager_->ProcessPacket(
- current_server_address_, current_client_address_,
- header.public_header.connection_id, header.packet_number,
- *current_packet_);
+ current_server_address_, current_client_address_, connection_id,
+ packet_number, *current_packet_);
+ break;
+ case kFateBuffer:
+ // This packet is a non-CHLO packet which has arrived out of order.
+ // Buffer it.
+ BufferEarlyPacket(connection_id);
break;
case kFateDrop:
// Do nothing with the packet.
break;
}
-
- return false;
}
QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks(
@@ -412,7 +433,7 @@ void QuicDispatcher::CleanUpSession(SessionMap::iterator it,
}
void QuicDispatcher::DeleteSessions() {
- STLDeleteElements(&closed_session_list_);
+ base::STLDeleteElements(&closed_session_list_);
}
void QuicDispatcher::OnCanWrite() {
@@ -463,8 +484,8 @@ void QuicDispatcher::OnConnectionClosed(QuicConnectionId connection_id,
<< ", with details: " << error_details;
if (closed_session_list_.empty()) {
- delete_sessions_alarm_->Cancel();
- delete_sessions_alarm_->Set(helper()->GetClock()->ApproximateNow());
+ delete_sessions_alarm_->Update(helper()->GetClock()->ApproximateNow(),
+ QuicTime::Delta::Zero());
}
closed_session_list_.push_back(it->second);
const bool should_close_statelessly =
@@ -594,20 +615,49 @@ void QuicDispatcher::OnPacketComplete() {
DCHECK(false);
}
-QuicServerSessionBase* QuicDispatcher::CreateQuicSession(
+void QuicDispatcher::OnExpiredPackets(
QuicConnectionId connection_id,
- const IPEndPoint& client_address) {
- // The QuicServerSessionBase takes ownership of |connection| below.
- QuicConnection* connection = new QuicConnection(
- connection_id, client_address, helper_.get(), alarm_factory_.get(),
- CreatePerConnectionWriter(),
- /* owns_writer= */ true, Perspective::IS_SERVER, GetSupportedVersions());
+ BufferedPacketList early_arrived_packets) {
+ time_wait_list_manager_->AddConnectionIdToTimeWait(
+ connection_id, framer_.version(), false, nullptr);
+}
+
+void QuicDispatcher::ProcessBufferedChlos(size_t max_connections_to_create) {
+ // Reset the counter before starting creating connections.
+ new_sessions_allowed_per_event_loop_ = max_connections_to_create;
+ for (; new_sessions_allowed_per_event_loop_ > 0;
+ --new_sessions_allowed_per_event_loop_) {
+ QuicConnectionId connection_id;
+ list<BufferedPacket> packets =
+ buffered_packets_.DeliverPacketsForNextConnection(&connection_id);
+ if (packets.empty()) {
+ return;
+ }
+ QuicServerSessionBase* session =
+ CreateQuicSession(connection_id, packets.front().client_address);
+ DVLOG(1) << "Created new session for " << connection_id;
+ session_map_.insert(std::make_pair(connection_id, session));
+ DeliverPacketsToSession(packets, session);
+ }
+}
- QuicServerSessionBase* session = new QuicSimpleServerSession(
- config_, connection, this, session_helper_.get(), crypto_config_,
- &compressed_certs_cache_);
- session->Initialize();
- return session;
+bool QuicDispatcher::HasChlosBuffered() const {
+ return buffered_packets_.HasChlosBuffered();
+}
+
+void QuicDispatcher::OnNewConnectionAdded(QuicConnectionId connection_id) {
+ VLOG(1) << "Received packet from new connection " << connection_id;
+}
+
+// Return true if there is any packet buffered in the store.
+bool QuicDispatcher::HasBufferedPackets(QuicConnectionId connection_id) {
+ return buffered_packets_.HasBufferedPackets(connection_id);
+}
+
+void QuicDispatcher::OnBufferPacketFailure(EnqueuePacketResult result,
+ QuicConnectionId connection_id) {
+ DVLOG(1) << "Fail to buffer packet on connection " << connection_id
+ << " because of " << result;
}
void QuicDispatcher::OnConnectionRejectedStatelessly() {}
@@ -623,6 +673,79 @@ QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() {
alarm_factory_.get());
}
+void QuicDispatcher::BufferEarlyPacket(QuicConnectionId connection_id) {
+ bool is_new_connection = !buffered_packets_.HasBufferedPackets(connection_id);
+ EnqueuePacketResult rs = buffered_packets_.EnqueuePacket(
+ connection_id, *current_packet_, current_server_address_,
+ current_client_address_, /*is_chlo=*/false);
+ if (rs != EnqueuePacketResult::SUCCESS) {
+ OnBufferPacketFailure(rs, connection_id);
+ } else if (is_new_connection) {
+ OnNewConnectionAdded(connection_id);
+ }
+}
+
+void QuicDispatcher::ProcessChlo() {
+ QUIC_BUG_IF(!FLAGS_quic_buffer_packet_till_chlo &&
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop)
+ << "Try to limit connection creation per epoll event while not "
+ "supporting packet buffer. "
+ "--quic_limit_num_new_sessions_per_epoll_loop = true "
+ "--quic_buffer_packet_till_chlo = false";
+
+ if (FLAGS_quic_limit_num_new_sessions_per_epoll_loop &&
+ FLAGS_quic_buffer_packet_till_chlo &&
+ new_sessions_allowed_per_event_loop_ <= 0) {
+ // Can't create new session any more. Wait till next event loop.
+ if (!buffered_packets_.HasChloForConnection(current_connection_id_)) {
+ // Only buffer one CHLO per connection. Remove this condition check when
+ // --gfe2_reloadable_flag_quic_buffer_packets_after_chlo
+ // is deprecated because after that retransmitted CHLO should be buffered
+ // earlier in OnUnauthenticatedPublicHeader().
+ bool is_new_connection =
+ !buffered_packets_.HasBufferedPackets(current_connection_id_);
+ EnqueuePacketResult rs = buffered_packets_.EnqueuePacket(
+ current_connection_id_, *current_packet_, current_server_address_,
+ current_client_address_, /*is_chlo=*/true);
+ if (rs != EnqueuePacketResult::SUCCESS) {
+ OnBufferPacketFailure(rs, current_connection_id_);
+ } else if (is_new_connection) {
+ OnNewConnectionAdded(current_connection_id_);
+ }
+ }
+ return;
+ }
+
+ // Creates a new session and process all buffered packets for this connection.
+ QuicServerSessionBase* session =
+ CreateQuicSession(current_connection_id_, current_client_address_);
+ if (FLAGS_quic_enforce_mtu_limit &&
+ current_packet().potentially_small_mtu()) {
+ session->connection()->set_largest_packet_size_supported(
+ kMinimumSupportedPacketSize);
+ }
+ DVLOG(1) << "Created new session for " << current_connection_id_;
+ session_map_.insert(std::make_pair(current_connection_id_, session));
+ std::list<BufferedPacket> packets =
+ buffered_packets_.DeliverPackets(current_connection_id_);
+ // Check if CHLO is the first packet arrived on this connection.
+ if (FLAGS_quic_buffer_packet_till_chlo && packets.empty()) {
+ OnNewConnectionAdded(current_connection_id_);
+ }
+ // Process CHLO at first.
+ session->ProcessUdpPacket(current_server_address_, current_client_address_,
+ *current_packet_);
+
+ // Deliver queued-up packets in the same order as they arrived.
+ // Do this even when flag is off because there might be still some packets
+ // buffered in the store before flag is turned off.
+ DeliverPacketsToSession(packets, session);
+ if (FLAGS_quic_limit_num_new_sessions_per_epoll_loop &&
+ FLAGS_quic_buffer_packet_till_chlo) {
+ --new_sessions_allowed_per_event_loop_;
+ }
+}
+
bool QuicDispatcher::HandlePacketForTimeWait(
const QuicPacketPublicHeader& header) {
if (header.reset_flag) {
@@ -653,30 +776,70 @@ bool QuicDispatcher::OnUnauthenticatedUnknownPublicHeader(
return true;
}
-QuicDispatcher::QuicPacketFate QuicDispatcher::MaybeRejectStatelessly(
- QuicConnectionId connection_id,
- const QuicPacketHeader& header) {
+class StatelessRejectorProcessDoneCallback
+ : public StatelessRejector::ProcessDoneCallback {
+ public:
+ StatelessRejectorProcessDoneCallback(QuicDispatcher* dispatcher,
+ QuicPacketNumber packet_number,
+ QuicVersion first_version)
+ : dispatcher_(dispatcher),
+ packet_number_(packet_number),
+ first_version_(first_version) {}
+
+ void Run(std::unique_ptr<StatelessRejector> rejector) override {
+ dispatcher_->OnStatelessRejectorProcessDone(std::move(rejector),
+ packet_number_, first_version_);
+ }
+
+ private:
+ QuicDispatcher* dispatcher_;
+ QuicPacketNumber packet_number_;
+ QuicVersion first_version_;
+};
+
+void QuicDispatcher::MaybeRejectStatelessly(QuicConnectionId connection_id,
+ const QuicPacketHeader& header) {
// TODO(rch): This logic should probably live completely inside the rejector.
if (!FLAGS_quic_use_cheap_stateless_rejects ||
!FLAGS_enable_quic_stateless_reject_support ||
header.public_header.versions.front() <= QUIC_VERSION_32 ||
!ShouldAttemptCheapStatelessRejection()) {
- return kFateProcess;
+ // Not use cheap stateless reject.
+ if (FLAGS_quic_buffer_packet_till_chlo &&
+ !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
+ nullptr)) {
+ // Buffer non-CHLO packets.
+ ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id,
+ header.packet_number);
+ return;
+ }
+ ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id,
+ header.packet_number);
+ return;
}
- StatelessRejector rejector(header.public_header.versions.front(),
- supported_versions_, crypto_config_,
- &compressed_certs_cache_, helper()->GetClock(),
- helper()->GetRandomGenerator(),
- current_client_address_, current_server_address_);
+ std::unique_ptr<StatelessRejector> rejector(new StatelessRejector(
+ header.public_header.versions.front(), GetSupportedVersions(),
+ crypto_config_, &compressed_certs_cache_, helper()->GetClock(),
+ helper()->GetRandomGenerator(), current_packet_->length(),
+ current_client_address_, current_server_address_));
ChloValidator validator(session_helper_.get(), current_server_address_,
- &rejector);
- if (!ChloExtractor::Extract(*current_packet_, supported_versions_,
+ rejector.get());
+ if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
&validator)) {
- // TODO(rch): Since there was no CHLO in this packet, buffer it until one
- // arrives.
- DLOG(ERROR) << "Dropping undecryptable packet.";
- return kFateDrop;
+ if (!FLAGS_quic_buffer_packet_till_chlo) {
+ QUIC_BUG
+ << "Have to drop packet because buffering non-chlo packet is "
+ "not supported while trying to do stateless reject. "
+ "--gfe2_reloadable_flag_quic_buffer_packet_till_chlo false"
+ " --gfe2_reloadable_flag_quic_use_cheap_stateless_rejects true";
+ ProcessUnauthenticatedHeaderFate(kFateDrop, connection_id,
+ header.packet_number);
+ return;
+ }
+ ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id,
+ header.packet_number);
+ return;
}
if (!validator.can_accept()) {
@@ -686,51 +849,76 @@ QuicDispatcher::QuicPacketFate QuicDispatcher::MaybeRejectStatelessly(
terminator.CloseConnection(QUIC_HANDSHAKE_FAILED,
validator.error_details());
OnConnectionClosedStatelessly(QUIC_HANDSHAKE_FAILED);
- return kFateTimeWait;
+ ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id,
+ header.packet_number);
+ return;
}
- // This packet included a CHLO. See if it can be rejected statelessly.
- switch (rejector.state()) {
+ // Continue stateless rejector processing
+ std::unique_ptr<StatelessRejectorProcessDoneCallback> cb(
+ new StatelessRejectorProcessDoneCallback(
+ this, header.packet_number, header.public_header.versions.front()));
+ StatelessRejector::Process(std::move(rejector), std::move(cb));
+}
+
+void QuicDispatcher::OnStatelessRejectorProcessDone(
+ std::unique_ptr<StatelessRejector> rejector,
+ QuicPacketNumber packet_number,
+ QuicVersion first_version) {
+ QuicPacketFate fate;
+ switch (rejector->state()) {
case StatelessRejector::FAILED: {
// There was an error processing the client hello.
- StatelessConnectionTerminator terminator(
- connection_id, &framer_, helper(), time_wait_list_manager_.get());
- terminator.CloseConnection(rejector.error(), rejector.error_details());
- return kFateTimeWait;
+ StatelessConnectionTerminator terminator(rejector->connection_id(),
+ &framer_, helper(),
+ time_wait_list_manager_.get());
+ terminator.CloseConnection(rejector->error(), rejector->error_details());
+ fate = kFateTimeWait;
+ break;
}
case StatelessRejector::UNSUPPORTED:
// Cheap stateless rejects are not supported so process the packet.
- return kFateProcess;
+ fate = kFateProcess;
+ break;
case StatelessRejector::ACCEPTED:
// Contains a valid CHLO, so process the packet and create a connection.
- return kFateProcess;
+ fate = kFateProcess;
+ break;
case StatelessRejector::REJECTED: {
- DCHECK_EQ(framer_.version(), header.public_header.versions.front());
- StatelessConnectionTerminator terminator(
- connection_id, &framer_, helper(), time_wait_list_manager_.get());
+ DCHECK_EQ(framer_.version(), first_version);
+ StatelessConnectionTerminator terminator(rejector->connection_id(),
+ &framer_, helper(),
+ time_wait_list_manager_.get());
terminator.RejectConnection(
- rejector.reply().GetSerialized().AsStringPiece());
+ rejector->reply().GetSerialized().AsStringPiece());
OnConnectionRejectedStatelessly();
- return kFateTimeWait;
+ fate = kFateTimeWait;
+ break;
}
- }
- QUIC_BUG << "Rejector has unknown invalid state.";
- return kFateDrop;
+ default:
+ QUIC_BUG << "Rejector has invalid state " << rejector->state();
+ fate = kFateDrop;
+ break;
+ }
+ ProcessUnauthenticatedHeaderFate(fate, rejector->connection_id(),
+ packet_number);
}
const QuicVersionVector& QuicDispatcher::GetSupportedVersions() {
- // Filter (or un-filter) the list of supported versions based on the flag.
- if (disable_quic_pre_30_ != FLAGS_quic_disable_pre_30) {
- DCHECK_EQ(supported_versions_.capacity(),
- allowed_supported_versions_.capacity());
- disable_quic_pre_30_ = FLAGS_quic_disable_pre_30;
- supported_versions_ = FilterSupportedVersions(allowed_supported_versions_);
- }
- return supported_versions_;
+ return version_manager_->GetSupportedVersions();
+}
+
+void QuicDispatcher::DeliverPacketsToSession(
+ const std::list<BufferedPacket>& packets,
+ QuicServerSessionBase* session) {
+ for (const BufferedPacket& packet : packets) {
+ session->ProcessUdpPacket(packet.server_address, packet.client_address,
+ *(packet.packet));
+ }
}
} // namespace net
diff --git a/chromium/net/tools/quic/quic_dispatcher.h b/chromium/net/tools/quic/quic_dispatcher.h
index db972530435..8d9197a4806 100644
--- a/chromium/net/tools/quic/quic_dispatcher.h
+++ b/chromium/net/tools/quic/quic_dispatcher.h
@@ -15,20 +15,23 @@
#include "base/macros.h"
#include "net/base/ip_endpoint.h"
#include "net/base/linked_hash_map.h"
-#include "net/quic/crypto/quic_compressed_certs_cache.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_blocked_writer_interface.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_session_base.h"
+#include "net/quic/core/crypto/quic_compressed_certs_cache.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_blocked_writer_interface.h"
+#include "net/quic/core/quic_buffered_packet_store.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_crypto_server_stream.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_session_base.h"
+
#include "net/tools/quic/quic_process_packet_interface.h"
#include "net/tools/quic/quic_time_wait_list_manager.h"
+#include "net/tools/quic/stateless_rejector.h"
namespace net {
class QuicConfig;
class QuicCryptoServerConfig;
-class QuicServerSessionBase;
namespace test {
class QuicDispatcherPeer;
@@ -37,7 +40,8 @@ class QuicDispatcherPeer;
class QuicDispatcher : public QuicServerSessionBase::Visitor,
public ProcessPacketInterface,
public QuicBlockedWriterInterface,
- public QuicFramerVisitorInterface {
+ public QuicFramerVisitorInterface,
+ public QuicBufferedPacketStore::VisitorInterface {
public:
// Ideally we'd have a linked_hash_set: the boolean is unused.
typedef linked_hash_map<QuicBlockedWriterInterface*,
@@ -47,9 +51,9 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
QuicDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig* crypto_config,
- const QuicVersionVector& supported_versions,
+ QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
- std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
std::unique_ptr<QuicAlarmFactory> alarm_factory);
~QuicDispatcher() override;
@@ -85,6 +89,9 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
// time-wait list.
void OnConnectionAddedToTimeWaitList(QuicConnectionId connection_id) override;
+ void OnPacketBeingDispatchedToSession(
+ QuicServerSessionBase* session) override {}
+
typedef std::unordered_map<QuicConnectionId, QuicServerSessionBase*>
SessionMap;
@@ -139,10 +146,21 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override;
void OnPacketComplete() override;
+ // QuicBufferedPacketStore::VisitorInterface implementation.
+ void OnExpiredPackets(QuicConnectionId connection_id,
+ QuicBufferedPacketStore::BufferedPacketList
+ early_arrived_packets) override;
+
+ // Create connections for previously buffered CHLOs as many as allowed.
+ virtual void ProcessBufferedChlos(size_t max_connections_to_create);
+
+ // Return true if there is CHLO buffered.
+ virtual bool HasChlosBuffered() const;
+
protected:
virtual QuicServerSessionBase* CreateQuicSession(
QuicConnectionId connection_id,
- const IPEndPoint& client_address);
+ const IPEndPoint& client_address) = 0;
// Called when a connection is rejected statelessly.
virtual void OnConnectionRejectedStatelessly();
@@ -163,6 +181,8 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
kFateProcess,
// Put the connection ID into time-wait state and send a public reset.
kFateTimeWait,
+ // Buffer the packet.
+ kFateBuffer,
// Drop the packet (ignore and give no response).
kFateDrop,
};
@@ -176,12 +196,22 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
// will be owned by the dispatcher as time_wait_list_manager_
virtual QuicTimeWaitListManager* CreateQuicTimeWaitListManager();
+ // Called when |current_packet_| is a data packet that has arrived before
+ // the CHLO or it is any kind of packet while a CHLO on same connection has
+ // already been in the buffer.
+ void BufferEarlyPacket(QuicConnectionId connection_id);
+
+ // Called when |current_packet_| is a CHLO packet. Creates a new connection
+ // and delivers any buffered packets for that connection id.
+ void ProcessChlo();
+
QuicTimeWaitListManager* time_wait_list_manager() {
return time_wait_list_manager_.get();
}
const QuicVersionVector& GetSupportedVersions();
+ QuicConnectionId current_connection_id() { return current_connection_id_; }
const IPEndPoint& current_server_address() { return current_server_address_; }
const IPEndPoint& current_client_address() { return current_client_address_; }
const QuicReceivedPacket& current_packet() { return *current_packet_; }
@@ -198,7 +228,7 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
QuicConnectionHelperInterface* helper() { return helper_.get(); }
- QuicServerSessionBase::Helper* session_helper() {
+ QuicCryptoServerStream::Helper* session_helper() {
return session_helper_.get();
}
@@ -225,8 +255,21 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
virtual bool OnUnauthenticatedUnknownPublicHeader(
const QuicPacketPublicHeader& header);
+ // Called when a new connection starts to be handled by this dispatcher.
+ // Either this connection is created or its packets is buffered while waiting
+ // for CHLO.
+ virtual void OnNewConnectionAdded(QuicConnectionId connection_id);
+
+ bool HasBufferedPackets(QuicConnectionId connection_id);
+
+ // Called when BufferEarlyPacket() fail to buffer the packet.
+ virtual void OnBufferPacketFailure(
+ QuicBufferedPacketStore::EnqueuePacketResult result,
+ QuicConnectionId connection_id);
+
private:
friend class net::test::QuicDispatcherPeer;
+ friend class StatelessRejectorProcessDoneCallback;
// Removes the session from the session map and write blocked list, and adds
// the ConnectionId to the time-wait list. If |session_closed_statelessly| is
@@ -236,11 +279,33 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
bool HandlePacketForTimeWait(const QuicPacketPublicHeader& header);
// Attempts to reject the connection statelessly, if stateless rejects are
- // possible and if the current packet contains a CHLO message.
- // Returns a fate which describes what subsequent processing should be
- // performed on the packets, like ValidityChecks.
- QuicPacketFate MaybeRejectStatelessly(QuicConnectionId connection_id,
- const QuicPacketHeader& header);
+ // possible and if the current packet contains a CHLO message. Determines a
+ // fate which describes what subsequent processing should be performed on the
+ // packets, like ValidityChecks, and invokes ProcessUnauthenticatedHeaderFate.
+ void MaybeRejectStatelessly(QuicConnectionId connection_id,
+ const QuicPacketHeader& header);
+
+ // Deliver |packets| to |session| for further processing.
+ void DeliverPacketsToSession(
+ const std::list<QuicBufferedPacketStore::BufferedPacket>& packets,
+ QuicServerSessionBase* session);
+
+ // Perform the appropriate actions on the current packet based on |fate| -
+ // either process, buffer, or drop it.
+ void ProcessUnauthenticatedHeaderFate(QuicPacketFate fate,
+ QuicConnectionId connection_id,
+ QuicPacketNumber packet_number);
+
+ // Invoked when StatelessRejector::Process completes.
+ void OnStatelessRejectorProcessDone(
+ std::unique_ptr<StatelessRejector> rejector,
+ QuicPacketNumber packet_number,
+ QuicVersion first_version);
+
+ void set_new_sessions_allowed_per_event_loop(
+ int16_t new_sessions_allowed_per_event_loop) {
+ new_sessions_allowed_per_event_loop_ = new_sessions_allowed_per_event_loop;
+ }
const QuicConfig& config_;
@@ -264,7 +329,7 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
std::unique_ptr<QuicConnectionHelperInterface> helper_;
// The helper used for all sessions.
- std::unique_ptr<QuicServerSessionBase::Helper> session_helper_;
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper_;
// Creates alarms.
std::unique_ptr<QuicAlarmFactory> alarm_factory_;
@@ -275,17 +340,9 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
// The writer to write to the socket with.
std::unique_ptr<QuicPacketWriter> writer_;
- // 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).
- QuicVersionVector supported_versions_;
-
- // FLAGS_quic_disable_pre_30
- bool disable_quic_pre_30_;
- // The list of versions that may be supported by this dispatcher.
- // |supported_versions| is derived from this list and |disable_quic_pre_30_|.
- const QuicVersionVector allowed_supported_versions_;
+ // Packets which are buffered until a connection can be created to handle
+ // them.
+ QuicBufferedPacketStore buffered_packets_;
// Information about the packet currently being handled.
IPEndPoint current_client_address_;
@@ -293,12 +350,19 @@ class QuicDispatcher : public QuicServerSessionBase::Visitor,
const QuicReceivedPacket* current_packet_;
QuicConnectionId current_connection_id_;
+ // Used to get the supported versions based on flag. Does not own.
+ QuicVersionManager* version_manager_;
+
QuicFramer framer_;
// The last error set by SetLastError(), which is called by
// framer_visitor_->OnError().
QuicErrorCode last_error_;
+ // A backward counter of how many new sessions can be create within current
+ // event loop. When reaches 0, it means can't create sessions for now.
+ int16_t new_sessions_allowed_per_event_loop_;
+
DISALLOW_COPY_AND_ASSIGN(QuicDispatcher);
};
diff --git a/chromium/net/tools/quic/quic_dispatcher_test.cc b/chromium/net/tools/quic/quic_dispatcher_test.cc
index a063a2daf66..23ca8797bae 100644
--- a/chromium/net/tools/quic/quic_dispatcher_test.cc
+++ b/chromium/net/tools/quic/quic_dispatcher_test.cc
@@ -9,42 +9,53 @@
#include <string>
#include "base/macros.h"
-#include "base/strings/string_piece.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_crypto_stream.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_utils.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_crypto_stream.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/quic_buffered_packet_store_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
+#include "net/test/gtest_util.h"
#include "net/tools/epoll_server/epoll_server.h"
+#include "net/tools/quic/chlo_extractor.h"
#include "net/tools/quic/quic_epoll_alarm_factory.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_packet_writer_wrapper.h"
-#include "net/tools/quic/quic_simple_server_session_helper.h"
+#include "net/tools/quic/quic_simple_crypto_server_stream_helper.h"
#include "net/tools/quic/quic_time_wait_list_manager.h"
+#include "net/tools/quic/stateless_rejector.h"
#include "net/tools/quic/test_tools/mock_quic_time_wait_list_manager.h"
#include "net/tools/quic/test_tools/quic_dispatcher_peer.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gmock_mutant.h"
#include "testing/gtest/include/gtest/gtest.h"
+using base::IntToString;
using base::StringPiece;
using net::EpollServer;
using net::test::ConstructEncryptedPacket;
using net::test::CryptoTestUtils;
using net::test::MockQuicConnection;
using net::test::MockQuicConnectionHelper;
-using net::test::ValueRestore;
+using std::ostream;
using std::string;
using std::vector;
+using testing::CreateFunctor;
using testing::DoAll;
using testing::InSequence;
using testing::Invoke;
using testing::WithoutArgs;
using testing::_;
+static const size_t kDefaultMaxConnectionsInStore = 100;
+static const size_t kMaxConnectionsWithoutCHLO =
+ kDefaultMaxConnectionsInStore / 2;
+static const int16_t kMaxNumSessionsToCreate = 16;
+
namespace net {
namespace test {
namespace {
@@ -62,7 +73,8 @@ class TestQuicSpdyServerSession : public QuicServerSessionBase {
crypto_config,
compressed_certs_cache),
crypto_stream_(QuicServerSessionBase::GetCryptoStream()) {}
- ~TestQuicSpdyServerSession() override{};
+
+ ~TestQuicSpdyServerSession() override { delete connection(); };
MOCK_METHOD3(OnConnectionClosed,
void(QuicErrorCode error,
@@ -77,7 +89,7 @@ class TestQuicSpdyServerSession : public QuicServerSessionBase {
QuicCompressedCertsCache* compressed_certs_cache) override {
return new QuicCryptoServerStream(
crypto_config, compressed_certs_cache,
- FLAGS_enable_quic_stateless_reject_support, this);
+ FLAGS_enable_quic_stateless_reject_support, this, stream_helper());
}
void SetCryptoStream(QuicCryptoServerStream* crypto_stream) {
@@ -88,6 +100,10 @@ class TestQuicSpdyServerSession : public QuicServerSessionBase {
return crypto_stream_;
}
+ QuicCryptoServerStream::Helper* stream_helper() {
+ return QuicServerSessionBase::stream_helper();
+ }
+
private:
QuicCryptoServerStreamBase* crypto_stream_;
@@ -98,15 +114,17 @@ class TestDispatcher : public QuicDispatcher {
public:
TestDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig* crypto_config,
+ QuicVersionManager* version_manager,
EpollServer* eps)
: QuicDispatcher(
config,
crypto_config,
- QuicSupportedVersions(),
+ version_manager,
std::unique_ptr<QuicEpollConnectionHelper>(
new QuicEpollConnectionHelper(eps, QuicAllocator::BUFFER_POOL)),
- std::unique_ptr<QuicServerSessionBase::Helper>(
- new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
+ std::unique_ptr<QuicCryptoServerStream::Helper>(
+ new QuicSimpleCryptoServerStreamHelper(
+ QuicRandom::GetInstance())),
std::unique_ptr<QuicEpollAlarmFactory>(
new QuicEpollAlarmFactory(eps))) {}
@@ -114,6 +132,8 @@ class TestDispatcher : public QuicDispatcher {
QuicServerSessionBase*(QuicConnectionId connection_id,
const IPEndPoint& client_address));
+ MOCK_METHOD1(OnNewConnectionAdded, void(QuicConnectionId connection_id));
+
using QuicDispatcher::current_server_address;
using QuicDispatcher::current_client_address;
};
@@ -144,43 +164,29 @@ class MockServerConnection : public MockQuicConnection {
QuicDispatcher* dispatcher_;
};
-QuicServerSessionBase* CreateSession(
- QuicDispatcher* dispatcher,
- const QuicConfig& config,
- QuicConnectionId connection_id,
- const IPEndPoint& client_address,
- MockQuicConnectionHelper* helper,
- MockAlarmFactory* alarm_factory,
- const QuicCryptoServerConfig* crypto_config,
- QuicCompressedCertsCache* compressed_certs_cache,
- TestQuicSpdyServerSession** session) {
- MockServerConnection* connection = new MockServerConnection(
- connection_id, helper, alarm_factory, dispatcher);
- *session = new TestQuicSpdyServerSession(config, connection, crypto_config,
- compressed_certs_cache);
- connection->set_visitor(*session);
- ON_CALL(*connection, CloseConnection(_, _, _))
- .WillByDefault(WithoutArgs(Invoke(
- connection, &MockServerConnection::UnregisterOnConnectionClosed)));
- EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>((*session)->connection()),
- ProcessUdpPacket(_, client_address, _));
-
- return *session;
-}
-
class QuicDispatcherTest : public ::testing::Test {
public:
QuicDispatcherTest()
: helper_(&eps_, QuicAllocator::BUFFER_POOL),
alarm_factory_(&eps_),
+ version_manager_(AllSupportedVersions()),
crypto_config_(QuicCryptoServerConfig::TESTING,
QuicRandom::GetInstance(),
CryptoTestUtils::ProofSourceForTesting()),
- dispatcher_(config_, &crypto_config_, &eps_),
+ dispatcher_(new TestDispatcher(config_,
+ &crypto_config_,
+ &version_manager_,
+ &eps_)),
time_wait_list_manager_(nullptr),
session1_(nullptr),
- session2_(nullptr) {
- dispatcher_.InitializeWithWriter(new QuicDefaultPacketWriter(1));
+ session2_(nullptr),
+ store_(nullptr) {}
+
+ void SetUp() override {
+ dispatcher_->InitializeWithWriter(new QuicDefaultPacketWriter(1));
+ // Set the counter to some value to start with.
+ QuicDispatcherPeer::set_new_sessions_allowed_per_event_loop(
+ dispatcher_.get(), kMaxNumSessionsToCreate);
}
~QuicDispatcherTest() override {}
@@ -231,8 +237,8 @@ class QuicDispatcherTest : public ::testing::Test {
QuicPathId path_id,
QuicPacketNumber packet_number) {
ProcessPacket(client_address, connection_id, has_version_flag,
- QuicSupportedVersions().front(), data, connection_id_length,
- packet_number_length, packet_number);
+ CurrentSupportedVersions().front(), data,
+ connection_id_length, packet_number_length, packet_number);
}
// Processes a packet.
@@ -251,22 +257,55 @@ class QuicDispatcherTest : public ::testing::Test {
std::unique_ptr<QuicReceivedPacket> received_packet(
ConstructReceivedPacket(*packet, helper_.GetClock()->Now()));
- data_ = string(packet->data(), packet->length());
- dispatcher_.ProcessPacket(server_address_, client_address,
- *received_packet);
+ if (ChloExtractor::Extract(*packet, versions, nullptr)) {
+ // Add CHLO packet to the beginning to be verified first, because it is
+ // also processed first by new session.
+ data_connection_map_[connection_id].push_front(
+ string(packet->data(), packet->length()));
+ } else {
+ // For non-CHLO, always append to last.
+ data_connection_map_[connection_id].push_back(
+ string(packet->data(), packet->length()));
+ }
+ dispatcher_->ProcessPacket(server_address_, client_address,
+ *received_packet);
}
- void ValidatePacket(const QuicEncryptedPacket& packet) {
- EXPECT_EQ(data_.length(), packet.AsStringPiece().length());
- EXPECT_EQ(data_, packet.AsStringPiece());
+ void ValidatePacket(QuicConnectionId conn_id,
+ const QuicEncryptedPacket& packet) {
+ EXPECT_EQ(data_connection_map_[conn_id].front().length(),
+ packet.AsStringPiece().length());
+ EXPECT_EQ(data_connection_map_[conn_id].front(), packet.AsStringPiece());
+ data_connection_map_[conn_id].pop_front();
+ }
+
+ QuicServerSessionBase* CreateSession(
+ QuicDispatcher* dispatcher,
+ const QuicConfig& config,
+ QuicConnectionId connection_id,
+ const IPEndPoint& client_address,
+ MockQuicConnectionHelper* helper,
+ MockAlarmFactory* alarm_factory,
+ const QuicCryptoServerConfig* crypto_config,
+ QuicCompressedCertsCache* compressed_certs_cache,
+ TestQuicSpdyServerSession** session) {
+ MockServerConnection* connection = new MockServerConnection(
+ connection_id, helper, alarm_factory, dispatcher);
+ *session = new TestQuicSpdyServerSession(config, connection, crypto_config,
+ compressed_certs_cache);
+ connection->set_visitor(*session);
+ ON_CALL(*connection, CloseConnection(_, _, _))
+ .WillByDefault(WithoutArgs(Invoke(
+ connection, &MockServerConnection::UnregisterOnConnectionClosed)));
+ return *session;
}
void CreateTimeWaitListManager() {
- time_wait_list_manager_ =
- new MockTimeWaitListManager(QuicDispatcherPeer::GetWriter(&dispatcher_),
- &dispatcher_, &helper_, &alarm_factory_);
+ time_wait_list_manager_ = new MockTimeWaitListManager(
+ QuicDispatcherPeer::GetWriter(dispatcher_.get()), dispatcher_.get(),
+ &helper_, &alarm_factory_);
// dispatcher_ takes the ownership of time_wait_list_manager_.
- QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_,
+ QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(),
time_wait_list_manager_);
}
@@ -276,46 +315,57 @@ class QuicDispatcherTest : public ::testing::Test {
return client_hello.GetSerialized().AsStringPiece().as_string();
}
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
EpollServer eps_;
QuicEpollConnectionHelper helper_;
MockQuicConnectionHelper mock_helper_;
QuicEpollAlarmFactory alarm_factory_;
MockAlarmFactory mock_alarm_factory_;
QuicConfig config_;
+ QuicVersionManager version_manager_;
QuicCryptoServerConfig crypto_config_;
IPEndPoint server_address_;
- TestDispatcher dispatcher_;
+ std::unique_ptr<TestDispatcher> dispatcher_;
MockTimeWaitListManager* time_wait_list_manager_;
TestQuicSpdyServerSession* session1_;
TestQuicSpdyServerSession* session2_;
- string data_;
+ std::map<QuicConnectionId, std::list<string>> data_connection_map_;
+ QuicBufferedPacketStore* store_;
};
TEST_F(QuicDispatcherTest, ProcessPackets) {
IPEndPoint client_address(net::test::Loopback4(), 1);
server_address_ = IPEndPoint(net::test::Any4(), 5);
- EXPECT_CALL(dispatcher_, CreateQuicSession(1, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(1, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, config_, 1, client_address, &mock_helper_,
+ dispatcher_.get(), config_, 1, client_address, &mock_helper_,
&mock_alarm_factory_, &crypto_config_,
- QuicDispatcherPeer::GetCache(&dispatcher_), &session1_)));
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
ProcessPacket(client_address, 1, true, false, SerializeCHLO());
- EXPECT_EQ(client_address, dispatcher_.current_client_address());
- EXPECT_EQ(server_address_, dispatcher_.current_server_address());
+ EXPECT_EQ(client_address, dispatcher_->current_client_address());
+ EXPECT_EQ(server_address_, dispatcher_->current_server_address());
- EXPECT_CALL(dispatcher_, CreateQuicSession(2, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(2, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, config_, 2, client_address, &mock_helper_,
+ dispatcher_.get(), config_, 2, client_address, &mock_helper_,
&mock_alarm_factory_, &crypto_config_,
- QuicDispatcherPeer::GetCache(&dispatcher_), &session2_)));
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session2_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session2_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 2))));
ProcessPacket(client_address, 2, true, false, SerializeCHLO());
EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
ProcessUdpPacket(_, _, _))
.Times(1)
- .WillOnce(testing::WithArgs<2>(
- Invoke(this, &QuicDispatcherTest::ValidatePacket)));
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
ProcessPacket(client_address, 1, false, false, "data");
}
@@ -323,7 +373,7 @@ TEST_F(QuicDispatcherTest, StatelessVersionNegotiation) {
IPEndPoint client_address(net::test::Loopback4(), 1);
server_address_ = IPEndPoint(net::test::Any4(), 5);
- EXPECT_CALL(dispatcher_, CreateQuicSession(1, client_address)).Times(0);
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(1, client_address)).Times(0);
QuicVersion version = static_cast<QuicVersion>(QuicVersionMin() - 1);
ProcessPacket(client_address, 1, true, version, SerializeCHLO(),
PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, 1);
@@ -332,18 +382,22 @@ TEST_F(QuicDispatcherTest, StatelessVersionNegotiation) {
TEST_F(QuicDispatcherTest, Shutdown) {
IPEndPoint client_address(net::test::Loopback4(), 1);
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, config_, 1, client_address, &mock_helper_,
+ dispatcher_.get(), config_, 1, client_address, &mock_helper_,
&mock_alarm_factory_, &crypto_config_,
- QuicDispatcherPeer::GetCache(&dispatcher_), &session1_)));
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
ProcessPacket(client_address, 1, true, false, SerializeCHLO());
EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
CloseConnection(QUIC_PEER_GOING_AWAY, _, _));
- dispatcher_.Shutdown();
+ dispatcher_->Shutdown();
}
TEST_F(QuicDispatcherTest, TimeWaitListManager) {
@@ -352,11 +406,16 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) {
// Create a new session.
IPEndPoint client_address(net::test::Loopback4(), 1);
QuicConnectionId connection_id = 1;
- EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, config_, connection_id, client_address, &mock_helper_,
- &mock_alarm_factory_, &crypto_config_,
- QuicDispatcherPeer::GetCache(&dispatcher_), &session1_)));
+ 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), 1))));
+
ProcessPacket(client_address, connection_id, true, false, SerializeCHLO());
// Close the connection by sending public reset packet.
@@ -368,8 +427,8 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) {
packet.nonce_proof = 132232;
std::unique_ptr<QuicEncryptedPacket> encrypted(
QuicFramer::BuildPublicResetPacket(packet));
- std::unique_ptr<QuicReceivedPacket> received(
- ConstructReceivedPacket(*encrypted, helper_.GetClock()->Now()));
+ std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
+ *encrypted, session1_->connection()->clock()->Now()));
EXPECT_CALL(*session1_, OnConnectionClosed(QUIC_PUBLIC_RESET, _,
ConnectionCloseSource::FROM_PEER))
.Times(1)
@@ -381,7 +440,7 @@ TEST_F(QuicDispatcherTest, TimeWaitListManager) {
.WillOnce(
Invoke(reinterpret_cast<MockQuicConnection*>(session1_->connection()),
&MockQuicConnection::ReallyProcessUdpPacket));
- dispatcher_.ProcessPacket(IPEndPoint(), client_address, *received);
+ dispatcher_->ProcessPacket(IPEndPoint(), client_address, *received);
EXPECT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
// Dispatcher forwards subsequent packets for this connection_id to the time
@@ -401,7 +460,7 @@ TEST_F(QuicDispatcherTest, NoVersionPacketToTimeWaitListManager) {
QuicConnectionId connection_id = 1;
// Dispatcher forwards all packets for this connection_id to the time wait
// list manager.
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, _)).Times(0);
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_,
ProcessPacket(_, _, connection_id, _, _))
.Times(1);
@@ -417,7 +476,7 @@ TEST_F(QuicDispatcherTest, ProcessPacketWithZeroPort) {
server_address_ = IPEndPoint(net::test::Any4(), 5);
// dispatcher_ should drop this packet.
- EXPECT_CALL(dispatcher_, CreateQuicSession(1, client_address)).Times(0);
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(1, client_address)).Times(0);
EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _))
.Times(0);
@@ -429,19 +488,23 @@ TEST_F(QuicDispatcherTest, OKSeqNoPacketProcessed) {
QuicConnectionId connection_id = 1;
server_address_ = IPEndPoint(net::test::Any4(), 5);
- EXPECT_CALL(dispatcher_, CreateQuicSession(1, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(1, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, config_, 1, client_address, &mock_helper_,
+ dispatcher_.get(), config_, 1, client_address, &mock_helper_,
&mock_alarm_factory_, &crypto_config_,
- QuicDispatcherPeer::GetCache(&dispatcher_), &session1_)));
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
// A packet whose packet number is the largest that is allowed to start a
// connection.
ProcessPacket(client_address, connection_id, true, false, SerializeCHLO(),
PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
kDefaultPathId,
QuicDispatcher::kMaxReasonableInitialPacketNumber);
- EXPECT_EQ(client_address, dispatcher_.current_client_address());
- EXPECT_EQ(server_address_, dispatcher_.current_server_address());
+ EXPECT_EQ(client_address, dispatcher_->current_client_address());
+ EXPECT_EQ(server_address_, dispatcher_->current_server_address());
}
TEST_F(QuicDispatcherTest, TooBigSeqNoPacketToTimeWaitListManager) {
@@ -451,7 +514,7 @@ TEST_F(QuicDispatcherTest, TooBigSeqNoPacketToTimeWaitListManager) {
QuicConnectionId connection_id = 1;
// Dispatcher forwards this packet for this connection_id to the time wait
// list manager.
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, _)).Times(0);
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_,
ProcessPacket(_, _, connection_id, _, _))
.Times(1);
@@ -470,11 +533,13 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream {
public:
MockQuicCryptoServerStream(const QuicCryptoServerConfig& crypto_config,
QuicCompressedCertsCache* compressed_certs_cache,
- QuicServerSessionBase* session)
+ QuicServerSessionBase* session,
+ QuicCryptoServerStream::Helper* helper)
: QuicCryptoServerStream(&crypto_config,
compressed_certs_cache,
FLAGS_enable_quic_stateless_reject_support,
- session) {}
+ session,
+ helper) {}
void set_handshake_confirmed_for_testing(bool handshake_confirmed) {
handshake_confirmed_ = handshake_confirmed;
}
@@ -530,7 +595,8 @@ class QuicDispatcherStatelessRejectTest
: public QuicDispatcherTest,
public ::testing::WithParamInterface<StatelessRejectTestParams> {
public:
- QuicDispatcherStatelessRejectTest() : crypto_stream1_(nullptr) {}
+ QuicDispatcherStatelessRejectTest()
+ : QuicDispatcherTest(), crypto_stream1_(nullptr) {}
~QuicDispatcherStatelessRejectTest() override {
if (crypto_stream1_) {
@@ -541,6 +607,7 @@ class QuicDispatcherStatelessRejectTest
// This test setup assumes that all testing will be done using
// crypto_stream1_.
void SetUp() override {
+ QuicDispatcherTest::SetUp();
FLAGS_enable_quic_stateless_reject_support =
GetParam().enable_stateless_rejects_via_flag;
}
@@ -553,17 +620,18 @@ class QuicDispatcherStatelessRejectTest
GetParam().client_supports_statelesss_rejects;
}
- // Sets up dispatcher_, sesession1_, and crypto_stream1_ based on
+ // Sets up dispatcher_, session1_, and crypto_stream1_ based on
// the test parameters.
QuicServerSessionBase* CreateSessionBasedOnTestParams(
QuicConnectionId connection_id,
const IPEndPoint& client_address) {
- CreateSession(&dispatcher_, config_, connection_id, client_address,
+ CreateSession(dispatcher_.get(), config_, connection_id, client_address,
&mock_helper_, &mock_alarm_factory_, &crypto_config_,
- QuicDispatcherPeer::GetCache(&dispatcher_), &session1_);
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_);
crypto_stream1_ = new MockQuicCryptoServerStream(
- crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_), session1_);
+ crypto_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()),
+ session1_, session1_->stream_helper());
session1_->SetCryptoStream(crypto_stream1_);
crypto_stream1_->set_handshake_confirmed_for_testing(
GetParam().crypto_handshake_successful);
@@ -587,10 +655,14 @@ TEST_P(QuicDispatcherStatelessRejectTest, ParameterizedBasicTest) {
IPEndPoint client_address(net::test::Loopback4(), 1);
QuicConnectionId connection_id = 1;
- EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
.WillOnce(testing::Return(
CreateSessionBasedOnTestParams(connection_id, client_address)));
-
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), connection_id))));
// Process the first packet for the connection.
ProcessPacket(client_address, connection_id, true, false, SerializeCHLO());
if (ExpectStatelessReject()) {
@@ -616,24 +688,30 @@ TEST_P(QuicDispatcherStatelessRejectTest, ParameterizedBasicTest) {
ProcessUdpPacket(_, _, _))
.Times(1)
.WillOnce(testing::WithArgs<2>(
- Invoke(this, &QuicDispatcherTest::ValidatePacket)));
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), connection_id))));
}
ProcessPacket(client_address, connection_id, true, false, "data");
}
TEST_P(QuicDispatcherStatelessRejectTest, CheapRejects) {
FLAGS_quic_use_cheap_stateless_rejects = true;
+ FLAGS_quic_buffer_packet_till_chlo = true;
CreateTimeWaitListManager();
IPEndPoint client_address(net::test::Loopback4(), 1);
QuicConnectionId connection_id = 1;
if (GetParam().enable_stateless_rejects_via_flag) {
- EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
.Times(0);
} else {
- EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
.WillOnce(testing::Return(
CreateSessionBasedOnTestParams(connection_id, client_address)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 1))));
}
VLOG(1) << "ExpectStatelessReject: " << ExpectStatelessReject();
@@ -660,6 +738,88 @@ TEST_P(QuicDispatcherStatelessRejectTest, CheapRejects) {
}
}
+TEST_P(QuicDispatcherStatelessRejectTest, BufferNonChlo) {
+ FLAGS_quic_use_cheap_stateless_rejects = true;
+ CreateTimeWaitListManager();
+
+ const IPEndPoint client_address(net::test::Loopback4(), 1);
+ const QuicConnectionId connection_id = 1;
+
+ if (!GetParam().enable_stateless_rejects_via_flag &&
+ !FLAGS_quic_buffer_packet_till_chlo) {
+ // If stateless rejects are not being used and early arrived packets are not
+ // buffered, then a connection will be created immediately.
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
+ .WillOnce(testing::Return(
+ CreateSessionBasedOnTestParams(connection_id, client_address)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, client_address, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), connection_id))));
+ }
+ bool first_packet_dropped = GetParam().enable_stateless_rejects_via_flag &&
+ !FLAGS_quic_buffer_packet_till_chlo;
+ if (first_packet_dropped) {
+ // Never do stateless reject while
+ // FLAGS_quic_buffer_packet_till_chlo is off.
+ EXPECT_QUIC_BUG(
+ ProcessPacket(client_address, connection_id, true, false,
+ "NOT DATA FOR A CHLO"),
+ "Have to drop packet because buffering non-chlo packet is "
+ "not supported while trying to do stateless reject. "
+ "--gfe2_reloadable_flag_quic_buffer_packet_till_chlo false "
+ "--gfe2_reloadable_flag_quic_use_cheap_stateless_rejects true");
+ } else {
+ ProcessPacket(client_address, connection_id, true, false,
+ "NOT DATA FOR A CHLO");
+ }
+
+ // Process the first packet for the connection.
+ // clang-format off
+ CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
+ "CHLO",
+ "AEAD", "AESG",
+ "KEXS", "C255",
+ "NONC", "1234567890123456789012",
+ "VER\0", "Q025",
+ "$padding", static_cast<int>(kClientHelloMinimumSize),
+ nullptr);
+ // clang-format on
+
+ if (GetParam().enable_stateless_rejects_via_flag ||
+ FLAGS_quic_buffer_packet_till_chlo) {
+ // If stateless rejects are enabled then a connection will be created now
+ // and the buffered packet will be processed
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
+ .WillOnce(testing::Return(
+ CreateSessionBasedOnTestParams(connection_id, client_address)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, client_address, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), connection_id))));
+ }
+ if (!first_packet_dropped) {
+ // Expect both packets to be passed to ProcessUdpPacket(). And one of them
+ // is already expected in CreateSessionBasedOnTestParams().
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, client_address, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), connection_id))))
+ .RetiresOnSaturation();
+ } else {
+ // Since first packet is dropped, remove it from map to skip
+ // ValidatePacket() on it.
+ data_connection_map_[connection_id].pop_front();
+ }
+ ProcessPacket(client_address, connection_id, true, false,
+ client_hello.GetSerialized().AsStringPiece().as_string());
+ EXPECT_FALSE(
+ time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
+}
+
// Verify the stopgap test: Packets with truncated connection IDs should be
// dropped.
class QuicDispatcherTestStrayPacketConnectionId : public QuicDispatcherTest {};
@@ -672,7 +832,7 @@ TEST_F(QuicDispatcherTestStrayPacketConnectionId,
IPEndPoint client_address(net::test::Loopback4(), 1);
QuicConnectionId connection_id = 1;
// Dispatcher drops this packet.
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, _)).Times(0);
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _)).Times(0);
EXPECT_CALL(*time_wait_list_manager_,
ProcessPacket(_, _, connection_id, _, _))
.Times(0);
@@ -707,39 +867,48 @@ class BlockingWriter : public QuicPacketWriterWrapper {
class QuicDispatcherWriteBlockedListTest : public QuicDispatcherTest {
public:
void SetUp() override {
+ QuicDispatcherTest::SetUp();
writer_ = new BlockingWriter;
- QuicDispatcherPeer::UseWriter(&dispatcher_, writer_);
+ QuicDispatcherPeer::UseWriter(dispatcher_.get(), writer_);
IPEndPoint client_address(net::test::Loopback4(), 1);
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, config_, 1, client_address, &helper_, &alarm_factory_,
- &crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_),
- &session1_)));
+ dispatcher_.get(), config_, 1, client_address, &helper_,
+ &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), 1))));
ProcessPacket(client_address, 1, true, false, SerializeCHLO());
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, client_address))
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, config_, 2, client_address, &helper_, &alarm_factory_,
- &crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_),
- &session2_)));
+ dispatcher_.get(), config_, 2, client_address, &helper_,
+ &alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session2_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session2_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArgs<2>(Invoke(CreateFunctor(
+ &QuicDispatcherTest::ValidatePacket, base::Unretained(this), 2))));
ProcessPacket(client_address, 2, true, false, SerializeCHLO());
- blocked_list_ = QuicDispatcherPeer::GetWriteBlockedList(&dispatcher_);
+ blocked_list_ = QuicDispatcherPeer::GetWriteBlockedList(dispatcher_.get());
}
void TearDown() override {
EXPECT_CALL(*connection1(), CloseConnection(QUIC_PEER_GOING_AWAY, _, _));
EXPECT_CALL(*connection2(), CloseConnection(QUIC_PEER_GOING_AWAY, _, _));
- dispatcher_.Shutdown();
+ dispatcher_->Shutdown();
}
void SetBlocked() { writer_->write_blocked_ = true; }
void BlockConnection2() {
writer_->write_blocked_ = true;
- dispatcher_.OnWriteBlocked(connection2());
+ dispatcher_->OnWriteBlocked(connection2());
}
protected:
@@ -751,95 +920,95 @@ class QuicDispatcherWriteBlockedListTest : public QuicDispatcherTest {
TEST_F(QuicDispatcherWriteBlockedListTest, BasicOnCanWrite) {
// No OnCanWrite calls because no connections are blocked.
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
// Register connection 1 for events, and make sure it's notified.
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
EXPECT_CALL(*connection1(), OnCanWrite());
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
// It should get only one notification.
EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
- dispatcher_.OnCanWrite();
- EXPECT_FALSE(dispatcher_.HasPendingWrites());
+ dispatcher_->OnCanWrite();
+ EXPECT_FALSE(dispatcher_->HasPendingWrites());
}
TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteOrder) {
// Make sure we handle events in order.
InSequence s;
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
- dispatcher_.OnWriteBlocked(connection2());
+ dispatcher_->OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection2());
EXPECT_CALL(*connection1(), OnCanWrite());
EXPECT_CALL(*connection2(), OnCanWrite());
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
// Check the other ordering.
SetBlocked();
- dispatcher_.OnWriteBlocked(connection2());
- dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection2());
+ dispatcher_->OnWriteBlocked(connection1());
EXPECT_CALL(*connection2(), OnCanWrite());
EXPECT_CALL(*connection1(), OnCanWrite());
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
}
TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteRemove) {
// Add and remove one connction.
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
blocked_list_->erase(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
// Add and remove one connction and make sure it doesn't affect others.
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
- dispatcher_.OnWriteBlocked(connection2());
+ dispatcher_->OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection2());
blocked_list_->erase(connection1());
EXPECT_CALL(*connection2(), OnCanWrite());
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
// Add it, remove it, and add it back and make sure things are OK.
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
blocked_list_->erase(connection1());
- dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
}
TEST_F(QuicDispatcherWriteBlockedListTest, DoubleAdd) {
// Make sure a double add does not necessitate a double remove.
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
- dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
blocked_list_->erase(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
// Make sure a double add does not result in two OnCanWrite calls.
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
- dispatcher_.OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection1());
EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
}
TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteHandleBlock) {
// Finally make sure if we write block on a write call, we stop calling.
InSequence s;
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
- dispatcher_.OnWriteBlocked(connection2());
+ dispatcher_->OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection2());
EXPECT_CALL(*connection1(), OnCanWrite())
.WillOnce(Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked));
EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
// And we'll resume where we left off when we get another call.
EXPECT_CALL(*connection2(), OnCanWrite());
- dispatcher_.OnCanWrite();
+ dispatcher_->OnCanWrite();
}
TEST_F(QuicDispatcherWriteBlockedListTest, LimitedWrites) {
@@ -847,37 +1016,495 @@ TEST_F(QuicDispatcherWriteBlockedListTest, LimitedWrites) {
// but should not be immediately called due to limits.
InSequence s;
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
- dispatcher_.OnWriteBlocked(connection2());
+ dispatcher_->OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection2());
EXPECT_CALL(*connection1(), OnCanWrite());
EXPECT_CALL(*connection2(), OnCanWrite())
.WillOnce(
Invoke(this, &QuicDispatcherWriteBlockedListTest::BlockConnection2));
- dispatcher_.OnCanWrite();
- EXPECT_TRUE(dispatcher_.HasPendingWrites());
+ dispatcher_->OnCanWrite();
+ EXPECT_TRUE(dispatcher_->HasPendingWrites());
// Now call OnCanWrite again, and connection1 should get its second chance
EXPECT_CALL(*connection2(), OnCanWrite());
- dispatcher_.OnCanWrite();
- EXPECT_FALSE(dispatcher_.HasPendingWrites());
+ dispatcher_->OnCanWrite();
+ EXPECT_FALSE(dispatcher_->HasPendingWrites());
}
TEST_F(QuicDispatcherWriteBlockedListTest, TestWriteLimits) {
// Finally make sure if we write block on a write call, we stop calling.
InSequence s;
SetBlocked();
- dispatcher_.OnWriteBlocked(connection1());
- dispatcher_.OnWriteBlocked(connection2());
+ dispatcher_->OnWriteBlocked(connection1());
+ dispatcher_->OnWriteBlocked(connection2());
EXPECT_CALL(*connection1(), OnCanWrite())
.WillOnce(Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked));
EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
- dispatcher_.OnCanWrite();
- EXPECT_TRUE(dispatcher_.HasPendingWrites());
+ dispatcher_->OnCanWrite();
+ EXPECT_TRUE(dispatcher_->HasPendingWrites());
// And we'll resume where we left off when we get another call.
EXPECT_CALL(*connection2(), OnCanWrite());
- dispatcher_.OnCanWrite();
- EXPECT_FALSE(dispatcher_.HasPendingWrites());
+ dispatcher_->OnCanWrite();
+ EXPECT_FALSE(dispatcher_->HasPendingWrites());
+}
+
+// Tests that bufferring packets works in stateful reject, expensive stateless
+// reject and cheap stateless reject.
+struct BufferedPacketStoreTestParams {
+ BufferedPacketStoreTestParams(bool enable_stateless_rejects_via_flag,
+ bool support_cheap_stateless_reject)
+ : enable_stateless_rejects_via_flag(enable_stateless_rejects_via_flag),
+ support_cheap_stateless_reject(support_cheap_stateless_reject) {}
+
+ friend ostream& operator<<(ostream& os,
+ const BufferedPacketStoreTestParams& p) {
+ os << "{ enable_stateless_rejects_via_flag: "
+ << p.enable_stateless_rejects_via_flag << std::endl;
+ os << " support_cheap_stateless_reject: "
+ << p.support_cheap_stateless_reject << " }";
+ return os;
+ }
+
+ // This only enables the stateless reject feature via the feature-flag.
+ // This should be a no-op if the peer does not support them.
+ bool enable_stateless_rejects_via_flag;
+ // Whether to do cheap stateless or not.
+ bool support_cheap_stateless_reject;
+};
+
+vector<BufferedPacketStoreTestParams> GetBufferedPacketStoreTestParams() {
+ vector<BufferedPacketStoreTestParams> params;
+ for (bool enable_stateless_rejects_via_flag : {true, false}) {
+ for (bool support_cheap_stateless_reject : {true, false}) {
+ params.push_back(BufferedPacketStoreTestParams(
+ enable_stateless_rejects_via_flag, support_cheap_stateless_reject));
+ }
+ }
+ return params;
+}
+
+// A dispatcher whose stateless rejector will always ACCEPTs CHLO.
+class BufferedPacketStoreTest
+ : public QuicDispatcherTest,
+ public ::testing::WithParamInterface<BufferedPacketStoreTestParams> {
+ public:
+ BufferedPacketStoreTest()
+ : QuicDispatcherTest(), client_addr_(Loopback4(), 1234) {
+ FLAGS_quic_buffer_packet_till_chlo = true;
+ FLAGS_quic_use_cheap_stateless_rejects =
+ GetParam().support_cheap_stateless_reject;
+ FLAGS_enable_quic_stateless_reject_support =
+ GetParam().enable_stateless_rejects_via_flag;
+ }
+
+ void SetUp() override {
+ QuicDispatcherTest::SetUp();
+ clock_ = QuicDispatcherPeer::GetHelper(dispatcher_.get())->GetClock();
+
+ QuicVersion version = AllSupportedVersions().front();
+ CryptoHandshakeMessage chlo = CryptoTestUtils::GenerateDefaultInchoateCHLO(
+ clock_, version, &crypto_config_);
+ chlo.SetVector(net::kCOPT, net::QuicTagVector{net::kSREJ});
+ // Pass an inchoate CHLO.
+ CryptoTestUtils::GenerateFullCHLO(
+ chlo, &crypto_config_, server_ip_, client_addr_, version, clock_,
+ &proof_, QuicDispatcherPeer::GetCache(dispatcher_.get()), &full_chlo_);
+ }
+
+ string SerializeFullCHLO() {
+ return full_chlo_.GetSerialized().AsStringPiece().as_string();
+ }
+
+ protected:
+ IPAddress server_ip_;
+ IPEndPoint client_addr_;
+ QuicCryptoProof proof_;
+ const QuicClock* clock_;
+ CryptoHandshakeMessage full_chlo_;
+};
+
+INSTANTIATE_TEST_CASE_P(
+ BufferedPacketStoreTests,
+ BufferedPacketStoreTest,
+ ::testing::ValuesIn(GetBufferedPacketStoreTestParams()));
+
+TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) {
+ InSequence s;
+ IPEndPoint client_address(Loopback4(), 1);
+ server_address_ = IPEndPoint(Any4(), 5);
+ QuicConnectionId conn_id = 1;
+ // A bunch of non-CHLO should be buffered upon arrival, and the first one
+ // should trigger OnNewConnectionAdded().
+ EXPECT_CALL(*dispatcher_, OnNewConnectionAdded(conn_id)).Times(1);
+ for (size_t i = 1; i <= kDefaultMaxUndecryptablePackets + 1; ++i) {
+ ProcessPacket(client_address, conn_id, true, false,
+ "data packet " + IntToString(i + 1),
+ PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
+ kDefaultPathId,
+ /*packet_number=*/i + 1);
+ }
+ EXPECT_EQ(0u, dispatcher_->session_map().size())
+ << "No session should be created before CHLO arrives.";
+
+ // Pop out the last packet as it is also be dropped by the store.
+ data_connection_map_[conn_id].pop_back();
+ // When CHLO arrives, a new session should be created, and all packets
+ // buffered should be delivered to the session.
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+
+ // Only |kDefaultMaxUndecryptablePackets| packets were buffered, and they
+ // should be delivered in arrival order.
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .Times(kDefaultMaxUndecryptablePackets + 1) // + 1 for CHLO.
+ .WillRepeatedly(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+}
+
+TEST_P(BufferedPacketStoreTest,
+ ProcessNonChloPacketsForDifferentConnectionsUptoLimit) {
+ InSequence s;
+ server_address_ = IPEndPoint(Any4(), 5);
+ // A bunch of non-CHLO should be buffered upon arrival.
+ size_t kNumConnections = (FLAGS_quic_limit_num_new_sessions_per_epoll_loop
+ ? kMaxConnectionsWithoutCHLO
+ : kDefaultMaxConnectionsInStore) +
+ 1;
+ for (size_t i = 1; i <= kNumConnections; ++i) {
+ IPEndPoint client_address(Loopback4(), i);
+ QuicConnectionId conn_id = i;
+ if (i <= kNumConnections - 1) {
+ // As they are on different connection, they should trigger
+ // OnNewConnectionAdded(). The last packet should be dropped.
+ EXPECT_CALL(*dispatcher_, OnNewConnectionAdded(conn_id));
+ }
+ ProcessPacket(client_address, conn_id, true, false,
+ "data packet on connection " + IntToString(i),
+ PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
+ kDefaultPathId,
+ /*packet_number=*/2);
+ }
+
+ // Pop out the packet on last connection as it shouldn't be enqueued in store
+ // as well.
+ data_connection_map_[kNumConnections].pop_front();
+
+ // Reset session creation counter to ensure processing CHLO can always
+ // create session.
+ QuicDispatcherPeer::set_new_sessions_allowed_per_event_loop(dispatcher_.get(),
+ kNumConnections);
+ // Process CHLOs to create session for these connections.
+ for (size_t i = 1; i <= kNumConnections; ++i) {
+ IPEndPoint client_address(Loopback4(), i);
+ QuicConnectionId conn_id = i;
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ if (conn_id == kNumConnections) {
+ // The last CHLO should trigger OnNewConnectionAdded() since it's the
+ // first packet arrives on that connection.
+ EXPECT_CALL(*dispatcher_, OnNewConnectionAdded(conn_id));
+ }
+ // First |kNumConnections| - 1 connections should have buffered
+ // a packet in store. The rest should have been dropped.
+ size_t upper_limit = FLAGS_quic_limit_num_new_sessions_per_epoll_loop
+ ? kMaxConnectionsWithoutCHLO
+ : kDefaultMaxConnectionsInStore;
+ size_t num_packet_to_process = i <= upper_limit ? 2u : 1u;
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, client_address, _))
+ .Times(num_packet_to_process)
+ .WillRepeatedly(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+ }
+}
+
+// Tests that store delivers empty packet list if CHLO arrives firstly.
+TEST_P(BufferedPacketStoreTest, DeliverEmptyPackets) {
+ QuicConnectionId conn_id = 1;
+ IPEndPoint client_address(Loopback4(), 1);
+ EXPECT_CALL(*dispatcher_, OnNewConnectionAdded(conn_id));
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+}
+
+// Tests that a retransmitted CHLO arrives after a connection for the
+// CHLO has been created.
+TEST_P(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) {
+ InSequence s;
+ IPEndPoint client_address(Loopback4(), 1);
+ server_address_ = IPEndPoint(Any4(), 5);
+ QuicConnectionId conn_id = 1;
+ ProcessPacket(client_address, conn_id, true, false,
+ "data packet " + IntToString(2), PACKET_8BYTE_CONNECTION_ID,
+ PACKET_6BYTE_PACKET_NUMBER, kDefaultPathId,
+ /*packet_number=*/2);
+
+ // When CHLO arrives, a new session should be created, and all packets
+ // buffered should be delivered to the session.
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address))
+ .Times(1) // Only triggered by 1st CHLO.
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .Times(3) // Triggered by 1 data packet and 2 CHLOs.
+ .WillRepeatedly(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+
+ ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+}
+
+// Tests that expiration of a connection add connection id to time wait list.
+TEST_P(BufferedPacketStoreTest, ReceiveCHLOAfterExpiration) {
+ InSequence s;
+ CreateTimeWaitListManager();
+ QuicBufferedPacketStore* store =
+ QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get());
+ QuicBufferedPacketStorePeer::set_clock(store, mock_helper_.GetClock());
+
+ IPEndPoint client_address(Loopback4(), 1);
+ server_address_ = IPEndPoint(Any4(), 5);
+ QuicConnectionId conn_id = 1;
+ ProcessPacket(client_address, conn_id, true, false,
+ "data packet " + IntToString(2), PACKET_8BYTE_CONNECTION_ID,
+ PACKET_6BYTE_PACKET_NUMBER, kDefaultPathId,
+ /*packet_number=*/2);
+
+ mock_helper_.AdvanceTime(
+ QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs));
+ QuicAlarm* alarm = QuicBufferedPacketStorePeer::expiration_alarm(store);
+ // Cancel alarm as if it had been fired.
+ alarm->Cancel();
+ store->OnExpirationTimeout();
+ // New arrived CHLO will be dropped because this connection is in time wait
+ // list.
+ ASSERT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id));
+ EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, conn_id, _, _));
+ ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
+}
+
+TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
+ // Process more than (|kMaxNumSessionsToCreate| +
+ // |kDefaultMaxConnectionsInStore|) CHLOs,
+ // the first |kMaxNumSessionsToCreate| should create connections immediately,
+ // the next |kDefaultMaxConnectionsInStore| should be buffered,
+ // the rest should be dropped.
+ QuicBufferedPacketStore* store =
+ QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get());
+ const size_t kNumCHLOs =
+ kMaxNumSessionsToCreate + kDefaultMaxConnectionsInStore + 1;
+ for (size_t conn_id = 1; conn_id <= kNumCHLOs; ++conn_id) {
+ if (conn_id < kNumCHLOs) {
+ // Except the last connection, all connections for previous CHLOs should
+ // be regarded as newly added.
+ EXPECT_CALL(*dispatcher_, OnNewConnectionAdded(conn_id));
+ }
+ if (conn_id <= kMaxNumSessionsToCreate) {
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(
+ *reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ }
+ ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
+ if (conn_id <= kMaxNumSessionsToCreate + kDefaultMaxConnectionsInStore &&
+ conn_id > kMaxNumSessionsToCreate) {
+ EXPECT_TRUE(store->HasChloForConnection(conn_id));
+ } else {
+ // First |kMaxNumSessionsToCreate| CHLOs should be passed to new
+ // connections immediately, and the last CHLO should be dropped as the
+ // store is full.
+ EXPECT_FALSE(store->HasChloForConnection(conn_id));
+ }
+ }
+
+ // Graduately consume buffered CHLOs. The buffered connections should be
+ // created but the dropped one shouldn't.
+ for (size_t conn_id = kMaxNumSessionsToCreate + 1;
+ conn_id <= kMaxNumSessionsToCreate + kDefaultMaxConnectionsInStore;
+ ++conn_id) {
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ }
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(kNumCHLOs, client_addr_))
+ .Times(0);
+
+ while (store->HasChlosBuffered()) {
+ dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate);
+ }
+
+ EXPECT_EQ(static_cast<size_t>(kMaxNumSessionsToCreate) +
+ kDefaultMaxConnectionsInStore,
+ session1_->connection_id());
+}
+
+// Duplicated CHLO shouldn't be buffered.
+TEST_P(BufferedPacketStoreTest, BufferDuplicatedCHLO) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
+ for (QuicConnectionId conn_id = 1; conn_id <= kMaxNumSessionsToCreate + 1;
+ ++conn_id) {
+ // Last CHLO will be buffered. Others will create connection right away.
+ if (conn_id <= kMaxNumSessionsToCreate) {
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(
+ *reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ }
+ ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
+ }
+ // Retransmit CHLO on last connection should be dropped.
+ QuicConnectionId last_connection = kMaxNumSessionsToCreate + 1;
+ ProcessPacket(client_addr_, last_connection, true, false,
+ SerializeFullCHLO());
+
+ size_t packets_buffered = 2;
+ if (!FLAGS_quic_buffer_packets_after_chlo) {
+ // The packet sent above is dropped when flag is off.
+ packets_buffered = 1;
+ }
+
+ // Reset counter and process buffered CHLO.
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(last_connection, client_addr_))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, last_connection, client_addr_,
+ &mock_helper_, &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ // Only one packet(CHLO) should be process.
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .Times(packets_buffered)
+ .WillRepeatedly(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), last_connection))));
+ dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate);
+}
+
+TEST_P(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
+ QuicConnectionId last_connection_id = kMaxNumSessionsToCreate + 1;
+ for (QuicConnectionId conn_id = 1; conn_id <= last_connection_id; ++conn_id) {
+ // Last CHLO will be buffered. Others will create connection right away.
+ if (conn_id <= kMaxNumSessionsToCreate) {
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(
+ *reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ }
+ ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
+ }
+
+ // Process another |kDefaultMaxUndecryptablePackets| + 1 data packets. The
+ // last one should be dropped.
+ for (QuicPacketNumber packet_number = 2;
+ packet_number <= kDefaultMaxUndecryptablePackets + 2; ++packet_number) {
+ ProcessPacket(client_addr_, last_connection_id, true, false, "data packet");
+ }
+
+ // Reset counter and process buffered CHLO.
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(last_connection_id, client_addr_))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, last_connection_id, client_addr_,
+ &mock_helper_, &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ // Only CHLO and following |kDefaultMaxUndecryptablePackets| data packets
+ // should be process.
+ EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .Times(kDefaultMaxUndecryptablePackets + 1)
+ .WillRepeatedly(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), last_connection_id))));
+ dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate);
+}
+
+// Tests that when dispatcher's packet buffer is full, a CHLO on connection
+// which doesn't have buffered CHLO should be buffered.
+TEST_P(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
+ QuicBufferedPacketStore* store =
+ QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get());
+
+ QuicConnectionId conn_id = 1;
+ ProcessPacket(client_addr_, conn_id, true, false, "data packet",
+ PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
+ kDefaultPathId,
+ /*packet_number=*/1);
+ // Fill packet buffer to full with CHLOs on other connections. Need to feed
+ // extra CHLOs because the first |kMaxNumSessionsToCreate| are going to create
+ // session directly.
+ for (conn_id = 2;
+ conn_id <= kDefaultMaxConnectionsInStore + kMaxNumSessionsToCreate;
+ ++conn_id) {
+ if (conn_id <= kMaxNumSessionsToCreate + 1) {
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_))
+ .WillOnce(testing::Return(CreateSession(
+ dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
+ &mock_alarm_factory_, &crypto_config_,
+ QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+ EXPECT_CALL(
+ *reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+ ProcessUdpPacket(_, _, _))
+ .WillOnce(testing::WithArg<2>(
+ Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
+ base::Unretained(this), conn_id))));
+ }
+ ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
+ }
+ EXPECT_FALSE(store->HasChloForConnection(/*connection_id=*/1));
+
+ // CHLO on connection 1 should still be buffered.
+ ProcessPacket(client_addr_, /*connection_id=*/1, true, false,
+ SerializeFullCHLO());
+ EXPECT_TRUE(store->HasChloForConnection(/*connection_id=*/1));
}
} // namespace
diff --git a/chromium/net/tools/quic/quic_epoll_alarm_factory.cc b/chromium/net/tools/quic/quic_epoll_alarm_factory.cc
index 21a166a70d5..56377b237b3 100644
--- a/chromium/net/tools/quic/quic_epoll_alarm_factory.cc
+++ b/chromium/net/tools/quic/quic_epoll_alarm_factory.cc
@@ -23,8 +23,7 @@ class QuicEpollAlarm : public QuicAlarm {
void SetImpl() override {
DCHECK(deadline().IsInitialized());
epoll_server_->RegisterAlarm(
- deadline().Subtract(QuicTime::Zero()).ToMicroseconds(),
- &epoll_alarm_impl_);
+ (deadline() - QuicTime::Zero()).ToMicroseconds(), &epoll_alarm_impl_);
}
void CancelImpl() override {
diff --git a/chromium/net/tools/quic/quic_epoll_alarm_factory.h b/chromium/net/tools/quic/quic_epoll_alarm_factory.h
index 6b59ccc781e..1f94b79417e 100644
--- a/chromium/net/tools/quic/quic_epoll_alarm_factory.h
+++ b/chromium/net/tools/quic/quic_epoll_alarm_factory.h
@@ -5,8 +5,8 @@
#ifndef NET_QUIC_QUIC_EPOLL_ALARM_FACTORY_H_
#define NET_QUIC_QUIC_EPOLL_ALARM_FACTORY_H_
-#include "net/quic/quic_alarm.h"
-#include "net/quic/quic_alarm_factory.h"
+#include "net/quic/core/quic_alarm.h"
+#include "net/quic/core/quic_alarm_factory.h"
namespace net {
diff --git a/chromium/net/tools/quic/quic_epoll_alarm_factory_test.cc b/chromium/net/tools/quic/quic_epoll_alarm_factory_test.cc
index 5dfe70185ec..3118be88a91 100644
--- a/chromium/net/tools/quic/quic_epoll_alarm_factory_test.cc
+++ b/chromium/net/tools/quic/quic_epoll_alarm_factory_test.cc
@@ -48,11 +48,11 @@ TEST_P(QuicEpollAlarmFactoryTest, CreateAlarm) {
QuicTime start = clock_.Now();
QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
- alarm->Set(start.Add(delta));
+ alarm->Set(start + delta);
epoll_server_.AdvanceByAndWaitForEventsAndExecuteCallbacks(
delta.ToMicroseconds());
- EXPECT_EQ(start.Add(delta), clock_.Now());
+ EXPECT_EQ(start + delta, clock_.Now());
}
TEST_P(QuicEpollAlarmFactoryTest, CreateAlarmAndCancel) {
@@ -64,11 +64,11 @@ TEST_P(QuicEpollAlarmFactoryTest, CreateAlarmAndCancel) {
QuicTime start = clock_.Now();
QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
- alarm->Set(start.Add(delta));
+ alarm->Set(start + delta);
alarm->Cancel();
epoll_server_.AdvanceByExactlyAndCallCallbacks(delta.ToMicroseconds());
- EXPECT_EQ(start.Add(delta), clock_.Now());
+ EXPECT_EQ(start + delta, clock_.Now());
EXPECT_FALSE(unowned_delegate->fired());
}
@@ -81,18 +81,18 @@ TEST_P(QuicEpollAlarmFactoryTest, CreateAlarmAndReset) {
QuicTime start = clock_.Now();
QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
- alarm->Set(clock_.Now().Add(delta));
+ alarm->Set(clock_.Now() + delta);
alarm->Cancel();
QuicTime::Delta new_delta = QuicTime::Delta::FromMicroseconds(3);
- alarm->Set(clock_.Now().Add(new_delta));
+ alarm->Set(clock_.Now() + new_delta);
epoll_server_.AdvanceByExactlyAndCallCallbacks(delta.ToMicroseconds());
- EXPECT_EQ(start.Add(delta), clock_.Now());
+ EXPECT_EQ(start + delta, clock_.Now());
EXPECT_FALSE(unowned_delegate->fired());
epoll_server_.AdvanceByExactlyAndCallCallbacks(
- new_delta.Subtract(delta).ToMicroseconds());
- EXPECT_EQ(start.Add(new_delta), clock_.Now());
+ (new_delta - delta).ToMicroseconds());
+ EXPECT_EQ(start + new_delta, clock_.Now());
EXPECT_TRUE(unowned_delegate->fired());
}
@@ -105,28 +105,25 @@ TEST_P(QuicEpollAlarmFactoryTest, CreateAlarmAndUpdate) {
QuicTime start = clock_.Now();
QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
- alarm->Set(clock_.Now().Add(delta));
+ alarm->Set(clock_.Now() + delta);
QuicTime::Delta new_delta = QuicTime::Delta::FromMicroseconds(3);
- alarm->Update(clock_.Now().Add(new_delta),
- QuicTime::Delta::FromMicroseconds(1));
+ alarm->Update(clock_.Now() + new_delta, QuicTime::Delta::FromMicroseconds(1));
epoll_server_.AdvanceByExactlyAndCallCallbacks(delta.ToMicroseconds());
- EXPECT_EQ(start.Add(delta), clock_.Now());
+ EXPECT_EQ(start + delta, clock_.Now());
EXPECT_FALSE(unowned_delegate->fired());
// Move the alarm forward 1us and ensure it doesn't move forward.
- alarm->Update(clock_.Now().Add(new_delta),
- QuicTime::Delta::FromMicroseconds(2));
+ alarm->Update(clock_.Now() + new_delta, QuicTime::Delta::FromMicroseconds(2));
epoll_server_.AdvanceByExactlyAndCallCallbacks(
- new_delta.Subtract(delta).ToMicroseconds());
- EXPECT_EQ(start.Add(new_delta), clock_.Now());
+ (new_delta - delta).ToMicroseconds());
+ EXPECT_EQ(start + new_delta, clock_.Now());
EXPECT_TRUE(unowned_delegate->fired());
// Set the alarm via an update call.
new_delta = QuicTime::Delta::FromMicroseconds(5);
- alarm->Update(clock_.Now().Add(new_delta),
- QuicTime::Delta::FromMicroseconds(1));
+ alarm->Update(clock_.Now() + new_delta, QuicTime::Delta::FromMicroseconds(1));
EXPECT_TRUE(alarm->IsSet());
// Update it with an uninitialized time and ensure it's cancelled.
diff --git a/chromium/net/tools/quic/quic_epoll_clock.cc b/chromium/net/tools/quic/quic_epoll_clock.cc
index cb7717647b7..357bc500c63 100644
--- a/chromium/net/tools/quic/quic_epoll_clock.cc
+++ b/chromium/net/tools/quic/quic_epoll_clock.cc
@@ -14,13 +14,13 @@ QuicEpollClock::QuicEpollClock(EpollServer* epoll_server)
QuicEpollClock::~QuicEpollClock() {}
QuicTime QuicEpollClock::ApproximateNow() const {
- return QuicTime::Zero().Add(
- QuicTime::Delta::FromMicroseconds(epoll_server_->ApproximateNowInUsec()));
+ return QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(
+ epoll_server_->ApproximateNowInUsec());
}
QuicTime QuicEpollClock::Now() const {
- return QuicTime::Zero().Add(
- QuicTime::Delta::FromMicroseconds(epoll_server_->NowInUsec()));
+ return QuicTime::Zero() +
+ QuicTime::Delta::FromMicroseconds(epoll_server_->NowInUsec());
}
QuicWallTime QuicEpollClock::WallNow() const {
@@ -30,8 +30,8 @@ QuicWallTime QuicEpollClock::WallNow() const {
QuicTime QuicEpollClock::ConvertWallTimeToQuicTime(
const QuicWallTime& walltime) const {
- return QuicTime::Zero().Add(
- QuicTime::Delta::FromMicroseconds(walltime.ToUNIXMicroseconds()));
-};
+ return QuicTime::Zero() +
+ QuicTime::Delta::FromMicroseconds(walltime.ToUNIXMicroseconds());
+}
} // namespace net
diff --git a/chromium/net/tools/quic/quic_epoll_clock.h b/chromium/net/tools/quic/quic_epoll_clock.h
index 520c529c9b7..509d3bf7e4d 100644
--- a/chromium/net/tools/quic/quic_epoll_clock.h
+++ b/chromium/net/tools/quic/quic_epoll_clock.h
@@ -7,8 +7,8 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_time.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_time.h"
namespace net {
diff --git a/chromium/net/tools/quic/quic_epoll_clock_test.cc b/chromium/net/tools/quic/quic_epoll_clock_test.cc
index 039e8bfa318..03d26b82106 100644
--- a/chromium/net/tools/quic/quic_epoll_clock_test.cc
+++ b/chromium/net/tools/quic/quic_epoll_clock_test.cc
@@ -16,13 +16,13 @@ TEST(QuicEpollClockTest, ApproximateNowInUsec) {
epoll_server.set_now_in_usec(1000000);
EXPECT_EQ(1000000,
- clock.ApproximateNow().Subtract(QuicTime::Zero()).ToMicroseconds());
+ (clock.ApproximateNow() - QuicTime::Zero()).ToMicroseconds());
EXPECT_EQ(1u, clock.WallNow().ToUNIXSeconds());
EXPECT_EQ(1000000u, clock.WallNow().ToUNIXMicroseconds());
epoll_server.AdvanceBy(5);
EXPECT_EQ(1000005,
- clock.ApproximateNow().Subtract(QuicTime::Zero()).ToMicroseconds());
+ (clock.ApproximateNow() - QuicTime::Zero()).ToMicroseconds());
EXPECT_EQ(1u, clock.WallNow().ToUNIXSeconds());
EXPECT_EQ(1000005u, clock.WallNow().ToUNIXMicroseconds());
@@ -36,10 +36,10 @@ TEST(QuicEpollClockTest, NowInUsec) {
QuicEpollClock clock(&epoll_server);
epoll_server.set_now_in_usec(1000000);
- EXPECT_EQ(1000000, clock.Now().Subtract(QuicTime::Zero()).ToMicroseconds());
+ EXPECT_EQ(1000000, (clock.Now() - QuicTime::Zero()).ToMicroseconds());
epoll_server.AdvanceBy(5);
- EXPECT_EQ(1000005, clock.Now().Subtract(QuicTime::Zero()).ToMicroseconds());
+ EXPECT_EQ(1000005, (clock.Now() - QuicTime::Zero()).ToMicroseconds());
}
} // namespace test
diff --git a/chromium/net/tools/quic/quic_epoll_connection_helper.cc b/chromium/net/tools/quic/quic_epoll_connection_helper.cc
index eec8fc5fd73..3f9671080e0 100644
--- a/chromium/net/tools/quic/quic_epoll_connection_helper.cc
+++ b/chromium/net/tools/quic/quic_epoll_connection_helper.cc
@@ -10,7 +10,7 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/crypto/quic_random.h"
+#include "net/quic/core/crypto/quic_random.h"
#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_socket_utils.h"
diff --git a/chromium/net/tools/quic/quic_epoll_connection_helper.h b/chromium/net/tools/quic/quic_epoll_connection_helper.h
index ccd7536b2bc..01964b35b9b 100644
--- a/chromium/net/tools/quic/quic_epoll_connection_helper.h
+++ b/chromium/net/tools/quic/quic_epoll_connection_helper.h
@@ -12,11 +12,11 @@
#include <set>
#include "base/macros.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_simple_buffer_allocator.h"
-#include "net/quic/quic_time.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_simple_buffer_allocator.h"
+#include "net/quic/core/quic_time.h"
#include "net/tools/quic/quic_default_packet_writer.h"
#include "net/tools/quic/quic_epoll_clock.h"
diff --git a/chromium/net/tools/quic/quic_epoll_connection_helper_test.cc b/chromium/net/tools/quic/quic_epoll_connection_helper_test.cc
index 078eef7b397..0f9106fe088 100644
--- a/chromium/net/tools/quic/quic_epoll_connection_helper_test.cc
+++ b/chromium/net/tools/quic/quic_epoll_connection_helper_test.cc
@@ -4,7 +4,7 @@
#include "net/tools/quic/quic_epoll_connection_helper.h"
-#include "net/quic/crypto/quic_random.h"
+#include "net/quic/core/crypto/quic_random.h"
#include "net/tools/quic/test_tools/mock_epoll_server.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -30,7 +30,7 @@ TEST_F(QuicEpollConnectionHelperTest, GetClock) {
QuicTime::Delta delta = QuicTime::Delta::FromMilliseconds(5);
epoll_server_.AdvanceBy(delta.ToMicroseconds());
- EXPECT_EQ(start.Add(delta), clock->Now());
+ EXPECT_EQ(start + delta, clock->Now());
}
TEST_F(QuicEpollConnectionHelperTest, GetRandomGenerator) {
diff --git a/chromium/net/tools/quic/quic_in_memory_cache.cc b/chromium/net/tools/quic/quic_in_memory_cache.cc
index 3b2f9e00b57..a63f4996e76 100644
--- a/chromium/net/tools/quic/quic_in_memory_cache.cc
+++ b/chromium/net/tools/quic/quic_in_memory_cache.cc
@@ -14,7 +14,7 @@
#include "base/strings/stringprintf.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
-#include "net/quic/quic_bug_tracker.h"
+#include "net/quic/core/quic_bug_tracker.h"
#include "net/spdy/spdy_http_utils.h"
using base::FilePath;
@@ -69,7 +69,7 @@ class ResourceFileImpl : public net::QuicInMemoryCache::ResourceFile {
body_ = StringPiece(file_contents_.data() + headers_end,
file_contents_.size() - headers_end);
- CreateSpdyHeadersFromHttpResponse(*http_headers_, HTTP2, &spdy_headers_);
+ CreateSpdyHeadersFromHttpResponse(*http_headers_, &spdy_headers_);
}
private:
@@ -119,9 +119,10 @@ void QuicInMemoryCache::ResourceFile::SetHostPathFromBase(StringPiece base) {
}
StringPiece QuicInMemoryCache::ResourceFile::RemoveScheme(StringPiece url) {
- if (url.starts_with("https://")) {
+ if (base::StartsWith(url, "https://", base::CompareCase::INSENSITIVE_ASCII)) {
url.remove_prefix(8);
- } else if (url.starts_with("http://")) {
+ } else if (base::StartsWith(url, "http://",
+ base::CompareCase::INSENSITIVE_ASCII)) {
url.remove_prefix(7);
}
return url;
@@ -142,6 +143,8 @@ QuicInMemoryCache* QuicInMemoryCache::GetInstance() {
const QuicInMemoryCache::Response* QuicInMemoryCache::GetResponse(
StringPiece host,
StringPiece path) const {
+ base::AutoLock lock(response_mutex_);
+
ResponseMap::const_iterator it = responses_.find(GetKey(host, path));
if (it == responses_.end()) {
DVLOG(1) << "Get response for resource failed: host " << host << " path "
@@ -178,6 +181,7 @@ void QuicInMemoryCache::AddSimpleResponseWithServerPushResources(
}
void QuicInMemoryCache::AddDefaultResponse(Response* response) {
+ base::AutoLock lock(response_mutex_);
default_response_.reset(response);
}
@@ -208,7 +212,8 @@ void QuicInMemoryCache::AddSpecialResponse(StringPiece host,
QuicInMemoryCache::QuicInMemoryCache() {}
void QuicInMemoryCache::ResetForTests() {
- STLDeleteValues(&responses_);
+ base::AutoLock lock(response_mutex_);
+ base::STLDeleteValues(&responses_);
server_push_resources_.clear();
}
@@ -268,6 +273,8 @@ void QuicInMemoryCache::InitializeFromDirectory(const string& cache_directory) {
list<ServerPushInfo> QuicInMemoryCache::GetServerPushResources(
string request_url) {
+ base::AutoLock lock(response_mutex_);
+
list<ServerPushInfo> resources;
auto resource_range = server_push_resources_.equal_range(request_url);
for (auto it = resource_range.first; it != resource_range.second; ++it) {
@@ -279,7 +286,10 @@ list<ServerPushInfo> QuicInMemoryCache::GetServerPushResources(
}
QuicInMemoryCache::~QuicInMemoryCache() {
- STLDeleteValues(&responses_);
+ {
+ base::AutoLock lock(response_mutex_);
+ base::STLDeleteValues(&responses_);
+ }
}
void QuicInMemoryCache::AddResponseImpl(StringPiece host,
@@ -288,9 +298,11 @@ void QuicInMemoryCache::AddResponseImpl(StringPiece host,
SpdyHeaderBlock response_headers,
StringPiece response_body,
SpdyHeaderBlock response_trailers) {
+ base::AutoLock lock(response_mutex_);
+
DCHECK(!host.empty()) << "Host must be populated, e.g. \"www.google.com\"";
string key = GetKey(host, path);
- if (ContainsKey(responses_, key)) {
+ if (base::ContainsKey(responses_, key)) {
QUIC_BUG << "Response for '" << key << "' already exists!";
return;
}
@@ -321,13 +333,22 @@ void QuicInMemoryCache::MaybeAddServerPushResources(
DVLOG(1) << "Add request-resource association: request url " << request_url
<< " push url " << push_resource.request_url
<< " response headers " << push_resource.headers.DebugString();
- server_push_resources_.insert(std::make_pair(request_url, push_resource));
+ {
+ base::AutoLock lock(response_mutex_);
+ server_push_resources_.insert(std::make_pair(request_url, push_resource));
+ }
string host = push_resource.request_url.host();
if (host.empty()) {
host = request_host.as_string();
}
string path = push_resource.request_url.path();
- if (responses_.find(GetKey(host, path)) == responses_.end()) {
+ bool found_existing_response = false;
+ {
+ base::AutoLock lock(response_mutex_);
+ found_existing_response =
+ base::ContainsKey(responses_, GetKey(host, path));
+ }
+ if (!found_existing_response) {
// Add a server push response to responses map, if it is not in the map.
StringPiece body = push_resource.body;
DVLOG(1) << "Add response for push resource: host " << host << " path "
@@ -339,6 +360,7 @@ void QuicInMemoryCache::MaybeAddServerPushResources(
bool QuicInMemoryCache::PushResourceExistsInCache(string original_request_url,
ServerPushInfo resource) {
+ base::AutoLock lock(response_mutex_);
auto resource_range =
server_push_resources_.equal_range(original_request_url);
for (auto it = resource_range.first; it != resource_range.second; ++it) {
diff --git a/chromium/net/tools/quic/quic_in_memory_cache.h b/chromium/net/tools/quic/quic_in_memory_cache.h
index 2747c9303be..174a7d51635 100644
--- a/chromium/net/tools/quic/quic_in_memory_cache.h
+++ b/chromium/net/tools/quic/quic_in_memory_cache.h
@@ -17,7 +17,7 @@
#include "base/memory/singleton.h"
#include "base/strings/string_piece.h"
#include "net/http/http_response_headers.h"
-#include "net/quic/spdy_utils.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/spdy/spdy_framer.h"
#include "url/gurl.h"
@@ -234,6 +234,10 @@ class QuicInMemoryCache {
// A map from request URL to associated server push responses (if any).
std::multimap<std::string, ServerPushInfo> server_push_resources_;
+ // Protects against concurrent access from test threads setting responses, and
+ // server threads accessing those responses.
+ mutable base::Lock response_mutex_;
+
DISALLOW_COPY_AND_ASSIGN(QuicInMemoryCache);
};
diff --git a/chromium/net/tools/quic/quic_in_memory_cache_test.cc b/chromium/net/tools/quic/quic_in_memory_cache_test.cc
index d31e8fd813e..d220e482af0 100644
--- a/chromium/net/tools/quic/quic_in_memory_cache_test.cc
+++ b/chromium/net/tools/quic/quic_in_memory_cache_test.cc
@@ -69,7 +69,7 @@ TEST_F(QuicInMemoryCacheTest, AddSimpleResponseGetResponse) {
const QuicInMemoryCache::Response* response =
cache->GetResponse("www.google.com", "/");
ASSERT_TRUE(response);
- ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), ":status"));
EXPECT_EQ("200", response->headers().find(":status")->second);
EXPECT_EQ(response_body.size(), response->body().length());
}
@@ -106,9 +106,9 @@ TEST_F(QuicInMemoryCacheTest, ReadsCacheDir) {
QuicInMemoryCache::GetInstance()->GetResponse("quic.test.url",
"/index.html");
ASSERT_TRUE(response);
- ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), ":status"));
EXPECT_EQ("200", response->headers().find(":status")->second);
- ASSERT_TRUE(ContainsKey(response->headers(), "connection"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), "connection"));
EXPECT_EQ("close", response->headers().find("connection")->second);
EXPECT_LT(0U, response->body().length());
}
@@ -137,9 +137,9 @@ TEST_F(QuicInMemoryCacheTest, UsesOriginalUrl) {
QuicInMemoryCache::GetInstance()->GetResponse("quic.test.url",
"/index.html");
ASSERT_TRUE(response);
- ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), ":status"));
EXPECT_EQ("200", response->headers().find(":status")->second);
- ASSERT_TRUE(ContainsKey(response->headers(), "connection"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), "connection"));
EXPECT_EQ("close", response->headers().find("connection")->second);
EXPECT_LT(0U, response->body().length());
}
@@ -164,20 +164,20 @@ TEST_F(QuicInMemoryCacheTest, DefaultResponse) {
// Now we should get the default response for the original request.
response = cache->GetResponse("www.google.com", "/");
ASSERT_TRUE(response);
- ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), ":status"));
EXPECT_EQ("200", response->headers().find(":status")->second);
// Now add a set response for / and make sure it is returned
cache->AddSimpleResponse("www.google.com", "/", 302, "");
response = cache->GetResponse("www.google.com", "/");
ASSERT_TRUE(response);
- ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), ":status"));
EXPECT_EQ("302", response->headers().find(":status")->second);
// We should get the default response for other requests.
response = cache->GetResponse("www.google.com", "/asd");
ASSERT_TRUE(response);
- ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), ":status"));
EXPECT_EQ("200", response->headers().find(":status")->second);
}
@@ -249,7 +249,7 @@ TEST_F(QuicInMemoryCacheTest, GetServerPushResourcesAndPushResponses) {
const QuicInMemoryCache::Response* response =
cache->GetResponse(host, path);
ASSERT_TRUE(response);
- ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+ ASSERT_TRUE(base::ContainsKey(response->headers(), ":status"));
EXPECT_EQ(push_response_status[i++],
response->headers().find(":status")->second);
EXPECT_EQ(push_resource.body, response->body());
diff --git a/chromium/net/tools/quic/quic_packet_printer_bin.cc b/chromium/net/tools/quic/quic_packet_printer_bin.cc
index a19b679b735..8be7be5fda3 100644
--- a/chromium/net/tools/quic/quic_packet_printer_bin.cc
+++ b/chromium/net/tools/quic/quic_packet_printer_bin.cc
@@ -40,8 +40,8 @@
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_utils.h"
using std::cerr;
using std::string;
@@ -184,7 +184,7 @@ int main(int argc, char* argv[]) {
return 1;
}
string hex = net::QuicUtils::HexDecode(ArgToString(args[1]));
- net::QuicVersionVector versions = net::QuicSupportedVersions();
+ net::QuicVersionVector 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);
diff --git a/chromium/net/tools/quic/quic_packet_reader.cc b/chromium/net/tools/quic/quic_packet_reader.cc
index f3e1fea8480..6a443e57f12 100644
--- a/chromium/net/tools/quic/quic_packet_reader.cc
+++ b/chromium/net/tools/quic/quic_packet_reader.cc
@@ -15,8 +15,8 @@
#include "base/logging.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
#include "net/tools/quic/quic_dispatcher.h"
#include "net/tools/quic/quic_process_packet_interface.h"
#include "net/tools/quic/quic_socket_utils.h"
@@ -63,21 +63,23 @@ QuicPacketReader::~QuicPacketReader() {}
bool QuicPacketReader::ReadAndDispatchPackets(
int fd,
int port,
+ bool potentially_small_mtu,
const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped) {
#if MMSG_MORE
- return ReadAndDispatchManyPackets(fd, port, clock, processor,
- packets_dropped);
+ return ReadAndDispatchManyPackets(fd, port, potentially_small_mtu, clock,
+ processor, packets_dropped);
#else
- return ReadAndDispatchSinglePacket(fd, port, clock, processor,
- packets_dropped);
+ return ReadAndDispatchSinglePacket(fd, port, potentially_small_mtu, clock,
+ processor, packets_dropped);
#endif
}
bool QuicPacketReader::ReadAndDispatchManyPackets(
int fd,
int port,
+ bool potentially_small_mtu,
const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped) {
@@ -98,7 +100,6 @@ bool QuicPacketReader::ReadAndDispatchManyPackets(
return false; // recvmmsg failed.
}
- QuicTime fallback_timestamp = QuicTime::Zero();
QuicWallTime fallback_walltimestamp = QuicWallTime::Zero();
for (int i = 0; i < packets_read; ++i) {
if (mmsg_hdr_[i].msg_len == 0) {
@@ -114,12 +115,9 @@ bool QuicPacketReader::ReadAndDispatchManyPackets(
IPEndPoint client_address = IPEndPoint(packets_[i].raw_address);
IPAddress server_ip;
- QuicTime packet_timestamp = QuicTime::Zero();
QuicWallTime packet_walltimestamp = QuicWallTime::Zero();
- bool latched_walltimestamps = FLAGS_quic_socket_walltimestamps;
QuicSocketUtils::GetAddressAndTimestampFromMsghdr(
- &mmsg_hdr_[i].msg_hdr, &server_ip, &packet_timestamp,
- &packet_walltimestamp, latched_walltimestamps);
+ &mmsg_hdr_[i].msg_hdr, &server_ip, &packet_walltimestamp);
if (!IsInitializedAddress(server_ip)) {
QUIC_BUG << "Unable to get server address.";
continue;
@@ -127,24 +125,19 @@ bool QuicPacketReader::ReadAndDispatchManyPackets(
// This isn't particularly desirable, but not all platforms support socket
// timestamping.
- if (latched_walltimestamps) {
- if (packet_walltimestamp.IsZero()) {
- if (fallback_walltimestamp.IsZero()) {
- fallback_walltimestamp = clock.WallNow();
- }
- packet_walltimestamp = fallback_walltimestamp;
- }
- packet_timestamp = clock.ConvertWallTimeToQuicTime(packet_walltimestamp);
- } else {
- if (packet_timestamp == QuicTime::Zero()) {
- if (fallback_timestamp == QuicTime::Zero()) {
- fallback_timestamp = clock.Now();
- }
- packet_timestamp = fallback_timestamp;
+ if (packet_walltimestamp.IsZero()) {
+ if (fallback_walltimestamp.IsZero()) {
+ fallback_walltimestamp = clock.WallNow();
}
+ packet_walltimestamp = fallback_walltimestamp;
}
+ QuicTime timestamp = clock.ConvertWallTimeToQuicTime(packet_walltimestamp);
+ int ttl = 0;
+ bool has_ttl =
+ QuicSocketUtils::GetTtlFromMsghdr(&mmsg_hdr_[i].msg_hdr, &ttl);
QuicReceivedPacket packet(reinterpret_cast<char*>(packets_[i].iov.iov_base),
- mmsg_hdr_[i].msg_len, packet_timestamp, false);
+ mmsg_hdr_[i].msg_len, timestamp, false,
+ potentially_small_mtu, ttl, has_ttl);
IPEndPoint server_address(server_ip, port);
processor->ProcessPacket(server_address, client_address, packet);
}
@@ -166,20 +159,18 @@ bool QuicPacketReader::ReadAndDispatchManyPackets(
bool QuicPacketReader::ReadAndDispatchSinglePacket(
int fd,
int port,
+ bool potentially_small_mtu,
const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped) {
- bool latched_walltimestamps = FLAGS_quic_socket_walltimestamps;
char buf[kMaxPacketSize];
IPEndPoint client_address;
IPAddress server_ip;
- QuicTime timestamp = QuicTime::Zero();
QuicWallTime walltimestamp = QuicWallTime::Zero();
- int bytes_read = QuicSocketUtils::ReadPacket(
- fd, buf, arraysize(buf), packets_dropped, &server_ip, &timestamp,
- &walltimestamp, latched_walltimestamps, &client_address);
-
+ int bytes_read =
+ QuicSocketUtils::ReadPacket(fd, buf, arraysize(buf), packets_dropped,
+ &server_ip, &walltimestamp, &client_address);
if (bytes_read < 0) {
return false; // ReadPacket failed.
}
@@ -190,18 +181,14 @@ bool QuicPacketReader::ReadAndDispatchSinglePacket(
}
// This isn't particularly desirable, but not all platforms support socket
// timestamping.
- if (latched_walltimestamps) {
- if (walltimestamp.IsZero()) {
- walltimestamp = clock.WallNow();
- }
- timestamp = clock.ConvertWallTimeToQuicTime(walltimestamp);
- } else {
- if (timestamp == QuicTime::Zero()) {
- timestamp = clock.Now();
- }
+ if (walltimestamp.IsZero()) {
+ walltimestamp = clock.WallNow();
}
+ QuicTime timestamp = clock.ConvertWallTimeToQuicTime(walltimestamp);
- QuicReceivedPacket packet(buf, bytes_read, timestamp, false);
+ QuicReceivedPacket packet(buf, bytes_read, timestamp, false /* owns_buffer */,
+ potentially_small_mtu, -1 /* ttl */,
+ false /* ttl_valid */);
IPEndPoint server_address(server_ip, port);
processor->ProcessPacket(server_address, client_address, packet);
diff --git a/chromium/net/tools/quic/quic_packet_reader.h b/chromium/net/tools/quic/quic_packet_reader.h
index b388406b478..a4d207581b7 100644
--- a/chromium/net/tools/quic/quic_packet_reader.h
+++ b/chromium/net/tools/quic/quic_packet_reader.h
@@ -11,8 +11,8 @@
#include <sys/socket.h>
#include "base/macros.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_process_packet_interface.h"
#include "net/tools/quic/quic_socket_utils.h"
@@ -44,8 +44,11 @@ class QuicPacketReader {
// to track dropped packets and some packets are read.
// If the socket has timestamping enabled, the per packet timestamps will be
// passed to the processor. Otherwise, |clock| will be used.
+ // If |potentially_small_mtu| is set, the incoming packets have been
+ // identified as potentially having an unusually small MTU.
virtual bool ReadAndDispatchPackets(int fd,
int port,
+ bool potentially_small_mtu,
const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped);
@@ -57,6 +60,7 @@ class QuicPacketReader {
// Reads and dispatches many packets using recvmmsg.
bool ReadAndDispatchManyPackets(int fd,
int port,
+ bool potentially_small_mtu,
const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped);
@@ -64,6 +68,7 @@ class QuicPacketReader {
// Reads and dispatches a single packet using recvmsg.
static bool ReadAndDispatchSinglePacket(int fd,
int port,
+ bool potentially_small_mtu,
const QuicClock& clock,
ProcessPacketInterface* processor,
QuicPacketCount* packets_dropped);
diff --git a/chromium/net/tools/quic/quic_packet_writer_wrapper.cc b/chromium/net/tools/quic/quic_packet_writer_wrapper.cc
index 3d008f09c73..de3d92b2e46 100644
--- a/chromium/net/tools/quic/quic_packet_writer_wrapper.cc
+++ b/chromium/net/tools/quic/quic_packet_writer_wrapper.cc
@@ -4,7 +4,7 @@
#include "net/tools/quic/quic_packet_writer_wrapper.h"
-#include "net/quic/quic_types.h"
+#include "net/quic/core/quic_types.h"
namespace net {
diff --git a/chromium/net/tools/quic/quic_packet_writer_wrapper.h b/chromium/net/tools/quic/quic_packet_writer_wrapper.h
index 34642a6282d..ea1f9fcb10f 100644
--- a/chromium/net/tools/quic/quic_packet_writer_wrapper.h
+++ b/chromium/net/tools/quic/quic_packet_writer_wrapper.h
@@ -10,7 +10,7 @@
#include <memory>
#include "base/macros.h"
-#include "net/quic/quic_packet_writer.h"
+#include "net/quic/core/quic_packet_writer.h"
namespace net {
diff --git a/chromium/net/tools/quic/quic_per_connection_packet_writer.h b/chromium/net/tools/quic/quic_per_connection_packet_writer.h
index 6902f3af839..cc48b635e14 100644
--- a/chromium/net/tools/quic/quic_per_connection_packet_writer.h
+++ b/chromium/net/tools/quic/quic_per_connection_packet_writer.h
@@ -8,8 +8,8 @@
#include <stddef.h>
#include "base/macros.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_packet_writer.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_packet_writer.h"
namespace net {
@@ -17,7 +17,7 @@ namespace net {
class QuicPerConnectionPacketWriter : public QuicPacketWriter {
public:
// Does not take ownership of |shared_writer|.
- QuicPerConnectionPacketWriter(QuicPacketWriter* shared_writer);
+ explicit QuicPerConnectionPacketWriter(QuicPacketWriter* shared_writer);
~QuicPerConnectionPacketWriter() override;
QuicPacketWriter* shared_writer() const { return shared_writer_; }
diff --git a/chromium/net/tools/quic/quic_process_packet_interface.h b/chromium/net/tools/quic/quic_process_packet_interface.h
index aa1035d946b..600bc70844b 100644
--- a/chromium/net/tools/quic/quic_process_packet_interface.h
+++ b/chromium/net/tools/quic/quic_process_packet_interface.h
@@ -7,7 +7,7 @@
#include "base/macros.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
diff --git a/chromium/net/tools/quic/quic_reject_reason_decoder_bin.cc b/chromium/net/tools/quic/quic_reject_reason_decoder_bin.cc
new file mode 100644
index 00000000000..aba019947b7
--- /dev/null
+++ b/chromium/net/tools/quic/quic_reject_reason_decoder_bin.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Decodes the packet HandshakeFailureReason from the chromium histogram
+// Net.QuicClientHelloRejectReasons
+
+#include <iostream>
+
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/crypto_utils.h"
+
+using base::CommandLine;
+using base::StringToUint;
+using net::HandshakeFailureReason;
+using net::CryptoUtils;
+using net::MAX_FAILURE_REASON;
+using std::cerr;
+using std::cout;
+
+int main(int argc, char* argv[]) {
+ CommandLine::Init(argc, argv);
+ CommandLine* line = CommandLine::ForCurrentProcess();
+ const CommandLine::StringVector& args = line->GetArgs();
+
+ if (args.size() != 1) {
+ cerr << "Missing argument (Usage: " << argv[0] << " <packed_reason>\n";
+ return 1;
+ }
+
+ uint32_t packed_error = 0;
+ if (!StringToUint(args[0], &packed_error)) {
+ cerr << "Unable to parse: " << args[0] << "\n";
+ return 2;
+ }
+
+ for (int i = 1; i < MAX_FAILURE_REASON; ++i) {
+ if ((packed_error & (1 << (i - 1))) == 0) {
+ continue;
+ }
+ HandshakeFailureReason reason = static_cast<HandshakeFailureReason>(i);
+ cout << CryptoUtils::HandshakeFailureReasonToString(reason) << "\n";
+ }
+ return 0;
+}
diff --git a/chromium/net/tools/quic/quic_server.cc b/chromium/net/tools/quic/quic_server.cc
index 94fdfdaca09..fb5d5912b0f 100644
--- a/chromium/net/tools/quic/quic_server.cc
+++ b/chromium/net/tools/quic/quic_server.cc
@@ -15,19 +15,20 @@
#include "net/base/ip_endpoint.h"
#include "net/base/sockaddr_storage.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_crypto_stream.h"
-#include "net/quic/quic_data_reader.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_crypto_stream.h"
+#include "net/quic/core/quic_data_reader.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_dispatcher.h"
#include "net/tools/quic/quic_epoll_alarm_factory.h"
#include "net/tools/quic/quic_epoll_clock.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_in_memory_cache.h"
#include "net/tools/quic/quic_packet_reader.h"
-#include "net/tools/quic/quic_simple_server_session_helper.h"
+#include "net/tools/quic/quic_simple_crypto_server_stream_helper.h"
+#include "net/tools/quic/quic_simple_dispatcher.h"
#include "net/tools/quic/quic_socket_utils.h"
#ifndef SO_RXQ_OVFL
@@ -47,14 +48,16 @@ const char kSourceAddressTokenSecret[] = "secret";
} // namespace
-QuicServer::QuicServer(ProofSource* proof_source)
- : QuicServer(proof_source,
+const size_t kNumSessionsToCreatePerSocketEvent = 16;
+
+QuicServer::QuicServer(std::unique_ptr<ProofSource> proof_source)
+ : QuicServer(std::move(proof_source),
QuicConfig(),
QuicCryptoServerConfig::ConfigOptions(),
- QuicSupportedVersions()) {}
+ AllSupportedVersions()) {}
QuicServer::QuicServer(
- ProofSource* proof_source,
+ std::unique_ptr<ProofSource> proof_source,
const QuicConfig& config,
const QuicCryptoServerConfig::ConfigOptions& crypto_config_options,
const QuicVersionVector& supported_versions)
@@ -65,9 +68,9 @@ QuicServer::QuicServer(
config_(config),
crypto_config_(kSourceAddressTokenSecret,
QuicRandom::GetInstance(),
- proof_source),
+ std::move(proof_source)),
crypto_config_options_(crypto_config_options),
- supported_versions_(supported_versions),
+ version_manager_(supported_versions),
packet_reader_(new QuicPacketReader()) {
Initialize();
}
@@ -147,12 +150,12 @@ QuicDefaultPacketWriter* QuicServer::CreateWriter(int fd) {
QuicDispatcher* QuicServer::CreateQuicDispatcher() {
QuicEpollAlarmFactory alarm_factory(&epoll_server_);
- return new QuicDispatcher(
- config_, &crypto_config_, supported_versions_,
+ return new QuicSimpleDispatcher(
+ config_, &crypto_config_, &version_manager_,
std::unique_ptr<QuicEpollConnectionHelper>(new QuicEpollConnectionHelper(
&epoll_server_, QuicAllocator::BUFFER_POOL)),
- std::unique_ptr<QuicServerSessionBase::Helper>(
- new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
+ std::unique_ptr<QuicCryptoServerStream::Helper>(
+ new QuicSimpleCryptoServerStreamHelper(QuicRandom::GetInstance())),
std::unique_ptr<QuicEpollAlarmFactory>(
new QuicEpollAlarmFactory(&epoll_server_)));
}
@@ -176,12 +179,25 @@ void QuicServer::OnEvent(int fd, EpollEvent* event) {
if (event->in_events & EPOLLIN) {
DVLOG(1) << "EPOLLIN";
+
+ if (FLAGS_quic_limit_num_new_sessions_per_epoll_loop &&
+ FLAGS_quic_buffer_packet_till_chlo) {
+ dispatcher_->ProcessBufferedChlos(kNumSessionsToCreatePerSocketEvent);
+ }
+
bool more_to_read = true;
while (more_to_read) {
more_to_read = packet_reader_->ReadAndDispatchPackets(
- fd_, port_, QuicEpollClock(&epoll_server_), dispatcher_.get(),
+ fd_, port_, false /* potentially_small_mtu */,
+ QuicEpollClock(&epoll_server_), dispatcher_.get(),
overflow_supported_ ? &packets_dropped_ : nullptr);
}
+
+ if (FLAGS_quic_limit_num_new_sessions_per_epoll_loop &&
+ FLAGS_quic_buffer_packet_till_chlo && dispatcher_->HasChlosBuffered()) {
+ // Register EPOLLIN event to consume buffered CHLO(s).
+ event->out_ready_mask |= EPOLLIN;
+ }
}
if (event->in_events & EPOLLOUT) {
dispatcher_->OnCanWrite();
diff --git a/chromium/net/tools/quic/quic_server.h b/chromium/net/tools/quic/quic_server.h
index 76ff17a45b0..0a5b9035e6e 100644
--- a/chromium/net/tools/quic/quic_server.h
+++ b/chromium/net/tools/quic/quic_server.h
@@ -17,10 +17,10 @@
#include "base/macros.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_framer.h"
+#include "net/quic/chromium/quic_chromium_connection_helper.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_framer.h"
#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_default_packet_writer.h"
@@ -35,8 +35,8 @@ class QuicPacketReader;
class QuicServer : public EpollCallbackInterface {
public:
- explicit QuicServer(ProofSource* proof_source);
- QuicServer(ProofSource* proof_source,
+ explicit QuicServer(std::unique_ptr<ProofSource> proof_source);
+ QuicServer(std::unique_ptr<ProofSource> proof_source,
const QuicConfig& config,
const QuicCryptoServerConfig::ConfigOptions& server_config_options,
const QuicVersionVector& supported_versions);
@@ -81,13 +81,12 @@ class QuicServer : public EpollCallbackInterface {
const QuicConfig& config() const { return config_; }
const QuicCryptoServerConfig& crypto_config() const { return crypto_config_; }
- const QuicVersionVector& supported_versions() const {
- return supported_versions_;
- }
EpollServer* epoll_server() { return &epoll_server_; }
QuicDispatcher* dispatcher() { return dispatcher_.get(); }
+ QuicVersionManager* version_manager() { return &version_manager_; }
+
private:
friend class net::test::QuicServerPeer;
@@ -122,11 +121,8 @@ class QuicServer : public EpollCallbackInterface {
// crypto_config_options_ contains crypto parameters for the handshake.
QuicCryptoServerConfig::ConfigOptions crypto_config_options_;
- // 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).
- QuicVersionVector supported_versions_;
+ // Used to generate current supported versions.
+ QuicVersionManager version_manager_;
// Point to a QuicPacketReader object on the heap. The reader allocates more
// space than allowed on the stack.
diff --git a/chromium/net/tools/quic/quic_server_bin.cc b/chromium/net/tools/quic/quic_server_bin.cc
index 983c58443bc..b1eafd73f01 100644
--- a/chromium/net/tools/quic/quic_server_bin.cc
+++ b/chromium/net/tools/quic/quic_server_bin.cc
@@ -14,19 +14,21 @@
#include "base/strings/string_number_conversions.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/crypto/proof_source_chromium.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/chromium/crypto/proof_source_chromium.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_in_memory_cache.h"
#include "net/tools/quic/quic_server.h"
// The port the quic server will listen on.
int32_t FLAGS_port = 6121;
-net::ProofSource* CreateProofSource(const base::FilePath& cert_path,
- const base::FilePath& key_path) {
- net::ProofSourceChromium* proof_source = new net::ProofSourceChromium();
+std::unique_ptr<net::ProofSource> CreateProofSource(
+ const base::FilePath& cert_path,
+ const base::FilePath& key_path) {
+ std::unique_ptr<net::ProofSourceChromium> proof_source(
+ new net::ProofSourceChromium());
CHECK(proof_source->Initialize(cert_path, key_path, base::FilePath()));
- return proof_source;
+ return std::move(proof_source);
}
int main(int argc, char* argv[]) {
@@ -84,7 +86,7 @@ int main(int argc, char* argv[]) {
CreateProofSource(line->GetSwitchValuePath("certificate_file"),
line->GetSwitchValuePath("key_file")),
config, net::QuicCryptoServerConfig::ConfigOptions(),
- net::QuicSupportedVersions());
+ net::AllSupportedVersions());
server.SetStrikeRegisterNoStartupPeriod();
int rc = server.CreateUDPSocketAndListen(net::IPEndPoint(ip, FLAGS_port));
diff --git a/chromium/net/tools/quic/quic_server_test.cc b/chromium/net/tools/quic/quic_server_test.cc
index fbada53be56..0cefdb52fff 100644
--- a/chromium/net/tools/quic/quic_server_test.cc
+++ b/chromium/net/tools/quic/quic_server_test.cc
@@ -4,13 +4,14 @@
#include "net/tools/quic/quic_server.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/mock_quic_dispatcher.h"
#include "net/tools/quic/quic_epoll_alarm_factory.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
-#include "net/tools/quic/quic_simple_server_session_helper.h"
+#include "net/tools/quic/quic_simple_crypto_server_stream_helper.h"
+#include "net/tools/quic/test_tools/quic_server_peer.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
@@ -22,20 +23,138 @@ namespace test {
namespace {
+class MockQuicSimpleDispatcher : public QuicSimpleDispatcher {
+ public:
+ MockQuicSimpleDispatcher(
+ const QuicConfig& config,
+ const QuicCryptoServerConfig* crypto_config,
+ QuicVersionManager* version_manager,
+ std::unique_ptr<QuicConnectionHelperInterface> helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
+ std::unique_ptr<QuicAlarmFactory> alarm_factory)
+ : QuicSimpleDispatcher(config,
+ crypto_config,
+ version_manager,
+ std::move(helper),
+ std::move(session_helper),
+ std::move(alarm_factory)) {}
+ ~MockQuicSimpleDispatcher() override {}
+
+ MOCK_METHOD0(OnCanWrite, void());
+ MOCK_CONST_METHOD0(HasPendingWrites, bool());
+ MOCK_CONST_METHOD0(HasChlosBuffered, bool());
+ MOCK_METHOD1(ProcessBufferedChlos, void(size_t));
+};
+
+class TestQuicServer : public QuicServer {
+ public:
+ TestQuicServer() : QuicServer(CryptoTestUtils::ProofSourceForTesting()) {}
+
+ ~TestQuicServer() override {}
+
+ MockQuicSimpleDispatcher* mock_dispatcher() { return mock_dispatcher_; }
+
+ protected:
+ QuicDispatcher* CreateQuicDispatcher() override {
+ mock_dispatcher_ = new MockQuicSimpleDispatcher(
+ config(), &crypto_config(), version_manager(),
+ std::unique_ptr<QuicEpollConnectionHelper>(
+ new QuicEpollConnectionHelper(epoll_server(),
+ QuicAllocator::BUFFER_POOL)),
+ std::unique_ptr<QuicCryptoServerStream::Helper>(
+ new QuicSimpleCryptoServerStreamHelper(QuicRandom::GetInstance())),
+ std::unique_ptr<QuicEpollAlarmFactory>(
+ new QuicEpollAlarmFactory(epoll_server())));
+ return mock_dispatcher_;
+ }
+
+ MockQuicSimpleDispatcher* mock_dispatcher_;
+};
+
+class QuicServerEpollInTest : public ::testing::Test {
+ public:
+ QuicServerEpollInTest()
+ : port_(net::test::kTestPort), server_address_(Loopback4(), port_) {}
+
+ void StartListening() {
+ server_.CreateUDPSocketAndListen(server_address_);
+ ASSERT_TRUE(QuicServerPeer::SetSmallSocket(&server_));
+
+ if (!server_.overflow_supported()) {
+ LOG(WARNING) << "Overflow not supported. Not testing.";
+ return;
+ }
+ }
+
+ protected:
+ QuicFlagSaver saver_;
+ int port_;
+ IPEndPoint server_address_;
+ TestQuicServer server_;
+};
+
+// Tests that if dispatcher has CHLOs waiting for connection creation, EPOLLIN
+// event should try to create connections for them. And set epoll mask with
+// EPOLLIN if there are still CHLOs remaining at the end of epoll event.
+TEST_F(QuicServerEpollInTest, ProcessBufferedCHLOsOnEpollin) {
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
+ FLAGS_quic_buffer_packet_till_chlo = true;
+ // Given an EPOLLIN event, try to create session for buffered CHLOs. In first
+ // event, dispatcher can't create session for all of CHLOs. So listener should
+ // register another EPOLLIN event by itself. Even without new packet arrival,
+ // the rest CHLOs should be process in next epoll event.
+ StartListening();
+ bool more_chlos = true;
+ MockQuicSimpleDispatcher* dispatcher_ = server_.mock_dispatcher();
+ DCHECK(dispatcher_ != nullptr);
+ EXPECT_CALL(*dispatcher_, OnCanWrite()).Times(testing::AnyNumber());
+ EXPECT_CALL(*dispatcher_, ProcessBufferedChlos(_)).Times(2);
+ EXPECT_CALL(*dispatcher_, HasPendingWrites()).Times(testing::AnyNumber());
+ // Expect there are still CHLOs buffered after 1st event. But not any more
+ // after 2nd event.
+ EXPECT_CALL(*dispatcher_, HasChlosBuffered())
+ .WillOnce(testing::Return(true))
+ .WillOnce(
+ DoAll(testing::Assign(&more_chlos, false), testing::Return(false)));
+
+ // Send a packet to trigger epoll event.
+ int fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
+ ASSERT_LT(0, fd);
+
+ char buf[1024];
+ memset(buf, 0, arraysize(buf));
+ sockaddr_storage storage;
+ socklen_t storage_size = sizeof(storage);
+ ASSERT_TRUE(server_address_.ToSockAddr(reinterpret_cast<sockaddr*>(&storage),
+ &storage_size));
+ int rc = sendto(fd, buf, arraysize(buf), 0,
+ reinterpret_cast<sockaddr*>(&storage), storage_size);
+ if (rc < 0) {
+ DVLOG(1) << errno << " " << strerror(errno);
+ }
+
+ while (more_chlos) {
+ server_.WaitForEvents();
+ }
+}
+
class QuicServerDispatchPacketTest : public ::testing::Test {
public:
QuicServerDispatchPacketTest()
: crypto_config_("blah",
QuicRandom::GetInstance(),
CryptoTestUtils::ProofSourceForTesting()),
+ version_manager_(AllSupportedVersions()),
dispatcher_(
config_,
&crypto_config_,
+ &version_manager_,
std::unique_ptr<QuicEpollConnectionHelper>(
new QuicEpollConnectionHelper(&eps_,
QuicAllocator::BUFFER_POOL)),
- std::unique_ptr<QuicServerSessionBase::Helper>(
- new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
+ std::unique_ptr<QuicCryptoServerStream::Helper>(
+ new QuicSimpleCryptoServerStreamHelper(
+ QuicRandom::GetInstance())),
std::unique_ptr<QuicEpollAlarmFactory>(
new QuicEpollAlarmFactory(&eps_))) {
dispatcher_.InitializeWithWriter(new QuicDefaultPacketWriter(1234));
@@ -49,6 +168,7 @@ class QuicServerDispatchPacketTest : public ::testing::Test {
protected:
QuicConfig config_;
QuicCryptoServerConfig crypto_config_;
+ QuicVersionManager version_manager_;
EpollServer eps_;
MockQuicDispatcher dispatcher_;
};
diff --git a/chromium/net/tools/quic/quic_simple_client.cc b/chromium/net/tools/quic/quic_simple_client.cc
index d179b371a91..48126191ad2 100644
--- a/chromium/net/tools/quic/quic_simple_client.cc
+++ b/chromium/net/tools/quic/quic_simple_client.cc
@@ -12,63 +12,56 @@
#include "net/base/net_errors.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_info.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_chromium_alarm_factory.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_chromium_packet_reader.h"
-#include "net/quic/quic_chromium_packet_writer.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_id.h"
-#include "net/quic/spdy_utils.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.h"
+#include "net/quic/chromium/quic_chromium_alarm_factory.h"
+#include "net/quic/chromium/quic_chromium_connection_helper.h"
+#include "net/quic/chromium/quic_chromium_packet_reader.h"
+#include "net/quic/chromium/quic_chromium_packet_writer.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/spdy/spdy_header_block.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/udp/udp_client_socket.h"
using std::string;
using std::vector;
+using base::StringPiece;
namespace net {
-void QuicSimpleClient::ClientQuicDataToResend::Resend() {
- client_->SendRequest(*headers_, body_, fin_);
- delete headers_;
- headers_ = nullptr;
-}
-
-QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address,
- const QuicServerId& server_id,
- const QuicVersionVector& supported_versions,
- ProofVerifier* proof_verifier)
- : QuicClientBase(server_id,
- supported_versions,
- QuicConfig(),
- CreateQuicConnectionHelper(),
- CreateQuicAlarmFactory(),
- proof_verifier),
- server_address_(server_address),
- local_port_(0),
- initialized_(false),
- packet_reader_started_(false),
- weak_factory_(this) {}
-
-QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address,
- const QuicServerId& server_id,
- const QuicVersionVector& supported_versions,
- const QuicConfig& config,
- ProofVerifier* proof_verifier)
+QuicSimpleClient::QuicSimpleClient(
+ IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicVersionVector& supported_versions,
+ std::unique_ptr<ProofVerifier> proof_verifier)
+ : QuicSimpleClient(server_address,
+ server_id,
+ supported_versions,
+ QuicConfig(),
+ std::move(proof_verifier)) {}
+
+QuicSimpleClient::QuicSimpleClient(
+ IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicVersionVector& supported_versions,
+ const QuicConfig& config,
+ std::unique_ptr<ProofVerifier> proof_verifier)
: QuicClientBase(server_id,
supported_versions,
config,
CreateQuicConnectionHelper(),
CreateQuicAlarmFactory(),
- proof_verifier),
- server_address_(server_address),
- local_port_(0),
+ std::move(proof_verifier)),
initialized_(false),
packet_reader_started_(false),
- weak_factory_(this) {}
+ weak_factory_(this) {
+ set_server_address(server_address);
+}
QuicSimpleClient::~QuicSimpleClient() {
if (connected()) {
@@ -76,49 +69,25 @@ QuicSimpleClient::~QuicSimpleClient() {
QUIC_PEER_GOING_AWAY, "Shutting down",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
- STLDeleteElements(&data_to_resend_on_connect_);
- STLDeleteElements(&data_sent_before_handshake_);
-}
-
-bool QuicSimpleClient::Initialize() {
- DCHECK(!initialized_);
-
- QuicClientBase::Initialize();
-
- if (!CreateUDPSocket()) {
- return false;
- }
-
- initialized_ = true;
- return true;
-}
-
-QuicSimpleClient::QuicDataToResend::QuicDataToResend(HttpRequestInfo* headers,
- base::StringPiece body,
- bool fin)
- : headers_(headers), body_(body), fin_(fin) {}
-
-QuicSimpleClient::QuicDataToResend::~QuicDataToResend() {
- if (headers_) {
- delete headers_;
- }
}
-bool QuicSimpleClient::CreateUDPSocket() {
+bool QuicSimpleClient::CreateUDPSocketAndBind(IPEndPoint server_address,
+ IPAddress bind_to_address,
+ int bind_to_port) {
std::unique_ptr<UDPClientSocket> socket(
new UDPClientSocket(DatagramSocket::DEFAULT_BIND, RandIntCallback(),
- &net_log_, NetLog::Source()));
+ &net_log_, NetLogSource()));
- int address_family = server_address_.GetSockAddrFamily();
- if (bind_to_address_.size() != 0) {
- client_address_ = IPEndPoint(bind_to_address_, local_port_);
+ int address_family = server_address.GetSockAddrFamily();
+ if (bind_to_address.size() != 0) {
+ client_address_ = IPEndPoint(bind_to_address, bind_to_port);
} else if (address_family == AF_INET) {
- client_address_ = IPEndPoint(IPAddress::IPv4AllZeros(), local_port_);
+ client_address_ = IPEndPoint(IPAddress::IPv4AllZeros(), bind_to_port);
} else {
- client_address_ = IPEndPoint(IPAddress::IPv6AllZeros(), local_port_);
+ client_address_ = IPEndPoint(IPAddress::IPv6AllZeros(), bind_to_port);
}
- int rc = socket->Connect(server_address_);
+ int rc = socket->Connect(server_address);
if (rc != OK) {
LOG(ERROR) << "Connect failed: " << ErrorToShortString(rc);
return false;
@@ -146,7 +115,7 @@ bool QuicSimpleClient::CreateUDPSocket() {
packet_reader_.reset(new QuicChromiumPacketReader(
socket_.get(), &clock_, this, kQuicYieldAfterPacketsRead,
QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds),
- BoundNetLog()));
+ NetLogWithSource()));
if (socket != nullptr) {
socket->Close();
@@ -155,231 +124,23 @@ bool QuicSimpleClient::CreateUDPSocket() {
return true;
}
-void QuicSimpleClient::StartPacketReaderIfNotStarted() {
- if (!packet_reader_started_) {
- packet_reader_->StartReading();
- packet_reader_started_ = true;
- }
-}
-
-bool QuicSimpleClient::Connect() {
- // Attempt multiple connects until the maximum number of client hellos have
- // been sent.
- while (!connected() &&
- GetNumSentClientHellos() <= QuicCryptoClientStream::kMaxClientHellos) {
- StartConnect();
- StartPacketReaderIfNotStarted();
- while (EncryptionBeingEstablished()) {
- WaitForEvents();
- }
- if (FLAGS_enable_quic_stateless_reject_support && connected() &&
- !data_to_resend_on_connect_.empty()) {
- // A connection has been established and there was previously queued data
- // to resend. Resend it and empty the queue.
- for (QuicDataToResend* data : data_to_resend_on_connect_) {
- data->Resend();
- }
- STLDeleteElements(&data_to_resend_on_connect_);
- }
- if (session() != nullptr &&
- session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- // We've successfully created a session but we're not connected, and there
- // is no stateless reject to recover from. Give up trying.
- break;
- }
- }
- if (!connected() &&
- GetNumSentClientHellos() > QuicCryptoClientStream::kMaxClientHellos &&
- session() != nullptr &&
- session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- // The overall connection failed due too many stateless rejects.
- set_connection_error(QUIC_CRYPTO_TOO_MANY_REJECTS);
- }
- return session()->connection()->connected();
-}
-
-void QuicSimpleClient::StartConnect() {
- DCHECK(initialized_);
- DCHECK(!connected());
-
- set_writer(CreateQuicPacketWriter());
-
- if (connected_or_attempting_connect()) {
- // Before we destroy the last session and create a new one, gather its stats
- // and update the stats for the overall connection.
- UpdateStats();
- if (session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- // If the last error was due to a stateless reject, queue up the data to
- // be resent on the next successful connection.
- // TODO(jokulik): I'm a little bit concerned about ordering here. Maybe
- // we should just maintain one queue?
- DCHECK(data_to_resend_on_connect_.empty());
- data_to_resend_on_connect_.swap(data_sent_before_handshake_);
- }
- }
-
- CreateQuicClientSession(new QuicConnection(
- GetNextConnectionId(), server_address_, helper(), alarm_factory(),
- writer(),
- /* owns_writer= */ false, Perspective::IS_CLIENT, supported_versions()));
-
- session()->Initialize();
- session()->CryptoConnect();
- set_connected_or_attempting_connect(true);
-}
-
-void QuicSimpleClient::Disconnect() {
- DCHECK(initialized_);
-
- if (connected()) {
- session()->connection()->CloseConnection(
- QUIC_PEER_GOING_AWAY, "Client disconnecting",
- ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
- }
- STLDeleteElements(&data_to_resend_on_connect_);
- STLDeleteElements(&data_sent_before_handshake_);
-
+void QuicSimpleClient::CleanUpAllUDPSockets() {
reset_writer();
packet_reader_.reset();
packet_reader_started_ = false;
- initialized_ = false;
}
-void QuicSimpleClient::SendRequest(const HttpRequestInfo& headers,
- base::StringPiece body,
- bool fin) {
- QuicSpdyClientStream* stream = CreateReliableClientStream();
- if (stream == nullptr) {
- LOG(DFATAL) << "stream creation failed!";
- return;
- }
- SpdyHeaderBlock header_block;
- CreateSpdyHeadersFromHttpRequest(headers, headers.extra_headers, net::HTTP2,
- true, &header_block);
- stream->set_visitor(this);
- stream->SendRequest(std::move(header_block), body, fin);
- if (FLAGS_enable_quic_stateless_reject_support) {
- // Record this in case we need to resend.
- auto* new_headers = new HttpRequestInfo;
- *new_headers = headers;
- auto* data_to_resend =
- new ClientQuicDataToResend(new_headers, body, fin, this);
- MaybeAddQuicDataToResend(data_to_resend);
- }
-}
-
-void QuicSimpleClient::MaybeAddQuicDataToResend(
- QuicDataToResend* data_to_resend) {
- DCHECK(FLAGS_enable_quic_stateless_reject_support);
- if (session()->IsCryptoHandshakeConfirmed()) {
- // The handshake is confirmed. No need to continue saving requests to
- // resend.
- STLDeleteElements(&data_sent_before_handshake_);
- delete data_to_resend;
- return;
- }
-
- // The handshake is not confirmed. Push the data onto the queue of data to
- // resend if statelessly rejected.
- data_sent_before_handshake_.push_back(data_to_resend);
-}
-
-void QuicSimpleClient::SendRequestAndWaitForResponse(
- const HttpRequestInfo& request,
- base::StringPiece body,
- bool fin) {
- SendRequest(request, body, fin);
- while (WaitForEvents()) {
- }
-}
-
-void QuicSimpleClient::SendRequestsAndWaitForResponse(
- const base::CommandLine::StringVector& url_list) {
- for (size_t i = 0; i < url_list.size(); ++i) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL(url_list[i]);
- SendRequest(request, "", true);
- }
-
- while (WaitForEvents()) {
+void QuicSimpleClient::StartPacketReaderIfNotStarted() {
+ if (!packet_reader_started_) {
+ packet_reader_->StartReading();
+ packet_reader_started_ = true;
}
}
-bool QuicSimpleClient::WaitForEvents() {
- DCHECK(connected());
-
+void QuicSimpleClient::RunEventLoop() {
+ StartPacketReaderIfNotStarted();
base::RunLoop().RunUntilIdle();
-
- DCHECK(session() != nullptr);
- if (!connected() &&
- session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
- DCHECK(FLAGS_enable_quic_stateless_reject_support);
- DVLOG(1) << "Detected stateless reject while waiting for events. "
- << "Attempting to reconnect.";
- Connect();
- }
-
- return session()->num_active_requests() != 0;
-}
-
-bool QuicSimpleClient::MigrateSocket(const IPAddress& new_host) {
- if (!connected()) {
- return false;
- }
-
- bind_to_address_ = new_host;
- if (!CreateUDPSocket()) {
- return false;
- }
-
- session()->connection()->SetSelfAddress(client_address_);
-
- QuicPacketWriter* writer = CreateQuicPacketWriter();
- set_writer(writer);
- session()->connection()->SetQuicPacketWriter(writer, false);
-
- return true;
-}
-
-void QuicSimpleClient::OnClose(QuicSpdyStream* stream) {
- DCHECK(stream != nullptr);
- QuicSpdyClientStream* client_stream =
- static_cast<QuicSpdyClientStream*>(stream);
- HttpResponseInfo response;
- SpdyHeadersToHttpResponse(client_stream->response_headers(), net::HTTP2,
- &response);
- if (response_listener_.get() != nullptr) {
- response_listener_->OnCompleteResponse(stream->id(), *response.headers,
- client_stream->data());
- }
-
- // Store response headers and body.
- if (store_response_) {
- latest_response_code_ = client_stream->response_code();
- response.headers->GetNormalizedHeaders(&latest_response_headers_);
- latest_response_body_ = client_stream->data();
- }
-}
-
-size_t QuicSimpleClient::latest_response_code() const {
- LOG_IF(DFATAL, !store_response_) << "Response not stored!";
- return latest_response_code_;
-}
-
-const string& QuicSimpleClient::latest_response_headers() const {
- LOG_IF(DFATAL, !store_response_) << "Response not stored!";
- return latest_response_headers_;
-}
-
-const string& QuicSimpleClient::latest_response_body() const {
- LOG_IF(DFATAL, !store_response_) << "Response not stored!";
- return latest_response_body_;
-}
-
-QuicConnectionId QuicSimpleClient::GenerateNewConnectionId() {
- return helper()->GetRandomGenerator()->RandUint64();
}
QuicChromiumConnectionHelper* QuicSimpleClient::CreateQuicConnectionHelper() {
@@ -401,6 +162,10 @@ void QuicSimpleClient::OnReadError(int result,
Disconnect();
}
+IPEndPoint QuicSimpleClient::GetLatestClientAddress() const {
+ return client_address_;
+}
+
bool QuicSimpleClient::OnPacket(const QuicReceivedPacket& packet,
IPEndPoint local_address,
IPEndPoint peer_address) {
diff --git a/chromium/net/tools/quic/quic_simple_client.h b/chromium/net/tools/quic/quic_simple_client.h
index b94399c87a9..a7109b190a0 100644
--- a/chromium/net/tools/quic/quic_simple_client.h
+++ b/chromium/net/tools/quic/quic_simple_client.h
@@ -20,9 +20,9 @@
#include "net/base/ip_endpoint.h"
#include "net/http/http_response_headers.h"
#include "net/log/net_log.h"
-#include "net/quic/quic_chromium_packet_reader.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_spdy_stream.h"
+#include "net/quic/chromium/quic_chromium_packet_reader.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_spdy_stream.h"
#include "net/tools/quic/quic_client_base.h"
namespace net {
@@ -38,168 +38,45 @@ class QuicClientPeer;
} // namespace test
class QuicSimpleClient : public QuicClientBase,
- public QuicSpdyStream::Visitor,
public QuicChromiumPacketReader::Visitor {
public:
- class ResponseListener {
- public:
- ResponseListener() {}
- virtual ~ResponseListener() {}
- virtual void OnCompleteResponse(QuicStreamId id,
- const HttpResponseHeaders& response_headers,
- const std::string& response_body) = 0;
- };
-
- // The client uses these objects to keep track of any data to resend upon
- // receipt of a stateless reject. Recall that the client API allows callers
- // to optimistically send data to the server prior to handshake-confirmation.
- // If the client subsequently receives a stateless reject, it must tear down
- // its existing session, create a new session, and resend all previously sent
- // data. It uses these objects to keep track of all the sent data, and to
- // resend the data upon a subsequent connection.
- class QuicDataToResend {
- public:
- // Takes ownership of |headers|. |headers| may be null, since it's possible
- // to send data without headers.
- QuicDataToResend(HttpRequestInfo* headers,
- base::StringPiece body,
- bool fin);
-
- virtual ~QuicDataToResend();
-
- // Must be overridden by specific classes with the actual method for
- // re-sending data.
- virtual void Resend() = 0;
-
- protected:
- HttpRequestInfo* headers_;
- base::StringPiece body_;
- bool fin_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(QuicDataToResend);
- };
-
// Create a quic client, which will have events managed by an externally owned
// EpollServer.
QuicSimpleClient(IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
- ProofVerifier* proof_verifier);
+ std::unique_ptr<ProofVerifier> proof_verifier);
QuicSimpleClient(IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
const QuicConfig& config,
- ProofVerifier* proof_verifier);
+ std::unique_ptr<ProofVerifier> proof_verifier);
~QuicSimpleClient() override;
- // From QuicClientBase
- bool Initialize() override;
- bool WaitForEvents() override;
- QuicConnectionId GenerateNewConnectionId() override;
-
- // "Connect" to the QUIC server, including performing synchronous crypto
- // handshake.
- bool Connect();
-
- // Start the crypto handshake. This can be done in place of the synchronous
- // Connect(), but callers are responsible for making sure the crypto handshake
- // completes.
- void StartConnect();
-
- // Disconnects from the QUIC server.
- void Disconnect();
-
- // Sends an HTTP request and does not wait for response before returning.
- void SendRequest(const HttpRequestInfo& headers,
- base::StringPiece body,
- bool fin);
-
- // Sends an HTTP request and waits for response before returning.
- void SendRequestAndWaitForResponse(const HttpRequestInfo& headers,
- base::StringPiece body,
- bool fin);
-
- // Sends a request simple GET for each URL in |args|, and then waits for
- // each to complete.
- void SendRequestsAndWaitForResponse(
- const base::CommandLine::StringVector& url_list);
-
- // Migrate to a new socket during an active connection.
- bool MigrateSocket(const IPAddress& new_host);
-
// QuicChromiumPacketReader::Visitor
void OnReadError(int result, const DatagramClientSocket* socket) override;
bool OnPacket(const QuicReceivedPacket& packet,
IPEndPoint local_address,
IPEndPoint peer_address) override;
- // QuicSpdyStream::Visitor
- void OnClose(QuicSpdyStream* stream) override;
-
- // If the crypto handshake has not yet been confirmed, adds the data to the
- // queue of data to resend if the client receives a stateless reject.
- // Otherwise, deletes the data. Takes ownerership of |data_to_resend|.
- void MaybeAddQuicDataToResend(QuicDataToResend* data_to_resend);
-
- void set_bind_to_address(const IPAddress& address) {
- bind_to_address_ = address;
- }
-
- const IPAddress& bind_to_address() const { return bind_to_address_; }
-
- void set_local_port(int local_port) { local_port_ = local_port; }
-
- const IPEndPoint& server_address() const { return server_address_; }
-
- const IPEndPoint& client_address() const { return client_address_; }
-
- // Takes ownership of the listener.
- void set_response_listener(ResponseListener* listener) {
- response_listener_.reset(listener);
- }
-
- void set_store_response(bool val) { store_response_ = val; }
-
- size_t latest_response_code() const;
- const std::string& latest_response_headers() const;
- const std::string& latest_response_body() const;
+ // From QuicClientBase
+ IPEndPoint GetLatestClientAddress() const override;
protected:
- virtual QuicChromiumAlarmFactory* CreateQuicAlarmFactory();
- virtual QuicChromiumConnectionHelper* CreateQuicConnectionHelper();
- virtual QuicPacketWriter* CreateQuicPacketWriter();
+ // From QuicClientBase
+ QuicPacketWriter* CreateQuicPacketWriter() override;
+ void RunEventLoop() override;
+ bool CreateUDPSocketAndBind(IPEndPoint server_address,
+ IPAddress bind_to_address,
+ int bind_to_port) override;
+ void CleanUpAllUDPSockets() override;
private:
friend class net::test::QuicClientPeer;
- // Specific QuicClient class for storing data to resend.
- class ClientQuicDataToResend : public QuicDataToResend {
- public:
- // Takes ownership of |headers|.
- ClientQuicDataToResend(HttpRequestInfo* headers,
- base::StringPiece body,
- bool fin,
- QuicSimpleClient* client)
- : QuicDataToResend(headers, body, fin), client_(client) {
- DCHECK(headers);
- DCHECK(client);
- }
-
- ~ClientQuicDataToResend() override {}
-
- void Resend() override;
-
- private:
- QuicSimpleClient* client_;
-
- DISALLOW_COPY_AND_ASSIGN(ClientQuicDataToResend);
- };
-
- // Used during initialization: creates the UDP socket FD, sets socket options,
- // and binds the socket to our address.
- bool CreateUDPSocket();
+ QuicChromiumAlarmFactory* CreateQuicAlarmFactory();
+ QuicChromiumConnectionHelper* CreateQuicConnectionHelper();
// Read a UDP packet and hand it to the framer.
bool ReadAndProcessPacket();
@@ -209,51 +86,15 @@ class QuicSimpleClient : public QuicClientBase,
// Used by |helper_| to time alarms.
QuicClock clock_;
- // Address of the server.
- const IPEndPoint server_address_;
-
// Address of the client if the client is connected to the server.
IPEndPoint client_address_;
- // If initialized, the address to bind to.
- IPAddress bind_to_address_;
-
- // Local port to bind to. Initialize to 0.
- int local_port_;
-
// UDP socket connected to the server.
std::unique_ptr<UDPClientSocket> socket_;
- // Listens for full responses.
- std::unique_ptr<ResponseListener> response_listener_;
-
// Tracks if the client is initialized to connect.
bool initialized_;
- // If overflow_supported_ is true, this will be the number of packets dropped
- // during the lifetime of the server.
- QuicPacketCount packets_dropped_;
-
- // True if the kernel supports SO_RXQ_OVFL, the number of packets dropped
- // because the socket would otherwise overflow.
- bool overflow_supported_;
-
- // If true, store the latest response code, headers, and body.
- bool store_response_;
- // HTTP response code from most recent response.
- size_t latest_response_code_;
- // HTTP headers from most recent response.
- std::string latest_response_headers_;
- // Body of most recent response.
- std::string latest_response_body_;
-
- // Keeps track of any data sent before the handshake.
- std::vector<QuicDataToResend*> data_sent_before_handshake_;
-
- // Once the client receives a stateless reject, keeps track of any data that
- // must be resent upon a subsequent successful connection.
- std::vector<QuicDataToResend*> data_to_resend_on_connect_;
-
// The log used for the sockets.
NetLog net_log_;
diff --git a/chromium/net/tools/quic/quic_simple_client_bin.cc b/chromium/net/tools/quic/quic_simple_client_bin.cc
index 7cbb6dbdb8b..5fcf760986a 100644
--- a/chromium/net/tools/quic/quic_simple_client_bin.cc
+++ b/chromium/net/tools/quic/quic_simple_client_bin.cc
@@ -56,11 +56,10 @@
#include "net/cert/multi_log_ct_verifier.h"
#include "net/http/http_request_info.h"
#include "net/http/transport_security_state.h"
-#include "net/log/net_log.h"
-#include "net/quic/crypto/proof_verifier_chromium.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_id.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/chromium/crypto/proof_verifier_chromium.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/quic_utils.h"
#include "net/spdy/spdy_header_block.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/tools/quic/quic_simple_client.h"
@@ -113,7 +112,7 @@ class FakeCertVerifier : public net::CertVerifier {
net::CertVerifyResult* verify_result,
const net::CompletionCallback& callback,
std::unique_ptr<Request>* out_req,
- const net::BoundNetLog& net_log) override {
+ const net::NetLogWithSource& net_log) override {
return net::OK;
}
@@ -240,7 +239,7 @@ 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::QuicVersionVector versions = net::QuicSupportedVersions();
+ net::QuicVersionVector versions = net::AllSupportedVersions();
if (FLAGS_quic_version != -1) {
versions.clear();
versions.push_back(static_cast<net::QuicVersion>(FLAGS_quic_version));
@@ -254,11 +253,12 @@ int main(int argc, char* argv[]) {
new TransportSecurityState);
std::unique_ptr<CTVerifier> ct_verifier(new MultiLogCTVerifier());
std::unique_ptr<CTPolicyEnforcer> ct_policy_enforcer(new CTPolicyEnforcer());
- ProofVerifierChromium* proof_verifier = new ProofVerifierChromium(
- cert_verifier.get(), ct_policy_enforcer.get(),
- transport_security_state.get(), ct_verifier.get());
+ std::unique_ptr<ProofVerifierChromium> proof_verifier(
+ new ProofVerifierChromium(cert_verifier.get(), ct_policy_enforcer.get(),
+ transport_security_state.get(),
+ ct_verifier.get()));
net::QuicSimpleClient client(net::IPEndPoint(ip_addr, port), server_id,
- versions, proof_verifier);
+ versions, std::move(proof_verifier));
client.set_initial_max_packet_length(
FLAGS_initial_mtu != 0 ? FLAGS_initial_mtu : net::kDefaultMaxPacketSize);
if (!client.Initialize()) {
@@ -316,9 +316,8 @@ int main(int argc, char* argv[]) {
// Send the request.
net::SpdyHeaderBlock header_block;
net::CreateSpdyHeadersFromHttpRequest(request, request.extra_headers,
- net::HTTP2, /*direct=*/true,
- &header_block);
- client.SendRequestAndWaitForResponse(request, body, /*fin=*/true);
+ /*direct=*/true, &header_block);
+ client.SendRequestAndWaitForResponse(header_block, body, /*fin=*/true);
// Print request and response details.
if (!FLAGS_quiet) {
@@ -326,9 +325,8 @@ int main(int argc, char* argv[]) {
cout << "headers:" << header_block.DebugString();
if (!FLAGS_body_hex.empty()) {
// Print the user provided hex, rather than binary body.
- cout << "body hex: " << FLAGS_body_hex << endl;
- cout << "body ascii: " << net::QuicUtils::BinaryToAscii(
- net::QuicUtils::HexDecode(FLAGS_body_hex))
+ cout << "body:\n"
+ << net::QuicUtils::HexDump(net::QuicUtils::HexDecode(FLAGS_body_hex))
<< endl;
} else {
cout << "body: " << body << endl;
@@ -339,10 +337,7 @@ int main(int argc, char* argv[]) {
string response_body = client.latest_response_body();
if (!FLAGS_body_hex.empty()) {
// Assume response is binary data.
- cout << "body hex: " << net::QuicUtils::HexEncode(response_body)
- << endl;
- cout << "body ascii: " << net::QuicUtils::BinaryToAscii(response_body)
- << endl;
+ cout << "body:\n" << net::QuicUtils::HexDump(response_body) << endl;
} else {
cout << "body: " << response_body << endl;
}
diff --git a/chromium/net/tools/quic/quic_simple_client_test.cc b/chromium/net/tools/quic/quic_simple_client_test.cc
index 02a5807b683..0a571a797b7 100644
--- a/chromium/net/tools/quic/quic_simple_client_test.cc
+++ b/chromium/net/tools/quic/quic_simple_client_test.cc
@@ -18,7 +18,7 @@ TEST(QuicSimpleClientTest, Initialize) {
IPEndPoint server_address(IPEndPoint(net::test::Loopback4(), 80));
QuicServerId server_id("hostname", server_address.port(),
PRIVACY_MODE_DISABLED);
- QuicVersionVector versions = QuicSupportedVersions();
+ QuicVersionVector versions = AllSupportedVersions();
QuicSimpleClient client(server_address, server_id, versions,
CryptoTestUtils::ProofVerifierForTesting());
EXPECT_TRUE(client.Initialize());
diff --git a/chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.cc b/chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.cc
new file mode 100644
index 00000000000..9f2870ac9a7
--- /dev/null
+++ b/chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.cc
@@ -0,0 +1,28 @@
+// 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/tools/quic/quic_simple_crypto_server_stream_helper.h"
+
+namespace net {
+
+QuicSimpleCryptoServerStreamHelper::QuicSimpleCryptoServerStreamHelper(
+ QuicRandom* random)
+ : random_(random) {}
+
+QuicSimpleCryptoServerStreamHelper::~QuicSimpleCryptoServerStreamHelper() {}
+
+QuicConnectionId
+ QuicSimpleCryptoServerStreamHelper::GenerateConnectionIdForReject(
+ QuicConnectionId /*connection_id*/) const {
+ return random_->RandUint64();
+}
+
+bool QuicSimpleCryptoServerStreamHelper::CanAcceptClientHello(
+ const CryptoHandshakeMessage& message,
+ const IPEndPoint& self_address,
+ std::string* error_details) const {
+ return true;
+}
+
+} // namespace net
diff --git a/chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.h b/chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.h
new file mode 100644
index 00000000000..5402a21fc7a
--- /dev/null
+++ b/chromium/net/tools/quic/quic_simple_crypto_server_stream_helper.h
@@ -0,0 +1,35 @@
+// 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.
+
+#ifndef NET_QUIC_TOOLS_QUIC_SIMPLE_CRYPTO_SERVER_STREAM_HELPER_H_
+#define NET_QUIC_TOOLS_QUIC_SIMPLE_CRYPTO_SERVER_STREAM_HELPER_H_
+
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_crypto_server_stream.h"
+
+namespace net {
+
+// Simple helper for server crypto streams which generates a new random
+// connection ID for stateless rejects.
+class QuicSimpleCryptoServerStreamHelper
+ : public QuicCryptoServerStream::Helper {
+ public:
+ explicit QuicSimpleCryptoServerStreamHelper(QuicRandom* random);
+
+ ~QuicSimpleCryptoServerStreamHelper() override;
+
+ QuicConnectionId GenerateConnectionIdForReject(
+ QuicConnectionId /*connection_id*/) const override;
+
+ bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
+ const IPEndPoint& self_address,
+ std::string* error_details) const override;
+
+ private:
+ QuicRandom* random_; // Unowned.
+};
+
+} // namespace net
+
+#endif // NET_QUIC_TOOLS_QUIC_SIMPLE_CRYPTO_SERVER_STREAM_HELPER_H_
diff --git a/chromium/net/tools/quic/quic_simple_dispatcher.cc b/chromium/net/tools/quic/quic_simple_dispatcher.cc
new file mode 100644
index 00000000000..bcad0565cea
--- /dev/null
+++ b/chromium/net/tools/quic/quic_simple_dispatcher.cc
@@ -0,0 +1,43 @@
+// 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/tools/quic/quic_simple_dispatcher.h"
+
+#include "net/tools/quic/quic_simple_server_session.h"
+
+namespace net {
+
+QuicSimpleDispatcher::QuicSimpleDispatcher(
+ const QuicConfig& config,
+ const QuicCryptoServerConfig* crypto_config,
+ QuicVersionManager* version_manager,
+ std::unique_ptr<QuicConnectionHelperInterface> helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
+ std::unique_ptr<QuicAlarmFactory> alarm_factory)
+ : QuicDispatcher(config,
+ crypto_config,
+ version_manager,
+ std::move(helper),
+ std::move(session_helper),
+ std::move(alarm_factory)) {}
+
+QuicSimpleDispatcher::~QuicSimpleDispatcher() {}
+
+QuicServerSessionBase* QuicSimpleDispatcher::CreateQuicSession(
+ QuicConnectionId connection_id,
+ const IPEndPoint& client_address) {
+ // 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, GetSupportedVersions());
+
+ QuicServerSessionBase* session =
+ new QuicSimpleServerSession(config(), connection, this, session_helper(),
+ crypto_config(), compressed_certs_cache());
+ session->Initialize();
+ return session;
+}
+
+} // namespace net
diff --git a/chromium/net/tools/quic/quic_simple_dispatcher.h b/chromium/net/tools/quic/quic_simple_dispatcher.h
new file mode 100644
index 00000000000..15b6b3c09de
--- /dev/null
+++ b/chromium/net/tools/quic/quic_simple_dispatcher.h
@@ -0,0 +1,32 @@
+// 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.
+
+#ifndef NET_TOOLS_QUIC_QUIC_SIMPLE_DISPATCHER_H_
+#define NET_TOOLS_QUIC_QUIC_SIMPLE_DISPATCHER_H_
+
+#include "net/tools/quic/quic_dispatcher.h"
+
+namespace net {
+
+class QuicSimpleDispatcher : public QuicDispatcher {
+ public:
+ QuicSimpleDispatcher(
+ const QuicConfig& config,
+ const QuicCryptoServerConfig* crypto_config,
+ QuicVersionManager* version_manager,
+ std::unique_ptr<QuicConnectionHelperInterface> helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
+ std::unique_ptr<QuicAlarmFactory> alarm_factory);
+
+ ~QuicSimpleDispatcher() override;
+
+ protected:
+ QuicServerSessionBase* CreateQuicSession(
+ QuicConnectionId connection_id,
+ const IPEndPoint& client_address) override;
+};
+
+} // namespace net
+
+#endif // NET_TOOLS_QUIC_QUIC_SIMPLE_DISPATCHER_H_
diff --git a/chromium/net/tools/quic/quic_simple_per_connection_packet_writer.h b/chromium/net/tools/quic/quic_simple_per_connection_packet_writer.h
index d1d4881efb3..c5a62bdc452 100644
--- a/chromium/net/tools/quic/quic_simple_per_connection_packet_writer.h
+++ b/chromium/net/tools/quic/quic_simple_per_connection_packet_writer.h
@@ -9,8 +9,8 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_packet_writer.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_packet_writer.h"
namespace net {
diff --git a/chromium/net/tools/quic/quic_simple_server.cc b/chromium/net/tools/quic/quic_simple_server.cc
index 814feabd87e..4848cdd901c 100644
--- a/chromium/net/tools/quic/quic_simple_server.cc
+++ b/chromium/net/tools/quic/quic_simple_server.cc
@@ -11,12 +11,13 @@
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_crypto_stream.h"
-#include "net/quic/quic_data_reader.h"
-#include "net/quic/quic_protocol.h"
-#include "net/tools/quic/quic_dispatcher.h"
+#include "net/log/net_log_source.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_crypto_stream.h"
+#include "net/quic/core/quic_data_reader.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/tools/quic/quic_simple_dispatcher.h"
#include "net/tools/quic/quic_simple_per_connection_packet_writer.h"
#include "net/tools/quic/quic_simple_server_packet_writer.h"
#include "net/tools/quic/quic_simple_server_session_helper.h"
@@ -27,60 +28,30 @@ namespace net {
namespace {
const char kSourceAddressTokenSecret[] = "secret";
+const size_t kNumSessionsToCreatePerSocketEvent = 16;
// Allocate some extra space so we can send an error if the client goes over
// the limit.
const int kReadBufferSize = 2 * kMaxPacketSize;
-class SimpleQuicDispatcher : public QuicDispatcher {
- public:
- SimpleQuicDispatcher(const QuicConfig& config,
- const QuicCryptoServerConfig* crypto_config,
- const QuicVersionVector& supported_versions,
- QuicConnectionHelperInterface* helper,
- QuicAlarmFactory* alarm_factory)
- : QuicDispatcher(
- config,
- crypto_config,
- supported_versions,
- std::unique_ptr<QuicConnectionHelperInterface>(helper),
- std::unique_ptr<QuicServerSessionBase::Helper>(
- new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
- std::unique_ptr<QuicAlarmFactory>(alarm_factory)) {}
-
- protected:
- QuicServerSessionBase* CreateQuicSession(
- QuicConnectionId connection_id,
- const IPEndPoint& client_address) override {
- QuicServerSessionBase* session =
- QuicDispatcher::CreateQuicSession(connection_id, client_address);
- static_cast<QuicSimplePerConnectionPacketWriter*>(
- session->connection()->writer())
- ->set_connection(session->connection());
- return session;
- }
-
- QuicPacketWriter* CreatePerConnectionWriter() override {
- return new QuicSimplePerConnectionPacketWriter(
- static_cast<QuicSimpleServerPacketWriter*>(writer()));
- }
-};
-
} // namespace
-QuicSimpleServer::QuicSimpleServer(ProofSource* proof_source,
- const QuicConfig& config,
- const QuicVersionVector& supported_versions)
- : helper_(
+QuicSimpleServer::QuicSimpleServer(
+ std::unique_ptr<ProofSource> proof_source,
+ const QuicConfig& config,
+ const QuicCryptoServerConfig::ConfigOptions& crypto_config_options,
+ const QuicVersionVector& supported_versions)
+ : version_manager_(supported_versions),
+ helper_(
new QuicChromiumConnectionHelper(&clock_, QuicRandom::GetInstance())),
alarm_factory_(new QuicChromiumAlarmFactory(
base::ThreadTaskRunnerHandle::Get().get(),
&clock_)),
config_(config),
+ crypto_config_options_(crypto_config_options),
crypto_config_(kSourceAddressTokenSecret,
QuicRandom::GetInstance(),
- proof_source),
- supported_versions_(supported_versions),
+ std::move(proof_source)),
read_pending_(false),
synchronous_read_count_(0),
read_buffer_(new IOBufferWithSize(kReadBufferSize)),
@@ -110,14 +81,14 @@ void QuicSimpleServer::Initialize() {
std::unique_ptr<CryptoHandshakeMessage> scfg(crypto_config_.AddDefaultConfig(
helper_->GetRandomGenerator(), helper_->GetClock(),
- QuicCryptoServerConfig::ConfigOptions()));
+ crypto_config_options_));
}
QuicSimpleServer::~QuicSimpleServer() {}
int QuicSimpleServer::Listen(const IPEndPoint& address) {
std::unique_ptr<UDPServerSocket> socket(
- new UDPServerSocket(&net_log_, NetLog::Source()));
+ new UDPServerSocket(&net_log_, NetLogSource()));
socket->AllowAddressReuse();
@@ -153,8 +124,12 @@ int QuicSimpleServer::Listen(const IPEndPoint& address) {
socket_.swap(socket);
- dispatcher_.reset(new SimpleQuicDispatcher(
- config_, &crypto_config_, supported_versions_, helper_, alarm_factory_));
+ dispatcher_.reset(new QuicSimpleDispatcher(
+ config_, &crypto_config_, &version_manager_,
+ std::unique_ptr<QuicConnectionHelperInterface>(helper_),
+ std::unique_ptr<QuicCryptoServerStream::Helper>(
+ new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
+ std::unique_ptr<QuicAlarmFactory>(alarm_factory_)));
QuicSimpleServerPacketWriter* writer =
new QuicSimpleServerPacketWriter(socket_.get(), dispatcher_.get());
dispatcher_->InitializeWithWriter(writer);
@@ -174,6 +149,11 @@ void QuicSimpleServer::Shutdown() {
}
void QuicSimpleServer::StartReading() {
+ if (synchronous_read_count_ == 0) {
+ // Only process buffered packets once per message loop.
+ dispatcher_->ProcessBufferedChlos(kNumSessionsToCreatePerSocketEvent);
+ }
+
if (read_pending_) {
return;
}
@@ -185,6 +165,12 @@ void QuicSimpleServer::StartReading() {
if (result == ERR_IO_PENDING) {
synchronous_read_count_ = 0;
+ if (dispatcher_->HasChlosBuffered()) {
+ // No more packets to read, so yield before processing buffered packets.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&QuicSimpleServer::StartReading,
+ weak_factory_.GetWeakPtr()));
+ }
return;
}
diff --git a/chromium/net/tools/quic/quic_simple_server.h b/chromium/net/tools/quic/quic_simple_server.h
index 7fe28a424a9..4b24d9cef73 100644
--- a/chromium/net/tools/quic/quic_simple_server.h
+++ b/chromium/net/tools/quic/quic_simple_server.h
@@ -14,11 +14,11 @@
#include "net/base/io_buffer.h"
#include "net/base/ip_endpoint.h"
#include "net/log/net_log.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/quic_chromium_alarm_factory.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_config.h"
+#include "net/quic/chromium/quic_chromium_alarm_factory.h"
+#include "net/quic/chromium/quic_chromium_connection_helper.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_config.h"
namespace net {
@@ -33,9 +33,11 @@ class QuicSimpleServerPeer;
class QuicSimpleServer {
public:
- QuicSimpleServer(ProofSource* proof_source,
- const QuicConfig& config,
- const QuicVersionVector& supported_versions);
+ QuicSimpleServer(
+ std::unique_ptr<ProofSource> proof_source,
+ const QuicConfig& config,
+ const QuicCryptoServerConfig::ConfigOptions& crypto_config_options,
+ const QuicVersionVector& supported_versions);
virtual ~QuicSimpleServer();
@@ -59,12 +61,16 @@ class QuicSimpleServer {
QuicDispatcher* dispatcher() { return dispatcher_.get(); }
+ IPEndPoint server_address() const { return server_address_; }
+
private:
friend class test::QuicSimpleServerPeer;
// Initialize the internal state of the server.
void Initialize();
+ QuicVersionManager version_manager_;
+
// Accepts data from the framer and demuxes clients to sessions.
std::unique_ptr<QuicDispatcher> dispatcher_;
@@ -83,15 +89,12 @@ class QuicSimpleServer {
// config_ contains non-crypto parameters that are negotiated in the crypto
// handshake.
QuicConfig config_;
+ // crypto_config_ contains crypto parameters that are negotiated in the crypto
+ // handshake.
+ QuicCryptoServerConfig::ConfigOptions crypto_config_options_;
// crypto_config_ contains crypto parameters for the handshake.
QuicCryptoServerConfig crypto_config_;
- // 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).
- QuicVersionVector supported_versions_;
-
// The address that the server listens on.
IPEndPoint server_address_;
diff --git a/chromium/net/tools/quic/quic_simple_server_bin.cc b/chromium/net/tools/quic/quic_simple_server_bin.cc
index b04bf15bce3..9187c9957dc 100644
--- a/chromium/net/tools/quic/quic_simple_server_bin.cc
+++ b/chromium/net/tools/quic/quic_simple_server_bin.cc
@@ -14,19 +14,21 @@
#include "base/strings/string_number_conversions.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/crypto/proof_source_chromium.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/chromium/crypto/proof_source_chromium.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_in_memory_cache.h"
#include "net/tools/quic/quic_simple_server.h"
// The port the quic server will listen on.
int32_t FLAGS_port = 6121;
-net::ProofSource* CreateProofSource(const base::FilePath& cert_path,
- const base::FilePath& key_path) {
- net::ProofSourceChromium* proof_source = new net::ProofSourceChromium();
+std::unique_ptr<net::ProofSource> CreateProofSource(
+ const base::FilePath& cert_path,
+ const base::FilePath& key_path) {
+ std::unique_ptr<net::ProofSourceChromium> proof_source(
+ new net::ProofSourceChromium());
CHECK(proof_source->Initialize(cert_path, key_path, base::FilePath()));
- return proof_source;
+ return std::move(proof_source);
}
int main(int argc, char* argv[]) {
@@ -83,7 +85,8 @@ int main(int argc, char* argv[]) {
net::QuicSimpleServer server(
CreateProofSource(line->GetSwitchValuePath("certificate_file"),
line->GetSwitchValuePath("key_file")),
- config, net::QuicSupportedVersions());
+ config, net::QuicCryptoServerConfig::ConfigOptions(),
+ net::AllSupportedVersions());
server.SetStrikeRegisterNoStartupPeriod();
int rc = server.Listen(net::IPEndPoint(ip, FLAGS_port));
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 7d64b316e23..a145086d782 100644
--- a/chromium/net/tools/quic/quic_simple_server_packet_writer.cc
+++ b/chromium/net/tools/quic/quic_simple_server_packet_writer.cc
@@ -45,7 +45,9 @@ void QuicSimpleServerPacketWriter::OnWriteComplete(int rv) {
DCHECK_NE(rv, ERR_IO_PENDING);
write_blocked_ = false;
WriteResult result(rv < 0 ? WRITE_STATUS_ERROR : WRITE_STATUS_OK, rv);
- base::ResetAndReturn(&callback_).Run(result);
+ if (!callback_.is_null()) {
+ base::ResetAndReturn(&callback_).Run(result);
+ }
blocked_writer_->OnCanWrite();
}
@@ -71,7 +73,6 @@ WriteResult QuicSimpleServerPacketWriter::WritePacket(
scoped_refptr<StringIOBuffer> buf(
new StringIOBuffer(std::string(buffer, buf_len)));
DCHECK(!IsWriteBlocked());
- DCHECK(!callback_.is_null());
int rv;
if (buf_len <= static_cast<size_t>(std::numeric_limits<int>::max())) {
rv = socket_->SendTo(
diff --git a/chromium/net/tools/quic/quic_simple_server_packet_writer.h b/chromium/net/tools/quic/quic_simple_server_packet_writer.h
index 3a6b562d639..d4cc814eadf 100644
--- a/chromium/net/tools/quic/quic_simple_server_packet_writer.h
+++ b/chromium/net/tools/quic/quic_simple_server_packet_writer.h
@@ -11,9 +11,9 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
@@ -33,15 +33,19 @@ class QuicSimpleServerPacketWriter : public QuicPacketWriter {
QuicBlockedWriterInterface* blocked_writer);
~QuicSimpleServerPacketWriter() override;
- // Use this method to write packets rather than WritePacket:
- // QuicSimpleServerPacketWriter requires a callback to exist for every
- // write, which will be called once the write completes.
- virtual WriteResult WritePacketWithCallback(const char* buffer,
- size_t buf_len,
- const IPAddress& self_address,
- const IPEndPoint& peer_address,
- PerPacketOptions* options,
- WriteCallback callback);
+ // Wraps WritePacket, and ensures that |callback| is run on successful write.
+ WriteResult WritePacketWithCallback(const char* buffer,
+ size_t buf_len,
+ const IPAddress& self_address,
+ const IPEndPoint& peer_address,
+ PerPacketOptions* options,
+ WriteCallback callback);
+
+ WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const IPAddress& self_address,
+ const IPEndPoint& peer_address,
+ PerPacketOptions* options) override;
void OnWriteComplete(int rv);
@@ -51,14 +55,6 @@ class QuicSimpleServerPacketWriter : public QuicPacketWriter {
void SetWritable() override;
QuicByteCount GetMaxPacketSize(const IPEndPoint& peer_address) const override;
- protected:
- // Do not call WritePacket on its own -- use WritePacketWithCallback
- WriteResult WritePacket(const char* buffer,
- size_t buf_len,
- const IPAddress& self_address,
- const IPEndPoint& peer_address,
- PerPacketOptions* options) override;
-
private:
UDPServerSocket* socket_;
diff --git a/chromium/net/tools/quic/quic_simple_server_session.cc b/chromium/net/tools/quic/quic_simple_server_session.cc
index 3db89a4cafe..64d987bacdf 100644
--- a/chromium/net/tools/quic/quic_simple_server_session.cc
+++ b/chromium/net/tools/quic/quic_simple_server_session.cc
@@ -8,11 +8,11 @@
#include "base/logging.h"
#include "base/stl_util.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_spdy_session.h"
-#include "net/quic/reliable_quic_stream.h"
+#include "net/quic/core/proto/cached_network_parameters.pb.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_spdy_session.h"
+#include "net/quic/core/reliable_quic_stream.h"
#include "net/tools/quic/quic_simple_server_stream.h"
#include "url/gurl.h"
@@ -24,7 +24,7 @@ QuicSimpleServerSession::QuicSimpleServerSession(
const QuicConfig& config,
QuicConnection* connection,
QuicServerSessionBase::Visitor* visitor,
- QuicServerSessionBase::Helper* helper,
+ QuicCryptoServerStream::Helper* helper,
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache)
: QuicServerSessionBase(config,
@@ -35,7 +35,9 @@ QuicSimpleServerSession::QuicSimpleServerSession(
compressed_certs_cache),
highest_promised_stream_id_(0) {}
-QuicSimpleServerSession::~QuicSimpleServerSession() {}
+QuicSimpleServerSession::~QuicSimpleServerSession() {
+ delete connection();
+}
QuicCryptoServerStreamBase*
QuicSimpleServerSession::CreateQuicCryptoServerStream(
@@ -43,7 +45,7 @@ QuicSimpleServerSession::CreateQuicCryptoServerStream(
QuicCompressedCertsCache* compressed_certs_cache) {
return new QuicCryptoServerStream(crypto_config, compressed_certs_cache,
FLAGS_enable_quic_stateless_reject_support,
- this);
+ this, stream_helper());
}
void QuicSimpleServerSession::StreamDraining(QuicStreamId id) {
@@ -175,7 +177,7 @@ void QuicSimpleServerSession::SendPushPromise(QuicStreamId original_stream_id,
DVLOG(1) << "stream " << original_stream_id
<< " send PUSH_PROMISE for promised stream " << promised_stream_id;
headers_stream()->WritePushPromise(original_stream_id, promised_stream_id,
- std::move(headers), nullptr);
+ std::move(headers));
}
void QuicSimpleServerSession::HandlePromisedPushRequests() {
diff --git a/chromium/net/tools/quic/quic_simple_server_session.h b/chromium/net/tools/quic/quic_simple_server_session.h
index fe806a43463..16ebdfb22fd 100644
--- a/chromium/net/tools/quic/quic_simple_server_session.h
+++ b/chromium/net/tools/quic/quic_simple_server_session.h
@@ -18,10 +18,10 @@
#include <vector>
#include "base/macros.h"
-#include "net/quic/quic_crypto_server_stream.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_session_base.h"
-#include "net/quic/quic_spdy_session.h"
+#include "net/quic/core/quic_crypto_server_stream.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_session_base.h"
+#include "net/quic/core/quic_spdy_session.h"
#include "net/tools/quic/quic_in_memory_cache.h"
#include "net/tools/quic/quic_simple_server_stream.h"
@@ -58,10 +58,11 @@ class QuicSimpleServerSession : public QuicServerSessionBase {
bool is_cancelled;
};
+ // Takes ownership of |connection|.
QuicSimpleServerSession(const QuicConfig& config,
QuicConnection* connection,
QuicServerSessionBase::Visitor* visitor,
- QuicServerSessionBase::Helper* helper,
+ QuicCryptoServerStream::Helper* helper,
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache);
diff --git a/chromium/net/tools/quic/quic_simple_server_session_helper.h b/chromium/net/tools/quic/quic_simple_server_session_helper.h
index 6ef33fa8d11..a876983b758 100644
--- a/chromium/net/tools/quic/quic_simple_server_session_helper.h
+++ b/chromium/net/tools/quic/quic_simple_server_session_helper.h
@@ -5,14 +5,14 @@
#ifndef NET_TOOLS_QUIC_QUIC_SIMPLE_SERVER_SESSION_HELPER_H_
#define NET_TOOLS_QUIC_QUIC_SIMPLE_SERVER_SESSION_HELPER_H_
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_server_session_base.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_server_session_base.h"
namespace net {
// Simple helper for server sessions which generates a new random
// connection ID for stateless rejects.
-class QuicSimpleServerSessionHelper : public QuicServerSessionBase::Helper {
+class QuicSimpleServerSessionHelper : public QuicCryptoServerStream::Helper {
public:
explicit QuicSimpleServerSessionHelper(QuicRandom* random);
diff --git a/chromium/net/tools/quic/quic_simple_server_session_helper_test.cc b/chromium/net/tools/quic/quic_simple_server_session_helper_test.cc
index e739ada62da..c25c60e54a8 100644
--- a/chromium/net/tools/quic/quic_simple_server_session_helper_test.cc
+++ b/chromium/net/tools/quic/quic_simple_server_session_helper_test.cc
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/tools/quic/quic_simple_server_session_helper.h"
-
#include "net/quic/test_tools/mock_random.h"
+#include "net/tools/quic/quic_simple_crypto_server_stream_helper.h"
+
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
-TEST(QuicSimpleServerSessionHelperTest, GenerateConnectionIdForReject) {
+TEST(QuicSimpleCryptoServerStreamHelperTest, GenerateConnectionIdForReject) {
test::MockRandom random;
- QuicSimpleServerSessionHelper helper(&random);
+ QuicSimpleCryptoServerStreamHelper helper(&random);
EXPECT_EQ(random.RandUint64(), helper.GenerateConnectionIdForReject(42));
}
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 8e93f9bb37f..518ce1da058 100644
--- a/chromium/net/tools/quic/quic_simple_server_session_test.cc
+++ b/chromium/net/tools/quic/quic_simple_server_session_test.cc
@@ -9,12 +9,12 @@
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_crypto_server_stream.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/proto/cached_network_parameters.pb.h"
+#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/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_config_peer.h"
#include "net/quic/test_tools/quic_connection_peer.h"
@@ -43,7 +43,6 @@ using net::test::QuicSessionPeer;
using net::test::QuicSpdySessionPeer;
using net::test::QuicSustainedBandwidthRecorderPeer;
using net::test::SupportedVersions;
-using net::test::ValueRestore;
using net::test::kClientDataStreamId1;
using net::test::kClientDataStreamId2;
using net::test::kClientDataStreamId3;
@@ -54,6 +53,7 @@ using testing::StrictMock;
using testing::_;
using testing::InSequence;
using testing::Return;
+using testing::AtLeast;
namespace net {
namespace test {
@@ -70,16 +70,14 @@ class MockQuicHeadersStream : public QuicHeadersStream {
// mocked directly.
size_t WritePushPromise(QuicStreamId original_stream_id,
QuicStreamId promised_stream_id,
- SpdyHeaderBlock headers,
- QuicAckListenerInterface* ack_listener) override {
- return WritePushPromiseMock(original_stream_id, promised_stream_id, headers,
- ack_listener);
+ SpdyHeaderBlock headers) override {
+ return WritePushPromiseMock(original_stream_id, promised_stream_id,
+ headers);
}
- MOCK_METHOD4(WritePushPromiseMock,
+ MOCK_METHOD3(WritePushPromiseMock,
size_t(QuicStreamId original_stream_id,
QuicStreamId promised_stream_id,
- const SpdyHeaderBlock& headers,
- QuicAckListenerInterface* ack_listener));
+ const SpdyHeaderBlock& headers));
size_t WriteHeaders(QuicStreamId stream_id,
SpdyHeaderBlock headers,
@@ -101,11 +99,13 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream {
explicit MockQuicCryptoServerStream(
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache,
- QuicServerSessionBase* session)
+ QuicServerSessionBase* session,
+ QuicCryptoServerStream::Helper* helper)
: QuicCryptoServerStream(crypto_config,
compressed_certs_cache,
FLAGS_enable_quic_stateless_reject_support,
- session) {}
+ session,
+ helper) {}
~MockQuicCryptoServerStream() override {}
MOCK_METHOD1(SendServerConfigUpdate,
@@ -181,7 +181,6 @@ class QuicSimpleServerSessionTest
CryptoTestUtils::ProofSourceForTesting()),
compressed_certs_cache_(
QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) {
- FLAGS_quic_always_log_bugs_for_tests = true;
config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, kMaxStreamsForTest);
config_.SetMaxIncomingDynamicStreamsToSend(kMaxStreamsForTest);
QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams(&config_,
@@ -194,9 +193,9 @@ class QuicSimpleServerSessionTest
connection_ = new StrictMock<MockQuicConnectionWithSendStreamData>(
&helper_, &alarm_factory_, Perspective::IS_SERVER,
SupportedVersions(GetParam()));
- session_.reset(new QuicSimpleServerSession(
- config_, connection_, &owner_, &session_helper_, &crypto_config_,
- &compressed_certs_cache_));
+ session_.reset(new QuicSimpleServerSession(config_, connection_, &owner_,
+ &stream_helper_, &crypto_config_,
+ &compressed_certs_cache_));
MockClock clock;
handshake_message_.reset(crypto_config_.AddDefaultConfig(
QuicRandom::GetInstance(), &clock,
@@ -205,14 +204,13 @@ class QuicSimpleServerSessionTest
visitor_ = QuicConnectionPeer::GetVisitor(connection_);
headers_stream_ = new MockQuicHeadersStream(session_.get());
QuicSpdySessionPeer::SetHeadersStream(session_.get(), headers_stream_);
- // TODO(jri): Remove this line once tests pass.
- FLAGS_quic_cede_correctly = false;
session_->OnConfigNegotiated();
}
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
StrictMock<MockQuicServerSessionVisitor> owner_;
- StrictMock<MockQuicServerSessionHelper> session_helper_;
+ StrictMock<MockQuicCryptoServerStreamHelper> stream_helper_;
MockQuicConnectionHelper helper_;
MockAlarmFactory alarm_factory_;
StrictMock<MockQuicConnectionWithSendStreamData>* connection_;
@@ -227,7 +225,7 @@ class QuicSimpleServerSessionTest
INSTANTIATE_TEST_CASE_P(Tests,
QuicSimpleServerSessionTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicSimpleServerSessionTest, CloseStreamDueToReset) {
// Open a stream, then reset it.
@@ -302,9 +300,9 @@ TEST_P(QuicSimpleServerSessionTest, CreateIncomingDynamicStreamDisconnected) {
// Tests that incoming stream creation fails when connection is not connected.
size_t initial_num_open_stream = session_->GetNumOpenIncomingStreams();
QuicConnectionPeer::TearDownLocalConnectionState(connection_);
- EXPECT_DFATAL(QuicSimpleServerSessionPeer::CreateIncomingDynamicStream(
- session_.get(), kClientDataStreamId1),
- "ShouldCreateIncomingDynamicStream called when disconnected");
+ EXPECT_QUIC_BUG(QuicSimpleServerSessionPeer::CreateIncomingDynamicStream(
+ session_.get(), kClientDataStreamId1),
+ "ShouldCreateIncomingDynamicStream called when disconnected");
EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenIncomingStreams());
}
@@ -330,9 +328,9 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamDisconnected) {
// Tests that outgoing stream creation fails when connection is not connected.
size_t initial_num_open_stream = session_->GetNumOpenOutgoingStreams();
QuicConnectionPeer::TearDownLocalConnectionState(connection_);
- EXPECT_DFATAL(QuicSimpleServerSessionPeer::CreateOutgoingDynamicStream(
- session_.get(), kDefaultPriority),
- "ShouldCreateOutgoingDynamicStream called when disconnected");
+ EXPECT_QUIC_BUG(QuicSimpleServerSessionPeer::CreateOutgoingDynamicStream(
+ session_.get(), kDefaultPriority),
+ "ShouldCreateOutgoingDynamicStream called when disconnected");
EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenOutgoingStreams());
}
@@ -341,9 +339,9 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUnencrypted) {
// Tests that outgoing stream creation fails when encryption has not yet been
// established.
size_t initial_num_open_stream = session_->GetNumOpenOutgoingStreams();
- EXPECT_DFATAL(QuicSimpleServerSessionPeer::CreateOutgoingDynamicStream(
- session_.get(), kDefaultPriority),
- "Encryption not established so no outgoing stream created.");
+ EXPECT_QUIC_BUG(QuicSimpleServerSessionPeer::CreateOutgoingDynamicStream(
+ session_.get(), kDefaultPriority),
+ "Encryption not established so no outgoing stream created.");
EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenOutgoingStreams());
}
@@ -360,8 +358,9 @@ TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUptoLimit) {
EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams());
// Assume encryption already established.
- MockQuicCryptoServerStream* crypto_stream = new MockQuicCryptoServerStream(
- &crypto_config_, &compressed_certs_cache_, session_.get());
+ MockQuicCryptoServerStream* crypto_stream =
+ new MockQuicCryptoServerStream(&crypto_config_, &compressed_certs_cache_,
+ session_.get(), &stream_helper_);
crypto_stream->set_encryption_established(true);
QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream);
@@ -434,9 +433,9 @@ class QuicSimpleServerSessionServerPushTest
connection_ = new StrictMock<MockQuicConnectionWithSendStreamData>(
&helper_, &alarm_factory_, Perspective::IS_SERVER,
SupportedVersions(GetParam()));
- session_.reset(new QuicSimpleServerSession(
- config_, connection_, &owner_, &session_helper_, &crypto_config_,
- &compressed_certs_cache_));
+ session_.reset(new QuicSimpleServerSession(config_, connection_, &owner_,
+ &stream_helper_, &crypto_config_,
+ &compressed_certs_cache_));
session_->Initialize();
// Needed to make new session flow control window and server push work.
session_->OnConfigNegotiated();
@@ -447,7 +446,9 @@ class QuicSimpleServerSessionServerPushTest
// Assume encryption already established.
MockQuicCryptoServerStream* crypto_stream = new MockQuicCryptoServerStream(
- &crypto_config_, &compressed_certs_cache_, session_.get());
+ &crypto_config_, &compressed_certs_cache_, session_.get(),
+ &stream_helper_);
+
crypto_stream->set_encryption_established(true);
QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream);
}
@@ -483,9 +484,8 @@ class QuicSimpleServerSessionServerPushTest
push_resources.push_back(QuicInMemoryCache::ServerPushInfo(
resource_url, SpdyHeaderBlock(), kDefaultPriority, body));
// PUSH_PROMISED are sent for all the resources.
- EXPECT_CALL(
- *headers_stream_,
- WritePushPromiseMock(kClientDataStreamId1, stream_id, _, nullptr));
+ EXPECT_CALL(*headers_stream_,
+ WritePushPromiseMock(kClientDataStreamId1, stream_id, _));
if (i <= kMaxStreamsForTest) {
// |kMaxStreamsForTest| promised responses should be sent.
EXPECT_CALL(
@@ -493,11 +493,25 @@ class QuicSimpleServerSessionServerPushTest
WriteHeadersMock(stream_id, _, false, kDefaultPriority, nullptr));
// Since flow control window is smaller than response body, not the
// whole body will be sent.
- EXPECT_CALL(*connection_,
- SendStreamData(stream_id, _, 0, false, nullptr))
- .WillOnce(
- Return(QuicConsumedData(kStreamFlowControlWindowSize, false)));
- EXPECT_CALL(*connection_, SendBlocked(stream_id));
+ if (!session_->force_hol_blocking()) {
+ EXPECT_CALL(*connection_,
+ SendStreamData(stream_id, _, 0, false, nullptr))
+ .WillOnce(Return(
+ QuicConsumedData(kStreamFlowControlWindowSize, false)));
+ EXPECT_CALL(*connection_, SendBlocked(stream_id));
+ } else {
+ // The forced HOL blocking encapsulates the stream data into
+ // HTTP/2 DATA frames within the headers stream. HTTP/2
+ // DATA frames are limited to a max size of 16KB, so the
+ // 64KB body will be fragemented into four DATA frames.
+ EXPECT_CALL(*connection_, SendStreamData(_, _, _, false, nullptr))
+ .Times(body_size / 16384)
+ .WillOnce(Return(QuicConsumedData(9 + 16394, false)))
+ .WillOnce(Return(QuicConsumedData(9 + 16394, false)))
+ .WillOnce(Return(QuicConsumedData(9 + 16394, false)))
+ .WillOnce(Return(QuicConsumedData(9 + 16394, false)));
+ EXPECT_CALL(*connection_, SendBlocked(_));
+ }
}
}
session_->PromisePushResources(request_url, push_resources,
@@ -507,12 +521,16 @@ class QuicSimpleServerSessionServerPushTest
INSTANTIATE_TEST_CASE_P(Tests,
QuicSimpleServerSessionServerPushTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) {
// Tests that given more than kMaxOpenStreamForTest resources, all their
// PUSH_PROMISE's will be sent out and only |kMaxOpenStreamForTest| streams
// will be opened and send push response.
+
+ if (session_->force_hol_blocking()) {
+ return;
+ }
size_t num_resources = kMaxStreamsForTest + 5;
PromisePushResources(num_resources);
EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams());
@@ -520,6 +538,10 @@ TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) {
TEST_P(QuicSimpleServerSessionServerPushTest,
HandlePromisedPushRequestsAfterStreamDraining) {
+ if (session_->force_hol_blocking()) {
+ return;
+ }
+
// Tests that after promised stream queued up, when an opened stream is marked
// draining, a queued promised stream will become open and send push response.
size_t num_resources = kMaxStreamsForTest + 1;
@@ -543,6 +565,9 @@ TEST_P(QuicSimpleServerSessionServerPushTest,
TEST_P(QuicSimpleServerSessionServerPushTest,
ResetPromisedStreamToCancelServerPush) {
+ if (session_->force_hol_blocking()) {
+ return;
+ }
// Tests that after all resources are promised, a RST frame from client can
// prevent a promised resource to be send out.
@@ -579,6 +604,9 @@ TEST_P(QuicSimpleServerSessionServerPushTest,
TEST_P(QuicSimpleServerSessionServerPushTest,
CloseStreamToHandleMorePromisedStream) {
+ if (session_->force_hol_blocking()) {
+ return;
+ }
// Tests that closing a open outgoing stream can trigger a promised resource
// in the queue to be send out.
size_t num_resources = kMaxStreamsForTest + 1;
diff --git a/chromium/net/tools/quic/quic_simple_server_stream.cc b/chromium/net/tools/quic/quic_simple_server_stream.cc
index dda6a420d18..685955f3c61 100644
--- a/chromium/net/tools/quic/quic_simple_server_stream.cc
+++ b/chromium/net/tools/quic/quic_simple_server_stream.cc
@@ -12,10 +12,10 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_spdy_stream.h"
-#include "net/quic/spdy_utils.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_spdy_stream.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/spdy/spdy_protocol.h"
#include "net/tools/quic/quic_in_memory_cache.h"
#include "net/tools/quic/quic_simple_server_session.h"
@@ -136,8 +136,8 @@ void QuicSimpleServerStream::PushResponse(
}
void QuicSimpleServerStream::SendResponse() {
- if (!ContainsKey(request_headers_, ":authority") ||
- !ContainsKey(request_headers_, ":path")) {
+ if (!base::ContainsKey(request_headers_, ":authority") ||
+ !base::ContainsKey(request_headers_, ":path")) {
DVLOG(1) << "Request headers do not contain :authority or :path.";
SendErrorResponse();
return;
@@ -250,11 +250,13 @@ void QuicSimpleServerStream::SendHeadersAndBodyAndTrailers(
return;
}
- // Send the body, with a FIN if there's nothing else to send.
+ // Send the body, with a FIN if there's no trailers to send.
send_fin = response_trailers.empty();
DVLOG(1) << "Writing body (fin = " << send_fin
<< ") with size: " << body.size();
- WriteOrBufferData(body, send_fin, nullptr);
+ if (!body.empty() || send_fin) {
+ WriteOrBufferData(body, send_fin, nullptr);
+ }
if (send_fin) {
// Nothing else to send.
return;
diff --git a/chromium/net/tools/quic/quic_simple_server_stream.h b/chromium/net/tools/quic/quic_simple_server_stream.h
index e270ed65f17..7217ad3aef6 100644
--- a/chromium/net/tools/quic/quic_simple_server_stream.h
+++ b/chromium/net/tools/quic/quic_simple_server_stream.h
@@ -10,8 +10,8 @@
#include <string>
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_spdy_stream.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_spdy_stream.h"
#include "net/spdy/spdy_framer.h"
namespace net {
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 5161c9f223c..eddc1a08b1c 100644
--- a/chromium/net/tools/quic/quic_simple_server_stream_test.cc
+++ b/chromium/net/tools/quic/quic_simple_server_stream_test.cc
@@ -8,11 +8,11 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/spdy_utils.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/reliable_quic_stream_peer.h"
@@ -87,7 +87,7 @@ class MockQuicSimpleServerSession : public QuicSimpleServerSession {
explicit MockQuicSimpleServerSession(
QuicConnection* connection,
MockQuicServerSessionVisitor* owner,
- MockQuicServerSessionHelper* helper,
+ MockQuicCryptoServerStreamHelper* helper,
QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache)
: QuicSimpleServerSession(DefaultQuicConfig(),
@@ -190,7 +190,6 @@ class QuicSimpleServerStreamTest
crypto_config_.get(),
&compressed_certs_cache_),
body_("hello world") {
- FLAGS_quic_always_log_bugs_for_tests = true;
SpdyHeaderBlock request_headers;
request_headers[":host"] = "";
request_headers[":authority"] = "www.google.com";
@@ -233,7 +232,7 @@ class QuicSimpleServerStreamTest
MockAlarmFactory alarm_factory_;
StrictMock<MockQuicConnection>* connection_;
StrictMock<MockQuicServerSessionVisitor> session_owner_;
- StrictMock<MockQuicServerSessionHelper> session_helper_;
+ StrictMock<MockQuicCryptoServerStreamHelper> session_helper_;
std::unique_ptr<QuicCryptoServerConfig> crypto_config_;
QuicCompressedCertsCache compressed_certs_cache_;
StrictMock<MockQuicSimpleServerSession> session_;
@@ -244,7 +243,7 @@ class QuicSimpleServerStreamTest
INSTANTIATE_TEST_CASE_P(Tests,
QuicSimpleServerStreamTest,
- ::testing::ValuesIn(QuicSupportedVersions()));
+ ::testing::ValuesIn(AllSupportedVersions()));
TEST_P(QuicSimpleServerStreamTest, TestFraming) {
EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
@@ -286,11 +285,7 @@ TEST_P(QuicSimpleServerStreamTest, SendQuicRstStreamNoErrorInStopReading) {
stream_->set_fin_sent(true);
stream_->CloseWriteSide();
- if (GetParam() > QUIC_VERSION_28) {
- EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(1);
- } else {
- EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
- }
+ EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(1);
stream_->StopReading();
}
@@ -472,9 +467,9 @@ TEST_P(QuicSimpleServerStreamTest, SendReponseWithPushResources) {
TEST_P(QuicSimpleServerStreamTest, PushResponseOnClientInitiatedStream) {
// Calling PushResponse() on a client initialted stream is never supposed to
// happen.
- EXPECT_DFATAL(stream_->PushResponse(SpdyHeaderBlock()),
- "Client initiated stream"
- " shouldn't be used as promised stream.");
+ EXPECT_QUIC_BUG(stream_->PushResponse(SpdyHeaderBlock()),
+ "Client initiated stream"
+ " shouldn't be used as promised stream.");
}
TEST_P(QuicSimpleServerStreamTest, PushResponseOnServerInitiatedStream) {
@@ -601,11 +596,7 @@ TEST_P(QuicSimpleServerStreamTest, SendQuicRstStreamNoErrorWithEarlyResponse) {
EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
.Times(1)
.WillOnce(Return(QuicConsumedData(3, true)));
- if (GetParam() > QUIC_VERSION_28) {
- EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(1);
- } else {
- EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
- }
+ EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(1);
EXPECT_FALSE(stream_->fin_received());
QuicSimpleServerStreamPeer::SendErrorResponse(stream_);
EXPECT_TRUE(stream_->reading_stopped());
diff --git a/chromium/net/tools/quic/quic_simple_server_test.cc b/chromium/net/tools/quic/quic_simple_server_test.cc
index 2bf39601b99..091c08761f5 100644
--- a/chromium/net/tools/quic/quic_simple_server_test.cc
+++ b/chromium/net/tools/quic/quic_simple_server_test.cc
@@ -4,8 +4,9 @@
#include "net/tools/quic/quic_simple_server.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_utils.h"
+#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/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/mock_quic_dispatcher.h"
#include "net/quic/test_tools/quic_test_utils.h"
@@ -25,12 +26,14 @@ class QuicChromeServerDispatchPacketTest : public ::testing::Test {
: crypto_config_("blah",
QuicRandom::GetInstance(),
CryptoTestUtils::ProofSourceForTesting()),
+ version_manager_(AllSupportedVersions()),
dispatcher_(
config_,
&crypto_config_,
+ &version_manager_,
std::unique_ptr<MockQuicConnectionHelper>(
new net::test::MockQuicConnectionHelper),
- std::unique_ptr<QuicServerSessionBase::Helper>(
+ std::unique_ptr<QuicCryptoServerStream::Helper>(
new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
std::unique_ptr<MockAlarmFactory>(
new net::test::MockAlarmFactory)) {
@@ -45,6 +48,7 @@ class QuicChromeServerDispatchPacketTest : public ::testing::Test {
protected:
QuicConfig config_;
QuicCryptoServerConfig crypto_config_;
+ QuicVersionManager version_manager_;
net::test::MockQuicDispatcher dispatcher_;
};
diff --git a/chromium/net/tools/quic/quic_socket_utils.cc b/chromium/net/tools/quic/quic_socket_utils.cc
index 61ec3783511..a6bc4c0c496 100644
--- a/chromium/net/tools/quic/quic_socket_utils.cc
+++ b/chromium/net/tools/quic/quic_socket_utils.cc
@@ -13,9 +13,9 @@
#include <string>
#include "base/logging.h"
-#include "net/quic/quic_bug_tracker.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_protocol.h"
#ifndef SO_RXQ_OVFL
#define SO_RXQ_OVFL 40
@@ -27,9 +27,7 @@ namespace net {
void QuicSocketUtils::GetAddressAndTimestampFromMsghdr(
struct msghdr* hdr,
IPAddress* address,
- QuicTime* timestamp,
- QuicWallTime* walltimestamp,
- bool latched_walltimestamps) {
+ QuicWallTime* walltimestamp) {
if (hdr->msg_controllen > 0) {
for (cmsghdr* cmsg = CMSG_FIRSTHDR(hdr); cmsg != nullptr;
cmsg = CMSG_NXTHDR(hdr, cmsg)) {
@@ -52,12 +50,7 @@ void QuicSocketUtils::GetAddressAndTimestampFromMsghdr(
timespec* ts = &lts->systime;
int64_t usec = (static_cast<int64_t>(ts->tv_sec) * 1000 * 1000) +
(static_cast<int64_t>(ts->tv_nsec) / 1000);
- if (latched_walltimestamps) {
- *walltimestamp = QuicWallTime::FromUNIXMicroseconds(usec);
- } else {
- *timestamp =
- QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(usec));
- }
+ *walltimestamp = QuicWallTime::FromUNIXMicroseconds(usec);
}
}
}
@@ -71,7 +64,24 @@ bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr* hdr,
for (cmsg = CMSG_FIRSTHDR(hdr); cmsg != nullptr;
cmsg = CMSG_NXTHDR(hdr, cmsg)) {
if (cmsg->cmsg_type == SO_RXQ_OVFL) {
- *dropped_packets = *(reinterpret_cast<int*> CMSG_DATA(cmsg));
+ *dropped_packets = *(reinterpret_cast<uint32_t*> CMSG_DATA(cmsg));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// static
+bool QuicSocketUtils::GetTtlFromMsghdr(struct msghdr* hdr, int* ttl) {
+ if (hdr->msg_controllen > 0) {
+ struct cmsghdr* cmsg;
+ for (cmsg = CMSG_FIRSTHDR(hdr); cmsg != nullptr;
+ cmsg = CMSG_NXTHDR(hdr, cmsg)) {
+ if ((cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL) ||
+ (cmsg->cmsg_level == IPPROTO_IPV6 &&
+ cmsg->cmsg_type == IPV6_HOPLIMIT)) {
+ *ttl = *(reinterpret_cast<int*>(CMSG_DATA(cmsg)));
return true;
}
}
@@ -122,9 +132,7 @@ int QuicSocketUtils::ReadPacket(int fd,
size_t buf_len,
QuicPacketCount* dropped_packets,
IPAddress* self_address,
- QuicTime* timestamp,
QuicWallTime* walltimestamp,
- bool latched_walltimestamps,
IPEndPoint* peer_address) {
DCHECK(peer_address != nullptr);
char cbuf[kSpaceForCmsg];
@@ -176,13 +184,7 @@ int QuicSocketUtils::ReadPacket(int fd,
walltimestamp = &stack_walltimestamp;
}
- QuicTime stack_timestamp = QuicTime::Zero();
- if (timestamp == nullptr) {
- timestamp = &stack_timestamp;
- }
-
- GetAddressAndTimestampFromMsghdr(&hdr, self_address, timestamp, walltimestamp,
- latched_walltimestamps);
+ GetAddressAndTimestampFromMsghdr(&hdr, self_address, walltimestamp);
if (raw_address.ss_family == AF_INET) {
CHECK(peer_address->FromSockAddr(
diff --git a/chromium/net/tools/quic/quic_socket_utils.h b/chromium/net/tools/quic/quic_socket_utils.h
index 0bad8381969..f8cc5392c5f 100644
--- a/chromium/net/tools/quic/quic_socket_utils.h
+++ b/chromium/net/tools/quic/quic_socket_utils.h
@@ -16,8 +16,8 @@
#include "base/macros.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_types.h"
+#include "net/quic/core/quic_bandwidth.h"
+#include "net/quic/core/quic_types.h"
namespace net {
@@ -38,30 +38,31 @@ class QuicSocketUtils {
public:
// The first integer is for overflow. The in6_pktinfo is the larger of the
// address structures present. LinuxTimestamping is present for socket
- // timestamping.
+ // timestamping. The subsequent int is for ttl.
// The final int is a sentinel so the msg_controllen feedback
// can be used to detect larger control messages than there is space for.
static const int kSpaceForCmsg =
CMSG_SPACE(CMSG_LEN(sizeof(int)) + CMSG_LEN(sizeof(in6_pktinfo)) +
CMSG_LEN(sizeof(LinuxTimestamping)) +
+ CMSG_LEN(sizeof(int)) +
CMSG_LEN(sizeof(int)));
// Fills in |address| if |hdr| contains IP_PKTINFO or IPV6_PKTINFO. Fills in
// |timestamp| if |hdr| contains |SO_TIMESTAMPING|. |address| and |timestamp|
// must not be null.
- // TODO(rjshade): Delete the |timestamp| argument when removing
- // FLAGS_quic_socket_timestamps_walltime
static void GetAddressAndTimestampFromMsghdr(struct msghdr* hdr,
IPAddress* address,
- QuicTime* timestamp,
- QuicWallTime* walltimestamp,
- bool latched_walltimestamps);
+ QuicWallTime* walltimestamp);
// If the msghdr contains an SO_RXQ_OVFL entry, this will set dropped_packets
// to the correct value and return true. Otherwise it will return false.
static bool GetOverflowFromMsghdr(struct msghdr* hdr,
QuicPacketCount* dropped_packets);
+ // If the msghdr contains an IP_TTL entry, this will set ttl to the correct
+ // value and return true. Otherwise it will return false.
+ static bool GetTtlFromMsghdr(struct msghdr* hdr, int* ttl);
+
// Sets either IP_PKTINFO or IPV6_PKTINFO on the socket, based on
// address_family. Returns the return code from setsockopt.
static int SetGetAddressInfo(int fd, int address_family);
@@ -90,16 +91,12 @@ class QuicSocketUtils {
// received packet, assuming a packet was read and the platform supports
// packet receipt timestamping. If the platform does not support packet
// receipt timestamping, timestamp will not be changed.
- // TODO(rjshade): Delete the |timestamp| argument when removing
- // FLAGS_quic_socket_timestamps_walltime
static int ReadPacket(int fd,
char* buffer,
size_t buf_len,
QuicPacketCount* dropped_packets,
IPAddress* self_address,
- QuicTime* timestamp,
QuicWallTime* walltimestamp,
- bool latched_walltimestamps,
IPEndPoint* peer_address);
// Writes buf_len to the socket. If writing is successful, sets the result's
diff --git a/chromium/net/tools/quic/quic_spdy_client_stream.cc b/chromium/net/tools/quic/quic_spdy_client_stream.cc
index 521c7b66e1f..253571ea39f 100644
--- a/chromium/net/tools/quic/quic_spdy_client_stream.cc
+++ b/chromium/net/tools/quic/quic_spdy_client_stream.cc
@@ -9,9 +9,9 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
-#include "net/quic/quic_alarm.h"
-#include "net/quic/quic_client_promised_info.h"
-#include "net/quic/spdy_utils.h"
+#include "net/quic/core/quic_alarm.h"
+#include "net/quic/core/quic_client_promised_info.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/spdy/spdy_protocol.h"
#include "net/tools/quic/quic_client_session.h"
#include "net/tools/quic/spdy_balsa_utils.h"
@@ -103,7 +103,7 @@ void QuicSpdyClientStream::OnTrailingHeadersComplete(
size_t frame_len,
const QuicHeaderList& header_list) {
QuicSpdyStream::OnTrailingHeadersComplete(fin, frame_len, header_list);
- MarkTrailersConsumed(decompressed_trailers().length());
+ MarkTrailersConsumed();
}
void QuicSpdyClientStream::OnPromiseHeadersComplete(QuicStreamId promised_id,
@@ -149,12 +149,10 @@ void QuicSpdyClientStream::OnPromiseHeaderList(
}
void QuicSpdyClientStream::OnDataAvailable() {
- if (FLAGS_quic_supports_push_promise) {
- // For push streams, visitor will not be set until the rendezvous
- // between server promise and client request is complete.
- if (visitor() == nullptr)
- return;
- }
+ // For push streams, visitor will not be set until the rendezvous
+ // between server promise and client request is complete.
+ if (visitor() == nullptr)
+ return;
while (HasBytesToRead()) {
struct iovec iov;
diff --git a/chromium/net/tools/quic/quic_spdy_client_stream.h b/chromium/net/tools/quic/quic_spdy_client_stream.h
index 04eb4932620..96ce11d086a 100644
--- a/chromium/net/tools/quic/quic_spdy_client_stream.h
+++ b/chromium/net/tools/quic/quic_spdy_client_stream.h
@@ -11,8 +11,8 @@
#include "base/macros.h"
#include "base/strings/string_piece.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_spdy_stream.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_spdy_stream.h"
#include "net/spdy/spdy_framer.h"
namespace net {
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 af3cb3c8cde..20f524a2ba1 100644
--- a/chromium/net/tools/quic/quic_spdy_client_stream_test.cc
+++ b/chromium/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -8,8 +8,8 @@
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
-#include "net/quic/quic_utils.h"
-#include "net/quic/spdy_utils.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/quic/quic_client_session.h"
@@ -26,7 +26,6 @@ using net::test::kClientDataStreamId1;
using net::test::kServerDataStreamId1;
using net::test::kInitialSessionFlowControlWindowForTest;
using net::test::kInitialStreamFlowControlWindowForTest;
-using net::test::ValueRestore;
using std::string;
using testing::StrictMock;
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 6686238a03c..4f99cb02fb9 100644
--- a/chromium/net/tools/quic/quic_time_wait_list_manager.cc
+++ b/chromium/net/tools/quic/quic_time_wait_list_manager.cc
@@ -12,15 +12,15 @@
#include "base/macros.h"
#include "base/stl_util.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/quic_clock.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_session_base.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_clock.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_session_base.h"
+#include "net/quic/core/quic_utils.h"
using base::StringPiece;
@@ -91,7 +91,7 @@ QuicTimeWaitListManager::QuicTimeWaitListManager(
QuicTimeWaitListManager::~QuicTimeWaitListManager() {
connection_id_clean_up_alarm_->Cancel();
- STLDeleteElements(&pending_packets_queue_);
+ base::STLDeleteElements(&pending_packets_queue_);
}
void QuicTimeWaitListManager::AddConnectionIdToTimeWait(
@@ -127,7 +127,7 @@ void QuicTimeWaitListManager::AddConnectionIdToTimeWait(
bool QuicTimeWaitListManager::IsConnectionIdInTimeWait(
QuicConnectionId connection_id) const {
- return ContainsKey(connection_id_map_, connection_id);
+ return base::ContainsKey(connection_id_map_, connection_id);
}
QuicVersion QuicTimeWaitListManager::GetQuicVersionFromConnectionId(
@@ -261,15 +261,13 @@ bool QuicTimeWaitListManager::WriteToWire(QueuedPacket* queued_packet) {
}
void QuicTimeWaitListManager::SetConnectionIdCleanUpAlarm() {
- connection_id_clean_up_alarm_->Cancel();
QuicTime::Delta next_alarm_interval = QuicTime::Delta::Zero();
if (!connection_id_map_.empty()) {
QuicTime oldest_connection_id =
connection_id_map_.begin()->second.time_added;
QuicTime now = clock_->ApproximateNow();
- if (now.Subtract(oldest_connection_id) < time_wait_period_) {
- next_alarm_interval =
- oldest_connection_id.Add(time_wait_period_).Subtract(now);
+ if (now - oldest_connection_id < time_wait_period_) {
+ next_alarm_interval = oldest_connection_id + time_wait_period_ - now;
} else {
LOG(ERROR) << "ConnectionId lingered for longer than time_wait_period_";
}
@@ -278,8 +276,8 @@ void QuicTimeWaitListManager::SetConnectionIdCleanUpAlarm() {
next_alarm_interval = time_wait_period_;
}
- connection_id_clean_up_alarm_->Set(
- clock_->ApproximateNow().Add(next_alarm_interval));
+ connection_id_clean_up_alarm_->Update(
+ clock_->ApproximateNow() + next_alarm_interval, QuicTime::Delta::Zero());
}
bool QuicTimeWaitListManager::MaybeExpireOldestConnection(
@@ -300,7 +298,7 @@ bool QuicTimeWaitListManager::MaybeExpireOldestConnection(
void QuicTimeWaitListManager::CleanUpOldConnectionIds() {
QuicTime now = clock_->ApproximateNow();
- QuicTime expiration = now.Subtract(time_wait_period_);
+ QuicTime expiration = now - time_wait_period_;
while (MaybeExpireOldestConnection(expiration)) {
}
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 136ee4bc650..52daa92a31b 100644
--- a/chromium/net/tools/quic/quic_time_wait_list_manager.h
+++ b/chromium/net/tools/quic/quic_time_wait_list_manager.h
@@ -16,16 +16,17 @@
#include "base/macros.h"
#include "net/base/linked_hash_map.h"
-#include "net/quic/quic_blocked_writer_interface.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_server_session_base.h"
+#include "net/quic/core/quic_blocked_writer_interface.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_server_session_base.h"
namespace net {
namespace test {
+class QuicDispatcherPeer;
class QuicTimeWaitListManagerPeer;
} // namespace test
@@ -113,6 +114,7 @@ class QuicTimeWaitListManager : public QuicBlockedWriterInterface {
const QuicPublicResetPacket& packet);
private:
+ friend class test::QuicDispatcherPeer;
friend class test::QuicTimeWaitListManagerPeer;
// Internal structure to store pending public reset 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 a1d06b4c4fd..54b5ea809d4 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
@@ -7,17 +7,16 @@
#include <errno.h>
#include <memory>
-#include "net/quic/crypto/crypto_protocol.h"
-#include "net/quic/crypto/null_encrypter.h"
-#include "net/quic/crypto/quic_decrypter.h"
-#include "net/quic/crypto/quic_encrypter.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_data_reader.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_utils.h"
+#include "net/quic/core/crypto/crypto_protocol.h"
+#include "net/quic/core/crypto/null_encrypter.h"
+#include "net/quic/core/crypto/quic_decrypter.h"
+#include "net/quic/core/crypto/quic_encrypter.h"
+#include "net/quic/core/quic_data_reader.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/core/quic_protocol.h"
+#include "net/quic/core/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/quic/quic_epoll_alarm_factory.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
@@ -31,7 +30,6 @@ using net::test::BuildUnsizedDataPacket;
using net::test::NoOpFramerVisitor;
using net::test::QuicVersionMax;
using net::test::QuicVersionMin;
-using net::test::ValueRestore;
using net::test::MockPacketWriter;
using testing::Args;
@@ -154,6 +152,7 @@ class QuicTimeWaitListManagerTest : public ::testing::Test {
packet_number, "data");
}
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
NiceMock<MockFakeTimeEpollServer> epoll_server_;
QuicEpollConnectionHelper helper_;
QuicEpollAlarmFactory alarm_factory_;
@@ -177,7 +176,7 @@ class ValidatePublicResetPacketPredicate
const std::tr1::tuple<const char*, int> packet_buffer,
testing::MatchResultListener* /* listener */) const override {
FramerVisitorCapturingPublicReset visitor;
- QuicFramer framer(QuicSupportedVersions(), QuicTime::Zero(),
+ QuicFramer framer(AllSupportedVersions(), QuicTime::Zero(),
Perspective::IS_CLIENT);
framer.set_visitor(&visitor);
QuicEncryptedPacket encrypted(std::tr1::get<0>(packet_buffer),
@@ -227,15 +226,14 @@ TEST_F(QuicTimeWaitListManagerTest, CheckStatelessConnectionIdInTimeWait) {
TEST_F(QuicTimeWaitListManagerTest, SendVersionNegotiationPacket) {
std::unique_ptr<QuicEncryptedPacket> packet(
QuicFramer::BuildVersionNegotiationPacket(connection_id_,
- QuicSupportedVersions()));
+ AllSupportedVersions()));
EXPECT_CALL(writer_,
WritePacket(_, packet->length(), server_address_.address(),
client_address_, _))
.WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1)));
time_wait_list_manager_.SendVersionNegotiationPacket(
- connection_id_, QuicSupportedVersions(), server_address_,
- client_address_);
+ connection_id_, AllSupportedVersions(), server_address_, client_address_);
EXPECT_EQ(0u, time_wait_list_manager_.num_connections());
}
@@ -353,11 +351,11 @@ TEST_F(QuicTimeWaitListManagerTest, CleanUpOldConnectionIds) {
QuicTime::Delta offset = QuicTime::Delta::FromMicroseconds(39);
// Now set the current time as time_wait_period + offset usecs.
- epoll_server_.set_now_in_usec(time_wait_period.Add(offset).ToMicroseconds());
+ epoll_server_.set_now_in_usec((time_wait_period + offset).ToMicroseconds());
// After all the old connection_ids are cleaned up, check the next alarm
// interval.
int64_t next_alarm_time = epoll_server_.ApproximateNowInUsec() +
- time_wait_period.Subtract(offset).ToMicroseconds();
+ (time_wait_period - offset).ToMicroseconds();
EXPECT_CALL(epoll_server_, RegisterAlarm(next_alarm_time, _));
time_wait_list_manager_.CleanUpOldConnectionIds();
@@ -479,7 +477,7 @@ TEST_F(QuicTimeWaitListManagerTest, AddConnectionIdTwice) {
QuicTime::Delta offset = QuicTime::Delta::FromMicroseconds(39);
// Now set the current time as time_wait_period + offset usecs.
- epoll_server_.set_now_in_usec(time_wait_period.Add(offset).ToMicroseconds());
+ epoll_server_.set_now_in_usec((time_wait_period + offset).ToMicroseconds());
// After the connection_ids are cleaned up, check the next alarm interval.
int64_t next_alarm_time =
epoll_server_.ApproximateNowInUsec() + time_wait_period.ToMicroseconds();
diff --git a/chromium/net/tools/quic/spdy_balsa_utils.cc b/chromium/net/tools/quic/spdy_balsa_utils.cc
index 8f1ebd2eac4..b5764208990 100644
--- a/chromium/net/tools/quic/spdy_balsa_utils.cc
+++ b/chromium/net/tools/quic/spdy_balsa_utils.cc
@@ -12,8 +12,8 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "net/base/linked_hash_map.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/spdy_utils.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/spdy_utils.h"
#include "net/spdy/spdy_frame_builder.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_protocol.h"
@@ -189,25 +189,29 @@ void SpdyHeadersToRequestHeaders(const SpdyHeaderBlock& header_block,
method = method_it->second.as_string();
}
string uri;
- if (path_it == end_it) {
- uri = "/";
- } else {
- uri = path_it->second.as_string();
- }
- request_headers->SetRequestFirstlineFromStringPieces(
- method, uri, net::kHttp2VersionString);
-
if (scheme_it == end_it) {
- request_headers->AppendHeader("Scheme", "https");
+ uri += "https";
} else {
- request_headers->AppendHeader("Scheme", scheme_it->second);
+ uri += scheme_it->second.as_string();
}
+ uri += "://";
+
if (authority_it != end_it) {
+ uri += authority_it->second.as_string();
request_headers->AppendHeader("host", authority_it->second);
} else if (host_it != end_it) {
+ uri += host_it->second.as_string();
request_headers->AppendHeader("host", host_it->second);
}
+ if (path_it == end_it) {
+ uri += "/";
+ } else {
+ uri += path_it->second.as_string();
+ }
+ request_headers->SetRequestFirstlineFromStringPieces(
+ method, uri, net::kHttp2VersionString);
+
for (BlockIt it = header_block.begin(); it != header_block.end(); ++it) {
if (!IsSpecialSpdyHeader(it, request_headers)) {
if (it->second.empty()) {
diff --git a/chromium/net/tools/quic/spdy_balsa_utils.h b/chromium/net/tools/quic/spdy_balsa_utils.h
index a1d555a642b..dadb0eca479 100644
--- a/chromium/net/tools/quic/spdy_balsa_utils.h
+++ b/chromium/net/tools/quic/spdy_balsa_utils.h
@@ -8,7 +8,7 @@
#include <string>
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_header_block.h"
#include "net/spdy/spdy_protocol.h"
diff --git a/chromium/net/tools/quic/spdy_balsa_utils_test.cc b/chromium/net/tools/quic/spdy_balsa_utils_test.cc
index c8591ea0df9..bf26667be27 100644
--- a/chromium/net/tools/quic/spdy_balsa_utils_test.cc
+++ b/chromium/net/tools/quic/spdy_balsa_utils_test.cc
@@ -58,7 +58,7 @@ TEST(SpdyBalsaUtilsTest, SpdyHeadersToRequestHeaders) {
SpdyBalsaUtils::SpdyHeadersToRequestHeaders(spdy_headers, &request_headers);
EXPECT_EQ("GET", request_headers.request_method());
EXPECT_EQ("HTTP/1.1", request_headers.request_version());
- EXPECT_EQ("/foo", request_headers.request_uri());
+ EXPECT_EQ("https://www.google.com/foo", request_headers.request_uri());
EXPECT_EQ("www.google.com", request_headers.GetHeader("host"));
EXPECT_TRUE(request_headers.HasHeader("bar"));
EXPECT_EQ("", request_headers.GetHeader("bar"));
@@ -76,7 +76,7 @@ TEST(SpdyBalsaUtilsTest, SpdyHeadersToRequestHeaders) {
SpdyBalsaUtils::SpdyHeadersToRequestHeaders(spdy_headers1, &request_headers1);
EXPECT_EQ("GET", request_headers1.request_method());
EXPECT_EQ("HTTP/1.1", request_headers1.request_version());
- EXPECT_EQ("/foo", request_headers1.request_uri());
+ EXPECT_EQ("http://www.google.com/foo", request_headers1.request_uri());
EXPECT_EQ("www.google.com", request_headers1.GetHeader("host"));
}
diff --git a/chromium/net/tools/quic/stateless_rejector.cc b/chromium/net/tools/quic/stateless_rejector.cc
index 0fbbedd88c4..6cf95304d90 100644
--- a/chromium/net/tools/quic/stateless_rejector.cc
+++ b/chromium/net/tools/quic/stateless_rejector.cc
@@ -4,26 +4,33 @@
#include "net/tools/quic/stateless_rejector.h"
-#include "net/quic/quic_crypto_server_stream.h"
-#include "net/quic/quic_flags.h"
+#include "net/quic/core/quic_bug_tracker.h"
+#include "net/quic/core/quic_crypto_server_stream.h"
+#include "net/quic/core/quic_flags.h"
namespace net {
class StatelessRejector::ValidateCallback
: public ValidateClientHelloResultCallback {
public:
- explicit ValidateCallback(StatelessRejector* rejector)
- : rejector_(rejector) {}
+ explicit ValidateCallback(
+ std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> cb)
+ : rejector_(std::move(rejector)), cb_(std::move(cb)) {}
~ValidateCallback() override {}
- void RunImpl(const CryptoHandshakeMessage& client_hello,
- const Result& result) override {
- rejector_->ProcessClientHello(client_hello, result);
+ void Run(scoped_refptr<Result> result,
+ std::unique_ptr<ProofSource::Details> /* proof_source_details */)
+ override {
+ StatelessRejector* rejector_ptr = rejector_.get();
+ rejector_ptr->ProcessClientHello(std::move(result), std::move(rejector_),
+ std::move(cb_));
}
private:
- StatelessRejector* rejector_;
+ std::unique_ptr<StatelessRejector> rejector_;
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> cb_;
};
StatelessRejector::StatelessRejector(
@@ -33,20 +40,21 @@ StatelessRejector::StatelessRejector(
QuicCompressedCertsCache* compressed_certs_cache,
const QuicClock* clock,
QuicRandom* random,
+ QuicByteCount chlo_packet_size,
const IPEndPoint& client_address,
const IPEndPoint& server_address)
- : state_(FAILED),
+ : state_(UNKNOWN),
error_(QUIC_INTERNAL_ERROR),
version_(version),
versions_(versions),
connection_id_(0),
+ chlo_packet_size_(chlo_packet_size),
client_address_(client_address),
server_address_(server_address),
clock_(clock),
random_(random),
crypto_config_(crypto_config),
- compressed_certs_cache_(compressed_certs_cache),
- chlo_(nullptr) {}
+ compressed_certs_cache_(compressed_certs_cache) {}
StatelessRejector::~StatelessRejector() {}
@@ -56,6 +64,7 @@ void StatelessRejector::OnChlo(QuicVersion version,
const CryptoHandshakeMessage& message) {
DCHECK_EQ(kCHLO, message.tag());
DCHECK_NE(connection_id, server_designated_connection_id);
+ DCHECK_EQ(state_, UNKNOWN);
if (!FLAGS_enable_quic_stateless_reject_support ||
!FLAGS_quic_use_cheap_stateless_rejects ||
@@ -67,36 +76,85 @@ void StatelessRejector::OnChlo(QuicVersion version,
connection_id_ = connection_id;
server_designated_connection_id_ = server_designated_connection_id;
- chlo_ = &message;
+ chlo_ = message; // Note: copies the message
+}
- crypto_config_->ValidateClientHello(
- message, client_address_.address(), server_address_.address(), version_,
- clock_, &proof_, new ValidateCallback(this));
+void StatelessRejector::Process(std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<ProcessDoneCallback> done_cb) {
+ // 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() != UNKNOWN) {
+ done_cb->Run(std::move(rejector));
+ return;
+ }
+
+ StatelessRejector* rejector_ptr = rejector.get();
+ rejector_ptr->crypto_config_->ValidateClientHello(
+ rejector_ptr->chlo_, rejector_ptr->client_address_.address(),
+ rejector_ptr->server_address_.address(), rejector_ptr->version_,
+ rejector_ptr->clock_, &rejector_ptr->proof_,
+ std::unique_ptr<ValidateCallback>(
+ new ValidateCallback(std::move(rejector), std::move(done_cb))));
}
+class StatelessRejector::ProcessClientHelloCallback
+ : public ProcessClientHelloResultCallback {
+ public:
+ ProcessClientHelloCallback(
+ std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb)
+ : rejector_(std::move(rejector)), done_cb_(std::move(done_cb)) {}
+
+ void Run(
+ QuicErrorCode error,
+ const std::string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> message,
+ std::unique_ptr<DiversificationNonce> diversification_nonce) override {
+ StatelessRejector* rejector_ptr = rejector_.get();
+ rejector_ptr->ProcessClientHelloDone(
+ error, error_details, std::move(message), std::move(rejector_),
+ std::move(done_cb_));
+ }
+
+ private:
+ std::unique_ptr<StatelessRejector> rejector_;
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb_;
+};
+
void StatelessRejector::ProcessClientHello(
- const CryptoHandshakeMessage& client_hello,
- const ValidateClientHelloResultCallback::Result& result) {
- QuicCryptoNegotiatedParameters params;
- DiversificationNonce diversification_nonce;
- QuicErrorCode error = crypto_config_->ProcessClientHello(
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result,
+ std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb) {
+ std::unique_ptr<ProcessClientHelloCallback> cb(
+ new ProcessClientHelloCallback(std::move(rejector), std::move(done_cb)));
+ crypto_config_->ProcessClientHello(
result,
/*reject_only=*/true, connection_id_, server_address_.address(),
client_address_, version_, versions_,
/*use_stateless_rejects=*/true, server_designated_connection_id_, clock_,
- random_, compressed_certs_cache_, &params, &proof_, &reply_,
- &diversification_nonce, &error_details_);
+ random_, compressed_certs_cache_, &params_, &proof_,
+ QuicCryptoStream::CryptoMessageFramingOverhead(version_),
+ chlo_packet_size_, std::move(cb));
+}
+
+void StatelessRejector::ProcessClientHelloDone(
+ QuicErrorCode error,
+ const std::string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> message,
+ std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb) {
+ reply_ = std::move(message);
+
if (error != QUIC_NO_ERROR) {
error_ = error;
- return;
- }
-
- if (reply_.tag() == kSREJ) {
+ error_details_ = error_details;
+ state_ = FAILED;
+ } else if (reply_->tag() == kSREJ) {
state_ = REJECTED;
- return;
+ } else {
+ state_ = ACCEPTED;
}
-
- state_ = ACCEPTED;
+ done_cb->Run(std::move(rejector));
}
} // namespace net
diff --git a/chromium/net/tools/quic/stateless_rejector.h b/chromium/net/tools/quic/stateless_rejector.h
index 07a666d0cc7..c8dcd4b97c8 100644
--- a/chromium/net/tools/quic/stateless_rejector.h
+++ b/chromium/net/tools/quic/stateless_rejector.h
@@ -6,9 +6,9 @@
#define NET_QUIC_STATELESS_REJECTOR_H_
#include "base/strings/string_piece.h"
-#include "net/quic/crypto/crypto_framer.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/crypto/crypto_framer.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/quic_protocol.h"
namespace net {
@@ -17,6 +17,7 @@ namespace net {
class StatelessRejector {
public:
enum State {
+ UNKNOWN, // State has not yet been determined
UNSUPPORTED, // Stateless rejects are not supported
FAILED, // There was an error processing the CHLO.
ACCEPTED, // The CHLO was accepted
@@ -29,18 +30,30 @@ class StatelessRejector {
QuicCompressedCertsCache* compressed_certs_cache,
const QuicClock* clock,
QuicRandom* random,
+ QuicByteCount chlo_packet_size,
const IPEndPoint& client_address,
const IPEndPoint& server_address);
~StatelessRejector();
- // Called when |chlo| is received for |connection_id| to determine
- // if it should be statelessly rejected.
+ // Called when |chlo| is received for |connection_id|.
void OnChlo(QuicVersion version,
QuicConnectionId connection_id,
QuicConnectionId server_designated_connection_id,
const CryptoHandshakeMessage& chlo);
+ class ProcessDoneCallback {
+ public:
+ virtual ~ProcessDoneCallback() = default;
+ virtual void Run(std::unique_ptr<StatelessRejector> rejector) = 0;
+ };
+
+ // Perform processing to determine whether the CHLO received in OnChlo should
+ // be statelessly rejected, and invoke the callback once a decision has been
+ // made.
+ static void Process(std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<ProcessDoneCallback> done_cb);
+
// Returns the state of the rejector after OnChlo() has been called.
State state() const { return state_; }
@@ -50,8 +63,11 @@ class StatelessRejector {
// Returns the error details when state() returns FAILED.
std::string error_details() const { return error_details_; }
+ // Returns the connection ID.
+ QuicConnectionId connection_id() const { return connection_id_; }
+
// Returns the SREJ message when state() returns REJECTED.
- const CryptoHandshakeMessage& reply() const { return reply_; }
+ const CryptoHandshakeMessage& reply() const { return *reply_; }
private:
// Helper class which is passed in to
@@ -59,9 +75,20 @@ class StatelessRejector {
class ValidateCallback;
friend class ValidateCallback;
+ class ProcessClientHelloCallback;
+ friend class ProcessClientHelloCallback;
+
void ProcessClientHello(
- const CryptoHandshakeMessage& client_hello,
- const ValidateClientHelloResultCallback::Result& result);
+ scoped_refptr<ValidateClientHelloResultCallback::Result> result,
+ std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb);
+
+ void ProcessClientHelloDone(
+ QuicErrorCode error,
+ const std::string& error_details,
+ std::unique_ptr<CryptoHandshakeMessage> message,
+ std::unique_ptr<StatelessRejector> rejector,
+ std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb);
State state_;
QuicErrorCode error_;
@@ -70,16 +97,18 @@ class StatelessRejector {
QuicVersionVector versions_;
QuicConnectionId connection_id_;
QuicConnectionId server_designated_connection_id_;
+ QuicByteCount chlo_packet_size_;
IPEndPoint client_address_;
IPEndPoint server_address_;
const QuicClock* clock_;
QuicRandom* random_;
const QuicCryptoServerConfig* crypto_config_;
QuicCompressedCertsCache* compressed_certs_cache_;
- const CryptoHandshakeMessage* chlo_;
- CryptoHandshakeMessage reply_;
+ CryptoHandshakeMessage chlo_;
+ std::unique_ptr<CryptoHandshakeMessage> reply_;
CryptoFramer crypto_framer_;
QuicCryptoProof proof_;
+ QuicCryptoNegotiatedParameters params_;
DISALLOW_COPY_AND_ASSIGN(StatelessRejector);
};
diff --git a/chromium/net/tools/quic/stateless_rejector_test.cc b/chromium/net/tools/quic/stateless_rejector_test.cc
index 97f7839998a..d773ff53de7 100644
--- a/chromium/net/tools/quic/stateless_rejector_test.cc
+++ b/chromium/net/tools/quic/stateless_rejector_test.cc
@@ -7,9 +7,11 @@
#include <memory>
#include <vector>
-#include "net/quic/crypto/crypto_handshake_message.h"
-#include "net/quic/crypto/proof_source.h"
-#include "net/quic/quic_utils.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/stringprintf.h"
+#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/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_crypto_server_config_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
@@ -28,21 +30,38 @@ const QuicConnectionId kServerDesignateConnectionId = 24;
// All four combinations of the two flags involved.
enum FlagsMode { ENABLED, STATELESS_DISABLED, CHEAP_DISABLED, BOTH_DISABLED };
+const char* FlagsModeToString(FlagsMode mode) {
+ switch (mode) {
+ case ENABLED:
+ return "ENABLED";
+ case STATELESS_DISABLED:
+ return "STATELESS_DISABLED";
+ case CHEAP_DISABLED:
+ return "CHEAP_DISABLED";
+ case BOTH_DISABLED:
+ return "BOTH_DISABLED";
+ default:
+ DLOG(FATAL) << "Unexpected FlagsMode";
+ return nullptr;
+ }
+}
+
// Test various combinations of QUIC version and flag state.
struct TestParams {
QuicVersion version;
FlagsMode flags;
- friend ostream& operator<<(ostream& os, const TestParams& p) {
- os << "{ version: " << p.version << " flags: " << p.flags << " }";
- return os;
- }
};
+string TestParamToString(const testing::TestParamInfo<TestParams>& params) {
+ return base::StringPrintf("v%i_%s", params.param.version,
+ FlagsModeToString(params.param.flags));
+}
+
vector<TestParams> GetTestParams() {
vector<TestParams> params;
for (FlagsMode flags :
{ENABLED, STATELESS_DISABLED, CHEAP_DISABLED, BOTH_DISABLED}) {
- for (QuicVersion version : QuicSupportedVersions()) {
+ for (QuicVersion version : AllSupportedVersions()) {
TestParams param;
param.version = version;
param.flags = flags;
@@ -62,14 +81,16 @@ class StatelessRejectorTest : public ::testing::TestWithParam<TestParams> {
config_peer_(&config_),
compressed_certs_cache_(
QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
- rejector_(GetParam().version,
- QuicSupportedVersions(),
- &config_,
- &compressed_certs_cache_,
- &clock_,
- QuicRandom::GetInstance(),
- IPEndPoint(net::test::Loopback4(), 12345),
- IPEndPoint(net::test::Loopback4(), 443)) {
+ rejector_(base::MakeUnique<StatelessRejector>(
+ GetParam().version,
+ AllSupportedVersions(),
+ &config_,
+ &compressed_certs_cache_,
+ &clock_,
+ QuicRandom::GetInstance(),
+ kDefaultMaxPacketSize,
+ IPEndPoint(net::test::Loopback4(), 12345),
+ IPEndPoint(net::test::Loopback4(), 443))) {
FLAGS_enable_quic_stateless_reject_support =
GetParam().flags == ENABLED || GetParam().flags == CHEAP_DISABLED;
FLAGS_quic_use_cheap_stateless_rejects =
@@ -111,13 +132,26 @@ class StatelessRejectorTest : public ::testing::TestWithParam<TestParams> {
}
protected:
+ class ProcessDoneCallback : public StatelessRejector::ProcessDoneCallback {
+ public:
+ explicit ProcessDoneCallback(StatelessRejectorTest* test) : test_(test) {}
+ void Run(std::unique_ptr<StatelessRejector> rejector) override {
+ test_->rejector_ = std::move(rejector);
+ }
+
+ private:
+ StatelessRejectorTest* test_;
+ };
+
+ QuicFlagSaver flags_; // Save/restore all QUIC flag values.
+
std::unique_ptr<ProofSource> proof_source_;
MockClock clock_;
QuicCryptoServerConfig config_;
QuicCryptoServerConfigPeer config_peer_;
QuicCompressedCertsCache compressed_certs_cache_;
QuicCryptoServerConfig::ConfigOptions config_options_;
- StatelessRejector rejector_;
+ std::unique_ptr<StatelessRejector> rejector_;
// Values used in CHLO messages
string scid_hex_;
@@ -129,31 +163,39 @@ class StatelessRejectorTest : public ::testing::TestWithParam<TestParams> {
INSTANTIATE_TEST_CASE_P(Flags,
StatelessRejectorTest,
- ::testing::ValuesIn(GetTestParams()));
+ ::testing::ValuesIn(GetTestParams()),
+ TestParamToString);
TEST_P(StatelessRejectorTest, InvalidChlo) {
// clang-format off
const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
"CHLO",
+ "PDMD", "X509",
"COPT", "SREJ",
nullptr);
// clang-format on
- rejector_.OnChlo(GetParam().version, kConnectionId,
- kServerDesignateConnectionId, client_hello);
+ rejector_->OnChlo(GetParam().version, kConnectionId,
+ kServerDesignateConnectionId, client_hello);
if (GetParam().flags != ENABLED || GetParam().version <= QUIC_VERSION_32) {
- EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_.state());
+ EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
return;
}
- EXPECT_EQ(StatelessRejector::FAILED, rejector_.state());
- EXPECT_EQ(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, rejector_.error());
+ // The StatelessRejector is undecided - proceed with async processing
+ ASSERT_EQ(StatelessRejector::UNKNOWN, rejector_->state());
+ StatelessRejector::Process(std::move(rejector_),
+ base::MakeUnique<ProcessDoneCallback>(this));
+
+ EXPECT_EQ(StatelessRejector::FAILED, rejector_->state());
+ EXPECT_EQ(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, rejector_->error());
}
TEST_P(StatelessRejectorTest, ValidChloWithoutSrejSupport) {
// clang-format off
const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
"CHLO",
+ "PDMD", "X509",
"AEAD", "AESG",
"KEXS", "C255",
"PUBS", pubs_hex_.c_str(),
@@ -163,15 +205,16 @@ TEST_P(StatelessRejectorTest, ValidChloWithoutSrejSupport) {
nullptr);
// clang-format on
- rejector_.OnChlo(GetParam().version, kConnectionId,
- kServerDesignateConnectionId, client_hello);
- EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_.state());
+ rejector_->OnChlo(GetParam().version, kConnectionId,
+ kServerDesignateConnectionId, client_hello);
+ EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
}
TEST_P(StatelessRejectorTest, RejectChlo) {
// clang-format off
const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
"CHLO",
+ "PDMD", "X509",
"AEAD", "AESG",
"KEXS", "C255",
"COPT", "SREJ",
@@ -184,14 +227,20 @@ TEST_P(StatelessRejectorTest, RejectChlo) {
nullptr);
// clang-format on
- rejector_.OnChlo(GetParam().version, kConnectionId,
- kServerDesignateConnectionId, client_hello);
+ rejector_->OnChlo(GetParam().version, kConnectionId,
+ kServerDesignateConnectionId, client_hello);
if (GetParam().flags != ENABLED || GetParam().version <= QUIC_VERSION_32) {
- EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_.state());
+ EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
return;
}
- ASSERT_EQ(StatelessRejector::REJECTED, rejector_.state());
- const CryptoHandshakeMessage& reply = rejector_.reply();
+
+ // The StatelessRejector is undecided - proceed with async processing
+ ASSERT_EQ(StatelessRejector::UNKNOWN, rejector_->state());
+ StatelessRejector::Process(std::move(rejector_),
+ base::MakeUnique<ProcessDoneCallback>(this));
+
+ ASSERT_EQ(StatelessRejector::REJECTED, rejector_->state());
+ const CryptoHandshakeMessage& reply = rejector_->reply();
EXPECT_EQ(kSREJ, reply.tag());
const uint32_t* reject_reasons;
size_t num_reject_reasons;
@@ -210,6 +259,7 @@ TEST_P(StatelessRejectorTest, AcceptChlo) {
// clang-format off
const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
"CHLO",
+ "PDMD", "X509",
"AEAD", "AESG",
"KEXS", "C255",
"COPT", "SREJ",
@@ -223,13 +273,19 @@ TEST_P(StatelessRejectorTest, AcceptChlo) {
nullptr);
// clang-format on
- rejector_.OnChlo(GetParam().version, kConnectionId,
- kServerDesignateConnectionId, client_hello);
+ rejector_->OnChlo(GetParam().version, kConnectionId,
+ kServerDesignateConnectionId, client_hello);
if (GetParam().flags != ENABLED || GetParam().version <= QUIC_VERSION_32) {
- EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_.state());
+ EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
return;
}
- EXPECT_EQ(StatelessRejector::ACCEPTED, rejector_.state());
+
+ // The StatelessRejector is undecided - proceed with async processing
+ ASSERT_EQ(StatelessRejector::UNKNOWN, rejector_->state());
+ StatelessRejector::Process(std::move(rejector_),
+ base::MakeUnique<ProcessDoneCallback>(this));
+
+ EXPECT_EQ(StatelessRejector::ACCEPTED, rejector_->state());
}
} // namespace
diff --git a/chromium/net/tools/quic/synchronous_host_resolver.cc b/chromium/net/tools/quic/synchronous_host_resolver.cc
index 7bdf5fd6e25..ba1e51b3f5b 100644
--- a/chromium/net/tools/quic/synchronous_host_resolver.cc
+++ b/chromium/net/tools/quic/synchronous_host_resolver.cc
@@ -15,7 +15,8 @@
#include "net/base/host_port_pair.h"
#include "net/base/net_errors.h"
#include "net/dns/host_resolver_impl.h"
-#include "net/dns/single_request_host_resolver.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
namespace net {
@@ -60,16 +61,16 @@ void ResolverThread::Run() {
net::HostResolver::Options options;
options.max_concurrent_resolves = 6;
options.max_retry_attempts = 3u;
- std::unique_ptr<net::HostResolverImpl> resolver_impl(
+ std::unique_ptr<net::HostResolverImpl> resolver(
new net::HostResolverImpl(options, &net_log));
- SingleRequestHostResolver resolver(resolver_impl.get());
+ std::unique_ptr<net::HostResolver::Request> request;
HostPortPair host_port_pair(host_, 80);
- rv_ = resolver.Resolve(HostResolver::RequestInfo(host_port_pair),
- DEFAULT_PRIORITY, addresses_,
- base::Bind(&ResolverThread::OnResolutionComplete,
- weak_factory_.GetWeakPtr()),
- BoundNetLog());
+ rv_ = resolver->Resolve(HostResolver::RequestInfo(host_port_pair),
+ DEFAULT_PRIORITY, addresses_,
+ base::Bind(&ResolverThread::OnResolutionComplete,
+ weak_factory_.GetWeakPtr()),
+ &request, NetLogWithSource());
if (rv_ != ERR_IO_PENDING)
return;
diff --git a/chromium/net/tools/quic/synchronous_host_resolver.h b/chromium/net/tools/quic/synchronous_host_resolver.h
index 7089c874251..d41f0afb79b 100644
--- a/chromium/net/tools/quic/synchronous_host_resolver.h
+++ b/chromium/net/tools/quic/synchronous_host_resolver.h
@@ -8,7 +8,6 @@
#define NET_TOOLS_QUIC_SYNCHRONOUS_HOST_RESOLVER_H_
#include "net/base/address_list.h"
-#include "net/base/net_export.h"
#include "net/dns/host_resolver.h"
namespace net {
diff --git a/chromium/net/tools/quic/test_tools/limited_mtu_test_writer.h b/chromium/net/tools/quic/test_tools/limited_mtu_test_writer.h
index a9efa7f1d91..c58b7662f26 100644
--- a/chromium/net/tools/quic/test_tools/limited_mtu_test_writer.h
+++ b/chromium/net/tools/quic/test_tools/limited_mtu_test_writer.h
@@ -8,7 +8,7 @@
#include <stddef.h>
#include "base/macros.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_packet_writer_wrapper.h"
namespace net {
diff --git a/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.cc b/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.cc
index 9b5d4c0a186..f3ae2b05686 100644
--- a/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.cc
+++ b/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.cc
@@ -11,9 +11,9 @@ MockQuicServerSessionVisitor::MockQuicServerSessionVisitor() {}
MockQuicServerSessionVisitor::~MockQuicServerSessionVisitor() {}
-MockQuicServerSessionHelper::MockQuicServerSessionHelper() {}
+MockQuicCryptoServerStreamHelper::MockQuicCryptoServerStreamHelper() {}
-MockQuicServerSessionHelper::~MockQuicServerSessionHelper() {}
+MockQuicCryptoServerStreamHelper::~MockQuicCryptoServerStreamHelper() {}
} // namespace test
} // namespace net
diff --git a/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.h b/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.h
index 52d59d2e795..d89f49cb8a0 100644
--- a/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.h
+++ b/chromium/net/tools/quic/test_tools/mock_quic_server_session_visitor.h
@@ -6,7 +6,8 @@
#define NET_TOOLS_QUIC_TEST_TOOLS_MOCK_QUIC_SERVER_SESSION_VISITOR_H_
#include "base/macros.h"
-#include "net/quic/quic_server_session_base.h"
+#include "net/quic/core/quic_crypto_server_stream.h"
+#include "net/quic/core/quic_server_session_base.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace net {
@@ -24,15 +25,17 @@ class MockQuicServerSessionVisitor : public QuicServerSessionBase::Visitor {
void(QuicBlockedWriterInterface* blocked_writer));
MOCK_METHOD1(OnConnectionAddedToTimeWaitList,
void(QuicConnectionId connection_id));
+ MOCK_METHOD1(OnPacketBeingDispatchedToSession,
+ void(QuicServerSessionBase* session));
private:
DISALLOW_COPY_AND_ASSIGN(MockQuicServerSessionVisitor);
};
-class MockQuicServerSessionHelper : public QuicServerSessionBase::Helper {
+class MockQuicCryptoServerStreamHelper : public QuicCryptoServerStream::Helper {
public:
- MockQuicServerSessionHelper();
- ~MockQuicServerSessionHelper() override;
+ MockQuicCryptoServerStreamHelper();
+ ~MockQuicCryptoServerStreamHelper() override;
MOCK_CONST_METHOD1(GenerateConnectionIdForReject,
QuicConnectionId(QuicConnectionId connection_id));
MOCK_CONST_METHOD3(CanAcceptClientHello,
@@ -41,7 +44,7 @@ class MockQuicServerSessionHelper : public QuicServerSessionBase::Helper {
std::string* error_details));
private:
- DISALLOW_COPY_AND_ASSIGN(MockQuicServerSessionHelper);
+ DISALLOW_COPY_AND_ASSIGN(MockQuicCryptoServerStreamHelper);
};
} // namespace test
diff --git a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc
index 4d85d5a85f9..54424887951 100644
--- a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc
+++ b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.cc
@@ -50,6 +50,7 @@ PacketDroppingTestWriter::PacketDroppingTestWriter()
: clock_(nullptr),
cur_buffer_size_(0),
num_calls_to_write_(0),
+ max_allowed_packet_size_(std::numeric_limits<QuicByteCount>::max()),
config_mutex_(),
fake_packet_loss_percentage_(0),
fake_drop_first_n_packets_(0),
@@ -81,6 +82,7 @@ WriteResult PacketDroppingTestWriter::WritePacket(
const IPAddress& self_address,
const IPEndPoint& peer_address,
PerPacketOptions* options) {
+ CHECK_LE(buf_len, max_allowed_packet_size_);
++num_calls_to_write_;
ReleaseOldPackets();
@@ -118,14 +120,14 @@ WriteResult PacketDroppingTestWriter::WritePacket(
}
// Queue it to be sent.
- QuicTime send_time = clock_->ApproximateNow().Add(fake_packet_delay_);
+ QuicTime send_time = clock_->ApproximateNow() + fake_packet_delay_;
if (!fake_bandwidth_.IsZero()) {
// Calculate a time the bandwidth limit would impose.
QuicTime::Delta bandwidth_delay = QuicTime::Delta::FromMicroseconds(
(buf_len * kNumMicrosPerSecond) / fake_bandwidth_.ToBytesPerSecond());
send_time = delayed_packets_.empty()
- ? send_time.Add(bandwidth_delay)
- : delayed_packets_.back().send_time.Add(bandwidth_delay);
+ ? send_time + bandwidth_delay
+ : delayed_packets_.back().send_time + bandwidth_delay;
}
std::unique_ptr<PerPacketOptions> delayed_options;
if (options != nullptr) {
diff --git a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h
index 2e3fcbca0ea..ff058b5660a 100644
--- a/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h
+++ b/chromium/net/tools/quic/test_tools/packet_dropping_test_writer.h
@@ -16,7 +16,7 @@
#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "net/base/ip_address.h"
-#include "net/quic/quic_alarm.h"
+#include "net/quic/core/quic_alarm.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/quic/quic_epoll_clock.h"
#include "net/tools/quic/quic_packet_writer_wrapper.h"
@@ -121,6 +121,12 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper {
// Useful for reproducing very flaky issues.
void set_seed(uint64_t seed) { simple_random_.set_seed(seed); }
+ // Sets the maximum allowed packet size to be sent. Packets larger than
+ // |packet_size| will cause the write to check-fail.
+ void set_max_allowed_packet_size(QuicByteCount packet_size) {
+ max_allowed_packet_size_ = packet_size;
+ }
+
private:
// Writes out the next packet to the contained writer and returns the time
// for the next delayed packet to be written.
@@ -162,6 +168,7 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper {
DelayedPacketList delayed_packets_;
QuicByteCount cur_buffer_size_;
uint64_t num_calls_to_write_;
+ QuicByteCount max_allowed_packet_size_;
base::Lock config_mutex_;
int32_t fake_packet_loss_percentage_;
diff --git a/chromium/net/tools/quic/test_tools/packet_reordering_writer.cc b/chromium/net/tools/quic/test_tools/packet_reordering_writer.cc
new file mode 100644
index 00000000000..a11f7d8e393
--- /dev/null
+++ b/chromium/net/tools/quic/test_tools/packet_reordering_writer.cc
@@ -0,0 +1,50 @@
+// Copyright 2013 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/packet_reordering_writer.h"
+
+namespace net {
+namespace test {
+
+PacketReorderingWriter::PacketReorderingWriter() {}
+
+PacketReorderingWriter::~PacketReorderingWriter() {}
+
+WriteResult PacketReorderingWriter::WritePacket(const char* buffer,
+ size_t buf_len,
+ const IPAddress& self_address,
+ const IPEndPoint& peer_address,
+ PerPacketOptions* options) {
+ if (!delay_next_) {
+ WriteResult wr = QuicPacketWriterWrapper::WritePacket(
+ buffer, buf_len, self_address, peer_address, options);
+ --num_packets_to_wait_;
+ if (num_packets_to_wait_ == 0) {
+ // It's time to write the delayed packet.
+ QuicPacketWriterWrapper::WritePacket(
+ delayed_data_.data(), delayed_data_.length(), delayed_self_address_,
+ delayed_peer_address_, delayed_options_.get());
+ }
+ return wr;
+ }
+ // Still have packet to wait.
+ DCHECK_LT(0u, num_packets_to_wait_) << "Only allow one packet to be delayed";
+ delayed_data_ = std::string(buffer, buf_len);
+ delayed_self_address_ = self_address;
+ delayed_peer_address_ = peer_address;
+ if (options != nullptr) {
+ delayed_options_.reset(options->Clone());
+ }
+ delay_next_ = false;
+ return WriteResult(WRITE_STATUS_OK, buf_len);
+}
+
+void PacketReorderingWriter::SetDelay(size_t num_packets_to_wait) {
+ DCHECK_GT(num_packets_to_wait, 0u);
+ num_packets_to_wait_ = num_packets_to_wait;
+ delay_next_ = true;
+}
+
+} // namespace test
+} // namespace net
diff --git a/chromium/net/tools/quic/test_tools/packet_reordering_writer.h b/chromium/net/tools/quic/test_tools/packet_reordering_writer.h
new file mode 100644
index 00000000000..d09aeb84a3a
--- /dev/null
+++ b/chromium/net/tools/quic/test_tools/packet_reordering_writer.h
@@ -0,0 +1,45 @@
+// Copyright 2013 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_PACKET_REORDERING_WRITER_H_
+#define NET_TOOLS_QUIC_TEST_TOOLS_PACKET_REORDERING_WRITER_H_
+
+#include "net/tools/quic/quic_packet_writer_wrapper.h"
+
+namespace net {
+
+namespace test {
+
+// This packet writer allows delaying writing the next packet after
+// SetDelay(num_packets_to_wait)
+// is called and buffer this packet and write it after it writes next
+// |num_packets_to_wait| packets. It doesn't support delaying a packet while
+// there is already a packet delayed.
+class PacketReorderingWriter : public QuicPacketWriterWrapper {
+ public:
+ PacketReorderingWriter();
+
+ ~PacketReorderingWriter() override;
+
+ WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const IPAddress& self_address,
+ const IPEndPoint& peer_address,
+ PerPacketOptions* options) override;
+
+ void SetDelay(size_t num_packets_to_wait);
+
+ private:
+ bool delay_next_ = false;
+ size_t num_packets_to_wait_ = 0;
+ std::string delayed_data_;
+ IPAddress delayed_self_address_;
+ IPEndPoint delayed_peer_address_;
+ std::unique_ptr<PerPacketOptions> delayed_options_;
+};
+
+} // namespace test
+} // namespace net
+
+#endif // NET_TOOLS_QUIC_TEST_TOOLS_PACKET_REORDERING_WRITER_H_
diff --git a/chromium/net/tools/quic/test_tools/quic_client_peer.cc b/chromium/net/tools/quic/test_tools/quic_client_peer.cc
index 961cc823e2d..aca80df0c20 100644
--- a/chromium/net/tools/quic/test_tools/quic_client_peer.cc
+++ b/chromium/net/tools/quic/test_tools/quic_client_peer.cc
@@ -16,7 +16,9 @@ QuicCryptoClientConfig* QuicClientPeer::GetCryptoConfig(QuicClient* client) {
// static
bool QuicClientPeer::CreateUDPSocketAndBind(QuicClient* client) {
- return client->CreateUDPSocketAndBind();
+ return client->CreateUDPSocketAndBind(client->server_address(),
+ client->bind_to_address(),
+ client->local_port());
}
// static
diff --git a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc
index 48a61f71d68..bb528841e83 100644
--- a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc
+++ b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.cc
@@ -62,10 +62,35 @@ QuicErrorCode QuicDispatcherPeer::GetAndClearLastError(
}
// static
+QuicBufferedPacketStore* QuicDispatcherPeer::GetBufferedPackets(
+ QuicDispatcher* dispatcher) {
+ return &(dispatcher->buffered_packets_);
+}
+
+// static
const QuicDispatcher::SessionMap& QuicDispatcherPeer::session_map(
QuicDispatcher* dispatcher) {
return dispatcher->session_map();
}
+// static
+void QuicDispatcherPeer::set_new_sessions_allowed_per_event_loop(
+ QuicDispatcher* dispatcher,
+ size_t num_session_allowed) {
+ return dispatcher->set_new_sessions_allowed_per_event_loop(
+ num_session_allowed);
+}
+
+// static
+void QuicDispatcherPeer::SendPublicReset(
+ QuicDispatcher* dispatcher,
+ const IPEndPoint& server_address,
+ const IPEndPoint& client_address,
+ QuicConnectionId connection_id,
+ QuicPacketNumber rejected_packet_number) {
+ dispatcher->time_wait_list_manager()->SendPublicReset(
+ server_address, client_address, connection_id, rejected_packet_number);
+}
+
} // namespace test
} // namespace net
diff --git a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h
index 4ff4d2d38b6..c415fc39ad1 100644
--- a/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h
+++ b/chromium/net/tools/quic/test_tools/quic_dispatcher_peer.h
@@ -41,9 +41,22 @@ class QuicDispatcherPeer {
// visitor's OnError() method. Then set that record to QUIC_NO_ERROR.
static QuicErrorCode GetAndClearLastError(QuicDispatcher* dispatcher);
+ static QuicBufferedPacketStore* GetBufferedPackets(
+ QuicDispatcher* dispatcher);
+
static const QuicDispatcher::SessionMap& session_map(
QuicDispatcher* dispatcher);
+ static void set_new_sessions_allowed_per_event_loop(
+ QuicDispatcher* dispatcher,
+ size_t num_session_allowed);
+
+ static void SendPublicReset(QuicDispatcher* dispatcher,
+ const IPEndPoint& server_address,
+ const IPEndPoint& client_address,
+ QuicConnectionId connection_id,
+ QuicPacketNumber rejected_packet_number);
+
private:
DISALLOW_COPY_AND_ASSIGN(QuicDispatcherPeer);
};
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 914c4f8ab03..e58916b0ee5 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_client.cc
+++ b/chromium/net/tools/quic/test_tools/quic_test_client.cc
@@ -7,14 +7,17 @@
#include <memory>
#include <utility>
+#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "net/base/completion_callback.h"
#include "net/base/net_errors.h"
#include "net/cert/cert_verify_result.h"
#include "net/cert/x509_certificate.h"
-#include "net/quic/crypto/proof_verifier.h"
-#include "net/quic/quic_flags.h"
-#include "net/quic/quic_server_id.h"
+#include "net/quic/core/crypto/proof_verifier.h"
+#include "net/quic/core/quic_flags.h"
+#include "net/quic/core/quic_server_id.h"
+#include "net/quic/core/quic_utils.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/quic/test_tools/quic_spdy_session_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
@@ -35,28 +38,36 @@ using net::test::QuicSpdySessionPeer;
using net::test::ReliableQuicStreamPeer;
using std::string;
using std::vector;
+using testing::_;
+using testing::Invoke;
namespace net {
namespace test {
namespace {
// RecordingProofVerifier accepts any certificate chain and records the common
-// name of the leaf.
+// name of the leaf and then delegates the actual verfication to an actual
+// verifier. If no optional verifier is provided, then VerifyProof will return
+// success.
class RecordingProofVerifier : public ProofVerifier {
public:
+ explicit RecordingProofVerifier(std::unique_ptr<ProofVerifier> verifier)
+ : verifier_(std::move(verifier)) {}
+
// ProofVerifier interface.
- QuicAsyncStatus VerifyProof(const string& hostname,
- const uint16_t port,
- const string& server_config,
- QuicVersion quic_version,
- StringPiece chlo_hash,
- const vector<string>& certs,
- const string& cert_sct,
- const string& signature,
- const ProofVerifyContext* context,
- string* error_details,
- std::unique_ptr<ProofVerifyDetails>* details,
- ProofVerifierCallback* callback) override {
+ QuicAsyncStatus VerifyProof(
+ const string& hostname,
+ const uint16_t port,
+ const string& server_config,
+ QuicVersion quic_version,
+ StringPiece chlo_hash,
+ const vector<string>& certs,
+ const string& cert_sct,
+ const string& signature,
+ const ProofVerifyContext* context,
+ string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* details,
+ std::unique_ptr<ProofVerifierCallback> callback) override {
common_name_.clear();
if (certs.empty()) {
return QUIC_FAILURE;
@@ -79,6 +90,22 @@ class RecordingProofVerifier : public ProofVerifier {
// common_name_ = cert->subject().GetDisplayName();
cert_sct_ = cert_sct;
+ if (!verifier_) {
+ return QUIC_SUCCESS;
+ }
+
+ return verifier_->VerifyProof(
+ hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct,
+ signature, context, error_details, details, std::move(callback));
+ }
+
+ QuicAsyncStatus VerifyCertChain(
+ const std::string& hostname,
+ const std::vector<std::string>& certs,
+ const ProofVerifyContext* verify_context,
+ std::string* error_details,
+ std::unique_ptr<ProofVerifyDetails>* verify_details,
+ std::unique_ptr<ProofVerifierCallback> callback) override {
return QUIC_SUCCESS;
}
@@ -87,6 +114,7 @@ class RecordingProofVerifier : public ProofVerifier {
const string& cert_sct() const { return cert_sct_; }
private:
+ std::unique_ptr<ProofVerifier> verifier_;
string common_name_;
string cert_sct_;
};
@@ -103,9 +131,11 @@ BalsaHeaders* MungeHeaders(const BalsaHeaders* const_headers) {
}
BalsaHeaders* headers = new BalsaHeaders;
headers->CopyFrom(*const_headers);
- if (!uri.starts_with("https://") && !uri.starts_with("http://")) {
+ if (!base::StartsWith(uri, "https://",
+ base::CompareCase::INSENSITIVE_ASCII) &&
+ !base::StartsWith(uri, "http://", base::CompareCase::INSENSITIVE_ASCII)) {
// If we have a relative URL, set some defaults.
- string full_uri = "https://www.google.com";
+ string full_uri = "https://test.example.com";
full_uri.append(uri.as_string());
headers->SetRequestUri(full_uri);
}
@@ -129,14 +159,39 @@ MockableQuicClient::MockableQuicClient(
const QuicConfig& config,
const QuicVersionVector& supported_versions,
EpollServer* epoll_server)
+ : MockableQuicClient(server_address,
+ server_id,
+ config,
+ supported_versions,
+ epoll_server,
+ nullptr) {}
+
+MockableQuicClient::MockableQuicClient(
+ IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicConfig& config,
+ const QuicVersionVector& supported_versions,
+ EpollServer* epoll_server,
+ std::unique_ptr<ProofVerifier> proof_verifier)
: QuicClient(server_address,
server_id,
supported_versions,
config,
epoll_server,
- new RecordingProofVerifier()),
+ base::WrapUnique(
+ new RecordingProofVerifier(std::move(proof_verifier)))),
override_connection_id_(0),
- test_writer_(nullptr) {}
+ test_writer_(nullptr),
+ track_last_incoming_packet_(false) {}
+
+void MockableQuicClient::ProcessPacket(const IPEndPoint& self_address,
+ const IPEndPoint& peer_address,
+ const QuicReceivedPacket& packet) {
+ QuicClient::ProcessPacket(self_address, peer_address, packet);
+ if (track_last_incoming_packet_) {
+ last_incoming_packet_.reset(packet.Clone());
+ }
+}
MockableQuicClient::~MockableQuicClient() {
if (connected()) {
@@ -187,11 +242,31 @@ QuicTestClient::QuicTestClient(IPEndPoint server_address,
config,
supported_versions,
&epoll_server_)),
+ response_complete_(false),
allow_bidirectional_data_(false) {
Initialize();
}
-QuicTestClient::QuicTestClient() : allow_bidirectional_data_(false) {}
+QuicTestClient::QuicTestClient(IPEndPoint server_address,
+ const string& server_hostname,
+ const QuicConfig& config,
+ const QuicVersionVector& supported_versions,
+ std::unique_ptr<ProofVerifier> proof_verifier)
+ : client_(new MockableQuicClient(server_address,
+ QuicServerId(server_hostname,
+ server_address.port(),
+ PRIVACY_MODE_DISABLED),
+ config,
+ supported_versions,
+ &epoll_server_,
+ std::move(proof_verifier))),
+ response_complete_(false),
+ allow_bidirectional_data_(false) {
+ Initialize();
+}
+
+QuicTestClient::QuicTestClient()
+ : response_complete_(false), allow_bidirectional_data_(false) {}
QuicTestClient::~QuicTestClient() {
if (stream_) {
@@ -248,10 +323,10 @@ ssize_t QuicTestClient::GetOrCreateStreamAndSendRequest(
return 1;
if (rv == QUIC_PENDING) {
// May need to retry request if asynchronous rendezvous fails.
- auto* new_headers = new BalsaHeaders;
- new_headers->CopyFrom(*headers);
- push_promise_data_to_resend_.reset(
- new TestClientDataToResend(new_headers, body, fin, this, delegate));
+ std::unique_ptr<SpdyHeaderBlock> new_headers(new SpdyHeaderBlock(
+ SpdyBalsaUtils::RequestHeadersToSpdyHeaders(*headers)));
+ push_promise_data_to_resend_.reset(new TestClientDataToResend(
+ std::move(new_headers), body, fin, this, delegate));
return 1;
}
}
@@ -286,24 +361,29 @@ ssize_t QuicTestClient::GetOrCreateStreamAndSendRequest(
ret = body.length();
}
if (FLAGS_enable_quic_stateless_reject_support) {
- BalsaHeaders* new_headers = nullptr;
+ std::unique_ptr<SpdyHeaderBlock> new_headers;
if (headers) {
- new_headers = new BalsaHeaders;
- new_headers->CopyFrom(*headers);
+ new_headers.reset(new SpdyHeaderBlock(
+ SpdyBalsaUtils::RequestHeadersToSpdyHeaders(*headers)));
}
- auto* data_to_resend =
- new TestClientDataToResend(new_headers, body, fin, this, delegate);
- client()->MaybeAddQuicDataToResend(data_to_resend);
+ std::unique_ptr<QuicClientBase::QuicDataToResend> data_to_resend(
+ new TestClientDataToResend(std::move(new_headers), body, fin, this,
+ delegate));
+ client()->MaybeAddQuicDataToResend(std::move(data_to_resend));
}
return ret;
}
ssize_t QuicTestClient::SendMessage(const HTTPMessage& message) {
stream_ = nullptr; // Always force creation of a stream for SendMessage.
+ // Any response we might have received for a previous request would no longer
+ // be valid. TODO(jeffpiazza): There's probably additional client state that
+ // should be reset here, too, if we were being more careful.
+ response_complete_ = false;
// If we're not connected, try to find an sni hostname.
if (!connected()) {
- GURL url(message.headers()->request_uri().as_string());
+ GURL url(message.headers()->request_uri());
if (override_sni_set_) {
client_->set_server_id(QuicServerId(override_sni_, url.EffectiveIntPort(),
PRIVACY_MODE_DISABLED));
@@ -386,6 +466,14 @@ string QuicTestClient::SendSynchronousRequest(const string& uri) {
return SendCustomSynchronousRequest(message);
}
+void QuicTestClient::SetStream(QuicSpdyClientStream* stream) {
+ stream_ = stream;
+ if (stream_ != nullptr) {
+ response_complete_ = false;
+ stream_->set_visitor(this);
+ }
+}
+
QuicSpdyClientStream* QuicTestClient::GetOrCreateStream() {
if (!connect_attempted_ || auto_reconnect_) {
if (!connected()) {
@@ -396,14 +484,11 @@ QuicSpdyClientStream* QuicTestClient::GetOrCreateStream() {
}
}
if (!stream_) {
- stream_ = client_->CreateReliableClientStream();
- if (stream_ == nullptr) {
- return nullptr;
+ SetStream(client_->CreateReliableClientStream());
+ if (stream_) {
+ stream_->SetPriority(priority_);
+ stream_->set_allow_bidirectional_data(allow_bidirectional_data_);
}
- stream_->set_visitor(this);
- QuicSpdyClientStream* cs = reinterpret_cast<QuicSpdyClientStream*>(stream_);
- cs->SetPriority(priority_);
- cs->set_allow_bidirectional_data(allow_bidirectional_data_);
}
return stream_;
@@ -485,7 +570,7 @@ bool QuicTestClient::HaveActiveStream() {
!client_->session()->IsClosedStream(stream_->id()));
}
-void QuicTestClient::WaitForResponseForMs(int timeout_ms) {
+void QuicTestClient::WaitUntil(int timeout_ms, std::function<bool()> trigger) {
int64_t timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
int64_t old_timeout_us = epoll_server()->timeout_in_us();
if (timeout_us > 0) {
@@ -495,35 +580,16 @@ void QuicTestClient::WaitForResponseForMs(int timeout_ms) {
QuicConnectionPeer::GetHelper(client()->session()->connection())
->GetClock();
QuicTime end_waiting_time =
- clock->Now().Add(QuicTime::Delta::FromMicroseconds(timeout_us));
- while (HaveActiveStream() &&
+ clock->Now() + QuicTime::Delta::FromMicroseconds(timeout_us);
+ while (HaveActiveStream() && !(trigger && trigger()) &&
(timeout_us < 0 || clock->Now() < end_waiting_time)) {
client_->WaitForEvents();
}
if (timeout_us > 0) {
epoll_server()->set_timeout_in_us(old_timeout_us);
}
-}
-
-void QuicTestClient::WaitForInitialResponseForMs(int timeout_ms) {
- int64_t timeout_us = timeout_ms * base::Time::kMicrosecondsPerMillisecond;
- int64_t old_timeout_us = epoll_server()->timeout_in_us();
- if (timeout_us > 0) {
- epoll_server()->set_timeout_in_us(timeout_us);
- }
- const QuicClock* clock =
- QuicConnectionPeer::GetHelper(client()->session()->connection())
- ->GetClock();
- QuicTime end_waiting_time =
- clock->Now().Add(QuicTime::Delta::FromMicroseconds(timeout_us));
- while (stream_ != nullptr &&
- !client_->session()->IsClosedStream(stream_->id()) &&
- stream_->stream_bytes_read() == 0 &&
- (timeout_us < 0 || clock->Now() < end_waiting_time)) {
- client_->WaitForEvents();
- }
- if (timeout_us > 0) {
- epoll_server()->set_timeout_in_us(old_timeout_us);
+ if (trigger && !trigger()) {
+ VLOG(1) << "Client WaitUntil returning with trigger returning false.";
}
}
@@ -553,15 +619,27 @@ const SpdyHeaderBlock& QuicTestClient::response_trailers() const {
}
int64_t QuicTestClient::response_size() const {
- return bytes_read_;
+ return bytes_read();
}
size_t QuicTestClient::bytes_read() const {
- return bytes_read_;
+ // While stream_ is available, its member functions provide more accurate
+ // information. bytes_read_ is updated only when stream_ becomes null.
+ if (stream_) {
+ return stream_->stream_bytes_read() + stream_->header_bytes_read();
+ } else {
+ return bytes_read_;
+ }
}
size_t QuicTestClient::bytes_written() const {
- return bytes_written_;
+ // While stream_ is available, its member functions provide more accurate
+ // information. bytes_written_ is updated only when stream_ becomes null.
+ if (stream_) {
+ return stream_->stream_bytes_written() + stream_->header_bytes_written();
+ } else {
+ return bytes_written_;
+ }
}
void QuicTestClient::OnClose(QuicSpdyStream* stream) {
@@ -601,9 +679,8 @@ bool QuicTestClient::CheckVary(const SpdyHeaderBlock& client_request,
void QuicTestClient::OnRendezvousResult(QuicSpdyStream* stream) {
std::unique_ptr<TestClientDataToResend> data_to_resend =
std::move(push_promise_data_to_resend_);
- stream_ = static_cast<QuicSpdyClientStream*>(stream);
+ SetStream(static_cast<QuicSpdyClientStream*>(stream));
if (stream) {
- stream->set_visitor(this);
stream->OnDataAvailable();
} else if (data_to_resend.get()) {
data_to_resend->Resend();
@@ -662,12 +739,11 @@ void QuicTestClient::WaitForWriteToFlush() {
}
void QuicTestClient::TestClientDataToResend::Resend() {
- test_client_->GetOrCreateStreamAndSendRequest(headers_, body_, fin_,
+ BalsaHeaders balsa_headers;
+ SpdyBalsaUtils::SpdyHeadersToRequestHeaders(*headers_, &balsa_headers);
+ test_client_->GetOrCreateStreamAndSendRequest(&balsa_headers, body_, fin_,
delegate_);
- if (headers_ != nullptr) {
- delete headers_;
- headers_ = nullptr;
- }
+ headers_.reset();
}
// static
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 b76d1cfce20..3e52fc956db 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_client.h
+++ b/chromium/net/tools/quic/test_tools/quic_test_client.h
@@ -15,14 +15,15 @@
#include "base/macros.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/proto/cached_network_parameters.pb.h"
-#include "net/quic/quic_framer.h"
-#include "net/quic/quic_packet_creator.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/proto/cached_network_parameters.pb.h"
+#include "net/quic/core/quic_framer.h"
+#include "net/quic/core/quic_packet_creator.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/balsa/balsa_frame.h"
#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_client.h"
#include "net/tools/quic/test_tools/simple_client.h"
+#include "testing/gmock/include/gmock/gmock.h"
using base::StringPiece;
@@ -30,6 +31,7 @@ namespace net {
class ProofVerifier;
+class ProofVerifier;
class QuicPacketWriterWrapper;
namespace test {
@@ -37,7 +39,7 @@ namespace test {
class HTTPMessage;
class MockableQuicClient;
-// A quic client which allows mocking out writes.
+// A quic client which allows mocking out reads and writes.
class MockableQuicClient : public QuicClient {
public:
MockableQuicClient(IPEndPoint server_address,
@@ -51,7 +53,19 @@ class MockableQuicClient : public QuicClient {
const QuicVersionVector& supported_versions,
EpollServer* epoll_server);
+ MockableQuicClient(IPEndPoint server_address,
+ const QuicServerId& server_id,
+ const QuicConfig& config,
+ const QuicVersionVector& supported_versions,
+ EpollServer* epoll_server,
+ std::unique_ptr<ProofVerifier> proof_verifier);
+
~MockableQuicClient() override;
+
+ void ProcessPacket(const IPEndPoint& self_address,
+ const IPEndPoint& peer_address,
+ const QuicReceivedPacket& packet) override;
+
QuicPacketWriter* CreateQuicPacketWriter() override;
QuicConnectionId GenerateNewConnectionId() override;
void UseWriter(QuicPacketWriterWrapper* writer);
@@ -60,11 +74,21 @@ class MockableQuicClient : public QuicClient {
const CachedNetworkParameters& cached_network_params) {
cached_network_paramaters_ = cached_network_params;
}
+ const QuicReceivedPacket* last_incoming_packet() {
+ return last_incoming_packet_.get();
+ }
+ void set_track_last_incoming_packet(bool track) {
+ track_last_incoming_packet_ = track;
+ }
private:
QuicConnectionId override_connection_id_; // ConnectionId to use, if nonzero
QuicPacketWriterWrapper* test_writer_;
CachedNetworkParameters cached_network_paramaters_;
+ // The last incoming packet, iff |track_last_incoming_packet_| is true.
+ std::unique_ptr<QuicReceivedPacket> last_incoming_packet_;
+ // If true, copy each packet from ProcessPacket into |last_incoming_packet_|
+ bool track_last_incoming_packet_;
DISALLOW_COPY_AND_ASSIGN(MockableQuicClient);
};
@@ -81,6 +105,11 @@ class QuicTestClient : public test::SimpleClient,
const std::string& server_hostname,
const QuicConfig& config,
const QuicVersionVector& supported_versions);
+ QuicTestClient(IPEndPoint server_address,
+ const std::string& server_hostname,
+ const QuicConfig& config,
+ const QuicVersionVector& supported_versions,
+ std::unique_ptr<ProofVerifier> proof_verifier);
~QuicTestClient() override;
@@ -111,8 +140,7 @@ class QuicTestClient : public test::SimpleClient,
void Disconnect() override;
IPEndPoint local_address() const override;
void ClearPerRequestState() override;
- void WaitForResponseForMs(int timeout_ms) override;
- void WaitForInitialResponseForMs(int timeout_ms) override;
+ void WaitUntil(int timeout_ms, std::function<bool()> trigger) override;
ssize_t Send(const void* buffer, size_t size) override;
bool response_complete() const override;
bool response_headers_complete() const override;
@@ -157,6 +185,8 @@ class QuicTestClient : public test::SimpleClient,
// ConnectionId instead of a random one.
void UseConnectionId(QuicConnectionId connection_id);
+ // Update internal stream_ pointer and perform accompanying housekeeping.
+ void SetStream(QuicSpdyClientStream* stream);
// Returns nullptr if the maximum number of streams have already been created.
QuicSpdyClientStream* GetOrCreateStream();
@@ -202,6 +232,10 @@ class QuicTestClient : public test::SimpleClient,
size_t num_responses() const { return num_responses_; }
+ void set_server_address(const IPEndPoint& server_address) {
+ client_->set_server_address(server_address);
+ }
+
// Explicitly set the SNI value for this client, overriding the default
// behavior which extracts the SNI value from the request URL.
void OverrideSni(const std::string& sni) {
@@ -219,12 +253,12 @@ class QuicTestClient : public test::SimpleClient,
private:
class TestClientDataToResend : public QuicClient::QuicDataToResend {
public:
- TestClientDataToResend(BalsaHeaders* headers,
- StringPiece body,
+ TestClientDataToResend(std::unique_ptr<SpdyHeaderBlock> headers,
+ base::StringPiece body,
bool fin,
QuicTestClient* test_client,
QuicAckListenerInterface* delegate)
- : QuicClient::QuicDataToResend(headers, body, fin),
+ : QuicClient::QuicDataToResend(std::move(headers), body, fin),
test_client_(test_client),
delegate_(delegate) {}
@@ -257,6 +291,8 @@ class QuicTestClient : public test::SimpleClient,
SpdyPriority priority_;
std::string response_;
+ // bytes_read_ and bytes_written_ are updated only when stream_ is released;
+ // prefer bytes_read() and bytes_written() member functions.
uint64_t bytes_read_;
uint64_t bytes_written_;
// The number of uncompressed HTTP header bytes received.
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 1edf41a448f..6c400a52fe3 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_server.cc
+++ b/chromium/net/tools/quic/test_tools/quic_test_server.cc
@@ -10,19 +10,19 @@
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
-#include "net/quic/crypto/crypto_handshake.h"
-#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/crypto/quic_random.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/quic/quic_config.h"
-#include "net/quic/quic_connection.h"
-#include "net/quic/quic_packet_writer.h"
-#include "net/quic/quic_protocol.h"
-#include "net/tools/quic/quic_dispatcher.h"
+#include "net/quic/chromium/quic_chromium_connection_helper.h"
+#include "net/quic/core/crypto/crypto_handshake.h"
+#include "net/quic/core/crypto/quic_crypto_server_config.h"
+#include "net/quic/core/crypto/quic_random.h"
+#include "net/quic/core/quic_config.h"
+#include "net/quic/core/quic_connection.h"
+#include "net/quic/core/quic_packet_writer.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/tools/quic/quic_epoll_alarm_factory.h"
#include "net/tools/quic/quic_epoll_connection_helper.h"
+#include "net/tools/quic/quic_simple_crypto_server_stream_helper.h"
+#include "net/tools/quic/quic_simple_dispatcher.h"
#include "net/tools/quic/quic_simple_server_session.h"
-#include "net/tools/quic/quic_simple_server_session_helper.h"
#include "net/tools/quic/quic_simple_server_stream.h"
namespace net {
@@ -34,7 +34,7 @@ class CustomStreamSession : public QuicSimpleServerSession {
const QuicConfig& config,
QuicConnection* connection,
QuicServerSessionBase::Visitor* visitor,
- QuicServerSessionBase::Helper* helper,
+ QuicCryptoServerStream::Helper* helper,
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache,
QuicTestServer::StreamFactory* factory,
@@ -75,21 +75,21 @@ class CustomStreamSession : public QuicSimpleServerSession {
QuicTestServer::CryptoStreamFactory* crypto_stream_factory_; // Not owned.
};
-class QuicTestDispatcher : public QuicDispatcher {
+class QuicTestDispatcher : public QuicSimpleDispatcher {
public:
QuicTestDispatcher(
const QuicConfig& config,
const QuicCryptoServerConfig* crypto_config,
- const QuicVersionVector& versions,
+ QuicVersionManager* version_manager,
std::unique_ptr<QuicConnectionHelperInterface> helper,
- std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
+ std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
std::unique_ptr<QuicAlarmFactory> alarm_factory)
- : QuicDispatcher(config,
- crypto_config,
- versions,
- std::move(helper),
- std::move(session_helper),
- std::move(alarm_factory)),
+ : QuicSimpleDispatcher(config,
+ crypto_config,
+ version_manager,
+ std::move(helper),
+ std::move(session_helper),
+ std::move(alarm_factory)),
session_factory_(nullptr),
stream_factory_(nullptr),
crypto_stream_factory_(nullptr) {}
@@ -99,7 +99,7 @@ class QuicTestDispatcher : public QuicDispatcher {
base::AutoLock lock(factory_lock_);
if (session_factory_ == nullptr && stream_factory_ == nullptr &&
crypto_stream_factory_ == nullptr) {
- return QuicDispatcher::CreateQuicSession(id, client);
+ return QuicSimpleDispatcher::CreateQuicSession(id, client);
}
QuicConnection* connection = new QuicConnection(
id, client, helper(), alarm_factory(), CreatePerConnectionWriter(),
@@ -149,24 +149,24 @@ class QuicTestDispatcher : public QuicDispatcher {
QuicTestServer::CryptoStreamFactory* crypto_stream_factory_; // Not owned.
};
-QuicTestServer::QuicTestServer(ProofSource* proof_source)
- : QuicServer(proof_source) {}
+QuicTestServer::QuicTestServer(std::unique_ptr<ProofSource> proof_source)
+ : QuicServer(std::move(proof_source)) {}
-QuicTestServer::QuicTestServer(ProofSource* proof_source,
+QuicTestServer::QuicTestServer(std::unique_ptr<ProofSource> proof_source,
const QuicConfig& config,
const QuicVersionVector& supported_versions)
- : QuicServer(proof_source,
+ : QuicServer(std::move(proof_source),
config,
QuicCryptoServerConfig::ConfigOptions(),
supported_versions) {}
QuicDispatcher* QuicTestServer::CreateQuicDispatcher() {
return new QuicTestDispatcher(
- config(), &crypto_config(), supported_versions(),
+ config(), &crypto_config(), version_manager(),
std::unique_ptr<QuicEpollConnectionHelper>(new QuicEpollConnectionHelper(
epoll_server(), QuicAllocator::BUFFER_POOL)),
- std::unique_ptr<QuicServerSessionBase::Helper>(
- new QuicSimpleServerSessionHelper(QuicRandom::GetInstance())),
+ std::unique_ptr<QuicCryptoServerStream::Helper>(
+ new QuicSimpleCryptoServerStreamHelper(QuicRandom::GetInstance())),
std::unique_ptr<QuicEpollAlarmFactory>(
new QuicEpollAlarmFactory(epoll_server())));
}
@@ -191,7 +191,7 @@ ImmediateGoAwaySession::ImmediateGoAwaySession(
const QuicConfig& config,
QuicConnection* connection,
QuicServerSessionBase::Visitor* visitor,
- QuicServerSessionBase::Helper* helper,
+ QuicCryptoServerStream::Helper* helper,
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache)
: QuicSimpleServerSession(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 071466853e5..75084bc0455 100644
--- a/chromium/net/tools/quic/test_tools/quic_test_server.h
+++ b/chromium/net/tools/quic/test_tools/quic_test_server.h
@@ -9,7 +9,7 @@
#include <string>
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_session.h"
+#include "net/quic/core/quic_session.h"
#include "net/tools/quic/quic_dispatcher.h"
#include "net/tools/quic/quic_server.h"
#include "net/tools/quic/quic_simple_server_session.h"
@@ -35,7 +35,7 @@ class QuicTestServer : public QuicServer {
const QuicConfig& config,
QuicConnection* connection,
QuicServerSessionBase::Visitor* visitor,
- QuicServerSessionBase::Helper* helper,
+ QuicCryptoServerStream::Helper* helper,
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache) = 0;
};
@@ -60,8 +60,8 @@ class QuicTestServer : public QuicServer {
QuicServerSessionBase* session) = 0;
};
- explicit QuicTestServer(ProofSource* proof_source);
- QuicTestServer(ProofSource* proof_source,
+ explicit QuicTestServer(std::unique_ptr<ProofSource> proof_source);
+ QuicTestServer(std::unique_ptr<ProofSource> proof_source,
const QuicConfig& config,
const QuicVersionVector& supported_versions);
@@ -91,7 +91,7 @@ class ImmediateGoAwaySession : public QuicSimpleServerSession {
ImmediateGoAwaySession(const QuicConfig& config,
QuicConnection* connection,
QuicServerSessionBase::Visitor* visitor,
- QuicServerSessionBase::Helper* helper,
+ QuicCryptoServerStream::Helper* helper,
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache);
// Override to send GoAway.
diff --git a/chromium/net/tools/quic/test_tools/server_thread.h b/chromium/net/tools/quic/test_tools/server_thread.h
index b907fd16010..898679dae4c 100644
--- a/chromium/net/tools/quic/test_tools/server_thread.h
+++ b/chromium/net/tools/quic/test_tools/server_thread.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "base/threading/simple_thread.h"
#include "net/base/ip_endpoint.h"
-#include "net/quic/quic_config.h"
+#include "net/quic/core/quic_config.h"
#include "net/tools/quic/quic_server.h"
namespace net {
diff --git a/chromium/net/tools/quic/test_tools/simple_client.cc b/chromium/net/tools/quic/test_tools/simple_client.cc
index 3559da1375e..f6ac39f3c56 100644
--- a/chromium/net/tools/quic/test_tools/simple_client.cc
+++ b/chromium/net/tools/quic/test_tools/simple_client.cc
@@ -4,6 +4,8 @@
#include "net/tools/quic/test_tools/simple_client.h"
+#include "net/tools/balsa/balsa_headers.h"
+
namespace net {
namespace test {
@@ -16,6 +18,18 @@ void SimpleClient::WaitForInitialResponse() {
WaitForInitialResponseForMs(-1);
}
+void SimpleClient::WaitForResponseForMs(int timeout_ms) {
+ WaitUntil(timeout_ms, [this]() { return response_complete(); });
+ if (response_complete()) {
+ VLOG(1) << "Client received response:" << response_headers()->DebugString()
+ << response_body();
+ }
+}
+
+void SimpleClient::WaitForInitialResponseForMs(int timeout_ms) {
+ WaitUntil(timeout_ms, [this]() { return response_size() != 0; });
+}
+
int SimpleClient::ResetSocket() {
LOG(FATAL) << "SimpleClient::ResetSocket is not implemented";
return 0;
diff --git a/chromium/net/tools/quic/test_tools/simple_client.h b/chromium/net/tools/quic/test_tools/simple_client.h
index 3c5d02cfd0a..68b5c897d51 100644
--- a/chromium/net/tools/quic/test_tools/simple_client.h
+++ b/chromium/net/tools/quic/test_tools/simple_client.h
@@ -55,11 +55,13 @@ class SimpleClient {
// Returns once a complete response or a connection close has been received
// from the server, or once the timeout expires. -1 for no timeout.
- virtual void WaitForResponseForMs(int timeout_ms) = 0;
+ virtual void WaitForResponseForMs(int timeout_ms);
// Waits for some data or response from the server, or once the timeout
// expires. -1 for no timeout.
- virtual void WaitForInitialResponseForMs(int timeout_ms) = 0;
+ virtual void WaitForInitialResponseForMs(int timeout_ms);
+
+ virtual void WaitUntil(int timeout_ms, std::function<bool()> trigger) = 0;
// Clears any outstanding state from the last request.
virtual void ClearPerRequestState() = 0;
diff --git a/chromium/net/tools/testserver/minica.py b/chromium/net/tools/testserver/minica.py
index acf68fcbb93..d7f39a1d691 100644
--- a/chromium/net/tools/testserver/minica.py
+++ b/chromium/net/tools/testserver/minica.py
@@ -3,9 +3,31 @@
# found in the LICENSE file.
import asn1
+import datetime
import hashlib
+import itertools
import os
+import time
+GENERALIZED_TIME_FORMAT = "%Y%m%d%H%M%SZ"
+
+OCSP_STATE_GOOD = 1
+OCSP_STATE_REVOKED = 2
+OCSP_STATE_INVALID_RESPONSE = 3
+OCSP_STATE_UNAUTHORIZED = 4
+OCSP_STATE_UNKNOWN = 5
+OCSP_STATE_TRY_LATER = 6
+OCSP_STATE_INVALID_RESPONSE_DATA = 7
+OCSP_STATE_MISMATCHED_SERIAL = 8
+
+OCSP_DATE_VALID = 1
+OCSP_DATE_OLD = 2
+OCSP_DATE_EARLY = 3
+OCSP_DATE_LONG = 4
+
+OCSP_PRODUCED_VALID = 1
+OCSP_PRODUCED_BEFORE_CERT = 2
+OCSP_PRODUCED_AFTER_CERT = 3
# This file implements very minimal certificate and OCSP generation. It's
# designed to test revocation checking.
@@ -137,20 +159,19 @@ CERT_POLICY_OID = asn1.OID([1, 3, 6, 1, 4, 1, 11129, 2, 4, 1])
# These result in the following root certificate:
# -----BEGIN CERTIFICATE-----
-# MIIB0TCCATqgAwIBAgIBATANBgkqhkiG9w0BAQUFADAVMRMwEQYDVQQDEwpUZXN0aW5nIENBMB4X
+# MIIBzTCCATagAwIBAgIBATANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwpUZXN0aW5nIENBMB4X
# DTEwMDEwMTA2MDAwMFoXDTMyMTIwMTA2MDAwMFowFTETMBEGA1UEAxMKVGVzdGluZyBDQTCBnTAN
# BgkqhkiG9w0BAQEFAAOBiwAwgYcCgYEApxmY8pML/nPQMah/Ez0vN47u7tUqd+RND8n/bwf/Msvz
# 2pmd5O1lgyr8sIB/mHh1BlOdJYoM48LHeWdlMJmpA0qbEVqHbDmoxOTtSs0MZAlZRvs57utHoHBN
-# uwGKz0jDocS4lfxAn7SjQKmGsa/EVRmrnspHwwGFx3HGSqXs8H0CAQOjMzAxMBIGA1UdEwEB/wQI
-# MAYBAf8CAQAwGwYDVR0gAQEABBEwDzANBgsrBgEEAdZ5AgHODzANBgkqhkiG9w0BAQUFAAOBgQA/
-# STb40A6D+93jMfLGQzXc997IsaJZdoPt7tYa8PqGJBL62EiTj+erd/H5pDZx/2/bcpOG4m9J56yg
-# wOohbllw2TM+oeEd8syzV6X+1SIPnGI56JRrm3UXcHYx1Rq5loM9WKAiz/WmIWmskljsEQ7+542p
-# q0pkHjs8nuXovSkUYA==
+# uwGKz0jDocS4lfxAn7SjQKmGsa/EVRmrnspHwwGFx3HGSqXs8H0CAQOjLzAtMBIGA1UdEwEB/wQI
+# MAYBAf8CAQAwFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgQBMA0GCSqGSIb3DQEBCwUAA4GBAHJJigXg
+# ArH/E9n3AilgivA58hawSRVqiTHHv7oAguDRrA4zC8IvsL6b/6LV7nA3KWM0OUSZSGE3zQb9UlB2
+# nNYsPMdv0Ls4GuOzVfy4bnQXqMWIflRw9L5Z5KH8Vu5U3ohoOUCfWN1sYMoeS9/22K9xtRsDPS+d
+# pQo7Q6ZoOo8o
# -----END CERTIFICATE-----
-# If you update any of the above, you can generate a new root with the
-# following line:
-# print DERToPEM(MakeCertificate(ISSUER_CN, ISSUER_CN, 1, KEY, KEY, None))
+# If you update any of the above, you can generate a new root by running this
+# file as a script.
# Various OIDs
@@ -183,7 +204,7 @@ def MakeCertificate(
o = None
extensions.children.append(
asn1.SEQUENCE([
- basic_constraints,
+ BASIC_CONSTRAINTS,
True,
asn1.OCTETSTRING(asn1.ToDER(asn1.SEQUENCE([
True, # IsCA
@@ -195,7 +216,8 @@ def MakeCertificate(
extensions.children.append(
asn1.SEQUENCE([
AUTHORITY_INFORMATION_ACCESS,
- False,
+ # There is implicitly a critical=False here. Since false is the default,
+ # encoding the value would be invalid DER.
asn1.OCTETSTRING(asn1.ToDER(asn1.SEQUENCE([
asn1.SEQUENCE([
AIA_OCSP,
@@ -207,7 +229,8 @@ def MakeCertificate(
extensions.children.append(
asn1.SEQUENCE([
CERT_POLICIES,
- False,
+ # There is implicitly a critical=False here. Since false is the default,
+ # encoding the value would be invalid DER.
asn1.OCTETSTRING(asn1.ToDER(asn1.SEQUENCE([
asn1.SEQUENCE([ # PolicyInformation
CERT_POLICY_OID,
@@ -245,15 +268,8 @@ def MakeCertificate(
asn1.BitString(privkey.Sign(tbsCert)),
]))
-
-def MakeOCSPResponse(issuer_cn, issuer_key, serial, ocsp_state):
- # https://tools.ietf.org/html/rfc2560
- issuer_name_hash = asn1.OCTETSTRING(
- hashlib.sha1(asn1.ToDER(Name(cn = issuer_cn))).digest())
-
- issuer_key_hash = asn1.OCTETSTRING(
- hashlib.sha1(asn1.ToDER(issuer_key)).digest())
-
+def MakeOCSPSingleResponse(
+ issuer_name_hash, issuer_key_hash, serial, ocsp_state, ocsp_date):
cert_status = None
if ocsp_state == OCSP_STATE_REVOKED:
cert_status = asn1.Explicit(1, asn1.GeneralizedTime("20100101060000Z"))
@@ -261,28 +277,79 @@ def MakeOCSPResponse(issuer_cn, issuer_key, serial, ocsp_state):
cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 2, 0))
elif ocsp_state == OCSP_STATE_GOOD:
cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 0, 0))
+ elif ocsp_state == OCSP_STATE_MISMATCHED_SERIAL:
+ cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 0, 0))
+ serial -= 1
else:
raise ValueError('Bad OCSP state: ' + str(ocsp_state))
- basic_resp_data_der = asn1.ToDER(asn1.SEQUENCE([
- asn1.Explicit(2, issuer_key_hash),
- asn1.GeneralizedTime("20100101060000Z"), # producedAt
- asn1.SEQUENCE([
- asn1.SEQUENCE([ # SingleResponse
- asn1.SEQUENCE([ # CertID
- asn1.SEQUENCE([ # hashAlgorithm
- HASH_SHA1,
- None,
- ]),
- issuer_name_hash,
- issuer_key_hash,
- serial,
- ]),
- cert_status,
- asn1.GeneralizedTime("20100101060000Z"), # thisUpdate
- asn1.Explicit(0, asn1.GeneralizedTime("20300101060000Z")), # nextUpdate
+ now = datetime.datetime.fromtimestamp(time.mktime(time.gmtime()))
+ if ocsp_date == OCSP_DATE_VALID:
+ thisUpdate = now - datetime.timedelta(days=1)
+ nextUpdate = thisUpdate + datetime.timedelta(weeks=1)
+ elif ocsp_date == OCSP_DATE_OLD:
+ thisUpdate = now - datetime.timedelta(days=1, weeks=1)
+ nextUpdate = thisUpdate + datetime.timedelta(weeks=1)
+ elif ocsp_date == OCSP_DATE_EARLY:
+ thisUpdate = now + datetime.timedelta(days=1)
+ nextUpdate = thisUpdate + datetime.timedelta(weeks=1)
+ elif ocsp_date == OCSP_DATE_LONG:
+ thisUpdate = now - datetime.timedelta(days=365)
+ nextUpdate = thisUpdate + datetime.timedelta(days=366)
+ else:
+ raise ValueError('Bad OCSP date: ' + str(ocsp_date))
+
+ return asn1.SEQUENCE([ # SingleResponse
+ asn1.SEQUENCE([ # CertID
+ asn1.SEQUENCE([ # hashAlgorithm
+ HASH_SHA1,
+ None,
]),
+ issuer_name_hash,
+ issuer_key_hash,
+ serial,
]),
+ cert_status,
+ asn1.GeneralizedTime( # thisUpdate
+ thisUpdate.strftime(GENERALIZED_TIME_FORMAT)
+ ),
+ asn1.Explicit( # nextUpdate
+ 0,
+ asn1.GeneralizedTime(nextUpdate.strftime(GENERALIZED_TIME_FORMAT))
+ ),
+ ])
+
+def MakeOCSPResponse(
+ issuer_cn, issuer_key, serial, ocsp_states, ocsp_dates, ocsp_produced):
+ # https://tools.ietf.org/html/rfc2560
+ issuer_name_hash = asn1.OCTETSTRING(
+ hashlib.sha1(asn1.ToDER(Name(cn = issuer_cn))).digest())
+
+ issuer_key_hash = asn1.OCTETSTRING(
+ hashlib.sha1(asn1.ToDER(issuer_key)).digest())
+
+ now = datetime.datetime.fromtimestamp(time.mktime(time.gmtime()))
+ if ocsp_produced == OCSP_PRODUCED_VALID:
+ producedAt = now - datetime.timedelta(days=1)
+ elif ocsp_produced == OCSP_PRODUCED_BEFORE_CERT:
+ producedAt = datetime.datetime.strptime(
+ "19100101050000Z", GENERALIZED_TIME_FORMAT)
+ elif ocsp_produced == OCSP_PRODUCED_AFTER_CERT:
+ producedAt = datetime.datetime.strptime(
+ "20321201070000Z", GENERALIZED_TIME_FORMAT)
+ else:
+ raise ValueError('Bad OCSP produced: ' + str(ocsp_produced))
+
+ single_responses = [
+ MakeOCSPSingleResponse(issuer_name_hash, issuer_key_hash, serial,
+ ocsp_state, ocsp_date)
+ for ocsp_state, ocsp_date in itertools.izip(ocsp_states, ocsp_dates)
+ ]
+
+ basic_resp_data_der = asn1.ToDER(asn1.SEQUENCE([
+ asn1.Explicit(2, issuer_key_hash),
+ asn1.GeneralizedTime(producedAt.strftime(GENERALIZED_TIME_FORMAT)),
+ asn1.SEQUENCE(single_responses),
]))
basic_resp = asn1.SEQUENCE([
@@ -311,19 +378,15 @@ def DERToPEM(der):
pem += '-----END CERTIFICATE-----\n'
return pem
-OCSP_STATE_GOOD = 1
-OCSP_STATE_REVOKED = 2
-OCSP_STATE_INVALID = 3
-OCSP_STATE_UNAUTHORIZED = 4
-OCSP_STATE_UNKNOWN = 5
-
# unauthorizedDER is an OCSPResponse with a status of 6:
# SEQUENCE { ENUM(6) }
unauthorizedDER = '30030a0106'.decode('hex')
def GenerateCertKeyAndOCSP(subject = "127.0.0.1",
ocsp_url = "http://127.0.0.1",
- ocsp_state = OCSP_STATE_GOOD,
+ ocsp_states = None,
+ ocsp_dates = None,
+ ocsp_produced = OCSP_PRODUCED_VALID,
serial = 0):
'''GenerateCertKeyAndOCSP returns a (cert_and_key_pem, ocsp_der) where:
* cert_and_key_pem contains a certificate and private key in PEM format
@@ -331,6 +394,11 @@ def GenerateCertKeyAndOCSP(subject = "127.0.0.1",
* ocsp_der contains a DER encoded OCSP response or None if ocsp_url is
None'''
+ if ocsp_states is None:
+ ocsp_states = [OCSP_STATE_GOOD]
+ if ocsp_dates is None:
+ ocsp_dates = [OCSP_DATE_VALID]
+
if serial == 0:
serial = RandomNumber(16)
cert_der = MakeCertificate(ISSUER_CN, bytes(subject), serial, KEY, KEY,
@@ -339,11 +407,57 @@ def GenerateCertKeyAndOCSP(subject = "127.0.0.1",
ocsp_der = None
if ocsp_url is not None:
- if ocsp_state == OCSP_STATE_UNAUTHORIZED:
+ if ocsp_states[0] == OCSP_STATE_UNAUTHORIZED:
ocsp_der = unauthorizedDER
- elif ocsp_state == OCSP_STATE_INVALID:
+ elif ocsp_states[0] == OCSP_STATE_INVALID_RESPONSE:
ocsp_der = '3'
+ elif ocsp_states[0] == OCSP_STATE_TRY_LATER:
+ resp = asn1.SEQUENCE([
+ asn1.ENUMERATED(3),
+ ])
+ ocsp_der = asn1.ToDER(resp)
+ elif ocsp_states[0] == OCSP_STATE_INVALID_RESPONSE_DATA:
+ invalid_data = asn1.ToDER(asn1.OCTETSTRING('not ocsp data'))
+ basic_resp = asn1.SEQUENCE([
+ asn1.Raw(invalid_data),
+ asn1.SEQUENCE([
+ SHA256_WITH_RSA_ENCRYPTION,
+ None,
+ ]),
+ asn1.BitString(KEY.Sign(invalid_data)),
+ ])
+ resp = asn1.SEQUENCE([
+ asn1.ENUMERATED(0),
+ asn1.Explicit(0, asn1.SEQUENCE([
+ OCSP_TYPE_BASIC,
+ asn1.OCTETSTRING(asn1.ToDER(basic_resp)),
+ ])),
+ ])
+ ocsp_der = asn1.ToDER(resp)
else:
- ocsp_der = MakeOCSPResponse(ISSUER_CN, KEY, serial, ocsp_state)
+ ocsp_der = MakeOCSPResponse(
+ ISSUER_CN, KEY, serial, ocsp_states, ocsp_dates, ocsp_produced)
return (cert_pem + KEY_PEM, ocsp_der)
+
+
+if __name__ == '__main__':
+ def bin_to_array(s):
+ return ' '.join(['0x%02x,'%ord(c) for c in s])
+
+ import sys
+ sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..',
+ '..', 'data', 'ssl', 'scripts'))
+ import crlsetutil
+
+ der_root = MakeCertificate(ISSUER_CN, ISSUER_CN, 1, KEY, KEY, None)
+ print 'ocsp-test-root.pem:'
+ print DERToPEM(der_root)
+
+ print
+ print 'kOCSPTestCertFingerprint:'
+ print bin_to_array(hashlib.sha1(der_root).digest())
+
+ print
+ print 'kOCSPTestCertSPKI:'
+ print bin_to_array(crlsetutil.der_cert_to_spki_hash(der_root))
diff --git a/chromium/net/tools/testserver/run_testserver.cc b/chromium/net/tools/testserver/run_testserver.cc
index 6da829d9f31..8e30710a47e 100644
--- a/chromium/net/tools/testserver/run_testserver.cc
+++ b/chromium/net/tools/testserver/run_testserver.cc
@@ -9,6 +9,7 @@
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/test_timeouts.h"
#include "net/test/spawned_test_server/spawned_test_server.h"
@@ -121,6 +122,6 @@ int main(int argc, const char* argv[]) {
printf("testserver running at %s (type ctrl+c to exit)\n",
test_server->host_port_pair().ToString().c_str());
- message_loop.Run();
+ base::RunLoop().Run();
return 0;
}
diff --git a/chromium/net/tools/testserver/testserver.py b/chromium/net/tools/testserver/testserver.py
index ba130af9943..e8241cb6e38 100755
--- a/chromium/net/tools/testserver/testserver.py
+++ b/chromium/net/tools/testserver/testserver.py
@@ -80,6 +80,13 @@ SERVER_WEBSOCKET = 5
# Default request queue size for WebSocketServer.
_DEFAULT_REQUEST_QUEUE_SIZE = 128
+OCSP_STATES_NO_SINGLE_RESPONSE = {
+ minica.OCSP_STATE_INVALID_RESPONSE,
+ minica.OCSP_STATE_UNAUTHORIZED,
+ minica.OCSP_STATE_TRY_LATER,
+ minica.OCSP_STATE_INVALID_RESPONSE_DATA,
+}
+
class WebSocketOptions:
"""Holds options for WebSocketServer."""
@@ -154,8 +161,8 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
def __init__(self, server_address, request_hander_class, pem_cert_and_key,
ssl_client_auth, ssl_client_cas, ssl_client_cert_types,
- ssl_bulk_ciphers, ssl_key_exchanges, npn_protocols,
- record_resume_info, tls_intolerant,
+ ssl_bulk_ciphers, ssl_key_exchanges, alpn_protocols,
+ npn_protocols, record_resume_info, tls_intolerant,
tls_intolerance_type, signed_cert_timestamps,
fallback_scsv_enabled, ocsp_response,
alert_after_handshake, disable_channel_id, disable_ems,
@@ -208,6 +215,7 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
self.ssl_handshake_settings.enableExtendedMasterSecret = False
self.ssl_handshake_settings.supportedTokenBindingParams = \
token_binding_params
+ self.ssl_handshake_settings.alpnProtos=alpn_protocols;
if record_resume_info:
# If record_resume_info is true then we'll replace the session cache with
@@ -1534,7 +1542,7 @@ class TestPageHandler(testserver_base.BasePageHandler):
return True
def ForwardTokenBindingHeader(self):
- """Send a redirect that sets the Include-Referer-Token-Binding-ID
+ """Send a redirect that sets the Include-Referred-Token-Binding-ID
header."""
test_name = '/forward-tokbind'
@@ -1549,7 +1557,7 @@ class TestPageHandler(testserver_base.BasePageHandler):
self.send_response(302)
self.send_header('Location', dest)
- self.send_header('Include-Referer-Token-Binding-ID', 'true')
+ self.send_header('Include-Referred-Token-Binding-ID', 'true')
self.end_headers()
return True
@@ -1896,27 +1904,71 @@ class ServerRunner(testserver_base.TestServerRunner):
print ('OCSP server started on %s:%d...' %
(host, self.__ocsp_server.server_port))
- ocsp_state = None
-
- if self.options.ocsp == 'ok':
- ocsp_state = minica.OCSP_STATE_GOOD
- elif self.options.ocsp == 'revoked':
- ocsp_state = minica.OCSP_STATE_REVOKED
- elif self.options.ocsp == 'invalid':
- ocsp_state = minica.OCSP_STATE_INVALID
- elif self.options.ocsp == 'unauthorized':
- ocsp_state = minica.OCSP_STATE_UNAUTHORIZED
- elif self.options.ocsp == 'unknown':
- ocsp_state = minica.OCSP_STATE_UNKNOWN
+ ocsp_states = list()
+ for ocsp_state_arg in self.options.ocsp.split(':'):
+ if ocsp_state_arg == 'ok':
+ ocsp_state = minica.OCSP_STATE_GOOD
+ elif ocsp_state_arg == 'revoked':
+ ocsp_state = minica.OCSP_STATE_REVOKED
+ elif ocsp_state_arg == 'invalid':
+ ocsp_state = minica.OCSP_STATE_INVALID_RESPONSE
+ elif ocsp_state_arg == 'unauthorized':
+ ocsp_state = minica.OCSP_STATE_UNAUTHORIZED
+ elif ocsp_state_arg == 'unknown':
+ ocsp_state = minica.OCSP_STATE_UNKNOWN
+ elif ocsp_state_arg == 'later':
+ ocsp_state = minica.OCSP_STATE_TRY_LATER
+ elif ocsp_state_arg == 'invalid_data':
+ ocsp_state = minica.OCSP_STATE_INVALID_RESPONSE_DATA
+ elif ocsp_state_arg == "mismatched_serial":
+ ocsp_state = minica.OCSP_STATE_MISMATCHED_SERIAL
+ else:
+ raise testserver_base.OptionError('unknown OCSP status: ' +
+ ocsp_state_arg)
+ ocsp_states.append(ocsp_state)
+
+ if len(ocsp_states) > 1:
+ if set(ocsp_states) & OCSP_STATES_NO_SINGLE_RESPONSE:
+ raise testserver_base.OptionError('Multiple OCSP responses '
+ 'incompatible with states ' + str(ocsp_states))
+
+ ocsp_dates = list()
+ for ocsp_date_arg in self.options.ocsp_date.split(':'):
+ if ocsp_date_arg == 'valid':
+ ocsp_date = minica.OCSP_DATE_VALID
+ elif ocsp_date_arg == 'old':
+ ocsp_date = minica.OCSP_DATE_OLD
+ elif ocsp_date_arg == 'early':
+ ocsp_date = minica.OCSP_DATE_EARLY
+ elif ocsp_date_arg == 'long':
+ ocsp_date = minica.OCSP_DATE_LONG
+ else:
+ raise testserver_base.OptionError('unknown OCSP date: ' +
+ ocsp_date_arg)
+ ocsp_dates.append(ocsp_date)
+
+ if len(ocsp_states) != len(ocsp_dates):
+ raise testserver_base.OptionError('mismatched ocsp and ocsp-date '
+ 'count')
+
+ ocsp_produced = None
+ if self.options.ocsp_produced == 'valid':
+ ocsp_produced = minica.OCSP_PRODUCED_VALID
+ elif self.options.ocsp_produced == 'before':
+ ocsp_produced = minica.OCSP_PRODUCED_BEFORE_CERT
+ elif self.options.ocsp_produced == 'after':
+ ocsp_produced = minica.OCSP_PRODUCED_AFTER_CERT
else:
- raise testserver_base.OptionError('unknown OCSP status: ' +
- self.options.ocsp_status)
+ raise testserver_base.OptionError('unknown OCSP produced: ' +
+ self.options.ocsp_produced)
(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)),
- ocsp_state = ocsp_state,
+ ocsp_states = ocsp_states,
+ ocsp_dates = ocsp_dates,
+ ocsp_produced = ocsp_produced,
serial = self.options.cert_serial)
if self.options.ocsp_server_unavailable:
@@ -1941,6 +1993,7 @@ class ServerRunner(testserver_base.TestServerRunner):
self.options.ssl_client_cert_type,
self.options.ssl_bulk_cipher,
self.options.ssl_key_exchange,
+ self.options.alpn_protocols,
self.options.npn_protocols,
self.options.record_resume,
self.options.tls_intolerant,
@@ -2088,6 +2141,12 @@ class ServerRunner(testserver_base.TestServerRunner):
help='The type of OCSP response generated '
'for the automatically generated '
'certificate. One of [ok,revoked,invalid]')
+ self.option_parser.add_option('--ocsp-date', dest='ocsp_date',
+ default='valid', help='The validity of the '
+ 'range between thisUpdate and nextUpdate')
+ self.option_parser.add_option('--ocsp-produced', dest='ocsp_produced',
+ default='valid', help='producedAt relative '
+ 'to certificate expiry')
self.option_parser.add_option('--cert-serial', dest='cert_serial',
default=0, type=int,
help='If non-zero then the generated '
@@ -2169,9 +2228,13 @@ class ServerRunner(testserver_base.TestServerRunner):
'will be used. This option may appear '
'multiple times, indicating multiple '
'algorithms should be enabled.');
- # TODO(davidben): Add ALPN support to tlslite.
+ self.option_parser.add_option('--alpn-protocols', action='append',
+ help='Specify the list of ALPN protocols. '
+ 'The server will not send an ALPN response '
+ 'if this list does not overlap with the '
+ 'list of protocols the client advertises.')
self.option_parser.add_option('--npn-protocols', action='append',
- help='Specify the list of protocols sent in'
+ help='Specify the list of protocols sent in '
'an NPN response. The server will not'
'support NPN if the list is empty.')
self.option_parser.add_option('--file-root-url', default='/files/',
diff --git a/chromium/net/tools/tld_cleanup/tld_cleanup.gyp b/chromium/net/tools/tld_cleanup/tld_cleanup.gyp
deleted file mode 100644
index dc0c45fac7b..00000000000
--- a/chromium/net/tools/tld_cleanup/tld_cleanup.gyp
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright (c) 2009 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.
-
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'targets': [
- {
- 'target_name': 'tld_cleanup_util',
- 'type': 'static_library',
- 'dependencies': [
- '../../../base/base.gyp:base',
- '../../../url/url.gyp:url_lib',
- ],
- 'sources': [
- 'tld_cleanup_util.cc',
- 'tld_cleanup_util.h',
- ],
- },
- ],
-}
diff --git a/chromium/net/tools/tld_cleanup/tld_cleanup_util.cc b/chromium/net/tools/tld_cleanup/tld_cleanup_util.cc
index f4d93ac0b17..6ed431f1177 100644
--- a/chromium/net/tools/tld_cleanup/tld_cleanup_util.cc
+++ b/chromium/net/tools/tld_cleanup/tld_cleanup_util.cc
@@ -165,7 +165,7 @@ NormalizeResult NormalizeDataToRuleMap(const std::string data,
line_end = data.find_first_of("\r\n \t", line_start);
if (line_end == std::string::npos)
line_end = data.size();
- domain.assign(data.data(), line_start, line_end - line_start);
+ domain.assign(data, line_start, line_end - line_start);
Rule rule;
rule.wildcard = false;
diff --git a/chromium/net/udp/datagram_client_socket.h b/chromium/net/udp/datagram_client_socket.h
index 88eeced8698..e8cf526248f 100644
--- a/chromium/net/udp/datagram_client_socket.h
+++ b/chromium/net/udp/datagram_client_socket.h
@@ -5,6 +5,7 @@
#ifndef NET_UDP_DATAGRAM_CLIENT_SOCKET_H_
#define NET_UDP_DATAGRAM_CLIENT_SOCKET_H_
+#include "net/base/net_export.h"
#include "net/base/network_change_notifier.h"
#include "net/socket/socket.h"
#include "net/udp/datagram_socket.h"
diff --git a/chromium/net/udp/datagram_server_socket.h b/chromium/net/udp/datagram_server_socket.h
index 7e5adee15e0..6695e2f9d9e 100644
--- a/chromium/net/udp/datagram_server_socket.h
+++ b/chromium/net/udp/datagram_server_socket.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
#include "net/udp/datagram_socket.h"
#include "net/udp/diff_serv_code_point.h"
diff --git a/chromium/net/udp/datagram_socket.h b/chromium/net/udp/datagram_socket.h
index f0e9fa10baa..88f4b999ea6 100644
--- a/chromium/net/udp/datagram_socket.h
+++ b/chromium/net/udp/datagram_socket.h
@@ -9,8 +9,8 @@
namespace net {
-class BoundNetLog;
class IPEndPoint;
+class NetLogWithSource;
// A datagram socket is an interface to a protocol which exchanges
// datagrams, like UDP.
@@ -34,8 +34,19 @@ class NET_EXPORT_PRIVATE DatagramSocket {
// (similar to getsockname)
virtual int GetLocalAddress(IPEndPoint* address) const = 0;
+ // Switch to use non-blocking IO. Must be called right after construction and
+ // before other calls.
+ virtual void UseNonBlockingIO() = 0;
+
+ // Requests that packets sent by this socket not be fragment, either locally
+ // by the host, or by routers (via the DF bit in the IPv4 packet header).
+ // May not be supported by all platforms. Returns a return a network error
+ // code if there was a problem, but the socket will still be usable. Can not
+ // return ERR_IO_PENDING.
+ virtual int SetDoNotFragment() = 0;
+
// Gets the NetLog for this socket.
- virtual const BoundNetLog& NetLog() const = 0;
+ virtual const NetLogWithSource& NetLog() const = 0;
};
} // namespace net
diff --git a/chromium/net/udp/fuzzed_datagram_client_socket.cc b/chromium/net/udp/fuzzed_datagram_client_socket.cc
index ac18cf41b85..0f9eaef0a7f 100644
--- a/chromium/net/udp/fuzzed_datagram_client_socket.cc
+++ b/chromium/net/udp/fuzzed_datagram_client_socket.cc
@@ -10,8 +10,8 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/strings/string_piece.h"
+#include "base/test/fuzzed_data_provider.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "net/base/fuzzed_data_provider.h"
#include "net/base/io_buffer.h"
#include "net/base/ip_address.h"
#include "net/base/net_errors.h"
@@ -27,7 +27,7 @@ const Error kWriteErrors[] = {ERR_FAILED, ERR_ADDRESS_UNREACHABLE,
ERR_MSG_TOO_BIG};
FuzzedDatagramClientSocket::FuzzedDatagramClientSocket(
- FuzzedDataProvider* data_provider)
+ base::FuzzedDataProvider* data_provider)
: data_provider_(data_provider), weak_factory_(this) {}
FuzzedDatagramClientSocket::~FuzzedDatagramClientSocket() {}
@@ -86,7 +86,9 @@ int FuzzedDatagramClientSocket::GetLocalAddress(IPEndPoint* address) const {
return OK;
}
-const BoundNetLog& FuzzedDatagramClientSocket::NetLog() const {
+void FuzzedDatagramClientSocket::UseNonBlockingIO() {}
+
+const NetLogWithSource& FuzzedDatagramClientSocket::NetLog() const {
return net_log_;
}
@@ -167,6 +169,10 @@ int FuzzedDatagramClientSocket::SetSendBufferSize(int32_t size) {
return OK;
}
+int FuzzedDatagramClientSocket::SetDoNotFragment() {
+ return OK;
+}
+
void FuzzedDatagramClientSocket::OnReadComplete(
const net::CompletionCallback& callback,
int result) {
diff --git a/chromium/net/udp/fuzzed_datagram_client_socket.h b/chromium/net/udp/fuzzed_datagram_client_socket.h
index b92b39cba2f..18886d9f2da 100644
--- a/chromium/net/udp/fuzzed_datagram_client_socket.h
+++ b/chromium/net/udp/fuzzed_datagram_client_socket.h
@@ -13,11 +13,14 @@
#include "net/base/completion_callback.h"
#include "net/base/ip_endpoint.h"
#include "net/base/network_change_notifier.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
+
+namespace base {
+class FuzzedDataProvider;
+}
namespace net {
-class FuzzedDataProvider;
class IOBuffer;
// Datagram ClientSocket implementation for use with fuzzers. Can fail to
@@ -26,7 +29,7 @@ class IOBuffer;
class FuzzedDatagramClientSocket : public DatagramClientSocket {
public:
// |data_provider| must outlive the created socket.
- explicit FuzzedDatagramClientSocket(FuzzedDataProvider* data_provider);
+ explicit FuzzedDatagramClientSocket(base::FuzzedDataProvider* data_provider);
~FuzzedDatagramClientSocket() override;
// DatagramClientSocket implementation:
@@ -40,7 +43,8 @@ class FuzzedDatagramClientSocket : public DatagramClientSocket {
void Close() override;
int GetPeerAddress(IPEndPoint* address) const override;
int GetLocalAddress(IPEndPoint* address) const override;
- const BoundNetLog& NetLog() const override;
+ void UseNonBlockingIO() override;
+ const NetLogWithSource& NetLog() const override;
// Socket implementation:
int Read(IOBuffer* buf,
@@ -51,18 +55,19 @@ class FuzzedDatagramClientSocket : public DatagramClientSocket {
const CompletionCallback& callback) override;
int SetReceiveBufferSize(int32_t size) override;
int SetSendBufferSize(int32_t size) override;
+ int SetDoNotFragment() override;
private:
void OnReadComplete(const net::CompletionCallback& callback, int result);
void OnWriteComplete(const net::CompletionCallback& callback, int result);
- FuzzedDataProvider* data_provider_;
+ base::FuzzedDataProvider* data_provider_;
bool connected_ = false;
bool read_pending_ = false;
bool write_pending_ = false;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
IPEndPoint remote_address_;
diff --git a/chromium/net/udp/udp_client_socket.cc b/chromium/net/udp/udp_client_socket.cc
index 7c3a2722a17..9a559ece9fa 100644
--- a/chromium/net/udp/udp_client_socket.cc
+++ b/chromium/net/udp/udp_client_socket.cc
@@ -5,14 +5,13 @@
#include "net/udp/udp_client_socket.h"
#include "net/base/net_errors.h"
-#include "net/log/net_log.h"
namespace net {
UDPClientSocket::UDPClientSocket(DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
net::NetLog* net_log,
- const net::NetLog::Source& source)
+ const net::NetLogSource& source)
: socket_(bind_type, rand_int_cb, net_log, source),
network_(NetworkChangeNotifier::kInvalidNetworkHandle) {}
@@ -109,14 +108,18 @@ int UDPClientSocket::SetSendBufferSize(int32_t size) {
return socket_.SetSendBufferSize(size);
}
-const BoundNetLog& UDPClientSocket::NetLog() const {
+int UDPClientSocket::SetDoNotFragment() {
+ return socket_.SetDoNotFragment();
+}
+
+const NetLogWithSource& UDPClientSocket::NetLog() const {
return socket_.NetLog();
}
-#if defined(OS_WIN)
void UDPClientSocket::UseNonBlockingIO() {
+#if defined(OS_WIN)
socket_.UseNonBlockingIO();
-}
#endif
+}
} // namespace net
diff --git a/chromium/net/udp/udp_client_socket.h b/chromium/net/udp/udp_client_socket.h
index ca563bbc0f1..0a9879b4016 100644
--- a/chromium/net/udp/udp_client_socket.h
+++ b/chromium/net/udp/udp_client_socket.h
@@ -8,14 +8,15 @@
#include <stdint.h>
#include "base/macros.h"
+#include "net/base/net_export.h"
#include "net/base/rand_callback.h"
-#include "net/log/net_log.h"
#include "net/udp/datagram_client_socket.h"
#include "net/udp/udp_socket.h"
namespace net {
-class BoundNetLog;
+class NetLog;
+struct NetLogSource;
// A client socket that uses UDP as the transport layer.
class NET_EXPORT_PRIVATE UDPClientSocket : public DatagramClientSocket {
@@ -23,7 +24,7 @@ class NET_EXPORT_PRIVATE UDPClientSocket : public DatagramClientSocket {
UDPClientSocket(DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
net::NetLog* net_log,
- const net::NetLog::Source& source);
+ const net::NetLogSource& source);
~UDPClientSocket() override;
// DatagramClientSocket implementation.
@@ -41,16 +42,14 @@ class NET_EXPORT_PRIVATE UDPClientSocket : public DatagramClientSocket {
void Close() override;
int GetPeerAddress(IPEndPoint* address) const override;
int GetLocalAddress(IPEndPoint* address) const override;
+ void UseNonBlockingIO() override;
int SetReceiveBufferSize(int32_t size) override;
int SetSendBufferSize(int32_t size) override;
- const BoundNetLog& NetLog() const override;
+ int SetDoNotFragment() override;
+ const NetLogWithSource& NetLog() const override;
-#if defined(OS_WIN)
// Switch to use non-blocking IO. Must be called right after construction and
// before other calls.
- void UseNonBlockingIO();
-#endif
-
private:
UDPSocket socket_;
NetworkChangeNotifier::NetworkHandle network_;
diff --git a/chromium/net/udp/udp_net_log_parameters.cc b/chromium/net/udp/udp_net_log_parameters.cc
index f52d50c4081..471f4e475f6 100644
--- a/chromium/net/udp/udp_net_log_parameters.cc
+++ b/chromium/net/udp/udp_net_log_parameters.cc
@@ -42,7 +42,7 @@ std::unique_ptr<base::Value> NetLogUDPConnectCallback(
} // namespace
-NetLog::ParametersCallback CreateNetLogUDPDataTranferCallback(
+NetLogParametersCallback CreateNetLogUDPDataTranferCallback(
int byte_count,
const char* bytes,
const IPEndPoint* address) {
@@ -50,7 +50,7 @@ NetLog::ParametersCallback CreateNetLogUDPDataTranferCallback(
return base::Bind(&NetLogUDPDataTranferCallback, byte_count, bytes, address);
}
-NetLog::ParametersCallback CreateNetLogUDPConnectCallback(
+NetLogParametersCallback CreateNetLogUDPConnectCallback(
const IPEndPoint* address,
NetworkChangeNotifier::NetworkHandle network) {
DCHECK(address);
diff --git a/chromium/net/udp/udp_net_log_parameters.h b/chromium/net/udp/udp_net_log_parameters.h
index 773f63e32d0..3dcaa3e8ed9 100644
--- a/chromium/net/udp/udp_net_log_parameters.h
+++ b/chromium/net/udp/udp_net_log_parameters.h
@@ -6,7 +6,7 @@
#define NET_UDP_UDP_NET_LOG_PARAMETERS_H_
#include "net/base/network_change_notifier.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_parameters_callback.h"
namespace net {
@@ -16,7 +16,7 @@ class IPEndPoint;
// receive/send event. |bytes| are only logged when byte logging is
// enabled. |address| may be NULL. |address| (if given) and |bytes|
// must be valid for the life of the callback.
-NetLog::ParametersCallback CreateNetLogUDPDataTranferCallback(
+NetLogParametersCallback CreateNetLogUDPDataTranferCallback(
int byte_count,
const char* bytes,
const IPEndPoint* address);
@@ -24,7 +24,7 @@ NetLog::ParametersCallback CreateNetLogUDPDataTranferCallback(
// Creates a NetLog callback that returns parameters describing a UDP
// connect event. |address| cannot be NULL, and must remain valid for
// the lifetime of the callback.
-NetLog::ParametersCallback CreateNetLogUDPConnectCallback(
+NetLogParametersCallback CreateNetLogUDPConnectCallback(
const IPEndPoint* address,
NetworkChangeNotifier::NetworkHandle network);
diff --git a/chromium/net/udp/udp_server_socket.cc b/chromium/net/udp/udp_server_socket.cc
index 4cba115d5fc..90d47a18882 100644
--- a/chromium/net/udp/udp_server_socket.cc
+++ b/chromium/net/udp/udp_server_socket.cc
@@ -10,14 +10,10 @@
namespace net {
UDPServerSocket::UDPServerSocket(net::NetLog* net_log,
- const net::NetLog::Source& source)
- : socket_(DatagramSocket::DEFAULT_BIND,
- RandIntCallback(),
- net_log,
- source),
+ const net::NetLogSource& source)
+ : socket_(DatagramSocket::DEFAULT_BIND, RandIntCallback(), net_log, source),
allow_address_reuse_(false),
- allow_broadcast_(false) {
-}
+ allow_broadcast_(false) {}
UDPServerSocket::~UDPServerSocket() {
}
@@ -68,6 +64,10 @@ int UDPServerSocket::SetSendBufferSize(int32_t size) {
return socket_.SetSendBufferSize(size);
}
+int UDPServerSocket::SetDoNotFragment() {
+ return socket_.SetDoNotFragment();
+}
+
void UDPServerSocket::Close() {
socket_.Close();
}
@@ -80,7 +80,7 @@ int UDPServerSocket::GetLocalAddress(IPEndPoint* address) const {
return socket_.GetLocalAddress(address);
}
-const BoundNetLog& UDPServerSocket::NetLog() const {
+const NetLogWithSource& UDPServerSocket::NetLog() const {
return socket_.NetLog();
}
@@ -120,10 +120,10 @@ void UDPServerSocket::DetachFromThread() {
socket_.DetachFromThread();
}
-#if defined(OS_WIN)
void UDPServerSocket::UseNonBlockingIO() {
+#if defined(OS_WIN)
socket_.UseNonBlockingIO();
-}
#endif
+}
} // namespace net
diff --git a/chromium/net/udp/udp_server_socket.h b/chromium/net/udp/udp_server_socket.h
index a0b4852b958..1b324daa283 100644
--- a/chromium/net/udp/udp_server_socket.h
+++ b/chromium/net/udp/udp_server_socket.h
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
#include "net/udp/datagram_server_socket.h"
#include "net/udp/udp_socket.h"
@@ -16,12 +17,13 @@ namespace net {
class IPAddress;
class IPEndPoint;
-class BoundNetLog;
+class NetLog;
+struct NetLogSource;
// A client socket that uses UDP as the transport layer.
class NET_EXPORT UDPServerSocket : public DatagramServerSocket {
public:
- UDPServerSocket(net::NetLog* net_log, const net::NetLog::Source& source);
+ UDPServerSocket(net::NetLog* net_log, const net::NetLogSource& source);
~UDPServerSocket() override;
// Implement DatagramServerSocket:
@@ -36,10 +38,12 @@ class NET_EXPORT UDPServerSocket : public DatagramServerSocket {
const CompletionCallback& callback) override;
int SetReceiveBufferSize(int32_t size) override;
int SetSendBufferSize(int32_t size) override;
+ int SetDoNotFragment() override;
void Close() override;
int GetPeerAddress(IPEndPoint* address) const override;
int GetLocalAddress(IPEndPoint* address) const override;
- const BoundNetLog& NetLog() const override;
+ void UseNonBlockingIO() override;
+ const NetLogWithSource& NetLog() const override;
void AllowAddressReuse() override;
void AllowBroadcast() override;
int JoinGroup(const IPAddress& group_address) const override;
@@ -50,12 +54,6 @@ class NET_EXPORT UDPServerSocket : public DatagramServerSocket {
int SetDiffServCodePoint(DiffServCodePoint dscp) override;
void DetachFromThread() override;
-#if defined(OS_WIN)
- // Switch to use non-blocking IO. Must be called right after construction and
- // before other calls.
- void UseNonBlockingIO();
-#endif
-
private:
UDPSocket socket_;
bool allow_address_reuse_;
diff --git a/chromium/net/udp/udp_socket_perftest.cc b/chromium/net/udp/udp_socket_perftest.cc
index 8441a0ecdc4..e89968ed1db 100644
--- a/chromium/net/udp/udp_socket_perftest.cc
+++ b/chromium/net/udp/udp_socket_perftest.cc
@@ -11,13 +11,18 @@
#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/test/gtest_util.h"
#include "net/test/net_test_suite.h"
#include "net/udp/udp_client_socket.h"
#include "net/udp/udp_server_socket.h"
#include "net/udp/udp_socket.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -89,26 +94,22 @@ void UDPSocketPerfTest::WriteBenchmark(bool use_nonblocking_io) {
IPEndPoint bind_address;
CreateUDPAddress("127.0.0.1", kPort, &bind_address);
std::unique_ptr<UDPServerSocket> server(
- new UDPServerSocket(nullptr, NetLog::Source()));
-#if defined(OS_WIN)
+ new UDPServerSocket(nullptr, NetLogSource()));
if (use_nonblocking_io)
server->UseNonBlockingIO();
-#endif
int rv = server->Listen(bind_address);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
// Setup the client.
IPEndPoint server_address;
CreateUDPAddress("127.0.0.1", kPort, &server_address);
std::unique_ptr<UDPClientSocket> client(
new UDPClientSocket(DatagramSocket::DEFAULT_BIND, RandIntCallback(),
- nullptr, NetLog::Source()));
-#if defined(OS_WIN)
+ nullptr, NetLogSource()));
if (use_nonblocking_io)
client->UseNonBlockingIO();
-#endif
rv = client->Connect(server_address);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
base::RunLoop run_loop;
base::TimeTicks start_ticks = base::TimeTicks::Now();
@@ -126,12 +127,10 @@ TEST_F(UDPSocketPerfTest, Write) {
WriteBenchmark(false);
}
-#if defined(OS_WIN)
TEST_F(UDPSocketPerfTest, WriteNonBlocking) {
base::PerfTimeLogger timer("UDP_socket_write_nonblocking");
WriteBenchmark(true);
}
-#endif
} // namespace
diff --git a/chromium/net/udp/udp_socket_posix.cc b/chromium/net/udp/udp_socket_posix.cc
index b3972625edc..f598b8bc112 100644
--- a/chromium/net/udp/udp_socket_posix.cc
+++ b/chromium/net/udp/udp_socket_posix.cc
@@ -28,6 +28,9 @@
#include "net/base/network_activity_monitor.h"
#include "net/base/sockaddr_storage.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
#include "net/socket/socket_descriptor.h"
#include "net/udp/udp_net_log_parameters.h"
@@ -74,7 +77,7 @@ int GetIPv4AddressFromIndex(int socket, uint32_t index, uint32_t* address) {
UDPSocketPosix::UDPSocketPosix(DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
net::NetLog* net_log,
- const net::NetLog::Source& source)
+ const net::NetLogSource& source)
: socket_(kInvalidSocket),
addr_family_(0),
is_connected_(false),
@@ -88,9 +91,9 @@ UDPSocketPosix::UDPSocketPosix(DatagramSocket::BindType bind_type,
read_buf_len_(0),
recv_from_address_(NULL),
write_buf_len_(0),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)),
+ net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::UDP_SOCKET)),
bound_network_(NetworkChangeNotifier::kInvalidNetworkHandle) {
- net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
+ net_log_.BeginEvent(NetLogEventType::SOCKET_ALIVE,
source.ToEventParametersCallback());
if (bind_type == DatagramSocket::RANDOM_BIND)
DCHECK(!rand_int_cb.is_null());
@@ -98,7 +101,7 @@ UDPSocketPosix::UDPSocketPosix(DatagramSocket::BindType bind_type,
UDPSocketPosix::~UDPSocketPosix() {
Close();
- net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
+ net_log_.EndEvent(NetLogEventType::SOCKET_ALIVE);
}
int UDPSocketPosix::Open(AddressFamily address_family) {
@@ -180,7 +183,7 @@ int UDPSocketPosix::GetLocalAddress(IPEndPoint* address) const {
return ERR_ADDRESS_INVALID;
local_address_.reset(address.release());
net_log_.AddEvent(
- NetLog::TYPE_UDP_LOCAL_ADDRESS,
+ NetLogEventType::UDP_LOCAL_ADDRESS,
CreateNetLogUDPConnectCallback(local_address_.get(), bound_network_));
}
@@ -273,10 +276,10 @@ int UDPSocketPosix::SendToOrWrite(IOBuffer* buf,
int UDPSocketPosix::Connect(const IPEndPoint& address) {
DCHECK_NE(socket_, kInvalidSocket);
- net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT,
+ net_log_.BeginEvent(NetLogEventType::UDP_CONNECT,
CreateNetLogUDPConnectCallback(&address, bound_network_));
int rv = InternalConnect(address);
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::UDP_CONNECT, rv);
is_connected_ = (rv == OK);
return rv;
}
@@ -346,27 +349,55 @@ int UDPSocketPosix::BindToNetwork(
base::android::SDK_VERSION_LOLLIPOP) {
return ERR_NOT_IMPLEMENTED;
}
- // NOTE(pauljensen): This does rely on Android implementation details, but
- // these details are unlikely to change.
- typedef int (*SetNetworkForSocket)(unsigned netId, int socketFd);
- static SetNetworkForSocket setNetworkForSocket;
- // This is racy, but all racers should come out with the same answer so it
- // shouldn't matter.
- if (!setNetworkForSocket) {
- // Android's netd client library should always be loaded in our address
- // space as it shims socket() which was used to create |socket_|.
- base::FilePath file(base::GetNativeLibraryName("netd_client"));
- // Use RTLD_NOW to match Android's prior loading of the library:
- // http://androidxref.com/6.0.0_r5/xref/bionic/libc/bionic/NetdClient.cpp#37
- // Use RTLD_NOLOAD to assert that the library is already loaded and
- // avoid doing any disk IO.
- void* dl = dlopen(file.value().c_str(), RTLD_NOW | RTLD_NOLOAD);
- setNetworkForSocket =
- reinterpret_cast<SetNetworkForSocket>(dlsym(dl, "setNetworkForSocket"));
+ int rv;
+ // On Android M and newer releases use supported NDK API. On Android L use
+ // setNetworkForSocket from libnetd_client.so.
+ if (base::android::BuildInfo::GetInstance()->sdk_int() >=
+ base::android::SDK_VERSION_MARSHMALLOW) {
+ // See declaration of android_setsocknetwork() here:
+ // http://androidxref.com/6.0.0_r1/xref/development/ndk/platforms/android-M/include/android/multinetwork.h#65
+ // Function cannot be called directly as it will cause app to fail to load
+ // on pre-marshmallow devices.
+ typedef int (*MarshmallowSetNetworkForSocket)(int64_t netId, int socketFd);
+ static MarshmallowSetNetworkForSocket marshmallowSetNetworkForSocket;
+ // This is racy, but all racers should come out with the same answer so it
+ // shouldn't matter.
+ if (!marshmallowSetNetworkForSocket) {
+ base::FilePath file(base::GetNativeLibraryName("android"));
+ void* dl = dlopen(file.value().c_str(), RTLD_NOW);
+ marshmallowSetNetworkForSocket =
+ reinterpret_cast<MarshmallowSetNetworkForSocket>(
+ dlsym(dl, "android_setsocknetwork"));
+ }
+ if (!marshmallowSetNetworkForSocket)
+ return ERR_NOT_IMPLEMENTED;
+ rv = marshmallowSetNetworkForSocket(network, socket_);
+ if (rv)
+ rv = errno;
+ } else {
+ // NOTE(pauljensen): This does rely on Android implementation details, but
+ // they won't change because Lollipop is already released.
+ typedef int (*LollipopSetNetworkForSocket)(unsigned netId, int socketFd);
+ static LollipopSetNetworkForSocket lollipopSetNetworkForSocket;
+ // This is racy, but all racers should come out with the same answer so it
+ // shouldn't matter.
+ if (!lollipopSetNetworkForSocket) {
+ // Android's netd client library should always be loaded in our address
+ // space as it shims socket() which was used to create |socket_|.
+ base::FilePath file(base::GetNativeLibraryName("netd_client"));
+ // Use RTLD_NOW to match Android's prior loading of the library:
+ // http://androidxref.com/6.0.0_r5/xref/bionic/libc/bionic/NetdClient.cpp#37
+ // Use RTLD_NOLOAD to assert that the library is already loaded and
+ // avoid doing any disk IO.
+ void* dl = dlopen(file.value().c_str(), RTLD_NOW | RTLD_NOLOAD);
+ lollipopSetNetworkForSocket =
+ reinterpret_cast<LollipopSetNetworkForSocket>(
+ dlsym(dl, "setNetworkForSocket"));
+ }
+ if (!lollipopSetNetworkForSocket)
+ return ERR_NOT_IMPLEMENTED;
+ rv = -lollipopSetNetworkForSocket(network, socket_);
}
- if (!setNetworkForSocket)
- return ERR_NOT_IMPLEMENTED;
- int rv = setNetworkForSocket(network, socket_);
// If |network| has since disconnected, |rv| will be ENONET. Surface this as
// ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back
// the less descriptive ERR_FAILED.
@@ -397,6 +428,37 @@ int UDPSocketPosix::SetSendBufferSize(int32_t size) {
return rv == 0 ? OK : MapSystemError(errno);
}
+int UDPSocketPosix::SetDoNotFragment() {
+ DCHECK_NE(socket_, kInvalidSocket);
+ DCHECK(CalledOnValidThread());
+
+#if !defined(IP_PMTUDISC_DO)
+ return ERR_NOT_IMPLEMENTED;
+#else
+ if (addr_family_ == AF_INET6) {
+ int val = IPV6_PMTUDISC_DO;
+ if (setsockopt(socket_, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
+ sizeof(val)) != 0) {
+ return MapSystemError(errno);
+ }
+
+ int v6_only = false;
+ socklen_t v6_only_len = sizeof(v6_only);
+ if (getsockopt(socket_, IPPROTO_IPV6, IPV6_V6ONLY, &v6_only,
+ &v6_only_len) != 0) {
+ return MapSystemError(errno);
+ }
+
+ if (v6_only)
+ return OK;
+ }
+
+ int val = IP_PMTUDISC_DO;
+ int rv = setsockopt(socket_, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val));
+ return rv == 0 ? OK : MapSystemError(errno);
+#endif
+}
+
int UDPSocketPosix::AllowAddressReuse() {
DCHECK_NE(socket_, kInvalidSocket);
DCHECK(CalledOnValidThread());
@@ -416,10 +478,15 @@ int UDPSocketPosix::SetBroadcast(bool broadcast) {
// SO_REUSEPORT on OSX permits multiple processes to each receive
// UDP multicast or broadcast datagrams destined for the bound
// port.
+ // This is only being set on OSX because its behavior is platform dependent
+ // and we are playing it safe by only setting it on platforms where things
+ // break.
rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value));
-#else
- rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value));
+ if (rv != 0)
+ return MapSystemError(errno);
#endif // defined(OS_MACOSX)
+ rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value));
+
return rv == 0 ? OK : MapSystemError(errno);
}
@@ -473,7 +540,8 @@ void UDPSocketPosix::LogRead(int result,
socklen_t addr_len,
const sockaddr* addr) const {
if (result < 0) {
- net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR, result);
+ net_log_.AddEventWithNetErrorCode(NetLogEventType::UDP_RECEIVE_ERROR,
+ result);
return;
}
@@ -483,11 +551,9 @@ void UDPSocketPosix::LogRead(int result,
IPEndPoint address;
bool is_address_valid = address.FromSockAddr(addr, addr_len);
- net_log_.AddEvent(
- NetLog::TYPE_UDP_BYTES_RECEIVED,
- CreateNetLogUDPDataTranferCallback(
- result, bytes,
- is_address_valid ? &address : NULL));
+ net_log_.AddEvent(NetLogEventType::UDP_BYTES_RECEIVED,
+ CreateNetLogUDPDataTranferCallback(
+ result, bytes, is_address_valid ? &address : NULL));
}
NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result);
@@ -510,13 +576,13 @@ void UDPSocketPosix::LogWrite(int result,
const char* bytes,
const IPEndPoint* address) const {
if (result < 0) {
- net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR, result);
+ net_log_.AddEventWithNetErrorCode(NetLogEventType::UDP_SEND_ERROR, result);
return;
}
if (net_log_.IsCapturing()) {
net_log_.AddEvent(
- NetLog::TYPE_UDP_BYTES_SENT,
+ NetLogEventType::UDP_BYTES_SENT,
CreateNetLogUDPDataTranferCallback(result, bytes, address));
}
diff --git a/chromium/net/udp/udp_socket_posix.h b/chromium/net/udp/udp_socket_posix.h
index 305c435334a..955ed6e2224 100644
--- a/chromium/net/udp/udp_socket_posix.h
+++ b/chromium/net/udp/udp_socket_posix.h
@@ -20,7 +20,7 @@
#include "net/base/net_export.h"
#include "net/base/network_change_notifier.h"
#include "net/base/rand_callback.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/socket/socket_descriptor.h"
#include "net/udp/datagram_socket.h"
#include "net/udp/diff_serv_code_point.h"
@@ -28,13 +28,15 @@
namespace net {
class IPAddress;
+class NetLog;
+struct NetLogSource;
class NET_EXPORT UDPSocketPosix : public base::NonThreadSafe {
public:
UDPSocketPosix(DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
net::NetLog* net_log,
- const net::NetLog::Source& source);
+ const net::NetLogSource& source);
virtual ~UDPSocketPosix();
// Opens the socket.
@@ -119,10 +121,17 @@ class NET_EXPORT UDPSocketPosix : public base::NonThreadSafe {
// Returns a net error code.
int SetSendBufferSize(int32_t size);
+ // Requests that packets sent by this socket not be fragment, either locally
+ // by the host, or by routers (via the DF bit in the IPv4 packet header).
+ // May not be supported by all platforms. Returns a return a network error
+ // code if there was a problem, but the socket will still be usable. Can not
+ // return ERR_IO_PENDING.
+ int SetDoNotFragment();
+
// Returns true if the socket is already connected or bound.
bool is_connected() const { return is_connected_; }
- const BoundNetLog& NetLog() const { return net_log_; }
+ const NetLogWithSource& NetLog() const { return net_log_; }
// Sets corresponding flags in |socket_options_| to allow the socket
// to share the local address to which the socket will be bound with
@@ -308,7 +317,7 @@ class NET_EXPORT UDPSocketPosix : public base::NonThreadSafe {
// External callback; called when write is complete.
CompletionCallback write_callback_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
// Network that this socket is bound to via BindToNetwork().
NetworkChangeNotifier::NetworkHandle bound_network_;
diff --git a/chromium/net/udp/udp_socket_unittest.cc b/chromium/net/udp/udp_socket_unittest.cc
index c7ab74dd4ae..21ac91811f0 100644
--- a/chromium/net/udp/udp_socket_unittest.cc
+++ b/chromium/net/udp/udp_socket_unittest.cc
@@ -10,27 +10,38 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/io_buffer.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_event_type.h"
+#include "net/log/net_log_source.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/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"
#include "testing/platform_test.h"
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
+
#if defined(OS_IOS)
#include <TargetConditionals.h>
#endif
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -160,14 +171,12 @@ void UDPSocketTest::ConnectTest(bool use_nonblocking_io) {
CreateUDPAddress("127.0.0.1", kPort, &bind_address);
TestNetLog server_log;
std::unique_ptr<UDPServerSocket> server(
- new UDPServerSocket(&server_log, NetLog::Source()));
-#if defined(OS_WIN)
+ new UDPServerSocket(&server_log, NetLogSource()));
if (use_nonblocking_io)
server->UseNonBlockingIO();
-#endif
server->AllowAddressReuse();
int rv = server->Listen(bind_address);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
// Setup the client.
IPEndPoint server_address;
@@ -175,14 +184,12 @@ void UDPSocketTest::ConnectTest(bool use_nonblocking_io) {
TestNetLog client_log;
std::unique_ptr<UDPClientSocket> client(
new UDPClientSocket(DatagramSocket::DEFAULT_BIND, RandIntCallback(),
- &client_log, NetLog::Source()));
-#if defined(OS_WIN)
+ &client_log, NetLogSource()));
if (use_nonblocking_io)
client->UseNonBlockingIO();
-#endif
rv = client->Connect(server_address);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Client sends to the server.
rv = WriteSocket(client.get(), simple_message);
@@ -206,7 +213,7 @@ void UDPSocketTest::ConnectTest(bool use_nonblocking_io) {
rv = server->RecvFrom(
buffer_.get(), kMaxRead, &recv_from_address_,
base::Bind(&ReadCompleteCallback, &read_result, run_loop.QuitClosure()));
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
// Client sends to the server.
base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -226,33 +233,40 @@ void UDPSocketTest::ConnectTest(bool use_nonblocking_io) {
server_log.GetEntries(&server_entries);
EXPECT_EQ(5u, server_entries.size());
EXPECT_TRUE(
- LogContainsBeginEvent(server_entries, 0, NetLog::TYPE_SOCKET_ALIVE));
- EXPECT_TRUE(LogContainsEvent(
- server_entries, 1, NetLog::TYPE_UDP_BYTES_RECEIVED, NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEvent(server_entries, 2, NetLog::TYPE_UDP_BYTES_SENT,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEvent(
- server_entries, 3, NetLog::TYPE_UDP_BYTES_RECEIVED, NetLog::PHASE_NONE));
+ LogContainsBeginEvent(server_entries, 0, NetLogEventType::SOCKET_ALIVE));
+ EXPECT_TRUE(LogContainsEvent(server_entries, 1,
+ NetLogEventType::UDP_BYTES_RECEIVED,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEvent(server_entries, 2,
+ NetLogEventType::UDP_BYTES_SENT,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEvent(server_entries, 3,
+ NetLogEventType::UDP_BYTES_RECEIVED,
+ NetLogEventPhase::NONE));
EXPECT_TRUE(
- LogContainsEndEvent(server_entries, 4, NetLog::TYPE_SOCKET_ALIVE));
+ LogContainsEndEvent(server_entries, 4, NetLogEventType::SOCKET_ALIVE));
// Check the client's log.
TestNetLogEntry::List client_entries;
client_log.GetEntries(&client_entries);
EXPECT_EQ(7u, client_entries.size());
EXPECT_TRUE(
- LogContainsBeginEvent(client_entries, 0, NetLog::TYPE_SOCKET_ALIVE));
+ LogContainsBeginEvent(client_entries, 0, NetLogEventType::SOCKET_ALIVE));
EXPECT_TRUE(
- LogContainsBeginEvent(client_entries, 1, NetLog::TYPE_UDP_CONNECT));
- EXPECT_TRUE(LogContainsEndEvent(client_entries, 2, NetLog::TYPE_UDP_CONNECT));
- EXPECT_TRUE(LogContainsEvent(client_entries, 3, NetLog::TYPE_UDP_BYTES_SENT,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEvent(
- client_entries, 4, NetLog::TYPE_UDP_BYTES_RECEIVED, NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEvent(client_entries, 5, NetLog::TYPE_UDP_BYTES_SENT,
- NetLog::PHASE_NONE));
+ LogContainsBeginEvent(client_entries, 1, NetLogEventType::UDP_CONNECT));
EXPECT_TRUE(
- LogContainsEndEvent(client_entries, 6, NetLog::TYPE_SOCKET_ALIVE));
+ LogContainsEndEvent(client_entries, 2, NetLogEventType::UDP_CONNECT));
+ EXPECT_TRUE(LogContainsEvent(client_entries, 3,
+ NetLogEventType::UDP_BYTES_SENT,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEvent(client_entries, 4,
+ NetLogEventType::UDP_BYTES_RECEIVED,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(LogContainsEvent(client_entries, 5,
+ NetLogEventType::UDP_BYTES_SENT,
+ NetLogEventPhase::NONE));
+ EXPECT_TRUE(
+ LogContainsEndEvent(client_entries, 6, NetLogEventType::SOCKET_ALIVE));
}
TEST_F(UDPSocketTest, Connect) {
@@ -288,18 +302,18 @@ TEST_F(UDPSocketTest, Broadcast) {
TestNetLog server1_log, server2_log;
std::unique_ptr<UDPServerSocket> server1(
- new UDPServerSocket(&server1_log, NetLog::Source()));
+ new UDPServerSocket(&server1_log, NetLogSource()));
std::unique_ptr<UDPServerSocket> server2(
- new UDPServerSocket(&server2_log, NetLog::Source()));
+ new UDPServerSocket(&server2_log, NetLogSource()));
server1->AllowAddressReuse();
server1->AllowBroadcast();
server2->AllowAddressReuse();
server2->AllowBroadcast();
int rv = server1->Listen(listen_address);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
rv = server2->Listen(listen_address);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
rv = SendToSocket(server1.get(), first_message, broadcast_address);
ASSERT_EQ(static_cast<int>(first_message.size()), rv);
@@ -351,28 +365,24 @@ class TestPrng {
};
TEST_F(UDPSocketTest, ConnectRandomBind) {
- std::vector<UDPClientSocket*> sockets;
+ std::vector<std::unique_ptr<UDPClientSocket>> sockets;
IPEndPoint peer_address;
CreateUDPAddress("127.0.0.1", 53, &peer_address);
// Create and connect sockets and save port numbers.
std::deque<int> used_ports;
for (int i = 0; i < kBindRetries; ++i) {
- UDPClientSocket* socket =
- new UDPClientSocket(DatagramSocket::DEFAULT_BIND,
- RandIntCallback(),
- NULL,
- NetLog::Source());
- sockets.push_back(socket);
- EXPECT_EQ(OK, socket->Connect(peer_address));
+ UDPClientSocket* socket = new UDPClientSocket(
+ DatagramSocket::DEFAULT_BIND, RandIntCallback(), NULL, NetLogSource());
+ sockets.push_back(base::WrapUnique(socket));
+ EXPECT_THAT(socket->Connect(peer_address), IsOk());
IPEndPoint client_address;
- EXPECT_EQ(OK, socket->GetLocalAddress(&client_address));
+ EXPECT_THAT(socket->GetLocalAddress(&client_address), IsOk());
used_ports.push_back(client_address.port());
}
// Free the last socket, its local port is still in |used_ports|.
- delete sockets.back();
sockets.pop_back();
TestPrng test_prng(used_ports);
@@ -381,15 +391,13 @@ TEST_F(UDPSocketTest, ConnectRandomBind) {
// Create a socket with random binding policy and connect.
std::unique_ptr<UDPClientSocket> test_socket(new UDPClientSocket(
- DatagramSocket::RANDOM_BIND, rand_int_cb, NULL, NetLog::Source()));
- EXPECT_EQ(OK, test_socket->Connect(peer_address));
+ DatagramSocket::RANDOM_BIND, rand_int_cb, NULL, NetLogSource()));
+ EXPECT_THAT(test_socket->Connect(peer_address), IsOk());
// Make sure that the last port number in the |used_ports| was used.
IPEndPoint client_address;
- EXPECT_EQ(OK, test_socket->GetLocalAddress(&client_address));
+ EXPECT_THAT(test_socket->GetLocalAddress(&client_address), IsOk());
EXPECT_EQ(used_ports.back(), client_address.port());
-
- STLDeleteElements(&sockets);
}
// Return a privileged port (under 1024) so binding will fail.
@@ -411,9 +419,9 @@ TEST_F(UDPSocketTest, MAYBE_ConnectFail) {
std::unique_ptr<UDPSocket> socket(new UDPSocket(DatagramSocket::RANDOM_BIND,
base::Bind(&PrivilegedRand),
- NULL, NetLog::Source()));
+ NULL, NetLogSource()));
int rv = socket->Open(peer_address.GetFamily());
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
rv = socket->Connect(peer_address);
// Connect should have failed since we couldn't bind to that port,
EXPECT_NE(OK, rv);
@@ -438,27 +446,25 @@ TEST_F(UDPSocketTest, VerifyConnectBindsAddr) {
// Setup the first server to listen.
IPEndPoint bind_address;
CreateUDPAddress("127.0.0.1", kPort1, &bind_address);
- UDPServerSocket server1(NULL, NetLog::Source());
+ UDPServerSocket server1(NULL, NetLogSource());
server1.AllowAddressReuse();
int rv = server1.Listen(bind_address);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
// Setup the second server to listen.
CreateUDPAddress("127.0.0.1", kPort2, &bind_address);
- UDPServerSocket server2(NULL, NetLog::Source());
+ UDPServerSocket server2(NULL, NetLogSource());
server2.AllowAddressReuse();
rv = server2.Listen(bind_address);
- ASSERT_EQ(OK, rv);
+ ASSERT_THAT(rv, IsOk());
// Setup the client, connected to server 1.
IPEndPoint server_address;
CreateUDPAddress("127.0.0.1", kPort1, &server_address);
- UDPClientSocket client(DatagramSocket::DEFAULT_BIND,
- RandIntCallback(),
- NULL,
- NetLog::Source());
+ UDPClientSocket client(DatagramSocket::DEFAULT_BIND, RandIntCallback(), NULL,
+ NetLogSource());
rv = client.Connect(server_address);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Client sends to server1.
rv = WriteSocket(&client, simple_message);
@@ -471,7 +477,7 @@ TEST_F(UDPSocketTest, VerifyConnectBindsAddr) {
// Get the client's address.
IPEndPoint client_address;
rv = client.GetLocalAddress(&client_address);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// Server2 sends reply.
rv = SendToSocket(&server2, foreign_message,
@@ -513,10 +519,8 @@ TEST_F(UDPSocketTest, ClientGetLocalPeerAddresses) {
EXPECT_TRUE(ip_address.AssignFromIPLiteral(tests[i].local_address));
IPEndPoint local_address(ip_address, 80);
- UDPClientSocket client(DatagramSocket::DEFAULT_BIND,
- RandIntCallback(),
- NULL,
- NetLog::Source());
+ UDPClientSocket client(DatagramSocket::DEFAULT_BIND, RandIntCallback(),
+ NULL, NetLogSource());
int rv = client.Connect(remote_address);
if (tests[i].may_fail && rv == ERR_ADDRESS_UNREACHABLE) {
// Connect() may return ERR_ADDRESS_UNREACHABLE for IPv6
@@ -528,7 +532,7 @@ TEST_F(UDPSocketTest, ClientGetLocalPeerAddresses) {
IPEndPoint fetched_local_address;
rv = client.GetLocalAddress(&fetched_local_address);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
// TODO(mbelshe): figure out how to verify the IP and port.
// The port is dynamically generated by the udp stack.
@@ -538,7 +542,7 @@ TEST_F(UDPSocketTest, ClientGetLocalPeerAddresses) {
IPEndPoint fetched_remote_address;
rv = client.GetPeerAddress(&fetched_remote_address);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ(remote_address, fetched_remote_address);
}
@@ -547,9 +551,9 @@ TEST_F(UDPSocketTest, ClientGetLocalPeerAddresses) {
TEST_F(UDPSocketTest, ServerGetLocalAddress) {
IPEndPoint bind_address;
CreateUDPAddress("127.0.0.1", 0, &bind_address);
- UDPServerSocket server(NULL, NetLog::Source());
+ UDPServerSocket server(NULL, NetLogSource());
int rv = server.Listen(bind_address);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
IPEndPoint local_address;
rv = server.GetLocalAddress(&local_address);
@@ -563,22 +567,66 @@ TEST_F(UDPSocketTest, ServerGetLocalAddress) {
TEST_F(UDPSocketTest, ServerGetPeerAddress) {
IPEndPoint bind_address;
CreateUDPAddress("127.0.0.1", 0, &bind_address);
- UDPServerSocket server(NULL, NetLog::Source());
+ UDPServerSocket server(NULL, NetLogSource());
int rv = server.Listen(bind_address);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
IPEndPoint peer_address;
rv = server.GetPeerAddress(&peer_address);
EXPECT_EQ(rv, ERR_SOCKET_NOT_CONNECTED);
}
+TEST_F(UDPSocketTest, ClientSetDoNotFragment) {
+ for (std::string ip : {"127.0.0.1", "::1"}) {
+ LOG(INFO) << "ip: " << ip;
+ UDPClientSocket client(DatagramSocket::DEFAULT_BIND, RandIntCallback(),
+ nullptr, NetLogSource());
+ IPAddress ip_address;
+ EXPECT_TRUE(ip_address.AssignFromIPLiteral(ip));
+ IPEndPoint remote_address(ip_address, 80);
+ int rv = client.Connect(remote_address);
+ // May fail on IPv6 is IPv6 is not configured.
+ if (ip_address.IsIPv6() && rv == ERR_ADDRESS_UNREACHABLE)
+ return;
+ EXPECT_THAT(rv, IsOk());
+
+#if defined(OS_MACOSX)
+ EXPECT_EQ(ERR_NOT_IMPLEMENTED, client.SetDoNotFragment());
+#else
+ rv = client.SetDoNotFragment();
+ EXPECT_THAT(rv, IsOk());
+#endif
+ }
+}
+
+TEST_F(UDPSocketTest, ServerSetDoNotFragment) {
+ for (std::string ip : {"127.0.0.1", "::1"}) {
+ LOG(INFO) << "ip: " << ip;
+ IPEndPoint bind_address;
+ CreateUDPAddress(ip, 0, &bind_address);
+ UDPServerSocket server(nullptr, NetLogSource());
+ int rv = server.Listen(bind_address);
+ // May fail on IPv6 is IPv6 is not configure
+ if (bind_address.address().IsIPv6() && rv == ERR_ADDRESS_INVALID)
+ return;
+ EXPECT_THAT(rv, IsOk());
+
+#if defined(OS_MACOSX)
+ EXPECT_EQ(ERR_NOT_IMPLEMENTED, server.SetDoNotFragment());
+#else
+ rv = server.SetDoNotFragment();
+ EXPECT_THAT(rv, IsOk());
+#endif
+ }
+}
+
// Close the socket while read is pending.
TEST_F(UDPSocketTest, CloseWithPendingRead) {
IPEndPoint bind_address;
CreateUDPAddress("127.0.0.1", 0, &bind_address);
- UDPServerSocket server(NULL, NetLog::Source());
+ UDPServerSocket server(NULL, NetLogSource());
int rv = server.Listen(bind_address);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
TestCompletionCallback callback;
IPEndPoint from;
@@ -608,16 +656,14 @@ TEST_F(UDPSocketTest, MAYBE_JoinMulticastGroup) {
IPAddress group_ip;
EXPECT_TRUE(group_ip.AssignFromIPLiteral(kGroup));
- UDPSocket socket(DatagramSocket::DEFAULT_BIND,
- RandIntCallback(),
- NULL,
- NetLog::Source());
- EXPECT_EQ(OK, socket.Open(bind_address.GetFamily()));
- EXPECT_EQ(OK, socket.Bind(bind_address));
- EXPECT_EQ(OK, socket.JoinGroup(group_ip));
+ UDPSocket socket(DatagramSocket::DEFAULT_BIND, RandIntCallback(), NULL,
+ NetLogSource());
+ EXPECT_THAT(socket.Open(bind_address.GetFamily()), IsOk());
+ EXPECT_THAT(socket.Bind(bind_address), IsOk());
+ EXPECT_THAT(socket.JoinGroup(group_ip), IsOk());
// Joining group multiple times.
EXPECT_NE(OK, socket.JoinGroup(group_ip));
- EXPECT_EQ(OK, socket.LeaveGroup(group_ip));
+ EXPECT_THAT(socket.LeaveGroup(group_ip), IsOk());
// Leaving group multiple times.
EXPECT_NE(OK, socket.LeaveGroup(group_ip));
@@ -629,20 +675,18 @@ TEST_F(UDPSocketTest, MulticastOptions) {
IPEndPoint bind_address;
CreateUDPAddress("0.0.0.0", kPort, &bind_address);
- UDPSocket socket(DatagramSocket::DEFAULT_BIND,
- RandIntCallback(),
- NULL,
- NetLog::Source());
+ UDPSocket socket(DatagramSocket::DEFAULT_BIND, RandIntCallback(), NULL,
+ NetLogSource());
// Before binding.
- EXPECT_EQ(OK, socket.SetMulticastLoopbackMode(false));
- EXPECT_EQ(OK, socket.SetMulticastLoopbackMode(true));
- EXPECT_EQ(OK, socket.SetMulticastTimeToLive(0));
- EXPECT_EQ(OK, socket.SetMulticastTimeToLive(3));
+ EXPECT_THAT(socket.SetMulticastLoopbackMode(false), IsOk());
+ EXPECT_THAT(socket.SetMulticastLoopbackMode(true), IsOk());
+ EXPECT_THAT(socket.SetMulticastTimeToLive(0), IsOk());
+ EXPECT_THAT(socket.SetMulticastTimeToLive(3), IsOk());
EXPECT_NE(OK, socket.SetMulticastTimeToLive(-1));
- EXPECT_EQ(OK, socket.SetMulticastInterface(0));
+ EXPECT_THAT(socket.SetMulticastInterface(0), IsOk());
- EXPECT_EQ(OK, socket.Open(bind_address.GetFamily()));
- EXPECT_EQ(OK, socket.Bind(bind_address));
+ EXPECT_THAT(socket.Open(bind_address.GetFamily()), IsOk());
+ EXPECT_THAT(socket.Bind(bind_address), IsOk());
EXPECT_NE(OK, socket.SetMulticastLoopbackMode(false));
EXPECT_NE(OK, socket.SetMulticastTimeToLive(0));
@@ -656,14 +700,12 @@ TEST_F(UDPSocketTest, MulticastOptions) {
TEST_F(UDPSocketTest, SetDSCP) {
// Setup the server to listen.
IPEndPoint bind_address;
- UDPSocket client(DatagramSocket::DEFAULT_BIND,
- RandIntCallback(),
- NULL,
- NetLog::Source());
+ UDPSocket client(DatagramSocket::DEFAULT_BIND, RandIntCallback(), NULL,
+ NetLogSource());
// We need a real IP, but we won't actually send anything to it.
CreateUDPAddress("8.8.8.8", 9999, &bind_address);
int rv = client.Open(bind_address.GetFamily());
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
rv = client.Connect(bind_address);
if (rv != OK) {
@@ -671,7 +713,7 @@ TEST_F(UDPSocketTest, SetDSCP) {
CreateUDPAddress("127.0.0.1", 9999, &bind_address);
rv = client.Connect(bind_address);
}
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
client.SetDiffServCodePoint(DSCP_NO_CHANGE);
client.SetDiffServCodePoint(DSCP_AF41);
@@ -682,6 +724,53 @@ TEST_F(UDPSocketTest, SetDSCP) {
client.Close();
}
+TEST_F(UDPSocketTest, TestBindToNetwork) {
+ UDPSocket socket(DatagramSocket::RANDOM_BIND, base::Bind(&PrivilegedRand),
+ NULL, NetLogSource());
+ ASSERT_EQ(OK, socket.Open(ADDRESS_FAMILY_IPV4));
+ // Test unsuccessful binding, by attempting to bind to a bogus NetworkHandle.
+ int rv = socket.BindToNetwork(65536);
+#if !defined(OS_ANDROID)
+ EXPECT_EQ(ERR_NOT_IMPLEMENTED, rv);
+#else
+ if (base::android::BuildInfo::GetInstance()->sdk_int() <
+ base::android::SDK_VERSION_LOLLIPOP) {
+ EXPECT_EQ(ERR_NOT_IMPLEMENTED, rv);
+ } else if (base::android::BuildInfo::GetInstance()->sdk_int() >=
+ base::android::SDK_VERSION_LOLLIPOP &&
+ base::android::BuildInfo::GetInstance()->sdk_int() <
+ base::android::SDK_VERSION_MARSHMALLOW) {
+ // On Lollipop, we assume if the user has a NetworkHandle that they must
+ // have gotten it from a legitimate source, so if binding to the network
+ // fails it's assumed to be because the network went away so
+ // ERR_NETWORK_CHANGED is returned. In this test the network never existed
+ // anyhow. ConnectivityService.MAX_NET_ID is 65535, so 65536 won't be used.
+ EXPECT_EQ(ERR_NETWORK_CHANGED, rv);
+ } else if (base::android::BuildInfo::GetInstance()->sdk_int() >=
+ base::android::SDK_VERSION_MARSHMALLOW) {
+ // On Marshmallow and newer releases, the NetworkHandle is munged by
+ // Network.getNetworkHandle() and 65536 isn't munged so it's rejected.
+ EXPECT_EQ(ERR_INVALID_ARGUMENT, rv);
+ }
+
+ if (base::android::BuildInfo::GetInstance()->sdk_int() >=
+ base::android::SDK_VERSION_LOLLIPOP) {
+ EXPECT_EQ(
+ ERR_INVALID_ARGUMENT,
+ 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));
+ }
+ }
+ }
+#endif
+}
+
} // namespace
#if defined(OS_WIN)
@@ -766,18 +855,16 @@ TEST_F(UDPSocketTest, SetDSCPFake) {
IPEndPoint bind_address;
// We need a real IP, but we won't actually send anything to it.
CreateUDPAddress("8.8.8.8", 9999, &bind_address);
- UDPSocket client(DatagramSocket::DEFAULT_BIND,
- RandIntCallback(),
- NULL,
- NetLog::Source());
+ UDPSocket client(DatagramSocket::DEFAULT_BIND, RandIntCallback(), NULL,
+ NetLogSource());
int rv = client.SetDiffServCodePoint(DSCP_AF41);
- EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, rv);
+ EXPECT_THAT(rv, IsError(ERR_SOCKET_NOT_CONNECTED));
rv = client.Open(bind_address.GetFamily());
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
rv = client.Connect(bind_address);
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
QwaveAPI& qos(QwaveAPI::Get());
qos.create_handle_func_ = FakeQOSCreateHandleFAIL;
@@ -787,24 +874,24 @@ TEST_F(UDPSocketTest, SetDSCPFake) {
qos.set_flow_func_ = FakeQOSSetFlow;
qos.qwave_supported_ = true;
- EXPECT_EQ(OK, client.SetDiffServCodePoint(DSCP_NO_CHANGE));
+ EXPECT_THAT(client.SetDiffServCodePoint(DSCP_NO_CHANGE), IsOk());
EXPECT_EQ(ERROR_NOT_SUPPORTED, client.SetDiffServCodePoint(DSCP_AF41));
qos.create_handle_func_ = FakeQOSCreateHandle;
g_expected_dscp = DSCP_AF41;
g_expected_traffic_type = QOSTrafficTypeAudioVideo;
- EXPECT_EQ(OK, client.SetDiffServCodePoint(DSCP_AF41));
+ EXPECT_THAT(client.SetDiffServCodePoint(DSCP_AF41), IsOk());
g_expected_dscp = DSCP_DEFAULT;
g_expected_traffic_type = QOSTrafficTypeBestEffort;
- EXPECT_EQ(OK, client.SetDiffServCodePoint(DSCP_DEFAULT));
+ EXPECT_THAT(client.SetDiffServCodePoint(DSCP_DEFAULT), IsOk());
g_expected_dscp = DSCP_CS2;
g_expected_traffic_type = QOSTrafficTypeExcellentEffort;
- EXPECT_EQ(OK, client.SetDiffServCodePoint(DSCP_CS2));
+ EXPECT_THAT(client.SetDiffServCodePoint(DSCP_CS2), IsOk());
g_expected_dscp = DSCP_CS3;
g_expected_traffic_type = QOSTrafficTypeExcellentEffort;
- EXPECT_EQ(OK, client.SetDiffServCodePoint(DSCP_NO_CHANGE));
+ EXPECT_THAT(client.SetDiffServCodePoint(DSCP_NO_CHANGE), IsOk());
g_expected_dscp = DSCP_DEFAULT;
g_expected_traffic_type = QOSTrafficTypeBestEffort;
- EXPECT_EQ(OK, client.SetDiffServCodePoint(DSCP_DEFAULT));
+ EXPECT_THAT(client.SetDiffServCodePoint(DSCP_DEFAULT), IsOk());
client.Close();
}
#endif
diff --git a/chromium/net/udp/udp_socket_win.cc b/chromium/net/udp/udp_socket_win.cc
index 42cb05af9d2..52e41bdfbf2 100644
--- a/chromium/net/udp/udp_socket_win.cc
+++ b/chromium/net/udp/udp_socket_win.cc
@@ -24,6 +24,9 @@
#include "net/base/winsock_init.h"
#include "net/base/winsock_util.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_source_type.h"
#include "net/socket/socket_descriptor.h"
#include "net/udp/udp_net_log_parameters.h"
@@ -242,7 +245,7 @@ BOOL QwaveAPI::SetFlow(HANDLE handle,
UDPSocketWin::UDPSocketWin(DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
net::NetLog* net_log,
- const net::NetLog::Source& source)
+ const net::NetLogSource& source)
: socket_(INVALID_SOCKET),
addr_family_(0),
is_connected_(false),
@@ -255,11 +258,11 @@ UDPSocketWin::UDPSocketWin(DatagramSocket::BindType bind_type,
read_iobuffer_len_(0),
write_iobuffer_len_(0),
recv_from_address_(NULL),
- net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)),
+ net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::UDP_SOCKET)),
qos_handle_(NULL),
qos_flow_id_(0) {
EnsureWinsockInit();
- net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
+ net_log_.BeginEvent(NetLogEventType::SOCKET_ALIVE,
source.ToEventParametersCallback());
if (bind_type == DatagramSocket::RANDOM_BIND)
DCHECK(!rand_int_cb.is_null());
@@ -267,7 +270,7 @@ UDPSocketWin::UDPSocketWin(DatagramSocket::BindType bind_type,
UDPSocketWin::~UDPSocketWin() {
Close();
- net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
+ net_log_.EndEvent(NetLogEventType::SOCKET_ALIVE);
}
int UDPSocketWin::Open(AddressFamily address_family) {
@@ -355,7 +358,7 @@ int UDPSocketWin::GetLocalAddress(IPEndPoint* address) const {
if (!local_address->FromSockAddr(storage.addr, storage.addr_len))
return ERR_ADDRESS_INVALID;
local_address_.reset(local_address.release());
- net_log_.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS,
+ net_log_.AddEvent(NetLogEventType::UDP_LOCAL_ADDRESS,
CreateNetLogUDPConnectCallback(
local_address_.get(),
NetworkChangeNotifier::kInvalidNetworkHandle));
@@ -430,11 +433,11 @@ int UDPSocketWin::SendToOrWrite(IOBuffer* buf,
int UDPSocketWin::Connect(const IPEndPoint& address) {
DCHECK_NE(socket_, INVALID_SOCKET);
net_log_.BeginEvent(
- NetLog::TYPE_UDP_CONNECT,
+ NetLogEventType::UDP_CONNECT,
CreateNetLogUDPConnectCallback(
&address, NetworkChangeNotifier::kInvalidNetworkHandle));
int rv = InternalConnect(address);
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::UDP_CONNECT, rv);
is_connected_ = (rv == OK);
return rv;
}
@@ -538,6 +541,19 @@ int UDPSocketWin::SetSendBufferSize(int32_t size) {
return ERR_SOCKET_SEND_BUFFER_SIZE_UNCHANGEABLE;
}
+int UDPSocketWin::SetDoNotFragment() {
+ DCHECK_NE(socket_, INVALID_SOCKET);
+ DCHECK(CalledOnValidThread());
+
+ if (addr_family_ == AF_INET6)
+ return OK;
+
+ DWORD val = 1;
+ int rv = setsockopt(socket_, IPPROTO_IP, IP_DONTFRAGMENT,
+ reinterpret_cast<const char*>(&val), sizeof(val));
+ return rv == 0 ? OK : MapSystemError(WSAGetLastError());
+}
+
int UDPSocketWin::AllowAddressReuse() {
DCHECK_NE(socket_, INVALID_SOCKET);
DCHECK(CalledOnValidThread());
@@ -688,13 +704,14 @@ void UDPSocketWin::LogRead(int result,
const char* bytes,
const IPEndPoint* address) const {
if (result < 0) {
- net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR, result);
+ net_log_.AddEventWithNetErrorCode(NetLogEventType::UDP_RECEIVE_ERROR,
+ result);
return;
}
if (net_log_.IsCapturing()) {
net_log_.AddEvent(
- NetLog::TYPE_UDP_BYTES_RECEIVED,
+ NetLogEventType::UDP_BYTES_RECEIVED,
CreateNetLogUDPDataTranferCallback(result, bytes, address));
}
@@ -705,13 +722,13 @@ void UDPSocketWin::LogWrite(int result,
const char* bytes,
const IPEndPoint* address) const {
if (result < 0) {
- net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR, result);
+ net_log_.AddEventWithNetErrorCode(NetLogEventType::UDP_SEND_ERROR, result);
return;
}
if (net_log_.IsCapturing()) {
net_log_.AddEvent(
- NetLog::TYPE_UDP_BYTES_SENT,
+ NetLogEventType::UDP_BYTES_SENT,
CreateNetLogUDPDataTranferCallback(result, bytes, address));
}
diff --git a/chromium/net/udp/udp_socket_win.h b/chromium/net/udp/udp_socket_win.h
index 14b801e36fe..87b42effd05 100644
--- a/chromium/net/udp/udp_socket_win.h
+++ b/chromium/net/udp/udp_socket_win.h
@@ -24,13 +24,15 @@
#include "net/base/net_export.h"
#include "net/base/network_change_notifier.h"
#include "net/base/rand_callback.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/udp/datagram_socket.h"
#include "net/udp/diff_serv_code_point.h"
namespace net {
class IPAddress;
+class NetLog;
+struct NetLogSource;
class NET_EXPORT UDPSocketWin
: NON_EXPORTED_BASE(public base::NonThreadSafe),
@@ -39,7 +41,7 @@ class NET_EXPORT UDPSocketWin
UDPSocketWin(DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
net::NetLog* net_log,
- const net::NetLog::Source& source);
+ const net::NetLogSource& source);
~UDPSocketWin() override;
// Opens the socket.
@@ -124,10 +126,17 @@ class NET_EXPORT UDPSocketWin
// Returns a net error code.
int SetSendBufferSize(int32_t size);
+ // Requests that packets sent by this socket not be fragment, either locally
+ // by the host, or by routers (via the DF bit in the IPv4 packet header).
+ // May not be supported by all platforms. Returns a return a network error
+ // code if there was a problem, but the socket will still be usable. Can not
+ // return ERR_IO_PENDING.
+ int SetDoNotFragment();
+
// Returns true if the socket is already connected or bound.
bool is_connected() const { return is_connected_; }
- const BoundNetLog& NetLog() const { return net_log_; }
+ const NetLogWithSource& NetLog() const { return net_log_; }
// Sets corresponding flags in |socket_options_| to allow the socket
// to share the local address to which the socket will be bound with
@@ -310,7 +319,7 @@ class NET_EXPORT UDPSocketWin
// External callback; called when write is complete.
CompletionCallback write_callback_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
// QWAVE data. Used to set DSCP bits on outgoing packets.
HANDLE qos_handle_;
diff --git a/chromium/net/url_request/data_protocol_handler.h b/chromium/net/url_request/data_protocol_handler.h
index bb4e093703d..c65758f01e0 100644
--- a/chromium/net/url_request/data_protocol_handler.h
+++ b/chromium/net/url_request/data_protocol_handler.h
@@ -7,6 +7,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "net/base/net_export.h"
#include "net/url_request/url_request_job_factory.h"
namespace net {
diff --git a/chromium/net/url_request/file_protocol_handler.h b/chromium/net/url_request/file_protocol_handler.h
index 4a66df15058..954d0162921 100644
--- a/chromium/net/url_request/file_protocol_handler.h
+++ b/chromium/net/url_request/file_protocol_handler.h
@@ -8,6 +8,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "net/base/net_export.h"
#include "net/url_request/url_request_job_factory.h"
class GURL;
diff --git a/chromium/net/url_request/ftp_protocol_handler.h b/chromium/net/url_request/ftp_protocol_handler.h
index 8e402256cfe..bb7796bb7c6 100644
--- a/chromium/net/url_request/ftp_protocol_handler.h
+++ b/chromium/net/url_request/ftp_protocol_handler.h
@@ -9,6 +9,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "net/base/net_export.h"
#include "net/url_request/url_request_job_factory.h"
namespace net {
diff --git a/chromium/net/url_request/report_sender.cc b/chromium/net/url_request/report_sender.cc
index bc8e11d6b47..b99ef692d6b 100644
--- a/chromium/net/url_request/report_sender.cc
+++ b/chromium/net/url_request/report_sender.cc
@@ -6,7 +6,6 @@
#include <utility>
-#include "base/stl_util.h"
#include "net/base/elements_upload_data_stream.h"
#include "net/base/load_flags.h"
#include "net/base/request_priority.h"
@@ -28,11 +27,12 @@ ReportSender::ReportSender(URLRequestContext* request_context,
error_callback_(error_callback) {}
ReportSender::~ReportSender() {
- // Cancel all of the uncompleted requests.
- STLDeleteElements(&inflight_requests_);
}
-void ReportSender::Send(const GURL& report_uri, const std::string& report) {
+void ReportSender::Send(const GURL& report_uri,
+ base::StringPiece content_type,
+ base::StringPiece report) {
+ DCHECK(!content_type.empty());
std::unique_ptr<URLRequest> url_request =
request_context_->CreateRequest(report_uri, DEFAULT_PRIORITY, this);
@@ -43,15 +43,20 @@ void ReportSender::Send(const GURL& report_uri, const std::string& report) {
}
url_request->SetLoadFlags(load_flags);
+ HttpRequestHeaders extra_headers;
+ extra_headers.SetHeader(HttpRequestHeaders::kContentType, content_type);
+ url_request->SetExtraRequestHeaders(extra_headers);
+
url_request->set_method("POST");
+ std::vector<char> report_data(report.begin(), report.end());
std::unique_ptr<UploadElementReader> reader(
- UploadOwnedBytesElementReader::CreateWithString(report));
+ new UploadOwnedBytesElementReader(&report_data));
url_request->set_upload(
ElementsUploadDataStream::CreateWithReader(std::move(reader), 0));
URLRequest* raw_url_request = url_request.get();
- inflight_requests_.insert(url_request.release());
+ inflight_requests_[raw_url_request] = std::move(url_request);
raw_url_request->Start();
}
@@ -59,16 +64,16 @@ void ReportSender::SetErrorCallback(const ErrorCallback& error_callback) {
error_callback_ = error_callback;
}
-void ReportSender::OnResponseStarted(URLRequest* request) {
- if (!request->status().is_success()) {
+void ReportSender::OnResponseStarted(URLRequest* request, int net_error) {
+ DCHECK_NE(ERR_IO_PENDING, net_error);
+
+ if (net_error != OK) {
DVLOG(1) << "Failed to send report for " << request->url().host();
if (!error_callback_.is_null())
- error_callback_.Run(request->url(), request->status().error());
+ error_callback_.Run(request->url(), net_error);
}
CHECK_GT(inflight_requests_.erase(request), 0u);
- // Clean up the request, which cancels it.
- delete request;
}
void ReportSender::OnReadCompleted(URLRequest* request, int bytes_read) {
diff --git a/chromium/net/url_request/report_sender.h b/chromium/net/url_request/report_sender.h
index cdc371b1330..8fa46ca330d 100644
--- a/chromium/net/url_request/report_sender.h
+++ b/chromium/net/url_request/report_sender.h
@@ -5,12 +5,13 @@
#ifndef NET_URL_REQUEST_REPORT_SENDER_H_
#define NET_URL_REQUEST_REPORT_SENDER_H_
+#include <map>
#include <memory>
-#include <set>
#include <string>
#include "base/callback.h"
#include "base/macros.h"
+#include "net/base/net_export.h"
#include "net/http/transport_security_state.h"
#include "net/url_request/url_request.h"
@@ -54,11 +55,13 @@ class NET_EXPORT ReportSender
~ReportSender() override;
// TransportSecurityState::ReportSenderInterface implementation.
- void Send(const GURL& report_uri, const std::string& report) override;
+ void Send(const GURL& report_uri,
+ base::StringPiece content_type,
+ base::StringPiece report) override;
void SetErrorCallback(const ErrorCallback& error_callback) override;
// net::URLRequest::Delegate implementation.
- void OnResponseStarted(URLRequest* request) override;
+ void OnResponseStarted(URLRequest* request, int net_error) override;
void OnReadCompleted(URLRequest* request, int bytes_read) override;
private:
@@ -66,8 +69,7 @@ class NET_EXPORT ReportSender
CookiesPreference cookies_preference_;
- // Owns the contained requests.
- std::set<URLRequest*> inflight_requests_;
+ std::map<URLRequest*, std::unique_ptr<URLRequest>> inflight_requests_;
// Called when a sent report results in an error.
ErrorCallback error_callback_;
diff --git a/chromium/net/url_request/report_sender_unittest.cc b/chromium/net/url_request/report_sender_unittest.cc
index 2143fbac876..4d1096ddc16 100644
--- a/chromium/net/url_request/report_sender_unittest.cc
+++ b/chromium/net/url_request/report_sender_unittest.cc
@@ -87,6 +87,10 @@ class TestReportSenderNetworkDelegate : public NetworkDelegateImpl {
expect_cookies_ = expect_cookies;
}
+ void set_expected_content_type(const std::string& content_type) {
+ expected_content_type_ = content_type;
+ }
+
// NetworkDelegateImpl implementation.
int OnBeforeURLRequest(URLRequest* request,
const CompletionCallback& callback,
@@ -103,6 +107,12 @@ class TestReportSenderNetworkDelegate : public NetworkDelegateImpl {
EXPECT_TRUE(request->load_flags() & LOAD_DO_NOT_SAVE_COOKIES);
}
+ const HttpRequestHeaders& extra_headers = request->extra_request_headers();
+ std::string content_type;
+ EXPECT_TRUE(extra_headers.GetHeader(HttpRequestHeaders::kContentType,
+ &content_type));
+ EXPECT_EQ(expected_content_type_, content_type);
+
CheckUploadData(*request, &expect_reports_);
// Unconditionally return OK, since the sender ignores the results
@@ -123,6 +133,7 @@ class TestReportSenderNetworkDelegate : public NetworkDelegateImpl {
GURL expect_url_;
std::set<std::string> expect_reports_;
bool expect_cookies_;
+ std::string expected_content_type_;
DISALLOW_COPY_AND_ASSIGN(TestReportSenderNetworkDelegate);
};
@@ -154,10 +165,11 @@ class ReportSenderTest : public ::testing::Test {
network_delegate_.set_expect_url(url);
network_delegate_.ExpectReport(report);
+ network_delegate_.set_expected_content_type("application/foobar");
EXPECT_EQ(request_sequence_number, network_delegate_.num_requests());
- reporter->Send(url, report);
+ reporter->Send(url, "application/foobar", report);
// The report is sent asynchronously, so wait for the report's
// URLRequest to be destroyed before checking that the report was
@@ -197,13 +209,14 @@ TEST_F(ReportSenderTest, SendMultipleReportsSimultaneously) {
network_delegate_.set_expect_url(url);
network_delegate_.ExpectReport(kDummyReport);
network_delegate_.ExpectReport(kSecondDummyReport);
+ network_delegate_.set_expected_content_type("application/foobar");
ReportSender reporter(context(), ReportSender::DO_NOT_SEND_COOKIES);
EXPECT_EQ(0u, network_delegate_.num_requests());
- reporter.Send(url, kDummyReport);
- reporter.Send(url, kSecondDummyReport);
+ reporter.Send(url, "application/foobar", kDummyReport);
+ reporter.Send(url, "application/foobar", kSecondDummyReport);
run_loop.Run();
@@ -221,12 +234,13 @@ TEST_F(ReportSenderTest, PendingRequestGetsDeleted) {
URLRequestFailedJob::START, ERR_IO_PENDING);
network_delegate_.set_expect_url(url);
network_delegate_.ExpectReport(kDummyReport);
+ network_delegate_.set_expected_content_type("application/foobar");
EXPECT_EQ(0u, network_delegate_.num_requests());
std::unique_ptr<ReportSender> reporter(
new ReportSender(context(), ReportSender::DO_NOT_SEND_COOKIES));
- reporter->Send(url, kDummyReport);
+ reporter->Send(url, "application/foobar", kDummyReport);
reporter.reset();
EXPECT_EQ(1u, network_delegate_.num_requests());
diff --git a/chromium/net/url_request/sdch_dictionary_fetcher.cc b/chromium/net/url_request/sdch_dictionary_fetcher.cc
index 8d90f5f0ea2..cf711592377 100644
--- a/chromium/net/url_request/sdch_dictionary_fetcher.cc
+++ b/chromium/net/url_request/sdch_dictionary_fetcher.cc
@@ -17,7 +17,8 @@
#include "net/base/load_flags.h"
#include "net/base/sdch_net_log_params.h"
#include "net/http/http_response_headers.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/url_request/redirect_info.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_status.h"
@@ -31,17 +32,15 @@ const int kBufferSize = 4096;
// Map the bytes_read result from a read attempt and a URLRequest's
// status into a single net return value.
-int GetReadResult(int bytes_read, const URLRequest* request) {
- int rv = request->status().error();
- if (request->status().is_success() && bytes_read < 0) {
+int GetReadResult(int rv, const URLRequest* request) {
+ DCHECK_NE(ERR_IO_PENDING, rv);
+
+ if (rv < 0) {
rv = ERR_FAILED;
request->net_log().AddEventWithNetErrorCode(
- NetLog::TYPE_SDCH_DICTIONARY_FETCH_IMPLIED_ERROR, rv);
+ NetLogEventType::SDCH_DICTIONARY_FETCH_IMPLIED_ERROR, rv);
}
- if (rv == OK)
- rv = bytes_read;
-
return rv;
}
@@ -155,28 +154,29 @@ void SdchDictionaryFetcher::OnReceivedRedirect(
DoLoop(OK);
}
-void SdchDictionaryFetcher::OnResponseStarted(URLRequest* request) {
+void SdchDictionaryFetcher::OnResponseStarted(URLRequest* request,
+ int net_error) {
DCHECK(CalledOnValidThread());
DCHECK_EQ(request, current_request_.get());
DCHECK_EQ(next_state_, STATE_SEND_REQUEST_PENDING);
DCHECK(!in_loop_);
+ DCHECK_NE(ERR_IO_PENDING, net_error);
// Confirm that the response isn't a stale read from the cache (as
// may happen in the reload case). If the response was not retrieved over
// HTTP, it is presumed to be fresh.
HttpResponseHeaders* response_headers = request->response_headers();
- int result = request->status().error();
- if (result == OK && response_headers) {
+ if (net_error == OK && response_headers) {
ValidationType validation_type = response_headers->RequiresValidation(
request->response_info().request_time,
request->response_info().response_time, base::Time::Now());
// TODO(rdsmith): Maybe handle VALIDATION_ASYNCHRONOUS by queueing
// a non-reload request for the dictionary.
if (validation_type != VALIDATION_NONE)
- result = ERR_FAILED;
+ net_error = ERR_FAILED;
}
- DoLoop(result);
+ DoLoop(net_error);
}
void SdchDictionaryFetcher::OnReadCompleted(URLRequest* request,
@@ -185,6 +185,7 @@ void SdchDictionaryFetcher::OnReadCompleted(URLRequest* request,
DCHECK_EQ(request, current_request_.get());
DCHECK_EQ(next_state_, STATE_READ_BODY_COMPLETE);
DCHECK(!in_loop_);
+ DCHECK_NE(ERR_IO_PENDING, bytes_read);
DoLoop(GetReadResult(bytes_read, current_request_.get()));
}
@@ -290,7 +291,7 @@ int SdchDictionaryFetcher::DoSendRequest(int rv) {
current_callback_ = info.callback;
current_request_->Start();
- current_request_->net_log().AddEvent(NetLog::TYPE_SDCH_DICTIONARY_FETCH);
+ current_request_->net_log().AddEvent(NetLogEventType::SDCH_DICTIONARY_FETCH);
return ERR_IO_PENDING;
}
@@ -329,9 +330,8 @@ int SdchDictionaryFetcher::DoReadBody(int rv) {
}
next_state_ = STATE_READ_BODY_COMPLETE;
- int bytes_read = 0;
- current_request_->Read(buffer_.get(), kBufferSize, &bytes_read);
- if (current_request_->status().is_io_pending())
+ int bytes_read = current_request_->Read(buffer_.get(), kBufferSize);
+ if (bytes_read == ERR_IO_PENDING)
return ERR_IO_PENDING;
return GetReadResult(bytes_read, current_request_.get());
@@ -347,7 +347,7 @@ int SdchDictionaryFetcher::DoReadBodyComplete(int rv) {
return OK;
}
- DCHECK(current_request_->status().is_success());
+ DCHECK_GE(rv, 0);
// Data; append to the dictionary and look for more data.
if (rv > 0) {
diff --git a/chromium/net/url_request/sdch_dictionary_fetcher.h b/chromium/net/url_request/sdch_dictionary_fetcher.h
index ea59582d80b..8c622b6aef6 100644
--- a/chromium/net/url_request/sdch_dictionary_fetcher.h
+++ b/chromium/net/url_request/sdch_dictionary_fetcher.h
@@ -17,6 +17,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/threading/non_thread_safe.h"
+#include "net/base/net_export.h"
#include "net/base/sdch_manager.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request.h"
@@ -24,7 +25,7 @@
namespace net {
-class BoundNetLog;
+class NetLogWithSource;
class URLRequest;
class URLRequestThrottlerEntryInterface;
@@ -38,7 +39,7 @@ class NET_EXPORT SdchDictionaryFetcher : public URLRequest::Delegate,
public:
typedef base::Callback<void(const std::string& dictionary_text,
const GURL& dictionary_url,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
bool was_from_cache)>
OnDictionaryFetchedCallback;
@@ -65,7 +66,7 @@ class NET_EXPORT SdchDictionaryFetcher : public URLRequest::Delegate,
void OnReceivedRedirect(URLRequest* request,
const RedirectInfo& redirect_info,
bool* defer_redirect) override;
- void OnResponseStarted(URLRequest* request) override;
+ void OnResponseStarted(URLRequest* request, int net_error) override;
void OnReadCompleted(URLRequest* request, int bytes_read) override;
private:
diff --git a/chromium/net/url_request/sdch_dictionary_fetcher_unittest.cc b/chromium/net/url_request/sdch_dictionary_fetcher_unittest.cc
index 02a9987f360..2b1f2d36e11 100644
--- a/chromium/net/url_request/sdch_dictionary_fetcher_unittest.cc
+++ b/chromium/net/url_request/sdch_dictionary_fetcher_unittest.cc
@@ -285,7 +285,7 @@ class SdchDictionaryFetcherTest : public ::testing::Test {
void OnDictionaryFetched(const std::string& dictionary_text,
const GURL& dictionary_url,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
bool was_from_cache) {
dictionary_additions_.push_back(
DictionaryAdditions(dictionary_text, dictionary_url));
diff --git a/chromium/net/url_request/test_url_fetcher_factory.cc b/chromium/net/url_request/test_url_fetcher_factory.cc
index 99d8de68dd0..24c9bf1f1b3 100644
--- a/chromium/net/url_request/test_url_fetcher_factory.cc
+++ b/chromium/net/url_request/test_url_fetcher_factory.cc
@@ -188,7 +188,7 @@ void TestURLFetcher::SaveResponseWithWriter(
fake_response_string_.size(),
CompletionCallback());
DCHECK_EQ(static_cast<int>(fake_response_string_.size()), response);
- response = response_writer_->Finish(CompletionCallback());
+ response = response_writer_->Finish(OK, CompletionCallback());
DCHECK_EQ(OK, response);
} else if (fake_response_destination_ == TEMP_FILE) {
// SaveResponseToFileAtPath() should be called instead of this method to
@@ -398,7 +398,7 @@ void FakeURLFetcher::RunDelegate() {
// this with a weak pointer, and only call OnURLFetchComplete if this still
// exists.
auto weak_this = weak_factory_.GetWeakPtr();
- delegate()->OnURLFetchDownloadProgress(this, response_bytes_,
+ delegate()->OnURLFetchDownloadProgress(this, response_bytes_, response_bytes_,
response_bytes_);
if (weak_this.get())
delegate()->OnURLFetchComplete(this);
diff --git a/chromium/net/url_request/url_fetcher_core.cc b/chromium/net/url_request/url_fetcher_core.cc
index 0f75e6789c0..2337cb5b425 100644
--- a/chromium/net/url_request/url_fetcher_core.cc
+++ b/chromium/net/url_request/url_fetcher_core.cc
@@ -50,12 +50,12 @@ URLFetcherCore::Registry::Registry() {}
URLFetcherCore::Registry::~Registry() {}
void URLFetcherCore::Registry::AddURLFetcherCore(URLFetcherCore* core) {
- DCHECK(!ContainsKey(fetchers_, core));
+ DCHECK(!base::ContainsKey(fetchers_, core));
fetchers_.insert(core);
}
void URLFetcherCore::Registry::RemoveURLFetcherCore(URLFetcherCore* core) {
- DCHECK(ContainsKey(fetchers_, core));
+ DCHECK(base::ContainsKey(fetchers_, core));
fetchers_.erase(core);
}
@@ -407,15 +407,17 @@ void URLFetcherCore::OnReceivedRedirect(URLRequest* request,
was_fetched_via_proxy_ = request_->was_fetched_via_proxy();
was_cached_ = request_->was_cached();
total_received_bytes_ += request_->GetTotalReceivedBytes();
- request->Cancel();
- OnReadCompleted(request, 0);
+ int result = request->Cancel();
+ OnReadCompleted(request, result);
}
}
-void URLFetcherCore::OnResponseStarted(URLRequest* request) {
+void URLFetcherCore::OnResponseStarted(URLRequest* request, int net_error) {
DCHECK_EQ(request, request_.get());
DCHECK(network_task_runner_->BelongsToCurrentThread());
- if (request_->status().is_success()) {
+ DCHECK_NE(ERR_IO_PENDING, net_error);
+
+ if (net_error == OK) {
response_code_ = request_->GetResponseCode();
response_headers_ = request_->response_headers();
socket_address_ = request_->GetSocketAddress();
@@ -452,10 +454,7 @@ void URLFetcherCore::OnReadCompleted(URLRequest* request,
if (throttler_manager)
url_throttler_entry_ = throttler_manager->RegisterRequestUrl(url_);
- do {
- if (!request_->status().is_success() || bytes_read <= 0)
- break;
-
+ while (bytes_read > 0) {
current_response_bytes_ += bytes_read;
InformDelegateDownloadProgress();
@@ -465,13 +464,12 @@ void URLFetcherCore::OnReadCompleted(URLRequest* request,
// Write failed or waiting for write completion.
return;
}
- } while (request_->Read(buffer_.get(), kBufferSize, &bytes_read));
-
- const URLRequestStatus status = request_->status();
+ bytes_read = request_->Read(buffer_.get(), kBufferSize);
+ }
// See comments re: HEAD requests in ReadResponse().
- if (!status.is_io_pending() || request_type_ == URLFetcher::HEAD) {
- status_ = status;
+ if (bytes_read != ERR_IO_PENDING || request_type_ == URLFetcher::HEAD) {
+ status_ = URLRequestStatus::FromError(bytes_read);
received_response_content_length_ =
request_->received_response_content_length();
total_received_bytes_ += request_->GetTotalReceivedBytes();
@@ -479,6 +477,7 @@ void URLFetcherCore::OnReadCompleted(URLRequest* request,
// No more data to write.
const int result = response_writer_->Finish(
+ bytes_read > 0 ? OK : bytes_read,
base::Bind(&URLFetcherCore::DidFinishWriting, this));
if (result != ERR_IO_PENDING)
DidFinishWriting(result);
@@ -863,7 +862,7 @@ int URLFetcherCore::WriteBuffer(scoped_refptr<DrainableIOBuffer> data) {
void URLFetcherCore::DidWriteBuffer(scoped_refptr<DrainableIOBuffer> data,
int result) {
if (result < 0) { // Handle errors.
- response_writer_->Finish(base::Bind(&EmptyCompletionCallback));
+ response_writer_->Finish(result, base::Bind(&EmptyCompletionCallback));
CancelRequestAndInformDelegate(result);
return;
}
@@ -886,11 +885,9 @@ void URLFetcherCore::ReadResponse() {
// completed immediately, without trying to read any data back (all we care
// about is the response code and headers, which we already have).
int bytes_read = 0;
- if (request_->status().is_success() &&
- (request_type_ != URLFetcher::HEAD)) {
- if (!request_->Read(buffer_.get(), kBufferSize, &bytes_read))
- bytes_read = -1; // Match OnReadCompleted() interface contract.
- }
+ if (request_type_ != URLFetcher::HEAD)
+ bytes_read = request_->Read(buffer_.get(), kBufferSize);
+
OnReadCompleted(request_.get(), bytes_read);
}
@@ -936,16 +933,19 @@ void URLFetcherCore::InformDelegateDownloadProgress() {
delegate_task_runner_->PostTask(
FROM_HERE,
base::Bind(
- &URLFetcherCore::InformDelegateDownloadProgressInDelegateThread,
- this, current_response_bytes_, total_response_bytes_));
+ &URLFetcherCore::InformDelegateDownloadProgressInDelegateThread, this,
+ current_response_bytes_, total_response_bytes_,
+ request_->GetTotalReceivedBytes()));
}
void URLFetcherCore::InformDelegateDownloadProgressInDelegateThread(
int64_t current,
- int64_t total) {
+ int64_t total,
+ int64_t current_network_bytes) {
DCHECK(delegate_task_runner_->BelongsToCurrentThread());
if (delegate_)
- delegate_->OnURLFetchDownloadProgress(fetcher_, current, total);
+ delegate_->OnURLFetchDownloadProgress(fetcher_, current, total,
+ current_network_bytes);
}
void URLFetcherCore::AssertHasNoUploadData() const {
diff --git a/chromium/net/url_request/url_fetcher_core.h b/chromium/net/url_request/url_fetcher_core.h
index 5ba4a5ac1fd..415badfa323 100644
--- a/chromium/net/url_request/url_fetcher_core.h
+++ b/chromium/net/url_request/url_fetcher_core.h
@@ -136,7 +136,7 @@ class URLFetcherCore : public base::RefCountedThreadSafe<URLFetcherCore>,
void OnReceivedRedirect(URLRequest* request,
const RedirectInfo& redirect_info,
bool* defer_redirect) override;
- void OnResponseStarted(URLRequest* request) override;
+ void OnResponseStarted(URLRequest* request, int net_error) override;
void OnReadCompleted(URLRequest* request, int bytes_read) override;
void OnCertificateRequested(URLRequest* request,
SSLCertRequestInfo* cert_request_info) override;
@@ -220,8 +220,10 @@ class URLFetcherCore : public base::RefCountedThreadSafe<URLFetcherCore>,
void InformDelegateUploadProgressInDelegateThread(int64_t current,
int64_t total);
void InformDelegateDownloadProgress();
- void InformDelegateDownloadProgressInDelegateThread(int64_t current,
- int64_t total);
+ void InformDelegateDownloadProgressInDelegateThread(
+ int64_t current,
+ int64_t total,
+ int64_t current_network_bytes);
// Check if any upload data is set or not.
void AssertHasNoUploadData() const;
diff --git a/chromium/net/url_request/url_fetcher_delegate.cc b/chromium/net/url_request/url_fetcher_delegate.cc
index 0d2edd961e9..18b9ab1b419 100644
--- a/chromium/net/url_request/url_fetcher_delegate.cc
+++ b/chromium/net/url_request/url_fetcher_delegate.cc
@@ -6,9 +6,11 @@
namespace net {
-void URLFetcherDelegate::OnURLFetchDownloadProgress(const URLFetcher* source,
- int64_t current,
- int64_t total) {}
+void URLFetcherDelegate::OnURLFetchDownloadProgress(
+ const URLFetcher* source,
+ int64_t current,
+ int64_t total,
+ int64_t current_network_bytes) {}
void URLFetcherDelegate::OnURLFetchUploadProgress(const URLFetcher* source,
int64_t current,
diff --git a/chromium/net/url_request/url_fetcher_delegate.h b/chromium/net/url_request/url_fetcher_delegate.h
index 192e70ac096..52f6567e059 100644
--- a/chromium/net/url_request/url_fetcher_delegate.h
+++ b/chromium/net/url_request/url_fetcher_delegate.h
@@ -26,9 +26,12 @@ class NET_EXPORT URLFetcherDelegate {
// This will be called when some part of the response is read. |current|
// denotes the number of bytes received up to the call, and |total| is the
// expected total size of the response (or -1 if not determined).
+ // |current_network_bytes| denotes the number of network bytes received
+ // up to the call, excluding redirect bodies, SSL and proxy handshakes.
virtual void OnURLFetchDownloadProgress(const URLFetcher* source,
int64_t current,
- int64_t total);
+ int64_t total,
+ int64_t current_network_bytes);
// This will be called when uploading of POST or PUT requests proceeded.
// |current| denotes the number of bytes sent so far, and |total| is the
diff --git a/chromium/net/url_request/url_fetcher_impl_unittest.cc b/chromium/net/url_request/url_fetcher_impl_unittest.cc
index 853ea7169c3..d48f74987de 100644
--- a/chromium/net/url_request/url_fetcher_impl_unittest.cc
+++ b/chromium/net/url_request/url_fetcher_impl_unittest.cc
@@ -39,10 +39,12 @@
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_response_headers.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/gtest_util.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_test_util.h"
#include "net/url_request/url_request_throttler_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(USE_NSS_CERTS)
@@ -53,6 +55,8 @@ namespace net {
using base::Time;
using base::TimeDelta;
+using net::test::IsError;
+using net::test::IsOk;
// TODO(eroman): Add a regression test for http://crbug.com/40505.
@@ -123,7 +127,8 @@ class WaitingURLFetcherDelegate : public URLFetcherDelegate {
void OnURLFetchDownloadProgress(const URLFetcher* source,
int64_t current,
- int64_t total) override {
+ int64_t total,
+ int64_t current_network_bytes) override {
// Note that the current progress may be greater than the previous progress,
// in the case of retrying the request.
EXPECT_FALSE(did_complete_);
@@ -175,7 +180,7 @@ class FetcherTestURLRequestContext : public TestURLRequestContext {
context_storage_.set_host_resolver(
std::unique_ptr<HostResolver>(mock_resolver_));
context_storage_.set_throttler_manager(
- base::WrapUnique(new URLRequestThrottlerManager()));
+ base::MakeUnique<URLRequestThrottlerManager>());
Init();
}
@@ -563,7 +568,8 @@ TEST_F(URLFetcherTest, DontRetryOnNetworkChangedByDefault) {
// And the owner of the fetcher gets the ERR_NETWORK_CHANGED error.
EXPECT_EQ(hanging_url(), delegate.fetcher()->GetOriginalURL());
ASSERT_FALSE(delegate.fetcher()->GetStatus().is_success());
- EXPECT_EQ(ERR_NETWORK_CHANGED, delegate.fetcher()->GetStatus().error());
+ EXPECT_THAT(delegate.fetcher()->GetStatus().error(),
+ IsError(ERR_NETWORK_CHANGED));
}
TEST_F(URLFetcherTest, RetryOnNetworkChangedAndFail) {
@@ -610,7 +616,8 @@ TEST_F(URLFetcherTest, RetryOnNetworkChangedAndFail) {
// And the owner of the fetcher gets the ERR_NETWORK_CHANGED error.
EXPECT_EQ(hanging_url(), delegate.fetcher()->GetOriginalURL());
ASSERT_FALSE(delegate.fetcher()->GetStatus().is_success());
- EXPECT_EQ(ERR_NETWORK_CHANGED, delegate.fetcher()->GetStatus().error());
+ EXPECT_THAT(delegate.fetcher()->GetStatus().error(),
+ IsError(ERR_NETWORK_CHANGED));
}
TEST_F(URLFetcherTest, RetryOnNetworkChangedAndSucceed) {
@@ -836,7 +843,8 @@ TEST_F(URLFetcherTest, PostAppendChunkAfterError) {
// Make sure the request failed, as expected.
EXPECT_FALSE(delegate.fetcher()->GetStatus().is_success());
- EXPECT_EQ(ERR_UNSAFE_PORT, delegate.fetcher()->GetStatus().error());
+ EXPECT_THAT(delegate.fetcher()->GetStatus().error(),
+ IsError(ERR_UNSAFE_PORT));
}
// Checks that upload progress increases over time, never exceeds what's already
@@ -917,10 +925,11 @@ class CheckDownloadProgressDelegate : public WaitingURLFetcherDelegate {
void OnURLFetchDownloadProgress(const URLFetcher* source,
int64_t current,
- int64_t total) override {
+ int64_t total,
+ int64_t current_network_bytes) override {
// Run default checks.
- WaitingURLFetcherDelegate::OnURLFetchDownloadProgress(source, current,
- total);
+ WaitingURLFetcherDelegate::OnURLFetchDownloadProgress(
+ source, current, total, current_network_bytes);
EXPECT_LE(last_seen_progress_, current);
EXPECT_EQ(file_size_, total);
@@ -1004,7 +1013,8 @@ class CancelOnDownloadProgressDelegate : public WaitingURLFetcherDelegate {
void OnURLFetchDownloadProgress(const URLFetcher* source,
int64_t current,
- int64_t total) override {
+ int64_t total,
+ int64_t current_network_bytes) override {
CancelFetch();
}
@@ -1073,7 +1083,7 @@ TEST_F(URLFetcherTest, StopOnRedirect) {
EXPECT_EQ(GURL(kRedirectTarget), delegate.fetcher()->GetURL());
EXPECT_EQ(URLRequestStatus::CANCELED,
delegate.fetcher()->GetStatus().status());
- EXPECT_EQ(ERR_ABORTED, delegate.fetcher()->GetStatus().error());
+ EXPECT_THAT(delegate.fetcher()->GetStatus().error(), IsError(ERR_ABORTED));
EXPECT_EQ(301, delegate.fetcher()->GetResponseCode());
}
@@ -1383,12 +1393,14 @@ TEST_F(URLFetcherTest, ShutdownSameThread) {
// Wait for the first fetcher, make sure it failed.
delegate1.WaitForComplete();
EXPECT_FALSE(delegate1.fetcher()->GetStatus().is_success());
- EXPECT_EQ(ERR_CONTEXT_SHUT_DOWN, delegate1.fetcher()->GetStatus().error());
+ EXPECT_THAT(delegate1.fetcher()->GetStatus().error(),
+ IsError(ERR_CONTEXT_SHUT_DOWN));
// Wait for the second fetcher, make sure it failed.
delegate2.WaitForComplete();
EXPECT_FALSE(delegate2.fetcher()->GetStatus().is_success());
- EXPECT_EQ(ERR_CONTEXT_SHUT_DOWN, delegate2.fetcher()->GetStatus().error());
+ EXPECT_THAT(delegate2.fetcher()->GetStatus().error(),
+ IsError(ERR_CONTEXT_SHUT_DOWN));
// New fetchers should automatically fail without making new requests. This
// should follow the same path as the second fetcher, but best to be safe.
@@ -1397,7 +1409,8 @@ TEST_F(URLFetcherTest, ShutdownSameThread) {
delegate3.fetcher()->Start();
delegate3.WaitForComplete();
EXPECT_FALSE(delegate3.fetcher()->GetStatus().is_success());
- EXPECT_EQ(ERR_CONTEXT_SHUT_DOWN, delegate3.fetcher()->GetStatus().error());
+ EXPECT_THAT(delegate3.fetcher()->GetStatus().error(),
+ IsError(ERR_CONTEXT_SHUT_DOWN));
}
TEST_F(URLFetcherTest, ShutdownCrossThread) {
@@ -1412,14 +1425,16 @@ TEST_F(URLFetcherTest, ShutdownCrossThread) {
context_getter->Shutdown();
delegate1.WaitForComplete();
EXPECT_FALSE(delegate1.fetcher()->GetStatus().is_success());
- EXPECT_EQ(ERR_CONTEXT_SHUT_DOWN, delegate1.fetcher()->GetStatus().error());
+ EXPECT_THAT(delegate1.fetcher()->GetStatus().error(),
+ IsError(ERR_CONTEXT_SHUT_DOWN));
// New requests should automatically fail without making new requests.
WaitingURLFetcherDelegate delegate2;
delegate2.CreateFetcher(hanging_url(), URLFetcher::GET, context_getter);
delegate2.StartFetcherAndWait();
EXPECT_FALSE(delegate2.fetcher()->GetStatus().is_success());
- EXPECT_EQ(ERR_CONTEXT_SHUT_DOWN, delegate2.fetcher()->GetStatus().error());
+ EXPECT_THAT(delegate2.fetcher()->GetStatus().error(),
+ IsError(ERR_CONTEXT_SHUT_DOWN));
}
// Get a small file.
@@ -1428,7 +1443,7 @@ TEST_F(URLFetcherTest, FileTestSmallGet) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- base::FilePath out_path = temp_dir.path().AppendASCII(kFileToFetch);
+ base::FilePath out_path = temp_dir.GetPath().AppendASCII(kFileToFetch);
SaveFileTest(kFileToFetch, false, out_path, false);
}
@@ -1439,7 +1454,7 @@ TEST_F(URLFetcherTest, FileTestLargeGet) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- base::FilePath out_path = temp_dir.path().AppendASCII(kFileToFetch);
+ base::FilePath out_path = temp_dir.GetPath().AppendASCII(kFileToFetch);
SaveFileTest(kFileToFetch, false, out_path, false);
}
@@ -1450,7 +1465,7 @@ TEST_F(URLFetcherTest, FileTestTakeOwnership) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- base::FilePath out_path = temp_dir.path().AppendASCII(kFileToFetch);
+ base::FilePath out_path = temp_dir.GetPath().AppendASCII(kFileToFetch);
SaveFileTest(kFileToFetch, false, out_path, true);
}
@@ -1462,7 +1477,7 @@ TEST_F(URLFetcherTest, FileTestOverwriteExisting) {
// Create a file before trying to fetch.
const char kFileToFetch[] = "simple.html";
std::string data(10000, '?'); // Meant to be larger than simple.html.
- base::FilePath out_path = temp_dir.path().AppendASCII(kFileToFetch);
+ base::FilePath out_path = temp_dir.GetPath().AppendASCII(kFileToFetch);
ASSERT_EQ(static_cast<int>(data.size()),
base::WriteFile(out_path, data.data(), data.size()));
ASSERT_TRUE(base::PathExists(out_path));
@@ -1477,7 +1492,7 @@ TEST_F(URLFetcherTest, FileTestTryToOverwriteDirectory) {
// Create a directory before trying to fetch.
static const char kFileToFetch[] = "simple.html";
- base::FilePath out_path = temp_dir.path().AppendASCII(kFileToFetch);
+ base::FilePath out_path = temp_dir.GetPath().AppendASCII(kFileToFetch);
ASSERT_TRUE(base::CreateDirectory(out_path));
ASSERT_TRUE(base::PathExists(out_path));
@@ -1491,7 +1506,8 @@ TEST_F(URLFetcherTest, FileTestTryToOverwriteDirectory) {
delegate.StartFetcherAndWait();
EXPECT_FALSE(delegate.fetcher()->GetStatus().is_success());
- EXPECT_EQ(ERR_ACCESS_DENIED, delegate.fetcher()->GetStatus().error());
+ EXPECT_THAT(delegate.fetcher()->GetStatus().error(),
+ IsError(ERR_ACCESS_DENIED));
}
// Get a small file and save it to a temp file.
@@ -1519,7 +1535,7 @@ TEST_F(URLFetcherBadHTTPSTest, BadHTTPS) {
EXPECT_EQ(URLRequestStatus::CANCELED,
delegate.fetcher()->GetStatus().status());
- EXPECT_EQ(ERR_ABORTED, delegate.fetcher()->GetStatus().error());
+ EXPECT_THAT(delegate.fetcher()->GetStatus().error(), IsError(ERR_ABORTED));
EXPECT_EQ(-1, delegate.fetcher()->GetResponseCode());
EXPECT_FALSE(delegate.fetcher()->GetResponseHeaders());
std::string data;
diff --git a/chromium/net/url_request/url_fetcher_response_writer.cc b/chromium/net/url_request/url_fetcher_response_writer.cc
index fcc8cbf38ff..3286e675ca1 100644
--- a/chromium/net/url_request/url_fetcher_response_writer.cc
+++ b/chromium/net/url_request/url_fetcher_response_writer.cc
@@ -4,6 +4,7 @@
#include "net/url_request/url_fetcher_response_writer.h"
+#include "base/callback_helpers.h"
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/sequenced_task_runner.h"
@@ -40,7 +41,8 @@ int URLFetcherStringWriter::Write(IOBuffer* buffer,
return num_bytes;
}
-int URLFetcherStringWriter::Finish(const CompletionCallback& callback) {
+int URLFetcherStringWriter::Finish(int net_error,
+ const CompletionCallback& callback) {
// Do nothing.
return OK;
}
@@ -64,9 +66,12 @@ URLFetcherFileWriter::~URLFetcherFileWriter() {
}
int URLFetcherFileWriter::Initialize(const CompletionCallback& callback) {
+ DCHECK(!callback_);
+
file_stream_.reset(new FileStream(file_task_runner_));
int result = ERR_IO_PENDING;
+ owns_file_ = true;
if (file_path_.empty()) {
base::FilePath* temp_file_path = new base::FilePath;
base::PostTaskAndReplyWithResult(
@@ -75,18 +80,22 @@ int URLFetcherFileWriter::Initialize(const CompletionCallback& callback) {
base::Bind(&base::CreateTemporaryFile, temp_file_path),
base::Bind(&URLFetcherFileWriter::DidCreateTempFile,
weak_factory_.GetWeakPtr(),
- callback,
base::Owned(temp_file_path)));
} else {
- result = file_stream_->Open(
- file_path_,
- base::File::FLAG_WRITE | base::File::FLAG_ASYNC |
- base::File::FLAG_CREATE_ALWAYS,
- base::Bind(&URLFetcherFileWriter::DidOpenFile,
- weak_factory_.GetWeakPtr(),
- callback));
+ result = file_stream_->Open(file_path_, base::File::FLAG_WRITE |
+ base::File::FLAG_ASYNC |
+ base::File::FLAG_CREATE_ALWAYS,
+ base::Bind(&URLFetcherFileWriter::OnIOCompleted,
+ weak_factory_.GetWeakPtr()));
DCHECK_NE(OK, result);
}
+
+ if (result == ERR_IO_PENDING) {
+ callback_ = callback;
+ return result;
+ }
+ if (result < 0)
+ CloseAndDeleteFile();
return result;
}
@@ -95,25 +104,44 @@ int URLFetcherFileWriter::Write(IOBuffer* buffer,
const CompletionCallback& callback) {
DCHECK(file_stream_);
DCHECK(owns_file_);
+ DCHECK(!callback_);
- int result = file_stream_->Write(buffer, num_bytes,
- base::Bind(&URLFetcherFileWriter::DidWrite,
- weak_factory_.GetWeakPtr(),
- callback));
- if (result < 0 && result != ERR_IO_PENDING)
+ int result = file_stream_->Write(
+ buffer, num_bytes, base::Bind(&URLFetcherFileWriter::OnIOCompleted,
+ weak_factory_.GetWeakPtr()));
+ if (result == ERR_IO_PENDING) {
+ callback_ = callback;
+ return result;
+ }
+ if (result < 0)
CloseAndDeleteFile();
-
return result;
}
-int URLFetcherFileWriter::Finish(const CompletionCallback& callback) {
+int URLFetcherFileWriter::Finish(int net_error,
+ const CompletionCallback& callback) {
+ DCHECK_NE(ERR_IO_PENDING, net_error);
+
+ // If an error occurred, simply delete the file after any pending operation
+ // is done. Do not call file_stream_->Close() because there might be an
+ // operation pending. See crbug.com/487732.
+ if (net_error < 0) {
+ // Cancel callback and invalid weak ptrs so as to cancel any posted task.
+ callback_.Reset();
+ weak_factory_.InvalidateWeakPtrs();
+ CloseAndDeleteFile();
+ return OK;
+ }
+ DCHECK(!callback_);
// If the file_stream_ still exists at this point, close it.
if (file_stream_) {
int result = file_stream_->Close(base::Bind(
- &URLFetcherFileWriter::CloseComplete,
- weak_factory_.GetWeakPtr(), callback));
- if (result != ERR_IO_PENDING)
- file_stream_.reset();
+ &URLFetcherFileWriter::CloseComplete, weak_factory_.GetWeakPtr()));
+ if (result == ERR_IO_PENDING) {
+ callback_ = callback;
+ return result;
+ }
+ file_stream_.reset();
return result;
}
return OK;
@@ -131,14 +159,6 @@ void URLFetcherFileWriter::DisownFile() {
owns_file_ = false;
}
-void URLFetcherFileWriter::DidWrite(const CompletionCallback& callback,
- int result) {
- if (result < 0)
- CloseAndDeleteFile();
-
- callback.Run(result);
-}
-
void URLFetcherFileWriter::CloseAndDeleteFile() {
if (!owns_file_)
return;
@@ -151,41 +171,35 @@ void URLFetcherFileWriter::CloseAndDeleteFile() {
false /* recursive */));
}
-void URLFetcherFileWriter::DidCreateTempFile(const CompletionCallback& callback,
- base::FilePath* temp_file_path,
+void URLFetcherFileWriter::DidCreateTempFile(base::FilePath* temp_file_path,
bool success) {
if (!success) {
- callback.Run(ERR_FILE_NOT_FOUND);
+ OnIOCompleted(ERR_FILE_NOT_FOUND);
return;
}
file_path_ = *temp_file_path;
- owns_file_ = true;
const int result = file_stream_->Open(
file_path_,
- base::File::FLAG_WRITE | base::File::FLAG_ASYNC |
- base::File::FLAG_OPEN,
- base::Bind(&URLFetcherFileWriter::DidOpenFile,
- weak_factory_.GetWeakPtr(),
- callback));
+ base::File::FLAG_WRITE | base::File::FLAG_ASYNC | base::File::FLAG_OPEN,
+ base::Bind(&URLFetcherFileWriter::OnIOCompleted,
+ weak_factory_.GetWeakPtr()));
if (result != ERR_IO_PENDING)
- DidOpenFile(callback, result);
+ OnIOCompleted(result);
}
-void URLFetcherFileWriter::DidOpenFile(const CompletionCallback& callback,
- int result) {
- if (result == OK)
- owns_file_ = true;
- else
+void URLFetcherFileWriter::OnIOCompleted(int result) {
+ if (result < OK)
CloseAndDeleteFile();
- callback.Run(result);
+ if (!callback_.is_null())
+ base::ResetAndReturn(&callback_).Run(result);
}
-void URLFetcherFileWriter::CloseComplete(const CompletionCallback& callback,
- int result) {
+void URLFetcherFileWriter::CloseComplete(int result) {
// Destroy |file_stream_| whether or not the close succeeded.
file_stream_.reset();
- callback.Run(result);
+ if (!callback_.is_null())
+ base::ResetAndReturn(&callback_).Run(result);
}
} // namespace net
diff --git a/chromium/net/url_request/url_fetcher_response_writer.h b/chromium/net/url_request/url_fetcher_response_writer.h
index f739502b9c9..7b644b622e1 100644
--- a/chromium/net/url_request/url_fetcher_response_writer.h
+++ b/chromium/net/url_request/url_fetcher_response_writer.h
@@ -45,9 +45,14 @@ class NET_EXPORT URLFetcherResponseWriter {
int num_bytes,
const CompletionCallback& callback) = 0;
- // Finishes writing. If ERR_IO_PENDING is returned, |callback| will be run
- // later with the result.
- virtual int Finish(const CompletionCallback& callback) = 0;
+ // Finishes writing. If |net_error| is not OK, this method can be called
+ // in the middle of another operation (eg. Initialize() and Write()). On
+ // errors (|net_error| not OK), this method may be called before the previous
+ // operation completed. In this case, URLFetcherResponseWriter may skip
+ // graceful shutdown and completion of the pending operation. After such a
+ // failure, the URLFetcherResponseWriter may be reused. If ERR_IO_PENDING is
+ // returned, |callback| will be run later with the result.
+ virtual int Finish(int net_error, const CompletionCallback& callback) = 0;
// Returns this instance's pointer as URLFetcherStringWriter when possible.
virtual URLFetcherStringWriter* AsStringWriter();
@@ -69,7 +74,7 @@ class NET_EXPORT URLFetcherStringWriter : public URLFetcherResponseWriter {
int Write(IOBuffer* buffer,
int num_bytes,
const CompletionCallback& callback) override;
- int Finish(const CompletionCallback& callback) override;
+ int Finish(int net_error, const CompletionCallback& callback) override;
URLFetcherStringWriter* AsStringWriter() override;
private:
@@ -95,7 +100,7 @@ class NET_EXPORT URLFetcherFileWriter : public URLFetcherResponseWriter {
int Write(IOBuffer* buffer,
int num_bytes,
const CompletionCallback& callback) override;
- int Finish(const CompletionCallback& callback) override;
+ int Finish(int net_error, const CompletionCallback& callback) override;
URLFetcherFileWriter* AsFileWriter() override;
// Drops ownership of the file at |file_path_|.
@@ -103,23 +108,18 @@ class NET_EXPORT URLFetcherFileWriter : public URLFetcherResponseWriter {
void DisownFile();
private:
- // Called when a write has been done.
- void DidWrite(const CompletionCallback& callback, int result);
-
// Closes the file if it is open and then delete it.
void CloseAndDeleteFile();
// Callback which gets the result of a temporary file creation.
- void DidCreateTempFile(const CompletionCallback& callback,
- base::FilePath* temp_file_path,
- bool success);
+ void DidCreateTempFile(base::FilePath* temp_file_path, bool success);
- // Callback which gets the result of FileStream::Open.
- void DidOpenFile(const CompletionCallback& callback,
- int result);
+ // Run |callback_| if it is non-null when FileStream::Open or
+ // FileStream::Write is completed.
+ void OnIOCompleted(int result);
// Callback which gets the result of closing a file.
- void CloseComplete(const CompletionCallback& callback, int result);
+ void CloseComplete(int result);
// Task runner on which file operations should happen.
scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
@@ -133,6 +133,8 @@ class NET_EXPORT URLFetcherFileWriter : public URLFetcherResponseWriter {
std::unique_ptr<FileStream> file_stream_;
+ CompletionCallback callback_;
+
// Callbacks are created for use with base::FileUtilProxy.
base::WeakPtrFactory<URLFetcherFileWriter> weak_factory_;
diff --git a/chromium/net/url_request/url_fetcher_response_writer_unittest.cc b/chromium/net/url_request/url_fetcher_response_writer_unittest.cc
index 8d39817c2a1..23369fadb81 100644
--- a/chromium/net/url_request/url_fetcher_response_writer_unittest.cc
+++ b/chromium/net/url_request/url_fetcher_response_writer_unittest.cc
@@ -11,8 +11,12 @@
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/platform_test.h"
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -37,18 +41,18 @@ TEST_F(URLFetcherStringWriterTest, Basic) {
// Initialize(), Write() and Finish().
TestCompletionCallback callback;
rv = writer_->Initialize(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
rv = writer_->Write(buf_.get(), buf_->size(), callback.callback());
EXPECT_EQ(buf_->size(), callback.GetResult(rv));
- rv = writer_->Finish(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ rv = writer_->Finish(OK, callback.callback());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
// Verify the result.
EXPECT_EQ(kData, writer_->data());
// Initialize() again to reset.
rv = writer_->Initialize(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(writer_->data().empty());
}
@@ -56,7 +60,7 @@ class URLFetcherFileWriterTest : public PlatformTest {
protected:
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- file_path_ = temp_dir_.path().AppendASCII("test.txt");
+ file_path_ = temp_dir_.GetPath().AppendASCII("test.txt");
writer_.reset(new URLFetcherFileWriter(base::ThreadTaskRunnerHandle::Get(),
file_path_));
buf_ = new StringIOBuffer(kData);
@@ -73,11 +77,11 @@ TEST_F(URLFetcherFileWriterTest, WriteToFile) {
// Initialize(), Write() and Finish().
TestCompletionCallback callback;
rv = writer_->Initialize(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
rv = writer_->Write(buf_.get(), buf_->size(), callback.callback());
EXPECT_EQ(buf_->size(), callback.GetResult(rv));
- rv = writer_->Finish(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ rv = writer_->Finish(OK, callback.callback());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
// Verify the result.
EXPECT_EQ(file_path_.value(), writer_->file_path().value());
@@ -96,11 +100,11 @@ TEST_F(URLFetcherFileWriterTest, InitializeAgain) {
// Initialize(), Write() and Finish().
TestCompletionCallback callback;
rv = writer_->Initialize(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
rv = writer_->Write(buf_.get(), buf_->size(), callback.callback());
EXPECT_EQ(buf_->size(), callback.GetResult(rv));
- rv = writer_->Finish(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ rv = writer_->Finish(OK, callback.callback());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
// Verify the result.
std::string file_contents;
@@ -112,11 +116,11 @@ TEST_F(URLFetcherFileWriterTest, InitializeAgain) {
scoped_refptr<StringIOBuffer> buf2(new StringIOBuffer(data2));
rv = writer_->Initialize(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
rv = writer_->Write(buf2.get(), buf2->size(), callback.callback());
EXPECT_EQ(buf2->size(), callback.GetResult(rv));
- rv = writer_->Finish(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ rv = writer_->Finish(OK, callback.callback());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
// Verify the result.
file_contents.clear();
@@ -124,14 +128,72 @@ TEST_F(URLFetcherFileWriterTest, InitializeAgain) {
EXPECT_EQ(data2, file_contents);
}
+TEST_F(URLFetcherFileWriterTest, FinishWhileWritePending) {
+ int rv = 0;
+ // Initialize(), Write() and Finish().
+ TestCompletionCallback callback;
+ rv = writer_->Initialize(callback.callback());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
+ TestCompletionCallback callback2;
+ rv = writer_->Write(buf_.get(), buf_->size(), callback2.callback());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ TestCompletionCallback callback3;
+ rv = writer_->Finish(ERR_FAILED, callback3.callback());
+ EXPECT_EQ(OK, rv);
+
+ base::RunLoop().RunUntilIdle();
+ // Verify the result.
+ EXPECT_FALSE(base::PathExists(file_path_));
+}
+
+TEST_F(URLFetcherFileWriterTest, FinishWhileOpenPending) {
+ int rv = 0;
+ // Initialize() and Finish().
+ TestCompletionCallback callback;
+ rv = writer_->Initialize(callback.callback());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ TestCompletionCallback callback2;
+ rv = writer_->Finish(ERR_FAILED, callback2.callback());
+ EXPECT_EQ(OK, rv);
+
+ base::RunLoop().RunUntilIdle();
+ // Verify the result.
+ EXPECT_FALSE(base::PathExists(file_path_));
+}
+
+TEST_F(URLFetcherFileWriterTest, InitializeAgainAfterFinishWithError) {
+ int rv = 0;
+ // Initialize(), Write() and Finish().
+ TestCompletionCallback callback;
+ rv = writer_->Initialize(callback.callback());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(callback.WaitForResult(), IsOk());
+ TestCompletionCallback callback2;
+ rv = writer_->Write(buf_.get(), buf_->size(), callback2.callback());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ TestCompletionCallback callback3;
+ rv = writer_->Finish(ERR_FAILED, callback3.callback());
+ EXPECT_EQ(OK, rv);
+
+ base::RunLoop().RunUntilIdle();
+ // Initialize() again and wait for it to complete.
+ TestCompletionCallback callback4;
+ rv = writer_->Initialize(callback4.callback());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_THAT(callback4.WaitForResult(), IsOk());
+ // Verify the result.
+ EXPECT_TRUE(base::PathExists(file_path_));
+}
+
TEST_F(URLFetcherFileWriterTest, DisownFile) {
int rv = 0;
// Initialize() and Finish() to create a file.
TestCompletionCallback callback;
rv = writer_->Initialize(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
- rv = writer_->Finish(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
+ rv = writer_->Finish(OK, callback.callback());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
// Disown file.
writer_->DisownFile();
@@ -159,11 +221,11 @@ TEST_F(URLFetcherFileWriterTemporaryFileTest, WriteToTemporaryFile) {
// Initialize(), Write() and Finish().
TestCompletionCallback callback;
rv = writer_->Initialize(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
rv = writer_->Write(buf_.get(), buf_->size(), callback.callback());
EXPECT_EQ(buf_->size(), callback.GetResult(rv));
- rv = writer_->Finish(callback.callback());
- EXPECT_EQ(OK, callback.GetResult(rv));
+ rv = writer_->Finish(OK, callback.callback());
+ EXPECT_THAT(callback.GetResult(rv), IsOk());
// Verify the result.
std::string file_contents;
diff --git a/chromium/net/url_request/url_request.cc b/chromium/net/url_request/url_request.cc
index 0c1d5f4c197..0a91e8df200 100644
--- a/chromium/net/url_request/url_request.cc
+++ b/chromium/net/url_request/url_request.cc
@@ -30,6 +30,8 @@
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source_type.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/url_request/redirect_info.h"
#include "net/url_request/url_request_context.h"
@@ -159,8 +161,13 @@ void URLRequest::Delegate::OnSSLCertificateError(URLRequest* request,
request->Cancel();
}
-void URLRequest::Delegate::OnBeforeNetworkStart(URLRequest* request,
- bool* defer) {
+void URLRequest::Delegate::OnResponseStarted(URLRequest* request,
+ int net_error) {
+ OnResponseStarted(request);
+}
+
+void URLRequest::Delegate::OnResponseStarted(URLRequest* request) {
+ NOTREACHED();
}
///////////////////////////////////////////////////////////////////////////////
@@ -186,7 +193,7 @@ URLRequest::~URLRequest() {
// are "cancelled" on destruction.
if (status_.status() == URLRequestStatus::FAILED)
net_error = status_.error();
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_REQUEST_ALIVE, net_error);
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::REQUEST_ALIVE, net_error);
}
void URLRequest::set_upload(std::unique_ptr<UploadDataStream> upload) {
@@ -327,9 +334,8 @@ void URLRequest::LogBlockedBy(const char* blocked_by) {
blocked_by_ = blocked_by;
use_blocked_by_as_load_param_ = false;
- net_log_.BeginEvent(
- NetLog::TYPE_DELEGATE_INFO,
- NetLog::StringCallback("delegate_info", &blocked_by_));
+ net_log_.BeginEvent(NetLogEventType::DELEGATE_INFO,
+ NetLog::StringCallback("delegate_info", &blocked_by_));
}
void URLRequest::LogAndReportBlockedBy(const char* source) {
@@ -341,7 +347,7 @@ void URLRequest::LogUnblocked() {
if (blocked_by_.empty())
return;
- net_log_.EndEvent(NetLog::TYPE_DELEGATE_INFO);
+ net_log_.EndEvent(NetLogEventType::DELEGATE_INFO);
blocked_by_.clear();
}
@@ -350,13 +356,18 @@ UploadProgress URLRequest::GetUploadProgress() const {
// We haven't started or the request was cancelled
return UploadProgress();
}
+
if (final_upload_progress_.position()) {
// The first job completed and none of the subsequent series of
// GETs when following redirects will upload anything, so we return the
// cached results from the initial job, the POST.
return final_upload_progress_;
}
- return job_->GetUploadProgress();
+
+ if (upload_data_stream_)
+ return upload_data_stream_->GetUploadProgress();
+
+ return UploadProgress();
}
void URLRequest::GetResponseHeaderByName(const string& name,
@@ -500,6 +511,9 @@ void URLRequest::set_delegate(Delegate* delegate) {
void URLRequest::Start() {
DCHECK(delegate_);
+ if (!status_.is_success())
+ return;
+
// TODO(pkasting): Remove ScopedTracker below once crbug.com/456327 is fixed.
tracked_objects::ScopedTracker tracking_profile(
FROM_HERE_WITH_EXPLICIT_FUNCTION("456327 URLRequest::Start"));
@@ -551,14 +565,15 @@ URLRequest::URLRequest(const GURL& url,
: context_(context),
network_delegate_(network_delegate ? network_delegate
: context->network_delegate()),
- net_log_(
- BoundNetLog::Make(context->net_log(), NetLog::SOURCE_URL_REQUEST)),
+ net_log_(NetLogWithSource::Make(context->net_log(),
+ NetLogSourceType::URL_REQUEST)),
url_chain_(1, url),
method_("GET"),
referrer_policy_(CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE),
first_party_url_policy_(NEVER_CHANGE_FIRST_PARTY_URL),
load_flags_(LOAD_NORMAL),
delegate_(delegate),
+ status_(URLRequestStatus::FromError(OK)),
is_pending_(false),
is_redirecting_(false),
redirect_limit_(kMaxRedirects),
@@ -570,14 +585,13 @@ URLRequest::URLRequest(const GURL& url,
base::Unretained(this))),
has_notified_completion_(false),
received_response_content_length_(0),
- creation_time_(base::TimeTicks::Now()),
- notified_before_network_start_(false) {
+ creation_time_(base::TimeTicks::Now()) {
// Sanity check out environment.
DCHECK(base::MessageLoop::current())
<< "The current base::MessageLoop must exist";
context->url_requests()->insert(this);
- net_log_.BeginEvent(NetLog::TYPE_REQUEST_ALIVE);
+ net_log_.BeginEvent(NetLogEventType::REQUEST_ALIVE);
}
void URLRequest::BeforeRequestComplete(int error) {
@@ -591,7 +605,7 @@ void URLRequest::BeforeRequestComplete(int error) {
if (error != OK) {
std::string source("delegate");
- net_log_.AddEvent(NetLog::TYPE_CANCELLED,
+ net_log_.AddEvent(NetLogEventType::CANCELLED,
NetLog::StringCallback("source", &source));
StartJob(new URLRequestErrorJob(this, network_delegate_, error));
} else if (!delegate_redirect_url_.is_empty()) {
@@ -618,9 +632,9 @@ void URLRequest::StartJob(URLRequestJob* job) {
DCHECK(!job_.get());
net_log_.BeginEvent(
- NetLog::TYPE_URL_REQUEST_START_JOB,
- base::Bind(&NetLogURLRequestStartCallback,
- &url(), &method_, load_flags_, priority_,
+ NetLogEventType::URL_REQUEST_START_JOB,
+ base::Bind(&NetLogURLRequestStartCallback, &url(), &method_, load_flags_,
+ priority_,
upload_data_stream_ ? upload_data_stream_->identifier() : -1));
job_.reset(job);
@@ -646,7 +660,7 @@ void URLRequest::StartJob(URLRequestJob* job) {
// when starting the error job.
referrer_.clear();
std::string source("delegate");
- net_log_.AddEvent(NetLog::TYPE_CANCELLED,
+ net_log_.AddEvent(NetLogEventType::CANCELLED,
NetLog::StringCallback("source", &source));
RestartWithJob(new URLRequestErrorJob(
this, network_delegate_, ERR_BLOCKED_BY_CLIENT));
@@ -677,12 +691,12 @@ void URLRequest::RestartWithJob(URLRequestJob *job) {
StartJob(job);
}
-void URLRequest::Cancel() {
- DoCancel(ERR_ABORTED, SSLInfo());
+int URLRequest::Cancel() {
+ return DoCancel(ERR_ABORTED, SSLInfo());
}
-void URLRequest::CancelWithError(int error) {
- DoCancel(error, SSLInfo());
+int URLRequest::CancelWithError(int error) {
+ return DoCancel(error, SSLInfo());
}
void URLRequest::CancelWithSSLError(int error, const SSLInfo& ssl_info) {
@@ -694,7 +708,7 @@ void URLRequest::CancelWithSSLError(int error, const SSLInfo& ssl_info) {
DoCancel(error, ssl_info);
}
-void URLRequest::DoCancel(int error, const SSLInfo& ssl_info) {
+int URLRequest::DoCancel(int error, const SSLInfo& ssl_info) {
DCHECK(error < 0);
// If cancelled while calling a delegate, clear delegate info.
if (calling_delegate_) {
@@ -711,7 +725,7 @@ void URLRequest::DoCancel(int error, const SSLInfo& ssl_info) {
// If the request hasn't already been completed, log a cancellation event.
if (!has_notified_completion_) {
// Don't log an error code on ERR_ABORTED, since that's redundant.
- net_log_.AddEventWithNetErrorCode(NetLog::TYPE_CANCELLED,
+ net_log_.AddEventWithNetErrorCode(NetLogEventType::CANCELLED,
error == ERR_ABORTED ? OK : error);
}
}
@@ -727,43 +741,61 @@ void URLRequest::DoCancel(int error, const SSLInfo& ssl_info) {
// The Job will call our NotifyDone method asynchronously. This is done so
// that the Delegate implementation can call Cancel without having to worry
// about being called recursively.
+
+ return status_.error();
}
-bool URLRequest::Read(IOBuffer* dest, int dest_size, int* bytes_read) {
+int URLRequest::Read(IOBuffer* dest, int dest_size) {
DCHECK(job_.get());
- DCHECK(bytes_read);
- *bytes_read = 0;
// If this is the first read, end the delegate call that may have started in
// OnResponseStarted.
OnCallToDelegateComplete();
- // This handles a cancel that happens while paused.
+ // If the request has failed, Read() will return actual network error code.
+ if (!status_.is_success())
+ return status_.error();
+
+ // This handles reads after the request already completed successfully.
// TODO(ahendrickson): DCHECK() that it is not done after
// http://crbug.com/115705 is fixed.
if (job_->is_done())
- return false;
+ return status_.error();
if (dest_size == 0) {
// Caller is not too bright. I guess we've done what they asked.
- return true;
+ return OK;
}
- // Once the request fails or is cancelled, read will just return 0 bytes
- // to indicate end of stream.
- if (!status_.is_success()) {
- return true;
- }
+ int rv = job_->Read(dest, dest_size);
+ if (rv == ERR_IO_PENDING)
+ set_status(URLRequestStatus::FromError(ERR_IO_PENDING));
- bool rv = job_->Read(dest, dest_size, bytes_read);
- // If rv is false, the status cannot be success.
- DCHECK(rv || status_.status() != URLRequestStatus::SUCCESS);
+ // If rv is not 0 or actual bytes read, the status cannot be success.
+ DCHECK(rv >= 0 || status_.status() != URLRequestStatus::SUCCESS);
- if (rv && *bytes_read <= 0 && status_.is_success())
+ if (rv == 0 && status_.is_success())
NotifyRequestCompleted();
return rv;
}
+// Deprecated.
+bool URLRequest::Read(IOBuffer* dest, int dest_size, int* bytes_read) {
+ int result = Read(dest, dest_size);
+ if (result >= 0) {
+ *bytes_read = result;
+ return true;
+ }
+
+ if (result == ERR_IO_PENDING) {
+ *bytes_read = 0;
+ } else {
+ *bytes_read = -1;
+ }
+
+ return false;
+}
+
void URLRequest::StopCaching() {
DCHECK(job_.get());
job_->StopCaching();
@@ -786,29 +818,15 @@ void URLRequest::NotifyReceivedRedirect(const RedirectInfo& redirect_info,
}
}
-void URLRequest::NotifyBeforeNetworkStart(bool* defer) {
- if (!notified_before_network_start_) {
- OnCallToDelegate();
- delegate_->OnBeforeNetworkStart(this, defer);
- if (!*defer)
- OnCallToDelegateComplete();
- notified_before_network_start_ = true;
- }
-}
+void URLRequest::NotifyResponseStarted(const URLRequestStatus& status) {
+ // Change status if there was an error.
+ if (status.status() != URLRequestStatus::SUCCESS)
+ set_status(status);
-void URLRequest::ResumeNetworkStart() {
- DCHECK(job_.get());
- DCHECK(notified_before_network_start_);
-
- OnCallToDelegateComplete();
- job_->ResumeNetworkStart();
-}
-
-void URLRequest::NotifyResponseStarted() {
int net_error = OK;
if (!status_.is_success())
net_error = status_.error();
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_URL_REQUEST_START_JOB,
+ net_log_.EndEventWithNetErrorCode(NetLogEventType::URL_REQUEST_START_JOB,
net_error);
URLRequestJob* job =
@@ -821,7 +839,7 @@ void URLRequest::NotifyResponseStarted() {
// completion event and receive a NotifyResponseStarted() later.
if (!has_notified_completion_ && status_.is_success()) {
if (network_delegate_)
- network_delegate_->NotifyResponseStarted(this);
+ network_delegate_->NotifyResponseStarted(this, net_error);
}
// Notify in case the entire URL Request has been finished.
@@ -829,7 +847,7 @@ void URLRequest::NotifyResponseStarted() {
NotifyRequestCompleted();
OnCallToDelegate();
- delegate_->OnResponseStarted(this);
+ delegate_->OnResponseStarted(this, net_error);
// Nothing may appear below this line as OnResponseStarted may delete
// |this|.
}
@@ -885,7 +903,7 @@ void URLRequest::PrepareToRestart() {
// Close the current URL_REQUEST_START_JOB, since we will be starting a new
// one.
- net_log_.EndEvent(NetLog::TYPE_URL_REQUEST_START_JOB);
+ net_log_.EndEvent(NetLogEventType::URL_REQUEST_START_JOB);
OrphanJob();
@@ -898,7 +916,7 @@ void URLRequest::PrepareToRestart() {
status_ = URLRequestStatus();
is_pending_ = false;
- proxy_server_ = HostPortPair();
+ proxy_server_ = ProxyServer();
}
void URLRequest::OrphanJob() {
@@ -919,7 +937,7 @@ int URLRequest::Redirect(const RedirectInfo& redirect_info) {
OnCallToDelegateComplete();
if (net_log_.IsCapturing()) {
net_log_.AddEvent(
- NetLog::TYPE_URL_REQUEST_REDIRECTED,
+ NetLogEventType::URL_REQUEST_REDIRECTED,
NetLog::StringCallback("location",
&redirect_info.new_url.possibly_invalid_spec()));
}
@@ -941,8 +959,8 @@ int URLRequest::Redirect(const RedirectInfo& redirect_info) {
return ERR_UNSAFE_REDIRECT;
}
- if (!final_upload_progress_.position())
- final_upload_progress_ = job_->GetUploadProgress();
+ if (!final_upload_progress_.position() && upload_data_stream_)
+ final_upload_progress_ = upload_data_stream_->GetUploadProgress();
PrepareToRestart();
if (redirect_info.new_method != method_) {
@@ -1027,7 +1045,7 @@ void URLRequest::SetPriority(RequestPriority priority) {
priority_ = priority;
if (job_.get()) {
net_log_.AddEvent(
- NetLog::TYPE_URL_REQUEST_SET_PRIORITY,
+ NetLogEventType::URL_REQUEST_SET_PRIORITY,
NetLog::StringCallback("priority", RequestPriorityToString(priority_)));
job_->SetPriority(priority_);
}
@@ -1129,10 +1147,20 @@ bool URLRequest::CanEnablePrivacyMode() const {
void URLRequest::NotifyReadCompleted(int bytes_read) {
+ if (bytes_read > 0)
+ set_status(URLRequestStatus());
// Notify in case the entire URL Request has been finished.
if (bytes_read <= 0)
NotifyRequestCompleted();
+ // When URLRequestJob notices there was an error in URLRequest's |status_|,
+ // it calls this method with |bytes_read| set to -1. Set it to a real error
+ // here.
+ // TODO(maksims): NotifyReadCompleted take the error code as an argument on
+ // failure, rather than -1.
+ if (bytes_read == -1)
+ bytes_read = status_.error();
+
// Notify NetworkChangeNotifier that we just received network data.
// This is to identify cases where the NetworkChangeNotifier thinks we
// are off-line but we are still receiving network data (crbug.com/124069),
@@ -1146,6 +1174,7 @@ void URLRequest::NotifyReadCompleted(int bytes_read) {
}
void URLRequest::OnHeadersComplete() {
+ set_status(URLRequestStatus());
// Cache load timing information now, as information will be lost once the
// socket is closed and the ClientSocketHandle is Reset, which will happen
// once the body is complete. The start times should already be populated.
@@ -1161,6 +1190,7 @@ void URLRequest::OnHeadersComplete() {
load_timing_info_.request_start = request_start;
load_timing_info_.request_start_time = request_start_time;
+ raw_header_size_ = GetTotalReceivedBytes();
ConvertRealLoadTimesToBlockingTimes(&load_timing_info_);
}
@@ -1176,14 +1206,15 @@ void URLRequest::NotifyRequestCompleted() {
is_redirecting_ = false;
has_notified_completion_ = true;
if (network_delegate_)
- network_delegate_->NotifyCompleted(this, job_.get() != NULL);
+ network_delegate_->NotifyCompleted(this, job_.get() != NULL,
+ status_.error());
}
void URLRequest::OnCallToDelegate() {
DCHECK(!calling_delegate_);
DCHECK(blocked_by_.empty());
calling_delegate_ = true;
- net_log_.BeginEvent(NetLog::TYPE_URL_REQUEST_DELEGATE);
+ net_log_.BeginEvent(NetLogEventType::URL_REQUEST_DELEGATE);
}
void URLRequest::OnCallToDelegateComplete() {
@@ -1192,7 +1223,7 @@ void URLRequest::OnCallToDelegateComplete() {
if (!calling_delegate_)
return;
calling_delegate_ = false;
- net_log_.EndEvent(NetLog::TYPE_URL_REQUEST_DELEGATE);
+ net_log_.EndEvent(NetLogEventType::URL_REQUEST_DELEGATE);
}
void URLRequest::GetConnectionAttempts(ConnectionAttempts* out) const {
@@ -1202,4 +1233,10 @@ void URLRequest::GetConnectionAttempts(ConnectionAttempts* out) const {
out->clear();
}
+void URLRequest::set_status(URLRequestStatus status) {
+ DCHECK(status_.is_io_pending() || status_.is_success() ||
+ (!status.is_success() && !status.is_io_pending()));
+ status_ = status;
+}
+
} // namespace net
diff --git a/chromium/net/url_request/url_request.h b/chromium/net/url_request/url_request.h
index 85eb2e4ead2..993afc97876 100644
--- a/chromium/net/url_request/url_request.h
+++ b/chromium/net/url_request/url_request.h
@@ -30,7 +30,8 @@
#include "net/cookies/canonical_cookie.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_info.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
+#include "net/proxy/proxy_server.h"
#include "net/socket/connection_attempts.h"
#include "net/url_request/url_request_status.h"
#include "url/gurl.h"
@@ -195,27 +196,23 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe),
const SSLInfo& ssl_info,
bool fatal);
- // Called to notify that the request must use the network to complete the
- // request and is about to do so. This is called at most once per
- // URLRequest, and by default does not defer. If deferred, call
- // ResumeNetworkStart() to continue or Cancel() to cancel.
- virtual void OnBeforeNetworkStart(URLRequest* request, bool* defer);
-
// After calling Start(), the delegate will receive an OnResponseStarted
- // callback when the request has completed. If an error occurred, the
- // request->status() will be set. On success, all redirects have been
+ // callback when the request has completed. |net_error| will be set to OK
+ // or an actual net error. On success, all redirects have been
// followed and the final response is beginning to arrive. At this point,
// meta data about the response is available, including for example HTTP
// response headers if this is a request for a HTTP resource.
- virtual void OnResponseStarted(URLRequest* request) = 0;
+ virtual void OnResponseStarted(URLRequest* request, int net_error);
+ // Deprecated.
+ // TODO(maksims): Remove this;
+ virtual void OnResponseStarted(URLRequest* request);
// Called when the a Read of the response body is completed after an
// IO_PENDING status from a Read() call.
// The data read is filled into the buffer which the caller passed
// to Read() previously.
//
- // If an error occurred, request->status() will contain the error,
- // and bytes read will be -1.
+ // If an error occurred, |bytes_read| will be set to the error.
virtual void OnReadCompleted(URLRequest* request, int bytes_read) = 0;
protected:
@@ -530,9 +527,6 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe),
// URL but has not yet initiated the new request.
bool is_redirecting() const { return is_redirecting_; }
- // Returns the error status of the request.
- const URLRequestStatus& status() const { return status_; }
-
// Returns a globally unique identifier for this request.
uint64_t identifier() const { return identifier_; }
@@ -546,12 +540,14 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe),
// no effect once the response has completed. It is guaranteed that no
// methods of the delegate will be called after the request has been
// cancelled, except that this may call the delegate's OnReadCompleted()
- // during the call to Cancel itself.
- void Cancel();
+ // during the call to Cancel itself. Returns |ERR_ABORTED| or other net error
+ // if there was one.
+ int Cancel();
- // Cancels the request and sets the error to |error| (see net_error_list.h
- // for values).
- void CancelWithError(int error);
+ // Cancels the request and sets the error to |error|, unless the request
+ // already failed with another error code (see net_error_list.h). Returns
+ // final network error code.
+ int CancelWithError(int error);
// Cancels the request and sets the error to |error| (see net_error_list.h
// for values) and attaches |ssl_info| as the SSLInfo for that request. This
@@ -559,28 +555,23 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe),
// request.
void CancelWithSSLError(int error, const SSLInfo& ssl_info);
- // Read initiates an asynchronous read from the response, and must only
- // be called after the OnResponseStarted callback is received with a
- // successful status.
- // If data is available, Read will return true, and the data and length will
- // be returned immediately. If data is not available, Read returns false,
- // and an asynchronous Read is initiated. The Read is finished when
- // the caller receives the OnReadComplete callback. Unless the request was
- // cancelled, OnReadComplete will always be called, even if the read failed.
+ // Read initiates an asynchronous read from the response, and must only be
+ // called after the OnResponseStarted callback is received with a net::OK. If
+ // data is available, length and the data will be returned immediately. If the
+ // request has failed, an error code will be returned. If data is not yet
+ // available, Read returns net::ERR_IO_PENDING, and the Delegate's
+ // OnReadComplete method will be called asynchronously with the result of the
+ // read, unless the URLRequest is canceled.
//
- // The buf parameter is a buffer to receive the data. If the operation
+ // The |buf| parameter is a buffer to receive the data. If the operation
// completes asynchronously, the implementation will reference the buffer
- // until OnReadComplete is called. The buffer must be at least max_bytes in
+ // until OnReadComplete is called. The buffer must be at least |max_bytes| in
// length.
//
- // The max_bytes parameter is the maximum number of bytes to read.
- //
- // The bytes_read parameter is an output parameter containing the
- // the number of bytes read. A value of 0 indicates that there is no
- // more data available to read from the stream.
- //
- // If a read error occurs, Read returns false and the request->status
- // will be set to an error.
+ // The |max_bytes| parameter is the maximum number of bytes to read.
+ int Read(IOBuffer* buf, int max_bytes);
+ // Deprecated.
+ // TODO(maksims): Remove this.
bool Read(IOBuffer* buf, int max_bytes, int* bytes_read);
// If this request is being cached by the HTTP cache, stop subsequent caching.
@@ -594,10 +585,6 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe),
// response to an OnReceivedRedirect call.
void FollowDeferredRedirect();
- // This method must be called to resume network communications that were
- // deferred in response to an OnBeforeNetworkStart call.
- void ResumeNetworkStart();
-
// One of the following two methods should be called in response to an
// OnAuthRequired() callback (and only then).
// SetAuth will reissue the request with the given credentials.
@@ -619,7 +606,7 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe),
// Used to specify the context (cookie store, cache) for this request.
const URLRequestContext* context() const;
- const BoundNetLog& net_log() const { return net_log_; }
+ const NetLogWithSource& net_log() const { return net_log_; }
// Returns the expected content size if available
int64_t GetExpectedContentSize() const;
@@ -645,21 +632,26 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe),
// Available at NetworkDelegate::NotifyHeadersReceived() time, which is before
// the more general response_info() is available, even though it is a subset.
- const HostPortPair& proxy_server() const {
- return proxy_server_;
- }
+ const ProxyServer& proxy_server() const { return proxy_server_; }
// Gets the connection attempts made in the process of servicing this
// URLRequest. Only guaranteed to be valid if called after the request fails
// or after the response headers are received.
void GetConnectionAttempts(ConnectionAttempts* out) const;
+ // Gets the over the wire raw header size of the response after https
+ // encryption, 0 for cached responses.
+ int raw_header_size() const { return raw_header_size_; }
+
+ // Returns the error status of the request.
+ // Do not use! Going to be protected!
+ const URLRequestStatus& status() const { return status_; }
protected:
// Allow the URLRequestJob class to control the is_pending() flag.
void set_is_pending(bool value) { is_pending_ = value; }
- // Allow the URLRequestJob class to set our status too
- void set_status(const URLRequestStatus& value) { status_ = value; }
+ // Allow the URLRequestJob class to set our status too.
+ void set_status(URLRequestStatus status);
// Allow the URLRequestJob to redirect this request. Returns OK if
// successful, otherwise an error code is returned.
@@ -669,10 +661,6 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe),
void NotifyReceivedRedirect(const RedirectInfo& redirect_info,
bool* defer_redirect);
- // Called by URLRequestHttpJob (note, only HTTP(S) jobs will call this) to
- // allow deferral of network initialization.
- void NotifyBeforeNetworkStart(bool* defer);
-
// Allow an interceptor's URLRequestJob to restart this request.
// Should only be called if the original job has not started a response.
void Restart();
@@ -681,6 +669,10 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe),
friend class URLRequestJob;
friend class URLRequestContext;
+ // For testing purposes.
+ // TODO(maksims): Remove this.
+ friend class TestNetworkDelegate;
+
// URLRequests are always created by calling URLRequestContext::CreateRequest.
//
// If no network delegate is passed in, will use the ones from the
@@ -712,8 +704,8 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe),
void OrphanJob();
// Cancels the request and set the error and ssl info for this request to the
- // passed values.
- void DoCancel(int error, const SSLInfo& ssl_info);
+ // passed values. Returns the error that was set.
+ int DoCancel(int error, const SSLInfo& ssl_info);
// Called by the URLRequestJob when the headers are received, before any other
// method, to allow caching of load timing information.
@@ -726,7 +718,7 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe),
// Called by URLRequestJob to allow interception when the final response
// occurs.
- void NotifyResponseStarted();
+ void NotifyResponseStarted(const URLRequestStatus& status);
// These functions delegate to |delegate_|. See URLRequest::Delegate for the
// meaning of these functions.
@@ -758,7 +750,7 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe),
NetworkDelegate* network_delegate_;
// Tracks the time spent in various load states throughout this request.
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
std::unique_ptr<URLRequestJob> job_;
std::unique_ptr<UploadDataStream> upload_data_stream_;
@@ -855,11 +847,11 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe),
// populated during Start(), and the rest are populated in OnResponseReceived.
LoadTimingInfo load_timing_info_;
- // Keeps track of whether or not OnBeforeNetworkStart has been called yet.
- bool notified_before_network_start_;
-
// The proxy server used for this request, if any.
- HostPortPair proxy_server_;
+ ProxyServer proxy_server_;
+
+ // The raw header size of the response.
+ int raw_header_size_;
DISALLOW_COPY_AND_ASSIGN(URLRequest);
};
diff --git a/chromium/net/url_request/url_request_backoff_manager.cc b/chromium/net/url_request/url_request_backoff_manager.cc
deleted file mode 100644
index 1212c47b77a..00000000000
--- a/chromium/net/url_request/url_request_backoff_manager.cc
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 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.
-
-#include "net/url_request/url_request_backoff_manager.h"
-
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
-#include "net/http/http_response_headers.h"
-
-namespace net {
-
-const uint16_t URLRequestBackoffManager::kMinimumBackoffInSeconds = 1;
-const uint16_t URLRequestBackoffManager::kMaximumBackoffInSeconds = 50000;
-const uint16_t URLRequestBackoffManager::kNewEntriesBetweenCollecting = 200;
-
-URLRequestBackoffManager::URLRequestBackoffManager()
- : new_entries_since_last_gc_(0) {
- url_id_replacements_.ClearPassword();
- url_id_replacements_.ClearUsername();
- url_id_replacements_.ClearQuery();
- url_id_replacements_.ClearRef();
-
- NetworkChangeNotifier::AddIPAddressObserver(this);
- NetworkChangeNotifier::AddConnectionTypeObserver(this);
-}
-
-URLRequestBackoffManager::~URLRequestBackoffManager() {
- NetworkChangeNotifier::RemoveIPAddressObserver(this);
- NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
- for (UrlEntryMap::iterator it = url_entries_.begin();
- it != url_entries_.end(); ++it) {
- delete it->second;
- }
- url_entries_.clear();
-}
-
-void URLRequestBackoffManager::UpdateWithResponse(
- const GURL& url,
- HttpResponseHeaders* headers,
- const base::Time& response_time) {
- CalledOnValidThread();
- base::TimeDelta result;
- if (GetBackoffTime(headers, &result)) {
- new_entries_since_last_gc_++;
- std::string url_id = GetIdFromUrl(url);
- auto it = url_entries_.find(url_id);
- if (it != url_entries_.end())
- delete it->second;
- url_entries_[url_id] =
- new Entry(response_time + result, response_time + result * 1.1);
- GarbageCollectEntriesIfNecessary();
- }
-}
-
-bool URLRequestBackoffManager::ShouldRejectRequest(
- const GURL& url,
- const base::Time& request_time) {
- CalledOnValidThread();
- std::string url_id = GetIdFromUrl(url);
- UrlEntryMap::iterator it = url_entries_.find(url_id);
- if (it == url_entries_.end())
- return false;
- Entry* entry = it->second;
- if (request_time < entry->throttled_time)
- return true;
- // Allow one request between throttled_time and release_time.
- if (request_time >= entry->throttled_time &&
- request_time < entry->release_time) {
- if (entry->used)
- return true;
- entry->used = true;
- }
- return false;
-}
-
-void URLRequestBackoffManager::OnIPAddressChanged() {
- OnNetworkChange();
-}
-
-void URLRequestBackoffManager::OnConnectionTypeChanged(
- NetworkChangeNotifier::ConnectionType type) {
- OnNetworkChange();
-}
-
-int URLRequestBackoffManager::GetNumberOfEntriesForTests() const {
- return url_entries_.size();
-}
-
-void URLRequestBackoffManager::GarbageCollectEntriesIfNecessary() {
- CalledOnValidThread();
- if (new_entries_since_last_gc_ < kNewEntriesBetweenCollecting)
- return;
-
- new_entries_since_last_gc_ = 0;
- UrlEntryMap::iterator it = url_entries_.begin();
- while (it != url_entries_.end()) {
- Entry* entry = it->second;
- if (entry->IsOutDated()) {
- url_entries_.erase(it++);
- delete entry;
- } else {
- ++it;
- }
- }
-}
-
-bool URLRequestBackoffManager::GetBackoffTime(HttpResponseHeaders* headers,
- base::TimeDelta* result) const {
- base::StringPiece name("Backoff");
- std::string value;
- size_t iter = 0;
- while (headers->EnumerateHeader(&iter, name, &value)) {
- int64_t seconds;
- base::StringToInt64(value, &seconds);
- if (seconds >= kMinimumBackoffInSeconds &&
- seconds <= kMaximumBackoffInSeconds) {
- *result = base::TimeDelta::FromSeconds(seconds);
- return true;
- }
- }
- return false;
-}
-
-std::string URLRequestBackoffManager::GetIdFromUrl(const GURL& url) const {
- if (!url.is_valid())
- return url.possibly_invalid_spec();
-
- GURL id = url.ReplaceComponents(url_id_replacements_);
- return base::ToLowerASCII(id.spec());
-}
-
-void URLRequestBackoffManager::OnNetworkChange() {
- CalledOnValidThread();
-
- new_entries_since_last_gc_ = 0;
- // Remove all entries.
- for (UrlEntryMap::iterator it = url_entries_.begin();
- it != url_entries_.end(); ++it) {
- delete it->second;
- }
- url_entries_.clear();
-}
-
-} // namespace net
diff --git a/chromium/net/url_request/url_request_backoff_manager.h b/chromium/net/url_request/url_request_backoff_manager.h
deleted file mode 100644
index 2aceb742c98..00000000000
--- a/chromium/net/url_request/url_request_backoff_manager.h
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 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.
-
-#ifndef NET_URL_REQUEST_URL_REQUEST_BACKOFF_MANAGER_H_
-#define NET_URL_REQUEST_URL_REQUEST_BACKOFF_MANAGER_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <string>
-
-#include "base/macros.h"
-#include "base/threading/non_thread_safe.h"
-#include "base/time/time.h"
-#include "net/base/net_export.h"
-#include "net/base/network_change_notifier.h"
-#include "url/gurl.h"
-
-namespace net {
-
-class HttpResponseHeaders;
-
-// Class that manages information on Backoff headers. URL requests for HTTPS
-// contents should update their URLs in this manager on each response.
-//
-// Design doc:
-// https://docs.google.com/document/d/1aAxwXK7Vw3VigFd6MmrItbAIgMdKAf-XxXXbhWXdID0/edit?usp=sharing
-//
-// URLRequestBackoffManager maintains a map of URL IDs to
-// URLRequestBackoffManager::Entry. It creates an entry when a request receives
-// a Backoff header, and does garbage collection from time to time in order to
-// clean out outdated entries. URL ID consists of lowercased scheme, host, port
-// and path. A newer request with the same ID will override the old entry.
-//
-// Note that the class does not implement logic to retry a request at random
-// with uniform distribution.
-// TODO(xunjieli): Expose release time so that the caller can retry accordingly.
-class NET_EXPORT URLRequestBackoffManager
- : NON_EXPORTED_BASE(public base::NonThreadSafe),
- public NetworkChangeNotifier::IPAddressObserver,
- public NetworkChangeNotifier::ConnectionTypeObserver {
- public:
- // Minimum number of seconds that a Backoff header can specify.
- static const uint16_t kMinimumBackoffInSeconds;
- // Maximum number of seconds that a Backoff header can specify.
- static const uint16_t kMaximumBackoffInSeconds;
- // Number of throttled requests that will be made between garbage collection.
- static const uint16_t kNewEntriesBetweenCollecting;
-
- URLRequestBackoffManager();
- ~URLRequestBackoffManager() override;
-
- // Updates internal states with a response.
- void UpdateWithResponse(const GURL& url,
- HttpResponseHeaders* headers,
- const base::Time& response_time);
-
- // Returns whether the request should be rejected because of a Backoff header.
- bool ShouldRejectRequest(const GURL& url, const base::Time& request_time);
-
- // IPAddressObserver implementation.
- void OnIPAddressChanged() override;
-
- // ConnectionTypeObserver implementation.
- void OnConnectionTypeChanged(
- NetworkChangeNotifier::ConnectionType type) override;
-
- // Used by tests.
- int GetNumberOfEntriesForTests() const;
-
- private:
- // An struct that holds relevant information obtained from a Backoff header.
- struct Entry {
- Entry(const base::Time& time1, const base::Time& time2)
- : throttled_time(time1), release_time(time2), used(false) {}
- ~Entry() {}
-
- // Returns whether this entry is outdated.
- bool IsOutDated() { return base::Time::Now() >= release_time; }
-
- // Before this time, requests with the same URL ID should be throttled.
- const base::Time throttled_time;
-
- // Only one request with the same URL ID should be allowed in
- // [|throttled_time|, |release_time|).
- // After this time, all requests with the same URL ID are allowed.
- const base::Time release_time;
-
- // Indicates whether a request has been made in
- // [|throttled_time|, |release_time|).
- bool used;
- };
-
- // From each URL, generate an ID composed of the scheme, host, port and path
- // that allows unique mapping an entry to it.
- typedef std::map<std::string, Entry*> UrlEntryMap;
-
- // Method that ensures the map gets cleaned from time to time. The period at
- // which garbage collecting happens is adjustable with the
- // kNewEntriesBetweenCollecting constant.
- void GarbageCollectEntriesIfNecessary();
-
- // Return true if there is a well-formed Backoff header key-value pair,
- // and write the Backoff header value in |result|. Return false if no header
- // is found or the value is invalid (i.e. less than kMinimumBackoffInSeconds
- // or greater than kMaximumBackoffInSeconds).
- bool GetBackoffTime(HttpResponseHeaders* headers,
- base::TimeDelta* result) const;
-
- // Method that transforms a URL into an ID that can be used in the map.
- // Resulting IDs will be lowercase and consist of the scheme, host, port
- // and path (without query string, fragment, etc.).
- // If the URL is invalid, the invalid spec will be returned, without any
- // transformation.
- std::string GetIdFromUrl(const GURL& url) const;
-
- // When switching from online to offline or change IP addresses,
- // clear all back-off history. This is a precaution in case the change in
- // online state now allows communicating without errors with servers that
- // were previously returning Backoff headers.
- void OnNetworkChange();
-
- UrlEntryMap url_entries_;
-
- // Keeps track of how many new entries are created since last garbage
- // collection.
- unsigned int new_entries_since_last_gc_;
-
- // Valid after construction.
- GURL::Replacements url_id_replacements_;
-
- DISALLOW_COPY_AND_ASSIGN(URLRequestBackoffManager);
-};
-
-} // namespace net
-
-#endif // NET_URL_REQUEST_URL_REQUEST_BACKOFF_MANAGER_H_
diff --git a/chromium/net/url_request/url_request_backoff_manager_unittest.cc b/chromium/net/url_request/url_request_backoff_manager_unittest.cc
deleted file mode 100644
index a41a537803d..00000000000
--- a/chromium/net/url_request/url_request_backoff_manager_unittest.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 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.
-
-#include "net/url_request/url_request_backoff_manager.h"
-
-#include <memory>
-
-#include "base/strings/stringprintf.h"
-#include "base/time/time.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-namespace {
-
-class URLRequestBackoffManagerTest : public testing::Test {
- protected:
- URLRequestBackoffManagerTest() : manager_(new URLRequestBackoffManager) {}
- void RegisterURL(const GURL& url,
- int backoff_in_sec,
- const base::Time& request_time) {
- std::string raw_headers = base::StringPrintf(
- "HTTP/1.0 200 OK\n"
- "backoff: %d\n\n",
- backoff_in_sec);
- scoped_refptr<HttpResponseHeaders> headers(new HttpResponseHeaders(
- HttpUtil::AssembleRawHeaders(raw_headers.c_str(), raw_headers.size())));
- manager_->UpdateWithResponse(url, headers.get(), request_time);
- }
-
- std::unique_ptr<URLRequestBackoffManager> manager_;
-};
-} // namespace
-
-TEST_F(URLRequestBackoffManagerTest, ShouldRejectRequest) {
- base::Time request_time = base::Time::Now();
- RegisterURL(GURL("https://example.com"), 3600, request_time);
- ASSERT_EQ(1, manager_->GetNumberOfEntriesForTests());
- ASSERT_TRUE(manager_->ShouldRejectRequest(
- GURL("https://example.com?q=v"),
- request_time + base::TimeDelta::FromSeconds(3500)));
-
- // Only can try once in the interval of
- // [|request_time| + 3600, |request_time| + 3600 * 1.1).
- ASSERT_FALSE(manager_->ShouldRejectRequest(
- GURL("https://example.com?q=v"),
- request_time + base::TimeDelta::FromSeconds(3700)));
- ASSERT_TRUE(manager_->ShouldRejectRequest(
- GURL("https://example.com?q=v"),
- request_time + base::TimeDelta::FromSeconds(3700)));
- ASSERT_EQ(1, manager_->GetNumberOfEntriesForTests());
-
- // After release time, throttling should not be applied.
- ASSERT_FALSE(manager_->ShouldRejectRequest(
- GURL("https://example.com?q=v"),
- request_time + base::TimeDelta::FromSeconds(3960)));
-}
-
-TEST_F(URLRequestBackoffManagerTest, MisconfiguredHeaders) {
- // Backoff time is smaller than the minimum allowed.
- RegisterURL(GURL("https://example.com"),
- URLRequestBackoffManager::kMinimumBackoffInSeconds - 1,
- base::Time::Now());
- ASSERT_EQ(0, manager_->GetNumberOfEntriesForTests());
-
- // Backoff time is bigger than the maximum allowed.
- RegisterURL(GURL("https://example.com"),
- URLRequestBackoffManager::kMaximumBackoffInSeconds + 1,
- base::Time::Now());
- ASSERT_EQ(0, manager_->GetNumberOfEntriesForTests());
-}
-
-TEST_F(URLRequestBackoffManagerTest, ShouldGarbageCollect) {
- base::Time request_time =
- base::Time::Now() - base::TimeDelta::FromSeconds(60);
- for (int i = 0;
- i < URLRequestBackoffManager::kNewEntriesBetweenCollecting - 1; i++) {
- RegisterURL(GURL(base::StringPrintf("http://example%d.com", i)), 10,
- request_time);
- ASSERT_EQ(i + 1, manager_->GetNumberOfEntriesForTests());
- }
- // Should clear all previous outdated entries.
- RegisterURL(GURL("http://example.com"), 10, base::Time::Now());
- ASSERT_EQ(1, manager_->GetNumberOfEntriesForTests());
-}
-
-TEST_F(URLRequestBackoffManagerTest, ClearOnNetworkChange) {
- for (int i = 0; i < 3; ++i) {
- RegisterURL(GURL("http://www.example.com/"), 60, base::Time::Now());
- ASSERT_EQ(1, manager_->GetNumberOfEntriesForTests());
- EXPECT_TRUE(manager_->ShouldRejectRequest(GURL("http://www.example.com/"),
- base::Time::Now()));
- switch (i) {
- case 0:
- manager_->OnIPAddressChanged();
- break;
- case 1:
- manager_->OnConnectionTypeChanged(
- NetworkChangeNotifier::CONNECTION_UNKNOWN);
- break;
- case 2:
- manager_->OnConnectionTypeChanged(
- NetworkChangeNotifier::CONNECTION_NONE);
- break;
- default:
- FAIL();
- }
-
- EXPECT_FALSE(manager_->ShouldRejectRequest(GURL("http://www.example.com/"),
- base::Time::Now()));
- ASSERT_EQ(0, manager_->GetNumberOfEntriesForTests());
- }
-}
-
-} // namespace net
diff --git a/chromium/net/url_request/url_request_context.h b/chromium/net/url_request/url_request_context.h
index 40b2486e68f..5c3542843d8 100644
--- a/chromium/net/url_request/url_request_context.h
+++ b/chromium/net/url_request/url_request_context.h
@@ -3,9 +3,7 @@
// found in the LICENSE file.
// This class represents contextual information (cookies, cache, etc.)
-// that's useful when processing resource requests.
-// The class is reference-counted so that it can be cleaned up after any
-// requests that are using it have been completed.
+// that's necessary when processing resource requests.
#ifndef NET_URL_REQUEST_URL_REQUEST_CONTEXT_H_
#define NET_URL_REQUEST_URL_REQUEST_CONTEXT_H_
@@ -23,7 +21,6 @@
#include "net/http/http_network_session.h"
#include "net/http/http_server_properties.h"
#include "net/http/transport_security_state.h"
-#include "net/log/net_log.h"
#include "net/ssl/ssl_config_service.h"
#include "net/url_request/url_request.h"
@@ -37,6 +34,7 @@ class HostResolver;
class HttpAuthHandlerFactory;
class HttpTransactionFactory;
class HttpUserAgentSettings;
+class NetLog;
class NetworkDelegate;
class NetworkQualityEstimator;
class SdchManager;
@@ -47,9 +45,11 @@ class URLRequestJobFactory;
class URLRequestThrottlerManager;
// Subclass to provide application-specific context for URLRequest
-// instances. Note that URLRequestContext typically does not provide storage for
-// these member variables, since they may be shared. For the ones that aren't
-// shared, URLRequestContextStorage can be helpful in defining their storage.
+// instances. URLRequestContext does not own these member variables, since they
+// may be shared with other contexts. URLRequestContextStorage can be used for
+// automatic lifetime management. Most callers should use an existing
+// URLRequestContext rather than creating a new one, as guaranteeing that the
+// URLRequestContext is destroyed before its members can be difficult.
class NET_EXPORT URLRequestContext
: NON_EXPORTED_BASE(public base::NonThreadSafe) {
public:
diff --git a/chromium/net/url_request/url_request_context_builder.cc b/chromium/net/url_request/url_request_context_builder.cc
index 4afa2a91ce9..fb4fd230736 100644
--- a/chromium/net/url_request/url_request_context_builder.cc
+++ b/chromium/net/url_request/url_request_context_builder.cc
@@ -35,13 +35,12 @@
#include "net/http/http_server_properties_manager.h"
#include "net/http/transport_security_persister.h"
#include "net/http/transport_security_state.h"
-#include "net/quic/quic_stream_factory.h"
+#include "net/quic/chromium/quic_stream_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/url_request/data_protocol_handler.h"
#include "net/url_request/static_http_user_agent_settings.h"
-#include "net/url_request/url_request_backoff_manager.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_storage.h"
#include "net/url_request/url_request_intercepting_job_factory.h"
@@ -95,9 +94,9 @@ class BasicNetworkDelegate : public NetworkDelegateImpl {
void OnBeforeRedirect(URLRequest* request,
const GURL& new_location) override {}
- void OnResponseStarted(URLRequest* request) override {}
+ void OnResponseStarted(URLRequest* request, int net_error) override {}
- void OnCompleted(URLRequest* request, bool started) override {}
+ void OnCompleted(URLRequest* request, bool started, int net_error) override {}
void OnURLRequestDestroyed(URLRequest* request) override {}
@@ -185,19 +184,17 @@ URLRequestContextBuilder::HttpNetworkSessionParams::HttpNetworkSessionParams()
host_mapping_rules(NULL),
testing_fixed_http_port(0),
testing_fixed_https_port(0),
- enable_spdy31(false),
enable_http2(true),
enable_quic(false),
quic_max_server_configs_stored_in_properties(0),
quic_delay_tcp_race(true),
- quic_max_number_of_lossy_connections(0),
quic_prefer_aes(false),
- quic_packet_loss_threshold(1.0f),
quic_idle_connection_timeout_seconds(kIdleConnectionTimeoutSeconds),
quic_close_sessions_on_ip_change(false),
quic_migrate_sessions_on_network_change(false),
quic_migrate_sessions_early(false),
- quic_disable_bidirectional_streams(false) {}
+ quic_disable_bidirectional_streams(false),
+ quic_race_cert_verification(false) {}
URLRequestContextBuilder::HttpNetworkSessionParams::~HttpNetworkSessionParams()
{}
@@ -212,7 +209,6 @@ URLRequestContextBuilder::URLRequestContextBuilder()
#endif
http_cache_enabled_(true),
throttling_enabled_(false),
- backoff_enabled_(false),
sdch_enabled_(false),
cookie_store_set_by_client_(false),
net_log_(nullptr),
@@ -249,7 +245,6 @@ void URLRequestContextBuilder::DisableHttpCache() {
void URLRequestContextBuilder::SetSpdyAndQuicEnabled(bool spdy_enabled,
bool quic_enabled) {
- http_network_session_params_.enable_spdy31 = spdy_enabled;
http_network_session_params_.enable_http2 = spdy_enabled;
http_network_session_params_.enable_quic = quic_enabled;
}
@@ -307,8 +302,9 @@ std::unique_ptr<URLRequestContext> URLRequestContextBuilder::Build() {
new ContainerURLRequestContext(file_task_runner_));
URLRequestContextStorage* storage = context->storage();
- storage->set_http_user_agent_settings(base::WrapUnique(
- new StaticHttpUserAgentSettings(accept_language_, user_agent_)));
+ storage->set_http_user_agent_settings(
+ base::MakeUnique<StaticHttpUserAgentSettings>(accept_language_,
+ user_agent_));
if (!network_delegate_)
network_delegate_.reset(new BasicNetworkDelegate);
@@ -374,7 +370,7 @@ std::unique_ptr<URLRequestContext> URLRequestContextBuilder::Build() {
}
storage->set_transport_security_state(
- base::WrapUnique(new TransportSecurityState()));
+ base::MakeUnique<TransportSecurityState>());
if (!transport_security_persister_path_.empty()) {
context->set_transport_security_persister(
base::WrapUnique<TransportSecurityPersister>(
@@ -409,12 +405,7 @@ std::unique_ptr<URLRequestContext> URLRequestContextBuilder::Build() {
if (throttling_enabled_) {
storage->set_throttler_manager(
- base::WrapUnique(new URLRequestThrottlerManager()));
- }
-
- if (backoff_enabled_) {
- storage->set_backoff_manager(
- base::WrapUnique(new URLRequestBackoffManager()));
+ base::MakeUnique<URLRequestThrottlerManager>());
}
HttpNetworkSession::Params network_session_params;
@@ -428,8 +419,6 @@ std::unique_ptr<URLRequestContext> URLRequestContextBuilder::Build() {
http_network_session_params_.testing_fixed_http_port;
network_session_params.testing_fixed_https_port =
http_network_session_params_.testing_fixed_https_port;
- network_session_params.enable_spdy31 =
- http_network_session_params_.enable_spdy31;
network_session_params.enable_http2 =
http_network_session_params_.enable_http2;
network_session_params.enable_quic = http_network_session_params_.enable_quic;
@@ -437,10 +426,6 @@ std::unique_ptr<URLRequestContext> URLRequestContextBuilder::Build() {
http_network_session_params_.quic_max_server_configs_stored_in_properties;
network_session_params.quic_delay_tcp_race =
http_network_session_params_.quic_delay_tcp_race;
- network_session_params.quic_max_number_of_lossy_connections =
- http_network_session_params_.quic_max_number_of_lossy_connections;
- network_session_params.quic_packet_loss_threshold =
- http_network_session_params_.quic_packet_loss_threshold;
network_session_params.quic_idle_connection_timeout_seconds =
http_network_session_params_.quic_idle_connection_timeout_seconds;
network_session_params.quic_connection_options =
@@ -459,6 +444,8 @@ std::unique_ptr<URLRequestContext> URLRequestContextBuilder::Build() {
http_network_session_params_.quic_migrate_sessions_early;
network_session_params.quic_disable_bidirectional_streams =
http_network_session_params_.quic_disable_bidirectional_streams;
+ network_session_params.quic_race_cert_verification =
+ http_network_session_params_.quic_race_cert_verification;
if (proxy_delegate_) {
network_session_params.proxy_delegate = proxy_delegate_.get();
storage->set_proxy_delegate(std::move(proxy_delegate_));
@@ -469,7 +456,7 @@ std::unique_ptr<URLRequestContext> URLRequestContextBuilder::Build() {
}
storage->set_http_network_session(
- base::WrapUnique(new HttpNetworkSession(network_session_params)));
+ base::MakeUnique<HttpNetworkSession>(network_session_params));
std::unique_ptr<HttpTransactionFactory> http_transaction_factory;
if (http_cache_enabled_) {
@@ -511,8 +498,8 @@ std::unique_ptr<URLRequestContext> URLRequestContextBuilder::Build() {
#if !defined(DISABLE_FILE_SUPPORT)
if (file_enabled_) {
job_factory->SetProtocolHandler(
- "file", base::WrapUnique(
- new FileProtocolHandler(context->GetFileTaskRunner())));
+ "file",
+ base::MakeUnique<FileProtocolHandler>(context->GetFileTaskRunner()));
}
#endif // !defined(DISABLE_FILE_SUPPORT)
@@ -520,9 +507,8 @@ std::unique_ptr<URLRequestContext> URLRequestContextBuilder::Build() {
if (ftp_enabled_) {
ftp_transaction_factory_.reset(
new FtpNetworkLayer(context->host_resolver()));
- job_factory->SetProtocolHandler(
- "ftp", base::WrapUnique(
- new FtpProtocolHandler(ftp_transaction_factory_.get())));
+ job_factory->SetProtocolHandler("ftp", base::MakeUnique<FtpProtocolHandler>(
+ ftp_transaction_factory_.get()));
}
#endif // !defined(DISABLE_FTP_SUPPORT)
diff --git a/chromium/net/url_request/url_request_context_builder.h b/chromium/net/url_request/url_request_context_builder.h
index 70c5fb0c1cd..29768464fee 100644
--- a/chromium/net/url_request/url_request_context_builder.h
+++ b/chromium/net/url_request/url_request_context_builder.h
@@ -34,7 +34,7 @@
#include "net/http/http_network_session.h"
#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_service.h"
-#include "net/quic/quic_protocol.h"
+#include "net/quic/core/quic_protocol.h"
#include "net/socket/next_proto.h"
#include "net/url_request/url_request_job_factory.h"
@@ -92,22 +92,20 @@ class NET_EXPORT URLRequestContextBuilder {
HostMappingRules* host_mapping_rules;
uint16_t testing_fixed_http_port;
uint16_t testing_fixed_https_port;
- bool enable_spdy31;
bool enable_http2;
bool enable_quic;
std::string quic_user_agent_id;
int quic_max_server_configs_stored_in_properties;
bool quic_delay_tcp_race;
- int quic_max_number_of_lossy_connections;
std::unordered_set<std::string> quic_host_whitelist;
bool quic_prefer_aes;
- float quic_packet_loss_threshold;
int quic_idle_connection_timeout_seconds;
QuicTagVector quic_connection_options;
bool quic_close_sessions_on_ip_change;
bool quic_migrate_sessions_on_network_change;
bool quic_migrate_sessions_early;
bool quic_disable_bidirectional_streams;
+ bool quic_race_cert_verification;
};
URLRequestContextBuilder();
@@ -237,17 +235,6 @@ class NET_EXPORT URLRequestContextBuilder {
http_network_session_params_.quic_delay_tcp_race = quic_delay_tcp_race;
}
- void set_quic_max_number_of_lossy_connections(
- int quic_max_number_of_lossy_connections) {
- http_network_session_params_.quic_max_number_of_lossy_connections =
- quic_max_number_of_lossy_connections;
- }
-
- void set_quic_packet_loss_threshold(float quic_packet_loss_threshold) {
- http_network_session_params_.quic_packet_loss_threshold =
- quic_packet_loss_threshold;
- }
-
void set_quic_idle_connection_timeout_seconds(
int quic_idle_connection_timeout_seconds) {
http_network_session_params_.quic_idle_connection_timeout_seconds =
@@ -286,12 +273,13 @@ class NET_EXPORT URLRequestContextBuilder {
quic_disable_bidirectional_streams;
}
- void set_throttling_enabled(bool throttling_enabled) {
- throttling_enabled_ = throttling_enabled;
+ void set_quic_race_cert_verification(bool quic_race_cert_verification) {
+ http_network_session_params_.quic_race_cert_verification =
+ quic_race_cert_verification;
}
- void set_backoff_enabled(bool backoff_enabled) {
- backoff_enabled_ = backoff_enabled;
+ void set_throttling_enabled(bool throttling_enabled) {
+ throttling_enabled_ = throttling_enabled;
}
void set_socket_performance_watcher_factory(
@@ -353,7 +341,6 @@ class NET_EXPORT URLRequestContextBuilder {
#endif
bool http_cache_enabled_;
bool throttling_enabled_;
- bool backoff_enabled_;
bool sdch_enabled_;
bool cookie_store_set_by_client_;
diff --git a/chromium/net/url_request/url_request_context_builder_unittest.cc b/chromium/net/url_request/url_request_context_builder_unittest.cc
index f66cf69887a..cd8f21dd4ff 100644
--- a/chromium/net/url_request/url_request_context_builder_unittest.cc
+++ b/chromium/net/url_request/url_request_context_builder_unittest.cc
@@ -13,6 +13,7 @@
#include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/http_auth_handler.h"
#include "net/http/http_auth_handler_factory.h"
+#include "net/log/net_log_with_source.h"
#include "net/ssl/ssl_info.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/url_request/url_request.h"
@@ -41,7 +42,7 @@ class MockHttpAuthHandlerFactory : public HttpAuthHandlerFactory {
const GURL& origin,
CreateReason reason,
int nonce_count,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<HttpAuthHandler>* handler) override {
handler->reset();
@@ -61,8 +62,8 @@ class URLRequestContextBuilderTest : public PlatformTest {
test_server_.AddDefaultHandlers(
base::FilePath(FILE_PATH_LITERAL("net/data/url_request_unittest")));
#if defined(OS_LINUX) || defined(OS_ANDROID)
- builder_.set_proxy_config_service(base::WrapUnique(
- new ProxyConfigServiceFixed(ProxyConfig::CreateDirect())));
+ builder_.set_proxy_config_service(
+ base::MakeUnique<ProxyConfigServiceFixed>(ProxyConfig::CreateDirect()));
#endif // defined(OS_LINUX) || defined(OS_ANDROID)
}
@@ -109,34 +110,35 @@ TEST_F(URLRequestContextBuilderTest, DefaultHttpAuthHandlerFactory) {
EXPECT_EQ(OK,
context->http_auth_handler_factory()->CreateAuthHandlerFromString(
"basic", HttpAuth::AUTH_SERVER, null_ssl_info, gurl,
- BoundNetLog(), &handler));
+ NetLogWithSource(), &handler));
}
TEST_F(URLRequestContextBuilderTest, CustomHttpAuthHandlerFactory) {
GURL gurl("www.google.com");
const int kBasicReturnCode = OK;
std::unique_ptr<HttpAuthHandler> handler;
- builder_.SetHttpAuthHandlerFactory(base::WrapUnique(
- new MockHttpAuthHandlerFactory("ExtraScheme", kBasicReturnCode)));
+ builder_.SetHttpAuthHandlerFactory(
+ base::MakeUnique<MockHttpAuthHandlerFactory>("ExtraScheme",
+ kBasicReturnCode));
std::unique_ptr<URLRequestContext> context(builder_.Build());
SSLInfo null_ssl_info;
// Verify that a handler is returned for a custom scheme.
EXPECT_EQ(kBasicReturnCode,
context->http_auth_handler_factory()->CreateAuthHandlerFromString(
"ExtraScheme", HttpAuth::AUTH_SERVER, null_ssl_info, gurl,
- BoundNetLog(), &handler));
+ NetLogWithSource(), &handler));
// Verify that the default basic handler isn't present
EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME,
context->http_auth_handler_factory()->CreateAuthHandlerFromString(
"basic", HttpAuth::AUTH_SERVER, null_ssl_info, gurl,
- BoundNetLog(), &handler));
+ NetLogWithSource(), &handler));
// Verify that a handler isn't returned for a bogus scheme.
EXPECT_EQ(ERR_UNSUPPORTED_AUTH_SCHEME,
context->http_auth_handler_factory()->CreateAuthHandlerFromString(
"Bogus", HttpAuth::AUTH_SERVER, null_ssl_info, gurl,
- BoundNetLog(), &handler));
+ NetLogWithSource(), &handler));
}
} // namespace
diff --git a/chromium/net/url_request/url_request_context_getter.cc b/chromium/net/url_request/url_request_context_getter.cc
index 18086175214..022aa0f958c 100644
--- a/chromium/net/url_request/url_request_context_getter.cc
+++ b/chromium/net/url_request/url_request_context_getter.cc
@@ -47,7 +47,7 @@ void URLRequestContextGetter::OnDestruct() const {
}
}
}
- // If no IO message loop proxy was available, we will just leak memory.
+ // If no IO task runner was available, we will just leak memory.
// This is also true if the IO thread is gone.
}
diff --git a/chromium/net/url_request/url_request_context_storage.cc b/chromium/net/url_request/url_request_context_storage.cc
index 08c8f29cd17..e010643abc7 100644
--- a/chromium/net/url_request/url_request_context_storage.cc
+++ b/chromium/net/url_request/url_request_context_storage.cc
@@ -22,7 +22,6 @@
#include "net/proxy/proxy_service.h"
#include "net/ssl/channel_id_service.h"
#include "net/url_request/http_user_agent_settings.h"
-#include "net/url_request/url_request_backoff_manager.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_job_factory.h"
#include "net/url_request/url_request_throttler_manager.h"
@@ -141,12 +140,6 @@ void URLRequestContextStorage::set_throttler_manager(
throttler_manager_ = std::move(throttler_manager);
}
-void URLRequestContextStorage::set_backoff_manager(
- std::unique_ptr<URLRequestBackoffManager> backoff_manager) {
- context_->set_backoff_manager(backoff_manager.get());
- backoff_manager_ = std::move(backoff_manager);
-}
-
void URLRequestContextStorage::set_http_user_agent_settings(
std::unique_ptr<HttpUserAgentSettings> http_user_agent_settings) {
context_->set_http_user_agent_settings(http_user_agent_settings.get());
diff --git a/chromium/net/url_request/url_request_context_storage.h b/chromium/net/url_request/url_request_context_storage.h
index a38fd130736..d5b08022839 100644
--- a/chromium/net/url_request/url_request_context_storage.h
+++ b/chromium/net/url_request/url_request_context_storage.h
@@ -33,7 +33,6 @@ class SdchManager;
class SSLConfigService;
class TransportSecurityState;
class URLRequestContext;
-class URLRequestBackoffManager;
class URLRequestJobFactory;
class URLRequestThrottlerManager;
@@ -77,8 +76,6 @@ class NET_EXPORT URLRequestContextStorage {
void set_job_factory(std::unique_ptr<URLRequestJobFactory> job_factory);
void set_throttler_manager(
std::unique_ptr<URLRequestThrottlerManager> throttler_manager);
- void set_backoff_manager(
- std::unique_ptr<URLRequestBackoffManager> backoff_manager);
void set_http_user_agent_settings(
std::unique_ptr<HttpUserAgentSettings> http_user_agent_settings);
void set_sdch_manager(std::unique_ptr<SdchManager> sdch_manager);
@@ -90,9 +87,7 @@ class NET_EXPORT URLRequestContextStorage {
}
private:
- // We use a raw pointer to prevent reference cycles, since
- // URLRequestContextStorage can often be contained within a URLRequestContext
- // subclass.
+ // Not owned.
URLRequestContext* const context_;
// Owned members.
@@ -103,7 +98,7 @@ class NET_EXPORT URLRequestContextStorage {
std::unique_ptr<ChannelIDService> channel_id_service_;
std::unique_ptr<HttpAuthHandlerFactory> http_auth_handler_factory_;
std::unique_ptr<ProxyService> proxy_service_;
- // TODO(willchan): Remove refcounting on these members.
+ // TODO(willchan): Remove refcounting on this member.
scoped_refptr<SSLConfigService> ssl_config_service_;
std::unique_ptr<NetworkDelegate> network_delegate_;
std::unique_ptr<ProxyDelegate> proxy_delegate_;
@@ -121,7 +116,6 @@ class NET_EXPORT URLRequestContextStorage {
std::unique_ptr<HttpTransactionFactory> http_transaction_factory_;
std::unique_ptr<URLRequestJobFactory> job_factory_;
std::unique_ptr<URLRequestThrottlerManager> throttler_manager_;
- std::unique_ptr<URLRequestBackoffManager> backoff_manager_;
std::unique_ptr<SdchManager> sdch_manager_;
DISALLOW_COPY_AND_ASSIGN(URLRequestContextStorage);
diff --git a/chromium/net/url_request/url_request_data_job.h b/chromium/net/url_request/url_request_data_job.h
index 9fb033d669e..7fa311f0ac2 100644
--- a/chromium/net/url_request/url_request_data_job.h
+++ b/chromium/net/url_request/url_request_data_job.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/macros.h"
+#include "net/base/net_export.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_simple_job.h"
diff --git a/chromium/net/url_request/url_request_data_job_fuzzer.cc b/chromium/net/url_request/url_request_data_job_fuzzer.cc
index 5a0987c909d..4c76e2cbd61 100644
--- a/chromium/net/url_request/url_request_data_job_fuzzer.cc
+++ b/chromium/net/url_request/url_request_data_job_fuzzer.cc
@@ -3,11 +3,12 @@
// found in the LICENSE file.
#include <memory>
+#include <string>
#include "base/memory/ptr_util.h"
#include "base/memory/singleton.h"
#include "base/run_loop.h"
-#include "net/base/fuzzed_data_provider.h"
+#include "base/test/fuzzed_data_provider.h"
#include "net/http/http_request_headers.h"
#include "net/url_request/data_protocol_handler.h"
#include "net/url_request/url_request.h"
@@ -29,7 +30,7 @@ class URLRequestDataJobFuzzerHarness : public net::URLRequest::Delegate {
URLRequestDataJobFuzzerHarness()
: context_(true), task_runner_(base::ThreadTaskRunnerHandle::Get()) {
job_factory_.SetProtocolHandler(
- "data", base::WrapUnique(new net::DataProtocolHandler()));
+ "data", base::MakeUnique<net::DataProtocolHandler>());
context_.set_job_factory(&job_factory_);
context_.Init();
}
@@ -39,7 +40,7 @@ class URLRequestDataJobFuzzerHarness : public net::URLRequest::Delegate {
}
int CreateAndReadFromDataURLRequest(const uint8_t* data, size_t size) {
- net::FuzzedDataProvider provider(data, size);
+ base::FuzzedDataProvider provider(data, size);
read_lengths_.clear();
// Allocate an IOBuffer with fuzzed size.
@@ -63,10 +64,12 @@ class URLRequestDataJobFuzzerHarness : public net::URLRequest::Delegate {
simulated_bytes_read += read_length;
}
- // The data URL is the rest of the fuzzed data. If the URL is invalid just
+ // The data URL is the rest of the fuzzed data with "data:" prepended, to
+ // ensure that if it's a URL, it's a data URL. If the URL is invalid just
// use a test variant, so the fuzzer has a chance to execute something.
- base::StringPiece data_bytes(provider.ConsumeRemainingBytes());
- GURL data_url(data_bytes);
+ std::string data_url_string =
+ std::string("data:") + provider.ConsumeRemainingBytes().as_string();
+ GURL data_url(data_url_string);
if (!data_url.is_valid())
data_url = GURL("data:text/html;charset=utf-8,<p>test</p>");
@@ -96,7 +99,7 @@ class URLRequestDataJobFuzzerHarness : public net::URLRequest::Delegate {
}
void ReadFromRequest(net::URLRequest* request) {
- bool sync = false;
+ int bytes_read = 0;
do {
// If possible, pop the next read size. If none exists, then this should
// be the last call to Read.
@@ -107,13 +110,10 @@ class URLRequestDataJobFuzzerHarness : public net::URLRequest::Delegate {
read_lengths_.pop_back();
}
- int bytes_read = 0;
- sync = request->Read(buf_.get(), read_size, &bytes_read);
- // No more populated reads implies !bytes_read.
- DCHECK(using_populated_read || !bytes_read);
- } while (sync);
+ bytes_read = request->Read(buf_.get(), read_size);
+ } while (bytes_read > 0);
- if (!request->status().is_io_pending())
+ if (bytes_read != net::ERR_IO_PENDING)
QuitLoop();
}
@@ -129,22 +129,23 @@ class URLRequestDataJobFuzzerHarness : public net::URLRequest::Delegate {
void OnSSLCertificateError(net::URLRequest* request,
const net::SSLInfo& ssl_info,
bool fatal) override {}
- void OnBeforeNetworkStart(net::URLRequest* request, bool* defer) override {}
- void OnResponseStarted(net::URLRequest* request) override {
- DCHECK(!request->status().is_io_pending());
+ void OnResponseStarted(net::URLRequest* request, int net_error) override {
DCHECK(buf_.get());
DCHECK(read_loop_);
- if (request->status().is_success()) {
+ DCHECK_NE(net::ERR_IO_PENDING, net_error);
+
+ if (net_error == net::OK) {
ReadFromRequest(request);
} else {
QuitLoop();
}
}
void OnReadCompleted(net::URLRequest* request, int bytes_read) override {
- DCHECK(!request->status().is_io_pending());
+ DCHECK_NE(net::ERR_IO_PENDING, bytes_read);
DCHECK(buf_.get());
DCHECK(read_loop_);
- if (request->status().is_success() && bytes_read > 0) {
+
+ if (bytes_read > 0) {
ReadFromRequest(request);
} else {
QuitLoop();
diff --git a/chromium/net/url_request/url_request_file_dir_job_unittest.cc b/chromium/net/url_request/url_request_file_dir_job_unittest.cc
index 079bb83b456..922402a59f0 100644
--- a/chromium/net/url_request/url_request_file_dir_job_unittest.cc
+++ b/chromium/net/url_request/url_request_file_dir_job_unittest.cc
@@ -16,10 +16,15 @@
#include "net/base/filename_util.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
+#include "net/test/gtest_util.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -77,7 +82,7 @@ class TestDirectoryURLRequestDelegate : public TestDelegate {
~TestDirectoryURLRequestDelegate() override {}
- void OnResponseStarted(URLRequest* request) override {
+ void OnResponseStarted(URLRequest* request, int net_error) override {
got_response_started_ = true;
}
@@ -104,11 +109,11 @@ TEST_F(URLRequestFileDirTest, ListCompletionOnNoPending) {
// It is necessary to pass an existing directory to UrlRequest object,
// but it will be deleted for testing purpose after request is started.
ASSERT_TRUE(directory.CreateUniqueTempDir());
- TestJobFactory factory(directory.path());
+ TestJobFactory factory(directory.GetPath());
context_.set_job_factory(&factory);
std::unique_ptr<URLRequest> request(context_.CreateRequest(
FilePathToFileURL(
- directory.path().AppendASCII("this_path_does_not_exist")),
+ directory.GetPath().AppendASCII("this_path_does_not_exist")),
DEFAULT_PRIORITY, &delegate_));
request->Start();
@@ -120,13 +125,12 @@ TEST_F(URLRequestFileDirTest, ListCompletionOnNoPending) {
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(delegate_.got_response_started());
- int bytes_read = 0;
- EXPECT_FALSE(request->Read(buffer_.get(), kBufferSize, &bytes_read));
+ int bytes_read = request->Read(buffer_.get(), kBufferSize);
// The URLRequestFileDirJobShould return the cached read error synchronously.
// If it's not returned synchronously, the code path this is intended to test
// was not executed.
- EXPECT_EQ(ERR_FILE_NOT_FOUND, request->status().ToNetError());
+ EXPECT_THAT(bytes_read, IsError(ERR_FILE_NOT_FOUND));
}
// Test the case where reading the response completes synchronously.
@@ -134,9 +138,9 @@ TEST_F(URLRequestFileDirTest, DirectoryWithASingleFileSync) {
base::ScopedTempDir directory;
ASSERT_TRUE(directory.CreateUniqueTempDir());
base::FilePath path;
- base::CreateTemporaryFileInDir(directory.path(), &path);
+ base::CreateTemporaryFileInDir(directory.GetPath(), &path);
- TestJobFactory factory(directory.path());
+ TestJobFactory factory(directory.GetPath());
context_.set_job_factory(&factory);
std::unique_ptr<URLRequest> request(context_.CreateRequest(
@@ -149,17 +153,14 @@ TEST_F(URLRequestFileDirTest, DirectoryWithASingleFileSync) {
// entire directory listing and cached it.
base::RunLoop().RunUntilIdle();
- int bytes_read = 0;
// This will complete synchronously, since the URLRequetsFileDirJob had
// directory listing cached in memory.
- EXPECT_TRUE(request->Read(buffer_.get(), kBufferSize, &bytes_read));
-
- EXPECT_EQ(URLRequestStatus::SUCCESS, request->status().status());
+ int bytes_read = request->Read(buffer_.get(), kBufferSize);
ASSERT_GT(bytes_read, 0);
ASSERT_LE(bytes_read, kBufferSize);
std::string data(buffer_->data(), bytes_read);
- EXPECT_TRUE(data.find(directory.path().BaseName().MaybeAsASCII()) !=
+ EXPECT_TRUE(data.find(directory.GetPath().BaseName().MaybeAsASCII()) !=
std::string::npos);
EXPECT_TRUE(data.find(path.BaseName().MaybeAsASCII()) != std::string::npos);
}
@@ -169,9 +170,9 @@ TEST_F(URLRequestFileDirTest, DirectoryWithASingleFileAsync) {
base::ScopedTempDir directory;
ASSERT_TRUE(directory.CreateUniqueTempDir());
base::FilePath path;
- base::CreateTemporaryFileInDir(directory.path(), &path);
+ base::CreateTemporaryFileInDir(directory.GetPath(), &path);
- TestJobFactory factory(directory.path());
+ TestJobFactory factory(directory.GetPath());
context_.set_job_factory(&factory);
TestDelegate delegate;
@@ -185,7 +186,7 @@ TEST_F(URLRequestFileDirTest, DirectoryWithASingleFileAsync) {
ASSERT_GT(delegate.bytes_received(), 0);
ASSERT_LE(delegate.bytes_received(), kBufferSize);
EXPECT_TRUE(delegate.data_received().find(
- directory.path().BaseName().MaybeAsASCII()) !=
+ directory.GetPath().BaseName().MaybeAsASCII()) !=
std::string::npos);
EXPECT_TRUE(delegate.data_received().find(path.BaseName().MaybeAsASCII()) !=
std::string::npos);
@@ -196,14 +197,14 @@ TEST_F(URLRequestFileDirTest, DirectoryWithAFileAndSubdirectory) {
ASSERT_TRUE(directory.CreateUniqueTempDir());
base::FilePath sub_dir;
- CreateTemporaryDirInDir(directory.path(),
+ CreateTemporaryDirInDir(directory.GetPath(),
FILE_PATH_LITERAL("CreateNewSubDirectoryInDirectory"),
&sub_dir);
base::FilePath path;
- base::CreateTemporaryFileInDir(directory.path(), &path);
+ base::CreateTemporaryFileInDir(directory.GetPath(), &path);
- TestJobFactory factory(directory.path());
+ TestJobFactory factory(directory.GetPath());
context_.set_job_factory(&factory);
TestDelegate delegate;
@@ -217,7 +218,7 @@ TEST_F(URLRequestFileDirTest, DirectoryWithAFileAndSubdirectory) {
ASSERT_GT(delegate.bytes_received(), 0);
ASSERT_LE(delegate.bytes_received(), kBufferSize);
EXPECT_TRUE(delegate.data_received().find(
- directory.path().BaseName().MaybeAsASCII()) !=
+ directory.GetPath().BaseName().MaybeAsASCII()) !=
std::string::npos);
EXPECT_TRUE(delegate.data_received().find(
sub_dir.BaseName().MaybeAsASCII()) != std::string::npos);
@@ -229,12 +230,12 @@ TEST_F(URLRequestFileDirTest, EmptyDirectory) {
base::ScopedTempDir directory;
ASSERT_TRUE(directory.CreateUniqueTempDir());
- TestJobFactory factory(directory.path());
+ TestJobFactory factory(directory.GetPath());
context_.set_job_factory(&factory);
TestDelegate delegate;
std::unique_ptr<URLRequest> request(context_.CreateRequest(
- FilePathToFileURL(directory.path()), DEFAULT_PRIORITY, &delegate));
+ FilePathToFileURL(directory.GetPath()), DEFAULT_PRIORITY, &delegate));
request->Start();
EXPECT_TRUE(request->is_pending());
@@ -243,7 +244,7 @@ TEST_F(URLRequestFileDirTest, EmptyDirectory) {
ASSERT_GT(delegate.bytes_received(), 0);
ASSERT_LE(delegate.bytes_received(), kBufferSize);
EXPECT_TRUE(delegate.data_received().find(
- directory.path().BaseName().MaybeAsASCII()) !=
+ directory.GetPath().BaseName().MaybeAsASCII()) !=
std::string::npos);
}
diff --git a/chromium/net/url_request/url_request_file_job_unittest.cc b/chromium/net/url_request/url_request_file_job_unittest.cc
index 706ea798d9f..613353dd866 100644
--- a/chromium/net/url_request/url_request_file_job_unittest.cc
+++ b/chromium/net/url_request/url_request_file_job_unittest.cc
@@ -6,6 +6,7 @@
#include <memory>
+#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
@@ -123,19 +124,11 @@ class TestJobFactory : public URLRequestJobFactory {
mutable std::string* observed_content_;
};
-// Helper function to create a file in |directory| filled with
-// |content|. Returns true on succes and fills in |path| with the full path to
-// the file.
-bool CreateTempFileWithContent(const std::string& content,
- const base::ScopedTempDir& directory,
- base::FilePath* path) {
- if (!directory.IsValid())
- return false;
-
- if (!base::CreateTemporaryFileInDir(directory.path(), path))
- return false;
-
- return base::WriteFile(*path, content.c_str(), content.length());
+// Helper function to create a file at |path| filled with |content|.
+// Returns true on success.
+bool CreateFileWithContent(const std::string& content,
+ const base::FilePath& path) {
+ return base::WriteFile(path, content.c_str(), content.length());
}
// A simple holder for start/end used in http range requests.
@@ -169,6 +162,14 @@ class URLRequestFileJobEventsTest : public testing::Test {
// observed.
void RunRequest(const std::string& content, const Range* range);
+ // This is the same as the method above it, except that it will make sure
+ // the content matches |expected_content| and allow caller to specify the
+ // extension of the filename in |file_extension|.
+ void RunRequest(const std::string& content,
+ const std::string& expected_content,
+ const base::FilePath::StringPieceType& file_extension,
+ const Range* range);
+
TestURLRequestContext context_;
TestDelegate delegate_;
};
@@ -177,10 +178,20 @@ URLRequestFileJobEventsTest::URLRequestFileJobEventsTest() {}
void URLRequestFileJobEventsTest::RunRequest(const std::string& content,
const Range* range) {
+ RunRequest(content, content, FILE_PATH_LITERAL(""), range);
+}
+
+void URLRequestFileJobEventsTest::RunRequest(
+ const std::string& raw_content,
+ const std::string& expected_content,
+ const base::FilePath::StringPieceType& file_extension,
+ const Range* range) {
base::ScopedTempDir directory;
ASSERT_TRUE(directory.CreateUniqueTempDir());
- base::FilePath path;
- ASSERT_TRUE(CreateTempFileWithContent(content, directory, &path));
+ base::FilePath path = directory.GetPath().Append(FILE_PATH_LITERAL("test"));
+ if (!file_extension.empty())
+ path = path.AddExtension(file_extension);
+ ASSERT_TRUE(CreateFileWithContent(raw_content, path));
{
int64_t seek_position;
@@ -194,7 +205,8 @@ void URLRequestFileJobEventsTest::RunRequest(const std::string& content,
ASSERT_GE(range->start, 0);
ASSERT_GE(range->end, 0);
ASSERT_LE(range->start, range->end);
- ASSERT_LT(static_cast<unsigned int>(range->end), content.length());
+ ASSERT_LT(static_cast<unsigned int>(range->end),
+ expected_content.length());
std::string range_value =
base::StringPrintf("bytes=%d-%d", range->start, range->end);
request->SetExtraRequestHeaderByName(HttpRequestHeaders::kRange,
@@ -206,19 +218,21 @@ void URLRequestFileJobEventsTest::RunRequest(const std::string& content,
EXPECT_FALSE(delegate_.request_failed());
int expected_length =
- range ? (range->end - range->start + 1) : content.length();
+ range ? (range->end - range->start + 1) : expected_content.length();
EXPECT_EQ(delegate_.bytes_received(), expected_length);
- std::string expected_content;
+ std::string expected_data_received;
if (range) {
- expected_content.insert(0, content, range->start, expected_length);
+ expected_data_received.insert(0, expected_content, range->start,
+ expected_length);
+ EXPECT_EQ(expected_data_received, observed_content);
} else {
- expected_content = content;
+ expected_data_received = expected_content;
+ EXPECT_EQ(raw_content, observed_content);
}
- EXPECT_TRUE(delegate_.data_received() == expected_content);
+ EXPECT_EQ(expected_data_received, delegate_.data_received());
EXPECT_EQ(seek_position, range ? range->start : 0);
- EXPECT_EQ(expected_content, observed_content);
}
base::RunLoop().RunUntilIdle();
@@ -256,6 +270,18 @@ TEST_F(URLRequestFileJobEventsTest, Range) {
RunRequest(MakeContentOfSize(size), &range);
}
+TEST_F(URLRequestFileJobEventsTest, DecodeSvgzFile) {
+ std::string expected_content("Hello, World!");
+ unsigned char gzip_data[] = {
+ // From:
+ // echo -n 'Hello, World!' | gzip | xxd -i | sed -e 's/^/ /'
+ 0x1f, 0x8b, 0x08, 0x00, 0x2b, 0x02, 0x84, 0x55, 0x00, 0x03, 0xf3,
+ 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51, 0x08, 0xcf, 0x2f, 0xca, 0x49,
+ 0x51, 0x04, 0x00, 0xd0, 0xc3, 0x4a, 0xec, 0x0d, 0x00, 0x00, 0x00};
+ RunRequest(std::string(reinterpret_cast<char*>(gzip_data), sizeof(gzip_data)),
+ expected_content, FILE_PATH_LITERAL("svgz"), nullptr);
+}
+
} // namespace
} // namespace net
diff --git a/chromium/net/url_request/url_request_ftp_job.cc b/chromium/net/url_request/url_request_ftp_job.cc
index 1c20a578370..dcb914a878d 100644
--- a/chromium/net/url_request/url_request_ftp_job.cc
+++ b/chromium/net/url_request/url_request_ftp_job.cc
@@ -6,6 +6,7 @@
#include "base/compiler_specific.h"
#include "base/location.h"
+#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -24,6 +25,19 @@
namespace net {
+class URLRequestFtpJob::AuthData {
+ public:
+ AuthState state; // Whether we need, have, or gave up on authentication.
+ AuthCredentials credentials; // The credentials to use for auth.
+
+ AuthData();
+ ~AuthData();
+};
+
+URLRequestFtpJob::AuthData::AuthData() : state(AUTH_STATE_NEED_AUTH) {}
+
+URLRequestFtpJob::AuthData::~AuthData() {}
+
URLRequestFtpJob::URLRequestFtpJob(
URLRequest* request,
NetworkDelegate* network_delegate,
@@ -101,7 +115,7 @@ void URLRequestFtpJob::Start() {
} else {
DCHECK_EQ(request_->context()->proxy_service(), proxy_service_);
rv = proxy_service_->ResolveProxy(
- request_->url(), "GET", request_->load_flags(), &proxy_info_,
+ request_->url(), "GET", &proxy_info_,
base::Bind(&URLRequestFtpJob::OnResolveProxyComplete,
base::Unretained(this)),
&pac_request_, NULL, request_->net_log());
@@ -325,10 +339,6 @@ void URLRequestFtpJob::CancelAuth() {
OnStartCompletedAsync(OK);
}
-UploadProgress URLRequestFtpJob::GetUploadProgress() const {
- return UploadProgress();
-}
-
int URLRequestFtpJob::ReadRawData(IOBuffer* buf, int buf_size) {
DCHECK_NE(buf_size, 0);
DCHECK(!read_in_progress_);
@@ -362,7 +372,7 @@ void URLRequestFtpJob::HandleAuthNeededResponse() {
if (ftp_transaction_ && auth_data_->state == AUTH_STATE_HAVE_AUTH)
ftp_auth_cache_->Remove(origin, auth_data_->credentials);
} else {
- auth_data_ = new AuthData;
+ auth_data_ = base::MakeUnique<AuthData>();
}
auth_data_->state = AUTH_STATE_NEED_AUTH;
diff --git a/chromium/net/url_request/url_request_ftp_job.h b/chromium/net/url_request/url_request_ftp_job.h
index 35d6593a8d4..b8d06db7bc2 100644
--- a/chromium/net/url_request/url_request_ftp_job.h
+++ b/chromium/net/url_request/url_request_ftp_job.h
@@ -5,6 +5,7 @@
#ifndef NET_URL_REQUEST_URL_REQUEST_FTP_JOB_H_
#define NET_URL_REQUEST_URL_REQUEST_FTP_JOB_H_
+#include <memory>
#include <string>
#include "base/macros.h"
@@ -49,6 +50,8 @@ class NET_EXPORT_PRIVATE URLRequestFtpJob : public URLRequestJob {
RequestPriority priority() const { return priority_; }
private:
+ class AuthData;
+
void OnResolveProxyComplete(int result);
void StartFtpTransaction();
@@ -70,8 +73,6 @@ class NET_EXPORT_PRIVATE URLRequestFtpJob : public URLRequestJob {
void SetAuth(const AuthCredentials& credentials) override;
void CancelAuth() override;
- // TODO(ibrar): Yet to give another look at this function.
- UploadProgress GetUploadProgress() const override;
int ReadRawData(IOBuffer* buf, int buf_size) override;
void HandleAuthNeededResponse();
@@ -91,7 +92,7 @@ class NET_EXPORT_PRIVATE URLRequestFtpJob : public URLRequestJob {
bool read_in_progress_;
- scoped_refptr<AuthData> auth_data_;
+ std::unique_ptr<AuthData> auth_data_;
FtpTransactionFactory* ftp_transaction_factory_;
FtpAuthCache* ftp_auth_cache_;
diff --git a/chromium/net/url_request/url_request_ftp_job_unittest.cc b/chromium/net/url_request/url_request_ftp_job_unittest.cc
index d6917fbebd0..6f2642106cf 100644
--- a/chromium/net/url_request/url_request_ftp_job_unittest.cc
+++ b/chromium/net/url_request/url_request_ftp_job_unittest.cc
@@ -19,16 +19,22 @@
#include "net/proxy/mock_proxy_resolver.h"
#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_config_service_fixed.h"
+#include "net/proxy/proxy_server.h"
#include "net/socket/socket_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/url_request/ftp_protocol_handler.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_job_factory_impl.h"
#include "net/url_request/url_request_status.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+using net::test::IsError;
+using net::test::IsOk;
+
using base::ASCIIToUTF16;
namespace net {
@@ -247,10 +253,10 @@ class URLRequestFtpJobTest : public testing::Test {
public:
URLRequestFtpJobTest()
: request_context_(&socket_factory_,
- base::WrapUnique(new ProxyService(
+ base::MakeUnique<ProxyService>(
base::WrapUnique(new SimpleProxyConfigService),
- NULL,
- NULL)),
+ nullptr,
+ nullptr),
&network_delegate_,
&ftp_transaction_factory_) {}
@@ -261,8 +267,9 @@ class URLRequestFtpJobTest : public testing::Test {
void AddSocket(MockRead* reads, size_t reads_size,
MockWrite* writes, size_t writes_size) {
- std::unique_ptr<SequencedSocketData> socket_data(base::WrapUnique(
- new SequencedSocketData(reads, reads_size, writes, writes_size)));
+ std::unique_ptr<SequencedSocketData> socket_data(
+ base::MakeUnique<SequencedSocketData>(reads, reads_size, writes,
+ writes_size));
socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
socket_factory_.AddSocketDataProvider(socket_data.get());
@@ -304,9 +311,10 @@ TEST_F(URLRequestFtpJobTest, FtpProxyRequest) {
// The TestDelegate will by default quit the message loop on completion.
base::RunLoop().Run();
- EXPECT_TRUE(url_request->status().is_success());
- EXPECT_TRUE(url_request->proxy_server().Equals(
- HostPortPair::FromString("localhost:80")));
+ EXPECT_THAT(request_delegate.request_status(), IsOk());
+ EXPECT_EQ(ProxyServer(ProxyServer::SCHEME_HTTP,
+ HostPortPair::FromString("localhost:80")),
+ url_request->proxy_server());
EXPECT_EQ(1, network_delegate()->completed_requests());
EXPECT_EQ(0, network_delegate()->error_count());
EXPECT_FALSE(request_delegate.auth_required_called());
@@ -400,9 +408,10 @@ TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedProxyAuthNoCredentials) {
// The TestDelegate will by default quit the message loop on completion.
base::RunLoop().Run();
- EXPECT_TRUE(url_request->status().is_success());
- EXPECT_TRUE(url_request->proxy_server().Equals(
- HostPortPair::FromString("localhost:80")));
+ EXPECT_THAT(request_delegate.request_status(), IsOk());
+ EXPECT_EQ(ProxyServer(ProxyServer::SCHEME_HTTP,
+ HostPortPair::FromString("localhost:80")),
+ url_request->proxy_server());
EXPECT_EQ(1, network_delegate()->completed_requests());
EXPECT_EQ(0, network_delegate()->error_count());
EXPECT_TRUE(request_delegate.auth_required_called());
@@ -446,7 +455,7 @@ TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedProxyAuthWithCredentials) {
// The TestDelegate will by default quit the message loop on completion.
base::RunLoop().Run();
- EXPECT_TRUE(url_request->status().is_success());
+ EXPECT_THAT(request_delegate.request_status(), IsOk());
EXPECT_EQ(1, network_delegate()->completed_requests());
EXPECT_EQ(0, network_delegate()->error_count());
EXPECT_TRUE(request_delegate.auth_required_called());
@@ -479,7 +488,7 @@ TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedServerAuthNoCredentials) {
// The TestDelegate will by default quit the message loop on completion.
base::RunLoop().Run();
- EXPECT_TRUE(url_request->status().is_success());
+ EXPECT_THAT(request_delegate.request_status(), IsOk());
EXPECT_EQ(1, network_delegate()->completed_requests());
EXPECT_EQ(0, network_delegate()->error_count());
EXPECT_TRUE(request_delegate.auth_required_called());
@@ -523,7 +532,7 @@ TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedServerAuthWithCredentials) {
// The TestDelegate will by default quit the message loop on completion.
base::RunLoop().Run();
- EXPECT_TRUE(url_request->status().is_success());
+ EXPECT_THAT(request_delegate.request_status(), IsOk());
EXPECT_EQ(1, network_delegate()->completed_requests());
EXPECT_EQ(0, network_delegate()->error_count());
EXPECT_TRUE(request_delegate.auth_required_called());
@@ -597,7 +606,6 @@ TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedProxyAndServerAuth) {
// Run until server auth is requested.
base::RunLoop().Run();
- EXPECT_TRUE(url_request->status().is_success());
EXPECT_EQ(0, network_delegate()->completed_requests());
EXPECT_EQ(0, network_delegate()->error_count());
url_request->SetAuth(
@@ -606,7 +614,7 @@ TEST_F(URLRequestFtpJobTest, FtpProxyRequestNeedProxyAndServerAuth) {
// The TestDelegate will by default quit the message loop on completion.
base::RunLoop().Run();
- EXPECT_TRUE(url_request->status().is_success());
+ EXPECT_THAT(request_delegate.request_status(), IsOk());
EXPECT_EQ(1, network_delegate()->completed_requests());
EXPECT_EQ(0, network_delegate()->error_count());
EXPECT_TRUE(request_delegate.auth_required_called());
@@ -637,7 +645,7 @@ TEST_F(URLRequestFtpJobTest, FtpProxyRequestDoNotSaveCookies) {
// The TestDelegate will by default quit the message loop on completion.
base::RunLoop().Run();
- EXPECT_TRUE(url_request->status().is_success());
+ EXPECT_THAT(request_delegate.request_status(), IsOk());
EXPECT_EQ(1, network_delegate()->completed_requests());
EXPECT_EQ(0, network_delegate()->error_count());
@@ -673,7 +681,7 @@ TEST_F(URLRequestFtpJobTest, FtpProxyRequestDoNotFollowRedirects) {
EXPECT_EQ(1, network_delegate()->completed_requests());
EXPECT_EQ(1, network_delegate()->error_count());
EXPECT_FALSE(url_request->status().is_success());
- EXPECT_EQ(ERR_UNSAFE_REDIRECT, url_request->status().error());
+ EXPECT_THAT(url_request->status().error(), IsError(ERR_UNSAFE_REDIRECT));
}
// We should re-use socket for requests using the same scheme, host, and port.
@@ -709,8 +717,9 @@ TEST_F(URLRequestFtpJobTest, FtpProxyRequestReuseSocket) {
base::RunLoop().Run();
EXPECT_TRUE(url_request1->status().is_success());
- EXPECT_TRUE(url_request1->proxy_server().Equals(
- HostPortPair::FromString("localhost:80")));
+ EXPECT_EQ(ProxyServer(ProxyServer::SCHEME_HTTP,
+ HostPortPair::FromString("localhost:80")),
+ url_request1->proxy_server());
EXPECT_EQ(1, network_delegate()->completed_requests());
EXPECT_EQ(0, network_delegate()->error_count());
EXPECT_FALSE(request_delegate1.auth_required_called());
diff --git a/chromium/net/url_request/url_request_fuzzer.cc b/chromium/net/url_request/url_request_fuzzer.cc
index db9cdfa86d5..a4d7b6a3a30 100644
--- a/chromium/net/url_request/url_request_fuzzer.cc
+++ b/chromium/net/url_request/url_request_fuzzer.cc
@@ -10,7 +10,7 @@
#include <memory>
#include "base/run_loop.h"
-#include "net/base/fuzzed_data_provider.h"
+#include "base/test/fuzzed_data_provider.h"
#include "net/base/request_priority.h"
#include "net/socket/fuzzed_socket_factory.h"
#include "net/url_request/url_request.h"
@@ -26,7 +26,7 @@
// QUIC, DNS failures (they all currently resolve to localhost), IPv6 DNS
// results, URLs with IPs instead of hostnames (v4 and v6), etc.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- net::FuzzedDataProvider data_provider(data, size);
+ base::FuzzedDataProvider data_provider(data, size);
net::TestURLRequestContext url_request_context(true);
net::FuzzedSocketFactory fuzzed_socket_factory(&data_provider);
url_request_context.set_client_socket_factory(&fuzzed_socket_factory);
diff --git a/chromium/net/url_request/url_request_http_job.cc b/chromium/net/url_request/url_request_http_job.cc
index 0fdeac11ac6..da2b27b27c9 100644
--- a/chromium/net/url_request/url_request_http_job.cc
+++ b/chromium/net/url_request/url_request_http_job.cc
@@ -41,6 +41,8 @@
#include "net/http/http_transaction.h"
#include "net/http/http_transaction_factory.h"
#include "net/http/http_util.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/nqe/network_quality_estimator.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_retry_info.h"
@@ -50,7 +52,6 @@
#include "net/ssl/ssl_config_service.h"
#include "net/url_request/http_user_agent_settings.h"
#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_backoff_manager.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_error_job.h"
#include "net/url_request/url_request_job_factory.h"
@@ -194,14 +195,14 @@ class URLRequestHttpJob::HttpFilterContext : public FilterContext {
int GetResponseCode() const override;
const URLRequestContext* GetURLRequestContext() const override;
void RecordPacketStats(StatisticSelector statistic) const override;
- const BoundNetLog& GetNetLog() const override;
+ const NetLogWithSource& GetNetLog() const override;
private:
URLRequestHttpJob* job_;
// URLRequestHttpJob may be detached from URLRequest, but we still need to
// return something.
- BoundNetLog dummy_log_;
+ NetLogWithSource dummy_log_;
DISALLOW_COPY_AND_ASSIGN(HttpFilterContext);
};
@@ -257,7 +258,8 @@ void URLRequestHttpJob::HttpFilterContext::RecordPacketStats(
job_->RecordPacketStats(statistic);
}
-const BoundNetLog& URLRequestHttpJob::HttpFilterContext::GetNetLog() const {
+const NetLogWithSource& URLRequestHttpJob::HttpFilterContext::GetNetLog()
+ const {
return job_->request() ? job_->request()->net_log() : dummy_log_;
}
@@ -316,7 +318,6 @@ URLRequestHttpJob::URLRequestHttpJob(
base::Unretained(this))),
awaiting_callback_(false),
http_user_agent_settings_(http_user_agent_settings),
- backoff_manager_(request->context()->backoff_manager()),
total_received_bytes_from_previous_transactions_(0),
total_sent_bytes_from_previous_transactions_(0),
weak_factory_(this) {
@@ -425,24 +426,6 @@ void URLRequestHttpJob::NotifyBeforeSendHeadersCallback(
}
}
-void URLRequestHttpJob::NotifyBeforeNetworkStart(bool* defer) {
- if (!request_)
- return;
- if (backoff_manager_) {
- if ((request_->load_flags() & LOAD_MAYBE_USER_GESTURE) == 0 &&
- backoff_manager_->ShouldRejectRequest(request()->url(),
- request()->request_time())) {
- *defer = true;
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&URLRequestHttpJob::OnStartCompleted,
- weak_factory_.GetWeakPtr(), ERR_TEMPORARY_BACKOFF));
- return;
- }
- }
- URLRequestJob::NotifyBeforeNetworkStart(defer);
-}
-
void URLRequestHttpJob::NotifyHeadersComplete() {
DCHECK(!response_info_);
@@ -455,9 +438,6 @@ void URLRequestHttpJob::NotifyHeadersComplete() {
if (!is_cached_content_ && throttling_entry_.get())
throttling_entry_->UpdateWithResponse(GetResponseCode());
- if (!is_cached_content_)
- ProcessBackoffHeader();
-
// The ordering of these calls is not important.
ProcessStrictTransportSecurityHeader();
ProcessPublicKeyPinsHeader();
@@ -470,7 +450,7 @@ void URLRequestHttpJob::NotifyHeadersComplete() {
if (rv != SDCH_OK) {
SdchManager::SdchErrorRecovery(rv);
request()->net_log().AddEvent(
- NetLog::TYPE_SDCH_DECODING_ERROR,
+ NetLogEventType::SDCH_DECODING_ERROR,
base::Bind(&NetLogSdchResourceProblemCallback, rv));
} else {
const std::string name = "Get-Dictionary";
@@ -495,7 +475,7 @@ void URLRequestHttpJob::NotifyHeadersComplete() {
if (rv != SDCH_OK) {
SdchManager::SdchErrorRecovery(rv);
request_->net_log().AddEvent(
- NetLog::TYPE_SDCH_DICTIONARY_ERROR,
+ NetLogEventType::SDCH_DICTIONARY_ERROR,
base::Bind(&NetLogSdchDictionaryFetchProblemCallback, rv,
sdch_dictionary_url, false));
}
@@ -591,7 +571,7 @@ void URLRequestHttpJob::MaybeStartTransactionInternal(int result) {
StartTransactionInternal();
} else {
std::string source("delegate");
- request_->net_log().AddEvent(NetLog::TYPE_CANCELLED,
+ request_->net_log().AddEvent(NetLogEventType::CANCELLED,
NetLog::StringCallback("source", &source));
NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
}
@@ -640,9 +620,6 @@ void URLRequestHttpJob::StartTransactionInternal() {
}
if (rv == OK) {
- transaction_->SetBeforeNetworkStartCallback(
- base::Bind(&URLRequestHttpJob::NotifyBeforeNetworkStart,
- base::Unretained(this)));
transaction_->SetBeforeHeadersSentCallback(
base::Bind(&URLRequestHttpJob::NotifyBeforeSendHeadersCallback,
base::Unretained(this)));
@@ -692,7 +669,7 @@ void URLRequestHttpJob::AddExtraHeaders() {
advertise_sdch = false;
SdchManager::SdchErrorRecovery(rv);
request()->net_log().AddEvent(
- NetLog::TYPE_SDCH_DECODING_ERROR,
+ NetLogEventType::SDCH_DECODING_ERROR,
base::Bind(&NetLogSdchResourceProblemCallback, rv));
}
}
@@ -722,8 +699,12 @@ void URLRequestHttpJob::AddExtraHeaders() {
// Advertise "br" encoding only if transferred data is opaque to proxy.
bool advertise_brotli = false;
- if (request()->context()->enable_brotli())
- advertise_brotli = request()->url().SchemeIsCryptographic();
+ if (request()->context()->enable_brotli()) {
+ if (request()->url().SchemeIsCryptographic() ||
+ IsLocalhost(request()->url().HostNoBrackets())) {
+ advertise_brotli = true;
+ }
+ }
// Supply Accept-Encoding headers first so that it is more likely that they
// will be in the first transmitted packet. This can sometimes make it
@@ -841,7 +822,7 @@ void URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete(int result) {
if (result != OK) {
std::string source("delegate");
- request_->net_log().AddEvent(NetLog::TYPE_CANCELLED,
+ request_->net_log().AddEvent(NetLogEventType::CANCELLED,
NetLog::StringCallback("source", &source));
NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
return;
@@ -891,26 +872,6 @@ void URLRequestHttpJob::FetchResponseCookies(
}
}
-void URLRequestHttpJob::ProcessBackoffHeader() {
- DCHECK(response_info_);
-
- if (!backoff_manager_)
- return;
-
- TransportSecurityState* security_state =
- request_->context()->transport_security_state();
- const SSLInfo& ssl_info = response_info_->ssl_info;
-
- // Only accept Backoff headers on HTTPS connections that have no
- // certificate errors.
- if (!ssl_info.is_valid() || IsCertStatusError(ssl_info.cert_status) ||
- !security_state)
- return;
-
- backoff_manager_->UpdateWithResponse(request()->url(), GetResponseHeaders(),
- base::Time::Now());
-}
-
// NOTE: |ProcessStrictTransportSecurityHeader| and
// |ProcessPublicKeyPinsHeader| have very similar structures, by design.
void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() {
@@ -1035,9 +996,9 @@ void URLRequestHttpJob::OnStartCompleted(int result) {
awaiting_callback_ = true;
} else {
std::string source("delegate");
- request_->net_log().AddEvent(NetLog::TYPE_CANCELLED,
- NetLog::StringCallback("source",
- &source));
+ request_->net_log().AddEvent(
+ NetLogEventType::CANCELLED,
+ NetLog::StringCallback("source", &source));
OnCallToDelegateComplete();
NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, error));
}
@@ -1129,11 +1090,6 @@ LoadState URLRequestHttpJob::GetLoadState() const {
transaction_->GetLoadState() : LOAD_STATE_IDLE;
}
-UploadProgress URLRequestHttpJob::GetUploadProgress() const {
- return transaction_.get() ?
- transaction_->GetUploadProgress() : UploadProgress();
-}
-
bool URLRequestHttpJob::GetMimeType(std::string* mime_type) const {
DCHECK(transaction_.get());
@@ -1373,11 +1329,6 @@ void URLRequestHttpJob::ContinueDespiteLastError() {
weak_factory_.GetWeakPtr(), rv));
}
-void URLRequestHttpJob::ResumeNetworkStart() {
- DCHECK(transaction_.get());
- transaction_->ResumeNetworkStart();
-}
-
bool URLRequestHttpJob::ShouldFixMismatchedContentLength(int rv) const {
// Some servers send the body compressed, but specify the content length as
// the uncompressed size. Although this violates the HTTP spec we want to
@@ -1388,8 +1339,7 @@ bool URLRequestHttpJob::ShouldFixMismatchedContentLength(int rv) const {
if (request_ && request_->response_headers()) {
int64_t expected_length =
request_->response_headers()->GetContentLength();
- VLOG(1) << __FUNCTION__ << "() "
- << "\"" << request_->url().spec() << "\""
+ VLOG(1) << __func__ << "() \"" << request_->url().spec() << "\""
<< " content-length = " << expected_length
<< " pre total = " << prefilter_bytes_read()
<< " post total = " << postfilter_bytes_read();
@@ -1490,6 +1440,10 @@ void URLRequestHttpJob::RecordTimer() {
request_creation_time_ = base::Time();
UMA_HISTOGRAM_MEDIUM_TIMES("Net.HttpTimeToFirstByte", to_start);
+ if (request_info_.upload_data_stream &&
+ request_info_.upload_data_stream->size() > 1024 * 1024) {
+ UMA_HISTOGRAM_MEDIUM_TIMES("Net.HttpTimeToFirstByte.LargeUpload", to_start);
+ }
}
void URLRequestHttpJob::ResetTimer() {
@@ -1625,7 +1579,8 @@ void URLRequestHttpJob::DoneWithRequest(CompletionCause reason) {
NetworkQualityEstimator* network_quality_estimator =
request()->context()->network_quality_estimator();
if (network_quality_estimator)
- network_quality_estimator->NotifyRequestCompleted(*request());
+ network_quality_estimator->NotifyRequestCompleted(
+ *request(), request_->status().error());
}
RecordPerfHistograms(reason);
diff --git a/chromium/net/url_request/url_request_http_job.h b/chromium/net/url_request/url_request_http_job.h
index 212ab51c3bc..f047e447742 100644
--- a/chromium/net/url_request/url_request_http_job.h
+++ b/chromium/net/url_request/url_request_http_job.h
@@ -25,7 +25,6 @@
#include "net/filter/filter.h"
#include "net/http/http_request_info.h"
#include "net/socket/connection_attempts.h"
-#include "net/url_request/url_request_backoff_manager.h"
#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_throttler_entry_interface.h"
@@ -76,9 +75,6 @@ class NET_EXPORT_PRIVATE URLRequestHttpJob : public URLRequestJob {
class HttpFilterContext;
- // Shadows URLRequestJob's version of this method.
- void NotifyBeforeNetworkStart(bool* defer);
-
// Shadows URLRequestJob's version of this method so we can grab cookies.
void NotifyHeadersComplete();
@@ -117,7 +113,6 @@ class NET_EXPORT_PRIVATE URLRequestHttpJob : public URLRequestJob {
void SetUpload(UploadDataStream* upload) override;
void SetExtraRequestHeaders(const HttpRequestHeaders& headers) override;
LoadState GetLoadState() const override;
- UploadProgress GetUploadProgress() const override;
bool GetMimeType(std::string* mime_type) const override;
bool GetCharset(std::string* charset) override;
void GetResponseInfo(HttpResponseInfo* info) override;
@@ -135,7 +130,6 @@ class NET_EXPORT_PRIVATE URLRequestHttpJob : public URLRequestJob {
void ContinueWithCertificate(X509Certificate* client_cert,
SSLPrivateKey* client_private_key) override;
void ContinueDespiteLastError() override;
- void ResumeNetworkStart() override;
int ReadRawData(IOBuffer* buf, int buf_size) override;
void StopCaching() override;
bool GetFullRequestHeaders(HttpRequestHeaders* headers) const override;
@@ -269,8 +263,6 @@ class NET_EXPORT_PRIVATE URLRequestHttpJob : public URLRequestJob {
const HttpUserAgentSettings* http_user_agent_settings_;
- URLRequestBackoffManager* backoff_manager_;
-
// Keeps track of total received bytes over the network from transactions used
// by this job that have already been destroyed.
int64_t total_received_bytes_from_previous_transactions_;
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 5165382eb3b..4d93df71ae2 100644
--- a/chromium/net/url_request/url_request_http_job_unittest.cc
+++ b/chromium/net/url_request/url_request_http_job_unittest.cc
@@ -20,11 +20,13 @@
#include "net/cookies/cookie_store_test_helpers.h"
#include "net/http/http_transaction_factory.h"
#include "net/http/http_transaction_test_util.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/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_job_factory_impl.h"
@@ -36,6 +38,9 @@
#include "url/gurl.h"
#include "url/url_constants.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -123,13 +128,11 @@ class URLRequestHttpJobWithMockSocketsTest : public ::testing::Test {
: context_(new TestURLRequestContext(true)) {
context_->set_client_socket_factory(&socket_factory_);
context_->set_network_delegate(&network_delegate_);
- context_->set_backoff_manager(&manager_);
context_->Init();
}
MockClientSocketFactory socket_factory_;
TestNetworkDelegate network_delegate_;
- URLRequestBackoffManager manager_;
std::unique_ptr<TestURLRequestContext> context_;
};
@@ -160,7 +163,7 @@ TEST_F(URLRequestHttpJobWithMockSocketsTest,
ASSERT_TRUE(request->is_pending());
base::RunLoop().Run();
- EXPECT_TRUE(request->status().is_success());
+ EXPECT_THAT(delegate.request_status(), IsOk());
EXPECT_EQ(12, request->received_response_content_length());
EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
request->GetTotalSentBytes());
@@ -189,7 +192,7 @@ TEST_F(URLRequestHttpJobWithMockSocketsTest,
ASSERT_TRUE(request->is_pending());
base::RunLoop().Run();
- EXPECT_TRUE(request->status().is_success());
+ EXPECT_THAT(delegate.request_status(), IsOk());
EXPECT_EQ(12, request->received_response_content_length());
EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
request->GetTotalSentBytes());
@@ -220,7 +223,7 @@ TEST_F(URLRequestHttpJobWithMockSocketsTest, TestContentLengthFailedRequest) {
ASSERT_TRUE(request->is_pending());
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::FAILED, request->status().status());
+ EXPECT_THAT(delegate.request_status(), IsError(ERR_FAILED));
EXPECT_EQ(12, request->received_response_content_length());
EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
request->GetTotalSentBytes());
@@ -252,7 +255,7 @@ TEST_F(URLRequestHttpJobWithMockSocketsTest,
request->Start();
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(URLRequestStatus::CANCELED, request->status().status());
+ EXPECT_THAT(delegate.request_status(), IsError(ERR_ABORTED));
EXPECT_EQ(12, request->received_response_content_length());
EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
request->GetTotalSentBytes());
@@ -265,6 +268,131 @@ TEST_F(URLRequestHttpJobWithMockSocketsTest,
}
TEST_F(URLRequestHttpJobWithMockSocketsTest,
+ TestRawHeaderSizeSuccessfullRequest) {
+ MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
+
+ const std::string& response_header =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Length: 12\r\n\r\n";
+ const std::string& content_data = "Test Content";
+
+ MockRead reads[] = {MockRead(response_header.c_str()),
+ MockRead(content_data.c_str()),
+ MockRead(net::SYNCHRONOUS, net::OK)};
+
+ StaticSocketDataProvider socket_data(reads, arraysize(reads), writes,
+ arraysize(writes));
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ TestDelegate delegate;
+ std::unique_ptr<URLRequest> request = context_->CreateRequest(
+ GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate);
+
+ request->Start();
+ ASSERT_TRUE(request->is_pending());
+ base::RunLoop().Run();
+
+ EXPECT_EQ(net::OK, request->status().error());
+ EXPECT_EQ(static_cast<int>(content_data.size()),
+ request->received_response_content_length());
+ EXPECT_EQ(static_cast<int>(response_header.size()),
+ request->raw_header_size());
+ EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
+ request->GetTotalReceivedBytes());
+}
+
+TEST_F(URLRequestHttpJobWithMockSocketsTest,
+ TestRawHeaderSizeSuccessfull100ContinueRequest) {
+ MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
+
+ const std::string& continue_header = "HTTP/1.1 100 Continue\r\n\r\n";
+ const std::string& response_header =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Length: 12\r\n\r\n";
+ const std::string& content_data = "Test Content";
+
+ MockRead reads[] = {
+ MockRead(continue_header.c_str()), MockRead(response_header.c_str()),
+ MockRead(content_data.c_str()), MockRead(net::SYNCHRONOUS, net::OK)};
+
+ StaticSocketDataProvider socket_data(reads, arraysize(reads), writes,
+ arraysize(writes));
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ TestDelegate delegate;
+ std::unique_ptr<URLRequest> request = context_->CreateRequest(
+ GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate);
+
+ request->Start();
+ ASSERT_TRUE(request->is_pending());
+ base::RunLoop().Run();
+
+ EXPECT_EQ(net::OK, request->status().error());
+ EXPECT_EQ(static_cast<int>(content_data.size()),
+ request->received_response_content_length());
+ EXPECT_EQ(static_cast<int>(continue_header.size() + response_header.size()),
+ request->raw_header_size());
+ EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
+ request->GetTotalReceivedBytes());
+}
+
+TEST_F(URLRequestHttpJobWithMockSocketsTest,
+ TestRawHeaderSizeFailureTruncatedHeaders) {
+ MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
+ MockRead reads[] = {MockRead("HTTP/1.0 200 OK\r\n"
+ "Content-Len"),
+ MockRead(net::SYNCHRONOUS, net::OK)};
+
+ StaticSocketDataProvider socket_data(reads, arraysize(reads), writes,
+ arraysize(writes));
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ TestDelegate delegate;
+ std::unique_ptr<URLRequest> request = context_->CreateRequest(
+ GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate);
+
+ delegate.set_cancel_in_response_started(true);
+ request->Start();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(ERR_ABORTED, request->status().error());
+ EXPECT_EQ(0, request->received_response_content_length());
+ EXPECT_EQ(28, request->raw_header_size());
+ EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
+ request->GetTotalReceivedBytes());
+}
+
+TEST_F(URLRequestHttpJobWithMockSocketsTest,
+ TestRawHeaderSizeSuccessfullContinuiousRead) {
+ MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
+ const std::string& header_data =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Length: 12\r\n\r\n";
+ const std::string& content_data = "Test Content";
+ std::string single_read_content = header_data;
+ single_read_content.append(content_data);
+ MockRead reads[] = {MockRead(single_read_content.c_str())};
+
+ StaticSocketDataProvider socket_data(reads, arraysize(reads), writes,
+ arraysize(writes));
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ TestDelegate delegate;
+ std::unique_ptr<URLRequest> request = context_->CreateRequest(
+ GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate);
+
+ request->Start();
+ base::RunLoop().Run();
+
+ EXPECT_EQ(net::OK, request->status().error());
+ EXPECT_EQ(static_cast<int>(content_data.size()),
+ request->received_response_content_length());
+ EXPECT_EQ(static_cast<int>(header_data.size()), request->raw_header_size());
+ EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
+ request->GetTotalReceivedBytes());
+}
+
+TEST_F(URLRequestHttpJobWithMockSocketsTest,
TestNetworkBytesRedirectedRequest) {
MockWrite redirect_writes[] = {
MockWrite("GET / HTTP/1.1\r\n"
@@ -300,7 +428,7 @@ TEST_F(URLRequestHttpJobWithMockSocketsTest,
ASSERT_TRUE(request->is_pending());
base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(request->status().is_success());
+ EXPECT_THAT(delegate.request_status(), IsOk());
EXPECT_EQ(12, request->received_response_content_length());
// Should not include the redirect.
EXPECT_EQ(CountWriteBytes(final_writes, arraysize(final_writes)),
@@ -332,7 +460,7 @@ TEST_F(URLRequestHttpJobWithMockSocketsTest,
request->Start();
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(URLRequestStatus::CANCELED, request->status().status());
+ EXPECT_THAT(delegate.request_status(), IsError(ERR_ABORTED));
EXPECT_EQ(0, request->received_response_content_length());
EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
request->GetTotalSentBytes());
@@ -357,197 +485,13 @@ TEST_F(URLRequestHttpJobWithMockSocketsTest,
request->Cancel();
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(URLRequestStatus::CANCELED, request->status().status());
+ EXPECT_THAT(delegate.request_status(), IsError(ERR_ABORTED));
EXPECT_EQ(0, request->received_response_content_length());
EXPECT_EQ(0, request->GetTotalSentBytes());
EXPECT_EQ(0, request->GetTotalReceivedBytes());
EXPECT_EQ(0, network_delegate_.total_network_bytes_received());
}
-TEST_F(URLRequestHttpJobWithMockSocketsTest, BackoffHeader) {
- MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
- MockRead reads[] = {MockRead(
- "HTTP/1.1 200 OK\r\n"
- "Backoff: 3600\r\n"
- "Content-Length: 9\r\n\r\n"),
- MockRead("test.html")};
-
- net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
- ssl_socket_data_provider.SetNextProto(kProtoHTTP11);
- ssl_socket_data_provider.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
- socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);
-
- StaticSocketDataProvider socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- TestDelegate delegate1;
- std::unique_ptr<URLRequest> request1 = context_->CreateRequest(
- GURL("https://www.example.com"), DEFAULT_PRIORITY, &delegate1);
-
- request1->Start();
- ASSERT_TRUE(request1->is_pending());
- base::RunLoop().Run();
-
- EXPECT_TRUE(request1->status().is_success());
- EXPECT_EQ("test.html", delegate1.data_received());
- EXPECT_EQ(1, delegate1.received_before_network_start_count());
- EXPECT_EQ(1, manager_.GetNumberOfEntriesForTests());
-
- // Issue another request, and backoff logic should apply.
- TestDelegate delegate2;
- std::unique_ptr<URLRequest> request2 = context_->CreateRequest(
- GURL("https://www.example.com"), DEFAULT_PRIORITY, &delegate2);
-
- request2->Start();
- ASSERT_TRUE(request2->is_pending());
- base::RunLoop().Run();
-
- EXPECT_FALSE(request2->status().is_success());
- EXPECT_EQ(ERR_TEMPORARY_BACKOFF, request2->status().error());
- EXPECT_EQ(0, delegate2.received_before_network_start_count());
-}
-
-// Tests that a user-initiated request is not throttled.
-TEST_F(URLRequestHttpJobWithMockSocketsTest, BackoffHeaderUserGesture) {
- MockWrite writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Connection: keep-alive\r\n"
- "User-Agent:\r\n"
- "Accept-Encoding: gzip, deflate\r\n"
- "Accept-Language: en-us,fr\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Connection: keep-alive\r\n"
- "User-Agent:\r\n"
- "Accept-Encoding: gzip, deflate\r\n"
- "Accept-Language: en-us,fr\r\n\r\n"),
- };
- MockRead reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Backoff: 3600\r\n"
- "Content-Length: 9\r\n\r\n"),
- MockRead("test.html"), MockRead("HTTP/1.1 200 OK\r\n"
- "Backoff: 3600\r\n"
- "Content-Length: 9\r\n\r\n"),
- MockRead("test.html"),
- };
-
- net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
- ssl_socket_data_provider.SetNextProto(kProtoHTTP11);
- ssl_socket_data_provider.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
- socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);
-
- StaticSocketDataProvider socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- TestDelegate delegate1;
- std::unique_ptr<URLRequest> request1 = context_->CreateRequest(
- GURL("https://www.example.com"), DEFAULT_PRIORITY, &delegate1);
-
- request1->Start();
- ASSERT_TRUE(request1->is_pending());
- base::RunLoop().Run();
-
- EXPECT_TRUE(request1->status().is_success());
- EXPECT_EQ("test.html", delegate1.data_received());
- EXPECT_EQ(1, delegate1.received_before_network_start_count());
- EXPECT_EQ(1, manager_.GetNumberOfEntriesForTests());
-
- // Issue a user-initiated request, backoff logic should not apply.
- TestDelegate delegate2;
- std::unique_ptr<URLRequest> request2 = context_->CreateRequest(
- GURL("https://www.example.com"), DEFAULT_PRIORITY, &delegate2);
- request2->SetLoadFlags(request2->load_flags() | LOAD_MAYBE_USER_GESTURE);
-
- request2->Start();
- ASSERT_TRUE(request2->is_pending());
- base::RunLoop().Run();
-
- EXPECT_NE(0, request2->load_flags() & LOAD_MAYBE_USER_GESTURE);
- EXPECT_TRUE(request2->status().is_success());
- EXPECT_EQ("test.html", delegate2.data_received());
- EXPECT_EQ(1, delegate2.received_before_network_start_count());
- EXPECT_EQ(1, manager_.GetNumberOfEntriesForTests());
-}
-
-TEST_F(URLRequestHttpJobWithMockSocketsTest, BackoffHeaderNotSecure) {
- MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
- MockRead reads[] = {MockRead(
- "HTTP/1.1 200 OK\r\n"
- "Backoff: 3600\r\n"
- "Content-Length: 9\r\n\r\n"),
- MockRead("test.html")};
-
- StaticSocketDataProvider socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- TestDelegate delegate;
- std::unique_ptr<URLRequest> request = context_->CreateRequest(
- GURL("http://www.example.com"), DEFAULT_PRIORITY, &delegate);
-
- request->Start();
- ASSERT_TRUE(request->is_pending());
- base::RunLoop().Run();
-
- EXPECT_TRUE(request->status().is_success());
- EXPECT_EQ("test.html", delegate.data_received());
- EXPECT_EQ(1, delegate.received_before_network_start_count());
- // Backoff logic does not apply to plain HTTP request.
- EXPECT_EQ(0, manager_.GetNumberOfEntriesForTests());
-}
-
-TEST_F(URLRequestHttpJobWithMockSocketsTest, BackoffHeaderCachedResponse) {
- MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)};
- MockRead reads[] = {MockRead(
- "HTTP/1.1 200 OK\r\n"
- "Backoff: 3600\r\n"
- "Cache-Control: max-age=120\r\n"
- "Content-Length: 9\r\n\r\n"),
- MockRead("test.html")};
-
- net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
- ssl_socket_data_provider.SetNextProto(kProtoHTTP11);
- ssl_socket_data_provider.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
- socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);
-
- StaticSocketDataProvider socket_data(reads, arraysize(reads), writes,
- arraysize(writes));
- socket_factory_.AddSocketDataProvider(&socket_data);
-
- TestDelegate delegate1;
- std::unique_ptr<URLRequest> request1 = context_->CreateRequest(
- GURL("https://www.example.com"), DEFAULT_PRIORITY, &delegate1);
-
- request1->Start();
- ASSERT_TRUE(request1->is_pending());
- base::RunLoop().Run();
-
- EXPECT_TRUE(request1->status().is_success());
- EXPECT_EQ("test.html", delegate1.data_received());
- EXPECT_EQ(1, delegate1.received_before_network_start_count());
- EXPECT_EQ(1, manager_.GetNumberOfEntriesForTests());
-
- // Backoff logic does not apply to a second request, since it is fetched
- // from cache.
- TestDelegate delegate2;
- std::unique_ptr<URLRequest> request2 = context_->CreateRequest(
- GURL("https://www.example.com"), DEFAULT_PRIORITY, &delegate2);
-
- request2->Start();
- ASSERT_TRUE(request2->is_pending());
- base::RunLoop().Run();
- EXPECT_TRUE(request2->was_cached());
- EXPECT_TRUE(request2->status().is_success());
- EXPECT_EQ(0, delegate2.received_before_network_start_count());
-}
-
TEST_F(URLRequestHttpJobTest, TestCancelWhileReadingCookies) {
DelayedCookieMonster cookie_monster;
TestURLRequestContext context(true);
@@ -562,8 +506,7 @@ TEST_F(URLRequestHttpJobTest, TestCancelWhileReadingCookies) {
request->Cancel();
base::RunLoop().Run();
- DCHECK_EQ(0, delegate.received_before_network_start_count());
- EXPECT_EQ(URLRequestStatus::CANCELED, request->status().status());
+ EXPECT_THAT(delegate.request_status(), IsError(ERR_ABORTED));
}
// Make sure that SetPriority actually sets the URLRequestHttpJob's
@@ -672,7 +615,7 @@ TEST_F(URLRequestHttpJobTest, HSTSInternalRedirectTest) {
net_log_.GetEntries(&entries);
int redirects = 0;
for (const auto& entry : entries) {
- if (entry.type == net::NetLog::TYPE_URL_REQUEST_REDIRECT_JOB) {
+ if (entry.type == net::NetLogEventType::URL_REQUEST_REDIRECT_JOB) {
redirects++;
std::string value;
EXPECT_TRUE(entry.GetStringValue("reason", &value));
@@ -750,7 +693,7 @@ TEST_F(URLRequestHttpJobWithSdchSupportTest, GetDictionary) {
request->Start();
base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(request->status().is_success());
+ EXPECT_THAT(delegate.request_status(), IsOk());
// Second response should be from cache without notification of SdchObserver
TestDelegate delegate2;
@@ -759,7 +702,7 @@ TEST_F(URLRequestHttpJobWithSdchSupportTest, GetDictionary) {
request2->Start();
base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(request->status().is_success());
+ EXPECT_THAT(delegate2.request_status(), IsOk());
// Cleanup manager.
sdch_manager.RemoveObserver(&sdch_observer);
@@ -796,7 +739,7 @@ TEST_F(URLRequestHttpJobWithBrotliSupportTest, NoBrotliAdvertisementOverHttp) {
request->Start();
base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(request->status().is_success());
+ EXPECT_THAT(delegate.request_status(), IsOk());
EXPECT_EQ(12, request->received_response_content_length());
EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
request->GetTotalSentBytes());
@@ -806,7 +749,7 @@ TEST_F(URLRequestHttpJobWithBrotliSupportTest, NoBrotliAdvertisementOverHttp) {
TEST_F(URLRequestHttpJobWithBrotliSupportTest, BrotliAdvertisement) {
net::SSLSocketDataProvider ssl_socket_data_provider(net::ASYNC, net::OK);
- ssl_socket_data_provider.SetNextProto(kProtoHTTP11);
+ ssl_socket_data_provider.next_proto = kProtoHTTP11;
ssl_socket_data_provider.cert =
ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
socket_factory_.AddSSLSocketDataProvider(&ssl_socket_data_provider);
@@ -831,7 +774,7 @@ TEST_F(URLRequestHttpJobWithBrotliSupportTest, BrotliAdvertisement) {
request->Start();
base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(request->status().is_success());
+ EXPECT_THAT(delegate.request_status(), IsOk());
EXPECT_EQ(12, request->received_response_content_length());
EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
request->GetTotalSentBytes());
@@ -907,7 +850,7 @@ class FakeWebSocketHandshakeStream : public WebSocketHandshakeStreamBase {
// Fake implementation of HttpStreamBase methods.
int InitializeStream(const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback) override {
initialize_stream_was_called_ = true;
return ERR_IO_PENDING;
@@ -951,8 +894,9 @@ class FakeWebSocketHandshakeStream : public WebSocketHandshakeStreamBase {
bool GetRemoteEndpoint(IPEndPoint* endpoint) override { return false; }
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) override {
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) override {
ADD_FAILURE();
return ERR_NOT_IMPLEMENTED;
}
@@ -963,10 +907,6 @@ class FakeWebSocketHandshakeStream : public WebSocketHandshakeStreamBase {
void SetPriority(RequestPriority priority) override {}
- UploadProgress GetUploadProgress() const override {
- return UploadProgress();
- }
-
HttpStream* RenewStreamForAuth() override { return nullptr; }
// Fake implementation of WebSocketHandshakeStreamBase method(s)
@@ -981,8 +921,7 @@ class FakeWebSocketHandshakeStream : public WebSocketHandshakeStreamBase {
TEST_F(URLRequestHttpJobWebSocketTest, RejectedWithoutCreateHelper) {
req_->Start();
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(URLRequestStatus::FAILED, req_->status().status());
- EXPECT_EQ(ERR_DISALLOWED_URL_SCHEME, req_->status().error());
+ EXPECT_THAT(delegate_.request_status(), IsError(ERR_DISALLOWED_URL_SCHEME));
}
TEST_F(URLRequestHttpJobWebSocketTest, CreateHelperPassedThrough) {
@@ -999,7 +938,7 @@ TEST_F(URLRequestHttpJobWebSocketTest, CreateHelperPassedThrough) {
req_->SetLoadFlags(LOAD_DISABLE_CACHE);
req_->Start();
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(URLRequestStatus::IO_PENDING, req_->status().status());
+ EXPECT_THAT(delegate_.request_status(), IsError(ERR_IO_PENDING));
EXPECT_TRUE(fake_handshake_stream->initialize_stream_was_called());
}
diff --git a/chromium/net/url_request/url_request_job.cc b/chromium/net/url_request/url_request_job.cc
index dc42edf860c..f9df57010d3 100644
--- a/chromium/net/url_request/url_request_job.cc
+++ b/chromium/net/url_request/url_request_job.cc
@@ -27,7 +27,12 @@
#include "net/base/network_delegate.h"
#include "net/filter/filter.h"
#include "net/http/http_response_headers.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/nqe/network_quality_estimator.h"
+#include "net/proxy/proxy_server.h"
#include "net/url_request/url_request_context.h"
namespace net {
@@ -79,14 +84,12 @@ URLRequest::ReferrerPolicy ProcessReferrerPolicyHeaderOnRedirect(
base::SPLIT_WANT_NONEMPTY);
for (const auto& token : policy_tokens) {
- if (base::CompareCaseInsensitiveASCII(token, "never") == 0 ||
- base::CompareCaseInsensitiveASCII(token, "no-referrer") == 0) {
+ if (base::CompareCaseInsensitiveASCII(token, "no-referrer") == 0) {
new_policy = URLRequest::NO_REFERRER;
continue;
}
- if (base::CompareCaseInsensitiveASCII(token, "default") == 0 ||
- base::CompareCaseInsensitiveASCII(token,
+ if (base::CompareCaseInsensitiveASCII(token,
"no-referrer-when-downgrade") == 0) {
new_policy =
URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
@@ -104,8 +107,7 @@ URLRequest::ReferrerPolicy ProcessReferrerPolicyHeaderOnRedirect(
continue;
}
- if (base::CompareCaseInsensitiveASCII(token, "always") == 0 ||
- base::CompareCaseInsensitiveASCII(token, "unsafe-url") == 0) {
+ if (base::CompareCaseInsensitiveASCII(token, "unsafe-url") == 0) {
new_policy = URLRequest::NEVER_CLEAR_REFERRER;
continue;
}
@@ -163,43 +165,42 @@ void URLRequestJob::Kill() {
// This function calls ReadRawData to get stream data. If a filter exists, it
// passes the data to the attached filter. It then returns the output from
// filter back to the caller.
-bool URLRequestJob::Read(IOBuffer* buf, int buf_size, int *bytes_read) {
+int URLRequestJob::Read(IOBuffer* buf, int buf_size) {
DCHECK_LT(buf_size, 1000000); // Sanity check.
DCHECK(buf);
- DCHECK(bytes_read);
DCHECK(!filtered_read_buffer_);
DCHECK_EQ(0, filtered_read_buffer_len_);
Error error = OK;
- *bytes_read = 0;
+ int bytes_read = 0;
// Skip Filter if not present.
if (!filter_) {
- error = ReadRawDataHelper(buf, buf_size, bytes_read);
+ error = ReadRawDataHelper(buf, buf_size, &bytes_read);
} else {
// Save the caller's buffers while we do IO
// in the filter's buffers.
filtered_read_buffer_ = buf;
filtered_read_buffer_len_ = buf_size;
- error = ReadFilteredData(bytes_read);
+ error = ReadFilteredData(&bytes_read);
// Synchronous EOF from the filter.
- if (error == OK && *bytes_read == 0)
+ if (error == OK && bytes_read == 0)
DoneReading();
}
- if (error == OK) {
- // If URLRequestJob read zero bytes, the job is at EOF.
- if (*bytes_read == 0)
- NotifyDone(URLRequestStatus());
- } else if (error == ERR_IO_PENDING) {
- SetStatus(URLRequestStatus::FromError(ERR_IO_PENDING));
- } else {
+ if (error == ERR_IO_PENDING)
+ return ERR_IO_PENDING;
+
+ if (error < 0) {
NotifyDone(URLRequestStatus::FromError(error));
- *bytes_read = -1;
+ return error;
}
- return error == OK;
+
+ if (bytes_read == 0)
+ NotifyDone(URLRequestStatus());
+ return bytes_read;
}
void URLRequestJob::StopCaching() {
@@ -223,10 +224,6 @@ LoadState URLRequestJob::GetLoadState() const {
return LOAD_STATE_IDLE;
}
-UploadProgress URLRequestJob::GetUploadProgress() const {
- return UploadProgress();
-}
-
bool URLRequestJob::GetCharset(std::string* charset) {
return false;
}
@@ -325,12 +322,6 @@ void URLRequestJob::FollowDeferredRedirect() {
FollowRedirect(redirect_info);
}
-void URLRequestJob::ResumeNetworkStart() {
- // This should only be called for HTTP Jobs, and implemented in the derived
- // class.
- NOTREACHED();
-}
-
bool URLRequestJob::GetMimeType(std::string* mime_type) const {
return false;
}
@@ -431,10 +422,6 @@ bool URLRequestJob::CanEnablePrivacyMode() const {
return request_->CanEnablePrivacyMode();
}
-void URLRequestJob::NotifyBeforeNetworkStart(bool* defer) {
- request_->NotifyBeforeNetworkStart(defer);
-}
-
void URLRequestJob::NotifyHeadersComplete() {
if (has_handled_response_)
return;
@@ -443,7 +430,6 @@ void URLRequestJob::NotifyHeadersComplete() {
// before the URLRequestJob was started. On error or cancellation, this
// method should not be called.
DCHECK(request_->status().is_io_pending());
- SetStatus(URLRequestStatus());
// Initialize to the current time, and let the subclass optionally override
// the time stamps if it has that information. The default request_time is
@@ -510,11 +496,11 @@ void URLRequestJob::NotifyHeadersComplete() {
base::StringToInt64(content_length, &expected_content_size_);
} else {
request_->net_log().AddEvent(
- NetLog::TYPE_URL_REQUEST_FILTERS_SET,
+ NetLogEventType::URL_REQUEST_FILTERS_SET,
base::Bind(&FiltersSetCallback, base::Unretained(filter_.get())));
}
- request_->NotifyResponseStarted();
+ request_->NotifyResponseStarted(URLRequestStatus());
// |this| may be destroyed at this point.
}
@@ -537,11 +523,6 @@ void URLRequestJob::ReadRawDataComplete(int result) {
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"475755 URLRequestJob::RawReadCompleted"));
- // TODO(darin): Bug 1004233. Re-enable this test once all of the chrome
- // unit_tests have been fixed to not trip this.
-#if 0
- DCHECK(!request_->status().is_io_pending());
-#endif
// The headers should be complete before reads complete
DCHECK(has_handled_response_);
@@ -569,38 +550,24 @@ void URLRequestJob::ReadRawDataComplete(int result) {
if (error == OK && !filter_bytes_read)
DoneReading();
- DVLOG(1) << __FUNCTION__ << "() "
- << "\"" << request_->url().spec() << "\""
+ DVLOG(1) << __func__ << "() \"" << request_->url().spec() << "\""
<< " pre bytes read = " << bytes_read
<< " pre total = " << prefilter_bytes_read_
<< " post total = " << postfilter_bytes_read_;
bytes_read = filter_bytes_read;
} else {
- DVLOG(1) << __FUNCTION__ << "() "
- << "\"" << request_->url().spec() << "\""
+ DVLOG(1) << __func__ << "() \"" << request_->url().spec() << "\""
<< " pre bytes read = " << bytes_read
<< " pre total = " << prefilter_bytes_read_
<< " post total = " << postfilter_bytes_read_;
}
- // Synchronize the URLRequest state machine with the URLRequestJob state
- // machine. If this read succeeded, either the request is at EOF and the
- // URLRequest state machine goes to 'finished', or it is not and the
- // URLRequest state machine goes to 'success'. If the read failed, the
- // URLRequest state machine goes directly to 'finished'. If filtered data is
- // pending, then there's nothing to do, since the status of the request is
- // already pending.
- //
- // Update the URLRequest's status first, so that NotifyReadCompleted has an
- // accurate view of the request.
- if (error == OK && bytes_read > 0) {
- SetStatus(URLRequestStatus());
- } else if (error != ERR_IO_PENDING) {
+ if (error == ERR_IO_PENDING)
+ return;
+
+ if (bytes_read <= 0)
NotifyDone(URLRequestStatus::FromError(error));
- }
- // NotifyReadCompleted should be called after SetStatus or NotifyDone updates
- // the status.
if (error == OK)
request_->NotifyReadCompleted(bytes_read);
@@ -616,8 +583,7 @@ void URLRequestJob::NotifyStartError(const URLRequestStatus &status) {
// error case.
GetResponseInfo(&request_->response_info_);
- SetStatus(status);
- request_->NotifyResponseStarted();
+ request_->NotifyResponseStarted(status);
// |this| may have been deleted here.
}
@@ -639,10 +605,9 @@ void URLRequestJob::NotifyDone(const URLRequestStatus &status) {
// enforce this, only set the status if the job is so far
// successful.
if (request_->status().is_success()) {
- if (status.status() == URLRequestStatus::FAILED) {
- request_->net_log().AddEventWithNetErrorCode(NetLog::TYPE_FAILED,
+ if (status.status() == URLRequestStatus::FAILED)
+ request_->net_log().AddEventWithNetErrorCode(NetLogEventType::FAILED,
status.error());
- }
request_->set_status(status);
}
@@ -654,7 +619,7 @@ void URLRequestJob::NotifyDone(const URLRequestStatus &status) {
int response_code = GetResponseCode();
if (400 <= response_code && response_code <= 599) {
bool page_has_content = (postfilter_bytes_read_ != 0);
- if (request_->load_flags() & net::LOAD_MAIN_FRAME) {
+ if (request_->load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED) {
UMA_HISTOGRAM_BOOLEAN("Net.ErrorResponseHasContentMainFrame",
page_has_content);
} else {
@@ -683,7 +648,7 @@ void URLRequestJob::CompleteNotifyDone() {
request_->NotifyReadCompleted(-1);
} else {
has_handled_response_ = true;
- request_->NotifyResponseStarted();
+ request_->NotifyResponseStarted(URLRequestStatus());
}
}
}
@@ -800,8 +765,7 @@ Error URLRequestJob::ReadFilteredData(int* bytes_read) {
break;
}
case Filter::FILTER_ERROR: {
- DVLOG(1) << __FUNCTION__ << "() "
- << "\"" << request_->url().spec() << "\""
+ DVLOG(1) << __func__ << "() \"" << request_->url().spec() << "\""
<< " Filter Error";
filter_needs_more_output_space_ = false;
error = ERR_CONTENT_DECODING_FAILED;
@@ -821,8 +785,8 @@ Error URLRequestJob::ReadFilteredData(int* bytes_read) {
if (error == OK && filtered_data_len > 0 &&
request()->net_log().IsCapturing()) {
request()->net_log().AddByteTransferEvent(
- NetLog::TYPE_URL_REQUEST_JOB_FILTERED_BYTES_READ, filtered_data_len,
- filtered_read_buffer_->data());
+ NetLogEventType::URL_REQUEST_JOB_FILTERED_BYTES_READ,
+ filtered_data_len, filtered_read_buffer_->data());
}
} else {
// we are done, or there is no data left.
@@ -848,17 +812,7 @@ const URLRequestStatus URLRequestJob::GetStatus() {
return request_->status();
}
-void URLRequestJob::SetStatus(const URLRequestStatus &status) {
- // An error status should never be replaced by a non-error status by a
- // URLRequestJob. URLRequest has some retry paths, but it resets the status
- // itself, if needed.
- DCHECK(request_->status().is_io_pending() ||
- request_->status().is_success() ||
- (!status.is_success() && !status.is_io_pending()));
- request_->set_status(status);
-}
-
-void URLRequestJob::SetProxyServer(const HostPortPair& proxy_server) {
+void URLRequestJob::SetProxyServer(const ProxyServer& proxy_server) {
request_->proxy_server_ = proxy_server;
}
@@ -917,7 +871,7 @@ void URLRequestJob::GatherRawReadStats(Error error, int bytes_read) {
// instead.
if (!filter_.get() && bytes_read > 0 && request()->net_log().IsCapturing()) {
request()->net_log().AddByteTransferEvent(
- NetLog::TYPE_URL_REQUEST_JOB_BYTES_READ, bytes_read,
+ NetLogEventType::URL_REQUEST_JOB_BYTES_READ, bytes_read,
raw_read_buffer_->data());
}
@@ -946,8 +900,7 @@ void URLRequestJob::RecordBytesRead(int bytes_read) {
if (!filter_.get())
postfilter_bytes_read_ += bytes_read;
- DVLOG(2) << __FUNCTION__ << "() "
- << "\"" << request_->url().spec() << "\""
+ DVLOG(2) << __func__ << "() \"" << request_->url().spec() << "\""
<< " pre bytes read = " << bytes_read
<< " pre total = " << prefilter_bytes_read_
<< " post total = " << postfilter_bytes_read_;
@@ -1017,8 +970,9 @@ RedirectInfo URLRequestJob::ComputeRedirectInfo(const GURL& location,
.spec();
std::string include_referer;
- request_->GetResponseHeaderByName("include-referer-token-binding-id",
+ request_->GetResponseHeaderByName("include-referred-token-binding-id",
&include_referer);
+ include_referer = base::ToLowerASCII(include_referer);
if (include_referer == "true" &&
request_->ssl_info().token_binding_negotiated) {
redirect_info.referred_token_binding_host = url.host();
diff --git a/chromium/net/url_request/url_request_job.h b/chromium/net/url_request/url_request_job.h
index 0124f854d65..8681a659954 100644
--- a/chromium/net/url_request/url_request_job.h
+++ b/chromium/net/url_request/url_request_job.h
@@ -13,14 +13,12 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/power_monitor/power_observer.h"
#include "net/base/host_port_pair.h"
#include "net/base/load_states.h"
#include "net/base/net_error_details.h"
#include "net/base/net_export.h"
#include "net/base/request_priority.h"
-#include "net/base/upload_progress.h"
#include "net/cookies/canonical_cookie.h"
#include "net/socket/connection_attempts.h"
#include "net/url_request/redirect_info.h"
@@ -38,6 +36,7 @@ class HttpResponseInfo;
class IOBuffer;
struct LoadTimingInfo;
class NetworkDelegate;
+class ProxyServer;
class SSLCertRequestInfo;
class SSLInfo;
class SSLPrivateKey;
@@ -96,10 +95,10 @@ class NET_EXPORT URLRequestJob : public base::PowerObserver {
virtual void Kill();
// Called to read post-filtered data from this Job, returning the number of
- // bytes read, 0 when there is no more data, or -1 if there was an error.
- // This is just the backend for URLRequest::Read, see that function for
+ // bytes read, 0 when there is no more data, or net error if there was an
+ // error. This is just the backend for URLRequest::Read, see that function for
// more info.
- bool Read(IOBuffer* buf, int buf_size, int* bytes_read);
+ int Read(IOBuffer* buf, int buf_size);
// Stops further caching of this request, if any. For more info, see
// URLRequest::StopCaching().
@@ -118,9 +117,6 @@ class NET_EXPORT URLRequestJob : public base::PowerObserver {
// Called to fetch the current load state for the job.
virtual LoadState GetLoadState() const;
- // Called to get the upload progress in bytes.
- virtual UploadProgress GetUploadProgress() const;
-
// Called to fetch the charset for this request. Only makes sense for some
// types of requests. Returns true on success. Calling this on a type that
// doesn't have a charset will return false.
@@ -198,9 +194,6 @@ class NET_EXPORT URLRequestJob : public base::PowerObserver {
// Continue processing the request ignoring the last error.
virtual void ContinueDespiteLastError();
- // Continue with the network request.
- virtual void ResumeNetworkStart();
-
void FollowDeferredRedirect();
// Returns true if the Job is done producing response data and has called
@@ -266,9 +259,6 @@ class NET_EXPORT URLRequestJob : public base::PowerObserver {
// Delegates to URLRequest::Delegate.
bool CanEnablePrivacyMode() const;
- // Notifies the job that the network is about to be used.
- void NotifyBeforeNetworkStart(bool* defer);
-
// Notifies the job that headers have been received.
void NotifyHeadersComplete();
@@ -336,7 +326,7 @@ class NET_EXPORT URLRequestJob : public base::PowerObserver {
const URLRequestStatus GetStatus();
// Set the proxy server that was used, if any.
- void SetProxyServer(const HostPortPair& proxy_server);
+ void SetProxyServer(const ProxyServer& proxy_server);
// The number of bytes read after passing through the filter. This value
// reflects bytes read even when there is no filter.
@@ -351,16 +341,13 @@ class NET_EXPORT URLRequestJob : public base::PowerObserver {
// Completion callback for raw reads. See |ReadRawData| for details.
// |bytes_read| is either >= 0 to indicate a successful read and count of
// bytes read, or < 0 to indicate an error.
+ // On return, |this| may be deleted.
void ReadRawDataComplete(int bytes_read);
// The request that initiated this job. This value will never be nullptr.
URLRequest* request_;
private:
- // Set the status of the associated URLRequest.
- // TODO(mmenke): Make the URLRequest manage its own status.
- void SetStatus(const URLRequestStatus& status);
-
// When data filtering is enabled, this function is used to read data
// for the filter. Returns a net error code to indicate if raw data was
// successfully read, an error happened, or the IO is pending.
diff --git a/chromium/net/url_request/url_request_job_factory_impl.cc b/chromium/net/url_request/url_request_job_factory_impl.cc
index f69db49ed51..8fe47034255 100644
--- a/chromium/net/url_request/url_request_job_factory_impl.cc
+++ b/chromium/net/url_request/url_request_job_factory_impl.cc
@@ -36,7 +36,7 @@ bool URLRequestJobFactoryImpl::SetProtocolHandler(
return true;
}
- if (ContainsKey(protocol_handler_map_, scheme))
+ if (base::ContainsKey(protocol_handler_map_, scheme))
return false;
protocol_handler_map_[scheme] = std::move(protocol_handler);
return true;
@@ -76,8 +76,8 @@ URLRequestJob* URLRequestJobFactoryImpl::MaybeInterceptResponse(
bool URLRequestJobFactoryImpl::IsHandledProtocol(
const std::string& scheme) const {
DCHECK(CalledOnValidThread());
- return ContainsKey(protocol_handler_map_, scheme) ||
- URLRequestJobManager::GetInstance()->SupportsScheme(scheme);
+ return base::ContainsKey(protocol_handler_map_, scheme) ||
+ URLRequestJobManager::GetInstance()->SupportsScheme(scheme);
}
bool URLRequestJobFactoryImpl::IsHandledURL(const GURL& url) const {
diff --git a/chromium/net/url_request/url_request_job_factory_impl_unittest.cc b/chromium/net/url_request/url_request_job_factory_impl_unittest.cc
index a829b1ae80f..871bd4711c7 100644
--- a/chromium/net/url_request/url_request_job_factory_impl_unittest.cc
+++ b/chromium/net/url_request/url_request_job_factory_impl_unittest.cc
@@ -14,11 +14,16 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/request_priority.h"
+#include "net/test/gtest_util.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -64,8 +69,7 @@ TEST(URLRequestJobFactoryTest, NoProtocolHandler) {
request->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::FAILED, request->status().status());
- EXPECT_EQ(ERR_UNKNOWN_URL_SCHEME, request->status().error());
+ EXPECT_EQ(ERR_UNKNOWN_URL_SCHEME, delegate.request_status());
}
TEST(URLRequestJobFactoryTest, BasicProtocolHandler) {
@@ -80,8 +84,7 @@ TEST(URLRequestJobFactoryTest, BasicProtocolHandler) {
request->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, request->status().status());
- EXPECT_EQ(OK, request->status().error());
+ EXPECT_EQ(OK, delegate.request_status());
}
TEST(URLRequestJobFactoryTest, DeleteProtocolHandler) {
diff --git a/chromium/net/url_request/url_request_job_unittest.cc b/chromium/net/url_request/url_request_job_unittest.cc
index 5d1631bd80a..29fd7e94fe5 100644
--- a/chromium/net/url_request/url_request_job_unittest.cc
+++ b/chromium/net/url_request/url_request_job_unittest.cc
@@ -10,11 +10,16 @@
#include "net/base/request_priority.h"
#include "net/http/http_transaction_test_util.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -266,14 +271,16 @@ TEST(URLRequestJob, RedirectTransactionWithReferrerPolicyHeader) {
URLRequest::NO_REFERRER /* expected final policy */,
"" /* expected final referrer */},
- // Same as above but for the legacy keyword 'never'.
+ // Same as above but for the legacy keyword 'never', which should
+ // not be supported.
{"http://foo.test/one" /* original url */,
"http://foo.test/one" /* original referrer */,
"Location: http://foo.test/test\nReferrer-Policy: never\n",
// original policy
URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
- URLRequest::NO_REFERRER /* expected final policy */,
- "" /* expected final referrer */},
+ // expected final policy
+ URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
+ "http://foo.test/one" /* expected final referrer */},
// If a redirect serves 'Referrer-Policy:
// no-referrer-when-downgrade', then the referrer should be cleared
@@ -288,15 +295,16 @@ TEST(URLRequestJob, RedirectTransactionWithReferrerPolicyHeader) {
URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
"" /* expected final referrer */},
- // Same as above but for the legacy keyword 'default'.
+ // Same as above but for the legacy keyword 'default', which
+ // should not be supported.
{"https://foo.test/one" /* original url */,
"https://foo.test/one" /* original referrer */,
"Location: http://foo.test\n"
"Referrer-Policy: default\n",
URLRequest::NEVER_CLEAR_REFERRER /* original policy */,
// expected final policy
- URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
- "" /* expected final referrer */},
+ URLRequest::NEVER_CLEAR_REFERRER,
+ "https://foo.test/one" /* expected final referrer */},
// If a redirect serves 'Referrer-Policy: origin', then the referrer
// should be stripped to its origin, even if the original request's
@@ -341,14 +349,16 @@ TEST(URLRequestJob, RedirectTransactionWithReferrerPolicyHeader) {
URLRequest::NEVER_CLEAR_REFERRER /* expected final policy */,
"https://foo.test/one" /* expected final referrer */},
- // Same as above but for the legacy keyword 'always'.
+ // Same as above but for the legacy keyword 'always', which should
+ // not be supported.
{"https://foo.test/one" /* original url */,
"https://foo.test/one" /* original referrer */,
"Location: https://bar.test/two\n"
"Referrer-Policy: always\n",
URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN /* original policy */,
- URLRequest::NEVER_CLEAR_REFERRER /* expected final policy */,
- "https://foo.test/one" /* expected final referrer */},
+ URLRequest::
+ ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN /* expected final policy */,
+ "https://foo.test/" /* expected final referrer */},
// An invalid keyword should leave the policy untouched.
{"https://foo.test/one" /* original url */,
@@ -506,8 +516,7 @@ TEST(URLRequestJob, InvalidContentGZipTransaction) {
// so should be false.
EXPECT_FALSE(d.request_failed());
EXPECT_EQ(200, req->GetResponseCode());
- EXPECT_FALSE(req->status().is_success());
- EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, req->status().error());
+ EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, d.request_status());
EXPECT_TRUE(d.data_received().empty());
EXPECT_FALSE(network_layer.done_reading_called());
diff --git a/chromium/net/url_request/url_request_netlog_params.cc b/chromium/net/url_request/url_request_netlog_params.cc
index ad7be23f835..97b67badcda 100644
--- a/chromium/net/url_request/url_request_netlog_params.cc
+++ b/chromium/net/url_request/url_request_netlog_params.cc
@@ -8,6 +8,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
+#include "net/log/net_log_capture_mode.h"
#include "url/gurl.h"
namespace net {
diff --git a/chromium/net/url_request/url_request_netlog_params.h b/chromium/net/url_request/url_request_netlog_params.h
index e3b92c601b9..a42ca3f3bc9 100644
--- a/chromium/net/url_request/url_request_netlog_params.h
+++ b/chromium/net/url_request/url_request_netlog_params.h
@@ -7,11 +7,11 @@
#include <stdint.h>
+#include <memory>
#include <string>
#include "net/base/net_export.h"
#include "net/base/request_priority.h"
-#include "net/log/net_log.h"
class GURL;
@@ -21,6 +21,8 @@ class Value;
namespace net {
+class NetLogCaptureMode;
+
// Returns a Value containing NetLog parameters for starting a URLRequest.
NET_EXPORT std::unique_ptr<base::Value> NetLogURLRequestStartCallback(
const GURL* url,
diff --git a/chromium/net/url_request/url_request_quic_unittest.cc b/chromium/net/url_request/url_request_quic_unittest.cc
new file mode 100644
index 00000000000..e37baffe69a
--- /dev/null
+++ b/chromium/net/url_request/url_request_quic_unittest.cc
@@ -0,0 +1,246 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "net/base/load_timing_info.h"
+#include "net/base/network_delegate.h"
+#include "net/cert/mock_cert_verifier.h"
+#include "net/dns/mapped_host_resolver.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/quic/chromium/crypto/proof_source_chromium.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
+#include "net/test/test_data_directory.h"
+#include "net/tools/quic/quic_in_memory_cache.h"
+#include "net/tools/quic/quic_simple_server.h"
+#include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+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;
+const char kTestServerHost[] = "test.example.com:6121";
+// Used as a simple response from the server.
+const char kHelloPath[] = "/hello.txt";
+const char kHelloBodyValue[] = "Hello from QUIC Server";
+const int kHelloStatus = 200;
+
+class URLRequestQuicTest : public ::testing::Test {
+ protected:
+ URLRequestQuicTest() : context_(new TestURLRequestContext(true)) {
+ StartQuicServer();
+
+ std::unique_ptr<HttpNetworkSession::Params> params(
+ 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");
+ cert_verifier_.AddResultForCertAndHost(verify_result.verified_cert.get(),
+ "test.example.com", verify_result,
+ OK);
+ // To simplify the test, and avoid the race with the HTTP request, we force
+ // QUIC for these requests.
+ params->origins_to_force_quic_on.insert(
+ HostPortPair::FromString(kTestServerHost));
+ params->cert_verifier = &cert_verifier_;
+ params->enable_quic = true;
+ params->host_resolver = host_resolver_.get();
+ context_->set_http_network_session_params(std::move(params));
+ context_->set_cert_verifier(&cert_verifier_);
+ }
+
+ void TearDown() override {
+ if (server_)
+ server_->Shutdown();
+ }
+
+ // Sets a NetworkDelegate to use for |context_|. Must be done before Init().
+ void SetNetworkDelegate(NetworkDelegate* network_delegate) {
+ context_->set_network_delegate(network_delegate);
+ }
+
+ // Initializes the TestURLRequestContext |context_|.
+ void Init() { context_->Init(); }
+
+ std::unique_ptr<URLRequest> CreateRequest(const GURL& url,
+ RequestPriority priority,
+ URLRequest::Delegate* delegate) {
+ return context_->CreateRequest(url, priority, delegate);
+ }
+
+ private:
+ void StartQuicServer() {
+ // Set up in-memory cache.
+ test::QuicInMemoryCachePeer::ResetForTests();
+ QuicInMemoryCache::GetInstance()->AddSimpleResponse(
+ kTestServerHost, kHelloPath, kHelloStatus, kHelloBodyValue);
+ net::QuicConfig config;
+ // Set up server certs.
+ std::unique_ptr<net::ProofSourceChromium> proof_source(
+ 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"))));
+ server_.reset(new QuicSimpleServer(
+ test::CryptoTestUtils::ProofSourceForTesting(), config,
+ net::QuicCryptoServerConfig::ConfigOptions(), AllSupportedVersions()));
+ int rv = server_->Listen(
+ net::IPEndPoint(net::IPAddress::IPv4AllZeros(), kTestServerPort));
+ EXPECT_GE(rv, 0) << "Quic server fails to start";
+
+ std::unique_ptr<MockHostResolver> resolver(new MockHostResolver());
+ resolver->rules()->AddRule("test.example.com", "127.0.0.1");
+ host_resolver_.reset(new MappedHostResolver(std::move(resolver)));
+ // Use a mapped host resolver so that request for test.example.com (port 80)
+ // reach the server running on localhost.
+ std::string map_rule = "MAP test.example.com test.example.com:" +
+ base::IntToString(server_->server_address().port());
+ EXPECT_TRUE(host_resolver_->AddRuleFromString(map_rule));
+ }
+
+ std::unique_ptr<MappedHostResolver> host_resolver_;
+ std::unique_ptr<QuicSimpleServer> server_;
+ std::unique_ptr<TestURLRequestContext> context_;
+ MockCertVerifier cert_verifier_;
+};
+
+// A URLRequest::Delegate that checks LoadTimingInfo when response headers are
+// received.
+class CheckLoadTimingDelegate : public TestDelegate {
+ public:
+ CheckLoadTimingDelegate(bool session_reused)
+ : session_reused_(session_reused) {}
+ void OnResponseStarted(URLRequest* request, int error) override {
+ TestDelegate::OnResponseStarted(request, error);
+ LoadTimingInfo load_timing_info;
+ request->GetLoadTimingInfo(&load_timing_info);
+ assertLoadTimingValid(load_timing_info, session_reused_);
+ }
+
+ private:
+ void assertLoadTimingValid(const LoadTimingInfo& load_timing_info,
+ bool session_reused) {
+ EXPECT_EQ(session_reused, load_timing_info.socket_reused);
+
+ // If |session_reused| is true, these fields should all be null, non-null
+ // otherwise.
+ EXPECT_EQ(session_reused,
+ load_timing_info.connect_timing.connect_start.is_null());
+ EXPECT_EQ(session_reused,
+ load_timing_info.connect_timing.connect_end.is_null());
+ EXPECT_EQ(session_reused,
+ load_timing_info.connect_timing.ssl_start.is_null());
+ EXPECT_EQ(session_reused,
+ load_timing_info.connect_timing.ssl_end.is_null());
+ EXPECT_EQ(load_timing_info.connect_timing.connect_start,
+ load_timing_info.connect_timing.ssl_start);
+ EXPECT_EQ(load_timing_info.connect_timing.connect_end,
+ load_timing_info.connect_timing.ssl_end);
+ EXPECT_EQ(session_reused,
+ load_timing_info.connect_timing.dns_start.is_null());
+ EXPECT_EQ(session_reused,
+ load_timing_info.connect_timing.dns_end.is_null());
+ }
+
+ bool session_reused_;
+
+ DISALLOW_COPY_AND_ASSIGN(CheckLoadTimingDelegate);
+};
+
+// A TestNetworkDelegate that invokes |all_requests_completed_callback| when
+// |num_expected_requests| requests are completed.
+class WaitForCompletionNetworkDelegate : public net::TestNetworkDelegate {
+ public:
+ WaitForCompletionNetworkDelegate(
+ const base::Closure& all_requests_completed_callback,
+ size_t num_expected_requests)
+ : all_requests_completed_callback_(all_requests_completed_callback),
+ num_expected_requests_(num_expected_requests) {}
+
+ void OnCompleted(URLRequest* request, bool started, int net_error) override {
+ net::TestNetworkDelegate::OnCompleted(request, started, net_error);
+ num_expected_requests_--;
+ if (num_expected_requests_ == 0)
+ all_requests_completed_callback_.Run();
+ }
+
+ private:
+ const base::Closure all_requests_completed_callback_;
+ size_t num_expected_requests_;
+ DISALLOW_COPY_AND_ASSIGN(WaitForCompletionNetworkDelegate);
+};
+
+} // namespace
+
+TEST_F(URLRequestQuicTest, TestGetRequest) {
+ Init();
+ CheckLoadTimingDelegate delegate(false);
+ std::string url =
+ base::StringPrintf("https://%s%s", kTestServerHost, kHelloPath);
+ std::unique_ptr<URLRequest> request =
+ CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate);
+
+ request->Start();
+ ASSERT_TRUE(request->is_pending());
+ base::RunLoop().Run();
+
+ EXPECT_TRUE(request->status().is_success());
+ EXPECT_EQ(kHelloBodyValue, delegate.data_received());
+}
+
+// Tests that if two requests use the same QUIC session, the second request
+// should not have |LoadTimingInfo::connect_timing|.
+TEST_F(URLRequestQuicTest, TestTwoRequests) {
+ base::RunLoop run_loop;
+ WaitForCompletionNetworkDelegate network_delegate(
+ run_loop.QuitClosure(), /*num_expected_requests=*/2);
+ SetNetworkDelegate(&network_delegate);
+ Init();
+ CheckLoadTimingDelegate delegate(false);
+ delegate.set_quit_on_complete(false);
+ std::string url =
+ base::StringPrintf("https://%s%s", kTestServerHost, kHelloPath);
+ std::unique_ptr<URLRequest> request =
+ CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate);
+
+ CheckLoadTimingDelegate delegate2(true);
+ delegate2.set_quit_on_complete(false);
+ std::unique_ptr<URLRequest> request2 =
+ CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate2);
+ request->Start();
+ request2->Start();
+ ASSERT_TRUE(request->is_pending());
+ ASSERT_TRUE(request2->is_pending());
+ run_loop.Run();
+
+ EXPECT_TRUE(request->status().is_success());
+ EXPECT_TRUE(request2->status().is_success());
+ EXPECT_EQ(kHelloBodyValue, delegate.data_received());
+ EXPECT_EQ(kHelloBodyValue, delegate2.data_received());
+}
+
+} // namespace net
diff --git a/chromium/net/url_request/url_request_redirect_job.cc b/chromium/net/url_request/url_request_redirect_job.cc
index 4e81728e338..e13dec0759b 100644
--- a/chromium/net/url_request/url_request_redirect_job.cc
+++ b/chromium/net/url_request/url_request_redirect_job.cc
@@ -19,6 +19,8 @@
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
#include "net/url_request/url_request.h"
namespace net {
@@ -60,7 +62,7 @@ void URLRequestRedirectJob::GetLoadTimingInfo(
void URLRequestRedirectJob::Start() {
request()->net_log().AddEvent(
- NetLog::TYPE_URL_REQUEST_REDIRECT_JOB,
+ NetLogEventType::URL_REQUEST_REDIRECT_JOB,
NetLog::StringCallback("reason", &redirect_reason_));
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&URLRequestRedirectJob::StartAsync,
@@ -121,10 +123,9 @@ void URLRequestRedirectJob::StartAsync() {
DCHECK(fake_headers_->IsRedirect(NULL));
request()->net_log().AddEvent(
- NetLog::TYPE_URL_REQUEST_FAKE_RESPONSE_HEADERS_CREATED,
- base::Bind(
- &HttpResponseHeaders::NetLogCallback,
- base::Unretained(fake_headers_.get())));
+ NetLogEventType::URL_REQUEST_FAKE_RESPONSE_HEADERS_CREATED,
+ base::Bind(&HttpResponseHeaders::NetLogCallback,
+ base::Unretained(fake_headers_.get())));
// TODO(mmenke): Consider calling the NetworkDelegate with the headers here.
// There's some weirdness about how to handle the case in which the delegate
diff --git a/chromium/net/url_request/url_request_simple_job_unittest.cc b/chromium/net/url_request/url_request_simple_job_unittest.cc
index 204693cdab8..8b0ef3232e8 100644
--- a/chromium/net/url_request/url_request_simple_job_unittest.cc
+++ b/chromium/net/url_request/url_request_simple_job_unittest.cc
@@ -5,21 +5,28 @@
#include "net/url_request/url_request_simple_job.h"
#include <memory>
+#include <utility>
#include "base/bind_helpers.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
-#include "base/test/sequenced_worker_pool_owner.h"
-#include "base/threading/worker_pool.h"
+#include "base/threading/thread.h"
#include "net/base/request_priority.h"
+#include "net/test/gtest_util.h"
#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_job_factory.h"
#include "net/url_request/url_request_job_factory_impl.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -38,10 +45,10 @@ class MockSimpleJob : public URLRequestSimpleJob {
MockSimpleJob(URLRequest* request,
NetworkDelegate* network_delegate,
scoped_refptr<base::TaskRunner> task_runner,
- std::string data)
+ base::StringPiece data)
: URLRequestSimpleJob(request, network_delegate),
- data_(data),
- task_runner_(task_runner) {}
+ data_(data.as_string()),
+ task_runner_(std::move(task_runner)) {}
protected:
// URLRequestSimpleJob implementation:
@@ -64,7 +71,7 @@ class MockSimpleJob : public URLRequestSimpleJob {
const std::string data_;
- scoped_refptr<base::TaskRunner> task_runner_;
+ const scoped_refptr<base::TaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(MockSimpleJob);
};
@@ -75,18 +82,14 @@ class CancelAfterFirstReadURLRequestDelegate : public TestDelegate {
~CancelAfterFirstReadURLRequestDelegate() override {}
- void OnResponseStarted(URLRequest* request) override {
+ void OnResponseStarted(URLRequest* request, int net_error) override {
+ DCHECK_NE(ERR_IO_PENDING, net_error);
// net::TestDelegate will start the first read.
- TestDelegate::OnResponseStarted(request);
+ TestDelegate::OnResponseStarted(request, net_error);
request->Cancel();
run_loop_->Quit();
}
- void OnReadCompleted(URLRequest* request, int bytes_read) override {
- // Read should have been cancelled.
- EXPECT_EQ(-1, bytes_read);
- }
-
void WaitUntilHeadersReceived() const { run_loop_->Run(); }
private:
@@ -99,7 +102,7 @@ class SimpleJobProtocolHandler :
public URLRequestJobFactory::ProtocolHandler {
public:
SimpleJobProtocolHandler(scoped_refptr<base::TaskRunner> task_runner)
- : task_runner_(task_runner) {}
+ : task_runner_(std::move(task_runner)) {}
URLRequestJob* MaybeCreateJob(
URLRequest* request,
NetworkDelegate* network_delegate) const override {
@@ -112,21 +115,19 @@ class SimpleJobProtocolHandler :
~SimpleJobProtocolHandler() override {}
private:
- scoped_refptr<base::TaskRunner> task_runner_;
+ const scoped_refptr<base::TaskRunner> task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(SimpleJobProtocolHandler);
};
class URLRequestSimpleJobTest : public ::testing::Test {
public:
URLRequestSimpleJobTest()
- : worker_pool_owner_(1, "URLRequestSimpleJobTest"),
- task_runner_(worker_pool_owner_.pool()
- ->GetSequencedTaskRunnerWithShutdownBehavior(
- worker_pool_owner_.pool()
- ->GetSequenceToken(),
- base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)),
- context_(true) {
+ : worker_thread_("URLRequestSimpleJobTest"), context_(true) {
+ EXPECT_TRUE(worker_thread_.Start());
+
job_factory_.SetProtocolHandler(
- "data", base::WrapUnique(new SimpleJobProtocolHandler(task_runner_)));
+ "data", base::MakeUnique<SimpleJobProtocolHandler>(task_runner()));
context_.set_job_factory(&job_factory_);
context_.Init();
@@ -144,20 +145,25 @@ class URLRequestSimpleJobTest : public ::testing::Test {
EXPECT_FALSE(request_->is_pending());
}
+ scoped_refptr<base::SequencedTaskRunner> task_runner() {
+ return worker_thread_.task_runner();
+ }
+
protected:
- base::SequencedWorkerPoolOwner worker_pool_owner_;
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ base::Thread worker_thread_;
TestURLRequestContext context_;
URLRequestJobFactoryImpl job_factory_;
TestDelegate delegate_;
std::unique_ptr<URLRequest> request_;
+
+ DISALLOW_COPY_AND_ASSIGN(URLRequestSimpleJobTest);
};
} // namespace
TEST_F(URLRequestSimpleJobTest, SimpleRequest) {
StartRequest(NULL);
- ASSERT_TRUE(request_->status().is_success());
+ EXPECT_THAT(delegate_.request_status(), IsOk());
EXPECT_EQ(kTestData, delegate_.data_received());
}
@@ -172,7 +178,7 @@ TEST_F(URLRequestSimpleJobTest, RangeRequest) {
StartRequest(&headers);
- ASSERT_TRUE(request_->status().is_success());
+ EXPECT_THAT(delegate_.request_status(), IsOk());
EXPECT_EQ(kExpectedBody, delegate_.data_received());
}
@@ -189,7 +195,7 @@ TEST_F(URLRequestSimpleJobTest, MultipleRangeRequest) {
StartRequest(&headers);
EXPECT_TRUE(delegate_.request_failed());
- EXPECT_EQ(ERR_REQUEST_RANGE_NOT_SATISFIABLE, request_->status().error());
+ EXPECT_EQ(ERR_REQUEST_RANGE_NOT_SATISFIABLE, delegate_.request_status());
}
TEST_F(URLRequestSimpleJobTest, InvalidRangeRequest) {
@@ -200,7 +206,7 @@ TEST_F(URLRequestSimpleJobTest, InvalidRangeRequest) {
StartRequest(&headers);
- ASSERT_TRUE(request_->status().is_success());
+ EXPECT_THAT(delegate_.request_status(), IsOk());
EXPECT_EQ(kTestData, delegate_.data_received());
}
@@ -208,7 +214,7 @@ TEST_F(URLRequestSimpleJobTest, EmptyDataRequest) {
request_ =
context_.CreateRequest(GURL("data:empty"), DEFAULT_PRIORITY, &delegate_);
StartRequest(nullptr);
- ASSERT_TRUE(request_->status().is_success());
+ EXPECT_THAT(delegate_.request_status(), IsOk());
EXPECT_EQ("", delegate_.data_received());
}
@@ -219,7 +225,7 @@ TEST_F(URLRequestSimpleJobTest, CancelBeforeResponseStarts) {
request_->Cancel();
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(URLRequestStatus::CANCELED, request_->status().status());
+ EXPECT_THAT(delegate_.request_status(), IsError(ERR_ABORTED));
EXPECT_EQ(1, delegate_.response_started_count());
}
@@ -233,11 +239,11 @@ TEST_F(URLRequestSimpleJobTest, CancelAfterFirstReadStarted) {
// Feed a dummy task to the SequencedTaskRunner to make sure that the
// callbacks which are invoked in ReadRawData have completed safely.
base::RunLoop run_loop;
- EXPECT_TRUE(task_runner_->PostTaskAndReply(
+ EXPECT_TRUE(task_runner()->PostTaskAndReply(
FROM_HERE, base::Bind(&base::DoNothing), run_loop.QuitClosure()));
run_loop.Run();
- EXPECT_EQ(URLRequestStatus::CANCELED, request_->status().status());
+ EXPECT_THAT(cancel_delegate.request_status(), IsError(ERR_ABORTED));
EXPECT_EQ(1, cancel_delegate.response_started_count());
EXPECT_EQ("", cancel_delegate.data_received());
// Destroy the request so it doesn't outlive its delegate.
diff --git a/chromium/net/url_request/url_request_test_job.cc b/chromium/net/url_request/url_request_test_job.cc
index aa39c3ac4ed..1f5824babc1 100644
--- a/chromium/net/url_request/url_request_test_job.cc
+++ b/chromium/net/url_request/url_request_test_job.cc
@@ -114,7 +114,7 @@ std::string URLRequestTestJob::test_error_headers() {
// static
std::unique_ptr<URLRequestJobFactory::ProtocolHandler>
URLRequestTestJob::CreateProtocolHandler() {
- return base::WrapUnique(new TestJobProtocolHandler());
+ return base::MakeUnique<TestJobProtocolHandler>();
}
URLRequestTestJob::URLRequestTestJob(URLRequest* request,
@@ -126,8 +126,8 @@ URLRequestTestJob::URLRequestTestJob(URLRequest* request,
offset_(0),
async_buf_(NULL),
async_buf_size_(0),
- weak_factory_(this) {
-}
+ response_headers_length_(0),
+ weak_factory_(this) {}
URLRequestTestJob::URLRequestTestJob(URLRequest* request,
NetworkDelegate* network_delegate,
@@ -139,8 +139,8 @@ URLRequestTestJob::URLRequestTestJob(URLRequest* request,
offset_(0),
async_buf_(NULL),
async_buf_size_(0),
- weak_factory_(this) {
-}
+ response_headers_length_(0),
+ weak_factory_(this) {}
URLRequestTestJob::URLRequestTestJob(URLRequest* request,
NetworkDelegate* network_delegate,
@@ -151,13 +151,14 @@ URLRequestTestJob::URLRequestTestJob(URLRequest* request,
auto_advance_(auto_advance),
stage_(WAITING),
priority_(DEFAULT_PRIORITY),
- response_headers_(new net::HttpResponseHeaders(
- net::HttpUtil::AssembleRawHeaders(response_headers.c_str(),
- response_headers.size()))),
response_data_(response_data),
offset_(0),
async_buf_(NULL),
async_buf_size_(0),
+ response_headers_(new net::HttpResponseHeaders(
+ net::HttpUtil::AssembleRawHeaders(response_headers.c_str(),
+ response_headers.size()))),
+ response_headers_length_(response_headers.size()),
weak_factory_(this) {}
URLRequestTestJob::~URLRequestTestJob() {
@@ -188,9 +189,7 @@ void URLRequestTestJob::Start() {
void URLRequestTestJob::StartAsync() {
if (!response_headers_.get()) {
- std::string headers = test_headers();
- response_headers_ = new HttpResponseHeaders(
- net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()));
+ SetResponseHeaders(test_headers());
if (request_->url().spec() == test_url_1().spec()) {
response_data_ = test_data_1();
stage_ = DATA_AVAILABLE; // Simulate a synchronous response for this one.
@@ -201,10 +200,7 @@ void URLRequestTestJob::StartAsync() {
} else if (request_->url().spec() == test_url_4().spec()) {
response_data_ = test_data_4();
} else if (request_->url().spec() == test_url_redirect_to_url_2().spec()) {
- std::string redirect_headers = test_redirect_to_url_2_headers();
- response_headers_ =
- new HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
- redirect_headers.c_str(), redirect_headers.size()));
+ SetResponseHeaders(test_redirect_to_url_2_headers());
} else {
AdvanceJob();
@@ -224,6 +220,13 @@ void URLRequestTestJob::StartAsync() {
this->NotifyHeadersComplete();
}
+void URLRequestTestJob::SetResponseHeaders(
+ const std::string& response_headers) {
+ response_headers_ = new HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+ response_headers.c_str(), response_headers.size()));
+ response_headers_length_ = response_headers.size();
+}
+
int URLRequestTestJob::ReadRawData(IOBuffer* buf, int buf_size) {
if (stage_ == WAITING) {
async_buf_ = buf;
@@ -266,6 +269,10 @@ int URLRequestTestJob::GetResponseCode() const {
return -1;
}
+int64_t URLRequestTestJob::GetTotalReceivedBytes() const {
+ return response_headers_length_ + offset_;
+}
+
bool URLRequestTestJob::IsRedirectResponse(GURL* location,
int* http_status_code) {
if (!response_headers_.get())
diff --git a/chromium/net/url_request/url_request_test_job.h b/chromium/net/url_request/url_request_test_job.h
index ef2e37e46fe..162d5094aa2 100644
--- a/chromium/net/url_request/url_request_test_job.h
+++ b/chromium/net/url_request/url_request_test_job.h
@@ -9,6 +9,7 @@
#include "base/memory/weak_ptr.h"
#include "net/base/load_timing_info.h"
+#include "net/base/net_export.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_job_factory.h"
@@ -119,6 +120,7 @@ class NET_EXPORT_PRIVATE URLRequestTestJob : public URLRequestJob {
void GetResponseInfo(HttpResponseInfo* info) override;
void GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
int GetResponseCode() const override;
+ int64_t GetTotalReceivedBytes() const override;
bool IsRedirectResponse(GURL* location, int* http_status_code) override;
protected:
@@ -142,16 +144,15 @@ class NET_EXPORT_PRIVATE URLRequestTestJob : public URLRequestJob {
// Called via InvokeLater to cause callbacks to occur after Start() returns.
virtual void StartAsync();
+ // Assigns |response_headers_| and |response_headers_length_|.
+ void SetResponseHeaders(const std::string& response_headers);
+
bool auto_advance_;
Stage stage_;
RequestPriority priority_;
- // The headers the job should return, will be set in Start() if not provided
- // in the explicit ctor.
- scoped_refptr<HttpResponseHeaders> response_headers_;
-
// The data to send, will be set in Start() if not provided in the explicit
// ctor.
std::string response_data_;
@@ -165,6 +166,14 @@ class NET_EXPORT_PRIVATE URLRequestTestJob : public URLRequestJob {
LoadTimingInfo load_timing_info_;
+ private:
+ // The headers the job should return, will be set in Start() if not provided
+ // in the explicit ctor.
+ scoped_refptr<HttpResponseHeaders> response_headers_;
+
+ // Original size in bytes of the response headers before decoding.
+ int response_headers_length_;
+
base::WeakPtrFactory<URLRequestTestJob> weak_factory_;
};
diff --git a/chromium/net/url_request/url_request_test_util.cc b/chromium/net/url_request/url_request_test_util.cc
index 2da0f0b8795..5a026d39534 100644
--- a/chromium/net/url_request/url_request_test_util.cc
+++ b/chromium/net/url_request/url_request_test_util.cc
@@ -80,11 +80,11 @@ void TestURLRequestContext::Init() {
context_storage_.set_cert_verifier(CertVerifier::CreateDefault());
if (!transport_security_state()) {
context_storage_.set_transport_security_state(
- base::WrapUnique(new TransportSecurityState()));
+ base::MakeUnique<TransportSecurityState>());
}
if (!cert_transparency_verifier()) {
context_storage_.set_cert_transparency_verifier(
- base::WrapUnique(new MultiLogCTVerifier()));
+ base::MakeUnique<MultiLogCTVerifier>());
}
if (!ct_policy_enforcer()) {
context_storage_.set_ct_policy_enforcer(
@@ -103,14 +103,14 @@ void TestURLRequestContext::Init() {
// In-memory cookie store.
if (!cookie_store()) {
context_storage_.set_cookie_store(
- base::WrapUnique(new CookieMonster(nullptr, nullptr)));
+ base::MakeUnique<CookieMonster>(nullptr, nullptr));
}
// In-memory Channel ID service. Must be created before the
// HttpNetworkSession.
if (!channel_id_service()) {
- context_storage_.set_channel_id_service(base::WrapUnique(
- new ChannelIDService(new DefaultChannelIDStore(nullptr),
- base::WorkerPool::GetTaskRunner(true))));
+ context_storage_.set_channel_id_service(base::MakeUnique<ChannelIDService>(
+ new DefaultChannelIDStore(nullptr),
+ base::WorkerPool::GetTaskRunner(true)));
}
if (http_transaction_factory()) {
// Make sure we haven't been passed an object we're not going to use.
@@ -134,18 +134,19 @@ void TestURLRequestContext::Init() {
params.net_log = net_log();
params.channel_id_service = channel_id_service();
context_storage_.set_http_network_session(
- base::WrapUnique(new HttpNetworkSession(params)));
- context_storage_.set_http_transaction_factory(base::WrapUnique(
- new HttpCache(context_storage_.http_network_session(),
- HttpCache::DefaultBackend::InMemory(0), false)));
+ base::MakeUnique<HttpNetworkSession>(params));
+ context_storage_.set_http_transaction_factory(base::MakeUnique<HttpCache>(
+ context_storage_.http_network_session(),
+ HttpCache::DefaultBackend::InMemory(0), false));
}
if (!http_user_agent_settings()) {
- context_storage_.set_http_user_agent_settings(base::WrapUnique(
- new StaticHttpUserAgentSettings("en-us,fr", std::string())));
+ context_storage_.set_http_user_agent_settings(
+ base::MakeUnique<StaticHttpUserAgentSettings>("en-us,fr",
+ std::string()));
}
if (!job_factory()) {
context_storage_.set_job_factory(
- base::WrapUnique(new URLRequestJobFactoryImpl()));
+ base::MakeUnique<URLRequestJobFactoryImpl>());
}
}
@@ -183,20 +184,18 @@ TestDelegate::TestDelegate()
quit_on_complete_(true),
quit_on_redirect_(false),
quit_on_auth_required_(false),
- quit_on_before_network_start_(false),
allow_certificate_errors_(false),
response_started_count_(0),
received_bytes_count_(0),
received_redirect_count_(0),
- received_before_network_start_count_(0),
received_data_before_response_(false),
request_failed_(false),
have_certificate_errors_(false),
certificate_errors_are_fatal_(false),
auth_required_(false),
have_full_request_headers_(false),
- buf_(new IOBuffer(kBufferSize)) {
-}
+ request_status_(ERR_IO_PENDING),
+ buf_(new IOBuffer(kBufferSize)) {}
TestDelegate::~TestDelegate() {}
@@ -223,15 +222,6 @@ void TestDelegate::OnReceivedRedirect(URLRequest* request,
}
}
-void TestDelegate::OnBeforeNetworkStart(URLRequest* request, bool* defer) {
- received_before_network_start_count_++;
- if (quit_on_before_network_start_) {
- *defer = true;
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
- }
-}
-
void TestDelegate::OnAuthRequired(URLRequest* request,
AuthChallengeInfo* auth_info) {
auth_required_ = true;
@@ -261,36 +251,35 @@ void TestDelegate::OnSSLCertificateError(URLRequest* request,
request->Cancel();
}
-void TestDelegate::OnResponseStarted(URLRequest* request) {
+void TestDelegate::OnResponseStarted(URLRequest* request, int net_error) {
// It doesn't make sense for the request to have IO pending at this point.
- DCHECK(!request->status().is_io_pending());
+ DCHECK_NE(ERR_IO_PENDING, net_error);
EXPECT_FALSE(request->is_redirecting());
have_full_request_headers_ =
request->GetFullRequestHeaders(&full_request_headers_);
response_started_count_++;
+ request_status_ = net_error;
if (cancel_in_rs_) {
- request->Cancel();
+ request_status_ = request->Cancel();
OnResponseCompleted(request);
- } else if (!request->status().is_success()) {
- DCHECK(request->status().status() == URLRequestStatus::FAILED ||
- request->status().status() == URLRequestStatus::CANCELED);
+ } else if (net_error != OK) {
request_failed_ = true;
OnResponseCompleted(request);
} else {
// Initiate the first read.
- int bytes_read = 0;
- if (request->Read(buf_.get(), kBufferSize, &bytes_read))
+ int bytes_read = request->Read(buf_.get(), kBufferSize);
+ if (bytes_read >= 0)
OnReadCompleted(request, bytes_read);
- else if (!request->status().is_io_pending())
+ else if (bytes_read != ERR_IO_PENDING)
OnResponseCompleted(request);
}
}
void TestDelegate::OnReadCompleted(URLRequest* request, int bytes_read) {
// It doesn't make sense for the request to have IO pending at this point.
- DCHECK(!request->status().is_io_pending());
+ DCHECK_NE(bytes_read, ERR_IO_PENDING);
// If the request was cancelled in a redirect, it should not signal
// OnReadCompleted. Note that |cancel_in_rs_| may be true due to
@@ -301,7 +290,7 @@ void TestDelegate::OnReadCompleted(URLRequest* request, int bytes_read) {
received_data_before_response_ = true;
if (cancel_in_rd_)
- request->Cancel();
+ request_status_ = request->Cancel();
if (bytes_read >= 0) {
// There is data to read.
@@ -312,21 +301,19 @@ void TestDelegate::OnReadCompleted(URLRequest* request, int bytes_read) {
}
// If it was not end of stream, request to read more.
- if (request->status().is_success() && bytes_read > 0) {
- bytes_read = 0;
- while (request->Read(buf_.get(), kBufferSize, &bytes_read)) {
- if (bytes_read > 0) {
- data_received_.append(buf_->data(), bytes_read);
- received_bytes_count_ += bytes_read;
- } else {
- break;
- }
+ while (bytes_read > 0) {
+ bytes_read = request->Read(buf_.get(), kBufferSize);
+ if (bytes_read > 0) {
+ data_received_.append(buf_->data(), bytes_read);
+ received_bytes_count_ += bytes_read;
}
}
- if (!request->status().is_io_pending())
+
+ request_status_ = bytes_read;
+ if (request_status_ != ERR_IO_PENDING)
OnResponseCompleted(request);
else if (cancel_in_rd_pending_)
- request->Cancel();
+ request_status_ = request->Cancel();
}
void TestDelegate::OnResponseCompleted(URLRequest* request) {
@@ -516,7 +503,10 @@ void TestNetworkDelegate::OnBeforeRedirect(URLRequest* request,
next_states_[req_id] |= kStageResponseStarted;
}
-void TestNetworkDelegate::OnResponseStarted(URLRequest* request) {
+void TestNetworkDelegate::OnResponseStarted(URLRequest* request,
+ int net_error) {
+ DCHECK_NE(ERR_IO_PENDING, net_error);
+
LoadTimingInfo load_timing_info;
request->GetLoadTimingInfo(&load_timing_info);
EXPECT_FALSE(load_timing_info.request_start_time.is_null());
@@ -525,12 +515,15 @@ void TestNetworkDelegate::OnResponseStarted(URLRequest* request) {
int req_id = request->identifier();
InitRequestStatesIfNew(req_id);
event_order_[req_id] += "OnResponseStarted\n";
- EXPECT_TRUE(next_states_[req_id] & kStageResponseStarted) <<
- event_order_[req_id];
+ EXPECT_TRUE(next_states_[req_id] & kStageResponseStarted)
+ << event_order_[req_id];
next_states_[req_id] = kStageCompletedSuccess | kStageCompletedError;
- if (request->status().status() == URLRequestStatus::FAILED) {
+ if (net_error == ERR_ABORTED)
+ return;
+
+ if (net_error != OK) {
error_count_++;
- last_error_ = request->status().error();
+ last_error_ = net_error;
}
}
@@ -546,28 +539,31 @@ void TestNetworkDelegate::OnNetworkBytesSent(URLRequest* request,
total_network_bytes_sent_ += bytes_sent;
}
-void TestNetworkDelegate::OnCompleted(URLRequest* request, bool started) {
+void TestNetworkDelegate::OnCompleted(URLRequest* request,
+ bool started,
+ int net_error) {
+ DCHECK_NE(net_error, net::ERR_IO_PENDING);
+
int req_id = request->identifier();
InitRequestStatesIfNew(req_id);
event_order_[req_id] += "OnCompleted\n";
// Expect "Success -> (next_states_ & kStageCompletedSuccess)"
// is logically identical to
// Expect "!(Success) || (next_states_ & kStageCompletedSuccess)"
- EXPECT_TRUE(!request->status().is_success() ||
- (next_states_[req_id] & kStageCompletedSuccess)) <<
- event_order_[req_id];
- EXPECT_TRUE(request->status().is_success() ||
- (next_states_[req_id] & kStageCompletedError)) <<
- event_order_[req_id];
+ EXPECT_TRUE(net_error != OK ||
+ (next_states_[req_id] & kStageCompletedSuccess))
+ << event_order_[req_id];
+ EXPECT_TRUE(net_error == OK || (next_states_[req_id] & kStageCompletedError))
+ << event_order_[req_id];
next_states_[req_id] = kStageURLRequestDestroyed;
completed_requests_++;
- if (request->status().status() == URLRequestStatus::FAILED) {
- error_count_++;
- last_error_ = request->status().error();
- } else if (request->status().status() == URLRequestStatus::CANCELED) {
+ if (net_error == ERR_ABORTED) {
canceled_requests_++;
+ } else if (net_error != OK) {
+ error_count_++;
+ last_error_ = net_error;
} else {
- DCHECK_EQ(URLRequestStatus::SUCCESS, request->status().status());
+ DCHECK_EQ(OK, net_error);
}
}
diff --git a/chromium/net/url_request/url_request_test_util.h b/chromium/net/url_request/url_request_test_util.h
index 54e45fd9e84..0de30427b30 100644
--- a/chromium/net/url_request/url_request_test_util.h
+++ b/chromium/net/url_request/url_request_test_util.h
@@ -154,10 +154,6 @@ class TestDelegate : public URLRequest::Delegate {
// Enables quitting the message loop in response to auth requests, as opposed
// to returning credentials or cancelling the request.
void set_quit_on_auth_required(bool val) { quit_on_auth_required_ = val; }
- void set_quit_on_network_start(bool val) {
- quit_on_before_network_start_ = val;
- }
-
void set_allow_certificate_errors(bool val) {
allow_certificate_errors_ = val;
}
@@ -170,9 +166,6 @@ class TestDelegate : public URLRequest::Delegate {
int bytes_received() const { return static_cast<int>(data_received_.size()); }
int response_started_count() const { return response_started_count_; }
int received_redirect_count() const { return received_redirect_count_; }
- int received_before_network_start_count() const {
- return received_before_network_start_count_;
- }
bool received_data_before_response() const {
return received_data_before_response_;
}
@@ -187,12 +180,12 @@ class TestDelegate : public URLRequest::Delegate {
return full_request_headers_;
}
void ClearFullRequestHeaders();
+ int request_status() const { return request_status_; }
// URLRequest::Delegate:
void OnReceivedRedirect(URLRequest* request,
const RedirectInfo& redirect_info,
bool* defer_redirect) override;
- void OnBeforeNetworkStart(URLRequest* request, bool* defer) override;
void OnAuthRequired(URLRequest* request,
AuthChallengeInfo* auth_info) override;
// NOTE: |fatal| causes |certificate_errors_are_fatal_| to be set to true.
@@ -201,7 +194,7 @@ class TestDelegate : public URLRequest::Delegate {
void OnSSLCertificateError(URLRequest* request,
const SSLInfo& ssl_info,
bool fatal) override;
- void OnResponseStarted(URLRequest* request) override;
+ void OnResponseStarted(URLRequest* request, int net_error) override;
void OnReadCompleted(URLRequest* request, int bytes_read) override;
private:
@@ -217,7 +210,6 @@ class TestDelegate : public URLRequest::Delegate {
bool quit_on_complete_;
bool quit_on_redirect_;
bool quit_on_auth_required_;
- bool quit_on_before_network_start_;
bool allow_certificate_errors_;
AuthCredentials credentials_;
@@ -225,7 +217,6 @@ class TestDelegate : public URLRequest::Delegate {
int response_started_count_;
int received_bytes_count_;
int received_redirect_count_;
- int received_before_network_start_count_;
bool received_data_before_response_;
bool request_failed_;
bool have_certificate_errors_;
@@ -235,6 +226,9 @@ class TestDelegate : public URLRequest::Delegate {
bool have_full_request_headers_;
HttpRequestHeaders full_request_headers_;
+ // tracks status of request
+ int request_status_;
+
// our read buffer
scoped_refptr<IOBuffer> buf_;
};
@@ -337,11 +331,11 @@ class TestNetworkDelegate : public NetworkDelegateImpl {
scoped_refptr<HttpResponseHeaders>* override_response_headers,
GURL* allowed_unsafe_redirect_url) override;
void OnBeforeRedirect(URLRequest* request, const GURL& new_location) override;
- void OnResponseStarted(URLRequest* request) override;
+ void OnResponseStarted(URLRequest* request, int net_error) override;
void OnNetworkBytesReceived(URLRequest* request,
int64_t bytes_received) override;
void OnNetworkBytesSent(URLRequest* request, int64_t bytes_sent) override;
- void OnCompleted(URLRequest* request, bool started) override;
+ void OnCompleted(URLRequest* request, bool started, int net_error) override;
void OnURLRequestDestroyed(URLRequest* request) override;
void OnPACScriptError(int line_number, const base::string16& error) override;
NetworkDelegate::AuthRequiredResponse OnAuthRequired(
diff --git a/chromium/net/url_request/url_request_throttler_entry.cc b/chromium/net/url_request/url_request_throttler_entry.cc
index 304d7d18465..f81e1b532d3 100644
--- a/chromium/net/url_request/url_request_throttler_entry.cc
+++ b/chromium/net/url_request/url_request_throttler_entry.cc
@@ -14,7 +14,9 @@
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "net/base/load_flags.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source_type.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_throttler_manager.h"
@@ -71,8 +73,9 @@ URLRequestThrottlerEntry::URLRequestThrottlerEntry(
backoff_entry_(&backoff_policy_),
manager_(manager),
url_id_(url_id),
- net_log_(BoundNetLog::Make(
- manager->net_log(), NetLog::SOURCE_EXPONENTIAL_BACKOFF_THROTTLING)) {
+ net_log_(NetLogWithSource::Make(
+ manager->net_log(),
+ NetLogSourceType::EXPONENTIAL_BACKOFF_THROTTLING)) {
DCHECK(manager_);
Initialize();
}
@@ -150,14 +153,11 @@ void URLRequestThrottlerEntry::DetachManager() {
bool URLRequestThrottlerEntry::ShouldRejectRequest(
const URLRequest& request) const {
bool reject_request = false;
- if (!is_backoff_disabled_ && !ExplicitUserRequest(request.load_flags()) &&
- GetBackoffEntry()->ShouldRejectRequest()) {
- net_log_.AddEvent(
- NetLog::TYPE_THROTTLING_REJECTED_REQUEST,
- base::Bind(&NetLogRejectedRequestCallback,
- &url_id_,
- GetBackoffEntry()->failure_count(),
- GetBackoffEntry()->GetTimeUntilRelease()));
+ if (!is_backoff_disabled_ && GetBackoffEntry()->ShouldRejectRequest()) {
+ net_log_.AddEvent(NetLogEventType::THROTTLING_REJECTED_REQUEST,
+ base::Bind(&NetLogRejectedRequestCallback, &url_id_,
+ GetBackoffEntry()->failure_count(),
+ GetBackoffEntry()->GetTimeUntilRelease()));
reject_request = true;
}
@@ -284,9 +284,4 @@ BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() {
return &backoff_entry_;
}
-// static
-bool URLRequestThrottlerEntry::ExplicitUserRequest(const int load_flags) {
- return (load_flags & LOAD_MAYBE_USER_GESTURE) != 0;
-}
-
} // namespace net
diff --git a/chromium/net/url_request/url_request_throttler_entry.h b/chromium/net/url_request/url_request_throttler_entry.h
index bd64c26ed45..2d1d32a6f5c 100644
--- a/chromium/net/url_request/url_request_throttler_entry.h
+++ b/chromium/net/url_request/url_request_throttler_entry.h
@@ -13,7 +13,8 @@
#include "base/macros.h"
#include "base/time/time.h"
#include "net/base/backoff_entry.h"
-#include "net/log/net_log.h"
+#include "net/base/net_export.h"
+#include "net/log/net_log_with_source.h"
#include "net/url_request/url_request_throttler_entry_interface.h"
namespace net {
@@ -111,11 +112,6 @@ class NET_EXPORT URLRequestThrottlerEntry
virtual const BackoffEntry* GetBackoffEntry() const;
virtual BackoffEntry* GetBackoffEntry();
- // Returns true if |load_flags| contains a flag that indicates an
- // explicit request by the user to load the resource. We never
- // throttle requests with such load flags.
- static bool ExplicitUserRequest(const int load_flags);
-
// Used by tests.
base::TimeTicks sliding_window_release_time() const {
return sliding_window_release_time_;
@@ -154,7 +150,7 @@ class NET_EXPORT URLRequestThrottlerEntry
// Canonicalized URL string that this entry is for; used for logging only.
std::string url_id_;
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
DISALLOW_COPY_AND_ASSIGN(URLRequestThrottlerEntry);
};
diff --git a/chromium/net/url_request/url_request_throttler_manager.cc b/chromium/net/url_request/url_request_throttler_manager.cc
index a36f0c96e93..12382671e56 100644
--- a/chromium/net/url_request/url_request_throttler_manager.cc
+++ b/chromium/net/url_request/url_request_throttler_manager.cc
@@ -8,6 +8,8 @@
#include "base/strings/string_util.h"
#include "net/base/url_util.h"
#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source_type.h"
namespace net {
@@ -78,7 +80,7 @@ scoped_refptr<URLRequestThrottlerEntryInterface>
if (IsLocalhost(host)) {
if (!logged_for_localhost_disabled_ && IsLocalhost(host)) {
logged_for_localhost_disabled_ = true;
- net_log_.AddEvent(NetLog::TYPE_THROTTLING_DISABLED_FOR_HOST,
+ net_log_.AddEvent(NetLogEventType::THROTTLING_DISABLED_FOR_HOST,
NetLog::StringCallback("host", &host));
}
@@ -120,8 +122,8 @@ bool URLRequestThrottlerManager::enable_thread_checks() const {
void URLRequestThrottlerManager::set_net_log(NetLog* net_log) {
DCHECK(net_log);
- net_log_ = BoundNetLog::Make(net_log,
- NetLog::SOURCE_EXPONENTIAL_BACKOFF_THROTTLING);
+ net_log_ = NetLogWithSource::Make(
+ net_log, NetLogSourceType::EXPONENTIAL_BACKOFF_THROTTLING);
}
NetLog* URLRequestThrottlerManager::net_log() const {
diff --git a/chromium/net/url_request/url_request_throttler_manager.h b/chromium/net/url_request/url_request_throttler_manager.h
index 855ef931d9b..e527b16b864 100644
--- a/chromium/net/url_request/url_request_throttler_manager.h
+++ b/chromium/net/url_request/url_request_throttler_manager.h
@@ -20,8 +20,8 @@
namespace net {
-class BoundNetLog;
class NetLog;
+class NetLogWithSource;
// Class that registers URL request throttler entries for URLs being accessed
// in order to supervise traffic. URL requests for HTTP contents should
@@ -141,7 +141,7 @@ class NET_EXPORT URLRequestThrottlerManager
bool logged_for_localhost_disabled_;
// NetLog to use, if configured.
- BoundNetLog net_log_;
+ NetLogWithSource net_log_;
// Valid once we've registered for network notifications.
base::PlatformThreadId registered_from_thread_;
diff --git a/chromium/net/url_request/url_request_throttler_unittest.cc b/chromium/net/url_request/url_request_throttler_unittest.cc
index beb443d7112..54be21c2b23 100644
--- a/chromium/net/url_request/url_request_throttler_unittest.cc
+++ b/chromium/net/url_request/url_request_throttler_unittest.cc
@@ -67,10 +67,6 @@ class MockURLRequestThrottlerEntry : public URLRequestThrottlerEntry {
BackoffEntry* GetBackoffEntry() override { return &backoff_entry_; }
- static bool ExplicitUserRequest(int load_flags) {
- return URLRequestThrottlerEntry::ExplicitUserRequest(load_flags);
- }
-
void ResetToBlank(const TimeTicks& time_now) {
fake_clock_.set_now(time_now);
@@ -195,11 +191,7 @@ TEST_F(URLRequestThrottlerEntryTest, InterfaceDuringExponentialBackoff) {
entry_->ImplGetTimeNow() + TimeDelta::FromMilliseconds(1));
EXPECT_TRUE(entry_->ShouldRejectRequest(*request_));
- // Also end-to-end test the load flags exceptions.
- request_->SetLoadFlags(LOAD_MAYBE_USER_GESTURE);
- EXPECT_FALSE(entry_->ShouldRejectRequest(*request_));
-
- histogram_tester.ExpectBucketCount(kRequestThrottledHistogramName, 0, 1);
+ histogram_tester.ExpectBucketCount(kRequestThrottledHistogramName, 0, 0);
histogram_tester.ExpectBucketCount(kRequestThrottledHistogramName, 1, 1);
}
@@ -314,14 +306,6 @@ TEST_F(URLRequestThrottlerEntryTest, SlidingWindow) {
EXPECT_EQ(time_4, entry_->sliding_window_release_time());
}
-TEST_F(URLRequestThrottlerEntryTest, ExplicitUserRequest) {
- ASSERT_FALSE(MockURLRequestThrottlerEntry::ExplicitUserRequest(0));
- ASSERT_TRUE(MockURLRequestThrottlerEntry::ExplicitUserRequest(
- LOAD_MAYBE_USER_GESTURE));
- ASSERT_FALSE(MockURLRequestThrottlerEntry::ExplicitUserRequest(
- ~LOAD_MAYBE_USER_GESTURE));
-}
-
class URLRequestThrottlerManagerTest : public testing::Test {
protected:
URLRequestThrottlerManagerTest()
diff --git a/chromium/net/url_request/url_request_unittest.cc b/chromium/net/url_request/url_request_unittest.cc
index fa4751a3174..94e7cfbd8c2 100644
--- a/chromium/net/url_request/url_request_unittest.cc
+++ b/chromium/net/url_request/url_request_unittest.cc
@@ -77,11 +77,13 @@
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_source.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/nqe/external_estimate_provider.h"
+#include "net/proxy/proxy_server.h"
#include "net/proxy/proxy_service.h"
#include "net/socket/ssl_client_socket.h"
#include "net/ssl/channel_id_service.h"
@@ -93,6 +95,7 @@
#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/test/gtest_util.h"
#include "net/test/spawned_test_server/spawned_test_server.h"
#include "net/test/test_data_directory.h"
#include "net/test/url_request/url_request_failed_job.h"
@@ -107,6 +110,7 @@
#include "net/url_request/url_request_redirect_job.h"
#include "net/url_request/url_request_test_job.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -126,6 +130,9 @@
#include "base/win/scoped_comptr.h"
#endif
+using net::test::IsError;
+using net::test::IsOk;
+
using base::ASCIIToUTF16;
using base::Time;
using std::string;
@@ -151,7 +158,7 @@ const char kFtpTestFile[] = "BullRunSpeech.txt";
void TestLoadTimingNotReused(const LoadTimingInfo& load_timing_info,
int connect_timing_flags) {
EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
EXPECT_FALSE(load_timing_info.request_start_time.is_null());
EXPECT_FALSE(load_timing_info.request_start.is_null());
@@ -174,7 +181,7 @@ void TestLoadTimingNotReusedWithProxy(
const LoadTimingInfo& load_timing_info,
int connect_timing_flags) {
EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
EXPECT_FALSE(load_timing_info.request_start_time.is_null());
EXPECT_FALSE(load_timing_info.request_start.is_null());
@@ -197,7 +204,7 @@ void TestLoadTimingNotReusedWithProxy(
void TestLoadTimingReusedWithProxy(
const LoadTimingInfo& load_timing_info) {
EXPECT_TRUE(load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
EXPECT_FALSE(load_timing_info.request_start_time.is_null());
EXPECT_FALSE(load_timing_info.request_start.is_null());
@@ -240,7 +247,7 @@ void FillBuffer(char* buffer, size_t len) {
void TestLoadTimingCacheHitNoNetwork(
const LoadTimingInfo& load_timing_info) {
EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_EQ(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_EQ(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
EXPECT_FALSE(load_timing_info.request_start_time.is_null());
EXPECT_FALSE(load_timing_info.request_start.is_null());
@@ -260,7 +267,7 @@ void TestLoadTimingCacheHitNoNetwork(
void TestLoadTimingNoHttpResponse(
const LoadTimingInfo& load_timing_info) {
EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_EQ(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
+ EXPECT_EQ(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
// Only the request times should be non-null.
EXPECT_FALSE(load_timing_info.request_start_time.is_null());
@@ -669,9 +676,12 @@ class MockCertificateReportSender
MockCertificateReportSender() {}
~MockCertificateReportSender() override {}
- void Send(const GURL& report_uri, const std::string& report) override {
+ void Send(const GURL& report_uri,
+ base::StringPiece content_type,
+ base::StringPiece report) override {
latest_report_uri_ = report_uri;
- latest_report_ = report;
+ report.CopyToString(&latest_report_);
+ content_type.CopyToString(&latest_content_type_);
}
void SetErrorCallback(
@@ -679,10 +689,12 @@ class MockCertificateReportSender
const GURL& latest_report_uri() { return latest_report_uri_; }
const std::string& latest_report() { return latest_report_; }
+ const std::string& latest_content_type() { return latest_content_type_; }
private:
GURL latest_report_uri_;
std::string latest_report_;
+ std::string latest_content_type_;
};
class TestExperimentalFeaturesNetworkDelegate : public TestNetworkDelegate {
@@ -691,6 +703,31 @@ class TestExperimentalFeaturesNetworkDelegate : public TestNetworkDelegate {
bool OnAreStrictSecureCookiesEnabled() const override { return true; }
};
+// OCSPErrorTestDelegate caches the SSLInfo passed to OnSSLCertificateError.
+// This is needed because after the certificate failure, the URLRequest will
+// retry the connection, and return a partial SSLInfo with a cached cert status.
+// The partial SSLInfo does not have the OCSP information filled out.
+class OCSPErrorTestDelegate : public TestDelegate {
+ public:
+ void OnSSLCertificateError(URLRequest* request,
+ const SSLInfo& ssl_info,
+ bool fatal) override {
+ ssl_info_ = ssl_info;
+ on_ssl_certificate_error_called_ = true;
+ TestDelegate::OnSSLCertificateError(request, ssl_info, fatal);
+ }
+
+ bool on_ssl_certificate_error_called() {
+ return on_ssl_certificate_error_called_;
+ }
+
+ SSLInfo ssl_info() { return ssl_info_; }
+
+ private:
+ bool on_ssl_certificate_error_called_ = false;
+ SSLInfo ssl_info_;
+};
+
} // namespace
// Inherit PlatformTest since we require the autorelease pool on Mac OS X.
@@ -720,8 +757,8 @@ class URLRequestTest : public PlatformTest {
"data", base::WrapUnique(new DataProtocolHandler));
#if !defined(DISABLE_FILE_SUPPORT)
job_factory_impl_->SetProtocolHandler(
- "file", base::WrapUnique(new FileProtocolHandler(
- base::ThreadTaskRunnerHandle::Get())));
+ "file", base::MakeUnique<FileProtocolHandler>(
+ base::ThreadTaskRunnerHandle::Get()));
#endif
}
@@ -998,7 +1035,7 @@ TEST_F(URLRequestTest, AllowFileURLs) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath test_file;
- ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &test_file));
+ ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.GetPath(), &test_file));
std::string test_data("monkey");
base::WriteFile(test_file, test_data.data(), test_data.size());
GURL test_file_url = FilePathToFileURL(test_file);
@@ -1086,7 +1123,7 @@ TEST_F(URLRequestTest, FileDirOutputSanity) {
ASSERT_LT(0, d.bytes_received());
ASSERT_FALSE(d.request_failed());
- ASSERT_TRUE(req->status().is_success());
+ EXPECT_EQ(OK, d.request_status());
// Check for the entry generated for the "sentinel" file.
const std::string& data = d.data_received();
ASSERT_NE(data.find(sentinel_output), std::string::npos);
@@ -1110,7 +1147,7 @@ TEST_F(URLRequestTest, FileDirRedirectNoCrash) {
ASSERT_EQ(1, d.received_redirect_count());
ASSERT_LT(0, d.bytes_received());
ASSERT_FALSE(d.request_failed());
- ASSERT_TRUE(req->status().is_success());
+ EXPECT_EQ(OK, d.request_status());
}
#if defined(OS_WIN)
@@ -1123,7 +1160,7 @@ TEST_F(URLRequestTest, FileDirRedirectSingleSlash) {
base::RunLoop().Run();
ASSERT_EQ(1, d.received_redirect_count());
- ASSERT_FALSE(req->status().is_success());
+ EXPECT_NE(OK, d.request_status());
}
#endif // defined(OS_WIN)
@@ -1585,7 +1622,7 @@ TEST_F(URLRequestInterceptorTest, Intercept) {
EXPECT_EQ(user_data2, req->GetUserData(&user_data2));
// Check that we got one good response.
- EXPECT_TRUE(req->status().is_success());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(200, req->response_headers()->response_code());
EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
EXPECT_EQ(1, d.response_started_count());
@@ -1616,8 +1653,9 @@ TEST_F(URLRequestInterceptorTest, InterceptRedirect) {
EXPECT_TRUE(interceptor()->did_intercept_redirect());
// Check that we got one good response.
- EXPECT_TRUE(req->status().is_success());
- if (req->status().is_success())
+ int status = d.request_status();
+ EXPECT_EQ(OK, status);
+ if (status == OK)
EXPECT_EQ(200, req->response_headers()->response_code());
EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
@@ -1648,7 +1686,7 @@ TEST_F(URLRequestInterceptorTest, InterceptServerError) {
EXPECT_TRUE(interceptor()->did_intercept_final());
// Check that we got one good response.
- EXPECT_TRUE(req->status().is_success());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(200, req->response_headers()->response_code());
EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
EXPECT_EQ(1, d.response_started_count());
@@ -1676,7 +1714,7 @@ TEST_F(URLRequestInterceptorTest, InterceptNetworkError) {
EXPECT_TRUE(interceptor()->did_intercept_final());
// Check that we received one good response.
- EXPECT_TRUE(req->status().is_success());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(200, req->response_headers()->response_code());
EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
EXPECT_EQ(1, d.response_started_count());
@@ -1704,8 +1742,9 @@ TEST_F(URLRequestInterceptorTest, InterceptRestartRequired) {
EXPECT_TRUE(interceptor()->did_intercept_main());
// Check that we received one good response.
- EXPECT_TRUE(req->status().is_success());
- if (req->status().is_success())
+ int status = d.request_status();
+ EXPECT_EQ(OK, status);
+ if (status == OK)
EXPECT_EQ(200, req->response_headers()->response_code());
EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
@@ -1734,8 +1773,7 @@ TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelMain) {
EXPECT_FALSE(interceptor()->did_intercept_final());
// Check that we see a canceled request.
- EXPECT_FALSE(req->status().is_success());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
+ EXPECT_EQ(ERR_ABORTED, d.request_status());
}
TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelRedirect) {
@@ -1766,8 +1804,7 @@ TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelRedirect) {
EXPECT_FALSE(interceptor()->did_intercept_final());
// Check that we see a canceled request.
- EXPECT_FALSE(req->status().is_success());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
+ EXPECT_EQ(ERR_ABORTED, d.request_status());
}
TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelFinal) {
@@ -1789,8 +1826,7 @@ TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelFinal) {
EXPECT_TRUE(interceptor()->did_cancel_final());
// Check that we see a canceled request.
- EXPECT_FALSE(req->status().is_success());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
+ EXPECT_EQ(ERR_ABORTED, d.request_status());
}
TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelInRestart) {
@@ -1814,8 +1850,7 @@ TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelInRestart) {
EXPECT_FALSE(interceptor()->did_intercept_final());
// Check that we see a canceled request.
- EXPECT_FALSE(req->status().is_success());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
+ EXPECT_EQ(ERR_ABORTED, d.request_status());
}
// "Normal" LoadTimingInfo as returned by a job. Everything is in order, not
@@ -2125,14 +2160,13 @@ TEST_F(URLRequestTest, MAYBE_NetworkDelegateProxyError) {
base::RunLoop().Run();
// Check we see a failed request.
- EXPECT_FALSE(req->status().is_success());
// The proxy server is not set before failure.
- EXPECT_TRUE(req->proxy_server().IsEmpty());
- EXPECT_EQ(URLRequestStatus::FAILED, req->status().status());
- EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, req->status().error());
+ EXPECT_FALSE(req->proxy_server().is_valid());
+ EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, d.request_status());
EXPECT_EQ(1, network_delegate.error_count());
- EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, network_delegate.last_error());
+ EXPECT_THAT(network_delegate.last_error(),
+ IsError(ERR_PROXY_CONNECTION_FAILED));
EXPECT_EQ(1, network_delegate.completed_requests());
}
@@ -2981,7 +3015,7 @@ TEST_F(URLRequestTest, CancelOnSuspend) {
power_monitor_source->Suspend();
// Wait for the suspend notification to cause the request to fail.
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::CANCELED, r->status().status());
+ EXPECT_EQ(ERR_ABORTED, d.request_status());
EXPECT_TRUE(d.request_failed());
EXPECT_EQ(1, default_network_delegate_.completed_requests());
@@ -3166,8 +3200,7 @@ class URLRequestTestHTTP : public URLRequestTest {
req->Start();
base::RunLoop().Run();
EXPECT_EQ(redirect_method, req->method());
- EXPECT_EQ(URLRequestStatus::SUCCESS, req->status().status());
- EXPECT_EQ(OK, req->status().error());
+ EXPECT_EQ(OK, d.request_status());
if (include_data) {
if (request_method == redirect_method) {
EXPECT_TRUE(req->extra_request_headers().HasHeader(
@@ -3256,9 +3289,8 @@ class URLRequestTestHTTP : public URLRequestTest {
base::RunLoop().Run();
- ASSERT_EQ(1, d.response_started_count())
- << "request failed: " << r->status().status()
- << ", os error: " << r->status().error();
+ ASSERT_EQ(1, d.response_started_count()) << "request failed. Error: "
+ << d.request_status();
EXPECT_FALSE(d.received_data_before_response());
EXPECT_EQ(uploadBytes, d.data_received());
@@ -3278,12 +3310,12 @@ class URLRequestTestHTTP : public URLRequestTest {
base::RunLoop().Run();
- bool is_success = r->status().is_success();
-
- if (!is_success)
- EXPECT_TRUE(r->status().error() == ERR_RESPONSE_HEADERS_TOO_BIG);
+ if (d.request_status() != OK) {
+ EXPECT_EQ(ERR_RESPONSE_HEADERS_TOO_BIG, d.request_status());
+ return false;
+ }
- return is_success;
+ return true;
}
LocalHttpTestServer* http_test_server() { return &test_server_; }
@@ -3387,7 +3419,7 @@ TEST_F(TokenBindingURLRequestTest, TokenBindingTest) {
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
+ EXPECT_EQ(OK, d.request_status());
HttpRequestHeaders headers;
std::string token_binding_header, token_binding_message;
@@ -3395,7 +3427,7 @@ TEST_F(TokenBindingURLRequestTest, TokenBindingTest) {
EXPECT_TRUE(headers.GetHeader(HttpRequestHeaders::kTokenBinding,
&token_binding_header));
EXPECT_TRUE(base::Base64UrlDecode(
- token_binding_header, base::Base64UrlDecodePolicy::REQUIRE_PADDING,
+ token_binding_header, base::Base64UrlDecodePolicy::DISALLOW_PADDING,
&token_binding_message));
std::vector<TokenBinding> token_bindings;
ASSERT_TRUE(
@@ -3406,8 +3438,9 @@ TEST_F(TokenBindingURLRequestTest, TokenBindingTest) {
std::string ekm = d.data_received();
EXPECT_EQ(TokenBindingType::PROVIDED, token_bindings[0].type);
- EXPECT_TRUE(VerifyEKMSignature(token_bindings[0].ec_point,
- token_bindings[0].signature, ekm));
+ EXPECT_TRUE(VerifyTokenBindingSignature(token_bindings[0].ec_point,
+ token_bindings[0].signature,
+ TokenBindingType::PROVIDED, ekm));
}
}
@@ -3430,7 +3463,7 @@ TEST_F(TokenBindingURLRequestTest, ForwardTokenBinding) {
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
+ EXPECT_EQ(OK, d.request_status());
HttpRequestHeaders headers;
std::string token_binding_header, token_binding_message;
@@ -3438,7 +3471,7 @@ TEST_F(TokenBindingURLRequestTest, ForwardTokenBinding) {
EXPECT_TRUE(headers.GetHeader(HttpRequestHeaders::kTokenBinding,
&token_binding_header));
EXPECT_TRUE(base::Base64UrlDecode(
- token_binding_header, base::Base64UrlDecodePolicy::REQUIRE_PADDING,
+ token_binding_header, base::Base64UrlDecodePolicy::DISALLOW_PADDING,
&token_binding_message));
std::vector<TokenBinding> token_bindings;
ASSERT_TRUE(
@@ -3449,11 +3482,13 @@ TEST_F(TokenBindingURLRequestTest, ForwardTokenBinding) {
std::string ekm = d.data_received();
EXPECT_EQ(TokenBindingType::PROVIDED, token_bindings[0].type);
- EXPECT_TRUE(VerifyEKMSignature(token_bindings[0].ec_point,
- token_bindings[0].signature, ekm));
+ EXPECT_TRUE(VerifyTokenBindingSignature(token_bindings[0].ec_point,
+ token_bindings[0].signature,
+ TokenBindingType::PROVIDED, ekm));
EXPECT_EQ(TokenBindingType::REFERRED, token_bindings[1].type);
- EXPECT_TRUE(VerifyEKMSignature(token_bindings[1].ec_point,
- token_bindings[1].signature, ekm));
+ EXPECT_TRUE(VerifyTokenBindingSignature(token_bindings[1].ec_point,
+ token_bindings[1].signature,
+ TokenBindingType::REFERRED, ekm));
}
}
@@ -3483,7 +3518,7 @@ TEST_F(TokenBindingURLRequestTest, DontForwardHeaderFromHttp) {
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
+ EXPECT_EQ(OK, d.request_status());
HttpRequestHeaders headers;
std::string token_binding_header, token_binding_message;
@@ -3491,7 +3526,7 @@ TEST_F(TokenBindingURLRequestTest, DontForwardHeaderFromHttp) {
EXPECT_TRUE(headers.GetHeader(HttpRequestHeaders::kTokenBinding,
&token_binding_header));
EXPECT_TRUE(base::Base64UrlDecode(
- token_binding_header, base::Base64UrlDecodePolicy::REQUIRE_PADDING,
+ token_binding_header, base::Base64UrlDecodePolicy::DISALLOW_PADDING,
&token_binding_message));
std::vector<TokenBinding> token_bindings;
ASSERT_TRUE(
@@ -3502,13 +3537,14 @@ TEST_F(TokenBindingURLRequestTest, DontForwardHeaderFromHttp) {
std::string ekm = d.data_received();
EXPECT_EQ(TokenBindingType::PROVIDED, token_bindings[0].type);
- EXPECT_TRUE(VerifyEKMSignature(token_bindings[0].ec_point,
- token_bindings[0].signature, ekm));
+ EXPECT_TRUE(VerifyTokenBindingSignature(token_bindings[0].ec_point,
+ token_bindings[0].signature,
+ TokenBindingType::PROVIDED, ekm));
}
}
// Test that if a server supporting Token Binding redirects (with
-// Include-Referer-Token-Binding-ID) to an https url on a server that does not
+// Include-Referred-Token-Binding-ID) to an https url on a server that does not
// support Token Binding, then we do not send a Sec-Token-Binding when following
// the redirect.
TEST_F(TokenBindingURLRequestTest, ForwardWithoutTokenBinding) {
@@ -3534,7 +3570,7 @@ TEST_F(TokenBindingURLRequestTest, ForwardWithoutTokenBinding) {
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
+ EXPECT_EQ(OK, d.request_status());
HttpRequestHeaders headers;
std::string token_binding_header, token_binding_message;
@@ -3568,10 +3604,9 @@ TEST_F(URLRequestTestHTTP, ProxyTunnelRedirectTest) {
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::FAILED, r->status().status());
// The proxy server is not set before failure.
- EXPECT_TRUE(r->proxy_server().IsEmpty());
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, r->status().error());
+ EXPECT_FALSE(r->proxy_server().is_valid());
+ EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, d.request_status());
EXPECT_EQ(1, d.response_started_count());
// We should not have followed the redirect.
EXPECT_EQ(0, d.received_redirect_count());
@@ -3596,16 +3631,16 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateTunnelConnectionFailed) {
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::FAILED, r->status().status());
// The proxy server is not set before failure.
- EXPECT_TRUE(r->proxy_server().IsEmpty());
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, r->status().error());
+ EXPECT_FALSE(r->proxy_server().is_valid());
EXPECT_EQ(1, d.response_started_count());
+ EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, d.request_status());
// We should not have followed the redirect.
EXPECT_EQ(0, d.received_redirect_count());
EXPECT_EQ(1, network_delegate.error_count());
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, network_delegate.last_error());
+ EXPECT_THAT(network_delegate.last_error(),
+ IsError(ERR_TUNNEL_CONNECTION_FAILED));
}
}
@@ -3645,7 +3680,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateBlockAsynchronously) {
}
base::RunLoop().Run();
EXPECT_EQ(200, r->GetResponseCode());
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
@@ -3672,10 +3707,9 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateCancelRequest) {
r->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::FAILED, r->status().status());
// The proxy server is not set before cancellation.
- EXPECT_TRUE(r->proxy_server().IsEmpty());
- EXPECT_EQ(ERR_EMPTY_RESPONSE, r->status().error());
+ EXPECT_FALSE(r->proxy_server().is_valid());
+ EXPECT_EQ(ERR_EMPTY_RESPONSE, d.request_status());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
@@ -3705,10 +3739,16 @@ void NetworkDelegateCancelRequest(BlockingNetworkDelegate::BlockMode block_mode,
r->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::FAILED, r->status().status());
// The proxy server is not set before cancellation.
- EXPECT_TRUE(r->proxy_server().IsEmpty());
- EXPECT_EQ(ERR_BLOCKED_BY_CLIENT, r->status().error());
+ if (stage == BlockingNetworkDelegate::ON_BEFORE_URL_REQUEST ||
+ stage == BlockingNetworkDelegate::ON_BEFORE_SEND_HEADERS) {
+ EXPECT_FALSE(r->proxy_server().is_valid());
+ } else if (stage == BlockingNetworkDelegate::ON_HEADERS_RECEIVED) {
+ EXPECT_TRUE(r->proxy_server().is_direct());
+ } else {
+ NOTREACHED();
+ }
+ EXPECT_EQ(ERR_BLOCKED_BY_CLIENT, d.request_status());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
@@ -3787,7 +3827,6 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateRedirectRequest) {
base::RunLoop().Run();
// Check headers from URLRequestJob.
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
EXPECT_EQ(307, r->GetResponseCode());
EXPECT_EQ(307, r->response_headers()->response_code());
std::string location;
@@ -3798,15 +3837,17 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateRedirectRequest) {
// Let the request finish.
r->FollowDeferredRedirect();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_TRUE(r->proxy_server().Equals(http_test_server()->host_port_pair()));
+ EXPECT_EQ(OK, d.request_status());
+ EXPECT_EQ(ProxyServer(ProxyServer::SCHEME_HTTP,
+ http_test_server()->host_port_pair()),
+ r->proxy_server());
// before_send_headers_with_proxy_count only increments for headers sent
// through an untunneled proxy.
EXPECT_EQ(1, network_delegate.before_send_headers_with_proxy_count());
EXPECT_TRUE(network_delegate.last_observed_proxy().Equals(
http_test_server()->host_port_pair()));
- EXPECT_EQ(0, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(redirect_url, r->url());
EXPECT_EQ(original_url, r->original_url());
EXPECT_EQ(2U, r->url_chain().size());
@@ -3841,7 +3882,6 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateRedirectRequestSynchronously) {
base::RunLoop().Run();
// Check headers from URLRequestJob.
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
EXPECT_EQ(307, r->GetResponseCode());
EXPECT_EQ(307, r->response_headers()->response_code());
std::string location;
@@ -3853,14 +3893,16 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateRedirectRequestSynchronously) {
r->FollowDeferredRedirect();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_TRUE(r->proxy_server().Equals(http_test_server()->host_port_pair()));
+ EXPECT_EQ(OK, d.request_status());
+ EXPECT_EQ(ProxyServer(ProxyServer::SCHEME_HTTP,
+ http_test_server()->host_port_pair()),
+ r->proxy_server());
// before_send_headers_with_proxy_count only increments for headers sent
// through an untunneled proxy.
EXPECT_EQ(1, network_delegate.before_send_headers_with_proxy_count());
EXPECT_TRUE(network_delegate.last_observed_proxy().Equals(
http_test_server()->host_port_pair()));
- EXPECT_EQ(0, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(redirect_url, r->url());
EXPECT_EQ(original_url, r->original_url());
EXPECT_EQ(2U, r->url_chain().size());
@@ -3904,7 +3946,6 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateRedirectRequestPost) {
base::RunLoop().Run();
// Check headers from URLRequestJob.
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
EXPECT_EQ(307, r->GetResponseCode());
EXPECT_EQ(307, r->response_headers()->response_code());
std::string location;
@@ -3916,8 +3957,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateRedirectRequestPost) {
r->FollowDeferredRedirect();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(0, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(redirect_url, r->url());
EXPECT_EQ(original_url, r->original_url());
EXPECT_EQ(2U, r->url_chain().size());
@@ -3952,15 +3992,17 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateRedirectRequestOnHeadersReceived) {
r->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_TRUE(r->proxy_server().Equals(http_test_server()->host_port_pair()));
+ EXPECT_EQ(OK, d.request_status());
+ EXPECT_EQ(ProxyServer(ProxyServer::SCHEME_HTTP,
+ http_test_server()->host_port_pair()),
+ r->proxy_server());
// before_send_headers_with_proxy_count only increments for headers sent
// through an untunneled proxy.
EXPECT_EQ(2, network_delegate.before_send_headers_with_proxy_count());
EXPECT_TRUE(network_delegate.last_observed_proxy().Equals(
http_test_server()->host_port_pair()));
- EXPECT_EQ(OK, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(redirect_url, r->url());
EXPECT_EQ(original_url, r->original_url());
EXPECT_EQ(2U, r->url_chain().size());
@@ -3995,8 +4037,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredSyncNoAction) {
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(0, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(200, r->GetResponseCode());
EXPECT_TRUE(d.auth_required_called());
EXPECT_EQ(1, network_delegate.created_requests());
@@ -4033,8 +4074,7 @@ TEST_F(URLRequestTestHTTP,
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(0, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(200, r->GetResponseCode());
EXPECT_TRUE(d.auth_required_called());
EXPECT_EQ(1, network_delegate.created_requests());
@@ -4068,8 +4108,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredSyncSetAuth) {
r->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(0, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(200, r->GetResponseCode());
EXPECT_FALSE(d.auth_required_called());
EXPECT_EQ(1, network_delegate.created_requests());
@@ -4104,8 +4143,7 @@ TEST_F(URLRequestTestHTTP,
r->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(0, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(200, r->GetResponseCode());
EXPECT_FALSE(d.auth_required_called());
EXPECT_EQ(1, network_delegate.created_requests());
@@ -4143,8 +4181,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredSyncCancel) {
r->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(OK, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(401, r->GetResponseCode());
EXPECT_FALSE(d.auth_required_called());
EXPECT_EQ(1, network_delegate.created_requests());
@@ -4178,8 +4215,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredAsyncNoAction) {
r->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(0, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(200, r->GetResponseCode());
EXPECT_TRUE(d.auth_required_called());
EXPECT_EQ(1, network_delegate.created_requests());
@@ -4214,9 +4250,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredAsyncSetAuth) {
r->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(0, r->status().error());
-
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(200, r->GetResponseCode());
EXPECT_FALSE(d.auth_required_called());
EXPECT_EQ(1, network_delegate.created_requests());
@@ -4248,8 +4282,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredAsyncCancel) {
r->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(OK, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(401, r->GetResponseCode());
EXPECT_FALSE(d.auth_required_called());
EXPECT_EQ(1, network_delegate.created_requests());
@@ -4286,8 +4319,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateCancelWhileWaiting1) {
r->Cancel();
// Ensure that network delegate is notified.
EXPECT_EQ(1, network_delegate.completed_requests());
- EXPECT_EQ(URLRequestStatus::CANCELED, r->status().status());
- EXPECT_EQ(ERR_ABORTED, r->status().error());
+ EXPECT_EQ(1, network_delegate.canceled_requests());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
@@ -4324,8 +4356,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateCancelWhileWaiting2) {
r->Cancel();
// Ensure that network delegate is notified.
EXPECT_EQ(1, network_delegate.completed_requests());
- EXPECT_EQ(URLRequestStatus::CANCELED, r->status().status());
- EXPECT_EQ(ERR_ABORTED, r->status().error());
+ EXPECT_EQ(1, network_delegate.canceled_requests());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
@@ -4360,8 +4391,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateCancelWhileWaiting3) {
r->Cancel();
// Ensure that network delegate is notified.
EXPECT_EQ(1, network_delegate.completed_requests());
- EXPECT_EQ(URLRequestStatus::CANCELED, r->status().status());
- EXPECT_EQ(ERR_ABORTED, r->status().error());
+ EXPECT_EQ(1, network_delegate.canceled_requests());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
@@ -4396,8 +4426,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateCancelWhileWaiting4) {
r->Cancel();
// Ensure that network delegate is notified.
EXPECT_EQ(1, network_delegate.completed_requests());
- EXPECT_EQ(URLRequestStatus::CANCELED, r->status().status());
- EXPECT_EQ(ERR_ABORTED, r->status().error());
+ EXPECT_EQ(1, network_delegate.canceled_requests());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
@@ -4446,10 +4475,9 @@ TEST_F(URLRequestTestHTTP, UnexpectedServerAuthTest) {
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::FAILED, r->status().status());
// The proxy server is not set before failure.
- EXPECT_TRUE(r->proxy_server().IsEmpty());
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, r->status().error());
+ EXPECT_FALSE(r->proxy_server().is_valid());
+ EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, d.request_status());
}
}
@@ -4623,7 +4651,14 @@ TEST_F(URLRequestTestHTTP, GetZippedTest) {
const bool test_expect_success[num_tests] =
{ true, true, false, false, true };
- for (int i = 0; i < num_tests ; i++) {
+ base::FilePath file_path;
+ PathService::Get(base::DIR_SOURCE_ROOT, &file_path);
+ file_path = file_path.Append(kTestFilePath);
+ file_path = file_path.Append(FILE_PATH_LITERAL("BullRunSpeech.txt"));
+ std::string expected_content;
+ ASSERT_TRUE(base::ReadFileToString(file_path, &expected_content));
+
+ for (int i = 0; i < num_tests; i++) {
TestDelegate d;
{
std::string test_file = base::StringPrintf(
@@ -4644,14 +4679,19 @@ TEST_F(URLRequestTestHTTP, GetZippedTest) {
EXPECT_EQ(1, d.response_started_count());
EXPECT_FALSE(d.received_data_before_response());
VLOG(1) << " Received " << d.bytes_received() << " bytes"
- << " status = " << r->status().status()
- << " error = " << r->status().error();
+ << " error = " << d.request_status();
if (test_expect_success[i]) {
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status())
- << " Parameter = \"" << test_file << "\"";
+ EXPECT_EQ(OK, d.request_status()) << " Parameter = \"" << test_file
+ << "\"";
+ if (test_parameters[i] == 'S') {
+ // When content length is smaller than both compressed length and
+ // uncompressed length, HttpStreamParser might not read the full
+ // response body.
+ continue;
+ }
+ EXPECT_EQ(expected_content, d.data_received());
} else {
- EXPECT_EQ(URLRequestStatus::FAILED, r->status().status());
- EXPECT_EQ(ERR_CONTENT_LENGTH_MISMATCH, r->status().error())
+ EXPECT_EQ(ERR_CONTENT_LENGTH_MISMATCH, d.request_status())
<< " Parameter = \"" << test_file << "\"";
}
}
@@ -4764,42 +4804,27 @@ class AsyncDelegateLogger : public base::RefCounted<AsyncDelegateLogger> {
return entries.size();
}
std::string delegate_info;
- EXPECT_EQ(NetLog::TYPE_DELEGATE_INFO, entries[log_position].type);
- EXPECT_EQ(NetLog::PHASE_BEGIN, entries[log_position].phase);
+ EXPECT_EQ(NetLogEventType::DELEGATE_INFO, entries[log_position].type);
+ EXPECT_EQ(NetLogEventPhase::BEGIN, entries[log_position].phase);
EXPECT_TRUE(entries[log_position].GetStringValue("delegate_info",
&delegate_info));
EXPECT_EQ(kFirstDelegateInfo, delegate_info);
++log_position;
- EXPECT_EQ(NetLog::TYPE_DELEGATE_INFO, entries[log_position].type);
- EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+ EXPECT_EQ(NetLogEventType::DELEGATE_INFO, entries[log_position].type);
+ EXPECT_EQ(NetLogEventPhase::END, entries[log_position].phase);
++log_position;
- EXPECT_EQ(NetLog::TYPE_DELEGATE_INFO, entries[log_position].type);
- EXPECT_EQ(NetLog::PHASE_BEGIN, entries[log_position].phase);
+ EXPECT_EQ(NetLogEventType::DELEGATE_INFO, entries[log_position].type);
+ EXPECT_EQ(NetLogEventPhase::BEGIN, entries[log_position].phase);
EXPECT_TRUE(entries[log_position].GetStringValue("delegate_info",
&delegate_info));
EXPECT_EQ(kSecondDelegateInfo, delegate_info);
++log_position;
- EXPECT_EQ(NetLog::TYPE_DELEGATE_INFO, entries[log_position].type);
- EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
-
- return log_position + 1;
- }
+ EXPECT_EQ(NetLogEventType::DELEGATE_INFO, entries[log_position].type);
+ EXPECT_EQ(NetLogEventPhase::END, entries[log_position].phase);
- // Find delegate request begin and end messages for OnBeforeNetworkStart.
- // Returns the position of the end message.
- static size_t ExpectBeforeNetworkEvents(const TestNetLogEntry::List& entries,
- size_t log_position) {
- log_position =
- ExpectLogContainsSomewhereAfter(entries,
- log_position,
- NetLog::TYPE_URL_REQUEST_DELEGATE,
- NetLog::PHASE_BEGIN);
- EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE,
- entries[log_position + 1].type);
- EXPECT_EQ(NetLog::PHASE_END, entries[log_position + 1].phase);
return log_position + 1;
}
@@ -4975,15 +5000,13 @@ class AsyncLoggingUrlRequestDelegate : public TestDelegate {
base::Unretained(this), request, redirect_info));
}
- void OnResponseStarted(URLRequest* request) override {
+ void OnResponseStarted(URLRequest* request, int net_error) override {
AsyncDelegateLogger::Run(
- request,
- LOAD_STATE_WAITING_FOR_DELEGATE,
- LOAD_STATE_WAITING_FOR_DELEGATE,
- LOAD_STATE_WAITING_FOR_DELEGATE,
- base::Bind(
- &AsyncLoggingUrlRequestDelegate::OnResponseStartedLoggingComplete,
- base::Unretained(this), request));
+ request, LOAD_STATE_WAITING_FOR_DELEGATE,
+ LOAD_STATE_WAITING_FOR_DELEGATE, LOAD_STATE_WAITING_FOR_DELEGATE,
+ base::Bind(
+ &AsyncLoggingUrlRequestDelegate::OnResponseStartedLoggingComplete,
+ base::Unretained(this), request, net_error));
}
void OnReadCompleted(URLRequest* request, int bytes_read) override {
@@ -5009,9 +5032,9 @@ class AsyncLoggingUrlRequestDelegate : public TestDelegate {
request->FollowDeferredRedirect();
}
- void OnResponseStartedLoggingComplete(URLRequest* request) {
+ void OnResponseStartedLoggingComplete(URLRequest* request, int net_error) {
// The parent class continues the request.
- TestDelegate::OnResponseStarted(request);
+ TestDelegate::OnResponseStarted(request, net_error);
}
void AfterReadCompletedLoggingComplete(URLRequest* request, int bytes_read) {
@@ -5052,22 +5075,19 @@ TEST_F(URLRequestTestHTTP, DelegateInfoBeforeStart) {
base::RunLoop().Run();
EXPECT_EQ(200, r->GetResponseCode());
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
+ EXPECT_EQ(OK, request_delegate.request_status());
}
TestNetLogEntry::List entries;
net_log_.GetEntries(&entries);
size_t log_position = ExpectLogContainsSomewhereAfter(
- entries,
- 0,
- NetLog::TYPE_DELEGATE_INFO,
- NetLog::PHASE_BEGIN);
+ entries, 0, NetLogEventType::DELEGATE_INFO, NetLogEventPhase::BEGIN);
log_position = AsyncDelegateLogger::CheckDelegateInfo(entries, log_position);
// Nothing else should add any delegate info to the request.
- EXPECT_FALSE(LogContainsEntryWithTypeAfter(
- entries, log_position + 1, NetLog::TYPE_DELEGATE_INFO));
+ EXPECT_FALSE(LogContainsEntryWithTypeAfter(entries, log_position + 1,
+ NetLogEventType::DELEGATE_INFO));
}
// Tests handling of delegate info from a network delegate.
@@ -5093,7 +5113,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateInfo) {
base::RunLoop().Run();
EXPECT_EQ(200, r->GetResponseCode());
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
+ EXPECT_EQ(OK, request_delegate.request_status());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
@@ -5104,26 +5124,20 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateInfo) {
net_log_.GetEntries(&entries);
for (size_t i = 0; i < 3; ++i) {
log_position = ExpectLogContainsSomewhereAfter(
- entries,
- log_position + 1,
- NetLog::TYPE_URL_REQUEST_DELEGATE,
- NetLog::PHASE_BEGIN);
+ entries, log_position + 1, NetLogEventType::URL_REQUEST_DELEGATE,
+ NetLogEventPhase::BEGIN);
log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
log_position + 1);
ASSERT_LT(log_position, entries.size());
- EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
- EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
-
- if (i == 1) {
- log_position = AsyncDelegateLogger::ExpectBeforeNetworkEvents(
- entries, log_position + 1);
- }
+ EXPECT_EQ(NetLogEventType::URL_REQUEST_DELEGATE,
+ entries[log_position].type);
+ EXPECT_EQ(NetLogEventPhase::END, entries[log_position].phase);
}
- EXPECT_FALSE(LogContainsEntryWithTypeAfter(
- entries, log_position + 1, NetLog::TYPE_DELEGATE_INFO));
+ EXPECT_FALSE(LogContainsEntryWithTypeAfter(entries, log_position + 1,
+ NetLogEventType::DELEGATE_INFO));
}
// Tests handling of delegate info from a network delegate in the case of an
@@ -5150,7 +5164,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateInfoRedirect) {
base::RunLoop().Run();
EXPECT_EQ(200, r->GetResponseCode());
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
+ EXPECT_EQ(OK, request_delegate.request_status());
EXPECT_EQ(2, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
@@ -5163,49 +5177,40 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateInfoRedirect) {
// OnBeforeStartTransaction, and OnHeadersReceived.
for (size_t i = 0; i < 3; ++i) {
log_position = ExpectLogContainsSomewhereAfter(
- entries,
- log_position + 1,
- NetLog::TYPE_URL_REQUEST_DELEGATE,
- NetLog::PHASE_BEGIN);
+ entries, log_position + 1, NetLogEventType::URL_REQUEST_DELEGATE,
+ NetLogEventPhase::BEGIN);
log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
log_position + 1);
ASSERT_LT(log_position, entries.size());
- EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
- EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
-
- if (i == 1) {
- log_position = AsyncDelegateLogger::ExpectBeforeNetworkEvents(
- entries, log_position + 1);
- }
+ EXPECT_EQ(NetLogEventType::URL_REQUEST_DELEGATE,
+ entries[log_position].type);
+ EXPECT_EQ(NetLogEventPhase::END, entries[log_position].phase);
}
// The URLRequest::Delegate then gets informed about the redirect.
log_position = ExpectLogContainsSomewhereAfter(
- entries,
- log_position + 1,
- NetLog::TYPE_URL_REQUEST_DELEGATE,
- NetLog::PHASE_BEGIN);
+ entries, log_position + 1, NetLogEventType::URL_REQUEST_DELEGATE,
+ NetLogEventPhase::BEGIN);
// The NetworkDelegate logged information in the same three events as before.
for (size_t i = 0; i < 3; ++i) {
log_position = ExpectLogContainsSomewhereAfter(
- entries,
- log_position + 1,
- NetLog::TYPE_URL_REQUEST_DELEGATE,
- NetLog::PHASE_BEGIN);
+ entries, log_position + 1, NetLogEventType::URL_REQUEST_DELEGATE,
+ NetLogEventPhase::BEGIN);
log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
log_position + 1);
ASSERT_LT(log_position, entries.size());
- EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
- EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+ EXPECT_EQ(NetLogEventType::URL_REQUEST_DELEGATE,
+ entries[log_position].type);
+ EXPECT_EQ(NetLogEventPhase::END, entries[log_position].phase);
}
- EXPECT_FALSE(LogContainsEntryWithTypeAfter(
- entries, log_position + 1, NetLog::TYPE_DELEGATE_INFO));
+ EXPECT_FALSE(LogContainsEntryWithTypeAfter(entries, log_position + 1,
+ NetLogEventType::DELEGATE_INFO));
}
// Tests handling of delegate info from a network delegate in the case of HTTP
@@ -5232,7 +5237,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateInfoAuth) {
base::RunLoop().Run();
EXPECT_EQ(200, r->GetResponseCode());
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
+ EXPECT_EQ(OK, request_delegate.request_status());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
@@ -5247,26 +5252,20 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateInfoAuth) {
// OnBeforeURLRequest and OnBeforeStartTransaction.
for (size_t i = 0; i < 6; ++i) {
log_position = ExpectLogContainsSomewhereAfter(
- entries,
- log_position + 1,
- NetLog::TYPE_URL_REQUEST_DELEGATE,
- NetLog::PHASE_BEGIN);
+ entries, log_position + 1, NetLogEventType::URL_REQUEST_DELEGATE,
+ NetLogEventPhase::BEGIN);
log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
log_position + 1);
ASSERT_LT(log_position, entries.size());
- EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
- EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
-
- if (i == 1) {
- log_position = AsyncDelegateLogger::ExpectBeforeNetworkEvents(
- entries, log_position + 1);
- }
+ EXPECT_EQ(NetLogEventType::URL_REQUEST_DELEGATE,
+ entries[log_position].type);
+ EXPECT_EQ(NetLogEventPhase::END, entries[log_position].phase);
}
- EXPECT_FALSE(LogContainsEntryWithTypeAfter(
- entries, log_position + 1, NetLog::TYPE_DELEGATE_INFO));
+ EXPECT_FALSE(LogContainsEntryWithTypeAfter(entries, log_position + 1,
+ NetLogEventType::DELEGATE_INFO));
}
// TODO(svaldez): Update tests to use EmbeddedTestServer.
@@ -5300,7 +5299,7 @@ TEST_F(URLRequestTestHTTP, URLRequestDelegateInfo) {
base::RunLoop().Run();
EXPECT_EQ(200, r->GetResponseCode());
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
+ EXPECT_EQ(OK, request_delegate.request_status());
}
TestNetLogEntry::List entries;
@@ -5308,28 +5307,23 @@ TEST_F(URLRequestTestHTTP, URLRequestDelegateInfo) {
size_t log_position = 0;
- log_position = AsyncDelegateLogger::ExpectBeforeNetworkEvents(
- entries, log_position);
-
// The delegate info should only have been logged on header complete. Other
// times it should silently be ignored.
- log_position =
- ExpectLogContainsSomewhereAfter(entries,
- log_position + 1,
- NetLog::TYPE_URL_REQUEST_DELEGATE,
- NetLog::PHASE_BEGIN);
+ log_position = ExpectLogContainsSomewhereAfter(
+ entries, log_position + 1, NetLogEventType::URL_REQUEST_DELEGATE,
+ NetLogEventPhase::BEGIN);
log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
log_position + 1);
ASSERT_LT(log_position, entries.size());
- EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
- EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+ EXPECT_EQ(NetLogEventType::URL_REQUEST_DELEGATE, entries[log_position].type);
+ EXPECT_EQ(NetLogEventPhase::END, entries[log_position].phase);
+ EXPECT_FALSE(LogContainsEntryWithTypeAfter(entries, log_position + 1,
+ NetLogEventType::DELEGATE_INFO));
EXPECT_FALSE(LogContainsEntryWithTypeAfter(
- entries, log_position + 1, NetLog::TYPE_DELEGATE_INFO));
- EXPECT_FALSE(LogContainsEntryWithTypeAfter(
- entries, log_position + 1, NetLog::TYPE_URL_REQUEST_DELEGATE));
+ entries, log_position + 1, NetLogEventType::URL_REQUEST_DELEGATE));
}
#endif // !defined(OS_IOS)
@@ -5354,7 +5348,7 @@ TEST_F(URLRequestTestHTTP, URLRequestDelegateInfoOnRedirect) {
base::RunLoop().Run();
EXPECT_EQ(200, r->GetResponseCode());
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
+ EXPECT_EQ(OK, request_delegate.request_status());
}
TestNetLogEntry::List entries;
@@ -5364,29 +5358,23 @@ TEST_F(URLRequestTestHTTP, URLRequestDelegateInfoOnRedirect) {
// OnResponseStarted.
size_t log_position = 0;
for (int i = 0; i < 2; ++i) {
- if (i == 0) {
- log_position = AsyncDelegateLogger::ExpectBeforeNetworkEvents(
- entries, log_position) + 1;
- }
-
log_position = ExpectLogContainsSomewhereAfter(
- entries,
- log_position,
- NetLog::TYPE_URL_REQUEST_DELEGATE,
- NetLog::PHASE_BEGIN);
+ entries, log_position, NetLogEventType::URL_REQUEST_DELEGATE,
+ NetLogEventPhase::BEGIN);
log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
log_position + 1);
ASSERT_LT(log_position, entries.size());
- EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
- EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+ EXPECT_EQ(NetLogEventType::URL_REQUEST_DELEGATE,
+ entries[log_position].type);
+ EXPECT_EQ(NetLogEventPhase::END, entries[log_position].phase);
}
+ EXPECT_FALSE(LogContainsEntryWithTypeAfter(entries, log_position + 1,
+ NetLogEventType::DELEGATE_INFO));
EXPECT_FALSE(LogContainsEntryWithTypeAfter(
- entries, log_position + 1, NetLog::TYPE_DELEGATE_INFO));
- EXPECT_FALSE(LogContainsEntryWithTypeAfter(
- entries, log_position + 1, NetLog::TYPE_URL_REQUEST_DELEGATE));
+ entries, log_position + 1, NetLogEventType::URL_REQUEST_DELEGATE));
}
// Tests handling of delegate info from a URLRequest::Delegate in the case of
@@ -5416,7 +5404,7 @@ TEST_F(URLRequestTestHTTP, URLRequestDelegateOnRedirectCancelled) {
LoadStateWithParam load_state = r->GetLoadState();
r->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::CANCELED, r->status().status());
+ EXPECT_EQ(ERR_ABORTED, request_delegate.request_status());
}
TestNetLogEntry::List entries;
@@ -5428,29 +5416,23 @@ TEST_F(URLRequestTestHTTP, URLRequestDelegateOnRedirectCancelled) {
// still currently supported in that call.
size_t log_position = 0;
for (int i = 0; i < 2; ++i) {
- if (i == 0) {
- log_position = AsyncDelegateLogger::ExpectBeforeNetworkEvents(
- entries, log_position) + 1;
- }
-
log_position = ExpectLogContainsSomewhereAfter(
- entries,
- log_position,
- NetLog::TYPE_URL_REQUEST_DELEGATE,
- NetLog::PHASE_BEGIN);
+ entries, log_position, NetLogEventType::URL_REQUEST_DELEGATE,
+ NetLogEventPhase::BEGIN);
log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
log_position + 1);
ASSERT_LT(log_position, entries.size());
- EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
- EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+ EXPECT_EQ(NetLogEventType::URL_REQUEST_DELEGATE,
+ entries[log_position].type);
+ EXPECT_EQ(NetLogEventPhase::END, entries[log_position].phase);
}
+ EXPECT_FALSE(LogContainsEntryWithTypeAfter(entries, log_position + 1,
+ NetLogEventType::DELEGATE_INFO));
EXPECT_FALSE(LogContainsEntryWithTypeAfter(
- entries, log_position + 1, NetLog::TYPE_DELEGATE_INFO));
- EXPECT_FALSE(LogContainsEntryWithTypeAfter(
- entries, log_position + 1, NetLog::TYPE_URL_REQUEST_DELEGATE));
+ entries, log_position + 1, NetLogEventType::URL_REQUEST_DELEGATE));
}
}
@@ -5568,7 +5550,7 @@ TEST_F(URLRequestTestHTTP, CancelTest2) {
EXPECT_EQ(1, d.response_started_count());
EXPECT_EQ(0, d.bytes_received());
EXPECT_FALSE(d.received_data_before_response());
- EXPECT_EQ(URLRequestStatus::CANCELED, r->status().status());
+ EXPECT_EQ(ERR_ABORTED, d.request_status());
}
}
@@ -5593,7 +5575,7 @@ TEST_F(URLRequestTestHTTP, CancelTest3) {
// or it could have been all the bytes.
// EXPECT_EQ(0, d.bytes_received());
EXPECT_FALSE(d.received_data_before_response());
- EXPECT_EQ(URLRequestStatus::CANCELED, r->status().status());
+ EXPECT_EQ(ERR_ABORTED, d.request_status());
}
}
@@ -5633,7 +5615,7 @@ TEST_F(URLRequestTestHTTP, CancelTest5) {
http_test_server()->GetURL("/cachetime"), DEFAULT_PRIORITY, &d));
r->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
+ EXPECT_EQ(OK, d.request_status());
}
// cancel read from cache (see bug 990242)
@@ -5645,7 +5627,7 @@ TEST_F(URLRequestTestHTTP, CancelTest5) {
r->Cancel();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::CANCELED, r->status().status());
+ EXPECT_EQ(ERR_ABORTED, d.request_status());
EXPECT_EQ(1, d.response_started_count());
EXPECT_EQ(0, d.bytes_received());
EXPECT_FALSE(d.received_data_before_response());
@@ -5676,9 +5658,8 @@ TEST_F(URLRequestTestHTTP, PostEmptyTest) {
base::RunLoop().Run();
- ASSERT_EQ(1, d.response_started_count())
- << "request failed: " << r->status().status()
- << ", error: " << r->status().error();
+ ASSERT_EQ(1, d.response_started_count()) << "request failed. Error: "
+ << d.request_status();
EXPECT_FALSE(d.received_data_before_response());
EXPECT_TRUE(d.data_received().empty());
@@ -5704,9 +5685,9 @@ TEST_F(URLRequestTestHTTP, PostFileTest) {
PathService::Get(base::DIR_SOURCE_ROOT, &path);
path = path.Append(kTestFilePath);
path = path.Append(FILE_PATH_LITERAL("with-headers.html"));
- element_readers.push_back(base::WrapUnique(new UploadFileElementReader(
+ element_readers.push_back(base::MakeUnique<UploadFileElementReader>(
base::ThreadTaskRunnerHandle::Get().get(), path, 0,
- std::numeric_limits<uint64_t>::max(), base::Time())));
+ std::numeric_limits<uint64_t>::max(), base::Time()));
r->set_upload(base::WrapUnique<UploadDataStream>(
new ElementsUploadDataStream(std::move(element_readers), 0)));
@@ -5723,9 +5704,8 @@ TEST_F(URLRequestTestHTTP, PostFileTest) {
ASSERT_EQ(size, base::ReadFile(path, buf.get(), size));
- ASSERT_EQ(1, d.response_started_count())
- << "request failed: " << r->status().status()
- << ", error: " << r->status().error();
+ ASSERT_EQ(1, d.response_started_count()) << "request failed. Error: "
+ << d.request_status();
EXPECT_FALSE(d.received_data_before_response());
@@ -5745,11 +5725,11 @@ TEST_F(URLRequestTestHTTP, PostUnreadableFileTest) {
std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(base::WrapUnique(new UploadFileElementReader(
+ element_readers.push_back(base::MakeUnique<UploadFileElementReader>(
base::ThreadTaskRunnerHandle::Get().get(),
base::FilePath(FILE_PATH_LITERAL(
"c:\\path\\to\\non\\existant\\file.randomness.12345")),
- 0, std::numeric_limits<uint64_t>::max(), base::Time())));
+ 0, std::numeric_limits<uint64_t>::max(), base::Time()));
r->set_upload(base::WrapUnique<UploadDataStream>(
new ElementsUploadDataStream(std::move(element_readers), 0)));
@@ -5761,8 +5741,7 @@ TEST_F(URLRequestTestHTTP, PostUnreadableFileTest) {
EXPECT_TRUE(d.request_failed());
EXPECT_FALSE(d.received_data_before_response());
EXPECT_EQ(0, d.bytes_received());
- EXPECT_EQ(URLRequestStatus::FAILED, r->status().status());
- EXPECT_EQ(ERR_FILE_NOT_FOUND, r->status().error());
+ EXPECT_EQ(ERR_FILE_NOT_FOUND, d.request_status());
}
}
@@ -5786,9 +5765,8 @@ void VerifyReceivedDataMatchesChunks(URLRequest* r, TestDelegate* d) {
const std::string expected_data =
"abcdthis is a longer chunk than before.\r\n\r\n02323";
- ASSERT_EQ(1, d->response_started_count())
- << "request failed: " << r->status().status()
- << ", os error: " << r->status().error();
+ ASSERT_EQ(1, d->response_started_count()) << "request failed. Error: "
+ << d->request_status();
EXPECT_FALSE(d->received_data_before_response());
@@ -5955,31 +5933,16 @@ TEST_F(URLRequestTestHTTP, STSNotProcessedOnIP) {
security_state->GetDynamicSTSState(test_server_hostname, &sts_state));
}
-// Android's CertVerifyProc does not (yet) handle pins. Therefore, it will
-// reject HPKP headers, and a test setting only HPKP headers will fail (no
-// PKPState present because header rejected).
-#if defined(OS_ANDROID)
-#define MAYBE_ProcessPKP DISABLED_ProcessPKP
-#define MAYBE_ProcessPKPAndSendReport DISABLED_ProcessPKPAndSendReport
-#define MAYBE_ProcessPKPReportOnly DISABLED_ProcessPKPReportOnly
-#define MAYBE_ProcessPKPReportOnlyWithNoViolation \
- DISABLED_ProcessPKPReportOnlyWithNoViolation
-#else
-#define MAYBE_ProcessPKP ProcessPKP
-#define MAYBE_ProcessPKPAndSendReport ProcessPKPAndSendReport
-#define MAYBE_ProcessPKPReportOnly ProcessPKPReportOnly
-#define MAYBE_ProcessPKPReportOnlyWithNoViolation \
- ProcessPKPReportOnlyWithNoViolation
-#endif
-
namespace {
const char kExpectCTStaticHostname[] = "preloaded-expect-ct.badssl.com";
+const char kExpectStapleStaticHostname[] = "preloaded-expect-staple.badssl.com";
+const char kExpectStapleReportURI[] = "https://report.badssl.com/expect-staple";
const char kHPKPReportUri[] = "https://hpkp-report.test";
} // namespace
// Tests that enabling HPKP on a domain does not affect the HSTS
// validity/expiration.
-TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKP) {
+TEST_F(URLRequestTestHTTP, ProcessPKP) {
GURL report_uri(kHPKPReportUri);
EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_test_server.SetSSLConfig(
@@ -6013,7 +5976,7 @@ TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKP) {
}
// Tests that reports get sent on HPKP violations when a report-uri is set.
-TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKPAndSendReport) {
+TEST_F(URLRequestTestHTTP, ProcessPKPAndSendReport) {
GURL report_uri(kHPKPReportUri);
EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_test_server.SetSSLConfig(
@@ -6078,6 +6041,8 @@ TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKPAndSendReport) {
// Check that a report was sent.
EXPECT_EQ(report_uri, mock_report_sender.latest_report_uri());
ASSERT_FALSE(mock_report_sender.latest_report().empty());
+ EXPECT_EQ("application/json; charset=utf-8",
+ mock_report_sender.latest_content_type());
std::unique_ptr<base::Value> value(
base::JSONReader::Read(mock_report_sender.latest_report()));
ASSERT_TRUE(value);
@@ -6091,7 +6056,7 @@ TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKPAndSendReport) {
// Tests that reports get sent on requests with
// Public-Key-Pins-Report-Only headers.
-TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKPReportOnly) {
+TEST_F(URLRequestTestHTTP, ProcessPKPReportOnly) {
GURL report_uri(kHPKPReportUri);
EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_test_server.SetSSLConfig(
@@ -6141,6 +6106,8 @@ TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKPReportOnly) {
// Check that a report was sent.
EXPECT_EQ(report_uri, mock_report_sender.latest_report_uri());
ASSERT_FALSE(mock_report_sender.latest_report().empty());
+ EXPECT_EQ("application/json; charset=utf-8",
+ mock_report_sender.latest_content_type());
std::unique_ptr<base::Value> value(
base::JSONReader::Read(mock_report_sender.latest_report()));
ASSERT_TRUE(value);
@@ -6154,7 +6121,7 @@ TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKPReportOnly) {
// Tests that reports do not get sent on requests with
// Public-Key-Pins-Report-Only headers that don't have pin violations.
-TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKPReportOnlyWithNoViolation) {
+TEST_F(URLRequestTestHTTP, ProcessPKPReportOnlyWithNoViolation) {
GURL report_uri(kHPKPReportUri);
EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_test_server.SetSSLConfig(
@@ -6412,7 +6379,7 @@ class MockCTVerifier : public CTVerifier {
const std::string& stapled_ocsp_response,
const std::string& sct_list_from_tls_extension,
ct::CTVerifyResult* result,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
return net::OK;
}
@@ -6431,7 +6398,7 @@ class MockCTPolicyEnforcer : public CTPolicyEnforcer {
ct::CertPolicyCompliance DoesConformToCertPolicy(
X509Certificate* cert,
const SCTList& verified_scts,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
return default_result_;
}
@@ -6555,8 +6522,7 @@ TEST_F(URLRequestTestHTTP, RestrictFileRedirects) {
req->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::FAILED, req->status().status());
- EXPECT_EQ(ERR_UNSAFE_REDIRECT, req->status().error());
+ EXPECT_EQ(ERR_UNSAFE_REDIRECT, d.request_status());
}
#endif // !defined(DISABLE_FILE_SUPPORT)
@@ -6570,8 +6536,7 @@ TEST_F(URLRequestTestHTTP, RestrictDataRedirects) {
req->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::FAILED, req->status().status());
- EXPECT_EQ(ERR_UNSAFE_REDIRECT, req->status().error());
+ EXPECT_EQ(ERR_UNSAFE_REDIRECT, d.request_status());
}
TEST_F(URLRequestTestHTTP, RedirectToInvalidURL) {
@@ -6584,8 +6549,7 @@ TEST_F(URLRequestTestHTTP, RedirectToInvalidURL) {
req->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::FAILED, req->status().status());
- EXPECT_EQ(ERR_INVALID_URL, req->status().error());
+ EXPECT_EQ(ERR_INVALID_URL, d.request_status());
}
// Make sure redirects are cached, despite not reading their bodies.
@@ -6600,7 +6564,7 @@ TEST_F(URLRequestTestHTTP, CacheRedirect) {
default_context_.CreateRequest(redirect_url, DEFAULT_PRIORITY, &d));
req->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, req->status().status());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(1, d.received_redirect_count());
EXPECT_EQ(http_test_server()->GetURL("/echo"), req->url());
}
@@ -6621,7 +6585,7 @@ TEST_F(URLRequestTestHTTP, CacheRedirect) {
base::RunLoop().Run();
EXPECT_EQ(1, d.received_redirect_count());
EXPECT_EQ(1, d.response_started_count());
- EXPECT_EQ(URLRequestStatus::SUCCESS, req->status().status());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(http_test_server()->GetURL("/echo"), req->url());
}
}
@@ -6644,7 +6608,7 @@ TEST_F(URLRequestTestHTTP, NoCacheOnNetworkDelegateRedirect) {
default_context_.CreateRequest(initial_url, DEFAULT_PRIORITY, &d));
req->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, req->status().status());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(1, d.received_redirect_count());
EXPECT_EQ(redirect_to_url, req->url());
}
@@ -6656,7 +6620,7 @@ TEST_F(URLRequestTestHTTP, NoCacheOnNetworkDelegateRedirect) {
req->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, req->status().status());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_FALSE(req->was_cached());
EXPECT_EQ(0, d.received_redirect_count());
EXPECT_EQ(initial_url, req->url());
@@ -6680,10 +6644,8 @@ TEST_F(URLRequestTestHTTP, UnsafeRedirectToWhitelistedUnsafeURL) {
r->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
-
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(2U, r->url_chain().size());
- EXPECT_EQ(OK, r->status().error());
EXPECT_EQ(unsafe_url, r->url());
EXPECT_EQ("this-is-considered-an-unsafe-url", d.data_received());
}
@@ -6708,8 +6670,7 @@ TEST_F(URLRequestTestHTTP, UnsafeRedirectToDifferentUnsafeURL) {
r->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::FAILED, r->status().status());
- EXPECT_EQ(ERR_UNSAFE_REDIRECT, r->status().error());
+ EXPECT_EQ(ERR_UNSAFE_REDIRECT, d.request_status());
}
}
@@ -6734,8 +6695,7 @@ TEST_F(URLRequestTestHTTP, UnsafeRedirectWithDifferentReferenceFragment) {
base::RunLoop().Run();
EXPECT_EQ(2U, r->url_chain().size());
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(OK, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(original_url, r->original_url());
EXPECT_EQ(expected_url, r->url());
}
@@ -6764,8 +6724,7 @@ TEST_F(URLRequestTestHTTP, RedirectWithReferenceFragmentAndUnrelatedUnsafeUrl) {
base::RunLoop().Run();
EXPECT_EQ(2U, r->url_chain().size());
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(OK, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(original_url, r->original_url());
EXPECT_EQ(expected_redirect_url, r->url());
}
@@ -6793,8 +6752,7 @@ TEST_F(URLRequestTestHTTP, RedirectWithReferenceFragment) {
base::RunLoop().Run();
EXPECT_EQ(2U, r->url_chain().size());
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(OK, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(original_url, r->original_url());
EXPECT_EQ(redirect_url, r->url());
}
@@ -6821,8 +6779,7 @@ TEST_F(URLRequestTestHTTP, RedirectJobWithReferenceFragment) {
r->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(OK, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(original_url, r->original_url());
EXPECT_EQ(redirect_url, r->url());
}
@@ -6881,96 +6838,6 @@ TEST_F(URLRequestTestHTTP, EmptyReferrerAfterValidReferrer) {
EXPECT_EQ(std::string("None"), d.data_received());
}
-// Defer network start and then resume, checking that the request was a success
-// and bytes were received.
-TEST_F(URLRequestTestHTTP, DeferredBeforeNetworkStart) {
- ASSERT_TRUE(http_test_server()->Start());
-
- TestDelegate d;
- {
- d.set_quit_on_network_start(true);
- GURL test_url(http_test_server()->GetURL("/echo"));
- std::unique_ptr<URLRequest> req(
- default_context_.CreateRequest(test_url, DEFAULT_PRIORITY, &d));
-
- req->Start();
- base::RunLoop().Run();
-
- EXPECT_EQ(1, d.received_before_network_start_count());
- EXPECT_EQ(0, d.response_started_count());
-
- req->ResumeNetworkStart();
- base::RunLoop().Run();
-
- EXPECT_EQ(1, d.response_started_count());
- EXPECT_NE(0, d.bytes_received());
- EXPECT_EQ(URLRequestStatus::SUCCESS, req->status().status());
- }
-}
-
-// Check that OnBeforeNetworkStart is only called once even if there is a
-// redirect.
-TEST_F(URLRequestTestHTTP, BeforeNetworkStartCalledOnce) {
- ASSERT_TRUE(http_test_server()->Start());
-
- TestDelegate d;
- {
- d.set_quit_on_redirect(true);
- d.set_quit_on_network_start(true);
- std::unique_ptr<URLRequest> req(default_context_.CreateRequest(
- http_test_server()->GetURL("/server-redirect?echo"), DEFAULT_PRIORITY,
- &d));
-
- req->Start();
- base::RunLoop().Run();
-
- EXPECT_EQ(1, d.received_before_network_start_count());
- EXPECT_EQ(0, d.response_started_count());
- EXPECT_EQ(0, d.received_redirect_count());
-
- req->ResumeNetworkStart();
- base::RunLoop().Run();
-
- EXPECT_EQ(1, d.received_redirect_count());
- req->FollowDeferredRedirect();
- base::RunLoop().Run();
-
- // Check that the redirect's new network transaction does not get propagated
- // to a second OnBeforeNetworkStart() notification.
- EXPECT_EQ(1, d.received_before_network_start_count());
-
- EXPECT_EQ(1, d.response_started_count());
- EXPECT_NE(0, d.bytes_received());
- EXPECT_EQ(URLRequestStatus::SUCCESS, req->status().status());
- }
-}
-
-// Cancel the request after learning that the request would use the network.
-TEST_F(URLRequestTestHTTP, CancelOnBeforeNetworkStart) {
- ASSERT_TRUE(http_test_server()->Start());
-
- TestDelegate d;
- {
- d.set_quit_on_network_start(true);
- GURL test_url(http_test_server()->GetURL("/echo"));
- std::unique_ptr<URLRequest> req(
- default_context_.CreateRequest(test_url, DEFAULT_PRIORITY, &d));
-
- req->Start();
- base::RunLoop().Run();
-
- EXPECT_EQ(1, d.received_before_network_start_count());
- EXPECT_EQ(0, d.response_started_count());
-
- req->Cancel();
- base::RunLoop().Run();
-
- EXPECT_EQ(1, d.response_started_count());
- EXPECT_EQ(0, d.bytes_received());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
- }
-}
-
TEST_F(URLRequestTestHTTP, CancelRedirect) {
ASSERT_TRUE(http_test_server()->Start());
@@ -6986,7 +6853,7 @@ TEST_F(URLRequestTestHTTP, CancelRedirect) {
EXPECT_EQ(1, d.response_started_count());
EXPECT_EQ(0, d.bytes_received());
EXPECT_FALSE(d.received_data_before_response());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
+ EXPECT_EQ(ERR_ABORTED, d.request_status());
}
}
@@ -7010,7 +6877,7 @@ TEST_F(URLRequestTestHTTP, DeferredRedirect) {
EXPECT_EQ(1, d.response_started_count());
EXPECT_FALSE(d.received_data_before_response());
- EXPECT_EQ(URLRequestStatus::SUCCESS, req->status().status());
+ EXPECT_EQ(OK, d.request_status());
base::FilePath path;
PathService::Get(base::DIR_SOURCE_ROOT, &path);
@@ -7051,7 +6918,7 @@ TEST_F(URLRequestTestHTTP, DeferredRedirect_GetFullRequestHeaders) {
EXPECT_TRUE(d.have_full_request_headers());
CheckFullRequestHeaders(d.full_request_headers(), target_url);
EXPECT_FALSE(d.received_data_before_response());
- EXPECT_EQ(URLRequestStatus::SUCCESS, req->status().status());
+ EXPECT_EQ(OK, d.request_status());
base::FilePath path;
PathService::Get(base::DIR_SOURCE_ROOT, &path);
@@ -7084,7 +6951,7 @@ TEST_F(URLRequestTestHTTP, CancelDeferredRedirect) {
EXPECT_EQ(1, d.response_started_count());
EXPECT_EQ(0, d.bytes_received());
EXPECT_FALSE(d.received_data_before_response());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
+ EXPECT_EQ(ERR_ABORTED, d.request_status());
}
}
@@ -7462,8 +7329,7 @@ TEST_F(URLRequestTestHTTP, NoRedirectOn308WithoutLocationHeader) {
request->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, request->status().status());
- EXPECT_EQ(OK, request->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(0, d.received_redirect_count());
EXPECT_EQ(308, request->response_headers()->response_code());
EXPECT_EQ("This is not a redirect.", d.data_received());
@@ -7485,8 +7351,7 @@ TEST_F(URLRequestTestHTTP, Redirect302PreserveReferenceFragment) {
base::RunLoop().Run();
EXPECT_EQ(2U, r->url_chain().size());
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(OK, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(original_url, r->original_url());
EXPECT_EQ(expected_url, r->url());
}
@@ -7508,8 +7373,7 @@ TEST_F(URLRequestTestHTTP, RedirectPreserveFirstPartyURL) {
base::RunLoop().Run();
EXPECT_EQ(2U, r->url_chain().size());
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(OK, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(first_party_url, r->first_party_for_cookies());
}
}
@@ -7533,8 +7397,7 @@ TEST_F(URLRequestTestHTTP, RedirectUpdateFirstPartyURL) {
base::RunLoop().Run();
EXPECT_EQ(2U, r->url_chain().size());
- EXPECT_EQ(URLRequestStatus::SUCCESS, r->status().status());
- EXPECT_EQ(OK, r->status().error());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(expected_first_party_url, r->first_party_for_cookies());
}
}
@@ -7824,8 +7687,7 @@ TEST_F(URLRequestTestHTTP, NetworkSuspendTest) {
base::RunLoop().Run();
EXPECT_TRUE(d.request_failed());
- EXPECT_EQ(URLRequestStatus::FAILED, req->status().status());
- EXPECT_EQ(ERR_NETWORK_IO_SUSPENDED, req->status().error());
+ EXPECT_EQ(ERR_NETWORK_IO_SUSPENDED, d.request_status());
}
namespace {
@@ -7885,7 +7747,7 @@ TEST_F(URLRequestTestHTTP, NetworkCancelAfterCreateTransactionFailsTest) {
EXPECT_TRUE(d.request_failed());
EXPECT_EQ(1, d.response_started_count());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
+ EXPECT_EQ(ERR_ABORTED, d.request_status());
// NetworkDelegate should see the cancellation, but not the error.
EXPECT_EQ(1, default_network_delegate()->canceled_requests());
@@ -7916,7 +7778,7 @@ TEST_F(URLRequestTestHTTP, NetworkAccessedClearOnCachedResponse) {
req->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, req->status().status());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_TRUE(req->response_info().network_accessed);
EXPECT_FALSE(req->response_info().was_cached);
@@ -7925,7 +7787,7 @@ TEST_F(URLRequestTestHTTP, NetworkAccessedClearOnCachedResponse) {
req->Start();
base::RunLoop().Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, req->status().status());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_FALSE(req->response_info().network_accessed);
EXPECT_TRUE(req->response_info().was_cached);
}
@@ -8007,8 +7869,9 @@ TEST_F(URLRequestInterceptorTestHTTP,
EXPECT_TRUE(interceptor()->did_intercept_redirect());
// Check we got one good response
- EXPECT_TRUE(req->status().is_success());
- if (req->status().is_success())
+ int status = d.request_status();
+ EXPECT_EQ(OK, status);
+ if (status == OK)
EXPECT_EQ(200, req->response_headers()->response_code());
EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
@@ -8041,8 +7904,9 @@ TEST_F(URLRequestInterceptorTestHTTP,
EXPECT_TRUE(interceptor()->did_intercept_final());
// Check we received one good response.
- EXPECT_TRUE(req->status().is_success());
- if (req->status().is_success())
+ int status = d.request_status();
+ EXPECT_EQ(OK, status);
+ if (status == OK)
EXPECT_EQ(200, req->response_headers()->response_code());
EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
EXPECT_EQ(1, d.response_started_count());
@@ -8073,8 +7937,9 @@ TEST_F(URLRequestInterceptorTestHTTP,
EXPECT_TRUE(interceptor()->did_intercept_final());
// Check we received one good response.
- EXPECT_TRUE(req->status().is_success());
- if (req->status().is_success())
+ int status = d.request_status();
+ EXPECT_EQ(OK, status);
+ if (status == OK)
EXPECT_EQ(200, req->response_headers()->response_code());
EXPECT_EQ("hello", d.data_received());
EXPECT_EQ(1, d.response_started_count());
@@ -8144,7 +8009,7 @@ class URLRequestTestReferrerPolicy : public URLRequestTest {
EXPECT_EQ(1, d.response_started_count());
EXPECT_EQ(1, d.received_redirect_count());
EXPECT_EQ(destination_url, req->url());
- EXPECT_TRUE(req->status().is_success());
+ EXPECT_EQ(OK, d.request_status());
EXPECT_EQ(200, req->response_headers()->response_code());
EXPECT_EQ(expected.spec(), req->referrer());
@@ -8667,9 +8532,7 @@ TEST_F(HTTPSRequestTest, DHE) {
base::RunLoop().Run();
EXPECT_EQ(1, d.response_started_count());
- EXPECT_FALSE(r->status().is_success());
- EXPECT_EQ(URLRequestStatus::FAILED, r->status().status());
- EXPECT_EQ(ERR_SSL_OBSOLETE_CIPHER, r->status().error());
+ EXPECT_EQ(ERR_SSL_OBSOLETE_CIPHER, d.request_status());
}
}
@@ -8918,20 +8781,9 @@ class HTTPSFallbackTest : public testing::Test {
base::RunLoop().Run();
}
- void ExpectConnection(int version) {
- EXPECT_EQ(1, delegate_.response_started_count());
- EXPECT_NE(0, delegate_.bytes_received());
- EXPECT_EQ(version, SSLConnectionStatusToVersion(
- request_->ssl_info().connection_status));
- EXPECT_TRUE(request_->ssl_info().connection_status &
- SSL_CONNECTION_VERSION_FALLBACK);
- }
-
void ExpectFailure(int error) {
EXPECT_EQ(1, delegate_.response_started_count());
- EXPECT_FALSE(request_->status().is_success());
- EXPECT_EQ(URLRequestStatus::FAILED, request_->status().status());
- EXPECT_EQ(error, request_->status().error());
+ EXPECT_EQ(error, delegate_.request_status());
}
private:
@@ -9043,9 +8895,10 @@ TEST_F(HTTPSSessionTest, DontResumeSessionsForInvalidCertificates) {
// This the fingerprint of the "Testing CA" certificate used by the testserver.
// See net/data/ssl/certificates/ocsp-test-root.pem.
-static const SHA1HashValue kOCSPTestCertFingerprint =
- { { 0xf1, 0xad, 0xf6, 0xce, 0x42, 0xac, 0xe7, 0xb4, 0xf4, 0x24,
- 0xdb, 0x1a, 0xf7, 0xa0, 0x9f, 0x09, 0xa1, 0xea, 0xf1, 0x5c } };
+static const SHA1HashValue kOCSPTestCertFingerprint = {{
+ 0xa7, 0xea, 0x4b, 0x0d, 0x13, 0xc1, 0x63, 0xbf, 0xb8, 0x4e,
+ 0x9a, 0xaf, 0x33, 0x05, 0xb0, 0x8f, 0x9c, 0xbe, 0x23, 0xe9,
+}};
// This is the SHA256, SPKI hash of the "Testing CA" certificate used by the
// testserver.
@@ -9087,26 +8940,41 @@ class HTTPSOCSPTest : public HTTPSRequestTest {
#endif
}
- void DoConnection(const SpawnedTestServer::SSLOptions& ssl_options,
- CertStatus* out_cert_status) {
- // We always overwrite out_cert_status.
- *out_cert_status = 0;
+ void DoConnectionWithDelegate(
+ const SpawnedTestServer::SSLOptions& ssl_options,
+ TestDelegate* delegate,
+ SSLInfo* out_ssl_info) {
+ // Always overwrite |out_ssl_info|.
+ out_ssl_info->Reset();
+
SpawnedTestServer test_server(
SpawnedTestServer::TYPE_HTTPS,
ssl_options,
base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
ASSERT_TRUE(test_server.Start());
- TestDelegate d;
- d.set_allow_certificate_errors(true);
- std::unique_ptr<URLRequest> r(
- context_.CreateRequest(test_server.GetURL("/"), DEFAULT_PRIORITY, &d));
+ delegate->set_allow_certificate_errors(true);
+ std::unique_ptr<URLRequest> r(context_.CreateRequest(
+ test_server.GetURL("/"), DEFAULT_PRIORITY, delegate));
r->Start();
base::RunLoop().Run();
+ EXPECT_EQ(1, delegate->response_started_count());
- EXPECT_EQ(1, d.response_started_count());
- *out_cert_status = r->ssl_info().cert_status;
+ *out_ssl_info = r->ssl_info();
+ }
+
+ void DoConnection(const SpawnedTestServer::SSLOptions& ssl_options,
+ CertStatus* out_cert_status) {
+ // Always overwrite |out_cert_status|.
+ *out_cert_status = 0;
+
+ TestDelegate d;
+ SSLInfo ssl_info;
+ ASSERT_NO_FATAL_FAILURE(
+ DoConnectionWithDelegate(ssl_options, &d, &ssl_info));
+
+ *out_cert_status = ssl_info.cert_status;
}
~HTTPSOCSPTest() override {
@@ -9124,7 +8992,7 @@ class HTTPSOCSPTest : public HTTPSRequestTest {
ct::CertPolicyCompliance DoesConformToCertPolicy(
X509Certificate* cert,
const SCTList& verified_scts,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
return ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS;
}
@@ -9132,7 +9000,7 @@ class HTTPSOCSPTest : public HTTPSRequestTest {
X509Certificate* cert,
const ct::EVCertsWhitelist* ev_whitelist,
const SCTList& verified_scts,
- const BoundNetLog& net_log) override {
+ const NetLogWithSource& net_log) override {
return ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS;
}
};
@@ -9153,7 +9021,7 @@ class HTTPSOCSPTest : public HTTPSRequestTest {
};
static CertStatus ExpectedCertStatusForFailedOnlineRevocationCheck() {
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_MACOSX)
// Windows can return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION but we don't
// have that ability on other platforms.
return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
@@ -9185,15 +9053,28 @@ static bool SystemUsesChromiumEVMetadata() {
#if defined(USE_OPENSSL_CERTS) && !defined(OS_ANDROID)
// http://crbug.com/117478 - OpenSSL does not support EV validation.
return false;
-#elif (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_ANDROID)
- // On OS X and Android, we use the system to tell us whether a certificate is
- // EV or not and the system won't recognise our testing root.
+#elif defined(OS_ANDROID)
+ // On Android, we use the system to tell us whether a certificate is EV or not
+ // and the system won't recognise our testing root.
return false;
#else
return true;
#endif
}
+// Returns the expected CertStatus for tests that expect an online revocation
+// check failure as a result of checking a test EV cert, which will not
+// actually trigger an online revocation check on some platforms.
+static CertStatus ExpectedCertStatusForFailedOnlineEVRevocationCheck() {
+ if (SystemUsesChromiumEVMetadata()) {
+ return ExpectedCertStatusForFailedOnlineRevocationCheck();
+ } else {
+ // If SystemUsesChromiumEVMetadata is false, revocation checking will not
+ // be enabled, and thus there will not be a revocation check to fail.
+ return 0u;
+ }
+}
+
static bool SystemSupportsOCSP() {
#if defined(OS_ANDROID)
// TODO(jnd): http://crbug.com/117478 - EV verification is not yet supported.
@@ -9245,10 +9126,7 @@ TEST_F(HTTPSOCSPTest, Revoked) {
CertStatus cert_status;
DoConnection(ssl_options, &cert_status);
-#if !(defined(OS_MACOSX) && !defined(OS_IOS))
- // Doesn't pass on OS X yet for reasons that need to be investigated.
EXPECT_EQ(CERT_STATUS_REVOKED, cert_status & CERT_STATUS_ALL_ERRORS);
-#endif
EXPECT_FALSE(cert_status & CERT_STATUS_IS_EV);
EXPECT_TRUE(cert_status & CERT_STATUS_REV_CHECKING_ENABLED);
}
@@ -9261,7 +9139,8 @@ TEST_F(HTTPSOCSPTest, Invalid) {
SpawnedTestServer::SSLOptions ssl_options(
SpawnedTestServer::SSLOptions::CERT_AUTO);
- ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_INVALID;
+ ssl_options.ocsp_status =
+ SpawnedTestServer::SSLOptions::OCSP_INVALID_RESPONSE;
CertStatus cert_status;
DoConnection(ssl_options, &cert_status);
@@ -9325,6 +9204,371 @@ TEST_F(HTTPSOCSPTest, MAYBE_RevokedStapled) {
EXPECT_TRUE(cert_status & CERT_STATUS_REV_CHECKING_ENABLED);
}
+TEST_F(HTTPSOCSPTest, ExpectStapleReportSentOnMissing) {
+ EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ https_test_server.SetSSLConfig(
+ net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
+ https_test_server.ServeFilesFromSourceDirectory(
+ base::FilePath(kTestFilePath));
+ ASSERT_TRUE(https_test_server.Start());
+
+ // Set up a MockCertVerifier to accept the certificate that the server sends,
+ // but not provide any OCSP information.
+ scoped_refptr<X509Certificate> cert = https_test_server.GetCertificate();
+ ASSERT_TRUE(cert);
+ MockCertVerifier cert_verifier;
+ CertVerifyResult verify_result;
+ verify_result.verified_cert = cert;
+ verify_result.is_issued_by_known_root = true;
+ verify_result.ocsp_result.response_status = OCSPVerifyResult::MISSING;
+ cert_verifier.AddResultForCert(cert.get(), verify_result, OK);
+
+ // Catch the Expect-Staple report.
+ TransportSecurityState transport_security_state;
+ MockCertificateReportSender mock_report_sender;
+ transport_security_state.SetReportSender(&mock_report_sender);
+
+ // Use a MockHostResolver (which by default maps all hosts to 127.0.0.1) so
+ // that the request can be sent to a site on the Expect-Staple preload list.
+ MockHostResolver host_resolver;
+ TestNetworkDelegate network_delegate;
+ TestURLRequestContext context(true);
+ context.set_host_resolver(&host_resolver);
+ context.set_transport_security_state(&transport_security_state);
+ context.set_network_delegate(&network_delegate);
+ context.set_cert_verifier(&cert_verifier);
+ context.Init();
+
+ // Now send a request to trigger the violation.
+ TestDelegate d;
+ GURL url = https_test_server.GetURL("/");
+ GURL::Replacements replace_host;
+ replace_host.SetHostStr(kExpectStapleStaticHostname);
+ url = url.ReplaceComponents(replace_host);
+ std::unique_ptr<URLRequest> violating_request(
+ context.CreateRequest(url, DEFAULT_PRIORITY, &d));
+ violating_request->Start();
+ base::RunLoop().Run();
+
+ // Confirm a report was sent.
+ EXPECT_FALSE(mock_report_sender.latest_report().empty());
+ EXPECT_EQ(GURL(kExpectStapleReportURI),
+ mock_report_sender.latest_report_uri());
+}
+
+TEST_F(HTTPSOCSPTest, ExpectStapleReportNotSentOnValid) {
+ EmbeddedTestServer https_test_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ https_test_server.SetSSLConfig(
+ net::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
+ https_test_server.ServeFilesFromSourceDirectory(
+ base::FilePath(kTestFilePath));
+ ASSERT_TRUE(https_test_server.Start());
+
+ // Set up a MockCertVerifier to accept the certificate that the server sends,
+ // and provide GOOD revocation status.
+ scoped_refptr<X509Certificate> cert = https_test_server.GetCertificate();
+ ASSERT_TRUE(cert);
+ MockCertVerifier cert_verifier;
+ CertVerifyResult verify_result;
+ verify_result.verified_cert = cert;
+ verify_result.is_issued_by_known_root = true;
+ verify_result.ocsp_result.response_status = OCSPVerifyResult::PROVIDED;
+ verify_result.ocsp_result.revocation_status = OCSPRevocationStatus::GOOD;
+ cert_verifier.AddResultForCert(cert.get(), verify_result, OK);
+
+ // Catch the Expect-Staple report.
+ TransportSecurityState transport_security_state;
+ MockCertificateReportSender mock_report_sender;
+ transport_security_state.SetReportSender(&mock_report_sender);
+
+ // Use a MockHostResolver (which by default maps all hosts to 127.0.0.1) so
+ // that the request can be sent to a site on the Expect-Staple preload list.
+ MockHostResolver host_resolver;
+ TestNetworkDelegate network_delegate;
+ TestURLRequestContext context(true);
+ context.set_host_resolver(&host_resolver);
+ context.set_transport_security_state(&transport_security_state);
+ context.set_network_delegate(&network_delegate);
+ context.set_cert_verifier(&cert_verifier);
+ context.Init();
+
+ // This request should not not trigger an Expect-Staple violation.
+ TestDelegate d;
+ GURL url = https_test_server.GetURL("/");
+ GURL::Replacements replace_host;
+ replace_host.SetHostStr(kExpectStapleStaticHostname);
+ url = url.ReplaceComponents(replace_host);
+ std::unique_ptr<URLRequest> ok_request(
+ context.CreateRequest(url, DEFAULT_PRIORITY, &d));
+ ok_request->Start();
+ base::RunLoop().Run();
+
+ // Check that no report was sent.
+ EXPECT_TRUE(mock_report_sender.latest_report().empty());
+ EXPECT_EQ(GURL(), mock_report_sender.latest_report_uri());
+}
+
+static const struct OCSPVerifyTestData {
+ std::vector<SpawnedTestServer::SSLOptions::OCSPSingleResponse> ocsp_responses;
+ SpawnedTestServer::SSLOptions::OCSPProduced ocsp_produced;
+ OCSPVerifyResult::ResponseStatus response_status;
+ bool has_revocation_status;
+ OCSPRevocationStatus cert_status;
+} kOCSPVerifyData[] = {
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::PROVIDED,
+ true,
+ OCSPRevocationStatus::GOOD},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_OLD}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::INVALID_DATE,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_EARLY}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::INVALID_DATE,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_LONG}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::INVALID_DATE,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_LONG}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::INVALID_DATE,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_TRY_LATER,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::ERROR_RESPONSE,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_INVALID_RESPONSE,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::PARSE_RESPONSE_ERROR,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_INVALID_RESPONSE_DATA,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::PARSE_RESPONSE_DATA_ERROR,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_REVOKED,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_EARLY}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::INVALID_DATE,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_UNKNOWN,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::PROVIDED,
+ true,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_UNKNOWN,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_OLD}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::INVALID_DATE,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_UNKNOWN,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_EARLY}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::INVALID_DATE,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_BEFORE_CERT,
+ OCSPVerifyResult::BAD_PRODUCED_AT,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_AFTER_CERT,
+ OCSPVerifyResult::BAD_PRODUCED_AT,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_AFTER_CERT,
+ OCSPVerifyResult::BAD_PRODUCED_AT,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_REVOKED,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::PROVIDED,
+ true,
+ OCSPRevocationStatus::REVOKED},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_REVOKED,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_OLD}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::INVALID_DATE,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_REVOKED,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_LONG}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::INVALID_DATE,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::PROVIDED,
+ true,
+ OCSPRevocationStatus::GOOD},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_OLD},
+ {SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::PROVIDED,
+ true,
+ OCSPRevocationStatus::GOOD},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_EARLY},
+ {SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::PROVIDED,
+ true,
+ OCSPRevocationStatus::GOOD},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_LONG},
+ {SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::PROVIDED,
+ true,
+ OCSPRevocationStatus::GOOD},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_EARLY},
+ {SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_OLD},
+ {SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_LONG}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::INVALID_DATE,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_UNKNOWN,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID},
+ {SpawnedTestServer::SSLOptions::OCSP_REVOKED,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID},
+ {SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::PROVIDED,
+ true,
+ OCSPRevocationStatus::REVOKED},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_UNKNOWN,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID},
+ {SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::PROVIDED,
+ true,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_UNKNOWN,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID},
+ {SpawnedTestServer::SSLOptions::OCSP_REVOKED,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_LONG},
+ {SpawnedTestServer::SSLOptions::OCSP_OK,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::PROVIDED,
+ true,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_MISMATCHED_SERIAL,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_VALID}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::NO_MATCHING_RESPONSE,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+ {{{SpawnedTestServer::SSLOptions::OCSP_MISMATCHED_SERIAL,
+ SpawnedTestServer::SSLOptions::OCSP_DATE_EARLY}},
+ SpawnedTestServer::SSLOptions::OCSP_PRODUCED_VALID,
+ OCSPVerifyResult::NO_MATCHING_RESPONSE,
+ false,
+ OCSPRevocationStatus::UNKNOWN},
+
+};
+
+class HTTPSOCSPVerifyTest
+ : public HTTPSOCSPTest,
+ public testing::WithParamInterface<OCSPVerifyTestData> {};
+
+TEST_P(HTTPSOCSPVerifyTest, VerifyResult) {
+ SpawnedTestServer::SSLOptions ssl_options(
+ SpawnedTestServer::SSLOptions::CERT_AUTO);
+ OCSPVerifyTestData test = GetParam();
+
+ ssl_options.ocsp_responses = test.ocsp_responses;
+ ssl_options.ocsp_produced = test.ocsp_produced;
+ ssl_options.staple_ocsp_response = true;
+
+ SSLInfo ssl_info;
+ OCSPErrorTestDelegate delegate;
+ ASSERT_NO_FATAL_FAILURE(
+ DoConnectionWithDelegate(ssl_options, &delegate, &ssl_info));
+
+ // The SSLInfo must be extracted from |delegate| on error, due to how
+ // URLRequest caches certificate errors.
+ if (delegate.have_certificate_errors()) {
+ ASSERT_TRUE(delegate.on_ssl_certificate_error_called());
+ ssl_info = delegate.ssl_info();
+ }
+
+ EXPECT_EQ(test.response_status, ssl_info.ocsp_result.response_status);
+
+ if (test.has_revocation_status)
+ EXPECT_EQ(test.cert_status, ssl_info.ocsp_result.revocation_status);
+}
+
+INSTANTIATE_TEST_CASE_P(OCSPVerify,
+ HTTPSOCSPVerifyTest,
+ testing::ValuesIn(kOCSPVerifyData));
+
class HTTPSHardFailTest : public HTTPSOCSPTest {
protected:
void SetupContext() override {
@@ -9350,7 +9594,8 @@ TEST_F(HTTPSHardFailTest, FailsOnOCSPInvalid) {
SpawnedTestServer::SSLOptions ssl_options(
SpawnedTestServer::SSLOptions::CERT_AUTO);
- ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_INVALID;
+ ssl_options.ocsp_status =
+ SpawnedTestServer::SSLOptions::OCSP_INVALID_RESPONSE;
CertStatus cert_status;
DoConnection(ssl_options, &cert_status);
@@ -9381,13 +9626,14 @@ TEST_F(HTTPSEVCRLSetTest, MissingCRLSetAndInvalidOCSP) {
SpawnedTestServer::SSLOptions ssl_options(
SpawnedTestServer::SSLOptions::CERT_AUTO);
- ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_INVALID;
+ ssl_options.ocsp_status =
+ SpawnedTestServer::SSLOptions::OCSP_INVALID_RESPONSE;
SSLConfigService::SetCRLSet(scoped_refptr<CRLSet>());
CertStatus cert_status;
DoConnection(ssl_options, &cert_status);
- EXPECT_EQ(ExpectedCertStatusForFailedOnlineRevocationCheck(),
+ EXPECT_EQ(ExpectedCertStatusForFailedOnlineEVRevocationCheck(),
cert_status & CERT_STATUS_ALL_ERRORS);
EXPECT_FALSE(cert_status & CERT_STATUS_IS_EV);
@@ -9409,10 +9655,10 @@ TEST_F(HTTPSEVCRLSetTest, MissingCRLSetAndRevokedOCSP) {
CertStatus cert_status;
DoConnection(ssl_options, &cert_status);
- // Currently only works for Windows. When using NSS or OS X, it's not
- // possible to determine whether the check failed because of actual
- // revocation or because there was an OCSP failure.
-#if defined(OS_WIN)
+// Currently only works for Windows and OS X. When using NSS, it's not
+// possible to determine whether the check failed because of actual
+// revocation or because there was an OCSP failure.
+#if defined(OS_WIN) || defined(OS_MACOSX)
EXPECT_EQ(CERT_STATUS_REVOKED, cert_status & CERT_STATUS_ALL_ERRORS);
#else
EXPECT_EQ(0u, cert_status & CERT_STATUS_ALL_ERRORS);
@@ -9453,14 +9699,15 @@ TEST_F(HTTPSEVCRLSetTest, ExpiredCRLSet) {
SpawnedTestServer::SSLOptions ssl_options(
SpawnedTestServer::SSLOptions::CERT_AUTO);
- ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_INVALID;
+ ssl_options.ocsp_status =
+ SpawnedTestServer::SSLOptions::OCSP_INVALID_RESPONSE;
SSLConfigService::SetCRLSet(
scoped_refptr<CRLSet>(CRLSet::ExpiredCRLSetForTesting()));
CertStatus cert_status;
DoConnection(ssl_options, &cert_status);
- EXPECT_EQ(ExpectedCertStatusForFailedOnlineRevocationCheck(),
+ EXPECT_EQ(ExpectedCertStatusForFailedOnlineEVRevocationCheck(),
cert_status & CERT_STATUS_ALL_ERRORS);
EXPECT_FALSE(cert_status & CERT_STATUS_IS_EV);
@@ -9476,7 +9723,8 @@ TEST_F(HTTPSEVCRLSetTest, FreshCRLSetCovered) {
SpawnedTestServer::SSLOptions ssl_options(
SpawnedTestServer::SSLOptions::CERT_AUTO);
- ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_INVALID;
+ ssl_options.ocsp_status =
+ SpawnedTestServer::SSLOptions::OCSP_INVALID_RESPONSE;
SSLConfigService::SetCRLSet(
scoped_refptr<CRLSet>(CRLSet::ForTesting(
false, &kOCSPTestCertSPKI, "")));
@@ -9501,7 +9749,8 @@ TEST_F(HTTPSEVCRLSetTest, FreshCRLSetNotCovered) {
SpawnedTestServer::SSLOptions ssl_options(
SpawnedTestServer::SSLOptions::CERT_AUTO);
- ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_INVALID;
+ ssl_options.ocsp_status =
+ SpawnedTestServer::SSLOptions::OCSP_INVALID_RESPONSE;
SSLConfigService::SetCRLSet(
scoped_refptr<CRLSet>(CRLSet::EmptyCRLSetForTesting()));
@@ -9511,7 +9760,7 @@ TEST_F(HTTPSEVCRLSetTest, FreshCRLSetNotCovered) {
// Even with a fresh CRLSet, we should still do online revocation checks when
// the certificate chain isn't covered by the CRLSet, which it isn't in this
// test.
- EXPECT_EQ(ExpectedCertStatusForFailedOnlineRevocationCheck(),
+ EXPECT_EQ(ExpectedCertStatusForFailedOnlineEVRevocationCheck(),
cert_status & CERT_STATUS_ALL_ERRORS);
EXPECT_FALSE(cert_status & CERT_STATUS_IS_EV);
@@ -9561,7 +9810,8 @@ class HTTPSCRLSetTest : public HTTPSOCSPTest {
TEST_F(HTTPSCRLSetTest, ExpiredCRLSet) {
SpawnedTestServer::SSLOptions ssl_options(
SpawnedTestServer::SSLOptions::CERT_AUTO);
- ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_INVALID;
+ ssl_options.ocsp_status =
+ SpawnedTestServer::SSLOptions::OCSP_INVALID_RESPONSE;
SSLConfigService::SetCRLSet(
scoped_refptr<CRLSet>(CRLSet::ExpiredCRLSetForTesting()));
@@ -9621,8 +9871,7 @@ class URLRequestTestFTP : public URLRequestTest {
void SetUpFactory() override {
// Add FTP support to the default URLRequestContext.
job_factory_impl_->SetProtocolHandler(
- "ftp",
- base::WrapUnique(new FtpProtocolHandler(&ftp_transaction_factory_)));
+ "ftp", base::MakeUnique<FtpProtocolHandler>(&ftp_transaction_factory_));
}
std::string GetTestFileContents() {
@@ -9656,8 +9905,7 @@ TEST_F(URLRequestTestFTP, UnsafePort) {
base::RunLoop().Run();
EXPECT_FALSE(r->is_pending());
- EXPECT_EQ(URLRequestStatus::FAILED, r->status().status());
- EXPECT_EQ(ERR_UNSAFE_PORT, r->status().error());
+ EXPECT_EQ(ERR_UNSAFE_PORT, d.request_status());
}
}
@@ -9921,25 +10169,6 @@ TEST_F(URLRequestTestFTP, RawBodyBytes) {
#endif // !defined(DISABLE_FTP_SUPPORT)
-TEST_F(URLRequestTest, NetworkAccessedClearBeforeNetworkStart) {
- TestDelegate d;
- std::unique_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d));
- d.set_quit_on_network_start(true);
-
- EXPECT_FALSE(req->response_info().network_accessed);
-
- req->Start();
- base::RunLoop().Run();
-
- EXPECT_EQ(1, d.received_before_network_start_count());
- EXPECT_EQ(0, d.response_started_count());
- EXPECT_FALSE(req->response_info().network_accessed);
-
- req->ResumeNetworkStart();
- base::RunLoop().Run();
-}
-
TEST_F(URLRequestTest, NetworkAccessedClearOnDataRequest) {
TestDelegate d;
std::unique_ptr<URLRequest> req(
@@ -9990,7 +10219,7 @@ TEST_F(URLRequestTest, URLRequestRedirectJobCancelRequest) {
req->Start();
req->Cancel();
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
+ EXPECT_EQ(ERR_ABORTED, d.request_status());
EXPECT_EQ(0, d.received_redirect_count());
}
diff --git a/chromium/net/url_request/view_cache_helper_unittest.cc b/chromium/net/url_request/view_cache_helper_unittest.cc
index e21e05ef4ed..7c7d5451dc8 100644
--- a/chromium/net/url_request/view_cache_helper_unittest.cc
+++ b/chromium/net/url_request/view_cache_helper_unittest.cc
@@ -11,9 +11,13 @@
#include "net/disk_cache/disk_cache.h"
#include "net/http/http_cache.h"
#include "net/http/http_transaction_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/url_request/url_request_context.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -32,7 +36,7 @@ class TestURLRequestContext : public URLRequestContext {
};
TestURLRequestContext::TestURLRequestContext()
- : cache_(base::WrapUnique(new MockNetworkLayer()),
+ : cache_(base::MakeUnique<MockNetworkLayer>(),
HttpCache::DefaultBackend::InMemory(0),
true) {
set_http_transaction_factory(&cache_);
@@ -80,7 +84,7 @@ void WriteToEntry(disk_cache::Backend* cache, const std::string& key,
rv = cb.GetResult(rv);
if (rv != OK) {
rv = cache->OpenEntry(key, &entry, cb.callback());
- ASSERT_EQ(OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
}
WriteHeaders(entry, 0, data0);
@@ -96,7 +100,7 @@ void FillCache(URLRequestContext* context) {
int rv =
context->http_transaction_factory()->GetCache()->GetBackend(
&cache, cb.callback());
- ASSERT_EQ(OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
std::string empty;
WriteToEntry(cache, "first", "some", empty, empty);
@@ -113,7 +117,7 @@ TEST(ViewCacheHelper, EmptyCache) {
TestCompletionCallback cb;
std::string prefix, data;
int rv = helper.GetContentsHTML(&context, prefix, &data, cb.callback());
- EXPECT_EQ(OK, cb.GetResult(rv));
+ EXPECT_THAT(cb.GetResult(rv), IsOk());
EXPECT_FALSE(data.empty());
}
@@ -126,7 +130,7 @@ TEST(ViewCacheHelper, ListContents) {
std::string prefix, data;
TestCompletionCallback cb;
int rv = helper.GetContentsHTML(&context, prefix, &data, cb.callback());
- EXPECT_EQ(OK, cb.GetResult(rv));
+ EXPECT_THAT(cb.GetResult(rv), IsOk());
EXPECT_EQ(0U, data.find("<html>"));
EXPECT_NE(std::string::npos, data.find("</html>"));
@@ -148,7 +152,7 @@ TEST(ViewCacheHelper, DumpEntry) {
std::string data;
TestCompletionCallback cb;
int rv = helper.GetEntryInfoHTML("second", &context, &data, cb.callback());
- EXPECT_EQ(OK, cb.GetResult(rv));
+ EXPECT_THAT(cb.GetResult(rv), IsOk());
EXPECT_EQ(0U, data.find("<html>"));
EXPECT_NE(std::string::npos, data.find("</html>"));
@@ -174,7 +178,7 @@ TEST(ViewCacheHelper, Prefix) {
std::string prefix("prefix:");
TestCompletionCallback cb;
int rv = helper.GetContentsHTML(&context, prefix, &data, cb.callback());
- EXPECT_EQ(OK, cb.GetResult(rv));
+ EXPECT_THAT(cb.GetResult(rv), IsOk());
EXPECT_EQ(0U, data.find("<html>"));
EXPECT_NE(std::string::npos, data.find("</html>"));
@@ -192,12 +196,12 @@ TEST(ViewCacheHelper, TruncatedFlag) {
int rv =
context.http_transaction_factory()->GetCache()->GetBackend(
&cache, cb.callback());
- ASSERT_EQ(OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
std::string key("the key");
disk_cache::Entry* entry;
rv = cache->CreateEntry(key, &entry, cb.callback());
- ASSERT_EQ(OK, cb.GetResult(rv));
+ ASSERT_THAT(cb.GetResult(rv), IsOk());
// RESPONSE_INFO_TRUNCATED defined on response_info.cc
int flags = 1 << 12;
@@ -207,7 +211,7 @@ TEST(ViewCacheHelper, TruncatedFlag) {
std::string data;
TestCompletionCallback cb1;
rv = helper.GetEntryInfoHTML(key, &context, &data, cb1.callback());
- EXPECT_EQ(OK, cb1.GetResult(rv));
+ EXPECT_THAT(cb1.GetResult(rv), IsOk());
EXPECT_NE(std::string::npos, data.find("RESPONSE_INFO_TRUNCATED"));
}
diff --git a/chromium/net/websockets/websocket_basic_handshake_stream.cc b/chromium/net/websockets/websocket_basic_handshake_stream.cc
index 64f1db68f69..efe263ade36 100644
--- a/chromium/net/websockets/websocket_basic_handshake_stream.cc
+++ b/chromium/net/websockets/websocket_basic_handshake_stream.cc
@@ -84,7 +84,8 @@ std::string MultipleHeaderValuesMessage(const std::string& header_name) {
std::string GenerateHandshakeChallenge() {
std::string raw_challenge(websockets::kRawChallengeLength, '\0');
- crypto::RandBytes(string_as_array(&raw_challenge), raw_challenge.length());
+ crypto::RandBytes(base::string_as_array(&raw_challenge),
+ raw_challenge.length());
std::string encoded_challenge;
base::Base64Encode(raw_challenge, &encoded_challenge);
return encoded_challenge;
@@ -293,15 +294,17 @@ WebSocketBasicHandshakeStream::WebSocketBasicHandshakeStream(
bool using_proxy,
std::vector<std::string> requested_sub_protocols,
std::vector<std::string> requested_extensions,
- std::string* failure_message)
- : state_(connection.release(), using_proxy),
+ WebSocketStreamRequest* request)
+ : state_(std::move(connection),
+ using_proxy,
+ false /* http_09_on_non_default_ports_enabled */),
connect_delegate_(connect_delegate),
http_response_info_(nullptr),
requested_sub_protocols_(requested_sub_protocols),
requested_extensions_(requested_extensions),
- failure_message_(failure_message) {
+ stream_request_(request) {
DCHECK(connect_delegate);
- DCHECK(failure_message);
+ DCHECK(request);
}
WebSocketBasicHandshakeStream::~WebSocketBasicHandshakeStream() {}
@@ -309,7 +312,7 @@ WebSocketBasicHandshakeStream::~WebSocketBasicHandshakeStream() {}
int WebSocketBasicHandshakeStream::InitializeStream(
const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback) {
url_ = request_info->url;
state_.Initialize(request_info, priority, net_log, callback);
@@ -444,8 +447,9 @@ void WebSocketBasicHandshakeStream::PopulateNetErrorDetails(
return;
}
-Error WebSocketBasicHandshakeStream::GetSignedEKMForTokenBinding(
+Error WebSocketBasicHandshakeStream::GetTokenBindingSignature(
crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
std::vector<uint8_t>* out) {
NOTREACHED();
return ERR_NOT_IMPLEMENTED;
@@ -462,10 +466,6 @@ void WebSocketBasicHandshakeStream::SetPriority(RequestPriority priority) {
// gone, then copy whatever has happened there over here.
}
-UploadProgress WebSocketBasicHandshakeStream::GetUploadProgress() const {
- return UploadProgress();
-}
-
HttpStream* WebSocketBasicHandshakeStream::RenewStreamForAuth() {
// Return null because we don't support renewing the stream.
return nullptr;
@@ -541,10 +541,9 @@ int WebSocketBasicHandshakeStream::ValidateResponse(int rv) {
// Reporting "Unexpected response code: 200" in this case is not
// helpful, so use a different error message.
if (headers->GetHttpVersion() == HttpVersion(0, 9)) {
- set_failure_message(
- "Error during WebSocket handshake: Invalid status line");
+ OnFailure("Error during WebSocket handshake: Invalid status line");
} else {
- set_failure_message(base::StringPrintf(
+ OnFailure(base::StringPrintf(
"Error during WebSocket handshake: Unexpected response code: %d",
headers->response_code()));
}
@@ -553,12 +552,11 @@ int WebSocketBasicHandshakeStream::ValidateResponse(int rv) {
}
} else {
if (rv == ERR_EMPTY_RESPONSE) {
- set_failure_message(
- "Connection closed before receiving a handshake response");
+ OnFailure("Connection closed before receiving a handshake response");
return rv;
}
- set_failure_message(std::string("Error during WebSocket handshake: ") +
- ErrorToString(rv));
+ OnFailure(std::string("Error during WebSocket handshake: ") +
+ ErrorToString(rv));
OnFinishOpeningHandshake();
// Some error codes (for example ERR_CONNECTION_CLOSED) get changed to OK at
// higher levels. To prevent an unvalidated connection getting erroneously
@@ -592,13 +590,12 @@ int WebSocketBasicHandshakeStream::ValidateUpgradeResponse(
extension_params_.get())) {
return OK;
}
- set_failure_message("Error during WebSocket handshake: " + failure_message);
+ OnFailure("Error during WebSocket handshake: " + failure_message);
return ERR_INVALID_RESPONSE;
}
-void WebSocketBasicHandshakeStream::set_failure_message(
- const std::string& failure_message) {
- *failure_message_ = failure_message;
+void WebSocketBasicHandshakeStream::OnFailure(const std::string& message) {
+ stream_request_->OnFailure(message);
}
} // namespace net
diff --git a/chromium/net/websockets/websocket_basic_handshake_stream.h b/chromium/net/websockets/websocket_basic_handshake_stream.h
index dbb847e6c3f..dffe472ea0e 100644
--- a/chromium/net/websockets/websocket_basic_handshake_stream.h
+++ b/chromium/net/websockets/websocket_basic_handshake_stream.h
@@ -26,6 +26,7 @@ class HttpResponseInfo;
class HttpStreamParser;
struct WebSocketExtensionParams;
+class WebSocketStreamRequest;
class NET_EXPORT_PRIVATE WebSocketBasicHandshakeStream
: public WebSocketHandshakeStreamBase {
@@ -37,14 +38,14 @@ class NET_EXPORT_PRIVATE WebSocketBasicHandshakeStream
bool using_proxy,
std::vector<std::string> requested_sub_protocols,
std::vector<std::string> requested_extensions,
- std::string* failure_message);
+ WebSocketStreamRequest* request);
~WebSocketBasicHandshakeStream() override;
// HttpStreamBase methods
int InitializeStream(const HttpRequestInfo* request_info,
RequestPriority priority,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
const CompletionCallback& callback) override;
int SendRequest(const HttpRequestHeaders& request_headers,
HttpResponseInfo* response,
@@ -64,12 +65,12 @@ class NET_EXPORT_PRIVATE WebSocketBasicHandshakeStream
void GetSSLInfo(SSLInfo* ssl_info) override;
void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
bool GetRemoteEndpoint(IPEndPoint* endpoint) override;
- Error GetSignedEKMForTokenBinding(crypto::ECPrivateKey* key,
- std::vector<uint8_t>* out) override;
+ Error GetTokenBindingSignature(crypto::ECPrivateKey* key,
+ TokenBindingType tb_type,
+ std::vector<uint8_t>* out) override;
void Drain(HttpNetworkSession* session) override;
void SetPriority(RequestPriority priority) override;
void PopulateNetErrorDetails(NetErrorDetails* details) override;
- UploadProgress GetUploadProgress() const override;
HttpStream* RenewStreamForAuth() override;
@@ -99,9 +100,9 @@ class NET_EXPORT_PRIVATE WebSocketBasicHandshakeStream
// OK if they are, otherwise returns ERR_INVALID_RESPONSE.
int ValidateUpgradeResponse(const HttpResponseHeaders* headers);
- HttpStreamParser* parser() const { return state_.parser(); }
+ void OnFailure(const std::string& message);
- void set_failure_message(const std::string& failure_message);
+ HttpStreamParser* parser() const { return state_.parser(); }
// The request URL.
GURL url_;
@@ -139,7 +140,7 @@ class NET_EXPORT_PRIVATE WebSocketBasicHandshakeStream
// to avoid including extension-related header files here.
std::unique_ptr<WebSocketExtensionParams> extension_params_;
- std::string* failure_message_;
+ WebSocketStreamRequest* stream_request_;
DISALLOW_COPY_AND_ASSIGN(WebSocketBasicHandshakeStream);
};
diff --git a/chromium/net/websockets/websocket_basic_stream.h b/chromium/net/websockets/websocket_basic_stream.h
index f326d64017e..c944ab64210 100644
--- a/chromium/net/websockets/websocket_basic_stream.h
+++ b/chromium/net/websockets/websocket_basic_stream.h
@@ -11,6 +11,7 @@
#include "base/callback.h"
#include "base/memory/ref_counted.h"
+#include "net/base/net_export.h"
#include "net/websockets/websocket_frame_parser.h"
#include "net/websockets/websocket_stream.h"
diff --git a/chromium/net/websockets/websocket_basic_stream_test.cc b/chromium/net/websockets/websocket_basic_stream_test.cc
index 0671114da86..7061e4b581d 100644
--- a/chromium/net/websockets/websocket_basic_stream_test.cc
+++ b/chromium/net/websockets/websocket_basic_stream_test.cc
@@ -20,8 +20,13 @@
#include "net/base/test_completion_callback.h"
#include "net/log/test_net_log.h"
#include "net/socket/socket_test_util.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -129,9 +134,9 @@ class WebSocketBasicStreamSocketTest : public WebSocketBasicStreamTest {
std::unique_ptr<ClientSocketHandle> transport_socket(
new ClientSocketHandle);
scoped_refptr<MockTransportSocketParams> params;
- transport_socket->Init(
- "a", params, MEDIUM, ClientSocketPool::RespectLimits::ENABLED,
- CompletionCallback(), &pool_, bound_net_log_.bound());
+ transport_socket->Init("a", params, MEDIUM,
+ ClientSocketPool::RespectLimits::ENABLED,
+ CompletionCallback(), &pool_, net_log_.bound());
return transport_socket;
}
@@ -164,7 +169,7 @@ class WebSocketBasicStreamSocketTest : public WebSocketBasicStreamTest {
std::unique_ptr<SocketDataProvider> socket_data_;
MockClientSocketFactory factory_;
MockTransportClientSocketPool pool_;
- BoundTestNetLog(bound_net_log_);
+ BoundTestNetLog(net_log_);
std::vector<std::unique_ptr<WebSocketFrame>> frames_;
TestCompletionCallback cb_;
scoped_refptr<GrowableIOBuffer> http_read_buffer_;
@@ -270,7 +275,7 @@ TEST_F(WebSocketBasicStreamSocketTest, ConstructionWorks) {
TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncReadWorks) {
CreateRead(MockRead(SYNCHRONOUS, kSampleFrame, kSampleFrameSize));
int result = stream_->ReadFrames(&frames_, cb_.callback());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(UINT64_C(6), frames_[0]->header.payload_length);
EXPECT_TRUE(frames_[0]->header.final);
@@ -279,8 +284,8 @@ TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncReadWorks) {
TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncReadWorks) {
CreateRead(MockRead(ASYNC, kSampleFrame, kSampleFrameSize));
int result = stream_->ReadFrames(&frames_, cb_.callback());
- ASSERT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(OK, cb_.WaitForResult());
+ ASSERT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(UINT64_C(6), frames_[0]->header.payload_length);
// Don't repeat all the tests from SyncReadWorks; just enough to be sure the
@@ -292,7 +297,7 @@ TEST_F(WebSocketBasicStreamSocketChunkedReadTest, HeaderFragmentedSync) {
CreateChunkedRead(
SYNCHRONOUS, kSampleFrame, kSampleFrameSize, 1, 2, LAST_FRAME_BIG);
int result = stream_->ReadFrames(&frames_, cb_.callback());
- EXPECT_EQ(OK, result);
+ EXPECT_THAT(result, IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(UINT64_C(6), frames_[0]->header.payload_length);
}
@@ -302,8 +307,8 @@ TEST_F(WebSocketBasicStreamSocketChunkedReadTest, HeaderFragmentedAsync) {
CreateChunkedRead(
ASYNC, kSampleFrame, kSampleFrameSize, 1, 2, LAST_FRAME_BIG);
int result = stream_->ReadFrames(&frames_, cb_.callback());
- ASSERT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(OK, cb_.WaitForResult());
+ ASSERT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(UINT64_C(6), frames_[0]->header.payload_length);
}
@@ -315,8 +320,8 @@ TEST_F(WebSocketBasicStreamSocketTest, HeaderFragmentedSyncAsync) {
MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1)};
CreateReadOnly(reads);
int result = stream_->ReadFrames(&frames_, cb_.callback());
- ASSERT_EQ(ERR_IO_PENDING, result);
- EXPECT_EQ(OK, cb_.WaitForResult());
+ ASSERT_THAT(result, IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(UINT64_C(6), frames_[0]->header.payload_length);
}
@@ -328,14 +333,15 @@ TEST_F(WebSocketBasicStreamSocketTest, FragmentedLargeHeader) {
MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize - 1),
MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
CreateReadOnly(reads);
- EXPECT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
}
// A frame that does not arrive in a single read should be broken into separate
// frames.
TEST_F(WebSocketBasicStreamSocketSingleReadTest, LargeFrameFirstChunk) {
CreateRead(MockRead(SYNCHRONOUS, kPartialLargeFrame, kPartialLargeFrameSize));
- EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_FALSE(frames_[0]->header.final);
EXPECT_EQ(kPartialLargeFrameSize - kLargeFrameHeaderSize,
@@ -347,7 +353,7 @@ TEST_F(WebSocketBasicStreamSocketSingleReadTest, LargeFrameFirstChunk) {
TEST_F(WebSocketBasicStreamSocketSingleReadTest, HeaderOnlyChunk) {
CreateRead(MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize));
- EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(NULL, frames_[0]->data.get());
EXPECT_EQ(0U, frames_[0]->header.payload_length);
@@ -363,13 +369,14 @@ TEST_F(WebSocketBasicStreamSocketTest, HeaderBodySeparated) {
kPartialLargeFrame + kLargeFrameHeaderSize,
kPartialLargeFrameSize - kLargeFrameHeaderSize)};
CreateReadOnly(reads);
- EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(NULL, frames_[0]->data.get());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_[0]->header.opcode);
frames_.clear();
- EXPECT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
- EXPECT_EQ(OK, cb_.WaitForResult());
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(kPartialLargeFrameSize - kLargeFrameHeaderSize,
frames_[0]->header.payload_length);
@@ -388,15 +395,17 @@ TEST_F(WebSocketBasicStreamSocketChunkedReadTest, LargeFrameTwoChunks) {
LAST_FRAME_NOT_BIG);
TestCompletionCallback cb[2];
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb[0].callback()));
- EXPECT_EQ(OK, cb[0].WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb[0].callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb[0].WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(kChunkSize - kLargeFrameHeaderSize,
frames_[0]->header.payload_length);
frames_.clear();
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb[1].callback()));
- EXPECT_EQ(OK, cb[1].WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb[1].callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb[1].WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(kChunkSize, frames_[0]->header.payload_length);
}
@@ -412,14 +421,16 @@ TEST_F(WebSocketBasicStreamSocketChunkedReadTest, OnlyFinalChunkIsFinal) {
LAST_FRAME_BIG);
TestCompletionCallback cb[2];
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb[0].callback()));
- EXPECT_EQ(OK, cb[0].WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb[0].callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb[0].WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
ASSERT_FALSE(frames_[0]->header.final);
frames_.clear();
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb[1].callback()));
- EXPECT_EQ(OK, cb[1].WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb[1].callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb[1].WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
ASSERT_TRUE(frames_[0]->header.final);
}
@@ -438,8 +449,9 @@ TEST_F(WebSocketBasicStreamSocketChunkedReadTest, ContinuationOpCodeUsed) {
LAST_FRAME_BIG);
TestCompletionCallback cb[kChunkCount];
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb[0].callback()));
- EXPECT_EQ(OK, cb[0].WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb[0].callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb[0].WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_[0]->header.opcode);
@@ -447,8 +459,9 @@ TEST_F(WebSocketBasicStreamSocketChunkedReadTest, ContinuationOpCodeUsed) {
// after the first is converted to Continuation.
for (int i = 1; i < kChunkCount; ++i) {
frames_.clear();
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb[i].callback()));
- EXPECT_EQ(OK, cb[i].WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb[i].callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb[i].WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeContinuation,
frames_[0]->header.opcode);
@@ -459,7 +472,7 @@ TEST_F(WebSocketBasicStreamSocketChunkedReadTest, ContinuationOpCodeUsed) {
TEST_F(WebSocketBasicStreamSocketSingleReadTest, ThreeFramesTogether) {
CreateRead(MockRead(SYNCHRONOUS, kMultipleFrames, kMultipleFramesSize));
- EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
ASSERT_EQ(3U, frames_.size());
EXPECT_TRUE(frames_[0]->header.final);
EXPECT_TRUE(frames_[1]->header.final);
@@ -477,8 +490,9 @@ TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncClose) {
TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncClose) {
CreateRead(MockRead(ASYNC, "", 0));
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
- EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
}
// The result should be the same if the socket returns
@@ -495,8 +509,9 @@ TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncCloseWithErr) {
TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncCloseWithErr) {
CreateRead(MockRead(ASYNC, ERR_CONNECTION_CLOSED));
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
- EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
}
TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncErrorsPassedThrough) {
@@ -511,8 +526,9 @@ TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncErrorsPassedThrough) {
TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncErrorsPassedThrough) {
CreateRead(MockRead(ASYNC, ERR_INSUFFICIENT_RESOURCES));
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
- EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES, cb_.WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsError(ERR_INSUFFICIENT_RESOURCES));
}
// If we get a frame followed by a close, we should receive them separately.
@@ -526,7 +542,7 @@ TEST_F(WebSocketBasicStreamSocketChunkedReadTest, CloseAfterFrame) {
2,
LAST_FRAME_NOT_BIG);
- EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
EXPECT_EQ(1U, frames_.size());
frames_.clear();
EXPECT_EQ(ERR_CONNECTION_CLOSED,
@@ -540,8 +556,9 @@ TEST_F(WebSocketBasicStreamSocketTest, AsyncCloseAfterIncompleteHeader) {
MockRead(SYNCHRONOUS, "", 0)};
CreateReadOnly(reads);
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
- EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
}
// When Stream::Read returns ERR_CONNECTION_CLOSED we get the same result via a
@@ -551,15 +568,16 @@ TEST_F(WebSocketBasicStreamSocketTest, AsyncErrCloseAfterIncompleteHeader) {
MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED)};
CreateReadOnly(reads);
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
- EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
}
// An empty first frame is not ignored.
TEST_F(WebSocketBasicStreamSocketSingleReadTest, EmptyFirstFrame) {
CreateRead(MockRead(SYNCHRONOUS, kEmptyFirstFrame, kEmptyFirstFrameSize));
- EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(NULL, frames_[0]->data.get());
EXPECT_EQ(0U, frames_[0]->header.payload_length);
@@ -573,10 +591,11 @@ TEST_F(WebSocketBasicStreamSocketTest, EmptyMiddleFrame) {
MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
CreateReadOnly(reads);
- EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
EXPECT_EQ(1U, frames_.size());
frames_.clear();
- EXPECT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
}
// An empty frame in the middle of a message that arrives separately is still
@@ -590,11 +609,12 @@ TEST_F(WebSocketBasicStreamSocketTest, EmptyMiddleFrameAsync) {
MockRead(ASYNC, kValidPong, kValidPongSize)};
CreateReadOnly(reads);
- EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
EXPECT_EQ(1U, frames_.size());
frames_.clear();
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
- EXPECT_EQ(OK, cb_.WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodePong, frames_[0]->header.opcode);
}
@@ -604,7 +624,7 @@ TEST_F(WebSocketBasicStreamSocketSingleReadTest, EmptyFinalFrame) {
CreateRead(
MockRead(SYNCHRONOUS, kEmptyFinalTextFrame, kEmptyFinalTextFrameSize));
- EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(NULL, frames_[0]->data.get());
EXPECT_EQ(0U, frames_[0]->header.payload_length);
@@ -620,11 +640,11 @@ TEST_F(WebSocketBasicStreamSocketTest, ThreeFrameEmptyMessage) {
kEmptyFinalContinuationFrameSize)};
CreateReadOnly(reads);
- EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_[0]->header.opcode);
frames_.clear();
- EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_TRUE(frames_[0]->header.final);
}
@@ -635,7 +655,7 @@ TEST_F(WebSocketBasicStreamSocketTest, HttpReadBufferIsUsed) {
SetHttpReadBuffer(kSampleFrame, kSampleFrameSize);
CreateNullStream();
- EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
ASSERT_EQ(1U, frames_.size());
ASSERT_TRUE(frames_[0]->data.get());
EXPECT_EQ(UINT64_C(6), frames_[0]->header.payload_length);
@@ -648,8 +668,9 @@ TEST_F(WebSocketBasicStreamSocketSingleReadTest,
SetHttpReadBuffer(kSampleFrame, 1);
CreateRead(MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1));
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
- EXPECT_EQ(OK, cb_.WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
ASSERT_TRUE(frames_[0]->data.get());
EXPECT_EQ(UINT64_C(6), frames_[0]->header.payload_length);
@@ -666,8 +687,9 @@ TEST_F(WebSocketBasicStreamSocketSingleReadTest,
kCloseFrame + kPartialFrameBytes,
kCloseFrameSize - kPartialFrameBytes));
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
- EXPECT_EQ(OK, cb_.WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode);
EXPECT_EQ(kCloseFrameSize - 2, frames_[0]->header.payload_length);
@@ -686,7 +708,7 @@ TEST_F(WebSocketBasicStreamSocketSingleReadTest,
kCloseFrame + kPartialFrameBytes,
kCloseFrameSize - kPartialFrameBytes));
- EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode);
}
@@ -702,8 +724,9 @@ TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncInvalidFrame) {
TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncInvalidFrame) {
CreateRead(MockRead(ASYNC, kInvalidFrame, kInvalidFrameSize));
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
- EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, cb_.WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsError(ERR_WS_PROTOCOL_ERROR));
}
// A control frame without a FIN flag is invalid and should not be passed
@@ -758,8 +781,9 @@ TEST_F(WebSocketBasicStreamSocketChunkedReadTest,
2,
LAST_FRAME_BIG);
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
- EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, cb_.WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsError(ERR_WS_PROTOCOL_ERROR));
// The caller should not call ReadFrames() again after receiving an error
// other than ERR_IO_PENDING.
EXPECT_TRUE(frames_.empty());
@@ -772,7 +796,7 @@ TEST_F(WebSocketBasicStreamSocketChunkedReadTest, SyncControlFrameAssembly) {
CreateChunkedRead(
SYNCHRONOUS, kCloseFrame, kCloseFrameSize, kChunkSize, 3, LAST_FRAME_BIG);
- EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode);
}
@@ -784,8 +808,9 @@ TEST_F(WebSocketBasicStreamSocketChunkedReadTest, AsyncControlFrameAssembly) {
CreateChunkedRead(
ASYNC, kCloseFrame, kCloseFrameSize, kChunkSize, 3, LAST_FRAME_BIG);
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
- EXPECT_EQ(OK, cb_.WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode);
}
@@ -813,8 +838,9 @@ TEST_F(WebSocketBasicStreamSocketChunkedReadTest, OneMegFrame) {
for (size_t frame = 0; frame < kExpectedFrameCount; ++frame) {
frames_.clear();
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
- EXPECT_EQ(OK, cb_.WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
size_t expected_payload_size = kReadBufferSize;
if (frame == 0) {
@@ -841,14 +867,16 @@ TEST_F(WebSocketBasicStreamSocketChunkedReadTest, ReservedFlagCleared) {
LAST_FRAME_BIG);
TestCompletionCallback cb[2];
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb[0].callback()));
- EXPECT_EQ(OK, cb[0].WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb[0].callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb[0].WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_TRUE(frames_[0]->header.reserved1);
frames_.clear();
- ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb[1].callback()));
- EXPECT_EQ(OK, cb[1].WaitForResult());
+ ASSERT_THAT(stream_->ReadFrames(&frames_, cb[1].callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb[1].WaitForResult(), IsOk());
ASSERT_EQ(1U, frames_.size());
EXPECT_FALSE(frames_[0]->header.reserved1);
}
@@ -858,7 +886,7 @@ TEST_F(WebSocketBasicStreamSocketWriteTest, WriteAtOnce) {
MockWrite writes[] = {MockWrite(SYNCHRONOUS, kWriteFrame, kWriteFrameSize)};
CreateWriteOnly(writes);
- EXPECT_EQ(OK, stream_->WriteFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->WriteFrames(&frames_, cb_.callback()), IsOk());
}
// Check that completely async writing works.
@@ -866,8 +894,9 @@ TEST_F(WebSocketBasicStreamSocketWriteTest, AsyncWriteAtOnce) {
MockWrite writes[] = {MockWrite(ASYNC, kWriteFrame, kWriteFrameSize)};
CreateWriteOnly(writes);
- ASSERT_EQ(ERR_IO_PENDING, stream_->WriteFrames(&frames_, cb_.callback()));
- EXPECT_EQ(OK, cb_.WaitForResult());
+ ASSERT_THAT(stream_->WriteFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsOk());
}
// Check that writing a frame to an extremely full kernel buffer (so that it
@@ -879,8 +908,9 @@ TEST_F(WebSocketBasicStreamSocketWriteTest, WriteInBits) {
MockWrite(ASYNC, kWriteFrame + 8, kWriteFrameSize - 8)};
CreateWriteOnly(writes);
- ASSERT_EQ(ERR_IO_PENDING, stream_->WriteFrames(&frames_, cb_.callback()));
- EXPECT_EQ(OK, cb_.WaitForResult());
+ ASSERT_THAT(stream_->WriteFrames(&frames_, cb_.callback()),
+ IsError(ERR_IO_PENDING));
+ EXPECT_THAT(cb_.WaitForResult(), IsOk());
}
// Check that writing a Pong frame with a NULL body works.
@@ -897,7 +927,7 @@ TEST_F(WebSocketBasicStreamSocketWriteTest, WriteNullPong) {
header.payload_length = 0;
std::vector<std::unique_ptr<WebSocketFrame>> frames;
frames.push_back(std::move(frame));
- EXPECT_EQ(OK, stream_->WriteFrames(&frames, cb_.callback()));
+ EXPECT_THAT(stream_->WriteFrames(&frames, cb_.callback()), IsOk());
}
// Check that writing with a non-NULL mask works correctly.
@@ -922,7 +952,7 @@ TEST_F(WebSocketBasicStreamSocketTest, WriteNonNulMask) {
header.payload_length = payload_size;
frames_.push_back(std::move(frame));
- EXPECT_EQ(OK, stream_->WriteFrames(&frames_, cb_.callback()));
+ EXPECT_THAT(stream_->WriteFrames(&frames_, cb_.callback()), IsOk());
}
TEST_F(WebSocketBasicStreamSocketTest, GetExtensionsWorks) {
diff --git a/chromium/net/websockets/websocket_channel.cc b/chromium/net/websockets/websocket_channel.cc
index a12d4f948f4..6cbd8b59642 100644
--- a/chromium/net/websockets/websocket_channel.cc
+++ b/chromium/net/websockets/websocket_channel.cc
@@ -28,12 +28,13 @@
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
-#include "net/log/net_log.h"
+#include "net/log/net_log_with_source.h"
#include "net/websockets/websocket_errors.h"
#include "net/websockets/websocket_event_interface.h"
#include "net/websockets/websocket_frame.h"
#include "net/websockets/websocket_handshake_request_info.h"
#include "net/websockets/websocket_handshake_response_info.h"
+#include "net/websockets/websocket_handshake_stream_create_helper.h"
#include "net/websockets/websocket_mux.h"
#include "net/websockets/websocket_stream.h"
#include "url/origin.h"
@@ -127,6 +128,16 @@ void GetFrameTypeForOpcode(WebSocketFrameHeader::OpCode opcode,
return;
}
+class DependentIOBuffer : public WrappedIOBuffer {
+ public:
+ DependentIOBuffer(scoped_refptr<IOBuffer> buffer, size_t offset)
+ : WrappedIOBuffer(buffer->data() + offset), buffer_(std::move(buffer)) {}
+
+ private:
+ ~DependentIOBuffer() override {}
+ scoped_refptr<net::IOBuffer> buffer_;
+};
+
} // namespace
// A class to encapsulate a set of frames and information about the size of
@@ -278,12 +289,12 @@ ChannelState WebSocketChannel::HandshakeNotificationSender::SendImmediately(
WebSocketChannel::PendingReceivedFrame::PendingReceivedFrame(
bool final,
WebSocketFrameHeader::OpCode opcode,
- const scoped_refptr<IOBuffer>& data,
+ scoped_refptr<IOBuffer> data,
uint64_t offset,
uint64_t size)
: final_(final),
opcode_(opcode),
- data_(data),
+ data_(std::move(data)),
offset_(offset),
size_(size) {}
@@ -340,8 +351,7 @@ void WebSocketChannel::SendAddChannelRequest(
const url::Origin& origin,
const GURL& first_party_for_cookies,
const std::string& additional_headers) {
- // Delegate to the tested version.
- SendAddChannelRequestWithSuppliedCreator(
+ SendAddChannelRequestWithSuppliedCallback(
socket_url, requested_subprotocols, origin, first_party_for_cookies,
additional_headers, base::Bind(&WebSocketStream::CreateAndConnectStream));
}
@@ -370,15 +380,16 @@ bool WebSocketChannel::InClosingState() const {
WebSocketChannel::ChannelState WebSocketChannel::SendFrame(
bool fin,
WebSocketFrameHeader::OpCode op_code,
- const std::vector<char>& data) {
- if (data.size() > INT_MAX) {
+ scoped_refptr<IOBuffer> buffer,
+ size_t buffer_size) {
+ if (buffer_size > INT_MAX) {
NOTREACHED() << "Frame size sanity check failed";
return CHANNEL_ALIVE;
}
if (stream_ == NULL) {
LOG(DFATAL) << "Got SendFrame without a connection established; "
<< "misbehaving renderer? fin=" << fin << " op_code=" << op_code
- << " data.size()=" << data.size();
+ << " buffer_size=" << buffer_size;
return CHANNEL_ALIVE;
}
if (InClosingState()) {
@@ -390,7 +401,7 @@ WebSocketChannel::ChannelState WebSocketChannel::SendFrame(
NOTREACHED() << "SendFrame() called in state " << state_;
return CHANNEL_ALIVE;
}
- if (data.size() > base::checked_cast<size_t>(current_send_quota_)) {
+ if (buffer_size > base::checked_cast<size_t>(current_send_quota_)) {
// TODO(ricea): Kill renderer.
return FailChannel("Send quota exceeded", kWebSocketErrorGoingAway, "");
// |this| has been deleted.
@@ -398,14 +409,14 @@ WebSocketChannel::ChannelState WebSocketChannel::SendFrame(
if (!WebSocketFrameHeader::IsKnownDataOpCode(op_code)) {
LOG(DFATAL) << "Got SendFrame with bogus op_code " << op_code
<< "; misbehaving renderer? fin=" << fin
- << " data.size()=" << data.size();
+ << " buffer_size=" << buffer_size;
return CHANNEL_ALIVE;
}
if (op_code == WebSocketFrameHeader::kOpCodeText ||
(op_code == WebSocketFrameHeader::kOpCodeContinuation &&
sending_text_message_)) {
StreamingUtf8Validator::State state =
- outgoing_utf8_validator_.AddBytes(data.data(), data.size());
+ outgoing_utf8_validator_.AddBytes(buffer->data(), buffer_size);
if (state == StreamingUtf8Validator::INVALID ||
(state == StreamingUtf8Validator::VALID_MIDPOINT && fin)) {
// TODO(ricea): Kill renderer.
@@ -416,14 +427,12 @@ WebSocketChannel::ChannelState WebSocketChannel::SendFrame(
sending_text_message_ = !fin;
DCHECK(!fin || state == StreamingUtf8Validator::VALID_ENDPOINT);
}
- current_send_quota_ -= data.size();
+ current_send_quota_ -= buffer_size;
// TODO(ricea): If current_send_quota_ has dropped below
// send_quota_low_water_mark_, it might be good to increase the "low
// water mark" and "high water mark", but only if the link to the WebSocket
// server is not saturated.
- scoped_refptr<IOBuffer> buffer(new IOBuffer(data.size()));
- std::copy(data.begin(), data.end(), buffer->data());
- return SendFrameFromIOBuffer(fin, op_code, buffer, data.size());
+ return SendFrameInternal(fin, op_code, std::move(buffer), buffer_size);
// |this| may have been deleted.
}
@@ -443,15 +452,18 @@ ChannelState WebSocketChannel::SendFlowControl(int64_t quota) {
const uint64_t bytes_to_send =
std::min(base::checked_cast<uint64_t>(quota), data_size);
const bool final = front.final() && data_size == bytes_to_send;
- const char* data =
- front.data().get() ? front.data()->data() + front.offset() : NULL;
- DCHECK(!bytes_to_send || data) << "Non empty data should not be null.";
- const std::vector<char> data_vector(data, data + bytes_to_send);
+ scoped_refptr<IOBuffer> buffer_to_pass;
+ if (front.data()) {
+ buffer_to_pass = new DependentIOBuffer(front.data(), front.offset());
+ } else {
+ DCHECK(!bytes_to_send) << "Non empty data should not be null.";
+ }
DVLOG(3) << "Sending frame previously split due to quota to the "
<< "renderer: quota=" << quota << " data_size=" << data_size
<< " bytes_to_send=" << bytes_to_send;
- if (event_interface_->OnDataFrame(final, front.opcode(), data_vector) ==
- CHANNEL_DELETED)
+ if (event_interface_->OnDataFrame(final, front.opcode(),
+ std::move(buffer_to_pass),
+ bytes_to_send) == CHANNEL_DELETED)
return CHANNEL_DELETED;
if (bytes_to_send < data_size) {
front.DidConsume(bytes_to_send);
@@ -547,10 +559,10 @@ void WebSocketChannel::SendAddChannelRequestForTesting(
const url::Origin& origin,
const GURL& first_party_for_cookies,
const std::string& additional_headers,
- const WebSocketStreamCreator& creator) {
- SendAddChannelRequestWithSuppliedCreator(socket_url, requested_subprotocols,
- origin, first_party_for_cookies,
- additional_headers, creator);
+ const WebSocketStreamRequestCreationCallback& callback) {
+ SendAddChannelRequestWithSuppliedCallback(socket_url, requested_subprotocols,
+ origin, first_party_for_cookies,
+ additional_headers, callback);
}
void WebSocketChannel::SetClosingHandshakeTimeoutForTesting(
@@ -563,13 +575,13 @@ void WebSocketChannel::SetUnderlyingConnectionCloseTimeoutForTesting(
underlying_connection_close_timeout_ = delay;
}
-void WebSocketChannel::SendAddChannelRequestWithSuppliedCreator(
+void WebSocketChannel::SendAddChannelRequestWithSuppliedCallback(
const GURL& socket_url,
const std::vector<std::string>& requested_subprotocols,
const url::Origin& origin,
const GURL& first_party_for_cookies,
const std::string& additional_headers,
- const WebSocketStreamCreator& creator) {
+ const WebSocketStreamRequestCreationCallback& callback) {
DCHECK_EQ(FRESHLY_CONSTRUCTED, state_);
if (!socket_url.SchemeIsWSOrWSS()) {
// TODO(ricea): Kill the renderer (this error should have been caught by
@@ -581,10 +593,13 @@ void WebSocketChannel::SendAddChannelRequestWithSuppliedCreator(
socket_url_ = socket_url;
std::unique_ptr<WebSocketStream::ConnectDelegate> connect_delegate(
new ConnectDelegate(this));
- stream_request_ = creator.Run(socket_url_, requested_subprotocols, origin,
- first_party_for_cookies, additional_headers,
- url_request_context_, BoundNetLog(),
- std::move(connect_delegate));
+ std::unique_ptr<WebSocketHandshakeStreamCreateHelper> create_helper(
+ new WebSocketHandshakeStreamCreateHelper(connect_delegate.get(),
+ requested_subprotocols));
+ stream_request_ = callback.Run(socket_url_, std::move(create_helper), origin,
+ first_party_for_cookies, additional_headers,
+ url_request_context_, NetLogWithSource(),
+ std::move(connect_delegate));
SetState(CONNECTING);
}
@@ -829,14 +844,14 @@ ChannelState WebSocketChannel::HandleFrame(
}
// Respond to the frame appropriately to its type.
- return HandleFrameByState(
- opcode, frame->header.final, frame->data, frame->header.payload_length);
+ return HandleFrameByState(opcode, frame->header.final, std::move(frame->data),
+ frame->header.payload_length);
}
ChannelState WebSocketChannel::HandleFrameByState(
const WebSocketFrameHeader::OpCode opcode,
bool final,
- const scoped_refptr<IOBuffer>& data_buffer,
+ scoped_refptr<IOBuffer> data_buffer,
uint64_t size) {
DCHECK_NE(RECV_CLOSED, state_)
<< "HandleFrame() does not support being called re-entrantly from within "
@@ -854,13 +869,13 @@ ChannelState WebSocketChannel::HandleFrameByState(
case WebSocketFrameHeader::kOpCodeText: // fall-thru
case WebSocketFrameHeader::kOpCodeBinary:
case WebSocketFrameHeader::kOpCodeContinuation:
- return HandleDataFrame(opcode, final, data_buffer, size);
+ return HandleDataFrame(opcode, final, std::move(data_buffer), size);
case WebSocketFrameHeader::kOpCodePing:
DVLOG(1) << "Got Ping of size " << size;
if (state_ == CONNECTED)
- return SendFrameFromIOBuffer(
- true, WebSocketFrameHeader::kOpCodePong, data_buffer, size);
+ return SendFrameInternal(true, WebSocketFrameHeader::kOpCodePong,
+ std::move(data_buffer), size);
DVLOG(3) << "Ignored ping in state " << state_;
return CHANNEL_ALIVE;
@@ -873,7 +888,7 @@ ChannelState WebSocketChannel::HandleFrameByState(
uint16_t code = kWebSocketNormalClosure;
std::string reason;
std::string message;
- if (!ParseClose(data_buffer, size, &code, &reason, &message)) {
+ if (!ParseClose(std::move(data_buffer), size, &code, &reason, &message)) {
return FailChannel(message, code, reason);
}
// TODO(ricea): Find a way to safely log the message from the close
@@ -893,7 +908,7 @@ ChannelState WebSocketChannel::HandleFrameByState(
ChannelState WebSocketChannel::HandleDataFrame(
WebSocketFrameHeader::OpCode opcode,
bool final,
- const scoped_refptr<IOBuffer>& data_buffer,
+ scoped_refptr<IOBuffer> data_buffer,
uint64_t size) {
if (state_ != CONNECTED) {
DVLOG(3) << "Ignored data packet received in state " << state_;
@@ -960,14 +975,11 @@ ChannelState WebSocketChannel::HandleDataFrame(
final = false;
}
- // TODO(ricea): Can this copy be eliminated?
- const char* const data_begin = size ? data_buffer->data() : NULL;
- const char* const data_end = data_begin + size;
- const std::vector<char> data(data_begin, data_end);
current_receive_quota_ -= size;
// Sends the received frame to the renderer process.
- return event_interface_->OnDataFrame(final, opcode_to_send, data);
+ return event_interface_->OnDataFrame(final, opcode_to_send,
+ std::move(data_buffer), size);
}
ChannelState WebSocketChannel::HandleCloseFrame(uint16_t code,
@@ -1030,10 +1042,10 @@ ChannelState WebSocketChannel::RespondToClosingHandshake() {
return event_interface_->OnClosingHandshake();
}
-ChannelState WebSocketChannel::SendFrameFromIOBuffer(
+ChannelState WebSocketChannel::SendFrameInternal(
bool fin,
WebSocketFrameHeader::OpCode op_code,
- const scoped_refptr<IOBuffer>& buffer,
+ scoped_refptr<IOBuffer> buffer,
uint64_t size) {
DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED);
DCHECK(stream_);
@@ -1043,7 +1055,7 @@ ChannelState WebSocketChannel::SendFrameFromIOBuffer(
header.final = fin;
header.masked = true;
header.payload_length = size;
- frame->data = buffer;
+ frame->data = std::move(buffer);
if (data_being_sent_) {
// Either the link to the WebSocket server is saturated, or several messages
@@ -1105,14 +1117,13 @@ ChannelState WebSocketChannel::SendClose(uint16_t code,
std::copy(
reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength);
}
- if (SendFrameFromIOBuffer(
- true, WebSocketFrameHeader::kOpCodeClose, body, size) ==
- CHANNEL_DELETED)
+ if (SendFrameInternal(true, WebSocketFrameHeader::kOpCodeClose,
+ std::move(body), size) == CHANNEL_DELETED)
return CHANNEL_DELETED;
return CHANNEL_ALIVE;
}
-bool WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer,
+bool WebSocketChannel::ParseClose(scoped_refptr<IOBuffer> buffer,
uint64_t size,
uint16_t* code,
std::string* reason,
diff --git a/chromium/net/websockets/websocket_channel.h b/chromium/net/websockets/websocket_channel.h
index ce46388dd0a..430897913a7 100644
--- a/chromium/net/websockets/websocket_channel.h
+++ b/chromium/net/websockets/websocket_channel.h
@@ -31,11 +31,12 @@ class Origin;
namespace net {
-class BoundNetLog;
+class NetLogWithSource;
class IOBuffer;
class URLRequestContext;
struct WebSocketHandshakeRequestInfo;
struct WebSocketHandshakeResponseInfo;
+class WebSocketHandshakeStreamCreateHelper;
// Transport-independent implementation of WebSockets. Implements protocol
// semantics that do not depend on the underlying transport. Provides the
@@ -48,14 +49,14 @@ class NET_EXPORT WebSocketChannel {
// WebSocketStream::CreateAndConnectStream().
typedef base::Callback<std::unique_ptr<WebSocketStreamRequest>(
const GURL&,
- const std::vector<std::string>&,
+ std::unique_ptr<WebSocketHandshakeStreamCreateHelper>,
const url::Origin&,
const GURL&,
const std::string&,
URLRequestContext*,
- const BoundNetLog&,
+ const NetLogWithSource&,
std::unique_ptr<WebSocketStream::ConnectDelegate>)>
- WebSocketStreamCreator;
+ WebSocketStreamRequestCreationCallback;
// Methods which return a value of type ChannelState may delete |this|. If the
// return value is CHANNEL_DELETED, then the caller must return without making
@@ -81,16 +82,17 @@ class NET_EXPORT WebSocketChannel {
// caller to ensure that they have sufficient send quota to send this data,
// otherwise the connection will be closed without sending. |fin| indicates
// the last frame in a message, equivalent to "FIN" as specified in section
- // 5.2 of RFC6455. |data| is the "Payload Data". If |op_code| is kOpCodeText,
- // or it is kOpCodeContinuation and the type the message is Text, then |data|
- // must be a chunk of a valid UTF-8 message, however there is no requirement
- // for |data| to be split on character boundaries. Calling SendFrame may
- // result in synchronous calls to |event_interface_| which may result in this
- // object being deleted. In that case, the return value will be
- // CHANNEL_DELETED.
+ // 5.2 of RFC6455. |buffer->data()| is the "Payload Data". If |op_code| is
+ // kOpCodeText, or it is kOpCodeContinuation and the type the message is
+ // Text, then |buffer->data()| must be a chunk of a valid UTF-8 message,
+ // however there is no requirement for |buffer->data()| to be split on
+ // character boundaries. Calling SendFrame may result in synchronous calls to
+ // |event_interface_| which may result in this object being deleted. In that
+ // case, the return value will be CHANNEL_DELETED.
ChannelState SendFrame(bool fin,
WebSocketFrameHeader::OpCode op_code,
- const std::vector<char>& data);
+ scoped_refptr<IOBuffer> buffer,
+ size_t buffer_size);
// Sends |quota| units of flow control to the remote side. If the underlying
// transport has a concept of |quota|, then it permits the remote server to
@@ -127,7 +129,7 @@ class NET_EXPORT WebSocketChannel {
const url::Origin& origin,
const GURL& first_party_for_cookies,
const std::string& additional_headers,
- const WebSocketStreamCreator& creator);
+ const WebSocketStreamRequestCreationCallback& callback);
// The default timout for the closing handshake is a sensible value (see
// kClosingHandshakeTimeoutSeconds in websocket_channel.cc). However, we can
@@ -158,7 +160,7 @@ class NET_EXPORT WebSocketChannel {
public:
PendingReceivedFrame(bool final,
WebSocketFrameHeader::OpCode opcode,
- const scoped_refptr<IOBuffer>& data,
+ scoped_refptr<IOBuffer> data,
uint64_t offset,
uint64_t size);
PendingReceivedFrame(const PendingReceivedFrame& other);
@@ -214,14 +216,15 @@ class NET_EXPORT WebSocketChannel {
// connection process.
class ConnectDelegate;
- // Starts the connection process, using the supplied creator callback.
- void SendAddChannelRequestWithSuppliedCreator(
+ // Starts the connection process, using the supplied stream request creation
+ // callback.
+ void SendAddChannelRequestWithSuppliedCallback(
const GURL& socket_url,
const std::vector<std::string>& requested_protocols,
const url::Origin& origin,
const GURL& first_party_for_cookies,
const std::string& additional_headers,
- const WebSocketStreamCreator& creator);
+ const WebSocketStreamRequestCreationCallback& callback);
// Success callback from WebSocketStream::CreateAndConnectStream(). Reports
// success to the event interface. May delete |this|.
@@ -284,7 +287,7 @@ class NET_EXPORT WebSocketChannel {
// HandleFrame() method.
ChannelState HandleFrameByState(const WebSocketFrameHeader::OpCode opcode,
bool final,
- const scoped_refptr<IOBuffer>& data_buffer,
+ scoped_refptr<IOBuffer> data_buffer,
uint64_t size) WARN_UNUSED_RESULT;
// Forwards a received data frame to the renderer, if connected. If
@@ -292,7 +295,7 @@ class NET_EXPORT WebSocketChannel {
// will fail the channel. Also checks the UTF-8 validity of text frames.
ChannelState HandleDataFrame(WebSocketFrameHeader::OpCode opcode,
bool final,
- const scoped_refptr<IOBuffer>& data_buffer,
+ scoped_refptr<IOBuffer> data_buffer,
uint64_t size) WARN_UNUSED_RESULT;
// Handles an incoming close frame with |code| and |reason|.
@@ -307,10 +310,10 @@ class NET_EXPORT WebSocketChannel {
// when the current write finishes. |fin| and |op_code| are defined as for
// SendFrame() above, except that |op_code| may also be a control frame
// opcode.
- ChannelState SendFrameFromIOBuffer(bool fin,
- WebSocketFrameHeader::OpCode op_code,
- const scoped_refptr<IOBuffer>& buffer,
- uint64_t size) WARN_UNUSED_RESULT;
+ ChannelState SendFrameInternal(bool fin,
+ WebSocketFrameHeader::OpCode op_code,
+ scoped_refptr<IOBuffer> buffer,
+ uint64_t buffer_size) WARN_UNUSED_RESULT;
// Performs the "Fail the WebSocket Connection" operation as defined in
// RFC6455. A NotifyFailure message is sent to the renderer with |message|.
@@ -338,7 +341,7 @@ class NET_EXPORT WebSocketChannel {
// is 1, or the supplied code is not permitted to be sent over the network,
// then false is returned and |message| is set to an appropriate console
// message.
- bool ParseClose(const scoped_refptr<IOBuffer>& buffer,
+ bool ParseClose(scoped_refptr<IOBuffer> buffer,
uint64_t size,
uint16_t* code,
std::string* reason,
diff --git a/chromium/net/websockets/websocket_channel_test.cc b/chromium/net/websockets/websocket_channel_test.cc
index 5fe3c800adb..10ea232eef5 100644
--- a/chromium/net/websockets/websocket_channel_test.cc
+++ b/chromium/net/websockets/websocket_channel_test.cc
@@ -30,11 +30,13 @@
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/http/http_response_headers.h"
+#include "net/log/net_log_with_source.h"
#include "net/url_request/url_request_context.h"
#include "net/websockets/websocket_errors.h"
#include "net/websockets/websocket_event_interface.h"
#include "net/websockets/websocket_handshake_request_info.h"
#include "net/websockets/websocket_handshake_response_info.h"
+#include "net/websockets/websocket_handshake_stream_create_helper.h"
#include "net/websockets/websocket_mux.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -156,13 +158,22 @@ class MockWebSocketEventInterface : public WebSocketEventInterface {
public:
MockWebSocketEventInterface() {}
+ ChannelState OnDataFrame(bool fin,
+ WebSocketMessageType type,
+ scoped_refptr<IOBuffer> buffer,
+ size_t buffer_size) override {
+ const char* data = buffer ? buffer->data() : nullptr;
+ return OnDataFrameVector(fin, type,
+ std::vector<char>(data, data + buffer_size));
+ }
+
MOCK_METHOD2(OnAddChannelResponse,
ChannelState(const std::string&,
const std::string&)); // NOLINT
- MOCK_METHOD3(OnDataFrame,
+ MOCK_METHOD3(OnDataFrameVector,
ChannelState(bool,
WebSocketMessageType,
- const std::vector<char>&)); // NOLINT
+ const std::vector<char>&)); // NOLINT
MOCK_METHOD1(OnFlowControl, ChannelState(int64_t)); // NOLINT
MOCK_METHOD0(OnClosingHandshake, ChannelState(void)); // NOLINT
MOCK_METHOD1(OnFailChannel, ChannelState(const std::string&)); // NOLINT
@@ -206,7 +217,8 @@ class FakeWebSocketEventInterface : public WebSocketEventInterface {
}
ChannelState OnDataFrame(bool fin,
WebSocketMessageType type,
- const std::vector<char>& data) override {
+ scoped_refptr<IOBuffer> data,
+ size_t data_size) override {
return CHANNEL_ALIVE;
}
ChannelState OnFlowControl(int64_t quota) override { return CHANNEL_ALIVE; }
@@ -470,8 +482,8 @@ class ReadableFakeWebSocketStream : public FakeWebSocketStream {
void PrepareReadFrames(IsSync async,
int error,
const InitFrame (&frames)[N]) {
- responses_.push_back(base::WrapUnique(
- new Response(async, error, CreateFrameVector(frames))));
+ responses_.push_back(
+ base::MakeUnique<Response>(async, error, CreateFrameVector(frames)));
}
// An alternate version of PrepareReadFrames for when we need to construct
@@ -481,13 +493,13 @@ class ReadableFakeWebSocketStream : public FakeWebSocketStream {
int error,
std::vector<std::unique_ptr<WebSocketFrame>> frames) {
responses_.push_back(
- base::WrapUnique(new Response(async, error, std::move(frames))));
+ base::MakeUnique<Response>(async, error, std::move(frames)));
}
// Prepares a fake error response (ie. there is no data).
void PrepareReadFramesError(IsSync async, int error) {
- responses_.push_back(base::WrapUnique(new Response(
- async, error, std::vector<std::unique_ptr<WebSocketFrame>>())));
+ responses_.push_back(base::MakeUnique<Response>(
+ async, error, std::vector<std::unique_ptr<WebSocketFrame>>()));
}
int ReadFrames(std::vector<std::unique_ptr<WebSocketFrame>>* frames,
@@ -695,42 +707,55 @@ class MockWebSocketStream : public WebSocketStream {
MOCK_METHOD0(AsWebSocketStream, WebSocketStream*());
};
-struct ArgumentCopyingWebSocketStreamCreator {
+class MockWebSocketStreamRequest : public WebSocketStreamRequest {
+ public:
+ MOCK_METHOD1(OnHandshakeStreamCreated,
+ void(WebSocketHandshakeStreamBase* handshake_stream));
+ MOCK_METHOD1(OnFailure, void(const std::string& message));
+};
+
+struct WebSocketStreamCreationCallbackArgumentSaver {
std::unique_ptr<WebSocketStreamRequest> Create(
const GURL& socket_url,
- const std::vector<std::string>& requested_subprotocols,
+ std::unique_ptr<WebSocketHandshakeStreamCreateHelper> create_helper,
const url::Origin& origin,
const GURL& first_party_for_cookies,
const std::string& additional_headers,
URLRequestContext* url_request_context,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<WebSocketStream::ConnectDelegate> connect_delegate) {
this->socket_url = socket_url;
- this->requested_subprotocols = requested_subprotocols;
+ this->create_helper = std::move(create_helper);
this->origin = origin;
this->first_party_for_cookies = first_party_for_cookies;
this->url_request_context = url_request_context;
this->net_log = net_log;
this->connect_delegate = std::move(connect_delegate);
- return base::WrapUnique(new WebSocketStreamRequest);
+ return base::WrapUnique(new MockWebSocketStreamRequest);
}
GURL socket_url;
+ std::unique_ptr<WebSocketHandshakeStreamCreateHelper> create_helper;
url::Origin origin;
GURL first_party_for_cookies;
- std::vector<std::string> requested_subprotocols;
URLRequestContext* url_request_context;
- BoundNetLog net_log;
+ NetLogWithSource net_log;
std::unique_ptr<WebSocketStream::ConnectDelegate> connect_delegate;
};
-// Converts a std::string to a std::vector<char>. For test purposes, it is
-// convenient to be able to specify data as a string, but the
-// WebSocketEventInterface requires the vector<char> type.
-std::vector<char> AsVector(const std::string& s) {
+std::vector<char> AsVector(const base::StringPiece& s) {
return std::vector<char>(s.begin(), s.end());
}
+// Converts a base::StringPiece to a IOBuffer. For test purposes, it is
+// convenient to be able to specify data as a string, but the
+// WebSocketEventInterface requires the IOBuffer type.
+scoped_refptr<IOBuffer> AsIOBuffer(const base::StringPiece& s) {
+ scoped_refptr<IOBuffer> buffer(new IOBuffer(s.size()));
+ std::copy(s.begin(), s.end(), buffer->data());
+ return buffer;
+}
+
class FakeSSLErrorCallbacks
: public WebSocketEventInterface::SSLErrorCallbacks {
public:
@@ -751,8 +776,8 @@ class WebSocketChannelTest : public ::testing::Test {
channel_->SendAddChannelRequestForTesting(
connect_data_.socket_url, connect_data_.requested_subprotocols,
connect_data_.origin, connect_data_.first_party_for_cookies, "",
- base::Bind(&ArgumentCopyingWebSocketStreamCreator::Create,
- base::Unretained(&connect_data_.creator)));
+ base::Bind(&WebSocketStreamCreationCallbackArgumentSaver::Create,
+ base::Unretained(&connect_data_.argument_saver)));
}
// Same as CreateChannelAndConnect(), but calls the on_success callback as
@@ -762,7 +787,8 @@ class WebSocketChannelTest : public ::testing::Test {
// Most tests aren't concerned with flow control from the renderer, so allow
// MAX_INT quota units.
EXPECT_EQ(CHANNEL_ALIVE, channel_->SendFlowControl(kPlentyOfQuota));
- connect_data_.creator.connect_delegate->OnSuccess(std::move(stream_));
+ connect_data_.argument_saver.connect_delegate->OnSuccess(
+ std::move(stream_));
}
// Returns a WebSocketEventInterface to be passed to the WebSocketChannel.
@@ -800,8 +826,7 @@ class WebSocketChannelTest : public ::testing::Test {
// First party for cookies for the request.
GURL first_party_for_cookies;
- // A fake WebSocketStreamCreator that just records its arguments.
- ArgumentCopyingWebSocketStreamCreator creator;
+ WebSocketStreamCreationCallbackArgumentSaver argument_saver;
};
ConnectData connect_data_;
@@ -873,7 +898,8 @@ class ChannelDeletingFakeWebSocketEventInterface
ChannelState OnDataFrame(bool fin,
WebSocketMessageType type,
- const std::vector<char>& data) override {
+ scoped_refptr<IOBuffer> data,
+ size_t data_size) override {
return fixture_->DeleteIfDeleting(EVENT_ON_DATA_FRAME);
}
@@ -919,7 +945,7 @@ class ChannelDeletingFakeWebSocketEventInterface
std::unique_ptr<WebSocketEventInterface>
WebSocketChannelDeletingTest::CreateEventInterface() {
- return base::WrapUnique(new ChannelDeletingFakeWebSocketEventInterface(this));
+ return base::MakeUnique<ChannelDeletingFakeWebSocketEventInterface>(this);
}
// Base class for tests which verify that EventInterface methods are called
@@ -990,7 +1016,8 @@ class WebSocketChannelFlowControlTest
void CreateChannelAndConnectWithQuota(int64_t quota) {
CreateChannelAndConnect();
EXPECT_EQ(CHANNEL_ALIVE, channel_->SendFlowControl(quota));
- connect_data_.creator.connect_delegate->OnSuccess(std::move(stream_));
+ connect_data_.argument_saver.connect_delegate->OnSuccess(
+ std::move(stream_));
}
virtual void CreateChannelAndConnectSuccesfully() { NOTREACHED(); }
@@ -1008,8 +1035,8 @@ class WebSocketChannelReceiveUtf8Test : public WebSocketChannelStreamTest {
}
};
-// Simple test that everything that should be passed to the creator function is
-// passed to the creator function.
+// Simple test that everything that should be passed to the stream creation
+// callback is passed to the argument saver.
TEST_F(WebSocketChannelTest, EverythingIsPassedToTheCreatorFunction) {
connect_data_.socket_url = GURL("ws://example.com/test");
connect_data_.origin = url::Origin(GURL("http://example.com"));
@@ -1018,13 +1045,12 @@ TEST_F(WebSocketChannelTest, EverythingIsPassedToTheCreatorFunction) {
CreateChannelAndConnect();
- const ArgumentCopyingWebSocketStreamCreator& actual = connect_data_.creator;
+ const WebSocketStreamCreationCallbackArgumentSaver& actual =
+ connect_data_.argument_saver;
EXPECT_EQ(&connect_data_.url_request_context, actual.url_request_context);
EXPECT_EQ(connect_data_.socket_url, actual.socket_url);
- EXPECT_EQ(connect_data_.requested_subprotocols,
- actual.requested_subprotocols);
EXPECT_EQ(connect_data_.origin.Serialize(), actual.origin.Serialize());
EXPECT_EQ(connect_data_.first_party_for_cookies,
actual.first_party_for_cookies);
@@ -1046,7 +1072,7 @@ TEST_F(WebSocketChannelTest, SendFlowControlDuringHandshakeOkay) {
TEST_F(WebSocketChannelDeletingTest, OnAddChannelResponseFail) {
CreateChannelAndConnect();
EXPECT_TRUE(channel_);
- connect_data_.creator.connect_delegate->OnFailure("bye");
+ connect_data_.argument_saver.connect_delegate->OnFailure("bye");
EXPECT_EQ(nullptr, channel_.get());
}
@@ -1098,9 +1124,9 @@ TEST_F(WebSocketChannelDeletingTest, OnFlowControlAfterSend) {
CreateChannelAndConnectSuccessfully();
ASSERT_TRUE(channel_);
deleting_ = EVENT_ON_FLOW_CONTROL;
- channel_->SendFrame(true,
- WebSocketFrameHeader::kOpCodeText,
- std::vector<char>(kDefaultInitialQuota, 'B'));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer(std::string(kDefaultInitialQuota, 'B')),
+ kDefaultInitialQuota);
EXPECT_EQ(nullptr, channel_.get());
}
@@ -1137,8 +1163,8 @@ TEST_F(WebSocketChannelDeletingTest, OnDropChannelWriteError) {
deleting_ = EVENT_ON_DROP_CHANNEL;
CreateChannelAndConnectSuccessfully();
ASSERT_TRUE(channel_);
- channel_->SendFrame(
- true, WebSocketFrameHeader::kOpCodeText, AsVector("this will fail"));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("this will fail"), 14U);
EXPECT_EQ(nullptr, channel_.get());
}
@@ -1188,9 +1214,9 @@ TEST_F(WebSocketChannelDeletingTest, OnNotifyFinishOpeningHandshakeError) {
scoped_refptr<HttpResponseHeaders> response_headers(
new HttpResponseHeaders(""));
channel_->OnFinishOpeningHandshake(
- base::WrapUnique(new WebSocketHandshakeResponseInfo(
+ base::MakeUnique<WebSocketHandshakeResponseInfo>(
GURL("http://www.example.com/"), 200, "OK", response_headers,
- base::Time())));
+ base::Time()));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(nullptr, channel_.get());
}
@@ -1200,9 +1226,9 @@ TEST_F(WebSocketChannelDeletingTest, FailChannelInSendFrame) {
deleting_ = EVENT_ON_FAIL_CHANNEL;
CreateChannelAndConnectSuccessfully();
ASSERT_TRUE(channel_);
- channel_->SendFrame(true,
- WebSocketFrameHeader::kOpCodeText,
- std::vector<char>(kDefaultInitialQuota * 2, 'T'));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer(std::string(kDefaultInitialQuota * 2, 'T')),
+ kDefaultInitialQuota * 2);
EXPECT_EQ(nullptr, channel_.get());
}
@@ -1335,7 +1361,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, ConnectSuccessReported) {
CreateChannelAndConnect();
- connect_data_.creator.connect_delegate->OnSuccess(std::move(stream_));
+ connect_data_.argument_saver.connect_delegate->OnSuccess(std::move(stream_));
}
TEST_F(WebSocketChannelEventInterfaceTest, ConnectFailureReported) {
@@ -1343,7 +1369,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, ConnectFailureReported) {
CreateChannelAndConnect();
- connect_data_.creator.connect_delegate->OnFailure("hello");
+ connect_data_.argument_saver.connect_delegate->OnFailure("hello");
}
TEST_F(WebSocketChannelEventInterfaceTest, NonWebSocketSchemeRejected) {
@@ -1358,8 +1384,8 @@ TEST_F(WebSocketChannelEventInterfaceTest, ProtocolPassed) {
CreateChannelAndConnect();
- connect_data_.creator.connect_delegate->OnSuccess(
- base::WrapUnique(new FakeWebSocketStream("Bob", "")));
+ connect_data_.argument_saver.connect_delegate->OnSuccess(
+ base::MakeUnique<FakeWebSocketStream>("Bob", ""));
}
TEST_F(WebSocketChannelEventInterfaceTest, ExtensionsPassed) {
@@ -1369,8 +1395,8 @@ TEST_F(WebSocketChannelEventInterfaceTest, ExtensionsPassed) {
CreateChannelAndConnect();
- connect_data_.creator.connect_delegate->OnSuccess(
- base::WrapUnique(new FakeWebSocketStream("", "extension1, extension2")));
+ connect_data_.argument_saver.connect_delegate->OnSuccess(
+ base::MakeUnique<FakeWebSocketStream>("", "extension1, extension2"));
}
// The first frames from the server can arrive together with the handshake, in
@@ -1387,10 +1413,9 @@ TEST_F(WebSocketChannelEventInterfaceTest, DataLeftFromHandshake) {
InSequence s;
EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _));
EXPECT_CALL(*event_interface_, OnFlowControl(_));
- EXPECT_CALL(
- *event_interface_,
- OnDataFrame(
- true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO")));
+ EXPECT_CALL(*event_interface_,
+ OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeText,
+ AsVector("HELLO")));
}
CreateChannelAndConnectSuccessfully();
@@ -1456,10 +1481,9 @@ TEST_F(WebSocketChannelEventInterfaceTest, NormalAsyncRead) {
EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _));
EXPECT_CALL(*event_interface_, OnFlowControl(_));
EXPECT_CALL(checkpoint, Call(1));
- EXPECT_CALL(
- *event_interface_,
- OnDataFrame(
- true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO")));
+ EXPECT_CALL(*event_interface_,
+ OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeText,
+ AsVector("HELLO")));
EXPECT_CALL(checkpoint, Call(2));
}
@@ -1485,14 +1509,12 @@ TEST_F(WebSocketChannelEventInterfaceTest, AsyncThenSyncRead) {
InSequence s;
EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _));
EXPECT_CALL(*event_interface_, OnFlowControl(_));
- EXPECT_CALL(
- *event_interface_,
- OnDataFrame(
- true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO")));
- EXPECT_CALL(
- *event_interface_,
- OnDataFrame(
- true, WebSocketFrameHeader::kOpCodeText, AsVector("WORLD")));
+ EXPECT_CALL(*event_interface_,
+ OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeText,
+ AsVector("HELLO")));
+ EXPECT_CALL(*event_interface_,
+ OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeText,
+ AsVector("WORLD")));
}
CreateChannelAndConnectSuccessfully();
@@ -1527,26 +1549,25 @@ TEST_F(WebSocketChannelEventInterfaceTest, FragmentedMessage) {
InSequence s;
EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _));
EXPECT_CALL(*event_interface_, OnFlowControl(_));
+ EXPECT_CALL(*event_interface_,
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeText,
+ AsVector("THREE")));
EXPECT_CALL(
*event_interface_,
- OnDataFrame(
- false, WebSocketFrameHeader::kOpCodeText, AsVector("THREE")));
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector(" ")));
EXPECT_CALL(
*event_interface_,
- OnDataFrame(
- false, WebSocketFrameHeader::kOpCodeContinuation, AsVector(" ")));
- EXPECT_CALL(*event_interface_,
- OnDataFrame(false,
- WebSocketFrameHeader::kOpCodeContinuation,
- AsVector("SMALL")));
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector("SMALL")));
EXPECT_CALL(
*event_interface_,
- OnDataFrame(
- false, WebSocketFrameHeader::kOpCodeContinuation, AsVector(" ")));
- EXPECT_CALL(*event_interface_,
- OnDataFrame(true,
- WebSocketFrameHeader::kOpCodeContinuation,
- AsVector("FRAMES")));
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector(" ")));
+ EXPECT_CALL(
+ *event_interface_,
+ OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector("FRAMES")));
}
CreateChannelAndConnectSuccessfully();
@@ -1565,7 +1586,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, NullMessage) {
EXPECT_CALL(*event_interface_, OnFlowControl(_));
EXPECT_CALL(
*event_interface_,
- OnDataFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("")));
+ OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeText, AsVector("")));
CreateChannelAndConnectSuccessfully();
}
@@ -1674,14 +1695,13 @@ TEST_F(WebSocketChannelEventInterfaceTest, ControlFrameInDataMessage) {
InSequence s;
EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _));
EXPECT_CALL(*event_interface_, OnFlowControl(_));
+ EXPECT_CALL(*event_interface_,
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeText,
+ AsVector("SPLIT ")));
EXPECT_CALL(
*event_interface_,
- OnDataFrame(
- false, WebSocketFrameHeader::kOpCodeText, AsVector("SPLIT ")));
- EXPECT_CALL(*event_interface_,
- OnDataFrame(true,
- WebSocketFrameHeader::kOpCodeContinuation,
- AsVector("MESSAGE")));
+ OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector("MESSAGE")));
}
CreateChannelAndConnectSuccessfully();
@@ -1740,7 +1760,8 @@ TEST_F(WebSocketChannelEventInterfaceTest, SmallWriteDoesntUpdateQuota) {
}
CreateChannelAndConnectSuccessfully();
- channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("B"));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsIOBuffer("B"),
+ 1U);
}
// If we send enough to go below |send_quota_low_water_mark_| we should get our
@@ -1761,9 +1782,9 @@ TEST_F(WebSocketChannelEventInterfaceTest, LargeWriteUpdatesQuota) {
CreateChannelAndConnectSuccessfully();
checkpoint.Call(1);
- channel_->SendFrame(true,
- WebSocketFrameHeader::kOpCodeText,
- std::vector<char>(kDefaultInitialQuota, 'B'));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer(std::string(kDefaultInitialQuota, 'B')),
+ kDefaultInitialQuota);
checkpoint.Call(2);
}
@@ -1786,14 +1807,14 @@ TEST_F(WebSocketChannelEventInterfaceTest, QuotaReallyIsRefreshed) {
CreateChannelAndConnectSuccessfully();
checkpoint.Call(1);
- channel_->SendFrame(true,
- WebSocketFrameHeader::kOpCodeText,
- std::vector<char>(kDefaultQuotaRefreshTrigger, 'D'));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer(std::string(kDefaultQuotaRefreshTrigger, 'D')),
+ kDefaultQuotaRefreshTrigger);
checkpoint.Call(2);
// We should have received more quota at this point.
- channel_->SendFrame(true,
- WebSocketFrameHeader::kOpCodeText,
- std::vector<char>(kDefaultQuotaRefreshTrigger, 'E'));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer(std::string(kDefaultQuotaRefreshTrigger, 'E')),
+ kDefaultQuotaRefreshTrigger);
checkpoint.Call(3);
}
@@ -1809,9 +1830,9 @@ TEST_F(WebSocketChannelEventInterfaceTest, WriteOverQuotaIsRejected) {
}
CreateChannelAndConnectSuccessfully();
- channel_->SendFrame(true,
- WebSocketFrameHeader::kOpCodeText,
- std::vector<char>(kDefaultInitialQuota + 1, 'C'));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer(std::string(kDefaultInitialQuota + 1, 'C')),
+ kDefaultInitialQuota + 1);
}
// If a write fails, the channel is dropped.
@@ -1831,7 +1852,8 @@ TEST_F(WebSocketChannelEventInterfaceTest, FailedWrite) {
CreateChannelAndConnectSuccessfully();
checkpoint.Call(1);
- channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("H"));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsIOBuffer("H"),
+ 1U);
checkpoint.Call(2);
}
@@ -1877,7 +1899,8 @@ TEST_F(WebSocketChannelEventInterfaceTest, OnDropChannelCalledOnce) {
CreateChannelAndConnectSuccessfully();
- channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("yt?"));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("yt?"), 3U);
base::RunLoop().RunUntilIdle();
}
@@ -1966,7 +1989,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, StartHandshakeRequest) {
std::unique_ptr<WebSocketHandshakeRequestInfo> request_info(
new WebSocketHandshakeRequestInfo(GURL("ws://www.example.com/"),
base::Time()));
- connect_data_.creator.connect_delegate->OnStartOpeningHandshake(
+ connect_data_.argument_saver.connect_delegate->OnStartOpeningHandshake(
std::move(request_info));
base::RunLoop().RunUntilIdle();
@@ -1987,7 +2010,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, FinishHandshakeRequest) {
std::unique_ptr<WebSocketHandshakeResponseInfo> response_info(
new WebSocketHandshakeResponseInfo(GURL("ws://www.example.com/"), 200,
"OK", response_headers, base::Time()));
- connect_data_.creator.connect_delegate->OnFinishOpeningHandshake(
+ connect_data_.argument_saver.connect_delegate->OnFinishOpeningHandshake(
std::move(response_info));
base::RunLoop().RunUntilIdle();
}
@@ -2003,7 +2026,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, FailJustAfterHandshake) {
CreateChannelAndConnect();
WebSocketStream::ConnectDelegate* connect_delegate =
- connect_data_.creator.connect_delegate.get();
+ connect_data_.argument_saver.connect_delegate.get();
GURL url("ws://www.example.com/");
std::unique_ptr<WebSocketHandshakeRequestInfo> request_info(
new WebSocketHandshakeRequestInfo(url, base::Time()));
@@ -2214,7 +2237,7 @@ TEST_F(WebSocketChannelStreamTest, FlowControlEarly) {
CreateChannelAndConnect();
ASSERT_EQ(CHANNEL_ALIVE, channel_->SendFlowControl(kPlentyOfQuota));
checkpoint.Call(1);
- connect_data_.creator.connect_delegate->OnSuccess(std::move(stream_));
+ connect_data_.argument_saver.connect_delegate->OnSuccess(std::move(stream_));
checkpoint.Call(2);
}
@@ -2237,7 +2260,7 @@ TEST_F(WebSocketChannelStreamTest, FlowControlLate) {
set_stream(std::move(mock_stream_));
CreateChannelAndConnect();
- connect_data_.creator.connect_delegate->OnSuccess(std::move(stream_));
+ connect_data_.argument_saver.connect_delegate->OnSuccess(std::move(stream_));
checkpoint.Call(1);
ASSERT_EQ(CHANNEL_ALIVE, channel_->SendFlowControl(kPlentyOfQuota));
checkpoint.Call(2);
@@ -2256,7 +2279,7 @@ TEST_F(WebSocketChannelStreamTest, FlowControlStopsReadFrames) {
set_stream(std::move(mock_stream_));
CreateChannelAndConnect();
ASSERT_EQ(CHANNEL_ALIVE, channel_->SendFlowControl(4));
- connect_data_.creator.connect_delegate->OnSuccess(std::move(stream_));
+ connect_data_.argument_saver.connect_delegate->OnSuccess(std::move(stream_));
}
// Providing extra quota causes ReadFrames() to be called again.
@@ -2279,7 +2302,7 @@ TEST_F(WebSocketChannelStreamTest, FlowControlStartsWithMoreQuota) {
set_stream(std::move(mock_stream_));
CreateChannelAndConnect();
ASSERT_EQ(CHANNEL_ALIVE, channel_->SendFlowControl(4));
- connect_data_.creator.connect_delegate->OnSuccess(std::move(stream_));
+ connect_data_.argument_saver.connect_delegate->OnSuccess(std::move(stream_));
checkpoint.Call(1);
ASSERT_EQ(CHANNEL_ALIVE, channel_->SendFlowControl(4));
}
@@ -2306,7 +2329,7 @@ TEST_F(WebSocketChannelStreamTest, ReadFramesNotCalledUntilQuotaAvailable) {
set_stream(std::move(mock_stream_));
CreateChannelAndConnect();
ASSERT_EQ(CHANNEL_ALIVE, channel_->SendFlowControl(2));
- connect_data_.creator.connect_delegate->OnSuccess(std::move(stream_));
+ connect_data_.argument_saver.connect_delegate->OnSuccess(std::move(stream_));
checkpoint.Call(1);
ASSERT_EQ(CHANNEL_ALIVE, channel_->SendFlowControl(2));
checkpoint.Call(2);
@@ -2326,17 +2349,17 @@ TEST_F(WebSocketChannelFlowControlTest, SingleFrameMessageSplitSync) {
InSequence s;
EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _));
EXPECT_CALL(*event_interface_, OnFlowControl(_));
+ EXPECT_CALL(*event_interface_,
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeText,
+ AsVector("FO")));
EXPECT_CALL(
*event_interface_,
- OnDataFrame(false, WebSocketFrameHeader::kOpCodeText, AsVector("FO")));
- EXPECT_CALL(
- *event_interface_,
- OnDataFrame(
- false, WebSocketFrameHeader::kOpCodeContinuation, AsVector("U")));
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector("U")));
EXPECT_CALL(
*event_interface_,
- OnDataFrame(
- true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("R")));
+ OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector("R")));
}
CreateChannelAndConnectWithQuota(2);
@@ -2359,19 +2382,19 @@ TEST_F(WebSocketChannelFlowControlTest, SingleFrameMessageSplitAsync) {
EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _));
EXPECT_CALL(*event_interface_, OnFlowControl(_));
EXPECT_CALL(checkpoint, Call(1));
- EXPECT_CALL(
- *event_interface_,
- OnDataFrame(false, WebSocketFrameHeader::kOpCodeText, AsVector("FO")));
+ EXPECT_CALL(*event_interface_,
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeText,
+ AsVector("FO")));
EXPECT_CALL(checkpoint, Call(2));
EXPECT_CALL(
*event_interface_,
- OnDataFrame(
- false, WebSocketFrameHeader::kOpCodeContinuation, AsVector("U")));
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector("U")));
EXPECT_CALL(checkpoint, Call(3));
EXPECT_CALL(
*event_interface_,
- OnDataFrame(
- true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("R")));
+ OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector("R")));
}
CreateChannelAndConnectWithQuota(2);
@@ -2405,25 +2428,24 @@ TEST_F(WebSocketChannelFlowControlTest, MultipleFrameSplit) {
EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _));
EXPECT_CALL(*event_interface_, OnFlowControl(_));
EXPECT_CALL(*event_interface_,
- OnDataFrame(false,
- WebSocketFrameHeader::kOpCodeText,
- AsVector("FIRST FRAME IS")));
- EXPECT_CALL(*event_interface_,
- OnDataFrame(false,
- WebSocketFrameHeader::kOpCodeContinuation,
- AsVector(" 25 BYTES. ")));
- EXPECT_CALL(*event_interface_,
- OnDataFrame(false,
- WebSocketFrameHeader::kOpCodeContinuation,
- AsVector("SECOND FRAME IS 26 BYTES. ")));
- EXPECT_CALL(*event_interface_,
- OnDataFrame(false,
- WebSocketFrameHeader::kOpCodeContinuation,
- AsVector("FINAL ")));
- EXPECT_CALL(*event_interface_,
- OnDataFrame(true,
- WebSocketFrameHeader::kOpCodeContinuation,
- AsVector("FRAME IS 24 BYTES.")));
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeText,
+ AsVector("FIRST FRAME IS")));
+ EXPECT_CALL(
+ *event_interface_,
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector(" 25 BYTES. ")));
+ EXPECT_CALL(
+ *event_interface_,
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector("SECOND FRAME IS 26 BYTES. ")));
+ EXPECT_CALL(
+ *event_interface_,
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector("FINAL ")));
+ EXPECT_CALL(
+ *event_interface_,
+ OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector("FRAME IS 24 BYTES.")));
}
CreateChannelAndConnectWithQuota(14);
ASSERT_EQ(CHANNEL_ALIVE, channel_->SendFlowControl(43));
@@ -2448,21 +2470,18 @@ TEST_F(WebSocketChannelFlowControlTest, EmptyMessageNoQuota) {
EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _));
EXPECT_CALL(*event_interface_, OnFlowControl(_));
EXPECT_CALL(*event_interface_,
- OnDataFrame(false,
- WebSocketFrameHeader::kOpCodeText,
- AsVector("FIRST ")));
- EXPECT_CALL(*event_interface_,
- OnDataFrame(true,
- WebSocketFrameHeader::kOpCodeContinuation,
- AsVector("MESSAGE")));
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeText,
+ AsVector("FIRST ")));
+ EXPECT_CALL(
+ *event_interface_,
+ OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector("MESSAGE")));
EXPECT_CALL(*event_interface_,
- OnDataFrame(true,
- WebSocketFrameHeader::kOpCodeText,
- AsVector("")));
+ OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeText,
+ AsVector("")));
EXPECT_CALL(*event_interface_,
- OnDataFrame(true,
- WebSocketFrameHeader::kOpCodeText,
- AsVector("THIRD MESSAGE")));
+ OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeText,
+ AsVector("THIRD MESSAGE")));
}
CreateChannelAndConnectWithQuota(6);
@@ -2490,23 +2509,25 @@ TEST_F(WebSocketChannelFlowControlTest, CloseFrameShouldNotOvertakeDataFrames) {
EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _));
EXPECT_CALL(*event_interface_, OnFlowControl(_));
EXPECT_CALL(*event_interface_,
- OnDataFrame(false, WebSocketFrameHeader::kOpCodeText,
- AsVector("FIRST ")));
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeText,
+ AsVector("FIRST ")));
EXPECT_CALL(checkpoint, Call(1));
- EXPECT_CALL(*event_interface_,
- OnDataFrame(false, WebSocketFrameHeader::kOpCodeContinuation,
- AsVector("MESSAG")));
+ EXPECT_CALL(
+ *event_interface_,
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector("MESSAG")));
EXPECT_CALL(checkpoint, Call(2));
EXPECT_CALL(*event_interface_,
- OnDataFrame(true, WebSocketFrameHeader::kOpCodeContinuation,
- AsVector("E")));
+ OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector("E")));
+ EXPECT_CALL(*event_interface_,
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeText,
+ AsVector("SECON")));
+ EXPECT_CALL(checkpoint, Call(3));
EXPECT_CALL(
*event_interface_,
- OnDataFrame(false, WebSocketFrameHeader::kOpCodeText, AsVector("SECON")));
- EXPECT_CALL(checkpoint, Call(3));
- EXPECT_CALL(*event_interface_,
- OnDataFrame(false, WebSocketFrameHeader::kOpCodeContinuation,
- AsVector("D ")));
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeContinuation,
+ AsVector("D ")));
EXPECT_CALL(*event_interface_, OnClosingHandshake());
EXPECT_CALL(checkpoint, Call(4));
@@ -2534,8 +2555,8 @@ TEST_F(WebSocketChannelStreamTest, SentFramesAreMasked) {
.WillOnce(Return(OK));
CreateChannelAndConnectSuccessfully();
- channel_->SendFrame(
- true, WebSocketFrameHeader::kOpCodeText, AsVector("NEEDS MASKING"));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("NEEDS MASKING"), 13U);
}
// RFC6455 5.5.1 "The application MUST NOT send any more data frames after
@@ -2552,8 +2573,8 @@ TEST_F(WebSocketChannelStreamTest, NothingIsSentAfterClose) {
CreateChannelAndConnectSuccessfully();
ASSERT_EQ(CHANNEL_ALIVE, channel_->StartClosingHandshake(1000, "Success"));
- channel_->SendFrame(
- true, WebSocketFrameHeader::kOpCodeText, AsVector("SHOULD BE IGNORED"));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("SHOULD BE IGNORED"), 18U);
}
// RFC6455 5.5.1 "If an endpoint receives a Close frame and did not previously
@@ -2794,12 +2815,12 @@ TEST_F(WebSocketChannelStreamTest, PongInTheMiddleOfDataMessage) {
}
CreateChannelAndConnectSuccessfully();
- channel_->SendFrame(
- false, WebSocketFrameHeader::kOpCodeText, AsVector("Hello "));
+ channel_->SendFrame(false, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("Hello "), 6U);
*read_frames = CreateFrameVector(frames);
read_callback.Run(OK);
- channel_->SendFrame(
- true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("World"));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeContinuation,
+ AsIOBuffer("World"), 5U);
}
// WriteFrames() may not be called until the previous write has completed.
@@ -2828,10 +2849,10 @@ TEST_F(WebSocketChannelStreamTest, WriteFramesOneAtATime) {
CreateChannelAndConnectSuccessfully();
checkpoint.Call(1);
- channel_->SendFrame(
- false, WebSocketFrameHeader::kOpCodeText, AsVector("Hello "));
- channel_->SendFrame(
- true, WebSocketFrameHeader::kOpCodeText, AsVector("World"));
+ channel_->SendFrame(false, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("Hello "), 6U);
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("World"), 5U);
checkpoint.Call(2);
write_callback.Run(OK);
checkpoint.Call(3);
@@ -2864,9 +2885,8 @@ TEST_F(WebSocketChannelStreamTest, WaitingMessagesAreBatched) {
CreateChannelAndConnectSuccessfully();
for (size_t i = 0; i < strlen(input_letters); ++i) {
- channel_->SendFrame(true,
- WebSocketFrameHeader::kOpCodeText,
- std::vector<char>(1, input_letters[i]));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer(std::string(1, input_letters[i])), 1U);
}
write_callback.Run(OK);
}
@@ -2885,9 +2905,9 @@ TEST_F(WebSocketChannelStreamTest, SendGoingAwayOnRendererQuotaExceeded) {
EXPECT_CALL(*mock_stream_, Close());
CreateChannelAndConnectSuccessfully();
- channel_->SendFrame(true,
- WebSocketFrameHeader::kOpCodeText,
- std::vector<char>(kDefaultInitialQuota + 1, 'C'));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer(std::string(kDefaultInitialQuota + 1, 'C')),
+ kDefaultInitialQuota + 1);
}
// For convenience, most of these tests use Text frames. However, the WebSocket
@@ -2904,9 +2924,9 @@ TEST_F(WebSocketChannelStreamTest, WrittenBinaryFramesAre8BitClean) {
CreateChannelAndConnectSuccessfully();
channel_->SendFrame(
- true,
- WebSocketFrameHeader::kOpCodeBinary,
- std::vector<char>(kBinaryBlob, kBinaryBlob + kBinaryBlobSize));
+ true, WebSocketFrameHeader::kOpCodeBinary,
+ AsIOBuffer(std::string(kBinaryBlob, kBinaryBlob + kBinaryBlobSize)),
+ kBinaryBlobSize);
ASSERT_TRUE(frames != nullptr);
ASSERT_EQ(1U, frames->size());
const WebSocketFrame* out_frame = (*frames)[0].get();
@@ -2933,11 +2953,11 @@ TEST_F(WebSocketChannelEventInterfaceTest, ReadBinaryFramesAre8BitClean) {
set_stream(std::move(stream));
EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _));
EXPECT_CALL(*event_interface_, OnFlowControl(_));
- EXPECT_CALL(*event_interface_,
- OnDataFrame(true,
- WebSocketFrameHeader::kOpCodeBinary,
- std::vector<char>(kBinaryBlob,
- kBinaryBlob + kBinaryBlobSize)));
+ EXPECT_CALL(
+ *event_interface_,
+ OnDataFrameVector(
+ true, WebSocketFrameHeader::kOpCodeBinary,
+ std::vector<char>(kBinaryBlob, kBinaryBlob + kBinaryBlobSize)));
CreateChannelAndConnectSuccessfully();
}
@@ -2950,8 +2970,8 @@ TEST_F(WebSocketChannelSendUtf8Test, InvalidUtf8Rejected) {
CreateChannelAndConnectSuccessfully();
- channel_->SendFrame(
- true, WebSocketFrameHeader::kOpCodeText, AsVector("\xff"));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("\xff"), 1U);
}
// A Text message cannot end with a partial UTF-8 character.
@@ -2962,8 +2982,8 @@ TEST_F(WebSocketChannelSendUtf8Test, IncompleteCharacterInFinalFrame) {
CreateChannelAndConnectSuccessfully();
- channel_->SendFrame(
- true, WebSocketFrameHeader::kOpCodeText, AsVector("\xc2"));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("\xc2"), 1U);
}
// A non-final Text frame may end with a partial UTF-8 character (compare to
@@ -2971,19 +2991,18 @@ TEST_F(WebSocketChannelSendUtf8Test, IncompleteCharacterInFinalFrame) {
TEST_F(WebSocketChannelSendUtf8Test, IncompleteCharacterInNonFinalFrame) {
CreateChannelAndConnectSuccessfully();
- channel_->SendFrame(
- false, WebSocketFrameHeader::kOpCodeText, AsVector("\xc2"));
+ channel_->SendFrame(false, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("\xc2"), 1U);
}
// UTF-8 parsing context must be retained between frames.
TEST_F(WebSocketChannelSendUtf8Test, ValidCharacterSplitBetweenFrames) {
CreateChannelAndConnectSuccessfully();
- channel_->SendFrame(
- false, WebSocketFrameHeader::kOpCodeText, AsVector("\xf1"));
- channel_->SendFrame(true,
- WebSocketFrameHeader::kOpCodeContinuation,
- AsVector("\x80\xa0\xbf"));
+ channel_->SendFrame(false, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("\xf1"), 1U);
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeContinuation,
+ AsIOBuffer("\x80\xa0\xbf"), 3U);
}
// Similarly, an invalid character should be detected even if split.
@@ -2994,11 +3013,10 @@ TEST_F(WebSocketChannelSendUtf8Test, InvalidCharacterSplit) {
CreateChannelAndConnectSuccessfully();
- channel_->SendFrame(
- false, WebSocketFrameHeader::kOpCodeText, AsVector("\xe1"));
- channel_->SendFrame(true,
- WebSocketFrameHeader::kOpCodeContinuation,
- AsVector("\x80\xa0\xbf"));
+ channel_->SendFrame(false, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("\xe1"), 1U);
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeContinuation,
+ AsIOBuffer("\x80\xa0\xbf"), 3U);
}
// An invalid character must be detected in continuation frames.
@@ -3009,12 +3027,12 @@ TEST_F(WebSocketChannelSendUtf8Test, InvalidByteInContinuation) {
CreateChannelAndConnectSuccessfully();
- channel_->SendFrame(
- false, WebSocketFrameHeader::kOpCodeText, AsVector("foo"));
- channel_->SendFrame(
- false, WebSocketFrameHeader::kOpCodeContinuation, AsVector("bar"));
- channel_->SendFrame(
- true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("\xff"));
+ channel_->SendFrame(false, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("foo"), 3U);
+ channel_->SendFrame(false, WebSocketFrameHeader::kOpCodeContinuation,
+ AsIOBuffer("bar"), 3U);
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeContinuation,
+ AsIOBuffer("\xff"), 1U);
}
// However, continuation frames of a Binary frame will not be tested for UTF-8
@@ -3022,12 +3040,12 @@ TEST_F(WebSocketChannelSendUtf8Test, InvalidByteInContinuation) {
TEST_F(WebSocketChannelSendUtf8Test, BinaryContinuationNotChecked) {
CreateChannelAndConnectSuccessfully();
- channel_->SendFrame(
- false, WebSocketFrameHeader::kOpCodeBinary, AsVector("foo"));
- channel_->SendFrame(
- false, WebSocketFrameHeader::kOpCodeContinuation, AsVector("bar"));
- channel_->SendFrame(
- true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("\xff"));
+ channel_->SendFrame(false, WebSocketFrameHeader::kOpCodeBinary,
+ AsIOBuffer("foo"), 3U);
+ channel_->SendFrame(false, WebSocketFrameHeader::kOpCodeContinuation,
+ AsIOBuffer("bar"), 3U);
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeContinuation,
+ AsIOBuffer("\xff"), 1U);
}
// Multiple text messages can be validated without the validation state getting
@@ -3035,8 +3053,10 @@ TEST_F(WebSocketChannelSendUtf8Test, BinaryContinuationNotChecked) {
TEST_F(WebSocketChannelSendUtf8Test, ValidateMultipleTextMessages) {
CreateChannelAndConnectSuccessfully();
- channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("foo"));
- channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("bar"));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("foo"), 3U);
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("bar"), 3U);
}
// UTF-8 validation is enforced on received Text frames.
@@ -3072,8 +3092,8 @@ TEST_F(WebSocketChannelStreamTest, InvalidUtf8TextFrameNotSent) {
CreateChannelAndConnectSuccessfully();
- channel_->SendFrame(
- true, WebSocketFrameHeader::kOpCodeText, AsVector("\xff"));
+ channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText,
+ AsIOBuffer("\xff"), 1U);
}
// The rest of the tests for receiving invalid UTF-8 test the communication with
@@ -3242,10 +3262,9 @@ TEST_F(WebSocketChannelEventInterfaceTest, BogusContinuation) {
EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _));
EXPECT_CALL(*event_interface_, OnFlowControl(kDefaultInitialQuota));
- EXPECT_CALL(
- *event_interface_,
- OnDataFrame(
- false, WebSocketFrameHeader::kOpCodeBinary, AsVector("frame1")));
+ EXPECT_CALL(*event_interface_,
+ OnDataFrameVector(false, WebSocketFrameHeader::kOpCodeBinary,
+ AsVector("frame1")));
EXPECT_CALL(
*event_interface_,
OnFailChannel(
@@ -3289,7 +3308,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, DataFramesNonEmptyOrFinal) {
EXPECT_CALL(*event_interface_, OnFlowControl(kDefaultInitialQuota));
EXPECT_CALL(
*event_interface_,
- OnDataFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("")));
+ OnDataFrameVector(true, WebSocketFrameHeader::kOpCodeText, AsVector("")));
CreateChannelAndConnectSuccessfully();
}
@@ -3308,7 +3327,7 @@ TEST_F(WebSocketChannelEventInterfaceTest, OnSSLCertificateErrorCalled) {
OnSSLCertificateErrorCalled(NotNull(), wss_url, _, fatal));
CreateChannelAndConnect();
- connect_data_.creator.connect_delegate->OnSSLCertificateError(
+ connect_data_.argument_saver.connect_delegate->OnSSLCertificateError(
std::move(fake_callbacks), ssl_info, fatal);
}
@@ -3374,7 +3393,8 @@ class WebSocketChannelStreamTimeoutTest : public WebSocketChannelStreamTest {
TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
channel_->SetUnderlyingConnectionCloseTimeoutForTesting(
TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
- connect_data_.creator.connect_delegate->OnSuccess(std::move(stream_));
+ connect_data_.argument_saver.connect_delegate->OnSuccess(
+ std::move(stream_));
}
};
@@ -3504,7 +3524,8 @@ TEST_F(WebSocketChannelTest, CurrentSendQuotaUpdated) {
channel_->SendFrame(
true, WebSocketFrameHeader::kOpCodeText,
- std::vector<char>(static_cast<size_t>(kMessageSize), 'a'));
+ AsIOBuffer(std::string(static_cast<size_t>(kMessageSize), 'a')),
+ static_cast<size_t>(kMessageSize));
int new_send_quota = channel_->current_send_quota();
EXPECT_EQ(kMessageSize, initial_send_quota - new_send_quota);
}
diff --git a/chromium/net/websockets/websocket_deflate_predictor_impl_test.cc b/chromium/net/websockets/websocket_deflate_predictor_impl_test.cc
index 191232daf2a..2d1ce001bfb 100644
--- a/chromium/net/websockets/websocket_deflate_predictor_impl_test.cc
+++ b/chromium/net/websockets/websocket_deflate_predictor_impl_test.cc
@@ -20,7 +20,7 @@ TEST(WebSocketDeflatePredictorImpl, Predict) {
WebSocketDeflatePredictorImpl predictor;
std::vector<std::unique_ptr<WebSocketFrame>> frames;
frames.push_back(
- base::WrapUnique(new WebSocketFrame(WebSocketFrameHeader::kOpCodeText)));
+ base::MakeUnique<WebSocketFrame>(WebSocketFrameHeader::kOpCodeText));
Result result = predictor.Predict(frames, 0);
EXPECT_EQ(WebSocketDeflatePredictor::DEFLATE, result);
diff --git a/chromium/net/websockets/websocket_deflate_stream_fuzzer.cc b/chromium/net/websockets/websocket_deflate_stream_fuzzer.cc
new file mode 100644
index 00000000000..fc5a15084c8
--- /dev/null
+++ b/chromium/net/websockets/websocket_deflate_stream_fuzzer.cc
@@ -0,0 +1,103 @@
+// Copyright 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.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_piece.h"
+#include "base/test/fuzzed_data_provider.h"
+#include "net/base/completion_callback.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/websockets/websocket_deflate_parameters.h"
+#include "net/websockets/websocket_deflate_predictor.h"
+#include "net/websockets/websocket_deflate_predictor_impl.h"
+#include "net/websockets/websocket_deflate_stream.h"
+#include "net/websockets/websocket_extension.h"
+#include "net/websockets/websocket_frame.h"
+#include "net/websockets/websocket_stream.h"
+
+namespace net {
+
+namespace {
+
+class WebSocketFuzzedStream final : public WebSocketStream {
+ public:
+ WebSocketFuzzedStream(const uint8_t* data, size_t size)
+ : fuzzed_data_provider_(data, size) {}
+
+ int ReadFrames(std::vector<std::unique_ptr<WebSocketFrame>>* frames,
+ const CompletionCallback& callback) override {
+ if (fuzzed_data_provider_.remaining_bytes() == 0)
+ return ERR_CONNECTION_CLOSED;
+ while (fuzzed_data_provider_.remaining_bytes() > 0)
+ frames->push_back(CreateFrame());
+ return OK;
+ }
+
+ int WriteFrames(std::vector<std::unique_ptr<WebSocketFrame>>* frames,
+ const CompletionCallback& callback) override {
+ return ERR_FILE_NOT_FOUND;
+ }
+
+ void Close() override {}
+ std::string GetSubProtocol() const override { return std::string(); }
+ std::string GetExtensions() const override { return std::string(); }
+
+ private:
+ std::unique_ptr<WebSocketFrame> CreateFrame() {
+ WebSocketFrameHeader::OpCode opcode =
+ fuzzed_data_provider_.ConsumeInt32InRange(
+ WebSocketFrameHeader::kOpCodeContinuation,
+ WebSocketFrameHeader::kOpCodeControlUnused);
+ auto frame = base::MakeUnique<WebSocketFrame>(opcode);
+ // Bad news: ConsumeBool actually consumes a whole byte per call, so do
+ // something hacky to conserve precious bits.
+ uint8_t flags = fuzzed_data_provider_.ConsumeUint8();
+ frame->header.final = flags & 0x1;
+ frame->header.reserved1 = (flags >> 1) & 0x1;
+ frame->header.reserved2 = (flags >> 2) & 0x1;
+ frame->header.reserved3 = (flags >> 3) & 0x1;
+ frame->header.masked = (flags >> 4) & 0x1;
+ uint64_t payload_length = fuzzed_data_provider_.ConsumeInt32InRange(0, 64);
+ base::StringPiece payload =
+ fuzzed_data_provider_.ConsumeBytes(payload_length);
+ frame->data = new WrappedIOBuffer(payload.data());
+ frame->header.payload_length = payload.size();
+ return frame;
+ }
+
+ base::FuzzedDataProvider fuzzed_data_provider_;
+};
+
+void WebSocketDeflateStreamFuzz(const uint8_t* data, size_t size) {
+ // WebSocketDeflateStream needs to be constructed on each call because it
+ // has state.
+ std::string failure_message;
+ WebSocketDeflateParameters parameters;
+ parameters.Initialize(WebSocketExtension("permessage-deflate"),
+ &failure_message);
+ WebSocketDeflateStream deflate_stream(
+ base::MakeUnique<WebSocketFuzzedStream>(data, size), parameters,
+ base::MakeUnique<WebSocketDeflatePredictorImpl>());
+ std::vector<std::unique_ptr<net::WebSocketFrame>> frames;
+ deflate_stream.ReadFrames(&frames, CompletionCallback());
+}
+
+} // namespace
+
+} // namespace net
+
+// Entry point for LibFuzzer.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ net::WebSocketDeflateStreamFuzz(data, size);
+
+ return 0;
+}
diff --git a/chromium/net/websockets/websocket_deflate_stream_test.cc b/chromium/net/websockets/websocket_deflate_stream_test.cc
index 5106df710cd..f4dde0872e5 100644
--- a/chromium/net/websockets/websocket_deflate_stream_test.cc
+++ b/chromium/net/websockets/websocket_deflate_stream_test.cc
@@ -21,6 +21,7 @@
#include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
+#include "net/test/gtest_util.h"
#include "net/websockets/websocket_deflate_parameters.h"
#include "net/websockets/websocket_deflate_predictor.h"
#include "net/websockets/websocket_deflater.h"
@@ -31,6 +32,9 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsError;
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -369,7 +373,8 @@ TEST_F(WebSocketDeflateStreamTest, ReadFailedImmediately) {
EXPECT_CALL(*mock_stream_, ReadFrames(&frames, _))
.WillOnce(Return(ERR_FAILED));
}
- EXPECT_EQ(ERR_FAILED, deflate_stream_->ReadFrames(&frames, callback));
+ EXPECT_THAT(deflate_stream_->ReadFrames(&frames, callback),
+ IsError(ERR_FAILED));
}
TEST_F(WebSocketDeflateStreamTest, ReadUncompressedFrameImmediately) {
@@ -387,7 +392,7 @@ TEST_F(WebSocketDeflateStreamTest, ReadUncompressedFrameImmediately) {
.WillOnce(Invoke(&stub, &ReadFramesStub::Call));
}
CompletionCallback callback;
- ASSERT_EQ(OK, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback), IsOk());
ASSERT_EQ(1u, frames.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames[0]->header.opcode);
EXPECT_TRUE(frames[0]->header.final);
@@ -409,7 +414,8 @@ TEST_F(WebSocketDeflateStreamTest, ReadUncompressedFrameAsync) {
EXPECT_CALL(checkpoint, Call(0));
EXPECT_CALL(mock_callback, Call(OK));
}
- ASSERT_EQ(ERR_IO_PENDING, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback),
+ IsError(ERR_IO_PENDING));
ASSERT_EQ(0u, frames.size());
checkpoint.Call(0);
@@ -440,7 +446,8 @@ TEST_F(WebSocketDeflateStreamTest, ReadFailedAsync) {
EXPECT_CALL(checkpoint, Call(0));
EXPECT_CALL(mock_callback, Call(ERR_FAILED));
}
- ASSERT_EQ(ERR_IO_PENDING, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback),
+ IsError(ERR_IO_PENDING));
ASSERT_EQ(0u, frames.size());
checkpoint.Call(0);
@@ -467,7 +474,7 @@ TEST_F(WebSocketDeflateStreamTest, ReadCompressedFrameImmediately) {
EXPECT_CALL(*mock_stream_, ReadFrames(&frames, _))
.WillOnce(Invoke(&stub, &ReadFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback), IsOk());
ASSERT_EQ(1u, frames.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames[0]->header.opcode);
EXPECT_TRUE(frames[0]->header.final);
@@ -488,7 +495,8 @@ TEST_F(WebSocketDeflateStreamTest, ReadCompressedFrameAsync) {
EXPECT_CALL(checkpoint, Call(0));
EXPECT_CALL(mock_callback, Call(OK));
}
- ASSERT_EQ(ERR_IO_PENDING, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback),
+ IsError(ERR_IO_PENDING));
checkpoint.Call(0);
@@ -528,7 +536,8 @@ TEST_F(WebSocketDeflateStreamTest,
EXPECT_CALL(checkpoint, Call(0));
EXPECT_CALL(mock_callback, Call(OK));
}
- ASSERT_EQ(ERR_IO_PENDING, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback),
+ IsError(ERR_IO_PENDING));
ASSERT_EQ(0u, frames.size());
AppendTo(stub2.frames_passed(),
@@ -588,7 +597,7 @@ TEST_F(WebSocketDeflateStreamTest, MergeMultipleFramesInReadFrames) {
EXPECT_CALL(*mock_stream_, ReadFrames(&frames, _))
.WillOnce(Invoke(&stub, &ReadFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback), IsOk());
ASSERT_EQ(1u, frames.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames[0]->header.opcode);
EXPECT_TRUE(frames[0]->header.final);
@@ -613,7 +622,7 @@ TEST_F(WebSocketDeflateStreamTest, ReadUncompressedEmptyFrames) {
EXPECT_CALL(*mock_stream_, ReadFrames(&frames, _))
.WillOnce(Invoke(&stub, &ReadFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback), IsOk());
ASSERT_EQ(2u, frames.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames[0]->header.opcode);
EXPECT_FALSE(frames[0]->header.final);
@@ -644,7 +653,7 @@ TEST_F(WebSocketDeflateStreamTest, ReadCompressedEmptyFrames) {
EXPECT_CALL(*mock_stream_, ReadFrames(&frames, _))
.WillOnce(Invoke(&stub, &ReadFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback), IsOk());
ASSERT_EQ(1u, frames.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames[0]->header.opcode);
EXPECT_TRUE(frames[0]->header.final);
@@ -672,7 +681,7 @@ TEST_F(WebSocketDeflateStreamTest,
EXPECT_CALL(*mock_stream_, ReadFrames(&frames, _))
.WillOnce(Invoke(&stub, &ReadFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback), IsOk());
ASSERT_EQ(1u, frames.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames[0]->header.opcode);
EXPECT_TRUE(frames[0]->header.final);
@@ -699,7 +708,7 @@ TEST_F(WebSocketDeflateStreamTest, ReadControlFrameBetweenDataFrames) {
EXPECT_CALL(*mock_stream_, ReadFrames(&frames, _))
.WillOnce(Invoke(&stub, &ReadFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback), IsOk());
ASSERT_EQ(2u, frames.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodePing, frames[0]->header.opcode);
EXPECT_TRUE(frames[0]->header.final);
@@ -733,7 +742,7 @@ TEST_F(WebSocketDeflateStreamTest, SplitToMultipleFramesInReadFrames) {
.WillOnce(Invoke(&stub, &ReadFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback), IsOk());
ASSERT_EQ(3u, frames.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeBinary, frames[0]->header.opcode);
EXPECT_FALSE(frames[0]->header.final);
@@ -779,7 +788,7 @@ TEST_F(WebSocketDeflateStreamTest, InflaterInternalDataCanBeEmpty) {
.WillOnce(Invoke(&stub, &ReadFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback), IsOk());
ASSERT_EQ(2u, frames.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeBinary, frames[0]->header.opcode);
EXPECT_FALSE(frames[0]->header.final);
@@ -864,7 +873,7 @@ TEST_F(WebSocketDeflateStreamTest, ReadCompressedMessages) {
EXPECT_CALL(*mock_stream_, ReadFrames(&frames, _))
.WillOnce(Invoke(&stub, &ReadFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback), IsOk());
ASSERT_EQ(2u, frames.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames[0]->header.opcode);
EXPECT_TRUE(frames[0]->header.final);
@@ -895,7 +904,7 @@ TEST_F(WebSocketDeflateStreamTest, ReadUncompressedMessages) {
EXPECT_CALL(*mock_stream_, ReadFrames(&frames, _))
.WillOnce(Invoke(&stub, &ReadFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback), IsOk());
ASSERT_EQ(2u, frames.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames[0]->header.opcode);
EXPECT_TRUE(frames[0]->header.final);
@@ -928,7 +937,7 @@ TEST_F(WebSocketDeflateStreamTest,
EXPECT_CALL(*mock_stream_, ReadFrames(&frames, _))
.WillOnce(Invoke(&stub, &ReadFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback), IsOk());
ASSERT_EQ(2u, frames.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames[0]->header.opcode);
EXPECT_TRUE(frames[0]->header.final);
@@ -961,7 +970,7 @@ TEST_F(WebSocketDeflateStreamTest,
EXPECT_CALL(*mock_stream_, ReadFrames(&frames, _))
.WillOnce(Invoke(&stub, &ReadFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback), IsOk());
ASSERT_EQ(2u, frames.size());
EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames[0]->header.opcode);
EXPECT_TRUE(frames[0]->header.final);
@@ -994,7 +1003,8 @@ TEST_F(WebSocketDeflateStreamTest, ReadEmptyAsyncFrame) {
EXPECT_CALL(mock_callback, Call(OK));
}
- ASSERT_EQ(ERR_IO_PENDING, deflate_stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->ReadFrames(&frames, callback),
+ IsError(ERR_IO_PENDING));
AppendTo(stub_vector[0]->frames_passed(),
WebSocketFrameHeader::kOpCodeText,
kReserved1,
@@ -1017,7 +1027,7 @@ TEST_F(WebSocketDeflateStreamTest, WriteEmpty) {
InSequence s;
EXPECT_CALL(*mock_stream_, WriteFrames(&frames, _)).Times(0);
}
- EXPECT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
+ EXPECT_THAT(deflate_stream_->WriteFrames(&frames, callback), IsOk());
}
TEST_F(WebSocketDeflateStreamTest, WriteFailedImmediately) {
@@ -1031,7 +1041,8 @@ TEST_F(WebSocketDeflateStreamTest, WriteFailedImmediately) {
AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "hello");
predictor_->AddFramesToBeInput(frames);
- EXPECT_EQ(ERR_FAILED, deflate_stream_->WriteFrames(&frames, callback));
+ EXPECT_THAT(deflate_stream_->WriteFrames(&frames, callback),
+ IsError(ERR_FAILED));
predictor_->Clear();
}
@@ -1046,7 +1057,7 @@ TEST_F(WebSocketDeflateStreamTest, WriteFrameImmediately) {
EXPECT_CALL(*mock_stream_, WriteFrames(_, _))
.WillOnce(Invoke(&stub, &WriteFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->WriteFrames(&frames, callback), IsOk());
const std::vector<std::unique_ptr<WebSocketFrame>>& frames_passed =
*stub.frames();
ASSERT_EQ(1u, frames_passed.size());
@@ -1072,7 +1083,8 @@ TEST_F(WebSocketDeflateStreamTest, WriteFrameAsync) {
}
AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "Hello");
predictor_->AddFramesToBeInput(frames);
- ASSERT_EQ(ERR_IO_PENDING, deflate_stream_->WriteFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->WriteFrames(&frames, callback),
+ IsError(ERR_IO_PENDING));
checkpoint.Call(0);
stub.callback().Run(OK);
@@ -1101,7 +1113,7 @@ TEST_F(WebSocketDeflateStreamTest, WriteControlFrameBetweenDataFrames) {
EXPECT_CALL(*mock_stream_, WriteFrames(&frames, _))
.WillOnce(Invoke(&stub, &WriteFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->WriteFrames(&frames, callback), IsOk());
const std::vector<std::unique_ptr<WebSocketFrame>>& frames_passed =
*stub.frames();
ASSERT_EQ(2u, frames_passed.size());
@@ -1127,7 +1139,7 @@ TEST_F(WebSocketDeflateStreamTest, WriteEmptyMessage) {
EXPECT_CALL(*mock_stream_, WriteFrames(&frames, _))
.WillOnce(Invoke(&stub, &WriteFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->WriteFrames(&frames, callback), IsOk());
const std::vector<std::unique_ptr<WebSocketFrame>>& frames_passed =
*stub.frames();
ASSERT_EQ(1u, frames_passed.size());
@@ -1152,7 +1164,7 @@ TEST_F(WebSocketDeflateStreamTest, WriteUncompressedMessage) {
EXPECT_CALL(*mock_stream_, WriteFrames(&frames, _))
.WillOnce(Invoke(&stub, &WriteFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->WriteFrames(&frames, callback), IsOk());
const std::vector<std::unique_ptr<WebSocketFrame>>& frames_passed =
*stub.frames();
ASSERT_EQ(2u, frames_passed.size());
@@ -1192,7 +1204,7 @@ TEST_F(WebSocketDeflateStreamTest, LargeDeflatedFramesShouldBeSplit) {
FrameFlag flag = is_final ? kFinal : kNoFlag;
AppendTo(&frames, WebSocketFrameHeader::kOpCodeBinary, flag, data);
predictor_->AddFramesToBeInput(frames);
- ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->WriteFrames(&frames, callback), IsOk());
total_compressed_frames.insert(
total_compressed_frames.end(),
std::make_move_iterator(stub.frames()->begin()),
@@ -1236,7 +1248,7 @@ TEST_F(WebSocketDeflateStreamTest, WriteMultipleMessages) {
EXPECT_CALL(*mock_stream_, WriteFrames(&frames, _))
.WillOnce(Invoke(&stub, &WriteFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->WriteFrames(&frames, callback), IsOk());
const std::vector<std::unique_ptr<WebSocketFrame>>& frames_passed =
*stub.frames();
ASSERT_EQ(2u, frames_passed.size());
@@ -1265,7 +1277,7 @@ TEST_F(WebSocketDeflateStreamWithDoNotTakeOverContextTest,
EXPECT_CALL(*mock_stream_, WriteFrames(&frames, _))
.WillOnce(Invoke(&stub, &WriteFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->WriteFrames(&frames, callback), IsOk());
const std::vector<std::unique_ptr<WebSocketFrame>>& frames_passed =
*stub.frames();
ASSERT_EQ(2u, frames_passed.size());
@@ -1302,7 +1314,7 @@ TEST_F(WebSocketDeflateStreamWithDoNotTakeOverContextTest,
EXPECT_CALL(*mock_stream_, WriteFrames(&frames, _))
.WillOnce(Invoke(&stub, &WriteFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
+ ASSERT_THAT(deflate_stream_->WriteFrames(&frames, callback), IsOk());
const std::vector<std::unique_ptr<WebSocketFrame>>& frames_passed =
*stub.frames();
ASSERT_EQ(5u, frames_passed.size());
@@ -1345,7 +1357,7 @@ TEST_F(WebSocketDeflateStreamWithClientWindowBitsTest, WindowBits8) {
EXPECT_CALL(*mock_stream_, WriteFrames(_, _))
.WillOnce(Invoke(&stub, &WriteFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames_, callback));
+ ASSERT_THAT(deflate_stream_->WriteFrames(&frames_, callback), IsOk());
const std::vector<std::unique_ptr<WebSocketFrame>>& frames_passed =
*stub.frames();
ASSERT_EQ(1u, frames_passed.size());
@@ -1365,7 +1377,7 @@ TEST_F(WebSocketDeflateStreamWithClientWindowBitsTest, WindowBits10) {
EXPECT_CALL(*mock_stream_, WriteFrames(_, _))
.WillOnce(Invoke(&stub, &WriteFramesStub::Call));
}
- ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames_, callback));
+ ASSERT_THAT(deflate_stream_->WriteFrames(&frames_, callback), IsOk());
const std::vector<std::unique_ptr<WebSocketFrame>>& frames_passed =
*stub.frames();
ASSERT_EQ(1u, frames_passed.size());
diff --git a/chromium/net/websockets/websocket_end_to_end_test.cc b/chromium/net/websockets/websocket_end_to_end_test.cc
index be464f6e103..a0a87e845dd 100644
--- a/chromium/net/websockets/websocket_end_to_end_test.cc
+++ b/chromium/net/websockets/websocket_end_to_end_test.cc
@@ -71,7 +71,8 @@ class ConnectTestingEventInterface : public WebSocketEventInterface {
ChannelState OnDataFrame(bool fin,
WebSocketMessageType type,
- const std::vector<char>& data) override;
+ scoped_refptr<IOBuffer> data,
+ size_t data_size) override;
ChannelState OnFlowControl(int64_t quota) override;
@@ -142,7 +143,8 @@ ChannelState ConnectTestingEventInterface::OnAddChannelResponse(
ChannelState ConnectTestingEventInterface::OnDataFrame(
bool fin,
WebSocketMessageType type,
- const std::vector<char>& data) {
+ scoped_refptr<IOBuffer> data,
+ size_t data_size) {
return CHANNEL_ALIVE;
}
@@ -213,7 +215,6 @@ class TestProxyDelegateWithProxyInfo : public ProxyDelegate {
protected:
void OnResolveProxy(const GURL& url,
const std::string& method,
- int load_flags,
const ProxyService& proxy_service,
ProxyInfo* result) override {
resolved_proxy_info_.url = url;
@@ -233,6 +234,15 @@ class TestProxyDelegateWithProxyInfo : public ProxyDelegate {
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 {}
+ ProxyServer GetDefaultAlternativeProxy() const override {
+ return ProxyServer();
+ }
private:
ResolvedProxyInfo resolved_proxy_info_;
@@ -430,7 +440,7 @@ TEST_F(WebSocketEndToEndTest, DISABLED_ON_ANDROID(HstsHttpsToWebSocket)) {
request->Start();
// TestDelegate exits the message loop when the request completes.
base::RunLoop().Run();
- EXPECT_TRUE(request->status().is_success());
+ EXPECT_EQ(OK, delegate.request_status());
// Check HSTS with ws:
// Change the scheme from wss: to ws: to verify that it is switched back.
@@ -464,7 +474,7 @@ TEST_F(WebSocketEndToEndTest, DISABLED_ON_ANDROID(HstsWebSocketToHttps)) {
request->Start();
// TestDelegate exits the message loop when the request completes.
base::RunLoop().Run();
- EXPECT_TRUE(request->status().is_success());
+ EXPECT_EQ(OK, delegate.request_status());
EXPECT_TRUE(request->url().SchemeIs("https"));
}
diff --git a/chromium/net/websockets/websocket_errors.h b/chromium/net/websockets/websocket_errors.h
index 7d62cc008e2..cf2b2b3366e 100644
--- a/chromium/net/websockets/websocket_errors.h
+++ b/chromium/net/websockets/websocket_errors.h
@@ -6,6 +6,7 @@
#define NET_WEBSOCKETS_WEBSOCKET_ERRORS_H_
#include "net/base/net_errors.h"
+#include "net/base/net_export.h"
namespace net {
diff --git a/chromium/net/websockets/websocket_errors_test.cc b/chromium/net/websockets/websocket_errors_test.cc
index 5e48e20e831..95147c70b88 100644
--- a/chromium/net/websockets/websocket_errors_test.cc
+++ b/chromium/net/websockets/websocket_errors_test.cc
@@ -5,8 +5,12 @@
#include "net/websockets/websocket_errors.h"
#include "net/base/net_errors.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -14,7 +18,7 @@ namespace {
// don't exhaustively test every error code, as it would be long, repetitive,
// and add little value.
TEST(WebSocketErrorToNetErrorTest, ResultsAreCorrect) {
- EXPECT_EQ(OK, WebSocketErrorToNetError(kWebSocketNormalClosure));
+ EXPECT_THAT(WebSocketErrorToNetError(kWebSocketNormalClosure), IsOk());
EXPECT_EQ(ERR_WS_PROTOCOL_ERROR,
WebSocketErrorToNetError(kWebSocketErrorProtocolError));
EXPECT_EQ(ERR_MSG_TOO_BIG,
diff --git a/chromium/net/websockets/websocket_event_interface.h b/chromium/net/websockets/websocket_event_interface.h
index 761f356c217..ac29659aac8 100644
--- a/chromium/net/websockets/websocket_event_interface.h
+++ b/chromium/net/websockets/websocket_event_interface.h
@@ -13,12 +13,14 @@
#include "base/compiler_specific.h" // for WARN_UNUSED_RESULT
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "net/base/net_export.h"
class GURL;
namespace net {
+class IOBuffer;
class SSLInfo;
struct WebSocketHandshakeRequestInfo;
struct WebSocketHandshakeResponseInfo;
@@ -47,10 +49,10 @@ class NET_EXPORT WebSocketEventInterface {
// Called when a data frame has been received from the remote host and needs
// to be forwarded to the renderer process.
- virtual ChannelState OnDataFrame(
- bool fin,
- WebSocketMessageType type,
- const std::vector<char>& data) WARN_UNUSED_RESULT = 0;
+ virtual ChannelState OnDataFrame(bool fin,
+ WebSocketMessageType type,
+ scoped_refptr<IOBuffer> buffer,
+ size_t buffer_size) WARN_UNUSED_RESULT = 0;
// Called to provide more send quota for this channel to the renderer
// process. Currently the quota units are always bytes of message body
diff --git a/chromium/net/websockets/websocket_extension_parser.cc b/chromium/net/websockets/websocket_extension_parser.cc
index b737d5eab6f..6e52fbf6bf1 100644
--- a/chromium/net/websockets/websocket_extension_parser.cc
+++ b/chromium/net/websockets/websocket_extension_parser.cc
@@ -4,7 +4,8 @@
#include "net/websockets/websocket_extension_parser.h"
-#include "base/strings/string_util.h"
+#include "base/logging.h"
+#include "net/http/http_util.h"
namespace net {
@@ -19,7 +20,7 @@ bool WebSocketExtensionParser::Parse(const char* data, size_t size) {
bool failed = false;
- while (true) {
+ do {
WebSocketExtension extension;
if (!ConsumeExtension(&extension)) {
failed = true;
@@ -28,11 +29,7 @@ bool WebSocketExtensionParser::Parse(const char* data, size_t size) {
extensions_.push_back(extension);
ConsumeSpaces();
-
- if (!ConsumeIfMatch(',')) {
- break;
- }
- }
+ } while (ConsumeIfMatch(','));
if (!failed && current_ == end_)
return true;
@@ -43,9 +40,8 @@ bool WebSocketExtensionParser::Parse(const char* data, size_t size) {
bool WebSocketExtensionParser::Consume(char c) {
ConsumeSpaces();
- if (current_ == end_ || c != current_[0]) {
+ if (current_ == end_ || c != *current_)
return false;
- }
++current_;
return true;
}
@@ -94,12 +90,10 @@ bool WebSocketExtensionParser::ConsumeExtensionParameter(
bool WebSocketExtensionParser::ConsumeToken(base::StringPiece* token) {
ConsumeSpaces();
const char* head = current_;
- while (current_ < end_ &&
- !IsControl(current_[0]) && !IsSeparator(current_[0]))
+ while (current_ < end_ && HttpUtil::IsTokenChar(*current_))
++current_;
- if (current_ == head) {
+ if (current_ == head)
return false;
- }
*token = base::StringPiece(head, current_ - head);
return true;
}
@@ -109,22 +103,20 @@ bool WebSocketExtensionParser::ConsumeQuotedToken(std::string* token) {
return false;
*token = "";
- while (current_ < end_ && !IsControl(current_[0])) {
- if (UnconsumedBytes() >= 2 && current_[0] == '\\') {
- char next = current_[1];
- if (IsControl(next) || IsSeparator(next)) break;
- *token += next;
- current_ += 2;
- } else if (IsSeparator(current_[0])) {
- break;
- } else {
- *token += current_[0];
+ while (current_ < end_ && *current_ != '"') {
+ if (*current_ == '\\') {
++current_;
+ if (current_ == end_)
+ return false;
}
+ if (!HttpUtil::IsTokenChar(*current_))
+ return false;
+ *token += *current_;
+ ++current_;
}
- // We can't use Consume here because we don't want to consume spaces.
- if (current_ >= end_ || current_[0] != '"')
+ if (current_ == end_)
return false;
+ DCHECK_EQ(*current_, '"');
++current_;
@@ -132,7 +124,7 @@ bool WebSocketExtensionParser::ConsumeQuotedToken(std::string* token) {
}
void WebSocketExtensionParser::ConsumeSpaces() {
- while (current_ < end_ && (current_[0] == ' ' || current_[0] == '\t'))
+ while (current_ < end_ && (*current_ == ' ' || *current_ == '\t'))
++current_;
return;
}
@@ -154,15 +146,4 @@ bool WebSocketExtensionParser::ConsumeIfMatch(char c) {
return true;
}
-// static
-bool WebSocketExtensionParser::IsControl(char c) {
- return (0 <= c && c <= 31) || c == 127;
-}
-
-// static
-bool WebSocketExtensionParser::IsSeparator(char c) {
- const char separators[] = "()<>@,;:\\\"/[]?={} \t";
- return strchr(separators, c) != NULL;
-}
-
} // namespace net
diff --git a/chromium/net/websockets/websocket_extension_parser.h b/chromium/net/websockets/websocket_extension_parser.h
index 365cbf60683..ebba4f04ab5 100644
--- a/chromium/net/websockets/websocket_extension_parser.h
+++ b/chromium/net/websockets/websocket_extension_parser.h
@@ -49,10 +49,6 @@ class NET_EXPORT_PRIVATE WebSocketExtensionParser {
void ConsumeSpaces();
WARN_UNUSED_RESULT bool Lookahead(char c);
WARN_UNUSED_RESULT bool ConsumeIfMatch(char c);
- size_t UnconsumedBytes() const { return end_ - current_; }
-
- static bool IsControl(char c);
- static bool IsSeparator(char c);
// The current position in the input string.
const char* current_;
diff --git a/chromium/net/websockets/websocket_extension_parser_fuzzer.cc b/chromium/net/websockets/websocket_extension_parser_fuzzer.cc
new file mode 100644
index 00000000000..120ee6ada6b
--- /dev/null
+++ b/chromium/net/websockets/websocket_extension_parser_fuzzer.cc
@@ -0,0 +1,16 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "net/websockets/websocket_extension_parser.h"
+
+// Entry point for LibFuzzer.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ net::WebSocketExtensionParser parser;
+ parser.Parse(reinterpret_cast<const char*>(data), size);
+
+ return 0;
+}
diff --git a/chromium/net/websockets/websocket_extension_parser_test.cc b/chromium/net/websockets/websocket_extension_parser_test.cc
index b0a2be9e87a..f726b3e1a39 100644
--- a/chromium/net/websockets/websocket_extension_parser_test.cc
+++ b/chromium/net/websockets/websocket_extension_parser_test.cc
@@ -131,10 +131,15 @@ TEST(WebSocketExtensionParserTest, InvalidPatterns) {
"foo; bar=\"\"", // quoted empty parameter value
"foo; bar=\"baz", // unterminated quoted string
"foo; bar=\"baz \"", // space in quoted string
- "foo; bar baz", // mising '='
+ "foo; bar baz", // missing '='
"foo; bar - baz", // '-' instead of '=' (note: "foo; bar-baz" is valid).
"foo; bar=\r\nbaz", // CRNL not followed by a space
"foo; bar=\r\n baz", // CRNL followed by a space
+ "f\xFFpp", // 8-bit character in extension name
+ "foo; b\xFFr=baz" // 8-bit character in parameter name
+ "foo; bar=b\xFF" // 8-bit character in parameter value
+ "foo; bar=\"b\xFF\"" // 8-bit character in quoted parameter value
+ "foo; bar=\"baz\\" // ends with backslash
};
for (size_t i = 0; i < arraysize(patterns); ++i) {
@@ -155,6 +160,13 @@ TEST(WebSocketExtensionParserTest, QuotedParameterValue) {
EXPECT_TRUE(expected.Equals(parser.extensions()[0]));
}
+// This is a regression test for crbug.com/647156
+TEST(WebSocketExtensionParserTest, InvalidToken) {
+ static const char kInvalidInput[] = "\304;\304!*777\377=\377\254\377";
+ WebSocketExtensionParser parser;
+ EXPECT_FALSE(parser.Parse(kInvalidInput));
+}
+
} // namespace
} // namespace net
diff --git a/chromium/net/websockets/websocket_frame_parser_fuzzer.cc b/chromium/net/websockets/websocket_frame_parser_fuzzer.cc
index 6e4b1f39ee3..562941dfdad 100644
--- a/chromium/net/websockets/websocket_frame_parser_fuzzer.cc
+++ b/chromium/net/websockets/websocket_frame_parser_fuzzer.cc
@@ -7,13 +7,18 @@
#include <vector>
+#include "base/test/fuzzed_data_provider.h"
#include "net/websockets/websocket_frame_parser.h"
// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ base::FuzzedDataProvider fuzzed_data_provider(data, size);
net::WebSocketFrameParser parser;
std::vector<std::unique_ptr<net::WebSocketFrameChunk>> frame_chunks;
- parser.Decode(reinterpret_cast<const char*>(data), size, &frame_chunks);
-
+ while (fuzzed_data_provider.remaining_bytes() > 0) {
+ size_t chunk_size = fuzzed_data_provider.ConsumeUint32InRange(1, 32);
+ base::StringPiece chunk = fuzzed_data_provider.ConsumeBytes(chunk_size);
+ parser.Decode(chunk.data(), chunk.size(), &frame_chunks);
+ }
return 0;
}
diff --git a/chromium/net/websockets/websocket_handshake_stream_base.h b/chromium/net/websockets/websocket_handshake_stream_base.h
index c198cf315cf..b9772feaaaa 100644
--- a/chromium/net/websockets/websocket_handshake_stream_base.h
+++ b/chromium/net/websockets/websocket_handshake_stream_base.h
@@ -15,6 +15,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/supports_user_data.h"
+#include "net/base/net_export.h"
#include "net/http/http_stream.h"
#include "net/url_request/websocket_handshake_userdata_key.h"
#include "net/websockets/websocket_stream.h"
diff --git a/chromium/net/websockets/websocket_handshake_stream_create_helper.cc b/chromium/net/websockets/websocket_handshake_stream_create_helper.cc
index 91e62f1bec0..3cb1d9fe90b 100644
--- a/chromium/net/websockets/websocket_handshake_stream_create_helper.cc
+++ b/chromium/net/websockets/websocket_handshake_stream_create_helper.cc
@@ -19,9 +19,8 @@ WebSocketHandshakeStreamCreateHelper::WebSocketHandshakeStreamCreateHelper(
WebSocketStream::ConnectDelegate* connect_delegate,
const std::vector<std::string>& requested_subprotocols)
: requested_subprotocols_(requested_subprotocols),
- stream_(NULL),
connect_delegate_(connect_delegate),
- failure_message_(NULL) {
+ request_(nullptr) {
DCHECK(connect_delegate_);
}
@@ -31,7 +30,8 @@ WebSocketHandshakeStreamBase*
WebSocketHandshakeStreamCreateHelper::CreateBasicStream(
std::unique_ptr<ClientSocketHandle> connection,
bool using_proxy) {
- DCHECK(failure_message_) << "set_failure_message() must be called";
+ DCHECK(request_) << "set_request() must be called";
+
// The list of supported extensions and parameters is hard-coded.
// TODO(ricea): If more extensions are added, consider a more flexible
// method.
@@ -39,9 +39,9 @@ WebSocketHandshakeStreamCreateHelper::CreateBasicStream(
1, "permessage-deflate; client_max_window_bits");
WebSocketBasicHandshakeStream* stream = new WebSocketBasicHandshakeStream(
std::move(connection), connect_delegate_, using_proxy,
- requested_subprotocols_, extensions, failure_message_);
- OnStreamCreated(stream);
- stream_ = stream;
+ requested_subprotocols_, extensions, request_);
+ OnBasicStreamCreated(stream);
+ request_->OnHandshakeStreamCreated(stream);
return stream;
}
@@ -54,16 +54,7 @@ WebSocketHandshakeStreamCreateHelper::CreateSpdyStream(
return NULL;
}
-std::unique_ptr<WebSocketStream>
-WebSocketHandshakeStreamCreateHelper::Upgrade() {
- DCHECK(stream_);
- WebSocketHandshakeStreamBase* stream = stream_;
- stream_ = NULL;
- return stream->Upgrade();
-}
-
-void WebSocketHandshakeStreamCreateHelper::OnStreamCreated(
- WebSocketBasicHandshakeStream* stream) {
-}
+void WebSocketHandshakeStreamCreateHelper::OnBasicStreamCreated(
+ WebSocketBasicHandshakeStream* stream) {}
} // namespace net
diff --git a/chromium/net/websockets/websocket_handshake_stream_create_helper.h b/chromium/net/websockets/websocket_handshake_stream_create_helper.h
index 67e62dd3e6b..15a2f151237 100644
--- a/chromium/net/websockets/websocket_handshake_stream_create_helper.h
+++ b/chromium/net/websockets/websocket_handshake_stream_create_helper.h
@@ -16,6 +16,7 @@
namespace net {
+class WebSocketStreamRequest;
class WebSocketBasicHandshakeStream;
// Implementation of WebSocketHandshakeStreamBase::CreateHelper. This class is
@@ -36,45 +37,35 @@ class NET_EXPORT_PRIVATE WebSocketHandshakeStreamCreateHelper
// WebSocketHandshakeStreamBase::CreateHelper methods
- // Create a WebSocketBasicHandshakeStream.
+ // Creates a WebSocketBasicHandshakeStream.
WebSocketHandshakeStreamBase* CreateBasicStream(
std::unique_ptr<ClientSocketHandle> connection,
bool using_proxy) override;
- // Unimplemented as of November 2013.
WebSocketHandshakeStreamBase* CreateSpdyStream(
const base::WeakPtr<SpdySession>& session,
bool use_relative_url) override;
- // Call Upgrade() on the WebSocketHandshakeStream and return the result. This
- // must only be called if the handshake succeeded.
- std::unique_ptr<WebSocketStream> Upgrade();
+ // WebSocketHandshakeStreamCreateHelper methods
- // Set a pointer to the std::string into which to write any failure messages
- // that are encountered. This method must be called before CreateBasicStream()
- // or CreateSpdyStream(). The |failure_message| pointer must remain valid as
+ // This method must be called before CreateBasicStream() or
+ // CreateSpdyStream(). The |request| pointer must remain valid as
// long as this object exists.
- void set_failure_message(std::string* failure_message) {
- failure_message_ = failure_message;
+ void set_stream_request(WebSocketStreamRequest* request) {
+ request_ = request;
}
protected:
// This is used by DeterministicKeyWebSocketHandshakeStreamCreateHelper.
// The default implementation does nothing.
- virtual void OnStreamCreated(WebSocketBasicHandshakeStream* stream);
+ virtual void OnBasicStreamCreated(WebSocketBasicHandshakeStream* stream);
private:
const std::vector<std::string> requested_subprotocols_;
- // This is owned by the caller of CreateBaseStream() or
- // CreateSpdyStream(). Both the stream and this object will be destroyed
- // during the destruction of the URLRequest object associated with the
- // handshake. This is only guaranteed to be a valid pointer if the handshake
- // succeeded.
- WebSocketHandshakeStreamBase* stream_;
-
WebSocketStream::ConnectDelegate* connect_delegate_;
- std::string* failure_message_;
+
+ WebSocketStreamRequest* request_;
DISALLOW_COPY_AND_ASSIGN(WebSocketHandshakeStreamCreateHelper);
};
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 9d28e3e8a2c..6b43527ffbd 100644
--- a/chromium/net/websockets/websocket_handshake_stream_create_helper_test.cc
+++ b/chromium/net/websockets/websocket_handshake_stream_create_helper_test.cc
@@ -15,15 +15,22 @@
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#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_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/websockets/websocket_basic_handshake_stream.h"
#include "net/websockets/websocket_stream.h"
#include "net/websockets/websocket_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
+using net::test::IsOk;
+
+using ::testing::_;
+
namespace net {
namespace {
@@ -43,7 +50,7 @@ class MockClientSocketHandleFactory {
std::unique_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
socket_handle->Init("a", scoped_refptr<MockTransportSocketParams>(), MEDIUM,
ClientSocketPool::RespectLimits::ENABLED,
- CompletionCallback(), &pool_, BoundNetLog());
+ CompletionCallback(), &pool_, NetLogWithSource());
return socket_handle;
}
@@ -71,6 +78,13 @@ class TestConnectDelegate : public WebSocketStream::ConnectDelegate {
bool fatal) override {}
};
+class MockWebSocketStreamRequest : public WebSocketStreamRequest {
+ public:
+ MOCK_METHOD1(OnHandshakeStreamCreated,
+ void(WebSocketHandshakeStreamBase* handshake_stream));
+ MOCK_METHOD1(OnFailure, void(const std::string& message));
+};
+
class WebSocketHandshakeStreamCreateHelperTest : public ::testing::Test {
protected:
std::unique_ptr<WebSocketStream> CreateAndInitializeStream(
@@ -80,7 +94,11 @@ class WebSocketHandshakeStreamCreateHelperTest : public ::testing::Test {
static const char kOrigin[] = "http://localhost";
WebSocketHandshakeStreamCreateHelper create_helper(&connect_delegate_,
sub_protocols);
- create_helper.set_failure_message(&failure_message_);
+
+ EXPECT_CALL(stream_request, OnHandshakeStreamCreated(_)).Times(1);
+ EXPECT_CALL(stream_request, OnFailure(_)).Times(0);
+
+ create_helper.set_stream_request(&stream_request);
std::unique_ptr<ClientSocketHandle> socket_handle =
socket_handle_factory_.CreateClientSocketHandle(
@@ -102,9 +120,10 @@ class WebSocketHandshakeStreamCreateHelperTest : public ::testing::Test {
request_info.url = GURL("ws://localhost/");
request_info.method = "GET";
request_info.load_flags = LOAD_DISABLE_CACHE;
- int rv = handshake->InitializeStream(
- &request_info, DEFAULT_PRIORITY, BoundNetLog(), CompletionCallback());
- EXPECT_EQ(OK, rv);
+ int rv =
+ handshake->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ NetLogWithSource(), CompletionCallback());
+ EXPECT_THAT(rv, IsOk());
HttpRequestHeaders headers;
headers.SetHeader("Host", "localhost");
@@ -123,10 +142,10 @@ class WebSocketHandshakeStreamCreateHelperTest : public ::testing::Test {
rv = handshake->SendRequest(headers, &response, dummy.callback());
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
rv = handshake->ReadResponseHeaders(dummy.callback());
- EXPECT_EQ(OK, rv);
+ EXPECT_THAT(rv, IsOk());
EXPECT_EQ(101, response.headers->response_code());
EXPECT_TRUE(response.headers->HasHeaderValue("Connection", "Upgrade"));
EXPECT_TRUE(response.headers->HasHeaderValue("Upgrade", "websocket"));
@@ -135,7 +154,7 @@ class WebSocketHandshakeStreamCreateHelperTest : public ::testing::Test {
MockClientSocketHandleFactory socket_handle_factory_;
TestConnectDelegate connect_delegate_;
- std::string failure_message_;
+ MockWebSocketStreamRequest stream_request;
};
// Confirm that the basic case works as expected.
diff --git a/chromium/net/websockets/websocket_stream.cc b/chromium/net/websockets/websocket_stream.cc
index d621f39ceb2..ef62c246c7b 100644
--- a/chromium/net/websockets/websocket_stream.cc
+++ b/chromium/net/websockets/websocket_stream.cc
@@ -38,7 +38,7 @@ namespace {
// JavaScript programs to recognize the timeout cause.
const int kHandshakeTimeoutIntervalInSeconds = 240;
-class StreamRequestImpl;
+class WebSocketStreamRequestImpl;
class Delegate : public URLRequest::Delegate {
public:
@@ -49,7 +49,7 @@ class Delegate : public URLRequest::Delegate {
NUM_HANDSHAKE_RESULT_TYPES,
};
- explicit Delegate(StreamRequestImpl* owner)
+ explicit Delegate(WebSocketStreamRequestImpl* owner)
: owner_(owner), result_(INCOMPLETE) {}
~Delegate() override {
UMA_HISTOGRAM_ENUMERATION(
@@ -61,7 +61,7 @@ class Delegate : public URLRequest::Delegate {
const RedirectInfo& redirect_info,
bool* defer_redirect) override;
- void OnResponseStarted(URLRequest* request) override;
+ void OnResponseStarted(URLRequest* request, int net_error) override;
void OnAuthRequired(URLRequest* request,
AuthChallengeInfo* auth_info) override;
@@ -76,13 +76,13 @@ class Delegate : public URLRequest::Delegate {
void OnReadCompleted(URLRequest* request, int bytes_read) override;
private:
- StreamRequestImpl* owner_;
+ WebSocketStreamRequestImpl* owner_;
HandshakeResult result_;
};
-class StreamRequestImpl : public WebSocketStreamRequest {
+class WebSocketStreamRequestImpl : public WebSocketStreamRequest {
public:
- StreamRequestImpl(
+ WebSocketStreamRequestImpl(
const GURL& url,
const URLRequestContext* context,
const url::Origin& origin,
@@ -94,8 +94,9 @@ class StreamRequestImpl : public WebSocketStreamRequest {
url_request_(
context->CreateRequest(url, DEFAULT_PRIORITY, delegate_.get())),
connect_delegate_(std::move(connect_delegate)),
- create_helper_(create_helper.release()) {
- create_helper_->set_failure_message(&failure_message_);
+ handshake_stream_create_helper_(create_helper.release()),
+ handshake_stream_(nullptr) {
+ handshake_stream_create_helper_->set_stream_request(this);
HttpRequestHeaders headers;
headers.SetHeader(websockets::kUpgrade, websockets::kWebSocketLowercase);
headers.SetHeader(HttpRequestHeaders::kConnection, websockets::kUpgrade);
@@ -109,16 +110,26 @@ class StreamRequestImpl : public WebSocketStreamRequest {
url_request_->set_initiator(origin);
url_request_->set_first_party_for_cookies(first_party_for_cookies);
- // This passes the ownership of |create_helper_| to |url_request_|.
+ // This passes the ownership of |handshake_stream_create_helper_| to
+ // |url_request_|.
url_request_->SetUserData(
WebSocketHandshakeStreamBase::CreateHelper::DataKey(),
- create_helper_);
+ handshake_stream_create_helper_);
url_request_->SetLoadFlags(LOAD_DISABLE_CACHE | LOAD_BYPASS_CACHE);
}
// Destroying this object destroys the URLRequest, which cancels the request
// and so terminates the handshake if it is incomplete.
- ~StreamRequestImpl() override {}
+ ~WebSocketStreamRequestImpl() override {}
+
+ void OnHandshakeStreamCreated(
+ WebSocketHandshakeStreamBase* handshake_stream) override {
+ handshake_stream_ = handshake_stream;
+ }
+
+ void OnFailure(const std::string& message) override {
+ failure_message_ = message;
+ }
void Start(std::unique_ptr<base::Timer> timer) {
DCHECK(timer);
@@ -126,20 +137,24 @@ class StreamRequestImpl : public WebSocketStreamRequest {
kHandshakeTimeoutIntervalInSeconds));
timer_ = std::move(timer);
timer_->Start(FROM_HERE, timeout,
- base::Bind(&StreamRequestImpl::OnTimeout,
+ base::Bind(&WebSocketStreamRequestImpl::OnTimeout,
base::Unretained(this)));
url_request_->Start();
}
void PerformUpgrade() {
DCHECK(timer_);
+ DCHECK(handshake_stream_);
+
timer_->Stop();
- connect_delegate_->OnSuccess(create_helper_->Upgrade());
+
+ WebSocketHandshakeStreamBase* handshake_stream = handshake_stream_;
+ handshake_stream_ = nullptr;
+ connect_delegate_->OnSuccess(handshake_stream->Upgrade());
}
- std::string FailureMessageFromNetError() {
- int error = url_request_->status().error();
- if (error == ERR_TUNNEL_CONNECTION_FAILED) {
+ std::string FailureMessageFromNetError(int net_error) {
+ if (net_error == ERR_TUNNEL_CONNECTION_FAILED) {
// This error is common and confusing, so special-case it.
// TODO(ricea): Include the HostPortPair of the selected proxy server in
// the error message. This is not currently possible because it isn't set
@@ -147,26 +162,26 @@ class StreamRequestImpl : public WebSocketStreamRequest {
return "Establishing a tunnel via proxy server failed.";
} else {
return std::string("Error in connection establishment: ") +
- ErrorToString(url_request_->status().error());
+ ErrorToString(net_error);
}
}
- void ReportFailure() {
+ void ReportFailure(int net_error) {
DCHECK(timer_);
timer_->Stop();
if (failure_message_.empty()) {
- switch (url_request_->status().status()) {
- case URLRequestStatus::SUCCESS:
- case URLRequestStatus::IO_PENDING:
+ switch (net_error) {
+ case OK:
+ case ERR_IO_PENDING:
+ break;
+ case ERR_ABORTED:
+ failure_message_ = "WebSocket opening handshake was canceled";
break;
- case URLRequestStatus::CANCELED:
- if (url_request_->status().error() == ERR_TIMED_OUT)
- failure_message_ = "WebSocket opening handshake timed out";
- else
- failure_message_ = "WebSocket opening handshake was canceled";
+ case ERR_TIMED_OUT:
+ failure_message_ = "WebSocket opening handshake timed out";
break;
- case URLRequestStatus::FAILED:
- failure_message_ = FailureMessageFromNetError();
+ default:
+ failure_message_ = FailureMessageFromNetError(net_error);
break;
}
}
@@ -197,14 +212,21 @@ class StreamRequestImpl : public WebSocketStreamRequest {
// initialised first.
std::unique_ptr<Delegate> delegate_;
- // Deleting the StreamRequestImpl object deletes this URLRequest object,
- // cancelling the whole connection.
+ // Deleting the WebSocketStreamRequestImpl object deletes this URLRequest
+ // object, cancelling the whole connection.
std::unique_ptr<URLRequest> url_request_;
std::unique_ptr<WebSocketStream::ConnectDelegate> connect_delegate_;
// Owned by the URLRequest.
- WebSocketHandshakeStreamCreateHelper* create_helper_;
+ WebSocketHandshakeStreamCreateHelper* handshake_stream_create_helper_;
+
+ // This is owned by the caller of CreateBaseStream() or
+ // CreateSpdyStream() of WebsocketHandshakeStreamCreateHelper. Both the
+ // stream and this object will be destroyed during the destruction of the
+ // URLRequest object associated with the handshake. This is only guaranteed
+ // to be a valid pointer if the handshake succeeded.
+ WebSocketHandshakeStreamBase* handshake_stream_;
// The failure message supplied by WebSocketBasicHandshakeStream, if any.
std::string failure_message_;
@@ -259,14 +281,14 @@ void Delegate::OnReceivedRedirect(URLRequest* request,
}
}
-void Delegate::OnResponseStarted(URLRequest* request) {
+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",
- -request->status().error());
- if (!request->status().is_success()) {
+ UMA_HISTOGRAM_SPARSE_SLOWLY("Net.WebSocket.ErrorCodes", -net_error);
+ if (net_error != OK) {
DVLOG(3) << "OnResponseStarted (request failed)";
- owner_->ReportFailure();
+ owner_->ReportFailure(net_error);
return;
}
const int response_code = request->GetResponseCode();
@@ -292,7 +314,7 @@ void Delegate::OnResponseStarted(URLRequest* request) {
default:
result_ = FAILED;
- owner_->ReportFailure();
+ owner_->ReportFailure(net_error);
}
}
@@ -337,39 +359,38 @@ WebSocketStream::ConnectDelegate::~ConnectDelegate() {}
std::unique_ptr<WebSocketStreamRequest> WebSocketStream::CreateAndConnectStream(
const GURL& socket_url,
- const std::vector<std::string>& requested_subprotocols,
+ std::unique_ptr<WebSocketHandshakeStreamCreateHelper> create_helper,
const url::Origin& origin,
const GURL& first_party_for_cookies,
const std::string& additional_headers,
URLRequestContext* url_request_context,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<ConnectDelegate> connect_delegate) {
- std::unique_ptr<WebSocketHandshakeStreamCreateHelper> create_helper(
- new WebSocketHandshakeStreamCreateHelper(connect_delegate.get(),
- requested_subprotocols));
- std::unique_ptr<StreamRequestImpl> request(new StreamRequestImpl(
- socket_url, url_request_context, origin, first_party_for_cookies,
- additional_headers, std::move(connect_delegate),
- std::move(create_helper)));
+ std::unique_ptr<WebSocketStreamRequestImpl> request(
+ new WebSocketStreamRequestImpl(
+ socket_url, url_request_context, origin, first_party_for_cookies,
+ additional_headers, std::move(connect_delegate),
+ std::move(create_helper)));
request->Start(std::unique_ptr<base::Timer>(new base::Timer(false, false)));
return std::move(request);
}
-// This is declared in websocket_test_util.h.
-std::unique_ptr<WebSocketStreamRequest> CreateAndConnectStreamForTesting(
+std::unique_ptr<WebSocketStreamRequest>
+WebSocketStream::CreateAndConnectStreamForTesting(
const GURL& socket_url,
std::unique_ptr<WebSocketHandshakeStreamCreateHelper> create_helper,
const url::Origin& origin,
const GURL& first_party_for_cookies,
const std::string& additional_headers,
URLRequestContext* url_request_context,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<WebSocketStream::ConnectDelegate> connect_delegate,
std::unique_ptr<base::Timer> timer) {
- std::unique_ptr<StreamRequestImpl> request(new StreamRequestImpl(
- socket_url, url_request_context, origin, first_party_for_cookies,
- additional_headers, std::move(connect_delegate),
- std::move(create_helper)));
+ std::unique_ptr<WebSocketStreamRequestImpl> request(
+ new WebSocketStreamRequestImpl(
+ socket_url, url_request_context, origin, first_party_for_cookies,
+ additional_headers, std::move(connect_delegate),
+ std::move(create_helper)));
request->Start(std::move(timer));
return std::move(request);
}
@@ -382,9 +403,9 @@ void WebSocketDispatchOnFinishOpeningHandshake(
DCHECK(connect_delegate);
if (headers.get()) {
connect_delegate->OnFinishOpeningHandshake(
- base::WrapUnique(new WebSocketHandshakeResponseInfo(
+ base::MakeUnique<WebSocketHandshakeResponseInfo>(
url, headers->response_code(), headers->GetStatusText(), headers,
- response_time)));
+ response_time));
}
}
diff --git a/chromium/net/websockets/websocket_stream.h b/chromium/net/websockets/websocket_stream.h
index 002c21a7838..389e0922c95 100644
--- a/chromium/net/websockets/websocket_stream.h
+++ b/chromium/net/websockets/websocket_stream.h
@@ -31,9 +31,10 @@ class Origin;
namespace net {
-class BoundNetLog;
+class NetLogWithSource;
class URLRequestContext;
struct WebSocketFrame;
+class WebSocketHandshakeStreamBase;
class WebSocketHandshakeStreamCreateHelper;
// WebSocketStreamRequest is the caller's handle to the process of creation of a
@@ -44,6 +45,10 @@ class WebSocketHandshakeStreamCreateHelper;
class NET_EXPORT_PRIVATE WebSocketStreamRequest {
public:
virtual ~WebSocketStreamRequest();
+
+ virtual void OnHandshakeStreamCreated(
+ WebSocketHandshakeStreamBase* handshake_stream) = 0;
+ virtual void OnFailure(const std::string& message) = 0;
};
// WebSocketStream is a transport-agnostic interface for reading and writing
@@ -106,14 +111,28 @@ class NET_EXPORT_PRIVATE WebSocketStream {
// it is safe to delete.
static std::unique_ptr<WebSocketStreamRequest> CreateAndConnectStream(
const GURL& socket_url,
- const std::vector<std::string>& requested_subprotocols,
+ std::unique_ptr<WebSocketHandshakeStreamCreateHelper> create_helper,
const url::Origin& origin,
const GURL& first_party_for_cookies,
const std::string& additional_headers,
URLRequestContext* url_request_context,
- const BoundNetLog& net_log,
+ const NetLogWithSource& net_log,
std::unique_ptr<ConnectDelegate> connect_delegate);
+ // Alternate version of CreateAndConnectStream() for testing use only. It
+ // takes |timer| as the handshake timeout timer.
+ static std::unique_ptr<WebSocketStreamRequest>
+ CreateAndConnectStreamForTesting(
+ const GURL& socket_url,
+ std::unique_ptr<WebSocketHandshakeStreamCreateHelper> create_helper,
+ const url::Origin& origin,
+ const GURL& first_party_for_cookies,
+ const std::string& additional_headers,
+ URLRequestContext* url_request_context,
+ const NetLogWithSource& net_log,
+ std::unique_ptr<ConnectDelegate> connect_delegate,
+ std::unique_ptr<base::Timer> timer);
+
// Derived classes must make sure Close() is called when the stream is not
// closed on destruction.
virtual ~WebSocketStream();
@@ -216,22 +235,6 @@ void WebSocketDispatchOnFinishOpeningHandshake(
const scoped_refptr<HttpResponseHeaders>& headers,
base::Time response_time);
-// Alternate version of WebSocketStream::CreateAndConnectStream() for testing
-// use only. The differences are the use of a |create_helper| argument in place
-// of |requested_subprotocols| and taking |timer| as the handshake timeout
-// timer. Implemented in websocket_stream.cc.
-NET_EXPORT_PRIVATE std::unique_ptr<WebSocketStreamRequest>
-CreateAndConnectStreamForTesting(
- const GURL& socket_url,
- std::unique_ptr<WebSocketHandshakeStreamCreateHelper> create_helper,
- const url::Origin& origin,
- const GURL& first_party_for_cookies,
- const std::string& additional_headers,
- URLRequestContext* url_request_context,
- const BoundNetLog& net_log,
- std::unique_ptr<WebSocketStream::ConnectDelegate> connect_delegate,
- std::unique_ptr<base::Timer> timer);
-
} // namespace net
#endif // NET_WEBSOCKETS_WEBSOCKET_STREAM_H_
diff --git a/chromium/net/websockets/websocket_stream_cookie_test.cc b/chromium/net/websockets/websocket_stream_cookie_test.cc
index 585e03d1681..fbbee223bda 100644
--- a/chromium/net/websockets/websocket_stream_cookie_test.cc
+++ b/chromium/net/websockets/websocket_stream_cookie_test.cc
@@ -122,7 +122,7 @@ class WebSocketStreamServerSetCookieTest
TEST_P(WebSocketStreamClientUseCookieTest, ClientUseCookie) {
// For wss tests.
- ssl_data_.push_back(base::WrapUnique(new SSLSocketDataProvider(ASYNC, OK)));
+ ssl_data_.push_back(base::MakeUnique<SSLSocketDataProvider>(ASYNC, OK));
CookieStore* store =
url_request_context_host_.GetURLRequestContext()->cookie_store();
@@ -157,7 +157,7 @@ TEST_P(WebSocketStreamClientUseCookieTest, ClientUseCookie) {
TEST_P(WebSocketStreamServerSetCookieTest, ServerSetCookie) {
// For wss tests.
- ssl_data_.push_back(base::WrapUnique(new SSLSocketDataProvider(ASYNC, OK)));
+ ssl_data_.push_back(base::MakeUnique<SSLSocketDataProvider>(ASYNC, OK));
const GURL url(GetParam().url);
const GURL cookie_url(GetParam().cookie_url);
diff --git a/chromium/net/websockets/websocket_stream_create_test_base.cc b/chromium/net/websockets/websocket_stream_create_test_base.cc
index 354c5d7e0a6..6ca5d70381a 100644
--- a/chromium/net/websockets/websocket_stream_create_test_base.cc
+++ b/chromium/net/websockets/websocket_stream_create_test_base.cc
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
+#include "net/log/net_log_with_source.h"
#include "net/websockets/websocket_basic_handshake_stream.h"
#include "net/websockets/websocket_handshake_request_info.h"
#include "net/websockets/websocket_handshake_response_info.h"
@@ -33,7 +34,7 @@ class DeterministicKeyWebSocketHandshakeStreamCreateHelper
: WebSocketHandshakeStreamCreateHelper(connect_delegate,
requested_subprotocols) {}
- void OnStreamCreated(WebSocketBasicHandshakeStream* stream) override {
+ void OnBasicStreamCreated(WebSocketBasicHandshakeStream* stream) override {
stream->SetWebSocketKeyForTesting("dGhlIHNhbXBsZSBub25jZQ==");
}
@@ -114,10 +115,10 @@ void WebSocketStreamCreateTestBase::CreateAndConnectStream(
std::unique_ptr<WebSocketHandshakeStreamCreateHelper> create_helper(
new DeterministicKeyWebSocketHandshakeStreamCreateHelper(delegate,
sub_protocols));
- stream_request_ = CreateAndConnectStreamForTesting(
+ stream_request_ = WebSocketStream::CreateAndConnectStreamForTesting(
socket_url, std::move(create_helper), origin, first_party_for_cookies,
additional_headers, url_request_context_host_.GetURLRequestContext(),
- BoundNetLog(), std::move(connect_delegate),
+ NetLogWithSource(), std::move(connect_delegate),
timer ? std::move(timer)
: std::unique_ptr<base::Timer>(new base::Timer(false, false)));
}
diff --git a/chromium/net/websockets/websocket_stream_create_test_base.h b/chromium/net/websockets/websocket_stream_create_test_base.h
index 3d6a7cf448f..be7912f63c8 100644
--- a/chromium/net/websockets/websocket_stream_create_test_base.h
+++ b/chromium/net/websockets/websocket_stream_create_test_base.h
@@ -13,7 +13,6 @@
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/timer/timer.h"
-#include "net/base/net_export.h"
#include "net/socket/socket_test_util.h"
#include "net/ssl/ssl_info.h"
#include "net/websockets/websocket_event_interface.h"
diff --git a/chromium/net/websockets/websocket_stream_test.cc b/chromium/net/websockets/websocket_stream_test.cc
index 35b7f890755..fcafedc8628 100644
--- a/chromium/net/websockets/websocket_stream_test.cc
+++ b/chromium/net/websockets/websocket_stream_test.cc
@@ -26,16 +26,20 @@
#include "net/socket/client_socket_handle.h"
#include "net/socket/socket_test_util.h"
#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
#include "net/test/test_data_directory.h"
#include "net/url_request/url_request_test_util.h"
#include "net/websockets/websocket_basic_handshake_stream.h"
#include "net/websockets/websocket_frame.h"
#include "net/websockets/websocket_stream_create_test_base.h"
#include "net/websockets/websocket_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
+using net::test::IsOk;
+
namespace net {
namespace {
@@ -571,7 +575,7 @@ TEST_F(WebSocketStreamCreateExtensionTest, PerMessageDeflateInflates) {
ASSERT_TRUE(stream_);
std::vector<std::unique_ptr<WebSocketFrame>> frames;
CompletionCallback callback;
- ASSERT_EQ(OK, stream_->ReadFrames(&frames, callback));
+ ASSERT_THAT(stream_->ReadFrames(&frames, callback), IsOk());
ASSERT_EQ(1U, frames.size());
ASSERT_EQ(5U, frames[0]->header.payload_length);
EXPECT_EQ("Hello", std::string(frames[0]->data->data(), 5));
@@ -1005,11 +1009,11 @@ TEST_F(WebSocketStreamCreateTest, CancellationDuringRead) {
// "cookie-flood.html".
TEST_F(WebSocketStreamCreateTest, VeryLargeResponseHeaders) {
std::string set_cookie_headers;
- set_cookie_headers.reserve(45 * 10000);
- for (int i = 0; i < 10000; ++i) {
- set_cookie_headers +=
- base::StringPrintf("Set-Cookie: WK-websocket-test-flood-%d=1\r\n", i);
+ set_cookie_headers.reserve(24 * 20000);
+ for (int i = 0; i < 20000; ++i) {
+ set_cookie_headers += base::StringPrintf("Set-Cookie: ws-%d=1\r\n", i);
}
+ ASSERT_GT(set_cookie_headers.size(), 256U * 1024U);
CreateAndConnectStandard("ws://localhost/", "localhost", "/",
NoSubProtocols(), LocalhostOrigin(), LocalhostUrl(),
"", "", set_cookie_headers);
@@ -1042,8 +1046,8 @@ TEST_F(WebSocketStreamCreateTest, NoResponse) {
}
TEST_F(WebSocketStreamCreateTest, SelfSignedCertificateFailure) {
- ssl_data_.push_back(base::WrapUnique(
- new SSLSocketDataProvider(ASYNC, ERR_CERT_AUTHORITY_INVALID)));
+ ssl_data_.push_back(base::MakeUnique<SSLSocketDataProvider>(
+ ASYNC, ERR_CERT_AUTHORITY_INVALID));
ssl_data_[0]->cert =
ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
ASSERT_TRUE(ssl_data_[0]->cert.get());
diff --git a/chromium/net/websockets/websocket_test_util.h b/chromium/net/websockets/websocket_test_util.h
index 6944cba589d..1a080867e4a 100644
--- a/chromium/net/websockets/websocket_test_util.h
+++ b/chromium/net/websockets/websocket_test_util.h
@@ -26,8 +26,8 @@ class Origin;
namespace net {
-class BoundNetLog;
class MockClientSocketFactory;
+class NetLogWithSource;
class ProxyService;
class SequencedSocketData;
struct SSLSocketDataProvider;